From 36a42bdbcf599a2d712008d6eb50ebcc4acb90b0 Mon Sep 17 00:00:00 2001 From: ChiTimesChi <88190723+ChiTimesChi@users.noreply.github.com> Date: Wed, 2 Oct 2024 15:32:52 +0100 Subject: [PATCH 01/85] feat: add `callValue` to bridge params --- packages/contracts-rfq/contracts/FastBridgeV2.sol | 1 + packages/contracts-rfq/contracts/interfaces/IFastBridgeV2.sol | 3 +++ packages/contracts-rfq/test/FastBridgeV2.Dst.Exclusivity.t.sol | 2 ++ packages/contracts-rfq/test/FastBridgeV2.t.sol | 2 ++ 4 files changed, 8 insertions(+) diff --git a/packages/contracts-rfq/contracts/FastBridgeV2.sol b/packages/contracts-rfq/contracts/FastBridgeV2.sol index 1a64515a33..8d1e604a44 100644 --- a/packages/contracts-rfq/contracts/FastBridgeV2.sol +++ b/packages/contracts-rfq/contracts/FastBridgeV2.sol @@ -54,6 +54,7 @@ contract FastBridgeV2 is Admin, IFastBridgeV2, IFastBridgeV2Errors { quoteRelayer: address(0), quoteExclusivitySeconds: 0, quoteId: bytes(""), + callValue: 0, callParams: bytes("") }) }); diff --git a/packages/contracts-rfq/contracts/interfaces/IFastBridgeV2.sol b/packages/contracts-rfq/contracts/interfaces/IFastBridgeV2.sol index c4c3751a5b..e11b4cd505 100644 --- a/packages/contracts-rfq/contracts/interfaces/IFastBridgeV2.sol +++ b/packages/contracts-rfq/contracts/interfaces/IFastBridgeV2.sol @@ -30,14 +30,17 @@ interface IFastBridgeV2 is IFastBridge { /// for backwards compatibility. /// Note: quoteRelayer and quoteExclusivitySeconds are either both zero (indicating no exclusivity) /// or both non-zero (indicating exclusivity for the given period). + /// Note: callValue > 0 could NOT be used with destToken = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE (ETH_ADDRESS) /// @param quoteRelayer Relayer that provided the quote for the transaction /// @param quoteExclusivitySeconds Period of time the quote relayer is guaranteed exclusivity after user's deposit /// @param quoteId Unique quote identifier used for tracking the quote + /// @param callValue ETH value to send to the recipient (if any) /// @param callParams Parameters for the arbitrary call to the destination recipient (if any) struct BridgeParamsV2 { address quoteRelayer; int256 quoteExclusivitySeconds; bytes quoteId; + uint256 callValue; bytes callParams; } diff --git a/packages/contracts-rfq/test/FastBridgeV2.Dst.Exclusivity.t.sol b/packages/contracts-rfq/test/FastBridgeV2.Dst.Exclusivity.t.sol index a616872f93..7926b3d362 100644 --- a/packages/contracts-rfq/test/FastBridgeV2.Dst.Exclusivity.t.sol +++ b/packages/contracts-rfq/test/FastBridgeV2.Dst.Exclusivity.t.sol @@ -12,12 +12,14 @@ contract FastBridgeV2DstExclusivityTest is FastBridgeV2DstTest { quoteRelayer: relayerA, quoteExclusivitySeconds: int256(EXCLUSIVITY_PERIOD), quoteId: "", + callValue: 0, callParams: "" }); ethParamsV2 = IFastBridgeV2.BridgeParamsV2({ quoteRelayer: relayerB, quoteExclusivitySeconds: int256(EXCLUSIVITY_PERIOD), quoteId: "", + callValue: 0, callParams: "" }); diff --git a/packages/contracts-rfq/test/FastBridgeV2.t.sol b/packages/contracts-rfq/test/FastBridgeV2.t.sol index 8011f8a8e2..af77ec05d8 100644 --- a/packages/contracts-rfq/test/FastBridgeV2.t.sol +++ b/packages/contracts-rfq/test/FastBridgeV2.t.sol @@ -128,12 +128,14 @@ abstract contract FastBridgeV2Test is Test, IFastBridgeV2Errors { quoteRelayer: address(0), quoteExclusivitySeconds: 0, quoteId: bytes(""), + callValue: 0, callParams: bytes("") }); ethParamsV2 = IFastBridgeV2.BridgeParamsV2({ quoteRelayer: address(0), quoteExclusivitySeconds: 0, quoteId: bytes(""), + callValue: 0, callParams: bytes("") }); From 919a0a94277e0af1b8ce9bf45a9e8d03a3735658 Mon Sep 17 00:00:00 2001 From: ChiTimesChi <88190723+ChiTimesChi@users.noreply.github.com> Date: Wed, 2 Oct 2024 16:07:50 +0100 Subject: [PATCH 02/85] feat: add `callValue` to bridge tx V2 --- packages/contracts-rfq/contracts/FastBridgeV2.sol | 2 +- packages/contracts-rfq/contracts/interfaces/IFastBridgeV2.sol | 2 +- packages/contracts-rfq/test/FastBridgeV2.Src.t.sol | 2 +- packages/contracts-rfq/test/FastBridgeV2.t.sol | 2 -- 4 files changed, 3 insertions(+), 5 deletions(-) diff --git a/packages/contracts-rfq/contracts/FastBridgeV2.sol b/packages/contracts-rfq/contracts/FastBridgeV2.sol index 8d1e604a44..20ef419645 100644 --- a/packages/contracts-rfq/contracts/FastBridgeV2.sol +++ b/packages/contracts-rfq/contracts/FastBridgeV2.sol @@ -173,7 +173,7 @@ contract FastBridgeV2 is Admin, IFastBridgeV2, IFastBridgeV2Errors { originAmount: originAmount, destAmount: params.destAmount, originFeeAmount: originFeeAmount, - sendChainGas: params.sendChainGas, + callValue: 0, // TODO: fix deadline: params.deadline, nonce: senderNonces[params.sender]++, // increment nonce on every bridge exclusivityRelayer: paramsV2.quoteRelayer, diff --git a/packages/contracts-rfq/contracts/interfaces/IFastBridgeV2.sol b/packages/contracts-rfq/contracts/interfaces/IFastBridgeV2.sol index e11b4cd505..a1485d3f31 100644 --- a/packages/contracts-rfq/contracts/interfaces/IFastBridgeV2.sol +++ b/packages/contracts-rfq/contracts/interfaces/IFastBridgeV2.sol @@ -57,7 +57,7 @@ interface IFastBridgeV2 is IFastBridge { uint256 originAmount; // amount in on origin bridge less originFeeAmount uint256 destAmount; uint256 originFeeAmount; - bool sendChainGas; + uint256 callValue; // ETH value to send to the recipient (if any) - replaces V1's sendChainGas flag uint256 deadline; // user specified deadline for destination relay uint256 nonce; address exclusivityRelayer; diff --git a/packages/contracts-rfq/test/FastBridgeV2.Src.t.sol b/packages/contracts-rfq/test/FastBridgeV2.Src.t.sol index c2a5902133..1b55ad4ef9 100644 --- a/packages/contracts-rfq/test/FastBridgeV2.Src.t.sol +++ b/packages/contracts-rfq/test/FastBridgeV2.Src.t.sol @@ -42,7 +42,7 @@ contract FastBridgeV2SrcTest is FastBridgeV2SrcBaseTest { destToken: bridgeTx.destToken, originAmount: bridgeTx.originAmount, destAmount: bridgeTx.destAmount, - sendChainGas: bridgeTx.sendChainGas + sendChainGas: bridgeTx.callValue > 0 }); } diff --git a/packages/contracts-rfq/test/FastBridgeV2.t.sol b/packages/contracts-rfq/test/FastBridgeV2.t.sol index af77ec05d8..9ac073146f 100644 --- a/packages/contracts-rfq/test/FastBridgeV2.t.sol +++ b/packages/contracts-rfq/test/FastBridgeV2.t.sol @@ -160,7 +160,6 @@ abstract contract FastBridgeV2Test is Test, IFastBridgeV2Errors { txV2.originAmount = txV1.originAmount; txV2.destAmount = txV1.destAmount; txV2.originFeeAmount = txV1.originFeeAmount; - txV2.sendChainGas = txV1.sendChainGas; txV2.deadline = txV1.deadline; txV2.nonce = txV1.nonce; } @@ -207,7 +206,6 @@ abstract contract FastBridgeV2Test is Test, IFastBridgeV2Errors { txV1.originAmount = txV2.originAmount; txV1.destAmount = txV2.destAmount; txV1.originFeeAmount = txV2.originFeeAmount; - txV1.sendChainGas = txV2.sendChainGas; txV1.deadline = txV2.deadline; txV1.nonce = txV2.nonce; } From 867d5d9ca8e953fd5acd85a1368fa7c3ab78628c Mon Sep 17 00:00:00 2001 From: ChiTimesChi <88190723+ChiTimesChi@users.noreply.github.com> Date: Thu, 3 Oct 2024 12:25:49 +0100 Subject: [PATCH 03/85] test: add cases for SRC calls with `callValue` --- .../interfaces/IFastBridgeV2Errors.sol | 1 + .../test/FastBridgeV2.Src.ArbitraryCall.t.sol | 53 +++++++++++++++++++ .../contracts-rfq/test/FastBridgeV2.t.sol | 10 ++++ 3 files changed, 64 insertions(+) diff --git a/packages/contracts-rfq/contracts/interfaces/IFastBridgeV2Errors.sol b/packages/contracts-rfq/contracts/interfaces/IFastBridgeV2Errors.sol index 7cc1423a84..f40b760c30 100644 --- a/packages/contracts-rfq/contracts/interfaces/IFastBridgeV2Errors.sol +++ b/packages/contracts-rfq/contracts/interfaces/IFastBridgeV2Errors.sol @@ -7,6 +7,7 @@ interface IFastBridgeV2Errors { error ChainIncorrect(); error ExclusivityParamsIncorrect(); error MsgValueIncorrect(); + error NativeTokenCallValueNotSupported(); error SenderIncorrect(); error StatusIncorrect(); error ZeroAddress(); diff --git a/packages/contracts-rfq/test/FastBridgeV2.Src.ArbitraryCall.t.sol b/packages/contracts-rfq/test/FastBridgeV2.Src.ArbitraryCall.t.sol index 2b1e83a30c..5b6e84b732 100644 --- a/packages/contracts-rfq/test/FastBridgeV2.Src.ArbitraryCall.t.sol +++ b/packages/contracts-rfq/test/FastBridgeV2.Src.ArbitraryCall.t.sol @@ -6,6 +6,7 @@ import {FastBridgeV2SrcExclusivityTest} from "./FastBridgeV2.Src.Exclusivity.t.s // solhint-disable func-name-mixedcase, ordering contract FastBridgeV2SrcArbitraryCallTest is FastBridgeV2SrcExclusivityTest { bytes public constant CALL_PARAMS = abi.encode("Hello, World!"); + uint256 public constant CALL_VALUE = 1_337_420; function createFixturesV2() public virtual override { super.createFixturesV2(); @@ -41,4 +42,56 @@ contract FastBridgeV2SrcArbitraryCallTest is FastBridgeV2SrcExclusivityTest { vm.expectRevert(CallParamsLengthAboveMax.selector); bridge({caller: userA, msgValue: ethParams.originAmount, params: ethParams, paramsV2: ethParamsV2}); } + + // ══════════════════════════════════════ WITH CALL VALUE, NO CALL PARAMS ══════════════════════════════════════════ + + function test_bridge_token_withCallValue_noCallParams() public { + setTokenTestCallParams(""); + setTokenTestCallValue(CALL_VALUE); + test_bridge_token(); + } + + function test_bridge_token_diffSender_withCallValue_noCallParams() public { + setTokenTestCallParams(""); + setTokenTestCallValue(CALL_VALUE); + test_bridge_token_diffSender(); + } + + function test_bridge_eth_withCallValue_noCallParams_revert() public { + setEthTestCallParams(""); + setEthTestCallValue(CALL_VALUE); + vm.expectRevert(NativeTokenCallValueNotSupported.selector); + bridge({caller: userA, msgValue: ethParams.originAmount, params: ethParams, paramsV2: ethParamsV2}); + } + + function test_bridge_eth_diffSender_withCallValue_noCallParams_revert() public { + setEthTestCallParams(""); + setEthTestCallValue(CALL_VALUE); + vm.expectRevert(NativeTokenCallValueNotSupported.selector); + bridge({caller: userB, msgValue: ethParams.originAmount, params: ethParams, paramsV2: ethParamsV2}); + } + + // ═══════════════════════════════════════ WITH CALL VALUE & CALL PARAMS ═══════════════════════════════════════════ + + function test_bridge_token_withCallValue_withCallParams() public { + setTokenTestCallValue(CALL_VALUE); + test_bridge_token(); + } + + function test_bridge_token_diffSender_withCallValue_withCallParams() public { + setTokenTestCallValue(CALL_VALUE); + test_bridge_token_diffSender(); + } + + function test_bridge_eth_withCallValue_withCallParams_revert() public { + setEthTestCallValue(CALL_VALUE); + vm.expectRevert(NativeTokenCallValueNotSupported.selector); + bridge({caller: userA, msgValue: ethParams.originAmount, params: ethParams, paramsV2: ethParamsV2}); + } + + function test_bridge_eth_diffSender_withCallValue_withCallParams_revert() public { + setEthTestCallValue(CALL_VALUE); + vm.expectRevert(NativeTokenCallValueNotSupported.selector); + bridge({caller: userB, msgValue: ethParams.originAmount, params: ethParams, paramsV2: ethParamsV2}); + } } diff --git a/packages/contracts-rfq/test/FastBridgeV2.t.sol b/packages/contracts-rfq/test/FastBridgeV2.t.sol index 9ac073146f..2b9bce809f 100644 --- a/packages/contracts-rfq/test/FastBridgeV2.t.sol +++ b/packages/contracts-rfq/test/FastBridgeV2.t.sol @@ -169,6 +169,11 @@ abstract contract FastBridgeV2Test is Test, IFastBridgeV2Errors { tokenTx.callParams = callParams; } + function setTokenTestCallValue(uint256 callValue) public { + tokenParamsV2.callValue = callValue; + tokenTx.callValue = callValue; + } + function setTokenTestExclusivityParams(address relayer, uint256 exclusivitySeconds) public { tokenParamsV2.quoteRelayer = relayer; tokenParamsV2.quoteExclusivitySeconds = int256(exclusivitySeconds); @@ -183,6 +188,11 @@ abstract contract FastBridgeV2Test is Test, IFastBridgeV2Errors { ethTx.callParams = callParams; } + function setEthTestCallValue(uint256 callValue) public { + ethParamsV2.callValue = callValue; + ethTx.callValue = callValue; + } + function setEthTestExclusivityParams(address relayer, uint256 exclusivitySeconds) public { ethParamsV2.quoteRelayer = relayer; ethParamsV2.quoteExclusivitySeconds = int256(exclusivitySeconds); From c93c403e77dc7af05a4b5885a825949a2b4f60ba Mon Sep 17 00:00:00 2001 From: ChiTimesChi <88190723+ChiTimesChi@users.noreply.github.com> Date: Thu, 3 Oct 2024 12:49:27 +0100 Subject: [PATCH 04/85] refactor: simplify tests further --- .../test/FastBridgeV2.Dst.Exclusivity.t.sol | 23 ++----------- .../contracts-rfq/test/FastBridgeV2.Dst.t.sol | 32 ++++++++++--------- 2 files changed, 20 insertions(+), 35 deletions(-) diff --git a/packages/contracts-rfq/test/FastBridgeV2.Dst.Exclusivity.t.sol b/packages/contracts-rfq/test/FastBridgeV2.Dst.Exclusivity.t.sol index 7926b3d362..ba66ae53c4 100644 --- a/packages/contracts-rfq/test/FastBridgeV2.Dst.Exclusivity.t.sol +++ b/packages/contracts-rfq/test/FastBridgeV2.Dst.Exclusivity.t.sol @@ -1,32 +1,15 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.20; -import {FastBridgeV2DstTest, IFastBridgeV2} from "./FastBridgeV2.Dst.t.sol"; +import {FastBridgeV2DstTest} from "./FastBridgeV2.Dst.t.sol"; // solhint-disable func-name-mixedcase, ordering contract FastBridgeV2DstExclusivityTest is FastBridgeV2DstTest { uint256 public constant EXCLUSIVITY_PERIOD = 60 seconds; function createFixturesV2() public virtual override { - tokenParamsV2 = IFastBridgeV2.BridgeParamsV2({ - quoteRelayer: relayerA, - quoteExclusivitySeconds: int256(EXCLUSIVITY_PERIOD), - quoteId: "", - callValue: 0, - callParams: "" - }); - ethParamsV2 = IFastBridgeV2.BridgeParamsV2({ - quoteRelayer: relayerB, - quoteExclusivitySeconds: int256(EXCLUSIVITY_PERIOD), - quoteId: "", - callValue: 0, - callParams: "" - }); - - tokenTx.exclusivityRelayer = relayerA; - tokenTx.exclusivityEndTime = block.timestamp + EXCLUSIVITY_PERIOD; - ethTx.exclusivityRelayer = relayerB; - ethTx.exclusivityEndTime = block.timestamp + EXCLUSIVITY_PERIOD; + setTokenTestExclusivityParams(relayerA, EXCLUSIVITY_PERIOD); + setEthTestExclusivityParams(relayerB, EXCLUSIVITY_PERIOD); } // ═══════════════════════════════════════════════ RELAY: TOKEN ════════════════════════════════════════════════════ diff --git a/packages/contracts-rfq/test/FastBridgeV2.Dst.t.sol b/packages/contracts-rfq/test/FastBridgeV2.Dst.t.sol index 89ef62af91..1463efa2e0 100644 --- a/packages/contracts-rfq/test/FastBridgeV2.Dst.t.sol +++ b/packages/contracts-rfq/test/FastBridgeV2.Dst.t.sol @@ -89,15 +89,25 @@ contract FastBridgeV2DstTest is FastBridgeV2DstBaseTest { assertEq(relayer, expectedRelayer); } + function checkTokenBalances(address recipient, address relayCaller) public view { + assertEq(dstToken.balanceOf(recipient), tokenParams.destAmount); + assertEq(dstToken.balanceOf(relayCaller), LEFTOVER_BALANCE); + assertEq(dstToken.balanceOf(address(fastBridge)), 0); + } + + function checkEthBalances(address recipient, address relayCaller) public view { + assertEq(recipient.balance, ethParams.destAmount); + assertEq(relayCaller.balance, LEFTOVER_BALANCE); + assertEq(address(fastBridge).balance, 0); + } + /// @notice RelayerA completes the ERC20 bridge request function test_relay_token() public { bytes32 txId = getTxId(tokenTx); expectBridgeRelayed(tokenTx, txId, relayerA); relay({caller: relayerA, msgValue: 0, bridgeTx: tokenTx}); checkRelayedViews({txId: txId, expectedRelayer: relayerA}); - assertEq(dstToken.balanceOf(userB), tokenParams.destAmount); - assertEq(dstToken.balanceOf(relayerA), LEFTOVER_BALANCE); - assertEq(dstToken.balanceOf(address(fastBridge)), 0); + checkTokenBalances({recipient: userB, relayCaller: relayerA}); } /// @notice RelayerB completes the ERC20 bridge request, using relayerA's address @@ -106,9 +116,7 @@ contract FastBridgeV2DstTest is FastBridgeV2DstBaseTest { expectBridgeRelayed(tokenTx, txId, relayerA); relayWithAddress({caller: relayerB, relayer: relayerA, msgValue: 0, bridgeTx: tokenTx}); checkRelayedViews({txId: txId, expectedRelayer: relayerA}); - assertEq(dstToken.balanceOf(userB), tokenParams.destAmount); - assertEq(dstToken.balanceOf(relayerB), LEFTOVER_BALANCE); - assertEq(dstToken.balanceOf(address(fastBridge)), 0); + checkTokenBalances({recipient: userB, relayCaller: relayerB}); } /// @notice RelayerB completes the ETH bridge request @@ -117,9 +125,7 @@ contract FastBridgeV2DstTest is FastBridgeV2DstBaseTest { expectBridgeRelayed(ethTx, txId, relayerB); relay({caller: relayerB, msgValue: ethParams.destAmount, bridgeTx: ethTx}); checkRelayedViews({txId: txId, expectedRelayer: relayerB}); - assertEq(userB.balance, ethParams.destAmount); - assertEq(relayerB.balance, LEFTOVER_BALANCE); - assertEq(address(fastBridge).balance, 0); + checkEthBalances({recipient: userB, relayCaller: relayerB}); } /// @notice RelayerA completes the ETH bridge request, using relayerB's address @@ -128,9 +134,7 @@ contract FastBridgeV2DstTest is FastBridgeV2DstBaseTest { expectBridgeRelayed(ethTx, txId, relayerB); relayWithAddress({caller: relayerA, relayer: relayerB, msgValue: ethParams.destAmount, bridgeTx: ethTx}); checkRelayedViews({txId: txId, expectedRelayer: relayerB}); - assertEq(userB.balance, ethParams.destAmount); - assertEq(relayerA.balance, LEFTOVER_BALANCE); - assertEq(address(fastBridge).balance, 0); + checkEthBalances({recipient: userB, relayCaller: relayerA}); } /// @notice RelayerA completes the ETH bridge request, using relayerB's address @@ -146,9 +150,7 @@ contract FastBridgeV2DstTest is FastBridgeV2DstBaseTest { assertEq(recordedBlockNumber, 987_654_321); assertEq(recordedBlockTimestamp, 123_456_789); assertEq(recordedRelayer, relayerB); - assertEq(userB.balance, ethParams.destAmount); - assertEq(relayerA.balance, LEFTOVER_BALANCE); - assertEq(address(fastBridge).balance, 0); + checkEthBalances({recipient: userB, relayCaller: relayerA}); } // ═════════════════════════════════════ EXCESSIVE RETURN VALUE RECIPIENT ══════════════════════════════════════════ From 957524679f2d2f3c85068db55e42d1e489ceb3ef Mon Sep 17 00:00:00 2001 From: ChiTimesChi <88190723+ChiTimesChi@users.noreply.github.com> Date: Thu, 3 Oct 2024 13:21:57 +0100 Subject: [PATCH 05/85] test: add cases for DST relays with `callValue` --- .../test/FastBridgeV2.Dst.ArbitraryCall.t.sol | 101 +++++++++- .../contracts-rfq/test/FastBridgeV2.Dst.t.sol | 175 +++++++++++++++++- 2 files changed, 274 insertions(+), 2 deletions(-) diff --git a/packages/contracts-rfq/test/FastBridgeV2.Dst.ArbitraryCall.t.sol b/packages/contracts-rfq/test/FastBridgeV2.Dst.ArbitraryCall.t.sol index af4f6235c6..d48420dba0 100644 --- a/packages/contracts-rfq/test/FastBridgeV2.Dst.ArbitraryCall.t.sol +++ b/packages/contracts-rfq/test/FastBridgeV2.Dst.ArbitraryCall.t.sol @@ -1,7 +1,8 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.20; -import {FastBridgeV2DstExclusivityTest, IFastBridgeV2} from "./FastBridgeV2.Dst.Exclusivity.t.sol"; +import {IFastBridgeV2} from "../contracts/interfaces/IFastBridgeV2.sol"; +import {FastBridgeV2DstExclusivityTest} from "./FastBridgeV2.Dst.Exclusivity.t.sol"; import {RecipientMock} from "./mocks/RecipientMock.sol"; import {Address} from "@openzeppelin/contracts/utils/Address.sol"; @@ -98,6 +99,28 @@ contract FastBridgeV2DstArbitraryCallTest is FastBridgeV2DstExclusivityTest { relayWithAddress({caller: relayerB, relayer: relayerA, msgValue: 0, bridgeTx: tokenTx}); } + function test_relay_token_withCallValue_excessiveReturnValueRecipient_revertWhenCallParamsPresent() + public + virtual + override + { + setTokenTestCallValue(CALL_VALUE); + setTokenTestRecipient(excessiveReturnValueRecipient); + vm.expectRevert(RecipientIncorrectReturnValue.selector); + relay({caller: relayerA, msgValue: CALL_VALUE, bridgeTx: tokenTx}); + } + + function test_relay_token_withRelayerAddressCallValue_excessiveReturnValueRecipient_revertWhenCallParamsPresent() + public + virtual + override + { + setTokenTestCallValue(CALL_VALUE); + setTokenTestRecipient(excessiveReturnValueRecipient); + vm.expectRevert(RecipientIncorrectReturnValue.selector); + relayWithAddress({caller: relayerB, relayer: relayerA, msgValue: CALL_VALUE, bridgeTx: tokenTx}); + } + function test_relay_eth_excessiveReturnValueRecipient_revertWhenCallParamsPresent() public virtual override { setEthTestRecipient(excessiveReturnValueRecipient); vm.expectRevert(RecipientIncorrectReturnValue.selector); @@ -132,6 +155,28 @@ contract FastBridgeV2DstArbitraryCallTest is FastBridgeV2DstExclusivityTest { relayWithAddress({caller: relayerB, relayer: relayerA, msgValue: 0, bridgeTx: tokenTx}); } + function test_relay_token_withCallValue_incorrectReturnValueRecipient_revertWhenCallParamsPresent() + public + virtual + override + { + setTokenTestCallValue(CALL_VALUE); + setTokenTestRecipient(incorrectReturnValueRecipient); + vm.expectRevert(RecipientIncorrectReturnValue.selector); + relay({caller: relayerA, msgValue: CALL_VALUE, bridgeTx: tokenTx}); + } + + function test_relay_token_withRelayerAddressCallValue_incorrectReturnValueRecipient_revertWhenCallParamsPresent() + public + virtual + override + { + setTokenTestCallValue(CALL_VALUE); + setTokenTestRecipient(incorrectReturnValueRecipient); + vm.expectRevert(RecipientIncorrectReturnValue.selector); + relayWithAddress({caller: relayerB, relayer: relayerA, msgValue: CALL_VALUE, bridgeTx: tokenTx}); + } + function test_relay_eth_incorrectReturnValueRecipient_revertWhenCallParamsPresent() public virtual override { setEthTestRecipient(incorrectReturnValueRecipient); vm.expectRevert(RecipientIncorrectReturnValue.selector); @@ -162,6 +207,24 @@ contract FastBridgeV2DstArbitraryCallTest is FastBridgeV2DstExclusivityTest { relayWithAddress({caller: relayerB, relayer: relayerA, msgValue: 0, bridgeTx: tokenTx}); } + function test_relay_token_withCallValue_noOpRecipient_revertWhenCallParamsPresent() public virtual override { + setTokenTestCallValue(CALL_VALUE); + setTokenTestRecipient(noOpRecipient); + vm.expectRevert(Address.FailedInnerCall.selector); + relay({caller: relayerA, msgValue: CALL_VALUE, bridgeTx: tokenTx}); + } + + function test_relay_token_withRelayerAddressCallValue_noOpRecipient_revertWhenCallParamsPresent() + public + virtual + override + { + setTokenTestCallValue(CALL_VALUE); + setTokenTestRecipient(noOpRecipient); + vm.expectRevert(Address.FailedInnerCall.selector); + relayWithAddress({caller: relayerB, relayer: relayerA, msgValue: CALL_VALUE, bridgeTx: tokenTx}); + } + function test_relay_eth_noOpRecipient_revertWhenCallParamsPresent() public virtual override { setEthTestRecipient(noOpRecipient); vm.expectRevert(Address.FailedInnerCall.selector); @@ -192,6 +255,28 @@ contract FastBridgeV2DstArbitraryCallTest is FastBridgeV2DstExclusivityTest { relayWithAddress({caller: relayerB, relayer: relayerA, msgValue: 0, bridgeTx: tokenTx}); } + function test_relay_token_withCallValue_noReturnValueRecipient_revertWhenCallParamsPresent() + public + virtual + override + { + setTokenTestCallValue(CALL_VALUE); + setTokenTestRecipient(noReturnValueRecipient); + vm.expectRevert(RecipientNoReturnValue.selector); + relay({caller: relayerA, msgValue: CALL_VALUE, bridgeTx: tokenTx}); + } + + function test_relay_token_withRelayerAddressCallValue_noReturnValueRecipient_revertWhenCallParamsPresent() + public + virtual + override + { + setTokenTestCallValue(CALL_VALUE); + setTokenTestRecipient(noReturnValueRecipient); + vm.expectRevert(RecipientNoReturnValue.selector); + relayWithAddress({caller: relayerB, relayer: relayerA, msgValue: CALL_VALUE, bridgeTx: tokenTx}); + } + function test_relay_eth_noReturnValueRecipient_revertWhenCallParamsPresent() public virtual override { setEthTestRecipient(noReturnValueRecipient); vm.expectRevert(RecipientNoReturnValue.selector); @@ -222,6 +307,20 @@ contract FastBridgeV2DstArbitraryCallTest is FastBridgeV2DstExclusivityTest { relayWithAddress({caller: relayerB, relayer: relayerA, msgValue: 0, bridgeTx: tokenTx}); } + function test_relay_token_withCallValue_revert_recipientReverts() public { + setTokenTestCallValue(CALL_VALUE); + mockRecipientRevert(tokenTx); + vm.expectRevert(REVERT_MSG); + relay({caller: relayerA, msgValue: CALL_VALUE, bridgeTx: tokenTx}); + } + + function test_relay_token_withRelayerAddressCallValue_revert_recipientReverts() public { + setTokenTestCallValue(CALL_VALUE); + mockRecipientRevert(tokenTx); + vm.expectRevert(REVERT_MSG); + relayWithAddress({caller: relayerB, relayer: relayerA, msgValue: CALL_VALUE, bridgeTx: tokenTx}); + } + function test_relay_eth_revert_recipientReverts() public { mockRecipientRevert(ethTx); vm.expectRevert(REVERT_MSG); diff --git a/packages/contracts-rfq/test/FastBridgeV2.Dst.t.sol b/packages/contracts-rfq/test/FastBridgeV2.Dst.t.sol index 1463efa2e0..a3a0f95556 100644 --- a/packages/contracts-rfq/test/FastBridgeV2.Dst.t.sol +++ b/packages/contracts-rfq/test/FastBridgeV2.Dst.t.sol @@ -23,6 +23,8 @@ contract FastBridgeV2DstTest is FastBridgeV2DstBaseTest { uint256 chainGasAmount ); + uint256 public constant CALL_VALUE = 1_337_420; + address public excessiveReturnValueRecipient; address public incorrectReturnValueRecipient; address public noOpRecipient; @@ -67,6 +69,7 @@ contract FastBridgeV2DstTest is FastBridgeV2DstBaseTest { public virtual { + uint256 chainGasAmount = bridgeTx.destToken == ETH_ADDRESS ? 0 : bridgeTx.callValue; vm.expectEmit(address(fastBridge)); emit BridgeRelayed({ transactionId: txId, @@ -77,7 +80,7 @@ contract FastBridgeV2DstTest is FastBridgeV2DstBaseTest { destToken: bridgeTx.destToken, originAmount: bridgeTx.originAmount, destAmount: bridgeTx.destAmount, - chainGasAmount: 0 + chainGasAmount: chainGasAmount }); } @@ -153,6 +156,28 @@ contract FastBridgeV2DstTest is FastBridgeV2DstBaseTest { checkEthBalances({recipient: userB, relayCaller: relayerA}); } + // ══════════════════════════════════════════ RELAYS WITH CALL VALUE ═══════════════════════════════════════════════ + + function test_relay_token_withCallValue() public { + setTokenTestCallValue(CALL_VALUE); + bytes32 txId = getTxId(tokenTx); + expectBridgeRelayed(tokenTx, txId, relayerA); + relay({caller: relayerA, msgValue: CALL_VALUE, bridgeTx: tokenTx}); + checkRelayedViews({txId: txId, expectedRelayer: relayerA}); + checkTokenBalances({recipient: userB, relayCaller: relayerA}); + assertEq(userB.balance, CALL_VALUE); + } + + function test_relay_token_withRelayerAddressCallValue() public { + setTokenTestCallValue(CALL_VALUE); + bytes32 txId = getTxId(tokenTx); + expectBridgeRelayed(tokenTx, txId, relayerA); + relayWithAddress({caller: relayerB, relayer: relayerA, msgValue: CALL_VALUE, bridgeTx: tokenTx}); + checkRelayedViews({txId: txId, expectedRelayer: relayerA}); + checkTokenBalances({recipient: userB, relayCaller: relayerB}); + assertEq(userB.balance, CALL_VALUE); + } + // ═════════════════════════════════════ EXCESSIVE RETURN VALUE RECIPIENT ══════════════════════════════════════════ // Note: in this test, the callParams are not present, and the below test functions succeed. @@ -173,6 +198,26 @@ contract FastBridgeV2DstTest is FastBridgeV2DstBaseTest { test_relay_token_withRelayerAddress(); } + function test_relay_token_withCallValue_excessiveReturnValueRecipient_revertWhenCallParamsPresent() + public + virtual + { + assertEmptyCallParams(tokenTx.callParams); + setTokenTestCallValue(CALL_VALUE); + setTokenTestRecipient(excessiveReturnValueRecipient); + test_relay_token_withCallValue(); + } + + function test_relay_token_withRelayerAddressCallValue_excessiveReturnValueRecipient_revertWhenCallParamsPresent() + public + virtual + { + assertEmptyCallParams(tokenTx.callParams); + setTokenTestCallValue(CALL_VALUE); + setTokenTestRecipient(excessiveReturnValueRecipient); + test_relay_token_withRelayerAddressCallValue(); + } + function test_relay_eth_excessiveReturnValueRecipient_revertWhenCallParamsPresent() public virtual { assertEmptyCallParams(ethTx.callParams); setEthTestRecipient(excessiveReturnValueRecipient); @@ -208,6 +253,26 @@ contract FastBridgeV2DstTest is FastBridgeV2DstBaseTest { test_relay_token_withRelayerAddress(); } + function test_relay_token_withCallValue_incorrectReturnValueRecipient_revertWhenCallParamsPresent() + public + virtual + { + assertEmptyCallParams(tokenTx.callParams); + setTokenTestCallValue(CALL_VALUE); + setTokenTestRecipient(incorrectReturnValueRecipient); + test_relay_token_withCallValue(); + } + + function test_relay_token_withRelayerAddressCallValue_incorrectReturnValueRecipient_revertWhenCallParamsPresent() + public + virtual + { + assertEmptyCallParams(tokenTx.callParams); + setTokenTestCallValue(CALL_VALUE); + setTokenTestRecipient(incorrectReturnValueRecipient); + test_relay_token_withRelayerAddressCallValue(); + } + function test_relay_eth_incorrectReturnValueRecipient_revertWhenCallParamsPresent() public virtual { assertEmptyCallParams(ethTx.callParams); setEthTestRecipient(incorrectReturnValueRecipient); @@ -236,6 +301,20 @@ contract FastBridgeV2DstTest is FastBridgeV2DstBaseTest { test_relay_token_withRelayerAddress(); } + function test_relay_token_withCallValue_nonPayableRecipient_revert() public { + setTokenTestCallValue(CALL_VALUE); + setTokenTestRecipient(nonPayableRecipient); + vm.expectRevert(); + relay({caller: relayerA, msgValue: CALL_VALUE, bridgeTx: tokenTx}); + } + + function test_relay_token_withRelayerAddressCallValue_nonPayableRecipient_revert() public { + setTokenTestCallValue(CALL_VALUE); + setTokenTestRecipient(nonPayableRecipient); + vm.expectRevert(); + relayWithAddress({caller: relayerB, relayer: relayerA, msgValue: CALL_VALUE, bridgeTx: tokenTx}); + } + function test_relay_eth_revert_nonPayableRecipient() public { setEthTestRecipient(nonPayableRecipient); vm.expectRevert(); @@ -265,6 +344,20 @@ contract FastBridgeV2DstTest is FastBridgeV2DstBaseTest { test_relay_token_withRelayerAddress(); } + function test_relay_token_withCallValue_noOpRecipient_revertWhenCallParamsPresent() public virtual { + assertEmptyCallParams(tokenTx.callParams); + setTokenTestCallValue(CALL_VALUE); + setTokenTestRecipient(noOpRecipient); + test_relay_token_withCallValue(); + } + + function test_relay_token_withRelayerAddressCallValue_noOpRecipient_revertWhenCallParamsPresent() public virtual { + assertEmptyCallParams(tokenTx.callParams); + setTokenTestCallValue(CALL_VALUE); + setTokenTestRecipient(noOpRecipient); + test_relay_token_withRelayerAddressCallValue(); + } + function test_relay_eth_noOpRecipient_revertWhenCallParamsPresent() public virtual { assertEmptyCallParams(ethTx.callParams); setEthTestRecipient(noOpRecipient); @@ -294,6 +387,23 @@ contract FastBridgeV2DstTest is FastBridgeV2DstBaseTest { test_relay_token_withRelayerAddress(); } + function test_relay_token_withCallValue_noReturnValueRecipient_revertWhenCallParamsPresent() public virtual { + assertEmptyCallParams(tokenTx.callParams); + setTokenTestCallValue(CALL_VALUE); + setTokenTestRecipient(noReturnValueRecipient); + test_relay_token_withCallValue(); + } + + function test_relay_token_withRelayerAddressCallValue_noReturnValueRecipient_revertWhenCallParamsPresent() + public + virtual + { + assertEmptyCallParams(tokenTx.callParams); + setTokenTestCallValue(CALL_VALUE); + setTokenTestRecipient(noReturnValueRecipient); + test_relay_token_withRelayerAddressCallValue(); + } + function test_relay_eth_noReturnValueRecipient_revertWhenCallParamsPresent() public virtual { assertEmptyCallParams(ethTx.callParams); setEthTestRecipient(noReturnValueRecipient); @@ -362,4 +472,67 @@ contract FastBridgeV2DstTest is FastBridgeV2DstBaseTest { vm.expectRevert(ZeroAddress.selector); relayWithAddress({caller: relayerA, relayer: address(0), msgValue: 0, bridgeTx: tokenTx}); } + + function test_relay_token_withCallValue_revert_zeroCallValue() public { + setTokenTestCallValue(CALL_VALUE); + vm.expectRevert(MsgValueIncorrect.selector); + relay({caller: relayerA, msgValue: 0, bridgeTx: tokenTx}); + } + + function test_relay_token_withCallValue_revert_lowerCallValue() public { + setTokenTestCallValue(CALL_VALUE); + vm.expectRevert(MsgValueIncorrect.selector); + relay({caller: relayerA, msgValue: CALL_VALUE - 1, bridgeTx: tokenTx}); + } + + function test_relay_token_withCallValue_revert_higherCallValue() public { + setTokenTestCallValue(CALL_VALUE); + vm.expectRevert(MsgValueIncorrect.selector); + relay({caller: relayerA, msgValue: CALL_VALUE + 1, bridgeTx: tokenTx}); + } + + function test_relay_token_withRelayerAddressCallValue_revert_zeroCallValue() public { + setTokenTestCallValue(CALL_VALUE); + vm.expectRevert(MsgValueIncorrect.selector); + relayWithAddress({caller: relayerB, relayer: relayerA, msgValue: 0, bridgeTx: tokenTx}); + } + + function test_relay_token_withRelayerAddressCallValue_revert_lowerCallValue() public { + setTokenTestCallValue(CALL_VALUE); + vm.expectRevert(MsgValueIncorrect.selector); + relayWithAddress({caller: relayerB, relayer: relayerA, msgValue: CALL_VALUE - 1, bridgeTx: tokenTx}); + } + + function test_relay_token_withRelayerAddressCallValue_revert_higherCallValue() public { + setTokenTestCallValue(CALL_VALUE); + vm.expectRevert(MsgValueIncorrect.selector); + relayWithAddress({caller: relayerB, relayer: relayerA, msgValue: CALL_VALUE + 1, bridgeTx: tokenTx}); + } + + function test_relay_eth_withCallValue_revert_notSupported() public { + setEthTestCallValue(CALL_VALUE); + // Neither destAmount, CALL_VALUE, nor destAmount + CALL_VALUE should work here + vm.expectRevert(NativeTokenCallValueNotSupported.selector); + relay({caller: relayerB, msgValue: CALL_VALUE, bridgeTx: ethTx}); + vm.expectRevert(NativeTokenCallValueNotSupported.selector); + relay({caller: relayerB, msgValue: ethParams.destAmount, bridgeTx: ethTx}); + vm.expectRevert(NativeTokenCallValueNotSupported.selector); + relay({caller: relayerB, msgValue: ethParams.destAmount + CALL_VALUE, bridgeTx: ethTx}); + } + + function test_relay_eth_withRelayerAddressCallValue_revert_notSupported() public { + setEthTestCallValue(CALL_VALUE); + // Neither destAmount, CALL_VALUE, nor destAmount + CALL_VALUE should work here + vm.expectRevert(NativeTokenCallValueNotSupported.selector); + relayWithAddress({caller: relayerA, relayer: relayerB, msgValue: CALL_VALUE, bridgeTx: ethTx}); + vm.expectRevert(NativeTokenCallValueNotSupported.selector); + relayWithAddress({caller: relayerA, relayer: relayerB, msgValue: ethParams.destAmount, bridgeTx: ethTx}); + vm.expectRevert(NativeTokenCallValueNotSupported.selector); + relayWithAddress({ + caller: relayerA, + relayer: relayerB, + msgValue: ethParams.destAmount + CALL_VALUE, + bridgeTx: ethTx + }); + } } From 7872f2a6d547d32ad1ed641b4d7484cf6231c505 Mon Sep 17 00:00:00 2001 From: ChiTimesChi <88190723+ChiTimesChi@users.noreply.github.com> Date: Thu, 3 Oct 2024 13:29:04 +0100 Subject: [PATCH 06/85] feat: support `callValue` in `bridge()` --- .../contracts-rfq/contracts/FastBridgeV2.sol | 27 ++++++++++--------- 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/packages/contracts-rfq/contracts/FastBridgeV2.sol b/packages/contracts-rfq/contracts/FastBridgeV2.sol index 20ef419645..970bff70af 100644 --- a/packages/contracts-rfq/contracts/FastBridgeV2.sol +++ b/packages/contracts-rfq/contracts/FastBridgeV2.sol @@ -147,6 +147,9 @@ contract FastBridgeV2 is Admin, IFastBridgeV2, IFastBridgeV2Errors { if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress(); if (params.deadline < block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort(); if (paramsV2.callParams.length > MAX_CALL_PARAMS_LENGTH) revert CallParamsLengthAboveMax(); + if (paramsV2.callValue != 0 && params.destToken == UniversalTokenLib.ETH_ADDRESS) { + revert NativeTokenCallValueNotSupported(); + } int256 exclusivityEndTime = int256(block.timestamp) + paramsV2.quoteExclusivitySeconds; // exclusivityEndTime must be in range (0 .. params.deadline] if (exclusivityEndTime <= 0 || exclusivityEndTime > int256(params.deadline)) { @@ -173,7 +176,7 @@ contract FastBridgeV2 is Admin, IFastBridgeV2, IFastBridgeV2Errors { originAmount: originAmount, destAmount: params.destAmount, originFeeAmount: originFeeAmount, - callValue: 0, // TODO: fix + callValue: paramsV2.callValue, deadline: params.deadline, nonce: senderNonces[params.sender]++, // increment nonce on every bridge exclusivityRelayer: paramsV2.quoteRelayer, @@ -185,17 +188,17 @@ contract FastBridgeV2 is Admin, IFastBridgeV2, IFastBridgeV2Errors { bytes32 transactionId = keccak256(request); bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED; - emit BridgeRequested( - transactionId, - params.sender, - request, - params.dstChainId, - params.originToken, - params.destToken, - originAmount, - params.destAmount, - params.sendChainGas - ); + emit BridgeRequested({ + transactionId: transactionId, + sender: params.sender, + request: request, + destChainId: params.dstChainId, + originToken: params.originToken, + destToken: params.destToken, + originAmount: originAmount, + destAmount: params.destAmount, + sendChainGas: paramsV2.callValue != 0 + }); emit BridgeQuoteDetails(transactionId, paramsV2.quoteId); } From ad7dd4c304bd62ed70c4b97de5d9317358c7c19b Mon Sep 17 00:00:00 2001 From: ChiTimesChi <88190723+ChiTimesChi@users.noreply.github.com> Date: Thu, 3 Oct 2024 13:49:54 +0100 Subject: [PATCH 07/85] feat: support `callValue` in `relay()` --- .../contracts-rfq/contracts/FastBridgeV2.sol | 61 ++++++++++--------- 1 file changed, 31 insertions(+), 30 deletions(-) diff --git a/packages/contracts-rfq/contracts/FastBridgeV2.sol b/packages/contracts-rfq/contracts/FastBridgeV2.sol index 970bff70af..a5887761b0 100644 --- a/packages/contracts-rfq/contracts/FastBridgeV2.sol +++ b/packages/contracts-rfq/contracts/FastBridgeV2.sol @@ -228,51 +228,52 @@ contract FastBridgeV2 is Admin, IFastBridgeV2, IFastBridgeV2Errors { bridgeRelayDetails[transactionId] = BridgeRelay({blockNumber: uint48(block.number), blockTimestamp: uint48(block.timestamp), relayer: relayer}); - // transfer tokens to recipient on destination chain and gas rebate if requested + // transfer tokens to recipient on destination chain and do an arbitrary call if requested address to = transaction.destRecipient; address token = transaction.destToken; uint256 amount = transaction.destAmount; // All state changes have been done at this point, can proceed to the external calls. // This follows the checks-effects-interactions pattern to mitigate potential reentrancy attacks. - if (transaction.callParams.length == 0) { - // No arbitrary call requested, so we just pull the tokens from the Relayer to the recipient, - // or transfer ETH to the recipient (if token is ETH_ADDRESS) - _pullToken(to, token, amount); - } else if (token != UniversalTokenLib.ETH_ADDRESS) { - // Arbitrary call requested with ERC20: pull the tokens from the Relayer to the recipient first - _pullToken(to, token, amount); - // Follow up with the hook function call - _checkedCallRecipient({ - recipient: to, - msgValue: 0, - token: token, - amount: amount, - callParams: transaction.callParams - }); + if (token == UniversalTokenLib.ETH_ADDRESS) { + // For ETH non-zero callValue is not allowed + if (transaction.callValue != 0) revert NativeTokenCallValueNotSupported(); + // Check that the correct msg.value was sent + if (msg.value != amount) revert MsgValueIncorrect(); } else { - // Arbitrary call requested with ETH: combine the ETH transfer with the call + // For ERC20s, we check that the correct msg.value was sent + if (msg.value != transaction.callValue) revert MsgValueIncorrect(); + // We need to pull the tokens from the Relayer to the recipient first before performing an + // optional post-transfer arbitrary call. + _pullToken(to, token, amount); + } + + if (transaction.callParams.length != 0) { + // Arbitrary call requested, perform it while supplying full msg.value to the recipient _checkedCallRecipient({ recipient: to, - msgValue: amount, + msgValue: msg.value, token: token, amount: amount, callParams: transaction.callParams }); + } else if (msg.value != 0) { + // No arbitrary call requested, but msg.value was sent. This is either a relay with ETH, + // or a non-zero callValue request with an ERC20. In both cases, transfer the ETH to the recipient. + Address.sendValue(payable(to), msg.value); } - emit BridgeRelayed( - transactionId, - relayer, - to, - transaction.originChainId, - transaction.originToken, - transaction.destToken, - transaction.originAmount, - transaction.destAmount, - // chainGasAmount is 0 since the gas rebate function is deprecated - 0 - ); + emit BridgeRelayed({ + transactionId: transactionId, + relayer: relayer, + to: to, + originChainId: transaction.originChainId, + originToken: transaction.originToken, + destToken: transaction.destToken, + originAmount: transaction.originAmount, + destAmount: transaction.destAmount, + chainGasAmount: transaction.callValue + }); } /// @inheritdoc IFastBridgeV2 From 5ca5ad1979b5cb60a67fefa4e6699b6cf50f979d Mon Sep 17 00:00:00 2001 From: ChiTimesChi <88190723+ChiTimesChi@users.noreply.github.com> Date: Thu, 3 Oct 2024 13:52:19 +0100 Subject: [PATCH 08/85] test: update revert message for failed ETH transfers --- .../contracts-rfq/test/FastBridgeV2.Dst.ArbitraryCall.t.sol | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/contracts-rfq/test/FastBridgeV2.Dst.ArbitraryCall.t.sol b/packages/contracts-rfq/test/FastBridgeV2.Dst.ArbitraryCall.t.sol index d48420dba0..1bd47fba4b 100644 --- a/packages/contracts-rfq/test/FastBridgeV2.Dst.ArbitraryCall.t.sol +++ b/packages/contracts-rfq/test/FastBridgeV2.Dst.ArbitraryCall.t.sol @@ -336,14 +336,14 @@ contract FastBridgeV2DstArbitraryCallTest is FastBridgeV2DstExclusivityTest { function test_relay_eth_noCallParams_revert_recipientReverts() public { setEthTestCallParams(""); vm.mockCallRevert({callee: userB, data: "", revertData: bytes(REVERT_MSG)}); - vm.expectRevert("ETH transfer failed"); + vm.expectRevert(Address.FailedInnerCall.selector); relay({caller: relayerB, msgValue: ethParams.destAmount, bridgeTx: ethTx}); } function test_relay_eth_withRelayerAddress_noCallParams_revert_recipientReverts() public { setEthTestCallParams(""); vm.mockCallRevert({callee: userB, data: "", revertData: bytes(REVERT_MSG)}); - vm.expectRevert("ETH transfer failed"); + vm.expectRevert(Address.FailedInnerCall.selector); relayWithAddress({caller: relayerA, relayer: relayerB, msgValue: ethParams.destAmount, bridgeTx: ethTx}); } } From e8355c327618ec34ed799f413c67091fe22c4dbd Mon Sep 17 00:00:00 2001 From: ChiTimesChi <88190723+ChiTimesChi@users.noreply.github.com> Date: Thu, 3 Oct 2024 13:53:45 +0100 Subject: [PATCH 09/85] refactor: always forward full msg.value for the hook call --- packages/contracts-rfq/contracts/FastBridgeV2.sol | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/packages/contracts-rfq/contracts/FastBridgeV2.sol b/packages/contracts-rfq/contracts/FastBridgeV2.sol index a5887761b0..15c1431f89 100644 --- a/packages/contracts-rfq/contracts/FastBridgeV2.sol +++ b/packages/contracts-rfq/contracts/FastBridgeV2.sol @@ -250,13 +250,7 @@ contract FastBridgeV2 is Admin, IFastBridgeV2, IFastBridgeV2Errors { if (transaction.callParams.length != 0) { // Arbitrary call requested, perform it while supplying full msg.value to the recipient - _checkedCallRecipient({ - recipient: to, - msgValue: msg.value, - token: token, - amount: amount, - callParams: transaction.callParams - }); + _checkedCallRecipient({recipient: to, token: token, amount: amount, callParams: transaction.callParams}); } else if (msg.value != 0) { // No arbitrary call requested, but msg.value was sent. This is either a relay with ETH, // or a non-zero callValue request with an ERC20. In both cases, transfer the ETH to the recipient. @@ -366,7 +360,6 @@ contract FastBridgeV2 is Admin, IFastBridgeV2, IFastBridgeV2Errors { /// all the necessary checks for the returned value. function _checkedCallRecipient( address recipient, - uint256 msgValue, address token, uint256 amount, bytes memory callParams @@ -376,7 +369,7 @@ contract FastBridgeV2 is Admin, IFastBridgeV2, IFastBridgeV2Errors { bytes memory hookData = abi.encodeCall(IFastBridgeRecipient.fastBridgeTransferReceived, (token, amount, callParams)); // This will bubble any revert messages from the hook function - bytes memory returnData = Address.functionCallWithValue({target: recipient, data: hookData, value: msgValue}); + bytes memory returnData = Address.functionCallWithValue({target: recipient, data: hookData, value: msg.value}); // Explicit revert if no return data at all if (returnData.length == 0) revert RecipientNoReturnValue(); // Check that exactly a single return value was returned From eb2bbb8025778b635569c768e234df48c8327b3f Mon Sep 17 00:00:00 2001 From: ChiTimesChi <88190723+ChiTimesChi@users.noreply.github.com> Date: Thu, 3 Oct 2024 14:01:39 +0100 Subject: [PATCH 10/85] refactor: use `_pullToken` only in `bridge()` --- .../contracts-rfq/contracts/FastBridgeV2.sol | 34 +++++++++---------- 1 file changed, 16 insertions(+), 18 deletions(-) diff --git a/packages/contracts-rfq/contracts/FastBridgeV2.sol b/packages/contracts-rfq/contracts/FastBridgeV2.sol index 15c1431f89..b2653bd401 100644 --- a/packages/contracts-rfq/contracts/FastBridgeV2.sol +++ b/packages/contracts-rfq/contracts/FastBridgeV2.sol @@ -156,8 +156,8 @@ contract FastBridgeV2 is Admin, IFastBridgeV2, IFastBridgeV2Errors { revert ExclusivityParamsIncorrect(); } // transfer tokens to bridge contract - // @dev use returned originAmount in request in case of transfer fees - uint256 originAmount = _pullToken(address(this), params.originToken, params.originAmount); + /// @dev use returned originAmount in request in case of transfer fees + uint256 originAmount = _pullToken(params.originToken, params.originAmount); // track amount of origin token owed to protocol uint256 originFeeAmount; @@ -243,13 +243,15 @@ contract FastBridgeV2 is Admin, IFastBridgeV2, IFastBridgeV2Errors { } else { // For ERC20s, we check that the correct msg.value was sent if (msg.value != transaction.callValue) revert MsgValueIncorrect(); - // We need to pull the tokens from the Relayer to the recipient first before performing an + // We need to transfer the tokens from the Relayer to the recipient first before performing an // optional post-transfer arbitrary call. - _pullToken(to, token, amount); + IERC20(token).safeTransferFrom(msg.sender, to, amount); } if (transaction.callParams.length != 0) { // Arbitrary call requested, perform it while supplying full msg.value to the recipient + // Note: if token has a fee on transfers, the recipient will have received less than `amount`. + // This is a very niche edge case and should be handled by the recipient contract. _checkedCallRecipient({recipient: to, token: token, amount: amount, callParams: transaction.callParams}); } else if (msg.value != 0) { // No arbitrary call requested, but msg.value was sent. This is either a relay with ETH, @@ -334,25 +336,21 @@ contract FastBridgeV2 is Admin, IFastBridgeV2, IFastBridgeV2Errors { return abi.decode(request, (BridgeTransactionV2)); } - /// @notice Pulls a requested token from the user to the requested recipient. - /// @dev Be careful of re-entrancy issues when msg.value > 0 and recipient != address(this) - function _pullToken(address recipient, address token, uint256 amount) internal returns (uint256 amountPulled) { - if (token != UniversalTokenLib.ETH_ADDRESS) { + /// @notice Pulls a requested token from the user to this contract. + function _pullToken(address token, uint256 amount) internal returns (uint256 amountPulled) { + if (token == UniversalTokenLib.ETH_ADDRESS) { + // For ETH we just need to check that the supplied msg.value is correct + if (amount != msg.value) revert MsgValueIncorrect(); + amountPulled = msg.value; + } else { token.assertIsContract(); // Record token balance before transfer - amountPulled = IERC20(token).balanceOf(recipient); + amountPulled = IERC20(token).balanceOf(address(this)); // Token needs to be pulled only if msg.value is zero // This way user can specify WETH as the origin asset - IERC20(token).safeTransferFrom(msg.sender, recipient, amount); + IERC20(token).safeTransferFrom(msg.sender, address(this), amount); // Use the difference between the recorded balance and the current balance as the amountPulled - amountPulled = IERC20(token).balanceOf(recipient) - amountPulled; - } else { - // Otherwise, we need to check that ETH amount matches msg.value - if (amount != msg.value) revert MsgValueIncorrect(); - // Transfer value to recipient if not this address - if (recipient != address(this)) token.universalTransfer(recipient, amount); - // We will forward msg.value in the external call later, if recipient is not this contract - amountPulled = msg.value; + amountPulled = IERC20(token).balanceOf(address(this)) - amountPulled; } } From c50042adbfee3c4a02ea6517cf2325b694160fd2 Mon Sep 17 00:00:00 2001 From: ChiTimesChi <88190723+ChiTimesChi@users.noreply.github.com> Date: Thu, 3 Oct 2024 14:19:27 +0100 Subject: [PATCH 11/85] refactor: isolate validation of relay params --- .../contracts-rfq/contracts/FastBridgeV2.sol | 45 +++++++++++-------- 1 file changed, 27 insertions(+), 18 deletions(-) diff --git a/packages/contracts-rfq/contracts/FastBridgeV2.sol b/packages/contracts-rfq/contracts/FastBridgeV2.sol index b2653bd401..513ee34a9f 100644 --- a/packages/contracts-rfq/contracts/FastBridgeV2.sol +++ b/packages/contracts-rfq/contracts/FastBridgeV2.sol @@ -203,27 +203,10 @@ contract FastBridgeV2 is Admin, IFastBridgeV2, IFastBridgeV2Errors { } /// @inheritdoc IFastBridgeV2 - // TODO: reduce cyclomatic complexity alongside arbitrary call - // solhint-disable-next-line code-complexity function relay(bytes memory request, address relayer) public payable { - if (relayer == address(0)) revert ZeroAddress(); - // Check if the transaction has already been relayed bytes32 transactionId = keccak256(request); - if (bridgeRelays(transactionId)) revert TransactionRelayed(); - // Decode the transaction and check that it could be relayed on this chain BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request); - if (transaction.destChainId != uint32(block.chainid)) revert ChainIncorrect(); - // Check the deadline for relay to happen - if (block.timestamp > transaction.deadline) revert DeadlineExceeded(); - // Check the exclusivity period, if it is still ongoing - // forgefmt: disable-next-item - if ( - transaction.exclusivityRelayer != address(0) && - transaction.exclusivityRelayer != relayer && - block.timestamp <= transaction.exclusivityEndTime - ) { - revert ExclusivityPeriodNotPassed(); - } + _validateRelayParams(transaction, transactionId, relayer); // mark bridge transaction as relayed bridgeRelayDetails[transactionId] = BridgeRelay({blockNumber: uint48(block.number), blockTimestamp: uint48(block.timestamp), relayer: relayer}); @@ -389,4 +372,30 @@ contract FastBridgeV2 is Admin, IFastBridgeV2, IFastBridgeV2Errors { delta = uint40(block.timestamp) - proofBlockTimestamp; } } + + /// @notice Performs all the necessary checks for a relay to happen. + function _validateRelayParams( + BridgeTransactionV2 memory transaction, + bytes32 transactionId, + address relayer + ) + internal + view + { + if (relayer == address(0)) revert ZeroAddress(); + // Check if the transaction has already been relayed + if (bridgeRelays(transactionId)) revert TransactionRelayed(); + if (transaction.destChainId != uint32(block.chainid)) revert ChainIncorrect(); + // Check the deadline for relay to happen + if (block.timestamp > transaction.deadline) revert DeadlineExceeded(); + // Check the exclusivity period, if it is still ongoing + // forgefmt: disable-next-item + if ( + transaction.exclusivityRelayer != address(0) && + transaction.exclusivityRelayer != relayer && + block.timestamp <= transaction.exclusivityEndTime + ) { + revert ExclusivityPeriodNotPassed(); + } + } } From 9fb4461b2df27625fdefbd9a3c7dfbf42f1558f0 Mon Sep 17 00:00:00 2001 From: ChiTimesChi <88190723+ChiTimesChi@users.noreply.github.com> Date: Thu, 3 Oct 2024 14:52:02 +0100 Subject: [PATCH 12/85] refactor: isolate validation of the bridge params --- .../contracts-rfq/contracts/FastBridgeV2.sol | 47 ++++++++++++------- 1 file changed, 31 insertions(+), 16 deletions(-) diff --git a/packages/contracts-rfq/contracts/FastBridgeV2.sol b/packages/contracts-rfq/contracts/FastBridgeV2.sol index 513ee34a9f..c4483b183f 100644 --- a/packages/contracts-rfq/contracts/FastBridgeV2.sol +++ b/packages/contracts-rfq/contracts/FastBridgeV2.sol @@ -137,24 +137,10 @@ contract FastBridgeV2 is Admin, IFastBridgeV2, IFastBridgeV2Errors { } /// @inheritdoc IFastBridgeV2 - // TODO: reduce cyclomatic complexity alongside arbitrary call - // solhint-disable-next-line code-complexity function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) public payable { - // check bridge params - if (params.dstChainId == block.chainid) revert ChainIncorrect(); - if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect(); - if (params.sender == address(0) || params.to == address(0)) revert ZeroAddress(); - if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress(); - if (params.deadline < block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort(); - if (paramsV2.callParams.length > MAX_CALL_PARAMS_LENGTH) revert CallParamsLengthAboveMax(); - if (paramsV2.callValue != 0 && params.destToken == UniversalTokenLib.ETH_ADDRESS) { - revert NativeTokenCallValueNotSupported(); - } int256 exclusivityEndTime = int256(block.timestamp) + paramsV2.quoteExclusivitySeconds; - // exclusivityEndTime must be in range (0 .. params.deadline] - if (exclusivityEndTime <= 0 || exclusivityEndTime > int256(params.deadline)) { - revert ExclusivityParamsIncorrect(); - } + _validateBridgeParams(params, paramsV2, exclusivityEndTime); + // transfer tokens to bridge contract /// @dev use returned originAmount in request in case of transfer fees uint256 originAmount = _pullToken(params.originToken, params.originAmount); @@ -373,6 +359,35 @@ contract FastBridgeV2 is Admin, IFastBridgeV2, IFastBridgeV2Errors { } } + /// @notice Performs all the necessary checks for a bridge to happen. + /// @dev There's no good way to refactor this function to reduce cyclomatic complexity due to + /// the number of checks that need to be performed, so we skip the code-complexity rule here. + // solhint-disable-next-line code-complexity + function _validateBridgeParams( + BridgeParams memory params, + BridgeParamsV2 memory paramsV2, + int256 exclusivityEndTime + ) + internal + view + { + // Check V1 (legacy) params + if (params.dstChainId == block.chainid) revert ChainIncorrect(); + if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect(); + if (params.sender == address(0) || params.to == address(0)) revert ZeroAddress(); + if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress(); + if (params.deadline < block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort(); + // Check V2 params + if (paramsV2.callParams.length > MAX_CALL_PARAMS_LENGTH) revert CallParamsLengthAboveMax(); + if (paramsV2.callValue != 0 && params.destToken == UniversalTokenLib.ETH_ADDRESS) { + revert NativeTokenCallValueNotSupported(); + } + // exclusivityEndTime must be in range (0 .. params.deadline] + if (exclusivityEndTime <= 0 || exclusivityEndTime > int256(params.deadline)) { + revert ExclusivityParamsIncorrect(); + } + } + /// @notice Performs all the necessary checks for a relay to happen. function _validateRelayParams( BridgeTransactionV2 memory transaction, From 156e33382371751ee00174470127fb8f95402107 Mon Sep 17 00:00:00 2001 From: ChiTimesChi <88190723+ChiTimesChi@users.noreply.github.com> Date: Tue, 8 Oct 2024 10:54:39 +0100 Subject: [PATCH 13/85] docs: could -> can --- packages/contracts-rfq/contracts/interfaces/IFastBridgeV2.sol | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/contracts-rfq/contracts/interfaces/IFastBridgeV2.sol b/packages/contracts-rfq/contracts/interfaces/IFastBridgeV2.sol index a1485d3f31..54dbb5f3f6 100644 --- a/packages/contracts-rfq/contracts/interfaces/IFastBridgeV2.sol +++ b/packages/contracts-rfq/contracts/interfaces/IFastBridgeV2.sol @@ -30,7 +30,7 @@ interface IFastBridgeV2 is IFastBridge { /// for backwards compatibility. /// Note: quoteRelayer and quoteExclusivitySeconds are either both zero (indicating no exclusivity) /// or both non-zero (indicating exclusivity for the given period). - /// Note: callValue > 0 could NOT be used with destToken = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE (ETH_ADDRESS) + /// Note: callValue > 0 can NOT be used with destToken = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE (ETH_ADDRESS) /// @param quoteRelayer Relayer that provided the quote for the transaction /// @param quoteExclusivitySeconds Period of time the quote relayer is guaranteed exclusivity after user's deposit /// @param quoteId Unique quote identifier used for tracking the quote @@ -70,7 +70,7 @@ interface IFastBridgeV2 is IFastBridge { /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability /// to provide temporary exclusivity fill rights for the quote relayer. /// @param params The parameters required to bridge - /// @param paramsV2 The parameters for exclusivity fill rights (optional, could be left empty) + /// @param paramsV2 The parameters for exclusivity fill rights (optional, can be left empty) function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) external payable; /// @notice Relays destination side of bridge transaction by off-chain relayer From 2b77b4af8091c58e54c93fb8a28b37ed292939d3 Mon Sep 17 00:00:00 2001 From: ChiTimesChi <88190723+ChiTimesChi@users.noreply.github.com> Date: Tue, 8 Oct 2024 11:05:09 +0100 Subject: [PATCH 14/85] test: enable the backwards compatibility encoding test --- .../test/FastBridgeV2.Encoding.t.sol | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/packages/contracts-rfq/test/FastBridgeV2.Encoding.t.sol b/packages/contracts-rfq/test/FastBridgeV2.Encoding.t.sol index 0918c66bf5..21d32876fc 100644 --- a/packages/contracts-rfq/test/FastBridgeV2.Encoding.t.sol +++ b/packages/contracts-rfq/test/FastBridgeV2.Encoding.t.sol @@ -47,17 +47,15 @@ contract FastBridgeV2EncodingTest is FastBridgeV2Test { assertEq(decodedTx, bridgeTx); } - // The addition of variable length field (callParams) in BridgeTransactionV2 breaks the compatibility - // with the original BridgeTransaction struct. - // Solidity's abi.encode(bridgeTxV2) will use the first 32 bytes to encode the data offset for the whole struct, - // which is ALWAYS equal to 32 (data starts right after the offset). This is weird, but it is what it is. - // https://ethereum.stackexchange.com/questions/152971/abi-encode-decode-mystery-additional-32-byte-field-uniswap-v2 - function test_getBridgeTransaction_supportsV2(IFastBridgeV2.BridgeTransactionV2 memory bridgeTxV2) public { - // TODO: reevaluate the necessity of this test if/when the encoding scheme is changed - vm.skip(true); + /// @notice We expect all the V1 fields except for `sendChainGas` to match. + /// `sendChainGas` is replaced with `callValue` in V2, therefore we expect non-zero `callValue` + /// to match `sendChainGas = true` in V1 + function test_getBridgeTransaction_supportsV2(IFastBridgeV2.BridgeTransactionV2 memory bridgeTxV2) public view { bytes memory request = abi.encode(bridgeTxV2); IFastBridge.BridgeTransaction memory decodedTx = fastBridge.getBridgeTransaction(request); - assertEq(decodedTx, extractV1(bridgeTxV2)); + IFastBridge.BridgeTransaction memory expectedTx = extractV1(bridgeTxV2); + expectedTx.sendChainGas = bridgeTxV2.callValue > 0; + assertEq(decodedTx, expectedTx); } function test_getBridgeTransactionV2(IFastBridgeV2.BridgeTransactionV2 memory bridgeTxV2) public view { From 271f59da3150e905ba28977b94a9bfa51f05647a Mon Sep 17 00:00:00 2001 From: ChiTimesChi <88190723+ChiTimesChi@users.noreply.github.com> Date: Tue, 8 Oct 2024 11:08:28 +0100 Subject: [PATCH 15/85] fix: getBridgeTransaction partial support for V2 structs --- .../contracts-rfq/contracts/FastBridgeV2.sol | 33 +++++++++++++++---- .../contracts/interfaces/IFastBridge.sol | 2 +- 2 files changed, 27 insertions(+), 8 deletions(-) diff --git a/packages/contracts-rfq/contracts/FastBridgeV2.sol b/packages/contracts-rfq/contracts/FastBridgeV2.sol index c4483b183f..0da1b511da 100644 --- a/packages/contracts-rfq/contracts/FastBridgeV2.sol +++ b/packages/contracts-rfq/contracts/FastBridgeV2.sol @@ -127,13 +127,32 @@ contract FastBridgeV2 is Admin, IFastBridgeV2, IFastBridgeV2Errors { } /// @inheritdoc IFastBridge - function getBridgeTransaction(bytes memory request) external pure returns (BridgeTransaction memory) { - // TODO: the note below isn't true anymore with the BridgeTransactionV2 struct - // since the variable length `callParams` was added. This needs to be fixed/acknowledged. - - // Note: when passing V2 request, this will decode the V1 fields correctly since the new fields were - // added as the last fields of the struct and hence the ABI decoder will simply ignore the extra data. - return abi.decode(request, (BridgeTransaction)); + /// @dev This method is added to achieve backwards compatibility with decoding requests into V1 structs: + /// - `callValue` is partially reported as a zero/non-zero flag + /// - `callParams` is ignored + /// In order to process all kinds of requests use getBridgeTransactionV2 instead. + function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory) { + // Try decoding into V2 struct first. This will revert if V1 struct is passed + try this.getBridgeTransactionV2(request) returns (BridgeTransactionV2 memory txV2) { + // Note: we entirely ignore the callParams field, as it was not present in V1 + return BridgeTransaction({ + originChainId: txV2.originChainId, + destChainId: txV2.destChainId, + originSender: txV2.originSender, + destRecipient: txV2.destRecipient, + originToken: txV2.originToken, + destToken: txV2.destToken, + originAmount: txV2.originAmount, + destAmount: txV2.destAmount, + originFeeAmount: txV2.originFeeAmount, + sendChainGas: txV2.callValue != 0, + deadline: txV2.deadline, + nonce: txV2.nonce + }); + } catch { + // Fallback to V1 struct + return abi.decode(request, (BridgeTransaction)); + } } /// @inheritdoc IFastBridgeV2 diff --git a/packages/contracts-rfq/contracts/interfaces/IFastBridge.sol b/packages/contracts-rfq/contracts/interfaces/IFastBridge.sol index b691dfb5b4..033d602f76 100644 --- a/packages/contracts-rfq/contracts/interfaces/IFastBridge.sol +++ b/packages/contracts-rfq/contracts/interfaces/IFastBridge.sol @@ -97,7 +97,7 @@ interface IFastBridge { /// @notice Decodes bridge request into a bridge transaction /// @param request The bridge request to decode - function getBridgeTransaction(bytes memory request) external pure returns (BridgeTransaction memory); + function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory); /// @notice Checks if the dispute period has passed so bridge deposit can be claimed /// @param transactionId The transaction id associated with the encoded bridge transaction to check From 2317a588c1fa3202c378ab05157562e1a13fa34c Mon Sep 17 00:00:00 2001 From: ChiTimesChi <88190723+ChiTimesChi@users.noreply.github.com> Date: Tue, 8 Oct 2024 12:26:01 +0100 Subject: [PATCH 16/85] test: add clarifications about expected reverts --- .../contracts-rfq/test/FastBridgeV2.Dst.ArbitraryCall.t.sol | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/packages/contracts-rfq/test/FastBridgeV2.Dst.ArbitraryCall.t.sol b/packages/contracts-rfq/test/FastBridgeV2.Dst.ArbitraryCall.t.sol index 1bd47fba4b..1fb3ed8148 100644 --- a/packages/contracts-rfq/test/FastBridgeV2.Dst.ArbitraryCall.t.sol +++ b/packages/contracts-rfq/test/FastBridgeV2.Dst.ArbitraryCall.t.sol @@ -195,6 +195,8 @@ contract FastBridgeV2DstArbitraryCallTest is FastBridgeV2DstExclusivityTest { // ══════════════════════════════════════════════ NO-OP RECIPIENT ══════════════════════════════════════════════════ + // Note: in these tests NoOpRecipient doesn't implement hook function, so we expect a generic OZ library revert. + function test_relay_token_noOpRecipient_revertWhenCallParamsPresent() public virtual override { setTokenTestRecipient(noOpRecipient); vm.expectRevert(Address.FailedInnerCall.selector); @@ -336,6 +338,8 @@ contract FastBridgeV2DstArbitraryCallTest is FastBridgeV2DstExclusivityTest { function test_relay_eth_noCallParams_revert_recipientReverts() public { setEthTestCallParams(""); vm.mockCallRevert({callee: userB, data: "", revertData: bytes(REVERT_MSG)}); + // Note: OZ library doesn't bubble the revert message for just sending ETH + // (as opposed to doing an external hook call). Therefore we expect a generic library revert. vm.expectRevert(Address.FailedInnerCall.selector); relay({caller: relayerB, msgValue: ethParams.destAmount, bridgeTx: ethTx}); } @@ -343,6 +347,8 @@ contract FastBridgeV2DstArbitraryCallTest is FastBridgeV2DstExclusivityTest { function test_relay_eth_withRelayerAddress_noCallParams_revert_recipientReverts() public { setEthTestCallParams(""); vm.mockCallRevert({callee: userB, data: "", revertData: bytes(REVERT_MSG)}); + // Note: OZ library doesn't bubble the revert message for just sending ETH + // (as opposed to doing an external hook call). Therefore we expect a generic library revert. vm.expectRevert(Address.FailedInnerCall.selector); relayWithAddress({caller: relayerA, relayer: relayerB, msgValue: ethParams.destAmount, bridgeTx: ethTx}); } From c6a1fdc4b21b68fb914de994d5a7b48f76bac5b0 Mon Sep 17 00:00:00 2001 From: Daniel Wasserman Date: Tue, 8 Oct 2024 14:45:02 -0500 Subject: [PATCH 17/85] Feat: initial fastbridgev2 bindings --- .../fastbridgev2/fastbridgev2.abigen.go | 14696 ++++++++++++++++ .../fastbridgev2.contractinfo.json | 1 + .../fastbridgev2/fastbridgev2.metadata.go | 25 + .../rfq/contracts/fastbridgev2/generate.go | 3 + 4 files changed, 14725 insertions(+) create mode 100644 services/rfq/contracts/fastbridgev2/fastbridgev2.abigen.go create mode 100644 services/rfq/contracts/fastbridgev2/fastbridgev2.contractinfo.json create mode 100644 services/rfq/contracts/fastbridgev2/fastbridgev2.metadata.go create mode 100644 services/rfq/contracts/fastbridgev2/generate.go diff --git a/services/rfq/contracts/fastbridgev2/fastbridgev2.abigen.go b/services/rfq/contracts/fastbridgev2/fastbridgev2.abigen.go new file mode 100644 index 0000000000..f7490e86f4 --- /dev/null +++ b/services/rfq/contracts/fastbridgev2/fastbridgev2.abigen.go @@ -0,0 +1,14696 @@ +// Code generated - DO NOT EDIT. +// This file is a generated binding and any manual changes will be lost. + +package fastbridgev2 + +import ( + "errors" + "math/big" + "strings" + + ethereum "github.com/ethereum/go-ethereum" + "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/event" +) + +// Reference imports to suppress errors if they are not otherwise used. +var ( + _ = errors.New + _ = big.NewInt + _ = strings.NewReader + _ = ethereum.NotFound + _ = bind.Bind + _ = common.Big1 + _ = types.BloomLookup + _ = event.NewSubscription + _ = abi.ConvertType +) + +// IFastBridgeBridgeParams is an auto generated low-level Go binding around an user-defined struct. +type IFastBridgeBridgeParams struct { + DstChainId uint32 + Sender common.Address + To common.Address + OriginToken common.Address + DestToken common.Address + OriginAmount *big.Int + DestAmount *big.Int + SendChainGas bool + Deadline *big.Int +} + +// IFastBridgeBridgeTransaction is an auto generated low-level Go binding around an user-defined struct. +type IFastBridgeBridgeTransaction struct { + OriginChainId uint32 + DestChainId uint32 + OriginSender common.Address + DestRecipient common.Address + OriginToken common.Address + DestToken common.Address + OriginAmount *big.Int + DestAmount *big.Int + OriginFeeAmount *big.Int + SendChainGas bool + Deadline *big.Int + Nonce *big.Int +} + +// IFastBridgeV2BridgeParamsV2 is an auto generated low-level Go binding around an user-defined struct. +type IFastBridgeV2BridgeParamsV2 struct { + QuoteRelayer common.Address + QuoteExclusivitySeconds *big.Int + QuoteId []byte + CallValue *big.Int + CallParams []byte +} + +// IFastBridgeV2BridgeTransactionV2 is an auto generated low-level Go binding around an user-defined struct. +type IFastBridgeV2BridgeTransactionV2 struct { + OriginChainId uint32 + DestChainId uint32 + OriginSender common.Address + DestRecipient common.Address + OriginToken common.Address + DestToken common.Address + OriginAmount *big.Int + DestAmount *big.Int + OriginFeeAmount *big.Int + CallValue *big.Int + Deadline *big.Int + Nonce *big.Int + ExclusivityRelayer common.Address + ExclusivityEndTime *big.Int + CallParams []byte +} + +// AccessControlMetaData contains all meta data concerning the AccessControl contract. +var AccessControlMetaData = &bind.MetaData{ + ABI: "[{\"inputs\":[],\"name\":\"AccessControlBadConfirmation\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"neededRole\",\"type\":\"bytes32\"}],\"name\":\"AccessControlUnauthorizedAccount\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"previousAdminRole\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"newAdminRole\",\"type\":\"bytes32\"}],\"name\":\"RoleAdminChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleGranted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleRevoked\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"DEFAULT_ADMIN_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"}],\"name\":\"getRoleAdmin\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"grantRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"hasRole\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"callerConfirmation\",\"type\":\"address\"}],\"name\":\"renounceRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"revokeRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes4\",\"name\":\"interfaceId\",\"type\":\"bytes4\"}],\"name\":\"supportsInterface\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"}]", + Sigs: map[string]string{ + "a217fddf": "DEFAULT_ADMIN_ROLE()", + "248a9ca3": "getRoleAdmin(bytes32)", + "2f2ff15d": "grantRole(bytes32,address)", + "91d14854": "hasRole(bytes32,address)", + "36568abe": "renounceRole(bytes32,address)", + "d547741f": "revokeRole(bytes32,address)", + "01ffc9a7": "supportsInterface(bytes4)", + }, +} + +// AccessControlABI is the input ABI used to generate the binding from. +// Deprecated: Use AccessControlMetaData.ABI instead. +var AccessControlABI = AccessControlMetaData.ABI + +// Deprecated: Use AccessControlMetaData.Sigs instead. +// AccessControlFuncSigs maps the 4-byte function signature to its string representation. +var AccessControlFuncSigs = AccessControlMetaData.Sigs + +// AccessControl is an auto generated Go binding around an Ethereum contract. +type AccessControl struct { + AccessControlCaller // Read-only binding to the contract + AccessControlTransactor // Write-only binding to the contract + AccessControlFilterer // Log filterer for contract events +} + +// AccessControlCaller is an auto generated read-only Go binding around an Ethereum contract. +type AccessControlCaller struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// AccessControlTransactor is an auto generated write-only Go binding around an Ethereum contract. +type AccessControlTransactor struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// AccessControlFilterer is an auto generated log filtering Go binding around an Ethereum contract events. +type AccessControlFilterer struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// AccessControlSession is an auto generated Go binding around an Ethereum contract, +// with pre-set call and transact options. +type AccessControlSession struct { + Contract *AccessControl // Generic contract binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// AccessControlCallerSession is an auto generated read-only Go binding around an Ethereum contract, +// with pre-set call options. +type AccessControlCallerSession struct { + Contract *AccessControlCaller // Generic contract caller binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session +} + +// AccessControlTransactorSession is an auto generated write-only Go binding around an Ethereum contract, +// with pre-set transact options. +type AccessControlTransactorSession struct { + Contract *AccessControlTransactor // Generic contract transactor binding to set the session for + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// AccessControlRaw is an auto generated low-level Go binding around an Ethereum contract. +type AccessControlRaw struct { + Contract *AccessControl // Generic contract binding to access the raw methods on +} + +// AccessControlCallerRaw is an auto generated low-level read-only Go binding around an Ethereum contract. +type AccessControlCallerRaw struct { + Contract *AccessControlCaller // Generic read-only contract binding to access the raw methods on +} + +// AccessControlTransactorRaw is an auto generated low-level write-only Go binding around an Ethereum contract. +type AccessControlTransactorRaw struct { + Contract *AccessControlTransactor // Generic write-only contract binding to access the raw methods on +} + +// NewAccessControl creates a new instance of AccessControl, bound to a specific deployed contract. +func NewAccessControl(address common.Address, backend bind.ContractBackend) (*AccessControl, error) { + contract, err := bindAccessControl(address, backend, backend, backend) + if err != nil { + return nil, err + } + return &AccessControl{AccessControlCaller: AccessControlCaller{contract: contract}, AccessControlTransactor: AccessControlTransactor{contract: contract}, AccessControlFilterer: AccessControlFilterer{contract: contract}}, nil +} + +// NewAccessControlCaller creates a new read-only instance of AccessControl, bound to a specific deployed contract. +func NewAccessControlCaller(address common.Address, caller bind.ContractCaller) (*AccessControlCaller, error) { + contract, err := bindAccessControl(address, caller, nil, nil) + if err != nil { + return nil, err + } + return &AccessControlCaller{contract: contract}, nil +} + +// NewAccessControlTransactor creates a new write-only instance of AccessControl, bound to a specific deployed contract. +func NewAccessControlTransactor(address common.Address, transactor bind.ContractTransactor) (*AccessControlTransactor, error) { + contract, err := bindAccessControl(address, nil, transactor, nil) + if err != nil { + return nil, err + } + return &AccessControlTransactor{contract: contract}, nil +} + +// NewAccessControlFilterer creates a new log filterer instance of AccessControl, bound to a specific deployed contract. +func NewAccessControlFilterer(address common.Address, filterer bind.ContractFilterer) (*AccessControlFilterer, error) { + contract, err := bindAccessControl(address, nil, nil, filterer) + if err != nil { + return nil, err + } + return &AccessControlFilterer{contract: contract}, nil +} + +// bindAccessControl binds a generic wrapper to an already deployed contract. +func bindAccessControl(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) { + parsed, err := AccessControlMetaData.GetAbi() + if err != nil { + return nil, err + } + return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil +} + +// Call invokes the (constant) contract method with params as input values and +// sets the output to result. The result type might be a single field for simple +// returns, a slice of interfaces for anonymous returns and a struct for named +// returns. +func (_AccessControl *AccessControlRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _AccessControl.Contract.AccessControlCaller.contract.Call(opts, result, method, params...) +} + +// Transfer initiates a plain transaction to move funds to the contract, calling +// its default method if one is available. +func (_AccessControl *AccessControlRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _AccessControl.Contract.AccessControlTransactor.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_AccessControl *AccessControlRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _AccessControl.Contract.AccessControlTransactor.contract.Transact(opts, method, params...) +} + +// Call invokes the (constant) contract method with params as input values and +// sets the output to result. The result type might be a single field for simple +// returns, a slice of interfaces for anonymous returns and a struct for named +// returns. +func (_AccessControl *AccessControlCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _AccessControl.Contract.contract.Call(opts, result, method, params...) +} + +// Transfer initiates a plain transaction to move funds to the contract, calling +// its default method if one is available. +func (_AccessControl *AccessControlTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _AccessControl.Contract.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_AccessControl *AccessControlTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _AccessControl.Contract.contract.Transact(opts, method, params...) +} + +// DEFAULTADMINROLE is a free data retrieval call binding the contract method 0xa217fddf. +// +// Solidity: function DEFAULT_ADMIN_ROLE() view returns(bytes32) +func (_AccessControl *AccessControlCaller) DEFAULTADMINROLE(opts *bind.CallOpts) ([32]byte, error) { + var out []interface{} + err := _AccessControl.contract.Call(opts, &out, "DEFAULT_ADMIN_ROLE") + + if err != nil { + return *new([32]byte), err + } + + out0 := *abi.ConvertType(out[0], new([32]byte)).(*[32]byte) + + return out0, err + +} + +// DEFAULTADMINROLE is a free data retrieval call binding the contract method 0xa217fddf. +// +// Solidity: function DEFAULT_ADMIN_ROLE() view returns(bytes32) +func (_AccessControl *AccessControlSession) DEFAULTADMINROLE() ([32]byte, error) { + return _AccessControl.Contract.DEFAULTADMINROLE(&_AccessControl.CallOpts) +} + +// DEFAULTADMINROLE is a free data retrieval call binding the contract method 0xa217fddf. +// +// Solidity: function DEFAULT_ADMIN_ROLE() view returns(bytes32) +func (_AccessControl *AccessControlCallerSession) DEFAULTADMINROLE() ([32]byte, error) { + return _AccessControl.Contract.DEFAULTADMINROLE(&_AccessControl.CallOpts) +} + +// GetRoleAdmin is a free data retrieval call binding the contract method 0x248a9ca3. +// +// Solidity: function getRoleAdmin(bytes32 role) view returns(bytes32) +func (_AccessControl *AccessControlCaller) GetRoleAdmin(opts *bind.CallOpts, role [32]byte) ([32]byte, error) { + var out []interface{} + err := _AccessControl.contract.Call(opts, &out, "getRoleAdmin", role) + + if err != nil { + return *new([32]byte), err + } + + out0 := *abi.ConvertType(out[0], new([32]byte)).(*[32]byte) + + return out0, err + +} + +// GetRoleAdmin is a free data retrieval call binding the contract method 0x248a9ca3. +// +// Solidity: function getRoleAdmin(bytes32 role) view returns(bytes32) +func (_AccessControl *AccessControlSession) GetRoleAdmin(role [32]byte) ([32]byte, error) { + return _AccessControl.Contract.GetRoleAdmin(&_AccessControl.CallOpts, role) +} + +// GetRoleAdmin is a free data retrieval call binding the contract method 0x248a9ca3. +// +// Solidity: function getRoleAdmin(bytes32 role) view returns(bytes32) +func (_AccessControl *AccessControlCallerSession) GetRoleAdmin(role [32]byte) ([32]byte, error) { + return _AccessControl.Contract.GetRoleAdmin(&_AccessControl.CallOpts, role) +} + +// HasRole is a free data retrieval call binding the contract method 0x91d14854. +// +// Solidity: function hasRole(bytes32 role, address account) view returns(bool) +func (_AccessControl *AccessControlCaller) HasRole(opts *bind.CallOpts, role [32]byte, account common.Address) (bool, error) { + var out []interface{} + err := _AccessControl.contract.Call(opts, &out, "hasRole", role, account) + + if err != nil { + return *new(bool), err + } + + out0 := *abi.ConvertType(out[0], new(bool)).(*bool) + + return out0, err + +} + +// HasRole is a free data retrieval call binding the contract method 0x91d14854. +// +// Solidity: function hasRole(bytes32 role, address account) view returns(bool) +func (_AccessControl *AccessControlSession) HasRole(role [32]byte, account common.Address) (bool, error) { + return _AccessControl.Contract.HasRole(&_AccessControl.CallOpts, role, account) +} + +// HasRole is a free data retrieval call binding the contract method 0x91d14854. +// +// Solidity: function hasRole(bytes32 role, address account) view returns(bool) +func (_AccessControl *AccessControlCallerSession) HasRole(role [32]byte, account common.Address) (bool, error) { + return _AccessControl.Contract.HasRole(&_AccessControl.CallOpts, role, account) +} + +// SupportsInterface is a free data retrieval call binding the contract method 0x01ffc9a7. +// +// Solidity: function supportsInterface(bytes4 interfaceId) view returns(bool) +func (_AccessControl *AccessControlCaller) SupportsInterface(opts *bind.CallOpts, interfaceId [4]byte) (bool, error) { + var out []interface{} + err := _AccessControl.contract.Call(opts, &out, "supportsInterface", interfaceId) + + if err != nil { + return *new(bool), err + } + + out0 := *abi.ConvertType(out[0], new(bool)).(*bool) + + return out0, err + +} + +// SupportsInterface is a free data retrieval call binding the contract method 0x01ffc9a7. +// +// Solidity: function supportsInterface(bytes4 interfaceId) view returns(bool) +func (_AccessControl *AccessControlSession) SupportsInterface(interfaceId [4]byte) (bool, error) { + return _AccessControl.Contract.SupportsInterface(&_AccessControl.CallOpts, interfaceId) +} + +// SupportsInterface is a free data retrieval call binding the contract method 0x01ffc9a7. +// +// Solidity: function supportsInterface(bytes4 interfaceId) view returns(bool) +func (_AccessControl *AccessControlCallerSession) SupportsInterface(interfaceId [4]byte) (bool, error) { + return _AccessControl.Contract.SupportsInterface(&_AccessControl.CallOpts, interfaceId) +} + +// GrantRole is a paid mutator transaction binding the contract method 0x2f2ff15d. +// +// Solidity: function grantRole(bytes32 role, address account) returns() +func (_AccessControl *AccessControlTransactor) GrantRole(opts *bind.TransactOpts, role [32]byte, account common.Address) (*types.Transaction, error) { + return _AccessControl.contract.Transact(opts, "grantRole", role, account) +} + +// GrantRole is a paid mutator transaction binding the contract method 0x2f2ff15d. +// +// Solidity: function grantRole(bytes32 role, address account) returns() +func (_AccessControl *AccessControlSession) GrantRole(role [32]byte, account common.Address) (*types.Transaction, error) { + return _AccessControl.Contract.GrantRole(&_AccessControl.TransactOpts, role, account) +} + +// GrantRole is a paid mutator transaction binding the contract method 0x2f2ff15d. +// +// Solidity: function grantRole(bytes32 role, address account) returns() +func (_AccessControl *AccessControlTransactorSession) GrantRole(role [32]byte, account common.Address) (*types.Transaction, error) { + return _AccessControl.Contract.GrantRole(&_AccessControl.TransactOpts, role, account) +} + +// RenounceRole is a paid mutator transaction binding the contract method 0x36568abe. +// +// Solidity: function renounceRole(bytes32 role, address callerConfirmation) returns() +func (_AccessControl *AccessControlTransactor) RenounceRole(opts *bind.TransactOpts, role [32]byte, callerConfirmation common.Address) (*types.Transaction, error) { + return _AccessControl.contract.Transact(opts, "renounceRole", role, callerConfirmation) +} + +// RenounceRole is a paid mutator transaction binding the contract method 0x36568abe. +// +// Solidity: function renounceRole(bytes32 role, address callerConfirmation) returns() +func (_AccessControl *AccessControlSession) RenounceRole(role [32]byte, callerConfirmation common.Address) (*types.Transaction, error) { + return _AccessControl.Contract.RenounceRole(&_AccessControl.TransactOpts, role, callerConfirmation) +} + +// RenounceRole is a paid mutator transaction binding the contract method 0x36568abe. +// +// Solidity: function renounceRole(bytes32 role, address callerConfirmation) returns() +func (_AccessControl *AccessControlTransactorSession) RenounceRole(role [32]byte, callerConfirmation common.Address) (*types.Transaction, error) { + return _AccessControl.Contract.RenounceRole(&_AccessControl.TransactOpts, role, callerConfirmation) +} + +// RevokeRole is a paid mutator transaction binding the contract method 0xd547741f. +// +// Solidity: function revokeRole(bytes32 role, address account) returns() +func (_AccessControl *AccessControlTransactor) RevokeRole(opts *bind.TransactOpts, role [32]byte, account common.Address) (*types.Transaction, error) { + return _AccessControl.contract.Transact(opts, "revokeRole", role, account) +} + +// RevokeRole is a paid mutator transaction binding the contract method 0xd547741f. +// +// Solidity: function revokeRole(bytes32 role, address account) returns() +func (_AccessControl *AccessControlSession) RevokeRole(role [32]byte, account common.Address) (*types.Transaction, error) { + return _AccessControl.Contract.RevokeRole(&_AccessControl.TransactOpts, role, account) +} + +// RevokeRole is a paid mutator transaction binding the contract method 0xd547741f. +// +// Solidity: function revokeRole(bytes32 role, address account) returns() +func (_AccessControl *AccessControlTransactorSession) RevokeRole(role [32]byte, account common.Address) (*types.Transaction, error) { + return _AccessControl.Contract.RevokeRole(&_AccessControl.TransactOpts, role, account) +} + +// AccessControlRoleAdminChangedIterator is returned from FilterRoleAdminChanged and is used to iterate over the raw logs and unpacked data for RoleAdminChanged events raised by the AccessControl contract. +type AccessControlRoleAdminChangedIterator struct { + Event *AccessControlRoleAdminChanged // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *AccessControlRoleAdminChangedIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(AccessControlRoleAdminChanged) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(AccessControlRoleAdminChanged) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *AccessControlRoleAdminChangedIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *AccessControlRoleAdminChangedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// AccessControlRoleAdminChanged represents a RoleAdminChanged event raised by the AccessControl contract. +type AccessControlRoleAdminChanged struct { + Role [32]byte + PreviousAdminRole [32]byte + NewAdminRole [32]byte + Raw types.Log // Blockchain specific contextual infos +} + +// FilterRoleAdminChanged is a free log retrieval operation binding the contract event 0xbd79b86ffe0ab8e8776151514217cd7cacd52c909f66475c3af44e129f0b00ff. +// +// Solidity: event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole) +func (_AccessControl *AccessControlFilterer) FilterRoleAdminChanged(opts *bind.FilterOpts, role [][32]byte, previousAdminRole [][32]byte, newAdminRole [][32]byte) (*AccessControlRoleAdminChangedIterator, error) { + + var roleRule []interface{} + for _, roleItem := range role { + roleRule = append(roleRule, roleItem) + } + var previousAdminRoleRule []interface{} + for _, previousAdminRoleItem := range previousAdminRole { + previousAdminRoleRule = append(previousAdminRoleRule, previousAdminRoleItem) + } + var newAdminRoleRule []interface{} + for _, newAdminRoleItem := range newAdminRole { + newAdminRoleRule = append(newAdminRoleRule, newAdminRoleItem) + } + + logs, sub, err := _AccessControl.contract.FilterLogs(opts, "RoleAdminChanged", roleRule, previousAdminRoleRule, newAdminRoleRule) + if err != nil { + return nil, err + } + return &AccessControlRoleAdminChangedIterator{contract: _AccessControl.contract, event: "RoleAdminChanged", logs: logs, sub: sub}, nil +} + +// WatchRoleAdminChanged is a free log subscription operation binding the contract event 0xbd79b86ffe0ab8e8776151514217cd7cacd52c909f66475c3af44e129f0b00ff. +// +// Solidity: event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole) +func (_AccessControl *AccessControlFilterer) WatchRoleAdminChanged(opts *bind.WatchOpts, sink chan<- *AccessControlRoleAdminChanged, role [][32]byte, previousAdminRole [][32]byte, newAdminRole [][32]byte) (event.Subscription, error) { + + var roleRule []interface{} + for _, roleItem := range role { + roleRule = append(roleRule, roleItem) + } + var previousAdminRoleRule []interface{} + for _, previousAdminRoleItem := range previousAdminRole { + previousAdminRoleRule = append(previousAdminRoleRule, previousAdminRoleItem) + } + var newAdminRoleRule []interface{} + for _, newAdminRoleItem := range newAdminRole { + newAdminRoleRule = append(newAdminRoleRule, newAdminRoleItem) + } + + logs, sub, err := _AccessControl.contract.WatchLogs(opts, "RoleAdminChanged", roleRule, previousAdminRoleRule, newAdminRoleRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(AccessControlRoleAdminChanged) + if err := _AccessControl.contract.UnpackLog(event, "RoleAdminChanged", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseRoleAdminChanged is a log parse operation binding the contract event 0xbd79b86ffe0ab8e8776151514217cd7cacd52c909f66475c3af44e129f0b00ff. +// +// Solidity: event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole) +func (_AccessControl *AccessControlFilterer) ParseRoleAdminChanged(log types.Log) (*AccessControlRoleAdminChanged, error) { + event := new(AccessControlRoleAdminChanged) + if err := _AccessControl.contract.UnpackLog(event, "RoleAdminChanged", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// AccessControlRoleGrantedIterator is returned from FilterRoleGranted and is used to iterate over the raw logs and unpacked data for RoleGranted events raised by the AccessControl contract. +type AccessControlRoleGrantedIterator struct { + Event *AccessControlRoleGranted // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *AccessControlRoleGrantedIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(AccessControlRoleGranted) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(AccessControlRoleGranted) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *AccessControlRoleGrantedIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *AccessControlRoleGrantedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// AccessControlRoleGranted represents a RoleGranted event raised by the AccessControl contract. +type AccessControlRoleGranted struct { + Role [32]byte + Account common.Address + Sender common.Address + Raw types.Log // Blockchain specific contextual infos +} + +// FilterRoleGranted is a free log retrieval operation binding the contract event 0x2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d. +// +// Solidity: event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender) +func (_AccessControl *AccessControlFilterer) FilterRoleGranted(opts *bind.FilterOpts, role [][32]byte, account []common.Address, sender []common.Address) (*AccessControlRoleGrantedIterator, error) { + + var roleRule []interface{} + for _, roleItem := range role { + roleRule = append(roleRule, roleItem) + } + var accountRule []interface{} + for _, accountItem := range account { + accountRule = append(accountRule, accountItem) + } + var senderRule []interface{} + for _, senderItem := range sender { + senderRule = append(senderRule, senderItem) + } + + logs, sub, err := _AccessControl.contract.FilterLogs(opts, "RoleGranted", roleRule, accountRule, senderRule) + if err != nil { + return nil, err + } + return &AccessControlRoleGrantedIterator{contract: _AccessControl.contract, event: "RoleGranted", logs: logs, sub: sub}, nil +} + +// WatchRoleGranted is a free log subscription operation binding the contract event 0x2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d. +// +// Solidity: event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender) +func (_AccessControl *AccessControlFilterer) WatchRoleGranted(opts *bind.WatchOpts, sink chan<- *AccessControlRoleGranted, role [][32]byte, account []common.Address, sender []common.Address) (event.Subscription, error) { + + var roleRule []interface{} + for _, roleItem := range role { + roleRule = append(roleRule, roleItem) + } + var accountRule []interface{} + for _, accountItem := range account { + accountRule = append(accountRule, accountItem) + } + var senderRule []interface{} + for _, senderItem := range sender { + senderRule = append(senderRule, senderItem) + } + + logs, sub, err := _AccessControl.contract.WatchLogs(opts, "RoleGranted", roleRule, accountRule, senderRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(AccessControlRoleGranted) + if err := _AccessControl.contract.UnpackLog(event, "RoleGranted", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseRoleGranted is a log parse operation binding the contract event 0x2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d. +// +// Solidity: event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender) +func (_AccessControl *AccessControlFilterer) ParseRoleGranted(log types.Log) (*AccessControlRoleGranted, error) { + event := new(AccessControlRoleGranted) + if err := _AccessControl.contract.UnpackLog(event, "RoleGranted", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// AccessControlRoleRevokedIterator is returned from FilterRoleRevoked and is used to iterate over the raw logs and unpacked data for RoleRevoked events raised by the AccessControl contract. +type AccessControlRoleRevokedIterator struct { + Event *AccessControlRoleRevoked // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *AccessControlRoleRevokedIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(AccessControlRoleRevoked) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(AccessControlRoleRevoked) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *AccessControlRoleRevokedIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *AccessControlRoleRevokedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// AccessControlRoleRevoked represents a RoleRevoked event raised by the AccessControl contract. +type AccessControlRoleRevoked struct { + Role [32]byte + Account common.Address + Sender common.Address + Raw types.Log // Blockchain specific contextual infos +} + +// FilterRoleRevoked is a free log retrieval operation binding the contract event 0xf6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b. +// +// Solidity: event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender) +func (_AccessControl *AccessControlFilterer) FilterRoleRevoked(opts *bind.FilterOpts, role [][32]byte, account []common.Address, sender []common.Address) (*AccessControlRoleRevokedIterator, error) { + + var roleRule []interface{} + for _, roleItem := range role { + roleRule = append(roleRule, roleItem) + } + var accountRule []interface{} + for _, accountItem := range account { + accountRule = append(accountRule, accountItem) + } + var senderRule []interface{} + for _, senderItem := range sender { + senderRule = append(senderRule, senderItem) + } + + logs, sub, err := _AccessControl.contract.FilterLogs(opts, "RoleRevoked", roleRule, accountRule, senderRule) + if err != nil { + return nil, err + } + return &AccessControlRoleRevokedIterator{contract: _AccessControl.contract, event: "RoleRevoked", logs: logs, sub: sub}, nil +} + +// WatchRoleRevoked is a free log subscription operation binding the contract event 0xf6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b. +// +// Solidity: event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender) +func (_AccessControl *AccessControlFilterer) WatchRoleRevoked(opts *bind.WatchOpts, sink chan<- *AccessControlRoleRevoked, role [][32]byte, account []common.Address, sender []common.Address) (event.Subscription, error) { + + var roleRule []interface{} + for _, roleItem := range role { + roleRule = append(roleRule, roleItem) + } + var accountRule []interface{} + for _, accountItem := range account { + accountRule = append(accountRule, accountItem) + } + var senderRule []interface{} + for _, senderItem := range sender { + senderRule = append(senderRule, senderItem) + } + + logs, sub, err := _AccessControl.contract.WatchLogs(opts, "RoleRevoked", roleRule, accountRule, senderRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(AccessControlRoleRevoked) + if err := _AccessControl.contract.UnpackLog(event, "RoleRevoked", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseRoleRevoked is a log parse operation binding the contract event 0xf6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b. +// +// Solidity: event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender) +func (_AccessControl *AccessControlFilterer) ParseRoleRevoked(log types.Log) (*AccessControlRoleRevoked, error) { + event := new(AccessControlRoleRevoked) + if err := _AccessControl.contract.UnpackLog(event, "RoleRevoked", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// AccessControlEnumerableMetaData contains all meta data concerning the AccessControlEnumerable contract. +var AccessControlEnumerableMetaData = &bind.MetaData{ + ABI: "[{\"inputs\":[],\"name\":\"AccessControlBadConfirmation\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"neededRole\",\"type\":\"bytes32\"}],\"name\":\"AccessControlUnauthorizedAccount\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"previousAdminRole\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"newAdminRole\",\"type\":\"bytes32\"}],\"name\":\"RoleAdminChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleGranted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleRevoked\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"DEFAULT_ADMIN_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"}],\"name\":\"getRoleAdmin\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"index\",\"type\":\"uint256\"}],\"name\":\"getRoleMember\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"}],\"name\":\"getRoleMemberCount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"grantRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"hasRole\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"callerConfirmation\",\"type\":\"address\"}],\"name\":\"renounceRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"revokeRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes4\",\"name\":\"interfaceId\",\"type\":\"bytes4\"}],\"name\":\"supportsInterface\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"}]", + Sigs: map[string]string{ + "a217fddf": "DEFAULT_ADMIN_ROLE()", + "248a9ca3": "getRoleAdmin(bytes32)", + "9010d07c": "getRoleMember(bytes32,uint256)", + "ca15c873": "getRoleMemberCount(bytes32)", + "2f2ff15d": "grantRole(bytes32,address)", + "91d14854": "hasRole(bytes32,address)", + "36568abe": "renounceRole(bytes32,address)", + "d547741f": "revokeRole(bytes32,address)", + "01ffc9a7": "supportsInterface(bytes4)", + }, +} + +// AccessControlEnumerableABI is the input ABI used to generate the binding from. +// Deprecated: Use AccessControlEnumerableMetaData.ABI instead. +var AccessControlEnumerableABI = AccessControlEnumerableMetaData.ABI + +// Deprecated: Use AccessControlEnumerableMetaData.Sigs instead. +// AccessControlEnumerableFuncSigs maps the 4-byte function signature to its string representation. +var AccessControlEnumerableFuncSigs = AccessControlEnumerableMetaData.Sigs + +// AccessControlEnumerable is an auto generated Go binding around an Ethereum contract. +type AccessControlEnumerable struct { + AccessControlEnumerableCaller // Read-only binding to the contract + AccessControlEnumerableTransactor // Write-only binding to the contract + AccessControlEnumerableFilterer // Log filterer for contract events +} + +// AccessControlEnumerableCaller is an auto generated read-only Go binding around an Ethereum contract. +type AccessControlEnumerableCaller struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// AccessControlEnumerableTransactor is an auto generated write-only Go binding around an Ethereum contract. +type AccessControlEnumerableTransactor struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// AccessControlEnumerableFilterer is an auto generated log filtering Go binding around an Ethereum contract events. +type AccessControlEnumerableFilterer struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// AccessControlEnumerableSession is an auto generated Go binding around an Ethereum contract, +// with pre-set call and transact options. +type AccessControlEnumerableSession struct { + Contract *AccessControlEnumerable // Generic contract binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// AccessControlEnumerableCallerSession is an auto generated read-only Go binding around an Ethereum contract, +// with pre-set call options. +type AccessControlEnumerableCallerSession struct { + Contract *AccessControlEnumerableCaller // Generic contract caller binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session +} + +// AccessControlEnumerableTransactorSession is an auto generated write-only Go binding around an Ethereum contract, +// with pre-set transact options. +type AccessControlEnumerableTransactorSession struct { + Contract *AccessControlEnumerableTransactor // Generic contract transactor binding to set the session for + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// AccessControlEnumerableRaw is an auto generated low-level Go binding around an Ethereum contract. +type AccessControlEnumerableRaw struct { + Contract *AccessControlEnumerable // Generic contract binding to access the raw methods on +} + +// AccessControlEnumerableCallerRaw is an auto generated low-level read-only Go binding around an Ethereum contract. +type AccessControlEnumerableCallerRaw struct { + Contract *AccessControlEnumerableCaller // Generic read-only contract binding to access the raw methods on +} + +// AccessControlEnumerableTransactorRaw is an auto generated low-level write-only Go binding around an Ethereum contract. +type AccessControlEnumerableTransactorRaw struct { + Contract *AccessControlEnumerableTransactor // Generic write-only contract binding to access the raw methods on +} + +// NewAccessControlEnumerable creates a new instance of AccessControlEnumerable, bound to a specific deployed contract. +func NewAccessControlEnumerable(address common.Address, backend bind.ContractBackend) (*AccessControlEnumerable, error) { + contract, err := bindAccessControlEnumerable(address, backend, backend, backend) + if err != nil { + return nil, err + } + return &AccessControlEnumerable{AccessControlEnumerableCaller: AccessControlEnumerableCaller{contract: contract}, AccessControlEnumerableTransactor: AccessControlEnumerableTransactor{contract: contract}, AccessControlEnumerableFilterer: AccessControlEnumerableFilterer{contract: contract}}, nil +} + +// NewAccessControlEnumerableCaller creates a new read-only instance of AccessControlEnumerable, bound to a specific deployed contract. +func NewAccessControlEnumerableCaller(address common.Address, caller bind.ContractCaller) (*AccessControlEnumerableCaller, error) { + contract, err := bindAccessControlEnumerable(address, caller, nil, nil) + if err != nil { + return nil, err + } + return &AccessControlEnumerableCaller{contract: contract}, nil +} + +// NewAccessControlEnumerableTransactor creates a new write-only instance of AccessControlEnumerable, bound to a specific deployed contract. +func NewAccessControlEnumerableTransactor(address common.Address, transactor bind.ContractTransactor) (*AccessControlEnumerableTransactor, error) { + contract, err := bindAccessControlEnumerable(address, nil, transactor, nil) + if err != nil { + return nil, err + } + return &AccessControlEnumerableTransactor{contract: contract}, nil +} + +// NewAccessControlEnumerableFilterer creates a new log filterer instance of AccessControlEnumerable, bound to a specific deployed contract. +func NewAccessControlEnumerableFilterer(address common.Address, filterer bind.ContractFilterer) (*AccessControlEnumerableFilterer, error) { + contract, err := bindAccessControlEnumerable(address, nil, nil, filterer) + if err != nil { + return nil, err + } + return &AccessControlEnumerableFilterer{contract: contract}, nil +} + +// bindAccessControlEnumerable binds a generic wrapper to an already deployed contract. +func bindAccessControlEnumerable(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) { + parsed, err := AccessControlEnumerableMetaData.GetAbi() + if err != nil { + return nil, err + } + return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil +} + +// Call invokes the (constant) contract method with params as input values and +// sets the output to result. The result type might be a single field for simple +// returns, a slice of interfaces for anonymous returns and a struct for named +// returns. +func (_AccessControlEnumerable *AccessControlEnumerableRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _AccessControlEnumerable.Contract.AccessControlEnumerableCaller.contract.Call(opts, result, method, params...) +} + +// Transfer initiates a plain transaction to move funds to the contract, calling +// its default method if one is available. +func (_AccessControlEnumerable *AccessControlEnumerableRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _AccessControlEnumerable.Contract.AccessControlEnumerableTransactor.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_AccessControlEnumerable *AccessControlEnumerableRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _AccessControlEnumerable.Contract.AccessControlEnumerableTransactor.contract.Transact(opts, method, params...) +} + +// Call invokes the (constant) contract method with params as input values and +// sets the output to result. The result type might be a single field for simple +// returns, a slice of interfaces for anonymous returns and a struct for named +// returns. +func (_AccessControlEnumerable *AccessControlEnumerableCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _AccessControlEnumerable.Contract.contract.Call(opts, result, method, params...) +} + +// Transfer initiates a plain transaction to move funds to the contract, calling +// its default method if one is available. +func (_AccessControlEnumerable *AccessControlEnumerableTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _AccessControlEnumerable.Contract.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_AccessControlEnumerable *AccessControlEnumerableTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _AccessControlEnumerable.Contract.contract.Transact(opts, method, params...) +} + +// DEFAULTADMINROLE is a free data retrieval call binding the contract method 0xa217fddf. +// +// Solidity: function DEFAULT_ADMIN_ROLE() view returns(bytes32) +func (_AccessControlEnumerable *AccessControlEnumerableCaller) DEFAULTADMINROLE(opts *bind.CallOpts) ([32]byte, error) { + var out []interface{} + err := _AccessControlEnumerable.contract.Call(opts, &out, "DEFAULT_ADMIN_ROLE") + + if err != nil { + return *new([32]byte), err + } + + out0 := *abi.ConvertType(out[0], new([32]byte)).(*[32]byte) + + return out0, err + +} + +// DEFAULTADMINROLE is a free data retrieval call binding the contract method 0xa217fddf. +// +// Solidity: function DEFAULT_ADMIN_ROLE() view returns(bytes32) +func (_AccessControlEnumerable *AccessControlEnumerableSession) DEFAULTADMINROLE() ([32]byte, error) { + return _AccessControlEnumerable.Contract.DEFAULTADMINROLE(&_AccessControlEnumerable.CallOpts) +} + +// DEFAULTADMINROLE is a free data retrieval call binding the contract method 0xa217fddf. +// +// Solidity: function DEFAULT_ADMIN_ROLE() view returns(bytes32) +func (_AccessControlEnumerable *AccessControlEnumerableCallerSession) DEFAULTADMINROLE() ([32]byte, error) { + return _AccessControlEnumerable.Contract.DEFAULTADMINROLE(&_AccessControlEnumerable.CallOpts) +} + +// GetRoleAdmin is a free data retrieval call binding the contract method 0x248a9ca3. +// +// Solidity: function getRoleAdmin(bytes32 role) view returns(bytes32) +func (_AccessControlEnumerable *AccessControlEnumerableCaller) GetRoleAdmin(opts *bind.CallOpts, role [32]byte) ([32]byte, error) { + var out []interface{} + err := _AccessControlEnumerable.contract.Call(opts, &out, "getRoleAdmin", role) + + if err != nil { + return *new([32]byte), err + } + + out0 := *abi.ConvertType(out[0], new([32]byte)).(*[32]byte) + + return out0, err + +} + +// GetRoleAdmin is a free data retrieval call binding the contract method 0x248a9ca3. +// +// Solidity: function getRoleAdmin(bytes32 role) view returns(bytes32) +func (_AccessControlEnumerable *AccessControlEnumerableSession) GetRoleAdmin(role [32]byte) ([32]byte, error) { + return _AccessControlEnumerable.Contract.GetRoleAdmin(&_AccessControlEnumerable.CallOpts, role) +} + +// GetRoleAdmin is a free data retrieval call binding the contract method 0x248a9ca3. +// +// Solidity: function getRoleAdmin(bytes32 role) view returns(bytes32) +func (_AccessControlEnumerable *AccessControlEnumerableCallerSession) GetRoleAdmin(role [32]byte) ([32]byte, error) { + return _AccessControlEnumerable.Contract.GetRoleAdmin(&_AccessControlEnumerable.CallOpts, role) +} + +// GetRoleMember is a free data retrieval call binding the contract method 0x9010d07c. +// +// Solidity: function getRoleMember(bytes32 role, uint256 index) view returns(address) +func (_AccessControlEnumerable *AccessControlEnumerableCaller) GetRoleMember(opts *bind.CallOpts, role [32]byte, index *big.Int) (common.Address, error) { + var out []interface{} + err := _AccessControlEnumerable.contract.Call(opts, &out, "getRoleMember", role, index) + + if err != nil { + return *new(common.Address), err + } + + out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) + + return out0, err + +} + +// GetRoleMember is a free data retrieval call binding the contract method 0x9010d07c. +// +// Solidity: function getRoleMember(bytes32 role, uint256 index) view returns(address) +func (_AccessControlEnumerable *AccessControlEnumerableSession) GetRoleMember(role [32]byte, index *big.Int) (common.Address, error) { + return _AccessControlEnumerable.Contract.GetRoleMember(&_AccessControlEnumerable.CallOpts, role, index) +} + +// GetRoleMember is a free data retrieval call binding the contract method 0x9010d07c. +// +// Solidity: function getRoleMember(bytes32 role, uint256 index) view returns(address) +func (_AccessControlEnumerable *AccessControlEnumerableCallerSession) GetRoleMember(role [32]byte, index *big.Int) (common.Address, error) { + return _AccessControlEnumerable.Contract.GetRoleMember(&_AccessControlEnumerable.CallOpts, role, index) +} + +// GetRoleMemberCount is a free data retrieval call binding the contract method 0xca15c873. +// +// Solidity: function getRoleMemberCount(bytes32 role) view returns(uint256) +func (_AccessControlEnumerable *AccessControlEnumerableCaller) GetRoleMemberCount(opts *bind.CallOpts, role [32]byte) (*big.Int, error) { + var out []interface{} + err := _AccessControlEnumerable.contract.Call(opts, &out, "getRoleMemberCount", role) + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// GetRoleMemberCount is a free data retrieval call binding the contract method 0xca15c873. +// +// Solidity: function getRoleMemberCount(bytes32 role) view returns(uint256) +func (_AccessControlEnumerable *AccessControlEnumerableSession) GetRoleMemberCount(role [32]byte) (*big.Int, error) { + return _AccessControlEnumerable.Contract.GetRoleMemberCount(&_AccessControlEnumerable.CallOpts, role) +} + +// GetRoleMemberCount is a free data retrieval call binding the contract method 0xca15c873. +// +// Solidity: function getRoleMemberCount(bytes32 role) view returns(uint256) +func (_AccessControlEnumerable *AccessControlEnumerableCallerSession) GetRoleMemberCount(role [32]byte) (*big.Int, error) { + return _AccessControlEnumerable.Contract.GetRoleMemberCount(&_AccessControlEnumerable.CallOpts, role) +} + +// HasRole is a free data retrieval call binding the contract method 0x91d14854. +// +// Solidity: function hasRole(bytes32 role, address account) view returns(bool) +func (_AccessControlEnumerable *AccessControlEnumerableCaller) HasRole(opts *bind.CallOpts, role [32]byte, account common.Address) (bool, error) { + var out []interface{} + err := _AccessControlEnumerable.contract.Call(opts, &out, "hasRole", role, account) + + if err != nil { + return *new(bool), err + } + + out0 := *abi.ConvertType(out[0], new(bool)).(*bool) + + return out0, err + +} + +// HasRole is a free data retrieval call binding the contract method 0x91d14854. +// +// Solidity: function hasRole(bytes32 role, address account) view returns(bool) +func (_AccessControlEnumerable *AccessControlEnumerableSession) HasRole(role [32]byte, account common.Address) (bool, error) { + return _AccessControlEnumerable.Contract.HasRole(&_AccessControlEnumerable.CallOpts, role, account) +} + +// HasRole is a free data retrieval call binding the contract method 0x91d14854. +// +// Solidity: function hasRole(bytes32 role, address account) view returns(bool) +func (_AccessControlEnumerable *AccessControlEnumerableCallerSession) HasRole(role [32]byte, account common.Address) (bool, error) { + return _AccessControlEnumerable.Contract.HasRole(&_AccessControlEnumerable.CallOpts, role, account) +} + +// SupportsInterface is a free data retrieval call binding the contract method 0x01ffc9a7. +// +// Solidity: function supportsInterface(bytes4 interfaceId) view returns(bool) +func (_AccessControlEnumerable *AccessControlEnumerableCaller) SupportsInterface(opts *bind.CallOpts, interfaceId [4]byte) (bool, error) { + var out []interface{} + err := _AccessControlEnumerable.contract.Call(opts, &out, "supportsInterface", interfaceId) + + if err != nil { + return *new(bool), err + } + + out0 := *abi.ConvertType(out[0], new(bool)).(*bool) + + return out0, err + +} + +// SupportsInterface is a free data retrieval call binding the contract method 0x01ffc9a7. +// +// Solidity: function supportsInterface(bytes4 interfaceId) view returns(bool) +func (_AccessControlEnumerable *AccessControlEnumerableSession) SupportsInterface(interfaceId [4]byte) (bool, error) { + return _AccessControlEnumerable.Contract.SupportsInterface(&_AccessControlEnumerable.CallOpts, interfaceId) +} + +// SupportsInterface is a free data retrieval call binding the contract method 0x01ffc9a7. +// +// Solidity: function supportsInterface(bytes4 interfaceId) view returns(bool) +func (_AccessControlEnumerable *AccessControlEnumerableCallerSession) SupportsInterface(interfaceId [4]byte) (bool, error) { + return _AccessControlEnumerable.Contract.SupportsInterface(&_AccessControlEnumerable.CallOpts, interfaceId) +} + +// GrantRole is a paid mutator transaction binding the contract method 0x2f2ff15d. +// +// Solidity: function grantRole(bytes32 role, address account) returns() +func (_AccessControlEnumerable *AccessControlEnumerableTransactor) GrantRole(opts *bind.TransactOpts, role [32]byte, account common.Address) (*types.Transaction, error) { + return _AccessControlEnumerable.contract.Transact(opts, "grantRole", role, account) +} + +// GrantRole is a paid mutator transaction binding the contract method 0x2f2ff15d. +// +// Solidity: function grantRole(bytes32 role, address account) returns() +func (_AccessControlEnumerable *AccessControlEnumerableSession) GrantRole(role [32]byte, account common.Address) (*types.Transaction, error) { + return _AccessControlEnumerable.Contract.GrantRole(&_AccessControlEnumerable.TransactOpts, role, account) +} + +// GrantRole is a paid mutator transaction binding the contract method 0x2f2ff15d. +// +// Solidity: function grantRole(bytes32 role, address account) returns() +func (_AccessControlEnumerable *AccessControlEnumerableTransactorSession) GrantRole(role [32]byte, account common.Address) (*types.Transaction, error) { + return _AccessControlEnumerable.Contract.GrantRole(&_AccessControlEnumerable.TransactOpts, role, account) +} + +// RenounceRole is a paid mutator transaction binding the contract method 0x36568abe. +// +// Solidity: function renounceRole(bytes32 role, address callerConfirmation) returns() +func (_AccessControlEnumerable *AccessControlEnumerableTransactor) RenounceRole(opts *bind.TransactOpts, role [32]byte, callerConfirmation common.Address) (*types.Transaction, error) { + return _AccessControlEnumerable.contract.Transact(opts, "renounceRole", role, callerConfirmation) +} + +// RenounceRole is a paid mutator transaction binding the contract method 0x36568abe. +// +// Solidity: function renounceRole(bytes32 role, address callerConfirmation) returns() +func (_AccessControlEnumerable *AccessControlEnumerableSession) RenounceRole(role [32]byte, callerConfirmation common.Address) (*types.Transaction, error) { + return _AccessControlEnumerable.Contract.RenounceRole(&_AccessControlEnumerable.TransactOpts, role, callerConfirmation) +} + +// RenounceRole is a paid mutator transaction binding the contract method 0x36568abe. +// +// Solidity: function renounceRole(bytes32 role, address callerConfirmation) returns() +func (_AccessControlEnumerable *AccessControlEnumerableTransactorSession) RenounceRole(role [32]byte, callerConfirmation common.Address) (*types.Transaction, error) { + return _AccessControlEnumerable.Contract.RenounceRole(&_AccessControlEnumerable.TransactOpts, role, callerConfirmation) +} + +// RevokeRole is a paid mutator transaction binding the contract method 0xd547741f. +// +// Solidity: function revokeRole(bytes32 role, address account) returns() +func (_AccessControlEnumerable *AccessControlEnumerableTransactor) RevokeRole(opts *bind.TransactOpts, role [32]byte, account common.Address) (*types.Transaction, error) { + return _AccessControlEnumerable.contract.Transact(opts, "revokeRole", role, account) +} + +// RevokeRole is a paid mutator transaction binding the contract method 0xd547741f. +// +// Solidity: function revokeRole(bytes32 role, address account) returns() +func (_AccessControlEnumerable *AccessControlEnumerableSession) RevokeRole(role [32]byte, account common.Address) (*types.Transaction, error) { + return _AccessControlEnumerable.Contract.RevokeRole(&_AccessControlEnumerable.TransactOpts, role, account) +} + +// RevokeRole is a paid mutator transaction binding the contract method 0xd547741f. +// +// Solidity: function revokeRole(bytes32 role, address account) returns() +func (_AccessControlEnumerable *AccessControlEnumerableTransactorSession) RevokeRole(role [32]byte, account common.Address) (*types.Transaction, error) { + return _AccessControlEnumerable.Contract.RevokeRole(&_AccessControlEnumerable.TransactOpts, role, account) +} + +// AccessControlEnumerableRoleAdminChangedIterator is returned from FilterRoleAdminChanged and is used to iterate over the raw logs and unpacked data for RoleAdminChanged events raised by the AccessControlEnumerable contract. +type AccessControlEnumerableRoleAdminChangedIterator struct { + Event *AccessControlEnumerableRoleAdminChanged // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *AccessControlEnumerableRoleAdminChangedIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(AccessControlEnumerableRoleAdminChanged) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(AccessControlEnumerableRoleAdminChanged) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *AccessControlEnumerableRoleAdminChangedIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *AccessControlEnumerableRoleAdminChangedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// AccessControlEnumerableRoleAdminChanged represents a RoleAdminChanged event raised by the AccessControlEnumerable contract. +type AccessControlEnumerableRoleAdminChanged struct { + Role [32]byte + PreviousAdminRole [32]byte + NewAdminRole [32]byte + Raw types.Log // Blockchain specific contextual infos +} + +// FilterRoleAdminChanged is a free log retrieval operation binding the contract event 0xbd79b86ffe0ab8e8776151514217cd7cacd52c909f66475c3af44e129f0b00ff. +// +// Solidity: event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole) +func (_AccessControlEnumerable *AccessControlEnumerableFilterer) FilterRoleAdminChanged(opts *bind.FilterOpts, role [][32]byte, previousAdminRole [][32]byte, newAdminRole [][32]byte) (*AccessControlEnumerableRoleAdminChangedIterator, error) { + + var roleRule []interface{} + for _, roleItem := range role { + roleRule = append(roleRule, roleItem) + } + var previousAdminRoleRule []interface{} + for _, previousAdminRoleItem := range previousAdminRole { + previousAdminRoleRule = append(previousAdminRoleRule, previousAdminRoleItem) + } + var newAdminRoleRule []interface{} + for _, newAdminRoleItem := range newAdminRole { + newAdminRoleRule = append(newAdminRoleRule, newAdminRoleItem) + } + + logs, sub, err := _AccessControlEnumerable.contract.FilterLogs(opts, "RoleAdminChanged", roleRule, previousAdminRoleRule, newAdminRoleRule) + if err != nil { + return nil, err + } + return &AccessControlEnumerableRoleAdminChangedIterator{contract: _AccessControlEnumerable.contract, event: "RoleAdminChanged", logs: logs, sub: sub}, nil +} + +// WatchRoleAdminChanged is a free log subscription operation binding the contract event 0xbd79b86ffe0ab8e8776151514217cd7cacd52c909f66475c3af44e129f0b00ff. +// +// Solidity: event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole) +func (_AccessControlEnumerable *AccessControlEnumerableFilterer) WatchRoleAdminChanged(opts *bind.WatchOpts, sink chan<- *AccessControlEnumerableRoleAdminChanged, role [][32]byte, previousAdminRole [][32]byte, newAdminRole [][32]byte) (event.Subscription, error) { + + var roleRule []interface{} + for _, roleItem := range role { + roleRule = append(roleRule, roleItem) + } + var previousAdminRoleRule []interface{} + for _, previousAdminRoleItem := range previousAdminRole { + previousAdminRoleRule = append(previousAdminRoleRule, previousAdminRoleItem) + } + var newAdminRoleRule []interface{} + for _, newAdminRoleItem := range newAdminRole { + newAdminRoleRule = append(newAdminRoleRule, newAdminRoleItem) + } + + logs, sub, err := _AccessControlEnumerable.contract.WatchLogs(opts, "RoleAdminChanged", roleRule, previousAdminRoleRule, newAdminRoleRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(AccessControlEnumerableRoleAdminChanged) + if err := _AccessControlEnumerable.contract.UnpackLog(event, "RoleAdminChanged", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseRoleAdminChanged is a log parse operation binding the contract event 0xbd79b86ffe0ab8e8776151514217cd7cacd52c909f66475c3af44e129f0b00ff. +// +// Solidity: event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole) +func (_AccessControlEnumerable *AccessControlEnumerableFilterer) ParseRoleAdminChanged(log types.Log) (*AccessControlEnumerableRoleAdminChanged, error) { + event := new(AccessControlEnumerableRoleAdminChanged) + if err := _AccessControlEnumerable.contract.UnpackLog(event, "RoleAdminChanged", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// AccessControlEnumerableRoleGrantedIterator is returned from FilterRoleGranted and is used to iterate over the raw logs and unpacked data for RoleGranted events raised by the AccessControlEnumerable contract. +type AccessControlEnumerableRoleGrantedIterator struct { + Event *AccessControlEnumerableRoleGranted // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *AccessControlEnumerableRoleGrantedIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(AccessControlEnumerableRoleGranted) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(AccessControlEnumerableRoleGranted) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *AccessControlEnumerableRoleGrantedIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *AccessControlEnumerableRoleGrantedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// AccessControlEnumerableRoleGranted represents a RoleGranted event raised by the AccessControlEnumerable contract. +type AccessControlEnumerableRoleGranted struct { + Role [32]byte + Account common.Address + Sender common.Address + Raw types.Log // Blockchain specific contextual infos +} + +// FilterRoleGranted is a free log retrieval operation binding the contract event 0x2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d. +// +// Solidity: event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender) +func (_AccessControlEnumerable *AccessControlEnumerableFilterer) FilterRoleGranted(opts *bind.FilterOpts, role [][32]byte, account []common.Address, sender []common.Address) (*AccessControlEnumerableRoleGrantedIterator, error) { + + var roleRule []interface{} + for _, roleItem := range role { + roleRule = append(roleRule, roleItem) + } + var accountRule []interface{} + for _, accountItem := range account { + accountRule = append(accountRule, accountItem) + } + var senderRule []interface{} + for _, senderItem := range sender { + senderRule = append(senderRule, senderItem) + } + + logs, sub, err := _AccessControlEnumerable.contract.FilterLogs(opts, "RoleGranted", roleRule, accountRule, senderRule) + if err != nil { + return nil, err + } + return &AccessControlEnumerableRoleGrantedIterator{contract: _AccessControlEnumerable.contract, event: "RoleGranted", logs: logs, sub: sub}, nil +} + +// WatchRoleGranted is a free log subscription operation binding the contract event 0x2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d. +// +// Solidity: event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender) +func (_AccessControlEnumerable *AccessControlEnumerableFilterer) WatchRoleGranted(opts *bind.WatchOpts, sink chan<- *AccessControlEnumerableRoleGranted, role [][32]byte, account []common.Address, sender []common.Address) (event.Subscription, error) { + + var roleRule []interface{} + for _, roleItem := range role { + roleRule = append(roleRule, roleItem) + } + var accountRule []interface{} + for _, accountItem := range account { + accountRule = append(accountRule, accountItem) + } + var senderRule []interface{} + for _, senderItem := range sender { + senderRule = append(senderRule, senderItem) + } + + logs, sub, err := _AccessControlEnumerable.contract.WatchLogs(opts, "RoleGranted", roleRule, accountRule, senderRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(AccessControlEnumerableRoleGranted) + if err := _AccessControlEnumerable.contract.UnpackLog(event, "RoleGranted", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseRoleGranted is a log parse operation binding the contract event 0x2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d. +// +// Solidity: event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender) +func (_AccessControlEnumerable *AccessControlEnumerableFilterer) ParseRoleGranted(log types.Log) (*AccessControlEnumerableRoleGranted, error) { + event := new(AccessControlEnumerableRoleGranted) + if err := _AccessControlEnumerable.contract.UnpackLog(event, "RoleGranted", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// AccessControlEnumerableRoleRevokedIterator is returned from FilterRoleRevoked and is used to iterate over the raw logs and unpacked data for RoleRevoked events raised by the AccessControlEnumerable contract. +type AccessControlEnumerableRoleRevokedIterator struct { + Event *AccessControlEnumerableRoleRevoked // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *AccessControlEnumerableRoleRevokedIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(AccessControlEnumerableRoleRevoked) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(AccessControlEnumerableRoleRevoked) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *AccessControlEnumerableRoleRevokedIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *AccessControlEnumerableRoleRevokedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// AccessControlEnumerableRoleRevoked represents a RoleRevoked event raised by the AccessControlEnumerable contract. +type AccessControlEnumerableRoleRevoked struct { + Role [32]byte + Account common.Address + Sender common.Address + Raw types.Log // Blockchain specific contextual infos +} + +// FilterRoleRevoked is a free log retrieval operation binding the contract event 0xf6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b. +// +// Solidity: event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender) +func (_AccessControlEnumerable *AccessControlEnumerableFilterer) FilterRoleRevoked(opts *bind.FilterOpts, role [][32]byte, account []common.Address, sender []common.Address) (*AccessControlEnumerableRoleRevokedIterator, error) { + + var roleRule []interface{} + for _, roleItem := range role { + roleRule = append(roleRule, roleItem) + } + var accountRule []interface{} + for _, accountItem := range account { + accountRule = append(accountRule, accountItem) + } + var senderRule []interface{} + for _, senderItem := range sender { + senderRule = append(senderRule, senderItem) + } + + logs, sub, err := _AccessControlEnumerable.contract.FilterLogs(opts, "RoleRevoked", roleRule, accountRule, senderRule) + if err != nil { + return nil, err + } + return &AccessControlEnumerableRoleRevokedIterator{contract: _AccessControlEnumerable.contract, event: "RoleRevoked", logs: logs, sub: sub}, nil +} + +// WatchRoleRevoked is a free log subscription operation binding the contract event 0xf6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b. +// +// Solidity: event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender) +func (_AccessControlEnumerable *AccessControlEnumerableFilterer) WatchRoleRevoked(opts *bind.WatchOpts, sink chan<- *AccessControlEnumerableRoleRevoked, role [][32]byte, account []common.Address, sender []common.Address) (event.Subscription, error) { + + var roleRule []interface{} + for _, roleItem := range role { + roleRule = append(roleRule, roleItem) + } + var accountRule []interface{} + for _, accountItem := range account { + accountRule = append(accountRule, accountItem) + } + var senderRule []interface{} + for _, senderItem := range sender { + senderRule = append(senderRule, senderItem) + } + + logs, sub, err := _AccessControlEnumerable.contract.WatchLogs(opts, "RoleRevoked", roleRule, accountRule, senderRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(AccessControlEnumerableRoleRevoked) + if err := _AccessControlEnumerable.contract.UnpackLog(event, "RoleRevoked", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseRoleRevoked is a log parse operation binding the contract event 0xf6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b. +// +// Solidity: event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender) +func (_AccessControlEnumerable *AccessControlEnumerableFilterer) ParseRoleRevoked(log types.Log) (*AccessControlEnumerableRoleRevoked, error) { + event := new(AccessControlEnumerableRoleRevoked) + if err := _AccessControlEnumerable.contract.UnpackLog(event, "RoleRevoked", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// AddressMetaData contains all meta data concerning the Address contract. +var AddressMetaData = &bind.MetaData{ + ABI: "[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"}],\"name\":\"AddressEmptyCode\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"AddressInsufficientBalance\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"FailedInnerCall\",\"type\":\"error\"}]", + Bin: "0x60556032600b8282823980515f1a607314602657634e487b7160e01b5f525f60045260245ffd5b305f52607381538281f3fe730000000000000000000000000000000000000000301460806040525f80fdfea264697066735822122066ad3e1b6dabcf400c86562013c52581c196e1c9e2e058e0440d32fcd4e26ad264736f6c63430008180033", +} + +// AddressABI is the input ABI used to generate the binding from. +// Deprecated: Use AddressMetaData.ABI instead. +var AddressABI = AddressMetaData.ABI + +// AddressBin is the compiled bytecode used for deploying new contracts. +// Deprecated: Use AddressMetaData.Bin instead. +var AddressBin = AddressMetaData.Bin + +// DeployAddress deploys a new Ethereum contract, binding an instance of Address to it. +func DeployAddress(auth *bind.TransactOpts, backend bind.ContractBackend) (common.Address, *types.Transaction, *Address, error) { + parsed, err := AddressMetaData.GetAbi() + if err != nil { + return common.Address{}, nil, nil, err + } + if parsed == nil { + return common.Address{}, nil, nil, errors.New("GetABI returned nil") + } + + address, tx, contract, err := bind.DeployContract(auth, *parsed, common.FromHex(AddressBin), backend) + if err != nil { + return common.Address{}, nil, nil, err + } + return address, tx, &Address{AddressCaller: AddressCaller{contract: contract}, AddressTransactor: AddressTransactor{contract: contract}, AddressFilterer: AddressFilterer{contract: contract}}, nil +} + +// Address is an auto generated Go binding around an Ethereum contract. +type Address struct { + AddressCaller // Read-only binding to the contract + AddressTransactor // Write-only binding to the contract + AddressFilterer // Log filterer for contract events +} + +// AddressCaller is an auto generated read-only Go binding around an Ethereum contract. +type AddressCaller struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// AddressTransactor is an auto generated write-only Go binding around an Ethereum contract. +type AddressTransactor struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// AddressFilterer is an auto generated log filtering Go binding around an Ethereum contract events. +type AddressFilterer struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// AddressSession is an auto generated Go binding around an Ethereum contract, +// with pre-set call and transact options. +type AddressSession struct { + Contract *Address // Generic contract binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// AddressCallerSession is an auto generated read-only Go binding around an Ethereum contract, +// with pre-set call options. +type AddressCallerSession struct { + Contract *AddressCaller // Generic contract caller binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session +} + +// AddressTransactorSession is an auto generated write-only Go binding around an Ethereum contract, +// with pre-set transact options. +type AddressTransactorSession struct { + Contract *AddressTransactor // Generic contract transactor binding to set the session for + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// AddressRaw is an auto generated low-level Go binding around an Ethereum contract. +type AddressRaw struct { + Contract *Address // Generic contract binding to access the raw methods on +} + +// AddressCallerRaw is an auto generated low-level read-only Go binding around an Ethereum contract. +type AddressCallerRaw struct { + Contract *AddressCaller // Generic read-only contract binding to access the raw methods on +} + +// AddressTransactorRaw is an auto generated low-level write-only Go binding around an Ethereum contract. +type AddressTransactorRaw struct { + Contract *AddressTransactor // Generic write-only contract binding to access the raw methods on +} + +// NewAddress creates a new instance of Address, bound to a specific deployed contract. +func NewAddress(address common.Address, backend bind.ContractBackend) (*Address, error) { + contract, err := bindAddress(address, backend, backend, backend) + if err != nil { + return nil, err + } + return &Address{AddressCaller: AddressCaller{contract: contract}, AddressTransactor: AddressTransactor{contract: contract}, AddressFilterer: AddressFilterer{contract: contract}}, nil +} + +// NewAddressCaller creates a new read-only instance of Address, bound to a specific deployed contract. +func NewAddressCaller(address common.Address, caller bind.ContractCaller) (*AddressCaller, error) { + contract, err := bindAddress(address, caller, nil, nil) + if err != nil { + return nil, err + } + return &AddressCaller{contract: contract}, nil +} + +// NewAddressTransactor creates a new write-only instance of Address, bound to a specific deployed contract. +func NewAddressTransactor(address common.Address, transactor bind.ContractTransactor) (*AddressTransactor, error) { + contract, err := bindAddress(address, nil, transactor, nil) + if err != nil { + return nil, err + } + return &AddressTransactor{contract: contract}, nil +} + +// NewAddressFilterer creates a new log filterer instance of Address, bound to a specific deployed contract. +func NewAddressFilterer(address common.Address, filterer bind.ContractFilterer) (*AddressFilterer, error) { + contract, err := bindAddress(address, nil, nil, filterer) + if err != nil { + return nil, err + } + return &AddressFilterer{contract: contract}, nil +} + +// bindAddress binds a generic wrapper to an already deployed contract. +func bindAddress(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) { + parsed, err := AddressMetaData.GetAbi() + if err != nil { + return nil, err + } + return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil +} + +// Call invokes the (constant) contract method with params as input values and +// sets the output to result. The result type might be a single field for simple +// returns, a slice of interfaces for anonymous returns and a struct for named +// returns. +func (_Address *AddressRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _Address.Contract.AddressCaller.contract.Call(opts, result, method, params...) +} + +// Transfer initiates a plain transaction to move funds to the contract, calling +// its default method if one is available. +func (_Address *AddressRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _Address.Contract.AddressTransactor.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_Address *AddressRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _Address.Contract.AddressTransactor.contract.Transact(opts, method, params...) +} + +// Call invokes the (constant) contract method with params as input values and +// sets the output to result. The result type might be a single field for simple +// returns, a slice of interfaces for anonymous returns and a struct for named +// returns. +func (_Address *AddressCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _Address.Contract.contract.Call(opts, result, method, params...) +} + +// Transfer initiates a plain transaction to move funds to the contract, calling +// its default method if one is available. +func (_Address *AddressTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _Address.Contract.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_Address *AddressTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _Address.Contract.contract.Transact(opts, method, params...) +} + +// AdminMetaData contains all meta data concerning the Admin contract. +var AdminMetaData = &bind.MetaData{ + ABI: "[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_owner\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"AccessControlBadConfirmation\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"neededRole\",\"type\":\"bytes32\"}],\"name\":\"AccessControlUnauthorizedAccount\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"}],\"name\":\"AddressEmptyCode\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"AddressInsufficientBalance\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"FailedInnerCall\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"}],\"name\":\"SafeERC20FailedOperation\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"oldChainGasAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newChainGasAmount\",\"type\":\"uint256\"}],\"name\":\"ChainGasAmountUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"oldFeeRate\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newFeeRate\",\"type\":\"uint256\"}],\"name\":\"FeeRateUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"FeesSwept\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"previousAdminRole\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"newAdminRole\",\"type\":\"bytes32\"}],\"name\":\"RoleAdminChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleGranted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleRevoked\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"DEFAULT_ADMIN_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"FEE_BPS\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"FEE_RATE_MAX\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"GOVERNOR_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"GUARD_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"REFUNDER_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"RELAYER_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"chainGasAmount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"}],\"name\":\"getRoleAdmin\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"index\",\"type\":\"uint256\"}],\"name\":\"getRoleMember\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"}],\"name\":\"getRoleMemberCount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"grantRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"hasRole\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"protocolFeeRate\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"protocolFees\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"callerConfirmation\",\"type\":\"address\"}],\"name\":\"renounceRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"revokeRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"newChainGasAmount\",\"type\":\"uint256\"}],\"name\":\"setChainGasAmount\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"newFeeRate\",\"type\":\"uint256\"}],\"name\":\"setProtocolFeeRate\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes4\",\"name\":\"interfaceId\",\"type\":\"bytes4\"}],\"name\":\"supportsInterface\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"}],\"name\":\"sweepProtocolFees\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", + Sigs: map[string]string{ + "a217fddf": "DEFAULT_ADMIN_ROLE()", + "bf333f2c": "FEE_BPS()", + "0f5f6ed7": "FEE_RATE_MAX()", + "ccc57490": "GOVERNOR_ROLE()", + "03ed0ee5": "GUARD_ROLE()", + "5960ccf2": "REFUNDER_ROLE()", + "926d7d7f": "RELAYER_ROLE()", + "e00a83e0": "chainGasAmount()", + "248a9ca3": "getRoleAdmin(bytes32)", + "9010d07c": "getRoleMember(bytes32,uint256)", + "ca15c873": "getRoleMemberCount(bytes32)", + "2f2ff15d": "grantRole(bytes32,address)", + "91d14854": "hasRole(bytes32,address)", + "58f85880": "protocolFeeRate()", + "dcf844a7": "protocolFees(address)", + "36568abe": "renounceRole(bytes32,address)", + "d547741f": "revokeRole(bytes32,address)", + "b250fe6b": "setChainGasAmount(uint256)", + "b13aa2d6": "setProtocolFeeRate(uint256)", + "01ffc9a7": "supportsInterface(bytes4)", + "06f333f2": "sweepProtocolFees(address,address)", + }, + Bin: "0x608060405234801562000010575f80fd5b50604051620013a3380380620013a3833981016040819052620000339162000184565b6200003f5f8262000047565b5050620001ac565b5f8062000055848462000082565b9050801562000079575f8481526001602052604090206200007790846200012d565b505b90505b92915050565b5f828152602081815260408083206001600160a01b038516845290915281205460ff1662000125575f838152602081815260408083206001600160a01b03861684529091529020805460ff19166001179055620000dc3390565b6001600160a01b0316826001600160a01b0316847f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45060016200007c565b505f6200007c565b5f62000079836001600160a01b0384165f8181526001830160205260408120546200012557508154600181810184555f8481526020808220909301849055845484825282860190935260409020919091556200007c565b5f6020828403121562000195575f80fd5b81516001600160a01b038116811462000079575f80fd5b6111e980620001ba5f395ff3fe608060405234801561000f575f80fd5b506004361061016e575f3560e01c806391d14854116100d2578063bf333f2c11610088578063d547741f11610063578063d547741f14610378578063dcf844a71461038b578063e00a83e0146103aa575f80fd5b8063bf333f2c14610334578063ca15c8731461033e578063ccc5749014610351575f80fd5b8063a217fddf116100b8578063a217fddf14610307578063b13aa2d61461030e578063b250fe6b14610321575f80fd5b806391d148541461029d578063926d7d7f146102e0575f80fd5b80632f2ff15d1161012757806358f858801161010d57806358f85880146102355780635960ccf21461023e5780639010d07c14610265575f80fd5b80632f2ff15d1461020f57806336568abe14610222575f80fd5b806306f333f21161015757806306f333f2146101cf5780630f5f6ed7146101e4578063248a9ca3146101ed575f80fd5b806301ffc9a71461017257806303ed0ee51461019a575b5f80fd5b610185610180366004610fcd565b6103b3565b60405190151581526020015b60405180910390f35b6101c17f043c983c49d46f0e102151eaf8085d4a2e6571d5df2d47b013f39bddfd4a639d81565b604051908152602001610191565b6101e26101dd366004611034565b61040e565b005b6101c161271081565b6101c16101fb366004611065565b5f9081526020819052604090206001015490565b6101e261021d36600461107c565b6104fa565b6101e261023036600461107c565b610524565b6101c160025481565b6101c17fdb9556138406326f00296e13ea2ad7db24ba82381212d816b1a40c23b466b32781565b61027861027336600461109d565b61057d565b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610191565b6101856102ab36600461107c565b5f9182526020828152604080842073ffffffffffffffffffffffffffffffffffffffff93909316845291905290205460ff1690565b6101c17fe2b7fb3b832174769106daebcfd6d1970523240dda11281102db9363b83b0dc481565b6101c15f81565b6101e261031c366004611065565b61059b565b6101e261032f366004611065565b61067d565b6101c1620f424081565b6101c161034c366004611065565b6106e5565b6101c17f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f5581565b6101e261038636600461107c565b6106fb565b6101c16103993660046110bd565b60036020525f908152604090205481565b6101c160045481565b5f7fffffffff0000000000000000000000000000000000000000000000000000000082167f5a05180f00000000000000000000000000000000000000000000000000000000148061040857506104088261071f565b92915050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f55610438816107b5565b73ffffffffffffffffffffffffffffffffffffffff83165f908152600360205260408120549081900361046b5750505050565b73ffffffffffffffffffffffffffffffffffffffff84165f8181526003602052604081205561049b9084836107c2565b6040805173ffffffffffffffffffffffffffffffffffffffff8087168252851660208201529081018290527f244e51bc38c1452fa8aaf487bcb4bca36c2baa3a5fbdb776b1eabd8dc6d277cd9060600160405180910390a1505b505050565b5f82815260208190526040902060010154610514816107b5565b61051e8383610914565b50505050565b73ffffffffffffffffffffffffffffffffffffffff81163314610573576040517f6697b23200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6104f58282610947565b5f8281526001602052604081206105949083610972565b9392505050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f556105c5816107b5565b612710821115610636576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f6e657746656552617465203e206d61780000000000000000000000000000000060448201526064015b60405180910390fd5b600280549083905560408051828152602081018590527f14914da2bf76024616fbe1859783fcd4dbddcb179b1f3a854949fbf920dcb95791015b60405180910390a1505050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f556106a7816107b5565b600480549083905560408051828152602081018590527f5cf09b12f3f56b4c564d51b25b40360af6d795198adb61ae0806a36c294323fa9101610670565b5f8181526001602052604081206104089061097d565b5f82815260208190526040902060010154610715816107b5565b61051e8383610947565b5f7fffffffff0000000000000000000000000000000000000000000000000000000082167f7965db0b00000000000000000000000000000000000000000000000000000000148061040857507f01ffc9a7000000000000000000000000000000000000000000000000000000007fffffffff00000000000000000000000000000000000000000000000000000000831614610408565b6107bf8133610986565b50565b3073ffffffffffffffffffffffffffffffffffffffff8316036107e457505050565b805f036107f057505050565b7fffffffffffffffffffffffff111111111111111111111111111111111111111273ffffffffffffffffffffffffffffffffffffffff8416016108f3575f8273ffffffffffffffffffffffffffffffffffffffff16826040515f6040518083038185875af1925050503d805f8114610883576040519150601f19603f3d011682016040523d82523d5f602084013e610888565b606091505b505090508061051e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f455448207472616e73666572206661696c656400000000000000000000000000604482015260640161062d565b6104f573ffffffffffffffffffffffffffffffffffffffff84168383610a0f565b5f806109208484610a9c565b90508015610594575f84815260016020526040902061093f9084610b95565b509392505050565b5f806109538484610bb6565b90508015610594575f84815260016020526040902061093f9084610c6f565b5f6105948383610c90565b5f610408825490565b5f8281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915290205460ff16610a0b576040517fe2517d3f00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff821660048201526024810183905260440161062d565b5050565b6040805173ffffffffffffffffffffffffffffffffffffffff8416602482015260448082018490528251808303909101815260649091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fa9059cbb000000000000000000000000000000000000000000000000000000001790526104f5908490610cb6565b5f8281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915281205460ff16610b8e575f8381526020818152604080832073ffffffffffffffffffffffffffffffffffffffff86168452909152902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055610b2c3390565b73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16847f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a4506001610408565b505f610408565b5f6105948373ffffffffffffffffffffffffffffffffffffffff8416610d4a565b5f8281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915281205460ff1615610b8e575f8381526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8616808552925280832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016905551339286917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a4506001610408565b5f6105948373ffffffffffffffffffffffffffffffffffffffff8416610d8f565b5f825f018281548110610ca557610ca56110d6565b905f5260205f200154905092915050565b5f610cd773ffffffffffffffffffffffffffffffffffffffff841683610e72565b905080515f14158015610cfb575080806020019051810190610cf99190611103565b155b156104f5576040517f5274afe700000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8416600482015260240161062d565b5f818152600183016020526040812054610b8e57508154600181810184555f848152602080822090930184905584548482528286019093526040902091909155610408565b5f8181526001830160205260408120548015610e69575f610db1600183611122565b85549091505f90610dc490600190611122565b9050808214610e23575f865f018281548110610de257610de26110d6565b905f5260205f200154905080875f018481548110610e0257610e026110d6565b5f918252602080832090910192909255918252600188019052604090208390555b8554869080610e3457610e3461115a565b600190038181905f5260205f20015f90559055856001015f8681526020019081526020015f205f905560019350505050610408565b5f915050610408565b606061059483835f845f808573ffffffffffffffffffffffffffffffffffffffff168486604051610ea39190611187565b5f6040518083038185875af1925050503d805f8114610edd576040519150601f19603f3d011682016040523d82523d5f602084013e610ee2565b606091505b5091509150610ef2868383610efc565b9695505050505050565b606082610f1157610f0c82610f8b565b610594565b8151158015610f35575073ffffffffffffffffffffffffffffffffffffffff84163b155b15610f84576040517f9996b31500000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8516600482015260240161062d565b5080610594565b805115610f9b5780518082602001fd5b6040517f1425ea4200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f60208284031215610fdd575f80fd5b81357fffffffff0000000000000000000000000000000000000000000000000000000081168114610594575f80fd5b803573ffffffffffffffffffffffffffffffffffffffff8116811461102f575f80fd5b919050565b5f8060408385031215611045575f80fd5b61104e8361100c565b915061105c6020840161100c565b90509250929050565b5f60208284031215611075575f80fd5b5035919050565b5f806040838503121561108d575f80fd5b8235915061105c6020840161100c565b5f80604083850312156110ae575f80fd5b50508035926020909101359150565b5f602082840312156110cd575f80fd5b6105948261100c565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b5f60208284031215611113575f80fd5b81518015158114610594575f80fd5b81810381811115610408577f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603160045260245ffd5b5f82515f5b818110156111a6576020818601810151858301520161118c565b505f92019182525091905056fea2646970667358221220663496d7fb99c06349f8fc2145322e6c10ba61153be06cea50f6b07db91bc1bd64736f6c63430008180033", +} + +// AdminABI is the input ABI used to generate the binding from. +// Deprecated: Use AdminMetaData.ABI instead. +var AdminABI = AdminMetaData.ABI + +// Deprecated: Use AdminMetaData.Sigs instead. +// AdminFuncSigs maps the 4-byte function signature to its string representation. +var AdminFuncSigs = AdminMetaData.Sigs + +// AdminBin is the compiled bytecode used for deploying new contracts. +// Deprecated: Use AdminMetaData.Bin instead. +var AdminBin = AdminMetaData.Bin + +// DeployAdmin deploys a new Ethereum contract, binding an instance of Admin to it. +func DeployAdmin(auth *bind.TransactOpts, backend bind.ContractBackend, _owner common.Address) (common.Address, *types.Transaction, *Admin, error) { + parsed, err := AdminMetaData.GetAbi() + if err != nil { + return common.Address{}, nil, nil, err + } + if parsed == nil { + return common.Address{}, nil, nil, errors.New("GetABI returned nil") + } + + address, tx, contract, err := bind.DeployContract(auth, *parsed, common.FromHex(AdminBin), backend, _owner) + if err != nil { + return common.Address{}, nil, nil, err + } + return address, tx, &Admin{AdminCaller: AdminCaller{contract: contract}, AdminTransactor: AdminTransactor{contract: contract}, AdminFilterer: AdminFilterer{contract: contract}}, nil +} + +// Admin is an auto generated Go binding around an Ethereum contract. +type Admin struct { + AdminCaller // Read-only binding to the contract + AdminTransactor // Write-only binding to the contract + AdminFilterer // Log filterer for contract events +} + +// AdminCaller is an auto generated read-only Go binding around an Ethereum contract. +type AdminCaller struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// AdminTransactor is an auto generated write-only Go binding around an Ethereum contract. +type AdminTransactor struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// AdminFilterer is an auto generated log filtering Go binding around an Ethereum contract events. +type AdminFilterer struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// AdminSession is an auto generated Go binding around an Ethereum contract, +// with pre-set call and transact options. +type AdminSession struct { + Contract *Admin // Generic contract binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// AdminCallerSession is an auto generated read-only Go binding around an Ethereum contract, +// with pre-set call options. +type AdminCallerSession struct { + Contract *AdminCaller // Generic contract caller binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session +} + +// AdminTransactorSession is an auto generated write-only Go binding around an Ethereum contract, +// with pre-set transact options. +type AdminTransactorSession struct { + Contract *AdminTransactor // Generic contract transactor binding to set the session for + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// AdminRaw is an auto generated low-level Go binding around an Ethereum contract. +type AdminRaw struct { + Contract *Admin // Generic contract binding to access the raw methods on +} + +// AdminCallerRaw is an auto generated low-level read-only Go binding around an Ethereum contract. +type AdminCallerRaw struct { + Contract *AdminCaller // Generic read-only contract binding to access the raw methods on +} + +// AdminTransactorRaw is an auto generated low-level write-only Go binding around an Ethereum contract. +type AdminTransactorRaw struct { + Contract *AdminTransactor // Generic write-only contract binding to access the raw methods on +} + +// NewAdmin creates a new instance of Admin, bound to a specific deployed contract. +func NewAdmin(address common.Address, backend bind.ContractBackend) (*Admin, error) { + contract, err := bindAdmin(address, backend, backend, backend) + if err != nil { + return nil, err + } + return &Admin{AdminCaller: AdminCaller{contract: contract}, AdminTransactor: AdminTransactor{contract: contract}, AdminFilterer: AdminFilterer{contract: contract}}, nil +} + +// NewAdminCaller creates a new read-only instance of Admin, bound to a specific deployed contract. +func NewAdminCaller(address common.Address, caller bind.ContractCaller) (*AdminCaller, error) { + contract, err := bindAdmin(address, caller, nil, nil) + if err != nil { + return nil, err + } + return &AdminCaller{contract: contract}, nil +} + +// NewAdminTransactor creates a new write-only instance of Admin, bound to a specific deployed contract. +func NewAdminTransactor(address common.Address, transactor bind.ContractTransactor) (*AdminTransactor, error) { + contract, err := bindAdmin(address, nil, transactor, nil) + if err != nil { + return nil, err + } + return &AdminTransactor{contract: contract}, nil +} + +// NewAdminFilterer creates a new log filterer instance of Admin, bound to a specific deployed contract. +func NewAdminFilterer(address common.Address, filterer bind.ContractFilterer) (*AdminFilterer, error) { + contract, err := bindAdmin(address, nil, nil, filterer) + if err != nil { + return nil, err + } + return &AdminFilterer{contract: contract}, nil +} + +// bindAdmin binds a generic wrapper to an already deployed contract. +func bindAdmin(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) { + parsed, err := AdminMetaData.GetAbi() + if err != nil { + return nil, err + } + return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil +} + +// Call invokes the (constant) contract method with params as input values and +// sets the output to result. The result type might be a single field for simple +// returns, a slice of interfaces for anonymous returns and a struct for named +// returns. +func (_Admin *AdminRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _Admin.Contract.AdminCaller.contract.Call(opts, result, method, params...) +} + +// Transfer initiates a plain transaction to move funds to the contract, calling +// its default method if one is available. +func (_Admin *AdminRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _Admin.Contract.AdminTransactor.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_Admin *AdminRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _Admin.Contract.AdminTransactor.contract.Transact(opts, method, params...) +} + +// Call invokes the (constant) contract method with params as input values and +// sets the output to result. The result type might be a single field for simple +// returns, a slice of interfaces for anonymous returns and a struct for named +// returns. +func (_Admin *AdminCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _Admin.Contract.contract.Call(opts, result, method, params...) +} + +// Transfer initiates a plain transaction to move funds to the contract, calling +// its default method if one is available. +func (_Admin *AdminTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _Admin.Contract.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_Admin *AdminTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _Admin.Contract.contract.Transact(opts, method, params...) +} + +// DEFAULTADMINROLE is a free data retrieval call binding the contract method 0xa217fddf. +// +// Solidity: function DEFAULT_ADMIN_ROLE() view returns(bytes32) +func (_Admin *AdminCaller) DEFAULTADMINROLE(opts *bind.CallOpts) ([32]byte, error) { + var out []interface{} + err := _Admin.contract.Call(opts, &out, "DEFAULT_ADMIN_ROLE") + + if err != nil { + return *new([32]byte), err + } + + out0 := *abi.ConvertType(out[0], new([32]byte)).(*[32]byte) + + return out0, err + +} + +// DEFAULTADMINROLE is a free data retrieval call binding the contract method 0xa217fddf. +// +// Solidity: function DEFAULT_ADMIN_ROLE() view returns(bytes32) +func (_Admin *AdminSession) DEFAULTADMINROLE() ([32]byte, error) { + return _Admin.Contract.DEFAULTADMINROLE(&_Admin.CallOpts) +} + +// DEFAULTADMINROLE is a free data retrieval call binding the contract method 0xa217fddf. +// +// Solidity: function DEFAULT_ADMIN_ROLE() view returns(bytes32) +func (_Admin *AdminCallerSession) DEFAULTADMINROLE() ([32]byte, error) { + return _Admin.Contract.DEFAULTADMINROLE(&_Admin.CallOpts) +} + +// FEEBPS is a free data retrieval call binding the contract method 0xbf333f2c. +// +// Solidity: function FEE_BPS() view returns(uint256) +func (_Admin *AdminCaller) FEEBPS(opts *bind.CallOpts) (*big.Int, error) { + var out []interface{} + err := _Admin.contract.Call(opts, &out, "FEE_BPS") + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// FEEBPS is a free data retrieval call binding the contract method 0xbf333f2c. +// +// Solidity: function FEE_BPS() view returns(uint256) +func (_Admin *AdminSession) FEEBPS() (*big.Int, error) { + return _Admin.Contract.FEEBPS(&_Admin.CallOpts) +} + +// FEEBPS is a free data retrieval call binding the contract method 0xbf333f2c. +// +// Solidity: function FEE_BPS() view returns(uint256) +func (_Admin *AdminCallerSession) FEEBPS() (*big.Int, error) { + return _Admin.Contract.FEEBPS(&_Admin.CallOpts) +} + +// FEERATEMAX is a free data retrieval call binding the contract method 0x0f5f6ed7. +// +// Solidity: function FEE_RATE_MAX() view returns(uint256) +func (_Admin *AdminCaller) FEERATEMAX(opts *bind.CallOpts) (*big.Int, error) { + var out []interface{} + err := _Admin.contract.Call(opts, &out, "FEE_RATE_MAX") + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// FEERATEMAX is a free data retrieval call binding the contract method 0x0f5f6ed7. +// +// Solidity: function FEE_RATE_MAX() view returns(uint256) +func (_Admin *AdminSession) FEERATEMAX() (*big.Int, error) { + return _Admin.Contract.FEERATEMAX(&_Admin.CallOpts) +} + +// FEERATEMAX is a free data retrieval call binding the contract method 0x0f5f6ed7. +// +// Solidity: function FEE_RATE_MAX() view returns(uint256) +func (_Admin *AdminCallerSession) FEERATEMAX() (*big.Int, error) { + return _Admin.Contract.FEERATEMAX(&_Admin.CallOpts) +} + +// GOVERNORROLE is a free data retrieval call binding the contract method 0xccc57490. +// +// Solidity: function GOVERNOR_ROLE() view returns(bytes32) +func (_Admin *AdminCaller) GOVERNORROLE(opts *bind.CallOpts) ([32]byte, error) { + var out []interface{} + err := _Admin.contract.Call(opts, &out, "GOVERNOR_ROLE") + + if err != nil { + return *new([32]byte), err + } + + out0 := *abi.ConvertType(out[0], new([32]byte)).(*[32]byte) + + return out0, err + +} + +// GOVERNORROLE is a free data retrieval call binding the contract method 0xccc57490. +// +// Solidity: function GOVERNOR_ROLE() view returns(bytes32) +func (_Admin *AdminSession) GOVERNORROLE() ([32]byte, error) { + return _Admin.Contract.GOVERNORROLE(&_Admin.CallOpts) +} + +// GOVERNORROLE is a free data retrieval call binding the contract method 0xccc57490. +// +// Solidity: function GOVERNOR_ROLE() view returns(bytes32) +func (_Admin *AdminCallerSession) GOVERNORROLE() ([32]byte, error) { + return _Admin.Contract.GOVERNORROLE(&_Admin.CallOpts) +} + +// GUARDROLE is a free data retrieval call binding the contract method 0x03ed0ee5. +// +// Solidity: function GUARD_ROLE() view returns(bytes32) +func (_Admin *AdminCaller) GUARDROLE(opts *bind.CallOpts) ([32]byte, error) { + var out []interface{} + err := _Admin.contract.Call(opts, &out, "GUARD_ROLE") + + if err != nil { + return *new([32]byte), err + } + + out0 := *abi.ConvertType(out[0], new([32]byte)).(*[32]byte) + + return out0, err + +} + +// GUARDROLE is a free data retrieval call binding the contract method 0x03ed0ee5. +// +// Solidity: function GUARD_ROLE() view returns(bytes32) +func (_Admin *AdminSession) GUARDROLE() ([32]byte, error) { + return _Admin.Contract.GUARDROLE(&_Admin.CallOpts) +} + +// GUARDROLE is a free data retrieval call binding the contract method 0x03ed0ee5. +// +// Solidity: function GUARD_ROLE() view returns(bytes32) +func (_Admin *AdminCallerSession) GUARDROLE() ([32]byte, error) { + return _Admin.Contract.GUARDROLE(&_Admin.CallOpts) +} + +// REFUNDERROLE is a free data retrieval call binding the contract method 0x5960ccf2. +// +// Solidity: function REFUNDER_ROLE() view returns(bytes32) +func (_Admin *AdminCaller) REFUNDERROLE(opts *bind.CallOpts) ([32]byte, error) { + var out []interface{} + err := _Admin.contract.Call(opts, &out, "REFUNDER_ROLE") + + if err != nil { + return *new([32]byte), err + } + + out0 := *abi.ConvertType(out[0], new([32]byte)).(*[32]byte) + + return out0, err + +} + +// REFUNDERROLE is a free data retrieval call binding the contract method 0x5960ccf2. +// +// Solidity: function REFUNDER_ROLE() view returns(bytes32) +func (_Admin *AdminSession) REFUNDERROLE() ([32]byte, error) { + return _Admin.Contract.REFUNDERROLE(&_Admin.CallOpts) +} + +// REFUNDERROLE is a free data retrieval call binding the contract method 0x5960ccf2. +// +// Solidity: function REFUNDER_ROLE() view returns(bytes32) +func (_Admin *AdminCallerSession) REFUNDERROLE() ([32]byte, error) { + return _Admin.Contract.REFUNDERROLE(&_Admin.CallOpts) +} + +// RELAYERROLE is a free data retrieval call binding the contract method 0x926d7d7f. +// +// Solidity: function RELAYER_ROLE() view returns(bytes32) +func (_Admin *AdminCaller) RELAYERROLE(opts *bind.CallOpts) ([32]byte, error) { + var out []interface{} + err := _Admin.contract.Call(opts, &out, "RELAYER_ROLE") + + if err != nil { + return *new([32]byte), err + } + + out0 := *abi.ConvertType(out[0], new([32]byte)).(*[32]byte) + + return out0, err + +} + +// RELAYERROLE is a free data retrieval call binding the contract method 0x926d7d7f. +// +// Solidity: function RELAYER_ROLE() view returns(bytes32) +func (_Admin *AdminSession) RELAYERROLE() ([32]byte, error) { + return _Admin.Contract.RELAYERROLE(&_Admin.CallOpts) +} + +// RELAYERROLE is a free data retrieval call binding the contract method 0x926d7d7f. +// +// Solidity: function RELAYER_ROLE() view returns(bytes32) +func (_Admin *AdminCallerSession) RELAYERROLE() ([32]byte, error) { + return _Admin.Contract.RELAYERROLE(&_Admin.CallOpts) +} + +// ChainGasAmount is a free data retrieval call binding the contract method 0xe00a83e0. +// +// Solidity: function chainGasAmount() view returns(uint256) +func (_Admin *AdminCaller) ChainGasAmount(opts *bind.CallOpts) (*big.Int, error) { + var out []interface{} + err := _Admin.contract.Call(opts, &out, "chainGasAmount") + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// ChainGasAmount is a free data retrieval call binding the contract method 0xe00a83e0. +// +// Solidity: function chainGasAmount() view returns(uint256) +func (_Admin *AdminSession) ChainGasAmount() (*big.Int, error) { + return _Admin.Contract.ChainGasAmount(&_Admin.CallOpts) +} + +// ChainGasAmount is a free data retrieval call binding the contract method 0xe00a83e0. +// +// Solidity: function chainGasAmount() view returns(uint256) +func (_Admin *AdminCallerSession) ChainGasAmount() (*big.Int, error) { + return _Admin.Contract.ChainGasAmount(&_Admin.CallOpts) +} + +// GetRoleAdmin is a free data retrieval call binding the contract method 0x248a9ca3. +// +// Solidity: function getRoleAdmin(bytes32 role) view returns(bytes32) +func (_Admin *AdminCaller) GetRoleAdmin(opts *bind.CallOpts, role [32]byte) ([32]byte, error) { + var out []interface{} + err := _Admin.contract.Call(opts, &out, "getRoleAdmin", role) + + if err != nil { + return *new([32]byte), err + } + + out0 := *abi.ConvertType(out[0], new([32]byte)).(*[32]byte) + + return out0, err + +} + +// GetRoleAdmin is a free data retrieval call binding the contract method 0x248a9ca3. +// +// Solidity: function getRoleAdmin(bytes32 role) view returns(bytes32) +func (_Admin *AdminSession) GetRoleAdmin(role [32]byte) ([32]byte, error) { + return _Admin.Contract.GetRoleAdmin(&_Admin.CallOpts, role) +} + +// GetRoleAdmin is a free data retrieval call binding the contract method 0x248a9ca3. +// +// Solidity: function getRoleAdmin(bytes32 role) view returns(bytes32) +func (_Admin *AdminCallerSession) GetRoleAdmin(role [32]byte) ([32]byte, error) { + return _Admin.Contract.GetRoleAdmin(&_Admin.CallOpts, role) +} + +// GetRoleMember is a free data retrieval call binding the contract method 0x9010d07c. +// +// Solidity: function getRoleMember(bytes32 role, uint256 index) view returns(address) +func (_Admin *AdminCaller) GetRoleMember(opts *bind.CallOpts, role [32]byte, index *big.Int) (common.Address, error) { + var out []interface{} + err := _Admin.contract.Call(opts, &out, "getRoleMember", role, index) + + if err != nil { + return *new(common.Address), err + } + + out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) + + return out0, err + +} + +// GetRoleMember is a free data retrieval call binding the contract method 0x9010d07c. +// +// Solidity: function getRoleMember(bytes32 role, uint256 index) view returns(address) +func (_Admin *AdminSession) GetRoleMember(role [32]byte, index *big.Int) (common.Address, error) { + return _Admin.Contract.GetRoleMember(&_Admin.CallOpts, role, index) +} + +// GetRoleMember is a free data retrieval call binding the contract method 0x9010d07c. +// +// Solidity: function getRoleMember(bytes32 role, uint256 index) view returns(address) +func (_Admin *AdminCallerSession) GetRoleMember(role [32]byte, index *big.Int) (common.Address, error) { + return _Admin.Contract.GetRoleMember(&_Admin.CallOpts, role, index) +} + +// GetRoleMemberCount is a free data retrieval call binding the contract method 0xca15c873. +// +// Solidity: function getRoleMemberCount(bytes32 role) view returns(uint256) +func (_Admin *AdminCaller) GetRoleMemberCount(opts *bind.CallOpts, role [32]byte) (*big.Int, error) { + var out []interface{} + err := _Admin.contract.Call(opts, &out, "getRoleMemberCount", role) + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// GetRoleMemberCount is a free data retrieval call binding the contract method 0xca15c873. +// +// Solidity: function getRoleMemberCount(bytes32 role) view returns(uint256) +func (_Admin *AdminSession) GetRoleMemberCount(role [32]byte) (*big.Int, error) { + return _Admin.Contract.GetRoleMemberCount(&_Admin.CallOpts, role) +} + +// GetRoleMemberCount is a free data retrieval call binding the contract method 0xca15c873. +// +// Solidity: function getRoleMemberCount(bytes32 role) view returns(uint256) +func (_Admin *AdminCallerSession) GetRoleMemberCount(role [32]byte) (*big.Int, error) { + return _Admin.Contract.GetRoleMemberCount(&_Admin.CallOpts, role) +} + +// HasRole is a free data retrieval call binding the contract method 0x91d14854. +// +// Solidity: function hasRole(bytes32 role, address account) view returns(bool) +func (_Admin *AdminCaller) HasRole(opts *bind.CallOpts, role [32]byte, account common.Address) (bool, error) { + var out []interface{} + err := _Admin.contract.Call(opts, &out, "hasRole", role, account) + + if err != nil { + return *new(bool), err + } + + out0 := *abi.ConvertType(out[0], new(bool)).(*bool) + + return out0, err + +} + +// HasRole is a free data retrieval call binding the contract method 0x91d14854. +// +// Solidity: function hasRole(bytes32 role, address account) view returns(bool) +func (_Admin *AdminSession) HasRole(role [32]byte, account common.Address) (bool, error) { + return _Admin.Contract.HasRole(&_Admin.CallOpts, role, account) +} + +// HasRole is a free data retrieval call binding the contract method 0x91d14854. +// +// Solidity: function hasRole(bytes32 role, address account) view returns(bool) +func (_Admin *AdminCallerSession) HasRole(role [32]byte, account common.Address) (bool, error) { + return _Admin.Contract.HasRole(&_Admin.CallOpts, role, account) +} + +// ProtocolFeeRate is a free data retrieval call binding the contract method 0x58f85880. +// +// Solidity: function protocolFeeRate() view returns(uint256) +func (_Admin *AdminCaller) ProtocolFeeRate(opts *bind.CallOpts) (*big.Int, error) { + var out []interface{} + err := _Admin.contract.Call(opts, &out, "protocolFeeRate") + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// ProtocolFeeRate is a free data retrieval call binding the contract method 0x58f85880. +// +// Solidity: function protocolFeeRate() view returns(uint256) +func (_Admin *AdminSession) ProtocolFeeRate() (*big.Int, error) { + return _Admin.Contract.ProtocolFeeRate(&_Admin.CallOpts) +} + +// ProtocolFeeRate is a free data retrieval call binding the contract method 0x58f85880. +// +// Solidity: function protocolFeeRate() view returns(uint256) +func (_Admin *AdminCallerSession) ProtocolFeeRate() (*big.Int, error) { + return _Admin.Contract.ProtocolFeeRate(&_Admin.CallOpts) +} + +// ProtocolFees is a free data retrieval call binding the contract method 0xdcf844a7. +// +// Solidity: function protocolFees(address ) view returns(uint256) +func (_Admin *AdminCaller) ProtocolFees(opts *bind.CallOpts, arg0 common.Address) (*big.Int, error) { + var out []interface{} + err := _Admin.contract.Call(opts, &out, "protocolFees", arg0) + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// ProtocolFees is a free data retrieval call binding the contract method 0xdcf844a7. +// +// Solidity: function protocolFees(address ) view returns(uint256) +func (_Admin *AdminSession) ProtocolFees(arg0 common.Address) (*big.Int, error) { + return _Admin.Contract.ProtocolFees(&_Admin.CallOpts, arg0) +} + +// ProtocolFees is a free data retrieval call binding the contract method 0xdcf844a7. +// +// Solidity: function protocolFees(address ) view returns(uint256) +func (_Admin *AdminCallerSession) ProtocolFees(arg0 common.Address) (*big.Int, error) { + return _Admin.Contract.ProtocolFees(&_Admin.CallOpts, arg0) +} + +// SupportsInterface is a free data retrieval call binding the contract method 0x01ffc9a7. +// +// Solidity: function supportsInterface(bytes4 interfaceId) view returns(bool) +func (_Admin *AdminCaller) SupportsInterface(opts *bind.CallOpts, interfaceId [4]byte) (bool, error) { + var out []interface{} + err := _Admin.contract.Call(opts, &out, "supportsInterface", interfaceId) + + if err != nil { + return *new(bool), err + } + + out0 := *abi.ConvertType(out[0], new(bool)).(*bool) + + return out0, err + +} + +// SupportsInterface is a free data retrieval call binding the contract method 0x01ffc9a7. +// +// Solidity: function supportsInterface(bytes4 interfaceId) view returns(bool) +func (_Admin *AdminSession) SupportsInterface(interfaceId [4]byte) (bool, error) { + return _Admin.Contract.SupportsInterface(&_Admin.CallOpts, interfaceId) +} + +// SupportsInterface is a free data retrieval call binding the contract method 0x01ffc9a7. +// +// Solidity: function supportsInterface(bytes4 interfaceId) view returns(bool) +func (_Admin *AdminCallerSession) SupportsInterface(interfaceId [4]byte) (bool, error) { + return _Admin.Contract.SupportsInterface(&_Admin.CallOpts, interfaceId) +} + +// GrantRole is a paid mutator transaction binding the contract method 0x2f2ff15d. +// +// Solidity: function grantRole(bytes32 role, address account) returns() +func (_Admin *AdminTransactor) GrantRole(opts *bind.TransactOpts, role [32]byte, account common.Address) (*types.Transaction, error) { + return _Admin.contract.Transact(opts, "grantRole", role, account) +} + +// GrantRole is a paid mutator transaction binding the contract method 0x2f2ff15d. +// +// Solidity: function grantRole(bytes32 role, address account) returns() +func (_Admin *AdminSession) GrantRole(role [32]byte, account common.Address) (*types.Transaction, error) { + return _Admin.Contract.GrantRole(&_Admin.TransactOpts, role, account) +} + +// GrantRole is a paid mutator transaction binding the contract method 0x2f2ff15d. +// +// Solidity: function grantRole(bytes32 role, address account) returns() +func (_Admin *AdminTransactorSession) GrantRole(role [32]byte, account common.Address) (*types.Transaction, error) { + return _Admin.Contract.GrantRole(&_Admin.TransactOpts, role, account) +} + +// RenounceRole is a paid mutator transaction binding the contract method 0x36568abe. +// +// Solidity: function renounceRole(bytes32 role, address callerConfirmation) returns() +func (_Admin *AdminTransactor) RenounceRole(opts *bind.TransactOpts, role [32]byte, callerConfirmation common.Address) (*types.Transaction, error) { + return _Admin.contract.Transact(opts, "renounceRole", role, callerConfirmation) +} + +// RenounceRole is a paid mutator transaction binding the contract method 0x36568abe. +// +// Solidity: function renounceRole(bytes32 role, address callerConfirmation) returns() +func (_Admin *AdminSession) RenounceRole(role [32]byte, callerConfirmation common.Address) (*types.Transaction, error) { + return _Admin.Contract.RenounceRole(&_Admin.TransactOpts, role, callerConfirmation) +} + +// RenounceRole is a paid mutator transaction binding the contract method 0x36568abe. +// +// Solidity: function renounceRole(bytes32 role, address callerConfirmation) returns() +func (_Admin *AdminTransactorSession) RenounceRole(role [32]byte, callerConfirmation common.Address) (*types.Transaction, error) { + return _Admin.Contract.RenounceRole(&_Admin.TransactOpts, role, callerConfirmation) +} + +// RevokeRole is a paid mutator transaction binding the contract method 0xd547741f. +// +// Solidity: function revokeRole(bytes32 role, address account) returns() +func (_Admin *AdminTransactor) RevokeRole(opts *bind.TransactOpts, role [32]byte, account common.Address) (*types.Transaction, error) { + return _Admin.contract.Transact(opts, "revokeRole", role, account) +} + +// RevokeRole is a paid mutator transaction binding the contract method 0xd547741f. +// +// Solidity: function revokeRole(bytes32 role, address account) returns() +func (_Admin *AdminSession) RevokeRole(role [32]byte, account common.Address) (*types.Transaction, error) { + return _Admin.Contract.RevokeRole(&_Admin.TransactOpts, role, account) +} + +// RevokeRole is a paid mutator transaction binding the contract method 0xd547741f. +// +// Solidity: function revokeRole(bytes32 role, address account) returns() +func (_Admin *AdminTransactorSession) RevokeRole(role [32]byte, account common.Address) (*types.Transaction, error) { + return _Admin.Contract.RevokeRole(&_Admin.TransactOpts, role, account) +} + +// SetChainGasAmount is a paid mutator transaction binding the contract method 0xb250fe6b. +// +// Solidity: function setChainGasAmount(uint256 newChainGasAmount) returns() +func (_Admin *AdminTransactor) SetChainGasAmount(opts *bind.TransactOpts, newChainGasAmount *big.Int) (*types.Transaction, error) { + return _Admin.contract.Transact(opts, "setChainGasAmount", newChainGasAmount) +} + +// SetChainGasAmount is a paid mutator transaction binding the contract method 0xb250fe6b. +// +// Solidity: function setChainGasAmount(uint256 newChainGasAmount) returns() +func (_Admin *AdminSession) SetChainGasAmount(newChainGasAmount *big.Int) (*types.Transaction, error) { + return _Admin.Contract.SetChainGasAmount(&_Admin.TransactOpts, newChainGasAmount) +} + +// SetChainGasAmount is a paid mutator transaction binding the contract method 0xb250fe6b. +// +// Solidity: function setChainGasAmount(uint256 newChainGasAmount) returns() +func (_Admin *AdminTransactorSession) SetChainGasAmount(newChainGasAmount *big.Int) (*types.Transaction, error) { + return _Admin.Contract.SetChainGasAmount(&_Admin.TransactOpts, newChainGasAmount) +} + +// SetProtocolFeeRate is a paid mutator transaction binding the contract method 0xb13aa2d6. +// +// Solidity: function setProtocolFeeRate(uint256 newFeeRate) returns() +func (_Admin *AdminTransactor) SetProtocolFeeRate(opts *bind.TransactOpts, newFeeRate *big.Int) (*types.Transaction, error) { + return _Admin.contract.Transact(opts, "setProtocolFeeRate", newFeeRate) +} + +// SetProtocolFeeRate is a paid mutator transaction binding the contract method 0xb13aa2d6. +// +// Solidity: function setProtocolFeeRate(uint256 newFeeRate) returns() +func (_Admin *AdminSession) SetProtocolFeeRate(newFeeRate *big.Int) (*types.Transaction, error) { + return _Admin.Contract.SetProtocolFeeRate(&_Admin.TransactOpts, newFeeRate) +} + +// SetProtocolFeeRate is a paid mutator transaction binding the contract method 0xb13aa2d6. +// +// Solidity: function setProtocolFeeRate(uint256 newFeeRate) returns() +func (_Admin *AdminTransactorSession) SetProtocolFeeRate(newFeeRate *big.Int) (*types.Transaction, error) { + return _Admin.Contract.SetProtocolFeeRate(&_Admin.TransactOpts, newFeeRate) +} + +// SweepProtocolFees is a paid mutator transaction binding the contract method 0x06f333f2. +// +// Solidity: function sweepProtocolFees(address token, address recipient) returns() +func (_Admin *AdminTransactor) SweepProtocolFees(opts *bind.TransactOpts, token common.Address, recipient common.Address) (*types.Transaction, error) { + return _Admin.contract.Transact(opts, "sweepProtocolFees", token, recipient) +} + +// SweepProtocolFees is a paid mutator transaction binding the contract method 0x06f333f2. +// +// Solidity: function sweepProtocolFees(address token, address recipient) returns() +func (_Admin *AdminSession) SweepProtocolFees(token common.Address, recipient common.Address) (*types.Transaction, error) { + return _Admin.Contract.SweepProtocolFees(&_Admin.TransactOpts, token, recipient) +} + +// SweepProtocolFees is a paid mutator transaction binding the contract method 0x06f333f2. +// +// Solidity: function sweepProtocolFees(address token, address recipient) returns() +func (_Admin *AdminTransactorSession) SweepProtocolFees(token common.Address, recipient common.Address) (*types.Transaction, error) { + return _Admin.Contract.SweepProtocolFees(&_Admin.TransactOpts, token, recipient) +} + +// AdminChainGasAmountUpdatedIterator is returned from FilterChainGasAmountUpdated and is used to iterate over the raw logs and unpacked data for ChainGasAmountUpdated events raised by the Admin contract. +type AdminChainGasAmountUpdatedIterator struct { + Event *AdminChainGasAmountUpdated // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *AdminChainGasAmountUpdatedIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(AdminChainGasAmountUpdated) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(AdminChainGasAmountUpdated) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *AdminChainGasAmountUpdatedIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *AdminChainGasAmountUpdatedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// AdminChainGasAmountUpdated represents a ChainGasAmountUpdated event raised by the Admin contract. +type AdminChainGasAmountUpdated struct { + OldChainGasAmount *big.Int + NewChainGasAmount *big.Int + Raw types.Log // Blockchain specific contextual infos +} + +// FilterChainGasAmountUpdated is a free log retrieval operation binding the contract event 0x5cf09b12f3f56b4c564d51b25b40360af6d795198adb61ae0806a36c294323fa. +// +// Solidity: event ChainGasAmountUpdated(uint256 oldChainGasAmount, uint256 newChainGasAmount) +func (_Admin *AdminFilterer) FilterChainGasAmountUpdated(opts *bind.FilterOpts) (*AdminChainGasAmountUpdatedIterator, error) { + + logs, sub, err := _Admin.contract.FilterLogs(opts, "ChainGasAmountUpdated") + if err != nil { + return nil, err + } + return &AdminChainGasAmountUpdatedIterator{contract: _Admin.contract, event: "ChainGasAmountUpdated", logs: logs, sub: sub}, nil +} + +// WatchChainGasAmountUpdated is a free log subscription operation binding the contract event 0x5cf09b12f3f56b4c564d51b25b40360af6d795198adb61ae0806a36c294323fa. +// +// Solidity: event ChainGasAmountUpdated(uint256 oldChainGasAmount, uint256 newChainGasAmount) +func (_Admin *AdminFilterer) WatchChainGasAmountUpdated(opts *bind.WatchOpts, sink chan<- *AdminChainGasAmountUpdated) (event.Subscription, error) { + + logs, sub, err := _Admin.contract.WatchLogs(opts, "ChainGasAmountUpdated") + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(AdminChainGasAmountUpdated) + if err := _Admin.contract.UnpackLog(event, "ChainGasAmountUpdated", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseChainGasAmountUpdated is a log parse operation binding the contract event 0x5cf09b12f3f56b4c564d51b25b40360af6d795198adb61ae0806a36c294323fa. +// +// Solidity: event ChainGasAmountUpdated(uint256 oldChainGasAmount, uint256 newChainGasAmount) +func (_Admin *AdminFilterer) ParseChainGasAmountUpdated(log types.Log) (*AdminChainGasAmountUpdated, error) { + event := new(AdminChainGasAmountUpdated) + if err := _Admin.contract.UnpackLog(event, "ChainGasAmountUpdated", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// AdminFeeRateUpdatedIterator is returned from FilterFeeRateUpdated and is used to iterate over the raw logs and unpacked data for FeeRateUpdated events raised by the Admin contract. +type AdminFeeRateUpdatedIterator struct { + Event *AdminFeeRateUpdated // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *AdminFeeRateUpdatedIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(AdminFeeRateUpdated) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(AdminFeeRateUpdated) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *AdminFeeRateUpdatedIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *AdminFeeRateUpdatedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// AdminFeeRateUpdated represents a FeeRateUpdated event raised by the Admin contract. +type AdminFeeRateUpdated struct { + OldFeeRate *big.Int + NewFeeRate *big.Int + Raw types.Log // Blockchain specific contextual infos +} + +// FilterFeeRateUpdated is a free log retrieval operation binding the contract event 0x14914da2bf76024616fbe1859783fcd4dbddcb179b1f3a854949fbf920dcb957. +// +// Solidity: event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate) +func (_Admin *AdminFilterer) FilterFeeRateUpdated(opts *bind.FilterOpts) (*AdminFeeRateUpdatedIterator, error) { + + logs, sub, err := _Admin.contract.FilterLogs(opts, "FeeRateUpdated") + if err != nil { + return nil, err + } + return &AdminFeeRateUpdatedIterator{contract: _Admin.contract, event: "FeeRateUpdated", logs: logs, sub: sub}, nil +} + +// WatchFeeRateUpdated is a free log subscription operation binding the contract event 0x14914da2bf76024616fbe1859783fcd4dbddcb179b1f3a854949fbf920dcb957. +// +// Solidity: event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate) +func (_Admin *AdminFilterer) WatchFeeRateUpdated(opts *bind.WatchOpts, sink chan<- *AdminFeeRateUpdated) (event.Subscription, error) { + + logs, sub, err := _Admin.contract.WatchLogs(opts, "FeeRateUpdated") + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(AdminFeeRateUpdated) + if err := _Admin.contract.UnpackLog(event, "FeeRateUpdated", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseFeeRateUpdated is a log parse operation binding the contract event 0x14914da2bf76024616fbe1859783fcd4dbddcb179b1f3a854949fbf920dcb957. +// +// Solidity: event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate) +func (_Admin *AdminFilterer) ParseFeeRateUpdated(log types.Log) (*AdminFeeRateUpdated, error) { + event := new(AdminFeeRateUpdated) + if err := _Admin.contract.UnpackLog(event, "FeeRateUpdated", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// AdminFeesSweptIterator is returned from FilterFeesSwept and is used to iterate over the raw logs and unpacked data for FeesSwept events raised by the Admin contract. +type AdminFeesSweptIterator struct { + Event *AdminFeesSwept // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *AdminFeesSweptIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(AdminFeesSwept) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(AdminFeesSwept) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *AdminFeesSweptIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *AdminFeesSweptIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// AdminFeesSwept represents a FeesSwept event raised by the Admin contract. +type AdminFeesSwept struct { + Token common.Address + Recipient common.Address + Amount *big.Int + Raw types.Log // Blockchain specific contextual infos +} + +// FilterFeesSwept is a free log retrieval operation binding the contract event 0x244e51bc38c1452fa8aaf487bcb4bca36c2baa3a5fbdb776b1eabd8dc6d277cd. +// +// Solidity: event FeesSwept(address token, address recipient, uint256 amount) +func (_Admin *AdminFilterer) FilterFeesSwept(opts *bind.FilterOpts) (*AdminFeesSweptIterator, error) { + + logs, sub, err := _Admin.contract.FilterLogs(opts, "FeesSwept") + if err != nil { + return nil, err + } + return &AdminFeesSweptIterator{contract: _Admin.contract, event: "FeesSwept", logs: logs, sub: sub}, nil +} + +// WatchFeesSwept is a free log subscription operation binding the contract event 0x244e51bc38c1452fa8aaf487bcb4bca36c2baa3a5fbdb776b1eabd8dc6d277cd. +// +// Solidity: event FeesSwept(address token, address recipient, uint256 amount) +func (_Admin *AdminFilterer) WatchFeesSwept(opts *bind.WatchOpts, sink chan<- *AdminFeesSwept) (event.Subscription, error) { + + logs, sub, err := _Admin.contract.WatchLogs(opts, "FeesSwept") + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(AdminFeesSwept) + if err := _Admin.contract.UnpackLog(event, "FeesSwept", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseFeesSwept is a log parse operation binding the contract event 0x244e51bc38c1452fa8aaf487bcb4bca36c2baa3a5fbdb776b1eabd8dc6d277cd. +// +// Solidity: event FeesSwept(address token, address recipient, uint256 amount) +func (_Admin *AdminFilterer) ParseFeesSwept(log types.Log) (*AdminFeesSwept, error) { + event := new(AdminFeesSwept) + if err := _Admin.contract.UnpackLog(event, "FeesSwept", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// AdminRoleAdminChangedIterator is returned from FilterRoleAdminChanged and is used to iterate over the raw logs and unpacked data for RoleAdminChanged events raised by the Admin contract. +type AdminRoleAdminChangedIterator struct { + Event *AdminRoleAdminChanged // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *AdminRoleAdminChangedIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(AdminRoleAdminChanged) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(AdminRoleAdminChanged) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *AdminRoleAdminChangedIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *AdminRoleAdminChangedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// AdminRoleAdminChanged represents a RoleAdminChanged event raised by the Admin contract. +type AdminRoleAdminChanged struct { + Role [32]byte + PreviousAdminRole [32]byte + NewAdminRole [32]byte + Raw types.Log // Blockchain specific contextual infos +} + +// FilterRoleAdminChanged is a free log retrieval operation binding the contract event 0xbd79b86ffe0ab8e8776151514217cd7cacd52c909f66475c3af44e129f0b00ff. +// +// Solidity: event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole) +func (_Admin *AdminFilterer) FilterRoleAdminChanged(opts *bind.FilterOpts, role [][32]byte, previousAdminRole [][32]byte, newAdminRole [][32]byte) (*AdminRoleAdminChangedIterator, error) { + + var roleRule []interface{} + for _, roleItem := range role { + roleRule = append(roleRule, roleItem) + } + var previousAdminRoleRule []interface{} + for _, previousAdminRoleItem := range previousAdminRole { + previousAdminRoleRule = append(previousAdminRoleRule, previousAdminRoleItem) + } + var newAdminRoleRule []interface{} + for _, newAdminRoleItem := range newAdminRole { + newAdminRoleRule = append(newAdminRoleRule, newAdminRoleItem) + } + + logs, sub, err := _Admin.contract.FilterLogs(opts, "RoleAdminChanged", roleRule, previousAdminRoleRule, newAdminRoleRule) + if err != nil { + return nil, err + } + return &AdminRoleAdminChangedIterator{contract: _Admin.contract, event: "RoleAdminChanged", logs: logs, sub: sub}, nil +} + +// WatchRoleAdminChanged is a free log subscription operation binding the contract event 0xbd79b86ffe0ab8e8776151514217cd7cacd52c909f66475c3af44e129f0b00ff. +// +// Solidity: event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole) +func (_Admin *AdminFilterer) WatchRoleAdminChanged(opts *bind.WatchOpts, sink chan<- *AdminRoleAdminChanged, role [][32]byte, previousAdminRole [][32]byte, newAdminRole [][32]byte) (event.Subscription, error) { + + var roleRule []interface{} + for _, roleItem := range role { + roleRule = append(roleRule, roleItem) + } + var previousAdminRoleRule []interface{} + for _, previousAdminRoleItem := range previousAdminRole { + previousAdminRoleRule = append(previousAdminRoleRule, previousAdminRoleItem) + } + var newAdminRoleRule []interface{} + for _, newAdminRoleItem := range newAdminRole { + newAdminRoleRule = append(newAdminRoleRule, newAdminRoleItem) + } + + logs, sub, err := _Admin.contract.WatchLogs(opts, "RoleAdminChanged", roleRule, previousAdminRoleRule, newAdminRoleRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(AdminRoleAdminChanged) + if err := _Admin.contract.UnpackLog(event, "RoleAdminChanged", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseRoleAdminChanged is a log parse operation binding the contract event 0xbd79b86ffe0ab8e8776151514217cd7cacd52c909f66475c3af44e129f0b00ff. +// +// Solidity: event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole) +func (_Admin *AdminFilterer) ParseRoleAdminChanged(log types.Log) (*AdminRoleAdminChanged, error) { + event := new(AdminRoleAdminChanged) + if err := _Admin.contract.UnpackLog(event, "RoleAdminChanged", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// AdminRoleGrantedIterator is returned from FilterRoleGranted and is used to iterate over the raw logs and unpacked data for RoleGranted events raised by the Admin contract. +type AdminRoleGrantedIterator struct { + Event *AdminRoleGranted // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *AdminRoleGrantedIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(AdminRoleGranted) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(AdminRoleGranted) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *AdminRoleGrantedIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *AdminRoleGrantedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// AdminRoleGranted represents a RoleGranted event raised by the Admin contract. +type AdminRoleGranted struct { + Role [32]byte + Account common.Address + Sender common.Address + Raw types.Log // Blockchain specific contextual infos +} + +// FilterRoleGranted is a free log retrieval operation binding the contract event 0x2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d. +// +// Solidity: event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender) +func (_Admin *AdminFilterer) FilterRoleGranted(opts *bind.FilterOpts, role [][32]byte, account []common.Address, sender []common.Address) (*AdminRoleGrantedIterator, error) { + + var roleRule []interface{} + for _, roleItem := range role { + roleRule = append(roleRule, roleItem) + } + var accountRule []interface{} + for _, accountItem := range account { + accountRule = append(accountRule, accountItem) + } + var senderRule []interface{} + for _, senderItem := range sender { + senderRule = append(senderRule, senderItem) + } + + logs, sub, err := _Admin.contract.FilterLogs(opts, "RoleGranted", roleRule, accountRule, senderRule) + if err != nil { + return nil, err + } + return &AdminRoleGrantedIterator{contract: _Admin.contract, event: "RoleGranted", logs: logs, sub: sub}, nil +} + +// WatchRoleGranted is a free log subscription operation binding the contract event 0x2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d. +// +// Solidity: event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender) +func (_Admin *AdminFilterer) WatchRoleGranted(opts *bind.WatchOpts, sink chan<- *AdminRoleGranted, role [][32]byte, account []common.Address, sender []common.Address) (event.Subscription, error) { + + var roleRule []interface{} + for _, roleItem := range role { + roleRule = append(roleRule, roleItem) + } + var accountRule []interface{} + for _, accountItem := range account { + accountRule = append(accountRule, accountItem) + } + var senderRule []interface{} + for _, senderItem := range sender { + senderRule = append(senderRule, senderItem) + } + + logs, sub, err := _Admin.contract.WatchLogs(opts, "RoleGranted", roleRule, accountRule, senderRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(AdminRoleGranted) + if err := _Admin.contract.UnpackLog(event, "RoleGranted", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseRoleGranted is a log parse operation binding the contract event 0x2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d. +// +// Solidity: event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender) +func (_Admin *AdminFilterer) ParseRoleGranted(log types.Log) (*AdminRoleGranted, error) { + event := new(AdminRoleGranted) + if err := _Admin.contract.UnpackLog(event, "RoleGranted", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// AdminRoleRevokedIterator is returned from FilterRoleRevoked and is used to iterate over the raw logs and unpacked data for RoleRevoked events raised by the Admin contract. +type AdminRoleRevokedIterator struct { + Event *AdminRoleRevoked // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *AdminRoleRevokedIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(AdminRoleRevoked) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(AdminRoleRevoked) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *AdminRoleRevokedIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *AdminRoleRevokedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// AdminRoleRevoked represents a RoleRevoked event raised by the Admin contract. +type AdminRoleRevoked struct { + Role [32]byte + Account common.Address + Sender common.Address + Raw types.Log // Blockchain specific contextual infos +} + +// FilterRoleRevoked is a free log retrieval operation binding the contract event 0xf6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b. +// +// Solidity: event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender) +func (_Admin *AdminFilterer) FilterRoleRevoked(opts *bind.FilterOpts, role [][32]byte, account []common.Address, sender []common.Address) (*AdminRoleRevokedIterator, error) { + + var roleRule []interface{} + for _, roleItem := range role { + roleRule = append(roleRule, roleItem) + } + var accountRule []interface{} + for _, accountItem := range account { + accountRule = append(accountRule, accountItem) + } + var senderRule []interface{} + for _, senderItem := range sender { + senderRule = append(senderRule, senderItem) + } + + logs, sub, err := _Admin.contract.FilterLogs(opts, "RoleRevoked", roleRule, accountRule, senderRule) + if err != nil { + return nil, err + } + return &AdminRoleRevokedIterator{contract: _Admin.contract, event: "RoleRevoked", logs: logs, sub: sub}, nil +} + +// WatchRoleRevoked is a free log subscription operation binding the contract event 0xf6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b. +// +// Solidity: event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender) +func (_Admin *AdminFilterer) WatchRoleRevoked(opts *bind.WatchOpts, sink chan<- *AdminRoleRevoked, role [][32]byte, account []common.Address, sender []common.Address) (event.Subscription, error) { + + var roleRule []interface{} + for _, roleItem := range role { + roleRule = append(roleRule, roleItem) + } + var accountRule []interface{} + for _, accountItem := range account { + accountRule = append(accountRule, accountItem) + } + var senderRule []interface{} + for _, senderItem := range sender { + senderRule = append(senderRule, senderItem) + } + + logs, sub, err := _Admin.contract.WatchLogs(opts, "RoleRevoked", roleRule, accountRule, senderRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(AdminRoleRevoked) + if err := _Admin.contract.UnpackLog(event, "RoleRevoked", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseRoleRevoked is a log parse operation binding the contract event 0xf6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b. +// +// Solidity: event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender) +func (_Admin *AdminFilterer) ParseRoleRevoked(log types.Log) (*AdminRoleRevoked, error) { + event := new(AdminRoleRevoked) + if err := _Admin.contract.UnpackLog(event, "RoleRevoked", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// ContextMetaData contains all meta data concerning the Context contract. +var ContextMetaData = &bind.MetaData{ + ABI: "[]", +} + +// ContextABI is the input ABI used to generate the binding from. +// Deprecated: Use ContextMetaData.ABI instead. +var ContextABI = ContextMetaData.ABI + +// Context is an auto generated Go binding around an Ethereum contract. +type Context struct { + ContextCaller // Read-only binding to the contract + ContextTransactor // Write-only binding to the contract + ContextFilterer // Log filterer for contract events +} + +// ContextCaller is an auto generated read-only Go binding around an Ethereum contract. +type ContextCaller struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// ContextTransactor is an auto generated write-only Go binding around an Ethereum contract. +type ContextTransactor struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// ContextFilterer is an auto generated log filtering Go binding around an Ethereum contract events. +type ContextFilterer struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// ContextSession is an auto generated Go binding around an Ethereum contract, +// with pre-set call and transact options. +type ContextSession struct { + Contract *Context // Generic contract binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// ContextCallerSession is an auto generated read-only Go binding around an Ethereum contract, +// with pre-set call options. +type ContextCallerSession struct { + Contract *ContextCaller // Generic contract caller binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session +} + +// ContextTransactorSession is an auto generated write-only Go binding around an Ethereum contract, +// with pre-set transact options. +type ContextTransactorSession struct { + Contract *ContextTransactor // Generic contract transactor binding to set the session for + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// ContextRaw is an auto generated low-level Go binding around an Ethereum contract. +type ContextRaw struct { + Contract *Context // Generic contract binding to access the raw methods on +} + +// ContextCallerRaw is an auto generated low-level read-only Go binding around an Ethereum contract. +type ContextCallerRaw struct { + Contract *ContextCaller // Generic read-only contract binding to access the raw methods on +} + +// ContextTransactorRaw is an auto generated low-level write-only Go binding around an Ethereum contract. +type ContextTransactorRaw struct { + Contract *ContextTransactor // Generic write-only contract binding to access the raw methods on +} + +// NewContext creates a new instance of Context, bound to a specific deployed contract. +func NewContext(address common.Address, backend bind.ContractBackend) (*Context, error) { + contract, err := bindContext(address, backend, backend, backend) + if err != nil { + return nil, err + } + return &Context{ContextCaller: ContextCaller{contract: contract}, ContextTransactor: ContextTransactor{contract: contract}, ContextFilterer: ContextFilterer{contract: contract}}, nil +} + +// NewContextCaller creates a new read-only instance of Context, bound to a specific deployed contract. +func NewContextCaller(address common.Address, caller bind.ContractCaller) (*ContextCaller, error) { + contract, err := bindContext(address, caller, nil, nil) + if err != nil { + return nil, err + } + return &ContextCaller{contract: contract}, nil +} + +// NewContextTransactor creates a new write-only instance of Context, bound to a specific deployed contract. +func NewContextTransactor(address common.Address, transactor bind.ContractTransactor) (*ContextTransactor, error) { + contract, err := bindContext(address, nil, transactor, nil) + if err != nil { + return nil, err + } + return &ContextTransactor{contract: contract}, nil +} + +// NewContextFilterer creates a new log filterer instance of Context, bound to a specific deployed contract. +func NewContextFilterer(address common.Address, filterer bind.ContractFilterer) (*ContextFilterer, error) { + contract, err := bindContext(address, nil, nil, filterer) + if err != nil { + return nil, err + } + return &ContextFilterer{contract: contract}, nil +} + +// bindContext binds a generic wrapper to an already deployed contract. +func bindContext(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) { + parsed, err := ContextMetaData.GetAbi() + if err != nil { + return nil, err + } + return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil +} + +// Call invokes the (constant) contract method with params as input values and +// sets the output to result. The result type might be a single field for simple +// returns, a slice of interfaces for anonymous returns and a struct for named +// returns. +func (_Context *ContextRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _Context.Contract.ContextCaller.contract.Call(opts, result, method, params...) +} + +// Transfer initiates a plain transaction to move funds to the contract, calling +// its default method if one is available. +func (_Context *ContextRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _Context.Contract.ContextTransactor.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_Context *ContextRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _Context.Contract.ContextTransactor.contract.Transact(opts, method, params...) +} + +// Call invokes the (constant) contract method with params as input values and +// sets the output to result. The result type might be a single field for simple +// returns, a slice of interfaces for anonymous returns and a struct for named +// returns. +func (_Context *ContextCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _Context.Contract.contract.Call(opts, result, method, params...) +} + +// Transfer initiates a plain transaction to move funds to the contract, calling +// its default method if one is available. +func (_Context *ContextTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _Context.Contract.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_Context *ContextTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _Context.Contract.contract.Transact(opts, method, params...) +} + +// ERC165MetaData contains all meta data concerning the ERC165 contract. +var ERC165MetaData = &bind.MetaData{ + ABI: "[{\"inputs\":[{\"internalType\":\"bytes4\",\"name\":\"interfaceId\",\"type\":\"bytes4\"}],\"name\":\"supportsInterface\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"}]", + Sigs: map[string]string{ + "01ffc9a7": "supportsInterface(bytes4)", + }, +} + +// ERC165ABI is the input ABI used to generate the binding from. +// Deprecated: Use ERC165MetaData.ABI instead. +var ERC165ABI = ERC165MetaData.ABI + +// Deprecated: Use ERC165MetaData.Sigs instead. +// ERC165FuncSigs maps the 4-byte function signature to its string representation. +var ERC165FuncSigs = ERC165MetaData.Sigs + +// ERC165 is an auto generated Go binding around an Ethereum contract. +type ERC165 struct { + ERC165Caller // Read-only binding to the contract + ERC165Transactor // Write-only binding to the contract + ERC165Filterer // Log filterer for contract events +} + +// ERC165Caller is an auto generated read-only Go binding around an Ethereum contract. +type ERC165Caller struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// ERC165Transactor is an auto generated write-only Go binding around an Ethereum contract. +type ERC165Transactor struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// ERC165Filterer is an auto generated log filtering Go binding around an Ethereum contract events. +type ERC165Filterer struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// ERC165Session is an auto generated Go binding around an Ethereum contract, +// with pre-set call and transact options. +type ERC165Session struct { + Contract *ERC165 // Generic contract binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// ERC165CallerSession is an auto generated read-only Go binding around an Ethereum contract, +// with pre-set call options. +type ERC165CallerSession struct { + Contract *ERC165Caller // Generic contract caller binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session +} + +// ERC165TransactorSession is an auto generated write-only Go binding around an Ethereum contract, +// with pre-set transact options. +type ERC165TransactorSession struct { + Contract *ERC165Transactor // Generic contract transactor binding to set the session for + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// ERC165Raw is an auto generated low-level Go binding around an Ethereum contract. +type ERC165Raw struct { + Contract *ERC165 // Generic contract binding to access the raw methods on +} + +// ERC165CallerRaw is an auto generated low-level read-only Go binding around an Ethereum contract. +type ERC165CallerRaw struct { + Contract *ERC165Caller // Generic read-only contract binding to access the raw methods on +} + +// ERC165TransactorRaw is an auto generated low-level write-only Go binding around an Ethereum contract. +type ERC165TransactorRaw struct { + Contract *ERC165Transactor // Generic write-only contract binding to access the raw methods on +} + +// NewERC165 creates a new instance of ERC165, bound to a specific deployed contract. +func NewERC165(address common.Address, backend bind.ContractBackend) (*ERC165, error) { + contract, err := bindERC165(address, backend, backend, backend) + if err != nil { + return nil, err + } + return &ERC165{ERC165Caller: ERC165Caller{contract: contract}, ERC165Transactor: ERC165Transactor{contract: contract}, ERC165Filterer: ERC165Filterer{contract: contract}}, nil +} + +// NewERC165Caller creates a new read-only instance of ERC165, bound to a specific deployed contract. +func NewERC165Caller(address common.Address, caller bind.ContractCaller) (*ERC165Caller, error) { + contract, err := bindERC165(address, caller, nil, nil) + if err != nil { + return nil, err + } + return &ERC165Caller{contract: contract}, nil +} + +// NewERC165Transactor creates a new write-only instance of ERC165, bound to a specific deployed contract. +func NewERC165Transactor(address common.Address, transactor bind.ContractTransactor) (*ERC165Transactor, error) { + contract, err := bindERC165(address, nil, transactor, nil) + if err != nil { + return nil, err + } + return &ERC165Transactor{contract: contract}, nil +} + +// NewERC165Filterer creates a new log filterer instance of ERC165, bound to a specific deployed contract. +func NewERC165Filterer(address common.Address, filterer bind.ContractFilterer) (*ERC165Filterer, error) { + contract, err := bindERC165(address, nil, nil, filterer) + if err != nil { + return nil, err + } + return &ERC165Filterer{contract: contract}, nil +} + +// bindERC165 binds a generic wrapper to an already deployed contract. +func bindERC165(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) { + parsed, err := ERC165MetaData.GetAbi() + if err != nil { + return nil, err + } + return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil +} + +// Call invokes the (constant) contract method with params as input values and +// sets the output to result. The result type might be a single field for simple +// returns, a slice of interfaces for anonymous returns and a struct for named +// returns. +func (_ERC165 *ERC165Raw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _ERC165.Contract.ERC165Caller.contract.Call(opts, result, method, params...) +} + +// Transfer initiates a plain transaction to move funds to the contract, calling +// its default method if one is available. +func (_ERC165 *ERC165Raw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _ERC165.Contract.ERC165Transactor.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_ERC165 *ERC165Raw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _ERC165.Contract.ERC165Transactor.contract.Transact(opts, method, params...) +} + +// Call invokes the (constant) contract method with params as input values and +// sets the output to result. The result type might be a single field for simple +// returns, a slice of interfaces for anonymous returns and a struct for named +// returns. +func (_ERC165 *ERC165CallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _ERC165.Contract.contract.Call(opts, result, method, params...) +} + +// Transfer initiates a plain transaction to move funds to the contract, calling +// its default method if one is available. +func (_ERC165 *ERC165TransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _ERC165.Contract.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_ERC165 *ERC165TransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _ERC165.Contract.contract.Transact(opts, method, params...) +} + +// SupportsInterface is a free data retrieval call binding the contract method 0x01ffc9a7. +// +// Solidity: function supportsInterface(bytes4 interfaceId) view returns(bool) +func (_ERC165 *ERC165Caller) SupportsInterface(opts *bind.CallOpts, interfaceId [4]byte) (bool, error) { + var out []interface{} + err := _ERC165.contract.Call(opts, &out, "supportsInterface", interfaceId) + + if err != nil { + return *new(bool), err + } + + out0 := *abi.ConvertType(out[0], new(bool)).(*bool) + + return out0, err + +} + +// SupportsInterface is a free data retrieval call binding the contract method 0x01ffc9a7. +// +// Solidity: function supportsInterface(bytes4 interfaceId) view returns(bool) +func (_ERC165 *ERC165Session) SupportsInterface(interfaceId [4]byte) (bool, error) { + return _ERC165.Contract.SupportsInterface(&_ERC165.CallOpts, interfaceId) +} + +// SupportsInterface is a free data retrieval call binding the contract method 0x01ffc9a7. +// +// Solidity: function supportsInterface(bytes4 interfaceId) view returns(bool) +func (_ERC165 *ERC165CallerSession) SupportsInterface(interfaceId [4]byte) (bool, error) { + return _ERC165.Contract.SupportsInterface(&_ERC165.CallOpts, interfaceId) +} + +// EnumerableSetMetaData contains all meta data concerning the EnumerableSet contract. +var EnumerableSetMetaData = &bind.MetaData{ + ABI: "[]", + Bin: "0x60556032600b8282823980515f1a607314602657634e487b7160e01b5f525f60045260245ffd5b305f52607381538281f3fe730000000000000000000000000000000000000000301460806040525f80fdfea26469706673582212201ec3fcd8425a477b64c89978a17adf538a2da29b003a43e615ec5e213f9f3bf964736f6c63430008180033", +} + +// EnumerableSetABI is the input ABI used to generate the binding from. +// Deprecated: Use EnumerableSetMetaData.ABI instead. +var EnumerableSetABI = EnumerableSetMetaData.ABI + +// EnumerableSetBin is the compiled bytecode used for deploying new contracts. +// Deprecated: Use EnumerableSetMetaData.Bin instead. +var EnumerableSetBin = EnumerableSetMetaData.Bin + +// DeployEnumerableSet deploys a new Ethereum contract, binding an instance of EnumerableSet to it. +func DeployEnumerableSet(auth *bind.TransactOpts, backend bind.ContractBackend) (common.Address, *types.Transaction, *EnumerableSet, error) { + parsed, err := EnumerableSetMetaData.GetAbi() + if err != nil { + return common.Address{}, nil, nil, err + } + if parsed == nil { + return common.Address{}, nil, nil, errors.New("GetABI returned nil") + } + + address, tx, contract, err := bind.DeployContract(auth, *parsed, common.FromHex(EnumerableSetBin), backend) + if err != nil { + return common.Address{}, nil, nil, err + } + return address, tx, &EnumerableSet{EnumerableSetCaller: EnumerableSetCaller{contract: contract}, EnumerableSetTransactor: EnumerableSetTransactor{contract: contract}, EnumerableSetFilterer: EnumerableSetFilterer{contract: contract}}, nil +} + +// EnumerableSet is an auto generated Go binding around an Ethereum contract. +type EnumerableSet struct { + EnumerableSetCaller // Read-only binding to the contract + EnumerableSetTransactor // Write-only binding to the contract + EnumerableSetFilterer // Log filterer for contract events +} + +// EnumerableSetCaller is an auto generated read-only Go binding around an Ethereum contract. +type EnumerableSetCaller struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// EnumerableSetTransactor is an auto generated write-only Go binding around an Ethereum contract. +type EnumerableSetTransactor struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// EnumerableSetFilterer is an auto generated log filtering Go binding around an Ethereum contract events. +type EnumerableSetFilterer struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// EnumerableSetSession is an auto generated Go binding around an Ethereum contract, +// with pre-set call and transact options. +type EnumerableSetSession struct { + Contract *EnumerableSet // Generic contract binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// EnumerableSetCallerSession is an auto generated read-only Go binding around an Ethereum contract, +// with pre-set call options. +type EnumerableSetCallerSession struct { + Contract *EnumerableSetCaller // Generic contract caller binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session +} + +// EnumerableSetTransactorSession is an auto generated write-only Go binding around an Ethereum contract, +// with pre-set transact options. +type EnumerableSetTransactorSession struct { + Contract *EnumerableSetTransactor // Generic contract transactor binding to set the session for + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// EnumerableSetRaw is an auto generated low-level Go binding around an Ethereum contract. +type EnumerableSetRaw struct { + Contract *EnumerableSet // Generic contract binding to access the raw methods on +} + +// EnumerableSetCallerRaw is an auto generated low-level read-only Go binding around an Ethereum contract. +type EnumerableSetCallerRaw struct { + Contract *EnumerableSetCaller // Generic read-only contract binding to access the raw methods on +} + +// EnumerableSetTransactorRaw is an auto generated low-level write-only Go binding around an Ethereum contract. +type EnumerableSetTransactorRaw struct { + Contract *EnumerableSetTransactor // Generic write-only contract binding to access the raw methods on +} + +// NewEnumerableSet creates a new instance of EnumerableSet, bound to a specific deployed contract. +func NewEnumerableSet(address common.Address, backend bind.ContractBackend) (*EnumerableSet, error) { + contract, err := bindEnumerableSet(address, backend, backend, backend) + if err != nil { + return nil, err + } + return &EnumerableSet{EnumerableSetCaller: EnumerableSetCaller{contract: contract}, EnumerableSetTransactor: EnumerableSetTransactor{contract: contract}, EnumerableSetFilterer: EnumerableSetFilterer{contract: contract}}, nil +} + +// NewEnumerableSetCaller creates a new read-only instance of EnumerableSet, bound to a specific deployed contract. +func NewEnumerableSetCaller(address common.Address, caller bind.ContractCaller) (*EnumerableSetCaller, error) { + contract, err := bindEnumerableSet(address, caller, nil, nil) + if err != nil { + return nil, err + } + return &EnumerableSetCaller{contract: contract}, nil +} + +// NewEnumerableSetTransactor creates a new write-only instance of EnumerableSet, bound to a specific deployed contract. +func NewEnumerableSetTransactor(address common.Address, transactor bind.ContractTransactor) (*EnumerableSetTransactor, error) { + contract, err := bindEnumerableSet(address, nil, transactor, nil) + if err != nil { + return nil, err + } + return &EnumerableSetTransactor{contract: contract}, nil +} + +// NewEnumerableSetFilterer creates a new log filterer instance of EnumerableSet, bound to a specific deployed contract. +func NewEnumerableSetFilterer(address common.Address, filterer bind.ContractFilterer) (*EnumerableSetFilterer, error) { + contract, err := bindEnumerableSet(address, nil, nil, filterer) + if err != nil { + return nil, err + } + return &EnumerableSetFilterer{contract: contract}, nil +} + +// bindEnumerableSet binds a generic wrapper to an already deployed contract. +func bindEnumerableSet(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) { + parsed, err := EnumerableSetMetaData.GetAbi() + if err != nil { + return nil, err + } + return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil +} + +// Call invokes the (constant) contract method with params as input values and +// sets the output to result. The result type might be a single field for simple +// returns, a slice of interfaces for anonymous returns and a struct for named +// returns. +func (_EnumerableSet *EnumerableSetRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _EnumerableSet.Contract.EnumerableSetCaller.contract.Call(opts, result, method, params...) +} + +// Transfer initiates a plain transaction to move funds to the contract, calling +// its default method if one is available. +func (_EnumerableSet *EnumerableSetRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _EnumerableSet.Contract.EnumerableSetTransactor.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_EnumerableSet *EnumerableSetRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _EnumerableSet.Contract.EnumerableSetTransactor.contract.Transact(opts, method, params...) +} + +// Call invokes the (constant) contract method with params as input values and +// sets the output to result. The result type might be a single field for simple +// returns, a slice of interfaces for anonymous returns and a struct for named +// returns. +func (_EnumerableSet *EnumerableSetCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _EnumerableSet.Contract.contract.Call(opts, result, method, params...) +} + +// Transfer initiates a plain transaction to move funds to the contract, calling +// its default method if one is available. +func (_EnumerableSet *EnumerableSetTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _EnumerableSet.Contract.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_EnumerableSet *EnumerableSetTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _EnumerableSet.Contract.contract.Transact(opts, method, params...) +} + +// FastBridgeV2MetaData contains all meta data concerning the FastBridgeV2 contract. +var FastBridgeV2MetaData = &bind.MetaData{ + ABI: "[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_owner\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"AccessControlBadConfirmation\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"neededRole\",\"type\":\"bytes32\"}],\"name\":\"AccessControlUnauthorizedAccount\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"}],\"name\":\"AddressEmptyCode\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"AddressInsufficientBalance\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"AmountIncorrect\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"CallParamsLengthAboveMax\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ChainIncorrect\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DeadlineExceeded\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DeadlineNotExceeded\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DeadlineTooShort\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DisputePeriodNotPassed\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DisputePeriodPassed\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ExclusivityParamsIncorrect\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ExclusivityPeriodNotPassed\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"FailedInnerCall\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"MsgValueIncorrect\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"NativeTokenCallValueNotSupported\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"RecipientIncorrectReturnValue\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"RecipientNoReturnValue\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"}],\"name\":\"SafeERC20FailedOperation\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"SenderIncorrect\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"StatusIncorrect\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"TokenNotContract\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"TransactionRelayed\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ZeroAddress\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"BridgeDepositClaimed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"BridgeDepositRefunded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"name\":\"BridgeProofDisputed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"transactionHash\",\"type\":\"bytes32\"}],\"name\":\"BridgeProofProvided\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"quoteId\",\"type\":\"bytes\"}],\"name\":\"BridgeQuoteDetails\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"originChainId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"chainGasAmount\",\"type\":\"uint256\"}],\"name\":\"BridgeRelayed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"destChainId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"sendChainGas\",\"type\":\"bool\"}],\"name\":\"BridgeRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"oldChainGasAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newChainGasAmount\",\"type\":\"uint256\"}],\"name\":\"ChainGasAmountUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"oldFeeRate\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newFeeRate\",\"type\":\"uint256\"}],\"name\":\"FeeRateUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"FeesSwept\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"previousAdminRole\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"newAdminRole\",\"type\":\"bytes32\"}],\"name\":\"RoleAdminChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleGranted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleRevoked\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"DEFAULT_ADMIN_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"DISPUTE_PERIOD\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"FEE_BPS\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"FEE_RATE_MAX\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"GOVERNOR_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"GUARD_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"MAX_CALL_PARAMS_LENGTH\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"MIN_DEADLINE_PERIOD\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"REFUNDER_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"REFUND_DELAY\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"RELAYER_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"dstChainId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"sendChainGas\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"}],\"internalType\":\"structIFastBridge.BridgeParams\",\"name\":\"params\",\"type\":\"tuple\"}],\"name\":\"bridge\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"dstChainId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"sendChainGas\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"}],\"internalType\":\"structIFastBridge.BridgeParams\",\"name\":\"params\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"quoteRelayer\",\"type\":\"address\"},{\"internalType\":\"int256\",\"name\":\"quoteExclusivitySeconds\",\"type\":\"int256\"},{\"internalType\":\"bytes\",\"name\":\"quoteId\",\"type\":\"bytes\"},{\"internalType\":\"uint256\",\"name\":\"callValue\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"callParams\",\"type\":\"bytes\"}],\"internalType\":\"structIFastBridgeV2.BridgeParamsV2\",\"name\":\"paramsV2\",\"type\":\"tuple\"}],\"name\":\"bridge\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"}],\"name\":\"bridgeProofs\",\"outputs\":[{\"internalType\":\"uint96\",\"name\":\"timestamp\",\"type\":\"uint96\"},{\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"bridgeRelayDetails\",\"outputs\":[{\"internalType\":\"uint48\",\"name\":\"blockNumber\",\"type\":\"uint48\"},{\"internalType\":\"uint48\",\"name\":\"blockTimestamp\",\"type\":\"uint48\"},{\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"}],\"name\":\"bridgeRelays\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"}],\"name\":\"bridgeStatuses\",\"outputs\":[{\"internalType\":\"enumIFastBridgeV2.BridgeStatus\",\"name\":\"status\",\"type\":\"uint8\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"bridgeTxDetails\",\"outputs\":[{\"internalType\":\"enumIFastBridgeV2.BridgeStatus\",\"name\":\"status\",\"type\":\"uint8\"},{\"internalType\":\"uint40\",\"name\":\"proofBlockTimestamp\",\"type\":\"uint40\"},{\"internalType\":\"uint48\",\"name\":\"proofBlockNumber\",\"type\":\"uint48\"},{\"internalType\":\"address\",\"name\":\"proofRelayer\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"name\":\"canClaim\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"chainGasAmount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"claim\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"claim\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"deployBlock\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"}],\"name\":\"dispute\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"getBridgeTransaction\",\"outputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"originChainId\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"destChainId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"originSender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destRecipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"originFeeAmount\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"sendChainGas\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"}],\"internalType\":\"structIFastBridge.BridgeTransaction\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"getBridgeTransactionV2\",\"outputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"originChainId\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"destChainId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"originSender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destRecipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"originFeeAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"callValue\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"exclusivityRelayer\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"exclusivityEndTime\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"callParams\",\"type\":\"bytes\"}],\"internalType\":\"structIFastBridgeV2.BridgeTransactionV2\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"}],\"name\":\"getRoleAdmin\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"index\",\"type\":\"uint256\"}],\"name\":\"getRoleMember\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"}],\"name\":\"getRoleMemberCount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"grantRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"hasRole\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"nonce\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"protocolFeeRate\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"protocolFees\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"destTxHash\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"name\":\"prove\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"},{\"internalType\":\"bytes32\",\"name\":\"destTxHash\",\"type\":\"bytes32\"}],\"name\":\"prove\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"refund\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"relay\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"},{\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"name\":\"relay\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"callerConfirmation\",\"type\":\"address\"}],\"name\":\"renounceRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"revokeRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"senderNonces\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"newChainGasAmount\",\"type\":\"uint256\"}],\"name\":\"setChainGasAmount\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"newFeeRate\",\"type\":\"uint256\"}],\"name\":\"setProtocolFeeRate\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes4\",\"name\":\"interfaceId\",\"type\":\"bytes4\"}],\"name\":\"supportsInterface\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"}],\"name\":\"sweepProtocolFees\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", + Sigs: map[string]string{ + "a217fddf": "DEFAULT_ADMIN_ROLE()", + "a5bbe22b": "DISPUTE_PERIOD()", + "bf333f2c": "FEE_BPS()", + "0f5f6ed7": "FEE_RATE_MAX()", + "ccc57490": "GOVERNOR_ROLE()", + "03ed0ee5": "GUARD_ROLE()", + "df36bb13": "MAX_CALL_PARAMS_LENGTH()", + "820688d5": "MIN_DEADLINE_PERIOD()", + "5960ccf2": "REFUNDER_ROLE()", + "190da595": "REFUND_DELAY()", + "926d7d7f": "RELAYER_ROLE()", + "45851694": "bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256))", + "bfc7c607": "bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256),(address,int256,bytes,uint256,bytes))", + "91ad5039": "bridgeProofs(bytes32)", + "c79371b1": "bridgeRelayDetails(bytes32)", + "8379a24f": "bridgeRelays(bytes32)", + "051287bc": "bridgeStatuses(bytes32)", + "63787e52": "bridgeTxDetails(bytes32)", + "aa9641ab": "canClaim(bytes32,address)", + "e00a83e0": "chainGasAmount()", + "c63ff8dd": "claim(bytes)", + "41fcb612": "claim(bytes,address)", + "a3ec191a": "deployBlock()", + "add98c70": "dispute(bytes32)", + "ac11fb1a": "getBridgeTransaction(bytes)", + "5aa6ccba": "getBridgeTransactionV2(bytes)", + "248a9ca3": "getRoleAdmin(bytes32)", + "9010d07c": "getRoleMember(bytes32,uint256)", + "ca15c873": "getRoleMemberCount(bytes32)", + "2f2ff15d": "grantRole(bytes32,address)", + "91d14854": "hasRole(bytes32,address)", + "affed0e0": "nonce()", + "58f85880": "protocolFeeRate()", + "dcf844a7": "protocolFees(address)", + "886d36ff": "prove(bytes,bytes32)", + "18e4357d": "prove(bytes32,bytes32,address)", + "5eb7d946": "refund(bytes)", + "8f0d6f17": "relay(bytes)", + "9c9545f0": "relay(bytes,address)", + "36568abe": "renounceRole(bytes32,address)", + "d547741f": "revokeRole(bytes32,address)", + "295710ff": "senderNonces(address)", + "b250fe6b": "setChainGasAmount(uint256)", + "b13aa2d6": "setProtocolFeeRate(uint256)", + "01ffc9a7": "supportsInterface(bytes4)", + "06f333f2": "sweepProtocolFees(address,address)", + }, + Bin: "0x60c06040525f60805234801562000014575f80fd5b5060405162003d2f38038062003d2f83398101604081905262000037916200018e565b80620000445f8262000051565b50504360a05250620001b6565b5f806200005f84846200008c565b9050801562000083575f84815260016020526040902062000081908462000137565b505b90505b92915050565b5f828152602081815260408083206001600160a01b038516845290915281205460ff166200012f575f838152602081815260408083206001600160a01b03861684529091529020805460ff19166001179055620000e63390565b6001600160a01b0316826001600160a01b0316847f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a450600162000086565b505f62000086565b5f62000083836001600160a01b0384165f8181526001830160205260408120546200012f57508154600181810184555f84815260208082209093018490558454848252828601909352604090209190915562000086565b5f602082840312156200019f575f80fd5b81516001600160a01b038116811462000083575f80fd5b60805160a051613b57620001d85f395f6107cf01525f61086c0152613b575ff3fe6080604052600436106102ed575f3560e01c806391ad503911610186578063b13aa2d6116100dc578063ca15c87311610087578063dcf844a711610062578063dcf844a714610a10578063df36bb1314610a3b578063e00a83e014610a50575f80fd5b8063ca15c8731461099f578063ccc57490146109be578063d547741f146109f1575f80fd5b8063bfc7c607116100b7578063bfc7c607146108e2578063c63ff8dd146108f5578063c79371b114610914575f80fd5b8063b13aa2d61461088e578063b250fe6b146108ad578063bf333f2c146108cc575f80fd5b8063a3ec191a1161013c578063ac11fb1a11610117578063ac11fb1a14610810578063add98c701461083c578063affed0e01461085b575f80fd5b8063a3ec191a146107be578063a5bbe22b146105e1578063aa9641ab146107f1575f80fd5b8063926d7d7f1161016c578063926d7d7f146107655780639c9545f014610798578063a217fddf146107ab575f80fd5b806391ad5039146106a557806391d1485414610723575f80fd5b806341fcb6121161024657806363787e52116101f1578063886d36ff116101cc578063886d36ff1461063c5780638f0d6f171461065b5780639010d07c1461066e575f80fd5b806363787e5214610568578063820688d5146105e15780638379a24f146105f6575f80fd5b80635960ccf2116102215780635960ccf2146104ea5780635aa6ccba1461051d5780635eb7d94614610549575f80fd5b806341fcb612146104a357806345851694146104c257806358f85880146104d5575f80fd5b806318e4357d116102a6578063295710ff11610281578063295710ff1461043a5780632f2ff15d1461046557806336568abe14610484575f80fd5b806318e4357d146103d7578063190da595146103f6578063248a9ca31461040c575f80fd5b8063051287bc116102d6578063051287bc1461036657806306f333f2146103a15780630f5f6ed7146103c2575f80fd5b806301ffc9a7146102f157806303ed0ee514610325575b5f80fd5b3480156102fc575f80fd5b5061031061030b366004612e21565b610a65565b60405190151581526020015b60405180910390f35b348015610330575f80fd5b506103587f043c983c49d46f0e102151eaf8085d4a2e6571d5df2d47b013f39bddfd4a639d81565b60405190815260200161031c565b348015610371575f80fd5b50610394610380366004612e60565b5f9081526005602052604090205460ff1690565b60405161031c9190612edd565b3480156103ac575f80fd5b506103c06103bb366004612f0a565b610ac0565b005b3480156103cd575f80fd5b5061035861271081565b3480156103e2575f80fd5b506103c06103f1366004612f41565b610b85565b348015610401575f80fd5b5061035862093a8081565b348015610417575f80fd5b50610358610426366004612e60565b5f9081526020819052604090206001015490565b348015610445575f80fd5b50610358610454366004612f77565b60076020525f908152604090205481565b348015610470575f80fd5b506103c061047f366004612f92565b610cf0565b34801561048f575f80fd5b506103c061049e366004612f92565b610d1a565b3480156104ae575f80fd5b506103c06104bd366004613121565b610d66565b6103c06104d036600461323a565b610fd4565b3480156104e0575f80fd5b5061035860025481565b3480156104f5575f80fd5b506103587fdb9556138406326f00296e13ea2ad7db24ba82381212d816b1a40c23b466b32781565b348015610528575f80fd5b5061053c610537366004613255565b61102c565b60405161031c91906132dc565b348015610554575f80fd5b506103c0610563366004613255565b6110e4565b348015610573575f80fd5b506105d1610582366004612e60565b60056020525f908152604090205460ff811690610100810464ffffffffff16906601000000000000810465ffffffffffff16906c0100000000000000000000000090046001600160a01b031684565b60405161031c94939291906133f0565b3480156105ec575f80fd5b5061035861070881565b348015610601575f80fd5b50610310610610366004612e60565b5f908152600660205260409020546c0100000000000000000000000090046001600160a01b0316151590565b348015610647575f80fd5b506103c0610656366004613431565b6112d5565b6103c0610669366004613255565b6112eb565b348015610679575f80fd5b5061068d610688366004613473565b6112f5565b6040516001600160a01b03909116815260200161031c565b3480156106b0575f80fd5b506106f76106bf366004612e60565b5f90815260056020526040902054610100810464ffffffffff16916c010000000000000000000000009091046001600160a01b031690565b604080516bffffffffffffffffffffffff90931683526001600160a01b0390911660208301520161031c565b34801561072e575f80fd5b5061031061073d366004612f92565b5f918252602082815260408084206001600160a01b0393909316845291905290205460ff1690565b348015610770575f80fd5b506103587fe2b7fb3b832174769106daebcfd6d1970523240dda11281102db9363b83b0dc481565b6103c06107a6366004613121565b611313565b3480156107b6575f80fd5b506103585f81565b3480156107c9575f80fd5b506103587f000000000000000000000000000000000000000000000000000000000000000081565b3480156107fc575f80fd5b5061031061080b366004612f92565b6115c1565b34801561081b575f80fd5b5061082f61082a366004613255565b6116a8565b60405161031c9190613493565b348015610847575f80fd5b506103c0610856366004612e60565b61185b565b348015610866575f80fd5b506103587f000000000000000000000000000000000000000000000000000000000000000081565b348015610899575f80fd5b506103c06108a8366004612e60565b61197a565b3480156108b8575f80fd5b506103c06108c7366004612e60565b611a5c565b3480156108d7575f80fd5b50610358620f424081565b6103c06108f0366004613579565b611ac4565b348015610900575f80fd5b506103c061090f366004613255565b611d3c565b34801561091f575f80fd5b5061097161092e366004612e60565b60066020525f908152604090205465ffffffffffff8082169166010000000000008104909116906c0100000000000000000000000090046001600160a01b031683565b6040805165ffffffffffff94851681529390921660208401526001600160a01b03169082015260600161031c565b3480156109aa575f80fd5b506103586109b9366004612e60565b611d46565b3480156109c9575f80fd5b506103587f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f5581565b3480156109fc575f80fd5b506103c0610a0b366004612f92565b611d5c565b348015610a1b575f80fd5b50610358610a2a366004612f77565b60036020525f908152604090205481565b348015610a46575f80fd5b5061035861ffff81565b348015610a5b575f80fd5b5061035860045481565b5f7fffffffff0000000000000000000000000000000000000000000000000000000082167f5a05180f000000000000000000000000000000000000000000000000000000001480610aba5750610aba82611d80565b92915050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f55610aea81611e16565b6001600160a01b0383165f9081526003602052604081205490819003610b105750505050565b6001600160a01b0384165f81815260036020526040812055610b33908483611e20565b604080516001600160a01b038087168252851660208201529081018290527f244e51bc38c1452fa8aaf487bcb4bca36c2baa3a5fbdb776b1eabd8dc6d277cd9060600160405180910390a1505b505050565b7fe2b7fb3b832174769106daebcfd6d1970523240dda11281102db9363b83b0dc4610baf81611e16565b60015f8581526005602052604090205460ff166004811115610bd357610bd3612e77565b14610c0a576040517f4145817200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f84815260056020908152604091829020805460027fffffffffffffffffffffffffffffffffffffffff0000000000000000000000009091166101004264ffffffffff16027fffffffffffffffffffffffffffffffffffffffff000000000000ffffffffffff161766010000000000004365ffffffffffff160217176bffffffffffffffffffffffff166c010000000000000000000000006001600160a01b0387169081029190911790915582518681529251909287927f4ac8af8a2cd87193d64dfc7a3b8d9923b714ec528b18725d080aa1299be0c5e492918290030190a350505050565b5f82815260208190526040902060010154610d0a81611e16565b610d148383611f3e565b50505050565b6001600160a01b0381163314610d5c576040517f6697b23200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610b808282611f71565b815160208301205f610d778461102c565b905060025f8381526005602052604090205460ff166004811115610d9d57610d9d612e77565b14610dd4576040517f4145817200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600160a01b038316610e10575f828152600560205260409020546c0100000000000000000000000090046001600160a01b03169250610e6f565b5f828152600560205260409020546c0100000000000000000000000090046001600160a01b03163314610e6f576040517f4af43a9000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f8281526005602052604090205461070890610100900464ffffffffff90811642031611610ec9576040517f1992d0bd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f82815260056020526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016600317905561010081015115610f415761010081015160808201516001600160a01b03165f9081526003602052604081208054909190610f3b90849061366e565b90915550505b608081015160c0820151610f5f6001600160a01b0383168683611e20565b5f848152600560209081526040918290205482516001600160a01b038681168252928101859052888316936c010000000000000000000000009092049092169187917f582211c35a2139ac3bbaac74663c6a1f56c6cbb658b41fe11fd45a82074ac678910160405180910390a4505050505050565b611029816040518060a001604052805f6001600160a01b031681526020015f815260200160405180602001604052805f81525081526020015f815260200160405180602001604052805f815250815250611ac4565b50565b6110d0604051806101e001604052805f63ffffffff1681526020015f63ffffffff1681526020015f6001600160a01b031681526020015f6001600160a01b031681526020015f6001600160a01b031681526020015f6001600160a01b031681526020015f81526020015f81526020015f81526020015f81526020015f81526020015f81526020015f6001600160a01b031681526020015f8152602001606081525090565b81806020019051810190610aba91906136d9565b805160208201205f6110f58361102c565b905060015f8381526005602052604090205460ff16600481111561111b5761111b612e77565b14611152576040517f4145817200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b335f9081527fd2043bf65931af3dbecf60d0db8f40e4160406d7beb00522f4200cf4944a1eb8602052604090205460ff16156111cb5780610140015142116111c6576040517fe15ff9ea00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611217565b62093a808161014001516111df919061366e565b4211611217576040517fe15ff9ea00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f8281526005602052604080822080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166004179055820151608083015161010084015160c08501519293919261126f919061366e565b90506112856001600160a01b0383168483611e20565b604080516001600160a01b0384811682526020820184905285169187917fb4c55c0c9bc613519b920e88748090150b890a875d307f21bea7d4fb2e8bc958910160405180910390a3505050505050565b6112e782805190602001208233610b85565b5050565b6110298133611313565b5f82815260016020526040812061130c9083611f9c565b9392505050565b815160208301205f6113248461102c565b9050611331818385611fa7565b604080516060808201835265ffffffffffff438116835242811660208085019182526001600160a01b03808a168688019081525f8a8152600690935296909120945185549251965182166c01000000000000000000000000026bffffffffffffffffffffffff9785166601000000000000027fffffffffffffffffffffffffffffffffffffffff000000000000000000000000909416919094161791909117949094161790915582015160a083015160e084015191929091907fffffffffffffffffffffffff11111111111111111111111111111111111111129083160161148e5761012084015115611450576040517f2598ad2e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b803414611489576040517f81de0bf300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6114e1565b83610120015134146114cc576040517f81de0bf300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6114e16001600160a01b038316338584612149565b6101c08401515115611503576114fe838383876101c001516121c5565b611513565b3415611513576115138334612321565b826001600160a01b0316866001600160a01b0316867ff8ae392d784b1ea5e8881bfa586d81abf07ef4f1e2fc75f7fe51c90f05199a5c875f015188608001518960a001518a60c001518b60e001518c61012001516040516115b09695949392919063ffffffff9690961686526001600160a01b0394851660208701529290931660408501526060840152608083019190915260a082015260c00190565b60405180910390a450505050505050565b5f60025f8481526005602052604090205460ff1660048111156115e6576115e6612e77565b1461161d576040517f4145817200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f838152600560205260409020546001600160a01b038381166c01000000000000000000000000909204161461167f576040517f4af43a9000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b50505f9081526005602052604090205461070861010090910464ffffffffff9081164203161190565b60408051610180810182525f80825260208201819052818301819052606082018190526080820181905260a0820181905260c0820181905260e0820181905261010082018190526101208201819052610140820181905261016082015290517f5aa6ccba0000000000000000000000000000000000000000000000000000000081523090635aa6ccba90611740908590600401613809565b5f60405180830381865afa92505050801561177c57506040513d5f823e601f3d908101601f1916820160405261177991908101906136d9565b60015b6117945781806020019051810190610aba9190613826565b604051806101800160405280825f015163ffffffff168152602001826020015163ffffffff16815260200182604001516001600160a01b0316815260200182606001516001600160a01b0316815260200182608001516001600160a01b031681526020018260a001516001600160a01b031681526020018260c0015181526020018260e00151815260200182610100015181526020018261012001515f1415151581526020018261014001518152602001826101600151815250915050919050565b919050565b7f043c983c49d46f0e102151eaf8085d4a2e6571d5df2d47b013f39bddfd4a639d61188581611e16565b60025f8381526005602052604090205460ff1660048111156118a9576118a9612e77565b146118e0576040517f4145817200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f8281526005602052604090205461070890610100900464ffffffffff908116420316111561193b576040517f3e908aac00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f828152600560205260408082206001905551339184917f0695cf1d39b3055dcd0fe02d8b47eaf0d5a13e1996de925de59d0ef9b7f7fad49190a35050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f556119a481611e16565b612710821115611a15576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f6e657746656552617465203e206d61780000000000000000000000000000000060448201526064015b60405180910390fd5b600280549083905560408051828152602081018590527f14914da2bf76024616fbe1859783fcd4dbddcb179b1f3a854949fbf920dcb95791015b60405180910390a1505050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f55611a8681611e16565b600480549083905560408051828152602081018590527f5cf09b12f3f56b4c564d51b25b40360af6d795198adb61ae0806a36c294323fa9101611a4f565b5f816020015142611ad591906138f0565b9050611ae28383836123e6565b5f611af584606001518560a00151612669565b90505f806002541115611b2157620f424060025483611b149190613917565b611b1e919061392e565b90505b611b2b8183613966565b91505f604051806101e001604052804663ffffffff168152602001875f015163ffffffff16815260200187602001516001600160a01b0316815260200187604001516001600160a01b0316815260200187606001516001600160a01b0316815260200187608001516001600160a01b031681526020018481526020018760c00151815260200183815260200186606001518152602001876101000151815260200160075f89602001516001600160a01b03166001600160a01b031681526020019081526020015f205f815480929190611c0390613979565b919050558152602001865f01516001600160a01b031681526020018581526020018660800151815250604051602001611c3c91906132dc565b60408051808303601f1901815282825280516020808301919091205f818152600583529390932080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016600117905589015189516060808c015160808d015160c08e0151928d015195985095966001600160a01b039094169587957f120ea0364f36cdac7983bcfdd55270ca09d7f9b314a2ebc425a3b01ab1d6403a95611cef958b95909493928e92901515906139b0565b60405180910390a3807f3120e2bb59c86aca6890191a589a96af3662838efa374fbdcdf4c95bfe4a6c0e8760400151604051611d2b9190613809565b60405180910390a250505050505050565b611029815f610d66565b5f818152600160205260408120610aba9061280d565b5f82815260208190526040902060010154611d7681611e16565b610d148383611f71565b5f7fffffffff0000000000000000000000000000000000000000000000000000000082167f7965db0b000000000000000000000000000000000000000000000000000000001480610aba57507f01ffc9a7000000000000000000000000000000000000000000000000000000007fffffffff00000000000000000000000000000000000000000000000000000000831614610aba565b6110298133612816565b306001600160a01b03831603611e3557505050565b805f03611e4157505050565b7fffffffffffffffffffffffff11111111111111111111111111111111111111126001600160a01b03841601611f2a575f826001600160a01b0316826040515f6040518083038185875af1925050503d805f8114611eba576040519150601f19603f3d011682016040523d82523d5f602084013e611ebf565b606091505b5050905080610d14576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f455448207472616e73666572206661696c6564000000000000000000000000006044820152606401611a0c565b610b806001600160a01b0384168383612881565b5f80611f4a84846128b2565b9050801561130c575f848152600160205260409020611f699084612977565b509392505050565b5f80611f7d848461298b565b9050801561130c575f848152600160205260409020611f699084612a2a565b5f61130c8383612a3e565b6001600160a01b038116611fe7576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f828152600660205260409020546c0100000000000000000000000090046001600160a01b031615612045576040517fbef7bb7d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b4663ffffffff16836020015163ffffffff161461208e576040517f7029fdf900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8261014001514211156120cd576040517f559895a300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6101808301516001600160a01b0316158015906121015750806001600160a01b03168361018001516001600160a01b031614155b80156121125750826101a001514211155b15610b80576040517f14be123200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040516001600160a01b038481166024830152838116604483015260648201839052610d149186918216906323b872dd906084015b604051602081830303815290604052915060e01b6020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8381831617835250505050612a64565b5f8383836040516024016121db93929190613a05565b60408051601f198184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f461e0c210000000000000000000000000000000000000000000000000000000017905290505f612241868334612ade565b905080515f0361227d576040517f1a95ad2600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80516020146122b8576040517ff3725cca00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f461e0c21000000000000000000000000000000000000000000000000000000006122e282613a35565b14612319576040517ff3725cca00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b505050505050565b8047101561235d576040517fcd786059000000000000000000000000000000000000000000000000000000008152306004820152602401611a0c565b5f826001600160a01b0316826040515f6040518083038185875af1925050503d805f81146123a6576040519150601f19603f3d011682016040523d82523d5f602084013e6123ab565b606091505b5050905080610b80576040517f1425ea4200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b46835f015163ffffffff1603612428576040517f7029fdf900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60a0830151158061243b575060c0830151155b15612472576040517fe38820c800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60208301516001600160a01b03161580612497575060408301516001600160a01b0316155b156124ce576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60608301516001600160a01b031615806124f3575060808301516001600160a01b0316155b1561252a576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6125366107084261366e565b8361010001511015612574576040517f04b7fcc800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61ffff82608001515111156125b5576040517ffbe24d4900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6060820151158015906125e8575060808301516001600160a01b031673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee145b1561261f576040517f2598ad2e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f81131580612632575082610100015181135b15610b80576040517f352807b900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f7fffffffffffffffffffffffff11111111111111111111111111111111111111126001600160a01b038416016126da573482146126d3576040517f81de0bf300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5034610aba565b6126ec836001600160a01b0316612b90565b6040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201526001600160a01b038416906370a0823190602401602060405180830381865afa158015612747573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061276b9190613a7a565b90506127826001600160a01b038416333085612149565b6040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015281906001600160a01b038516906370a0823190602401602060405180830381865afa1580156127df573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906128039190613a7a565b61130c9190613966565b5f610aba825490565b5f828152602081815260408083206001600160a01b038516845290915290205460ff166112e7576040517fe2517d3f0000000000000000000000000000000000000000000000000000000081526001600160a01b038216600482015260248101839052604401611a0c565b6040516001600160a01b03838116602483015260448201839052610b8091859182169063a9059cbb9060640161217e565b5f828152602081815260408083206001600160a01b038516845290915281205460ff16612970575f838152602081815260408083206001600160a01b0386168452909152902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790556129283390565b6001600160a01b0316826001600160a01b0316847f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a4506001610aba565b505f610aba565b5f61130c836001600160a01b038416612c35565b5f828152602081815260408083206001600160a01b038516845290915281205460ff1615612970575f838152602081815260408083206001600160a01b038616808552925280832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016905551339286917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a4506001610aba565b5f61130c836001600160a01b038416612c7a565b5f825f018281548110612a5357612a53613a91565b905f5260205f200154905092915050565b5f612a786001600160a01b03841683612d5d565b905080515f14158015612a9c575080806020019051810190612a9a9190613abe565b155b15610b80576040517f5274afe70000000000000000000000000000000000000000000000000000000081526001600160a01b0384166004820152602401611a0c565b606081471015612b1c576040517fcd786059000000000000000000000000000000000000000000000000000000008152306004820152602401611a0c565b5f80856001600160a01b03168486604051612b379190613ad9565b5f6040518083038185875af1925050503d805f8114612b71576040519150601f19603f3d011682016040523d82523d5f602084013e612b76565b606091505b5091509150612b86868383612d6a565b9695505050505050565b7fffffffffffffffffffffffff11111111111111111111111111111111111111126001600160a01b03821601612bf2576040517f7f523fe800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b806001600160a01b03163b5f03611029576040517f7f523fe800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f81815260018301602052604081205461297057508154600181810184555f848152602080822090930184905584548482528286019093526040902091909155610aba565b5f8181526001830160205260408120548015612d54575f612c9c600183613966565b85549091505f90612caf90600190613966565b9050808214612d0e575f865f018281548110612ccd57612ccd613a91565b905f5260205f200154905080875f018481548110612ced57612ced613a91565b5f918252602080832090910192909255918252600188019052604090208390555b8554869080612d1f57612d1f613af4565b600190038181905f5260205f20015f90559055856001015f8681526020019081526020015f205f905560019350505050610aba565b5f915050610aba565b606061130c83835f612ade565b606082612d7f57612d7a82612ddf565b61130c565b8151158015612d9657506001600160a01b0384163b155b15612dd8576040517f9996b3150000000000000000000000000000000000000000000000000000000081526001600160a01b0385166004820152602401611a0c565b508061130c565b805115612def5780518082602001fd5b6040517f1425ea4200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f60208284031215612e31575f80fd5b81357fffffffff000000000000000000000000000000000000000000000000000000008116811461130c575f80fd5b5f60208284031215612e70575f80fd5b5035919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602160045260245ffd5b60058110612ed9577f4e487b71000000000000000000000000000000000000000000000000000000005f52602160045260245ffd5b9052565b60208101610aba8284612ea4565b6001600160a01b0381168114611029575f80fd5b803561185681612eeb565b5f8060408385031215612f1b575f80fd5b8235612f2681612eeb565b91506020830135612f3681612eeb565b809150509250929050565b5f805f60608486031215612f53575f80fd5b83359250602084013591506040840135612f6c81612eeb565b809150509250925092565b5f60208284031215612f87575f80fd5b813561130c81612eeb565b5f8060408385031215612fa3575f80fd5b823591506020830135612f3681612eeb565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b604051610120810167ffffffffffffffff8111828210171561300657613006612fb5565b60405290565b60405160a0810167ffffffffffffffff8111828210171561300657613006612fb5565b6040516101e0810167ffffffffffffffff8111828210171561300657613006612fb5565b604051610180810167ffffffffffffffff8111828210171561300657613006612fb5565b604051601f8201601f1916810167ffffffffffffffff811182821017156130a0576130a0612fb5565b604052919050565b5f67ffffffffffffffff8211156130c1576130c1612fb5565b50601f01601f191660200190565b5f82601f8301126130de575f80fd5b81356130f16130ec826130a8565b613077565b818152846020838601011115613105575f80fd5b816020850160208301375f918101602001919091529392505050565b5f8060408385031215613132575f80fd5b823567ffffffffffffffff811115613148575f80fd5b613154858286016130cf565b9250506020830135612f3681612eeb565b63ffffffff81168114611029575f80fd5b803561185681613165565b8015158114611029575f80fd5b803561185681613181565b5f61012082840312156131aa575f80fd5b6131b2612fe2565b90506131bd82613176565b81526131cb60208301612eff565b60208201526131dc60408301612eff565b60408201526131ed60608301612eff565b60608201526131fe60808301612eff565b608082015260a082013560a082015260c082013560c082015261322360e0830161318e565b60e082015261010080830135818301525092915050565b5f610120828403121561324b575f80fd5b61130c8383613199565b5f60208284031215613265575f80fd5b813567ffffffffffffffff81111561327b575f80fd5b613287848285016130cf565b949350505050565b5f5b838110156132a9578181015183820152602001613291565b50505f910152565b5f81518084526132c881602086016020860161328f565b601f01601f19169290920160200192915050565b602081526132f360208201835163ffffffff169052565b5f602083015161330b604084018263ffffffff169052565b5060408301516001600160a01b03811660608401525060608301516001600160a01b03811660808401525060808301516001600160a01b03811660a08401525060a08301516001600160a01b03811660c08401525060c083015160e08381019190915283015161010080840191909152830151610120808401919091528301516101408084019190915283015161016080840191909152830151610180808401919091528301516101a06133c9818501836001600160a01b03169052565b8401516101c0848101919091528401516101e08085015290506132876102008401826132b1565b608081016133fe8287612ea4565b64ffffffffff8516602083015265ffffffffffff841660408301526001600160a01b038316606083015295945050505050565b5f8060408385031215613442575f80fd5b823567ffffffffffffffff811115613458575f80fd5b613464858286016130cf565b95602094909401359450505050565b5f8060408385031215613484575f80fd5b50508035926020909101359150565b815163ffffffff168152610180810160208301516134b9602084018263ffffffff169052565b5060408301516134d460408401826001600160a01b03169052565b5060608301516134ef60608401826001600160a01b03169052565b50608083015161350a60808401826001600160a01b03169052565b5060a083015161352560a08401826001600160a01b03169052565b5060c083015160c083015260e083015160e08301526101008084015181840152506101208084015161355a8285018215159052565b5050610140838101519083015261016092830151929091019190915290565b5f80610140838503121561358b575f80fd5b6135958484613199565b915061012083013567ffffffffffffffff808211156135b2575f80fd5b9084019060a082870312156135c5575f80fd5b6135cd61300c565b82356135d881612eeb565b8152602083810135908201526040830135828111156135f5575f80fd5b613601888286016130cf565b60408301525060608301356060820152608083013582811115613622575f80fd5b61362e888286016130cf565b6080830152508093505050509250929050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b80820180821115610aba57610aba613641565b805161185681613165565b805161185681612eeb565b5f82601f8301126136a6575f80fd5b81516136b46130ec826130a8565b8181528460208386010111156136c8575f80fd5b61328782602083016020870161328f565b5f602082840312156136e9575f80fd5b815167ffffffffffffffff80821115613700575f80fd5b908301906101e08286031215613714575f80fd5b61371c61302f565b61372583613681565b815261373360208401613681565b60208201526137446040840161368c565b60408201526137556060840161368c565b60608201526137666080840161368c565b608082015261377760a0840161368c565b60a082015260c0838101519082015260e0808401519082015261010080840151908201526101208084015190820152610140808401519082015261016080840151908201526101806137ca81850161368c565b908201526101a083810151908201526101c080840151838111156137ec575f80fd5b6137f888828701613697565b918301919091525095945050505050565b602081525f61130c60208301846132b1565b805161185681613181565b5f6101808284031215613837575f80fd5b61383f613053565b61384883613681565b815261385660208401613681565b60208201526138676040840161368c565b60408201526138786060840161368c565b60608201526138896080840161368c565b608082015261389a60a0840161368c565b60a082015260c083015160c082015260e083015160e08201526101008084015181830152506101206138cd81850161381b565b908201526101408381015190820152610160928301519281019290925250919050565b8082018281125f83128015821682158216171561390f5761390f613641565b505092915050565b8082028115828204841417610aba57610aba613641565b5f82613961577f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b500490565b81810381811115610aba57610aba613641565b5f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82036139a9576139a9613641565b5060010190565b60e081525f6139c260e083018a6132b1565b63ffffffff989098166020830152506001600160a01b039586166040820152939094166060840152608083019190915260a082015290151560c090910152919050565b6001600160a01b0384168152826020820152606060408201525f613a2c60608301846132b1565b95945050505050565b80516020808301519190811015613a74577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8160200360031b1b821691505b50919050565b5f60208284031215613a8a575f80fd5b5051919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b5f60208284031215613ace575f80fd5b815161130c81613181565b5f8251613aea81846020870161328f565b9190910192915050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603160045260245ffdfea264697066735822122007a09ea15c5efbb28f239593161aeb6ee596d67bad8a87d0cd46703d115a053164736f6c63430008180033", +} + +// FastBridgeV2ABI is the input ABI used to generate the binding from. +// Deprecated: Use FastBridgeV2MetaData.ABI instead. +var FastBridgeV2ABI = FastBridgeV2MetaData.ABI + +// Deprecated: Use FastBridgeV2MetaData.Sigs instead. +// FastBridgeV2FuncSigs maps the 4-byte function signature to its string representation. +var FastBridgeV2FuncSigs = FastBridgeV2MetaData.Sigs + +// FastBridgeV2Bin is the compiled bytecode used for deploying new contracts. +// Deprecated: Use FastBridgeV2MetaData.Bin instead. +var FastBridgeV2Bin = FastBridgeV2MetaData.Bin + +// DeployFastBridgeV2 deploys a new Ethereum contract, binding an instance of FastBridgeV2 to it. +func DeployFastBridgeV2(auth *bind.TransactOpts, backend bind.ContractBackend, _owner common.Address) (common.Address, *types.Transaction, *FastBridgeV2, error) { + parsed, err := FastBridgeV2MetaData.GetAbi() + if err != nil { + return common.Address{}, nil, nil, err + } + if parsed == nil { + return common.Address{}, nil, nil, errors.New("GetABI returned nil") + } + + address, tx, contract, err := bind.DeployContract(auth, *parsed, common.FromHex(FastBridgeV2Bin), backend, _owner) + if err != nil { + return common.Address{}, nil, nil, err + } + return address, tx, &FastBridgeV2{FastBridgeV2Caller: FastBridgeV2Caller{contract: contract}, FastBridgeV2Transactor: FastBridgeV2Transactor{contract: contract}, FastBridgeV2Filterer: FastBridgeV2Filterer{contract: contract}}, nil +} + +// FastBridgeV2 is an auto generated Go binding around an Ethereum contract. +type FastBridgeV2 struct { + FastBridgeV2Caller // Read-only binding to the contract + FastBridgeV2Transactor // Write-only binding to the contract + FastBridgeV2Filterer // Log filterer for contract events +} + +// FastBridgeV2Caller is an auto generated read-only Go binding around an Ethereum contract. +type FastBridgeV2Caller struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// FastBridgeV2Transactor is an auto generated write-only Go binding around an Ethereum contract. +type FastBridgeV2Transactor struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// FastBridgeV2Filterer is an auto generated log filtering Go binding around an Ethereum contract events. +type FastBridgeV2Filterer struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// FastBridgeV2Session is an auto generated Go binding around an Ethereum contract, +// with pre-set call and transact options. +type FastBridgeV2Session struct { + Contract *FastBridgeV2 // Generic contract binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// FastBridgeV2CallerSession is an auto generated read-only Go binding around an Ethereum contract, +// with pre-set call options. +type FastBridgeV2CallerSession struct { + Contract *FastBridgeV2Caller // Generic contract caller binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session +} + +// FastBridgeV2TransactorSession is an auto generated write-only Go binding around an Ethereum contract, +// with pre-set transact options. +type FastBridgeV2TransactorSession struct { + Contract *FastBridgeV2Transactor // Generic contract transactor binding to set the session for + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// FastBridgeV2Raw is an auto generated low-level Go binding around an Ethereum contract. +type FastBridgeV2Raw struct { + Contract *FastBridgeV2 // Generic contract binding to access the raw methods on +} + +// FastBridgeV2CallerRaw is an auto generated low-level read-only Go binding around an Ethereum contract. +type FastBridgeV2CallerRaw struct { + Contract *FastBridgeV2Caller // Generic read-only contract binding to access the raw methods on +} + +// FastBridgeV2TransactorRaw is an auto generated low-level write-only Go binding around an Ethereum contract. +type FastBridgeV2TransactorRaw struct { + Contract *FastBridgeV2Transactor // Generic write-only contract binding to access the raw methods on +} + +// NewFastBridgeV2 creates a new instance of FastBridgeV2, bound to a specific deployed contract. +func NewFastBridgeV2(address common.Address, backend bind.ContractBackend) (*FastBridgeV2, error) { + contract, err := bindFastBridgeV2(address, backend, backend, backend) + if err != nil { + return nil, err + } + return &FastBridgeV2{FastBridgeV2Caller: FastBridgeV2Caller{contract: contract}, FastBridgeV2Transactor: FastBridgeV2Transactor{contract: contract}, FastBridgeV2Filterer: FastBridgeV2Filterer{contract: contract}}, nil +} + +// NewFastBridgeV2Caller creates a new read-only instance of FastBridgeV2, bound to a specific deployed contract. +func NewFastBridgeV2Caller(address common.Address, caller bind.ContractCaller) (*FastBridgeV2Caller, error) { + contract, err := bindFastBridgeV2(address, caller, nil, nil) + if err != nil { + return nil, err + } + return &FastBridgeV2Caller{contract: contract}, nil +} + +// NewFastBridgeV2Transactor creates a new write-only instance of FastBridgeV2, bound to a specific deployed contract. +func NewFastBridgeV2Transactor(address common.Address, transactor bind.ContractTransactor) (*FastBridgeV2Transactor, error) { + contract, err := bindFastBridgeV2(address, nil, transactor, nil) + if err != nil { + return nil, err + } + return &FastBridgeV2Transactor{contract: contract}, nil +} + +// NewFastBridgeV2Filterer creates a new log filterer instance of FastBridgeV2, bound to a specific deployed contract. +func NewFastBridgeV2Filterer(address common.Address, filterer bind.ContractFilterer) (*FastBridgeV2Filterer, error) { + contract, err := bindFastBridgeV2(address, nil, nil, filterer) + if err != nil { + return nil, err + } + return &FastBridgeV2Filterer{contract: contract}, nil +} + +// bindFastBridgeV2 binds a generic wrapper to an already deployed contract. +func bindFastBridgeV2(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) { + parsed, err := FastBridgeV2MetaData.GetAbi() + if err != nil { + return nil, err + } + return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil +} + +// Call invokes the (constant) contract method with params as input values and +// sets the output to result. The result type might be a single field for simple +// returns, a slice of interfaces for anonymous returns and a struct for named +// returns. +func (_FastBridgeV2 *FastBridgeV2Raw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _FastBridgeV2.Contract.FastBridgeV2Caller.contract.Call(opts, result, method, params...) +} + +// Transfer initiates a plain transaction to move funds to the contract, calling +// its default method if one is available. +func (_FastBridgeV2 *FastBridgeV2Raw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _FastBridgeV2.Contract.FastBridgeV2Transactor.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_FastBridgeV2 *FastBridgeV2Raw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _FastBridgeV2.Contract.FastBridgeV2Transactor.contract.Transact(opts, method, params...) +} + +// Call invokes the (constant) contract method with params as input values and +// sets the output to result. The result type might be a single field for simple +// returns, a slice of interfaces for anonymous returns and a struct for named +// returns. +func (_FastBridgeV2 *FastBridgeV2CallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _FastBridgeV2.Contract.contract.Call(opts, result, method, params...) +} + +// Transfer initiates a plain transaction to move funds to the contract, calling +// its default method if one is available. +func (_FastBridgeV2 *FastBridgeV2TransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _FastBridgeV2.Contract.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_FastBridgeV2 *FastBridgeV2TransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _FastBridgeV2.Contract.contract.Transact(opts, method, params...) +} + +// DEFAULTADMINROLE is a free data retrieval call binding the contract method 0xa217fddf. +// +// Solidity: function DEFAULT_ADMIN_ROLE() view returns(bytes32) +func (_FastBridgeV2 *FastBridgeV2Caller) DEFAULTADMINROLE(opts *bind.CallOpts) ([32]byte, error) { + var out []interface{} + err := _FastBridgeV2.contract.Call(opts, &out, "DEFAULT_ADMIN_ROLE") + + if err != nil { + return *new([32]byte), err + } + + out0 := *abi.ConvertType(out[0], new([32]byte)).(*[32]byte) + + return out0, err + +} + +// DEFAULTADMINROLE is a free data retrieval call binding the contract method 0xa217fddf. +// +// Solidity: function DEFAULT_ADMIN_ROLE() view returns(bytes32) +func (_FastBridgeV2 *FastBridgeV2Session) DEFAULTADMINROLE() ([32]byte, error) { + return _FastBridgeV2.Contract.DEFAULTADMINROLE(&_FastBridgeV2.CallOpts) +} + +// DEFAULTADMINROLE is a free data retrieval call binding the contract method 0xa217fddf. +// +// Solidity: function DEFAULT_ADMIN_ROLE() view returns(bytes32) +func (_FastBridgeV2 *FastBridgeV2CallerSession) DEFAULTADMINROLE() ([32]byte, error) { + return _FastBridgeV2.Contract.DEFAULTADMINROLE(&_FastBridgeV2.CallOpts) +} + +// DISPUTEPERIOD is a free data retrieval call binding the contract method 0xa5bbe22b. +// +// Solidity: function DISPUTE_PERIOD() view returns(uint256) +func (_FastBridgeV2 *FastBridgeV2Caller) DISPUTEPERIOD(opts *bind.CallOpts) (*big.Int, error) { + var out []interface{} + err := _FastBridgeV2.contract.Call(opts, &out, "DISPUTE_PERIOD") + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// DISPUTEPERIOD is a free data retrieval call binding the contract method 0xa5bbe22b. +// +// Solidity: function DISPUTE_PERIOD() view returns(uint256) +func (_FastBridgeV2 *FastBridgeV2Session) DISPUTEPERIOD() (*big.Int, error) { + return _FastBridgeV2.Contract.DISPUTEPERIOD(&_FastBridgeV2.CallOpts) +} + +// DISPUTEPERIOD is a free data retrieval call binding the contract method 0xa5bbe22b. +// +// Solidity: function DISPUTE_PERIOD() view returns(uint256) +func (_FastBridgeV2 *FastBridgeV2CallerSession) DISPUTEPERIOD() (*big.Int, error) { + return _FastBridgeV2.Contract.DISPUTEPERIOD(&_FastBridgeV2.CallOpts) +} + +// FEEBPS is a free data retrieval call binding the contract method 0xbf333f2c. +// +// Solidity: function FEE_BPS() view returns(uint256) +func (_FastBridgeV2 *FastBridgeV2Caller) FEEBPS(opts *bind.CallOpts) (*big.Int, error) { + var out []interface{} + err := _FastBridgeV2.contract.Call(opts, &out, "FEE_BPS") + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// FEEBPS is a free data retrieval call binding the contract method 0xbf333f2c. +// +// Solidity: function FEE_BPS() view returns(uint256) +func (_FastBridgeV2 *FastBridgeV2Session) FEEBPS() (*big.Int, error) { + return _FastBridgeV2.Contract.FEEBPS(&_FastBridgeV2.CallOpts) +} + +// FEEBPS is a free data retrieval call binding the contract method 0xbf333f2c. +// +// Solidity: function FEE_BPS() view returns(uint256) +func (_FastBridgeV2 *FastBridgeV2CallerSession) FEEBPS() (*big.Int, error) { + return _FastBridgeV2.Contract.FEEBPS(&_FastBridgeV2.CallOpts) +} + +// FEERATEMAX is a free data retrieval call binding the contract method 0x0f5f6ed7. +// +// Solidity: function FEE_RATE_MAX() view returns(uint256) +func (_FastBridgeV2 *FastBridgeV2Caller) FEERATEMAX(opts *bind.CallOpts) (*big.Int, error) { + var out []interface{} + err := _FastBridgeV2.contract.Call(opts, &out, "FEE_RATE_MAX") + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// FEERATEMAX is a free data retrieval call binding the contract method 0x0f5f6ed7. +// +// Solidity: function FEE_RATE_MAX() view returns(uint256) +func (_FastBridgeV2 *FastBridgeV2Session) FEERATEMAX() (*big.Int, error) { + return _FastBridgeV2.Contract.FEERATEMAX(&_FastBridgeV2.CallOpts) +} + +// FEERATEMAX is a free data retrieval call binding the contract method 0x0f5f6ed7. +// +// Solidity: function FEE_RATE_MAX() view returns(uint256) +func (_FastBridgeV2 *FastBridgeV2CallerSession) FEERATEMAX() (*big.Int, error) { + return _FastBridgeV2.Contract.FEERATEMAX(&_FastBridgeV2.CallOpts) +} + +// GOVERNORROLE is a free data retrieval call binding the contract method 0xccc57490. +// +// Solidity: function GOVERNOR_ROLE() view returns(bytes32) +func (_FastBridgeV2 *FastBridgeV2Caller) GOVERNORROLE(opts *bind.CallOpts) ([32]byte, error) { + var out []interface{} + err := _FastBridgeV2.contract.Call(opts, &out, "GOVERNOR_ROLE") + + if err != nil { + return *new([32]byte), err + } + + out0 := *abi.ConvertType(out[0], new([32]byte)).(*[32]byte) + + return out0, err + +} + +// GOVERNORROLE is a free data retrieval call binding the contract method 0xccc57490. +// +// Solidity: function GOVERNOR_ROLE() view returns(bytes32) +func (_FastBridgeV2 *FastBridgeV2Session) GOVERNORROLE() ([32]byte, error) { + return _FastBridgeV2.Contract.GOVERNORROLE(&_FastBridgeV2.CallOpts) +} + +// GOVERNORROLE is a free data retrieval call binding the contract method 0xccc57490. +// +// Solidity: function GOVERNOR_ROLE() view returns(bytes32) +func (_FastBridgeV2 *FastBridgeV2CallerSession) GOVERNORROLE() ([32]byte, error) { + return _FastBridgeV2.Contract.GOVERNORROLE(&_FastBridgeV2.CallOpts) +} + +// GUARDROLE is a free data retrieval call binding the contract method 0x03ed0ee5. +// +// Solidity: function GUARD_ROLE() view returns(bytes32) +func (_FastBridgeV2 *FastBridgeV2Caller) GUARDROLE(opts *bind.CallOpts) ([32]byte, error) { + var out []interface{} + err := _FastBridgeV2.contract.Call(opts, &out, "GUARD_ROLE") + + if err != nil { + return *new([32]byte), err + } + + out0 := *abi.ConvertType(out[0], new([32]byte)).(*[32]byte) + + return out0, err + +} + +// GUARDROLE is a free data retrieval call binding the contract method 0x03ed0ee5. +// +// Solidity: function GUARD_ROLE() view returns(bytes32) +func (_FastBridgeV2 *FastBridgeV2Session) GUARDROLE() ([32]byte, error) { + return _FastBridgeV2.Contract.GUARDROLE(&_FastBridgeV2.CallOpts) +} + +// GUARDROLE is a free data retrieval call binding the contract method 0x03ed0ee5. +// +// Solidity: function GUARD_ROLE() view returns(bytes32) +func (_FastBridgeV2 *FastBridgeV2CallerSession) GUARDROLE() ([32]byte, error) { + return _FastBridgeV2.Contract.GUARDROLE(&_FastBridgeV2.CallOpts) +} + +// MAXCALLPARAMSLENGTH is a free data retrieval call binding the contract method 0xdf36bb13. +// +// Solidity: function MAX_CALL_PARAMS_LENGTH() view returns(uint256) +func (_FastBridgeV2 *FastBridgeV2Caller) MAXCALLPARAMSLENGTH(opts *bind.CallOpts) (*big.Int, error) { + var out []interface{} + err := _FastBridgeV2.contract.Call(opts, &out, "MAX_CALL_PARAMS_LENGTH") + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// MAXCALLPARAMSLENGTH is a free data retrieval call binding the contract method 0xdf36bb13. +// +// Solidity: function MAX_CALL_PARAMS_LENGTH() view returns(uint256) +func (_FastBridgeV2 *FastBridgeV2Session) MAXCALLPARAMSLENGTH() (*big.Int, error) { + return _FastBridgeV2.Contract.MAXCALLPARAMSLENGTH(&_FastBridgeV2.CallOpts) +} + +// MAXCALLPARAMSLENGTH is a free data retrieval call binding the contract method 0xdf36bb13. +// +// Solidity: function MAX_CALL_PARAMS_LENGTH() view returns(uint256) +func (_FastBridgeV2 *FastBridgeV2CallerSession) MAXCALLPARAMSLENGTH() (*big.Int, error) { + return _FastBridgeV2.Contract.MAXCALLPARAMSLENGTH(&_FastBridgeV2.CallOpts) +} + +// MINDEADLINEPERIOD is a free data retrieval call binding the contract method 0x820688d5. +// +// Solidity: function MIN_DEADLINE_PERIOD() view returns(uint256) +func (_FastBridgeV2 *FastBridgeV2Caller) MINDEADLINEPERIOD(opts *bind.CallOpts) (*big.Int, error) { + var out []interface{} + err := _FastBridgeV2.contract.Call(opts, &out, "MIN_DEADLINE_PERIOD") + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// MINDEADLINEPERIOD is a free data retrieval call binding the contract method 0x820688d5. +// +// Solidity: function MIN_DEADLINE_PERIOD() view returns(uint256) +func (_FastBridgeV2 *FastBridgeV2Session) MINDEADLINEPERIOD() (*big.Int, error) { + return _FastBridgeV2.Contract.MINDEADLINEPERIOD(&_FastBridgeV2.CallOpts) +} + +// MINDEADLINEPERIOD is a free data retrieval call binding the contract method 0x820688d5. +// +// Solidity: function MIN_DEADLINE_PERIOD() view returns(uint256) +func (_FastBridgeV2 *FastBridgeV2CallerSession) MINDEADLINEPERIOD() (*big.Int, error) { + return _FastBridgeV2.Contract.MINDEADLINEPERIOD(&_FastBridgeV2.CallOpts) +} + +// REFUNDERROLE is a free data retrieval call binding the contract method 0x5960ccf2. +// +// Solidity: function REFUNDER_ROLE() view returns(bytes32) +func (_FastBridgeV2 *FastBridgeV2Caller) REFUNDERROLE(opts *bind.CallOpts) ([32]byte, error) { + var out []interface{} + err := _FastBridgeV2.contract.Call(opts, &out, "REFUNDER_ROLE") + + if err != nil { + return *new([32]byte), err + } + + out0 := *abi.ConvertType(out[0], new([32]byte)).(*[32]byte) + + return out0, err + +} + +// REFUNDERROLE is a free data retrieval call binding the contract method 0x5960ccf2. +// +// Solidity: function REFUNDER_ROLE() view returns(bytes32) +func (_FastBridgeV2 *FastBridgeV2Session) REFUNDERROLE() ([32]byte, error) { + return _FastBridgeV2.Contract.REFUNDERROLE(&_FastBridgeV2.CallOpts) +} + +// REFUNDERROLE is a free data retrieval call binding the contract method 0x5960ccf2. +// +// Solidity: function REFUNDER_ROLE() view returns(bytes32) +func (_FastBridgeV2 *FastBridgeV2CallerSession) REFUNDERROLE() ([32]byte, error) { + return _FastBridgeV2.Contract.REFUNDERROLE(&_FastBridgeV2.CallOpts) +} + +// REFUNDDELAY is a free data retrieval call binding the contract method 0x190da595. +// +// Solidity: function REFUND_DELAY() view returns(uint256) +func (_FastBridgeV2 *FastBridgeV2Caller) REFUNDDELAY(opts *bind.CallOpts) (*big.Int, error) { + var out []interface{} + err := _FastBridgeV2.contract.Call(opts, &out, "REFUND_DELAY") + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// REFUNDDELAY is a free data retrieval call binding the contract method 0x190da595. +// +// Solidity: function REFUND_DELAY() view returns(uint256) +func (_FastBridgeV2 *FastBridgeV2Session) REFUNDDELAY() (*big.Int, error) { + return _FastBridgeV2.Contract.REFUNDDELAY(&_FastBridgeV2.CallOpts) +} + +// REFUNDDELAY is a free data retrieval call binding the contract method 0x190da595. +// +// Solidity: function REFUND_DELAY() view returns(uint256) +func (_FastBridgeV2 *FastBridgeV2CallerSession) REFUNDDELAY() (*big.Int, error) { + return _FastBridgeV2.Contract.REFUNDDELAY(&_FastBridgeV2.CallOpts) +} + +// RELAYERROLE is a free data retrieval call binding the contract method 0x926d7d7f. +// +// Solidity: function RELAYER_ROLE() view returns(bytes32) +func (_FastBridgeV2 *FastBridgeV2Caller) RELAYERROLE(opts *bind.CallOpts) ([32]byte, error) { + var out []interface{} + err := _FastBridgeV2.contract.Call(opts, &out, "RELAYER_ROLE") + + if err != nil { + return *new([32]byte), err + } + + out0 := *abi.ConvertType(out[0], new([32]byte)).(*[32]byte) + + return out0, err + +} + +// RELAYERROLE is a free data retrieval call binding the contract method 0x926d7d7f. +// +// Solidity: function RELAYER_ROLE() view returns(bytes32) +func (_FastBridgeV2 *FastBridgeV2Session) RELAYERROLE() ([32]byte, error) { + return _FastBridgeV2.Contract.RELAYERROLE(&_FastBridgeV2.CallOpts) +} + +// RELAYERROLE is a free data retrieval call binding the contract method 0x926d7d7f. +// +// Solidity: function RELAYER_ROLE() view returns(bytes32) +func (_FastBridgeV2 *FastBridgeV2CallerSession) RELAYERROLE() ([32]byte, error) { + return _FastBridgeV2.Contract.RELAYERROLE(&_FastBridgeV2.CallOpts) +} + +// BridgeProofs is a free data retrieval call binding the contract method 0x91ad5039. +// +// Solidity: function bridgeProofs(bytes32 transactionId) view returns(uint96 timestamp, address relayer) +func (_FastBridgeV2 *FastBridgeV2Caller) BridgeProofs(opts *bind.CallOpts, transactionId [32]byte) (struct { + Timestamp *big.Int + Relayer common.Address +}, error) { + var out []interface{} + err := _FastBridgeV2.contract.Call(opts, &out, "bridgeProofs", transactionId) + + outstruct := new(struct { + Timestamp *big.Int + Relayer common.Address + }) + if err != nil { + return *outstruct, err + } + + outstruct.Timestamp = *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + outstruct.Relayer = *abi.ConvertType(out[1], new(common.Address)).(*common.Address) + + return *outstruct, err + +} + +// BridgeProofs is a free data retrieval call binding the contract method 0x91ad5039. +// +// Solidity: function bridgeProofs(bytes32 transactionId) view returns(uint96 timestamp, address relayer) +func (_FastBridgeV2 *FastBridgeV2Session) BridgeProofs(transactionId [32]byte) (struct { + Timestamp *big.Int + Relayer common.Address +}, error) { + return _FastBridgeV2.Contract.BridgeProofs(&_FastBridgeV2.CallOpts, transactionId) +} + +// BridgeProofs is a free data retrieval call binding the contract method 0x91ad5039. +// +// Solidity: function bridgeProofs(bytes32 transactionId) view returns(uint96 timestamp, address relayer) +func (_FastBridgeV2 *FastBridgeV2CallerSession) BridgeProofs(transactionId [32]byte) (struct { + Timestamp *big.Int + Relayer common.Address +}, error) { + return _FastBridgeV2.Contract.BridgeProofs(&_FastBridgeV2.CallOpts, transactionId) +} + +// BridgeRelayDetails is a free data retrieval call binding the contract method 0xc79371b1. +// +// Solidity: function bridgeRelayDetails(bytes32 ) view returns(uint48 blockNumber, uint48 blockTimestamp, address relayer) +func (_FastBridgeV2 *FastBridgeV2Caller) BridgeRelayDetails(opts *bind.CallOpts, arg0 [32]byte) (struct { + BlockNumber *big.Int + BlockTimestamp *big.Int + Relayer common.Address +}, error) { + var out []interface{} + err := _FastBridgeV2.contract.Call(opts, &out, "bridgeRelayDetails", arg0) + + outstruct := new(struct { + BlockNumber *big.Int + BlockTimestamp *big.Int + Relayer common.Address + }) + if err != nil { + return *outstruct, err + } + + outstruct.BlockNumber = *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + outstruct.BlockTimestamp = *abi.ConvertType(out[1], new(*big.Int)).(**big.Int) + outstruct.Relayer = *abi.ConvertType(out[2], new(common.Address)).(*common.Address) + + return *outstruct, err + +} + +// BridgeRelayDetails is a free data retrieval call binding the contract method 0xc79371b1. +// +// Solidity: function bridgeRelayDetails(bytes32 ) view returns(uint48 blockNumber, uint48 blockTimestamp, address relayer) +func (_FastBridgeV2 *FastBridgeV2Session) BridgeRelayDetails(arg0 [32]byte) (struct { + BlockNumber *big.Int + BlockTimestamp *big.Int + Relayer common.Address +}, error) { + return _FastBridgeV2.Contract.BridgeRelayDetails(&_FastBridgeV2.CallOpts, arg0) +} + +// BridgeRelayDetails is a free data retrieval call binding the contract method 0xc79371b1. +// +// Solidity: function bridgeRelayDetails(bytes32 ) view returns(uint48 blockNumber, uint48 blockTimestamp, address relayer) +func (_FastBridgeV2 *FastBridgeV2CallerSession) BridgeRelayDetails(arg0 [32]byte) (struct { + BlockNumber *big.Int + BlockTimestamp *big.Int + Relayer common.Address +}, error) { + return _FastBridgeV2.Contract.BridgeRelayDetails(&_FastBridgeV2.CallOpts, arg0) +} + +// BridgeRelays is a free data retrieval call binding the contract method 0x8379a24f. +// +// Solidity: function bridgeRelays(bytes32 transactionId) view returns(bool) +func (_FastBridgeV2 *FastBridgeV2Caller) BridgeRelays(opts *bind.CallOpts, transactionId [32]byte) (bool, error) { + var out []interface{} + err := _FastBridgeV2.contract.Call(opts, &out, "bridgeRelays", transactionId) + + if err != nil { + return *new(bool), err + } + + out0 := *abi.ConvertType(out[0], new(bool)).(*bool) + + return out0, err + +} + +// BridgeRelays is a free data retrieval call binding the contract method 0x8379a24f. +// +// Solidity: function bridgeRelays(bytes32 transactionId) view returns(bool) +func (_FastBridgeV2 *FastBridgeV2Session) BridgeRelays(transactionId [32]byte) (bool, error) { + return _FastBridgeV2.Contract.BridgeRelays(&_FastBridgeV2.CallOpts, transactionId) +} + +// BridgeRelays is a free data retrieval call binding the contract method 0x8379a24f. +// +// Solidity: function bridgeRelays(bytes32 transactionId) view returns(bool) +func (_FastBridgeV2 *FastBridgeV2CallerSession) BridgeRelays(transactionId [32]byte) (bool, error) { + return _FastBridgeV2.Contract.BridgeRelays(&_FastBridgeV2.CallOpts, transactionId) +} + +// BridgeStatuses is a free data retrieval call binding the contract method 0x051287bc. +// +// Solidity: function bridgeStatuses(bytes32 transactionId) view returns(uint8 status) +func (_FastBridgeV2 *FastBridgeV2Caller) BridgeStatuses(opts *bind.CallOpts, transactionId [32]byte) (uint8, error) { + var out []interface{} + err := _FastBridgeV2.contract.Call(opts, &out, "bridgeStatuses", transactionId) + + if err != nil { + return *new(uint8), err + } + + out0 := *abi.ConvertType(out[0], new(uint8)).(*uint8) + + return out0, err + +} + +// BridgeStatuses is a free data retrieval call binding the contract method 0x051287bc. +// +// Solidity: function bridgeStatuses(bytes32 transactionId) view returns(uint8 status) +func (_FastBridgeV2 *FastBridgeV2Session) BridgeStatuses(transactionId [32]byte) (uint8, error) { + return _FastBridgeV2.Contract.BridgeStatuses(&_FastBridgeV2.CallOpts, transactionId) +} + +// BridgeStatuses is a free data retrieval call binding the contract method 0x051287bc. +// +// Solidity: function bridgeStatuses(bytes32 transactionId) view returns(uint8 status) +func (_FastBridgeV2 *FastBridgeV2CallerSession) BridgeStatuses(transactionId [32]byte) (uint8, error) { + return _FastBridgeV2.Contract.BridgeStatuses(&_FastBridgeV2.CallOpts, transactionId) +} + +// BridgeTxDetails is a free data retrieval call binding the contract method 0x63787e52. +// +// Solidity: function bridgeTxDetails(bytes32 ) view returns(uint8 status, uint40 proofBlockTimestamp, uint48 proofBlockNumber, address proofRelayer) +func (_FastBridgeV2 *FastBridgeV2Caller) BridgeTxDetails(opts *bind.CallOpts, arg0 [32]byte) (struct { + Status uint8 + ProofBlockTimestamp *big.Int + ProofBlockNumber *big.Int + ProofRelayer common.Address +}, error) { + var out []interface{} + err := _FastBridgeV2.contract.Call(opts, &out, "bridgeTxDetails", arg0) + + outstruct := new(struct { + Status uint8 + ProofBlockTimestamp *big.Int + ProofBlockNumber *big.Int + ProofRelayer common.Address + }) + if err != nil { + return *outstruct, err + } + + outstruct.Status = *abi.ConvertType(out[0], new(uint8)).(*uint8) + outstruct.ProofBlockTimestamp = *abi.ConvertType(out[1], new(*big.Int)).(**big.Int) + outstruct.ProofBlockNumber = *abi.ConvertType(out[2], new(*big.Int)).(**big.Int) + outstruct.ProofRelayer = *abi.ConvertType(out[3], new(common.Address)).(*common.Address) + + return *outstruct, err + +} + +// BridgeTxDetails is a free data retrieval call binding the contract method 0x63787e52. +// +// Solidity: function bridgeTxDetails(bytes32 ) view returns(uint8 status, uint40 proofBlockTimestamp, uint48 proofBlockNumber, address proofRelayer) +func (_FastBridgeV2 *FastBridgeV2Session) BridgeTxDetails(arg0 [32]byte) (struct { + Status uint8 + ProofBlockTimestamp *big.Int + ProofBlockNumber *big.Int + ProofRelayer common.Address +}, error) { + return _FastBridgeV2.Contract.BridgeTxDetails(&_FastBridgeV2.CallOpts, arg0) +} + +// BridgeTxDetails is a free data retrieval call binding the contract method 0x63787e52. +// +// Solidity: function bridgeTxDetails(bytes32 ) view returns(uint8 status, uint40 proofBlockTimestamp, uint48 proofBlockNumber, address proofRelayer) +func (_FastBridgeV2 *FastBridgeV2CallerSession) BridgeTxDetails(arg0 [32]byte) (struct { + Status uint8 + ProofBlockTimestamp *big.Int + ProofBlockNumber *big.Int + ProofRelayer common.Address +}, error) { + return _FastBridgeV2.Contract.BridgeTxDetails(&_FastBridgeV2.CallOpts, arg0) +} + +// CanClaim is a free data retrieval call binding the contract method 0xaa9641ab. +// +// Solidity: function canClaim(bytes32 transactionId, address relayer) view returns(bool) +func (_FastBridgeV2 *FastBridgeV2Caller) CanClaim(opts *bind.CallOpts, transactionId [32]byte, relayer common.Address) (bool, error) { + var out []interface{} + err := _FastBridgeV2.contract.Call(opts, &out, "canClaim", transactionId, relayer) + + if err != nil { + return *new(bool), err + } + + out0 := *abi.ConvertType(out[0], new(bool)).(*bool) + + return out0, err + +} + +// CanClaim is a free data retrieval call binding the contract method 0xaa9641ab. +// +// Solidity: function canClaim(bytes32 transactionId, address relayer) view returns(bool) +func (_FastBridgeV2 *FastBridgeV2Session) CanClaim(transactionId [32]byte, relayer common.Address) (bool, error) { + return _FastBridgeV2.Contract.CanClaim(&_FastBridgeV2.CallOpts, transactionId, relayer) +} + +// CanClaim is a free data retrieval call binding the contract method 0xaa9641ab. +// +// Solidity: function canClaim(bytes32 transactionId, address relayer) view returns(bool) +func (_FastBridgeV2 *FastBridgeV2CallerSession) CanClaim(transactionId [32]byte, relayer common.Address) (bool, error) { + return _FastBridgeV2.Contract.CanClaim(&_FastBridgeV2.CallOpts, transactionId, relayer) +} + +// ChainGasAmount is a free data retrieval call binding the contract method 0xe00a83e0. +// +// Solidity: function chainGasAmount() view returns(uint256) +func (_FastBridgeV2 *FastBridgeV2Caller) ChainGasAmount(opts *bind.CallOpts) (*big.Int, error) { + var out []interface{} + err := _FastBridgeV2.contract.Call(opts, &out, "chainGasAmount") + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// ChainGasAmount is a free data retrieval call binding the contract method 0xe00a83e0. +// +// Solidity: function chainGasAmount() view returns(uint256) +func (_FastBridgeV2 *FastBridgeV2Session) ChainGasAmount() (*big.Int, error) { + return _FastBridgeV2.Contract.ChainGasAmount(&_FastBridgeV2.CallOpts) +} + +// ChainGasAmount is a free data retrieval call binding the contract method 0xe00a83e0. +// +// Solidity: function chainGasAmount() view returns(uint256) +func (_FastBridgeV2 *FastBridgeV2CallerSession) ChainGasAmount() (*big.Int, error) { + return _FastBridgeV2.Contract.ChainGasAmount(&_FastBridgeV2.CallOpts) +} + +// DeployBlock is a free data retrieval call binding the contract method 0xa3ec191a. +// +// Solidity: function deployBlock() view returns(uint256) +func (_FastBridgeV2 *FastBridgeV2Caller) DeployBlock(opts *bind.CallOpts) (*big.Int, error) { + var out []interface{} + err := _FastBridgeV2.contract.Call(opts, &out, "deployBlock") + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// DeployBlock is a free data retrieval call binding the contract method 0xa3ec191a. +// +// Solidity: function deployBlock() view returns(uint256) +func (_FastBridgeV2 *FastBridgeV2Session) DeployBlock() (*big.Int, error) { + return _FastBridgeV2.Contract.DeployBlock(&_FastBridgeV2.CallOpts) +} + +// DeployBlock is a free data retrieval call binding the contract method 0xa3ec191a. +// +// Solidity: function deployBlock() view returns(uint256) +func (_FastBridgeV2 *FastBridgeV2CallerSession) DeployBlock() (*big.Int, error) { + return _FastBridgeV2.Contract.DeployBlock(&_FastBridgeV2.CallOpts) +} + +// GetBridgeTransaction is a free data retrieval call binding the contract method 0xac11fb1a. +// +// Solidity: function getBridgeTransaction(bytes request) view returns((uint32,uint32,address,address,address,address,uint256,uint256,uint256,bool,uint256,uint256)) +func (_FastBridgeV2 *FastBridgeV2Caller) GetBridgeTransaction(opts *bind.CallOpts, request []byte) (IFastBridgeBridgeTransaction, error) { + var out []interface{} + err := _FastBridgeV2.contract.Call(opts, &out, "getBridgeTransaction", request) + + if err != nil { + return *new(IFastBridgeBridgeTransaction), err + } + + out0 := *abi.ConvertType(out[0], new(IFastBridgeBridgeTransaction)).(*IFastBridgeBridgeTransaction) + + return out0, err + +} + +// GetBridgeTransaction is a free data retrieval call binding the contract method 0xac11fb1a. +// +// Solidity: function getBridgeTransaction(bytes request) view returns((uint32,uint32,address,address,address,address,uint256,uint256,uint256,bool,uint256,uint256)) +func (_FastBridgeV2 *FastBridgeV2Session) GetBridgeTransaction(request []byte) (IFastBridgeBridgeTransaction, error) { + return _FastBridgeV2.Contract.GetBridgeTransaction(&_FastBridgeV2.CallOpts, request) +} + +// GetBridgeTransaction is a free data retrieval call binding the contract method 0xac11fb1a. +// +// Solidity: function getBridgeTransaction(bytes request) view returns((uint32,uint32,address,address,address,address,uint256,uint256,uint256,bool,uint256,uint256)) +func (_FastBridgeV2 *FastBridgeV2CallerSession) GetBridgeTransaction(request []byte) (IFastBridgeBridgeTransaction, error) { + return _FastBridgeV2.Contract.GetBridgeTransaction(&_FastBridgeV2.CallOpts, request) +} + +// GetBridgeTransactionV2 is a free data retrieval call binding the contract method 0x5aa6ccba. +// +// Solidity: function getBridgeTransactionV2(bytes request) pure returns((uint32,uint32,address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,address,uint256,bytes)) +func (_FastBridgeV2 *FastBridgeV2Caller) GetBridgeTransactionV2(opts *bind.CallOpts, request []byte) (IFastBridgeV2BridgeTransactionV2, error) { + var out []interface{} + err := _FastBridgeV2.contract.Call(opts, &out, "getBridgeTransactionV2", request) + + if err != nil { + return *new(IFastBridgeV2BridgeTransactionV2), err + } + + out0 := *abi.ConvertType(out[0], new(IFastBridgeV2BridgeTransactionV2)).(*IFastBridgeV2BridgeTransactionV2) + + return out0, err + +} + +// GetBridgeTransactionV2 is a free data retrieval call binding the contract method 0x5aa6ccba. +// +// Solidity: function getBridgeTransactionV2(bytes request) pure returns((uint32,uint32,address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,address,uint256,bytes)) +func (_FastBridgeV2 *FastBridgeV2Session) GetBridgeTransactionV2(request []byte) (IFastBridgeV2BridgeTransactionV2, error) { + return _FastBridgeV2.Contract.GetBridgeTransactionV2(&_FastBridgeV2.CallOpts, request) +} + +// GetBridgeTransactionV2 is a free data retrieval call binding the contract method 0x5aa6ccba. +// +// Solidity: function getBridgeTransactionV2(bytes request) pure returns((uint32,uint32,address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,address,uint256,bytes)) +func (_FastBridgeV2 *FastBridgeV2CallerSession) GetBridgeTransactionV2(request []byte) (IFastBridgeV2BridgeTransactionV2, error) { + return _FastBridgeV2.Contract.GetBridgeTransactionV2(&_FastBridgeV2.CallOpts, request) +} + +// GetRoleAdmin is a free data retrieval call binding the contract method 0x248a9ca3. +// +// Solidity: function getRoleAdmin(bytes32 role) view returns(bytes32) +func (_FastBridgeV2 *FastBridgeV2Caller) GetRoleAdmin(opts *bind.CallOpts, role [32]byte) ([32]byte, error) { + var out []interface{} + err := _FastBridgeV2.contract.Call(opts, &out, "getRoleAdmin", role) + + if err != nil { + return *new([32]byte), err + } + + out0 := *abi.ConvertType(out[0], new([32]byte)).(*[32]byte) + + return out0, err + +} + +// GetRoleAdmin is a free data retrieval call binding the contract method 0x248a9ca3. +// +// Solidity: function getRoleAdmin(bytes32 role) view returns(bytes32) +func (_FastBridgeV2 *FastBridgeV2Session) GetRoleAdmin(role [32]byte) ([32]byte, error) { + return _FastBridgeV2.Contract.GetRoleAdmin(&_FastBridgeV2.CallOpts, role) +} + +// GetRoleAdmin is a free data retrieval call binding the contract method 0x248a9ca3. +// +// Solidity: function getRoleAdmin(bytes32 role) view returns(bytes32) +func (_FastBridgeV2 *FastBridgeV2CallerSession) GetRoleAdmin(role [32]byte) ([32]byte, error) { + return _FastBridgeV2.Contract.GetRoleAdmin(&_FastBridgeV2.CallOpts, role) +} + +// GetRoleMember is a free data retrieval call binding the contract method 0x9010d07c. +// +// Solidity: function getRoleMember(bytes32 role, uint256 index) view returns(address) +func (_FastBridgeV2 *FastBridgeV2Caller) GetRoleMember(opts *bind.CallOpts, role [32]byte, index *big.Int) (common.Address, error) { + var out []interface{} + err := _FastBridgeV2.contract.Call(opts, &out, "getRoleMember", role, index) + + if err != nil { + return *new(common.Address), err + } + + out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) + + return out0, err + +} + +// GetRoleMember is a free data retrieval call binding the contract method 0x9010d07c. +// +// Solidity: function getRoleMember(bytes32 role, uint256 index) view returns(address) +func (_FastBridgeV2 *FastBridgeV2Session) GetRoleMember(role [32]byte, index *big.Int) (common.Address, error) { + return _FastBridgeV2.Contract.GetRoleMember(&_FastBridgeV2.CallOpts, role, index) +} + +// GetRoleMember is a free data retrieval call binding the contract method 0x9010d07c. +// +// Solidity: function getRoleMember(bytes32 role, uint256 index) view returns(address) +func (_FastBridgeV2 *FastBridgeV2CallerSession) GetRoleMember(role [32]byte, index *big.Int) (common.Address, error) { + return _FastBridgeV2.Contract.GetRoleMember(&_FastBridgeV2.CallOpts, role, index) +} + +// GetRoleMemberCount is a free data retrieval call binding the contract method 0xca15c873. +// +// Solidity: function getRoleMemberCount(bytes32 role) view returns(uint256) +func (_FastBridgeV2 *FastBridgeV2Caller) GetRoleMemberCount(opts *bind.CallOpts, role [32]byte) (*big.Int, error) { + var out []interface{} + err := _FastBridgeV2.contract.Call(opts, &out, "getRoleMemberCount", role) + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// GetRoleMemberCount is a free data retrieval call binding the contract method 0xca15c873. +// +// Solidity: function getRoleMemberCount(bytes32 role) view returns(uint256) +func (_FastBridgeV2 *FastBridgeV2Session) GetRoleMemberCount(role [32]byte) (*big.Int, error) { + return _FastBridgeV2.Contract.GetRoleMemberCount(&_FastBridgeV2.CallOpts, role) +} + +// GetRoleMemberCount is a free data retrieval call binding the contract method 0xca15c873. +// +// Solidity: function getRoleMemberCount(bytes32 role) view returns(uint256) +func (_FastBridgeV2 *FastBridgeV2CallerSession) GetRoleMemberCount(role [32]byte) (*big.Int, error) { + return _FastBridgeV2.Contract.GetRoleMemberCount(&_FastBridgeV2.CallOpts, role) +} + +// HasRole is a free data retrieval call binding the contract method 0x91d14854. +// +// Solidity: function hasRole(bytes32 role, address account) view returns(bool) +func (_FastBridgeV2 *FastBridgeV2Caller) HasRole(opts *bind.CallOpts, role [32]byte, account common.Address) (bool, error) { + var out []interface{} + err := _FastBridgeV2.contract.Call(opts, &out, "hasRole", role, account) + + if err != nil { + return *new(bool), err + } + + out0 := *abi.ConvertType(out[0], new(bool)).(*bool) + + return out0, err + +} + +// HasRole is a free data retrieval call binding the contract method 0x91d14854. +// +// Solidity: function hasRole(bytes32 role, address account) view returns(bool) +func (_FastBridgeV2 *FastBridgeV2Session) HasRole(role [32]byte, account common.Address) (bool, error) { + return _FastBridgeV2.Contract.HasRole(&_FastBridgeV2.CallOpts, role, account) +} + +// HasRole is a free data retrieval call binding the contract method 0x91d14854. +// +// Solidity: function hasRole(bytes32 role, address account) view returns(bool) +func (_FastBridgeV2 *FastBridgeV2CallerSession) HasRole(role [32]byte, account common.Address) (bool, error) { + return _FastBridgeV2.Contract.HasRole(&_FastBridgeV2.CallOpts, role, account) +} + +// Nonce is a free data retrieval call binding the contract method 0xaffed0e0. +// +// Solidity: function nonce() view returns(uint256) +func (_FastBridgeV2 *FastBridgeV2Caller) Nonce(opts *bind.CallOpts) (*big.Int, error) { + var out []interface{} + err := _FastBridgeV2.contract.Call(opts, &out, "nonce") + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// Nonce is a free data retrieval call binding the contract method 0xaffed0e0. +// +// Solidity: function nonce() view returns(uint256) +func (_FastBridgeV2 *FastBridgeV2Session) Nonce() (*big.Int, error) { + return _FastBridgeV2.Contract.Nonce(&_FastBridgeV2.CallOpts) +} + +// Nonce is a free data retrieval call binding the contract method 0xaffed0e0. +// +// Solidity: function nonce() view returns(uint256) +func (_FastBridgeV2 *FastBridgeV2CallerSession) Nonce() (*big.Int, error) { + return _FastBridgeV2.Contract.Nonce(&_FastBridgeV2.CallOpts) +} + +// ProtocolFeeRate is a free data retrieval call binding the contract method 0x58f85880. +// +// Solidity: function protocolFeeRate() view returns(uint256) +func (_FastBridgeV2 *FastBridgeV2Caller) ProtocolFeeRate(opts *bind.CallOpts) (*big.Int, error) { + var out []interface{} + err := _FastBridgeV2.contract.Call(opts, &out, "protocolFeeRate") + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// ProtocolFeeRate is a free data retrieval call binding the contract method 0x58f85880. +// +// Solidity: function protocolFeeRate() view returns(uint256) +func (_FastBridgeV2 *FastBridgeV2Session) ProtocolFeeRate() (*big.Int, error) { + return _FastBridgeV2.Contract.ProtocolFeeRate(&_FastBridgeV2.CallOpts) +} + +// ProtocolFeeRate is a free data retrieval call binding the contract method 0x58f85880. +// +// Solidity: function protocolFeeRate() view returns(uint256) +func (_FastBridgeV2 *FastBridgeV2CallerSession) ProtocolFeeRate() (*big.Int, error) { + return _FastBridgeV2.Contract.ProtocolFeeRate(&_FastBridgeV2.CallOpts) +} + +// ProtocolFees is a free data retrieval call binding the contract method 0xdcf844a7. +// +// Solidity: function protocolFees(address ) view returns(uint256) +func (_FastBridgeV2 *FastBridgeV2Caller) ProtocolFees(opts *bind.CallOpts, arg0 common.Address) (*big.Int, error) { + var out []interface{} + err := _FastBridgeV2.contract.Call(opts, &out, "protocolFees", arg0) + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// ProtocolFees is a free data retrieval call binding the contract method 0xdcf844a7. +// +// Solidity: function protocolFees(address ) view returns(uint256) +func (_FastBridgeV2 *FastBridgeV2Session) ProtocolFees(arg0 common.Address) (*big.Int, error) { + return _FastBridgeV2.Contract.ProtocolFees(&_FastBridgeV2.CallOpts, arg0) +} + +// ProtocolFees is a free data retrieval call binding the contract method 0xdcf844a7. +// +// Solidity: function protocolFees(address ) view returns(uint256) +func (_FastBridgeV2 *FastBridgeV2CallerSession) ProtocolFees(arg0 common.Address) (*big.Int, error) { + return _FastBridgeV2.Contract.ProtocolFees(&_FastBridgeV2.CallOpts, arg0) +} + +// SenderNonces is a free data retrieval call binding the contract method 0x295710ff. +// +// Solidity: function senderNonces(address ) view returns(uint256) +func (_FastBridgeV2 *FastBridgeV2Caller) SenderNonces(opts *bind.CallOpts, arg0 common.Address) (*big.Int, error) { + var out []interface{} + err := _FastBridgeV2.contract.Call(opts, &out, "senderNonces", arg0) + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// SenderNonces is a free data retrieval call binding the contract method 0x295710ff. +// +// Solidity: function senderNonces(address ) view returns(uint256) +func (_FastBridgeV2 *FastBridgeV2Session) SenderNonces(arg0 common.Address) (*big.Int, error) { + return _FastBridgeV2.Contract.SenderNonces(&_FastBridgeV2.CallOpts, arg0) +} + +// SenderNonces is a free data retrieval call binding the contract method 0x295710ff. +// +// Solidity: function senderNonces(address ) view returns(uint256) +func (_FastBridgeV2 *FastBridgeV2CallerSession) SenderNonces(arg0 common.Address) (*big.Int, error) { + return _FastBridgeV2.Contract.SenderNonces(&_FastBridgeV2.CallOpts, arg0) +} + +// SupportsInterface is a free data retrieval call binding the contract method 0x01ffc9a7. +// +// Solidity: function supportsInterface(bytes4 interfaceId) view returns(bool) +func (_FastBridgeV2 *FastBridgeV2Caller) SupportsInterface(opts *bind.CallOpts, interfaceId [4]byte) (bool, error) { + var out []interface{} + err := _FastBridgeV2.contract.Call(opts, &out, "supportsInterface", interfaceId) + + if err != nil { + return *new(bool), err + } + + out0 := *abi.ConvertType(out[0], new(bool)).(*bool) + + return out0, err + +} + +// SupportsInterface is a free data retrieval call binding the contract method 0x01ffc9a7. +// +// Solidity: function supportsInterface(bytes4 interfaceId) view returns(bool) +func (_FastBridgeV2 *FastBridgeV2Session) SupportsInterface(interfaceId [4]byte) (bool, error) { + return _FastBridgeV2.Contract.SupportsInterface(&_FastBridgeV2.CallOpts, interfaceId) +} + +// SupportsInterface is a free data retrieval call binding the contract method 0x01ffc9a7. +// +// Solidity: function supportsInterface(bytes4 interfaceId) view returns(bool) +func (_FastBridgeV2 *FastBridgeV2CallerSession) SupportsInterface(interfaceId [4]byte) (bool, error) { + return _FastBridgeV2.Contract.SupportsInterface(&_FastBridgeV2.CallOpts, interfaceId) +} + +// Bridge is a paid mutator transaction binding the contract method 0x45851694. +// +// Solidity: function bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256) params) payable returns() +func (_FastBridgeV2 *FastBridgeV2Transactor) Bridge(opts *bind.TransactOpts, params IFastBridgeBridgeParams) (*types.Transaction, error) { + return _FastBridgeV2.contract.Transact(opts, "bridge", params) +} + +// Bridge is a paid mutator transaction binding the contract method 0x45851694. +// +// Solidity: function bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256) params) payable returns() +func (_FastBridgeV2 *FastBridgeV2Session) Bridge(params IFastBridgeBridgeParams) (*types.Transaction, error) { + return _FastBridgeV2.Contract.Bridge(&_FastBridgeV2.TransactOpts, params) +} + +// Bridge is a paid mutator transaction binding the contract method 0x45851694. +// +// Solidity: function bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256) params) payable returns() +func (_FastBridgeV2 *FastBridgeV2TransactorSession) Bridge(params IFastBridgeBridgeParams) (*types.Transaction, error) { + return _FastBridgeV2.Contract.Bridge(&_FastBridgeV2.TransactOpts, params) +} + +// Bridge0 is a paid mutator transaction binding the contract method 0xbfc7c607. +// +// Solidity: function bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256) params, (address,int256,bytes,uint256,bytes) paramsV2) payable returns() +func (_FastBridgeV2 *FastBridgeV2Transactor) Bridge0(opts *bind.TransactOpts, params IFastBridgeBridgeParams, paramsV2 IFastBridgeV2BridgeParamsV2) (*types.Transaction, error) { + return _FastBridgeV2.contract.Transact(opts, "bridge0", params, paramsV2) +} + +// Bridge0 is a paid mutator transaction binding the contract method 0xbfc7c607. +// +// Solidity: function bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256) params, (address,int256,bytes,uint256,bytes) paramsV2) payable returns() +func (_FastBridgeV2 *FastBridgeV2Session) Bridge0(params IFastBridgeBridgeParams, paramsV2 IFastBridgeV2BridgeParamsV2) (*types.Transaction, error) { + return _FastBridgeV2.Contract.Bridge0(&_FastBridgeV2.TransactOpts, params, paramsV2) +} + +// Bridge0 is a paid mutator transaction binding the contract method 0xbfc7c607. +// +// Solidity: function bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256) params, (address,int256,bytes,uint256,bytes) paramsV2) payable returns() +func (_FastBridgeV2 *FastBridgeV2TransactorSession) Bridge0(params IFastBridgeBridgeParams, paramsV2 IFastBridgeV2BridgeParamsV2) (*types.Transaction, error) { + return _FastBridgeV2.Contract.Bridge0(&_FastBridgeV2.TransactOpts, params, paramsV2) +} + +// Claim is a paid mutator transaction binding the contract method 0x41fcb612. +// +// Solidity: function claim(bytes request, address to) returns() +func (_FastBridgeV2 *FastBridgeV2Transactor) Claim(opts *bind.TransactOpts, request []byte, to common.Address) (*types.Transaction, error) { + return _FastBridgeV2.contract.Transact(opts, "claim", request, to) +} + +// Claim is a paid mutator transaction binding the contract method 0x41fcb612. +// +// Solidity: function claim(bytes request, address to) returns() +func (_FastBridgeV2 *FastBridgeV2Session) Claim(request []byte, to common.Address) (*types.Transaction, error) { + return _FastBridgeV2.Contract.Claim(&_FastBridgeV2.TransactOpts, request, to) +} + +// Claim is a paid mutator transaction binding the contract method 0x41fcb612. +// +// Solidity: function claim(bytes request, address to) returns() +func (_FastBridgeV2 *FastBridgeV2TransactorSession) Claim(request []byte, to common.Address) (*types.Transaction, error) { + return _FastBridgeV2.Contract.Claim(&_FastBridgeV2.TransactOpts, request, to) +} + +// Claim0 is a paid mutator transaction binding the contract method 0xc63ff8dd. +// +// Solidity: function claim(bytes request) returns() +func (_FastBridgeV2 *FastBridgeV2Transactor) Claim0(opts *bind.TransactOpts, request []byte) (*types.Transaction, error) { + return _FastBridgeV2.contract.Transact(opts, "claim0", request) +} + +// Claim0 is a paid mutator transaction binding the contract method 0xc63ff8dd. +// +// Solidity: function claim(bytes request) returns() +func (_FastBridgeV2 *FastBridgeV2Session) Claim0(request []byte) (*types.Transaction, error) { + return _FastBridgeV2.Contract.Claim0(&_FastBridgeV2.TransactOpts, request) +} + +// Claim0 is a paid mutator transaction binding the contract method 0xc63ff8dd. +// +// Solidity: function claim(bytes request) returns() +func (_FastBridgeV2 *FastBridgeV2TransactorSession) Claim0(request []byte) (*types.Transaction, error) { + return _FastBridgeV2.Contract.Claim0(&_FastBridgeV2.TransactOpts, request) +} + +// Dispute is a paid mutator transaction binding the contract method 0xadd98c70. +// +// Solidity: function dispute(bytes32 transactionId) returns() +func (_FastBridgeV2 *FastBridgeV2Transactor) Dispute(opts *bind.TransactOpts, transactionId [32]byte) (*types.Transaction, error) { + return _FastBridgeV2.contract.Transact(opts, "dispute", transactionId) +} + +// Dispute is a paid mutator transaction binding the contract method 0xadd98c70. +// +// Solidity: function dispute(bytes32 transactionId) returns() +func (_FastBridgeV2 *FastBridgeV2Session) Dispute(transactionId [32]byte) (*types.Transaction, error) { + return _FastBridgeV2.Contract.Dispute(&_FastBridgeV2.TransactOpts, transactionId) +} + +// Dispute is a paid mutator transaction binding the contract method 0xadd98c70. +// +// Solidity: function dispute(bytes32 transactionId) returns() +func (_FastBridgeV2 *FastBridgeV2TransactorSession) Dispute(transactionId [32]byte) (*types.Transaction, error) { + return _FastBridgeV2.Contract.Dispute(&_FastBridgeV2.TransactOpts, transactionId) +} + +// GrantRole is a paid mutator transaction binding the contract method 0x2f2ff15d. +// +// Solidity: function grantRole(bytes32 role, address account) returns() +func (_FastBridgeV2 *FastBridgeV2Transactor) GrantRole(opts *bind.TransactOpts, role [32]byte, account common.Address) (*types.Transaction, error) { + return _FastBridgeV2.contract.Transact(opts, "grantRole", role, account) +} + +// GrantRole is a paid mutator transaction binding the contract method 0x2f2ff15d. +// +// Solidity: function grantRole(bytes32 role, address account) returns() +func (_FastBridgeV2 *FastBridgeV2Session) GrantRole(role [32]byte, account common.Address) (*types.Transaction, error) { + return _FastBridgeV2.Contract.GrantRole(&_FastBridgeV2.TransactOpts, role, account) +} + +// GrantRole is a paid mutator transaction binding the contract method 0x2f2ff15d. +// +// Solidity: function grantRole(bytes32 role, address account) returns() +func (_FastBridgeV2 *FastBridgeV2TransactorSession) GrantRole(role [32]byte, account common.Address) (*types.Transaction, error) { + return _FastBridgeV2.Contract.GrantRole(&_FastBridgeV2.TransactOpts, role, account) +} + +// Prove is a paid mutator transaction binding the contract method 0x18e4357d. +// +// Solidity: function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) returns() +func (_FastBridgeV2 *FastBridgeV2Transactor) Prove(opts *bind.TransactOpts, transactionId [32]byte, destTxHash [32]byte, relayer common.Address) (*types.Transaction, error) { + return _FastBridgeV2.contract.Transact(opts, "prove", transactionId, destTxHash, relayer) +} + +// Prove is a paid mutator transaction binding the contract method 0x18e4357d. +// +// Solidity: function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) returns() +func (_FastBridgeV2 *FastBridgeV2Session) Prove(transactionId [32]byte, destTxHash [32]byte, relayer common.Address) (*types.Transaction, error) { + return _FastBridgeV2.Contract.Prove(&_FastBridgeV2.TransactOpts, transactionId, destTxHash, relayer) +} + +// Prove is a paid mutator transaction binding the contract method 0x18e4357d. +// +// Solidity: function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) returns() +func (_FastBridgeV2 *FastBridgeV2TransactorSession) Prove(transactionId [32]byte, destTxHash [32]byte, relayer common.Address) (*types.Transaction, error) { + return _FastBridgeV2.Contract.Prove(&_FastBridgeV2.TransactOpts, transactionId, destTxHash, relayer) +} + +// Prove0 is a paid mutator transaction binding the contract method 0x886d36ff. +// +// Solidity: function prove(bytes request, bytes32 destTxHash) returns() +func (_FastBridgeV2 *FastBridgeV2Transactor) Prove0(opts *bind.TransactOpts, request []byte, destTxHash [32]byte) (*types.Transaction, error) { + return _FastBridgeV2.contract.Transact(opts, "prove0", request, destTxHash) +} + +// Prove0 is a paid mutator transaction binding the contract method 0x886d36ff. +// +// Solidity: function prove(bytes request, bytes32 destTxHash) returns() +func (_FastBridgeV2 *FastBridgeV2Session) Prove0(request []byte, destTxHash [32]byte) (*types.Transaction, error) { + return _FastBridgeV2.Contract.Prove0(&_FastBridgeV2.TransactOpts, request, destTxHash) +} + +// Prove0 is a paid mutator transaction binding the contract method 0x886d36ff. +// +// Solidity: function prove(bytes request, bytes32 destTxHash) returns() +func (_FastBridgeV2 *FastBridgeV2TransactorSession) Prove0(request []byte, destTxHash [32]byte) (*types.Transaction, error) { + return _FastBridgeV2.Contract.Prove0(&_FastBridgeV2.TransactOpts, request, destTxHash) +} + +// Refund is a paid mutator transaction binding the contract method 0x5eb7d946. +// +// Solidity: function refund(bytes request) returns() +func (_FastBridgeV2 *FastBridgeV2Transactor) Refund(opts *bind.TransactOpts, request []byte) (*types.Transaction, error) { + return _FastBridgeV2.contract.Transact(opts, "refund", request) +} + +// Refund is a paid mutator transaction binding the contract method 0x5eb7d946. +// +// Solidity: function refund(bytes request) returns() +func (_FastBridgeV2 *FastBridgeV2Session) Refund(request []byte) (*types.Transaction, error) { + return _FastBridgeV2.Contract.Refund(&_FastBridgeV2.TransactOpts, request) +} + +// Refund is a paid mutator transaction binding the contract method 0x5eb7d946. +// +// Solidity: function refund(bytes request) returns() +func (_FastBridgeV2 *FastBridgeV2TransactorSession) Refund(request []byte) (*types.Transaction, error) { + return _FastBridgeV2.Contract.Refund(&_FastBridgeV2.TransactOpts, request) +} + +// Relay is a paid mutator transaction binding the contract method 0x8f0d6f17. +// +// Solidity: function relay(bytes request) payable returns() +func (_FastBridgeV2 *FastBridgeV2Transactor) Relay(opts *bind.TransactOpts, request []byte) (*types.Transaction, error) { + return _FastBridgeV2.contract.Transact(opts, "relay", request) +} + +// Relay is a paid mutator transaction binding the contract method 0x8f0d6f17. +// +// Solidity: function relay(bytes request) payable returns() +func (_FastBridgeV2 *FastBridgeV2Session) Relay(request []byte) (*types.Transaction, error) { + return _FastBridgeV2.Contract.Relay(&_FastBridgeV2.TransactOpts, request) +} + +// Relay is a paid mutator transaction binding the contract method 0x8f0d6f17. +// +// Solidity: function relay(bytes request) payable returns() +func (_FastBridgeV2 *FastBridgeV2TransactorSession) Relay(request []byte) (*types.Transaction, error) { + return _FastBridgeV2.Contract.Relay(&_FastBridgeV2.TransactOpts, request) +} + +// Relay0 is a paid mutator transaction binding the contract method 0x9c9545f0. +// +// Solidity: function relay(bytes request, address relayer) payable returns() +func (_FastBridgeV2 *FastBridgeV2Transactor) Relay0(opts *bind.TransactOpts, request []byte, relayer common.Address) (*types.Transaction, error) { + return _FastBridgeV2.contract.Transact(opts, "relay0", request, relayer) +} + +// Relay0 is a paid mutator transaction binding the contract method 0x9c9545f0. +// +// Solidity: function relay(bytes request, address relayer) payable returns() +func (_FastBridgeV2 *FastBridgeV2Session) Relay0(request []byte, relayer common.Address) (*types.Transaction, error) { + return _FastBridgeV2.Contract.Relay0(&_FastBridgeV2.TransactOpts, request, relayer) +} + +// Relay0 is a paid mutator transaction binding the contract method 0x9c9545f0. +// +// Solidity: function relay(bytes request, address relayer) payable returns() +func (_FastBridgeV2 *FastBridgeV2TransactorSession) Relay0(request []byte, relayer common.Address) (*types.Transaction, error) { + return _FastBridgeV2.Contract.Relay0(&_FastBridgeV2.TransactOpts, request, relayer) +} + +// RenounceRole is a paid mutator transaction binding the contract method 0x36568abe. +// +// Solidity: function renounceRole(bytes32 role, address callerConfirmation) returns() +func (_FastBridgeV2 *FastBridgeV2Transactor) RenounceRole(opts *bind.TransactOpts, role [32]byte, callerConfirmation common.Address) (*types.Transaction, error) { + return _FastBridgeV2.contract.Transact(opts, "renounceRole", role, callerConfirmation) +} + +// RenounceRole is a paid mutator transaction binding the contract method 0x36568abe. +// +// Solidity: function renounceRole(bytes32 role, address callerConfirmation) returns() +func (_FastBridgeV2 *FastBridgeV2Session) RenounceRole(role [32]byte, callerConfirmation common.Address) (*types.Transaction, error) { + return _FastBridgeV2.Contract.RenounceRole(&_FastBridgeV2.TransactOpts, role, callerConfirmation) +} + +// RenounceRole is a paid mutator transaction binding the contract method 0x36568abe. +// +// Solidity: function renounceRole(bytes32 role, address callerConfirmation) returns() +func (_FastBridgeV2 *FastBridgeV2TransactorSession) RenounceRole(role [32]byte, callerConfirmation common.Address) (*types.Transaction, error) { + return _FastBridgeV2.Contract.RenounceRole(&_FastBridgeV2.TransactOpts, role, callerConfirmation) +} + +// RevokeRole is a paid mutator transaction binding the contract method 0xd547741f. +// +// Solidity: function revokeRole(bytes32 role, address account) returns() +func (_FastBridgeV2 *FastBridgeV2Transactor) RevokeRole(opts *bind.TransactOpts, role [32]byte, account common.Address) (*types.Transaction, error) { + return _FastBridgeV2.contract.Transact(opts, "revokeRole", role, account) +} + +// RevokeRole is a paid mutator transaction binding the contract method 0xd547741f. +// +// Solidity: function revokeRole(bytes32 role, address account) returns() +func (_FastBridgeV2 *FastBridgeV2Session) RevokeRole(role [32]byte, account common.Address) (*types.Transaction, error) { + return _FastBridgeV2.Contract.RevokeRole(&_FastBridgeV2.TransactOpts, role, account) +} + +// RevokeRole is a paid mutator transaction binding the contract method 0xd547741f. +// +// Solidity: function revokeRole(bytes32 role, address account) returns() +func (_FastBridgeV2 *FastBridgeV2TransactorSession) RevokeRole(role [32]byte, account common.Address) (*types.Transaction, error) { + return _FastBridgeV2.Contract.RevokeRole(&_FastBridgeV2.TransactOpts, role, account) +} + +// SetChainGasAmount is a paid mutator transaction binding the contract method 0xb250fe6b. +// +// Solidity: function setChainGasAmount(uint256 newChainGasAmount) returns() +func (_FastBridgeV2 *FastBridgeV2Transactor) SetChainGasAmount(opts *bind.TransactOpts, newChainGasAmount *big.Int) (*types.Transaction, error) { + return _FastBridgeV2.contract.Transact(opts, "setChainGasAmount", newChainGasAmount) +} + +// SetChainGasAmount is a paid mutator transaction binding the contract method 0xb250fe6b. +// +// Solidity: function setChainGasAmount(uint256 newChainGasAmount) returns() +func (_FastBridgeV2 *FastBridgeV2Session) SetChainGasAmount(newChainGasAmount *big.Int) (*types.Transaction, error) { + return _FastBridgeV2.Contract.SetChainGasAmount(&_FastBridgeV2.TransactOpts, newChainGasAmount) +} + +// SetChainGasAmount is a paid mutator transaction binding the contract method 0xb250fe6b. +// +// Solidity: function setChainGasAmount(uint256 newChainGasAmount) returns() +func (_FastBridgeV2 *FastBridgeV2TransactorSession) SetChainGasAmount(newChainGasAmount *big.Int) (*types.Transaction, error) { + return _FastBridgeV2.Contract.SetChainGasAmount(&_FastBridgeV2.TransactOpts, newChainGasAmount) +} + +// SetProtocolFeeRate is a paid mutator transaction binding the contract method 0xb13aa2d6. +// +// Solidity: function setProtocolFeeRate(uint256 newFeeRate) returns() +func (_FastBridgeV2 *FastBridgeV2Transactor) SetProtocolFeeRate(opts *bind.TransactOpts, newFeeRate *big.Int) (*types.Transaction, error) { + return _FastBridgeV2.contract.Transact(opts, "setProtocolFeeRate", newFeeRate) +} + +// SetProtocolFeeRate is a paid mutator transaction binding the contract method 0xb13aa2d6. +// +// Solidity: function setProtocolFeeRate(uint256 newFeeRate) returns() +func (_FastBridgeV2 *FastBridgeV2Session) SetProtocolFeeRate(newFeeRate *big.Int) (*types.Transaction, error) { + return _FastBridgeV2.Contract.SetProtocolFeeRate(&_FastBridgeV2.TransactOpts, newFeeRate) +} + +// SetProtocolFeeRate is a paid mutator transaction binding the contract method 0xb13aa2d6. +// +// Solidity: function setProtocolFeeRate(uint256 newFeeRate) returns() +func (_FastBridgeV2 *FastBridgeV2TransactorSession) SetProtocolFeeRate(newFeeRate *big.Int) (*types.Transaction, error) { + return _FastBridgeV2.Contract.SetProtocolFeeRate(&_FastBridgeV2.TransactOpts, newFeeRate) +} + +// SweepProtocolFees is a paid mutator transaction binding the contract method 0x06f333f2. +// +// Solidity: function sweepProtocolFees(address token, address recipient) returns() +func (_FastBridgeV2 *FastBridgeV2Transactor) SweepProtocolFees(opts *bind.TransactOpts, token common.Address, recipient common.Address) (*types.Transaction, error) { + return _FastBridgeV2.contract.Transact(opts, "sweepProtocolFees", token, recipient) +} + +// SweepProtocolFees is a paid mutator transaction binding the contract method 0x06f333f2. +// +// Solidity: function sweepProtocolFees(address token, address recipient) returns() +func (_FastBridgeV2 *FastBridgeV2Session) SweepProtocolFees(token common.Address, recipient common.Address) (*types.Transaction, error) { + return _FastBridgeV2.Contract.SweepProtocolFees(&_FastBridgeV2.TransactOpts, token, recipient) +} + +// SweepProtocolFees is a paid mutator transaction binding the contract method 0x06f333f2. +// +// Solidity: function sweepProtocolFees(address token, address recipient) returns() +func (_FastBridgeV2 *FastBridgeV2TransactorSession) SweepProtocolFees(token common.Address, recipient common.Address) (*types.Transaction, error) { + return _FastBridgeV2.Contract.SweepProtocolFees(&_FastBridgeV2.TransactOpts, token, recipient) +} + +// FastBridgeV2BridgeDepositClaimedIterator is returned from FilterBridgeDepositClaimed and is used to iterate over the raw logs and unpacked data for BridgeDepositClaimed events raised by the FastBridgeV2 contract. +type FastBridgeV2BridgeDepositClaimedIterator struct { + Event *FastBridgeV2BridgeDepositClaimed // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *FastBridgeV2BridgeDepositClaimedIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(FastBridgeV2BridgeDepositClaimed) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(FastBridgeV2BridgeDepositClaimed) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *FastBridgeV2BridgeDepositClaimedIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *FastBridgeV2BridgeDepositClaimedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// FastBridgeV2BridgeDepositClaimed represents a BridgeDepositClaimed event raised by the FastBridgeV2 contract. +type FastBridgeV2BridgeDepositClaimed struct { + TransactionId [32]byte + Relayer common.Address + To common.Address + Token common.Address + Amount *big.Int + Raw types.Log // Blockchain specific contextual infos +} + +// FilterBridgeDepositClaimed is a free log retrieval operation binding the contract event 0x582211c35a2139ac3bbaac74663c6a1f56c6cbb658b41fe11fd45a82074ac678. +// +// Solidity: event BridgeDepositClaimed(bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount) +func (_FastBridgeV2 *FastBridgeV2Filterer) FilterBridgeDepositClaimed(opts *bind.FilterOpts, transactionId [][32]byte, relayer []common.Address, to []common.Address) (*FastBridgeV2BridgeDepositClaimedIterator, error) { + + var transactionIdRule []interface{} + for _, transactionIdItem := range transactionId { + transactionIdRule = append(transactionIdRule, transactionIdItem) + } + var relayerRule []interface{} + for _, relayerItem := range relayer { + relayerRule = append(relayerRule, relayerItem) + } + var toRule []interface{} + for _, toItem := range to { + toRule = append(toRule, toItem) + } + + logs, sub, err := _FastBridgeV2.contract.FilterLogs(opts, "BridgeDepositClaimed", transactionIdRule, relayerRule, toRule) + if err != nil { + return nil, err + } + return &FastBridgeV2BridgeDepositClaimedIterator{contract: _FastBridgeV2.contract, event: "BridgeDepositClaimed", logs: logs, sub: sub}, nil +} + +// WatchBridgeDepositClaimed is a free log subscription operation binding the contract event 0x582211c35a2139ac3bbaac74663c6a1f56c6cbb658b41fe11fd45a82074ac678. +// +// Solidity: event BridgeDepositClaimed(bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount) +func (_FastBridgeV2 *FastBridgeV2Filterer) WatchBridgeDepositClaimed(opts *bind.WatchOpts, sink chan<- *FastBridgeV2BridgeDepositClaimed, transactionId [][32]byte, relayer []common.Address, to []common.Address) (event.Subscription, error) { + + var transactionIdRule []interface{} + for _, transactionIdItem := range transactionId { + transactionIdRule = append(transactionIdRule, transactionIdItem) + } + var relayerRule []interface{} + for _, relayerItem := range relayer { + relayerRule = append(relayerRule, relayerItem) + } + var toRule []interface{} + for _, toItem := range to { + toRule = append(toRule, toItem) + } + + logs, sub, err := _FastBridgeV2.contract.WatchLogs(opts, "BridgeDepositClaimed", transactionIdRule, relayerRule, toRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(FastBridgeV2BridgeDepositClaimed) + if err := _FastBridgeV2.contract.UnpackLog(event, "BridgeDepositClaimed", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseBridgeDepositClaimed is a log parse operation binding the contract event 0x582211c35a2139ac3bbaac74663c6a1f56c6cbb658b41fe11fd45a82074ac678. +// +// Solidity: event BridgeDepositClaimed(bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount) +func (_FastBridgeV2 *FastBridgeV2Filterer) ParseBridgeDepositClaimed(log types.Log) (*FastBridgeV2BridgeDepositClaimed, error) { + event := new(FastBridgeV2BridgeDepositClaimed) + if err := _FastBridgeV2.contract.UnpackLog(event, "BridgeDepositClaimed", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// FastBridgeV2BridgeDepositRefundedIterator is returned from FilterBridgeDepositRefunded and is used to iterate over the raw logs and unpacked data for BridgeDepositRefunded events raised by the FastBridgeV2 contract. +type FastBridgeV2BridgeDepositRefundedIterator struct { + Event *FastBridgeV2BridgeDepositRefunded // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *FastBridgeV2BridgeDepositRefundedIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(FastBridgeV2BridgeDepositRefunded) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(FastBridgeV2BridgeDepositRefunded) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *FastBridgeV2BridgeDepositRefundedIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *FastBridgeV2BridgeDepositRefundedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// FastBridgeV2BridgeDepositRefunded represents a BridgeDepositRefunded event raised by the FastBridgeV2 contract. +type FastBridgeV2BridgeDepositRefunded struct { + TransactionId [32]byte + To common.Address + Token common.Address + Amount *big.Int + Raw types.Log // Blockchain specific contextual infos +} + +// FilterBridgeDepositRefunded is a free log retrieval operation binding the contract event 0xb4c55c0c9bc613519b920e88748090150b890a875d307f21bea7d4fb2e8bc958. +// +// Solidity: event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount) +func (_FastBridgeV2 *FastBridgeV2Filterer) FilterBridgeDepositRefunded(opts *bind.FilterOpts, transactionId [][32]byte, to []common.Address) (*FastBridgeV2BridgeDepositRefundedIterator, error) { + + var transactionIdRule []interface{} + for _, transactionIdItem := range transactionId { + transactionIdRule = append(transactionIdRule, transactionIdItem) + } + var toRule []interface{} + for _, toItem := range to { + toRule = append(toRule, toItem) + } + + logs, sub, err := _FastBridgeV2.contract.FilterLogs(opts, "BridgeDepositRefunded", transactionIdRule, toRule) + if err != nil { + return nil, err + } + return &FastBridgeV2BridgeDepositRefundedIterator{contract: _FastBridgeV2.contract, event: "BridgeDepositRefunded", logs: logs, sub: sub}, nil +} + +// WatchBridgeDepositRefunded is a free log subscription operation binding the contract event 0xb4c55c0c9bc613519b920e88748090150b890a875d307f21bea7d4fb2e8bc958. +// +// Solidity: event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount) +func (_FastBridgeV2 *FastBridgeV2Filterer) WatchBridgeDepositRefunded(opts *bind.WatchOpts, sink chan<- *FastBridgeV2BridgeDepositRefunded, transactionId [][32]byte, to []common.Address) (event.Subscription, error) { + + var transactionIdRule []interface{} + for _, transactionIdItem := range transactionId { + transactionIdRule = append(transactionIdRule, transactionIdItem) + } + var toRule []interface{} + for _, toItem := range to { + toRule = append(toRule, toItem) + } + + logs, sub, err := _FastBridgeV2.contract.WatchLogs(opts, "BridgeDepositRefunded", transactionIdRule, toRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(FastBridgeV2BridgeDepositRefunded) + if err := _FastBridgeV2.contract.UnpackLog(event, "BridgeDepositRefunded", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseBridgeDepositRefunded is a log parse operation binding the contract event 0xb4c55c0c9bc613519b920e88748090150b890a875d307f21bea7d4fb2e8bc958. +// +// Solidity: event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount) +func (_FastBridgeV2 *FastBridgeV2Filterer) ParseBridgeDepositRefunded(log types.Log) (*FastBridgeV2BridgeDepositRefunded, error) { + event := new(FastBridgeV2BridgeDepositRefunded) + if err := _FastBridgeV2.contract.UnpackLog(event, "BridgeDepositRefunded", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// FastBridgeV2BridgeProofDisputedIterator is returned from FilterBridgeProofDisputed and is used to iterate over the raw logs and unpacked data for BridgeProofDisputed events raised by the FastBridgeV2 contract. +type FastBridgeV2BridgeProofDisputedIterator struct { + Event *FastBridgeV2BridgeProofDisputed // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *FastBridgeV2BridgeProofDisputedIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(FastBridgeV2BridgeProofDisputed) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(FastBridgeV2BridgeProofDisputed) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *FastBridgeV2BridgeProofDisputedIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *FastBridgeV2BridgeProofDisputedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// FastBridgeV2BridgeProofDisputed represents a BridgeProofDisputed event raised by the FastBridgeV2 contract. +type FastBridgeV2BridgeProofDisputed struct { + TransactionId [32]byte + Relayer common.Address + Raw types.Log // Blockchain specific contextual infos +} + +// FilterBridgeProofDisputed is a free log retrieval operation binding the contract event 0x0695cf1d39b3055dcd0fe02d8b47eaf0d5a13e1996de925de59d0ef9b7f7fad4. +// +// Solidity: event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer) +func (_FastBridgeV2 *FastBridgeV2Filterer) FilterBridgeProofDisputed(opts *bind.FilterOpts, transactionId [][32]byte, relayer []common.Address) (*FastBridgeV2BridgeProofDisputedIterator, error) { + + var transactionIdRule []interface{} + for _, transactionIdItem := range transactionId { + transactionIdRule = append(transactionIdRule, transactionIdItem) + } + var relayerRule []interface{} + for _, relayerItem := range relayer { + relayerRule = append(relayerRule, relayerItem) + } + + logs, sub, err := _FastBridgeV2.contract.FilterLogs(opts, "BridgeProofDisputed", transactionIdRule, relayerRule) + if err != nil { + return nil, err + } + return &FastBridgeV2BridgeProofDisputedIterator{contract: _FastBridgeV2.contract, event: "BridgeProofDisputed", logs: logs, sub: sub}, nil +} + +// WatchBridgeProofDisputed is a free log subscription operation binding the contract event 0x0695cf1d39b3055dcd0fe02d8b47eaf0d5a13e1996de925de59d0ef9b7f7fad4. +// +// Solidity: event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer) +func (_FastBridgeV2 *FastBridgeV2Filterer) WatchBridgeProofDisputed(opts *bind.WatchOpts, sink chan<- *FastBridgeV2BridgeProofDisputed, transactionId [][32]byte, relayer []common.Address) (event.Subscription, error) { + + var transactionIdRule []interface{} + for _, transactionIdItem := range transactionId { + transactionIdRule = append(transactionIdRule, transactionIdItem) + } + var relayerRule []interface{} + for _, relayerItem := range relayer { + relayerRule = append(relayerRule, relayerItem) + } + + logs, sub, err := _FastBridgeV2.contract.WatchLogs(opts, "BridgeProofDisputed", transactionIdRule, relayerRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(FastBridgeV2BridgeProofDisputed) + if err := _FastBridgeV2.contract.UnpackLog(event, "BridgeProofDisputed", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseBridgeProofDisputed is a log parse operation binding the contract event 0x0695cf1d39b3055dcd0fe02d8b47eaf0d5a13e1996de925de59d0ef9b7f7fad4. +// +// Solidity: event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer) +func (_FastBridgeV2 *FastBridgeV2Filterer) ParseBridgeProofDisputed(log types.Log) (*FastBridgeV2BridgeProofDisputed, error) { + event := new(FastBridgeV2BridgeProofDisputed) + if err := _FastBridgeV2.contract.UnpackLog(event, "BridgeProofDisputed", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// FastBridgeV2BridgeProofProvidedIterator is returned from FilterBridgeProofProvided and is used to iterate over the raw logs and unpacked data for BridgeProofProvided events raised by the FastBridgeV2 contract. +type FastBridgeV2BridgeProofProvidedIterator struct { + Event *FastBridgeV2BridgeProofProvided // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *FastBridgeV2BridgeProofProvidedIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(FastBridgeV2BridgeProofProvided) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(FastBridgeV2BridgeProofProvided) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *FastBridgeV2BridgeProofProvidedIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *FastBridgeV2BridgeProofProvidedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// FastBridgeV2BridgeProofProvided represents a BridgeProofProvided event raised by the FastBridgeV2 contract. +type FastBridgeV2BridgeProofProvided struct { + TransactionId [32]byte + Relayer common.Address + TransactionHash [32]byte + Raw types.Log // Blockchain specific contextual infos +} + +// FilterBridgeProofProvided is a free log retrieval operation binding the contract event 0x4ac8af8a2cd87193d64dfc7a3b8d9923b714ec528b18725d080aa1299be0c5e4. +// +// Solidity: event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash) +func (_FastBridgeV2 *FastBridgeV2Filterer) FilterBridgeProofProvided(opts *bind.FilterOpts, transactionId [][32]byte, relayer []common.Address) (*FastBridgeV2BridgeProofProvidedIterator, error) { + + var transactionIdRule []interface{} + for _, transactionIdItem := range transactionId { + transactionIdRule = append(transactionIdRule, transactionIdItem) + } + var relayerRule []interface{} + for _, relayerItem := range relayer { + relayerRule = append(relayerRule, relayerItem) + } + + logs, sub, err := _FastBridgeV2.contract.FilterLogs(opts, "BridgeProofProvided", transactionIdRule, relayerRule) + if err != nil { + return nil, err + } + return &FastBridgeV2BridgeProofProvidedIterator{contract: _FastBridgeV2.contract, event: "BridgeProofProvided", logs: logs, sub: sub}, nil +} + +// WatchBridgeProofProvided is a free log subscription operation binding the contract event 0x4ac8af8a2cd87193d64dfc7a3b8d9923b714ec528b18725d080aa1299be0c5e4. +// +// Solidity: event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash) +func (_FastBridgeV2 *FastBridgeV2Filterer) WatchBridgeProofProvided(opts *bind.WatchOpts, sink chan<- *FastBridgeV2BridgeProofProvided, transactionId [][32]byte, relayer []common.Address) (event.Subscription, error) { + + var transactionIdRule []interface{} + for _, transactionIdItem := range transactionId { + transactionIdRule = append(transactionIdRule, transactionIdItem) + } + var relayerRule []interface{} + for _, relayerItem := range relayer { + relayerRule = append(relayerRule, relayerItem) + } + + logs, sub, err := _FastBridgeV2.contract.WatchLogs(opts, "BridgeProofProvided", transactionIdRule, relayerRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(FastBridgeV2BridgeProofProvided) + if err := _FastBridgeV2.contract.UnpackLog(event, "BridgeProofProvided", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseBridgeProofProvided is a log parse operation binding the contract event 0x4ac8af8a2cd87193d64dfc7a3b8d9923b714ec528b18725d080aa1299be0c5e4. +// +// Solidity: event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash) +func (_FastBridgeV2 *FastBridgeV2Filterer) ParseBridgeProofProvided(log types.Log) (*FastBridgeV2BridgeProofProvided, error) { + event := new(FastBridgeV2BridgeProofProvided) + if err := _FastBridgeV2.contract.UnpackLog(event, "BridgeProofProvided", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// FastBridgeV2BridgeQuoteDetailsIterator is returned from FilterBridgeQuoteDetails and is used to iterate over the raw logs and unpacked data for BridgeQuoteDetails events raised by the FastBridgeV2 contract. +type FastBridgeV2BridgeQuoteDetailsIterator struct { + Event *FastBridgeV2BridgeQuoteDetails // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *FastBridgeV2BridgeQuoteDetailsIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(FastBridgeV2BridgeQuoteDetails) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(FastBridgeV2BridgeQuoteDetails) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *FastBridgeV2BridgeQuoteDetailsIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *FastBridgeV2BridgeQuoteDetailsIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// FastBridgeV2BridgeQuoteDetails represents a BridgeQuoteDetails event raised by the FastBridgeV2 contract. +type FastBridgeV2BridgeQuoteDetails struct { + TransactionId [32]byte + QuoteId []byte + Raw types.Log // Blockchain specific contextual infos +} + +// FilterBridgeQuoteDetails is a free log retrieval operation binding the contract event 0x3120e2bb59c86aca6890191a589a96af3662838efa374fbdcdf4c95bfe4a6c0e. +// +// Solidity: event BridgeQuoteDetails(bytes32 indexed transactionId, bytes quoteId) +func (_FastBridgeV2 *FastBridgeV2Filterer) FilterBridgeQuoteDetails(opts *bind.FilterOpts, transactionId [][32]byte) (*FastBridgeV2BridgeQuoteDetailsIterator, error) { + + var transactionIdRule []interface{} + for _, transactionIdItem := range transactionId { + transactionIdRule = append(transactionIdRule, transactionIdItem) + } + + logs, sub, err := _FastBridgeV2.contract.FilterLogs(opts, "BridgeQuoteDetails", transactionIdRule) + if err != nil { + return nil, err + } + return &FastBridgeV2BridgeQuoteDetailsIterator{contract: _FastBridgeV2.contract, event: "BridgeQuoteDetails", logs: logs, sub: sub}, nil +} + +// WatchBridgeQuoteDetails is a free log subscription operation binding the contract event 0x3120e2bb59c86aca6890191a589a96af3662838efa374fbdcdf4c95bfe4a6c0e. +// +// Solidity: event BridgeQuoteDetails(bytes32 indexed transactionId, bytes quoteId) +func (_FastBridgeV2 *FastBridgeV2Filterer) WatchBridgeQuoteDetails(opts *bind.WatchOpts, sink chan<- *FastBridgeV2BridgeQuoteDetails, transactionId [][32]byte) (event.Subscription, error) { + + var transactionIdRule []interface{} + for _, transactionIdItem := range transactionId { + transactionIdRule = append(transactionIdRule, transactionIdItem) + } + + logs, sub, err := _FastBridgeV2.contract.WatchLogs(opts, "BridgeQuoteDetails", transactionIdRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(FastBridgeV2BridgeQuoteDetails) + if err := _FastBridgeV2.contract.UnpackLog(event, "BridgeQuoteDetails", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseBridgeQuoteDetails is a log parse operation binding the contract event 0x3120e2bb59c86aca6890191a589a96af3662838efa374fbdcdf4c95bfe4a6c0e. +// +// Solidity: event BridgeQuoteDetails(bytes32 indexed transactionId, bytes quoteId) +func (_FastBridgeV2 *FastBridgeV2Filterer) ParseBridgeQuoteDetails(log types.Log) (*FastBridgeV2BridgeQuoteDetails, error) { + event := new(FastBridgeV2BridgeQuoteDetails) + if err := _FastBridgeV2.contract.UnpackLog(event, "BridgeQuoteDetails", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// FastBridgeV2BridgeRelayedIterator is returned from FilterBridgeRelayed and is used to iterate over the raw logs and unpacked data for BridgeRelayed events raised by the FastBridgeV2 contract. +type FastBridgeV2BridgeRelayedIterator struct { + Event *FastBridgeV2BridgeRelayed // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *FastBridgeV2BridgeRelayedIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(FastBridgeV2BridgeRelayed) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(FastBridgeV2BridgeRelayed) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *FastBridgeV2BridgeRelayedIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *FastBridgeV2BridgeRelayedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// FastBridgeV2BridgeRelayed represents a BridgeRelayed event raised by the FastBridgeV2 contract. +type FastBridgeV2BridgeRelayed struct { + TransactionId [32]byte + Relayer common.Address + To common.Address + OriginChainId uint32 + OriginToken common.Address + DestToken common.Address + OriginAmount *big.Int + DestAmount *big.Int + ChainGasAmount *big.Int + Raw types.Log // Blockchain specific contextual infos +} + +// FilterBridgeRelayed is a free log retrieval operation binding the contract event 0xf8ae392d784b1ea5e8881bfa586d81abf07ef4f1e2fc75f7fe51c90f05199a5c. +// +// Solidity: event BridgeRelayed(bytes32 indexed transactionId, address indexed relayer, address indexed to, uint32 originChainId, address originToken, address destToken, uint256 originAmount, uint256 destAmount, uint256 chainGasAmount) +func (_FastBridgeV2 *FastBridgeV2Filterer) FilterBridgeRelayed(opts *bind.FilterOpts, transactionId [][32]byte, relayer []common.Address, to []common.Address) (*FastBridgeV2BridgeRelayedIterator, error) { + + var transactionIdRule []interface{} + for _, transactionIdItem := range transactionId { + transactionIdRule = append(transactionIdRule, transactionIdItem) + } + var relayerRule []interface{} + for _, relayerItem := range relayer { + relayerRule = append(relayerRule, relayerItem) + } + var toRule []interface{} + for _, toItem := range to { + toRule = append(toRule, toItem) + } + + logs, sub, err := _FastBridgeV2.contract.FilterLogs(opts, "BridgeRelayed", transactionIdRule, relayerRule, toRule) + if err != nil { + return nil, err + } + return &FastBridgeV2BridgeRelayedIterator{contract: _FastBridgeV2.contract, event: "BridgeRelayed", logs: logs, sub: sub}, nil +} + +// WatchBridgeRelayed is a free log subscription operation binding the contract event 0xf8ae392d784b1ea5e8881bfa586d81abf07ef4f1e2fc75f7fe51c90f05199a5c. +// +// Solidity: event BridgeRelayed(bytes32 indexed transactionId, address indexed relayer, address indexed to, uint32 originChainId, address originToken, address destToken, uint256 originAmount, uint256 destAmount, uint256 chainGasAmount) +func (_FastBridgeV2 *FastBridgeV2Filterer) WatchBridgeRelayed(opts *bind.WatchOpts, sink chan<- *FastBridgeV2BridgeRelayed, transactionId [][32]byte, relayer []common.Address, to []common.Address) (event.Subscription, error) { + + var transactionIdRule []interface{} + for _, transactionIdItem := range transactionId { + transactionIdRule = append(transactionIdRule, transactionIdItem) + } + var relayerRule []interface{} + for _, relayerItem := range relayer { + relayerRule = append(relayerRule, relayerItem) + } + var toRule []interface{} + for _, toItem := range to { + toRule = append(toRule, toItem) + } + + logs, sub, err := _FastBridgeV2.contract.WatchLogs(opts, "BridgeRelayed", transactionIdRule, relayerRule, toRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(FastBridgeV2BridgeRelayed) + if err := _FastBridgeV2.contract.UnpackLog(event, "BridgeRelayed", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseBridgeRelayed is a log parse operation binding the contract event 0xf8ae392d784b1ea5e8881bfa586d81abf07ef4f1e2fc75f7fe51c90f05199a5c. +// +// Solidity: event BridgeRelayed(bytes32 indexed transactionId, address indexed relayer, address indexed to, uint32 originChainId, address originToken, address destToken, uint256 originAmount, uint256 destAmount, uint256 chainGasAmount) +func (_FastBridgeV2 *FastBridgeV2Filterer) ParseBridgeRelayed(log types.Log) (*FastBridgeV2BridgeRelayed, error) { + event := new(FastBridgeV2BridgeRelayed) + if err := _FastBridgeV2.contract.UnpackLog(event, "BridgeRelayed", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// FastBridgeV2BridgeRequestedIterator is returned from FilterBridgeRequested and is used to iterate over the raw logs and unpacked data for BridgeRequested events raised by the FastBridgeV2 contract. +type FastBridgeV2BridgeRequestedIterator struct { + Event *FastBridgeV2BridgeRequested // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *FastBridgeV2BridgeRequestedIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(FastBridgeV2BridgeRequested) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(FastBridgeV2BridgeRequested) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *FastBridgeV2BridgeRequestedIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *FastBridgeV2BridgeRequestedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// FastBridgeV2BridgeRequested represents a BridgeRequested event raised by the FastBridgeV2 contract. +type FastBridgeV2BridgeRequested struct { + TransactionId [32]byte + Sender common.Address + Request []byte + DestChainId uint32 + OriginToken common.Address + DestToken common.Address + OriginAmount *big.Int + DestAmount *big.Int + SendChainGas bool + Raw types.Log // Blockchain specific contextual infos +} + +// FilterBridgeRequested is a free log retrieval operation binding the contract event 0x120ea0364f36cdac7983bcfdd55270ca09d7f9b314a2ebc425a3b01ab1d6403a. +// +// Solidity: event BridgeRequested(bytes32 indexed transactionId, address indexed sender, bytes request, uint32 destChainId, address originToken, address destToken, uint256 originAmount, uint256 destAmount, bool sendChainGas) +func (_FastBridgeV2 *FastBridgeV2Filterer) FilterBridgeRequested(opts *bind.FilterOpts, transactionId [][32]byte, sender []common.Address) (*FastBridgeV2BridgeRequestedIterator, error) { + + var transactionIdRule []interface{} + for _, transactionIdItem := range transactionId { + transactionIdRule = append(transactionIdRule, transactionIdItem) + } + var senderRule []interface{} + for _, senderItem := range sender { + senderRule = append(senderRule, senderItem) + } + + logs, sub, err := _FastBridgeV2.contract.FilterLogs(opts, "BridgeRequested", transactionIdRule, senderRule) + if err != nil { + return nil, err + } + return &FastBridgeV2BridgeRequestedIterator{contract: _FastBridgeV2.contract, event: "BridgeRequested", logs: logs, sub: sub}, nil +} + +// WatchBridgeRequested is a free log subscription operation binding the contract event 0x120ea0364f36cdac7983bcfdd55270ca09d7f9b314a2ebc425a3b01ab1d6403a. +// +// Solidity: event BridgeRequested(bytes32 indexed transactionId, address indexed sender, bytes request, uint32 destChainId, address originToken, address destToken, uint256 originAmount, uint256 destAmount, bool sendChainGas) +func (_FastBridgeV2 *FastBridgeV2Filterer) WatchBridgeRequested(opts *bind.WatchOpts, sink chan<- *FastBridgeV2BridgeRequested, transactionId [][32]byte, sender []common.Address) (event.Subscription, error) { + + var transactionIdRule []interface{} + for _, transactionIdItem := range transactionId { + transactionIdRule = append(transactionIdRule, transactionIdItem) + } + var senderRule []interface{} + for _, senderItem := range sender { + senderRule = append(senderRule, senderItem) + } + + logs, sub, err := _FastBridgeV2.contract.WatchLogs(opts, "BridgeRequested", transactionIdRule, senderRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(FastBridgeV2BridgeRequested) + if err := _FastBridgeV2.contract.UnpackLog(event, "BridgeRequested", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseBridgeRequested is a log parse operation binding the contract event 0x120ea0364f36cdac7983bcfdd55270ca09d7f9b314a2ebc425a3b01ab1d6403a. +// +// Solidity: event BridgeRequested(bytes32 indexed transactionId, address indexed sender, bytes request, uint32 destChainId, address originToken, address destToken, uint256 originAmount, uint256 destAmount, bool sendChainGas) +func (_FastBridgeV2 *FastBridgeV2Filterer) ParseBridgeRequested(log types.Log) (*FastBridgeV2BridgeRequested, error) { + event := new(FastBridgeV2BridgeRequested) + if err := _FastBridgeV2.contract.UnpackLog(event, "BridgeRequested", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// FastBridgeV2ChainGasAmountUpdatedIterator is returned from FilterChainGasAmountUpdated and is used to iterate over the raw logs and unpacked data for ChainGasAmountUpdated events raised by the FastBridgeV2 contract. +type FastBridgeV2ChainGasAmountUpdatedIterator struct { + Event *FastBridgeV2ChainGasAmountUpdated // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *FastBridgeV2ChainGasAmountUpdatedIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(FastBridgeV2ChainGasAmountUpdated) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(FastBridgeV2ChainGasAmountUpdated) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *FastBridgeV2ChainGasAmountUpdatedIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *FastBridgeV2ChainGasAmountUpdatedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// FastBridgeV2ChainGasAmountUpdated represents a ChainGasAmountUpdated event raised by the FastBridgeV2 contract. +type FastBridgeV2ChainGasAmountUpdated struct { + OldChainGasAmount *big.Int + NewChainGasAmount *big.Int + Raw types.Log // Blockchain specific contextual infos +} + +// FilterChainGasAmountUpdated is a free log retrieval operation binding the contract event 0x5cf09b12f3f56b4c564d51b25b40360af6d795198adb61ae0806a36c294323fa. +// +// Solidity: event ChainGasAmountUpdated(uint256 oldChainGasAmount, uint256 newChainGasAmount) +func (_FastBridgeV2 *FastBridgeV2Filterer) FilterChainGasAmountUpdated(opts *bind.FilterOpts) (*FastBridgeV2ChainGasAmountUpdatedIterator, error) { + + logs, sub, err := _FastBridgeV2.contract.FilterLogs(opts, "ChainGasAmountUpdated") + if err != nil { + return nil, err + } + return &FastBridgeV2ChainGasAmountUpdatedIterator{contract: _FastBridgeV2.contract, event: "ChainGasAmountUpdated", logs: logs, sub: sub}, nil +} + +// WatchChainGasAmountUpdated is a free log subscription operation binding the contract event 0x5cf09b12f3f56b4c564d51b25b40360af6d795198adb61ae0806a36c294323fa. +// +// Solidity: event ChainGasAmountUpdated(uint256 oldChainGasAmount, uint256 newChainGasAmount) +func (_FastBridgeV2 *FastBridgeV2Filterer) WatchChainGasAmountUpdated(opts *bind.WatchOpts, sink chan<- *FastBridgeV2ChainGasAmountUpdated) (event.Subscription, error) { + + logs, sub, err := _FastBridgeV2.contract.WatchLogs(opts, "ChainGasAmountUpdated") + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(FastBridgeV2ChainGasAmountUpdated) + if err := _FastBridgeV2.contract.UnpackLog(event, "ChainGasAmountUpdated", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseChainGasAmountUpdated is a log parse operation binding the contract event 0x5cf09b12f3f56b4c564d51b25b40360af6d795198adb61ae0806a36c294323fa. +// +// Solidity: event ChainGasAmountUpdated(uint256 oldChainGasAmount, uint256 newChainGasAmount) +func (_FastBridgeV2 *FastBridgeV2Filterer) ParseChainGasAmountUpdated(log types.Log) (*FastBridgeV2ChainGasAmountUpdated, error) { + event := new(FastBridgeV2ChainGasAmountUpdated) + if err := _FastBridgeV2.contract.UnpackLog(event, "ChainGasAmountUpdated", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// FastBridgeV2FeeRateUpdatedIterator is returned from FilterFeeRateUpdated and is used to iterate over the raw logs and unpacked data for FeeRateUpdated events raised by the FastBridgeV2 contract. +type FastBridgeV2FeeRateUpdatedIterator struct { + Event *FastBridgeV2FeeRateUpdated // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *FastBridgeV2FeeRateUpdatedIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(FastBridgeV2FeeRateUpdated) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(FastBridgeV2FeeRateUpdated) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *FastBridgeV2FeeRateUpdatedIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *FastBridgeV2FeeRateUpdatedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// FastBridgeV2FeeRateUpdated represents a FeeRateUpdated event raised by the FastBridgeV2 contract. +type FastBridgeV2FeeRateUpdated struct { + OldFeeRate *big.Int + NewFeeRate *big.Int + Raw types.Log // Blockchain specific contextual infos +} + +// FilterFeeRateUpdated is a free log retrieval operation binding the contract event 0x14914da2bf76024616fbe1859783fcd4dbddcb179b1f3a854949fbf920dcb957. +// +// Solidity: event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate) +func (_FastBridgeV2 *FastBridgeV2Filterer) FilterFeeRateUpdated(opts *bind.FilterOpts) (*FastBridgeV2FeeRateUpdatedIterator, error) { + + logs, sub, err := _FastBridgeV2.contract.FilterLogs(opts, "FeeRateUpdated") + if err != nil { + return nil, err + } + return &FastBridgeV2FeeRateUpdatedIterator{contract: _FastBridgeV2.contract, event: "FeeRateUpdated", logs: logs, sub: sub}, nil +} + +// WatchFeeRateUpdated is a free log subscription operation binding the contract event 0x14914da2bf76024616fbe1859783fcd4dbddcb179b1f3a854949fbf920dcb957. +// +// Solidity: event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate) +func (_FastBridgeV2 *FastBridgeV2Filterer) WatchFeeRateUpdated(opts *bind.WatchOpts, sink chan<- *FastBridgeV2FeeRateUpdated) (event.Subscription, error) { + + logs, sub, err := _FastBridgeV2.contract.WatchLogs(opts, "FeeRateUpdated") + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(FastBridgeV2FeeRateUpdated) + if err := _FastBridgeV2.contract.UnpackLog(event, "FeeRateUpdated", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseFeeRateUpdated is a log parse operation binding the contract event 0x14914da2bf76024616fbe1859783fcd4dbddcb179b1f3a854949fbf920dcb957. +// +// Solidity: event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate) +func (_FastBridgeV2 *FastBridgeV2Filterer) ParseFeeRateUpdated(log types.Log) (*FastBridgeV2FeeRateUpdated, error) { + event := new(FastBridgeV2FeeRateUpdated) + if err := _FastBridgeV2.contract.UnpackLog(event, "FeeRateUpdated", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// FastBridgeV2FeesSweptIterator is returned from FilterFeesSwept and is used to iterate over the raw logs and unpacked data for FeesSwept events raised by the FastBridgeV2 contract. +type FastBridgeV2FeesSweptIterator struct { + Event *FastBridgeV2FeesSwept // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *FastBridgeV2FeesSweptIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(FastBridgeV2FeesSwept) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(FastBridgeV2FeesSwept) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *FastBridgeV2FeesSweptIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *FastBridgeV2FeesSweptIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// FastBridgeV2FeesSwept represents a FeesSwept event raised by the FastBridgeV2 contract. +type FastBridgeV2FeesSwept struct { + Token common.Address + Recipient common.Address + Amount *big.Int + Raw types.Log // Blockchain specific contextual infos +} + +// FilterFeesSwept is a free log retrieval operation binding the contract event 0x244e51bc38c1452fa8aaf487bcb4bca36c2baa3a5fbdb776b1eabd8dc6d277cd. +// +// Solidity: event FeesSwept(address token, address recipient, uint256 amount) +func (_FastBridgeV2 *FastBridgeV2Filterer) FilterFeesSwept(opts *bind.FilterOpts) (*FastBridgeV2FeesSweptIterator, error) { + + logs, sub, err := _FastBridgeV2.contract.FilterLogs(opts, "FeesSwept") + if err != nil { + return nil, err + } + return &FastBridgeV2FeesSweptIterator{contract: _FastBridgeV2.contract, event: "FeesSwept", logs: logs, sub: sub}, nil +} + +// WatchFeesSwept is a free log subscription operation binding the contract event 0x244e51bc38c1452fa8aaf487bcb4bca36c2baa3a5fbdb776b1eabd8dc6d277cd. +// +// Solidity: event FeesSwept(address token, address recipient, uint256 amount) +func (_FastBridgeV2 *FastBridgeV2Filterer) WatchFeesSwept(opts *bind.WatchOpts, sink chan<- *FastBridgeV2FeesSwept) (event.Subscription, error) { + + logs, sub, err := _FastBridgeV2.contract.WatchLogs(opts, "FeesSwept") + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(FastBridgeV2FeesSwept) + if err := _FastBridgeV2.contract.UnpackLog(event, "FeesSwept", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseFeesSwept is a log parse operation binding the contract event 0x244e51bc38c1452fa8aaf487bcb4bca36c2baa3a5fbdb776b1eabd8dc6d277cd. +// +// Solidity: event FeesSwept(address token, address recipient, uint256 amount) +func (_FastBridgeV2 *FastBridgeV2Filterer) ParseFeesSwept(log types.Log) (*FastBridgeV2FeesSwept, error) { + event := new(FastBridgeV2FeesSwept) + if err := _FastBridgeV2.contract.UnpackLog(event, "FeesSwept", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// FastBridgeV2RoleAdminChangedIterator is returned from FilterRoleAdminChanged and is used to iterate over the raw logs and unpacked data for RoleAdminChanged events raised by the FastBridgeV2 contract. +type FastBridgeV2RoleAdminChangedIterator struct { + Event *FastBridgeV2RoleAdminChanged // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *FastBridgeV2RoleAdminChangedIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(FastBridgeV2RoleAdminChanged) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(FastBridgeV2RoleAdminChanged) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *FastBridgeV2RoleAdminChangedIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *FastBridgeV2RoleAdminChangedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// FastBridgeV2RoleAdminChanged represents a RoleAdminChanged event raised by the FastBridgeV2 contract. +type FastBridgeV2RoleAdminChanged struct { + Role [32]byte + PreviousAdminRole [32]byte + NewAdminRole [32]byte + Raw types.Log // Blockchain specific contextual infos +} + +// FilterRoleAdminChanged is a free log retrieval operation binding the contract event 0xbd79b86ffe0ab8e8776151514217cd7cacd52c909f66475c3af44e129f0b00ff. +// +// Solidity: event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole) +func (_FastBridgeV2 *FastBridgeV2Filterer) FilterRoleAdminChanged(opts *bind.FilterOpts, role [][32]byte, previousAdminRole [][32]byte, newAdminRole [][32]byte) (*FastBridgeV2RoleAdminChangedIterator, error) { + + var roleRule []interface{} + for _, roleItem := range role { + roleRule = append(roleRule, roleItem) + } + var previousAdminRoleRule []interface{} + for _, previousAdminRoleItem := range previousAdminRole { + previousAdminRoleRule = append(previousAdminRoleRule, previousAdminRoleItem) + } + var newAdminRoleRule []interface{} + for _, newAdminRoleItem := range newAdminRole { + newAdminRoleRule = append(newAdminRoleRule, newAdminRoleItem) + } + + logs, sub, err := _FastBridgeV2.contract.FilterLogs(opts, "RoleAdminChanged", roleRule, previousAdminRoleRule, newAdminRoleRule) + if err != nil { + return nil, err + } + return &FastBridgeV2RoleAdminChangedIterator{contract: _FastBridgeV2.contract, event: "RoleAdminChanged", logs: logs, sub: sub}, nil +} + +// WatchRoleAdminChanged is a free log subscription operation binding the contract event 0xbd79b86ffe0ab8e8776151514217cd7cacd52c909f66475c3af44e129f0b00ff. +// +// Solidity: event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole) +func (_FastBridgeV2 *FastBridgeV2Filterer) WatchRoleAdminChanged(opts *bind.WatchOpts, sink chan<- *FastBridgeV2RoleAdminChanged, role [][32]byte, previousAdminRole [][32]byte, newAdminRole [][32]byte) (event.Subscription, error) { + + var roleRule []interface{} + for _, roleItem := range role { + roleRule = append(roleRule, roleItem) + } + var previousAdminRoleRule []interface{} + for _, previousAdminRoleItem := range previousAdminRole { + previousAdminRoleRule = append(previousAdminRoleRule, previousAdminRoleItem) + } + var newAdminRoleRule []interface{} + for _, newAdminRoleItem := range newAdminRole { + newAdminRoleRule = append(newAdminRoleRule, newAdminRoleItem) + } + + logs, sub, err := _FastBridgeV2.contract.WatchLogs(opts, "RoleAdminChanged", roleRule, previousAdminRoleRule, newAdminRoleRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(FastBridgeV2RoleAdminChanged) + if err := _FastBridgeV2.contract.UnpackLog(event, "RoleAdminChanged", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseRoleAdminChanged is a log parse operation binding the contract event 0xbd79b86ffe0ab8e8776151514217cd7cacd52c909f66475c3af44e129f0b00ff. +// +// Solidity: event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole) +func (_FastBridgeV2 *FastBridgeV2Filterer) ParseRoleAdminChanged(log types.Log) (*FastBridgeV2RoleAdminChanged, error) { + event := new(FastBridgeV2RoleAdminChanged) + if err := _FastBridgeV2.contract.UnpackLog(event, "RoleAdminChanged", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// FastBridgeV2RoleGrantedIterator is returned from FilterRoleGranted and is used to iterate over the raw logs and unpacked data for RoleGranted events raised by the FastBridgeV2 contract. +type FastBridgeV2RoleGrantedIterator struct { + Event *FastBridgeV2RoleGranted // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *FastBridgeV2RoleGrantedIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(FastBridgeV2RoleGranted) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(FastBridgeV2RoleGranted) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *FastBridgeV2RoleGrantedIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *FastBridgeV2RoleGrantedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// FastBridgeV2RoleGranted represents a RoleGranted event raised by the FastBridgeV2 contract. +type FastBridgeV2RoleGranted struct { + Role [32]byte + Account common.Address + Sender common.Address + Raw types.Log // Blockchain specific contextual infos +} + +// FilterRoleGranted is a free log retrieval operation binding the contract event 0x2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d. +// +// Solidity: event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender) +func (_FastBridgeV2 *FastBridgeV2Filterer) FilterRoleGranted(opts *bind.FilterOpts, role [][32]byte, account []common.Address, sender []common.Address) (*FastBridgeV2RoleGrantedIterator, error) { + + var roleRule []interface{} + for _, roleItem := range role { + roleRule = append(roleRule, roleItem) + } + var accountRule []interface{} + for _, accountItem := range account { + accountRule = append(accountRule, accountItem) + } + var senderRule []interface{} + for _, senderItem := range sender { + senderRule = append(senderRule, senderItem) + } + + logs, sub, err := _FastBridgeV2.contract.FilterLogs(opts, "RoleGranted", roleRule, accountRule, senderRule) + if err != nil { + return nil, err + } + return &FastBridgeV2RoleGrantedIterator{contract: _FastBridgeV2.contract, event: "RoleGranted", logs: logs, sub: sub}, nil +} + +// WatchRoleGranted is a free log subscription operation binding the contract event 0x2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d. +// +// Solidity: event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender) +func (_FastBridgeV2 *FastBridgeV2Filterer) WatchRoleGranted(opts *bind.WatchOpts, sink chan<- *FastBridgeV2RoleGranted, role [][32]byte, account []common.Address, sender []common.Address) (event.Subscription, error) { + + var roleRule []interface{} + for _, roleItem := range role { + roleRule = append(roleRule, roleItem) + } + var accountRule []interface{} + for _, accountItem := range account { + accountRule = append(accountRule, accountItem) + } + var senderRule []interface{} + for _, senderItem := range sender { + senderRule = append(senderRule, senderItem) + } + + logs, sub, err := _FastBridgeV2.contract.WatchLogs(opts, "RoleGranted", roleRule, accountRule, senderRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(FastBridgeV2RoleGranted) + if err := _FastBridgeV2.contract.UnpackLog(event, "RoleGranted", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseRoleGranted is a log parse operation binding the contract event 0x2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d. +// +// Solidity: event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender) +func (_FastBridgeV2 *FastBridgeV2Filterer) ParseRoleGranted(log types.Log) (*FastBridgeV2RoleGranted, error) { + event := new(FastBridgeV2RoleGranted) + if err := _FastBridgeV2.contract.UnpackLog(event, "RoleGranted", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// FastBridgeV2RoleRevokedIterator is returned from FilterRoleRevoked and is used to iterate over the raw logs and unpacked data for RoleRevoked events raised by the FastBridgeV2 contract. +type FastBridgeV2RoleRevokedIterator struct { + Event *FastBridgeV2RoleRevoked // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *FastBridgeV2RoleRevokedIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(FastBridgeV2RoleRevoked) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(FastBridgeV2RoleRevoked) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *FastBridgeV2RoleRevokedIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *FastBridgeV2RoleRevokedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// FastBridgeV2RoleRevoked represents a RoleRevoked event raised by the FastBridgeV2 contract. +type FastBridgeV2RoleRevoked struct { + Role [32]byte + Account common.Address + Sender common.Address + Raw types.Log // Blockchain specific contextual infos +} + +// FilterRoleRevoked is a free log retrieval operation binding the contract event 0xf6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b. +// +// Solidity: event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender) +func (_FastBridgeV2 *FastBridgeV2Filterer) FilterRoleRevoked(opts *bind.FilterOpts, role [][32]byte, account []common.Address, sender []common.Address) (*FastBridgeV2RoleRevokedIterator, error) { + + var roleRule []interface{} + for _, roleItem := range role { + roleRule = append(roleRule, roleItem) + } + var accountRule []interface{} + for _, accountItem := range account { + accountRule = append(accountRule, accountItem) + } + var senderRule []interface{} + for _, senderItem := range sender { + senderRule = append(senderRule, senderItem) + } + + logs, sub, err := _FastBridgeV2.contract.FilterLogs(opts, "RoleRevoked", roleRule, accountRule, senderRule) + if err != nil { + return nil, err + } + return &FastBridgeV2RoleRevokedIterator{contract: _FastBridgeV2.contract, event: "RoleRevoked", logs: logs, sub: sub}, nil +} + +// WatchRoleRevoked is a free log subscription operation binding the contract event 0xf6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b. +// +// Solidity: event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender) +func (_FastBridgeV2 *FastBridgeV2Filterer) WatchRoleRevoked(opts *bind.WatchOpts, sink chan<- *FastBridgeV2RoleRevoked, role [][32]byte, account []common.Address, sender []common.Address) (event.Subscription, error) { + + var roleRule []interface{} + for _, roleItem := range role { + roleRule = append(roleRule, roleItem) + } + var accountRule []interface{} + for _, accountItem := range account { + accountRule = append(accountRule, accountItem) + } + var senderRule []interface{} + for _, senderItem := range sender { + senderRule = append(senderRule, senderItem) + } + + logs, sub, err := _FastBridgeV2.contract.WatchLogs(opts, "RoleRevoked", roleRule, accountRule, senderRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(FastBridgeV2RoleRevoked) + if err := _FastBridgeV2.contract.UnpackLog(event, "RoleRevoked", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseRoleRevoked is a log parse operation binding the contract event 0xf6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b. +// +// Solidity: event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender) +func (_FastBridgeV2 *FastBridgeV2Filterer) ParseRoleRevoked(log types.Log) (*FastBridgeV2RoleRevoked, error) { + event := new(FastBridgeV2RoleRevoked) + if err := _FastBridgeV2.contract.UnpackLog(event, "RoleRevoked", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// IAccessControlMetaData contains all meta data concerning the IAccessControl contract. +var IAccessControlMetaData = &bind.MetaData{ + ABI: "[{\"inputs\":[],\"name\":\"AccessControlBadConfirmation\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"neededRole\",\"type\":\"bytes32\"}],\"name\":\"AccessControlUnauthorizedAccount\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"previousAdminRole\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"newAdminRole\",\"type\":\"bytes32\"}],\"name\":\"RoleAdminChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleGranted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleRevoked\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"}],\"name\":\"getRoleAdmin\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"grantRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"hasRole\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"callerConfirmation\",\"type\":\"address\"}],\"name\":\"renounceRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"revokeRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", + Sigs: map[string]string{ + "248a9ca3": "getRoleAdmin(bytes32)", + "2f2ff15d": "grantRole(bytes32,address)", + "91d14854": "hasRole(bytes32,address)", + "36568abe": "renounceRole(bytes32,address)", + "d547741f": "revokeRole(bytes32,address)", + }, +} + +// IAccessControlABI is the input ABI used to generate the binding from. +// Deprecated: Use IAccessControlMetaData.ABI instead. +var IAccessControlABI = IAccessControlMetaData.ABI + +// Deprecated: Use IAccessControlMetaData.Sigs instead. +// IAccessControlFuncSigs maps the 4-byte function signature to its string representation. +var IAccessControlFuncSigs = IAccessControlMetaData.Sigs + +// IAccessControl is an auto generated Go binding around an Ethereum contract. +type IAccessControl struct { + IAccessControlCaller // Read-only binding to the contract + IAccessControlTransactor // Write-only binding to the contract + IAccessControlFilterer // Log filterer for contract events +} + +// IAccessControlCaller is an auto generated read-only Go binding around an Ethereum contract. +type IAccessControlCaller struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// IAccessControlTransactor is an auto generated write-only Go binding around an Ethereum contract. +type IAccessControlTransactor struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// IAccessControlFilterer is an auto generated log filtering Go binding around an Ethereum contract events. +type IAccessControlFilterer struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// IAccessControlSession is an auto generated Go binding around an Ethereum contract, +// with pre-set call and transact options. +type IAccessControlSession struct { + Contract *IAccessControl // Generic contract binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// IAccessControlCallerSession is an auto generated read-only Go binding around an Ethereum contract, +// with pre-set call options. +type IAccessControlCallerSession struct { + Contract *IAccessControlCaller // Generic contract caller binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session +} + +// IAccessControlTransactorSession is an auto generated write-only Go binding around an Ethereum contract, +// with pre-set transact options. +type IAccessControlTransactorSession struct { + Contract *IAccessControlTransactor // Generic contract transactor binding to set the session for + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// IAccessControlRaw is an auto generated low-level Go binding around an Ethereum contract. +type IAccessControlRaw struct { + Contract *IAccessControl // Generic contract binding to access the raw methods on +} + +// IAccessControlCallerRaw is an auto generated low-level read-only Go binding around an Ethereum contract. +type IAccessControlCallerRaw struct { + Contract *IAccessControlCaller // Generic read-only contract binding to access the raw methods on +} + +// IAccessControlTransactorRaw is an auto generated low-level write-only Go binding around an Ethereum contract. +type IAccessControlTransactorRaw struct { + Contract *IAccessControlTransactor // Generic write-only contract binding to access the raw methods on +} + +// NewIAccessControl creates a new instance of IAccessControl, bound to a specific deployed contract. +func NewIAccessControl(address common.Address, backend bind.ContractBackend) (*IAccessControl, error) { + contract, err := bindIAccessControl(address, backend, backend, backend) + if err != nil { + return nil, err + } + return &IAccessControl{IAccessControlCaller: IAccessControlCaller{contract: contract}, IAccessControlTransactor: IAccessControlTransactor{contract: contract}, IAccessControlFilterer: IAccessControlFilterer{contract: contract}}, nil +} + +// NewIAccessControlCaller creates a new read-only instance of IAccessControl, bound to a specific deployed contract. +func NewIAccessControlCaller(address common.Address, caller bind.ContractCaller) (*IAccessControlCaller, error) { + contract, err := bindIAccessControl(address, caller, nil, nil) + if err != nil { + return nil, err + } + return &IAccessControlCaller{contract: contract}, nil +} + +// NewIAccessControlTransactor creates a new write-only instance of IAccessControl, bound to a specific deployed contract. +func NewIAccessControlTransactor(address common.Address, transactor bind.ContractTransactor) (*IAccessControlTransactor, error) { + contract, err := bindIAccessControl(address, nil, transactor, nil) + if err != nil { + return nil, err + } + return &IAccessControlTransactor{contract: contract}, nil +} + +// NewIAccessControlFilterer creates a new log filterer instance of IAccessControl, bound to a specific deployed contract. +func NewIAccessControlFilterer(address common.Address, filterer bind.ContractFilterer) (*IAccessControlFilterer, error) { + contract, err := bindIAccessControl(address, nil, nil, filterer) + if err != nil { + return nil, err + } + return &IAccessControlFilterer{contract: contract}, nil +} + +// bindIAccessControl binds a generic wrapper to an already deployed contract. +func bindIAccessControl(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) { + parsed, err := IAccessControlMetaData.GetAbi() + if err != nil { + return nil, err + } + return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil +} + +// Call invokes the (constant) contract method with params as input values and +// sets the output to result. The result type might be a single field for simple +// returns, a slice of interfaces for anonymous returns and a struct for named +// returns. +func (_IAccessControl *IAccessControlRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _IAccessControl.Contract.IAccessControlCaller.contract.Call(opts, result, method, params...) +} + +// Transfer initiates a plain transaction to move funds to the contract, calling +// its default method if one is available. +func (_IAccessControl *IAccessControlRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _IAccessControl.Contract.IAccessControlTransactor.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_IAccessControl *IAccessControlRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _IAccessControl.Contract.IAccessControlTransactor.contract.Transact(opts, method, params...) +} + +// Call invokes the (constant) contract method with params as input values and +// sets the output to result. The result type might be a single field for simple +// returns, a slice of interfaces for anonymous returns and a struct for named +// returns. +func (_IAccessControl *IAccessControlCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _IAccessControl.Contract.contract.Call(opts, result, method, params...) +} + +// Transfer initiates a plain transaction to move funds to the contract, calling +// its default method if one is available. +func (_IAccessControl *IAccessControlTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _IAccessControl.Contract.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_IAccessControl *IAccessControlTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _IAccessControl.Contract.contract.Transact(opts, method, params...) +} + +// GetRoleAdmin is a free data retrieval call binding the contract method 0x248a9ca3. +// +// Solidity: function getRoleAdmin(bytes32 role) view returns(bytes32) +func (_IAccessControl *IAccessControlCaller) GetRoleAdmin(opts *bind.CallOpts, role [32]byte) ([32]byte, error) { + var out []interface{} + err := _IAccessControl.contract.Call(opts, &out, "getRoleAdmin", role) + + if err != nil { + return *new([32]byte), err + } + + out0 := *abi.ConvertType(out[0], new([32]byte)).(*[32]byte) + + return out0, err + +} + +// GetRoleAdmin is a free data retrieval call binding the contract method 0x248a9ca3. +// +// Solidity: function getRoleAdmin(bytes32 role) view returns(bytes32) +func (_IAccessControl *IAccessControlSession) GetRoleAdmin(role [32]byte) ([32]byte, error) { + return _IAccessControl.Contract.GetRoleAdmin(&_IAccessControl.CallOpts, role) +} + +// GetRoleAdmin is a free data retrieval call binding the contract method 0x248a9ca3. +// +// Solidity: function getRoleAdmin(bytes32 role) view returns(bytes32) +func (_IAccessControl *IAccessControlCallerSession) GetRoleAdmin(role [32]byte) ([32]byte, error) { + return _IAccessControl.Contract.GetRoleAdmin(&_IAccessControl.CallOpts, role) +} + +// HasRole is a free data retrieval call binding the contract method 0x91d14854. +// +// Solidity: function hasRole(bytes32 role, address account) view returns(bool) +func (_IAccessControl *IAccessControlCaller) HasRole(opts *bind.CallOpts, role [32]byte, account common.Address) (bool, error) { + var out []interface{} + err := _IAccessControl.contract.Call(opts, &out, "hasRole", role, account) + + if err != nil { + return *new(bool), err + } + + out0 := *abi.ConvertType(out[0], new(bool)).(*bool) + + return out0, err + +} + +// HasRole is a free data retrieval call binding the contract method 0x91d14854. +// +// Solidity: function hasRole(bytes32 role, address account) view returns(bool) +func (_IAccessControl *IAccessControlSession) HasRole(role [32]byte, account common.Address) (bool, error) { + return _IAccessControl.Contract.HasRole(&_IAccessControl.CallOpts, role, account) +} + +// HasRole is a free data retrieval call binding the contract method 0x91d14854. +// +// Solidity: function hasRole(bytes32 role, address account) view returns(bool) +func (_IAccessControl *IAccessControlCallerSession) HasRole(role [32]byte, account common.Address) (bool, error) { + return _IAccessControl.Contract.HasRole(&_IAccessControl.CallOpts, role, account) +} + +// GrantRole is a paid mutator transaction binding the contract method 0x2f2ff15d. +// +// Solidity: function grantRole(bytes32 role, address account) returns() +func (_IAccessControl *IAccessControlTransactor) GrantRole(opts *bind.TransactOpts, role [32]byte, account common.Address) (*types.Transaction, error) { + return _IAccessControl.contract.Transact(opts, "grantRole", role, account) +} + +// GrantRole is a paid mutator transaction binding the contract method 0x2f2ff15d. +// +// Solidity: function grantRole(bytes32 role, address account) returns() +func (_IAccessControl *IAccessControlSession) GrantRole(role [32]byte, account common.Address) (*types.Transaction, error) { + return _IAccessControl.Contract.GrantRole(&_IAccessControl.TransactOpts, role, account) +} + +// GrantRole is a paid mutator transaction binding the contract method 0x2f2ff15d. +// +// Solidity: function grantRole(bytes32 role, address account) returns() +func (_IAccessControl *IAccessControlTransactorSession) GrantRole(role [32]byte, account common.Address) (*types.Transaction, error) { + return _IAccessControl.Contract.GrantRole(&_IAccessControl.TransactOpts, role, account) +} + +// RenounceRole is a paid mutator transaction binding the contract method 0x36568abe. +// +// Solidity: function renounceRole(bytes32 role, address callerConfirmation) returns() +func (_IAccessControl *IAccessControlTransactor) RenounceRole(opts *bind.TransactOpts, role [32]byte, callerConfirmation common.Address) (*types.Transaction, error) { + return _IAccessControl.contract.Transact(opts, "renounceRole", role, callerConfirmation) +} + +// RenounceRole is a paid mutator transaction binding the contract method 0x36568abe. +// +// Solidity: function renounceRole(bytes32 role, address callerConfirmation) returns() +func (_IAccessControl *IAccessControlSession) RenounceRole(role [32]byte, callerConfirmation common.Address) (*types.Transaction, error) { + return _IAccessControl.Contract.RenounceRole(&_IAccessControl.TransactOpts, role, callerConfirmation) +} + +// RenounceRole is a paid mutator transaction binding the contract method 0x36568abe. +// +// Solidity: function renounceRole(bytes32 role, address callerConfirmation) returns() +func (_IAccessControl *IAccessControlTransactorSession) RenounceRole(role [32]byte, callerConfirmation common.Address) (*types.Transaction, error) { + return _IAccessControl.Contract.RenounceRole(&_IAccessControl.TransactOpts, role, callerConfirmation) +} + +// RevokeRole is a paid mutator transaction binding the contract method 0xd547741f. +// +// Solidity: function revokeRole(bytes32 role, address account) returns() +func (_IAccessControl *IAccessControlTransactor) RevokeRole(opts *bind.TransactOpts, role [32]byte, account common.Address) (*types.Transaction, error) { + return _IAccessControl.contract.Transact(opts, "revokeRole", role, account) +} + +// RevokeRole is a paid mutator transaction binding the contract method 0xd547741f. +// +// Solidity: function revokeRole(bytes32 role, address account) returns() +func (_IAccessControl *IAccessControlSession) RevokeRole(role [32]byte, account common.Address) (*types.Transaction, error) { + return _IAccessControl.Contract.RevokeRole(&_IAccessControl.TransactOpts, role, account) +} + +// RevokeRole is a paid mutator transaction binding the contract method 0xd547741f. +// +// Solidity: function revokeRole(bytes32 role, address account) returns() +func (_IAccessControl *IAccessControlTransactorSession) RevokeRole(role [32]byte, account common.Address) (*types.Transaction, error) { + return _IAccessControl.Contract.RevokeRole(&_IAccessControl.TransactOpts, role, account) +} + +// IAccessControlRoleAdminChangedIterator is returned from FilterRoleAdminChanged and is used to iterate over the raw logs and unpacked data for RoleAdminChanged events raised by the IAccessControl contract. +type IAccessControlRoleAdminChangedIterator struct { + Event *IAccessControlRoleAdminChanged // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *IAccessControlRoleAdminChangedIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(IAccessControlRoleAdminChanged) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(IAccessControlRoleAdminChanged) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *IAccessControlRoleAdminChangedIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *IAccessControlRoleAdminChangedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// IAccessControlRoleAdminChanged represents a RoleAdminChanged event raised by the IAccessControl contract. +type IAccessControlRoleAdminChanged struct { + Role [32]byte + PreviousAdminRole [32]byte + NewAdminRole [32]byte + Raw types.Log // Blockchain specific contextual infos +} + +// FilterRoleAdminChanged is a free log retrieval operation binding the contract event 0xbd79b86ffe0ab8e8776151514217cd7cacd52c909f66475c3af44e129f0b00ff. +// +// Solidity: event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole) +func (_IAccessControl *IAccessControlFilterer) FilterRoleAdminChanged(opts *bind.FilterOpts, role [][32]byte, previousAdminRole [][32]byte, newAdminRole [][32]byte) (*IAccessControlRoleAdminChangedIterator, error) { + + var roleRule []interface{} + for _, roleItem := range role { + roleRule = append(roleRule, roleItem) + } + var previousAdminRoleRule []interface{} + for _, previousAdminRoleItem := range previousAdminRole { + previousAdminRoleRule = append(previousAdminRoleRule, previousAdminRoleItem) + } + var newAdminRoleRule []interface{} + for _, newAdminRoleItem := range newAdminRole { + newAdminRoleRule = append(newAdminRoleRule, newAdminRoleItem) + } + + logs, sub, err := _IAccessControl.contract.FilterLogs(opts, "RoleAdminChanged", roleRule, previousAdminRoleRule, newAdminRoleRule) + if err != nil { + return nil, err + } + return &IAccessControlRoleAdminChangedIterator{contract: _IAccessControl.contract, event: "RoleAdminChanged", logs: logs, sub: sub}, nil +} + +// WatchRoleAdminChanged is a free log subscription operation binding the contract event 0xbd79b86ffe0ab8e8776151514217cd7cacd52c909f66475c3af44e129f0b00ff. +// +// Solidity: event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole) +func (_IAccessControl *IAccessControlFilterer) WatchRoleAdminChanged(opts *bind.WatchOpts, sink chan<- *IAccessControlRoleAdminChanged, role [][32]byte, previousAdminRole [][32]byte, newAdminRole [][32]byte) (event.Subscription, error) { + + var roleRule []interface{} + for _, roleItem := range role { + roleRule = append(roleRule, roleItem) + } + var previousAdminRoleRule []interface{} + for _, previousAdminRoleItem := range previousAdminRole { + previousAdminRoleRule = append(previousAdminRoleRule, previousAdminRoleItem) + } + var newAdminRoleRule []interface{} + for _, newAdminRoleItem := range newAdminRole { + newAdminRoleRule = append(newAdminRoleRule, newAdminRoleItem) + } + + logs, sub, err := _IAccessControl.contract.WatchLogs(opts, "RoleAdminChanged", roleRule, previousAdminRoleRule, newAdminRoleRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(IAccessControlRoleAdminChanged) + if err := _IAccessControl.contract.UnpackLog(event, "RoleAdminChanged", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseRoleAdminChanged is a log parse operation binding the contract event 0xbd79b86ffe0ab8e8776151514217cd7cacd52c909f66475c3af44e129f0b00ff. +// +// Solidity: event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole) +func (_IAccessControl *IAccessControlFilterer) ParseRoleAdminChanged(log types.Log) (*IAccessControlRoleAdminChanged, error) { + event := new(IAccessControlRoleAdminChanged) + if err := _IAccessControl.contract.UnpackLog(event, "RoleAdminChanged", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// IAccessControlRoleGrantedIterator is returned from FilterRoleGranted and is used to iterate over the raw logs and unpacked data for RoleGranted events raised by the IAccessControl contract. +type IAccessControlRoleGrantedIterator struct { + Event *IAccessControlRoleGranted // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *IAccessControlRoleGrantedIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(IAccessControlRoleGranted) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(IAccessControlRoleGranted) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *IAccessControlRoleGrantedIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *IAccessControlRoleGrantedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// IAccessControlRoleGranted represents a RoleGranted event raised by the IAccessControl contract. +type IAccessControlRoleGranted struct { + Role [32]byte + Account common.Address + Sender common.Address + Raw types.Log // Blockchain specific contextual infos +} + +// FilterRoleGranted is a free log retrieval operation binding the contract event 0x2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d. +// +// Solidity: event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender) +func (_IAccessControl *IAccessControlFilterer) FilterRoleGranted(opts *bind.FilterOpts, role [][32]byte, account []common.Address, sender []common.Address) (*IAccessControlRoleGrantedIterator, error) { + + var roleRule []interface{} + for _, roleItem := range role { + roleRule = append(roleRule, roleItem) + } + var accountRule []interface{} + for _, accountItem := range account { + accountRule = append(accountRule, accountItem) + } + var senderRule []interface{} + for _, senderItem := range sender { + senderRule = append(senderRule, senderItem) + } + + logs, sub, err := _IAccessControl.contract.FilterLogs(opts, "RoleGranted", roleRule, accountRule, senderRule) + if err != nil { + return nil, err + } + return &IAccessControlRoleGrantedIterator{contract: _IAccessControl.contract, event: "RoleGranted", logs: logs, sub: sub}, nil +} + +// WatchRoleGranted is a free log subscription operation binding the contract event 0x2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d. +// +// Solidity: event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender) +func (_IAccessControl *IAccessControlFilterer) WatchRoleGranted(opts *bind.WatchOpts, sink chan<- *IAccessControlRoleGranted, role [][32]byte, account []common.Address, sender []common.Address) (event.Subscription, error) { + + var roleRule []interface{} + for _, roleItem := range role { + roleRule = append(roleRule, roleItem) + } + var accountRule []interface{} + for _, accountItem := range account { + accountRule = append(accountRule, accountItem) + } + var senderRule []interface{} + for _, senderItem := range sender { + senderRule = append(senderRule, senderItem) + } + + logs, sub, err := _IAccessControl.contract.WatchLogs(opts, "RoleGranted", roleRule, accountRule, senderRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(IAccessControlRoleGranted) + if err := _IAccessControl.contract.UnpackLog(event, "RoleGranted", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseRoleGranted is a log parse operation binding the contract event 0x2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d. +// +// Solidity: event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender) +func (_IAccessControl *IAccessControlFilterer) ParseRoleGranted(log types.Log) (*IAccessControlRoleGranted, error) { + event := new(IAccessControlRoleGranted) + if err := _IAccessControl.contract.UnpackLog(event, "RoleGranted", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// IAccessControlRoleRevokedIterator is returned from FilterRoleRevoked and is used to iterate over the raw logs and unpacked data for RoleRevoked events raised by the IAccessControl contract. +type IAccessControlRoleRevokedIterator struct { + Event *IAccessControlRoleRevoked // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *IAccessControlRoleRevokedIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(IAccessControlRoleRevoked) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(IAccessControlRoleRevoked) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *IAccessControlRoleRevokedIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *IAccessControlRoleRevokedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// IAccessControlRoleRevoked represents a RoleRevoked event raised by the IAccessControl contract. +type IAccessControlRoleRevoked struct { + Role [32]byte + Account common.Address + Sender common.Address + Raw types.Log // Blockchain specific contextual infos +} + +// FilterRoleRevoked is a free log retrieval operation binding the contract event 0xf6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b. +// +// Solidity: event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender) +func (_IAccessControl *IAccessControlFilterer) FilterRoleRevoked(opts *bind.FilterOpts, role [][32]byte, account []common.Address, sender []common.Address) (*IAccessControlRoleRevokedIterator, error) { + + var roleRule []interface{} + for _, roleItem := range role { + roleRule = append(roleRule, roleItem) + } + var accountRule []interface{} + for _, accountItem := range account { + accountRule = append(accountRule, accountItem) + } + var senderRule []interface{} + for _, senderItem := range sender { + senderRule = append(senderRule, senderItem) + } + + logs, sub, err := _IAccessControl.contract.FilterLogs(opts, "RoleRevoked", roleRule, accountRule, senderRule) + if err != nil { + return nil, err + } + return &IAccessControlRoleRevokedIterator{contract: _IAccessControl.contract, event: "RoleRevoked", logs: logs, sub: sub}, nil +} + +// WatchRoleRevoked is a free log subscription operation binding the contract event 0xf6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b. +// +// Solidity: event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender) +func (_IAccessControl *IAccessControlFilterer) WatchRoleRevoked(opts *bind.WatchOpts, sink chan<- *IAccessControlRoleRevoked, role [][32]byte, account []common.Address, sender []common.Address) (event.Subscription, error) { + + var roleRule []interface{} + for _, roleItem := range role { + roleRule = append(roleRule, roleItem) + } + var accountRule []interface{} + for _, accountItem := range account { + accountRule = append(accountRule, accountItem) + } + var senderRule []interface{} + for _, senderItem := range sender { + senderRule = append(senderRule, senderItem) + } + + logs, sub, err := _IAccessControl.contract.WatchLogs(opts, "RoleRevoked", roleRule, accountRule, senderRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(IAccessControlRoleRevoked) + if err := _IAccessControl.contract.UnpackLog(event, "RoleRevoked", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseRoleRevoked is a log parse operation binding the contract event 0xf6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b. +// +// Solidity: event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender) +func (_IAccessControl *IAccessControlFilterer) ParseRoleRevoked(log types.Log) (*IAccessControlRoleRevoked, error) { + event := new(IAccessControlRoleRevoked) + if err := _IAccessControl.contract.UnpackLog(event, "RoleRevoked", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// IAccessControlEnumerableMetaData contains all meta data concerning the IAccessControlEnumerable contract. +var IAccessControlEnumerableMetaData = &bind.MetaData{ + ABI: "[{\"inputs\":[],\"name\":\"AccessControlBadConfirmation\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"neededRole\",\"type\":\"bytes32\"}],\"name\":\"AccessControlUnauthorizedAccount\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"previousAdminRole\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"newAdminRole\",\"type\":\"bytes32\"}],\"name\":\"RoleAdminChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleGranted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleRevoked\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"}],\"name\":\"getRoleAdmin\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"index\",\"type\":\"uint256\"}],\"name\":\"getRoleMember\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"}],\"name\":\"getRoleMemberCount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"grantRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"hasRole\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"callerConfirmation\",\"type\":\"address\"}],\"name\":\"renounceRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"revokeRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", + Sigs: map[string]string{ + "248a9ca3": "getRoleAdmin(bytes32)", + "9010d07c": "getRoleMember(bytes32,uint256)", + "ca15c873": "getRoleMemberCount(bytes32)", + "2f2ff15d": "grantRole(bytes32,address)", + "91d14854": "hasRole(bytes32,address)", + "36568abe": "renounceRole(bytes32,address)", + "d547741f": "revokeRole(bytes32,address)", + }, +} + +// IAccessControlEnumerableABI is the input ABI used to generate the binding from. +// Deprecated: Use IAccessControlEnumerableMetaData.ABI instead. +var IAccessControlEnumerableABI = IAccessControlEnumerableMetaData.ABI + +// Deprecated: Use IAccessControlEnumerableMetaData.Sigs instead. +// IAccessControlEnumerableFuncSigs maps the 4-byte function signature to its string representation. +var IAccessControlEnumerableFuncSigs = IAccessControlEnumerableMetaData.Sigs + +// IAccessControlEnumerable is an auto generated Go binding around an Ethereum contract. +type IAccessControlEnumerable struct { + IAccessControlEnumerableCaller // Read-only binding to the contract + IAccessControlEnumerableTransactor // Write-only binding to the contract + IAccessControlEnumerableFilterer // Log filterer for contract events +} + +// IAccessControlEnumerableCaller is an auto generated read-only Go binding around an Ethereum contract. +type IAccessControlEnumerableCaller struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// IAccessControlEnumerableTransactor is an auto generated write-only Go binding around an Ethereum contract. +type IAccessControlEnumerableTransactor struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// IAccessControlEnumerableFilterer is an auto generated log filtering Go binding around an Ethereum contract events. +type IAccessControlEnumerableFilterer struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// IAccessControlEnumerableSession is an auto generated Go binding around an Ethereum contract, +// with pre-set call and transact options. +type IAccessControlEnumerableSession struct { + Contract *IAccessControlEnumerable // Generic contract binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// IAccessControlEnumerableCallerSession is an auto generated read-only Go binding around an Ethereum contract, +// with pre-set call options. +type IAccessControlEnumerableCallerSession struct { + Contract *IAccessControlEnumerableCaller // Generic contract caller binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session +} + +// IAccessControlEnumerableTransactorSession is an auto generated write-only Go binding around an Ethereum contract, +// with pre-set transact options. +type IAccessControlEnumerableTransactorSession struct { + Contract *IAccessControlEnumerableTransactor // Generic contract transactor binding to set the session for + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// IAccessControlEnumerableRaw is an auto generated low-level Go binding around an Ethereum contract. +type IAccessControlEnumerableRaw struct { + Contract *IAccessControlEnumerable // Generic contract binding to access the raw methods on +} + +// IAccessControlEnumerableCallerRaw is an auto generated low-level read-only Go binding around an Ethereum contract. +type IAccessControlEnumerableCallerRaw struct { + Contract *IAccessControlEnumerableCaller // Generic read-only contract binding to access the raw methods on +} + +// IAccessControlEnumerableTransactorRaw is an auto generated low-level write-only Go binding around an Ethereum contract. +type IAccessControlEnumerableTransactorRaw struct { + Contract *IAccessControlEnumerableTransactor // Generic write-only contract binding to access the raw methods on +} + +// NewIAccessControlEnumerable creates a new instance of IAccessControlEnumerable, bound to a specific deployed contract. +func NewIAccessControlEnumerable(address common.Address, backend bind.ContractBackend) (*IAccessControlEnumerable, error) { + contract, err := bindIAccessControlEnumerable(address, backend, backend, backend) + if err != nil { + return nil, err + } + return &IAccessControlEnumerable{IAccessControlEnumerableCaller: IAccessControlEnumerableCaller{contract: contract}, IAccessControlEnumerableTransactor: IAccessControlEnumerableTransactor{contract: contract}, IAccessControlEnumerableFilterer: IAccessControlEnumerableFilterer{contract: contract}}, nil +} + +// NewIAccessControlEnumerableCaller creates a new read-only instance of IAccessControlEnumerable, bound to a specific deployed contract. +func NewIAccessControlEnumerableCaller(address common.Address, caller bind.ContractCaller) (*IAccessControlEnumerableCaller, error) { + contract, err := bindIAccessControlEnumerable(address, caller, nil, nil) + if err != nil { + return nil, err + } + return &IAccessControlEnumerableCaller{contract: contract}, nil +} + +// NewIAccessControlEnumerableTransactor creates a new write-only instance of IAccessControlEnumerable, bound to a specific deployed contract. +func NewIAccessControlEnumerableTransactor(address common.Address, transactor bind.ContractTransactor) (*IAccessControlEnumerableTransactor, error) { + contract, err := bindIAccessControlEnumerable(address, nil, transactor, nil) + if err != nil { + return nil, err + } + return &IAccessControlEnumerableTransactor{contract: contract}, nil +} + +// NewIAccessControlEnumerableFilterer creates a new log filterer instance of IAccessControlEnumerable, bound to a specific deployed contract. +func NewIAccessControlEnumerableFilterer(address common.Address, filterer bind.ContractFilterer) (*IAccessControlEnumerableFilterer, error) { + contract, err := bindIAccessControlEnumerable(address, nil, nil, filterer) + if err != nil { + return nil, err + } + return &IAccessControlEnumerableFilterer{contract: contract}, nil +} + +// bindIAccessControlEnumerable binds a generic wrapper to an already deployed contract. +func bindIAccessControlEnumerable(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) { + parsed, err := IAccessControlEnumerableMetaData.GetAbi() + if err != nil { + return nil, err + } + return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil +} + +// Call invokes the (constant) contract method with params as input values and +// sets the output to result. The result type might be a single field for simple +// returns, a slice of interfaces for anonymous returns and a struct for named +// returns. +func (_IAccessControlEnumerable *IAccessControlEnumerableRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _IAccessControlEnumerable.Contract.IAccessControlEnumerableCaller.contract.Call(opts, result, method, params...) +} + +// Transfer initiates a plain transaction to move funds to the contract, calling +// its default method if one is available. +func (_IAccessControlEnumerable *IAccessControlEnumerableRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _IAccessControlEnumerable.Contract.IAccessControlEnumerableTransactor.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_IAccessControlEnumerable *IAccessControlEnumerableRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _IAccessControlEnumerable.Contract.IAccessControlEnumerableTransactor.contract.Transact(opts, method, params...) +} + +// Call invokes the (constant) contract method with params as input values and +// sets the output to result. The result type might be a single field for simple +// returns, a slice of interfaces for anonymous returns and a struct for named +// returns. +func (_IAccessControlEnumerable *IAccessControlEnumerableCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _IAccessControlEnumerable.Contract.contract.Call(opts, result, method, params...) +} + +// Transfer initiates a plain transaction to move funds to the contract, calling +// its default method if one is available. +func (_IAccessControlEnumerable *IAccessControlEnumerableTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _IAccessControlEnumerable.Contract.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_IAccessControlEnumerable *IAccessControlEnumerableTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _IAccessControlEnumerable.Contract.contract.Transact(opts, method, params...) +} + +// GetRoleAdmin is a free data retrieval call binding the contract method 0x248a9ca3. +// +// Solidity: function getRoleAdmin(bytes32 role) view returns(bytes32) +func (_IAccessControlEnumerable *IAccessControlEnumerableCaller) GetRoleAdmin(opts *bind.CallOpts, role [32]byte) ([32]byte, error) { + var out []interface{} + err := _IAccessControlEnumerable.contract.Call(opts, &out, "getRoleAdmin", role) + + if err != nil { + return *new([32]byte), err + } + + out0 := *abi.ConvertType(out[0], new([32]byte)).(*[32]byte) + + return out0, err + +} + +// GetRoleAdmin is a free data retrieval call binding the contract method 0x248a9ca3. +// +// Solidity: function getRoleAdmin(bytes32 role) view returns(bytes32) +func (_IAccessControlEnumerable *IAccessControlEnumerableSession) GetRoleAdmin(role [32]byte) ([32]byte, error) { + return _IAccessControlEnumerable.Contract.GetRoleAdmin(&_IAccessControlEnumerable.CallOpts, role) +} + +// GetRoleAdmin is a free data retrieval call binding the contract method 0x248a9ca3. +// +// Solidity: function getRoleAdmin(bytes32 role) view returns(bytes32) +func (_IAccessControlEnumerable *IAccessControlEnumerableCallerSession) GetRoleAdmin(role [32]byte) ([32]byte, error) { + return _IAccessControlEnumerable.Contract.GetRoleAdmin(&_IAccessControlEnumerable.CallOpts, role) +} + +// GetRoleMember is a free data retrieval call binding the contract method 0x9010d07c. +// +// Solidity: function getRoleMember(bytes32 role, uint256 index) view returns(address) +func (_IAccessControlEnumerable *IAccessControlEnumerableCaller) GetRoleMember(opts *bind.CallOpts, role [32]byte, index *big.Int) (common.Address, error) { + var out []interface{} + err := _IAccessControlEnumerable.contract.Call(opts, &out, "getRoleMember", role, index) + + if err != nil { + return *new(common.Address), err + } + + out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) + + return out0, err + +} + +// GetRoleMember is a free data retrieval call binding the contract method 0x9010d07c. +// +// Solidity: function getRoleMember(bytes32 role, uint256 index) view returns(address) +func (_IAccessControlEnumerable *IAccessControlEnumerableSession) GetRoleMember(role [32]byte, index *big.Int) (common.Address, error) { + return _IAccessControlEnumerable.Contract.GetRoleMember(&_IAccessControlEnumerable.CallOpts, role, index) +} + +// GetRoleMember is a free data retrieval call binding the contract method 0x9010d07c. +// +// Solidity: function getRoleMember(bytes32 role, uint256 index) view returns(address) +func (_IAccessControlEnumerable *IAccessControlEnumerableCallerSession) GetRoleMember(role [32]byte, index *big.Int) (common.Address, error) { + return _IAccessControlEnumerable.Contract.GetRoleMember(&_IAccessControlEnumerable.CallOpts, role, index) +} + +// GetRoleMemberCount is a free data retrieval call binding the contract method 0xca15c873. +// +// Solidity: function getRoleMemberCount(bytes32 role) view returns(uint256) +func (_IAccessControlEnumerable *IAccessControlEnumerableCaller) GetRoleMemberCount(opts *bind.CallOpts, role [32]byte) (*big.Int, error) { + var out []interface{} + err := _IAccessControlEnumerable.contract.Call(opts, &out, "getRoleMemberCount", role) + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// GetRoleMemberCount is a free data retrieval call binding the contract method 0xca15c873. +// +// Solidity: function getRoleMemberCount(bytes32 role) view returns(uint256) +func (_IAccessControlEnumerable *IAccessControlEnumerableSession) GetRoleMemberCount(role [32]byte) (*big.Int, error) { + return _IAccessControlEnumerable.Contract.GetRoleMemberCount(&_IAccessControlEnumerable.CallOpts, role) +} + +// GetRoleMemberCount is a free data retrieval call binding the contract method 0xca15c873. +// +// Solidity: function getRoleMemberCount(bytes32 role) view returns(uint256) +func (_IAccessControlEnumerable *IAccessControlEnumerableCallerSession) GetRoleMemberCount(role [32]byte) (*big.Int, error) { + return _IAccessControlEnumerable.Contract.GetRoleMemberCount(&_IAccessControlEnumerable.CallOpts, role) +} + +// HasRole is a free data retrieval call binding the contract method 0x91d14854. +// +// Solidity: function hasRole(bytes32 role, address account) view returns(bool) +func (_IAccessControlEnumerable *IAccessControlEnumerableCaller) HasRole(opts *bind.CallOpts, role [32]byte, account common.Address) (bool, error) { + var out []interface{} + err := _IAccessControlEnumerable.contract.Call(opts, &out, "hasRole", role, account) + + if err != nil { + return *new(bool), err + } + + out0 := *abi.ConvertType(out[0], new(bool)).(*bool) + + return out0, err + +} + +// HasRole is a free data retrieval call binding the contract method 0x91d14854. +// +// Solidity: function hasRole(bytes32 role, address account) view returns(bool) +func (_IAccessControlEnumerable *IAccessControlEnumerableSession) HasRole(role [32]byte, account common.Address) (bool, error) { + return _IAccessControlEnumerable.Contract.HasRole(&_IAccessControlEnumerable.CallOpts, role, account) +} + +// HasRole is a free data retrieval call binding the contract method 0x91d14854. +// +// Solidity: function hasRole(bytes32 role, address account) view returns(bool) +func (_IAccessControlEnumerable *IAccessControlEnumerableCallerSession) HasRole(role [32]byte, account common.Address) (bool, error) { + return _IAccessControlEnumerable.Contract.HasRole(&_IAccessControlEnumerable.CallOpts, role, account) +} + +// GrantRole is a paid mutator transaction binding the contract method 0x2f2ff15d. +// +// Solidity: function grantRole(bytes32 role, address account) returns() +func (_IAccessControlEnumerable *IAccessControlEnumerableTransactor) GrantRole(opts *bind.TransactOpts, role [32]byte, account common.Address) (*types.Transaction, error) { + return _IAccessControlEnumerable.contract.Transact(opts, "grantRole", role, account) +} + +// GrantRole is a paid mutator transaction binding the contract method 0x2f2ff15d. +// +// Solidity: function grantRole(bytes32 role, address account) returns() +func (_IAccessControlEnumerable *IAccessControlEnumerableSession) GrantRole(role [32]byte, account common.Address) (*types.Transaction, error) { + return _IAccessControlEnumerable.Contract.GrantRole(&_IAccessControlEnumerable.TransactOpts, role, account) +} + +// GrantRole is a paid mutator transaction binding the contract method 0x2f2ff15d. +// +// Solidity: function grantRole(bytes32 role, address account) returns() +func (_IAccessControlEnumerable *IAccessControlEnumerableTransactorSession) GrantRole(role [32]byte, account common.Address) (*types.Transaction, error) { + return _IAccessControlEnumerable.Contract.GrantRole(&_IAccessControlEnumerable.TransactOpts, role, account) +} + +// RenounceRole is a paid mutator transaction binding the contract method 0x36568abe. +// +// Solidity: function renounceRole(bytes32 role, address callerConfirmation) returns() +func (_IAccessControlEnumerable *IAccessControlEnumerableTransactor) RenounceRole(opts *bind.TransactOpts, role [32]byte, callerConfirmation common.Address) (*types.Transaction, error) { + return _IAccessControlEnumerable.contract.Transact(opts, "renounceRole", role, callerConfirmation) +} + +// RenounceRole is a paid mutator transaction binding the contract method 0x36568abe. +// +// Solidity: function renounceRole(bytes32 role, address callerConfirmation) returns() +func (_IAccessControlEnumerable *IAccessControlEnumerableSession) RenounceRole(role [32]byte, callerConfirmation common.Address) (*types.Transaction, error) { + return _IAccessControlEnumerable.Contract.RenounceRole(&_IAccessControlEnumerable.TransactOpts, role, callerConfirmation) +} + +// RenounceRole is a paid mutator transaction binding the contract method 0x36568abe. +// +// Solidity: function renounceRole(bytes32 role, address callerConfirmation) returns() +func (_IAccessControlEnumerable *IAccessControlEnumerableTransactorSession) RenounceRole(role [32]byte, callerConfirmation common.Address) (*types.Transaction, error) { + return _IAccessControlEnumerable.Contract.RenounceRole(&_IAccessControlEnumerable.TransactOpts, role, callerConfirmation) +} + +// RevokeRole is a paid mutator transaction binding the contract method 0xd547741f. +// +// Solidity: function revokeRole(bytes32 role, address account) returns() +func (_IAccessControlEnumerable *IAccessControlEnumerableTransactor) RevokeRole(opts *bind.TransactOpts, role [32]byte, account common.Address) (*types.Transaction, error) { + return _IAccessControlEnumerable.contract.Transact(opts, "revokeRole", role, account) +} + +// RevokeRole is a paid mutator transaction binding the contract method 0xd547741f. +// +// Solidity: function revokeRole(bytes32 role, address account) returns() +func (_IAccessControlEnumerable *IAccessControlEnumerableSession) RevokeRole(role [32]byte, account common.Address) (*types.Transaction, error) { + return _IAccessControlEnumerable.Contract.RevokeRole(&_IAccessControlEnumerable.TransactOpts, role, account) +} + +// RevokeRole is a paid mutator transaction binding the contract method 0xd547741f. +// +// Solidity: function revokeRole(bytes32 role, address account) returns() +func (_IAccessControlEnumerable *IAccessControlEnumerableTransactorSession) RevokeRole(role [32]byte, account common.Address) (*types.Transaction, error) { + return _IAccessControlEnumerable.Contract.RevokeRole(&_IAccessControlEnumerable.TransactOpts, role, account) +} + +// IAccessControlEnumerableRoleAdminChangedIterator is returned from FilterRoleAdminChanged and is used to iterate over the raw logs and unpacked data for RoleAdminChanged events raised by the IAccessControlEnumerable contract. +type IAccessControlEnumerableRoleAdminChangedIterator struct { + Event *IAccessControlEnumerableRoleAdminChanged // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *IAccessControlEnumerableRoleAdminChangedIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(IAccessControlEnumerableRoleAdminChanged) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(IAccessControlEnumerableRoleAdminChanged) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *IAccessControlEnumerableRoleAdminChangedIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *IAccessControlEnumerableRoleAdminChangedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// IAccessControlEnumerableRoleAdminChanged represents a RoleAdminChanged event raised by the IAccessControlEnumerable contract. +type IAccessControlEnumerableRoleAdminChanged struct { + Role [32]byte + PreviousAdminRole [32]byte + NewAdminRole [32]byte + Raw types.Log // Blockchain specific contextual infos +} + +// FilterRoleAdminChanged is a free log retrieval operation binding the contract event 0xbd79b86ffe0ab8e8776151514217cd7cacd52c909f66475c3af44e129f0b00ff. +// +// Solidity: event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole) +func (_IAccessControlEnumerable *IAccessControlEnumerableFilterer) FilterRoleAdminChanged(opts *bind.FilterOpts, role [][32]byte, previousAdminRole [][32]byte, newAdminRole [][32]byte) (*IAccessControlEnumerableRoleAdminChangedIterator, error) { + + var roleRule []interface{} + for _, roleItem := range role { + roleRule = append(roleRule, roleItem) + } + var previousAdminRoleRule []interface{} + for _, previousAdminRoleItem := range previousAdminRole { + previousAdminRoleRule = append(previousAdminRoleRule, previousAdminRoleItem) + } + var newAdminRoleRule []interface{} + for _, newAdminRoleItem := range newAdminRole { + newAdminRoleRule = append(newAdminRoleRule, newAdminRoleItem) + } + + logs, sub, err := _IAccessControlEnumerable.contract.FilterLogs(opts, "RoleAdminChanged", roleRule, previousAdminRoleRule, newAdminRoleRule) + if err != nil { + return nil, err + } + return &IAccessControlEnumerableRoleAdminChangedIterator{contract: _IAccessControlEnumerable.contract, event: "RoleAdminChanged", logs: logs, sub: sub}, nil +} + +// WatchRoleAdminChanged is a free log subscription operation binding the contract event 0xbd79b86ffe0ab8e8776151514217cd7cacd52c909f66475c3af44e129f0b00ff. +// +// Solidity: event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole) +func (_IAccessControlEnumerable *IAccessControlEnumerableFilterer) WatchRoleAdminChanged(opts *bind.WatchOpts, sink chan<- *IAccessControlEnumerableRoleAdminChanged, role [][32]byte, previousAdminRole [][32]byte, newAdminRole [][32]byte) (event.Subscription, error) { + + var roleRule []interface{} + for _, roleItem := range role { + roleRule = append(roleRule, roleItem) + } + var previousAdminRoleRule []interface{} + for _, previousAdminRoleItem := range previousAdminRole { + previousAdminRoleRule = append(previousAdminRoleRule, previousAdminRoleItem) + } + var newAdminRoleRule []interface{} + for _, newAdminRoleItem := range newAdminRole { + newAdminRoleRule = append(newAdminRoleRule, newAdminRoleItem) + } + + logs, sub, err := _IAccessControlEnumerable.contract.WatchLogs(opts, "RoleAdminChanged", roleRule, previousAdminRoleRule, newAdminRoleRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(IAccessControlEnumerableRoleAdminChanged) + if err := _IAccessControlEnumerable.contract.UnpackLog(event, "RoleAdminChanged", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseRoleAdminChanged is a log parse operation binding the contract event 0xbd79b86ffe0ab8e8776151514217cd7cacd52c909f66475c3af44e129f0b00ff. +// +// Solidity: event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole) +func (_IAccessControlEnumerable *IAccessControlEnumerableFilterer) ParseRoleAdminChanged(log types.Log) (*IAccessControlEnumerableRoleAdminChanged, error) { + event := new(IAccessControlEnumerableRoleAdminChanged) + if err := _IAccessControlEnumerable.contract.UnpackLog(event, "RoleAdminChanged", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// IAccessControlEnumerableRoleGrantedIterator is returned from FilterRoleGranted and is used to iterate over the raw logs and unpacked data for RoleGranted events raised by the IAccessControlEnumerable contract. +type IAccessControlEnumerableRoleGrantedIterator struct { + Event *IAccessControlEnumerableRoleGranted // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *IAccessControlEnumerableRoleGrantedIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(IAccessControlEnumerableRoleGranted) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(IAccessControlEnumerableRoleGranted) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *IAccessControlEnumerableRoleGrantedIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *IAccessControlEnumerableRoleGrantedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// IAccessControlEnumerableRoleGranted represents a RoleGranted event raised by the IAccessControlEnumerable contract. +type IAccessControlEnumerableRoleGranted struct { + Role [32]byte + Account common.Address + Sender common.Address + Raw types.Log // Blockchain specific contextual infos +} + +// FilterRoleGranted is a free log retrieval operation binding the contract event 0x2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d. +// +// Solidity: event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender) +func (_IAccessControlEnumerable *IAccessControlEnumerableFilterer) FilterRoleGranted(opts *bind.FilterOpts, role [][32]byte, account []common.Address, sender []common.Address) (*IAccessControlEnumerableRoleGrantedIterator, error) { + + var roleRule []interface{} + for _, roleItem := range role { + roleRule = append(roleRule, roleItem) + } + var accountRule []interface{} + for _, accountItem := range account { + accountRule = append(accountRule, accountItem) + } + var senderRule []interface{} + for _, senderItem := range sender { + senderRule = append(senderRule, senderItem) + } + + logs, sub, err := _IAccessControlEnumerable.contract.FilterLogs(opts, "RoleGranted", roleRule, accountRule, senderRule) + if err != nil { + return nil, err + } + return &IAccessControlEnumerableRoleGrantedIterator{contract: _IAccessControlEnumerable.contract, event: "RoleGranted", logs: logs, sub: sub}, nil +} + +// WatchRoleGranted is a free log subscription operation binding the contract event 0x2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d. +// +// Solidity: event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender) +func (_IAccessControlEnumerable *IAccessControlEnumerableFilterer) WatchRoleGranted(opts *bind.WatchOpts, sink chan<- *IAccessControlEnumerableRoleGranted, role [][32]byte, account []common.Address, sender []common.Address) (event.Subscription, error) { + + var roleRule []interface{} + for _, roleItem := range role { + roleRule = append(roleRule, roleItem) + } + var accountRule []interface{} + for _, accountItem := range account { + accountRule = append(accountRule, accountItem) + } + var senderRule []interface{} + for _, senderItem := range sender { + senderRule = append(senderRule, senderItem) + } + + logs, sub, err := _IAccessControlEnumerable.contract.WatchLogs(opts, "RoleGranted", roleRule, accountRule, senderRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(IAccessControlEnumerableRoleGranted) + if err := _IAccessControlEnumerable.contract.UnpackLog(event, "RoleGranted", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseRoleGranted is a log parse operation binding the contract event 0x2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d. +// +// Solidity: event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender) +func (_IAccessControlEnumerable *IAccessControlEnumerableFilterer) ParseRoleGranted(log types.Log) (*IAccessControlEnumerableRoleGranted, error) { + event := new(IAccessControlEnumerableRoleGranted) + if err := _IAccessControlEnumerable.contract.UnpackLog(event, "RoleGranted", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// IAccessControlEnumerableRoleRevokedIterator is returned from FilterRoleRevoked and is used to iterate over the raw logs and unpacked data for RoleRevoked events raised by the IAccessControlEnumerable contract. +type IAccessControlEnumerableRoleRevokedIterator struct { + Event *IAccessControlEnumerableRoleRevoked // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *IAccessControlEnumerableRoleRevokedIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(IAccessControlEnumerableRoleRevoked) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(IAccessControlEnumerableRoleRevoked) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *IAccessControlEnumerableRoleRevokedIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *IAccessControlEnumerableRoleRevokedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// IAccessControlEnumerableRoleRevoked represents a RoleRevoked event raised by the IAccessControlEnumerable contract. +type IAccessControlEnumerableRoleRevoked struct { + Role [32]byte + Account common.Address + Sender common.Address + Raw types.Log // Blockchain specific contextual infos +} + +// FilterRoleRevoked is a free log retrieval operation binding the contract event 0xf6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b. +// +// Solidity: event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender) +func (_IAccessControlEnumerable *IAccessControlEnumerableFilterer) FilterRoleRevoked(opts *bind.FilterOpts, role [][32]byte, account []common.Address, sender []common.Address) (*IAccessControlEnumerableRoleRevokedIterator, error) { + + var roleRule []interface{} + for _, roleItem := range role { + roleRule = append(roleRule, roleItem) + } + var accountRule []interface{} + for _, accountItem := range account { + accountRule = append(accountRule, accountItem) + } + var senderRule []interface{} + for _, senderItem := range sender { + senderRule = append(senderRule, senderItem) + } + + logs, sub, err := _IAccessControlEnumerable.contract.FilterLogs(opts, "RoleRevoked", roleRule, accountRule, senderRule) + if err != nil { + return nil, err + } + return &IAccessControlEnumerableRoleRevokedIterator{contract: _IAccessControlEnumerable.contract, event: "RoleRevoked", logs: logs, sub: sub}, nil +} + +// WatchRoleRevoked is a free log subscription operation binding the contract event 0xf6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b. +// +// Solidity: event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender) +func (_IAccessControlEnumerable *IAccessControlEnumerableFilterer) WatchRoleRevoked(opts *bind.WatchOpts, sink chan<- *IAccessControlEnumerableRoleRevoked, role [][32]byte, account []common.Address, sender []common.Address) (event.Subscription, error) { + + var roleRule []interface{} + for _, roleItem := range role { + roleRule = append(roleRule, roleItem) + } + var accountRule []interface{} + for _, accountItem := range account { + accountRule = append(accountRule, accountItem) + } + var senderRule []interface{} + for _, senderItem := range sender { + senderRule = append(senderRule, senderItem) + } + + logs, sub, err := _IAccessControlEnumerable.contract.WatchLogs(opts, "RoleRevoked", roleRule, accountRule, senderRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(IAccessControlEnumerableRoleRevoked) + if err := _IAccessControlEnumerable.contract.UnpackLog(event, "RoleRevoked", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseRoleRevoked is a log parse operation binding the contract event 0xf6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b. +// +// Solidity: event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender) +func (_IAccessControlEnumerable *IAccessControlEnumerableFilterer) ParseRoleRevoked(log types.Log) (*IAccessControlEnumerableRoleRevoked, error) { + event := new(IAccessControlEnumerableRoleRevoked) + if err := _IAccessControlEnumerable.contract.UnpackLog(event, "RoleRevoked", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// IAdminMetaData contains all meta data concerning the IAdmin contract. +var IAdminMetaData = &bind.MetaData{ + ABI: "[{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"oldChainGasAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newChainGasAmount\",\"type\":\"uint256\"}],\"name\":\"ChainGasAmountUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"oldFeeRate\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newFeeRate\",\"type\":\"uint256\"}],\"name\":\"FeeRateUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"FeesSwept\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"newChainGasAmount\",\"type\":\"uint256\"}],\"name\":\"setChainGasAmount\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"newFeeRate\",\"type\":\"uint256\"}],\"name\":\"setProtocolFeeRate\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"}],\"name\":\"sweepProtocolFees\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", + Sigs: map[string]string{ + "b250fe6b": "setChainGasAmount(uint256)", + "b13aa2d6": "setProtocolFeeRate(uint256)", + "06f333f2": "sweepProtocolFees(address,address)", + }, +} + +// IAdminABI is the input ABI used to generate the binding from. +// Deprecated: Use IAdminMetaData.ABI instead. +var IAdminABI = IAdminMetaData.ABI + +// Deprecated: Use IAdminMetaData.Sigs instead. +// IAdminFuncSigs maps the 4-byte function signature to its string representation. +var IAdminFuncSigs = IAdminMetaData.Sigs + +// IAdmin is an auto generated Go binding around an Ethereum contract. +type IAdmin struct { + IAdminCaller // Read-only binding to the contract + IAdminTransactor // Write-only binding to the contract + IAdminFilterer // Log filterer for contract events +} + +// IAdminCaller is an auto generated read-only Go binding around an Ethereum contract. +type IAdminCaller struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// IAdminTransactor is an auto generated write-only Go binding around an Ethereum contract. +type IAdminTransactor struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// IAdminFilterer is an auto generated log filtering Go binding around an Ethereum contract events. +type IAdminFilterer struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// IAdminSession is an auto generated Go binding around an Ethereum contract, +// with pre-set call and transact options. +type IAdminSession struct { + Contract *IAdmin // Generic contract binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// IAdminCallerSession is an auto generated read-only Go binding around an Ethereum contract, +// with pre-set call options. +type IAdminCallerSession struct { + Contract *IAdminCaller // Generic contract caller binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session +} + +// IAdminTransactorSession is an auto generated write-only Go binding around an Ethereum contract, +// with pre-set transact options. +type IAdminTransactorSession struct { + Contract *IAdminTransactor // Generic contract transactor binding to set the session for + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// IAdminRaw is an auto generated low-level Go binding around an Ethereum contract. +type IAdminRaw struct { + Contract *IAdmin // Generic contract binding to access the raw methods on +} + +// IAdminCallerRaw is an auto generated low-level read-only Go binding around an Ethereum contract. +type IAdminCallerRaw struct { + Contract *IAdminCaller // Generic read-only contract binding to access the raw methods on +} + +// IAdminTransactorRaw is an auto generated low-level write-only Go binding around an Ethereum contract. +type IAdminTransactorRaw struct { + Contract *IAdminTransactor // Generic write-only contract binding to access the raw methods on +} + +// NewIAdmin creates a new instance of IAdmin, bound to a specific deployed contract. +func NewIAdmin(address common.Address, backend bind.ContractBackend) (*IAdmin, error) { + contract, err := bindIAdmin(address, backend, backend, backend) + if err != nil { + return nil, err + } + return &IAdmin{IAdminCaller: IAdminCaller{contract: contract}, IAdminTransactor: IAdminTransactor{contract: contract}, IAdminFilterer: IAdminFilterer{contract: contract}}, nil +} + +// NewIAdminCaller creates a new read-only instance of IAdmin, bound to a specific deployed contract. +func NewIAdminCaller(address common.Address, caller bind.ContractCaller) (*IAdminCaller, error) { + contract, err := bindIAdmin(address, caller, nil, nil) + if err != nil { + return nil, err + } + return &IAdminCaller{contract: contract}, nil +} + +// NewIAdminTransactor creates a new write-only instance of IAdmin, bound to a specific deployed contract. +func NewIAdminTransactor(address common.Address, transactor bind.ContractTransactor) (*IAdminTransactor, error) { + contract, err := bindIAdmin(address, nil, transactor, nil) + if err != nil { + return nil, err + } + return &IAdminTransactor{contract: contract}, nil +} + +// NewIAdminFilterer creates a new log filterer instance of IAdmin, bound to a specific deployed contract. +func NewIAdminFilterer(address common.Address, filterer bind.ContractFilterer) (*IAdminFilterer, error) { + contract, err := bindIAdmin(address, nil, nil, filterer) + if err != nil { + return nil, err + } + return &IAdminFilterer{contract: contract}, nil +} + +// bindIAdmin binds a generic wrapper to an already deployed contract. +func bindIAdmin(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) { + parsed, err := IAdminMetaData.GetAbi() + if err != nil { + return nil, err + } + return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil +} + +// Call invokes the (constant) contract method with params as input values and +// sets the output to result. The result type might be a single field for simple +// returns, a slice of interfaces for anonymous returns and a struct for named +// returns. +func (_IAdmin *IAdminRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _IAdmin.Contract.IAdminCaller.contract.Call(opts, result, method, params...) +} + +// Transfer initiates a plain transaction to move funds to the contract, calling +// its default method if one is available. +func (_IAdmin *IAdminRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _IAdmin.Contract.IAdminTransactor.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_IAdmin *IAdminRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _IAdmin.Contract.IAdminTransactor.contract.Transact(opts, method, params...) +} + +// Call invokes the (constant) contract method with params as input values and +// sets the output to result. The result type might be a single field for simple +// returns, a slice of interfaces for anonymous returns and a struct for named +// returns. +func (_IAdmin *IAdminCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _IAdmin.Contract.contract.Call(opts, result, method, params...) +} + +// Transfer initiates a plain transaction to move funds to the contract, calling +// its default method if one is available. +func (_IAdmin *IAdminTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _IAdmin.Contract.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_IAdmin *IAdminTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _IAdmin.Contract.contract.Transact(opts, method, params...) +} + +// SetChainGasAmount is a paid mutator transaction binding the contract method 0xb250fe6b. +// +// Solidity: function setChainGasAmount(uint256 newChainGasAmount) returns() +func (_IAdmin *IAdminTransactor) SetChainGasAmount(opts *bind.TransactOpts, newChainGasAmount *big.Int) (*types.Transaction, error) { + return _IAdmin.contract.Transact(opts, "setChainGasAmount", newChainGasAmount) +} + +// SetChainGasAmount is a paid mutator transaction binding the contract method 0xb250fe6b. +// +// Solidity: function setChainGasAmount(uint256 newChainGasAmount) returns() +func (_IAdmin *IAdminSession) SetChainGasAmount(newChainGasAmount *big.Int) (*types.Transaction, error) { + return _IAdmin.Contract.SetChainGasAmount(&_IAdmin.TransactOpts, newChainGasAmount) +} + +// SetChainGasAmount is a paid mutator transaction binding the contract method 0xb250fe6b. +// +// Solidity: function setChainGasAmount(uint256 newChainGasAmount) returns() +func (_IAdmin *IAdminTransactorSession) SetChainGasAmount(newChainGasAmount *big.Int) (*types.Transaction, error) { + return _IAdmin.Contract.SetChainGasAmount(&_IAdmin.TransactOpts, newChainGasAmount) +} + +// SetProtocolFeeRate is a paid mutator transaction binding the contract method 0xb13aa2d6. +// +// Solidity: function setProtocolFeeRate(uint256 newFeeRate) returns() +func (_IAdmin *IAdminTransactor) SetProtocolFeeRate(opts *bind.TransactOpts, newFeeRate *big.Int) (*types.Transaction, error) { + return _IAdmin.contract.Transact(opts, "setProtocolFeeRate", newFeeRate) +} + +// SetProtocolFeeRate is a paid mutator transaction binding the contract method 0xb13aa2d6. +// +// Solidity: function setProtocolFeeRate(uint256 newFeeRate) returns() +func (_IAdmin *IAdminSession) SetProtocolFeeRate(newFeeRate *big.Int) (*types.Transaction, error) { + return _IAdmin.Contract.SetProtocolFeeRate(&_IAdmin.TransactOpts, newFeeRate) +} + +// SetProtocolFeeRate is a paid mutator transaction binding the contract method 0xb13aa2d6. +// +// Solidity: function setProtocolFeeRate(uint256 newFeeRate) returns() +func (_IAdmin *IAdminTransactorSession) SetProtocolFeeRate(newFeeRate *big.Int) (*types.Transaction, error) { + return _IAdmin.Contract.SetProtocolFeeRate(&_IAdmin.TransactOpts, newFeeRate) +} + +// SweepProtocolFees is a paid mutator transaction binding the contract method 0x06f333f2. +// +// Solidity: function sweepProtocolFees(address token, address recipient) returns() +func (_IAdmin *IAdminTransactor) SweepProtocolFees(opts *bind.TransactOpts, token common.Address, recipient common.Address) (*types.Transaction, error) { + return _IAdmin.contract.Transact(opts, "sweepProtocolFees", token, recipient) +} + +// SweepProtocolFees is a paid mutator transaction binding the contract method 0x06f333f2. +// +// Solidity: function sweepProtocolFees(address token, address recipient) returns() +func (_IAdmin *IAdminSession) SweepProtocolFees(token common.Address, recipient common.Address) (*types.Transaction, error) { + return _IAdmin.Contract.SweepProtocolFees(&_IAdmin.TransactOpts, token, recipient) +} + +// SweepProtocolFees is a paid mutator transaction binding the contract method 0x06f333f2. +// +// Solidity: function sweepProtocolFees(address token, address recipient) returns() +func (_IAdmin *IAdminTransactorSession) SweepProtocolFees(token common.Address, recipient common.Address) (*types.Transaction, error) { + return _IAdmin.Contract.SweepProtocolFees(&_IAdmin.TransactOpts, token, recipient) +} + +// IAdminChainGasAmountUpdatedIterator is returned from FilterChainGasAmountUpdated and is used to iterate over the raw logs and unpacked data for ChainGasAmountUpdated events raised by the IAdmin contract. +type IAdminChainGasAmountUpdatedIterator struct { + Event *IAdminChainGasAmountUpdated // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *IAdminChainGasAmountUpdatedIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(IAdminChainGasAmountUpdated) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(IAdminChainGasAmountUpdated) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *IAdminChainGasAmountUpdatedIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *IAdminChainGasAmountUpdatedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// IAdminChainGasAmountUpdated represents a ChainGasAmountUpdated event raised by the IAdmin contract. +type IAdminChainGasAmountUpdated struct { + OldChainGasAmount *big.Int + NewChainGasAmount *big.Int + Raw types.Log // Blockchain specific contextual infos +} + +// FilterChainGasAmountUpdated is a free log retrieval operation binding the contract event 0x5cf09b12f3f56b4c564d51b25b40360af6d795198adb61ae0806a36c294323fa. +// +// Solidity: event ChainGasAmountUpdated(uint256 oldChainGasAmount, uint256 newChainGasAmount) +func (_IAdmin *IAdminFilterer) FilterChainGasAmountUpdated(opts *bind.FilterOpts) (*IAdminChainGasAmountUpdatedIterator, error) { + + logs, sub, err := _IAdmin.contract.FilterLogs(opts, "ChainGasAmountUpdated") + if err != nil { + return nil, err + } + return &IAdminChainGasAmountUpdatedIterator{contract: _IAdmin.contract, event: "ChainGasAmountUpdated", logs: logs, sub: sub}, nil +} + +// WatchChainGasAmountUpdated is a free log subscription operation binding the contract event 0x5cf09b12f3f56b4c564d51b25b40360af6d795198adb61ae0806a36c294323fa. +// +// Solidity: event ChainGasAmountUpdated(uint256 oldChainGasAmount, uint256 newChainGasAmount) +func (_IAdmin *IAdminFilterer) WatchChainGasAmountUpdated(opts *bind.WatchOpts, sink chan<- *IAdminChainGasAmountUpdated) (event.Subscription, error) { + + logs, sub, err := _IAdmin.contract.WatchLogs(opts, "ChainGasAmountUpdated") + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(IAdminChainGasAmountUpdated) + if err := _IAdmin.contract.UnpackLog(event, "ChainGasAmountUpdated", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseChainGasAmountUpdated is a log parse operation binding the contract event 0x5cf09b12f3f56b4c564d51b25b40360af6d795198adb61ae0806a36c294323fa. +// +// Solidity: event ChainGasAmountUpdated(uint256 oldChainGasAmount, uint256 newChainGasAmount) +func (_IAdmin *IAdminFilterer) ParseChainGasAmountUpdated(log types.Log) (*IAdminChainGasAmountUpdated, error) { + event := new(IAdminChainGasAmountUpdated) + if err := _IAdmin.contract.UnpackLog(event, "ChainGasAmountUpdated", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// IAdminFeeRateUpdatedIterator is returned from FilterFeeRateUpdated and is used to iterate over the raw logs and unpacked data for FeeRateUpdated events raised by the IAdmin contract. +type IAdminFeeRateUpdatedIterator struct { + Event *IAdminFeeRateUpdated // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *IAdminFeeRateUpdatedIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(IAdminFeeRateUpdated) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(IAdminFeeRateUpdated) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *IAdminFeeRateUpdatedIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *IAdminFeeRateUpdatedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// IAdminFeeRateUpdated represents a FeeRateUpdated event raised by the IAdmin contract. +type IAdminFeeRateUpdated struct { + OldFeeRate *big.Int + NewFeeRate *big.Int + Raw types.Log // Blockchain specific contextual infos +} + +// FilterFeeRateUpdated is a free log retrieval operation binding the contract event 0x14914da2bf76024616fbe1859783fcd4dbddcb179b1f3a854949fbf920dcb957. +// +// Solidity: event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate) +func (_IAdmin *IAdminFilterer) FilterFeeRateUpdated(opts *bind.FilterOpts) (*IAdminFeeRateUpdatedIterator, error) { + + logs, sub, err := _IAdmin.contract.FilterLogs(opts, "FeeRateUpdated") + if err != nil { + return nil, err + } + return &IAdminFeeRateUpdatedIterator{contract: _IAdmin.contract, event: "FeeRateUpdated", logs: logs, sub: sub}, nil +} + +// WatchFeeRateUpdated is a free log subscription operation binding the contract event 0x14914da2bf76024616fbe1859783fcd4dbddcb179b1f3a854949fbf920dcb957. +// +// Solidity: event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate) +func (_IAdmin *IAdminFilterer) WatchFeeRateUpdated(opts *bind.WatchOpts, sink chan<- *IAdminFeeRateUpdated) (event.Subscription, error) { + + logs, sub, err := _IAdmin.contract.WatchLogs(opts, "FeeRateUpdated") + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(IAdminFeeRateUpdated) + if err := _IAdmin.contract.UnpackLog(event, "FeeRateUpdated", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseFeeRateUpdated is a log parse operation binding the contract event 0x14914da2bf76024616fbe1859783fcd4dbddcb179b1f3a854949fbf920dcb957. +// +// Solidity: event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate) +func (_IAdmin *IAdminFilterer) ParseFeeRateUpdated(log types.Log) (*IAdminFeeRateUpdated, error) { + event := new(IAdminFeeRateUpdated) + if err := _IAdmin.contract.UnpackLog(event, "FeeRateUpdated", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// IAdminFeesSweptIterator is returned from FilterFeesSwept and is used to iterate over the raw logs and unpacked data for FeesSwept events raised by the IAdmin contract. +type IAdminFeesSweptIterator struct { + Event *IAdminFeesSwept // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *IAdminFeesSweptIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(IAdminFeesSwept) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(IAdminFeesSwept) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *IAdminFeesSweptIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *IAdminFeesSweptIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// IAdminFeesSwept represents a FeesSwept event raised by the IAdmin contract. +type IAdminFeesSwept struct { + Token common.Address + Recipient common.Address + Amount *big.Int + Raw types.Log // Blockchain specific contextual infos +} + +// FilterFeesSwept is a free log retrieval operation binding the contract event 0x244e51bc38c1452fa8aaf487bcb4bca36c2baa3a5fbdb776b1eabd8dc6d277cd. +// +// Solidity: event FeesSwept(address token, address recipient, uint256 amount) +func (_IAdmin *IAdminFilterer) FilterFeesSwept(opts *bind.FilterOpts) (*IAdminFeesSweptIterator, error) { + + logs, sub, err := _IAdmin.contract.FilterLogs(opts, "FeesSwept") + if err != nil { + return nil, err + } + return &IAdminFeesSweptIterator{contract: _IAdmin.contract, event: "FeesSwept", logs: logs, sub: sub}, nil +} + +// WatchFeesSwept is a free log subscription operation binding the contract event 0x244e51bc38c1452fa8aaf487bcb4bca36c2baa3a5fbdb776b1eabd8dc6d277cd. +// +// Solidity: event FeesSwept(address token, address recipient, uint256 amount) +func (_IAdmin *IAdminFilterer) WatchFeesSwept(opts *bind.WatchOpts, sink chan<- *IAdminFeesSwept) (event.Subscription, error) { + + logs, sub, err := _IAdmin.contract.WatchLogs(opts, "FeesSwept") + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(IAdminFeesSwept) + if err := _IAdmin.contract.UnpackLog(event, "FeesSwept", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseFeesSwept is a log parse operation binding the contract event 0x244e51bc38c1452fa8aaf487bcb4bca36c2baa3a5fbdb776b1eabd8dc6d277cd. +// +// Solidity: event FeesSwept(address token, address recipient, uint256 amount) +func (_IAdmin *IAdminFilterer) ParseFeesSwept(log types.Log) (*IAdminFeesSwept, error) { + event := new(IAdminFeesSwept) + if err := _IAdmin.contract.UnpackLog(event, "FeesSwept", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// IERC165MetaData contains all meta data concerning the IERC165 contract. +var IERC165MetaData = &bind.MetaData{ + ABI: "[{\"inputs\":[{\"internalType\":\"bytes4\",\"name\":\"interfaceId\",\"type\":\"bytes4\"}],\"name\":\"supportsInterface\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"}]", + Sigs: map[string]string{ + "01ffc9a7": "supportsInterface(bytes4)", + }, +} + +// IERC165ABI is the input ABI used to generate the binding from. +// Deprecated: Use IERC165MetaData.ABI instead. +var IERC165ABI = IERC165MetaData.ABI + +// Deprecated: Use IERC165MetaData.Sigs instead. +// IERC165FuncSigs maps the 4-byte function signature to its string representation. +var IERC165FuncSigs = IERC165MetaData.Sigs + +// IERC165 is an auto generated Go binding around an Ethereum contract. +type IERC165 struct { + IERC165Caller // Read-only binding to the contract + IERC165Transactor // Write-only binding to the contract + IERC165Filterer // Log filterer for contract events +} + +// IERC165Caller is an auto generated read-only Go binding around an Ethereum contract. +type IERC165Caller struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// IERC165Transactor is an auto generated write-only Go binding around an Ethereum contract. +type IERC165Transactor struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// IERC165Filterer is an auto generated log filtering Go binding around an Ethereum contract events. +type IERC165Filterer struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// IERC165Session is an auto generated Go binding around an Ethereum contract, +// with pre-set call and transact options. +type IERC165Session struct { + Contract *IERC165 // Generic contract binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// IERC165CallerSession is an auto generated read-only Go binding around an Ethereum contract, +// with pre-set call options. +type IERC165CallerSession struct { + Contract *IERC165Caller // Generic contract caller binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session +} + +// IERC165TransactorSession is an auto generated write-only Go binding around an Ethereum contract, +// with pre-set transact options. +type IERC165TransactorSession struct { + Contract *IERC165Transactor // Generic contract transactor binding to set the session for + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// IERC165Raw is an auto generated low-level Go binding around an Ethereum contract. +type IERC165Raw struct { + Contract *IERC165 // Generic contract binding to access the raw methods on +} + +// IERC165CallerRaw is an auto generated low-level read-only Go binding around an Ethereum contract. +type IERC165CallerRaw struct { + Contract *IERC165Caller // Generic read-only contract binding to access the raw methods on +} + +// IERC165TransactorRaw is an auto generated low-level write-only Go binding around an Ethereum contract. +type IERC165TransactorRaw struct { + Contract *IERC165Transactor // Generic write-only contract binding to access the raw methods on +} + +// NewIERC165 creates a new instance of IERC165, bound to a specific deployed contract. +func NewIERC165(address common.Address, backend bind.ContractBackend) (*IERC165, error) { + contract, err := bindIERC165(address, backend, backend, backend) + if err != nil { + return nil, err + } + return &IERC165{IERC165Caller: IERC165Caller{contract: contract}, IERC165Transactor: IERC165Transactor{contract: contract}, IERC165Filterer: IERC165Filterer{contract: contract}}, nil +} + +// NewIERC165Caller creates a new read-only instance of IERC165, bound to a specific deployed contract. +func NewIERC165Caller(address common.Address, caller bind.ContractCaller) (*IERC165Caller, error) { + contract, err := bindIERC165(address, caller, nil, nil) + if err != nil { + return nil, err + } + return &IERC165Caller{contract: contract}, nil +} + +// NewIERC165Transactor creates a new write-only instance of IERC165, bound to a specific deployed contract. +func NewIERC165Transactor(address common.Address, transactor bind.ContractTransactor) (*IERC165Transactor, error) { + contract, err := bindIERC165(address, nil, transactor, nil) + if err != nil { + return nil, err + } + return &IERC165Transactor{contract: contract}, nil +} + +// NewIERC165Filterer creates a new log filterer instance of IERC165, bound to a specific deployed contract. +func NewIERC165Filterer(address common.Address, filterer bind.ContractFilterer) (*IERC165Filterer, error) { + contract, err := bindIERC165(address, nil, nil, filterer) + if err != nil { + return nil, err + } + return &IERC165Filterer{contract: contract}, nil +} + +// bindIERC165 binds a generic wrapper to an already deployed contract. +func bindIERC165(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) { + parsed, err := IERC165MetaData.GetAbi() + if err != nil { + return nil, err + } + return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil +} + +// Call invokes the (constant) contract method with params as input values and +// sets the output to result. The result type might be a single field for simple +// returns, a slice of interfaces for anonymous returns and a struct for named +// returns. +func (_IERC165 *IERC165Raw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _IERC165.Contract.IERC165Caller.contract.Call(opts, result, method, params...) +} + +// Transfer initiates a plain transaction to move funds to the contract, calling +// its default method if one is available. +func (_IERC165 *IERC165Raw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _IERC165.Contract.IERC165Transactor.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_IERC165 *IERC165Raw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _IERC165.Contract.IERC165Transactor.contract.Transact(opts, method, params...) +} + +// Call invokes the (constant) contract method with params as input values and +// sets the output to result. The result type might be a single field for simple +// returns, a slice of interfaces for anonymous returns and a struct for named +// returns. +func (_IERC165 *IERC165CallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _IERC165.Contract.contract.Call(opts, result, method, params...) +} + +// Transfer initiates a plain transaction to move funds to the contract, calling +// its default method if one is available. +func (_IERC165 *IERC165TransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _IERC165.Contract.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_IERC165 *IERC165TransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _IERC165.Contract.contract.Transact(opts, method, params...) +} + +// SupportsInterface is a free data retrieval call binding the contract method 0x01ffc9a7. +// +// Solidity: function supportsInterface(bytes4 interfaceId) view returns(bool) +func (_IERC165 *IERC165Caller) SupportsInterface(opts *bind.CallOpts, interfaceId [4]byte) (bool, error) { + var out []interface{} + err := _IERC165.contract.Call(opts, &out, "supportsInterface", interfaceId) + + if err != nil { + return *new(bool), err + } + + out0 := *abi.ConvertType(out[0], new(bool)).(*bool) + + return out0, err + +} + +// SupportsInterface is a free data retrieval call binding the contract method 0x01ffc9a7. +// +// Solidity: function supportsInterface(bytes4 interfaceId) view returns(bool) +func (_IERC165 *IERC165Session) SupportsInterface(interfaceId [4]byte) (bool, error) { + return _IERC165.Contract.SupportsInterface(&_IERC165.CallOpts, interfaceId) +} + +// SupportsInterface is a free data retrieval call binding the contract method 0x01ffc9a7. +// +// Solidity: function supportsInterface(bytes4 interfaceId) view returns(bool) +func (_IERC165 *IERC165CallerSession) SupportsInterface(interfaceId [4]byte) (bool, error) { + return _IERC165.Contract.SupportsInterface(&_IERC165.CallOpts, interfaceId) +} + +// IERC20MetaData contains all meta data concerning the IERC20 contract. +var IERC20MetaData = &bind.MetaData{ + ABI: "[{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"Approval\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"Transfer\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"}],\"name\":\"allowance\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"approve\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"balanceOf\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"totalSupply\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"transfer\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"transferFrom\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", + Sigs: map[string]string{ + "dd62ed3e": "allowance(address,address)", + "095ea7b3": "approve(address,uint256)", + "70a08231": "balanceOf(address)", + "18160ddd": "totalSupply()", + "a9059cbb": "transfer(address,uint256)", + "23b872dd": "transferFrom(address,address,uint256)", + }, +} + +// IERC20ABI is the input ABI used to generate the binding from. +// Deprecated: Use IERC20MetaData.ABI instead. +var IERC20ABI = IERC20MetaData.ABI + +// Deprecated: Use IERC20MetaData.Sigs instead. +// IERC20FuncSigs maps the 4-byte function signature to its string representation. +var IERC20FuncSigs = IERC20MetaData.Sigs + +// IERC20 is an auto generated Go binding around an Ethereum contract. +type IERC20 struct { + IERC20Caller // Read-only binding to the contract + IERC20Transactor // Write-only binding to the contract + IERC20Filterer // Log filterer for contract events +} + +// IERC20Caller is an auto generated read-only Go binding around an Ethereum contract. +type IERC20Caller struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// IERC20Transactor is an auto generated write-only Go binding around an Ethereum contract. +type IERC20Transactor struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// IERC20Filterer is an auto generated log filtering Go binding around an Ethereum contract events. +type IERC20Filterer struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// IERC20Session is an auto generated Go binding around an Ethereum contract, +// with pre-set call and transact options. +type IERC20Session struct { + Contract *IERC20 // Generic contract binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// IERC20CallerSession is an auto generated read-only Go binding around an Ethereum contract, +// with pre-set call options. +type IERC20CallerSession struct { + Contract *IERC20Caller // Generic contract caller binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session +} + +// IERC20TransactorSession is an auto generated write-only Go binding around an Ethereum contract, +// with pre-set transact options. +type IERC20TransactorSession struct { + Contract *IERC20Transactor // Generic contract transactor binding to set the session for + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// IERC20Raw is an auto generated low-level Go binding around an Ethereum contract. +type IERC20Raw struct { + Contract *IERC20 // Generic contract binding to access the raw methods on +} + +// IERC20CallerRaw is an auto generated low-level read-only Go binding around an Ethereum contract. +type IERC20CallerRaw struct { + Contract *IERC20Caller // Generic read-only contract binding to access the raw methods on +} + +// IERC20TransactorRaw is an auto generated low-level write-only Go binding around an Ethereum contract. +type IERC20TransactorRaw struct { + Contract *IERC20Transactor // Generic write-only contract binding to access the raw methods on +} + +// NewIERC20 creates a new instance of IERC20, bound to a specific deployed contract. +func NewIERC20(address common.Address, backend bind.ContractBackend) (*IERC20, error) { + contract, err := bindIERC20(address, backend, backend, backend) + if err != nil { + return nil, err + } + return &IERC20{IERC20Caller: IERC20Caller{contract: contract}, IERC20Transactor: IERC20Transactor{contract: contract}, IERC20Filterer: IERC20Filterer{contract: contract}}, nil +} + +// NewIERC20Caller creates a new read-only instance of IERC20, bound to a specific deployed contract. +func NewIERC20Caller(address common.Address, caller bind.ContractCaller) (*IERC20Caller, error) { + contract, err := bindIERC20(address, caller, nil, nil) + if err != nil { + return nil, err + } + return &IERC20Caller{contract: contract}, nil +} + +// NewIERC20Transactor creates a new write-only instance of IERC20, bound to a specific deployed contract. +func NewIERC20Transactor(address common.Address, transactor bind.ContractTransactor) (*IERC20Transactor, error) { + contract, err := bindIERC20(address, nil, transactor, nil) + if err != nil { + return nil, err + } + return &IERC20Transactor{contract: contract}, nil +} + +// NewIERC20Filterer creates a new log filterer instance of IERC20, bound to a specific deployed contract. +func NewIERC20Filterer(address common.Address, filterer bind.ContractFilterer) (*IERC20Filterer, error) { + contract, err := bindIERC20(address, nil, nil, filterer) + if err != nil { + return nil, err + } + return &IERC20Filterer{contract: contract}, nil +} + +// bindIERC20 binds a generic wrapper to an already deployed contract. +func bindIERC20(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) { + parsed, err := IERC20MetaData.GetAbi() + if err != nil { + return nil, err + } + return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil +} + +// Call invokes the (constant) contract method with params as input values and +// sets the output to result. The result type might be a single field for simple +// returns, a slice of interfaces for anonymous returns and a struct for named +// returns. +func (_IERC20 *IERC20Raw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _IERC20.Contract.IERC20Caller.contract.Call(opts, result, method, params...) +} + +// Transfer initiates a plain transaction to move funds to the contract, calling +// its default method if one is available. +func (_IERC20 *IERC20Raw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _IERC20.Contract.IERC20Transactor.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_IERC20 *IERC20Raw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _IERC20.Contract.IERC20Transactor.contract.Transact(opts, method, params...) +} + +// Call invokes the (constant) contract method with params as input values and +// sets the output to result. The result type might be a single field for simple +// returns, a slice of interfaces for anonymous returns and a struct for named +// returns. +func (_IERC20 *IERC20CallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _IERC20.Contract.contract.Call(opts, result, method, params...) +} + +// Transfer initiates a plain transaction to move funds to the contract, calling +// its default method if one is available. +func (_IERC20 *IERC20TransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _IERC20.Contract.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_IERC20 *IERC20TransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _IERC20.Contract.contract.Transact(opts, method, params...) +} + +// Allowance is a free data retrieval call binding the contract method 0xdd62ed3e. +// +// Solidity: function allowance(address owner, address spender) view returns(uint256) +func (_IERC20 *IERC20Caller) Allowance(opts *bind.CallOpts, owner common.Address, spender common.Address) (*big.Int, error) { + var out []interface{} + err := _IERC20.contract.Call(opts, &out, "allowance", owner, spender) + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// Allowance is a free data retrieval call binding the contract method 0xdd62ed3e. +// +// Solidity: function allowance(address owner, address spender) view returns(uint256) +func (_IERC20 *IERC20Session) Allowance(owner common.Address, spender common.Address) (*big.Int, error) { + return _IERC20.Contract.Allowance(&_IERC20.CallOpts, owner, spender) +} + +// Allowance is a free data retrieval call binding the contract method 0xdd62ed3e. +// +// Solidity: function allowance(address owner, address spender) view returns(uint256) +func (_IERC20 *IERC20CallerSession) Allowance(owner common.Address, spender common.Address) (*big.Int, error) { + return _IERC20.Contract.Allowance(&_IERC20.CallOpts, owner, spender) +} + +// BalanceOf is a free data retrieval call binding the contract method 0x70a08231. +// +// Solidity: function balanceOf(address account) view returns(uint256) +func (_IERC20 *IERC20Caller) BalanceOf(opts *bind.CallOpts, account common.Address) (*big.Int, error) { + var out []interface{} + err := _IERC20.contract.Call(opts, &out, "balanceOf", account) + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// BalanceOf is a free data retrieval call binding the contract method 0x70a08231. +// +// Solidity: function balanceOf(address account) view returns(uint256) +func (_IERC20 *IERC20Session) BalanceOf(account common.Address) (*big.Int, error) { + return _IERC20.Contract.BalanceOf(&_IERC20.CallOpts, account) +} + +// BalanceOf is a free data retrieval call binding the contract method 0x70a08231. +// +// Solidity: function balanceOf(address account) view returns(uint256) +func (_IERC20 *IERC20CallerSession) BalanceOf(account common.Address) (*big.Int, error) { + return _IERC20.Contract.BalanceOf(&_IERC20.CallOpts, account) +} + +// TotalSupply is a free data retrieval call binding the contract method 0x18160ddd. +// +// Solidity: function totalSupply() view returns(uint256) +func (_IERC20 *IERC20Caller) TotalSupply(opts *bind.CallOpts) (*big.Int, error) { + var out []interface{} + err := _IERC20.contract.Call(opts, &out, "totalSupply") + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// TotalSupply is a free data retrieval call binding the contract method 0x18160ddd. +// +// Solidity: function totalSupply() view returns(uint256) +func (_IERC20 *IERC20Session) TotalSupply() (*big.Int, error) { + return _IERC20.Contract.TotalSupply(&_IERC20.CallOpts) +} + +// TotalSupply is a free data retrieval call binding the contract method 0x18160ddd. +// +// Solidity: function totalSupply() view returns(uint256) +func (_IERC20 *IERC20CallerSession) TotalSupply() (*big.Int, error) { + return _IERC20.Contract.TotalSupply(&_IERC20.CallOpts) +} + +// Approve is a paid mutator transaction binding the contract method 0x095ea7b3. +// +// Solidity: function approve(address spender, uint256 value) returns(bool) +func (_IERC20 *IERC20Transactor) Approve(opts *bind.TransactOpts, spender common.Address, value *big.Int) (*types.Transaction, error) { + return _IERC20.contract.Transact(opts, "approve", spender, value) +} + +// Approve is a paid mutator transaction binding the contract method 0x095ea7b3. +// +// Solidity: function approve(address spender, uint256 value) returns(bool) +func (_IERC20 *IERC20Session) Approve(spender common.Address, value *big.Int) (*types.Transaction, error) { + return _IERC20.Contract.Approve(&_IERC20.TransactOpts, spender, value) +} + +// Approve is a paid mutator transaction binding the contract method 0x095ea7b3. +// +// Solidity: function approve(address spender, uint256 value) returns(bool) +func (_IERC20 *IERC20TransactorSession) Approve(spender common.Address, value *big.Int) (*types.Transaction, error) { + return _IERC20.Contract.Approve(&_IERC20.TransactOpts, spender, value) +} + +// Transfer is a paid mutator transaction binding the contract method 0xa9059cbb. +// +// Solidity: function transfer(address to, uint256 value) returns(bool) +func (_IERC20 *IERC20Transactor) Transfer(opts *bind.TransactOpts, to common.Address, value *big.Int) (*types.Transaction, error) { + return _IERC20.contract.Transact(opts, "transfer", to, value) +} + +// Transfer is a paid mutator transaction binding the contract method 0xa9059cbb. +// +// Solidity: function transfer(address to, uint256 value) returns(bool) +func (_IERC20 *IERC20Session) Transfer(to common.Address, value *big.Int) (*types.Transaction, error) { + return _IERC20.Contract.Transfer(&_IERC20.TransactOpts, to, value) +} + +// Transfer is a paid mutator transaction binding the contract method 0xa9059cbb. +// +// Solidity: function transfer(address to, uint256 value) returns(bool) +func (_IERC20 *IERC20TransactorSession) Transfer(to common.Address, value *big.Int) (*types.Transaction, error) { + return _IERC20.Contract.Transfer(&_IERC20.TransactOpts, to, value) +} + +// TransferFrom is a paid mutator transaction binding the contract method 0x23b872dd. +// +// Solidity: function transferFrom(address from, address to, uint256 value) returns(bool) +func (_IERC20 *IERC20Transactor) TransferFrom(opts *bind.TransactOpts, from common.Address, to common.Address, value *big.Int) (*types.Transaction, error) { + return _IERC20.contract.Transact(opts, "transferFrom", from, to, value) +} + +// TransferFrom is a paid mutator transaction binding the contract method 0x23b872dd. +// +// Solidity: function transferFrom(address from, address to, uint256 value) returns(bool) +func (_IERC20 *IERC20Session) TransferFrom(from common.Address, to common.Address, value *big.Int) (*types.Transaction, error) { + return _IERC20.Contract.TransferFrom(&_IERC20.TransactOpts, from, to, value) +} + +// TransferFrom is a paid mutator transaction binding the contract method 0x23b872dd. +// +// Solidity: function transferFrom(address from, address to, uint256 value) returns(bool) +func (_IERC20 *IERC20TransactorSession) TransferFrom(from common.Address, to common.Address, value *big.Int) (*types.Transaction, error) { + return _IERC20.Contract.TransferFrom(&_IERC20.TransactOpts, from, to, value) +} + +// IERC20ApprovalIterator is returned from FilterApproval and is used to iterate over the raw logs and unpacked data for Approval events raised by the IERC20 contract. +type IERC20ApprovalIterator struct { + Event *IERC20Approval // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *IERC20ApprovalIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(IERC20Approval) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(IERC20Approval) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *IERC20ApprovalIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *IERC20ApprovalIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// IERC20Approval represents a Approval event raised by the IERC20 contract. +type IERC20Approval struct { + Owner common.Address + Spender common.Address + Value *big.Int + Raw types.Log // Blockchain specific contextual infos +} + +// FilterApproval is a free log retrieval operation binding the contract event 0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925. +// +// Solidity: event Approval(address indexed owner, address indexed spender, uint256 value) +func (_IERC20 *IERC20Filterer) FilterApproval(opts *bind.FilterOpts, owner []common.Address, spender []common.Address) (*IERC20ApprovalIterator, error) { + + var ownerRule []interface{} + for _, ownerItem := range owner { + ownerRule = append(ownerRule, ownerItem) + } + var spenderRule []interface{} + for _, spenderItem := range spender { + spenderRule = append(spenderRule, spenderItem) + } + + logs, sub, err := _IERC20.contract.FilterLogs(opts, "Approval", ownerRule, spenderRule) + if err != nil { + return nil, err + } + return &IERC20ApprovalIterator{contract: _IERC20.contract, event: "Approval", logs: logs, sub: sub}, nil +} + +// WatchApproval is a free log subscription operation binding the contract event 0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925. +// +// Solidity: event Approval(address indexed owner, address indexed spender, uint256 value) +func (_IERC20 *IERC20Filterer) WatchApproval(opts *bind.WatchOpts, sink chan<- *IERC20Approval, owner []common.Address, spender []common.Address) (event.Subscription, error) { + + var ownerRule []interface{} + for _, ownerItem := range owner { + ownerRule = append(ownerRule, ownerItem) + } + var spenderRule []interface{} + for _, spenderItem := range spender { + spenderRule = append(spenderRule, spenderItem) + } + + logs, sub, err := _IERC20.contract.WatchLogs(opts, "Approval", ownerRule, spenderRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(IERC20Approval) + if err := _IERC20.contract.UnpackLog(event, "Approval", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseApproval is a log parse operation binding the contract event 0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925. +// +// Solidity: event Approval(address indexed owner, address indexed spender, uint256 value) +func (_IERC20 *IERC20Filterer) ParseApproval(log types.Log) (*IERC20Approval, error) { + event := new(IERC20Approval) + if err := _IERC20.contract.UnpackLog(event, "Approval", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// IERC20TransferIterator is returned from FilterTransfer and is used to iterate over the raw logs and unpacked data for Transfer events raised by the IERC20 contract. +type IERC20TransferIterator struct { + Event *IERC20Transfer // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *IERC20TransferIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(IERC20Transfer) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(IERC20Transfer) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *IERC20TransferIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *IERC20TransferIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// IERC20Transfer represents a Transfer event raised by the IERC20 contract. +type IERC20Transfer struct { + From common.Address + To common.Address + Value *big.Int + Raw types.Log // Blockchain specific contextual infos +} + +// FilterTransfer is a free log retrieval operation binding the contract event 0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef. +// +// Solidity: event Transfer(address indexed from, address indexed to, uint256 value) +func (_IERC20 *IERC20Filterer) FilterTransfer(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*IERC20TransferIterator, error) { + + var fromRule []interface{} + for _, fromItem := range from { + fromRule = append(fromRule, fromItem) + } + var toRule []interface{} + for _, toItem := range to { + toRule = append(toRule, toItem) + } + + logs, sub, err := _IERC20.contract.FilterLogs(opts, "Transfer", fromRule, toRule) + if err != nil { + return nil, err + } + return &IERC20TransferIterator{contract: _IERC20.contract, event: "Transfer", logs: logs, sub: sub}, nil +} + +// WatchTransfer is a free log subscription operation binding the contract event 0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef. +// +// Solidity: event Transfer(address indexed from, address indexed to, uint256 value) +func (_IERC20 *IERC20Filterer) WatchTransfer(opts *bind.WatchOpts, sink chan<- *IERC20Transfer, from []common.Address, to []common.Address) (event.Subscription, error) { + + var fromRule []interface{} + for _, fromItem := range from { + fromRule = append(fromRule, fromItem) + } + var toRule []interface{} + for _, toItem := range to { + toRule = append(toRule, toItem) + } + + logs, sub, err := _IERC20.contract.WatchLogs(opts, "Transfer", fromRule, toRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(IERC20Transfer) + if err := _IERC20.contract.UnpackLog(event, "Transfer", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseTransfer is a log parse operation binding the contract event 0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef. +// +// Solidity: event Transfer(address indexed from, address indexed to, uint256 value) +func (_IERC20 *IERC20Filterer) ParseTransfer(log types.Log) (*IERC20Transfer, error) { + event := new(IERC20Transfer) + if err := _IERC20.contract.UnpackLog(event, "Transfer", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// IERC20PermitMetaData contains all meta data concerning the IERC20Permit contract. +var IERC20PermitMetaData = &bind.MetaData{ + ABI: "[{\"inputs\":[],\"name\":\"DOMAIN_SEPARATOR\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"}],\"name\":\"nonces\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"},{\"internalType\":\"uint8\",\"name\":\"v\",\"type\":\"uint8\"},{\"internalType\":\"bytes32\",\"name\":\"r\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"s\",\"type\":\"bytes32\"}],\"name\":\"permit\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", + Sigs: map[string]string{ + "3644e515": "DOMAIN_SEPARATOR()", + "7ecebe00": "nonces(address)", + "d505accf": "permit(address,address,uint256,uint256,uint8,bytes32,bytes32)", + }, +} + +// IERC20PermitABI is the input ABI used to generate the binding from. +// Deprecated: Use IERC20PermitMetaData.ABI instead. +var IERC20PermitABI = IERC20PermitMetaData.ABI + +// Deprecated: Use IERC20PermitMetaData.Sigs instead. +// IERC20PermitFuncSigs maps the 4-byte function signature to its string representation. +var IERC20PermitFuncSigs = IERC20PermitMetaData.Sigs + +// IERC20Permit is an auto generated Go binding around an Ethereum contract. +type IERC20Permit struct { + IERC20PermitCaller // Read-only binding to the contract + IERC20PermitTransactor // Write-only binding to the contract + IERC20PermitFilterer // Log filterer for contract events +} + +// IERC20PermitCaller is an auto generated read-only Go binding around an Ethereum contract. +type IERC20PermitCaller struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// IERC20PermitTransactor is an auto generated write-only Go binding around an Ethereum contract. +type IERC20PermitTransactor struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// IERC20PermitFilterer is an auto generated log filtering Go binding around an Ethereum contract events. +type IERC20PermitFilterer struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// IERC20PermitSession is an auto generated Go binding around an Ethereum contract, +// with pre-set call and transact options. +type IERC20PermitSession struct { + Contract *IERC20Permit // Generic contract binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// IERC20PermitCallerSession is an auto generated read-only Go binding around an Ethereum contract, +// with pre-set call options. +type IERC20PermitCallerSession struct { + Contract *IERC20PermitCaller // Generic contract caller binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session +} + +// IERC20PermitTransactorSession is an auto generated write-only Go binding around an Ethereum contract, +// with pre-set transact options. +type IERC20PermitTransactorSession struct { + Contract *IERC20PermitTransactor // Generic contract transactor binding to set the session for + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// IERC20PermitRaw is an auto generated low-level Go binding around an Ethereum contract. +type IERC20PermitRaw struct { + Contract *IERC20Permit // Generic contract binding to access the raw methods on +} + +// IERC20PermitCallerRaw is an auto generated low-level read-only Go binding around an Ethereum contract. +type IERC20PermitCallerRaw struct { + Contract *IERC20PermitCaller // Generic read-only contract binding to access the raw methods on +} + +// IERC20PermitTransactorRaw is an auto generated low-level write-only Go binding around an Ethereum contract. +type IERC20PermitTransactorRaw struct { + Contract *IERC20PermitTransactor // Generic write-only contract binding to access the raw methods on +} + +// NewIERC20Permit creates a new instance of IERC20Permit, bound to a specific deployed contract. +func NewIERC20Permit(address common.Address, backend bind.ContractBackend) (*IERC20Permit, error) { + contract, err := bindIERC20Permit(address, backend, backend, backend) + if err != nil { + return nil, err + } + return &IERC20Permit{IERC20PermitCaller: IERC20PermitCaller{contract: contract}, IERC20PermitTransactor: IERC20PermitTransactor{contract: contract}, IERC20PermitFilterer: IERC20PermitFilterer{contract: contract}}, nil +} + +// NewIERC20PermitCaller creates a new read-only instance of IERC20Permit, bound to a specific deployed contract. +func NewIERC20PermitCaller(address common.Address, caller bind.ContractCaller) (*IERC20PermitCaller, error) { + contract, err := bindIERC20Permit(address, caller, nil, nil) + if err != nil { + return nil, err + } + return &IERC20PermitCaller{contract: contract}, nil +} + +// NewIERC20PermitTransactor creates a new write-only instance of IERC20Permit, bound to a specific deployed contract. +func NewIERC20PermitTransactor(address common.Address, transactor bind.ContractTransactor) (*IERC20PermitTransactor, error) { + contract, err := bindIERC20Permit(address, nil, transactor, nil) + if err != nil { + return nil, err + } + return &IERC20PermitTransactor{contract: contract}, nil +} + +// NewIERC20PermitFilterer creates a new log filterer instance of IERC20Permit, bound to a specific deployed contract. +func NewIERC20PermitFilterer(address common.Address, filterer bind.ContractFilterer) (*IERC20PermitFilterer, error) { + contract, err := bindIERC20Permit(address, nil, nil, filterer) + if err != nil { + return nil, err + } + return &IERC20PermitFilterer{contract: contract}, nil +} + +// bindIERC20Permit binds a generic wrapper to an already deployed contract. +func bindIERC20Permit(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) { + parsed, err := IERC20PermitMetaData.GetAbi() + if err != nil { + return nil, err + } + return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil +} + +// Call invokes the (constant) contract method with params as input values and +// sets the output to result. The result type might be a single field for simple +// returns, a slice of interfaces for anonymous returns and a struct for named +// returns. +func (_IERC20Permit *IERC20PermitRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _IERC20Permit.Contract.IERC20PermitCaller.contract.Call(opts, result, method, params...) +} + +// Transfer initiates a plain transaction to move funds to the contract, calling +// its default method if one is available. +func (_IERC20Permit *IERC20PermitRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _IERC20Permit.Contract.IERC20PermitTransactor.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_IERC20Permit *IERC20PermitRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _IERC20Permit.Contract.IERC20PermitTransactor.contract.Transact(opts, method, params...) +} + +// Call invokes the (constant) contract method with params as input values and +// sets the output to result. The result type might be a single field for simple +// returns, a slice of interfaces for anonymous returns and a struct for named +// returns. +func (_IERC20Permit *IERC20PermitCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _IERC20Permit.Contract.contract.Call(opts, result, method, params...) +} + +// Transfer initiates a plain transaction to move funds to the contract, calling +// its default method if one is available. +func (_IERC20Permit *IERC20PermitTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _IERC20Permit.Contract.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_IERC20Permit *IERC20PermitTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _IERC20Permit.Contract.contract.Transact(opts, method, params...) +} + +// DOMAINSEPARATOR is a free data retrieval call binding the contract method 0x3644e515. +// +// Solidity: function DOMAIN_SEPARATOR() view returns(bytes32) +func (_IERC20Permit *IERC20PermitCaller) DOMAINSEPARATOR(opts *bind.CallOpts) ([32]byte, error) { + var out []interface{} + err := _IERC20Permit.contract.Call(opts, &out, "DOMAIN_SEPARATOR") + + if err != nil { + return *new([32]byte), err + } + + out0 := *abi.ConvertType(out[0], new([32]byte)).(*[32]byte) + + return out0, err + +} + +// DOMAINSEPARATOR is a free data retrieval call binding the contract method 0x3644e515. +// +// Solidity: function DOMAIN_SEPARATOR() view returns(bytes32) +func (_IERC20Permit *IERC20PermitSession) DOMAINSEPARATOR() ([32]byte, error) { + return _IERC20Permit.Contract.DOMAINSEPARATOR(&_IERC20Permit.CallOpts) +} + +// DOMAINSEPARATOR is a free data retrieval call binding the contract method 0x3644e515. +// +// Solidity: function DOMAIN_SEPARATOR() view returns(bytes32) +func (_IERC20Permit *IERC20PermitCallerSession) DOMAINSEPARATOR() ([32]byte, error) { + return _IERC20Permit.Contract.DOMAINSEPARATOR(&_IERC20Permit.CallOpts) +} + +// Nonces is a free data retrieval call binding the contract method 0x7ecebe00. +// +// Solidity: function nonces(address owner) view returns(uint256) +func (_IERC20Permit *IERC20PermitCaller) Nonces(opts *bind.CallOpts, owner common.Address) (*big.Int, error) { + var out []interface{} + err := _IERC20Permit.contract.Call(opts, &out, "nonces", owner) + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// Nonces is a free data retrieval call binding the contract method 0x7ecebe00. +// +// Solidity: function nonces(address owner) view returns(uint256) +func (_IERC20Permit *IERC20PermitSession) Nonces(owner common.Address) (*big.Int, error) { + return _IERC20Permit.Contract.Nonces(&_IERC20Permit.CallOpts, owner) +} + +// Nonces is a free data retrieval call binding the contract method 0x7ecebe00. +// +// Solidity: function nonces(address owner) view returns(uint256) +func (_IERC20Permit *IERC20PermitCallerSession) Nonces(owner common.Address) (*big.Int, error) { + return _IERC20Permit.Contract.Nonces(&_IERC20Permit.CallOpts, owner) +} + +// Permit is a paid mutator transaction binding the contract method 0xd505accf. +// +// Solidity: function permit(address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) returns() +func (_IERC20Permit *IERC20PermitTransactor) Permit(opts *bind.TransactOpts, owner common.Address, spender common.Address, value *big.Int, deadline *big.Int, v uint8, r [32]byte, s [32]byte) (*types.Transaction, error) { + return _IERC20Permit.contract.Transact(opts, "permit", owner, spender, value, deadline, v, r, s) +} + +// Permit is a paid mutator transaction binding the contract method 0xd505accf. +// +// Solidity: function permit(address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) returns() +func (_IERC20Permit *IERC20PermitSession) Permit(owner common.Address, spender common.Address, value *big.Int, deadline *big.Int, v uint8, r [32]byte, s [32]byte) (*types.Transaction, error) { + return _IERC20Permit.Contract.Permit(&_IERC20Permit.TransactOpts, owner, spender, value, deadline, v, r, s) +} + +// Permit is a paid mutator transaction binding the contract method 0xd505accf. +// +// Solidity: function permit(address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) returns() +func (_IERC20Permit *IERC20PermitTransactorSession) Permit(owner common.Address, spender common.Address, value *big.Int, deadline *big.Int, v uint8, r [32]byte, s [32]byte) (*types.Transaction, error) { + return _IERC20Permit.Contract.Permit(&_IERC20Permit.TransactOpts, owner, spender, value, deadline, v, r, s) +} + +// IFastBridgeMetaData contains all meta data concerning the IFastBridge contract. +var IFastBridgeMetaData = &bind.MetaData{ + ABI: "[{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"BridgeDepositClaimed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"BridgeDepositRefunded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"name\":\"BridgeProofDisputed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"transactionHash\",\"type\":\"bytes32\"}],\"name\":\"BridgeProofProvided\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"originChainId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"chainGasAmount\",\"type\":\"uint256\"}],\"name\":\"BridgeRelayed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"destChainId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"sendChainGas\",\"type\":\"bool\"}],\"name\":\"BridgeRequested\",\"type\":\"event\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"dstChainId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"sendChainGas\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"}],\"internalType\":\"structIFastBridge.BridgeParams\",\"name\":\"params\",\"type\":\"tuple\"}],\"name\":\"bridge\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"name\":\"canClaim\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"claim\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"}],\"name\":\"dispute\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"getBridgeTransaction\",\"outputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"originChainId\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"destChainId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"originSender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destRecipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"originFeeAmount\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"sendChainGas\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"}],\"internalType\":\"structIFastBridge.BridgeTransaction\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"},{\"internalType\":\"bytes32\",\"name\":\"destTxHash\",\"type\":\"bytes32\"}],\"name\":\"prove\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"refund\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"relay\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"}]", + Sigs: map[string]string{ + "45851694": "bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256))", + "aa9641ab": "canClaim(bytes32,address)", + "41fcb612": "claim(bytes,address)", + "add98c70": "dispute(bytes32)", + "ac11fb1a": "getBridgeTransaction(bytes)", + "886d36ff": "prove(bytes,bytes32)", + "5eb7d946": "refund(bytes)", + "8f0d6f17": "relay(bytes)", + }, +} + +// IFastBridgeABI is the input ABI used to generate the binding from. +// Deprecated: Use IFastBridgeMetaData.ABI instead. +var IFastBridgeABI = IFastBridgeMetaData.ABI + +// Deprecated: Use IFastBridgeMetaData.Sigs instead. +// IFastBridgeFuncSigs maps the 4-byte function signature to its string representation. +var IFastBridgeFuncSigs = IFastBridgeMetaData.Sigs + +// IFastBridge is an auto generated Go binding around an Ethereum contract. +type IFastBridge struct { + IFastBridgeCaller // Read-only binding to the contract + IFastBridgeTransactor // Write-only binding to the contract + IFastBridgeFilterer // Log filterer for contract events +} + +// IFastBridgeCaller is an auto generated read-only Go binding around an Ethereum contract. +type IFastBridgeCaller struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// IFastBridgeTransactor is an auto generated write-only Go binding around an Ethereum contract. +type IFastBridgeTransactor struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// IFastBridgeFilterer is an auto generated log filtering Go binding around an Ethereum contract events. +type IFastBridgeFilterer struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// IFastBridgeSession is an auto generated Go binding around an Ethereum contract, +// with pre-set call and transact options. +type IFastBridgeSession struct { + Contract *IFastBridge // Generic contract binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// IFastBridgeCallerSession is an auto generated read-only Go binding around an Ethereum contract, +// with pre-set call options. +type IFastBridgeCallerSession struct { + Contract *IFastBridgeCaller // Generic contract caller binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session +} + +// IFastBridgeTransactorSession is an auto generated write-only Go binding around an Ethereum contract, +// with pre-set transact options. +type IFastBridgeTransactorSession struct { + Contract *IFastBridgeTransactor // Generic contract transactor binding to set the session for + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// IFastBridgeRaw is an auto generated low-level Go binding around an Ethereum contract. +type IFastBridgeRaw struct { + Contract *IFastBridge // Generic contract binding to access the raw methods on +} + +// IFastBridgeCallerRaw is an auto generated low-level read-only Go binding around an Ethereum contract. +type IFastBridgeCallerRaw struct { + Contract *IFastBridgeCaller // Generic read-only contract binding to access the raw methods on +} + +// IFastBridgeTransactorRaw is an auto generated low-level write-only Go binding around an Ethereum contract. +type IFastBridgeTransactorRaw struct { + Contract *IFastBridgeTransactor // Generic write-only contract binding to access the raw methods on +} + +// NewIFastBridge creates a new instance of IFastBridge, bound to a specific deployed contract. +func NewIFastBridge(address common.Address, backend bind.ContractBackend) (*IFastBridge, error) { + contract, err := bindIFastBridge(address, backend, backend, backend) + if err != nil { + return nil, err + } + return &IFastBridge{IFastBridgeCaller: IFastBridgeCaller{contract: contract}, IFastBridgeTransactor: IFastBridgeTransactor{contract: contract}, IFastBridgeFilterer: IFastBridgeFilterer{contract: contract}}, nil +} + +// NewIFastBridgeCaller creates a new read-only instance of IFastBridge, bound to a specific deployed contract. +func NewIFastBridgeCaller(address common.Address, caller bind.ContractCaller) (*IFastBridgeCaller, error) { + contract, err := bindIFastBridge(address, caller, nil, nil) + if err != nil { + return nil, err + } + return &IFastBridgeCaller{contract: contract}, nil +} + +// NewIFastBridgeTransactor creates a new write-only instance of IFastBridge, bound to a specific deployed contract. +func NewIFastBridgeTransactor(address common.Address, transactor bind.ContractTransactor) (*IFastBridgeTransactor, error) { + contract, err := bindIFastBridge(address, nil, transactor, nil) + if err != nil { + return nil, err + } + return &IFastBridgeTransactor{contract: contract}, nil +} + +// NewIFastBridgeFilterer creates a new log filterer instance of IFastBridge, bound to a specific deployed contract. +func NewIFastBridgeFilterer(address common.Address, filterer bind.ContractFilterer) (*IFastBridgeFilterer, error) { + contract, err := bindIFastBridge(address, nil, nil, filterer) + if err != nil { + return nil, err + } + return &IFastBridgeFilterer{contract: contract}, nil +} + +// bindIFastBridge binds a generic wrapper to an already deployed contract. +func bindIFastBridge(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) { + parsed, err := IFastBridgeMetaData.GetAbi() + if err != nil { + return nil, err + } + return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil +} + +// Call invokes the (constant) contract method with params as input values and +// sets the output to result. The result type might be a single field for simple +// returns, a slice of interfaces for anonymous returns and a struct for named +// returns. +func (_IFastBridge *IFastBridgeRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _IFastBridge.Contract.IFastBridgeCaller.contract.Call(opts, result, method, params...) +} + +// Transfer initiates a plain transaction to move funds to the contract, calling +// its default method if one is available. +func (_IFastBridge *IFastBridgeRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _IFastBridge.Contract.IFastBridgeTransactor.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_IFastBridge *IFastBridgeRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _IFastBridge.Contract.IFastBridgeTransactor.contract.Transact(opts, method, params...) +} + +// Call invokes the (constant) contract method with params as input values and +// sets the output to result. The result type might be a single field for simple +// returns, a slice of interfaces for anonymous returns and a struct for named +// returns. +func (_IFastBridge *IFastBridgeCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _IFastBridge.Contract.contract.Call(opts, result, method, params...) +} + +// Transfer initiates a plain transaction to move funds to the contract, calling +// its default method if one is available. +func (_IFastBridge *IFastBridgeTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _IFastBridge.Contract.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_IFastBridge *IFastBridgeTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _IFastBridge.Contract.contract.Transact(opts, method, params...) +} + +// CanClaim is a free data retrieval call binding the contract method 0xaa9641ab. +// +// Solidity: function canClaim(bytes32 transactionId, address relayer) view returns(bool) +func (_IFastBridge *IFastBridgeCaller) CanClaim(opts *bind.CallOpts, transactionId [32]byte, relayer common.Address) (bool, error) { + var out []interface{} + err := _IFastBridge.contract.Call(opts, &out, "canClaim", transactionId, relayer) + + if err != nil { + return *new(bool), err + } + + out0 := *abi.ConvertType(out[0], new(bool)).(*bool) + + return out0, err + +} + +// CanClaim is a free data retrieval call binding the contract method 0xaa9641ab. +// +// Solidity: function canClaim(bytes32 transactionId, address relayer) view returns(bool) +func (_IFastBridge *IFastBridgeSession) CanClaim(transactionId [32]byte, relayer common.Address) (bool, error) { + return _IFastBridge.Contract.CanClaim(&_IFastBridge.CallOpts, transactionId, relayer) +} + +// CanClaim is a free data retrieval call binding the contract method 0xaa9641ab. +// +// Solidity: function canClaim(bytes32 transactionId, address relayer) view returns(bool) +func (_IFastBridge *IFastBridgeCallerSession) CanClaim(transactionId [32]byte, relayer common.Address) (bool, error) { + return _IFastBridge.Contract.CanClaim(&_IFastBridge.CallOpts, transactionId, relayer) +} + +// GetBridgeTransaction is a free data retrieval call binding the contract method 0xac11fb1a. +// +// Solidity: function getBridgeTransaction(bytes request) view returns((uint32,uint32,address,address,address,address,uint256,uint256,uint256,bool,uint256,uint256)) +func (_IFastBridge *IFastBridgeCaller) GetBridgeTransaction(opts *bind.CallOpts, request []byte) (IFastBridgeBridgeTransaction, error) { + var out []interface{} + err := _IFastBridge.contract.Call(opts, &out, "getBridgeTransaction", request) + + if err != nil { + return *new(IFastBridgeBridgeTransaction), err + } + + out0 := *abi.ConvertType(out[0], new(IFastBridgeBridgeTransaction)).(*IFastBridgeBridgeTransaction) + + return out0, err + +} + +// GetBridgeTransaction is a free data retrieval call binding the contract method 0xac11fb1a. +// +// Solidity: function getBridgeTransaction(bytes request) view returns((uint32,uint32,address,address,address,address,uint256,uint256,uint256,bool,uint256,uint256)) +func (_IFastBridge *IFastBridgeSession) GetBridgeTransaction(request []byte) (IFastBridgeBridgeTransaction, error) { + return _IFastBridge.Contract.GetBridgeTransaction(&_IFastBridge.CallOpts, request) +} + +// GetBridgeTransaction is a free data retrieval call binding the contract method 0xac11fb1a. +// +// Solidity: function getBridgeTransaction(bytes request) view returns((uint32,uint32,address,address,address,address,uint256,uint256,uint256,bool,uint256,uint256)) +func (_IFastBridge *IFastBridgeCallerSession) GetBridgeTransaction(request []byte) (IFastBridgeBridgeTransaction, error) { + return _IFastBridge.Contract.GetBridgeTransaction(&_IFastBridge.CallOpts, request) +} + +// Bridge is a paid mutator transaction binding the contract method 0x45851694. +// +// Solidity: function bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256) params) payable returns() +func (_IFastBridge *IFastBridgeTransactor) Bridge(opts *bind.TransactOpts, params IFastBridgeBridgeParams) (*types.Transaction, error) { + return _IFastBridge.contract.Transact(opts, "bridge", params) +} + +// Bridge is a paid mutator transaction binding the contract method 0x45851694. +// +// Solidity: function bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256) params) payable returns() +func (_IFastBridge *IFastBridgeSession) Bridge(params IFastBridgeBridgeParams) (*types.Transaction, error) { + return _IFastBridge.Contract.Bridge(&_IFastBridge.TransactOpts, params) +} + +// Bridge is a paid mutator transaction binding the contract method 0x45851694. +// +// Solidity: function bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256) params) payable returns() +func (_IFastBridge *IFastBridgeTransactorSession) Bridge(params IFastBridgeBridgeParams) (*types.Transaction, error) { + return _IFastBridge.Contract.Bridge(&_IFastBridge.TransactOpts, params) +} + +// Claim is a paid mutator transaction binding the contract method 0x41fcb612. +// +// Solidity: function claim(bytes request, address to) returns() +func (_IFastBridge *IFastBridgeTransactor) Claim(opts *bind.TransactOpts, request []byte, to common.Address) (*types.Transaction, error) { + return _IFastBridge.contract.Transact(opts, "claim", request, to) +} + +// Claim is a paid mutator transaction binding the contract method 0x41fcb612. +// +// Solidity: function claim(bytes request, address to) returns() +func (_IFastBridge *IFastBridgeSession) Claim(request []byte, to common.Address) (*types.Transaction, error) { + return _IFastBridge.Contract.Claim(&_IFastBridge.TransactOpts, request, to) +} + +// Claim is a paid mutator transaction binding the contract method 0x41fcb612. +// +// Solidity: function claim(bytes request, address to) returns() +func (_IFastBridge *IFastBridgeTransactorSession) Claim(request []byte, to common.Address) (*types.Transaction, error) { + return _IFastBridge.Contract.Claim(&_IFastBridge.TransactOpts, request, to) +} + +// Dispute is a paid mutator transaction binding the contract method 0xadd98c70. +// +// Solidity: function dispute(bytes32 transactionId) returns() +func (_IFastBridge *IFastBridgeTransactor) Dispute(opts *bind.TransactOpts, transactionId [32]byte) (*types.Transaction, error) { + return _IFastBridge.contract.Transact(opts, "dispute", transactionId) +} + +// Dispute is a paid mutator transaction binding the contract method 0xadd98c70. +// +// Solidity: function dispute(bytes32 transactionId) returns() +func (_IFastBridge *IFastBridgeSession) Dispute(transactionId [32]byte) (*types.Transaction, error) { + return _IFastBridge.Contract.Dispute(&_IFastBridge.TransactOpts, transactionId) +} + +// Dispute is a paid mutator transaction binding the contract method 0xadd98c70. +// +// Solidity: function dispute(bytes32 transactionId) returns() +func (_IFastBridge *IFastBridgeTransactorSession) Dispute(transactionId [32]byte) (*types.Transaction, error) { + return _IFastBridge.Contract.Dispute(&_IFastBridge.TransactOpts, transactionId) +} + +// Prove is a paid mutator transaction binding the contract method 0x886d36ff. +// +// Solidity: function prove(bytes request, bytes32 destTxHash) returns() +func (_IFastBridge *IFastBridgeTransactor) Prove(opts *bind.TransactOpts, request []byte, destTxHash [32]byte) (*types.Transaction, error) { + return _IFastBridge.contract.Transact(opts, "prove", request, destTxHash) +} + +// Prove is a paid mutator transaction binding the contract method 0x886d36ff. +// +// Solidity: function prove(bytes request, bytes32 destTxHash) returns() +func (_IFastBridge *IFastBridgeSession) Prove(request []byte, destTxHash [32]byte) (*types.Transaction, error) { + return _IFastBridge.Contract.Prove(&_IFastBridge.TransactOpts, request, destTxHash) +} + +// Prove is a paid mutator transaction binding the contract method 0x886d36ff. +// +// Solidity: function prove(bytes request, bytes32 destTxHash) returns() +func (_IFastBridge *IFastBridgeTransactorSession) Prove(request []byte, destTxHash [32]byte) (*types.Transaction, error) { + return _IFastBridge.Contract.Prove(&_IFastBridge.TransactOpts, request, destTxHash) +} + +// Refund is a paid mutator transaction binding the contract method 0x5eb7d946. +// +// Solidity: function refund(bytes request) returns() +func (_IFastBridge *IFastBridgeTransactor) Refund(opts *bind.TransactOpts, request []byte) (*types.Transaction, error) { + return _IFastBridge.contract.Transact(opts, "refund", request) +} + +// Refund is a paid mutator transaction binding the contract method 0x5eb7d946. +// +// Solidity: function refund(bytes request) returns() +func (_IFastBridge *IFastBridgeSession) Refund(request []byte) (*types.Transaction, error) { + return _IFastBridge.Contract.Refund(&_IFastBridge.TransactOpts, request) +} + +// Refund is a paid mutator transaction binding the contract method 0x5eb7d946. +// +// Solidity: function refund(bytes request) returns() +func (_IFastBridge *IFastBridgeTransactorSession) Refund(request []byte) (*types.Transaction, error) { + return _IFastBridge.Contract.Refund(&_IFastBridge.TransactOpts, request) +} + +// Relay is a paid mutator transaction binding the contract method 0x8f0d6f17. +// +// Solidity: function relay(bytes request) payable returns() +func (_IFastBridge *IFastBridgeTransactor) Relay(opts *bind.TransactOpts, request []byte) (*types.Transaction, error) { + return _IFastBridge.contract.Transact(opts, "relay", request) +} + +// Relay is a paid mutator transaction binding the contract method 0x8f0d6f17. +// +// Solidity: function relay(bytes request) payable returns() +func (_IFastBridge *IFastBridgeSession) Relay(request []byte) (*types.Transaction, error) { + return _IFastBridge.Contract.Relay(&_IFastBridge.TransactOpts, request) +} + +// Relay is a paid mutator transaction binding the contract method 0x8f0d6f17. +// +// Solidity: function relay(bytes request) payable returns() +func (_IFastBridge *IFastBridgeTransactorSession) Relay(request []byte) (*types.Transaction, error) { + return _IFastBridge.Contract.Relay(&_IFastBridge.TransactOpts, request) +} + +// IFastBridgeBridgeDepositClaimedIterator is returned from FilterBridgeDepositClaimed and is used to iterate over the raw logs and unpacked data for BridgeDepositClaimed events raised by the IFastBridge contract. +type IFastBridgeBridgeDepositClaimedIterator struct { + Event *IFastBridgeBridgeDepositClaimed // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *IFastBridgeBridgeDepositClaimedIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(IFastBridgeBridgeDepositClaimed) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(IFastBridgeBridgeDepositClaimed) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *IFastBridgeBridgeDepositClaimedIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *IFastBridgeBridgeDepositClaimedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// IFastBridgeBridgeDepositClaimed represents a BridgeDepositClaimed event raised by the IFastBridge contract. +type IFastBridgeBridgeDepositClaimed struct { + TransactionId [32]byte + Relayer common.Address + To common.Address + Token common.Address + Amount *big.Int + Raw types.Log // Blockchain specific contextual infos +} + +// FilterBridgeDepositClaimed is a free log retrieval operation binding the contract event 0x582211c35a2139ac3bbaac74663c6a1f56c6cbb658b41fe11fd45a82074ac678. +// +// Solidity: event BridgeDepositClaimed(bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount) +func (_IFastBridge *IFastBridgeFilterer) FilterBridgeDepositClaimed(opts *bind.FilterOpts, transactionId [][32]byte, relayer []common.Address, to []common.Address) (*IFastBridgeBridgeDepositClaimedIterator, error) { + + var transactionIdRule []interface{} + for _, transactionIdItem := range transactionId { + transactionIdRule = append(transactionIdRule, transactionIdItem) + } + var relayerRule []interface{} + for _, relayerItem := range relayer { + relayerRule = append(relayerRule, relayerItem) + } + var toRule []interface{} + for _, toItem := range to { + toRule = append(toRule, toItem) + } + + logs, sub, err := _IFastBridge.contract.FilterLogs(opts, "BridgeDepositClaimed", transactionIdRule, relayerRule, toRule) + if err != nil { + return nil, err + } + return &IFastBridgeBridgeDepositClaimedIterator{contract: _IFastBridge.contract, event: "BridgeDepositClaimed", logs: logs, sub: sub}, nil +} + +// WatchBridgeDepositClaimed is a free log subscription operation binding the contract event 0x582211c35a2139ac3bbaac74663c6a1f56c6cbb658b41fe11fd45a82074ac678. +// +// Solidity: event BridgeDepositClaimed(bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount) +func (_IFastBridge *IFastBridgeFilterer) WatchBridgeDepositClaimed(opts *bind.WatchOpts, sink chan<- *IFastBridgeBridgeDepositClaimed, transactionId [][32]byte, relayer []common.Address, to []common.Address) (event.Subscription, error) { + + var transactionIdRule []interface{} + for _, transactionIdItem := range transactionId { + transactionIdRule = append(transactionIdRule, transactionIdItem) + } + var relayerRule []interface{} + for _, relayerItem := range relayer { + relayerRule = append(relayerRule, relayerItem) + } + var toRule []interface{} + for _, toItem := range to { + toRule = append(toRule, toItem) + } + + logs, sub, err := _IFastBridge.contract.WatchLogs(opts, "BridgeDepositClaimed", transactionIdRule, relayerRule, toRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(IFastBridgeBridgeDepositClaimed) + if err := _IFastBridge.contract.UnpackLog(event, "BridgeDepositClaimed", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseBridgeDepositClaimed is a log parse operation binding the contract event 0x582211c35a2139ac3bbaac74663c6a1f56c6cbb658b41fe11fd45a82074ac678. +// +// Solidity: event BridgeDepositClaimed(bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount) +func (_IFastBridge *IFastBridgeFilterer) ParseBridgeDepositClaimed(log types.Log) (*IFastBridgeBridgeDepositClaimed, error) { + event := new(IFastBridgeBridgeDepositClaimed) + if err := _IFastBridge.contract.UnpackLog(event, "BridgeDepositClaimed", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// IFastBridgeBridgeDepositRefundedIterator is returned from FilterBridgeDepositRefunded and is used to iterate over the raw logs and unpacked data for BridgeDepositRefunded events raised by the IFastBridge contract. +type IFastBridgeBridgeDepositRefundedIterator struct { + Event *IFastBridgeBridgeDepositRefunded // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *IFastBridgeBridgeDepositRefundedIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(IFastBridgeBridgeDepositRefunded) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(IFastBridgeBridgeDepositRefunded) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *IFastBridgeBridgeDepositRefundedIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *IFastBridgeBridgeDepositRefundedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// IFastBridgeBridgeDepositRefunded represents a BridgeDepositRefunded event raised by the IFastBridge contract. +type IFastBridgeBridgeDepositRefunded struct { + TransactionId [32]byte + To common.Address + Token common.Address + Amount *big.Int + Raw types.Log // Blockchain specific contextual infos +} + +// FilterBridgeDepositRefunded is a free log retrieval operation binding the contract event 0xb4c55c0c9bc613519b920e88748090150b890a875d307f21bea7d4fb2e8bc958. +// +// Solidity: event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount) +func (_IFastBridge *IFastBridgeFilterer) FilterBridgeDepositRefunded(opts *bind.FilterOpts, transactionId [][32]byte, to []common.Address) (*IFastBridgeBridgeDepositRefundedIterator, error) { + + var transactionIdRule []interface{} + for _, transactionIdItem := range transactionId { + transactionIdRule = append(transactionIdRule, transactionIdItem) + } + var toRule []interface{} + for _, toItem := range to { + toRule = append(toRule, toItem) + } + + logs, sub, err := _IFastBridge.contract.FilterLogs(opts, "BridgeDepositRefunded", transactionIdRule, toRule) + if err != nil { + return nil, err + } + return &IFastBridgeBridgeDepositRefundedIterator{contract: _IFastBridge.contract, event: "BridgeDepositRefunded", logs: logs, sub: sub}, nil +} + +// WatchBridgeDepositRefunded is a free log subscription operation binding the contract event 0xb4c55c0c9bc613519b920e88748090150b890a875d307f21bea7d4fb2e8bc958. +// +// Solidity: event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount) +func (_IFastBridge *IFastBridgeFilterer) WatchBridgeDepositRefunded(opts *bind.WatchOpts, sink chan<- *IFastBridgeBridgeDepositRefunded, transactionId [][32]byte, to []common.Address) (event.Subscription, error) { + + var transactionIdRule []interface{} + for _, transactionIdItem := range transactionId { + transactionIdRule = append(transactionIdRule, transactionIdItem) + } + var toRule []interface{} + for _, toItem := range to { + toRule = append(toRule, toItem) + } + + logs, sub, err := _IFastBridge.contract.WatchLogs(opts, "BridgeDepositRefunded", transactionIdRule, toRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(IFastBridgeBridgeDepositRefunded) + if err := _IFastBridge.contract.UnpackLog(event, "BridgeDepositRefunded", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseBridgeDepositRefunded is a log parse operation binding the contract event 0xb4c55c0c9bc613519b920e88748090150b890a875d307f21bea7d4fb2e8bc958. +// +// Solidity: event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount) +func (_IFastBridge *IFastBridgeFilterer) ParseBridgeDepositRefunded(log types.Log) (*IFastBridgeBridgeDepositRefunded, error) { + event := new(IFastBridgeBridgeDepositRefunded) + if err := _IFastBridge.contract.UnpackLog(event, "BridgeDepositRefunded", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// IFastBridgeBridgeProofDisputedIterator is returned from FilterBridgeProofDisputed and is used to iterate over the raw logs and unpacked data for BridgeProofDisputed events raised by the IFastBridge contract. +type IFastBridgeBridgeProofDisputedIterator struct { + Event *IFastBridgeBridgeProofDisputed // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *IFastBridgeBridgeProofDisputedIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(IFastBridgeBridgeProofDisputed) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(IFastBridgeBridgeProofDisputed) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *IFastBridgeBridgeProofDisputedIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *IFastBridgeBridgeProofDisputedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// IFastBridgeBridgeProofDisputed represents a BridgeProofDisputed event raised by the IFastBridge contract. +type IFastBridgeBridgeProofDisputed struct { + TransactionId [32]byte + Relayer common.Address + Raw types.Log // Blockchain specific contextual infos +} + +// FilterBridgeProofDisputed is a free log retrieval operation binding the contract event 0x0695cf1d39b3055dcd0fe02d8b47eaf0d5a13e1996de925de59d0ef9b7f7fad4. +// +// Solidity: event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer) +func (_IFastBridge *IFastBridgeFilterer) FilterBridgeProofDisputed(opts *bind.FilterOpts, transactionId [][32]byte, relayer []common.Address) (*IFastBridgeBridgeProofDisputedIterator, error) { + + var transactionIdRule []interface{} + for _, transactionIdItem := range transactionId { + transactionIdRule = append(transactionIdRule, transactionIdItem) + } + var relayerRule []interface{} + for _, relayerItem := range relayer { + relayerRule = append(relayerRule, relayerItem) + } + + logs, sub, err := _IFastBridge.contract.FilterLogs(opts, "BridgeProofDisputed", transactionIdRule, relayerRule) + if err != nil { + return nil, err + } + return &IFastBridgeBridgeProofDisputedIterator{contract: _IFastBridge.contract, event: "BridgeProofDisputed", logs: logs, sub: sub}, nil +} + +// WatchBridgeProofDisputed is a free log subscription operation binding the contract event 0x0695cf1d39b3055dcd0fe02d8b47eaf0d5a13e1996de925de59d0ef9b7f7fad4. +// +// Solidity: event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer) +func (_IFastBridge *IFastBridgeFilterer) WatchBridgeProofDisputed(opts *bind.WatchOpts, sink chan<- *IFastBridgeBridgeProofDisputed, transactionId [][32]byte, relayer []common.Address) (event.Subscription, error) { + + var transactionIdRule []interface{} + for _, transactionIdItem := range transactionId { + transactionIdRule = append(transactionIdRule, transactionIdItem) + } + var relayerRule []interface{} + for _, relayerItem := range relayer { + relayerRule = append(relayerRule, relayerItem) + } + + logs, sub, err := _IFastBridge.contract.WatchLogs(opts, "BridgeProofDisputed", transactionIdRule, relayerRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(IFastBridgeBridgeProofDisputed) + if err := _IFastBridge.contract.UnpackLog(event, "BridgeProofDisputed", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseBridgeProofDisputed is a log parse operation binding the contract event 0x0695cf1d39b3055dcd0fe02d8b47eaf0d5a13e1996de925de59d0ef9b7f7fad4. +// +// Solidity: event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer) +func (_IFastBridge *IFastBridgeFilterer) ParseBridgeProofDisputed(log types.Log) (*IFastBridgeBridgeProofDisputed, error) { + event := new(IFastBridgeBridgeProofDisputed) + if err := _IFastBridge.contract.UnpackLog(event, "BridgeProofDisputed", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// IFastBridgeBridgeProofProvidedIterator is returned from FilterBridgeProofProvided and is used to iterate over the raw logs and unpacked data for BridgeProofProvided events raised by the IFastBridge contract. +type IFastBridgeBridgeProofProvidedIterator struct { + Event *IFastBridgeBridgeProofProvided // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *IFastBridgeBridgeProofProvidedIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(IFastBridgeBridgeProofProvided) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(IFastBridgeBridgeProofProvided) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *IFastBridgeBridgeProofProvidedIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *IFastBridgeBridgeProofProvidedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// IFastBridgeBridgeProofProvided represents a BridgeProofProvided event raised by the IFastBridge contract. +type IFastBridgeBridgeProofProvided struct { + TransactionId [32]byte + Relayer common.Address + TransactionHash [32]byte + Raw types.Log // Blockchain specific contextual infos +} + +// FilterBridgeProofProvided is a free log retrieval operation binding the contract event 0x4ac8af8a2cd87193d64dfc7a3b8d9923b714ec528b18725d080aa1299be0c5e4. +// +// Solidity: event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash) +func (_IFastBridge *IFastBridgeFilterer) FilterBridgeProofProvided(opts *bind.FilterOpts, transactionId [][32]byte, relayer []common.Address) (*IFastBridgeBridgeProofProvidedIterator, error) { + + var transactionIdRule []interface{} + for _, transactionIdItem := range transactionId { + transactionIdRule = append(transactionIdRule, transactionIdItem) + } + var relayerRule []interface{} + for _, relayerItem := range relayer { + relayerRule = append(relayerRule, relayerItem) + } + + logs, sub, err := _IFastBridge.contract.FilterLogs(opts, "BridgeProofProvided", transactionIdRule, relayerRule) + if err != nil { + return nil, err + } + return &IFastBridgeBridgeProofProvidedIterator{contract: _IFastBridge.contract, event: "BridgeProofProvided", logs: logs, sub: sub}, nil +} + +// WatchBridgeProofProvided is a free log subscription operation binding the contract event 0x4ac8af8a2cd87193d64dfc7a3b8d9923b714ec528b18725d080aa1299be0c5e4. +// +// Solidity: event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash) +func (_IFastBridge *IFastBridgeFilterer) WatchBridgeProofProvided(opts *bind.WatchOpts, sink chan<- *IFastBridgeBridgeProofProvided, transactionId [][32]byte, relayer []common.Address) (event.Subscription, error) { + + var transactionIdRule []interface{} + for _, transactionIdItem := range transactionId { + transactionIdRule = append(transactionIdRule, transactionIdItem) + } + var relayerRule []interface{} + for _, relayerItem := range relayer { + relayerRule = append(relayerRule, relayerItem) + } + + logs, sub, err := _IFastBridge.contract.WatchLogs(opts, "BridgeProofProvided", transactionIdRule, relayerRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(IFastBridgeBridgeProofProvided) + if err := _IFastBridge.contract.UnpackLog(event, "BridgeProofProvided", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseBridgeProofProvided is a log parse operation binding the contract event 0x4ac8af8a2cd87193d64dfc7a3b8d9923b714ec528b18725d080aa1299be0c5e4. +// +// Solidity: event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash) +func (_IFastBridge *IFastBridgeFilterer) ParseBridgeProofProvided(log types.Log) (*IFastBridgeBridgeProofProvided, error) { + event := new(IFastBridgeBridgeProofProvided) + if err := _IFastBridge.contract.UnpackLog(event, "BridgeProofProvided", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// IFastBridgeBridgeRelayedIterator is returned from FilterBridgeRelayed and is used to iterate over the raw logs and unpacked data for BridgeRelayed events raised by the IFastBridge contract. +type IFastBridgeBridgeRelayedIterator struct { + Event *IFastBridgeBridgeRelayed // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *IFastBridgeBridgeRelayedIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(IFastBridgeBridgeRelayed) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(IFastBridgeBridgeRelayed) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *IFastBridgeBridgeRelayedIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *IFastBridgeBridgeRelayedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// IFastBridgeBridgeRelayed represents a BridgeRelayed event raised by the IFastBridge contract. +type IFastBridgeBridgeRelayed struct { + TransactionId [32]byte + Relayer common.Address + To common.Address + OriginChainId uint32 + OriginToken common.Address + DestToken common.Address + OriginAmount *big.Int + DestAmount *big.Int + ChainGasAmount *big.Int + Raw types.Log // Blockchain specific contextual infos +} + +// FilterBridgeRelayed is a free log retrieval operation binding the contract event 0xf8ae392d784b1ea5e8881bfa586d81abf07ef4f1e2fc75f7fe51c90f05199a5c. +// +// Solidity: event BridgeRelayed(bytes32 indexed transactionId, address indexed relayer, address indexed to, uint32 originChainId, address originToken, address destToken, uint256 originAmount, uint256 destAmount, uint256 chainGasAmount) +func (_IFastBridge *IFastBridgeFilterer) FilterBridgeRelayed(opts *bind.FilterOpts, transactionId [][32]byte, relayer []common.Address, to []common.Address) (*IFastBridgeBridgeRelayedIterator, error) { + + var transactionIdRule []interface{} + for _, transactionIdItem := range transactionId { + transactionIdRule = append(transactionIdRule, transactionIdItem) + } + var relayerRule []interface{} + for _, relayerItem := range relayer { + relayerRule = append(relayerRule, relayerItem) + } + var toRule []interface{} + for _, toItem := range to { + toRule = append(toRule, toItem) + } + + logs, sub, err := _IFastBridge.contract.FilterLogs(opts, "BridgeRelayed", transactionIdRule, relayerRule, toRule) + if err != nil { + return nil, err + } + return &IFastBridgeBridgeRelayedIterator{contract: _IFastBridge.contract, event: "BridgeRelayed", logs: logs, sub: sub}, nil +} + +// WatchBridgeRelayed is a free log subscription operation binding the contract event 0xf8ae392d784b1ea5e8881bfa586d81abf07ef4f1e2fc75f7fe51c90f05199a5c. +// +// Solidity: event BridgeRelayed(bytes32 indexed transactionId, address indexed relayer, address indexed to, uint32 originChainId, address originToken, address destToken, uint256 originAmount, uint256 destAmount, uint256 chainGasAmount) +func (_IFastBridge *IFastBridgeFilterer) WatchBridgeRelayed(opts *bind.WatchOpts, sink chan<- *IFastBridgeBridgeRelayed, transactionId [][32]byte, relayer []common.Address, to []common.Address) (event.Subscription, error) { + + var transactionIdRule []interface{} + for _, transactionIdItem := range transactionId { + transactionIdRule = append(transactionIdRule, transactionIdItem) + } + var relayerRule []interface{} + for _, relayerItem := range relayer { + relayerRule = append(relayerRule, relayerItem) + } + var toRule []interface{} + for _, toItem := range to { + toRule = append(toRule, toItem) + } + + logs, sub, err := _IFastBridge.contract.WatchLogs(opts, "BridgeRelayed", transactionIdRule, relayerRule, toRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(IFastBridgeBridgeRelayed) + if err := _IFastBridge.contract.UnpackLog(event, "BridgeRelayed", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseBridgeRelayed is a log parse operation binding the contract event 0xf8ae392d784b1ea5e8881bfa586d81abf07ef4f1e2fc75f7fe51c90f05199a5c. +// +// Solidity: event BridgeRelayed(bytes32 indexed transactionId, address indexed relayer, address indexed to, uint32 originChainId, address originToken, address destToken, uint256 originAmount, uint256 destAmount, uint256 chainGasAmount) +func (_IFastBridge *IFastBridgeFilterer) ParseBridgeRelayed(log types.Log) (*IFastBridgeBridgeRelayed, error) { + event := new(IFastBridgeBridgeRelayed) + if err := _IFastBridge.contract.UnpackLog(event, "BridgeRelayed", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// IFastBridgeBridgeRequestedIterator is returned from FilterBridgeRequested and is used to iterate over the raw logs and unpacked data for BridgeRequested events raised by the IFastBridge contract. +type IFastBridgeBridgeRequestedIterator struct { + Event *IFastBridgeBridgeRequested // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *IFastBridgeBridgeRequestedIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(IFastBridgeBridgeRequested) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(IFastBridgeBridgeRequested) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *IFastBridgeBridgeRequestedIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *IFastBridgeBridgeRequestedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// IFastBridgeBridgeRequested represents a BridgeRequested event raised by the IFastBridge contract. +type IFastBridgeBridgeRequested struct { + TransactionId [32]byte + Sender common.Address + Request []byte + DestChainId uint32 + OriginToken common.Address + DestToken common.Address + OriginAmount *big.Int + DestAmount *big.Int + SendChainGas bool + Raw types.Log // Blockchain specific contextual infos +} + +// FilterBridgeRequested is a free log retrieval operation binding the contract event 0x120ea0364f36cdac7983bcfdd55270ca09d7f9b314a2ebc425a3b01ab1d6403a. +// +// Solidity: event BridgeRequested(bytes32 indexed transactionId, address indexed sender, bytes request, uint32 destChainId, address originToken, address destToken, uint256 originAmount, uint256 destAmount, bool sendChainGas) +func (_IFastBridge *IFastBridgeFilterer) FilterBridgeRequested(opts *bind.FilterOpts, transactionId [][32]byte, sender []common.Address) (*IFastBridgeBridgeRequestedIterator, error) { + + var transactionIdRule []interface{} + for _, transactionIdItem := range transactionId { + transactionIdRule = append(transactionIdRule, transactionIdItem) + } + var senderRule []interface{} + for _, senderItem := range sender { + senderRule = append(senderRule, senderItem) + } + + logs, sub, err := _IFastBridge.contract.FilterLogs(opts, "BridgeRequested", transactionIdRule, senderRule) + if err != nil { + return nil, err + } + return &IFastBridgeBridgeRequestedIterator{contract: _IFastBridge.contract, event: "BridgeRequested", logs: logs, sub: sub}, nil +} + +// WatchBridgeRequested is a free log subscription operation binding the contract event 0x120ea0364f36cdac7983bcfdd55270ca09d7f9b314a2ebc425a3b01ab1d6403a. +// +// Solidity: event BridgeRequested(bytes32 indexed transactionId, address indexed sender, bytes request, uint32 destChainId, address originToken, address destToken, uint256 originAmount, uint256 destAmount, bool sendChainGas) +func (_IFastBridge *IFastBridgeFilterer) WatchBridgeRequested(opts *bind.WatchOpts, sink chan<- *IFastBridgeBridgeRequested, transactionId [][32]byte, sender []common.Address) (event.Subscription, error) { + + var transactionIdRule []interface{} + for _, transactionIdItem := range transactionId { + transactionIdRule = append(transactionIdRule, transactionIdItem) + } + var senderRule []interface{} + for _, senderItem := range sender { + senderRule = append(senderRule, senderItem) + } + + logs, sub, err := _IFastBridge.contract.WatchLogs(opts, "BridgeRequested", transactionIdRule, senderRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(IFastBridgeBridgeRequested) + if err := _IFastBridge.contract.UnpackLog(event, "BridgeRequested", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseBridgeRequested is a log parse operation binding the contract event 0x120ea0364f36cdac7983bcfdd55270ca09d7f9b314a2ebc425a3b01ab1d6403a. +// +// Solidity: event BridgeRequested(bytes32 indexed transactionId, address indexed sender, bytes request, uint32 destChainId, address originToken, address destToken, uint256 originAmount, uint256 destAmount, bool sendChainGas) +func (_IFastBridge *IFastBridgeFilterer) ParseBridgeRequested(log types.Log) (*IFastBridgeBridgeRequested, error) { + event := new(IFastBridgeBridgeRequested) + if err := _IFastBridge.contract.UnpackLog(event, "BridgeRequested", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// IFastBridgeRecipientMetaData contains all meta data concerning the IFastBridgeRecipient contract. +var IFastBridgeRecipientMetaData = &bind.MetaData{ + ABI: "[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"callParams\",\"type\":\"bytes\"}],\"name\":\"fastBridgeTransferReceived\",\"outputs\":[{\"internalType\":\"bytes4\",\"name\":\"\",\"type\":\"bytes4\"}],\"stateMutability\":\"payable\",\"type\":\"function\"}]", + Sigs: map[string]string{ + "461e0c21": "fastBridgeTransferReceived(address,uint256,bytes)", + }, +} + +// IFastBridgeRecipientABI is the input ABI used to generate the binding from. +// Deprecated: Use IFastBridgeRecipientMetaData.ABI instead. +var IFastBridgeRecipientABI = IFastBridgeRecipientMetaData.ABI + +// Deprecated: Use IFastBridgeRecipientMetaData.Sigs instead. +// IFastBridgeRecipientFuncSigs maps the 4-byte function signature to its string representation. +var IFastBridgeRecipientFuncSigs = IFastBridgeRecipientMetaData.Sigs + +// IFastBridgeRecipient is an auto generated Go binding around an Ethereum contract. +type IFastBridgeRecipient struct { + IFastBridgeRecipientCaller // Read-only binding to the contract + IFastBridgeRecipientTransactor // Write-only binding to the contract + IFastBridgeRecipientFilterer // Log filterer for contract events +} + +// IFastBridgeRecipientCaller is an auto generated read-only Go binding around an Ethereum contract. +type IFastBridgeRecipientCaller struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// IFastBridgeRecipientTransactor is an auto generated write-only Go binding around an Ethereum contract. +type IFastBridgeRecipientTransactor struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// IFastBridgeRecipientFilterer is an auto generated log filtering Go binding around an Ethereum contract events. +type IFastBridgeRecipientFilterer struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// IFastBridgeRecipientSession is an auto generated Go binding around an Ethereum contract, +// with pre-set call and transact options. +type IFastBridgeRecipientSession struct { + Contract *IFastBridgeRecipient // Generic contract binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// IFastBridgeRecipientCallerSession is an auto generated read-only Go binding around an Ethereum contract, +// with pre-set call options. +type IFastBridgeRecipientCallerSession struct { + Contract *IFastBridgeRecipientCaller // Generic contract caller binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session +} + +// IFastBridgeRecipientTransactorSession is an auto generated write-only Go binding around an Ethereum contract, +// with pre-set transact options. +type IFastBridgeRecipientTransactorSession struct { + Contract *IFastBridgeRecipientTransactor // Generic contract transactor binding to set the session for + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// IFastBridgeRecipientRaw is an auto generated low-level Go binding around an Ethereum contract. +type IFastBridgeRecipientRaw struct { + Contract *IFastBridgeRecipient // Generic contract binding to access the raw methods on +} + +// IFastBridgeRecipientCallerRaw is an auto generated low-level read-only Go binding around an Ethereum contract. +type IFastBridgeRecipientCallerRaw struct { + Contract *IFastBridgeRecipientCaller // Generic read-only contract binding to access the raw methods on +} + +// IFastBridgeRecipientTransactorRaw is an auto generated low-level write-only Go binding around an Ethereum contract. +type IFastBridgeRecipientTransactorRaw struct { + Contract *IFastBridgeRecipientTransactor // Generic write-only contract binding to access the raw methods on +} + +// NewIFastBridgeRecipient creates a new instance of IFastBridgeRecipient, bound to a specific deployed contract. +func NewIFastBridgeRecipient(address common.Address, backend bind.ContractBackend) (*IFastBridgeRecipient, error) { + contract, err := bindIFastBridgeRecipient(address, backend, backend, backend) + if err != nil { + return nil, err + } + return &IFastBridgeRecipient{IFastBridgeRecipientCaller: IFastBridgeRecipientCaller{contract: contract}, IFastBridgeRecipientTransactor: IFastBridgeRecipientTransactor{contract: contract}, IFastBridgeRecipientFilterer: IFastBridgeRecipientFilterer{contract: contract}}, nil +} + +// NewIFastBridgeRecipientCaller creates a new read-only instance of IFastBridgeRecipient, bound to a specific deployed contract. +func NewIFastBridgeRecipientCaller(address common.Address, caller bind.ContractCaller) (*IFastBridgeRecipientCaller, error) { + contract, err := bindIFastBridgeRecipient(address, caller, nil, nil) + if err != nil { + return nil, err + } + return &IFastBridgeRecipientCaller{contract: contract}, nil +} + +// NewIFastBridgeRecipientTransactor creates a new write-only instance of IFastBridgeRecipient, bound to a specific deployed contract. +func NewIFastBridgeRecipientTransactor(address common.Address, transactor bind.ContractTransactor) (*IFastBridgeRecipientTransactor, error) { + contract, err := bindIFastBridgeRecipient(address, nil, transactor, nil) + if err != nil { + return nil, err + } + return &IFastBridgeRecipientTransactor{contract: contract}, nil +} + +// NewIFastBridgeRecipientFilterer creates a new log filterer instance of IFastBridgeRecipient, bound to a specific deployed contract. +func NewIFastBridgeRecipientFilterer(address common.Address, filterer bind.ContractFilterer) (*IFastBridgeRecipientFilterer, error) { + contract, err := bindIFastBridgeRecipient(address, nil, nil, filterer) + if err != nil { + return nil, err + } + return &IFastBridgeRecipientFilterer{contract: contract}, nil +} + +// bindIFastBridgeRecipient binds a generic wrapper to an already deployed contract. +func bindIFastBridgeRecipient(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) { + parsed, err := IFastBridgeRecipientMetaData.GetAbi() + if err != nil { + return nil, err + } + return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil +} + +// Call invokes the (constant) contract method with params as input values and +// sets the output to result. The result type might be a single field for simple +// returns, a slice of interfaces for anonymous returns and a struct for named +// returns. +func (_IFastBridgeRecipient *IFastBridgeRecipientRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _IFastBridgeRecipient.Contract.IFastBridgeRecipientCaller.contract.Call(opts, result, method, params...) +} + +// Transfer initiates a plain transaction to move funds to the contract, calling +// its default method if one is available. +func (_IFastBridgeRecipient *IFastBridgeRecipientRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _IFastBridgeRecipient.Contract.IFastBridgeRecipientTransactor.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_IFastBridgeRecipient *IFastBridgeRecipientRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _IFastBridgeRecipient.Contract.IFastBridgeRecipientTransactor.contract.Transact(opts, method, params...) +} + +// Call invokes the (constant) contract method with params as input values and +// sets the output to result. The result type might be a single field for simple +// returns, a slice of interfaces for anonymous returns and a struct for named +// returns. +func (_IFastBridgeRecipient *IFastBridgeRecipientCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _IFastBridgeRecipient.Contract.contract.Call(opts, result, method, params...) +} + +// Transfer initiates a plain transaction to move funds to the contract, calling +// its default method if one is available. +func (_IFastBridgeRecipient *IFastBridgeRecipientTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _IFastBridgeRecipient.Contract.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_IFastBridgeRecipient *IFastBridgeRecipientTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _IFastBridgeRecipient.Contract.contract.Transact(opts, method, params...) +} + +// FastBridgeTransferReceived is a paid mutator transaction binding the contract method 0x461e0c21. +// +// Solidity: function fastBridgeTransferReceived(address token, uint256 amount, bytes callParams) payable returns(bytes4) +func (_IFastBridgeRecipient *IFastBridgeRecipientTransactor) FastBridgeTransferReceived(opts *bind.TransactOpts, token common.Address, amount *big.Int, callParams []byte) (*types.Transaction, error) { + return _IFastBridgeRecipient.contract.Transact(opts, "fastBridgeTransferReceived", token, amount, callParams) +} + +// FastBridgeTransferReceived is a paid mutator transaction binding the contract method 0x461e0c21. +// +// Solidity: function fastBridgeTransferReceived(address token, uint256 amount, bytes callParams) payable returns(bytes4) +func (_IFastBridgeRecipient *IFastBridgeRecipientSession) FastBridgeTransferReceived(token common.Address, amount *big.Int, callParams []byte) (*types.Transaction, error) { + return _IFastBridgeRecipient.Contract.FastBridgeTransferReceived(&_IFastBridgeRecipient.TransactOpts, token, amount, callParams) +} + +// FastBridgeTransferReceived is a paid mutator transaction binding the contract method 0x461e0c21. +// +// Solidity: function fastBridgeTransferReceived(address token, uint256 amount, bytes callParams) payable returns(bytes4) +func (_IFastBridgeRecipient *IFastBridgeRecipientTransactorSession) FastBridgeTransferReceived(token common.Address, amount *big.Int, callParams []byte) (*types.Transaction, error) { + return _IFastBridgeRecipient.Contract.FastBridgeTransferReceived(&_IFastBridgeRecipient.TransactOpts, token, amount, callParams) +} + +// IFastBridgeV2MetaData contains all meta data concerning the IFastBridgeV2 contract. +var IFastBridgeV2MetaData = &bind.MetaData{ + ABI: "[{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"BridgeDepositClaimed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"BridgeDepositRefunded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"name\":\"BridgeProofDisputed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"transactionHash\",\"type\":\"bytes32\"}],\"name\":\"BridgeProofProvided\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"quoteId\",\"type\":\"bytes\"}],\"name\":\"BridgeQuoteDetails\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"originChainId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"chainGasAmount\",\"type\":\"uint256\"}],\"name\":\"BridgeRelayed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"destChainId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"sendChainGas\",\"type\":\"bool\"}],\"name\":\"BridgeRequested\",\"type\":\"event\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"dstChainId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"sendChainGas\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"}],\"internalType\":\"structIFastBridge.BridgeParams\",\"name\":\"params\",\"type\":\"tuple\"}],\"name\":\"bridge\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"dstChainId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"sendChainGas\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"}],\"internalType\":\"structIFastBridge.BridgeParams\",\"name\":\"params\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"quoteRelayer\",\"type\":\"address\"},{\"internalType\":\"int256\",\"name\":\"quoteExclusivitySeconds\",\"type\":\"int256\"},{\"internalType\":\"bytes\",\"name\":\"quoteId\",\"type\":\"bytes\"},{\"internalType\":\"uint256\",\"name\":\"callValue\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"callParams\",\"type\":\"bytes\"}],\"internalType\":\"structIFastBridgeV2.BridgeParamsV2\",\"name\":\"paramsV2\",\"type\":\"tuple\"}],\"name\":\"bridge\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"}],\"name\":\"bridgeProofs\",\"outputs\":[{\"internalType\":\"uint96\",\"name\":\"timestamp\",\"type\":\"uint96\"},{\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"}],\"name\":\"bridgeRelays\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"}],\"name\":\"bridgeStatuses\",\"outputs\":[{\"internalType\":\"enumIFastBridgeV2.BridgeStatus\",\"name\":\"\",\"type\":\"uint8\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"name\":\"canClaim\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"claim\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"claim\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"}],\"name\":\"dispute\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"getBridgeTransaction\",\"outputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"originChainId\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"destChainId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"originSender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destRecipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"originFeeAmount\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"sendChainGas\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"}],\"internalType\":\"structIFastBridge.BridgeTransaction\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"getBridgeTransactionV2\",\"outputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"originChainId\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"destChainId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"originSender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destRecipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"originFeeAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"callValue\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"exclusivityRelayer\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"exclusivityEndTime\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"callParams\",\"type\":\"bytes\"}],\"internalType\":\"structIFastBridgeV2.BridgeTransactionV2\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"destTxHash\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"name\":\"prove\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"},{\"internalType\":\"bytes32\",\"name\":\"destTxHash\",\"type\":\"bytes32\"}],\"name\":\"prove\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"refund\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"relay\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"},{\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"name\":\"relay\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"}]", + Sigs: map[string]string{ + "45851694": "bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256))", + "bfc7c607": "bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256),(address,int256,bytes,uint256,bytes))", + "91ad5039": "bridgeProofs(bytes32)", + "8379a24f": "bridgeRelays(bytes32)", + "051287bc": "bridgeStatuses(bytes32)", + "aa9641ab": "canClaim(bytes32,address)", + "c63ff8dd": "claim(bytes)", + "41fcb612": "claim(bytes,address)", + "add98c70": "dispute(bytes32)", + "ac11fb1a": "getBridgeTransaction(bytes)", + "5aa6ccba": "getBridgeTransactionV2(bytes)", + "886d36ff": "prove(bytes,bytes32)", + "18e4357d": "prove(bytes32,bytes32,address)", + "5eb7d946": "refund(bytes)", + "8f0d6f17": "relay(bytes)", + "9c9545f0": "relay(bytes,address)", + }, +} + +// IFastBridgeV2ABI is the input ABI used to generate the binding from. +// Deprecated: Use IFastBridgeV2MetaData.ABI instead. +var IFastBridgeV2ABI = IFastBridgeV2MetaData.ABI + +// Deprecated: Use IFastBridgeV2MetaData.Sigs instead. +// IFastBridgeV2FuncSigs maps the 4-byte function signature to its string representation. +var IFastBridgeV2FuncSigs = IFastBridgeV2MetaData.Sigs + +// IFastBridgeV2 is an auto generated Go binding around an Ethereum contract. +type IFastBridgeV2 struct { + IFastBridgeV2Caller // Read-only binding to the contract + IFastBridgeV2Transactor // Write-only binding to the contract + IFastBridgeV2Filterer // Log filterer for contract events +} + +// IFastBridgeV2Caller is an auto generated read-only Go binding around an Ethereum contract. +type IFastBridgeV2Caller struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// IFastBridgeV2Transactor is an auto generated write-only Go binding around an Ethereum contract. +type IFastBridgeV2Transactor struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// IFastBridgeV2Filterer is an auto generated log filtering Go binding around an Ethereum contract events. +type IFastBridgeV2Filterer struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// IFastBridgeV2Session is an auto generated Go binding around an Ethereum contract, +// with pre-set call and transact options. +type IFastBridgeV2Session struct { + Contract *IFastBridgeV2 // Generic contract binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// IFastBridgeV2CallerSession is an auto generated read-only Go binding around an Ethereum contract, +// with pre-set call options. +type IFastBridgeV2CallerSession struct { + Contract *IFastBridgeV2Caller // Generic contract caller binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session +} + +// IFastBridgeV2TransactorSession is an auto generated write-only Go binding around an Ethereum contract, +// with pre-set transact options. +type IFastBridgeV2TransactorSession struct { + Contract *IFastBridgeV2Transactor // Generic contract transactor binding to set the session for + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// IFastBridgeV2Raw is an auto generated low-level Go binding around an Ethereum contract. +type IFastBridgeV2Raw struct { + Contract *IFastBridgeV2 // Generic contract binding to access the raw methods on +} + +// IFastBridgeV2CallerRaw is an auto generated low-level read-only Go binding around an Ethereum contract. +type IFastBridgeV2CallerRaw struct { + Contract *IFastBridgeV2Caller // Generic read-only contract binding to access the raw methods on +} + +// IFastBridgeV2TransactorRaw is an auto generated low-level write-only Go binding around an Ethereum contract. +type IFastBridgeV2TransactorRaw struct { + Contract *IFastBridgeV2Transactor // Generic write-only contract binding to access the raw methods on +} + +// NewIFastBridgeV2 creates a new instance of IFastBridgeV2, bound to a specific deployed contract. +func NewIFastBridgeV2(address common.Address, backend bind.ContractBackend) (*IFastBridgeV2, error) { + contract, err := bindIFastBridgeV2(address, backend, backend, backend) + if err != nil { + return nil, err + } + return &IFastBridgeV2{IFastBridgeV2Caller: IFastBridgeV2Caller{contract: contract}, IFastBridgeV2Transactor: IFastBridgeV2Transactor{contract: contract}, IFastBridgeV2Filterer: IFastBridgeV2Filterer{contract: contract}}, nil +} + +// NewIFastBridgeV2Caller creates a new read-only instance of IFastBridgeV2, bound to a specific deployed contract. +func NewIFastBridgeV2Caller(address common.Address, caller bind.ContractCaller) (*IFastBridgeV2Caller, error) { + contract, err := bindIFastBridgeV2(address, caller, nil, nil) + if err != nil { + return nil, err + } + return &IFastBridgeV2Caller{contract: contract}, nil +} + +// NewIFastBridgeV2Transactor creates a new write-only instance of IFastBridgeV2, bound to a specific deployed contract. +func NewIFastBridgeV2Transactor(address common.Address, transactor bind.ContractTransactor) (*IFastBridgeV2Transactor, error) { + contract, err := bindIFastBridgeV2(address, nil, transactor, nil) + if err != nil { + return nil, err + } + return &IFastBridgeV2Transactor{contract: contract}, nil +} + +// NewIFastBridgeV2Filterer creates a new log filterer instance of IFastBridgeV2, bound to a specific deployed contract. +func NewIFastBridgeV2Filterer(address common.Address, filterer bind.ContractFilterer) (*IFastBridgeV2Filterer, error) { + contract, err := bindIFastBridgeV2(address, nil, nil, filterer) + if err != nil { + return nil, err + } + return &IFastBridgeV2Filterer{contract: contract}, nil +} + +// bindIFastBridgeV2 binds a generic wrapper to an already deployed contract. +func bindIFastBridgeV2(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) { + parsed, err := IFastBridgeV2MetaData.GetAbi() + if err != nil { + return nil, err + } + return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil +} + +// Call invokes the (constant) contract method with params as input values and +// sets the output to result. The result type might be a single field for simple +// returns, a slice of interfaces for anonymous returns and a struct for named +// returns. +func (_IFastBridgeV2 *IFastBridgeV2Raw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _IFastBridgeV2.Contract.IFastBridgeV2Caller.contract.Call(opts, result, method, params...) +} + +// Transfer initiates a plain transaction to move funds to the contract, calling +// its default method if one is available. +func (_IFastBridgeV2 *IFastBridgeV2Raw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _IFastBridgeV2.Contract.IFastBridgeV2Transactor.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_IFastBridgeV2 *IFastBridgeV2Raw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _IFastBridgeV2.Contract.IFastBridgeV2Transactor.contract.Transact(opts, method, params...) +} + +// Call invokes the (constant) contract method with params as input values and +// sets the output to result. The result type might be a single field for simple +// returns, a slice of interfaces for anonymous returns and a struct for named +// returns. +func (_IFastBridgeV2 *IFastBridgeV2CallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _IFastBridgeV2.Contract.contract.Call(opts, result, method, params...) +} + +// Transfer initiates a plain transaction to move funds to the contract, calling +// its default method if one is available. +func (_IFastBridgeV2 *IFastBridgeV2TransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _IFastBridgeV2.Contract.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_IFastBridgeV2 *IFastBridgeV2TransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _IFastBridgeV2.Contract.contract.Transact(opts, method, params...) +} + +// BridgeProofs is a free data retrieval call binding the contract method 0x91ad5039. +// +// Solidity: function bridgeProofs(bytes32 transactionId) view returns(uint96 timestamp, address relayer) +func (_IFastBridgeV2 *IFastBridgeV2Caller) BridgeProofs(opts *bind.CallOpts, transactionId [32]byte) (struct { + Timestamp *big.Int + Relayer common.Address +}, error) { + var out []interface{} + err := _IFastBridgeV2.contract.Call(opts, &out, "bridgeProofs", transactionId) + + outstruct := new(struct { + Timestamp *big.Int + Relayer common.Address + }) + if err != nil { + return *outstruct, err + } + + outstruct.Timestamp = *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + outstruct.Relayer = *abi.ConvertType(out[1], new(common.Address)).(*common.Address) + + return *outstruct, err + +} + +// BridgeProofs is a free data retrieval call binding the contract method 0x91ad5039. +// +// Solidity: function bridgeProofs(bytes32 transactionId) view returns(uint96 timestamp, address relayer) +func (_IFastBridgeV2 *IFastBridgeV2Session) BridgeProofs(transactionId [32]byte) (struct { + Timestamp *big.Int + Relayer common.Address +}, error) { + return _IFastBridgeV2.Contract.BridgeProofs(&_IFastBridgeV2.CallOpts, transactionId) +} + +// BridgeProofs is a free data retrieval call binding the contract method 0x91ad5039. +// +// Solidity: function bridgeProofs(bytes32 transactionId) view returns(uint96 timestamp, address relayer) +func (_IFastBridgeV2 *IFastBridgeV2CallerSession) BridgeProofs(transactionId [32]byte) (struct { + Timestamp *big.Int + Relayer common.Address +}, error) { + return _IFastBridgeV2.Contract.BridgeProofs(&_IFastBridgeV2.CallOpts, transactionId) +} + +// BridgeRelays is a free data retrieval call binding the contract method 0x8379a24f. +// +// Solidity: function bridgeRelays(bytes32 transactionId) view returns(bool) +func (_IFastBridgeV2 *IFastBridgeV2Caller) BridgeRelays(opts *bind.CallOpts, transactionId [32]byte) (bool, error) { + var out []interface{} + err := _IFastBridgeV2.contract.Call(opts, &out, "bridgeRelays", transactionId) + + if err != nil { + return *new(bool), err + } + + out0 := *abi.ConvertType(out[0], new(bool)).(*bool) + + return out0, err + +} + +// BridgeRelays is a free data retrieval call binding the contract method 0x8379a24f. +// +// Solidity: function bridgeRelays(bytes32 transactionId) view returns(bool) +func (_IFastBridgeV2 *IFastBridgeV2Session) BridgeRelays(transactionId [32]byte) (bool, error) { + return _IFastBridgeV2.Contract.BridgeRelays(&_IFastBridgeV2.CallOpts, transactionId) +} + +// BridgeRelays is a free data retrieval call binding the contract method 0x8379a24f. +// +// Solidity: function bridgeRelays(bytes32 transactionId) view returns(bool) +func (_IFastBridgeV2 *IFastBridgeV2CallerSession) BridgeRelays(transactionId [32]byte) (bool, error) { + return _IFastBridgeV2.Contract.BridgeRelays(&_IFastBridgeV2.CallOpts, transactionId) +} + +// BridgeStatuses is a free data retrieval call binding the contract method 0x051287bc. +// +// Solidity: function bridgeStatuses(bytes32 transactionId) view returns(uint8) +func (_IFastBridgeV2 *IFastBridgeV2Caller) BridgeStatuses(opts *bind.CallOpts, transactionId [32]byte) (uint8, error) { + var out []interface{} + err := _IFastBridgeV2.contract.Call(opts, &out, "bridgeStatuses", transactionId) + + if err != nil { + return *new(uint8), err + } + + out0 := *abi.ConvertType(out[0], new(uint8)).(*uint8) + + return out0, err + +} + +// BridgeStatuses is a free data retrieval call binding the contract method 0x051287bc. +// +// Solidity: function bridgeStatuses(bytes32 transactionId) view returns(uint8) +func (_IFastBridgeV2 *IFastBridgeV2Session) BridgeStatuses(transactionId [32]byte) (uint8, error) { + return _IFastBridgeV2.Contract.BridgeStatuses(&_IFastBridgeV2.CallOpts, transactionId) +} + +// BridgeStatuses is a free data retrieval call binding the contract method 0x051287bc. +// +// Solidity: function bridgeStatuses(bytes32 transactionId) view returns(uint8) +func (_IFastBridgeV2 *IFastBridgeV2CallerSession) BridgeStatuses(transactionId [32]byte) (uint8, error) { + return _IFastBridgeV2.Contract.BridgeStatuses(&_IFastBridgeV2.CallOpts, transactionId) +} + +// CanClaim is a free data retrieval call binding the contract method 0xaa9641ab. +// +// Solidity: function canClaim(bytes32 transactionId, address relayer) view returns(bool) +func (_IFastBridgeV2 *IFastBridgeV2Caller) CanClaim(opts *bind.CallOpts, transactionId [32]byte, relayer common.Address) (bool, error) { + var out []interface{} + err := _IFastBridgeV2.contract.Call(opts, &out, "canClaim", transactionId, relayer) + + if err != nil { + return *new(bool), err + } + + out0 := *abi.ConvertType(out[0], new(bool)).(*bool) + + return out0, err + +} + +// CanClaim is a free data retrieval call binding the contract method 0xaa9641ab. +// +// Solidity: function canClaim(bytes32 transactionId, address relayer) view returns(bool) +func (_IFastBridgeV2 *IFastBridgeV2Session) CanClaim(transactionId [32]byte, relayer common.Address) (bool, error) { + return _IFastBridgeV2.Contract.CanClaim(&_IFastBridgeV2.CallOpts, transactionId, relayer) +} + +// CanClaim is a free data retrieval call binding the contract method 0xaa9641ab. +// +// Solidity: function canClaim(bytes32 transactionId, address relayer) view returns(bool) +func (_IFastBridgeV2 *IFastBridgeV2CallerSession) CanClaim(transactionId [32]byte, relayer common.Address) (bool, error) { + return _IFastBridgeV2.Contract.CanClaim(&_IFastBridgeV2.CallOpts, transactionId, relayer) +} + +// GetBridgeTransaction is a free data retrieval call binding the contract method 0xac11fb1a. +// +// Solidity: function getBridgeTransaction(bytes request) view returns((uint32,uint32,address,address,address,address,uint256,uint256,uint256,bool,uint256,uint256)) +func (_IFastBridgeV2 *IFastBridgeV2Caller) GetBridgeTransaction(opts *bind.CallOpts, request []byte) (IFastBridgeBridgeTransaction, error) { + var out []interface{} + err := _IFastBridgeV2.contract.Call(opts, &out, "getBridgeTransaction", request) + + if err != nil { + return *new(IFastBridgeBridgeTransaction), err + } + + out0 := *abi.ConvertType(out[0], new(IFastBridgeBridgeTransaction)).(*IFastBridgeBridgeTransaction) + + return out0, err + +} + +// GetBridgeTransaction is a free data retrieval call binding the contract method 0xac11fb1a. +// +// Solidity: function getBridgeTransaction(bytes request) view returns((uint32,uint32,address,address,address,address,uint256,uint256,uint256,bool,uint256,uint256)) +func (_IFastBridgeV2 *IFastBridgeV2Session) GetBridgeTransaction(request []byte) (IFastBridgeBridgeTransaction, error) { + return _IFastBridgeV2.Contract.GetBridgeTransaction(&_IFastBridgeV2.CallOpts, request) +} + +// GetBridgeTransaction is a free data retrieval call binding the contract method 0xac11fb1a. +// +// Solidity: function getBridgeTransaction(bytes request) view returns((uint32,uint32,address,address,address,address,uint256,uint256,uint256,bool,uint256,uint256)) +func (_IFastBridgeV2 *IFastBridgeV2CallerSession) GetBridgeTransaction(request []byte) (IFastBridgeBridgeTransaction, error) { + return _IFastBridgeV2.Contract.GetBridgeTransaction(&_IFastBridgeV2.CallOpts, request) +} + +// GetBridgeTransactionV2 is a free data retrieval call binding the contract method 0x5aa6ccba. +// +// Solidity: function getBridgeTransactionV2(bytes request) view returns((uint32,uint32,address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,address,uint256,bytes)) +func (_IFastBridgeV2 *IFastBridgeV2Caller) GetBridgeTransactionV2(opts *bind.CallOpts, request []byte) (IFastBridgeV2BridgeTransactionV2, error) { + var out []interface{} + err := _IFastBridgeV2.contract.Call(opts, &out, "getBridgeTransactionV2", request) + + if err != nil { + return *new(IFastBridgeV2BridgeTransactionV2), err + } + + out0 := *abi.ConvertType(out[0], new(IFastBridgeV2BridgeTransactionV2)).(*IFastBridgeV2BridgeTransactionV2) + + return out0, err + +} + +// GetBridgeTransactionV2 is a free data retrieval call binding the contract method 0x5aa6ccba. +// +// Solidity: function getBridgeTransactionV2(bytes request) view returns((uint32,uint32,address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,address,uint256,bytes)) +func (_IFastBridgeV2 *IFastBridgeV2Session) GetBridgeTransactionV2(request []byte) (IFastBridgeV2BridgeTransactionV2, error) { + return _IFastBridgeV2.Contract.GetBridgeTransactionV2(&_IFastBridgeV2.CallOpts, request) +} + +// GetBridgeTransactionV2 is a free data retrieval call binding the contract method 0x5aa6ccba. +// +// Solidity: function getBridgeTransactionV2(bytes request) view returns((uint32,uint32,address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,address,uint256,bytes)) +func (_IFastBridgeV2 *IFastBridgeV2CallerSession) GetBridgeTransactionV2(request []byte) (IFastBridgeV2BridgeTransactionV2, error) { + return _IFastBridgeV2.Contract.GetBridgeTransactionV2(&_IFastBridgeV2.CallOpts, request) +} + +// Bridge is a paid mutator transaction binding the contract method 0x45851694. +// +// Solidity: function bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256) params) payable returns() +func (_IFastBridgeV2 *IFastBridgeV2Transactor) Bridge(opts *bind.TransactOpts, params IFastBridgeBridgeParams) (*types.Transaction, error) { + return _IFastBridgeV2.contract.Transact(opts, "bridge", params) +} + +// Bridge is a paid mutator transaction binding the contract method 0x45851694. +// +// Solidity: function bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256) params) payable returns() +func (_IFastBridgeV2 *IFastBridgeV2Session) Bridge(params IFastBridgeBridgeParams) (*types.Transaction, error) { + return _IFastBridgeV2.Contract.Bridge(&_IFastBridgeV2.TransactOpts, params) +} + +// Bridge is a paid mutator transaction binding the contract method 0x45851694. +// +// Solidity: function bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256) params) payable returns() +func (_IFastBridgeV2 *IFastBridgeV2TransactorSession) Bridge(params IFastBridgeBridgeParams) (*types.Transaction, error) { + return _IFastBridgeV2.Contract.Bridge(&_IFastBridgeV2.TransactOpts, params) +} + +// Bridge0 is a paid mutator transaction binding the contract method 0xbfc7c607. +// +// Solidity: function bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256) params, (address,int256,bytes,uint256,bytes) paramsV2) payable returns() +func (_IFastBridgeV2 *IFastBridgeV2Transactor) Bridge0(opts *bind.TransactOpts, params IFastBridgeBridgeParams, paramsV2 IFastBridgeV2BridgeParamsV2) (*types.Transaction, error) { + return _IFastBridgeV2.contract.Transact(opts, "bridge0", params, paramsV2) +} + +// Bridge0 is a paid mutator transaction binding the contract method 0xbfc7c607. +// +// Solidity: function bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256) params, (address,int256,bytes,uint256,bytes) paramsV2) payable returns() +func (_IFastBridgeV2 *IFastBridgeV2Session) Bridge0(params IFastBridgeBridgeParams, paramsV2 IFastBridgeV2BridgeParamsV2) (*types.Transaction, error) { + return _IFastBridgeV2.Contract.Bridge0(&_IFastBridgeV2.TransactOpts, params, paramsV2) +} + +// Bridge0 is a paid mutator transaction binding the contract method 0xbfc7c607. +// +// Solidity: function bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256) params, (address,int256,bytes,uint256,bytes) paramsV2) payable returns() +func (_IFastBridgeV2 *IFastBridgeV2TransactorSession) Bridge0(params IFastBridgeBridgeParams, paramsV2 IFastBridgeV2BridgeParamsV2) (*types.Transaction, error) { + return _IFastBridgeV2.Contract.Bridge0(&_IFastBridgeV2.TransactOpts, params, paramsV2) +} + +// Claim is a paid mutator transaction binding the contract method 0x41fcb612. +// +// Solidity: function claim(bytes request, address to) returns() +func (_IFastBridgeV2 *IFastBridgeV2Transactor) Claim(opts *bind.TransactOpts, request []byte, to common.Address) (*types.Transaction, error) { + return _IFastBridgeV2.contract.Transact(opts, "claim", request, to) +} + +// Claim is a paid mutator transaction binding the contract method 0x41fcb612. +// +// Solidity: function claim(bytes request, address to) returns() +func (_IFastBridgeV2 *IFastBridgeV2Session) Claim(request []byte, to common.Address) (*types.Transaction, error) { + return _IFastBridgeV2.Contract.Claim(&_IFastBridgeV2.TransactOpts, request, to) +} + +// Claim is a paid mutator transaction binding the contract method 0x41fcb612. +// +// Solidity: function claim(bytes request, address to) returns() +func (_IFastBridgeV2 *IFastBridgeV2TransactorSession) Claim(request []byte, to common.Address) (*types.Transaction, error) { + return _IFastBridgeV2.Contract.Claim(&_IFastBridgeV2.TransactOpts, request, to) +} + +// Claim0 is a paid mutator transaction binding the contract method 0xc63ff8dd. +// +// Solidity: function claim(bytes request) returns() +func (_IFastBridgeV2 *IFastBridgeV2Transactor) Claim0(opts *bind.TransactOpts, request []byte) (*types.Transaction, error) { + return _IFastBridgeV2.contract.Transact(opts, "claim0", request) +} + +// Claim0 is a paid mutator transaction binding the contract method 0xc63ff8dd. +// +// Solidity: function claim(bytes request) returns() +func (_IFastBridgeV2 *IFastBridgeV2Session) Claim0(request []byte) (*types.Transaction, error) { + return _IFastBridgeV2.Contract.Claim0(&_IFastBridgeV2.TransactOpts, request) +} + +// Claim0 is a paid mutator transaction binding the contract method 0xc63ff8dd. +// +// Solidity: function claim(bytes request) returns() +func (_IFastBridgeV2 *IFastBridgeV2TransactorSession) Claim0(request []byte) (*types.Transaction, error) { + return _IFastBridgeV2.Contract.Claim0(&_IFastBridgeV2.TransactOpts, request) +} + +// Dispute is a paid mutator transaction binding the contract method 0xadd98c70. +// +// Solidity: function dispute(bytes32 transactionId) returns() +func (_IFastBridgeV2 *IFastBridgeV2Transactor) Dispute(opts *bind.TransactOpts, transactionId [32]byte) (*types.Transaction, error) { + return _IFastBridgeV2.contract.Transact(opts, "dispute", transactionId) +} + +// Dispute is a paid mutator transaction binding the contract method 0xadd98c70. +// +// Solidity: function dispute(bytes32 transactionId) returns() +func (_IFastBridgeV2 *IFastBridgeV2Session) Dispute(transactionId [32]byte) (*types.Transaction, error) { + return _IFastBridgeV2.Contract.Dispute(&_IFastBridgeV2.TransactOpts, transactionId) +} + +// Dispute is a paid mutator transaction binding the contract method 0xadd98c70. +// +// Solidity: function dispute(bytes32 transactionId) returns() +func (_IFastBridgeV2 *IFastBridgeV2TransactorSession) Dispute(transactionId [32]byte) (*types.Transaction, error) { + return _IFastBridgeV2.Contract.Dispute(&_IFastBridgeV2.TransactOpts, transactionId) +} + +// Prove is a paid mutator transaction binding the contract method 0x18e4357d. +// +// Solidity: function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) returns() +func (_IFastBridgeV2 *IFastBridgeV2Transactor) Prove(opts *bind.TransactOpts, transactionId [32]byte, destTxHash [32]byte, relayer common.Address) (*types.Transaction, error) { + return _IFastBridgeV2.contract.Transact(opts, "prove", transactionId, destTxHash, relayer) +} + +// Prove is a paid mutator transaction binding the contract method 0x18e4357d. +// +// Solidity: function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) returns() +func (_IFastBridgeV2 *IFastBridgeV2Session) Prove(transactionId [32]byte, destTxHash [32]byte, relayer common.Address) (*types.Transaction, error) { + return _IFastBridgeV2.Contract.Prove(&_IFastBridgeV2.TransactOpts, transactionId, destTxHash, relayer) +} + +// Prove is a paid mutator transaction binding the contract method 0x18e4357d. +// +// Solidity: function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) returns() +func (_IFastBridgeV2 *IFastBridgeV2TransactorSession) Prove(transactionId [32]byte, destTxHash [32]byte, relayer common.Address) (*types.Transaction, error) { + return _IFastBridgeV2.Contract.Prove(&_IFastBridgeV2.TransactOpts, transactionId, destTxHash, relayer) +} + +// Prove0 is a paid mutator transaction binding the contract method 0x886d36ff. +// +// Solidity: function prove(bytes request, bytes32 destTxHash) returns() +func (_IFastBridgeV2 *IFastBridgeV2Transactor) Prove0(opts *bind.TransactOpts, request []byte, destTxHash [32]byte) (*types.Transaction, error) { + return _IFastBridgeV2.contract.Transact(opts, "prove0", request, destTxHash) +} + +// Prove0 is a paid mutator transaction binding the contract method 0x886d36ff. +// +// Solidity: function prove(bytes request, bytes32 destTxHash) returns() +func (_IFastBridgeV2 *IFastBridgeV2Session) Prove0(request []byte, destTxHash [32]byte) (*types.Transaction, error) { + return _IFastBridgeV2.Contract.Prove0(&_IFastBridgeV2.TransactOpts, request, destTxHash) +} + +// Prove0 is a paid mutator transaction binding the contract method 0x886d36ff. +// +// Solidity: function prove(bytes request, bytes32 destTxHash) returns() +func (_IFastBridgeV2 *IFastBridgeV2TransactorSession) Prove0(request []byte, destTxHash [32]byte) (*types.Transaction, error) { + return _IFastBridgeV2.Contract.Prove0(&_IFastBridgeV2.TransactOpts, request, destTxHash) +} + +// Refund is a paid mutator transaction binding the contract method 0x5eb7d946. +// +// Solidity: function refund(bytes request) returns() +func (_IFastBridgeV2 *IFastBridgeV2Transactor) Refund(opts *bind.TransactOpts, request []byte) (*types.Transaction, error) { + return _IFastBridgeV2.contract.Transact(opts, "refund", request) +} + +// Refund is a paid mutator transaction binding the contract method 0x5eb7d946. +// +// Solidity: function refund(bytes request) returns() +func (_IFastBridgeV2 *IFastBridgeV2Session) Refund(request []byte) (*types.Transaction, error) { + return _IFastBridgeV2.Contract.Refund(&_IFastBridgeV2.TransactOpts, request) +} + +// Refund is a paid mutator transaction binding the contract method 0x5eb7d946. +// +// Solidity: function refund(bytes request) returns() +func (_IFastBridgeV2 *IFastBridgeV2TransactorSession) Refund(request []byte) (*types.Transaction, error) { + return _IFastBridgeV2.Contract.Refund(&_IFastBridgeV2.TransactOpts, request) +} + +// Relay is a paid mutator transaction binding the contract method 0x8f0d6f17. +// +// Solidity: function relay(bytes request) payable returns() +func (_IFastBridgeV2 *IFastBridgeV2Transactor) Relay(opts *bind.TransactOpts, request []byte) (*types.Transaction, error) { + return _IFastBridgeV2.contract.Transact(opts, "relay", request) +} + +// Relay is a paid mutator transaction binding the contract method 0x8f0d6f17. +// +// Solidity: function relay(bytes request) payable returns() +func (_IFastBridgeV2 *IFastBridgeV2Session) Relay(request []byte) (*types.Transaction, error) { + return _IFastBridgeV2.Contract.Relay(&_IFastBridgeV2.TransactOpts, request) +} + +// Relay is a paid mutator transaction binding the contract method 0x8f0d6f17. +// +// Solidity: function relay(bytes request) payable returns() +func (_IFastBridgeV2 *IFastBridgeV2TransactorSession) Relay(request []byte) (*types.Transaction, error) { + return _IFastBridgeV2.Contract.Relay(&_IFastBridgeV2.TransactOpts, request) +} + +// Relay0 is a paid mutator transaction binding the contract method 0x9c9545f0. +// +// Solidity: function relay(bytes request, address relayer) payable returns() +func (_IFastBridgeV2 *IFastBridgeV2Transactor) Relay0(opts *bind.TransactOpts, request []byte, relayer common.Address) (*types.Transaction, error) { + return _IFastBridgeV2.contract.Transact(opts, "relay0", request, relayer) +} + +// Relay0 is a paid mutator transaction binding the contract method 0x9c9545f0. +// +// Solidity: function relay(bytes request, address relayer) payable returns() +func (_IFastBridgeV2 *IFastBridgeV2Session) Relay0(request []byte, relayer common.Address) (*types.Transaction, error) { + return _IFastBridgeV2.Contract.Relay0(&_IFastBridgeV2.TransactOpts, request, relayer) +} + +// Relay0 is a paid mutator transaction binding the contract method 0x9c9545f0. +// +// Solidity: function relay(bytes request, address relayer) payable returns() +func (_IFastBridgeV2 *IFastBridgeV2TransactorSession) Relay0(request []byte, relayer common.Address) (*types.Transaction, error) { + return _IFastBridgeV2.Contract.Relay0(&_IFastBridgeV2.TransactOpts, request, relayer) +} + +// IFastBridgeV2BridgeDepositClaimedIterator is returned from FilterBridgeDepositClaimed and is used to iterate over the raw logs and unpacked data for BridgeDepositClaimed events raised by the IFastBridgeV2 contract. +type IFastBridgeV2BridgeDepositClaimedIterator struct { + Event *IFastBridgeV2BridgeDepositClaimed // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *IFastBridgeV2BridgeDepositClaimedIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(IFastBridgeV2BridgeDepositClaimed) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(IFastBridgeV2BridgeDepositClaimed) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *IFastBridgeV2BridgeDepositClaimedIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *IFastBridgeV2BridgeDepositClaimedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// IFastBridgeV2BridgeDepositClaimed represents a BridgeDepositClaimed event raised by the IFastBridgeV2 contract. +type IFastBridgeV2BridgeDepositClaimed struct { + TransactionId [32]byte + Relayer common.Address + To common.Address + Token common.Address + Amount *big.Int + Raw types.Log // Blockchain specific contextual infos +} + +// FilterBridgeDepositClaimed is a free log retrieval operation binding the contract event 0x582211c35a2139ac3bbaac74663c6a1f56c6cbb658b41fe11fd45a82074ac678. +// +// Solidity: event BridgeDepositClaimed(bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount) +func (_IFastBridgeV2 *IFastBridgeV2Filterer) FilterBridgeDepositClaimed(opts *bind.FilterOpts, transactionId [][32]byte, relayer []common.Address, to []common.Address) (*IFastBridgeV2BridgeDepositClaimedIterator, error) { + + var transactionIdRule []interface{} + for _, transactionIdItem := range transactionId { + transactionIdRule = append(transactionIdRule, transactionIdItem) + } + var relayerRule []interface{} + for _, relayerItem := range relayer { + relayerRule = append(relayerRule, relayerItem) + } + var toRule []interface{} + for _, toItem := range to { + toRule = append(toRule, toItem) + } + + logs, sub, err := _IFastBridgeV2.contract.FilterLogs(opts, "BridgeDepositClaimed", transactionIdRule, relayerRule, toRule) + if err != nil { + return nil, err + } + return &IFastBridgeV2BridgeDepositClaimedIterator{contract: _IFastBridgeV2.contract, event: "BridgeDepositClaimed", logs: logs, sub: sub}, nil +} + +// WatchBridgeDepositClaimed is a free log subscription operation binding the contract event 0x582211c35a2139ac3bbaac74663c6a1f56c6cbb658b41fe11fd45a82074ac678. +// +// Solidity: event BridgeDepositClaimed(bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount) +func (_IFastBridgeV2 *IFastBridgeV2Filterer) WatchBridgeDepositClaimed(opts *bind.WatchOpts, sink chan<- *IFastBridgeV2BridgeDepositClaimed, transactionId [][32]byte, relayer []common.Address, to []common.Address) (event.Subscription, error) { + + var transactionIdRule []interface{} + for _, transactionIdItem := range transactionId { + transactionIdRule = append(transactionIdRule, transactionIdItem) + } + var relayerRule []interface{} + for _, relayerItem := range relayer { + relayerRule = append(relayerRule, relayerItem) + } + var toRule []interface{} + for _, toItem := range to { + toRule = append(toRule, toItem) + } + + logs, sub, err := _IFastBridgeV2.contract.WatchLogs(opts, "BridgeDepositClaimed", transactionIdRule, relayerRule, toRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(IFastBridgeV2BridgeDepositClaimed) + if err := _IFastBridgeV2.contract.UnpackLog(event, "BridgeDepositClaimed", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseBridgeDepositClaimed is a log parse operation binding the contract event 0x582211c35a2139ac3bbaac74663c6a1f56c6cbb658b41fe11fd45a82074ac678. +// +// Solidity: event BridgeDepositClaimed(bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount) +func (_IFastBridgeV2 *IFastBridgeV2Filterer) ParseBridgeDepositClaimed(log types.Log) (*IFastBridgeV2BridgeDepositClaimed, error) { + event := new(IFastBridgeV2BridgeDepositClaimed) + if err := _IFastBridgeV2.contract.UnpackLog(event, "BridgeDepositClaimed", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// IFastBridgeV2BridgeDepositRefundedIterator is returned from FilterBridgeDepositRefunded and is used to iterate over the raw logs and unpacked data for BridgeDepositRefunded events raised by the IFastBridgeV2 contract. +type IFastBridgeV2BridgeDepositRefundedIterator struct { + Event *IFastBridgeV2BridgeDepositRefunded // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *IFastBridgeV2BridgeDepositRefundedIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(IFastBridgeV2BridgeDepositRefunded) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(IFastBridgeV2BridgeDepositRefunded) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *IFastBridgeV2BridgeDepositRefundedIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *IFastBridgeV2BridgeDepositRefundedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// IFastBridgeV2BridgeDepositRefunded represents a BridgeDepositRefunded event raised by the IFastBridgeV2 contract. +type IFastBridgeV2BridgeDepositRefunded struct { + TransactionId [32]byte + To common.Address + Token common.Address + Amount *big.Int + Raw types.Log // Blockchain specific contextual infos +} + +// FilterBridgeDepositRefunded is a free log retrieval operation binding the contract event 0xb4c55c0c9bc613519b920e88748090150b890a875d307f21bea7d4fb2e8bc958. +// +// Solidity: event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount) +func (_IFastBridgeV2 *IFastBridgeV2Filterer) FilterBridgeDepositRefunded(opts *bind.FilterOpts, transactionId [][32]byte, to []common.Address) (*IFastBridgeV2BridgeDepositRefundedIterator, error) { + + var transactionIdRule []interface{} + for _, transactionIdItem := range transactionId { + transactionIdRule = append(transactionIdRule, transactionIdItem) + } + var toRule []interface{} + for _, toItem := range to { + toRule = append(toRule, toItem) + } + + logs, sub, err := _IFastBridgeV2.contract.FilterLogs(opts, "BridgeDepositRefunded", transactionIdRule, toRule) + if err != nil { + return nil, err + } + return &IFastBridgeV2BridgeDepositRefundedIterator{contract: _IFastBridgeV2.contract, event: "BridgeDepositRefunded", logs: logs, sub: sub}, nil +} + +// WatchBridgeDepositRefunded is a free log subscription operation binding the contract event 0xb4c55c0c9bc613519b920e88748090150b890a875d307f21bea7d4fb2e8bc958. +// +// Solidity: event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount) +func (_IFastBridgeV2 *IFastBridgeV2Filterer) WatchBridgeDepositRefunded(opts *bind.WatchOpts, sink chan<- *IFastBridgeV2BridgeDepositRefunded, transactionId [][32]byte, to []common.Address) (event.Subscription, error) { + + var transactionIdRule []interface{} + for _, transactionIdItem := range transactionId { + transactionIdRule = append(transactionIdRule, transactionIdItem) + } + var toRule []interface{} + for _, toItem := range to { + toRule = append(toRule, toItem) + } + + logs, sub, err := _IFastBridgeV2.contract.WatchLogs(opts, "BridgeDepositRefunded", transactionIdRule, toRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(IFastBridgeV2BridgeDepositRefunded) + if err := _IFastBridgeV2.contract.UnpackLog(event, "BridgeDepositRefunded", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseBridgeDepositRefunded is a log parse operation binding the contract event 0xb4c55c0c9bc613519b920e88748090150b890a875d307f21bea7d4fb2e8bc958. +// +// Solidity: event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount) +func (_IFastBridgeV2 *IFastBridgeV2Filterer) ParseBridgeDepositRefunded(log types.Log) (*IFastBridgeV2BridgeDepositRefunded, error) { + event := new(IFastBridgeV2BridgeDepositRefunded) + if err := _IFastBridgeV2.contract.UnpackLog(event, "BridgeDepositRefunded", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// IFastBridgeV2BridgeProofDisputedIterator is returned from FilterBridgeProofDisputed and is used to iterate over the raw logs and unpacked data for BridgeProofDisputed events raised by the IFastBridgeV2 contract. +type IFastBridgeV2BridgeProofDisputedIterator struct { + Event *IFastBridgeV2BridgeProofDisputed // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *IFastBridgeV2BridgeProofDisputedIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(IFastBridgeV2BridgeProofDisputed) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(IFastBridgeV2BridgeProofDisputed) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *IFastBridgeV2BridgeProofDisputedIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *IFastBridgeV2BridgeProofDisputedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// IFastBridgeV2BridgeProofDisputed represents a BridgeProofDisputed event raised by the IFastBridgeV2 contract. +type IFastBridgeV2BridgeProofDisputed struct { + TransactionId [32]byte + Relayer common.Address + Raw types.Log // Blockchain specific contextual infos +} + +// FilterBridgeProofDisputed is a free log retrieval operation binding the contract event 0x0695cf1d39b3055dcd0fe02d8b47eaf0d5a13e1996de925de59d0ef9b7f7fad4. +// +// Solidity: event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer) +func (_IFastBridgeV2 *IFastBridgeV2Filterer) FilterBridgeProofDisputed(opts *bind.FilterOpts, transactionId [][32]byte, relayer []common.Address) (*IFastBridgeV2BridgeProofDisputedIterator, error) { + + var transactionIdRule []interface{} + for _, transactionIdItem := range transactionId { + transactionIdRule = append(transactionIdRule, transactionIdItem) + } + var relayerRule []interface{} + for _, relayerItem := range relayer { + relayerRule = append(relayerRule, relayerItem) + } + + logs, sub, err := _IFastBridgeV2.contract.FilterLogs(opts, "BridgeProofDisputed", transactionIdRule, relayerRule) + if err != nil { + return nil, err + } + return &IFastBridgeV2BridgeProofDisputedIterator{contract: _IFastBridgeV2.contract, event: "BridgeProofDisputed", logs: logs, sub: sub}, nil +} + +// WatchBridgeProofDisputed is a free log subscription operation binding the contract event 0x0695cf1d39b3055dcd0fe02d8b47eaf0d5a13e1996de925de59d0ef9b7f7fad4. +// +// Solidity: event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer) +func (_IFastBridgeV2 *IFastBridgeV2Filterer) WatchBridgeProofDisputed(opts *bind.WatchOpts, sink chan<- *IFastBridgeV2BridgeProofDisputed, transactionId [][32]byte, relayer []common.Address) (event.Subscription, error) { + + var transactionIdRule []interface{} + for _, transactionIdItem := range transactionId { + transactionIdRule = append(transactionIdRule, transactionIdItem) + } + var relayerRule []interface{} + for _, relayerItem := range relayer { + relayerRule = append(relayerRule, relayerItem) + } + + logs, sub, err := _IFastBridgeV2.contract.WatchLogs(opts, "BridgeProofDisputed", transactionIdRule, relayerRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(IFastBridgeV2BridgeProofDisputed) + if err := _IFastBridgeV2.contract.UnpackLog(event, "BridgeProofDisputed", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseBridgeProofDisputed is a log parse operation binding the contract event 0x0695cf1d39b3055dcd0fe02d8b47eaf0d5a13e1996de925de59d0ef9b7f7fad4. +// +// Solidity: event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer) +func (_IFastBridgeV2 *IFastBridgeV2Filterer) ParseBridgeProofDisputed(log types.Log) (*IFastBridgeV2BridgeProofDisputed, error) { + event := new(IFastBridgeV2BridgeProofDisputed) + if err := _IFastBridgeV2.contract.UnpackLog(event, "BridgeProofDisputed", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// IFastBridgeV2BridgeProofProvidedIterator is returned from FilterBridgeProofProvided and is used to iterate over the raw logs and unpacked data for BridgeProofProvided events raised by the IFastBridgeV2 contract. +type IFastBridgeV2BridgeProofProvidedIterator struct { + Event *IFastBridgeV2BridgeProofProvided // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *IFastBridgeV2BridgeProofProvidedIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(IFastBridgeV2BridgeProofProvided) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(IFastBridgeV2BridgeProofProvided) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *IFastBridgeV2BridgeProofProvidedIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *IFastBridgeV2BridgeProofProvidedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// IFastBridgeV2BridgeProofProvided represents a BridgeProofProvided event raised by the IFastBridgeV2 contract. +type IFastBridgeV2BridgeProofProvided struct { + TransactionId [32]byte + Relayer common.Address + TransactionHash [32]byte + Raw types.Log // Blockchain specific contextual infos +} + +// FilterBridgeProofProvided is a free log retrieval operation binding the contract event 0x4ac8af8a2cd87193d64dfc7a3b8d9923b714ec528b18725d080aa1299be0c5e4. +// +// Solidity: event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash) +func (_IFastBridgeV2 *IFastBridgeV2Filterer) FilterBridgeProofProvided(opts *bind.FilterOpts, transactionId [][32]byte, relayer []common.Address) (*IFastBridgeV2BridgeProofProvidedIterator, error) { + + var transactionIdRule []interface{} + for _, transactionIdItem := range transactionId { + transactionIdRule = append(transactionIdRule, transactionIdItem) + } + var relayerRule []interface{} + for _, relayerItem := range relayer { + relayerRule = append(relayerRule, relayerItem) + } + + logs, sub, err := _IFastBridgeV2.contract.FilterLogs(opts, "BridgeProofProvided", transactionIdRule, relayerRule) + if err != nil { + return nil, err + } + return &IFastBridgeV2BridgeProofProvidedIterator{contract: _IFastBridgeV2.contract, event: "BridgeProofProvided", logs: logs, sub: sub}, nil +} + +// WatchBridgeProofProvided is a free log subscription operation binding the contract event 0x4ac8af8a2cd87193d64dfc7a3b8d9923b714ec528b18725d080aa1299be0c5e4. +// +// Solidity: event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash) +func (_IFastBridgeV2 *IFastBridgeV2Filterer) WatchBridgeProofProvided(opts *bind.WatchOpts, sink chan<- *IFastBridgeV2BridgeProofProvided, transactionId [][32]byte, relayer []common.Address) (event.Subscription, error) { + + var transactionIdRule []interface{} + for _, transactionIdItem := range transactionId { + transactionIdRule = append(transactionIdRule, transactionIdItem) + } + var relayerRule []interface{} + for _, relayerItem := range relayer { + relayerRule = append(relayerRule, relayerItem) + } + + logs, sub, err := _IFastBridgeV2.contract.WatchLogs(opts, "BridgeProofProvided", transactionIdRule, relayerRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(IFastBridgeV2BridgeProofProvided) + if err := _IFastBridgeV2.contract.UnpackLog(event, "BridgeProofProvided", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseBridgeProofProvided is a log parse operation binding the contract event 0x4ac8af8a2cd87193d64dfc7a3b8d9923b714ec528b18725d080aa1299be0c5e4. +// +// Solidity: event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash) +func (_IFastBridgeV2 *IFastBridgeV2Filterer) ParseBridgeProofProvided(log types.Log) (*IFastBridgeV2BridgeProofProvided, error) { + event := new(IFastBridgeV2BridgeProofProvided) + if err := _IFastBridgeV2.contract.UnpackLog(event, "BridgeProofProvided", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// IFastBridgeV2BridgeQuoteDetailsIterator is returned from FilterBridgeQuoteDetails and is used to iterate over the raw logs and unpacked data for BridgeQuoteDetails events raised by the IFastBridgeV2 contract. +type IFastBridgeV2BridgeQuoteDetailsIterator struct { + Event *IFastBridgeV2BridgeQuoteDetails // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *IFastBridgeV2BridgeQuoteDetailsIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(IFastBridgeV2BridgeQuoteDetails) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(IFastBridgeV2BridgeQuoteDetails) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *IFastBridgeV2BridgeQuoteDetailsIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *IFastBridgeV2BridgeQuoteDetailsIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// IFastBridgeV2BridgeQuoteDetails represents a BridgeQuoteDetails event raised by the IFastBridgeV2 contract. +type IFastBridgeV2BridgeQuoteDetails struct { + TransactionId [32]byte + QuoteId []byte + Raw types.Log // Blockchain specific contextual infos +} + +// FilterBridgeQuoteDetails is a free log retrieval operation binding the contract event 0x3120e2bb59c86aca6890191a589a96af3662838efa374fbdcdf4c95bfe4a6c0e. +// +// Solidity: event BridgeQuoteDetails(bytes32 indexed transactionId, bytes quoteId) +func (_IFastBridgeV2 *IFastBridgeV2Filterer) FilterBridgeQuoteDetails(opts *bind.FilterOpts, transactionId [][32]byte) (*IFastBridgeV2BridgeQuoteDetailsIterator, error) { + + var transactionIdRule []interface{} + for _, transactionIdItem := range transactionId { + transactionIdRule = append(transactionIdRule, transactionIdItem) + } + + logs, sub, err := _IFastBridgeV2.contract.FilterLogs(opts, "BridgeQuoteDetails", transactionIdRule) + if err != nil { + return nil, err + } + return &IFastBridgeV2BridgeQuoteDetailsIterator{contract: _IFastBridgeV2.contract, event: "BridgeQuoteDetails", logs: logs, sub: sub}, nil +} + +// WatchBridgeQuoteDetails is a free log subscription operation binding the contract event 0x3120e2bb59c86aca6890191a589a96af3662838efa374fbdcdf4c95bfe4a6c0e. +// +// Solidity: event BridgeQuoteDetails(bytes32 indexed transactionId, bytes quoteId) +func (_IFastBridgeV2 *IFastBridgeV2Filterer) WatchBridgeQuoteDetails(opts *bind.WatchOpts, sink chan<- *IFastBridgeV2BridgeQuoteDetails, transactionId [][32]byte) (event.Subscription, error) { + + var transactionIdRule []interface{} + for _, transactionIdItem := range transactionId { + transactionIdRule = append(transactionIdRule, transactionIdItem) + } + + logs, sub, err := _IFastBridgeV2.contract.WatchLogs(opts, "BridgeQuoteDetails", transactionIdRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(IFastBridgeV2BridgeQuoteDetails) + if err := _IFastBridgeV2.contract.UnpackLog(event, "BridgeQuoteDetails", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseBridgeQuoteDetails is a log parse operation binding the contract event 0x3120e2bb59c86aca6890191a589a96af3662838efa374fbdcdf4c95bfe4a6c0e. +// +// Solidity: event BridgeQuoteDetails(bytes32 indexed transactionId, bytes quoteId) +func (_IFastBridgeV2 *IFastBridgeV2Filterer) ParseBridgeQuoteDetails(log types.Log) (*IFastBridgeV2BridgeQuoteDetails, error) { + event := new(IFastBridgeV2BridgeQuoteDetails) + if err := _IFastBridgeV2.contract.UnpackLog(event, "BridgeQuoteDetails", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// IFastBridgeV2BridgeRelayedIterator is returned from FilterBridgeRelayed and is used to iterate over the raw logs and unpacked data for BridgeRelayed events raised by the IFastBridgeV2 contract. +type IFastBridgeV2BridgeRelayedIterator struct { + Event *IFastBridgeV2BridgeRelayed // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *IFastBridgeV2BridgeRelayedIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(IFastBridgeV2BridgeRelayed) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(IFastBridgeV2BridgeRelayed) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *IFastBridgeV2BridgeRelayedIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *IFastBridgeV2BridgeRelayedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// IFastBridgeV2BridgeRelayed represents a BridgeRelayed event raised by the IFastBridgeV2 contract. +type IFastBridgeV2BridgeRelayed struct { + TransactionId [32]byte + Relayer common.Address + To common.Address + OriginChainId uint32 + OriginToken common.Address + DestToken common.Address + OriginAmount *big.Int + DestAmount *big.Int + ChainGasAmount *big.Int + Raw types.Log // Blockchain specific contextual infos +} + +// FilterBridgeRelayed is a free log retrieval operation binding the contract event 0xf8ae392d784b1ea5e8881bfa586d81abf07ef4f1e2fc75f7fe51c90f05199a5c. +// +// Solidity: event BridgeRelayed(bytes32 indexed transactionId, address indexed relayer, address indexed to, uint32 originChainId, address originToken, address destToken, uint256 originAmount, uint256 destAmount, uint256 chainGasAmount) +func (_IFastBridgeV2 *IFastBridgeV2Filterer) FilterBridgeRelayed(opts *bind.FilterOpts, transactionId [][32]byte, relayer []common.Address, to []common.Address) (*IFastBridgeV2BridgeRelayedIterator, error) { + + var transactionIdRule []interface{} + for _, transactionIdItem := range transactionId { + transactionIdRule = append(transactionIdRule, transactionIdItem) + } + var relayerRule []interface{} + for _, relayerItem := range relayer { + relayerRule = append(relayerRule, relayerItem) + } + var toRule []interface{} + for _, toItem := range to { + toRule = append(toRule, toItem) + } + + logs, sub, err := _IFastBridgeV2.contract.FilterLogs(opts, "BridgeRelayed", transactionIdRule, relayerRule, toRule) + if err != nil { + return nil, err + } + return &IFastBridgeV2BridgeRelayedIterator{contract: _IFastBridgeV2.contract, event: "BridgeRelayed", logs: logs, sub: sub}, nil +} + +// WatchBridgeRelayed is a free log subscription operation binding the contract event 0xf8ae392d784b1ea5e8881bfa586d81abf07ef4f1e2fc75f7fe51c90f05199a5c. +// +// Solidity: event BridgeRelayed(bytes32 indexed transactionId, address indexed relayer, address indexed to, uint32 originChainId, address originToken, address destToken, uint256 originAmount, uint256 destAmount, uint256 chainGasAmount) +func (_IFastBridgeV2 *IFastBridgeV2Filterer) WatchBridgeRelayed(opts *bind.WatchOpts, sink chan<- *IFastBridgeV2BridgeRelayed, transactionId [][32]byte, relayer []common.Address, to []common.Address) (event.Subscription, error) { + + var transactionIdRule []interface{} + for _, transactionIdItem := range transactionId { + transactionIdRule = append(transactionIdRule, transactionIdItem) + } + var relayerRule []interface{} + for _, relayerItem := range relayer { + relayerRule = append(relayerRule, relayerItem) + } + var toRule []interface{} + for _, toItem := range to { + toRule = append(toRule, toItem) + } + + logs, sub, err := _IFastBridgeV2.contract.WatchLogs(opts, "BridgeRelayed", transactionIdRule, relayerRule, toRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(IFastBridgeV2BridgeRelayed) + if err := _IFastBridgeV2.contract.UnpackLog(event, "BridgeRelayed", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseBridgeRelayed is a log parse operation binding the contract event 0xf8ae392d784b1ea5e8881bfa586d81abf07ef4f1e2fc75f7fe51c90f05199a5c. +// +// Solidity: event BridgeRelayed(bytes32 indexed transactionId, address indexed relayer, address indexed to, uint32 originChainId, address originToken, address destToken, uint256 originAmount, uint256 destAmount, uint256 chainGasAmount) +func (_IFastBridgeV2 *IFastBridgeV2Filterer) ParseBridgeRelayed(log types.Log) (*IFastBridgeV2BridgeRelayed, error) { + event := new(IFastBridgeV2BridgeRelayed) + if err := _IFastBridgeV2.contract.UnpackLog(event, "BridgeRelayed", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// IFastBridgeV2BridgeRequestedIterator is returned from FilterBridgeRequested and is used to iterate over the raw logs and unpacked data for BridgeRequested events raised by the IFastBridgeV2 contract. +type IFastBridgeV2BridgeRequestedIterator struct { + Event *IFastBridgeV2BridgeRequested // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *IFastBridgeV2BridgeRequestedIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(IFastBridgeV2BridgeRequested) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(IFastBridgeV2BridgeRequested) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *IFastBridgeV2BridgeRequestedIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *IFastBridgeV2BridgeRequestedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// IFastBridgeV2BridgeRequested represents a BridgeRequested event raised by the IFastBridgeV2 contract. +type IFastBridgeV2BridgeRequested struct { + TransactionId [32]byte + Sender common.Address + Request []byte + DestChainId uint32 + OriginToken common.Address + DestToken common.Address + OriginAmount *big.Int + DestAmount *big.Int + SendChainGas bool + Raw types.Log // Blockchain specific contextual infos +} + +// FilterBridgeRequested is a free log retrieval operation binding the contract event 0x120ea0364f36cdac7983bcfdd55270ca09d7f9b314a2ebc425a3b01ab1d6403a. +// +// Solidity: event BridgeRequested(bytes32 indexed transactionId, address indexed sender, bytes request, uint32 destChainId, address originToken, address destToken, uint256 originAmount, uint256 destAmount, bool sendChainGas) +func (_IFastBridgeV2 *IFastBridgeV2Filterer) FilterBridgeRequested(opts *bind.FilterOpts, transactionId [][32]byte, sender []common.Address) (*IFastBridgeV2BridgeRequestedIterator, error) { + + var transactionIdRule []interface{} + for _, transactionIdItem := range transactionId { + transactionIdRule = append(transactionIdRule, transactionIdItem) + } + var senderRule []interface{} + for _, senderItem := range sender { + senderRule = append(senderRule, senderItem) + } + + logs, sub, err := _IFastBridgeV2.contract.FilterLogs(opts, "BridgeRequested", transactionIdRule, senderRule) + if err != nil { + return nil, err + } + return &IFastBridgeV2BridgeRequestedIterator{contract: _IFastBridgeV2.contract, event: "BridgeRequested", logs: logs, sub: sub}, nil +} + +// WatchBridgeRequested is a free log subscription operation binding the contract event 0x120ea0364f36cdac7983bcfdd55270ca09d7f9b314a2ebc425a3b01ab1d6403a. +// +// Solidity: event BridgeRequested(bytes32 indexed transactionId, address indexed sender, bytes request, uint32 destChainId, address originToken, address destToken, uint256 originAmount, uint256 destAmount, bool sendChainGas) +func (_IFastBridgeV2 *IFastBridgeV2Filterer) WatchBridgeRequested(opts *bind.WatchOpts, sink chan<- *IFastBridgeV2BridgeRequested, transactionId [][32]byte, sender []common.Address) (event.Subscription, error) { + + var transactionIdRule []interface{} + for _, transactionIdItem := range transactionId { + transactionIdRule = append(transactionIdRule, transactionIdItem) + } + var senderRule []interface{} + for _, senderItem := range sender { + senderRule = append(senderRule, senderItem) + } + + logs, sub, err := _IFastBridgeV2.contract.WatchLogs(opts, "BridgeRequested", transactionIdRule, senderRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(IFastBridgeV2BridgeRequested) + if err := _IFastBridgeV2.contract.UnpackLog(event, "BridgeRequested", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseBridgeRequested is a log parse operation binding the contract event 0x120ea0364f36cdac7983bcfdd55270ca09d7f9b314a2ebc425a3b01ab1d6403a. +// +// Solidity: event BridgeRequested(bytes32 indexed transactionId, address indexed sender, bytes request, uint32 destChainId, address originToken, address destToken, uint256 originAmount, uint256 destAmount, bool sendChainGas) +func (_IFastBridgeV2 *IFastBridgeV2Filterer) ParseBridgeRequested(log types.Log) (*IFastBridgeV2BridgeRequested, error) { + event := new(IFastBridgeV2BridgeRequested) + if err := _IFastBridgeV2.contract.UnpackLog(event, "BridgeRequested", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// IFastBridgeV2ErrorsMetaData contains all meta data concerning the IFastBridgeV2Errors contract. +var IFastBridgeV2ErrorsMetaData = &bind.MetaData{ + ABI: "[{\"inputs\":[],\"name\":\"AmountIncorrect\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"CallParamsLengthAboveMax\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ChainIncorrect\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DeadlineExceeded\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DeadlineNotExceeded\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DeadlineTooShort\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DisputePeriodNotPassed\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DisputePeriodPassed\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ExclusivityParamsIncorrect\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ExclusivityPeriodNotPassed\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"MsgValueIncorrect\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"NativeTokenCallValueNotSupported\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"RecipientIncorrectReturnValue\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"RecipientNoReturnValue\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"SenderIncorrect\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"StatusIncorrect\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"TransactionRelayed\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ZeroAddress\",\"type\":\"error\"}]", +} + +// IFastBridgeV2ErrorsABI is the input ABI used to generate the binding from. +// Deprecated: Use IFastBridgeV2ErrorsMetaData.ABI instead. +var IFastBridgeV2ErrorsABI = IFastBridgeV2ErrorsMetaData.ABI + +// IFastBridgeV2Errors is an auto generated Go binding around an Ethereum contract. +type IFastBridgeV2Errors struct { + IFastBridgeV2ErrorsCaller // Read-only binding to the contract + IFastBridgeV2ErrorsTransactor // Write-only binding to the contract + IFastBridgeV2ErrorsFilterer // Log filterer for contract events +} + +// IFastBridgeV2ErrorsCaller is an auto generated read-only Go binding around an Ethereum contract. +type IFastBridgeV2ErrorsCaller struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// IFastBridgeV2ErrorsTransactor is an auto generated write-only Go binding around an Ethereum contract. +type IFastBridgeV2ErrorsTransactor struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// IFastBridgeV2ErrorsFilterer is an auto generated log filtering Go binding around an Ethereum contract events. +type IFastBridgeV2ErrorsFilterer struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// IFastBridgeV2ErrorsSession is an auto generated Go binding around an Ethereum contract, +// with pre-set call and transact options. +type IFastBridgeV2ErrorsSession struct { + Contract *IFastBridgeV2Errors // Generic contract binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// IFastBridgeV2ErrorsCallerSession is an auto generated read-only Go binding around an Ethereum contract, +// with pre-set call options. +type IFastBridgeV2ErrorsCallerSession struct { + Contract *IFastBridgeV2ErrorsCaller // Generic contract caller binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session +} + +// IFastBridgeV2ErrorsTransactorSession is an auto generated write-only Go binding around an Ethereum contract, +// with pre-set transact options. +type IFastBridgeV2ErrorsTransactorSession struct { + Contract *IFastBridgeV2ErrorsTransactor // Generic contract transactor binding to set the session for + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// IFastBridgeV2ErrorsRaw is an auto generated low-level Go binding around an Ethereum contract. +type IFastBridgeV2ErrorsRaw struct { + Contract *IFastBridgeV2Errors // Generic contract binding to access the raw methods on +} + +// IFastBridgeV2ErrorsCallerRaw is an auto generated low-level read-only Go binding around an Ethereum contract. +type IFastBridgeV2ErrorsCallerRaw struct { + Contract *IFastBridgeV2ErrorsCaller // Generic read-only contract binding to access the raw methods on +} + +// IFastBridgeV2ErrorsTransactorRaw is an auto generated low-level write-only Go binding around an Ethereum contract. +type IFastBridgeV2ErrorsTransactorRaw struct { + Contract *IFastBridgeV2ErrorsTransactor // Generic write-only contract binding to access the raw methods on +} + +// NewIFastBridgeV2Errors creates a new instance of IFastBridgeV2Errors, bound to a specific deployed contract. +func NewIFastBridgeV2Errors(address common.Address, backend bind.ContractBackend) (*IFastBridgeV2Errors, error) { + contract, err := bindIFastBridgeV2Errors(address, backend, backend, backend) + if err != nil { + return nil, err + } + return &IFastBridgeV2Errors{IFastBridgeV2ErrorsCaller: IFastBridgeV2ErrorsCaller{contract: contract}, IFastBridgeV2ErrorsTransactor: IFastBridgeV2ErrorsTransactor{contract: contract}, IFastBridgeV2ErrorsFilterer: IFastBridgeV2ErrorsFilterer{contract: contract}}, nil +} + +// NewIFastBridgeV2ErrorsCaller creates a new read-only instance of IFastBridgeV2Errors, bound to a specific deployed contract. +func NewIFastBridgeV2ErrorsCaller(address common.Address, caller bind.ContractCaller) (*IFastBridgeV2ErrorsCaller, error) { + contract, err := bindIFastBridgeV2Errors(address, caller, nil, nil) + if err != nil { + return nil, err + } + return &IFastBridgeV2ErrorsCaller{contract: contract}, nil +} + +// NewIFastBridgeV2ErrorsTransactor creates a new write-only instance of IFastBridgeV2Errors, bound to a specific deployed contract. +func NewIFastBridgeV2ErrorsTransactor(address common.Address, transactor bind.ContractTransactor) (*IFastBridgeV2ErrorsTransactor, error) { + contract, err := bindIFastBridgeV2Errors(address, nil, transactor, nil) + if err != nil { + return nil, err + } + return &IFastBridgeV2ErrorsTransactor{contract: contract}, nil +} + +// NewIFastBridgeV2ErrorsFilterer creates a new log filterer instance of IFastBridgeV2Errors, bound to a specific deployed contract. +func NewIFastBridgeV2ErrorsFilterer(address common.Address, filterer bind.ContractFilterer) (*IFastBridgeV2ErrorsFilterer, error) { + contract, err := bindIFastBridgeV2Errors(address, nil, nil, filterer) + if err != nil { + return nil, err + } + return &IFastBridgeV2ErrorsFilterer{contract: contract}, nil +} + +// bindIFastBridgeV2Errors binds a generic wrapper to an already deployed contract. +func bindIFastBridgeV2Errors(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) { + parsed, err := IFastBridgeV2ErrorsMetaData.GetAbi() + if err != nil { + return nil, err + } + return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil +} + +// Call invokes the (constant) contract method with params as input values and +// sets the output to result. The result type might be a single field for simple +// returns, a slice of interfaces for anonymous returns and a struct for named +// returns. +func (_IFastBridgeV2Errors *IFastBridgeV2ErrorsRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _IFastBridgeV2Errors.Contract.IFastBridgeV2ErrorsCaller.contract.Call(opts, result, method, params...) +} + +// Transfer initiates a plain transaction to move funds to the contract, calling +// its default method if one is available. +func (_IFastBridgeV2Errors *IFastBridgeV2ErrorsRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _IFastBridgeV2Errors.Contract.IFastBridgeV2ErrorsTransactor.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_IFastBridgeV2Errors *IFastBridgeV2ErrorsRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _IFastBridgeV2Errors.Contract.IFastBridgeV2ErrorsTransactor.contract.Transact(opts, method, params...) +} + +// Call invokes the (constant) contract method with params as input values and +// sets the output to result. The result type might be a single field for simple +// returns, a slice of interfaces for anonymous returns and a struct for named +// returns. +func (_IFastBridgeV2Errors *IFastBridgeV2ErrorsCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _IFastBridgeV2Errors.Contract.contract.Call(opts, result, method, params...) +} + +// Transfer initiates a plain transaction to move funds to the contract, calling +// its default method if one is available. +func (_IFastBridgeV2Errors *IFastBridgeV2ErrorsTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _IFastBridgeV2Errors.Contract.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_IFastBridgeV2Errors *IFastBridgeV2ErrorsTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _IFastBridgeV2Errors.Contract.contract.Transact(opts, method, params...) +} + +// SafeERC20MetaData contains all meta data concerning the SafeERC20 contract. +var SafeERC20MetaData = &bind.MetaData{ + ABI: "[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"currentAllowance\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"requestedDecrease\",\"type\":\"uint256\"}],\"name\":\"SafeERC20FailedDecreaseAllowance\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"}],\"name\":\"SafeERC20FailedOperation\",\"type\":\"error\"}]", + Bin: "0x60556032600b8282823980515f1a607314602657634e487b7160e01b5f525f60045260245ffd5b305f52607381538281f3fe730000000000000000000000000000000000000000301460806040525f80fdfea26469706673582212206104d055d945cd85c5e0a242eb38679d97b94eed1093fc3540437ea8fe4ace7364736f6c63430008180033", +} + +// SafeERC20ABI is the input ABI used to generate the binding from. +// Deprecated: Use SafeERC20MetaData.ABI instead. +var SafeERC20ABI = SafeERC20MetaData.ABI + +// SafeERC20Bin is the compiled bytecode used for deploying new contracts. +// Deprecated: Use SafeERC20MetaData.Bin instead. +var SafeERC20Bin = SafeERC20MetaData.Bin + +// DeploySafeERC20 deploys a new Ethereum contract, binding an instance of SafeERC20 to it. +func DeploySafeERC20(auth *bind.TransactOpts, backend bind.ContractBackend) (common.Address, *types.Transaction, *SafeERC20, error) { + parsed, err := SafeERC20MetaData.GetAbi() + if err != nil { + return common.Address{}, nil, nil, err + } + if parsed == nil { + return common.Address{}, nil, nil, errors.New("GetABI returned nil") + } + + address, tx, contract, err := bind.DeployContract(auth, *parsed, common.FromHex(SafeERC20Bin), backend) + if err != nil { + return common.Address{}, nil, nil, err + } + return address, tx, &SafeERC20{SafeERC20Caller: SafeERC20Caller{contract: contract}, SafeERC20Transactor: SafeERC20Transactor{contract: contract}, SafeERC20Filterer: SafeERC20Filterer{contract: contract}}, nil +} + +// SafeERC20 is an auto generated Go binding around an Ethereum contract. +type SafeERC20 struct { + SafeERC20Caller // Read-only binding to the contract + SafeERC20Transactor // Write-only binding to the contract + SafeERC20Filterer // Log filterer for contract events +} + +// SafeERC20Caller is an auto generated read-only Go binding around an Ethereum contract. +type SafeERC20Caller struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// SafeERC20Transactor is an auto generated write-only Go binding around an Ethereum contract. +type SafeERC20Transactor struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// SafeERC20Filterer is an auto generated log filtering Go binding around an Ethereum contract events. +type SafeERC20Filterer struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// SafeERC20Session is an auto generated Go binding around an Ethereum contract, +// with pre-set call and transact options. +type SafeERC20Session struct { + Contract *SafeERC20 // Generic contract binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// SafeERC20CallerSession is an auto generated read-only Go binding around an Ethereum contract, +// with pre-set call options. +type SafeERC20CallerSession struct { + Contract *SafeERC20Caller // Generic contract caller binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session +} + +// SafeERC20TransactorSession is an auto generated write-only Go binding around an Ethereum contract, +// with pre-set transact options. +type SafeERC20TransactorSession struct { + Contract *SafeERC20Transactor // Generic contract transactor binding to set the session for + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// SafeERC20Raw is an auto generated low-level Go binding around an Ethereum contract. +type SafeERC20Raw struct { + Contract *SafeERC20 // Generic contract binding to access the raw methods on +} + +// SafeERC20CallerRaw is an auto generated low-level read-only Go binding around an Ethereum contract. +type SafeERC20CallerRaw struct { + Contract *SafeERC20Caller // Generic read-only contract binding to access the raw methods on +} + +// SafeERC20TransactorRaw is an auto generated low-level write-only Go binding around an Ethereum contract. +type SafeERC20TransactorRaw struct { + Contract *SafeERC20Transactor // Generic write-only contract binding to access the raw methods on +} + +// NewSafeERC20 creates a new instance of SafeERC20, bound to a specific deployed contract. +func NewSafeERC20(address common.Address, backend bind.ContractBackend) (*SafeERC20, error) { + contract, err := bindSafeERC20(address, backend, backend, backend) + if err != nil { + return nil, err + } + return &SafeERC20{SafeERC20Caller: SafeERC20Caller{contract: contract}, SafeERC20Transactor: SafeERC20Transactor{contract: contract}, SafeERC20Filterer: SafeERC20Filterer{contract: contract}}, nil +} + +// NewSafeERC20Caller creates a new read-only instance of SafeERC20, bound to a specific deployed contract. +func NewSafeERC20Caller(address common.Address, caller bind.ContractCaller) (*SafeERC20Caller, error) { + contract, err := bindSafeERC20(address, caller, nil, nil) + if err != nil { + return nil, err + } + return &SafeERC20Caller{contract: contract}, nil +} + +// NewSafeERC20Transactor creates a new write-only instance of SafeERC20, bound to a specific deployed contract. +func NewSafeERC20Transactor(address common.Address, transactor bind.ContractTransactor) (*SafeERC20Transactor, error) { + contract, err := bindSafeERC20(address, nil, transactor, nil) + if err != nil { + return nil, err + } + return &SafeERC20Transactor{contract: contract}, nil +} + +// NewSafeERC20Filterer creates a new log filterer instance of SafeERC20, bound to a specific deployed contract. +func NewSafeERC20Filterer(address common.Address, filterer bind.ContractFilterer) (*SafeERC20Filterer, error) { + contract, err := bindSafeERC20(address, nil, nil, filterer) + if err != nil { + return nil, err + } + return &SafeERC20Filterer{contract: contract}, nil +} + +// bindSafeERC20 binds a generic wrapper to an already deployed contract. +func bindSafeERC20(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) { + parsed, err := SafeERC20MetaData.GetAbi() + if err != nil { + return nil, err + } + return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil +} + +// Call invokes the (constant) contract method with params as input values and +// sets the output to result. The result type might be a single field for simple +// returns, a slice of interfaces for anonymous returns and a struct for named +// returns. +func (_SafeERC20 *SafeERC20Raw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _SafeERC20.Contract.SafeERC20Caller.contract.Call(opts, result, method, params...) +} + +// Transfer initiates a plain transaction to move funds to the contract, calling +// its default method if one is available. +func (_SafeERC20 *SafeERC20Raw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _SafeERC20.Contract.SafeERC20Transactor.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_SafeERC20 *SafeERC20Raw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _SafeERC20.Contract.SafeERC20Transactor.contract.Transact(opts, method, params...) +} + +// Call invokes the (constant) contract method with params as input values and +// sets the output to result. The result type might be a single field for simple +// returns, a slice of interfaces for anonymous returns and a struct for named +// returns. +func (_SafeERC20 *SafeERC20CallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _SafeERC20.Contract.contract.Call(opts, result, method, params...) +} + +// Transfer initiates a plain transaction to move funds to the contract, calling +// its default method if one is available. +func (_SafeERC20 *SafeERC20TransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _SafeERC20.Contract.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_SafeERC20 *SafeERC20TransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _SafeERC20.Contract.contract.Transact(opts, method, params...) +} + +// UniversalTokenLibMetaData contains all meta data concerning the UniversalTokenLib contract. +var UniversalTokenLibMetaData = &bind.MetaData{ + ABI: "[]", + Bin: "0x60556032600b8282823980515f1a607314602657634e487b7160e01b5f525f60045260245ffd5b305f52607381538281f3fe730000000000000000000000000000000000000000301460806040525f80fdfea2646970667358221220b863ead2f0a667d62ff1983d9a28f2cdc6740a5303e83e27e29c037676ea45c264736f6c63430008180033", +} + +// UniversalTokenLibABI is the input ABI used to generate the binding from. +// Deprecated: Use UniversalTokenLibMetaData.ABI instead. +var UniversalTokenLibABI = UniversalTokenLibMetaData.ABI + +// UniversalTokenLibBin is the compiled bytecode used for deploying new contracts. +// Deprecated: Use UniversalTokenLibMetaData.Bin instead. +var UniversalTokenLibBin = UniversalTokenLibMetaData.Bin + +// DeployUniversalTokenLib deploys a new Ethereum contract, binding an instance of UniversalTokenLib to it. +func DeployUniversalTokenLib(auth *bind.TransactOpts, backend bind.ContractBackend) (common.Address, *types.Transaction, *UniversalTokenLib, error) { + parsed, err := UniversalTokenLibMetaData.GetAbi() + if err != nil { + return common.Address{}, nil, nil, err + } + if parsed == nil { + return common.Address{}, nil, nil, errors.New("GetABI returned nil") + } + + address, tx, contract, err := bind.DeployContract(auth, *parsed, common.FromHex(UniversalTokenLibBin), backend) + if err != nil { + return common.Address{}, nil, nil, err + } + return address, tx, &UniversalTokenLib{UniversalTokenLibCaller: UniversalTokenLibCaller{contract: contract}, UniversalTokenLibTransactor: UniversalTokenLibTransactor{contract: contract}, UniversalTokenLibFilterer: UniversalTokenLibFilterer{contract: contract}}, nil +} + +// UniversalTokenLib is an auto generated Go binding around an Ethereum contract. +type UniversalTokenLib struct { + UniversalTokenLibCaller // Read-only binding to the contract + UniversalTokenLibTransactor // Write-only binding to the contract + UniversalTokenLibFilterer // Log filterer for contract events +} + +// UniversalTokenLibCaller is an auto generated read-only Go binding around an Ethereum contract. +type UniversalTokenLibCaller struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// UniversalTokenLibTransactor is an auto generated write-only Go binding around an Ethereum contract. +type UniversalTokenLibTransactor struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// UniversalTokenLibFilterer is an auto generated log filtering Go binding around an Ethereum contract events. +type UniversalTokenLibFilterer struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// UniversalTokenLibSession is an auto generated Go binding around an Ethereum contract, +// with pre-set call and transact options. +type UniversalTokenLibSession struct { + Contract *UniversalTokenLib // Generic contract binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// UniversalTokenLibCallerSession is an auto generated read-only Go binding around an Ethereum contract, +// with pre-set call options. +type UniversalTokenLibCallerSession struct { + Contract *UniversalTokenLibCaller // Generic contract caller binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session +} + +// UniversalTokenLibTransactorSession is an auto generated write-only Go binding around an Ethereum contract, +// with pre-set transact options. +type UniversalTokenLibTransactorSession struct { + Contract *UniversalTokenLibTransactor // Generic contract transactor binding to set the session for + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// UniversalTokenLibRaw is an auto generated low-level Go binding around an Ethereum contract. +type UniversalTokenLibRaw struct { + Contract *UniversalTokenLib // Generic contract binding to access the raw methods on +} + +// UniversalTokenLibCallerRaw is an auto generated low-level read-only Go binding around an Ethereum contract. +type UniversalTokenLibCallerRaw struct { + Contract *UniversalTokenLibCaller // Generic read-only contract binding to access the raw methods on +} + +// UniversalTokenLibTransactorRaw is an auto generated low-level write-only Go binding around an Ethereum contract. +type UniversalTokenLibTransactorRaw struct { + Contract *UniversalTokenLibTransactor // Generic write-only contract binding to access the raw methods on +} + +// NewUniversalTokenLib creates a new instance of UniversalTokenLib, bound to a specific deployed contract. +func NewUniversalTokenLib(address common.Address, backend bind.ContractBackend) (*UniversalTokenLib, error) { + contract, err := bindUniversalTokenLib(address, backend, backend, backend) + if err != nil { + return nil, err + } + return &UniversalTokenLib{UniversalTokenLibCaller: UniversalTokenLibCaller{contract: contract}, UniversalTokenLibTransactor: UniversalTokenLibTransactor{contract: contract}, UniversalTokenLibFilterer: UniversalTokenLibFilterer{contract: contract}}, nil +} + +// NewUniversalTokenLibCaller creates a new read-only instance of UniversalTokenLib, bound to a specific deployed contract. +func NewUniversalTokenLibCaller(address common.Address, caller bind.ContractCaller) (*UniversalTokenLibCaller, error) { + contract, err := bindUniversalTokenLib(address, caller, nil, nil) + if err != nil { + return nil, err + } + return &UniversalTokenLibCaller{contract: contract}, nil +} + +// NewUniversalTokenLibTransactor creates a new write-only instance of UniversalTokenLib, bound to a specific deployed contract. +func NewUniversalTokenLibTransactor(address common.Address, transactor bind.ContractTransactor) (*UniversalTokenLibTransactor, error) { + contract, err := bindUniversalTokenLib(address, nil, transactor, nil) + if err != nil { + return nil, err + } + return &UniversalTokenLibTransactor{contract: contract}, nil +} + +// NewUniversalTokenLibFilterer creates a new log filterer instance of UniversalTokenLib, bound to a specific deployed contract. +func NewUniversalTokenLibFilterer(address common.Address, filterer bind.ContractFilterer) (*UniversalTokenLibFilterer, error) { + contract, err := bindUniversalTokenLib(address, nil, nil, filterer) + if err != nil { + return nil, err + } + return &UniversalTokenLibFilterer{contract: contract}, nil +} + +// bindUniversalTokenLib binds a generic wrapper to an already deployed contract. +func bindUniversalTokenLib(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) { + parsed, err := UniversalTokenLibMetaData.GetAbi() + if err != nil { + return nil, err + } + return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil +} + +// Call invokes the (constant) contract method with params as input values and +// sets the output to result. The result type might be a single field for simple +// returns, a slice of interfaces for anonymous returns and a struct for named +// returns. +func (_UniversalTokenLib *UniversalTokenLibRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _UniversalTokenLib.Contract.UniversalTokenLibCaller.contract.Call(opts, result, method, params...) +} + +// Transfer initiates a plain transaction to move funds to the contract, calling +// its default method if one is available. +func (_UniversalTokenLib *UniversalTokenLibRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _UniversalTokenLib.Contract.UniversalTokenLibTransactor.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_UniversalTokenLib *UniversalTokenLibRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _UniversalTokenLib.Contract.UniversalTokenLibTransactor.contract.Transact(opts, method, params...) +} + +// Call invokes the (constant) contract method with params as input values and +// sets the output to result. The result type might be a single field for simple +// returns, a slice of interfaces for anonymous returns and a struct for named +// returns. +func (_UniversalTokenLib *UniversalTokenLibCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _UniversalTokenLib.Contract.contract.Call(opts, result, method, params...) +} + +// Transfer initiates a plain transaction to move funds to the contract, calling +// its default method if one is available. +func (_UniversalTokenLib *UniversalTokenLibTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _UniversalTokenLib.Contract.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_UniversalTokenLib *UniversalTokenLibTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _UniversalTokenLib.Contract.contract.Transact(opts, method, params...) +} diff --git a/services/rfq/contracts/fastbridgev2/fastbridgev2.contractinfo.json b/services/rfq/contracts/fastbridgev2/fastbridgev2.contractinfo.json new file mode 100644 index 0000000000..1cf3c2b242 --- /dev/null +++ b/services/rfq/contracts/fastbridgev2/fastbridgev2.contractinfo.json @@ -0,0 +1 @@ +{"solidity/FastBridgeV2.sol:AccessControl":{"code":"0x","runtime-code":"0x","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.24 ^0.8.0 ^0.8.20;\n\n// contracts/interfaces/IAdmin.sol\n\ninterface IAdmin {\n // ============ Events ============\n\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n event ChainGasAmountUpdated(uint256 oldChainGasAmount, uint256 newChainGasAmount);\n\n // ============ Methods ============\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n\n function setChainGasAmount(uint256 newChainGasAmount) external;\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IFastBridgeRecipient.sol\n\ninterface IFastBridgeRecipient {\n function fastBridgeTransferReceived(\n address token,\n uint256 amount,\n bytes memory callParams\n )\n external\n payable\n returns (bytes4);\n}\n\n// contracts/interfaces/IFastBridgeV2Errors.sol\n\ninterface IFastBridgeV2Errors {\n error AmountIncorrect();\n error CallParamsLengthAboveMax();\n error ChainIncorrect();\n error ExclusivityParamsIncorrect();\n error MsgValueIncorrect();\n error NativeTokenCallValueNotSupported();\n error SenderIncorrect();\n error StatusIncorrect();\n error ZeroAddress();\n\n error RecipientIncorrectReturnValue();\n error RecipientNoReturnValue();\n\n error DeadlineExceeded();\n error DeadlineNotExceeded();\n error DeadlineTooShort();\n error DisputePeriodNotPassed();\n error DisputePeriodPassed();\n error ExclusivityPeriodNotPassed();\n\n error TransactionRelayed();\n}\n\n// contracts/libs/Errors.sol\n\nerror DeadlineExceeded();\nerror DeadlineNotExceeded();\nerror DeadlineTooShort();\nerror InsufficientOutputAmount();\n\nerror MsgValueIncorrect();\nerror PoolNotFound();\nerror TokenAddressMismatch();\nerror TokenNotContract();\nerror TokenNotETH();\nerror TokensIdentical();\n\nerror ChainIncorrect();\nerror AmountIncorrect();\nerror ZeroAddress();\n\nerror DisputePeriodNotPassed();\nerror DisputePeriodPassed();\nerror SenderIncorrect();\nerror StatusIncorrect();\nerror TransactionIdIncorrect();\nerror TransactionRelayed();\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// contracts/interfaces/IFastBridgeV2.sol\n\ninterface IFastBridgeV2 is IFastBridge {\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n struct BridgeTxDetails {\n BridgeStatus status;\n uint40 proofBlockTimestamp;\n uint48 proofBlockNumber;\n address proofRelayer;\n }\n\n struct BridgeRelay {\n uint48 blockNumber;\n uint48 blockTimestamp;\n address relayer;\n }\n\n /// @notice New params introduced in the FastBridgeV2.\n /// We are passing fields from the older BridgeParams struct outside of this struct\n /// for backwards compatibility.\n /// Note: quoteRelayer and quoteExclusivitySeconds are either both zero (indicating no exclusivity)\n /// or both non-zero (indicating exclusivity for the given period).\n /// Note: callValue \u003e 0 can NOT be used with destToken = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE (ETH_ADDRESS)\n /// @param quoteRelayer Relayer that provided the quote for the transaction\n /// @param quoteExclusivitySeconds Period of time the quote relayer is guaranteed exclusivity after user's deposit\n /// @param quoteId Unique quote identifier used for tracking the quote\n /// @param callValue ETH value to send to the recipient (if any)\n /// @param callParams Parameters for the arbitrary call to the destination recipient (if any)\n struct BridgeParamsV2 {\n address quoteRelayer;\n int256 quoteExclusivitySeconds;\n bytes quoteId;\n uint256 callValue;\n bytes callParams;\n }\n\n /// @notice Updated bridge transaction struct to include parameters introduced in FastBridgeV2.\n /// Note: only `exclusivityRelayer` can fill such a transaction until `exclusivityEndTime`.\n /// TODO: consider changing the encoding scheme to prevent spending extra gas on decoding.\n struct BridgeTransactionV2 {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n uint256 callValue; // ETH value to send to the recipient (if any) - replaces V1's sendChainGas flag\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n address exclusivityRelayer;\n uint256 exclusivityEndTime;\n bytes callParams;\n }\n\n event BridgeQuoteDetails(bytes32 indexed transactionId, bytes quoteId);\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability\n /// to provide temporary exclusivity fill rights for the quote relayer.\n /// @param params The parameters required to bridge\n /// @param paramsV2 The parameters for exclusivity fill rights (optional, can be left empty)\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function relay(bytes memory request, address relayer) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param transactionId The transaction id associated with the encoded bridge transaction to prove\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital.\n /// @notice Can only send funds to the relayer address on the proof.\n /// @param request The encoded bridge transaction to claim on origin chain\n function claim(bytes memory request) external;\n /// @notice Checks if a transaction has been relayed\n /// @param transactionId The ID of the transaction to check\n /// @return True if the transaction has been relayed, false otherwise\n function bridgeRelays(bytes32 transactionId) external view returns (bool);\n\n /// @notice Returns the status of a bridge transaction\n /// @param transactionId The ID of the bridge transaction\n /// @return BridgeStatus Status of the bridge transaction\n function bridgeStatuses(bytes32 transactionId) external view returns (BridgeStatus);\n\n /// @notice Returns the timestamp and relayer of a bridge proof\n /// @param transactionId The ID of the bridge transaction\n /// @return timestamp The timestamp of the bridge proof\n /// @return relayer The relayer address of the bridge proof\n function bridgeProofs(bytes32 transactionId) external view returns (uint96 timestamp, address relayer);\n\n /// @notice Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\n /// @param request The bridge request to decode\n function getBridgeTransactionV2(bytes memory request) external view returns (BridgeTransactionV2 memory);\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// contracts/libs/UniversalToken.sol\n\nlibrary UniversalTokenLib {\n using SafeERC20 for IERC20;\n\n address internal constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Transfers tokens to the given account. Reverts if transfer is not successful.\n /// @dev This might trigger fallback, if ETH is transferred to the contract.\n /// Make sure this can not lead to reentrancy attacks.\n function universalTransfer(address token, address to, uint256 value) internal {\n // Don't do anything, if need to send tokens to this address\n if (to == address(this)) return;\n // Don't do anything, if trying to send zero value\n if (value == 0) return;\n if (token == ETH_ADDRESS) {\n /// @dev Note: this can potentially lead to executing code in `to`.\n // solhint-disable-next-line avoid-low-level-calls\n (bool success,) = to.call{value: value}(\"\");\n require(success, \"ETH transfer failed\");\n } else {\n IERC20(token).safeTransfer(to, value);\n }\n }\n\n /// @notice Issues an infinite allowance to the spender, if the current allowance is insufficient\n /// to spend the given amount.\n function universalApproveInfinity(address token, address spender, uint256 amountToSpend) internal {\n // ETH Chad doesn't require your approval\n if (token == ETH_ADDRESS) return;\n // No-op if allowance is already sufficient\n uint256 allowance = IERC20(token).allowance(address(this), spender);\n if (allowance \u003e= amountToSpend) return;\n // Otherwise, reset approval to 0 and set to max allowance\n if (allowance \u003e 0) IERC20(token).safeDecreaseAllowance(spender, allowance);\n IERC20(token).safeIncreaseAllowance(spender, type(uint256).max);\n }\n\n /// @notice Returns the balance of the given token (or native ETH) for the given account.\n function universalBalanceOf(address token, address account) internal view returns (uint256) {\n if (token == ETH_ADDRESS) {\n return account.balance;\n } else {\n return IERC20(token).balanceOf(account);\n }\n }\n\n /// @dev Checks that token is a contract and not ETH_ADDRESS.\n function assertIsContract(address token) internal view {\n // Check that ETH_ADDRESS was not used (in case this is a predeploy on any of the chains)\n if (token == UniversalTokenLib.ETH_ADDRESS) revert TokenNotContract();\n // Check that token is not an EOA\n if (token.code.length == 0) revert TokenNotContract();\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/Admin.sol\n\ncontract Admin is IAdmin, AccessControlEnumerable {\n using UniversalTokenLib for address;\n\n bytes32 public constant RELAYER_ROLE = keccak256(\"RELAYER_ROLE\");\n bytes32 public constant REFUNDER_ROLE = keccak256(\"REFUNDER_ROLE\");\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n uint256 public constant FEE_BPS = 1e6;\n uint256 public constant FEE_RATE_MAX = 0.01e6; // max 1% on origin amount\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Chain gas amount to forward as rebate if requested\n uint256 public chainGasAmount;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n }\n\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n require(newFeeRate \u003c= FEE_RATE_MAX, \"newFeeRate \u003e max\");\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n token.universalTransfer(recipient, feeAmount);\n emit FeesSwept(token, recipient, feeAmount);\n }\n\n function setChainGasAmount(uint256 newChainGasAmount) external onlyRole(GOVERNOR_ROLE) {\n uint256 oldChainGasAmount = chainGasAmount;\n chainGasAmount = newChainGasAmount;\n emit ChainGasAmountUpdated(oldChainGasAmount, newChainGasAmount);\n }\n}\n\n// contracts/FastBridgeV2.sol\n\n/// @notice FastBridgeV2 is a contract for bridging tokens across chains.\ncontract FastBridgeV2 is Admin, IFastBridgeV2, IFastBridgeV2Errors {\n using SafeERC20 for IERC20;\n using UniversalTokenLib for address;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Delay for a transaction after which it could be permisionlessly refunded\n uint256 public constant REFUND_DELAY = 7 days;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n /// @notice Maximum length of accepted callParams\n uint256 public constant MAX_CALL_PARAMS_LENGTH = 2 ** 16 - 1;\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeTxDetails) public bridgeTxDetails;\n /// @notice Relay details on destination chain\n mapping(bytes32 =\u003e BridgeRelay) public bridgeRelayDetails;\n /// @notice Unique bridge nonces tracked per originSender\n mapping(address =\u003e uint256) public senderNonces;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Replaced by senderNonces\n uint256 public immutable nonce = 0;\n /// @notice the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n bridge({\n params: params,\n paramsV2: BridgeParamsV2({\n quoteRelayer: address(0),\n quoteExclusivitySeconds: 0,\n quoteId: bytes(\"\"),\n callValue: 0,\n callParams: bytes(\"\")\n })\n });\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes memory request) external payable {\n relay({request: request, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes memory request, bytes32 destTxHash) external {\n prove({transactionId: keccak256(request), destTxHash: destTxHash, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridgeV2\n function claim(bytes memory request) external {\n claim({request: request, to: address(0)});\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003e DISPUTE_PERIOD) {\n revert DisputePeriodPassed();\n }\n\n // @dev relayer gets slashed effectively if dest relay has gone thru\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n bridgeTxDetails[transactionId].proofRelayer = address(0);\n bridgeTxDetails[transactionId].proofBlockTimestamp = 0;\n bridgeTxDetails[transactionId].proofBlockNumber = 0;\n\n emit BridgeProofDisputed(transactionId, msg.sender);\n }\n\n /// @inheritdoc IFastBridge\n function refund(bytes memory request) external {\n bytes32 transactionId = keccak256(request);\n\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n\n if (bridgeTxDetails[transactionId].status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n\n if (hasRole(REFUNDER_ROLE, msg.sender)) {\n // Refunder can refund if deadline has passed\n if (block.timestamp \u003c= transaction.deadline) revert DeadlineNotExceeded();\n } else {\n // Permissionless refund is allowed after REFUND_DELAY\n if (block.timestamp \u003c= transaction.deadline + REFUND_DELAY) revert DeadlineNotExceeded();\n }\n\n // if all checks passed, set to REFUNDED status\n bridgeTxDetails[transactionId].status = BridgeStatus.REFUNDED;\n\n // transfer origin collateral back to original sender\n address to = transaction.originSender;\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount + transaction.originFeeAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (bridgeTxDetails[transactionId].proofRelayer != relayer) revert SenderIncorrect();\n return _timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n /// @dev This method is added to achieve backwards compatibility with decoding requests into V1 structs:\n /// - `callValue` is partially reported as a zero/non-zero flag\n /// - `callParams` is ignored\n /// In order to process all kinds of requests use getBridgeTransactionV2 instead.\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory) {\n // Try decoding into V2 struct first. This will revert if V1 struct is passed\n try this.getBridgeTransactionV2(request) returns (BridgeTransactionV2 memory txV2) {\n // Note: we entirely ignore the callParams field, as it was not present in V1\n return BridgeTransaction({\n originChainId: txV2.originChainId,\n destChainId: txV2.destChainId,\n originSender: txV2.originSender,\n destRecipient: txV2.destRecipient,\n originToken: txV2.originToken,\n destToken: txV2.destToken,\n originAmount: txV2.originAmount,\n destAmount: txV2.destAmount,\n originFeeAmount: txV2.originFeeAmount,\n sendChainGas: txV2.callValue != 0,\n deadline: txV2.deadline,\n nonce: txV2.nonce\n });\n } catch {\n // Fallback to V1 struct\n return abi.decode(request, (BridgeTransaction));\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) public payable {\n int256 exclusivityEndTime = int256(block.timestamp) + paramsV2.quoteExclusivitySeconds;\n _validateBridgeParams(params, paramsV2, exclusivityEndTime);\n\n // transfer tokens to bridge contract\n /// @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _pullToken(params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n\n // set status to requested\n bytes memory request = abi.encode(\n BridgeTransactionV2({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n callValue: paramsV2.callValue,\n deadline: params.deadline,\n nonce: senderNonces[params.sender]++, // increment nonce on every bridge\n exclusivityRelayer: paramsV2.quoteRelayer,\n // We checked exclusivityEndTime to be in range (0 .. params.deadline] above, so can safely cast\n exclusivityEndTime: uint256(exclusivityEndTime),\n callParams: paramsV2.callParams\n })\n );\n bytes32 transactionId = keccak256(request);\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n\n emit BridgeRequested({\n transactionId: transactionId,\n sender: params.sender,\n request: request,\n destChainId: params.dstChainId,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n sendChainGas: paramsV2.callValue != 0\n });\n emit BridgeQuoteDetails(transactionId, paramsV2.quoteId);\n }\n\n /// @inheritdoc IFastBridgeV2\n function relay(bytes memory request, address relayer) public payable {\n bytes32 transactionId = keccak256(request);\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n _validateRelayParams(transaction, transactionId, relayer);\n // mark bridge transaction as relayed\n bridgeRelayDetails[transactionId] =\n BridgeRelay({blockNumber: uint48(block.number), blockTimestamp: uint48(block.timestamp), relayer: relayer});\n\n // transfer tokens to recipient on destination chain and do an arbitrary call if requested\n address to = transaction.destRecipient;\n address token = transaction.destToken;\n uint256 amount = transaction.destAmount;\n\n // All state changes have been done at this point, can proceed to the external calls.\n // This follows the checks-effects-interactions pattern to mitigate potential reentrancy attacks.\n if (token == UniversalTokenLib.ETH_ADDRESS) {\n // For ETH non-zero callValue is not allowed\n if (transaction.callValue != 0) revert NativeTokenCallValueNotSupported();\n // Check that the correct msg.value was sent\n if (msg.value != amount) revert MsgValueIncorrect();\n } else {\n // For ERC20s, we check that the correct msg.value was sent\n if (msg.value != transaction.callValue) revert MsgValueIncorrect();\n // We need to transfer the tokens from the Relayer to the recipient first before performing an\n // optional post-transfer arbitrary call.\n IERC20(token).safeTransferFrom(msg.sender, to, amount);\n }\n\n if (transaction.callParams.length != 0) {\n // Arbitrary call requested, perform it while supplying full msg.value to the recipient\n // Note: if token has a fee on transfers, the recipient will have received less than `amount`.\n // This is a very niche edge case and should be handled by the recipient contract.\n _checkedCallRecipient({recipient: to, token: token, amount: amount, callParams: transaction.callParams});\n } else if (msg.value != 0) {\n // No arbitrary call requested, but msg.value was sent. This is either a relay with ETH,\n // or a non-zero callValue request with an ERC20. In both cases, transfer the ETH to the recipient.\n Address.sendValue(payable(to), msg.value);\n }\n\n emit BridgeRelayed({\n transactionId: transactionId,\n relayer: relayer,\n to: to,\n originChainId: transaction.originChainId,\n originToken: transaction.originToken,\n destToken: transaction.destToken,\n originAmount: transaction.originAmount,\n destAmount: transaction.destAmount,\n chainGasAmount: transaction.callValue\n });\n }\n\n /// @inheritdoc IFastBridgeV2\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) public onlyRole(RELAYER_ROLE) {\n // update bridge tx status given proof provided\n if (bridgeTxDetails[transactionId].status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n bridgeTxDetails[transactionId].status = BridgeStatus.RELAYER_PROVED;\n bridgeTxDetails[transactionId].proofBlockTimestamp = uint40(block.timestamp);\n bridgeTxDetails[transactionId].proofBlockNumber = uint48(block.number);\n bridgeTxDetails[transactionId].proofRelayer = relayer;\n\n emit BridgeProofProvided(transactionId, relayer, destTxHash);\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes memory request, address to) public {\n bytes32 transactionId = keccak256(request);\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n\n // update bridge tx status if able to claim origin collateral\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n\n // if \"to\" is zero addr, permissionlessly send funds to proven relayer\n if (to == address(0)) {\n to = bridgeTxDetails[transactionId].proofRelayer;\n } else if (bridgeTxDetails[transactionId].proofRelayer != msg.sender) {\n revert SenderIncorrect();\n }\n\n if (_timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003c= DISPUTE_PERIOD) {\n revert DisputePeriodNotPassed();\n }\n\n bridgeTxDetails[transactionId].status = BridgeStatus.RELAYER_CLAIMED;\n\n // update protocol fees if origin fee amount exists\n if (transaction.originFeeAmount \u003e 0) protocolFees[transaction.originToken] += transaction.originFeeAmount;\n\n // transfer origin collateral less fee to specified address\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositClaimed(transactionId, bridgeTxDetails[transactionId].proofRelayer, to, token, amount);\n }\n\n function bridgeStatuses(bytes32 transactionId) public view returns (BridgeStatus status) {\n return bridgeTxDetails[transactionId].status;\n }\n\n function bridgeProofs(bytes32 transactionId) public view returns (uint96 timestamp, address relayer) {\n timestamp = bridgeTxDetails[transactionId].proofBlockTimestamp;\n relayer = bridgeTxDetails[transactionId].proofRelayer;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeRelays(bytes32 transactionId) public view returns (bool) {\n // has this transactionId been relayed?\n return bridgeRelayDetails[transactionId].relayer != address(0);\n }\n\n /// @inheritdoc IFastBridgeV2\n function getBridgeTransactionV2(bytes memory request) public pure returns (BridgeTransactionV2 memory) {\n return abi.decode(request, (BridgeTransactionV2));\n }\n\n /// @notice Pulls a requested token from the user to this contract.\n function _pullToken(address token, uint256 amount) internal returns (uint256 amountPulled) {\n if (token == UniversalTokenLib.ETH_ADDRESS) {\n // For ETH we just need to check that the supplied msg.value is correct\n if (amount != msg.value) revert MsgValueIncorrect();\n amountPulled = msg.value;\n } else {\n token.assertIsContract();\n // Record token balance before transfer\n amountPulled = IERC20(token).balanceOf(address(this));\n // Token needs to be pulled only if msg.value is zero\n // This way user can specify WETH as the origin asset\n IERC20(token).safeTransferFrom(msg.sender, address(this), amount);\n // Use the difference between the recorded balance and the current balance as the amountPulled\n amountPulled = IERC20(token).balanceOf(address(this)) - amountPulled;\n }\n }\n\n /// @notice Calls the Recipient's hook function with the specified callParams and performs\n /// all the necessary checks for the returned value.\n function _checkedCallRecipient(\n address recipient,\n address token,\n uint256 amount,\n bytes memory callParams\n )\n internal\n {\n bytes memory hookData =\n abi.encodeCall(IFastBridgeRecipient.fastBridgeTransferReceived, (token, amount, callParams));\n // This will bubble any revert messages from the hook function\n bytes memory returnData = Address.functionCallWithValue({target: recipient, data: hookData, value: msg.value});\n // Explicit revert if no return data at all\n if (returnData.length == 0) revert RecipientNoReturnValue();\n // Check that exactly a single return value was returned\n if (returnData.length != 32) revert RecipientIncorrectReturnValue();\n // Return value should be abi-encoded hook function selector\n if (bytes32(returnData) != bytes32(IFastBridgeRecipient.fastBridgeTransferReceived.selector)) {\n revert RecipientIncorrectReturnValue();\n }\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint40(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint40).max but\n /// proof.timestamp \u003c type(uint40).max via unchecked statement\n /// @param proofBlockTimestamp The bridge proof block timestamp\n /// @return delta Time delta since proof submitted\n function _timeSince(uint40 proofBlockTimestamp) internal view returns (uint256 delta) {\n unchecked {\n delta = uint40(block.timestamp) - proofBlockTimestamp;\n }\n }\n\n /// @notice Performs all the necessary checks for a bridge to happen.\n /// @dev There's no good way to refactor this function to reduce cyclomatic complexity due to\n /// the number of checks that need to be performed, so we skip the code-complexity rule here.\n // solhint-disable-next-line code-complexity\n function _validateBridgeParams(\n BridgeParams memory params,\n BridgeParamsV2 memory paramsV2,\n int256 exclusivityEndTime\n )\n internal\n view\n {\n // Check V1 (legacy) params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.sender == address(0) || params.to == address(0)) revert ZeroAddress();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n // Check V2 params\n if (paramsV2.callParams.length \u003e MAX_CALL_PARAMS_LENGTH) revert CallParamsLengthAboveMax();\n if (paramsV2.callValue != 0 \u0026\u0026 params.destToken == UniversalTokenLib.ETH_ADDRESS) {\n revert NativeTokenCallValueNotSupported();\n }\n // exclusivityEndTime must be in range (0 .. params.deadline]\n if (exclusivityEndTime \u003c= 0 || exclusivityEndTime \u003e int256(params.deadline)) {\n revert ExclusivityParamsIncorrect();\n }\n }\n\n /// @notice Performs all the necessary checks for a relay to happen.\n function _validateRelayParams(\n BridgeTransactionV2 memory transaction,\n bytes32 transactionId,\n address relayer\n )\n internal\n view\n {\n if (relayer == address(0)) revert ZeroAddress();\n // Check if the transaction has already been relayed\n if (bridgeRelays(transactionId)) revert TransactionRelayed();\n if (transaction.destChainId != uint32(block.chainid)) revert ChainIncorrect();\n // Check the deadline for relay to happen\n if (block.timestamp \u003e transaction.deadline) revert DeadlineExceeded();\n // Check the exclusivity period, if it is still ongoing\n // forgefmt: disable-next-item\n if (\n transaction.exclusivityRelayer != address(0) \u0026\u0026\n transaction.exclusivityRelayer != relayer \u0026\u0026\n block.timestamp \u003c= transaction.exclusivityEndTime\n ) {\n revert ExclusivityPeriodNotPassed();\n }\n }\n}\n","language":"Solidity","languageVersion":"0.8.24","compilerVersion":"0.8.24","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../","srcMap":"","srcMapRuntime":"","abiDefinition":[{"inputs":[],"name":"AccessControlBadConfirmation","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"bytes32","name":"neededRole","type":"bytes32"}],"name":"AccessControlUnauthorizedAccount","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"previousAdminRole","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"newAdminRole","type":"bytes32"}],"name":"RoleAdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleRevoked","type":"event"},{"inputs":[],"name":"DEFAULT_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleAdmin","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"grantRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"hasRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"callerConfirmation","type":"address"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"revokeRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"}],"userDoc":{"kind":"user","methods":{},"version":1},"developerDoc":{"details":"Contract module that allows children to implement role-based access control mechanisms. This is a lightweight version that doesn't allow enumerating role members except through off-chain means by accessing the contract event logs. Some applications may benefit from on-chain enumerability, for those cases see {AccessControlEnumerable}. Roles are referred to by their `bytes32` identifier. These should be exposed in the external API and be unique. The best way to achieve this is by using `public constant` hash digests: ```solidity bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\"); ``` Roles can be used to represent a set of permissions. To restrict access to a function call, use {hasRole}: ```solidity function foo() public { require(hasRole(MY_ROLE, msg.sender)); ... } ``` Roles can be granted and revoked dynamically via the {grantRole} and {revokeRole} functions. Each role has an associated admin role, and only accounts that have a role's admin role can call {grantRole} and {revokeRole}. By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means that only accounts with this role will be able to grant or revoke other roles. More complex role relationships can be created by using {_setRoleAdmin}. WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to grant and revoke this role. Extra precautions should be taken to secure accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules} to enforce additional security measures for this role.","errors":{"AccessControlBadConfirmation()":[{"details":"The caller of a function is not the expected one. NOTE: Don't confuse with {AccessControlUnauthorizedAccount}."}],"AccessControlUnauthorizedAccount(address,bytes32)":[{"details":"The `account` is missing a role."}]},"events":{"RoleAdminChanged(bytes32,bytes32,bytes32)":{"details":"Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole` `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite {RoleAdminChanged} not being emitted signaling this."},"RoleGranted(bytes32,address,address)":{"details":"Emitted when `account` is granted `role`. `sender` is the account that originated the contract call, an admin role bearer except when using {AccessControl-_setupRole}."},"RoleRevoked(bytes32,address,address)":{"details":"Emitted when `account` is revoked `role`. `sender` is the account that originated the contract call: - if using `revokeRole`, it is the admin role bearer - if using `renounceRole`, it is the role bearer (i.e. `account`)"}},"kind":"dev","methods":{"getRoleAdmin(bytes32)":{"details":"Returns the admin role that controls `role`. See {grantRole} and {revokeRole}. To change a role's admin, use {_setRoleAdmin}."},"grantRole(bytes32,address)":{"details":"Grants `role` to `account`. If `account` had not been already granted `role`, emits a {RoleGranted} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleGranted} event."},"hasRole(bytes32,address)":{"details":"Returns `true` if `account` has been granted `role`."},"renounceRole(bytes32,address)":{"details":"Revokes `role` from the calling account. Roles are often managed via {grantRole} and {revokeRole}: this function's purpose is to provide a mechanism for accounts to lose their privileges if they are compromised (such as when a trusted device is misplaced). If the calling account had been revoked `role`, emits a {RoleRevoked} event. Requirements: - the caller must be `callerConfirmation`. May emit a {RoleRevoked} event."},"revokeRole(bytes32,address)":{"details":"Revokes `role` from `account`. If `account` had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleRevoked} event."},"supportsInterface(bytes4)":{"details":"See {IERC165-supportsInterface}."}},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[],\"name\":\"AccessControlBadConfirmation\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"neededRole\",\"type\":\"bytes32\"}],\"name\":\"AccessControlUnauthorizedAccount\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"previousAdminRole\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"newAdminRole\",\"type\":\"bytes32\"}],\"name\":\"RoleAdminChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleGranted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleRevoked\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"DEFAULT_ADMIN_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"}],\"name\":\"getRoleAdmin\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"grantRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"hasRole\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"callerConfirmation\",\"type\":\"address\"}],\"name\":\"renounceRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"revokeRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes4\",\"name\":\"interfaceId\",\"type\":\"bytes4\"}],\"name\":\"supportsInterface\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"}],\"devdoc\":{\"details\":\"Contract module that allows children to implement role-based access control mechanisms. This is a lightweight version that doesn't allow enumerating role members except through off-chain means by accessing the contract event logs. Some applications may benefit from on-chain enumerability, for those cases see {AccessControlEnumerable}. Roles are referred to by their `bytes32` identifier. These should be exposed in the external API and be unique. The best way to achieve this is by using `public constant` hash digests: ```solidity bytes32 public constant MY_ROLE = keccak256(\\\"MY_ROLE\\\"); ``` Roles can be used to represent a set of permissions. To restrict access to a function call, use {hasRole}: ```solidity function foo() public { require(hasRole(MY_ROLE, msg.sender)); ... } ``` Roles can be granted and revoked dynamically via the {grantRole} and {revokeRole} functions. Each role has an associated admin role, and only accounts that have a role's admin role can call {grantRole} and {revokeRole}. By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means that only accounts with this role will be able to grant or revoke other roles. More complex role relationships can be created by using {_setRoleAdmin}. WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to grant and revoke this role. Extra precautions should be taken to secure accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules} to enforce additional security measures for this role.\",\"errors\":{\"AccessControlBadConfirmation()\":[{\"details\":\"The caller of a function is not the expected one. NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\"}],\"AccessControlUnauthorizedAccount(address,bytes32)\":[{\"details\":\"The `account` is missing a role.\"}]},\"events\":{\"RoleAdminChanged(bytes32,bytes32,bytes32)\":{\"details\":\"Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole` `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite {RoleAdminChanged} not being emitted signaling this.\"},\"RoleGranted(bytes32,address,address)\":{\"details\":\"Emitted when `account` is granted `role`. `sender` is the account that originated the contract call, an admin role bearer except when using {AccessControl-_setupRole}.\"},\"RoleRevoked(bytes32,address,address)\":{\"details\":\"Emitted when `account` is revoked `role`. `sender` is the account that originated the contract call: - if using `revokeRole`, it is the admin role bearer - if using `renounceRole`, it is the role bearer (i.e. `account`)\"}},\"kind\":\"dev\",\"methods\":{\"getRoleAdmin(bytes32)\":{\"details\":\"Returns the admin role that controls `role`. See {grantRole} and {revokeRole}. To change a role's admin, use {_setRoleAdmin}.\"},\"grantRole(bytes32,address)\":{\"details\":\"Grants `role` to `account`. If `account` had not been already granted `role`, emits a {RoleGranted} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleGranted} event.\"},\"hasRole(bytes32,address)\":{\"details\":\"Returns `true` if `account` has been granted `role`.\"},\"renounceRole(bytes32,address)\":{\"details\":\"Revokes `role` from the calling account. Roles are often managed via {grantRole} and {revokeRole}: this function's purpose is to provide a mechanism for accounts to lose their privileges if they are compromised (such as when a trusted device is misplaced). If the calling account had been revoked `role`, emits a {RoleRevoked} event. Requirements: - the caller must be `callerConfirmation`. May emit a {RoleRevoked} event.\"},\"revokeRole(bytes32,address)\":{\"details\":\"Revokes `role` from `account`. If `account` had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleRevoked} event.\"},\"supportsInterface(bytes4)\":{\"details\":\"See {IERC165-supportsInterface}.\"}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeV2.sol\":\"AccessControl\"},\"evmVersion\":\"shanghai\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeV2.sol\":{\"keccak256\":\"0x7cd0f885e80e2bdaa638bc32ae7af7d2e248f99ce4b354c217d0f0f7d7302e0a\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://7ccf28df0bd7b4606986585acd8622ed9b4e81379690061bb66088f0a2270af1\",\"dweb:/ipfs/QmTf7HNdHZkK6vmx8ZgewycQEb72oLD9nPwBpsM5reMstQ\"]}},\"version\":1}"},"hashes":{"DEFAULT_ADMIN_ROLE()":"a217fddf","getRoleAdmin(bytes32)":"248a9ca3","grantRole(bytes32,address)":"2f2ff15d","hasRole(bytes32,address)":"91d14854","renounceRole(bytes32,address)":"36568abe","revokeRole(bytes32,address)":"d547741f","supportsInterface(bytes4)":"01ffc9a7"}},"solidity/FastBridgeV2.sol:AccessControlEnumerable":{"code":"0x","runtime-code":"0x","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.24 ^0.8.0 ^0.8.20;\n\n// contracts/interfaces/IAdmin.sol\n\ninterface IAdmin {\n // ============ Events ============\n\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n event ChainGasAmountUpdated(uint256 oldChainGasAmount, uint256 newChainGasAmount);\n\n // ============ Methods ============\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n\n function setChainGasAmount(uint256 newChainGasAmount) external;\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IFastBridgeRecipient.sol\n\ninterface IFastBridgeRecipient {\n function fastBridgeTransferReceived(\n address token,\n uint256 amount,\n bytes memory callParams\n )\n external\n payable\n returns (bytes4);\n}\n\n// contracts/interfaces/IFastBridgeV2Errors.sol\n\ninterface IFastBridgeV2Errors {\n error AmountIncorrect();\n error CallParamsLengthAboveMax();\n error ChainIncorrect();\n error ExclusivityParamsIncorrect();\n error MsgValueIncorrect();\n error NativeTokenCallValueNotSupported();\n error SenderIncorrect();\n error StatusIncorrect();\n error ZeroAddress();\n\n error RecipientIncorrectReturnValue();\n error RecipientNoReturnValue();\n\n error DeadlineExceeded();\n error DeadlineNotExceeded();\n error DeadlineTooShort();\n error DisputePeriodNotPassed();\n error DisputePeriodPassed();\n error ExclusivityPeriodNotPassed();\n\n error TransactionRelayed();\n}\n\n// contracts/libs/Errors.sol\n\nerror DeadlineExceeded();\nerror DeadlineNotExceeded();\nerror DeadlineTooShort();\nerror InsufficientOutputAmount();\n\nerror MsgValueIncorrect();\nerror PoolNotFound();\nerror TokenAddressMismatch();\nerror TokenNotContract();\nerror TokenNotETH();\nerror TokensIdentical();\n\nerror ChainIncorrect();\nerror AmountIncorrect();\nerror ZeroAddress();\n\nerror DisputePeriodNotPassed();\nerror DisputePeriodPassed();\nerror SenderIncorrect();\nerror StatusIncorrect();\nerror TransactionIdIncorrect();\nerror TransactionRelayed();\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// contracts/interfaces/IFastBridgeV2.sol\n\ninterface IFastBridgeV2 is IFastBridge {\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n struct BridgeTxDetails {\n BridgeStatus status;\n uint40 proofBlockTimestamp;\n uint48 proofBlockNumber;\n address proofRelayer;\n }\n\n struct BridgeRelay {\n uint48 blockNumber;\n uint48 blockTimestamp;\n address relayer;\n }\n\n /// @notice New params introduced in the FastBridgeV2.\n /// We are passing fields from the older BridgeParams struct outside of this struct\n /// for backwards compatibility.\n /// Note: quoteRelayer and quoteExclusivitySeconds are either both zero (indicating no exclusivity)\n /// or both non-zero (indicating exclusivity for the given period).\n /// Note: callValue \u003e 0 can NOT be used with destToken = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE (ETH_ADDRESS)\n /// @param quoteRelayer Relayer that provided the quote for the transaction\n /// @param quoteExclusivitySeconds Period of time the quote relayer is guaranteed exclusivity after user's deposit\n /// @param quoteId Unique quote identifier used for tracking the quote\n /// @param callValue ETH value to send to the recipient (if any)\n /// @param callParams Parameters for the arbitrary call to the destination recipient (if any)\n struct BridgeParamsV2 {\n address quoteRelayer;\n int256 quoteExclusivitySeconds;\n bytes quoteId;\n uint256 callValue;\n bytes callParams;\n }\n\n /// @notice Updated bridge transaction struct to include parameters introduced in FastBridgeV2.\n /// Note: only `exclusivityRelayer` can fill such a transaction until `exclusivityEndTime`.\n /// TODO: consider changing the encoding scheme to prevent spending extra gas on decoding.\n struct BridgeTransactionV2 {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n uint256 callValue; // ETH value to send to the recipient (if any) - replaces V1's sendChainGas flag\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n address exclusivityRelayer;\n uint256 exclusivityEndTime;\n bytes callParams;\n }\n\n event BridgeQuoteDetails(bytes32 indexed transactionId, bytes quoteId);\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability\n /// to provide temporary exclusivity fill rights for the quote relayer.\n /// @param params The parameters required to bridge\n /// @param paramsV2 The parameters for exclusivity fill rights (optional, can be left empty)\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function relay(bytes memory request, address relayer) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param transactionId The transaction id associated with the encoded bridge transaction to prove\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital.\n /// @notice Can only send funds to the relayer address on the proof.\n /// @param request The encoded bridge transaction to claim on origin chain\n function claim(bytes memory request) external;\n /// @notice Checks if a transaction has been relayed\n /// @param transactionId The ID of the transaction to check\n /// @return True if the transaction has been relayed, false otherwise\n function bridgeRelays(bytes32 transactionId) external view returns (bool);\n\n /// @notice Returns the status of a bridge transaction\n /// @param transactionId The ID of the bridge transaction\n /// @return BridgeStatus Status of the bridge transaction\n function bridgeStatuses(bytes32 transactionId) external view returns (BridgeStatus);\n\n /// @notice Returns the timestamp and relayer of a bridge proof\n /// @param transactionId The ID of the bridge transaction\n /// @return timestamp The timestamp of the bridge proof\n /// @return relayer The relayer address of the bridge proof\n function bridgeProofs(bytes32 transactionId) external view returns (uint96 timestamp, address relayer);\n\n /// @notice Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\n /// @param request The bridge request to decode\n function getBridgeTransactionV2(bytes memory request) external view returns (BridgeTransactionV2 memory);\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// contracts/libs/UniversalToken.sol\n\nlibrary UniversalTokenLib {\n using SafeERC20 for IERC20;\n\n address internal constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Transfers tokens to the given account. Reverts if transfer is not successful.\n /// @dev This might trigger fallback, if ETH is transferred to the contract.\n /// Make sure this can not lead to reentrancy attacks.\n function universalTransfer(address token, address to, uint256 value) internal {\n // Don't do anything, if need to send tokens to this address\n if (to == address(this)) return;\n // Don't do anything, if trying to send zero value\n if (value == 0) return;\n if (token == ETH_ADDRESS) {\n /// @dev Note: this can potentially lead to executing code in `to`.\n // solhint-disable-next-line avoid-low-level-calls\n (bool success,) = to.call{value: value}(\"\");\n require(success, \"ETH transfer failed\");\n } else {\n IERC20(token).safeTransfer(to, value);\n }\n }\n\n /// @notice Issues an infinite allowance to the spender, if the current allowance is insufficient\n /// to spend the given amount.\n function universalApproveInfinity(address token, address spender, uint256 amountToSpend) internal {\n // ETH Chad doesn't require your approval\n if (token == ETH_ADDRESS) return;\n // No-op if allowance is already sufficient\n uint256 allowance = IERC20(token).allowance(address(this), spender);\n if (allowance \u003e= amountToSpend) return;\n // Otherwise, reset approval to 0 and set to max allowance\n if (allowance \u003e 0) IERC20(token).safeDecreaseAllowance(spender, allowance);\n IERC20(token).safeIncreaseAllowance(spender, type(uint256).max);\n }\n\n /// @notice Returns the balance of the given token (or native ETH) for the given account.\n function universalBalanceOf(address token, address account) internal view returns (uint256) {\n if (token == ETH_ADDRESS) {\n return account.balance;\n } else {\n return IERC20(token).balanceOf(account);\n }\n }\n\n /// @dev Checks that token is a contract and not ETH_ADDRESS.\n function assertIsContract(address token) internal view {\n // Check that ETH_ADDRESS was not used (in case this is a predeploy on any of the chains)\n if (token == UniversalTokenLib.ETH_ADDRESS) revert TokenNotContract();\n // Check that token is not an EOA\n if (token.code.length == 0) revert TokenNotContract();\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/Admin.sol\n\ncontract Admin is IAdmin, AccessControlEnumerable {\n using UniversalTokenLib for address;\n\n bytes32 public constant RELAYER_ROLE = keccak256(\"RELAYER_ROLE\");\n bytes32 public constant REFUNDER_ROLE = keccak256(\"REFUNDER_ROLE\");\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n uint256 public constant FEE_BPS = 1e6;\n uint256 public constant FEE_RATE_MAX = 0.01e6; // max 1% on origin amount\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Chain gas amount to forward as rebate if requested\n uint256 public chainGasAmount;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n }\n\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n require(newFeeRate \u003c= FEE_RATE_MAX, \"newFeeRate \u003e max\");\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n token.universalTransfer(recipient, feeAmount);\n emit FeesSwept(token, recipient, feeAmount);\n }\n\n function setChainGasAmount(uint256 newChainGasAmount) external onlyRole(GOVERNOR_ROLE) {\n uint256 oldChainGasAmount = chainGasAmount;\n chainGasAmount = newChainGasAmount;\n emit ChainGasAmountUpdated(oldChainGasAmount, newChainGasAmount);\n }\n}\n\n// contracts/FastBridgeV2.sol\n\n/// @notice FastBridgeV2 is a contract for bridging tokens across chains.\ncontract FastBridgeV2 is Admin, IFastBridgeV2, IFastBridgeV2Errors {\n using SafeERC20 for IERC20;\n using UniversalTokenLib for address;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Delay for a transaction after which it could be permisionlessly refunded\n uint256 public constant REFUND_DELAY = 7 days;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n /// @notice Maximum length of accepted callParams\n uint256 public constant MAX_CALL_PARAMS_LENGTH = 2 ** 16 - 1;\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeTxDetails) public bridgeTxDetails;\n /// @notice Relay details on destination chain\n mapping(bytes32 =\u003e BridgeRelay) public bridgeRelayDetails;\n /// @notice Unique bridge nonces tracked per originSender\n mapping(address =\u003e uint256) public senderNonces;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Replaced by senderNonces\n uint256 public immutable nonce = 0;\n /// @notice the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n bridge({\n params: params,\n paramsV2: BridgeParamsV2({\n quoteRelayer: address(0),\n quoteExclusivitySeconds: 0,\n quoteId: bytes(\"\"),\n callValue: 0,\n callParams: bytes(\"\")\n })\n });\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes memory request) external payable {\n relay({request: request, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes memory request, bytes32 destTxHash) external {\n prove({transactionId: keccak256(request), destTxHash: destTxHash, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridgeV2\n function claim(bytes memory request) external {\n claim({request: request, to: address(0)});\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003e DISPUTE_PERIOD) {\n revert DisputePeriodPassed();\n }\n\n // @dev relayer gets slashed effectively if dest relay has gone thru\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n bridgeTxDetails[transactionId].proofRelayer = address(0);\n bridgeTxDetails[transactionId].proofBlockTimestamp = 0;\n bridgeTxDetails[transactionId].proofBlockNumber = 0;\n\n emit BridgeProofDisputed(transactionId, msg.sender);\n }\n\n /// @inheritdoc IFastBridge\n function refund(bytes memory request) external {\n bytes32 transactionId = keccak256(request);\n\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n\n if (bridgeTxDetails[transactionId].status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n\n if (hasRole(REFUNDER_ROLE, msg.sender)) {\n // Refunder can refund if deadline has passed\n if (block.timestamp \u003c= transaction.deadline) revert DeadlineNotExceeded();\n } else {\n // Permissionless refund is allowed after REFUND_DELAY\n if (block.timestamp \u003c= transaction.deadline + REFUND_DELAY) revert DeadlineNotExceeded();\n }\n\n // if all checks passed, set to REFUNDED status\n bridgeTxDetails[transactionId].status = BridgeStatus.REFUNDED;\n\n // transfer origin collateral back to original sender\n address to = transaction.originSender;\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount + transaction.originFeeAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (bridgeTxDetails[transactionId].proofRelayer != relayer) revert SenderIncorrect();\n return _timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n /// @dev This method is added to achieve backwards compatibility with decoding requests into V1 structs:\n /// - `callValue` is partially reported as a zero/non-zero flag\n /// - `callParams` is ignored\n /// In order to process all kinds of requests use getBridgeTransactionV2 instead.\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory) {\n // Try decoding into V2 struct first. This will revert if V1 struct is passed\n try this.getBridgeTransactionV2(request) returns (BridgeTransactionV2 memory txV2) {\n // Note: we entirely ignore the callParams field, as it was not present in V1\n return BridgeTransaction({\n originChainId: txV2.originChainId,\n destChainId: txV2.destChainId,\n originSender: txV2.originSender,\n destRecipient: txV2.destRecipient,\n originToken: txV2.originToken,\n destToken: txV2.destToken,\n originAmount: txV2.originAmount,\n destAmount: txV2.destAmount,\n originFeeAmount: txV2.originFeeAmount,\n sendChainGas: txV2.callValue != 0,\n deadline: txV2.deadline,\n nonce: txV2.nonce\n });\n } catch {\n // Fallback to V1 struct\n return abi.decode(request, (BridgeTransaction));\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) public payable {\n int256 exclusivityEndTime = int256(block.timestamp) + paramsV2.quoteExclusivitySeconds;\n _validateBridgeParams(params, paramsV2, exclusivityEndTime);\n\n // transfer tokens to bridge contract\n /// @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _pullToken(params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n\n // set status to requested\n bytes memory request = abi.encode(\n BridgeTransactionV2({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n callValue: paramsV2.callValue,\n deadline: params.deadline,\n nonce: senderNonces[params.sender]++, // increment nonce on every bridge\n exclusivityRelayer: paramsV2.quoteRelayer,\n // We checked exclusivityEndTime to be in range (0 .. params.deadline] above, so can safely cast\n exclusivityEndTime: uint256(exclusivityEndTime),\n callParams: paramsV2.callParams\n })\n );\n bytes32 transactionId = keccak256(request);\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n\n emit BridgeRequested({\n transactionId: transactionId,\n sender: params.sender,\n request: request,\n destChainId: params.dstChainId,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n sendChainGas: paramsV2.callValue != 0\n });\n emit BridgeQuoteDetails(transactionId, paramsV2.quoteId);\n }\n\n /// @inheritdoc IFastBridgeV2\n function relay(bytes memory request, address relayer) public payable {\n bytes32 transactionId = keccak256(request);\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n _validateRelayParams(transaction, transactionId, relayer);\n // mark bridge transaction as relayed\n bridgeRelayDetails[transactionId] =\n BridgeRelay({blockNumber: uint48(block.number), blockTimestamp: uint48(block.timestamp), relayer: relayer});\n\n // transfer tokens to recipient on destination chain and do an arbitrary call if requested\n address to = transaction.destRecipient;\n address token = transaction.destToken;\n uint256 amount = transaction.destAmount;\n\n // All state changes have been done at this point, can proceed to the external calls.\n // This follows the checks-effects-interactions pattern to mitigate potential reentrancy attacks.\n if (token == UniversalTokenLib.ETH_ADDRESS) {\n // For ETH non-zero callValue is not allowed\n if (transaction.callValue != 0) revert NativeTokenCallValueNotSupported();\n // Check that the correct msg.value was sent\n if (msg.value != amount) revert MsgValueIncorrect();\n } else {\n // For ERC20s, we check that the correct msg.value was sent\n if (msg.value != transaction.callValue) revert MsgValueIncorrect();\n // We need to transfer the tokens from the Relayer to the recipient first before performing an\n // optional post-transfer arbitrary call.\n IERC20(token).safeTransferFrom(msg.sender, to, amount);\n }\n\n if (transaction.callParams.length != 0) {\n // Arbitrary call requested, perform it while supplying full msg.value to the recipient\n // Note: if token has a fee on transfers, the recipient will have received less than `amount`.\n // This is a very niche edge case and should be handled by the recipient contract.\n _checkedCallRecipient({recipient: to, token: token, amount: amount, callParams: transaction.callParams});\n } else if (msg.value != 0) {\n // No arbitrary call requested, but msg.value was sent. This is either a relay with ETH,\n // or a non-zero callValue request with an ERC20. In both cases, transfer the ETH to the recipient.\n Address.sendValue(payable(to), msg.value);\n }\n\n emit BridgeRelayed({\n transactionId: transactionId,\n relayer: relayer,\n to: to,\n originChainId: transaction.originChainId,\n originToken: transaction.originToken,\n destToken: transaction.destToken,\n originAmount: transaction.originAmount,\n destAmount: transaction.destAmount,\n chainGasAmount: transaction.callValue\n });\n }\n\n /// @inheritdoc IFastBridgeV2\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) public onlyRole(RELAYER_ROLE) {\n // update bridge tx status given proof provided\n if (bridgeTxDetails[transactionId].status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n bridgeTxDetails[transactionId].status = BridgeStatus.RELAYER_PROVED;\n bridgeTxDetails[transactionId].proofBlockTimestamp = uint40(block.timestamp);\n bridgeTxDetails[transactionId].proofBlockNumber = uint48(block.number);\n bridgeTxDetails[transactionId].proofRelayer = relayer;\n\n emit BridgeProofProvided(transactionId, relayer, destTxHash);\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes memory request, address to) public {\n bytes32 transactionId = keccak256(request);\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n\n // update bridge tx status if able to claim origin collateral\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n\n // if \"to\" is zero addr, permissionlessly send funds to proven relayer\n if (to == address(0)) {\n to = bridgeTxDetails[transactionId].proofRelayer;\n } else if (bridgeTxDetails[transactionId].proofRelayer != msg.sender) {\n revert SenderIncorrect();\n }\n\n if (_timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003c= DISPUTE_PERIOD) {\n revert DisputePeriodNotPassed();\n }\n\n bridgeTxDetails[transactionId].status = BridgeStatus.RELAYER_CLAIMED;\n\n // update protocol fees if origin fee amount exists\n if (transaction.originFeeAmount \u003e 0) protocolFees[transaction.originToken] += transaction.originFeeAmount;\n\n // transfer origin collateral less fee to specified address\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositClaimed(transactionId, bridgeTxDetails[transactionId].proofRelayer, to, token, amount);\n }\n\n function bridgeStatuses(bytes32 transactionId) public view returns (BridgeStatus status) {\n return bridgeTxDetails[transactionId].status;\n }\n\n function bridgeProofs(bytes32 transactionId) public view returns (uint96 timestamp, address relayer) {\n timestamp = bridgeTxDetails[transactionId].proofBlockTimestamp;\n relayer = bridgeTxDetails[transactionId].proofRelayer;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeRelays(bytes32 transactionId) public view returns (bool) {\n // has this transactionId been relayed?\n return bridgeRelayDetails[transactionId].relayer != address(0);\n }\n\n /// @inheritdoc IFastBridgeV2\n function getBridgeTransactionV2(bytes memory request) public pure returns (BridgeTransactionV2 memory) {\n return abi.decode(request, (BridgeTransactionV2));\n }\n\n /// @notice Pulls a requested token from the user to this contract.\n function _pullToken(address token, uint256 amount) internal returns (uint256 amountPulled) {\n if (token == UniversalTokenLib.ETH_ADDRESS) {\n // For ETH we just need to check that the supplied msg.value is correct\n if (amount != msg.value) revert MsgValueIncorrect();\n amountPulled = msg.value;\n } else {\n token.assertIsContract();\n // Record token balance before transfer\n amountPulled = IERC20(token).balanceOf(address(this));\n // Token needs to be pulled only if msg.value is zero\n // This way user can specify WETH as the origin asset\n IERC20(token).safeTransferFrom(msg.sender, address(this), amount);\n // Use the difference between the recorded balance and the current balance as the amountPulled\n amountPulled = IERC20(token).balanceOf(address(this)) - amountPulled;\n }\n }\n\n /// @notice Calls the Recipient's hook function with the specified callParams and performs\n /// all the necessary checks for the returned value.\n function _checkedCallRecipient(\n address recipient,\n address token,\n uint256 amount,\n bytes memory callParams\n )\n internal\n {\n bytes memory hookData =\n abi.encodeCall(IFastBridgeRecipient.fastBridgeTransferReceived, (token, amount, callParams));\n // This will bubble any revert messages from the hook function\n bytes memory returnData = Address.functionCallWithValue({target: recipient, data: hookData, value: msg.value});\n // Explicit revert if no return data at all\n if (returnData.length == 0) revert RecipientNoReturnValue();\n // Check that exactly a single return value was returned\n if (returnData.length != 32) revert RecipientIncorrectReturnValue();\n // Return value should be abi-encoded hook function selector\n if (bytes32(returnData) != bytes32(IFastBridgeRecipient.fastBridgeTransferReceived.selector)) {\n revert RecipientIncorrectReturnValue();\n }\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint40(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint40).max but\n /// proof.timestamp \u003c type(uint40).max via unchecked statement\n /// @param proofBlockTimestamp The bridge proof block timestamp\n /// @return delta Time delta since proof submitted\n function _timeSince(uint40 proofBlockTimestamp) internal view returns (uint256 delta) {\n unchecked {\n delta = uint40(block.timestamp) - proofBlockTimestamp;\n }\n }\n\n /// @notice Performs all the necessary checks for a bridge to happen.\n /// @dev There's no good way to refactor this function to reduce cyclomatic complexity due to\n /// the number of checks that need to be performed, so we skip the code-complexity rule here.\n // solhint-disable-next-line code-complexity\n function _validateBridgeParams(\n BridgeParams memory params,\n BridgeParamsV2 memory paramsV2,\n int256 exclusivityEndTime\n )\n internal\n view\n {\n // Check V1 (legacy) params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.sender == address(0) || params.to == address(0)) revert ZeroAddress();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n // Check V2 params\n if (paramsV2.callParams.length \u003e MAX_CALL_PARAMS_LENGTH) revert CallParamsLengthAboveMax();\n if (paramsV2.callValue != 0 \u0026\u0026 params.destToken == UniversalTokenLib.ETH_ADDRESS) {\n revert NativeTokenCallValueNotSupported();\n }\n // exclusivityEndTime must be in range (0 .. params.deadline]\n if (exclusivityEndTime \u003c= 0 || exclusivityEndTime \u003e int256(params.deadline)) {\n revert ExclusivityParamsIncorrect();\n }\n }\n\n /// @notice Performs all the necessary checks for a relay to happen.\n function _validateRelayParams(\n BridgeTransactionV2 memory transaction,\n bytes32 transactionId,\n address relayer\n )\n internal\n view\n {\n if (relayer == address(0)) revert ZeroAddress();\n // Check if the transaction has already been relayed\n if (bridgeRelays(transactionId)) revert TransactionRelayed();\n if (transaction.destChainId != uint32(block.chainid)) revert ChainIncorrect();\n // Check the deadline for relay to happen\n if (block.timestamp \u003e transaction.deadline) revert DeadlineExceeded();\n // Check the exclusivity period, if it is still ongoing\n // forgefmt: disable-next-item\n if (\n transaction.exclusivityRelayer != address(0) \u0026\u0026\n transaction.exclusivityRelayer != relayer \u0026\u0026\n block.timestamp \u003c= transaction.exclusivityEndTime\n ) {\n revert ExclusivityPeriodNotPassed();\n }\n }\n}\n","language":"Solidity","languageVersion":"0.8.24","compilerVersion":"0.8.24","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../","srcMap":"","srcMapRuntime":"","abiDefinition":[{"inputs":[],"name":"AccessControlBadConfirmation","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"bytes32","name":"neededRole","type":"bytes32"}],"name":"AccessControlUnauthorizedAccount","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"previousAdminRole","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"newAdminRole","type":"bytes32"}],"name":"RoleAdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleRevoked","type":"event"},{"inputs":[],"name":"DEFAULT_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleAdmin","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"uint256","name":"index","type":"uint256"}],"name":"getRoleMember","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleMemberCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"grantRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"hasRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"callerConfirmation","type":"address"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"revokeRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"}],"userDoc":{"kind":"user","methods":{},"version":1},"developerDoc":{"details":"Extension of {AccessControl} that allows enumerating the members of each role.","errors":{"AccessControlBadConfirmation()":[{"details":"The caller of a function is not the expected one. NOTE: Don't confuse with {AccessControlUnauthorizedAccount}."}],"AccessControlUnauthorizedAccount(address,bytes32)":[{"details":"The `account` is missing a role."}]},"events":{"RoleAdminChanged(bytes32,bytes32,bytes32)":{"details":"Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole` `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite {RoleAdminChanged} not being emitted signaling this."},"RoleGranted(bytes32,address,address)":{"details":"Emitted when `account` is granted `role`. `sender` is the account that originated the contract call, an admin role bearer except when using {AccessControl-_setupRole}."},"RoleRevoked(bytes32,address,address)":{"details":"Emitted when `account` is revoked `role`. `sender` is the account that originated the contract call: - if using `revokeRole`, it is the admin role bearer - if using `renounceRole`, it is the role bearer (i.e. `account`)"}},"kind":"dev","methods":{"getRoleAdmin(bytes32)":{"details":"Returns the admin role that controls `role`. See {grantRole} and {revokeRole}. To change a role's admin, use {_setRoleAdmin}."},"getRoleMember(bytes32,uint256)":{"details":"Returns one of the accounts that have `role`. `index` must be a value between 0 and {getRoleMemberCount}, non-inclusive. Role bearers are not sorted in any particular way, and their ordering may change at any point. WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure you perform all queries on the same block. See the following https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post] for more information."},"getRoleMemberCount(bytes32)":{"details":"Returns the number of accounts that have `role`. Can be used together with {getRoleMember} to enumerate all bearers of a role."},"grantRole(bytes32,address)":{"details":"Grants `role` to `account`. If `account` had not been already granted `role`, emits a {RoleGranted} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleGranted} event."},"hasRole(bytes32,address)":{"details":"Returns `true` if `account` has been granted `role`."},"renounceRole(bytes32,address)":{"details":"Revokes `role` from the calling account. Roles are often managed via {grantRole} and {revokeRole}: this function's purpose is to provide a mechanism for accounts to lose their privileges if they are compromised (such as when a trusted device is misplaced). If the calling account had been revoked `role`, emits a {RoleRevoked} event. Requirements: - the caller must be `callerConfirmation`. May emit a {RoleRevoked} event."},"revokeRole(bytes32,address)":{"details":"Revokes `role` from `account`. If `account` had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleRevoked} event."},"supportsInterface(bytes4)":{"details":"See {IERC165-supportsInterface}."}},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[],\"name\":\"AccessControlBadConfirmation\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"neededRole\",\"type\":\"bytes32\"}],\"name\":\"AccessControlUnauthorizedAccount\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"previousAdminRole\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"newAdminRole\",\"type\":\"bytes32\"}],\"name\":\"RoleAdminChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleGranted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleRevoked\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"DEFAULT_ADMIN_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"}],\"name\":\"getRoleAdmin\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"index\",\"type\":\"uint256\"}],\"name\":\"getRoleMember\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"}],\"name\":\"getRoleMemberCount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"grantRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"hasRole\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"callerConfirmation\",\"type\":\"address\"}],\"name\":\"renounceRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"revokeRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes4\",\"name\":\"interfaceId\",\"type\":\"bytes4\"}],\"name\":\"supportsInterface\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"}],\"devdoc\":{\"details\":\"Extension of {AccessControl} that allows enumerating the members of each role.\",\"errors\":{\"AccessControlBadConfirmation()\":[{\"details\":\"The caller of a function is not the expected one. NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\"}],\"AccessControlUnauthorizedAccount(address,bytes32)\":[{\"details\":\"The `account` is missing a role.\"}]},\"events\":{\"RoleAdminChanged(bytes32,bytes32,bytes32)\":{\"details\":\"Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole` `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite {RoleAdminChanged} not being emitted signaling this.\"},\"RoleGranted(bytes32,address,address)\":{\"details\":\"Emitted when `account` is granted `role`. `sender` is the account that originated the contract call, an admin role bearer except when using {AccessControl-_setupRole}.\"},\"RoleRevoked(bytes32,address,address)\":{\"details\":\"Emitted when `account` is revoked `role`. `sender` is the account that originated the contract call: - if using `revokeRole`, it is the admin role bearer - if using `renounceRole`, it is the role bearer (i.e. `account`)\"}},\"kind\":\"dev\",\"methods\":{\"getRoleAdmin(bytes32)\":{\"details\":\"Returns the admin role that controls `role`. See {grantRole} and {revokeRole}. To change a role's admin, use {_setRoleAdmin}.\"},\"getRoleMember(bytes32,uint256)\":{\"details\":\"Returns one of the accounts that have `role`. `index` must be a value between 0 and {getRoleMemberCount}, non-inclusive. Role bearers are not sorted in any particular way, and their ordering may change at any point. WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure you perform all queries on the same block. See the following https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post] for more information.\"},\"getRoleMemberCount(bytes32)\":{\"details\":\"Returns the number of accounts that have `role`. Can be used together with {getRoleMember} to enumerate all bearers of a role.\"},\"grantRole(bytes32,address)\":{\"details\":\"Grants `role` to `account`. If `account` had not been already granted `role`, emits a {RoleGranted} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleGranted} event.\"},\"hasRole(bytes32,address)\":{\"details\":\"Returns `true` if `account` has been granted `role`.\"},\"renounceRole(bytes32,address)\":{\"details\":\"Revokes `role` from the calling account. Roles are often managed via {grantRole} and {revokeRole}: this function's purpose is to provide a mechanism for accounts to lose their privileges if they are compromised (such as when a trusted device is misplaced). If the calling account had been revoked `role`, emits a {RoleRevoked} event. Requirements: - the caller must be `callerConfirmation`. May emit a {RoleRevoked} event.\"},\"revokeRole(bytes32,address)\":{\"details\":\"Revokes `role` from `account`. If `account` had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleRevoked} event.\"},\"supportsInterface(bytes4)\":{\"details\":\"See {IERC165-supportsInterface}.\"}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeV2.sol\":\"AccessControlEnumerable\"},\"evmVersion\":\"shanghai\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeV2.sol\":{\"keccak256\":\"0x7cd0f885e80e2bdaa638bc32ae7af7d2e248f99ce4b354c217d0f0f7d7302e0a\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://7ccf28df0bd7b4606986585acd8622ed9b4e81379690061bb66088f0a2270af1\",\"dweb:/ipfs/QmTf7HNdHZkK6vmx8ZgewycQEb72oLD9nPwBpsM5reMstQ\"]}},\"version\":1}"},"hashes":{"DEFAULT_ADMIN_ROLE()":"a217fddf","getRoleAdmin(bytes32)":"248a9ca3","getRoleMember(bytes32,uint256)":"9010d07c","getRoleMemberCount(bytes32)":"ca15c873","grantRole(bytes32,address)":"2f2ff15d","hasRole(bytes32,address)":"91d14854","renounceRole(bytes32,address)":"36568abe","revokeRole(bytes32,address)":"d547741f","supportsInterface(bytes4)":"01ffc9a7"}},"solidity/FastBridgeV2.sol:Address":{"code":"0x60556032600b8282823980515f1a607314602657634e487b7160e01b5f525f60045260245ffd5b305f52607381538281f3fe730000000000000000000000000000000000000000301460806040525f80fdfea264697066735822122066ad3e1b6dabcf400c86562013c52581c196e1c9e2e058e0440d32fcd4e26ad264736f6c63430008180033","runtime-code":"0x730000000000000000000000000000000000000000301460806040525f80fdfea264697066735822122066ad3e1b6dabcf400c86562013c52581c196e1c9e2e058e0440d32fcd4e26ad264736f6c63430008180033","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.24 ^0.8.0 ^0.8.20;\n\n// contracts/interfaces/IAdmin.sol\n\ninterface IAdmin {\n // ============ Events ============\n\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n event ChainGasAmountUpdated(uint256 oldChainGasAmount, uint256 newChainGasAmount);\n\n // ============ Methods ============\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n\n function setChainGasAmount(uint256 newChainGasAmount) external;\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IFastBridgeRecipient.sol\n\ninterface IFastBridgeRecipient {\n function fastBridgeTransferReceived(\n address token,\n uint256 amount,\n bytes memory callParams\n )\n external\n payable\n returns (bytes4);\n}\n\n// contracts/interfaces/IFastBridgeV2Errors.sol\n\ninterface IFastBridgeV2Errors {\n error AmountIncorrect();\n error CallParamsLengthAboveMax();\n error ChainIncorrect();\n error ExclusivityParamsIncorrect();\n error MsgValueIncorrect();\n error NativeTokenCallValueNotSupported();\n error SenderIncorrect();\n error StatusIncorrect();\n error ZeroAddress();\n\n error RecipientIncorrectReturnValue();\n error RecipientNoReturnValue();\n\n error DeadlineExceeded();\n error DeadlineNotExceeded();\n error DeadlineTooShort();\n error DisputePeriodNotPassed();\n error DisputePeriodPassed();\n error ExclusivityPeriodNotPassed();\n\n error TransactionRelayed();\n}\n\n// contracts/libs/Errors.sol\n\nerror DeadlineExceeded();\nerror DeadlineNotExceeded();\nerror DeadlineTooShort();\nerror InsufficientOutputAmount();\n\nerror MsgValueIncorrect();\nerror PoolNotFound();\nerror TokenAddressMismatch();\nerror TokenNotContract();\nerror TokenNotETH();\nerror TokensIdentical();\n\nerror ChainIncorrect();\nerror AmountIncorrect();\nerror ZeroAddress();\n\nerror DisputePeriodNotPassed();\nerror DisputePeriodPassed();\nerror SenderIncorrect();\nerror StatusIncorrect();\nerror TransactionIdIncorrect();\nerror TransactionRelayed();\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// contracts/interfaces/IFastBridgeV2.sol\n\ninterface IFastBridgeV2 is IFastBridge {\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n struct BridgeTxDetails {\n BridgeStatus status;\n uint40 proofBlockTimestamp;\n uint48 proofBlockNumber;\n address proofRelayer;\n }\n\n struct BridgeRelay {\n uint48 blockNumber;\n uint48 blockTimestamp;\n address relayer;\n }\n\n /// @notice New params introduced in the FastBridgeV2.\n /// We are passing fields from the older BridgeParams struct outside of this struct\n /// for backwards compatibility.\n /// Note: quoteRelayer and quoteExclusivitySeconds are either both zero (indicating no exclusivity)\n /// or both non-zero (indicating exclusivity for the given period).\n /// Note: callValue \u003e 0 can NOT be used with destToken = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE (ETH_ADDRESS)\n /// @param quoteRelayer Relayer that provided the quote for the transaction\n /// @param quoteExclusivitySeconds Period of time the quote relayer is guaranteed exclusivity after user's deposit\n /// @param quoteId Unique quote identifier used for tracking the quote\n /// @param callValue ETH value to send to the recipient (if any)\n /// @param callParams Parameters for the arbitrary call to the destination recipient (if any)\n struct BridgeParamsV2 {\n address quoteRelayer;\n int256 quoteExclusivitySeconds;\n bytes quoteId;\n uint256 callValue;\n bytes callParams;\n }\n\n /// @notice Updated bridge transaction struct to include parameters introduced in FastBridgeV2.\n /// Note: only `exclusivityRelayer` can fill such a transaction until `exclusivityEndTime`.\n /// TODO: consider changing the encoding scheme to prevent spending extra gas on decoding.\n struct BridgeTransactionV2 {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n uint256 callValue; // ETH value to send to the recipient (if any) - replaces V1's sendChainGas flag\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n address exclusivityRelayer;\n uint256 exclusivityEndTime;\n bytes callParams;\n }\n\n event BridgeQuoteDetails(bytes32 indexed transactionId, bytes quoteId);\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability\n /// to provide temporary exclusivity fill rights for the quote relayer.\n /// @param params The parameters required to bridge\n /// @param paramsV2 The parameters for exclusivity fill rights (optional, can be left empty)\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function relay(bytes memory request, address relayer) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param transactionId The transaction id associated with the encoded bridge transaction to prove\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital.\n /// @notice Can only send funds to the relayer address on the proof.\n /// @param request The encoded bridge transaction to claim on origin chain\n function claim(bytes memory request) external;\n /// @notice Checks if a transaction has been relayed\n /// @param transactionId The ID of the transaction to check\n /// @return True if the transaction has been relayed, false otherwise\n function bridgeRelays(bytes32 transactionId) external view returns (bool);\n\n /// @notice Returns the status of a bridge transaction\n /// @param transactionId The ID of the bridge transaction\n /// @return BridgeStatus Status of the bridge transaction\n function bridgeStatuses(bytes32 transactionId) external view returns (BridgeStatus);\n\n /// @notice Returns the timestamp and relayer of a bridge proof\n /// @param transactionId The ID of the bridge transaction\n /// @return timestamp The timestamp of the bridge proof\n /// @return relayer The relayer address of the bridge proof\n function bridgeProofs(bytes32 transactionId) external view returns (uint96 timestamp, address relayer);\n\n /// @notice Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\n /// @param request The bridge request to decode\n function getBridgeTransactionV2(bytes memory request) external view returns (BridgeTransactionV2 memory);\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// contracts/libs/UniversalToken.sol\n\nlibrary UniversalTokenLib {\n using SafeERC20 for IERC20;\n\n address internal constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Transfers tokens to the given account. Reverts if transfer is not successful.\n /// @dev This might trigger fallback, if ETH is transferred to the contract.\n /// Make sure this can not lead to reentrancy attacks.\n function universalTransfer(address token, address to, uint256 value) internal {\n // Don't do anything, if need to send tokens to this address\n if (to == address(this)) return;\n // Don't do anything, if trying to send zero value\n if (value == 0) return;\n if (token == ETH_ADDRESS) {\n /// @dev Note: this can potentially lead to executing code in `to`.\n // solhint-disable-next-line avoid-low-level-calls\n (bool success,) = to.call{value: value}(\"\");\n require(success, \"ETH transfer failed\");\n } else {\n IERC20(token).safeTransfer(to, value);\n }\n }\n\n /// @notice Issues an infinite allowance to the spender, if the current allowance is insufficient\n /// to spend the given amount.\n function universalApproveInfinity(address token, address spender, uint256 amountToSpend) internal {\n // ETH Chad doesn't require your approval\n if (token == ETH_ADDRESS) return;\n // No-op if allowance is already sufficient\n uint256 allowance = IERC20(token).allowance(address(this), spender);\n if (allowance \u003e= amountToSpend) return;\n // Otherwise, reset approval to 0 and set to max allowance\n if (allowance \u003e 0) IERC20(token).safeDecreaseAllowance(spender, allowance);\n IERC20(token).safeIncreaseAllowance(spender, type(uint256).max);\n }\n\n /// @notice Returns the balance of the given token (or native ETH) for the given account.\n function universalBalanceOf(address token, address account) internal view returns (uint256) {\n if (token == ETH_ADDRESS) {\n return account.balance;\n } else {\n return IERC20(token).balanceOf(account);\n }\n }\n\n /// @dev Checks that token is a contract and not ETH_ADDRESS.\n function assertIsContract(address token) internal view {\n // Check that ETH_ADDRESS was not used (in case this is a predeploy on any of the chains)\n if (token == UniversalTokenLib.ETH_ADDRESS) revert TokenNotContract();\n // Check that token is not an EOA\n if (token.code.length == 0) revert TokenNotContract();\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/Admin.sol\n\ncontract Admin is IAdmin, AccessControlEnumerable {\n using UniversalTokenLib for address;\n\n bytes32 public constant RELAYER_ROLE = keccak256(\"RELAYER_ROLE\");\n bytes32 public constant REFUNDER_ROLE = keccak256(\"REFUNDER_ROLE\");\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n uint256 public constant FEE_BPS = 1e6;\n uint256 public constant FEE_RATE_MAX = 0.01e6; // max 1% on origin amount\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Chain gas amount to forward as rebate if requested\n uint256 public chainGasAmount;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n }\n\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n require(newFeeRate \u003c= FEE_RATE_MAX, \"newFeeRate \u003e max\");\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n token.universalTransfer(recipient, feeAmount);\n emit FeesSwept(token, recipient, feeAmount);\n }\n\n function setChainGasAmount(uint256 newChainGasAmount) external onlyRole(GOVERNOR_ROLE) {\n uint256 oldChainGasAmount = chainGasAmount;\n chainGasAmount = newChainGasAmount;\n emit ChainGasAmountUpdated(oldChainGasAmount, newChainGasAmount);\n }\n}\n\n// contracts/FastBridgeV2.sol\n\n/// @notice FastBridgeV2 is a contract for bridging tokens across chains.\ncontract FastBridgeV2 is Admin, IFastBridgeV2, IFastBridgeV2Errors {\n using SafeERC20 for IERC20;\n using UniversalTokenLib for address;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Delay for a transaction after which it could be permisionlessly refunded\n uint256 public constant REFUND_DELAY = 7 days;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n /// @notice Maximum length of accepted callParams\n uint256 public constant MAX_CALL_PARAMS_LENGTH = 2 ** 16 - 1;\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeTxDetails) public bridgeTxDetails;\n /// @notice Relay details on destination chain\n mapping(bytes32 =\u003e BridgeRelay) public bridgeRelayDetails;\n /// @notice Unique bridge nonces tracked per originSender\n mapping(address =\u003e uint256) public senderNonces;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Replaced by senderNonces\n uint256 public immutable nonce = 0;\n /// @notice the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n bridge({\n params: params,\n paramsV2: BridgeParamsV2({\n quoteRelayer: address(0),\n quoteExclusivitySeconds: 0,\n quoteId: bytes(\"\"),\n callValue: 0,\n callParams: bytes(\"\")\n })\n });\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes memory request) external payable {\n relay({request: request, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes memory request, bytes32 destTxHash) external {\n prove({transactionId: keccak256(request), destTxHash: destTxHash, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridgeV2\n function claim(bytes memory request) external {\n claim({request: request, to: address(0)});\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003e DISPUTE_PERIOD) {\n revert DisputePeriodPassed();\n }\n\n // @dev relayer gets slashed effectively if dest relay has gone thru\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n bridgeTxDetails[transactionId].proofRelayer = address(0);\n bridgeTxDetails[transactionId].proofBlockTimestamp = 0;\n bridgeTxDetails[transactionId].proofBlockNumber = 0;\n\n emit BridgeProofDisputed(transactionId, msg.sender);\n }\n\n /// @inheritdoc IFastBridge\n function refund(bytes memory request) external {\n bytes32 transactionId = keccak256(request);\n\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n\n if (bridgeTxDetails[transactionId].status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n\n if (hasRole(REFUNDER_ROLE, msg.sender)) {\n // Refunder can refund if deadline has passed\n if (block.timestamp \u003c= transaction.deadline) revert DeadlineNotExceeded();\n } else {\n // Permissionless refund is allowed after REFUND_DELAY\n if (block.timestamp \u003c= transaction.deadline + REFUND_DELAY) revert DeadlineNotExceeded();\n }\n\n // if all checks passed, set to REFUNDED status\n bridgeTxDetails[transactionId].status = BridgeStatus.REFUNDED;\n\n // transfer origin collateral back to original sender\n address to = transaction.originSender;\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount + transaction.originFeeAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (bridgeTxDetails[transactionId].proofRelayer != relayer) revert SenderIncorrect();\n return _timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n /// @dev This method is added to achieve backwards compatibility with decoding requests into V1 structs:\n /// - `callValue` is partially reported as a zero/non-zero flag\n /// - `callParams` is ignored\n /// In order to process all kinds of requests use getBridgeTransactionV2 instead.\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory) {\n // Try decoding into V2 struct first. This will revert if V1 struct is passed\n try this.getBridgeTransactionV2(request) returns (BridgeTransactionV2 memory txV2) {\n // Note: we entirely ignore the callParams field, as it was not present in V1\n return BridgeTransaction({\n originChainId: txV2.originChainId,\n destChainId: txV2.destChainId,\n originSender: txV2.originSender,\n destRecipient: txV2.destRecipient,\n originToken: txV2.originToken,\n destToken: txV2.destToken,\n originAmount: txV2.originAmount,\n destAmount: txV2.destAmount,\n originFeeAmount: txV2.originFeeAmount,\n sendChainGas: txV2.callValue != 0,\n deadline: txV2.deadline,\n nonce: txV2.nonce\n });\n } catch {\n // Fallback to V1 struct\n return abi.decode(request, (BridgeTransaction));\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) public payable {\n int256 exclusivityEndTime = int256(block.timestamp) + paramsV2.quoteExclusivitySeconds;\n _validateBridgeParams(params, paramsV2, exclusivityEndTime);\n\n // transfer tokens to bridge contract\n /// @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _pullToken(params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n\n // set status to requested\n bytes memory request = abi.encode(\n BridgeTransactionV2({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n callValue: paramsV2.callValue,\n deadline: params.deadline,\n nonce: senderNonces[params.sender]++, // increment nonce on every bridge\n exclusivityRelayer: paramsV2.quoteRelayer,\n // We checked exclusivityEndTime to be in range (0 .. params.deadline] above, so can safely cast\n exclusivityEndTime: uint256(exclusivityEndTime),\n callParams: paramsV2.callParams\n })\n );\n bytes32 transactionId = keccak256(request);\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n\n emit BridgeRequested({\n transactionId: transactionId,\n sender: params.sender,\n request: request,\n destChainId: params.dstChainId,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n sendChainGas: paramsV2.callValue != 0\n });\n emit BridgeQuoteDetails(transactionId, paramsV2.quoteId);\n }\n\n /// @inheritdoc IFastBridgeV2\n function relay(bytes memory request, address relayer) public payable {\n bytes32 transactionId = keccak256(request);\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n _validateRelayParams(transaction, transactionId, relayer);\n // mark bridge transaction as relayed\n bridgeRelayDetails[transactionId] =\n BridgeRelay({blockNumber: uint48(block.number), blockTimestamp: uint48(block.timestamp), relayer: relayer});\n\n // transfer tokens to recipient on destination chain and do an arbitrary call if requested\n address to = transaction.destRecipient;\n address token = transaction.destToken;\n uint256 amount = transaction.destAmount;\n\n // All state changes have been done at this point, can proceed to the external calls.\n // This follows the checks-effects-interactions pattern to mitigate potential reentrancy attacks.\n if (token == UniversalTokenLib.ETH_ADDRESS) {\n // For ETH non-zero callValue is not allowed\n if (transaction.callValue != 0) revert NativeTokenCallValueNotSupported();\n // Check that the correct msg.value was sent\n if (msg.value != amount) revert MsgValueIncorrect();\n } else {\n // For ERC20s, we check that the correct msg.value was sent\n if (msg.value != transaction.callValue) revert MsgValueIncorrect();\n // We need to transfer the tokens from the Relayer to the recipient first before performing an\n // optional post-transfer arbitrary call.\n IERC20(token).safeTransferFrom(msg.sender, to, amount);\n }\n\n if (transaction.callParams.length != 0) {\n // Arbitrary call requested, perform it while supplying full msg.value to the recipient\n // Note: if token has a fee on transfers, the recipient will have received less than `amount`.\n // This is a very niche edge case and should be handled by the recipient contract.\n _checkedCallRecipient({recipient: to, token: token, amount: amount, callParams: transaction.callParams});\n } else if (msg.value != 0) {\n // No arbitrary call requested, but msg.value was sent. This is either a relay with ETH,\n // or a non-zero callValue request with an ERC20. In both cases, transfer the ETH to the recipient.\n Address.sendValue(payable(to), msg.value);\n }\n\n emit BridgeRelayed({\n transactionId: transactionId,\n relayer: relayer,\n to: to,\n originChainId: transaction.originChainId,\n originToken: transaction.originToken,\n destToken: transaction.destToken,\n originAmount: transaction.originAmount,\n destAmount: transaction.destAmount,\n chainGasAmount: transaction.callValue\n });\n }\n\n /// @inheritdoc IFastBridgeV2\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) public onlyRole(RELAYER_ROLE) {\n // update bridge tx status given proof provided\n if (bridgeTxDetails[transactionId].status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n bridgeTxDetails[transactionId].status = BridgeStatus.RELAYER_PROVED;\n bridgeTxDetails[transactionId].proofBlockTimestamp = uint40(block.timestamp);\n bridgeTxDetails[transactionId].proofBlockNumber = uint48(block.number);\n bridgeTxDetails[transactionId].proofRelayer = relayer;\n\n emit BridgeProofProvided(transactionId, relayer, destTxHash);\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes memory request, address to) public {\n bytes32 transactionId = keccak256(request);\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n\n // update bridge tx status if able to claim origin collateral\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n\n // if \"to\" is zero addr, permissionlessly send funds to proven relayer\n if (to == address(0)) {\n to = bridgeTxDetails[transactionId].proofRelayer;\n } else if (bridgeTxDetails[transactionId].proofRelayer != msg.sender) {\n revert SenderIncorrect();\n }\n\n if (_timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003c= DISPUTE_PERIOD) {\n revert DisputePeriodNotPassed();\n }\n\n bridgeTxDetails[transactionId].status = BridgeStatus.RELAYER_CLAIMED;\n\n // update protocol fees if origin fee amount exists\n if (transaction.originFeeAmount \u003e 0) protocolFees[transaction.originToken] += transaction.originFeeAmount;\n\n // transfer origin collateral less fee to specified address\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositClaimed(transactionId, bridgeTxDetails[transactionId].proofRelayer, to, token, amount);\n }\n\n function bridgeStatuses(bytes32 transactionId) public view returns (BridgeStatus status) {\n return bridgeTxDetails[transactionId].status;\n }\n\n function bridgeProofs(bytes32 transactionId) public view returns (uint96 timestamp, address relayer) {\n timestamp = bridgeTxDetails[transactionId].proofBlockTimestamp;\n relayer = bridgeTxDetails[transactionId].proofRelayer;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeRelays(bytes32 transactionId) public view returns (bool) {\n // has this transactionId been relayed?\n return bridgeRelayDetails[transactionId].relayer != address(0);\n }\n\n /// @inheritdoc IFastBridgeV2\n function getBridgeTransactionV2(bytes memory request) public pure returns (BridgeTransactionV2 memory) {\n return abi.decode(request, (BridgeTransactionV2));\n }\n\n /// @notice Pulls a requested token from the user to this contract.\n function _pullToken(address token, uint256 amount) internal returns (uint256 amountPulled) {\n if (token == UniversalTokenLib.ETH_ADDRESS) {\n // For ETH we just need to check that the supplied msg.value is correct\n if (amount != msg.value) revert MsgValueIncorrect();\n amountPulled = msg.value;\n } else {\n token.assertIsContract();\n // Record token balance before transfer\n amountPulled = IERC20(token).balanceOf(address(this));\n // Token needs to be pulled only if msg.value is zero\n // This way user can specify WETH as the origin asset\n IERC20(token).safeTransferFrom(msg.sender, address(this), amount);\n // Use the difference between the recorded balance and the current balance as the amountPulled\n amountPulled = IERC20(token).balanceOf(address(this)) - amountPulled;\n }\n }\n\n /// @notice Calls the Recipient's hook function with the specified callParams and performs\n /// all the necessary checks for the returned value.\n function _checkedCallRecipient(\n address recipient,\n address token,\n uint256 amount,\n bytes memory callParams\n )\n internal\n {\n bytes memory hookData =\n abi.encodeCall(IFastBridgeRecipient.fastBridgeTransferReceived, (token, amount, callParams));\n // This will bubble any revert messages from the hook function\n bytes memory returnData = Address.functionCallWithValue({target: recipient, data: hookData, value: msg.value});\n // Explicit revert if no return data at all\n if (returnData.length == 0) revert RecipientNoReturnValue();\n // Check that exactly a single return value was returned\n if (returnData.length != 32) revert RecipientIncorrectReturnValue();\n // Return value should be abi-encoded hook function selector\n if (bytes32(returnData) != bytes32(IFastBridgeRecipient.fastBridgeTransferReceived.selector)) {\n revert RecipientIncorrectReturnValue();\n }\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint40(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint40).max but\n /// proof.timestamp \u003c type(uint40).max via unchecked statement\n /// @param proofBlockTimestamp The bridge proof block timestamp\n /// @return delta Time delta since proof submitted\n function _timeSince(uint40 proofBlockTimestamp) internal view returns (uint256 delta) {\n unchecked {\n delta = uint40(block.timestamp) - proofBlockTimestamp;\n }\n }\n\n /// @notice Performs all the necessary checks for a bridge to happen.\n /// @dev There's no good way to refactor this function to reduce cyclomatic complexity due to\n /// the number of checks that need to be performed, so we skip the code-complexity rule here.\n // solhint-disable-next-line code-complexity\n function _validateBridgeParams(\n BridgeParams memory params,\n BridgeParamsV2 memory paramsV2,\n int256 exclusivityEndTime\n )\n internal\n view\n {\n // Check V1 (legacy) params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.sender == address(0) || params.to == address(0)) revert ZeroAddress();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n // Check V2 params\n if (paramsV2.callParams.length \u003e MAX_CALL_PARAMS_LENGTH) revert CallParamsLengthAboveMax();\n if (paramsV2.callValue != 0 \u0026\u0026 params.destToken == UniversalTokenLib.ETH_ADDRESS) {\n revert NativeTokenCallValueNotSupported();\n }\n // exclusivityEndTime must be in range (0 .. params.deadline]\n if (exclusivityEndTime \u003c= 0 || exclusivityEndTime \u003e int256(params.deadline)) {\n revert ExclusivityParamsIncorrect();\n }\n }\n\n /// @notice Performs all the necessary checks for a relay to happen.\n function _validateRelayParams(\n BridgeTransactionV2 memory transaction,\n bytes32 transactionId,\n address relayer\n )\n internal\n view\n {\n if (relayer == address(0)) revert ZeroAddress();\n // Check if the transaction has already been relayed\n if (bridgeRelays(transactionId)) revert TransactionRelayed();\n if (transaction.destChainId != uint32(block.chainid)) revert ChainIncorrect();\n // Check the deadline for relay to happen\n if (block.timestamp \u003e transaction.deadline) revert DeadlineExceeded();\n // Check the exclusivity period, if it is still ongoing\n // forgefmt: disable-next-item\n if (\n transaction.exclusivityRelayer != address(0) \u0026\u0026\n transaction.exclusivityRelayer != relayer \u0026\u0026\n block.timestamp \u003c= transaction.exclusivityEndTime\n ) {\n revert ExclusivityPeriodNotPassed();\n }\n }\n}\n","language":"Solidity","languageVersion":"0.8.24","compilerVersion":"0.8.24","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../","srcMap":"16564:6066:0:-:0;;;;;;;;;;;;;;;-1:-1:-1;;;16564:6066:0;;;;;;;;;;;;;;;;;","srcMapRuntime":"16564:6066:0:-:0;;;;;;;;","abiDefinition":[{"inputs":[{"internalType":"address","name":"target","type":"address"}],"name":"AddressEmptyCode","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"AddressInsufficientBalance","type":"error"},{"inputs":[],"name":"FailedInnerCall","type":"error"}],"userDoc":{"kind":"user","methods":{},"version":1},"developerDoc":{"details":"Collection of functions related to the address type","errors":{"AddressEmptyCode(address)":[{"details":"There's no code at `target` (it is not a contract)."}],"AddressInsufficientBalance(address)":[{"details":"The ETH balance of the account is not enough to perform the operation."}],"FailedInnerCall()":[{"details":"A call to an address target failed. The target may have reverted."}]},"kind":"dev","methods":{},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"}],\"name\":\"AddressEmptyCode\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"AddressInsufficientBalance\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"FailedInnerCall\",\"type\":\"error\"}],\"devdoc\":{\"details\":\"Collection of functions related to the address type\",\"errors\":{\"AddressEmptyCode(address)\":[{\"details\":\"There's no code at `target` (it is not a contract).\"}],\"AddressInsufficientBalance(address)\":[{\"details\":\"The ETH balance of the account is not enough to perform the operation.\"}],\"FailedInnerCall()\":[{\"details\":\"A call to an address target failed. The target may have reverted.\"}]},\"kind\":\"dev\",\"methods\":{},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeV2.sol\":\"Address\"},\"evmVersion\":\"shanghai\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeV2.sol\":{\"keccak256\":\"0x7cd0f885e80e2bdaa638bc32ae7af7d2e248f99ce4b354c217d0f0f7d7302e0a\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://7ccf28df0bd7b4606986585acd8622ed9b4e81379690061bb66088f0a2270af1\",\"dweb:/ipfs/QmTf7HNdHZkK6vmx8ZgewycQEb72oLD9nPwBpsM5reMstQ\"]}},\"version\":1}"},"hashes":{}},"solidity/FastBridgeV2.sol:Admin":{"code":"0x608060405234801562000010575f80fd5b50604051620013a3380380620013a3833981016040819052620000339162000184565b6200003f5f8262000047565b5050620001ac565b5f8062000055848462000082565b9050801562000079575f8481526001602052604090206200007790846200012d565b505b90505b92915050565b5f828152602081815260408083206001600160a01b038516845290915281205460ff1662000125575f838152602081815260408083206001600160a01b03861684529091529020805460ff19166001179055620000dc3390565b6001600160a01b0316826001600160a01b0316847f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45060016200007c565b505f6200007c565b5f62000079836001600160a01b0384165f8181526001830160205260408120546200012557508154600181810184555f8481526020808220909301849055845484825282860190935260409020919091556200007c565b5f6020828403121562000195575f80fd5b81516001600160a01b038116811462000079575f80fd5b6111e980620001ba5f395ff3fe608060405234801561000f575f80fd5b506004361061016e575f3560e01c806391d14854116100d2578063bf333f2c11610088578063d547741f11610063578063d547741f14610378578063dcf844a71461038b578063e00a83e0146103aa575f80fd5b8063bf333f2c14610334578063ca15c8731461033e578063ccc5749014610351575f80fd5b8063a217fddf116100b8578063a217fddf14610307578063b13aa2d61461030e578063b250fe6b14610321575f80fd5b806391d148541461029d578063926d7d7f146102e0575f80fd5b80632f2ff15d1161012757806358f858801161010d57806358f85880146102355780635960ccf21461023e5780639010d07c14610265575f80fd5b80632f2ff15d1461020f57806336568abe14610222575f80fd5b806306f333f21161015757806306f333f2146101cf5780630f5f6ed7146101e4578063248a9ca3146101ed575f80fd5b806301ffc9a71461017257806303ed0ee51461019a575b5f80fd5b610185610180366004610fcd565b6103b3565b60405190151581526020015b60405180910390f35b6101c17f043c983c49d46f0e102151eaf8085d4a2e6571d5df2d47b013f39bddfd4a639d81565b604051908152602001610191565b6101e26101dd366004611034565b61040e565b005b6101c161271081565b6101c16101fb366004611065565b5f9081526020819052604090206001015490565b6101e261021d36600461107c565b6104fa565b6101e261023036600461107c565b610524565b6101c160025481565b6101c17fdb9556138406326f00296e13ea2ad7db24ba82381212d816b1a40c23b466b32781565b61027861027336600461109d565b61057d565b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610191565b6101856102ab36600461107c565b5f9182526020828152604080842073ffffffffffffffffffffffffffffffffffffffff93909316845291905290205460ff1690565b6101c17fe2b7fb3b832174769106daebcfd6d1970523240dda11281102db9363b83b0dc481565b6101c15f81565b6101e261031c366004611065565b61059b565b6101e261032f366004611065565b61067d565b6101c1620f424081565b6101c161034c366004611065565b6106e5565b6101c17f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f5581565b6101e261038636600461107c565b6106fb565b6101c16103993660046110bd565b60036020525f908152604090205481565b6101c160045481565b5f7fffffffff0000000000000000000000000000000000000000000000000000000082167f5a05180f00000000000000000000000000000000000000000000000000000000148061040857506104088261071f565b92915050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f55610438816107b5565b73ffffffffffffffffffffffffffffffffffffffff83165f908152600360205260408120549081900361046b5750505050565b73ffffffffffffffffffffffffffffffffffffffff84165f8181526003602052604081205561049b9084836107c2565b6040805173ffffffffffffffffffffffffffffffffffffffff8087168252851660208201529081018290527f244e51bc38c1452fa8aaf487bcb4bca36c2baa3a5fbdb776b1eabd8dc6d277cd9060600160405180910390a1505b505050565b5f82815260208190526040902060010154610514816107b5565b61051e8383610914565b50505050565b73ffffffffffffffffffffffffffffffffffffffff81163314610573576040517f6697b23200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6104f58282610947565b5f8281526001602052604081206105949083610972565b9392505050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f556105c5816107b5565b612710821115610636576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f6e657746656552617465203e206d61780000000000000000000000000000000060448201526064015b60405180910390fd5b600280549083905560408051828152602081018590527f14914da2bf76024616fbe1859783fcd4dbddcb179b1f3a854949fbf920dcb95791015b60405180910390a1505050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f556106a7816107b5565b600480549083905560408051828152602081018590527f5cf09b12f3f56b4c564d51b25b40360af6d795198adb61ae0806a36c294323fa9101610670565b5f8181526001602052604081206104089061097d565b5f82815260208190526040902060010154610715816107b5565b61051e8383610947565b5f7fffffffff0000000000000000000000000000000000000000000000000000000082167f7965db0b00000000000000000000000000000000000000000000000000000000148061040857507f01ffc9a7000000000000000000000000000000000000000000000000000000007fffffffff00000000000000000000000000000000000000000000000000000000831614610408565b6107bf8133610986565b50565b3073ffffffffffffffffffffffffffffffffffffffff8316036107e457505050565b805f036107f057505050565b7fffffffffffffffffffffffff111111111111111111111111111111111111111273ffffffffffffffffffffffffffffffffffffffff8416016108f3575f8273ffffffffffffffffffffffffffffffffffffffff16826040515f6040518083038185875af1925050503d805f8114610883576040519150601f19603f3d011682016040523d82523d5f602084013e610888565b606091505b505090508061051e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f455448207472616e73666572206661696c656400000000000000000000000000604482015260640161062d565b6104f573ffffffffffffffffffffffffffffffffffffffff84168383610a0f565b5f806109208484610a9c565b90508015610594575f84815260016020526040902061093f9084610b95565b509392505050565b5f806109538484610bb6565b90508015610594575f84815260016020526040902061093f9084610c6f565b5f6105948383610c90565b5f610408825490565b5f8281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915290205460ff16610a0b576040517fe2517d3f00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff821660048201526024810183905260440161062d565b5050565b6040805173ffffffffffffffffffffffffffffffffffffffff8416602482015260448082018490528251808303909101815260649091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fa9059cbb000000000000000000000000000000000000000000000000000000001790526104f5908490610cb6565b5f8281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915281205460ff16610b8e575f8381526020818152604080832073ffffffffffffffffffffffffffffffffffffffff86168452909152902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055610b2c3390565b73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16847f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a4506001610408565b505f610408565b5f6105948373ffffffffffffffffffffffffffffffffffffffff8416610d4a565b5f8281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915281205460ff1615610b8e575f8381526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8616808552925280832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016905551339286917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a4506001610408565b5f6105948373ffffffffffffffffffffffffffffffffffffffff8416610d8f565b5f825f018281548110610ca557610ca56110d6565b905f5260205f200154905092915050565b5f610cd773ffffffffffffffffffffffffffffffffffffffff841683610e72565b905080515f14158015610cfb575080806020019051810190610cf99190611103565b155b156104f5576040517f5274afe700000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8416600482015260240161062d565b5f818152600183016020526040812054610b8e57508154600181810184555f848152602080822090930184905584548482528286019093526040902091909155610408565b5f8181526001830160205260408120548015610e69575f610db1600183611122565b85549091505f90610dc490600190611122565b9050808214610e23575f865f018281548110610de257610de26110d6565b905f5260205f200154905080875f018481548110610e0257610e026110d6565b5f918252602080832090910192909255918252600188019052604090208390555b8554869080610e3457610e3461115a565b600190038181905f5260205f20015f90559055856001015f8681526020019081526020015f205f905560019350505050610408565b5f915050610408565b606061059483835f845f808573ffffffffffffffffffffffffffffffffffffffff168486604051610ea39190611187565b5f6040518083038185875af1925050503d805f8114610edd576040519150601f19603f3d011682016040523d82523d5f602084013e610ee2565b606091505b5091509150610ef2868383610efc565b9695505050505050565b606082610f1157610f0c82610f8b565b610594565b8151158015610f35575073ffffffffffffffffffffffffffffffffffffffff84163b155b15610f84576040517f9996b31500000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8516600482015260240161062d565b5080610594565b805115610f9b5780518082602001fd5b6040517f1425ea4200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f60208284031215610fdd575f80fd5b81357fffffffff0000000000000000000000000000000000000000000000000000000081168114610594575f80fd5b803573ffffffffffffffffffffffffffffffffffffffff8116811461102f575f80fd5b919050565b5f8060408385031215611045575f80fd5b61104e8361100c565b915061105c6020840161100c565b90509250929050565b5f60208284031215611075575f80fd5b5035919050565b5f806040838503121561108d575f80fd5b8235915061105c6020840161100c565b5f80604083850312156110ae575f80fd5b50508035926020909101359150565b5f602082840312156110cd575f80fd5b6105948261100c565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b5f60208284031215611113575f80fd5b81518015158114610594575f80fd5b81810381811115610408577f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603160045260245ffd5b5f82515f5b818110156111a6576020818601810151858301520161118c565b505f92019182525091905056fea2646970667358221220663496d7fb99c06349f8fc2145322e6c10ba61153be06cea50f6b07db91bc1bd64736f6c63430008180033","runtime-code":"0x608060405234801561000f575f80fd5b506004361061016e575f3560e01c806391d14854116100d2578063bf333f2c11610088578063d547741f11610063578063d547741f14610378578063dcf844a71461038b578063e00a83e0146103aa575f80fd5b8063bf333f2c14610334578063ca15c8731461033e578063ccc5749014610351575f80fd5b8063a217fddf116100b8578063a217fddf14610307578063b13aa2d61461030e578063b250fe6b14610321575f80fd5b806391d148541461029d578063926d7d7f146102e0575f80fd5b80632f2ff15d1161012757806358f858801161010d57806358f85880146102355780635960ccf21461023e5780639010d07c14610265575f80fd5b80632f2ff15d1461020f57806336568abe14610222575f80fd5b806306f333f21161015757806306f333f2146101cf5780630f5f6ed7146101e4578063248a9ca3146101ed575f80fd5b806301ffc9a71461017257806303ed0ee51461019a575b5f80fd5b610185610180366004610fcd565b6103b3565b60405190151581526020015b60405180910390f35b6101c17f043c983c49d46f0e102151eaf8085d4a2e6571d5df2d47b013f39bddfd4a639d81565b604051908152602001610191565b6101e26101dd366004611034565b61040e565b005b6101c161271081565b6101c16101fb366004611065565b5f9081526020819052604090206001015490565b6101e261021d36600461107c565b6104fa565b6101e261023036600461107c565b610524565b6101c160025481565b6101c17fdb9556138406326f00296e13ea2ad7db24ba82381212d816b1a40c23b466b32781565b61027861027336600461109d565b61057d565b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610191565b6101856102ab36600461107c565b5f9182526020828152604080842073ffffffffffffffffffffffffffffffffffffffff93909316845291905290205460ff1690565b6101c17fe2b7fb3b832174769106daebcfd6d1970523240dda11281102db9363b83b0dc481565b6101c15f81565b6101e261031c366004611065565b61059b565b6101e261032f366004611065565b61067d565b6101c1620f424081565b6101c161034c366004611065565b6106e5565b6101c17f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f5581565b6101e261038636600461107c565b6106fb565b6101c16103993660046110bd565b60036020525f908152604090205481565b6101c160045481565b5f7fffffffff0000000000000000000000000000000000000000000000000000000082167f5a05180f00000000000000000000000000000000000000000000000000000000148061040857506104088261071f565b92915050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f55610438816107b5565b73ffffffffffffffffffffffffffffffffffffffff83165f908152600360205260408120549081900361046b5750505050565b73ffffffffffffffffffffffffffffffffffffffff84165f8181526003602052604081205561049b9084836107c2565b6040805173ffffffffffffffffffffffffffffffffffffffff8087168252851660208201529081018290527f244e51bc38c1452fa8aaf487bcb4bca36c2baa3a5fbdb776b1eabd8dc6d277cd9060600160405180910390a1505b505050565b5f82815260208190526040902060010154610514816107b5565b61051e8383610914565b50505050565b73ffffffffffffffffffffffffffffffffffffffff81163314610573576040517f6697b23200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6104f58282610947565b5f8281526001602052604081206105949083610972565b9392505050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f556105c5816107b5565b612710821115610636576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f6e657746656552617465203e206d61780000000000000000000000000000000060448201526064015b60405180910390fd5b600280549083905560408051828152602081018590527f14914da2bf76024616fbe1859783fcd4dbddcb179b1f3a854949fbf920dcb95791015b60405180910390a1505050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f556106a7816107b5565b600480549083905560408051828152602081018590527f5cf09b12f3f56b4c564d51b25b40360af6d795198adb61ae0806a36c294323fa9101610670565b5f8181526001602052604081206104089061097d565b5f82815260208190526040902060010154610715816107b5565b61051e8383610947565b5f7fffffffff0000000000000000000000000000000000000000000000000000000082167f7965db0b00000000000000000000000000000000000000000000000000000000148061040857507f01ffc9a7000000000000000000000000000000000000000000000000000000007fffffffff00000000000000000000000000000000000000000000000000000000831614610408565b6107bf8133610986565b50565b3073ffffffffffffffffffffffffffffffffffffffff8316036107e457505050565b805f036107f057505050565b7fffffffffffffffffffffffff111111111111111111111111111111111111111273ffffffffffffffffffffffffffffffffffffffff8416016108f3575f8273ffffffffffffffffffffffffffffffffffffffff16826040515f6040518083038185875af1925050503d805f8114610883576040519150601f19603f3d011682016040523d82523d5f602084013e610888565b606091505b505090508061051e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f455448207472616e73666572206661696c656400000000000000000000000000604482015260640161062d565b6104f573ffffffffffffffffffffffffffffffffffffffff84168383610a0f565b5f806109208484610a9c565b90508015610594575f84815260016020526040902061093f9084610b95565b509392505050565b5f806109538484610bb6565b90508015610594575f84815260016020526040902061093f9084610c6f565b5f6105948383610c90565b5f610408825490565b5f8281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915290205460ff16610a0b576040517fe2517d3f00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff821660048201526024810183905260440161062d565b5050565b6040805173ffffffffffffffffffffffffffffffffffffffff8416602482015260448082018490528251808303909101815260649091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fa9059cbb000000000000000000000000000000000000000000000000000000001790526104f5908490610cb6565b5f8281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915281205460ff16610b8e575f8381526020818152604080832073ffffffffffffffffffffffffffffffffffffffff86168452909152902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055610b2c3390565b73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16847f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a4506001610408565b505f610408565b5f6105948373ffffffffffffffffffffffffffffffffffffffff8416610d4a565b5f8281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915281205460ff1615610b8e575f8381526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8616808552925280832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016905551339286917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a4506001610408565b5f6105948373ffffffffffffffffffffffffffffffffffffffff8416610d8f565b5f825f018281548110610ca557610ca56110d6565b905f5260205f200154905092915050565b5f610cd773ffffffffffffffffffffffffffffffffffffffff841683610e72565b905080515f14158015610cfb575080806020019051810190610cf99190611103565b155b156104f5576040517f5274afe700000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8416600482015260240161062d565b5f818152600183016020526040812054610b8e57508154600181810184555f848152602080822090930184905584548482528286019093526040902091909155610408565b5f8181526001830160205260408120548015610e69575f610db1600183611122565b85549091505f90610dc490600190611122565b9050808214610e23575f865f018281548110610de257610de26110d6565b905f5260205f200154905080875f018481548110610e0257610e026110d6565b5f918252602080832090910192909255918252600188019052604090208390555b8554869080610e3457610e3461115a565b600190038181905f5260205f20015f90559055856001015f8681526020019081526020015f205f905560019350505050610408565b5f915050610408565b606061059483835f845f808573ffffffffffffffffffffffffffffffffffffffff168486604051610ea39190611187565b5f6040518083038185875af1925050503d805f8114610edd576040519150601f19603f3d011682016040523d82523d5f602084013e610ee2565b606091505b5091509150610ef2868383610efc565b9695505050505050565b606082610f1157610f0c82610f8b565b610594565b8151158015610f35575073ffffffffffffffffffffffffffffffffffffffff84163b155b15610f84576040517f9996b31500000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8516600482015260240161062d565b5080610594565b805115610f9b5780518082602001fd5b6040517f1425ea4200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f60208284031215610fdd575f80fd5b81357fffffffff0000000000000000000000000000000000000000000000000000000081168114610594575f80fd5b803573ffffffffffffffffffffffffffffffffffffffff8116811461102f575f80fd5b919050565b5f8060408385031215611045575f80fd5b61104e8361100c565b915061105c6020840161100c565b90509250929050565b5f60208284031215611075575f80fd5b5035919050565b5f806040838503121561108d575f80fd5b8235915061105c6020840161100c565b5f80604083850312156110ae575f80fd5b50508035926020909101359150565b5f602082840312156110cd575f80fd5b6105948261100c565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b5f60208284031215611113575f80fd5b81518015158114610594575f80fd5b81810381811115610408577f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603160045260245ffd5b5f82515f5b818110156111a6576020818601810151858301520161118c565b505f92019182525091905056fea2646970667358221220663496d7fb99c06349f8fc2145322e6c10ba61153be06cea50f6b07db91bc1bd64736f6c63430008180033","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.24 ^0.8.0 ^0.8.20;\n\n// contracts/interfaces/IAdmin.sol\n\ninterface IAdmin {\n // ============ Events ============\n\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n event ChainGasAmountUpdated(uint256 oldChainGasAmount, uint256 newChainGasAmount);\n\n // ============ Methods ============\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n\n function setChainGasAmount(uint256 newChainGasAmount) external;\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IFastBridgeRecipient.sol\n\ninterface IFastBridgeRecipient {\n function fastBridgeTransferReceived(\n address token,\n uint256 amount,\n bytes memory callParams\n )\n external\n payable\n returns (bytes4);\n}\n\n// contracts/interfaces/IFastBridgeV2Errors.sol\n\ninterface IFastBridgeV2Errors {\n error AmountIncorrect();\n error CallParamsLengthAboveMax();\n error ChainIncorrect();\n error ExclusivityParamsIncorrect();\n error MsgValueIncorrect();\n error NativeTokenCallValueNotSupported();\n error SenderIncorrect();\n error StatusIncorrect();\n error ZeroAddress();\n\n error RecipientIncorrectReturnValue();\n error RecipientNoReturnValue();\n\n error DeadlineExceeded();\n error DeadlineNotExceeded();\n error DeadlineTooShort();\n error DisputePeriodNotPassed();\n error DisputePeriodPassed();\n error ExclusivityPeriodNotPassed();\n\n error TransactionRelayed();\n}\n\n// contracts/libs/Errors.sol\n\nerror DeadlineExceeded();\nerror DeadlineNotExceeded();\nerror DeadlineTooShort();\nerror InsufficientOutputAmount();\n\nerror MsgValueIncorrect();\nerror PoolNotFound();\nerror TokenAddressMismatch();\nerror TokenNotContract();\nerror TokenNotETH();\nerror TokensIdentical();\n\nerror ChainIncorrect();\nerror AmountIncorrect();\nerror ZeroAddress();\n\nerror DisputePeriodNotPassed();\nerror DisputePeriodPassed();\nerror SenderIncorrect();\nerror StatusIncorrect();\nerror TransactionIdIncorrect();\nerror TransactionRelayed();\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// contracts/interfaces/IFastBridgeV2.sol\n\ninterface IFastBridgeV2 is IFastBridge {\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n struct BridgeTxDetails {\n BridgeStatus status;\n uint40 proofBlockTimestamp;\n uint48 proofBlockNumber;\n address proofRelayer;\n }\n\n struct BridgeRelay {\n uint48 blockNumber;\n uint48 blockTimestamp;\n address relayer;\n }\n\n /// @notice New params introduced in the FastBridgeV2.\n /// We are passing fields from the older BridgeParams struct outside of this struct\n /// for backwards compatibility.\n /// Note: quoteRelayer and quoteExclusivitySeconds are either both zero (indicating no exclusivity)\n /// or both non-zero (indicating exclusivity for the given period).\n /// Note: callValue \u003e 0 can NOT be used with destToken = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE (ETH_ADDRESS)\n /// @param quoteRelayer Relayer that provided the quote for the transaction\n /// @param quoteExclusivitySeconds Period of time the quote relayer is guaranteed exclusivity after user's deposit\n /// @param quoteId Unique quote identifier used for tracking the quote\n /// @param callValue ETH value to send to the recipient (if any)\n /// @param callParams Parameters for the arbitrary call to the destination recipient (if any)\n struct BridgeParamsV2 {\n address quoteRelayer;\n int256 quoteExclusivitySeconds;\n bytes quoteId;\n uint256 callValue;\n bytes callParams;\n }\n\n /// @notice Updated bridge transaction struct to include parameters introduced in FastBridgeV2.\n /// Note: only `exclusivityRelayer` can fill such a transaction until `exclusivityEndTime`.\n /// TODO: consider changing the encoding scheme to prevent spending extra gas on decoding.\n struct BridgeTransactionV2 {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n uint256 callValue; // ETH value to send to the recipient (if any) - replaces V1's sendChainGas flag\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n address exclusivityRelayer;\n uint256 exclusivityEndTime;\n bytes callParams;\n }\n\n event BridgeQuoteDetails(bytes32 indexed transactionId, bytes quoteId);\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability\n /// to provide temporary exclusivity fill rights for the quote relayer.\n /// @param params The parameters required to bridge\n /// @param paramsV2 The parameters for exclusivity fill rights (optional, can be left empty)\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function relay(bytes memory request, address relayer) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param transactionId The transaction id associated with the encoded bridge transaction to prove\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital.\n /// @notice Can only send funds to the relayer address on the proof.\n /// @param request The encoded bridge transaction to claim on origin chain\n function claim(bytes memory request) external;\n /// @notice Checks if a transaction has been relayed\n /// @param transactionId The ID of the transaction to check\n /// @return True if the transaction has been relayed, false otherwise\n function bridgeRelays(bytes32 transactionId) external view returns (bool);\n\n /// @notice Returns the status of a bridge transaction\n /// @param transactionId The ID of the bridge transaction\n /// @return BridgeStatus Status of the bridge transaction\n function bridgeStatuses(bytes32 transactionId) external view returns (BridgeStatus);\n\n /// @notice Returns the timestamp and relayer of a bridge proof\n /// @param transactionId The ID of the bridge transaction\n /// @return timestamp The timestamp of the bridge proof\n /// @return relayer The relayer address of the bridge proof\n function bridgeProofs(bytes32 transactionId) external view returns (uint96 timestamp, address relayer);\n\n /// @notice Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\n /// @param request The bridge request to decode\n function getBridgeTransactionV2(bytes memory request) external view returns (BridgeTransactionV2 memory);\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// contracts/libs/UniversalToken.sol\n\nlibrary UniversalTokenLib {\n using SafeERC20 for IERC20;\n\n address internal constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Transfers tokens to the given account. Reverts if transfer is not successful.\n /// @dev This might trigger fallback, if ETH is transferred to the contract.\n /// Make sure this can not lead to reentrancy attacks.\n function universalTransfer(address token, address to, uint256 value) internal {\n // Don't do anything, if need to send tokens to this address\n if (to == address(this)) return;\n // Don't do anything, if trying to send zero value\n if (value == 0) return;\n if (token == ETH_ADDRESS) {\n /// @dev Note: this can potentially lead to executing code in `to`.\n // solhint-disable-next-line avoid-low-level-calls\n (bool success,) = to.call{value: value}(\"\");\n require(success, \"ETH transfer failed\");\n } else {\n IERC20(token).safeTransfer(to, value);\n }\n }\n\n /// @notice Issues an infinite allowance to the spender, if the current allowance is insufficient\n /// to spend the given amount.\n function universalApproveInfinity(address token, address spender, uint256 amountToSpend) internal {\n // ETH Chad doesn't require your approval\n if (token == ETH_ADDRESS) return;\n // No-op if allowance is already sufficient\n uint256 allowance = IERC20(token).allowance(address(this), spender);\n if (allowance \u003e= amountToSpend) return;\n // Otherwise, reset approval to 0 and set to max allowance\n if (allowance \u003e 0) IERC20(token).safeDecreaseAllowance(spender, allowance);\n IERC20(token).safeIncreaseAllowance(spender, type(uint256).max);\n }\n\n /// @notice Returns the balance of the given token (or native ETH) for the given account.\n function universalBalanceOf(address token, address account) internal view returns (uint256) {\n if (token == ETH_ADDRESS) {\n return account.balance;\n } else {\n return IERC20(token).balanceOf(account);\n }\n }\n\n /// @dev Checks that token is a contract and not ETH_ADDRESS.\n function assertIsContract(address token) internal view {\n // Check that ETH_ADDRESS was not used (in case this is a predeploy on any of the chains)\n if (token == UniversalTokenLib.ETH_ADDRESS) revert TokenNotContract();\n // Check that token is not an EOA\n if (token.code.length == 0) revert TokenNotContract();\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/Admin.sol\n\ncontract Admin is IAdmin, AccessControlEnumerable {\n using UniversalTokenLib for address;\n\n bytes32 public constant RELAYER_ROLE = keccak256(\"RELAYER_ROLE\");\n bytes32 public constant REFUNDER_ROLE = keccak256(\"REFUNDER_ROLE\");\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n uint256 public constant FEE_BPS = 1e6;\n uint256 public constant FEE_RATE_MAX = 0.01e6; // max 1% on origin amount\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Chain gas amount to forward as rebate if requested\n uint256 public chainGasAmount;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n }\n\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n require(newFeeRate \u003c= FEE_RATE_MAX, \"newFeeRate \u003e max\");\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n token.universalTransfer(recipient, feeAmount);\n emit FeesSwept(token, recipient, feeAmount);\n }\n\n function setChainGasAmount(uint256 newChainGasAmount) external onlyRole(GOVERNOR_ROLE) {\n uint256 oldChainGasAmount = chainGasAmount;\n chainGasAmount = newChainGasAmount;\n emit ChainGasAmountUpdated(oldChainGasAmount, newChainGasAmount);\n }\n}\n\n// contracts/FastBridgeV2.sol\n\n/// @notice FastBridgeV2 is a contract for bridging tokens across chains.\ncontract FastBridgeV2 is Admin, IFastBridgeV2, IFastBridgeV2Errors {\n using SafeERC20 for IERC20;\n using UniversalTokenLib for address;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Delay for a transaction after which it could be permisionlessly refunded\n uint256 public constant REFUND_DELAY = 7 days;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n /// @notice Maximum length of accepted callParams\n uint256 public constant MAX_CALL_PARAMS_LENGTH = 2 ** 16 - 1;\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeTxDetails) public bridgeTxDetails;\n /// @notice Relay details on destination chain\n mapping(bytes32 =\u003e BridgeRelay) public bridgeRelayDetails;\n /// @notice Unique bridge nonces tracked per originSender\n mapping(address =\u003e uint256) public senderNonces;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Replaced by senderNonces\n uint256 public immutable nonce = 0;\n /// @notice the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n bridge({\n params: params,\n paramsV2: BridgeParamsV2({\n quoteRelayer: address(0),\n quoteExclusivitySeconds: 0,\n quoteId: bytes(\"\"),\n callValue: 0,\n callParams: bytes(\"\")\n })\n });\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes memory request) external payable {\n relay({request: request, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes memory request, bytes32 destTxHash) external {\n prove({transactionId: keccak256(request), destTxHash: destTxHash, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridgeV2\n function claim(bytes memory request) external {\n claim({request: request, to: address(0)});\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003e DISPUTE_PERIOD) {\n revert DisputePeriodPassed();\n }\n\n // @dev relayer gets slashed effectively if dest relay has gone thru\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n bridgeTxDetails[transactionId].proofRelayer = address(0);\n bridgeTxDetails[transactionId].proofBlockTimestamp = 0;\n bridgeTxDetails[transactionId].proofBlockNumber = 0;\n\n emit BridgeProofDisputed(transactionId, msg.sender);\n }\n\n /// @inheritdoc IFastBridge\n function refund(bytes memory request) external {\n bytes32 transactionId = keccak256(request);\n\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n\n if (bridgeTxDetails[transactionId].status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n\n if (hasRole(REFUNDER_ROLE, msg.sender)) {\n // Refunder can refund if deadline has passed\n if (block.timestamp \u003c= transaction.deadline) revert DeadlineNotExceeded();\n } else {\n // Permissionless refund is allowed after REFUND_DELAY\n if (block.timestamp \u003c= transaction.deadline + REFUND_DELAY) revert DeadlineNotExceeded();\n }\n\n // if all checks passed, set to REFUNDED status\n bridgeTxDetails[transactionId].status = BridgeStatus.REFUNDED;\n\n // transfer origin collateral back to original sender\n address to = transaction.originSender;\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount + transaction.originFeeAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (bridgeTxDetails[transactionId].proofRelayer != relayer) revert SenderIncorrect();\n return _timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n /// @dev This method is added to achieve backwards compatibility with decoding requests into V1 structs:\n /// - `callValue` is partially reported as a zero/non-zero flag\n /// - `callParams` is ignored\n /// In order to process all kinds of requests use getBridgeTransactionV2 instead.\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory) {\n // Try decoding into V2 struct first. This will revert if V1 struct is passed\n try this.getBridgeTransactionV2(request) returns (BridgeTransactionV2 memory txV2) {\n // Note: we entirely ignore the callParams field, as it was not present in V1\n return BridgeTransaction({\n originChainId: txV2.originChainId,\n destChainId: txV2.destChainId,\n originSender: txV2.originSender,\n destRecipient: txV2.destRecipient,\n originToken: txV2.originToken,\n destToken: txV2.destToken,\n originAmount: txV2.originAmount,\n destAmount: txV2.destAmount,\n originFeeAmount: txV2.originFeeAmount,\n sendChainGas: txV2.callValue != 0,\n deadline: txV2.deadline,\n nonce: txV2.nonce\n });\n } catch {\n // Fallback to V1 struct\n return abi.decode(request, (BridgeTransaction));\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) public payable {\n int256 exclusivityEndTime = int256(block.timestamp) + paramsV2.quoteExclusivitySeconds;\n _validateBridgeParams(params, paramsV2, exclusivityEndTime);\n\n // transfer tokens to bridge contract\n /// @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _pullToken(params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n\n // set status to requested\n bytes memory request = abi.encode(\n BridgeTransactionV2({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n callValue: paramsV2.callValue,\n deadline: params.deadline,\n nonce: senderNonces[params.sender]++, // increment nonce on every bridge\n exclusivityRelayer: paramsV2.quoteRelayer,\n // We checked exclusivityEndTime to be in range (0 .. params.deadline] above, so can safely cast\n exclusivityEndTime: uint256(exclusivityEndTime),\n callParams: paramsV2.callParams\n })\n );\n bytes32 transactionId = keccak256(request);\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n\n emit BridgeRequested({\n transactionId: transactionId,\n sender: params.sender,\n request: request,\n destChainId: params.dstChainId,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n sendChainGas: paramsV2.callValue != 0\n });\n emit BridgeQuoteDetails(transactionId, paramsV2.quoteId);\n }\n\n /// @inheritdoc IFastBridgeV2\n function relay(bytes memory request, address relayer) public payable {\n bytes32 transactionId = keccak256(request);\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n _validateRelayParams(transaction, transactionId, relayer);\n // mark bridge transaction as relayed\n bridgeRelayDetails[transactionId] =\n BridgeRelay({blockNumber: uint48(block.number), blockTimestamp: uint48(block.timestamp), relayer: relayer});\n\n // transfer tokens to recipient on destination chain and do an arbitrary call if requested\n address to = transaction.destRecipient;\n address token = transaction.destToken;\n uint256 amount = transaction.destAmount;\n\n // All state changes have been done at this point, can proceed to the external calls.\n // This follows the checks-effects-interactions pattern to mitigate potential reentrancy attacks.\n if (token == UniversalTokenLib.ETH_ADDRESS) {\n // For ETH non-zero callValue is not allowed\n if (transaction.callValue != 0) revert NativeTokenCallValueNotSupported();\n // Check that the correct msg.value was sent\n if (msg.value != amount) revert MsgValueIncorrect();\n } else {\n // For ERC20s, we check that the correct msg.value was sent\n if (msg.value != transaction.callValue) revert MsgValueIncorrect();\n // We need to transfer the tokens from the Relayer to the recipient first before performing an\n // optional post-transfer arbitrary call.\n IERC20(token).safeTransferFrom(msg.sender, to, amount);\n }\n\n if (transaction.callParams.length != 0) {\n // Arbitrary call requested, perform it while supplying full msg.value to the recipient\n // Note: if token has a fee on transfers, the recipient will have received less than `amount`.\n // This is a very niche edge case and should be handled by the recipient contract.\n _checkedCallRecipient({recipient: to, token: token, amount: amount, callParams: transaction.callParams});\n } else if (msg.value != 0) {\n // No arbitrary call requested, but msg.value was sent. This is either a relay with ETH,\n // or a non-zero callValue request with an ERC20. In both cases, transfer the ETH to the recipient.\n Address.sendValue(payable(to), msg.value);\n }\n\n emit BridgeRelayed({\n transactionId: transactionId,\n relayer: relayer,\n to: to,\n originChainId: transaction.originChainId,\n originToken: transaction.originToken,\n destToken: transaction.destToken,\n originAmount: transaction.originAmount,\n destAmount: transaction.destAmount,\n chainGasAmount: transaction.callValue\n });\n }\n\n /// @inheritdoc IFastBridgeV2\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) public onlyRole(RELAYER_ROLE) {\n // update bridge tx status given proof provided\n if (bridgeTxDetails[transactionId].status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n bridgeTxDetails[transactionId].status = BridgeStatus.RELAYER_PROVED;\n bridgeTxDetails[transactionId].proofBlockTimestamp = uint40(block.timestamp);\n bridgeTxDetails[transactionId].proofBlockNumber = uint48(block.number);\n bridgeTxDetails[transactionId].proofRelayer = relayer;\n\n emit BridgeProofProvided(transactionId, relayer, destTxHash);\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes memory request, address to) public {\n bytes32 transactionId = keccak256(request);\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n\n // update bridge tx status if able to claim origin collateral\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n\n // if \"to\" is zero addr, permissionlessly send funds to proven relayer\n if (to == address(0)) {\n to = bridgeTxDetails[transactionId].proofRelayer;\n } else if (bridgeTxDetails[transactionId].proofRelayer != msg.sender) {\n revert SenderIncorrect();\n }\n\n if (_timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003c= DISPUTE_PERIOD) {\n revert DisputePeriodNotPassed();\n }\n\n bridgeTxDetails[transactionId].status = BridgeStatus.RELAYER_CLAIMED;\n\n // update protocol fees if origin fee amount exists\n if (transaction.originFeeAmount \u003e 0) protocolFees[transaction.originToken] += transaction.originFeeAmount;\n\n // transfer origin collateral less fee to specified address\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositClaimed(transactionId, bridgeTxDetails[transactionId].proofRelayer, to, token, amount);\n }\n\n function bridgeStatuses(bytes32 transactionId) public view returns (BridgeStatus status) {\n return bridgeTxDetails[transactionId].status;\n }\n\n function bridgeProofs(bytes32 transactionId) public view returns (uint96 timestamp, address relayer) {\n timestamp = bridgeTxDetails[transactionId].proofBlockTimestamp;\n relayer = bridgeTxDetails[transactionId].proofRelayer;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeRelays(bytes32 transactionId) public view returns (bool) {\n // has this transactionId been relayed?\n return bridgeRelayDetails[transactionId].relayer != address(0);\n }\n\n /// @inheritdoc IFastBridgeV2\n function getBridgeTransactionV2(bytes memory request) public pure returns (BridgeTransactionV2 memory) {\n return abi.decode(request, (BridgeTransactionV2));\n }\n\n /// @notice Pulls a requested token from the user to this contract.\n function _pullToken(address token, uint256 amount) internal returns (uint256 amountPulled) {\n if (token == UniversalTokenLib.ETH_ADDRESS) {\n // For ETH we just need to check that the supplied msg.value is correct\n if (amount != msg.value) revert MsgValueIncorrect();\n amountPulled = msg.value;\n } else {\n token.assertIsContract();\n // Record token balance before transfer\n amountPulled = IERC20(token).balanceOf(address(this));\n // Token needs to be pulled only if msg.value is zero\n // This way user can specify WETH as the origin asset\n IERC20(token).safeTransferFrom(msg.sender, address(this), amount);\n // Use the difference between the recorded balance and the current balance as the amountPulled\n amountPulled = IERC20(token).balanceOf(address(this)) - amountPulled;\n }\n }\n\n /// @notice Calls the Recipient's hook function with the specified callParams and performs\n /// all the necessary checks for the returned value.\n function _checkedCallRecipient(\n address recipient,\n address token,\n uint256 amount,\n bytes memory callParams\n )\n internal\n {\n bytes memory hookData =\n abi.encodeCall(IFastBridgeRecipient.fastBridgeTransferReceived, (token, amount, callParams));\n // This will bubble any revert messages from the hook function\n bytes memory returnData = Address.functionCallWithValue({target: recipient, data: hookData, value: msg.value});\n // Explicit revert if no return data at all\n if (returnData.length == 0) revert RecipientNoReturnValue();\n // Check that exactly a single return value was returned\n if (returnData.length != 32) revert RecipientIncorrectReturnValue();\n // Return value should be abi-encoded hook function selector\n if (bytes32(returnData) != bytes32(IFastBridgeRecipient.fastBridgeTransferReceived.selector)) {\n revert RecipientIncorrectReturnValue();\n }\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint40(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint40).max but\n /// proof.timestamp \u003c type(uint40).max via unchecked statement\n /// @param proofBlockTimestamp The bridge proof block timestamp\n /// @return delta Time delta since proof submitted\n function _timeSince(uint40 proofBlockTimestamp) internal view returns (uint256 delta) {\n unchecked {\n delta = uint40(block.timestamp) - proofBlockTimestamp;\n }\n }\n\n /// @notice Performs all the necessary checks for a bridge to happen.\n /// @dev There's no good way to refactor this function to reduce cyclomatic complexity due to\n /// the number of checks that need to be performed, so we skip the code-complexity rule here.\n // solhint-disable-next-line code-complexity\n function _validateBridgeParams(\n BridgeParams memory params,\n BridgeParamsV2 memory paramsV2,\n int256 exclusivityEndTime\n )\n internal\n view\n {\n // Check V1 (legacy) params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.sender == address(0) || params.to == address(0)) revert ZeroAddress();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n // Check V2 params\n if (paramsV2.callParams.length \u003e MAX_CALL_PARAMS_LENGTH) revert CallParamsLengthAboveMax();\n if (paramsV2.callValue != 0 \u0026\u0026 params.destToken == UniversalTokenLib.ETH_ADDRESS) {\n revert NativeTokenCallValueNotSupported();\n }\n // exclusivityEndTime must be in range (0 .. params.deadline]\n if (exclusivityEndTime \u003c= 0 || exclusivityEndTime \u003e int256(params.deadline)) {\n revert ExclusivityParamsIncorrect();\n }\n }\n\n /// @notice Performs all the necessary checks for a relay to happen.\n function _validateRelayParams(\n BridgeTransactionV2 memory transaction,\n bytes32 transactionId,\n address relayer\n )\n internal\n view\n {\n if (relayer == address(0)) revert ZeroAddress();\n // Check if the transaction has already been relayed\n if (bridgeRelays(transactionId)) revert TransactionRelayed();\n if (transaction.destChainId != uint32(block.chainid)) revert ChainIncorrect();\n // Check the deadline for relay to happen\n if (block.timestamp \u003e transaction.deadline) revert DeadlineExceeded();\n // Check the exclusivity period, if it is still ongoing\n // forgefmt: disable-next-item\n if (\n transaction.exclusivityRelayer != address(0) \u0026\u0026\n transaction.exclusivityRelayer != relayer \u0026\u0026\n block.timestamp \u003c= transaction.exclusivityEndTime\n ) {\n revert ExclusivityPeriodNotPassed();\n }\n }\n}\n","language":"Solidity","languageVersion":"0.8.24","compilerVersion":"0.8.24","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../","srcMap":"62810:1843:0:-:0;;;63637:83;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;63675:38;52847:4;63706:6;63675:10;:38::i;:::-;;63637:83;62810:1843;;62160:257;62246:4;;62277:31;62294:4;62300:7;62277:16;:31::i;:::-;62262:46;;62322:7;62318:69;;;62345:18;;;;:12;:18;;;;;:31;;62368:7;62345:22;:31::i;:::-;;62318:69;62403:7;-1:-1:-1;62160:257:0;;;;;:::o;56794:316::-;56871:4;53569:12;;;;;;;;;;;-1:-1:-1;;;;;53569:29:0;;;;;;;;;;;;56887:217;;56930:6;:12;;;;;;;;;;;-1:-1:-1;;;;;56930:29:0;;;;;;;;;:36;;-1:-1:-1;;56930:36:0;56962:4;56930:36;;;57012:12;23368:10;;23289:96;57012:12;-1:-1:-1;;;;;56985:40:0;57003:7;-1:-1:-1;;;;;56985:40:0;56997:4;56985:40;;;;;;;;;;-1:-1:-1;57046:4:0;57039:11;;56887:217;-1:-1:-1;57088:5:0;57081:12;;32813:150;32883:4;32906:50;32911:3;-1:-1:-1;;;;;32931:23:0;;26801:4;28857:21;;;:14;;;:21;;;;;;26817:321;;-1:-1:-1;26859:23:0;;;;;;;;:11;:23;;;;;;;;;;;;;27041:18;;27017:21;;;:14;;;:21;;;;;;:42;;;;27073:11;;14:290:1;84:6;137:2;125:9;116:7;112:23;108:32;105:52;;;153:1;150;143:12;105:52;179:16;;-1:-1:-1;;;;;224:31:1;;214:42;;204:70;;270:1;267;260:12;14:290;62810:1843:0;;;;;;","srcMapRuntime":"62810:1843:0:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;60820:212;;;;;;:::i;:::-;;:::i;:::-;;;516:14:1;;509:22;491:41;;479:2;464:18;60820:212:0;;;;;;;;63050:60;;63087:23;63050:60;;;;;689:25:1;;;677:2;662:18;63050:60:0;543:177:1;64022:359:0;;;;;;:::i;:::-;;:::i;:::-;;63232:45;;63271:6;63232:45;;54425:120;;;;;;:::i;:::-;54490:7;54516:12;;;;;;;;;;:22;;;;54425:120;54841:136;;;;;;:::i;:::-;;:::i;55943:245::-;;;;;;:::i;:::-;;:::i;63394:30::-;;;;;;62978:66;;63018:26;62978:66;;61617:142;;;;;;:::i;:::-;;:::i;:::-;;;2246:42:1;2234:55;;;2216:74;;2204:2;2189:18;61617:142:0;2070:226:1;53469:136:0;;;;;;:::i;:::-;53546:4;53569:12;;;;;;;;;;;:29;;;;;;;;;;;;;;;;53469:136;62908:64;;62947:25;62908:64;;52802:49;;52847:4;52802:49;;63726:290;;;;;;:::i;:::-;;:::i;64387:264::-;;;;;;:::i;:::-;;:::i;63189:37::-;;63223:3;63189:37;;61927:131;;;;;;:::i;:::-;;:::i;63116:66::-;;63156:26;63116:66;;55257:138;;;;;;:::i;:::-;;:::i;63480:47::-;;;;;;:::i;:::-;;;;;;;;;;;;;;63601:29;;;;;;60820:212;60905:4;60928:57;;;60943:42;60928:57;;:97;;;60989:36;61013:11;60989:23;:36::i;:::-;60921:104;60820:212;-1:-1:-1;;60820:212:0:o;64022:359::-;63156:26;53079:16;53090:4;53079:10;:16::i;:::-;64146:19:::1;::::0;::::1;64126:17;64146:19:::0;;;:12:::1;:19;::::0;;;;;;64179:14;;;64175:27:::1;;64195:7;64022:359:::0;;;:::o;64175:27::-:1;64243:19;::::0;::::1;64265:1;64243:19:::0;;;:12:::1;:19;::::0;;;;:23;64276:45:::1;::::0;64300:9;64311;64276:23:::1;:45::i;:::-;64336:38;::::0;;2889:42:1;2958:15;;;2940:34;;3010:15;;3005:2;2990:18;;2983:43;3042:18;;;3035:34;;;64336:38:0::1;::::0;2867:2:1;2852:18;64336:38:0::1;;;;;;;64116:265;53105:1;64022:359:::0;;;:::o;54841:136::-;54490:7;54516:12;;;;;;;;;;:22;;;53079:16;53090:4;53079:10;:16::i;:::-;54945:25:::1;54956:4;54962:7;54945:10;:25::i;:::-;;54841:136:::0;;;:::o;55943:245::-;56036:34;;;23368:10;56036:34;56032:102;;56093:30;;;;;;;;;;;;;;56032:102;56144:37;56156:4;56162:18;56144:11;:37::i;61617:142::-;61698:7;61724:18;;;:12;:18;;;;;:28;;61746:5;61724:21;:28::i;:::-;61717:35;61617:142;-1:-1:-1;;;61617:142:0:o;63726:290::-;63156:26;53079:16;53090:4;53079:10;:16::i;:::-;63271:6:::1;63825:10;:26;;63817:55;;;::::0;::::1;::::0;;3282:2:1;63817:55:0::1;::::0;::::1;3264:21:1::0;3321:2;3301:18;;;3294:30;3360:18;3340;;;3333:46;3396:18;;63817:55:0::1;;;;;;;;;63903:15;::::0;;63928:28;;;;63971:38:::1;::::0;;3599:25:1;;;3655:2;3640:18;;3633:34;;;63971:38:0::1;::::0;3572:18:1;63971:38:0::1;;;;;;;;63807:209;63726:290:::0;;:::o;64387:264::-;63156:26;53079:16;53090:4;53079:10;:16::i;:::-;64512:14:::1;::::0;;64536:34;;;;64585:59:::1;::::0;;3599:25:1;;;3655:2;3640:18;;3633:34;;;64585:59:0::1;::::0;3572:18:1;64585:59:0::1;3425:248:1::0;61927:131:0;61998:7;62024:18;;;:12;:18;;;;;:27;;:25;:27::i;55257:138::-;54490:7;54516:12;;;;;;;;;;:22;;;53079:16;53090:4;53079:10;:16::i;:::-;55362:26:::1;55374:4;55380:7;55362:11;:26::i;53180:202::-:0;53265:4;53288:47;;;53303:32;53288:47;;:87;;-1:-1:-1;45095:25:0;45080:40;;;;53339:36;44981:146;53814:103;53880:30;53891:4;23368:10;53880;:30::i;:::-;53814:103;:::o;58092:653::-;58267:4;58253:19;;;;58249:32;;58092:653;;;:::o;58249:32::-;58353:5;58362:1;58353:10;58349:23;;58092:653;;;:::o;58349:23::-;58385:20;;;;;58381:358;;58565:12;58582:2;:7;;58597:5;58582:25;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;58564:43;;;58629:7;58621:39;;;;;;;4090:2:1;58621:39:0;;;4072:21:1;4129:2;4109:18;;;4102:30;4168:21;4148:18;;;4141:49;4207:18;;58621:39:0;3888:343:1;58381:358:0;58691:37;:26;;;58718:2;58722:5;58691:26;:37::i;62160:257::-;62246:4;62262:12;62277:31;62294:4;62300:7;62277:16;:31::i;:::-;62262:46;;62322:7;62318:69;;;62345:18;;;;:12;:18;;;;;:31;;62368:7;62345:22;:31::i;:::-;;62403:7;62160:257;-1:-1:-1;;;62160:257:0:o;62520:262::-;62607:4;62623:12;62638:32;62656:4;62662:7;62638:17;:32::i;:::-;62623:47;;62684:7;62680:72;;;62707:18;;;;:12;:18;;;;;:34;;62733:7;62707:25;:34::i;34071:156::-;34145:7;34195:22;34199:3;34211:5;34195:3;:22::i;33614:115::-;33677:7;33703:19;33711:3;29053:18;;28971:107;54047:197;53546:4;53569:12;;;;;;;;;;;:29;;;;;;;;;;;;;54130:108;;54180:47;;;;;4440:42:1;4428:55;;54180:47:0;;;4410:74:1;4500:18;;;4493:34;;;4383:18;;54180:47:0;4236:297:1;54130:108:0;54047:197;;:::o;46297:160::-;46406:43;;;46421:14;4428:55:1;;46406:43:0;;;4410:74:1;4500:18;;;;4493:34;;;46406:43:0;;;;;;;;;;4383:18:1;;;;46406:43:0;;;;;;;;;;;;;;46379:71;;46399:5;;46379:19;:71::i;56794:316::-;56871:4;53569:12;;;;;;;;;;;:29;;;;;;;;;;;;;56887:217;;56930:6;:12;;;;;;;;;;;:29;;;;;;;;;;:36;;;;56962:4;56930:36;;;57012:12;23368:10;;23289:96;57012:12;56985:40;;57003:7;56985:40;;56997:4;56985:40;;;;;;;;;;-1:-1:-1;57046:4:0;57039:11;;56887:217;-1:-1:-1;57088:5:0;57081:12;;32813:150;32883:4;32906:50;32911:3;32931:23;;;32906:4;:50::i;57345:317::-;57423:4;53569:12;;;;;;;;;;;:29;;;;;;;;;;;;;57439:217;;;57513:5;57481:12;;;;;;;;;;;:29;;;;;;;;;;;:37;;;;;;57537:40;23368:10;;57481:12;;57537:40;;57513:5;57537:40;-1:-1:-1;57598:4:0;57591:11;;33131:156;33204:4;33227:53;33235:3;33255:23;;;33227:7;:53::i;29420:118::-;29487:7;29513:3;:11;;29525:5;29513:18;;;;;;;;:::i;:::-;;;;;;;;;29506:25;;29420:118;;;;:::o;49053:629::-;49472:23;49498:33;:27;;;49526:4;49498:27;:33::i;:::-;49472:59;;49545:10;:17;49566:1;49545:22;;:57;;;;;49583:10;49572:30;;;;;;;;;;;;:::i;:::-;49571:31;49545:57;49541:135;;;49625:40;;;;;2246:42:1;2234:55;;49625:40:0;;;2216:74:1;2189:18;;49625:40:0;2070:226:1;26738:406:0;26801:4;28857:21;;;:14;;;:21;;;;;;26817:321;;-1:-1:-1;26859:23:0;;;;;;;;:11;:23;;;;;;;;;;;;;27041:18;;27017:21;;;:14;;;:21;;;;;;:42;;;;27073:11;;27312:1368;27378:4;27507:21;;;:14;;;:21;;;;;;27543:13;;27539:1135;;27910:18;27931:12;27942:1;27931:8;:12;:::i;:::-;27977:18;;27910:33;;-1:-1:-1;27957:17:0;;27977:22;;27998:1;;27977:22;:::i;:::-;27957:42;;28032:9;28018:10;:23;28014:378;;28061:17;28081:3;:11;;28093:9;28081:22;;;;;;;;:::i;:::-;;;;;;;;;28061:42;;28228:9;28202:3;:11;;28214:10;28202:23;;;;;;;;:::i;:::-;;;;;;;;;;;;:35;;;;28341:25;;;:14;;;:25;;;;;:36;;;28014:378;28470:17;;:3;;:17;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;28573:3;:14;;:21;28588:5;28573:21;;;;;;;;;;;28566:28;;;28616:4;28609:11;;;;;;;27539:1135;28658:5;28651:12;;;;;19074:151;19149:12;19180:38;19202:6;19210:4;19216:1;19149:12;19790;19804:23;19831:6;:11;;19850:5;19857:4;19831:31;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;19789:73;;;;19879:55;19906:6;19914:7;19923:10;19879:26;:55::i;:::-;19872:62;19549:392;-1:-1:-1;;;;;;19549:392:0:o;20994:582::-;21138:12;21167:7;21162:408;;21190:19;21198:10;21190:7;:19::i;:::-;21162:408;;;21414:17;;:22;:49;;;;-1:-1:-1;21440:18:0;;;;:23;21414:49;21410:119;;;21490:24;;;;;2246:42:1;2234:55;;21490:24:0;;;2216:74:1;2189:18;;21490:24:0;2070:226:1;21410:119:0;-1:-1:-1;21549:10:0;21542:17;;22112:516;22243:17;;:21;22239:383;;22471:10;22465:17;22527:15;22514:10;22510:2;22506:19;22499:44;22239:383;22594:17;;;;;;;;;;;;;;14:332:1;72:6;125:2;113:9;104:7;100:23;96:32;93:52;;;141:1;138;131:12;93:52;180:9;167:23;230:66;223:5;219:78;212:5;209:89;199:117;;312:1;309;302:12;725:196;793:20;;853:42;842:54;;832:65;;822:93;;911:1;908;901:12;822:93;725:196;;;:::o;926:260::-;994:6;1002;1055:2;1043:9;1034:7;1030:23;1026:32;1023:52;;;1071:1;1068;1061:12;1023:52;1094:29;1113:9;1094:29;:::i;:::-;1084:39;;1142:38;1176:2;1165:9;1161:18;1142:38;:::i;:::-;1132:48;;926:260;;;;;:::o;1373:180::-;1432:6;1485:2;1473:9;1464:7;1460:23;1456:32;1453:52;;;1501:1;1498;1491:12;1453:52;-1:-1:-1;1524:23:1;;1373:180;-1:-1:-1;1373:180:1:o;1558:254::-;1626:6;1634;1687:2;1675:9;1666:7;1662:23;1658:32;1655:52;;;1703:1;1700;1693:12;1655:52;1739:9;1726:23;1716:33;;1768:38;1802:2;1791:9;1787:18;1768:38;:::i;1817:248::-;1885:6;1893;1946:2;1934:9;1925:7;1921:23;1917:32;1914:52;;;1962:1;1959;1952:12;1914:52;-1:-1:-1;;1985:23:1;;;2055:2;2040:18;;;2027:32;;-1:-1:-1;1817:248:1:o;2486:186::-;2545:6;2598:2;2586:9;2577:7;2573:23;2569:32;2566:52;;;2614:1;2611;2604:12;2566:52;2637:29;2656:9;2637:29;:::i;4840:184::-;4892:77;4889:1;4882:88;4989:4;4986:1;4979:15;5013:4;5010:1;5003:15;5029:277;5096:6;5149:2;5137:9;5128:7;5124:23;5120:32;5117:52;;;5165:1;5162;5155:12;5117:52;5197:9;5191:16;5250:5;5243:13;5236:21;5229:5;5226:32;5216:60;;5272:1;5269;5262:12;5311:282;5378:9;;;5399:11;;;5396:191;;;5443:77;5440:1;5433:88;5544:4;5541:1;5534:15;5572:4;5569:1;5562:15;5598:184;5650:77;5647:1;5640:88;5747:4;5744:1;5737:15;5771:4;5768:1;5761:15;5787:412;5916:3;5954:6;5948:13;5979:1;5989:129;6003:6;6000:1;5997:13;5989:129;;;6101:4;6085:14;;;6081:25;;6075:32;6062:11;;;6055:53;6018:12;5989:129;;;-1:-1:-1;6173:1:1;6137:16;;6162:13;;;-1:-1:-1;6137:16:1;5787:412;-1:-1:-1;5787:412:1:o","abiDefinition":[{"inputs":[{"internalType":"address","name":"_owner","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AccessControlBadConfirmation","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"bytes32","name":"neededRole","type":"bytes32"}],"name":"AccessControlUnauthorizedAccount","type":"error"},{"inputs":[{"internalType":"address","name":"target","type":"address"}],"name":"AddressEmptyCode","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"AddressInsufficientBalance","type":"error"},{"inputs":[],"name":"FailedInnerCall","type":"error"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"SafeERC20FailedOperation","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldChainGasAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newChainGasAmount","type":"uint256"}],"name":"ChainGasAmountUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldFeeRate","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newFeeRate","type":"uint256"}],"name":"FeeRateUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"address","name":"recipient","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"FeesSwept","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"previousAdminRole","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"newAdminRole","type":"bytes32"}],"name":"RoleAdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleRevoked","type":"event"},{"inputs":[],"name":"DEFAULT_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"FEE_BPS","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"FEE_RATE_MAX","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"GOVERNOR_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"GUARD_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"REFUNDER_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"RELAYER_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"chainGasAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleAdmin","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"uint256","name":"index","type":"uint256"}],"name":"getRoleMember","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleMemberCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"grantRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"hasRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"protocolFeeRate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"protocolFees","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"callerConfirmation","type":"address"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"revokeRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"newChainGasAmount","type":"uint256"}],"name":"setChainGasAmount","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"newFeeRate","type":"uint256"}],"name":"setProtocolFeeRate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"address","name":"recipient","type":"address"}],"name":"sweepProtocolFees","outputs":[],"stateMutability":"nonpayable","type":"function"}],"userDoc":{"kind":"user","methods":{"chainGasAmount()":{"notice":"Chain gas amount to forward as rebate if requested"},"protocolFeeRate()":{"notice":"Protocol fee rate taken on origin amount deposited in origin chain"},"protocolFees(address)":{"notice":"Protocol fee amounts accumulated"}},"version":1},"developerDoc":{"errors":{"AccessControlBadConfirmation()":[{"details":"The caller of a function is not the expected one. NOTE: Don't confuse with {AccessControlUnauthorizedAccount}."}],"AccessControlUnauthorizedAccount(address,bytes32)":[{"details":"The `account` is missing a role."}],"AddressEmptyCode(address)":[{"details":"There's no code at `target` (it is not a contract)."}],"AddressInsufficientBalance(address)":[{"details":"The ETH balance of the account is not enough to perform the operation."}],"FailedInnerCall()":[{"details":"A call to an address target failed. The target may have reverted."}],"SafeERC20FailedOperation(address)":[{"details":"An operation with an ERC20 token failed."}]},"events":{"RoleAdminChanged(bytes32,bytes32,bytes32)":{"details":"Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole` `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite {RoleAdminChanged} not being emitted signaling this."},"RoleGranted(bytes32,address,address)":{"details":"Emitted when `account` is granted `role`. `sender` is the account that originated the contract call, an admin role bearer except when using {AccessControl-_setupRole}."},"RoleRevoked(bytes32,address,address)":{"details":"Emitted when `account` is revoked `role`. `sender` is the account that originated the contract call: - if using `revokeRole`, it is the admin role bearer - if using `renounceRole`, it is the role bearer (i.e. `account`)"}},"kind":"dev","methods":{"getRoleAdmin(bytes32)":{"details":"Returns the admin role that controls `role`. See {grantRole} and {revokeRole}. To change a role's admin, use {_setRoleAdmin}."},"getRoleMember(bytes32,uint256)":{"details":"Returns one of the accounts that have `role`. `index` must be a value between 0 and {getRoleMemberCount}, non-inclusive. Role bearers are not sorted in any particular way, and their ordering may change at any point. WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure you perform all queries on the same block. See the following https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post] for more information."},"getRoleMemberCount(bytes32)":{"details":"Returns the number of accounts that have `role`. Can be used together with {getRoleMember} to enumerate all bearers of a role."},"grantRole(bytes32,address)":{"details":"Grants `role` to `account`. If `account` had not been already granted `role`, emits a {RoleGranted} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleGranted} event."},"hasRole(bytes32,address)":{"details":"Returns `true` if `account` has been granted `role`."},"renounceRole(bytes32,address)":{"details":"Revokes `role` from the calling account. Roles are often managed via {grantRole} and {revokeRole}: this function's purpose is to provide a mechanism for accounts to lose their privileges if they are compromised (such as when a trusted device is misplaced). If the calling account had been revoked `role`, emits a {RoleRevoked} event. Requirements: - the caller must be `callerConfirmation`. May emit a {RoleRevoked} event."},"revokeRole(bytes32,address)":{"details":"Revokes `role` from `account`. If `account` had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleRevoked} event."},"supportsInterface(bytes4)":{"details":"See {IERC165-supportsInterface}."}},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_owner\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"AccessControlBadConfirmation\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"neededRole\",\"type\":\"bytes32\"}],\"name\":\"AccessControlUnauthorizedAccount\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"}],\"name\":\"AddressEmptyCode\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"AddressInsufficientBalance\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"FailedInnerCall\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"}],\"name\":\"SafeERC20FailedOperation\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"oldChainGasAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newChainGasAmount\",\"type\":\"uint256\"}],\"name\":\"ChainGasAmountUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"oldFeeRate\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newFeeRate\",\"type\":\"uint256\"}],\"name\":\"FeeRateUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"FeesSwept\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"previousAdminRole\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"newAdminRole\",\"type\":\"bytes32\"}],\"name\":\"RoleAdminChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleGranted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleRevoked\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"DEFAULT_ADMIN_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"FEE_BPS\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"FEE_RATE_MAX\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"GOVERNOR_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"GUARD_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"REFUNDER_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"RELAYER_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"chainGasAmount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"}],\"name\":\"getRoleAdmin\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"index\",\"type\":\"uint256\"}],\"name\":\"getRoleMember\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"}],\"name\":\"getRoleMemberCount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"grantRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"hasRole\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"protocolFeeRate\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"protocolFees\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"callerConfirmation\",\"type\":\"address\"}],\"name\":\"renounceRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"revokeRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"newChainGasAmount\",\"type\":\"uint256\"}],\"name\":\"setChainGasAmount\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"newFeeRate\",\"type\":\"uint256\"}],\"name\":\"setProtocolFeeRate\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes4\",\"name\":\"interfaceId\",\"type\":\"bytes4\"}],\"name\":\"supportsInterface\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"}],\"name\":\"sweepProtocolFees\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"errors\":{\"AccessControlBadConfirmation()\":[{\"details\":\"The caller of a function is not the expected one. NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\"}],\"AccessControlUnauthorizedAccount(address,bytes32)\":[{\"details\":\"The `account` is missing a role.\"}],\"AddressEmptyCode(address)\":[{\"details\":\"There's no code at `target` (it is not a contract).\"}],\"AddressInsufficientBalance(address)\":[{\"details\":\"The ETH balance of the account is not enough to perform the operation.\"}],\"FailedInnerCall()\":[{\"details\":\"A call to an address target failed. The target may have reverted.\"}],\"SafeERC20FailedOperation(address)\":[{\"details\":\"An operation with an ERC20 token failed.\"}]},\"events\":{\"RoleAdminChanged(bytes32,bytes32,bytes32)\":{\"details\":\"Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole` `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite {RoleAdminChanged} not being emitted signaling this.\"},\"RoleGranted(bytes32,address,address)\":{\"details\":\"Emitted when `account` is granted `role`. `sender` is the account that originated the contract call, an admin role bearer except when using {AccessControl-_setupRole}.\"},\"RoleRevoked(bytes32,address,address)\":{\"details\":\"Emitted when `account` is revoked `role`. `sender` is the account that originated the contract call: - if using `revokeRole`, it is the admin role bearer - if using `renounceRole`, it is the role bearer (i.e. `account`)\"}},\"kind\":\"dev\",\"methods\":{\"getRoleAdmin(bytes32)\":{\"details\":\"Returns the admin role that controls `role`. See {grantRole} and {revokeRole}. To change a role's admin, use {_setRoleAdmin}.\"},\"getRoleMember(bytes32,uint256)\":{\"details\":\"Returns one of the accounts that have `role`. `index` must be a value between 0 and {getRoleMemberCount}, non-inclusive. Role bearers are not sorted in any particular way, and their ordering may change at any point. WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure you perform all queries on the same block. See the following https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post] for more information.\"},\"getRoleMemberCount(bytes32)\":{\"details\":\"Returns the number of accounts that have `role`. Can be used together with {getRoleMember} to enumerate all bearers of a role.\"},\"grantRole(bytes32,address)\":{\"details\":\"Grants `role` to `account`. If `account` had not been already granted `role`, emits a {RoleGranted} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleGranted} event.\"},\"hasRole(bytes32,address)\":{\"details\":\"Returns `true` if `account` has been granted `role`.\"},\"renounceRole(bytes32,address)\":{\"details\":\"Revokes `role` from the calling account. Roles are often managed via {grantRole} and {revokeRole}: this function's purpose is to provide a mechanism for accounts to lose their privileges if they are compromised (such as when a trusted device is misplaced). If the calling account had been revoked `role`, emits a {RoleRevoked} event. Requirements: - the caller must be `callerConfirmation`. May emit a {RoleRevoked} event.\"},\"revokeRole(bytes32,address)\":{\"details\":\"Revokes `role` from `account`. If `account` had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleRevoked} event.\"},\"supportsInterface(bytes4)\":{\"details\":\"See {IERC165-supportsInterface}.\"}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"chainGasAmount()\":{\"notice\":\"Chain gas amount to forward as rebate if requested\"},\"protocolFeeRate()\":{\"notice\":\"Protocol fee rate taken on origin amount deposited in origin chain\"},\"protocolFees(address)\":{\"notice\":\"Protocol fee amounts accumulated\"}},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeV2.sol\":\"Admin\"},\"evmVersion\":\"shanghai\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeV2.sol\":{\"keccak256\":\"0x7cd0f885e80e2bdaa638bc32ae7af7d2e248f99ce4b354c217d0f0f7d7302e0a\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://7ccf28df0bd7b4606986585acd8622ed9b4e81379690061bb66088f0a2270af1\",\"dweb:/ipfs/QmTf7HNdHZkK6vmx8ZgewycQEb72oLD9nPwBpsM5reMstQ\"]}},\"version\":1}"},"hashes":{"DEFAULT_ADMIN_ROLE()":"a217fddf","FEE_BPS()":"bf333f2c","FEE_RATE_MAX()":"0f5f6ed7","GOVERNOR_ROLE()":"ccc57490","GUARD_ROLE()":"03ed0ee5","REFUNDER_ROLE()":"5960ccf2","RELAYER_ROLE()":"926d7d7f","chainGasAmount()":"e00a83e0","getRoleAdmin(bytes32)":"248a9ca3","getRoleMember(bytes32,uint256)":"9010d07c","getRoleMemberCount(bytes32)":"ca15c873","grantRole(bytes32,address)":"2f2ff15d","hasRole(bytes32,address)":"91d14854","protocolFeeRate()":"58f85880","protocolFees(address)":"dcf844a7","renounceRole(bytes32,address)":"36568abe","revokeRole(bytes32,address)":"d547741f","setChainGasAmount(uint256)":"b250fe6b","setProtocolFeeRate(uint256)":"b13aa2d6","supportsInterface(bytes4)":"01ffc9a7","sweepProtocolFees(address,address)":"06f333f2"}},"solidity/FastBridgeV2.sol:Context":{"code":"0x","runtime-code":"0x","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.24 ^0.8.0 ^0.8.20;\n\n// contracts/interfaces/IAdmin.sol\n\ninterface IAdmin {\n // ============ Events ============\n\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n event ChainGasAmountUpdated(uint256 oldChainGasAmount, uint256 newChainGasAmount);\n\n // ============ Methods ============\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n\n function setChainGasAmount(uint256 newChainGasAmount) external;\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IFastBridgeRecipient.sol\n\ninterface IFastBridgeRecipient {\n function fastBridgeTransferReceived(\n address token,\n uint256 amount,\n bytes memory callParams\n )\n external\n payable\n returns (bytes4);\n}\n\n// contracts/interfaces/IFastBridgeV2Errors.sol\n\ninterface IFastBridgeV2Errors {\n error AmountIncorrect();\n error CallParamsLengthAboveMax();\n error ChainIncorrect();\n error ExclusivityParamsIncorrect();\n error MsgValueIncorrect();\n error NativeTokenCallValueNotSupported();\n error SenderIncorrect();\n error StatusIncorrect();\n error ZeroAddress();\n\n error RecipientIncorrectReturnValue();\n error RecipientNoReturnValue();\n\n error DeadlineExceeded();\n error DeadlineNotExceeded();\n error DeadlineTooShort();\n error DisputePeriodNotPassed();\n error DisputePeriodPassed();\n error ExclusivityPeriodNotPassed();\n\n error TransactionRelayed();\n}\n\n// contracts/libs/Errors.sol\n\nerror DeadlineExceeded();\nerror DeadlineNotExceeded();\nerror DeadlineTooShort();\nerror InsufficientOutputAmount();\n\nerror MsgValueIncorrect();\nerror PoolNotFound();\nerror TokenAddressMismatch();\nerror TokenNotContract();\nerror TokenNotETH();\nerror TokensIdentical();\n\nerror ChainIncorrect();\nerror AmountIncorrect();\nerror ZeroAddress();\n\nerror DisputePeriodNotPassed();\nerror DisputePeriodPassed();\nerror SenderIncorrect();\nerror StatusIncorrect();\nerror TransactionIdIncorrect();\nerror TransactionRelayed();\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// contracts/interfaces/IFastBridgeV2.sol\n\ninterface IFastBridgeV2 is IFastBridge {\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n struct BridgeTxDetails {\n BridgeStatus status;\n uint40 proofBlockTimestamp;\n uint48 proofBlockNumber;\n address proofRelayer;\n }\n\n struct BridgeRelay {\n uint48 blockNumber;\n uint48 blockTimestamp;\n address relayer;\n }\n\n /// @notice New params introduced in the FastBridgeV2.\n /// We are passing fields from the older BridgeParams struct outside of this struct\n /// for backwards compatibility.\n /// Note: quoteRelayer and quoteExclusivitySeconds are either both zero (indicating no exclusivity)\n /// or both non-zero (indicating exclusivity for the given period).\n /// Note: callValue \u003e 0 can NOT be used with destToken = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE (ETH_ADDRESS)\n /// @param quoteRelayer Relayer that provided the quote for the transaction\n /// @param quoteExclusivitySeconds Period of time the quote relayer is guaranteed exclusivity after user's deposit\n /// @param quoteId Unique quote identifier used for tracking the quote\n /// @param callValue ETH value to send to the recipient (if any)\n /// @param callParams Parameters for the arbitrary call to the destination recipient (if any)\n struct BridgeParamsV2 {\n address quoteRelayer;\n int256 quoteExclusivitySeconds;\n bytes quoteId;\n uint256 callValue;\n bytes callParams;\n }\n\n /// @notice Updated bridge transaction struct to include parameters introduced in FastBridgeV2.\n /// Note: only `exclusivityRelayer` can fill such a transaction until `exclusivityEndTime`.\n /// TODO: consider changing the encoding scheme to prevent spending extra gas on decoding.\n struct BridgeTransactionV2 {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n uint256 callValue; // ETH value to send to the recipient (if any) - replaces V1's sendChainGas flag\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n address exclusivityRelayer;\n uint256 exclusivityEndTime;\n bytes callParams;\n }\n\n event BridgeQuoteDetails(bytes32 indexed transactionId, bytes quoteId);\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability\n /// to provide temporary exclusivity fill rights for the quote relayer.\n /// @param params The parameters required to bridge\n /// @param paramsV2 The parameters for exclusivity fill rights (optional, can be left empty)\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function relay(bytes memory request, address relayer) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param transactionId The transaction id associated with the encoded bridge transaction to prove\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital.\n /// @notice Can only send funds to the relayer address on the proof.\n /// @param request The encoded bridge transaction to claim on origin chain\n function claim(bytes memory request) external;\n /// @notice Checks if a transaction has been relayed\n /// @param transactionId The ID of the transaction to check\n /// @return True if the transaction has been relayed, false otherwise\n function bridgeRelays(bytes32 transactionId) external view returns (bool);\n\n /// @notice Returns the status of a bridge transaction\n /// @param transactionId The ID of the bridge transaction\n /// @return BridgeStatus Status of the bridge transaction\n function bridgeStatuses(bytes32 transactionId) external view returns (BridgeStatus);\n\n /// @notice Returns the timestamp and relayer of a bridge proof\n /// @param transactionId The ID of the bridge transaction\n /// @return timestamp The timestamp of the bridge proof\n /// @return relayer The relayer address of the bridge proof\n function bridgeProofs(bytes32 transactionId) external view returns (uint96 timestamp, address relayer);\n\n /// @notice Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\n /// @param request The bridge request to decode\n function getBridgeTransactionV2(bytes memory request) external view returns (BridgeTransactionV2 memory);\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// contracts/libs/UniversalToken.sol\n\nlibrary UniversalTokenLib {\n using SafeERC20 for IERC20;\n\n address internal constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Transfers tokens to the given account. Reverts if transfer is not successful.\n /// @dev This might trigger fallback, if ETH is transferred to the contract.\n /// Make sure this can not lead to reentrancy attacks.\n function universalTransfer(address token, address to, uint256 value) internal {\n // Don't do anything, if need to send tokens to this address\n if (to == address(this)) return;\n // Don't do anything, if trying to send zero value\n if (value == 0) return;\n if (token == ETH_ADDRESS) {\n /// @dev Note: this can potentially lead to executing code in `to`.\n // solhint-disable-next-line avoid-low-level-calls\n (bool success,) = to.call{value: value}(\"\");\n require(success, \"ETH transfer failed\");\n } else {\n IERC20(token).safeTransfer(to, value);\n }\n }\n\n /// @notice Issues an infinite allowance to the spender, if the current allowance is insufficient\n /// to spend the given amount.\n function universalApproveInfinity(address token, address spender, uint256 amountToSpend) internal {\n // ETH Chad doesn't require your approval\n if (token == ETH_ADDRESS) return;\n // No-op if allowance is already sufficient\n uint256 allowance = IERC20(token).allowance(address(this), spender);\n if (allowance \u003e= amountToSpend) return;\n // Otherwise, reset approval to 0 and set to max allowance\n if (allowance \u003e 0) IERC20(token).safeDecreaseAllowance(spender, allowance);\n IERC20(token).safeIncreaseAllowance(spender, type(uint256).max);\n }\n\n /// @notice Returns the balance of the given token (or native ETH) for the given account.\n function universalBalanceOf(address token, address account) internal view returns (uint256) {\n if (token == ETH_ADDRESS) {\n return account.balance;\n } else {\n return IERC20(token).balanceOf(account);\n }\n }\n\n /// @dev Checks that token is a contract and not ETH_ADDRESS.\n function assertIsContract(address token) internal view {\n // Check that ETH_ADDRESS was not used (in case this is a predeploy on any of the chains)\n if (token == UniversalTokenLib.ETH_ADDRESS) revert TokenNotContract();\n // Check that token is not an EOA\n if (token.code.length == 0) revert TokenNotContract();\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/Admin.sol\n\ncontract Admin is IAdmin, AccessControlEnumerable {\n using UniversalTokenLib for address;\n\n bytes32 public constant RELAYER_ROLE = keccak256(\"RELAYER_ROLE\");\n bytes32 public constant REFUNDER_ROLE = keccak256(\"REFUNDER_ROLE\");\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n uint256 public constant FEE_BPS = 1e6;\n uint256 public constant FEE_RATE_MAX = 0.01e6; // max 1% on origin amount\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Chain gas amount to forward as rebate if requested\n uint256 public chainGasAmount;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n }\n\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n require(newFeeRate \u003c= FEE_RATE_MAX, \"newFeeRate \u003e max\");\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n token.universalTransfer(recipient, feeAmount);\n emit FeesSwept(token, recipient, feeAmount);\n }\n\n function setChainGasAmount(uint256 newChainGasAmount) external onlyRole(GOVERNOR_ROLE) {\n uint256 oldChainGasAmount = chainGasAmount;\n chainGasAmount = newChainGasAmount;\n emit ChainGasAmountUpdated(oldChainGasAmount, newChainGasAmount);\n }\n}\n\n// contracts/FastBridgeV2.sol\n\n/// @notice FastBridgeV2 is a contract for bridging tokens across chains.\ncontract FastBridgeV2 is Admin, IFastBridgeV2, IFastBridgeV2Errors {\n using SafeERC20 for IERC20;\n using UniversalTokenLib for address;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Delay for a transaction after which it could be permisionlessly refunded\n uint256 public constant REFUND_DELAY = 7 days;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n /// @notice Maximum length of accepted callParams\n uint256 public constant MAX_CALL_PARAMS_LENGTH = 2 ** 16 - 1;\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeTxDetails) public bridgeTxDetails;\n /// @notice Relay details on destination chain\n mapping(bytes32 =\u003e BridgeRelay) public bridgeRelayDetails;\n /// @notice Unique bridge nonces tracked per originSender\n mapping(address =\u003e uint256) public senderNonces;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Replaced by senderNonces\n uint256 public immutable nonce = 0;\n /// @notice the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n bridge({\n params: params,\n paramsV2: BridgeParamsV2({\n quoteRelayer: address(0),\n quoteExclusivitySeconds: 0,\n quoteId: bytes(\"\"),\n callValue: 0,\n callParams: bytes(\"\")\n })\n });\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes memory request) external payable {\n relay({request: request, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes memory request, bytes32 destTxHash) external {\n prove({transactionId: keccak256(request), destTxHash: destTxHash, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridgeV2\n function claim(bytes memory request) external {\n claim({request: request, to: address(0)});\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003e DISPUTE_PERIOD) {\n revert DisputePeriodPassed();\n }\n\n // @dev relayer gets slashed effectively if dest relay has gone thru\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n bridgeTxDetails[transactionId].proofRelayer = address(0);\n bridgeTxDetails[transactionId].proofBlockTimestamp = 0;\n bridgeTxDetails[transactionId].proofBlockNumber = 0;\n\n emit BridgeProofDisputed(transactionId, msg.sender);\n }\n\n /// @inheritdoc IFastBridge\n function refund(bytes memory request) external {\n bytes32 transactionId = keccak256(request);\n\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n\n if (bridgeTxDetails[transactionId].status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n\n if (hasRole(REFUNDER_ROLE, msg.sender)) {\n // Refunder can refund if deadline has passed\n if (block.timestamp \u003c= transaction.deadline) revert DeadlineNotExceeded();\n } else {\n // Permissionless refund is allowed after REFUND_DELAY\n if (block.timestamp \u003c= transaction.deadline + REFUND_DELAY) revert DeadlineNotExceeded();\n }\n\n // if all checks passed, set to REFUNDED status\n bridgeTxDetails[transactionId].status = BridgeStatus.REFUNDED;\n\n // transfer origin collateral back to original sender\n address to = transaction.originSender;\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount + transaction.originFeeAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (bridgeTxDetails[transactionId].proofRelayer != relayer) revert SenderIncorrect();\n return _timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n /// @dev This method is added to achieve backwards compatibility with decoding requests into V1 structs:\n /// - `callValue` is partially reported as a zero/non-zero flag\n /// - `callParams` is ignored\n /// In order to process all kinds of requests use getBridgeTransactionV2 instead.\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory) {\n // Try decoding into V2 struct first. This will revert if V1 struct is passed\n try this.getBridgeTransactionV2(request) returns (BridgeTransactionV2 memory txV2) {\n // Note: we entirely ignore the callParams field, as it was not present in V1\n return BridgeTransaction({\n originChainId: txV2.originChainId,\n destChainId: txV2.destChainId,\n originSender: txV2.originSender,\n destRecipient: txV2.destRecipient,\n originToken: txV2.originToken,\n destToken: txV2.destToken,\n originAmount: txV2.originAmount,\n destAmount: txV2.destAmount,\n originFeeAmount: txV2.originFeeAmount,\n sendChainGas: txV2.callValue != 0,\n deadline: txV2.deadline,\n nonce: txV2.nonce\n });\n } catch {\n // Fallback to V1 struct\n return abi.decode(request, (BridgeTransaction));\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) public payable {\n int256 exclusivityEndTime = int256(block.timestamp) + paramsV2.quoteExclusivitySeconds;\n _validateBridgeParams(params, paramsV2, exclusivityEndTime);\n\n // transfer tokens to bridge contract\n /// @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _pullToken(params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n\n // set status to requested\n bytes memory request = abi.encode(\n BridgeTransactionV2({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n callValue: paramsV2.callValue,\n deadline: params.deadline,\n nonce: senderNonces[params.sender]++, // increment nonce on every bridge\n exclusivityRelayer: paramsV2.quoteRelayer,\n // We checked exclusivityEndTime to be in range (0 .. params.deadline] above, so can safely cast\n exclusivityEndTime: uint256(exclusivityEndTime),\n callParams: paramsV2.callParams\n })\n );\n bytes32 transactionId = keccak256(request);\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n\n emit BridgeRequested({\n transactionId: transactionId,\n sender: params.sender,\n request: request,\n destChainId: params.dstChainId,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n sendChainGas: paramsV2.callValue != 0\n });\n emit BridgeQuoteDetails(transactionId, paramsV2.quoteId);\n }\n\n /// @inheritdoc IFastBridgeV2\n function relay(bytes memory request, address relayer) public payable {\n bytes32 transactionId = keccak256(request);\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n _validateRelayParams(transaction, transactionId, relayer);\n // mark bridge transaction as relayed\n bridgeRelayDetails[transactionId] =\n BridgeRelay({blockNumber: uint48(block.number), blockTimestamp: uint48(block.timestamp), relayer: relayer});\n\n // transfer tokens to recipient on destination chain and do an arbitrary call if requested\n address to = transaction.destRecipient;\n address token = transaction.destToken;\n uint256 amount = transaction.destAmount;\n\n // All state changes have been done at this point, can proceed to the external calls.\n // This follows the checks-effects-interactions pattern to mitigate potential reentrancy attacks.\n if (token == UniversalTokenLib.ETH_ADDRESS) {\n // For ETH non-zero callValue is not allowed\n if (transaction.callValue != 0) revert NativeTokenCallValueNotSupported();\n // Check that the correct msg.value was sent\n if (msg.value != amount) revert MsgValueIncorrect();\n } else {\n // For ERC20s, we check that the correct msg.value was sent\n if (msg.value != transaction.callValue) revert MsgValueIncorrect();\n // We need to transfer the tokens from the Relayer to the recipient first before performing an\n // optional post-transfer arbitrary call.\n IERC20(token).safeTransferFrom(msg.sender, to, amount);\n }\n\n if (transaction.callParams.length != 0) {\n // Arbitrary call requested, perform it while supplying full msg.value to the recipient\n // Note: if token has a fee on transfers, the recipient will have received less than `amount`.\n // This is a very niche edge case and should be handled by the recipient contract.\n _checkedCallRecipient({recipient: to, token: token, amount: amount, callParams: transaction.callParams});\n } else if (msg.value != 0) {\n // No arbitrary call requested, but msg.value was sent. This is either a relay with ETH,\n // or a non-zero callValue request with an ERC20. In both cases, transfer the ETH to the recipient.\n Address.sendValue(payable(to), msg.value);\n }\n\n emit BridgeRelayed({\n transactionId: transactionId,\n relayer: relayer,\n to: to,\n originChainId: transaction.originChainId,\n originToken: transaction.originToken,\n destToken: transaction.destToken,\n originAmount: transaction.originAmount,\n destAmount: transaction.destAmount,\n chainGasAmount: transaction.callValue\n });\n }\n\n /// @inheritdoc IFastBridgeV2\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) public onlyRole(RELAYER_ROLE) {\n // update bridge tx status given proof provided\n if (bridgeTxDetails[transactionId].status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n bridgeTxDetails[transactionId].status = BridgeStatus.RELAYER_PROVED;\n bridgeTxDetails[transactionId].proofBlockTimestamp = uint40(block.timestamp);\n bridgeTxDetails[transactionId].proofBlockNumber = uint48(block.number);\n bridgeTxDetails[transactionId].proofRelayer = relayer;\n\n emit BridgeProofProvided(transactionId, relayer, destTxHash);\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes memory request, address to) public {\n bytes32 transactionId = keccak256(request);\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n\n // update bridge tx status if able to claim origin collateral\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n\n // if \"to\" is zero addr, permissionlessly send funds to proven relayer\n if (to == address(0)) {\n to = bridgeTxDetails[transactionId].proofRelayer;\n } else if (bridgeTxDetails[transactionId].proofRelayer != msg.sender) {\n revert SenderIncorrect();\n }\n\n if (_timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003c= DISPUTE_PERIOD) {\n revert DisputePeriodNotPassed();\n }\n\n bridgeTxDetails[transactionId].status = BridgeStatus.RELAYER_CLAIMED;\n\n // update protocol fees if origin fee amount exists\n if (transaction.originFeeAmount \u003e 0) protocolFees[transaction.originToken] += transaction.originFeeAmount;\n\n // transfer origin collateral less fee to specified address\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositClaimed(transactionId, bridgeTxDetails[transactionId].proofRelayer, to, token, amount);\n }\n\n function bridgeStatuses(bytes32 transactionId) public view returns (BridgeStatus status) {\n return bridgeTxDetails[transactionId].status;\n }\n\n function bridgeProofs(bytes32 transactionId) public view returns (uint96 timestamp, address relayer) {\n timestamp = bridgeTxDetails[transactionId].proofBlockTimestamp;\n relayer = bridgeTxDetails[transactionId].proofRelayer;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeRelays(bytes32 transactionId) public view returns (bool) {\n // has this transactionId been relayed?\n return bridgeRelayDetails[transactionId].relayer != address(0);\n }\n\n /// @inheritdoc IFastBridgeV2\n function getBridgeTransactionV2(bytes memory request) public pure returns (BridgeTransactionV2 memory) {\n return abi.decode(request, (BridgeTransactionV2));\n }\n\n /// @notice Pulls a requested token from the user to this contract.\n function _pullToken(address token, uint256 amount) internal returns (uint256 amountPulled) {\n if (token == UniversalTokenLib.ETH_ADDRESS) {\n // For ETH we just need to check that the supplied msg.value is correct\n if (amount != msg.value) revert MsgValueIncorrect();\n amountPulled = msg.value;\n } else {\n token.assertIsContract();\n // Record token balance before transfer\n amountPulled = IERC20(token).balanceOf(address(this));\n // Token needs to be pulled only if msg.value is zero\n // This way user can specify WETH as the origin asset\n IERC20(token).safeTransferFrom(msg.sender, address(this), amount);\n // Use the difference between the recorded balance and the current balance as the amountPulled\n amountPulled = IERC20(token).balanceOf(address(this)) - amountPulled;\n }\n }\n\n /// @notice Calls the Recipient's hook function with the specified callParams and performs\n /// all the necessary checks for the returned value.\n function _checkedCallRecipient(\n address recipient,\n address token,\n uint256 amount,\n bytes memory callParams\n )\n internal\n {\n bytes memory hookData =\n abi.encodeCall(IFastBridgeRecipient.fastBridgeTransferReceived, (token, amount, callParams));\n // This will bubble any revert messages from the hook function\n bytes memory returnData = Address.functionCallWithValue({target: recipient, data: hookData, value: msg.value});\n // Explicit revert if no return data at all\n if (returnData.length == 0) revert RecipientNoReturnValue();\n // Check that exactly a single return value was returned\n if (returnData.length != 32) revert RecipientIncorrectReturnValue();\n // Return value should be abi-encoded hook function selector\n if (bytes32(returnData) != bytes32(IFastBridgeRecipient.fastBridgeTransferReceived.selector)) {\n revert RecipientIncorrectReturnValue();\n }\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint40(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint40).max but\n /// proof.timestamp \u003c type(uint40).max via unchecked statement\n /// @param proofBlockTimestamp The bridge proof block timestamp\n /// @return delta Time delta since proof submitted\n function _timeSince(uint40 proofBlockTimestamp) internal view returns (uint256 delta) {\n unchecked {\n delta = uint40(block.timestamp) - proofBlockTimestamp;\n }\n }\n\n /// @notice Performs all the necessary checks for a bridge to happen.\n /// @dev There's no good way to refactor this function to reduce cyclomatic complexity due to\n /// the number of checks that need to be performed, so we skip the code-complexity rule here.\n // solhint-disable-next-line code-complexity\n function _validateBridgeParams(\n BridgeParams memory params,\n BridgeParamsV2 memory paramsV2,\n int256 exclusivityEndTime\n )\n internal\n view\n {\n // Check V1 (legacy) params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.sender == address(0) || params.to == address(0)) revert ZeroAddress();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n // Check V2 params\n if (paramsV2.callParams.length \u003e MAX_CALL_PARAMS_LENGTH) revert CallParamsLengthAboveMax();\n if (paramsV2.callValue != 0 \u0026\u0026 params.destToken == UniversalTokenLib.ETH_ADDRESS) {\n revert NativeTokenCallValueNotSupported();\n }\n // exclusivityEndTime must be in range (0 .. params.deadline]\n if (exclusivityEndTime \u003c= 0 || exclusivityEndTime \u003e int256(params.deadline)) {\n revert ExclusivityParamsIncorrect();\n }\n }\n\n /// @notice Performs all the necessary checks for a relay to happen.\n function _validateRelayParams(\n BridgeTransactionV2 memory transaction,\n bytes32 transactionId,\n address relayer\n )\n internal\n view\n {\n if (relayer == address(0)) revert ZeroAddress();\n // Check if the transaction has already been relayed\n if (bridgeRelays(transactionId)) revert TransactionRelayed();\n if (transaction.destChainId != uint32(block.chainid)) revert ChainIncorrect();\n // Check the deadline for relay to happen\n if (block.timestamp \u003e transaction.deadline) revert DeadlineExceeded();\n // Check the exclusivity period, if it is still ongoing\n // forgefmt: disable-next-item\n if (\n transaction.exclusivityRelayer != address(0) \u0026\u0026\n transaction.exclusivityRelayer != relayer \u0026\u0026\n block.timestamp \u003c= transaction.exclusivityEndTime\n ) {\n revert ExclusivityPeriodNotPassed();\n }\n }\n}\n","language":"Solidity","languageVersion":"0.8.24","compilerVersion":"0.8.24","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../","srcMap":"","srcMapRuntime":"","abiDefinition":[],"userDoc":{"kind":"user","methods":{},"version":1},"developerDoc":{"details":"Provides information about the current execution context, including the sender of the transaction and its data. While these are generally available via msg.sender and msg.data, they should not be accessed in such a direct manner, since when dealing with meta-transactions the account sending and paying for execution may not be the actual sender (as far as an application is concerned). This contract is only required for intermediate, library-like contracts.","kind":"dev","methods":{},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[],\"devdoc\":{\"details\":\"Provides information about the current execution context, including the sender of the transaction and its data. While these are generally available via msg.sender and msg.data, they should not be accessed in such a direct manner, since when dealing with meta-transactions the account sending and paying for execution may not be the actual sender (as far as an application is concerned). This contract is only required for intermediate, library-like contracts.\",\"kind\":\"dev\",\"methods\":{},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeV2.sol\":\"Context\"},\"evmVersion\":\"shanghai\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeV2.sol\":{\"keccak256\":\"0x7cd0f885e80e2bdaa638bc32ae7af7d2e248f99ce4b354c217d0f0f7d7302e0a\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://7ccf28df0bd7b4606986585acd8622ed9b4e81379690061bb66088f0a2270af1\",\"dweb:/ipfs/QmTf7HNdHZkK6vmx8ZgewycQEb72oLD9nPwBpsM5reMstQ\"]}},\"version\":1}"},"hashes":{}},"solidity/FastBridgeV2.sol:ERC165":{"code":"0x","runtime-code":"0x","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.24 ^0.8.0 ^0.8.20;\n\n// contracts/interfaces/IAdmin.sol\n\ninterface IAdmin {\n // ============ Events ============\n\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n event ChainGasAmountUpdated(uint256 oldChainGasAmount, uint256 newChainGasAmount);\n\n // ============ Methods ============\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n\n function setChainGasAmount(uint256 newChainGasAmount) external;\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IFastBridgeRecipient.sol\n\ninterface IFastBridgeRecipient {\n function fastBridgeTransferReceived(\n address token,\n uint256 amount,\n bytes memory callParams\n )\n external\n payable\n returns (bytes4);\n}\n\n// contracts/interfaces/IFastBridgeV2Errors.sol\n\ninterface IFastBridgeV2Errors {\n error AmountIncorrect();\n error CallParamsLengthAboveMax();\n error ChainIncorrect();\n error ExclusivityParamsIncorrect();\n error MsgValueIncorrect();\n error NativeTokenCallValueNotSupported();\n error SenderIncorrect();\n error StatusIncorrect();\n error ZeroAddress();\n\n error RecipientIncorrectReturnValue();\n error RecipientNoReturnValue();\n\n error DeadlineExceeded();\n error DeadlineNotExceeded();\n error DeadlineTooShort();\n error DisputePeriodNotPassed();\n error DisputePeriodPassed();\n error ExclusivityPeriodNotPassed();\n\n error TransactionRelayed();\n}\n\n// contracts/libs/Errors.sol\n\nerror DeadlineExceeded();\nerror DeadlineNotExceeded();\nerror DeadlineTooShort();\nerror InsufficientOutputAmount();\n\nerror MsgValueIncorrect();\nerror PoolNotFound();\nerror TokenAddressMismatch();\nerror TokenNotContract();\nerror TokenNotETH();\nerror TokensIdentical();\n\nerror ChainIncorrect();\nerror AmountIncorrect();\nerror ZeroAddress();\n\nerror DisputePeriodNotPassed();\nerror DisputePeriodPassed();\nerror SenderIncorrect();\nerror StatusIncorrect();\nerror TransactionIdIncorrect();\nerror TransactionRelayed();\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// contracts/interfaces/IFastBridgeV2.sol\n\ninterface IFastBridgeV2 is IFastBridge {\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n struct BridgeTxDetails {\n BridgeStatus status;\n uint40 proofBlockTimestamp;\n uint48 proofBlockNumber;\n address proofRelayer;\n }\n\n struct BridgeRelay {\n uint48 blockNumber;\n uint48 blockTimestamp;\n address relayer;\n }\n\n /// @notice New params introduced in the FastBridgeV2.\n /// We are passing fields from the older BridgeParams struct outside of this struct\n /// for backwards compatibility.\n /// Note: quoteRelayer and quoteExclusivitySeconds are either both zero (indicating no exclusivity)\n /// or both non-zero (indicating exclusivity for the given period).\n /// Note: callValue \u003e 0 can NOT be used with destToken = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE (ETH_ADDRESS)\n /// @param quoteRelayer Relayer that provided the quote for the transaction\n /// @param quoteExclusivitySeconds Period of time the quote relayer is guaranteed exclusivity after user's deposit\n /// @param quoteId Unique quote identifier used for tracking the quote\n /// @param callValue ETH value to send to the recipient (if any)\n /// @param callParams Parameters for the arbitrary call to the destination recipient (if any)\n struct BridgeParamsV2 {\n address quoteRelayer;\n int256 quoteExclusivitySeconds;\n bytes quoteId;\n uint256 callValue;\n bytes callParams;\n }\n\n /// @notice Updated bridge transaction struct to include parameters introduced in FastBridgeV2.\n /// Note: only `exclusivityRelayer` can fill such a transaction until `exclusivityEndTime`.\n /// TODO: consider changing the encoding scheme to prevent spending extra gas on decoding.\n struct BridgeTransactionV2 {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n uint256 callValue; // ETH value to send to the recipient (if any) - replaces V1's sendChainGas flag\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n address exclusivityRelayer;\n uint256 exclusivityEndTime;\n bytes callParams;\n }\n\n event BridgeQuoteDetails(bytes32 indexed transactionId, bytes quoteId);\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability\n /// to provide temporary exclusivity fill rights for the quote relayer.\n /// @param params The parameters required to bridge\n /// @param paramsV2 The parameters for exclusivity fill rights (optional, can be left empty)\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function relay(bytes memory request, address relayer) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param transactionId The transaction id associated with the encoded bridge transaction to prove\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital.\n /// @notice Can only send funds to the relayer address on the proof.\n /// @param request The encoded bridge transaction to claim on origin chain\n function claim(bytes memory request) external;\n /// @notice Checks if a transaction has been relayed\n /// @param transactionId The ID of the transaction to check\n /// @return True if the transaction has been relayed, false otherwise\n function bridgeRelays(bytes32 transactionId) external view returns (bool);\n\n /// @notice Returns the status of a bridge transaction\n /// @param transactionId The ID of the bridge transaction\n /// @return BridgeStatus Status of the bridge transaction\n function bridgeStatuses(bytes32 transactionId) external view returns (BridgeStatus);\n\n /// @notice Returns the timestamp and relayer of a bridge proof\n /// @param transactionId The ID of the bridge transaction\n /// @return timestamp The timestamp of the bridge proof\n /// @return relayer The relayer address of the bridge proof\n function bridgeProofs(bytes32 transactionId) external view returns (uint96 timestamp, address relayer);\n\n /// @notice Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\n /// @param request The bridge request to decode\n function getBridgeTransactionV2(bytes memory request) external view returns (BridgeTransactionV2 memory);\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// contracts/libs/UniversalToken.sol\n\nlibrary UniversalTokenLib {\n using SafeERC20 for IERC20;\n\n address internal constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Transfers tokens to the given account. Reverts if transfer is not successful.\n /// @dev This might trigger fallback, if ETH is transferred to the contract.\n /// Make sure this can not lead to reentrancy attacks.\n function universalTransfer(address token, address to, uint256 value) internal {\n // Don't do anything, if need to send tokens to this address\n if (to == address(this)) return;\n // Don't do anything, if trying to send zero value\n if (value == 0) return;\n if (token == ETH_ADDRESS) {\n /// @dev Note: this can potentially lead to executing code in `to`.\n // solhint-disable-next-line avoid-low-level-calls\n (bool success,) = to.call{value: value}(\"\");\n require(success, \"ETH transfer failed\");\n } else {\n IERC20(token).safeTransfer(to, value);\n }\n }\n\n /// @notice Issues an infinite allowance to the spender, if the current allowance is insufficient\n /// to spend the given amount.\n function universalApproveInfinity(address token, address spender, uint256 amountToSpend) internal {\n // ETH Chad doesn't require your approval\n if (token == ETH_ADDRESS) return;\n // No-op if allowance is already sufficient\n uint256 allowance = IERC20(token).allowance(address(this), spender);\n if (allowance \u003e= amountToSpend) return;\n // Otherwise, reset approval to 0 and set to max allowance\n if (allowance \u003e 0) IERC20(token).safeDecreaseAllowance(spender, allowance);\n IERC20(token).safeIncreaseAllowance(spender, type(uint256).max);\n }\n\n /// @notice Returns the balance of the given token (or native ETH) for the given account.\n function universalBalanceOf(address token, address account) internal view returns (uint256) {\n if (token == ETH_ADDRESS) {\n return account.balance;\n } else {\n return IERC20(token).balanceOf(account);\n }\n }\n\n /// @dev Checks that token is a contract and not ETH_ADDRESS.\n function assertIsContract(address token) internal view {\n // Check that ETH_ADDRESS was not used (in case this is a predeploy on any of the chains)\n if (token == UniversalTokenLib.ETH_ADDRESS) revert TokenNotContract();\n // Check that token is not an EOA\n if (token.code.length == 0) revert TokenNotContract();\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/Admin.sol\n\ncontract Admin is IAdmin, AccessControlEnumerable {\n using UniversalTokenLib for address;\n\n bytes32 public constant RELAYER_ROLE = keccak256(\"RELAYER_ROLE\");\n bytes32 public constant REFUNDER_ROLE = keccak256(\"REFUNDER_ROLE\");\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n uint256 public constant FEE_BPS = 1e6;\n uint256 public constant FEE_RATE_MAX = 0.01e6; // max 1% on origin amount\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Chain gas amount to forward as rebate if requested\n uint256 public chainGasAmount;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n }\n\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n require(newFeeRate \u003c= FEE_RATE_MAX, \"newFeeRate \u003e max\");\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n token.universalTransfer(recipient, feeAmount);\n emit FeesSwept(token, recipient, feeAmount);\n }\n\n function setChainGasAmount(uint256 newChainGasAmount) external onlyRole(GOVERNOR_ROLE) {\n uint256 oldChainGasAmount = chainGasAmount;\n chainGasAmount = newChainGasAmount;\n emit ChainGasAmountUpdated(oldChainGasAmount, newChainGasAmount);\n }\n}\n\n// contracts/FastBridgeV2.sol\n\n/// @notice FastBridgeV2 is a contract for bridging tokens across chains.\ncontract FastBridgeV2 is Admin, IFastBridgeV2, IFastBridgeV2Errors {\n using SafeERC20 for IERC20;\n using UniversalTokenLib for address;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Delay for a transaction after which it could be permisionlessly refunded\n uint256 public constant REFUND_DELAY = 7 days;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n /// @notice Maximum length of accepted callParams\n uint256 public constant MAX_CALL_PARAMS_LENGTH = 2 ** 16 - 1;\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeTxDetails) public bridgeTxDetails;\n /// @notice Relay details on destination chain\n mapping(bytes32 =\u003e BridgeRelay) public bridgeRelayDetails;\n /// @notice Unique bridge nonces tracked per originSender\n mapping(address =\u003e uint256) public senderNonces;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Replaced by senderNonces\n uint256 public immutable nonce = 0;\n /// @notice the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n bridge({\n params: params,\n paramsV2: BridgeParamsV2({\n quoteRelayer: address(0),\n quoteExclusivitySeconds: 0,\n quoteId: bytes(\"\"),\n callValue: 0,\n callParams: bytes(\"\")\n })\n });\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes memory request) external payable {\n relay({request: request, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes memory request, bytes32 destTxHash) external {\n prove({transactionId: keccak256(request), destTxHash: destTxHash, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridgeV2\n function claim(bytes memory request) external {\n claim({request: request, to: address(0)});\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003e DISPUTE_PERIOD) {\n revert DisputePeriodPassed();\n }\n\n // @dev relayer gets slashed effectively if dest relay has gone thru\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n bridgeTxDetails[transactionId].proofRelayer = address(0);\n bridgeTxDetails[transactionId].proofBlockTimestamp = 0;\n bridgeTxDetails[transactionId].proofBlockNumber = 0;\n\n emit BridgeProofDisputed(transactionId, msg.sender);\n }\n\n /// @inheritdoc IFastBridge\n function refund(bytes memory request) external {\n bytes32 transactionId = keccak256(request);\n\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n\n if (bridgeTxDetails[transactionId].status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n\n if (hasRole(REFUNDER_ROLE, msg.sender)) {\n // Refunder can refund if deadline has passed\n if (block.timestamp \u003c= transaction.deadline) revert DeadlineNotExceeded();\n } else {\n // Permissionless refund is allowed after REFUND_DELAY\n if (block.timestamp \u003c= transaction.deadline + REFUND_DELAY) revert DeadlineNotExceeded();\n }\n\n // if all checks passed, set to REFUNDED status\n bridgeTxDetails[transactionId].status = BridgeStatus.REFUNDED;\n\n // transfer origin collateral back to original sender\n address to = transaction.originSender;\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount + transaction.originFeeAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (bridgeTxDetails[transactionId].proofRelayer != relayer) revert SenderIncorrect();\n return _timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n /// @dev This method is added to achieve backwards compatibility with decoding requests into V1 structs:\n /// - `callValue` is partially reported as a zero/non-zero flag\n /// - `callParams` is ignored\n /// In order to process all kinds of requests use getBridgeTransactionV2 instead.\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory) {\n // Try decoding into V2 struct first. This will revert if V1 struct is passed\n try this.getBridgeTransactionV2(request) returns (BridgeTransactionV2 memory txV2) {\n // Note: we entirely ignore the callParams field, as it was not present in V1\n return BridgeTransaction({\n originChainId: txV2.originChainId,\n destChainId: txV2.destChainId,\n originSender: txV2.originSender,\n destRecipient: txV2.destRecipient,\n originToken: txV2.originToken,\n destToken: txV2.destToken,\n originAmount: txV2.originAmount,\n destAmount: txV2.destAmount,\n originFeeAmount: txV2.originFeeAmount,\n sendChainGas: txV2.callValue != 0,\n deadline: txV2.deadline,\n nonce: txV2.nonce\n });\n } catch {\n // Fallback to V1 struct\n return abi.decode(request, (BridgeTransaction));\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) public payable {\n int256 exclusivityEndTime = int256(block.timestamp) + paramsV2.quoteExclusivitySeconds;\n _validateBridgeParams(params, paramsV2, exclusivityEndTime);\n\n // transfer tokens to bridge contract\n /// @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _pullToken(params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n\n // set status to requested\n bytes memory request = abi.encode(\n BridgeTransactionV2({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n callValue: paramsV2.callValue,\n deadline: params.deadline,\n nonce: senderNonces[params.sender]++, // increment nonce on every bridge\n exclusivityRelayer: paramsV2.quoteRelayer,\n // We checked exclusivityEndTime to be in range (0 .. params.deadline] above, so can safely cast\n exclusivityEndTime: uint256(exclusivityEndTime),\n callParams: paramsV2.callParams\n })\n );\n bytes32 transactionId = keccak256(request);\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n\n emit BridgeRequested({\n transactionId: transactionId,\n sender: params.sender,\n request: request,\n destChainId: params.dstChainId,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n sendChainGas: paramsV2.callValue != 0\n });\n emit BridgeQuoteDetails(transactionId, paramsV2.quoteId);\n }\n\n /// @inheritdoc IFastBridgeV2\n function relay(bytes memory request, address relayer) public payable {\n bytes32 transactionId = keccak256(request);\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n _validateRelayParams(transaction, transactionId, relayer);\n // mark bridge transaction as relayed\n bridgeRelayDetails[transactionId] =\n BridgeRelay({blockNumber: uint48(block.number), blockTimestamp: uint48(block.timestamp), relayer: relayer});\n\n // transfer tokens to recipient on destination chain and do an arbitrary call if requested\n address to = transaction.destRecipient;\n address token = transaction.destToken;\n uint256 amount = transaction.destAmount;\n\n // All state changes have been done at this point, can proceed to the external calls.\n // This follows the checks-effects-interactions pattern to mitigate potential reentrancy attacks.\n if (token == UniversalTokenLib.ETH_ADDRESS) {\n // For ETH non-zero callValue is not allowed\n if (transaction.callValue != 0) revert NativeTokenCallValueNotSupported();\n // Check that the correct msg.value was sent\n if (msg.value != amount) revert MsgValueIncorrect();\n } else {\n // For ERC20s, we check that the correct msg.value was sent\n if (msg.value != transaction.callValue) revert MsgValueIncorrect();\n // We need to transfer the tokens from the Relayer to the recipient first before performing an\n // optional post-transfer arbitrary call.\n IERC20(token).safeTransferFrom(msg.sender, to, amount);\n }\n\n if (transaction.callParams.length != 0) {\n // Arbitrary call requested, perform it while supplying full msg.value to the recipient\n // Note: if token has a fee on transfers, the recipient will have received less than `amount`.\n // This is a very niche edge case and should be handled by the recipient contract.\n _checkedCallRecipient({recipient: to, token: token, amount: amount, callParams: transaction.callParams});\n } else if (msg.value != 0) {\n // No arbitrary call requested, but msg.value was sent. This is either a relay with ETH,\n // or a non-zero callValue request with an ERC20. In both cases, transfer the ETH to the recipient.\n Address.sendValue(payable(to), msg.value);\n }\n\n emit BridgeRelayed({\n transactionId: transactionId,\n relayer: relayer,\n to: to,\n originChainId: transaction.originChainId,\n originToken: transaction.originToken,\n destToken: transaction.destToken,\n originAmount: transaction.originAmount,\n destAmount: transaction.destAmount,\n chainGasAmount: transaction.callValue\n });\n }\n\n /// @inheritdoc IFastBridgeV2\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) public onlyRole(RELAYER_ROLE) {\n // update bridge tx status given proof provided\n if (bridgeTxDetails[transactionId].status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n bridgeTxDetails[transactionId].status = BridgeStatus.RELAYER_PROVED;\n bridgeTxDetails[transactionId].proofBlockTimestamp = uint40(block.timestamp);\n bridgeTxDetails[transactionId].proofBlockNumber = uint48(block.number);\n bridgeTxDetails[transactionId].proofRelayer = relayer;\n\n emit BridgeProofProvided(transactionId, relayer, destTxHash);\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes memory request, address to) public {\n bytes32 transactionId = keccak256(request);\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n\n // update bridge tx status if able to claim origin collateral\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n\n // if \"to\" is zero addr, permissionlessly send funds to proven relayer\n if (to == address(0)) {\n to = bridgeTxDetails[transactionId].proofRelayer;\n } else if (bridgeTxDetails[transactionId].proofRelayer != msg.sender) {\n revert SenderIncorrect();\n }\n\n if (_timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003c= DISPUTE_PERIOD) {\n revert DisputePeriodNotPassed();\n }\n\n bridgeTxDetails[transactionId].status = BridgeStatus.RELAYER_CLAIMED;\n\n // update protocol fees if origin fee amount exists\n if (transaction.originFeeAmount \u003e 0) protocolFees[transaction.originToken] += transaction.originFeeAmount;\n\n // transfer origin collateral less fee to specified address\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositClaimed(transactionId, bridgeTxDetails[transactionId].proofRelayer, to, token, amount);\n }\n\n function bridgeStatuses(bytes32 transactionId) public view returns (BridgeStatus status) {\n return bridgeTxDetails[transactionId].status;\n }\n\n function bridgeProofs(bytes32 transactionId) public view returns (uint96 timestamp, address relayer) {\n timestamp = bridgeTxDetails[transactionId].proofBlockTimestamp;\n relayer = bridgeTxDetails[transactionId].proofRelayer;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeRelays(bytes32 transactionId) public view returns (bool) {\n // has this transactionId been relayed?\n return bridgeRelayDetails[transactionId].relayer != address(0);\n }\n\n /// @inheritdoc IFastBridgeV2\n function getBridgeTransactionV2(bytes memory request) public pure returns (BridgeTransactionV2 memory) {\n return abi.decode(request, (BridgeTransactionV2));\n }\n\n /// @notice Pulls a requested token from the user to this contract.\n function _pullToken(address token, uint256 amount) internal returns (uint256 amountPulled) {\n if (token == UniversalTokenLib.ETH_ADDRESS) {\n // For ETH we just need to check that the supplied msg.value is correct\n if (amount != msg.value) revert MsgValueIncorrect();\n amountPulled = msg.value;\n } else {\n token.assertIsContract();\n // Record token balance before transfer\n amountPulled = IERC20(token).balanceOf(address(this));\n // Token needs to be pulled only if msg.value is zero\n // This way user can specify WETH as the origin asset\n IERC20(token).safeTransferFrom(msg.sender, address(this), amount);\n // Use the difference between the recorded balance and the current balance as the amountPulled\n amountPulled = IERC20(token).balanceOf(address(this)) - amountPulled;\n }\n }\n\n /// @notice Calls the Recipient's hook function with the specified callParams and performs\n /// all the necessary checks for the returned value.\n function _checkedCallRecipient(\n address recipient,\n address token,\n uint256 amount,\n bytes memory callParams\n )\n internal\n {\n bytes memory hookData =\n abi.encodeCall(IFastBridgeRecipient.fastBridgeTransferReceived, (token, amount, callParams));\n // This will bubble any revert messages from the hook function\n bytes memory returnData = Address.functionCallWithValue({target: recipient, data: hookData, value: msg.value});\n // Explicit revert if no return data at all\n if (returnData.length == 0) revert RecipientNoReturnValue();\n // Check that exactly a single return value was returned\n if (returnData.length != 32) revert RecipientIncorrectReturnValue();\n // Return value should be abi-encoded hook function selector\n if (bytes32(returnData) != bytes32(IFastBridgeRecipient.fastBridgeTransferReceived.selector)) {\n revert RecipientIncorrectReturnValue();\n }\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint40(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint40).max but\n /// proof.timestamp \u003c type(uint40).max via unchecked statement\n /// @param proofBlockTimestamp The bridge proof block timestamp\n /// @return delta Time delta since proof submitted\n function _timeSince(uint40 proofBlockTimestamp) internal view returns (uint256 delta) {\n unchecked {\n delta = uint40(block.timestamp) - proofBlockTimestamp;\n }\n }\n\n /// @notice Performs all the necessary checks for a bridge to happen.\n /// @dev There's no good way to refactor this function to reduce cyclomatic complexity due to\n /// the number of checks that need to be performed, so we skip the code-complexity rule here.\n // solhint-disable-next-line code-complexity\n function _validateBridgeParams(\n BridgeParams memory params,\n BridgeParamsV2 memory paramsV2,\n int256 exclusivityEndTime\n )\n internal\n view\n {\n // Check V1 (legacy) params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.sender == address(0) || params.to == address(0)) revert ZeroAddress();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n // Check V2 params\n if (paramsV2.callParams.length \u003e MAX_CALL_PARAMS_LENGTH) revert CallParamsLengthAboveMax();\n if (paramsV2.callValue != 0 \u0026\u0026 params.destToken == UniversalTokenLib.ETH_ADDRESS) {\n revert NativeTokenCallValueNotSupported();\n }\n // exclusivityEndTime must be in range (0 .. params.deadline]\n if (exclusivityEndTime \u003c= 0 || exclusivityEndTime \u003e int256(params.deadline)) {\n revert ExclusivityParamsIncorrect();\n }\n }\n\n /// @notice Performs all the necessary checks for a relay to happen.\n function _validateRelayParams(\n BridgeTransactionV2 memory transaction,\n bytes32 transactionId,\n address relayer\n )\n internal\n view\n {\n if (relayer == address(0)) revert ZeroAddress();\n // Check if the transaction has already been relayed\n if (bridgeRelays(transactionId)) revert TransactionRelayed();\n if (transaction.destChainId != uint32(block.chainid)) revert ChainIncorrect();\n // Check the deadline for relay to happen\n if (block.timestamp \u003e transaction.deadline) revert DeadlineExceeded();\n // Check the exclusivity period, if it is still ongoing\n // forgefmt: disable-next-item\n if (\n transaction.exclusivityRelayer != address(0) \u0026\u0026\n transaction.exclusivityRelayer != relayer \u0026\u0026\n block.timestamp \u003c= transaction.exclusivityEndTime\n ) {\n revert ExclusivityPeriodNotPassed();\n }\n }\n}\n","language":"Solidity","languageVersion":"0.8.24","compilerVersion":"0.8.24","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../","srcMap":"","srcMapRuntime":"","abiDefinition":[{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"}],"userDoc":{"kind":"user","methods":{},"version":1},"developerDoc":{"details":"Implementation of the {IERC165} interface. Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check for the additional interface id that will be supported. For example: ```solidity function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId); } ```","kind":"dev","methods":{"supportsInterface(bytes4)":{"details":"See {IERC165-supportsInterface}."}},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"bytes4\",\"name\":\"interfaceId\",\"type\":\"bytes4\"}],\"name\":\"supportsInterface\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"}],\"devdoc\":{\"details\":\"Implementation of the {IERC165} interface. Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check for the additional interface id that will be supported. For example: ```solidity function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId); } ```\",\"kind\":\"dev\",\"methods\":{\"supportsInterface(bytes4)\":{\"details\":\"See {IERC165-supportsInterface}.\"}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeV2.sol\":\"ERC165\"},\"evmVersion\":\"shanghai\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeV2.sol\":{\"keccak256\":\"0x7cd0f885e80e2bdaa638bc32ae7af7d2e248f99ce4b354c217d0f0f7d7302e0a\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://7ccf28df0bd7b4606986585acd8622ed9b4e81379690061bb66088f0a2270af1\",\"dweb:/ipfs/QmTf7HNdHZkK6vmx8ZgewycQEb72oLD9nPwBpsM5reMstQ\"]}},\"version\":1}"},"hashes":{"supportsInterface(bytes4)":"01ffc9a7"}},"solidity/FastBridgeV2.sol:EnumerableSet":{"code":"0x60556032600b8282823980515f1a607314602657634e487b7160e01b5f525f60045260245ffd5b305f52607381538281f3fe730000000000000000000000000000000000000000301460806040525f80fdfea26469706673582212201ec3fcd8425a477b64c89978a17adf538a2da29b003a43e615ec5e213f9f3bf964736f6c63430008180033","runtime-code":"0x730000000000000000000000000000000000000000301460806040525f80fdfea26469706673582212201ec3fcd8425a477b64c89978a17adf538a2da29b003a43e615ec5e213f9f3bf964736f6c63430008180033","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.24 ^0.8.0 ^0.8.20;\n\n// contracts/interfaces/IAdmin.sol\n\ninterface IAdmin {\n // ============ Events ============\n\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n event ChainGasAmountUpdated(uint256 oldChainGasAmount, uint256 newChainGasAmount);\n\n // ============ Methods ============\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n\n function setChainGasAmount(uint256 newChainGasAmount) external;\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IFastBridgeRecipient.sol\n\ninterface IFastBridgeRecipient {\n function fastBridgeTransferReceived(\n address token,\n uint256 amount,\n bytes memory callParams\n )\n external\n payable\n returns (bytes4);\n}\n\n// contracts/interfaces/IFastBridgeV2Errors.sol\n\ninterface IFastBridgeV2Errors {\n error AmountIncorrect();\n error CallParamsLengthAboveMax();\n error ChainIncorrect();\n error ExclusivityParamsIncorrect();\n error MsgValueIncorrect();\n error NativeTokenCallValueNotSupported();\n error SenderIncorrect();\n error StatusIncorrect();\n error ZeroAddress();\n\n error RecipientIncorrectReturnValue();\n error RecipientNoReturnValue();\n\n error DeadlineExceeded();\n error DeadlineNotExceeded();\n error DeadlineTooShort();\n error DisputePeriodNotPassed();\n error DisputePeriodPassed();\n error ExclusivityPeriodNotPassed();\n\n error TransactionRelayed();\n}\n\n// contracts/libs/Errors.sol\n\nerror DeadlineExceeded();\nerror DeadlineNotExceeded();\nerror DeadlineTooShort();\nerror InsufficientOutputAmount();\n\nerror MsgValueIncorrect();\nerror PoolNotFound();\nerror TokenAddressMismatch();\nerror TokenNotContract();\nerror TokenNotETH();\nerror TokensIdentical();\n\nerror ChainIncorrect();\nerror AmountIncorrect();\nerror ZeroAddress();\n\nerror DisputePeriodNotPassed();\nerror DisputePeriodPassed();\nerror SenderIncorrect();\nerror StatusIncorrect();\nerror TransactionIdIncorrect();\nerror TransactionRelayed();\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// contracts/interfaces/IFastBridgeV2.sol\n\ninterface IFastBridgeV2 is IFastBridge {\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n struct BridgeTxDetails {\n BridgeStatus status;\n uint40 proofBlockTimestamp;\n uint48 proofBlockNumber;\n address proofRelayer;\n }\n\n struct BridgeRelay {\n uint48 blockNumber;\n uint48 blockTimestamp;\n address relayer;\n }\n\n /// @notice New params introduced in the FastBridgeV2.\n /// We are passing fields from the older BridgeParams struct outside of this struct\n /// for backwards compatibility.\n /// Note: quoteRelayer and quoteExclusivitySeconds are either both zero (indicating no exclusivity)\n /// or both non-zero (indicating exclusivity for the given period).\n /// Note: callValue \u003e 0 can NOT be used with destToken = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE (ETH_ADDRESS)\n /// @param quoteRelayer Relayer that provided the quote for the transaction\n /// @param quoteExclusivitySeconds Period of time the quote relayer is guaranteed exclusivity after user's deposit\n /// @param quoteId Unique quote identifier used for tracking the quote\n /// @param callValue ETH value to send to the recipient (if any)\n /// @param callParams Parameters for the arbitrary call to the destination recipient (if any)\n struct BridgeParamsV2 {\n address quoteRelayer;\n int256 quoteExclusivitySeconds;\n bytes quoteId;\n uint256 callValue;\n bytes callParams;\n }\n\n /// @notice Updated bridge transaction struct to include parameters introduced in FastBridgeV2.\n /// Note: only `exclusivityRelayer` can fill such a transaction until `exclusivityEndTime`.\n /// TODO: consider changing the encoding scheme to prevent spending extra gas on decoding.\n struct BridgeTransactionV2 {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n uint256 callValue; // ETH value to send to the recipient (if any) - replaces V1's sendChainGas flag\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n address exclusivityRelayer;\n uint256 exclusivityEndTime;\n bytes callParams;\n }\n\n event BridgeQuoteDetails(bytes32 indexed transactionId, bytes quoteId);\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability\n /// to provide temporary exclusivity fill rights for the quote relayer.\n /// @param params The parameters required to bridge\n /// @param paramsV2 The parameters for exclusivity fill rights (optional, can be left empty)\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function relay(bytes memory request, address relayer) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param transactionId The transaction id associated with the encoded bridge transaction to prove\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital.\n /// @notice Can only send funds to the relayer address on the proof.\n /// @param request The encoded bridge transaction to claim on origin chain\n function claim(bytes memory request) external;\n /// @notice Checks if a transaction has been relayed\n /// @param transactionId The ID of the transaction to check\n /// @return True if the transaction has been relayed, false otherwise\n function bridgeRelays(bytes32 transactionId) external view returns (bool);\n\n /// @notice Returns the status of a bridge transaction\n /// @param transactionId The ID of the bridge transaction\n /// @return BridgeStatus Status of the bridge transaction\n function bridgeStatuses(bytes32 transactionId) external view returns (BridgeStatus);\n\n /// @notice Returns the timestamp and relayer of a bridge proof\n /// @param transactionId The ID of the bridge transaction\n /// @return timestamp The timestamp of the bridge proof\n /// @return relayer The relayer address of the bridge proof\n function bridgeProofs(bytes32 transactionId) external view returns (uint96 timestamp, address relayer);\n\n /// @notice Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\n /// @param request The bridge request to decode\n function getBridgeTransactionV2(bytes memory request) external view returns (BridgeTransactionV2 memory);\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// contracts/libs/UniversalToken.sol\n\nlibrary UniversalTokenLib {\n using SafeERC20 for IERC20;\n\n address internal constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Transfers tokens to the given account. Reverts if transfer is not successful.\n /// @dev This might trigger fallback, if ETH is transferred to the contract.\n /// Make sure this can not lead to reentrancy attacks.\n function universalTransfer(address token, address to, uint256 value) internal {\n // Don't do anything, if need to send tokens to this address\n if (to == address(this)) return;\n // Don't do anything, if trying to send zero value\n if (value == 0) return;\n if (token == ETH_ADDRESS) {\n /// @dev Note: this can potentially lead to executing code in `to`.\n // solhint-disable-next-line avoid-low-level-calls\n (bool success,) = to.call{value: value}(\"\");\n require(success, \"ETH transfer failed\");\n } else {\n IERC20(token).safeTransfer(to, value);\n }\n }\n\n /// @notice Issues an infinite allowance to the spender, if the current allowance is insufficient\n /// to spend the given amount.\n function universalApproveInfinity(address token, address spender, uint256 amountToSpend) internal {\n // ETH Chad doesn't require your approval\n if (token == ETH_ADDRESS) return;\n // No-op if allowance is already sufficient\n uint256 allowance = IERC20(token).allowance(address(this), spender);\n if (allowance \u003e= amountToSpend) return;\n // Otherwise, reset approval to 0 and set to max allowance\n if (allowance \u003e 0) IERC20(token).safeDecreaseAllowance(spender, allowance);\n IERC20(token).safeIncreaseAllowance(spender, type(uint256).max);\n }\n\n /// @notice Returns the balance of the given token (or native ETH) for the given account.\n function universalBalanceOf(address token, address account) internal view returns (uint256) {\n if (token == ETH_ADDRESS) {\n return account.balance;\n } else {\n return IERC20(token).balanceOf(account);\n }\n }\n\n /// @dev Checks that token is a contract and not ETH_ADDRESS.\n function assertIsContract(address token) internal view {\n // Check that ETH_ADDRESS was not used (in case this is a predeploy on any of the chains)\n if (token == UniversalTokenLib.ETH_ADDRESS) revert TokenNotContract();\n // Check that token is not an EOA\n if (token.code.length == 0) revert TokenNotContract();\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/Admin.sol\n\ncontract Admin is IAdmin, AccessControlEnumerable {\n using UniversalTokenLib for address;\n\n bytes32 public constant RELAYER_ROLE = keccak256(\"RELAYER_ROLE\");\n bytes32 public constant REFUNDER_ROLE = keccak256(\"REFUNDER_ROLE\");\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n uint256 public constant FEE_BPS = 1e6;\n uint256 public constant FEE_RATE_MAX = 0.01e6; // max 1% on origin amount\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Chain gas amount to forward as rebate if requested\n uint256 public chainGasAmount;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n }\n\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n require(newFeeRate \u003c= FEE_RATE_MAX, \"newFeeRate \u003e max\");\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n token.universalTransfer(recipient, feeAmount);\n emit FeesSwept(token, recipient, feeAmount);\n }\n\n function setChainGasAmount(uint256 newChainGasAmount) external onlyRole(GOVERNOR_ROLE) {\n uint256 oldChainGasAmount = chainGasAmount;\n chainGasAmount = newChainGasAmount;\n emit ChainGasAmountUpdated(oldChainGasAmount, newChainGasAmount);\n }\n}\n\n// contracts/FastBridgeV2.sol\n\n/// @notice FastBridgeV2 is a contract for bridging tokens across chains.\ncontract FastBridgeV2 is Admin, IFastBridgeV2, IFastBridgeV2Errors {\n using SafeERC20 for IERC20;\n using UniversalTokenLib for address;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Delay for a transaction after which it could be permisionlessly refunded\n uint256 public constant REFUND_DELAY = 7 days;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n /// @notice Maximum length of accepted callParams\n uint256 public constant MAX_CALL_PARAMS_LENGTH = 2 ** 16 - 1;\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeTxDetails) public bridgeTxDetails;\n /// @notice Relay details on destination chain\n mapping(bytes32 =\u003e BridgeRelay) public bridgeRelayDetails;\n /// @notice Unique bridge nonces tracked per originSender\n mapping(address =\u003e uint256) public senderNonces;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Replaced by senderNonces\n uint256 public immutable nonce = 0;\n /// @notice the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n bridge({\n params: params,\n paramsV2: BridgeParamsV2({\n quoteRelayer: address(0),\n quoteExclusivitySeconds: 0,\n quoteId: bytes(\"\"),\n callValue: 0,\n callParams: bytes(\"\")\n })\n });\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes memory request) external payable {\n relay({request: request, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes memory request, bytes32 destTxHash) external {\n prove({transactionId: keccak256(request), destTxHash: destTxHash, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridgeV2\n function claim(bytes memory request) external {\n claim({request: request, to: address(0)});\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003e DISPUTE_PERIOD) {\n revert DisputePeriodPassed();\n }\n\n // @dev relayer gets slashed effectively if dest relay has gone thru\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n bridgeTxDetails[transactionId].proofRelayer = address(0);\n bridgeTxDetails[transactionId].proofBlockTimestamp = 0;\n bridgeTxDetails[transactionId].proofBlockNumber = 0;\n\n emit BridgeProofDisputed(transactionId, msg.sender);\n }\n\n /// @inheritdoc IFastBridge\n function refund(bytes memory request) external {\n bytes32 transactionId = keccak256(request);\n\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n\n if (bridgeTxDetails[transactionId].status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n\n if (hasRole(REFUNDER_ROLE, msg.sender)) {\n // Refunder can refund if deadline has passed\n if (block.timestamp \u003c= transaction.deadline) revert DeadlineNotExceeded();\n } else {\n // Permissionless refund is allowed after REFUND_DELAY\n if (block.timestamp \u003c= transaction.deadline + REFUND_DELAY) revert DeadlineNotExceeded();\n }\n\n // if all checks passed, set to REFUNDED status\n bridgeTxDetails[transactionId].status = BridgeStatus.REFUNDED;\n\n // transfer origin collateral back to original sender\n address to = transaction.originSender;\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount + transaction.originFeeAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (bridgeTxDetails[transactionId].proofRelayer != relayer) revert SenderIncorrect();\n return _timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n /// @dev This method is added to achieve backwards compatibility with decoding requests into V1 structs:\n /// - `callValue` is partially reported as a zero/non-zero flag\n /// - `callParams` is ignored\n /// In order to process all kinds of requests use getBridgeTransactionV2 instead.\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory) {\n // Try decoding into V2 struct first. This will revert if V1 struct is passed\n try this.getBridgeTransactionV2(request) returns (BridgeTransactionV2 memory txV2) {\n // Note: we entirely ignore the callParams field, as it was not present in V1\n return BridgeTransaction({\n originChainId: txV2.originChainId,\n destChainId: txV2.destChainId,\n originSender: txV2.originSender,\n destRecipient: txV2.destRecipient,\n originToken: txV2.originToken,\n destToken: txV2.destToken,\n originAmount: txV2.originAmount,\n destAmount: txV2.destAmount,\n originFeeAmount: txV2.originFeeAmount,\n sendChainGas: txV2.callValue != 0,\n deadline: txV2.deadline,\n nonce: txV2.nonce\n });\n } catch {\n // Fallback to V1 struct\n return abi.decode(request, (BridgeTransaction));\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) public payable {\n int256 exclusivityEndTime = int256(block.timestamp) + paramsV2.quoteExclusivitySeconds;\n _validateBridgeParams(params, paramsV2, exclusivityEndTime);\n\n // transfer tokens to bridge contract\n /// @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _pullToken(params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n\n // set status to requested\n bytes memory request = abi.encode(\n BridgeTransactionV2({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n callValue: paramsV2.callValue,\n deadline: params.deadline,\n nonce: senderNonces[params.sender]++, // increment nonce on every bridge\n exclusivityRelayer: paramsV2.quoteRelayer,\n // We checked exclusivityEndTime to be in range (0 .. params.deadline] above, so can safely cast\n exclusivityEndTime: uint256(exclusivityEndTime),\n callParams: paramsV2.callParams\n })\n );\n bytes32 transactionId = keccak256(request);\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n\n emit BridgeRequested({\n transactionId: transactionId,\n sender: params.sender,\n request: request,\n destChainId: params.dstChainId,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n sendChainGas: paramsV2.callValue != 0\n });\n emit BridgeQuoteDetails(transactionId, paramsV2.quoteId);\n }\n\n /// @inheritdoc IFastBridgeV2\n function relay(bytes memory request, address relayer) public payable {\n bytes32 transactionId = keccak256(request);\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n _validateRelayParams(transaction, transactionId, relayer);\n // mark bridge transaction as relayed\n bridgeRelayDetails[transactionId] =\n BridgeRelay({blockNumber: uint48(block.number), blockTimestamp: uint48(block.timestamp), relayer: relayer});\n\n // transfer tokens to recipient on destination chain and do an arbitrary call if requested\n address to = transaction.destRecipient;\n address token = transaction.destToken;\n uint256 amount = transaction.destAmount;\n\n // All state changes have been done at this point, can proceed to the external calls.\n // This follows the checks-effects-interactions pattern to mitigate potential reentrancy attacks.\n if (token == UniversalTokenLib.ETH_ADDRESS) {\n // For ETH non-zero callValue is not allowed\n if (transaction.callValue != 0) revert NativeTokenCallValueNotSupported();\n // Check that the correct msg.value was sent\n if (msg.value != amount) revert MsgValueIncorrect();\n } else {\n // For ERC20s, we check that the correct msg.value was sent\n if (msg.value != transaction.callValue) revert MsgValueIncorrect();\n // We need to transfer the tokens from the Relayer to the recipient first before performing an\n // optional post-transfer arbitrary call.\n IERC20(token).safeTransferFrom(msg.sender, to, amount);\n }\n\n if (transaction.callParams.length != 0) {\n // Arbitrary call requested, perform it while supplying full msg.value to the recipient\n // Note: if token has a fee on transfers, the recipient will have received less than `amount`.\n // This is a very niche edge case and should be handled by the recipient contract.\n _checkedCallRecipient({recipient: to, token: token, amount: amount, callParams: transaction.callParams});\n } else if (msg.value != 0) {\n // No arbitrary call requested, but msg.value was sent. This is either a relay with ETH,\n // or a non-zero callValue request with an ERC20. In both cases, transfer the ETH to the recipient.\n Address.sendValue(payable(to), msg.value);\n }\n\n emit BridgeRelayed({\n transactionId: transactionId,\n relayer: relayer,\n to: to,\n originChainId: transaction.originChainId,\n originToken: transaction.originToken,\n destToken: transaction.destToken,\n originAmount: transaction.originAmount,\n destAmount: transaction.destAmount,\n chainGasAmount: transaction.callValue\n });\n }\n\n /// @inheritdoc IFastBridgeV2\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) public onlyRole(RELAYER_ROLE) {\n // update bridge tx status given proof provided\n if (bridgeTxDetails[transactionId].status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n bridgeTxDetails[transactionId].status = BridgeStatus.RELAYER_PROVED;\n bridgeTxDetails[transactionId].proofBlockTimestamp = uint40(block.timestamp);\n bridgeTxDetails[transactionId].proofBlockNumber = uint48(block.number);\n bridgeTxDetails[transactionId].proofRelayer = relayer;\n\n emit BridgeProofProvided(transactionId, relayer, destTxHash);\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes memory request, address to) public {\n bytes32 transactionId = keccak256(request);\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n\n // update bridge tx status if able to claim origin collateral\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n\n // if \"to\" is zero addr, permissionlessly send funds to proven relayer\n if (to == address(0)) {\n to = bridgeTxDetails[transactionId].proofRelayer;\n } else if (bridgeTxDetails[transactionId].proofRelayer != msg.sender) {\n revert SenderIncorrect();\n }\n\n if (_timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003c= DISPUTE_PERIOD) {\n revert DisputePeriodNotPassed();\n }\n\n bridgeTxDetails[transactionId].status = BridgeStatus.RELAYER_CLAIMED;\n\n // update protocol fees if origin fee amount exists\n if (transaction.originFeeAmount \u003e 0) protocolFees[transaction.originToken] += transaction.originFeeAmount;\n\n // transfer origin collateral less fee to specified address\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositClaimed(transactionId, bridgeTxDetails[transactionId].proofRelayer, to, token, amount);\n }\n\n function bridgeStatuses(bytes32 transactionId) public view returns (BridgeStatus status) {\n return bridgeTxDetails[transactionId].status;\n }\n\n function bridgeProofs(bytes32 transactionId) public view returns (uint96 timestamp, address relayer) {\n timestamp = bridgeTxDetails[transactionId].proofBlockTimestamp;\n relayer = bridgeTxDetails[transactionId].proofRelayer;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeRelays(bytes32 transactionId) public view returns (bool) {\n // has this transactionId been relayed?\n return bridgeRelayDetails[transactionId].relayer != address(0);\n }\n\n /// @inheritdoc IFastBridgeV2\n function getBridgeTransactionV2(bytes memory request) public pure returns (BridgeTransactionV2 memory) {\n return abi.decode(request, (BridgeTransactionV2));\n }\n\n /// @notice Pulls a requested token from the user to this contract.\n function _pullToken(address token, uint256 amount) internal returns (uint256 amountPulled) {\n if (token == UniversalTokenLib.ETH_ADDRESS) {\n // For ETH we just need to check that the supplied msg.value is correct\n if (amount != msg.value) revert MsgValueIncorrect();\n amountPulled = msg.value;\n } else {\n token.assertIsContract();\n // Record token balance before transfer\n amountPulled = IERC20(token).balanceOf(address(this));\n // Token needs to be pulled only if msg.value is zero\n // This way user can specify WETH as the origin asset\n IERC20(token).safeTransferFrom(msg.sender, address(this), amount);\n // Use the difference between the recorded balance and the current balance as the amountPulled\n amountPulled = IERC20(token).balanceOf(address(this)) - amountPulled;\n }\n }\n\n /// @notice Calls the Recipient's hook function with the specified callParams and performs\n /// all the necessary checks for the returned value.\n function _checkedCallRecipient(\n address recipient,\n address token,\n uint256 amount,\n bytes memory callParams\n )\n internal\n {\n bytes memory hookData =\n abi.encodeCall(IFastBridgeRecipient.fastBridgeTransferReceived, (token, amount, callParams));\n // This will bubble any revert messages from the hook function\n bytes memory returnData = Address.functionCallWithValue({target: recipient, data: hookData, value: msg.value});\n // Explicit revert if no return data at all\n if (returnData.length == 0) revert RecipientNoReturnValue();\n // Check that exactly a single return value was returned\n if (returnData.length != 32) revert RecipientIncorrectReturnValue();\n // Return value should be abi-encoded hook function selector\n if (bytes32(returnData) != bytes32(IFastBridgeRecipient.fastBridgeTransferReceived.selector)) {\n revert RecipientIncorrectReturnValue();\n }\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint40(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint40).max but\n /// proof.timestamp \u003c type(uint40).max via unchecked statement\n /// @param proofBlockTimestamp The bridge proof block timestamp\n /// @return delta Time delta since proof submitted\n function _timeSince(uint40 proofBlockTimestamp) internal view returns (uint256 delta) {\n unchecked {\n delta = uint40(block.timestamp) - proofBlockTimestamp;\n }\n }\n\n /// @notice Performs all the necessary checks for a bridge to happen.\n /// @dev There's no good way to refactor this function to reduce cyclomatic complexity due to\n /// the number of checks that need to be performed, so we skip the code-complexity rule here.\n // solhint-disable-next-line code-complexity\n function _validateBridgeParams(\n BridgeParams memory params,\n BridgeParamsV2 memory paramsV2,\n int256 exclusivityEndTime\n )\n internal\n view\n {\n // Check V1 (legacy) params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.sender == address(0) || params.to == address(0)) revert ZeroAddress();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n // Check V2 params\n if (paramsV2.callParams.length \u003e MAX_CALL_PARAMS_LENGTH) revert CallParamsLengthAboveMax();\n if (paramsV2.callValue != 0 \u0026\u0026 params.destToken == UniversalTokenLib.ETH_ADDRESS) {\n revert NativeTokenCallValueNotSupported();\n }\n // exclusivityEndTime must be in range (0 .. params.deadline]\n if (exclusivityEndTime \u003c= 0 || exclusivityEndTime \u003e int256(params.deadline)) {\n revert ExclusivityParamsIncorrect();\n }\n }\n\n /// @notice Performs all the necessary checks for a relay to happen.\n function _validateRelayParams(\n BridgeTransactionV2 memory transaction,\n bytes32 transactionId,\n address relayer\n )\n internal\n view\n {\n if (relayer == address(0)) revert ZeroAddress();\n // Check if the transaction has already been relayed\n if (bridgeRelays(transactionId)) revert TransactionRelayed();\n if (transaction.destChainId != uint32(block.chainid)) revert ChainIncorrect();\n // Check the deadline for relay to happen\n if (block.timestamp \u003e transaction.deadline) revert DeadlineExceeded();\n // Check the exclusivity period, if it is still ongoing\n // forgefmt: disable-next-item\n if (\n transaction.exclusivityRelayer != address(0) \u0026\u0026\n transaction.exclusivityRelayer != relayer \u0026\u0026\n block.timestamp \u003c= transaction.exclusivityEndTime\n ) {\n revert ExclusivityPeriodNotPassed();\n }\n }\n}\n","language":"Solidity","languageVersion":"0.8.24","compilerVersion":"0.8.24","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../","srcMap":"25827:11640:0:-:0;;;;;;;;;;;;;;;-1:-1:-1;;;25827:11640:0;;;;;;;;;;;;;;;;;","srcMapRuntime":"25827:11640:0:-:0;;;;;;;;","abiDefinition":[],"userDoc":{"kind":"user","methods":{},"version":1},"developerDoc":{"details":"Library for managing https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive types. Sets have the following properties: - Elements are added, removed, and checked for existence in constant time (O(1)). - Elements are enumerated in O(n). No guarantees are made on the ordering. ```solidity contract Example { // Add the library methods using EnumerableSet for EnumerableSet.AddressSet; // Declare a set state variable EnumerableSet.AddressSet private mySet; } ``` As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`) and `uint256` (`UintSet`) are supported. [WARNING] ==== Trying to delete such a structure from storage will likely result in data corruption, rendering the structure unusable. See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info. In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an array of EnumerableSet. ====","kind":"dev","methods":{},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[],\"devdoc\":{\"details\":\"Library for managing https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive types. Sets have the following properties: - Elements are added, removed, and checked for existence in constant time (O(1)). - Elements are enumerated in O(n). No guarantees are made on the ordering. ```solidity contract Example { // Add the library methods using EnumerableSet for EnumerableSet.AddressSet; // Declare a set state variable EnumerableSet.AddressSet private mySet; } ``` As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`) and `uint256` (`UintSet`) are supported. [WARNING] ==== Trying to delete such a structure from storage will likely result in data corruption, rendering the structure unusable. See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info. In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an array of EnumerableSet. ====\",\"kind\":\"dev\",\"methods\":{},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeV2.sol\":\"EnumerableSet\"},\"evmVersion\":\"shanghai\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeV2.sol\":{\"keccak256\":\"0x7cd0f885e80e2bdaa638bc32ae7af7d2e248f99ce4b354c217d0f0f7d7302e0a\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://7ccf28df0bd7b4606986585acd8622ed9b4e81379690061bb66088f0a2270af1\",\"dweb:/ipfs/QmTf7HNdHZkK6vmx8ZgewycQEb72oLD9nPwBpsM5reMstQ\"]}},\"version\":1}"},"hashes":{}},"solidity/FastBridgeV2.sol:FastBridgeV2":{"code":"0x60c06040525f60805234801562000014575f80fd5b5060405162003d2f38038062003d2f83398101604081905262000037916200018e565b80620000445f8262000051565b50504360a05250620001b6565b5f806200005f84846200008c565b9050801562000083575f84815260016020526040902062000081908462000137565b505b90505b92915050565b5f828152602081815260408083206001600160a01b038516845290915281205460ff166200012f575f838152602081815260408083206001600160a01b03861684529091529020805460ff19166001179055620000e63390565b6001600160a01b0316826001600160a01b0316847f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a450600162000086565b505f62000086565b5f62000083836001600160a01b0384165f8181526001830160205260408120546200012f57508154600181810184555f84815260208082209093018490558454848252828601909352604090209190915562000086565b5f602082840312156200019f575f80fd5b81516001600160a01b038116811462000083575f80fd5b60805160a051613b57620001d85f395f6107cf01525f61086c0152613b575ff3fe6080604052600436106102ed575f3560e01c806391ad503911610186578063b13aa2d6116100dc578063ca15c87311610087578063dcf844a711610062578063dcf844a714610a10578063df36bb1314610a3b578063e00a83e014610a50575f80fd5b8063ca15c8731461099f578063ccc57490146109be578063d547741f146109f1575f80fd5b8063bfc7c607116100b7578063bfc7c607146108e2578063c63ff8dd146108f5578063c79371b114610914575f80fd5b8063b13aa2d61461088e578063b250fe6b146108ad578063bf333f2c146108cc575f80fd5b8063a3ec191a1161013c578063ac11fb1a11610117578063ac11fb1a14610810578063add98c701461083c578063affed0e01461085b575f80fd5b8063a3ec191a146107be578063a5bbe22b146105e1578063aa9641ab146107f1575f80fd5b8063926d7d7f1161016c578063926d7d7f146107655780639c9545f014610798578063a217fddf146107ab575f80fd5b806391ad5039146106a557806391d1485414610723575f80fd5b806341fcb6121161024657806363787e52116101f1578063886d36ff116101cc578063886d36ff1461063c5780638f0d6f171461065b5780639010d07c1461066e575f80fd5b806363787e5214610568578063820688d5146105e15780638379a24f146105f6575f80fd5b80635960ccf2116102215780635960ccf2146104ea5780635aa6ccba1461051d5780635eb7d94614610549575f80fd5b806341fcb612146104a357806345851694146104c257806358f85880146104d5575f80fd5b806318e4357d116102a6578063295710ff11610281578063295710ff1461043a5780632f2ff15d1461046557806336568abe14610484575f80fd5b806318e4357d146103d7578063190da595146103f6578063248a9ca31461040c575f80fd5b8063051287bc116102d6578063051287bc1461036657806306f333f2146103a15780630f5f6ed7146103c2575f80fd5b806301ffc9a7146102f157806303ed0ee514610325575b5f80fd5b3480156102fc575f80fd5b5061031061030b366004612e21565b610a65565b60405190151581526020015b60405180910390f35b348015610330575f80fd5b506103587f043c983c49d46f0e102151eaf8085d4a2e6571d5df2d47b013f39bddfd4a639d81565b60405190815260200161031c565b348015610371575f80fd5b50610394610380366004612e60565b5f9081526005602052604090205460ff1690565b60405161031c9190612edd565b3480156103ac575f80fd5b506103c06103bb366004612f0a565b610ac0565b005b3480156103cd575f80fd5b5061035861271081565b3480156103e2575f80fd5b506103c06103f1366004612f41565b610b85565b348015610401575f80fd5b5061035862093a8081565b348015610417575f80fd5b50610358610426366004612e60565b5f9081526020819052604090206001015490565b348015610445575f80fd5b50610358610454366004612f77565b60076020525f908152604090205481565b348015610470575f80fd5b506103c061047f366004612f92565b610cf0565b34801561048f575f80fd5b506103c061049e366004612f92565b610d1a565b3480156104ae575f80fd5b506103c06104bd366004613121565b610d66565b6103c06104d036600461323a565b610fd4565b3480156104e0575f80fd5b5061035860025481565b3480156104f5575f80fd5b506103587fdb9556138406326f00296e13ea2ad7db24ba82381212d816b1a40c23b466b32781565b348015610528575f80fd5b5061053c610537366004613255565b61102c565b60405161031c91906132dc565b348015610554575f80fd5b506103c0610563366004613255565b6110e4565b348015610573575f80fd5b506105d1610582366004612e60565b60056020525f908152604090205460ff811690610100810464ffffffffff16906601000000000000810465ffffffffffff16906c0100000000000000000000000090046001600160a01b031684565b60405161031c94939291906133f0565b3480156105ec575f80fd5b5061035861070881565b348015610601575f80fd5b50610310610610366004612e60565b5f908152600660205260409020546c0100000000000000000000000090046001600160a01b0316151590565b348015610647575f80fd5b506103c0610656366004613431565b6112d5565b6103c0610669366004613255565b6112eb565b348015610679575f80fd5b5061068d610688366004613473565b6112f5565b6040516001600160a01b03909116815260200161031c565b3480156106b0575f80fd5b506106f76106bf366004612e60565b5f90815260056020526040902054610100810464ffffffffff16916c010000000000000000000000009091046001600160a01b031690565b604080516bffffffffffffffffffffffff90931683526001600160a01b0390911660208301520161031c565b34801561072e575f80fd5b5061031061073d366004612f92565b5f918252602082815260408084206001600160a01b0393909316845291905290205460ff1690565b348015610770575f80fd5b506103587fe2b7fb3b832174769106daebcfd6d1970523240dda11281102db9363b83b0dc481565b6103c06107a6366004613121565b611313565b3480156107b6575f80fd5b506103585f81565b3480156107c9575f80fd5b506103587f000000000000000000000000000000000000000000000000000000000000000081565b3480156107fc575f80fd5b5061031061080b366004612f92565b6115c1565b34801561081b575f80fd5b5061082f61082a366004613255565b6116a8565b60405161031c9190613493565b348015610847575f80fd5b506103c0610856366004612e60565b61185b565b348015610866575f80fd5b506103587f000000000000000000000000000000000000000000000000000000000000000081565b348015610899575f80fd5b506103c06108a8366004612e60565b61197a565b3480156108b8575f80fd5b506103c06108c7366004612e60565b611a5c565b3480156108d7575f80fd5b50610358620f424081565b6103c06108f0366004613579565b611ac4565b348015610900575f80fd5b506103c061090f366004613255565b611d3c565b34801561091f575f80fd5b5061097161092e366004612e60565b60066020525f908152604090205465ffffffffffff8082169166010000000000008104909116906c0100000000000000000000000090046001600160a01b031683565b6040805165ffffffffffff94851681529390921660208401526001600160a01b03169082015260600161031c565b3480156109aa575f80fd5b506103586109b9366004612e60565b611d46565b3480156109c9575f80fd5b506103587f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f5581565b3480156109fc575f80fd5b506103c0610a0b366004612f92565b611d5c565b348015610a1b575f80fd5b50610358610a2a366004612f77565b60036020525f908152604090205481565b348015610a46575f80fd5b5061035861ffff81565b348015610a5b575f80fd5b5061035860045481565b5f7fffffffff0000000000000000000000000000000000000000000000000000000082167f5a05180f000000000000000000000000000000000000000000000000000000001480610aba5750610aba82611d80565b92915050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f55610aea81611e16565b6001600160a01b0383165f9081526003602052604081205490819003610b105750505050565b6001600160a01b0384165f81815260036020526040812055610b33908483611e20565b604080516001600160a01b038087168252851660208201529081018290527f244e51bc38c1452fa8aaf487bcb4bca36c2baa3a5fbdb776b1eabd8dc6d277cd9060600160405180910390a1505b505050565b7fe2b7fb3b832174769106daebcfd6d1970523240dda11281102db9363b83b0dc4610baf81611e16565b60015f8581526005602052604090205460ff166004811115610bd357610bd3612e77565b14610c0a576040517f4145817200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f84815260056020908152604091829020805460027fffffffffffffffffffffffffffffffffffffffff0000000000000000000000009091166101004264ffffffffff16027fffffffffffffffffffffffffffffffffffffffff000000000000ffffffffffff161766010000000000004365ffffffffffff160217176bffffffffffffffffffffffff166c010000000000000000000000006001600160a01b0387169081029190911790915582518681529251909287927f4ac8af8a2cd87193d64dfc7a3b8d9923b714ec528b18725d080aa1299be0c5e492918290030190a350505050565b5f82815260208190526040902060010154610d0a81611e16565b610d148383611f3e565b50505050565b6001600160a01b0381163314610d5c576040517f6697b23200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610b808282611f71565b815160208301205f610d778461102c565b905060025f8381526005602052604090205460ff166004811115610d9d57610d9d612e77565b14610dd4576040517f4145817200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600160a01b038316610e10575f828152600560205260409020546c0100000000000000000000000090046001600160a01b03169250610e6f565b5f828152600560205260409020546c0100000000000000000000000090046001600160a01b03163314610e6f576040517f4af43a9000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f8281526005602052604090205461070890610100900464ffffffffff90811642031611610ec9576040517f1992d0bd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f82815260056020526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016600317905561010081015115610f415761010081015160808201516001600160a01b03165f9081526003602052604081208054909190610f3b90849061366e565b90915550505b608081015160c0820151610f5f6001600160a01b0383168683611e20565b5f848152600560209081526040918290205482516001600160a01b038681168252928101859052888316936c010000000000000000000000009092049092169187917f582211c35a2139ac3bbaac74663c6a1f56c6cbb658b41fe11fd45a82074ac678910160405180910390a4505050505050565b611029816040518060a001604052805f6001600160a01b031681526020015f815260200160405180602001604052805f81525081526020015f815260200160405180602001604052805f815250815250611ac4565b50565b6110d0604051806101e001604052805f63ffffffff1681526020015f63ffffffff1681526020015f6001600160a01b031681526020015f6001600160a01b031681526020015f6001600160a01b031681526020015f6001600160a01b031681526020015f81526020015f81526020015f81526020015f81526020015f81526020015f81526020015f6001600160a01b031681526020015f8152602001606081525090565b81806020019051810190610aba91906136d9565b805160208201205f6110f58361102c565b905060015f8381526005602052604090205460ff16600481111561111b5761111b612e77565b14611152576040517f4145817200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b335f9081527fd2043bf65931af3dbecf60d0db8f40e4160406d7beb00522f4200cf4944a1eb8602052604090205460ff16156111cb5780610140015142116111c6576040517fe15ff9ea00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611217565b62093a808161014001516111df919061366e565b4211611217576040517fe15ff9ea00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f8281526005602052604080822080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166004179055820151608083015161010084015160c08501519293919261126f919061366e565b90506112856001600160a01b0383168483611e20565b604080516001600160a01b0384811682526020820184905285169187917fb4c55c0c9bc613519b920e88748090150b890a875d307f21bea7d4fb2e8bc958910160405180910390a3505050505050565b6112e782805190602001208233610b85565b5050565b6110298133611313565b5f82815260016020526040812061130c9083611f9c565b9392505050565b815160208301205f6113248461102c565b9050611331818385611fa7565b604080516060808201835265ffffffffffff438116835242811660208085019182526001600160a01b03808a168688019081525f8a8152600690935296909120945185549251965182166c01000000000000000000000000026bffffffffffffffffffffffff9785166601000000000000027fffffffffffffffffffffffffffffffffffffffff000000000000000000000000909416919094161791909117949094161790915582015160a083015160e084015191929091907fffffffffffffffffffffffff11111111111111111111111111111111111111129083160161148e5761012084015115611450576040517f2598ad2e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b803414611489576040517f81de0bf300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6114e1565b83610120015134146114cc576040517f81de0bf300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6114e16001600160a01b038316338584612149565b6101c08401515115611503576114fe838383876101c001516121c5565b611513565b3415611513576115138334612321565b826001600160a01b0316866001600160a01b0316867ff8ae392d784b1ea5e8881bfa586d81abf07ef4f1e2fc75f7fe51c90f05199a5c875f015188608001518960a001518a60c001518b60e001518c61012001516040516115b09695949392919063ffffffff9690961686526001600160a01b0394851660208701529290931660408501526060840152608083019190915260a082015260c00190565b60405180910390a450505050505050565b5f60025f8481526005602052604090205460ff1660048111156115e6576115e6612e77565b1461161d576040517f4145817200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f838152600560205260409020546001600160a01b038381166c01000000000000000000000000909204161461167f576040517f4af43a9000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b50505f9081526005602052604090205461070861010090910464ffffffffff9081164203161190565b60408051610180810182525f80825260208201819052818301819052606082018190526080820181905260a0820181905260c0820181905260e0820181905261010082018190526101208201819052610140820181905261016082015290517f5aa6ccba0000000000000000000000000000000000000000000000000000000081523090635aa6ccba90611740908590600401613809565b5f60405180830381865afa92505050801561177c57506040513d5f823e601f3d908101601f1916820160405261177991908101906136d9565b60015b6117945781806020019051810190610aba9190613826565b604051806101800160405280825f015163ffffffff168152602001826020015163ffffffff16815260200182604001516001600160a01b0316815260200182606001516001600160a01b0316815260200182608001516001600160a01b031681526020018260a001516001600160a01b031681526020018260c0015181526020018260e00151815260200182610100015181526020018261012001515f1415151581526020018261014001518152602001826101600151815250915050919050565b919050565b7f043c983c49d46f0e102151eaf8085d4a2e6571d5df2d47b013f39bddfd4a639d61188581611e16565b60025f8381526005602052604090205460ff1660048111156118a9576118a9612e77565b146118e0576040517f4145817200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f8281526005602052604090205461070890610100900464ffffffffff908116420316111561193b576040517f3e908aac00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f828152600560205260408082206001905551339184917f0695cf1d39b3055dcd0fe02d8b47eaf0d5a13e1996de925de59d0ef9b7f7fad49190a35050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f556119a481611e16565b612710821115611a15576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f6e657746656552617465203e206d61780000000000000000000000000000000060448201526064015b60405180910390fd5b600280549083905560408051828152602081018590527f14914da2bf76024616fbe1859783fcd4dbddcb179b1f3a854949fbf920dcb95791015b60405180910390a1505050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f55611a8681611e16565b600480549083905560408051828152602081018590527f5cf09b12f3f56b4c564d51b25b40360af6d795198adb61ae0806a36c294323fa9101611a4f565b5f816020015142611ad591906138f0565b9050611ae28383836123e6565b5f611af584606001518560a00151612669565b90505f806002541115611b2157620f424060025483611b149190613917565b611b1e919061392e565b90505b611b2b8183613966565b91505f604051806101e001604052804663ffffffff168152602001875f015163ffffffff16815260200187602001516001600160a01b0316815260200187604001516001600160a01b0316815260200187606001516001600160a01b0316815260200187608001516001600160a01b031681526020018481526020018760c00151815260200183815260200186606001518152602001876101000151815260200160075f89602001516001600160a01b03166001600160a01b031681526020019081526020015f205f815480929190611c0390613979565b919050558152602001865f01516001600160a01b031681526020018581526020018660800151815250604051602001611c3c91906132dc565b60408051808303601f1901815282825280516020808301919091205f818152600583529390932080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016600117905589015189516060808c015160808d015160c08e0151928d015195985095966001600160a01b039094169587957f120ea0364f36cdac7983bcfdd55270ca09d7f9b314a2ebc425a3b01ab1d6403a95611cef958b95909493928e92901515906139b0565b60405180910390a3807f3120e2bb59c86aca6890191a589a96af3662838efa374fbdcdf4c95bfe4a6c0e8760400151604051611d2b9190613809565b60405180910390a250505050505050565b611029815f610d66565b5f818152600160205260408120610aba9061280d565b5f82815260208190526040902060010154611d7681611e16565b610d148383611f71565b5f7fffffffff0000000000000000000000000000000000000000000000000000000082167f7965db0b000000000000000000000000000000000000000000000000000000001480610aba57507f01ffc9a7000000000000000000000000000000000000000000000000000000007fffffffff00000000000000000000000000000000000000000000000000000000831614610aba565b6110298133612816565b306001600160a01b03831603611e3557505050565b805f03611e4157505050565b7fffffffffffffffffffffffff11111111111111111111111111111111111111126001600160a01b03841601611f2a575f826001600160a01b0316826040515f6040518083038185875af1925050503d805f8114611eba576040519150601f19603f3d011682016040523d82523d5f602084013e611ebf565b606091505b5050905080610d14576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f455448207472616e73666572206661696c6564000000000000000000000000006044820152606401611a0c565b610b806001600160a01b0384168383612881565b5f80611f4a84846128b2565b9050801561130c575f848152600160205260409020611f699084612977565b509392505050565b5f80611f7d848461298b565b9050801561130c575f848152600160205260409020611f699084612a2a565b5f61130c8383612a3e565b6001600160a01b038116611fe7576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f828152600660205260409020546c0100000000000000000000000090046001600160a01b031615612045576040517fbef7bb7d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b4663ffffffff16836020015163ffffffff161461208e576040517f7029fdf900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8261014001514211156120cd576040517f559895a300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6101808301516001600160a01b0316158015906121015750806001600160a01b03168361018001516001600160a01b031614155b80156121125750826101a001514211155b15610b80576040517f14be123200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040516001600160a01b038481166024830152838116604483015260648201839052610d149186918216906323b872dd906084015b604051602081830303815290604052915060e01b6020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8381831617835250505050612a64565b5f8383836040516024016121db93929190613a05565b60408051601f198184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f461e0c210000000000000000000000000000000000000000000000000000000017905290505f612241868334612ade565b905080515f0361227d576040517f1a95ad2600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80516020146122b8576040517ff3725cca00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f461e0c21000000000000000000000000000000000000000000000000000000006122e282613a35565b14612319576040517ff3725cca00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b505050505050565b8047101561235d576040517fcd786059000000000000000000000000000000000000000000000000000000008152306004820152602401611a0c565b5f826001600160a01b0316826040515f6040518083038185875af1925050503d805f81146123a6576040519150601f19603f3d011682016040523d82523d5f602084013e6123ab565b606091505b5050905080610b80576040517f1425ea4200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b46835f015163ffffffff1603612428576040517f7029fdf900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60a0830151158061243b575060c0830151155b15612472576040517fe38820c800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60208301516001600160a01b03161580612497575060408301516001600160a01b0316155b156124ce576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60608301516001600160a01b031615806124f3575060808301516001600160a01b0316155b1561252a576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6125366107084261366e565b8361010001511015612574576040517f04b7fcc800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61ffff82608001515111156125b5576040517ffbe24d4900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6060820151158015906125e8575060808301516001600160a01b031673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee145b1561261f576040517f2598ad2e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f81131580612632575082610100015181135b15610b80576040517f352807b900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f7fffffffffffffffffffffffff11111111111111111111111111111111111111126001600160a01b038416016126da573482146126d3576040517f81de0bf300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5034610aba565b6126ec836001600160a01b0316612b90565b6040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201526001600160a01b038416906370a0823190602401602060405180830381865afa158015612747573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061276b9190613a7a565b90506127826001600160a01b038416333085612149565b6040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015281906001600160a01b038516906370a0823190602401602060405180830381865afa1580156127df573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906128039190613a7a565b61130c9190613966565b5f610aba825490565b5f828152602081815260408083206001600160a01b038516845290915290205460ff166112e7576040517fe2517d3f0000000000000000000000000000000000000000000000000000000081526001600160a01b038216600482015260248101839052604401611a0c565b6040516001600160a01b03838116602483015260448201839052610b8091859182169063a9059cbb9060640161217e565b5f828152602081815260408083206001600160a01b038516845290915281205460ff16612970575f838152602081815260408083206001600160a01b0386168452909152902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790556129283390565b6001600160a01b0316826001600160a01b0316847f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a4506001610aba565b505f610aba565b5f61130c836001600160a01b038416612c35565b5f828152602081815260408083206001600160a01b038516845290915281205460ff1615612970575f838152602081815260408083206001600160a01b038616808552925280832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016905551339286917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a4506001610aba565b5f61130c836001600160a01b038416612c7a565b5f825f018281548110612a5357612a53613a91565b905f5260205f200154905092915050565b5f612a786001600160a01b03841683612d5d565b905080515f14158015612a9c575080806020019051810190612a9a9190613abe565b155b15610b80576040517f5274afe70000000000000000000000000000000000000000000000000000000081526001600160a01b0384166004820152602401611a0c565b606081471015612b1c576040517fcd786059000000000000000000000000000000000000000000000000000000008152306004820152602401611a0c565b5f80856001600160a01b03168486604051612b379190613ad9565b5f6040518083038185875af1925050503d805f8114612b71576040519150601f19603f3d011682016040523d82523d5f602084013e612b76565b606091505b5091509150612b86868383612d6a565b9695505050505050565b7fffffffffffffffffffffffff11111111111111111111111111111111111111126001600160a01b03821601612bf2576040517f7f523fe800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b806001600160a01b03163b5f03611029576040517f7f523fe800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f81815260018301602052604081205461297057508154600181810184555f848152602080822090930184905584548482528286019093526040902091909155610aba565b5f8181526001830160205260408120548015612d54575f612c9c600183613966565b85549091505f90612caf90600190613966565b9050808214612d0e575f865f018281548110612ccd57612ccd613a91565b905f5260205f200154905080875f018481548110612ced57612ced613a91565b5f918252602080832090910192909255918252600188019052604090208390555b8554869080612d1f57612d1f613af4565b600190038181905f5260205f20015f90559055856001015f8681526020019081526020015f205f905560019350505050610aba565b5f915050610aba565b606061130c83835f612ade565b606082612d7f57612d7a82612ddf565b61130c565b8151158015612d9657506001600160a01b0384163b155b15612dd8576040517f9996b3150000000000000000000000000000000000000000000000000000000081526001600160a01b0385166004820152602401611a0c565b508061130c565b805115612def5780518082602001fd5b6040517f1425ea4200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f60208284031215612e31575f80fd5b81357fffffffff000000000000000000000000000000000000000000000000000000008116811461130c575f80fd5b5f60208284031215612e70575f80fd5b5035919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602160045260245ffd5b60058110612ed9577f4e487b71000000000000000000000000000000000000000000000000000000005f52602160045260245ffd5b9052565b60208101610aba8284612ea4565b6001600160a01b0381168114611029575f80fd5b803561185681612eeb565b5f8060408385031215612f1b575f80fd5b8235612f2681612eeb565b91506020830135612f3681612eeb565b809150509250929050565b5f805f60608486031215612f53575f80fd5b83359250602084013591506040840135612f6c81612eeb565b809150509250925092565b5f60208284031215612f87575f80fd5b813561130c81612eeb565b5f8060408385031215612fa3575f80fd5b823591506020830135612f3681612eeb565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b604051610120810167ffffffffffffffff8111828210171561300657613006612fb5565b60405290565b60405160a0810167ffffffffffffffff8111828210171561300657613006612fb5565b6040516101e0810167ffffffffffffffff8111828210171561300657613006612fb5565b604051610180810167ffffffffffffffff8111828210171561300657613006612fb5565b604051601f8201601f1916810167ffffffffffffffff811182821017156130a0576130a0612fb5565b604052919050565b5f67ffffffffffffffff8211156130c1576130c1612fb5565b50601f01601f191660200190565b5f82601f8301126130de575f80fd5b81356130f16130ec826130a8565b613077565b818152846020838601011115613105575f80fd5b816020850160208301375f918101602001919091529392505050565b5f8060408385031215613132575f80fd5b823567ffffffffffffffff811115613148575f80fd5b613154858286016130cf565b9250506020830135612f3681612eeb565b63ffffffff81168114611029575f80fd5b803561185681613165565b8015158114611029575f80fd5b803561185681613181565b5f61012082840312156131aa575f80fd5b6131b2612fe2565b90506131bd82613176565b81526131cb60208301612eff565b60208201526131dc60408301612eff565b60408201526131ed60608301612eff565b60608201526131fe60808301612eff565b608082015260a082013560a082015260c082013560c082015261322360e0830161318e565b60e082015261010080830135818301525092915050565b5f610120828403121561324b575f80fd5b61130c8383613199565b5f60208284031215613265575f80fd5b813567ffffffffffffffff81111561327b575f80fd5b613287848285016130cf565b949350505050565b5f5b838110156132a9578181015183820152602001613291565b50505f910152565b5f81518084526132c881602086016020860161328f565b601f01601f19169290920160200192915050565b602081526132f360208201835163ffffffff169052565b5f602083015161330b604084018263ffffffff169052565b5060408301516001600160a01b03811660608401525060608301516001600160a01b03811660808401525060808301516001600160a01b03811660a08401525060a08301516001600160a01b03811660c08401525060c083015160e08381019190915283015161010080840191909152830151610120808401919091528301516101408084019190915283015161016080840191909152830151610180808401919091528301516101a06133c9818501836001600160a01b03169052565b8401516101c0848101919091528401516101e08085015290506132876102008401826132b1565b608081016133fe8287612ea4565b64ffffffffff8516602083015265ffffffffffff841660408301526001600160a01b038316606083015295945050505050565b5f8060408385031215613442575f80fd5b823567ffffffffffffffff811115613458575f80fd5b613464858286016130cf565b95602094909401359450505050565b5f8060408385031215613484575f80fd5b50508035926020909101359150565b815163ffffffff168152610180810160208301516134b9602084018263ffffffff169052565b5060408301516134d460408401826001600160a01b03169052565b5060608301516134ef60608401826001600160a01b03169052565b50608083015161350a60808401826001600160a01b03169052565b5060a083015161352560a08401826001600160a01b03169052565b5060c083015160c083015260e083015160e08301526101008084015181840152506101208084015161355a8285018215159052565b5050610140838101519083015261016092830151929091019190915290565b5f80610140838503121561358b575f80fd5b6135958484613199565b915061012083013567ffffffffffffffff808211156135b2575f80fd5b9084019060a082870312156135c5575f80fd5b6135cd61300c565b82356135d881612eeb565b8152602083810135908201526040830135828111156135f5575f80fd5b613601888286016130cf565b60408301525060608301356060820152608083013582811115613622575f80fd5b61362e888286016130cf565b6080830152508093505050509250929050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b80820180821115610aba57610aba613641565b805161185681613165565b805161185681612eeb565b5f82601f8301126136a6575f80fd5b81516136b46130ec826130a8565b8181528460208386010111156136c8575f80fd5b61328782602083016020870161328f565b5f602082840312156136e9575f80fd5b815167ffffffffffffffff80821115613700575f80fd5b908301906101e08286031215613714575f80fd5b61371c61302f565b61372583613681565b815261373360208401613681565b60208201526137446040840161368c565b60408201526137556060840161368c565b60608201526137666080840161368c565b608082015261377760a0840161368c565b60a082015260c0838101519082015260e0808401519082015261010080840151908201526101208084015190820152610140808401519082015261016080840151908201526101806137ca81850161368c565b908201526101a083810151908201526101c080840151838111156137ec575f80fd5b6137f888828701613697565b918301919091525095945050505050565b602081525f61130c60208301846132b1565b805161185681613181565b5f6101808284031215613837575f80fd5b61383f613053565b61384883613681565b815261385660208401613681565b60208201526138676040840161368c565b60408201526138786060840161368c565b60608201526138896080840161368c565b608082015261389a60a0840161368c565b60a082015260c083015160c082015260e083015160e08201526101008084015181830152506101206138cd81850161381b565b908201526101408381015190820152610160928301519281019290925250919050565b8082018281125f83128015821682158216171561390f5761390f613641565b505092915050565b8082028115828204841417610aba57610aba613641565b5f82613961577f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b500490565b81810381811115610aba57610aba613641565b5f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82036139a9576139a9613641565b5060010190565b60e081525f6139c260e083018a6132b1565b63ffffffff989098166020830152506001600160a01b039586166040820152939094166060840152608083019190915260a082015290151560c090910152919050565b6001600160a01b0384168152826020820152606060408201525f613a2c60608301846132b1565b95945050505050565b80516020808301519190811015613a74577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8160200360031b1b821691505b50919050565b5f60208284031215613a8a575f80fd5b5051919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b5f60208284031215613ace575f80fd5b815161130c81613181565b5f8251613aea81846020870161328f565b9190910192915050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603160045260245ffdfea264697066735822122007a09ea15c5efbb28f239593161aeb6ee596d67bad8a87d0cd46703d115a053164736f6c63430008180033","runtime-code":"0x6080604052600436106102ed575f3560e01c806391ad503911610186578063b13aa2d6116100dc578063ca15c87311610087578063dcf844a711610062578063dcf844a714610a10578063df36bb1314610a3b578063e00a83e014610a50575f80fd5b8063ca15c8731461099f578063ccc57490146109be578063d547741f146109f1575f80fd5b8063bfc7c607116100b7578063bfc7c607146108e2578063c63ff8dd146108f5578063c79371b114610914575f80fd5b8063b13aa2d61461088e578063b250fe6b146108ad578063bf333f2c146108cc575f80fd5b8063a3ec191a1161013c578063ac11fb1a11610117578063ac11fb1a14610810578063add98c701461083c578063affed0e01461085b575f80fd5b8063a3ec191a146107be578063a5bbe22b146105e1578063aa9641ab146107f1575f80fd5b8063926d7d7f1161016c578063926d7d7f146107655780639c9545f014610798578063a217fddf146107ab575f80fd5b806391ad5039146106a557806391d1485414610723575f80fd5b806341fcb6121161024657806363787e52116101f1578063886d36ff116101cc578063886d36ff1461063c5780638f0d6f171461065b5780639010d07c1461066e575f80fd5b806363787e5214610568578063820688d5146105e15780638379a24f146105f6575f80fd5b80635960ccf2116102215780635960ccf2146104ea5780635aa6ccba1461051d5780635eb7d94614610549575f80fd5b806341fcb612146104a357806345851694146104c257806358f85880146104d5575f80fd5b806318e4357d116102a6578063295710ff11610281578063295710ff1461043a5780632f2ff15d1461046557806336568abe14610484575f80fd5b806318e4357d146103d7578063190da595146103f6578063248a9ca31461040c575f80fd5b8063051287bc116102d6578063051287bc1461036657806306f333f2146103a15780630f5f6ed7146103c2575f80fd5b806301ffc9a7146102f157806303ed0ee514610325575b5f80fd5b3480156102fc575f80fd5b5061031061030b366004612e21565b610a65565b60405190151581526020015b60405180910390f35b348015610330575f80fd5b506103587f043c983c49d46f0e102151eaf8085d4a2e6571d5df2d47b013f39bddfd4a639d81565b60405190815260200161031c565b348015610371575f80fd5b50610394610380366004612e60565b5f9081526005602052604090205460ff1690565b60405161031c9190612edd565b3480156103ac575f80fd5b506103c06103bb366004612f0a565b610ac0565b005b3480156103cd575f80fd5b5061035861271081565b3480156103e2575f80fd5b506103c06103f1366004612f41565b610b85565b348015610401575f80fd5b5061035862093a8081565b348015610417575f80fd5b50610358610426366004612e60565b5f9081526020819052604090206001015490565b348015610445575f80fd5b50610358610454366004612f77565b60076020525f908152604090205481565b348015610470575f80fd5b506103c061047f366004612f92565b610cf0565b34801561048f575f80fd5b506103c061049e366004612f92565b610d1a565b3480156104ae575f80fd5b506103c06104bd366004613121565b610d66565b6103c06104d036600461323a565b610fd4565b3480156104e0575f80fd5b5061035860025481565b3480156104f5575f80fd5b506103587fdb9556138406326f00296e13ea2ad7db24ba82381212d816b1a40c23b466b32781565b348015610528575f80fd5b5061053c610537366004613255565b61102c565b60405161031c91906132dc565b348015610554575f80fd5b506103c0610563366004613255565b6110e4565b348015610573575f80fd5b506105d1610582366004612e60565b60056020525f908152604090205460ff811690610100810464ffffffffff16906601000000000000810465ffffffffffff16906c0100000000000000000000000090046001600160a01b031684565b60405161031c94939291906133f0565b3480156105ec575f80fd5b5061035861070881565b348015610601575f80fd5b50610310610610366004612e60565b5f908152600660205260409020546c0100000000000000000000000090046001600160a01b0316151590565b348015610647575f80fd5b506103c0610656366004613431565b6112d5565b6103c0610669366004613255565b6112eb565b348015610679575f80fd5b5061068d610688366004613473565b6112f5565b6040516001600160a01b03909116815260200161031c565b3480156106b0575f80fd5b506106f76106bf366004612e60565b5f90815260056020526040902054610100810464ffffffffff16916c010000000000000000000000009091046001600160a01b031690565b604080516bffffffffffffffffffffffff90931683526001600160a01b0390911660208301520161031c565b34801561072e575f80fd5b5061031061073d366004612f92565b5f918252602082815260408084206001600160a01b0393909316845291905290205460ff1690565b348015610770575f80fd5b506103587fe2b7fb3b832174769106daebcfd6d1970523240dda11281102db9363b83b0dc481565b6103c06107a6366004613121565b611313565b3480156107b6575f80fd5b506103585f81565b3480156107c9575f80fd5b506103587f000000000000000000000000000000000000000000000000000000000000000081565b3480156107fc575f80fd5b5061031061080b366004612f92565b6115c1565b34801561081b575f80fd5b5061082f61082a366004613255565b6116a8565b60405161031c9190613493565b348015610847575f80fd5b506103c0610856366004612e60565b61185b565b348015610866575f80fd5b506103587f000000000000000000000000000000000000000000000000000000000000000081565b348015610899575f80fd5b506103c06108a8366004612e60565b61197a565b3480156108b8575f80fd5b506103c06108c7366004612e60565b611a5c565b3480156108d7575f80fd5b50610358620f424081565b6103c06108f0366004613579565b611ac4565b348015610900575f80fd5b506103c061090f366004613255565b611d3c565b34801561091f575f80fd5b5061097161092e366004612e60565b60066020525f908152604090205465ffffffffffff8082169166010000000000008104909116906c0100000000000000000000000090046001600160a01b031683565b6040805165ffffffffffff94851681529390921660208401526001600160a01b03169082015260600161031c565b3480156109aa575f80fd5b506103586109b9366004612e60565b611d46565b3480156109c9575f80fd5b506103587f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f5581565b3480156109fc575f80fd5b506103c0610a0b366004612f92565b611d5c565b348015610a1b575f80fd5b50610358610a2a366004612f77565b60036020525f908152604090205481565b348015610a46575f80fd5b5061035861ffff81565b348015610a5b575f80fd5b5061035860045481565b5f7fffffffff0000000000000000000000000000000000000000000000000000000082167f5a05180f000000000000000000000000000000000000000000000000000000001480610aba5750610aba82611d80565b92915050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f55610aea81611e16565b6001600160a01b0383165f9081526003602052604081205490819003610b105750505050565b6001600160a01b0384165f81815260036020526040812055610b33908483611e20565b604080516001600160a01b038087168252851660208201529081018290527f244e51bc38c1452fa8aaf487bcb4bca36c2baa3a5fbdb776b1eabd8dc6d277cd9060600160405180910390a1505b505050565b7fe2b7fb3b832174769106daebcfd6d1970523240dda11281102db9363b83b0dc4610baf81611e16565b60015f8581526005602052604090205460ff166004811115610bd357610bd3612e77565b14610c0a576040517f4145817200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f84815260056020908152604091829020805460027fffffffffffffffffffffffffffffffffffffffff0000000000000000000000009091166101004264ffffffffff16027fffffffffffffffffffffffffffffffffffffffff000000000000ffffffffffff161766010000000000004365ffffffffffff160217176bffffffffffffffffffffffff166c010000000000000000000000006001600160a01b0387169081029190911790915582518681529251909287927f4ac8af8a2cd87193d64dfc7a3b8d9923b714ec528b18725d080aa1299be0c5e492918290030190a350505050565b5f82815260208190526040902060010154610d0a81611e16565b610d148383611f3e565b50505050565b6001600160a01b0381163314610d5c576040517f6697b23200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610b808282611f71565b815160208301205f610d778461102c565b905060025f8381526005602052604090205460ff166004811115610d9d57610d9d612e77565b14610dd4576040517f4145817200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600160a01b038316610e10575f828152600560205260409020546c0100000000000000000000000090046001600160a01b03169250610e6f565b5f828152600560205260409020546c0100000000000000000000000090046001600160a01b03163314610e6f576040517f4af43a9000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f8281526005602052604090205461070890610100900464ffffffffff90811642031611610ec9576040517f1992d0bd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f82815260056020526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016600317905561010081015115610f415761010081015160808201516001600160a01b03165f9081526003602052604081208054909190610f3b90849061366e565b90915550505b608081015160c0820151610f5f6001600160a01b0383168683611e20565b5f848152600560209081526040918290205482516001600160a01b038681168252928101859052888316936c010000000000000000000000009092049092169187917f582211c35a2139ac3bbaac74663c6a1f56c6cbb658b41fe11fd45a82074ac678910160405180910390a4505050505050565b611029816040518060a001604052805f6001600160a01b031681526020015f815260200160405180602001604052805f81525081526020015f815260200160405180602001604052805f815250815250611ac4565b50565b6110d0604051806101e001604052805f63ffffffff1681526020015f63ffffffff1681526020015f6001600160a01b031681526020015f6001600160a01b031681526020015f6001600160a01b031681526020015f6001600160a01b031681526020015f81526020015f81526020015f81526020015f81526020015f81526020015f81526020015f6001600160a01b031681526020015f8152602001606081525090565b81806020019051810190610aba91906136d9565b805160208201205f6110f58361102c565b905060015f8381526005602052604090205460ff16600481111561111b5761111b612e77565b14611152576040517f4145817200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b335f9081527fd2043bf65931af3dbecf60d0db8f40e4160406d7beb00522f4200cf4944a1eb8602052604090205460ff16156111cb5780610140015142116111c6576040517fe15ff9ea00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611217565b62093a808161014001516111df919061366e565b4211611217576040517fe15ff9ea00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f8281526005602052604080822080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166004179055820151608083015161010084015160c08501519293919261126f919061366e565b90506112856001600160a01b0383168483611e20565b604080516001600160a01b0384811682526020820184905285169187917fb4c55c0c9bc613519b920e88748090150b890a875d307f21bea7d4fb2e8bc958910160405180910390a3505050505050565b6112e782805190602001208233610b85565b5050565b6110298133611313565b5f82815260016020526040812061130c9083611f9c565b9392505050565b815160208301205f6113248461102c565b9050611331818385611fa7565b604080516060808201835265ffffffffffff438116835242811660208085019182526001600160a01b03808a168688019081525f8a8152600690935296909120945185549251965182166c01000000000000000000000000026bffffffffffffffffffffffff9785166601000000000000027fffffffffffffffffffffffffffffffffffffffff000000000000000000000000909416919094161791909117949094161790915582015160a083015160e084015191929091907fffffffffffffffffffffffff11111111111111111111111111111111111111129083160161148e5761012084015115611450576040517f2598ad2e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b803414611489576040517f81de0bf300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6114e1565b83610120015134146114cc576040517f81de0bf300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6114e16001600160a01b038316338584612149565b6101c08401515115611503576114fe838383876101c001516121c5565b611513565b3415611513576115138334612321565b826001600160a01b0316866001600160a01b0316867ff8ae392d784b1ea5e8881bfa586d81abf07ef4f1e2fc75f7fe51c90f05199a5c875f015188608001518960a001518a60c001518b60e001518c61012001516040516115b09695949392919063ffffffff9690961686526001600160a01b0394851660208701529290931660408501526060840152608083019190915260a082015260c00190565b60405180910390a450505050505050565b5f60025f8481526005602052604090205460ff1660048111156115e6576115e6612e77565b1461161d576040517f4145817200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f838152600560205260409020546001600160a01b038381166c01000000000000000000000000909204161461167f576040517f4af43a9000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b50505f9081526005602052604090205461070861010090910464ffffffffff9081164203161190565b60408051610180810182525f80825260208201819052818301819052606082018190526080820181905260a0820181905260c0820181905260e0820181905261010082018190526101208201819052610140820181905261016082015290517f5aa6ccba0000000000000000000000000000000000000000000000000000000081523090635aa6ccba90611740908590600401613809565b5f60405180830381865afa92505050801561177c57506040513d5f823e601f3d908101601f1916820160405261177991908101906136d9565b60015b6117945781806020019051810190610aba9190613826565b604051806101800160405280825f015163ffffffff168152602001826020015163ffffffff16815260200182604001516001600160a01b0316815260200182606001516001600160a01b0316815260200182608001516001600160a01b031681526020018260a001516001600160a01b031681526020018260c0015181526020018260e00151815260200182610100015181526020018261012001515f1415151581526020018261014001518152602001826101600151815250915050919050565b919050565b7f043c983c49d46f0e102151eaf8085d4a2e6571d5df2d47b013f39bddfd4a639d61188581611e16565b60025f8381526005602052604090205460ff1660048111156118a9576118a9612e77565b146118e0576040517f4145817200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f8281526005602052604090205461070890610100900464ffffffffff908116420316111561193b576040517f3e908aac00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f828152600560205260408082206001905551339184917f0695cf1d39b3055dcd0fe02d8b47eaf0d5a13e1996de925de59d0ef9b7f7fad49190a35050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f556119a481611e16565b612710821115611a15576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f6e657746656552617465203e206d61780000000000000000000000000000000060448201526064015b60405180910390fd5b600280549083905560408051828152602081018590527f14914da2bf76024616fbe1859783fcd4dbddcb179b1f3a854949fbf920dcb95791015b60405180910390a1505050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f55611a8681611e16565b600480549083905560408051828152602081018590527f5cf09b12f3f56b4c564d51b25b40360af6d795198adb61ae0806a36c294323fa9101611a4f565b5f816020015142611ad591906138f0565b9050611ae28383836123e6565b5f611af584606001518560a00151612669565b90505f806002541115611b2157620f424060025483611b149190613917565b611b1e919061392e565b90505b611b2b8183613966565b91505f604051806101e001604052804663ffffffff168152602001875f015163ffffffff16815260200187602001516001600160a01b0316815260200187604001516001600160a01b0316815260200187606001516001600160a01b0316815260200187608001516001600160a01b031681526020018481526020018760c00151815260200183815260200186606001518152602001876101000151815260200160075f89602001516001600160a01b03166001600160a01b031681526020019081526020015f205f815480929190611c0390613979565b919050558152602001865f01516001600160a01b031681526020018581526020018660800151815250604051602001611c3c91906132dc565b60408051808303601f1901815282825280516020808301919091205f818152600583529390932080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016600117905589015189516060808c015160808d015160c08e0151928d015195985095966001600160a01b039094169587957f120ea0364f36cdac7983bcfdd55270ca09d7f9b314a2ebc425a3b01ab1d6403a95611cef958b95909493928e92901515906139b0565b60405180910390a3807f3120e2bb59c86aca6890191a589a96af3662838efa374fbdcdf4c95bfe4a6c0e8760400151604051611d2b9190613809565b60405180910390a250505050505050565b611029815f610d66565b5f818152600160205260408120610aba9061280d565b5f82815260208190526040902060010154611d7681611e16565b610d148383611f71565b5f7fffffffff0000000000000000000000000000000000000000000000000000000082167f7965db0b000000000000000000000000000000000000000000000000000000001480610aba57507f01ffc9a7000000000000000000000000000000000000000000000000000000007fffffffff00000000000000000000000000000000000000000000000000000000831614610aba565b6110298133612816565b306001600160a01b03831603611e3557505050565b805f03611e4157505050565b7fffffffffffffffffffffffff11111111111111111111111111111111111111126001600160a01b03841601611f2a575f826001600160a01b0316826040515f6040518083038185875af1925050503d805f8114611eba576040519150601f19603f3d011682016040523d82523d5f602084013e611ebf565b606091505b5050905080610d14576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f455448207472616e73666572206661696c6564000000000000000000000000006044820152606401611a0c565b610b806001600160a01b0384168383612881565b5f80611f4a84846128b2565b9050801561130c575f848152600160205260409020611f699084612977565b509392505050565b5f80611f7d848461298b565b9050801561130c575f848152600160205260409020611f699084612a2a565b5f61130c8383612a3e565b6001600160a01b038116611fe7576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f828152600660205260409020546c0100000000000000000000000090046001600160a01b031615612045576040517fbef7bb7d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b4663ffffffff16836020015163ffffffff161461208e576040517f7029fdf900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8261014001514211156120cd576040517f559895a300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6101808301516001600160a01b0316158015906121015750806001600160a01b03168361018001516001600160a01b031614155b80156121125750826101a001514211155b15610b80576040517f14be123200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040516001600160a01b038481166024830152838116604483015260648201839052610d149186918216906323b872dd906084015b604051602081830303815290604052915060e01b6020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8381831617835250505050612a64565b5f8383836040516024016121db93929190613a05565b60408051601f198184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f461e0c210000000000000000000000000000000000000000000000000000000017905290505f612241868334612ade565b905080515f0361227d576040517f1a95ad2600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80516020146122b8576040517ff3725cca00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f461e0c21000000000000000000000000000000000000000000000000000000006122e282613a35565b14612319576040517ff3725cca00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b505050505050565b8047101561235d576040517fcd786059000000000000000000000000000000000000000000000000000000008152306004820152602401611a0c565b5f826001600160a01b0316826040515f6040518083038185875af1925050503d805f81146123a6576040519150601f19603f3d011682016040523d82523d5f602084013e6123ab565b606091505b5050905080610b80576040517f1425ea4200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b46835f015163ffffffff1603612428576040517f7029fdf900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60a0830151158061243b575060c0830151155b15612472576040517fe38820c800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60208301516001600160a01b03161580612497575060408301516001600160a01b0316155b156124ce576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60608301516001600160a01b031615806124f3575060808301516001600160a01b0316155b1561252a576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6125366107084261366e565b8361010001511015612574576040517f04b7fcc800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61ffff82608001515111156125b5576040517ffbe24d4900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6060820151158015906125e8575060808301516001600160a01b031673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee145b1561261f576040517f2598ad2e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f81131580612632575082610100015181135b15610b80576040517f352807b900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f7fffffffffffffffffffffffff11111111111111111111111111111111111111126001600160a01b038416016126da573482146126d3576040517f81de0bf300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5034610aba565b6126ec836001600160a01b0316612b90565b6040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201526001600160a01b038416906370a0823190602401602060405180830381865afa158015612747573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061276b9190613a7a565b90506127826001600160a01b038416333085612149565b6040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015281906001600160a01b038516906370a0823190602401602060405180830381865afa1580156127df573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906128039190613a7a565b61130c9190613966565b5f610aba825490565b5f828152602081815260408083206001600160a01b038516845290915290205460ff166112e7576040517fe2517d3f0000000000000000000000000000000000000000000000000000000081526001600160a01b038216600482015260248101839052604401611a0c565b6040516001600160a01b03838116602483015260448201839052610b8091859182169063a9059cbb9060640161217e565b5f828152602081815260408083206001600160a01b038516845290915281205460ff16612970575f838152602081815260408083206001600160a01b0386168452909152902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790556129283390565b6001600160a01b0316826001600160a01b0316847f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a4506001610aba565b505f610aba565b5f61130c836001600160a01b038416612c35565b5f828152602081815260408083206001600160a01b038516845290915281205460ff1615612970575f838152602081815260408083206001600160a01b038616808552925280832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016905551339286917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a4506001610aba565b5f61130c836001600160a01b038416612c7a565b5f825f018281548110612a5357612a53613a91565b905f5260205f200154905092915050565b5f612a786001600160a01b03841683612d5d565b905080515f14158015612a9c575080806020019051810190612a9a9190613abe565b155b15610b80576040517f5274afe70000000000000000000000000000000000000000000000000000000081526001600160a01b0384166004820152602401611a0c565b606081471015612b1c576040517fcd786059000000000000000000000000000000000000000000000000000000008152306004820152602401611a0c565b5f80856001600160a01b03168486604051612b379190613ad9565b5f6040518083038185875af1925050503d805f8114612b71576040519150601f19603f3d011682016040523d82523d5f602084013e612b76565b606091505b5091509150612b86868383612d6a565b9695505050505050565b7fffffffffffffffffffffffff11111111111111111111111111111111111111126001600160a01b03821601612bf2576040517f7f523fe800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b806001600160a01b03163b5f03611029576040517f7f523fe800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f81815260018301602052604081205461297057508154600181810184555f848152602080822090930184905584548482528286019093526040902091909155610aba565b5f8181526001830160205260408120548015612d54575f612c9c600183613966565b85549091505f90612caf90600190613966565b9050808214612d0e575f865f018281548110612ccd57612ccd613a91565b905f5260205f200154905080875f018481548110612ced57612ced613a91565b5f918252602080832090910192909255918252600188019052604090208390555b8554869080612d1f57612d1f613af4565b600190038181905f5260205f20015f90559055856001015f8681526020019081526020015f205f905560019350505050610aba565b5f915050610aba565b606061130c83835f612ade565b606082612d7f57612d7a82612ddf565b61130c565b8151158015612d9657506001600160a01b0384163b155b15612dd8576040517f9996b3150000000000000000000000000000000000000000000000000000000081526001600160a01b0385166004820152602401611a0c565b508061130c565b805115612def5780518082602001fd5b6040517f1425ea4200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f60208284031215612e31575f80fd5b81357fffffffff000000000000000000000000000000000000000000000000000000008116811461130c575f80fd5b5f60208284031215612e70575f80fd5b5035919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602160045260245ffd5b60058110612ed9577f4e487b71000000000000000000000000000000000000000000000000000000005f52602160045260245ffd5b9052565b60208101610aba8284612ea4565b6001600160a01b0381168114611029575f80fd5b803561185681612eeb565b5f8060408385031215612f1b575f80fd5b8235612f2681612eeb565b91506020830135612f3681612eeb565b809150509250929050565b5f805f60608486031215612f53575f80fd5b83359250602084013591506040840135612f6c81612eeb565b809150509250925092565b5f60208284031215612f87575f80fd5b813561130c81612eeb565b5f8060408385031215612fa3575f80fd5b823591506020830135612f3681612eeb565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b604051610120810167ffffffffffffffff8111828210171561300657613006612fb5565b60405290565b60405160a0810167ffffffffffffffff8111828210171561300657613006612fb5565b6040516101e0810167ffffffffffffffff8111828210171561300657613006612fb5565b604051610180810167ffffffffffffffff8111828210171561300657613006612fb5565b604051601f8201601f1916810167ffffffffffffffff811182821017156130a0576130a0612fb5565b604052919050565b5f67ffffffffffffffff8211156130c1576130c1612fb5565b50601f01601f191660200190565b5f82601f8301126130de575f80fd5b81356130f16130ec826130a8565b613077565b818152846020838601011115613105575f80fd5b816020850160208301375f918101602001919091529392505050565b5f8060408385031215613132575f80fd5b823567ffffffffffffffff811115613148575f80fd5b613154858286016130cf565b9250506020830135612f3681612eeb565b63ffffffff81168114611029575f80fd5b803561185681613165565b8015158114611029575f80fd5b803561185681613181565b5f61012082840312156131aa575f80fd5b6131b2612fe2565b90506131bd82613176565b81526131cb60208301612eff565b60208201526131dc60408301612eff565b60408201526131ed60608301612eff565b60608201526131fe60808301612eff565b608082015260a082013560a082015260c082013560c082015261322360e0830161318e565b60e082015261010080830135818301525092915050565b5f610120828403121561324b575f80fd5b61130c8383613199565b5f60208284031215613265575f80fd5b813567ffffffffffffffff81111561327b575f80fd5b613287848285016130cf565b949350505050565b5f5b838110156132a9578181015183820152602001613291565b50505f910152565b5f81518084526132c881602086016020860161328f565b601f01601f19169290920160200192915050565b602081526132f360208201835163ffffffff169052565b5f602083015161330b604084018263ffffffff169052565b5060408301516001600160a01b03811660608401525060608301516001600160a01b03811660808401525060808301516001600160a01b03811660a08401525060a08301516001600160a01b03811660c08401525060c083015160e08381019190915283015161010080840191909152830151610120808401919091528301516101408084019190915283015161016080840191909152830151610180808401919091528301516101a06133c9818501836001600160a01b03169052565b8401516101c0848101919091528401516101e08085015290506132876102008401826132b1565b608081016133fe8287612ea4565b64ffffffffff8516602083015265ffffffffffff841660408301526001600160a01b038316606083015295945050505050565b5f8060408385031215613442575f80fd5b823567ffffffffffffffff811115613458575f80fd5b613464858286016130cf565b95602094909401359450505050565b5f8060408385031215613484575f80fd5b50508035926020909101359150565b815163ffffffff168152610180810160208301516134b9602084018263ffffffff169052565b5060408301516134d460408401826001600160a01b03169052565b5060608301516134ef60608401826001600160a01b03169052565b50608083015161350a60808401826001600160a01b03169052565b5060a083015161352560a08401826001600160a01b03169052565b5060c083015160c083015260e083015160e08301526101008084015181840152506101208084015161355a8285018215159052565b5050610140838101519083015261016092830151929091019190915290565b5f80610140838503121561358b575f80fd5b6135958484613199565b915061012083013567ffffffffffffffff808211156135b2575f80fd5b9084019060a082870312156135c5575f80fd5b6135cd61300c565b82356135d881612eeb565b8152602083810135908201526040830135828111156135f5575f80fd5b613601888286016130cf565b60408301525060608301356060820152608083013582811115613622575f80fd5b61362e888286016130cf565b6080830152508093505050509250929050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b80820180821115610aba57610aba613641565b805161185681613165565b805161185681612eeb565b5f82601f8301126136a6575f80fd5b81516136b46130ec826130a8565b8181528460208386010111156136c8575f80fd5b61328782602083016020870161328f565b5f602082840312156136e9575f80fd5b815167ffffffffffffffff80821115613700575f80fd5b908301906101e08286031215613714575f80fd5b61371c61302f565b61372583613681565b815261373360208401613681565b60208201526137446040840161368c565b60408201526137556060840161368c565b60608201526137666080840161368c565b608082015261377760a0840161368c565b60a082015260c0838101519082015260e0808401519082015261010080840151908201526101208084015190820152610140808401519082015261016080840151908201526101806137ca81850161368c565b908201526101a083810151908201526101c080840151838111156137ec575f80fd5b6137f888828701613697565b918301919091525095945050505050565b602081525f61130c60208301846132b1565b805161185681613181565b5f6101808284031215613837575f80fd5b61383f613053565b61384883613681565b815261385660208401613681565b60208201526138676040840161368c565b60408201526138786060840161368c565b60608201526138896080840161368c565b608082015261389a60a0840161368c565b60a082015260c083015160c082015260e083015160e08201526101008084015181830152506101206138cd81850161381b565b908201526101408381015190820152610160928301519281019290925250919050565b8082018281125f83128015821682158216171561390f5761390f613641565b505092915050565b8082028115828204841417610aba57610aba613641565b5f82613961577f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b500490565b81810381811115610aba57610aba613641565b5f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82036139a9576139a9613641565b5060010190565b60e081525f6139c260e083018a6132b1565b63ffffffff989098166020830152506001600160a01b039586166040820152939094166060840152608083019190915260a082015290151560c090910152919050565b6001600160a01b0384168152826020820152606060408201525f613a2c60608301846132b1565b95945050505050565b80516020808301519190811015613a74577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8160200360031b1b821691505b50919050565b5f60208284031215613a8a575f80fd5b5051919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b5f60208284031215613ace575f80fd5b815161130c81613181565b5f8251613aea81846020870161328f565b9190910192915050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603160045260245ffdfea264697066735822122007a09ea15c5efbb28f239593161aeb6ee596d67bad8a87d0cd46703d115a053164736f6c63430008180033","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.24 ^0.8.0 ^0.8.20;\n\n// contracts/interfaces/IAdmin.sol\n\ninterface IAdmin {\n // ============ Events ============\n\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n event ChainGasAmountUpdated(uint256 oldChainGasAmount, uint256 newChainGasAmount);\n\n // ============ Methods ============\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n\n function setChainGasAmount(uint256 newChainGasAmount) external;\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IFastBridgeRecipient.sol\n\ninterface IFastBridgeRecipient {\n function fastBridgeTransferReceived(\n address token,\n uint256 amount,\n bytes memory callParams\n )\n external\n payable\n returns (bytes4);\n}\n\n// contracts/interfaces/IFastBridgeV2Errors.sol\n\ninterface IFastBridgeV2Errors {\n error AmountIncorrect();\n error CallParamsLengthAboveMax();\n error ChainIncorrect();\n error ExclusivityParamsIncorrect();\n error MsgValueIncorrect();\n error NativeTokenCallValueNotSupported();\n error SenderIncorrect();\n error StatusIncorrect();\n error ZeroAddress();\n\n error RecipientIncorrectReturnValue();\n error RecipientNoReturnValue();\n\n error DeadlineExceeded();\n error DeadlineNotExceeded();\n error DeadlineTooShort();\n error DisputePeriodNotPassed();\n error DisputePeriodPassed();\n error ExclusivityPeriodNotPassed();\n\n error TransactionRelayed();\n}\n\n// contracts/libs/Errors.sol\n\nerror DeadlineExceeded();\nerror DeadlineNotExceeded();\nerror DeadlineTooShort();\nerror InsufficientOutputAmount();\n\nerror MsgValueIncorrect();\nerror PoolNotFound();\nerror TokenAddressMismatch();\nerror TokenNotContract();\nerror TokenNotETH();\nerror TokensIdentical();\n\nerror ChainIncorrect();\nerror AmountIncorrect();\nerror ZeroAddress();\n\nerror DisputePeriodNotPassed();\nerror DisputePeriodPassed();\nerror SenderIncorrect();\nerror StatusIncorrect();\nerror TransactionIdIncorrect();\nerror TransactionRelayed();\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// contracts/interfaces/IFastBridgeV2.sol\n\ninterface IFastBridgeV2 is IFastBridge {\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n struct BridgeTxDetails {\n BridgeStatus status;\n uint40 proofBlockTimestamp;\n uint48 proofBlockNumber;\n address proofRelayer;\n }\n\n struct BridgeRelay {\n uint48 blockNumber;\n uint48 blockTimestamp;\n address relayer;\n }\n\n /// @notice New params introduced in the FastBridgeV2.\n /// We are passing fields from the older BridgeParams struct outside of this struct\n /// for backwards compatibility.\n /// Note: quoteRelayer and quoteExclusivitySeconds are either both zero (indicating no exclusivity)\n /// or both non-zero (indicating exclusivity for the given period).\n /// Note: callValue \u003e 0 can NOT be used with destToken = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE (ETH_ADDRESS)\n /// @param quoteRelayer Relayer that provided the quote for the transaction\n /// @param quoteExclusivitySeconds Period of time the quote relayer is guaranteed exclusivity after user's deposit\n /// @param quoteId Unique quote identifier used for tracking the quote\n /// @param callValue ETH value to send to the recipient (if any)\n /// @param callParams Parameters for the arbitrary call to the destination recipient (if any)\n struct BridgeParamsV2 {\n address quoteRelayer;\n int256 quoteExclusivitySeconds;\n bytes quoteId;\n uint256 callValue;\n bytes callParams;\n }\n\n /// @notice Updated bridge transaction struct to include parameters introduced in FastBridgeV2.\n /// Note: only `exclusivityRelayer` can fill such a transaction until `exclusivityEndTime`.\n /// TODO: consider changing the encoding scheme to prevent spending extra gas on decoding.\n struct BridgeTransactionV2 {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n uint256 callValue; // ETH value to send to the recipient (if any) - replaces V1's sendChainGas flag\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n address exclusivityRelayer;\n uint256 exclusivityEndTime;\n bytes callParams;\n }\n\n event BridgeQuoteDetails(bytes32 indexed transactionId, bytes quoteId);\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability\n /// to provide temporary exclusivity fill rights for the quote relayer.\n /// @param params The parameters required to bridge\n /// @param paramsV2 The parameters for exclusivity fill rights (optional, can be left empty)\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function relay(bytes memory request, address relayer) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param transactionId The transaction id associated with the encoded bridge transaction to prove\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital.\n /// @notice Can only send funds to the relayer address on the proof.\n /// @param request The encoded bridge transaction to claim on origin chain\n function claim(bytes memory request) external;\n /// @notice Checks if a transaction has been relayed\n /// @param transactionId The ID of the transaction to check\n /// @return True if the transaction has been relayed, false otherwise\n function bridgeRelays(bytes32 transactionId) external view returns (bool);\n\n /// @notice Returns the status of a bridge transaction\n /// @param transactionId The ID of the bridge transaction\n /// @return BridgeStatus Status of the bridge transaction\n function bridgeStatuses(bytes32 transactionId) external view returns (BridgeStatus);\n\n /// @notice Returns the timestamp and relayer of a bridge proof\n /// @param transactionId The ID of the bridge transaction\n /// @return timestamp The timestamp of the bridge proof\n /// @return relayer The relayer address of the bridge proof\n function bridgeProofs(bytes32 transactionId) external view returns (uint96 timestamp, address relayer);\n\n /// @notice Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\n /// @param request The bridge request to decode\n function getBridgeTransactionV2(bytes memory request) external view returns (BridgeTransactionV2 memory);\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// contracts/libs/UniversalToken.sol\n\nlibrary UniversalTokenLib {\n using SafeERC20 for IERC20;\n\n address internal constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Transfers tokens to the given account. Reverts if transfer is not successful.\n /// @dev This might trigger fallback, if ETH is transferred to the contract.\n /// Make sure this can not lead to reentrancy attacks.\n function universalTransfer(address token, address to, uint256 value) internal {\n // Don't do anything, if need to send tokens to this address\n if (to == address(this)) return;\n // Don't do anything, if trying to send zero value\n if (value == 0) return;\n if (token == ETH_ADDRESS) {\n /// @dev Note: this can potentially lead to executing code in `to`.\n // solhint-disable-next-line avoid-low-level-calls\n (bool success,) = to.call{value: value}(\"\");\n require(success, \"ETH transfer failed\");\n } else {\n IERC20(token).safeTransfer(to, value);\n }\n }\n\n /// @notice Issues an infinite allowance to the spender, if the current allowance is insufficient\n /// to spend the given amount.\n function universalApproveInfinity(address token, address spender, uint256 amountToSpend) internal {\n // ETH Chad doesn't require your approval\n if (token == ETH_ADDRESS) return;\n // No-op if allowance is already sufficient\n uint256 allowance = IERC20(token).allowance(address(this), spender);\n if (allowance \u003e= amountToSpend) return;\n // Otherwise, reset approval to 0 and set to max allowance\n if (allowance \u003e 0) IERC20(token).safeDecreaseAllowance(spender, allowance);\n IERC20(token).safeIncreaseAllowance(spender, type(uint256).max);\n }\n\n /// @notice Returns the balance of the given token (or native ETH) for the given account.\n function universalBalanceOf(address token, address account) internal view returns (uint256) {\n if (token == ETH_ADDRESS) {\n return account.balance;\n } else {\n return IERC20(token).balanceOf(account);\n }\n }\n\n /// @dev Checks that token is a contract and not ETH_ADDRESS.\n function assertIsContract(address token) internal view {\n // Check that ETH_ADDRESS was not used (in case this is a predeploy on any of the chains)\n if (token == UniversalTokenLib.ETH_ADDRESS) revert TokenNotContract();\n // Check that token is not an EOA\n if (token.code.length == 0) revert TokenNotContract();\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/Admin.sol\n\ncontract Admin is IAdmin, AccessControlEnumerable {\n using UniversalTokenLib for address;\n\n bytes32 public constant RELAYER_ROLE = keccak256(\"RELAYER_ROLE\");\n bytes32 public constant REFUNDER_ROLE = keccak256(\"REFUNDER_ROLE\");\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n uint256 public constant FEE_BPS = 1e6;\n uint256 public constant FEE_RATE_MAX = 0.01e6; // max 1% on origin amount\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Chain gas amount to forward as rebate if requested\n uint256 public chainGasAmount;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n }\n\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n require(newFeeRate \u003c= FEE_RATE_MAX, \"newFeeRate \u003e max\");\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n token.universalTransfer(recipient, feeAmount);\n emit FeesSwept(token, recipient, feeAmount);\n }\n\n function setChainGasAmount(uint256 newChainGasAmount) external onlyRole(GOVERNOR_ROLE) {\n uint256 oldChainGasAmount = chainGasAmount;\n chainGasAmount = newChainGasAmount;\n emit ChainGasAmountUpdated(oldChainGasAmount, newChainGasAmount);\n }\n}\n\n// contracts/FastBridgeV2.sol\n\n/// @notice FastBridgeV2 is a contract for bridging tokens across chains.\ncontract FastBridgeV2 is Admin, IFastBridgeV2, IFastBridgeV2Errors {\n using SafeERC20 for IERC20;\n using UniversalTokenLib for address;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Delay for a transaction after which it could be permisionlessly refunded\n uint256 public constant REFUND_DELAY = 7 days;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n /// @notice Maximum length of accepted callParams\n uint256 public constant MAX_CALL_PARAMS_LENGTH = 2 ** 16 - 1;\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeTxDetails) public bridgeTxDetails;\n /// @notice Relay details on destination chain\n mapping(bytes32 =\u003e BridgeRelay) public bridgeRelayDetails;\n /// @notice Unique bridge nonces tracked per originSender\n mapping(address =\u003e uint256) public senderNonces;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Replaced by senderNonces\n uint256 public immutable nonce = 0;\n /// @notice the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n bridge({\n params: params,\n paramsV2: BridgeParamsV2({\n quoteRelayer: address(0),\n quoteExclusivitySeconds: 0,\n quoteId: bytes(\"\"),\n callValue: 0,\n callParams: bytes(\"\")\n })\n });\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes memory request) external payable {\n relay({request: request, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes memory request, bytes32 destTxHash) external {\n prove({transactionId: keccak256(request), destTxHash: destTxHash, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridgeV2\n function claim(bytes memory request) external {\n claim({request: request, to: address(0)});\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003e DISPUTE_PERIOD) {\n revert DisputePeriodPassed();\n }\n\n // @dev relayer gets slashed effectively if dest relay has gone thru\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n bridgeTxDetails[transactionId].proofRelayer = address(0);\n bridgeTxDetails[transactionId].proofBlockTimestamp = 0;\n bridgeTxDetails[transactionId].proofBlockNumber = 0;\n\n emit BridgeProofDisputed(transactionId, msg.sender);\n }\n\n /// @inheritdoc IFastBridge\n function refund(bytes memory request) external {\n bytes32 transactionId = keccak256(request);\n\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n\n if (bridgeTxDetails[transactionId].status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n\n if (hasRole(REFUNDER_ROLE, msg.sender)) {\n // Refunder can refund if deadline has passed\n if (block.timestamp \u003c= transaction.deadline) revert DeadlineNotExceeded();\n } else {\n // Permissionless refund is allowed after REFUND_DELAY\n if (block.timestamp \u003c= transaction.deadline + REFUND_DELAY) revert DeadlineNotExceeded();\n }\n\n // if all checks passed, set to REFUNDED status\n bridgeTxDetails[transactionId].status = BridgeStatus.REFUNDED;\n\n // transfer origin collateral back to original sender\n address to = transaction.originSender;\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount + transaction.originFeeAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (bridgeTxDetails[transactionId].proofRelayer != relayer) revert SenderIncorrect();\n return _timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n /// @dev This method is added to achieve backwards compatibility with decoding requests into V1 structs:\n /// - `callValue` is partially reported as a zero/non-zero flag\n /// - `callParams` is ignored\n /// In order to process all kinds of requests use getBridgeTransactionV2 instead.\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory) {\n // Try decoding into V2 struct first. This will revert if V1 struct is passed\n try this.getBridgeTransactionV2(request) returns (BridgeTransactionV2 memory txV2) {\n // Note: we entirely ignore the callParams field, as it was not present in V1\n return BridgeTransaction({\n originChainId: txV2.originChainId,\n destChainId: txV2.destChainId,\n originSender: txV2.originSender,\n destRecipient: txV2.destRecipient,\n originToken: txV2.originToken,\n destToken: txV2.destToken,\n originAmount: txV2.originAmount,\n destAmount: txV2.destAmount,\n originFeeAmount: txV2.originFeeAmount,\n sendChainGas: txV2.callValue != 0,\n deadline: txV2.deadline,\n nonce: txV2.nonce\n });\n } catch {\n // Fallback to V1 struct\n return abi.decode(request, (BridgeTransaction));\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) public payable {\n int256 exclusivityEndTime = int256(block.timestamp) + paramsV2.quoteExclusivitySeconds;\n _validateBridgeParams(params, paramsV2, exclusivityEndTime);\n\n // transfer tokens to bridge contract\n /// @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _pullToken(params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n\n // set status to requested\n bytes memory request = abi.encode(\n BridgeTransactionV2({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n callValue: paramsV2.callValue,\n deadline: params.deadline,\n nonce: senderNonces[params.sender]++, // increment nonce on every bridge\n exclusivityRelayer: paramsV2.quoteRelayer,\n // We checked exclusivityEndTime to be in range (0 .. params.deadline] above, so can safely cast\n exclusivityEndTime: uint256(exclusivityEndTime),\n callParams: paramsV2.callParams\n })\n );\n bytes32 transactionId = keccak256(request);\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n\n emit BridgeRequested({\n transactionId: transactionId,\n sender: params.sender,\n request: request,\n destChainId: params.dstChainId,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n sendChainGas: paramsV2.callValue != 0\n });\n emit BridgeQuoteDetails(transactionId, paramsV2.quoteId);\n }\n\n /// @inheritdoc IFastBridgeV2\n function relay(bytes memory request, address relayer) public payable {\n bytes32 transactionId = keccak256(request);\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n _validateRelayParams(transaction, transactionId, relayer);\n // mark bridge transaction as relayed\n bridgeRelayDetails[transactionId] =\n BridgeRelay({blockNumber: uint48(block.number), blockTimestamp: uint48(block.timestamp), relayer: relayer});\n\n // transfer tokens to recipient on destination chain and do an arbitrary call if requested\n address to = transaction.destRecipient;\n address token = transaction.destToken;\n uint256 amount = transaction.destAmount;\n\n // All state changes have been done at this point, can proceed to the external calls.\n // This follows the checks-effects-interactions pattern to mitigate potential reentrancy attacks.\n if (token == UniversalTokenLib.ETH_ADDRESS) {\n // For ETH non-zero callValue is not allowed\n if (transaction.callValue != 0) revert NativeTokenCallValueNotSupported();\n // Check that the correct msg.value was sent\n if (msg.value != amount) revert MsgValueIncorrect();\n } else {\n // For ERC20s, we check that the correct msg.value was sent\n if (msg.value != transaction.callValue) revert MsgValueIncorrect();\n // We need to transfer the tokens from the Relayer to the recipient first before performing an\n // optional post-transfer arbitrary call.\n IERC20(token).safeTransferFrom(msg.sender, to, amount);\n }\n\n if (transaction.callParams.length != 0) {\n // Arbitrary call requested, perform it while supplying full msg.value to the recipient\n // Note: if token has a fee on transfers, the recipient will have received less than `amount`.\n // This is a very niche edge case and should be handled by the recipient contract.\n _checkedCallRecipient({recipient: to, token: token, amount: amount, callParams: transaction.callParams});\n } else if (msg.value != 0) {\n // No arbitrary call requested, but msg.value was sent. This is either a relay with ETH,\n // or a non-zero callValue request with an ERC20. In both cases, transfer the ETH to the recipient.\n Address.sendValue(payable(to), msg.value);\n }\n\n emit BridgeRelayed({\n transactionId: transactionId,\n relayer: relayer,\n to: to,\n originChainId: transaction.originChainId,\n originToken: transaction.originToken,\n destToken: transaction.destToken,\n originAmount: transaction.originAmount,\n destAmount: transaction.destAmount,\n chainGasAmount: transaction.callValue\n });\n }\n\n /// @inheritdoc IFastBridgeV2\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) public onlyRole(RELAYER_ROLE) {\n // update bridge tx status given proof provided\n if (bridgeTxDetails[transactionId].status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n bridgeTxDetails[transactionId].status = BridgeStatus.RELAYER_PROVED;\n bridgeTxDetails[transactionId].proofBlockTimestamp = uint40(block.timestamp);\n bridgeTxDetails[transactionId].proofBlockNumber = uint48(block.number);\n bridgeTxDetails[transactionId].proofRelayer = relayer;\n\n emit BridgeProofProvided(transactionId, relayer, destTxHash);\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes memory request, address to) public {\n bytes32 transactionId = keccak256(request);\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n\n // update bridge tx status if able to claim origin collateral\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n\n // if \"to\" is zero addr, permissionlessly send funds to proven relayer\n if (to == address(0)) {\n to = bridgeTxDetails[transactionId].proofRelayer;\n } else if (bridgeTxDetails[transactionId].proofRelayer != msg.sender) {\n revert SenderIncorrect();\n }\n\n if (_timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003c= DISPUTE_PERIOD) {\n revert DisputePeriodNotPassed();\n }\n\n bridgeTxDetails[transactionId].status = BridgeStatus.RELAYER_CLAIMED;\n\n // update protocol fees if origin fee amount exists\n if (transaction.originFeeAmount \u003e 0) protocolFees[transaction.originToken] += transaction.originFeeAmount;\n\n // transfer origin collateral less fee to specified address\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositClaimed(transactionId, bridgeTxDetails[transactionId].proofRelayer, to, token, amount);\n }\n\n function bridgeStatuses(bytes32 transactionId) public view returns (BridgeStatus status) {\n return bridgeTxDetails[transactionId].status;\n }\n\n function bridgeProofs(bytes32 transactionId) public view returns (uint96 timestamp, address relayer) {\n timestamp = bridgeTxDetails[transactionId].proofBlockTimestamp;\n relayer = bridgeTxDetails[transactionId].proofRelayer;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeRelays(bytes32 transactionId) public view returns (bool) {\n // has this transactionId been relayed?\n return bridgeRelayDetails[transactionId].relayer != address(0);\n }\n\n /// @inheritdoc IFastBridgeV2\n function getBridgeTransactionV2(bytes memory request) public pure returns (BridgeTransactionV2 memory) {\n return abi.decode(request, (BridgeTransactionV2));\n }\n\n /// @notice Pulls a requested token from the user to this contract.\n function _pullToken(address token, uint256 amount) internal returns (uint256 amountPulled) {\n if (token == UniversalTokenLib.ETH_ADDRESS) {\n // For ETH we just need to check that the supplied msg.value is correct\n if (amount != msg.value) revert MsgValueIncorrect();\n amountPulled = msg.value;\n } else {\n token.assertIsContract();\n // Record token balance before transfer\n amountPulled = IERC20(token).balanceOf(address(this));\n // Token needs to be pulled only if msg.value is zero\n // This way user can specify WETH as the origin asset\n IERC20(token).safeTransferFrom(msg.sender, address(this), amount);\n // Use the difference between the recorded balance and the current balance as the amountPulled\n amountPulled = IERC20(token).balanceOf(address(this)) - amountPulled;\n }\n }\n\n /// @notice Calls the Recipient's hook function with the specified callParams and performs\n /// all the necessary checks for the returned value.\n function _checkedCallRecipient(\n address recipient,\n address token,\n uint256 amount,\n bytes memory callParams\n )\n internal\n {\n bytes memory hookData =\n abi.encodeCall(IFastBridgeRecipient.fastBridgeTransferReceived, (token, amount, callParams));\n // This will bubble any revert messages from the hook function\n bytes memory returnData = Address.functionCallWithValue({target: recipient, data: hookData, value: msg.value});\n // Explicit revert if no return data at all\n if (returnData.length == 0) revert RecipientNoReturnValue();\n // Check that exactly a single return value was returned\n if (returnData.length != 32) revert RecipientIncorrectReturnValue();\n // Return value should be abi-encoded hook function selector\n if (bytes32(returnData) != bytes32(IFastBridgeRecipient.fastBridgeTransferReceived.selector)) {\n revert RecipientIncorrectReturnValue();\n }\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint40(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint40).max but\n /// proof.timestamp \u003c type(uint40).max via unchecked statement\n /// @param proofBlockTimestamp The bridge proof block timestamp\n /// @return delta Time delta since proof submitted\n function _timeSince(uint40 proofBlockTimestamp) internal view returns (uint256 delta) {\n unchecked {\n delta = uint40(block.timestamp) - proofBlockTimestamp;\n }\n }\n\n /// @notice Performs all the necessary checks for a bridge to happen.\n /// @dev There's no good way to refactor this function to reduce cyclomatic complexity due to\n /// the number of checks that need to be performed, so we skip the code-complexity rule here.\n // solhint-disable-next-line code-complexity\n function _validateBridgeParams(\n BridgeParams memory params,\n BridgeParamsV2 memory paramsV2,\n int256 exclusivityEndTime\n )\n internal\n view\n {\n // Check V1 (legacy) params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.sender == address(0) || params.to == address(0)) revert ZeroAddress();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n // Check V2 params\n if (paramsV2.callParams.length \u003e MAX_CALL_PARAMS_LENGTH) revert CallParamsLengthAboveMax();\n if (paramsV2.callValue != 0 \u0026\u0026 params.destToken == UniversalTokenLib.ETH_ADDRESS) {\n revert NativeTokenCallValueNotSupported();\n }\n // exclusivityEndTime must be in range (0 .. params.deadline]\n if (exclusivityEndTime \u003c= 0 || exclusivityEndTime \u003e int256(params.deadline)) {\n revert ExclusivityParamsIncorrect();\n }\n }\n\n /// @notice Performs all the necessary checks for a relay to happen.\n function _validateRelayParams(\n BridgeTransactionV2 memory transaction,\n bytes32 transactionId,\n address relayer\n )\n internal\n view\n {\n if (relayer == address(0)) revert ZeroAddress();\n // Check if the transaction has already been relayed\n if (bridgeRelays(transactionId)) revert TransactionRelayed();\n if (transaction.destChainId != uint32(block.chainid)) revert ChainIncorrect();\n // Check the deadline for relay to happen\n if (block.timestamp \u003e transaction.deadline) revert DeadlineExceeded();\n // Check the exclusivity period, if it is still ongoing\n // forgefmt: disable-next-item\n if (\n transaction.exclusivityRelayer != address(0) \u0026\u0026\n transaction.exclusivityRelayer != relayer \u0026\u0026\n block.timestamp \u003c= transaction.exclusivityEndTime\n ) {\n revert ExclusivityPeriodNotPassed();\n }\n }\n}\n","language":"Solidity","languageVersion":"0.8.24","compilerVersion":"0.8.24","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../","srcMap":"64760:19813:0:-:0;;;65906:1;65873:34;;66011:85;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;66045:6;63675:38;52847:4;66045:6;63675:10;:38::i;:::-;-1:-1:-1;;66077:12:0::1;66063:26;::::0;-1:-1:-1;64760:19813:0;;62160:257;62246:4;;62277:31;62294:4;62300:7;62277:16;:31::i;:::-;62262:46;;62322:7;62318:69;;;62345:18;;;;:12;:18;;;;;:31;;62368:7;62345:22;:31::i;:::-;;62318:69;62403:7;-1:-1:-1;62160:257:0;;;;;:::o;56794:316::-;56871:4;53569:12;;;;;;;;;;;-1:-1:-1;;;;;53569:29:0;;;;;;;;;;;;56887:217;;56930:6;:12;;;;;;;;;;;-1:-1:-1;;;;;56930:29:0;;;;;;;;;:36;;-1:-1:-1;;56930:36:0;56962:4;56930:36;;;57012:12;23368:10;;23289:96;57012:12;-1:-1:-1;;;;;56985:40:0;57003:7;-1:-1:-1;;;;;56985:40:0;56997:4;56985:40;;;;;;;;;;-1:-1:-1;57046:4:0;57039:11;;56887:217;-1:-1:-1;57088:5:0;57081:12;;32813:150;32883:4;32906:50;32911:3;-1:-1:-1;;;;;32931:23:0;;26801:4;28857:21;;;:14;;;:21;;;;;;26817:321;;-1:-1:-1;26859:23:0;;;;;;;;:11;:23;;;;;;;;;;;;;27041:18;;27017:21;;;:14;;;:21;;;;;;:42;;;;27073:11;;14:290:1;84:6;137:2;125:9;116:7;112:23;108:32;105:52;;;153:1;150;143:12;105:52;179:16;;-1:-1:-1;;;;;224:31:1;;214:42;;204:70;;270:1;267;260:12;14:290;64760:19813:0;;;;;;;;;;;;;;;;;;","srcMapRuntime":"64760:19813:0:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;60820:212;;;;;;;;;;-1:-1:-1;60820:212:0;;;;;:::i;:::-;;:::i;:::-;;;612:14:1;;605:22;587:41;;575:2;560:18;60820:212:0;;;;;;;;63050:60;;;;;;;;;;;;63087:23;63050:60;;;;;785:25:1;;;773:2;758:18;63050:60:0;639:177:1;78381:150:0;;;;;;;;;;-1:-1:-1;78381:150:0;;;;;:::i;:::-;78449:19;78487:30;;;:15;:30;;;;;:37;;;;78381:150;;;;;;;;:::i;64022:359::-;;;;;;;;;;-1:-1:-1;64022:359:0;;;;;:::i;:::-;;:::i;:::-;;63232:45;;;;;;;;;;;;63271:6;63232:45;;76275:648;;;;;;;;;;-1:-1:-1;76275:648:0;;;;;:::i;:::-;;:::i;65110:45::-;;;;;;;;;;;;65149:6;65110:45;;54425:120;;;;;;;;;;-1:-1:-1;54425:120:0;;;;;:::i;:::-;54490:7;54516:12;;;;;;;;;;:22;;;;54425:120;65722:47;;;;;;;;;;-1:-1:-1;65722:47:0;;;;;:::i;:::-;;;;;;;;;;;;;;54841:136;;;;;;;;;;-1:-1:-1;54841:136:0;;;;;:::i;:::-;;:::i;55943:245::-;;;;;;;;;;-1:-1:-1;55943:245:0;;;;;:::i;:::-;;:::i;76961:1414::-;;;;;;;;;;-1:-1:-1;76961:1414:0;;;;;:::i;:::-;;:::i;66134:369::-;;;;;;:::i;:::-;;:::i;63394:30::-;;;;;;;;;;;;;;;;62978:66;;;;;;;;;;;;63018:26;62978:66;;79059:169;;;;;;;;;;-1:-1:-1;79059:169:0;;;;;:::i;:::-;;:::i;:::-;;;;;;;:::i;67821:1169::-;;;;;;;;;;-1:-1:-1;67821:1169:0;;;;;:::i;:::-;;:::i;65482:58::-;;;;;;;;;;-1:-1:-1;65482:58:0;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;65482:58:0;;;;;;;;;;;;;:::i;65242:56::-;;;;;;;;;;;;65288:10;65242:56;;78820:199;;;;;;;;;;-1:-1:-1;78820:199:0;;;;;:::i;:::-;78886:4;78957:33;;;:18;:33;;;;;:41;;;;-1:-1:-1;;;;;78957:41:0;:55;;;78820:199;66696:170;;;;;;;;;;-1:-1:-1;66696:170:0;;;;;:::i;:::-;;:::i;66541:117::-;;;;;;:::i;:::-;;:::i;61617:142::-;;;;;;;;;;-1:-1:-1;61617:142:0;;;;;:::i;:::-;;:::i;:::-;;;-1:-1:-1;;;;;12205:55:1;;;12187:74;;12175:2;12160:18;61617:142:0;12041:226:1;78537:243:0;;;;;;;;;;-1:-1:-1;78537:243:0;;;;;:::i;:::-;78603:16;78660:30;;;:15;:30;;;;;:50;;;;;;;78730:43;;;;-1:-1:-1;;;;;78730:43:0;;78537:243;;;;;12474:26:1;12462:39;;;12444:58;;-1:-1:-1;;;;;12538:55:1;;;12533:2;12518:18;;12511:83;12417:18;78537:243:0;12272:328:1;53469:136:0;;;;;;;;;;-1:-1:-1;53469:136:0;;;;;:::i;:::-;53546:4;53569:12;;;;;;;;;;;-1:-1:-1;;;;;53569:29:0;;;;;;;;;;;;;;;53469:136;62908:64;;;;;;;;;;;;62947:25;62908:64;;73354:2881;;;;;;:::i;:::-;;:::i;52802:49::-;;;;;;;;;;-1:-1:-1;52802:49:0;52847:4;52802:49;;65968:36;;;;;;;;;;;;;;;69028:392;;;;;;;;;;-1:-1:-1;69028:392:0;;;;;:::i;:::-;;:::i;69755:1121::-;;;;;;;;;;-1:-1:-1;69755:1121:0;;;;;:::i;:::-;;:::i;:::-;;;;;;;:::i;67048:735::-;;;;;;;;;;-1:-1:-1;67048:735:0;;;;;:::i;:::-;;:::i;65873:34::-;;;;;;;;;;;;;;;63726:290;;;;;;;;;;-1:-1:-1;63726:290:0;;;;;:::i;:::-;;:::i;64387:264::-;;;;;;;;;;-1:-1:-1;64387:264:0;;;;;:::i;:::-;;:::i;63189:37::-;;;;;;;;;;;;63223:3;63189:37;;70916:2398;;;;;;:::i;:::-;;:::i;66906:104::-;;;;;;;;;;-1:-1:-1;66906:104:0;;;;;:::i;:::-;;:::i;65597:57::-;;;;;;;;;;-1:-1:-1;65597:57:0;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;65597:57:0;;;;;;;15543:14:1;15584:15;;;15566:34;;15636:15;;;;15631:2;15616:18;;15609:43;-1:-1:-1;;;;;15688:55:1;15668:18;;;15661:83;15521:2;15506:18;65597:57:0;15335:415:1;61927:131:0;;;;;;;;;;-1:-1:-1;61927:131:0;;;;;:::i;:::-;;:::i;63116:66::-;;;;;;;;;;;;63156:26;63116:66;;55257:138;;;;;;;;;;-1:-1:-1;55257:138:0;;;;;:::i;:::-;;:::i;63480:47::-;;;;;;;;;;-1:-1:-1;63480:47:0;;;;;:::i;:::-;;;;;;;;;;;;;;65359:60;;;;;;;;;;;;65408:11;65359:60;;63601:29;;;;;;;;;;;;;;;;60820:212;60905:4;60928:57;;;60943:42;60928:57;;:97;;;60989:36;61013:11;60989:23;:36::i;:::-;60921:104;60820:212;-1:-1:-1;;60820:212:0:o;64022:359::-;63156:26;53079:16;53090:4;53079:10;:16::i;:::-;-1:-1:-1;;;;;64146:19:0;::::1;64126:17;64146:19:::0;;;:12:::1;:19;::::0;;;;;;64179:14;;;64175:27:::1;;64195:7;64022:359:::0;;;:::o;64175:27::-:1;-1:-1:-1::0;;;;;64243:19:0;::::1;64265:1;64243:19:::0;;;:12:::1;:19;::::0;;;;:23;64276:45:::1;::::0;64300:9;64311;64276:23:::1;:45::i;:::-;64336:38;::::0;;-1:-1:-1;;;;;16036:15:1;;;16018:34;;16088:15;;16083:2;16068:18;;16061:43;16120:18;;;16113:34;;;64336:38:0::1;::::0;15945:2:1;15930:18;64336:38:0::1;;;;;;;64116:265;53105:1;64022:359:::0;;;:::o;76275:648::-;62947:25;53079:16;53090:4;53079:10;:16::i;:::-;76491:22:::1;76450:30;::::0;;;:15:::1;:30;::::0;;;;:37;::::1;;:63;::::0;::::1;;;;;;:::i;:::-;;76446:93;;76522:17;;;;;;;;;;;;;;76446:93;76549:30;::::0;;;:15:::1;:30;::::0;;;;;;;;:67;;76589:27:::1;76712:70:::0;;;;76626:76:::1;76686:15;76626:76;;;76712:70:::0;;;;76769:12:::1;76712:70;;;::::0;;76792:53;::::1;::::0;-1:-1:-1;;;;;76792:53:0;::::1;::::0;;::::1;::::0;;;::::1;::::0;;;76861:55;;785:25:1;;;76861:55:0;;76792:53;;76549:30;;76861:55:::1;::::0;;;;;;;::::1;76275:648:::0;;;;:::o;54841:136::-;54490:7;54516:12;;;;;;;;;;:22;;;53079:16;53090:4;53079:10;:16::i;:::-;54945:25:::1;54956:4;54962:7;54945:10;:25::i;:::-;;54841:136:::0;;;:::o;55943:245::-;-1:-1:-1;;;;;56036:34:0;;23368:10;56036:34;56032:102;;56093:30;;;;;;;;;;;;;;56032:102;56144:37;56156:4;56162:18;56144:11;:37::i;76961:1414::-;77051:18;;;;;;77027:21;77120:31;77061:7;77120:22;:31::i;:::-;77079:72;-1:-1:-1;77277:27:0;77236:30;;;;:15;:30;;;;;:37;;;:68;;;;;;;;:::i;:::-;;77232:98;;77313:17;;;;;;;;;;;;;;77232:98;-1:-1:-1;;;;;77424:16:0;;77420:213;;77461:30;;;;:15;:30;;;;;:43;;;;-1:-1:-1;;;;;77461:43:0;;-1:-1:-1;77420:213:0;;;77525:30;;;;:15;:30;;;;;:43;;;;-1:-1:-1;;;;;77525:43:0;77572:10;77525:57;77521:112;;77605:17;;;;;;;;;;;;;;77521:112;77658:30;;;;:15;:30;;;;;:50;65004:10;;77658:50;;;;;;;81985:15;81978:45;81970:53;77647:80;77643:142;;77750:24;;;;;;;;;;;;;;77643:142;77795:30;;;;:15;:30;;;;;:68;;;;77835:28;77795:68;;;77938:27;;;;:31;77934:105;;78012:27;;;;77984:23;;;;-1:-1:-1;;;;;77971:37:0;;;;;:12;:37;;;;;:68;;:37;;;:68;;78012:27;;77971:68;:::i;:::-;;;;-1:-1:-1;;77934:105:0;78134:23;;;;78184:24;;;;78218:35;-1:-1:-1;;;;;78218:23:0;;78242:2;78184:24;78218:23;:35::i;:::-;78305:30;;;;:15;:30;;;;;;;;;:43;78269:99;;-1:-1:-1;;;;;16669:55:1;;;16651:74;;16741:18;;;16734:34;;;78269:99:0;;;;78305:43;;;;;;;;:30;;78269:99;;16624:18:1;78269:99:0;;;;;;;77017:1358;;;;76961:1414;;:::o;66134:369::-;66205:291;66234:6;66264:221;;;;;;;;66319:1;-1:-1:-1;;;;;66264:221:0;;;;;66364:1;66264:221;;;;66392:9;;;;;;;;;;;;66264:221;;;;66430:1;66264:221;;;;66461:9;;;;;;;;;;;;66264:221;;;66205:6;:291::i;:::-;66134:369;:::o;79059:169::-;79134:26;-1:-1:-1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;79134:26:0;79190:7;79179:42;;;;;;;;;;;;:::i;67821:1169::-;67902:18;;;;;;67878:21;67972:31;67912:7;67972:22;:31::i;:::-;67931:72;-1:-1:-1;68059:22:0;68018:30;;;;:15;:30;;;;;:37;;;:63;;;;;;;;:::i;:::-;;68014:93;;68090:17;;;;;;;;;;;;;;68014:93;68145:10;53546:4;53569:29;;;:12;;:29;:12;:29;;;;;68118:382;;;68253:11;:20;;;68234:15;:39;68230:73;;68282:21;;;;;;;;;;;;;;68230:73;68118:382;;;65149:6;68424:11;:20;;;:35;;;;:::i;:::-;68405:15;:54;68401:88;;68468:21;;;;;;;;;;;;;;68401:88;68566:30;;;;:15;:30;;;;;;:61;;;;68606:21;68566:61;;;68713:24;;;68763:23;;;;68840:27;;;;68813:24;;;;68713;;68763:23;;68813:54;;68840:27;68813:54;:::i;:::-;68796:71;-1:-1:-1;68877:35:0;-1:-1:-1;;;;;68877:23:0;;68901:2;68796:71;68877:23;:35::i;:::-;68928:55;;;-1:-1:-1;;;;;16669:55:1;;;16651:74;;16756:2;16741:18;;16734:34;;;68928:55:0;;;68950:13;;68928:55;;16624:18:1;68928:55:0;;;;;;;67868:1122;;;;;67821:1169;:::o;66696:170::-;66772:87;66804:7;66794:18;;;;;;66826:10;66847;66772:5;:87::i;:::-;66696:170;;:::o;66541:117::-;66605:46;66621:7;66639:10;66605:5;:46::i;61617:142::-;61698:7;61724:18;;;:12;:18;;;;;:28;;61746:5;61724:21;:28::i;:::-;61717:35;61617:142;-1:-1:-1;;;61617:142:0:o;73354:2881::-;73457:18;;;;;;73433:21;73526:31;73467:7;73526:22;:31::i;:::-;73485:72;;73567:57;73588:11;73601:13;73616:7;73567:20;:57::i;:::-;73728:107;;;;;;;;;;73761:12;73728:107;;;;73799:15;73728:107;;;;;;;;;-1:-1:-1;;;;;73728:107:0;;;;;;;;;-1:-1:-1;73680:33:0;;;:18;:33;;;;;;;:155;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;73958:25;;;74009:21;;;;74057:22;;;;73958:25;;74009:21;;74057:22;74294:38;;;;;74290:719;;74409:21;;;;:26;74405:73;;74444:34;;;;;;;;;;;;;;74405:73;74566:6;74553:9;:19;74549:51;;74581:19;;;;;;;;;;;;;;74549:51;74290:719;;;74720:11;:21;;;74707:9;:34;74703:66;;74750:19;;;;;;;;;;;;;;74703:66;74944:54;-1:-1:-1;;;;;74944:30:0;;74975:10;74987:2;74991:6;74944:30;:54::i;:::-;75023:22;;;;:29;:34;75019:776;;75375:104;75409:2;75420:5;75435:6;75455:11;:22;;;75375:21;:104::i;:::-;75019:776;;;75500:9;:14;75496:299;;75743:41;75769:2;75774:9;75743:17;:41::i;:::-;75914:2;-1:-1:-1;;;;;75810:418:0;75889:7;-1:-1:-1;;;;;75810:418:0;75853:13;75810:418;75945:11;:25;;;75997:11;:23;;;76045:11;:21;;;76094:11;:24;;;76144:11;:22;;;76196:11;:21;;;75810:418;;;;;;;;;;19501:10:1;19489:23;;;;19471:42;;-1:-1:-1;;;;;19610:15:1;;;19605:2;19590:18;;19583:43;19662:15;;;;19657:2;19642:18;;19635:43;19709:2;19694:18;;19687:34;19752:3;19737:19;;19730:35;;;;19796:3;19781:19;;19774:35;19458:3;19443:19;;19186:629;75810:418:0;;;;;;;;73423:2812;;;;;73354:2881;;:::o;69028:392::-;69109:4;69170:27;69129:30;;;;:15;:30;;;;;:37;;;:68;;;;;;;;:::i;:::-;;69125:98;;69206:17;;;;;;;;;;;;;;69125:98;69237:30;;;;:15;:30;;;;;:43;-1:-1:-1;;;;;69237:54:0;;;:43;;;;;:54;69233:84;;69300:17;;;;;;;;;;;;;;69233:84;-1:-1:-1;;69345:30:0;;;;:15;:30;;;;;:50;65004:10;69345:50;;;;;;;;81985:15;81978:45;81970:53;69334:79;;69028:392::o;69755:1121::-;-1:-1:-1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;69956:36:0;;;;;:4;;:27;;:36;;69984:7;;69956:36;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;69956:36:0;;;;;;;;;;;;:::i;:::-;;;69952:918;;70830:7;70819:40;;;;;;;;;;;;:::i;69952:918::-;70146:597;;;;;;;;70197:4;:18;;;70146:597;;;;;;70246:4;:16;;;70146:597;;;;;;70294:4;:17;;;-1:-1:-1;;;;;70146:597:0;;;;;70344:4;:18;;;-1:-1:-1;;;;;70146:597:0;;;;;70393:4;:16;;;-1:-1:-1;;;;;70146:597:0;;;;;70438:4;:14;;;-1:-1:-1;;;;;70146:597:0;;;;;70484:4;:17;;;70146:597;;;;70531:4;:15;;;70146:597;;;;70581:4;:20;;;70146:597;;;;70633:4;:14;;;70651:1;70633:19;;70146:597;;;;;;70680:4;:13;;;70146:597;;;;70718:4;:10;;;70146:597;;;70139:604;;;69755:1121;;;:::o;69952:918::-;69755:1121;;;:::o;67048:735::-;63087:23;53079:16;53090:4;53079:10;:16::i;:::-;67173:27:::1;67132:30;::::0;;;:15:::1;:30;::::0;;;;:37;::::1;;:68;::::0;::::1;;;;;;:::i;:::-;;67128:98;;67209:17;;;;;;;;;;;;;;67128:98;67251:30;::::0;;;:15:::1;:30;::::0;;;;:50;65004:10:::1;::::0;67251:50:::1;::::0;::::1;;::::0;;::::1;81985:15:::0;81978:45;81970:53;67240:79:::1;67236:138;;;67342:21;;;;;;;;;;;;;;67236:138;67461:30;::::0;;;:15:::1;:30;::::0;;;;;67501:22:::1;67663:51:::0;;67730:46;67765:10:::1;::::0;67461:30;;67730:46:::1;::::0;67461:30;67730:46:::1;67048:735:::0;;:::o;63726:290::-;63156:26;53079:16;53090:4;53079:10;:16::i;:::-;63271:6:::1;63825:10;:26;;63817:55;;;::::0;::::1;::::0;;21574:2:1;63817:55:0::1;::::0;::::1;21556:21:1::0;21613:2;21593:18;;;21586:30;21652:18;21632;;;21625:46;21688:18;;63817:55:0::1;;;;;;;;;63903:15;::::0;;63928:28;;;;63971:38:::1;::::0;;21891:25:1;;;21947:2;21932:18;;21925:34;;;63971:38:0::1;::::0;21864:18:1;63971:38:0::1;;;;;;;;63807:209;63726:290:::0;;:::o;64387:264::-;63156:26;53079:16;53090:4;53079:10;:16::i;:::-;64512:14:::1;::::0;;64536:34;;;;64585:59:::1;::::0;;21891:25:1;;;21947:2;21932:18;;21925:34;;;64585:59:0::1;::::0;21864:18:1;64585:59:0::1;21717:248:1::0;70916:2398:0;71017:25;71071:8;:32;;;71052:15;71045:58;;;;:::i;:::-;71017:86;;71113:59;71135:6;71143:8;71153:18;71113:21;:59::i;:::-;71308:20;71331:51;71342:6;:18;;;71362:6;:19;;;71331:10;:51::i;:::-;71308:74;;71450:23;71505:1;71487:15;;:19;71483:85;;;63223:3;71542:15;;71527:12;:30;;;;:::i;:::-;71526:42;;;;:::i;:::-;71508:60;;71483:85;71578:31;71594:15;71578:31;;:::i;:::-;;;71722:20;71769:924;;;;;;;;71829:13;71769:924;;;;;;71874:6;:17;;;71769:924;;;;;;71923:6;:13;;;-1:-1:-1;;;;;71769:924:0;;;;;71969:6;:9;;;-1:-1:-1;;;;;71769:924:0;;;;;72009:6;:18;;;-1:-1:-1;;;;;71769:924:0;;;;;72056:6;:16;;;-1:-1:-1;;;;;71769:924:0;;;;;72104:12;71769:924;;;;72146:6;:17;;;71769:924;;;;72198:15;71769:924;;;;72242:8;:18;;;71769:924;;;;72288:6;:15;;;71769:924;;;;72328:12;:27;72341:6;:13;;;-1:-1:-1;;;;;72328:27:0;-1:-1:-1;;;;;72328:27:0;;;;;;;;;;;;;:29;;;;;;;;;:::i;:::-;;;;;71769:924;;;;72430:8;:21;;;-1:-1:-1;;;;;71769:924:0;;;;;72610:18;71769:924;;;;72659:8;:19;;;71769:924;;;71745:958;;;;;;;;:::i;:::-;;;;;;;-1:-1:-1;;71745:958:0;;;;;;72737:18;;71745:958;72737:18;;;;;;;72713:21;72765:30;;;:15;:30;;;;;;:62;;;;72805:22;72765:62;;;72923:13;;;72993:17;;73037:18;;;;;73080:16;;;;73162:17;;;;73207:18;;;;71745:958;;-1:-1:-1;72737:18:0;;-1:-1:-1;;;;;72843:398:0;;;;72737:18;;72843:398;;;;71745:958;;72993:17;;73037:18;73080:16;73124:12;;73207:23;;;;72843:398;:::i;:::-;;;;;;;;73275:13;73256:51;73290:8;:16;;;73256:51;;;;;;:::i;:::-;;;;;;;;71007:2307;;;;;70916:2398;;:::o;66906:104::-;66962:41;66978:7;66999:1;66962:5;:41::i;61927:131::-;61998:7;62024:18;;;:12;:18;;;;;:27;;:25;:27::i;55257:138::-;54490:7;54516:12;;;;;;;;;;:22;;;53079:16;53090:4;53079:10;:16::i;:::-;55362:26:::1;55374:4;55380:7;55362:11;:26::i;53180:202::-:0;53265:4;53288:47;;;53303:32;53288:47;;:87;;-1:-1:-1;45095:25:0;45080:40;;;;53339:36;44981:146;53814:103;53880:30;53891:4;23368:10;53880;:30::i;58092:653::-;58267:4;-1:-1:-1;;;;;58253:19:0;;;58249:32;;58092:653;;;:::o;58249:32::-;58353:5;58362:1;58353:10;58349:23;;58092:653;;;:::o;58349:23::-;58385:20;-1:-1:-1;;;;;58385:20:0;;;58381:358;;58565:12;58582:2;-1:-1:-1;;;;;58582:7:0;58597:5;58582:25;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;58564:43;;;58629:7;58621:39;;;;;;;24145:2:1;58621:39:0;;;24127:21:1;24184:2;24164:18;;;24157:30;24223:21;24203:18;;;24196:49;24262:18;;58621:39:0;23943:343:1;58381:358:0;58691:37;-1:-1:-1;;;;;58691:26:0;;58718:2;58722:5;58691:26;:37::i;62160:257::-;62246:4;62262:12;62277:31;62294:4;62300:7;62277:16;:31::i;:::-;62262:46;;62322:7;62318:69;;;62345:18;;;;:12;:18;;;;;:31;;62368:7;62345:22;:31::i;:::-;;62403:7;62160:257;-1:-1:-1;;;62160:257:0:o;62520:262::-;62607:4;62623:12;62638:32;62656:4;62662:7;62638:17;:32::i;:::-;62623:47;;62684:7;62680:72;;;62707:18;;;;:12;:18;;;;;:34;;62733:7;62707:25;:34::i;34071:156::-;34145:7;34195:22;34199:3;34211:5;34195:3;:22::i;83620:951::-;-1:-1:-1;;;;;83808:21:0;;83804:47;;83838:13;;;;;;;;;;;;;;83804:47;78886:4;78957:33;;;:18;:33;;;;;:41;;;;-1:-1:-1;;;;;78957:41:0;:55;83922:60;;83962:20;;;;;;;;;;;;;;83922:60;84030:13;83996:48;;:11;:23;;;:48;;;83992:77;;84053:16;;;;;;;;;;;;;;83992:77;84151:11;:20;;;84133:15;:38;84129:69;;;84180:18;;;;;;;;;;;;;;84129:69;84328:30;;;;-1:-1:-1;;;;;84328:44:0;;;;;:101;;;84422:7;-1:-1:-1;;;;;84388:41:0;:11;:30;;;-1:-1:-1;;;;;84388:41:0;;;84328:101;:166;;;;;84464:11;:30;;;84445:15;:49;;84328:166;84311:254;;;84526:28;;;;;;;;;;;;;;46696:188;46823:53;;-1:-1:-1;;;;;16036:15:1;;;46823:53:0;;;16018:34:1;16088:15;;;16068:18;;;16061:43;16120:18;;;16113:34;;;46796:81:0;;46816:5;;46838:18;;;;;15930::1;;46823:53:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;46796:19;:81::i;80387:999::-;80562:21;80663:5;80670:6;80678:10;80598:92;;;;;;;;;;:::i;:::-;;;;-1:-1:-1;;80598:92:0;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;80797:84:0;80836:9;80598:92;80870:9;80797:29;:84::i;:::-;80771:110;;80947:10;:17;80968:1;80947:22;80943:59;;80978:24;;;;;;;;;;;;;;80943:59;81081:10;:17;81102:2;81081:23;81077:67;;81113:31;;;;;;;;;;;;;;81077:67;81258:56;81227:19;81235:10;81227:19;:::i;:::-;:88;81223:157;;81338:31;;;;;;;;;;;;;;81223:157;80552:834;;80387:999;;;;:::o;17900:331::-;18009:6;17985:21;:30;17981:109;;;18038:41;;;;;18073:4;18038:41;;;12187:74:1;12160:18;;18038:41:0;12041:226:1;17981:109:0;18101:12;18119:9;-1:-1:-1;;;;;18119:14:0;18141:6;18119:33;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;18100:52;;;18167:7;18162:63;;18197:17;;;;;;;;;;;;;;82365:1176;82618:13;82597:6;:17;;;:34;;;82593:63;;82640:16;;;;;;;;;;;;;;82593:63;82670:19;;;;:24;;:50;;-1:-1:-1;82698:17:0;;;;:22;82670:50;82666:80;;;82729:17;;;;;;;;;;;;;;82666:80;82760:13;;;;-1:-1:-1;;;;;82760:27:0;;;:54;;-1:-1:-1;82791:9:0;;;;-1:-1:-1;;;;;82791:23:0;;82760:54;82756:80;;;82823:13;;;;;;;;;;;;;;82756:80;82850:18;;;;-1:-1:-1;;;;;82850:32:0;;;:66;;-1:-1:-1;82886:16:0;;;;-1:-1:-1;;;;;82886:30:0;;82850:66;82846:92;;;82925:13;;;;;;;;;;;;;;82846:92;82970:37;65288:10;82970:15;:37;:::i;:::-;82952:6;:15;;;:55;82948:86;;;83016:18;;;;;;;;;;;;;;82948:86;65408:11;83075:8;:19;;;:26;:51;83071:90;;;83135:26;;;;;;;;;;;;;;83071:90;83175:18;;;;:23;;;;:76;;-1:-1:-1;83202:16:0;;;;-1:-1:-1;;;;;83202:49:0;57809:42;83202:49;83175:76;83171:148;;;83274:34;;;;;;;;;;;;;;83171:148;83424:1;83402:18;:23;;:71;;;;83457:6;:15;;;83429:18;:44;83402:71;83398:137;;;83496:28;;;;;;;;;;;;;;79306:923;79375:20;79411:38;-1:-1:-1;;;;;79411:38:0;;;79407:816;;79563:9;79553:6;:19;79549:51;;79581:19;;;;;;;;;;;;;;79549:51;-1:-1:-1;79629:9:0;79407:816;;;79669:24;:5;-1:-1:-1;;;;;79669:22:0;;:24::i;:::-;79774:38;;;;;79806:4;79774:38;;;12187:74:1;-1:-1:-1;;;;;79774:23:0;;;;;12160:18:1;;79774:38:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;79759:53;-1:-1:-1;79958:65:0;-1:-1:-1;;;;;79958:30:0;;79989:10;80009:4;80016:6;79958:30;:65::i;:::-;80159:38;;;;;80191:4;80159:38;;;12187:74:1;80200:12:0;;-1:-1:-1;;;;;80159:23:0;;;;;12160:18:1;;80159:38:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;:53;;;;:::i;33614:115::-;33677:7;33703:19;33711:3;29053:18;;28971:107;54047:197;53546:4;53569:12;;;;;;;;;;;-1:-1:-1;;;;;53569:29:0;;;;;;;;;;;;54130:108;;54180:47;;;;;-1:-1:-1;;;;;16669:55:1;;54180:47:0;;;16651:74:1;16741:18;;;16734:34;;;16624:18;;54180:47:0;16477:297:1;46297:160:0;46406:43;;-1:-1:-1;;;;;16669:55:1;;;46406:43:0;;;16651:74:1;16741:18;;;16734:34;;;46379:71:0;;46399:5;;46421:14;;;;;16624:18:1;;46406:43:0;16477:297:1;56794:316:0;56871:4;53569:12;;;;;;;;;;;-1:-1:-1;;;;;53569:29:0;;;;;;;;;;;;56887:217;;56930:6;:12;;;;;;;;;;;-1:-1:-1;;;;;56930:29:0;;;;;;;;;:36;;;;56962:4;56930:36;;;57012:12;23368:10;;23289:96;57012:12;-1:-1:-1;;;;;56985:40:0;57003:7;-1:-1:-1;;;;;56985:40:0;56997:4;56985:40;;;;;;;;;;-1:-1:-1;57046:4:0;57039:11;;56887:217;-1:-1:-1;57088:5:0;57081:12;;32813:150;32883:4;32906:50;32911:3;-1:-1:-1;;;;;32931:23:0;;32906:4;:50::i;57345:317::-;57423:4;53569:12;;;;;;;;;;;-1:-1:-1;;;;;53569:29:0;;;;;;;;;;;;57439:217;;;57513:5;57481:12;;;;;;;;;;;-1:-1:-1;;;;;57481:29:0;;;;;;;;;;:37;;;;;;57537:40;23368:10;;57481:12;;57537:40;;57513:5;57537:40;-1:-1:-1;57598:4:0;57591:11;;33131:156;33204:4;33227:53;33235:3;-1:-1:-1;;;;;33255:23:0;;33227:7;:53::i;29420:118::-;29487:7;29513:3;:11;;29525:5;29513:18;;;;;;;;:::i;:::-;;;;;;;;;29506:25;;29420:118;;;;:::o;49053:629::-;49472:23;49498:33;-1:-1:-1;;;;;49498:27:0;;49526:4;49498:27;:33::i;:::-;49472:59;;49545:10;:17;49566:1;49545:22;;:57;;;;;49583:10;49572:30;;;;;;;;;;;;:::i;:::-;49571:31;49545:57;49541:135;;;49625:40;;;;;-1:-1:-1;;;;;12205:55:1;;49625:40:0;;;12187:74:1;12160:18;;49625:40:0;12041:226:1;19549:392:0;19648:12;19700:5;19676:21;:29;19672:108;;;19728:41;;;;;19763:4;19728:41;;;12187:74:1;12160:18;;19728:41:0;12041:226:1;19672:108:0;19790:12;19804:23;19831:6;-1:-1:-1;;;;;19831:11:0;19850:5;19857:4;19831:31;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;19789:73;;;;19879:55;19906:6;19914:7;19923:10;19879:26;:55::i;:::-;19872:62;19549:392;-1:-1:-1;;;;;;19549:392:0:o;59909:344::-;60076:38;-1:-1:-1;;;;;60076:38:0;;;60072:69;;60123:18;;;;;;;;;;;;;;60072:69;60197:5;-1:-1:-1;;;;;60197:17:0;;60218:1;60197:22;60193:53;;60228:18;;;;;;;;;;;;;;26738:406;26801:4;28857:21;;;:14;;;:21;;;;;;26817:321;;-1:-1:-1;26859:23:0;;;;;;;;:11;:23;;;;;;;;;;;;;27041:18;;27017:21;;;:14;;;:21;;;;;;:42;;;;27073:11;;27312:1368;27378:4;27507:21;;;:14;;;:21;;;;;;27543:13;;27539:1135;;27910:18;27931:12;27942:1;27931:8;:12;:::i;:::-;27977:18;;27910:33;;-1:-1:-1;27957:17:0;;27977:22;;27998:1;;27977:22;:::i;:::-;27957:42;;28032:9;28018:10;:23;28014:378;;28061:17;28081:3;:11;;28093:9;28081:22;;;;;;;;:::i;:::-;;;;;;;;;28061:42;;28228:9;28202:3;:11;;28214:10;28202:23;;;;;;;;:::i;:::-;;;;;;;;;;;;:35;;;;28341:25;;;:14;;;:25;;;;;:36;;;28014:378;28470:17;;:3;;:17;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;28573:3;:14;;:21;28588:5;28573:21;;;;;;;;;;;28566:28;;;28616:4;28609:11;;;;;;;27539:1135;28658:5;28651:12;;;;;19074:151;19149:12;19180:38;19202:6;19210:4;19216:1;19180:21;:38::i;20994:582::-;21138:12;21167:7;21162:408;;21190:19;21198:10;21190:7;:19::i;:::-;21162:408;;;21414:17;;:22;:49;;;;-1:-1:-1;;;;;;21440:18:0;;;:23;21414:49;21410:119;;;21490:24;;;;;-1:-1:-1;;;;;12205:55:1;;21490:24:0;;;12187:74:1;12160:18;;21490:24:0;12041:226:1;21410:119:0;-1:-1:-1;21549:10:0;21542:17;;22112:516;22243:17;;:21;22239:383;;22471:10;22465:17;22527:15;22514:10;22510:2;22506:19;22499:44;22239:383;22594:17;;;;;;;;;;;;;;14:332:1;72:6;125:2;113:9;104:7;100:23;96:32;93:52;;;141:1;138;131:12;93:52;180:9;167:23;230:66;223:5;219:78;212:5;209:89;199:117;;312:1;309;302:12;821:180;880:6;933:2;921:9;912:7;908:23;904:32;901:52;;;949:1;946;939:12;901:52;-1:-1:-1;972:23:1;;821:180;-1:-1:-1;821:180:1:o;1006:184::-;1058:77;1055:1;1048:88;1155:4;1152:1;1145:15;1179:4;1176:1;1169:15;1195:297;1279:1;1272:5;1269:12;1259:200;;1315:77;1312:1;1305:88;1416:4;1413:1;1406:15;1444:4;1441:1;1434:15;1259:200;1468:18;;1195:297::o;1497:214::-;1646:2;1631:18;;1658:47;1635:9;1687:6;1658:47;:::i;1716:154::-;-1:-1:-1;;;;;1795:5:1;1791:54;1784:5;1781:65;1771:93;;1860:1;1857;1850:12;1875:134;1943:20;;1972:31;1943:20;1972:31;:::i;2014:388::-;2082:6;2090;2143:2;2131:9;2122:7;2118:23;2114:32;2111:52;;;2159:1;2156;2149:12;2111:52;2198:9;2185:23;2217:31;2242:5;2217:31;:::i;:::-;2267:5;-1:-1:-1;2324:2:1;2309:18;;2296:32;2337:33;2296:32;2337:33;:::i;:::-;2389:7;2379:17;;;2014:388;;;;;:::o;2589:383::-;2666:6;2674;2682;2735:2;2723:9;2714:7;2710:23;2706:32;2703:52;;;2751:1;2748;2741:12;2703:52;2787:9;2774:23;2764:33;;2844:2;2833:9;2829:18;2816:32;2806:42;;2898:2;2887:9;2883:18;2870:32;2911:31;2936:5;2911:31;:::i;:::-;2961:5;2951:15;;;2589:383;;;;;:::o;2977:247::-;3036:6;3089:2;3077:9;3068:7;3064:23;3060:32;3057:52;;;3105:1;3102;3095:12;3057:52;3144:9;3131:23;3163:31;3188:5;3163:31;:::i;3229:315::-;3297:6;3305;3358:2;3346:9;3337:7;3333:23;3329:32;3326:52;;;3374:1;3371;3364:12;3326:52;3410:9;3397:23;3387:33;;3470:2;3459:9;3455:18;3442:32;3483:31;3508:5;3483:31;:::i;3549:184::-;3601:77;3598:1;3591:88;3698:4;3695:1;3688:15;3722:4;3719:1;3712:15;3738:255;3810:2;3804:9;3852:6;3840:19;;3889:18;3874:34;;3910:22;;;3871:62;3868:88;;;3936:18;;:::i;:::-;3972:2;3965:22;3738:255;:::o;3998:253::-;4070:2;4064:9;4112:4;4100:17;;4147:18;4132:34;;4168:22;;;4129:62;4126:88;;;4194:18;;:::i;4256:255::-;4328:2;4322:9;4370:6;4358:19;;4407:18;4392:34;;4428:22;;;4389:62;4386:88;;;4454:18;;:::i;4516:252::-;4588:2;4582:9;4630:3;4618:16;;4664:18;4649:34;;4685:22;;;4646:62;4643:88;;;4711:18;;:::i;4773:334::-;4844:2;4838:9;4900:2;4890:13;;-1:-1:-1;;4886:86:1;4874:99;;5003:18;4988:34;;5024:22;;;4985:62;4982:88;;;5050:18;;:::i;:::-;5086:2;5079:22;4773:334;;-1:-1:-1;4773:334:1:o;5112:245::-;5160:4;5193:18;5185:6;5182:30;5179:56;;;5215:18;;:::i;:::-;-1:-1:-1;5272:2:1;5260:15;-1:-1:-1;;5256:88:1;5346:4;5252:99;;5112:245::o;5362:462::-;5404:5;5457:3;5450:4;5442:6;5438:17;5434:27;5424:55;;5475:1;5472;5465:12;5424:55;5511:6;5498:20;5542:48;5558:31;5586:2;5558:31;:::i;:::-;5542:48;:::i;:::-;5615:2;5606:7;5599:19;5661:3;5654:4;5649:2;5641:6;5637:15;5633:26;5630:35;5627:55;;;5678:1;5675;5668:12;5627:55;5743:2;5736:4;5728:6;5724:17;5717:4;5708:7;5704:18;5691:55;5791:1;5766:16;;;5784:4;5762:27;5755:38;;;;5770:7;5362:462;-1:-1:-1;;;5362:462:1:o;5829:455::-;5906:6;5914;5967:2;5955:9;5946:7;5942:23;5938:32;5935:52;;;5983:1;5980;5973:12;5935:52;6023:9;6010:23;6056:18;6048:6;6045:30;6042:50;;;6088:1;6085;6078:12;6042:50;6111:49;6152:7;6143:6;6132:9;6128:22;6111:49;:::i;:::-;6101:59;;;6210:2;6199:9;6195:18;6182:32;6223:31;6248:5;6223:31;:::i;6289:121::-;6374:10;6367:5;6363:22;6356:5;6353:33;6343:61;;6400:1;6397;6390:12;6415:132;6482:20;;6511:30;6482:20;6511:30;:::i;6552:118::-;6638:5;6631:13;6624:21;6617:5;6614:32;6604:60;;6660:1;6657;6650:12;6675:128;6740:20;;6769:28;6740:20;6769:28;:::i;6808:806::-;6867:5;6915:6;6903:9;6898:3;6894:19;6890:32;6887:52;;;6935:1;6932;6925:12;6887:52;6957:22;;:::i;:::-;6948:31;;7002:28;7020:9;7002:28;:::i;:::-;6995:5;6988:43;7063:38;7097:2;7086:9;7082:18;7063:38;:::i;:::-;7058:2;7051:5;7047:14;7040:62;7134:38;7168:2;7157:9;7153:18;7134:38;:::i;:::-;7129:2;7122:5;7118:14;7111:62;7205:38;7239:2;7228:9;7224:18;7205:38;:::i;:::-;7200:2;7193:5;7189:14;7182:62;7277:39;7311:3;7300:9;7296:19;7277:39;:::i;:::-;7271:3;7264:5;7260:15;7253:64;7378:3;7367:9;7363:19;7350:33;7344:3;7337:5;7333:15;7326:58;7445:3;7434:9;7430:19;7417:33;7411:3;7404:5;7400:15;7393:58;7484:36;7515:3;7504:9;7500:19;7484:36;:::i;:::-;7478:3;7471:5;7467:15;7460:61;7540:3;7603:2;7592:9;7588:18;7575:32;7570:2;7563:5;7559:14;7552:56;;6808:806;;;;:::o;7619:237::-;7707:6;7760:3;7748:9;7739:7;7735:23;7731:33;7728:53;;;7777:1;7774;7767:12;7728:53;7800:50;7842:7;7831:9;7800:50;:::i;7861:320::-;7929:6;7982:2;7970:9;7961:7;7957:23;7953:32;7950:52;;;7998:1;7995;7988:12;7950:52;8038:9;8025:23;8071:18;8063:6;8060:30;8057:50;;;8103:1;8100;8093:12;8057:50;8126:49;8167:7;8158:6;8147:9;8143:22;8126:49;:::i;:::-;8116:59;7861:320;-1:-1:-1;;;;7861:320:1:o;8417:250::-;8502:1;8512:113;8526:6;8523:1;8520:13;8512:113;;;8602:11;;;8596:18;8583:11;;;8576:39;8548:2;8541:10;8512:113;;;-1:-1:-1;;8659:1:1;8641:16;;8634:27;8417:250::o;8672:329::-;8713:3;8751:5;8745:12;8778:6;8773:3;8766:19;8794:76;8863:6;8856:4;8851:3;8847:14;8840:4;8833:5;8829:16;8794:76;:::i;:::-;8915:2;8903:15;-1:-1:-1;;8899:88:1;8890:98;;;;8990:4;8886:109;;8672:329;-1:-1:-1;;8672:329:1:o;9006:1866::-;9209:2;9198:9;9191:21;9221:52;9269:2;9258:9;9254:18;9245:6;9239:13;8262:10;8251:22;8239:35;;8186:94;9221:52;9172:4;9320:2;9312:6;9308:15;9302:22;9333:51;9380:2;9369:9;9365:18;9351:12;8262:10;8251:22;8239:35;;8186:94;9333:51;-1:-1:-1;9433:2:1;9421:15;;9415:22;-1:-1:-1;;;;;8351:54:1;;9496:2;9481:18;;8339:67;-1:-1:-1;9549:2:1;9537:15;;9531:22;-1:-1:-1;;;;;8351:54:1;;9612:3;9597:19;;8339:67;-1:-1:-1;9666:3:1;9654:16;;9648:23;-1:-1:-1;;;;;8351:54:1;;9730:3;9715:19;;8339:67;-1:-1:-1;9784:3:1;9772:16;;9766:23;-1:-1:-1;;;;;8351:54:1;;9848:3;9833:19;;8339:67;-1:-1:-1;9908:3:1;9896:16;;9890:23;9884:3;9869:19;;;9862:52;;;;9939:16;;9933:23;9975:3;9994:18;;;9987:30;;;;10042:15;;10036:22;10077:3;10096:18;;;10089:30;;;;10144:15;;10138:22;10179:3;10198:18;;;10191:30;;;;10246:15;;10240:22;10281:3;10300:18;;;10293:30;;;;10348:15;;10342:22;10384:3;10403:19;;;10396:31;;;;10464:16;;10458:23;10501:3;10513:55;10548:19;;;10458:23;-1:-1:-1;;;;;8351:54:1;8339:67;;8285:127;10513:55;10594:16;;10588:23;10631:3;10650:19;;;10643:32;;;;10712:16;;10706:23;10749:6;10771:19;;;10764:32;10706:23;-1:-1:-1;10813:53:1;10861:3;10846:19;;10706:23;10813:53;:::i;10877:513::-;11106:3;11091:19;;11119:47;11095:9;11148:6;11119:47;:::i;:::-;11214:12;11206:6;11202:25;11197:2;11186:9;11182:18;11175:53;11276:14;11268:6;11264:27;11259:2;11248:9;11244:18;11237:55;-1:-1:-1;;;;;11332:6:1;11328:55;11323:2;11312:9;11308:18;11301:83;10877:513;;;;;;;:::o;11395:388::-;11472:6;11480;11533:2;11521:9;11512:7;11508:23;11504:32;11501:52;;;11549:1;11546;11539:12;11501:52;11589:9;11576:23;11622:18;11614:6;11611:30;11608:50;;;11654:1;11651;11644:12;11608:50;11677:49;11718:7;11709:6;11698:9;11694:22;11677:49;:::i;:::-;11667:59;11773:2;11758:18;;;;11745:32;;-1:-1:-1;;;;11395:388:1:o;11788:248::-;11856:6;11864;11917:2;11905:9;11896:7;11892:23;11888:32;11885:52;;;11933:1;11930;11923:12;11885:52;-1:-1:-1;;11956:23:1;;;12026:2;12011:18;;;11998:32;;-1:-1:-1;11788:248:1:o;12605:1373::-;12836:13;;8262:10;8251:22;8239:35;;12805:3;12790:19;;12908:4;12900:6;12896:17;12890:24;12923:53;12970:4;12959:9;12955:20;12941:12;8262:10;8251:22;8239:35;;8186:94;12923:53;;13025:4;13017:6;13013:17;13007:24;13040:56;13090:4;13079:9;13075:20;13059:14;-1:-1:-1;;;;;8351:54:1;8339:67;;8285:127;13040:56;;13145:4;13137:6;13133:17;13127:24;13160:56;13210:4;13199:9;13195:20;13179:14;-1:-1:-1;;;;;8351:54:1;8339:67;;8285:127;13160:56;;13265:4;13257:6;13253:17;13247:24;13280:56;13330:4;13319:9;13315:20;13299:14;-1:-1:-1;;;;;8351:54:1;8339:67;;8285:127;13280:56;;13385:4;13377:6;13373:17;13367:24;13400:56;13450:4;13439:9;13435:20;13419:14;-1:-1:-1;;;;;8351:54:1;8339:67;;8285:127;13400:56;;13512:4;13504:6;13500:17;13494:24;13487:4;13476:9;13472:20;13465:54;13575:4;13567:6;13563:17;13557:24;13550:4;13539:9;13535:20;13528:54;13601:6;13661:2;13653:6;13649:15;13643:22;13638:2;13627:9;13623:18;13616:50;;13685:6;13740:2;13732:6;13728:15;13722:22;13753:51;13800:2;13789:9;13785:18;13769:14;421:13;414:21;402:34;;351:91;13753:51;-1:-1:-1;;13823:6:1;13871:15;;;13865:22;13845:18;;;13838:50;13907:6;13955:15;;;13949:22;13929:18;;;;13922:50;;;;12605:1373;:::o;14168:1162::-;14297:6;14305;14358:3;14346:9;14337:7;14333:23;14329:33;14326:53;;;14375:1;14372;14365:12;14326:53;14398:50;14440:7;14429:9;14398:50;:::i;:::-;14388:60;;14499:3;14488:9;14484:19;14471:33;14523:18;14564:2;14556:6;14553:14;14550:34;;;14580:1;14577;14570:12;14550:34;14603:22;;;;14659:4;14641:16;;;14637:27;14634:47;;;14677:1;14674;14667:12;14634:47;14703:22;;:::i;:::-;14762:2;14749:16;14774:33;14799:7;14774:33;:::i;:::-;14816:22;;14891:2;14883:11;;;14870:25;14854:14;;;14847:49;14942:2;14934:11;;14921:25;14958:16;;;14955:36;;;14987:1;14984;14977:12;14955:36;15023:44;15059:7;15048:8;15044:2;15040:17;15023:44;:::i;:::-;15018:2;15011:5;15007:14;15000:68;;15121:2;15117;15113:11;15100:25;15095:2;15088:5;15084:14;15077:49;15172:3;15168:2;15164:12;15151:26;15202:2;15192:8;15189:16;15186:36;;;15218:1;15215;15208:12;15186:36;15255:44;15291:7;15280:8;15276:2;15272:17;15255:44;:::i;:::-;15249:3;15242:5;15238:15;15231:69;;15319:5;15309:15;;;;;14168:1162;;;;;:::o;16158:184::-;16210:77;16207:1;16200:88;16307:4;16304:1;16297:15;16331:4;16328:1;16321:15;16347:125;16412:9;;;16433:10;;;16430:36;;;16446:18;;:::i;16779:136::-;16857:13;;16879:30;16857:13;16879:30;:::i;16920:138::-;16999:13;;17021:31;16999:13;17021:31;:::i;17063:441::-;17116:5;17169:3;17162:4;17154:6;17150:17;17146:27;17136:55;;17187:1;17184;17177:12;17136:55;17216:6;17210:13;17247:48;17263:31;17291:2;17263:31;:::i;17247:48::-;17320:2;17311:7;17304:19;17366:3;17359:4;17354:2;17346:6;17342:15;17338:26;17335:35;17332:55;;;17383:1;17380;17373:12;17332:55;17396:77;17470:2;17463:4;17454:7;17450:18;17443:4;17435:6;17431:17;17396:77;:::i;17509:1672::-;17616:6;17669:2;17657:9;17648:7;17644:23;17640:32;17637:52;;;17685:1;17682;17675:12;17637:52;17718:9;17712:16;17747:18;17788:2;17780:6;17777:14;17774:34;;;17804:1;17801;17794:12;17774:34;17827:22;;;;17883:6;17865:16;;;17861:29;17858:49;;;17903:1;17900;17893:12;17858:49;17929:22;;:::i;:::-;17974:32;18003:2;17974:32;:::i;:::-;17967:5;17960:47;18039:41;18076:2;18072;18068:11;18039:41;:::i;:::-;18034:2;18027:5;18023:14;18016:65;18113:42;18151:2;18147;18143:11;18113:42;:::i;:::-;18108:2;18101:5;18097:14;18090:66;18188:42;18226:2;18222;18218:11;18188:42;:::i;:::-;18183:2;18176:5;18172:14;18165:66;18264:43;18302:3;18298:2;18294:12;18264:43;:::i;:::-;18258:3;18251:5;18247:15;18240:68;18341:43;18379:3;18375:2;18371:12;18341:43;:::i;:::-;18335:3;18324:15;;18317:68;18432:3;18424:12;;;18418:19;18401:15;;;18394:44;18485:3;18477:12;;;18471:19;18454:15;;;18447:44;18510:3;18551:11;;;18545:18;18529:14;;;18522:42;18583:3;18624:11;;;18618:18;18602:14;;;18595:42;18656:3;18697:11;;;18691:18;18675:14;;;18668:42;18729:3;18770:11;;;18764:18;18748:14;;;18741:42;18802:3;18837:42;18867:11;;;18837:42;:::i;:::-;18821:14;;;18814:66;18899:3;18940:11;;;18934:18;18918:14;;;18911:42;18972:3;19006:11;;;19000:18;19030:16;;;19027:36;;;19059:1;19056;19049:12;19027:36;19095:55;19142:7;19131:8;19127:2;19123:17;19095:55;:::i;:::-;19079:14;;;19072:79;;;;-1:-1:-1;19083:5:1;17509:1672;-1:-1:-1;;;;;17509:1672:1:o;19820:217::-;19967:2;19956:9;19949:21;19930:4;19987:44;20027:2;20016:9;20012:18;20004:6;19987:44;:::i;20042:132::-;20118:13;;20140:28;20118:13;20140:28;:::i;20179:1188::-;20282:6;20335:3;20323:9;20314:7;20310:23;20306:33;20303:53;;;20352:1;20349;20342:12;20303:53;20378:22;;:::i;:::-;20423:39;20452:9;20423:39;:::i;:::-;20416:5;20409:54;20495:48;20539:2;20528:9;20524:18;20495:48;:::i;:::-;20490:2;20483:5;20479:14;20472:72;20576:49;20621:2;20610:9;20606:18;20576:49;:::i;:::-;20571:2;20564:5;20560:14;20553:73;20658:49;20703:2;20692:9;20688:18;20658:49;:::i;:::-;20653:2;20646:5;20642:14;20635:73;20741:50;20786:3;20775:9;20771:19;20741:50;:::i;:::-;20735:3;20728:5;20724:15;20717:75;20825:50;20870:3;20859:9;20855:19;20825:50;:::i;:::-;20819:3;20812:5;20808:15;20801:75;20930:3;20919:9;20915:19;20909:26;20903:3;20896:5;20892:15;20885:51;20990:3;20979:9;20975:19;20969:26;20963:3;20956:5;20952:15;20945:51;21015:3;21071:2;21060:9;21056:18;21050:25;21045:2;21038:5;21034:14;21027:49;;21095:3;21130:46;21172:2;21161:9;21157:18;21130:46;:::i;:::-;21114:14;;;21107:70;21196:3;21237:18;;;21231:25;21215:14;;;21208:49;21276:3;21317:18;;;21311:25;21295:14;;;21288:49;;;;-1:-1:-1;21118:5:1;20179:1188;-1:-1:-1;20179:1188:1:o;21970:216::-;22034:9;;;22062:11;;;22009:3;22092:9;;22120:10;;22116:19;;22145:10;;22137:19;;22113:44;22110:70;;;22160:18;;:::i;:::-;22110:70;;21970:216;;;;:::o;22191:168::-;22264:9;;;22295;;22312:15;;;22306:22;;22292:37;22282:71;;22333:18;;:::i;22364:274::-;22404:1;22430;22420:189;;22465:77;22462:1;22455:88;22566:4;22563:1;22556:15;22594:4;22591:1;22584:15;22420:189;-1:-1:-1;22623:9:1;;22364:274::o;22643:128::-;22710:9;;;22731:11;;;22728:37;;;22745:18;;:::i;22776:195::-;22815:3;22846:66;22839:5;22836:77;22833:103;;22916:18;;:::i;:::-;-1:-1:-1;22963:1:1;22952:13;;22776:195::o;22976:752::-;23283:3;23272:9;23265:22;23246:4;23304:45;23344:3;23333:9;23329:19;23321:6;23304:45;:::i;:::-;23397:10;23385:23;;;;23380:2;23365:18;;23358:51;-1:-1:-1;;;;;;23506:15:1;;;23501:2;23486:18;;23479:43;23558:15;;;;23553:2;23538:18;;23531:43;23605:3;23590:19;;23583:35;;;;23649:3;23634:19;;23627:35;23706:14;;23699:22;23693:3;23678:19;;;23671:51;23296:53;22976:752;-1:-1:-1;22976:752:1:o;24291:408::-;-1:-1:-1;;;;;24498:6:1;24494:55;24483:9;24476:74;24586:6;24581:2;24570:9;24566:18;24559:34;24629:2;24624;24613:9;24609:18;24602:30;24457:4;24649:44;24689:2;24678:9;24674:18;24666:6;24649:44;:::i;:::-;24641:52;24291:408;-1:-1:-1;;;;;24291:408:1:o;24704:357::-;24822:12;;24869:4;24858:16;;;24852:23;;24822:12;24887:16;;24884:171;;;24977:66;24967:6;24961:4;24957:17;24954:1;24950:25;24946:98;24939:5;24935:110;24926:119;;24884:171;;24704:357;;;:::o;25066:184::-;25136:6;25189:2;25177:9;25168:7;25164:23;25160:32;25157:52;;;25205:1;25202;25195:12;25157:52;-1:-1:-1;25228:16:1;;25066:184;-1:-1:-1;25066:184:1:o;25557:::-;25609:77;25606:1;25599:88;25706:4;25703:1;25696:15;25730:4;25727:1;25720:15;25746:245;25813:6;25866:2;25854:9;25845:7;25841:23;25837:32;25834:52;;;25882:1;25879;25872:12;25834:52;25914:9;25908:16;25933:28;25955:5;25933:28;:::i;25996:287::-;26125:3;26163:6;26157:13;26179:66;26238:6;26233:3;26226:4;26218:6;26214:17;26179:66;:::i;:::-;26261:16;;;;;25996:287;-1:-1:-1;;25996:287:1:o;26288:184::-;26340:77;26337:1;26330:88;26437:4;26434:1;26427:15;26461:4;26458:1;26451:15","abiDefinition":[{"inputs":[{"internalType":"address","name":"_owner","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AccessControlBadConfirmation","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"bytes32","name":"neededRole","type":"bytes32"}],"name":"AccessControlUnauthorizedAccount","type":"error"},{"inputs":[{"internalType":"address","name":"target","type":"address"}],"name":"AddressEmptyCode","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"AddressInsufficientBalance","type":"error"},{"inputs":[],"name":"AmountIncorrect","type":"error"},{"inputs":[],"name":"CallParamsLengthAboveMax","type":"error"},{"inputs":[],"name":"ChainIncorrect","type":"error"},{"inputs":[],"name":"DeadlineExceeded","type":"error"},{"inputs":[],"name":"DeadlineNotExceeded","type":"error"},{"inputs":[],"name":"DeadlineTooShort","type":"error"},{"inputs":[],"name":"DisputePeriodNotPassed","type":"error"},{"inputs":[],"name":"DisputePeriodPassed","type":"error"},{"inputs":[],"name":"ExclusivityParamsIncorrect","type":"error"},{"inputs":[],"name":"ExclusivityPeriodNotPassed","type":"error"},{"inputs":[],"name":"FailedInnerCall","type":"error"},{"inputs":[],"name":"MsgValueIncorrect","type":"error"},{"inputs":[],"name":"NativeTokenCallValueNotSupported","type":"error"},{"inputs":[],"name":"RecipientIncorrectReturnValue","type":"error"},{"inputs":[],"name":"RecipientNoReturnValue","type":"error"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"SafeERC20FailedOperation","type":"error"},{"inputs":[],"name":"SenderIncorrect","type":"error"},{"inputs":[],"name":"StatusIncorrect","type":"error"},{"inputs":[],"name":"TokenNotContract","type":"error"},{"inputs":[],"name":"TransactionRelayed","type":"error"},{"inputs":[],"name":"ZeroAddress","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"relayer","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"BridgeDepositClaimed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"BridgeDepositRefunded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"relayer","type":"address"}],"name":"BridgeProofDisputed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"relayer","type":"address"},{"indexed":false,"internalType":"bytes32","name":"transactionHash","type":"bytes32"}],"name":"BridgeProofProvided","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":false,"internalType":"bytes","name":"quoteId","type":"bytes"}],"name":"BridgeQuoteDetails","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"relayer","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint32","name":"originChainId","type":"uint32"},{"indexed":false,"internalType":"address","name":"originToken","type":"address"},{"indexed":false,"internalType":"address","name":"destToken","type":"address"},{"indexed":false,"internalType":"uint256","name":"originAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"destAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"chainGasAmount","type":"uint256"}],"name":"BridgeRelayed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"bytes","name":"request","type":"bytes"},{"indexed":false,"internalType":"uint32","name":"destChainId","type":"uint32"},{"indexed":false,"internalType":"address","name":"originToken","type":"address"},{"indexed":false,"internalType":"address","name":"destToken","type":"address"},{"indexed":false,"internalType":"uint256","name":"originAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"destAmount","type":"uint256"},{"indexed":false,"internalType":"bool","name":"sendChainGas","type":"bool"}],"name":"BridgeRequested","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldChainGasAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newChainGasAmount","type":"uint256"}],"name":"ChainGasAmountUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldFeeRate","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newFeeRate","type":"uint256"}],"name":"FeeRateUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"address","name":"recipient","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"FeesSwept","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"previousAdminRole","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"newAdminRole","type":"bytes32"}],"name":"RoleAdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleRevoked","type":"event"},{"inputs":[],"name":"DEFAULT_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"DISPUTE_PERIOD","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"FEE_BPS","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"FEE_RATE_MAX","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"GOVERNOR_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"GUARD_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_CALL_PARAMS_LENGTH","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MIN_DEADLINE_PERIOD","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"REFUNDER_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"REFUND_DELAY","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"RELAYER_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"uint32","name":"dstChainId","type":"uint32"},{"internalType":"address","name":"sender","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"address","name":"originToken","type":"address"},{"internalType":"address","name":"destToken","type":"address"},{"internalType":"uint256","name":"originAmount","type":"uint256"},{"internalType":"uint256","name":"destAmount","type":"uint256"},{"internalType":"bool","name":"sendChainGas","type":"bool"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"internalType":"struct IFastBridge.BridgeParams","name":"params","type":"tuple"}],"name":"bridge","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"uint32","name":"dstChainId","type":"uint32"},{"internalType":"address","name":"sender","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"address","name":"originToken","type":"address"},{"internalType":"address","name":"destToken","type":"address"},{"internalType":"uint256","name":"originAmount","type":"uint256"},{"internalType":"uint256","name":"destAmount","type":"uint256"},{"internalType":"bool","name":"sendChainGas","type":"bool"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"internalType":"struct IFastBridge.BridgeParams","name":"params","type":"tuple"},{"components":[{"internalType":"address","name":"quoteRelayer","type":"address"},{"internalType":"int256","name":"quoteExclusivitySeconds","type":"int256"},{"internalType":"bytes","name":"quoteId","type":"bytes"},{"internalType":"uint256","name":"callValue","type":"uint256"},{"internalType":"bytes","name":"callParams","type":"bytes"}],"internalType":"struct IFastBridgeV2.BridgeParamsV2","name":"paramsV2","type":"tuple"}],"name":"bridge","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"transactionId","type":"bytes32"}],"name":"bridgeProofs","outputs":[{"internalType":"uint96","name":"timestamp","type":"uint96"},{"internalType":"address","name":"relayer","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"bridgeRelayDetails","outputs":[{"internalType":"uint48","name":"blockNumber","type":"uint48"},{"internalType":"uint48","name":"blockTimestamp","type":"uint48"},{"internalType":"address","name":"relayer","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"transactionId","type":"bytes32"}],"name":"bridgeRelays","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"transactionId","type":"bytes32"}],"name":"bridgeStatuses","outputs":[{"internalType":"enum IFastBridgeV2.BridgeStatus","name":"status","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"bridgeTxDetails","outputs":[{"internalType":"enum IFastBridgeV2.BridgeStatus","name":"status","type":"uint8"},{"internalType":"uint40","name":"proofBlockTimestamp","type":"uint40"},{"internalType":"uint48","name":"proofBlockNumber","type":"uint48"},{"internalType":"address","name":"proofRelayer","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"internalType":"address","name":"relayer","type":"address"}],"name":"canClaim","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"chainGasAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"},{"internalType":"address","name":"to","type":"address"}],"name":"claim","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"}],"name":"claim","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"deployBlock","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"transactionId","type":"bytes32"}],"name":"dispute","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"}],"name":"getBridgeTransaction","outputs":[{"components":[{"internalType":"uint32","name":"originChainId","type":"uint32"},{"internalType":"uint32","name":"destChainId","type":"uint32"},{"internalType":"address","name":"originSender","type":"address"},{"internalType":"address","name":"destRecipient","type":"address"},{"internalType":"address","name":"originToken","type":"address"},{"internalType":"address","name":"destToken","type":"address"},{"internalType":"uint256","name":"originAmount","type":"uint256"},{"internalType":"uint256","name":"destAmount","type":"uint256"},{"internalType":"uint256","name":"originFeeAmount","type":"uint256"},{"internalType":"bool","name":"sendChainGas","type":"bool"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint256","name":"nonce","type":"uint256"}],"internalType":"struct IFastBridge.BridgeTransaction","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"}],"name":"getBridgeTransactionV2","outputs":[{"components":[{"internalType":"uint32","name":"originChainId","type":"uint32"},{"internalType":"uint32","name":"destChainId","type":"uint32"},{"internalType":"address","name":"originSender","type":"address"},{"internalType":"address","name":"destRecipient","type":"address"},{"internalType":"address","name":"originToken","type":"address"},{"internalType":"address","name":"destToken","type":"address"},{"internalType":"uint256","name":"originAmount","type":"uint256"},{"internalType":"uint256","name":"destAmount","type":"uint256"},{"internalType":"uint256","name":"originFeeAmount","type":"uint256"},{"internalType":"uint256","name":"callValue","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"address","name":"exclusivityRelayer","type":"address"},{"internalType":"uint256","name":"exclusivityEndTime","type":"uint256"},{"internalType":"bytes","name":"callParams","type":"bytes"}],"internalType":"struct IFastBridgeV2.BridgeTransactionV2","name":"","type":"tuple"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleAdmin","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"uint256","name":"index","type":"uint256"}],"name":"getRoleMember","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleMemberCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"grantRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"hasRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"nonce","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"protocolFeeRate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"protocolFees","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"internalType":"bytes32","name":"destTxHash","type":"bytes32"},{"internalType":"address","name":"relayer","type":"address"}],"name":"prove","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"},{"internalType":"bytes32","name":"destTxHash","type":"bytes32"}],"name":"prove","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"}],"name":"refund","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"}],"name":"relay","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"},{"internalType":"address","name":"relayer","type":"address"}],"name":"relay","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"callerConfirmation","type":"address"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"revokeRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"senderNonces","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"newChainGasAmount","type":"uint256"}],"name":"setChainGasAmount","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"newFeeRate","type":"uint256"}],"name":"setProtocolFeeRate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"address","name":"recipient","type":"address"}],"name":"sweepProtocolFees","outputs":[],"stateMutability":"nonpayable","type":"function"}],"userDoc":{"kind":"user","methods":{"DISPUTE_PERIOD()":{"notice":"Dispute period for relayed transactions"},"MAX_CALL_PARAMS_LENGTH()":{"notice":"Maximum length of accepted callParams"},"MIN_DEADLINE_PERIOD()":{"notice":"Minimum deadline period to relay a requested bridge transaction"},"REFUND_DELAY()":{"notice":"Delay for a transaction after which it could be permisionlessly refunded"},"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256))":{"notice":"Initiates bridge on origin chain to be relayed by off-chain relayer"},"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256),(address,int256,bytes,uint256,bytes))":{"notice":"Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability to provide temporary exclusivity fill rights for the quote relayer."},"bridgeProofs(bytes32)":{"notice":"Returns the timestamp and relayer of a bridge proof"},"bridgeRelayDetails(bytes32)":{"notice":"Relay details on destination chain"},"bridgeRelays(bytes32)":{"notice":"Checks if a transaction has been relayed"},"bridgeStatuses(bytes32)":{"notice":"Returns the status of a bridge transaction"},"bridgeTxDetails(bytes32)":{"notice":"Status of the bridge tx on origin chain"},"canClaim(bytes32,address)":{"notice":"Checks if the dispute period has passed so bridge deposit can be claimed"},"chainGasAmount()":{"notice":"Chain gas amount to forward as rebate if requested"},"claim(bytes)":{"notice":"Completes bridge transaction on origin chain by claiming originally deposited capital.Can only send funds to the relayer address on the proof."},"claim(bytes,address)":{"notice":"Completes bridge transaction on origin chain by claiming originally deposited capital"},"deployBlock()":{"notice":"the block the contract was deployed at"},"dispute(bytes32)":{"notice":"Disputes an outstanding proof in case relayer provided dest chain tx is invalid"},"getBridgeTransaction(bytes)":{"notice":"Decodes bridge request into a bridge transaction"},"getBridgeTransactionV2(bytes)":{"notice":"Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2"},"nonce()":{"notice":"This is deprecated and should not be used."},"protocolFeeRate()":{"notice":"Protocol fee rate taken on origin amount deposited in origin chain"},"protocolFees(address)":{"notice":"Protocol fee amounts accumulated"},"prove(bytes,bytes32)":{"notice":"Provides proof on origin side that relayer provided funds on destination side of bridge transaction"},"prove(bytes32,bytes32,address)":{"notice":"Provides proof on origin side that relayer provided funds on destination side of bridge transaction"},"refund(bytes)":{"notice":"Refunds an outstanding bridge transaction in case optimistic bridging failed"},"relay(bytes)":{"notice":"Relays destination side of bridge transaction by off-chain relayer"},"relay(bytes,address)":{"notice":"Relays destination side of bridge transaction by off-chain relayer"},"senderNonces(address)":{"notice":"Unique bridge nonces tracked per originSender"}},"notice":"FastBridgeV2 is a contract for bridging tokens across chains.","version":1},"developerDoc":{"errors":{"AccessControlBadConfirmation()":[{"details":"The caller of a function is not the expected one. NOTE: Don't confuse with {AccessControlUnauthorizedAccount}."}],"AccessControlUnauthorizedAccount(address,bytes32)":[{"details":"The `account` is missing a role."}],"AddressEmptyCode(address)":[{"details":"There's no code at `target` (it is not a contract)."}],"AddressInsufficientBalance(address)":[{"details":"The ETH balance of the account is not enough to perform the operation."}],"FailedInnerCall()":[{"details":"A call to an address target failed. The target may have reverted."}],"SafeERC20FailedOperation(address)":[{"details":"An operation with an ERC20 token failed."}]},"events":{"RoleAdminChanged(bytes32,bytes32,bytes32)":{"details":"Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole` `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite {RoleAdminChanged} not being emitted signaling this."},"RoleGranted(bytes32,address,address)":{"details":"Emitted when `account` is granted `role`. `sender` is the account that originated the contract call, an admin role bearer except when using {AccessControl-_setupRole}."},"RoleRevoked(bytes32,address,address)":{"details":"Emitted when `account` is revoked `role`. `sender` is the account that originated the contract call: - if using `revokeRole`, it is the admin role bearer - if using `renounceRole`, it is the role bearer (i.e. `account`)"}},"kind":"dev","methods":{"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256))":{"params":{"params":"The parameters required to bridge"}},"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256),(address,int256,bytes,uint256,bytes))":{"params":{"params":"The parameters required to bridge","paramsV2":"The parameters for exclusivity fill rights (optional, can be left empty)"}},"bridgeProofs(bytes32)":{"params":{"transactionId":"The ID of the bridge transaction"},"returns":{"relayer":"The relayer address of the bridge proof","timestamp":"The timestamp of the bridge proof"}},"bridgeRelays(bytes32)":{"params":{"transactionId":"The ID of the transaction to check"},"returns":{"_0":"True if the transaction has been relayed, false otherwise"}},"bridgeStatuses(bytes32)":{"params":{"transactionId":"The ID of the bridge transaction"},"returns":{"status":"BridgeStatus Status of the bridge transaction"}},"canClaim(bytes32,address)":{"params":{"relayer":"The address of the relayer attempting to claim","transactionId":"The transaction id associated with the encoded bridge transaction to check"}},"claim(bytes)":{"params":{"request":"The encoded bridge transaction to claim on origin chain"}},"claim(bytes,address)":{"params":{"request":"The encoded bridge transaction to claim on origin chain","to":"The recipient address of the funds"}},"dispute(bytes32)":{"params":{"transactionId":"The transaction id associated with the encoded bridge transaction to dispute"}},"getBridgeTransaction(bytes)":{"details":"This method is added to achieve backwards compatibility with decoding requests into V1 structs: - `callValue` is partially reported as a zero/non-zero flag - `callParams` is ignored In order to process all kinds of requests use getBridgeTransactionV2 instead.","params":{"request":"The bridge request to decode"}},"getBridgeTransactionV2(bytes)":{"params":{"request":"The bridge request to decode"}},"getRoleAdmin(bytes32)":{"details":"Returns the admin role that controls `role`. See {grantRole} and {revokeRole}. To change a role's admin, use {_setRoleAdmin}."},"getRoleMember(bytes32,uint256)":{"details":"Returns one of the accounts that have `role`. `index` must be a value between 0 and {getRoleMemberCount}, non-inclusive. Role bearers are not sorted in any particular way, and their ordering may change at any point. WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure you perform all queries on the same block. See the following https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post] for more information."},"getRoleMemberCount(bytes32)":{"details":"Returns the number of accounts that have `role`. Can be used together with {getRoleMember} to enumerate all bearers of a role."},"grantRole(bytes32,address)":{"details":"Grants `role` to `account`. If `account` had not been already granted `role`, emits a {RoleGranted} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleGranted} event."},"hasRole(bytes32,address)":{"details":"Returns `true` if `account` has been granted `role`."},"prove(bytes,bytes32)":{"params":{"destTxHash":"The destination tx hash proving bridge transaction was relayed","request":"The encoded bridge transaction to prove on origin chain"}},"prove(bytes32,bytes32,address)":{"params":{"destTxHash":"The destination tx hash proving bridge transaction was relayed","relayer":"The address of the relaying entity which should have control of the origin funds when claimed","transactionId":"The transaction id associated with the encoded bridge transaction to prove"}},"refund(bytes)":{"params":{"request":"The encoded bridge transaction to refund"}},"relay(bytes)":{"params":{"request":"The encoded bridge transaction to relay on destination chain"}},"relay(bytes,address)":{"params":{"relayer":"The address of the relaying entity which should have control of the origin funds when claimed","request":"The encoded bridge transaction to relay on destination chain"}},"renounceRole(bytes32,address)":{"details":"Revokes `role` from the calling account. Roles are often managed via {grantRole} and {revokeRole}: this function's purpose is to provide a mechanism for accounts to lose their privileges if they are compromised (such as when a trusted device is misplaced). If the calling account had been revoked `role`, emits a {RoleRevoked} event. Requirements: - the caller must be `callerConfirmation`. May emit a {RoleRevoked} event."},"revokeRole(bytes32,address)":{"details":"Revokes `role` from `account`. If `account` had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleRevoked} event."},"supportsInterface(bytes4)":{"details":"See {IERC165-supportsInterface}."}},"stateVariables":{"nonce":{"details":"Replaced by senderNonces"}},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_owner\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"AccessControlBadConfirmation\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"neededRole\",\"type\":\"bytes32\"}],\"name\":\"AccessControlUnauthorizedAccount\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"}],\"name\":\"AddressEmptyCode\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"AddressInsufficientBalance\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"AmountIncorrect\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"CallParamsLengthAboveMax\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ChainIncorrect\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DeadlineExceeded\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DeadlineNotExceeded\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DeadlineTooShort\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DisputePeriodNotPassed\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DisputePeriodPassed\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ExclusivityParamsIncorrect\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ExclusivityPeriodNotPassed\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"FailedInnerCall\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"MsgValueIncorrect\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"NativeTokenCallValueNotSupported\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"RecipientIncorrectReturnValue\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"RecipientNoReturnValue\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"}],\"name\":\"SafeERC20FailedOperation\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"SenderIncorrect\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"StatusIncorrect\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"TokenNotContract\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"TransactionRelayed\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ZeroAddress\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"BridgeDepositClaimed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"BridgeDepositRefunded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"name\":\"BridgeProofDisputed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"transactionHash\",\"type\":\"bytes32\"}],\"name\":\"BridgeProofProvided\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"quoteId\",\"type\":\"bytes\"}],\"name\":\"BridgeQuoteDetails\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"originChainId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"chainGasAmount\",\"type\":\"uint256\"}],\"name\":\"BridgeRelayed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"destChainId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"sendChainGas\",\"type\":\"bool\"}],\"name\":\"BridgeRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"oldChainGasAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newChainGasAmount\",\"type\":\"uint256\"}],\"name\":\"ChainGasAmountUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"oldFeeRate\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newFeeRate\",\"type\":\"uint256\"}],\"name\":\"FeeRateUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"FeesSwept\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"previousAdminRole\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"newAdminRole\",\"type\":\"bytes32\"}],\"name\":\"RoleAdminChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleGranted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleRevoked\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"DEFAULT_ADMIN_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"DISPUTE_PERIOD\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"FEE_BPS\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"FEE_RATE_MAX\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"GOVERNOR_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"GUARD_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"MAX_CALL_PARAMS_LENGTH\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"MIN_DEADLINE_PERIOD\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"REFUNDER_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"REFUND_DELAY\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"RELAYER_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"dstChainId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"sendChainGas\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"}],\"internalType\":\"struct IFastBridge.BridgeParams\",\"name\":\"params\",\"type\":\"tuple\"}],\"name\":\"bridge\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"dstChainId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"sendChainGas\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"}],\"internalType\":\"struct IFastBridge.BridgeParams\",\"name\":\"params\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"quoteRelayer\",\"type\":\"address\"},{\"internalType\":\"int256\",\"name\":\"quoteExclusivitySeconds\",\"type\":\"int256\"},{\"internalType\":\"bytes\",\"name\":\"quoteId\",\"type\":\"bytes\"},{\"internalType\":\"uint256\",\"name\":\"callValue\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"callParams\",\"type\":\"bytes\"}],\"internalType\":\"struct IFastBridgeV2.BridgeParamsV2\",\"name\":\"paramsV2\",\"type\":\"tuple\"}],\"name\":\"bridge\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"}],\"name\":\"bridgeProofs\",\"outputs\":[{\"internalType\":\"uint96\",\"name\":\"timestamp\",\"type\":\"uint96\"},{\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"bridgeRelayDetails\",\"outputs\":[{\"internalType\":\"uint48\",\"name\":\"blockNumber\",\"type\":\"uint48\"},{\"internalType\":\"uint48\",\"name\":\"blockTimestamp\",\"type\":\"uint48\"},{\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"}],\"name\":\"bridgeRelays\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"}],\"name\":\"bridgeStatuses\",\"outputs\":[{\"internalType\":\"enum IFastBridgeV2.BridgeStatus\",\"name\":\"status\",\"type\":\"uint8\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"bridgeTxDetails\",\"outputs\":[{\"internalType\":\"enum IFastBridgeV2.BridgeStatus\",\"name\":\"status\",\"type\":\"uint8\"},{\"internalType\":\"uint40\",\"name\":\"proofBlockTimestamp\",\"type\":\"uint40\"},{\"internalType\":\"uint48\",\"name\":\"proofBlockNumber\",\"type\":\"uint48\"},{\"internalType\":\"address\",\"name\":\"proofRelayer\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"name\":\"canClaim\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"chainGasAmount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"claim\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"claim\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"deployBlock\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"}],\"name\":\"dispute\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"getBridgeTransaction\",\"outputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"originChainId\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"destChainId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"originSender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destRecipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"originFeeAmount\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"sendChainGas\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"}],\"internalType\":\"struct IFastBridge.BridgeTransaction\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"getBridgeTransactionV2\",\"outputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"originChainId\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"destChainId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"originSender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destRecipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"originFeeAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"callValue\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"exclusivityRelayer\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"exclusivityEndTime\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"callParams\",\"type\":\"bytes\"}],\"internalType\":\"struct IFastBridgeV2.BridgeTransactionV2\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"}],\"name\":\"getRoleAdmin\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"index\",\"type\":\"uint256\"}],\"name\":\"getRoleMember\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"}],\"name\":\"getRoleMemberCount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"grantRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"hasRole\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"nonce\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"protocolFeeRate\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"protocolFees\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"destTxHash\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"name\":\"prove\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"},{\"internalType\":\"bytes32\",\"name\":\"destTxHash\",\"type\":\"bytes32\"}],\"name\":\"prove\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"refund\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"relay\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"},{\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"name\":\"relay\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"callerConfirmation\",\"type\":\"address\"}],\"name\":\"renounceRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"revokeRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"senderNonces\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"newChainGasAmount\",\"type\":\"uint256\"}],\"name\":\"setChainGasAmount\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"newFeeRate\",\"type\":\"uint256\"}],\"name\":\"setProtocolFeeRate\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes4\",\"name\":\"interfaceId\",\"type\":\"bytes4\"}],\"name\":\"supportsInterface\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"}],\"name\":\"sweepProtocolFees\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"errors\":{\"AccessControlBadConfirmation()\":[{\"details\":\"The caller of a function is not the expected one. NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\"}],\"AccessControlUnauthorizedAccount(address,bytes32)\":[{\"details\":\"The `account` is missing a role.\"}],\"AddressEmptyCode(address)\":[{\"details\":\"There's no code at `target` (it is not a contract).\"}],\"AddressInsufficientBalance(address)\":[{\"details\":\"The ETH balance of the account is not enough to perform the operation.\"}],\"FailedInnerCall()\":[{\"details\":\"A call to an address target failed. The target may have reverted.\"}],\"SafeERC20FailedOperation(address)\":[{\"details\":\"An operation with an ERC20 token failed.\"}]},\"events\":{\"RoleAdminChanged(bytes32,bytes32,bytes32)\":{\"details\":\"Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole` `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite {RoleAdminChanged} not being emitted signaling this.\"},\"RoleGranted(bytes32,address,address)\":{\"details\":\"Emitted when `account` is granted `role`. `sender` is the account that originated the contract call, an admin role bearer except when using {AccessControl-_setupRole}.\"},\"RoleRevoked(bytes32,address,address)\":{\"details\":\"Emitted when `account` is revoked `role`. `sender` is the account that originated the contract call: - if using `revokeRole`, it is the admin role bearer - if using `renounceRole`, it is the role bearer (i.e. `account`)\"}},\"kind\":\"dev\",\"methods\":{\"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256))\":{\"params\":{\"params\":\"The parameters required to bridge\"}},\"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256),(address,int256,bytes,uint256,bytes))\":{\"params\":{\"params\":\"The parameters required to bridge\",\"paramsV2\":\"The parameters for exclusivity fill rights (optional, can be left empty)\"}},\"bridgeProofs(bytes32)\":{\"params\":{\"transactionId\":\"The ID of the bridge transaction\"},\"returns\":{\"relayer\":\"The relayer address of the bridge proof\",\"timestamp\":\"The timestamp of the bridge proof\"}},\"bridgeRelays(bytes32)\":{\"params\":{\"transactionId\":\"The ID of the transaction to check\"},\"returns\":{\"_0\":\"True if the transaction has been relayed, false otherwise\"}},\"bridgeStatuses(bytes32)\":{\"params\":{\"transactionId\":\"The ID of the bridge transaction\"},\"returns\":{\"status\":\"BridgeStatus Status of the bridge transaction\"}},\"canClaim(bytes32,address)\":{\"params\":{\"relayer\":\"The address of the relayer attempting to claim\",\"transactionId\":\"The transaction id associated with the encoded bridge transaction to check\"}},\"claim(bytes)\":{\"params\":{\"request\":\"The encoded bridge transaction to claim on origin chain\"}},\"claim(bytes,address)\":{\"params\":{\"request\":\"The encoded bridge transaction to claim on origin chain\",\"to\":\"The recipient address of the funds\"}},\"dispute(bytes32)\":{\"params\":{\"transactionId\":\"The transaction id associated with the encoded bridge transaction to dispute\"}},\"getBridgeTransaction(bytes)\":{\"details\":\"This method is added to achieve backwards compatibility with decoding requests into V1 structs: - `callValue` is partially reported as a zero/non-zero flag - `callParams` is ignored In order to process all kinds of requests use getBridgeTransactionV2 instead.\",\"params\":{\"request\":\"The bridge request to decode\"}},\"getBridgeTransactionV2(bytes)\":{\"params\":{\"request\":\"The bridge request to decode\"}},\"getRoleAdmin(bytes32)\":{\"details\":\"Returns the admin role that controls `role`. See {grantRole} and {revokeRole}. To change a role's admin, use {_setRoleAdmin}.\"},\"getRoleMember(bytes32,uint256)\":{\"details\":\"Returns one of the accounts that have `role`. `index` must be a value between 0 and {getRoleMemberCount}, non-inclusive. Role bearers are not sorted in any particular way, and their ordering may change at any point. WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure you perform all queries on the same block. See the following https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post] for more information.\"},\"getRoleMemberCount(bytes32)\":{\"details\":\"Returns the number of accounts that have `role`. Can be used together with {getRoleMember} to enumerate all bearers of a role.\"},\"grantRole(bytes32,address)\":{\"details\":\"Grants `role` to `account`. If `account` had not been already granted `role`, emits a {RoleGranted} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleGranted} event.\"},\"hasRole(bytes32,address)\":{\"details\":\"Returns `true` if `account` has been granted `role`.\"},\"prove(bytes,bytes32)\":{\"params\":{\"destTxHash\":\"The destination tx hash proving bridge transaction was relayed\",\"request\":\"The encoded bridge transaction to prove on origin chain\"}},\"prove(bytes32,bytes32,address)\":{\"params\":{\"destTxHash\":\"The destination tx hash proving bridge transaction was relayed\",\"relayer\":\"The address of the relaying entity which should have control of the origin funds when claimed\",\"transactionId\":\"The transaction id associated with the encoded bridge transaction to prove\"}},\"refund(bytes)\":{\"params\":{\"request\":\"The encoded bridge transaction to refund\"}},\"relay(bytes)\":{\"params\":{\"request\":\"The encoded bridge transaction to relay on destination chain\"}},\"relay(bytes,address)\":{\"params\":{\"relayer\":\"The address of the relaying entity which should have control of the origin funds when claimed\",\"request\":\"The encoded bridge transaction to relay on destination chain\"}},\"renounceRole(bytes32,address)\":{\"details\":\"Revokes `role` from the calling account. Roles are often managed via {grantRole} and {revokeRole}: this function's purpose is to provide a mechanism for accounts to lose their privileges if they are compromised (such as when a trusted device is misplaced). If the calling account had been revoked `role`, emits a {RoleRevoked} event. Requirements: - the caller must be `callerConfirmation`. May emit a {RoleRevoked} event.\"},\"revokeRole(bytes32,address)\":{\"details\":\"Revokes `role` from `account`. If `account` had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleRevoked} event.\"},\"supportsInterface(bytes4)\":{\"details\":\"See {IERC165-supportsInterface}.\"}},\"stateVariables\":{\"nonce\":{\"details\":\"Replaced by senderNonces\"}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"DISPUTE_PERIOD()\":{\"notice\":\"Dispute period for relayed transactions\"},\"MAX_CALL_PARAMS_LENGTH()\":{\"notice\":\"Maximum length of accepted callParams\"},\"MIN_DEADLINE_PERIOD()\":{\"notice\":\"Minimum deadline period to relay a requested bridge transaction\"},\"REFUND_DELAY()\":{\"notice\":\"Delay for a transaction after which it could be permisionlessly refunded\"},\"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256))\":{\"notice\":\"Initiates bridge on origin chain to be relayed by off-chain relayer\"},\"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256),(address,int256,bytes,uint256,bytes))\":{\"notice\":\"Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability to provide temporary exclusivity fill rights for the quote relayer.\"},\"bridgeProofs(bytes32)\":{\"notice\":\"Returns the timestamp and relayer of a bridge proof\"},\"bridgeRelayDetails(bytes32)\":{\"notice\":\"Relay details on destination chain\"},\"bridgeRelays(bytes32)\":{\"notice\":\"Checks if a transaction has been relayed\"},\"bridgeStatuses(bytes32)\":{\"notice\":\"Returns the status of a bridge transaction\"},\"bridgeTxDetails(bytes32)\":{\"notice\":\"Status of the bridge tx on origin chain\"},\"canClaim(bytes32,address)\":{\"notice\":\"Checks if the dispute period has passed so bridge deposit can be claimed\"},\"chainGasAmount()\":{\"notice\":\"Chain gas amount to forward as rebate if requested\"},\"claim(bytes)\":{\"notice\":\"Completes bridge transaction on origin chain by claiming originally deposited capital.Can only send funds to the relayer address on the proof.\"},\"claim(bytes,address)\":{\"notice\":\"Completes bridge transaction on origin chain by claiming originally deposited capital\"},\"deployBlock()\":{\"notice\":\"the block the contract was deployed at\"},\"dispute(bytes32)\":{\"notice\":\"Disputes an outstanding proof in case relayer provided dest chain tx is invalid\"},\"getBridgeTransaction(bytes)\":{\"notice\":\"Decodes bridge request into a bridge transaction\"},\"getBridgeTransactionV2(bytes)\":{\"notice\":\"Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\"},\"nonce()\":{\"notice\":\"This is deprecated and should not be used.\"},\"protocolFeeRate()\":{\"notice\":\"Protocol fee rate taken on origin amount deposited in origin chain\"},\"protocolFees(address)\":{\"notice\":\"Protocol fee amounts accumulated\"},\"prove(bytes,bytes32)\":{\"notice\":\"Provides proof on origin side that relayer provided funds on destination side of bridge transaction\"},\"prove(bytes32,bytes32,address)\":{\"notice\":\"Provides proof on origin side that relayer provided funds on destination side of bridge transaction\"},\"refund(bytes)\":{\"notice\":\"Refunds an outstanding bridge transaction in case optimistic bridging failed\"},\"relay(bytes)\":{\"notice\":\"Relays destination side of bridge transaction by off-chain relayer\"},\"relay(bytes,address)\":{\"notice\":\"Relays destination side of bridge transaction by off-chain relayer\"},\"senderNonces(address)\":{\"notice\":\"Unique bridge nonces tracked per originSender\"}},\"notice\":\"FastBridgeV2 is a contract for bridging tokens across chains.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeV2.sol\":\"FastBridgeV2\"},\"evmVersion\":\"shanghai\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeV2.sol\":{\"keccak256\":\"0x7cd0f885e80e2bdaa638bc32ae7af7d2e248f99ce4b354c217d0f0f7d7302e0a\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://7ccf28df0bd7b4606986585acd8622ed9b4e81379690061bb66088f0a2270af1\",\"dweb:/ipfs/QmTf7HNdHZkK6vmx8ZgewycQEb72oLD9nPwBpsM5reMstQ\"]}},\"version\":1}"},"hashes":{"DEFAULT_ADMIN_ROLE()":"a217fddf","DISPUTE_PERIOD()":"a5bbe22b","FEE_BPS()":"bf333f2c","FEE_RATE_MAX()":"0f5f6ed7","GOVERNOR_ROLE()":"ccc57490","GUARD_ROLE()":"03ed0ee5","MAX_CALL_PARAMS_LENGTH()":"df36bb13","MIN_DEADLINE_PERIOD()":"820688d5","REFUNDER_ROLE()":"5960ccf2","REFUND_DELAY()":"190da595","RELAYER_ROLE()":"926d7d7f","bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256))":"45851694","bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256),(address,int256,bytes,uint256,bytes))":"bfc7c607","bridgeProofs(bytes32)":"91ad5039","bridgeRelayDetails(bytes32)":"c79371b1","bridgeRelays(bytes32)":"8379a24f","bridgeStatuses(bytes32)":"051287bc","bridgeTxDetails(bytes32)":"63787e52","canClaim(bytes32,address)":"aa9641ab","chainGasAmount()":"e00a83e0","claim(bytes)":"c63ff8dd","claim(bytes,address)":"41fcb612","deployBlock()":"a3ec191a","dispute(bytes32)":"add98c70","getBridgeTransaction(bytes)":"ac11fb1a","getBridgeTransactionV2(bytes)":"5aa6ccba","getRoleAdmin(bytes32)":"248a9ca3","getRoleMember(bytes32,uint256)":"9010d07c","getRoleMemberCount(bytes32)":"ca15c873","grantRole(bytes32,address)":"2f2ff15d","hasRole(bytes32,address)":"91d14854","nonce()":"affed0e0","protocolFeeRate()":"58f85880","protocolFees(address)":"dcf844a7","prove(bytes,bytes32)":"886d36ff","prove(bytes32,bytes32,address)":"18e4357d","refund(bytes)":"5eb7d946","relay(bytes)":"8f0d6f17","relay(bytes,address)":"9c9545f0","renounceRole(bytes32,address)":"36568abe","revokeRole(bytes32,address)":"d547741f","senderNonces(address)":"295710ff","setChainGasAmount(uint256)":"b250fe6b","setProtocolFeeRate(uint256)":"b13aa2d6","supportsInterface(bytes4)":"01ffc9a7","sweepProtocolFees(address,address)":"06f333f2"}},"solidity/FastBridgeV2.sol:IAccessControl":{"code":"0x","runtime-code":"0x","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.24 ^0.8.0 ^0.8.20;\n\n// contracts/interfaces/IAdmin.sol\n\ninterface IAdmin {\n // ============ Events ============\n\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n event ChainGasAmountUpdated(uint256 oldChainGasAmount, uint256 newChainGasAmount);\n\n // ============ Methods ============\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n\n function setChainGasAmount(uint256 newChainGasAmount) external;\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IFastBridgeRecipient.sol\n\ninterface IFastBridgeRecipient {\n function fastBridgeTransferReceived(\n address token,\n uint256 amount,\n bytes memory callParams\n )\n external\n payable\n returns (bytes4);\n}\n\n// contracts/interfaces/IFastBridgeV2Errors.sol\n\ninterface IFastBridgeV2Errors {\n error AmountIncorrect();\n error CallParamsLengthAboveMax();\n error ChainIncorrect();\n error ExclusivityParamsIncorrect();\n error MsgValueIncorrect();\n error NativeTokenCallValueNotSupported();\n error SenderIncorrect();\n error StatusIncorrect();\n error ZeroAddress();\n\n error RecipientIncorrectReturnValue();\n error RecipientNoReturnValue();\n\n error DeadlineExceeded();\n error DeadlineNotExceeded();\n error DeadlineTooShort();\n error DisputePeriodNotPassed();\n error DisputePeriodPassed();\n error ExclusivityPeriodNotPassed();\n\n error TransactionRelayed();\n}\n\n// contracts/libs/Errors.sol\n\nerror DeadlineExceeded();\nerror DeadlineNotExceeded();\nerror DeadlineTooShort();\nerror InsufficientOutputAmount();\n\nerror MsgValueIncorrect();\nerror PoolNotFound();\nerror TokenAddressMismatch();\nerror TokenNotContract();\nerror TokenNotETH();\nerror TokensIdentical();\n\nerror ChainIncorrect();\nerror AmountIncorrect();\nerror ZeroAddress();\n\nerror DisputePeriodNotPassed();\nerror DisputePeriodPassed();\nerror SenderIncorrect();\nerror StatusIncorrect();\nerror TransactionIdIncorrect();\nerror TransactionRelayed();\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// contracts/interfaces/IFastBridgeV2.sol\n\ninterface IFastBridgeV2 is IFastBridge {\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n struct BridgeTxDetails {\n BridgeStatus status;\n uint40 proofBlockTimestamp;\n uint48 proofBlockNumber;\n address proofRelayer;\n }\n\n struct BridgeRelay {\n uint48 blockNumber;\n uint48 blockTimestamp;\n address relayer;\n }\n\n /// @notice New params introduced in the FastBridgeV2.\n /// We are passing fields from the older BridgeParams struct outside of this struct\n /// for backwards compatibility.\n /// Note: quoteRelayer and quoteExclusivitySeconds are either both zero (indicating no exclusivity)\n /// or both non-zero (indicating exclusivity for the given period).\n /// Note: callValue \u003e 0 can NOT be used with destToken = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE (ETH_ADDRESS)\n /// @param quoteRelayer Relayer that provided the quote for the transaction\n /// @param quoteExclusivitySeconds Period of time the quote relayer is guaranteed exclusivity after user's deposit\n /// @param quoteId Unique quote identifier used for tracking the quote\n /// @param callValue ETH value to send to the recipient (if any)\n /// @param callParams Parameters for the arbitrary call to the destination recipient (if any)\n struct BridgeParamsV2 {\n address quoteRelayer;\n int256 quoteExclusivitySeconds;\n bytes quoteId;\n uint256 callValue;\n bytes callParams;\n }\n\n /// @notice Updated bridge transaction struct to include parameters introduced in FastBridgeV2.\n /// Note: only `exclusivityRelayer` can fill such a transaction until `exclusivityEndTime`.\n /// TODO: consider changing the encoding scheme to prevent spending extra gas on decoding.\n struct BridgeTransactionV2 {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n uint256 callValue; // ETH value to send to the recipient (if any) - replaces V1's sendChainGas flag\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n address exclusivityRelayer;\n uint256 exclusivityEndTime;\n bytes callParams;\n }\n\n event BridgeQuoteDetails(bytes32 indexed transactionId, bytes quoteId);\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability\n /// to provide temporary exclusivity fill rights for the quote relayer.\n /// @param params The parameters required to bridge\n /// @param paramsV2 The parameters for exclusivity fill rights (optional, can be left empty)\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function relay(bytes memory request, address relayer) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param transactionId The transaction id associated with the encoded bridge transaction to prove\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital.\n /// @notice Can only send funds to the relayer address on the proof.\n /// @param request The encoded bridge transaction to claim on origin chain\n function claim(bytes memory request) external;\n /// @notice Checks if a transaction has been relayed\n /// @param transactionId The ID of the transaction to check\n /// @return True if the transaction has been relayed, false otherwise\n function bridgeRelays(bytes32 transactionId) external view returns (bool);\n\n /// @notice Returns the status of a bridge transaction\n /// @param transactionId The ID of the bridge transaction\n /// @return BridgeStatus Status of the bridge transaction\n function bridgeStatuses(bytes32 transactionId) external view returns (BridgeStatus);\n\n /// @notice Returns the timestamp and relayer of a bridge proof\n /// @param transactionId The ID of the bridge transaction\n /// @return timestamp The timestamp of the bridge proof\n /// @return relayer The relayer address of the bridge proof\n function bridgeProofs(bytes32 transactionId) external view returns (uint96 timestamp, address relayer);\n\n /// @notice Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\n /// @param request The bridge request to decode\n function getBridgeTransactionV2(bytes memory request) external view returns (BridgeTransactionV2 memory);\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// contracts/libs/UniversalToken.sol\n\nlibrary UniversalTokenLib {\n using SafeERC20 for IERC20;\n\n address internal constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Transfers tokens to the given account. Reverts if transfer is not successful.\n /// @dev This might trigger fallback, if ETH is transferred to the contract.\n /// Make sure this can not lead to reentrancy attacks.\n function universalTransfer(address token, address to, uint256 value) internal {\n // Don't do anything, if need to send tokens to this address\n if (to == address(this)) return;\n // Don't do anything, if trying to send zero value\n if (value == 0) return;\n if (token == ETH_ADDRESS) {\n /// @dev Note: this can potentially lead to executing code in `to`.\n // solhint-disable-next-line avoid-low-level-calls\n (bool success,) = to.call{value: value}(\"\");\n require(success, \"ETH transfer failed\");\n } else {\n IERC20(token).safeTransfer(to, value);\n }\n }\n\n /// @notice Issues an infinite allowance to the spender, if the current allowance is insufficient\n /// to spend the given amount.\n function universalApproveInfinity(address token, address spender, uint256 amountToSpend) internal {\n // ETH Chad doesn't require your approval\n if (token == ETH_ADDRESS) return;\n // No-op if allowance is already sufficient\n uint256 allowance = IERC20(token).allowance(address(this), spender);\n if (allowance \u003e= amountToSpend) return;\n // Otherwise, reset approval to 0 and set to max allowance\n if (allowance \u003e 0) IERC20(token).safeDecreaseAllowance(spender, allowance);\n IERC20(token).safeIncreaseAllowance(spender, type(uint256).max);\n }\n\n /// @notice Returns the balance of the given token (or native ETH) for the given account.\n function universalBalanceOf(address token, address account) internal view returns (uint256) {\n if (token == ETH_ADDRESS) {\n return account.balance;\n } else {\n return IERC20(token).balanceOf(account);\n }\n }\n\n /// @dev Checks that token is a contract and not ETH_ADDRESS.\n function assertIsContract(address token) internal view {\n // Check that ETH_ADDRESS was not used (in case this is a predeploy on any of the chains)\n if (token == UniversalTokenLib.ETH_ADDRESS) revert TokenNotContract();\n // Check that token is not an EOA\n if (token.code.length == 0) revert TokenNotContract();\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/Admin.sol\n\ncontract Admin is IAdmin, AccessControlEnumerable {\n using UniversalTokenLib for address;\n\n bytes32 public constant RELAYER_ROLE = keccak256(\"RELAYER_ROLE\");\n bytes32 public constant REFUNDER_ROLE = keccak256(\"REFUNDER_ROLE\");\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n uint256 public constant FEE_BPS = 1e6;\n uint256 public constant FEE_RATE_MAX = 0.01e6; // max 1% on origin amount\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Chain gas amount to forward as rebate if requested\n uint256 public chainGasAmount;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n }\n\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n require(newFeeRate \u003c= FEE_RATE_MAX, \"newFeeRate \u003e max\");\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n token.universalTransfer(recipient, feeAmount);\n emit FeesSwept(token, recipient, feeAmount);\n }\n\n function setChainGasAmount(uint256 newChainGasAmount) external onlyRole(GOVERNOR_ROLE) {\n uint256 oldChainGasAmount = chainGasAmount;\n chainGasAmount = newChainGasAmount;\n emit ChainGasAmountUpdated(oldChainGasAmount, newChainGasAmount);\n }\n}\n\n// contracts/FastBridgeV2.sol\n\n/// @notice FastBridgeV2 is a contract for bridging tokens across chains.\ncontract FastBridgeV2 is Admin, IFastBridgeV2, IFastBridgeV2Errors {\n using SafeERC20 for IERC20;\n using UniversalTokenLib for address;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Delay for a transaction after which it could be permisionlessly refunded\n uint256 public constant REFUND_DELAY = 7 days;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n /// @notice Maximum length of accepted callParams\n uint256 public constant MAX_CALL_PARAMS_LENGTH = 2 ** 16 - 1;\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeTxDetails) public bridgeTxDetails;\n /// @notice Relay details on destination chain\n mapping(bytes32 =\u003e BridgeRelay) public bridgeRelayDetails;\n /// @notice Unique bridge nonces tracked per originSender\n mapping(address =\u003e uint256) public senderNonces;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Replaced by senderNonces\n uint256 public immutable nonce = 0;\n /// @notice the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n bridge({\n params: params,\n paramsV2: BridgeParamsV2({\n quoteRelayer: address(0),\n quoteExclusivitySeconds: 0,\n quoteId: bytes(\"\"),\n callValue: 0,\n callParams: bytes(\"\")\n })\n });\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes memory request) external payable {\n relay({request: request, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes memory request, bytes32 destTxHash) external {\n prove({transactionId: keccak256(request), destTxHash: destTxHash, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridgeV2\n function claim(bytes memory request) external {\n claim({request: request, to: address(0)});\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003e DISPUTE_PERIOD) {\n revert DisputePeriodPassed();\n }\n\n // @dev relayer gets slashed effectively if dest relay has gone thru\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n bridgeTxDetails[transactionId].proofRelayer = address(0);\n bridgeTxDetails[transactionId].proofBlockTimestamp = 0;\n bridgeTxDetails[transactionId].proofBlockNumber = 0;\n\n emit BridgeProofDisputed(transactionId, msg.sender);\n }\n\n /// @inheritdoc IFastBridge\n function refund(bytes memory request) external {\n bytes32 transactionId = keccak256(request);\n\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n\n if (bridgeTxDetails[transactionId].status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n\n if (hasRole(REFUNDER_ROLE, msg.sender)) {\n // Refunder can refund if deadline has passed\n if (block.timestamp \u003c= transaction.deadline) revert DeadlineNotExceeded();\n } else {\n // Permissionless refund is allowed after REFUND_DELAY\n if (block.timestamp \u003c= transaction.deadline + REFUND_DELAY) revert DeadlineNotExceeded();\n }\n\n // if all checks passed, set to REFUNDED status\n bridgeTxDetails[transactionId].status = BridgeStatus.REFUNDED;\n\n // transfer origin collateral back to original sender\n address to = transaction.originSender;\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount + transaction.originFeeAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (bridgeTxDetails[transactionId].proofRelayer != relayer) revert SenderIncorrect();\n return _timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n /// @dev This method is added to achieve backwards compatibility with decoding requests into V1 structs:\n /// - `callValue` is partially reported as a zero/non-zero flag\n /// - `callParams` is ignored\n /// In order to process all kinds of requests use getBridgeTransactionV2 instead.\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory) {\n // Try decoding into V2 struct first. This will revert if V1 struct is passed\n try this.getBridgeTransactionV2(request) returns (BridgeTransactionV2 memory txV2) {\n // Note: we entirely ignore the callParams field, as it was not present in V1\n return BridgeTransaction({\n originChainId: txV2.originChainId,\n destChainId: txV2.destChainId,\n originSender: txV2.originSender,\n destRecipient: txV2.destRecipient,\n originToken: txV2.originToken,\n destToken: txV2.destToken,\n originAmount: txV2.originAmount,\n destAmount: txV2.destAmount,\n originFeeAmount: txV2.originFeeAmount,\n sendChainGas: txV2.callValue != 0,\n deadline: txV2.deadline,\n nonce: txV2.nonce\n });\n } catch {\n // Fallback to V1 struct\n return abi.decode(request, (BridgeTransaction));\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) public payable {\n int256 exclusivityEndTime = int256(block.timestamp) + paramsV2.quoteExclusivitySeconds;\n _validateBridgeParams(params, paramsV2, exclusivityEndTime);\n\n // transfer tokens to bridge contract\n /// @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _pullToken(params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n\n // set status to requested\n bytes memory request = abi.encode(\n BridgeTransactionV2({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n callValue: paramsV2.callValue,\n deadline: params.deadline,\n nonce: senderNonces[params.sender]++, // increment nonce on every bridge\n exclusivityRelayer: paramsV2.quoteRelayer,\n // We checked exclusivityEndTime to be in range (0 .. params.deadline] above, so can safely cast\n exclusivityEndTime: uint256(exclusivityEndTime),\n callParams: paramsV2.callParams\n })\n );\n bytes32 transactionId = keccak256(request);\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n\n emit BridgeRequested({\n transactionId: transactionId,\n sender: params.sender,\n request: request,\n destChainId: params.dstChainId,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n sendChainGas: paramsV2.callValue != 0\n });\n emit BridgeQuoteDetails(transactionId, paramsV2.quoteId);\n }\n\n /// @inheritdoc IFastBridgeV2\n function relay(bytes memory request, address relayer) public payable {\n bytes32 transactionId = keccak256(request);\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n _validateRelayParams(transaction, transactionId, relayer);\n // mark bridge transaction as relayed\n bridgeRelayDetails[transactionId] =\n BridgeRelay({blockNumber: uint48(block.number), blockTimestamp: uint48(block.timestamp), relayer: relayer});\n\n // transfer tokens to recipient on destination chain and do an arbitrary call if requested\n address to = transaction.destRecipient;\n address token = transaction.destToken;\n uint256 amount = transaction.destAmount;\n\n // All state changes have been done at this point, can proceed to the external calls.\n // This follows the checks-effects-interactions pattern to mitigate potential reentrancy attacks.\n if (token == UniversalTokenLib.ETH_ADDRESS) {\n // For ETH non-zero callValue is not allowed\n if (transaction.callValue != 0) revert NativeTokenCallValueNotSupported();\n // Check that the correct msg.value was sent\n if (msg.value != amount) revert MsgValueIncorrect();\n } else {\n // For ERC20s, we check that the correct msg.value was sent\n if (msg.value != transaction.callValue) revert MsgValueIncorrect();\n // We need to transfer the tokens from the Relayer to the recipient first before performing an\n // optional post-transfer arbitrary call.\n IERC20(token).safeTransferFrom(msg.sender, to, amount);\n }\n\n if (transaction.callParams.length != 0) {\n // Arbitrary call requested, perform it while supplying full msg.value to the recipient\n // Note: if token has a fee on transfers, the recipient will have received less than `amount`.\n // This is a very niche edge case and should be handled by the recipient contract.\n _checkedCallRecipient({recipient: to, token: token, amount: amount, callParams: transaction.callParams});\n } else if (msg.value != 0) {\n // No arbitrary call requested, but msg.value was sent. This is either a relay with ETH,\n // or a non-zero callValue request with an ERC20. In both cases, transfer the ETH to the recipient.\n Address.sendValue(payable(to), msg.value);\n }\n\n emit BridgeRelayed({\n transactionId: transactionId,\n relayer: relayer,\n to: to,\n originChainId: transaction.originChainId,\n originToken: transaction.originToken,\n destToken: transaction.destToken,\n originAmount: transaction.originAmount,\n destAmount: transaction.destAmount,\n chainGasAmount: transaction.callValue\n });\n }\n\n /// @inheritdoc IFastBridgeV2\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) public onlyRole(RELAYER_ROLE) {\n // update bridge tx status given proof provided\n if (bridgeTxDetails[transactionId].status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n bridgeTxDetails[transactionId].status = BridgeStatus.RELAYER_PROVED;\n bridgeTxDetails[transactionId].proofBlockTimestamp = uint40(block.timestamp);\n bridgeTxDetails[transactionId].proofBlockNumber = uint48(block.number);\n bridgeTxDetails[transactionId].proofRelayer = relayer;\n\n emit BridgeProofProvided(transactionId, relayer, destTxHash);\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes memory request, address to) public {\n bytes32 transactionId = keccak256(request);\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n\n // update bridge tx status if able to claim origin collateral\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n\n // if \"to\" is zero addr, permissionlessly send funds to proven relayer\n if (to == address(0)) {\n to = bridgeTxDetails[transactionId].proofRelayer;\n } else if (bridgeTxDetails[transactionId].proofRelayer != msg.sender) {\n revert SenderIncorrect();\n }\n\n if (_timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003c= DISPUTE_PERIOD) {\n revert DisputePeriodNotPassed();\n }\n\n bridgeTxDetails[transactionId].status = BridgeStatus.RELAYER_CLAIMED;\n\n // update protocol fees if origin fee amount exists\n if (transaction.originFeeAmount \u003e 0) protocolFees[transaction.originToken] += transaction.originFeeAmount;\n\n // transfer origin collateral less fee to specified address\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositClaimed(transactionId, bridgeTxDetails[transactionId].proofRelayer, to, token, amount);\n }\n\n function bridgeStatuses(bytes32 transactionId) public view returns (BridgeStatus status) {\n return bridgeTxDetails[transactionId].status;\n }\n\n function bridgeProofs(bytes32 transactionId) public view returns (uint96 timestamp, address relayer) {\n timestamp = bridgeTxDetails[transactionId].proofBlockTimestamp;\n relayer = bridgeTxDetails[transactionId].proofRelayer;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeRelays(bytes32 transactionId) public view returns (bool) {\n // has this transactionId been relayed?\n return bridgeRelayDetails[transactionId].relayer != address(0);\n }\n\n /// @inheritdoc IFastBridgeV2\n function getBridgeTransactionV2(bytes memory request) public pure returns (BridgeTransactionV2 memory) {\n return abi.decode(request, (BridgeTransactionV2));\n }\n\n /// @notice Pulls a requested token from the user to this contract.\n function _pullToken(address token, uint256 amount) internal returns (uint256 amountPulled) {\n if (token == UniversalTokenLib.ETH_ADDRESS) {\n // For ETH we just need to check that the supplied msg.value is correct\n if (amount != msg.value) revert MsgValueIncorrect();\n amountPulled = msg.value;\n } else {\n token.assertIsContract();\n // Record token balance before transfer\n amountPulled = IERC20(token).balanceOf(address(this));\n // Token needs to be pulled only if msg.value is zero\n // This way user can specify WETH as the origin asset\n IERC20(token).safeTransferFrom(msg.sender, address(this), amount);\n // Use the difference between the recorded balance and the current balance as the amountPulled\n amountPulled = IERC20(token).balanceOf(address(this)) - amountPulled;\n }\n }\n\n /// @notice Calls the Recipient's hook function with the specified callParams and performs\n /// all the necessary checks for the returned value.\n function _checkedCallRecipient(\n address recipient,\n address token,\n uint256 amount,\n bytes memory callParams\n )\n internal\n {\n bytes memory hookData =\n abi.encodeCall(IFastBridgeRecipient.fastBridgeTransferReceived, (token, amount, callParams));\n // This will bubble any revert messages from the hook function\n bytes memory returnData = Address.functionCallWithValue({target: recipient, data: hookData, value: msg.value});\n // Explicit revert if no return data at all\n if (returnData.length == 0) revert RecipientNoReturnValue();\n // Check that exactly a single return value was returned\n if (returnData.length != 32) revert RecipientIncorrectReturnValue();\n // Return value should be abi-encoded hook function selector\n if (bytes32(returnData) != bytes32(IFastBridgeRecipient.fastBridgeTransferReceived.selector)) {\n revert RecipientIncorrectReturnValue();\n }\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint40(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint40).max but\n /// proof.timestamp \u003c type(uint40).max via unchecked statement\n /// @param proofBlockTimestamp The bridge proof block timestamp\n /// @return delta Time delta since proof submitted\n function _timeSince(uint40 proofBlockTimestamp) internal view returns (uint256 delta) {\n unchecked {\n delta = uint40(block.timestamp) - proofBlockTimestamp;\n }\n }\n\n /// @notice Performs all the necessary checks for a bridge to happen.\n /// @dev There's no good way to refactor this function to reduce cyclomatic complexity due to\n /// the number of checks that need to be performed, so we skip the code-complexity rule here.\n // solhint-disable-next-line code-complexity\n function _validateBridgeParams(\n BridgeParams memory params,\n BridgeParamsV2 memory paramsV2,\n int256 exclusivityEndTime\n )\n internal\n view\n {\n // Check V1 (legacy) params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.sender == address(0) || params.to == address(0)) revert ZeroAddress();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n // Check V2 params\n if (paramsV2.callParams.length \u003e MAX_CALL_PARAMS_LENGTH) revert CallParamsLengthAboveMax();\n if (paramsV2.callValue != 0 \u0026\u0026 params.destToken == UniversalTokenLib.ETH_ADDRESS) {\n revert NativeTokenCallValueNotSupported();\n }\n // exclusivityEndTime must be in range (0 .. params.deadline]\n if (exclusivityEndTime \u003c= 0 || exclusivityEndTime \u003e int256(params.deadline)) {\n revert ExclusivityParamsIncorrect();\n }\n }\n\n /// @notice Performs all the necessary checks for a relay to happen.\n function _validateRelayParams(\n BridgeTransactionV2 memory transaction,\n bytes32 transactionId,\n address relayer\n )\n internal\n view\n {\n if (relayer == address(0)) revert ZeroAddress();\n // Check if the transaction has already been relayed\n if (bridgeRelays(transactionId)) revert TransactionRelayed();\n if (transaction.destChainId != uint32(block.chainid)) revert ChainIncorrect();\n // Check the deadline for relay to happen\n if (block.timestamp \u003e transaction.deadline) revert DeadlineExceeded();\n // Check the exclusivity period, if it is still ongoing\n // forgefmt: disable-next-item\n if (\n transaction.exclusivityRelayer != address(0) \u0026\u0026\n transaction.exclusivityRelayer != relayer \u0026\u0026\n block.timestamp \u003c= transaction.exclusivityEndTime\n ) {\n revert ExclusivityPeriodNotPassed();\n }\n }\n}\n","language":"Solidity","languageVersion":"0.8.24","compilerVersion":"0.8.24","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../","srcMap":"","srcMapRuntime":"","abiDefinition":[{"inputs":[],"name":"AccessControlBadConfirmation","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"bytes32","name":"neededRole","type":"bytes32"}],"name":"AccessControlUnauthorizedAccount","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"previousAdminRole","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"newAdminRole","type":"bytes32"}],"name":"RoleAdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleRevoked","type":"event"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleAdmin","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"grantRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"hasRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"callerConfirmation","type":"address"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"revokeRole","outputs":[],"stateMutability":"nonpayable","type":"function"}],"userDoc":{"kind":"user","methods":{},"version":1},"developerDoc":{"details":"External interface of AccessControl declared to support ERC165 detection.","errors":{"AccessControlBadConfirmation()":[{"details":"The caller of a function is not the expected one. NOTE: Don't confuse with {AccessControlUnauthorizedAccount}."}],"AccessControlUnauthorizedAccount(address,bytes32)":[{"details":"The `account` is missing a role."}]},"events":{"RoleAdminChanged(bytes32,bytes32,bytes32)":{"details":"Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole` `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite {RoleAdminChanged} not being emitted signaling this."},"RoleGranted(bytes32,address,address)":{"details":"Emitted when `account` is granted `role`. `sender` is the account that originated the contract call, an admin role bearer except when using {AccessControl-_setupRole}."},"RoleRevoked(bytes32,address,address)":{"details":"Emitted when `account` is revoked `role`. `sender` is the account that originated the contract call: - if using `revokeRole`, it is the admin role bearer - if using `renounceRole`, it is the role bearer (i.e. `account`)"}},"kind":"dev","methods":{"getRoleAdmin(bytes32)":{"details":"Returns the admin role that controls `role`. See {grantRole} and {revokeRole}. To change a role's admin, use {AccessControl-_setRoleAdmin}."},"grantRole(bytes32,address)":{"details":"Grants `role` to `account`. If `account` had not been already granted `role`, emits a {RoleGranted} event. Requirements: - the caller must have ``role``'s admin role."},"hasRole(bytes32,address)":{"details":"Returns `true` if `account` has been granted `role`."},"renounceRole(bytes32,address)":{"details":"Revokes `role` from the calling account. Roles are often managed via {grantRole} and {revokeRole}: this function's purpose is to provide a mechanism for accounts to lose their privileges if they are compromised (such as when a trusted device is misplaced). If the calling account had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must be `callerConfirmation`."},"revokeRole(bytes32,address)":{"details":"Revokes `role` from `account`. If `account` had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must have ``role``'s admin role."}},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[],\"name\":\"AccessControlBadConfirmation\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"neededRole\",\"type\":\"bytes32\"}],\"name\":\"AccessControlUnauthorizedAccount\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"previousAdminRole\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"newAdminRole\",\"type\":\"bytes32\"}],\"name\":\"RoleAdminChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleGranted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleRevoked\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"}],\"name\":\"getRoleAdmin\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"grantRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"hasRole\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"callerConfirmation\",\"type\":\"address\"}],\"name\":\"renounceRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"revokeRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"details\":\"External interface of AccessControl declared to support ERC165 detection.\",\"errors\":{\"AccessControlBadConfirmation()\":[{\"details\":\"The caller of a function is not the expected one. NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\"}],\"AccessControlUnauthorizedAccount(address,bytes32)\":[{\"details\":\"The `account` is missing a role.\"}]},\"events\":{\"RoleAdminChanged(bytes32,bytes32,bytes32)\":{\"details\":\"Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole` `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite {RoleAdminChanged} not being emitted signaling this.\"},\"RoleGranted(bytes32,address,address)\":{\"details\":\"Emitted when `account` is granted `role`. `sender` is the account that originated the contract call, an admin role bearer except when using {AccessControl-_setupRole}.\"},\"RoleRevoked(bytes32,address,address)\":{\"details\":\"Emitted when `account` is revoked `role`. `sender` is the account that originated the contract call: - if using `revokeRole`, it is the admin role bearer - if using `renounceRole`, it is the role bearer (i.e. `account`)\"}},\"kind\":\"dev\",\"methods\":{\"getRoleAdmin(bytes32)\":{\"details\":\"Returns the admin role that controls `role`. See {grantRole} and {revokeRole}. To change a role's admin, use {AccessControl-_setRoleAdmin}.\"},\"grantRole(bytes32,address)\":{\"details\":\"Grants `role` to `account`. If `account` had not been already granted `role`, emits a {RoleGranted} event. Requirements: - the caller must have ``role``'s admin role.\"},\"hasRole(bytes32,address)\":{\"details\":\"Returns `true` if `account` has been granted `role`.\"},\"renounceRole(bytes32,address)\":{\"details\":\"Revokes `role` from the calling account. Roles are often managed via {grantRole} and {revokeRole}: this function's purpose is to provide a mechanism for accounts to lose their privileges if they are compromised (such as when a trusted device is misplaced). If the calling account had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must be `callerConfirmation`.\"},\"revokeRole(bytes32,address)\":{\"details\":\"Revokes `role` from `account`. If `account` had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must have ``role``'s admin role.\"}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeV2.sol\":\"IAccessControl\"},\"evmVersion\":\"shanghai\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeV2.sol\":{\"keccak256\":\"0x7cd0f885e80e2bdaa638bc32ae7af7d2e248f99ce4b354c217d0f0f7d7302e0a\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://7ccf28df0bd7b4606986585acd8622ed9b4e81379690061bb66088f0a2270af1\",\"dweb:/ipfs/QmTf7HNdHZkK6vmx8ZgewycQEb72oLD9nPwBpsM5reMstQ\"]}},\"version\":1}"},"hashes":{"getRoleAdmin(bytes32)":"248a9ca3","grantRole(bytes32,address)":"2f2ff15d","hasRole(bytes32,address)":"91d14854","renounceRole(bytes32,address)":"36568abe","revokeRole(bytes32,address)":"d547741f"}},"solidity/FastBridgeV2.sol:IAccessControlEnumerable":{"code":"0x","runtime-code":"0x","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.24 ^0.8.0 ^0.8.20;\n\n// contracts/interfaces/IAdmin.sol\n\ninterface IAdmin {\n // ============ Events ============\n\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n event ChainGasAmountUpdated(uint256 oldChainGasAmount, uint256 newChainGasAmount);\n\n // ============ Methods ============\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n\n function setChainGasAmount(uint256 newChainGasAmount) external;\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IFastBridgeRecipient.sol\n\ninterface IFastBridgeRecipient {\n function fastBridgeTransferReceived(\n address token,\n uint256 amount,\n bytes memory callParams\n )\n external\n payable\n returns (bytes4);\n}\n\n// contracts/interfaces/IFastBridgeV2Errors.sol\n\ninterface IFastBridgeV2Errors {\n error AmountIncorrect();\n error CallParamsLengthAboveMax();\n error ChainIncorrect();\n error ExclusivityParamsIncorrect();\n error MsgValueIncorrect();\n error NativeTokenCallValueNotSupported();\n error SenderIncorrect();\n error StatusIncorrect();\n error ZeroAddress();\n\n error RecipientIncorrectReturnValue();\n error RecipientNoReturnValue();\n\n error DeadlineExceeded();\n error DeadlineNotExceeded();\n error DeadlineTooShort();\n error DisputePeriodNotPassed();\n error DisputePeriodPassed();\n error ExclusivityPeriodNotPassed();\n\n error TransactionRelayed();\n}\n\n// contracts/libs/Errors.sol\n\nerror DeadlineExceeded();\nerror DeadlineNotExceeded();\nerror DeadlineTooShort();\nerror InsufficientOutputAmount();\n\nerror MsgValueIncorrect();\nerror PoolNotFound();\nerror TokenAddressMismatch();\nerror TokenNotContract();\nerror TokenNotETH();\nerror TokensIdentical();\n\nerror ChainIncorrect();\nerror AmountIncorrect();\nerror ZeroAddress();\n\nerror DisputePeriodNotPassed();\nerror DisputePeriodPassed();\nerror SenderIncorrect();\nerror StatusIncorrect();\nerror TransactionIdIncorrect();\nerror TransactionRelayed();\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// contracts/interfaces/IFastBridgeV2.sol\n\ninterface IFastBridgeV2 is IFastBridge {\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n struct BridgeTxDetails {\n BridgeStatus status;\n uint40 proofBlockTimestamp;\n uint48 proofBlockNumber;\n address proofRelayer;\n }\n\n struct BridgeRelay {\n uint48 blockNumber;\n uint48 blockTimestamp;\n address relayer;\n }\n\n /// @notice New params introduced in the FastBridgeV2.\n /// We are passing fields from the older BridgeParams struct outside of this struct\n /// for backwards compatibility.\n /// Note: quoteRelayer and quoteExclusivitySeconds are either both zero (indicating no exclusivity)\n /// or both non-zero (indicating exclusivity for the given period).\n /// Note: callValue \u003e 0 can NOT be used with destToken = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE (ETH_ADDRESS)\n /// @param quoteRelayer Relayer that provided the quote for the transaction\n /// @param quoteExclusivitySeconds Period of time the quote relayer is guaranteed exclusivity after user's deposit\n /// @param quoteId Unique quote identifier used for tracking the quote\n /// @param callValue ETH value to send to the recipient (if any)\n /// @param callParams Parameters for the arbitrary call to the destination recipient (if any)\n struct BridgeParamsV2 {\n address quoteRelayer;\n int256 quoteExclusivitySeconds;\n bytes quoteId;\n uint256 callValue;\n bytes callParams;\n }\n\n /// @notice Updated bridge transaction struct to include parameters introduced in FastBridgeV2.\n /// Note: only `exclusivityRelayer` can fill such a transaction until `exclusivityEndTime`.\n /// TODO: consider changing the encoding scheme to prevent spending extra gas on decoding.\n struct BridgeTransactionV2 {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n uint256 callValue; // ETH value to send to the recipient (if any) - replaces V1's sendChainGas flag\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n address exclusivityRelayer;\n uint256 exclusivityEndTime;\n bytes callParams;\n }\n\n event BridgeQuoteDetails(bytes32 indexed transactionId, bytes quoteId);\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability\n /// to provide temporary exclusivity fill rights for the quote relayer.\n /// @param params The parameters required to bridge\n /// @param paramsV2 The parameters for exclusivity fill rights (optional, can be left empty)\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function relay(bytes memory request, address relayer) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param transactionId The transaction id associated with the encoded bridge transaction to prove\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital.\n /// @notice Can only send funds to the relayer address on the proof.\n /// @param request The encoded bridge transaction to claim on origin chain\n function claim(bytes memory request) external;\n /// @notice Checks if a transaction has been relayed\n /// @param transactionId The ID of the transaction to check\n /// @return True if the transaction has been relayed, false otherwise\n function bridgeRelays(bytes32 transactionId) external view returns (bool);\n\n /// @notice Returns the status of a bridge transaction\n /// @param transactionId The ID of the bridge transaction\n /// @return BridgeStatus Status of the bridge transaction\n function bridgeStatuses(bytes32 transactionId) external view returns (BridgeStatus);\n\n /// @notice Returns the timestamp and relayer of a bridge proof\n /// @param transactionId The ID of the bridge transaction\n /// @return timestamp The timestamp of the bridge proof\n /// @return relayer The relayer address of the bridge proof\n function bridgeProofs(bytes32 transactionId) external view returns (uint96 timestamp, address relayer);\n\n /// @notice Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\n /// @param request The bridge request to decode\n function getBridgeTransactionV2(bytes memory request) external view returns (BridgeTransactionV2 memory);\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// contracts/libs/UniversalToken.sol\n\nlibrary UniversalTokenLib {\n using SafeERC20 for IERC20;\n\n address internal constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Transfers tokens to the given account. Reverts if transfer is not successful.\n /// @dev This might trigger fallback, if ETH is transferred to the contract.\n /// Make sure this can not lead to reentrancy attacks.\n function universalTransfer(address token, address to, uint256 value) internal {\n // Don't do anything, if need to send tokens to this address\n if (to == address(this)) return;\n // Don't do anything, if trying to send zero value\n if (value == 0) return;\n if (token == ETH_ADDRESS) {\n /// @dev Note: this can potentially lead to executing code in `to`.\n // solhint-disable-next-line avoid-low-level-calls\n (bool success,) = to.call{value: value}(\"\");\n require(success, \"ETH transfer failed\");\n } else {\n IERC20(token).safeTransfer(to, value);\n }\n }\n\n /// @notice Issues an infinite allowance to the spender, if the current allowance is insufficient\n /// to spend the given amount.\n function universalApproveInfinity(address token, address spender, uint256 amountToSpend) internal {\n // ETH Chad doesn't require your approval\n if (token == ETH_ADDRESS) return;\n // No-op if allowance is already sufficient\n uint256 allowance = IERC20(token).allowance(address(this), spender);\n if (allowance \u003e= amountToSpend) return;\n // Otherwise, reset approval to 0 and set to max allowance\n if (allowance \u003e 0) IERC20(token).safeDecreaseAllowance(spender, allowance);\n IERC20(token).safeIncreaseAllowance(spender, type(uint256).max);\n }\n\n /// @notice Returns the balance of the given token (or native ETH) for the given account.\n function universalBalanceOf(address token, address account) internal view returns (uint256) {\n if (token == ETH_ADDRESS) {\n return account.balance;\n } else {\n return IERC20(token).balanceOf(account);\n }\n }\n\n /// @dev Checks that token is a contract and not ETH_ADDRESS.\n function assertIsContract(address token) internal view {\n // Check that ETH_ADDRESS was not used (in case this is a predeploy on any of the chains)\n if (token == UniversalTokenLib.ETH_ADDRESS) revert TokenNotContract();\n // Check that token is not an EOA\n if (token.code.length == 0) revert TokenNotContract();\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/Admin.sol\n\ncontract Admin is IAdmin, AccessControlEnumerable {\n using UniversalTokenLib for address;\n\n bytes32 public constant RELAYER_ROLE = keccak256(\"RELAYER_ROLE\");\n bytes32 public constant REFUNDER_ROLE = keccak256(\"REFUNDER_ROLE\");\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n uint256 public constant FEE_BPS = 1e6;\n uint256 public constant FEE_RATE_MAX = 0.01e6; // max 1% on origin amount\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Chain gas amount to forward as rebate if requested\n uint256 public chainGasAmount;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n }\n\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n require(newFeeRate \u003c= FEE_RATE_MAX, \"newFeeRate \u003e max\");\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n token.universalTransfer(recipient, feeAmount);\n emit FeesSwept(token, recipient, feeAmount);\n }\n\n function setChainGasAmount(uint256 newChainGasAmount) external onlyRole(GOVERNOR_ROLE) {\n uint256 oldChainGasAmount = chainGasAmount;\n chainGasAmount = newChainGasAmount;\n emit ChainGasAmountUpdated(oldChainGasAmount, newChainGasAmount);\n }\n}\n\n// contracts/FastBridgeV2.sol\n\n/// @notice FastBridgeV2 is a contract for bridging tokens across chains.\ncontract FastBridgeV2 is Admin, IFastBridgeV2, IFastBridgeV2Errors {\n using SafeERC20 for IERC20;\n using UniversalTokenLib for address;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Delay for a transaction after which it could be permisionlessly refunded\n uint256 public constant REFUND_DELAY = 7 days;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n /// @notice Maximum length of accepted callParams\n uint256 public constant MAX_CALL_PARAMS_LENGTH = 2 ** 16 - 1;\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeTxDetails) public bridgeTxDetails;\n /// @notice Relay details on destination chain\n mapping(bytes32 =\u003e BridgeRelay) public bridgeRelayDetails;\n /// @notice Unique bridge nonces tracked per originSender\n mapping(address =\u003e uint256) public senderNonces;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Replaced by senderNonces\n uint256 public immutable nonce = 0;\n /// @notice the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n bridge({\n params: params,\n paramsV2: BridgeParamsV2({\n quoteRelayer: address(0),\n quoteExclusivitySeconds: 0,\n quoteId: bytes(\"\"),\n callValue: 0,\n callParams: bytes(\"\")\n })\n });\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes memory request) external payable {\n relay({request: request, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes memory request, bytes32 destTxHash) external {\n prove({transactionId: keccak256(request), destTxHash: destTxHash, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridgeV2\n function claim(bytes memory request) external {\n claim({request: request, to: address(0)});\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003e DISPUTE_PERIOD) {\n revert DisputePeriodPassed();\n }\n\n // @dev relayer gets slashed effectively if dest relay has gone thru\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n bridgeTxDetails[transactionId].proofRelayer = address(0);\n bridgeTxDetails[transactionId].proofBlockTimestamp = 0;\n bridgeTxDetails[transactionId].proofBlockNumber = 0;\n\n emit BridgeProofDisputed(transactionId, msg.sender);\n }\n\n /// @inheritdoc IFastBridge\n function refund(bytes memory request) external {\n bytes32 transactionId = keccak256(request);\n\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n\n if (bridgeTxDetails[transactionId].status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n\n if (hasRole(REFUNDER_ROLE, msg.sender)) {\n // Refunder can refund if deadline has passed\n if (block.timestamp \u003c= transaction.deadline) revert DeadlineNotExceeded();\n } else {\n // Permissionless refund is allowed after REFUND_DELAY\n if (block.timestamp \u003c= transaction.deadline + REFUND_DELAY) revert DeadlineNotExceeded();\n }\n\n // if all checks passed, set to REFUNDED status\n bridgeTxDetails[transactionId].status = BridgeStatus.REFUNDED;\n\n // transfer origin collateral back to original sender\n address to = transaction.originSender;\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount + transaction.originFeeAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (bridgeTxDetails[transactionId].proofRelayer != relayer) revert SenderIncorrect();\n return _timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n /// @dev This method is added to achieve backwards compatibility with decoding requests into V1 structs:\n /// - `callValue` is partially reported as a zero/non-zero flag\n /// - `callParams` is ignored\n /// In order to process all kinds of requests use getBridgeTransactionV2 instead.\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory) {\n // Try decoding into V2 struct first. This will revert if V1 struct is passed\n try this.getBridgeTransactionV2(request) returns (BridgeTransactionV2 memory txV2) {\n // Note: we entirely ignore the callParams field, as it was not present in V1\n return BridgeTransaction({\n originChainId: txV2.originChainId,\n destChainId: txV2.destChainId,\n originSender: txV2.originSender,\n destRecipient: txV2.destRecipient,\n originToken: txV2.originToken,\n destToken: txV2.destToken,\n originAmount: txV2.originAmount,\n destAmount: txV2.destAmount,\n originFeeAmount: txV2.originFeeAmount,\n sendChainGas: txV2.callValue != 0,\n deadline: txV2.deadline,\n nonce: txV2.nonce\n });\n } catch {\n // Fallback to V1 struct\n return abi.decode(request, (BridgeTransaction));\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) public payable {\n int256 exclusivityEndTime = int256(block.timestamp) + paramsV2.quoteExclusivitySeconds;\n _validateBridgeParams(params, paramsV2, exclusivityEndTime);\n\n // transfer tokens to bridge contract\n /// @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _pullToken(params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n\n // set status to requested\n bytes memory request = abi.encode(\n BridgeTransactionV2({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n callValue: paramsV2.callValue,\n deadline: params.deadline,\n nonce: senderNonces[params.sender]++, // increment nonce on every bridge\n exclusivityRelayer: paramsV2.quoteRelayer,\n // We checked exclusivityEndTime to be in range (0 .. params.deadline] above, so can safely cast\n exclusivityEndTime: uint256(exclusivityEndTime),\n callParams: paramsV2.callParams\n })\n );\n bytes32 transactionId = keccak256(request);\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n\n emit BridgeRequested({\n transactionId: transactionId,\n sender: params.sender,\n request: request,\n destChainId: params.dstChainId,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n sendChainGas: paramsV2.callValue != 0\n });\n emit BridgeQuoteDetails(transactionId, paramsV2.quoteId);\n }\n\n /// @inheritdoc IFastBridgeV2\n function relay(bytes memory request, address relayer) public payable {\n bytes32 transactionId = keccak256(request);\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n _validateRelayParams(transaction, transactionId, relayer);\n // mark bridge transaction as relayed\n bridgeRelayDetails[transactionId] =\n BridgeRelay({blockNumber: uint48(block.number), blockTimestamp: uint48(block.timestamp), relayer: relayer});\n\n // transfer tokens to recipient on destination chain and do an arbitrary call if requested\n address to = transaction.destRecipient;\n address token = transaction.destToken;\n uint256 amount = transaction.destAmount;\n\n // All state changes have been done at this point, can proceed to the external calls.\n // This follows the checks-effects-interactions pattern to mitigate potential reentrancy attacks.\n if (token == UniversalTokenLib.ETH_ADDRESS) {\n // For ETH non-zero callValue is not allowed\n if (transaction.callValue != 0) revert NativeTokenCallValueNotSupported();\n // Check that the correct msg.value was sent\n if (msg.value != amount) revert MsgValueIncorrect();\n } else {\n // For ERC20s, we check that the correct msg.value was sent\n if (msg.value != transaction.callValue) revert MsgValueIncorrect();\n // We need to transfer the tokens from the Relayer to the recipient first before performing an\n // optional post-transfer arbitrary call.\n IERC20(token).safeTransferFrom(msg.sender, to, amount);\n }\n\n if (transaction.callParams.length != 0) {\n // Arbitrary call requested, perform it while supplying full msg.value to the recipient\n // Note: if token has a fee on transfers, the recipient will have received less than `amount`.\n // This is a very niche edge case and should be handled by the recipient contract.\n _checkedCallRecipient({recipient: to, token: token, amount: amount, callParams: transaction.callParams});\n } else if (msg.value != 0) {\n // No arbitrary call requested, but msg.value was sent. This is either a relay with ETH,\n // or a non-zero callValue request with an ERC20. In both cases, transfer the ETH to the recipient.\n Address.sendValue(payable(to), msg.value);\n }\n\n emit BridgeRelayed({\n transactionId: transactionId,\n relayer: relayer,\n to: to,\n originChainId: transaction.originChainId,\n originToken: transaction.originToken,\n destToken: transaction.destToken,\n originAmount: transaction.originAmount,\n destAmount: transaction.destAmount,\n chainGasAmount: transaction.callValue\n });\n }\n\n /// @inheritdoc IFastBridgeV2\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) public onlyRole(RELAYER_ROLE) {\n // update bridge tx status given proof provided\n if (bridgeTxDetails[transactionId].status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n bridgeTxDetails[transactionId].status = BridgeStatus.RELAYER_PROVED;\n bridgeTxDetails[transactionId].proofBlockTimestamp = uint40(block.timestamp);\n bridgeTxDetails[transactionId].proofBlockNumber = uint48(block.number);\n bridgeTxDetails[transactionId].proofRelayer = relayer;\n\n emit BridgeProofProvided(transactionId, relayer, destTxHash);\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes memory request, address to) public {\n bytes32 transactionId = keccak256(request);\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n\n // update bridge tx status if able to claim origin collateral\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n\n // if \"to\" is zero addr, permissionlessly send funds to proven relayer\n if (to == address(0)) {\n to = bridgeTxDetails[transactionId].proofRelayer;\n } else if (bridgeTxDetails[transactionId].proofRelayer != msg.sender) {\n revert SenderIncorrect();\n }\n\n if (_timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003c= DISPUTE_PERIOD) {\n revert DisputePeriodNotPassed();\n }\n\n bridgeTxDetails[transactionId].status = BridgeStatus.RELAYER_CLAIMED;\n\n // update protocol fees if origin fee amount exists\n if (transaction.originFeeAmount \u003e 0) protocolFees[transaction.originToken] += transaction.originFeeAmount;\n\n // transfer origin collateral less fee to specified address\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositClaimed(transactionId, bridgeTxDetails[transactionId].proofRelayer, to, token, amount);\n }\n\n function bridgeStatuses(bytes32 transactionId) public view returns (BridgeStatus status) {\n return bridgeTxDetails[transactionId].status;\n }\n\n function bridgeProofs(bytes32 transactionId) public view returns (uint96 timestamp, address relayer) {\n timestamp = bridgeTxDetails[transactionId].proofBlockTimestamp;\n relayer = bridgeTxDetails[transactionId].proofRelayer;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeRelays(bytes32 transactionId) public view returns (bool) {\n // has this transactionId been relayed?\n return bridgeRelayDetails[transactionId].relayer != address(0);\n }\n\n /// @inheritdoc IFastBridgeV2\n function getBridgeTransactionV2(bytes memory request) public pure returns (BridgeTransactionV2 memory) {\n return abi.decode(request, (BridgeTransactionV2));\n }\n\n /// @notice Pulls a requested token from the user to this contract.\n function _pullToken(address token, uint256 amount) internal returns (uint256 amountPulled) {\n if (token == UniversalTokenLib.ETH_ADDRESS) {\n // For ETH we just need to check that the supplied msg.value is correct\n if (amount != msg.value) revert MsgValueIncorrect();\n amountPulled = msg.value;\n } else {\n token.assertIsContract();\n // Record token balance before transfer\n amountPulled = IERC20(token).balanceOf(address(this));\n // Token needs to be pulled only if msg.value is zero\n // This way user can specify WETH as the origin asset\n IERC20(token).safeTransferFrom(msg.sender, address(this), amount);\n // Use the difference between the recorded balance and the current balance as the amountPulled\n amountPulled = IERC20(token).balanceOf(address(this)) - amountPulled;\n }\n }\n\n /// @notice Calls the Recipient's hook function with the specified callParams and performs\n /// all the necessary checks for the returned value.\n function _checkedCallRecipient(\n address recipient,\n address token,\n uint256 amount,\n bytes memory callParams\n )\n internal\n {\n bytes memory hookData =\n abi.encodeCall(IFastBridgeRecipient.fastBridgeTransferReceived, (token, amount, callParams));\n // This will bubble any revert messages from the hook function\n bytes memory returnData = Address.functionCallWithValue({target: recipient, data: hookData, value: msg.value});\n // Explicit revert if no return data at all\n if (returnData.length == 0) revert RecipientNoReturnValue();\n // Check that exactly a single return value was returned\n if (returnData.length != 32) revert RecipientIncorrectReturnValue();\n // Return value should be abi-encoded hook function selector\n if (bytes32(returnData) != bytes32(IFastBridgeRecipient.fastBridgeTransferReceived.selector)) {\n revert RecipientIncorrectReturnValue();\n }\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint40(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint40).max but\n /// proof.timestamp \u003c type(uint40).max via unchecked statement\n /// @param proofBlockTimestamp The bridge proof block timestamp\n /// @return delta Time delta since proof submitted\n function _timeSince(uint40 proofBlockTimestamp) internal view returns (uint256 delta) {\n unchecked {\n delta = uint40(block.timestamp) - proofBlockTimestamp;\n }\n }\n\n /// @notice Performs all the necessary checks for a bridge to happen.\n /// @dev There's no good way to refactor this function to reduce cyclomatic complexity due to\n /// the number of checks that need to be performed, so we skip the code-complexity rule here.\n // solhint-disable-next-line code-complexity\n function _validateBridgeParams(\n BridgeParams memory params,\n BridgeParamsV2 memory paramsV2,\n int256 exclusivityEndTime\n )\n internal\n view\n {\n // Check V1 (legacy) params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.sender == address(0) || params.to == address(0)) revert ZeroAddress();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n // Check V2 params\n if (paramsV2.callParams.length \u003e MAX_CALL_PARAMS_LENGTH) revert CallParamsLengthAboveMax();\n if (paramsV2.callValue != 0 \u0026\u0026 params.destToken == UniversalTokenLib.ETH_ADDRESS) {\n revert NativeTokenCallValueNotSupported();\n }\n // exclusivityEndTime must be in range (0 .. params.deadline]\n if (exclusivityEndTime \u003c= 0 || exclusivityEndTime \u003e int256(params.deadline)) {\n revert ExclusivityParamsIncorrect();\n }\n }\n\n /// @notice Performs all the necessary checks for a relay to happen.\n function _validateRelayParams(\n BridgeTransactionV2 memory transaction,\n bytes32 transactionId,\n address relayer\n )\n internal\n view\n {\n if (relayer == address(0)) revert ZeroAddress();\n // Check if the transaction has already been relayed\n if (bridgeRelays(transactionId)) revert TransactionRelayed();\n if (transaction.destChainId != uint32(block.chainid)) revert ChainIncorrect();\n // Check the deadline for relay to happen\n if (block.timestamp \u003e transaction.deadline) revert DeadlineExceeded();\n // Check the exclusivity period, if it is still ongoing\n // forgefmt: disable-next-item\n if (\n transaction.exclusivityRelayer != address(0) \u0026\u0026\n transaction.exclusivityRelayer != relayer \u0026\u0026\n block.timestamp \u003c= transaction.exclusivityEndTime\n ) {\n revert ExclusivityPeriodNotPassed();\n }\n }\n}\n","language":"Solidity","languageVersion":"0.8.24","compilerVersion":"0.8.24","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../","srcMap":"","srcMapRuntime":"","abiDefinition":[{"inputs":[],"name":"AccessControlBadConfirmation","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"bytes32","name":"neededRole","type":"bytes32"}],"name":"AccessControlUnauthorizedAccount","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"previousAdminRole","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"newAdminRole","type":"bytes32"}],"name":"RoleAdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleRevoked","type":"event"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleAdmin","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"uint256","name":"index","type":"uint256"}],"name":"getRoleMember","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleMemberCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"grantRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"hasRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"callerConfirmation","type":"address"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"revokeRole","outputs":[],"stateMutability":"nonpayable","type":"function"}],"userDoc":{"kind":"user","methods":{},"version":1},"developerDoc":{"details":"External interface of AccessControlEnumerable declared to support ERC165 detection.","errors":{"AccessControlBadConfirmation()":[{"details":"The caller of a function is not the expected one. NOTE: Don't confuse with {AccessControlUnauthorizedAccount}."}],"AccessControlUnauthorizedAccount(address,bytes32)":[{"details":"The `account` is missing a role."}]},"events":{"RoleAdminChanged(bytes32,bytes32,bytes32)":{"details":"Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole` `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite {RoleAdminChanged} not being emitted signaling this."},"RoleGranted(bytes32,address,address)":{"details":"Emitted when `account` is granted `role`. `sender` is the account that originated the contract call, an admin role bearer except when using {AccessControl-_setupRole}."},"RoleRevoked(bytes32,address,address)":{"details":"Emitted when `account` is revoked `role`. `sender` is the account that originated the contract call: - if using `revokeRole`, it is the admin role bearer - if using `renounceRole`, it is the role bearer (i.e. `account`)"}},"kind":"dev","methods":{"getRoleAdmin(bytes32)":{"details":"Returns the admin role that controls `role`. See {grantRole} and {revokeRole}. To change a role's admin, use {AccessControl-_setRoleAdmin}."},"getRoleMember(bytes32,uint256)":{"details":"Returns one of the accounts that have `role`. `index` must be a value between 0 and {getRoleMemberCount}, non-inclusive. Role bearers are not sorted in any particular way, and their ordering may change at any point. WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure you perform all queries on the same block. See the following https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post] for more information."},"getRoleMemberCount(bytes32)":{"details":"Returns the number of accounts that have `role`. Can be used together with {getRoleMember} to enumerate all bearers of a role."},"grantRole(bytes32,address)":{"details":"Grants `role` to `account`. If `account` had not been already granted `role`, emits a {RoleGranted} event. Requirements: - the caller must have ``role``'s admin role."},"hasRole(bytes32,address)":{"details":"Returns `true` if `account` has been granted `role`."},"renounceRole(bytes32,address)":{"details":"Revokes `role` from the calling account. Roles are often managed via {grantRole} and {revokeRole}: this function's purpose is to provide a mechanism for accounts to lose their privileges if they are compromised (such as when a trusted device is misplaced). If the calling account had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must be `callerConfirmation`."},"revokeRole(bytes32,address)":{"details":"Revokes `role` from `account`. If `account` had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must have ``role``'s admin role."}},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[],\"name\":\"AccessControlBadConfirmation\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"neededRole\",\"type\":\"bytes32\"}],\"name\":\"AccessControlUnauthorizedAccount\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"previousAdminRole\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"newAdminRole\",\"type\":\"bytes32\"}],\"name\":\"RoleAdminChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleGranted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleRevoked\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"}],\"name\":\"getRoleAdmin\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"index\",\"type\":\"uint256\"}],\"name\":\"getRoleMember\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"}],\"name\":\"getRoleMemberCount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"grantRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"hasRole\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"callerConfirmation\",\"type\":\"address\"}],\"name\":\"renounceRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"revokeRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"details\":\"External interface of AccessControlEnumerable declared to support ERC165 detection.\",\"errors\":{\"AccessControlBadConfirmation()\":[{\"details\":\"The caller of a function is not the expected one. NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\"}],\"AccessControlUnauthorizedAccount(address,bytes32)\":[{\"details\":\"The `account` is missing a role.\"}]},\"events\":{\"RoleAdminChanged(bytes32,bytes32,bytes32)\":{\"details\":\"Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole` `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite {RoleAdminChanged} not being emitted signaling this.\"},\"RoleGranted(bytes32,address,address)\":{\"details\":\"Emitted when `account` is granted `role`. `sender` is the account that originated the contract call, an admin role bearer except when using {AccessControl-_setupRole}.\"},\"RoleRevoked(bytes32,address,address)\":{\"details\":\"Emitted when `account` is revoked `role`. `sender` is the account that originated the contract call: - if using `revokeRole`, it is the admin role bearer - if using `renounceRole`, it is the role bearer (i.e. `account`)\"}},\"kind\":\"dev\",\"methods\":{\"getRoleAdmin(bytes32)\":{\"details\":\"Returns the admin role that controls `role`. See {grantRole} and {revokeRole}. To change a role's admin, use {AccessControl-_setRoleAdmin}.\"},\"getRoleMember(bytes32,uint256)\":{\"details\":\"Returns one of the accounts that have `role`. `index` must be a value between 0 and {getRoleMemberCount}, non-inclusive. Role bearers are not sorted in any particular way, and their ordering may change at any point. WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure you perform all queries on the same block. See the following https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post] for more information.\"},\"getRoleMemberCount(bytes32)\":{\"details\":\"Returns the number of accounts that have `role`. Can be used together with {getRoleMember} to enumerate all bearers of a role.\"},\"grantRole(bytes32,address)\":{\"details\":\"Grants `role` to `account`. If `account` had not been already granted `role`, emits a {RoleGranted} event. Requirements: - the caller must have ``role``'s admin role.\"},\"hasRole(bytes32,address)\":{\"details\":\"Returns `true` if `account` has been granted `role`.\"},\"renounceRole(bytes32,address)\":{\"details\":\"Revokes `role` from the calling account. Roles are often managed via {grantRole} and {revokeRole}: this function's purpose is to provide a mechanism for accounts to lose their privileges if they are compromised (such as when a trusted device is misplaced). If the calling account had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must be `callerConfirmation`.\"},\"revokeRole(bytes32,address)\":{\"details\":\"Revokes `role` from `account`. If `account` had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must have ``role``'s admin role.\"}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeV2.sol\":\"IAccessControlEnumerable\"},\"evmVersion\":\"shanghai\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeV2.sol\":{\"keccak256\":\"0x7cd0f885e80e2bdaa638bc32ae7af7d2e248f99ce4b354c217d0f0f7d7302e0a\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://7ccf28df0bd7b4606986585acd8622ed9b4e81379690061bb66088f0a2270af1\",\"dweb:/ipfs/QmTf7HNdHZkK6vmx8ZgewycQEb72oLD9nPwBpsM5reMstQ\"]}},\"version\":1}"},"hashes":{"getRoleAdmin(bytes32)":"248a9ca3","getRoleMember(bytes32,uint256)":"9010d07c","getRoleMemberCount(bytes32)":"ca15c873","grantRole(bytes32,address)":"2f2ff15d","hasRole(bytes32,address)":"91d14854","renounceRole(bytes32,address)":"36568abe","revokeRole(bytes32,address)":"d547741f"}},"solidity/FastBridgeV2.sol:IAdmin":{"code":"0x","runtime-code":"0x","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.24 ^0.8.0 ^0.8.20;\n\n// contracts/interfaces/IAdmin.sol\n\ninterface IAdmin {\n // ============ Events ============\n\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n event ChainGasAmountUpdated(uint256 oldChainGasAmount, uint256 newChainGasAmount);\n\n // ============ Methods ============\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n\n function setChainGasAmount(uint256 newChainGasAmount) external;\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IFastBridgeRecipient.sol\n\ninterface IFastBridgeRecipient {\n function fastBridgeTransferReceived(\n address token,\n uint256 amount,\n bytes memory callParams\n )\n external\n payable\n returns (bytes4);\n}\n\n// contracts/interfaces/IFastBridgeV2Errors.sol\n\ninterface IFastBridgeV2Errors {\n error AmountIncorrect();\n error CallParamsLengthAboveMax();\n error ChainIncorrect();\n error ExclusivityParamsIncorrect();\n error MsgValueIncorrect();\n error NativeTokenCallValueNotSupported();\n error SenderIncorrect();\n error StatusIncorrect();\n error ZeroAddress();\n\n error RecipientIncorrectReturnValue();\n error RecipientNoReturnValue();\n\n error DeadlineExceeded();\n error DeadlineNotExceeded();\n error DeadlineTooShort();\n error DisputePeriodNotPassed();\n error DisputePeriodPassed();\n error ExclusivityPeriodNotPassed();\n\n error TransactionRelayed();\n}\n\n// contracts/libs/Errors.sol\n\nerror DeadlineExceeded();\nerror DeadlineNotExceeded();\nerror DeadlineTooShort();\nerror InsufficientOutputAmount();\n\nerror MsgValueIncorrect();\nerror PoolNotFound();\nerror TokenAddressMismatch();\nerror TokenNotContract();\nerror TokenNotETH();\nerror TokensIdentical();\n\nerror ChainIncorrect();\nerror AmountIncorrect();\nerror ZeroAddress();\n\nerror DisputePeriodNotPassed();\nerror DisputePeriodPassed();\nerror SenderIncorrect();\nerror StatusIncorrect();\nerror TransactionIdIncorrect();\nerror TransactionRelayed();\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// contracts/interfaces/IFastBridgeV2.sol\n\ninterface IFastBridgeV2 is IFastBridge {\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n struct BridgeTxDetails {\n BridgeStatus status;\n uint40 proofBlockTimestamp;\n uint48 proofBlockNumber;\n address proofRelayer;\n }\n\n struct BridgeRelay {\n uint48 blockNumber;\n uint48 blockTimestamp;\n address relayer;\n }\n\n /// @notice New params introduced in the FastBridgeV2.\n /// We are passing fields from the older BridgeParams struct outside of this struct\n /// for backwards compatibility.\n /// Note: quoteRelayer and quoteExclusivitySeconds are either both zero (indicating no exclusivity)\n /// or both non-zero (indicating exclusivity for the given period).\n /// Note: callValue \u003e 0 can NOT be used with destToken = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE (ETH_ADDRESS)\n /// @param quoteRelayer Relayer that provided the quote for the transaction\n /// @param quoteExclusivitySeconds Period of time the quote relayer is guaranteed exclusivity after user's deposit\n /// @param quoteId Unique quote identifier used for tracking the quote\n /// @param callValue ETH value to send to the recipient (if any)\n /// @param callParams Parameters for the arbitrary call to the destination recipient (if any)\n struct BridgeParamsV2 {\n address quoteRelayer;\n int256 quoteExclusivitySeconds;\n bytes quoteId;\n uint256 callValue;\n bytes callParams;\n }\n\n /// @notice Updated bridge transaction struct to include parameters introduced in FastBridgeV2.\n /// Note: only `exclusivityRelayer` can fill such a transaction until `exclusivityEndTime`.\n /// TODO: consider changing the encoding scheme to prevent spending extra gas on decoding.\n struct BridgeTransactionV2 {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n uint256 callValue; // ETH value to send to the recipient (if any) - replaces V1's sendChainGas flag\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n address exclusivityRelayer;\n uint256 exclusivityEndTime;\n bytes callParams;\n }\n\n event BridgeQuoteDetails(bytes32 indexed transactionId, bytes quoteId);\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability\n /// to provide temporary exclusivity fill rights for the quote relayer.\n /// @param params The parameters required to bridge\n /// @param paramsV2 The parameters for exclusivity fill rights (optional, can be left empty)\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function relay(bytes memory request, address relayer) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param transactionId The transaction id associated with the encoded bridge transaction to prove\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital.\n /// @notice Can only send funds to the relayer address on the proof.\n /// @param request The encoded bridge transaction to claim on origin chain\n function claim(bytes memory request) external;\n /// @notice Checks if a transaction has been relayed\n /// @param transactionId The ID of the transaction to check\n /// @return True if the transaction has been relayed, false otherwise\n function bridgeRelays(bytes32 transactionId) external view returns (bool);\n\n /// @notice Returns the status of a bridge transaction\n /// @param transactionId The ID of the bridge transaction\n /// @return BridgeStatus Status of the bridge transaction\n function bridgeStatuses(bytes32 transactionId) external view returns (BridgeStatus);\n\n /// @notice Returns the timestamp and relayer of a bridge proof\n /// @param transactionId The ID of the bridge transaction\n /// @return timestamp The timestamp of the bridge proof\n /// @return relayer The relayer address of the bridge proof\n function bridgeProofs(bytes32 transactionId) external view returns (uint96 timestamp, address relayer);\n\n /// @notice Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\n /// @param request The bridge request to decode\n function getBridgeTransactionV2(bytes memory request) external view returns (BridgeTransactionV2 memory);\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// contracts/libs/UniversalToken.sol\n\nlibrary UniversalTokenLib {\n using SafeERC20 for IERC20;\n\n address internal constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Transfers tokens to the given account. Reverts if transfer is not successful.\n /// @dev This might trigger fallback, if ETH is transferred to the contract.\n /// Make sure this can not lead to reentrancy attacks.\n function universalTransfer(address token, address to, uint256 value) internal {\n // Don't do anything, if need to send tokens to this address\n if (to == address(this)) return;\n // Don't do anything, if trying to send zero value\n if (value == 0) return;\n if (token == ETH_ADDRESS) {\n /// @dev Note: this can potentially lead to executing code in `to`.\n // solhint-disable-next-line avoid-low-level-calls\n (bool success,) = to.call{value: value}(\"\");\n require(success, \"ETH transfer failed\");\n } else {\n IERC20(token).safeTransfer(to, value);\n }\n }\n\n /// @notice Issues an infinite allowance to the spender, if the current allowance is insufficient\n /// to spend the given amount.\n function universalApproveInfinity(address token, address spender, uint256 amountToSpend) internal {\n // ETH Chad doesn't require your approval\n if (token == ETH_ADDRESS) return;\n // No-op if allowance is already sufficient\n uint256 allowance = IERC20(token).allowance(address(this), spender);\n if (allowance \u003e= amountToSpend) return;\n // Otherwise, reset approval to 0 and set to max allowance\n if (allowance \u003e 0) IERC20(token).safeDecreaseAllowance(spender, allowance);\n IERC20(token).safeIncreaseAllowance(spender, type(uint256).max);\n }\n\n /// @notice Returns the balance of the given token (or native ETH) for the given account.\n function universalBalanceOf(address token, address account) internal view returns (uint256) {\n if (token == ETH_ADDRESS) {\n return account.balance;\n } else {\n return IERC20(token).balanceOf(account);\n }\n }\n\n /// @dev Checks that token is a contract and not ETH_ADDRESS.\n function assertIsContract(address token) internal view {\n // Check that ETH_ADDRESS was not used (in case this is a predeploy on any of the chains)\n if (token == UniversalTokenLib.ETH_ADDRESS) revert TokenNotContract();\n // Check that token is not an EOA\n if (token.code.length == 0) revert TokenNotContract();\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/Admin.sol\n\ncontract Admin is IAdmin, AccessControlEnumerable {\n using UniversalTokenLib for address;\n\n bytes32 public constant RELAYER_ROLE = keccak256(\"RELAYER_ROLE\");\n bytes32 public constant REFUNDER_ROLE = keccak256(\"REFUNDER_ROLE\");\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n uint256 public constant FEE_BPS = 1e6;\n uint256 public constant FEE_RATE_MAX = 0.01e6; // max 1% on origin amount\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Chain gas amount to forward as rebate if requested\n uint256 public chainGasAmount;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n }\n\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n require(newFeeRate \u003c= FEE_RATE_MAX, \"newFeeRate \u003e max\");\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n token.universalTransfer(recipient, feeAmount);\n emit FeesSwept(token, recipient, feeAmount);\n }\n\n function setChainGasAmount(uint256 newChainGasAmount) external onlyRole(GOVERNOR_ROLE) {\n uint256 oldChainGasAmount = chainGasAmount;\n chainGasAmount = newChainGasAmount;\n emit ChainGasAmountUpdated(oldChainGasAmount, newChainGasAmount);\n }\n}\n\n// contracts/FastBridgeV2.sol\n\n/// @notice FastBridgeV2 is a contract for bridging tokens across chains.\ncontract FastBridgeV2 is Admin, IFastBridgeV2, IFastBridgeV2Errors {\n using SafeERC20 for IERC20;\n using UniversalTokenLib for address;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Delay for a transaction after which it could be permisionlessly refunded\n uint256 public constant REFUND_DELAY = 7 days;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n /// @notice Maximum length of accepted callParams\n uint256 public constant MAX_CALL_PARAMS_LENGTH = 2 ** 16 - 1;\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeTxDetails) public bridgeTxDetails;\n /// @notice Relay details on destination chain\n mapping(bytes32 =\u003e BridgeRelay) public bridgeRelayDetails;\n /// @notice Unique bridge nonces tracked per originSender\n mapping(address =\u003e uint256) public senderNonces;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Replaced by senderNonces\n uint256 public immutable nonce = 0;\n /// @notice the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n bridge({\n params: params,\n paramsV2: BridgeParamsV2({\n quoteRelayer: address(0),\n quoteExclusivitySeconds: 0,\n quoteId: bytes(\"\"),\n callValue: 0,\n callParams: bytes(\"\")\n })\n });\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes memory request) external payable {\n relay({request: request, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes memory request, bytes32 destTxHash) external {\n prove({transactionId: keccak256(request), destTxHash: destTxHash, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridgeV2\n function claim(bytes memory request) external {\n claim({request: request, to: address(0)});\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003e DISPUTE_PERIOD) {\n revert DisputePeriodPassed();\n }\n\n // @dev relayer gets slashed effectively if dest relay has gone thru\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n bridgeTxDetails[transactionId].proofRelayer = address(0);\n bridgeTxDetails[transactionId].proofBlockTimestamp = 0;\n bridgeTxDetails[transactionId].proofBlockNumber = 0;\n\n emit BridgeProofDisputed(transactionId, msg.sender);\n }\n\n /// @inheritdoc IFastBridge\n function refund(bytes memory request) external {\n bytes32 transactionId = keccak256(request);\n\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n\n if (bridgeTxDetails[transactionId].status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n\n if (hasRole(REFUNDER_ROLE, msg.sender)) {\n // Refunder can refund if deadline has passed\n if (block.timestamp \u003c= transaction.deadline) revert DeadlineNotExceeded();\n } else {\n // Permissionless refund is allowed after REFUND_DELAY\n if (block.timestamp \u003c= transaction.deadline + REFUND_DELAY) revert DeadlineNotExceeded();\n }\n\n // if all checks passed, set to REFUNDED status\n bridgeTxDetails[transactionId].status = BridgeStatus.REFUNDED;\n\n // transfer origin collateral back to original sender\n address to = transaction.originSender;\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount + transaction.originFeeAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (bridgeTxDetails[transactionId].proofRelayer != relayer) revert SenderIncorrect();\n return _timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n /// @dev This method is added to achieve backwards compatibility with decoding requests into V1 structs:\n /// - `callValue` is partially reported as a zero/non-zero flag\n /// - `callParams` is ignored\n /// In order to process all kinds of requests use getBridgeTransactionV2 instead.\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory) {\n // Try decoding into V2 struct first. This will revert if V1 struct is passed\n try this.getBridgeTransactionV2(request) returns (BridgeTransactionV2 memory txV2) {\n // Note: we entirely ignore the callParams field, as it was not present in V1\n return BridgeTransaction({\n originChainId: txV2.originChainId,\n destChainId: txV2.destChainId,\n originSender: txV2.originSender,\n destRecipient: txV2.destRecipient,\n originToken: txV2.originToken,\n destToken: txV2.destToken,\n originAmount: txV2.originAmount,\n destAmount: txV2.destAmount,\n originFeeAmount: txV2.originFeeAmount,\n sendChainGas: txV2.callValue != 0,\n deadline: txV2.deadline,\n nonce: txV2.nonce\n });\n } catch {\n // Fallback to V1 struct\n return abi.decode(request, (BridgeTransaction));\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) public payable {\n int256 exclusivityEndTime = int256(block.timestamp) + paramsV2.quoteExclusivitySeconds;\n _validateBridgeParams(params, paramsV2, exclusivityEndTime);\n\n // transfer tokens to bridge contract\n /// @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _pullToken(params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n\n // set status to requested\n bytes memory request = abi.encode(\n BridgeTransactionV2({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n callValue: paramsV2.callValue,\n deadline: params.deadline,\n nonce: senderNonces[params.sender]++, // increment nonce on every bridge\n exclusivityRelayer: paramsV2.quoteRelayer,\n // We checked exclusivityEndTime to be in range (0 .. params.deadline] above, so can safely cast\n exclusivityEndTime: uint256(exclusivityEndTime),\n callParams: paramsV2.callParams\n })\n );\n bytes32 transactionId = keccak256(request);\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n\n emit BridgeRequested({\n transactionId: transactionId,\n sender: params.sender,\n request: request,\n destChainId: params.dstChainId,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n sendChainGas: paramsV2.callValue != 0\n });\n emit BridgeQuoteDetails(transactionId, paramsV2.quoteId);\n }\n\n /// @inheritdoc IFastBridgeV2\n function relay(bytes memory request, address relayer) public payable {\n bytes32 transactionId = keccak256(request);\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n _validateRelayParams(transaction, transactionId, relayer);\n // mark bridge transaction as relayed\n bridgeRelayDetails[transactionId] =\n BridgeRelay({blockNumber: uint48(block.number), blockTimestamp: uint48(block.timestamp), relayer: relayer});\n\n // transfer tokens to recipient on destination chain and do an arbitrary call if requested\n address to = transaction.destRecipient;\n address token = transaction.destToken;\n uint256 amount = transaction.destAmount;\n\n // All state changes have been done at this point, can proceed to the external calls.\n // This follows the checks-effects-interactions pattern to mitigate potential reentrancy attacks.\n if (token == UniversalTokenLib.ETH_ADDRESS) {\n // For ETH non-zero callValue is not allowed\n if (transaction.callValue != 0) revert NativeTokenCallValueNotSupported();\n // Check that the correct msg.value was sent\n if (msg.value != amount) revert MsgValueIncorrect();\n } else {\n // For ERC20s, we check that the correct msg.value was sent\n if (msg.value != transaction.callValue) revert MsgValueIncorrect();\n // We need to transfer the tokens from the Relayer to the recipient first before performing an\n // optional post-transfer arbitrary call.\n IERC20(token).safeTransferFrom(msg.sender, to, amount);\n }\n\n if (transaction.callParams.length != 0) {\n // Arbitrary call requested, perform it while supplying full msg.value to the recipient\n // Note: if token has a fee on transfers, the recipient will have received less than `amount`.\n // This is a very niche edge case and should be handled by the recipient contract.\n _checkedCallRecipient({recipient: to, token: token, amount: amount, callParams: transaction.callParams});\n } else if (msg.value != 0) {\n // No arbitrary call requested, but msg.value was sent. This is either a relay with ETH,\n // or a non-zero callValue request with an ERC20. In both cases, transfer the ETH to the recipient.\n Address.sendValue(payable(to), msg.value);\n }\n\n emit BridgeRelayed({\n transactionId: transactionId,\n relayer: relayer,\n to: to,\n originChainId: transaction.originChainId,\n originToken: transaction.originToken,\n destToken: transaction.destToken,\n originAmount: transaction.originAmount,\n destAmount: transaction.destAmount,\n chainGasAmount: transaction.callValue\n });\n }\n\n /// @inheritdoc IFastBridgeV2\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) public onlyRole(RELAYER_ROLE) {\n // update bridge tx status given proof provided\n if (bridgeTxDetails[transactionId].status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n bridgeTxDetails[transactionId].status = BridgeStatus.RELAYER_PROVED;\n bridgeTxDetails[transactionId].proofBlockTimestamp = uint40(block.timestamp);\n bridgeTxDetails[transactionId].proofBlockNumber = uint48(block.number);\n bridgeTxDetails[transactionId].proofRelayer = relayer;\n\n emit BridgeProofProvided(transactionId, relayer, destTxHash);\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes memory request, address to) public {\n bytes32 transactionId = keccak256(request);\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n\n // update bridge tx status if able to claim origin collateral\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n\n // if \"to\" is zero addr, permissionlessly send funds to proven relayer\n if (to == address(0)) {\n to = bridgeTxDetails[transactionId].proofRelayer;\n } else if (bridgeTxDetails[transactionId].proofRelayer != msg.sender) {\n revert SenderIncorrect();\n }\n\n if (_timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003c= DISPUTE_PERIOD) {\n revert DisputePeriodNotPassed();\n }\n\n bridgeTxDetails[transactionId].status = BridgeStatus.RELAYER_CLAIMED;\n\n // update protocol fees if origin fee amount exists\n if (transaction.originFeeAmount \u003e 0) protocolFees[transaction.originToken] += transaction.originFeeAmount;\n\n // transfer origin collateral less fee to specified address\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositClaimed(transactionId, bridgeTxDetails[transactionId].proofRelayer, to, token, amount);\n }\n\n function bridgeStatuses(bytes32 transactionId) public view returns (BridgeStatus status) {\n return bridgeTxDetails[transactionId].status;\n }\n\n function bridgeProofs(bytes32 transactionId) public view returns (uint96 timestamp, address relayer) {\n timestamp = bridgeTxDetails[transactionId].proofBlockTimestamp;\n relayer = bridgeTxDetails[transactionId].proofRelayer;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeRelays(bytes32 transactionId) public view returns (bool) {\n // has this transactionId been relayed?\n return bridgeRelayDetails[transactionId].relayer != address(0);\n }\n\n /// @inheritdoc IFastBridgeV2\n function getBridgeTransactionV2(bytes memory request) public pure returns (BridgeTransactionV2 memory) {\n return abi.decode(request, (BridgeTransactionV2));\n }\n\n /// @notice Pulls a requested token from the user to this contract.\n function _pullToken(address token, uint256 amount) internal returns (uint256 amountPulled) {\n if (token == UniversalTokenLib.ETH_ADDRESS) {\n // For ETH we just need to check that the supplied msg.value is correct\n if (amount != msg.value) revert MsgValueIncorrect();\n amountPulled = msg.value;\n } else {\n token.assertIsContract();\n // Record token balance before transfer\n amountPulled = IERC20(token).balanceOf(address(this));\n // Token needs to be pulled only if msg.value is zero\n // This way user can specify WETH as the origin asset\n IERC20(token).safeTransferFrom(msg.sender, address(this), amount);\n // Use the difference between the recorded balance and the current balance as the amountPulled\n amountPulled = IERC20(token).balanceOf(address(this)) - amountPulled;\n }\n }\n\n /// @notice Calls the Recipient's hook function with the specified callParams and performs\n /// all the necessary checks for the returned value.\n function _checkedCallRecipient(\n address recipient,\n address token,\n uint256 amount,\n bytes memory callParams\n )\n internal\n {\n bytes memory hookData =\n abi.encodeCall(IFastBridgeRecipient.fastBridgeTransferReceived, (token, amount, callParams));\n // This will bubble any revert messages from the hook function\n bytes memory returnData = Address.functionCallWithValue({target: recipient, data: hookData, value: msg.value});\n // Explicit revert if no return data at all\n if (returnData.length == 0) revert RecipientNoReturnValue();\n // Check that exactly a single return value was returned\n if (returnData.length != 32) revert RecipientIncorrectReturnValue();\n // Return value should be abi-encoded hook function selector\n if (bytes32(returnData) != bytes32(IFastBridgeRecipient.fastBridgeTransferReceived.selector)) {\n revert RecipientIncorrectReturnValue();\n }\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint40(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint40).max but\n /// proof.timestamp \u003c type(uint40).max via unchecked statement\n /// @param proofBlockTimestamp The bridge proof block timestamp\n /// @return delta Time delta since proof submitted\n function _timeSince(uint40 proofBlockTimestamp) internal view returns (uint256 delta) {\n unchecked {\n delta = uint40(block.timestamp) - proofBlockTimestamp;\n }\n }\n\n /// @notice Performs all the necessary checks for a bridge to happen.\n /// @dev There's no good way to refactor this function to reduce cyclomatic complexity due to\n /// the number of checks that need to be performed, so we skip the code-complexity rule here.\n // solhint-disable-next-line code-complexity\n function _validateBridgeParams(\n BridgeParams memory params,\n BridgeParamsV2 memory paramsV2,\n int256 exclusivityEndTime\n )\n internal\n view\n {\n // Check V1 (legacy) params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.sender == address(0) || params.to == address(0)) revert ZeroAddress();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n // Check V2 params\n if (paramsV2.callParams.length \u003e MAX_CALL_PARAMS_LENGTH) revert CallParamsLengthAboveMax();\n if (paramsV2.callValue != 0 \u0026\u0026 params.destToken == UniversalTokenLib.ETH_ADDRESS) {\n revert NativeTokenCallValueNotSupported();\n }\n // exclusivityEndTime must be in range (0 .. params.deadline]\n if (exclusivityEndTime \u003c= 0 || exclusivityEndTime \u003e int256(params.deadline)) {\n revert ExclusivityParamsIncorrect();\n }\n }\n\n /// @notice Performs all the necessary checks for a relay to happen.\n function _validateRelayParams(\n BridgeTransactionV2 memory transaction,\n bytes32 transactionId,\n address relayer\n )\n internal\n view\n {\n if (relayer == address(0)) revert ZeroAddress();\n // Check if the transaction has already been relayed\n if (bridgeRelays(transactionId)) revert TransactionRelayed();\n if (transaction.destChainId != uint32(block.chainid)) revert ChainIncorrect();\n // Check the deadline for relay to happen\n if (block.timestamp \u003e transaction.deadline) revert DeadlineExceeded();\n // Check the exclusivity period, if it is still ongoing\n // forgefmt: disable-next-item\n if (\n transaction.exclusivityRelayer != address(0) \u0026\u0026\n transaction.exclusivityRelayer != relayer \u0026\u0026\n block.timestamp \u003c= transaction.exclusivityEndTime\n ) {\n revert ExclusivityPeriodNotPassed();\n }\n }\n}\n","language":"Solidity","languageVersion":"0.8.24","compilerVersion":"0.8.24","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../","srcMap":"","srcMapRuntime":"","abiDefinition":[{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldChainGasAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newChainGasAmount","type":"uint256"}],"name":"ChainGasAmountUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldFeeRate","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newFeeRate","type":"uint256"}],"name":"FeeRateUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"address","name":"recipient","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"FeesSwept","type":"event"},{"inputs":[{"internalType":"uint256","name":"newChainGasAmount","type":"uint256"}],"name":"setChainGasAmount","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"newFeeRate","type":"uint256"}],"name":"setProtocolFeeRate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"address","name":"recipient","type":"address"}],"name":"sweepProtocolFees","outputs":[],"stateMutability":"nonpayable","type":"function"}],"userDoc":{"kind":"user","methods":{},"version":1},"developerDoc":{"kind":"dev","methods":{},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"oldChainGasAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newChainGasAmount\",\"type\":\"uint256\"}],\"name\":\"ChainGasAmountUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"oldFeeRate\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newFeeRate\",\"type\":\"uint256\"}],\"name\":\"FeeRateUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"FeesSwept\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"newChainGasAmount\",\"type\":\"uint256\"}],\"name\":\"setChainGasAmount\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"newFeeRate\",\"type\":\"uint256\"}],\"name\":\"setProtocolFeeRate\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"}],\"name\":\"sweepProtocolFees\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeV2.sol\":\"IAdmin\"},\"evmVersion\":\"shanghai\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeV2.sol\":{\"keccak256\":\"0x7cd0f885e80e2bdaa638bc32ae7af7d2e248f99ce4b354c217d0f0f7d7302e0a\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://7ccf28df0bd7b4606986585acd8622ed9b4e81379690061bb66088f0a2270af1\",\"dweb:/ipfs/QmTf7HNdHZkK6vmx8ZgewycQEb72oLD9nPwBpsM5reMstQ\"]}},\"version\":1}"},"hashes":{"setChainGasAmount(uint256)":"b250fe6b","setProtocolFeeRate(uint256)":"b13aa2d6","sweepProtocolFees(address,address)":"06f333f2"}},"solidity/FastBridgeV2.sol:IERC165":{"code":"0x","runtime-code":"0x","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.24 ^0.8.0 ^0.8.20;\n\n// contracts/interfaces/IAdmin.sol\n\ninterface IAdmin {\n // ============ Events ============\n\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n event ChainGasAmountUpdated(uint256 oldChainGasAmount, uint256 newChainGasAmount);\n\n // ============ Methods ============\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n\n function setChainGasAmount(uint256 newChainGasAmount) external;\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IFastBridgeRecipient.sol\n\ninterface IFastBridgeRecipient {\n function fastBridgeTransferReceived(\n address token,\n uint256 amount,\n bytes memory callParams\n )\n external\n payable\n returns (bytes4);\n}\n\n// contracts/interfaces/IFastBridgeV2Errors.sol\n\ninterface IFastBridgeV2Errors {\n error AmountIncorrect();\n error CallParamsLengthAboveMax();\n error ChainIncorrect();\n error ExclusivityParamsIncorrect();\n error MsgValueIncorrect();\n error NativeTokenCallValueNotSupported();\n error SenderIncorrect();\n error StatusIncorrect();\n error ZeroAddress();\n\n error RecipientIncorrectReturnValue();\n error RecipientNoReturnValue();\n\n error DeadlineExceeded();\n error DeadlineNotExceeded();\n error DeadlineTooShort();\n error DisputePeriodNotPassed();\n error DisputePeriodPassed();\n error ExclusivityPeriodNotPassed();\n\n error TransactionRelayed();\n}\n\n// contracts/libs/Errors.sol\n\nerror DeadlineExceeded();\nerror DeadlineNotExceeded();\nerror DeadlineTooShort();\nerror InsufficientOutputAmount();\n\nerror MsgValueIncorrect();\nerror PoolNotFound();\nerror TokenAddressMismatch();\nerror TokenNotContract();\nerror TokenNotETH();\nerror TokensIdentical();\n\nerror ChainIncorrect();\nerror AmountIncorrect();\nerror ZeroAddress();\n\nerror DisputePeriodNotPassed();\nerror DisputePeriodPassed();\nerror SenderIncorrect();\nerror StatusIncorrect();\nerror TransactionIdIncorrect();\nerror TransactionRelayed();\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// contracts/interfaces/IFastBridgeV2.sol\n\ninterface IFastBridgeV2 is IFastBridge {\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n struct BridgeTxDetails {\n BridgeStatus status;\n uint40 proofBlockTimestamp;\n uint48 proofBlockNumber;\n address proofRelayer;\n }\n\n struct BridgeRelay {\n uint48 blockNumber;\n uint48 blockTimestamp;\n address relayer;\n }\n\n /// @notice New params introduced in the FastBridgeV2.\n /// We are passing fields from the older BridgeParams struct outside of this struct\n /// for backwards compatibility.\n /// Note: quoteRelayer and quoteExclusivitySeconds are either both zero (indicating no exclusivity)\n /// or both non-zero (indicating exclusivity for the given period).\n /// Note: callValue \u003e 0 can NOT be used with destToken = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE (ETH_ADDRESS)\n /// @param quoteRelayer Relayer that provided the quote for the transaction\n /// @param quoteExclusivitySeconds Period of time the quote relayer is guaranteed exclusivity after user's deposit\n /// @param quoteId Unique quote identifier used for tracking the quote\n /// @param callValue ETH value to send to the recipient (if any)\n /// @param callParams Parameters for the arbitrary call to the destination recipient (if any)\n struct BridgeParamsV2 {\n address quoteRelayer;\n int256 quoteExclusivitySeconds;\n bytes quoteId;\n uint256 callValue;\n bytes callParams;\n }\n\n /// @notice Updated bridge transaction struct to include parameters introduced in FastBridgeV2.\n /// Note: only `exclusivityRelayer` can fill such a transaction until `exclusivityEndTime`.\n /// TODO: consider changing the encoding scheme to prevent spending extra gas on decoding.\n struct BridgeTransactionV2 {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n uint256 callValue; // ETH value to send to the recipient (if any) - replaces V1's sendChainGas flag\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n address exclusivityRelayer;\n uint256 exclusivityEndTime;\n bytes callParams;\n }\n\n event BridgeQuoteDetails(bytes32 indexed transactionId, bytes quoteId);\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability\n /// to provide temporary exclusivity fill rights for the quote relayer.\n /// @param params The parameters required to bridge\n /// @param paramsV2 The parameters for exclusivity fill rights (optional, can be left empty)\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function relay(bytes memory request, address relayer) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param transactionId The transaction id associated with the encoded bridge transaction to prove\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital.\n /// @notice Can only send funds to the relayer address on the proof.\n /// @param request The encoded bridge transaction to claim on origin chain\n function claim(bytes memory request) external;\n /// @notice Checks if a transaction has been relayed\n /// @param transactionId The ID of the transaction to check\n /// @return True if the transaction has been relayed, false otherwise\n function bridgeRelays(bytes32 transactionId) external view returns (bool);\n\n /// @notice Returns the status of a bridge transaction\n /// @param transactionId The ID of the bridge transaction\n /// @return BridgeStatus Status of the bridge transaction\n function bridgeStatuses(bytes32 transactionId) external view returns (BridgeStatus);\n\n /// @notice Returns the timestamp and relayer of a bridge proof\n /// @param transactionId The ID of the bridge transaction\n /// @return timestamp The timestamp of the bridge proof\n /// @return relayer The relayer address of the bridge proof\n function bridgeProofs(bytes32 transactionId) external view returns (uint96 timestamp, address relayer);\n\n /// @notice Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\n /// @param request The bridge request to decode\n function getBridgeTransactionV2(bytes memory request) external view returns (BridgeTransactionV2 memory);\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// contracts/libs/UniversalToken.sol\n\nlibrary UniversalTokenLib {\n using SafeERC20 for IERC20;\n\n address internal constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Transfers tokens to the given account. Reverts if transfer is not successful.\n /// @dev This might trigger fallback, if ETH is transferred to the contract.\n /// Make sure this can not lead to reentrancy attacks.\n function universalTransfer(address token, address to, uint256 value) internal {\n // Don't do anything, if need to send tokens to this address\n if (to == address(this)) return;\n // Don't do anything, if trying to send zero value\n if (value == 0) return;\n if (token == ETH_ADDRESS) {\n /// @dev Note: this can potentially lead to executing code in `to`.\n // solhint-disable-next-line avoid-low-level-calls\n (bool success,) = to.call{value: value}(\"\");\n require(success, \"ETH transfer failed\");\n } else {\n IERC20(token).safeTransfer(to, value);\n }\n }\n\n /// @notice Issues an infinite allowance to the spender, if the current allowance is insufficient\n /// to spend the given amount.\n function universalApproveInfinity(address token, address spender, uint256 amountToSpend) internal {\n // ETH Chad doesn't require your approval\n if (token == ETH_ADDRESS) return;\n // No-op if allowance is already sufficient\n uint256 allowance = IERC20(token).allowance(address(this), spender);\n if (allowance \u003e= amountToSpend) return;\n // Otherwise, reset approval to 0 and set to max allowance\n if (allowance \u003e 0) IERC20(token).safeDecreaseAllowance(spender, allowance);\n IERC20(token).safeIncreaseAllowance(spender, type(uint256).max);\n }\n\n /// @notice Returns the balance of the given token (or native ETH) for the given account.\n function universalBalanceOf(address token, address account) internal view returns (uint256) {\n if (token == ETH_ADDRESS) {\n return account.balance;\n } else {\n return IERC20(token).balanceOf(account);\n }\n }\n\n /// @dev Checks that token is a contract and not ETH_ADDRESS.\n function assertIsContract(address token) internal view {\n // Check that ETH_ADDRESS was not used (in case this is a predeploy on any of the chains)\n if (token == UniversalTokenLib.ETH_ADDRESS) revert TokenNotContract();\n // Check that token is not an EOA\n if (token.code.length == 0) revert TokenNotContract();\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/Admin.sol\n\ncontract Admin is IAdmin, AccessControlEnumerable {\n using UniversalTokenLib for address;\n\n bytes32 public constant RELAYER_ROLE = keccak256(\"RELAYER_ROLE\");\n bytes32 public constant REFUNDER_ROLE = keccak256(\"REFUNDER_ROLE\");\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n uint256 public constant FEE_BPS = 1e6;\n uint256 public constant FEE_RATE_MAX = 0.01e6; // max 1% on origin amount\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Chain gas amount to forward as rebate if requested\n uint256 public chainGasAmount;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n }\n\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n require(newFeeRate \u003c= FEE_RATE_MAX, \"newFeeRate \u003e max\");\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n token.universalTransfer(recipient, feeAmount);\n emit FeesSwept(token, recipient, feeAmount);\n }\n\n function setChainGasAmount(uint256 newChainGasAmount) external onlyRole(GOVERNOR_ROLE) {\n uint256 oldChainGasAmount = chainGasAmount;\n chainGasAmount = newChainGasAmount;\n emit ChainGasAmountUpdated(oldChainGasAmount, newChainGasAmount);\n }\n}\n\n// contracts/FastBridgeV2.sol\n\n/// @notice FastBridgeV2 is a contract for bridging tokens across chains.\ncontract FastBridgeV2 is Admin, IFastBridgeV2, IFastBridgeV2Errors {\n using SafeERC20 for IERC20;\n using UniversalTokenLib for address;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Delay for a transaction after which it could be permisionlessly refunded\n uint256 public constant REFUND_DELAY = 7 days;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n /// @notice Maximum length of accepted callParams\n uint256 public constant MAX_CALL_PARAMS_LENGTH = 2 ** 16 - 1;\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeTxDetails) public bridgeTxDetails;\n /// @notice Relay details on destination chain\n mapping(bytes32 =\u003e BridgeRelay) public bridgeRelayDetails;\n /// @notice Unique bridge nonces tracked per originSender\n mapping(address =\u003e uint256) public senderNonces;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Replaced by senderNonces\n uint256 public immutable nonce = 0;\n /// @notice the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n bridge({\n params: params,\n paramsV2: BridgeParamsV2({\n quoteRelayer: address(0),\n quoteExclusivitySeconds: 0,\n quoteId: bytes(\"\"),\n callValue: 0,\n callParams: bytes(\"\")\n })\n });\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes memory request) external payable {\n relay({request: request, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes memory request, bytes32 destTxHash) external {\n prove({transactionId: keccak256(request), destTxHash: destTxHash, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridgeV2\n function claim(bytes memory request) external {\n claim({request: request, to: address(0)});\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003e DISPUTE_PERIOD) {\n revert DisputePeriodPassed();\n }\n\n // @dev relayer gets slashed effectively if dest relay has gone thru\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n bridgeTxDetails[transactionId].proofRelayer = address(0);\n bridgeTxDetails[transactionId].proofBlockTimestamp = 0;\n bridgeTxDetails[transactionId].proofBlockNumber = 0;\n\n emit BridgeProofDisputed(transactionId, msg.sender);\n }\n\n /// @inheritdoc IFastBridge\n function refund(bytes memory request) external {\n bytes32 transactionId = keccak256(request);\n\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n\n if (bridgeTxDetails[transactionId].status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n\n if (hasRole(REFUNDER_ROLE, msg.sender)) {\n // Refunder can refund if deadline has passed\n if (block.timestamp \u003c= transaction.deadline) revert DeadlineNotExceeded();\n } else {\n // Permissionless refund is allowed after REFUND_DELAY\n if (block.timestamp \u003c= transaction.deadline + REFUND_DELAY) revert DeadlineNotExceeded();\n }\n\n // if all checks passed, set to REFUNDED status\n bridgeTxDetails[transactionId].status = BridgeStatus.REFUNDED;\n\n // transfer origin collateral back to original sender\n address to = transaction.originSender;\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount + transaction.originFeeAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (bridgeTxDetails[transactionId].proofRelayer != relayer) revert SenderIncorrect();\n return _timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n /// @dev This method is added to achieve backwards compatibility with decoding requests into V1 structs:\n /// - `callValue` is partially reported as a zero/non-zero flag\n /// - `callParams` is ignored\n /// In order to process all kinds of requests use getBridgeTransactionV2 instead.\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory) {\n // Try decoding into V2 struct first. This will revert if V1 struct is passed\n try this.getBridgeTransactionV2(request) returns (BridgeTransactionV2 memory txV2) {\n // Note: we entirely ignore the callParams field, as it was not present in V1\n return BridgeTransaction({\n originChainId: txV2.originChainId,\n destChainId: txV2.destChainId,\n originSender: txV2.originSender,\n destRecipient: txV2.destRecipient,\n originToken: txV2.originToken,\n destToken: txV2.destToken,\n originAmount: txV2.originAmount,\n destAmount: txV2.destAmount,\n originFeeAmount: txV2.originFeeAmount,\n sendChainGas: txV2.callValue != 0,\n deadline: txV2.deadline,\n nonce: txV2.nonce\n });\n } catch {\n // Fallback to V1 struct\n return abi.decode(request, (BridgeTransaction));\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) public payable {\n int256 exclusivityEndTime = int256(block.timestamp) + paramsV2.quoteExclusivitySeconds;\n _validateBridgeParams(params, paramsV2, exclusivityEndTime);\n\n // transfer tokens to bridge contract\n /// @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _pullToken(params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n\n // set status to requested\n bytes memory request = abi.encode(\n BridgeTransactionV2({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n callValue: paramsV2.callValue,\n deadline: params.deadline,\n nonce: senderNonces[params.sender]++, // increment nonce on every bridge\n exclusivityRelayer: paramsV2.quoteRelayer,\n // We checked exclusivityEndTime to be in range (0 .. params.deadline] above, so can safely cast\n exclusivityEndTime: uint256(exclusivityEndTime),\n callParams: paramsV2.callParams\n })\n );\n bytes32 transactionId = keccak256(request);\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n\n emit BridgeRequested({\n transactionId: transactionId,\n sender: params.sender,\n request: request,\n destChainId: params.dstChainId,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n sendChainGas: paramsV2.callValue != 0\n });\n emit BridgeQuoteDetails(transactionId, paramsV2.quoteId);\n }\n\n /// @inheritdoc IFastBridgeV2\n function relay(bytes memory request, address relayer) public payable {\n bytes32 transactionId = keccak256(request);\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n _validateRelayParams(transaction, transactionId, relayer);\n // mark bridge transaction as relayed\n bridgeRelayDetails[transactionId] =\n BridgeRelay({blockNumber: uint48(block.number), blockTimestamp: uint48(block.timestamp), relayer: relayer});\n\n // transfer tokens to recipient on destination chain and do an arbitrary call if requested\n address to = transaction.destRecipient;\n address token = transaction.destToken;\n uint256 amount = transaction.destAmount;\n\n // All state changes have been done at this point, can proceed to the external calls.\n // This follows the checks-effects-interactions pattern to mitigate potential reentrancy attacks.\n if (token == UniversalTokenLib.ETH_ADDRESS) {\n // For ETH non-zero callValue is not allowed\n if (transaction.callValue != 0) revert NativeTokenCallValueNotSupported();\n // Check that the correct msg.value was sent\n if (msg.value != amount) revert MsgValueIncorrect();\n } else {\n // For ERC20s, we check that the correct msg.value was sent\n if (msg.value != transaction.callValue) revert MsgValueIncorrect();\n // We need to transfer the tokens from the Relayer to the recipient first before performing an\n // optional post-transfer arbitrary call.\n IERC20(token).safeTransferFrom(msg.sender, to, amount);\n }\n\n if (transaction.callParams.length != 0) {\n // Arbitrary call requested, perform it while supplying full msg.value to the recipient\n // Note: if token has a fee on transfers, the recipient will have received less than `amount`.\n // This is a very niche edge case and should be handled by the recipient contract.\n _checkedCallRecipient({recipient: to, token: token, amount: amount, callParams: transaction.callParams});\n } else if (msg.value != 0) {\n // No arbitrary call requested, but msg.value was sent. This is either a relay with ETH,\n // or a non-zero callValue request with an ERC20. In both cases, transfer the ETH to the recipient.\n Address.sendValue(payable(to), msg.value);\n }\n\n emit BridgeRelayed({\n transactionId: transactionId,\n relayer: relayer,\n to: to,\n originChainId: transaction.originChainId,\n originToken: transaction.originToken,\n destToken: transaction.destToken,\n originAmount: transaction.originAmount,\n destAmount: transaction.destAmount,\n chainGasAmount: transaction.callValue\n });\n }\n\n /// @inheritdoc IFastBridgeV2\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) public onlyRole(RELAYER_ROLE) {\n // update bridge tx status given proof provided\n if (bridgeTxDetails[transactionId].status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n bridgeTxDetails[transactionId].status = BridgeStatus.RELAYER_PROVED;\n bridgeTxDetails[transactionId].proofBlockTimestamp = uint40(block.timestamp);\n bridgeTxDetails[transactionId].proofBlockNumber = uint48(block.number);\n bridgeTxDetails[transactionId].proofRelayer = relayer;\n\n emit BridgeProofProvided(transactionId, relayer, destTxHash);\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes memory request, address to) public {\n bytes32 transactionId = keccak256(request);\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n\n // update bridge tx status if able to claim origin collateral\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n\n // if \"to\" is zero addr, permissionlessly send funds to proven relayer\n if (to == address(0)) {\n to = bridgeTxDetails[transactionId].proofRelayer;\n } else if (bridgeTxDetails[transactionId].proofRelayer != msg.sender) {\n revert SenderIncorrect();\n }\n\n if (_timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003c= DISPUTE_PERIOD) {\n revert DisputePeriodNotPassed();\n }\n\n bridgeTxDetails[transactionId].status = BridgeStatus.RELAYER_CLAIMED;\n\n // update protocol fees if origin fee amount exists\n if (transaction.originFeeAmount \u003e 0) protocolFees[transaction.originToken] += transaction.originFeeAmount;\n\n // transfer origin collateral less fee to specified address\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositClaimed(transactionId, bridgeTxDetails[transactionId].proofRelayer, to, token, amount);\n }\n\n function bridgeStatuses(bytes32 transactionId) public view returns (BridgeStatus status) {\n return bridgeTxDetails[transactionId].status;\n }\n\n function bridgeProofs(bytes32 transactionId) public view returns (uint96 timestamp, address relayer) {\n timestamp = bridgeTxDetails[transactionId].proofBlockTimestamp;\n relayer = bridgeTxDetails[transactionId].proofRelayer;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeRelays(bytes32 transactionId) public view returns (bool) {\n // has this transactionId been relayed?\n return bridgeRelayDetails[transactionId].relayer != address(0);\n }\n\n /// @inheritdoc IFastBridgeV2\n function getBridgeTransactionV2(bytes memory request) public pure returns (BridgeTransactionV2 memory) {\n return abi.decode(request, (BridgeTransactionV2));\n }\n\n /// @notice Pulls a requested token from the user to this contract.\n function _pullToken(address token, uint256 amount) internal returns (uint256 amountPulled) {\n if (token == UniversalTokenLib.ETH_ADDRESS) {\n // For ETH we just need to check that the supplied msg.value is correct\n if (amount != msg.value) revert MsgValueIncorrect();\n amountPulled = msg.value;\n } else {\n token.assertIsContract();\n // Record token balance before transfer\n amountPulled = IERC20(token).balanceOf(address(this));\n // Token needs to be pulled only if msg.value is zero\n // This way user can specify WETH as the origin asset\n IERC20(token).safeTransferFrom(msg.sender, address(this), amount);\n // Use the difference between the recorded balance and the current balance as the amountPulled\n amountPulled = IERC20(token).balanceOf(address(this)) - amountPulled;\n }\n }\n\n /// @notice Calls the Recipient's hook function with the specified callParams and performs\n /// all the necessary checks for the returned value.\n function _checkedCallRecipient(\n address recipient,\n address token,\n uint256 amount,\n bytes memory callParams\n )\n internal\n {\n bytes memory hookData =\n abi.encodeCall(IFastBridgeRecipient.fastBridgeTransferReceived, (token, amount, callParams));\n // This will bubble any revert messages from the hook function\n bytes memory returnData = Address.functionCallWithValue({target: recipient, data: hookData, value: msg.value});\n // Explicit revert if no return data at all\n if (returnData.length == 0) revert RecipientNoReturnValue();\n // Check that exactly a single return value was returned\n if (returnData.length != 32) revert RecipientIncorrectReturnValue();\n // Return value should be abi-encoded hook function selector\n if (bytes32(returnData) != bytes32(IFastBridgeRecipient.fastBridgeTransferReceived.selector)) {\n revert RecipientIncorrectReturnValue();\n }\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint40(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint40).max but\n /// proof.timestamp \u003c type(uint40).max via unchecked statement\n /// @param proofBlockTimestamp The bridge proof block timestamp\n /// @return delta Time delta since proof submitted\n function _timeSince(uint40 proofBlockTimestamp) internal view returns (uint256 delta) {\n unchecked {\n delta = uint40(block.timestamp) - proofBlockTimestamp;\n }\n }\n\n /// @notice Performs all the necessary checks for a bridge to happen.\n /// @dev There's no good way to refactor this function to reduce cyclomatic complexity due to\n /// the number of checks that need to be performed, so we skip the code-complexity rule here.\n // solhint-disable-next-line code-complexity\n function _validateBridgeParams(\n BridgeParams memory params,\n BridgeParamsV2 memory paramsV2,\n int256 exclusivityEndTime\n )\n internal\n view\n {\n // Check V1 (legacy) params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.sender == address(0) || params.to == address(0)) revert ZeroAddress();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n // Check V2 params\n if (paramsV2.callParams.length \u003e MAX_CALL_PARAMS_LENGTH) revert CallParamsLengthAboveMax();\n if (paramsV2.callValue != 0 \u0026\u0026 params.destToken == UniversalTokenLib.ETH_ADDRESS) {\n revert NativeTokenCallValueNotSupported();\n }\n // exclusivityEndTime must be in range (0 .. params.deadline]\n if (exclusivityEndTime \u003c= 0 || exclusivityEndTime \u003e int256(params.deadline)) {\n revert ExclusivityParamsIncorrect();\n }\n }\n\n /// @notice Performs all the necessary checks for a relay to happen.\n function _validateRelayParams(\n BridgeTransactionV2 memory transaction,\n bytes32 transactionId,\n address relayer\n )\n internal\n view\n {\n if (relayer == address(0)) revert ZeroAddress();\n // Check if the transaction has already been relayed\n if (bridgeRelays(transactionId)) revert TransactionRelayed();\n if (transaction.destChainId != uint32(block.chainid)) revert ChainIncorrect();\n // Check the deadline for relay to happen\n if (block.timestamp \u003e transaction.deadline) revert DeadlineExceeded();\n // Check the exclusivity period, if it is still ongoing\n // forgefmt: disable-next-item\n if (\n transaction.exclusivityRelayer != address(0) \u0026\u0026\n transaction.exclusivityRelayer != relayer \u0026\u0026\n block.timestamp \u003c= transaction.exclusivityEndTime\n ) {\n revert ExclusivityPeriodNotPassed();\n }\n }\n}\n","language":"Solidity","languageVersion":"0.8.24","compilerVersion":"0.8.24","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../","srcMap":"","srcMapRuntime":"","abiDefinition":[{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"}],"userDoc":{"kind":"user","methods":{},"version":1},"developerDoc":{"details":"Interface of the ERC165 standard, as defined in the https://eips.ethereum.org/EIPS/eip-165[EIP]. Implementers can declare support of contract interfaces, which can then be queried by others ({ERC165Checker}). For an implementation, see {ERC165}.","kind":"dev","methods":{"supportsInterface(bytes4)":{"details":"Returns true if this contract implements the interface defined by `interfaceId`. See the corresponding https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section] to learn more about how these ids are created. This function call must use less than 30 000 gas."}},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"bytes4\",\"name\":\"interfaceId\",\"type\":\"bytes4\"}],\"name\":\"supportsInterface\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"}],\"devdoc\":{\"details\":\"Interface of the ERC165 standard, as defined in the https://eips.ethereum.org/EIPS/eip-165[EIP]. Implementers can declare support of contract interfaces, which can then be queried by others ({ERC165Checker}). For an implementation, see {ERC165}.\",\"kind\":\"dev\",\"methods\":{\"supportsInterface(bytes4)\":{\"details\":\"Returns true if this contract implements the interface defined by `interfaceId`. See the corresponding https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section] to learn more about how these ids are created. This function call must use less than 30 000 gas.\"}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeV2.sol\":\"IERC165\"},\"evmVersion\":\"shanghai\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeV2.sol\":{\"keccak256\":\"0x7cd0f885e80e2bdaa638bc32ae7af7d2e248f99ce4b354c217d0f0f7d7302e0a\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://7ccf28df0bd7b4606986585acd8622ed9b4e81379690061bb66088f0a2270af1\",\"dweb:/ipfs/QmTf7HNdHZkK6vmx8ZgewycQEb72oLD9nPwBpsM5reMstQ\"]}},\"version\":1}"},"hashes":{"supportsInterface(bytes4)":"01ffc9a7"}},"solidity/FastBridgeV2.sol:IERC20":{"code":"0x","runtime-code":"0x","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.24 ^0.8.0 ^0.8.20;\n\n// contracts/interfaces/IAdmin.sol\n\ninterface IAdmin {\n // ============ Events ============\n\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n event ChainGasAmountUpdated(uint256 oldChainGasAmount, uint256 newChainGasAmount);\n\n // ============ Methods ============\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n\n function setChainGasAmount(uint256 newChainGasAmount) external;\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IFastBridgeRecipient.sol\n\ninterface IFastBridgeRecipient {\n function fastBridgeTransferReceived(\n address token,\n uint256 amount,\n bytes memory callParams\n )\n external\n payable\n returns (bytes4);\n}\n\n// contracts/interfaces/IFastBridgeV2Errors.sol\n\ninterface IFastBridgeV2Errors {\n error AmountIncorrect();\n error CallParamsLengthAboveMax();\n error ChainIncorrect();\n error ExclusivityParamsIncorrect();\n error MsgValueIncorrect();\n error NativeTokenCallValueNotSupported();\n error SenderIncorrect();\n error StatusIncorrect();\n error ZeroAddress();\n\n error RecipientIncorrectReturnValue();\n error RecipientNoReturnValue();\n\n error DeadlineExceeded();\n error DeadlineNotExceeded();\n error DeadlineTooShort();\n error DisputePeriodNotPassed();\n error DisputePeriodPassed();\n error ExclusivityPeriodNotPassed();\n\n error TransactionRelayed();\n}\n\n// contracts/libs/Errors.sol\n\nerror DeadlineExceeded();\nerror DeadlineNotExceeded();\nerror DeadlineTooShort();\nerror InsufficientOutputAmount();\n\nerror MsgValueIncorrect();\nerror PoolNotFound();\nerror TokenAddressMismatch();\nerror TokenNotContract();\nerror TokenNotETH();\nerror TokensIdentical();\n\nerror ChainIncorrect();\nerror AmountIncorrect();\nerror ZeroAddress();\n\nerror DisputePeriodNotPassed();\nerror DisputePeriodPassed();\nerror SenderIncorrect();\nerror StatusIncorrect();\nerror TransactionIdIncorrect();\nerror TransactionRelayed();\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// contracts/interfaces/IFastBridgeV2.sol\n\ninterface IFastBridgeV2 is IFastBridge {\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n struct BridgeTxDetails {\n BridgeStatus status;\n uint40 proofBlockTimestamp;\n uint48 proofBlockNumber;\n address proofRelayer;\n }\n\n struct BridgeRelay {\n uint48 blockNumber;\n uint48 blockTimestamp;\n address relayer;\n }\n\n /// @notice New params introduced in the FastBridgeV2.\n /// We are passing fields from the older BridgeParams struct outside of this struct\n /// for backwards compatibility.\n /// Note: quoteRelayer and quoteExclusivitySeconds are either both zero (indicating no exclusivity)\n /// or both non-zero (indicating exclusivity for the given period).\n /// Note: callValue \u003e 0 can NOT be used with destToken = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE (ETH_ADDRESS)\n /// @param quoteRelayer Relayer that provided the quote for the transaction\n /// @param quoteExclusivitySeconds Period of time the quote relayer is guaranteed exclusivity after user's deposit\n /// @param quoteId Unique quote identifier used for tracking the quote\n /// @param callValue ETH value to send to the recipient (if any)\n /// @param callParams Parameters for the arbitrary call to the destination recipient (if any)\n struct BridgeParamsV2 {\n address quoteRelayer;\n int256 quoteExclusivitySeconds;\n bytes quoteId;\n uint256 callValue;\n bytes callParams;\n }\n\n /// @notice Updated bridge transaction struct to include parameters introduced in FastBridgeV2.\n /// Note: only `exclusivityRelayer` can fill such a transaction until `exclusivityEndTime`.\n /// TODO: consider changing the encoding scheme to prevent spending extra gas on decoding.\n struct BridgeTransactionV2 {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n uint256 callValue; // ETH value to send to the recipient (if any) - replaces V1's sendChainGas flag\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n address exclusivityRelayer;\n uint256 exclusivityEndTime;\n bytes callParams;\n }\n\n event BridgeQuoteDetails(bytes32 indexed transactionId, bytes quoteId);\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability\n /// to provide temporary exclusivity fill rights for the quote relayer.\n /// @param params The parameters required to bridge\n /// @param paramsV2 The parameters for exclusivity fill rights (optional, can be left empty)\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function relay(bytes memory request, address relayer) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param transactionId The transaction id associated with the encoded bridge transaction to prove\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital.\n /// @notice Can only send funds to the relayer address on the proof.\n /// @param request The encoded bridge transaction to claim on origin chain\n function claim(bytes memory request) external;\n /// @notice Checks if a transaction has been relayed\n /// @param transactionId The ID of the transaction to check\n /// @return True if the transaction has been relayed, false otherwise\n function bridgeRelays(bytes32 transactionId) external view returns (bool);\n\n /// @notice Returns the status of a bridge transaction\n /// @param transactionId The ID of the bridge transaction\n /// @return BridgeStatus Status of the bridge transaction\n function bridgeStatuses(bytes32 transactionId) external view returns (BridgeStatus);\n\n /// @notice Returns the timestamp and relayer of a bridge proof\n /// @param transactionId The ID of the bridge transaction\n /// @return timestamp The timestamp of the bridge proof\n /// @return relayer The relayer address of the bridge proof\n function bridgeProofs(bytes32 transactionId) external view returns (uint96 timestamp, address relayer);\n\n /// @notice Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\n /// @param request The bridge request to decode\n function getBridgeTransactionV2(bytes memory request) external view returns (BridgeTransactionV2 memory);\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// contracts/libs/UniversalToken.sol\n\nlibrary UniversalTokenLib {\n using SafeERC20 for IERC20;\n\n address internal constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Transfers tokens to the given account. Reverts if transfer is not successful.\n /// @dev This might trigger fallback, if ETH is transferred to the contract.\n /// Make sure this can not lead to reentrancy attacks.\n function universalTransfer(address token, address to, uint256 value) internal {\n // Don't do anything, if need to send tokens to this address\n if (to == address(this)) return;\n // Don't do anything, if trying to send zero value\n if (value == 0) return;\n if (token == ETH_ADDRESS) {\n /// @dev Note: this can potentially lead to executing code in `to`.\n // solhint-disable-next-line avoid-low-level-calls\n (bool success,) = to.call{value: value}(\"\");\n require(success, \"ETH transfer failed\");\n } else {\n IERC20(token).safeTransfer(to, value);\n }\n }\n\n /// @notice Issues an infinite allowance to the spender, if the current allowance is insufficient\n /// to spend the given amount.\n function universalApproveInfinity(address token, address spender, uint256 amountToSpend) internal {\n // ETH Chad doesn't require your approval\n if (token == ETH_ADDRESS) return;\n // No-op if allowance is already sufficient\n uint256 allowance = IERC20(token).allowance(address(this), spender);\n if (allowance \u003e= amountToSpend) return;\n // Otherwise, reset approval to 0 and set to max allowance\n if (allowance \u003e 0) IERC20(token).safeDecreaseAllowance(spender, allowance);\n IERC20(token).safeIncreaseAllowance(spender, type(uint256).max);\n }\n\n /// @notice Returns the balance of the given token (or native ETH) for the given account.\n function universalBalanceOf(address token, address account) internal view returns (uint256) {\n if (token == ETH_ADDRESS) {\n return account.balance;\n } else {\n return IERC20(token).balanceOf(account);\n }\n }\n\n /// @dev Checks that token is a contract and not ETH_ADDRESS.\n function assertIsContract(address token) internal view {\n // Check that ETH_ADDRESS was not used (in case this is a predeploy on any of the chains)\n if (token == UniversalTokenLib.ETH_ADDRESS) revert TokenNotContract();\n // Check that token is not an EOA\n if (token.code.length == 0) revert TokenNotContract();\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/Admin.sol\n\ncontract Admin is IAdmin, AccessControlEnumerable {\n using UniversalTokenLib for address;\n\n bytes32 public constant RELAYER_ROLE = keccak256(\"RELAYER_ROLE\");\n bytes32 public constant REFUNDER_ROLE = keccak256(\"REFUNDER_ROLE\");\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n uint256 public constant FEE_BPS = 1e6;\n uint256 public constant FEE_RATE_MAX = 0.01e6; // max 1% on origin amount\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Chain gas amount to forward as rebate if requested\n uint256 public chainGasAmount;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n }\n\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n require(newFeeRate \u003c= FEE_RATE_MAX, \"newFeeRate \u003e max\");\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n token.universalTransfer(recipient, feeAmount);\n emit FeesSwept(token, recipient, feeAmount);\n }\n\n function setChainGasAmount(uint256 newChainGasAmount) external onlyRole(GOVERNOR_ROLE) {\n uint256 oldChainGasAmount = chainGasAmount;\n chainGasAmount = newChainGasAmount;\n emit ChainGasAmountUpdated(oldChainGasAmount, newChainGasAmount);\n }\n}\n\n// contracts/FastBridgeV2.sol\n\n/// @notice FastBridgeV2 is a contract for bridging tokens across chains.\ncontract FastBridgeV2 is Admin, IFastBridgeV2, IFastBridgeV2Errors {\n using SafeERC20 for IERC20;\n using UniversalTokenLib for address;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Delay for a transaction after which it could be permisionlessly refunded\n uint256 public constant REFUND_DELAY = 7 days;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n /// @notice Maximum length of accepted callParams\n uint256 public constant MAX_CALL_PARAMS_LENGTH = 2 ** 16 - 1;\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeTxDetails) public bridgeTxDetails;\n /// @notice Relay details on destination chain\n mapping(bytes32 =\u003e BridgeRelay) public bridgeRelayDetails;\n /// @notice Unique bridge nonces tracked per originSender\n mapping(address =\u003e uint256) public senderNonces;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Replaced by senderNonces\n uint256 public immutable nonce = 0;\n /// @notice the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n bridge({\n params: params,\n paramsV2: BridgeParamsV2({\n quoteRelayer: address(0),\n quoteExclusivitySeconds: 0,\n quoteId: bytes(\"\"),\n callValue: 0,\n callParams: bytes(\"\")\n })\n });\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes memory request) external payable {\n relay({request: request, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes memory request, bytes32 destTxHash) external {\n prove({transactionId: keccak256(request), destTxHash: destTxHash, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridgeV2\n function claim(bytes memory request) external {\n claim({request: request, to: address(0)});\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003e DISPUTE_PERIOD) {\n revert DisputePeriodPassed();\n }\n\n // @dev relayer gets slashed effectively if dest relay has gone thru\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n bridgeTxDetails[transactionId].proofRelayer = address(0);\n bridgeTxDetails[transactionId].proofBlockTimestamp = 0;\n bridgeTxDetails[transactionId].proofBlockNumber = 0;\n\n emit BridgeProofDisputed(transactionId, msg.sender);\n }\n\n /// @inheritdoc IFastBridge\n function refund(bytes memory request) external {\n bytes32 transactionId = keccak256(request);\n\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n\n if (bridgeTxDetails[transactionId].status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n\n if (hasRole(REFUNDER_ROLE, msg.sender)) {\n // Refunder can refund if deadline has passed\n if (block.timestamp \u003c= transaction.deadline) revert DeadlineNotExceeded();\n } else {\n // Permissionless refund is allowed after REFUND_DELAY\n if (block.timestamp \u003c= transaction.deadline + REFUND_DELAY) revert DeadlineNotExceeded();\n }\n\n // if all checks passed, set to REFUNDED status\n bridgeTxDetails[transactionId].status = BridgeStatus.REFUNDED;\n\n // transfer origin collateral back to original sender\n address to = transaction.originSender;\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount + transaction.originFeeAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (bridgeTxDetails[transactionId].proofRelayer != relayer) revert SenderIncorrect();\n return _timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n /// @dev This method is added to achieve backwards compatibility with decoding requests into V1 structs:\n /// - `callValue` is partially reported as a zero/non-zero flag\n /// - `callParams` is ignored\n /// In order to process all kinds of requests use getBridgeTransactionV2 instead.\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory) {\n // Try decoding into V2 struct first. This will revert if V1 struct is passed\n try this.getBridgeTransactionV2(request) returns (BridgeTransactionV2 memory txV2) {\n // Note: we entirely ignore the callParams field, as it was not present in V1\n return BridgeTransaction({\n originChainId: txV2.originChainId,\n destChainId: txV2.destChainId,\n originSender: txV2.originSender,\n destRecipient: txV2.destRecipient,\n originToken: txV2.originToken,\n destToken: txV2.destToken,\n originAmount: txV2.originAmount,\n destAmount: txV2.destAmount,\n originFeeAmount: txV2.originFeeAmount,\n sendChainGas: txV2.callValue != 0,\n deadline: txV2.deadline,\n nonce: txV2.nonce\n });\n } catch {\n // Fallback to V1 struct\n return abi.decode(request, (BridgeTransaction));\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) public payable {\n int256 exclusivityEndTime = int256(block.timestamp) + paramsV2.quoteExclusivitySeconds;\n _validateBridgeParams(params, paramsV2, exclusivityEndTime);\n\n // transfer tokens to bridge contract\n /// @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _pullToken(params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n\n // set status to requested\n bytes memory request = abi.encode(\n BridgeTransactionV2({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n callValue: paramsV2.callValue,\n deadline: params.deadline,\n nonce: senderNonces[params.sender]++, // increment nonce on every bridge\n exclusivityRelayer: paramsV2.quoteRelayer,\n // We checked exclusivityEndTime to be in range (0 .. params.deadline] above, so can safely cast\n exclusivityEndTime: uint256(exclusivityEndTime),\n callParams: paramsV2.callParams\n })\n );\n bytes32 transactionId = keccak256(request);\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n\n emit BridgeRequested({\n transactionId: transactionId,\n sender: params.sender,\n request: request,\n destChainId: params.dstChainId,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n sendChainGas: paramsV2.callValue != 0\n });\n emit BridgeQuoteDetails(transactionId, paramsV2.quoteId);\n }\n\n /// @inheritdoc IFastBridgeV2\n function relay(bytes memory request, address relayer) public payable {\n bytes32 transactionId = keccak256(request);\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n _validateRelayParams(transaction, transactionId, relayer);\n // mark bridge transaction as relayed\n bridgeRelayDetails[transactionId] =\n BridgeRelay({blockNumber: uint48(block.number), blockTimestamp: uint48(block.timestamp), relayer: relayer});\n\n // transfer tokens to recipient on destination chain and do an arbitrary call if requested\n address to = transaction.destRecipient;\n address token = transaction.destToken;\n uint256 amount = transaction.destAmount;\n\n // All state changes have been done at this point, can proceed to the external calls.\n // This follows the checks-effects-interactions pattern to mitigate potential reentrancy attacks.\n if (token == UniversalTokenLib.ETH_ADDRESS) {\n // For ETH non-zero callValue is not allowed\n if (transaction.callValue != 0) revert NativeTokenCallValueNotSupported();\n // Check that the correct msg.value was sent\n if (msg.value != amount) revert MsgValueIncorrect();\n } else {\n // For ERC20s, we check that the correct msg.value was sent\n if (msg.value != transaction.callValue) revert MsgValueIncorrect();\n // We need to transfer the tokens from the Relayer to the recipient first before performing an\n // optional post-transfer arbitrary call.\n IERC20(token).safeTransferFrom(msg.sender, to, amount);\n }\n\n if (transaction.callParams.length != 0) {\n // Arbitrary call requested, perform it while supplying full msg.value to the recipient\n // Note: if token has a fee on transfers, the recipient will have received less than `amount`.\n // This is a very niche edge case and should be handled by the recipient contract.\n _checkedCallRecipient({recipient: to, token: token, amount: amount, callParams: transaction.callParams});\n } else if (msg.value != 0) {\n // No arbitrary call requested, but msg.value was sent. This is either a relay with ETH,\n // or a non-zero callValue request with an ERC20. In both cases, transfer the ETH to the recipient.\n Address.sendValue(payable(to), msg.value);\n }\n\n emit BridgeRelayed({\n transactionId: transactionId,\n relayer: relayer,\n to: to,\n originChainId: transaction.originChainId,\n originToken: transaction.originToken,\n destToken: transaction.destToken,\n originAmount: transaction.originAmount,\n destAmount: transaction.destAmount,\n chainGasAmount: transaction.callValue\n });\n }\n\n /// @inheritdoc IFastBridgeV2\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) public onlyRole(RELAYER_ROLE) {\n // update bridge tx status given proof provided\n if (bridgeTxDetails[transactionId].status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n bridgeTxDetails[transactionId].status = BridgeStatus.RELAYER_PROVED;\n bridgeTxDetails[transactionId].proofBlockTimestamp = uint40(block.timestamp);\n bridgeTxDetails[transactionId].proofBlockNumber = uint48(block.number);\n bridgeTxDetails[transactionId].proofRelayer = relayer;\n\n emit BridgeProofProvided(transactionId, relayer, destTxHash);\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes memory request, address to) public {\n bytes32 transactionId = keccak256(request);\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n\n // update bridge tx status if able to claim origin collateral\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n\n // if \"to\" is zero addr, permissionlessly send funds to proven relayer\n if (to == address(0)) {\n to = bridgeTxDetails[transactionId].proofRelayer;\n } else if (bridgeTxDetails[transactionId].proofRelayer != msg.sender) {\n revert SenderIncorrect();\n }\n\n if (_timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003c= DISPUTE_PERIOD) {\n revert DisputePeriodNotPassed();\n }\n\n bridgeTxDetails[transactionId].status = BridgeStatus.RELAYER_CLAIMED;\n\n // update protocol fees if origin fee amount exists\n if (transaction.originFeeAmount \u003e 0) protocolFees[transaction.originToken] += transaction.originFeeAmount;\n\n // transfer origin collateral less fee to specified address\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositClaimed(transactionId, bridgeTxDetails[transactionId].proofRelayer, to, token, amount);\n }\n\n function bridgeStatuses(bytes32 transactionId) public view returns (BridgeStatus status) {\n return bridgeTxDetails[transactionId].status;\n }\n\n function bridgeProofs(bytes32 transactionId) public view returns (uint96 timestamp, address relayer) {\n timestamp = bridgeTxDetails[transactionId].proofBlockTimestamp;\n relayer = bridgeTxDetails[transactionId].proofRelayer;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeRelays(bytes32 transactionId) public view returns (bool) {\n // has this transactionId been relayed?\n return bridgeRelayDetails[transactionId].relayer != address(0);\n }\n\n /// @inheritdoc IFastBridgeV2\n function getBridgeTransactionV2(bytes memory request) public pure returns (BridgeTransactionV2 memory) {\n return abi.decode(request, (BridgeTransactionV2));\n }\n\n /// @notice Pulls a requested token from the user to this contract.\n function _pullToken(address token, uint256 amount) internal returns (uint256 amountPulled) {\n if (token == UniversalTokenLib.ETH_ADDRESS) {\n // For ETH we just need to check that the supplied msg.value is correct\n if (amount != msg.value) revert MsgValueIncorrect();\n amountPulled = msg.value;\n } else {\n token.assertIsContract();\n // Record token balance before transfer\n amountPulled = IERC20(token).balanceOf(address(this));\n // Token needs to be pulled only if msg.value is zero\n // This way user can specify WETH as the origin asset\n IERC20(token).safeTransferFrom(msg.sender, address(this), amount);\n // Use the difference between the recorded balance and the current balance as the amountPulled\n amountPulled = IERC20(token).balanceOf(address(this)) - amountPulled;\n }\n }\n\n /// @notice Calls the Recipient's hook function with the specified callParams and performs\n /// all the necessary checks for the returned value.\n function _checkedCallRecipient(\n address recipient,\n address token,\n uint256 amount,\n bytes memory callParams\n )\n internal\n {\n bytes memory hookData =\n abi.encodeCall(IFastBridgeRecipient.fastBridgeTransferReceived, (token, amount, callParams));\n // This will bubble any revert messages from the hook function\n bytes memory returnData = Address.functionCallWithValue({target: recipient, data: hookData, value: msg.value});\n // Explicit revert if no return data at all\n if (returnData.length == 0) revert RecipientNoReturnValue();\n // Check that exactly a single return value was returned\n if (returnData.length != 32) revert RecipientIncorrectReturnValue();\n // Return value should be abi-encoded hook function selector\n if (bytes32(returnData) != bytes32(IFastBridgeRecipient.fastBridgeTransferReceived.selector)) {\n revert RecipientIncorrectReturnValue();\n }\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint40(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint40).max but\n /// proof.timestamp \u003c type(uint40).max via unchecked statement\n /// @param proofBlockTimestamp The bridge proof block timestamp\n /// @return delta Time delta since proof submitted\n function _timeSince(uint40 proofBlockTimestamp) internal view returns (uint256 delta) {\n unchecked {\n delta = uint40(block.timestamp) - proofBlockTimestamp;\n }\n }\n\n /// @notice Performs all the necessary checks for a bridge to happen.\n /// @dev There's no good way to refactor this function to reduce cyclomatic complexity due to\n /// the number of checks that need to be performed, so we skip the code-complexity rule here.\n // solhint-disable-next-line code-complexity\n function _validateBridgeParams(\n BridgeParams memory params,\n BridgeParamsV2 memory paramsV2,\n int256 exclusivityEndTime\n )\n internal\n view\n {\n // Check V1 (legacy) params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.sender == address(0) || params.to == address(0)) revert ZeroAddress();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n // Check V2 params\n if (paramsV2.callParams.length \u003e MAX_CALL_PARAMS_LENGTH) revert CallParamsLengthAboveMax();\n if (paramsV2.callValue != 0 \u0026\u0026 params.destToken == UniversalTokenLib.ETH_ADDRESS) {\n revert NativeTokenCallValueNotSupported();\n }\n // exclusivityEndTime must be in range (0 .. params.deadline]\n if (exclusivityEndTime \u003c= 0 || exclusivityEndTime \u003e int256(params.deadline)) {\n revert ExclusivityParamsIncorrect();\n }\n }\n\n /// @notice Performs all the necessary checks for a relay to happen.\n function _validateRelayParams(\n BridgeTransactionV2 memory transaction,\n bytes32 transactionId,\n address relayer\n )\n internal\n view\n {\n if (relayer == address(0)) revert ZeroAddress();\n // Check if the transaction has already been relayed\n if (bridgeRelays(transactionId)) revert TransactionRelayed();\n if (transaction.destChainId != uint32(block.chainid)) revert ChainIncorrect();\n // Check the deadline for relay to happen\n if (block.timestamp \u003e transaction.deadline) revert DeadlineExceeded();\n // Check the exclusivity period, if it is still ongoing\n // forgefmt: disable-next-item\n if (\n transaction.exclusivityRelayer != address(0) \u0026\u0026\n transaction.exclusivityRelayer != relayer \u0026\u0026\n block.timestamp \u003c= transaction.exclusivityEndTime\n ) {\n revert ExclusivityPeriodNotPassed();\n }\n }\n}\n","language":"Solidity","languageVersion":"0.8.24","compilerVersion":"0.8.24","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../","srcMap":"","srcMapRuntime":"","abiDefinition":[{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Transfer","type":"event"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"}],"userDoc":{"kind":"user","methods":{},"version":1},"developerDoc":{"details":"Interface of the ERC20 standard as defined in the EIP.","events":{"Approval(address,address,uint256)":{"details":"Emitted when the allowance of a `spender` for an `owner` is set by a call to {approve}. `value` is the new allowance."},"Transfer(address,address,uint256)":{"details":"Emitted when `value` tokens are moved from one account (`from`) to another (`to`). Note that `value` may be zero."}},"kind":"dev","methods":{"allowance(address,address)":{"details":"Returns the remaining number of tokens that `spender` will be allowed to spend on behalf of `owner` through {transferFrom}. This is zero by default. This value changes when {approve} or {transferFrom} are called."},"approve(address,uint256)":{"details":"Sets a `value` amount of tokens as the allowance of `spender` over the caller's tokens. Returns a boolean value indicating whether the operation succeeded. IMPORTANT: Beware that changing an allowance with this method brings the risk that someone may use both the old and the new allowance by unfortunate transaction ordering. One possible solution to mitigate this race condition is to first reduce the spender's allowance to 0 and set the desired value afterwards: https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 Emits an {Approval} event."},"balanceOf(address)":{"details":"Returns the value of tokens owned by `account`."},"totalSupply()":{"details":"Returns the value of tokens in existence."},"transfer(address,uint256)":{"details":"Moves a `value` amount of tokens from the caller's account to `to`. Returns a boolean value indicating whether the operation succeeded. Emits a {Transfer} event."},"transferFrom(address,address,uint256)":{"details":"Moves a `value` amount of tokens from `from` to `to` using the allowance mechanism. `value` is then deducted from the caller's allowance. Returns a boolean value indicating whether the operation succeeded. Emits a {Transfer} event."}},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"Approval\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"Transfer\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"}],\"name\":\"allowance\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"approve\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"balanceOf\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"totalSupply\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"transfer\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"transferFrom\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"details\":\"Interface of the ERC20 standard as defined in the EIP.\",\"events\":{\"Approval(address,address,uint256)\":{\"details\":\"Emitted when the allowance of a `spender` for an `owner` is set by a call to {approve}. `value` is the new allowance.\"},\"Transfer(address,address,uint256)\":{\"details\":\"Emitted when `value` tokens are moved from one account (`from`) to another (`to`). Note that `value` may be zero.\"}},\"kind\":\"dev\",\"methods\":{\"allowance(address,address)\":{\"details\":\"Returns the remaining number of tokens that `spender` will be allowed to spend on behalf of `owner` through {transferFrom}. This is zero by default. This value changes when {approve} or {transferFrom} are called.\"},\"approve(address,uint256)\":{\"details\":\"Sets a `value` amount of tokens as the allowance of `spender` over the caller's tokens. Returns a boolean value indicating whether the operation succeeded. IMPORTANT: Beware that changing an allowance with this method brings the risk that someone may use both the old and the new allowance by unfortunate transaction ordering. One possible solution to mitigate this race condition is to first reduce the spender's allowance to 0 and set the desired value afterwards: https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 Emits an {Approval} event.\"},\"balanceOf(address)\":{\"details\":\"Returns the value of tokens owned by `account`.\"},\"totalSupply()\":{\"details\":\"Returns the value of tokens in existence.\"},\"transfer(address,uint256)\":{\"details\":\"Moves a `value` amount of tokens from the caller's account to `to`. Returns a boolean value indicating whether the operation succeeded. Emits a {Transfer} event.\"},\"transferFrom(address,address,uint256)\":{\"details\":\"Moves a `value` amount of tokens from `from` to `to` using the allowance mechanism. `value` is then deducted from the caller's allowance. Returns a boolean value indicating whether the operation succeeded. Emits a {Transfer} event.\"}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeV2.sol\":\"IERC20\"},\"evmVersion\":\"shanghai\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeV2.sol\":{\"keccak256\":\"0x7cd0f885e80e2bdaa638bc32ae7af7d2e248f99ce4b354c217d0f0f7d7302e0a\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://7ccf28df0bd7b4606986585acd8622ed9b4e81379690061bb66088f0a2270af1\",\"dweb:/ipfs/QmTf7HNdHZkK6vmx8ZgewycQEb72oLD9nPwBpsM5reMstQ\"]}},\"version\":1}"},"hashes":{"allowance(address,address)":"dd62ed3e","approve(address,uint256)":"095ea7b3","balanceOf(address)":"70a08231","totalSupply()":"18160ddd","transfer(address,uint256)":"a9059cbb","transferFrom(address,address,uint256)":"23b872dd"}},"solidity/FastBridgeV2.sol:IERC20Permit":{"code":"0x","runtime-code":"0x","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.24 ^0.8.0 ^0.8.20;\n\n// contracts/interfaces/IAdmin.sol\n\ninterface IAdmin {\n // ============ Events ============\n\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n event ChainGasAmountUpdated(uint256 oldChainGasAmount, uint256 newChainGasAmount);\n\n // ============ Methods ============\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n\n function setChainGasAmount(uint256 newChainGasAmount) external;\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IFastBridgeRecipient.sol\n\ninterface IFastBridgeRecipient {\n function fastBridgeTransferReceived(\n address token,\n uint256 amount,\n bytes memory callParams\n )\n external\n payable\n returns (bytes4);\n}\n\n// contracts/interfaces/IFastBridgeV2Errors.sol\n\ninterface IFastBridgeV2Errors {\n error AmountIncorrect();\n error CallParamsLengthAboveMax();\n error ChainIncorrect();\n error ExclusivityParamsIncorrect();\n error MsgValueIncorrect();\n error NativeTokenCallValueNotSupported();\n error SenderIncorrect();\n error StatusIncorrect();\n error ZeroAddress();\n\n error RecipientIncorrectReturnValue();\n error RecipientNoReturnValue();\n\n error DeadlineExceeded();\n error DeadlineNotExceeded();\n error DeadlineTooShort();\n error DisputePeriodNotPassed();\n error DisputePeriodPassed();\n error ExclusivityPeriodNotPassed();\n\n error TransactionRelayed();\n}\n\n// contracts/libs/Errors.sol\n\nerror DeadlineExceeded();\nerror DeadlineNotExceeded();\nerror DeadlineTooShort();\nerror InsufficientOutputAmount();\n\nerror MsgValueIncorrect();\nerror PoolNotFound();\nerror TokenAddressMismatch();\nerror TokenNotContract();\nerror TokenNotETH();\nerror TokensIdentical();\n\nerror ChainIncorrect();\nerror AmountIncorrect();\nerror ZeroAddress();\n\nerror DisputePeriodNotPassed();\nerror DisputePeriodPassed();\nerror SenderIncorrect();\nerror StatusIncorrect();\nerror TransactionIdIncorrect();\nerror TransactionRelayed();\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// contracts/interfaces/IFastBridgeV2.sol\n\ninterface IFastBridgeV2 is IFastBridge {\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n struct BridgeTxDetails {\n BridgeStatus status;\n uint40 proofBlockTimestamp;\n uint48 proofBlockNumber;\n address proofRelayer;\n }\n\n struct BridgeRelay {\n uint48 blockNumber;\n uint48 blockTimestamp;\n address relayer;\n }\n\n /// @notice New params introduced in the FastBridgeV2.\n /// We are passing fields from the older BridgeParams struct outside of this struct\n /// for backwards compatibility.\n /// Note: quoteRelayer and quoteExclusivitySeconds are either both zero (indicating no exclusivity)\n /// or both non-zero (indicating exclusivity for the given period).\n /// Note: callValue \u003e 0 can NOT be used with destToken = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE (ETH_ADDRESS)\n /// @param quoteRelayer Relayer that provided the quote for the transaction\n /// @param quoteExclusivitySeconds Period of time the quote relayer is guaranteed exclusivity after user's deposit\n /// @param quoteId Unique quote identifier used for tracking the quote\n /// @param callValue ETH value to send to the recipient (if any)\n /// @param callParams Parameters for the arbitrary call to the destination recipient (if any)\n struct BridgeParamsV2 {\n address quoteRelayer;\n int256 quoteExclusivitySeconds;\n bytes quoteId;\n uint256 callValue;\n bytes callParams;\n }\n\n /// @notice Updated bridge transaction struct to include parameters introduced in FastBridgeV2.\n /// Note: only `exclusivityRelayer` can fill such a transaction until `exclusivityEndTime`.\n /// TODO: consider changing the encoding scheme to prevent spending extra gas on decoding.\n struct BridgeTransactionV2 {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n uint256 callValue; // ETH value to send to the recipient (if any) - replaces V1's sendChainGas flag\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n address exclusivityRelayer;\n uint256 exclusivityEndTime;\n bytes callParams;\n }\n\n event BridgeQuoteDetails(bytes32 indexed transactionId, bytes quoteId);\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability\n /// to provide temporary exclusivity fill rights for the quote relayer.\n /// @param params The parameters required to bridge\n /// @param paramsV2 The parameters for exclusivity fill rights (optional, can be left empty)\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function relay(bytes memory request, address relayer) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param transactionId The transaction id associated with the encoded bridge transaction to prove\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital.\n /// @notice Can only send funds to the relayer address on the proof.\n /// @param request The encoded bridge transaction to claim on origin chain\n function claim(bytes memory request) external;\n /// @notice Checks if a transaction has been relayed\n /// @param transactionId The ID of the transaction to check\n /// @return True if the transaction has been relayed, false otherwise\n function bridgeRelays(bytes32 transactionId) external view returns (bool);\n\n /// @notice Returns the status of a bridge transaction\n /// @param transactionId The ID of the bridge transaction\n /// @return BridgeStatus Status of the bridge transaction\n function bridgeStatuses(bytes32 transactionId) external view returns (BridgeStatus);\n\n /// @notice Returns the timestamp and relayer of a bridge proof\n /// @param transactionId The ID of the bridge transaction\n /// @return timestamp The timestamp of the bridge proof\n /// @return relayer The relayer address of the bridge proof\n function bridgeProofs(bytes32 transactionId) external view returns (uint96 timestamp, address relayer);\n\n /// @notice Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\n /// @param request The bridge request to decode\n function getBridgeTransactionV2(bytes memory request) external view returns (BridgeTransactionV2 memory);\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// contracts/libs/UniversalToken.sol\n\nlibrary UniversalTokenLib {\n using SafeERC20 for IERC20;\n\n address internal constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Transfers tokens to the given account. Reverts if transfer is not successful.\n /// @dev This might trigger fallback, if ETH is transferred to the contract.\n /// Make sure this can not lead to reentrancy attacks.\n function universalTransfer(address token, address to, uint256 value) internal {\n // Don't do anything, if need to send tokens to this address\n if (to == address(this)) return;\n // Don't do anything, if trying to send zero value\n if (value == 0) return;\n if (token == ETH_ADDRESS) {\n /// @dev Note: this can potentially lead to executing code in `to`.\n // solhint-disable-next-line avoid-low-level-calls\n (bool success,) = to.call{value: value}(\"\");\n require(success, \"ETH transfer failed\");\n } else {\n IERC20(token).safeTransfer(to, value);\n }\n }\n\n /// @notice Issues an infinite allowance to the spender, if the current allowance is insufficient\n /// to spend the given amount.\n function universalApproveInfinity(address token, address spender, uint256 amountToSpend) internal {\n // ETH Chad doesn't require your approval\n if (token == ETH_ADDRESS) return;\n // No-op if allowance is already sufficient\n uint256 allowance = IERC20(token).allowance(address(this), spender);\n if (allowance \u003e= amountToSpend) return;\n // Otherwise, reset approval to 0 and set to max allowance\n if (allowance \u003e 0) IERC20(token).safeDecreaseAllowance(spender, allowance);\n IERC20(token).safeIncreaseAllowance(spender, type(uint256).max);\n }\n\n /// @notice Returns the balance of the given token (or native ETH) for the given account.\n function universalBalanceOf(address token, address account) internal view returns (uint256) {\n if (token == ETH_ADDRESS) {\n return account.balance;\n } else {\n return IERC20(token).balanceOf(account);\n }\n }\n\n /// @dev Checks that token is a contract and not ETH_ADDRESS.\n function assertIsContract(address token) internal view {\n // Check that ETH_ADDRESS was not used (in case this is a predeploy on any of the chains)\n if (token == UniversalTokenLib.ETH_ADDRESS) revert TokenNotContract();\n // Check that token is not an EOA\n if (token.code.length == 0) revert TokenNotContract();\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/Admin.sol\n\ncontract Admin is IAdmin, AccessControlEnumerable {\n using UniversalTokenLib for address;\n\n bytes32 public constant RELAYER_ROLE = keccak256(\"RELAYER_ROLE\");\n bytes32 public constant REFUNDER_ROLE = keccak256(\"REFUNDER_ROLE\");\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n uint256 public constant FEE_BPS = 1e6;\n uint256 public constant FEE_RATE_MAX = 0.01e6; // max 1% on origin amount\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Chain gas amount to forward as rebate if requested\n uint256 public chainGasAmount;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n }\n\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n require(newFeeRate \u003c= FEE_RATE_MAX, \"newFeeRate \u003e max\");\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n token.universalTransfer(recipient, feeAmount);\n emit FeesSwept(token, recipient, feeAmount);\n }\n\n function setChainGasAmount(uint256 newChainGasAmount) external onlyRole(GOVERNOR_ROLE) {\n uint256 oldChainGasAmount = chainGasAmount;\n chainGasAmount = newChainGasAmount;\n emit ChainGasAmountUpdated(oldChainGasAmount, newChainGasAmount);\n }\n}\n\n// contracts/FastBridgeV2.sol\n\n/// @notice FastBridgeV2 is a contract for bridging tokens across chains.\ncontract FastBridgeV2 is Admin, IFastBridgeV2, IFastBridgeV2Errors {\n using SafeERC20 for IERC20;\n using UniversalTokenLib for address;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Delay for a transaction after which it could be permisionlessly refunded\n uint256 public constant REFUND_DELAY = 7 days;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n /// @notice Maximum length of accepted callParams\n uint256 public constant MAX_CALL_PARAMS_LENGTH = 2 ** 16 - 1;\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeTxDetails) public bridgeTxDetails;\n /// @notice Relay details on destination chain\n mapping(bytes32 =\u003e BridgeRelay) public bridgeRelayDetails;\n /// @notice Unique bridge nonces tracked per originSender\n mapping(address =\u003e uint256) public senderNonces;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Replaced by senderNonces\n uint256 public immutable nonce = 0;\n /// @notice the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n bridge({\n params: params,\n paramsV2: BridgeParamsV2({\n quoteRelayer: address(0),\n quoteExclusivitySeconds: 0,\n quoteId: bytes(\"\"),\n callValue: 0,\n callParams: bytes(\"\")\n })\n });\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes memory request) external payable {\n relay({request: request, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes memory request, bytes32 destTxHash) external {\n prove({transactionId: keccak256(request), destTxHash: destTxHash, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridgeV2\n function claim(bytes memory request) external {\n claim({request: request, to: address(0)});\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003e DISPUTE_PERIOD) {\n revert DisputePeriodPassed();\n }\n\n // @dev relayer gets slashed effectively if dest relay has gone thru\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n bridgeTxDetails[transactionId].proofRelayer = address(0);\n bridgeTxDetails[transactionId].proofBlockTimestamp = 0;\n bridgeTxDetails[transactionId].proofBlockNumber = 0;\n\n emit BridgeProofDisputed(transactionId, msg.sender);\n }\n\n /// @inheritdoc IFastBridge\n function refund(bytes memory request) external {\n bytes32 transactionId = keccak256(request);\n\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n\n if (bridgeTxDetails[transactionId].status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n\n if (hasRole(REFUNDER_ROLE, msg.sender)) {\n // Refunder can refund if deadline has passed\n if (block.timestamp \u003c= transaction.deadline) revert DeadlineNotExceeded();\n } else {\n // Permissionless refund is allowed after REFUND_DELAY\n if (block.timestamp \u003c= transaction.deadline + REFUND_DELAY) revert DeadlineNotExceeded();\n }\n\n // if all checks passed, set to REFUNDED status\n bridgeTxDetails[transactionId].status = BridgeStatus.REFUNDED;\n\n // transfer origin collateral back to original sender\n address to = transaction.originSender;\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount + transaction.originFeeAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (bridgeTxDetails[transactionId].proofRelayer != relayer) revert SenderIncorrect();\n return _timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n /// @dev This method is added to achieve backwards compatibility with decoding requests into V1 structs:\n /// - `callValue` is partially reported as a zero/non-zero flag\n /// - `callParams` is ignored\n /// In order to process all kinds of requests use getBridgeTransactionV2 instead.\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory) {\n // Try decoding into V2 struct first. This will revert if V1 struct is passed\n try this.getBridgeTransactionV2(request) returns (BridgeTransactionV2 memory txV2) {\n // Note: we entirely ignore the callParams field, as it was not present in V1\n return BridgeTransaction({\n originChainId: txV2.originChainId,\n destChainId: txV2.destChainId,\n originSender: txV2.originSender,\n destRecipient: txV2.destRecipient,\n originToken: txV2.originToken,\n destToken: txV2.destToken,\n originAmount: txV2.originAmount,\n destAmount: txV2.destAmount,\n originFeeAmount: txV2.originFeeAmount,\n sendChainGas: txV2.callValue != 0,\n deadline: txV2.deadline,\n nonce: txV2.nonce\n });\n } catch {\n // Fallback to V1 struct\n return abi.decode(request, (BridgeTransaction));\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) public payable {\n int256 exclusivityEndTime = int256(block.timestamp) + paramsV2.quoteExclusivitySeconds;\n _validateBridgeParams(params, paramsV2, exclusivityEndTime);\n\n // transfer tokens to bridge contract\n /// @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _pullToken(params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n\n // set status to requested\n bytes memory request = abi.encode(\n BridgeTransactionV2({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n callValue: paramsV2.callValue,\n deadline: params.deadline,\n nonce: senderNonces[params.sender]++, // increment nonce on every bridge\n exclusivityRelayer: paramsV2.quoteRelayer,\n // We checked exclusivityEndTime to be in range (0 .. params.deadline] above, so can safely cast\n exclusivityEndTime: uint256(exclusivityEndTime),\n callParams: paramsV2.callParams\n })\n );\n bytes32 transactionId = keccak256(request);\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n\n emit BridgeRequested({\n transactionId: transactionId,\n sender: params.sender,\n request: request,\n destChainId: params.dstChainId,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n sendChainGas: paramsV2.callValue != 0\n });\n emit BridgeQuoteDetails(transactionId, paramsV2.quoteId);\n }\n\n /// @inheritdoc IFastBridgeV2\n function relay(bytes memory request, address relayer) public payable {\n bytes32 transactionId = keccak256(request);\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n _validateRelayParams(transaction, transactionId, relayer);\n // mark bridge transaction as relayed\n bridgeRelayDetails[transactionId] =\n BridgeRelay({blockNumber: uint48(block.number), blockTimestamp: uint48(block.timestamp), relayer: relayer});\n\n // transfer tokens to recipient on destination chain and do an arbitrary call if requested\n address to = transaction.destRecipient;\n address token = transaction.destToken;\n uint256 amount = transaction.destAmount;\n\n // All state changes have been done at this point, can proceed to the external calls.\n // This follows the checks-effects-interactions pattern to mitigate potential reentrancy attacks.\n if (token == UniversalTokenLib.ETH_ADDRESS) {\n // For ETH non-zero callValue is not allowed\n if (transaction.callValue != 0) revert NativeTokenCallValueNotSupported();\n // Check that the correct msg.value was sent\n if (msg.value != amount) revert MsgValueIncorrect();\n } else {\n // For ERC20s, we check that the correct msg.value was sent\n if (msg.value != transaction.callValue) revert MsgValueIncorrect();\n // We need to transfer the tokens from the Relayer to the recipient first before performing an\n // optional post-transfer arbitrary call.\n IERC20(token).safeTransferFrom(msg.sender, to, amount);\n }\n\n if (transaction.callParams.length != 0) {\n // Arbitrary call requested, perform it while supplying full msg.value to the recipient\n // Note: if token has a fee on transfers, the recipient will have received less than `amount`.\n // This is a very niche edge case and should be handled by the recipient contract.\n _checkedCallRecipient({recipient: to, token: token, amount: amount, callParams: transaction.callParams});\n } else if (msg.value != 0) {\n // No arbitrary call requested, but msg.value was sent. This is either a relay with ETH,\n // or a non-zero callValue request with an ERC20. In both cases, transfer the ETH to the recipient.\n Address.sendValue(payable(to), msg.value);\n }\n\n emit BridgeRelayed({\n transactionId: transactionId,\n relayer: relayer,\n to: to,\n originChainId: transaction.originChainId,\n originToken: transaction.originToken,\n destToken: transaction.destToken,\n originAmount: transaction.originAmount,\n destAmount: transaction.destAmount,\n chainGasAmount: transaction.callValue\n });\n }\n\n /// @inheritdoc IFastBridgeV2\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) public onlyRole(RELAYER_ROLE) {\n // update bridge tx status given proof provided\n if (bridgeTxDetails[transactionId].status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n bridgeTxDetails[transactionId].status = BridgeStatus.RELAYER_PROVED;\n bridgeTxDetails[transactionId].proofBlockTimestamp = uint40(block.timestamp);\n bridgeTxDetails[transactionId].proofBlockNumber = uint48(block.number);\n bridgeTxDetails[transactionId].proofRelayer = relayer;\n\n emit BridgeProofProvided(transactionId, relayer, destTxHash);\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes memory request, address to) public {\n bytes32 transactionId = keccak256(request);\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n\n // update bridge tx status if able to claim origin collateral\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n\n // if \"to\" is zero addr, permissionlessly send funds to proven relayer\n if (to == address(0)) {\n to = bridgeTxDetails[transactionId].proofRelayer;\n } else if (bridgeTxDetails[transactionId].proofRelayer != msg.sender) {\n revert SenderIncorrect();\n }\n\n if (_timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003c= DISPUTE_PERIOD) {\n revert DisputePeriodNotPassed();\n }\n\n bridgeTxDetails[transactionId].status = BridgeStatus.RELAYER_CLAIMED;\n\n // update protocol fees if origin fee amount exists\n if (transaction.originFeeAmount \u003e 0) protocolFees[transaction.originToken] += transaction.originFeeAmount;\n\n // transfer origin collateral less fee to specified address\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositClaimed(transactionId, bridgeTxDetails[transactionId].proofRelayer, to, token, amount);\n }\n\n function bridgeStatuses(bytes32 transactionId) public view returns (BridgeStatus status) {\n return bridgeTxDetails[transactionId].status;\n }\n\n function bridgeProofs(bytes32 transactionId) public view returns (uint96 timestamp, address relayer) {\n timestamp = bridgeTxDetails[transactionId].proofBlockTimestamp;\n relayer = bridgeTxDetails[transactionId].proofRelayer;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeRelays(bytes32 transactionId) public view returns (bool) {\n // has this transactionId been relayed?\n return bridgeRelayDetails[transactionId].relayer != address(0);\n }\n\n /// @inheritdoc IFastBridgeV2\n function getBridgeTransactionV2(bytes memory request) public pure returns (BridgeTransactionV2 memory) {\n return abi.decode(request, (BridgeTransactionV2));\n }\n\n /// @notice Pulls a requested token from the user to this contract.\n function _pullToken(address token, uint256 amount) internal returns (uint256 amountPulled) {\n if (token == UniversalTokenLib.ETH_ADDRESS) {\n // For ETH we just need to check that the supplied msg.value is correct\n if (amount != msg.value) revert MsgValueIncorrect();\n amountPulled = msg.value;\n } else {\n token.assertIsContract();\n // Record token balance before transfer\n amountPulled = IERC20(token).balanceOf(address(this));\n // Token needs to be pulled only if msg.value is zero\n // This way user can specify WETH as the origin asset\n IERC20(token).safeTransferFrom(msg.sender, address(this), amount);\n // Use the difference between the recorded balance and the current balance as the amountPulled\n amountPulled = IERC20(token).balanceOf(address(this)) - amountPulled;\n }\n }\n\n /// @notice Calls the Recipient's hook function with the specified callParams and performs\n /// all the necessary checks for the returned value.\n function _checkedCallRecipient(\n address recipient,\n address token,\n uint256 amount,\n bytes memory callParams\n )\n internal\n {\n bytes memory hookData =\n abi.encodeCall(IFastBridgeRecipient.fastBridgeTransferReceived, (token, amount, callParams));\n // This will bubble any revert messages from the hook function\n bytes memory returnData = Address.functionCallWithValue({target: recipient, data: hookData, value: msg.value});\n // Explicit revert if no return data at all\n if (returnData.length == 0) revert RecipientNoReturnValue();\n // Check that exactly a single return value was returned\n if (returnData.length != 32) revert RecipientIncorrectReturnValue();\n // Return value should be abi-encoded hook function selector\n if (bytes32(returnData) != bytes32(IFastBridgeRecipient.fastBridgeTransferReceived.selector)) {\n revert RecipientIncorrectReturnValue();\n }\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint40(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint40).max but\n /// proof.timestamp \u003c type(uint40).max via unchecked statement\n /// @param proofBlockTimestamp The bridge proof block timestamp\n /// @return delta Time delta since proof submitted\n function _timeSince(uint40 proofBlockTimestamp) internal view returns (uint256 delta) {\n unchecked {\n delta = uint40(block.timestamp) - proofBlockTimestamp;\n }\n }\n\n /// @notice Performs all the necessary checks for a bridge to happen.\n /// @dev There's no good way to refactor this function to reduce cyclomatic complexity due to\n /// the number of checks that need to be performed, so we skip the code-complexity rule here.\n // solhint-disable-next-line code-complexity\n function _validateBridgeParams(\n BridgeParams memory params,\n BridgeParamsV2 memory paramsV2,\n int256 exclusivityEndTime\n )\n internal\n view\n {\n // Check V1 (legacy) params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.sender == address(0) || params.to == address(0)) revert ZeroAddress();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n // Check V2 params\n if (paramsV2.callParams.length \u003e MAX_CALL_PARAMS_LENGTH) revert CallParamsLengthAboveMax();\n if (paramsV2.callValue != 0 \u0026\u0026 params.destToken == UniversalTokenLib.ETH_ADDRESS) {\n revert NativeTokenCallValueNotSupported();\n }\n // exclusivityEndTime must be in range (0 .. params.deadline]\n if (exclusivityEndTime \u003c= 0 || exclusivityEndTime \u003e int256(params.deadline)) {\n revert ExclusivityParamsIncorrect();\n }\n }\n\n /// @notice Performs all the necessary checks for a relay to happen.\n function _validateRelayParams(\n BridgeTransactionV2 memory transaction,\n bytes32 transactionId,\n address relayer\n )\n internal\n view\n {\n if (relayer == address(0)) revert ZeroAddress();\n // Check if the transaction has already been relayed\n if (bridgeRelays(transactionId)) revert TransactionRelayed();\n if (transaction.destChainId != uint32(block.chainid)) revert ChainIncorrect();\n // Check the deadline for relay to happen\n if (block.timestamp \u003e transaction.deadline) revert DeadlineExceeded();\n // Check the exclusivity period, if it is still ongoing\n // forgefmt: disable-next-item\n if (\n transaction.exclusivityRelayer != address(0) \u0026\u0026\n transaction.exclusivityRelayer != relayer \u0026\u0026\n block.timestamp \u003c= transaction.exclusivityEndTime\n ) {\n revert ExclusivityPeriodNotPassed();\n }\n }\n}\n","language":"Solidity","languageVersion":"0.8.24","compilerVersion":"0.8.24","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../","srcMap":"","srcMapRuntime":"","abiDefinition":[{"inputs":[],"name":"DOMAIN_SEPARATOR","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"nonces","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"permit","outputs":[],"stateMutability":"nonpayable","type":"function"}],"userDoc":{"kind":"user","methods":{},"version":1},"developerDoc":{"details":"Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in https://eips.ethereum.org/EIPS/eip-2612[EIP-2612]. Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't need to send a transaction, and thus is not required to hold Ether at all. ==== Security Considerations There are two important considerations concerning the use of `permit`. The first is that a valid permit signature expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be considered as an intention to spend the allowance in any specific way. The second is that because permits have built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be generally recommended is: ```solidity function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public { try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {} doThing(..., value); } function doThing(..., uint256 value) public { token.safeTransferFrom(msg.sender, address(this), value); ... } ``` Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also {SafeERC20-safeTransferFrom}). Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so contracts should have entry points that don't rely on permit.","kind":"dev","methods":{"DOMAIN_SEPARATOR()":{"details":"Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}."},"nonces(address)":{"details":"Returns the current nonce for `owner`. This value must be included whenever a signature is generated for {permit}. Every successful call to {permit} increases ``owner``'s nonce by one. This prevents a signature from being used multiple times."},"permit(address,address,uint256,uint256,uint8,bytes32,bytes32)":{"details":"Sets `value` as the allowance of `spender` over ``owner``'s tokens, given ``owner``'s signed approval. IMPORTANT: The same issues {IERC20-approve} has related to transaction ordering also apply here. Emits an {Approval} event. Requirements: - `spender` cannot be the zero address. - `deadline` must be a timestamp in the future. - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner` over the EIP712-formatted function arguments. - the signature must use ``owner``'s current nonce (see {nonces}). For more information on the signature format, see the https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP section]. CAUTION: See Security Considerations above."}},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[],\"name\":\"DOMAIN_SEPARATOR\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"}],\"name\":\"nonces\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"},{\"internalType\":\"uint8\",\"name\":\"v\",\"type\":\"uint8\"},{\"internalType\":\"bytes32\",\"name\":\"r\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"s\",\"type\":\"bytes32\"}],\"name\":\"permit\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"details\":\"Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in https://eips.ethereum.org/EIPS/eip-2612[EIP-2612]. Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't need to send a transaction, and thus is not required to hold Ether at all. ==== Security Considerations There are two important considerations concerning the use of `permit`. The first is that a valid permit signature expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be considered as an intention to spend the allowance in any specific way. The second is that because permits have built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be generally recommended is: ```solidity function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public { try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {} doThing(..., value); } function doThing(..., uint256 value) public { token.safeTransferFrom(msg.sender, address(this), value); ... } ``` Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also {SafeERC20-safeTransferFrom}). Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so contracts should have entry points that don't rely on permit.\",\"kind\":\"dev\",\"methods\":{\"DOMAIN_SEPARATOR()\":{\"details\":\"Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\"},\"nonces(address)\":{\"details\":\"Returns the current nonce for `owner`. This value must be included whenever a signature is generated for {permit}. Every successful call to {permit} increases ``owner``'s nonce by one. This prevents a signature from being used multiple times.\"},\"permit(address,address,uint256,uint256,uint8,bytes32,bytes32)\":{\"details\":\"Sets `value` as the allowance of `spender` over ``owner``'s tokens, given ``owner``'s signed approval. IMPORTANT: The same issues {IERC20-approve} has related to transaction ordering also apply here. Emits an {Approval} event. Requirements: - `spender` cannot be the zero address. - `deadline` must be a timestamp in the future. - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner` over the EIP712-formatted function arguments. - the signature must use ``owner``'s current nonce (see {nonces}). For more information on the signature format, see the https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP section]. CAUTION: See Security Considerations above.\"}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeV2.sol\":\"IERC20Permit\"},\"evmVersion\":\"shanghai\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeV2.sol\":{\"keccak256\":\"0x7cd0f885e80e2bdaa638bc32ae7af7d2e248f99ce4b354c217d0f0f7d7302e0a\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://7ccf28df0bd7b4606986585acd8622ed9b4e81379690061bb66088f0a2270af1\",\"dweb:/ipfs/QmTf7HNdHZkK6vmx8ZgewycQEb72oLD9nPwBpsM5reMstQ\"]}},\"version\":1}"},"hashes":{"DOMAIN_SEPARATOR()":"3644e515","nonces(address)":"7ecebe00","permit(address,address,uint256,uint256,uint8,bytes32,bytes32)":"d505accf"}},"solidity/FastBridgeV2.sol:IFastBridge":{"code":"0x","runtime-code":"0x","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.24 ^0.8.0 ^0.8.20;\n\n// contracts/interfaces/IAdmin.sol\n\ninterface IAdmin {\n // ============ Events ============\n\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n event ChainGasAmountUpdated(uint256 oldChainGasAmount, uint256 newChainGasAmount);\n\n // ============ Methods ============\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n\n function setChainGasAmount(uint256 newChainGasAmount) external;\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IFastBridgeRecipient.sol\n\ninterface IFastBridgeRecipient {\n function fastBridgeTransferReceived(\n address token,\n uint256 amount,\n bytes memory callParams\n )\n external\n payable\n returns (bytes4);\n}\n\n// contracts/interfaces/IFastBridgeV2Errors.sol\n\ninterface IFastBridgeV2Errors {\n error AmountIncorrect();\n error CallParamsLengthAboveMax();\n error ChainIncorrect();\n error ExclusivityParamsIncorrect();\n error MsgValueIncorrect();\n error NativeTokenCallValueNotSupported();\n error SenderIncorrect();\n error StatusIncorrect();\n error ZeroAddress();\n\n error RecipientIncorrectReturnValue();\n error RecipientNoReturnValue();\n\n error DeadlineExceeded();\n error DeadlineNotExceeded();\n error DeadlineTooShort();\n error DisputePeriodNotPassed();\n error DisputePeriodPassed();\n error ExclusivityPeriodNotPassed();\n\n error TransactionRelayed();\n}\n\n// contracts/libs/Errors.sol\n\nerror DeadlineExceeded();\nerror DeadlineNotExceeded();\nerror DeadlineTooShort();\nerror InsufficientOutputAmount();\n\nerror MsgValueIncorrect();\nerror PoolNotFound();\nerror TokenAddressMismatch();\nerror TokenNotContract();\nerror TokenNotETH();\nerror TokensIdentical();\n\nerror ChainIncorrect();\nerror AmountIncorrect();\nerror ZeroAddress();\n\nerror DisputePeriodNotPassed();\nerror DisputePeriodPassed();\nerror SenderIncorrect();\nerror StatusIncorrect();\nerror TransactionIdIncorrect();\nerror TransactionRelayed();\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// contracts/interfaces/IFastBridgeV2.sol\n\ninterface IFastBridgeV2 is IFastBridge {\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n struct BridgeTxDetails {\n BridgeStatus status;\n uint40 proofBlockTimestamp;\n uint48 proofBlockNumber;\n address proofRelayer;\n }\n\n struct BridgeRelay {\n uint48 blockNumber;\n uint48 blockTimestamp;\n address relayer;\n }\n\n /// @notice New params introduced in the FastBridgeV2.\n /// We are passing fields from the older BridgeParams struct outside of this struct\n /// for backwards compatibility.\n /// Note: quoteRelayer and quoteExclusivitySeconds are either both zero (indicating no exclusivity)\n /// or both non-zero (indicating exclusivity for the given period).\n /// Note: callValue \u003e 0 can NOT be used with destToken = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE (ETH_ADDRESS)\n /// @param quoteRelayer Relayer that provided the quote for the transaction\n /// @param quoteExclusivitySeconds Period of time the quote relayer is guaranteed exclusivity after user's deposit\n /// @param quoteId Unique quote identifier used for tracking the quote\n /// @param callValue ETH value to send to the recipient (if any)\n /// @param callParams Parameters for the arbitrary call to the destination recipient (if any)\n struct BridgeParamsV2 {\n address quoteRelayer;\n int256 quoteExclusivitySeconds;\n bytes quoteId;\n uint256 callValue;\n bytes callParams;\n }\n\n /// @notice Updated bridge transaction struct to include parameters introduced in FastBridgeV2.\n /// Note: only `exclusivityRelayer` can fill such a transaction until `exclusivityEndTime`.\n /// TODO: consider changing the encoding scheme to prevent spending extra gas on decoding.\n struct BridgeTransactionV2 {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n uint256 callValue; // ETH value to send to the recipient (if any) - replaces V1's sendChainGas flag\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n address exclusivityRelayer;\n uint256 exclusivityEndTime;\n bytes callParams;\n }\n\n event BridgeQuoteDetails(bytes32 indexed transactionId, bytes quoteId);\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability\n /// to provide temporary exclusivity fill rights for the quote relayer.\n /// @param params The parameters required to bridge\n /// @param paramsV2 The parameters for exclusivity fill rights (optional, can be left empty)\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function relay(bytes memory request, address relayer) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param transactionId The transaction id associated with the encoded bridge transaction to prove\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital.\n /// @notice Can only send funds to the relayer address on the proof.\n /// @param request The encoded bridge transaction to claim on origin chain\n function claim(bytes memory request) external;\n /// @notice Checks if a transaction has been relayed\n /// @param transactionId The ID of the transaction to check\n /// @return True if the transaction has been relayed, false otherwise\n function bridgeRelays(bytes32 transactionId) external view returns (bool);\n\n /// @notice Returns the status of a bridge transaction\n /// @param transactionId The ID of the bridge transaction\n /// @return BridgeStatus Status of the bridge transaction\n function bridgeStatuses(bytes32 transactionId) external view returns (BridgeStatus);\n\n /// @notice Returns the timestamp and relayer of a bridge proof\n /// @param transactionId The ID of the bridge transaction\n /// @return timestamp The timestamp of the bridge proof\n /// @return relayer The relayer address of the bridge proof\n function bridgeProofs(bytes32 transactionId) external view returns (uint96 timestamp, address relayer);\n\n /// @notice Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\n /// @param request The bridge request to decode\n function getBridgeTransactionV2(bytes memory request) external view returns (BridgeTransactionV2 memory);\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// contracts/libs/UniversalToken.sol\n\nlibrary UniversalTokenLib {\n using SafeERC20 for IERC20;\n\n address internal constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Transfers tokens to the given account. Reverts if transfer is not successful.\n /// @dev This might trigger fallback, if ETH is transferred to the contract.\n /// Make sure this can not lead to reentrancy attacks.\n function universalTransfer(address token, address to, uint256 value) internal {\n // Don't do anything, if need to send tokens to this address\n if (to == address(this)) return;\n // Don't do anything, if trying to send zero value\n if (value == 0) return;\n if (token == ETH_ADDRESS) {\n /// @dev Note: this can potentially lead to executing code in `to`.\n // solhint-disable-next-line avoid-low-level-calls\n (bool success,) = to.call{value: value}(\"\");\n require(success, \"ETH transfer failed\");\n } else {\n IERC20(token).safeTransfer(to, value);\n }\n }\n\n /// @notice Issues an infinite allowance to the spender, if the current allowance is insufficient\n /// to spend the given amount.\n function universalApproveInfinity(address token, address spender, uint256 amountToSpend) internal {\n // ETH Chad doesn't require your approval\n if (token == ETH_ADDRESS) return;\n // No-op if allowance is already sufficient\n uint256 allowance = IERC20(token).allowance(address(this), spender);\n if (allowance \u003e= amountToSpend) return;\n // Otherwise, reset approval to 0 and set to max allowance\n if (allowance \u003e 0) IERC20(token).safeDecreaseAllowance(spender, allowance);\n IERC20(token).safeIncreaseAllowance(spender, type(uint256).max);\n }\n\n /// @notice Returns the balance of the given token (or native ETH) for the given account.\n function universalBalanceOf(address token, address account) internal view returns (uint256) {\n if (token == ETH_ADDRESS) {\n return account.balance;\n } else {\n return IERC20(token).balanceOf(account);\n }\n }\n\n /// @dev Checks that token is a contract and not ETH_ADDRESS.\n function assertIsContract(address token) internal view {\n // Check that ETH_ADDRESS was not used (in case this is a predeploy on any of the chains)\n if (token == UniversalTokenLib.ETH_ADDRESS) revert TokenNotContract();\n // Check that token is not an EOA\n if (token.code.length == 0) revert TokenNotContract();\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/Admin.sol\n\ncontract Admin is IAdmin, AccessControlEnumerable {\n using UniversalTokenLib for address;\n\n bytes32 public constant RELAYER_ROLE = keccak256(\"RELAYER_ROLE\");\n bytes32 public constant REFUNDER_ROLE = keccak256(\"REFUNDER_ROLE\");\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n uint256 public constant FEE_BPS = 1e6;\n uint256 public constant FEE_RATE_MAX = 0.01e6; // max 1% on origin amount\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Chain gas amount to forward as rebate if requested\n uint256 public chainGasAmount;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n }\n\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n require(newFeeRate \u003c= FEE_RATE_MAX, \"newFeeRate \u003e max\");\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n token.universalTransfer(recipient, feeAmount);\n emit FeesSwept(token, recipient, feeAmount);\n }\n\n function setChainGasAmount(uint256 newChainGasAmount) external onlyRole(GOVERNOR_ROLE) {\n uint256 oldChainGasAmount = chainGasAmount;\n chainGasAmount = newChainGasAmount;\n emit ChainGasAmountUpdated(oldChainGasAmount, newChainGasAmount);\n }\n}\n\n// contracts/FastBridgeV2.sol\n\n/// @notice FastBridgeV2 is a contract for bridging tokens across chains.\ncontract FastBridgeV2 is Admin, IFastBridgeV2, IFastBridgeV2Errors {\n using SafeERC20 for IERC20;\n using UniversalTokenLib for address;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Delay for a transaction after which it could be permisionlessly refunded\n uint256 public constant REFUND_DELAY = 7 days;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n /// @notice Maximum length of accepted callParams\n uint256 public constant MAX_CALL_PARAMS_LENGTH = 2 ** 16 - 1;\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeTxDetails) public bridgeTxDetails;\n /// @notice Relay details on destination chain\n mapping(bytes32 =\u003e BridgeRelay) public bridgeRelayDetails;\n /// @notice Unique bridge nonces tracked per originSender\n mapping(address =\u003e uint256) public senderNonces;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Replaced by senderNonces\n uint256 public immutable nonce = 0;\n /// @notice the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n bridge({\n params: params,\n paramsV2: BridgeParamsV2({\n quoteRelayer: address(0),\n quoteExclusivitySeconds: 0,\n quoteId: bytes(\"\"),\n callValue: 0,\n callParams: bytes(\"\")\n })\n });\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes memory request) external payable {\n relay({request: request, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes memory request, bytes32 destTxHash) external {\n prove({transactionId: keccak256(request), destTxHash: destTxHash, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridgeV2\n function claim(bytes memory request) external {\n claim({request: request, to: address(0)});\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003e DISPUTE_PERIOD) {\n revert DisputePeriodPassed();\n }\n\n // @dev relayer gets slashed effectively if dest relay has gone thru\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n bridgeTxDetails[transactionId].proofRelayer = address(0);\n bridgeTxDetails[transactionId].proofBlockTimestamp = 0;\n bridgeTxDetails[transactionId].proofBlockNumber = 0;\n\n emit BridgeProofDisputed(transactionId, msg.sender);\n }\n\n /// @inheritdoc IFastBridge\n function refund(bytes memory request) external {\n bytes32 transactionId = keccak256(request);\n\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n\n if (bridgeTxDetails[transactionId].status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n\n if (hasRole(REFUNDER_ROLE, msg.sender)) {\n // Refunder can refund if deadline has passed\n if (block.timestamp \u003c= transaction.deadline) revert DeadlineNotExceeded();\n } else {\n // Permissionless refund is allowed after REFUND_DELAY\n if (block.timestamp \u003c= transaction.deadline + REFUND_DELAY) revert DeadlineNotExceeded();\n }\n\n // if all checks passed, set to REFUNDED status\n bridgeTxDetails[transactionId].status = BridgeStatus.REFUNDED;\n\n // transfer origin collateral back to original sender\n address to = transaction.originSender;\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount + transaction.originFeeAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (bridgeTxDetails[transactionId].proofRelayer != relayer) revert SenderIncorrect();\n return _timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n /// @dev This method is added to achieve backwards compatibility with decoding requests into V1 structs:\n /// - `callValue` is partially reported as a zero/non-zero flag\n /// - `callParams` is ignored\n /// In order to process all kinds of requests use getBridgeTransactionV2 instead.\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory) {\n // Try decoding into V2 struct first. This will revert if V1 struct is passed\n try this.getBridgeTransactionV2(request) returns (BridgeTransactionV2 memory txV2) {\n // Note: we entirely ignore the callParams field, as it was not present in V1\n return BridgeTransaction({\n originChainId: txV2.originChainId,\n destChainId: txV2.destChainId,\n originSender: txV2.originSender,\n destRecipient: txV2.destRecipient,\n originToken: txV2.originToken,\n destToken: txV2.destToken,\n originAmount: txV2.originAmount,\n destAmount: txV2.destAmount,\n originFeeAmount: txV2.originFeeAmount,\n sendChainGas: txV2.callValue != 0,\n deadline: txV2.deadline,\n nonce: txV2.nonce\n });\n } catch {\n // Fallback to V1 struct\n return abi.decode(request, (BridgeTransaction));\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) public payable {\n int256 exclusivityEndTime = int256(block.timestamp) + paramsV2.quoteExclusivitySeconds;\n _validateBridgeParams(params, paramsV2, exclusivityEndTime);\n\n // transfer tokens to bridge contract\n /// @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _pullToken(params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n\n // set status to requested\n bytes memory request = abi.encode(\n BridgeTransactionV2({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n callValue: paramsV2.callValue,\n deadline: params.deadline,\n nonce: senderNonces[params.sender]++, // increment nonce on every bridge\n exclusivityRelayer: paramsV2.quoteRelayer,\n // We checked exclusivityEndTime to be in range (0 .. params.deadline] above, so can safely cast\n exclusivityEndTime: uint256(exclusivityEndTime),\n callParams: paramsV2.callParams\n })\n );\n bytes32 transactionId = keccak256(request);\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n\n emit BridgeRequested({\n transactionId: transactionId,\n sender: params.sender,\n request: request,\n destChainId: params.dstChainId,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n sendChainGas: paramsV2.callValue != 0\n });\n emit BridgeQuoteDetails(transactionId, paramsV2.quoteId);\n }\n\n /// @inheritdoc IFastBridgeV2\n function relay(bytes memory request, address relayer) public payable {\n bytes32 transactionId = keccak256(request);\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n _validateRelayParams(transaction, transactionId, relayer);\n // mark bridge transaction as relayed\n bridgeRelayDetails[transactionId] =\n BridgeRelay({blockNumber: uint48(block.number), blockTimestamp: uint48(block.timestamp), relayer: relayer});\n\n // transfer tokens to recipient on destination chain and do an arbitrary call if requested\n address to = transaction.destRecipient;\n address token = transaction.destToken;\n uint256 amount = transaction.destAmount;\n\n // All state changes have been done at this point, can proceed to the external calls.\n // This follows the checks-effects-interactions pattern to mitigate potential reentrancy attacks.\n if (token == UniversalTokenLib.ETH_ADDRESS) {\n // For ETH non-zero callValue is not allowed\n if (transaction.callValue != 0) revert NativeTokenCallValueNotSupported();\n // Check that the correct msg.value was sent\n if (msg.value != amount) revert MsgValueIncorrect();\n } else {\n // For ERC20s, we check that the correct msg.value was sent\n if (msg.value != transaction.callValue) revert MsgValueIncorrect();\n // We need to transfer the tokens from the Relayer to the recipient first before performing an\n // optional post-transfer arbitrary call.\n IERC20(token).safeTransferFrom(msg.sender, to, amount);\n }\n\n if (transaction.callParams.length != 0) {\n // Arbitrary call requested, perform it while supplying full msg.value to the recipient\n // Note: if token has a fee on transfers, the recipient will have received less than `amount`.\n // This is a very niche edge case and should be handled by the recipient contract.\n _checkedCallRecipient({recipient: to, token: token, amount: amount, callParams: transaction.callParams});\n } else if (msg.value != 0) {\n // No arbitrary call requested, but msg.value was sent. This is either a relay with ETH,\n // or a non-zero callValue request with an ERC20. In both cases, transfer the ETH to the recipient.\n Address.sendValue(payable(to), msg.value);\n }\n\n emit BridgeRelayed({\n transactionId: transactionId,\n relayer: relayer,\n to: to,\n originChainId: transaction.originChainId,\n originToken: transaction.originToken,\n destToken: transaction.destToken,\n originAmount: transaction.originAmount,\n destAmount: transaction.destAmount,\n chainGasAmount: transaction.callValue\n });\n }\n\n /// @inheritdoc IFastBridgeV2\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) public onlyRole(RELAYER_ROLE) {\n // update bridge tx status given proof provided\n if (bridgeTxDetails[transactionId].status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n bridgeTxDetails[transactionId].status = BridgeStatus.RELAYER_PROVED;\n bridgeTxDetails[transactionId].proofBlockTimestamp = uint40(block.timestamp);\n bridgeTxDetails[transactionId].proofBlockNumber = uint48(block.number);\n bridgeTxDetails[transactionId].proofRelayer = relayer;\n\n emit BridgeProofProvided(transactionId, relayer, destTxHash);\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes memory request, address to) public {\n bytes32 transactionId = keccak256(request);\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n\n // update bridge tx status if able to claim origin collateral\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n\n // if \"to\" is zero addr, permissionlessly send funds to proven relayer\n if (to == address(0)) {\n to = bridgeTxDetails[transactionId].proofRelayer;\n } else if (bridgeTxDetails[transactionId].proofRelayer != msg.sender) {\n revert SenderIncorrect();\n }\n\n if (_timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003c= DISPUTE_PERIOD) {\n revert DisputePeriodNotPassed();\n }\n\n bridgeTxDetails[transactionId].status = BridgeStatus.RELAYER_CLAIMED;\n\n // update protocol fees if origin fee amount exists\n if (transaction.originFeeAmount \u003e 0) protocolFees[transaction.originToken] += transaction.originFeeAmount;\n\n // transfer origin collateral less fee to specified address\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositClaimed(transactionId, bridgeTxDetails[transactionId].proofRelayer, to, token, amount);\n }\n\n function bridgeStatuses(bytes32 transactionId) public view returns (BridgeStatus status) {\n return bridgeTxDetails[transactionId].status;\n }\n\n function bridgeProofs(bytes32 transactionId) public view returns (uint96 timestamp, address relayer) {\n timestamp = bridgeTxDetails[transactionId].proofBlockTimestamp;\n relayer = bridgeTxDetails[transactionId].proofRelayer;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeRelays(bytes32 transactionId) public view returns (bool) {\n // has this transactionId been relayed?\n return bridgeRelayDetails[transactionId].relayer != address(0);\n }\n\n /// @inheritdoc IFastBridgeV2\n function getBridgeTransactionV2(bytes memory request) public pure returns (BridgeTransactionV2 memory) {\n return abi.decode(request, (BridgeTransactionV2));\n }\n\n /// @notice Pulls a requested token from the user to this contract.\n function _pullToken(address token, uint256 amount) internal returns (uint256 amountPulled) {\n if (token == UniversalTokenLib.ETH_ADDRESS) {\n // For ETH we just need to check that the supplied msg.value is correct\n if (amount != msg.value) revert MsgValueIncorrect();\n amountPulled = msg.value;\n } else {\n token.assertIsContract();\n // Record token balance before transfer\n amountPulled = IERC20(token).balanceOf(address(this));\n // Token needs to be pulled only if msg.value is zero\n // This way user can specify WETH as the origin asset\n IERC20(token).safeTransferFrom(msg.sender, address(this), amount);\n // Use the difference between the recorded balance and the current balance as the amountPulled\n amountPulled = IERC20(token).balanceOf(address(this)) - amountPulled;\n }\n }\n\n /// @notice Calls the Recipient's hook function with the specified callParams and performs\n /// all the necessary checks for the returned value.\n function _checkedCallRecipient(\n address recipient,\n address token,\n uint256 amount,\n bytes memory callParams\n )\n internal\n {\n bytes memory hookData =\n abi.encodeCall(IFastBridgeRecipient.fastBridgeTransferReceived, (token, amount, callParams));\n // This will bubble any revert messages from the hook function\n bytes memory returnData = Address.functionCallWithValue({target: recipient, data: hookData, value: msg.value});\n // Explicit revert if no return data at all\n if (returnData.length == 0) revert RecipientNoReturnValue();\n // Check that exactly a single return value was returned\n if (returnData.length != 32) revert RecipientIncorrectReturnValue();\n // Return value should be abi-encoded hook function selector\n if (bytes32(returnData) != bytes32(IFastBridgeRecipient.fastBridgeTransferReceived.selector)) {\n revert RecipientIncorrectReturnValue();\n }\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint40(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint40).max but\n /// proof.timestamp \u003c type(uint40).max via unchecked statement\n /// @param proofBlockTimestamp The bridge proof block timestamp\n /// @return delta Time delta since proof submitted\n function _timeSince(uint40 proofBlockTimestamp) internal view returns (uint256 delta) {\n unchecked {\n delta = uint40(block.timestamp) - proofBlockTimestamp;\n }\n }\n\n /// @notice Performs all the necessary checks for a bridge to happen.\n /// @dev There's no good way to refactor this function to reduce cyclomatic complexity due to\n /// the number of checks that need to be performed, so we skip the code-complexity rule here.\n // solhint-disable-next-line code-complexity\n function _validateBridgeParams(\n BridgeParams memory params,\n BridgeParamsV2 memory paramsV2,\n int256 exclusivityEndTime\n )\n internal\n view\n {\n // Check V1 (legacy) params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.sender == address(0) || params.to == address(0)) revert ZeroAddress();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n // Check V2 params\n if (paramsV2.callParams.length \u003e MAX_CALL_PARAMS_LENGTH) revert CallParamsLengthAboveMax();\n if (paramsV2.callValue != 0 \u0026\u0026 params.destToken == UniversalTokenLib.ETH_ADDRESS) {\n revert NativeTokenCallValueNotSupported();\n }\n // exclusivityEndTime must be in range (0 .. params.deadline]\n if (exclusivityEndTime \u003c= 0 || exclusivityEndTime \u003e int256(params.deadline)) {\n revert ExclusivityParamsIncorrect();\n }\n }\n\n /// @notice Performs all the necessary checks for a relay to happen.\n function _validateRelayParams(\n BridgeTransactionV2 memory transaction,\n bytes32 transactionId,\n address relayer\n )\n internal\n view\n {\n if (relayer == address(0)) revert ZeroAddress();\n // Check if the transaction has already been relayed\n if (bridgeRelays(transactionId)) revert TransactionRelayed();\n if (transaction.destChainId != uint32(block.chainid)) revert ChainIncorrect();\n // Check the deadline for relay to happen\n if (block.timestamp \u003e transaction.deadline) revert DeadlineExceeded();\n // Check the exclusivity period, if it is still ongoing\n // forgefmt: disable-next-item\n if (\n transaction.exclusivityRelayer != address(0) \u0026\u0026\n transaction.exclusivityRelayer != relayer \u0026\u0026\n block.timestamp \u003c= transaction.exclusivityEndTime\n ) {\n revert ExclusivityPeriodNotPassed();\n }\n }\n}\n","language":"Solidity","languageVersion":"0.8.24","compilerVersion":"0.8.24","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../","srcMap":"","srcMapRuntime":"","abiDefinition":[{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"relayer","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"BridgeDepositClaimed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"BridgeDepositRefunded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"relayer","type":"address"}],"name":"BridgeProofDisputed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"relayer","type":"address"},{"indexed":false,"internalType":"bytes32","name":"transactionHash","type":"bytes32"}],"name":"BridgeProofProvided","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"relayer","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint32","name":"originChainId","type":"uint32"},{"indexed":false,"internalType":"address","name":"originToken","type":"address"},{"indexed":false,"internalType":"address","name":"destToken","type":"address"},{"indexed":false,"internalType":"uint256","name":"originAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"destAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"chainGasAmount","type":"uint256"}],"name":"BridgeRelayed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"bytes","name":"request","type":"bytes"},{"indexed":false,"internalType":"uint32","name":"destChainId","type":"uint32"},{"indexed":false,"internalType":"address","name":"originToken","type":"address"},{"indexed":false,"internalType":"address","name":"destToken","type":"address"},{"indexed":false,"internalType":"uint256","name":"originAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"destAmount","type":"uint256"},{"indexed":false,"internalType":"bool","name":"sendChainGas","type":"bool"}],"name":"BridgeRequested","type":"event"},{"inputs":[{"components":[{"internalType":"uint32","name":"dstChainId","type":"uint32"},{"internalType":"address","name":"sender","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"address","name":"originToken","type":"address"},{"internalType":"address","name":"destToken","type":"address"},{"internalType":"uint256","name":"originAmount","type":"uint256"},{"internalType":"uint256","name":"destAmount","type":"uint256"},{"internalType":"bool","name":"sendChainGas","type":"bool"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"internalType":"struct IFastBridge.BridgeParams","name":"params","type":"tuple"}],"name":"bridge","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"internalType":"address","name":"relayer","type":"address"}],"name":"canClaim","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"},{"internalType":"address","name":"to","type":"address"}],"name":"claim","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"transactionId","type":"bytes32"}],"name":"dispute","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"}],"name":"getBridgeTransaction","outputs":[{"components":[{"internalType":"uint32","name":"originChainId","type":"uint32"},{"internalType":"uint32","name":"destChainId","type":"uint32"},{"internalType":"address","name":"originSender","type":"address"},{"internalType":"address","name":"destRecipient","type":"address"},{"internalType":"address","name":"originToken","type":"address"},{"internalType":"address","name":"destToken","type":"address"},{"internalType":"uint256","name":"originAmount","type":"uint256"},{"internalType":"uint256","name":"destAmount","type":"uint256"},{"internalType":"uint256","name":"originFeeAmount","type":"uint256"},{"internalType":"bool","name":"sendChainGas","type":"bool"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint256","name":"nonce","type":"uint256"}],"internalType":"struct IFastBridge.BridgeTransaction","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"},{"internalType":"bytes32","name":"destTxHash","type":"bytes32"}],"name":"prove","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"}],"name":"refund","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"}],"name":"relay","outputs":[],"stateMutability":"payable","type":"function"}],"userDoc":{"kind":"user","methods":{"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256))":{"notice":"Initiates bridge on origin chain to be relayed by off-chain relayer"},"canClaim(bytes32,address)":{"notice":"Checks if the dispute period has passed so bridge deposit can be claimed"},"claim(bytes,address)":{"notice":"Completes bridge transaction on origin chain by claiming originally deposited capital"},"dispute(bytes32)":{"notice":"Disputes an outstanding proof in case relayer provided dest chain tx is invalid"},"getBridgeTransaction(bytes)":{"notice":"Decodes bridge request into a bridge transaction"},"prove(bytes,bytes32)":{"notice":"Provides proof on origin side that relayer provided funds on destination side of bridge transaction"},"refund(bytes)":{"notice":"Refunds an outstanding bridge transaction in case optimistic bridging failed"},"relay(bytes)":{"notice":"Relays destination side of bridge transaction by off-chain relayer"}},"version":1},"developerDoc":{"kind":"dev","methods":{"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256))":{"params":{"params":"The parameters required to bridge"}},"canClaim(bytes32,address)":{"params":{"relayer":"The address of the relayer attempting to claim","transactionId":"The transaction id associated with the encoded bridge transaction to check"}},"claim(bytes,address)":{"params":{"request":"The encoded bridge transaction to claim on origin chain","to":"The recipient address of the funds"}},"dispute(bytes32)":{"params":{"transactionId":"The transaction id associated with the encoded bridge transaction to dispute"}},"getBridgeTransaction(bytes)":{"params":{"request":"The bridge request to decode"}},"prove(bytes,bytes32)":{"params":{"destTxHash":"The destination tx hash proving bridge transaction was relayed","request":"The encoded bridge transaction to prove on origin chain"}},"refund(bytes)":{"params":{"request":"The encoded bridge transaction to refund"}},"relay(bytes)":{"params":{"request":"The encoded bridge transaction to relay on destination chain"}}},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"BridgeDepositClaimed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"BridgeDepositRefunded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"name\":\"BridgeProofDisputed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"transactionHash\",\"type\":\"bytes32\"}],\"name\":\"BridgeProofProvided\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"originChainId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"chainGasAmount\",\"type\":\"uint256\"}],\"name\":\"BridgeRelayed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"destChainId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"sendChainGas\",\"type\":\"bool\"}],\"name\":\"BridgeRequested\",\"type\":\"event\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"dstChainId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"sendChainGas\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"}],\"internalType\":\"struct IFastBridge.BridgeParams\",\"name\":\"params\",\"type\":\"tuple\"}],\"name\":\"bridge\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"name\":\"canClaim\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"claim\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"}],\"name\":\"dispute\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"getBridgeTransaction\",\"outputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"originChainId\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"destChainId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"originSender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destRecipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"originFeeAmount\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"sendChainGas\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"}],\"internalType\":\"struct IFastBridge.BridgeTransaction\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"},{\"internalType\":\"bytes32\",\"name\":\"destTxHash\",\"type\":\"bytes32\"}],\"name\":\"prove\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"refund\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"relay\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{\"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256))\":{\"params\":{\"params\":\"The parameters required to bridge\"}},\"canClaim(bytes32,address)\":{\"params\":{\"relayer\":\"The address of the relayer attempting to claim\",\"transactionId\":\"The transaction id associated with the encoded bridge transaction to check\"}},\"claim(bytes,address)\":{\"params\":{\"request\":\"The encoded bridge transaction to claim on origin chain\",\"to\":\"The recipient address of the funds\"}},\"dispute(bytes32)\":{\"params\":{\"transactionId\":\"The transaction id associated with the encoded bridge transaction to dispute\"}},\"getBridgeTransaction(bytes)\":{\"params\":{\"request\":\"The bridge request to decode\"}},\"prove(bytes,bytes32)\":{\"params\":{\"destTxHash\":\"The destination tx hash proving bridge transaction was relayed\",\"request\":\"The encoded bridge transaction to prove on origin chain\"}},\"refund(bytes)\":{\"params\":{\"request\":\"The encoded bridge transaction to refund\"}},\"relay(bytes)\":{\"params\":{\"request\":\"The encoded bridge transaction to relay on destination chain\"}}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256))\":{\"notice\":\"Initiates bridge on origin chain to be relayed by off-chain relayer\"},\"canClaim(bytes32,address)\":{\"notice\":\"Checks if the dispute period has passed so bridge deposit can be claimed\"},\"claim(bytes,address)\":{\"notice\":\"Completes bridge transaction on origin chain by claiming originally deposited capital\"},\"dispute(bytes32)\":{\"notice\":\"Disputes an outstanding proof in case relayer provided dest chain tx is invalid\"},\"getBridgeTransaction(bytes)\":{\"notice\":\"Decodes bridge request into a bridge transaction\"},\"prove(bytes,bytes32)\":{\"notice\":\"Provides proof on origin side that relayer provided funds on destination side of bridge transaction\"},\"refund(bytes)\":{\"notice\":\"Refunds an outstanding bridge transaction in case optimistic bridging failed\"},\"relay(bytes)\":{\"notice\":\"Relays destination side of bridge transaction by off-chain relayer\"}},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeV2.sol\":\"IFastBridge\"},\"evmVersion\":\"shanghai\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeV2.sol\":{\"keccak256\":\"0x7cd0f885e80e2bdaa638bc32ae7af7d2e248f99ce4b354c217d0f0f7d7302e0a\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://7ccf28df0bd7b4606986585acd8622ed9b4e81379690061bb66088f0a2270af1\",\"dweb:/ipfs/QmTf7HNdHZkK6vmx8ZgewycQEb72oLD9nPwBpsM5reMstQ\"]}},\"version\":1}"},"hashes":{"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256))":"45851694","canClaim(bytes32,address)":"aa9641ab","claim(bytes,address)":"41fcb612","dispute(bytes32)":"add98c70","getBridgeTransaction(bytes)":"ac11fb1a","prove(bytes,bytes32)":"886d36ff","refund(bytes)":"5eb7d946","relay(bytes)":"8f0d6f17"}},"solidity/FastBridgeV2.sol:IFastBridgeRecipient":{"code":"0x","runtime-code":"0x","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.24 ^0.8.0 ^0.8.20;\n\n// contracts/interfaces/IAdmin.sol\n\ninterface IAdmin {\n // ============ Events ============\n\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n event ChainGasAmountUpdated(uint256 oldChainGasAmount, uint256 newChainGasAmount);\n\n // ============ Methods ============\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n\n function setChainGasAmount(uint256 newChainGasAmount) external;\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IFastBridgeRecipient.sol\n\ninterface IFastBridgeRecipient {\n function fastBridgeTransferReceived(\n address token,\n uint256 amount,\n bytes memory callParams\n )\n external\n payable\n returns (bytes4);\n}\n\n// contracts/interfaces/IFastBridgeV2Errors.sol\n\ninterface IFastBridgeV2Errors {\n error AmountIncorrect();\n error CallParamsLengthAboveMax();\n error ChainIncorrect();\n error ExclusivityParamsIncorrect();\n error MsgValueIncorrect();\n error NativeTokenCallValueNotSupported();\n error SenderIncorrect();\n error StatusIncorrect();\n error ZeroAddress();\n\n error RecipientIncorrectReturnValue();\n error RecipientNoReturnValue();\n\n error DeadlineExceeded();\n error DeadlineNotExceeded();\n error DeadlineTooShort();\n error DisputePeriodNotPassed();\n error DisputePeriodPassed();\n error ExclusivityPeriodNotPassed();\n\n error TransactionRelayed();\n}\n\n// contracts/libs/Errors.sol\n\nerror DeadlineExceeded();\nerror DeadlineNotExceeded();\nerror DeadlineTooShort();\nerror InsufficientOutputAmount();\n\nerror MsgValueIncorrect();\nerror PoolNotFound();\nerror TokenAddressMismatch();\nerror TokenNotContract();\nerror TokenNotETH();\nerror TokensIdentical();\n\nerror ChainIncorrect();\nerror AmountIncorrect();\nerror ZeroAddress();\n\nerror DisputePeriodNotPassed();\nerror DisputePeriodPassed();\nerror SenderIncorrect();\nerror StatusIncorrect();\nerror TransactionIdIncorrect();\nerror TransactionRelayed();\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// contracts/interfaces/IFastBridgeV2.sol\n\ninterface IFastBridgeV2 is IFastBridge {\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n struct BridgeTxDetails {\n BridgeStatus status;\n uint40 proofBlockTimestamp;\n uint48 proofBlockNumber;\n address proofRelayer;\n }\n\n struct BridgeRelay {\n uint48 blockNumber;\n uint48 blockTimestamp;\n address relayer;\n }\n\n /// @notice New params introduced in the FastBridgeV2.\n /// We are passing fields from the older BridgeParams struct outside of this struct\n /// for backwards compatibility.\n /// Note: quoteRelayer and quoteExclusivitySeconds are either both zero (indicating no exclusivity)\n /// or both non-zero (indicating exclusivity for the given period).\n /// Note: callValue \u003e 0 can NOT be used with destToken = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE (ETH_ADDRESS)\n /// @param quoteRelayer Relayer that provided the quote for the transaction\n /// @param quoteExclusivitySeconds Period of time the quote relayer is guaranteed exclusivity after user's deposit\n /// @param quoteId Unique quote identifier used for tracking the quote\n /// @param callValue ETH value to send to the recipient (if any)\n /// @param callParams Parameters for the arbitrary call to the destination recipient (if any)\n struct BridgeParamsV2 {\n address quoteRelayer;\n int256 quoteExclusivitySeconds;\n bytes quoteId;\n uint256 callValue;\n bytes callParams;\n }\n\n /// @notice Updated bridge transaction struct to include parameters introduced in FastBridgeV2.\n /// Note: only `exclusivityRelayer` can fill such a transaction until `exclusivityEndTime`.\n /// TODO: consider changing the encoding scheme to prevent spending extra gas on decoding.\n struct BridgeTransactionV2 {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n uint256 callValue; // ETH value to send to the recipient (if any) - replaces V1's sendChainGas flag\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n address exclusivityRelayer;\n uint256 exclusivityEndTime;\n bytes callParams;\n }\n\n event BridgeQuoteDetails(bytes32 indexed transactionId, bytes quoteId);\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability\n /// to provide temporary exclusivity fill rights for the quote relayer.\n /// @param params The parameters required to bridge\n /// @param paramsV2 The parameters for exclusivity fill rights (optional, can be left empty)\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function relay(bytes memory request, address relayer) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param transactionId The transaction id associated with the encoded bridge transaction to prove\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital.\n /// @notice Can only send funds to the relayer address on the proof.\n /// @param request The encoded bridge transaction to claim on origin chain\n function claim(bytes memory request) external;\n /// @notice Checks if a transaction has been relayed\n /// @param transactionId The ID of the transaction to check\n /// @return True if the transaction has been relayed, false otherwise\n function bridgeRelays(bytes32 transactionId) external view returns (bool);\n\n /// @notice Returns the status of a bridge transaction\n /// @param transactionId The ID of the bridge transaction\n /// @return BridgeStatus Status of the bridge transaction\n function bridgeStatuses(bytes32 transactionId) external view returns (BridgeStatus);\n\n /// @notice Returns the timestamp and relayer of a bridge proof\n /// @param transactionId The ID of the bridge transaction\n /// @return timestamp The timestamp of the bridge proof\n /// @return relayer The relayer address of the bridge proof\n function bridgeProofs(bytes32 transactionId) external view returns (uint96 timestamp, address relayer);\n\n /// @notice Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\n /// @param request The bridge request to decode\n function getBridgeTransactionV2(bytes memory request) external view returns (BridgeTransactionV2 memory);\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// contracts/libs/UniversalToken.sol\n\nlibrary UniversalTokenLib {\n using SafeERC20 for IERC20;\n\n address internal constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Transfers tokens to the given account. Reverts if transfer is not successful.\n /// @dev This might trigger fallback, if ETH is transferred to the contract.\n /// Make sure this can not lead to reentrancy attacks.\n function universalTransfer(address token, address to, uint256 value) internal {\n // Don't do anything, if need to send tokens to this address\n if (to == address(this)) return;\n // Don't do anything, if trying to send zero value\n if (value == 0) return;\n if (token == ETH_ADDRESS) {\n /// @dev Note: this can potentially lead to executing code in `to`.\n // solhint-disable-next-line avoid-low-level-calls\n (bool success,) = to.call{value: value}(\"\");\n require(success, \"ETH transfer failed\");\n } else {\n IERC20(token).safeTransfer(to, value);\n }\n }\n\n /// @notice Issues an infinite allowance to the spender, if the current allowance is insufficient\n /// to spend the given amount.\n function universalApproveInfinity(address token, address spender, uint256 amountToSpend) internal {\n // ETH Chad doesn't require your approval\n if (token == ETH_ADDRESS) return;\n // No-op if allowance is already sufficient\n uint256 allowance = IERC20(token).allowance(address(this), spender);\n if (allowance \u003e= amountToSpend) return;\n // Otherwise, reset approval to 0 and set to max allowance\n if (allowance \u003e 0) IERC20(token).safeDecreaseAllowance(spender, allowance);\n IERC20(token).safeIncreaseAllowance(spender, type(uint256).max);\n }\n\n /// @notice Returns the balance of the given token (or native ETH) for the given account.\n function universalBalanceOf(address token, address account) internal view returns (uint256) {\n if (token == ETH_ADDRESS) {\n return account.balance;\n } else {\n return IERC20(token).balanceOf(account);\n }\n }\n\n /// @dev Checks that token is a contract and not ETH_ADDRESS.\n function assertIsContract(address token) internal view {\n // Check that ETH_ADDRESS was not used (in case this is a predeploy on any of the chains)\n if (token == UniversalTokenLib.ETH_ADDRESS) revert TokenNotContract();\n // Check that token is not an EOA\n if (token.code.length == 0) revert TokenNotContract();\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/Admin.sol\n\ncontract Admin is IAdmin, AccessControlEnumerable {\n using UniversalTokenLib for address;\n\n bytes32 public constant RELAYER_ROLE = keccak256(\"RELAYER_ROLE\");\n bytes32 public constant REFUNDER_ROLE = keccak256(\"REFUNDER_ROLE\");\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n uint256 public constant FEE_BPS = 1e6;\n uint256 public constant FEE_RATE_MAX = 0.01e6; // max 1% on origin amount\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Chain gas amount to forward as rebate if requested\n uint256 public chainGasAmount;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n }\n\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n require(newFeeRate \u003c= FEE_RATE_MAX, \"newFeeRate \u003e max\");\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n token.universalTransfer(recipient, feeAmount);\n emit FeesSwept(token, recipient, feeAmount);\n }\n\n function setChainGasAmount(uint256 newChainGasAmount) external onlyRole(GOVERNOR_ROLE) {\n uint256 oldChainGasAmount = chainGasAmount;\n chainGasAmount = newChainGasAmount;\n emit ChainGasAmountUpdated(oldChainGasAmount, newChainGasAmount);\n }\n}\n\n// contracts/FastBridgeV2.sol\n\n/// @notice FastBridgeV2 is a contract for bridging tokens across chains.\ncontract FastBridgeV2 is Admin, IFastBridgeV2, IFastBridgeV2Errors {\n using SafeERC20 for IERC20;\n using UniversalTokenLib for address;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Delay for a transaction after which it could be permisionlessly refunded\n uint256 public constant REFUND_DELAY = 7 days;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n /// @notice Maximum length of accepted callParams\n uint256 public constant MAX_CALL_PARAMS_LENGTH = 2 ** 16 - 1;\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeTxDetails) public bridgeTxDetails;\n /// @notice Relay details on destination chain\n mapping(bytes32 =\u003e BridgeRelay) public bridgeRelayDetails;\n /// @notice Unique bridge nonces tracked per originSender\n mapping(address =\u003e uint256) public senderNonces;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Replaced by senderNonces\n uint256 public immutable nonce = 0;\n /// @notice the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n bridge({\n params: params,\n paramsV2: BridgeParamsV2({\n quoteRelayer: address(0),\n quoteExclusivitySeconds: 0,\n quoteId: bytes(\"\"),\n callValue: 0,\n callParams: bytes(\"\")\n })\n });\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes memory request) external payable {\n relay({request: request, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes memory request, bytes32 destTxHash) external {\n prove({transactionId: keccak256(request), destTxHash: destTxHash, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridgeV2\n function claim(bytes memory request) external {\n claim({request: request, to: address(0)});\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003e DISPUTE_PERIOD) {\n revert DisputePeriodPassed();\n }\n\n // @dev relayer gets slashed effectively if dest relay has gone thru\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n bridgeTxDetails[transactionId].proofRelayer = address(0);\n bridgeTxDetails[transactionId].proofBlockTimestamp = 0;\n bridgeTxDetails[transactionId].proofBlockNumber = 0;\n\n emit BridgeProofDisputed(transactionId, msg.sender);\n }\n\n /// @inheritdoc IFastBridge\n function refund(bytes memory request) external {\n bytes32 transactionId = keccak256(request);\n\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n\n if (bridgeTxDetails[transactionId].status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n\n if (hasRole(REFUNDER_ROLE, msg.sender)) {\n // Refunder can refund if deadline has passed\n if (block.timestamp \u003c= transaction.deadline) revert DeadlineNotExceeded();\n } else {\n // Permissionless refund is allowed after REFUND_DELAY\n if (block.timestamp \u003c= transaction.deadline + REFUND_DELAY) revert DeadlineNotExceeded();\n }\n\n // if all checks passed, set to REFUNDED status\n bridgeTxDetails[transactionId].status = BridgeStatus.REFUNDED;\n\n // transfer origin collateral back to original sender\n address to = transaction.originSender;\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount + transaction.originFeeAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (bridgeTxDetails[transactionId].proofRelayer != relayer) revert SenderIncorrect();\n return _timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n /// @dev This method is added to achieve backwards compatibility with decoding requests into V1 structs:\n /// - `callValue` is partially reported as a zero/non-zero flag\n /// - `callParams` is ignored\n /// In order to process all kinds of requests use getBridgeTransactionV2 instead.\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory) {\n // Try decoding into V2 struct first. This will revert if V1 struct is passed\n try this.getBridgeTransactionV2(request) returns (BridgeTransactionV2 memory txV2) {\n // Note: we entirely ignore the callParams field, as it was not present in V1\n return BridgeTransaction({\n originChainId: txV2.originChainId,\n destChainId: txV2.destChainId,\n originSender: txV2.originSender,\n destRecipient: txV2.destRecipient,\n originToken: txV2.originToken,\n destToken: txV2.destToken,\n originAmount: txV2.originAmount,\n destAmount: txV2.destAmount,\n originFeeAmount: txV2.originFeeAmount,\n sendChainGas: txV2.callValue != 0,\n deadline: txV2.deadline,\n nonce: txV2.nonce\n });\n } catch {\n // Fallback to V1 struct\n return abi.decode(request, (BridgeTransaction));\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) public payable {\n int256 exclusivityEndTime = int256(block.timestamp) + paramsV2.quoteExclusivitySeconds;\n _validateBridgeParams(params, paramsV2, exclusivityEndTime);\n\n // transfer tokens to bridge contract\n /// @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _pullToken(params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n\n // set status to requested\n bytes memory request = abi.encode(\n BridgeTransactionV2({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n callValue: paramsV2.callValue,\n deadline: params.deadline,\n nonce: senderNonces[params.sender]++, // increment nonce on every bridge\n exclusivityRelayer: paramsV2.quoteRelayer,\n // We checked exclusivityEndTime to be in range (0 .. params.deadline] above, so can safely cast\n exclusivityEndTime: uint256(exclusivityEndTime),\n callParams: paramsV2.callParams\n })\n );\n bytes32 transactionId = keccak256(request);\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n\n emit BridgeRequested({\n transactionId: transactionId,\n sender: params.sender,\n request: request,\n destChainId: params.dstChainId,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n sendChainGas: paramsV2.callValue != 0\n });\n emit BridgeQuoteDetails(transactionId, paramsV2.quoteId);\n }\n\n /// @inheritdoc IFastBridgeV2\n function relay(bytes memory request, address relayer) public payable {\n bytes32 transactionId = keccak256(request);\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n _validateRelayParams(transaction, transactionId, relayer);\n // mark bridge transaction as relayed\n bridgeRelayDetails[transactionId] =\n BridgeRelay({blockNumber: uint48(block.number), blockTimestamp: uint48(block.timestamp), relayer: relayer});\n\n // transfer tokens to recipient on destination chain and do an arbitrary call if requested\n address to = transaction.destRecipient;\n address token = transaction.destToken;\n uint256 amount = transaction.destAmount;\n\n // All state changes have been done at this point, can proceed to the external calls.\n // This follows the checks-effects-interactions pattern to mitigate potential reentrancy attacks.\n if (token == UniversalTokenLib.ETH_ADDRESS) {\n // For ETH non-zero callValue is not allowed\n if (transaction.callValue != 0) revert NativeTokenCallValueNotSupported();\n // Check that the correct msg.value was sent\n if (msg.value != amount) revert MsgValueIncorrect();\n } else {\n // For ERC20s, we check that the correct msg.value was sent\n if (msg.value != transaction.callValue) revert MsgValueIncorrect();\n // We need to transfer the tokens from the Relayer to the recipient first before performing an\n // optional post-transfer arbitrary call.\n IERC20(token).safeTransferFrom(msg.sender, to, amount);\n }\n\n if (transaction.callParams.length != 0) {\n // Arbitrary call requested, perform it while supplying full msg.value to the recipient\n // Note: if token has a fee on transfers, the recipient will have received less than `amount`.\n // This is a very niche edge case and should be handled by the recipient contract.\n _checkedCallRecipient({recipient: to, token: token, amount: amount, callParams: transaction.callParams});\n } else if (msg.value != 0) {\n // No arbitrary call requested, but msg.value was sent. This is either a relay with ETH,\n // or a non-zero callValue request with an ERC20. In both cases, transfer the ETH to the recipient.\n Address.sendValue(payable(to), msg.value);\n }\n\n emit BridgeRelayed({\n transactionId: transactionId,\n relayer: relayer,\n to: to,\n originChainId: transaction.originChainId,\n originToken: transaction.originToken,\n destToken: transaction.destToken,\n originAmount: transaction.originAmount,\n destAmount: transaction.destAmount,\n chainGasAmount: transaction.callValue\n });\n }\n\n /// @inheritdoc IFastBridgeV2\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) public onlyRole(RELAYER_ROLE) {\n // update bridge tx status given proof provided\n if (bridgeTxDetails[transactionId].status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n bridgeTxDetails[transactionId].status = BridgeStatus.RELAYER_PROVED;\n bridgeTxDetails[transactionId].proofBlockTimestamp = uint40(block.timestamp);\n bridgeTxDetails[transactionId].proofBlockNumber = uint48(block.number);\n bridgeTxDetails[transactionId].proofRelayer = relayer;\n\n emit BridgeProofProvided(transactionId, relayer, destTxHash);\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes memory request, address to) public {\n bytes32 transactionId = keccak256(request);\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n\n // update bridge tx status if able to claim origin collateral\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n\n // if \"to\" is zero addr, permissionlessly send funds to proven relayer\n if (to == address(0)) {\n to = bridgeTxDetails[transactionId].proofRelayer;\n } else if (bridgeTxDetails[transactionId].proofRelayer != msg.sender) {\n revert SenderIncorrect();\n }\n\n if (_timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003c= DISPUTE_PERIOD) {\n revert DisputePeriodNotPassed();\n }\n\n bridgeTxDetails[transactionId].status = BridgeStatus.RELAYER_CLAIMED;\n\n // update protocol fees if origin fee amount exists\n if (transaction.originFeeAmount \u003e 0) protocolFees[transaction.originToken] += transaction.originFeeAmount;\n\n // transfer origin collateral less fee to specified address\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositClaimed(transactionId, bridgeTxDetails[transactionId].proofRelayer, to, token, amount);\n }\n\n function bridgeStatuses(bytes32 transactionId) public view returns (BridgeStatus status) {\n return bridgeTxDetails[transactionId].status;\n }\n\n function bridgeProofs(bytes32 transactionId) public view returns (uint96 timestamp, address relayer) {\n timestamp = bridgeTxDetails[transactionId].proofBlockTimestamp;\n relayer = bridgeTxDetails[transactionId].proofRelayer;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeRelays(bytes32 transactionId) public view returns (bool) {\n // has this transactionId been relayed?\n return bridgeRelayDetails[transactionId].relayer != address(0);\n }\n\n /// @inheritdoc IFastBridgeV2\n function getBridgeTransactionV2(bytes memory request) public pure returns (BridgeTransactionV2 memory) {\n return abi.decode(request, (BridgeTransactionV2));\n }\n\n /// @notice Pulls a requested token from the user to this contract.\n function _pullToken(address token, uint256 amount) internal returns (uint256 amountPulled) {\n if (token == UniversalTokenLib.ETH_ADDRESS) {\n // For ETH we just need to check that the supplied msg.value is correct\n if (amount != msg.value) revert MsgValueIncorrect();\n amountPulled = msg.value;\n } else {\n token.assertIsContract();\n // Record token balance before transfer\n amountPulled = IERC20(token).balanceOf(address(this));\n // Token needs to be pulled only if msg.value is zero\n // This way user can specify WETH as the origin asset\n IERC20(token).safeTransferFrom(msg.sender, address(this), amount);\n // Use the difference between the recorded balance and the current balance as the amountPulled\n amountPulled = IERC20(token).balanceOf(address(this)) - amountPulled;\n }\n }\n\n /// @notice Calls the Recipient's hook function with the specified callParams and performs\n /// all the necessary checks for the returned value.\n function _checkedCallRecipient(\n address recipient,\n address token,\n uint256 amount,\n bytes memory callParams\n )\n internal\n {\n bytes memory hookData =\n abi.encodeCall(IFastBridgeRecipient.fastBridgeTransferReceived, (token, amount, callParams));\n // This will bubble any revert messages from the hook function\n bytes memory returnData = Address.functionCallWithValue({target: recipient, data: hookData, value: msg.value});\n // Explicit revert if no return data at all\n if (returnData.length == 0) revert RecipientNoReturnValue();\n // Check that exactly a single return value was returned\n if (returnData.length != 32) revert RecipientIncorrectReturnValue();\n // Return value should be abi-encoded hook function selector\n if (bytes32(returnData) != bytes32(IFastBridgeRecipient.fastBridgeTransferReceived.selector)) {\n revert RecipientIncorrectReturnValue();\n }\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint40(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint40).max but\n /// proof.timestamp \u003c type(uint40).max via unchecked statement\n /// @param proofBlockTimestamp The bridge proof block timestamp\n /// @return delta Time delta since proof submitted\n function _timeSince(uint40 proofBlockTimestamp) internal view returns (uint256 delta) {\n unchecked {\n delta = uint40(block.timestamp) - proofBlockTimestamp;\n }\n }\n\n /// @notice Performs all the necessary checks for a bridge to happen.\n /// @dev There's no good way to refactor this function to reduce cyclomatic complexity due to\n /// the number of checks that need to be performed, so we skip the code-complexity rule here.\n // solhint-disable-next-line code-complexity\n function _validateBridgeParams(\n BridgeParams memory params,\n BridgeParamsV2 memory paramsV2,\n int256 exclusivityEndTime\n )\n internal\n view\n {\n // Check V1 (legacy) params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.sender == address(0) || params.to == address(0)) revert ZeroAddress();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n // Check V2 params\n if (paramsV2.callParams.length \u003e MAX_CALL_PARAMS_LENGTH) revert CallParamsLengthAboveMax();\n if (paramsV2.callValue != 0 \u0026\u0026 params.destToken == UniversalTokenLib.ETH_ADDRESS) {\n revert NativeTokenCallValueNotSupported();\n }\n // exclusivityEndTime must be in range (0 .. params.deadline]\n if (exclusivityEndTime \u003c= 0 || exclusivityEndTime \u003e int256(params.deadline)) {\n revert ExclusivityParamsIncorrect();\n }\n }\n\n /// @notice Performs all the necessary checks for a relay to happen.\n function _validateRelayParams(\n BridgeTransactionV2 memory transaction,\n bytes32 transactionId,\n address relayer\n )\n internal\n view\n {\n if (relayer == address(0)) revert ZeroAddress();\n // Check if the transaction has already been relayed\n if (bridgeRelays(transactionId)) revert TransactionRelayed();\n if (transaction.destChainId != uint32(block.chainid)) revert ChainIncorrect();\n // Check the deadline for relay to happen\n if (block.timestamp \u003e transaction.deadline) revert DeadlineExceeded();\n // Check the exclusivity period, if it is still ongoing\n // forgefmt: disable-next-item\n if (\n transaction.exclusivityRelayer != address(0) \u0026\u0026\n transaction.exclusivityRelayer != relayer \u0026\u0026\n block.timestamp \u003c= transaction.exclusivityEndTime\n ) {\n revert ExclusivityPeriodNotPassed();\n }\n }\n}\n","language":"Solidity","languageVersion":"0.8.24","compilerVersion":"0.8.24","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../","srcMap":"","srcMapRuntime":"","abiDefinition":[{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"bytes","name":"callParams","type":"bytes"}],"name":"fastBridgeTransferReceived","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"payable","type":"function"}],"userDoc":{"kind":"user","methods":{},"version":1},"developerDoc":{"kind":"dev","methods":{},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"callParams\",\"type\":\"bytes\"}],\"name\":\"fastBridgeTransferReceived\",\"outputs\":[{\"internalType\":\"bytes4\",\"name\":\"\",\"type\":\"bytes4\"}],\"stateMutability\":\"payable\",\"type\":\"function\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeV2.sol\":\"IFastBridgeRecipient\"},\"evmVersion\":\"shanghai\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeV2.sol\":{\"keccak256\":\"0x7cd0f885e80e2bdaa638bc32ae7af7d2e248f99ce4b354c217d0f0f7d7302e0a\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://7ccf28df0bd7b4606986585acd8622ed9b4e81379690061bb66088f0a2270af1\",\"dweb:/ipfs/QmTf7HNdHZkK6vmx8ZgewycQEb72oLD9nPwBpsM5reMstQ\"]}},\"version\":1}"},"hashes":{"fastBridgeTransferReceived(address,uint256,bytes)":"461e0c21"}},"solidity/FastBridgeV2.sol:IFastBridgeV2":{"code":"0x","runtime-code":"0x","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.24 ^0.8.0 ^0.8.20;\n\n// contracts/interfaces/IAdmin.sol\n\ninterface IAdmin {\n // ============ Events ============\n\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n event ChainGasAmountUpdated(uint256 oldChainGasAmount, uint256 newChainGasAmount);\n\n // ============ Methods ============\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n\n function setChainGasAmount(uint256 newChainGasAmount) external;\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IFastBridgeRecipient.sol\n\ninterface IFastBridgeRecipient {\n function fastBridgeTransferReceived(\n address token,\n uint256 amount,\n bytes memory callParams\n )\n external\n payable\n returns (bytes4);\n}\n\n// contracts/interfaces/IFastBridgeV2Errors.sol\n\ninterface IFastBridgeV2Errors {\n error AmountIncorrect();\n error CallParamsLengthAboveMax();\n error ChainIncorrect();\n error ExclusivityParamsIncorrect();\n error MsgValueIncorrect();\n error NativeTokenCallValueNotSupported();\n error SenderIncorrect();\n error StatusIncorrect();\n error ZeroAddress();\n\n error RecipientIncorrectReturnValue();\n error RecipientNoReturnValue();\n\n error DeadlineExceeded();\n error DeadlineNotExceeded();\n error DeadlineTooShort();\n error DisputePeriodNotPassed();\n error DisputePeriodPassed();\n error ExclusivityPeriodNotPassed();\n\n error TransactionRelayed();\n}\n\n// contracts/libs/Errors.sol\n\nerror DeadlineExceeded();\nerror DeadlineNotExceeded();\nerror DeadlineTooShort();\nerror InsufficientOutputAmount();\n\nerror MsgValueIncorrect();\nerror PoolNotFound();\nerror TokenAddressMismatch();\nerror TokenNotContract();\nerror TokenNotETH();\nerror TokensIdentical();\n\nerror ChainIncorrect();\nerror AmountIncorrect();\nerror ZeroAddress();\n\nerror DisputePeriodNotPassed();\nerror DisputePeriodPassed();\nerror SenderIncorrect();\nerror StatusIncorrect();\nerror TransactionIdIncorrect();\nerror TransactionRelayed();\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// contracts/interfaces/IFastBridgeV2.sol\n\ninterface IFastBridgeV2 is IFastBridge {\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n struct BridgeTxDetails {\n BridgeStatus status;\n uint40 proofBlockTimestamp;\n uint48 proofBlockNumber;\n address proofRelayer;\n }\n\n struct BridgeRelay {\n uint48 blockNumber;\n uint48 blockTimestamp;\n address relayer;\n }\n\n /// @notice New params introduced in the FastBridgeV2.\n /// We are passing fields from the older BridgeParams struct outside of this struct\n /// for backwards compatibility.\n /// Note: quoteRelayer and quoteExclusivitySeconds are either both zero (indicating no exclusivity)\n /// or both non-zero (indicating exclusivity for the given period).\n /// Note: callValue \u003e 0 can NOT be used with destToken = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE (ETH_ADDRESS)\n /// @param quoteRelayer Relayer that provided the quote for the transaction\n /// @param quoteExclusivitySeconds Period of time the quote relayer is guaranteed exclusivity after user's deposit\n /// @param quoteId Unique quote identifier used for tracking the quote\n /// @param callValue ETH value to send to the recipient (if any)\n /// @param callParams Parameters for the arbitrary call to the destination recipient (if any)\n struct BridgeParamsV2 {\n address quoteRelayer;\n int256 quoteExclusivitySeconds;\n bytes quoteId;\n uint256 callValue;\n bytes callParams;\n }\n\n /// @notice Updated bridge transaction struct to include parameters introduced in FastBridgeV2.\n /// Note: only `exclusivityRelayer` can fill such a transaction until `exclusivityEndTime`.\n /// TODO: consider changing the encoding scheme to prevent spending extra gas on decoding.\n struct BridgeTransactionV2 {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n uint256 callValue; // ETH value to send to the recipient (if any) - replaces V1's sendChainGas flag\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n address exclusivityRelayer;\n uint256 exclusivityEndTime;\n bytes callParams;\n }\n\n event BridgeQuoteDetails(bytes32 indexed transactionId, bytes quoteId);\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability\n /// to provide temporary exclusivity fill rights for the quote relayer.\n /// @param params The parameters required to bridge\n /// @param paramsV2 The parameters for exclusivity fill rights (optional, can be left empty)\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function relay(bytes memory request, address relayer) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param transactionId The transaction id associated with the encoded bridge transaction to prove\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital.\n /// @notice Can only send funds to the relayer address on the proof.\n /// @param request The encoded bridge transaction to claim on origin chain\n function claim(bytes memory request) external;\n /// @notice Checks if a transaction has been relayed\n /// @param transactionId The ID of the transaction to check\n /// @return True if the transaction has been relayed, false otherwise\n function bridgeRelays(bytes32 transactionId) external view returns (bool);\n\n /// @notice Returns the status of a bridge transaction\n /// @param transactionId The ID of the bridge transaction\n /// @return BridgeStatus Status of the bridge transaction\n function bridgeStatuses(bytes32 transactionId) external view returns (BridgeStatus);\n\n /// @notice Returns the timestamp and relayer of a bridge proof\n /// @param transactionId The ID of the bridge transaction\n /// @return timestamp The timestamp of the bridge proof\n /// @return relayer The relayer address of the bridge proof\n function bridgeProofs(bytes32 transactionId) external view returns (uint96 timestamp, address relayer);\n\n /// @notice Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\n /// @param request The bridge request to decode\n function getBridgeTransactionV2(bytes memory request) external view returns (BridgeTransactionV2 memory);\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// contracts/libs/UniversalToken.sol\n\nlibrary UniversalTokenLib {\n using SafeERC20 for IERC20;\n\n address internal constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Transfers tokens to the given account. Reverts if transfer is not successful.\n /// @dev This might trigger fallback, if ETH is transferred to the contract.\n /// Make sure this can not lead to reentrancy attacks.\n function universalTransfer(address token, address to, uint256 value) internal {\n // Don't do anything, if need to send tokens to this address\n if (to == address(this)) return;\n // Don't do anything, if trying to send zero value\n if (value == 0) return;\n if (token == ETH_ADDRESS) {\n /// @dev Note: this can potentially lead to executing code in `to`.\n // solhint-disable-next-line avoid-low-level-calls\n (bool success,) = to.call{value: value}(\"\");\n require(success, \"ETH transfer failed\");\n } else {\n IERC20(token).safeTransfer(to, value);\n }\n }\n\n /// @notice Issues an infinite allowance to the spender, if the current allowance is insufficient\n /// to spend the given amount.\n function universalApproveInfinity(address token, address spender, uint256 amountToSpend) internal {\n // ETH Chad doesn't require your approval\n if (token == ETH_ADDRESS) return;\n // No-op if allowance is already sufficient\n uint256 allowance = IERC20(token).allowance(address(this), spender);\n if (allowance \u003e= amountToSpend) return;\n // Otherwise, reset approval to 0 and set to max allowance\n if (allowance \u003e 0) IERC20(token).safeDecreaseAllowance(spender, allowance);\n IERC20(token).safeIncreaseAllowance(spender, type(uint256).max);\n }\n\n /// @notice Returns the balance of the given token (or native ETH) for the given account.\n function universalBalanceOf(address token, address account) internal view returns (uint256) {\n if (token == ETH_ADDRESS) {\n return account.balance;\n } else {\n return IERC20(token).balanceOf(account);\n }\n }\n\n /// @dev Checks that token is a contract and not ETH_ADDRESS.\n function assertIsContract(address token) internal view {\n // Check that ETH_ADDRESS was not used (in case this is a predeploy on any of the chains)\n if (token == UniversalTokenLib.ETH_ADDRESS) revert TokenNotContract();\n // Check that token is not an EOA\n if (token.code.length == 0) revert TokenNotContract();\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/Admin.sol\n\ncontract Admin is IAdmin, AccessControlEnumerable {\n using UniversalTokenLib for address;\n\n bytes32 public constant RELAYER_ROLE = keccak256(\"RELAYER_ROLE\");\n bytes32 public constant REFUNDER_ROLE = keccak256(\"REFUNDER_ROLE\");\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n uint256 public constant FEE_BPS = 1e6;\n uint256 public constant FEE_RATE_MAX = 0.01e6; // max 1% on origin amount\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Chain gas amount to forward as rebate if requested\n uint256 public chainGasAmount;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n }\n\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n require(newFeeRate \u003c= FEE_RATE_MAX, \"newFeeRate \u003e max\");\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n token.universalTransfer(recipient, feeAmount);\n emit FeesSwept(token, recipient, feeAmount);\n }\n\n function setChainGasAmount(uint256 newChainGasAmount) external onlyRole(GOVERNOR_ROLE) {\n uint256 oldChainGasAmount = chainGasAmount;\n chainGasAmount = newChainGasAmount;\n emit ChainGasAmountUpdated(oldChainGasAmount, newChainGasAmount);\n }\n}\n\n// contracts/FastBridgeV2.sol\n\n/// @notice FastBridgeV2 is a contract for bridging tokens across chains.\ncontract FastBridgeV2 is Admin, IFastBridgeV2, IFastBridgeV2Errors {\n using SafeERC20 for IERC20;\n using UniversalTokenLib for address;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Delay for a transaction after which it could be permisionlessly refunded\n uint256 public constant REFUND_DELAY = 7 days;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n /// @notice Maximum length of accepted callParams\n uint256 public constant MAX_CALL_PARAMS_LENGTH = 2 ** 16 - 1;\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeTxDetails) public bridgeTxDetails;\n /// @notice Relay details on destination chain\n mapping(bytes32 =\u003e BridgeRelay) public bridgeRelayDetails;\n /// @notice Unique bridge nonces tracked per originSender\n mapping(address =\u003e uint256) public senderNonces;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Replaced by senderNonces\n uint256 public immutable nonce = 0;\n /// @notice the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n bridge({\n params: params,\n paramsV2: BridgeParamsV2({\n quoteRelayer: address(0),\n quoteExclusivitySeconds: 0,\n quoteId: bytes(\"\"),\n callValue: 0,\n callParams: bytes(\"\")\n })\n });\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes memory request) external payable {\n relay({request: request, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes memory request, bytes32 destTxHash) external {\n prove({transactionId: keccak256(request), destTxHash: destTxHash, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridgeV2\n function claim(bytes memory request) external {\n claim({request: request, to: address(0)});\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003e DISPUTE_PERIOD) {\n revert DisputePeriodPassed();\n }\n\n // @dev relayer gets slashed effectively if dest relay has gone thru\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n bridgeTxDetails[transactionId].proofRelayer = address(0);\n bridgeTxDetails[transactionId].proofBlockTimestamp = 0;\n bridgeTxDetails[transactionId].proofBlockNumber = 0;\n\n emit BridgeProofDisputed(transactionId, msg.sender);\n }\n\n /// @inheritdoc IFastBridge\n function refund(bytes memory request) external {\n bytes32 transactionId = keccak256(request);\n\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n\n if (bridgeTxDetails[transactionId].status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n\n if (hasRole(REFUNDER_ROLE, msg.sender)) {\n // Refunder can refund if deadline has passed\n if (block.timestamp \u003c= transaction.deadline) revert DeadlineNotExceeded();\n } else {\n // Permissionless refund is allowed after REFUND_DELAY\n if (block.timestamp \u003c= transaction.deadline + REFUND_DELAY) revert DeadlineNotExceeded();\n }\n\n // if all checks passed, set to REFUNDED status\n bridgeTxDetails[transactionId].status = BridgeStatus.REFUNDED;\n\n // transfer origin collateral back to original sender\n address to = transaction.originSender;\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount + transaction.originFeeAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (bridgeTxDetails[transactionId].proofRelayer != relayer) revert SenderIncorrect();\n return _timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n /// @dev This method is added to achieve backwards compatibility with decoding requests into V1 structs:\n /// - `callValue` is partially reported as a zero/non-zero flag\n /// - `callParams` is ignored\n /// In order to process all kinds of requests use getBridgeTransactionV2 instead.\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory) {\n // Try decoding into V2 struct first. This will revert if V1 struct is passed\n try this.getBridgeTransactionV2(request) returns (BridgeTransactionV2 memory txV2) {\n // Note: we entirely ignore the callParams field, as it was not present in V1\n return BridgeTransaction({\n originChainId: txV2.originChainId,\n destChainId: txV2.destChainId,\n originSender: txV2.originSender,\n destRecipient: txV2.destRecipient,\n originToken: txV2.originToken,\n destToken: txV2.destToken,\n originAmount: txV2.originAmount,\n destAmount: txV2.destAmount,\n originFeeAmount: txV2.originFeeAmount,\n sendChainGas: txV2.callValue != 0,\n deadline: txV2.deadline,\n nonce: txV2.nonce\n });\n } catch {\n // Fallback to V1 struct\n return abi.decode(request, (BridgeTransaction));\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) public payable {\n int256 exclusivityEndTime = int256(block.timestamp) + paramsV2.quoteExclusivitySeconds;\n _validateBridgeParams(params, paramsV2, exclusivityEndTime);\n\n // transfer tokens to bridge contract\n /// @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _pullToken(params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n\n // set status to requested\n bytes memory request = abi.encode(\n BridgeTransactionV2({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n callValue: paramsV2.callValue,\n deadline: params.deadline,\n nonce: senderNonces[params.sender]++, // increment nonce on every bridge\n exclusivityRelayer: paramsV2.quoteRelayer,\n // We checked exclusivityEndTime to be in range (0 .. params.deadline] above, so can safely cast\n exclusivityEndTime: uint256(exclusivityEndTime),\n callParams: paramsV2.callParams\n })\n );\n bytes32 transactionId = keccak256(request);\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n\n emit BridgeRequested({\n transactionId: transactionId,\n sender: params.sender,\n request: request,\n destChainId: params.dstChainId,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n sendChainGas: paramsV2.callValue != 0\n });\n emit BridgeQuoteDetails(transactionId, paramsV2.quoteId);\n }\n\n /// @inheritdoc IFastBridgeV2\n function relay(bytes memory request, address relayer) public payable {\n bytes32 transactionId = keccak256(request);\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n _validateRelayParams(transaction, transactionId, relayer);\n // mark bridge transaction as relayed\n bridgeRelayDetails[transactionId] =\n BridgeRelay({blockNumber: uint48(block.number), blockTimestamp: uint48(block.timestamp), relayer: relayer});\n\n // transfer tokens to recipient on destination chain and do an arbitrary call if requested\n address to = transaction.destRecipient;\n address token = transaction.destToken;\n uint256 amount = transaction.destAmount;\n\n // All state changes have been done at this point, can proceed to the external calls.\n // This follows the checks-effects-interactions pattern to mitigate potential reentrancy attacks.\n if (token == UniversalTokenLib.ETH_ADDRESS) {\n // For ETH non-zero callValue is not allowed\n if (transaction.callValue != 0) revert NativeTokenCallValueNotSupported();\n // Check that the correct msg.value was sent\n if (msg.value != amount) revert MsgValueIncorrect();\n } else {\n // For ERC20s, we check that the correct msg.value was sent\n if (msg.value != transaction.callValue) revert MsgValueIncorrect();\n // We need to transfer the tokens from the Relayer to the recipient first before performing an\n // optional post-transfer arbitrary call.\n IERC20(token).safeTransferFrom(msg.sender, to, amount);\n }\n\n if (transaction.callParams.length != 0) {\n // Arbitrary call requested, perform it while supplying full msg.value to the recipient\n // Note: if token has a fee on transfers, the recipient will have received less than `amount`.\n // This is a very niche edge case and should be handled by the recipient contract.\n _checkedCallRecipient({recipient: to, token: token, amount: amount, callParams: transaction.callParams});\n } else if (msg.value != 0) {\n // No arbitrary call requested, but msg.value was sent. This is either a relay with ETH,\n // or a non-zero callValue request with an ERC20. In both cases, transfer the ETH to the recipient.\n Address.sendValue(payable(to), msg.value);\n }\n\n emit BridgeRelayed({\n transactionId: transactionId,\n relayer: relayer,\n to: to,\n originChainId: transaction.originChainId,\n originToken: transaction.originToken,\n destToken: transaction.destToken,\n originAmount: transaction.originAmount,\n destAmount: transaction.destAmount,\n chainGasAmount: transaction.callValue\n });\n }\n\n /// @inheritdoc IFastBridgeV2\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) public onlyRole(RELAYER_ROLE) {\n // update bridge tx status given proof provided\n if (bridgeTxDetails[transactionId].status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n bridgeTxDetails[transactionId].status = BridgeStatus.RELAYER_PROVED;\n bridgeTxDetails[transactionId].proofBlockTimestamp = uint40(block.timestamp);\n bridgeTxDetails[transactionId].proofBlockNumber = uint48(block.number);\n bridgeTxDetails[transactionId].proofRelayer = relayer;\n\n emit BridgeProofProvided(transactionId, relayer, destTxHash);\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes memory request, address to) public {\n bytes32 transactionId = keccak256(request);\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n\n // update bridge tx status if able to claim origin collateral\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n\n // if \"to\" is zero addr, permissionlessly send funds to proven relayer\n if (to == address(0)) {\n to = bridgeTxDetails[transactionId].proofRelayer;\n } else if (bridgeTxDetails[transactionId].proofRelayer != msg.sender) {\n revert SenderIncorrect();\n }\n\n if (_timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003c= DISPUTE_PERIOD) {\n revert DisputePeriodNotPassed();\n }\n\n bridgeTxDetails[transactionId].status = BridgeStatus.RELAYER_CLAIMED;\n\n // update protocol fees if origin fee amount exists\n if (transaction.originFeeAmount \u003e 0) protocolFees[transaction.originToken] += transaction.originFeeAmount;\n\n // transfer origin collateral less fee to specified address\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositClaimed(transactionId, bridgeTxDetails[transactionId].proofRelayer, to, token, amount);\n }\n\n function bridgeStatuses(bytes32 transactionId) public view returns (BridgeStatus status) {\n return bridgeTxDetails[transactionId].status;\n }\n\n function bridgeProofs(bytes32 transactionId) public view returns (uint96 timestamp, address relayer) {\n timestamp = bridgeTxDetails[transactionId].proofBlockTimestamp;\n relayer = bridgeTxDetails[transactionId].proofRelayer;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeRelays(bytes32 transactionId) public view returns (bool) {\n // has this transactionId been relayed?\n return bridgeRelayDetails[transactionId].relayer != address(0);\n }\n\n /// @inheritdoc IFastBridgeV2\n function getBridgeTransactionV2(bytes memory request) public pure returns (BridgeTransactionV2 memory) {\n return abi.decode(request, (BridgeTransactionV2));\n }\n\n /// @notice Pulls a requested token from the user to this contract.\n function _pullToken(address token, uint256 amount) internal returns (uint256 amountPulled) {\n if (token == UniversalTokenLib.ETH_ADDRESS) {\n // For ETH we just need to check that the supplied msg.value is correct\n if (amount != msg.value) revert MsgValueIncorrect();\n amountPulled = msg.value;\n } else {\n token.assertIsContract();\n // Record token balance before transfer\n amountPulled = IERC20(token).balanceOf(address(this));\n // Token needs to be pulled only if msg.value is zero\n // This way user can specify WETH as the origin asset\n IERC20(token).safeTransferFrom(msg.sender, address(this), amount);\n // Use the difference between the recorded balance and the current balance as the amountPulled\n amountPulled = IERC20(token).balanceOf(address(this)) - amountPulled;\n }\n }\n\n /// @notice Calls the Recipient's hook function with the specified callParams and performs\n /// all the necessary checks for the returned value.\n function _checkedCallRecipient(\n address recipient,\n address token,\n uint256 amount,\n bytes memory callParams\n )\n internal\n {\n bytes memory hookData =\n abi.encodeCall(IFastBridgeRecipient.fastBridgeTransferReceived, (token, amount, callParams));\n // This will bubble any revert messages from the hook function\n bytes memory returnData = Address.functionCallWithValue({target: recipient, data: hookData, value: msg.value});\n // Explicit revert if no return data at all\n if (returnData.length == 0) revert RecipientNoReturnValue();\n // Check that exactly a single return value was returned\n if (returnData.length != 32) revert RecipientIncorrectReturnValue();\n // Return value should be abi-encoded hook function selector\n if (bytes32(returnData) != bytes32(IFastBridgeRecipient.fastBridgeTransferReceived.selector)) {\n revert RecipientIncorrectReturnValue();\n }\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint40(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint40).max but\n /// proof.timestamp \u003c type(uint40).max via unchecked statement\n /// @param proofBlockTimestamp The bridge proof block timestamp\n /// @return delta Time delta since proof submitted\n function _timeSince(uint40 proofBlockTimestamp) internal view returns (uint256 delta) {\n unchecked {\n delta = uint40(block.timestamp) - proofBlockTimestamp;\n }\n }\n\n /// @notice Performs all the necessary checks for a bridge to happen.\n /// @dev There's no good way to refactor this function to reduce cyclomatic complexity due to\n /// the number of checks that need to be performed, so we skip the code-complexity rule here.\n // solhint-disable-next-line code-complexity\n function _validateBridgeParams(\n BridgeParams memory params,\n BridgeParamsV2 memory paramsV2,\n int256 exclusivityEndTime\n )\n internal\n view\n {\n // Check V1 (legacy) params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.sender == address(0) || params.to == address(0)) revert ZeroAddress();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n // Check V2 params\n if (paramsV2.callParams.length \u003e MAX_CALL_PARAMS_LENGTH) revert CallParamsLengthAboveMax();\n if (paramsV2.callValue != 0 \u0026\u0026 params.destToken == UniversalTokenLib.ETH_ADDRESS) {\n revert NativeTokenCallValueNotSupported();\n }\n // exclusivityEndTime must be in range (0 .. params.deadline]\n if (exclusivityEndTime \u003c= 0 || exclusivityEndTime \u003e int256(params.deadline)) {\n revert ExclusivityParamsIncorrect();\n }\n }\n\n /// @notice Performs all the necessary checks for a relay to happen.\n function _validateRelayParams(\n BridgeTransactionV2 memory transaction,\n bytes32 transactionId,\n address relayer\n )\n internal\n view\n {\n if (relayer == address(0)) revert ZeroAddress();\n // Check if the transaction has already been relayed\n if (bridgeRelays(transactionId)) revert TransactionRelayed();\n if (transaction.destChainId != uint32(block.chainid)) revert ChainIncorrect();\n // Check the deadline for relay to happen\n if (block.timestamp \u003e transaction.deadline) revert DeadlineExceeded();\n // Check the exclusivity period, if it is still ongoing\n // forgefmt: disable-next-item\n if (\n transaction.exclusivityRelayer != address(0) \u0026\u0026\n transaction.exclusivityRelayer != relayer \u0026\u0026\n block.timestamp \u003c= transaction.exclusivityEndTime\n ) {\n revert ExclusivityPeriodNotPassed();\n }\n }\n}\n","language":"Solidity","languageVersion":"0.8.24","compilerVersion":"0.8.24","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../","srcMap":"","srcMapRuntime":"","abiDefinition":[{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"relayer","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"BridgeDepositClaimed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"BridgeDepositRefunded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"relayer","type":"address"}],"name":"BridgeProofDisputed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"relayer","type":"address"},{"indexed":false,"internalType":"bytes32","name":"transactionHash","type":"bytes32"}],"name":"BridgeProofProvided","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":false,"internalType":"bytes","name":"quoteId","type":"bytes"}],"name":"BridgeQuoteDetails","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"relayer","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint32","name":"originChainId","type":"uint32"},{"indexed":false,"internalType":"address","name":"originToken","type":"address"},{"indexed":false,"internalType":"address","name":"destToken","type":"address"},{"indexed":false,"internalType":"uint256","name":"originAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"destAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"chainGasAmount","type":"uint256"}],"name":"BridgeRelayed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"bytes","name":"request","type":"bytes"},{"indexed":false,"internalType":"uint32","name":"destChainId","type":"uint32"},{"indexed":false,"internalType":"address","name":"originToken","type":"address"},{"indexed":false,"internalType":"address","name":"destToken","type":"address"},{"indexed":false,"internalType":"uint256","name":"originAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"destAmount","type":"uint256"},{"indexed":false,"internalType":"bool","name":"sendChainGas","type":"bool"}],"name":"BridgeRequested","type":"event"},{"inputs":[{"components":[{"internalType":"uint32","name":"dstChainId","type":"uint32"},{"internalType":"address","name":"sender","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"address","name":"originToken","type":"address"},{"internalType":"address","name":"destToken","type":"address"},{"internalType":"uint256","name":"originAmount","type":"uint256"},{"internalType":"uint256","name":"destAmount","type":"uint256"},{"internalType":"bool","name":"sendChainGas","type":"bool"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"internalType":"struct IFastBridge.BridgeParams","name":"params","type":"tuple"}],"name":"bridge","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"uint32","name":"dstChainId","type":"uint32"},{"internalType":"address","name":"sender","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"address","name":"originToken","type":"address"},{"internalType":"address","name":"destToken","type":"address"},{"internalType":"uint256","name":"originAmount","type":"uint256"},{"internalType":"uint256","name":"destAmount","type":"uint256"},{"internalType":"bool","name":"sendChainGas","type":"bool"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"internalType":"struct IFastBridge.BridgeParams","name":"params","type":"tuple"},{"components":[{"internalType":"address","name":"quoteRelayer","type":"address"},{"internalType":"int256","name":"quoteExclusivitySeconds","type":"int256"},{"internalType":"bytes","name":"quoteId","type":"bytes"},{"internalType":"uint256","name":"callValue","type":"uint256"},{"internalType":"bytes","name":"callParams","type":"bytes"}],"internalType":"struct IFastBridgeV2.BridgeParamsV2","name":"paramsV2","type":"tuple"}],"name":"bridge","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"transactionId","type":"bytes32"}],"name":"bridgeProofs","outputs":[{"internalType":"uint96","name":"timestamp","type":"uint96"},{"internalType":"address","name":"relayer","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"transactionId","type":"bytes32"}],"name":"bridgeRelays","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"transactionId","type":"bytes32"}],"name":"bridgeStatuses","outputs":[{"internalType":"enum IFastBridgeV2.BridgeStatus","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"internalType":"address","name":"relayer","type":"address"}],"name":"canClaim","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"},{"internalType":"address","name":"to","type":"address"}],"name":"claim","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"}],"name":"claim","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"transactionId","type":"bytes32"}],"name":"dispute","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"}],"name":"getBridgeTransaction","outputs":[{"components":[{"internalType":"uint32","name":"originChainId","type":"uint32"},{"internalType":"uint32","name":"destChainId","type":"uint32"},{"internalType":"address","name":"originSender","type":"address"},{"internalType":"address","name":"destRecipient","type":"address"},{"internalType":"address","name":"originToken","type":"address"},{"internalType":"address","name":"destToken","type":"address"},{"internalType":"uint256","name":"originAmount","type":"uint256"},{"internalType":"uint256","name":"destAmount","type":"uint256"},{"internalType":"uint256","name":"originFeeAmount","type":"uint256"},{"internalType":"bool","name":"sendChainGas","type":"bool"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint256","name":"nonce","type":"uint256"}],"internalType":"struct IFastBridge.BridgeTransaction","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"}],"name":"getBridgeTransactionV2","outputs":[{"components":[{"internalType":"uint32","name":"originChainId","type":"uint32"},{"internalType":"uint32","name":"destChainId","type":"uint32"},{"internalType":"address","name":"originSender","type":"address"},{"internalType":"address","name":"destRecipient","type":"address"},{"internalType":"address","name":"originToken","type":"address"},{"internalType":"address","name":"destToken","type":"address"},{"internalType":"uint256","name":"originAmount","type":"uint256"},{"internalType":"uint256","name":"destAmount","type":"uint256"},{"internalType":"uint256","name":"originFeeAmount","type":"uint256"},{"internalType":"uint256","name":"callValue","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"address","name":"exclusivityRelayer","type":"address"},{"internalType":"uint256","name":"exclusivityEndTime","type":"uint256"},{"internalType":"bytes","name":"callParams","type":"bytes"}],"internalType":"struct IFastBridgeV2.BridgeTransactionV2","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"internalType":"bytes32","name":"destTxHash","type":"bytes32"},{"internalType":"address","name":"relayer","type":"address"}],"name":"prove","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"},{"internalType":"bytes32","name":"destTxHash","type":"bytes32"}],"name":"prove","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"}],"name":"refund","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"}],"name":"relay","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"},{"internalType":"address","name":"relayer","type":"address"}],"name":"relay","outputs":[],"stateMutability":"payable","type":"function"}],"userDoc":{"kind":"user","methods":{"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256))":{"notice":"Initiates bridge on origin chain to be relayed by off-chain relayer"},"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256),(address,int256,bytes,uint256,bytes))":{"notice":"Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability to provide temporary exclusivity fill rights for the quote relayer."},"bridgeProofs(bytes32)":{"notice":"Returns the timestamp and relayer of a bridge proof"},"bridgeRelays(bytes32)":{"notice":"Checks if a transaction has been relayed"},"bridgeStatuses(bytes32)":{"notice":"Returns the status of a bridge transaction"},"canClaim(bytes32,address)":{"notice":"Checks if the dispute period has passed so bridge deposit can be claimed"},"claim(bytes)":{"notice":"Completes bridge transaction on origin chain by claiming originally deposited capital.Can only send funds to the relayer address on the proof."},"claim(bytes,address)":{"notice":"Completes bridge transaction on origin chain by claiming originally deposited capital"},"dispute(bytes32)":{"notice":"Disputes an outstanding proof in case relayer provided dest chain tx is invalid"},"getBridgeTransaction(bytes)":{"notice":"Decodes bridge request into a bridge transaction"},"getBridgeTransactionV2(bytes)":{"notice":"Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2"},"prove(bytes,bytes32)":{"notice":"Provides proof on origin side that relayer provided funds on destination side of bridge transaction"},"prove(bytes32,bytes32,address)":{"notice":"Provides proof on origin side that relayer provided funds on destination side of bridge transaction"},"refund(bytes)":{"notice":"Refunds an outstanding bridge transaction in case optimistic bridging failed"},"relay(bytes)":{"notice":"Relays destination side of bridge transaction by off-chain relayer"},"relay(bytes,address)":{"notice":"Relays destination side of bridge transaction by off-chain relayer"}},"version":1},"developerDoc":{"kind":"dev","methods":{"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256))":{"params":{"params":"The parameters required to bridge"}},"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256),(address,int256,bytes,uint256,bytes))":{"params":{"params":"The parameters required to bridge","paramsV2":"The parameters for exclusivity fill rights (optional, can be left empty)"}},"bridgeProofs(bytes32)":{"params":{"transactionId":"The ID of the bridge transaction"},"returns":{"relayer":"The relayer address of the bridge proof","timestamp":"The timestamp of the bridge proof"}},"bridgeRelays(bytes32)":{"params":{"transactionId":"The ID of the transaction to check"},"returns":{"_0":"True if the transaction has been relayed, false otherwise"}},"bridgeStatuses(bytes32)":{"params":{"transactionId":"The ID of the bridge transaction"},"returns":{"_0":"BridgeStatus Status of the bridge transaction"}},"canClaim(bytes32,address)":{"params":{"relayer":"The address of the relayer attempting to claim","transactionId":"The transaction id associated with the encoded bridge transaction to check"}},"claim(bytes)":{"params":{"request":"The encoded bridge transaction to claim on origin chain"}},"claim(bytes,address)":{"params":{"request":"The encoded bridge transaction to claim on origin chain","to":"The recipient address of the funds"}},"dispute(bytes32)":{"params":{"transactionId":"The transaction id associated with the encoded bridge transaction to dispute"}},"getBridgeTransaction(bytes)":{"params":{"request":"The bridge request to decode"}},"getBridgeTransactionV2(bytes)":{"params":{"request":"The bridge request to decode"}},"prove(bytes,bytes32)":{"params":{"destTxHash":"The destination tx hash proving bridge transaction was relayed","request":"The encoded bridge transaction to prove on origin chain"}},"prove(bytes32,bytes32,address)":{"params":{"destTxHash":"The destination tx hash proving bridge transaction was relayed","relayer":"The address of the relaying entity which should have control of the origin funds when claimed","transactionId":"The transaction id associated with the encoded bridge transaction to prove"}},"refund(bytes)":{"params":{"request":"The encoded bridge transaction to refund"}},"relay(bytes)":{"params":{"request":"The encoded bridge transaction to relay on destination chain"}},"relay(bytes,address)":{"params":{"relayer":"The address of the relaying entity which should have control of the origin funds when claimed","request":"The encoded bridge transaction to relay on destination chain"}}},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"BridgeDepositClaimed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"BridgeDepositRefunded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"name\":\"BridgeProofDisputed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"transactionHash\",\"type\":\"bytes32\"}],\"name\":\"BridgeProofProvided\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"quoteId\",\"type\":\"bytes\"}],\"name\":\"BridgeQuoteDetails\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"originChainId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"chainGasAmount\",\"type\":\"uint256\"}],\"name\":\"BridgeRelayed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"destChainId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"sendChainGas\",\"type\":\"bool\"}],\"name\":\"BridgeRequested\",\"type\":\"event\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"dstChainId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"sendChainGas\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"}],\"internalType\":\"struct IFastBridge.BridgeParams\",\"name\":\"params\",\"type\":\"tuple\"}],\"name\":\"bridge\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"dstChainId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"sendChainGas\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"}],\"internalType\":\"struct IFastBridge.BridgeParams\",\"name\":\"params\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"quoteRelayer\",\"type\":\"address\"},{\"internalType\":\"int256\",\"name\":\"quoteExclusivitySeconds\",\"type\":\"int256\"},{\"internalType\":\"bytes\",\"name\":\"quoteId\",\"type\":\"bytes\"},{\"internalType\":\"uint256\",\"name\":\"callValue\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"callParams\",\"type\":\"bytes\"}],\"internalType\":\"struct IFastBridgeV2.BridgeParamsV2\",\"name\":\"paramsV2\",\"type\":\"tuple\"}],\"name\":\"bridge\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"}],\"name\":\"bridgeProofs\",\"outputs\":[{\"internalType\":\"uint96\",\"name\":\"timestamp\",\"type\":\"uint96\"},{\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"}],\"name\":\"bridgeRelays\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"}],\"name\":\"bridgeStatuses\",\"outputs\":[{\"internalType\":\"enum IFastBridgeV2.BridgeStatus\",\"name\":\"\",\"type\":\"uint8\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"name\":\"canClaim\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"claim\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"claim\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"}],\"name\":\"dispute\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"getBridgeTransaction\",\"outputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"originChainId\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"destChainId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"originSender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destRecipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"originFeeAmount\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"sendChainGas\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"}],\"internalType\":\"struct IFastBridge.BridgeTransaction\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"getBridgeTransactionV2\",\"outputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"originChainId\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"destChainId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"originSender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destRecipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"originFeeAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"callValue\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"exclusivityRelayer\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"exclusivityEndTime\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"callParams\",\"type\":\"bytes\"}],\"internalType\":\"struct IFastBridgeV2.BridgeTransactionV2\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"destTxHash\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"name\":\"prove\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"},{\"internalType\":\"bytes32\",\"name\":\"destTxHash\",\"type\":\"bytes32\"}],\"name\":\"prove\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"refund\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"relay\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"},{\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"name\":\"relay\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{\"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256))\":{\"params\":{\"params\":\"The parameters required to bridge\"}},\"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256),(address,int256,bytes,uint256,bytes))\":{\"params\":{\"params\":\"The parameters required to bridge\",\"paramsV2\":\"The parameters for exclusivity fill rights (optional, can be left empty)\"}},\"bridgeProofs(bytes32)\":{\"params\":{\"transactionId\":\"The ID of the bridge transaction\"},\"returns\":{\"relayer\":\"The relayer address of the bridge proof\",\"timestamp\":\"The timestamp of the bridge proof\"}},\"bridgeRelays(bytes32)\":{\"params\":{\"transactionId\":\"The ID of the transaction to check\"},\"returns\":{\"_0\":\"True if the transaction has been relayed, false otherwise\"}},\"bridgeStatuses(bytes32)\":{\"params\":{\"transactionId\":\"The ID of the bridge transaction\"},\"returns\":{\"_0\":\"BridgeStatus Status of the bridge transaction\"}},\"canClaim(bytes32,address)\":{\"params\":{\"relayer\":\"The address of the relayer attempting to claim\",\"transactionId\":\"The transaction id associated with the encoded bridge transaction to check\"}},\"claim(bytes)\":{\"params\":{\"request\":\"The encoded bridge transaction to claim on origin chain\"}},\"claim(bytes,address)\":{\"params\":{\"request\":\"The encoded bridge transaction to claim on origin chain\",\"to\":\"The recipient address of the funds\"}},\"dispute(bytes32)\":{\"params\":{\"transactionId\":\"The transaction id associated with the encoded bridge transaction to dispute\"}},\"getBridgeTransaction(bytes)\":{\"params\":{\"request\":\"The bridge request to decode\"}},\"getBridgeTransactionV2(bytes)\":{\"params\":{\"request\":\"The bridge request to decode\"}},\"prove(bytes,bytes32)\":{\"params\":{\"destTxHash\":\"The destination tx hash proving bridge transaction was relayed\",\"request\":\"The encoded bridge transaction to prove on origin chain\"}},\"prove(bytes32,bytes32,address)\":{\"params\":{\"destTxHash\":\"The destination tx hash proving bridge transaction was relayed\",\"relayer\":\"The address of the relaying entity which should have control of the origin funds when claimed\",\"transactionId\":\"The transaction id associated with the encoded bridge transaction to prove\"}},\"refund(bytes)\":{\"params\":{\"request\":\"The encoded bridge transaction to refund\"}},\"relay(bytes)\":{\"params\":{\"request\":\"The encoded bridge transaction to relay on destination chain\"}},\"relay(bytes,address)\":{\"params\":{\"relayer\":\"The address of the relaying entity which should have control of the origin funds when claimed\",\"request\":\"The encoded bridge transaction to relay on destination chain\"}}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256))\":{\"notice\":\"Initiates bridge on origin chain to be relayed by off-chain relayer\"},\"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256),(address,int256,bytes,uint256,bytes))\":{\"notice\":\"Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability to provide temporary exclusivity fill rights for the quote relayer.\"},\"bridgeProofs(bytes32)\":{\"notice\":\"Returns the timestamp and relayer of a bridge proof\"},\"bridgeRelays(bytes32)\":{\"notice\":\"Checks if a transaction has been relayed\"},\"bridgeStatuses(bytes32)\":{\"notice\":\"Returns the status of a bridge transaction\"},\"canClaim(bytes32,address)\":{\"notice\":\"Checks if the dispute period has passed so bridge deposit can be claimed\"},\"claim(bytes)\":{\"notice\":\"Completes bridge transaction on origin chain by claiming originally deposited capital.Can only send funds to the relayer address on the proof.\"},\"claim(bytes,address)\":{\"notice\":\"Completes bridge transaction on origin chain by claiming originally deposited capital\"},\"dispute(bytes32)\":{\"notice\":\"Disputes an outstanding proof in case relayer provided dest chain tx is invalid\"},\"getBridgeTransaction(bytes)\":{\"notice\":\"Decodes bridge request into a bridge transaction\"},\"getBridgeTransactionV2(bytes)\":{\"notice\":\"Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\"},\"prove(bytes,bytes32)\":{\"notice\":\"Provides proof on origin side that relayer provided funds on destination side of bridge transaction\"},\"prove(bytes32,bytes32,address)\":{\"notice\":\"Provides proof on origin side that relayer provided funds on destination side of bridge transaction\"},\"refund(bytes)\":{\"notice\":\"Refunds an outstanding bridge transaction in case optimistic bridging failed\"},\"relay(bytes)\":{\"notice\":\"Relays destination side of bridge transaction by off-chain relayer\"},\"relay(bytes,address)\":{\"notice\":\"Relays destination side of bridge transaction by off-chain relayer\"}},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeV2.sol\":\"IFastBridgeV2\"},\"evmVersion\":\"shanghai\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeV2.sol\":{\"keccak256\":\"0x7cd0f885e80e2bdaa638bc32ae7af7d2e248f99ce4b354c217d0f0f7d7302e0a\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://7ccf28df0bd7b4606986585acd8622ed9b4e81379690061bb66088f0a2270af1\",\"dweb:/ipfs/QmTf7HNdHZkK6vmx8ZgewycQEb72oLD9nPwBpsM5reMstQ\"]}},\"version\":1}"},"hashes":{"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256))":"45851694","bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256),(address,int256,bytes,uint256,bytes))":"bfc7c607","bridgeProofs(bytes32)":"91ad5039","bridgeRelays(bytes32)":"8379a24f","bridgeStatuses(bytes32)":"051287bc","canClaim(bytes32,address)":"aa9641ab","claim(bytes)":"c63ff8dd","claim(bytes,address)":"41fcb612","dispute(bytes32)":"add98c70","getBridgeTransaction(bytes)":"ac11fb1a","getBridgeTransactionV2(bytes)":"5aa6ccba","prove(bytes,bytes32)":"886d36ff","prove(bytes32,bytes32,address)":"18e4357d","refund(bytes)":"5eb7d946","relay(bytes)":"8f0d6f17","relay(bytes,address)":"9c9545f0"}},"solidity/FastBridgeV2.sol:IFastBridgeV2Errors":{"code":"0x","runtime-code":"0x","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.24 ^0.8.0 ^0.8.20;\n\n// contracts/interfaces/IAdmin.sol\n\ninterface IAdmin {\n // ============ Events ============\n\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n event ChainGasAmountUpdated(uint256 oldChainGasAmount, uint256 newChainGasAmount);\n\n // ============ Methods ============\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n\n function setChainGasAmount(uint256 newChainGasAmount) external;\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IFastBridgeRecipient.sol\n\ninterface IFastBridgeRecipient {\n function fastBridgeTransferReceived(\n address token,\n uint256 amount,\n bytes memory callParams\n )\n external\n payable\n returns (bytes4);\n}\n\n// contracts/interfaces/IFastBridgeV2Errors.sol\n\ninterface IFastBridgeV2Errors {\n error AmountIncorrect();\n error CallParamsLengthAboveMax();\n error ChainIncorrect();\n error ExclusivityParamsIncorrect();\n error MsgValueIncorrect();\n error NativeTokenCallValueNotSupported();\n error SenderIncorrect();\n error StatusIncorrect();\n error ZeroAddress();\n\n error RecipientIncorrectReturnValue();\n error RecipientNoReturnValue();\n\n error DeadlineExceeded();\n error DeadlineNotExceeded();\n error DeadlineTooShort();\n error DisputePeriodNotPassed();\n error DisputePeriodPassed();\n error ExclusivityPeriodNotPassed();\n\n error TransactionRelayed();\n}\n\n// contracts/libs/Errors.sol\n\nerror DeadlineExceeded();\nerror DeadlineNotExceeded();\nerror DeadlineTooShort();\nerror InsufficientOutputAmount();\n\nerror MsgValueIncorrect();\nerror PoolNotFound();\nerror TokenAddressMismatch();\nerror TokenNotContract();\nerror TokenNotETH();\nerror TokensIdentical();\n\nerror ChainIncorrect();\nerror AmountIncorrect();\nerror ZeroAddress();\n\nerror DisputePeriodNotPassed();\nerror DisputePeriodPassed();\nerror SenderIncorrect();\nerror StatusIncorrect();\nerror TransactionIdIncorrect();\nerror TransactionRelayed();\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// contracts/interfaces/IFastBridgeV2.sol\n\ninterface IFastBridgeV2 is IFastBridge {\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n struct BridgeTxDetails {\n BridgeStatus status;\n uint40 proofBlockTimestamp;\n uint48 proofBlockNumber;\n address proofRelayer;\n }\n\n struct BridgeRelay {\n uint48 blockNumber;\n uint48 blockTimestamp;\n address relayer;\n }\n\n /// @notice New params introduced in the FastBridgeV2.\n /// We are passing fields from the older BridgeParams struct outside of this struct\n /// for backwards compatibility.\n /// Note: quoteRelayer and quoteExclusivitySeconds are either both zero (indicating no exclusivity)\n /// or both non-zero (indicating exclusivity for the given period).\n /// Note: callValue \u003e 0 can NOT be used with destToken = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE (ETH_ADDRESS)\n /// @param quoteRelayer Relayer that provided the quote for the transaction\n /// @param quoteExclusivitySeconds Period of time the quote relayer is guaranteed exclusivity after user's deposit\n /// @param quoteId Unique quote identifier used for tracking the quote\n /// @param callValue ETH value to send to the recipient (if any)\n /// @param callParams Parameters for the arbitrary call to the destination recipient (if any)\n struct BridgeParamsV2 {\n address quoteRelayer;\n int256 quoteExclusivitySeconds;\n bytes quoteId;\n uint256 callValue;\n bytes callParams;\n }\n\n /// @notice Updated bridge transaction struct to include parameters introduced in FastBridgeV2.\n /// Note: only `exclusivityRelayer` can fill such a transaction until `exclusivityEndTime`.\n /// TODO: consider changing the encoding scheme to prevent spending extra gas on decoding.\n struct BridgeTransactionV2 {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n uint256 callValue; // ETH value to send to the recipient (if any) - replaces V1's sendChainGas flag\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n address exclusivityRelayer;\n uint256 exclusivityEndTime;\n bytes callParams;\n }\n\n event BridgeQuoteDetails(bytes32 indexed transactionId, bytes quoteId);\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability\n /// to provide temporary exclusivity fill rights for the quote relayer.\n /// @param params The parameters required to bridge\n /// @param paramsV2 The parameters for exclusivity fill rights (optional, can be left empty)\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function relay(bytes memory request, address relayer) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param transactionId The transaction id associated with the encoded bridge transaction to prove\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital.\n /// @notice Can only send funds to the relayer address on the proof.\n /// @param request The encoded bridge transaction to claim on origin chain\n function claim(bytes memory request) external;\n /// @notice Checks if a transaction has been relayed\n /// @param transactionId The ID of the transaction to check\n /// @return True if the transaction has been relayed, false otherwise\n function bridgeRelays(bytes32 transactionId) external view returns (bool);\n\n /// @notice Returns the status of a bridge transaction\n /// @param transactionId The ID of the bridge transaction\n /// @return BridgeStatus Status of the bridge transaction\n function bridgeStatuses(bytes32 transactionId) external view returns (BridgeStatus);\n\n /// @notice Returns the timestamp and relayer of a bridge proof\n /// @param transactionId The ID of the bridge transaction\n /// @return timestamp The timestamp of the bridge proof\n /// @return relayer The relayer address of the bridge proof\n function bridgeProofs(bytes32 transactionId) external view returns (uint96 timestamp, address relayer);\n\n /// @notice Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\n /// @param request The bridge request to decode\n function getBridgeTransactionV2(bytes memory request) external view returns (BridgeTransactionV2 memory);\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// contracts/libs/UniversalToken.sol\n\nlibrary UniversalTokenLib {\n using SafeERC20 for IERC20;\n\n address internal constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Transfers tokens to the given account. Reverts if transfer is not successful.\n /// @dev This might trigger fallback, if ETH is transferred to the contract.\n /// Make sure this can not lead to reentrancy attacks.\n function universalTransfer(address token, address to, uint256 value) internal {\n // Don't do anything, if need to send tokens to this address\n if (to == address(this)) return;\n // Don't do anything, if trying to send zero value\n if (value == 0) return;\n if (token == ETH_ADDRESS) {\n /// @dev Note: this can potentially lead to executing code in `to`.\n // solhint-disable-next-line avoid-low-level-calls\n (bool success,) = to.call{value: value}(\"\");\n require(success, \"ETH transfer failed\");\n } else {\n IERC20(token).safeTransfer(to, value);\n }\n }\n\n /// @notice Issues an infinite allowance to the spender, if the current allowance is insufficient\n /// to spend the given amount.\n function universalApproveInfinity(address token, address spender, uint256 amountToSpend) internal {\n // ETH Chad doesn't require your approval\n if (token == ETH_ADDRESS) return;\n // No-op if allowance is already sufficient\n uint256 allowance = IERC20(token).allowance(address(this), spender);\n if (allowance \u003e= amountToSpend) return;\n // Otherwise, reset approval to 0 and set to max allowance\n if (allowance \u003e 0) IERC20(token).safeDecreaseAllowance(spender, allowance);\n IERC20(token).safeIncreaseAllowance(spender, type(uint256).max);\n }\n\n /// @notice Returns the balance of the given token (or native ETH) for the given account.\n function universalBalanceOf(address token, address account) internal view returns (uint256) {\n if (token == ETH_ADDRESS) {\n return account.balance;\n } else {\n return IERC20(token).balanceOf(account);\n }\n }\n\n /// @dev Checks that token is a contract and not ETH_ADDRESS.\n function assertIsContract(address token) internal view {\n // Check that ETH_ADDRESS was not used (in case this is a predeploy on any of the chains)\n if (token == UniversalTokenLib.ETH_ADDRESS) revert TokenNotContract();\n // Check that token is not an EOA\n if (token.code.length == 0) revert TokenNotContract();\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/Admin.sol\n\ncontract Admin is IAdmin, AccessControlEnumerable {\n using UniversalTokenLib for address;\n\n bytes32 public constant RELAYER_ROLE = keccak256(\"RELAYER_ROLE\");\n bytes32 public constant REFUNDER_ROLE = keccak256(\"REFUNDER_ROLE\");\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n uint256 public constant FEE_BPS = 1e6;\n uint256 public constant FEE_RATE_MAX = 0.01e6; // max 1% on origin amount\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Chain gas amount to forward as rebate if requested\n uint256 public chainGasAmount;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n }\n\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n require(newFeeRate \u003c= FEE_RATE_MAX, \"newFeeRate \u003e max\");\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n token.universalTransfer(recipient, feeAmount);\n emit FeesSwept(token, recipient, feeAmount);\n }\n\n function setChainGasAmount(uint256 newChainGasAmount) external onlyRole(GOVERNOR_ROLE) {\n uint256 oldChainGasAmount = chainGasAmount;\n chainGasAmount = newChainGasAmount;\n emit ChainGasAmountUpdated(oldChainGasAmount, newChainGasAmount);\n }\n}\n\n// contracts/FastBridgeV2.sol\n\n/// @notice FastBridgeV2 is a contract for bridging tokens across chains.\ncontract FastBridgeV2 is Admin, IFastBridgeV2, IFastBridgeV2Errors {\n using SafeERC20 for IERC20;\n using UniversalTokenLib for address;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Delay for a transaction after which it could be permisionlessly refunded\n uint256 public constant REFUND_DELAY = 7 days;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n /// @notice Maximum length of accepted callParams\n uint256 public constant MAX_CALL_PARAMS_LENGTH = 2 ** 16 - 1;\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeTxDetails) public bridgeTxDetails;\n /// @notice Relay details on destination chain\n mapping(bytes32 =\u003e BridgeRelay) public bridgeRelayDetails;\n /// @notice Unique bridge nonces tracked per originSender\n mapping(address =\u003e uint256) public senderNonces;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Replaced by senderNonces\n uint256 public immutable nonce = 0;\n /// @notice the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n bridge({\n params: params,\n paramsV2: BridgeParamsV2({\n quoteRelayer: address(0),\n quoteExclusivitySeconds: 0,\n quoteId: bytes(\"\"),\n callValue: 0,\n callParams: bytes(\"\")\n })\n });\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes memory request) external payable {\n relay({request: request, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes memory request, bytes32 destTxHash) external {\n prove({transactionId: keccak256(request), destTxHash: destTxHash, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridgeV2\n function claim(bytes memory request) external {\n claim({request: request, to: address(0)});\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003e DISPUTE_PERIOD) {\n revert DisputePeriodPassed();\n }\n\n // @dev relayer gets slashed effectively if dest relay has gone thru\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n bridgeTxDetails[transactionId].proofRelayer = address(0);\n bridgeTxDetails[transactionId].proofBlockTimestamp = 0;\n bridgeTxDetails[transactionId].proofBlockNumber = 0;\n\n emit BridgeProofDisputed(transactionId, msg.sender);\n }\n\n /// @inheritdoc IFastBridge\n function refund(bytes memory request) external {\n bytes32 transactionId = keccak256(request);\n\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n\n if (bridgeTxDetails[transactionId].status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n\n if (hasRole(REFUNDER_ROLE, msg.sender)) {\n // Refunder can refund if deadline has passed\n if (block.timestamp \u003c= transaction.deadline) revert DeadlineNotExceeded();\n } else {\n // Permissionless refund is allowed after REFUND_DELAY\n if (block.timestamp \u003c= transaction.deadline + REFUND_DELAY) revert DeadlineNotExceeded();\n }\n\n // if all checks passed, set to REFUNDED status\n bridgeTxDetails[transactionId].status = BridgeStatus.REFUNDED;\n\n // transfer origin collateral back to original sender\n address to = transaction.originSender;\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount + transaction.originFeeAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (bridgeTxDetails[transactionId].proofRelayer != relayer) revert SenderIncorrect();\n return _timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n /// @dev This method is added to achieve backwards compatibility with decoding requests into V1 structs:\n /// - `callValue` is partially reported as a zero/non-zero flag\n /// - `callParams` is ignored\n /// In order to process all kinds of requests use getBridgeTransactionV2 instead.\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory) {\n // Try decoding into V2 struct first. This will revert if V1 struct is passed\n try this.getBridgeTransactionV2(request) returns (BridgeTransactionV2 memory txV2) {\n // Note: we entirely ignore the callParams field, as it was not present in V1\n return BridgeTransaction({\n originChainId: txV2.originChainId,\n destChainId: txV2.destChainId,\n originSender: txV2.originSender,\n destRecipient: txV2.destRecipient,\n originToken: txV2.originToken,\n destToken: txV2.destToken,\n originAmount: txV2.originAmount,\n destAmount: txV2.destAmount,\n originFeeAmount: txV2.originFeeAmount,\n sendChainGas: txV2.callValue != 0,\n deadline: txV2.deadline,\n nonce: txV2.nonce\n });\n } catch {\n // Fallback to V1 struct\n return abi.decode(request, (BridgeTransaction));\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) public payable {\n int256 exclusivityEndTime = int256(block.timestamp) + paramsV2.quoteExclusivitySeconds;\n _validateBridgeParams(params, paramsV2, exclusivityEndTime);\n\n // transfer tokens to bridge contract\n /// @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _pullToken(params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n\n // set status to requested\n bytes memory request = abi.encode(\n BridgeTransactionV2({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n callValue: paramsV2.callValue,\n deadline: params.deadline,\n nonce: senderNonces[params.sender]++, // increment nonce on every bridge\n exclusivityRelayer: paramsV2.quoteRelayer,\n // We checked exclusivityEndTime to be in range (0 .. params.deadline] above, so can safely cast\n exclusivityEndTime: uint256(exclusivityEndTime),\n callParams: paramsV2.callParams\n })\n );\n bytes32 transactionId = keccak256(request);\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n\n emit BridgeRequested({\n transactionId: transactionId,\n sender: params.sender,\n request: request,\n destChainId: params.dstChainId,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n sendChainGas: paramsV2.callValue != 0\n });\n emit BridgeQuoteDetails(transactionId, paramsV2.quoteId);\n }\n\n /// @inheritdoc IFastBridgeV2\n function relay(bytes memory request, address relayer) public payable {\n bytes32 transactionId = keccak256(request);\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n _validateRelayParams(transaction, transactionId, relayer);\n // mark bridge transaction as relayed\n bridgeRelayDetails[transactionId] =\n BridgeRelay({blockNumber: uint48(block.number), blockTimestamp: uint48(block.timestamp), relayer: relayer});\n\n // transfer tokens to recipient on destination chain and do an arbitrary call if requested\n address to = transaction.destRecipient;\n address token = transaction.destToken;\n uint256 amount = transaction.destAmount;\n\n // All state changes have been done at this point, can proceed to the external calls.\n // This follows the checks-effects-interactions pattern to mitigate potential reentrancy attacks.\n if (token == UniversalTokenLib.ETH_ADDRESS) {\n // For ETH non-zero callValue is not allowed\n if (transaction.callValue != 0) revert NativeTokenCallValueNotSupported();\n // Check that the correct msg.value was sent\n if (msg.value != amount) revert MsgValueIncorrect();\n } else {\n // For ERC20s, we check that the correct msg.value was sent\n if (msg.value != transaction.callValue) revert MsgValueIncorrect();\n // We need to transfer the tokens from the Relayer to the recipient first before performing an\n // optional post-transfer arbitrary call.\n IERC20(token).safeTransferFrom(msg.sender, to, amount);\n }\n\n if (transaction.callParams.length != 0) {\n // Arbitrary call requested, perform it while supplying full msg.value to the recipient\n // Note: if token has a fee on transfers, the recipient will have received less than `amount`.\n // This is a very niche edge case and should be handled by the recipient contract.\n _checkedCallRecipient({recipient: to, token: token, amount: amount, callParams: transaction.callParams});\n } else if (msg.value != 0) {\n // No arbitrary call requested, but msg.value was sent. This is either a relay with ETH,\n // or a non-zero callValue request with an ERC20. In both cases, transfer the ETH to the recipient.\n Address.sendValue(payable(to), msg.value);\n }\n\n emit BridgeRelayed({\n transactionId: transactionId,\n relayer: relayer,\n to: to,\n originChainId: transaction.originChainId,\n originToken: transaction.originToken,\n destToken: transaction.destToken,\n originAmount: transaction.originAmount,\n destAmount: transaction.destAmount,\n chainGasAmount: transaction.callValue\n });\n }\n\n /// @inheritdoc IFastBridgeV2\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) public onlyRole(RELAYER_ROLE) {\n // update bridge tx status given proof provided\n if (bridgeTxDetails[transactionId].status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n bridgeTxDetails[transactionId].status = BridgeStatus.RELAYER_PROVED;\n bridgeTxDetails[transactionId].proofBlockTimestamp = uint40(block.timestamp);\n bridgeTxDetails[transactionId].proofBlockNumber = uint48(block.number);\n bridgeTxDetails[transactionId].proofRelayer = relayer;\n\n emit BridgeProofProvided(transactionId, relayer, destTxHash);\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes memory request, address to) public {\n bytes32 transactionId = keccak256(request);\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n\n // update bridge tx status if able to claim origin collateral\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n\n // if \"to\" is zero addr, permissionlessly send funds to proven relayer\n if (to == address(0)) {\n to = bridgeTxDetails[transactionId].proofRelayer;\n } else if (bridgeTxDetails[transactionId].proofRelayer != msg.sender) {\n revert SenderIncorrect();\n }\n\n if (_timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003c= DISPUTE_PERIOD) {\n revert DisputePeriodNotPassed();\n }\n\n bridgeTxDetails[transactionId].status = BridgeStatus.RELAYER_CLAIMED;\n\n // update protocol fees if origin fee amount exists\n if (transaction.originFeeAmount \u003e 0) protocolFees[transaction.originToken] += transaction.originFeeAmount;\n\n // transfer origin collateral less fee to specified address\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositClaimed(transactionId, bridgeTxDetails[transactionId].proofRelayer, to, token, amount);\n }\n\n function bridgeStatuses(bytes32 transactionId) public view returns (BridgeStatus status) {\n return bridgeTxDetails[transactionId].status;\n }\n\n function bridgeProofs(bytes32 transactionId) public view returns (uint96 timestamp, address relayer) {\n timestamp = bridgeTxDetails[transactionId].proofBlockTimestamp;\n relayer = bridgeTxDetails[transactionId].proofRelayer;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeRelays(bytes32 transactionId) public view returns (bool) {\n // has this transactionId been relayed?\n return bridgeRelayDetails[transactionId].relayer != address(0);\n }\n\n /// @inheritdoc IFastBridgeV2\n function getBridgeTransactionV2(bytes memory request) public pure returns (BridgeTransactionV2 memory) {\n return abi.decode(request, (BridgeTransactionV2));\n }\n\n /// @notice Pulls a requested token from the user to this contract.\n function _pullToken(address token, uint256 amount) internal returns (uint256 amountPulled) {\n if (token == UniversalTokenLib.ETH_ADDRESS) {\n // For ETH we just need to check that the supplied msg.value is correct\n if (amount != msg.value) revert MsgValueIncorrect();\n amountPulled = msg.value;\n } else {\n token.assertIsContract();\n // Record token balance before transfer\n amountPulled = IERC20(token).balanceOf(address(this));\n // Token needs to be pulled only if msg.value is zero\n // This way user can specify WETH as the origin asset\n IERC20(token).safeTransferFrom(msg.sender, address(this), amount);\n // Use the difference between the recorded balance and the current balance as the amountPulled\n amountPulled = IERC20(token).balanceOf(address(this)) - amountPulled;\n }\n }\n\n /// @notice Calls the Recipient's hook function with the specified callParams and performs\n /// all the necessary checks for the returned value.\n function _checkedCallRecipient(\n address recipient,\n address token,\n uint256 amount,\n bytes memory callParams\n )\n internal\n {\n bytes memory hookData =\n abi.encodeCall(IFastBridgeRecipient.fastBridgeTransferReceived, (token, amount, callParams));\n // This will bubble any revert messages from the hook function\n bytes memory returnData = Address.functionCallWithValue({target: recipient, data: hookData, value: msg.value});\n // Explicit revert if no return data at all\n if (returnData.length == 0) revert RecipientNoReturnValue();\n // Check that exactly a single return value was returned\n if (returnData.length != 32) revert RecipientIncorrectReturnValue();\n // Return value should be abi-encoded hook function selector\n if (bytes32(returnData) != bytes32(IFastBridgeRecipient.fastBridgeTransferReceived.selector)) {\n revert RecipientIncorrectReturnValue();\n }\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint40(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint40).max but\n /// proof.timestamp \u003c type(uint40).max via unchecked statement\n /// @param proofBlockTimestamp The bridge proof block timestamp\n /// @return delta Time delta since proof submitted\n function _timeSince(uint40 proofBlockTimestamp) internal view returns (uint256 delta) {\n unchecked {\n delta = uint40(block.timestamp) - proofBlockTimestamp;\n }\n }\n\n /// @notice Performs all the necessary checks for a bridge to happen.\n /// @dev There's no good way to refactor this function to reduce cyclomatic complexity due to\n /// the number of checks that need to be performed, so we skip the code-complexity rule here.\n // solhint-disable-next-line code-complexity\n function _validateBridgeParams(\n BridgeParams memory params,\n BridgeParamsV2 memory paramsV2,\n int256 exclusivityEndTime\n )\n internal\n view\n {\n // Check V1 (legacy) params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.sender == address(0) || params.to == address(0)) revert ZeroAddress();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n // Check V2 params\n if (paramsV2.callParams.length \u003e MAX_CALL_PARAMS_LENGTH) revert CallParamsLengthAboveMax();\n if (paramsV2.callValue != 0 \u0026\u0026 params.destToken == UniversalTokenLib.ETH_ADDRESS) {\n revert NativeTokenCallValueNotSupported();\n }\n // exclusivityEndTime must be in range (0 .. params.deadline]\n if (exclusivityEndTime \u003c= 0 || exclusivityEndTime \u003e int256(params.deadline)) {\n revert ExclusivityParamsIncorrect();\n }\n }\n\n /// @notice Performs all the necessary checks for a relay to happen.\n function _validateRelayParams(\n BridgeTransactionV2 memory transaction,\n bytes32 transactionId,\n address relayer\n )\n internal\n view\n {\n if (relayer == address(0)) revert ZeroAddress();\n // Check if the transaction has already been relayed\n if (bridgeRelays(transactionId)) revert TransactionRelayed();\n if (transaction.destChainId != uint32(block.chainid)) revert ChainIncorrect();\n // Check the deadline for relay to happen\n if (block.timestamp \u003e transaction.deadline) revert DeadlineExceeded();\n // Check the exclusivity period, if it is still ongoing\n // forgefmt: disable-next-item\n if (\n transaction.exclusivityRelayer != address(0) \u0026\u0026\n transaction.exclusivityRelayer != relayer \u0026\u0026\n block.timestamp \u003c= transaction.exclusivityEndTime\n ) {\n revert ExclusivityPeriodNotPassed();\n }\n }\n}\n","language":"Solidity","languageVersion":"0.8.24","compilerVersion":"0.8.24","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../","srcMap":"","srcMapRuntime":"","abiDefinition":[{"inputs":[],"name":"AmountIncorrect","type":"error"},{"inputs":[],"name":"CallParamsLengthAboveMax","type":"error"},{"inputs":[],"name":"ChainIncorrect","type":"error"},{"inputs":[],"name":"DeadlineExceeded","type":"error"},{"inputs":[],"name":"DeadlineNotExceeded","type":"error"},{"inputs":[],"name":"DeadlineTooShort","type":"error"},{"inputs":[],"name":"DisputePeriodNotPassed","type":"error"},{"inputs":[],"name":"DisputePeriodPassed","type":"error"},{"inputs":[],"name":"ExclusivityParamsIncorrect","type":"error"},{"inputs":[],"name":"ExclusivityPeriodNotPassed","type":"error"},{"inputs":[],"name":"MsgValueIncorrect","type":"error"},{"inputs":[],"name":"NativeTokenCallValueNotSupported","type":"error"},{"inputs":[],"name":"RecipientIncorrectReturnValue","type":"error"},{"inputs":[],"name":"RecipientNoReturnValue","type":"error"},{"inputs":[],"name":"SenderIncorrect","type":"error"},{"inputs":[],"name":"StatusIncorrect","type":"error"},{"inputs":[],"name":"TransactionRelayed","type":"error"},{"inputs":[],"name":"ZeroAddress","type":"error"}],"userDoc":{"kind":"user","methods":{},"version":1},"developerDoc":{"kind":"dev","methods":{},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[],\"name\":\"AmountIncorrect\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"CallParamsLengthAboveMax\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ChainIncorrect\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DeadlineExceeded\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DeadlineNotExceeded\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DeadlineTooShort\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DisputePeriodNotPassed\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DisputePeriodPassed\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ExclusivityParamsIncorrect\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ExclusivityPeriodNotPassed\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"MsgValueIncorrect\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"NativeTokenCallValueNotSupported\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"RecipientIncorrectReturnValue\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"RecipientNoReturnValue\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"SenderIncorrect\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"StatusIncorrect\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"TransactionRelayed\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ZeroAddress\",\"type\":\"error\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeV2.sol\":\"IFastBridgeV2Errors\"},\"evmVersion\":\"shanghai\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeV2.sol\":{\"keccak256\":\"0x7cd0f885e80e2bdaa638bc32ae7af7d2e248f99ce4b354c217d0f0f7d7302e0a\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://7ccf28df0bd7b4606986585acd8622ed9b4e81379690061bb66088f0a2270af1\",\"dweb:/ipfs/QmTf7HNdHZkK6vmx8ZgewycQEb72oLD9nPwBpsM5reMstQ\"]}},\"version\":1}"},"hashes":{}},"solidity/FastBridgeV2.sol:SafeERC20":{"code":"0x60556032600b8282823980515f1a607314602657634e487b7160e01b5f525f60045260245ffd5b305f52607381538281f3fe730000000000000000000000000000000000000000301460806040525f80fdfea26469706673582212206104d055d945cd85c5e0a242eb38679d97b94eed1093fc3540437ea8fe4ace7364736f6c63430008180033","runtime-code":"0x730000000000000000000000000000000000000000301460806040525f80fdfea26469706673582212206104d055d945cd85c5e0a242eb38679d97b94eed1093fc3540437ea8fe4ace7364736f6c63430008180033","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.24 ^0.8.0 ^0.8.20;\n\n// contracts/interfaces/IAdmin.sol\n\ninterface IAdmin {\n // ============ Events ============\n\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n event ChainGasAmountUpdated(uint256 oldChainGasAmount, uint256 newChainGasAmount);\n\n // ============ Methods ============\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n\n function setChainGasAmount(uint256 newChainGasAmount) external;\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IFastBridgeRecipient.sol\n\ninterface IFastBridgeRecipient {\n function fastBridgeTransferReceived(\n address token,\n uint256 amount,\n bytes memory callParams\n )\n external\n payable\n returns (bytes4);\n}\n\n// contracts/interfaces/IFastBridgeV2Errors.sol\n\ninterface IFastBridgeV2Errors {\n error AmountIncorrect();\n error CallParamsLengthAboveMax();\n error ChainIncorrect();\n error ExclusivityParamsIncorrect();\n error MsgValueIncorrect();\n error NativeTokenCallValueNotSupported();\n error SenderIncorrect();\n error StatusIncorrect();\n error ZeroAddress();\n\n error RecipientIncorrectReturnValue();\n error RecipientNoReturnValue();\n\n error DeadlineExceeded();\n error DeadlineNotExceeded();\n error DeadlineTooShort();\n error DisputePeriodNotPassed();\n error DisputePeriodPassed();\n error ExclusivityPeriodNotPassed();\n\n error TransactionRelayed();\n}\n\n// contracts/libs/Errors.sol\n\nerror DeadlineExceeded();\nerror DeadlineNotExceeded();\nerror DeadlineTooShort();\nerror InsufficientOutputAmount();\n\nerror MsgValueIncorrect();\nerror PoolNotFound();\nerror TokenAddressMismatch();\nerror TokenNotContract();\nerror TokenNotETH();\nerror TokensIdentical();\n\nerror ChainIncorrect();\nerror AmountIncorrect();\nerror ZeroAddress();\n\nerror DisputePeriodNotPassed();\nerror DisputePeriodPassed();\nerror SenderIncorrect();\nerror StatusIncorrect();\nerror TransactionIdIncorrect();\nerror TransactionRelayed();\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// contracts/interfaces/IFastBridgeV2.sol\n\ninterface IFastBridgeV2 is IFastBridge {\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n struct BridgeTxDetails {\n BridgeStatus status;\n uint40 proofBlockTimestamp;\n uint48 proofBlockNumber;\n address proofRelayer;\n }\n\n struct BridgeRelay {\n uint48 blockNumber;\n uint48 blockTimestamp;\n address relayer;\n }\n\n /// @notice New params introduced in the FastBridgeV2.\n /// We are passing fields from the older BridgeParams struct outside of this struct\n /// for backwards compatibility.\n /// Note: quoteRelayer and quoteExclusivitySeconds are either both zero (indicating no exclusivity)\n /// or both non-zero (indicating exclusivity for the given period).\n /// Note: callValue \u003e 0 can NOT be used with destToken = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE (ETH_ADDRESS)\n /// @param quoteRelayer Relayer that provided the quote for the transaction\n /// @param quoteExclusivitySeconds Period of time the quote relayer is guaranteed exclusivity after user's deposit\n /// @param quoteId Unique quote identifier used for tracking the quote\n /// @param callValue ETH value to send to the recipient (if any)\n /// @param callParams Parameters for the arbitrary call to the destination recipient (if any)\n struct BridgeParamsV2 {\n address quoteRelayer;\n int256 quoteExclusivitySeconds;\n bytes quoteId;\n uint256 callValue;\n bytes callParams;\n }\n\n /// @notice Updated bridge transaction struct to include parameters introduced in FastBridgeV2.\n /// Note: only `exclusivityRelayer` can fill such a transaction until `exclusivityEndTime`.\n /// TODO: consider changing the encoding scheme to prevent spending extra gas on decoding.\n struct BridgeTransactionV2 {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n uint256 callValue; // ETH value to send to the recipient (if any) - replaces V1's sendChainGas flag\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n address exclusivityRelayer;\n uint256 exclusivityEndTime;\n bytes callParams;\n }\n\n event BridgeQuoteDetails(bytes32 indexed transactionId, bytes quoteId);\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability\n /// to provide temporary exclusivity fill rights for the quote relayer.\n /// @param params The parameters required to bridge\n /// @param paramsV2 The parameters for exclusivity fill rights (optional, can be left empty)\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function relay(bytes memory request, address relayer) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param transactionId The transaction id associated with the encoded bridge transaction to prove\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital.\n /// @notice Can only send funds to the relayer address on the proof.\n /// @param request The encoded bridge transaction to claim on origin chain\n function claim(bytes memory request) external;\n /// @notice Checks if a transaction has been relayed\n /// @param transactionId The ID of the transaction to check\n /// @return True if the transaction has been relayed, false otherwise\n function bridgeRelays(bytes32 transactionId) external view returns (bool);\n\n /// @notice Returns the status of a bridge transaction\n /// @param transactionId The ID of the bridge transaction\n /// @return BridgeStatus Status of the bridge transaction\n function bridgeStatuses(bytes32 transactionId) external view returns (BridgeStatus);\n\n /// @notice Returns the timestamp and relayer of a bridge proof\n /// @param transactionId The ID of the bridge transaction\n /// @return timestamp The timestamp of the bridge proof\n /// @return relayer The relayer address of the bridge proof\n function bridgeProofs(bytes32 transactionId) external view returns (uint96 timestamp, address relayer);\n\n /// @notice Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\n /// @param request The bridge request to decode\n function getBridgeTransactionV2(bytes memory request) external view returns (BridgeTransactionV2 memory);\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// contracts/libs/UniversalToken.sol\n\nlibrary UniversalTokenLib {\n using SafeERC20 for IERC20;\n\n address internal constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Transfers tokens to the given account. Reverts if transfer is not successful.\n /// @dev This might trigger fallback, if ETH is transferred to the contract.\n /// Make sure this can not lead to reentrancy attacks.\n function universalTransfer(address token, address to, uint256 value) internal {\n // Don't do anything, if need to send tokens to this address\n if (to == address(this)) return;\n // Don't do anything, if trying to send zero value\n if (value == 0) return;\n if (token == ETH_ADDRESS) {\n /// @dev Note: this can potentially lead to executing code in `to`.\n // solhint-disable-next-line avoid-low-level-calls\n (bool success,) = to.call{value: value}(\"\");\n require(success, \"ETH transfer failed\");\n } else {\n IERC20(token).safeTransfer(to, value);\n }\n }\n\n /// @notice Issues an infinite allowance to the spender, if the current allowance is insufficient\n /// to spend the given amount.\n function universalApproveInfinity(address token, address spender, uint256 amountToSpend) internal {\n // ETH Chad doesn't require your approval\n if (token == ETH_ADDRESS) return;\n // No-op if allowance is already sufficient\n uint256 allowance = IERC20(token).allowance(address(this), spender);\n if (allowance \u003e= amountToSpend) return;\n // Otherwise, reset approval to 0 and set to max allowance\n if (allowance \u003e 0) IERC20(token).safeDecreaseAllowance(spender, allowance);\n IERC20(token).safeIncreaseAllowance(spender, type(uint256).max);\n }\n\n /// @notice Returns the balance of the given token (or native ETH) for the given account.\n function universalBalanceOf(address token, address account) internal view returns (uint256) {\n if (token == ETH_ADDRESS) {\n return account.balance;\n } else {\n return IERC20(token).balanceOf(account);\n }\n }\n\n /// @dev Checks that token is a contract and not ETH_ADDRESS.\n function assertIsContract(address token) internal view {\n // Check that ETH_ADDRESS was not used (in case this is a predeploy on any of the chains)\n if (token == UniversalTokenLib.ETH_ADDRESS) revert TokenNotContract();\n // Check that token is not an EOA\n if (token.code.length == 0) revert TokenNotContract();\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/Admin.sol\n\ncontract Admin is IAdmin, AccessControlEnumerable {\n using UniversalTokenLib for address;\n\n bytes32 public constant RELAYER_ROLE = keccak256(\"RELAYER_ROLE\");\n bytes32 public constant REFUNDER_ROLE = keccak256(\"REFUNDER_ROLE\");\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n uint256 public constant FEE_BPS = 1e6;\n uint256 public constant FEE_RATE_MAX = 0.01e6; // max 1% on origin amount\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Chain gas amount to forward as rebate if requested\n uint256 public chainGasAmount;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n }\n\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n require(newFeeRate \u003c= FEE_RATE_MAX, \"newFeeRate \u003e max\");\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n token.universalTransfer(recipient, feeAmount);\n emit FeesSwept(token, recipient, feeAmount);\n }\n\n function setChainGasAmount(uint256 newChainGasAmount) external onlyRole(GOVERNOR_ROLE) {\n uint256 oldChainGasAmount = chainGasAmount;\n chainGasAmount = newChainGasAmount;\n emit ChainGasAmountUpdated(oldChainGasAmount, newChainGasAmount);\n }\n}\n\n// contracts/FastBridgeV2.sol\n\n/// @notice FastBridgeV2 is a contract for bridging tokens across chains.\ncontract FastBridgeV2 is Admin, IFastBridgeV2, IFastBridgeV2Errors {\n using SafeERC20 for IERC20;\n using UniversalTokenLib for address;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Delay for a transaction after which it could be permisionlessly refunded\n uint256 public constant REFUND_DELAY = 7 days;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n /// @notice Maximum length of accepted callParams\n uint256 public constant MAX_CALL_PARAMS_LENGTH = 2 ** 16 - 1;\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeTxDetails) public bridgeTxDetails;\n /// @notice Relay details on destination chain\n mapping(bytes32 =\u003e BridgeRelay) public bridgeRelayDetails;\n /// @notice Unique bridge nonces tracked per originSender\n mapping(address =\u003e uint256) public senderNonces;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Replaced by senderNonces\n uint256 public immutable nonce = 0;\n /// @notice the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n bridge({\n params: params,\n paramsV2: BridgeParamsV2({\n quoteRelayer: address(0),\n quoteExclusivitySeconds: 0,\n quoteId: bytes(\"\"),\n callValue: 0,\n callParams: bytes(\"\")\n })\n });\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes memory request) external payable {\n relay({request: request, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes memory request, bytes32 destTxHash) external {\n prove({transactionId: keccak256(request), destTxHash: destTxHash, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridgeV2\n function claim(bytes memory request) external {\n claim({request: request, to: address(0)});\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003e DISPUTE_PERIOD) {\n revert DisputePeriodPassed();\n }\n\n // @dev relayer gets slashed effectively if dest relay has gone thru\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n bridgeTxDetails[transactionId].proofRelayer = address(0);\n bridgeTxDetails[transactionId].proofBlockTimestamp = 0;\n bridgeTxDetails[transactionId].proofBlockNumber = 0;\n\n emit BridgeProofDisputed(transactionId, msg.sender);\n }\n\n /// @inheritdoc IFastBridge\n function refund(bytes memory request) external {\n bytes32 transactionId = keccak256(request);\n\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n\n if (bridgeTxDetails[transactionId].status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n\n if (hasRole(REFUNDER_ROLE, msg.sender)) {\n // Refunder can refund if deadline has passed\n if (block.timestamp \u003c= transaction.deadline) revert DeadlineNotExceeded();\n } else {\n // Permissionless refund is allowed after REFUND_DELAY\n if (block.timestamp \u003c= transaction.deadline + REFUND_DELAY) revert DeadlineNotExceeded();\n }\n\n // if all checks passed, set to REFUNDED status\n bridgeTxDetails[transactionId].status = BridgeStatus.REFUNDED;\n\n // transfer origin collateral back to original sender\n address to = transaction.originSender;\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount + transaction.originFeeAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (bridgeTxDetails[transactionId].proofRelayer != relayer) revert SenderIncorrect();\n return _timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n /// @dev This method is added to achieve backwards compatibility with decoding requests into V1 structs:\n /// - `callValue` is partially reported as a zero/non-zero flag\n /// - `callParams` is ignored\n /// In order to process all kinds of requests use getBridgeTransactionV2 instead.\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory) {\n // Try decoding into V2 struct first. This will revert if V1 struct is passed\n try this.getBridgeTransactionV2(request) returns (BridgeTransactionV2 memory txV2) {\n // Note: we entirely ignore the callParams field, as it was not present in V1\n return BridgeTransaction({\n originChainId: txV2.originChainId,\n destChainId: txV2.destChainId,\n originSender: txV2.originSender,\n destRecipient: txV2.destRecipient,\n originToken: txV2.originToken,\n destToken: txV2.destToken,\n originAmount: txV2.originAmount,\n destAmount: txV2.destAmount,\n originFeeAmount: txV2.originFeeAmount,\n sendChainGas: txV2.callValue != 0,\n deadline: txV2.deadline,\n nonce: txV2.nonce\n });\n } catch {\n // Fallback to V1 struct\n return abi.decode(request, (BridgeTransaction));\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) public payable {\n int256 exclusivityEndTime = int256(block.timestamp) + paramsV2.quoteExclusivitySeconds;\n _validateBridgeParams(params, paramsV2, exclusivityEndTime);\n\n // transfer tokens to bridge contract\n /// @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _pullToken(params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n\n // set status to requested\n bytes memory request = abi.encode(\n BridgeTransactionV2({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n callValue: paramsV2.callValue,\n deadline: params.deadline,\n nonce: senderNonces[params.sender]++, // increment nonce on every bridge\n exclusivityRelayer: paramsV2.quoteRelayer,\n // We checked exclusivityEndTime to be in range (0 .. params.deadline] above, so can safely cast\n exclusivityEndTime: uint256(exclusivityEndTime),\n callParams: paramsV2.callParams\n })\n );\n bytes32 transactionId = keccak256(request);\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n\n emit BridgeRequested({\n transactionId: transactionId,\n sender: params.sender,\n request: request,\n destChainId: params.dstChainId,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n sendChainGas: paramsV2.callValue != 0\n });\n emit BridgeQuoteDetails(transactionId, paramsV2.quoteId);\n }\n\n /// @inheritdoc IFastBridgeV2\n function relay(bytes memory request, address relayer) public payable {\n bytes32 transactionId = keccak256(request);\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n _validateRelayParams(transaction, transactionId, relayer);\n // mark bridge transaction as relayed\n bridgeRelayDetails[transactionId] =\n BridgeRelay({blockNumber: uint48(block.number), blockTimestamp: uint48(block.timestamp), relayer: relayer});\n\n // transfer tokens to recipient on destination chain and do an arbitrary call if requested\n address to = transaction.destRecipient;\n address token = transaction.destToken;\n uint256 amount = transaction.destAmount;\n\n // All state changes have been done at this point, can proceed to the external calls.\n // This follows the checks-effects-interactions pattern to mitigate potential reentrancy attacks.\n if (token == UniversalTokenLib.ETH_ADDRESS) {\n // For ETH non-zero callValue is not allowed\n if (transaction.callValue != 0) revert NativeTokenCallValueNotSupported();\n // Check that the correct msg.value was sent\n if (msg.value != amount) revert MsgValueIncorrect();\n } else {\n // For ERC20s, we check that the correct msg.value was sent\n if (msg.value != transaction.callValue) revert MsgValueIncorrect();\n // We need to transfer the tokens from the Relayer to the recipient first before performing an\n // optional post-transfer arbitrary call.\n IERC20(token).safeTransferFrom(msg.sender, to, amount);\n }\n\n if (transaction.callParams.length != 0) {\n // Arbitrary call requested, perform it while supplying full msg.value to the recipient\n // Note: if token has a fee on transfers, the recipient will have received less than `amount`.\n // This is a very niche edge case and should be handled by the recipient contract.\n _checkedCallRecipient({recipient: to, token: token, amount: amount, callParams: transaction.callParams});\n } else if (msg.value != 0) {\n // No arbitrary call requested, but msg.value was sent. This is either a relay with ETH,\n // or a non-zero callValue request with an ERC20. In both cases, transfer the ETH to the recipient.\n Address.sendValue(payable(to), msg.value);\n }\n\n emit BridgeRelayed({\n transactionId: transactionId,\n relayer: relayer,\n to: to,\n originChainId: transaction.originChainId,\n originToken: transaction.originToken,\n destToken: transaction.destToken,\n originAmount: transaction.originAmount,\n destAmount: transaction.destAmount,\n chainGasAmount: transaction.callValue\n });\n }\n\n /// @inheritdoc IFastBridgeV2\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) public onlyRole(RELAYER_ROLE) {\n // update bridge tx status given proof provided\n if (bridgeTxDetails[transactionId].status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n bridgeTxDetails[transactionId].status = BridgeStatus.RELAYER_PROVED;\n bridgeTxDetails[transactionId].proofBlockTimestamp = uint40(block.timestamp);\n bridgeTxDetails[transactionId].proofBlockNumber = uint48(block.number);\n bridgeTxDetails[transactionId].proofRelayer = relayer;\n\n emit BridgeProofProvided(transactionId, relayer, destTxHash);\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes memory request, address to) public {\n bytes32 transactionId = keccak256(request);\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n\n // update bridge tx status if able to claim origin collateral\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n\n // if \"to\" is zero addr, permissionlessly send funds to proven relayer\n if (to == address(0)) {\n to = bridgeTxDetails[transactionId].proofRelayer;\n } else if (bridgeTxDetails[transactionId].proofRelayer != msg.sender) {\n revert SenderIncorrect();\n }\n\n if (_timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003c= DISPUTE_PERIOD) {\n revert DisputePeriodNotPassed();\n }\n\n bridgeTxDetails[transactionId].status = BridgeStatus.RELAYER_CLAIMED;\n\n // update protocol fees if origin fee amount exists\n if (transaction.originFeeAmount \u003e 0) protocolFees[transaction.originToken] += transaction.originFeeAmount;\n\n // transfer origin collateral less fee to specified address\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositClaimed(transactionId, bridgeTxDetails[transactionId].proofRelayer, to, token, amount);\n }\n\n function bridgeStatuses(bytes32 transactionId) public view returns (BridgeStatus status) {\n return bridgeTxDetails[transactionId].status;\n }\n\n function bridgeProofs(bytes32 transactionId) public view returns (uint96 timestamp, address relayer) {\n timestamp = bridgeTxDetails[transactionId].proofBlockTimestamp;\n relayer = bridgeTxDetails[transactionId].proofRelayer;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeRelays(bytes32 transactionId) public view returns (bool) {\n // has this transactionId been relayed?\n return bridgeRelayDetails[transactionId].relayer != address(0);\n }\n\n /// @inheritdoc IFastBridgeV2\n function getBridgeTransactionV2(bytes memory request) public pure returns (BridgeTransactionV2 memory) {\n return abi.decode(request, (BridgeTransactionV2));\n }\n\n /// @notice Pulls a requested token from the user to this contract.\n function _pullToken(address token, uint256 amount) internal returns (uint256 amountPulled) {\n if (token == UniversalTokenLib.ETH_ADDRESS) {\n // For ETH we just need to check that the supplied msg.value is correct\n if (amount != msg.value) revert MsgValueIncorrect();\n amountPulled = msg.value;\n } else {\n token.assertIsContract();\n // Record token balance before transfer\n amountPulled = IERC20(token).balanceOf(address(this));\n // Token needs to be pulled only if msg.value is zero\n // This way user can specify WETH as the origin asset\n IERC20(token).safeTransferFrom(msg.sender, address(this), amount);\n // Use the difference between the recorded balance and the current balance as the amountPulled\n amountPulled = IERC20(token).balanceOf(address(this)) - amountPulled;\n }\n }\n\n /// @notice Calls the Recipient's hook function with the specified callParams and performs\n /// all the necessary checks for the returned value.\n function _checkedCallRecipient(\n address recipient,\n address token,\n uint256 amount,\n bytes memory callParams\n )\n internal\n {\n bytes memory hookData =\n abi.encodeCall(IFastBridgeRecipient.fastBridgeTransferReceived, (token, amount, callParams));\n // This will bubble any revert messages from the hook function\n bytes memory returnData = Address.functionCallWithValue({target: recipient, data: hookData, value: msg.value});\n // Explicit revert if no return data at all\n if (returnData.length == 0) revert RecipientNoReturnValue();\n // Check that exactly a single return value was returned\n if (returnData.length != 32) revert RecipientIncorrectReturnValue();\n // Return value should be abi-encoded hook function selector\n if (bytes32(returnData) != bytes32(IFastBridgeRecipient.fastBridgeTransferReceived.selector)) {\n revert RecipientIncorrectReturnValue();\n }\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint40(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint40).max but\n /// proof.timestamp \u003c type(uint40).max via unchecked statement\n /// @param proofBlockTimestamp The bridge proof block timestamp\n /// @return delta Time delta since proof submitted\n function _timeSince(uint40 proofBlockTimestamp) internal view returns (uint256 delta) {\n unchecked {\n delta = uint40(block.timestamp) - proofBlockTimestamp;\n }\n }\n\n /// @notice Performs all the necessary checks for a bridge to happen.\n /// @dev There's no good way to refactor this function to reduce cyclomatic complexity due to\n /// the number of checks that need to be performed, so we skip the code-complexity rule here.\n // solhint-disable-next-line code-complexity\n function _validateBridgeParams(\n BridgeParams memory params,\n BridgeParamsV2 memory paramsV2,\n int256 exclusivityEndTime\n )\n internal\n view\n {\n // Check V1 (legacy) params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.sender == address(0) || params.to == address(0)) revert ZeroAddress();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n // Check V2 params\n if (paramsV2.callParams.length \u003e MAX_CALL_PARAMS_LENGTH) revert CallParamsLengthAboveMax();\n if (paramsV2.callValue != 0 \u0026\u0026 params.destToken == UniversalTokenLib.ETH_ADDRESS) {\n revert NativeTokenCallValueNotSupported();\n }\n // exclusivityEndTime must be in range (0 .. params.deadline]\n if (exclusivityEndTime \u003c= 0 || exclusivityEndTime \u003e int256(params.deadline)) {\n revert ExclusivityParamsIncorrect();\n }\n }\n\n /// @notice Performs all the necessary checks for a relay to happen.\n function _validateRelayParams(\n BridgeTransactionV2 memory transaction,\n bytes32 transactionId,\n address relayer\n )\n internal\n view\n {\n if (relayer == address(0)) revert ZeroAddress();\n // Check if the transaction has already been relayed\n if (bridgeRelays(transactionId)) revert TransactionRelayed();\n if (transaction.destChainId != uint32(block.chainid)) revert ChainIncorrect();\n // Check the deadline for relay to happen\n if (block.timestamp \u003e transaction.deadline) revert DeadlineExceeded();\n // Check the exclusivity period, if it is still ongoing\n // forgefmt: disable-next-item\n if (\n transaction.exclusivityRelayer != address(0) \u0026\u0026\n transaction.exclusivityRelayer != relayer \u0026\u0026\n block.timestamp \u003c= transaction.exclusivityEndTime\n ) {\n revert ExclusivityPeriodNotPassed();\n }\n }\n}\n","language":"Solidity","languageVersion":"0.8.24","compilerVersion":"0.8.24","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../","srcMap":"45745:5018:0:-:0;;;;;;;;;;;;;;;-1:-1:-1;;;45745:5018:0;;;;;;;;;;;;;;;;;","srcMapRuntime":"45745:5018:0:-:0;;;;;;;;","abiDefinition":[{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"currentAllowance","type":"uint256"},{"internalType":"uint256","name":"requestedDecrease","type":"uint256"}],"name":"SafeERC20FailedDecreaseAllowance","type":"error"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"SafeERC20FailedOperation","type":"error"}],"userDoc":{"kind":"user","methods":{},"version":1},"developerDoc":{"details":"Wrappers around ERC20 operations that throw on failure (when the token contract returns false). Tokens that return no value (and instead revert or throw on failure) are also supported, non-reverting calls are assumed to be successful. To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract, which allows you to call the safe operations as `token.safeTransfer(...)`, etc.","errors":{"SafeERC20FailedDecreaseAllowance(address,uint256,uint256)":[{"details":"Indicates a failed `decreaseAllowance` request."}],"SafeERC20FailedOperation(address)":[{"details":"An operation with an ERC20 token failed."}]},"kind":"dev","methods":{},"title":"SafeERC20","version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"currentAllowance\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"requestedDecrease\",\"type\":\"uint256\"}],\"name\":\"SafeERC20FailedDecreaseAllowance\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"}],\"name\":\"SafeERC20FailedOperation\",\"type\":\"error\"}],\"devdoc\":{\"details\":\"Wrappers around ERC20 operations that throw on failure (when the token contract returns false). Tokens that return no value (and instead revert or throw on failure) are also supported, non-reverting calls are assumed to be successful. To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract, which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\",\"errors\":{\"SafeERC20FailedDecreaseAllowance(address,uint256,uint256)\":[{\"details\":\"Indicates a failed `decreaseAllowance` request.\"}],\"SafeERC20FailedOperation(address)\":[{\"details\":\"An operation with an ERC20 token failed.\"}]},\"kind\":\"dev\",\"methods\":{},\"title\":\"SafeERC20\",\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeV2.sol\":\"SafeERC20\"},\"evmVersion\":\"shanghai\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeV2.sol\":{\"keccak256\":\"0x7cd0f885e80e2bdaa638bc32ae7af7d2e248f99ce4b354c217d0f0f7d7302e0a\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://7ccf28df0bd7b4606986585acd8622ed9b4e81379690061bb66088f0a2270af1\",\"dweb:/ipfs/QmTf7HNdHZkK6vmx8ZgewycQEb72oLD9nPwBpsM5reMstQ\"]}},\"version\":1}"},"hashes":{}},"solidity/FastBridgeV2.sol:UniversalTokenLib":{"code":"0x60556032600b8282823980515f1a607314602657634e487b7160e01b5f525f60045260245ffd5b305f52607381538281f3fe730000000000000000000000000000000000000000301460806040525f80fdfea2646970667358221220b863ead2f0a667d62ff1983d9a28f2cdc6740a5303e83e27e29c037676ea45c264736f6c63430008180033","runtime-code":"0x730000000000000000000000000000000000000000301460806040525f80fdfea2646970667358221220b863ead2f0a667d62ff1983d9a28f2cdc6740a5303e83e27e29c037676ea45c264736f6c63430008180033","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.24 ^0.8.0 ^0.8.20;\n\n// contracts/interfaces/IAdmin.sol\n\ninterface IAdmin {\n // ============ Events ============\n\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n event ChainGasAmountUpdated(uint256 oldChainGasAmount, uint256 newChainGasAmount);\n\n // ============ Methods ============\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n\n function setChainGasAmount(uint256 newChainGasAmount) external;\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IFastBridgeRecipient.sol\n\ninterface IFastBridgeRecipient {\n function fastBridgeTransferReceived(\n address token,\n uint256 amount,\n bytes memory callParams\n )\n external\n payable\n returns (bytes4);\n}\n\n// contracts/interfaces/IFastBridgeV2Errors.sol\n\ninterface IFastBridgeV2Errors {\n error AmountIncorrect();\n error CallParamsLengthAboveMax();\n error ChainIncorrect();\n error ExclusivityParamsIncorrect();\n error MsgValueIncorrect();\n error NativeTokenCallValueNotSupported();\n error SenderIncorrect();\n error StatusIncorrect();\n error ZeroAddress();\n\n error RecipientIncorrectReturnValue();\n error RecipientNoReturnValue();\n\n error DeadlineExceeded();\n error DeadlineNotExceeded();\n error DeadlineTooShort();\n error DisputePeriodNotPassed();\n error DisputePeriodPassed();\n error ExclusivityPeriodNotPassed();\n\n error TransactionRelayed();\n}\n\n// contracts/libs/Errors.sol\n\nerror DeadlineExceeded();\nerror DeadlineNotExceeded();\nerror DeadlineTooShort();\nerror InsufficientOutputAmount();\n\nerror MsgValueIncorrect();\nerror PoolNotFound();\nerror TokenAddressMismatch();\nerror TokenNotContract();\nerror TokenNotETH();\nerror TokensIdentical();\n\nerror ChainIncorrect();\nerror AmountIncorrect();\nerror ZeroAddress();\n\nerror DisputePeriodNotPassed();\nerror DisputePeriodPassed();\nerror SenderIncorrect();\nerror StatusIncorrect();\nerror TransactionIdIncorrect();\nerror TransactionRelayed();\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// contracts/interfaces/IFastBridgeV2.sol\n\ninterface IFastBridgeV2 is IFastBridge {\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n struct BridgeTxDetails {\n BridgeStatus status;\n uint40 proofBlockTimestamp;\n uint48 proofBlockNumber;\n address proofRelayer;\n }\n\n struct BridgeRelay {\n uint48 blockNumber;\n uint48 blockTimestamp;\n address relayer;\n }\n\n /// @notice New params introduced in the FastBridgeV2.\n /// We are passing fields from the older BridgeParams struct outside of this struct\n /// for backwards compatibility.\n /// Note: quoteRelayer and quoteExclusivitySeconds are either both zero (indicating no exclusivity)\n /// or both non-zero (indicating exclusivity for the given period).\n /// Note: callValue \u003e 0 can NOT be used with destToken = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE (ETH_ADDRESS)\n /// @param quoteRelayer Relayer that provided the quote for the transaction\n /// @param quoteExclusivitySeconds Period of time the quote relayer is guaranteed exclusivity after user's deposit\n /// @param quoteId Unique quote identifier used for tracking the quote\n /// @param callValue ETH value to send to the recipient (if any)\n /// @param callParams Parameters for the arbitrary call to the destination recipient (if any)\n struct BridgeParamsV2 {\n address quoteRelayer;\n int256 quoteExclusivitySeconds;\n bytes quoteId;\n uint256 callValue;\n bytes callParams;\n }\n\n /// @notice Updated bridge transaction struct to include parameters introduced in FastBridgeV2.\n /// Note: only `exclusivityRelayer` can fill such a transaction until `exclusivityEndTime`.\n /// TODO: consider changing the encoding scheme to prevent spending extra gas on decoding.\n struct BridgeTransactionV2 {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n uint256 callValue; // ETH value to send to the recipient (if any) - replaces V1's sendChainGas flag\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n address exclusivityRelayer;\n uint256 exclusivityEndTime;\n bytes callParams;\n }\n\n event BridgeQuoteDetails(bytes32 indexed transactionId, bytes quoteId);\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability\n /// to provide temporary exclusivity fill rights for the quote relayer.\n /// @param params The parameters required to bridge\n /// @param paramsV2 The parameters for exclusivity fill rights (optional, can be left empty)\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function relay(bytes memory request, address relayer) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param transactionId The transaction id associated with the encoded bridge transaction to prove\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital.\n /// @notice Can only send funds to the relayer address on the proof.\n /// @param request The encoded bridge transaction to claim on origin chain\n function claim(bytes memory request) external;\n /// @notice Checks if a transaction has been relayed\n /// @param transactionId The ID of the transaction to check\n /// @return True if the transaction has been relayed, false otherwise\n function bridgeRelays(bytes32 transactionId) external view returns (bool);\n\n /// @notice Returns the status of a bridge transaction\n /// @param transactionId The ID of the bridge transaction\n /// @return BridgeStatus Status of the bridge transaction\n function bridgeStatuses(bytes32 transactionId) external view returns (BridgeStatus);\n\n /// @notice Returns the timestamp and relayer of a bridge proof\n /// @param transactionId The ID of the bridge transaction\n /// @return timestamp The timestamp of the bridge proof\n /// @return relayer The relayer address of the bridge proof\n function bridgeProofs(bytes32 transactionId) external view returns (uint96 timestamp, address relayer);\n\n /// @notice Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\n /// @param request The bridge request to decode\n function getBridgeTransactionV2(bytes memory request) external view returns (BridgeTransactionV2 memory);\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// contracts/libs/UniversalToken.sol\n\nlibrary UniversalTokenLib {\n using SafeERC20 for IERC20;\n\n address internal constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Transfers tokens to the given account. Reverts if transfer is not successful.\n /// @dev This might trigger fallback, if ETH is transferred to the contract.\n /// Make sure this can not lead to reentrancy attacks.\n function universalTransfer(address token, address to, uint256 value) internal {\n // Don't do anything, if need to send tokens to this address\n if (to == address(this)) return;\n // Don't do anything, if trying to send zero value\n if (value == 0) return;\n if (token == ETH_ADDRESS) {\n /// @dev Note: this can potentially lead to executing code in `to`.\n // solhint-disable-next-line avoid-low-level-calls\n (bool success,) = to.call{value: value}(\"\");\n require(success, \"ETH transfer failed\");\n } else {\n IERC20(token).safeTransfer(to, value);\n }\n }\n\n /// @notice Issues an infinite allowance to the spender, if the current allowance is insufficient\n /// to spend the given amount.\n function universalApproveInfinity(address token, address spender, uint256 amountToSpend) internal {\n // ETH Chad doesn't require your approval\n if (token == ETH_ADDRESS) return;\n // No-op if allowance is already sufficient\n uint256 allowance = IERC20(token).allowance(address(this), spender);\n if (allowance \u003e= amountToSpend) return;\n // Otherwise, reset approval to 0 and set to max allowance\n if (allowance \u003e 0) IERC20(token).safeDecreaseAllowance(spender, allowance);\n IERC20(token).safeIncreaseAllowance(spender, type(uint256).max);\n }\n\n /// @notice Returns the balance of the given token (or native ETH) for the given account.\n function universalBalanceOf(address token, address account) internal view returns (uint256) {\n if (token == ETH_ADDRESS) {\n return account.balance;\n } else {\n return IERC20(token).balanceOf(account);\n }\n }\n\n /// @dev Checks that token is a contract and not ETH_ADDRESS.\n function assertIsContract(address token) internal view {\n // Check that ETH_ADDRESS was not used (in case this is a predeploy on any of the chains)\n if (token == UniversalTokenLib.ETH_ADDRESS) revert TokenNotContract();\n // Check that token is not an EOA\n if (token.code.length == 0) revert TokenNotContract();\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/Admin.sol\n\ncontract Admin is IAdmin, AccessControlEnumerable {\n using UniversalTokenLib for address;\n\n bytes32 public constant RELAYER_ROLE = keccak256(\"RELAYER_ROLE\");\n bytes32 public constant REFUNDER_ROLE = keccak256(\"REFUNDER_ROLE\");\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n uint256 public constant FEE_BPS = 1e6;\n uint256 public constant FEE_RATE_MAX = 0.01e6; // max 1% on origin amount\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Chain gas amount to forward as rebate if requested\n uint256 public chainGasAmount;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n }\n\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n require(newFeeRate \u003c= FEE_RATE_MAX, \"newFeeRate \u003e max\");\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n token.universalTransfer(recipient, feeAmount);\n emit FeesSwept(token, recipient, feeAmount);\n }\n\n function setChainGasAmount(uint256 newChainGasAmount) external onlyRole(GOVERNOR_ROLE) {\n uint256 oldChainGasAmount = chainGasAmount;\n chainGasAmount = newChainGasAmount;\n emit ChainGasAmountUpdated(oldChainGasAmount, newChainGasAmount);\n }\n}\n\n// contracts/FastBridgeV2.sol\n\n/// @notice FastBridgeV2 is a contract for bridging tokens across chains.\ncontract FastBridgeV2 is Admin, IFastBridgeV2, IFastBridgeV2Errors {\n using SafeERC20 for IERC20;\n using UniversalTokenLib for address;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Delay for a transaction after which it could be permisionlessly refunded\n uint256 public constant REFUND_DELAY = 7 days;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n /// @notice Maximum length of accepted callParams\n uint256 public constant MAX_CALL_PARAMS_LENGTH = 2 ** 16 - 1;\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeTxDetails) public bridgeTxDetails;\n /// @notice Relay details on destination chain\n mapping(bytes32 =\u003e BridgeRelay) public bridgeRelayDetails;\n /// @notice Unique bridge nonces tracked per originSender\n mapping(address =\u003e uint256) public senderNonces;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Replaced by senderNonces\n uint256 public immutable nonce = 0;\n /// @notice the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n bridge({\n params: params,\n paramsV2: BridgeParamsV2({\n quoteRelayer: address(0),\n quoteExclusivitySeconds: 0,\n quoteId: bytes(\"\"),\n callValue: 0,\n callParams: bytes(\"\")\n })\n });\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes memory request) external payable {\n relay({request: request, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes memory request, bytes32 destTxHash) external {\n prove({transactionId: keccak256(request), destTxHash: destTxHash, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridgeV2\n function claim(bytes memory request) external {\n claim({request: request, to: address(0)});\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003e DISPUTE_PERIOD) {\n revert DisputePeriodPassed();\n }\n\n // @dev relayer gets slashed effectively if dest relay has gone thru\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n bridgeTxDetails[transactionId].proofRelayer = address(0);\n bridgeTxDetails[transactionId].proofBlockTimestamp = 0;\n bridgeTxDetails[transactionId].proofBlockNumber = 0;\n\n emit BridgeProofDisputed(transactionId, msg.sender);\n }\n\n /// @inheritdoc IFastBridge\n function refund(bytes memory request) external {\n bytes32 transactionId = keccak256(request);\n\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n\n if (bridgeTxDetails[transactionId].status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n\n if (hasRole(REFUNDER_ROLE, msg.sender)) {\n // Refunder can refund if deadline has passed\n if (block.timestamp \u003c= transaction.deadline) revert DeadlineNotExceeded();\n } else {\n // Permissionless refund is allowed after REFUND_DELAY\n if (block.timestamp \u003c= transaction.deadline + REFUND_DELAY) revert DeadlineNotExceeded();\n }\n\n // if all checks passed, set to REFUNDED status\n bridgeTxDetails[transactionId].status = BridgeStatus.REFUNDED;\n\n // transfer origin collateral back to original sender\n address to = transaction.originSender;\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount + transaction.originFeeAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (bridgeTxDetails[transactionId].proofRelayer != relayer) revert SenderIncorrect();\n return _timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n /// @dev This method is added to achieve backwards compatibility with decoding requests into V1 structs:\n /// - `callValue` is partially reported as a zero/non-zero flag\n /// - `callParams` is ignored\n /// In order to process all kinds of requests use getBridgeTransactionV2 instead.\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory) {\n // Try decoding into V2 struct first. This will revert if V1 struct is passed\n try this.getBridgeTransactionV2(request) returns (BridgeTransactionV2 memory txV2) {\n // Note: we entirely ignore the callParams field, as it was not present in V1\n return BridgeTransaction({\n originChainId: txV2.originChainId,\n destChainId: txV2.destChainId,\n originSender: txV2.originSender,\n destRecipient: txV2.destRecipient,\n originToken: txV2.originToken,\n destToken: txV2.destToken,\n originAmount: txV2.originAmount,\n destAmount: txV2.destAmount,\n originFeeAmount: txV2.originFeeAmount,\n sendChainGas: txV2.callValue != 0,\n deadline: txV2.deadline,\n nonce: txV2.nonce\n });\n } catch {\n // Fallback to V1 struct\n return abi.decode(request, (BridgeTransaction));\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) public payable {\n int256 exclusivityEndTime = int256(block.timestamp) + paramsV2.quoteExclusivitySeconds;\n _validateBridgeParams(params, paramsV2, exclusivityEndTime);\n\n // transfer tokens to bridge contract\n /// @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _pullToken(params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n\n // set status to requested\n bytes memory request = abi.encode(\n BridgeTransactionV2({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n callValue: paramsV2.callValue,\n deadline: params.deadline,\n nonce: senderNonces[params.sender]++, // increment nonce on every bridge\n exclusivityRelayer: paramsV2.quoteRelayer,\n // We checked exclusivityEndTime to be in range (0 .. params.deadline] above, so can safely cast\n exclusivityEndTime: uint256(exclusivityEndTime),\n callParams: paramsV2.callParams\n })\n );\n bytes32 transactionId = keccak256(request);\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n\n emit BridgeRequested({\n transactionId: transactionId,\n sender: params.sender,\n request: request,\n destChainId: params.dstChainId,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n sendChainGas: paramsV2.callValue != 0\n });\n emit BridgeQuoteDetails(transactionId, paramsV2.quoteId);\n }\n\n /// @inheritdoc IFastBridgeV2\n function relay(bytes memory request, address relayer) public payable {\n bytes32 transactionId = keccak256(request);\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n _validateRelayParams(transaction, transactionId, relayer);\n // mark bridge transaction as relayed\n bridgeRelayDetails[transactionId] =\n BridgeRelay({blockNumber: uint48(block.number), blockTimestamp: uint48(block.timestamp), relayer: relayer});\n\n // transfer tokens to recipient on destination chain and do an arbitrary call if requested\n address to = transaction.destRecipient;\n address token = transaction.destToken;\n uint256 amount = transaction.destAmount;\n\n // All state changes have been done at this point, can proceed to the external calls.\n // This follows the checks-effects-interactions pattern to mitigate potential reentrancy attacks.\n if (token == UniversalTokenLib.ETH_ADDRESS) {\n // For ETH non-zero callValue is not allowed\n if (transaction.callValue != 0) revert NativeTokenCallValueNotSupported();\n // Check that the correct msg.value was sent\n if (msg.value != amount) revert MsgValueIncorrect();\n } else {\n // For ERC20s, we check that the correct msg.value was sent\n if (msg.value != transaction.callValue) revert MsgValueIncorrect();\n // We need to transfer the tokens from the Relayer to the recipient first before performing an\n // optional post-transfer arbitrary call.\n IERC20(token).safeTransferFrom(msg.sender, to, amount);\n }\n\n if (transaction.callParams.length != 0) {\n // Arbitrary call requested, perform it while supplying full msg.value to the recipient\n // Note: if token has a fee on transfers, the recipient will have received less than `amount`.\n // This is a very niche edge case and should be handled by the recipient contract.\n _checkedCallRecipient({recipient: to, token: token, amount: amount, callParams: transaction.callParams});\n } else if (msg.value != 0) {\n // No arbitrary call requested, but msg.value was sent. This is either a relay with ETH,\n // or a non-zero callValue request with an ERC20. In both cases, transfer the ETH to the recipient.\n Address.sendValue(payable(to), msg.value);\n }\n\n emit BridgeRelayed({\n transactionId: transactionId,\n relayer: relayer,\n to: to,\n originChainId: transaction.originChainId,\n originToken: transaction.originToken,\n destToken: transaction.destToken,\n originAmount: transaction.originAmount,\n destAmount: transaction.destAmount,\n chainGasAmount: transaction.callValue\n });\n }\n\n /// @inheritdoc IFastBridgeV2\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) public onlyRole(RELAYER_ROLE) {\n // update bridge tx status given proof provided\n if (bridgeTxDetails[transactionId].status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n bridgeTxDetails[transactionId].status = BridgeStatus.RELAYER_PROVED;\n bridgeTxDetails[transactionId].proofBlockTimestamp = uint40(block.timestamp);\n bridgeTxDetails[transactionId].proofBlockNumber = uint48(block.number);\n bridgeTxDetails[transactionId].proofRelayer = relayer;\n\n emit BridgeProofProvided(transactionId, relayer, destTxHash);\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes memory request, address to) public {\n bytes32 transactionId = keccak256(request);\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n\n // update bridge tx status if able to claim origin collateral\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n\n // if \"to\" is zero addr, permissionlessly send funds to proven relayer\n if (to == address(0)) {\n to = bridgeTxDetails[transactionId].proofRelayer;\n } else if (bridgeTxDetails[transactionId].proofRelayer != msg.sender) {\n revert SenderIncorrect();\n }\n\n if (_timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003c= DISPUTE_PERIOD) {\n revert DisputePeriodNotPassed();\n }\n\n bridgeTxDetails[transactionId].status = BridgeStatus.RELAYER_CLAIMED;\n\n // update protocol fees if origin fee amount exists\n if (transaction.originFeeAmount \u003e 0) protocolFees[transaction.originToken] += transaction.originFeeAmount;\n\n // transfer origin collateral less fee to specified address\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositClaimed(transactionId, bridgeTxDetails[transactionId].proofRelayer, to, token, amount);\n }\n\n function bridgeStatuses(bytes32 transactionId) public view returns (BridgeStatus status) {\n return bridgeTxDetails[transactionId].status;\n }\n\n function bridgeProofs(bytes32 transactionId) public view returns (uint96 timestamp, address relayer) {\n timestamp = bridgeTxDetails[transactionId].proofBlockTimestamp;\n relayer = bridgeTxDetails[transactionId].proofRelayer;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeRelays(bytes32 transactionId) public view returns (bool) {\n // has this transactionId been relayed?\n return bridgeRelayDetails[transactionId].relayer != address(0);\n }\n\n /// @inheritdoc IFastBridgeV2\n function getBridgeTransactionV2(bytes memory request) public pure returns (BridgeTransactionV2 memory) {\n return abi.decode(request, (BridgeTransactionV2));\n }\n\n /// @notice Pulls a requested token from the user to this contract.\n function _pullToken(address token, uint256 amount) internal returns (uint256 amountPulled) {\n if (token == UniversalTokenLib.ETH_ADDRESS) {\n // For ETH we just need to check that the supplied msg.value is correct\n if (amount != msg.value) revert MsgValueIncorrect();\n amountPulled = msg.value;\n } else {\n token.assertIsContract();\n // Record token balance before transfer\n amountPulled = IERC20(token).balanceOf(address(this));\n // Token needs to be pulled only if msg.value is zero\n // This way user can specify WETH as the origin asset\n IERC20(token).safeTransferFrom(msg.sender, address(this), amount);\n // Use the difference between the recorded balance and the current balance as the amountPulled\n amountPulled = IERC20(token).balanceOf(address(this)) - amountPulled;\n }\n }\n\n /// @notice Calls the Recipient's hook function with the specified callParams and performs\n /// all the necessary checks for the returned value.\n function _checkedCallRecipient(\n address recipient,\n address token,\n uint256 amount,\n bytes memory callParams\n )\n internal\n {\n bytes memory hookData =\n abi.encodeCall(IFastBridgeRecipient.fastBridgeTransferReceived, (token, amount, callParams));\n // This will bubble any revert messages from the hook function\n bytes memory returnData = Address.functionCallWithValue({target: recipient, data: hookData, value: msg.value});\n // Explicit revert if no return data at all\n if (returnData.length == 0) revert RecipientNoReturnValue();\n // Check that exactly a single return value was returned\n if (returnData.length != 32) revert RecipientIncorrectReturnValue();\n // Return value should be abi-encoded hook function selector\n if (bytes32(returnData) != bytes32(IFastBridgeRecipient.fastBridgeTransferReceived.selector)) {\n revert RecipientIncorrectReturnValue();\n }\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint40(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint40).max but\n /// proof.timestamp \u003c type(uint40).max via unchecked statement\n /// @param proofBlockTimestamp The bridge proof block timestamp\n /// @return delta Time delta since proof submitted\n function _timeSince(uint40 proofBlockTimestamp) internal view returns (uint256 delta) {\n unchecked {\n delta = uint40(block.timestamp) - proofBlockTimestamp;\n }\n }\n\n /// @notice Performs all the necessary checks for a bridge to happen.\n /// @dev There's no good way to refactor this function to reduce cyclomatic complexity due to\n /// the number of checks that need to be performed, so we skip the code-complexity rule here.\n // solhint-disable-next-line code-complexity\n function _validateBridgeParams(\n BridgeParams memory params,\n BridgeParamsV2 memory paramsV2,\n int256 exclusivityEndTime\n )\n internal\n view\n {\n // Check V1 (legacy) params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.sender == address(0) || params.to == address(0)) revert ZeroAddress();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n // Check V2 params\n if (paramsV2.callParams.length \u003e MAX_CALL_PARAMS_LENGTH) revert CallParamsLengthAboveMax();\n if (paramsV2.callValue != 0 \u0026\u0026 params.destToken == UniversalTokenLib.ETH_ADDRESS) {\n revert NativeTokenCallValueNotSupported();\n }\n // exclusivityEndTime must be in range (0 .. params.deadline]\n if (exclusivityEndTime \u003c= 0 || exclusivityEndTime \u003e int256(params.deadline)) {\n revert ExclusivityParamsIncorrect();\n }\n }\n\n /// @notice Performs all the necessary checks for a relay to happen.\n function _validateRelayParams(\n BridgeTransactionV2 memory transaction,\n bytes32 transactionId,\n address relayer\n )\n internal\n view\n {\n if (relayer == address(0)) revert ZeroAddress();\n // Check if the transaction has already been relayed\n if (bridgeRelays(transactionId)) revert TransactionRelayed();\n if (transaction.destChainId != uint32(block.chainid)) revert ChainIncorrect();\n // Check the deadline for relay to happen\n if (block.timestamp \u003e transaction.deadline) revert DeadlineExceeded();\n // Check the exclusivity period, if it is still ongoing\n // forgefmt: disable-next-item\n if (\n transaction.exclusivityRelayer != address(0) \u0026\u0026\n transaction.exclusivityRelayer != relayer \u0026\u0026\n block.timestamp \u003c= transaction.exclusivityEndTime\n ) {\n revert ExclusivityPeriodNotPassed();\n }\n }\n}\n","language":"Solidity","languageVersion":"0.8.24","compilerVersion":"0.8.24","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../","srcMap":"57704:2551:0:-:0;;;;;;;;;;;;;;;-1:-1:-1;;;57704:2551:0;;;;;;;;;;;;;;;;;","srcMapRuntime":"57704:2551:0:-:0;;;;;;;;","abiDefinition":[],"userDoc":{"kind":"user","methods":{},"version":1},"developerDoc":{"kind":"dev","methods":{},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[],\"devdoc\":{\"kind\":\"dev\",\"methods\":{},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeV2.sol\":\"UniversalTokenLib\"},\"evmVersion\":\"shanghai\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeV2.sol\":{\"keccak256\":\"0x7cd0f885e80e2bdaa638bc32ae7af7d2e248f99ce4b354c217d0f0f7d7302e0a\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://7ccf28df0bd7b4606986585acd8622ed9b4e81379690061bb66088f0a2270af1\",\"dweb:/ipfs/QmTf7HNdHZkK6vmx8ZgewycQEb72oLD9nPwBpsM5reMstQ\"]}},\"version\":1}"},"hashes":{}}} \ No newline at end of file diff --git a/services/rfq/contracts/fastbridgev2/fastbridgev2.metadata.go b/services/rfq/contracts/fastbridgev2/fastbridgev2.metadata.go new file mode 100644 index 0000000000..d12cd81b75 --- /dev/null +++ b/services/rfq/contracts/fastbridgev2/fastbridgev2.metadata.go @@ -0,0 +1,25 @@ +// Code generated by synapse abigen DO NOT EDIT. +package fastbridgev2 + +import ( + _ "embed" + "encoding/json" + "github.com/ethereum/go-ethereum/common/compiler" +) + +// rawContracts are the json we use to derive the processed contracts +// +//go:embed fastbridgev2.contractinfo.json +var rawContracts []byte + +// Contracts are unmarshalled on start +var Contracts map[string]*compiler.Contract + +func init() { + // load contract metadata + var err error + err = json.Unmarshal(rawContracts, &Contracts) + if err != nil { + panic(err) + } +} diff --git a/services/rfq/contracts/fastbridgev2/generate.go b/services/rfq/contracts/fastbridgev2/generate.go new file mode 100644 index 0000000000..6f9caefe60 --- /dev/null +++ b/services/rfq/contracts/fastbridgev2/generate.go @@ -0,0 +1,3 @@ +package fastbridgev2 + +//go:generate go run github.com/synapsecns/sanguine/tools/abigen generate --sol ../../../../packages/contracts-rfq/flattened/FastBridgeV2.sol --pkg fastbridgev2 --sol-version 0.8.20 --filename fastbridgev2 --evm-version istanbul From e5e86464a702222055010bfaf1be1cc99859cf8b Mon Sep 17 00:00:00 2001 From: Daniel Wasserman Date: Tue, 8 Oct 2024 14:48:13 -0500 Subject: [PATCH 18/85] Feat: abigen helpers --- services/rfq/contracts/fastbridgev2/events.go | 82 ++++++++++++++++ services/rfq/contracts/fastbridgev2/helper.go | 35 +++++++ services/rfq/contracts/fastbridgev2/parser.go | 98 +++++++++++++++++++ 3 files changed, 215 insertions(+) create mode 100644 services/rfq/contracts/fastbridgev2/events.go create mode 100644 services/rfq/contracts/fastbridgev2/helper.go create mode 100644 services/rfq/contracts/fastbridgev2/parser.go diff --git a/services/rfq/contracts/fastbridgev2/events.go b/services/rfq/contracts/fastbridgev2/events.go new file mode 100644 index 0000000000..2547ebad28 --- /dev/null +++ b/services/rfq/contracts/fastbridgev2/events.go @@ -0,0 +1,82 @@ +package fastbridgev2 + +import ( + "bytes" + "strings" + + "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/ethereum/go-ethereum/common" +) + +// TODO: consider not exporting to avoid accidental mutation. +var ( + // BridgeRequestedTopic is the event topic for a bridge request. + BridgeRequestedTopic common.Hash + // BridgeRelayedTopic is the topic emitted by a bridge relay. + BridgeRelayedTopic common.Hash + // BridgeProofProvidedTopic is the topic emitted by a bridge relay. + BridgeProofProvidedTopic common.Hash + // BridgeDepositClaimedTopic is the topic emitted by a bridge relay. + BridgeDepositClaimedTopic common.Hash + // BridgeProofDisputedTopic is the topic emitted by a bridge dispute. + BridgeProofDisputedTopic common.Hash +) + +// static checks to make sure topics actually exist. +func init() { + var err error + + parsedABI, err := abi.JSON(strings.NewReader(FastBridgeV2MetaData.ABI)) + if err != nil { + panic(err) + } + + BridgeRequestedTopic = parsedABI.Events["BridgeRequested"].ID + BridgeRelayedTopic = parsedABI.Events["BridgeRelayed"].ID + BridgeProofProvidedTopic = parsedABI.Events["BridgeProofProvided"].ID + BridgeDepositClaimedTopic = parsedABI.Events["BridgeDepositClaimed"].ID + BridgeProofDisputedTopic = parsedABI.Events["BridgeProofDisputed"].ID + + _, err = parsedABI.EventByID(BridgeRequestedTopic) + if err != nil { + panic(err) + } + + _, err = parsedABI.EventByID(BridgeRelayedTopic) + if err != nil { + panic(err) + } + + _, err = parsedABI.EventByID(BridgeProofProvidedTopic) + if err != nil { + panic(err) + } + + _, err = parsedABI.EventByID(BridgeProofDisputedTopic) + if err != nil { + panic(err) + } +} + +// topicMap maps events to topics. +// this is returned as a function to assert immutability. +func topicMap() map[EventType]common.Hash { + return map[EventType]common.Hash{ + BridgeRequestedEvent: BridgeRequestedTopic, + BridgeRelayedEvent: BridgeRelayedTopic, + BridgeProofProvidedEvent: BridgeProofProvidedTopic, + BridgeDepositClaimedEvent: BridgeDepositClaimedTopic, + BridgeDisputeEvent: BridgeProofDisputedTopic, + } +} + +// eventTypeFromTopic gets the event type from the topic +// returns nil if the topic is not found. +func eventTypeFromTopic(ogTopic common.Hash) *EventType { + for eventType, topic := range topicMap() { + if bytes.Equal(ogTopic.Bytes(), topic.Bytes()) { + return &eventType + } + } + return nil +} diff --git a/services/rfq/contracts/fastbridgev2/helper.go b/services/rfq/contracts/fastbridgev2/helper.go new file mode 100644 index 0000000000..96fbdf0008 --- /dev/null +++ b/services/rfq/contracts/fastbridgev2/helper.go @@ -0,0 +1,35 @@ +package fastbridgev2 + +import ( + "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/vm" +) + +// FastBridgeV2Ref is a bound fast bridge contract that returns the address of the contract. +// +//nolint:golint +type FastBridgeV2Ref struct { + *FastBridgeV2 + address common.Address +} + +// Address gets the ocntract address. +func (f *FastBridgeV2Ref) Address() common.Address { + return f.address +} + +// NewFastBridgeV2Ref creates a new fast bridge contract witha ref. +func NewFastBridgeV2Ref(address common.Address, backend bind.ContractBackend) (*FastBridgeV2Ref, error) { + fastBridge, err := NewFastBridgeV2(address, backend) + if err != nil { + return nil, err + } + + return &FastBridgeV2Ref{ + FastBridgeV2: fastBridge, + address: address, + }, nil +} + +var _ vm.ContractRef = &FastBridgeV2Ref{} diff --git a/services/rfq/contracts/fastbridgev2/parser.go b/services/rfq/contracts/fastbridgev2/parser.go new file mode 100644 index 0000000000..15a662b4b9 --- /dev/null +++ b/services/rfq/contracts/fastbridgev2/parser.go @@ -0,0 +1,98 @@ +package fastbridgev2 + +import ( + "fmt" + + "github.com/ethereum/go-ethereum/common" + ethTypes "github.com/ethereum/go-ethereum/core/types" +) + +// EventType is the type of the bridge watcher +// +//go:generate go run golang.org/x/tools/cmd/stringer -type=EventType +type EventType uint + +const ( + // BridgeRequestedEvent is the event type for the BridgeRequested event. + BridgeRequestedEvent EventType = iota + 1 + // BridgeRelayedEvent is the event type for the BridgeRelayed event. + BridgeRelayedEvent + // BridgeProofProvidedEvent is the event type for the BridgeProofProvided event. + BridgeProofProvidedEvent + // BridgeDepositClaimedEvent is the event type for the BridgeDepositClaimed event. + BridgeDepositClaimedEvent + // BridgeDisputeEvent is the event type for the BridgeDispute event. + BridgeDisputeEvent +) + +// Parser parses events from the fastbridge contracat. +type Parser interface { + // ParseEvent parses the event from the log. + ParseEvent(log ethTypes.Log) (_ EventType, event interface{}, ok bool) +} +type parserImpl struct { + filterer *FastBridgeV2Filterer +} + +// NewParser creates a new parser for the fastbridge contract. +func NewParser(fastBridgeAddress common.Address) (Parser, error) { + parser, err := NewFastBridgeV2Filterer(fastBridgeAddress, nil) + if err != nil { + return nil, fmt.Errorf("could not create %T: %w", FastBridgeV2Filterer{}, err) + } + + return &parserImpl{filterer: parser}, nil +} + +// nolint: cyclop +func (p parserImpl) ParseEvent(log ethTypes.Log) (_ EventType, event interface{}, ok bool) { + // return an unknown event to avoid cases where user failed to check the event type + // make it high enough to make it obvious (we start iotas at +1, see uber style guide for details) + noOpEvent := EventType(len(topicMap()) + 2) + + if len(log.Topics) == 0 { + return noOpEvent, nil, false + } + nillableEventType := eventTypeFromTopic(log.Topics[0]) + if nillableEventType == nil { + return noOpEvent, nil, false + } + + eventType := *nillableEventType + + switch eventType { + case BridgeRequestedEvent: + requested, err := p.filterer.ParseBridgeRequested(log) + if err != nil { + return noOpEvent, nil, false + } + return eventType, requested, true + case BridgeRelayedEvent: + requested, err := p.filterer.ParseBridgeRelayed(log) + if err != nil { + return noOpEvent, nil, false + } + return eventType, requested, true + case BridgeProofProvidedEvent: + proven, err := p.filterer.ParseBridgeProofProvided(log) + if err != nil { + return noOpEvent, nil, false + } + return eventType, proven, true + case BridgeDepositClaimedEvent: + claimed, err := p.filterer.ParseBridgeDepositClaimed(log) + if err != nil { + return noOpEvent, nil, false + } + return eventType, claimed, true + case BridgeDisputeEvent: + disputed, err := p.filterer.ParseBridgeProofDisputed(log) + if err != nil { + return noOpEvent, nil, false + } + return eventType, disputed, true + + } + + return eventType, nil, true +} From ab63286e85304ba855330a51d68e3d528cf01dc2 Mon Sep 17 00:00:00 2001 From: Daniel Wasserman Date: Tue, 8 Oct 2024 14:51:15 -0500 Subject: [PATCH 19/85] Fix: generate --- .../fastbridgev2/eventtype_string.go | 28 +++++++++++++++++++ .../fastbridgev2/fastbridgev2.abigen.go | 12 ++++---- .../fastbridgev2.contractinfo.json | 2 +- .../rfq/contracts/fastbridgev2/generate.go | 2 +- 4 files changed, 36 insertions(+), 8 deletions(-) create mode 100644 services/rfq/contracts/fastbridgev2/eventtype_string.go diff --git a/services/rfq/contracts/fastbridgev2/eventtype_string.go b/services/rfq/contracts/fastbridgev2/eventtype_string.go new file mode 100644 index 0000000000..b7c65ba096 --- /dev/null +++ b/services/rfq/contracts/fastbridgev2/eventtype_string.go @@ -0,0 +1,28 @@ +// Code generated by "stringer -type=EventType"; DO NOT EDIT. + +package fastbridgev2 + +import "strconv" + +func _() { + // An "invalid array index" compiler error signifies that the constant values have changed. + // Re-run the stringer command to generate them again. + var x [1]struct{} + _ = x[BridgeRequestedEvent-1] + _ = x[BridgeRelayedEvent-2] + _ = x[BridgeProofProvidedEvent-3] + _ = x[BridgeDepositClaimedEvent-4] + _ = x[BridgeDisputeEvent-5] +} + +const _EventType_name = "BridgeRequestedEventBridgeRelayedEventBridgeProofProvidedEventBridgeDepositClaimedEventBridgeDisputeEvent" + +var _EventType_index = [...]uint8{0, 20, 38, 62, 87, 105} + +func (i EventType) String() string { + i -= 1 + if i >= EventType(len(_EventType_index)-1) { + return "EventType(" + strconv.FormatInt(int64(i+1), 10) + ")" + } + return _EventType_name[_EventType_index[i]:_EventType_index[i+1]] +} diff --git a/services/rfq/contracts/fastbridgev2/fastbridgev2.abigen.go b/services/rfq/contracts/fastbridgev2/fastbridgev2.abigen.go index f7490e86f4..3975f8a673 100644 --- a/services/rfq/contracts/fastbridgev2/fastbridgev2.abigen.go +++ b/services/rfq/contracts/fastbridgev2/fastbridgev2.abigen.go @@ -1827,7 +1827,7 @@ func (_AccessControlEnumerable *AccessControlEnumerableFilterer) ParseRoleRevoke // AddressMetaData contains all meta data concerning the Address contract. var AddressMetaData = &bind.MetaData{ ABI: "[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"}],\"name\":\"AddressEmptyCode\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"AddressInsufficientBalance\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"FailedInnerCall\",\"type\":\"error\"}]", - Bin: "0x60556032600b8282823980515f1a607314602657634e487b7160e01b5f525f60045260245ffd5b305f52607381538281f3fe730000000000000000000000000000000000000000301460806040525f80fdfea264697066735822122066ad3e1b6dabcf400c86562013c52581c196e1c9e2e058e0440d32fcd4e26ad264736f6c63430008180033", + Bin: "0x60566037600b82828239805160001a607314602a57634e487b7160e01b600052600060045260246000fd5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600080fdfea26469706673582212209373c953367c76b94c1908124544fbcf053f6653eb651760b4d42f0f487710d864736f6c63430008180033", } // AddressABI is the input ABI used to generate the binding from. @@ -2023,7 +2023,7 @@ var AdminMetaData = &bind.MetaData{ "01ffc9a7": "supportsInterface(bytes4)", "06f333f2": "sweepProtocolFees(address,address)", }, - Bin: "0x608060405234801562000010575f80fd5b50604051620013a3380380620013a3833981016040819052620000339162000184565b6200003f5f8262000047565b5050620001ac565b5f8062000055848462000082565b9050801562000079575f8481526001602052604090206200007790846200012d565b505b90505b92915050565b5f828152602081815260408083206001600160a01b038516845290915281205460ff1662000125575f838152602081815260408083206001600160a01b03861684529091529020805460ff19166001179055620000dc3390565b6001600160a01b0316826001600160a01b0316847f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45060016200007c565b505f6200007c565b5f62000079836001600160a01b0384165f8181526001830160205260408120546200012557508154600181810184555f8481526020808220909301849055845484825282860190935260409020919091556200007c565b5f6020828403121562000195575f80fd5b81516001600160a01b038116811462000079575f80fd5b6111e980620001ba5f395ff3fe608060405234801561000f575f80fd5b506004361061016e575f3560e01c806391d14854116100d2578063bf333f2c11610088578063d547741f11610063578063d547741f14610378578063dcf844a71461038b578063e00a83e0146103aa575f80fd5b8063bf333f2c14610334578063ca15c8731461033e578063ccc5749014610351575f80fd5b8063a217fddf116100b8578063a217fddf14610307578063b13aa2d61461030e578063b250fe6b14610321575f80fd5b806391d148541461029d578063926d7d7f146102e0575f80fd5b80632f2ff15d1161012757806358f858801161010d57806358f85880146102355780635960ccf21461023e5780639010d07c14610265575f80fd5b80632f2ff15d1461020f57806336568abe14610222575f80fd5b806306f333f21161015757806306f333f2146101cf5780630f5f6ed7146101e4578063248a9ca3146101ed575f80fd5b806301ffc9a71461017257806303ed0ee51461019a575b5f80fd5b610185610180366004610fcd565b6103b3565b60405190151581526020015b60405180910390f35b6101c17f043c983c49d46f0e102151eaf8085d4a2e6571d5df2d47b013f39bddfd4a639d81565b604051908152602001610191565b6101e26101dd366004611034565b61040e565b005b6101c161271081565b6101c16101fb366004611065565b5f9081526020819052604090206001015490565b6101e261021d36600461107c565b6104fa565b6101e261023036600461107c565b610524565b6101c160025481565b6101c17fdb9556138406326f00296e13ea2ad7db24ba82381212d816b1a40c23b466b32781565b61027861027336600461109d565b61057d565b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610191565b6101856102ab36600461107c565b5f9182526020828152604080842073ffffffffffffffffffffffffffffffffffffffff93909316845291905290205460ff1690565b6101c17fe2b7fb3b832174769106daebcfd6d1970523240dda11281102db9363b83b0dc481565b6101c15f81565b6101e261031c366004611065565b61059b565b6101e261032f366004611065565b61067d565b6101c1620f424081565b6101c161034c366004611065565b6106e5565b6101c17f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f5581565b6101e261038636600461107c565b6106fb565b6101c16103993660046110bd565b60036020525f908152604090205481565b6101c160045481565b5f7fffffffff0000000000000000000000000000000000000000000000000000000082167f5a05180f00000000000000000000000000000000000000000000000000000000148061040857506104088261071f565b92915050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f55610438816107b5565b73ffffffffffffffffffffffffffffffffffffffff83165f908152600360205260408120549081900361046b5750505050565b73ffffffffffffffffffffffffffffffffffffffff84165f8181526003602052604081205561049b9084836107c2565b6040805173ffffffffffffffffffffffffffffffffffffffff8087168252851660208201529081018290527f244e51bc38c1452fa8aaf487bcb4bca36c2baa3a5fbdb776b1eabd8dc6d277cd9060600160405180910390a1505b505050565b5f82815260208190526040902060010154610514816107b5565b61051e8383610914565b50505050565b73ffffffffffffffffffffffffffffffffffffffff81163314610573576040517f6697b23200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6104f58282610947565b5f8281526001602052604081206105949083610972565b9392505050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f556105c5816107b5565b612710821115610636576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f6e657746656552617465203e206d61780000000000000000000000000000000060448201526064015b60405180910390fd5b600280549083905560408051828152602081018590527f14914da2bf76024616fbe1859783fcd4dbddcb179b1f3a854949fbf920dcb95791015b60405180910390a1505050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f556106a7816107b5565b600480549083905560408051828152602081018590527f5cf09b12f3f56b4c564d51b25b40360af6d795198adb61ae0806a36c294323fa9101610670565b5f8181526001602052604081206104089061097d565b5f82815260208190526040902060010154610715816107b5565b61051e8383610947565b5f7fffffffff0000000000000000000000000000000000000000000000000000000082167f7965db0b00000000000000000000000000000000000000000000000000000000148061040857507f01ffc9a7000000000000000000000000000000000000000000000000000000007fffffffff00000000000000000000000000000000000000000000000000000000831614610408565b6107bf8133610986565b50565b3073ffffffffffffffffffffffffffffffffffffffff8316036107e457505050565b805f036107f057505050565b7fffffffffffffffffffffffff111111111111111111111111111111111111111273ffffffffffffffffffffffffffffffffffffffff8416016108f3575f8273ffffffffffffffffffffffffffffffffffffffff16826040515f6040518083038185875af1925050503d805f8114610883576040519150601f19603f3d011682016040523d82523d5f602084013e610888565b606091505b505090508061051e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f455448207472616e73666572206661696c656400000000000000000000000000604482015260640161062d565b6104f573ffffffffffffffffffffffffffffffffffffffff84168383610a0f565b5f806109208484610a9c565b90508015610594575f84815260016020526040902061093f9084610b95565b509392505050565b5f806109538484610bb6565b90508015610594575f84815260016020526040902061093f9084610c6f565b5f6105948383610c90565b5f610408825490565b5f8281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915290205460ff16610a0b576040517fe2517d3f00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff821660048201526024810183905260440161062d565b5050565b6040805173ffffffffffffffffffffffffffffffffffffffff8416602482015260448082018490528251808303909101815260649091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fa9059cbb000000000000000000000000000000000000000000000000000000001790526104f5908490610cb6565b5f8281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915281205460ff16610b8e575f8381526020818152604080832073ffffffffffffffffffffffffffffffffffffffff86168452909152902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055610b2c3390565b73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16847f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a4506001610408565b505f610408565b5f6105948373ffffffffffffffffffffffffffffffffffffffff8416610d4a565b5f8281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915281205460ff1615610b8e575f8381526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8616808552925280832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016905551339286917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a4506001610408565b5f6105948373ffffffffffffffffffffffffffffffffffffffff8416610d8f565b5f825f018281548110610ca557610ca56110d6565b905f5260205f200154905092915050565b5f610cd773ffffffffffffffffffffffffffffffffffffffff841683610e72565b905080515f14158015610cfb575080806020019051810190610cf99190611103565b155b156104f5576040517f5274afe700000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8416600482015260240161062d565b5f818152600183016020526040812054610b8e57508154600181810184555f848152602080822090930184905584548482528286019093526040902091909155610408565b5f8181526001830160205260408120548015610e69575f610db1600183611122565b85549091505f90610dc490600190611122565b9050808214610e23575f865f018281548110610de257610de26110d6565b905f5260205f200154905080875f018481548110610e0257610e026110d6565b5f918252602080832090910192909255918252600188019052604090208390555b8554869080610e3457610e3461115a565b600190038181905f5260205f20015f90559055856001015f8681526020019081526020015f205f905560019350505050610408565b5f915050610408565b606061059483835f845f808573ffffffffffffffffffffffffffffffffffffffff168486604051610ea39190611187565b5f6040518083038185875af1925050503d805f8114610edd576040519150601f19603f3d011682016040523d82523d5f602084013e610ee2565b606091505b5091509150610ef2868383610efc565b9695505050505050565b606082610f1157610f0c82610f8b565b610594565b8151158015610f35575073ffffffffffffffffffffffffffffffffffffffff84163b155b15610f84576040517f9996b31500000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8516600482015260240161062d565b5080610594565b805115610f9b5780518082602001fd5b6040517f1425ea4200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f60208284031215610fdd575f80fd5b81357fffffffff0000000000000000000000000000000000000000000000000000000081168114610594575f80fd5b803573ffffffffffffffffffffffffffffffffffffffff8116811461102f575f80fd5b919050565b5f8060408385031215611045575f80fd5b61104e8361100c565b915061105c6020840161100c565b90509250929050565b5f60208284031215611075575f80fd5b5035919050565b5f806040838503121561108d575f80fd5b8235915061105c6020840161100c565b5f80604083850312156110ae575f80fd5b50508035926020909101359150565b5f602082840312156110cd575f80fd5b6105948261100c565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b5f60208284031215611113575f80fd5b81518015158114610594575f80fd5b81810381811115610408577f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603160045260245ffd5b5f82515f5b818110156111a6576020818601810151858301520161118c565b505f92019182525091905056fea2646970667358221220663496d7fb99c06349f8fc2145322e6c10ba61153be06cea50f6b07db91bc1bd64736f6c63430008180033", + Bin: "0x60806040523480156200001157600080fd5b50604051620014123803806200141283398101604081905262000034916200018e565b6200004160008262000049565b5050620001b9565b60008062000058848462000086565b905080156200007d5760008481526001602052604090206200007b908462000134565b505b90505b92915050565b6000828152602081815260408083206001600160a01b038516845290915281205460ff166200012b576000838152602081815260408083206001600160a01b03861684529091529020805460ff19166001179055620000e23390565b6001600160a01b0316826001600160a01b0316847f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a450600162000080565b50600062000080565b60006200007d836001600160a01b03841660008181526001830160205260408120546200012b5750815460018181018455600084815260208082209093018490558454848252828601909352604090209190915562000080565b600060208284031215620001a157600080fd5b81516001600160a01b03811681146200007d57600080fd5b61124980620001c96000396000f3fe608060405234801561001057600080fd5b50600436106101775760003560e01c806391d14854116100d8578063bf333f2c1161008c578063d547741f11610066578063d547741f14610385578063dcf844a714610398578063e00a83e0146103b857600080fd5b8063bf333f2c14610341578063ca15c8731461034b578063ccc574901461035e57600080fd5b8063a217fddf116100bd578063a217fddf14610313578063b13aa2d61461031b578063b250fe6b1461032e57600080fd5b806391d14854146102a8578063926d7d7f146102ec57600080fd5b80632f2ff15d1161012f57806358f858801161011457806358f85880146102405780635960ccf2146102495780639010d07c1461027057600080fd5b80632f2ff15d1461021a57806336568abe1461022d57600080fd5b806306f333f21161016057806306f333f2146101d95780630f5f6ed7146101ee578063248a9ca3146101f757600080fd5b806301ffc9a71461017c57806303ed0ee5146101a4575b600080fd5b61018f61018a366004611013565b6103c1565b60405190151581526020015b60405180910390f35b6101cb7f043c983c49d46f0e102151eaf8085d4a2e6571d5df2d47b013f39bddfd4a639d81565b60405190815260200161019b565b6101ec6101e736600461107e565b61041d565b005b6101cb61271081565b6101cb6102053660046110b1565b60009081526020819052604090206001015490565b6101ec6102283660046110ca565b61050b565b6101ec61023b3660046110ca565b610536565b6101cb60025481565b6101cb7fdb9556138406326f00296e13ea2ad7db24ba82381212d816b1a40c23b466b32781565b61028361027e3660046110ed565b61058f565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200161019b565b61018f6102b63660046110ca565b60009182526020828152604080842073ffffffffffffffffffffffffffffffffffffffff93909316845291905290205460ff1690565b6101cb7fe2b7fb3b832174769106daebcfd6d1970523240dda11281102db9363b83b0dc481565b6101cb600081565b6101ec6103293660046110b1565b6105ae565b6101ec61033c3660046110b1565b610690565b6101cb620f424081565b6101cb6103593660046110b1565b6106f8565b6101cb7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f5581565b6101ec6103933660046110ca565b61070f565b6101cb6103a636600461110f565b60036020526000908152604090205481565b6101cb60045481565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f5a05180f000000000000000000000000000000000000000000000000000000001480610417575061041782610734565b92915050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f55610447816107cb565b73ffffffffffffffffffffffffffffffffffffffff83166000908152600360205260408120549081900361047b5750505050565b73ffffffffffffffffffffffffffffffffffffffff84166000818152600360205260408120556104ac9084836107d8565b6040805173ffffffffffffffffffffffffffffffffffffffff8087168252851660208201529081018290527f244e51bc38c1452fa8aaf487bcb4bca36c2baa3a5fbdb776b1eabd8dc6d277cd9060600160405180910390a1505b505050565b600082815260208190526040902060010154610526816107cb565b610530838361092f565b50505050565b73ffffffffffffffffffffffffffffffffffffffff81163314610585576040517f6697b23200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6105068282610964565b60008281526001602052604081206105a79083610991565b9392505050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f556105d8816107cb565b612710821115610649576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f6e657746656552617465203e206d61780000000000000000000000000000000060448201526064015b60405180910390fd5b600280549083905560408051828152602081018590527f14914da2bf76024616fbe1859783fcd4dbddcb179b1f3a854949fbf920dcb95791015b60405180910390a1505050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f556106ba816107cb565b600480549083905560408051828152602081018590527f5cf09b12f3f56b4c564d51b25b40360af6d795198adb61ae0806a36c294323fa9101610683565b60008181526001602052604081206104179061099d565b60008281526020819052604090206001015461072a816107cb565b6105308383610964565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f7965db0b00000000000000000000000000000000000000000000000000000000148061041757507f01ffc9a7000000000000000000000000000000000000000000000000000000007fffffffff00000000000000000000000000000000000000000000000000000000831614610417565b6107d581336109a7565b50565b3073ffffffffffffffffffffffffffffffffffffffff8316036107fa57505050565b8060000361080757505050565b7fffffffffffffffffffffffff111111111111111111111111111111111111111273ffffffffffffffffffffffffffffffffffffffff84160161090e5760008273ffffffffffffffffffffffffffffffffffffffff168260405160006040518083038185875af1925050503d806000811461089e576040519150601f19603f3d011682016040523d82523d6000602084013e6108a3565b606091505b5050905080610530576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f455448207472616e73666572206661696c6564000000000000000000000000006044820152606401610640565b61050673ffffffffffffffffffffffffffffffffffffffff84168383610a31565b60008061093c8484610abe565b905080156105a757600084815260016020526040902061095c9084610bba565b509392505050565b6000806109718484610bdc565b905080156105a757600084815260016020526040902061095c9084610c97565b60006105a78383610cb9565b6000610417825490565b60008281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915290205460ff16610a2d576040517fe2517d3f00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8216600482015260248101839052604401610640565b5050565b6040805173ffffffffffffffffffffffffffffffffffffffff8416602482015260448082018490528251808303909101815260649091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fa9059cbb00000000000000000000000000000000000000000000000000000000179052610506908490610ce3565b60008281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915281205460ff16610bb25760008381526020818152604080832073ffffffffffffffffffffffffffffffffffffffff86168452909152902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055610b503390565b73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16847f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a4506001610417565b506000610417565b60006105a78373ffffffffffffffffffffffffffffffffffffffff8416610d79565b60008281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915281205460ff1615610bb25760008381526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8616808552925280832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016905551339286917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a4506001610417565b60006105a78373ffffffffffffffffffffffffffffffffffffffff8416610dc0565b6000826000018281548110610cd057610cd061112a565b9060005260206000200154905092915050565b6000610d0573ffffffffffffffffffffffffffffffffffffffff841683610eb3565b90508051600014158015610d2a575080806020019051810190610d289190611159565b155b15610506576040517f5274afe700000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff84166004820152602401610640565b6000818152600183016020526040812054610bb257508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155610417565b60008181526001830160205260408120548015610ea9576000610de460018361117b565b8554909150600090610df89060019061117b565b9050808214610e5d576000866000018281548110610e1857610e1861112a565b9060005260206000200154905080876000018481548110610e3b57610e3b61112a565b6000918252602080832090910192909255918252600188019052604090208390555b8554869080610e6e57610e6e6111b5565b600190038181906000526020600020016000905590558560010160008681526020019081526020016000206000905560019350505050610417565b6000915050610417565b60606105a783836000846000808573ffffffffffffffffffffffffffffffffffffffff168486604051610ee691906111e4565b60006040518083038185875af1925050503d8060008114610f23576040519150601f19603f3d011682016040523d82523d6000602084013e610f28565b606091505b5091509150610f38868383610f42565b9695505050505050565b606082610f5757610f5282610fd1565b6105a7565b8151158015610f7b575073ffffffffffffffffffffffffffffffffffffffff84163b155b15610fca576040517f9996b31500000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff85166004820152602401610640565b50806105a7565b805115610fe15780518082602001fd5b6040517f1425ea4200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006020828403121561102557600080fd5b81357fffffffff00000000000000000000000000000000000000000000000000000000811681146105a757600080fd5b803573ffffffffffffffffffffffffffffffffffffffff8116811461107957600080fd5b919050565b6000806040838503121561109157600080fd5b61109a83611055565b91506110a860208401611055565b90509250929050565b6000602082840312156110c357600080fd5b5035919050565b600080604083850312156110dd57600080fd5b823591506110a860208401611055565b6000806040838503121561110057600080fd5b50508035926020909101359150565b60006020828403121561112157600080fd5b6105a782611055565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60006020828403121561116b57600080fd5b815180151581146105a757600080fd5b81810381811115610417577f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fd5b6000825160005b8181101561120557602081860181015185830152016111eb565b50600092019182525091905056fea2646970667358221220e128d8a06a9c2200c4304cd29f76ba6d8295d2c98b16f4a06921d33d0cebefd764736f6c63430008180033", } // AdminABI is the input ABI used to generate the binding from. @@ -4023,7 +4023,7 @@ func (_ERC165 *ERC165CallerSession) SupportsInterface(interfaceId [4]byte) (bool // EnumerableSetMetaData contains all meta data concerning the EnumerableSet contract. var EnumerableSetMetaData = &bind.MetaData{ ABI: "[]", - Bin: "0x60556032600b8282823980515f1a607314602657634e487b7160e01b5f525f60045260245ffd5b305f52607381538281f3fe730000000000000000000000000000000000000000301460806040525f80fdfea26469706673582212201ec3fcd8425a477b64c89978a17adf538a2da29b003a43e615ec5e213f9f3bf964736f6c63430008180033", + Bin: "0x60566037600b82828239805160001a607314602a57634e487b7160e01b600052600060045260246000fd5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600080fdfea2646970667358221220c93e0a4d209c73a0e712af3f8fe75c461fc5f2c8421cf7a3112f43749245c31a64736f6c63430008180033", } // EnumerableSetABI is the input ABI used to generate the binding from. @@ -4244,7 +4244,7 @@ var FastBridgeV2MetaData = &bind.MetaData{ "01ffc9a7": "supportsInterface(bytes4)", "06f333f2": "sweepProtocolFees(address,address)", }, - Bin: "0x60c06040525f60805234801562000014575f80fd5b5060405162003d2f38038062003d2f83398101604081905262000037916200018e565b80620000445f8262000051565b50504360a05250620001b6565b5f806200005f84846200008c565b9050801562000083575f84815260016020526040902062000081908462000137565b505b90505b92915050565b5f828152602081815260408083206001600160a01b038516845290915281205460ff166200012f575f838152602081815260408083206001600160a01b03861684529091529020805460ff19166001179055620000e63390565b6001600160a01b0316826001600160a01b0316847f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a450600162000086565b505f62000086565b5f62000083836001600160a01b0384165f8181526001830160205260408120546200012f57508154600181810184555f84815260208082209093018490558454848252828601909352604090209190915562000086565b5f602082840312156200019f575f80fd5b81516001600160a01b038116811462000083575f80fd5b60805160a051613b57620001d85f395f6107cf01525f61086c0152613b575ff3fe6080604052600436106102ed575f3560e01c806391ad503911610186578063b13aa2d6116100dc578063ca15c87311610087578063dcf844a711610062578063dcf844a714610a10578063df36bb1314610a3b578063e00a83e014610a50575f80fd5b8063ca15c8731461099f578063ccc57490146109be578063d547741f146109f1575f80fd5b8063bfc7c607116100b7578063bfc7c607146108e2578063c63ff8dd146108f5578063c79371b114610914575f80fd5b8063b13aa2d61461088e578063b250fe6b146108ad578063bf333f2c146108cc575f80fd5b8063a3ec191a1161013c578063ac11fb1a11610117578063ac11fb1a14610810578063add98c701461083c578063affed0e01461085b575f80fd5b8063a3ec191a146107be578063a5bbe22b146105e1578063aa9641ab146107f1575f80fd5b8063926d7d7f1161016c578063926d7d7f146107655780639c9545f014610798578063a217fddf146107ab575f80fd5b806391ad5039146106a557806391d1485414610723575f80fd5b806341fcb6121161024657806363787e52116101f1578063886d36ff116101cc578063886d36ff1461063c5780638f0d6f171461065b5780639010d07c1461066e575f80fd5b806363787e5214610568578063820688d5146105e15780638379a24f146105f6575f80fd5b80635960ccf2116102215780635960ccf2146104ea5780635aa6ccba1461051d5780635eb7d94614610549575f80fd5b806341fcb612146104a357806345851694146104c257806358f85880146104d5575f80fd5b806318e4357d116102a6578063295710ff11610281578063295710ff1461043a5780632f2ff15d1461046557806336568abe14610484575f80fd5b806318e4357d146103d7578063190da595146103f6578063248a9ca31461040c575f80fd5b8063051287bc116102d6578063051287bc1461036657806306f333f2146103a15780630f5f6ed7146103c2575f80fd5b806301ffc9a7146102f157806303ed0ee514610325575b5f80fd5b3480156102fc575f80fd5b5061031061030b366004612e21565b610a65565b60405190151581526020015b60405180910390f35b348015610330575f80fd5b506103587f043c983c49d46f0e102151eaf8085d4a2e6571d5df2d47b013f39bddfd4a639d81565b60405190815260200161031c565b348015610371575f80fd5b50610394610380366004612e60565b5f9081526005602052604090205460ff1690565b60405161031c9190612edd565b3480156103ac575f80fd5b506103c06103bb366004612f0a565b610ac0565b005b3480156103cd575f80fd5b5061035861271081565b3480156103e2575f80fd5b506103c06103f1366004612f41565b610b85565b348015610401575f80fd5b5061035862093a8081565b348015610417575f80fd5b50610358610426366004612e60565b5f9081526020819052604090206001015490565b348015610445575f80fd5b50610358610454366004612f77565b60076020525f908152604090205481565b348015610470575f80fd5b506103c061047f366004612f92565b610cf0565b34801561048f575f80fd5b506103c061049e366004612f92565b610d1a565b3480156104ae575f80fd5b506103c06104bd366004613121565b610d66565b6103c06104d036600461323a565b610fd4565b3480156104e0575f80fd5b5061035860025481565b3480156104f5575f80fd5b506103587fdb9556138406326f00296e13ea2ad7db24ba82381212d816b1a40c23b466b32781565b348015610528575f80fd5b5061053c610537366004613255565b61102c565b60405161031c91906132dc565b348015610554575f80fd5b506103c0610563366004613255565b6110e4565b348015610573575f80fd5b506105d1610582366004612e60565b60056020525f908152604090205460ff811690610100810464ffffffffff16906601000000000000810465ffffffffffff16906c0100000000000000000000000090046001600160a01b031684565b60405161031c94939291906133f0565b3480156105ec575f80fd5b5061035861070881565b348015610601575f80fd5b50610310610610366004612e60565b5f908152600660205260409020546c0100000000000000000000000090046001600160a01b0316151590565b348015610647575f80fd5b506103c0610656366004613431565b6112d5565b6103c0610669366004613255565b6112eb565b348015610679575f80fd5b5061068d610688366004613473565b6112f5565b6040516001600160a01b03909116815260200161031c565b3480156106b0575f80fd5b506106f76106bf366004612e60565b5f90815260056020526040902054610100810464ffffffffff16916c010000000000000000000000009091046001600160a01b031690565b604080516bffffffffffffffffffffffff90931683526001600160a01b0390911660208301520161031c565b34801561072e575f80fd5b5061031061073d366004612f92565b5f918252602082815260408084206001600160a01b0393909316845291905290205460ff1690565b348015610770575f80fd5b506103587fe2b7fb3b832174769106daebcfd6d1970523240dda11281102db9363b83b0dc481565b6103c06107a6366004613121565b611313565b3480156107b6575f80fd5b506103585f81565b3480156107c9575f80fd5b506103587f000000000000000000000000000000000000000000000000000000000000000081565b3480156107fc575f80fd5b5061031061080b366004612f92565b6115c1565b34801561081b575f80fd5b5061082f61082a366004613255565b6116a8565b60405161031c9190613493565b348015610847575f80fd5b506103c0610856366004612e60565b61185b565b348015610866575f80fd5b506103587f000000000000000000000000000000000000000000000000000000000000000081565b348015610899575f80fd5b506103c06108a8366004612e60565b61197a565b3480156108b8575f80fd5b506103c06108c7366004612e60565b611a5c565b3480156108d7575f80fd5b50610358620f424081565b6103c06108f0366004613579565b611ac4565b348015610900575f80fd5b506103c061090f366004613255565b611d3c565b34801561091f575f80fd5b5061097161092e366004612e60565b60066020525f908152604090205465ffffffffffff8082169166010000000000008104909116906c0100000000000000000000000090046001600160a01b031683565b6040805165ffffffffffff94851681529390921660208401526001600160a01b03169082015260600161031c565b3480156109aa575f80fd5b506103586109b9366004612e60565b611d46565b3480156109c9575f80fd5b506103587f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f5581565b3480156109fc575f80fd5b506103c0610a0b366004612f92565b611d5c565b348015610a1b575f80fd5b50610358610a2a366004612f77565b60036020525f908152604090205481565b348015610a46575f80fd5b5061035861ffff81565b348015610a5b575f80fd5b5061035860045481565b5f7fffffffff0000000000000000000000000000000000000000000000000000000082167f5a05180f000000000000000000000000000000000000000000000000000000001480610aba5750610aba82611d80565b92915050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f55610aea81611e16565b6001600160a01b0383165f9081526003602052604081205490819003610b105750505050565b6001600160a01b0384165f81815260036020526040812055610b33908483611e20565b604080516001600160a01b038087168252851660208201529081018290527f244e51bc38c1452fa8aaf487bcb4bca36c2baa3a5fbdb776b1eabd8dc6d277cd9060600160405180910390a1505b505050565b7fe2b7fb3b832174769106daebcfd6d1970523240dda11281102db9363b83b0dc4610baf81611e16565b60015f8581526005602052604090205460ff166004811115610bd357610bd3612e77565b14610c0a576040517f4145817200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f84815260056020908152604091829020805460027fffffffffffffffffffffffffffffffffffffffff0000000000000000000000009091166101004264ffffffffff16027fffffffffffffffffffffffffffffffffffffffff000000000000ffffffffffff161766010000000000004365ffffffffffff160217176bffffffffffffffffffffffff166c010000000000000000000000006001600160a01b0387169081029190911790915582518681529251909287927f4ac8af8a2cd87193d64dfc7a3b8d9923b714ec528b18725d080aa1299be0c5e492918290030190a350505050565b5f82815260208190526040902060010154610d0a81611e16565b610d148383611f3e565b50505050565b6001600160a01b0381163314610d5c576040517f6697b23200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610b808282611f71565b815160208301205f610d778461102c565b905060025f8381526005602052604090205460ff166004811115610d9d57610d9d612e77565b14610dd4576040517f4145817200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600160a01b038316610e10575f828152600560205260409020546c0100000000000000000000000090046001600160a01b03169250610e6f565b5f828152600560205260409020546c0100000000000000000000000090046001600160a01b03163314610e6f576040517f4af43a9000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f8281526005602052604090205461070890610100900464ffffffffff90811642031611610ec9576040517f1992d0bd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f82815260056020526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016600317905561010081015115610f415761010081015160808201516001600160a01b03165f9081526003602052604081208054909190610f3b90849061366e565b90915550505b608081015160c0820151610f5f6001600160a01b0383168683611e20565b5f848152600560209081526040918290205482516001600160a01b038681168252928101859052888316936c010000000000000000000000009092049092169187917f582211c35a2139ac3bbaac74663c6a1f56c6cbb658b41fe11fd45a82074ac678910160405180910390a4505050505050565b611029816040518060a001604052805f6001600160a01b031681526020015f815260200160405180602001604052805f81525081526020015f815260200160405180602001604052805f815250815250611ac4565b50565b6110d0604051806101e001604052805f63ffffffff1681526020015f63ffffffff1681526020015f6001600160a01b031681526020015f6001600160a01b031681526020015f6001600160a01b031681526020015f6001600160a01b031681526020015f81526020015f81526020015f81526020015f81526020015f81526020015f81526020015f6001600160a01b031681526020015f8152602001606081525090565b81806020019051810190610aba91906136d9565b805160208201205f6110f58361102c565b905060015f8381526005602052604090205460ff16600481111561111b5761111b612e77565b14611152576040517f4145817200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b335f9081527fd2043bf65931af3dbecf60d0db8f40e4160406d7beb00522f4200cf4944a1eb8602052604090205460ff16156111cb5780610140015142116111c6576040517fe15ff9ea00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611217565b62093a808161014001516111df919061366e565b4211611217576040517fe15ff9ea00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f8281526005602052604080822080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166004179055820151608083015161010084015160c08501519293919261126f919061366e565b90506112856001600160a01b0383168483611e20565b604080516001600160a01b0384811682526020820184905285169187917fb4c55c0c9bc613519b920e88748090150b890a875d307f21bea7d4fb2e8bc958910160405180910390a3505050505050565b6112e782805190602001208233610b85565b5050565b6110298133611313565b5f82815260016020526040812061130c9083611f9c565b9392505050565b815160208301205f6113248461102c565b9050611331818385611fa7565b604080516060808201835265ffffffffffff438116835242811660208085019182526001600160a01b03808a168688019081525f8a8152600690935296909120945185549251965182166c01000000000000000000000000026bffffffffffffffffffffffff9785166601000000000000027fffffffffffffffffffffffffffffffffffffffff000000000000000000000000909416919094161791909117949094161790915582015160a083015160e084015191929091907fffffffffffffffffffffffff11111111111111111111111111111111111111129083160161148e5761012084015115611450576040517f2598ad2e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b803414611489576040517f81de0bf300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6114e1565b83610120015134146114cc576040517f81de0bf300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6114e16001600160a01b038316338584612149565b6101c08401515115611503576114fe838383876101c001516121c5565b611513565b3415611513576115138334612321565b826001600160a01b0316866001600160a01b0316867ff8ae392d784b1ea5e8881bfa586d81abf07ef4f1e2fc75f7fe51c90f05199a5c875f015188608001518960a001518a60c001518b60e001518c61012001516040516115b09695949392919063ffffffff9690961686526001600160a01b0394851660208701529290931660408501526060840152608083019190915260a082015260c00190565b60405180910390a450505050505050565b5f60025f8481526005602052604090205460ff1660048111156115e6576115e6612e77565b1461161d576040517f4145817200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f838152600560205260409020546001600160a01b038381166c01000000000000000000000000909204161461167f576040517f4af43a9000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b50505f9081526005602052604090205461070861010090910464ffffffffff9081164203161190565b60408051610180810182525f80825260208201819052818301819052606082018190526080820181905260a0820181905260c0820181905260e0820181905261010082018190526101208201819052610140820181905261016082015290517f5aa6ccba0000000000000000000000000000000000000000000000000000000081523090635aa6ccba90611740908590600401613809565b5f60405180830381865afa92505050801561177c57506040513d5f823e601f3d908101601f1916820160405261177991908101906136d9565b60015b6117945781806020019051810190610aba9190613826565b604051806101800160405280825f015163ffffffff168152602001826020015163ffffffff16815260200182604001516001600160a01b0316815260200182606001516001600160a01b0316815260200182608001516001600160a01b031681526020018260a001516001600160a01b031681526020018260c0015181526020018260e00151815260200182610100015181526020018261012001515f1415151581526020018261014001518152602001826101600151815250915050919050565b919050565b7f043c983c49d46f0e102151eaf8085d4a2e6571d5df2d47b013f39bddfd4a639d61188581611e16565b60025f8381526005602052604090205460ff1660048111156118a9576118a9612e77565b146118e0576040517f4145817200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f8281526005602052604090205461070890610100900464ffffffffff908116420316111561193b576040517f3e908aac00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f828152600560205260408082206001905551339184917f0695cf1d39b3055dcd0fe02d8b47eaf0d5a13e1996de925de59d0ef9b7f7fad49190a35050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f556119a481611e16565b612710821115611a15576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f6e657746656552617465203e206d61780000000000000000000000000000000060448201526064015b60405180910390fd5b600280549083905560408051828152602081018590527f14914da2bf76024616fbe1859783fcd4dbddcb179b1f3a854949fbf920dcb95791015b60405180910390a1505050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f55611a8681611e16565b600480549083905560408051828152602081018590527f5cf09b12f3f56b4c564d51b25b40360af6d795198adb61ae0806a36c294323fa9101611a4f565b5f816020015142611ad591906138f0565b9050611ae28383836123e6565b5f611af584606001518560a00151612669565b90505f806002541115611b2157620f424060025483611b149190613917565b611b1e919061392e565b90505b611b2b8183613966565b91505f604051806101e001604052804663ffffffff168152602001875f015163ffffffff16815260200187602001516001600160a01b0316815260200187604001516001600160a01b0316815260200187606001516001600160a01b0316815260200187608001516001600160a01b031681526020018481526020018760c00151815260200183815260200186606001518152602001876101000151815260200160075f89602001516001600160a01b03166001600160a01b031681526020019081526020015f205f815480929190611c0390613979565b919050558152602001865f01516001600160a01b031681526020018581526020018660800151815250604051602001611c3c91906132dc565b60408051808303601f1901815282825280516020808301919091205f818152600583529390932080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016600117905589015189516060808c015160808d015160c08e0151928d015195985095966001600160a01b039094169587957f120ea0364f36cdac7983bcfdd55270ca09d7f9b314a2ebc425a3b01ab1d6403a95611cef958b95909493928e92901515906139b0565b60405180910390a3807f3120e2bb59c86aca6890191a589a96af3662838efa374fbdcdf4c95bfe4a6c0e8760400151604051611d2b9190613809565b60405180910390a250505050505050565b611029815f610d66565b5f818152600160205260408120610aba9061280d565b5f82815260208190526040902060010154611d7681611e16565b610d148383611f71565b5f7fffffffff0000000000000000000000000000000000000000000000000000000082167f7965db0b000000000000000000000000000000000000000000000000000000001480610aba57507f01ffc9a7000000000000000000000000000000000000000000000000000000007fffffffff00000000000000000000000000000000000000000000000000000000831614610aba565b6110298133612816565b306001600160a01b03831603611e3557505050565b805f03611e4157505050565b7fffffffffffffffffffffffff11111111111111111111111111111111111111126001600160a01b03841601611f2a575f826001600160a01b0316826040515f6040518083038185875af1925050503d805f8114611eba576040519150601f19603f3d011682016040523d82523d5f602084013e611ebf565b606091505b5050905080610d14576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f455448207472616e73666572206661696c6564000000000000000000000000006044820152606401611a0c565b610b806001600160a01b0384168383612881565b5f80611f4a84846128b2565b9050801561130c575f848152600160205260409020611f699084612977565b509392505050565b5f80611f7d848461298b565b9050801561130c575f848152600160205260409020611f699084612a2a565b5f61130c8383612a3e565b6001600160a01b038116611fe7576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f828152600660205260409020546c0100000000000000000000000090046001600160a01b031615612045576040517fbef7bb7d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b4663ffffffff16836020015163ffffffff161461208e576040517f7029fdf900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8261014001514211156120cd576040517f559895a300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6101808301516001600160a01b0316158015906121015750806001600160a01b03168361018001516001600160a01b031614155b80156121125750826101a001514211155b15610b80576040517f14be123200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040516001600160a01b038481166024830152838116604483015260648201839052610d149186918216906323b872dd906084015b604051602081830303815290604052915060e01b6020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8381831617835250505050612a64565b5f8383836040516024016121db93929190613a05565b60408051601f198184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f461e0c210000000000000000000000000000000000000000000000000000000017905290505f612241868334612ade565b905080515f0361227d576040517f1a95ad2600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80516020146122b8576040517ff3725cca00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f461e0c21000000000000000000000000000000000000000000000000000000006122e282613a35565b14612319576040517ff3725cca00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b505050505050565b8047101561235d576040517fcd786059000000000000000000000000000000000000000000000000000000008152306004820152602401611a0c565b5f826001600160a01b0316826040515f6040518083038185875af1925050503d805f81146123a6576040519150601f19603f3d011682016040523d82523d5f602084013e6123ab565b606091505b5050905080610b80576040517f1425ea4200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b46835f015163ffffffff1603612428576040517f7029fdf900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60a0830151158061243b575060c0830151155b15612472576040517fe38820c800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60208301516001600160a01b03161580612497575060408301516001600160a01b0316155b156124ce576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60608301516001600160a01b031615806124f3575060808301516001600160a01b0316155b1561252a576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6125366107084261366e565b8361010001511015612574576040517f04b7fcc800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61ffff82608001515111156125b5576040517ffbe24d4900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6060820151158015906125e8575060808301516001600160a01b031673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee145b1561261f576040517f2598ad2e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f81131580612632575082610100015181135b15610b80576040517f352807b900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f7fffffffffffffffffffffffff11111111111111111111111111111111111111126001600160a01b038416016126da573482146126d3576040517f81de0bf300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5034610aba565b6126ec836001600160a01b0316612b90565b6040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201526001600160a01b038416906370a0823190602401602060405180830381865afa158015612747573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061276b9190613a7a565b90506127826001600160a01b038416333085612149565b6040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015281906001600160a01b038516906370a0823190602401602060405180830381865afa1580156127df573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906128039190613a7a565b61130c9190613966565b5f610aba825490565b5f828152602081815260408083206001600160a01b038516845290915290205460ff166112e7576040517fe2517d3f0000000000000000000000000000000000000000000000000000000081526001600160a01b038216600482015260248101839052604401611a0c565b6040516001600160a01b03838116602483015260448201839052610b8091859182169063a9059cbb9060640161217e565b5f828152602081815260408083206001600160a01b038516845290915281205460ff16612970575f838152602081815260408083206001600160a01b0386168452909152902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790556129283390565b6001600160a01b0316826001600160a01b0316847f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a4506001610aba565b505f610aba565b5f61130c836001600160a01b038416612c35565b5f828152602081815260408083206001600160a01b038516845290915281205460ff1615612970575f838152602081815260408083206001600160a01b038616808552925280832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016905551339286917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a4506001610aba565b5f61130c836001600160a01b038416612c7a565b5f825f018281548110612a5357612a53613a91565b905f5260205f200154905092915050565b5f612a786001600160a01b03841683612d5d565b905080515f14158015612a9c575080806020019051810190612a9a9190613abe565b155b15610b80576040517f5274afe70000000000000000000000000000000000000000000000000000000081526001600160a01b0384166004820152602401611a0c565b606081471015612b1c576040517fcd786059000000000000000000000000000000000000000000000000000000008152306004820152602401611a0c565b5f80856001600160a01b03168486604051612b379190613ad9565b5f6040518083038185875af1925050503d805f8114612b71576040519150601f19603f3d011682016040523d82523d5f602084013e612b76565b606091505b5091509150612b86868383612d6a565b9695505050505050565b7fffffffffffffffffffffffff11111111111111111111111111111111111111126001600160a01b03821601612bf2576040517f7f523fe800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b806001600160a01b03163b5f03611029576040517f7f523fe800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f81815260018301602052604081205461297057508154600181810184555f848152602080822090930184905584548482528286019093526040902091909155610aba565b5f8181526001830160205260408120548015612d54575f612c9c600183613966565b85549091505f90612caf90600190613966565b9050808214612d0e575f865f018281548110612ccd57612ccd613a91565b905f5260205f200154905080875f018481548110612ced57612ced613a91565b5f918252602080832090910192909255918252600188019052604090208390555b8554869080612d1f57612d1f613af4565b600190038181905f5260205f20015f90559055856001015f8681526020019081526020015f205f905560019350505050610aba565b5f915050610aba565b606061130c83835f612ade565b606082612d7f57612d7a82612ddf565b61130c565b8151158015612d9657506001600160a01b0384163b155b15612dd8576040517f9996b3150000000000000000000000000000000000000000000000000000000081526001600160a01b0385166004820152602401611a0c565b508061130c565b805115612def5780518082602001fd5b6040517f1425ea4200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f60208284031215612e31575f80fd5b81357fffffffff000000000000000000000000000000000000000000000000000000008116811461130c575f80fd5b5f60208284031215612e70575f80fd5b5035919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602160045260245ffd5b60058110612ed9577f4e487b71000000000000000000000000000000000000000000000000000000005f52602160045260245ffd5b9052565b60208101610aba8284612ea4565b6001600160a01b0381168114611029575f80fd5b803561185681612eeb565b5f8060408385031215612f1b575f80fd5b8235612f2681612eeb565b91506020830135612f3681612eeb565b809150509250929050565b5f805f60608486031215612f53575f80fd5b83359250602084013591506040840135612f6c81612eeb565b809150509250925092565b5f60208284031215612f87575f80fd5b813561130c81612eeb565b5f8060408385031215612fa3575f80fd5b823591506020830135612f3681612eeb565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b604051610120810167ffffffffffffffff8111828210171561300657613006612fb5565b60405290565b60405160a0810167ffffffffffffffff8111828210171561300657613006612fb5565b6040516101e0810167ffffffffffffffff8111828210171561300657613006612fb5565b604051610180810167ffffffffffffffff8111828210171561300657613006612fb5565b604051601f8201601f1916810167ffffffffffffffff811182821017156130a0576130a0612fb5565b604052919050565b5f67ffffffffffffffff8211156130c1576130c1612fb5565b50601f01601f191660200190565b5f82601f8301126130de575f80fd5b81356130f16130ec826130a8565b613077565b818152846020838601011115613105575f80fd5b816020850160208301375f918101602001919091529392505050565b5f8060408385031215613132575f80fd5b823567ffffffffffffffff811115613148575f80fd5b613154858286016130cf565b9250506020830135612f3681612eeb565b63ffffffff81168114611029575f80fd5b803561185681613165565b8015158114611029575f80fd5b803561185681613181565b5f61012082840312156131aa575f80fd5b6131b2612fe2565b90506131bd82613176565b81526131cb60208301612eff565b60208201526131dc60408301612eff565b60408201526131ed60608301612eff565b60608201526131fe60808301612eff565b608082015260a082013560a082015260c082013560c082015261322360e0830161318e565b60e082015261010080830135818301525092915050565b5f610120828403121561324b575f80fd5b61130c8383613199565b5f60208284031215613265575f80fd5b813567ffffffffffffffff81111561327b575f80fd5b613287848285016130cf565b949350505050565b5f5b838110156132a9578181015183820152602001613291565b50505f910152565b5f81518084526132c881602086016020860161328f565b601f01601f19169290920160200192915050565b602081526132f360208201835163ffffffff169052565b5f602083015161330b604084018263ffffffff169052565b5060408301516001600160a01b03811660608401525060608301516001600160a01b03811660808401525060808301516001600160a01b03811660a08401525060a08301516001600160a01b03811660c08401525060c083015160e08381019190915283015161010080840191909152830151610120808401919091528301516101408084019190915283015161016080840191909152830151610180808401919091528301516101a06133c9818501836001600160a01b03169052565b8401516101c0848101919091528401516101e08085015290506132876102008401826132b1565b608081016133fe8287612ea4565b64ffffffffff8516602083015265ffffffffffff841660408301526001600160a01b038316606083015295945050505050565b5f8060408385031215613442575f80fd5b823567ffffffffffffffff811115613458575f80fd5b613464858286016130cf565b95602094909401359450505050565b5f8060408385031215613484575f80fd5b50508035926020909101359150565b815163ffffffff168152610180810160208301516134b9602084018263ffffffff169052565b5060408301516134d460408401826001600160a01b03169052565b5060608301516134ef60608401826001600160a01b03169052565b50608083015161350a60808401826001600160a01b03169052565b5060a083015161352560a08401826001600160a01b03169052565b5060c083015160c083015260e083015160e08301526101008084015181840152506101208084015161355a8285018215159052565b5050610140838101519083015261016092830151929091019190915290565b5f80610140838503121561358b575f80fd5b6135958484613199565b915061012083013567ffffffffffffffff808211156135b2575f80fd5b9084019060a082870312156135c5575f80fd5b6135cd61300c565b82356135d881612eeb565b8152602083810135908201526040830135828111156135f5575f80fd5b613601888286016130cf565b60408301525060608301356060820152608083013582811115613622575f80fd5b61362e888286016130cf565b6080830152508093505050509250929050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b80820180821115610aba57610aba613641565b805161185681613165565b805161185681612eeb565b5f82601f8301126136a6575f80fd5b81516136b46130ec826130a8565b8181528460208386010111156136c8575f80fd5b61328782602083016020870161328f565b5f602082840312156136e9575f80fd5b815167ffffffffffffffff80821115613700575f80fd5b908301906101e08286031215613714575f80fd5b61371c61302f565b61372583613681565b815261373360208401613681565b60208201526137446040840161368c565b60408201526137556060840161368c565b60608201526137666080840161368c565b608082015261377760a0840161368c565b60a082015260c0838101519082015260e0808401519082015261010080840151908201526101208084015190820152610140808401519082015261016080840151908201526101806137ca81850161368c565b908201526101a083810151908201526101c080840151838111156137ec575f80fd5b6137f888828701613697565b918301919091525095945050505050565b602081525f61130c60208301846132b1565b805161185681613181565b5f6101808284031215613837575f80fd5b61383f613053565b61384883613681565b815261385660208401613681565b60208201526138676040840161368c565b60408201526138786060840161368c565b60608201526138896080840161368c565b608082015261389a60a0840161368c565b60a082015260c083015160c082015260e083015160e08201526101008084015181830152506101206138cd81850161381b565b908201526101408381015190820152610160928301519281019290925250919050565b8082018281125f83128015821682158216171561390f5761390f613641565b505092915050565b8082028115828204841417610aba57610aba613641565b5f82613961577f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b500490565b81810381811115610aba57610aba613641565b5f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82036139a9576139a9613641565b5060010190565b60e081525f6139c260e083018a6132b1565b63ffffffff989098166020830152506001600160a01b039586166040820152939094166060840152608083019190915260a082015290151560c090910152919050565b6001600160a01b0384168152826020820152606060408201525f613a2c60608301846132b1565b95945050505050565b80516020808301519190811015613a74577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8160200360031b1b821691505b50919050565b5f60208284031215613a8a575f80fd5b5051919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b5f60208284031215613ace575f80fd5b815161130c81613181565b5f8251613aea81846020870161328f565b9190910192915050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603160045260245ffdfea264697066735822122007a09ea15c5efbb28f239593161aeb6ee596d67bad8a87d0cd46703d115a053164736f6c63430008180033", + Bin: "0x60c060405260006080523480156200001657600080fd5b5060405162003e5a38038062003e5a833981016040819052620000399162000199565b806200004760008262000054565b50504360a05250620001c4565b60008062000063848462000091565b90508015620000885760008481526001602052604090206200008690846200013f565b505b90505b92915050565b6000828152602081815260408083206001600160a01b038516845290915281205460ff1662000136576000838152602081815260408083206001600160a01b03861684529091529020805460ff19166001179055620000ed3390565b6001600160a01b0316826001600160a01b0316847f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45060016200008b565b5060006200008b565b600062000088836001600160a01b038416600081815260018301602052604081205462000136575081546001818101845560008481526020808220909301849055845484825282860190935260409020919091556200008b565b600060208284031215620001ac57600080fd5b81516001600160a01b03811681146200008857600080fd5b60805160a051613c70620001ea6000396000610802015260006108a30152613c706000f3fe6080604052600436106102fd5760003560e01c806391ad50391161018f578063b13aa2d6116100e1578063ca15c8731161008a578063dcf844a711610064578063dcf844a714610a50578063df36bb1314610a7d578063e00a83e014610a9357600080fd5b8063ca15c873146109dc578063ccc57490146109fc578063d547741f14610a3057600080fd5b8063bfc7c607116100bb578063bfc7c6071461091c578063c63ff8dd1461092f578063c79371b11461094f57600080fd5b8063b13aa2d6146108c5578063b250fe6b146108e5578063bf333f2c1461090557600080fd5b8063a3ec191a11610143578063ac11fb1a1161011d578063ac11fb1a14610844578063add98c7014610871578063affed0e01461089157600080fd5b8063a3ec191a146107f0578063a5bbe22b14610607578063aa9641ab1461082457600080fd5b8063926d7d7f11610174578063926d7d7f146107945780639c9545f0146107c8578063a217fddf146107db57600080fd5b806391ad5039146106d057806391d148541461075057600080fd5b806341fcb6121161025357806363787e52116101fc578063886d36ff116101d6578063886d36ff146106655780638f0d6f17146106855780639010d07c1461069857600080fd5b806363787e521461058c578063820688d5146106075780638379a24f1461061d57600080fd5b80635960ccf21161022d5780635960ccf21461050b5780635aa6ccba1461053f5780635eb7d9461461056c57600080fd5b806341fcb612146104c257806345851694146104e257806358f85880146104f557600080fd5b806318e4357d116102b5578063295710ff1161028f578063295710ff146104555780632f2ff15d1461048257806336568abe146104a257600080fd5b806318e4357d146103ee578063190da5951461040e578063248a9ca31461042557600080fd5b8063051287bc116102e6578063051287bc1461037957806306f333f2146103b65780630f5f6ed7146103d857600080fd5b806301ffc9a71461030257806303ed0ee514610337575b600080fd5b34801561030e57600080fd5b5061032261031d366004612ee8565b610aa9565b60405190151581526020015b60405180910390f35b34801561034357600080fd5b5061036b7f043c983c49d46f0e102151eaf8085d4a2e6571d5df2d47b013f39bddfd4a639d81565b60405190815260200161032e565b34801561038557600080fd5b506103a9610394366004612f2a565b60009081526005602052604090205460ff1690565b60405161032e9190612fad565b3480156103c257600080fd5b506103d66103d1366004612fdb565b610b05565b005b3480156103e457600080fd5b5061036b61271081565b3480156103fa57600080fd5b506103d6610409366004613014565b610bcc565b34801561041a57600080fd5b5061036b62093a8081565b34801561043157600080fd5b5061036b610440366004612f2a565b60009081526020819052604090206001015490565b34801561046157600080fd5b5061036b61047036600461304d565b60076020526000908152604090205481565b34801561048e57600080fd5b506103d661049d36600461306a565b610d39565b3480156104ae57600080fd5b506103d66104bd36600461306a565b610d64565b3480156104ce57600080fd5b506103d66104dd366004613202565b610db0565b6103d66104f0366004613322565b611026565b34801561050157600080fd5b5061036b60025481565b34801561051757600080fd5b5061036b7fdb9556138406326f00296e13ea2ad7db24ba82381212d816b1a40c23b466b32781565b34801561054b57600080fd5b5061055f61055a36600461333f565b611083565b60405161032e91906133cc565b34801561057857600080fd5b506103d661058736600461333f565b611149565b34801561059857600080fd5b506105f76105a7366004612f2a565b60056020526000908152604090205460ff811690610100810464ffffffffff16906601000000000000810465ffffffffffff16906c0100000000000000000000000090046001600160a01b031684565b60405161032e94939291906134e1565b34801561061357600080fd5b5061036b61070881565b34801561062957600080fd5b50610322610638366004612f2a565b6000908152600660205260409020546c0100000000000000000000000090046001600160a01b0316151590565b34801561067157600080fd5b506103d6610680366004613522565b61133e565b6103d661069336600461333f565b611354565b3480156106a457600080fd5b506106b86106b3366004613567565b61135e565b6040516001600160a01b03909116815260200161032e565b3480156106dc57600080fd5b506107246106eb366004612f2a565b600090815260056020526040902054610100810464ffffffffff16916c010000000000000000000000009091046001600160a01b031690565b604080516bffffffffffffffffffffffff90931683526001600160a01b0390911660208301520161032e565b34801561075c57600080fd5b5061032261076b36600461306a565b6000918252602082815260408084206001600160a01b0393909316845291905290205460ff1690565b3480156107a057600080fd5b5061036b7fe2b7fb3b832174769106daebcfd6d1970523240dda11281102db9363b83b0dc481565b6103d66107d6366004613202565b61137d565b3480156107e757600080fd5b5061036b600081565b3480156107fc57600080fd5b5061036b7f000000000000000000000000000000000000000000000000000000000000000081565b34801561083057600080fd5b5061032261083f36600461306a565b61162e565b34801561085057600080fd5b5061086461085f36600461333f565b611719565b60405161032e9190613589565b34801561087d57600080fd5b506103d661088c366004612f2a565b6118d1565b34801561089d57600080fd5b5061036b7f000000000000000000000000000000000000000000000000000000000000000081565b3480156108d157600080fd5b506103d66108e0366004612f2a565b6119f3565b3480156108f157600080fd5b506103d6610900366004612f2a565b611ad5565b34801561091157600080fd5b5061036b620f424081565b6103d661092a36600461366f565b611b3d565b34801561093b57600080fd5b506103d661094a36600461333f565b611dbf565b34801561095b57600080fd5b506109ae61096a366004612f2a565b60066020526000908152604090205465ffffffffffff8082169166010000000000008104909116906c0100000000000000000000000090046001600160a01b031683565b6040805165ffffffffffff94851681529390921660208401526001600160a01b03169082015260600161032e565b3480156109e857600080fd5b5061036b6109f7366004612f2a565b611dca565b348015610a0857600080fd5b5061036b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f5581565b348015610a3c57600080fd5b506103d6610a4b36600461306a565b611de1565b348015610a5c57600080fd5b5061036b610a6b36600461304d565b60036020526000908152604090205481565b348015610a8957600080fd5b5061036b61ffff81565b348015610a9f57600080fd5b5061036b60045481565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f5a05180f000000000000000000000000000000000000000000000000000000001480610aff5750610aff82611e06565b92915050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f55610b2f81611e9d565b6001600160a01b03831660009081526003602052604081205490819003610b565750505050565b6001600160a01b038416600081815260036020526040812055610b7a908483611ea7565b604080516001600160a01b038087168252851660208201529081018290527f244e51bc38c1452fa8aaf487bcb4bca36c2baa3a5fbdb776b1eabd8dc6d277cd9060600160405180910390a1505b505050565b7fe2b7fb3b832174769106daebcfd6d1970523240dda11281102db9363b83b0dc4610bf681611e9d565b600160008581526005602052604090205460ff166004811115610c1b57610c1b612f43565b14610c52576040517f4145817200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600084815260056020908152604091829020805460027fffffffffffffffffffffffffffffffffffffffff0000000000000000000000009091166101004264ffffffffff16027fffffffffffffffffffffffffffffffffffffffff000000000000ffffffffffff161766010000000000004365ffffffffffff160217176bffffffffffffffffffffffff166c010000000000000000000000006001600160a01b0387169081029190911790915582518681529251909287927f4ac8af8a2cd87193d64dfc7a3b8d9923b714ec528b18725d080aa1299be0c5e492918290030190a350505050565b600082815260208190526040902060010154610d5481611e9d565b610d5e8383611fca565b50505050565b6001600160a01b0381163314610da6576040517f6697b23200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610bc78282611fff565b815160208301206000610dc284611083565b9050600260008381526005602052604090205460ff166004811115610de957610de9612f43565b14610e20576040517f4145817200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600160a01b038316610e5d576000828152600560205260409020546c0100000000000000000000000090046001600160a01b03169250610ebd565b6000828152600560205260409020546c0100000000000000000000000090046001600160a01b03163314610ebd576040517f4af43a9000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008281526005602052604090205461070890610100900464ffffffffff90811642031611610f18576040517f1992d0bd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600082815260056020526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016600317905561010081015115610f925761010081015160808201516001600160a01b031660009081526003602052604081208054909190610f8c90849061376c565b90915550505b608081015160c0820151610fb06001600160a01b0383168683611ea7565b6000848152600560209081526040918290205482516001600160a01b038681168252928101859052888316936c010000000000000000000000009092049092169187917f582211c35a2139ac3bbaac74663c6a1f56c6cbb658b41fe11fd45a82074ac678910160405180910390a4505050505050565b611080816040518060a0016040528060006001600160a01b03168152602001600081526020016040518060200160405280600081525081526020016000815260200160405180602001604052806000815250815250611b3d565b50565b611135604051806101e00160405280600063ffffffff168152602001600063ffffffff16815260200160006001600160a01b0316815260200160006001600160a01b0316815260200160006001600160a01b0316815260200160006001600160a01b0316815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160006001600160a01b0316815260200160008152602001606081525090565b81806020019051810190610aff91906137da565b80516020820120600061115b83611083565b9050600160008381526005602052604090205460ff16600481111561118257611182612f43565b146111b9576040517f4145817200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b3360009081527fd2043bf65931af3dbecf60d0db8f40e4160406d7beb00522f4200cf4944a1eb8602052604090205460ff161561123357806101400151421161122e576040517fe15ff9ea00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61127f565b62093a80816101400151611247919061376c565b421161127f576040517fe15ff9ea00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008281526005602052604080822080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166004179055820151608083015161010084015160c0850151929391926112d8919061376c565b90506112ee6001600160a01b0383168483611ea7565b604080516001600160a01b0384811682526020820184905285169187917fb4c55c0c9bc613519b920e88748090150b890a875d307f21bea7d4fb2e8bc958910160405180910390a3505050505050565b61135082805190602001208233610bcc565b5050565b611080813361137d565b6000828152600160205260408120611376908361202c565b9392505050565b81516020830120600061138f84611083565b905061139c818385612038565b604080516060808201835265ffffffffffff438116835242811660208085019182526001600160a01b03808a1686880190815260008a8152600690935296909120945185549251965182166c01000000000000000000000000026bffffffffffffffffffffffff9785166601000000000000027fffffffffffffffffffffffffffffffffffffffff000000000000000000000000909416919094161791909117949094161790915582015160a083015160e084015191929091907fffffffffffffffffffffffff1111111111111111111111111111111111111112908316016114fa57610120840151156114bc576040517f2598ad2e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8034146114f5576040517f81de0bf300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61154d565b8361012001513414611538576040517f81de0bf300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61154d6001600160a01b0383163385846121db565b6101c0840151511561156f5761156a838383876101c00151612257565b61157f565b341561157f5761157f83346123b6565b826001600160a01b0316866001600160a01b0316867ff8ae392d784b1ea5e8881bfa586d81abf07ef4f1e2fc75f7fe51c90f05199a5c876000015188608001518960a001518a60c001518b60e001518c610120015160405161161d9695949392919063ffffffff9690961686526001600160a01b0394851660208701529290931660408501526060840152608083019190915260a082015260c00190565b60405180910390a450505050505050565b6000600260008481526005602052604090205460ff16600481111561165557611655612f43565b1461168c576040517f4145817200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000838152600560205260409020546001600160a01b038381166c0100000000000000000000000090920416146116ef576040517f4af43a9000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b505060009081526005602052604090205461070861010090910464ffffffffff9081164203161190565b6040805161018081018252600080825260208201819052818301819052606082018190526080820181905260a0820181905260c0820181905260e0820181905261010082018190526101208201819052610140820181905261016082015290517f5aa6ccba0000000000000000000000000000000000000000000000000000000081523090635aa6ccba906117b290859060040161390f565b600060405180830381865afa9250505080156117f057506040513d6000823e601f3d908101601f191682016040526117ed91908101906137da565b60015b6118085781806020019051810190610aff919061392d565b604051806101800160405280826000015163ffffffff168152602001826020015163ffffffff16815260200182604001516001600160a01b0316815260200182606001516001600160a01b0316815260200182608001516001600160a01b031681526020018260a001516001600160a01b031681526020018260c0015181526020018260e001518152602001826101000151815260200182610120015160001415151581526020018261014001518152602001826101600151815250915050919050565b919050565b7f043c983c49d46f0e102151eaf8085d4a2e6571d5df2d47b013f39bddfd4a639d6118fb81611e9d565b600260008381526005602052604090205460ff16600481111561192057611920612f43565b14611957576040517f4145817200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008281526005602052604090205461070890610100900464ffffffffff90811642031611156119b3576040517f3e908aac00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000828152600560205260408082206001905551339184917f0695cf1d39b3055dcd0fe02d8b47eaf0d5a13e1996de925de59d0ef9b7f7fad49190a35050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f55611a1d81611e9d565b612710821115611a8e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f6e657746656552617465203e206d61780000000000000000000000000000000060448201526064015b60405180910390fd5b600280549083905560408051828152602081018590527f14914da2bf76024616fbe1859783fcd4dbddcb179b1f3a854949fbf920dcb95791015b60405180910390a1505050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f55611aff81611e9d565b600480549083905560408051828152602081018590527f5cf09b12f3f56b4c564d51b25b40360af6d795198adb61ae0806a36c294323fa9101611ac8565b6000816020015142611b4f91906139f9565b9050611b5c83838361247f565b6000611b7084606001518560a00151612704565b90506000806002541115611b9d57620f424060025483611b909190613a21565b611b9a9190613a38565b90505b611ba78183613a73565b91506000604051806101e001604052804663ffffffff168152602001876000015163ffffffff16815260200187602001516001600160a01b0316815260200187604001516001600160a01b0316815260200187606001516001600160a01b0316815260200187608001516001600160a01b031681526020018481526020018760c0015181526020018381526020018660600151815260200187610100015181526020016007600089602001516001600160a01b03166001600160a01b031681526020019081526020016000206000815480929190611c8490613a86565b91905055815260200186600001516001600160a01b031681526020018581526020018660800151815250604051602001611cbe91906133cc565b60408051808303601f1901815282825280516020808301919091206000818152600583529390932080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016600117905589015189516060808c015160808d015160c08e0151928d015195985095966001600160a01b039094169587957f120ea0364f36cdac7983bcfdd55270ca09d7f9b314a2ebc425a3b01ab1d6403a95611d72958b95909493928e9290151590613abe565b60405180910390a3807f3120e2bb59c86aca6890191a589a96af3662838efa374fbdcdf4c95bfe4a6c0e8760400151604051611dae919061390f565b60405180910390a250505050505050565b611080816000610db0565b6000818152600160205260408120610aff906128ad565b600082815260208190526040902060010154611dfc81611e9d565b610d5e8383611fff565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f7965db0b000000000000000000000000000000000000000000000000000000001480610aff57507f01ffc9a7000000000000000000000000000000000000000000000000000000007fffffffff00000000000000000000000000000000000000000000000000000000831614610aff565b61108081336128b7565b306001600160a01b03831603611ebc57505050565b80600003611ec957505050565b7fffffffffffffffffffffffff11111111111111111111111111111111111111126001600160a01b03841601611fb6576000826001600160a01b03168260405160006040518083038185875af1925050503d8060008114611f46576040519150601f19603f3d011682016040523d82523d6000602084013e611f4b565b606091505b5050905080610d5e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f455448207472616e73666572206661696c6564000000000000000000000000006044820152606401611a85565b610bc76001600160a01b0384168383612923565b600080611fd78484612954565b90508015611376576000848152600160205260409020611ff79084612a1c565b509392505050565b60008061200c8484612a31565b90508015611376576000848152600160205260409020611ff79084612ad2565b60006113768383612ae7565b6001600160a01b038116612078576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000828152600660205260409020546c0100000000000000000000000090046001600160a01b0316156120d7576040517fbef7bb7d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b4663ffffffff16836020015163ffffffff1614612120576040517f7029fdf900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b82610140015142111561215f576040517f559895a300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6101808301516001600160a01b0316158015906121935750806001600160a01b03168361018001516001600160a01b031614155b80156121a45750826101a001514211155b15610bc7576040517f14be123200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040516001600160a01b038481166024830152838116604483015260648201839052610d5e9186918216906323b872dd906084015b604051602081830303815290604052915060e01b6020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8381831617835250505050612b11565b600083838360405160240161226e93929190613b14565b60408051601f198184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f461e0c2100000000000000000000000000000000000000000000000000000000179052905060006122d5868334612b8d565b90508051600003612312576040517f1a95ad2600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b805160201461234d576040517ff3725cca00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f461e0c210000000000000000000000000000000000000000000000000000000061237782613b45565b146123ae576040517ff3725cca00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b505050505050565b804710156123f2576040517fcd786059000000000000000000000000000000000000000000000000000000008152306004820152602401611a85565b6000826001600160a01b03168260405160006040518083038185875af1925050503d806000811461243f576040519150601f19603f3d011682016040523d82523d6000602084013e612444565b606091505b5050905080610bc7576040517f1425ea4200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b46836000015163ffffffff16036124c2576040517f7029fdf900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60a083015115806124d5575060c0830151155b1561250c576040517fe38820c800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60208301516001600160a01b03161580612531575060408301516001600160a01b0316155b15612568576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60608301516001600160a01b0316158061258d575060808301516001600160a01b0316155b156125c4576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6125d06107084261376c565b836101000151101561260e576040517f04b7fcc800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61ffff826080015151111561264f576040517ffbe24d4900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b606082015115801590612682575060808301516001600160a01b031673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee145b156126b9576040517f2598ad2e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000811315806126cd575082610100015181135b15610bc7576040517f352807b900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60007fffffffffffffffffffffffff11111111111111111111111111111111111111126001600160a01b038416016127765734821461276f576040517f81de0bf300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5034610aff565b612788836001600160a01b0316612c43565b6040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201526001600160a01b038416906370a0823190602401602060405180830381865afa1580156127e5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128099190613b8a565b90506128206001600160a01b0384163330856121db565b6040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015281906001600160a01b038516906370a0823190602401602060405180830381865afa15801561287f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128a39190613b8a565b6113769190613a73565b6000610aff825490565b6000828152602081815260408083206001600160a01b038516845290915290205460ff16611350576040517fe2517d3f0000000000000000000000000000000000000000000000000000000081526001600160a01b038216600482015260248101839052604401611a85565b6040516001600160a01b03838116602483015260448201839052610bc791859182169063a9059cbb90606401612210565b6000828152602081815260408083206001600160a01b038516845290915281205460ff16612a14576000838152602081815260408083206001600160a01b0386168452909152902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790556129cc3390565b6001600160a01b0316826001600160a01b0316847f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a4506001610aff565b506000610aff565b6000611376836001600160a01b038416612ce9565b6000828152602081815260408083206001600160a01b038516845290915281205460ff1615612a14576000838152602081815260408083206001600160a01b038616808552925280832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016905551339286917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a4506001610aff565b6000611376836001600160a01b038416612d30565b6000826000018281548110612afe57612afe613ba3565b9060005260206000200154905092915050565b6000612b266001600160a01b03841683612e23565b90508051600014158015612b4b575080806020019051810190612b499190613bd2565b155b15610bc7576040517f5274afe70000000000000000000000000000000000000000000000000000000081526001600160a01b0384166004820152602401611a85565b606081471015612bcb576040517fcd786059000000000000000000000000000000000000000000000000000000008152306004820152602401611a85565b600080856001600160a01b03168486604051612be79190613bef565b60006040518083038185875af1925050503d8060008114612c24576040519150601f19603f3d011682016040523d82523d6000602084013e612c29565b606091505b5091509150612c39868383612e31565b9695505050505050565b7fffffffffffffffffffffffff11111111111111111111111111111111111111126001600160a01b03821601612ca5576040517f7f523fe800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b806001600160a01b03163b600003611080576040517f7f523fe800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000818152600183016020526040812054612a1457508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155610aff565b60008181526001830160205260408120548015612e19576000612d54600183613a73565b8554909150600090612d6890600190613a73565b9050808214612dcd576000866000018281548110612d8857612d88613ba3565b9060005260206000200154905080876000018481548110612dab57612dab613ba3565b6000918252602080832090910192909255918252600188019052604090208390555b8554869080612dde57612dde613c0b565b600190038181906000526020600020016000905590558560010160008681526020019081526020016000206000905560019350505050610aff565b6000915050610aff565b606061137683836000612b8d565b606082612e4657612e4182612ea6565b611376565b8151158015612e5d57506001600160a01b0384163b155b15612e9f576040517f9996b3150000000000000000000000000000000000000000000000000000000081526001600160a01b0385166004820152602401611a85565b5080611376565b805115612eb65780518082602001fd5b6040517f1425ea4200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600060208284031215612efa57600080fd5b81357fffffffff000000000000000000000000000000000000000000000000000000008116811461137657600080fd5b600060208284031215612f3c57600080fd5b5035919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b60058110612fa9577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b9052565b60208101610aff8284612f72565b6001600160a01b038116811461108057600080fd5b80356118cc81612fbb565b60008060408385031215612fee57600080fd5b8235612ff981612fbb565b9150602083013561300981612fbb565b809150509250929050565b60008060006060848603121561302957600080fd5b8335925060208401359150604084013561304281612fbb565b809150509250925092565b60006020828403121561305f57600080fd5b813561137681612fbb565b6000806040838503121561307d57600080fd5b82359150602083013561300981612fbb565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051610120810167ffffffffffffffff811182821017156130e2576130e261308f565b60405290565b60405160a0810167ffffffffffffffff811182821017156130e2576130e261308f565b6040516101e0810167ffffffffffffffff811182821017156130e2576130e261308f565b604051610180810167ffffffffffffffff811182821017156130e2576130e261308f565b604051601f8201601f1916810167ffffffffffffffff8111828210171561317c5761317c61308f565b604052919050565b600067ffffffffffffffff82111561319e5761319e61308f565b50601f01601f191660200190565b600082601f8301126131bd57600080fd5b81356131d06131cb82613184565b613153565b8181528460208386010111156131e557600080fd5b816020850160208301376000918101602001919091529392505050565b6000806040838503121561321557600080fd5b823567ffffffffffffffff81111561322c57600080fd5b613238858286016131ac565b925050602083013561300981612fbb565b63ffffffff8116811461108057600080fd5b80356118cc81613249565b801515811461108057600080fd5b80356118cc81613266565b6000610120828403121561329257600080fd5b61329a6130be565b90506132a58261325b565b81526132b360208301612fd0565b60208201526132c460408301612fd0565b60408201526132d560608301612fd0565b60608201526132e660808301612fd0565b608082015260a082013560a082015260c082013560c082015261330b60e08301613274565b60e082015261010080830135818301525092915050565b6000610120828403121561333557600080fd5b611376838361327f565b60006020828403121561335157600080fd5b813567ffffffffffffffff81111561336857600080fd5b613374848285016131ac565b949350505050565b60005b8381101561339757818101518382015260200161337f565b50506000910152565b600081518084526133b881602086016020860161337c565b601f01601f19169290920160200192915050565b602081526133e360208201835163ffffffff169052565b600060208301516133fc604084018263ffffffff169052565b5060408301516001600160a01b03811660608401525060608301516001600160a01b03811660808401525060808301516001600160a01b03811660a08401525060a08301516001600160a01b03811660c08401525060c083015160e08381019190915283015161010080840191909152830151610120808401919091528301516101408084019190915283015161016080840191909152830151610180808401919091528301516101a06134ba818501836001600160a01b03169052565b8401516101c0848101919091528401516101e08085015290506133746102008401826133a0565b608081016134ef8287612f72565b64ffffffffff8516602083015265ffffffffffff841660408301526001600160a01b038316606083015295945050505050565b6000806040838503121561353557600080fd5b823567ffffffffffffffff81111561354c57600080fd5b613558858286016131ac565b95602094909401359450505050565b6000806040838503121561357a57600080fd5b50508035926020909101359150565b815163ffffffff168152610180810160208301516135af602084018263ffffffff169052565b5060408301516135ca60408401826001600160a01b03169052565b5060608301516135e560608401826001600160a01b03169052565b50608083015161360060808401826001600160a01b03169052565b5060a083015161361b60a08401826001600160a01b03169052565b5060c083015160c083015260e083015160e0830152610100808401518184015250610120808401516136508285018215159052565b5050610140838101519083015261016092830151929091019190915290565b600080610140838503121561368357600080fd5b61368d848461327f565b915061012083013567ffffffffffffffff808211156136ab57600080fd5b9084019060a082870312156136bf57600080fd5b6136c76130e8565b82356136d281612fbb565b8152602083810135908201526040830135828111156136f057600080fd5b6136fc888286016131ac565b6040830152506060830135606082015260808301358281111561371e57600080fd5b61372a888286016131ac565b6080830152508093505050509250929050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b80820180821115610aff57610aff61373d565b80516118cc81613249565b80516118cc81612fbb565b600082601f8301126137a657600080fd5b81516137b46131cb82613184565b8181528460208386010111156137c957600080fd5b61337482602083016020870161337c565b6000602082840312156137ec57600080fd5b815167ffffffffffffffff8082111561380457600080fd5b908301906101e0828603121561381957600080fd5b61382161310b565b61382a8361377f565b81526138386020840161377f565b60208201526138496040840161378a565b604082015261385a6060840161378a565b606082015261386b6080840161378a565b608082015261387c60a0840161378a565b60a082015260c0838101519082015260e0808401519082015261010080840151908201526101208084015190820152610140808401519082015261016080840151908201526101806138cf81850161378a565b908201526101a083810151908201526101c080840151838111156138f257600080fd5b6138fe88828701613795565b918301919091525095945050505050565b60208152600061137660208301846133a0565b80516118cc81613266565b6000610180828403121561394057600080fd5b61394861312f565b6139518361377f565b815261395f6020840161377f565b60208201526139706040840161378a565b60408201526139816060840161378a565b60608201526139926080840161378a565b60808201526139a360a0840161378a565b60a082015260c083015160c082015260e083015160e08201526101008084015181830152506101206139d6818501613922565b908201526101408381015190820152610160928301519281019290925250919050565b8082018281126000831280158216821582161715613a1957613a1961373d565b505092915050565b8082028115828204841417610aff57610aff61373d565b600082613a6e577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b81810381811115610aff57610aff61373d565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203613ab757613ab761373d565b5060010190565b60e081526000613ad160e083018a6133a0565b63ffffffff989098166020830152506001600160a01b039586166040820152939094166060840152608083019190915260a082015290151560c090910152919050565b6001600160a01b0384168152826020820152606060408201526000613b3c60608301846133a0565b95945050505050565b80516020808301519190811015613b84577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8160200360031b1b821691505b50919050565b600060208284031215613b9c57600080fd5b5051919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b600060208284031215613be457600080fd5b815161137681613266565b60008251613c0181846020870161337c565b9190910192915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fdfea2646970667358221220a3680a17873f4c46b682e496f075c28aef799dbfefc67679607c7ecbffed72b464736f6c63430008180033", } // FastBridgeV2ABI is the input ABI used to generate the binding from. @@ -14352,7 +14352,7 @@ func (_IFastBridgeV2Errors *IFastBridgeV2ErrorsTransactorRaw) Transact(opts *bin // SafeERC20MetaData contains all meta data concerning the SafeERC20 contract. var SafeERC20MetaData = &bind.MetaData{ ABI: "[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"currentAllowance\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"requestedDecrease\",\"type\":\"uint256\"}],\"name\":\"SafeERC20FailedDecreaseAllowance\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"}],\"name\":\"SafeERC20FailedOperation\",\"type\":\"error\"}]", - Bin: "0x60556032600b8282823980515f1a607314602657634e487b7160e01b5f525f60045260245ffd5b305f52607381538281f3fe730000000000000000000000000000000000000000301460806040525f80fdfea26469706673582212206104d055d945cd85c5e0a242eb38679d97b94eed1093fc3540437ea8fe4ace7364736f6c63430008180033", + Bin: "0x60566037600b82828239805160001a607314602a57634e487b7160e01b600052600060045260246000fd5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600080fdfea26469706673582212202e6244574a9418b179bbe1f5d6f1483cf0da887e64158bb04463fae84495de4464736f6c63430008180033", } // SafeERC20ABI is the input ABI used to generate the binding from. @@ -14525,7 +14525,7 @@ func (_SafeERC20 *SafeERC20TransactorRaw) Transact(opts *bind.TransactOpts, meth // UniversalTokenLibMetaData contains all meta data concerning the UniversalTokenLib contract. var UniversalTokenLibMetaData = &bind.MetaData{ ABI: "[]", - Bin: "0x60556032600b8282823980515f1a607314602657634e487b7160e01b5f525f60045260245ffd5b305f52607381538281f3fe730000000000000000000000000000000000000000301460806040525f80fdfea2646970667358221220b863ead2f0a667d62ff1983d9a28f2cdc6740a5303e83e27e29c037676ea45c264736f6c63430008180033", + Bin: "0x60566037600b82828239805160001a607314602a57634e487b7160e01b600052600060045260246000fd5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600080fdfea2646970667358221220f32c0660d6e44933a56619135234122fa7c42eeae2b3df059ed3d1e4d3c16aa264736f6c63430008180033", } // UniversalTokenLibABI is the input ABI used to generate the binding from. diff --git a/services/rfq/contracts/fastbridgev2/fastbridgev2.contractinfo.json b/services/rfq/contracts/fastbridgev2/fastbridgev2.contractinfo.json index 1cf3c2b242..f7b2869bb1 100644 --- a/services/rfq/contracts/fastbridgev2/fastbridgev2.contractinfo.json +++ b/services/rfq/contracts/fastbridgev2/fastbridgev2.contractinfo.json @@ -1 +1 @@ -{"solidity/FastBridgeV2.sol:AccessControl":{"code":"0x","runtime-code":"0x","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.24 ^0.8.0 ^0.8.20;\n\n// contracts/interfaces/IAdmin.sol\n\ninterface IAdmin {\n // ============ Events ============\n\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n event ChainGasAmountUpdated(uint256 oldChainGasAmount, uint256 newChainGasAmount);\n\n // ============ Methods ============\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n\n function setChainGasAmount(uint256 newChainGasAmount) external;\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IFastBridgeRecipient.sol\n\ninterface IFastBridgeRecipient {\n function fastBridgeTransferReceived(\n address token,\n uint256 amount,\n bytes memory callParams\n )\n external\n payable\n returns (bytes4);\n}\n\n// contracts/interfaces/IFastBridgeV2Errors.sol\n\ninterface IFastBridgeV2Errors {\n error AmountIncorrect();\n error CallParamsLengthAboveMax();\n error ChainIncorrect();\n error ExclusivityParamsIncorrect();\n error MsgValueIncorrect();\n error NativeTokenCallValueNotSupported();\n error SenderIncorrect();\n error StatusIncorrect();\n error ZeroAddress();\n\n error RecipientIncorrectReturnValue();\n error RecipientNoReturnValue();\n\n error DeadlineExceeded();\n error DeadlineNotExceeded();\n error DeadlineTooShort();\n error DisputePeriodNotPassed();\n error DisputePeriodPassed();\n error ExclusivityPeriodNotPassed();\n\n error TransactionRelayed();\n}\n\n// contracts/libs/Errors.sol\n\nerror DeadlineExceeded();\nerror DeadlineNotExceeded();\nerror DeadlineTooShort();\nerror InsufficientOutputAmount();\n\nerror MsgValueIncorrect();\nerror PoolNotFound();\nerror TokenAddressMismatch();\nerror TokenNotContract();\nerror TokenNotETH();\nerror TokensIdentical();\n\nerror ChainIncorrect();\nerror AmountIncorrect();\nerror ZeroAddress();\n\nerror DisputePeriodNotPassed();\nerror DisputePeriodPassed();\nerror SenderIncorrect();\nerror StatusIncorrect();\nerror TransactionIdIncorrect();\nerror TransactionRelayed();\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// contracts/interfaces/IFastBridgeV2.sol\n\ninterface IFastBridgeV2 is IFastBridge {\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n struct BridgeTxDetails {\n BridgeStatus status;\n uint40 proofBlockTimestamp;\n uint48 proofBlockNumber;\n address proofRelayer;\n }\n\n struct BridgeRelay {\n uint48 blockNumber;\n uint48 blockTimestamp;\n address relayer;\n }\n\n /// @notice New params introduced in the FastBridgeV2.\n /// We are passing fields from the older BridgeParams struct outside of this struct\n /// for backwards compatibility.\n /// Note: quoteRelayer and quoteExclusivitySeconds are either both zero (indicating no exclusivity)\n /// or both non-zero (indicating exclusivity for the given period).\n /// Note: callValue \u003e 0 can NOT be used with destToken = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE (ETH_ADDRESS)\n /// @param quoteRelayer Relayer that provided the quote for the transaction\n /// @param quoteExclusivitySeconds Period of time the quote relayer is guaranteed exclusivity after user's deposit\n /// @param quoteId Unique quote identifier used for tracking the quote\n /// @param callValue ETH value to send to the recipient (if any)\n /// @param callParams Parameters for the arbitrary call to the destination recipient (if any)\n struct BridgeParamsV2 {\n address quoteRelayer;\n int256 quoteExclusivitySeconds;\n bytes quoteId;\n uint256 callValue;\n bytes callParams;\n }\n\n /// @notice Updated bridge transaction struct to include parameters introduced in FastBridgeV2.\n /// Note: only `exclusivityRelayer` can fill such a transaction until `exclusivityEndTime`.\n /// TODO: consider changing the encoding scheme to prevent spending extra gas on decoding.\n struct BridgeTransactionV2 {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n uint256 callValue; // ETH value to send to the recipient (if any) - replaces V1's sendChainGas flag\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n address exclusivityRelayer;\n uint256 exclusivityEndTime;\n bytes callParams;\n }\n\n event BridgeQuoteDetails(bytes32 indexed transactionId, bytes quoteId);\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability\n /// to provide temporary exclusivity fill rights for the quote relayer.\n /// @param params The parameters required to bridge\n /// @param paramsV2 The parameters for exclusivity fill rights (optional, can be left empty)\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function relay(bytes memory request, address relayer) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param transactionId The transaction id associated with the encoded bridge transaction to prove\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital.\n /// @notice Can only send funds to the relayer address on the proof.\n /// @param request The encoded bridge transaction to claim on origin chain\n function claim(bytes memory request) external;\n /// @notice Checks if a transaction has been relayed\n /// @param transactionId The ID of the transaction to check\n /// @return True if the transaction has been relayed, false otherwise\n function bridgeRelays(bytes32 transactionId) external view returns (bool);\n\n /// @notice Returns the status of a bridge transaction\n /// @param transactionId The ID of the bridge transaction\n /// @return BridgeStatus Status of the bridge transaction\n function bridgeStatuses(bytes32 transactionId) external view returns (BridgeStatus);\n\n /// @notice Returns the timestamp and relayer of a bridge proof\n /// @param transactionId The ID of the bridge transaction\n /// @return timestamp The timestamp of the bridge proof\n /// @return relayer The relayer address of the bridge proof\n function bridgeProofs(bytes32 transactionId) external view returns (uint96 timestamp, address relayer);\n\n /// @notice Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\n /// @param request The bridge request to decode\n function getBridgeTransactionV2(bytes memory request) external view returns (BridgeTransactionV2 memory);\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// contracts/libs/UniversalToken.sol\n\nlibrary UniversalTokenLib {\n using SafeERC20 for IERC20;\n\n address internal constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Transfers tokens to the given account. Reverts if transfer is not successful.\n /// @dev This might trigger fallback, if ETH is transferred to the contract.\n /// Make sure this can not lead to reentrancy attacks.\n function universalTransfer(address token, address to, uint256 value) internal {\n // Don't do anything, if need to send tokens to this address\n if (to == address(this)) return;\n // Don't do anything, if trying to send zero value\n if (value == 0) return;\n if (token == ETH_ADDRESS) {\n /// @dev Note: this can potentially lead to executing code in `to`.\n // solhint-disable-next-line avoid-low-level-calls\n (bool success,) = to.call{value: value}(\"\");\n require(success, \"ETH transfer failed\");\n } else {\n IERC20(token).safeTransfer(to, value);\n }\n }\n\n /// @notice Issues an infinite allowance to the spender, if the current allowance is insufficient\n /// to spend the given amount.\n function universalApproveInfinity(address token, address spender, uint256 amountToSpend) internal {\n // ETH Chad doesn't require your approval\n if (token == ETH_ADDRESS) return;\n // No-op if allowance is already sufficient\n uint256 allowance = IERC20(token).allowance(address(this), spender);\n if (allowance \u003e= amountToSpend) return;\n // Otherwise, reset approval to 0 and set to max allowance\n if (allowance \u003e 0) IERC20(token).safeDecreaseAllowance(spender, allowance);\n IERC20(token).safeIncreaseAllowance(spender, type(uint256).max);\n }\n\n /// @notice Returns the balance of the given token (or native ETH) for the given account.\n function universalBalanceOf(address token, address account) internal view returns (uint256) {\n if (token == ETH_ADDRESS) {\n return account.balance;\n } else {\n return IERC20(token).balanceOf(account);\n }\n }\n\n /// @dev Checks that token is a contract and not ETH_ADDRESS.\n function assertIsContract(address token) internal view {\n // Check that ETH_ADDRESS was not used (in case this is a predeploy on any of the chains)\n if (token == UniversalTokenLib.ETH_ADDRESS) revert TokenNotContract();\n // Check that token is not an EOA\n if (token.code.length == 0) revert TokenNotContract();\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/Admin.sol\n\ncontract Admin is IAdmin, AccessControlEnumerable {\n using UniversalTokenLib for address;\n\n bytes32 public constant RELAYER_ROLE = keccak256(\"RELAYER_ROLE\");\n bytes32 public constant REFUNDER_ROLE = keccak256(\"REFUNDER_ROLE\");\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n uint256 public constant FEE_BPS = 1e6;\n uint256 public constant FEE_RATE_MAX = 0.01e6; // max 1% on origin amount\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Chain gas amount to forward as rebate if requested\n uint256 public chainGasAmount;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n }\n\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n require(newFeeRate \u003c= FEE_RATE_MAX, \"newFeeRate \u003e max\");\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n token.universalTransfer(recipient, feeAmount);\n emit FeesSwept(token, recipient, feeAmount);\n }\n\n function setChainGasAmount(uint256 newChainGasAmount) external onlyRole(GOVERNOR_ROLE) {\n uint256 oldChainGasAmount = chainGasAmount;\n chainGasAmount = newChainGasAmount;\n emit ChainGasAmountUpdated(oldChainGasAmount, newChainGasAmount);\n }\n}\n\n// contracts/FastBridgeV2.sol\n\n/// @notice FastBridgeV2 is a contract for bridging tokens across chains.\ncontract FastBridgeV2 is Admin, IFastBridgeV2, IFastBridgeV2Errors {\n using SafeERC20 for IERC20;\n using UniversalTokenLib for address;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Delay for a transaction after which it could be permisionlessly refunded\n uint256 public constant REFUND_DELAY = 7 days;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n /// @notice Maximum length of accepted callParams\n uint256 public constant MAX_CALL_PARAMS_LENGTH = 2 ** 16 - 1;\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeTxDetails) public bridgeTxDetails;\n /// @notice Relay details on destination chain\n mapping(bytes32 =\u003e BridgeRelay) public bridgeRelayDetails;\n /// @notice Unique bridge nonces tracked per originSender\n mapping(address =\u003e uint256) public senderNonces;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Replaced by senderNonces\n uint256 public immutable nonce = 0;\n /// @notice the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n bridge({\n params: params,\n paramsV2: BridgeParamsV2({\n quoteRelayer: address(0),\n quoteExclusivitySeconds: 0,\n quoteId: bytes(\"\"),\n callValue: 0,\n callParams: bytes(\"\")\n })\n });\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes memory request) external payable {\n relay({request: request, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes memory request, bytes32 destTxHash) external {\n prove({transactionId: keccak256(request), destTxHash: destTxHash, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridgeV2\n function claim(bytes memory request) external {\n claim({request: request, to: address(0)});\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003e DISPUTE_PERIOD) {\n revert DisputePeriodPassed();\n }\n\n // @dev relayer gets slashed effectively if dest relay has gone thru\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n bridgeTxDetails[transactionId].proofRelayer = address(0);\n bridgeTxDetails[transactionId].proofBlockTimestamp = 0;\n bridgeTxDetails[transactionId].proofBlockNumber = 0;\n\n emit BridgeProofDisputed(transactionId, msg.sender);\n }\n\n /// @inheritdoc IFastBridge\n function refund(bytes memory request) external {\n bytes32 transactionId = keccak256(request);\n\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n\n if (bridgeTxDetails[transactionId].status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n\n if (hasRole(REFUNDER_ROLE, msg.sender)) {\n // Refunder can refund if deadline has passed\n if (block.timestamp \u003c= transaction.deadline) revert DeadlineNotExceeded();\n } else {\n // Permissionless refund is allowed after REFUND_DELAY\n if (block.timestamp \u003c= transaction.deadline + REFUND_DELAY) revert DeadlineNotExceeded();\n }\n\n // if all checks passed, set to REFUNDED status\n bridgeTxDetails[transactionId].status = BridgeStatus.REFUNDED;\n\n // transfer origin collateral back to original sender\n address to = transaction.originSender;\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount + transaction.originFeeAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (bridgeTxDetails[transactionId].proofRelayer != relayer) revert SenderIncorrect();\n return _timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n /// @dev This method is added to achieve backwards compatibility with decoding requests into V1 structs:\n /// - `callValue` is partially reported as a zero/non-zero flag\n /// - `callParams` is ignored\n /// In order to process all kinds of requests use getBridgeTransactionV2 instead.\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory) {\n // Try decoding into V2 struct first. This will revert if V1 struct is passed\n try this.getBridgeTransactionV2(request) returns (BridgeTransactionV2 memory txV2) {\n // Note: we entirely ignore the callParams field, as it was not present in V1\n return BridgeTransaction({\n originChainId: txV2.originChainId,\n destChainId: txV2.destChainId,\n originSender: txV2.originSender,\n destRecipient: txV2.destRecipient,\n originToken: txV2.originToken,\n destToken: txV2.destToken,\n originAmount: txV2.originAmount,\n destAmount: txV2.destAmount,\n originFeeAmount: txV2.originFeeAmount,\n sendChainGas: txV2.callValue != 0,\n deadline: txV2.deadline,\n nonce: txV2.nonce\n });\n } catch {\n // Fallback to V1 struct\n return abi.decode(request, (BridgeTransaction));\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) public payable {\n int256 exclusivityEndTime = int256(block.timestamp) + paramsV2.quoteExclusivitySeconds;\n _validateBridgeParams(params, paramsV2, exclusivityEndTime);\n\n // transfer tokens to bridge contract\n /// @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _pullToken(params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n\n // set status to requested\n bytes memory request = abi.encode(\n BridgeTransactionV2({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n callValue: paramsV2.callValue,\n deadline: params.deadline,\n nonce: senderNonces[params.sender]++, // increment nonce on every bridge\n exclusivityRelayer: paramsV2.quoteRelayer,\n // We checked exclusivityEndTime to be in range (0 .. params.deadline] above, so can safely cast\n exclusivityEndTime: uint256(exclusivityEndTime),\n callParams: paramsV2.callParams\n })\n );\n bytes32 transactionId = keccak256(request);\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n\n emit BridgeRequested({\n transactionId: transactionId,\n sender: params.sender,\n request: request,\n destChainId: params.dstChainId,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n sendChainGas: paramsV2.callValue != 0\n });\n emit BridgeQuoteDetails(transactionId, paramsV2.quoteId);\n }\n\n /// @inheritdoc IFastBridgeV2\n function relay(bytes memory request, address relayer) public payable {\n bytes32 transactionId = keccak256(request);\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n _validateRelayParams(transaction, transactionId, relayer);\n // mark bridge transaction as relayed\n bridgeRelayDetails[transactionId] =\n BridgeRelay({blockNumber: uint48(block.number), blockTimestamp: uint48(block.timestamp), relayer: relayer});\n\n // transfer tokens to recipient on destination chain and do an arbitrary call if requested\n address to = transaction.destRecipient;\n address token = transaction.destToken;\n uint256 amount = transaction.destAmount;\n\n // All state changes have been done at this point, can proceed to the external calls.\n // This follows the checks-effects-interactions pattern to mitigate potential reentrancy attacks.\n if (token == UniversalTokenLib.ETH_ADDRESS) {\n // For ETH non-zero callValue is not allowed\n if (transaction.callValue != 0) revert NativeTokenCallValueNotSupported();\n // Check that the correct msg.value was sent\n if (msg.value != amount) revert MsgValueIncorrect();\n } else {\n // For ERC20s, we check that the correct msg.value was sent\n if (msg.value != transaction.callValue) revert MsgValueIncorrect();\n // We need to transfer the tokens from the Relayer to the recipient first before performing an\n // optional post-transfer arbitrary call.\n IERC20(token).safeTransferFrom(msg.sender, to, amount);\n }\n\n if (transaction.callParams.length != 0) {\n // Arbitrary call requested, perform it while supplying full msg.value to the recipient\n // Note: if token has a fee on transfers, the recipient will have received less than `amount`.\n // This is a very niche edge case and should be handled by the recipient contract.\n _checkedCallRecipient({recipient: to, token: token, amount: amount, callParams: transaction.callParams});\n } else if (msg.value != 0) {\n // No arbitrary call requested, but msg.value was sent. This is either a relay with ETH,\n // or a non-zero callValue request with an ERC20. In both cases, transfer the ETH to the recipient.\n Address.sendValue(payable(to), msg.value);\n }\n\n emit BridgeRelayed({\n transactionId: transactionId,\n relayer: relayer,\n to: to,\n originChainId: transaction.originChainId,\n originToken: transaction.originToken,\n destToken: transaction.destToken,\n originAmount: transaction.originAmount,\n destAmount: transaction.destAmount,\n chainGasAmount: transaction.callValue\n });\n }\n\n /// @inheritdoc IFastBridgeV2\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) public onlyRole(RELAYER_ROLE) {\n // update bridge tx status given proof provided\n if (bridgeTxDetails[transactionId].status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n bridgeTxDetails[transactionId].status = BridgeStatus.RELAYER_PROVED;\n bridgeTxDetails[transactionId].proofBlockTimestamp = uint40(block.timestamp);\n bridgeTxDetails[transactionId].proofBlockNumber = uint48(block.number);\n bridgeTxDetails[transactionId].proofRelayer = relayer;\n\n emit BridgeProofProvided(transactionId, relayer, destTxHash);\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes memory request, address to) public {\n bytes32 transactionId = keccak256(request);\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n\n // update bridge tx status if able to claim origin collateral\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n\n // if \"to\" is zero addr, permissionlessly send funds to proven relayer\n if (to == address(0)) {\n to = bridgeTxDetails[transactionId].proofRelayer;\n } else if (bridgeTxDetails[transactionId].proofRelayer != msg.sender) {\n revert SenderIncorrect();\n }\n\n if (_timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003c= DISPUTE_PERIOD) {\n revert DisputePeriodNotPassed();\n }\n\n bridgeTxDetails[transactionId].status = BridgeStatus.RELAYER_CLAIMED;\n\n // update protocol fees if origin fee amount exists\n if (transaction.originFeeAmount \u003e 0) protocolFees[transaction.originToken] += transaction.originFeeAmount;\n\n // transfer origin collateral less fee to specified address\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositClaimed(transactionId, bridgeTxDetails[transactionId].proofRelayer, to, token, amount);\n }\n\n function bridgeStatuses(bytes32 transactionId) public view returns (BridgeStatus status) {\n return bridgeTxDetails[transactionId].status;\n }\n\n function bridgeProofs(bytes32 transactionId) public view returns (uint96 timestamp, address relayer) {\n timestamp = bridgeTxDetails[transactionId].proofBlockTimestamp;\n relayer = bridgeTxDetails[transactionId].proofRelayer;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeRelays(bytes32 transactionId) public view returns (bool) {\n // has this transactionId been relayed?\n return bridgeRelayDetails[transactionId].relayer != address(0);\n }\n\n /// @inheritdoc IFastBridgeV2\n function getBridgeTransactionV2(bytes memory request) public pure returns (BridgeTransactionV2 memory) {\n return abi.decode(request, (BridgeTransactionV2));\n }\n\n /// @notice Pulls a requested token from the user to this contract.\n function _pullToken(address token, uint256 amount) internal returns (uint256 amountPulled) {\n if (token == UniversalTokenLib.ETH_ADDRESS) {\n // For ETH we just need to check that the supplied msg.value is correct\n if (amount != msg.value) revert MsgValueIncorrect();\n amountPulled = msg.value;\n } else {\n token.assertIsContract();\n // Record token balance before transfer\n amountPulled = IERC20(token).balanceOf(address(this));\n // Token needs to be pulled only if msg.value is zero\n // This way user can specify WETH as the origin asset\n IERC20(token).safeTransferFrom(msg.sender, address(this), amount);\n // Use the difference between the recorded balance and the current balance as the amountPulled\n amountPulled = IERC20(token).balanceOf(address(this)) - amountPulled;\n }\n }\n\n /// @notice Calls the Recipient's hook function with the specified callParams and performs\n /// all the necessary checks for the returned value.\n function _checkedCallRecipient(\n address recipient,\n address token,\n uint256 amount,\n bytes memory callParams\n )\n internal\n {\n bytes memory hookData =\n abi.encodeCall(IFastBridgeRecipient.fastBridgeTransferReceived, (token, amount, callParams));\n // This will bubble any revert messages from the hook function\n bytes memory returnData = Address.functionCallWithValue({target: recipient, data: hookData, value: msg.value});\n // Explicit revert if no return data at all\n if (returnData.length == 0) revert RecipientNoReturnValue();\n // Check that exactly a single return value was returned\n if (returnData.length != 32) revert RecipientIncorrectReturnValue();\n // Return value should be abi-encoded hook function selector\n if (bytes32(returnData) != bytes32(IFastBridgeRecipient.fastBridgeTransferReceived.selector)) {\n revert RecipientIncorrectReturnValue();\n }\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint40(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint40).max but\n /// proof.timestamp \u003c type(uint40).max via unchecked statement\n /// @param proofBlockTimestamp The bridge proof block timestamp\n /// @return delta Time delta since proof submitted\n function _timeSince(uint40 proofBlockTimestamp) internal view returns (uint256 delta) {\n unchecked {\n delta = uint40(block.timestamp) - proofBlockTimestamp;\n }\n }\n\n /// @notice Performs all the necessary checks for a bridge to happen.\n /// @dev There's no good way to refactor this function to reduce cyclomatic complexity due to\n /// the number of checks that need to be performed, so we skip the code-complexity rule here.\n // solhint-disable-next-line code-complexity\n function _validateBridgeParams(\n BridgeParams memory params,\n BridgeParamsV2 memory paramsV2,\n int256 exclusivityEndTime\n )\n internal\n view\n {\n // Check V1 (legacy) params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.sender == address(0) || params.to == address(0)) revert ZeroAddress();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n // Check V2 params\n if (paramsV2.callParams.length \u003e MAX_CALL_PARAMS_LENGTH) revert CallParamsLengthAboveMax();\n if (paramsV2.callValue != 0 \u0026\u0026 params.destToken == UniversalTokenLib.ETH_ADDRESS) {\n revert NativeTokenCallValueNotSupported();\n }\n // exclusivityEndTime must be in range (0 .. params.deadline]\n if (exclusivityEndTime \u003c= 0 || exclusivityEndTime \u003e int256(params.deadline)) {\n revert ExclusivityParamsIncorrect();\n }\n }\n\n /// @notice Performs all the necessary checks for a relay to happen.\n function _validateRelayParams(\n BridgeTransactionV2 memory transaction,\n bytes32 transactionId,\n address relayer\n )\n internal\n view\n {\n if (relayer == address(0)) revert ZeroAddress();\n // Check if the transaction has already been relayed\n if (bridgeRelays(transactionId)) revert TransactionRelayed();\n if (transaction.destChainId != uint32(block.chainid)) revert ChainIncorrect();\n // Check the deadline for relay to happen\n if (block.timestamp \u003e transaction.deadline) revert DeadlineExceeded();\n // Check the exclusivity period, if it is still ongoing\n // forgefmt: disable-next-item\n if (\n transaction.exclusivityRelayer != address(0) \u0026\u0026\n transaction.exclusivityRelayer != relayer \u0026\u0026\n block.timestamp \u003c= transaction.exclusivityEndTime\n ) {\n revert ExclusivityPeriodNotPassed();\n }\n }\n}\n","language":"Solidity","languageVersion":"0.8.24","compilerVersion":"0.8.24","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../","srcMap":"","srcMapRuntime":"","abiDefinition":[{"inputs":[],"name":"AccessControlBadConfirmation","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"bytes32","name":"neededRole","type":"bytes32"}],"name":"AccessControlUnauthorizedAccount","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"previousAdminRole","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"newAdminRole","type":"bytes32"}],"name":"RoleAdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleRevoked","type":"event"},{"inputs":[],"name":"DEFAULT_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleAdmin","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"grantRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"hasRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"callerConfirmation","type":"address"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"revokeRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"}],"userDoc":{"kind":"user","methods":{},"version":1},"developerDoc":{"details":"Contract module that allows children to implement role-based access control mechanisms. This is a lightweight version that doesn't allow enumerating role members except through off-chain means by accessing the contract event logs. Some applications may benefit from on-chain enumerability, for those cases see {AccessControlEnumerable}. Roles are referred to by their `bytes32` identifier. These should be exposed in the external API and be unique. The best way to achieve this is by using `public constant` hash digests: ```solidity bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\"); ``` Roles can be used to represent a set of permissions. To restrict access to a function call, use {hasRole}: ```solidity function foo() public { require(hasRole(MY_ROLE, msg.sender)); ... } ``` Roles can be granted and revoked dynamically via the {grantRole} and {revokeRole} functions. Each role has an associated admin role, and only accounts that have a role's admin role can call {grantRole} and {revokeRole}. By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means that only accounts with this role will be able to grant or revoke other roles. More complex role relationships can be created by using {_setRoleAdmin}. WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to grant and revoke this role. Extra precautions should be taken to secure accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules} to enforce additional security measures for this role.","errors":{"AccessControlBadConfirmation()":[{"details":"The caller of a function is not the expected one. NOTE: Don't confuse with {AccessControlUnauthorizedAccount}."}],"AccessControlUnauthorizedAccount(address,bytes32)":[{"details":"The `account` is missing a role."}]},"events":{"RoleAdminChanged(bytes32,bytes32,bytes32)":{"details":"Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole` `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite {RoleAdminChanged} not being emitted signaling this."},"RoleGranted(bytes32,address,address)":{"details":"Emitted when `account` is granted `role`. `sender` is the account that originated the contract call, an admin role bearer except when using {AccessControl-_setupRole}."},"RoleRevoked(bytes32,address,address)":{"details":"Emitted when `account` is revoked `role`. `sender` is the account that originated the contract call: - if using `revokeRole`, it is the admin role bearer - if using `renounceRole`, it is the role bearer (i.e. `account`)"}},"kind":"dev","methods":{"getRoleAdmin(bytes32)":{"details":"Returns the admin role that controls `role`. See {grantRole} and {revokeRole}. To change a role's admin, use {_setRoleAdmin}."},"grantRole(bytes32,address)":{"details":"Grants `role` to `account`. If `account` had not been already granted `role`, emits a {RoleGranted} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleGranted} event."},"hasRole(bytes32,address)":{"details":"Returns `true` if `account` has been granted `role`."},"renounceRole(bytes32,address)":{"details":"Revokes `role` from the calling account. Roles are often managed via {grantRole} and {revokeRole}: this function's purpose is to provide a mechanism for accounts to lose their privileges if they are compromised (such as when a trusted device is misplaced). If the calling account had been revoked `role`, emits a {RoleRevoked} event. Requirements: - the caller must be `callerConfirmation`. May emit a {RoleRevoked} event."},"revokeRole(bytes32,address)":{"details":"Revokes `role` from `account`. If `account` had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleRevoked} event."},"supportsInterface(bytes4)":{"details":"See {IERC165-supportsInterface}."}},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[],\"name\":\"AccessControlBadConfirmation\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"neededRole\",\"type\":\"bytes32\"}],\"name\":\"AccessControlUnauthorizedAccount\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"previousAdminRole\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"newAdminRole\",\"type\":\"bytes32\"}],\"name\":\"RoleAdminChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleGranted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleRevoked\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"DEFAULT_ADMIN_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"}],\"name\":\"getRoleAdmin\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"grantRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"hasRole\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"callerConfirmation\",\"type\":\"address\"}],\"name\":\"renounceRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"revokeRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes4\",\"name\":\"interfaceId\",\"type\":\"bytes4\"}],\"name\":\"supportsInterface\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"}],\"devdoc\":{\"details\":\"Contract module that allows children to implement role-based access control mechanisms. This is a lightweight version that doesn't allow enumerating role members except through off-chain means by accessing the contract event logs. Some applications may benefit from on-chain enumerability, for those cases see {AccessControlEnumerable}. Roles are referred to by their `bytes32` identifier. These should be exposed in the external API and be unique. The best way to achieve this is by using `public constant` hash digests: ```solidity bytes32 public constant MY_ROLE = keccak256(\\\"MY_ROLE\\\"); ``` Roles can be used to represent a set of permissions. To restrict access to a function call, use {hasRole}: ```solidity function foo() public { require(hasRole(MY_ROLE, msg.sender)); ... } ``` Roles can be granted and revoked dynamically via the {grantRole} and {revokeRole} functions. Each role has an associated admin role, and only accounts that have a role's admin role can call {grantRole} and {revokeRole}. By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means that only accounts with this role will be able to grant or revoke other roles. More complex role relationships can be created by using {_setRoleAdmin}. WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to grant and revoke this role. Extra precautions should be taken to secure accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules} to enforce additional security measures for this role.\",\"errors\":{\"AccessControlBadConfirmation()\":[{\"details\":\"The caller of a function is not the expected one. NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\"}],\"AccessControlUnauthorizedAccount(address,bytes32)\":[{\"details\":\"The `account` is missing a role.\"}]},\"events\":{\"RoleAdminChanged(bytes32,bytes32,bytes32)\":{\"details\":\"Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole` `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite {RoleAdminChanged} not being emitted signaling this.\"},\"RoleGranted(bytes32,address,address)\":{\"details\":\"Emitted when `account` is granted `role`. `sender` is the account that originated the contract call, an admin role bearer except when using {AccessControl-_setupRole}.\"},\"RoleRevoked(bytes32,address,address)\":{\"details\":\"Emitted when `account` is revoked `role`. `sender` is the account that originated the contract call: - if using `revokeRole`, it is the admin role bearer - if using `renounceRole`, it is the role bearer (i.e. `account`)\"}},\"kind\":\"dev\",\"methods\":{\"getRoleAdmin(bytes32)\":{\"details\":\"Returns the admin role that controls `role`. See {grantRole} and {revokeRole}. To change a role's admin, use {_setRoleAdmin}.\"},\"grantRole(bytes32,address)\":{\"details\":\"Grants `role` to `account`. If `account` had not been already granted `role`, emits a {RoleGranted} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleGranted} event.\"},\"hasRole(bytes32,address)\":{\"details\":\"Returns `true` if `account` has been granted `role`.\"},\"renounceRole(bytes32,address)\":{\"details\":\"Revokes `role` from the calling account. Roles are often managed via {grantRole} and {revokeRole}: this function's purpose is to provide a mechanism for accounts to lose their privileges if they are compromised (such as when a trusted device is misplaced). If the calling account had been revoked `role`, emits a {RoleRevoked} event. Requirements: - the caller must be `callerConfirmation`. May emit a {RoleRevoked} event.\"},\"revokeRole(bytes32,address)\":{\"details\":\"Revokes `role` from `account`. If `account` had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleRevoked} event.\"},\"supportsInterface(bytes4)\":{\"details\":\"See {IERC165-supportsInterface}.\"}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeV2.sol\":\"AccessControl\"},\"evmVersion\":\"shanghai\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeV2.sol\":{\"keccak256\":\"0x7cd0f885e80e2bdaa638bc32ae7af7d2e248f99ce4b354c217d0f0f7d7302e0a\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://7ccf28df0bd7b4606986585acd8622ed9b4e81379690061bb66088f0a2270af1\",\"dweb:/ipfs/QmTf7HNdHZkK6vmx8ZgewycQEb72oLD9nPwBpsM5reMstQ\"]}},\"version\":1}"},"hashes":{"DEFAULT_ADMIN_ROLE()":"a217fddf","getRoleAdmin(bytes32)":"248a9ca3","grantRole(bytes32,address)":"2f2ff15d","hasRole(bytes32,address)":"91d14854","renounceRole(bytes32,address)":"36568abe","revokeRole(bytes32,address)":"d547741f","supportsInterface(bytes4)":"01ffc9a7"}},"solidity/FastBridgeV2.sol:AccessControlEnumerable":{"code":"0x","runtime-code":"0x","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.24 ^0.8.0 ^0.8.20;\n\n// contracts/interfaces/IAdmin.sol\n\ninterface IAdmin {\n // ============ Events ============\n\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n event ChainGasAmountUpdated(uint256 oldChainGasAmount, uint256 newChainGasAmount);\n\n // ============ Methods ============\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n\n function setChainGasAmount(uint256 newChainGasAmount) external;\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IFastBridgeRecipient.sol\n\ninterface IFastBridgeRecipient {\n function fastBridgeTransferReceived(\n address token,\n uint256 amount,\n bytes memory callParams\n )\n external\n payable\n returns (bytes4);\n}\n\n// contracts/interfaces/IFastBridgeV2Errors.sol\n\ninterface IFastBridgeV2Errors {\n error AmountIncorrect();\n error CallParamsLengthAboveMax();\n error ChainIncorrect();\n error ExclusivityParamsIncorrect();\n error MsgValueIncorrect();\n error NativeTokenCallValueNotSupported();\n error SenderIncorrect();\n error StatusIncorrect();\n error ZeroAddress();\n\n error RecipientIncorrectReturnValue();\n error RecipientNoReturnValue();\n\n error DeadlineExceeded();\n error DeadlineNotExceeded();\n error DeadlineTooShort();\n error DisputePeriodNotPassed();\n error DisputePeriodPassed();\n error ExclusivityPeriodNotPassed();\n\n error TransactionRelayed();\n}\n\n// contracts/libs/Errors.sol\n\nerror DeadlineExceeded();\nerror DeadlineNotExceeded();\nerror DeadlineTooShort();\nerror InsufficientOutputAmount();\n\nerror MsgValueIncorrect();\nerror PoolNotFound();\nerror TokenAddressMismatch();\nerror TokenNotContract();\nerror TokenNotETH();\nerror TokensIdentical();\n\nerror ChainIncorrect();\nerror AmountIncorrect();\nerror ZeroAddress();\n\nerror DisputePeriodNotPassed();\nerror DisputePeriodPassed();\nerror SenderIncorrect();\nerror StatusIncorrect();\nerror TransactionIdIncorrect();\nerror TransactionRelayed();\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// contracts/interfaces/IFastBridgeV2.sol\n\ninterface IFastBridgeV2 is IFastBridge {\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n struct BridgeTxDetails {\n BridgeStatus status;\n uint40 proofBlockTimestamp;\n uint48 proofBlockNumber;\n address proofRelayer;\n }\n\n struct BridgeRelay {\n uint48 blockNumber;\n uint48 blockTimestamp;\n address relayer;\n }\n\n /// @notice New params introduced in the FastBridgeV2.\n /// We are passing fields from the older BridgeParams struct outside of this struct\n /// for backwards compatibility.\n /// Note: quoteRelayer and quoteExclusivitySeconds are either both zero (indicating no exclusivity)\n /// or both non-zero (indicating exclusivity for the given period).\n /// Note: callValue \u003e 0 can NOT be used with destToken = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE (ETH_ADDRESS)\n /// @param quoteRelayer Relayer that provided the quote for the transaction\n /// @param quoteExclusivitySeconds Period of time the quote relayer is guaranteed exclusivity after user's deposit\n /// @param quoteId Unique quote identifier used for tracking the quote\n /// @param callValue ETH value to send to the recipient (if any)\n /// @param callParams Parameters for the arbitrary call to the destination recipient (if any)\n struct BridgeParamsV2 {\n address quoteRelayer;\n int256 quoteExclusivitySeconds;\n bytes quoteId;\n uint256 callValue;\n bytes callParams;\n }\n\n /// @notice Updated bridge transaction struct to include parameters introduced in FastBridgeV2.\n /// Note: only `exclusivityRelayer` can fill such a transaction until `exclusivityEndTime`.\n /// TODO: consider changing the encoding scheme to prevent spending extra gas on decoding.\n struct BridgeTransactionV2 {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n uint256 callValue; // ETH value to send to the recipient (if any) - replaces V1's sendChainGas flag\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n address exclusivityRelayer;\n uint256 exclusivityEndTime;\n bytes callParams;\n }\n\n event BridgeQuoteDetails(bytes32 indexed transactionId, bytes quoteId);\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability\n /// to provide temporary exclusivity fill rights for the quote relayer.\n /// @param params The parameters required to bridge\n /// @param paramsV2 The parameters for exclusivity fill rights (optional, can be left empty)\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function relay(bytes memory request, address relayer) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param transactionId The transaction id associated with the encoded bridge transaction to prove\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital.\n /// @notice Can only send funds to the relayer address on the proof.\n /// @param request The encoded bridge transaction to claim on origin chain\n function claim(bytes memory request) external;\n /// @notice Checks if a transaction has been relayed\n /// @param transactionId The ID of the transaction to check\n /// @return True if the transaction has been relayed, false otherwise\n function bridgeRelays(bytes32 transactionId) external view returns (bool);\n\n /// @notice Returns the status of a bridge transaction\n /// @param transactionId The ID of the bridge transaction\n /// @return BridgeStatus Status of the bridge transaction\n function bridgeStatuses(bytes32 transactionId) external view returns (BridgeStatus);\n\n /// @notice Returns the timestamp and relayer of a bridge proof\n /// @param transactionId The ID of the bridge transaction\n /// @return timestamp The timestamp of the bridge proof\n /// @return relayer The relayer address of the bridge proof\n function bridgeProofs(bytes32 transactionId) external view returns (uint96 timestamp, address relayer);\n\n /// @notice Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\n /// @param request The bridge request to decode\n function getBridgeTransactionV2(bytes memory request) external view returns (BridgeTransactionV2 memory);\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// contracts/libs/UniversalToken.sol\n\nlibrary UniversalTokenLib {\n using SafeERC20 for IERC20;\n\n address internal constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Transfers tokens to the given account. Reverts if transfer is not successful.\n /// @dev This might trigger fallback, if ETH is transferred to the contract.\n /// Make sure this can not lead to reentrancy attacks.\n function universalTransfer(address token, address to, uint256 value) internal {\n // Don't do anything, if need to send tokens to this address\n if (to == address(this)) return;\n // Don't do anything, if trying to send zero value\n if (value == 0) return;\n if (token == ETH_ADDRESS) {\n /// @dev Note: this can potentially lead to executing code in `to`.\n // solhint-disable-next-line avoid-low-level-calls\n (bool success,) = to.call{value: value}(\"\");\n require(success, \"ETH transfer failed\");\n } else {\n IERC20(token).safeTransfer(to, value);\n }\n }\n\n /// @notice Issues an infinite allowance to the spender, if the current allowance is insufficient\n /// to spend the given amount.\n function universalApproveInfinity(address token, address spender, uint256 amountToSpend) internal {\n // ETH Chad doesn't require your approval\n if (token == ETH_ADDRESS) return;\n // No-op if allowance is already sufficient\n uint256 allowance = IERC20(token).allowance(address(this), spender);\n if (allowance \u003e= amountToSpend) return;\n // Otherwise, reset approval to 0 and set to max allowance\n if (allowance \u003e 0) IERC20(token).safeDecreaseAllowance(spender, allowance);\n IERC20(token).safeIncreaseAllowance(spender, type(uint256).max);\n }\n\n /// @notice Returns the balance of the given token (or native ETH) for the given account.\n function universalBalanceOf(address token, address account) internal view returns (uint256) {\n if (token == ETH_ADDRESS) {\n return account.balance;\n } else {\n return IERC20(token).balanceOf(account);\n }\n }\n\n /// @dev Checks that token is a contract and not ETH_ADDRESS.\n function assertIsContract(address token) internal view {\n // Check that ETH_ADDRESS was not used (in case this is a predeploy on any of the chains)\n if (token == UniversalTokenLib.ETH_ADDRESS) revert TokenNotContract();\n // Check that token is not an EOA\n if (token.code.length == 0) revert TokenNotContract();\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/Admin.sol\n\ncontract Admin is IAdmin, AccessControlEnumerable {\n using UniversalTokenLib for address;\n\n bytes32 public constant RELAYER_ROLE = keccak256(\"RELAYER_ROLE\");\n bytes32 public constant REFUNDER_ROLE = keccak256(\"REFUNDER_ROLE\");\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n uint256 public constant FEE_BPS = 1e6;\n uint256 public constant FEE_RATE_MAX = 0.01e6; // max 1% on origin amount\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Chain gas amount to forward as rebate if requested\n uint256 public chainGasAmount;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n }\n\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n require(newFeeRate \u003c= FEE_RATE_MAX, \"newFeeRate \u003e max\");\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n token.universalTransfer(recipient, feeAmount);\n emit FeesSwept(token, recipient, feeAmount);\n }\n\n function setChainGasAmount(uint256 newChainGasAmount) external onlyRole(GOVERNOR_ROLE) {\n uint256 oldChainGasAmount = chainGasAmount;\n chainGasAmount = newChainGasAmount;\n emit ChainGasAmountUpdated(oldChainGasAmount, newChainGasAmount);\n }\n}\n\n// contracts/FastBridgeV2.sol\n\n/// @notice FastBridgeV2 is a contract for bridging tokens across chains.\ncontract FastBridgeV2 is Admin, IFastBridgeV2, IFastBridgeV2Errors {\n using SafeERC20 for IERC20;\n using UniversalTokenLib for address;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Delay for a transaction after which it could be permisionlessly refunded\n uint256 public constant REFUND_DELAY = 7 days;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n /// @notice Maximum length of accepted callParams\n uint256 public constant MAX_CALL_PARAMS_LENGTH = 2 ** 16 - 1;\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeTxDetails) public bridgeTxDetails;\n /// @notice Relay details on destination chain\n mapping(bytes32 =\u003e BridgeRelay) public bridgeRelayDetails;\n /// @notice Unique bridge nonces tracked per originSender\n mapping(address =\u003e uint256) public senderNonces;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Replaced by senderNonces\n uint256 public immutable nonce = 0;\n /// @notice the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n bridge({\n params: params,\n paramsV2: BridgeParamsV2({\n quoteRelayer: address(0),\n quoteExclusivitySeconds: 0,\n quoteId: bytes(\"\"),\n callValue: 0,\n callParams: bytes(\"\")\n })\n });\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes memory request) external payable {\n relay({request: request, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes memory request, bytes32 destTxHash) external {\n prove({transactionId: keccak256(request), destTxHash: destTxHash, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridgeV2\n function claim(bytes memory request) external {\n claim({request: request, to: address(0)});\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003e DISPUTE_PERIOD) {\n revert DisputePeriodPassed();\n }\n\n // @dev relayer gets slashed effectively if dest relay has gone thru\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n bridgeTxDetails[transactionId].proofRelayer = address(0);\n bridgeTxDetails[transactionId].proofBlockTimestamp = 0;\n bridgeTxDetails[transactionId].proofBlockNumber = 0;\n\n emit BridgeProofDisputed(transactionId, msg.sender);\n }\n\n /// @inheritdoc IFastBridge\n function refund(bytes memory request) external {\n bytes32 transactionId = keccak256(request);\n\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n\n if (bridgeTxDetails[transactionId].status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n\n if (hasRole(REFUNDER_ROLE, msg.sender)) {\n // Refunder can refund if deadline has passed\n if (block.timestamp \u003c= transaction.deadline) revert DeadlineNotExceeded();\n } else {\n // Permissionless refund is allowed after REFUND_DELAY\n if (block.timestamp \u003c= transaction.deadline + REFUND_DELAY) revert DeadlineNotExceeded();\n }\n\n // if all checks passed, set to REFUNDED status\n bridgeTxDetails[transactionId].status = BridgeStatus.REFUNDED;\n\n // transfer origin collateral back to original sender\n address to = transaction.originSender;\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount + transaction.originFeeAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (bridgeTxDetails[transactionId].proofRelayer != relayer) revert SenderIncorrect();\n return _timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n /// @dev This method is added to achieve backwards compatibility with decoding requests into V1 structs:\n /// - `callValue` is partially reported as a zero/non-zero flag\n /// - `callParams` is ignored\n /// In order to process all kinds of requests use getBridgeTransactionV2 instead.\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory) {\n // Try decoding into V2 struct first. This will revert if V1 struct is passed\n try this.getBridgeTransactionV2(request) returns (BridgeTransactionV2 memory txV2) {\n // Note: we entirely ignore the callParams field, as it was not present in V1\n return BridgeTransaction({\n originChainId: txV2.originChainId,\n destChainId: txV2.destChainId,\n originSender: txV2.originSender,\n destRecipient: txV2.destRecipient,\n originToken: txV2.originToken,\n destToken: txV2.destToken,\n originAmount: txV2.originAmount,\n destAmount: txV2.destAmount,\n originFeeAmount: txV2.originFeeAmount,\n sendChainGas: txV2.callValue != 0,\n deadline: txV2.deadline,\n nonce: txV2.nonce\n });\n } catch {\n // Fallback to V1 struct\n return abi.decode(request, (BridgeTransaction));\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) public payable {\n int256 exclusivityEndTime = int256(block.timestamp) + paramsV2.quoteExclusivitySeconds;\n _validateBridgeParams(params, paramsV2, exclusivityEndTime);\n\n // transfer tokens to bridge contract\n /// @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _pullToken(params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n\n // set status to requested\n bytes memory request = abi.encode(\n BridgeTransactionV2({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n callValue: paramsV2.callValue,\n deadline: params.deadline,\n nonce: senderNonces[params.sender]++, // increment nonce on every bridge\n exclusivityRelayer: paramsV2.quoteRelayer,\n // We checked exclusivityEndTime to be in range (0 .. params.deadline] above, so can safely cast\n exclusivityEndTime: uint256(exclusivityEndTime),\n callParams: paramsV2.callParams\n })\n );\n bytes32 transactionId = keccak256(request);\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n\n emit BridgeRequested({\n transactionId: transactionId,\n sender: params.sender,\n request: request,\n destChainId: params.dstChainId,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n sendChainGas: paramsV2.callValue != 0\n });\n emit BridgeQuoteDetails(transactionId, paramsV2.quoteId);\n }\n\n /// @inheritdoc IFastBridgeV2\n function relay(bytes memory request, address relayer) public payable {\n bytes32 transactionId = keccak256(request);\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n _validateRelayParams(transaction, transactionId, relayer);\n // mark bridge transaction as relayed\n bridgeRelayDetails[transactionId] =\n BridgeRelay({blockNumber: uint48(block.number), blockTimestamp: uint48(block.timestamp), relayer: relayer});\n\n // transfer tokens to recipient on destination chain and do an arbitrary call if requested\n address to = transaction.destRecipient;\n address token = transaction.destToken;\n uint256 amount = transaction.destAmount;\n\n // All state changes have been done at this point, can proceed to the external calls.\n // This follows the checks-effects-interactions pattern to mitigate potential reentrancy attacks.\n if (token == UniversalTokenLib.ETH_ADDRESS) {\n // For ETH non-zero callValue is not allowed\n if (transaction.callValue != 0) revert NativeTokenCallValueNotSupported();\n // Check that the correct msg.value was sent\n if (msg.value != amount) revert MsgValueIncorrect();\n } else {\n // For ERC20s, we check that the correct msg.value was sent\n if (msg.value != transaction.callValue) revert MsgValueIncorrect();\n // We need to transfer the tokens from the Relayer to the recipient first before performing an\n // optional post-transfer arbitrary call.\n IERC20(token).safeTransferFrom(msg.sender, to, amount);\n }\n\n if (transaction.callParams.length != 0) {\n // Arbitrary call requested, perform it while supplying full msg.value to the recipient\n // Note: if token has a fee on transfers, the recipient will have received less than `amount`.\n // This is a very niche edge case and should be handled by the recipient contract.\n _checkedCallRecipient({recipient: to, token: token, amount: amount, callParams: transaction.callParams});\n } else if (msg.value != 0) {\n // No arbitrary call requested, but msg.value was sent. This is either a relay with ETH,\n // or a non-zero callValue request with an ERC20. In both cases, transfer the ETH to the recipient.\n Address.sendValue(payable(to), msg.value);\n }\n\n emit BridgeRelayed({\n transactionId: transactionId,\n relayer: relayer,\n to: to,\n originChainId: transaction.originChainId,\n originToken: transaction.originToken,\n destToken: transaction.destToken,\n originAmount: transaction.originAmount,\n destAmount: transaction.destAmount,\n chainGasAmount: transaction.callValue\n });\n }\n\n /// @inheritdoc IFastBridgeV2\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) public onlyRole(RELAYER_ROLE) {\n // update bridge tx status given proof provided\n if (bridgeTxDetails[transactionId].status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n bridgeTxDetails[transactionId].status = BridgeStatus.RELAYER_PROVED;\n bridgeTxDetails[transactionId].proofBlockTimestamp = uint40(block.timestamp);\n bridgeTxDetails[transactionId].proofBlockNumber = uint48(block.number);\n bridgeTxDetails[transactionId].proofRelayer = relayer;\n\n emit BridgeProofProvided(transactionId, relayer, destTxHash);\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes memory request, address to) public {\n bytes32 transactionId = keccak256(request);\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n\n // update bridge tx status if able to claim origin collateral\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n\n // if \"to\" is zero addr, permissionlessly send funds to proven relayer\n if (to == address(0)) {\n to = bridgeTxDetails[transactionId].proofRelayer;\n } else if (bridgeTxDetails[transactionId].proofRelayer != msg.sender) {\n revert SenderIncorrect();\n }\n\n if (_timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003c= DISPUTE_PERIOD) {\n revert DisputePeriodNotPassed();\n }\n\n bridgeTxDetails[transactionId].status = BridgeStatus.RELAYER_CLAIMED;\n\n // update protocol fees if origin fee amount exists\n if (transaction.originFeeAmount \u003e 0) protocolFees[transaction.originToken] += transaction.originFeeAmount;\n\n // transfer origin collateral less fee to specified address\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositClaimed(transactionId, bridgeTxDetails[transactionId].proofRelayer, to, token, amount);\n }\n\n function bridgeStatuses(bytes32 transactionId) public view returns (BridgeStatus status) {\n return bridgeTxDetails[transactionId].status;\n }\n\n function bridgeProofs(bytes32 transactionId) public view returns (uint96 timestamp, address relayer) {\n timestamp = bridgeTxDetails[transactionId].proofBlockTimestamp;\n relayer = bridgeTxDetails[transactionId].proofRelayer;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeRelays(bytes32 transactionId) public view returns (bool) {\n // has this transactionId been relayed?\n return bridgeRelayDetails[transactionId].relayer != address(0);\n }\n\n /// @inheritdoc IFastBridgeV2\n function getBridgeTransactionV2(bytes memory request) public pure returns (BridgeTransactionV2 memory) {\n return abi.decode(request, (BridgeTransactionV2));\n }\n\n /// @notice Pulls a requested token from the user to this contract.\n function _pullToken(address token, uint256 amount) internal returns (uint256 amountPulled) {\n if (token == UniversalTokenLib.ETH_ADDRESS) {\n // For ETH we just need to check that the supplied msg.value is correct\n if (amount != msg.value) revert MsgValueIncorrect();\n amountPulled = msg.value;\n } else {\n token.assertIsContract();\n // Record token balance before transfer\n amountPulled = IERC20(token).balanceOf(address(this));\n // Token needs to be pulled only if msg.value is zero\n // This way user can specify WETH as the origin asset\n IERC20(token).safeTransferFrom(msg.sender, address(this), amount);\n // Use the difference between the recorded balance and the current balance as the amountPulled\n amountPulled = IERC20(token).balanceOf(address(this)) - amountPulled;\n }\n }\n\n /// @notice Calls the Recipient's hook function with the specified callParams and performs\n /// all the necessary checks for the returned value.\n function _checkedCallRecipient(\n address recipient,\n address token,\n uint256 amount,\n bytes memory callParams\n )\n internal\n {\n bytes memory hookData =\n abi.encodeCall(IFastBridgeRecipient.fastBridgeTransferReceived, (token, amount, callParams));\n // This will bubble any revert messages from the hook function\n bytes memory returnData = Address.functionCallWithValue({target: recipient, data: hookData, value: msg.value});\n // Explicit revert if no return data at all\n if (returnData.length == 0) revert RecipientNoReturnValue();\n // Check that exactly a single return value was returned\n if (returnData.length != 32) revert RecipientIncorrectReturnValue();\n // Return value should be abi-encoded hook function selector\n if (bytes32(returnData) != bytes32(IFastBridgeRecipient.fastBridgeTransferReceived.selector)) {\n revert RecipientIncorrectReturnValue();\n }\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint40(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint40).max but\n /// proof.timestamp \u003c type(uint40).max via unchecked statement\n /// @param proofBlockTimestamp The bridge proof block timestamp\n /// @return delta Time delta since proof submitted\n function _timeSince(uint40 proofBlockTimestamp) internal view returns (uint256 delta) {\n unchecked {\n delta = uint40(block.timestamp) - proofBlockTimestamp;\n }\n }\n\n /// @notice Performs all the necessary checks for a bridge to happen.\n /// @dev There's no good way to refactor this function to reduce cyclomatic complexity due to\n /// the number of checks that need to be performed, so we skip the code-complexity rule here.\n // solhint-disable-next-line code-complexity\n function _validateBridgeParams(\n BridgeParams memory params,\n BridgeParamsV2 memory paramsV2,\n int256 exclusivityEndTime\n )\n internal\n view\n {\n // Check V1 (legacy) params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.sender == address(0) || params.to == address(0)) revert ZeroAddress();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n // Check V2 params\n if (paramsV2.callParams.length \u003e MAX_CALL_PARAMS_LENGTH) revert CallParamsLengthAboveMax();\n if (paramsV2.callValue != 0 \u0026\u0026 params.destToken == UniversalTokenLib.ETH_ADDRESS) {\n revert NativeTokenCallValueNotSupported();\n }\n // exclusivityEndTime must be in range (0 .. params.deadline]\n if (exclusivityEndTime \u003c= 0 || exclusivityEndTime \u003e int256(params.deadline)) {\n revert ExclusivityParamsIncorrect();\n }\n }\n\n /// @notice Performs all the necessary checks for a relay to happen.\n function _validateRelayParams(\n BridgeTransactionV2 memory transaction,\n bytes32 transactionId,\n address relayer\n )\n internal\n view\n {\n if (relayer == address(0)) revert ZeroAddress();\n // Check if the transaction has already been relayed\n if (bridgeRelays(transactionId)) revert TransactionRelayed();\n if (transaction.destChainId != uint32(block.chainid)) revert ChainIncorrect();\n // Check the deadline for relay to happen\n if (block.timestamp \u003e transaction.deadline) revert DeadlineExceeded();\n // Check the exclusivity period, if it is still ongoing\n // forgefmt: disable-next-item\n if (\n transaction.exclusivityRelayer != address(0) \u0026\u0026\n transaction.exclusivityRelayer != relayer \u0026\u0026\n block.timestamp \u003c= transaction.exclusivityEndTime\n ) {\n revert ExclusivityPeriodNotPassed();\n }\n }\n}\n","language":"Solidity","languageVersion":"0.8.24","compilerVersion":"0.8.24","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../","srcMap":"","srcMapRuntime":"","abiDefinition":[{"inputs":[],"name":"AccessControlBadConfirmation","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"bytes32","name":"neededRole","type":"bytes32"}],"name":"AccessControlUnauthorizedAccount","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"previousAdminRole","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"newAdminRole","type":"bytes32"}],"name":"RoleAdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleRevoked","type":"event"},{"inputs":[],"name":"DEFAULT_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleAdmin","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"uint256","name":"index","type":"uint256"}],"name":"getRoleMember","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleMemberCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"grantRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"hasRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"callerConfirmation","type":"address"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"revokeRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"}],"userDoc":{"kind":"user","methods":{},"version":1},"developerDoc":{"details":"Extension of {AccessControl} that allows enumerating the members of each role.","errors":{"AccessControlBadConfirmation()":[{"details":"The caller of a function is not the expected one. NOTE: Don't confuse with {AccessControlUnauthorizedAccount}."}],"AccessControlUnauthorizedAccount(address,bytes32)":[{"details":"The `account` is missing a role."}]},"events":{"RoleAdminChanged(bytes32,bytes32,bytes32)":{"details":"Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole` `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite {RoleAdminChanged} not being emitted signaling this."},"RoleGranted(bytes32,address,address)":{"details":"Emitted when `account` is granted `role`. `sender` is the account that originated the contract call, an admin role bearer except when using {AccessControl-_setupRole}."},"RoleRevoked(bytes32,address,address)":{"details":"Emitted when `account` is revoked `role`. `sender` is the account that originated the contract call: - if using `revokeRole`, it is the admin role bearer - if using `renounceRole`, it is the role bearer (i.e. `account`)"}},"kind":"dev","methods":{"getRoleAdmin(bytes32)":{"details":"Returns the admin role that controls `role`. See {grantRole} and {revokeRole}. To change a role's admin, use {_setRoleAdmin}."},"getRoleMember(bytes32,uint256)":{"details":"Returns one of the accounts that have `role`. `index` must be a value between 0 and {getRoleMemberCount}, non-inclusive. Role bearers are not sorted in any particular way, and their ordering may change at any point. WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure you perform all queries on the same block. See the following https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post] for more information."},"getRoleMemberCount(bytes32)":{"details":"Returns the number of accounts that have `role`. Can be used together with {getRoleMember} to enumerate all bearers of a role."},"grantRole(bytes32,address)":{"details":"Grants `role` to `account`. If `account` had not been already granted `role`, emits a {RoleGranted} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleGranted} event."},"hasRole(bytes32,address)":{"details":"Returns `true` if `account` has been granted `role`."},"renounceRole(bytes32,address)":{"details":"Revokes `role` from the calling account. Roles are often managed via {grantRole} and {revokeRole}: this function's purpose is to provide a mechanism for accounts to lose their privileges if they are compromised (such as when a trusted device is misplaced). If the calling account had been revoked `role`, emits a {RoleRevoked} event. Requirements: - the caller must be `callerConfirmation`. May emit a {RoleRevoked} event."},"revokeRole(bytes32,address)":{"details":"Revokes `role` from `account`. If `account` had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleRevoked} event."},"supportsInterface(bytes4)":{"details":"See {IERC165-supportsInterface}."}},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[],\"name\":\"AccessControlBadConfirmation\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"neededRole\",\"type\":\"bytes32\"}],\"name\":\"AccessControlUnauthorizedAccount\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"previousAdminRole\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"newAdminRole\",\"type\":\"bytes32\"}],\"name\":\"RoleAdminChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleGranted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleRevoked\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"DEFAULT_ADMIN_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"}],\"name\":\"getRoleAdmin\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"index\",\"type\":\"uint256\"}],\"name\":\"getRoleMember\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"}],\"name\":\"getRoleMemberCount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"grantRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"hasRole\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"callerConfirmation\",\"type\":\"address\"}],\"name\":\"renounceRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"revokeRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes4\",\"name\":\"interfaceId\",\"type\":\"bytes4\"}],\"name\":\"supportsInterface\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"}],\"devdoc\":{\"details\":\"Extension of {AccessControl} that allows enumerating the members of each role.\",\"errors\":{\"AccessControlBadConfirmation()\":[{\"details\":\"The caller of a function is not the expected one. NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\"}],\"AccessControlUnauthorizedAccount(address,bytes32)\":[{\"details\":\"The `account` is missing a role.\"}]},\"events\":{\"RoleAdminChanged(bytes32,bytes32,bytes32)\":{\"details\":\"Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole` `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite {RoleAdminChanged} not being emitted signaling this.\"},\"RoleGranted(bytes32,address,address)\":{\"details\":\"Emitted when `account` is granted `role`. `sender` is the account that originated the contract call, an admin role bearer except when using {AccessControl-_setupRole}.\"},\"RoleRevoked(bytes32,address,address)\":{\"details\":\"Emitted when `account` is revoked `role`. `sender` is the account that originated the contract call: - if using `revokeRole`, it is the admin role bearer - if using `renounceRole`, it is the role bearer (i.e. `account`)\"}},\"kind\":\"dev\",\"methods\":{\"getRoleAdmin(bytes32)\":{\"details\":\"Returns the admin role that controls `role`. See {grantRole} and {revokeRole}. To change a role's admin, use {_setRoleAdmin}.\"},\"getRoleMember(bytes32,uint256)\":{\"details\":\"Returns one of the accounts that have `role`. `index` must be a value between 0 and {getRoleMemberCount}, non-inclusive. Role bearers are not sorted in any particular way, and their ordering may change at any point. WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure you perform all queries on the same block. See the following https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post] for more information.\"},\"getRoleMemberCount(bytes32)\":{\"details\":\"Returns the number of accounts that have `role`. Can be used together with {getRoleMember} to enumerate all bearers of a role.\"},\"grantRole(bytes32,address)\":{\"details\":\"Grants `role` to `account`. If `account` had not been already granted `role`, emits a {RoleGranted} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleGranted} event.\"},\"hasRole(bytes32,address)\":{\"details\":\"Returns `true` if `account` has been granted `role`.\"},\"renounceRole(bytes32,address)\":{\"details\":\"Revokes `role` from the calling account. Roles are often managed via {grantRole} and {revokeRole}: this function's purpose is to provide a mechanism for accounts to lose their privileges if they are compromised (such as when a trusted device is misplaced). If the calling account had been revoked `role`, emits a {RoleRevoked} event. Requirements: - the caller must be `callerConfirmation`. May emit a {RoleRevoked} event.\"},\"revokeRole(bytes32,address)\":{\"details\":\"Revokes `role` from `account`. If `account` had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleRevoked} event.\"},\"supportsInterface(bytes4)\":{\"details\":\"See {IERC165-supportsInterface}.\"}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeV2.sol\":\"AccessControlEnumerable\"},\"evmVersion\":\"shanghai\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeV2.sol\":{\"keccak256\":\"0x7cd0f885e80e2bdaa638bc32ae7af7d2e248f99ce4b354c217d0f0f7d7302e0a\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://7ccf28df0bd7b4606986585acd8622ed9b4e81379690061bb66088f0a2270af1\",\"dweb:/ipfs/QmTf7HNdHZkK6vmx8ZgewycQEb72oLD9nPwBpsM5reMstQ\"]}},\"version\":1}"},"hashes":{"DEFAULT_ADMIN_ROLE()":"a217fddf","getRoleAdmin(bytes32)":"248a9ca3","getRoleMember(bytes32,uint256)":"9010d07c","getRoleMemberCount(bytes32)":"ca15c873","grantRole(bytes32,address)":"2f2ff15d","hasRole(bytes32,address)":"91d14854","renounceRole(bytes32,address)":"36568abe","revokeRole(bytes32,address)":"d547741f","supportsInterface(bytes4)":"01ffc9a7"}},"solidity/FastBridgeV2.sol:Address":{"code":"0x60556032600b8282823980515f1a607314602657634e487b7160e01b5f525f60045260245ffd5b305f52607381538281f3fe730000000000000000000000000000000000000000301460806040525f80fdfea264697066735822122066ad3e1b6dabcf400c86562013c52581c196e1c9e2e058e0440d32fcd4e26ad264736f6c63430008180033","runtime-code":"0x730000000000000000000000000000000000000000301460806040525f80fdfea264697066735822122066ad3e1b6dabcf400c86562013c52581c196e1c9e2e058e0440d32fcd4e26ad264736f6c63430008180033","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.24 ^0.8.0 ^0.8.20;\n\n// contracts/interfaces/IAdmin.sol\n\ninterface IAdmin {\n // ============ Events ============\n\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n event ChainGasAmountUpdated(uint256 oldChainGasAmount, uint256 newChainGasAmount);\n\n // ============ Methods ============\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n\n function setChainGasAmount(uint256 newChainGasAmount) external;\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IFastBridgeRecipient.sol\n\ninterface IFastBridgeRecipient {\n function fastBridgeTransferReceived(\n address token,\n uint256 amount,\n bytes memory callParams\n )\n external\n payable\n returns (bytes4);\n}\n\n// contracts/interfaces/IFastBridgeV2Errors.sol\n\ninterface IFastBridgeV2Errors {\n error AmountIncorrect();\n error CallParamsLengthAboveMax();\n error ChainIncorrect();\n error ExclusivityParamsIncorrect();\n error MsgValueIncorrect();\n error NativeTokenCallValueNotSupported();\n error SenderIncorrect();\n error StatusIncorrect();\n error ZeroAddress();\n\n error RecipientIncorrectReturnValue();\n error RecipientNoReturnValue();\n\n error DeadlineExceeded();\n error DeadlineNotExceeded();\n error DeadlineTooShort();\n error DisputePeriodNotPassed();\n error DisputePeriodPassed();\n error ExclusivityPeriodNotPassed();\n\n error TransactionRelayed();\n}\n\n// contracts/libs/Errors.sol\n\nerror DeadlineExceeded();\nerror DeadlineNotExceeded();\nerror DeadlineTooShort();\nerror InsufficientOutputAmount();\n\nerror MsgValueIncorrect();\nerror PoolNotFound();\nerror TokenAddressMismatch();\nerror TokenNotContract();\nerror TokenNotETH();\nerror TokensIdentical();\n\nerror ChainIncorrect();\nerror AmountIncorrect();\nerror ZeroAddress();\n\nerror DisputePeriodNotPassed();\nerror DisputePeriodPassed();\nerror SenderIncorrect();\nerror StatusIncorrect();\nerror TransactionIdIncorrect();\nerror TransactionRelayed();\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// contracts/interfaces/IFastBridgeV2.sol\n\ninterface IFastBridgeV2 is IFastBridge {\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n struct BridgeTxDetails {\n BridgeStatus status;\n uint40 proofBlockTimestamp;\n uint48 proofBlockNumber;\n address proofRelayer;\n }\n\n struct BridgeRelay {\n uint48 blockNumber;\n uint48 blockTimestamp;\n address relayer;\n }\n\n /// @notice New params introduced in the FastBridgeV2.\n /// We are passing fields from the older BridgeParams struct outside of this struct\n /// for backwards compatibility.\n /// Note: quoteRelayer and quoteExclusivitySeconds are either both zero (indicating no exclusivity)\n /// or both non-zero (indicating exclusivity for the given period).\n /// Note: callValue \u003e 0 can NOT be used with destToken = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE (ETH_ADDRESS)\n /// @param quoteRelayer Relayer that provided the quote for the transaction\n /// @param quoteExclusivitySeconds Period of time the quote relayer is guaranteed exclusivity after user's deposit\n /// @param quoteId Unique quote identifier used for tracking the quote\n /// @param callValue ETH value to send to the recipient (if any)\n /// @param callParams Parameters for the arbitrary call to the destination recipient (if any)\n struct BridgeParamsV2 {\n address quoteRelayer;\n int256 quoteExclusivitySeconds;\n bytes quoteId;\n uint256 callValue;\n bytes callParams;\n }\n\n /// @notice Updated bridge transaction struct to include parameters introduced in FastBridgeV2.\n /// Note: only `exclusivityRelayer` can fill such a transaction until `exclusivityEndTime`.\n /// TODO: consider changing the encoding scheme to prevent spending extra gas on decoding.\n struct BridgeTransactionV2 {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n uint256 callValue; // ETH value to send to the recipient (if any) - replaces V1's sendChainGas flag\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n address exclusivityRelayer;\n uint256 exclusivityEndTime;\n bytes callParams;\n }\n\n event BridgeQuoteDetails(bytes32 indexed transactionId, bytes quoteId);\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability\n /// to provide temporary exclusivity fill rights for the quote relayer.\n /// @param params The parameters required to bridge\n /// @param paramsV2 The parameters for exclusivity fill rights (optional, can be left empty)\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function relay(bytes memory request, address relayer) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param transactionId The transaction id associated with the encoded bridge transaction to prove\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital.\n /// @notice Can only send funds to the relayer address on the proof.\n /// @param request The encoded bridge transaction to claim on origin chain\n function claim(bytes memory request) external;\n /// @notice Checks if a transaction has been relayed\n /// @param transactionId The ID of the transaction to check\n /// @return True if the transaction has been relayed, false otherwise\n function bridgeRelays(bytes32 transactionId) external view returns (bool);\n\n /// @notice Returns the status of a bridge transaction\n /// @param transactionId The ID of the bridge transaction\n /// @return BridgeStatus Status of the bridge transaction\n function bridgeStatuses(bytes32 transactionId) external view returns (BridgeStatus);\n\n /// @notice Returns the timestamp and relayer of a bridge proof\n /// @param transactionId The ID of the bridge transaction\n /// @return timestamp The timestamp of the bridge proof\n /// @return relayer The relayer address of the bridge proof\n function bridgeProofs(bytes32 transactionId) external view returns (uint96 timestamp, address relayer);\n\n /// @notice Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\n /// @param request The bridge request to decode\n function getBridgeTransactionV2(bytes memory request) external view returns (BridgeTransactionV2 memory);\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// contracts/libs/UniversalToken.sol\n\nlibrary UniversalTokenLib {\n using SafeERC20 for IERC20;\n\n address internal constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Transfers tokens to the given account. Reverts if transfer is not successful.\n /// @dev This might trigger fallback, if ETH is transferred to the contract.\n /// Make sure this can not lead to reentrancy attacks.\n function universalTransfer(address token, address to, uint256 value) internal {\n // Don't do anything, if need to send tokens to this address\n if (to == address(this)) return;\n // Don't do anything, if trying to send zero value\n if (value == 0) return;\n if (token == ETH_ADDRESS) {\n /// @dev Note: this can potentially lead to executing code in `to`.\n // solhint-disable-next-line avoid-low-level-calls\n (bool success,) = to.call{value: value}(\"\");\n require(success, \"ETH transfer failed\");\n } else {\n IERC20(token).safeTransfer(to, value);\n }\n }\n\n /// @notice Issues an infinite allowance to the spender, if the current allowance is insufficient\n /// to spend the given amount.\n function universalApproveInfinity(address token, address spender, uint256 amountToSpend) internal {\n // ETH Chad doesn't require your approval\n if (token == ETH_ADDRESS) return;\n // No-op if allowance is already sufficient\n uint256 allowance = IERC20(token).allowance(address(this), spender);\n if (allowance \u003e= amountToSpend) return;\n // Otherwise, reset approval to 0 and set to max allowance\n if (allowance \u003e 0) IERC20(token).safeDecreaseAllowance(spender, allowance);\n IERC20(token).safeIncreaseAllowance(spender, type(uint256).max);\n }\n\n /// @notice Returns the balance of the given token (or native ETH) for the given account.\n function universalBalanceOf(address token, address account) internal view returns (uint256) {\n if (token == ETH_ADDRESS) {\n return account.balance;\n } else {\n return IERC20(token).balanceOf(account);\n }\n }\n\n /// @dev Checks that token is a contract and not ETH_ADDRESS.\n function assertIsContract(address token) internal view {\n // Check that ETH_ADDRESS was not used (in case this is a predeploy on any of the chains)\n if (token == UniversalTokenLib.ETH_ADDRESS) revert TokenNotContract();\n // Check that token is not an EOA\n if (token.code.length == 0) revert TokenNotContract();\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/Admin.sol\n\ncontract Admin is IAdmin, AccessControlEnumerable {\n using UniversalTokenLib for address;\n\n bytes32 public constant RELAYER_ROLE = keccak256(\"RELAYER_ROLE\");\n bytes32 public constant REFUNDER_ROLE = keccak256(\"REFUNDER_ROLE\");\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n uint256 public constant FEE_BPS = 1e6;\n uint256 public constant FEE_RATE_MAX = 0.01e6; // max 1% on origin amount\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Chain gas amount to forward as rebate if requested\n uint256 public chainGasAmount;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n }\n\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n require(newFeeRate \u003c= FEE_RATE_MAX, \"newFeeRate \u003e max\");\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n token.universalTransfer(recipient, feeAmount);\n emit FeesSwept(token, recipient, feeAmount);\n }\n\n function setChainGasAmount(uint256 newChainGasAmount) external onlyRole(GOVERNOR_ROLE) {\n uint256 oldChainGasAmount = chainGasAmount;\n chainGasAmount = newChainGasAmount;\n emit ChainGasAmountUpdated(oldChainGasAmount, newChainGasAmount);\n }\n}\n\n// contracts/FastBridgeV2.sol\n\n/// @notice FastBridgeV2 is a contract for bridging tokens across chains.\ncontract FastBridgeV2 is Admin, IFastBridgeV2, IFastBridgeV2Errors {\n using SafeERC20 for IERC20;\n using UniversalTokenLib for address;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Delay for a transaction after which it could be permisionlessly refunded\n uint256 public constant REFUND_DELAY = 7 days;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n /// @notice Maximum length of accepted callParams\n uint256 public constant MAX_CALL_PARAMS_LENGTH = 2 ** 16 - 1;\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeTxDetails) public bridgeTxDetails;\n /// @notice Relay details on destination chain\n mapping(bytes32 =\u003e BridgeRelay) public bridgeRelayDetails;\n /// @notice Unique bridge nonces tracked per originSender\n mapping(address =\u003e uint256) public senderNonces;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Replaced by senderNonces\n uint256 public immutable nonce = 0;\n /// @notice the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n bridge({\n params: params,\n paramsV2: BridgeParamsV2({\n quoteRelayer: address(0),\n quoteExclusivitySeconds: 0,\n quoteId: bytes(\"\"),\n callValue: 0,\n callParams: bytes(\"\")\n })\n });\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes memory request) external payable {\n relay({request: request, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes memory request, bytes32 destTxHash) external {\n prove({transactionId: keccak256(request), destTxHash: destTxHash, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridgeV2\n function claim(bytes memory request) external {\n claim({request: request, to: address(0)});\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003e DISPUTE_PERIOD) {\n revert DisputePeriodPassed();\n }\n\n // @dev relayer gets slashed effectively if dest relay has gone thru\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n bridgeTxDetails[transactionId].proofRelayer = address(0);\n bridgeTxDetails[transactionId].proofBlockTimestamp = 0;\n bridgeTxDetails[transactionId].proofBlockNumber = 0;\n\n emit BridgeProofDisputed(transactionId, msg.sender);\n }\n\n /// @inheritdoc IFastBridge\n function refund(bytes memory request) external {\n bytes32 transactionId = keccak256(request);\n\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n\n if (bridgeTxDetails[transactionId].status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n\n if (hasRole(REFUNDER_ROLE, msg.sender)) {\n // Refunder can refund if deadline has passed\n if (block.timestamp \u003c= transaction.deadline) revert DeadlineNotExceeded();\n } else {\n // Permissionless refund is allowed after REFUND_DELAY\n if (block.timestamp \u003c= transaction.deadline + REFUND_DELAY) revert DeadlineNotExceeded();\n }\n\n // if all checks passed, set to REFUNDED status\n bridgeTxDetails[transactionId].status = BridgeStatus.REFUNDED;\n\n // transfer origin collateral back to original sender\n address to = transaction.originSender;\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount + transaction.originFeeAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (bridgeTxDetails[transactionId].proofRelayer != relayer) revert SenderIncorrect();\n return _timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n /// @dev This method is added to achieve backwards compatibility with decoding requests into V1 structs:\n /// - `callValue` is partially reported as a zero/non-zero flag\n /// - `callParams` is ignored\n /// In order to process all kinds of requests use getBridgeTransactionV2 instead.\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory) {\n // Try decoding into V2 struct first. This will revert if V1 struct is passed\n try this.getBridgeTransactionV2(request) returns (BridgeTransactionV2 memory txV2) {\n // Note: we entirely ignore the callParams field, as it was not present in V1\n return BridgeTransaction({\n originChainId: txV2.originChainId,\n destChainId: txV2.destChainId,\n originSender: txV2.originSender,\n destRecipient: txV2.destRecipient,\n originToken: txV2.originToken,\n destToken: txV2.destToken,\n originAmount: txV2.originAmount,\n destAmount: txV2.destAmount,\n originFeeAmount: txV2.originFeeAmount,\n sendChainGas: txV2.callValue != 0,\n deadline: txV2.deadline,\n nonce: txV2.nonce\n });\n } catch {\n // Fallback to V1 struct\n return abi.decode(request, (BridgeTransaction));\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) public payable {\n int256 exclusivityEndTime = int256(block.timestamp) + paramsV2.quoteExclusivitySeconds;\n _validateBridgeParams(params, paramsV2, exclusivityEndTime);\n\n // transfer tokens to bridge contract\n /// @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _pullToken(params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n\n // set status to requested\n bytes memory request = abi.encode(\n BridgeTransactionV2({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n callValue: paramsV2.callValue,\n deadline: params.deadline,\n nonce: senderNonces[params.sender]++, // increment nonce on every bridge\n exclusivityRelayer: paramsV2.quoteRelayer,\n // We checked exclusivityEndTime to be in range (0 .. params.deadline] above, so can safely cast\n exclusivityEndTime: uint256(exclusivityEndTime),\n callParams: paramsV2.callParams\n })\n );\n bytes32 transactionId = keccak256(request);\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n\n emit BridgeRequested({\n transactionId: transactionId,\n sender: params.sender,\n request: request,\n destChainId: params.dstChainId,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n sendChainGas: paramsV2.callValue != 0\n });\n emit BridgeQuoteDetails(transactionId, paramsV2.quoteId);\n }\n\n /// @inheritdoc IFastBridgeV2\n function relay(bytes memory request, address relayer) public payable {\n bytes32 transactionId = keccak256(request);\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n _validateRelayParams(transaction, transactionId, relayer);\n // mark bridge transaction as relayed\n bridgeRelayDetails[transactionId] =\n BridgeRelay({blockNumber: uint48(block.number), blockTimestamp: uint48(block.timestamp), relayer: relayer});\n\n // transfer tokens to recipient on destination chain and do an arbitrary call if requested\n address to = transaction.destRecipient;\n address token = transaction.destToken;\n uint256 amount = transaction.destAmount;\n\n // All state changes have been done at this point, can proceed to the external calls.\n // This follows the checks-effects-interactions pattern to mitigate potential reentrancy attacks.\n if (token == UniversalTokenLib.ETH_ADDRESS) {\n // For ETH non-zero callValue is not allowed\n if (transaction.callValue != 0) revert NativeTokenCallValueNotSupported();\n // Check that the correct msg.value was sent\n if (msg.value != amount) revert MsgValueIncorrect();\n } else {\n // For ERC20s, we check that the correct msg.value was sent\n if (msg.value != transaction.callValue) revert MsgValueIncorrect();\n // We need to transfer the tokens from the Relayer to the recipient first before performing an\n // optional post-transfer arbitrary call.\n IERC20(token).safeTransferFrom(msg.sender, to, amount);\n }\n\n if (transaction.callParams.length != 0) {\n // Arbitrary call requested, perform it while supplying full msg.value to the recipient\n // Note: if token has a fee on transfers, the recipient will have received less than `amount`.\n // This is a very niche edge case and should be handled by the recipient contract.\n _checkedCallRecipient({recipient: to, token: token, amount: amount, callParams: transaction.callParams});\n } else if (msg.value != 0) {\n // No arbitrary call requested, but msg.value was sent. This is either a relay with ETH,\n // or a non-zero callValue request with an ERC20. In both cases, transfer the ETH to the recipient.\n Address.sendValue(payable(to), msg.value);\n }\n\n emit BridgeRelayed({\n transactionId: transactionId,\n relayer: relayer,\n to: to,\n originChainId: transaction.originChainId,\n originToken: transaction.originToken,\n destToken: transaction.destToken,\n originAmount: transaction.originAmount,\n destAmount: transaction.destAmount,\n chainGasAmount: transaction.callValue\n });\n }\n\n /// @inheritdoc IFastBridgeV2\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) public onlyRole(RELAYER_ROLE) {\n // update bridge tx status given proof provided\n if (bridgeTxDetails[transactionId].status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n bridgeTxDetails[transactionId].status = BridgeStatus.RELAYER_PROVED;\n bridgeTxDetails[transactionId].proofBlockTimestamp = uint40(block.timestamp);\n bridgeTxDetails[transactionId].proofBlockNumber = uint48(block.number);\n bridgeTxDetails[transactionId].proofRelayer = relayer;\n\n emit BridgeProofProvided(transactionId, relayer, destTxHash);\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes memory request, address to) public {\n bytes32 transactionId = keccak256(request);\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n\n // update bridge tx status if able to claim origin collateral\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n\n // if \"to\" is zero addr, permissionlessly send funds to proven relayer\n if (to == address(0)) {\n to = bridgeTxDetails[transactionId].proofRelayer;\n } else if (bridgeTxDetails[transactionId].proofRelayer != msg.sender) {\n revert SenderIncorrect();\n }\n\n if (_timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003c= DISPUTE_PERIOD) {\n revert DisputePeriodNotPassed();\n }\n\n bridgeTxDetails[transactionId].status = BridgeStatus.RELAYER_CLAIMED;\n\n // update protocol fees if origin fee amount exists\n if (transaction.originFeeAmount \u003e 0) protocolFees[transaction.originToken] += transaction.originFeeAmount;\n\n // transfer origin collateral less fee to specified address\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositClaimed(transactionId, bridgeTxDetails[transactionId].proofRelayer, to, token, amount);\n }\n\n function bridgeStatuses(bytes32 transactionId) public view returns (BridgeStatus status) {\n return bridgeTxDetails[transactionId].status;\n }\n\n function bridgeProofs(bytes32 transactionId) public view returns (uint96 timestamp, address relayer) {\n timestamp = bridgeTxDetails[transactionId].proofBlockTimestamp;\n relayer = bridgeTxDetails[transactionId].proofRelayer;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeRelays(bytes32 transactionId) public view returns (bool) {\n // has this transactionId been relayed?\n return bridgeRelayDetails[transactionId].relayer != address(0);\n }\n\n /// @inheritdoc IFastBridgeV2\n function getBridgeTransactionV2(bytes memory request) public pure returns (BridgeTransactionV2 memory) {\n return abi.decode(request, (BridgeTransactionV2));\n }\n\n /// @notice Pulls a requested token from the user to this contract.\n function _pullToken(address token, uint256 amount) internal returns (uint256 amountPulled) {\n if (token == UniversalTokenLib.ETH_ADDRESS) {\n // For ETH we just need to check that the supplied msg.value is correct\n if (amount != msg.value) revert MsgValueIncorrect();\n amountPulled = msg.value;\n } else {\n token.assertIsContract();\n // Record token balance before transfer\n amountPulled = IERC20(token).balanceOf(address(this));\n // Token needs to be pulled only if msg.value is zero\n // This way user can specify WETH as the origin asset\n IERC20(token).safeTransferFrom(msg.sender, address(this), amount);\n // Use the difference between the recorded balance and the current balance as the amountPulled\n amountPulled = IERC20(token).balanceOf(address(this)) - amountPulled;\n }\n }\n\n /// @notice Calls the Recipient's hook function with the specified callParams and performs\n /// all the necessary checks for the returned value.\n function _checkedCallRecipient(\n address recipient,\n address token,\n uint256 amount,\n bytes memory callParams\n )\n internal\n {\n bytes memory hookData =\n abi.encodeCall(IFastBridgeRecipient.fastBridgeTransferReceived, (token, amount, callParams));\n // This will bubble any revert messages from the hook function\n bytes memory returnData = Address.functionCallWithValue({target: recipient, data: hookData, value: msg.value});\n // Explicit revert if no return data at all\n if (returnData.length == 0) revert RecipientNoReturnValue();\n // Check that exactly a single return value was returned\n if (returnData.length != 32) revert RecipientIncorrectReturnValue();\n // Return value should be abi-encoded hook function selector\n if (bytes32(returnData) != bytes32(IFastBridgeRecipient.fastBridgeTransferReceived.selector)) {\n revert RecipientIncorrectReturnValue();\n }\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint40(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint40).max but\n /// proof.timestamp \u003c type(uint40).max via unchecked statement\n /// @param proofBlockTimestamp The bridge proof block timestamp\n /// @return delta Time delta since proof submitted\n function _timeSince(uint40 proofBlockTimestamp) internal view returns (uint256 delta) {\n unchecked {\n delta = uint40(block.timestamp) - proofBlockTimestamp;\n }\n }\n\n /// @notice Performs all the necessary checks for a bridge to happen.\n /// @dev There's no good way to refactor this function to reduce cyclomatic complexity due to\n /// the number of checks that need to be performed, so we skip the code-complexity rule here.\n // solhint-disable-next-line code-complexity\n function _validateBridgeParams(\n BridgeParams memory params,\n BridgeParamsV2 memory paramsV2,\n int256 exclusivityEndTime\n )\n internal\n view\n {\n // Check V1 (legacy) params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.sender == address(0) || params.to == address(0)) revert ZeroAddress();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n // Check V2 params\n if (paramsV2.callParams.length \u003e MAX_CALL_PARAMS_LENGTH) revert CallParamsLengthAboveMax();\n if (paramsV2.callValue != 0 \u0026\u0026 params.destToken == UniversalTokenLib.ETH_ADDRESS) {\n revert NativeTokenCallValueNotSupported();\n }\n // exclusivityEndTime must be in range (0 .. params.deadline]\n if (exclusivityEndTime \u003c= 0 || exclusivityEndTime \u003e int256(params.deadline)) {\n revert ExclusivityParamsIncorrect();\n }\n }\n\n /// @notice Performs all the necessary checks for a relay to happen.\n function _validateRelayParams(\n BridgeTransactionV2 memory transaction,\n bytes32 transactionId,\n address relayer\n )\n internal\n view\n {\n if (relayer == address(0)) revert ZeroAddress();\n // Check if the transaction has already been relayed\n if (bridgeRelays(transactionId)) revert TransactionRelayed();\n if (transaction.destChainId != uint32(block.chainid)) revert ChainIncorrect();\n // Check the deadline for relay to happen\n if (block.timestamp \u003e transaction.deadline) revert DeadlineExceeded();\n // Check the exclusivity period, if it is still ongoing\n // forgefmt: disable-next-item\n if (\n transaction.exclusivityRelayer != address(0) \u0026\u0026\n transaction.exclusivityRelayer != relayer \u0026\u0026\n block.timestamp \u003c= transaction.exclusivityEndTime\n ) {\n revert ExclusivityPeriodNotPassed();\n }\n }\n}\n","language":"Solidity","languageVersion":"0.8.24","compilerVersion":"0.8.24","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../","srcMap":"16564:6066:0:-:0;;;;;;;;;;;;;;;-1:-1:-1;;;16564:6066:0;;;;;;;;;;;;;;;;;","srcMapRuntime":"16564:6066:0:-:0;;;;;;;;","abiDefinition":[{"inputs":[{"internalType":"address","name":"target","type":"address"}],"name":"AddressEmptyCode","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"AddressInsufficientBalance","type":"error"},{"inputs":[],"name":"FailedInnerCall","type":"error"}],"userDoc":{"kind":"user","methods":{},"version":1},"developerDoc":{"details":"Collection of functions related to the address type","errors":{"AddressEmptyCode(address)":[{"details":"There's no code at `target` (it is not a contract)."}],"AddressInsufficientBalance(address)":[{"details":"The ETH balance of the account is not enough to perform the operation."}],"FailedInnerCall()":[{"details":"A call to an address target failed. The target may have reverted."}]},"kind":"dev","methods":{},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"}],\"name\":\"AddressEmptyCode\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"AddressInsufficientBalance\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"FailedInnerCall\",\"type\":\"error\"}],\"devdoc\":{\"details\":\"Collection of functions related to the address type\",\"errors\":{\"AddressEmptyCode(address)\":[{\"details\":\"There's no code at `target` (it is not a contract).\"}],\"AddressInsufficientBalance(address)\":[{\"details\":\"The ETH balance of the account is not enough to perform the operation.\"}],\"FailedInnerCall()\":[{\"details\":\"A call to an address target failed. The target may have reverted.\"}]},\"kind\":\"dev\",\"methods\":{},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeV2.sol\":\"Address\"},\"evmVersion\":\"shanghai\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeV2.sol\":{\"keccak256\":\"0x7cd0f885e80e2bdaa638bc32ae7af7d2e248f99ce4b354c217d0f0f7d7302e0a\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://7ccf28df0bd7b4606986585acd8622ed9b4e81379690061bb66088f0a2270af1\",\"dweb:/ipfs/QmTf7HNdHZkK6vmx8ZgewycQEb72oLD9nPwBpsM5reMstQ\"]}},\"version\":1}"},"hashes":{}},"solidity/FastBridgeV2.sol:Admin":{"code":"0x608060405234801562000010575f80fd5b50604051620013a3380380620013a3833981016040819052620000339162000184565b6200003f5f8262000047565b5050620001ac565b5f8062000055848462000082565b9050801562000079575f8481526001602052604090206200007790846200012d565b505b90505b92915050565b5f828152602081815260408083206001600160a01b038516845290915281205460ff1662000125575f838152602081815260408083206001600160a01b03861684529091529020805460ff19166001179055620000dc3390565b6001600160a01b0316826001600160a01b0316847f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45060016200007c565b505f6200007c565b5f62000079836001600160a01b0384165f8181526001830160205260408120546200012557508154600181810184555f8481526020808220909301849055845484825282860190935260409020919091556200007c565b5f6020828403121562000195575f80fd5b81516001600160a01b038116811462000079575f80fd5b6111e980620001ba5f395ff3fe608060405234801561000f575f80fd5b506004361061016e575f3560e01c806391d14854116100d2578063bf333f2c11610088578063d547741f11610063578063d547741f14610378578063dcf844a71461038b578063e00a83e0146103aa575f80fd5b8063bf333f2c14610334578063ca15c8731461033e578063ccc5749014610351575f80fd5b8063a217fddf116100b8578063a217fddf14610307578063b13aa2d61461030e578063b250fe6b14610321575f80fd5b806391d148541461029d578063926d7d7f146102e0575f80fd5b80632f2ff15d1161012757806358f858801161010d57806358f85880146102355780635960ccf21461023e5780639010d07c14610265575f80fd5b80632f2ff15d1461020f57806336568abe14610222575f80fd5b806306f333f21161015757806306f333f2146101cf5780630f5f6ed7146101e4578063248a9ca3146101ed575f80fd5b806301ffc9a71461017257806303ed0ee51461019a575b5f80fd5b610185610180366004610fcd565b6103b3565b60405190151581526020015b60405180910390f35b6101c17f043c983c49d46f0e102151eaf8085d4a2e6571d5df2d47b013f39bddfd4a639d81565b604051908152602001610191565b6101e26101dd366004611034565b61040e565b005b6101c161271081565b6101c16101fb366004611065565b5f9081526020819052604090206001015490565b6101e261021d36600461107c565b6104fa565b6101e261023036600461107c565b610524565b6101c160025481565b6101c17fdb9556138406326f00296e13ea2ad7db24ba82381212d816b1a40c23b466b32781565b61027861027336600461109d565b61057d565b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610191565b6101856102ab36600461107c565b5f9182526020828152604080842073ffffffffffffffffffffffffffffffffffffffff93909316845291905290205460ff1690565b6101c17fe2b7fb3b832174769106daebcfd6d1970523240dda11281102db9363b83b0dc481565b6101c15f81565b6101e261031c366004611065565b61059b565b6101e261032f366004611065565b61067d565b6101c1620f424081565b6101c161034c366004611065565b6106e5565b6101c17f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f5581565b6101e261038636600461107c565b6106fb565b6101c16103993660046110bd565b60036020525f908152604090205481565b6101c160045481565b5f7fffffffff0000000000000000000000000000000000000000000000000000000082167f5a05180f00000000000000000000000000000000000000000000000000000000148061040857506104088261071f565b92915050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f55610438816107b5565b73ffffffffffffffffffffffffffffffffffffffff83165f908152600360205260408120549081900361046b5750505050565b73ffffffffffffffffffffffffffffffffffffffff84165f8181526003602052604081205561049b9084836107c2565b6040805173ffffffffffffffffffffffffffffffffffffffff8087168252851660208201529081018290527f244e51bc38c1452fa8aaf487bcb4bca36c2baa3a5fbdb776b1eabd8dc6d277cd9060600160405180910390a1505b505050565b5f82815260208190526040902060010154610514816107b5565b61051e8383610914565b50505050565b73ffffffffffffffffffffffffffffffffffffffff81163314610573576040517f6697b23200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6104f58282610947565b5f8281526001602052604081206105949083610972565b9392505050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f556105c5816107b5565b612710821115610636576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f6e657746656552617465203e206d61780000000000000000000000000000000060448201526064015b60405180910390fd5b600280549083905560408051828152602081018590527f14914da2bf76024616fbe1859783fcd4dbddcb179b1f3a854949fbf920dcb95791015b60405180910390a1505050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f556106a7816107b5565b600480549083905560408051828152602081018590527f5cf09b12f3f56b4c564d51b25b40360af6d795198adb61ae0806a36c294323fa9101610670565b5f8181526001602052604081206104089061097d565b5f82815260208190526040902060010154610715816107b5565b61051e8383610947565b5f7fffffffff0000000000000000000000000000000000000000000000000000000082167f7965db0b00000000000000000000000000000000000000000000000000000000148061040857507f01ffc9a7000000000000000000000000000000000000000000000000000000007fffffffff00000000000000000000000000000000000000000000000000000000831614610408565b6107bf8133610986565b50565b3073ffffffffffffffffffffffffffffffffffffffff8316036107e457505050565b805f036107f057505050565b7fffffffffffffffffffffffff111111111111111111111111111111111111111273ffffffffffffffffffffffffffffffffffffffff8416016108f3575f8273ffffffffffffffffffffffffffffffffffffffff16826040515f6040518083038185875af1925050503d805f8114610883576040519150601f19603f3d011682016040523d82523d5f602084013e610888565b606091505b505090508061051e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f455448207472616e73666572206661696c656400000000000000000000000000604482015260640161062d565b6104f573ffffffffffffffffffffffffffffffffffffffff84168383610a0f565b5f806109208484610a9c565b90508015610594575f84815260016020526040902061093f9084610b95565b509392505050565b5f806109538484610bb6565b90508015610594575f84815260016020526040902061093f9084610c6f565b5f6105948383610c90565b5f610408825490565b5f8281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915290205460ff16610a0b576040517fe2517d3f00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff821660048201526024810183905260440161062d565b5050565b6040805173ffffffffffffffffffffffffffffffffffffffff8416602482015260448082018490528251808303909101815260649091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fa9059cbb000000000000000000000000000000000000000000000000000000001790526104f5908490610cb6565b5f8281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915281205460ff16610b8e575f8381526020818152604080832073ffffffffffffffffffffffffffffffffffffffff86168452909152902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055610b2c3390565b73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16847f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a4506001610408565b505f610408565b5f6105948373ffffffffffffffffffffffffffffffffffffffff8416610d4a565b5f8281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915281205460ff1615610b8e575f8381526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8616808552925280832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016905551339286917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a4506001610408565b5f6105948373ffffffffffffffffffffffffffffffffffffffff8416610d8f565b5f825f018281548110610ca557610ca56110d6565b905f5260205f200154905092915050565b5f610cd773ffffffffffffffffffffffffffffffffffffffff841683610e72565b905080515f14158015610cfb575080806020019051810190610cf99190611103565b155b156104f5576040517f5274afe700000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8416600482015260240161062d565b5f818152600183016020526040812054610b8e57508154600181810184555f848152602080822090930184905584548482528286019093526040902091909155610408565b5f8181526001830160205260408120548015610e69575f610db1600183611122565b85549091505f90610dc490600190611122565b9050808214610e23575f865f018281548110610de257610de26110d6565b905f5260205f200154905080875f018481548110610e0257610e026110d6565b5f918252602080832090910192909255918252600188019052604090208390555b8554869080610e3457610e3461115a565b600190038181905f5260205f20015f90559055856001015f8681526020019081526020015f205f905560019350505050610408565b5f915050610408565b606061059483835f845f808573ffffffffffffffffffffffffffffffffffffffff168486604051610ea39190611187565b5f6040518083038185875af1925050503d805f8114610edd576040519150601f19603f3d011682016040523d82523d5f602084013e610ee2565b606091505b5091509150610ef2868383610efc565b9695505050505050565b606082610f1157610f0c82610f8b565b610594565b8151158015610f35575073ffffffffffffffffffffffffffffffffffffffff84163b155b15610f84576040517f9996b31500000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8516600482015260240161062d565b5080610594565b805115610f9b5780518082602001fd5b6040517f1425ea4200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f60208284031215610fdd575f80fd5b81357fffffffff0000000000000000000000000000000000000000000000000000000081168114610594575f80fd5b803573ffffffffffffffffffffffffffffffffffffffff8116811461102f575f80fd5b919050565b5f8060408385031215611045575f80fd5b61104e8361100c565b915061105c6020840161100c565b90509250929050565b5f60208284031215611075575f80fd5b5035919050565b5f806040838503121561108d575f80fd5b8235915061105c6020840161100c565b5f80604083850312156110ae575f80fd5b50508035926020909101359150565b5f602082840312156110cd575f80fd5b6105948261100c565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b5f60208284031215611113575f80fd5b81518015158114610594575f80fd5b81810381811115610408577f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603160045260245ffd5b5f82515f5b818110156111a6576020818601810151858301520161118c565b505f92019182525091905056fea2646970667358221220663496d7fb99c06349f8fc2145322e6c10ba61153be06cea50f6b07db91bc1bd64736f6c63430008180033","runtime-code":"0x608060405234801561000f575f80fd5b506004361061016e575f3560e01c806391d14854116100d2578063bf333f2c11610088578063d547741f11610063578063d547741f14610378578063dcf844a71461038b578063e00a83e0146103aa575f80fd5b8063bf333f2c14610334578063ca15c8731461033e578063ccc5749014610351575f80fd5b8063a217fddf116100b8578063a217fddf14610307578063b13aa2d61461030e578063b250fe6b14610321575f80fd5b806391d148541461029d578063926d7d7f146102e0575f80fd5b80632f2ff15d1161012757806358f858801161010d57806358f85880146102355780635960ccf21461023e5780639010d07c14610265575f80fd5b80632f2ff15d1461020f57806336568abe14610222575f80fd5b806306f333f21161015757806306f333f2146101cf5780630f5f6ed7146101e4578063248a9ca3146101ed575f80fd5b806301ffc9a71461017257806303ed0ee51461019a575b5f80fd5b610185610180366004610fcd565b6103b3565b60405190151581526020015b60405180910390f35b6101c17f043c983c49d46f0e102151eaf8085d4a2e6571d5df2d47b013f39bddfd4a639d81565b604051908152602001610191565b6101e26101dd366004611034565b61040e565b005b6101c161271081565b6101c16101fb366004611065565b5f9081526020819052604090206001015490565b6101e261021d36600461107c565b6104fa565b6101e261023036600461107c565b610524565b6101c160025481565b6101c17fdb9556138406326f00296e13ea2ad7db24ba82381212d816b1a40c23b466b32781565b61027861027336600461109d565b61057d565b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610191565b6101856102ab36600461107c565b5f9182526020828152604080842073ffffffffffffffffffffffffffffffffffffffff93909316845291905290205460ff1690565b6101c17fe2b7fb3b832174769106daebcfd6d1970523240dda11281102db9363b83b0dc481565b6101c15f81565b6101e261031c366004611065565b61059b565b6101e261032f366004611065565b61067d565b6101c1620f424081565b6101c161034c366004611065565b6106e5565b6101c17f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f5581565b6101e261038636600461107c565b6106fb565b6101c16103993660046110bd565b60036020525f908152604090205481565b6101c160045481565b5f7fffffffff0000000000000000000000000000000000000000000000000000000082167f5a05180f00000000000000000000000000000000000000000000000000000000148061040857506104088261071f565b92915050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f55610438816107b5565b73ffffffffffffffffffffffffffffffffffffffff83165f908152600360205260408120549081900361046b5750505050565b73ffffffffffffffffffffffffffffffffffffffff84165f8181526003602052604081205561049b9084836107c2565b6040805173ffffffffffffffffffffffffffffffffffffffff8087168252851660208201529081018290527f244e51bc38c1452fa8aaf487bcb4bca36c2baa3a5fbdb776b1eabd8dc6d277cd9060600160405180910390a1505b505050565b5f82815260208190526040902060010154610514816107b5565b61051e8383610914565b50505050565b73ffffffffffffffffffffffffffffffffffffffff81163314610573576040517f6697b23200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6104f58282610947565b5f8281526001602052604081206105949083610972565b9392505050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f556105c5816107b5565b612710821115610636576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f6e657746656552617465203e206d61780000000000000000000000000000000060448201526064015b60405180910390fd5b600280549083905560408051828152602081018590527f14914da2bf76024616fbe1859783fcd4dbddcb179b1f3a854949fbf920dcb95791015b60405180910390a1505050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f556106a7816107b5565b600480549083905560408051828152602081018590527f5cf09b12f3f56b4c564d51b25b40360af6d795198adb61ae0806a36c294323fa9101610670565b5f8181526001602052604081206104089061097d565b5f82815260208190526040902060010154610715816107b5565b61051e8383610947565b5f7fffffffff0000000000000000000000000000000000000000000000000000000082167f7965db0b00000000000000000000000000000000000000000000000000000000148061040857507f01ffc9a7000000000000000000000000000000000000000000000000000000007fffffffff00000000000000000000000000000000000000000000000000000000831614610408565b6107bf8133610986565b50565b3073ffffffffffffffffffffffffffffffffffffffff8316036107e457505050565b805f036107f057505050565b7fffffffffffffffffffffffff111111111111111111111111111111111111111273ffffffffffffffffffffffffffffffffffffffff8416016108f3575f8273ffffffffffffffffffffffffffffffffffffffff16826040515f6040518083038185875af1925050503d805f8114610883576040519150601f19603f3d011682016040523d82523d5f602084013e610888565b606091505b505090508061051e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f455448207472616e73666572206661696c656400000000000000000000000000604482015260640161062d565b6104f573ffffffffffffffffffffffffffffffffffffffff84168383610a0f565b5f806109208484610a9c565b90508015610594575f84815260016020526040902061093f9084610b95565b509392505050565b5f806109538484610bb6565b90508015610594575f84815260016020526040902061093f9084610c6f565b5f6105948383610c90565b5f610408825490565b5f8281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915290205460ff16610a0b576040517fe2517d3f00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff821660048201526024810183905260440161062d565b5050565b6040805173ffffffffffffffffffffffffffffffffffffffff8416602482015260448082018490528251808303909101815260649091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fa9059cbb000000000000000000000000000000000000000000000000000000001790526104f5908490610cb6565b5f8281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915281205460ff16610b8e575f8381526020818152604080832073ffffffffffffffffffffffffffffffffffffffff86168452909152902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055610b2c3390565b73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16847f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a4506001610408565b505f610408565b5f6105948373ffffffffffffffffffffffffffffffffffffffff8416610d4a565b5f8281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915281205460ff1615610b8e575f8381526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8616808552925280832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016905551339286917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a4506001610408565b5f6105948373ffffffffffffffffffffffffffffffffffffffff8416610d8f565b5f825f018281548110610ca557610ca56110d6565b905f5260205f200154905092915050565b5f610cd773ffffffffffffffffffffffffffffffffffffffff841683610e72565b905080515f14158015610cfb575080806020019051810190610cf99190611103565b155b156104f5576040517f5274afe700000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8416600482015260240161062d565b5f818152600183016020526040812054610b8e57508154600181810184555f848152602080822090930184905584548482528286019093526040902091909155610408565b5f8181526001830160205260408120548015610e69575f610db1600183611122565b85549091505f90610dc490600190611122565b9050808214610e23575f865f018281548110610de257610de26110d6565b905f5260205f200154905080875f018481548110610e0257610e026110d6565b5f918252602080832090910192909255918252600188019052604090208390555b8554869080610e3457610e3461115a565b600190038181905f5260205f20015f90559055856001015f8681526020019081526020015f205f905560019350505050610408565b5f915050610408565b606061059483835f845f808573ffffffffffffffffffffffffffffffffffffffff168486604051610ea39190611187565b5f6040518083038185875af1925050503d805f8114610edd576040519150601f19603f3d011682016040523d82523d5f602084013e610ee2565b606091505b5091509150610ef2868383610efc565b9695505050505050565b606082610f1157610f0c82610f8b565b610594565b8151158015610f35575073ffffffffffffffffffffffffffffffffffffffff84163b155b15610f84576040517f9996b31500000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8516600482015260240161062d565b5080610594565b805115610f9b5780518082602001fd5b6040517f1425ea4200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f60208284031215610fdd575f80fd5b81357fffffffff0000000000000000000000000000000000000000000000000000000081168114610594575f80fd5b803573ffffffffffffffffffffffffffffffffffffffff8116811461102f575f80fd5b919050565b5f8060408385031215611045575f80fd5b61104e8361100c565b915061105c6020840161100c565b90509250929050565b5f60208284031215611075575f80fd5b5035919050565b5f806040838503121561108d575f80fd5b8235915061105c6020840161100c565b5f80604083850312156110ae575f80fd5b50508035926020909101359150565b5f602082840312156110cd575f80fd5b6105948261100c565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b5f60208284031215611113575f80fd5b81518015158114610594575f80fd5b81810381811115610408577f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603160045260245ffd5b5f82515f5b818110156111a6576020818601810151858301520161118c565b505f92019182525091905056fea2646970667358221220663496d7fb99c06349f8fc2145322e6c10ba61153be06cea50f6b07db91bc1bd64736f6c63430008180033","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.24 ^0.8.0 ^0.8.20;\n\n// contracts/interfaces/IAdmin.sol\n\ninterface IAdmin {\n // ============ Events ============\n\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n event ChainGasAmountUpdated(uint256 oldChainGasAmount, uint256 newChainGasAmount);\n\n // ============ Methods ============\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n\n function setChainGasAmount(uint256 newChainGasAmount) external;\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IFastBridgeRecipient.sol\n\ninterface IFastBridgeRecipient {\n function fastBridgeTransferReceived(\n address token,\n uint256 amount,\n bytes memory callParams\n )\n external\n payable\n returns (bytes4);\n}\n\n// contracts/interfaces/IFastBridgeV2Errors.sol\n\ninterface IFastBridgeV2Errors {\n error AmountIncorrect();\n error CallParamsLengthAboveMax();\n error ChainIncorrect();\n error ExclusivityParamsIncorrect();\n error MsgValueIncorrect();\n error NativeTokenCallValueNotSupported();\n error SenderIncorrect();\n error StatusIncorrect();\n error ZeroAddress();\n\n error RecipientIncorrectReturnValue();\n error RecipientNoReturnValue();\n\n error DeadlineExceeded();\n error DeadlineNotExceeded();\n error DeadlineTooShort();\n error DisputePeriodNotPassed();\n error DisputePeriodPassed();\n error ExclusivityPeriodNotPassed();\n\n error TransactionRelayed();\n}\n\n// contracts/libs/Errors.sol\n\nerror DeadlineExceeded();\nerror DeadlineNotExceeded();\nerror DeadlineTooShort();\nerror InsufficientOutputAmount();\n\nerror MsgValueIncorrect();\nerror PoolNotFound();\nerror TokenAddressMismatch();\nerror TokenNotContract();\nerror TokenNotETH();\nerror TokensIdentical();\n\nerror ChainIncorrect();\nerror AmountIncorrect();\nerror ZeroAddress();\n\nerror DisputePeriodNotPassed();\nerror DisputePeriodPassed();\nerror SenderIncorrect();\nerror StatusIncorrect();\nerror TransactionIdIncorrect();\nerror TransactionRelayed();\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// contracts/interfaces/IFastBridgeV2.sol\n\ninterface IFastBridgeV2 is IFastBridge {\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n struct BridgeTxDetails {\n BridgeStatus status;\n uint40 proofBlockTimestamp;\n uint48 proofBlockNumber;\n address proofRelayer;\n }\n\n struct BridgeRelay {\n uint48 blockNumber;\n uint48 blockTimestamp;\n address relayer;\n }\n\n /// @notice New params introduced in the FastBridgeV2.\n /// We are passing fields from the older BridgeParams struct outside of this struct\n /// for backwards compatibility.\n /// Note: quoteRelayer and quoteExclusivitySeconds are either both zero (indicating no exclusivity)\n /// or both non-zero (indicating exclusivity for the given period).\n /// Note: callValue \u003e 0 can NOT be used with destToken = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE (ETH_ADDRESS)\n /// @param quoteRelayer Relayer that provided the quote for the transaction\n /// @param quoteExclusivitySeconds Period of time the quote relayer is guaranteed exclusivity after user's deposit\n /// @param quoteId Unique quote identifier used for tracking the quote\n /// @param callValue ETH value to send to the recipient (if any)\n /// @param callParams Parameters for the arbitrary call to the destination recipient (if any)\n struct BridgeParamsV2 {\n address quoteRelayer;\n int256 quoteExclusivitySeconds;\n bytes quoteId;\n uint256 callValue;\n bytes callParams;\n }\n\n /// @notice Updated bridge transaction struct to include parameters introduced in FastBridgeV2.\n /// Note: only `exclusivityRelayer` can fill such a transaction until `exclusivityEndTime`.\n /// TODO: consider changing the encoding scheme to prevent spending extra gas on decoding.\n struct BridgeTransactionV2 {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n uint256 callValue; // ETH value to send to the recipient (if any) - replaces V1's sendChainGas flag\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n address exclusivityRelayer;\n uint256 exclusivityEndTime;\n bytes callParams;\n }\n\n event BridgeQuoteDetails(bytes32 indexed transactionId, bytes quoteId);\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability\n /// to provide temporary exclusivity fill rights for the quote relayer.\n /// @param params The parameters required to bridge\n /// @param paramsV2 The parameters for exclusivity fill rights (optional, can be left empty)\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function relay(bytes memory request, address relayer) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param transactionId The transaction id associated with the encoded bridge transaction to prove\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital.\n /// @notice Can only send funds to the relayer address on the proof.\n /// @param request The encoded bridge transaction to claim on origin chain\n function claim(bytes memory request) external;\n /// @notice Checks if a transaction has been relayed\n /// @param transactionId The ID of the transaction to check\n /// @return True if the transaction has been relayed, false otherwise\n function bridgeRelays(bytes32 transactionId) external view returns (bool);\n\n /// @notice Returns the status of a bridge transaction\n /// @param transactionId The ID of the bridge transaction\n /// @return BridgeStatus Status of the bridge transaction\n function bridgeStatuses(bytes32 transactionId) external view returns (BridgeStatus);\n\n /// @notice Returns the timestamp and relayer of a bridge proof\n /// @param transactionId The ID of the bridge transaction\n /// @return timestamp The timestamp of the bridge proof\n /// @return relayer The relayer address of the bridge proof\n function bridgeProofs(bytes32 transactionId) external view returns (uint96 timestamp, address relayer);\n\n /// @notice Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\n /// @param request The bridge request to decode\n function getBridgeTransactionV2(bytes memory request) external view returns (BridgeTransactionV2 memory);\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// contracts/libs/UniversalToken.sol\n\nlibrary UniversalTokenLib {\n using SafeERC20 for IERC20;\n\n address internal constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Transfers tokens to the given account. Reverts if transfer is not successful.\n /// @dev This might trigger fallback, if ETH is transferred to the contract.\n /// Make sure this can not lead to reentrancy attacks.\n function universalTransfer(address token, address to, uint256 value) internal {\n // Don't do anything, if need to send tokens to this address\n if (to == address(this)) return;\n // Don't do anything, if trying to send zero value\n if (value == 0) return;\n if (token == ETH_ADDRESS) {\n /// @dev Note: this can potentially lead to executing code in `to`.\n // solhint-disable-next-line avoid-low-level-calls\n (bool success,) = to.call{value: value}(\"\");\n require(success, \"ETH transfer failed\");\n } else {\n IERC20(token).safeTransfer(to, value);\n }\n }\n\n /// @notice Issues an infinite allowance to the spender, if the current allowance is insufficient\n /// to spend the given amount.\n function universalApproveInfinity(address token, address spender, uint256 amountToSpend) internal {\n // ETH Chad doesn't require your approval\n if (token == ETH_ADDRESS) return;\n // No-op if allowance is already sufficient\n uint256 allowance = IERC20(token).allowance(address(this), spender);\n if (allowance \u003e= amountToSpend) return;\n // Otherwise, reset approval to 0 and set to max allowance\n if (allowance \u003e 0) IERC20(token).safeDecreaseAllowance(spender, allowance);\n IERC20(token).safeIncreaseAllowance(spender, type(uint256).max);\n }\n\n /// @notice Returns the balance of the given token (or native ETH) for the given account.\n function universalBalanceOf(address token, address account) internal view returns (uint256) {\n if (token == ETH_ADDRESS) {\n return account.balance;\n } else {\n return IERC20(token).balanceOf(account);\n }\n }\n\n /// @dev Checks that token is a contract and not ETH_ADDRESS.\n function assertIsContract(address token) internal view {\n // Check that ETH_ADDRESS was not used (in case this is a predeploy on any of the chains)\n if (token == UniversalTokenLib.ETH_ADDRESS) revert TokenNotContract();\n // Check that token is not an EOA\n if (token.code.length == 0) revert TokenNotContract();\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/Admin.sol\n\ncontract Admin is IAdmin, AccessControlEnumerable {\n using UniversalTokenLib for address;\n\n bytes32 public constant RELAYER_ROLE = keccak256(\"RELAYER_ROLE\");\n bytes32 public constant REFUNDER_ROLE = keccak256(\"REFUNDER_ROLE\");\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n uint256 public constant FEE_BPS = 1e6;\n uint256 public constant FEE_RATE_MAX = 0.01e6; // max 1% on origin amount\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Chain gas amount to forward as rebate if requested\n uint256 public chainGasAmount;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n }\n\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n require(newFeeRate \u003c= FEE_RATE_MAX, \"newFeeRate \u003e max\");\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n token.universalTransfer(recipient, feeAmount);\n emit FeesSwept(token, recipient, feeAmount);\n }\n\n function setChainGasAmount(uint256 newChainGasAmount) external onlyRole(GOVERNOR_ROLE) {\n uint256 oldChainGasAmount = chainGasAmount;\n chainGasAmount = newChainGasAmount;\n emit ChainGasAmountUpdated(oldChainGasAmount, newChainGasAmount);\n }\n}\n\n// contracts/FastBridgeV2.sol\n\n/// @notice FastBridgeV2 is a contract for bridging tokens across chains.\ncontract FastBridgeV2 is Admin, IFastBridgeV2, IFastBridgeV2Errors {\n using SafeERC20 for IERC20;\n using UniversalTokenLib for address;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Delay for a transaction after which it could be permisionlessly refunded\n uint256 public constant REFUND_DELAY = 7 days;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n /// @notice Maximum length of accepted callParams\n uint256 public constant MAX_CALL_PARAMS_LENGTH = 2 ** 16 - 1;\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeTxDetails) public bridgeTxDetails;\n /// @notice Relay details on destination chain\n mapping(bytes32 =\u003e BridgeRelay) public bridgeRelayDetails;\n /// @notice Unique bridge nonces tracked per originSender\n mapping(address =\u003e uint256) public senderNonces;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Replaced by senderNonces\n uint256 public immutable nonce = 0;\n /// @notice the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n bridge({\n params: params,\n paramsV2: BridgeParamsV2({\n quoteRelayer: address(0),\n quoteExclusivitySeconds: 0,\n quoteId: bytes(\"\"),\n callValue: 0,\n callParams: bytes(\"\")\n })\n });\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes memory request) external payable {\n relay({request: request, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes memory request, bytes32 destTxHash) external {\n prove({transactionId: keccak256(request), destTxHash: destTxHash, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridgeV2\n function claim(bytes memory request) external {\n claim({request: request, to: address(0)});\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003e DISPUTE_PERIOD) {\n revert DisputePeriodPassed();\n }\n\n // @dev relayer gets slashed effectively if dest relay has gone thru\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n bridgeTxDetails[transactionId].proofRelayer = address(0);\n bridgeTxDetails[transactionId].proofBlockTimestamp = 0;\n bridgeTxDetails[transactionId].proofBlockNumber = 0;\n\n emit BridgeProofDisputed(transactionId, msg.sender);\n }\n\n /// @inheritdoc IFastBridge\n function refund(bytes memory request) external {\n bytes32 transactionId = keccak256(request);\n\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n\n if (bridgeTxDetails[transactionId].status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n\n if (hasRole(REFUNDER_ROLE, msg.sender)) {\n // Refunder can refund if deadline has passed\n if (block.timestamp \u003c= transaction.deadline) revert DeadlineNotExceeded();\n } else {\n // Permissionless refund is allowed after REFUND_DELAY\n if (block.timestamp \u003c= transaction.deadline + REFUND_DELAY) revert DeadlineNotExceeded();\n }\n\n // if all checks passed, set to REFUNDED status\n bridgeTxDetails[transactionId].status = BridgeStatus.REFUNDED;\n\n // transfer origin collateral back to original sender\n address to = transaction.originSender;\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount + transaction.originFeeAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (bridgeTxDetails[transactionId].proofRelayer != relayer) revert SenderIncorrect();\n return _timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n /// @dev This method is added to achieve backwards compatibility with decoding requests into V1 structs:\n /// - `callValue` is partially reported as a zero/non-zero flag\n /// - `callParams` is ignored\n /// In order to process all kinds of requests use getBridgeTransactionV2 instead.\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory) {\n // Try decoding into V2 struct first. This will revert if V1 struct is passed\n try this.getBridgeTransactionV2(request) returns (BridgeTransactionV2 memory txV2) {\n // Note: we entirely ignore the callParams field, as it was not present in V1\n return BridgeTransaction({\n originChainId: txV2.originChainId,\n destChainId: txV2.destChainId,\n originSender: txV2.originSender,\n destRecipient: txV2.destRecipient,\n originToken: txV2.originToken,\n destToken: txV2.destToken,\n originAmount: txV2.originAmount,\n destAmount: txV2.destAmount,\n originFeeAmount: txV2.originFeeAmount,\n sendChainGas: txV2.callValue != 0,\n deadline: txV2.deadline,\n nonce: txV2.nonce\n });\n } catch {\n // Fallback to V1 struct\n return abi.decode(request, (BridgeTransaction));\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) public payable {\n int256 exclusivityEndTime = int256(block.timestamp) + paramsV2.quoteExclusivitySeconds;\n _validateBridgeParams(params, paramsV2, exclusivityEndTime);\n\n // transfer tokens to bridge contract\n /// @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _pullToken(params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n\n // set status to requested\n bytes memory request = abi.encode(\n BridgeTransactionV2({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n callValue: paramsV2.callValue,\n deadline: params.deadline,\n nonce: senderNonces[params.sender]++, // increment nonce on every bridge\n exclusivityRelayer: paramsV2.quoteRelayer,\n // We checked exclusivityEndTime to be in range (0 .. params.deadline] above, so can safely cast\n exclusivityEndTime: uint256(exclusivityEndTime),\n callParams: paramsV2.callParams\n })\n );\n bytes32 transactionId = keccak256(request);\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n\n emit BridgeRequested({\n transactionId: transactionId,\n sender: params.sender,\n request: request,\n destChainId: params.dstChainId,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n sendChainGas: paramsV2.callValue != 0\n });\n emit BridgeQuoteDetails(transactionId, paramsV2.quoteId);\n }\n\n /// @inheritdoc IFastBridgeV2\n function relay(bytes memory request, address relayer) public payable {\n bytes32 transactionId = keccak256(request);\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n _validateRelayParams(transaction, transactionId, relayer);\n // mark bridge transaction as relayed\n bridgeRelayDetails[transactionId] =\n BridgeRelay({blockNumber: uint48(block.number), blockTimestamp: uint48(block.timestamp), relayer: relayer});\n\n // transfer tokens to recipient on destination chain and do an arbitrary call if requested\n address to = transaction.destRecipient;\n address token = transaction.destToken;\n uint256 amount = transaction.destAmount;\n\n // All state changes have been done at this point, can proceed to the external calls.\n // This follows the checks-effects-interactions pattern to mitigate potential reentrancy attacks.\n if (token == UniversalTokenLib.ETH_ADDRESS) {\n // For ETH non-zero callValue is not allowed\n if (transaction.callValue != 0) revert NativeTokenCallValueNotSupported();\n // Check that the correct msg.value was sent\n if (msg.value != amount) revert MsgValueIncorrect();\n } else {\n // For ERC20s, we check that the correct msg.value was sent\n if (msg.value != transaction.callValue) revert MsgValueIncorrect();\n // We need to transfer the tokens from the Relayer to the recipient first before performing an\n // optional post-transfer arbitrary call.\n IERC20(token).safeTransferFrom(msg.sender, to, amount);\n }\n\n if (transaction.callParams.length != 0) {\n // Arbitrary call requested, perform it while supplying full msg.value to the recipient\n // Note: if token has a fee on transfers, the recipient will have received less than `amount`.\n // This is a very niche edge case and should be handled by the recipient contract.\n _checkedCallRecipient({recipient: to, token: token, amount: amount, callParams: transaction.callParams});\n } else if (msg.value != 0) {\n // No arbitrary call requested, but msg.value was sent. This is either a relay with ETH,\n // or a non-zero callValue request with an ERC20. In both cases, transfer the ETH to the recipient.\n Address.sendValue(payable(to), msg.value);\n }\n\n emit BridgeRelayed({\n transactionId: transactionId,\n relayer: relayer,\n to: to,\n originChainId: transaction.originChainId,\n originToken: transaction.originToken,\n destToken: transaction.destToken,\n originAmount: transaction.originAmount,\n destAmount: transaction.destAmount,\n chainGasAmount: transaction.callValue\n });\n }\n\n /// @inheritdoc IFastBridgeV2\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) public onlyRole(RELAYER_ROLE) {\n // update bridge tx status given proof provided\n if (bridgeTxDetails[transactionId].status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n bridgeTxDetails[transactionId].status = BridgeStatus.RELAYER_PROVED;\n bridgeTxDetails[transactionId].proofBlockTimestamp = uint40(block.timestamp);\n bridgeTxDetails[transactionId].proofBlockNumber = uint48(block.number);\n bridgeTxDetails[transactionId].proofRelayer = relayer;\n\n emit BridgeProofProvided(transactionId, relayer, destTxHash);\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes memory request, address to) public {\n bytes32 transactionId = keccak256(request);\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n\n // update bridge tx status if able to claim origin collateral\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n\n // if \"to\" is zero addr, permissionlessly send funds to proven relayer\n if (to == address(0)) {\n to = bridgeTxDetails[transactionId].proofRelayer;\n } else if (bridgeTxDetails[transactionId].proofRelayer != msg.sender) {\n revert SenderIncorrect();\n }\n\n if (_timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003c= DISPUTE_PERIOD) {\n revert DisputePeriodNotPassed();\n }\n\n bridgeTxDetails[transactionId].status = BridgeStatus.RELAYER_CLAIMED;\n\n // update protocol fees if origin fee amount exists\n if (transaction.originFeeAmount \u003e 0) protocolFees[transaction.originToken] += transaction.originFeeAmount;\n\n // transfer origin collateral less fee to specified address\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositClaimed(transactionId, bridgeTxDetails[transactionId].proofRelayer, to, token, amount);\n }\n\n function bridgeStatuses(bytes32 transactionId) public view returns (BridgeStatus status) {\n return bridgeTxDetails[transactionId].status;\n }\n\n function bridgeProofs(bytes32 transactionId) public view returns (uint96 timestamp, address relayer) {\n timestamp = bridgeTxDetails[transactionId].proofBlockTimestamp;\n relayer = bridgeTxDetails[transactionId].proofRelayer;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeRelays(bytes32 transactionId) public view returns (bool) {\n // has this transactionId been relayed?\n return bridgeRelayDetails[transactionId].relayer != address(0);\n }\n\n /// @inheritdoc IFastBridgeV2\n function getBridgeTransactionV2(bytes memory request) public pure returns (BridgeTransactionV2 memory) {\n return abi.decode(request, (BridgeTransactionV2));\n }\n\n /// @notice Pulls a requested token from the user to this contract.\n function _pullToken(address token, uint256 amount) internal returns (uint256 amountPulled) {\n if (token == UniversalTokenLib.ETH_ADDRESS) {\n // For ETH we just need to check that the supplied msg.value is correct\n if (amount != msg.value) revert MsgValueIncorrect();\n amountPulled = msg.value;\n } else {\n token.assertIsContract();\n // Record token balance before transfer\n amountPulled = IERC20(token).balanceOf(address(this));\n // Token needs to be pulled only if msg.value is zero\n // This way user can specify WETH as the origin asset\n IERC20(token).safeTransferFrom(msg.sender, address(this), amount);\n // Use the difference between the recorded balance and the current balance as the amountPulled\n amountPulled = IERC20(token).balanceOf(address(this)) - amountPulled;\n }\n }\n\n /// @notice Calls the Recipient's hook function with the specified callParams and performs\n /// all the necessary checks for the returned value.\n function _checkedCallRecipient(\n address recipient,\n address token,\n uint256 amount,\n bytes memory callParams\n )\n internal\n {\n bytes memory hookData =\n abi.encodeCall(IFastBridgeRecipient.fastBridgeTransferReceived, (token, amount, callParams));\n // This will bubble any revert messages from the hook function\n bytes memory returnData = Address.functionCallWithValue({target: recipient, data: hookData, value: msg.value});\n // Explicit revert if no return data at all\n if (returnData.length == 0) revert RecipientNoReturnValue();\n // Check that exactly a single return value was returned\n if (returnData.length != 32) revert RecipientIncorrectReturnValue();\n // Return value should be abi-encoded hook function selector\n if (bytes32(returnData) != bytes32(IFastBridgeRecipient.fastBridgeTransferReceived.selector)) {\n revert RecipientIncorrectReturnValue();\n }\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint40(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint40).max but\n /// proof.timestamp \u003c type(uint40).max via unchecked statement\n /// @param proofBlockTimestamp The bridge proof block timestamp\n /// @return delta Time delta since proof submitted\n function _timeSince(uint40 proofBlockTimestamp) internal view returns (uint256 delta) {\n unchecked {\n delta = uint40(block.timestamp) - proofBlockTimestamp;\n }\n }\n\n /// @notice Performs all the necessary checks for a bridge to happen.\n /// @dev There's no good way to refactor this function to reduce cyclomatic complexity due to\n /// the number of checks that need to be performed, so we skip the code-complexity rule here.\n // solhint-disable-next-line code-complexity\n function _validateBridgeParams(\n BridgeParams memory params,\n BridgeParamsV2 memory paramsV2,\n int256 exclusivityEndTime\n )\n internal\n view\n {\n // Check V1 (legacy) params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.sender == address(0) || params.to == address(0)) revert ZeroAddress();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n // Check V2 params\n if (paramsV2.callParams.length \u003e MAX_CALL_PARAMS_LENGTH) revert CallParamsLengthAboveMax();\n if (paramsV2.callValue != 0 \u0026\u0026 params.destToken == UniversalTokenLib.ETH_ADDRESS) {\n revert NativeTokenCallValueNotSupported();\n }\n // exclusivityEndTime must be in range (0 .. params.deadline]\n if (exclusivityEndTime \u003c= 0 || exclusivityEndTime \u003e int256(params.deadline)) {\n revert ExclusivityParamsIncorrect();\n }\n }\n\n /// @notice Performs all the necessary checks for a relay to happen.\n function _validateRelayParams(\n BridgeTransactionV2 memory transaction,\n bytes32 transactionId,\n address relayer\n )\n internal\n view\n {\n if (relayer == address(0)) revert ZeroAddress();\n // Check if the transaction has already been relayed\n if (bridgeRelays(transactionId)) revert TransactionRelayed();\n if (transaction.destChainId != uint32(block.chainid)) revert ChainIncorrect();\n // Check the deadline for relay to happen\n if (block.timestamp \u003e transaction.deadline) revert DeadlineExceeded();\n // Check the exclusivity period, if it is still ongoing\n // forgefmt: disable-next-item\n if (\n transaction.exclusivityRelayer != address(0) \u0026\u0026\n transaction.exclusivityRelayer != relayer \u0026\u0026\n block.timestamp \u003c= transaction.exclusivityEndTime\n ) {\n revert ExclusivityPeriodNotPassed();\n }\n }\n}\n","language":"Solidity","languageVersion":"0.8.24","compilerVersion":"0.8.24","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../","srcMap":"62810:1843:0:-:0;;;63637:83;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;63675:38;52847:4;63706:6;63675:10;:38::i;:::-;;63637:83;62810:1843;;62160:257;62246:4;;62277:31;62294:4;62300:7;62277:16;:31::i;:::-;62262:46;;62322:7;62318:69;;;62345:18;;;;:12;:18;;;;;:31;;62368:7;62345:22;:31::i;:::-;;62318:69;62403:7;-1:-1:-1;62160:257:0;;;;;:::o;56794:316::-;56871:4;53569:12;;;;;;;;;;;-1:-1:-1;;;;;53569:29:0;;;;;;;;;;;;56887:217;;56930:6;:12;;;;;;;;;;;-1:-1:-1;;;;;56930:29:0;;;;;;;;;:36;;-1:-1:-1;;56930:36:0;56962:4;56930:36;;;57012:12;23368:10;;23289:96;57012:12;-1:-1:-1;;;;;56985:40:0;57003:7;-1:-1:-1;;;;;56985:40:0;56997:4;56985:40;;;;;;;;;;-1:-1:-1;57046:4:0;57039:11;;56887:217;-1:-1:-1;57088:5:0;57081:12;;32813:150;32883:4;32906:50;32911:3;-1:-1:-1;;;;;32931:23:0;;26801:4;28857:21;;;:14;;;:21;;;;;;26817:321;;-1:-1:-1;26859:23:0;;;;;;;;:11;:23;;;;;;;;;;;;;27041:18;;27017:21;;;:14;;;:21;;;;;;:42;;;;27073:11;;14:290:1;84:6;137:2;125:9;116:7;112:23;108:32;105:52;;;153:1;150;143:12;105:52;179:16;;-1:-1:-1;;;;;224:31:1;;214:42;;204:70;;270:1;267;260:12;14:290;62810:1843:0;;;;;;","srcMapRuntime":"62810:1843:0:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;60820:212;;;;;;:::i;:::-;;:::i;:::-;;;516:14:1;;509:22;491:41;;479:2;464:18;60820:212:0;;;;;;;;63050:60;;63087:23;63050:60;;;;;689:25:1;;;677:2;662:18;63050:60:0;543:177:1;64022:359:0;;;;;;:::i;:::-;;:::i;:::-;;63232:45;;63271:6;63232:45;;54425:120;;;;;;:::i;:::-;54490:7;54516:12;;;;;;;;;;:22;;;;54425:120;54841:136;;;;;;:::i;:::-;;:::i;55943:245::-;;;;;;:::i;:::-;;:::i;63394:30::-;;;;;;62978:66;;63018:26;62978:66;;61617:142;;;;;;:::i;:::-;;:::i;:::-;;;2246:42:1;2234:55;;;2216:74;;2204:2;2189:18;61617:142:0;2070:226:1;53469:136:0;;;;;;:::i;:::-;53546:4;53569:12;;;;;;;;;;;:29;;;;;;;;;;;;;;;;53469:136;62908:64;;62947:25;62908:64;;52802:49;;52847:4;52802:49;;63726:290;;;;;;:::i;:::-;;:::i;64387:264::-;;;;;;:::i;:::-;;:::i;63189:37::-;;63223:3;63189:37;;61927:131;;;;;;:::i;:::-;;:::i;63116:66::-;;63156:26;63116:66;;55257:138;;;;;;:::i;:::-;;:::i;63480:47::-;;;;;;:::i;:::-;;;;;;;;;;;;;;63601:29;;;;;;60820:212;60905:4;60928:57;;;60943:42;60928:57;;:97;;;60989:36;61013:11;60989:23;:36::i;:::-;60921:104;60820:212;-1:-1:-1;;60820:212:0:o;64022:359::-;63156:26;53079:16;53090:4;53079:10;:16::i;:::-;64146:19:::1;::::0;::::1;64126:17;64146:19:::0;;;:12:::1;:19;::::0;;;;;;64179:14;;;64175:27:::1;;64195:7;64022:359:::0;;;:::o;64175:27::-:1;64243:19;::::0;::::1;64265:1;64243:19:::0;;;:12:::1;:19;::::0;;;;:23;64276:45:::1;::::0;64300:9;64311;64276:23:::1;:45::i;:::-;64336:38;::::0;;2889:42:1;2958:15;;;2940:34;;3010:15;;3005:2;2990:18;;2983:43;3042:18;;;3035:34;;;64336:38:0::1;::::0;2867:2:1;2852:18;64336:38:0::1;;;;;;;64116:265;53105:1;64022:359:::0;;;:::o;54841:136::-;54490:7;54516:12;;;;;;;;;;:22;;;53079:16;53090:4;53079:10;:16::i;:::-;54945:25:::1;54956:4;54962:7;54945:10;:25::i;:::-;;54841:136:::0;;;:::o;55943:245::-;56036:34;;;23368:10;56036:34;56032:102;;56093:30;;;;;;;;;;;;;;56032:102;56144:37;56156:4;56162:18;56144:11;:37::i;61617:142::-;61698:7;61724:18;;;:12;:18;;;;;:28;;61746:5;61724:21;:28::i;:::-;61717:35;61617:142;-1:-1:-1;;;61617:142:0:o;63726:290::-;63156:26;53079:16;53090:4;53079:10;:16::i;:::-;63271:6:::1;63825:10;:26;;63817:55;;;::::0;::::1;::::0;;3282:2:1;63817:55:0::1;::::0;::::1;3264:21:1::0;3321:2;3301:18;;;3294:30;3360:18;3340;;;3333:46;3396:18;;63817:55:0::1;;;;;;;;;63903:15;::::0;;63928:28;;;;63971:38:::1;::::0;;3599:25:1;;;3655:2;3640:18;;3633:34;;;63971:38:0::1;::::0;3572:18:1;63971:38:0::1;;;;;;;;63807:209;63726:290:::0;;:::o;64387:264::-;63156:26;53079:16;53090:4;53079:10;:16::i;:::-;64512:14:::1;::::0;;64536:34;;;;64585:59:::1;::::0;;3599:25:1;;;3655:2;3640:18;;3633:34;;;64585:59:0::1;::::0;3572:18:1;64585:59:0::1;3425:248:1::0;61927:131:0;61998:7;62024:18;;;:12;:18;;;;;:27;;:25;:27::i;55257:138::-;54490:7;54516:12;;;;;;;;;;:22;;;53079:16;53090:4;53079:10;:16::i;:::-;55362:26:::1;55374:4;55380:7;55362:11;:26::i;53180:202::-:0;53265:4;53288:47;;;53303:32;53288:47;;:87;;-1:-1:-1;45095:25:0;45080:40;;;;53339:36;44981:146;53814:103;53880:30;53891:4;23368:10;53880;:30::i;:::-;53814:103;:::o;58092:653::-;58267:4;58253:19;;;;58249:32;;58092:653;;;:::o;58249:32::-;58353:5;58362:1;58353:10;58349:23;;58092:653;;;:::o;58349:23::-;58385:20;;;;;58381:358;;58565:12;58582:2;:7;;58597:5;58582:25;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;58564:43;;;58629:7;58621:39;;;;;;;4090:2:1;58621:39:0;;;4072:21:1;4129:2;4109:18;;;4102:30;4168:21;4148:18;;;4141:49;4207:18;;58621:39:0;3888:343:1;58381:358:0;58691:37;:26;;;58718:2;58722:5;58691:26;:37::i;62160:257::-;62246:4;62262:12;62277:31;62294:4;62300:7;62277:16;:31::i;:::-;62262:46;;62322:7;62318:69;;;62345:18;;;;:12;:18;;;;;:31;;62368:7;62345:22;:31::i;:::-;;62403:7;62160:257;-1:-1:-1;;;62160:257:0:o;62520:262::-;62607:4;62623:12;62638:32;62656:4;62662:7;62638:17;:32::i;:::-;62623:47;;62684:7;62680:72;;;62707:18;;;;:12;:18;;;;;:34;;62733:7;62707:25;:34::i;34071:156::-;34145:7;34195:22;34199:3;34211:5;34195:3;:22::i;33614:115::-;33677:7;33703:19;33711:3;29053:18;;28971:107;54047:197;53546:4;53569:12;;;;;;;;;;;:29;;;;;;;;;;;;;54130:108;;54180:47;;;;;4440:42:1;4428:55;;54180:47:0;;;4410:74:1;4500:18;;;4493:34;;;4383:18;;54180:47:0;4236:297:1;54130:108:0;54047:197;;:::o;46297:160::-;46406:43;;;46421:14;4428:55:1;;46406:43:0;;;4410:74:1;4500:18;;;;4493:34;;;46406:43:0;;;;;;;;;;4383:18:1;;;;46406:43:0;;;;;;;;;;;;;;46379:71;;46399:5;;46379:19;:71::i;56794:316::-;56871:4;53569:12;;;;;;;;;;;:29;;;;;;;;;;;;;56887:217;;56930:6;:12;;;;;;;;;;;:29;;;;;;;;;;:36;;;;56962:4;56930:36;;;57012:12;23368:10;;23289:96;57012:12;56985:40;;57003:7;56985:40;;56997:4;56985:40;;;;;;;;;;-1:-1:-1;57046:4:0;57039:11;;56887:217;-1:-1:-1;57088:5:0;57081:12;;32813:150;32883:4;32906:50;32911:3;32931:23;;;32906:4;:50::i;57345:317::-;57423:4;53569:12;;;;;;;;;;;:29;;;;;;;;;;;;;57439:217;;;57513:5;57481:12;;;;;;;;;;;:29;;;;;;;;;;;:37;;;;;;57537:40;23368:10;;57481:12;;57537:40;;57513:5;57537:40;-1:-1:-1;57598:4:0;57591:11;;33131:156;33204:4;33227:53;33235:3;33255:23;;;33227:7;:53::i;29420:118::-;29487:7;29513:3;:11;;29525:5;29513:18;;;;;;;;:::i;:::-;;;;;;;;;29506:25;;29420:118;;;;:::o;49053:629::-;49472:23;49498:33;:27;;;49526:4;49498:27;:33::i;:::-;49472:59;;49545:10;:17;49566:1;49545:22;;:57;;;;;49583:10;49572:30;;;;;;;;;;;;:::i;:::-;49571:31;49545:57;49541:135;;;49625:40;;;;;2246:42:1;2234:55;;49625:40:0;;;2216:74:1;2189:18;;49625:40:0;2070:226:1;26738:406:0;26801:4;28857:21;;;:14;;;:21;;;;;;26817:321;;-1:-1:-1;26859:23:0;;;;;;;;:11;:23;;;;;;;;;;;;;27041:18;;27017:21;;;:14;;;:21;;;;;;:42;;;;27073:11;;27312:1368;27378:4;27507:21;;;:14;;;:21;;;;;;27543:13;;27539:1135;;27910:18;27931:12;27942:1;27931:8;:12;:::i;:::-;27977:18;;27910:33;;-1:-1:-1;27957:17:0;;27977:22;;27998:1;;27977:22;:::i;:::-;27957:42;;28032:9;28018:10;:23;28014:378;;28061:17;28081:3;:11;;28093:9;28081:22;;;;;;;;:::i;:::-;;;;;;;;;28061:42;;28228:9;28202:3;:11;;28214:10;28202:23;;;;;;;;:::i;:::-;;;;;;;;;;;;:35;;;;28341:25;;;:14;;;:25;;;;;:36;;;28014:378;28470:17;;:3;;:17;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;28573:3;:14;;:21;28588:5;28573:21;;;;;;;;;;;28566:28;;;28616:4;28609:11;;;;;;;27539:1135;28658:5;28651:12;;;;;19074:151;19149:12;19180:38;19202:6;19210:4;19216:1;19149:12;19790;19804:23;19831:6;:11;;19850:5;19857:4;19831:31;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;19789:73;;;;19879:55;19906:6;19914:7;19923:10;19879:26;:55::i;:::-;19872:62;19549:392;-1:-1:-1;;;;;;19549:392:0:o;20994:582::-;21138:12;21167:7;21162:408;;21190:19;21198:10;21190:7;:19::i;:::-;21162:408;;;21414:17;;:22;:49;;;;-1:-1:-1;21440:18:0;;;;:23;21414:49;21410:119;;;21490:24;;;;;2246:42:1;2234:55;;21490:24:0;;;2216:74:1;2189:18;;21490:24:0;2070:226:1;21410:119:0;-1:-1:-1;21549:10:0;21542:17;;22112:516;22243:17;;:21;22239:383;;22471:10;22465:17;22527:15;22514:10;22510:2;22506:19;22499:44;22239:383;22594:17;;;;;;;;;;;;;;14:332:1;72:6;125:2;113:9;104:7;100:23;96:32;93:52;;;141:1;138;131:12;93:52;180:9;167:23;230:66;223:5;219:78;212:5;209:89;199:117;;312:1;309;302:12;725:196;793:20;;853:42;842:54;;832:65;;822:93;;911:1;908;901:12;822:93;725:196;;;:::o;926:260::-;994:6;1002;1055:2;1043:9;1034:7;1030:23;1026:32;1023:52;;;1071:1;1068;1061:12;1023:52;1094:29;1113:9;1094:29;:::i;:::-;1084:39;;1142:38;1176:2;1165:9;1161:18;1142:38;:::i;:::-;1132:48;;926:260;;;;;:::o;1373:180::-;1432:6;1485:2;1473:9;1464:7;1460:23;1456:32;1453:52;;;1501:1;1498;1491:12;1453:52;-1:-1:-1;1524:23:1;;1373:180;-1:-1:-1;1373:180:1:o;1558:254::-;1626:6;1634;1687:2;1675:9;1666:7;1662:23;1658:32;1655:52;;;1703:1;1700;1693:12;1655:52;1739:9;1726:23;1716:33;;1768:38;1802:2;1791:9;1787:18;1768:38;:::i;1817:248::-;1885:6;1893;1946:2;1934:9;1925:7;1921:23;1917:32;1914:52;;;1962:1;1959;1952:12;1914:52;-1:-1:-1;;1985:23:1;;;2055:2;2040:18;;;2027:32;;-1:-1:-1;1817:248:1:o;2486:186::-;2545:6;2598:2;2586:9;2577:7;2573:23;2569:32;2566:52;;;2614:1;2611;2604:12;2566:52;2637:29;2656:9;2637:29;:::i;4840:184::-;4892:77;4889:1;4882:88;4989:4;4986:1;4979:15;5013:4;5010:1;5003:15;5029:277;5096:6;5149:2;5137:9;5128:7;5124:23;5120:32;5117:52;;;5165:1;5162;5155:12;5117:52;5197:9;5191:16;5250:5;5243:13;5236:21;5229:5;5226:32;5216:60;;5272:1;5269;5262:12;5311:282;5378:9;;;5399:11;;;5396:191;;;5443:77;5440:1;5433:88;5544:4;5541:1;5534:15;5572:4;5569:1;5562:15;5598:184;5650:77;5647:1;5640:88;5747:4;5744:1;5737:15;5771:4;5768:1;5761:15;5787:412;5916:3;5954:6;5948:13;5979:1;5989:129;6003:6;6000:1;5997:13;5989:129;;;6101:4;6085:14;;;6081:25;;6075:32;6062:11;;;6055:53;6018:12;5989:129;;;-1:-1:-1;6173:1:1;6137:16;;6162:13;;;-1:-1:-1;6137:16:1;5787:412;-1:-1:-1;5787:412:1:o","abiDefinition":[{"inputs":[{"internalType":"address","name":"_owner","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AccessControlBadConfirmation","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"bytes32","name":"neededRole","type":"bytes32"}],"name":"AccessControlUnauthorizedAccount","type":"error"},{"inputs":[{"internalType":"address","name":"target","type":"address"}],"name":"AddressEmptyCode","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"AddressInsufficientBalance","type":"error"},{"inputs":[],"name":"FailedInnerCall","type":"error"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"SafeERC20FailedOperation","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldChainGasAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newChainGasAmount","type":"uint256"}],"name":"ChainGasAmountUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldFeeRate","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newFeeRate","type":"uint256"}],"name":"FeeRateUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"address","name":"recipient","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"FeesSwept","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"previousAdminRole","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"newAdminRole","type":"bytes32"}],"name":"RoleAdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleRevoked","type":"event"},{"inputs":[],"name":"DEFAULT_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"FEE_BPS","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"FEE_RATE_MAX","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"GOVERNOR_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"GUARD_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"REFUNDER_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"RELAYER_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"chainGasAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleAdmin","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"uint256","name":"index","type":"uint256"}],"name":"getRoleMember","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleMemberCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"grantRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"hasRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"protocolFeeRate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"protocolFees","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"callerConfirmation","type":"address"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"revokeRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"newChainGasAmount","type":"uint256"}],"name":"setChainGasAmount","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"newFeeRate","type":"uint256"}],"name":"setProtocolFeeRate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"address","name":"recipient","type":"address"}],"name":"sweepProtocolFees","outputs":[],"stateMutability":"nonpayable","type":"function"}],"userDoc":{"kind":"user","methods":{"chainGasAmount()":{"notice":"Chain gas amount to forward as rebate if requested"},"protocolFeeRate()":{"notice":"Protocol fee rate taken on origin amount deposited in origin chain"},"protocolFees(address)":{"notice":"Protocol fee amounts accumulated"}},"version":1},"developerDoc":{"errors":{"AccessControlBadConfirmation()":[{"details":"The caller of a function is not the expected one. NOTE: Don't confuse with {AccessControlUnauthorizedAccount}."}],"AccessControlUnauthorizedAccount(address,bytes32)":[{"details":"The `account` is missing a role."}],"AddressEmptyCode(address)":[{"details":"There's no code at `target` (it is not a contract)."}],"AddressInsufficientBalance(address)":[{"details":"The ETH balance of the account is not enough to perform the operation."}],"FailedInnerCall()":[{"details":"A call to an address target failed. The target may have reverted."}],"SafeERC20FailedOperation(address)":[{"details":"An operation with an ERC20 token failed."}]},"events":{"RoleAdminChanged(bytes32,bytes32,bytes32)":{"details":"Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole` `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite {RoleAdminChanged} not being emitted signaling this."},"RoleGranted(bytes32,address,address)":{"details":"Emitted when `account` is granted `role`. `sender` is the account that originated the contract call, an admin role bearer except when using {AccessControl-_setupRole}."},"RoleRevoked(bytes32,address,address)":{"details":"Emitted when `account` is revoked `role`. `sender` is the account that originated the contract call: - if using `revokeRole`, it is the admin role bearer - if using `renounceRole`, it is the role bearer (i.e. `account`)"}},"kind":"dev","methods":{"getRoleAdmin(bytes32)":{"details":"Returns the admin role that controls `role`. See {grantRole} and {revokeRole}. To change a role's admin, use {_setRoleAdmin}."},"getRoleMember(bytes32,uint256)":{"details":"Returns one of the accounts that have `role`. `index` must be a value between 0 and {getRoleMemberCount}, non-inclusive. Role bearers are not sorted in any particular way, and their ordering may change at any point. WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure you perform all queries on the same block. See the following https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post] for more information."},"getRoleMemberCount(bytes32)":{"details":"Returns the number of accounts that have `role`. Can be used together with {getRoleMember} to enumerate all bearers of a role."},"grantRole(bytes32,address)":{"details":"Grants `role` to `account`. If `account` had not been already granted `role`, emits a {RoleGranted} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleGranted} event."},"hasRole(bytes32,address)":{"details":"Returns `true` if `account` has been granted `role`."},"renounceRole(bytes32,address)":{"details":"Revokes `role` from the calling account. Roles are often managed via {grantRole} and {revokeRole}: this function's purpose is to provide a mechanism for accounts to lose their privileges if they are compromised (such as when a trusted device is misplaced). If the calling account had been revoked `role`, emits a {RoleRevoked} event. Requirements: - the caller must be `callerConfirmation`. May emit a {RoleRevoked} event."},"revokeRole(bytes32,address)":{"details":"Revokes `role` from `account`. If `account` had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleRevoked} event."},"supportsInterface(bytes4)":{"details":"See {IERC165-supportsInterface}."}},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_owner\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"AccessControlBadConfirmation\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"neededRole\",\"type\":\"bytes32\"}],\"name\":\"AccessControlUnauthorizedAccount\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"}],\"name\":\"AddressEmptyCode\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"AddressInsufficientBalance\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"FailedInnerCall\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"}],\"name\":\"SafeERC20FailedOperation\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"oldChainGasAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newChainGasAmount\",\"type\":\"uint256\"}],\"name\":\"ChainGasAmountUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"oldFeeRate\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newFeeRate\",\"type\":\"uint256\"}],\"name\":\"FeeRateUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"FeesSwept\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"previousAdminRole\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"newAdminRole\",\"type\":\"bytes32\"}],\"name\":\"RoleAdminChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleGranted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleRevoked\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"DEFAULT_ADMIN_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"FEE_BPS\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"FEE_RATE_MAX\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"GOVERNOR_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"GUARD_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"REFUNDER_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"RELAYER_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"chainGasAmount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"}],\"name\":\"getRoleAdmin\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"index\",\"type\":\"uint256\"}],\"name\":\"getRoleMember\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"}],\"name\":\"getRoleMemberCount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"grantRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"hasRole\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"protocolFeeRate\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"protocolFees\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"callerConfirmation\",\"type\":\"address\"}],\"name\":\"renounceRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"revokeRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"newChainGasAmount\",\"type\":\"uint256\"}],\"name\":\"setChainGasAmount\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"newFeeRate\",\"type\":\"uint256\"}],\"name\":\"setProtocolFeeRate\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes4\",\"name\":\"interfaceId\",\"type\":\"bytes4\"}],\"name\":\"supportsInterface\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"}],\"name\":\"sweepProtocolFees\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"errors\":{\"AccessControlBadConfirmation()\":[{\"details\":\"The caller of a function is not the expected one. NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\"}],\"AccessControlUnauthorizedAccount(address,bytes32)\":[{\"details\":\"The `account` is missing a role.\"}],\"AddressEmptyCode(address)\":[{\"details\":\"There's no code at `target` (it is not a contract).\"}],\"AddressInsufficientBalance(address)\":[{\"details\":\"The ETH balance of the account is not enough to perform the operation.\"}],\"FailedInnerCall()\":[{\"details\":\"A call to an address target failed. The target may have reverted.\"}],\"SafeERC20FailedOperation(address)\":[{\"details\":\"An operation with an ERC20 token failed.\"}]},\"events\":{\"RoleAdminChanged(bytes32,bytes32,bytes32)\":{\"details\":\"Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole` `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite {RoleAdminChanged} not being emitted signaling this.\"},\"RoleGranted(bytes32,address,address)\":{\"details\":\"Emitted when `account` is granted `role`. `sender` is the account that originated the contract call, an admin role bearer except when using {AccessControl-_setupRole}.\"},\"RoleRevoked(bytes32,address,address)\":{\"details\":\"Emitted when `account` is revoked `role`. `sender` is the account that originated the contract call: - if using `revokeRole`, it is the admin role bearer - if using `renounceRole`, it is the role bearer (i.e. `account`)\"}},\"kind\":\"dev\",\"methods\":{\"getRoleAdmin(bytes32)\":{\"details\":\"Returns the admin role that controls `role`. See {grantRole} and {revokeRole}. To change a role's admin, use {_setRoleAdmin}.\"},\"getRoleMember(bytes32,uint256)\":{\"details\":\"Returns one of the accounts that have `role`. `index` must be a value between 0 and {getRoleMemberCount}, non-inclusive. Role bearers are not sorted in any particular way, and their ordering may change at any point. WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure you perform all queries on the same block. See the following https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post] for more information.\"},\"getRoleMemberCount(bytes32)\":{\"details\":\"Returns the number of accounts that have `role`. Can be used together with {getRoleMember} to enumerate all bearers of a role.\"},\"grantRole(bytes32,address)\":{\"details\":\"Grants `role` to `account`. If `account` had not been already granted `role`, emits a {RoleGranted} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleGranted} event.\"},\"hasRole(bytes32,address)\":{\"details\":\"Returns `true` if `account` has been granted `role`.\"},\"renounceRole(bytes32,address)\":{\"details\":\"Revokes `role` from the calling account. Roles are often managed via {grantRole} and {revokeRole}: this function's purpose is to provide a mechanism for accounts to lose their privileges if they are compromised (such as when a trusted device is misplaced). If the calling account had been revoked `role`, emits a {RoleRevoked} event. Requirements: - the caller must be `callerConfirmation`. May emit a {RoleRevoked} event.\"},\"revokeRole(bytes32,address)\":{\"details\":\"Revokes `role` from `account`. If `account` had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleRevoked} event.\"},\"supportsInterface(bytes4)\":{\"details\":\"See {IERC165-supportsInterface}.\"}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"chainGasAmount()\":{\"notice\":\"Chain gas amount to forward as rebate if requested\"},\"protocolFeeRate()\":{\"notice\":\"Protocol fee rate taken on origin amount deposited in origin chain\"},\"protocolFees(address)\":{\"notice\":\"Protocol fee amounts accumulated\"}},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeV2.sol\":\"Admin\"},\"evmVersion\":\"shanghai\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeV2.sol\":{\"keccak256\":\"0x7cd0f885e80e2bdaa638bc32ae7af7d2e248f99ce4b354c217d0f0f7d7302e0a\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://7ccf28df0bd7b4606986585acd8622ed9b4e81379690061bb66088f0a2270af1\",\"dweb:/ipfs/QmTf7HNdHZkK6vmx8ZgewycQEb72oLD9nPwBpsM5reMstQ\"]}},\"version\":1}"},"hashes":{"DEFAULT_ADMIN_ROLE()":"a217fddf","FEE_BPS()":"bf333f2c","FEE_RATE_MAX()":"0f5f6ed7","GOVERNOR_ROLE()":"ccc57490","GUARD_ROLE()":"03ed0ee5","REFUNDER_ROLE()":"5960ccf2","RELAYER_ROLE()":"926d7d7f","chainGasAmount()":"e00a83e0","getRoleAdmin(bytes32)":"248a9ca3","getRoleMember(bytes32,uint256)":"9010d07c","getRoleMemberCount(bytes32)":"ca15c873","grantRole(bytes32,address)":"2f2ff15d","hasRole(bytes32,address)":"91d14854","protocolFeeRate()":"58f85880","protocolFees(address)":"dcf844a7","renounceRole(bytes32,address)":"36568abe","revokeRole(bytes32,address)":"d547741f","setChainGasAmount(uint256)":"b250fe6b","setProtocolFeeRate(uint256)":"b13aa2d6","supportsInterface(bytes4)":"01ffc9a7","sweepProtocolFees(address,address)":"06f333f2"}},"solidity/FastBridgeV2.sol:Context":{"code":"0x","runtime-code":"0x","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.24 ^0.8.0 ^0.8.20;\n\n// contracts/interfaces/IAdmin.sol\n\ninterface IAdmin {\n // ============ Events ============\n\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n event ChainGasAmountUpdated(uint256 oldChainGasAmount, uint256 newChainGasAmount);\n\n // ============ Methods ============\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n\n function setChainGasAmount(uint256 newChainGasAmount) external;\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IFastBridgeRecipient.sol\n\ninterface IFastBridgeRecipient {\n function fastBridgeTransferReceived(\n address token,\n uint256 amount,\n bytes memory callParams\n )\n external\n payable\n returns (bytes4);\n}\n\n// contracts/interfaces/IFastBridgeV2Errors.sol\n\ninterface IFastBridgeV2Errors {\n error AmountIncorrect();\n error CallParamsLengthAboveMax();\n error ChainIncorrect();\n error ExclusivityParamsIncorrect();\n error MsgValueIncorrect();\n error NativeTokenCallValueNotSupported();\n error SenderIncorrect();\n error StatusIncorrect();\n error ZeroAddress();\n\n error RecipientIncorrectReturnValue();\n error RecipientNoReturnValue();\n\n error DeadlineExceeded();\n error DeadlineNotExceeded();\n error DeadlineTooShort();\n error DisputePeriodNotPassed();\n error DisputePeriodPassed();\n error ExclusivityPeriodNotPassed();\n\n error TransactionRelayed();\n}\n\n// contracts/libs/Errors.sol\n\nerror DeadlineExceeded();\nerror DeadlineNotExceeded();\nerror DeadlineTooShort();\nerror InsufficientOutputAmount();\n\nerror MsgValueIncorrect();\nerror PoolNotFound();\nerror TokenAddressMismatch();\nerror TokenNotContract();\nerror TokenNotETH();\nerror TokensIdentical();\n\nerror ChainIncorrect();\nerror AmountIncorrect();\nerror ZeroAddress();\n\nerror DisputePeriodNotPassed();\nerror DisputePeriodPassed();\nerror SenderIncorrect();\nerror StatusIncorrect();\nerror TransactionIdIncorrect();\nerror TransactionRelayed();\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// contracts/interfaces/IFastBridgeV2.sol\n\ninterface IFastBridgeV2 is IFastBridge {\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n struct BridgeTxDetails {\n BridgeStatus status;\n uint40 proofBlockTimestamp;\n uint48 proofBlockNumber;\n address proofRelayer;\n }\n\n struct BridgeRelay {\n uint48 blockNumber;\n uint48 blockTimestamp;\n address relayer;\n }\n\n /// @notice New params introduced in the FastBridgeV2.\n /// We are passing fields from the older BridgeParams struct outside of this struct\n /// for backwards compatibility.\n /// Note: quoteRelayer and quoteExclusivitySeconds are either both zero (indicating no exclusivity)\n /// or both non-zero (indicating exclusivity for the given period).\n /// Note: callValue \u003e 0 can NOT be used with destToken = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE (ETH_ADDRESS)\n /// @param quoteRelayer Relayer that provided the quote for the transaction\n /// @param quoteExclusivitySeconds Period of time the quote relayer is guaranteed exclusivity after user's deposit\n /// @param quoteId Unique quote identifier used for tracking the quote\n /// @param callValue ETH value to send to the recipient (if any)\n /// @param callParams Parameters for the arbitrary call to the destination recipient (if any)\n struct BridgeParamsV2 {\n address quoteRelayer;\n int256 quoteExclusivitySeconds;\n bytes quoteId;\n uint256 callValue;\n bytes callParams;\n }\n\n /// @notice Updated bridge transaction struct to include parameters introduced in FastBridgeV2.\n /// Note: only `exclusivityRelayer` can fill such a transaction until `exclusivityEndTime`.\n /// TODO: consider changing the encoding scheme to prevent spending extra gas on decoding.\n struct BridgeTransactionV2 {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n uint256 callValue; // ETH value to send to the recipient (if any) - replaces V1's sendChainGas flag\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n address exclusivityRelayer;\n uint256 exclusivityEndTime;\n bytes callParams;\n }\n\n event BridgeQuoteDetails(bytes32 indexed transactionId, bytes quoteId);\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability\n /// to provide temporary exclusivity fill rights for the quote relayer.\n /// @param params The parameters required to bridge\n /// @param paramsV2 The parameters for exclusivity fill rights (optional, can be left empty)\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function relay(bytes memory request, address relayer) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param transactionId The transaction id associated with the encoded bridge transaction to prove\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital.\n /// @notice Can only send funds to the relayer address on the proof.\n /// @param request The encoded bridge transaction to claim on origin chain\n function claim(bytes memory request) external;\n /// @notice Checks if a transaction has been relayed\n /// @param transactionId The ID of the transaction to check\n /// @return True if the transaction has been relayed, false otherwise\n function bridgeRelays(bytes32 transactionId) external view returns (bool);\n\n /// @notice Returns the status of a bridge transaction\n /// @param transactionId The ID of the bridge transaction\n /// @return BridgeStatus Status of the bridge transaction\n function bridgeStatuses(bytes32 transactionId) external view returns (BridgeStatus);\n\n /// @notice Returns the timestamp and relayer of a bridge proof\n /// @param transactionId The ID of the bridge transaction\n /// @return timestamp The timestamp of the bridge proof\n /// @return relayer The relayer address of the bridge proof\n function bridgeProofs(bytes32 transactionId) external view returns (uint96 timestamp, address relayer);\n\n /// @notice Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\n /// @param request The bridge request to decode\n function getBridgeTransactionV2(bytes memory request) external view returns (BridgeTransactionV2 memory);\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// contracts/libs/UniversalToken.sol\n\nlibrary UniversalTokenLib {\n using SafeERC20 for IERC20;\n\n address internal constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Transfers tokens to the given account. Reverts if transfer is not successful.\n /// @dev This might trigger fallback, if ETH is transferred to the contract.\n /// Make sure this can not lead to reentrancy attacks.\n function universalTransfer(address token, address to, uint256 value) internal {\n // Don't do anything, if need to send tokens to this address\n if (to == address(this)) return;\n // Don't do anything, if trying to send zero value\n if (value == 0) return;\n if (token == ETH_ADDRESS) {\n /// @dev Note: this can potentially lead to executing code in `to`.\n // solhint-disable-next-line avoid-low-level-calls\n (bool success,) = to.call{value: value}(\"\");\n require(success, \"ETH transfer failed\");\n } else {\n IERC20(token).safeTransfer(to, value);\n }\n }\n\n /// @notice Issues an infinite allowance to the spender, if the current allowance is insufficient\n /// to spend the given amount.\n function universalApproveInfinity(address token, address spender, uint256 amountToSpend) internal {\n // ETH Chad doesn't require your approval\n if (token == ETH_ADDRESS) return;\n // No-op if allowance is already sufficient\n uint256 allowance = IERC20(token).allowance(address(this), spender);\n if (allowance \u003e= amountToSpend) return;\n // Otherwise, reset approval to 0 and set to max allowance\n if (allowance \u003e 0) IERC20(token).safeDecreaseAllowance(spender, allowance);\n IERC20(token).safeIncreaseAllowance(spender, type(uint256).max);\n }\n\n /// @notice Returns the balance of the given token (or native ETH) for the given account.\n function universalBalanceOf(address token, address account) internal view returns (uint256) {\n if (token == ETH_ADDRESS) {\n return account.balance;\n } else {\n return IERC20(token).balanceOf(account);\n }\n }\n\n /// @dev Checks that token is a contract and not ETH_ADDRESS.\n function assertIsContract(address token) internal view {\n // Check that ETH_ADDRESS was not used (in case this is a predeploy on any of the chains)\n if (token == UniversalTokenLib.ETH_ADDRESS) revert TokenNotContract();\n // Check that token is not an EOA\n if (token.code.length == 0) revert TokenNotContract();\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/Admin.sol\n\ncontract Admin is IAdmin, AccessControlEnumerable {\n using UniversalTokenLib for address;\n\n bytes32 public constant RELAYER_ROLE = keccak256(\"RELAYER_ROLE\");\n bytes32 public constant REFUNDER_ROLE = keccak256(\"REFUNDER_ROLE\");\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n uint256 public constant FEE_BPS = 1e6;\n uint256 public constant FEE_RATE_MAX = 0.01e6; // max 1% on origin amount\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Chain gas amount to forward as rebate if requested\n uint256 public chainGasAmount;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n }\n\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n require(newFeeRate \u003c= FEE_RATE_MAX, \"newFeeRate \u003e max\");\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n token.universalTransfer(recipient, feeAmount);\n emit FeesSwept(token, recipient, feeAmount);\n }\n\n function setChainGasAmount(uint256 newChainGasAmount) external onlyRole(GOVERNOR_ROLE) {\n uint256 oldChainGasAmount = chainGasAmount;\n chainGasAmount = newChainGasAmount;\n emit ChainGasAmountUpdated(oldChainGasAmount, newChainGasAmount);\n }\n}\n\n// contracts/FastBridgeV2.sol\n\n/// @notice FastBridgeV2 is a contract for bridging tokens across chains.\ncontract FastBridgeV2 is Admin, IFastBridgeV2, IFastBridgeV2Errors {\n using SafeERC20 for IERC20;\n using UniversalTokenLib for address;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Delay for a transaction after which it could be permisionlessly refunded\n uint256 public constant REFUND_DELAY = 7 days;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n /// @notice Maximum length of accepted callParams\n uint256 public constant MAX_CALL_PARAMS_LENGTH = 2 ** 16 - 1;\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeTxDetails) public bridgeTxDetails;\n /// @notice Relay details on destination chain\n mapping(bytes32 =\u003e BridgeRelay) public bridgeRelayDetails;\n /// @notice Unique bridge nonces tracked per originSender\n mapping(address =\u003e uint256) public senderNonces;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Replaced by senderNonces\n uint256 public immutable nonce = 0;\n /// @notice the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n bridge({\n params: params,\n paramsV2: BridgeParamsV2({\n quoteRelayer: address(0),\n quoteExclusivitySeconds: 0,\n quoteId: bytes(\"\"),\n callValue: 0,\n callParams: bytes(\"\")\n })\n });\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes memory request) external payable {\n relay({request: request, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes memory request, bytes32 destTxHash) external {\n prove({transactionId: keccak256(request), destTxHash: destTxHash, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridgeV2\n function claim(bytes memory request) external {\n claim({request: request, to: address(0)});\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003e DISPUTE_PERIOD) {\n revert DisputePeriodPassed();\n }\n\n // @dev relayer gets slashed effectively if dest relay has gone thru\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n bridgeTxDetails[transactionId].proofRelayer = address(0);\n bridgeTxDetails[transactionId].proofBlockTimestamp = 0;\n bridgeTxDetails[transactionId].proofBlockNumber = 0;\n\n emit BridgeProofDisputed(transactionId, msg.sender);\n }\n\n /// @inheritdoc IFastBridge\n function refund(bytes memory request) external {\n bytes32 transactionId = keccak256(request);\n\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n\n if (bridgeTxDetails[transactionId].status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n\n if (hasRole(REFUNDER_ROLE, msg.sender)) {\n // Refunder can refund if deadline has passed\n if (block.timestamp \u003c= transaction.deadline) revert DeadlineNotExceeded();\n } else {\n // Permissionless refund is allowed after REFUND_DELAY\n if (block.timestamp \u003c= transaction.deadline + REFUND_DELAY) revert DeadlineNotExceeded();\n }\n\n // if all checks passed, set to REFUNDED status\n bridgeTxDetails[transactionId].status = BridgeStatus.REFUNDED;\n\n // transfer origin collateral back to original sender\n address to = transaction.originSender;\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount + transaction.originFeeAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (bridgeTxDetails[transactionId].proofRelayer != relayer) revert SenderIncorrect();\n return _timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n /// @dev This method is added to achieve backwards compatibility with decoding requests into V1 structs:\n /// - `callValue` is partially reported as a zero/non-zero flag\n /// - `callParams` is ignored\n /// In order to process all kinds of requests use getBridgeTransactionV2 instead.\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory) {\n // Try decoding into V2 struct first. This will revert if V1 struct is passed\n try this.getBridgeTransactionV2(request) returns (BridgeTransactionV2 memory txV2) {\n // Note: we entirely ignore the callParams field, as it was not present in V1\n return BridgeTransaction({\n originChainId: txV2.originChainId,\n destChainId: txV2.destChainId,\n originSender: txV2.originSender,\n destRecipient: txV2.destRecipient,\n originToken: txV2.originToken,\n destToken: txV2.destToken,\n originAmount: txV2.originAmount,\n destAmount: txV2.destAmount,\n originFeeAmount: txV2.originFeeAmount,\n sendChainGas: txV2.callValue != 0,\n deadline: txV2.deadline,\n nonce: txV2.nonce\n });\n } catch {\n // Fallback to V1 struct\n return abi.decode(request, (BridgeTransaction));\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) public payable {\n int256 exclusivityEndTime = int256(block.timestamp) + paramsV2.quoteExclusivitySeconds;\n _validateBridgeParams(params, paramsV2, exclusivityEndTime);\n\n // transfer tokens to bridge contract\n /// @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _pullToken(params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n\n // set status to requested\n bytes memory request = abi.encode(\n BridgeTransactionV2({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n callValue: paramsV2.callValue,\n deadline: params.deadline,\n nonce: senderNonces[params.sender]++, // increment nonce on every bridge\n exclusivityRelayer: paramsV2.quoteRelayer,\n // We checked exclusivityEndTime to be in range (0 .. params.deadline] above, so can safely cast\n exclusivityEndTime: uint256(exclusivityEndTime),\n callParams: paramsV2.callParams\n })\n );\n bytes32 transactionId = keccak256(request);\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n\n emit BridgeRequested({\n transactionId: transactionId,\n sender: params.sender,\n request: request,\n destChainId: params.dstChainId,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n sendChainGas: paramsV2.callValue != 0\n });\n emit BridgeQuoteDetails(transactionId, paramsV2.quoteId);\n }\n\n /// @inheritdoc IFastBridgeV2\n function relay(bytes memory request, address relayer) public payable {\n bytes32 transactionId = keccak256(request);\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n _validateRelayParams(transaction, transactionId, relayer);\n // mark bridge transaction as relayed\n bridgeRelayDetails[transactionId] =\n BridgeRelay({blockNumber: uint48(block.number), blockTimestamp: uint48(block.timestamp), relayer: relayer});\n\n // transfer tokens to recipient on destination chain and do an arbitrary call if requested\n address to = transaction.destRecipient;\n address token = transaction.destToken;\n uint256 amount = transaction.destAmount;\n\n // All state changes have been done at this point, can proceed to the external calls.\n // This follows the checks-effects-interactions pattern to mitigate potential reentrancy attacks.\n if (token == UniversalTokenLib.ETH_ADDRESS) {\n // For ETH non-zero callValue is not allowed\n if (transaction.callValue != 0) revert NativeTokenCallValueNotSupported();\n // Check that the correct msg.value was sent\n if (msg.value != amount) revert MsgValueIncorrect();\n } else {\n // For ERC20s, we check that the correct msg.value was sent\n if (msg.value != transaction.callValue) revert MsgValueIncorrect();\n // We need to transfer the tokens from the Relayer to the recipient first before performing an\n // optional post-transfer arbitrary call.\n IERC20(token).safeTransferFrom(msg.sender, to, amount);\n }\n\n if (transaction.callParams.length != 0) {\n // Arbitrary call requested, perform it while supplying full msg.value to the recipient\n // Note: if token has a fee on transfers, the recipient will have received less than `amount`.\n // This is a very niche edge case and should be handled by the recipient contract.\n _checkedCallRecipient({recipient: to, token: token, amount: amount, callParams: transaction.callParams});\n } else if (msg.value != 0) {\n // No arbitrary call requested, but msg.value was sent. This is either a relay with ETH,\n // or a non-zero callValue request with an ERC20. In both cases, transfer the ETH to the recipient.\n Address.sendValue(payable(to), msg.value);\n }\n\n emit BridgeRelayed({\n transactionId: transactionId,\n relayer: relayer,\n to: to,\n originChainId: transaction.originChainId,\n originToken: transaction.originToken,\n destToken: transaction.destToken,\n originAmount: transaction.originAmount,\n destAmount: transaction.destAmount,\n chainGasAmount: transaction.callValue\n });\n }\n\n /// @inheritdoc IFastBridgeV2\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) public onlyRole(RELAYER_ROLE) {\n // update bridge tx status given proof provided\n if (bridgeTxDetails[transactionId].status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n bridgeTxDetails[transactionId].status = BridgeStatus.RELAYER_PROVED;\n bridgeTxDetails[transactionId].proofBlockTimestamp = uint40(block.timestamp);\n bridgeTxDetails[transactionId].proofBlockNumber = uint48(block.number);\n bridgeTxDetails[transactionId].proofRelayer = relayer;\n\n emit BridgeProofProvided(transactionId, relayer, destTxHash);\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes memory request, address to) public {\n bytes32 transactionId = keccak256(request);\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n\n // update bridge tx status if able to claim origin collateral\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n\n // if \"to\" is zero addr, permissionlessly send funds to proven relayer\n if (to == address(0)) {\n to = bridgeTxDetails[transactionId].proofRelayer;\n } else if (bridgeTxDetails[transactionId].proofRelayer != msg.sender) {\n revert SenderIncorrect();\n }\n\n if (_timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003c= DISPUTE_PERIOD) {\n revert DisputePeriodNotPassed();\n }\n\n bridgeTxDetails[transactionId].status = BridgeStatus.RELAYER_CLAIMED;\n\n // update protocol fees if origin fee amount exists\n if (transaction.originFeeAmount \u003e 0) protocolFees[transaction.originToken] += transaction.originFeeAmount;\n\n // transfer origin collateral less fee to specified address\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositClaimed(transactionId, bridgeTxDetails[transactionId].proofRelayer, to, token, amount);\n }\n\n function bridgeStatuses(bytes32 transactionId) public view returns (BridgeStatus status) {\n return bridgeTxDetails[transactionId].status;\n }\n\n function bridgeProofs(bytes32 transactionId) public view returns (uint96 timestamp, address relayer) {\n timestamp = bridgeTxDetails[transactionId].proofBlockTimestamp;\n relayer = bridgeTxDetails[transactionId].proofRelayer;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeRelays(bytes32 transactionId) public view returns (bool) {\n // has this transactionId been relayed?\n return bridgeRelayDetails[transactionId].relayer != address(0);\n }\n\n /// @inheritdoc IFastBridgeV2\n function getBridgeTransactionV2(bytes memory request) public pure returns (BridgeTransactionV2 memory) {\n return abi.decode(request, (BridgeTransactionV2));\n }\n\n /// @notice Pulls a requested token from the user to this contract.\n function _pullToken(address token, uint256 amount) internal returns (uint256 amountPulled) {\n if (token == UniversalTokenLib.ETH_ADDRESS) {\n // For ETH we just need to check that the supplied msg.value is correct\n if (amount != msg.value) revert MsgValueIncorrect();\n amountPulled = msg.value;\n } else {\n token.assertIsContract();\n // Record token balance before transfer\n amountPulled = IERC20(token).balanceOf(address(this));\n // Token needs to be pulled only if msg.value is zero\n // This way user can specify WETH as the origin asset\n IERC20(token).safeTransferFrom(msg.sender, address(this), amount);\n // Use the difference between the recorded balance and the current balance as the amountPulled\n amountPulled = IERC20(token).balanceOf(address(this)) - amountPulled;\n }\n }\n\n /// @notice Calls the Recipient's hook function with the specified callParams and performs\n /// all the necessary checks for the returned value.\n function _checkedCallRecipient(\n address recipient,\n address token,\n uint256 amount,\n bytes memory callParams\n )\n internal\n {\n bytes memory hookData =\n abi.encodeCall(IFastBridgeRecipient.fastBridgeTransferReceived, (token, amount, callParams));\n // This will bubble any revert messages from the hook function\n bytes memory returnData = Address.functionCallWithValue({target: recipient, data: hookData, value: msg.value});\n // Explicit revert if no return data at all\n if (returnData.length == 0) revert RecipientNoReturnValue();\n // Check that exactly a single return value was returned\n if (returnData.length != 32) revert RecipientIncorrectReturnValue();\n // Return value should be abi-encoded hook function selector\n if (bytes32(returnData) != bytes32(IFastBridgeRecipient.fastBridgeTransferReceived.selector)) {\n revert RecipientIncorrectReturnValue();\n }\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint40(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint40).max but\n /// proof.timestamp \u003c type(uint40).max via unchecked statement\n /// @param proofBlockTimestamp The bridge proof block timestamp\n /// @return delta Time delta since proof submitted\n function _timeSince(uint40 proofBlockTimestamp) internal view returns (uint256 delta) {\n unchecked {\n delta = uint40(block.timestamp) - proofBlockTimestamp;\n }\n }\n\n /// @notice Performs all the necessary checks for a bridge to happen.\n /// @dev There's no good way to refactor this function to reduce cyclomatic complexity due to\n /// the number of checks that need to be performed, so we skip the code-complexity rule here.\n // solhint-disable-next-line code-complexity\n function _validateBridgeParams(\n BridgeParams memory params,\n BridgeParamsV2 memory paramsV2,\n int256 exclusivityEndTime\n )\n internal\n view\n {\n // Check V1 (legacy) params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.sender == address(0) || params.to == address(0)) revert ZeroAddress();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n // Check V2 params\n if (paramsV2.callParams.length \u003e MAX_CALL_PARAMS_LENGTH) revert CallParamsLengthAboveMax();\n if (paramsV2.callValue != 0 \u0026\u0026 params.destToken == UniversalTokenLib.ETH_ADDRESS) {\n revert NativeTokenCallValueNotSupported();\n }\n // exclusivityEndTime must be in range (0 .. params.deadline]\n if (exclusivityEndTime \u003c= 0 || exclusivityEndTime \u003e int256(params.deadline)) {\n revert ExclusivityParamsIncorrect();\n }\n }\n\n /// @notice Performs all the necessary checks for a relay to happen.\n function _validateRelayParams(\n BridgeTransactionV2 memory transaction,\n bytes32 transactionId,\n address relayer\n )\n internal\n view\n {\n if (relayer == address(0)) revert ZeroAddress();\n // Check if the transaction has already been relayed\n if (bridgeRelays(transactionId)) revert TransactionRelayed();\n if (transaction.destChainId != uint32(block.chainid)) revert ChainIncorrect();\n // Check the deadline for relay to happen\n if (block.timestamp \u003e transaction.deadline) revert DeadlineExceeded();\n // Check the exclusivity period, if it is still ongoing\n // forgefmt: disable-next-item\n if (\n transaction.exclusivityRelayer != address(0) \u0026\u0026\n transaction.exclusivityRelayer != relayer \u0026\u0026\n block.timestamp \u003c= transaction.exclusivityEndTime\n ) {\n revert ExclusivityPeriodNotPassed();\n }\n }\n}\n","language":"Solidity","languageVersion":"0.8.24","compilerVersion":"0.8.24","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../","srcMap":"","srcMapRuntime":"","abiDefinition":[],"userDoc":{"kind":"user","methods":{},"version":1},"developerDoc":{"details":"Provides information about the current execution context, including the sender of the transaction and its data. While these are generally available via msg.sender and msg.data, they should not be accessed in such a direct manner, since when dealing with meta-transactions the account sending and paying for execution may not be the actual sender (as far as an application is concerned). This contract is only required for intermediate, library-like contracts.","kind":"dev","methods":{},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[],\"devdoc\":{\"details\":\"Provides information about the current execution context, including the sender of the transaction and its data. While these are generally available via msg.sender and msg.data, they should not be accessed in such a direct manner, since when dealing with meta-transactions the account sending and paying for execution may not be the actual sender (as far as an application is concerned). This contract is only required for intermediate, library-like contracts.\",\"kind\":\"dev\",\"methods\":{},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeV2.sol\":\"Context\"},\"evmVersion\":\"shanghai\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeV2.sol\":{\"keccak256\":\"0x7cd0f885e80e2bdaa638bc32ae7af7d2e248f99ce4b354c217d0f0f7d7302e0a\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://7ccf28df0bd7b4606986585acd8622ed9b4e81379690061bb66088f0a2270af1\",\"dweb:/ipfs/QmTf7HNdHZkK6vmx8ZgewycQEb72oLD9nPwBpsM5reMstQ\"]}},\"version\":1}"},"hashes":{}},"solidity/FastBridgeV2.sol:ERC165":{"code":"0x","runtime-code":"0x","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.24 ^0.8.0 ^0.8.20;\n\n// contracts/interfaces/IAdmin.sol\n\ninterface IAdmin {\n // ============ Events ============\n\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n event ChainGasAmountUpdated(uint256 oldChainGasAmount, uint256 newChainGasAmount);\n\n // ============ Methods ============\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n\n function setChainGasAmount(uint256 newChainGasAmount) external;\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IFastBridgeRecipient.sol\n\ninterface IFastBridgeRecipient {\n function fastBridgeTransferReceived(\n address token,\n uint256 amount,\n bytes memory callParams\n )\n external\n payable\n returns (bytes4);\n}\n\n// contracts/interfaces/IFastBridgeV2Errors.sol\n\ninterface IFastBridgeV2Errors {\n error AmountIncorrect();\n error CallParamsLengthAboveMax();\n error ChainIncorrect();\n error ExclusivityParamsIncorrect();\n error MsgValueIncorrect();\n error NativeTokenCallValueNotSupported();\n error SenderIncorrect();\n error StatusIncorrect();\n error ZeroAddress();\n\n error RecipientIncorrectReturnValue();\n error RecipientNoReturnValue();\n\n error DeadlineExceeded();\n error DeadlineNotExceeded();\n error DeadlineTooShort();\n error DisputePeriodNotPassed();\n error DisputePeriodPassed();\n error ExclusivityPeriodNotPassed();\n\n error TransactionRelayed();\n}\n\n// contracts/libs/Errors.sol\n\nerror DeadlineExceeded();\nerror DeadlineNotExceeded();\nerror DeadlineTooShort();\nerror InsufficientOutputAmount();\n\nerror MsgValueIncorrect();\nerror PoolNotFound();\nerror TokenAddressMismatch();\nerror TokenNotContract();\nerror TokenNotETH();\nerror TokensIdentical();\n\nerror ChainIncorrect();\nerror AmountIncorrect();\nerror ZeroAddress();\n\nerror DisputePeriodNotPassed();\nerror DisputePeriodPassed();\nerror SenderIncorrect();\nerror StatusIncorrect();\nerror TransactionIdIncorrect();\nerror TransactionRelayed();\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// contracts/interfaces/IFastBridgeV2.sol\n\ninterface IFastBridgeV2 is IFastBridge {\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n struct BridgeTxDetails {\n BridgeStatus status;\n uint40 proofBlockTimestamp;\n uint48 proofBlockNumber;\n address proofRelayer;\n }\n\n struct BridgeRelay {\n uint48 blockNumber;\n uint48 blockTimestamp;\n address relayer;\n }\n\n /// @notice New params introduced in the FastBridgeV2.\n /// We are passing fields from the older BridgeParams struct outside of this struct\n /// for backwards compatibility.\n /// Note: quoteRelayer and quoteExclusivitySeconds are either both zero (indicating no exclusivity)\n /// or both non-zero (indicating exclusivity for the given period).\n /// Note: callValue \u003e 0 can NOT be used with destToken = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE (ETH_ADDRESS)\n /// @param quoteRelayer Relayer that provided the quote for the transaction\n /// @param quoteExclusivitySeconds Period of time the quote relayer is guaranteed exclusivity after user's deposit\n /// @param quoteId Unique quote identifier used for tracking the quote\n /// @param callValue ETH value to send to the recipient (if any)\n /// @param callParams Parameters for the arbitrary call to the destination recipient (if any)\n struct BridgeParamsV2 {\n address quoteRelayer;\n int256 quoteExclusivitySeconds;\n bytes quoteId;\n uint256 callValue;\n bytes callParams;\n }\n\n /// @notice Updated bridge transaction struct to include parameters introduced in FastBridgeV2.\n /// Note: only `exclusivityRelayer` can fill such a transaction until `exclusivityEndTime`.\n /// TODO: consider changing the encoding scheme to prevent spending extra gas on decoding.\n struct BridgeTransactionV2 {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n uint256 callValue; // ETH value to send to the recipient (if any) - replaces V1's sendChainGas flag\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n address exclusivityRelayer;\n uint256 exclusivityEndTime;\n bytes callParams;\n }\n\n event BridgeQuoteDetails(bytes32 indexed transactionId, bytes quoteId);\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability\n /// to provide temporary exclusivity fill rights for the quote relayer.\n /// @param params The parameters required to bridge\n /// @param paramsV2 The parameters for exclusivity fill rights (optional, can be left empty)\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function relay(bytes memory request, address relayer) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param transactionId The transaction id associated with the encoded bridge transaction to prove\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital.\n /// @notice Can only send funds to the relayer address on the proof.\n /// @param request The encoded bridge transaction to claim on origin chain\n function claim(bytes memory request) external;\n /// @notice Checks if a transaction has been relayed\n /// @param transactionId The ID of the transaction to check\n /// @return True if the transaction has been relayed, false otherwise\n function bridgeRelays(bytes32 transactionId) external view returns (bool);\n\n /// @notice Returns the status of a bridge transaction\n /// @param transactionId The ID of the bridge transaction\n /// @return BridgeStatus Status of the bridge transaction\n function bridgeStatuses(bytes32 transactionId) external view returns (BridgeStatus);\n\n /// @notice Returns the timestamp and relayer of a bridge proof\n /// @param transactionId The ID of the bridge transaction\n /// @return timestamp The timestamp of the bridge proof\n /// @return relayer The relayer address of the bridge proof\n function bridgeProofs(bytes32 transactionId) external view returns (uint96 timestamp, address relayer);\n\n /// @notice Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\n /// @param request The bridge request to decode\n function getBridgeTransactionV2(bytes memory request) external view returns (BridgeTransactionV2 memory);\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// contracts/libs/UniversalToken.sol\n\nlibrary UniversalTokenLib {\n using SafeERC20 for IERC20;\n\n address internal constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Transfers tokens to the given account. Reverts if transfer is not successful.\n /// @dev This might trigger fallback, if ETH is transferred to the contract.\n /// Make sure this can not lead to reentrancy attacks.\n function universalTransfer(address token, address to, uint256 value) internal {\n // Don't do anything, if need to send tokens to this address\n if (to == address(this)) return;\n // Don't do anything, if trying to send zero value\n if (value == 0) return;\n if (token == ETH_ADDRESS) {\n /// @dev Note: this can potentially lead to executing code in `to`.\n // solhint-disable-next-line avoid-low-level-calls\n (bool success,) = to.call{value: value}(\"\");\n require(success, \"ETH transfer failed\");\n } else {\n IERC20(token).safeTransfer(to, value);\n }\n }\n\n /// @notice Issues an infinite allowance to the spender, if the current allowance is insufficient\n /// to spend the given amount.\n function universalApproveInfinity(address token, address spender, uint256 amountToSpend) internal {\n // ETH Chad doesn't require your approval\n if (token == ETH_ADDRESS) return;\n // No-op if allowance is already sufficient\n uint256 allowance = IERC20(token).allowance(address(this), spender);\n if (allowance \u003e= amountToSpend) return;\n // Otherwise, reset approval to 0 and set to max allowance\n if (allowance \u003e 0) IERC20(token).safeDecreaseAllowance(spender, allowance);\n IERC20(token).safeIncreaseAllowance(spender, type(uint256).max);\n }\n\n /// @notice Returns the balance of the given token (or native ETH) for the given account.\n function universalBalanceOf(address token, address account) internal view returns (uint256) {\n if (token == ETH_ADDRESS) {\n return account.balance;\n } else {\n return IERC20(token).balanceOf(account);\n }\n }\n\n /// @dev Checks that token is a contract and not ETH_ADDRESS.\n function assertIsContract(address token) internal view {\n // Check that ETH_ADDRESS was not used (in case this is a predeploy on any of the chains)\n if (token == UniversalTokenLib.ETH_ADDRESS) revert TokenNotContract();\n // Check that token is not an EOA\n if (token.code.length == 0) revert TokenNotContract();\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/Admin.sol\n\ncontract Admin is IAdmin, AccessControlEnumerable {\n using UniversalTokenLib for address;\n\n bytes32 public constant RELAYER_ROLE = keccak256(\"RELAYER_ROLE\");\n bytes32 public constant REFUNDER_ROLE = keccak256(\"REFUNDER_ROLE\");\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n uint256 public constant FEE_BPS = 1e6;\n uint256 public constant FEE_RATE_MAX = 0.01e6; // max 1% on origin amount\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Chain gas amount to forward as rebate if requested\n uint256 public chainGasAmount;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n }\n\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n require(newFeeRate \u003c= FEE_RATE_MAX, \"newFeeRate \u003e max\");\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n token.universalTransfer(recipient, feeAmount);\n emit FeesSwept(token, recipient, feeAmount);\n }\n\n function setChainGasAmount(uint256 newChainGasAmount) external onlyRole(GOVERNOR_ROLE) {\n uint256 oldChainGasAmount = chainGasAmount;\n chainGasAmount = newChainGasAmount;\n emit ChainGasAmountUpdated(oldChainGasAmount, newChainGasAmount);\n }\n}\n\n// contracts/FastBridgeV2.sol\n\n/// @notice FastBridgeV2 is a contract for bridging tokens across chains.\ncontract FastBridgeV2 is Admin, IFastBridgeV2, IFastBridgeV2Errors {\n using SafeERC20 for IERC20;\n using UniversalTokenLib for address;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Delay for a transaction after which it could be permisionlessly refunded\n uint256 public constant REFUND_DELAY = 7 days;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n /// @notice Maximum length of accepted callParams\n uint256 public constant MAX_CALL_PARAMS_LENGTH = 2 ** 16 - 1;\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeTxDetails) public bridgeTxDetails;\n /// @notice Relay details on destination chain\n mapping(bytes32 =\u003e BridgeRelay) public bridgeRelayDetails;\n /// @notice Unique bridge nonces tracked per originSender\n mapping(address =\u003e uint256) public senderNonces;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Replaced by senderNonces\n uint256 public immutable nonce = 0;\n /// @notice the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n bridge({\n params: params,\n paramsV2: BridgeParamsV2({\n quoteRelayer: address(0),\n quoteExclusivitySeconds: 0,\n quoteId: bytes(\"\"),\n callValue: 0,\n callParams: bytes(\"\")\n })\n });\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes memory request) external payable {\n relay({request: request, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes memory request, bytes32 destTxHash) external {\n prove({transactionId: keccak256(request), destTxHash: destTxHash, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridgeV2\n function claim(bytes memory request) external {\n claim({request: request, to: address(0)});\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003e DISPUTE_PERIOD) {\n revert DisputePeriodPassed();\n }\n\n // @dev relayer gets slashed effectively if dest relay has gone thru\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n bridgeTxDetails[transactionId].proofRelayer = address(0);\n bridgeTxDetails[transactionId].proofBlockTimestamp = 0;\n bridgeTxDetails[transactionId].proofBlockNumber = 0;\n\n emit BridgeProofDisputed(transactionId, msg.sender);\n }\n\n /// @inheritdoc IFastBridge\n function refund(bytes memory request) external {\n bytes32 transactionId = keccak256(request);\n\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n\n if (bridgeTxDetails[transactionId].status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n\n if (hasRole(REFUNDER_ROLE, msg.sender)) {\n // Refunder can refund if deadline has passed\n if (block.timestamp \u003c= transaction.deadline) revert DeadlineNotExceeded();\n } else {\n // Permissionless refund is allowed after REFUND_DELAY\n if (block.timestamp \u003c= transaction.deadline + REFUND_DELAY) revert DeadlineNotExceeded();\n }\n\n // if all checks passed, set to REFUNDED status\n bridgeTxDetails[transactionId].status = BridgeStatus.REFUNDED;\n\n // transfer origin collateral back to original sender\n address to = transaction.originSender;\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount + transaction.originFeeAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (bridgeTxDetails[transactionId].proofRelayer != relayer) revert SenderIncorrect();\n return _timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n /// @dev This method is added to achieve backwards compatibility with decoding requests into V1 structs:\n /// - `callValue` is partially reported as a zero/non-zero flag\n /// - `callParams` is ignored\n /// In order to process all kinds of requests use getBridgeTransactionV2 instead.\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory) {\n // Try decoding into V2 struct first. This will revert if V1 struct is passed\n try this.getBridgeTransactionV2(request) returns (BridgeTransactionV2 memory txV2) {\n // Note: we entirely ignore the callParams field, as it was not present in V1\n return BridgeTransaction({\n originChainId: txV2.originChainId,\n destChainId: txV2.destChainId,\n originSender: txV2.originSender,\n destRecipient: txV2.destRecipient,\n originToken: txV2.originToken,\n destToken: txV2.destToken,\n originAmount: txV2.originAmount,\n destAmount: txV2.destAmount,\n originFeeAmount: txV2.originFeeAmount,\n sendChainGas: txV2.callValue != 0,\n deadline: txV2.deadline,\n nonce: txV2.nonce\n });\n } catch {\n // Fallback to V1 struct\n return abi.decode(request, (BridgeTransaction));\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) public payable {\n int256 exclusivityEndTime = int256(block.timestamp) + paramsV2.quoteExclusivitySeconds;\n _validateBridgeParams(params, paramsV2, exclusivityEndTime);\n\n // transfer tokens to bridge contract\n /// @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _pullToken(params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n\n // set status to requested\n bytes memory request = abi.encode(\n BridgeTransactionV2({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n callValue: paramsV2.callValue,\n deadline: params.deadline,\n nonce: senderNonces[params.sender]++, // increment nonce on every bridge\n exclusivityRelayer: paramsV2.quoteRelayer,\n // We checked exclusivityEndTime to be in range (0 .. params.deadline] above, so can safely cast\n exclusivityEndTime: uint256(exclusivityEndTime),\n callParams: paramsV2.callParams\n })\n );\n bytes32 transactionId = keccak256(request);\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n\n emit BridgeRequested({\n transactionId: transactionId,\n sender: params.sender,\n request: request,\n destChainId: params.dstChainId,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n sendChainGas: paramsV2.callValue != 0\n });\n emit BridgeQuoteDetails(transactionId, paramsV2.quoteId);\n }\n\n /// @inheritdoc IFastBridgeV2\n function relay(bytes memory request, address relayer) public payable {\n bytes32 transactionId = keccak256(request);\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n _validateRelayParams(transaction, transactionId, relayer);\n // mark bridge transaction as relayed\n bridgeRelayDetails[transactionId] =\n BridgeRelay({blockNumber: uint48(block.number), blockTimestamp: uint48(block.timestamp), relayer: relayer});\n\n // transfer tokens to recipient on destination chain and do an arbitrary call if requested\n address to = transaction.destRecipient;\n address token = transaction.destToken;\n uint256 amount = transaction.destAmount;\n\n // All state changes have been done at this point, can proceed to the external calls.\n // This follows the checks-effects-interactions pattern to mitigate potential reentrancy attacks.\n if (token == UniversalTokenLib.ETH_ADDRESS) {\n // For ETH non-zero callValue is not allowed\n if (transaction.callValue != 0) revert NativeTokenCallValueNotSupported();\n // Check that the correct msg.value was sent\n if (msg.value != amount) revert MsgValueIncorrect();\n } else {\n // For ERC20s, we check that the correct msg.value was sent\n if (msg.value != transaction.callValue) revert MsgValueIncorrect();\n // We need to transfer the tokens from the Relayer to the recipient first before performing an\n // optional post-transfer arbitrary call.\n IERC20(token).safeTransferFrom(msg.sender, to, amount);\n }\n\n if (transaction.callParams.length != 0) {\n // Arbitrary call requested, perform it while supplying full msg.value to the recipient\n // Note: if token has a fee on transfers, the recipient will have received less than `amount`.\n // This is a very niche edge case and should be handled by the recipient contract.\n _checkedCallRecipient({recipient: to, token: token, amount: amount, callParams: transaction.callParams});\n } else if (msg.value != 0) {\n // No arbitrary call requested, but msg.value was sent. This is either a relay with ETH,\n // or a non-zero callValue request with an ERC20. In both cases, transfer the ETH to the recipient.\n Address.sendValue(payable(to), msg.value);\n }\n\n emit BridgeRelayed({\n transactionId: transactionId,\n relayer: relayer,\n to: to,\n originChainId: transaction.originChainId,\n originToken: transaction.originToken,\n destToken: transaction.destToken,\n originAmount: transaction.originAmount,\n destAmount: transaction.destAmount,\n chainGasAmount: transaction.callValue\n });\n }\n\n /// @inheritdoc IFastBridgeV2\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) public onlyRole(RELAYER_ROLE) {\n // update bridge tx status given proof provided\n if (bridgeTxDetails[transactionId].status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n bridgeTxDetails[transactionId].status = BridgeStatus.RELAYER_PROVED;\n bridgeTxDetails[transactionId].proofBlockTimestamp = uint40(block.timestamp);\n bridgeTxDetails[transactionId].proofBlockNumber = uint48(block.number);\n bridgeTxDetails[transactionId].proofRelayer = relayer;\n\n emit BridgeProofProvided(transactionId, relayer, destTxHash);\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes memory request, address to) public {\n bytes32 transactionId = keccak256(request);\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n\n // update bridge tx status if able to claim origin collateral\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n\n // if \"to\" is zero addr, permissionlessly send funds to proven relayer\n if (to == address(0)) {\n to = bridgeTxDetails[transactionId].proofRelayer;\n } else if (bridgeTxDetails[transactionId].proofRelayer != msg.sender) {\n revert SenderIncorrect();\n }\n\n if (_timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003c= DISPUTE_PERIOD) {\n revert DisputePeriodNotPassed();\n }\n\n bridgeTxDetails[transactionId].status = BridgeStatus.RELAYER_CLAIMED;\n\n // update protocol fees if origin fee amount exists\n if (transaction.originFeeAmount \u003e 0) protocolFees[transaction.originToken] += transaction.originFeeAmount;\n\n // transfer origin collateral less fee to specified address\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositClaimed(transactionId, bridgeTxDetails[transactionId].proofRelayer, to, token, amount);\n }\n\n function bridgeStatuses(bytes32 transactionId) public view returns (BridgeStatus status) {\n return bridgeTxDetails[transactionId].status;\n }\n\n function bridgeProofs(bytes32 transactionId) public view returns (uint96 timestamp, address relayer) {\n timestamp = bridgeTxDetails[transactionId].proofBlockTimestamp;\n relayer = bridgeTxDetails[transactionId].proofRelayer;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeRelays(bytes32 transactionId) public view returns (bool) {\n // has this transactionId been relayed?\n return bridgeRelayDetails[transactionId].relayer != address(0);\n }\n\n /// @inheritdoc IFastBridgeV2\n function getBridgeTransactionV2(bytes memory request) public pure returns (BridgeTransactionV2 memory) {\n return abi.decode(request, (BridgeTransactionV2));\n }\n\n /// @notice Pulls a requested token from the user to this contract.\n function _pullToken(address token, uint256 amount) internal returns (uint256 amountPulled) {\n if (token == UniversalTokenLib.ETH_ADDRESS) {\n // For ETH we just need to check that the supplied msg.value is correct\n if (amount != msg.value) revert MsgValueIncorrect();\n amountPulled = msg.value;\n } else {\n token.assertIsContract();\n // Record token balance before transfer\n amountPulled = IERC20(token).balanceOf(address(this));\n // Token needs to be pulled only if msg.value is zero\n // This way user can specify WETH as the origin asset\n IERC20(token).safeTransferFrom(msg.sender, address(this), amount);\n // Use the difference between the recorded balance and the current balance as the amountPulled\n amountPulled = IERC20(token).balanceOf(address(this)) - amountPulled;\n }\n }\n\n /// @notice Calls the Recipient's hook function with the specified callParams and performs\n /// all the necessary checks for the returned value.\n function _checkedCallRecipient(\n address recipient,\n address token,\n uint256 amount,\n bytes memory callParams\n )\n internal\n {\n bytes memory hookData =\n abi.encodeCall(IFastBridgeRecipient.fastBridgeTransferReceived, (token, amount, callParams));\n // This will bubble any revert messages from the hook function\n bytes memory returnData = Address.functionCallWithValue({target: recipient, data: hookData, value: msg.value});\n // Explicit revert if no return data at all\n if (returnData.length == 0) revert RecipientNoReturnValue();\n // Check that exactly a single return value was returned\n if (returnData.length != 32) revert RecipientIncorrectReturnValue();\n // Return value should be abi-encoded hook function selector\n if (bytes32(returnData) != bytes32(IFastBridgeRecipient.fastBridgeTransferReceived.selector)) {\n revert RecipientIncorrectReturnValue();\n }\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint40(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint40).max but\n /// proof.timestamp \u003c type(uint40).max via unchecked statement\n /// @param proofBlockTimestamp The bridge proof block timestamp\n /// @return delta Time delta since proof submitted\n function _timeSince(uint40 proofBlockTimestamp) internal view returns (uint256 delta) {\n unchecked {\n delta = uint40(block.timestamp) - proofBlockTimestamp;\n }\n }\n\n /// @notice Performs all the necessary checks for a bridge to happen.\n /// @dev There's no good way to refactor this function to reduce cyclomatic complexity due to\n /// the number of checks that need to be performed, so we skip the code-complexity rule here.\n // solhint-disable-next-line code-complexity\n function _validateBridgeParams(\n BridgeParams memory params,\n BridgeParamsV2 memory paramsV2,\n int256 exclusivityEndTime\n )\n internal\n view\n {\n // Check V1 (legacy) params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.sender == address(0) || params.to == address(0)) revert ZeroAddress();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n // Check V2 params\n if (paramsV2.callParams.length \u003e MAX_CALL_PARAMS_LENGTH) revert CallParamsLengthAboveMax();\n if (paramsV2.callValue != 0 \u0026\u0026 params.destToken == UniversalTokenLib.ETH_ADDRESS) {\n revert NativeTokenCallValueNotSupported();\n }\n // exclusivityEndTime must be in range (0 .. params.deadline]\n if (exclusivityEndTime \u003c= 0 || exclusivityEndTime \u003e int256(params.deadline)) {\n revert ExclusivityParamsIncorrect();\n }\n }\n\n /// @notice Performs all the necessary checks for a relay to happen.\n function _validateRelayParams(\n BridgeTransactionV2 memory transaction,\n bytes32 transactionId,\n address relayer\n )\n internal\n view\n {\n if (relayer == address(0)) revert ZeroAddress();\n // Check if the transaction has already been relayed\n if (bridgeRelays(transactionId)) revert TransactionRelayed();\n if (transaction.destChainId != uint32(block.chainid)) revert ChainIncorrect();\n // Check the deadline for relay to happen\n if (block.timestamp \u003e transaction.deadline) revert DeadlineExceeded();\n // Check the exclusivity period, if it is still ongoing\n // forgefmt: disable-next-item\n if (\n transaction.exclusivityRelayer != address(0) \u0026\u0026\n transaction.exclusivityRelayer != relayer \u0026\u0026\n block.timestamp \u003c= transaction.exclusivityEndTime\n ) {\n revert ExclusivityPeriodNotPassed();\n }\n }\n}\n","language":"Solidity","languageVersion":"0.8.24","compilerVersion":"0.8.24","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../","srcMap":"","srcMapRuntime":"","abiDefinition":[{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"}],"userDoc":{"kind":"user","methods":{},"version":1},"developerDoc":{"details":"Implementation of the {IERC165} interface. Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check for the additional interface id that will be supported. For example: ```solidity function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId); } ```","kind":"dev","methods":{"supportsInterface(bytes4)":{"details":"See {IERC165-supportsInterface}."}},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"bytes4\",\"name\":\"interfaceId\",\"type\":\"bytes4\"}],\"name\":\"supportsInterface\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"}],\"devdoc\":{\"details\":\"Implementation of the {IERC165} interface. Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check for the additional interface id that will be supported. For example: ```solidity function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId); } ```\",\"kind\":\"dev\",\"methods\":{\"supportsInterface(bytes4)\":{\"details\":\"See {IERC165-supportsInterface}.\"}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeV2.sol\":\"ERC165\"},\"evmVersion\":\"shanghai\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeV2.sol\":{\"keccak256\":\"0x7cd0f885e80e2bdaa638bc32ae7af7d2e248f99ce4b354c217d0f0f7d7302e0a\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://7ccf28df0bd7b4606986585acd8622ed9b4e81379690061bb66088f0a2270af1\",\"dweb:/ipfs/QmTf7HNdHZkK6vmx8ZgewycQEb72oLD9nPwBpsM5reMstQ\"]}},\"version\":1}"},"hashes":{"supportsInterface(bytes4)":"01ffc9a7"}},"solidity/FastBridgeV2.sol:EnumerableSet":{"code":"0x60556032600b8282823980515f1a607314602657634e487b7160e01b5f525f60045260245ffd5b305f52607381538281f3fe730000000000000000000000000000000000000000301460806040525f80fdfea26469706673582212201ec3fcd8425a477b64c89978a17adf538a2da29b003a43e615ec5e213f9f3bf964736f6c63430008180033","runtime-code":"0x730000000000000000000000000000000000000000301460806040525f80fdfea26469706673582212201ec3fcd8425a477b64c89978a17adf538a2da29b003a43e615ec5e213f9f3bf964736f6c63430008180033","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.24 ^0.8.0 ^0.8.20;\n\n// contracts/interfaces/IAdmin.sol\n\ninterface IAdmin {\n // ============ Events ============\n\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n event ChainGasAmountUpdated(uint256 oldChainGasAmount, uint256 newChainGasAmount);\n\n // ============ Methods ============\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n\n function setChainGasAmount(uint256 newChainGasAmount) external;\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IFastBridgeRecipient.sol\n\ninterface IFastBridgeRecipient {\n function fastBridgeTransferReceived(\n address token,\n uint256 amount,\n bytes memory callParams\n )\n external\n payable\n returns (bytes4);\n}\n\n// contracts/interfaces/IFastBridgeV2Errors.sol\n\ninterface IFastBridgeV2Errors {\n error AmountIncorrect();\n error CallParamsLengthAboveMax();\n error ChainIncorrect();\n error ExclusivityParamsIncorrect();\n error MsgValueIncorrect();\n error NativeTokenCallValueNotSupported();\n error SenderIncorrect();\n error StatusIncorrect();\n error ZeroAddress();\n\n error RecipientIncorrectReturnValue();\n error RecipientNoReturnValue();\n\n error DeadlineExceeded();\n error DeadlineNotExceeded();\n error DeadlineTooShort();\n error DisputePeriodNotPassed();\n error DisputePeriodPassed();\n error ExclusivityPeriodNotPassed();\n\n error TransactionRelayed();\n}\n\n// contracts/libs/Errors.sol\n\nerror DeadlineExceeded();\nerror DeadlineNotExceeded();\nerror DeadlineTooShort();\nerror InsufficientOutputAmount();\n\nerror MsgValueIncorrect();\nerror PoolNotFound();\nerror TokenAddressMismatch();\nerror TokenNotContract();\nerror TokenNotETH();\nerror TokensIdentical();\n\nerror ChainIncorrect();\nerror AmountIncorrect();\nerror ZeroAddress();\n\nerror DisputePeriodNotPassed();\nerror DisputePeriodPassed();\nerror SenderIncorrect();\nerror StatusIncorrect();\nerror TransactionIdIncorrect();\nerror TransactionRelayed();\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// contracts/interfaces/IFastBridgeV2.sol\n\ninterface IFastBridgeV2 is IFastBridge {\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n struct BridgeTxDetails {\n BridgeStatus status;\n uint40 proofBlockTimestamp;\n uint48 proofBlockNumber;\n address proofRelayer;\n }\n\n struct BridgeRelay {\n uint48 blockNumber;\n uint48 blockTimestamp;\n address relayer;\n }\n\n /// @notice New params introduced in the FastBridgeV2.\n /// We are passing fields from the older BridgeParams struct outside of this struct\n /// for backwards compatibility.\n /// Note: quoteRelayer and quoteExclusivitySeconds are either both zero (indicating no exclusivity)\n /// or both non-zero (indicating exclusivity for the given period).\n /// Note: callValue \u003e 0 can NOT be used with destToken = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE (ETH_ADDRESS)\n /// @param quoteRelayer Relayer that provided the quote for the transaction\n /// @param quoteExclusivitySeconds Period of time the quote relayer is guaranteed exclusivity after user's deposit\n /// @param quoteId Unique quote identifier used for tracking the quote\n /// @param callValue ETH value to send to the recipient (if any)\n /// @param callParams Parameters for the arbitrary call to the destination recipient (if any)\n struct BridgeParamsV2 {\n address quoteRelayer;\n int256 quoteExclusivitySeconds;\n bytes quoteId;\n uint256 callValue;\n bytes callParams;\n }\n\n /// @notice Updated bridge transaction struct to include parameters introduced in FastBridgeV2.\n /// Note: only `exclusivityRelayer` can fill such a transaction until `exclusivityEndTime`.\n /// TODO: consider changing the encoding scheme to prevent spending extra gas on decoding.\n struct BridgeTransactionV2 {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n uint256 callValue; // ETH value to send to the recipient (if any) - replaces V1's sendChainGas flag\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n address exclusivityRelayer;\n uint256 exclusivityEndTime;\n bytes callParams;\n }\n\n event BridgeQuoteDetails(bytes32 indexed transactionId, bytes quoteId);\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability\n /// to provide temporary exclusivity fill rights for the quote relayer.\n /// @param params The parameters required to bridge\n /// @param paramsV2 The parameters for exclusivity fill rights (optional, can be left empty)\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function relay(bytes memory request, address relayer) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param transactionId The transaction id associated with the encoded bridge transaction to prove\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital.\n /// @notice Can only send funds to the relayer address on the proof.\n /// @param request The encoded bridge transaction to claim on origin chain\n function claim(bytes memory request) external;\n /// @notice Checks if a transaction has been relayed\n /// @param transactionId The ID of the transaction to check\n /// @return True if the transaction has been relayed, false otherwise\n function bridgeRelays(bytes32 transactionId) external view returns (bool);\n\n /// @notice Returns the status of a bridge transaction\n /// @param transactionId The ID of the bridge transaction\n /// @return BridgeStatus Status of the bridge transaction\n function bridgeStatuses(bytes32 transactionId) external view returns (BridgeStatus);\n\n /// @notice Returns the timestamp and relayer of a bridge proof\n /// @param transactionId The ID of the bridge transaction\n /// @return timestamp The timestamp of the bridge proof\n /// @return relayer The relayer address of the bridge proof\n function bridgeProofs(bytes32 transactionId) external view returns (uint96 timestamp, address relayer);\n\n /// @notice Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\n /// @param request The bridge request to decode\n function getBridgeTransactionV2(bytes memory request) external view returns (BridgeTransactionV2 memory);\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// contracts/libs/UniversalToken.sol\n\nlibrary UniversalTokenLib {\n using SafeERC20 for IERC20;\n\n address internal constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Transfers tokens to the given account. Reverts if transfer is not successful.\n /// @dev This might trigger fallback, if ETH is transferred to the contract.\n /// Make sure this can not lead to reentrancy attacks.\n function universalTransfer(address token, address to, uint256 value) internal {\n // Don't do anything, if need to send tokens to this address\n if (to == address(this)) return;\n // Don't do anything, if trying to send zero value\n if (value == 0) return;\n if (token == ETH_ADDRESS) {\n /// @dev Note: this can potentially lead to executing code in `to`.\n // solhint-disable-next-line avoid-low-level-calls\n (bool success,) = to.call{value: value}(\"\");\n require(success, \"ETH transfer failed\");\n } else {\n IERC20(token).safeTransfer(to, value);\n }\n }\n\n /// @notice Issues an infinite allowance to the spender, if the current allowance is insufficient\n /// to spend the given amount.\n function universalApproveInfinity(address token, address spender, uint256 amountToSpend) internal {\n // ETH Chad doesn't require your approval\n if (token == ETH_ADDRESS) return;\n // No-op if allowance is already sufficient\n uint256 allowance = IERC20(token).allowance(address(this), spender);\n if (allowance \u003e= amountToSpend) return;\n // Otherwise, reset approval to 0 and set to max allowance\n if (allowance \u003e 0) IERC20(token).safeDecreaseAllowance(spender, allowance);\n IERC20(token).safeIncreaseAllowance(spender, type(uint256).max);\n }\n\n /// @notice Returns the balance of the given token (or native ETH) for the given account.\n function universalBalanceOf(address token, address account) internal view returns (uint256) {\n if (token == ETH_ADDRESS) {\n return account.balance;\n } else {\n return IERC20(token).balanceOf(account);\n }\n }\n\n /// @dev Checks that token is a contract and not ETH_ADDRESS.\n function assertIsContract(address token) internal view {\n // Check that ETH_ADDRESS was not used (in case this is a predeploy on any of the chains)\n if (token == UniversalTokenLib.ETH_ADDRESS) revert TokenNotContract();\n // Check that token is not an EOA\n if (token.code.length == 0) revert TokenNotContract();\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/Admin.sol\n\ncontract Admin is IAdmin, AccessControlEnumerable {\n using UniversalTokenLib for address;\n\n bytes32 public constant RELAYER_ROLE = keccak256(\"RELAYER_ROLE\");\n bytes32 public constant REFUNDER_ROLE = keccak256(\"REFUNDER_ROLE\");\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n uint256 public constant FEE_BPS = 1e6;\n uint256 public constant FEE_RATE_MAX = 0.01e6; // max 1% on origin amount\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Chain gas amount to forward as rebate if requested\n uint256 public chainGasAmount;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n }\n\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n require(newFeeRate \u003c= FEE_RATE_MAX, \"newFeeRate \u003e max\");\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n token.universalTransfer(recipient, feeAmount);\n emit FeesSwept(token, recipient, feeAmount);\n }\n\n function setChainGasAmount(uint256 newChainGasAmount) external onlyRole(GOVERNOR_ROLE) {\n uint256 oldChainGasAmount = chainGasAmount;\n chainGasAmount = newChainGasAmount;\n emit ChainGasAmountUpdated(oldChainGasAmount, newChainGasAmount);\n }\n}\n\n// contracts/FastBridgeV2.sol\n\n/// @notice FastBridgeV2 is a contract for bridging tokens across chains.\ncontract FastBridgeV2 is Admin, IFastBridgeV2, IFastBridgeV2Errors {\n using SafeERC20 for IERC20;\n using UniversalTokenLib for address;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Delay for a transaction after which it could be permisionlessly refunded\n uint256 public constant REFUND_DELAY = 7 days;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n /// @notice Maximum length of accepted callParams\n uint256 public constant MAX_CALL_PARAMS_LENGTH = 2 ** 16 - 1;\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeTxDetails) public bridgeTxDetails;\n /// @notice Relay details on destination chain\n mapping(bytes32 =\u003e BridgeRelay) public bridgeRelayDetails;\n /// @notice Unique bridge nonces tracked per originSender\n mapping(address =\u003e uint256) public senderNonces;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Replaced by senderNonces\n uint256 public immutable nonce = 0;\n /// @notice the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n bridge({\n params: params,\n paramsV2: BridgeParamsV2({\n quoteRelayer: address(0),\n quoteExclusivitySeconds: 0,\n quoteId: bytes(\"\"),\n callValue: 0,\n callParams: bytes(\"\")\n })\n });\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes memory request) external payable {\n relay({request: request, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes memory request, bytes32 destTxHash) external {\n prove({transactionId: keccak256(request), destTxHash: destTxHash, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridgeV2\n function claim(bytes memory request) external {\n claim({request: request, to: address(0)});\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003e DISPUTE_PERIOD) {\n revert DisputePeriodPassed();\n }\n\n // @dev relayer gets slashed effectively if dest relay has gone thru\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n bridgeTxDetails[transactionId].proofRelayer = address(0);\n bridgeTxDetails[transactionId].proofBlockTimestamp = 0;\n bridgeTxDetails[transactionId].proofBlockNumber = 0;\n\n emit BridgeProofDisputed(transactionId, msg.sender);\n }\n\n /// @inheritdoc IFastBridge\n function refund(bytes memory request) external {\n bytes32 transactionId = keccak256(request);\n\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n\n if (bridgeTxDetails[transactionId].status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n\n if (hasRole(REFUNDER_ROLE, msg.sender)) {\n // Refunder can refund if deadline has passed\n if (block.timestamp \u003c= transaction.deadline) revert DeadlineNotExceeded();\n } else {\n // Permissionless refund is allowed after REFUND_DELAY\n if (block.timestamp \u003c= transaction.deadline + REFUND_DELAY) revert DeadlineNotExceeded();\n }\n\n // if all checks passed, set to REFUNDED status\n bridgeTxDetails[transactionId].status = BridgeStatus.REFUNDED;\n\n // transfer origin collateral back to original sender\n address to = transaction.originSender;\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount + transaction.originFeeAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (bridgeTxDetails[transactionId].proofRelayer != relayer) revert SenderIncorrect();\n return _timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n /// @dev This method is added to achieve backwards compatibility with decoding requests into V1 structs:\n /// - `callValue` is partially reported as a zero/non-zero flag\n /// - `callParams` is ignored\n /// In order to process all kinds of requests use getBridgeTransactionV2 instead.\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory) {\n // Try decoding into V2 struct first. This will revert if V1 struct is passed\n try this.getBridgeTransactionV2(request) returns (BridgeTransactionV2 memory txV2) {\n // Note: we entirely ignore the callParams field, as it was not present in V1\n return BridgeTransaction({\n originChainId: txV2.originChainId,\n destChainId: txV2.destChainId,\n originSender: txV2.originSender,\n destRecipient: txV2.destRecipient,\n originToken: txV2.originToken,\n destToken: txV2.destToken,\n originAmount: txV2.originAmount,\n destAmount: txV2.destAmount,\n originFeeAmount: txV2.originFeeAmount,\n sendChainGas: txV2.callValue != 0,\n deadline: txV2.deadline,\n nonce: txV2.nonce\n });\n } catch {\n // Fallback to V1 struct\n return abi.decode(request, (BridgeTransaction));\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) public payable {\n int256 exclusivityEndTime = int256(block.timestamp) + paramsV2.quoteExclusivitySeconds;\n _validateBridgeParams(params, paramsV2, exclusivityEndTime);\n\n // transfer tokens to bridge contract\n /// @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _pullToken(params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n\n // set status to requested\n bytes memory request = abi.encode(\n BridgeTransactionV2({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n callValue: paramsV2.callValue,\n deadline: params.deadline,\n nonce: senderNonces[params.sender]++, // increment nonce on every bridge\n exclusivityRelayer: paramsV2.quoteRelayer,\n // We checked exclusivityEndTime to be in range (0 .. params.deadline] above, so can safely cast\n exclusivityEndTime: uint256(exclusivityEndTime),\n callParams: paramsV2.callParams\n })\n );\n bytes32 transactionId = keccak256(request);\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n\n emit BridgeRequested({\n transactionId: transactionId,\n sender: params.sender,\n request: request,\n destChainId: params.dstChainId,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n sendChainGas: paramsV2.callValue != 0\n });\n emit BridgeQuoteDetails(transactionId, paramsV2.quoteId);\n }\n\n /// @inheritdoc IFastBridgeV2\n function relay(bytes memory request, address relayer) public payable {\n bytes32 transactionId = keccak256(request);\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n _validateRelayParams(transaction, transactionId, relayer);\n // mark bridge transaction as relayed\n bridgeRelayDetails[transactionId] =\n BridgeRelay({blockNumber: uint48(block.number), blockTimestamp: uint48(block.timestamp), relayer: relayer});\n\n // transfer tokens to recipient on destination chain and do an arbitrary call if requested\n address to = transaction.destRecipient;\n address token = transaction.destToken;\n uint256 amount = transaction.destAmount;\n\n // All state changes have been done at this point, can proceed to the external calls.\n // This follows the checks-effects-interactions pattern to mitigate potential reentrancy attacks.\n if (token == UniversalTokenLib.ETH_ADDRESS) {\n // For ETH non-zero callValue is not allowed\n if (transaction.callValue != 0) revert NativeTokenCallValueNotSupported();\n // Check that the correct msg.value was sent\n if (msg.value != amount) revert MsgValueIncorrect();\n } else {\n // For ERC20s, we check that the correct msg.value was sent\n if (msg.value != transaction.callValue) revert MsgValueIncorrect();\n // We need to transfer the tokens from the Relayer to the recipient first before performing an\n // optional post-transfer arbitrary call.\n IERC20(token).safeTransferFrom(msg.sender, to, amount);\n }\n\n if (transaction.callParams.length != 0) {\n // Arbitrary call requested, perform it while supplying full msg.value to the recipient\n // Note: if token has a fee on transfers, the recipient will have received less than `amount`.\n // This is a very niche edge case and should be handled by the recipient contract.\n _checkedCallRecipient({recipient: to, token: token, amount: amount, callParams: transaction.callParams});\n } else if (msg.value != 0) {\n // No arbitrary call requested, but msg.value was sent. This is either a relay with ETH,\n // or a non-zero callValue request with an ERC20. In both cases, transfer the ETH to the recipient.\n Address.sendValue(payable(to), msg.value);\n }\n\n emit BridgeRelayed({\n transactionId: transactionId,\n relayer: relayer,\n to: to,\n originChainId: transaction.originChainId,\n originToken: transaction.originToken,\n destToken: transaction.destToken,\n originAmount: transaction.originAmount,\n destAmount: transaction.destAmount,\n chainGasAmount: transaction.callValue\n });\n }\n\n /// @inheritdoc IFastBridgeV2\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) public onlyRole(RELAYER_ROLE) {\n // update bridge tx status given proof provided\n if (bridgeTxDetails[transactionId].status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n bridgeTxDetails[transactionId].status = BridgeStatus.RELAYER_PROVED;\n bridgeTxDetails[transactionId].proofBlockTimestamp = uint40(block.timestamp);\n bridgeTxDetails[transactionId].proofBlockNumber = uint48(block.number);\n bridgeTxDetails[transactionId].proofRelayer = relayer;\n\n emit BridgeProofProvided(transactionId, relayer, destTxHash);\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes memory request, address to) public {\n bytes32 transactionId = keccak256(request);\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n\n // update bridge tx status if able to claim origin collateral\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n\n // if \"to\" is zero addr, permissionlessly send funds to proven relayer\n if (to == address(0)) {\n to = bridgeTxDetails[transactionId].proofRelayer;\n } else if (bridgeTxDetails[transactionId].proofRelayer != msg.sender) {\n revert SenderIncorrect();\n }\n\n if (_timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003c= DISPUTE_PERIOD) {\n revert DisputePeriodNotPassed();\n }\n\n bridgeTxDetails[transactionId].status = BridgeStatus.RELAYER_CLAIMED;\n\n // update protocol fees if origin fee amount exists\n if (transaction.originFeeAmount \u003e 0) protocolFees[transaction.originToken] += transaction.originFeeAmount;\n\n // transfer origin collateral less fee to specified address\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositClaimed(transactionId, bridgeTxDetails[transactionId].proofRelayer, to, token, amount);\n }\n\n function bridgeStatuses(bytes32 transactionId) public view returns (BridgeStatus status) {\n return bridgeTxDetails[transactionId].status;\n }\n\n function bridgeProofs(bytes32 transactionId) public view returns (uint96 timestamp, address relayer) {\n timestamp = bridgeTxDetails[transactionId].proofBlockTimestamp;\n relayer = bridgeTxDetails[transactionId].proofRelayer;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeRelays(bytes32 transactionId) public view returns (bool) {\n // has this transactionId been relayed?\n return bridgeRelayDetails[transactionId].relayer != address(0);\n }\n\n /// @inheritdoc IFastBridgeV2\n function getBridgeTransactionV2(bytes memory request) public pure returns (BridgeTransactionV2 memory) {\n return abi.decode(request, (BridgeTransactionV2));\n }\n\n /// @notice Pulls a requested token from the user to this contract.\n function _pullToken(address token, uint256 amount) internal returns (uint256 amountPulled) {\n if (token == UniversalTokenLib.ETH_ADDRESS) {\n // For ETH we just need to check that the supplied msg.value is correct\n if (amount != msg.value) revert MsgValueIncorrect();\n amountPulled = msg.value;\n } else {\n token.assertIsContract();\n // Record token balance before transfer\n amountPulled = IERC20(token).balanceOf(address(this));\n // Token needs to be pulled only if msg.value is zero\n // This way user can specify WETH as the origin asset\n IERC20(token).safeTransferFrom(msg.sender, address(this), amount);\n // Use the difference between the recorded balance and the current balance as the amountPulled\n amountPulled = IERC20(token).balanceOf(address(this)) - amountPulled;\n }\n }\n\n /// @notice Calls the Recipient's hook function with the specified callParams and performs\n /// all the necessary checks for the returned value.\n function _checkedCallRecipient(\n address recipient,\n address token,\n uint256 amount,\n bytes memory callParams\n )\n internal\n {\n bytes memory hookData =\n abi.encodeCall(IFastBridgeRecipient.fastBridgeTransferReceived, (token, amount, callParams));\n // This will bubble any revert messages from the hook function\n bytes memory returnData = Address.functionCallWithValue({target: recipient, data: hookData, value: msg.value});\n // Explicit revert if no return data at all\n if (returnData.length == 0) revert RecipientNoReturnValue();\n // Check that exactly a single return value was returned\n if (returnData.length != 32) revert RecipientIncorrectReturnValue();\n // Return value should be abi-encoded hook function selector\n if (bytes32(returnData) != bytes32(IFastBridgeRecipient.fastBridgeTransferReceived.selector)) {\n revert RecipientIncorrectReturnValue();\n }\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint40(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint40).max but\n /// proof.timestamp \u003c type(uint40).max via unchecked statement\n /// @param proofBlockTimestamp The bridge proof block timestamp\n /// @return delta Time delta since proof submitted\n function _timeSince(uint40 proofBlockTimestamp) internal view returns (uint256 delta) {\n unchecked {\n delta = uint40(block.timestamp) - proofBlockTimestamp;\n }\n }\n\n /// @notice Performs all the necessary checks for a bridge to happen.\n /// @dev There's no good way to refactor this function to reduce cyclomatic complexity due to\n /// the number of checks that need to be performed, so we skip the code-complexity rule here.\n // solhint-disable-next-line code-complexity\n function _validateBridgeParams(\n BridgeParams memory params,\n BridgeParamsV2 memory paramsV2,\n int256 exclusivityEndTime\n )\n internal\n view\n {\n // Check V1 (legacy) params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.sender == address(0) || params.to == address(0)) revert ZeroAddress();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n // Check V2 params\n if (paramsV2.callParams.length \u003e MAX_CALL_PARAMS_LENGTH) revert CallParamsLengthAboveMax();\n if (paramsV2.callValue != 0 \u0026\u0026 params.destToken == UniversalTokenLib.ETH_ADDRESS) {\n revert NativeTokenCallValueNotSupported();\n }\n // exclusivityEndTime must be in range (0 .. params.deadline]\n if (exclusivityEndTime \u003c= 0 || exclusivityEndTime \u003e int256(params.deadline)) {\n revert ExclusivityParamsIncorrect();\n }\n }\n\n /// @notice Performs all the necessary checks for a relay to happen.\n function _validateRelayParams(\n BridgeTransactionV2 memory transaction,\n bytes32 transactionId,\n address relayer\n )\n internal\n view\n {\n if (relayer == address(0)) revert ZeroAddress();\n // Check if the transaction has already been relayed\n if (bridgeRelays(transactionId)) revert TransactionRelayed();\n if (transaction.destChainId != uint32(block.chainid)) revert ChainIncorrect();\n // Check the deadline for relay to happen\n if (block.timestamp \u003e transaction.deadline) revert DeadlineExceeded();\n // Check the exclusivity period, if it is still ongoing\n // forgefmt: disable-next-item\n if (\n transaction.exclusivityRelayer != address(0) \u0026\u0026\n transaction.exclusivityRelayer != relayer \u0026\u0026\n block.timestamp \u003c= transaction.exclusivityEndTime\n ) {\n revert ExclusivityPeriodNotPassed();\n }\n }\n}\n","language":"Solidity","languageVersion":"0.8.24","compilerVersion":"0.8.24","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../","srcMap":"25827:11640:0:-:0;;;;;;;;;;;;;;;-1:-1:-1;;;25827:11640:0;;;;;;;;;;;;;;;;;","srcMapRuntime":"25827:11640:0:-:0;;;;;;;;","abiDefinition":[],"userDoc":{"kind":"user","methods":{},"version":1},"developerDoc":{"details":"Library for managing https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive types. Sets have the following properties: - Elements are added, removed, and checked for existence in constant time (O(1)). - Elements are enumerated in O(n). No guarantees are made on the ordering. ```solidity contract Example { // Add the library methods using EnumerableSet for EnumerableSet.AddressSet; // Declare a set state variable EnumerableSet.AddressSet private mySet; } ``` As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`) and `uint256` (`UintSet`) are supported. [WARNING] ==== Trying to delete such a structure from storage will likely result in data corruption, rendering the structure unusable. See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info. In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an array of EnumerableSet. ====","kind":"dev","methods":{},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[],\"devdoc\":{\"details\":\"Library for managing https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive types. Sets have the following properties: - Elements are added, removed, and checked for existence in constant time (O(1)). - Elements are enumerated in O(n). No guarantees are made on the ordering. ```solidity contract Example { // Add the library methods using EnumerableSet for EnumerableSet.AddressSet; // Declare a set state variable EnumerableSet.AddressSet private mySet; } ``` As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`) and `uint256` (`UintSet`) are supported. [WARNING] ==== Trying to delete such a structure from storage will likely result in data corruption, rendering the structure unusable. See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info. In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an array of EnumerableSet. ====\",\"kind\":\"dev\",\"methods\":{},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeV2.sol\":\"EnumerableSet\"},\"evmVersion\":\"shanghai\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeV2.sol\":{\"keccak256\":\"0x7cd0f885e80e2bdaa638bc32ae7af7d2e248f99ce4b354c217d0f0f7d7302e0a\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://7ccf28df0bd7b4606986585acd8622ed9b4e81379690061bb66088f0a2270af1\",\"dweb:/ipfs/QmTf7HNdHZkK6vmx8ZgewycQEb72oLD9nPwBpsM5reMstQ\"]}},\"version\":1}"},"hashes":{}},"solidity/FastBridgeV2.sol:FastBridgeV2":{"code":"0x60c06040525f60805234801562000014575f80fd5b5060405162003d2f38038062003d2f83398101604081905262000037916200018e565b80620000445f8262000051565b50504360a05250620001b6565b5f806200005f84846200008c565b9050801562000083575f84815260016020526040902062000081908462000137565b505b90505b92915050565b5f828152602081815260408083206001600160a01b038516845290915281205460ff166200012f575f838152602081815260408083206001600160a01b03861684529091529020805460ff19166001179055620000e63390565b6001600160a01b0316826001600160a01b0316847f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a450600162000086565b505f62000086565b5f62000083836001600160a01b0384165f8181526001830160205260408120546200012f57508154600181810184555f84815260208082209093018490558454848252828601909352604090209190915562000086565b5f602082840312156200019f575f80fd5b81516001600160a01b038116811462000083575f80fd5b60805160a051613b57620001d85f395f6107cf01525f61086c0152613b575ff3fe6080604052600436106102ed575f3560e01c806391ad503911610186578063b13aa2d6116100dc578063ca15c87311610087578063dcf844a711610062578063dcf844a714610a10578063df36bb1314610a3b578063e00a83e014610a50575f80fd5b8063ca15c8731461099f578063ccc57490146109be578063d547741f146109f1575f80fd5b8063bfc7c607116100b7578063bfc7c607146108e2578063c63ff8dd146108f5578063c79371b114610914575f80fd5b8063b13aa2d61461088e578063b250fe6b146108ad578063bf333f2c146108cc575f80fd5b8063a3ec191a1161013c578063ac11fb1a11610117578063ac11fb1a14610810578063add98c701461083c578063affed0e01461085b575f80fd5b8063a3ec191a146107be578063a5bbe22b146105e1578063aa9641ab146107f1575f80fd5b8063926d7d7f1161016c578063926d7d7f146107655780639c9545f014610798578063a217fddf146107ab575f80fd5b806391ad5039146106a557806391d1485414610723575f80fd5b806341fcb6121161024657806363787e52116101f1578063886d36ff116101cc578063886d36ff1461063c5780638f0d6f171461065b5780639010d07c1461066e575f80fd5b806363787e5214610568578063820688d5146105e15780638379a24f146105f6575f80fd5b80635960ccf2116102215780635960ccf2146104ea5780635aa6ccba1461051d5780635eb7d94614610549575f80fd5b806341fcb612146104a357806345851694146104c257806358f85880146104d5575f80fd5b806318e4357d116102a6578063295710ff11610281578063295710ff1461043a5780632f2ff15d1461046557806336568abe14610484575f80fd5b806318e4357d146103d7578063190da595146103f6578063248a9ca31461040c575f80fd5b8063051287bc116102d6578063051287bc1461036657806306f333f2146103a15780630f5f6ed7146103c2575f80fd5b806301ffc9a7146102f157806303ed0ee514610325575b5f80fd5b3480156102fc575f80fd5b5061031061030b366004612e21565b610a65565b60405190151581526020015b60405180910390f35b348015610330575f80fd5b506103587f043c983c49d46f0e102151eaf8085d4a2e6571d5df2d47b013f39bddfd4a639d81565b60405190815260200161031c565b348015610371575f80fd5b50610394610380366004612e60565b5f9081526005602052604090205460ff1690565b60405161031c9190612edd565b3480156103ac575f80fd5b506103c06103bb366004612f0a565b610ac0565b005b3480156103cd575f80fd5b5061035861271081565b3480156103e2575f80fd5b506103c06103f1366004612f41565b610b85565b348015610401575f80fd5b5061035862093a8081565b348015610417575f80fd5b50610358610426366004612e60565b5f9081526020819052604090206001015490565b348015610445575f80fd5b50610358610454366004612f77565b60076020525f908152604090205481565b348015610470575f80fd5b506103c061047f366004612f92565b610cf0565b34801561048f575f80fd5b506103c061049e366004612f92565b610d1a565b3480156104ae575f80fd5b506103c06104bd366004613121565b610d66565b6103c06104d036600461323a565b610fd4565b3480156104e0575f80fd5b5061035860025481565b3480156104f5575f80fd5b506103587fdb9556138406326f00296e13ea2ad7db24ba82381212d816b1a40c23b466b32781565b348015610528575f80fd5b5061053c610537366004613255565b61102c565b60405161031c91906132dc565b348015610554575f80fd5b506103c0610563366004613255565b6110e4565b348015610573575f80fd5b506105d1610582366004612e60565b60056020525f908152604090205460ff811690610100810464ffffffffff16906601000000000000810465ffffffffffff16906c0100000000000000000000000090046001600160a01b031684565b60405161031c94939291906133f0565b3480156105ec575f80fd5b5061035861070881565b348015610601575f80fd5b50610310610610366004612e60565b5f908152600660205260409020546c0100000000000000000000000090046001600160a01b0316151590565b348015610647575f80fd5b506103c0610656366004613431565b6112d5565b6103c0610669366004613255565b6112eb565b348015610679575f80fd5b5061068d610688366004613473565b6112f5565b6040516001600160a01b03909116815260200161031c565b3480156106b0575f80fd5b506106f76106bf366004612e60565b5f90815260056020526040902054610100810464ffffffffff16916c010000000000000000000000009091046001600160a01b031690565b604080516bffffffffffffffffffffffff90931683526001600160a01b0390911660208301520161031c565b34801561072e575f80fd5b5061031061073d366004612f92565b5f918252602082815260408084206001600160a01b0393909316845291905290205460ff1690565b348015610770575f80fd5b506103587fe2b7fb3b832174769106daebcfd6d1970523240dda11281102db9363b83b0dc481565b6103c06107a6366004613121565b611313565b3480156107b6575f80fd5b506103585f81565b3480156107c9575f80fd5b506103587f000000000000000000000000000000000000000000000000000000000000000081565b3480156107fc575f80fd5b5061031061080b366004612f92565b6115c1565b34801561081b575f80fd5b5061082f61082a366004613255565b6116a8565b60405161031c9190613493565b348015610847575f80fd5b506103c0610856366004612e60565b61185b565b348015610866575f80fd5b506103587f000000000000000000000000000000000000000000000000000000000000000081565b348015610899575f80fd5b506103c06108a8366004612e60565b61197a565b3480156108b8575f80fd5b506103c06108c7366004612e60565b611a5c565b3480156108d7575f80fd5b50610358620f424081565b6103c06108f0366004613579565b611ac4565b348015610900575f80fd5b506103c061090f366004613255565b611d3c565b34801561091f575f80fd5b5061097161092e366004612e60565b60066020525f908152604090205465ffffffffffff8082169166010000000000008104909116906c0100000000000000000000000090046001600160a01b031683565b6040805165ffffffffffff94851681529390921660208401526001600160a01b03169082015260600161031c565b3480156109aa575f80fd5b506103586109b9366004612e60565b611d46565b3480156109c9575f80fd5b506103587f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f5581565b3480156109fc575f80fd5b506103c0610a0b366004612f92565b611d5c565b348015610a1b575f80fd5b50610358610a2a366004612f77565b60036020525f908152604090205481565b348015610a46575f80fd5b5061035861ffff81565b348015610a5b575f80fd5b5061035860045481565b5f7fffffffff0000000000000000000000000000000000000000000000000000000082167f5a05180f000000000000000000000000000000000000000000000000000000001480610aba5750610aba82611d80565b92915050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f55610aea81611e16565b6001600160a01b0383165f9081526003602052604081205490819003610b105750505050565b6001600160a01b0384165f81815260036020526040812055610b33908483611e20565b604080516001600160a01b038087168252851660208201529081018290527f244e51bc38c1452fa8aaf487bcb4bca36c2baa3a5fbdb776b1eabd8dc6d277cd9060600160405180910390a1505b505050565b7fe2b7fb3b832174769106daebcfd6d1970523240dda11281102db9363b83b0dc4610baf81611e16565b60015f8581526005602052604090205460ff166004811115610bd357610bd3612e77565b14610c0a576040517f4145817200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f84815260056020908152604091829020805460027fffffffffffffffffffffffffffffffffffffffff0000000000000000000000009091166101004264ffffffffff16027fffffffffffffffffffffffffffffffffffffffff000000000000ffffffffffff161766010000000000004365ffffffffffff160217176bffffffffffffffffffffffff166c010000000000000000000000006001600160a01b0387169081029190911790915582518681529251909287927f4ac8af8a2cd87193d64dfc7a3b8d9923b714ec528b18725d080aa1299be0c5e492918290030190a350505050565b5f82815260208190526040902060010154610d0a81611e16565b610d148383611f3e565b50505050565b6001600160a01b0381163314610d5c576040517f6697b23200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610b808282611f71565b815160208301205f610d778461102c565b905060025f8381526005602052604090205460ff166004811115610d9d57610d9d612e77565b14610dd4576040517f4145817200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600160a01b038316610e10575f828152600560205260409020546c0100000000000000000000000090046001600160a01b03169250610e6f565b5f828152600560205260409020546c0100000000000000000000000090046001600160a01b03163314610e6f576040517f4af43a9000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f8281526005602052604090205461070890610100900464ffffffffff90811642031611610ec9576040517f1992d0bd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f82815260056020526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016600317905561010081015115610f415761010081015160808201516001600160a01b03165f9081526003602052604081208054909190610f3b90849061366e565b90915550505b608081015160c0820151610f5f6001600160a01b0383168683611e20565b5f848152600560209081526040918290205482516001600160a01b038681168252928101859052888316936c010000000000000000000000009092049092169187917f582211c35a2139ac3bbaac74663c6a1f56c6cbb658b41fe11fd45a82074ac678910160405180910390a4505050505050565b611029816040518060a001604052805f6001600160a01b031681526020015f815260200160405180602001604052805f81525081526020015f815260200160405180602001604052805f815250815250611ac4565b50565b6110d0604051806101e001604052805f63ffffffff1681526020015f63ffffffff1681526020015f6001600160a01b031681526020015f6001600160a01b031681526020015f6001600160a01b031681526020015f6001600160a01b031681526020015f81526020015f81526020015f81526020015f81526020015f81526020015f81526020015f6001600160a01b031681526020015f8152602001606081525090565b81806020019051810190610aba91906136d9565b805160208201205f6110f58361102c565b905060015f8381526005602052604090205460ff16600481111561111b5761111b612e77565b14611152576040517f4145817200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b335f9081527fd2043bf65931af3dbecf60d0db8f40e4160406d7beb00522f4200cf4944a1eb8602052604090205460ff16156111cb5780610140015142116111c6576040517fe15ff9ea00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611217565b62093a808161014001516111df919061366e565b4211611217576040517fe15ff9ea00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f8281526005602052604080822080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166004179055820151608083015161010084015160c08501519293919261126f919061366e565b90506112856001600160a01b0383168483611e20565b604080516001600160a01b0384811682526020820184905285169187917fb4c55c0c9bc613519b920e88748090150b890a875d307f21bea7d4fb2e8bc958910160405180910390a3505050505050565b6112e782805190602001208233610b85565b5050565b6110298133611313565b5f82815260016020526040812061130c9083611f9c565b9392505050565b815160208301205f6113248461102c565b9050611331818385611fa7565b604080516060808201835265ffffffffffff438116835242811660208085019182526001600160a01b03808a168688019081525f8a8152600690935296909120945185549251965182166c01000000000000000000000000026bffffffffffffffffffffffff9785166601000000000000027fffffffffffffffffffffffffffffffffffffffff000000000000000000000000909416919094161791909117949094161790915582015160a083015160e084015191929091907fffffffffffffffffffffffff11111111111111111111111111111111111111129083160161148e5761012084015115611450576040517f2598ad2e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b803414611489576040517f81de0bf300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6114e1565b83610120015134146114cc576040517f81de0bf300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6114e16001600160a01b038316338584612149565b6101c08401515115611503576114fe838383876101c001516121c5565b611513565b3415611513576115138334612321565b826001600160a01b0316866001600160a01b0316867ff8ae392d784b1ea5e8881bfa586d81abf07ef4f1e2fc75f7fe51c90f05199a5c875f015188608001518960a001518a60c001518b60e001518c61012001516040516115b09695949392919063ffffffff9690961686526001600160a01b0394851660208701529290931660408501526060840152608083019190915260a082015260c00190565b60405180910390a450505050505050565b5f60025f8481526005602052604090205460ff1660048111156115e6576115e6612e77565b1461161d576040517f4145817200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f838152600560205260409020546001600160a01b038381166c01000000000000000000000000909204161461167f576040517f4af43a9000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b50505f9081526005602052604090205461070861010090910464ffffffffff9081164203161190565b60408051610180810182525f80825260208201819052818301819052606082018190526080820181905260a0820181905260c0820181905260e0820181905261010082018190526101208201819052610140820181905261016082015290517f5aa6ccba0000000000000000000000000000000000000000000000000000000081523090635aa6ccba90611740908590600401613809565b5f60405180830381865afa92505050801561177c57506040513d5f823e601f3d908101601f1916820160405261177991908101906136d9565b60015b6117945781806020019051810190610aba9190613826565b604051806101800160405280825f015163ffffffff168152602001826020015163ffffffff16815260200182604001516001600160a01b0316815260200182606001516001600160a01b0316815260200182608001516001600160a01b031681526020018260a001516001600160a01b031681526020018260c0015181526020018260e00151815260200182610100015181526020018261012001515f1415151581526020018261014001518152602001826101600151815250915050919050565b919050565b7f043c983c49d46f0e102151eaf8085d4a2e6571d5df2d47b013f39bddfd4a639d61188581611e16565b60025f8381526005602052604090205460ff1660048111156118a9576118a9612e77565b146118e0576040517f4145817200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f8281526005602052604090205461070890610100900464ffffffffff908116420316111561193b576040517f3e908aac00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f828152600560205260408082206001905551339184917f0695cf1d39b3055dcd0fe02d8b47eaf0d5a13e1996de925de59d0ef9b7f7fad49190a35050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f556119a481611e16565b612710821115611a15576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f6e657746656552617465203e206d61780000000000000000000000000000000060448201526064015b60405180910390fd5b600280549083905560408051828152602081018590527f14914da2bf76024616fbe1859783fcd4dbddcb179b1f3a854949fbf920dcb95791015b60405180910390a1505050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f55611a8681611e16565b600480549083905560408051828152602081018590527f5cf09b12f3f56b4c564d51b25b40360af6d795198adb61ae0806a36c294323fa9101611a4f565b5f816020015142611ad591906138f0565b9050611ae28383836123e6565b5f611af584606001518560a00151612669565b90505f806002541115611b2157620f424060025483611b149190613917565b611b1e919061392e565b90505b611b2b8183613966565b91505f604051806101e001604052804663ffffffff168152602001875f015163ffffffff16815260200187602001516001600160a01b0316815260200187604001516001600160a01b0316815260200187606001516001600160a01b0316815260200187608001516001600160a01b031681526020018481526020018760c00151815260200183815260200186606001518152602001876101000151815260200160075f89602001516001600160a01b03166001600160a01b031681526020019081526020015f205f815480929190611c0390613979565b919050558152602001865f01516001600160a01b031681526020018581526020018660800151815250604051602001611c3c91906132dc565b60408051808303601f1901815282825280516020808301919091205f818152600583529390932080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016600117905589015189516060808c015160808d015160c08e0151928d015195985095966001600160a01b039094169587957f120ea0364f36cdac7983bcfdd55270ca09d7f9b314a2ebc425a3b01ab1d6403a95611cef958b95909493928e92901515906139b0565b60405180910390a3807f3120e2bb59c86aca6890191a589a96af3662838efa374fbdcdf4c95bfe4a6c0e8760400151604051611d2b9190613809565b60405180910390a250505050505050565b611029815f610d66565b5f818152600160205260408120610aba9061280d565b5f82815260208190526040902060010154611d7681611e16565b610d148383611f71565b5f7fffffffff0000000000000000000000000000000000000000000000000000000082167f7965db0b000000000000000000000000000000000000000000000000000000001480610aba57507f01ffc9a7000000000000000000000000000000000000000000000000000000007fffffffff00000000000000000000000000000000000000000000000000000000831614610aba565b6110298133612816565b306001600160a01b03831603611e3557505050565b805f03611e4157505050565b7fffffffffffffffffffffffff11111111111111111111111111111111111111126001600160a01b03841601611f2a575f826001600160a01b0316826040515f6040518083038185875af1925050503d805f8114611eba576040519150601f19603f3d011682016040523d82523d5f602084013e611ebf565b606091505b5050905080610d14576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f455448207472616e73666572206661696c6564000000000000000000000000006044820152606401611a0c565b610b806001600160a01b0384168383612881565b5f80611f4a84846128b2565b9050801561130c575f848152600160205260409020611f699084612977565b509392505050565b5f80611f7d848461298b565b9050801561130c575f848152600160205260409020611f699084612a2a565b5f61130c8383612a3e565b6001600160a01b038116611fe7576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f828152600660205260409020546c0100000000000000000000000090046001600160a01b031615612045576040517fbef7bb7d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b4663ffffffff16836020015163ffffffff161461208e576040517f7029fdf900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8261014001514211156120cd576040517f559895a300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6101808301516001600160a01b0316158015906121015750806001600160a01b03168361018001516001600160a01b031614155b80156121125750826101a001514211155b15610b80576040517f14be123200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040516001600160a01b038481166024830152838116604483015260648201839052610d149186918216906323b872dd906084015b604051602081830303815290604052915060e01b6020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8381831617835250505050612a64565b5f8383836040516024016121db93929190613a05565b60408051601f198184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f461e0c210000000000000000000000000000000000000000000000000000000017905290505f612241868334612ade565b905080515f0361227d576040517f1a95ad2600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80516020146122b8576040517ff3725cca00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f461e0c21000000000000000000000000000000000000000000000000000000006122e282613a35565b14612319576040517ff3725cca00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b505050505050565b8047101561235d576040517fcd786059000000000000000000000000000000000000000000000000000000008152306004820152602401611a0c565b5f826001600160a01b0316826040515f6040518083038185875af1925050503d805f81146123a6576040519150601f19603f3d011682016040523d82523d5f602084013e6123ab565b606091505b5050905080610b80576040517f1425ea4200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b46835f015163ffffffff1603612428576040517f7029fdf900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60a0830151158061243b575060c0830151155b15612472576040517fe38820c800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60208301516001600160a01b03161580612497575060408301516001600160a01b0316155b156124ce576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60608301516001600160a01b031615806124f3575060808301516001600160a01b0316155b1561252a576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6125366107084261366e565b8361010001511015612574576040517f04b7fcc800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61ffff82608001515111156125b5576040517ffbe24d4900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6060820151158015906125e8575060808301516001600160a01b031673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee145b1561261f576040517f2598ad2e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f81131580612632575082610100015181135b15610b80576040517f352807b900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f7fffffffffffffffffffffffff11111111111111111111111111111111111111126001600160a01b038416016126da573482146126d3576040517f81de0bf300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5034610aba565b6126ec836001600160a01b0316612b90565b6040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201526001600160a01b038416906370a0823190602401602060405180830381865afa158015612747573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061276b9190613a7a565b90506127826001600160a01b038416333085612149565b6040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015281906001600160a01b038516906370a0823190602401602060405180830381865afa1580156127df573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906128039190613a7a565b61130c9190613966565b5f610aba825490565b5f828152602081815260408083206001600160a01b038516845290915290205460ff166112e7576040517fe2517d3f0000000000000000000000000000000000000000000000000000000081526001600160a01b038216600482015260248101839052604401611a0c565b6040516001600160a01b03838116602483015260448201839052610b8091859182169063a9059cbb9060640161217e565b5f828152602081815260408083206001600160a01b038516845290915281205460ff16612970575f838152602081815260408083206001600160a01b0386168452909152902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790556129283390565b6001600160a01b0316826001600160a01b0316847f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a4506001610aba565b505f610aba565b5f61130c836001600160a01b038416612c35565b5f828152602081815260408083206001600160a01b038516845290915281205460ff1615612970575f838152602081815260408083206001600160a01b038616808552925280832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016905551339286917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a4506001610aba565b5f61130c836001600160a01b038416612c7a565b5f825f018281548110612a5357612a53613a91565b905f5260205f200154905092915050565b5f612a786001600160a01b03841683612d5d565b905080515f14158015612a9c575080806020019051810190612a9a9190613abe565b155b15610b80576040517f5274afe70000000000000000000000000000000000000000000000000000000081526001600160a01b0384166004820152602401611a0c565b606081471015612b1c576040517fcd786059000000000000000000000000000000000000000000000000000000008152306004820152602401611a0c565b5f80856001600160a01b03168486604051612b379190613ad9565b5f6040518083038185875af1925050503d805f8114612b71576040519150601f19603f3d011682016040523d82523d5f602084013e612b76565b606091505b5091509150612b86868383612d6a565b9695505050505050565b7fffffffffffffffffffffffff11111111111111111111111111111111111111126001600160a01b03821601612bf2576040517f7f523fe800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b806001600160a01b03163b5f03611029576040517f7f523fe800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f81815260018301602052604081205461297057508154600181810184555f848152602080822090930184905584548482528286019093526040902091909155610aba565b5f8181526001830160205260408120548015612d54575f612c9c600183613966565b85549091505f90612caf90600190613966565b9050808214612d0e575f865f018281548110612ccd57612ccd613a91565b905f5260205f200154905080875f018481548110612ced57612ced613a91565b5f918252602080832090910192909255918252600188019052604090208390555b8554869080612d1f57612d1f613af4565b600190038181905f5260205f20015f90559055856001015f8681526020019081526020015f205f905560019350505050610aba565b5f915050610aba565b606061130c83835f612ade565b606082612d7f57612d7a82612ddf565b61130c565b8151158015612d9657506001600160a01b0384163b155b15612dd8576040517f9996b3150000000000000000000000000000000000000000000000000000000081526001600160a01b0385166004820152602401611a0c565b508061130c565b805115612def5780518082602001fd5b6040517f1425ea4200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f60208284031215612e31575f80fd5b81357fffffffff000000000000000000000000000000000000000000000000000000008116811461130c575f80fd5b5f60208284031215612e70575f80fd5b5035919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602160045260245ffd5b60058110612ed9577f4e487b71000000000000000000000000000000000000000000000000000000005f52602160045260245ffd5b9052565b60208101610aba8284612ea4565b6001600160a01b0381168114611029575f80fd5b803561185681612eeb565b5f8060408385031215612f1b575f80fd5b8235612f2681612eeb565b91506020830135612f3681612eeb565b809150509250929050565b5f805f60608486031215612f53575f80fd5b83359250602084013591506040840135612f6c81612eeb565b809150509250925092565b5f60208284031215612f87575f80fd5b813561130c81612eeb565b5f8060408385031215612fa3575f80fd5b823591506020830135612f3681612eeb565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b604051610120810167ffffffffffffffff8111828210171561300657613006612fb5565b60405290565b60405160a0810167ffffffffffffffff8111828210171561300657613006612fb5565b6040516101e0810167ffffffffffffffff8111828210171561300657613006612fb5565b604051610180810167ffffffffffffffff8111828210171561300657613006612fb5565b604051601f8201601f1916810167ffffffffffffffff811182821017156130a0576130a0612fb5565b604052919050565b5f67ffffffffffffffff8211156130c1576130c1612fb5565b50601f01601f191660200190565b5f82601f8301126130de575f80fd5b81356130f16130ec826130a8565b613077565b818152846020838601011115613105575f80fd5b816020850160208301375f918101602001919091529392505050565b5f8060408385031215613132575f80fd5b823567ffffffffffffffff811115613148575f80fd5b613154858286016130cf565b9250506020830135612f3681612eeb565b63ffffffff81168114611029575f80fd5b803561185681613165565b8015158114611029575f80fd5b803561185681613181565b5f61012082840312156131aa575f80fd5b6131b2612fe2565b90506131bd82613176565b81526131cb60208301612eff565b60208201526131dc60408301612eff565b60408201526131ed60608301612eff565b60608201526131fe60808301612eff565b608082015260a082013560a082015260c082013560c082015261322360e0830161318e565b60e082015261010080830135818301525092915050565b5f610120828403121561324b575f80fd5b61130c8383613199565b5f60208284031215613265575f80fd5b813567ffffffffffffffff81111561327b575f80fd5b613287848285016130cf565b949350505050565b5f5b838110156132a9578181015183820152602001613291565b50505f910152565b5f81518084526132c881602086016020860161328f565b601f01601f19169290920160200192915050565b602081526132f360208201835163ffffffff169052565b5f602083015161330b604084018263ffffffff169052565b5060408301516001600160a01b03811660608401525060608301516001600160a01b03811660808401525060808301516001600160a01b03811660a08401525060a08301516001600160a01b03811660c08401525060c083015160e08381019190915283015161010080840191909152830151610120808401919091528301516101408084019190915283015161016080840191909152830151610180808401919091528301516101a06133c9818501836001600160a01b03169052565b8401516101c0848101919091528401516101e08085015290506132876102008401826132b1565b608081016133fe8287612ea4565b64ffffffffff8516602083015265ffffffffffff841660408301526001600160a01b038316606083015295945050505050565b5f8060408385031215613442575f80fd5b823567ffffffffffffffff811115613458575f80fd5b613464858286016130cf565b95602094909401359450505050565b5f8060408385031215613484575f80fd5b50508035926020909101359150565b815163ffffffff168152610180810160208301516134b9602084018263ffffffff169052565b5060408301516134d460408401826001600160a01b03169052565b5060608301516134ef60608401826001600160a01b03169052565b50608083015161350a60808401826001600160a01b03169052565b5060a083015161352560a08401826001600160a01b03169052565b5060c083015160c083015260e083015160e08301526101008084015181840152506101208084015161355a8285018215159052565b5050610140838101519083015261016092830151929091019190915290565b5f80610140838503121561358b575f80fd5b6135958484613199565b915061012083013567ffffffffffffffff808211156135b2575f80fd5b9084019060a082870312156135c5575f80fd5b6135cd61300c565b82356135d881612eeb565b8152602083810135908201526040830135828111156135f5575f80fd5b613601888286016130cf565b60408301525060608301356060820152608083013582811115613622575f80fd5b61362e888286016130cf565b6080830152508093505050509250929050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b80820180821115610aba57610aba613641565b805161185681613165565b805161185681612eeb565b5f82601f8301126136a6575f80fd5b81516136b46130ec826130a8565b8181528460208386010111156136c8575f80fd5b61328782602083016020870161328f565b5f602082840312156136e9575f80fd5b815167ffffffffffffffff80821115613700575f80fd5b908301906101e08286031215613714575f80fd5b61371c61302f565b61372583613681565b815261373360208401613681565b60208201526137446040840161368c565b60408201526137556060840161368c565b60608201526137666080840161368c565b608082015261377760a0840161368c565b60a082015260c0838101519082015260e0808401519082015261010080840151908201526101208084015190820152610140808401519082015261016080840151908201526101806137ca81850161368c565b908201526101a083810151908201526101c080840151838111156137ec575f80fd5b6137f888828701613697565b918301919091525095945050505050565b602081525f61130c60208301846132b1565b805161185681613181565b5f6101808284031215613837575f80fd5b61383f613053565b61384883613681565b815261385660208401613681565b60208201526138676040840161368c565b60408201526138786060840161368c565b60608201526138896080840161368c565b608082015261389a60a0840161368c565b60a082015260c083015160c082015260e083015160e08201526101008084015181830152506101206138cd81850161381b565b908201526101408381015190820152610160928301519281019290925250919050565b8082018281125f83128015821682158216171561390f5761390f613641565b505092915050565b8082028115828204841417610aba57610aba613641565b5f82613961577f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b500490565b81810381811115610aba57610aba613641565b5f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82036139a9576139a9613641565b5060010190565b60e081525f6139c260e083018a6132b1565b63ffffffff989098166020830152506001600160a01b039586166040820152939094166060840152608083019190915260a082015290151560c090910152919050565b6001600160a01b0384168152826020820152606060408201525f613a2c60608301846132b1565b95945050505050565b80516020808301519190811015613a74577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8160200360031b1b821691505b50919050565b5f60208284031215613a8a575f80fd5b5051919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b5f60208284031215613ace575f80fd5b815161130c81613181565b5f8251613aea81846020870161328f565b9190910192915050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603160045260245ffdfea264697066735822122007a09ea15c5efbb28f239593161aeb6ee596d67bad8a87d0cd46703d115a053164736f6c63430008180033","runtime-code":"0x6080604052600436106102ed575f3560e01c806391ad503911610186578063b13aa2d6116100dc578063ca15c87311610087578063dcf844a711610062578063dcf844a714610a10578063df36bb1314610a3b578063e00a83e014610a50575f80fd5b8063ca15c8731461099f578063ccc57490146109be578063d547741f146109f1575f80fd5b8063bfc7c607116100b7578063bfc7c607146108e2578063c63ff8dd146108f5578063c79371b114610914575f80fd5b8063b13aa2d61461088e578063b250fe6b146108ad578063bf333f2c146108cc575f80fd5b8063a3ec191a1161013c578063ac11fb1a11610117578063ac11fb1a14610810578063add98c701461083c578063affed0e01461085b575f80fd5b8063a3ec191a146107be578063a5bbe22b146105e1578063aa9641ab146107f1575f80fd5b8063926d7d7f1161016c578063926d7d7f146107655780639c9545f014610798578063a217fddf146107ab575f80fd5b806391ad5039146106a557806391d1485414610723575f80fd5b806341fcb6121161024657806363787e52116101f1578063886d36ff116101cc578063886d36ff1461063c5780638f0d6f171461065b5780639010d07c1461066e575f80fd5b806363787e5214610568578063820688d5146105e15780638379a24f146105f6575f80fd5b80635960ccf2116102215780635960ccf2146104ea5780635aa6ccba1461051d5780635eb7d94614610549575f80fd5b806341fcb612146104a357806345851694146104c257806358f85880146104d5575f80fd5b806318e4357d116102a6578063295710ff11610281578063295710ff1461043a5780632f2ff15d1461046557806336568abe14610484575f80fd5b806318e4357d146103d7578063190da595146103f6578063248a9ca31461040c575f80fd5b8063051287bc116102d6578063051287bc1461036657806306f333f2146103a15780630f5f6ed7146103c2575f80fd5b806301ffc9a7146102f157806303ed0ee514610325575b5f80fd5b3480156102fc575f80fd5b5061031061030b366004612e21565b610a65565b60405190151581526020015b60405180910390f35b348015610330575f80fd5b506103587f043c983c49d46f0e102151eaf8085d4a2e6571d5df2d47b013f39bddfd4a639d81565b60405190815260200161031c565b348015610371575f80fd5b50610394610380366004612e60565b5f9081526005602052604090205460ff1690565b60405161031c9190612edd565b3480156103ac575f80fd5b506103c06103bb366004612f0a565b610ac0565b005b3480156103cd575f80fd5b5061035861271081565b3480156103e2575f80fd5b506103c06103f1366004612f41565b610b85565b348015610401575f80fd5b5061035862093a8081565b348015610417575f80fd5b50610358610426366004612e60565b5f9081526020819052604090206001015490565b348015610445575f80fd5b50610358610454366004612f77565b60076020525f908152604090205481565b348015610470575f80fd5b506103c061047f366004612f92565b610cf0565b34801561048f575f80fd5b506103c061049e366004612f92565b610d1a565b3480156104ae575f80fd5b506103c06104bd366004613121565b610d66565b6103c06104d036600461323a565b610fd4565b3480156104e0575f80fd5b5061035860025481565b3480156104f5575f80fd5b506103587fdb9556138406326f00296e13ea2ad7db24ba82381212d816b1a40c23b466b32781565b348015610528575f80fd5b5061053c610537366004613255565b61102c565b60405161031c91906132dc565b348015610554575f80fd5b506103c0610563366004613255565b6110e4565b348015610573575f80fd5b506105d1610582366004612e60565b60056020525f908152604090205460ff811690610100810464ffffffffff16906601000000000000810465ffffffffffff16906c0100000000000000000000000090046001600160a01b031684565b60405161031c94939291906133f0565b3480156105ec575f80fd5b5061035861070881565b348015610601575f80fd5b50610310610610366004612e60565b5f908152600660205260409020546c0100000000000000000000000090046001600160a01b0316151590565b348015610647575f80fd5b506103c0610656366004613431565b6112d5565b6103c0610669366004613255565b6112eb565b348015610679575f80fd5b5061068d610688366004613473565b6112f5565b6040516001600160a01b03909116815260200161031c565b3480156106b0575f80fd5b506106f76106bf366004612e60565b5f90815260056020526040902054610100810464ffffffffff16916c010000000000000000000000009091046001600160a01b031690565b604080516bffffffffffffffffffffffff90931683526001600160a01b0390911660208301520161031c565b34801561072e575f80fd5b5061031061073d366004612f92565b5f918252602082815260408084206001600160a01b0393909316845291905290205460ff1690565b348015610770575f80fd5b506103587fe2b7fb3b832174769106daebcfd6d1970523240dda11281102db9363b83b0dc481565b6103c06107a6366004613121565b611313565b3480156107b6575f80fd5b506103585f81565b3480156107c9575f80fd5b506103587f000000000000000000000000000000000000000000000000000000000000000081565b3480156107fc575f80fd5b5061031061080b366004612f92565b6115c1565b34801561081b575f80fd5b5061082f61082a366004613255565b6116a8565b60405161031c9190613493565b348015610847575f80fd5b506103c0610856366004612e60565b61185b565b348015610866575f80fd5b506103587f000000000000000000000000000000000000000000000000000000000000000081565b348015610899575f80fd5b506103c06108a8366004612e60565b61197a565b3480156108b8575f80fd5b506103c06108c7366004612e60565b611a5c565b3480156108d7575f80fd5b50610358620f424081565b6103c06108f0366004613579565b611ac4565b348015610900575f80fd5b506103c061090f366004613255565b611d3c565b34801561091f575f80fd5b5061097161092e366004612e60565b60066020525f908152604090205465ffffffffffff8082169166010000000000008104909116906c0100000000000000000000000090046001600160a01b031683565b6040805165ffffffffffff94851681529390921660208401526001600160a01b03169082015260600161031c565b3480156109aa575f80fd5b506103586109b9366004612e60565b611d46565b3480156109c9575f80fd5b506103587f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f5581565b3480156109fc575f80fd5b506103c0610a0b366004612f92565b611d5c565b348015610a1b575f80fd5b50610358610a2a366004612f77565b60036020525f908152604090205481565b348015610a46575f80fd5b5061035861ffff81565b348015610a5b575f80fd5b5061035860045481565b5f7fffffffff0000000000000000000000000000000000000000000000000000000082167f5a05180f000000000000000000000000000000000000000000000000000000001480610aba5750610aba82611d80565b92915050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f55610aea81611e16565b6001600160a01b0383165f9081526003602052604081205490819003610b105750505050565b6001600160a01b0384165f81815260036020526040812055610b33908483611e20565b604080516001600160a01b038087168252851660208201529081018290527f244e51bc38c1452fa8aaf487bcb4bca36c2baa3a5fbdb776b1eabd8dc6d277cd9060600160405180910390a1505b505050565b7fe2b7fb3b832174769106daebcfd6d1970523240dda11281102db9363b83b0dc4610baf81611e16565b60015f8581526005602052604090205460ff166004811115610bd357610bd3612e77565b14610c0a576040517f4145817200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f84815260056020908152604091829020805460027fffffffffffffffffffffffffffffffffffffffff0000000000000000000000009091166101004264ffffffffff16027fffffffffffffffffffffffffffffffffffffffff000000000000ffffffffffff161766010000000000004365ffffffffffff160217176bffffffffffffffffffffffff166c010000000000000000000000006001600160a01b0387169081029190911790915582518681529251909287927f4ac8af8a2cd87193d64dfc7a3b8d9923b714ec528b18725d080aa1299be0c5e492918290030190a350505050565b5f82815260208190526040902060010154610d0a81611e16565b610d148383611f3e565b50505050565b6001600160a01b0381163314610d5c576040517f6697b23200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610b808282611f71565b815160208301205f610d778461102c565b905060025f8381526005602052604090205460ff166004811115610d9d57610d9d612e77565b14610dd4576040517f4145817200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600160a01b038316610e10575f828152600560205260409020546c0100000000000000000000000090046001600160a01b03169250610e6f565b5f828152600560205260409020546c0100000000000000000000000090046001600160a01b03163314610e6f576040517f4af43a9000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f8281526005602052604090205461070890610100900464ffffffffff90811642031611610ec9576040517f1992d0bd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f82815260056020526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016600317905561010081015115610f415761010081015160808201516001600160a01b03165f9081526003602052604081208054909190610f3b90849061366e565b90915550505b608081015160c0820151610f5f6001600160a01b0383168683611e20565b5f848152600560209081526040918290205482516001600160a01b038681168252928101859052888316936c010000000000000000000000009092049092169187917f582211c35a2139ac3bbaac74663c6a1f56c6cbb658b41fe11fd45a82074ac678910160405180910390a4505050505050565b611029816040518060a001604052805f6001600160a01b031681526020015f815260200160405180602001604052805f81525081526020015f815260200160405180602001604052805f815250815250611ac4565b50565b6110d0604051806101e001604052805f63ffffffff1681526020015f63ffffffff1681526020015f6001600160a01b031681526020015f6001600160a01b031681526020015f6001600160a01b031681526020015f6001600160a01b031681526020015f81526020015f81526020015f81526020015f81526020015f81526020015f81526020015f6001600160a01b031681526020015f8152602001606081525090565b81806020019051810190610aba91906136d9565b805160208201205f6110f58361102c565b905060015f8381526005602052604090205460ff16600481111561111b5761111b612e77565b14611152576040517f4145817200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b335f9081527fd2043bf65931af3dbecf60d0db8f40e4160406d7beb00522f4200cf4944a1eb8602052604090205460ff16156111cb5780610140015142116111c6576040517fe15ff9ea00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611217565b62093a808161014001516111df919061366e565b4211611217576040517fe15ff9ea00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f8281526005602052604080822080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166004179055820151608083015161010084015160c08501519293919261126f919061366e565b90506112856001600160a01b0383168483611e20565b604080516001600160a01b0384811682526020820184905285169187917fb4c55c0c9bc613519b920e88748090150b890a875d307f21bea7d4fb2e8bc958910160405180910390a3505050505050565b6112e782805190602001208233610b85565b5050565b6110298133611313565b5f82815260016020526040812061130c9083611f9c565b9392505050565b815160208301205f6113248461102c565b9050611331818385611fa7565b604080516060808201835265ffffffffffff438116835242811660208085019182526001600160a01b03808a168688019081525f8a8152600690935296909120945185549251965182166c01000000000000000000000000026bffffffffffffffffffffffff9785166601000000000000027fffffffffffffffffffffffffffffffffffffffff000000000000000000000000909416919094161791909117949094161790915582015160a083015160e084015191929091907fffffffffffffffffffffffff11111111111111111111111111111111111111129083160161148e5761012084015115611450576040517f2598ad2e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b803414611489576040517f81de0bf300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6114e1565b83610120015134146114cc576040517f81de0bf300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6114e16001600160a01b038316338584612149565b6101c08401515115611503576114fe838383876101c001516121c5565b611513565b3415611513576115138334612321565b826001600160a01b0316866001600160a01b0316867ff8ae392d784b1ea5e8881bfa586d81abf07ef4f1e2fc75f7fe51c90f05199a5c875f015188608001518960a001518a60c001518b60e001518c61012001516040516115b09695949392919063ffffffff9690961686526001600160a01b0394851660208701529290931660408501526060840152608083019190915260a082015260c00190565b60405180910390a450505050505050565b5f60025f8481526005602052604090205460ff1660048111156115e6576115e6612e77565b1461161d576040517f4145817200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f838152600560205260409020546001600160a01b038381166c01000000000000000000000000909204161461167f576040517f4af43a9000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b50505f9081526005602052604090205461070861010090910464ffffffffff9081164203161190565b60408051610180810182525f80825260208201819052818301819052606082018190526080820181905260a0820181905260c0820181905260e0820181905261010082018190526101208201819052610140820181905261016082015290517f5aa6ccba0000000000000000000000000000000000000000000000000000000081523090635aa6ccba90611740908590600401613809565b5f60405180830381865afa92505050801561177c57506040513d5f823e601f3d908101601f1916820160405261177991908101906136d9565b60015b6117945781806020019051810190610aba9190613826565b604051806101800160405280825f015163ffffffff168152602001826020015163ffffffff16815260200182604001516001600160a01b0316815260200182606001516001600160a01b0316815260200182608001516001600160a01b031681526020018260a001516001600160a01b031681526020018260c0015181526020018260e00151815260200182610100015181526020018261012001515f1415151581526020018261014001518152602001826101600151815250915050919050565b919050565b7f043c983c49d46f0e102151eaf8085d4a2e6571d5df2d47b013f39bddfd4a639d61188581611e16565b60025f8381526005602052604090205460ff1660048111156118a9576118a9612e77565b146118e0576040517f4145817200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f8281526005602052604090205461070890610100900464ffffffffff908116420316111561193b576040517f3e908aac00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f828152600560205260408082206001905551339184917f0695cf1d39b3055dcd0fe02d8b47eaf0d5a13e1996de925de59d0ef9b7f7fad49190a35050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f556119a481611e16565b612710821115611a15576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f6e657746656552617465203e206d61780000000000000000000000000000000060448201526064015b60405180910390fd5b600280549083905560408051828152602081018590527f14914da2bf76024616fbe1859783fcd4dbddcb179b1f3a854949fbf920dcb95791015b60405180910390a1505050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f55611a8681611e16565b600480549083905560408051828152602081018590527f5cf09b12f3f56b4c564d51b25b40360af6d795198adb61ae0806a36c294323fa9101611a4f565b5f816020015142611ad591906138f0565b9050611ae28383836123e6565b5f611af584606001518560a00151612669565b90505f806002541115611b2157620f424060025483611b149190613917565b611b1e919061392e565b90505b611b2b8183613966565b91505f604051806101e001604052804663ffffffff168152602001875f015163ffffffff16815260200187602001516001600160a01b0316815260200187604001516001600160a01b0316815260200187606001516001600160a01b0316815260200187608001516001600160a01b031681526020018481526020018760c00151815260200183815260200186606001518152602001876101000151815260200160075f89602001516001600160a01b03166001600160a01b031681526020019081526020015f205f815480929190611c0390613979565b919050558152602001865f01516001600160a01b031681526020018581526020018660800151815250604051602001611c3c91906132dc565b60408051808303601f1901815282825280516020808301919091205f818152600583529390932080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016600117905589015189516060808c015160808d015160c08e0151928d015195985095966001600160a01b039094169587957f120ea0364f36cdac7983bcfdd55270ca09d7f9b314a2ebc425a3b01ab1d6403a95611cef958b95909493928e92901515906139b0565b60405180910390a3807f3120e2bb59c86aca6890191a589a96af3662838efa374fbdcdf4c95bfe4a6c0e8760400151604051611d2b9190613809565b60405180910390a250505050505050565b611029815f610d66565b5f818152600160205260408120610aba9061280d565b5f82815260208190526040902060010154611d7681611e16565b610d148383611f71565b5f7fffffffff0000000000000000000000000000000000000000000000000000000082167f7965db0b000000000000000000000000000000000000000000000000000000001480610aba57507f01ffc9a7000000000000000000000000000000000000000000000000000000007fffffffff00000000000000000000000000000000000000000000000000000000831614610aba565b6110298133612816565b306001600160a01b03831603611e3557505050565b805f03611e4157505050565b7fffffffffffffffffffffffff11111111111111111111111111111111111111126001600160a01b03841601611f2a575f826001600160a01b0316826040515f6040518083038185875af1925050503d805f8114611eba576040519150601f19603f3d011682016040523d82523d5f602084013e611ebf565b606091505b5050905080610d14576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f455448207472616e73666572206661696c6564000000000000000000000000006044820152606401611a0c565b610b806001600160a01b0384168383612881565b5f80611f4a84846128b2565b9050801561130c575f848152600160205260409020611f699084612977565b509392505050565b5f80611f7d848461298b565b9050801561130c575f848152600160205260409020611f699084612a2a565b5f61130c8383612a3e565b6001600160a01b038116611fe7576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f828152600660205260409020546c0100000000000000000000000090046001600160a01b031615612045576040517fbef7bb7d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b4663ffffffff16836020015163ffffffff161461208e576040517f7029fdf900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8261014001514211156120cd576040517f559895a300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6101808301516001600160a01b0316158015906121015750806001600160a01b03168361018001516001600160a01b031614155b80156121125750826101a001514211155b15610b80576040517f14be123200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040516001600160a01b038481166024830152838116604483015260648201839052610d149186918216906323b872dd906084015b604051602081830303815290604052915060e01b6020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8381831617835250505050612a64565b5f8383836040516024016121db93929190613a05565b60408051601f198184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f461e0c210000000000000000000000000000000000000000000000000000000017905290505f612241868334612ade565b905080515f0361227d576040517f1a95ad2600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80516020146122b8576040517ff3725cca00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f461e0c21000000000000000000000000000000000000000000000000000000006122e282613a35565b14612319576040517ff3725cca00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b505050505050565b8047101561235d576040517fcd786059000000000000000000000000000000000000000000000000000000008152306004820152602401611a0c565b5f826001600160a01b0316826040515f6040518083038185875af1925050503d805f81146123a6576040519150601f19603f3d011682016040523d82523d5f602084013e6123ab565b606091505b5050905080610b80576040517f1425ea4200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b46835f015163ffffffff1603612428576040517f7029fdf900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60a0830151158061243b575060c0830151155b15612472576040517fe38820c800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60208301516001600160a01b03161580612497575060408301516001600160a01b0316155b156124ce576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60608301516001600160a01b031615806124f3575060808301516001600160a01b0316155b1561252a576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6125366107084261366e565b8361010001511015612574576040517f04b7fcc800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61ffff82608001515111156125b5576040517ffbe24d4900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6060820151158015906125e8575060808301516001600160a01b031673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee145b1561261f576040517f2598ad2e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f81131580612632575082610100015181135b15610b80576040517f352807b900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f7fffffffffffffffffffffffff11111111111111111111111111111111111111126001600160a01b038416016126da573482146126d3576040517f81de0bf300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5034610aba565b6126ec836001600160a01b0316612b90565b6040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201526001600160a01b038416906370a0823190602401602060405180830381865afa158015612747573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061276b9190613a7a565b90506127826001600160a01b038416333085612149565b6040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015281906001600160a01b038516906370a0823190602401602060405180830381865afa1580156127df573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906128039190613a7a565b61130c9190613966565b5f610aba825490565b5f828152602081815260408083206001600160a01b038516845290915290205460ff166112e7576040517fe2517d3f0000000000000000000000000000000000000000000000000000000081526001600160a01b038216600482015260248101839052604401611a0c565b6040516001600160a01b03838116602483015260448201839052610b8091859182169063a9059cbb9060640161217e565b5f828152602081815260408083206001600160a01b038516845290915281205460ff16612970575f838152602081815260408083206001600160a01b0386168452909152902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790556129283390565b6001600160a01b0316826001600160a01b0316847f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a4506001610aba565b505f610aba565b5f61130c836001600160a01b038416612c35565b5f828152602081815260408083206001600160a01b038516845290915281205460ff1615612970575f838152602081815260408083206001600160a01b038616808552925280832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016905551339286917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a4506001610aba565b5f61130c836001600160a01b038416612c7a565b5f825f018281548110612a5357612a53613a91565b905f5260205f200154905092915050565b5f612a786001600160a01b03841683612d5d565b905080515f14158015612a9c575080806020019051810190612a9a9190613abe565b155b15610b80576040517f5274afe70000000000000000000000000000000000000000000000000000000081526001600160a01b0384166004820152602401611a0c565b606081471015612b1c576040517fcd786059000000000000000000000000000000000000000000000000000000008152306004820152602401611a0c565b5f80856001600160a01b03168486604051612b379190613ad9565b5f6040518083038185875af1925050503d805f8114612b71576040519150601f19603f3d011682016040523d82523d5f602084013e612b76565b606091505b5091509150612b86868383612d6a565b9695505050505050565b7fffffffffffffffffffffffff11111111111111111111111111111111111111126001600160a01b03821601612bf2576040517f7f523fe800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b806001600160a01b03163b5f03611029576040517f7f523fe800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f81815260018301602052604081205461297057508154600181810184555f848152602080822090930184905584548482528286019093526040902091909155610aba565b5f8181526001830160205260408120548015612d54575f612c9c600183613966565b85549091505f90612caf90600190613966565b9050808214612d0e575f865f018281548110612ccd57612ccd613a91565b905f5260205f200154905080875f018481548110612ced57612ced613a91565b5f918252602080832090910192909255918252600188019052604090208390555b8554869080612d1f57612d1f613af4565b600190038181905f5260205f20015f90559055856001015f8681526020019081526020015f205f905560019350505050610aba565b5f915050610aba565b606061130c83835f612ade565b606082612d7f57612d7a82612ddf565b61130c565b8151158015612d9657506001600160a01b0384163b155b15612dd8576040517f9996b3150000000000000000000000000000000000000000000000000000000081526001600160a01b0385166004820152602401611a0c565b508061130c565b805115612def5780518082602001fd5b6040517f1425ea4200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f60208284031215612e31575f80fd5b81357fffffffff000000000000000000000000000000000000000000000000000000008116811461130c575f80fd5b5f60208284031215612e70575f80fd5b5035919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602160045260245ffd5b60058110612ed9577f4e487b71000000000000000000000000000000000000000000000000000000005f52602160045260245ffd5b9052565b60208101610aba8284612ea4565b6001600160a01b0381168114611029575f80fd5b803561185681612eeb565b5f8060408385031215612f1b575f80fd5b8235612f2681612eeb565b91506020830135612f3681612eeb565b809150509250929050565b5f805f60608486031215612f53575f80fd5b83359250602084013591506040840135612f6c81612eeb565b809150509250925092565b5f60208284031215612f87575f80fd5b813561130c81612eeb565b5f8060408385031215612fa3575f80fd5b823591506020830135612f3681612eeb565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b604051610120810167ffffffffffffffff8111828210171561300657613006612fb5565b60405290565b60405160a0810167ffffffffffffffff8111828210171561300657613006612fb5565b6040516101e0810167ffffffffffffffff8111828210171561300657613006612fb5565b604051610180810167ffffffffffffffff8111828210171561300657613006612fb5565b604051601f8201601f1916810167ffffffffffffffff811182821017156130a0576130a0612fb5565b604052919050565b5f67ffffffffffffffff8211156130c1576130c1612fb5565b50601f01601f191660200190565b5f82601f8301126130de575f80fd5b81356130f16130ec826130a8565b613077565b818152846020838601011115613105575f80fd5b816020850160208301375f918101602001919091529392505050565b5f8060408385031215613132575f80fd5b823567ffffffffffffffff811115613148575f80fd5b613154858286016130cf565b9250506020830135612f3681612eeb565b63ffffffff81168114611029575f80fd5b803561185681613165565b8015158114611029575f80fd5b803561185681613181565b5f61012082840312156131aa575f80fd5b6131b2612fe2565b90506131bd82613176565b81526131cb60208301612eff565b60208201526131dc60408301612eff565b60408201526131ed60608301612eff565b60608201526131fe60808301612eff565b608082015260a082013560a082015260c082013560c082015261322360e0830161318e565b60e082015261010080830135818301525092915050565b5f610120828403121561324b575f80fd5b61130c8383613199565b5f60208284031215613265575f80fd5b813567ffffffffffffffff81111561327b575f80fd5b613287848285016130cf565b949350505050565b5f5b838110156132a9578181015183820152602001613291565b50505f910152565b5f81518084526132c881602086016020860161328f565b601f01601f19169290920160200192915050565b602081526132f360208201835163ffffffff169052565b5f602083015161330b604084018263ffffffff169052565b5060408301516001600160a01b03811660608401525060608301516001600160a01b03811660808401525060808301516001600160a01b03811660a08401525060a08301516001600160a01b03811660c08401525060c083015160e08381019190915283015161010080840191909152830151610120808401919091528301516101408084019190915283015161016080840191909152830151610180808401919091528301516101a06133c9818501836001600160a01b03169052565b8401516101c0848101919091528401516101e08085015290506132876102008401826132b1565b608081016133fe8287612ea4565b64ffffffffff8516602083015265ffffffffffff841660408301526001600160a01b038316606083015295945050505050565b5f8060408385031215613442575f80fd5b823567ffffffffffffffff811115613458575f80fd5b613464858286016130cf565b95602094909401359450505050565b5f8060408385031215613484575f80fd5b50508035926020909101359150565b815163ffffffff168152610180810160208301516134b9602084018263ffffffff169052565b5060408301516134d460408401826001600160a01b03169052565b5060608301516134ef60608401826001600160a01b03169052565b50608083015161350a60808401826001600160a01b03169052565b5060a083015161352560a08401826001600160a01b03169052565b5060c083015160c083015260e083015160e08301526101008084015181840152506101208084015161355a8285018215159052565b5050610140838101519083015261016092830151929091019190915290565b5f80610140838503121561358b575f80fd5b6135958484613199565b915061012083013567ffffffffffffffff808211156135b2575f80fd5b9084019060a082870312156135c5575f80fd5b6135cd61300c565b82356135d881612eeb565b8152602083810135908201526040830135828111156135f5575f80fd5b613601888286016130cf565b60408301525060608301356060820152608083013582811115613622575f80fd5b61362e888286016130cf565b6080830152508093505050509250929050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b80820180821115610aba57610aba613641565b805161185681613165565b805161185681612eeb565b5f82601f8301126136a6575f80fd5b81516136b46130ec826130a8565b8181528460208386010111156136c8575f80fd5b61328782602083016020870161328f565b5f602082840312156136e9575f80fd5b815167ffffffffffffffff80821115613700575f80fd5b908301906101e08286031215613714575f80fd5b61371c61302f565b61372583613681565b815261373360208401613681565b60208201526137446040840161368c565b60408201526137556060840161368c565b60608201526137666080840161368c565b608082015261377760a0840161368c565b60a082015260c0838101519082015260e0808401519082015261010080840151908201526101208084015190820152610140808401519082015261016080840151908201526101806137ca81850161368c565b908201526101a083810151908201526101c080840151838111156137ec575f80fd5b6137f888828701613697565b918301919091525095945050505050565b602081525f61130c60208301846132b1565b805161185681613181565b5f6101808284031215613837575f80fd5b61383f613053565b61384883613681565b815261385660208401613681565b60208201526138676040840161368c565b60408201526138786060840161368c565b60608201526138896080840161368c565b608082015261389a60a0840161368c565b60a082015260c083015160c082015260e083015160e08201526101008084015181830152506101206138cd81850161381b565b908201526101408381015190820152610160928301519281019290925250919050565b8082018281125f83128015821682158216171561390f5761390f613641565b505092915050565b8082028115828204841417610aba57610aba613641565b5f82613961577f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b500490565b81810381811115610aba57610aba613641565b5f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82036139a9576139a9613641565b5060010190565b60e081525f6139c260e083018a6132b1565b63ffffffff989098166020830152506001600160a01b039586166040820152939094166060840152608083019190915260a082015290151560c090910152919050565b6001600160a01b0384168152826020820152606060408201525f613a2c60608301846132b1565b95945050505050565b80516020808301519190811015613a74577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8160200360031b1b821691505b50919050565b5f60208284031215613a8a575f80fd5b5051919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b5f60208284031215613ace575f80fd5b815161130c81613181565b5f8251613aea81846020870161328f565b9190910192915050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603160045260245ffdfea264697066735822122007a09ea15c5efbb28f239593161aeb6ee596d67bad8a87d0cd46703d115a053164736f6c63430008180033","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.24 ^0.8.0 ^0.8.20;\n\n// contracts/interfaces/IAdmin.sol\n\ninterface IAdmin {\n // ============ Events ============\n\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n event ChainGasAmountUpdated(uint256 oldChainGasAmount, uint256 newChainGasAmount);\n\n // ============ Methods ============\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n\n function setChainGasAmount(uint256 newChainGasAmount) external;\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IFastBridgeRecipient.sol\n\ninterface IFastBridgeRecipient {\n function fastBridgeTransferReceived(\n address token,\n uint256 amount,\n bytes memory callParams\n )\n external\n payable\n returns (bytes4);\n}\n\n// contracts/interfaces/IFastBridgeV2Errors.sol\n\ninterface IFastBridgeV2Errors {\n error AmountIncorrect();\n error CallParamsLengthAboveMax();\n error ChainIncorrect();\n error ExclusivityParamsIncorrect();\n error MsgValueIncorrect();\n error NativeTokenCallValueNotSupported();\n error SenderIncorrect();\n error StatusIncorrect();\n error ZeroAddress();\n\n error RecipientIncorrectReturnValue();\n error RecipientNoReturnValue();\n\n error DeadlineExceeded();\n error DeadlineNotExceeded();\n error DeadlineTooShort();\n error DisputePeriodNotPassed();\n error DisputePeriodPassed();\n error ExclusivityPeriodNotPassed();\n\n error TransactionRelayed();\n}\n\n// contracts/libs/Errors.sol\n\nerror DeadlineExceeded();\nerror DeadlineNotExceeded();\nerror DeadlineTooShort();\nerror InsufficientOutputAmount();\n\nerror MsgValueIncorrect();\nerror PoolNotFound();\nerror TokenAddressMismatch();\nerror TokenNotContract();\nerror TokenNotETH();\nerror TokensIdentical();\n\nerror ChainIncorrect();\nerror AmountIncorrect();\nerror ZeroAddress();\n\nerror DisputePeriodNotPassed();\nerror DisputePeriodPassed();\nerror SenderIncorrect();\nerror StatusIncorrect();\nerror TransactionIdIncorrect();\nerror TransactionRelayed();\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// contracts/interfaces/IFastBridgeV2.sol\n\ninterface IFastBridgeV2 is IFastBridge {\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n struct BridgeTxDetails {\n BridgeStatus status;\n uint40 proofBlockTimestamp;\n uint48 proofBlockNumber;\n address proofRelayer;\n }\n\n struct BridgeRelay {\n uint48 blockNumber;\n uint48 blockTimestamp;\n address relayer;\n }\n\n /// @notice New params introduced in the FastBridgeV2.\n /// We are passing fields from the older BridgeParams struct outside of this struct\n /// for backwards compatibility.\n /// Note: quoteRelayer and quoteExclusivitySeconds are either both zero (indicating no exclusivity)\n /// or both non-zero (indicating exclusivity for the given period).\n /// Note: callValue \u003e 0 can NOT be used with destToken = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE (ETH_ADDRESS)\n /// @param quoteRelayer Relayer that provided the quote for the transaction\n /// @param quoteExclusivitySeconds Period of time the quote relayer is guaranteed exclusivity after user's deposit\n /// @param quoteId Unique quote identifier used for tracking the quote\n /// @param callValue ETH value to send to the recipient (if any)\n /// @param callParams Parameters for the arbitrary call to the destination recipient (if any)\n struct BridgeParamsV2 {\n address quoteRelayer;\n int256 quoteExclusivitySeconds;\n bytes quoteId;\n uint256 callValue;\n bytes callParams;\n }\n\n /// @notice Updated bridge transaction struct to include parameters introduced in FastBridgeV2.\n /// Note: only `exclusivityRelayer` can fill such a transaction until `exclusivityEndTime`.\n /// TODO: consider changing the encoding scheme to prevent spending extra gas on decoding.\n struct BridgeTransactionV2 {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n uint256 callValue; // ETH value to send to the recipient (if any) - replaces V1's sendChainGas flag\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n address exclusivityRelayer;\n uint256 exclusivityEndTime;\n bytes callParams;\n }\n\n event BridgeQuoteDetails(bytes32 indexed transactionId, bytes quoteId);\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability\n /// to provide temporary exclusivity fill rights for the quote relayer.\n /// @param params The parameters required to bridge\n /// @param paramsV2 The parameters for exclusivity fill rights (optional, can be left empty)\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function relay(bytes memory request, address relayer) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param transactionId The transaction id associated with the encoded bridge transaction to prove\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital.\n /// @notice Can only send funds to the relayer address on the proof.\n /// @param request The encoded bridge transaction to claim on origin chain\n function claim(bytes memory request) external;\n /// @notice Checks if a transaction has been relayed\n /// @param transactionId The ID of the transaction to check\n /// @return True if the transaction has been relayed, false otherwise\n function bridgeRelays(bytes32 transactionId) external view returns (bool);\n\n /// @notice Returns the status of a bridge transaction\n /// @param transactionId The ID of the bridge transaction\n /// @return BridgeStatus Status of the bridge transaction\n function bridgeStatuses(bytes32 transactionId) external view returns (BridgeStatus);\n\n /// @notice Returns the timestamp and relayer of a bridge proof\n /// @param transactionId The ID of the bridge transaction\n /// @return timestamp The timestamp of the bridge proof\n /// @return relayer The relayer address of the bridge proof\n function bridgeProofs(bytes32 transactionId) external view returns (uint96 timestamp, address relayer);\n\n /// @notice Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\n /// @param request The bridge request to decode\n function getBridgeTransactionV2(bytes memory request) external view returns (BridgeTransactionV2 memory);\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// contracts/libs/UniversalToken.sol\n\nlibrary UniversalTokenLib {\n using SafeERC20 for IERC20;\n\n address internal constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Transfers tokens to the given account. Reverts if transfer is not successful.\n /// @dev This might trigger fallback, if ETH is transferred to the contract.\n /// Make sure this can not lead to reentrancy attacks.\n function universalTransfer(address token, address to, uint256 value) internal {\n // Don't do anything, if need to send tokens to this address\n if (to == address(this)) return;\n // Don't do anything, if trying to send zero value\n if (value == 0) return;\n if (token == ETH_ADDRESS) {\n /// @dev Note: this can potentially lead to executing code in `to`.\n // solhint-disable-next-line avoid-low-level-calls\n (bool success,) = to.call{value: value}(\"\");\n require(success, \"ETH transfer failed\");\n } else {\n IERC20(token).safeTransfer(to, value);\n }\n }\n\n /// @notice Issues an infinite allowance to the spender, if the current allowance is insufficient\n /// to spend the given amount.\n function universalApproveInfinity(address token, address spender, uint256 amountToSpend) internal {\n // ETH Chad doesn't require your approval\n if (token == ETH_ADDRESS) return;\n // No-op if allowance is already sufficient\n uint256 allowance = IERC20(token).allowance(address(this), spender);\n if (allowance \u003e= amountToSpend) return;\n // Otherwise, reset approval to 0 and set to max allowance\n if (allowance \u003e 0) IERC20(token).safeDecreaseAllowance(spender, allowance);\n IERC20(token).safeIncreaseAllowance(spender, type(uint256).max);\n }\n\n /// @notice Returns the balance of the given token (or native ETH) for the given account.\n function universalBalanceOf(address token, address account) internal view returns (uint256) {\n if (token == ETH_ADDRESS) {\n return account.balance;\n } else {\n return IERC20(token).balanceOf(account);\n }\n }\n\n /// @dev Checks that token is a contract and not ETH_ADDRESS.\n function assertIsContract(address token) internal view {\n // Check that ETH_ADDRESS was not used (in case this is a predeploy on any of the chains)\n if (token == UniversalTokenLib.ETH_ADDRESS) revert TokenNotContract();\n // Check that token is not an EOA\n if (token.code.length == 0) revert TokenNotContract();\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/Admin.sol\n\ncontract Admin is IAdmin, AccessControlEnumerable {\n using UniversalTokenLib for address;\n\n bytes32 public constant RELAYER_ROLE = keccak256(\"RELAYER_ROLE\");\n bytes32 public constant REFUNDER_ROLE = keccak256(\"REFUNDER_ROLE\");\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n uint256 public constant FEE_BPS = 1e6;\n uint256 public constant FEE_RATE_MAX = 0.01e6; // max 1% on origin amount\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Chain gas amount to forward as rebate if requested\n uint256 public chainGasAmount;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n }\n\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n require(newFeeRate \u003c= FEE_RATE_MAX, \"newFeeRate \u003e max\");\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n token.universalTransfer(recipient, feeAmount);\n emit FeesSwept(token, recipient, feeAmount);\n }\n\n function setChainGasAmount(uint256 newChainGasAmount) external onlyRole(GOVERNOR_ROLE) {\n uint256 oldChainGasAmount = chainGasAmount;\n chainGasAmount = newChainGasAmount;\n emit ChainGasAmountUpdated(oldChainGasAmount, newChainGasAmount);\n }\n}\n\n// contracts/FastBridgeV2.sol\n\n/// @notice FastBridgeV2 is a contract for bridging tokens across chains.\ncontract FastBridgeV2 is Admin, IFastBridgeV2, IFastBridgeV2Errors {\n using SafeERC20 for IERC20;\n using UniversalTokenLib for address;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Delay for a transaction after which it could be permisionlessly refunded\n uint256 public constant REFUND_DELAY = 7 days;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n /// @notice Maximum length of accepted callParams\n uint256 public constant MAX_CALL_PARAMS_LENGTH = 2 ** 16 - 1;\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeTxDetails) public bridgeTxDetails;\n /// @notice Relay details on destination chain\n mapping(bytes32 =\u003e BridgeRelay) public bridgeRelayDetails;\n /// @notice Unique bridge nonces tracked per originSender\n mapping(address =\u003e uint256) public senderNonces;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Replaced by senderNonces\n uint256 public immutable nonce = 0;\n /// @notice the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n bridge({\n params: params,\n paramsV2: BridgeParamsV2({\n quoteRelayer: address(0),\n quoteExclusivitySeconds: 0,\n quoteId: bytes(\"\"),\n callValue: 0,\n callParams: bytes(\"\")\n })\n });\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes memory request) external payable {\n relay({request: request, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes memory request, bytes32 destTxHash) external {\n prove({transactionId: keccak256(request), destTxHash: destTxHash, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridgeV2\n function claim(bytes memory request) external {\n claim({request: request, to: address(0)});\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003e DISPUTE_PERIOD) {\n revert DisputePeriodPassed();\n }\n\n // @dev relayer gets slashed effectively if dest relay has gone thru\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n bridgeTxDetails[transactionId].proofRelayer = address(0);\n bridgeTxDetails[transactionId].proofBlockTimestamp = 0;\n bridgeTxDetails[transactionId].proofBlockNumber = 0;\n\n emit BridgeProofDisputed(transactionId, msg.sender);\n }\n\n /// @inheritdoc IFastBridge\n function refund(bytes memory request) external {\n bytes32 transactionId = keccak256(request);\n\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n\n if (bridgeTxDetails[transactionId].status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n\n if (hasRole(REFUNDER_ROLE, msg.sender)) {\n // Refunder can refund if deadline has passed\n if (block.timestamp \u003c= transaction.deadline) revert DeadlineNotExceeded();\n } else {\n // Permissionless refund is allowed after REFUND_DELAY\n if (block.timestamp \u003c= transaction.deadline + REFUND_DELAY) revert DeadlineNotExceeded();\n }\n\n // if all checks passed, set to REFUNDED status\n bridgeTxDetails[transactionId].status = BridgeStatus.REFUNDED;\n\n // transfer origin collateral back to original sender\n address to = transaction.originSender;\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount + transaction.originFeeAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (bridgeTxDetails[transactionId].proofRelayer != relayer) revert SenderIncorrect();\n return _timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n /// @dev This method is added to achieve backwards compatibility with decoding requests into V1 structs:\n /// - `callValue` is partially reported as a zero/non-zero flag\n /// - `callParams` is ignored\n /// In order to process all kinds of requests use getBridgeTransactionV2 instead.\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory) {\n // Try decoding into V2 struct first. This will revert if V1 struct is passed\n try this.getBridgeTransactionV2(request) returns (BridgeTransactionV2 memory txV2) {\n // Note: we entirely ignore the callParams field, as it was not present in V1\n return BridgeTransaction({\n originChainId: txV2.originChainId,\n destChainId: txV2.destChainId,\n originSender: txV2.originSender,\n destRecipient: txV2.destRecipient,\n originToken: txV2.originToken,\n destToken: txV2.destToken,\n originAmount: txV2.originAmount,\n destAmount: txV2.destAmount,\n originFeeAmount: txV2.originFeeAmount,\n sendChainGas: txV2.callValue != 0,\n deadline: txV2.deadline,\n nonce: txV2.nonce\n });\n } catch {\n // Fallback to V1 struct\n return abi.decode(request, (BridgeTransaction));\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) public payable {\n int256 exclusivityEndTime = int256(block.timestamp) + paramsV2.quoteExclusivitySeconds;\n _validateBridgeParams(params, paramsV2, exclusivityEndTime);\n\n // transfer tokens to bridge contract\n /// @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _pullToken(params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n\n // set status to requested\n bytes memory request = abi.encode(\n BridgeTransactionV2({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n callValue: paramsV2.callValue,\n deadline: params.deadline,\n nonce: senderNonces[params.sender]++, // increment nonce on every bridge\n exclusivityRelayer: paramsV2.quoteRelayer,\n // We checked exclusivityEndTime to be in range (0 .. params.deadline] above, so can safely cast\n exclusivityEndTime: uint256(exclusivityEndTime),\n callParams: paramsV2.callParams\n })\n );\n bytes32 transactionId = keccak256(request);\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n\n emit BridgeRequested({\n transactionId: transactionId,\n sender: params.sender,\n request: request,\n destChainId: params.dstChainId,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n sendChainGas: paramsV2.callValue != 0\n });\n emit BridgeQuoteDetails(transactionId, paramsV2.quoteId);\n }\n\n /// @inheritdoc IFastBridgeV2\n function relay(bytes memory request, address relayer) public payable {\n bytes32 transactionId = keccak256(request);\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n _validateRelayParams(transaction, transactionId, relayer);\n // mark bridge transaction as relayed\n bridgeRelayDetails[transactionId] =\n BridgeRelay({blockNumber: uint48(block.number), blockTimestamp: uint48(block.timestamp), relayer: relayer});\n\n // transfer tokens to recipient on destination chain and do an arbitrary call if requested\n address to = transaction.destRecipient;\n address token = transaction.destToken;\n uint256 amount = transaction.destAmount;\n\n // All state changes have been done at this point, can proceed to the external calls.\n // This follows the checks-effects-interactions pattern to mitigate potential reentrancy attacks.\n if (token == UniversalTokenLib.ETH_ADDRESS) {\n // For ETH non-zero callValue is not allowed\n if (transaction.callValue != 0) revert NativeTokenCallValueNotSupported();\n // Check that the correct msg.value was sent\n if (msg.value != amount) revert MsgValueIncorrect();\n } else {\n // For ERC20s, we check that the correct msg.value was sent\n if (msg.value != transaction.callValue) revert MsgValueIncorrect();\n // We need to transfer the tokens from the Relayer to the recipient first before performing an\n // optional post-transfer arbitrary call.\n IERC20(token).safeTransferFrom(msg.sender, to, amount);\n }\n\n if (transaction.callParams.length != 0) {\n // Arbitrary call requested, perform it while supplying full msg.value to the recipient\n // Note: if token has a fee on transfers, the recipient will have received less than `amount`.\n // This is a very niche edge case and should be handled by the recipient contract.\n _checkedCallRecipient({recipient: to, token: token, amount: amount, callParams: transaction.callParams});\n } else if (msg.value != 0) {\n // No arbitrary call requested, but msg.value was sent. This is either a relay with ETH,\n // or a non-zero callValue request with an ERC20. In both cases, transfer the ETH to the recipient.\n Address.sendValue(payable(to), msg.value);\n }\n\n emit BridgeRelayed({\n transactionId: transactionId,\n relayer: relayer,\n to: to,\n originChainId: transaction.originChainId,\n originToken: transaction.originToken,\n destToken: transaction.destToken,\n originAmount: transaction.originAmount,\n destAmount: transaction.destAmount,\n chainGasAmount: transaction.callValue\n });\n }\n\n /// @inheritdoc IFastBridgeV2\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) public onlyRole(RELAYER_ROLE) {\n // update bridge tx status given proof provided\n if (bridgeTxDetails[transactionId].status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n bridgeTxDetails[transactionId].status = BridgeStatus.RELAYER_PROVED;\n bridgeTxDetails[transactionId].proofBlockTimestamp = uint40(block.timestamp);\n bridgeTxDetails[transactionId].proofBlockNumber = uint48(block.number);\n bridgeTxDetails[transactionId].proofRelayer = relayer;\n\n emit BridgeProofProvided(transactionId, relayer, destTxHash);\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes memory request, address to) public {\n bytes32 transactionId = keccak256(request);\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n\n // update bridge tx status if able to claim origin collateral\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n\n // if \"to\" is zero addr, permissionlessly send funds to proven relayer\n if (to == address(0)) {\n to = bridgeTxDetails[transactionId].proofRelayer;\n } else if (bridgeTxDetails[transactionId].proofRelayer != msg.sender) {\n revert SenderIncorrect();\n }\n\n if (_timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003c= DISPUTE_PERIOD) {\n revert DisputePeriodNotPassed();\n }\n\n bridgeTxDetails[transactionId].status = BridgeStatus.RELAYER_CLAIMED;\n\n // update protocol fees if origin fee amount exists\n if (transaction.originFeeAmount \u003e 0) protocolFees[transaction.originToken] += transaction.originFeeAmount;\n\n // transfer origin collateral less fee to specified address\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositClaimed(transactionId, bridgeTxDetails[transactionId].proofRelayer, to, token, amount);\n }\n\n function bridgeStatuses(bytes32 transactionId) public view returns (BridgeStatus status) {\n return bridgeTxDetails[transactionId].status;\n }\n\n function bridgeProofs(bytes32 transactionId) public view returns (uint96 timestamp, address relayer) {\n timestamp = bridgeTxDetails[transactionId].proofBlockTimestamp;\n relayer = bridgeTxDetails[transactionId].proofRelayer;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeRelays(bytes32 transactionId) public view returns (bool) {\n // has this transactionId been relayed?\n return bridgeRelayDetails[transactionId].relayer != address(0);\n }\n\n /// @inheritdoc IFastBridgeV2\n function getBridgeTransactionV2(bytes memory request) public pure returns (BridgeTransactionV2 memory) {\n return abi.decode(request, (BridgeTransactionV2));\n }\n\n /// @notice Pulls a requested token from the user to this contract.\n function _pullToken(address token, uint256 amount) internal returns (uint256 amountPulled) {\n if (token == UniversalTokenLib.ETH_ADDRESS) {\n // For ETH we just need to check that the supplied msg.value is correct\n if (amount != msg.value) revert MsgValueIncorrect();\n amountPulled = msg.value;\n } else {\n token.assertIsContract();\n // Record token balance before transfer\n amountPulled = IERC20(token).balanceOf(address(this));\n // Token needs to be pulled only if msg.value is zero\n // This way user can specify WETH as the origin asset\n IERC20(token).safeTransferFrom(msg.sender, address(this), amount);\n // Use the difference between the recorded balance and the current balance as the amountPulled\n amountPulled = IERC20(token).balanceOf(address(this)) - amountPulled;\n }\n }\n\n /// @notice Calls the Recipient's hook function with the specified callParams and performs\n /// all the necessary checks for the returned value.\n function _checkedCallRecipient(\n address recipient,\n address token,\n uint256 amount,\n bytes memory callParams\n )\n internal\n {\n bytes memory hookData =\n abi.encodeCall(IFastBridgeRecipient.fastBridgeTransferReceived, (token, amount, callParams));\n // This will bubble any revert messages from the hook function\n bytes memory returnData = Address.functionCallWithValue({target: recipient, data: hookData, value: msg.value});\n // Explicit revert if no return data at all\n if (returnData.length == 0) revert RecipientNoReturnValue();\n // Check that exactly a single return value was returned\n if (returnData.length != 32) revert RecipientIncorrectReturnValue();\n // Return value should be abi-encoded hook function selector\n if (bytes32(returnData) != bytes32(IFastBridgeRecipient.fastBridgeTransferReceived.selector)) {\n revert RecipientIncorrectReturnValue();\n }\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint40(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint40).max but\n /// proof.timestamp \u003c type(uint40).max via unchecked statement\n /// @param proofBlockTimestamp The bridge proof block timestamp\n /// @return delta Time delta since proof submitted\n function _timeSince(uint40 proofBlockTimestamp) internal view returns (uint256 delta) {\n unchecked {\n delta = uint40(block.timestamp) - proofBlockTimestamp;\n }\n }\n\n /// @notice Performs all the necessary checks for a bridge to happen.\n /// @dev There's no good way to refactor this function to reduce cyclomatic complexity due to\n /// the number of checks that need to be performed, so we skip the code-complexity rule here.\n // solhint-disable-next-line code-complexity\n function _validateBridgeParams(\n BridgeParams memory params,\n BridgeParamsV2 memory paramsV2,\n int256 exclusivityEndTime\n )\n internal\n view\n {\n // Check V1 (legacy) params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.sender == address(0) || params.to == address(0)) revert ZeroAddress();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n // Check V2 params\n if (paramsV2.callParams.length \u003e MAX_CALL_PARAMS_LENGTH) revert CallParamsLengthAboveMax();\n if (paramsV2.callValue != 0 \u0026\u0026 params.destToken == UniversalTokenLib.ETH_ADDRESS) {\n revert NativeTokenCallValueNotSupported();\n }\n // exclusivityEndTime must be in range (0 .. params.deadline]\n if (exclusivityEndTime \u003c= 0 || exclusivityEndTime \u003e int256(params.deadline)) {\n revert ExclusivityParamsIncorrect();\n }\n }\n\n /// @notice Performs all the necessary checks for a relay to happen.\n function _validateRelayParams(\n BridgeTransactionV2 memory transaction,\n bytes32 transactionId,\n address relayer\n )\n internal\n view\n {\n if (relayer == address(0)) revert ZeroAddress();\n // Check if the transaction has already been relayed\n if (bridgeRelays(transactionId)) revert TransactionRelayed();\n if (transaction.destChainId != uint32(block.chainid)) revert ChainIncorrect();\n // Check the deadline for relay to happen\n if (block.timestamp \u003e transaction.deadline) revert DeadlineExceeded();\n // Check the exclusivity period, if it is still ongoing\n // forgefmt: disable-next-item\n if (\n transaction.exclusivityRelayer != address(0) \u0026\u0026\n transaction.exclusivityRelayer != relayer \u0026\u0026\n block.timestamp \u003c= transaction.exclusivityEndTime\n ) {\n revert ExclusivityPeriodNotPassed();\n }\n }\n}\n","language":"Solidity","languageVersion":"0.8.24","compilerVersion":"0.8.24","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../","srcMap":"64760:19813:0:-:0;;;65906:1;65873:34;;66011:85;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;66045:6;63675:38;52847:4;66045:6;63675:10;:38::i;:::-;-1:-1:-1;;66077:12:0::1;66063:26;::::0;-1:-1:-1;64760:19813:0;;62160:257;62246:4;;62277:31;62294:4;62300:7;62277:16;:31::i;:::-;62262:46;;62322:7;62318:69;;;62345:18;;;;:12;:18;;;;;:31;;62368:7;62345:22;:31::i;:::-;;62318:69;62403:7;-1:-1:-1;62160:257:0;;;;;:::o;56794:316::-;56871:4;53569:12;;;;;;;;;;;-1:-1:-1;;;;;53569:29:0;;;;;;;;;;;;56887:217;;56930:6;:12;;;;;;;;;;;-1:-1:-1;;;;;56930:29:0;;;;;;;;;:36;;-1:-1:-1;;56930:36:0;56962:4;56930:36;;;57012:12;23368:10;;23289:96;57012:12;-1:-1:-1;;;;;56985:40:0;57003:7;-1:-1:-1;;;;;56985:40:0;56997:4;56985:40;;;;;;;;;;-1:-1:-1;57046:4:0;57039:11;;56887:217;-1:-1:-1;57088:5:0;57081:12;;32813:150;32883:4;32906:50;32911:3;-1:-1:-1;;;;;32931:23:0;;26801:4;28857:21;;;:14;;;:21;;;;;;26817:321;;-1:-1:-1;26859:23:0;;;;;;;;:11;:23;;;;;;;;;;;;;27041:18;;27017:21;;;:14;;;:21;;;;;;:42;;;;27073:11;;14:290:1;84:6;137:2;125:9;116:7;112:23;108:32;105:52;;;153:1;150;143:12;105:52;179:16;;-1:-1:-1;;;;;224:31:1;;214:42;;204:70;;270:1;267;260:12;14:290;64760:19813:0;;;;;;;;;;;;;;;;;;","srcMapRuntime":"64760:19813:0:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;60820:212;;;;;;;;;;-1:-1:-1;60820:212:0;;;;;:::i;:::-;;:::i;:::-;;;612:14:1;;605:22;587:41;;575:2;560:18;60820:212:0;;;;;;;;63050:60;;;;;;;;;;;;63087:23;63050:60;;;;;785:25:1;;;773:2;758:18;63050:60:0;639:177:1;78381:150:0;;;;;;;;;;-1:-1:-1;78381:150:0;;;;;:::i;:::-;78449:19;78487:30;;;:15;:30;;;;;:37;;;;78381:150;;;;;;;;:::i;64022:359::-;;;;;;;;;;-1:-1:-1;64022:359:0;;;;;:::i;:::-;;:::i;:::-;;63232:45;;;;;;;;;;;;63271:6;63232:45;;76275:648;;;;;;;;;;-1:-1:-1;76275:648:0;;;;;:::i;:::-;;:::i;65110:45::-;;;;;;;;;;;;65149:6;65110:45;;54425:120;;;;;;;;;;-1:-1:-1;54425:120:0;;;;;:::i;:::-;54490:7;54516:12;;;;;;;;;;:22;;;;54425:120;65722:47;;;;;;;;;;-1:-1:-1;65722:47:0;;;;;:::i;:::-;;;;;;;;;;;;;;54841:136;;;;;;;;;;-1:-1:-1;54841:136:0;;;;;:::i;:::-;;:::i;55943:245::-;;;;;;;;;;-1:-1:-1;55943:245:0;;;;;:::i;:::-;;:::i;76961:1414::-;;;;;;;;;;-1:-1:-1;76961:1414:0;;;;;:::i;:::-;;:::i;66134:369::-;;;;;;:::i;:::-;;:::i;63394:30::-;;;;;;;;;;;;;;;;62978:66;;;;;;;;;;;;63018:26;62978:66;;79059:169;;;;;;;;;;-1:-1:-1;79059:169:0;;;;;:::i;:::-;;:::i;:::-;;;;;;;:::i;67821:1169::-;;;;;;;;;;-1:-1:-1;67821:1169:0;;;;;:::i;:::-;;:::i;65482:58::-;;;;;;;;;;-1:-1:-1;65482:58:0;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;65482:58:0;;;;;;;;;;;;;:::i;65242:56::-;;;;;;;;;;;;65288:10;65242:56;;78820:199;;;;;;;;;;-1:-1:-1;78820:199:0;;;;;:::i;:::-;78886:4;78957:33;;;:18;:33;;;;;:41;;;;-1:-1:-1;;;;;78957:41:0;:55;;;78820:199;66696:170;;;;;;;;;;-1:-1:-1;66696:170:0;;;;;:::i;:::-;;:::i;66541:117::-;;;;;;:::i;:::-;;:::i;61617:142::-;;;;;;;;;;-1:-1:-1;61617:142:0;;;;;:::i;:::-;;:::i;:::-;;;-1:-1:-1;;;;;12205:55:1;;;12187:74;;12175:2;12160:18;61617:142:0;12041:226:1;78537:243:0;;;;;;;;;;-1:-1:-1;78537:243:0;;;;;:::i;:::-;78603:16;78660:30;;;:15;:30;;;;;:50;;;;;;;78730:43;;;;-1:-1:-1;;;;;78730:43:0;;78537:243;;;;;12474:26:1;12462:39;;;12444:58;;-1:-1:-1;;;;;12538:55:1;;;12533:2;12518:18;;12511:83;12417:18;78537:243:0;12272:328:1;53469:136:0;;;;;;;;;;-1:-1:-1;53469:136:0;;;;;:::i;:::-;53546:4;53569:12;;;;;;;;;;;-1:-1:-1;;;;;53569:29:0;;;;;;;;;;;;;;;53469:136;62908:64;;;;;;;;;;;;62947:25;62908:64;;73354:2881;;;;;;:::i;:::-;;:::i;52802:49::-;;;;;;;;;;-1:-1:-1;52802:49:0;52847:4;52802:49;;65968:36;;;;;;;;;;;;;;;69028:392;;;;;;;;;;-1:-1:-1;69028:392:0;;;;;:::i;:::-;;:::i;69755:1121::-;;;;;;;;;;-1:-1:-1;69755:1121:0;;;;;:::i;:::-;;:::i;:::-;;;;;;;:::i;67048:735::-;;;;;;;;;;-1:-1:-1;67048:735:0;;;;;:::i;:::-;;:::i;65873:34::-;;;;;;;;;;;;;;;63726:290;;;;;;;;;;-1:-1:-1;63726:290:0;;;;;:::i;:::-;;:::i;64387:264::-;;;;;;;;;;-1:-1:-1;64387:264:0;;;;;:::i;:::-;;:::i;63189:37::-;;;;;;;;;;;;63223:3;63189:37;;70916:2398;;;;;;:::i;:::-;;:::i;66906:104::-;;;;;;;;;;-1:-1:-1;66906:104:0;;;;;:::i;:::-;;:::i;65597:57::-;;;;;;;;;;-1:-1:-1;65597:57:0;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;65597:57:0;;;;;;;15543:14:1;15584:15;;;15566:34;;15636:15;;;;15631:2;15616:18;;15609:43;-1:-1:-1;;;;;15688:55:1;15668:18;;;15661:83;15521:2;15506:18;65597:57:0;15335:415:1;61927:131:0;;;;;;;;;;-1:-1:-1;61927:131:0;;;;;:::i;:::-;;:::i;63116:66::-;;;;;;;;;;;;63156:26;63116:66;;55257:138;;;;;;;;;;-1:-1:-1;55257:138:0;;;;;:::i;:::-;;:::i;63480:47::-;;;;;;;;;;-1:-1:-1;63480:47:0;;;;;:::i;:::-;;;;;;;;;;;;;;65359:60;;;;;;;;;;;;65408:11;65359:60;;63601:29;;;;;;;;;;;;;;;;60820:212;60905:4;60928:57;;;60943:42;60928:57;;:97;;;60989:36;61013:11;60989:23;:36::i;:::-;60921:104;60820:212;-1:-1:-1;;60820:212:0:o;64022:359::-;63156:26;53079:16;53090:4;53079:10;:16::i;:::-;-1:-1:-1;;;;;64146:19:0;::::1;64126:17;64146:19:::0;;;:12:::1;:19;::::0;;;;;;64179:14;;;64175:27:::1;;64195:7;64022:359:::0;;;:::o;64175:27::-:1;-1:-1:-1::0;;;;;64243:19:0;::::1;64265:1;64243:19:::0;;;:12:::1;:19;::::0;;;;:23;64276:45:::1;::::0;64300:9;64311;64276:23:::1;:45::i;:::-;64336:38;::::0;;-1:-1:-1;;;;;16036:15:1;;;16018:34;;16088:15;;16083:2;16068:18;;16061:43;16120:18;;;16113:34;;;64336:38:0::1;::::0;15945:2:1;15930:18;64336:38:0::1;;;;;;;64116:265;53105:1;64022:359:::0;;;:::o;76275:648::-;62947:25;53079:16;53090:4;53079:10;:16::i;:::-;76491:22:::1;76450:30;::::0;;;:15:::1;:30;::::0;;;;:37;::::1;;:63;::::0;::::1;;;;;;:::i;:::-;;76446:93;;76522:17;;;;;;;;;;;;;;76446:93;76549:30;::::0;;;:15:::1;:30;::::0;;;;;;;;:67;;76589:27:::1;76712:70:::0;;;;76626:76:::1;76686:15;76626:76;;;76712:70:::0;;;;76769:12:::1;76712:70;;;::::0;;76792:53;::::1;::::0;-1:-1:-1;;;;;76792:53:0;::::1;::::0;;::::1;::::0;;;::::1;::::0;;;76861:55;;785:25:1;;;76861:55:0;;76792:53;;76549:30;;76861:55:::1;::::0;;;;;;;::::1;76275:648:::0;;;;:::o;54841:136::-;54490:7;54516:12;;;;;;;;;;:22;;;53079:16;53090:4;53079:10;:16::i;:::-;54945:25:::1;54956:4;54962:7;54945:10;:25::i;:::-;;54841:136:::0;;;:::o;55943:245::-;-1:-1:-1;;;;;56036:34:0;;23368:10;56036:34;56032:102;;56093:30;;;;;;;;;;;;;;56032:102;56144:37;56156:4;56162:18;56144:11;:37::i;76961:1414::-;77051:18;;;;;;77027:21;77120:31;77061:7;77120:22;:31::i;:::-;77079:72;-1:-1:-1;77277:27:0;77236:30;;;;:15;:30;;;;;:37;;;:68;;;;;;;;:::i;:::-;;77232:98;;77313:17;;;;;;;;;;;;;;77232:98;-1:-1:-1;;;;;77424:16:0;;77420:213;;77461:30;;;;:15;:30;;;;;:43;;;;-1:-1:-1;;;;;77461:43:0;;-1:-1:-1;77420:213:0;;;77525:30;;;;:15;:30;;;;;:43;;;;-1:-1:-1;;;;;77525:43:0;77572:10;77525:57;77521:112;;77605:17;;;;;;;;;;;;;;77521:112;77658:30;;;;:15;:30;;;;;:50;65004:10;;77658:50;;;;;;;81985:15;81978:45;81970:53;77647:80;77643:142;;77750:24;;;;;;;;;;;;;;77643:142;77795:30;;;;:15;:30;;;;;:68;;;;77835:28;77795:68;;;77938:27;;;;:31;77934:105;;78012:27;;;;77984:23;;;;-1:-1:-1;;;;;77971:37:0;;;;;:12;:37;;;;;:68;;:37;;;:68;;78012:27;;77971:68;:::i;:::-;;;;-1:-1:-1;;77934:105:0;78134:23;;;;78184:24;;;;78218:35;-1:-1:-1;;;;;78218:23:0;;78242:2;78184:24;78218:23;:35::i;:::-;78305:30;;;;:15;:30;;;;;;;;;:43;78269:99;;-1:-1:-1;;;;;16669:55:1;;;16651:74;;16741:18;;;16734:34;;;78269:99:0;;;;78305:43;;;;;;;;:30;;78269:99;;16624:18:1;78269:99:0;;;;;;;77017:1358;;;;76961:1414;;:::o;66134:369::-;66205:291;66234:6;66264:221;;;;;;;;66319:1;-1:-1:-1;;;;;66264:221:0;;;;;66364:1;66264:221;;;;66392:9;;;;;;;;;;;;66264:221;;;;66430:1;66264:221;;;;66461:9;;;;;;;;;;;;66264:221;;;66205:6;:291::i;:::-;66134:369;:::o;79059:169::-;79134:26;-1:-1:-1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;79134:26:0;79190:7;79179:42;;;;;;;;;;;;:::i;67821:1169::-;67902:18;;;;;;67878:21;67972:31;67912:7;67972:22;:31::i;:::-;67931:72;-1:-1:-1;68059:22:0;68018:30;;;;:15;:30;;;;;:37;;;:63;;;;;;;;:::i;:::-;;68014:93;;68090:17;;;;;;;;;;;;;;68014:93;68145:10;53546:4;53569:29;;;:12;;:29;:12;:29;;;;;68118:382;;;68253:11;:20;;;68234:15;:39;68230:73;;68282:21;;;;;;;;;;;;;;68230:73;68118:382;;;65149:6;68424:11;:20;;;:35;;;;:::i;:::-;68405:15;:54;68401:88;;68468:21;;;;;;;;;;;;;;68401:88;68566:30;;;;:15;:30;;;;;;:61;;;;68606:21;68566:61;;;68713:24;;;68763:23;;;;68840:27;;;;68813:24;;;;68713;;68763:23;;68813:54;;68840:27;68813:54;:::i;:::-;68796:71;-1:-1:-1;68877:35:0;-1:-1:-1;;;;;68877:23:0;;68901:2;68796:71;68877:23;:35::i;:::-;68928:55;;;-1:-1:-1;;;;;16669:55:1;;;16651:74;;16756:2;16741:18;;16734:34;;;68928:55:0;;;68950:13;;68928:55;;16624:18:1;68928:55:0;;;;;;;67868:1122;;;;;67821:1169;:::o;66696:170::-;66772:87;66804:7;66794:18;;;;;;66826:10;66847;66772:5;:87::i;:::-;66696:170;;:::o;66541:117::-;66605:46;66621:7;66639:10;66605:5;:46::i;61617:142::-;61698:7;61724:18;;;:12;:18;;;;;:28;;61746:5;61724:21;:28::i;:::-;61717:35;61617:142;-1:-1:-1;;;61617:142:0:o;73354:2881::-;73457:18;;;;;;73433:21;73526:31;73467:7;73526:22;:31::i;:::-;73485:72;;73567:57;73588:11;73601:13;73616:7;73567:20;:57::i;:::-;73728:107;;;;;;;;;;73761:12;73728:107;;;;73799:15;73728:107;;;;;;;;;-1:-1:-1;;;;;73728:107:0;;;;;;;;;-1:-1:-1;73680:33:0;;;:18;:33;;;;;;;:155;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;73958:25;;;74009:21;;;;74057:22;;;;73958:25;;74009:21;;74057:22;74294:38;;;;;74290:719;;74409:21;;;;:26;74405:73;;74444:34;;;;;;;;;;;;;;74405:73;74566:6;74553:9;:19;74549:51;;74581:19;;;;;;;;;;;;;;74549:51;74290:719;;;74720:11;:21;;;74707:9;:34;74703:66;;74750:19;;;;;;;;;;;;;;74703:66;74944:54;-1:-1:-1;;;;;74944:30:0;;74975:10;74987:2;74991:6;74944:30;:54::i;:::-;75023:22;;;;:29;:34;75019:776;;75375:104;75409:2;75420:5;75435:6;75455:11;:22;;;75375:21;:104::i;:::-;75019:776;;;75500:9;:14;75496:299;;75743:41;75769:2;75774:9;75743:17;:41::i;:::-;75914:2;-1:-1:-1;;;;;75810:418:0;75889:7;-1:-1:-1;;;;;75810:418:0;75853:13;75810:418;75945:11;:25;;;75997:11;:23;;;76045:11;:21;;;76094:11;:24;;;76144:11;:22;;;76196:11;:21;;;75810:418;;;;;;;;;;19501:10:1;19489:23;;;;19471:42;;-1:-1:-1;;;;;19610:15:1;;;19605:2;19590:18;;19583:43;19662:15;;;;19657:2;19642:18;;19635:43;19709:2;19694:18;;19687:34;19752:3;19737:19;;19730:35;;;;19796:3;19781:19;;19774:35;19458:3;19443:19;;19186:629;75810:418:0;;;;;;;;73423:2812;;;;;73354:2881;;:::o;69028:392::-;69109:4;69170:27;69129:30;;;;:15;:30;;;;;:37;;;:68;;;;;;;;:::i;:::-;;69125:98;;69206:17;;;;;;;;;;;;;;69125:98;69237:30;;;;:15;:30;;;;;:43;-1:-1:-1;;;;;69237:54:0;;;:43;;;;;:54;69233:84;;69300:17;;;;;;;;;;;;;;69233:84;-1:-1:-1;;69345:30:0;;;;:15;:30;;;;;:50;65004:10;69345:50;;;;;;;;81985:15;81978:45;81970:53;69334:79;;69028:392::o;69755:1121::-;-1:-1:-1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;69956:36:0;;;;;:4;;:27;;:36;;69984:7;;69956:36;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;69956:36:0;;;;;;;;;;;;:::i;:::-;;;69952:918;;70830:7;70819:40;;;;;;;;;;;;:::i;69952:918::-;70146:597;;;;;;;;70197:4;:18;;;70146:597;;;;;;70246:4;:16;;;70146:597;;;;;;70294:4;:17;;;-1:-1:-1;;;;;70146:597:0;;;;;70344:4;:18;;;-1:-1:-1;;;;;70146:597:0;;;;;70393:4;:16;;;-1:-1:-1;;;;;70146:597:0;;;;;70438:4;:14;;;-1:-1:-1;;;;;70146:597:0;;;;;70484:4;:17;;;70146:597;;;;70531:4;:15;;;70146:597;;;;70581:4;:20;;;70146:597;;;;70633:4;:14;;;70651:1;70633:19;;70146:597;;;;;;70680:4;:13;;;70146:597;;;;70718:4;:10;;;70146:597;;;70139:604;;;69755:1121;;;:::o;69952:918::-;69755:1121;;;:::o;67048:735::-;63087:23;53079:16;53090:4;53079:10;:16::i;:::-;67173:27:::1;67132:30;::::0;;;:15:::1;:30;::::0;;;;:37;::::1;;:68;::::0;::::1;;;;;;:::i;:::-;;67128:98;;67209:17;;;;;;;;;;;;;;67128:98;67251:30;::::0;;;:15:::1;:30;::::0;;;;:50;65004:10:::1;::::0;67251:50:::1;::::0;::::1;;::::0;;::::1;81985:15:::0;81978:45;81970:53;67240:79:::1;67236:138;;;67342:21;;;;;;;;;;;;;;67236:138;67461:30;::::0;;;:15:::1;:30;::::0;;;;;67501:22:::1;67663:51:::0;;67730:46;67765:10:::1;::::0;67461:30;;67730:46:::1;::::0;67461:30;67730:46:::1;67048:735:::0;;:::o;63726:290::-;63156:26;53079:16;53090:4;53079:10;:16::i;:::-;63271:6:::1;63825:10;:26;;63817:55;;;::::0;::::1;::::0;;21574:2:1;63817:55:0::1;::::0;::::1;21556:21:1::0;21613:2;21593:18;;;21586:30;21652:18;21632;;;21625:46;21688:18;;63817:55:0::1;;;;;;;;;63903:15;::::0;;63928:28;;;;63971:38:::1;::::0;;21891:25:1;;;21947:2;21932:18;;21925:34;;;63971:38:0::1;::::0;21864:18:1;63971:38:0::1;;;;;;;;63807:209;63726:290:::0;;:::o;64387:264::-;63156:26;53079:16;53090:4;53079:10;:16::i;:::-;64512:14:::1;::::0;;64536:34;;;;64585:59:::1;::::0;;21891:25:1;;;21947:2;21932:18;;21925:34;;;64585:59:0::1;::::0;21864:18:1;64585:59:0::1;21717:248:1::0;70916:2398:0;71017:25;71071:8;:32;;;71052:15;71045:58;;;;:::i;:::-;71017:86;;71113:59;71135:6;71143:8;71153:18;71113:21;:59::i;:::-;71308:20;71331:51;71342:6;:18;;;71362:6;:19;;;71331:10;:51::i;:::-;71308:74;;71450:23;71505:1;71487:15;;:19;71483:85;;;63223:3;71542:15;;71527:12;:30;;;;:::i;:::-;71526:42;;;;:::i;:::-;71508:60;;71483:85;71578:31;71594:15;71578:31;;:::i;:::-;;;71722:20;71769:924;;;;;;;;71829:13;71769:924;;;;;;71874:6;:17;;;71769:924;;;;;;71923:6;:13;;;-1:-1:-1;;;;;71769:924:0;;;;;71969:6;:9;;;-1:-1:-1;;;;;71769:924:0;;;;;72009:6;:18;;;-1:-1:-1;;;;;71769:924:0;;;;;72056:6;:16;;;-1:-1:-1;;;;;71769:924:0;;;;;72104:12;71769:924;;;;72146:6;:17;;;71769:924;;;;72198:15;71769:924;;;;72242:8;:18;;;71769:924;;;;72288:6;:15;;;71769:924;;;;72328:12;:27;72341:6;:13;;;-1:-1:-1;;;;;72328:27:0;-1:-1:-1;;;;;72328:27:0;;;;;;;;;;;;;:29;;;;;;;;;:::i;:::-;;;;;71769:924;;;;72430:8;:21;;;-1:-1:-1;;;;;71769:924:0;;;;;72610:18;71769:924;;;;72659:8;:19;;;71769:924;;;71745:958;;;;;;;;:::i;:::-;;;;;;;-1:-1:-1;;71745:958:0;;;;;;72737:18;;71745:958;72737:18;;;;;;;72713:21;72765:30;;;:15;:30;;;;;;:62;;;;72805:22;72765:62;;;72923:13;;;72993:17;;73037:18;;;;;73080:16;;;;73162:17;;;;73207:18;;;;71745:958;;-1:-1:-1;72737:18:0;;-1:-1:-1;;;;;72843:398:0;;;;72737:18;;72843:398;;;;71745:958;;72993:17;;73037:18;73080:16;73124:12;;73207:23;;;;72843:398;:::i;:::-;;;;;;;;73275:13;73256:51;73290:8;:16;;;73256:51;;;;;;:::i;:::-;;;;;;;;71007:2307;;;;;70916:2398;;:::o;66906:104::-;66962:41;66978:7;66999:1;66962:5;:41::i;61927:131::-;61998:7;62024:18;;;:12;:18;;;;;:27;;:25;:27::i;55257:138::-;54490:7;54516:12;;;;;;;;;;:22;;;53079:16;53090:4;53079:10;:16::i;:::-;55362:26:::1;55374:4;55380:7;55362:11;:26::i;53180:202::-:0;53265:4;53288:47;;;53303:32;53288:47;;:87;;-1:-1:-1;45095:25:0;45080:40;;;;53339:36;44981:146;53814:103;53880:30;53891:4;23368:10;53880;:30::i;58092:653::-;58267:4;-1:-1:-1;;;;;58253:19:0;;;58249:32;;58092:653;;;:::o;58249:32::-;58353:5;58362:1;58353:10;58349:23;;58092:653;;;:::o;58349:23::-;58385:20;-1:-1:-1;;;;;58385:20:0;;;58381:358;;58565:12;58582:2;-1:-1:-1;;;;;58582:7:0;58597:5;58582:25;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;58564:43;;;58629:7;58621:39;;;;;;;24145:2:1;58621:39:0;;;24127:21:1;24184:2;24164:18;;;24157:30;24223:21;24203:18;;;24196:49;24262:18;;58621:39:0;23943:343:1;58381:358:0;58691:37;-1:-1:-1;;;;;58691:26:0;;58718:2;58722:5;58691:26;:37::i;62160:257::-;62246:4;62262:12;62277:31;62294:4;62300:7;62277:16;:31::i;:::-;62262:46;;62322:7;62318:69;;;62345:18;;;;:12;:18;;;;;:31;;62368:7;62345:22;:31::i;:::-;;62403:7;62160:257;-1:-1:-1;;;62160:257:0:o;62520:262::-;62607:4;62623:12;62638:32;62656:4;62662:7;62638:17;:32::i;:::-;62623:47;;62684:7;62680:72;;;62707:18;;;;:12;:18;;;;;:34;;62733:7;62707:25;:34::i;34071:156::-;34145:7;34195:22;34199:3;34211:5;34195:3;:22::i;83620:951::-;-1:-1:-1;;;;;83808:21:0;;83804:47;;83838:13;;;;;;;;;;;;;;83804:47;78886:4;78957:33;;;:18;:33;;;;;:41;;;;-1:-1:-1;;;;;78957:41:0;:55;83922:60;;83962:20;;;;;;;;;;;;;;83922:60;84030:13;83996:48;;:11;:23;;;:48;;;83992:77;;84053:16;;;;;;;;;;;;;;83992:77;84151:11;:20;;;84133:15;:38;84129:69;;;84180:18;;;;;;;;;;;;;;84129:69;84328:30;;;;-1:-1:-1;;;;;84328:44:0;;;;;:101;;;84422:7;-1:-1:-1;;;;;84388:41:0;:11;:30;;;-1:-1:-1;;;;;84388:41:0;;;84328:101;:166;;;;;84464:11;:30;;;84445:15;:49;;84328:166;84311:254;;;84526:28;;;;;;;;;;;;;;46696:188;46823:53;;-1:-1:-1;;;;;16036:15:1;;;46823:53:0;;;16018:34:1;16088:15;;;16068:18;;;16061:43;16120:18;;;16113:34;;;46796:81:0;;46816:5;;46838:18;;;;;15930::1;;46823:53:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;46796:19;:81::i;80387:999::-;80562:21;80663:5;80670:6;80678:10;80598:92;;;;;;;;;;:::i;:::-;;;;-1:-1:-1;;80598:92:0;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;80797:84:0;80836:9;80598:92;80870:9;80797:29;:84::i;:::-;80771:110;;80947:10;:17;80968:1;80947:22;80943:59;;80978:24;;;;;;;;;;;;;;80943:59;81081:10;:17;81102:2;81081:23;81077:67;;81113:31;;;;;;;;;;;;;;81077:67;81258:56;81227:19;81235:10;81227:19;:::i;:::-;:88;81223:157;;81338:31;;;;;;;;;;;;;;81223:157;80552:834;;80387:999;;;;:::o;17900:331::-;18009:6;17985:21;:30;17981:109;;;18038:41;;;;;18073:4;18038:41;;;12187:74:1;12160:18;;18038:41:0;12041:226:1;17981:109:0;18101:12;18119:9;-1:-1:-1;;;;;18119:14:0;18141:6;18119:33;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;18100:52;;;18167:7;18162:63;;18197:17;;;;;;;;;;;;;;82365:1176;82618:13;82597:6;:17;;;:34;;;82593:63;;82640:16;;;;;;;;;;;;;;82593:63;82670:19;;;;:24;;:50;;-1:-1:-1;82698:17:0;;;;:22;82670:50;82666:80;;;82729:17;;;;;;;;;;;;;;82666:80;82760:13;;;;-1:-1:-1;;;;;82760:27:0;;;:54;;-1:-1:-1;82791:9:0;;;;-1:-1:-1;;;;;82791:23:0;;82760:54;82756:80;;;82823:13;;;;;;;;;;;;;;82756:80;82850:18;;;;-1:-1:-1;;;;;82850:32:0;;;:66;;-1:-1:-1;82886:16:0;;;;-1:-1:-1;;;;;82886:30:0;;82850:66;82846:92;;;82925:13;;;;;;;;;;;;;;82846:92;82970:37;65288:10;82970:15;:37;:::i;:::-;82952:6;:15;;;:55;82948:86;;;83016:18;;;;;;;;;;;;;;82948:86;65408:11;83075:8;:19;;;:26;:51;83071:90;;;83135:26;;;;;;;;;;;;;;83071:90;83175:18;;;;:23;;;;:76;;-1:-1:-1;83202:16:0;;;;-1:-1:-1;;;;;83202:49:0;57809:42;83202:49;83175:76;83171:148;;;83274:34;;;;;;;;;;;;;;83171:148;83424:1;83402:18;:23;;:71;;;;83457:6;:15;;;83429:18;:44;83402:71;83398:137;;;83496:28;;;;;;;;;;;;;;79306:923;79375:20;79411:38;-1:-1:-1;;;;;79411:38:0;;;79407:816;;79563:9;79553:6;:19;79549:51;;79581:19;;;;;;;;;;;;;;79549:51;-1:-1:-1;79629:9:0;79407:816;;;79669:24;:5;-1:-1:-1;;;;;79669:22:0;;:24::i;:::-;79774:38;;;;;79806:4;79774:38;;;12187:74:1;-1:-1:-1;;;;;79774:23:0;;;;;12160:18:1;;79774:38:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;79759:53;-1:-1:-1;79958:65:0;-1:-1:-1;;;;;79958:30:0;;79989:10;80009:4;80016:6;79958:30;:65::i;:::-;80159:38;;;;;80191:4;80159:38;;;12187:74:1;80200:12:0;;-1:-1:-1;;;;;80159:23:0;;;;;12160:18:1;;80159:38:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;:53;;;;:::i;33614:115::-;33677:7;33703:19;33711:3;29053:18;;28971:107;54047:197;53546:4;53569:12;;;;;;;;;;;-1:-1:-1;;;;;53569:29:0;;;;;;;;;;;;54130:108;;54180:47;;;;;-1:-1:-1;;;;;16669:55:1;;54180:47:0;;;16651:74:1;16741:18;;;16734:34;;;16624:18;;54180:47:0;16477:297:1;46297:160:0;46406:43;;-1:-1:-1;;;;;16669:55:1;;;46406:43:0;;;16651:74:1;16741:18;;;16734:34;;;46379:71:0;;46399:5;;46421:14;;;;;16624:18:1;;46406:43:0;16477:297:1;56794:316:0;56871:4;53569:12;;;;;;;;;;;-1:-1:-1;;;;;53569:29:0;;;;;;;;;;;;56887:217;;56930:6;:12;;;;;;;;;;;-1:-1:-1;;;;;56930:29:0;;;;;;;;;:36;;;;56962:4;56930:36;;;57012:12;23368:10;;23289:96;57012:12;-1:-1:-1;;;;;56985:40:0;57003:7;-1:-1:-1;;;;;56985:40:0;56997:4;56985:40;;;;;;;;;;-1:-1:-1;57046:4:0;57039:11;;56887:217;-1:-1:-1;57088:5:0;57081:12;;32813:150;32883:4;32906:50;32911:3;-1:-1:-1;;;;;32931:23:0;;32906:4;:50::i;57345:317::-;57423:4;53569:12;;;;;;;;;;;-1:-1:-1;;;;;53569:29:0;;;;;;;;;;;;57439:217;;;57513:5;57481:12;;;;;;;;;;;-1:-1:-1;;;;;57481:29:0;;;;;;;;;;:37;;;;;;57537:40;23368:10;;57481:12;;57537:40;;57513:5;57537:40;-1:-1:-1;57598:4:0;57591:11;;33131:156;33204:4;33227:53;33235:3;-1:-1:-1;;;;;33255:23:0;;33227:7;:53::i;29420:118::-;29487:7;29513:3;:11;;29525:5;29513:18;;;;;;;;:::i;:::-;;;;;;;;;29506:25;;29420:118;;;;:::o;49053:629::-;49472:23;49498:33;-1:-1:-1;;;;;49498:27:0;;49526:4;49498:27;:33::i;:::-;49472:59;;49545:10;:17;49566:1;49545:22;;:57;;;;;49583:10;49572:30;;;;;;;;;;;;:::i;:::-;49571:31;49545:57;49541:135;;;49625:40;;;;;-1:-1:-1;;;;;12205:55:1;;49625:40:0;;;12187:74:1;12160:18;;49625:40:0;12041:226:1;19549:392:0;19648:12;19700:5;19676:21;:29;19672:108;;;19728:41;;;;;19763:4;19728:41;;;12187:74:1;12160:18;;19728:41:0;12041:226:1;19672:108:0;19790:12;19804:23;19831:6;-1:-1:-1;;;;;19831:11:0;19850:5;19857:4;19831:31;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;19789:73;;;;19879:55;19906:6;19914:7;19923:10;19879:26;:55::i;:::-;19872:62;19549:392;-1:-1:-1;;;;;;19549:392:0:o;59909:344::-;60076:38;-1:-1:-1;;;;;60076:38:0;;;60072:69;;60123:18;;;;;;;;;;;;;;60072:69;60197:5;-1:-1:-1;;;;;60197:17:0;;60218:1;60197:22;60193:53;;60228:18;;;;;;;;;;;;;;26738:406;26801:4;28857:21;;;:14;;;:21;;;;;;26817:321;;-1:-1:-1;26859:23:0;;;;;;;;:11;:23;;;;;;;;;;;;;27041:18;;27017:21;;;:14;;;:21;;;;;;:42;;;;27073:11;;27312:1368;27378:4;27507:21;;;:14;;;:21;;;;;;27543:13;;27539:1135;;27910:18;27931:12;27942:1;27931:8;:12;:::i;:::-;27977:18;;27910:33;;-1:-1:-1;27957:17:0;;27977:22;;27998:1;;27977:22;:::i;:::-;27957:42;;28032:9;28018:10;:23;28014:378;;28061:17;28081:3;:11;;28093:9;28081:22;;;;;;;;:::i;:::-;;;;;;;;;28061:42;;28228:9;28202:3;:11;;28214:10;28202:23;;;;;;;;:::i;:::-;;;;;;;;;;;;:35;;;;28341:25;;;:14;;;:25;;;;;:36;;;28014:378;28470:17;;:3;;:17;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;28573:3;:14;;:21;28588:5;28573:21;;;;;;;;;;;28566:28;;;28616:4;28609:11;;;;;;;27539:1135;28658:5;28651:12;;;;;19074:151;19149:12;19180:38;19202:6;19210:4;19216:1;19180:21;:38::i;20994:582::-;21138:12;21167:7;21162:408;;21190:19;21198:10;21190:7;:19::i;:::-;21162:408;;;21414:17;;:22;:49;;;;-1:-1:-1;;;;;;21440:18:0;;;:23;21414:49;21410:119;;;21490:24;;;;;-1:-1:-1;;;;;12205:55:1;;21490:24:0;;;12187:74:1;12160:18;;21490:24:0;12041:226:1;21410:119:0;-1:-1:-1;21549:10:0;21542:17;;22112:516;22243:17;;:21;22239:383;;22471:10;22465:17;22527:15;22514:10;22510:2;22506:19;22499:44;22239:383;22594:17;;;;;;;;;;;;;;14:332:1;72:6;125:2;113:9;104:7;100:23;96:32;93:52;;;141:1;138;131:12;93:52;180:9;167:23;230:66;223:5;219:78;212:5;209:89;199:117;;312:1;309;302:12;821:180;880:6;933:2;921:9;912:7;908:23;904:32;901:52;;;949:1;946;939:12;901:52;-1:-1:-1;972:23:1;;821:180;-1:-1:-1;821:180:1:o;1006:184::-;1058:77;1055:1;1048:88;1155:4;1152:1;1145:15;1179:4;1176:1;1169:15;1195:297;1279:1;1272:5;1269:12;1259:200;;1315:77;1312:1;1305:88;1416:4;1413:1;1406:15;1444:4;1441:1;1434:15;1259:200;1468:18;;1195:297::o;1497:214::-;1646:2;1631:18;;1658:47;1635:9;1687:6;1658:47;:::i;1716:154::-;-1:-1:-1;;;;;1795:5:1;1791:54;1784:5;1781:65;1771:93;;1860:1;1857;1850:12;1875:134;1943:20;;1972:31;1943:20;1972:31;:::i;2014:388::-;2082:6;2090;2143:2;2131:9;2122:7;2118:23;2114:32;2111:52;;;2159:1;2156;2149:12;2111:52;2198:9;2185:23;2217:31;2242:5;2217:31;:::i;:::-;2267:5;-1:-1:-1;2324:2:1;2309:18;;2296:32;2337:33;2296:32;2337:33;:::i;:::-;2389:7;2379:17;;;2014:388;;;;;:::o;2589:383::-;2666:6;2674;2682;2735:2;2723:9;2714:7;2710:23;2706:32;2703:52;;;2751:1;2748;2741:12;2703:52;2787:9;2774:23;2764:33;;2844:2;2833:9;2829:18;2816:32;2806:42;;2898:2;2887:9;2883:18;2870:32;2911:31;2936:5;2911:31;:::i;:::-;2961:5;2951:15;;;2589:383;;;;;:::o;2977:247::-;3036:6;3089:2;3077:9;3068:7;3064:23;3060:32;3057:52;;;3105:1;3102;3095:12;3057:52;3144:9;3131:23;3163:31;3188:5;3163:31;:::i;3229:315::-;3297:6;3305;3358:2;3346:9;3337:7;3333:23;3329:32;3326:52;;;3374:1;3371;3364:12;3326:52;3410:9;3397:23;3387:33;;3470:2;3459:9;3455:18;3442:32;3483:31;3508:5;3483:31;:::i;3549:184::-;3601:77;3598:1;3591:88;3698:4;3695:1;3688:15;3722:4;3719:1;3712:15;3738:255;3810:2;3804:9;3852:6;3840:19;;3889:18;3874:34;;3910:22;;;3871:62;3868:88;;;3936:18;;:::i;:::-;3972:2;3965:22;3738:255;:::o;3998:253::-;4070:2;4064:9;4112:4;4100:17;;4147:18;4132:34;;4168:22;;;4129:62;4126:88;;;4194:18;;:::i;4256:255::-;4328:2;4322:9;4370:6;4358:19;;4407:18;4392:34;;4428:22;;;4389:62;4386:88;;;4454:18;;:::i;4516:252::-;4588:2;4582:9;4630:3;4618:16;;4664:18;4649:34;;4685:22;;;4646:62;4643:88;;;4711:18;;:::i;4773:334::-;4844:2;4838:9;4900:2;4890:13;;-1:-1:-1;;4886:86:1;4874:99;;5003:18;4988:34;;5024:22;;;4985:62;4982:88;;;5050:18;;:::i;:::-;5086:2;5079:22;4773:334;;-1:-1:-1;4773:334:1:o;5112:245::-;5160:4;5193:18;5185:6;5182:30;5179:56;;;5215:18;;:::i;:::-;-1:-1:-1;5272:2:1;5260:15;-1:-1:-1;;5256:88:1;5346:4;5252:99;;5112:245::o;5362:462::-;5404:5;5457:3;5450:4;5442:6;5438:17;5434:27;5424:55;;5475:1;5472;5465:12;5424:55;5511:6;5498:20;5542:48;5558:31;5586:2;5558:31;:::i;:::-;5542:48;:::i;:::-;5615:2;5606:7;5599:19;5661:3;5654:4;5649:2;5641:6;5637:15;5633:26;5630:35;5627:55;;;5678:1;5675;5668:12;5627:55;5743:2;5736:4;5728:6;5724:17;5717:4;5708:7;5704:18;5691:55;5791:1;5766:16;;;5784:4;5762:27;5755:38;;;;5770:7;5362:462;-1:-1:-1;;;5362:462:1:o;5829:455::-;5906:6;5914;5967:2;5955:9;5946:7;5942:23;5938:32;5935:52;;;5983:1;5980;5973:12;5935:52;6023:9;6010:23;6056:18;6048:6;6045:30;6042:50;;;6088:1;6085;6078:12;6042:50;6111:49;6152:7;6143:6;6132:9;6128:22;6111:49;:::i;:::-;6101:59;;;6210:2;6199:9;6195:18;6182:32;6223:31;6248:5;6223:31;:::i;6289:121::-;6374:10;6367:5;6363:22;6356:5;6353:33;6343:61;;6400:1;6397;6390:12;6415:132;6482:20;;6511:30;6482:20;6511:30;:::i;6552:118::-;6638:5;6631:13;6624:21;6617:5;6614:32;6604:60;;6660:1;6657;6650:12;6675:128;6740:20;;6769:28;6740:20;6769:28;:::i;6808:806::-;6867:5;6915:6;6903:9;6898:3;6894:19;6890:32;6887:52;;;6935:1;6932;6925:12;6887:52;6957:22;;:::i;:::-;6948:31;;7002:28;7020:9;7002:28;:::i;:::-;6995:5;6988:43;7063:38;7097:2;7086:9;7082:18;7063:38;:::i;:::-;7058:2;7051:5;7047:14;7040:62;7134:38;7168:2;7157:9;7153:18;7134:38;:::i;:::-;7129:2;7122:5;7118:14;7111:62;7205:38;7239:2;7228:9;7224:18;7205:38;:::i;:::-;7200:2;7193:5;7189:14;7182:62;7277:39;7311:3;7300:9;7296:19;7277:39;:::i;:::-;7271:3;7264:5;7260:15;7253:64;7378:3;7367:9;7363:19;7350:33;7344:3;7337:5;7333:15;7326:58;7445:3;7434:9;7430:19;7417:33;7411:3;7404:5;7400:15;7393:58;7484:36;7515:3;7504:9;7500:19;7484:36;:::i;:::-;7478:3;7471:5;7467:15;7460:61;7540:3;7603:2;7592:9;7588:18;7575:32;7570:2;7563:5;7559:14;7552:56;;6808:806;;;;:::o;7619:237::-;7707:6;7760:3;7748:9;7739:7;7735:23;7731:33;7728:53;;;7777:1;7774;7767:12;7728:53;7800:50;7842:7;7831:9;7800:50;:::i;7861:320::-;7929:6;7982:2;7970:9;7961:7;7957:23;7953:32;7950:52;;;7998:1;7995;7988:12;7950:52;8038:9;8025:23;8071:18;8063:6;8060:30;8057:50;;;8103:1;8100;8093:12;8057:50;8126:49;8167:7;8158:6;8147:9;8143:22;8126:49;:::i;:::-;8116:59;7861:320;-1:-1:-1;;;;7861:320:1:o;8417:250::-;8502:1;8512:113;8526:6;8523:1;8520:13;8512:113;;;8602:11;;;8596:18;8583:11;;;8576:39;8548:2;8541:10;8512:113;;;-1:-1:-1;;8659:1:1;8641:16;;8634:27;8417:250::o;8672:329::-;8713:3;8751:5;8745:12;8778:6;8773:3;8766:19;8794:76;8863:6;8856:4;8851:3;8847:14;8840:4;8833:5;8829:16;8794:76;:::i;:::-;8915:2;8903:15;-1:-1:-1;;8899:88:1;8890:98;;;;8990:4;8886:109;;8672:329;-1:-1:-1;;8672:329:1:o;9006:1866::-;9209:2;9198:9;9191:21;9221:52;9269:2;9258:9;9254:18;9245:6;9239:13;8262:10;8251:22;8239:35;;8186:94;9221:52;9172:4;9320:2;9312:6;9308:15;9302:22;9333:51;9380:2;9369:9;9365:18;9351:12;8262:10;8251:22;8239:35;;8186:94;9333:51;-1:-1:-1;9433:2:1;9421:15;;9415:22;-1:-1:-1;;;;;8351:54:1;;9496:2;9481:18;;8339:67;-1:-1:-1;9549:2:1;9537:15;;9531:22;-1:-1:-1;;;;;8351:54:1;;9612:3;9597:19;;8339:67;-1:-1:-1;9666:3:1;9654:16;;9648:23;-1:-1:-1;;;;;8351:54:1;;9730:3;9715:19;;8339:67;-1:-1:-1;9784:3:1;9772:16;;9766:23;-1:-1:-1;;;;;8351:54:1;;9848:3;9833:19;;8339:67;-1:-1:-1;9908:3:1;9896:16;;9890:23;9884:3;9869:19;;;9862:52;;;;9939:16;;9933:23;9975:3;9994:18;;;9987:30;;;;10042:15;;10036:22;10077:3;10096:18;;;10089:30;;;;10144:15;;10138:22;10179:3;10198:18;;;10191:30;;;;10246:15;;10240:22;10281:3;10300:18;;;10293:30;;;;10348:15;;10342:22;10384:3;10403:19;;;10396:31;;;;10464:16;;10458:23;10501:3;10513:55;10548:19;;;10458:23;-1:-1:-1;;;;;8351:54:1;8339:67;;8285:127;10513:55;10594:16;;10588:23;10631:3;10650:19;;;10643:32;;;;10712:16;;10706:23;10749:6;10771:19;;;10764:32;10706:23;-1:-1:-1;10813:53:1;10861:3;10846:19;;10706:23;10813:53;:::i;10877:513::-;11106:3;11091:19;;11119:47;11095:9;11148:6;11119:47;:::i;:::-;11214:12;11206:6;11202:25;11197:2;11186:9;11182:18;11175:53;11276:14;11268:6;11264:27;11259:2;11248:9;11244:18;11237:55;-1:-1:-1;;;;;11332:6:1;11328:55;11323:2;11312:9;11308:18;11301:83;10877:513;;;;;;;:::o;11395:388::-;11472:6;11480;11533:2;11521:9;11512:7;11508:23;11504:32;11501:52;;;11549:1;11546;11539:12;11501:52;11589:9;11576:23;11622:18;11614:6;11611:30;11608:50;;;11654:1;11651;11644:12;11608:50;11677:49;11718:7;11709:6;11698:9;11694:22;11677:49;:::i;:::-;11667:59;11773:2;11758:18;;;;11745:32;;-1:-1:-1;;;;11395:388:1:o;11788:248::-;11856:6;11864;11917:2;11905:9;11896:7;11892:23;11888:32;11885:52;;;11933:1;11930;11923:12;11885:52;-1:-1:-1;;11956:23:1;;;12026:2;12011:18;;;11998:32;;-1:-1:-1;11788:248:1:o;12605:1373::-;12836:13;;8262:10;8251:22;8239:35;;12805:3;12790:19;;12908:4;12900:6;12896:17;12890:24;12923:53;12970:4;12959:9;12955:20;12941:12;8262:10;8251:22;8239:35;;8186:94;12923:53;;13025:4;13017:6;13013:17;13007:24;13040:56;13090:4;13079:9;13075:20;13059:14;-1:-1:-1;;;;;8351:54:1;8339:67;;8285:127;13040:56;;13145:4;13137:6;13133:17;13127:24;13160:56;13210:4;13199:9;13195:20;13179:14;-1:-1:-1;;;;;8351:54:1;8339:67;;8285:127;13160:56;;13265:4;13257:6;13253:17;13247:24;13280:56;13330:4;13319:9;13315:20;13299:14;-1:-1:-1;;;;;8351:54:1;8339:67;;8285:127;13280:56;;13385:4;13377:6;13373:17;13367:24;13400:56;13450:4;13439:9;13435:20;13419:14;-1:-1:-1;;;;;8351:54:1;8339:67;;8285:127;13400:56;;13512:4;13504:6;13500:17;13494:24;13487:4;13476:9;13472:20;13465:54;13575:4;13567:6;13563:17;13557:24;13550:4;13539:9;13535:20;13528:54;13601:6;13661:2;13653:6;13649:15;13643:22;13638:2;13627:9;13623:18;13616:50;;13685:6;13740:2;13732:6;13728:15;13722:22;13753:51;13800:2;13789:9;13785:18;13769:14;421:13;414:21;402:34;;351:91;13753:51;-1:-1:-1;;13823:6:1;13871:15;;;13865:22;13845:18;;;13838:50;13907:6;13955:15;;;13949:22;13929:18;;;;13922:50;;;;12605:1373;:::o;14168:1162::-;14297:6;14305;14358:3;14346:9;14337:7;14333:23;14329:33;14326:53;;;14375:1;14372;14365:12;14326:53;14398:50;14440:7;14429:9;14398:50;:::i;:::-;14388:60;;14499:3;14488:9;14484:19;14471:33;14523:18;14564:2;14556:6;14553:14;14550:34;;;14580:1;14577;14570:12;14550:34;14603:22;;;;14659:4;14641:16;;;14637:27;14634:47;;;14677:1;14674;14667:12;14634:47;14703:22;;:::i;:::-;14762:2;14749:16;14774:33;14799:7;14774:33;:::i;:::-;14816:22;;14891:2;14883:11;;;14870:25;14854:14;;;14847:49;14942:2;14934:11;;14921:25;14958:16;;;14955:36;;;14987:1;14984;14977:12;14955:36;15023:44;15059:7;15048:8;15044:2;15040:17;15023:44;:::i;:::-;15018:2;15011:5;15007:14;15000:68;;15121:2;15117;15113:11;15100:25;15095:2;15088:5;15084:14;15077:49;15172:3;15168:2;15164:12;15151:26;15202:2;15192:8;15189:16;15186:36;;;15218:1;15215;15208:12;15186:36;15255:44;15291:7;15280:8;15276:2;15272:17;15255:44;:::i;:::-;15249:3;15242:5;15238:15;15231:69;;15319:5;15309:15;;;;;14168:1162;;;;;:::o;16158:184::-;16210:77;16207:1;16200:88;16307:4;16304:1;16297:15;16331:4;16328:1;16321:15;16347:125;16412:9;;;16433:10;;;16430:36;;;16446:18;;:::i;16779:136::-;16857:13;;16879:30;16857:13;16879:30;:::i;16920:138::-;16999:13;;17021:31;16999:13;17021:31;:::i;17063:441::-;17116:5;17169:3;17162:4;17154:6;17150:17;17146:27;17136:55;;17187:1;17184;17177:12;17136:55;17216:6;17210:13;17247:48;17263:31;17291:2;17263:31;:::i;17247:48::-;17320:2;17311:7;17304:19;17366:3;17359:4;17354:2;17346:6;17342:15;17338:26;17335:35;17332:55;;;17383:1;17380;17373:12;17332:55;17396:77;17470:2;17463:4;17454:7;17450:18;17443:4;17435:6;17431:17;17396:77;:::i;17509:1672::-;17616:6;17669:2;17657:9;17648:7;17644:23;17640:32;17637:52;;;17685:1;17682;17675:12;17637:52;17718:9;17712:16;17747:18;17788:2;17780:6;17777:14;17774:34;;;17804:1;17801;17794:12;17774:34;17827:22;;;;17883:6;17865:16;;;17861:29;17858:49;;;17903:1;17900;17893:12;17858:49;17929:22;;:::i;:::-;17974:32;18003:2;17974:32;:::i;:::-;17967:5;17960:47;18039:41;18076:2;18072;18068:11;18039:41;:::i;:::-;18034:2;18027:5;18023:14;18016:65;18113:42;18151:2;18147;18143:11;18113:42;:::i;:::-;18108:2;18101:5;18097:14;18090:66;18188:42;18226:2;18222;18218:11;18188:42;:::i;:::-;18183:2;18176:5;18172:14;18165:66;18264:43;18302:3;18298:2;18294:12;18264:43;:::i;:::-;18258:3;18251:5;18247:15;18240:68;18341:43;18379:3;18375:2;18371:12;18341:43;:::i;:::-;18335:3;18324:15;;18317:68;18432:3;18424:12;;;18418:19;18401:15;;;18394:44;18485:3;18477:12;;;18471:19;18454:15;;;18447:44;18510:3;18551:11;;;18545:18;18529:14;;;18522:42;18583:3;18624:11;;;18618:18;18602:14;;;18595:42;18656:3;18697:11;;;18691:18;18675:14;;;18668:42;18729:3;18770:11;;;18764:18;18748:14;;;18741:42;18802:3;18837:42;18867:11;;;18837:42;:::i;:::-;18821:14;;;18814:66;18899:3;18940:11;;;18934:18;18918:14;;;18911:42;18972:3;19006:11;;;19000:18;19030:16;;;19027:36;;;19059:1;19056;19049:12;19027:36;19095:55;19142:7;19131:8;19127:2;19123:17;19095:55;:::i;:::-;19079:14;;;19072:79;;;;-1:-1:-1;19083:5:1;17509:1672;-1:-1:-1;;;;;17509:1672:1:o;19820:217::-;19967:2;19956:9;19949:21;19930:4;19987:44;20027:2;20016:9;20012:18;20004:6;19987:44;:::i;20042:132::-;20118:13;;20140:28;20118:13;20140:28;:::i;20179:1188::-;20282:6;20335:3;20323:9;20314:7;20310:23;20306:33;20303:53;;;20352:1;20349;20342:12;20303:53;20378:22;;:::i;:::-;20423:39;20452:9;20423:39;:::i;:::-;20416:5;20409:54;20495:48;20539:2;20528:9;20524:18;20495:48;:::i;:::-;20490:2;20483:5;20479:14;20472:72;20576:49;20621:2;20610:9;20606:18;20576:49;:::i;:::-;20571:2;20564:5;20560:14;20553:73;20658:49;20703:2;20692:9;20688:18;20658:49;:::i;:::-;20653:2;20646:5;20642:14;20635:73;20741:50;20786:3;20775:9;20771:19;20741:50;:::i;:::-;20735:3;20728:5;20724:15;20717:75;20825:50;20870:3;20859:9;20855:19;20825:50;:::i;:::-;20819:3;20812:5;20808:15;20801:75;20930:3;20919:9;20915:19;20909:26;20903:3;20896:5;20892:15;20885:51;20990:3;20979:9;20975:19;20969:26;20963:3;20956:5;20952:15;20945:51;21015:3;21071:2;21060:9;21056:18;21050:25;21045:2;21038:5;21034:14;21027:49;;21095:3;21130:46;21172:2;21161:9;21157:18;21130:46;:::i;:::-;21114:14;;;21107:70;21196:3;21237:18;;;21231:25;21215:14;;;21208:49;21276:3;21317:18;;;21311:25;21295:14;;;21288:49;;;;-1:-1:-1;21118:5:1;20179:1188;-1:-1:-1;20179:1188:1:o;21970:216::-;22034:9;;;22062:11;;;22009:3;22092:9;;22120:10;;22116:19;;22145:10;;22137:19;;22113:44;22110:70;;;22160:18;;:::i;:::-;22110:70;;21970:216;;;;:::o;22191:168::-;22264:9;;;22295;;22312:15;;;22306:22;;22292:37;22282:71;;22333:18;;:::i;22364:274::-;22404:1;22430;22420:189;;22465:77;22462:1;22455:88;22566:4;22563:1;22556:15;22594:4;22591:1;22584:15;22420:189;-1:-1:-1;22623:9:1;;22364:274::o;22643:128::-;22710:9;;;22731:11;;;22728:37;;;22745:18;;:::i;22776:195::-;22815:3;22846:66;22839:5;22836:77;22833:103;;22916:18;;:::i;:::-;-1:-1:-1;22963:1:1;22952:13;;22776:195::o;22976:752::-;23283:3;23272:9;23265:22;23246:4;23304:45;23344:3;23333:9;23329:19;23321:6;23304:45;:::i;:::-;23397:10;23385:23;;;;23380:2;23365:18;;23358:51;-1:-1:-1;;;;;;23506:15:1;;;23501:2;23486:18;;23479:43;23558:15;;;;23553:2;23538:18;;23531:43;23605:3;23590:19;;23583:35;;;;23649:3;23634:19;;23627:35;23706:14;;23699:22;23693:3;23678:19;;;23671:51;23296:53;22976:752;-1:-1:-1;22976:752:1:o;24291:408::-;-1:-1:-1;;;;;24498:6:1;24494:55;24483:9;24476:74;24586:6;24581:2;24570:9;24566:18;24559:34;24629:2;24624;24613:9;24609:18;24602:30;24457:4;24649:44;24689:2;24678:9;24674:18;24666:6;24649:44;:::i;:::-;24641:52;24291:408;-1:-1:-1;;;;;24291:408:1:o;24704:357::-;24822:12;;24869:4;24858:16;;;24852:23;;24822:12;24887:16;;24884:171;;;24977:66;24967:6;24961:4;24957:17;24954:1;24950:25;24946:98;24939:5;24935:110;24926:119;;24884:171;;24704:357;;;:::o;25066:184::-;25136:6;25189:2;25177:9;25168:7;25164:23;25160:32;25157:52;;;25205:1;25202;25195:12;25157:52;-1:-1:-1;25228:16:1;;25066:184;-1:-1:-1;25066:184:1:o;25557:::-;25609:77;25606:1;25599:88;25706:4;25703:1;25696:15;25730:4;25727:1;25720:15;25746:245;25813:6;25866:2;25854:9;25845:7;25841:23;25837:32;25834:52;;;25882:1;25879;25872:12;25834:52;25914:9;25908:16;25933:28;25955:5;25933:28;:::i;25996:287::-;26125:3;26163:6;26157:13;26179:66;26238:6;26233:3;26226:4;26218:6;26214:17;26179:66;:::i;:::-;26261:16;;;;;25996:287;-1:-1:-1;;25996:287:1:o;26288:184::-;26340:77;26337:1;26330:88;26437:4;26434:1;26427:15;26461:4;26458:1;26451:15","abiDefinition":[{"inputs":[{"internalType":"address","name":"_owner","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AccessControlBadConfirmation","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"bytes32","name":"neededRole","type":"bytes32"}],"name":"AccessControlUnauthorizedAccount","type":"error"},{"inputs":[{"internalType":"address","name":"target","type":"address"}],"name":"AddressEmptyCode","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"AddressInsufficientBalance","type":"error"},{"inputs":[],"name":"AmountIncorrect","type":"error"},{"inputs":[],"name":"CallParamsLengthAboveMax","type":"error"},{"inputs":[],"name":"ChainIncorrect","type":"error"},{"inputs":[],"name":"DeadlineExceeded","type":"error"},{"inputs":[],"name":"DeadlineNotExceeded","type":"error"},{"inputs":[],"name":"DeadlineTooShort","type":"error"},{"inputs":[],"name":"DisputePeriodNotPassed","type":"error"},{"inputs":[],"name":"DisputePeriodPassed","type":"error"},{"inputs":[],"name":"ExclusivityParamsIncorrect","type":"error"},{"inputs":[],"name":"ExclusivityPeriodNotPassed","type":"error"},{"inputs":[],"name":"FailedInnerCall","type":"error"},{"inputs":[],"name":"MsgValueIncorrect","type":"error"},{"inputs":[],"name":"NativeTokenCallValueNotSupported","type":"error"},{"inputs":[],"name":"RecipientIncorrectReturnValue","type":"error"},{"inputs":[],"name":"RecipientNoReturnValue","type":"error"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"SafeERC20FailedOperation","type":"error"},{"inputs":[],"name":"SenderIncorrect","type":"error"},{"inputs":[],"name":"StatusIncorrect","type":"error"},{"inputs":[],"name":"TokenNotContract","type":"error"},{"inputs":[],"name":"TransactionRelayed","type":"error"},{"inputs":[],"name":"ZeroAddress","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"relayer","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"BridgeDepositClaimed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"BridgeDepositRefunded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"relayer","type":"address"}],"name":"BridgeProofDisputed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"relayer","type":"address"},{"indexed":false,"internalType":"bytes32","name":"transactionHash","type":"bytes32"}],"name":"BridgeProofProvided","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":false,"internalType":"bytes","name":"quoteId","type":"bytes"}],"name":"BridgeQuoteDetails","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"relayer","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint32","name":"originChainId","type":"uint32"},{"indexed":false,"internalType":"address","name":"originToken","type":"address"},{"indexed":false,"internalType":"address","name":"destToken","type":"address"},{"indexed":false,"internalType":"uint256","name":"originAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"destAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"chainGasAmount","type":"uint256"}],"name":"BridgeRelayed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"bytes","name":"request","type":"bytes"},{"indexed":false,"internalType":"uint32","name":"destChainId","type":"uint32"},{"indexed":false,"internalType":"address","name":"originToken","type":"address"},{"indexed":false,"internalType":"address","name":"destToken","type":"address"},{"indexed":false,"internalType":"uint256","name":"originAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"destAmount","type":"uint256"},{"indexed":false,"internalType":"bool","name":"sendChainGas","type":"bool"}],"name":"BridgeRequested","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldChainGasAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newChainGasAmount","type":"uint256"}],"name":"ChainGasAmountUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldFeeRate","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newFeeRate","type":"uint256"}],"name":"FeeRateUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"address","name":"recipient","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"FeesSwept","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"previousAdminRole","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"newAdminRole","type":"bytes32"}],"name":"RoleAdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleRevoked","type":"event"},{"inputs":[],"name":"DEFAULT_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"DISPUTE_PERIOD","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"FEE_BPS","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"FEE_RATE_MAX","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"GOVERNOR_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"GUARD_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_CALL_PARAMS_LENGTH","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MIN_DEADLINE_PERIOD","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"REFUNDER_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"REFUND_DELAY","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"RELAYER_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"uint32","name":"dstChainId","type":"uint32"},{"internalType":"address","name":"sender","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"address","name":"originToken","type":"address"},{"internalType":"address","name":"destToken","type":"address"},{"internalType":"uint256","name":"originAmount","type":"uint256"},{"internalType":"uint256","name":"destAmount","type":"uint256"},{"internalType":"bool","name":"sendChainGas","type":"bool"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"internalType":"struct IFastBridge.BridgeParams","name":"params","type":"tuple"}],"name":"bridge","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"uint32","name":"dstChainId","type":"uint32"},{"internalType":"address","name":"sender","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"address","name":"originToken","type":"address"},{"internalType":"address","name":"destToken","type":"address"},{"internalType":"uint256","name":"originAmount","type":"uint256"},{"internalType":"uint256","name":"destAmount","type":"uint256"},{"internalType":"bool","name":"sendChainGas","type":"bool"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"internalType":"struct IFastBridge.BridgeParams","name":"params","type":"tuple"},{"components":[{"internalType":"address","name":"quoteRelayer","type":"address"},{"internalType":"int256","name":"quoteExclusivitySeconds","type":"int256"},{"internalType":"bytes","name":"quoteId","type":"bytes"},{"internalType":"uint256","name":"callValue","type":"uint256"},{"internalType":"bytes","name":"callParams","type":"bytes"}],"internalType":"struct IFastBridgeV2.BridgeParamsV2","name":"paramsV2","type":"tuple"}],"name":"bridge","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"transactionId","type":"bytes32"}],"name":"bridgeProofs","outputs":[{"internalType":"uint96","name":"timestamp","type":"uint96"},{"internalType":"address","name":"relayer","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"bridgeRelayDetails","outputs":[{"internalType":"uint48","name":"blockNumber","type":"uint48"},{"internalType":"uint48","name":"blockTimestamp","type":"uint48"},{"internalType":"address","name":"relayer","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"transactionId","type":"bytes32"}],"name":"bridgeRelays","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"transactionId","type":"bytes32"}],"name":"bridgeStatuses","outputs":[{"internalType":"enum IFastBridgeV2.BridgeStatus","name":"status","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"bridgeTxDetails","outputs":[{"internalType":"enum IFastBridgeV2.BridgeStatus","name":"status","type":"uint8"},{"internalType":"uint40","name":"proofBlockTimestamp","type":"uint40"},{"internalType":"uint48","name":"proofBlockNumber","type":"uint48"},{"internalType":"address","name":"proofRelayer","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"internalType":"address","name":"relayer","type":"address"}],"name":"canClaim","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"chainGasAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"},{"internalType":"address","name":"to","type":"address"}],"name":"claim","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"}],"name":"claim","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"deployBlock","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"transactionId","type":"bytes32"}],"name":"dispute","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"}],"name":"getBridgeTransaction","outputs":[{"components":[{"internalType":"uint32","name":"originChainId","type":"uint32"},{"internalType":"uint32","name":"destChainId","type":"uint32"},{"internalType":"address","name":"originSender","type":"address"},{"internalType":"address","name":"destRecipient","type":"address"},{"internalType":"address","name":"originToken","type":"address"},{"internalType":"address","name":"destToken","type":"address"},{"internalType":"uint256","name":"originAmount","type":"uint256"},{"internalType":"uint256","name":"destAmount","type":"uint256"},{"internalType":"uint256","name":"originFeeAmount","type":"uint256"},{"internalType":"bool","name":"sendChainGas","type":"bool"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint256","name":"nonce","type":"uint256"}],"internalType":"struct IFastBridge.BridgeTransaction","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"}],"name":"getBridgeTransactionV2","outputs":[{"components":[{"internalType":"uint32","name":"originChainId","type":"uint32"},{"internalType":"uint32","name":"destChainId","type":"uint32"},{"internalType":"address","name":"originSender","type":"address"},{"internalType":"address","name":"destRecipient","type":"address"},{"internalType":"address","name":"originToken","type":"address"},{"internalType":"address","name":"destToken","type":"address"},{"internalType":"uint256","name":"originAmount","type":"uint256"},{"internalType":"uint256","name":"destAmount","type":"uint256"},{"internalType":"uint256","name":"originFeeAmount","type":"uint256"},{"internalType":"uint256","name":"callValue","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"address","name":"exclusivityRelayer","type":"address"},{"internalType":"uint256","name":"exclusivityEndTime","type":"uint256"},{"internalType":"bytes","name":"callParams","type":"bytes"}],"internalType":"struct IFastBridgeV2.BridgeTransactionV2","name":"","type":"tuple"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleAdmin","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"uint256","name":"index","type":"uint256"}],"name":"getRoleMember","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleMemberCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"grantRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"hasRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"nonce","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"protocolFeeRate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"protocolFees","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"internalType":"bytes32","name":"destTxHash","type":"bytes32"},{"internalType":"address","name":"relayer","type":"address"}],"name":"prove","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"},{"internalType":"bytes32","name":"destTxHash","type":"bytes32"}],"name":"prove","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"}],"name":"refund","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"}],"name":"relay","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"},{"internalType":"address","name":"relayer","type":"address"}],"name":"relay","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"callerConfirmation","type":"address"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"revokeRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"senderNonces","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"newChainGasAmount","type":"uint256"}],"name":"setChainGasAmount","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"newFeeRate","type":"uint256"}],"name":"setProtocolFeeRate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"address","name":"recipient","type":"address"}],"name":"sweepProtocolFees","outputs":[],"stateMutability":"nonpayable","type":"function"}],"userDoc":{"kind":"user","methods":{"DISPUTE_PERIOD()":{"notice":"Dispute period for relayed transactions"},"MAX_CALL_PARAMS_LENGTH()":{"notice":"Maximum length of accepted callParams"},"MIN_DEADLINE_PERIOD()":{"notice":"Minimum deadline period to relay a requested bridge transaction"},"REFUND_DELAY()":{"notice":"Delay for a transaction after which it could be permisionlessly refunded"},"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256))":{"notice":"Initiates bridge on origin chain to be relayed by off-chain relayer"},"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256),(address,int256,bytes,uint256,bytes))":{"notice":"Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability to provide temporary exclusivity fill rights for the quote relayer."},"bridgeProofs(bytes32)":{"notice":"Returns the timestamp and relayer of a bridge proof"},"bridgeRelayDetails(bytes32)":{"notice":"Relay details on destination chain"},"bridgeRelays(bytes32)":{"notice":"Checks if a transaction has been relayed"},"bridgeStatuses(bytes32)":{"notice":"Returns the status of a bridge transaction"},"bridgeTxDetails(bytes32)":{"notice":"Status of the bridge tx on origin chain"},"canClaim(bytes32,address)":{"notice":"Checks if the dispute period has passed so bridge deposit can be claimed"},"chainGasAmount()":{"notice":"Chain gas amount to forward as rebate if requested"},"claim(bytes)":{"notice":"Completes bridge transaction on origin chain by claiming originally deposited capital.Can only send funds to the relayer address on the proof."},"claim(bytes,address)":{"notice":"Completes bridge transaction on origin chain by claiming originally deposited capital"},"deployBlock()":{"notice":"the block the contract was deployed at"},"dispute(bytes32)":{"notice":"Disputes an outstanding proof in case relayer provided dest chain tx is invalid"},"getBridgeTransaction(bytes)":{"notice":"Decodes bridge request into a bridge transaction"},"getBridgeTransactionV2(bytes)":{"notice":"Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2"},"nonce()":{"notice":"This is deprecated and should not be used."},"protocolFeeRate()":{"notice":"Protocol fee rate taken on origin amount deposited in origin chain"},"protocolFees(address)":{"notice":"Protocol fee amounts accumulated"},"prove(bytes,bytes32)":{"notice":"Provides proof on origin side that relayer provided funds on destination side of bridge transaction"},"prove(bytes32,bytes32,address)":{"notice":"Provides proof on origin side that relayer provided funds on destination side of bridge transaction"},"refund(bytes)":{"notice":"Refunds an outstanding bridge transaction in case optimistic bridging failed"},"relay(bytes)":{"notice":"Relays destination side of bridge transaction by off-chain relayer"},"relay(bytes,address)":{"notice":"Relays destination side of bridge transaction by off-chain relayer"},"senderNonces(address)":{"notice":"Unique bridge nonces tracked per originSender"}},"notice":"FastBridgeV2 is a contract for bridging tokens across chains.","version":1},"developerDoc":{"errors":{"AccessControlBadConfirmation()":[{"details":"The caller of a function is not the expected one. NOTE: Don't confuse with {AccessControlUnauthorizedAccount}."}],"AccessControlUnauthorizedAccount(address,bytes32)":[{"details":"The `account` is missing a role."}],"AddressEmptyCode(address)":[{"details":"There's no code at `target` (it is not a contract)."}],"AddressInsufficientBalance(address)":[{"details":"The ETH balance of the account is not enough to perform the operation."}],"FailedInnerCall()":[{"details":"A call to an address target failed. The target may have reverted."}],"SafeERC20FailedOperation(address)":[{"details":"An operation with an ERC20 token failed."}]},"events":{"RoleAdminChanged(bytes32,bytes32,bytes32)":{"details":"Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole` `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite {RoleAdminChanged} not being emitted signaling this."},"RoleGranted(bytes32,address,address)":{"details":"Emitted when `account` is granted `role`. `sender` is the account that originated the contract call, an admin role bearer except when using {AccessControl-_setupRole}."},"RoleRevoked(bytes32,address,address)":{"details":"Emitted when `account` is revoked `role`. `sender` is the account that originated the contract call: - if using `revokeRole`, it is the admin role bearer - if using `renounceRole`, it is the role bearer (i.e. `account`)"}},"kind":"dev","methods":{"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256))":{"params":{"params":"The parameters required to bridge"}},"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256),(address,int256,bytes,uint256,bytes))":{"params":{"params":"The parameters required to bridge","paramsV2":"The parameters for exclusivity fill rights (optional, can be left empty)"}},"bridgeProofs(bytes32)":{"params":{"transactionId":"The ID of the bridge transaction"},"returns":{"relayer":"The relayer address of the bridge proof","timestamp":"The timestamp of the bridge proof"}},"bridgeRelays(bytes32)":{"params":{"transactionId":"The ID of the transaction to check"},"returns":{"_0":"True if the transaction has been relayed, false otherwise"}},"bridgeStatuses(bytes32)":{"params":{"transactionId":"The ID of the bridge transaction"},"returns":{"status":"BridgeStatus Status of the bridge transaction"}},"canClaim(bytes32,address)":{"params":{"relayer":"The address of the relayer attempting to claim","transactionId":"The transaction id associated with the encoded bridge transaction to check"}},"claim(bytes)":{"params":{"request":"The encoded bridge transaction to claim on origin chain"}},"claim(bytes,address)":{"params":{"request":"The encoded bridge transaction to claim on origin chain","to":"The recipient address of the funds"}},"dispute(bytes32)":{"params":{"transactionId":"The transaction id associated with the encoded bridge transaction to dispute"}},"getBridgeTransaction(bytes)":{"details":"This method is added to achieve backwards compatibility with decoding requests into V1 structs: - `callValue` is partially reported as a zero/non-zero flag - `callParams` is ignored In order to process all kinds of requests use getBridgeTransactionV2 instead.","params":{"request":"The bridge request to decode"}},"getBridgeTransactionV2(bytes)":{"params":{"request":"The bridge request to decode"}},"getRoleAdmin(bytes32)":{"details":"Returns the admin role that controls `role`. See {grantRole} and {revokeRole}. To change a role's admin, use {_setRoleAdmin}."},"getRoleMember(bytes32,uint256)":{"details":"Returns one of the accounts that have `role`. `index` must be a value between 0 and {getRoleMemberCount}, non-inclusive. Role bearers are not sorted in any particular way, and their ordering may change at any point. WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure you perform all queries on the same block. See the following https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post] for more information."},"getRoleMemberCount(bytes32)":{"details":"Returns the number of accounts that have `role`. Can be used together with {getRoleMember} to enumerate all bearers of a role."},"grantRole(bytes32,address)":{"details":"Grants `role` to `account`. If `account` had not been already granted `role`, emits a {RoleGranted} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleGranted} event."},"hasRole(bytes32,address)":{"details":"Returns `true` if `account` has been granted `role`."},"prove(bytes,bytes32)":{"params":{"destTxHash":"The destination tx hash proving bridge transaction was relayed","request":"The encoded bridge transaction to prove on origin chain"}},"prove(bytes32,bytes32,address)":{"params":{"destTxHash":"The destination tx hash proving bridge transaction was relayed","relayer":"The address of the relaying entity which should have control of the origin funds when claimed","transactionId":"The transaction id associated with the encoded bridge transaction to prove"}},"refund(bytes)":{"params":{"request":"The encoded bridge transaction to refund"}},"relay(bytes)":{"params":{"request":"The encoded bridge transaction to relay on destination chain"}},"relay(bytes,address)":{"params":{"relayer":"The address of the relaying entity which should have control of the origin funds when claimed","request":"The encoded bridge transaction to relay on destination chain"}},"renounceRole(bytes32,address)":{"details":"Revokes `role` from the calling account. Roles are often managed via {grantRole} and {revokeRole}: this function's purpose is to provide a mechanism for accounts to lose their privileges if they are compromised (such as when a trusted device is misplaced). If the calling account had been revoked `role`, emits a {RoleRevoked} event. Requirements: - the caller must be `callerConfirmation`. May emit a {RoleRevoked} event."},"revokeRole(bytes32,address)":{"details":"Revokes `role` from `account`. If `account` had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleRevoked} event."},"supportsInterface(bytes4)":{"details":"See {IERC165-supportsInterface}."}},"stateVariables":{"nonce":{"details":"Replaced by senderNonces"}},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_owner\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"AccessControlBadConfirmation\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"neededRole\",\"type\":\"bytes32\"}],\"name\":\"AccessControlUnauthorizedAccount\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"}],\"name\":\"AddressEmptyCode\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"AddressInsufficientBalance\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"AmountIncorrect\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"CallParamsLengthAboveMax\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ChainIncorrect\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DeadlineExceeded\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DeadlineNotExceeded\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DeadlineTooShort\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DisputePeriodNotPassed\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DisputePeriodPassed\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ExclusivityParamsIncorrect\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ExclusivityPeriodNotPassed\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"FailedInnerCall\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"MsgValueIncorrect\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"NativeTokenCallValueNotSupported\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"RecipientIncorrectReturnValue\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"RecipientNoReturnValue\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"}],\"name\":\"SafeERC20FailedOperation\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"SenderIncorrect\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"StatusIncorrect\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"TokenNotContract\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"TransactionRelayed\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ZeroAddress\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"BridgeDepositClaimed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"BridgeDepositRefunded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"name\":\"BridgeProofDisputed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"transactionHash\",\"type\":\"bytes32\"}],\"name\":\"BridgeProofProvided\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"quoteId\",\"type\":\"bytes\"}],\"name\":\"BridgeQuoteDetails\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"originChainId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"chainGasAmount\",\"type\":\"uint256\"}],\"name\":\"BridgeRelayed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"destChainId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"sendChainGas\",\"type\":\"bool\"}],\"name\":\"BridgeRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"oldChainGasAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newChainGasAmount\",\"type\":\"uint256\"}],\"name\":\"ChainGasAmountUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"oldFeeRate\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newFeeRate\",\"type\":\"uint256\"}],\"name\":\"FeeRateUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"FeesSwept\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"previousAdminRole\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"newAdminRole\",\"type\":\"bytes32\"}],\"name\":\"RoleAdminChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleGranted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleRevoked\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"DEFAULT_ADMIN_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"DISPUTE_PERIOD\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"FEE_BPS\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"FEE_RATE_MAX\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"GOVERNOR_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"GUARD_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"MAX_CALL_PARAMS_LENGTH\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"MIN_DEADLINE_PERIOD\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"REFUNDER_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"REFUND_DELAY\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"RELAYER_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"dstChainId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"sendChainGas\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"}],\"internalType\":\"struct IFastBridge.BridgeParams\",\"name\":\"params\",\"type\":\"tuple\"}],\"name\":\"bridge\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"dstChainId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"sendChainGas\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"}],\"internalType\":\"struct IFastBridge.BridgeParams\",\"name\":\"params\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"quoteRelayer\",\"type\":\"address\"},{\"internalType\":\"int256\",\"name\":\"quoteExclusivitySeconds\",\"type\":\"int256\"},{\"internalType\":\"bytes\",\"name\":\"quoteId\",\"type\":\"bytes\"},{\"internalType\":\"uint256\",\"name\":\"callValue\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"callParams\",\"type\":\"bytes\"}],\"internalType\":\"struct IFastBridgeV2.BridgeParamsV2\",\"name\":\"paramsV2\",\"type\":\"tuple\"}],\"name\":\"bridge\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"}],\"name\":\"bridgeProofs\",\"outputs\":[{\"internalType\":\"uint96\",\"name\":\"timestamp\",\"type\":\"uint96\"},{\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"bridgeRelayDetails\",\"outputs\":[{\"internalType\":\"uint48\",\"name\":\"blockNumber\",\"type\":\"uint48\"},{\"internalType\":\"uint48\",\"name\":\"blockTimestamp\",\"type\":\"uint48\"},{\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"}],\"name\":\"bridgeRelays\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"}],\"name\":\"bridgeStatuses\",\"outputs\":[{\"internalType\":\"enum IFastBridgeV2.BridgeStatus\",\"name\":\"status\",\"type\":\"uint8\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"bridgeTxDetails\",\"outputs\":[{\"internalType\":\"enum IFastBridgeV2.BridgeStatus\",\"name\":\"status\",\"type\":\"uint8\"},{\"internalType\":\"uint40\",\"name\":\"proofBlockTimestamp\",\"type\":\"uint40\"},{\"internalType\":\"uint48\",\"name\":\"proofBlockNumber\",\"type\":\"uint48\"},{\"internalType\":\"address\",\"name\":\"proofRelayer\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"name\":\"canClaim\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"chainGasAmount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"claim\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"claim\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"deployBlock\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"}],\"name\":\"dispute\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"getBridgeTransaction\",\"outputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"originChainId\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"destChainId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"originSender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destRecipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"originFeeAmount\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"sendChainGas\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"}],\"internalType\":\"struct IFastBridge.BridgeTransaction\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"getBridgeTransactionV2\",\"outputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"originChainId\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"destChainId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"originSender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destRecipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"originFeeAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"callValue\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"exclusivityRelayer\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"exclusivityEndTime\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"callParams\",\"type\":\"bytes\"}],\"internalType\":\"struct IFastBridgeV2.BridgeTransactionV2\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"}],\"name\":\"getRoleAdmin\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"index\",\"type\":\"uint256\"}],\"name\":\"getRoleMember\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"}],\"name\":\"getRoleMemberCount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"grantRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"hasRole\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"nonce\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"protocolFeeRate\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"protocolFees\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"destTxHash\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"name\":\"prove\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"},{\"internalType\":\"bytes32\",\"name\":\"destTxHash\",\"type\":\"bytes32\"}],\"name\":\"prove\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"refund\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"relay\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"},{\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"name\":\"relay\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"callerConfirmation\",\"type\":\"address\"}],\"name\":\"renounceRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"revokeRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"senderNonces\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"newChainGasAmount\",\"type\":\"uint256\"}],\"name\":\"setChainGasAmount\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"newFeeRate\",\"type\":\"uint256\"}],\"name\":\"setProtocolFeeRate\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes4\",\"name\":\"interfaceId\",\"type\":\"bytes4\"}],\"name\":\"supportsInterface\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"}],\"name\":\"sweepProtocolFees\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"errors\":{\"AccessControlBadConfirmation()\":[{\"details\":\"The caller of a function is not the expected one. NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\"}],\"AccessControlUnauthorizedAccount(address,bytes32)\":[{\"details\":\"The `account` is missing a role.\"}],\"AddressEmptyCode(address)\":[{\"details\":\"There's no code at `target` (it is not a contract).\"}],\"AddressInsufficientBalance(address)\":[{\"details\":\"The ETH balance of the account is not enough to perform the operation.\"}],\"FailedInnerCall()\":[{\"details\":\"A call to an address target failed. The target may have reverted.\"}],\"SafeERC20FailedOperation(address)\":[{\"details\":\"An operation with an ERC20 token failed.\"}]},\"events\":{\"RoleAdminChanged(bytes32,bytes32,bytes32)\":{\"details\":\"Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole` `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite {RoleAdminChanged} not being emitted signaling this.\"},\"RoleGranted(bytes32,address,address)\":{\"details\":\"Emitted when `account` is granted `role`. `sender` is the account that originated the contract call, an admin role bearer except when using {AccessControl-_setupRole}.\"},\"RoleRevoked(bytes32,address,address)\":{\"details\":\"Emitted when `account` is revoked `role`. `sender` is the account that originated the contract call: - if using `revokeRole`, it is the admin role bearer - if using `renounceRole`, it is the role bearer (i.e. `account`)\"}},\"kind\":\"dev\",\"methods\":{\"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256))\":{\"params\":{\"params\":\"The parameters required to bridge\"}},\"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256),(address,int256,bytes,uint256,bytes))\":{\"params\":{\"params\":\"The parameters required to bridge\",\"paramsV2\":\"The parameters for exclusivity fill rights (optional, can be left empty)\"}},\"bridgeProofs(bytes32)\":{\"params\":{\"transactionId\":\"The ID of the bridge transaction\"},\"returns\":{\"relayer\":\"The relayer address of the bridge proof\",\"timestamp\":\"The timestamp of the bridge proof\"}},\"bridgeRelays(bytes32)\":{\"params\":{\"transactionId\":\"The ID of the transaction to check\"},\"returns\":{\"_0\":\"True if the transaction has been relayed, false otherwise\"}},\"bridgeStatuses(bytes32)\":{\"params\":{\"transactionId\":\"The ID of the bridge transaction\"},\"returns\":{\"status\":\"BridgeStatus Status of the bridge transaction\"}},\"canClaim(bytes32,address)\":{\"params\":{\"relayer\":\"The address of the relayer attempting to claim\",\"transactionId\":\"The transaction id associated with the encoded bridge transaction to check\"}},\"claim(bytes)\":{\"params\":{\"request\":\"The encoded bridge transaction to claim on origin chain\"}},\"claim(bytes,address)\":{\"params\":{\"request\":\"The encoded bridge transaction to claim on origin chain\",\"to\":\"The recipient address of the funds\"}},\"dispute(bytes32)\":{\"params\":{\"transactionId\":\"The transaction id associated with the encoded bridge transaction to dispute\"}},\"getBridgeTransaction(bytes)\":{\"details\":\"This method is added to achieve backwards compatibility with decoding requests into V1 structs: - `callValue` is partially reported as a zero/non-zero flag - `callParams` is ignored In order to process all kinds of requests use getBridgeTransactionV2 instead.\",\"params\":{\"request\":\"The bridge request to decode\"}},\"getBridgeTransactionV2(bytes)\":{\"params\":{\"request\":\"The bridge request to decode\"}},\"getRoleAdmin(bytes32)\":{\"details\":\"Returns the admin role that controls `role`. See {grantRole} and {revokeRole}. To change a role's admin, use {_setRoleAdmin}.\"},\"getRoleMember(bytes32,uint256)\":{\"details\":\"Returns one of the accounts that have `role`. `index` must be a value between 0 and {getRoleMemberCount}, non-inclusive. Role bearers are not sorted in any particular way, and their ordering may change at any point. WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure you perform all queries on the same block. See the following https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post] for more information.\"},\"getRoleMemberCount(bytes32)\":{\"details\":\"Returns the number of accounts that have `role`. Can be used together with {getRoleMember} to enumerate all bearers of a role.\"},\"grantRole(bytes32,address)\":{\"details\":\"Grants `role` to `account`. If `account` had not been already granted `role`, emits a {RoleGranted} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleGranted} event.\"},\"hasRole(bytes32,address)\":{\"details\":\"Returns `true` if `account` has been granted `role`.\"},\"prove(bytes,bytes32)\":{\"params\":{\"destTxHash\":\"The destination tx hash proving bridge transaction was relayed\",\"request\":\"The encoded bridge transaction to prove on origin chain\"}},\"prove(bytes32,bytes32,address)\":{\"params\":{\"destTxHash\":\"The destination tx hash proving bridge transaction was relayed\",\"relayer\":\"The address of the relaying entity which should have control of the origin funds when claimed\",\"transactionId\":\"The transaction id associated with the encoded bridge transaction to prove\"}},\"refund(bytes)\":{\"params\":{\"request\":\"The encoded bridge transaction to refund\"}},\"relay(bytes)\":{\"params\":{\"request\":\"The encoded bridge transaction to relay on destination chain\"}},\"relay(bytes,address)\":{\"params\":{\"relayer\":\"The address of the relaying entity which should have control of the origin funds when claimed\",\"request\":\"The encoded bridge transaction to relay on destination chain\"}},\"renounceRole(bytes32,address)\":{\"details\":\"Revokes `role` from the calling account. Roles are often managed via {grantRole} and {revokeRole}: this function's purpose is to provide a mechanism for accounts to lose their privileges if they are compromised (such as when a trusted device is misplaced). If the calling account had been revoked `role`, emits a {RoleRevoked} event. Requirements: - the caller must be `callerConfirmation`. May emit a {RoleRevoked} event.\"},\"revokeRole(bytes32,address)\":{\"details\":\"Revokes `role` from `account`. If `account` had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleRevoked} event.\"},\"supportsInterface(bytes4)\":{\"details\":\"See {IERC165-supportsInterface}.\"}},\"stateVariables\":{\"nonce\":{\"details\":\"Replaced by senderNonces\"}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"DISPUTE_PERIOD()\":{\"notice\":\"Dispute period for relayed transactions\"},\"MAX_CALL_PARAMS_LENGTH()\":{\"notice\":\"Maximum length of accepted callParams\"},\"MIN_DEADLINE_PERIOD()\":{\"notice\":\"Minimum deadline period to relay a requested bridge transaction\"},\"REFUND_DELAY()\":{\"notice\":\"Delay for a transaction after which it could be permisionlessly refunded\"},\"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256))\":{\"notice\":\"Initiates bridge on origin chain to be relayed by off-chain relayer\"},\"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256),(address,int256,bytes,uint256,bytes))\":{\"notice\":\"Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability to provide temporary exclusivity fill rights for the quote relayer.\"},\"bridgeProofs(bytes32)\":{\"notice\":\"Returns the timestamp and relayer of a bridge proof\"},\"bridgeRelayDetails(bytes32)\":{\"notice\":\"Relay details on destination chain\"},\"bridgeRelays(bytes32)\":{\"notice\":\"Checks if a transaction has been relayed\"},\"bridgeStatuses(bytes32)\":{\"notice\":\"Returns the status of a bridge transaction\"},\"bridgeTxDetails(bytes32)\":{\"notice\":\"Status of the bridge tx on origin chain\"},\"canClaim(bytes32,address)\":{\"notice\":\"Checks if the dispute period has passed so bridge deposit can be claimed\"},\"chainGasAmount()\":{\"notice\":\"Chain gas amount to forward as rebate if requested\"},\"claim(bytes)\":{\"notice\":\"Completes bridge transaction on origin chain by claiming originally deposited capital.Can only send funds to the relayer address on the proof.\"},\"claim(bytes,address)\":{\"notice\":\"Completes bridge transaction on origin chain by claiming originally deposited capital\"},\"deployBlock()\":{\"notice\":\"the block the contract was deployed at\"},\"dispute(bytes32)\":{\"notice\":\"Disputes an outstanding proof in case relayer provided dest chain tx is invalid\"},\"getBridgeTransaction(bytes)\":{\"notice\":\"Decodes bridge request into a bridge transaction\"},\"getBridgeTransactionV2(bytes)\":{\"notice\":\"Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\"},\"nonce()\":{\"notice\":\"This is deprecated and should not be used.\"},\"protocolFeeRate()\":{\"notice\":\"Protocol fee rate taken on origin amount deposited in origin chain\"},\"protocolFees(address)\":{\"notice\":\"Protocol fee amounts accumulated\"},\"prove(bytes,bytes32)\":{\"notice\":\"Provides proof on origin side that relayer provided funds on destination side of bridge transaction\"},\"prove(bytes32,bytes32,address)\":{\"notice\":\"Provides proof on origin side that relayer provided funds on destination side of bridge transaction\"},\"refund(bytes)\":{\"notice\":\"Refunds an outstanding bridge transaction in case optimistic bridging failed\"},\"relay(bytes)\":{\"notice\":\"Relays destination side of bridge transaction by off-chain relayer\"},\"relay(bytes,address)\":{\"notice\":\"Relays destination side of bridge transaction by off-chain relayer\"},\"senderNonces(address)\":{\"notice\":\"Unique bridge nonces tracked per originSender\"}},\"notice\":\"FastBridgeV2 is a contract for bridging tokens across chains.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeV2.sol\":\"FastBridgeV2\"},\"evmVersion\":\"shanghai\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeV2.sol\":{\"keccak256\":\"0x7cd0f885e80e2bdaa638bc32ae7af7d2e248f99ce4b354c217d0f0f7d7302e0a\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://7ccf28df0bd7b4606986585acd8622ed9b4e81379690061bb66088f0a2270af1\",\"dweb:/ipfs/QmTf7HNdHZkK6vmx8ZgewycQEb72oLD9nPwBpsM5reMstQ\"]}},\"version\":1}"},"hashes":{"DEFAULT_ADMIN_ROLE()":"a217fddf","DISPUTE_PERIOD()":"a5bbe22b","FEE_BPS()":"bf333f2c","FEE_RATE_MAX()":"0f5f6ed7","GOVERNOR_ROLE()":"ccc57490","GUARD_ROLE()":"03ed0ee5","MAX_CALL_PARAMS_LENGTH()":"df36bb13","MIN_DEADLINE_PERIOD()":"820688d5","REFUNDER_ROLE()":"5960ccf2","REFUND_DELAY()":"190da595","RELAYER_ROLE()":"926d7d7f","bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256))":"45851694","bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256),(address,int256,bytes,uint256,bytes))":"bfc7c607","bridgeProofs(bytes32)":"91ad5039","bridgeRelayDetails(bytes32)":"c79371b1","bridgeRelays(bytes32)":"8379a24f","bridgeStatuses(bytes32)":"051287bc","bridgeTxDetails(bytes32)":"63787e52","canClaim(bytes32,address)":"aa9641ab","chainGasAmount()":"e00a83e0","claim(bytes)":"c63ff8dd","claim(bytes,address)":"41fcb612","deployBlock()":"a3ec191a","dispute(bytes32)":"add98c70","getBridgeTransaction(bytes)":"ac11fb1a","getBridgeTransactionV2(bytes)":"5aa6ccba","getRoleAdmin(bytes32)":"248a9ca3","getRoleMember(bytes32,uint256)":"9010d07c","getRoleMemberCount(bytes32)":"ca15c873","grantRole(bytes32,address)":"2f2ff15d","hasRole(bytes32,address)":"91d14854","nonce()":"affed0e0","protocolFeeRate()":"58f85880","protocolFees(address)":"dcf844a7","prove(bytes,bytes32)":"886d36ff","prove(bytes32,bytes32,address)":"18e4357d","refund(bytes)":"5eb7d946","relay(bytes)":"8f0d6f17","relay(bytes,address)":"9c9545f0","renounceRole(bytes32,address)":"36568abe","revokeRole(bytes32,address)":"d547741f","senderNonces(address)":"295710ff","setChainGasAmount(uint256)":"b250fe6b","setProtocolFeeRate(uint256)":"b13aa2d6","supportsInterface(bytes4)":"01ffc9a7","sweepProtocolFees(address,address)":"06f333f2"}},"solidity/FastBridgeV2.sol:IAccessControl":{"code":"0x","runtime-code":"0x","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.24 ^0.8.0 ^0.8.20;\n\n// contracts/interfaces/IAdmin.sol\n\ninterface IAdmin {\n // ============ Events ============\n\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n event ChainGasAmountUpdated(uint256 oldChainGasAmount, uint256 newChainGasAmount);\n\n // ============ Methods ============\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n\n function setChainGasAmount(uint256 newChainGasAmount) external;\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IFastBridgeRecipient.sol\n\ninterface IFastBridgeRecipient {\n function fastBridgeTransferReceived(\n address token,\n uint256 amount,\n bytes memory callParams\n )\n external\n payable\n returns (bytes4);\n}\n\n// contracts/interfaces/IFastBridgeV2Errors.sol\n\ninterface IFastBridgeV2Errors {\n error AmountIncorrect();\n error CallParamsLengthAboveMax();\n error ChainIncorrect();\n error ExclusivityParamsIncorrect();\n error MsgValueIncorrect();\n error NativeTokenCallValueNotSupported();\n error SenderIncorrect();\n error StatusIncorrect();\n error ZeroAddress();\n\n error RecipientIncorrectReturnValue();\n error RecipientNoReturnValue();\n\n error DeadlineExceeded();\n error DeadlineNotExceeded();\n error DeadlineTooShort();\n error DisputePeriodNotPassed();\n error DisputePeriodPassed();\n error ExclusivityPeriodNotPassed();\n\n error TransactionRelayed();\n}\n\n// contracts/libs/Errors.sol\n\nerror DeadlineExceeded();\nerror DeadlineNotExceeded();\nerror DeadlineTooShort();\nerror InsufficientOutputAmount();\n\nerror MsgValueIncorrect();\nerror PoolNotFound();\nerror TokenAddressMismatch();\nerror TokenNotContract();\nerror TokenNotETH();\nerror TokensIdentical();\n\nerror ChainIncorrect();\nerror AmountIncorrect();\nerror ZeroAddress();\n\nerror DisputePeriodNotPassed();\nerror DisputePeriodPassed();\nerror SenderIncorrect();\nerror StatusIncorrect();\nerror TransactionIdIncorrect();\nerror TransactionRelayed();\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// contracts/interfaces/IFastBridgeV2.sol\n\ninterface IFastBridgeV2 is IFastBridge {\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n struct BridgeTxDetails {\n BridgeStatus status;\n uint40 proofBlockTimestamp;\n uint48 proofBlockNumber;\n address proofRelayer;\n }\n\n struct BridgeRelay {\n uint48 blockNumber;\n uint48 blockTimestamp;\n address relayer;\n }\n\n /// @notice New params introduced in the FastBridgeV2.\n /// We are passing fields from the older BridgeParams struct outside of this struct\n /// for backwards compatibility.\n /// Note: quoteRelayer and quoteExclusivitySeconds are either both zero (indicating no exclusivity)\n /// or both non-zero (indicating exclusivity for the given period).\n /// Note: callValue \u003e 0 can NOT be used with destToken = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE (ETH_ADDRESS)\n /// @param quoteRelayer Relayer that provided the quote for the transaction\n /// @param quoteExclusivitySeconds Period of time the quote relayer is guaranteed exclusivity after user's deposit\n /// @param quoteId Unique quote identifier used for tracking the quote\n /// @param callValue ETH value to send to the recipient (if any)\n /// @param callParams Parameters for the arbitrary call to the destination recipient (if any)\n struct BridgeParamsV2 {\n address quoteRelayer;\n int256 quoteExclusivitySeconds;\n bytes quoteId;\n uint256 callValue;\n bytes callParams;\n }\n\n /// @notice Updated bridge transaction struct to include parameters introduced in FastBridgeV2.\n /// Note: only `exclusivityRelayer` can fill such a transaction until `exclusivityEndTime`.\n /// TODO: consider changing the encoding scheme to prevent spending extra gas on decoding.\n struct BridgeTransactionV2 {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n uint256 callValue; // ETH value to send to the recipient (if any) - replaces V1's sendChainGas flag\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n address exclusivityRelayer;\n uint256 exclusivityEndTime;\n bytes callParams;\n }\n\n event BridgeQuoteDetails(bytes32 indexed transactionId, bytes quoteId);\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability\n /// to provide temporary exclusivity fill rights for the quote relayer.\n /// @param params The parameters required to bridge\n /// @param paramsV2 The parameters for exclusivity fill rights (optional, can be left empty)\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function relay(bytes memory request, address relayer) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param transactionId The transaction id associated with the encoded bridge transaction to prove\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital.\n /// @notice Can only send funds to the relayer address on the proof.\n /// @param request The encoded bridge transaction to claim on origin chain\n function claim(bytes memory request) external;\n /// @notice Checks if a transaction has been relayed\n /// @param transactionId The ID of the transaction to check\n /// @return True if the transaction has been relayed, false otherwise\n function bridgeRelays(bytes32 transactionId) external view returns (bool);\n\n /// @notice Returns the status of a bridge transaction\n /// @param transactionId The ID of the bridge transaction\n /// @return BridgeStatus Status of the bridge transaction\n function bridgeStatuses(bytes32 transactionId) external view returns (BridgeStatus);\n\n /// @notice Returns the timestamp and relayer of a bridge proof\n /// @param transactionId The ID of the bridge transaction\n /// @return timestamp The timestamp of the bridge proof\n /// @return relayer The relayer address of the bridge proof\n function bridgeProofs(bytes32 transactionId) external view returns (uint96 timestamp, address relayer);\n\n /// @notice Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\n /// @param request The bridge request to decode\n function getBridgeTransactionV2(bytes memory request) external view returns (BridgeTransactionV2 memory);\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// contracts/libs/UniversalToken.sol\n\nlibrary UniversalTokenLib {\n using SafeERC20 for IERC20;\n\n address internal constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Transfers tokens to the given account. Reverts if transfer is not successful.\n /// @dev This might trigger fallback, if ETH is transferred to the contract.\n /// Make sure this can not lead to reentrancy attacks.\n function universalTransfer(address token, address to, uint256 value) internal {\n // Don't do anything, if need to send tokens to this address\n if (to == address(this)) return;\n // Don't do anything, if trying to send zero value\n if (value == 0) return;\n if (token == ETH_ADDRESS) {\n /// @dev Note: this can potentially lead to executing code in `to`.\n // solhint-disable-next-line avoid-low-level-calls\n (bool success,) = to.call{value: value}(\"\");\n require(success, \"ETH transfer failed\");\n } else {\n IERC20(token).safeTransfer(to, value);\n }\n }\n\n /// @notice Issues an infinite allowance to the spender, if the current allowance is insufficient\n /// to spend the given amount.\n function universalApproveInfinity(address token, address spender, uint256 amountToSpend) internal {\n // ETH Chad doesn't require your approval\n if (token == ETH_ADDRESS) return;\n // No-op if allowance is already sufficient\n uint256 allowance = IERC20(token).allowance(address(this), spender);\n if (allowance \u003e= amountToSpend) return;\n // Otherwise, reset approval to 0 and set to max allowance\n if (allowance \u003e 0) IERC20(token).safeDecreaseAllowance(spender, allowance);\n IERC20(token).safeIncreaseAllowance(spender, type(uint256).max);\n }\n\n /// @notice Returns the balance of the given token (or native ETH) for the given account.\n function universalBalanceOf(address token, address account) internal view returns (uint256) {\n if (token == ETH_ADDRESS) {\n return account.balance;\n } else {\n return IERC20(token).balanceOf(account);\n }\n }\n\n /// @dev Checks that token is a contract and not ETH_ADDRESS.\n function assertIsContract(address token) internal view {\n // Check that ETH_ADDRESS was not used (in case this is a predeploy on any of the chains)\n if (token == UniversalTokenLib.ETH_ADDRESS) revert TokenNotContract();\n // Check that token is not an EOA\n if (token.code.length == 0) revert TokenNotContract();\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/Admin.sol\n\ncontract Admin is IAdmin, AccessControlEnumerable {\n using UniversalTokenLib for address;\n\n bytes32 public constant RELAYER_ROLE = keccak256(\"RELAYER_ROLE\");\n bytes32 public constant REFUNDER_ROLE = keccak256(\"REFUNDER_ROLE\");\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n uint256 public constant FEE_BPS = 1e6;\n uint256 public constant FEE_RATE_MAX = 0.01e6; // max 1% on origin amount\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Chain gas amount to forward as rebate if requested\n uint256 public chainGasAmount;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n }\n\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n require(newFeeRate \u003c= FEE_RATE_MAX, \"newFeeRate \u003e max\");\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n token.universalTransfer(recipient, feeAmount);\n emit FeesSwept(token, recipient, feeAmount);\n }\n\n function setChainGasAmount(uint256 newChainGasAmount) external onlyRole(GOVERNOR_ROLE) {\n uint256 oldChainGasAmount = chainGasAmount;\n chainGasAmount = newChainGasAmount;\n emit ChainGasAmountUpdated(oldChainGasAmount, newChainGasAmount);\n }\n}\n\n// contracts/FastBridgeV2.sol\n\n/// @notice FastBridgeV2 is a contract for bridging tokens across chains.\ncontract FastBridgeV2 is Admin, IFastBridgeV2, IFastBridgeV2Errors {\n using SafeERC20 for IERC20;\n using UniversalTokenLib for address;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Delay for a transaction after which it could be permisionlessly refunded\n uint256 public constant REFUND_DELAY = 7 days;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n /// @notice Maximum length of accepted callParams\n uint256 public constant MAX_CALL_PARAMS_LENGTH = 2 ** 16 - 1;\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeTxDetails) public bridgeTxDetails;\n /// @notice Relay details on destination chain\n mapping(bytes32 =\u003e BridgeRelay) public bridgeRelayDetails;\n /// @notice Unique bridge nonces tracked per originSender\n mapping(address =\u003e uint256) public senderNonces;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Replaced by senderNonces\n uint256 public immutable nonce = 0;\n /// @notice the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n bridge({\n params: params,\n paramsV2: BridgeParamsV2({\n quoteRelayer: address(0),\n quoteExclusivitySeconds: 0,\n quoteId: bytes(\"\"),\n callValue: 0,\n callParams: bytes(\"\")\n })\n });\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes memory request) external payable {\n relay({request: request, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes memory request, bytes32 destTxHash) external {\n prove({transactionId: keccak256(request), destTxHash: destTxHash, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridgeV2\n function claim(bytes memory request) external {\n claim({request: request, to: address(0)});\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003e DISPUTE_PERIOD) {\n revert DisputePeriodPassed();\n }\n\n // @dev relayer gets slashed effectively if dest relay has gone thru\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n bridgeTxDetails[transactionId].proofRelayer = address(0);\n bridgeTxDetails[transactionId].proofBlockTimestamp = 0;\n bridgeTxDetails[transactionId].proofBlockNumber = 0;\n\n emit BridgeProofDisputed(transactionId, msg.sender);\n }\n\n /// @inheritdoc IFastBridge\n function refund(bytes memory request) external {\n bytes32 transactionId = keccak256(request);\n\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n\n if (bridgeTxDetails[transactionId].status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n\n if (hasRole(REFUNDER_ROLE, msg.sender)) {\n // Refunder can refund if deadline has passed\n if (block.timestamp \u003c= transaction.deadline) revert DeadlineNotExceeded();\n } else {\n // Permissionless refund is allowed after REFUND_DELAY\n if (block.timestamp \u003c= transaction.deadline + REFUND_DELAY) revert DeadlineNotExceeded();\n }\n\n // if all checks passed, set to REFUNDED status\n bridgeTxDetails[transactionId].status = BridgeStatus.REFUNDED;\n\n // transfer origin collateral back to original sender\n address to = transaction.originSender;\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount + transaction.originFeeAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (bridgeTxDetails[transactionId].proofRelayer != relayer) revert SenderIncorrect();\n return _timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n /// @dev This method is added to achieve backwards compatibility with decoding requests into V1 structs:\n /// - `callValue` is partially reported as a zero/non-zero flag\n /// - `callParams` is ignored\n /// In order to process all kinds of requests use getBridgeTransactionV2 instead.\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory) {\n // Try decoding into V2 struct first. This will revert if V1 struct is passed\n try this.getBridgeTransactionV2(request) returns (BridgeTransactionV2 memory txV2) {\n // Note: we entirely ignore the callParams field, as it was not present in V1\n return BridgeTransaction({\n originChainId: txV2.originChainId,\n destChainId: txV2.destChainId,\n originSender: txV2.originSender,\n destRecipient: txV2.destRecipient,\n originToken: txV2.originToken,\n destToken: txV2.destToken,\n originAmount: txV2.originAmount,\n destAmount: txV2.destAmount,\n originFeeAmount: txV2.originFeeAmount,\n sendChainGas: txV2.callValue != 0,\n deadline: txV2.deadline,\n nonce: txV2.nonce\n });\n } catch {\n // Fallback to V1 struct\n return abi.decode(request, (BridgeTransaction));\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) public payable {\n int256 exclusivityEndTime = int256(block.timestamp) + paramsV2.quoteExclusivitySeconds;\n _validateBridgeParams(params, paramsV2, exclusivityEndTime);\n\n // transfer tokens to bridge contract\n /// @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _pullToken(params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n\n // set status to requested\n bytes memory request = abi.encode(\n BridgeTransactionV2({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n callValue: paramsV2.callValue,\n deadline: params.deadline,\n nonce: senderNonces[params.sender]++, // increment nonce on every bridge\n exclusivityRelayer: paramsV2.quoteRelayer,\n // We checked exclusivityEndTime to be in range (0 .. params.deadline] above, so can safely cast\n exclusivityEndTime: uint256(exclusivityEndTime),\n callParams: paramsV2.callParams\n })\n );\n bytes32 transactionId = keccak256(request);\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n\n emit BridgeRequested({\n transactionId: transactionId,\n sender: params.sender,\n request: request,\n destChainId: params.dstChainId,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n sendChainGas: paramsV2.callValue != 0\n });\n emit BridgeQuoteDetails(transactionId, paramsV2.quoteId);\n }\n\n /// @inheritdoc IFastBridgeV2\n function relay(bytes memory request, address relayer) public payable {\n bytes32 transactionId = keccak256(request);\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n _validateRelayParams(transaction, transactionId, relayer);\n // mark bridge transaction as relayed\n bridgeRelayDetails[transactionId] =\n BridgeRelay({blockNumber: uint48(block.number), blockTimestamp: uint48(block.timestamp), relayer: relayer});\n\n // transfer tokens to recipient on destination chain and do an arbitrary call if requested\n address to = transaction.destRecipient;\n address token = transaction.destToken;\n uint256 amount = transaction.destAmount;\n\n // All state changes have been done at this point, can proceed to the external calls.\n // This follows the checks-effects-interactions pattern to mitigate potential reentrancy attacks.\n if (token == UniversalTokenLib.ETH_ADDRESS) {\n // For ETH non-zero callValue is not allowed\n if (transaction.callValue != 0) revert NativeTokenCallValueNotSupported();\n // Check that the correct msg.value was sent\n if (msg.value != amount) revert MsgValueIncorrect();\n } else {\n // For ERC20s, we check that the correct msg.value was sent\n if (msg.value != transaction.callValue) revert MsgValueIncorrect();\n // We need to transfer the tokens from the Relayer to the recipient first before performing an\n // optional post-transfer arbitrary call.\n IERC20(token).safeTransferFrom(msg.sender, to, amount);\n }\n\n if (transaction.callParams.length != 0) {\n // Arbitrary call requested, perform it while supplying full msg.value to the recipient\n // Note: if token has a fee on transfers, the recipient will have received less than `amount`.\n // This is a very niche edge case and should be handled by the recipient contract.\n _checkedCallRecipient({recipient: to, token: token, amount: amount, callParams: transaction.callParams});\n } else if (msg.value != 0) {\n // No arbitrary call requested, but msg.value was sent. This is either a relay with ETH,\n // or a non-zero callValue request with an ERC20. In both cases, transfer the ETH to the recipient.\n Address.sendValue(payable(to), msg.value);\n }\n\n emit BridgeRelayed({\n transactionId: transactionId,\n relayer: relayer,\n to: to,\n originChainId: transaction.originChainId,\n originToken: transaction.originToken,\n destToken: transaction.destToken,\n originAmount: transaction.originAmount,\n destAmount: transaction.destAmount,\n chainGasAmount: transaction.callValue\n });\n }\n\n /// @inheritdoc IFastBridgeV2\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) public onlyRole(RELAYER_ROLE) {\n // update bridge tx status given proof provided\n if (bridgeTxDetails[transactionId].status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n bridgeTxDetails[transactionId].status = BridgeStatus.RELAYER_PROVED;\n bridgeTxDetails[transactionId].proofBlockTimestamp = uint40(block.timestamp);\n bridgeTxDetails[transactionId].proofBlockNumber = uint48(block.number);\n bridgeTxDetails[transactionId].proofRelayer = relayer;\n\n emit BridgeProofProvided(transactionId, relayer, destTxHash);\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes memory request, address to) public {\n bytes32 transactionId = keccak256(request);\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n\n // update bridge tx status if able to claim origin collateral\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n\n // if \"to\" is zero addr, permissionlessly send funds to proven relayer\n if (to == address(0)) {\n to = bridgeTxDetails[transactionId].proofRelayer;\n } else if (bridgeTxDetails[transactionId].proofRelayer != msg.sender) {\n revert SenderIncorrect();\n }\n\n if (_timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003c= DISPUTE_PERIOD) {\n revert DisputePeriodNotPassed();\n }\n\n bridgeTxDetails[transactionId].status = BridgeStatus.RELAYER_CLAIMED;\n\n // update protocol fees if origin fee amount exists\n if (transaction.originFeeAmount \u003e 0) protocolFees[transaction.originToken] += transaction.originFeeAmount;\n\n // transfer origin collateral less fee to specified address\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositClaimed(transactionId, bridgeTxDetails[transactionId].proofRelayer, to, token, amount);\n }\n\n function bridgeStatuses(bytes32 transactionId) public view returns (BridgeStatus status) {\n return bridgeTxDetails[transactionId].status;\n }\n\n function bridgeProofs(bytes32 transactionId) public view returns (uint96 timestamp, address relayer) {\n timestamp = bridgeTxDetails[transactionId].proofBlockTimestamp;\n relayer = bridgeTxDetails[transactionId].proofRelayer;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeRelays(bytes32 transactionId) public view returns (bool) {\n // has this transactionId been relayed?\n return bridgeRelayDetails[transactionId].relayer != address(0);\n }\n\n /// @inheritdoc IFastBridgeV2\n function getBridgeTransactionV2(bytes memory request) public pure returns (BridgeTransactionV2 memory) {\n return abi.decode(request, (BridgeTransactionV2));\n }\n\n /// @notice Pulls a requested token from the user to this contract.\n function _pullToken(address token, uint256 amount) internal returns (uint256 amountPulled) {\n if (token == UniversalTokenLib.ETH_ADDRESS) {\n // For ETH we just need to check that the supplied msg.value is correct\n if (amount != msg.value) revert MsgValueIncorrect();\n amountPulled = msg.value;\n } else {\n token.assertIsContract();\n // Record token balance before transfer\n amountPulled = IERC20(token).balanceOf(address(this));\n // Token needs to be pulled only if msg.value is zero\n // This way user can specify WETH as the origin asset\n IERC20(token).safeTransferFrom(msg.sender, address(this), amount);\n // Use the difference between the recorded balance and the current balance as the amountPulled\n amountPulled = IERC20(token).balanceOf(address(this)) - amountPulled;\n }\n }\n\n /// @notice Calls the Recipient's hook function with the specified callParams and performs\n /// all the necessary checks for the returned value.\n function _checkedCallRecipient(\n address recipient,\n address token,\n uint256 amount,\n bytes memory callParams\n )\n internal\n {\n bytes memory hookData =\n abi.encodeCall(IFastBridgeRecipient.fastBridgeTransferReceived, (token, amount, callParams));\n // This will bubble any revert messages from the hook function\n bytes memory returnData = Address.functionCallWithValue({target: recipient, data: hookData, value: msg.value});\n // Explicit revert if no return data at all\n if (returnData.length == 0) revert RecipientNoReturnValue();\n // Check that exactly a single return value was returned\n if (returnData.length != 32) revert RecipientIncorrectReturnValue();\n // Return value should be abi-encoded hook function selector\n if (bytes32(returnData) != bytes32(IFastBridgeRecipient.fastBridgeTransferReceived.selector)) {\n revert RecipientIncorrectReturnValue();\n }\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint40(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint40).max but\n /// proof.timestamp \u003c type(uint40).max via unchecked statement\n /// @param proofBlockTimestamp The bridge proof block timestamp\n /// @return delta Time delta since proof submitted\n function _timeSince(uint40 proofBlockTimestamp) internal view returns (uint256 delta) {\n unchecked {\n delta = uint40(block.timestamp) - proofBlockTimestamp;\n }\n }\n\n /// @notice Performs all the necessary checks for a bridge to happen.\n /// @dev There's no good way to refactor this function to reduce cyclomatic complexity due to\n /// the number of checks that need to be performed, so we skip the code-complexity rule here.\n // solhint-disable-next-line code-complexity\n function _validateBridgeParams(\n BridgeParams memory params,\n BridgeParamsV2 memory paramsV2,\n int256 exclusivityEndTime\n )\n internal\n view\n {\n // Check V1 (legacy) params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.sender == address(0) || params.to == address(0)) revert ZeroAddress();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n // Check V2 params\n if (paramsV2.callParams.length \u003e MAX_CALL_PARAMS_LENGTH) revert CallParamsLengthAboveMax();\n if (paramsV2.callValue != 0 \u0026\u0026 params.destToken == UniversalTokenLib.ETH_ADDRESS) {\n revert NativeTokenCallValueNotSupported();\n }\n // exclusivityEndTime must be in range (0 .. params.deadline]\n if (exclusivityEndTime \u003c= 0 || exclusivityEndTime \u003e int256(params.deadline)) {\n revert ExclusivityParamsIncorrect();\n }\n }\n\n /// @notice Performs all the necessary checks for a relay to happen.\n function _validateRelayParams(\n BridgeTransactionV2 memory transaction,\n bytes32 transactionId,\n address relayer\n )\n internal\n view\n {\n if (relayer == address(0)) revert ZeroAddress();\n // Check if the transaction has already been relayed\n if (bridgeRelays(transactionId)) revert TransactionRelayed();\n if (transaction.destChainId != uint32(block.chainid)) revert ChainIncorrect();\n // Check the deadline for relay to happen\n if (block.timestamp \u003e transaction.deadline) revert DeadlineExceeded();\n // Check the exclusivity period, if it is still ongoing\n // forgefmt: disable-next-item\n if (\n transaction.exclusivityRelayer != address(0) \u0026\u0026\n transaction.exclusivityRelayer != relayer \u0026\u0026\n block.timestamp \u003c= transaction.exclusivityEndTime\n ) {\n revert ExclusivityPeriodNotPassed();\n }\n }\n}\n","language":"Solidity","languageVersion":"0.8.24","compilerVersion":"0.8.24","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../","srcMap":"","srcMapRuntime":"","abiDefinition":[{"inputs":[],"name":"AccessControlBadConfirmation","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"bytes32","name":"neededRole","type":"bytes32"}],"name":"AccessControlUnauthorizedAccount","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"previousAdminRole","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"newAdminRole","type":"bytes32"}],"name":"RoleAdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleRevoked","type":"event"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleAdmin","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"grantRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"hasRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"callerConfirmation","type":"address"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"revokeRole","outputs":[],"stateMutability":"nonpayable","type":"function"}],"userDoc":{"kind":"user","methods":{},"version":1},"developerDoc":{"details":"External interface of AccessControl declared to support ERC165 detection.","errors":{"AccessControlBadConfirmation()":[{"details":"The caller of a function is not the expected one. NOTE: Don't confuse with {AccessControlUnauthorizedAccount}."}],"AccessControlUnauthorizedAccount(address,bytes32)":[{"details":"The `account` is missing a role."}]},"events":{"RoleAdminChanged(bytes32,bytes32,bytes32)":{"details":"Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole` `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite {RoleAdminChanged} not being emitted signaling this."},"RoleGranted(bytes32,address,address)":{"details":"Emitted when `account` is granted `role`. `sender` is the account that originated the contract call, an admin role bearer except when using {AccessControl-_setupRole}."},"RoleRevoked(bytes32,address,address)":{"details":"Emitted when `account` is revoked `role`. `sender` is the account that originated the contract call: - if using `revokeRole`, it is the admin role bearer - if using `renounceRole`, it is the role bearer (i.e. `account`)"}},"kind":"dev","methods":{"getRoleAdmin(bytes32)":{"details":"Returns the admin role that controls `role`. See {grantRole} and {revokeRole}. To change a role's admin, use {AccessControl-_setRoleAdmin}."},"grantRole(bytes32,address)":{"details":"Grants `role` to `account`. If `account` had not been already granted `role`, emits a {RoleGranted} event. Requirements: - the caller must have ``role``'s admin role."},"hasRole(bytes32,address)":{"details":"Returns `true` if `account` has been granted `role`."},"renounceRole(bytes32,address)":{"details":"Revokes `role` from the calling account. Roles are often managed via {grantRole} and {revokeRole}: this function's purpose is to provide a mechanism for accounts to lose their privileges if they are compromised (such as when a trusted device is misplaced). If the calling account had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must be `callerConfirmation`."},"revokeRole(bytes32,address)":{"details":"Revokes `role` from `account`. If `account` had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must have ``role``'s admin role."}},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[],\"name\":\"AccessControlBadConfirmation\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"neededRole\",\"type\":\"bytes32\"}],\"name\":\"AccessControlUnauthorizedAccount\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"previousAdminRole\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"newAdminRole\",\"type\":\"bytes32\"}],\"name\":\"RoleAdminChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleGranted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleRevoked\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"}],\"name\":\"getRoleAdmin\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"grantRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"hasRole\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"callerConfirmation\",\"type\":\"address\"}],\"name\":\"renounceRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"revokeRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"details\":\"External interface of AccessControl declared to support ERC165 detection.\",\"errors\":{\"AccessControlBadConfirmation()\":[{\"details\":\"The caller of a function is not the expected one. NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\"}],\"AccessControlUnauthorizedAccount(address,bytes32)\":[{\"details\":\"The `account` is missing a role.\"}]},\"events\":{\"RoleAdminChanged(bytes32,bytes32,bytes32)\":{\"details\":\"Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole` `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite {RoleAdminChanged} not being emitted signaling this.\"},\"RoleGranted(bytes32,address,address)\":{\"details\":\"Emitted when `account` is granted `role`. `sender` is the account that originated the contract call, an admin role bearer except when using {AccessControl-_setupRole}.\"},\"RoleRevoked(bytes32,address,address)\":{\"details\":\"Emitted when `account` is revoked `role`. `sender` is the account that originated the contract call: - if using `revokeRole`, it is the admin role bearer - if using `renounceRole`, it is the role bearer (i.e. `account`)\"}},\"kind\":\"dev\",\"methods\":{\"getRoleAdmin(bytes32)\":{\"details\":\"Returns the admin role that controls `role`. See {grantRole} and {revokeRole}. To change a role's admin, use {AccessControl-_setRoleAdmin}.\"},\"grantRole(bytes32,address)\":{\"details\":\"Grants `role` to `account`. If `account` had not been already granted `role`, emits a {RoleGranted} event. Requirements: - the caller must have ``role``'s admin role.\"},\"hasRole(bytes32,address)\":{\"details\":\"Returns `true` if `account` has been granted `role`.\"},\"renounceRole(bytes32,address)\":{\"details\":\"Revokes `role` from the calling account. Roles are often managed via {grantRole} and {revokeRole}: this function's purpose is to provide a mechanism for accounts to lose their privileges if they are compromised (such as when a trusted device is misplaced). If the calling account had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must be `callerConfirmation`.\"},\"revokeRole(bytes32,address)\":{\"details\":\"Revokes `role` from `account`. If `account` had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must have ``role``'s admin role.\"}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeV2.sol\":\"IAccessControl\"},\"evmVersion\":\"shanghai\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeV2.sol\":{\"keccak256\":\"0x7cd0f885e80e2bdaa638bc32ae7af7d2e248f99ce4b354c217d0f0f7d7302e0a\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://7ccf28df0bd7b4606986585acd8622ed9b4e81379690061bb66088f0a2270af1\",\"dweb:/ipfs/QmTf7HNdHZkK6vmx8ZgewycQEb72oLD9nPwBpsM5reMstQ\"]}},\"version\":1}"},"hashes":{"getRoleAdmin(bytes32)":"248a9ca3","grantRole(bytes32,address)":"2f2ff15d","hasRole(bytes32,address)":"91d14854","renounceRole(bytes32,address)":"36568abe","revokeRole(bytes32,address)":"d547741f"}},"solidity/FastBridgeV2.sol:IAccessControlEnumerable":{"code":"0x","runtime-code":"0x","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.24 ^0.8.0 ^0.8.20;\n\n// contracts/interfaces/IAdmin.sol\n\ninterface IAdmin {\n // ============ Events ============\n\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n event ChainGasAmountUpdated(uint256 oldChainGasAmount, uint256 newChainGasAmount);\n\n // ============ Methods ============\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n\n function setChainGasAmount(uint256 newChainGasAmount) external;\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IFastBridgeRecipient.sol\n\ninterface IFastBridgeRecipient {\n function fastBridgeTransferReceived(\n address token,\n uint256 amount,\n bytes memory callParams\n )\n external\n payable\n returns (bytes4);\n}\n\n// contracts/interfaces/IFastBridgeV2Errors.sol\n\ninterface IFastBridgeV2Errors {\n error AmountIncorrect();\n error CallParamsLengthAboveMax();\n error ChainIncorrect();\n error ExclusivityParamsIncorrect();\n error MsgValueIncorrect();\n error NativeTokenCallValueNotSupported();\n error SenderIncorrect();\n error StatusIncorrect();\n error ZeroAddress();\n\n error RecipientIncorrectReturnValue();\n error RecipientNoReturnValue();\n\n error DeadlineExceeded();\n error DeadlineNotExceeded();\n error DeadlineTooShort();\n error DisputePeriodNotPassed();\n error DisputePeriodPassed();\n error ExclusivityPeriodNotPassed();\n\n error TransactionRelayed();\n}\n\n// contracts/libs/Errors.sol\n\nerror DeadlineExceeded();\nerror DeadlineNotExceeded();\nerror DeadlineTooShort();\nerror InsufficientOutputAmount();\n\nerror MsgValueIncorrect();\nerror PoolNotFound();\nerror TokenAddressMismatch();\nerror TokenNotContract();\nerror TokenNotETH();\nerror TokensIdentical();\n\nerror ChainIncorrect();\nerror AmountIncorrect();\nerror ZeroAddress();\n\nerror DisputePeriodNotPassed();\nerror DisputePeriodPassed();\nerror SenderIncorrect();\nerror StatusIncorrect();\nerror TransactionIdIncorrect();\nerror TransactionRelayed();\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// contracts/interfaces/IFastBridgeV2.sol\n\ninterface IFastBridgeV2 is IFastBridge {\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n struct BridgeTxDetails {\n BridgeStatus status;\n uint40 proofBlockTimestamp;\n uint48 proofBlockNumber;\n address proofRelayer;\n }\n\n struct BridgeRelay {\n uint48 blockNumber;\n uint48 blockTimestamp;\n address relayer;\n }\n\n /// @notice New params introduced in the FastBridgeV2.\n /// We are passing fields from the older BridgeParams struct outside of this struct\n /// for backwards compatibility.\n /// Note: quoteRelayer and quoteExclusivitySeconds are either both zero (indicating no exclusivity)\n /// or both non-zero (indicating exclusivity for the given period).\n /// Note: callValue \u003e 0 can NOT be used with destToken = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE (ETH_ADDRESS)\n /// @param quoteRelayer Relayer that provided the quote for the transaction\n /// @param quoteExclusivitySeconds Period of time the quote relayer is guaranteed exclusivity after user's deposit\n /// @param quoteId Unique quote identifier used for tracking the quote\n /// @param callValue ETH value to send to the recipient (if any)\n /// @param callParams Parameters for the arbitrary call to the destination recipient (if any)\n struct BridgeParamsV2 {\n address quoteRelayer;\n int256 quoteExclusivitySeconds;\n bytes quoteId;\n uint256 callValue;\n bytes callParams;\n }\n\n /// @notice Updated bridge transaction struct to include parameters introduced in FastBridgeV2.\n /// Note: only `exclusivityRelayer` can fill such a transaction until `exclusivityEndTime`.\n /// TODO: consider changing the encoding scheme to prevent spending extra gas on decoding.\n struct BridgeTransactionV2 {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n uint256 callValue; // ETH value to send to the recipient (if any) - replaces V1's sendChainGas flag\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n address exclusivityRelayer;\n uint256 exclusivityEndTime;\n bytes callParams;\n }\n\n event BridgeQuoteDetails(bytes32 indexed transactionId, bytes quoteId);\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability\n /// to provide temporary exclusivity fill rights for the quote relayer.\n /// @param params The parameters required to bridge\n /// @param paramsV2 The parameters for exclusivity fill rights (optional, can be left empty)\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function relay(bytes memory request, address relayer) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param transactionId The transaction id associated with the encoded bridge transaction to prove\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital.\n /// @notice Can only send funds to the relayer address on the proof.\n /// @param request The encoded bridge transaction to claim on origin chain\n function claim(bytes memory request) external;\n /// @notice Checks if a transaction has been relayed\n /// @param transactionId The ID of the transaction to check\n /// @return True if the transaction has been relayed, false otherwise\n function bridgeRelays(bytes32 transactionId) external view returns (bool);\n\n /// @notice Returns the status of a bridge transaction\n /// @param transactionId The ID of the bridge transaction\n /// @return BridgeStatus Status of the bridge transaction\n function bridgeStatuses(bytes32 transactionId) external view returns (BridgeStatus);\n\n /// @notice Returns the timestamp and relayer of a bridge proof\n /// @param transactionId The ID of the bridge transaction\n /// @return timestamp The timestamp of the bridge proof\n /// @return relayer The relayer address of the bridge proof\n function bridgeProofs(bytes32 transactionId) external view returns (uint96 timestamp, address relayer);\n\n /// @notice Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\n /// @param request The bridge request to decode\n function getBridgeTransactionV2(bytes memory request) external view returns (BridgeTransactionV2 memory);\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// contracts/libs/UniversalToken.sol\n\nlibrary UniversalTokenLib {\n using SafeERC20 for IERC20;\n\n address internal constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Transfers tokens to the given account. Reverts if transfer is not successful.\n /// @dev This might trigger fallback, if ETH is transferred to the contract.\n /// Make sure this can not lead to reentrancy attacks.\n function universalTransfer(address token, address to, uint256 value) internal {\n // Don't do anything, if need to send tokens to this address\n if (to == address(this)) return;\n // Don't do anything, if trying to send zero value\n if (value == 0) return;\n if (token == ETH_ADDRESS) {\n /// @dev Note: this can potentially lead to executing code in `to`.\n // solhint-disable-next-line avoid-low-level-calls\n (bool success,) = to.call{value: value}(\"\");\n require(success, \"ETH transfer failed\");\n } else {\n IERC20(token).safeTransfer(to, value);\n }\n }\n\n /// @notice Issues an infinite allowance to the spender, if the current allowance is insufficient\n /// to spend the given amount.\n function universalApproveInfinity(address token, address spender, uint256 amountToSpend) internal {\n // ETH Chad doesn't require your approval\n if (token == ETH_ADDRESS) return;\n // No-op if allowance is already sufficient\n uint256 allowance = IERC20(token).allowance(address(this), spender);\n if (allowance \u003e= amountToSpend) return;\n // Otherwise, reset approval to 0 and set to max allowance\n if (allowance \u003e 0) IERC20(token).safeDecreaseAllowance(spender, allowance);\n IERC20(token).safeIncreaseAllowance(spender, type(uint256).max);\n }\n\n /// @notice Returns the balance of the given token (or native ETH) for the given account.\n function universalBalanceOf(address token, address account) internal view returns (uint256) {\n if (token == ETH_ADDRESS) {\n return account.balance;\n } else {\n return IERC20(token).balanceOf(account);\n }\n }\n\n /// @dev Checks that token is a contract and not ETH_ADDRESS.\n function assertIsContract(address token) internal view {\n // Check that ETH_ADDRESS was not used (in case this is a predeploy on any of the chains)\n if (token == UniversalTokenLib.ETH_ADDRESS) revert TokenNotContract();\n // Check that token is not an EOA\n if (token.code.length == 0) revert TokenNotContract();\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/Admin.sol\n\ncontract Admin is IAdmin, AccessControlEnumerable {\n using UniversalTokenLib for address;\n\n bytes32 public constant RELAYER_ROLE = keccak256(\"RELAYER_ROLE\");\n bytes32 public constant REFUNDER_ROLE = keccak256(\"REFUNDER_ROLE\");\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n uint256 public constant FEE_BPS = 1e6;\n uint256 public constant FEE_RATE_MAX = 0.01e6; // max 1% on origin amount\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Chain gas amount to forward as rebate if requested\n uint256 public chainGasAmount;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n }\n\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n require(newFeeRate \u003c= FEE_RATE_MAX, \"newFeeRate \u003e max\");\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n token.universalTransfer(recipient, feeAmount);\n emit FeesSwept(token, recipient, feeAmount);\n }\n\n function setChainGasAmount(uint256 newChainGasAmount) external onlyRole(GOVERNOR_ROLE) {\n uint256 oldChainGasAmount = chainGasAmount;\n chainGasAmount = newChainGasAmount;\n emit ChainGasAmountUpdated(oldChainGasAmount, newChainGasAmount);\n }\n}\n\n// contracts/FastBridgeV2.sol\n\n/// @notice FastBridgeV2 is a contract for bridging tokens across chains.\ncontract FastBridgeV2 is Admin, IFastBridgeV2, IFastBridgeV2Errors {\n using SafeERC20 for IERC20;\n using UniversalTokenLib for address;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Delay for a transaction after which it could be permisionlessly refunded\n uint256 public constant REFUND_DELAY = 7 days;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n /// @notice Maximum length of accepted callParams\n uint256 public constant MAX_CALL_PARAMS_LENGTH = 2 ** 16 - 1;\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeTxDetails) public bridgeTxDetails;\n /// @notice Relay details on destination chain\n mapping(bytes32 =\u003e BridgeRelay) public bridgeRelayDetails;\n /// @notice Unique bridge nonces tracked per originSender\n mapping(address =\u003e uint256) public senderNonces;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Replaced by senderNonces\n uint256 public immutable nonce = 0;\n /// @notice the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n bridge({\n params: params,\n paramsV2: BridgeParamsV2({\n quoteRelayer: address(0),\n quoteExclusivitySeconds: 0,\n quoteId: bytes(\"\"),\n callValue: 0,\n callParams: bytes(\"\")\n })\n });\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes memory request) external payable {\n relay({request: request, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes memory request, bytes32 destTxHash) external {\n prove({transactionId: keccak256(request), destTxHash: destTxHash, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridgeV2\n function claim(bytes memory request) external {\n claim({request: request, to: address(0)});\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003e DISPUTE_PERIOD) {\n revert DisputePeriodPassed();\n }\n\n // @dev relayer gets slashed effectively if dest relay has gone thru\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n bridgeTxDetails[transactionId].proofRelayer = address(0);\n bridgeTxDetails[transactionId].proofBlockTimestamp = 0;\n bridgeTxDetails[transactionId].proofBlockNumber = 0;\n\n emit BridgeProofDisputed(transactionId, msg.sender);\n }\n\n /// @inheritdoc IFastBridge\n function refund(bytes memory request) external {\n bytes32 transactionId = keccak256(request);\n\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n\n if (bridgeTxDetails[transactionId].status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n\n if (hasRole(REFUNDER_ROLE, msg.sender)) {\n // Refunder can refund if deadline has passed\n if (block.timestamp \u003c= transaction.deadline) revert DeadlineNotExceeded();\n } else {\n // Permissionless refund is allowed after REFUND_DELAY\n if (block.timestamp \u003c= transaction.deadline + REFUND_DELAY) revert DeadlineNotExceeded();\n }\n\n // if all checks passed, set to REFUNDED status\n bridgeTxDetails[transactionId].status = BridgeStatus.REFUNDED;\n\n // transfer origin collateral back to original sender\n address to = transaction.originSender;\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount + transaction.originFeeAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (bridgeTxDetails[transactionId].proofRelayer != relayer) revert SenderIncorrect();\n return _timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n /// @dev This method is added to achieve backwards compatibility with decoding requests into V1 structs:\n /// - `callValue` is partially reported as a zero/non-zero flag\n /// - `callParams` is ignored\n /// In order to process all kinds of requests use getBridgeTransactionV2 instead.\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory) {\n // Try decoding into V2 struct first. This will revert if V1 struct is passed\n try this.getBridgeTransactionV2(request) returns (BridgeTransactionV2 memory txV2) {\n // Note: we entirely ignore the callParams field, as it was not present in V1\n return BridgeTransaction({\n originChainId: txV2.originChainId,\n destChainId: txV2.destChainId,\n originSender: txV2.originSender,\n destRecipient: txV2.destRecipient,\n originToken: txV2.originToken,\n destToken: txV2.destToken,\n originAmount: txV2.originAmount,\n destAmount: txV2.destAmount,\n originFeeAmount: txV2.originFeeAmount,\n sendChainGas: txV2.callValue != 0,\n deadline: txV2.deadline,\n nonce: txV2.nonce\n });\n } catch {\n // Fallback to V1 struct\n return abi.decode(request, (BridgeTransaction));\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) public payable {\n int256 exclusivityEndTime = int256(block.timestamp) + paramsV2.quoteExclusivitySeconds;\n _validateBridgeParams(params, paramsV2, exclusivityEndTime);\n\n // transfer tokens to bridge contract\n /// @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _pullToken(params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n\n // set status to requested\n bytes memory request = abi.encode(\n BridgeTransactionV2({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n callValue: paramsV2.callValue,\n deadline: params.deadline,\n nonce: senderNonces[params.sender]++, // increment nonce on every bridge\n exclusivityRelayer: paramsV2.quoteRelayer,\n // We checked exclusivityEndTime to be in range (0 .. params.deadline] above, so can safely cast\n exclusivityEndTime: uint256(exclusivityEndTime),\n callParams: paramsV2.callParams\n })\n );\n bytes32 transactionId = keccak256(request);\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n\n emit BridgeRequested({\n transactionId: transactionId,\n sender: params.sender,\n request: request,\n destChainId: params.dstChainId,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n sendChainGas: paramsV2.callValue != 0\n });\n emit BridgeQuoteDetails(transactionId, paramsV2.quoteId);\n }\n\n /// @inheritdoc IFastBridgeV2\n function relay(bytes memory request, address relayer) public payable {\n bytes32 transactionId = keccak256(request);\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n _validateRelayParams(transaction, transactionId, relayer);\n // mark bridge transaction as relayed\n bridgeRelayDetails[transactionId] =\n BridgeRelay({blockNumber: uint48(block.number), blockTimestamp: uint48(block.timestamp), relayer: relayer});\n\n // transfer tokens to recipient on destination chain and do an arbitrary call if requested\n address to = transaction.destRecipient;\n address token = transaction.destToken;\n uint256 amount = transaction.destAmount;\n\n // All state changes have been done at this point, can proceed to the external calls.\n // This follows the checks-effects-interactions pattern to mitigate potential reentrancy attacks.\n if (token == UniversalTokenLib.ETH_ADDRESS) {\n // For ETH non-zero callValue is not allowed\n if (transaction.callValue != 0) revert NativeTokenCallValueNotSupported();\n // Check that the correct msg.value was sent\n if (msg.value != amount) revert MsgValueIncorrect();\n } else {\n // For ERC20s, we check that the correct msg.value was sent\n if (msg.value != transaction.callValue) revert MsgValueIncorrect();\n // We need to transfer the tokens from the Relayer to the recipient first before performing an\n // optional post-transfer arbitrary call.\n IERC20(token).safeTransferFrom(msg.sender, to, amount);\n }\n\n if (transaction.callParams.length != 0) {\n // Arbitrary call requested, perform it while supplying full msg.value to the recipient\n // Note: if token has a fee on transfers, the recipient will have received less than `amount`.\n // This is a very niche edge case and should be handled by the recipient contract.\n _checkedCallRecipient({recipient: to, token: token, amount: amount, callParams: transaction.callParams});\n } else if (msg.value != 0) {\n // No arbitrary call requested, but msg.value was sent. This is either a relay with ETH,\n // or a non-zero callValue request with an ERC20. In both cases, transfer the ETH to the recipient.\n Address.sendValue(payable(to), msg.value);\n }\n\n emit BridgeRelayed({\n transactionId: transactionId,\n relayer: relayer,\n to: to,\n originChainId: transaction.originChainId,\n originToken: transaction.originToken,\n destToken: transaction.destToken,\n originAmount: transaction.originAmount,\n destAmount: transaction.destAmount,\n chainGasAmount: transaction.callValue\n });\n }\n\n /// @inheritdoc IFastBridgeV2\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) public onlyRole(RELAYER_ROLE) {\n // update bridge tx status given proof provided\n if (bridgeTxDetails[transactionId].status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n bridgeTxDetails[transactionId].status = BridgeStatus.RELAYER_PROVED;\n bridgeTxDetails[transactionId].proofBlockTimestamp = uint40(block.timestamp);\n bridgeTxDetails[transactionId].proofBlockNumber = uint48(block.number);\n bridgeTxDetails[transactionId].proofRelayer = relayer;\n\n emit BridgeProofProvided(transactionId, relayer, destTxHash);\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes memory request, address to) public {\n bytes32 transactionId = keccak256(request);\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n\n // update bridge tx status if able to claim origin collateral\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n\n // if \"to\" is zero addr, permissionlessly send funds to proven relayer\n if (to == address(0)) {\n to = bridgeTxDetails[transactionId].proofRelayer;\n } else if (bridgeTxDetails[transactionId].proofRelayer != msg.sender) {\n revert SenderIncorrect();\n }\n\n if (_timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003c= DISPUTE_PERIOD) {\n revert DisputePeriodNotPassed();\n }\n\n bridgeTxDetails[transactionId].status = BridgeStatus.RELAYER_CLAIMED;\n\n // update protocol fees if origin fee amount exists\n if (transaction.originFeeAmount \u003e 0) protocolFees[transaction.originToken] += transaction.originFeeAmount;\n\n // transfer origin collateral less fee to specified address\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositClaimed(transactionId, bridgeTxDetails[transactionId].proofRelayer, to, token, amount);\n }\n\n function bridgeStatuses(bytes32 transactionId) public view returns (BridgeStatus status) {\n return bridgeTxDetails[transactionId].status;\n }\n\n function bridgeProofs(bytes32 transactionId) public view returns (uint96 timestamp, address relayer) {\n timestamp = bridgeTxDetails[transactionId].proofBlockTimestamp;\n relayer = bridgeTxDetails[transactionId].proofRelayer;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeRelays(bytes32 transactionId) public view returns (bool) {\n // has this transactionId been relayed?\n return bridgeRelayDetails[transactionId].relayer != address(0);\n }\n\n /// @inheritdoc IFastBridgeV2\n function getBridgeTransactionV2(bytes memory request) public pure returns (BridgeTransactionV2 memory) {\n return abi.decode(request, (BridgeTransactionV2));\n }\n\n /// @notice Pulls a requested token from the user to this contract.\n function _pullToken(address token, uint256 amount) internal returns (uint256 amountPulled) {\n if (token == UniversalTokenLib.ETH_ADDRESS) {\n // For ETH we just need to check that the supplied msg.value is correct\n if (amount != msg.value) revert MsgValueIncorrect();\n amountPulled = msg.value;\n } else {\n token.assertIsContract();\n // Record token balance before transfer\n amountPulled = IERC20(token).balanceOf(address(this));\n // Token needs to be pulled only if msg.value is zero\n // This way user can specify WETH as the origin asset\n IERC20(token).safeTransferFrom(msg.sender, address(this), amount);\n // Use the difference between the recorded balance and the current balance as the amountPulled\n amountPulled = IERC20(token).balanceOf(address(this)) - amountPulled;\n }\n }\n\n /// @notice Calls the Recipient's hook function with the specified callParams and performs\n /// all the necessary checks for the returned value.\n function _checkedCallRecipient(\n address recipient,\n address token,\n uint256 amount,\n bytes memory callParams\n )\n internal\n {\n bytes memory hookData =\n abi.encodeCall(IFastBridgeRecipient.fastBridgeTransferReceived, (token, amount, callParams));\n // This will bubble any revert messages from the hook function\n bytes memory returnData = Address.functionCallWithValue({target: recipient, data: hookData, value: msg.value});\n // Explicit revert if no return data at all\n if (returnData.length == 0) revert RecipientNoReturnValue();\n // Check that exactly a single return value was returned\n if (returnData.length != 32) revert RecipientIncorrectReturnValue();\n // Return value should be abi-encoded hook function selector\n if (bytes32(returnData) != bytes32(IFastBridgeRecipient.fastBridgeTransferReceived.selector)) {\n revert RecipientIncorrectReturnValue();\n }\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint40(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint40).max but\n /// proof.timestamp \u003c type(uint40).max via unchecked statement\n /// @param proofBlockTimestamp The bridge proof block timestamp\n /// @return delta Time delta since proof submitted\n function _timeSince(uint40 proofBlockTimestamp) internal view returns (uint256 delta) {\n unchecked {\n delta = uint40(block.timestamp) - proofBlockTimestamp;\n }\n }\n\n /// @notice Performs all the necessary checks for a bridge to happen.\n /// @dev There's no good way to refactor this function to reduce cyclomatic complexity due to\n /// the number of checks that need to be performed, so we skip the code-complexity rule here.\n // solhint-disable-next-line code-complexity\n function _validateBridgeParams(\n BridgeParams memory params,\n BridgeParamsV2 memory paramsV2,\n int256 exclusivityEndTime\n )\n internal\n view\n {\n // Check V1 (legacy) params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.sender == address(0) || params.to == address(0)) revert ZeroAddress();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n // Check V2 params\n if (paramsV2.callParams.length \u003e MAX_CALL_PARAMS_LENGTH) revert CallParamsLengthAboveMax();\n if (paramsV2.callValue != 0 \u0026\u0026 params.destToken == UniversalTokenLib.ETH_ADDRESS) {\n revert NativeTokenCallValueNotSupported();\n }\n // exclusivityEndTime must be in range (0 .. params.deadline]\n if (exclusivityEndTime \u003c= 0 || exclusivityEndTime \u003e int256(params.deadline)) {\n revert ExclusivityParamsIncorrect();\n }\n }\n\n /// @notice Performs all the necessary checks for a relay to happen.\n function _validateRelayParams(\n BridgeTransactionV2 memory transaction,\n bytes32 transactionId,\n address relayer\n )\n internal\n view\n {\n if (relayer == address(0)) revert ZeroAddress();\n // Check if the transaction has already been relayed\n if (bridgeRelays(transactionId)) revert TransactionRelayed();\n if (transaction.destChainId != uint32(block.chainid)) revert ChainIncorrect();\n // Check the deadline for relay to happen\n if (block.timestamp \u003e transaction.deadline) revert DeadlineExceeded();\n // Check the exclusivity period, if it is still ongoing\n // forgefmt: disable-next-item\n if (\n transaction.exclusivityRelayer != address(0) \u0026\u0026\n transaction.exclusivityRelayer != relayer \u0026\u0026\n block.timestamp \u003c= transaction.exclusivityEndTime\n ) {\n revert ExclusivityPeriodNotPassed();\n }\n }\n}\n","language":"Solidity","languageVersion":"0.8.24","compilerVersion":"0.8.24","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../","srcMap":"","srcMapRuntime":"","abiDefinition":[{"inputs":[],"name":"AccessControlBadConfirmation","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"bytes32","name":"neededRole","type":"bytes32"}],"name":"AccessControlUnauthorizedAccount","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"previousAdminRole","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"newAdminRole","type":"bytes32"}],"name":"RoleAdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleRevoked","type":"event"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleAdmin","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"uint256","name":"index","type":"uint256"}],"name":"getRoleMember","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleMemberCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"grantRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"hasRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"callerConfirmation","type":"address"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"revokeRole","outputs":[],"stateMutability":"nonpayable","type":"function"}],"userDoc":{"kind":"user","methods":{},"version":1},"developerDoc":{"details":"External interface of AccessControlEnumerable declared to support ERC165 detection.","errors":{"AccessControlBadConfirmation()":[{"details":"The caller of a function is not the expected one. NOTE: Don't confuse with {AccessControlUnauthorizedAccount}."}],"AccessControlUnauthorizedAccount(address,bytes32)":[{"details":"The `account` is missing a role."}]},"events":{"RoleAdminChanged(bytes32,bytes32,bytes32)":{"details":"Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole` `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite {RoleAdminChanged} not being emitted signaling this."},"RoleGranted(bytes32,address,address)":{"details":"Emitted when `account` is granted `role`. `sender` is the account that originated the contract call, an admin role bearer except when using {AccessControl-_setupRole}."},"RoleRevoked(bytes32,address,address)":{"details":"Emitted when `account` is revoked `role`. `sender` is the account that originated the contract call: - if using `revokeRole`, it is the admin role bearer - if using `renounceRole`, it is the role bearer (i.e. `account`)"}},"kind":"dev","methods":{"getRoleAdmin(bytes32)":{"details":"Returns the admin role that controls `role`. See {grantRole} and {revokeRole}. To change a role's admin, use {AccessControl-_setRoleAdmin}."},"getRoleMember(bytes32,uint256)":{"details":"Returns one of the accounts that have `role`. `index` must be a value between 0 and {getRoleMemberCount}, non-inclusive. Role bearers are not sorted in any particular way, and their ordering may change at any point. WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure you perform all queries on the same block. See the following https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post] for more information."},"getRoleMemberCount(bytes32)":{"details":"Returns the number of accounts that have `role`. Can be used together with {getRoleMember} to enumerate all bearers of a role."},"grantRole(bytes32,address)":{"details":"Grants `role` to `account`. If `account` had not been already granted `role`, emits a {RoleGranted} event. Requirements: - the caller must have ``role``'s admin role."},"hasRole(bytes32,address)":{"details":"Returns `true` if `account` has been granted `role`."},"renounceRole(bytes32,address)":{"details":"Revokes `role` from the calling account. Roles are often managed via {grantRole} and {revokeRole}: this function's purpose is to provide a mechanism for accounts to lose their privileges if they are compromised (such as when a trusted device is misplaced). If the calling account had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must be `callerConfirmation`."},"revokeRole(bytes32,address)":{"details":"Revokes `role` from `account`. If `account` had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must have ``role``'s admin role."}},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[],\"name\":\"AccessControlBadConfirmation\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"neededRole\",\"type\":\"bytes32\"}],\"name\":\"AccessControlUnauthorizedAccount\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"previousAdminRole\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"newAdminRole\",\"type\":\"bytes32\"}],\"name\":\"RoleAdminChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleGranted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleRevoked\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"}],\"name\":\"getRoleAdmin\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"index\",\"type\":\"uint256\"}],\"name\":\"getRoleMember\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"}],\"name\":\"getRoleMemberCount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"grantRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"hasRole\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"callerConfirmation\",\"type\":\"address\"}],\"name\":\"renounceRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"revokeRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"details\":\"External interface of AccessControlEnumerable declared to support ERC165 detection.\",\"errors\":{\"AccessControlBadConfirmation()\":[{\"details\":\"The caller of a function is not the expected one. NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\"}],\"AccessControlUnauthorizedAccount(address,bytes32)\":[{\"details\":\"The `account` is missing a role.\"}]},\"events\":{\"RoleAdminChanged(bytes32,bytes32,bytes32)\":{\"details\":\"Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole` `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite {RoleAdminChanged} not being emitted signaling this.\"},\"RoleGranted(bytes32,address,address)\":{\"details\":\"Emitted when `account` is granted `role`. `sender` is the account that originated the contract call, an admin role bearer except when using {AccessControl-_setupRole}.\"},\"RoleRevoked(bytes32,address,address)\":{\"details\":\"Emitted when `account` is revoked `role`. `sender` is the account that originated the contract call: - if using `revokeRole`, it is the admin role bearer - if using `renounceRole`, it is the role bearer (i.e. `account`)\"}},\"kind\":\"dev\",\"methods\":{\"getRoleAdmin(bytes32)\":{\"details\":\"Returns the admin role that controls `role`. See {grantRole} and {revokeRole}. To change a role's admin, use {AccessControl-_setRoleAdmin}.\"},\"getRoleMember(bytes32,uint256)\":{\"details\":\"Returns one of the accounts that have `role`. `index` must be a value between 0 and {getRoleMemberCount}, non-inclusive. Role bearers are not sorted in any particular way, and their ordering may change at any point. WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure you perform all queries on the same block. See the following https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post] for more information.\"},\"getRoleMemberCount(bytes32)\":{\"details\":\"Returns the number of accounts that have `role`. Can be used together with {getRoleMember} to enumerate all bearers of a role.\"},\"grantRole(bytes32,address)\":{\"details\":\"Grants `role` to `account`. If `account` had not been already granted `role`, emits a {RoleGranted} event. Requirements: - the caller must have ``role``'s admin role.\"},\"hasRole(bytes32,address)\":{\"details\":\"Returns `true` if `account` has been granted `role`.\"},\"renounceRole(bytes32,address)\":{\"details\":\"Revokes `role` from the calling account. Roles are often managed via {grantRole} and {revokeRole}: this function's purpose is to provide a mechanism for accounts to lose their privileges if they are compromised (such as when a trusted device is misplaced). If the calling account had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must be `callerConfirmation`.\"},\"revokeRole(bytes32,address)\":{\"details\":\"Revokes `role` from `account`. If `account` had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must have ``role``'s admin role.\"}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeV2.sol\":\"IAccessControlEnumerable\"},\"evmVersion\":\"shanghai\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeV2.sol\":{\"keccak256\":\"0x7cd0f885e80e2bdaa638bc32ae7af7d2e248f99ce4b354c217d0f0f7d7302e0a\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://7ccf28df0bd7b4606986585acd8622ed9b4e81379690061bb66088f0a2270af1\",\"dweb:/ipfs/QmTf7HNdHZkK6vmx8ZgewycQEb72oLD9nPwBpsM5reMstQ\"]}},\"version\":1}"},"hashes":{"getRoleAdmin(bytes32)":"248a9ca3","getRoleMember(bytes32,uint256)":"9010d07c","getRoleMemberCount(bytes32)":"ca15c873","grantRole(bytes32,address)":"2f2ff15d","hasRole(bytes32,address)":"91d14854","renounceRole(bytes32,address)":"36568abe","revokeRole(bytes32,address)":"d547741f"}},"solidity/FastBridgeV2.sol:IAdmin":{"code":"0x","runtime-code":"0x","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.24 ^0.8.0 ^0.8.20;\n\n// contracts/interfaces/IAdmin.sol\n\ninterface IAdmin {\n // ============ Events ============\n\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n event ChainGasAmountUpdated(uint256 oldChainGasAmount, uint256 newChainGasAmount);\n\n // ============ Methods ============\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n\n function setChainGasAmount(uint256 newChainGasAmount) external;\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IFastBridgeRecipient.sol\n\ninterface IFastBridgeRecipient {\n function fastBridgeTransferReceived(\n address token,\n uint256 amount,\n bytes memory callParams\n )\n external\n payable\n returns (bytes4);\n}\n\n// contracts/interfaces/IFastBridgeV2Errors.sol\n\ninterface IFastBridgeV2Errors {\n error AmountIncorrect();\n error CallParamsLengthAboveMax();\n error ChainIncorrect();\n error ExclusivityParamsIncorrect();\n error MsgValueIncorrect();\n error NativeTokenCallValueNotSupported();\n error SenderIncorrect();\n error StatusIncorrect();\n error ZeroAddress();\n\n error RecipientIncorrectReturnValue();\n error RecipientNoReturnValue();\n\n error DeadlineExceeded();\n error DeadlineNotExceeded();\n error DeadlineTooShort();\n error DisputePeriodNotPassed();\n error DisputePeriodPassed();\n error ExclusivityPeriodNotPassed();\n\n error TransactionRelayed();\n}\n\n// contracts/libs/Errors.sol\n\nerror DeadlineExceeded();\nerror DeadlineNotExceeded();\nerror DeadlineTooShort();\nerror InsufficientOutputAmount();\n\nerror MsgValueIncorrect();\nerror PoolNotFound();\nerror TokenAddressMismatch();\nerror TokenNotContract();\nerror TokenNotETH();\nerror TokensIdentical();\n\nerror ChainIncorrect();\nerror AmountIncorrect();\nerror ZeroAddress();\n\nerror DisputePeriodNotPassed();\nerror DisputePeriodPassed();\nerror SenderIncorrect();\nerror StatusIncorrect();\nerror TransactionIdIncorrect();\nerror TransactionRelayed();\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// contracts/interfaces/IFastBridgeV2.sol\n\ninterface IFastBridgeV2 is IFastBridge {\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n struct BridgeTxDetails {\n BridgeStatus status;\n uint40 proofBlockTimestamp;\n uint48 proofBlockNumber;\n address proofRelayer;\n }\n\n struct BridgeRelay {\n uint48 blockNumber;\n uint48 blockTimestamp;\n address relayer;\n }\n\n /// @notice New params introduced in the FastBridgeV2.\n /// We are passing fields from the older BridgeParams struct outside of this struct\n /// for backwards compatibility.\n /// Note: quoteRelayer and quoteExclusivitySeconds are either both zero (indicating no exclusivity)\n /// or both non-zero (indicating exclusivity for the given period).\n /// Note: callValue \u003e 0 can NOT be used with destToken = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE (ETH_ADDRESS)\n /// @param quoteRelayer Relayer that provided the quote for the transaction\n /// @param quoteExclusivitySeconds Period of time the quote relayer is guaranteed exclusivity after user's deposit\n /// @param quoteId Unique quote identifier used for tracking the quote\n /// @param callValue ETH value to send to the recipient (if any)\n /// @param callParams Parameters for the arbitrary call to the destination recipient (if any)\n struct BridgeParamsV2 {\n address quoteRelayer;\n int256 quoteExclusivitySeconds;\n bytes quoteId;\n uint256 callValue;\n bytes callParams;\n }\n\n /// @notice Updated bridge transaction struct to include parameters introduced in FastBridgeV2.\n /// Note: only `exclusivityRelayer` can fill such a transaction until `exclusivityEndTime`.\n /// TODO: consider changing the encoding scheme to prevent spending extra gas on decoding.\n struct BridgeTransactionV2 {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n uint256 callValue; // ETH value to send to the recipient (if any) - replaces V1's sendChainGas flag\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n address exclusivityRelayer;\n uint256 exclusivityEndTime;\n bytes callParams;\n }\n\n event BridgeQuoteDetails(bytes32 indexed transactionId, bytes quoteId);\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability\n /// to provide temporary exclusivity fill rights for the quote relayer.\n /// @param params The parameters required to bridge\n /// @param paramsV2 The parameters for exclusivity fill rights (optional, can be left empty)\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function relay(bytes memory request, address relayer) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param transactionId The transaction id associated with the encoded bridge transaction to prove\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital.\n /// @notice Can only send funds to the relayer address on the proof.\n /// @param request The encoded bridge transaction to claim on origin chain\n function claim(bytes memory request) external;\n /// @notice Checks if a transaction has been relayed\n /// @param transactionId The ID of the transaction to check\n /// @return True if the transaction has been relayed, false otherwise\n function bridgeRelays(bytes32 transactionId) external view returns (bool);\n\n /// @notice Returns the status of a bridge transaction\n /// @param transactionId The ID of the bridge transaction\n /// @return BridgeStatus Status of the bridge transaction\n function bridgeStatuses(bytes32 transactionId) external view returns (BridgeStatus);\n\n /// @notice Returns the timestamp and relayer of a bridge proof\n /// @param transactionId The ID of the bridge transaction\n /// @return timestamp The timestamp of the bridge proof\n /// @return relayer The relayer address of the bridge proof\n function bridgeProofs(bytes32 transactionId) external view returns (uint96 timestamp, address relayer);\n\n /// @notice Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\n /// @param request The bridge request to decode\n function getBridgeTransactionV2(bytes memory request) external view returns (BridgeTransactionV2 memory);\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// contracts/libs/UniversalToken.sol\n\nlibrary UniversalTokenLib {\n using SafeERC20 for IERC20;\n\n address internal constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Transfers tokens to the given account. Reverts if transfer is not successful.\n /// @dev This might trigger fallback, if ETH is transferred to the contract.\n /// Make sure this can not lead to reentrancy attacks.\n function universalTransfer(address token, address to, uint256 value) internal {\n // Don't do anything, if need to send tokens to this address\n if (to == address(this)) return;\n // Don't do anything, if trying to send zero value\n if (value == 0) return;\n if (token == ETH_ADDRESS) {\n /// @dev Note: this can potentially lead to executing code in `to`.\n // solhint-disable-next-line avoid-low-level-calls\n (bool success,) = to.call{value: value}(\"\");\n require(success, \"ETH transfer failed\");\n } else {\n IERC20(token).safeTransfer(to, value);\n }\n }\n\n /// @notice Issues an infinite allowance to the spender, if the current allowance is insufficient\n /// to spend the given amount.\n function universalApproveInfinity(address token, address spender, uint256 amountToSpend) internal {\n // ETH Chad doesn't require your approval\n if (token == ETH_ADDRESS) return;\n // No-op if allowance is already sufficient\n uint256 allowance = IERC20(token).allowance(address(this), spender);\n if (allowance \u003e= amountToSpend) return;\n // Otherwise, reset approval to 0 and set to max allowance\n if (allowance \u003e 0) IERC20(token).safeDecreaseAllowance(spender, allowance);\n IERC20(token).safeIncreaseAllowance(spender, type(uint256).max);\n }\n\n /// @notice Returns the balance of the given token (or native ETH) for the given account.\n function universalBalanceOf(address token, address account) internal view returns (uint256) {\n if (token == ETH_ADDRESS) {\n return account.balance;\n } else {\n return IERC20(token).balanceOf(account);\n }\n }\n\n /// @dev Checks that token is a contract and not ETH_ADDRESS.\n function assertIsContract(address token) internal view {\n // Check that ETH_ADDRESS was not used (in case this is a predeploy on any of the chains)\n if (token == UniversalTokenLib.ETH_ADDRESS) revert TokenNotContract();\n // Check that token is not an EOA\n if (token.code.length == 0) revert TokenNotContract();\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/Admin.sol\n\ncontract Admin is IAdmin, AccessControlEnumerable {\n using UniversalTokenLib for address;\n\n bytes32 public constant RELAYER_ROLE = keccak256(\"RELAYER_ROLE\");\n bytes32 public constant REFUNDER_ROLE = keccak256(\"REFUNDER_ROLE\");\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n uint256 public constant FEE_BPS = 1e6;\n uint256 public constant FEE_RATE_MAX = 0.01e6; // max 1% on origin amount\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Chain gas amount to forward as rebate if requested\n uint256 public chainGasAmount;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n }\n\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n require(newFeeRate \u003c= FEE_RATE_MAX, \"newFeeRate \u003e max\");\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n token.universalTransfer(recipient, feeAmount);\n emit FeesSwept(token, recipient, feeAmount);\n }\n\n function setChainGasAmount(uint256 newChainGasAmount) external onlyRole(GOVERNOR_ROLE) {\n uint256 oldChainGasAmount = chainGasAmount;\n chainGasAmount = newChainGasAmount;\n emit ChainGasAmountUpdated(oldChainGasAmount, newChainGasAmount);\n }\n}\n\n// contracts/FastBridgeV2.sol\n\n/// @notice FastBridgeV2 is a contract for bridging tokens across chains.\ncontract FastBridgeV2 is Admin, IFastBridgeV2, IFastBridgeV2Errors {\n using SafeERC20 for IERC20;\n using UniversalTokenLib for address;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Delay for a transaction after which it could be permisionlessly refunded\n uint256 public constant REFUND_DELAY = 7 days;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n /// @notice Maximum length of accepted callParams\n uint256 public constant MAX_CALL_PARAMS_LENGTH = 2 ** 16 - 1;\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeTxDetails) public bridgeTxDetails;\n /// @notice Relay details on destination chain\n mapping(bytes32 =\u003e BridgeRelay) public bridgeRelayDetails;\n /// @notice Unique bridge nonces tracked per originSender\n mapping(address =\u003e uint256) public senderNonces;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Replaced by senderNonces\n uint256 public immutable nonce = 0;\n /// @notice the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n bridge({\n params: params,\n paramsV2: BridgeParamsV2({\n quoteRelayer: address(0),\n quoteExclusivitySeconds: 0,\n quoteId: bytes(\"\"),\n callValue: 0,\n callParams: bytes(\"\")\n })\n });\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes memory request) external payable {\n relay({request: request, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes memory request, bytes32 destTxHash) external {\n prove({transactionId: keccak256(request), destTxHash: destTxHash, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridgeV2\n function claim(bytes memory request) external {\n claim({request: request, to: address(0)});\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003e DISPUTE_PERIOD) {\n revert DisputePeriodPassed();\n }\n\n // @dev relayer gets slashed effectively if dest relay has gone thru\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n bridgeTxDetails[transactionId].proofRelayer = address(0);\n bridgeTxDetails[transactionId].proofBlockTimestamp = 0;\n bridgeTxDetails[transactionId].proofBlockNumber = 0;\n\n emit BridgeProofDisputed(transactionId, msg.sender);\n }\n\n /// @inheritdoc IFastBridge\n function refund(bytes memory request) external {\n bytes32 transactionId = keccak256(request);\n\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n\n if (bridgeTxDetails[transactionId].status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n\n if (hasRole(REFUNDER_ROLE, msg.sender)) {\n // Refunder can refund if deadline has passed\n if (block.timestamp \u003c= transaction.deadline) revert DeadlineNotExceeded();\n } else {\n // Permissionless refund is allowed after REFUND_DELAY\n if (block.timestamp \u003c= transaction.deadline + REFUND_DELAY) revert DeadlineNotExceeded();\n }\n\n // if all checks passed, set to REFUNDED status\n bridgeTxDetails[transactionId].status = BridgeStatus.REFUNDED;\n\n // transfer origin collateral back to original sender\n address to = transaction.originSender;\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount + transaction.originFeeAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (bridgeTxDetails[transactionId].proofRelayer != relayer) revert SenderIncorrect();\n return _timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n /// @dev This method is added to achieve backwards compatibility with decoding requests into V1 structs:\n /// - `callValue` is partially reported as a zero/non-zero flag\n /// - `callParams` is ignored\n /// In order to process all kinds of requests use getBridgeTransactionV2 instead.\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory) {\n // Try decoding into V2 struct first. This will revert if V1 struct is passed\n try this.getBridgeTransactionV2(request) returns (BridgeTransactionV2 memory txV2) {\n // Note: we entirely ignore the callParams field, as it was not present in V1\n return BridgeTransaction({\n originChainId: txV2.originChainId,\n destChainId: txV2.destChainId,\n originSender: txV2.originSender,\n destRecipient: txV2.destRecipient,\n originToken: txV2.originToken,\n destToken: txV2.destToken,\n originAmount: txV2.originAmount,\n destAmount: txV2.destAmount,\n originFeeAmount: txV2.originFeeAmount,\n sendChainGas: txV2.callValue != 0,\n deadline: txV2.deadline,\n nonce: txV2.nonce\n });\n } catch {\n // Fallback to V1 struct\n return abi.decode(request, (BridgeTransaction));\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) public payable {\n int256 exclusivityEndTime = int256(block.timestamp) + paramsV2.quoteExclusivitySeconds;\n _validateBridgeParams(params, paramsV2, exclusivityEndTime);\n\n // transfer tokens to bridge contract\n /// @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _pullToken(params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n\n // set status to requested\n bytes memory request = abi.encode(\n BridgeTransactionV2({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n callValue: paramsV2.callValue,\n deadline: params.deadline,\n nonce: senderNonces[params.sender]++, // increment nonce on every bridge\n exclusivityRelayer: paramsV2.quoteRelayer,\n // We checked exclusivityEndTime to be in range (0 .. params.deadline] above, so can safely cast\n exclusivityEndTime: uint256(exclusivityEndTime),\n callParams: paramsV2.callParams\n })\n );\n bytes32 transactionId = keccak256(request);\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n\n emit BridgeRequested({\n transactionId: transactionId,\n sender: params.sender,\n request: request,\n destChainId: params.dstChainId,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n sendChainGas: paramsV2.callValue != 0\n });\n emit BridgeQuoteDetails(transactionId, paramsV2.quoteId);\n }\n\n /// @inheritdoc IFastBridgeV2\n function relay(bytes memory request, address relayer) public payable {\n bytes32 transactionId = keccak256(request);\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n _validateRelayParams(transaction, transactionId, relayer);\n // mark bridge transaction as relayed\n bridgeRelayDetails[transactionId] =\n BridgeRelay({blockNumber: uint48(block.number), blockTimestamp: uint48(block.timestamp), relayer: relayer});\n\n // transfer tokens to recipient on destination chain and do an arbitrary call if requested\n address to = transaction.destRecipient;\n address token = transaction.destToken;\n uint256 amount = transaction.destAmount;\n\n // All state changes have been done at this point, can proceed to the external calls.\n // This follows the checks-effects-interactions pattern to mitigate potential reentrancy attacks.\n if (token == UniversalTokenLib.ETH_ADDRESS) {\n // For ETH non-zero callValue is not allowed\n if (transaction.callValue != 0) revert NativeTokenCallValueNotSupported();\n // Check that the correct msg.value was sent\n if (msg.value != amount) revert MsgValueIncorrect();\n } else {\n // For ERC20s, we check that the correct msg.value was sent\n if (msg.value != transaction.callValue) revert MsgValueIncorrect();\n // We need to transfer the tokens from the Relayer to the recipient first before performing an\n // optional post-transfer arbitrary call.\n IERC20(token).safeTransferFrom(msg.sender, to, amount);\n }\n\n if (transaction.callParams.length != 0) {\n // Arbitrary call requested, perform it while supplying full msg.value to the recipient\n // Note: if token has a fee on transfers, the recipient will have received less than `amount`.\n // This is a very niche edge case and should be handled by the recipient contract.\n _checkedCallRecipient({recipient: to, token: token, amount: amount, callParams: transaction.callParams});\n } else if (msg.value != 0) {\n // No arbitrary call requested, but msg.value was sent. This is either a relay with ETH,\n // or a non-zero callValue request with an ERC20. In both cases, transfer the ETH to the recipient.\n Address.sendValue(payable(to), msg.value);\n }\n\n emit BridgeRelayed({\n transactionId: transactionId,\n relayer: relayer,\n to: to,\n originChainId: transaction.originChainId,\n originToken: transaction.originToken,\n destToken: transaction.destToken,\n originAmount: transaction.originAmount,\n destAmount: transaction.destAmount,\n chainGasAmount: transaction.callValue\n });\n }\n\n /// @inheritdoc IFastBridgeV2\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) public onlyRole(RELAYER_ROLE) {\n // update bridge tx status given proof provided\n if (bridgeTxDetails[transactionId].status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n bridgeTxDetails[transactionId].status = BridgeStatus.RELAYER_PROVED;\n bridgeTxDetails[transactionId].proofBlockTimestamp = uint40(block.timestamp);\n bridgeTxDetails[transactionId].proofBlockNumber = uint48(block.number);\n bridgeTxDetails[transactionId].proofRelayer = relayer;\n\n emit BridgeProofProvided(transactionId, relayer, destTxHash);\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes memory request, address to) public {\n bytes32 transactionId = keccak256(request);\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n\n // update bridge tx status if able to claim origin collateral\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n\n // if \"to\" is zero addr, permissionlessly send funds to proven relayer\n if (to == address(0)) {\n to = bridgeTxDetails[transactionId].proofRelayer;\n } else if (bridgeTxDetails[transactionId].proofRelayer != msg.sender) {\n revert SenderIncorrect();\n }\n\n if (_timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003c= DISPUTE_PERIOD) {\n revert DisputePeriodNotPassed();\n }\n\n bridgeTxDetails[transactionId].status = BridgeStatus.RELAYER_CLAIMED;\n\n // update protocol fees if origin fee amount exists\n if (transaction.originFeeAmount \u003e 0) protocolFees[transaction.originToken] += transaction.originFeeAmount;\n\n // transfer origin collateral less fee to specified address\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositClaimed(transactionId, bridgeTxDetails[transactionId].proofRelayer, to, token, amount);\n }\n\n function bridgeStatuses(bytes32 transactionId) public view returns (BridgeStatus status) {\n return bridgeTxDetails[transactionId].status;\n }\n\n function bridgeProofs(bytes32 transactionId) public view returns (uint96 timestamp, address relayer) {\n timestamp = bridgeTxDetails[transactionId].proofBlockTimestamp;\n relayer = bridgeTxDetails[transactionId].proofRelayer;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeRelays(bytes32 transactionId) public view returns (bool) {\n // has this transactionId been relayed?\n return bridgeRelayDetails[transactionId].relayer != address(0);\n }\n\n /// @inheritdoc IFastBridgeV2\n function getBridgeTransactionV2(bytes memory request) public pure returns (BridgeTransactionV2 memory) {\n return abi.decode(request, (BridgeTransactionV2));\n }\n\n /// @notice Pulls a requested token from the user to this contract.\n function _pullToken(address token, uint256 amount) internal returns (uint256 amountPulled) {\n if (token == UniversalTokenLib.ETH_ADDRESS) {\n // For ETH we just need to check that the supplied msg.value is correct\n if (amount != msg.value) revert MsgValueIncorrect();\n amountPulled = msg.value;\n } else {\n token.assertIsContract();\n // Record token balance before transfer\n amountPulled = IERC20(token).balanceOf(address(this));\n // Token needs to be pulled only if msg.value is zero\n // This way user can specify WETH as the origin asset\n IERC20(token).safeTransferFrom(msg.sender, address(this), amount);\n // Use the difference between the recorded balance and the current balance as the amountPulled\n amountPulled = IERC20(token).balanceOf(address(this)) - amountPulled;\n }\n }\n\n /// @notice Calls the Recipient's hook function with the specified callParams and performs\n /// all the necessary checks for the returned value.\n function _checkedCallRecipient(\n address recipient,\n address token,\n uint256 amount,\n bytes memory callParams\n )\n internal\n {\n bytes memory hookData =\n abi.encodeCall(IFastBridgeRecipient.fastBridgeTransferReceived, (token, amount, callParams));\n // This will bubble any revert messages from the hook function\n bytes memory returnData = Address.functionCallWithValue({target: recipient, data: hookData, value: msg.value});\n // Explicit revert if no return data at all\n if (returnData.length == 0) revert RecipientNoReturnValue();\n // Check that exactly a single return value was returned\n if (returnData.length != 32) revert RecipientIncorrectReturnValue();\n // Return value should be abi-encoded hook function selector\n if (bytes32(returnData) != bytes32(IFastBridgeRecipient.fastBridgeTransferReceived.selector)) {\n revert RecipientIncorrectReturnValue();\n }\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint40(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint40).max but\n /// proof.timestamp \u003c type(uint40).max via unchecked statement\n /// @param proofBlockTimestamp The bridge proof block timestamp\n /// @return delta Time delta since proof submitted\n function _timeSince(uint40 proofBlockTimestamp) internal view returns (uint256 delta) {\n unchecked {\n delta = uint40(block.timestamp) - proofBlockTimestamp;\n }\n }\n\n /// @notice Performs all the necessary checks for a bridge to happen.\n /// @dev There's no good way to refactor this function to reduce cyclomatic complexity due to\n /// the number of checks that need to be performed, so we skip the code-complexity rule here.\n // solhint-disable-next-line code-complexity\n function _validateBridgeParams(\n BridgeParams memory params,\n BridgeParamsV2 memory paramsV2,\n int256 exclusivityEndTime\n )\n internal\n view\n {\n // Check V1 (legacy) params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.sender == address(0) || params.to == address(0)) revert ZeroAddress();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n // Check V2 params\n if (paramsV2.callParams.length \u003e MAX_CALL_PARAMS_LENGTH) revert CallParamsLengthAboveMax();\n if (paramsV2.callValue != 0 \u0026\u0026 params.destToken == UniversalTokenLib.ETH_ADDRESS) {\n revert NativeTokenCallValueNotSupported();\n }\n // exclusivityEndTime must be in range (0 .. params.deadline]\n if (exclusivityEndTime \u003c= 0 || exclusivityEndTime \u003e int256(params.deadline)) {\n revert ExclusivityParamsIncorrect();\n }\n }\n\n /// @notice Performs all the necessary checks for a relay to happen.\n function _validateRelayParams(\n BridgeTransactionV2 memory transaction,\n bytes32 transactionId,\n address relayer\n )\n internal\n view\n {\n if (relayer == address(0)) revert ZeroAddress();\n // Check if the transaction has already been relayed\n if (bridgeRelays(transactionId)) revert TransactionRelayed();\n if (transaction.destChainId != uint32(block.chainid)) revert ChainIncorrect();\n // Check the deadline for relay to happen\n if (block.timestamp \u003e transaction.deadline) revert DeadlineExceeded();\n // Check the exclusivity period, if it is still ongoing\n // forgefmt: disable-next-item\n if (\n transaction.exclusivityRelayer != address(0) \u0026\u0026\n transaction.exclusivityRelayer != relayer \u0026\u0026\n block.timestamp \u003c= transaction.exclusivityEndTime\n ) {\n revert ExclusivityPeriodNotPassed();\n }\n }\n}\n","language":"Solidity","languageVersion":"0.8.24","compilerVersion":"0.8.24","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../","srcMap":"","srcMapRuntime":"","abiDefinition":[{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldChainGasAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newChainGasAmount","type":"uint256"}],"name":"ChainGasAmountUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldFeeRate","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newFeeRate","type":"uint256"}],"name":"FeeRateUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"address","name":"recipient","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"FeesSwept","type":"event"},{"inputs":[{"internalType":"uint256","name":"newChainGasAmount","type":"uint256"}],"name":"setChainGasAmount","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"newFeeRate","type":"uint256"}],"name":"setProtocolFeeRate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"address","name":"recipient","type":"address"}],"name":"sweepProtocolFees","outputs":[],"stateMutability":"nonpayable","type":"function"}],"userDoc":{"kind":"user","methods":{},"version":1},"developerDoc":{"kind":"dev","methods":{},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"oldChainGasAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newChainGasAmount\",\"type\":\"uint256\"}],\"name\":\"ChainGasAmountUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"oldFeeRate\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newFeeRate\",\"type\":\"uint256\"}],\"name\":\"FeeRateUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"FeesSwept\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"newChainGasAmount\",\"type\":\"uint256\"}],\"name\":\"setChainGasAmount\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"newFeeRate\",\"type\":\"uint256\"}],\"name\":\"setProtocolFeeRate\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"}],\"name\":\"sweepProtocolFees\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeV2.sol\":\"IAdmin\"},\"evmVersion\":\"shanghai\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeV2.sol\":{\"keccak256\":\"0x7cd0f885e80e2bdaa638bc32ae7af7d2e248f99ce4b354c217d0f0f7d7302e0a\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://7ccf28df0bd7b4606986585acd8622ed9b4e81379690061bb66088f0a2270af1\",\"dweb:/ipfs/QmTf7HNdHZkK6vmx8ZgewycQEb72oLD9nPwBpsM5reMstQ\"]}},\"version\":1}"},"hashes":{"setChainGasAmount(uint256)":"b250fe6b","setProtocolFeeRate(uint256)":"b13aa2d6","sweepProtocolFees(address,address)":"06f333f2"}},"solidity/FastBridgeV2.sol:IERC165":{"code":"0x","runtime-code":"0x","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.24 ^0.8.0 ^0.8.20;\n\n// contracts/interfaces/IAdmin.sol\n\ninterface IAdmin {\n // ============ Events ============\n\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n event ChainGasAmountUpdated(uint256 oldChainGasAmount, uint256 newChainGasAmount);\n\n // ============ Methods ============\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n\n function setChainGasAmount(uint256 newChainGasAmount) external;\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IFastBridgeRecipient.sol\n\ninterface IFastBridgeRecipient {\n function fastBridgeTransferReceived(\n address token,\n uint256 amount,\n bytes memory callParams\n )\n external\n payable\n returns (bytes4);\n}\n\n// contracts/interfaces/IFastBridgeV2Errors.sol\n\ninterface IFastBridgeV2Errors {\n error AmountIncorrect();\n error CallParamsLengthAboveMax();\n error ChainIncorrect();\n error ExclusivityParamsIncorrect();\n error MsgValueIncorrect();\n error NativeTokenCallValueNotSupported();\n error SenderIncorrect();\n error StatusIncorrect();\n error ZeroAddress();\n\n error RecipientIncorrectReturnValue();\n error RecipientNoReturnValue();\n\n error DeadlineExceeded();\n error DeadlineNotExceeded();\n error DeadlineTooShort();\n error DisputePeriodNotPassed();\n error DisputePeriodPassed();\n error ExclusivityPeriodNotPassed();\n\n error TransactionRelayed();\n}\n\n// contracts/libs/Errors.sol\n\nerror DeadlineExceeded();\nerror DeadlineNotExceeded();\nerror DeadlineTooShort();\nerror InsufficientOutputAmount();\n\nerror MsgValueIncorrect();\nerror PoolNotFound();\nerror TokenAddressMismatch();\nerror TokenNotContract();\nerror TokenNotETH();\nerror TokensIdentical();\n\nerror ChainIncorrect();\nerror AmountIncorrect();\nerror ZeroAddress();\n\nerror DisputePeriodNotPassed();\nerror DisputePeriodPassed();\nerror SenderIncorrect();\nerror StatusIncorrect();\nerror TransactionIdIncorrect();\nerror TransactionRelayed();\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// contracts/interfaces/IFastBridgeV2.sol\n\ninterface IFastBridgeV2 is IFastBridge {\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n struct BridgeTxDetails {\n BridgeStatus status;\n uint40 proofBlockTimestamp;\n uint48 proofBlockNumber;\n address proofRelayer;\n }\n\n struct BridgeRelay {\n uint48 blockNumber;\n uint48 blockTimestamp;\n address relayer;\n }\n\n /// @notice New params introduced in the FastBridgeV2.\n /// We are passing fields from the older BridgeParams struct outside of this struct\n /// for backwards compatibility.\n /// Note: quoteRelayer and quoteExclusivitySeconds are either both zero (indicating no exclusivity)\n /// or both non-zero (indicating exclusivity for the given period).\n /// Note: callValue \u003e 0 can NOT be used with destToken = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE (ETH_ADDRESS)\n /// @param quoteRelayer Relayer that provided the quote for the transaction\n /// @param quoteExclusivitySeconds Period of time the quote relayer is guaranteed exclusivity after user's deposit\n /// @param quoteId Unique quote identifier used for tracking the quote\n /// @param callValue ETH value to send to the recipient (if any)\n /// @param callParams Parameters for the arbitrary call to the destination recipient (if any)\n struct BridgeParamsV2 {\n address quoteRelayer;\n int256 quoteExclusivitySeconds;\n bytes quoteId;\n uint256 callValue;\n bytes callParams;\n }\n\n /// @notice Updated bridge transaction struct to include parameters introduced in FastBridgeV2.\n /// Note: only `exclusivityRelayer` can fill such a transaction until `exclusivityEndTime`.\n /// TODO: consider changing the encoding scheme to prevent spending extra gas on decoding.\n struct BridgeTransactionV2 {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n uint256 callValue; // ETH value to send to the recipient (if any) - replaces V1's sendChainGas flag\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n address exclusivityRelayer;\n uint256 exclusivityEndTime;\n bytes callParams;\n }\n\n event BridgeQuoteDetails(bytes32 indexed transactionId, bytes quoteId);\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability\n /// to provide temporary exclusivity fill rights for the quote relayer.\n /// @param params The parameters required to bridge\n /// @param paramsV2 The parameters for exclusivity fill rights (optional, can be left empty)\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function relay(bytes memory request, address relayer) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param transactionId The transaction id associated with the encoded bridge transaction to prove\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital.\n /// @notice Can only send funds to the relayer address on the proof.\n /// @param request The encoded bridge transaction to claim on origin chain\n function claim(bytes memory request) external;\n /// @notice Checks if a transaction has been relayed\n /// @param transactionId The ID of the transaction to check\n /// @return True if the transaction has been relayed, false otherwise\n function bridgeRelays(bytes32 transactionId) external view returns (bool);\n\n /// @notice Returns the status of a bridge transaction\n /// @param transactionId The ID of the bridge transaction\n /// @return BridgeStatus Status of the bridge transaction\n function bridgeStatuses(bytes32 transactionId) external view returns (BridgeStatus);\n\n /// @notice Returns the timestamp and relayer of a bridge proof\n /// @param transactionId The ID of the bridge transaction\n /// @return timestamp The timestamp of the bridge proof\n /// @return relayer The relayer address of the bridge proof\n function bridgeProofs(bytes32 transactionId) external view returns (uint96 timestamp, address relayer);\n\n /// @notice Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\n /// @param request The bridge request to decode\n function getBridgeTransactionV2(bytes memory request) external view returns (BridgeTransactionV2 memory);\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// contracts/libs/UniversalToken.sol\n\nlibrary UniversalTokenLib {\n using SafeERC20 for IERC20;\n\n address internal constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Transfers tokens to the given account. Reverts if transfer is not successful.\n /// @dev This might trigger fallback, if ETH is transferred to the contract.\n /// Make sure this can not lead to reentrancy attacks.\n function universalTransfer(address token, address to, uint256 value) internal {\n // Don't do anything, if need to send tokens to this address\n if (to == address(this)) return;\n // Don't do anything, if trying to send zero value\n if (value == 0) return;\n if (token == ETH_ADDRESS) {\n /// @dev Note: this can potentially lead to executing code in `to`.\n // solhint-disable-next-line avoid-low-level-calls\n (bool success,) = to.call{value: value}(\"\");\n require(success, \"ETH transfer failed\");\n } else {\n IERC20(token).safeTransfer(to, value);\n }\n }\n\n /// @notice Issues an infinite allowance to the spender, if the current allowance is insufficient\n /// to spend the given amount.\n function universalApproveInfinity(address token, address spender, uint256 amountToSpend) internal {\n // ETH Chad doesn't require your approval\n if (token == ETH_ADDRESS) return;\n // No-op if allowance is already sufficient\n uint256 allowance = IERC20(token).allowance(address(this), spender);\n if (allowance \u003e= amountToSpend) return;\n // Otherwise, reset approval to 0 and set to max allowance\n if (allowance \u003e 0) IERC20(token).safeDecreaseAllowance(spender, allowance);\n IERC20(token).safeIncreaseAllowance(spender, type(uint256).max);\n }\n\n /// @notice Returns the balance of the given token (or native ETH) for the given account.\n function universalBalanceOf(address token, address account) internal view returns (uint256) {\n if (token == ETH_ADDRESS) {\n return account.balance;\n } else {\n return IERC20(token).balanceOf(account);\n }\n }\n\n /// @dev Checks that token is a contract and not ETH_ADDRESS.\n function assertIsContract(address token) internal view {\n // Check that ETH_ADDRESS was not used (in case this is a predeploy on any of the chains)\n if (token == UniversalTokenLib.ETH_ADDRESS) revert TokenNotContract();\n // Check that token is not an EOA\n if (token.code.length == 0) revert TokenNotContract();\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/Admin.sol\n\ncontract Admin is IAdmin, AccessControlEnumerable {\n using UniversalTokenLib for address;\n\n bytes32 public constant RELAYER_ROLE = keccak256(\"RELAYER_ROLE\");\n bytes32 public constant REFUNDER_ROLE = keccak256(\"REFUNDER_ROLE\");\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n uint256 public constant FEE_BPS = 1e6;\n uint256 public constant FEE_RATE_MAX = 0.01e6; // max 1% on origin amount\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Chain gas amount to forward as rebate if requested\n uint256 public chainGasAmount;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n }\n\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n require(newFeeRate \u003c= FEE_RATE_MAX, \"newFeeRate \u003e max\");\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n token.universalTransfer(recipient, feeAmount);\n emit FeesSwept(token, recipient, feeAmount);\n }\n\n function setChainGasAmount(uint256 newChainGasAmount) external onlyRole(GOVERNOR_ROLE) {\n uint256 oldChainGasAmount = chainGasAmount;\n chainGasAmount = newChainGasAmount;\n emit ChainGasAmountUpdated(oldChainGasAmount, newChainGasAmount);\n }\n}\n\n// contracts/FastBridgeV2.sol\n\n/// @notice FastBridgeV2 is a contract for bridging tokens across chains.\ncontract FastBridgeV2 is Admin, IFastBridgeV2, IFastBridgeV2Errors {\n using SafeERC20 for IERC20;\n using UniversalTokenLib for address;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Delay for a transaction after which it could be permisionlessly refunded\n uint256 public constant REFUND_DELAY = 7 days;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n /// @notice Maximum length of accepted callParams\n uint256 public constant MAX_CALL_PARAMS_LENGTH = 2 ** 16 - 1;\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeTxDetails) public bridgeTxDetails;\n /// @notice Relay details on destination chain\n mapping(bytes32 =\u003e BridgeRelay) public bridgeRelayDetails;\n /// @notice Unique bridge nonces tracked per originSender\n mapping(address =\u003e uint256) public senderNonces;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Replaced by senderNonces\n uint256 public immutable nonce = 0;\n /// @notice the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n bridge({\n params: params,\n paramsV2: BridgeParamsV2({\n quoteRelayer: address(0),\n quoteExclusivitySeconds: 0,\n quoteId: bytes(\"\"),\n callValue: 0,\n callParams: bytes(\"\")\n })\n });\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes memory request) external payable {\n relay({request: request, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes memory request, bytes32 destTxHash) external {\n prove({transactionId: keccak256(request), destTxHash: destTxHash, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridgeV2\n function claim(bytes memory request) external {\n claim({request: request, to: address(0)});\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003e DISPUTE_PERIOD) {\n revert DisputePeriodPassed();\n }\n\n // @dev relayer gets slashed effectively if dest relay has gone thru\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n bridgeTxDetails[transactionId].proofRelayer = address(0);\n bridgeTxDetails[transactionId].proofBlockTimestamp = 0;\n bridgeTxDetails[transactionId].proofBlockNumber = 0;\n\n emit BridgeProofDisputed(transactionId, msg.sender);\n }\n\n /// @inheritdoc IFastBridge\n function refund(bytes memory request) external {\n bytes32 transactionId = keccak256(request);\n\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n\n if (bridgeTxDetails[transactionId].status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n\n if (hasRole(REFUNDER_ROLE, msg.sender)) {\n // Refunder can refund if deadline has passed\n if (block.timestamp \u003c= transaction.deadline) revert DeadlineNotExceeded();\n } else {\n // Permissionless refund is allowed after REFUND_DELAY\n if (block.timestamp \u003c= transaction.deadline + REFUND_DELAY) revert DeadlineNotExceeded();\n }\n\n // if all checks passed, set to REFUNDED status\n bridgeTxDetails[transactionId].status = BridgeStatus.REFUNDED;\n\n // transfer origin collateral back to original sender\n address to = transaction.originSender;\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount + transaction.originFeeAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (bridgeTxDetails[transactionId].proofRelayer != relayer) revert SenderIncorrect();\n return _timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n /// @dev This method is added to achieve backwards compatibility with decoding requests into V1 structs:\n /// - `callValue` is partially reported as a zero/non-zero flag\n /// - `callParams` is ignored\n /// In order to process all kinds of requests use getBridgeTransactionV2 instead.\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory) {\n // Try decoding into V2 struct first. This will revert if V1 struct is passed\n try this.getBridgeTransactionV2(request) returns (BridgeTransactionV2 memory txV2) {\n // Note: we entirely ignore the callParams field, as it was not present in V1\n return BridgeTransaction({\n originChainId: txV2.originChainId,\n destChainId: txV2.destChainId,\n originSender: txV2.originSender,\n destRecipient: txV2.destRecipient,\n originToken: txV2.originToken,\n destToken: txV2.destToken,\n originAmount: txV2.originAmount,\n destAmount: txV2.destAmount,\n originFeeAmount: txV2.originFeeAmount,\n sendChainGas: txV2.callValue != 0,\n deadline: txV2.deadline,\n nonce: txV2.nonce\n });\n } catch {\n // Fallback to V1 struct\n return abi.decode(request, (BridgeTransaction));\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) public payable {\n int256 exclusivityEndTime = int256(block.timestamp) + paramsV2.quoteExclusivitySeconds;\n _validateBridgeParams(params, paramsV2, exclusivityEndTime);\n\n // transfer tokens to bridge contract\n /// @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _pullToken(params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n\n // set status to requested\n bytes memory request = abi.encode(\n BridgeTransactionV2({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n callValue: paramsV2.callValue,\n deadline: params.deadline,\n nonce: senderNonces[params.sender]++, // increment nonce on every bridge\n exclusivityRelayer: paramsV2.quoteRelayer,\n // We checked exclusivityEndTime to be in range (0 .. params.deadline] above, so can safely cast\n exclusivityEndTime: uint256(exclusivityEndTime),\n callParams: paramsV2.callParams\n })\n );\n bytes32 transactionId = keccak256(request);\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n\n emit BridgeRequested({\n transactionId: transactionId,\n sender: params.sender,\n request: request,\n destChainId: params.dstChainId,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n sendChainGas: paramsV2.callValue != 0\n });\n emit BridgeQuoteDetails(transactionId, paramsV2.quoteId);\n }\n\n /// @inheritdoc IFastBridgeV2\n function relay(bytes memory request, address relayer) public payable {\n bytes32 transactionId = keccak256(request);\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n _validateRelayParams(transaction, transactionId, relayer);\n // mark bridge transaction as relayed\n bridgeRelayDetails[transactionId] =\n BridgeRelay({blockNumber: uint48(block.number), blockTimestamp: uint48(block.timestamp), relayer: relayer});\n\n // transfer tokens to recipient on destination chain and do an arbitrary call if requested\n address to = transaction.destRecipient;\n address token = transaction.destToken;\n uint256 amount = transaction.destAmount;\n\n // All state changes have been done at this point, can proceed to the external calls.\n // This follows the checks-effects-interactions pattern to mitigate potential reentrancy attacks.\n if (token == UniversalTokenLib.ETH_ADDRESS) {\n // For ETH non-zero callValue is not allowed\n if (transaction.callValue != 0) revert NativeTokenCallValueNotSupported();\n // Check that the correct msg.value was sent\n if (msg.value != amount) revert MsgValueIncorrect();\n } else {\n // For ERC20s, we check that the correct msg.value was sent\n if (msg.value != transaction.callValue) revert MsgValueIncorrect();\n // We need to transfer the tokens from the Relayer to the recipient first before performing an\n // optional post-transfer arbitrary call.\n IERC20(token).safeTransferFrom(msg.sender, to, amount);\n }\n\n if (transaction.callParams.length != 0) {\n // Arbitrary call requested, perform it while supplying full msg.value to the recipient\n // Note: if token has a fee on transfers, the recipient will have received less than `amount`.\n // This is a very niche edge case and should be handled by the recipient contract.\n _checkedCallRecipient({recipient: to, token: token, amount: amount, callParams: transaction.callParams});\n } else if (msg.value != 0) {\n // No arbitrary call requested, but msg.value was sent. This is either a relay with ETH,\n // or a non-zero callValue request with an ERC20. In both cases, transfer the ETH to the recipient.\n Address.sendValue(payable(to), msg.value);\n }\n\n emit BridgeRelayed({\n transactionId: transactionId,\n relayer: relayer,\n to: to,\n originChainId: transaction.originChainId,\n originToken: transaction.originToken,\n destToken: transaction.destToken,\n originAmount: transaction.originAmount,\n destAmount: transaction.destAmount,\n chainGasAmount: transaction.callValue\n });\n }\n\n /// @inheritdoc IFastBridgeV2\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) public onlyRole(RELAYER_ROLE) {\n // update bridge tx status given proof provided\n if (bridgeTxDetails[transactionId].status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n bridgeTxDetails[transactionId].status = BridgeStatus.RELAYER_PROVED;\n bridgeTxDetails[transactionId].proofBlockTimestamp = uint40(block.timestamp);\n bridgeTxDetails[transactionId].proofBlockNumber = uint48(block.number);\n bridgeTxDetails[transactionId].proofRelayer = relayer;\n\n emit BridgeProofProvided(transactionId, relayer, destTxHash);\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes memory request, address to) public {\n bytes32 transactionId = keccak256(request);\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n\n // update bridge tx status if able to claim origin collateral\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n\n // if \"to\" is zero addr, permissionlessly send funds to proven relayer\n if (to == address(0)) {\n to = bridgeTxDetails[transactionId].proofRelayer;\n } else if (bridgeTxDetails[transactionId].proofRelayer != msg.sender) {\n revert SenderIncorrect();\n }\n\n if (_timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003c= DISPUTE_PERIOD) {\n revert DisputePeriodNotPassed();\n }\n\n bridgeTxDetails[transactionId].status = BridgeStatus.RELAYER_CLAIMED;\n\n // update protocol fees if origin fee amount exists\n if (transaction.originFeeAmount \u003e 0) protocolFees[transaction.originToken] += transaction.originFeeAmount;\n\n // transfer origin collateral less fee to specified address\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositClaimed(transactionId, bridgeTxDetails[transactionId].proofRelayer, to, token, amount);\n }\n\n function bridgeStatuses(bytes32 transactionId) public view returns (BridgeStatus status) {\n return bridgeTxDetails[transactionId].status;\n }\n\n function bridgeProofs(bytes32 transactionId) public view returns (uint96 timestamp, address relayer) {\n timestamp = bridgeTxDetails[transactionId].proofBlockTimestamp;\n relayer = bridgeTxDetails[transactionId].proofRelayer;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeRelays(bytes32 transactionId) public view returns (bool) {\n // has this transactionId been relayed?\n return bridgeRelayDetails[transactionId].relayer != address(0);\n }\n\n /// @inheritdoc IFastBridgeV2\n function getBridgeTransactionV2(bytes memory request) public pure returns (BridgeTransactionV2 memory) {\n return abi.decode(request, (BridgeTransactionV2));\n }\n\n /// @notice Pulls a requested token from the user to this contract.\n function _pullToken(address token, uint256 amount) internal returns (uint256 amountPulled) {\n if (token == UniversalTokenLib.ETH_ADDRESS) {\n // For ETH we just need to check that the supplied msg.value is correct\n if (amount != msg.value) revert MsgValueIncorrect();\n amountPulled = msg.value;\n } else {\n token.assertIsContract();\n // Record token balance before transfer\n amountPulled = IERC20(token).balanceOf(address(this));\n // Token needs to be pulled only if msg.value is zero\n // This way user can specify WETH as the origin asset\n IERC20(token).safeTransferFrom(msg.sender, address(this), amount);\n // Use the difference between the recorded balance and the current balance as the amountPulled\n amountPulled = IERC20(token).balanceOf(address(this)) - amountPulled;\n }\n }\n\n /// @notice Calls the Recipient's hook function with the specified callParams and performs\n /// all the necessary checks for the returned value.\n function _checkedCallRecipient(\n address recipient,\n address token,\n uint256 amount,\n bytes memory callParams\n )\n internal\n {\n bytes memory hookData =\n abi.encodeCall(IFastBridgeRecipient.fastBridgeTransferReceived, (token, amount, callParams));\n // This will bubble any revert messages from the hook function\n bytes memory returnData = Address.functionCallWithValue({target: recipient, data: hookData, value: msg.value});\n // Explicit revert if no return data at all\n if (returnData.length == 0) revert RecipientNoReturnValue();\n // Check that exactly a single return value was returned\n if (returnData.length != 32) revert RecipientIncorrectReturnValue();\n // Return value should be abi-encoded hook function selector\n if (bytes32(returnData) != bytes32(IFastBridgeRecipient.fastBridgeTransferReceived.selector)) {\n revert RecipientIncorrectReturnValue();\n }\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint40(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint40).max but\n /// proof.timestamp \u003c type(uint40).max via unchecked statement\n /// @param proofBlockTimestamp The bridge proof block timestamp\n /// @return delta Time delta since proof submitted\n function _timeSince(uint40 proofBlockTimestamp) internal view returns (uint256 delta) {\n unchecked {\n delta = uint40(block.timestamp) - proofBlockTimestamp;\n }\n }\n\n /// @notice Performs all the necessary checks for a bridge to happen.\n /// @dev There's no good way to refactor this function to reduce cyclomatic complexity due to\n /// the number of checks that need to be performed, so we skip the code-complexity rule here.\n // solhint-disable-next-line code-complexity\n function _validateBridgeParams(\n BridgeParams memory params,\n BridgeParamsV2 memory paramsV2,\n int256 exclusivityEndTime\n )\n internal\n view\n {\n // Check V1 (legacy) params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.sender == address(0) || params.to == address(0)) revert ZeroAddress();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n // Check V2 params\n if (paramsV2.callParams.length \u003e MAX_CALL_PARAMS_LENGTH) revert CallParamsLengthAboveMax();\n if (paramsV2.callValue != 0 \u0026\u0026 params.destToken == UniversalTokenLib.ETH_ADDRESS) {\n revert NativeTokenCallValueNotSupported();\n }\n // exclusivityEndTime must be in range (0 .. params.deadline]\n if (exclusivityEndTime \u003c= 0 || exclusivityEndTime \u003e int256(params.deadline)) {\n revert ExclusivityParamsIncorrect();\n }\n }\n\n /// @notice Performs all the necessary checks for a relay to happen.\n function _validateRelayParams(\n BridgeTransactionV2 memory transaction,\n bytes32 transactionId,\n address relayer\n )\n internal\n view\n {\n if (relayer == address(0)) revert ZeroAddress();\n // Check if the transaction has already been relayed\n if (bridgeRelays(transactionId)) revert TransactionRelayed();\n if (transaction.destChainId != uint32(block.chainid)) revert ChainIncorrect();\n // Check the deadline for relay to happen\n if (block.timestamp \u003e transaction.deadline) revert DeadlineExceeded();\n // Check the exclusivity period, if it is still ongoing\n // forgefmt: disable-next-item\n if (\n transaction.exclusivityRelayer != address(0) \u0026\u0026\n transaction.exclusivityRelayer != relayer \u0026\u0026\n block.timestamp \u003c= transaction.exclusivityEndTime\n ) {\n revert ExclusivityPeriodNotPassed();\n }\n }\n}\n","language":"Solidity","languageVersion":"0.8.24","compilerVersion":"0.8.24","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../","srcMap":"","srcMapRuntime":"","abiDefinition":[{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"}],"userDoc":{"kind":"user","methods":{},"version":1},"developerDoc":{"details":"Interface of the ERC165 standard, as defined in the https://eips.ethereum.org/EIPS/eip-165[EIP]. Implementers can declare support of contract interfaces, which can then be queried by others ({ERC165Checker}). For an implementation, see {ERC165}.","kind":"dev","methods":{"supportsInterface(bytes4)":{"details":"Returns true if this contract implements the interface defined by `interfaceId`. See the corresponding https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section] to learn more about how these ids are created. This function call must use less than 30 000 gas."}},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"bytes4\",\"name\":\"interfaceId\",\"type\":\"bytes4\"}],\"name\":\"supportsInterface\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"}],\"devdoc\":{\"details\":\"Interface of the ERC165 standard, as defined in the https://eips.ethereum.org/EIPS/eip-165[EIP]. Implementers can declare support of contract interfaces, which can then be queried by others ({ERC165Checker}). For an implementation, see {ERC165}.\",\"kind\":\"dev\",\"methods\":{\"supportsInterface(bytes4)\":{\"details\":\"Returns true if this contract implements the interface defined by `interfaceId`. See the corresponding https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section] to learn more about how these ids are created. This function call must use less than 30 000 gas.\"}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeV2.sol\":\"IERC165\"},\"evmVersion\":\"shanghai\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeV2.sol\":{\"keccak256\":\"0x7cd0f885e80e2bdaa638bc32ae7af7d2e248f99ce4b354c217d0f0f7d7302e0a\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://7ccf28df0bd7b4606986585acd8622ed9b4e81379690061bb66088f0a2270af1\",\"dweb:/ipfs/QmTf7HNdHZkK6vmx8ZgewycQEb72oLD9nPwBpsM5reMstQ\"]}},\"version\":1}"},"hashes":{"supportsInterface(bytes4)":"01ffc9a7"}},"solidity/FastBridgeV2.sol:IERC20":{"code":"0x","runtime-code":"0x","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.24 ^0.8.0 ^0.8.20;\n\n// contracts/interfaces/IAdmin.sol\n\ninterface IAdmin {\n // ============ Events ============\n\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n event ChainGasAmountUpdated(uint256 oldChainGasAmount, uint256 newChainGasAmount);\n\n // ============ Methods ============\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n\n function setChainGasAmount(uint256 newChainGasAmount) external;\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IFastBridgeRecipient.sol\n\ninterface IFastBridgeRecipient {\n function fastBridgeTransferReceived(\n address token,\n uint256 amount,\n bytes memory callParams\n )\n external\n payable\n returns (bytes4);\n}\n\n// contracts/interfaces/IFastBridgeV2Errors.sol\n\ninterface IFastBridgeV2Errors {\n error AmountIncorrect();\n error CallParamsLengthAboveMax();\n error ChainIncorrect();\n error ExclusivityParamsIncorrect();\n error MsgValueIncorrect();\n error NativeTokenCallValueNotSupported();\n error SenderIncorrect();\n error StatusIncorrect();\n error ZeroAddress();\n\n error RecipientIncorrectReturnValue();\n error RecipientNoReturnValue();\n\n error DeadlineExceeded();\n error DeadlineNotExceeded();\n error DeadlineTooShort();\n error DisputePeriodNotPassed();\n error DisputePeriodPassed();\n error ExclusivityPeriodNotPassed();\n\n error TransactionRelayed();\n}\n\n// contracts/libs/Errors.sol\n\nerror DeadlineExceeded();\nerror DeadlineNotExceeded();\nerror DeadlineTooShort();\nerror InsufficientOutputAmount();\n\nerror MsgValueIncorrect();\nerror PoolNotFound();\nerror TokenAddressMismatch();\nerror TokenNotContract();\nerror TokenNotETH();\nerror TokensIdentical();\n\nerror ChainIncorrect();\nerror AmountIncorrect();\nerror ZeroAddress();\n\nerror DisputePeriodNotPassed();\nerror DisputePeriodPassed();\nerror SenderIncorrect();\nerror StatusIncorrect();\nerror TransactionIdIncorrect();\nerror TransactionRelayed();\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// contracts/interfaces/IFastBridgeV2.sol\n\ninterface IFastBridgeV2 is IFastBridge {\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n struct BridgeTxDetails {\n BridgeStatus status;\n uint40 proofBlockTimestamp;\n uint48 proofBlockNumber;\n address proofRelayer;\n }\n\n struct BridgeRelay {\n uint48 blockNumber;\n uint48 blockTimestamp;\n address relayer;\n }\n\n /// @notice New params introduced in the FastBridgeV2.\n /// We are passing fields from the older BridgeParams struct outside of this struct\n /// for backwards compatibility.\n /// Note: quoteRelayer and quoteExclusivitySeconds are either both zero (indicating no exclusivity)\n /// or both non-zero (indicating exclusivity for the given period).\n /// Note: callValue \u003e 0 can NOT be used with destToken = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE (ETH_ADDRESS)\n /// @param quoteRelayer Relayer that provided the quote for the transaction\n /// @param quoteExclusivitySeconds Period of time the quote relayer is guaranteed exclusivity after user's deposit\n /// @param quoteId Unique quote identifier used for tracking the quote\n /// @param callValue ETH value to send to the recipient (if any)\n /// @param callParams Parameters for the arbitrary call to the destination recipient (if any)\n struct BridgeParamsV2 {\n address quoteRelayer;\n int256 quoteExclusivitySeconds;\n bytes quoteId;\n uint256 callValue;\n bytes callParams;\n }\n\n /// @notice Updated bridge transaction struct to include parameters introduced in FastBridgeV2.\n /// Note: only `exclusivityRelayer` can fill such a transaction until `exclusivityEndTime`.\n /// TODO: consider changing the encoding scheme to prevent spending extra gas on decoding.\n struct BridgeTransactionV2 {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n uint256 callValue; // ETH value to send to the recipient (if any) - replaces V1's sendChainGas flag\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n address exclusivityRelayer;\n uint256 exclusivityEndTime;\n bytes callParams;\n }\n\n event BridgeQuoteDetails(bytes32 indexed transactionId, bytes quoteId);\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability\n /// to provide temporary exclusivity fill rights for the quote relayer.\n /// @param params The parameters required to bridge\n /// @param paramsV2 The parameters for exclusivity fill rights (optional, can be left empty)\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function relay(bytes memory request, address relayer) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param transactionId The transaction id associated with the encoded bridge transaction to prove\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital.\n /// @notice Can only send funds to the relayer address on the proof.\n /// @param request The encoded bridge transaction to claim on origin chain\n function claim(bytes memory request) external;\n /// @notice Checks if a transaction has been relayed\n /// @param transactionId The ID of the transaction to check\n /// @return True if the transaction has been relayed, false otherwise\n function bridgeRelays(bytes32 transactionId) external view returns (bool);\n\n /// @notice Returns the status of a bridge transaction\n /// @param transactionId The ID of the bridge transaction\n /// @return BridgeStatus Status of the bridge transaction\n function bridgeStatuses(bytes32 transactionId) external view returns (BridgeStatus);\n\n /// @notice Returns the timestamp and relayer of a bridge proof\n /// @param transactionId The ID of the bridge transaction\n /// @return timestamp The timestamp of the bridge proof\n /// @return relayer The relayer address of the bridge proof\n function bridgeProofs(bytes32 transactionId) external view returns (uint96 timestamp, address relayer);\n\n /// @notice Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\n /// @param request The bridge request to decode\n function getBridgeTransactionV2(bytes memory request) external view returns (BridgeTransactionV2 memory);\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// contracts/libs/UniversalToken.sol\n\nlibrary UniversalTokenLib {\n using SafeERC20 for IERC20;\n\n address internal constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Transfers tokens to the given account. Reverts if transfer is not successful.\n /// @dev This might trigger fallback, if ETH is transferred to the contract.\n /// Make sure this can not lead to reentrancy attacks.\n function universalTransfer(address token, address to, uint256 value) internal {\n // Don't do anything, if need to send tokens to this address\n if (to == address(this)) return;\n // Don't do anything, if trying to send zero value\n if (value == 0) return;\n if (token == ETH_ADDRESS) {\n /// @dev Note: this can potentially lead to executing code in `to`.\n // solhint-disable-next-line avoid-low-level-calls\n (bool success,) = to.call{value: value}(\"\");\n require(success, \"ETH transfer failed\");\n } else {\n IERC20(token).safeTransfer(to, value);\n }\n }\n\n /// @notice Issues an infinite allowance to the spender, if the current allowance is insufficient\n /// to spend the given amount.\n function universalApproveInfinity(address token, address spender, uint256 amountToSpend) internal {\n // ETH Chad doesn't require your approval\n if (token == ETH_ADDRESS) return;\n // No-op if allowance is already sufficient\n uint256 allowance = IERC20(token).allowance(address(this), spender);\n if (allowance \u003e= amountToSpend) return;\n // Otherwise, reset approval to 0 and set to max allowance\n if (allowance \u003e 0) IERC20(token).safeDecreaseAllowance(spender, allowance);\n IERC20(token).safeIncreaseAllowance(spender, type(uint256).max);\n }\n\n /// @notice Returns the balance of the given token (or native ETH) for the given account.\n function universalBalanceOf(address token, address account) internal view returns (uint256) {\n if (token == ETH_ADDRESS) {\n return account.balance;\n } else {\n return IERC20(token).balanceOf(account);\n }\n }\n\n /// @dev Checks that token is a contract and not ETH_ADDRESS.\n function assertIsContract(address token) internal view {\n // Check that ETH_ADDRESS was not used (in case this is a predeploy on any of the chains)\n if (token == UniversalTokenLib.ETH_ADDRESS) revert TokenNotContract();\n // Check that token is not an EOA\n if (token.code.length == 0) revert TokenNotContract();\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/Admin.sol\n\ncontract Admin is IAdmin, AccessControlEnumerable {\n using UniversalTokenLib for address;\n\n bytes32 public constant RELAYER_ROLE = keccak256(\"RELAYER_ROLE\");\n bytes32 public constant REFUNDER_ROLE = keccak256(\"REFUNDER_ROLE\");\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n uint256 public constant FEE_BPS = 1e6;\n uint256 public constant FEE_RATE_MAX = 0.01e6; // max 1% on origin amount\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Chain gas amount to forward as rebate if requested\n uint256 public chainGasAmount;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n }\n\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n require(newFeeRate \u003c= FEE_RATE_MAX, \"newFeeRate \u003e max\");\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n token.universalTransfer(recipient, feeAmount);\n emit FeesSwept(token, recipient, feeAmount);\n }\n\n function setChainGasAmount(uint256 newChainGasAmount) external onlyRole(GOVERNOR_ROLE) {\n uint256 oldChainGasAmount = chainGasAmount;\n chainGasAmount = newChainGasAmount;\n emit ChainGasAmountUpdated(oldChainGasAmount, newChainGasAmount);\n }\n}\n\n// contracts/FastBridgeV2.sol\n\n/// @notice FastBridgeV2 is a contract for bridging tokens across chains.\ncontract FastBridgeV2 is Admin, IFastBridgeV2, IFastBridgeV2Errors {\n using SafeERC20 for IERC20;\n using UniversalTokenLib for address;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Delay for a transaction after which it could be permisionlessly refunded\n uint256 public constant REFUND_DELAY = 7 days;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n /// @notice Maximum length of accepted callParams\n uint256 public constant MAX_CALL_PARAMS_LENGTH = 2 ** 16 - 1;\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeTxDetails) public bridgeTxDetails;\n /// @notice Relay details on destination chain\n mapping(bytes32 =\u003e BridgeRelay) public bridgeRelayDetails;\n /// @notice Unique bridge nonces tracked per originSender\n mapping(address =\u003e uint256) public senderNonces;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Replaced by senderNonces\n uint256 public immutable nonce = 0;\n /// @notice the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n bridge({\n params: params,\n paramsV2: BridgeParamsV2({\n quoteRelayer: address(0),\n quoteExclusivitySeconds: 0,\n quoteId: bytes(\"\"),\n callValue: 0,\n callParams: bytes(\"\")\n })\n });\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes memory request) external payable {\n relay({request: request, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes memory request, bytes32 destTxHash) external {\n prove({transactionId: keccak256(request), destTxHash: destTxHash, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridgeV2\n function claim(bytes memory request) external {\n claim({request: request, to: address(0)});\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003e DISPUTE_PERIOD) {\n revert DisputePeriodPassed();\n }\n\n // @dev relayer gets slashed effectively if dest relay has gone thru\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n bridgeTxDetails[transactionId].proofRelayer = address(0);\n bridgeTxDetails[transactionId].proofBlockTimestamp = 0;\n bridgeTxDetails[transactionId].proofBlockNumber = 0;\n\n emit BridgeProofDisputed(transactionId, msg.sender);\n }\n\n /// @inheritdoc IFastBridge\n function refund(bytes memory request) external {\n bytes32 transactionId = keccak256(request);\n\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n\n if (bridgeTxDetails[transactionId].status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n\n if (hasRole(REFUNDER_ROLE, msg.sender)) {\n // Refunder can refund if deadline has passed\n if (block.timestamp \u003c= transaction.deadline) revert DeadlineNotExceeded();\n } else {\n // Permissionless refund is allowed after REFUND_DELAY\n if (block.timestamp \u003c= transaction.deadline + REFUND_DELAY) revert DeadlineNotExceeded();\n }\n\n // if all checks passed, set to REFUNDED status\n bridgeTxDetails[transactionId].status = BridgeStatus.REFUNDED;\n\n // transfer origin collateral back to original sender\n address to = transaction.originSender;\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount + transaction.originFeeAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (bridgeTxDetails[transactionId].proofRelayer != relayer) revert SenderIncorrect();\n return _timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n /// @dev This method is added to achieve backwards compatibility with decoding requests into V1 structs:\n /// - `callValue` is partially reported as a zero/non-zero flag\n /// - `callParams` is ignored\n /// In order to process all kinds of requests use getBridgeTransactionV2 instead.\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory) {\n // Try decoding into V2 struct first. This will revert if V1 struct is passed\n try this.getBridgeTransactionV2(request) returns (BridgeTransactionV2 memory txV2) {\n // Note: we entirely ignore the callParams field, as it was not present in V1\n return BridgeTransaction({\n originChainId: txV2.originChainId,\n destChainId: txV2.destChainId,\n originSender: txV2.originSender,\n destRecipient: txV2.destRecipient,\n originToken: txV2.originToken,\n destToken: txV2.destToken,\n originAmount: txV2.originAmount,\n destAmount: txV2.destAmount,\n originFeeAmount: txV2.originFeeAmount,\n sendChainGas: txV2.callValue != 0,\n deadline: txV2.deadline,\n nonce: txV2.nonce\n });\n } catch {\n // Fallback to V1 struct\n return abi.decode(request, (BridgeTransaction));\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) public payable {\n int256 exclusivityEndTime = int256(block.timestamp) + paramsV2.quoteExclusivitySeconds;\n _validateBridgeParams(params, paramsV2, exclusivityEndTime);\n\n // transfer tokens to bridge contract\n /// @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _pullToken(params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n\n // set status to requested\n bytes memory request = abi.encode(\n BridgeTransactionV2({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n callValue: paramsV2.callValue,\n deadline: params.deadline,\n nonce: senderNonces[params.sender]++, // increment nonce on every bridge\n exclusivityRelayer: paramsV2.quoteRelayer,\n // We checked exclusivityEndTime to be in range (0 .. params.deadline] above, so can safely cast\n exclusivityEndTime: uint256(exclusivityEndTime),\n callParams: paramsV2.callParams\n })\n );\n bytes32 transactionId = keccak256(request);\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n\n emit BridgeRequested({\n transactionId: transactionId,\n sender: params.sender,\n request: request,\n destChainId: params.dstChainId,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n sendChainGas: paramsV2.callValue != 0\n });\n emit BridgeQuoteDetails(transactionId, paramsV2.quoteId);\n }\n\n /// @inheritdoc IFastBridgeV2\n function relay(bytes memory request, address relayer) public payable {\n bytes32 transactionId = keccak256(request);\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n _validateRelayParams(transaction, transactionId, relayer);\n // mark bridge transaction as relayed\n bridgeRelayDetails[transactionId] =\n BridgeRelay({blockNumber: uint48(block.number), blockTimestamp: uint48(block.timestamp), relayer: relayer});\n\n // transfer tokens to recipient on destination chain and do an arbitrary call if requested\n address to = transaction.destRecipient;\n address token = transaction.destToken;\n uint256 amount = transaction.destAmount;\n\n // All state changes have been done at this point, can proceed to the external calls.\n // This follows the checks-effects-interactions pattern to mitigate potential reentrancy attacks.\n if (token == UniversalTokenLib.ETH_ADDRESS) {\n // For ETH non-zero callValue is not allowed\n if (transaction.callValue != 0) revert NativeTokenCallValueNotSupported();\n // Check that the correct msg.value was sent\n if (msg.value != amount) revert MsgValueIncorrect();\n } else {\n // For ERC20s, we check that the correct msg.value was sent\n if (msg.value != transaction.callValue) revert MsgValueIncorrect();\n // We need to transfer the tokens from the Relayer to the recipient first before performing an\n // optional post-transfer arbitrary call.\n IERC20(token).safeTransferFrom(msg.sender, to, amount);\n }\n\n if (transaction.callParams.length != 0) {\n // Arbitrary call requested, perform it while supplying full msg.value to the recipient\n // Note: if token has a fee on transfers, the recipient will have received less than `amount`.\n // This is a very niche edge case and should be handled by the recipient contract.\n _checkedCallRecipient({recipient: to, token: token, amount: amount, callParams: transaction.callParams});\n } else if (msg.value != 0) {\n // No arbitrary call requested, but msg.value was sent. This is either a relay with ETH,\n // or a non-zero callValue request with an ERC20. In both cases, transfer the ETH to the recipient.\n Address.sendValue(payable(to), msg.value);\n }\n\n emit BridgeRelayed({\n transactionId: transactionId,\n relayer: relayer,\n to: to,\n originChainId: transaction.originChainId,\n originToken: transaction.originToken,\n destToken: transaction.destToken,\n originAmount: transaction.originAmount,\n destAmount: transaction.destAmount,\n chainGasAmount: transaction.callValue\n });\n }\n\n /// @inheritdoc IFastBridgeV2\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) public onlyRole(RELAYER_ROLE) {\n // update bridge tx status given proof provided\n if (bridgeTxDetails[transactionId].status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n bridgeTxDetails[transactionId].status = BridgeStatus.RELAYER_PROVED;\n bridgeTxDetails[transactionId].proofBlockTimestamp = uint40(block.timestamp);\n bridgeTxDetails[transactionId].proofBlockNumber = uint48(block.number);\n bridgeTxDetails[transactionId].proofRelayer = relayer;\n\n emit BridgeProofProvided(transactionId, relayer, destTxHash);\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes memory request, address to) public {\n bytes32 transactionId = keccak256(request);\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n\n // update bridge tx status if able to claim origin collateral\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n\n // if \"to\" is zero addr, permissionlessly send funds to proven relayer\n if (to == address(0)) {\n to = bridgeTxDetails[transactionId].proofRelayer;\n } else if (bridgeTxDetails[transactionId].proofRelayer != msg.sender) {\n revert SenderIncorrect();\n }\n\n if (_timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003c= DISPUTE_PERIOD) {\n revert DisputePeriodNotPassed();\n }\n\n bridgeTxDetails[transactionId].status = BridgeStatus.RELAYER_CLAIMED;\n\n // update protocol fees if origin fee amount exists\n if (transaction.originFeeAmount \u003e 0) protocolFees[transaction.originToken] += transaction.originFeeAmount;\n\n // transfer origin collateral less fee to specified address\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositClaimed(transactionId, bridgeTxDetails[transactionId].proofRelayer, to, token, amount);\n }\n\n function bridgeStatuses(bytes32 transactionId) public view returns (BridgeStatus status) {\n return bridgeTxDetails[transactionId].status;\n }\n\n function bridgeProofs(bytes32 transactionId) public view returns (uint96 timestamp, address relayer) {\n timestamp = bridgeTxDetails[transactionId].proofBlockTimestamp;\n relayer = bridgeTxDetails[transactionId].proofRelayer;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeRelays(bytes32 transactionId) public view returns (bool) {\n // has this transactionId been relayed?\n return bridgeRelayDetails[transactionId].relayer != address(0);\n }\n\n /// @inheritdoc IFastBridgeV2\n function getBridgeTransactionV2(bytes memory request) public pure returns (BridgeTransactionV2 memory) {\n return abi.decode(request, (BridgeTransactionV2));\n }\n\n /// @notice Pulls a requested token from the user to this contract.\n function _pullToken(address token, uint256 amount) internal returns (uint256 amountPulled) {\n if (token == UniversalTokenLib.ETH_ADDRESS) {\n // For ETH we just need to check that the supplied msg.value is correct\n if (amount != msg.value) revert MsgValueIncorrect();\n amountPulled = msg.value;\n } else {\n token.assertIsContract();\n // Record token balance before transfer\n amountPulled = IERC20(token).balanceOf(address(this));\n // Token needs to be pulled only if msg.value is zero\n // This way user can specify WETH as the origin asset\n IERC20(token).safeTransferFrom(msg.sender, address(this), amount);\n // Use the difference between the recorded balance and the current balance as the amountPulled\n amountPulled = IERC20(token).balanceOf(address(this)) - amountPulled;\n }\n }\n\n /// @notice Calls the Recipient's hook function with the specified callParams and performs\n /// all the necessary checks for the returned value.\n function _checkedCallRecipient(\n address recipient,\n address token,\n uint256 amount,\n bytes memory callParams\n )\n internal\n {\n bytes memory hookData =\n abi.encodeCall(IFastBridgeRecipient.fastBridgeTransferReceived, (token, amount, callParams));\n // This will bubble any revert messages from the hook function\n bytes memory returnData = Address.functionCallWithValue({target: recipient, data: hookData, value: msg.value});\n // Explicit revert if no return data at all\n if (returnData.length == 0) revert RecipientNoReturnValue();\n // Check that exactly a single return value was returned\n if (returnData.length != 32) revert RecipientIncorrectReturnValue();\n // Return value should be abi-encoded hook function selector\n if (bytes32(returnData) != bytes32(IFastBridgeRecipient.fastBridgeTransferReceived.selector)) {\n revert RecipientIncorrectReturnValue();\n }\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint40(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint40).max but\n /// proof.timestamp \u003c type(uint40).max via unchecked statement\n /// @param proofBlockTimestamp The bridge proof block timestamp\n /// @return delta Time delta since proof submitted\n function _timeSince(uint40 proofBlockTimestamp) internal view returns (uint256 delta) {\n unchecked {\n delta = uint40(block.timestamp) - proofBlockTimestamp;\n }\n }\n\n /// @notice Performs all the necessary checks for a bridge to happen.\n /// @dev There's no good way to refactor this function to reduce cyclomatic complexity due to\n /// the number of checks that need to be performed, so we skip the code-complexity rule here.\n // solhint-disable-next-line code-complexity\n function _validateBridgeParams(\n BridgeParams memory params,\n BridgeParamsV2 memory paramsV2,\n int256 exclusivityEndTime\n )\n internal\n view\n {\n // Check V1 (legacy) params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.sender == address(0) || params.to == address(0)) revert ZeroAddress();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n // Check V2 params\n if (paramsV2.callParams.length \u003e MAX_CALL_PARAMS_LENGTH) revert CallParamsLengthAboveMax();\n if (paramsV2.callValue != 0 \u0026\u0026 params.destToken == UniversalTokenLib.ETH_ADDRESS) {\n revert NativeTokenCallValueNotSupported();\n }\n // exclusivityEndTime must be in range (0 .. params.deadline]\n if (exclusivityEndTime \u003c= 0 || exclusivityEndTime \u003e int256(params.deadline)) {\n revert ExclusivityParamsIncorrect();\n }\n }\n\n /// @notice Performs all the necessary checks for a relay to happen.\n function _validateRelayParams(\n BridgeTransactionV2 memory transaction,\n bytes32 transactionId,\n address relayer\n )\n internal\n view\n {\n if (relayer == address(0)) revert ZeroAddress();\n // Check if the transaction has already been relayed\n if (bridgeRelays(transactionId)) revert TransactionRelayed();\n if (transaction.destChainId != uint32(block.chainid)) revert ChainIncorrect();\n // Check the deadline for relay to happen\n if (block.timestamp \u003e transaction.deadline) revert DeadlineExceeded();\n // Check the exclusivity period, if it is still ongoing\n // forgefmt: disable-next-item\n if (\n transaction.exclusivityRelayer != address(0) \u0026\u0026\n transaction.exclusivityRelayer != relayer \u0026\u0026\n block.timestamp \u003c= transaction.exclusivityEndTime\n ) {\n revert ExclusivityPeriodNotPassed();\n }\n }\n}\n","language":"Solidity","languageVersion":"0.8.24","compilerVersion":"0.8.24","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../","srcMap":"","srcMapRuntime":"","abiDefinition":[{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Transfer","type":"event"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"}],"userDoc":{"kind":"user","methods":{},"version":1},"developerDoc":{"details":"Interface of the ERC20 standard as defined in the EIP.","events":{"Approval(address,address,uint256)":{"details":"Emitted when the allowance of a `spender` for an `owner` is set by a call to {approve}. `value` is the new allowance."},"Transfer(address,address,uint256)":{"details":"Emitted when `value` tokens are moved from one account (`from`) to another (`to`). Note that `value` may be zero."}},"kind":"dev","methods":{"allowance(address,address)":{"details":"Returns the remaining number of tokens that `spender` will be allowed to spend on behalf of `owner` through {transferFrom}. This is zero by default. This value changes when {approve} or {transferFrom} are called."},"approve(address,uint256)":{"details":"Sets a `value` amount of tokens as the allowance of `spender` over the caller's tokens. Returns a boolean value indicating whether the operation succeeded. IMPORTANT: Beware that changing an allowance with this method brings the risk that someone may use both the old and the new allowance by unfortunate transaction ordering. One possible solution to mitigate this race condition is to first reduce the spender's allowance to 0 and set the desired value afterwards: https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 Emits an {Approval} event."},"balanceOf(address)":{"details":"Returns the value of tokens owned by `account`."},"totalSupply()":{"details":"Returns the value of tokens in existence."},"transfer(address,uint256)":{"details":"Moves a `value` amount of tokens from the caller's account to `to`. Returns a boolean value indicating whether the operation succeeded. Emits a {Transfer} event."},"transferFrom(address,address,uint256)":{"details":"Moves a `value` amount of tokens from `from` to `to` using the allowance mechanism. `value` is then deducted from the caller's allowance. Returns a boolean value indicating whether the operation succeeded. Emits a {Transfer} event."}},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"Approval\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"Transfer\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"}],\"name\":\"allowance\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"approve\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"balanceOf\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"totalSupply\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"transfer\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"transferFrom\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"details\":\"Interface of the ERC20 standard as defined in the EIP.\",\"events\":{\"Approval(address,address,uint256)\":{\"details\":\"Emitted when the allowance of a `spender` for an `owner` is set by a call to {approve}. `value` is the new allowance.\"},\"Transfer(address,address,uint256)\":{\"details\":\"Emitted when `value` tokens are moved from one account (`from`) to another (`to`). Note that `value` may be zero.\"}},\"kind\":\"dev\",\"methods\":{\"allowance(address,address)\":{\"details\":\"Returns the remaining number of tokens that `spender` will be allowed to spend on behalf of `owner` through {transferFrom}. This is zero by default. This value changes when {approve} or {transferFrom} are called.\"},\"approve(address,uint256)\":{\"details\":\"Sets a `value` amount of tokens as the allowance of `spender` over the caller's tokens. Returns a boolean value indicating whether the operation succeeded. IMPORTANT: Beware that changing an allowance with this method brings the risk that someone may use both the old and the new allowance by unfortunate transaction ordering. One possible solution to mitigate this race condition is to first reduce the spender's allowance to 0 and set the desired value afterwards: https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 Emits an {Approval} event.\"},\"balanceOf(address)\":{\"details\":\"Returns the value of tokens owned by `account`.\"},\"totalSupply()\":{\"details\":\"Returns the value of tokens in existence.\"},\"transfer(address,uint256)\":{\"details\":\"Moves a `value` amount of tokens from the caller's account to `to`. Returns a boolean value indicating whether the operation succeeded. Emits a {Transfer} event.\"},\"transferFrom(address,address,uint256)\":{\"details\":\"Moves a `value` amount of tokens from `from` to `to` using the allowance mechanism. `value` is then deducted from the caller's allowance. Returns a boolean value indicating whether the operation succeeded. Emits a {Transfer} event.\"}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeV2.sol\":\"IERC20\"},\"evmVersion\":\"shanghai\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeV2.sol\":{\"keccak256\":\"0x7cd0f885e80e2bdaa638bc32ae7af7d2e248f99ce4b354c217d0f0f7d7302e0a\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://7ccf28df0bd7b4606986585acd8622ed9b4e81379690061bb66088f0a2270af1\",\"dweb:/ipfs/QmTf7HNdHZkK6vmx8ZgewycQEb72oLD9nPwBpsM5reMstQ\"]}},\"version\":1}"},"hashes":{"allowance(address,address)":"dd62ed3e","approve(address,uint256)":"095ea7b3","balanceOf(address)":"70a08231","totalSupply()":"18160ddd","transfer(address,uint256)":"a9059cbb","transferFrom(address,address,uint256)":"23b872dd"}},"solidity/FastBridgeV2.sol:IERC20Permit":{"code":"0x","runtime-code":"0x","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.24 ^0.8.0 ^0.8.20;\n\n// contracts/interfaces/IAdmin.sol\n\ninterface IAdmin {\n // ============ Events ============\n\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n event ChainGasAmountUpdated(uint256 oldChainGasAmount, uint256 newChainGasAmount);\n\n // ============ Methods ============\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n\n function setChainGasAmount(uint256 newChainGasAmount) external;\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IFastBridgeRecipient.sol\n\ninterface IFastBridgeRecipient {\n function fastBridgeTransferReceived(\n address token,\n uint256 amount,\n bytes memory callParams\n )\n external\n payable\n returns (bytes4);\n}\n\n// contracts/interfaces/IFastBridgeV2Errors.sol\n\ninterface IFastBridgeV2Errors {\n error AmountIncorrect();\n error CallParamsLengthAboveMax();\n error ChainIncorrect();\n error ExclusivityParamsIncorrect();\n error MsgValueIncorrect();\n error NativeTokenCallValueNotSupported();\n error SenderIncorrect();\n error StatusIncorrect();\n error ZeroAddress();\n\n error RecipientIncorrectReturnValue();\n error RecipientNoReturnValue();\n\n error DeadlineExceeded();\n error DeadlineNotExceeded();\n error DeadlineTooShort();\n error DisputePeriodNotPassed();\n error DisputePeriodPassed();\n error ExclusivityPeriodNotPassed();\n\n error TransactionRelayed();\n}\n\n// contracts/libs/Errors.sol\n\nerror DeadlineExceeded();\nerror DeadlineNotExceeded();\nerror DeadlineTooShort();\nerror InsufficientOutputAmount();\n\nerror MsgValueIncorrect();\nerror PoolNotFound();\nerror TokenAddressMismatch();\nerror TokenNotContract();\nerror TokenNotETH();\nerror TokensIdentical();\n\nerror ChainIncorrect();\nerror AmountIncorrect();\nerror ZeroAddress();\n\nerror DisputePeriodNotPassed();\nerror DisputePeriodPassed();\nerror SenderIncorrect();\nerror StatusIncorrect();\nerror TransactionIdIncorrect();\nerror TransactionRelayed();\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// contracts/interfaces/IFastBridgeV2.sol\n\ninterface IFastBridgeV2 is IFastBridge {\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n struct BridgeTxDetails {\n BridgeStatus status;\n uint40 proofBlockTimestamp;\n uint48 proofBlockNumber;\n address proofRelayer;\n }\n\n struct BridgeRelay {\n uint48 blockNumber;\n uint48 blockTimestamp;\n address relayer;\n }\n\n /// @notice New params introduced in the FastBridgeV2.\n /// We are passing fields from the older BridgeParams struct outside of this struct\n /// for backwards compatibility.\n /// Note: quoteRelayer and quoteExclusivitySeconds are either both zero (indicating no exclusivity)\n /// or both non-zero (indicating exclusivity for the given period).\n /// Note: callValue \u003e 0 can NOT be used with destToken = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE (ETH_ADDRESS)\n /// @param quoteRelayer Relayer that provided the quote for the transaction\n /// @param quoteExclusivitySeconds Period of time the quote relayer is guaranteed exclusivity after user's deposit\n /// @param quoteId Unique quote identifier used for tracking the quote\n /// @param callValue ETH value to send to the recipient (if any)\n /// @param callParams Parameters for the arbitrary call to the destination recipient (if any)\n struct BridgeParamsV2 {\n address quoteRelayer;\n int256 quoteExclusivitySeconds;\n bytes quoteId;\n uint256 callValue;\n bytes callParams;\n }\n\n /// @notice Updated bridge transaction struct to include parameters introduced in FastBridgeV2.\n /// Note: only `exclusivityRelayer` can fill such a transaction until `exclusivityEndTime`.\n /// TODO: consider changing the encoding scheme to prevent spending extra gas on decoding.\n struct BridgeTransactionV2 {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n uint256 callValue; // ETH value to send to the recipient (if any) - replaces V1's sendChainGas flag\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n address exclusivityRelayer;\n uint256 exclusivityEndTime;\n bytes callParams;\n }\n\n event BridgeQuoteDetails(bytes32 indexed transactionId, bytes quoteId);\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability\n /// to provide temporary exclusivity fill rights for the quote relayer.\n /// @param params The parameters required to bridge\n /// @param paramsV2 The parameters for exclusivity fill rights (optional, can be left empty)\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function relay(bytes memory request, address relayer) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param transactionId The transaction id associated with the encoded bridge transaction to prove\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital.\n /// @notice Can only send funds to the relayer address on the proof.\n /// @param request The encoded bridge transaction to claim on origin chain\n function claim(bytes memory request) external;\n /// @notice Checks if a transaction has been relayed\n /// @param transactionId The ID of the transaction to check\n /// @return True if the transaction has been relayed, false otherwise\n function bridgeRelays(bytes32 transactionId) external view returns (bool);\n\n /// @notice Returns the status of a bridge transaction\n /// @param transactionId The ID of the bridge transaction\n /// @return BridgeStatus Status of the bridge transaction\n function bridgeStatuses(bytes32 transactionId) external view returns (BridgeStatus);\n\n /// @notice Returns the timestamp and relayer of a bridge proof\n /// @param transactionId The ID of the bridge transaction\n /// @return timestamp The timestamp of the bridge proof\n /// @return relayer The relayer address of the bridge proof\n function bridgeProofs(bytes32 transactionId) external view returns (uint96 timestamp, address relayer);\n\n /// @notice Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\n /// @param request The bridge request to decode\n function getBridgeTransactionV2(bytes memory request) external view returns (BridgeTransactionV2 memory);\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// contracts/libs/UniversalToken.sol\n\nlibrary UniversalTokenLib {\n using SafeERC20 for IERC20;\n\n address internal constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Transfers tokens to the given account. Reverts if transfer is not successful.\n /// @dev This might trigger fallback, if ETH is transferred to the contract.\n /// Make sure this can not lead to reentrancy attacks.\n function universalTransfer(address token, address to, uint256 value) internal {\n // Don't do anything, if need to send tokens to this address\n if (to == address(this)) return;\n // Don't do anything, if trying to send zero value\n if (value == 0) return;\n if (token == ETH_ADDRESS) {\n /// @dev Note: this can potentially lead to executing code in `to`.\n // solhint-disable-next-line avoid-low-level-calls\n (bool success,) = to.call{value: value}(\"\");\n require(success, \"ETH transfer failed\");\n } else {\n IERC20(token).safeTransfer(to, value);\n }\n }\n\n /// @notice Issues an infinite allowance to the spender, if the current allowance is insufficient\n /// to spend the given amount.\n function universalApproveInfinity(address token, address spender, uint256 amountToSpend) internal {\n // ETH Chad doesn't require your approval\n if (token == ETH_ADDRESS) return;\n // No-op if allowance is already sufficient\n uint256 allowance = IERC20(token).allowance(address(this), spender);\n if (allowance \u003e= amountToSpend) return;\n // Otherwise, reset approval to 0 and set to max allowance\n if (allowance \u003e 0) IERC20(token).safeDecreaseAllowance(spender, allowance);\n IERC20(token).safeIncreaseAllowance(spender, type(uint256).max);\n }\n\n /// @notice Returns the balance of the given token (or native ETH) for the given account.\n function universalBalanceOf(address token, address account) internal view returns (uint256) {\n if (token == ETH_ADDRESS) {\n return account.balance;\n } else {\n return IERC20(token).balanceOf(account);\n }\n }\n\n /// @dev Checks that token is a contract and not ETH_ADDRESS.\n function assertIsContract(address token) internal view {\n // Check that ETH_ADDRESS was not used (in case this is a predeploy on any of the chains)\n if (token == UniversalTokenLib.ETH_ADDRESS) revert TokenNotContract();\n // Check that token is not an EOA\n if (token.code.length == 0) revert TokenNotContract();\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/Admin.sol\n\ncontract Admin is IAdmin, AccessControlEnumerable {\n using UniversalTokenLib for address;\n\n bytes32 public constant RELAYER_ROLE = keccak256(\"RELAYER_ROLE\");\n bytes32 public constant REFUNDER_ROLE = keccak256(\"REFUNDER_ROLE\");\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n uint256 public constant FEE_BPS = 1e6;\n uint256 public constant FEE_RATE_MAX = 0.01e6; // max 1% on origin amount\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Chain gas amount to forward as rebate if requested\n uint256 public chainGasAmount;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n }\n\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n require(newFeeRate \u003c= FEE_RATE_MAX, \"newFeeRate \u003e max\");\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n token.universalTransfer(recipient, feeAmount);\n emit FeesSwept(token, recipient, feeAmount);\n }\n\n function setChainGasAmount(uint256 newChainGasAmount) external onlyRole(GOVERNOR_ROLE) {\n uint256 oldChainGasAmount = chainGasAmount;\n chainGasAmount = newChainGasAmount;\n emit ChainGasAmountUpdated(oldChainGasAmount, newChainGasAmount);\n }\n}\n\n// contracts/FastBridgeV2.sol\n\n/// @notice FastBridgeV2 is a contract for bridging tokens across chains.\ncontract FastBridgeV2 is Admin, IFastBridgeV2, IFastBridgeV2Errors {\n using SafeERC20 for IERC20;\n using UniversalTokenLib for address;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Delay for a transaction after which it could be permisionlessly refunded\n uint256 public constant REFUND_DELAY = 7 days;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n /// @notice Maximum length of accepted callParams\n uint256 public constant MAX_CALL_PARAMS_LENGTH = 2 ** 16 - 1;\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeTxDetails) public bridgeTxDetails;\n /// @notice Relay details on destination chain\n mapping(bytes32 =\u003e BridgeRelay) public bridgeRelayDetails;\n /// @notice Unique bridge nonces tracked per originSender\n mapping(address =\u003e uint256) public senderNonces;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Replaced by senderNonces\n uint256 public immutable nonce = 0;\n /// @notice the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n bridge({\n params: params,\n paramsV2: BridgeParamsV2({\n quoteRelayer: address(0),\n quoteExclusivitySeconds: 0,\n quoteId: bytes(\"\"),\n callValue: 0,\n callParams: bytes(\"\")\n })\n });\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes memory request) external payable {\n relay({request: request, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes memory request, bytes32 destTxHash) external {\n prove({transactionId: keccak256(request), destTxHash: destTxHash, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridgeV2\n function claim(bytes memory request) external {\n claim({request: request, to: address(0)});\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003e DISPUTE_PERIOD) {\n revert DisputePeriodPassed();\n }\n\n // @dev relayer gets slashed effectively if dest relay has gone thru\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n bridgeTxDetails[transactionId].proofRelayer = address(0);\n bridgeTxDetails[transactionId].proofBlockTimestamp = 0;\n bridgeTxDetails[transactionId].proofBlockNumber = 0;\n\n emit BridgeProofDisputed(transactionId, msg.sender);\n }\n\n /// @inheritdoc IFastBridge\n function refund(bytes memory request) external {\n bytes32 transactionId = keccak256(request);\n\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n\n if (bridgeTxDetails[transactionId].status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n\n if (hasRole(REFUNDER_ROLE, msg.sender)) {\n // Refunder can refund if deadline has passed\n if (block.timestamp \u003c= transaction.deadline) revert DeadlineNotExceeded();\n } else {\n // Permissionless refund is allowed after REFUND_DELAY\n if (block.timestamp \u003c= transaction.deadline + REFUND_DELAY) revert DeadlineNotExceeded();\n }\n\n // if all checks passed, set to REFUNDED status\n bridgeTxDetails[transactionId].status = BridgeStatus.REFUNDED;\n\n // transfer origin collateral back to original sender\n address to = transaction.originSender;\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount + transaction.originFeeAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (bridgeTxDetails[transactionId].proofRelayer != relayer) revert SenderIncorrect();\n return _timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n /// @dev This method is added to achieve backwards compatibility with decoding requests into V1 structs:\n /// - `callValue` is partially reported as a zero/non-zero flag\n /// - `callParams` is ignored\n /// In order to process all kinds of requests use getBridgeTransactionV2 instead.\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory) {\n // Try decoding into V2 struct first. This will revert if V1 struct is passed\n try this.getBridgeTransactionV2(request) returns (BridgeTransactionV2 memory txV2) {\n // Note: we entirely ignore the callParams field, as it was not present in V1\n return BridgeTransaction({\n originChainId: txV2.originChainId,\n destChainId: txV2.destChainId,\n originSender: txV2.originSender,\n destRecipient: txV2.destRecipient,\n originToken: txV2.originToken,\n destToken: txV2.destToken,\n originAmount: txV2.originAmount,\n destAmount: txV2.destAmount,\n originFeeAmount: txV2.originFeeAmount,\n sendChainGas: txV2.callValue != 0,\n deadline: txV2.deadline,\n nonce: txV2.nonce\n });\n } catch {\n // Fallback to V1 struct\n return abi.decode(request, (BridgeTransaction));\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) public payable {\n int256 exclusivityEndTime = int256(block.timestamp) + paramsV2.quoteExclusivitySeconds;\n _validateBridgeParams(params, paramsV2, exclusivityEndTime);\n\n // transfer tokens to bridge contract\n /// @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _pullToken(params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n\n // set status to requested\n bytes memory request = abi.encode(\n BridgeTransactionV2({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n callValue: paramsV2.callValue,\n deadline: params.deadline,\n nonce: senderNonces[params.sender]++, // increment nonce on every bridge\n exclusivityRelayer: paramsV2.quoteRelayer,\n // We checked exclusivityEndTime to be in range (0 .. params.deadline] above, so can safely cast\n exclusivityEndTime: uint256(exclusivityEndTime),\n callParams: paramsV2.callParams\n })\n );\n bytes32 transactionId = keccak256(request);\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n\n emit BridgeRequested({\n transactionId: transactionId,\n sender: params.sender,\n request: request,\n destChainId: params.dstChainId,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n sendChainGas: paramsV2.callValue != 0\n });\n emit BridgeQuoteDetails(transactionId, paramsV2.quoteId);\n }\n\n /// @inheritdoc IFastBridgeV2\n function relay(bytes memory request, address relayer) public payable {\n bytes32 transactionId = keccak256(request);\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n _validateRelayParams(transaction, transactionId, relayer);\n // mark bridge transaction as relayed\n bridgeRelayDetails[transactionId] =\n BridgeRelay({blockNumber: uint48(block.number), blockTimestamp: uint48(block.timestamp), relayer: relayer});\n\n // transfer tokens to recipient on destination chain and do an arbitrary call if requested\n address to = transaction.destRecipient;\n address token = transaction.destToken;\n uint256 amount = transaction.destAmount;\n\n // All state changes have been done at this point, can proceed to the external calls.\n // This follows the checks-effects-interactions pattern to mitigate potential reentrancy attacks.\n if (token == UniversalTokenLib.ETH_ADDRESS) {\n // For ETH non-zero callValue is not allowed\n if (transaction.callValue != 0) revert NativeTokenCallValueNotSupported();\n // Check that the correct msg.value was sent\n if (msg.value != amount) revert MsgValueIncorrect();\n } else {\n // For ERC20s, we check that the correct msg.value was sent\n if (msg.value != transaction.callValue) revert MsgValueIncorrect();\n // We need to transfer the tokens from the Relayer to the recipient first before performing an\n // optional post-transfer arbitrary call.\n IERC20(token).safeTransferFrom(msg.sender, to, amount);\n }\n\n if (transaction.callParams.length != 0) {\n // Arbitrary call requested, perform it while supplying full msg.value to the recipient\n // Note: if token has a fee on transfers, the recipient will have received less than `amount`.\n // This is a very niche edge case and should be handled by the recipient contract.\n _checkedCallRecipient({recipient: to, token: token, amount: amount, callParams: transaction.callParams});\n } else if (msg.value != 0) {\n // No arbitrary call requested, but msg.value was sent. This is either a relay with ETH,\n // or a non-zero callValue request with an ERC20. In both cases, transfer the ETH to the recipient.\n Address.sendValue(payable(to), msg.value);\n }\n\n emit BridgeRelayed({\n transactionId: transactionId,\n relayer: relayer,\n to: to,\n originChainId: transaction.originChainId,\n originToken: transaction.originToken,\n destToken: transaction.destToken,\n originAmount: transaction.originAmount,\n destAmount: transaction.destAmount,\n chainGasAmount: transaction.callValue\n });\n }\n\n /// @inheritdoc IFastBridgeV2\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) public onlyRole(RELAYER_ROLE) {\n // update bridge tx status given proof provided\n if (bridgeTxDetails[transactionId].status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n bridgeTxDetails[transactionId].status = BridgeStatus.RELAYER_PROVED;\n bridgeTxDetails[transactionId].proofBlockTimestamp = uint40(block.timestamp);\n bridgeTxDetails[transactionId].proofBlockNumber = uint48(block.number);\n bridgeTxDetails[transactionId].proofRelayer = relayer;\n\n emit BridgeProofProvided(transactionId, relayer, destTxHash);\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes memory request, address to) public {\n bytes32 transactionId = keccak256(request);\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n\n // update bridge tx status if able to claim origin collateral\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n\n // if \"to\" is zero addr, permissionlessly send funds to proven relayer\n if (to == address(0)) {\n to = bridgeTxDetails[transactionId].proofRelayer;\n } else if (bridgeTxDetails[transactionId].proofRelayer != msg.sender) {\n revert SenderIncorrect();\n }\n\n if (_timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003c= DISPUTE_PERIOD) {\n revert DisputePeriodNotPassed();\n }\n\n bridgeTxDetails[transactionId].status = BridgeStatus.RELAYER_CLAIMED;\n\n // update protocol fees if origin fee amount exists\n if (transaction.originFeeAmount \u003e 0) protocolFees[transaction.originToken] += transaction.originFeeAmount;\n\n // transfer origin collateral less fee to specified address\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositClaimed(transactionId, bridgeTxDetails[transactionId].proofRelayer, to, token, amount);\n }\n\n function bridgeStatuses(bytes32 transactionId) public view returns (BridgeStatus status) {\n return bridgeTxDetails[transactionId].status;\n }\n\n function bridgeProofs(bytes32 transactionId) public view returns (uint96 timestamp, address relayer) {\n timestamp = bridgeTxDetails[transactionId].proofBlockTimestamp;\n relayer = bridgeTxDetails[transactionId].proofRelayer;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeRelays(bytes32 transactionId) public view returns (bool) {\n // has this transactionId been relayed?\n return bridgeRelayDetails[transactionId].relayer != address(0);\n }\n\n /// @inheritdoc IFastBridgeV2\n function getBridgeTransactionV2(bytes memory request) public pure returns (BridgeTransactionV2 memory) {\n return abi.decode(request, (BridgeTransactionV2));\n }\n\n /// @notice Pulls a requested token from the user to this contract.\n function _pullToken(address token, uint256 amount) internal returns (uint256 amountPulled) {\n if (token == UniversalTokenLib.ETH_ADDRESS) {\n // For ETH we just need to check that the supplied msg.value is correct\n if (amount != msg.value) revert MsgValueIncorrect();\n amountPulled = msg.value;\n } else {\n token.assertIsContract();\n // Record token balance before transfer\n amountPulled = IERC20(token).balanceOf(address(this));\n // Token needs to be pulled only if msg.value is zero\n // This way user can specify WETH as the origin asset\n IERC20(token).safeTransferFrom(msg.sender, address(this), amount);\n // Use the difference between the recorded balance and the current balance as the amountPulled\n amountPulled = IERC20(token).balanceOf(address(this)) - amountPulled;\n }\n }\n\n /// @notice Calls the Recipient's hook function with the specified callParams and performs\n /// all the necessary checks for the returned value.\n function _checkedCallRecipient(\n address recipient,\n address token,\n uint256 amount,\n bytes memory callParams\n )\n internal\n {\n bytes memory hookData =\n abi.encodeCall(IFastBridgeRecipient.fastBridgeTransferReceived, (token, amount, callParams));\n // This will bubble any revert messages from the hook function\n bytes memory returnData = Address.functionCallWithValue({target: recipient, data: hookData, value: msg.value});\n // Explicit revert if no return data at all\n if (returnData.length == 0) revert RecipientNoReturnValue();\n // Check that exactly a single return value was returned\n if (returnData.length != 32) revert RecipientIncorrectReturnValue();\n // Return value should be abi-encoded hook function selector\n if (bytes32(returnData) != bytes32(IFastBridgeRecipient.fastBridgeTransferReceived.selector)) {\n revert RecipientIncorrectReturnValue();\n }\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint40(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint40).max but\n /// proof.timestamp \u003c type(uint40).max via unchecked statement\n /// @param proofBlockTimestamp The bridge proof block timestamp\n /// @return delta Time delta since proof submitted\n function _timeSince(uint40 proofBlockTimestamp) internal view returns (uint256 delta) {\n unchecked {\n delta = uint40(block.timestamp) - proofBlockTimestamp;\n }\n }\n\n /// @notice Performs all the necessary checks for a bridge to happen.\n /// @dev There's no good way to refactor this function to reduce cyclomatic complexity due to\n /// the number of checks that need to be performed, so we skip the code-complexity rule here.\n // solhint-disable-next-line code-complexity\n function _validateBridgeParams(\n BridgeParams memory params,\n BridgeParamsV2 memory paramsV2,\n int256 exclusivityEndTime\n )\n internal\n view\n {\n // Check V1 (legacy) params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.sender == address(0) || params.to == address(0)) revert ZeroAddress();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n // Check V2 params\n if (paramsV2.callParams.length \u003e MAX_CALL_PARAMS_LENGTH) revert CallParamsLengthAboveMax();\n if (paramsV2.callValue != 0 \u0026\u0026 params.destToken == UniversalTokenLib.ETH_ADDRESS) {\n revert NativeTokenCallValueNotSupported();\n }\n // exclusivityEndTime must be in range (0 .. params.deadline]\n if (exclusivityEndTime \u003c= 0 || exclusivityEndTime \u003e int256(params.deadline)) {\n revert ExclusivityParamsIncorrect();\n }\n }\n\n /// @notice Performs all the necessary checks for a relay to happen.\n function _validateRelayParams(\n BridgeTransactionV2 memory transaction,\n bytes32 transactionId,\n address relayer\n )\n internal\n view\n {\n if (relayer == address(0)) revert ZeroAddress();\n // Check if the transaction has already been relayed\n if (bridgeRelays(transactionId)) revert TransactionRelayed();\n if (transaction.destChainId != uint32(block.chainid)) revert ChainIncorrect();\n // Check the deadline for relay to happen\n if (block.timestamp \u003e transaction.deadline) revert DeadlineExceeded();\n // Check the exclusivity period, if it is still ongoing\n // forgefmt: disable-next-item\n if (\n transaction.exclusivityRelayer != address(0) \u0026\u0026\n transaction.exclusivityRelayer != relayer \u0026\u0026\n block.timestamp \u003c= transaction.exclusivityEndTime\n ) {\n revert ExclusivityPeriodNotPassed();\n }\n }\n}\n","language":"Solidity","languageVersion":"0.8.24","compilerVersion":"0.8.24","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../","srcMap":"","srcMapRuntime":"","abiDefinition":[{"inputs":[],"name":"DOMAIN_SEPARATOR","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"nonces","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"permit","outputs":[],"stateMutability":"nonpayable","type":"function"}],"userDoc":{"kind":"user","methods":{},"version":1},"developerDoc":{"details":"Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in https://eips.ethereum.org/EIPS/eip-2612[EIP-2612]. Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't need to send a transaction, and thus is not required to hold Ether at all. ==== Security Considerations There are two important considerations concerning the use of `permit`. The first is that a valid permit signature expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be considered as an intention to spend the allowance in any specific way. The second is that because permits have built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be generally recommended is: ```solidity function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public { try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {} doThing(..., value); } function doThing(..., uint256 value) public { token.safeTransferFrom(msg.sender, address(this), value); ... } ``` Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also {SafeERC20-safeTransferFrom}). Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so contracts should have entry points that don't rely on permit.","kind":"dev","methods":{"DOMAIN_SEPARATOR()":{"details":"Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}."},"nonces(address)":{"details":"Returns the current nonce for `owner`. This value must be included whenever a signature is generated for {permit}. Every successful call to {permit} increases ``owner``'s nonce by one. This prevents a signature from being used multiple times."},"permit(address,address,uint256,uint256,uint8,bytes32,bytes32)":{"details":"Sets `value` as the allowance of `spender` over ``owner``'s tokens, given ``owner``'s signed approval. IMPORTANT: The same issues {IERC20-approve} has related to transaction ordering also apply here. Emits an {Approval} event. Requirements: - `spender` cannot be the zero address. - `deadline` must be a timestamp in the future. - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner` over the EIP712-formatted function arguments. - the signature must use ``owner``'s current nonce (see {nonces}). For more information on the signature format, see the https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP section]. CAUTION: See Security Considerations above."}},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[],\"name\":\"DOMAIN_SEPARATOR\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"}],\"name\":\"nonces\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"},{\"internalType\":\"uint8\",\"name\":\"v\",\"type\":\"uint8\"},{\"internalType\":\"bytes32\",\"name\":\"r\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"s\",\"type\":\"bytes32\"}],\"name\":\"permit\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"details\":\"Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in https://eips.ethereum.org/EIPS/eip-2612[EIP-2612]. Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't need to send a transaction, and thus is not required to hold Ether at all. ==== Security Considerations There are two important considerations concerning the use of `permit`. The first is that a valid permit signature expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be considered as an intention to spend the allowance in any specific way. The second is that because permits have built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be generally recommended is: ```solidity function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public { try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {} doThing(..., value); } function doThing(..., uint256 value) public { token.safeTransferFrom(msg.sender, address(this), value); ... } ``` Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also {SafeERC20-safeTransferFrom}). Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so contracts should have entry points that don't rely on permit.\",\"kind\":\"dev\",\"methods\":{\"DOMAIN_SEPARATOR()\":{\"details\":\"Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\"},\"nonces(address)\":{\"details\":\"Returns the current nonce for `owner`. This value must be included whenever a signature is generated for {permit}. Every successful call to {permit} increases ``owner``'s nonce by one. This prevents a signature from being used multiple times.\"},\"permit(address,address,uint256,uint256,uint8,bytes32,bytes32)\":{\"details\":\"Sets `value` as the allowance of `spender` over ``owner``'s tokens, given ``owner``'s signed approval. IMPORTANT: The same issues {IERC20-approve} has related to transaction ordering also apply here. Emits an {Approval} event. Requirements: - `spender` cannot be the zero address. - `deadline` must be a timestamp in the future. - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner` over the EIP712-formatted function arguments. - the signature must use ``owner``'s current nonce (see {nonces}). For more information on the signature format, see the https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP section]. CAUTION: See Security Considerations above.\"}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeV2.sol\":\"IERC20Permit\"},\"evmVersion\":\"shanghai\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeV2.sol\":{\"keccak256\":\"0x7cd0f885e80e2bdaa638bc32ae7af7d2e248f99ce4b354c217d0f0f7d7302e0a\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://7ccf28df0bd7b4606986585acd8622ed9b4e81379690061bb66088f0a2270af1\",\"dweb:/ipfs/QmTf7HNdHZkK6vmx8ZgewycQEb72oLD9nPwBpsM5reMstQ\"]}},\"version\":1}"},"hashes":{"DOMAIN_SEPARATOR()":"3644e515","nonces(address)":"7ecebe00","permit(address,address,uint256,uint256,uint8,bytes32,bytes32)":"d505accf"}},"solidity/FastBridgeV2.sol:IFastBridge":{"code":"0x","runtime-code":"0x","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.24 ^0.8.0 ^0.8.20;\n\n// contracts/interfaces/IAdmin.sol\n\ninterface IAdmin {\n // ============ Events ============\n\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n event ChainGasAmountUpdated(uint256 oldChainGasAmount, uint256 newChainGasAmount);\n\n // ============ Methods ============\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n\n function setChainGasAmount(uint256 newChainGasAmount) external;\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IFastBridgeRecipient.sol\n\ninterface IFastBridgeRecipient {\n function fastBridgeTransferReceived(\n address token,\n uint256 amount,\n bytes memory callParams\n )\n external\n payable\n returns (bytes4);\n}\n\n// contracts/interfaces/IFastBridgeV2Errors.sol\n\ninterface IFastBridgeV2Errors {\n error AmountIncorrect();\n error CallParamsLengthAboveMax();\n error ChainIncorrect();\n error ExclusivityParamsIncorrect();\n error MsgValueIncorrect();\n error NativeTokenCallValueNotSupported();\n error SenderIncorrect();\n error StatusIncorrect();\n error ZeroAddress();\n\n error RecipientIncorrectReturnValue();\n error RecipientNoReturnValue();\n\n error DeadlineExceeded();\n error DeadlineNotExceeded();\n error DeadlineTooShort();\n error DisputePeriodNotPassed();\n error DisputePeriodPassed();\n error ExclusivityPeriodNotPassed();\n\n error TransactionRelayed();\n}\n\n// contracts/libs/Errors.sol\n\nerror DeadlineExceeded();\nerror DeadlineNotExceeded();\nerror DeadlineTooShort();\nerror InsufficientOutputAmount();\n\nerror MsgValueIncorrect();\nerror PoolNotFound();\nerror TokenAddressMismatch();\nerror TokenNotContract();\nerror TokenNotETH();\nerror TokensIdentical();\n\nerror ChainIncorrect();\nerror AmountIncorrect();\nerror ZeroAddress();\n\nerror DisputePeriodNotPassed();\nerror DisputePeriodPassed();\nerror SenderIncorrect();\nerror StatusIncorrect();\nerror TransactionIdIncorrect();\nerror TransactionRelayed();\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// contracts/interfaces/IFastBridgeV2.sol\n\ninterface IFastBridgeV2 is IFastBridge {\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n struct BridgeTxDetails {\n BridgeStatus status;\n uint40 proofBlockTimestamp;\n uint48 proofBlockNumber;\n address proofRelayer;\n }\n\n struct BridgeRelay {\n uint48 blockNumber;\n uint48 blockTimestamp;\n address relayer;\n }\n\n /// @notice New params introduced in the FastBridgeV2.\n /// We are passing fields from the older BridgeParams struct outside of this struct\n /// for backwards compatibility.\n /// Note: quoteRelayer and quoteExclusivitySeconds are either both zero (indicating no exclusivity)\n /// or both non-zero (indicating exclusivity for the given period).\n /// Note: callValue \u003e 0 can NOT be used with destToken = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE (ETH_ADDRESS)\n /// @param quoteRelayer Relayer that provided the quote for the transaction\n /// @param quoteExclusivitySeconds Period of time the quote relayer is guaranteed exclusivity after user's deposit\n /// @param quoteId Unique quote identifier used for tracking the quote\n /// @param callValue ETH value to send to the recipient (if any)\n /// @param callParams Parameters for the arbitrary call to the destination recipient (if any)\n struct BridgeParamsV2 {\n address quoteRelayer;\n int256 quoteExclusivitySeconds;\n bytes quoteId;\n uint256 callValue;\n bytes callParams;\n }\n\n /// @notice Updated bridge transaction struct to include parameters introduced in FastBridgeV2.\n /// Note: only `exclusivityRelayer` can fill such a transaction until `exclusivityEndTime`.\n /// TODO: consider changing the encoding scheme to prevent spending extra gas on decoding.\n struct BridgeTransactionV2 {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n uint256 callValue; // ETH value to send to the recipient (if any) - replaces V1's sendChainGas flag\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n address exclusivityRelayer;\n uint256 exclusivityEndTime;\n bytes callParams;\n }\n\n event BridgeQuoteDetails(bytes32 indexed transactionId, bytes quoteId);\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability\n /// to provide temporary exclusivity fill rights for the quote relayer.\n /// @param params The parameters required to bridge\n /// @param paramsV2 The parameters for exclusivity fill rights (optional, can be left empty)\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function relay(bytes memory request, address relayer) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param transactionId The transaction id associated with the encoded bridge transaction to prove\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital.\n /// @notice Can only send funds to the relayer address on the proof.\n /// @param request The encoded bridge transaction to claim on origin chain\n function claim(bytes memory request) external;\n /// @notice Checks if a transaction has been relayed\n /// @param transactionId The ID of the transaction to check\n /// @return True if the transaction has been relayed, false otherwise\n function bridgeRelays(bytes32 transactionId) external view returns (bool);\n\n /// @notice Returns the status of a bridge transaction\n /// @param transactionId The ID of the bridge transaction\n /// @return BridgeStatus Status of the bridge transaction\n function bridgeStatuses(bytes32 transactionId) external view returns (BridgeStatus);\n\n /// @notice Returns the timestamp and relayer of a bridge proof\n /// @param transactionId The ID of the bridge transaction\n /// @return timestamp The timestamp of the bridge proof\n /// @return relayer The relayer address of the bridge proof\n function bridgeProofs(bytes32 transactionId) external view returns (uint96 timestamp, address relayer);\n\n /// @notice Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\n /// @param request The bridge request to decode\n function getBridgeTransactionV2(bytes memory request) external view returns (BridgeTransactionV2 memory);\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// contracts/libs/UniversalToken.sol\n\nlibrary UniversalTokenLib {\n using SafeERC20 for IERC20;\n\n address internal constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Transfers tokens to the given account. Reverts if transfer is not successful.\n /// @dev This might trigger fallback, if ETH is transferred to the contract.\n /// Make sure this can not lead to reentrancy attacks.\n function universalTransfer(address token, address to, uint256 value) internal {\n // Don't do anything, if need to send tokens to this address\n if (to == address(this)) return;\n // Don't do anything, if trying to send zero value\n if (value == 0) return;\n if (token == ETH_ADDRESS) {\n /// @dev Note: this can potentially lead to executing code in `to`.\n // solhint-disable-next-line avoid-low-level-calls\n (bool success,) = to.call{value: value}(\"\");\n require(success, \"ETH transfer failed\");\n } else {\n IERC20(token).safeTransfer(to, value);\n }\n }\n\n /// @notice Issues an infinite allowance to the spender, if the current allowance is insufficient\n /// to spend the given amount.\n function universalApproveInfinity(address token, address spender, uint256 amountToSpend) internal {\n // ETH Chad doesn't require your approval\n if (token == ETH_ADDRESS) return;\n // No-op if allowance is already sufficient\n uint256 allowance = IERC20(token).allowance(address(this), spender);\n if (allowance \u003e= amountToSpend) return;\n // Otherwise, reset approval to 0 and set to max allowance\n if (allowance \u003e 0) IERC20(token).safeDecreaseAllowance(spender, allowance);\n IERC20(token).safeIncreaseAllowance(spender, type(uint256).max);\n }\n\n /// @notice Returns the balance of the given token (or native ETH) for the given account.\n function universalBalanceOf(address token, address account) internal view returns (uint256) {\n if (token == ETH_ADDRESS) {\n return account.balance;\n } else {\n return IERC20(token).balanceOf(account);\n }\n }\n\n /// @dev Checks that token is a contract and not ETH_ADDRESS.\n function assertIsContract(address token) internal view {\n // Check that ETH_ADDRESS was not used (in case this is a predeploy on any of the chains)\n if (token == UniversalTokenLib.ETH_ADDRESS) revert TokenNotContract();\n // Check that token is not an EOA\n if (token.code.length == 0) revert TokenNotContract();\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/Admin.sol\n\ncontract Admin is IAdmin, AccessControlEnumerable {\n using UniversalTokenLib for address;\n\n bytes32 public constant RELAYER_ROLE = keccak256(\"RELAYER_ROLE\");\n bytes32 public constant REFUNDER_ROLE = keccak256(\"REFUNDER_ROLE\");\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n uint256 public constant FEE_BPS = 1e6;\n uint256 public constant FEE_RATE_MAX = 0.01e6; // max 1% on origin amount\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Chain gas amount to forward as rebate if requested\n uint256 public chainGasAmount;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n }\n\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n require(newFeeRate \u003c= FEE_RATE_MAX, \"newFeeRate \u003e max\");\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n token.universalTransfer(recipient, feeAmount);\n emit FeesSwept(token, recipient, feeAmount);\n }\n\n function setChainGasAmount(uint256 newChainGasAmount) external onlyRole(GOVERNOR_ROLE) {\n uint256 oldChainGasAmount = chainGasAmount;\n chainGasAmount = newChainGasAmount;\n emit ChainGasAmountUpdated(oldChainGasAmount, newChainGasAmount);\n }\n}\n\n// contracts/FastBridgeV2.sol\n\n/// @notice FastBridgeV2 is a contract for bridging tokens across chains.\ncontract FastBridgeV2 is Admin, IFastBridgeV2, IFastBridgeV2Errors {\n using SafeERC20 for IERC20;\n using UniversalTokenLib for address;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Delay for a transaction after which it could be permisionlessly refunded\n uint256 public constant REFUND_DELAY = 7 days;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n /// @notice Maximum length of accepted callParams\n uint256 public constant MAX_CALL_PARAMS_LENGTH = 2 ** 16 - 1;\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeTxDetails) public bridgeTxDetails;\n /// @notice Relay details on destination chain\n mapping(bytes32 =\u003e BridgeRelay) public bridgeRelayDetails;\n /// @notice Unique bridge nonces tracked per originSender\n mapping(address =\u003e uint256) public senderNonces;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Replaced by senderNonces\n uint256 public immutable nonce = 0;\n /// @notice the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n bridge({\n params: params,\n paramsV2: BridgeParamsV2({\n quoteRelayer: address(0),\n quoteExclusivitySeconds: 0,\n quoteId: bytes(\"\"),\n callValue: 0,\n callParams: bytes(\"\")\n })\n });\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes memory request) external payable {\n relay({request: request, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes memory request, bytes32 destTxHash) external {\n prove({transactionId: keccak256(request), destTxHash: destTxHash, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridgeV2\n function claim(bytes memory request) external {\n claim({request: request, to: address(0)});\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003e DISPUTE_PERIOD) {\n revert DisputePeriodPassed();\n }\n\n // @dev relayer gets slashed effectively if dest relay has gone thru\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n bridgeTxDetails[transactionId].proofRelayer = address(0);\n bridgeTxDetails[transactionId].proofBlockTimestamp = 0;\n bridgeTxDetails[transactionId].proofBlockNumber = 0;\n\n emit BridgeProofDisputed(transactionId, msg.sender);\n }\n\n /// @inheritdoc IFastBridge\n function refund(bytes memory request) external {\n bytes32 transactionId = keccak256(request);\n\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n\n if (bridgeTxDetails[transactionId].status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n\n if (hasRole(REFUNDER_ROLE, msg.sender)) {\n // Refunder can refund if deadline has passed\n if (block.timestamp \u003c= transaction.deadline) revert DeadlineNotExceeded();\n } else {\n // Permissionless refund is allowed after REFUND_DELAY\n if (block.timestamp \u003c= transaction.deadline + REFUND_DELAY) revert DeadlineNotExceeded();\n }\n\n // if all checks passed, set to REFUNDED status\n bridgeTxDetails[transactionId].status = BridgeStatus.REFUNDED;\n\n // transfer origin collateral back to original sender\n address to = transaction.originSender;\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount + transaction.originFeeAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (bridgeTxDetails[transactionId].proofRelayer != relayer) revert SenderIncorrect();\n return _timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n /// @dev This method is added to achieve backwards compatibility with decoding requests into V1 structs:\n /// - `callValue` is partially reported as a zero/non-zero flag\n /// - `callParams` is ignored\n /// In order to process all kinds of requests use getBridgeTransactionV2 instead.\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory) {\n // Try decoding into V2 struct first. This will revert if V1 struct is passed\n try this.getBridgeTransactionV2(request) returns (BridgeTransactionV2 memory txV2) {\n // Note: we entirely ignore the callParams field, as it was not present in V1\n return BridgeTransaction({\n originChainId: txV2.originChainId,\n destChainId: txV2.destChainId,\n originSender: txV2.originSender,\n destRecipient: txV2.destRecipient,\n originToken: txV2.originToken,\n destToken: txV2.destToken,\n originAmount: txV2.originAmount,\n destAmount: txV2.destAmount,\n originFeeAmount: txV2.originFeeAmount,\n sendChainGas: txV2.callValue != 0,\n deadline: txV2.deadline,\n nonce: txV2.nonce\n });\n } catch {\n // Fallback to V1 struct\n return abi.decode(request, (BridgeTransaction));\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) public payable {\n int256 exclusivityEndTime = int256(block.timestamp) + paramsV2.quoteExclusivitySeconds;\n _validateBridgeParams(params, paramsV2, exclusivityEndTime);\n\n // transfer tokens to bridge contract\n /// @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _pullToken(params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n\n // set status to requested\n bytes memory request = abi.encode(\n BridgeTransactionV2({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n callValue: paramsV2.callValue,\n deadline: params.deadline,\n nonce: senderNonces[params.sender]++, // increment nonce on every bridge\n exclusivityRelayer: paramsV2.quoteRelayer,\n // We checked exclusivityEndTime to be in range (0 .. params.deadline] above, so can safely cast\n exclusivityEndTime: uint256(exclusivityEndTime),\n callParams: paramsV2.callParams\n })\n );\n bytes32 transactionId = keccak256(request);\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n\n emit BridgeRequested({\n transactionId: transactionId,\n sender: params.sender,\n request: request,\n destChainId: params.dstChainId,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n sendChainGas: paramsV2.callValue != 0\n });\n emit BridgeQuoteDetails(transactionId, paramsV2.quoteId);\n }\n\n /// @inheritdoc IFastBridgeV2\n function relay(bytes memory request, address relayer) public payable {\n bytes32 transactionId = keccak256(request);\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n _validateRelayParams(transaction, transactionId, relayer);\n // mark bridge transaction as relayed\n bridgeRelayDetails[transactionId] =\n BridgeRelay({blockNumber: uint48(block.number), blockTimestamp: uint48(block.timestamp), relayer: relayer});\n\n // transfer tokens to recipient on destination chain and do an arbitrary call if requested\n address to = transaction.destRecipient;\n address token = transaction.destToken;\n uint256 amount = transaction.destAmount;\n\n // All state changes have been done at this point, can proceed to the external calls.\n // This follows the checks-effects-interactions pattern to mitigate potential reentrancy attacks.\n if (token == UniversalTokenLib.ETH_ADDRESS) {\n // For ETH non-zero callValue is not allowed\n if (transaction.callValue != 0) revert NativeTokenCallValueNotSupported();\n // Check that the correct msg.value was sent\n if (msg.value != amount) revert MsgValueIncorrect();\n } else {\n // For ERC20s, we check that the correct msg.value was sent\n if (msg.value != transaction.callValue) revert MsgValueIncorrect();\n // We need to transfer the tokens from the Relayer to the recipient first before performing an\n // optional post-transfer arbitrary call.\n IERC20(token).safeTransferFrom(msg.sender, to, amount);\n }\n\n if (transaction.callParams.length != 0) {\n // Arbitrary call requested, perform it while supplying full msg.value to the recipient\n // Note: if token has a fee on transfers, the recipient will have received less than `amount`.\n // This is a very niche edge case and should be handled by the recipient contract.\n _checkedCallRecipient({recipient: to, token: token, amount: amount, callParams: transaction.callParams});\n } else if (msg.value != 0) {\n // No arbitrary call requested, but msg.value was sent. This is either a relay with ETH,\n // or a non-zero callValue request with an ERC20. In both cases, transfer the ETH to the recipient.\n Address.sendValue(payable(to), msg.value);\n }\n\n emit BridgeRelayed({\n transactionId: transactionId,\n relayer: relayer,\n to: to,\n originChainId: transaction.originChainId,\n originToken: transaction.originToken,\n destToken: transaction.destToken,\n originAmount: transaction.originAmount,\n destAmount: transaction.destAmount,\n chainGasAmount: transaction.callValue\n });\n }\n\n /// @inheritdoc IFastBridgeV2\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) public onlyRole(RELAYER_ROLE) {\n // update bridge tx status given proof provided\n if (bridgeTxDetails[transactionId].status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n bridgeTxDetails[transactionId].status = BridgeStatus.RELAYER_PROVED;\n bridgeTxDetails[transactionId].proofBlockTimestamp = uint40(block.timestamp);\n bridgeTxDetails[transactionId].proofBlockNumber = uint48(block.number);\n bridgeTxDetails[transactionId].proofRelayer = relayer;\n\n emit BridgeProofProvided(transactionId, relayer, destTxHash);\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes memory request, address to) public {\n bytes32 transactionId = keccak256(request);\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n\n // update bridge tx status if able to claim origin collateral\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n\n // if \"to\" is zero addr, permissionlessly send funds to proven relayer\n if (to == address(0)) {\n to = bridgeTxDetails[transactionId].proofRelayer;\n } else if (bridgeTxDetails[transactionId].proofRelayer != msg.sender) {\n revert SenderIncorrect();\n }\n\n if (_timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003c= DISPUTE_PERIOD) {\n revert DisputePeriodNotPassed();\n }\n\n bridgeTxDetails[transactionId].status = BridgeStatus.RELAYER_CLAIMED;\n\n // update protocol fees if origin fee amount exists\n if (transaction.originFeeAmount \u003e 0) protocolFees[transaction.originToken] += transaction.originFeeAmount;\n\n // transfer origin collateral less fee to specified address\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositClaimed(transactionId, bridgeTxDetails[transactionId].proofRelayer, to, token, amount);\n }\n\n function bridgeStatuses(bytes32 transactionId) public view returns (BridgeStatus status) {\n return bridgeTxDetails[transactionId].status;\n }\n\n function bridgeProofs(bytes32 transactionId) public view returns (uint96 timestamp, address relayer) {\n timestamp = bridgeTxDetails[transactionId].proofBlockTimestamp;\n relayer = bridgeTxDetails[transactionId].proofRelayer;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeRelays(bytes32 transactionId) public view returns (bool) {\n // has this transactionId been relayed?\n return bridgeRelayDetails[transactionId].relayer != address(0);\n }\n\n /// @inheritdoc IFastBridgeV2\n function getBridgeTransactionV2(bytes memory request) public pure returns (BridgeTransactionV2 memory) {\n return abi.decode(request, (BridgeTransactionV2));\n }\n\n /// @notice Pulls a requested token from the user to this contract.\n function _pullToken(address token, uint256 amount) internal returns (uint256 amountPulled) {\n if (token == UniversalTokenLib.ETH_ADDRESS) {\n // For ETH we just need to check that the supplied msg.value is correct\n if (amount != msg.value) revert MsgValueIncorrect();\n amountPulled = msg.value;\n } else {\n token.assertIsContract();\n // Record token balance before transfer\n amountPulled = IERC20(token).balanceOf(address(this));\n // Token needs to be pulled only if msg.value is zero\n // This way user can specify WETH as the origin asset\n IERC20(token).safeTransferFrom(msg.sender, address(this), amount);\n // Use the difference between the recorded balance and the current balance as the amountPulled\n amountPulled = IERC20(token).balanceOf(address(this)) - amountPulled;\n }\n }\n\n /// @notice Calls the Recipient's hook function with the specified callParams and performs\n /// all the necessary checks for the returned value.\n function _checkedCallRecipient(\n address recipient,\n address token,\n uint256 amount,\n bytes memory callParams\n )\n internal\n {\n bytes memory hookData =\n abi.encodeCall(IFastBridgeRecipient.fastBridgeTransferReceived, (token, amount, callParams));\n // This will bubble any revert messages from the hook function\n bytes memory returnData = Address.functionCallWithValue({target: recipient, data: hookData, value: msg.value});\n // Explicit revert if no return data at all\n if (returnData.length == 0) revert RecipientNoReturnValue();\n // Check that exactly a single return value was returned\n if (returnData.length != 32) revert RecipientIncorrectReturnValue();\n // Return value should be abi-encoded hook function selector\n if (bytes32(returnData) != bytes32(IFastBridgeRecipient.fastBridgeTransferReceived.selector)) {\n revert RecipientIncorrectReturnValue();\n }\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint40(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint40).max but\n /// proof.timestamp \u003c type(uint40).max via unchecked statement\n /// @param proofBlockTimestamp The bridge proof block timestamp\n /// @return delta Time delta since proof submitted\n function _timeSince(uint40 proofBlockTimestamp) internal view returns (uint256 delta) {\n unchecked {\n delta = uint40(block.timestamp) - proofBlockTimestamp;\n }\n }\n\n /// @notice Performs all the necessary checks for a bridge to happen.\n /// @dev There's no good way to refactor this function to reduce cyclomatic complexity due to\n /// the number of checks that need to be performed, so we skip the code-complexity rule here.\n // solhint-disable-next-line code-complexity\n function _validateBridgeParams(\n BridgeParams memory params,\n BridgeParamsV2 memory paramsV2,\n int256 exclusivityEndTime\n )\n internal\n view\n {\n // Check V1 (legacy) params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.sender == address(0) || params.to == address(0)) revert ZeroAddress();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n // Check V2 params\n if (paramsV2.callParams.length \u003e MAX_CALL_PARAMS_LENGTH) revert CallParamsLengthAboveMax();\n if (paramsV2.callValue != 0 \u0026\u0026 params.destToken == UniversalTokenLib.ETH_ADDRESS) {\n revert NativeTokenCallValueNotSupported();\n }\n // exclusivityEndTime must be in range (0 .. params.deadline]\n if (exclusivityEndTime \u003c= 0 || exclusivityEndTime \u003e int256(params.deadline)) {\n revert ExclusivityParamsIncorrect();\n }\n }\n\n /// @notice Performs all the necessary checks for a relay to happen.\n function _validateRelayParams(\n BridgeTransactionV2 memory transaction,\n bytes32 transactionId,\n address relayer\n )\n internal\n view\n {\n if (relayer == address(0)) revert ZeroAddress();\n // Check if the transaction has already been relayed\n if (bridgeRelays(transactionId)) revert TransactionRelayed();\n if (transaction.destChainId != uint32(block.chainid)) revert ChainIncorrect();\n // Check the deadline for relay to happen\n if (block.timestamp \u003e transaction.deadline) revert DeadlineExceeded();\n // Check the exclusivity period, if it is still ongoing\n // forgefmt: disable-next-item\n if (\n transaction.exclusivityRelayer != address(0) \u0026\u0026\n transaction.exclusivityRelayer != relayer \u0026\u0026\n block.timestamp \u003c= transaction.exclusivityEndTime\n ) {\n revert ExclusivityPeriodNotPassed();\n }\n }\n}\n","language":"Solidity","languageVersion":"0.8.24","compilerVersion":"0.8.24","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../","srcMap":"","srcMapRuntime":"","abiDefinition":[{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"relayer","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"BridgeDepositClaimed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"BridgeDepositRefunded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"relayer","type":"address"}],"name":"BridgeProofDisputed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"relayer","type":"address"},{"indexed":false,"internalType":"bytes32","name":"transactionHash","type":"bytes32"}],"name":"BridgeProofProvided","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"relayer","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint32","name":"originChainId","type":"uint32"},{"indexed":false,"internalType":"address","name":"originToken","type":"address"},{"indexed":false,"internalType":"address","name":"destToken","type":"address"},{"indexed":false,"internalType":"uint256","name":"originAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"destAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"chainGasAmount","type":"uint256"}],"name":"BridgeRelayed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"bytes","name":"request","type":"bytes"},{"indexed":false,"internalType":"uint32","name":"destChainId","type":"uint32"},{"indexed":false,"internalType":"address","name":"originToken","type":"address"},{"indexed":false,"internalType":"address","name":"destToken","type":"address"},{"indexed":false,"internalType":"uint256","name":"originAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"destAmount","type":"uint256"},{"indexed":false,"internalType":"bool","name":"sendChainGas","type":"bool"}],"name":"BridgeRequested","type":"event"},{"inputs":[{"components":[{"internalType":"uint32","name":"dstChainId","type":"uint32"},{"internalType":"address","name":"sender","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"address","name":"originToken","type":"address"},{"internalType":"address","name":"destToken","type":"address"},{"internalType":"uint256","name":"originAmount","type":"uint256"},{"internalType":"uint256","name":"destAmount","type":"uint256"},{"internalType":"bool","name":"sendChainGas","type":"bool"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"internalType":"struct IFastBridge.BridgeParams","name":"params","type":"tuple"}],"name":"bridge","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"internalType":"address","name":"relayer","type":"address"}],"name":"canClaim","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"},{"internalType":"address","name":"to","type":"address"}],"name":"claim","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"transactionId","type":"bytes32"}],"name":"dispute","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"}],"name":"getBridgeTransaction","outputs":[{"components":[{"internalType":"uint32","name":"originChainId","type":"uint32"},{"internalType":"uint32","name":"destChainId","type":"uint32"},{"internalType":"address","name":"originSender","type":"address"},{"internalType":"address","name":"destRecipient","type":"address"},{"internalType":"address","name":"originToken","type":"address"},{"internalType":"address","name":"destToken","type":"address"},{"internalType":"uint256","name":"originAmount","type":"uint256"},{"internalType":"uint256","name":"destAmount","type":"uint256"},{"internalType":"uint256","name":"originFeeAmount","type":"uint256"},{"internalType":"bool","name":"sendChainGas","type":"bool"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint256","name":"nonce","type":"uint256"}],"internalType":"struct IFastBridge.BridgeTransaction","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"},{"internalType":"bytes32","name":"destTxHash","type":"bytes32"}],"name":"prove","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"}],"name":"refund","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"}],"name":"relay","outputs":[],"stateMutability":"payable","type":"function"}],"userDoc":{"kind":"user","methods":{"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256))":{"notice":"Initiates bridge on origin chain to be relayed by off-chain relayer"},"canClaim(bytes32,address)":{"notice":"Checks if the dispute period has passed so bridge deposit can be claimed"},"claim(bytes,address)":{"notice":"Completes bridge transaction on origin chain by claiming originally deposited capital"},"dispute(bytes32)":{"notice":"Disputes an outstanding proof in case relayer provided dest chain tx is invalid"},"getBridgeTransaction(bytes)":{"notice":"Decodes bridge request into a bridge transaction"},"prove(bytes,bytes32)":{"notice":"Provides proof on origin side that relayer provided funds on destination side of bridge transaction"},"refund(bytes)":{"notice":"Refunds an outstanding bridge transaction in case optimistic bridging failed"},"relay(bytes)":{"notice":"Relays destination side of bridge transaction by off-chain relayer"}},"version":1},"developerDoc":{"kind":"dev","methods":{"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256))":{"params":{"params":"The parameters required to bridge"}},"canClaim(bytes32,address)":{"params":{"relayer":"The address of the relayer attempting to claim","transactionId":"The transaction id associated with the encoded bridge transaction to check"}},"claim(bytes,address)":{"params":{"request":"The encoded bridge transaction to claim on origin chain","to":"The recipient address of the funds"}},"dispute(bytes32)":{"params":{"transactionId":"The transaction id associated with the encoded bridge transaction to dispute"}},"getBridgeTransaction(bytes)":{"params":{"request":"The bridge request to decode"}},"prove(bytes,bytes32)":{"params":{"destTxHash":"The destination tx hash proving bridge transaction was relayed","request":"The encoded bridge transaction to prove on origin chain"}},"refund(bytes)":{"params":{"request":"The encoded bridge transaction to refund"}},"relay(bytes)":{"params":{"request":"The encoded bridge transaction to relay on destination chain"}}},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"BridgeDepositClaimed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"BridgeDepositRefunded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"name\":\"BridgeProofDisputed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"transactionHash\",\"type\":\"bytes32\"}],\"name\":\"BridgeProofProvided\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"originChainId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"chainGasAmount\",\"type\":\"uint256\"}],\"name\":\"BridgeRelayed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"destChainId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"sendChainGas\",\"type\":\"bool\"}],\"name\":\"BridgeRequested\",\"type\":\"event\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"dstChainId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"sendChainGas\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"}],\"internalType\":\"struct IFastBridge.BridgeParams\",\"name\":\"params\",\"type\":\"tuple\"}],\"name\":\"bridge\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"name\":\"canClaim\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"claim\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"}],\"name\":\"dispute\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"getBridgeTransaction\",\"outputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"originChainId\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"destChainId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"originSender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destRecipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"originFeeAmount\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"sendChainGas\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"}],\"internalType\":\"struct IFastBridge.BridgeTransaction\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"},{\"internalType\":\"bytes32\",\"name\":\"destTxHash\",\"type\":\"bytes32\"}],\"name\":\"prove\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"refund\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"relay\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{\"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256))\":{\"params\":{\"params\":\"The parameters required to bridge\"}},\"canClaim(bytes32,address)\":{\"params\":{\"relayer\":\"The address of the relayer attempting to claim\",\"transactionId\":\"The transaction id associated with the encoded bridge transaction to check\"}},\"claim(bytes,address)\":{\"params\":{\"request\":\"The encoded bridge transaction to claim on origin chain\",\"to\":\"The recipient address of the funds\"}},\"dispute(bytes32)\":{\"params\":{\"transactionId\":\"The transaction id associated with the encoded bridge transaction to dispute\"}},\"getBridgeTransaction(bytes)\":{\"params\":{\"request\":\"The bridge request to decode\"}},\"prove(bytes,bytes32)\":{\"params\":{\"destTxHash\":\"The destination tx hash proving bridge transaction was relayed\",\"request\":\"The encoded bridge transaction to prove on origin chain\"}},\"refund(bytes)\":{\"params\":{\"request\":\"The encoded bridge transaction to refund\"}},\"relay(bytes)\":{\"params\":{\"request\":\"The encoded bridge transaction to relay on destination chain\"}}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256))\":{\"notice\":\"Initiates bridge on origin chain to be relayed by off-chain relayer\"},\"canClaim(bytes32,address)\":{\"notice\":\"Checks if the dispute period has passed so bridge deposit can be claimed\"},\"claim(bytes,address)\":{\"notice\":\"Completes bridge transaction on origin chain by claiming originally deposited capital\"},\"dispute(bytes32)\":{\"notice\":\"Disputes an outstanding proof in case relayer provided dest chain tx is invalid\"},\"getBridgeTransaction(bytes)\":{\"notice\":\"Decodes bridge request into a bridge transaction\"},\"prove(bytes,bytes32)\":{\"notice\":\"Provides proof on origin side that relayer provided funds on destination side of bridge transaction\"},\"refund(bytes)\":{\"notice\":\"Refunds an outstanding bridge transaction in case optimistic bridging failed\"},\"relay(bytes)\":{\"notice\":\"Relays destination side of bridge transaction by off-chain relayer\"}},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeV2.sol\":\"IFastBridge\"},\"evmVersion\":\"shanghai\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeV2.sol\":{\"keccak256\":\"0x7cd0f885e80e2bdaa638bc32ae7af7d2e248f99ce4b354c217d0f0f7d7302e0a\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://7ccf28df0bd7b4606986585acd8622ed9b4e81379690061bb66088f0a2270af1\",\"dweb:/ipfs/QmTf7HNdHZkK6vmx8ZgewycQEb72oLD9nPwBpsM5reMstQ\"]}},\"version\":1}"},"hashes":{"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256))":"45851694","canClaim(bytes32,address)":"aa9641ab","claim(bytes,address)":"41fcb612","dispute(bytes32)":"add98c70","getBridgeTransaction(bytes)":"ac11fb1a","prove(bytes,bytes32)":"886d36ff","refund(bytes)":"5eb7d946","relay(bytes)":"8f0d6f17"}},"solidity/FastBridgeV2.sol:IFastBridgeRecipient":{"code":"0x","runtime-code":"0x","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.24 ^0.8.0 ^0.8.20;\n\n// contracts/interfaces/IAdmin.sol\n\ninterface IAdmin {\n // ============ Events ============\n\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n event ChainGasAmountUpdated(uint256 oldChainGasAmount, uint256 newChainGasAmount);\n\n // ============ Methods ============\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n\n function setChainGasAmount(uint256 newChainGasAmount) external;\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IFastBridgeRecipient.sol\n\ninterface IFastBridgeRecipient {\n function fastBridgeTransferReceived(\n address token,\n uint256 amount,\n bytes memory callParams\n )\n external\n payable\n returns (bytes4);\n}\n\n// contracts/interfaces/IFastBridgeV2Errors.sol\n\ninterface IFastBridgeV2Errors {\n error AmountIncorrect();\n error CallParamsLengthAboveMax();\n error ChainIncorrect();\n error ExclusivityParamsIncorrect();\n error MsgValueIncorrect();\n error NativeTokenCallValueNotSupported();\n error SenderIncorrect();\n error StatusIncorrect();\n error ZeroAddress();\n\n error RecipientIncorrectReturnValue();\n error RecipientNoReturnValue();\n\n error DeadlineExceeded();\n error DeadlineNotExceeded();\n error DeadlineTooShort();\n error DisputePeriodNotPassed();\n error DisputePeriodPassed();\n error ExclusivityPeriodNotPassed();\n\n error TransactionRelayed();\n}\n\n// contracts/libs/Errors.sol\n\nerror DeadlineExceeded();\nerror DeadlineNotExceeded();\nerror DeadlineTooShort();\nerror InsufficientOutputAmount();\n\nerror MsgValueIncorrect();\nerror PoolNotFound();\nerror TokenAddressMismatch();\nerror TokenNotContract();\nerror TokenNotETH();\nerror TokensIdentical();\n\nerror ChainIncorrect();\nerror AmountIncorrect();\nerror ZeroAddress();\n\nerror DisputePeriodNotPassed();\nerror DisputePeriodPassed();\nerror SenderIncorrect();\nerror StatusIncorrect();\nerror TransactionIdIncorrect();\nerror TransactionRelayed();\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// contracts/interfaces/IFastBridgeV2.sol\n\ninterface IFastBridgeV2 is IFastBridge {\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n struct BridgeTxDetails {\n BridgeStatus status;\n uint40 proofBlockTimestamp;\n uint48 proofBlockNumber;\n address proofRelayer;\n }\n\n struct BridgeRelay {\n uint48 blockNumber;\n uint48 blockTimestamp;\n address relayer;\n }\n\n /// @notice New params introduced in the FastBridgeV2.\n /// We are passing fields from the older BridgeParams struct outside of this struct\n /// for backwards compatibility.\n /// Note: quoteRelayer and quoteExclusivitySeconds are either both zero (indicating no exclusivity)\n /// or both non-zero (indicating exclusivity for the given period).\n /// Note: callValue \u003e 0 can NOT be used with destToken = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE (ETH_ADDRESS)\n /// @param quoteRelayer Relayer that provided the quote for the transaction\n /// @param quoteExclusivitySeconds Period of time the quote relayer is guaranteed exclusivity after user's deposit\n /// @param quoteId Unique quote identifier used for tracking the quote\n /// @param callValue ETH value to send to the recipient (if any)\n /// @param callParams Parameters for the arbitrary call to the destination recipient (if any)\n struct BridgeParamsV2 {\n address quoteRelayer;\n int256 quoteExclusivitySeconds;\n bytes quoteId;\n uint256 callValue;\n bytes callParams;\n }\n\n /// @notice Updated bridge transaction struct to include parameters introduced in FastBridgeV2.\n /// Note: only `exclusivityRelayer` can fill such a transaction until `exclusivityEndTime`.\n /// TODO: consider changing the encoding scheme to prevent spending extra gas on decoding.\n struct BridgeTransactionV2 {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n uint256 callValue; // ETH value to send to the recipient (if any) - replaces V1's sendChainGas flag\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n address exclusivityRelayer;\n uint256 exclusivityEndTime;\n bytes callParams;\n }\n\n event BridgeQuoteDetails(bytes32 indexed transactionId, bytes quoteId);\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability\n /// to provide temporary exclusivity fill rights for the quote relayer.\n /// @param params The parameters required to bridge\n /// @param paramsV2 The parameters for exclusivity fill rights (optional, can be left empty)\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function relay(bytes memory request, address relayer) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param transactionId The transaction id associated with the encoded bridge transaction to prove\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital.\n /// @notice Can only send funds to the relayer address on the proof.\n /// @param request The encoded bridge transaction to claim on origin chain\n function claim(bytes memory request) external;\n /// @notice Checks if a transaction has been relayed\n /// @param transactionId The ID of the transaction to check\n /// @return True if the transaction has been relayed, false otherwise\n function bridgeRelays(bytes32 transactionId) external view returns (bool);\n\n /// @notice Returns the status of a bridge transaction\n /// @param transactionId The ID of the bridge transaction\n /// @return BridgeStatus Status of the bridge transaction\n function bridgeStatuses(bytes32 transactionId) external view returns (BridgeStatus);\n\n /// @notice Returns the timestamp and relayer of a bridge proof\n /// @param transactionId The ID of the bridge transaction\n /// @return timestamp The timestamp of the bridge proof\n /// @return relayer The relayer address of the bridge proof\n function bridgeProofs(bytes32 transactionId) external view returns (uint96 timestamp, address relayer);\n\n /// @notice Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\n /// @param request The bridge request to decode\n function getBridgeTransactionV2(bytes memory request) external view returns (BridgeTransactionV2 memory);\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// contracts/libs/UniversalToken.sol\n\nlibrary UniversalTokenLib {\n using SafeERC20 for IERC20;\n\n address internal constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Transfers tokens to the given account. Reverts if transfer is not successful.\n /// @dev This might trigger fallback, if ETH is transferred to the contract.\n /// Make sure this can not lead to reentrancy attacks.\n function universalTransfer(address token, address to, uint256 value) internal {\n // Don't do anything, if need to send tokens to this address\n if (to == address(this)) return;\n // Don't do anything, if trying to send zero value\n if (value == 0) return;\n if (token == ETH_ADDRESS) {\n /// @dev Note: this can potentially lead to executing code in `to`.\n // solhint-disable-next-line avoid-low-level-calls\n (bool success,) = to.call{value: value}(\"\");\n require(success, \"ETH transfer failed\");\n } else {\n IERC20(token).safeTransfer(to, value);\n }\n }\n\n /// @notice Issues an infinite allowance to the spender, if the current allowance is insufficient\n /// to spend the given amount.\n function universalApproveInfinity(address token, address spender, uint256 amountToSpend) internal {\n // ETH Chad doesn't require your approval\n if (token == ETH_ADDRESS) return;\n // No-op if allowance is already sufficient\n uint256 allowance = IERC20(token).allowance(address(this), spender);\n if (allowance \u003e= amountToSpend) return;\n // Otherwise, reset approval to 0 and set to max allowance\n if (allowance \u003e 0) IERC20(token).safeDecreaseAllowance(spender, allowance);\n IERC20(token).safeIncreaseAllowance(spender, type(uint256).max);\n }\n\n /// @notice Returns the balance of the given token (or native ETH) for the given account.\n function universalBalanceOf(address token, address account) internal view returns (uint256) {\n if (token == ETH_ADDRESS) {\n return account.balance;\n } else {\n return IERC20(token).balanceOf(account);\n }\n }\n\n /// @dev Checks that token is a contract and not ETH_ADDRESS.\n function assertIsContract(address token) internal view {\n // Check that ETH_ADDRESS was not used (in case this is a predeploy on any of the chains)\n if (token == UniversalTokenLib.ETH_ADDRESS) revert TokenNotContract();\n // Check that token is not an EOA\n if (token.code.length == 0) revert TokenNotContract();\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/Admin.sol\n\ncontract Admin is IAdmin, AccessControlEnumerable {\n using UniversalTokenLib for address;\n\n bytes32 public constant RELAYER_ROLE = keccak256(\"RELAYER_ROLE\");\n bytes32 public constant REFUNDER_ROLE = keccak256(\"REFUNDER_ROLE\");\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n uint256 public constant FEE_BPS = 1e6;\n uint256 public constant FEE_RATE_MAX = 0.01e6; // max 1% on origin amount\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Chain gas amount to forward as rebate if requested\n uint256 public chainGasAmount;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n }\n\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n require(newFeeRate \u003c= FEE_RATE_MAX, \"newFeeRate \u003e max\");\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n token.universalTransfer(recipient, feeAmount);\n emit FeesSwept(token, recipient, feeAmount);\n }\n\n function setChainGasAmount(uint256 newChainGasAmount) external onlyRole(GOVERNOR_ROLE) {\n uint256 oldChainGasAmount = chainGasAmount;\n chainGasAmount = newChainGasAmount;\n emit ChainGasAmountUpdated(oldChainGasAmount, newChainGasAmount);\n }\n}\n\n// contracts/FastBridgeV2.sol\n\n/// @notice FastBridgeV2 is a contract for bridging tokens across chains.\ncontract FastBridgeV2 is Admin, IFastBridgeV2, IFastBridgeV2Errors {\n using SafeERC20 for IERC20;\n using UniversalTokenLib for address;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Delay for a transaction after which it could be permisionlessly refunded\n uint256 public constant REFUND_DELAY = 7 days;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n /// @notice Maximum length of accepted callParams\n uint256 public constant MAX_CALL_PARAMS_LENGTH = 2 ** 16 - 1;\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeTxDetails) public bridgeTxDetails;\n /// @notice Relay details on destination chain\n mapping(bytes32 =\u003e BridgeRelay) public bridgeRelayDetails;\n /// @notice Unique bridge nonces tracked per originSender\n mapping(address =\u003e uint256) public senderNonces;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Replaced by senderNonces\n uint256 public immutable nonce = 0;\n /// @notice the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n bridge({\n params: params,\n paramsV2: BridgeParamsV2({\n quoteRelayer: address(0),\n quoteExclusivitySeconds: 0,\n quoteId: bytes(\"\"),\n callValue: 0,\n callParams: bytes(\"\")\n })\n });\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes memory request) external payable {\n relay({request: request, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes memory request, bytes32 destTxHash) external {\n prove({transactionId: keccak256(request), destTxHash: destTxHash, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridgeV2\n function claim(bytes memory request) external {\n claim({request: request, to: address(0)});\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003e DISPUTE_PERIOD) {\n revert DisputePeriodPassed();\n }\n\n // @dev relayer gets slashed effectively if dest relay has gone thru\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n bridgeTxDetails[transactionId].proofRelayer = address(0);\n bridgeTxDetails[transactionId].proofBlockTimestamp = 0;\n bridgeTxDetails[transactionId].proofBlockNumber = 0;\n\n emit BridgeProofDisputed(transactionId, msg.sender);\n }\n\n /// @inheritdoc IFastBridge\n function refund(bytes memory request) external {\n bytes32 transactionId = keccak256(request);\n\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n\n if (bridgeTxDetails[transactionId].status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n\n if (hasRole(REFUNDER_ROLE, msg.sender)) {\n // Refunder can refund if deadline has passed\n if (block.timestamp \u003c= transaction.deadline) revert DeadlineNotExceeded();\n } else {\n // Permissionless refund is allowed after REFUND_DELAY\n if (block.timestamp \u003c= transaction.deadline + REFUND_DELAY) revert DeadlineNotExceeded();\n }\n\n // if all checks passed, set to REFUNDED status\n bridgeTxDetails[transactionId].status = BridgeStatus.REFUNDED;\n\n // transfer origin collateral back to original sender\n address to = transaction.originSender;\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount + transaction.originFeeAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (bridgeTxDetails[transactionId].proofRelayer != relayer) revert SenderIncorrect();\n return _timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n /// @dev This method is added to achieve backwards compatibility with decoding requests into V1 structs:\n /// - `callValue` is partially reported as a zero/non-zero flag\n /// - `callParams` is ignored\n /// In order to process all kinds of requests use getBridgeTransactionV2 instead.\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory) {\n // Try decoding into V2 struct first. This will revert if V1 struct is passed\n try this.getBridgeTransactionV2(request) returns (BridgeTransactionV2 memory txV2) {\n // Note: we entirely ignore the callParams field, as it was not present in V1\n return BridgeTransaction({\n originChainId: txV2.originChainId,\n destChainId: txV2.destChainId,\n originSender: txV2.originSender,\n destRecipient: txV2.destRecipient,\n originToken: txV2.originToken,\n destToken: txV2.destToken,\n originAmount: txV2.originAmount,\n destAmount: txV2.destAmount,\n originFeeAmount: txV2.originFeeAmount,\n sendChainGas: txV2.callValue != 0,\n deadline: txV2.deadline,\n nonce: txV2.nonce\n });\n } catch {\n // Fallback to V1 struct\n return abi.decode(request, (BridgeTransaction));\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) public payable {\n int256 exclusivityEndTime = int256(block.timestamp) + paramsV2.quoteExclusivitySeconds;\n _validateBridgeParams(params, paramsV2, exclusivityEndTime);\n\n // transfer tokens to bridge contract\n /// @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _pullToken(params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n\n // set status to requested\n bytes memory request = abi.encode(\n BridgeTransactionV2({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n callValue: paramsV2.callValue,\n deadline: params.deadline,\n nonce: senderNonces[params.sender]++, // increment nonce on every bridge\n exclusivityRelayer: paramsV2.quoteRelayer,\n // We checked exclusivityEndTime to be in range (0 .. params.deadline] above, so can safely cast\n exclusivityEndTime: uint256(exclusivityEndTime),\n callParams: paramsV2.callParams\n })\n );\n bytes32 transactionId = keccak256(request);\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n\n emit BridgeRequested({\n transactionId: transactionId,\n sender: params.sender,\n request: request,\n destChainId: params.dstChainId,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n sendChainGas: paramsV2.callValue != 0\n });\n emit BridgeQuoteDetails(transactionId, paramsV2.quoteId);\n }\n\n /// @inheritdoc IFastBridgeV2\n function relay(bytes memory request, address relayer) public payable {\n bytes32 transactionId = keccak256(request);\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n _validateRelayParams(transaction, transactionId, relayer);\n // mark bridge transaction as relayed\n bridgeRelayDetails[transactionId] =\n BridgeRelay({blockNumber: uint48(block.number), blockTimestamp: uint48(block.timestamp), relayer: relayer});\n\n // transfer tokens to recipient on destination chain and do an arbitrary call if requested\n address to = transaction.destRecipient;\n address token = transaction.destToken;\n uint256 amount = transaction.destAmount;\n\n // All state changes have been done at this point, can proceed to the external calls.\n // This follows the checks-effects-interactions pattern to mitigate potential reentrancy attacks.\n if (token == UniversalTokenLib.ETH_ADDRESS) {\n // For ETH non-zero callValue is not allowed\n if (transaction.callValue != 0) revert NativeTokenCallValueNotSupported();\n // Check that the correct msg.value was sent\n if (msg.value != amount) revert MsgValueIncorrect();\n } else {\n // For ERC20s, we check that the correct msg.value was sent\n if (msg.value != transaction.callValue) revert MsgValueIncorrect();\n // We need to transfer the tokens from the Relayer to the recipient first before performing an\n // optional post-transfer arbitrary call.\n IERC20(token).safeTransferFrom(msg.sender, to, amount);\n }\n\n if (transaction.callParams.length != 0) {\n // Arbitrary call requested, perform it while supplying full msg.value to the recipient\n // Note: if token has a fee on transfers, the recipient will have received less than `amount`.\n // This is a very niche edge case and should be handled by the recipient contract.\n _checkedCallRecipient({recipient: to, token: token, amount: amount, callParams: transaction.callParams});\n } else if (msg.value != 0) {\n // No arbitrary call requested, but msg.value was sent. This is either a relay with ETH,\n // or a non-zero callValue request with an ERC20. In both cases, transfer the ETH to the recipient.\n Address.sendValue(payable(to), msg.value);\n }\n\n emit BridgeRelayed({\n transactionId: transactionId,\n relayer: relayer,\n to: to,\n originChainId: transaction.originChainId,\n originToken: transaction.originToken,\n destToken: transaction.destToken,\n originAmount: transaction.originAmount,\n destAmount: transaction.destAmount,\n chainGasAmount: transaction.callValue\n });\n }\n\n /// @inheritdoc IFastBridgeV2\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) public onlyRole(RELAYER_ROLE) {\n // update bridge tx status given proof provided\n if (bridgeTxDetails[transactionId].status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n bridgeTxDetails[transactionId].status = BridgeStatus.RELAYER_PROVED;\n bridgeTxDetails[transactionId].proofBlockTimestamp = uint40(block.timestamp);\n bridgeTxDetails[transactionId].proofBlockNumber = uint48(block.number);\n bridgeTxDetails[transactionId].proofRelayer = relayer;\n\n emit BridgeProofProvided(transactionId, relayer, destTxHash);\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes memory request, address to) public {\n bytes32 transactionId = keccak256(request);\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n\n // update bridge tx status if able to claim origin collateral\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n\n // if \"to\" is zero addr, permissionlessly send funds to proven relayer\n if (to == address(0)) {\n to = bridgeTxDetails[transactionId].proofRelayer;\n } else if (bridgeTxDetails[transactionId].proofRelayer != msg.sender) {\n revert SenderIncorrect();\n }\n\n if (_timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003c= DISPUTE_PERIOD) {\n revert DisputePeriodNotPassed();\n }\n\n bridgeTxDetails[transactionId].status = BridgeStatus.RELAYER_CLAIMED;\n\n // update protocol fees if origin fee amount exists\n if (transaction.originFeeAmount \u003e 0) protocolFees[transaction.originToken] += transaction.originFeeAmount;\n\n // transfer origin collateral less fee to specified address\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositClaimed(transactionId, bridgeTxDetails[transactionId].proofRelayer, to, token, amount);\n }\n\n function bridgeStatuses(bytes32 transactionId) public view returns (BridgeStatus status) {\n return bridgeTxDetails[transactionId].status;\n }\n\n function bridgeProofs(bytes32 transactionId) public view returns (uint96 timestamp, address relayer) {\n timestamp = bridgeTxDetails[transactionId].proofBlockTimestamp;\n relayer = bridgeTxDetails[transactionId].proofRelayer;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeRelays(bytes32 transactionId) public view returns (bool) {\n // has this transactionId been relayed?\n return bridgeRelayDetails[transactionId].relayer != address(0);\n }\n\n /// @inheritdoc IFastBridgeV2\n function getBridgeTransactionV2(bytes memory request) public pure returns (BridgeTransactionV2 memory) {\n return abi.decode(request, (BridgeTransactionV2));\n }\n\n /// @notice Pulls a requested token from the user to this contract.\n function _pullToken(address token, uint256 amount) internal returns (uint256 amountPulled) {\n if (token == UniversalTokenLib.ETH_ADDRESS) {\n // For ETH we just need to check that the supplied msg.value is correct\n if (amount != msg.value) revert MsgValueIncorrect();\n amountPulled = msg.value;\n } else {\n token.assertIsContract();\n // Record token balance before transfer\n amountPulled = IERC20(token).balanceOf(address(this));\n // Token needs to be pulled only if msg.value is zero\n // This way user can specify WETH as the origin asset\n IERC20(token).safeTransferFrom(msg.sender, address(this), amount);\n // Use the difference between the recorded balance and the current balance as the amountPulled\n amountPulled = IERC20(token).balanceOf(address(this)) - amountPulled;\n }\n }\n\n /// @notice Calls the Recipient's hook function with the specified callParams and performs\n /// all the necessary checks for the returned value.\n function _checkedCallRecipient(\n address recipient,\n address token,\n uint256 amount,\n bytes memory callParams\n )\n internal\n {\n bytes memory hookData =\n abi.encodeCall(IFastBridgeRecipient.fastBridgeTransferReceived, (token, amount, callParams));\n // This will bubble any revert messages from the hook function\n bytes memory returnData = Address.functionCallWithValue({target: recipient, data: hookData, value: msg.value});\n // Explicit revert if no return data at all\n if (returnData.length == 0) revert RecipientNoReturnValue();\n // Check that exactly a single return value was returned\n if (returnData.length != 32) revert RecipientIncorrectReturnValue();\n // Return value should be abi-encoded hook function selector\n if (bytes32(returnData) != bytes32(IFastBridgeRecipient.fastBridgeTransferReceived.selector)) {\n revert RecipientIncorrectReturnValue();\n }\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint40(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint40).max but\n /// proof.timestamp \u003c type(uint40).max via unchecked statement\n /// @param proofBlockTimestamp The bridge proof block timestamp\n /// @return delta Time delta since proof submitted\n function _timeSince(uint40 proofBlockTimestamp) internal view returns (uint256 delta) {\n unchecked {\n delta = uint40(block.timestamp) - proofBlockTimestamp;\n }\n }\n\n /// @notice Performs all the necessary checks for a bridge to happen.\n /// @dev There's no good way to refactor this function to reduce cyclomatic complexity due to\n /// the number of checks that need to be performed, so we skip the code-complexity rule here.\n // solhint-disable-next-line code-complexity\n function _validateBridgeParams(\n BridgeParams memory params,\n BridgeParamsV2 memory paramsV2,\n int256 exclusivityEndTime\n )\n internal\n view\n {\n // Check V1 (legacy) params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.sender == address(0) || params.to == address(0)) revert ZeroAddress();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n // Check V2 params\n if (paramsV2.callParams.length \u003e MAX_CALL_PARAMS_LENGTH) revert CallParamsLengthAboveMax();\n if (paramsV2.callValue != 0 \u0026\u0026 params.destToken == UniversalTokenLib.ETH_ADDRESS) {\n revert NativeTokenCallValueNotSupported();\n }\n // exclusivityEndTime must be in range (0 .. params.deadline]\n if (exclusivityEndTime \u003c= 0 || exclusivityEndTime \u003e int256(params.deadline)) {\n revert ExclusivityParamsIncorrect();\n }\n }\n\n /// @notice Performs all the necessary checks for a relay to happen.\n function _validateRelayParams(\n BridgeTransactionV2 memory transaction,\n bytes32 transactionId,\n address relayer\n )\n internal\n view\n {\n if (relayer == address(0)) revert ZeroAddress();\n // Check if the transaction has already been relayed\n if (bridgeRelays(transactionId)) revert TransactionRelayed();\n if (transaction.destChainId != uint32(block.chainid)) revert ChainIncorrect();\n // Check the deadline for relay to happen\n if (block.timestamp \u003e transaction.deadline) revert DeadlineExceeded();\n // Check the exclusivity period, if it is still ongoing\n // forgefmt: disable-next-item\n if (\n transaction.exclusivityRelayer != address(0) \u0026\u0026\n transaction.exclusivityRelayer != relayer \u0026\u0026\n block.timestamp \u003c= transaction.exclusivityEndTime\n ) {\n revert ExclusivityPeriodNotPassed();\n }\n }\n}\n","language":"Solidity","languageVersion":"0.8.24","compilerVersion":"0.8.24","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../","srcMap":"","srcMapRuntime":"","abiDefinition":[{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"bytes","name":"callParams","type":"bytes"}],"name":"fastBridgeTransferReceived","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"payable","type":"function"}],"userDoc":{"kind":"user","methods":{},"version":1},"developerDoc":{"kind":"dev","methods":{},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"callParams\",\"type\":\"bytes\"}],\"name\":\"fastBridgeTransferReceived\",\"outputs\":[{\"internalType\":\"bytes4\",\"name\":\"\",\"type\":\"bytes4\"}],\"stateMutability\":\"payable\",\"type\":\"function\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeV2.sol\":\"IFastBridgeRecipient\"},\"evmVersion\":\"shanghai\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeV2.sol\":{\"keccak256\":\"0x7cd0f885e80e2bdaa638bc32ae7af7d2e248f99ce4b354c217d0f0f7d7302e0a\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://7ccf28df0bd7b4606986585acd8622ed9b4e81379690061bb66088f0a2270af1\",\"dweb:/ipfs/QmTf7HNdHZkK6vmx8ZgewycQEb72oLD9nPwBpsM5reMstQ\"]}},\"version\":1}"},"hashes":{"fastBridgeTransferReceived(address,uint256,bytes)":"461e0c21"}},"solidity/FastBridgeV2.sol:IFastBridgeV2":{"code":"0x","runtime-code":"0x","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.24 ^0.8.0 ^0.8.20;\n\n// contracts/interfaces/IAdmin.sol\n\ninterface IAdmin {\n // ============ Events ============\n\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n event ChainGasAmountUpdated(uint256 oldChainGasAmount, uint256 newChainGasAmount);\n\n // ============ Methods ============\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n\n function setChainGasAmount(uint256 newChainGasAmount) external;\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IFastBridgeRecipient.sol\n\ninterface IFastBridgeRecipient {\n function fastBridgeTransferReceived(\n address token,\n uint256 amount,\n bytes memory callParams\n )\n external\n payable\n returns (bytes4);\n}\n\n// contracts/interfaces/IFastBridgeV2Errors.sol\n\ninterface IFastBridgeV2Errors {\n error AmountIncorrect();\n error CallParamsLengthAboveMax();\n error ChainIncorrect();\n error ExclusivityParamsIncorrect();\n error MsgValueIncorrect();\n error NativeTokenCallValueNotSupported();\n error SenderIncorrect();\n error StatusIncorrect();\n error ZeroAddress();\n\n error RecipientIncorrectReturnValue();\n error RecipientNoReturnValue();\n\n error DeadlineExceeded();\n error DeadlineNotExceeded();\n error DeadlineTooShort();\n error DisputePeriodNotPassed();\n error DisputePeriodPassed();\n error ExclusivityPeriodNotPassed();\n\n error TransactionRelayed();\n}\n\n// contracts/libs/Errors.sol\n\nerror DeadlineExceeded();\nerror DeadlineNotExceeded();\nerror DeadlineTooShort();\nerror InsufficientOutputAmount();\n\nerror MsgValueIncorrect();\nerror PoolNotFound();\nerror TokenAddressMismatch();\nerror TokenNotContract();\nerror TokenNotETH();\nerror TokensIdentical();\n\nerror ChainIncorrect();\nerror AmountIncorrect();\nerror ZeroAddress();\n\nerror DisputePeriodNotPassed();\nerror DisputePeriodPassed();\nerror SenderIncorrect();\nerror StatusIncorrect();\nerror TransactionIdIncorrect();\nerror TransactionRelayed();\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// contracts/interfaces/IFastBridgeV2.sol\n\ninterface IFastBridgeV2 is IFastBridge {\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n struct BridgeTxDetails {\n BridgeStatus status;\n uint40 proofBlockTimestamp;\n uint48 proofBlockNumber;\n address proofRelayer;\n }\n\n struct BridgeRelay {\n uint48 blockNumber;\n uint48 blockTimestamp;\n address relayer;\n }\n\n /// @notice New params introduced in the FastBridgeV2.\n /// We are passing fields from the older BridgeParams struct outside of this struct\n /// for backwards compatibility.\n /// Note: quoteRelayer and quoteExclusivitySeconds are either both zero (indicating no exclusivity)\n /// or both non-zero (indicating exclusivity for the given period).\n /// Note: callValue \u003e 0 can NOT be used with destToken = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE (ETH_ADDRESS)\n /// @param quoteRelayer Relayer that provided the quote for the transaction\n /// @param quoteExclusivitySeconds Period of time the quote relayer is guaranteed exclusivity after user's deposit\n /// @param quoteId Unique quote identifier used for tracking the quote\n /// @param callValue ETH value to send to the recipient (if any)\n /// @param callParams Parameters for the arbitrary call to the destination recipient (if any)\n struct BridgeParamsV2 {\n address quoteRelayer;\n int256 quoteExclusivitySeconds;\n bytes quoteId;\n uint256 callValue;\n bytes callParams;\n }\n\n /// @notice Updated bridge transaction struct to include parameters introduced in FastBridgeV2.\n /// Note: only `exclusivityRelayer` can fill such a transaction until `exclusivityEndTime`.\n /// TODO: consider changing the encoding scheme to prevent spending extra gas on decoding.\n struct BridgeTransactionV2 {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n uint256 callValue; // ETH value to send to the recipient (if any) - replaces V1's sendChainGas flag\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n address exclusivityRelayer;\n uint256 exclusivityEndTime;\n bytes callParams;\n }\n\n event BridgeQuoteDetails(bytes32 indexed transactionId, bytes quoteId);\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability\n /// to provide temporary exclusivity fill rights for the quote relayer.\n /// @param params The parameters required to bridge\n /// @param paramsV2 The parameters for exclusivity fill rights (optional, can be left empty)\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function relay(bytes memory request, address relayer) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param transactionId The transaction id associated with the encoded bridge transaction to prove\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital.\n /// @notice Can only send funds to the relayer address on the proof.\n /// @param request The encoded bridge transaction to claim on origin chain\n function claim(bytes memory request) external;\n /// @notice Checks if a transaction has been relayed\n /// @param transactionId The ID of the transaction to check\n /// @return True if the transaction has been relayed, false otherwise\n function bridgeRelays(bytes32 transactionId) external view returns (bool);\n\n /// @notice Returns the status of a bridge transaction\n /// @param transactionId The ID of the bridge transaction\n /// @return BridgeStatus Status of the bridge transaction\n function bridgeStatuses(bytes32 transactionId) external view returns (BridgeStatus);\n\n /// @notice Returns the timestamp and relayer of a bridge proof\n /// @param transactionId The ID of the bridge transaction\n /// @return timestamp The timestamp of the bridge proof\n /// @return relayer The relayer address of the bridge proof\n function bridgeProofs(bytes32 transactionId) external view returns (uint96 timestamp, address relayer);\n\n /// @notice Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\n /// @param request The bridge request to decode\n function getBridgeTransactionV2(bytes memory request) external view returns (BridgeTransactionV2 memory);\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// contracts/libs/UniversalToken.sol\n\nlibrary UniversalTokenLib {\n using SafeERC20 for IERC20;\n\n address internal constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Transfers tokens to the given account. Reverts if transfer is not successful.\n /// @dev This might trigger fallback, if ETH is transferred to the contract.\n /// Make sure this can not lead to reentrancy attacks.\n function universalTransfer(address token, address to, uint256 value) internal {\n // Don't do anything, if need to send tokens to this address\n if (to == address(this)) return;\n // Don't do anything, if trying to send zero value\n if (value == 0) return;\n if (token == ETH_ADDRESS) {\n /// @dev Note: this can potentially lead to executing code in `to`.\n // solhint-disable-next-line avoid-low-level-calls\n (bool success,) = to.call{value: value}(\"\");\n require(success, \"ETH transfer failed\");\n } else {\n IERC20(token).safeTransfer(to, value);\n }\n }\n\n /// @notice Issues an infinite allowance to the spender, if the current allowance is insufficient\n /// to spend the given amount.\n function universalApproveInfinity(address token, address spender, uint256 amountToSpend) internal {\n // ETH Chad doesn't require your approval\n if (token == ETH_ADDRESS) return;\n // No-op if allowance is already sufficient\n uint256 allowance = IERC20(token).allowance(address(this), spender);\n if (allowance \u003e= amountToSpend) return;\n // Otherwise, reset approval to 0 and set to max allowance\n if (allowance \u003e 0) IERC20(token).safeDecreaseAllowance(spender, allowance);\n IERC20(token).safeIncreaseAllowance(spender, type(uint256).max);\n }\n\n /// @notice Returns the balance of the given token (or native ETH) for the given account.\n function universalBalanceOf(address token, address account) internal view returns (uint256) {\n if (token == ETH_ADDRESS) {\n return account.balance;\n } else {\n return IERC20(token).balanceOf(account);\n }\n }\n\n /// @dev Checks that token is a contract and not ETH_ADDRESS.\n function assertIsContract(address token) internal view {\n // Check that ETH_ADDRESS was not used (in case this is a predeploy on any of the chains)\n if (token == UniversalTokenLib.ETH_ADDRESS) revert TokenNotContract();\n // Check that token is not an EOA\n if (token.code.length == 0) revert TokenNotContract();\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/Admin.sol\n\ncontract Admin is IAdmin, AccessControlEnumerable {\n using UniversalTokenLib for address;\n\n bytes32 public constant RELAYER_ROLE = keccak256(\"RELAYER_ROLE\");\n bytes32 public constant REFUNDER_ROLE = keccak256(\"REFUNDER_ROLE\");\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n uint256 public constant FEE_BPS = 1e6;\n uint256 public constant FEE_RATE_MAX = 0.01e6; // max 1% on origin amount\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Chain gas amount to forward as rebate if requested\n uint256 public chainGasAmount;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n }\n\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n require(newFeeRate \u003c= FEE_RATE_MAX, \"newFeeRate \u003e max\");\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n token.universalTransfer(recipient, feeAmount);\n emit FeesSwept(token, recipient, feeAmount);\n }\n\n function setChainGasAmount(uint256 newChainGasAmount) external onlyRole(GOVERNOR_ROLE) {\n uint256 oldChainGasAmount = chainGasAmount;\n chainGasAmount = newChainGasAmount;\n emit ChainGasAmountUpdated(oldChainGasAmount, newChainGasAmount);\n }\n}\n\n// contracts/FastBridgeV2.sol\n\n/// @notice FastBridgeV2 is a contract for bridging tokens across chains.\ncontract FastBridgeV2 is Admin, IFastBridgeV2, IFastBridgeV2Errors {\n using SafeERC20 for IERC20;\n using UniversalTokenLib for address;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Delay for a transaction after which it could be permisionlessly refunded\n uint256 public constant REFUND_DELAY = 7 days;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n /// @notice Maximum length of accepted callParams\n uint256 public constant MAX_CALL_PARAMS_LENGTH = 2 ** 16 - 1;\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeTxDetails) public bridgeTxDetails;\n /// @notice Relay details on destination chain\n mapping(bytes32 =\u003e BridgeRelay) public bridgeRelayDetails;\n /// @notice Unique bridge nonces tracked per originSender\n mapping(address =\u003e uint256) public senderNonces;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Replaced by senderNonces\n uint256 public immutable nonce = 0;\n /// @notice the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n bridge({\n params: params,\n paramsV2: BridgeParamsV2({\n quoteRelayer: address(0),\n quoteExclusivitySeconds: 0,\n quoteId: bytes(\"\"),\n callValue: 0,\n callParams: bytes(\"\")\n })\n });\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes memory request) external payable {\n relay({request: request, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes memory request, bytes32 destTxHash) external {\n prove({transactionId: keccak256(request), destTxHash: destTxHash, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridgeV2\n function claim(bytes memory request) external {\n claim({request: request, to: address(0)});\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003e DISPUTE_PERIOD) {\n revert DisputePeriodPassed();\n }\n\n // @dev relayer gets slashed effectively if dest relay has gone thru\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n bridgeTxDetails[transactionId].proofRelayer = address(0);\n bridgeTxDetails[transactionId].proofBlockTimestamp = 0;\n bridgeTxDetails[transactionId].proofBlockNumber = 0;\n\n emit BridgeProofDisputed(transactionId, msg.sender);\n }\n\n /// @inheritdoc IFastBridge\n function refund(bytes memory request) external {\n bytes32 transactionId = keccak256(request);\n\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n\n if (bridgeTxDetails[transactionId].status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n\n if (hasRole(REFUNDER_ROLE, msg.sender)) {\n // Refunder can refund if deadline has passed\n if (block.timestamp \u003c= transaction.deadline) revert DeadlineNotExceeded();\n } else {\n // Permissionless refund is allowed after REFUND_DELAY\n if (block.timestamp \u003c= transaction.deadline + REFUND_DELAY) revert DeadlineNotExceeded();\n }\n\n // if all checks passed, set to REFUNDED status\n bridgeTxDetails[transactionId].status = BridgeStatus.REFUNDED;\n\n // transfer origin collateral back to original sender\n address to = transaction.originSender;\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount + transaction.originFeeAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (bridgeTxDetails[transactionId].proofRelayer != relayer) revert SenderIncorrect();\n return _timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n /// @dev This method is added to achieve backwards compatibility with decoding requests into V1 structs:\n /// - `callValue` is partially reported as a zero/non-zero flag\n /// - `callParams` is ignored\n /// In order to process all kinds of requests use getBridgeTransactionV2 instead.\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory) {\n // Try decoding into V2 struct first. This will revert if V1 struct is passed\n try this.getBridgeTransactionV2(request) returns (BridgeTransactionV2 memory txV2) {\n // Note: we entirely ignore the callParams field, as it was not present in V1\n return BridgeTransaction({\n originChainId: txV2.originChainId,\n destChainId: txV2.destChainId,\n originSender: txV2.originSender,\n destRecipient: txV2.destRecipient,\n originToken: txV2.originToken,\n destToken: txV2.destToken,\n originAmount: txV2.originAmount,\n destAmount: txV2.destAmount,\n originFeeAmount: txV2.originFeeAmount,\n sendChainGas: txV2.callValue != 0,\n deadline: txV2.deadline,\n nonce: txV2.nonce\n });\n } catch {\n // Fallback to V1 struct\n return abi.decode(request, (BridgeTransaction));\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) public payable {\n int256 exclusivityEndTime = int256(block.timestamp) + paramsV2.quoteExclusivitySeconds;\n _validateBridgeParams(params, paramsV2, exclusivityEndTime);\n\n // transfer tokens to bridge contract\n /// @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _pullToken(params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n\n // set status to requested\n bytes memory request = abi.encode(\n BridgeTransactionV2({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n callValue: paramsV2.callValue,\n deadline: params.deadline,\n nonce: senderNonces[params.sender]++, // increment nonce on every bridge\n exclusivityRelayer: paramsV2.quoteRelayer,\n // We checked exclusivityEndTime to be in range (0 .. params.deadline] above, so can safely cast\n exclusivityEndTime: uint256(exclusivityEndTime),\n callParams: paramsV2.callParams\n })\n );\n bytes32 transactionId = keccak256(request);\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n\n emit BridgeRequested({\n transactionId: transactionId,\n sender: params.sender,\n request: request,\n destChainId: params.dstChainId,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n sendChainGas: paramsV2.callValue != 0\n });\n emit BridgeQuoteDetails(transactionId, paramsV2.quoteId);\n }\n\n /// @inheritdoc IFastBridgeV2\n function relay(bytes memory request, address relayer) public payable {\n bytes32 transactionId = keccak256(request);\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n _validateRelayParams(transaction, transactionId, relayer);\n // mark bridge transaction as relayed\n bridgeRelayDetails[transactionId] =\n BridgeRelay({blockNumber: uint48(block.number), blockTimestamp: uint48(block.timestamp), relayer: relayer});\n\n // transfer tokens to recipient on destination chain and do an arbitrary call if requested\n address to = transaction.destRecipient;\n address token = transaction.destToken;\n uint256 amount = transaction.destAmount;\n\n // All state changes have been done at this point, can proceed to the external calls.\n // This follows the checks-effects-interactions pattern to mitigate potential reentrancy attacks.\n if (token == UniversalTokenLib.ETH_ADDRESS) {\n // For ETH non-zero callValue is not allowed\n if (transaction.callValue != 0) revert NativeTokenCallValueNotSupported();\n // Check that the correct msg.value was sent\n if (msg.value != amount) revert MsgValueIncorrect();\n } else {\n // For ERC20s, we check that the correct msg.value was sent\n if (msg.value != transaction.callValue) revert MsgValueIncorrect();\n // We need to transfer the tokens from the Relayer to the recipient first before performing an\n // optional post-transfer arbitrary call.\n IERC20(token).safeTransferFrom(msg.sender, to, amount);\n }\n\n if (transaction.callParams.length != 0) {\n // Arbitrary call requested, perform it while supplying full msg.value to the recipient\n // Note: if token has a fee on transfers, the recipient will have received less than `amount`.\n // This is a very niche edge case and should be handled by the recipient contract.\n _checkedCallRecipient({recipient: to, token: token, amount: amount, callParams: transaction.callParams});\n } else if (msg.value != 0) {\n // No arbitrary call requested, but msg.value was sent. This is either a relay with ETH,\n // or a non-zero callValue request with an ERC20. In both cases, transfer the ETH to the recipient.\n Address.sendValue(payable(to), msg.value);\n }\n\n emit BridgeRelayed({\n transactionId: transactionId,\n relayer: relayer,\n to: to,\n originChainId: transaction.originChainId,\n originToken: transaction.originToken,\n destToken: transaction.destToken,\n originAmount: transaction.originAmount,\n destAmount: transaction.destAmount,\n chainGasAmount: transaction.callValue\n });\n }\n\n /// @inheritdoc IFastBridgeV2\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) public onlyRole(RELAYER_ROLE) {\n // update bridge tx status given proof provided\n if (bridgeTxDetails[transactionId].status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n bridgeTxDetails[transactionId].status = BridgeStatus.RELAYER_PROVED;\n bridgeTxDetails[transactionId].proofBlockTimestamp = uint40(block.timestamp);\n bridgeTxDetails[transactionId].proofBlockNumber = uint48(block.number);\n bridgeTxDetails[transactionId].proofRelayer = relayer;\n\n emit BridgeProofProvided(transactionId, relayer, destTxHash);\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes memory request, address to) public {\n bytes32 transactionId = keccak256(request);\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n\n // update bridge tx status if able to claim origin collateral\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n\n // if \"to\" is zero addr, permissionlessly send funds to proven relayer\n if (to == address(0)) {\n to = bridgeTxDetails[transactionId].proofRelayer;\n } else if (bridgeTxDetails[transactionId].proofRelayer != msg.sender) {\n revert SenderIncorrect();\n }\n\n if (_timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003c= DISPUTE_PERIOD) {\n revert DisputePeriodNotPassed();\n }\n\n bridgeTxDetails[transactionId].status = BridgeStatus.RELAYER_CLAIMED;\n\n // update protocol fees if origin fee amount exists\n if (transaction.originFeeAmount \u003e 0) protocolFees[transaction.originToken] += transaction.originFeeAmount;\n\n // transfer origin collateral less fee to specified address\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositClaimed(transactionId, bridgeTxDetails[transactionId].proofRelayer, to, token, amount);\n }\n\n function bridgeStatuses(bytes32 transactionId) public view returns (BridgeStatus status) {\n return bridgeTxDetails[transactionId].status;\n }\n\n function bridgeProofs(bytes32 transactionId) public view returns (uint96 timestamp, address relayer) {\n timestamp = bridgeTxDetails[transactionId].proofBlockTimestamp;\n relayer = bridgeTxDetails[transactionId].proofRelayer;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeRelays(bytes32 transactionId) public view returns (bool) {\n // has this transactionId been relayed?\n return bridgeRelayDetails[transactionId].relayer != address(0);\n }\n\n /// @inheritdoc IFastBridgeV2\n function getBridgeTransactionV2(bytes memory request) public pure returns (BridgeTransactionV2 memory) {\n return abi.decode(request, (BridgeTransactionV2));\n }\n\n /// @notice Pulls a requested token from the user to this contract.\n function _pullToken(address token, uint256 amount) internal returns (uint256 amountPulled) {\n if (token == UniversalTokenLib.ETH_ADDRESS) {\n // For ETH we just need to check that the supplied msg.value is correct\n if (amount != msg.value) revert MsgValueIncorrect();\n amountPulled = msg.value;\n } else {\n token.assertIsContract();\n // Record token balance before transfer\n amountPulled = IERC20(token).balanceOf(address(this));\n // Token needs to be pulled only if msg.value is zero\n // This way user can specify WETH as the origin asset\n IERC20(token).safeTransferFrom(msg.sender, address(this), amount);\n // Use the difference between the recorded balance and the current balance as the amountPulled\n amountPulled = IERC20(token).balanceOf(address(this)) - amountPulled;\n }\n }\n\n /// @notice Calls the Recipient's hook function with the specified callParams and performs\n /// all the necessary checks for the returned value.\n function _checkedCallRecipient(\n address recipient,\n address token,\n uint256 amount,\n bytes memory callParams\n )\n internal\n {\n bytes memory hookData =\n abi.encodeCall(IFastBridgeRecipient.fastBridgeTransferReceived, (token, amount, callParams));\n // This will bubble any revert messages from the hook function\n bytes memory returnData = Address.functionCallWithValue({target: recipient, data: hookData, value: msg.value});\n // Explicit revert if no return data at all\n if (returnData.length == 0) revert RecipientNoReturnValue();\n // Check that exactly a single return value was returned\n if (returnData.length != 32) revert RecipientIncorrectReturnValue();\n // Return value should be abi-encoded hook function selector\n if (bytes32(returnData) != bytes32(IFastBridgeRecipient.fastBridgeTransferReceived.selector)) {\n revert RecipientIncorrectReturnValue();\n }\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint40(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint40).max but\n /// proof.timestamp \u003c type(uint40).max via unchecked statement\n /// @param proofBlockTimestamp The bridge proof block timestamp\n /// @return delta Time delta since proof submitted\n function _timeSince(uint40 proofBlockTimestamp) internal view returns (uint256 delta) {\n unchecked {\n delta = uint40(block.timestamp) - proofBlockTimestamp;\n }\n }\n\n /// @notice Performs all the necessary checks for a bridge to happen.\n /// @dev There's no good way to refactor this function to reduce cyclomatic complexity due to\n /// the number of checks that need to be performed, so we skip the code-complexity rule here.\n // solhint-disable-next-line code-complexity\n function _validateBridgeParams(\n BridgeParams memory params,\n BridgeParamsV2 memory paramsV2,\n int256 exclusivityEndTime\n )\n internal\n view\n {\n // Check V1 (legacy) params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.sender == address(0) || params.to == address(0)) revert ZeroAddress();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n // Check V2 params\n if (paramsV2.callParams.length \u003e MAX_CALL_PARAMS_LENGTH) revert CallParamsLengthAboveMax();\n if (paramsV2.callValue != 0 \u0026\u0026 params.destToken == UniversalTokenLib.ETH_ADDRESS) {\n revert NativeTokenCallValueNotSupported();\n }\n // exclusivityEndTime must be in range (0 .. params.deadline]\n if (exclusivityEndTime \u003c= 0 || exclusivityEndTime \u003e int256(params.deadline)) {\n revert ExclusivityParamsIncorrect();\n }\n }\n\n /// @notice Performs all the necessary checks for a relay to happen.\n function _validateRelayParams(\n BridgeTransactionV2 memory transaction,\n bytes32 transactionId,\n address relayer\n )\n internal\n view\n {\n if (relayer == address(0)) revert ZeroAddress();\n // Check if the transaction has already been relayed\n if (bridgeRelays(transactionId)) revert TransactionRelayed();\n if (transaction.destChainId != uint32(block.chainid)) revert ChainIncorrect();\n // Check the deadline for relay to happen\n if (block.timestamp \u003e transaction.deadline) revert DeadlineExceeded();\n // Check the exclusivity period, if it is still ongoing\n // forgefmt: disable-next-item\n if (\n transaction.exclusivityRelayer != address(0) \u0026\u0026\n transaction.exclusivityRelayer != relayer \u0026\u0026\n block.timestamp \u003c= transaction.exclusivityEndTime\n ) {\n revert ExclusivityPeriodNotPassed();\n }\n }\n}\n","language":"Solidity","languageVersion":"0.8.24","compilerVersion":"0.8.24","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../","srcMap":"","srcMapRuntime":"","abiDefinition":[{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"relayer","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"BridgeDepositClaimed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"BridgeDepositRefunded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"relayer","type":"address"}],"name":"BridgeProofDisputed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"relayer","type":"address"},{"indexed":false,"internalType":"bytes32","name":"transactionHash","type":"bytes32"}],"name":"BridgeProofProvided","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":false,"internalType":"bytes","name":"quoteId","type":"bytes"}],"name":"BridgeQuoteDetails","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"relayer","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint32","name":"originChainId","type":"uint32"},{"indexed":false,"internalType":"address","name":"originToken","type":"address"},{"indexed":false,"internalType":"address","name":"destToken","type":"address"},{"indexed":false,"internalType":"uint256","name":"originAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"destAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"chainGasAmount","type":"uint256"}],"name":"BridgeRelayed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"bytes","name":"request","type":"bytes"},{"indexed":false,"internalType":"uint32","name":"destChainId","type":"uint32"},{"indexed":false,"internalType":"address","name":"originToken","type":"address"},{"indexed":false,"internalType":"address","name":"destToken","type":"address"},{"indexed":false,"internalType":"uint256","name":"originAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"destAmount","type":"uint256"},{"indexed":false,"internalType":"bool","name":"sendChainGas","type":"bool"}],"name":"BridgeRequested","type":"event"},{"inputs":[{"components":[{"internalType":"uint32","name":"dstChainId","type":"uint32"},{"internalType":"address","name":"sender","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"address","name":"originToken","type":"address"},{"internalType":"address","name":"destToken","type":"address"},{"internalType":"uint256","name":"originAmount","type":"uint256"},{"internalType":"uint256","name":"destAmount","type":"uint256"},{"internalType":"bool","name":"sendChainGas","type":"bool"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"internalType":"struct IFastBridge.BridgeParams","name":"params","type":"tuple"}],"name":"bridge","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"uint32","name":"dstChainId","type":"uint32"},{"internalType":"address","name":"sender","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"address","name":"originToken","type":"address"},{"internalType":"address","name":"destToken","type":"address"},{"internalType":"uint256","name":"originAmount","type":"uint256"},{"internalType":"uint256","name":"destAmount","type":"uint256"},{"internalType":"bool","name":"sendChainGas","type":"bool"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"internalType":"struct IFastBridge.BridgeParams","name":"params","type":"tuple"},{"components":[{"internalType":"address","name":"quoteRelayer","type":"address"},{"internalType":"int256","name":"quoteExclusivitySeconds","type":"int256"},{"internalType":"bytes","name":"quoteId","type":"bytes"},{"internalType":"uint256","name":"callValue","type":"uint256"},{"internalType":"bytes","name":"callParams","type":"bytes"}],"internalType":"struct IFastBridgeV2.BridgeParamsV2","name":"paramsV2","type":"tuple"}],"name":"bridge","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"transactionId","type":"bytes32"}],"name":"bridgeProofs","outputs":[{"internalType":"uint96","name":"timestamp","type":"uint96"},{"internalType":"address","name":"relayer","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"transactionId","type":"bytes32"}],"name":"bridgeRelays","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"transactionId","type":"bytes32"}],"name":"bridgeStatuses","outputs":[{"internalType":"enum IFastBridgeV2.BridgeStatus","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"internalType":"address","name":"relayer","type":"address"}],"name":"canClaim","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"},{"internalType":"address","name":"to","type":"address"}],"name":"claim","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"}],"name":"claim","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"transactionId","type":"bytes32"}],"name":"dispute","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"}],"name":"getBridgeTransaction","outputs":[{"components":[{"internalType":"uint32","name":"originChainId","type":"uint32"},{"internalType":"uint32","name":"destChainId","type":"uint32"},{"internalType":"address","name":"originSender","type":"address"},{"internalType":"address","name":"destRecipient","type":"address"},{"internalType":"address","name":"originToken","type":"address"},{"internalType":"address","name":"destToken","type":"address"},{"internalType":"uint256","name":"originAmount","type":"uint256"},{"internalType":"uint256","name":"destAmount","type":"uint256"},{"internalType":"uint256","name":"originFeeAmount","type":"uint256"},{"internalType":"bool","name":"sendChainGas","type":"bool"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint256","name":"nonce","type":"uint256"}],"internalType":"struct IFastBridge.BridgeTransaction","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"}],"name":"getBridgeTransactionV2","outputs":[{"components":[{"internalType":"uint32","name":"originChainId","type":"uint32"},{"internalType":"uint32","name":"destChainId","type":"uint32"},{"internalType":"address","name":"originSender","type":"address"},{"internalType":"address","name":"destRecipient","type":"address"},{"internalType":"address","name":"originToken","type":"address"},{"internalType":"address","name":"destToken","type":"address"},{"internalType":"uint256","name":"originAmount","type":"uint256"},{"internalType":"uint256","name":"destAmount","type":"uint256"},{"internalType":"uint256","name":"originFeeAmount","type":"uint256"},{"internalType":"uint256","name":"callValue","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"address","name":"exclusivityRelayer","type":"address"},{"internalType":"uint256","name":"exclusivityEndTime","type":"uint256"},{"internalType":"bytes","name":"callParams","type":"bytes"}],"internalType":"struct IFastBridgeV2.BridgeTransactionV2","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"internalType":"bytes32","name":"destTxHash","type":"bytes32"},{"internalType":"address","name":"relayer","type":"address"}],"name":"prove","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"},{"internalType":"bytes32","name":"destTxHash","type":"bytes32"}],"name":"prove","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"}],"name":"refund","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"}],"name":"relay","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"},{"internalType":"address","name":"relayer","type":"address"}],"name":"relay","outputs":[],"stateMutability":"payable","type":"function"}],"userDoc":{"kind":"user","methods":{"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256))":{"notice":"Initiates bridge on origin chain to be relayed by off-chain relayer"},"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256),(address,int256,bytes,uint256,bytes))":{"notice":"Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability to provide temporary exclusivity fill rights for the quote relayer."},"bridgeProofs(bytes32)":{"notice":"Returns the timestamp and relayer of a bridge proof"},"bridgeRelays(bytes32)":{"notice":"Checks if a transaction has been relayed"},"bridgeStatuses(bytes32)":{"notice":"Returns the status of a bridge transaction"},"canClaim(bytes32,address)":{"notice":"Checks if the dispute period has passed so bridge deposit can be claimed"},"claim(bytes)":{"notice":"Completes bridge transaction on origin chain by claiming originally deposited capital.Can only send funds to the relayer address on the proof."},"claim(bytes,address)":{"notice":"Completes bridge transaction on origin chain by claiming originally deposited capital"},"dispute(bytes32)":{"notice":"Disputes an outstanding proof in case relayer provided dest chain tx is invalid"},"getBridgeTransaction(bytes)":{"notice":"Decodes bridge request into a bridge transaction"},"getBridgeTransactionV2(bytes)":{"notice":"Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2"},"prove(bytes,bytes32)":{"notice":"Provides proof on origin side that relayer provided funds on destination side of bridge transaction"},"prove(bytes32,bytes32,address)":{"notice":"Provides proof on origin side that relayer provided funds on destination side of bridge transaction"},"refund(bytes)":{"notice":"Refunds an outstanding bridge transaction in case optimistic bridging failed"},"relay(bytes)":{"notice":"Relays destination side of bridge transaction by off-chain relayer"},"relay(bytes,address)":{"notice":"Relays destination side of bridge transaction by off-chain relayer"}},"version":1},"developerDoc":{"kind":"dev","methods":{"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256))":{"params":{"params":"The parameters required to bridge"}},"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256),(address,int256,bytes,uint256,bytes))":{"params":{"params":"The parameters required to bridge","paramsV2":"The parameters for exclusivity fill rights (optional, can be left empty)"}},"bridgeProofs(bytes32)":{"params":{"transactionId":"The ID of the bridge transaction"},"returns":{"relayer":"The relayer address of the bridge proof","timestamp":"The timestamp of the bridge proof"}},"bridgeRelays(bytes32)":{"params":{"transactionId":"The ID of the transaction to check"},"returns":{"_0":"True if the transaction has been relayed, false otherwise"}},"bridgeStatuses(bytes32)":{"params":{"transactionId":"The ID of the bridge transaction"},"returns":{"_0":"BridgeStatus Status of the bridge transaction"}},"canClaim(bytes32,address)":{"params":{"relayer":"The address of the relayer attempting to claim","transactionId":"The transaction id associated with the encoded bridge transaction to check"}},"claim(bytes)":{"params":{"request":"The encoded bridge transaction to claim on origin chain"}},"claim(bytes,address)":{"params":{"request":"The encoded bridge transaction to claim on origin chain","to":"The recipient address of the funds"}},"dispute(bytes32)":{"params":{"transactionId":"The transaction id associated with the encoded bridge transaction to dispute"}},"getBridgeTransaction(bytes)":{"params":{"request":"The bridge request to decode"}},"getBridgeTransactionV2(bytes)":{"params":{"request":"The bridge request to decode"}},"prove(bytes,bytes32)":{"params":{"destTxHash":"The destination tx hash proving bridge transaction was relayed","request":"The encoded bridge transaction to prove on origin chain"}},"prove(bytes32,bytes32,address)":{"params":{"destTxHash":"The destination tx hash proving bridge transaction was relayed","relayer":"The address of the relaying entity which should have control of the origin funds when claimed","transactionId":"The transaction id associated with the encoded bridge transaction to prove"}},"refund(bytes)":{"params":{"request":"The encoded bridge transaction to refund"}},"relay(bytes)":{"params":{"request":"The encoded bridge transaction to relay on destination chain"}},"relay(bytes,address)":{"params":{"relayer":"The address of the relaying entity which should have control of the origin funds when claimed","request":"The encoded bridge transaction to relay on destination chain"}}},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"BridgeDepositClaimed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"BridgeDepositRefunded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"name\":\"BridgeProofDisputed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"transactionHash\",\"type\":\"bytes32\"}],\"name\":\"BridgeProofProvided\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"quoteId\",\"type\":\"bytes\"}],\"name\":\"BridgeQuoteDetails\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"originChainId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"chainGasAmount\",\"type\":\"uint256\"}],\"name\":\"BridgeRelayed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"destChainId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"sendChainGas\",\"type\":\"bool\"}],\"name\":\"BridgeRequested\",\"type\":\"event\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"dstChainId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"sendChainGas\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"}],\"internalType\":\"struct IFastBridge.BridgeParams\",\"name\":\"params\",\"type\":\"tuple\"}],\"name\":\"bridge\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"dstChainId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"sendChainGas\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"}],\"internalType\":\"struct IFastBridge.BridgeParams\",\"name\":\"params\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"quoteRelayer\",\"type\":\"address\"},{\"internalType\":\"int256\",\"name\":\"quoteExclusivitySeconds\",\"type\":\"int256\"},{\"internalType\":\"bytes\",\"name\":\"quoteId\",\"type\":\"bytes\"},{\"internalType\":\"uint256\",\"name\":\"callValue\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"callParams\",\"type\":\"bytes\"}],\"internalType\":\"struct IFastBridgeV2.BridgeParamsV2\",\"name\":\"paramsV2\",\"type\":\"tuple\"}],\"name\":\"bridge\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"}],\"name\":\"bridgeProofs\",\"outputs\":[{\"internalType\":\"uint96\",\"name\":\"timestamp\",\"type\":\"uint96\"},{\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"}],\"name\":\"bridgeRelays\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"}],\"name\":\"bridgeStatuses\",\"outputs\":[{\"internalType\":\"enum IFastBridgeV2.BridgeStatus\",\"name\":\"\",\"type\":\"uint8\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"name\":\"canClaim\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"claim\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"claim\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"}],\"name\":\"dispute\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"getBridgeTransaction\",\"outputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"originChainId\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"destChainId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"originSender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destRecipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"originFeeAmount\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"sendChainGas\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"}],\"internalType\":\"struct IFastBridge.BridgeTransaction\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"getBridgeTransactionV2\",\"outputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"originChainId\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"destChainId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"originSender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destRecipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"originFeeAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"callValue\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"exclusivityRelayer\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"exclusivityEndTime\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"callParams\",\"type\":\"bytes\"}],\"internalType\":\"struct IFastBridgeV2.BridgeTransactionV2\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"destTxHash\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"name\":\"prove\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"},{\"internalType\":\"bytes32\",\"name\":\"destTxHash\",\"type\":\"bytes32\"}],\"name\":\"prove\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"refund\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"relay\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"},{\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"name\":\"relay\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{\"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256))\":{\"params\":{\"params\":\"The parameters required to bridge\"}},\"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256),(address,int256,bytes,uint256,bytes))\":{\"params\":{\"params\":\"The parameters required to bridge\",\"paramsV2\":\"The parameters for exclusivity fill rights (optional, can be left empty)\"}},\"bridgeProofs(bytes32)\":{\"params\":{\"transactionId\":\"The ID of the bridge transaction\"},\"returns\":{\"relayer\":\"The relayer address of the bridge proof\",\"timestamp\":\"The timestamp of the bridge proof\"}},\"bridgeRelays(bytes32)\":{\"params\":{\"transactionId\":\"The ID of the transaction to check\"},\"returns\":{\"_0\":\"True if the transaction has been relayed, false otherwise\"}},\"bridgeStatuses(bytes32)\":{\"params\":{\"transactionId\":\"The ID of the bridge transaction\"},\"returns\":{\"_0\":\"BridgeStatus Status of the bridge transaction\"}},\"canClaim(bytes32,address)\":{\"params\":{\"relayer\":\"The address of the relayer attempting to claim\",\"transactionId\":\"The transaction id associated with the encoded bridge transaction to check\"}},\"claim(bytes)\":{\"params\":{\"request\":\"The encoded bridge transaction to claim on origin chain\"}},\"claim(bytes,address)\":{\"params\":{\"request\":\"The encoded bridge transaction to claim on origin chain\",\"to\":\"The recipient address of the funds\"}},\"dispute(bytes32)\":{\"params\":{\"transactionId\":\"The transaction id associated with the encoded bridge transaction to dispute\"}},\"getBridgeTransaction(bytes)\":{\"params\":{\"request\":\"The bridge request to decode\"}},\"getBridgeTransactionV2(bytes)\":{\"params\":{\"request\":\"The bridge request to decode\"}},\"prove(bytes,bytes32)\":{\"params\":{\"destTxHash\":\"The destination tx hash proving bridge transaction was relayed\",\"request\":\"The encoded bridge transaction to prove on origin chain\"}},\"prove(bytes32,bytes32,address)\":{\"params\":{\"destTxHash\":\"The destination tx hash proving bridge transaction was relayed\",\"relayer\":\"The address of the relaying entity which should have control of the origin funds when claimed\",\"transactionId\":\"The transaction id associated with the encoded bridge transaction to prove\"}},\"refund(bytes)\":{\"params\":{\"request\":\"The encoded bridge transaction to refund\"}},\"relay(bytes)\":{\"params\":{\"request\":\"The encoded bridge transaction to relay on destination chain\"}},\"relay(bytes,address)\":{\"params\":{\"relayer\":\"The address of the relaying entity which should have control of the origin funds when claimed\",\"request\":\"The encoded bridge transaction to relay on destination chain\"}}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256))\":{\"notice\":\"Initiates bridge on origin chain to be relayed by off-chain relayer\"},\"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256),(address,int256,bytes,uint256,bytes))\":{\"notice\":\"Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability to provide temporary exclusivity fill rights for the quote relayer.\"},\"bridgeProofs(bytes32)\":{\"notice\":\"Returns the timestamp and relayer of a bridge proof\"},\"bridgeRelays(bytes32)\":{\"notice\":\"Checks if a transaction has been relayed\"},\"bridgeStatuses(bytes32)\":{\"notice\":\"Returns the status of a bridge transaction\"},\"canClaim(bytes32,address)\":{\"notice\":\"Checks if the dispute period has passed so bridge deposit can be claimed\"},\"claim(bytes)\":{\"notice\":\"Completes bridge transaction on origin chain by claiming originally deposited capital.Can only send funds to the relayer address on the proof.\"},\"claim(bytes,address)\":{\"notice\":\"Completes bridge transaction on origin chain by claiming originally deposited capital\"},\"dispute(bytes32)\":{\"notice\":\"Disputes an outstanding proof in case relayer provided dest chain tx is invalid\"},\"getBridgeTransaction(bytes)\":{\"notice\":\"Decodes bridge request into a bridge transaction\"},\"getBridgeTransactionV2(bytes)\":{\"notice\":\"Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\"},\"prove(bytes,bytes32)\":{\"notice\":\"Provides proof on origin side that relayer provided funds on destination side of bridge transaction\"},\"prove(bytes32,bytes32,address)\":{\"notice\":\"Provides proof on origin side that relayer provided funds on destination side of bridge transaction\"},\"refund(bytes)\":{\"notice\":\"Refunds an outstanding bridge transaction in case optimistic bridging failed\"},\"relay(bytes)\":{\"notice\":\"Relays destination side of bridge transaction by off-chain relayer\"},\"relay(bytes,address)\":{\"notice\":\"Relays destination side of bridge transaction by off-chain relayer\"}},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeV2.sol\":\"IFastBridgeV2\"},\"evmVersion\":\"shanghai\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeV2.sol\":{\"keccak256\":\"0x7cd0f885e80e2bdaa638bc32ae7af7d2e248f99ce4b354c217d0f0f7d7302e0a\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://7ccf28df0bd7b4606986585acd8622ed9b4e81379690061bb66088f0a2270af1\",\"dweb:/ipfs/QmTf7HNdHZkK6vmx8ZgewycQEb72oLD9nPwBpsM5reMstQ\"]}},\"version\":1}"},"hashes":{"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256))":"45851694","bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256),(address,int256,bytes,uint256,bytes))":"bfc7c607","bridgeProofs(bytes32)":"91ad5039","bridgeRelays(bytes32)":"8379a24f","bridgeStatuses(bytes32)":"051287bc","canClaim(bytes32,address)":"aa9641ab","claim(bytes)":"c63ff8dd","claim(bytes,address)":"41fcb612","dispute(bytes32)":"add98c70","getBridgeTransaction(bytes)":"ac11fb1a","getBridgeTransactionV2(bytes)":"5aa6ccba","prove(bytes,bytes32)":"886d36ff","prove(bytes32,bytes32,address)":"18e4357d","refund(bytes)":"5eb7d946","relay(bytes)":"8f0d6f17","relay(bytes,address)":"9c9545f0"}},"solidity/FastBridgeV2.sol:IFastBridgeV2Errors":{"code":"0x","runtime-code":"0x","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.24 ^0.8.0 ^0.8.20;\n\n// contracts/interfaces/IAdmin.sol\n\ninterface IAdmin {\n // ============ Events ============\n\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n event ChainGasAmountUpdated(uint256 oldChainGasAmount, uint256 newChainGasAmount);\n\n // ============ Methods ============\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n\n function setChainGasAmount(uint256 newChainGasAmount) external;\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IFastBridgeRecipient.sol\n\ninterface IFastBridgeRecipient {\n function fastBridgeTransferReceived(\n address token,\n uint256 amount,\n bytes memory callParams\n )\n external\n payable\n returns (bytes4);\n}\n\n// contracts/interfaces/IFastBridgeV2Errors.sol\n\ninterface IFastBridgeV2Errors {\n error AmountIncorrect();\n error CallParamsLengthAboveMax();\n error ChainIncorrect();\n error ExclusivityParamsIncorrect();\n error MsgValueIncorrect();\n error NativeTokenCallValueNotSupported();\n error SenderIncorrect();\n error StatusIncorrect();\n error ZeroAddress();\n\n error RecipientIncorrectReturnValue();\n error RecipientNoReturnValue();\n\n error DeadlineExceeded();\n error DeadlineNotExceeded();\n error DeadlineTooShort();\n error DisputePeriodNotPassed();\n error DisputePeriodPassed();\n error ExclusivityPeriodNotPassed();\n\n error TransactionRelayed();\n}\n\n// contracts/libs/Errors.sol\n\nerror DeadlineExceeded();\nerror DeadlineNotExceeded();\nerror DeadlineTooShort();\nerror InsufficientOutputAmount();\n\nerror MsgValueIncorrect();\nerror PoolNotFound();\nerror TokenAddressMismatch();\nerror TokenNotContract();\nerror TokenNotETH();\nerror TokensIdentical();\n\nerror ChainIncorrect();\nerror AmountIncorrect();\nerror ZeroAddress();\n\nerror DisputePeriodNotPassed();\nerror DisputePeriodPassed();\nerror SenderIncorrect();\nerror StatusIncorrect();\nerror TransactionIdIncorrect();\nerror TransactionRelayed();\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// contracts/interfaces/IFastBridgeV2.sol\n\ninterface IFastBridgeV2 is IFastBridge {\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n struct BridgeTxDetails {\n BridgeStatus status;\n uint40 proofBlockTimestamp;\n uint48 proofBlockNumber;\n address proofRelayer;\n }\n\n struct BridgeRelay {\n uint48 blockNumber;\n uint48 blockTimestamp;\n address relayer;\n }\n\n /// @notice New params introduced in the FastBridgeV2.\n /// We are passing fields from the older BridgeParams struct outside of this struct\n /// for backwards compatibility.\n /// Note: quoteRelayer and quoteExclusivitySeconds are either both zero (indicating no exclusivity)\n /// or both non-zero (indicating exclusivity for the given period).\n /// Note: callValue \u003e 0 can NOT be used with destToken = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE (ETH_ADDRESS)\n /// @param quoteRelayer Relayer that provided the quote for the transaction\n /// @param quoteExclusivitySeconds Period of time the quote relayer is guaranteed exclusivity after user's deposit\n /// @param quoteId Unique quote identifier used for tracking the quote\n /// @param callValue ETH value to send to the recipient (if any)\n /// @param callParams Parameters for the arbitrary call to the destination recipient (if any)\n struct BridgeParamsV2 {\n address quoteRelayer;\n int256 quoteExclusivitySeconds;\n bytes quoteId;\n uint256 callValue;\n bytes callParams;\n }\n\n /// @notice Updated bridge transaction struct to include parameters introduced in FastBridgeV2.\n /// Note: only `exclusivityRelayer` can fill such a transaction until `exclusivityEndTime`.\n /// TODO: consider changing the encoding scheme to prevent spending extra gas on decoding.\n struct BridgeTransactionV2 {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n uint256 callValue; // ETH value to send to the recipient (if any) - replaces V1's sendChainGas flag\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n address exclusivityRelayer;\n uint256 exclusivityEndTime;\n bytes callParams;\n }\n\n event BridgeQuoteDetails(bytes32 indexed transactionId, bytes quoteId);\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability\n /// to provide temporary exclusivity fill rights for the quote relayer.\n /// @param params The parameters required to bridge\n /// @param paramsV2 The parameters for exclusivity fill rights (optional, can be left empty)\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function relay(bytes memory request, address relayer) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param transactionId The transaction id associated with the encoded bridge transaction to prove\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital.\n /// @notice Can only send funds to the relayer address on the proof.\n /// @param request The encoded bridge transaction to claim on origin chain\n function claim(bytes memory request) external;\n /// @notice Checks if a transaction has been relayed\n /// @param transactionId The ID of the transaction to check\n /// @return True if the transaction has been relayed, false otherwise\n function bridgeRelays(bytes32 transactionId) external view returns (bool);\n\n /// @notice Returns the status of a bridge transaction\n /// @param transactionId The ID of the bridge transaction\n /// @return BridgeStatus Status of the bridge transaction\n function bridgeStatuses(bytes32 transactionId) external view returns (BridgeStatus);\n\n /// @notice Returns the timestamp and relayer of a bridge proof\n /// @param transactionId The ID of the bridge transaction\n /// @return timestamp The timestamp of the bridge proof\n /// @return relayer The relayer address of the bridge proof\n function bridgeProofs(bytes32 transactionId) external view returns (uint96 timestamp, address relayer);\n\n /// @notice Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\n /// @param request The bridge request to decode\n function getBridgeTransactionV2(bytes memory request) external view returns (BridgeTransactionV2 memory);\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// contracts/libs/UniversalToken.sol\n\nlibrary UniversalTokenLib {\n using SafeERC20 for IERC20;\n\n address internal constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Transfers tokens to the given account. Reverts if transfer is not successful.\n /// @dev This might trigger fallback, if ETH is transferred to the contract.\n /// Make sure this can not lead to reentrancy attacks.\n function universalTransfer(address token, address to, uint256 value) internal {\n // Don't do anything, if need to send tokens to this address\n if (to == address(this)) return;\n // Don't do anything, if trying to send zero value\n if (value == 0) return;\n if (token == ETH_ADDRESS) {\n /// @dev Note: this can potentially lead to executing code in `to`.\n // solhint-disable-next-line avoid-low-level-calls\n (bool success,) = to.call{value: value}(\"\");\n require(success, \"ETH transfer failed\");\n } else {\n IERC20(token).safeTransfer(to, value);\n }\n }\n\n /// @notice Issues an infinite allowance to the spender, if the current allowance is insufficient\n /// to spend the given amount.\n function universalApproveInfinity(address token, address spender, uint256 amountToSpend) internal {\n // ETH Chad doesn't require your approval\n if (token == ETH_ADDRESS) return;\n // No-op if allowance is already sufficient\n uint256 allowance = IERC20(token).allowance(address(this), spender);\n if (allowance \u003e= amountToSpend) return;\n // Otherwise, reset approval to 0 and set to max allowance\n if (allowance \u003e 0) IERC20(token).safeDecreaseAllowance(spender, allowance);\n IERC20(token).safeIncreaseAllowance(spender, type(uint256).max);\n }\n\n /// @notice Returns the balance of the given token (or native ETH) for the given account.\n function universalBalanceOf(address token, address account) internal view returns (uint256) {\n if (token == ETH_ADDRESS) {\n return account.balance;\n } else {\n return IERC20(token).balanceOf(account);\n }\n }\n\n /// @dev Checks that token is a contract and not ETH_ADDRESS.\n function assertIsContract(address token) internal view {\n // Check that ETH_ADDRESS was not used (in case this is a predeploy on any of the chains)\n if (token == UniversalTokenLib.ETH_ADDRESS) revert TokenNotContract();\n // Check that token is not an EOA\n if (token.code.length == 0) revert TokenNotContract();\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/Admin.sol\n\ncontract Admin is IAdmin, AccessControlEnumerable {\n using UniversalTokenLib for address;\n\n bytes32 public constant RELAYER_ROLE = keccak256(\"RELAYER_ROLE\");\n bytes32 public constant REFUNDER_ROLE = keccak256(\"REFUNDER_ROLE\");\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n uint256 public constant FEE_BPS = 1e6;\n uint256 public constant FEE_RATE_MAX = 0.01e6; // max 1% on origin amount\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Chain gas amount to forward as rebate if requested\n uint256 public chainGasAmount;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n }\n\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n require(newFeeRate \u003c= FEE_RATE_MAX, \"newFeeRate \u003e max\");\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n token.universalTransfer(recipient, feeAmount);\n emit FeesSwept(token, recipient, feeAmount);\n }\n\n function setChainGasAmount(uint256 newChainGasAmount) external onlyRole(GOVERNOR_ROLE) {\n uint256 oldChainGasAmount = chainGasAmount;\n chainGasAmount = newChainGasAmount;\n emit ChainGasAmountUpdated(oldChainGasAmount, newChainGasAmount);\n }\n}\n\n// contracts/FastBridgeV2.sol\n\n/// @notice FastBridgeV2 is a contract for bridging tokens across chains.\ncontract FastBridgeV2 is Admin, IFastBridgeV2, IFastBridgeV2Errors {\n using SafeERC20 for IERC20;\n using UniversalTokenLib for address;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Delay for a transaction after which it could be permisionlessly refunded\n uint256 public constant REFUND_DELAY = 7 days;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n /// @notice Maximum length of accepted callParams\n uint256 public constant MAX_CALL_PARAMS_LENGTH = 2 ** 16 - 1;\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeTxDetails) public bridgeTxDetails;\n /// @notice Relay details on destination chain\n mapping(bytes32 =\u003e BridgeRelay) public bridgeRelayDetails;\n /// @notice Unique bridge nonces tracked per originSender\n mapping(address =\u003e uint256) public senderNonces;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Replaced by senderNonces\n uint256 public immutable nonce = 0;\n /// @notice the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n bridge({\n params: params,\n paramsV2: BridgeParamsV2({\n quoteRelayer: address(0),\n quoteExclusivitySeconds: 0,\n quoteId: bytes(\"\"),\n callValue: 0,\n callParams: bytes(\"\")\n })\n });\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes memory request) external payable {\n relay({request: request, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes memory request, bytes32 destTxHash) external {\n prove({transactionId: keccak256(request), destTxHash: destTxHash, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridgeV2\n function claim(bytes memory request) external {\n claim({request: request, to: address(0)});\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003e DISPUTE_PERIOD) {\n revert DisputePeriodPassed();\n }\n\n // @dev relayer gets slashed effectively if dest relay has gone thru\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n bridgeTxDetails[transactionId].proofRelayer = address(0);\n bridgeTxDetails[transactionId].proofBlockTimestamp = 0;\n bridgeTxDetails[transactionId].proofBlockNumber = 0;\n\n emit BridgeProofDisputed(transactionId, msg.sender);\n }\n\n /// @inheritdoc IFastBridge\n function refund(bytes memory request) external {\n bytes32 transactionId = keccak256(request);\n\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n\n if (bridgeTxDetails[transactionId].status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n\n if (hasRole(REFUNDER_ROLE, msg.sender)) {\n // Refunder can refund if deadline has passed\n if (block.timestamp \u003c= transaction.deadline) revert DeadlineNotExceeded();\n } else {\n // Permissionless refund is allowed after REFUND_DELAY\n if (block.timestamp \u003c= transaction.deadline + REFUND_DELAY) revert DeadlineNotExceeded();\n }\n\n // if all checks passed, set to REFUNDED status\n bridgeTxDetails[transactionId].status = BridgeStatus.REFUNDED;\n\n // transfer origin collateral back to original sender\n address to = transaction.originSender;\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount + transaction.originFeeAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (bridgeTxDetails[transactionId].proofRelayer != relayer) revert SenderIncorrect();\n return _timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n /// @dev This method is added to achieve backwards compatibility with decoding requests into V1 structs:\n /// - `callValue` is partially reported as a zero/non-zero flag\n /// - `callParams` is ignored\n /// In order to process all kinds of requests use getBridgeTransactionV2 instead.\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory) {\n // Try decoding into V2 struct first. This will revert if V1 struct is passed\n try this.getBridgeTransactionV2(request) returns (BridgeTransactionV2 memory txV2) {\n // Note: we entirely ignore the callParams field, as it was not present in V1\n return BridgeTransaction({\n originChainId: txV2.originChainId,\n destChainId: txV2.destChainId,\n originSender: txV2.originSender,\n destRecipient: txV2.destRecipient,\n originToken: txV2.originToken,\n destToken: txV2.destToken,\n originAmount: txV2.originAmount,\n destAmount: txV2.destAmount,\n originFeeAmount: txV2.originFeeAmount,\n sendChainGas: txV2.callValue != 0,\n deadline: txV2.deadline,\n nonce: txV2.nonce\n });\n } catch {\n // Fallback to V1 struct\n return abi.decode(request, (BridgeTransaction));\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) public payable {\n int256 exclusivityEndTime = int256(block.timestamp) + paramsV2.quoteExclusivitySeconds;\n _validateBridgeParams(params, paramsV2, exclusivityEndTime);\n\n // transfer tokens to bridge contract\n /// @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _pullToken(params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n\n // set status to requested\n bytes memory request = abi.encode(\n BridgeTransactionV2({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n callValue: paramsV2.callValue,\n deadline: params.deadline,\n nonce: senderNonces[params.sender]++, // increment nonce on every bridge\n exclusivityRelayer: paramsV2.quoteRelayer,\n // We checked exclusivityEndTime to be in range (0 .. params.deadline] above, so can safely cast\n exclusivityEndTime: uint256(exclusivityEndTime),\n callParams: paramsV2.callParams\n })\n );\n bytes32 transactionId = keccak256(request);\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n\n emit BridgeRequested({\n transactionId: transactionId,\n sender: params.sender,\n request: request,\n destChainId: params.dstChainId,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n sendChainGas: paramsV2.callValue != 0\n });\n emit BridgeQuoteDetails(transactionId, paramsV2.quoteId);\n }\n\n /// @inheritdoc IFastBridgeV2\n function relay(bytes memory request, address relayer) public payable {\n bytes32 transactionId = keccak256(request);\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n _validateRelayParams(transaction, transactionId, relayer);\n // mark bridge transaction as relayed\n bridgeRelayDetails[transactionId] =\n BridgeRelay({blockNumber: uint48(block.number), blockTimestamp: uint48(block.timestamp), relayer: relayer});\n\n // transfer tokens to recipient on destination chain and do an arbitrary call if requested\n address to = transaction.destRecipient;\n address token = transaction.destToken;\n uint256 amount = transaction.destAmount;\n\n // All state changes have been done at this point, can proceed to the external calls.\n // This follows the checks-effects-interactions pattern to mitigate potential reentrancy attacks.\n if (token == UniversalTokenLib.ETH_ADDRESS) {\n // For ETH non-zero callValue is not allowed\n if (transaction.callValue != 0) revert NativeTokenCallValueNotSupported();\n // Check that the correct msg.value was sent\n if (msg.value != amount) revert MsgValueIncorrect();\n } else {\n // For ERC20s, we check that the correct msg.value was sent\n if (msg.value != transaction.callValue) revert MsgValueIncorrect();\n // We need to transfer the tokens from the Relayer to the recipient first before performing an\n // optional post-transfer arbitrary call.\n IERC20(token).safeTransferFrom(msg.sender, to, amount);\n }\n\n if (transaction.callParams.length != 0) {\n // Arbitrary call requested, perform it while supplying full msg.value to the recipient\n // Note: if token has a fee on transfers, the recipient will have received less than `amount`.\n // This is a very niche edge case and should be handled by the recipient contract.\n _checkedCallRecipient({recipient: to, token: token, amount: amount, callParams: transaction.callParams});\n } else if (msg.value != 0) {\n // No arbitrary call requested, but msg.value was sent. This is either a relay with ETH,\n // or a non-zero callValue request with an ERC20. In both cases, transfer the ETH to the recipient.\n Address.sendValue(payable(to), msg.value);\n }\n\n emit BridgeRelayed({\n transactionId: transactionId,\n relayer: relayer,\n to: to,\n originChainId: transaction.originChainId,\n originToken: transaction.originToken,\n destToken: transaction.destToken,\n originAmount: transaction.originAmount,\n destAmount: transaction.destAmount,\n chainGasAmount: transaction.callValue\n });\n }\n\n /// @inheritdoc IFastBridgeV2\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) public onlyRole(RELAYER_ROLE) {\n // update bridge tx status given proof provided\n if (bridgeTxDetails[transactionId].status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n bridgeTxDetails[transactionId].status = BridgeStatus.RELAYER_PROVED;\n bridgeTxDetails[transactionId].proofBlockTimestamp = uint40(block.timestamp);\n bridgeTxDetails[transactionId].proofBlockNumber = uint48(block.number);\n bridgeTxDetails[transactionId].proofRelayer = relayer;\n\n emit BridgeProofProvided(transactionId, relayer, destTxHash);\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes memory request, address to) public {\n bytes32 transactionId = keccak256(request);\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n\n // update bridge tx status if able to claim origin collateral\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n\n // if \"to\" is zero addr, permissionlessly send funds to proven relayer\n if (to == address(0)) {\n to = bridgeTxDetails[transactionId].proofRelayer;\n } else if (bridgeTxDetails[transactionId].proofRelayer != msg.sender) {\n revert SenderIncorrect();\n }\n\n if (_timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003c= DISPUTE_PERIOD) {\n revert DisputePeriodNotPassed();\n }\n\n bridgeTxDetails[transactionId].status = BridgeStatus.RELAYER_CLAIMED;\n\n // update protocol fees if origin fee amount exists\n if (transaction.originFeeAmount \u003e 0) protocolFees[transaction.originToken] += transaction.originFeeAmount;\n\n // transfer origin collateral less fee to specified address\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositClaimed(transactionId, bridgeTxDetails[transactionId].proofRelayer, to, token, amount);\n }\n\n function bridgeStatuses(bytes32 transactionId) public view returns (BridgeStatus status) {\n return bridgeTxDetails[transactionId].status;\n }\n\n function bridgeProofs(bytes32 transactionId) public view returns (uint96 timestamp, address relayer) {\n timestamp = bridgeTxDetails[transactionId].proofBlockTimestamp;\n relayer = bridgeTxDetails[transactionId].proofRelayer;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeRelays(bytes32 transactionId) public view returns (bool) {\n // has this transactionId been relayed?\n return bridgeRelayDetails[transactionId].relayer != address(0);\n }\n\n /// @inheritdoc IFastBridgeV2\n function getBridgeTransactionV2(bytes memory request) public pure returns (BridgeTransactionV2 memory) {\n return abi.decode(request, (BridgeTransactionV2));\n }\n\n /// @notice Pulls a requested token from the user to this contract.\n function _pullToken(address token, uint256 amount) internal returns (uint256 amountPulled) {\n if (token == UniversalTokenLib.ETH_ADDRESS) {\n // For ETH we just need to check that the supplied msg.value is correct\n if (amount != msg.value) revert MsgValueIncorrect();\n amountPulled = msg.value;\n } else {\n token.assertIsContract();\n // Record token balance before transfer\n amountPulled = IERC20(token).balanceOf(address(this));\n // Token needs to be pulled only if msg.value is zero\n // This way user can specify WETH as the origin asset\n IERC20(token).safeTransferFrom(msg.sender, address(this), amount);\n // Use the difference between the recorded balance and the current balance as the amountPulled\n amountPulled = IERC20(token).balanceOf(address(this)) - amountPulled;\n }\n }\n\n /// @notice Calls the Recipient's hook function with the specified callParams and performs\n /// all the necessary checks for the returned value.\n function _checkedCallRecipient(\n address recipient,\n address token,\n uint256 amount,\n bytes memory callParams\n )\n internal\n {\n bytes memory hookData =\n abi.encodeCall(IFastBridgeRecipient.fastBridgeTransferReceived, (token, amount, callParams));\n // This will bubble any revert messages from the hook function\n bytes memory returnData = Address.functionCallWithValue({target: recipient, data: hookData, value: msg.value});\n // Explicit revert if no return data at all\n if (returnData.length == 0) revert RecipientNoReturnValue();\n // Check that exactly a single return value was returned\n if (returnData.length != 32) revert RecipientIncorrectReturnValue();\n // Return value should be abi-encoded hook function selector\n if (bytes32(returnData) != bytes32(IFastBridgeRecipient.fastBridgeTransferReceived.selector)) {\n revert RecipientIncorrectReturnValue();\n }\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint40(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint40).max but\n /// proof.timestamp \u003c type(uint40).max via unchecked statement\n /// @param proofBlockTimestamp The bridge proof block timestamp\n /// @return delta Time delta since proof submitted\n function _timeSince(uint40 proofBlockTimestamp) internal view returns (uint256 delta) {\n unchecked {\n delta = uint40(block.timestamp) - proofBlockTimestamp;\n }\n }\n\n /// @notice Performs all the necessary checks for a bridge to happen.\n /// @dev There's no good way to refactor this function to reduce cyclomatic complexity due to\n /// the number of checks that need to be performed, so we skip the code-complexity rule here.\n // solhint-disable-next-line code-complexity\n function _validateBridgeParams(\n BridgeParams memory params,\n BridgeParamsV2 memory paramsV2,\n int256 exclusivityEndTime\n )\n internal\n view\n {\n // Check V1 (legacy) params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.sender == address(0) || params.to == address(0)) revert ZeroAddress();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n // Check V2 params\n if (paramsV2.callParams.length \u003e MAX_CALL_PARAMS_LENGTH) revert CallParamsLengthAboveMax();\n if (paramsV2.callValue != 0 \u0026\u0026 params.destToken == UniversalTokenLib.ETH_ADDRESS) {\n revert NativeTokenCallValueNotSupported();\n }\n // exclusivityEndTime must be in range (0 .. params.deadline]\n if (exclusivityEndTime \u003c= 0 || exclusivityEndTime \u003e int256(params.deadline)) {\n revert ExclusivityParamsIncorrect();\n }\n }\n\n /// @notice Performs all the necessary checks for a relay to happen.\n function _validateRelayParams(\n BridgeTransactionV2 memory transaction,\n bytes32 transactionId,\n address relayer\n )\n internal\n view\n {\n if (relayer == address(0)) revert ZeroAddress();\n // Check if the transaction has already been relayed\n if (bridgeRelays(transactionId)) revert TransactionRelayed();\n if (transaction.destChainId != uint32(block.chainid)) revert ChainIncorrect();\n // Check the deadline for relay to happen\n if (block.timestamp \u003e transaction.deadline) revert DeadlineExceeded();\n // Check the exclusivity period, if it is still ongoing\n // forgefmt: disable-next-item\n if (\n transaction.exclusivityRelayer != address(0) \u0026\u0026\n transaction.exclusivityRelayer != relayer \u0026\u0026\n block.timestamp \u003c= transaction.exclusivityEndTime\n ) {\n revert ExclusivityPeriodNotPassed();\n }\n }\n}\n","language":"Solidity","languageVersion":"0.8.24","compilerVersion":"0.8.24","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../","srcMap":"","srcMapRuntime":"","abiDefinition":[{"inputs":[],"name":"AmountIncorrect","type":"error"},{"inputs":[],"name":"CallParamsLengthAboveMax","type":"error"},{"inputs":[],"name":"ChainIncorrect","type":"error"},{"inputs":[],"name":"DeadlineExceeded","type":"error"},{"inputs":[],"name":"DeadlineNotExceeded","type":"error"},{"inputs":[],"name":"DeadlineTooShort","type":"error"},{"inputs":[],"name":"DisputePeriodNotPassed","type":"error"},{"inputs":[],"name":"DisputePeriodPassed","type":"error"},{"inputs":[],"name":"ExclusivityParamsIncorrect","type":"error"},{"inputs":[],"name":"ExclusivityPeriodNotPassed","type":"error"},{"inputs":[],"name":"MsgValueIncorrect","type":"error"},{"inputs":[],"name":"NativeTokenCallValueNotSupported","type":"error"},{"inputs":[],"name":"RecipientIncorrectReturnValue","type":"error"},{"inputs":[],"name":"RecipientNoReturnValue","type":"error"},{"inputs":[],"name":"SenderIncorrect","type":"error"},{"inputs":[],"name":"StatusIncorrect","type":"error"},{"inputs":[],"name":"TransactionRelayed","type":"error"},{"inputs":[],"name":"ZeroAddress","type":"error"}],"userDoc":{"kind":"user","methods":{},"version":1},"developerDoc":{"kind":"dev","methods":{},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[],\"name\":\"AmountIncorrect\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"CallParamsLengthAboveMax\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ChainIncorrect\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DeadlineExceeded\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DeadlineNotExceeded\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DeadlineTooShort\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DisputePeriodNotPassed\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DisputePeriodPassed\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ExclusivityParamsIncorrect\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ExclusivityPeriodNotPassed\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"MsgValueIncorrect\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"NativeTokenCallValueNotSupported\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"RecipientIncorrectReturnValue\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"RecipientNoReturnValue\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"SenderIncorrect\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"StatusIncorrect\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"TransactionRelayed\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ZeroAddress\",\"type\":\"error\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeV2.sol\":\"IFastBridgeV2Errors\"},\"evmVersion\":\"shanghai\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeV2.sol\":{\"keccak256\":\"0x7cd0f885e80e2bdaa638bc32ae7af7d2e248f99ce4b354c217d0f0f7d7302e0a\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://7ccf28df0bd7b4606986585acd8622ed9b4e81379690061bb66088f0a2270af1\",\"dweb:/ipfs/QmTf7HNdHZkK6vmx8ZgewycQEb72oLD9nPwBpsM5reMstQ\"]}},\"version\":1}"},"hashes":{}},"solidity/FastBridgeV2.sol:SafeERC20":{"code":"0x60556032600b8282823980515f1a607314602657634e487b7160e01b5f525f60045260245ffd5b305f52607381538281f3fe730000000000000000000000000000000000000000301460806040525f80fdfea26469706673582212206104d055d945cd85c5e0a242eb38679d97b94eed1093fc3540437ea8fe4ace7364736f6c63430008180033","runtime-code":"0x730000000000000000000000000000000000000000301460806040525f80fdfea26469706673582212206104d055d945cd85c5e0a242eb38679d97b94eed1093fc3540437ea8fe4ace7364736f6c63430008180033","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.24 ^0.8.0 ^0.8.20;\n\n// contracts/interfaces/IAdmin.sol\n\ninterface IAdmin {\n // ============ Events ============\n\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n event ChainGasAmountUpdated(uint256 oldChainGasAmount, uint256 newChainGasAmount);\n\n // ============ Methods ============\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n\n function setChainGasAmount(uint256 newChainGasAmount) external;\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IFastBridgeRecipient.sol\n\ninterface IFastBridgeRecipient {\n function fastBridgeTransferReceived(\n address token,\n uint256 amount,\n bytes memory callParams\n )\n external\n payable\n returns (bytes4);\n}\n\n// contracts/interfaces/IFastBridgeV2Errors.sol\n\ninterface IFastBridgeV2Errors {\n error AmountIncorrect();\n error CallParamsLengthAboveMax();\n error ChainIncorrect();\n error ExclusivityParamsIncorrect();\n error MsgValueIncorrect();\n error NativeTokenCallValueNotSupported();\n error SenderIncorrect();\n error StatusIncorrect();\n error ZeroAddress();\n\n error RecipientIncorrectReturnValue();\n error RecipientNoReturnValue();\n\n error DeadlineExceeded();\n error DeadlineNotExceeded();\n error DeadlineTooShort();\n error DisputePeriodNotPassed();\n error DisputePeriodPassed();\n error ExclusivityPeriodNotPassed();\n\n error TransactionRelayed();\n}\n\n// contracts/libs/Errors.sol\n\nerror DeadlineExceeded();\nerror DeadlineNotExceeded();\nerror DeadlineTooShort();\nerror InsufficientOutputAmount();\n\nerror MsgValueIncorrect();\nerror PoolNotFound();\nerror TokenAddressMismatch();\nerror TokenNotContract();\nerror TokenNotETH();\nerror TokensIdentical();\n\nerror ChainIncorrect();\nerror AmountIncorrect();\nerror ZeroAddress();\n\nerror DisputePeriodNotPassed();\nerror DisputePeriodPassed();\nerror SenderIncorrect();\nerror StatusIncorrect();\nerror TransactionIdIncorrect();\nerror TransactionRelayed();\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// contracts/interfaces/IFastBridgeV2.sol\n\ninterface IFastBridgeV2 is IFastBridge {\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n struct BridgeTxDetails {\n BridgeStatus status;\n uint40 proofBlockTimestamp;\n uint48 proofBlockNumber;\n address proofRelayer;\n }\n\n struct BridgeRelay {\n uint48 blockNumber;\n uint48 blockTimestamp;\n address relayer;\n }\n\n /// @notice New params introduced in the FastBridgeV2.\n /// We are passing fields from the older BridgeParams struct outside of this struct\n /// for backwards compatibility.\n /// Note: quoteRelayer and quoteExclusivitySeconds are either both zero (indicating no exclusivity)\n /// or both non-zero (indicating exclusivity for the given period).\n /// Note: callValue \u003e 0 can NOT be used with destToken = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE (ETH_ADDRESS)\n /// @param quoteRelayer Relayer that provided the quote for the transaction\n /// @param quoteExclusivitySeconds Period of time the quote relayer is guaranteed exclusivity after user's deposit\n /// @param quoteId Unique quote identifier used for tracking the quote\n /// @param callValue ETH value to send to the recipient (if any)\n /// @param callParams Parameters for the arbitrary call to the destination recipient (if any)\n struct BridgeParamsV2 {\n address quoteRelayer;\n int256 quoteExclusivitySeconds;\n bytes quoteId;\n uint256 callValue;\n bytes callParams;\n }\n\n /// @notice Updated bridge transaction struct to include parameters introduced in FastBridgeV2.\n /// Note: only `exclusivityRelayer` can fill such a transaction until `exclusivityEndTime`.\n /// TODO: consider changing the encoding scheme to prevent spending extra gas on decoding.\n struct BridgeTransactionV2 {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n uint256 callValue; // ETH value to send to the recipient (if any) - replaces V1's sendChainGas flag\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n address exclusivityRelayer;\n uint256 exclusivityEndTime;\n bytes callParams;\n }\n\n event BridgeQuoteDetails(bytes32 indexed transactionId, bytes quoteId);\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability\n /// to provide temporary exclusivity fill rights for the quote relayer.\n /// @param params The parameters required to bridge\n /// @param paramsV2 The parameters for exclusivity fill rights (optional, can be left empty)\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function relay(bytes memory request, address relayer) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param transactionId The transaction id associated with the encoded bridge transaction to prove\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital.\n /// @notice Can only send funds to the relayer address on the proof.\n /// @param request The encoded bridge transaction to claim on origin chain\n function claim(bytes memory request) external;\n /// @notice Checks if a transaction has been relayed\n /// @param transactionId The ID of the transaction to check\n /// @return True if the transaction has been relayed, false otherwise\n function bridgeRelays(bytes32 transactionId) external view returns (bool);\n\n /// @notice Returns the status of a bridge transaction\n /// @param transactionId The ID of the bridge transaction\n /// @return BridgeStatus Status of the bridge transaction\n function bridgeStatuses(bytes32 transactionId) external view returns (BridgeStatus);\n\n /// @notice Returns the timestamp and relayer of a bridge proof\n /// @param transactionId The ID of the bridge transaction\n /// @return timestamp The timestamp of the bridge proof\n /// @return relayer The relayer address of the bridge proof\n function bridgeProofs(bytes32 transactionId) external view returns (uint96 timestamp, address relayer);\n\n /// @notice Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\n /// @param request The bridge request to decode\n function getBridgeTransactionV2(bytes memory request) external view returns (BridgeTransactionV2 memory);\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// contracts/libs/UniversalToken.sol\n\nlibrary UniversalTokenLib {\n using SafeERC20 for IERC20;\n\n address internal constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Transfers tokens to the given account. Reverts if transfer is not successful.\n /// @dev This might trigger fallback, if ETH is transferred to the contract.\n /// Make sure this can not lead to reentrancy attacks.\n function universalTransfer(address token, address to, uint256 value) internal {\n // Don't do anything, if need to send tokens to this address\n if (to == address(this)) return;\n // Don't do anything, if trying to send zero value\n if (value == 0) return;\n if (token == ETH_ADDRESS) {\n /// @dev Note: this can potentially lead to executing code in `to`.\n // solhint-disable-next-line avoid-low-level-calls\n (bool success,) = to.call{value: value}(\"\");\n require(success, \"ETH transfer failed\");\n } else {\n IERC20(token).safeTransfer(to, value);\n }\n }\n\n /// @notice Issues an infinite allowance to the spender, if the current allowance is insufficient\n /// to spend the given amount.\n function universalApproveInfinity(address token, address spender, uint256 amountToSpend) internal {\n // ETH Chad doesn't require your approval\n if (token == ETH_ADDRESS) return;\n // No-op if allowance is already sufficient\n uint256 allowance = IERC20(token).allowance(address(this), spender);\n if (allowance \u003e= amountToSpend) return;\n // Otherwise, reset approval to 0 and set to max allowance\n if (allowance \u003e 0) IERC20(token).safeDecreaseAllowance(spender, allowance);\n IERC20(token).safeIncreaseAllowance(spender, type(uint256).max);\n }\n\n /// @notice Returns the balance of the given token (or native ETH) for the given account.\n function universalBalanceOf(address token, address account) internal view returns (uint256) {\n if (token == ETH_ADDRESS) {\n return account.balance;\n } else {\n return IERC20(token).balanceOf(account);\n }\n }\n\n /// @dev Checks that token is a contract and not ETH_ADDRESS.\n function assertIsContract(address token) internal view {\n // Check that ETH_ADDRESS was not used (in case this is a predeploy on any of the chains)\n if (token == UniversalTokenLib.ETH_ADDRESS) revert TokenNotContract();\n // Check that token is not an EOA\n if (token.code.length == 0) revert TokenNotContract();\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/Admin.sol\n\ncontract Admin is IAdmin, AccessControlEnumerable {\n using UniversalTokenLib for address;\n\n bytes32 public constant RELAYER_ROLE = keccak256(\"RELAYER_ROLE\");\n bytes32 public constant REFUNDER_ROLE = keccak256(\"REFUNDER_ROLE\");\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n uint256 public constant FEE_BPS = 1e6;\n uint256 public constant FEE_RATE_MAX = 0.01e6; // max 1% on origin amount\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Chain gas amount to forward as rebate if requested\n uint256 public chainGasAmount;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n }\n\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n require(newFeeRate \u003c= FEE_RATE_MAX, \"newFeeRate \u003e max\");\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n token.universalTransfer(recipient, feeAmount);\n emit FeesSwept(token, recipient, feeAmount);\n }\n\n function setChainGasAmount(uint256 newChainGasAmount) external onlyRole(GOVERNOR_ROLE) {\n uint256 oldChainGasAmount = chainGasAmount;\n chainGasAmount = newChainGasAmount;\n emit ChainGasAmountUpdated(oldChainGasAmount, newChainGasAmount);\n }\n}\n\n// contracts/FastBridgeV2.sol\n\n/// @notice FastBridgeV2 is a contract for bridging tokens across chains.\ncontract FastBridgeV2 is Admin, IFastBridgeV2, IFastBridgeV2Errors {\n using SafeERC20 for IERC20;\n using UniversalTokenLib for address;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Delay for a transaction after which it could be permisionlessly refunded\n uint256 public constant REFUND_DELAY = 7 days;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n /// @notice Maximum length of accepted callParams\n uint256 public constant MAX_CALL_PARAMS_LENGTH = 2 ** 16 - 1;\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeTxDetails) public bridgeTxDetails;\n /// @notice Relay details on destination chain\n mapping(bytes32 =\u003e BridgeRelay) public bridgeRelayDetails;\n /// @notice Unique bridge nonces tracked per originSender\n mapping(address =\u003e uint256) public senderNonces;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Replaced by senderNonces\n uint256 public immutable nonce = 0;\n /// @notice the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n bridge({\n params: params,\n paramsV2: BridgeParamsV2({\n quoteRelayer: address(0),\n quoteExclusivitySeconds: 0,\n quoteId: bytes(\"\"),\n callValue: 0,\n callParams: bytes(\"\")\n })\n });\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes memory request) external payable {\n relay({request: request, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes memory request, bytes32 destTxHash) external {\n prove({transactionId: keccak256(request), destTxHash: destTxHash, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridgeV2\n function claim(bytes memory request) external {\n claim({request: request, to: address(0)});\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003e DISPUTE_PERIOD) {\n revert DisputePeriodPassed();\n }\n\n // @dev relayer gets slashed effectively if dest relay has gone thru\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n bridgeTxDetails[transactionId].proofRelayer = address(0);\n bridgeTxDetails[transactionId].proofBlockTimestamp = 0;\n bridgeTxDetails[transactionId].proofBlockNumber = 0;\n\n emit BridgeProofDisputed(transactionId, msg.sender);\n }\n\n /// @inheritdoc IFastBridge\n function refund(bytes memory request) external {\n bytes32 transactionId = keccak256(request);\n\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n\n if (bridgeTxDetails[transactionId].status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n\n if (hasRole(REFUNDER_ROLE, msg.sender)) {\n // Refunder can refund if deadline has passed\n if (block.timestamp \u003c= transaction.deadline) revert DeadlineNotExceeded();\n } else {\n // Permissionless refund is allowed after REFUND_DELAY\n if (block.timestamp \u003c= transaction.deadline + REFUND_DELAY) revert DeadlineNotExceeded();\n }\n\n // if all checks passed, set to REFUNDED status\n bridgeTxDetails[transactionId].status = BridgeStatus.REFUNDED;\n\n // transfer origin collateral back to original sender\n address to = transaction.originSender;\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount + transaction.originFeeAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (bridgeTxDetails[transactionId].proofRelayer != relayer) revert SenderIncorrect();\n return _timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n /// @dev This method is added to achieve backwards compatibility with decoding requests into V1 structs:\n /// - `callValue` is partially reported as a zero/non-zero flag\n /// - `callParams` is ignored\n /// In order to process all kinds of requests use getBridgeTransactionV2 instead.\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory) {\n // Try decoding into V2 struct first. This will revert if V1 struct is passed\n try this.getBridgeTransactionV2(request) returns (BridgeTransactionV2 memory txV2) {\n // Note: we entirely ignore the callParams field, as it was not present in V1\n return BridgeTransaction({\n originChainId: txV2.originChainId,\n destChainId: txV2.destChainId,\n originSender: txV2.originSender,\n destRecipient: txV2.destRecipient,\n originToken: txV2.originToken,\n destToken: txV2.destToken,\n originAmount: txV2.originAmount,\n destAmount: txV2.destAmount,\n originFeeAmount: txV2.originFeeAmount,\n sendChainGas: txV2.callValue != 0,\n deadline: txV2.deadline,\n nonce: txV2.nonce\n });\n } catch {\n // Fallback to V1 struct\n return abi.decode(request, (BridgeTransaction));\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) public payable {\n int256 exclusivityEndTime = int256(block.timestamp) + paramsV2.quoteExclusivitySeconds;\n _validateBridgeParams(params, paramsV2, exclusivityEndTime);\n\n // transfer tokens to bridge contract\n /// @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _pullToken(params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n\n // set status to requested\n bytes memory request = abi.encode(\n BridgeTransactionV2({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n callValue: paramsV2.callValue,\n deadline: params.deadline,\n nonce: senderNonces[params.sender]++, // increment nonce on every bridge\n exclusivityRelayer: paramsV2.quoteRelayer,\n // We checked exclusivityEndTime to be in range (0 .. params.deadline] above, so can safely cast\n exclusivityEndTime: uint256(exclusivityEndTime),\n callParams: paramsV2.callParams\n })\n );\n bytes32 transactionId = keccak256(request);\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n\n emit BridgeRequested({\n transactionId: transactionId,\n sender: params.sender,\n request: request,\n destChainId: params.dstChainId,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n sendChainGas: paramsV2.callValue != 0\n });\n emit BridgeQuoteDetails(transactionId, paramsV2.quoteId);\n }\n\n /// @inheritdoc IFastBridgeV2\n function relay(bytes memory request, address relayer) public payable {\n bytes32 transactionId = keccak256(request);\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n _validateRelayParams(transaction, transactionId, relayer);\n // mark bridge transaction as relayed\n bridgeRelayDetails[transactionId] =\n BridgeRelay({blockNumber: uint48(block.number), blockTimestamp: uint48(block.timestamp), relayer: relayer});\n\n // transfer tokens to recipient on destination chain and do an arbitrary call if requested\n address to = transaction.destRecipient;\n address token = transaction.destToken;\n uint256 amount = transaction.destAmount;\n\n // All state changes have been done at this point, can proceed to the external calls.\n // This follows the checks-effects-interactions pattern to mitigate potential reentrancy attacks.\n if (token == UniversalTokenLib.ETH_ADDRESS) {\n // For ETH non-zero callValue is not allowed\n if (transaction.callValue != 0) revert NativeTokenCallValueNotSupported();\n // Check that the correct msg.value was sent\n if (msg.value != amount) revert MsgValueIncorrect();\n } else {\n // For ERC20s, we check that the correct msg.value was sent\n if (msg.value != transaction.callValue) revert MsgValueIncorrect();\n // We need to transfer the tokens from the Relayer to the recipient first before performing an\n // optional post-transfer arbitrary call.\n IERC20(token).safeTransferFrom(msg.sender, to, amount);\n }\n\n if (transaction.callParams.length != 0) {\n // Arbitrary call requested, perform it while supplying full msg.value to the recipient\n // Note: if token has a fee on transfers, the recipient will have received less than `amount`.\n // This is a very niche edge case and should be handled by the recipient contract.\n _checkedCallRecipient({recipient: to, token: token, amount: amount, callParams: transaction.callParams});\n } else if (msg.value != 0) {\n // No arbitrary call requested, but msg.value was sent. This is either a relay with ETH,\n // or a non-zero callValue request with an ERC20. In both cases, transfer the ETH to the recipient.\n Address.sendValue(payable(to), msg.value);\n }\n\n emit BridgeRelayed({\n transactionId: transactionId,\n relayer: relayer,\n to: to,\n originChainId: transaction.originChainId,\n originToken: transaction.originToken,\n destToken: transaction.destToken,\n originAmount: transaction.originAmount,\n destAmount: transaction.destAmount,\n chainGasAmount: transaction.callValue\n });\n }\n\n /// @inheritdoc IFastBridgeV2\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) public onlyRole(RELAYER_ROLE) {\n // update bridge tx status given proof provided\n if (bridgeTxDetails[transactionId].status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n bridgeTxDetails[transactionId].status = BridgeStatus.RELAYER_PROVED;\n bridgeTxDetails[transactionId].proofBlockTimestamp = uint40(block.timestamp);\n bridgeTxDetails[transactionId].proofBlockNumber = uint48(block.number);\n bridgeTxDetails[transactionId].proofRelayer = relayer;\n\n emit BridgeProofProvided(transactionId, relayer, destTxHash);\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes memory request, address to) public {\n bytes32 transactionId = keccak256(request);\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n\n // update bridge tx status if able to claim origin collateral\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n\n // if \"to\" is zero addr, permissionlessly send funds to proven relayer\n if (to == address(0)) {\n to = bridgeTxDetails[transactionId].proofRelayer;\n } else if (bridgeTxDetails[transactionId].proofRelayer != msg.sender) {\n revert SenderIncorrect();\n }\n\n if (_timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003c= DISPUTE_PERIOD) {\n revert DisputePeriodNotPassed();\n }\n\n bridgeTxDetails[transactionId].status = BridgeStatus.RELAYER_CLAIMED;\n\n // update protocol fees if origin fee amount exists\n if (transaction.originFeeAmount \u003e 0) protocolFees[transaction.originToken] += transaction.originFeeAmount;\n\n // transfer origin collateral less fee to specified address\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositClaimed(transactionId, bridgeTxDetails[transactionId].proofRelayer, to, token, amount);\n }\n\n function bridgeStatuses(bytes32 transactionId) public view returns (BridgeStatus status) {\n return bridgeTxDetails[transactionId].status;\n }\n\n function bridgeProofs(bytes32 transactionId) public view returns (uint96 timestamp, address relayer) {\n timestamp = bridgeTxDetails[transactionId].proofBlockTimestamp;\n relayer = bridgeTxDetails[transactionId].proofRelayer;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeRelays(bytes32 transactionId) public view returns (bool) {\n // has this transactionId been relayed?\n return bridgeRelayDetails[transactionId].relayer != address(0);\n }\n\n /// @inheritdoc IFastBridgeV2\n function getBridgeTransactionV2(bytes memory request) public pure returns (BridgeTransactionV2 memory) {\n return abi.decode(request, (BridgeTransactionV2));\n }\n\n /// @notice Pulls a requested token from the user to this contract.\n function _pullToken(address token, uint256 amount) internal returns (uint256 amountPulled) {\n if (token == UniversalTokenLib.ETH_ADDRESS) {\n // For ETH we just need to check that the supplied msg.value is correct\n if (amount != msg.value) revert MsgValueIncorrect();\n amountPulled = msg.value;\n } else {\n token.assertIsContract();\n // Record token balance before transfer\n amountPulled = IERC20(token).balanceOf(address(this));\n // Token needs to be pulled only if msg.value is zero\n // This way user can specify WETH as the origin asset\n IERC20(token).safeTransferFrom(msg.sender, address(this), amount);\n // Use the difference between the recorded balance and the current balance as the amountPulled\n amountPulled = IERC20(token).balanceOf(address(this)) - amountPulled;\n }\n }\n\n /// @notice Calls the Recipient's hook function with the specified callParams and performs\n /// all the necessary checks for the returned value.\n function _checkedCallRecipient(\n address recipient,\n address token,\n uint256 amount,\n bytes memory callParams\n )\n internal\n {\n bytes memory hookData =\n abi.encodeCall(IFastBridgeRecipient.fastBridgeTransferReceived, (token, amount, callParams));\n // This will bubble any revert messages from the hook function\n bytes memory returnData = Address.functionCallWithValue({target: recipient, data: hookData, value: msg.value});\n // Explicit revert if no return data at all\n if (returnData.length == 0) revert RecipientNoReturnValue();\n // Check that exactly a single return value was returned\n if (returnData.length != 32) revert RecipientIncorrectReturnValue();\n // Return value should be abi-encoded hook function selector\n if (bytes32(returnData) != bytes32(IFastBridgeRecipient.fastBridgeTransferReceived.selector)) {\n revert RecipientIncorrectReturnValue();\n }\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint40(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint40).max but\n /// proof.timestamp \u003c type(uint40).max via unchecked statement\n /// @param proofBlockTimestamp The bridge proof block timestamp\n /// @return delta Time delta since proof submitted\n function _timeSince(uint40 proofBlockTimestamp) internal view returns (uint256 delta) {\n unchecked {\n delta = uint40(block.timestamp) - proofBlockTimestamp;\n }\n }\n\n /// @notice Performs all the necessary checks for a bridge to happen.\n /// @dev There's no good way to refactor this function to reduce cyclomatic complexity due to\n /// the number of checks that need to be performed, so we skip the code-complexity rule here.\n // solhint-disable-next-line code-complexity\n function _validateBridgeParams(\n BridgeParams memory params,\n BridgeParamsV2 memory paramsV2,\n int256 exclusivityEndTime\n )\n internal\n view\n {\n // Check V1 (legacy) params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.sender == address(0) || params.to == address(0)) revert ZeroAddress();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n // Check V2 params\n if (paramsV2.callParams.length \u003e MAX_CALL_PARAMS_LENGTH) revert CallParamsLengthAboveMax();\n if (paramsV2.callValue != 0 \u0026\u0026 params.destToken == UniversalTokenLib.ETH_ADDRESS) {\n revert NativeTokenCallValueNotSupported();\n }\n // exclusivityEndTime must be in range (0 .. params.deadline]\n if (exclusivityEndTime \u003c= 0 || exclusivityEndTime \u003e int256(params.deadline)) {\n revert ExclusivityParamsIncorrect();\n }\n }\n\n /// @notice Performs all the necessary checks for a relay to happen.\n function _validateRelayParams(\n BridgeTransactionV2 memory transaction,\n bytes32 transactionId,\n address relayer\n )\n internal\n view\n {\n if (relayer == address(0)) revert ZeroAddress();\n // Check if the transaction has already been relayed\n if (bridgeRelays(transactionId)) revert TransactionRelayed();\n if (transaction.destChainId != uint32(block.chainid)) revert ChainIncorrect();\n // Check the deadline for relay to happen\n if (block.timestamp \u003e transaction.deadline) revert DeadlineExceeded();\n // Check the exclusivity period, if it is still ongoing\n // forgefmt: disable-next-item\n if (\n transaction.exclusivityRelayer != address(0) \u0026\u0026\n transaction.exclusivityRelayer != relayer \u0026\u0026\n block.timestamp \u003c= transaction.exclusivityEndTime\n ) {\n revert ExclusivityPeriodNotPassed();\n }\n }\n}\n","language":"Solidity","languageVersion":"0.8.24","compilerVersion":"0.8.24","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../","srcMap":"45745:5018:0:-:0;;;;;;;;;;;;;;;-1:-1:-1;;;45745:5018:0;;;;;;;;;;;;;;;;;","srcMapRuntime":"45745:5018:0:-:0;;;;;;;;","abiDefinition":[{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"currentAllowance","type":"uint256"},{"internalType":"uint256","name":"requestedDecrease","type":"uint256"}],"name":"SafeERC20FailedDecreaseAllowance","type":"error"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"SafeERC20FailedOperation","type":"error"}],"userDoc":{"kind":"user","methods":{},"version":1},"developerDoc":{"details":"Wrappers around ERC20 operations that throw on failure (when the token contract returns false). Tokens that return no value (and instead revert or throw on failure) are also supported, non-reverting calls are assumed to be successful. To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract, which allows you to call the safe operations as `token.safeTransfer(...)`, etc.","errors":{"SafeERC20FailedDecreaseAllowance(address,uint256,uint256)":[{"details":"Indicates a failed `decreaseAllowance` request."}],"SafeERC20FailedOperation(address)":[{"details":"An operation with an ERC20 token failed."}]},"kind":"dev","methods":{},"title":"SafeERC20","version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"currentAllowance\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"requestedDecrease\",\"type\":\"uint256\"}],\"name\":\"SafeERC20FailedDecreaseAllowance\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"}],\"name\":\"SafeERC20FailedOperation\",\"type\":\"error\"}],\"devdoc\":{\"details\":\"Wrappers around ERC20 operations that throw on failure (when the token contract returns false). Tokens that return no value (and instead revert or throw on failure) are also supported, non-reverting calls are assumed to be successful. To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract, which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\",\"errors\":{\"SafeERC20FailedDecreaseAllowance(address,uint256,uint256)\":[{\"details\":\"Indicates a failed `decreaseAllowance` request.\"}],\"SafeERC20FailedOperation(address)\":[{\"details\":\"An operation with an ERC20 token failed.\"}]},\"kind\":\"dev\",\"methods\":{},\"title\":\"SafeERC20\",\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeV2.sol\":\"SafeERC20\"},\"evmVersion\":\"shanghai\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeV2.sol\":{\"keccak256\":\"0x7cd0f885e80e2bdaa638bc32ae7af7d2e248f99ce4b354c217d0f0f7d7302e0a\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://7ccf28df0bd7b4606986585acd8622ed9b4e81379690061bb66088f0a2270af1\",\"dweb:/ipfs/QmTf7HNdHZkK6vmx8ZgewycQEb72oLD9nPwBpsM5reMstQ\"]}},\"version\":1}"},"hashes":{}},"solidity/FastBridgeV2.sol:UniversalTokenLib":{"code":"0x60556032600b8282823980515f1a607314602657634e487b7160e01b5f525f60045260245ffd5b305f52607381538281f3fe730000000000000000000000000000000000000000301460806040525f80fdfea2646970667358221220b863ead2f0a667d62ff1983d9a28f2cdc6740a5303e83e27e29c037676ea45c264736f6c63430008180033","runtime-code":"0x730000000000000000000000000000000000000000301460806040525f80fdfea2646970667358221220b863ead2f0a667d62ff1983d9a28f2cdc6740a5303e83e27e29c037676ea45c264736f6c63430008180033","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.24 ^0.8.0 ^0.8.20;\n\n// contracts/interfaces/IAdmin.sol\n\ninterface IAdmin {\n // ============ Events ============\n\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n event ChainGasAmountUpdated(uint256 oldChainGasAmount, uint256 newChainGasAmount);\n\n // ============ Methods ============\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n\n function setChainGasAmount(uint256 newChainGasAmount) external;\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IFastBridgeRecipient.sol\n\ninterface IFastBridgeRecipient {\n function fastBridgeTransferReceived(\n address token,\n uint256 amount,\n bytes memory callParams\n )\n external\n payable\n returns (bytes4);\n}\n\n// contracts/interfaces/IFastBridgeV2Errors.sol\n\ninterface IFastBridgeV2Errors {\n error AmountIncorrect();\n error CallParamsLengthAboveMax();\n error ChainIncorrect();\n error ExclusivityParamsIncorrect();\n error MsgValueIncorrect();\n error NativeTokenCallValueNotSupported();\n error SenderIncorrect();\n error StatusIncorrect();\n error ZeroAddress();\n\n error RecipientIncorrectReturnValue();\n error RecipientNoReturnValue();\n\n error DeadlineExceeded();\n error DeadlineNotExceeded();\n error DeadlineTooShort();\n error DisputePeriodNotPassed();\n error DisputePeriodPassed();\n error ExclusivityPeriodNotPassed();\n\n error TransactionRelayed();\n}\n\n// contracts/libs/Errors.sol\n\nerror DeadlineExceeded();\nerror DeadlineNotExceeded();\nerror DeadlineTooShort();\nerror InsufficientOutputAmount();\n\nerror MsgValueIncorrect();\nerror PoolNotFound();\nerror TokenAddressMismatch();\nerror TokenNotContract();\nerror TokenNotETH();\nerror TokensIdentical();\n\nerror ChainIncorrect();\nerror AmountIncorrect();\nerror ZeroAddress();\n\nerror DisputePeriodNotPassed();\nerror DisputePeriodPassed();\nerror SenderIncorrect();\nerror StatusIncorrect();\nerror TransactionIdIncorrect();\nerror TransactionRelayed();\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// contracts/interfaces/IFastBridgeV2.sol\n\ninterface IFastBridgeV2 is IFastBridge {\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n struct BridgeTxDetails {\n BridgeStatus status;\n uint40 proofBlockTimestamp;\n uint48 proofBlockNumber;\n address proofRelayer;\n }\n\n struct BridgeRelay {\n uint48 blockNumber;\n uint48 blockTimestamp;\n address relayer;\n }\n\n /// @notice New params introduced in the FastBridgeV2.\n /// We are passing fields from the older BridgeParams struct outside of this struct\n /// for backwards compatibility.\n /// Note: quoteRelayer and quoteExclusivitySeconds are either both zero (indicating no exclusivity)\n /// or both non-zero (indicating exclusivity for the given period).\n /// Note: callValue \u003e 0 can NOT be used with destToken = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE (ETH_ADDRESS)\n /// @param quoteRelayer Relayer that provided the quote for the transaction\n /// @param quoteExclusivitySeconds Period of time the quote relayer is guaranteed exclusivity after user's deposit\n /// @param quoteId Unique quote identifier used for tracking the quote\n /// @param callValue ETH value to send to the recipient (if any)\n /// @param callParams Parameters for the arbitrary call to the destination recipient (if any)\n struct BridgeParamsV2 {\n address quoteRelayer;\n int256 quoteExclusivitySeconds;\n bytes quoteId;\n uint256 callValue;\n bytes callParams;\n }\n\n /// @notice Updated bridge transaction struct to include parameters introduced in FastBridgeV2.\n /// Note: only `exclusivityRelayer` can fill such a transaction until `exclusivityEndTime`.\n /// TODO: consider changing the encoding scheme to prevent spending extra gas on decoding.\n struct BridgeTransactionV2 {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n uint256 callValue; // ETH value to send to the recipient (if any) - replaces V1's sendChainGas flag\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n address exclusivityRelayer;\n uint256 exclusivityEndTime;\n bytes callParams;\n }\n\n event BridgeQuoteDetails(bytes32 indexed transactionId, bytes quoteId);\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability\n /// to provide temporary exclusivity fill rights for the quote relayer.\n /// @param params The parameters required to bridge\n /// @param paramsV2 The parameters for exclusivity fill rights (optional, can be left empty)\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function relay(bytes memory request, address relayer) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param transactionId The transaction id associated with the encoded bridge transaction to prove\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital.\n /// @notice Can only send funds to the relayer address on the proof.\n /// @param request The encoded bridge transaction to claim on origin chain\n function claim(bytes memory request) external;\n /// @notice Checks if a transaction has been relayed\n /// @param transactionId The ID of the transaction to check\n /// @return True if the transaction has been relayed, false otherwise\n function bridgeRelays(bytes32 transactionId) external view returns (bool);\n\n /// @notice Returns the status of a bridge transaction\n /// @param transactionId The ID of the bridge transaction\n /// @return BridgeStatus Status of the bridge transaction\n function bridgeStatuses(bytes32 transactionId) external view returns (BridgeStatus);\n\n /// @notice Returns the timestamp and relayer of a bridge proof\n /// @param transactionId The ID of the bridge transaction\n /// @return timestamp The timestamp of the bridge proof\n /// @return relayer The relayer address of the bridge proof\n function bridgeProofs(bytes32 transactionId) external view returns (uint96 timestamp, address relayer);\n\n /// @notice Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\n /// @param request The bridge request to decode\n function getBridgeTransactionV2(bytes memory request) external view returns (BridgeTransactionV2 memory);\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// contracts/libs/UniversalToken.sol\n\nlibrary UniversalTokenLib {\n using SafeERC20 for IERC20;\n\n address internal constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Transfers tokens to the given account. Reverts if transfer is not successful.\n /// @dev This might trigger fallback, if ETH is transferred to the contract.\n /// Make sure this can not lead to reentrancy attacks.\n function universalTransfer(address token, address to, uint256 value) internal {\n // Don't do anything, if need to send tokens to this address\n if (to == address(this)) return;\n // Don't do anything, if trying to send zero value\n if (value == 0) return;\n if (token == ETH_ADDRESS) {\n /// @dev Note: this can potentially lead to executing code in `to`.\n // solhint-disable-next-line avoid-low-level-calls\n (bool success,) = to.call{value: value}(\"\");\n require(success, \"ETH transfer failed\");\n } else {\n IERC20(token).safeTransfer(to, value);\n }\n }\n\n /// @notice Issues an infinite allowance to the spender, if the current allowance is insufficient\n /// to spend the given amount.\n function universalApproveInfinity(address token, address spender, uint256 amountToSpend) internal {\n // ETH Chad doesn't require your approval\n if (token == ETH_ADDRESS) return;\n // No-op if allowance is already sufficient\n uint256 allowance = IERC20(token).allowance(address(this), spender);\n if (allowance \u003e= amountToSpend) return;\n // Otherwise, reset approval to 0 and set to max allowance\n if (allowance \u003e 0) IERC20(token).safeDecreaseAllowance(spender, allowance);\n IERC20(token).safeIncreaseAllowance(spender, type(uint256).max);\n }\n\n /// @notice Returns the balance of the given token (or native ETH) for the given account.\n function universalBalanceOf(address token, address account) internal view returns (uint256) {\n if (token == ETH_ADDRESS) {\n return account.balance;\n } else {\n return IERC20(token).balanceOf(account);\n }\n }\n\n /// @dev Checks that token is a contract and not ETH_ADDRESS.\n function assertIsContract(address token) internal view {\n // Check that ETH_ADDRESS was not used (in case this is a predeploy on any of the chains)\n if (token == UniversalTokenLib.ETH_ADDRESS) revert TokenNotContract();\n // Check that token is not an EOA\n if (token.code.length == 0) revert TokenNotContract();\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/Admin.sol\n\ncontract Admin is IAdmin, AccessControlEnumerable {\n using UniversalTokenLib for address;\n\n bytes32 public constant RELAYER_ROLE = keccak256(\"RELAYER_ROLE\");\n bytes32 public constant REFUNDER_ROLE = keccak256(\"REFUNDER_ROLE\");\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n uint256 public constant FEE_BPS = 1e6;\n uint256 public constant FEE_RATE_MAX = 0.01e6; // max 1% on origin amount\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Chain gas amount to forward as rebate if requested\n uint256 public chainGasAmount;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n }\n\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n require(newFeeRate \u003c= FEE_RATE_MAX, \"newFeeRate \u003e max\");\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n token.universalTransfer(recipient, feeAmount);\n emit FeesSwept(token, recipient, feeAmount);\n }\n\n function setChainGasAmount(uint256 newChainGasAmount) external onlyRole(GOVERNOR_ROLE) {\n uint256 oldChainGasAmount = chainGasAmount;\n chainGasAmount = newChainGasAmount;\n emit ChainGasAmountUpdated(oldChainGasAmount, newChainGasAmount);\n }\n}\n\n// contracts/FastBridgeV2.sol\n\n/// @notice FastBridgeV2 is a contract for bridging tokens across chains.\ncontract FastBridgeV2 is Admin, IFastBridgeV2, IFastBridgeV2Errors {\n using SafeERC20 for IERC20;\n using UniversalTokenLib for address;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Delay for a transaction after which it could be permisionlessly refunded\n uint256 public constant REFUND_DELAY = 7 days;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n /// @notice Maximum length of accepted callParams\n uint256 public constant MAX_CALL_PARAMS_LENGTH = 2 ** 16 - 1;\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeTxDetails) public bridgeTxDetails;\n /// @notice Relay details on destination chain\n mapping(bytes32 =\u003e BridgeRelay) public bridgeRelayDetails;\n /// @notice Unique bridge nonces tracked per originSender\n mapping(address =\u003e uint256) public senderNonces;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Replaced by senderNonces\n uint256 public immutable nonce = 0;\n /// @notice the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n bridge({\n params: params,\n paramsV2: BridgeParamsV2({\n quoteRelayer: address(0),\n quoteExclusivitySeconds: 0,\n quoteId: bytes(\"\"),\n callValue: 0,\n callParams: bytes(\"\")\n })\n });\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes memory request) external payable {\n relay({request: request, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes memory request, bytes32 destTxHash) external {\n prove({transactionId: keccak256(request), destTxHash: destTxHash, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridgeV2\n function claim(bytes memory request) external {\n claim({request: request, to: address(0)});\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003e DISPUTE_PERIOD) {\n revert DisputePeriodPassed();\n }\n\n // @dev relayer gets slashed effectively if dest relay has gone thru\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n bridgeTxDetails[transactionId].proofRelayer = address(0);\n bridgeTxDetails[transactionId].proofBlockTimestamp = 0;\n bridgeTxDetails[transactionId].proofBlockNumber = 0;\n\n emit BridgeProofDisputed(transactionId, msg.sender);\n }\n\n /// @inheritdoc IFastBridge\n function refund(bytes memory request) external {\n bytes32 transactionId = keccak256(request);\n\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n\n if (bridgeTxDetails[transactionId].status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n\n if (hasRole(REFUNDER_ROLE, msg.sender)) {\n // Refunder can refund if deadline has passed\n if (block.timestamp \u003c= transaction.deadline) revert DeadlineNotExceeded();\n } else {\n // Permissionless refund is allowed after REFUND_DELAY\n if (block.timestamp \u003c= transaction.deadline + REFUND_DELAY) revert DeadlineNotExceeded();\n }\n\n // if all checks passed, set to REFUNDED status\n bridgeTxDetails[transactionId].status = BridgeStatus.REFUNDED;\n\n // transfer origin collateral back to original sender\n address to = transaction.originSender;\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount + transaction.originFeeAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (bridgeTxDetails[transactionId].proofRelayer != relayer) revert SenderIncorrect();\n return _timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n /// @dev This method is added to achieve backwards compatibility with decoding requests into V1 structs:\n /// - `callValue` is partially reported as a zero/non-zero flag\n /// - `callParams` is ignored\n /// In order to process all kinds of requests use getBridgeTransactionV2 instead.\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory) {\n // Try decoding into V2 struct first. This will revert if V1 struct is passed\n try this.getBridgeTransactionV2(request) returns (BridgeTransactionV2 memory txV2) {\n // Note: we entirely ignore the callParams field, as it was not present in V1\n return BridgeTransaction({\n originChainId: txV2.originChainId,\n destChainId: txV2.destChainId,\n originSender: txV2.originSender,\n destRecipient: txV2.destRecipient,\n originToken: txV2.originToken,\n destToken: txV2.destToken,\n originAmount: txV2.originAmount,\n destAmount: txV2.destAmount,\n originFeeAmount: txV2.originFeeAmount,\n sendChainGas: txV2.callValue != 0,\n deadline: txV2.deadline,\n nonce: txV2.nonce\n });\n } catch {\n // Fallback to V1 struct\n return abi.decode(request, (BridgeTransaction));\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) public payable {\n int256 exclusivityEndTime = int256(block.timestamp) + paramsV2.quoteExclusivitySeconds;\n _validateBridgeParams(params, paramsV2, exclusivityEndTime);\n\n // transfer tokens to bridge contract\n /// @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _pullToken(params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n\n // set status to requested\n bytes memory request = abi.encode(\n BridgeTransactionV2({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n callValue: paramsV2.callValue,\n deadline: params.deadline,\n nonce: senderNonces[params.sender]++, // increment nonce on every bridge\n exclusivityRelayer: paramsV2.quoteRelayer,\n // We checked exclusivityEndTime to be in range (0 .. params.deadline] above, so can safely cast\n exclusivityEndTime: uint256(exclusivityEndTime),\n callParams: paramsV2.callParams\n })\n );\n bytes32 transactionId = keccak256(request);\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n\n emit BridgeRequested({\n transactionId: transactionId,\n sender: params.sender,\n request: request,\n destChainId: params.dstChainId,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n sendChainGas: paramsV2.callValue != 0\n });\n emit BridgeQuoteDetails(transactionId, paramsV2.quoteId);\n }\n\n /// @inheritdoc IFastBridgeV2\n function relay(bytes memory request, address relayer) public payable {\n bytes32 transactionId = keccak256(request);\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n _validateRelayParams(transaction, transactionId, relayer);\n // mark bridge transaction as relayed\n bridgeRelayDetails[transactionId] =\n BridgeRelay({blockNumber: uint48(block.number), blockTimestamp: uint48(block.timestamp), relayer: relayer});\n\n // transfer tokens to recipient on destination chain and do an arbitrary call if requested\n address to = transaction.destRecipient;\n address token = transaction.destToken;\n uint256 amount = transaction.destAmount;\n\n // All state changes have been done at this point, can proceed to the external calls.\n // This follows the checks-effects-interactions pattern to mitigate potential reentrancy attacks.\n if (token == UniversalTokenLib.ETH_ADDRESS) {\n // For ETH non-zero callValue is not allowed\n if (transaction.callValue != 0) revert NativeTokenCallValueNotSupported();\n // Check that the correct msg.value was sent\n if (msg.value != amount) revert MsgValueIncorrect();\n } else {\n // For ERC20s, we check that the correct msg.value was sent\n if (msg.value != transaction.callValue) revert MsgValueIncorrect();\n // We need to transfer the tokens from the Relayer to the recipient first before performing an\n // optional post-transfer arbitrary call.\n IERC20(token).safeTransferFrom(msg.sender, to, amount);\n }\n\n if (transaction.callParams.length != 0) {\n // Arbitrary call requested, perform it while supplying full msg.value to the recipient\n // Note: if token has a fee on transfers, the recipient will have received less than `amount`.\n // This is a very niche edge case and should be handled by the recipient contract.\n _checkedCallRecipient({recipient: to, token: token, amount: amount, callParams: transaction.callParams});\n } else if (msg.value != 0) {\n // No arbitrary call requested, but msg.value was sent. This is either a relay with ETH,\n // or a non-zero callValue request with an ERC20. In both cases, transfer the ETH to the recipient.\n Address.sendValue(payable(to), msg.value);\n }\n\n emit BridgeRelayed({\n transactionId: transactionId,\n relayer: relayer,\n to: to,\n originChainId: transaction.originChainId,\n originToken: transaction.originToken,\n destToken: transaction.destToken,\n originAmount: transaction.originAmount,\n destAmount: transaction.destAmount,\n chainGasAmount: transaction.callValue\n });\n }\n\n /// @inheritdoc IFastBridgeV2\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) public onlyRole(RELAYER_ROLE) {\n // update bridge tx status given proof provided\n if (bridgeTxDetails[transactionId].status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n bridgeTxDetails[transactionId].status = BridgeStatus.RELAYER_PROVED;\n bridgeTxDetails[transactionId].proofBlockTimestamp = uint40(block.timestamp);\n bridgeTxDetails[transactionId].proofBlockNumber = uint48(block.number);\n bridgeTxDetails[transactionId].proofRelayer = relayer;\n\n emit BridgeProofProvided(transactionId, relayer, destTxHash);\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes memory request, address to) public {\n bytes32 transactionId = keccak256(request);\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n\n // update bridge tx status if able to claim origin collateral\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n\n // if \"to\" is zero addr, permissionlessly send funds to proven relayer\n if (to == address(0)) {\n to = bridgeTxDetails[transactionId].proofRelayer;\n } else if (bridgeTxDetails[transactionId].proofRelayer != msg.sender) {\n revert SenderIncorrect();\n }\n\n if (_timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003c= DISPUTE_PERIOD) {\n revert DisputePeriodNotPassed();\n }\n\n bridgeTxDetails[transactionId].status = BridgeStatus.RELAYER_CLAIMED;\n\n // update protocol fees if origin fee amount exists\n if (transaction.originFeeAmount \u003e 0) protocolFees[transaction.originToken] += transaction.originFeeAmount;\n\n // transfer origin collateral less fee to specified address\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositClaimed(transactionId, bridgeTxDetails[transactionId].proofRelayer, to, token, amount);\n }\n\n function bridgeStatuses(bytes32 transactionId) public view returns (BridgeStatus status) {\n return bridgeTxDetails[transactionId].status;\n }\n\n function bridgeProofs(bytes32 transactionId) public view returns (uint96 timestamp, address relayer) {\n timestamp = bridgeTxDetails[transactionId].proofBlockTimestamp;\n relayer = bridgeTxDetails[transactionId].proofRelayer;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeRelays(bytes32 transactionId) public view returns (bool) {\n // has this transactionId been relayed?\n return bridgeRelayDetails[transactionId].relayer != address(0);\n }\n\n /// @inheritdoc IFastBridgeV2\n function getBridgeTransactionV2(bytes memory request) public pure returns (BridgeTransactionV2 memory) {\n return abi.decode(request, (BridgeTransactionV2));\n }\n\n /// @notice Pulls a requested token from the user to this contract.\n function _pullToken(address token, uint256 amount) internal returns (uint256 amountPulled) {\n if (token == UniversalTokenLib.ETH_ADDRESS) {\n // For ETH we just need to check that the supplied msg.value is correct\n if (amount != msg.value) revert MsgValueIncorrect();\n amountPulled = msg.value;\n } else {\n token.assertIsContract();\n // Record token balance before transfer\n amountPulled = IERC20(token).balanceOf(address(this));\n // Token needs to be pulled only if msg.value is zero\n // This way user can specify WETH as the origin asset\n IERC20(token).safeTransferFrom(msg.sender, address(this), amount);\n // Use the difference between the recorded balance and the current balance as the amountPulled\n amountPulled = IERC20(token).balanceOf(address(this)) - amountPulled;\n }\n }\n\n /// @notice Calls the Recipient's hook function with the specified callParams and performs\n /// all the necessary checks for the returned value.\n function _checkedCallRecipient(\n address recipient,\n address token,\n uint256 amount,\n bytes memory callParams\n )\n internal\n {\n bytes memory hookData =\n abi.encodeCall(IFastBridgeRecipient.fastBridgeTransferReceived, (token, amount, callParams));\n // This will bubble any revert messages from the hook function\n bytes memory returnData = Address.functionCallWithValue({target: recipient, data: hookData, value: msg.value});\n // Explicit revert if no return data at all\n if (returnData.length == 0) revert RecipientNoReturnValue();\n // Check that exactly a single return value was returned\n if (returnData.length != 32) revert RecipientIncorrectReturnValue();\n // Return value should be abi-encoded hook function selector\n if (bytes32(returnData) != bytes32(IFastBridgeRecipient.fastBridgeTransferReceived.selector)) {\n revert RecipientIncorrectReturnValue();\n }\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint40(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint40).max but\n /// proof.timestamp \u003c type(uint40).max via unchecked statement\n /// @param proofBlockTimestamp The bridge proof block timestamp\n /// @return delta Time delta since proof submitted\n function _timeSince(uint40 proofBlockTimestamp) internal view returns (uint256 delta) {\n unchecked {\n delta = uint40(block.timestamp) - proofBlockTimestamp;\n }\n }\n\n /// @notice Performs all the necessary checks for a bridge to happen.\n /// @dev There's no good way to refactor this function to reduce cyclomatic complexity due to\n /// the number of checks that need to be performed, so we skip the code-complexity rule here.\n // solhint-disable-next-line code-complexity\n function _validateBridgeParams(\n BridgeParams memory params,\n BridgeParamsV2 memory paramsV2,\n int256 exclusivityEndTime\n )\n internal\n view\n {\n // Check V1 (legacy) params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.sender == address(0) || params.to == address(0)) revert ZeroAddress();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n // Check V2 params\n if (paramsV2.callParams.length \u003e MAX_CALL_PARAMS_LENGTH) revert CallParamsLengthAboveMax();\n if (paramsV2.callValue != 0 \u0026\u0026 params.destToken == UniversalTokenLib.ETH_ADDRESS) {\n revert NativeTokenCallValueNotSupported();\n }\n // exclusivityEndTime must be in range (0 .. params.deadline]\n if (exclusivityEndTime \u003c= 0 || exclusivityEndTime \u003e int256(params.deadline)) {\n revert ExclusivityParamsIncorrect();\n }\n }\n\n /// @notice Performs all the necessary checks for a relay to happen.\n function _validateRelayParams(\n BridgeTransactionV2 memory transaction,\n bytes32 transactionId,\n address relayer\n )\n internal\n view\n {\n if (relayer == address(0)) revert ZeroAddress();\n // Check if the transaction has already been relayed\n if (bridgeRelays(transactionId)) revert TransactionRelayed();\n if (transaction.destChainId != uint32(block.chainid)) revert ChainIncorrect();\n // Check the deadline for relay to happen\n if (block.timestamp \u003e transaction.deadline) revert DeadlineExceeded();\n // Check the exclusivity period, if it is still ongoing\n // forgefmt: disable-next-item\n if (\n transaction.exclusivityRelayer != address(0) \u0026\u0026\n transaction.exclusivityRelayer != relayer \u0026\u0026\n block.timestamp \u003c= transaction.exclusivityEndTime\n ) {\n revert ExclusivityPeriodNotPassed();\n }\n }\n}\n","language":"Solidity","languageVersion":"0.8.24","compilerVersion":"0.8.24","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../","srcMap":"57704:2551:0:-:0;;;;;;;;;;;;;;;-1:-1:-1;;;57704:2551:0;;;;;;;;;;;;;;;;;","srcMapRuntime":"57704:2551:0:-:0;;;;;;;;","abiDefinition":[],"userDoc":{"kind":"user","methods":{},"version":1},"developerDoc":{"kind":"dev","methods":{},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[],\"devdoc\":{\"kind\":\"dev\",\"methods\":{},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeV2.sol\":\"UniversalTokenLib\"},\"evmVersion\":\"shanghai\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeV2.sol\":{\"keccak256\":\"0x7cd0f885e80e2bdaa638bc32ae7af7d2e248f99ce4b354c217d0f0f7d7302e0a\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://7ccf28df0bd7b4606986585acd8622ed9b4e81379690061bb66088f0a2270af1\",\"dweb:/ipfs/QmTf7HNdHZkK6vmx8ZgewycQEb72oLD9nPwBpsM5reMstQ\"]}},\"version\":1}"},"hashes":{}}} \ No newline at end of file +{"solidity/FastBridgeV2.sol:AccessControl":{"code":"0x","runtime-code":"0x","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.24 ^0.8.0 ^0.8.20;\n\n// contracts/interfaces/IAdmin.sol\n\ninterface IAdmin {\n // ============ Events ============\n\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n event ChainGasAmountUpdated(uint256 oldChainGasAmount, uint256 newChainGasAmount);\n\n // ============ Methods ============\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n\n function setChainGasAmount(uint256 newChainGasAmount) external;\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IFastBridgeRecipient.sol\n\ninterface IFastBridgeRecipient {\n function fastBridgeTransferReceived(\n address token,\n uint256 amount,\n bytes memory callParams\n )\n external\n payable\n returns (bytes4);\n}\n\n// contracts/interfaces/IFastBridgeV2Errors.sol\n\ninterface IFastBridgeV2Errors {\n error AmountIncorrect();\n error CallParamsLengthAboveMax();\n error ChainIncorrect();\n error ExclusivityParamsIncorrect();\n error MsgValueIncorrect();\n error NativeTokenCallValueNotSupported();\n error SenderIncorrect();\n error StatusIncorrect();\n error ZeroAddress();\n\n error RecipientIncorrectReturnValue();\n error RecipientNoReturnValue();\n\n error DeadlineExceeded();\n error DeadlineNotExceeded();\n error DeadlineTooShort();\n error DisputePeriodNotPassed();\n error DisputePeriodPassed();\n error ExclusivityPeriodNotPassed();\n\n error TransactionRelayed();\n}\n\n// contracts/libs/Errors.sol\n\nerror DeadlineExceeded();\nerror DeadlineNotExceeded();\nerror DeadlineTooShort();\nerror InsufficientOutputAmount();\n\nerror MsgValueIncorrect();\nerror PoolNotFound();\nerror TokenAddressMismatch();\nerror TokenNotContract();\nerror TokenNotETH();\nerror TokensIdentical();\n\nerror ChainIncorrect();\nerror AmountIncorrect();\nerror ZeroAddress();\n\nerror DisputePeriodNotPassed();\nerror DisputePeriodPassed();\nerror SenderIncorrect();\nerror StatusIncorrect();\nerror TransactionIdIncorrect();\nerror TransactionRelayed();\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// contracts/interfaces/IFastBridgeV2.sol\n\ninterface IFastBridgeV2 is IFastBridge {\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n struct BridgeTxDetails {\n BridgeStatus status;\n uint40 proofBlockTimestamp;\n uint48 proofBlockNumber;\n address proofRelayer;\n }\n\n struct BridgeRelay {\n uint48 blockNumber;\n uint48 blockTimestamp;\n address relayer;\n }\n\n /// @notice New params introduced in the FastBridgeV2.\n /// We are passing fields from the older BridgeParams struct outside of this struct\n /// for backwards compatibility.\n /// Note: quoteRelayer and quoteExclusivitySeconds are either both zero (indicating no exclusivity)\n /// or both non-zero (indicating exclusivity for the given period).\n /// Note: callValue \u003e 0 can NOT be used with destToken = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE (ETH_ADDRESS)\n /// @param quoteRelayer Relayer that provided the quote for the transaction\n /// @param quoteExclusivitySeconds Period of time the quote relayer is guaranteed exclusivity after user's deposit\n /// @param quoteId Unique quote identifier used for tracking the quote\n /// @param callValue ETH value to send to the recipient (if any)\n /// @param callParams Parameters for the arbitrary call to the destination recipient (if any)\n struct BridgeParamsV2 {\n address quoteRelayer;\n int256 quoteExclusivitySeconds;\n bytes quoteId;\n uint256 callValue;\n bytes callParams;\n }\n\n /// @notice Updated bridge transaction struct to include parameters introduced in FastBridgeV2.\n /// Note: only `exclusivityRelayer` can fill such a transaction until `exclusivityEndTime`.\n /// TODO: consider changing the encoding scheme to prevent spending extra gas on decoding.\n struct BridgeTransactionV2 {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n uint256 callValue; // ETH value to send to the recipient (if any) - replaces V1's sendChainGas flag\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n address exclusivityRelayer;\n uint256 exclusivityEndTime;\n bytes callParams;\n }\n\n event BridgeQuoteDetails(bytes32 indexed transactionId, bytes quoteId);\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability\n /// to provide temporary exclusivity fill rights for the quote relayer.\n /// @param params The parameters required to bridge\n /// @param paramsV2 The parameters for exclusivity fill rights (optional, can be left empty)\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function relay(bytes memory request, address relayer) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param transactionId The transaction id associated with the encoded bridge transaction to prove\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital.\n /// @notice Can only send funds to the relayer address on the proof.\n /// @param request The encoded bridge transaction to claim on origin chain\n function claim(bytes memory request) external;\n /// @notice Checks if a transaction has been relayed\n /// @param transactionId The ID of the transaction to check\n /// @return True if the transaction has been relayed, false otherwise\n function bridgeRelays(bytes32 transactionId) external view returns (bool);\n\n /// @notice Returns the status of a bridge transaction\n /// @param transactionId The ID of the bridge transaction\n /// @return BridgeStatus Status of the bridge transaction\n function bridgeStatuses(bytes32 transactionId) external view returns (BridgeStatus);\n\n /// @notice Returns the timestamp and relayer of a bridge proof\n /// @param transactionId The ID of the bridge transaction\n /// @return timestamp The timestamp of the bridge proof\n /// @return relayer The relayer address of the bridge proof\n function bridgeProofs(bytes32 transactionId) external view returns (uint96 timestamp, address relayer);\n\n /// @notice Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\n /// @param request The bridge request to decode\n function getBridgeTransactionV2(bytes memory request) external view returns (BridgeTransactionV2 memory);\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// contracts/libs/UniversalToken.sol\n\nlibrary UniversalTokenLib {\n using SafeERC20 for IERC20;\n\n address internal constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Transfers tokens to the given account. Reverts if transfer is not successful.\n /// @dev This might trigger fallback, if ETH is transferred to the contract.\n /// Make sure this can not lead to reentrancy attacks.\n function universalTransfer(address token, address to, uint256 value) internal {\n // Don't do anything, if need to send tokens to this address\n if (to == address(this)) return;\n // Don't do anything, if trying to send zero value\n if (value == 0) return;\n if (token == ETH_ADDRESS) {\n /// @dev Note: this can potentially lead to executing code in `to`.\n // solhint-disable-next-line avoid-low-level-calls\n (bool success,) = to.call{value: value}(\"\");\n require(success, \"ETH transfer failed\");\n } else {\n IERC20(token).safeTransfer(to, value);\n }\n }\n\n /// @notice Issues an infinite allowance to the spender, if the current allowance is insufficient\n /// to spend the given amount.\n function universalApproveInfinity(address token, address spender, uint256 amountToSpend) internal {\n // ETH Chad doesn't require your approval\n if (token == ETH_ADDRESS) return;\n // No-op if allowance is already sufficient\n uint256 allowance = IERC20(token).allowance(address(this), spender);\n if (allowance \u003e= amountToSpend) return;\n // Otherwise, reset approval to 0 and set to max allowance\n if (allowance \u003e 0) IERC20(token).safeDecreaseAllowance(spender, allowance);\n IERC20(token).safeIncreaseAllowance(spender, type(uint256).max);\n }\n\n /// @notice Returns the balance of the given token (or native ETH) for the given account.\n function universalBalanceOf(address token, address account) internal view returns (uint256) {\n if (token == ETH_ADDRESS) {\n return account.balance;\n } else {\n return IERC20(token).balanceOf(account);\n }\n }\n\n /// @dev Checks that token is a contract and not ETH_ADDRESS.\n function assertIsContract(address token) internal view {\n // Check that ETH_ADDRESS was not used (in case this is a predeploy on any of the chains)\n if (token == UniversalTokenLib.ETH_ADDRESS) revert TokenNotContract();\n // Check that token is not an EOA\n if (token.code.length == 0) revert TokenNotContract();\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/Admin.sol\n\ncontract Admin is IAdmin, AccessControlEnumerable {\n using UniversalTokenLib for address;\n\n bytes32 public constant RELAYER_ROLE = keccak256(\"RELAYER_ROLE\");\n bytes32 public constant REFUNDER_ROLE = keccak256(\"REFUNDER_ROLE\");\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n uint256 public constant FEE_BPS = 1e6;\n uint256 public constant FEE_RATE_MAX = 0.01e6; // max 1% on origin amount\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Chain gas amount to forward as rebate if requested\n uint256 public chainGasAmount;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n }\n\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n require(newFeeRate \u003c= FEE_RATE_MAX, \"newFeeRate \u003e max\");\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n token.universalTransfer(recipient, feeAmount);\n emit FeesSwept(token, recipient, feeAmount);\n }\n\n function setChainGasAmount(uint256 newChainGasAmount) external onlyRole(GOVERNOR_ROLE) {\n uint256 oldChainGasAmount = chainGasAmount;\n chainGasAmount = newChainGasAmount;\n emit ChainGasAmountUpdated(oldChainGasAmount, newChainGasAmount);\n }\n}\n\n// contracts/FastBridgeV2.sol\n\n/// @notice FastBridgeV2 is a contract for bridging tokens across chains.\ncontract FastBridgeV2 is Admin, IFastBridgeV2, IFastBridgeV2Errors {\n using SafeERC20 for IERC20;\n using UniversalTokenLib for address;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Delay for a transaction after which it could be permisionlessly refunded\n uint256 public constant REFUND_DELAY = 7 days;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n /// @notice Maximum length of accepted callParams\n uint256 public constant MAX_CALL_PARAMS_LENGTH = 2 ** 16 - 1;\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeTxDetails) public bridgeTxDetails;\n /// @notice Relay details on destination chain\n mapping(bytes32 =\u003e BridgeRelay) public bridgeRelayDetails;\n /// @notice Unique bridge nonces tracked per originSender\n mapping(address =\u003e uint256) public senderNonces;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Replaced by senderNonces\n uint256 public immutable nonce = 0;\n /// @notice the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n bridge({\n params: params,\n paramsV2: BridgeParamsV2({\n quoteRelayer: address(0),\n quoteExclusivitySeconds: 0,\n quoteId: bytes(\"\"),\n callValue: 0,\n callParams: bytes(\"\")\n })\n });\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes memory request) external payable {\n relay({request: request, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes memory request, bytes32 destTxHash) external {\n prove({transactionId: keccak256(request), destTxHash: destTxHash, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridgeV2\n function claim(bytes memory request) external {\n claim({request: request, to: address(0)});\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003e DISPUTE_PERIOD) {\n revert DisputePeriodPassed();\n }\n\n // @dev relayer gets slashed effectively if dest relay has gone thru\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n bridgeTxDetails[transactionId].proofRelayer = address(0);\n bridgeTxDetails[transactionId].proofBlockTimestamp = 0;\n bridgeTxDetails[transactionId].proofBlockNumber = 0;\n\n emit BridgeProofDisputed(transactionId, msg.sender);\n }\n\n /// @inheritdoc IFastBridge\n function refund(bytes memory request) external {\n bytes32 transactionId = keccak256(request);\n\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n\n if (bridgeTxDetails[transactionId].status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n\n if (hasRole(REFUNDER_ROLE, msg.sender)) {\n // Refunder can refund if deadline has passed\n if (block.timestamp \u003c= transaction.deadline) revert DeadlineNotExceeded();\n } else {\n // Permissionless refund is allowed after REFUND_DELAY\n if (block.timestamp \u003c= transaction.deadline + REFUND_DELAY) revert DeadlineNotExceeded();\n }\n\n // if all checks passed, set to REFUNDED status\n bridgeTxDetails[transactionId].status = BridgeStatus.REFUNDED;\n\n // transfer origin collateral back to original sender\n address to = transaction.originSender;\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount + transaction.originFeeAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (bridgeTxDetails[transactionId].proofRelayer != relayer) revert SenderIncorrect();\n return _timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n /// @dev This method is added to achieve backwards compatibility with decoding requests into V1 structs:\n /// - `callValue` is partially reported as a zero/non-zero flag\n /// - `callParams` is ignored\n /// In order to process all kinds of requests use getBridgeTransactionV2 instead.\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory) {\n // Try decoding into V2 struct first. This will revert if V1 struct is passed\n try this.getBridgeTransactionV2(request) returns (BridgeTransactionV2 memory txV2) {\n // Note: we entirely ignore the callParams field, as it was not present in V1\n return BridgeTransaction({\n originChainId: txV2.originChainId,\n destChainId: txV2.destChainId,\n originSender: txV2.originSender,\n destRecipient: txV2.destRecipient,\n originToken: txV2.originToken,\n destToken: txV2.destToken,\n originAmount: txV2.originAmount,\n destAmount: txV2.destAmount,\n originFeeAmount: txV2.originFeeAmount,\n sendChainGas: txV2.callValue != 0,\n deadline: txV2.deadline,\n nonce: txV2.nonce\n });\n } catch {\n // Fallback to V1 struct\n return abi.decode(request, (BridgeTransaction));\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) public payable {\n int256 exclusivityEndTime = int256(block.timestamp) + paramsV2.quoteExclusivitySeconds;\n _validateBridgeParams(params, paramsV2, exclusivityEndTime);\n\n // transfer tokens to bridge contract\n /// @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _pullToken(params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n\n // set status to requested\n bytes memory request = abi.encode(\n BridgeTransactionV2({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n callValue: paramsV2.callValue,\n deadline: params.deadline,\n nonce: senderNonces[params.sender]++, // increment nonce on every bridge\n exclusivityRelayer: paramsV2.quoteRelayer,\n // We checked exclusivityEndTime to be in range (0 .. params.deadline] above, so can safely cast\n exclusivityEndTime: uint256(exclusivityEndTime),\n callParams: paramsV2.callParams\n })\n );\n bytes32 transactionId = keccak256(request);\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n\n emit BridgeRequested({\n transactionId: transactionId,\n sender: params.sender,\n request: request,\n destChainId: params.dstChainId,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n sendChainGas: paramsV2.callValue != 0\n });\n emit BridgeQuoteDetails(transactionId, paramsV2.quoteId);\n }\n\n /// @inheritdoc IFastBridgeV2\n function relay(bytes memory request, address relayer) public payable {\n bytes32 transactionId = keccak256(request);\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n _validateRelayParams(transaction, transactionId, relayer);\n // mark bridge transaction as relayed\n bridgeRelayDetails[transactionId] =\n BridgeRelay({blockNumber: uint48(block.number), blockTimestamp: uint48(block.timestamp), relayer: relayer});\n\n // transfer tokens to recipient on destination chain and do an arbitrary call if requested\n address to = transaction.destRecipient;\n address token = transaction.destToken;\n uint256 amount = transaction.destAmount;\n\n // All state changes have been done at this point, can proceed to the external calls.\n // This follows the checks-effects-interactions pattern to mitigate potential reentrancy attacks.\n if (token == UniversalTokenLib.ETH_ADDRESS) {\n // For ETH non-zero callValue is not allowed\n if (transaction.callValue != 0) revert NativeTokenCallValueNotSupported();\n // Check that the correct msg.value was sent\n if (msg.value != amount) revert MsgValueIncorrect();\n } else {\n // For ERC20s, we check that the correct msg.value was sent\n if (msg.value != transaction.callValue) revert MsgValueIncorrect();\n // We need to transfer the tokens from the Relayer to the recipient first before performing an\n // optional post-transfer arbitrary call.\n IERC20(token).safeTransferFrom(msg.sender, to, amount);\n }\n\n if (transaction.callParams.length != 0) {\n // Arbitrary call requested, perform it while supplying full msg.value to the recipient\n // Note: if token has a fee on transfers, the recipient will have received less than `amount`.\n // This is a very niche edge case and should be handled by the recipient contract.\n _checkedCallRecipient({recipient: to, token: token, amount: amount, callParams: transaction.callParams});\n } else if (msg.value != 0) {\n // No arbitrary call requested, but msg.value was sent. This is either a relay with ETH,\n // or a non-zero callValue request with an ERC20. In both cases, transfer the ETH to the recipient.\n Address.sendValue(payable(to), msg.value);\n }\n\n emit BridgeRelayed({\n transactionId: transactionId,\n relayer: relayer,\n to: to,\n originChainId: transaction.originChainId,\n originToken: transaction.originToken,\n destToken: transaction.destToken,\n originAmount: transaction.originAmount,\n destAmount: transaction.destAmount,\n chainGasAmount: transaction.callValue\n });\n }\n\n /// @inheritdoc IFastBridgeV2\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) public onlyRole(RELAYER_ROLE) {\n // update bridge tx status given proof provided\n if (bridgeTxDetails[transactionId].status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n bridgeTxDetails[transactionId].status = BridgeStatus.RELAYER_PROVED;\n bridgeTxDetails[transactionId].proofBlockTimestamp = uint40(block.timestamp);\n bridgeTxDetails[transactionId].proofBlockNumber = uint48(block.number);\n bridgeTxDetails[transactionId].proofRelayer = relayer;\n\n emit BridgeProofProvided(transactionId, relayer, destTxHash);\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes memory request, address to) public {\n bytes32 transactionId = keccak256(request);\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n\n // update bridge tx status if able to claim origin collateral\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n\n // if \"to\" is zero addr, permissionlessly send funds to proven relayer\n if (to == address(0)) {\n to = bridgeTxDetails[transactionId].proofRelayer;\n } else if (bridgeTxDetails[transactionId].proofRelayer != msg.sender) {\n revert SenderIncorrect();\n }\n\n if (_timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003c= DISPUTE_PERIOD) {\n revert DisputePeriodNotPassed();\n }\n\n bridgeTxDetails[transactionId].status = BridgeStatus.RELAYER_CLAIMED;\n\n // update protocol fees if origin fee amount exists\n if (transaction.originFeeAmount \u003e 0) protocolFees[transaction.originToken] += transaction.originFeeAmount;\n\n // transfer origin collateral less fee to specified address\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositClaimed(transactionId, bridgeTxDetails[transactionId].proofRelayer, to, token, amount);\n }\n\n function bridgeStatuses(bytes32 transactionId) public view returns (BridgeStatus status) {\n return bridgeTxDetails[transactionId].status;\n }\n\n function bridgeProofs(bytes32 transactionId) public view returns (uint96 timestamp, address relayer) {\n timestamp = bridgeTxDetails[transactionId].proofBlockTimestamp;\n relayer = bridgeTxDetails[transactionId].proofRelayer;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeRelays(bytes32 transactionId) public view returns (bool) {\n // has this transactionId been relayed?\n return bridgeRelayDetails[transactionId].relayer != address(0);\n }\n\n /// @inheritdoc IFastBridgeV2\n function getBridgeTransactionV2(bytes memory request) public pure returns (BridgeTransactionV2 memory) {\n return abi.decode(request, (BridgeTransactionV2));\n }\n\n /// @notice Pulls a requested token from the user to this contract.\n function _pullToken(address token, uint256 amount) internal returns (uint256 amountPulled) {\n if (token == UniversalTokenLib.ETH_ADDRESS) {\n // For ETH we just need to check that the supplied msg.value is correct\n if (amount != msg.value) revert MsgValueIncorrect();\n amountPulled = msg.value;\n } else {\n token.assertIsContract();\n // Record token balance before transfer\n amountPulled = IERC20(token).balanceOf(address(this));\n // Token needs to be pulled only if msg.value is zero\n // This way user can specify WETH as the origin asset\n IERC20(token).safeTransferFrom(msg.sender, address(this), amount);\n // Use the difference between the recorded balance and the current balance as the amountPulled\n amountPulled = IERC20(token).balanceOf(address(this)) - amountPulled;\n }\n }\n\n /// @notice Calls the Recipient's hook function with the specified callParams and performs\n /// all the necessary checks for the returned value.\n function _checkedCallRecipient(\n address recipient,\n address token,\n uint256 amount,\n bytes memory callParams\n )\n internal\n {\n bytes memory hookData =\n abi.encodeCall(IFastBridgeRecipient.fastBridgeTransferReceived, (token, amount, callParams));\n // This will bubble any revert messages from the hook function\n bytes memory returnData = Address.functionCallWithValue({target: recipient, data: hookData, value: msg.value});\n // Explicit revert if no return data at all\n if (returnData.length == 0) revert RecipientNoReturnValue();\n // Check that exactly a single return value was returned\n if (returnData.length != 32) revert RecipientIncorrectReturnValue();\n // Return value should be abi-encoded hook function selector\n if (bytes32(returnData) != bytes32(IFastBridgeRecipient.fastBridgeTransferReceived.selector)) {\n revert RecipientIncorrectReturnValue();\n }\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint40(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint40).max but\n /// proof.timestamp \u003c type(uint40).max via unchecked statement\n /// @param proofBlockTimestamp The bridge proof block timestamp\n /// @return delta Time delta since proof submitted\n function _timeSince(uint40 proofBlockTimestamp) internal view returns (uint256 delta) {\n unchecked {\n delta = uint40(block.timestamp) - proofBlockTimestamp;\n }\n }\n\n /// @notice Performs all the necessary checks for a bridge to happen.\n /// @dev There's no good way to refactor this function to reduce cyclomatic complexity due to\n /// the number of checks that need to be performed, so we skip the code-complexity rule here.\n // solhint-disable-next-line code-complexity\n function _validateBridgeParams(\n BridgeParams memory params,\n BridgeParamsV2 memory paramsV2,\n int256 exclusivityEndTime\n )\n internal\n view\n {\n // Check V1 (legacy) params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.sender == address(0) || params.to == address(0)) revert ZeroAddress();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n // Check V2 params\n if (paramsV2.callParams.length \u003e MAX_CALL_PARAMS_LENGTH) revert CallParamsLengthAboveMax();\n if (paramsV2.callValue != 0 \u0026\u0026 params.destToken == UniversalTokenLib.ETH_ADDRESS) {\n revert NativeTokenCallValueNotSupported();\n }\n // exclusivityEndTime must be in range (0 .. params.deadline]\n if (exclusivityEndTime \u003c= 0 || exclusivityEndTime \u003e int256(params.deadline)) {\n revert ExclusivityParamsIncorrect();\n }\n }\n\n /// @notice Performs all the necessary checks for a relay to happen.\n function _validateRelayParams(\n BridgeTransactionV2 memory transaction,\n bytes32 transactionId,\n address relayer\n )\n internal\n view\n {\n if (relayer == address(0)) revert ZeroAddress();\n // Check if the transaction has already been relayed\n if (bridgeRelays(transactionId)) revert TransactionRelayed();\n if (transaction.destChainId != uint32(block.chainid)) revert ChainIncorrect();\n // Check the deadline for relay to happen\n if (block.timestamp \u003e transaction.deadline) revert DeadlineExceeded();\n // Check the exclusivity period, if it is still ongoing\n // forgefmt: disable-next-item\n if (\n transaction.exclusivityRelayer != address(0) \u0026\u0026\n transaction.exclusivityRelayer != relayer \u0026\u0026\n block.timestamp \u003c= transaction.exclusivityEndTime\n ) {\n revert ExclusivityPeriodNotPassed();\n }\n }\n}\n","language":"Solidity","languageVersion":"0.8.24","compilerVersion":"0.8.24","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"","srcMapRuntime":"","abiDefinition":[{"inputs":[],"name":"AccessControlBadConfirmation","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"bytes32","name":"neededRole","type":"bytes32"}],"name":"AccessControlUnauthorizedAccount","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"previousAdminRole","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"newAdminRole","type":"bytes32"}],"name":"RoleAdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleRevoked","type":"event"},{"inputs":[],"name":"DEFAULT_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleAdmin","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"grantRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"hasRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"callerConfirmation","type":"address"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"revokeRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"}],"userDoc":{"kind":"user","methods":{},"version":1},"developerDoc":{"details":"Contract module that allows children to implement role-based access control mechanisms. This is a lightweight version that doesn't allow enumerating role members except through off-chain means by accessing the contract event logs. Some applications may benefit from on-chain enumerability, for those cases see {AccessControlEnumerable}. Roles are referred to by their `bytes32` identifier. These should be exposed in the external API and be unique. The best way to achieve this is by using `public constant` hash digests: ```solidity bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\"); ``` Roles can be used to represent a set of permissions. To restrict access to a function call, use {hasRole}: ```solidity function foo() public { require(hasRole(MY_ROLE, msg.sender)); ... } ``` Roles can be granted and revoked dynamically via the {grantRole} and {revokeRole} functions. Each role has an associated admin role, and only accounts that have a role's admin role can call {grantRole} and {revokeRole}. By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means that only accounts with this role will be able to grant or revoke other roles. More complex role relationships can be created by using {_setRoleAdmin}. WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to grant and revoke this role. Extra precautions should be taken to secure accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules} to enforce additional security measures for this role.","errors":{"AccessControlBadConfirmation()":[{"details":"The caller of a function is not the expected one. NOTE: Don't confuse with {AccessControlUnauthorizedAccount}."}],"AccessControlUnauthorizedAccount(address,bytes32)":[{"details":"The `account` is missing a role."}]},"events":{"RoleAdminChanged(bytes32,bytes32,bytes32)":{"details":"Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole` `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite {RoleAdminChanged} not being emitted signaling this."},"RoleGranted(bytes32,address,address)":{"details":"Emitted when `account` is granted `role`. `sender` is the account that originated the contract call, an admin role bearer except when using {AccessControl-_setupRole}."},"RoleRevoked(bytes32,address,address)":{"details":"Emitted when `account` is revoked `role`. `sender` is the account that originated the contract call: - if using `revokeRole`, it is the admin role bearer - if using `renounceRole`, it is the role bearer (i.e. `account`)"}},"kind":"dev","methods":{"getRoleAdmin(bytes32)":{"details":"Returns the admin role that controls `role`. See {grantRole} and {revokeRole}. To change a role's admin, use {_setRoleAdmin}."},"grantRole(bytes32,address)":{"details":"Grants `role` to `account`. If `account` had not been already granted `role`, emits a {RoleGranted} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleGranted} event."},"hasRole(bytes32,address)":{"details":"Returns `true` if `account` has been granted `role`."},"renounceRole(bytes32,address)":{"details":"Revokes `role` from the calling account. Roles are often managed via {grantRole} and {revokeRole}: this function's purpose is to provide a mechanism for accounts to lose their privileges if they are compromised (such as when a trusted device is misplaced). If the calling account had been revoked `role`, emits a {RoleRevoked} event. Requirements: - the caller must be `callerConfirmation`. May emit a {RoleRevoked} event."},"revokeRole(bytes32,address)":{"details":"Revokes `role` from `account`. If `account` had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleRevoked} event."},"supportsInterface(bytes4)":{"details":"See {IERC165-supportsInterface}."}},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[],\"name\":\"AccessControlBadConfirmation\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"neededRole\",\"type\":\"bytes32\"}],\"name\":\"AccessControlUnauthorizedAccount\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"previousAdminRole\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"newAdminRole\",\"type\":\"bytes32\"}],\"name\":\"RoleAdminChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleGranted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleRevoked\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"DEFAULT_ADMIN_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"}],\"name\":\"getRoleAdmin\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"grantRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"hasRole\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"callerConfirmation\",\"type\":\"address\"}],\"name\":\"renounceRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"revokeRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes4\",\"name\":\"interfaceId\",\"type\":\"bytes4\"}],\"name\":\"supportsInterface\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"}],\"devdoc\":{\"details\":\"Contract module that allows children to implement role-based access control mechanisms. This is a lightweight version that doesn't allow enumerating role members except through off-chain means by accessing the contract event logs. Some applications may benefit from on-chain enumerability, for those cases see {AccessControlEnumerable}. Roles are referred to by their `bytes32` identifier. These should be exposed in the external API and be unique. The best way to achieve this is by using `public constant` hash digests: ```solidity bytes32 public constant MY_ROLE = keccak256(\\\"MY_ROLE\\\"); ``` Roles can be used to represent a set of permissions. To restrict access to a function call, use {hasRole}: ```solidity function foo() public { require(hasRole(MY_ROLE, msg.sender)); ... } ``` Roles can be granted and revoked dynamically via the {grantRole} and {revokeRole} functions. Each role has an associated admin role, and only accounts that have a role's admin role can call {grantRole} and {revokeRole}. By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means that only accounts with this role will be able to grant or revoke other roles. More complex role relationships can be created by using {_setRoleAdmin}. WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to grant and revoke this role. Extra precautions should be taken to secure accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules} to enforce additional security measures for this role.\",\"errors\":{\"AccessControlBadConfirmation()\":[{\"details\":\"The caller of a function is not the expected one. NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\"}],\"AccessControlUnauthorizedAccount(address,bytes32)\":[{\"details\":\"The `account` is missing a role.\"}]},\"events\":{\"RoleAdminChanged(bytes32,bytes32,bytes32)\":{\"details\":\"Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole` `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite {RoleAdminChanged} not being emitted signaling this.\"},\"RoleGranted(bytes32,address,address)\":{\"details\":\"Emitted when `account` is granted `role`. `sender` is the account that originated the contract call, an admin role bearer except when using {AccessControl-_setupRole}.\"},\"RoleRevoked(bytes32,address,address)\":{\"details\":\"Emitted when `account` is revoked `role`. `sender` is the account that originated the contract call: - if using `revokeRole`, it is the admin role bearer - if using `renounceRole`, it is the role bearer (i.e. `account`)\"}},\"kind\":\"dev\",\"methods\":{\"getRoleAdmin(bytes32)\":{\"details\":\"Returns the admin role that controls `role`. See {grantRole} and {revokeRole}. To change a role's admin, use {_setRoleAdmin}.\"},\"grantRole(bytes32,address)\":{\"details\":\"Grants `role` to `account`. If `account` had not been already granted `role`, emits a {RoleGranted} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleGranted} event.\"},\"hasRole(bytes32,address)\":{\"details\":\"Returns `true` if `account` has been granted `role`.\"},\"renounceRole(bytes32,address)\":{\"details\":\"Revokes `role` from the calling account. Roles are often managed via {grantRole} and {revokeRole}: this function's purpose is to provide a mechanism for accounts to lose their privileges if they are compromised (such as when a trusted device is misplaced). If the calling account had been revoked `role`, emits a {RoleRevoked} event. Requirements: - the caller must be `callerConfirmation`. May emit a {RoleRevoked} event.\"},\"revokeRole(bytes32,address)\":{\"details\":\"Revokes `role` from `account`. If `account` had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleRevoked} event.\"},\"supportsInterface(bytes4)\":{\"details\":\"See {IERC165-supportsInterface}.\"}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeV2.sol\":\"AccessControl\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeV2.sol\":{\"keccak256\":\"0x7cd0f885e80e2bdaa638bc32ae7af7d2e248f99ce4b354c217d0f0f7d7302e0a\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://7ccf28df0bd7b4606986585acd8622ed9b4e81379690061bb66088f0a2270af1\",\"dweb:/ipfs/QmTf7HNdHZkK6vmx8ZgewycQEb72oLD9nPwBpsM5reMstQ\"]}},\"version\":1}"},"hashes":{"DEFAULT_ADMIN_ROLE()":"a217fddf","getRoleAdmin(bytes32)":"248a9ca3","grantRole(bytes32,address)":"2f2ff15d","hasRole(bytes32,address)":"91d14854","renounceRole(bytes32,address)":"36568abe","revokeRole(bytes32,address)":"d547741f","supportsInterface(bytes4)":"01ffc9a7"}},"solidity/FastBridgeV2.sol:AccessControlEnumerable":{"code":"0x","runtime-code":"0x","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.24 ^0.8.0 ^0.8.20;\n\n// contracts/interfaces/IAdmin.sol\n\ninterface IAdmin {\n // ============ Events ============\n\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n event ChainGasAmountUpdated(uint256 oldChainGasAmount, uint256 newChainGasAmount);\n\n // ============ Methods ============\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n\n function setChainGasAmount(uint256 newChainGasAmount) external;\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IFastBridgeRecipient.sol\n\ninterface IFastBridgeRecipient {\n function fastBridgeTransferReceived(\n address token,\n uint256 amount,\n bytes memory callParams\n )\n external\n payable\n returns (bytes4);\n}\n\n// contracts/interfaces/IFastBridgeV2Errors.sol\n\ninterface IFastBridgeV2Errors {\n error AmountIncorrect();\n error CallParamsLengthAboveMax();\n error ChainIncorrect();\n error ExclusivityParamsIncorrect();\n error MsgValueIncorrect();\n error NativeTokenCallValueNotSupported();\n error SenderIncorrect();\n error StatusIncorrect();\n error ZeroAddress();\n\n error RecipientIncorrectReturnValue();\n error RecipientNoReturnValue();\n\n error DeadlineExceeded();\n error DeadlineNotExceeded();\n error DeadlineTooShort();\n error DisputePeriodNotPassed();\n error DisputePeriodPassed();\n error ExclusivityPeriodNotPassed();\n\n error TransactionRelayed();\n}\n\n// contracts/libs/Errors.sol\n\nerror DeadlineExceeded();\nerror DeadlineNotExceeded();\nerror DeadlineTooShort();\nerror InsufficientOutputAmount();\n\nerror MsgValueIncorrect();\nerror PoolNotFound();\nerror TokenAddressMismatch();\nerror TokenNotContract();\nerror TokenNotETH();\nerror TokensIdentical();\n\nerror ChainIncorrect();\nerror AmountIncorrect();\nerror ZeroAddress();\n\nerror DisputePeriodNotPassed();\nerror DisputePeriodPassed();\nerror SenderIncorrect();\nerror StatusIncorrect();\nerror TransactionIdIncorrect();\nerror TransactionRelayed();\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// contracts/interfaces/IFastBridgeV2.sol\n\ninterface IFastBridgeV2 is IFastBridge {\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n struct BridgeTxDetails {\n BridgeStatus status;\n uint40 proofBlockTimestamp;\n uint48 proofBlockNumber;\n address proofRelayer;\n }\n\n struct BridgeRelay {\n uint48 blockNumber;\n uint48 blockTimestamp;\n address relayer;\n }\n\n /// @notice New params introduced in the FastBridgeV2.\n /// We are passing fields from the older BridgeParams struct outside of this struct\n /// for backwards compatibility.\n /// Note: quoteRelayer and quoteExclusivitySeconds are either both zero (indicating no exclusivity)\n /// or both non-zero (indicating exclusivity for the given period).\n /// Note: callValue \u003e 0 can NOT be used with destToken = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE (ETH_ADDRESS)\n /// @param quoteRelayer Relayer that provided the quote for the transaction\n /// @param quoteExclusivitySeconds Period of time the quote relayer is guaranteed exclusivity after user's deposit\n /// @param quoteId Unique quote identifier used for tracking the quote\n /// @param callValue ETH value to send to the recipient (if any)\n /// @param callParams Parameters for the arbitrary call to the destination recipient (if any)\n struct BridgeParamsV2 {\n address quoteRelayer;\n int256 quoteExclusivitySeconds;\n bytes quoteId;\n uint256 callValue;\n bytes callParams;\n }\n\n /// @notice Updated bridge transaction struct to include parameters introduced in FastBridgeV2.\n /// Note: only `exclusivityRelayer` can fill such a transaction until `exclusivityEndTime`.\n /// TODO: consider changing the encoding scheme to prevent spending extra gas on decoding.\n struct BridgeTransactionV2 {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n uint256 callValue; // ETH value to send to the recipient (if any) - replaces V1's sendChainGas flag\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n address exclusivityRelayer;\n uint256 exclusivityEndTime;\n bytes callParams;\n }\n\n event BridgeQuoteDetails(bytes32 indexed transactionId, bytes quoteId);\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability\n /// to provide temporary exclusivity fill rights for the quote relayer.\n /// @param params The parameters required to bridge\n /// @param paramsV2 The parameters for exclusivity fill rights (optional, can be left empty)\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function relay(bytes memory request, address relayer) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param transactionId The transaction id associated with the encoded bridge transaction to prove\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital.\n /// @notice Can only send funds to the relayer address on the proof.\n /// @param request The encoded bridge transaction to claim on origin chain\n function claim(bytes memory request) external;\n /// @notice Checks if a transaction has been relayed\n /// @param transactionId The ID of the transaction to check\n /// @return True if the transaction has been relayed, false otherwise\n function bridgeRelays(bytes32 transactionId) external view returns (bool);\n\n /// @notice Returns the status of a bridge transaction\n /// @param transactionId The ID of the bridge transaction\n /// @return BridgeStatus Status of the bridge transaction\n function bridgeStatuses(bytes32 transactionId) external view returns (BridgeStatus);\n\n /// @notice Returns the timestamp and relayer of a bridge proof\n /// @param transactionId The ID of the bridge transaction\n /// @return timestamp The timestamp of the bridge proof\n /// @return relayer The relayer address of the bridge proof\n function bridgeProofs(bytes32 transactionId) external view returns (uint96 timestamp, address relayer);\n\n /// @notice Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\n /// @param request The bridge request to decode\n function getBridgeTransactionV2(bytes memory request) external view returns (BridgeTransactionV2 memory);\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// contracts/libs/UniversalToken.sol\n\nlibrary UniversalTokenLib {\n using SafeERC20 for IERC20;\n\n address internal constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Transfers tokens to the given account. Reverts if transfer is not successful.\n /// @dev This might trigger fallback, if ETH is transferred to the contract.\n /// Make sure this can not lead to reentrancy attacks.\n function universalTransfer(address token, address to, uint256 value) internal {\n // Don't do anything, if need to send tokens to this address\n if (to == address(this)) return;\n // Don't do anything, if trying to send zero value\n if (value == 0) return;\n if (token == ETH_ADDRESS) {\n /// @dev Note: this can potentially lead to executing code in `to`.\n // solhint-disable-next-line avoid-low-level-calls\n (bool success,) = to.call{value: value}(\"\");\n require(success, \"ETH transfer failed\");\n } else {\n IERC20(token).safeTransfer(to, value);\n }\n }\n\n /// @notice Issues an infinite allowance to the spender, if the current allowance is insufficient\n /// to spend the given amount.\n function universalApproveInfinity(address token, address spender, uint256 amountToSpend) internal {\n // ETH Chad doesn't require your approval\n if (token == ETH_ADDRESS) return;\n // No-op if allowance is already sufficient\n uint256 allowance = IERC20(token).allowance(address(this), spender);\n if (allowance \u003e= amountToSpend) return;\n // Otherwise, reset approval to 0 and set to max allowance\n if (allowance \u003e 0) IERC20(token).safeDecreaseAllowance(spender, allowance);\n IERC20(token).safeIncreaseAllowance(spender, type(uint256).max);\n }\n\n /// @notice Returns the balance of the given token (or native ETH) for the given account.\n function universalBalanceOf(address token, address account) internal view returns (uint256) {\n if (token == ETH_ADDRESS) {\n return account.balance;\n } else {\n return IERC20(token).balanceOf(account);\n }\n }\n\n /// @dev Checks that token is a contract and not ETH_ADDRESS.\n function assertIsContract(address token) internal view {\n // Check that ETH_ADDRESS was not used (in case this is a predeploy on any of the chains)\n if (token == UniversalTokenLib.ETH_ADDRESS) revert TokenNotContract();\n // Check that token is not an EOA\n if (token.code.length == 0) revert TokenNotContract();\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/Admin.sol\n\ncontract Admin is IAdmin, AccessControlEnumerable {\n using UniversalTokenLib for address;\n\n bytes32 public constant RELAYER_ROLE = keccak256(\"RELAYER_ROLE\");\n bytes32 public constant REFUNDER_ROLE = keccak256(\"REFUNDER_ROLE\");\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n uint256 public constant FEE_BPS = 1e6;\n uint256 public constant FEE_RATE_MAX = 0.01e6; // max 1% on origin amount\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Chain gas amount to forward as rebate if requested\n uint256 public chainGasAmount;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n }\n\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n require(newFeeRate \u003c= FEE_RATE_MAX, \"newFeeRate \u003e max\");\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n token.universalTransfer(recipient, feeAmount);\n emit FeesSwept(token, recipient, feeAmount);\n }\n\n function setChainGasAmount(uint256 newChainGasAmount) external onlyRole(GOVERNOR_ROLE) {\n uint256 oldChainGasAmount = chainGasAmount;\n chainGasAmount = newChainGasAmount;\n emit ChainGasAmountUpdated(oldChainGasAmount, newChainGasAmount);\n }\n}\n\n// contracts/FastBridgeV2.sol\n\n/// @notice FastBridgeV2 is a contract for bridging tokens across chains.\ncontract FastBridgeV2 is Admin, IFastBridgeV2, IFastBridgeV2Errors {\n using SafeERC20 for IERC20;\n using UniversalTokenLib for address;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Delay for a transaction after which it could be permisionlessly refunded\n uint256 public constant REFUND_DELAY = 7 days;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n /// @notice Maximum length of accepted callParams\n uint256 public constant MAX_CALL_PARAMS_LENGTH = 2 ** 16 - 1;\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeTxDetails) public bridgeTxDetails;\n /// @notice Relay details on destination chain\n mapping(bytes32 =\u003e BridgeRelay) public bridgeRelayDetails;\n /// @notice Unique bridge nonces tracked per originSender\n mapping(address =\u003e uint256) public senderNonces;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Replaced by senderNonces\n uint256 public immutable nonce = 0;\n /// @notice the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n bridge({\n params: params,\n paramsV2: BridgeParamsV2({\n quoteRelayer: address(0),\n quoteExclusivitySeconds: 0,\n quoteId: bytes(\"\"),\n callValue: 0,\n callParams: bytes(\"\")\n })\n });\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes memory request) external payable {\n relay({request: request, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes memory request, bytes32 destTxHash) external {\n prove({transactionId: keccak256(request), destTxHash: destTxHash, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridgeV2\n function claim(bytes memory request) external {\n claim({request: request, to: address(0)});\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003e DISPUTE_PERIOD) {\n revert DisputePeriodPassed();\n }\n\n // @dev relayer gets slashed effectively if dest relay has gone thru\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n bridgeTxDetails[transactionId].proofRelayer = address(0);\n bridgeTxDetails[transactionId].proofBlockTimestamp = 0;\n bridgeTxDetails[transactionId].proofBlockNumber = 0;\n\n emit BridgeProofDisputed(transactionId, msg.sender);\n }\n\n /// @inheritdoc IFastBridge\n function refund(bytes memory request) external {\n bytes32 transactionId = keccak256(request);\n\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n\n if (bridgeTxDetails[transactionId].status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n\n if (hasRole(REFUNDER_ROLE, msg.sender)) {\n // Refunder can refund if deadline has passed\n if (block.timestamp \u003c= transaction.deadline) revert DeadlineNotExceeded();\n } else {\n // Permissionless refund is allowed after REFUND_DELAY\n if (block.timestamp \u003c= transaction.deadline + REFUND_DELAY) revert DeadlineNotExceeded();\n }\n\n // if all checks passed, set to REFUNDED status\n bridgeTxDetails[transactionId].status = BridgeStatus.REFUNDED;\n\n // transfer origin collateral back to original sender\n address to = transaction.originSender;\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount + transaction.originFeeAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (bridgeTxDetails[transactionId].proofRelayer != relayer) revert SenderIncorrect();\n return _timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n /// @dev This method is added to achieve backwards compatibility with decoding requests into V1 structs:\n /// - `callValue` is partially reported as a zero/non-zero flag\n /// - `callParams` is ignored\n /// In order to process all kinds of requests use getBridgeTransactionV2 instead.\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory) {\n // Try decoding into V2 struct first. This will revert if V1 struct is passed\n try this.getBridgeTransactionV2(request) returns (BridgeTransactionV2 memory txV2) {\n // Note: we entirely ignore the callParams field, as it was not present in V1\n return BridgeTransaction({\n originChainId: txV2.originChainId,\n destChainId: txV2.destChainId,\n originSender: txV2.originSender,\n destRecipient: txV2.destRecipient,\n originToken: txV2.originToken,\n destToken: txV2.destToken,\n originAmount: txV2.originAmount,\n destAmount: txV2.destAmount,\n originFeeAmount: txV2.originFeeAmount,\n sendChainGas: txV2.callValue != 0,\n deadline: txV2.deadline,\n nonce: txV2.nonce\n });\n } catch {\n // Fallback to V1 struct\n return abi.decode(request, (BridgeTransaction));\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) public payable {\n int256 exclusivityEndTime = int256(block.timestamp) + paramsV2.quoteExclusivitySeconds;\n _validateBridgeParams(params, paramsV2, exclusivityEndTime);\n\n // transfer tokens to bridge contract\n /// @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _pullToken(params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n\n // set status to requested\n bytes memory request = abi.encode(\n BridgeTransactionV2({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n callValue: paramsV2.callValue,\n deadline: params.deadline,\n nonce: senderNonces[params.sender]++, // increment nonce on every bridge\n exclusivityRelayer: paramsV2.quoteRelayer,\n // We checked exclusivityEndTime to be in range (0 .. params.deadline] above, so can safely cast\n exclusivityEndTime: uint256(exclusivityEndTime),\n callParams: paramsV2.callParams\n })\n );\n bytes32 transactionId = keccak256(request);\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n\n emit BridgeRequested({\n transactionId: transactionId,\n sender: params.sender,\n request: request,\n destChainId: params.dstChainId,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n sendChainGas: paramsV2.callValue != 0\n });\n emit BridgeQuoteDetails(transactionId, paramsV2.quoteId);\n }\n\n /// @inheritdoc IFastBridgeV2\n function relay(bytes memory request, address relayer) public payable {\n bytes32 transactionId = keccak256(request);\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n _validateRelayParams(transaction, transactionId, relayer);\n // mark bridge transaction as relayed\n bridgeRelayDetails[transactionId] =\n BridgeRelay({blockNumber: uint48(block.number), blockTimestamp: uint48(block.timestamp), relayer: relayer});\n\n // transfer tokens to recipient on destination chain and do an arbitrary call if requested\n address to = transaction.destRecipient;\n address token = transaction.destToken;\n uint256 amount = transaction.destAmount;\n\n // All state changes have been done at this point, can proceed to the external calls.\n // This follows the checks-effects-interactions pattern to mitigate potential reentrancy attacks.\n if (token == UniversalTokenLib.ETH_ADDRESS) {\n // For ETH non-zero callValue is not allowed\n if (transaction.callValue != 0) revert NativeTokenCallValueNotSupported();\n // Check that the correct msg.value was sent\n if (msg.value != amount) revert MsgValueIncorrect();\n } else {\n // For ERC20s, we check that the correct msg.value was sent\n if (msg.value != transaction.callValue) revert MsgValueIncorrect();\n // We need to transfer the tokens from the Relayer to the recipient first before performing an\n // optional post-transfer arbitrary call.\n IERC20(token).safeTransferFrom(msg.sender, to, amount);\n }\n\n if (transaction.callParams.length != 0) {\n // Arbitrary call requested, perform it while supplying full msg.value to the recipient\n // Note: if token has a fee on transfers, the recipient will have received less than `amount`.\n // This is a very niche edge case and should be handled by the recipient contract.\n _checkedCallRecipient({recipient: to, token: token, amount: amount, callParams: transaction.callParams});\n } else if (msg.value != 0) {\n // No arbitrary call requested, but msg.value was sent. This is either a relay with ETH,\n // or a non-zero callValue request with an ERC20. In both cases, transfer the ETH to the recipient.\n Address.sendValue(payable(to), msg.value);\n }\n\n emit BridgeRelayed({\n transactionId: transactionId,\n relayer: relayer,\n to: to,\n originChainId: transaction.originChainId,\n originToken: transaction.originToken,\n destToken: transaction.destToken,\n originAmount: transaction.originAmount,\n destAmount: transaction.destAmount,\n chainGasAmount: transaction.callValue\n });\n }\n\n /// @inheritdoc IFastBridgeV2\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) public onlyRole(RELAYER_ROLE) {\n // update bridge tx status given proof provided\n if (bridgeTxDetails[transactionId].status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n bridgeTxDetails[transactionId].status = BridgeStatus.RELAYER_PROVED;\n bridgeTxDetails[transactionId].proofBlockTimestamp = uint40(block.timestamp);\n bridgeTxDetails[transactionId].proofBlockNumber = uint48(block.number);\n bridgeTxDetails[transactionId].proofRelayer = relayer;\n\n emit BridgeProofProvided(transactionId, relayer, destTxHash);\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes memory request, address to) public {\n bytes32 transactionId = keccak256(request);\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n\n // update bridge tx status if able to claim origin collateral\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n\n // if \"to\" is zero addr, permissionlessly send funds to proven relayer\n if (to == address(0)) {\n to = bridgeTxDetails[transactionId].proofRelayer;\n } else if (bridgeTxDetails[transactionId].proofRelayer != msg.sender) {\n revert SenderIncorrect();\n }\n\n if (_timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003c= DISPUTE_PERIOD) {\n revert DisputePeriodNotPassed();\n }\n\n bridgeTxDetails[transactionId].status = BridgeStatus.RELAYER_CLAIMED;\n\n // update protocol fees if origin fee amount exists\n if (transaction.originFeeAmount \u003e 0) protocolFees[transaction.originToken] += transaction.originFeeAmount;\n\n // transfer origin collateral less fee to specified address\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositClaimed(transactionId, bridgeTxDetails[transactionId].proofRelayer, to, token, amount);\n }\n\n function bridgeStatuses(bytes32 transactionId) public view returns (BridgeStatus status) {\n return bridgeTxDetails[transactionId].status;\n }\n\n function bridgeProofs(bytes32 transactionId) public view returns (uint96 timestamp, address relayer) {\n timestamp = bridgeTxDetails[transactionId].proofBlockTimestamp;\n relayer = bridgeTxDetails[transactionId].proofRelayer;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeRelays(bytes32 transactionId) public view returns (bool) {\n // has this transactionId been relayed?\n return bridgeRelayDetails[transactionId].relayer != address(0);\n }\n\n /// @inheritdoc IFastBridgeV2\n function getBridgeTransactionV2(bytes memory request) public pure returns (BridgeTransactionV2 memory) {\n return abi.decode(request, (BridgeTransactionV2));\n }\n\n /// @notice Pulls a requested token from the user to this contract.\n function _pullToken(address token, uint256 amount) internal returns (uint256 amountPulled) {\n if (token == UniversalTokenLib.ETH_ADDRESS) {\n // For ETH we just need to check that the supplied msg.value is correct\n if (amount != msg.value) revert MsgValueIncorrect();\n amountPulled = msg.value;\n } else {\n token.assertIsContract();\n // Record token balance before transfer\n amountPulled = IERC20(token).balanceOf(address(this));\n // Token needs to be pulled only if msg.value is zero\n // This way user can specify WETH as the origin asset\n IERC20(token).safeTransferFrom(msg.sender, address(this), amount);\n // Use the difference between the recorded balance and the current balance as the amountPulled\n amountPulled = IERC20(token).balanceOf(address(this)) - amountPulled;\n }\n }\n\n /// @notice Calls the Recipient's hook function with the specified callParams and performs\n /// all the necessary checks for the returned value.\n function _checkedCallRecipient(\n address recipient,\n address token,\n uint256 amount,\n bytes memory callParams\n )\n internal\n {\n bytes memory hookData =\n abi.encodeCall(IFastBridgeRecipient.fastBridgeTransferReceived, (token, amount, callParams));\n // This will bubble any revert messages from the hook function\n bytes memory returnData = Address.functionCallWithValue({target: recipient, data: hookData, value: msg.value});\n // Explicit revert if no return data at all\n if (returnData.length == 0) revert RecipientNoReturnValue();\n // Check that exactly a single return value was returned\n if (returnData.length != 32) revert RecipientIncorrectReturnValue();\n // Return value should be abi-encoded hook function selector\n if (bytes32(returnData) != bytes32(IFastBridgeRecipient.fastBridgeTransferReceived.selector)) {\n revert RecipientIncorrectReturnValue();\n }\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint40(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint40).max but\n /// proof.timestamp \u003c type(uint40).max via unchecked statement\n /// @param proofBlockTimestamp The bridge proof block timestamp\n /// @return delta Time delta since proof submitted\n function _timeSince(uint40 proofBlockTimestamp) internal view returns (uint256 delta) {\n unchecked {\n delta = uint40(block.timestamp) - proofBlockTimestamp;\n }\n }\n\n /// @notice Performs all the necessary checks for a bridge to happen.\n /// @dev There's no good way to refactor this function to reduce cyclomatic complexity due to\n /// the number of checks that need to be performed, so we skip the code-complexity rule here.\n // solhint-disable-next-line code-complexity\n function _validateBridgeParams(\n BridgeParams memory params,\n BridgeParamsV2 memory paramsV2,\n int256 exclusivityEndTime\n )\n internal\n view\n {\n // Check V1 (legacy) params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.sender == address(0) || params.to == address(0)) revert ZeroAddress();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n // Check V2 params\n if (paramsV2.callParams.length \u003e MAX_CALL_PARAMS_LENGTH) revert CallParamsLengthAboveMax();\n if (paramsV2.callValue != 0 \u0026\u0026 params.destToken == UniversalTokenLib.ETH_ADDRESS) {\n revert NativeTokenCallValueNotSupported();\n }\n // exclusivityEndTime must be in range (0 .. params.deadline]\n if (exclusivityEndTime \u003c= 0 || exclusivityEndTime \u003e int256(params.deadline)) {\n revert ExclusivityParamsIncorrect();\n }\n }\n\n /// @notice Performs all the necessary checks for a relay to happen.\n function _validateRelayParams(\n BridgeTransactionV2 memory transaction,\n bytes32 transactionId,\n address relayer\n )\n internal\n view\n {\n if (relayer == address(0)) revert ZeroAddress();\n // Check if the transaction has already been relayed\n if (bridgeRelays(transactionId)) revert TransactionRelayed();\n if (transaction.destChainId != uint32(block.chainid)) revert ChainIncorrect();\n // Check the deadline for relay to happen\n if (block.timestamp \u003e transaction.deadline) revert DeadlineExceeded();\n // Check the exclusivity period, if it is still ongoing\n // forgefmt: disable-next-item\n if (\n transaction.exclusivityRelayer != address(0) \u0026\u0026\n transaction.exclusivityRelayer != relayer \u0026\u0026\n block.timestamp \u003c= transaction.exclusivityEndTime\n ) {\n revert ExclusivityPeriodNotPassed();\n }\n }\n}\n","language":"Solidity","languageVersion":"0.8.24","compilerVersion":"0.8.24","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"","srcMapRuntime":"","abiDefinition":[{"inputs":[],"name":"AccessControlBadConfirmation","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"bytes32","name":"neededRole","type":"bytes32"}],"name":"AccessControlUnauthorizedAccount","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"previousAdminRole","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"newAdminRole","type":"bytes32"}],"name":"RoleAdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleRevoked","type":"event"},{"inputs":[],"name":"DEFAULT_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleAdmin","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"uint256","name":"index","type":"uint256"}],"name":"getRoleMember","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleMemberCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"grantRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"hasRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"callerConfirmation","type":"address"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"revokeRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"}],"userDoc":{"kind":"user","methods":{},"version":1},"developerDoc":{"details":"Extension of {AccessControl} that allows enumerating the members of each role.","errors":{"AccessControlBadConfirmation()":[{"details":"The caller of a function is not the expected one. NOTE: Don't confuse with {AccessControlUnauthorizedAccount}."}],"AccessControlUnauthorizedAccount(address,bytes32)":[{"details":"The `account` is missing a role."}]},"events":{"RoleAdminChanged(bytes32,bytes32,bytes32)":{"details":"Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole` `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite {RoleAdminChanged} not being emitted signaling this."},"RoleGranted(bytes32,address,address)":{"details":"Emitted when `account` is granted `role`. `sender` is the account that originated the contract call, an admin role bearer except when using {AccessControl-_setupRole}."},"RoleRevoked(bytes32,address,address)":{"details":"Emitted when `account` is revoked `role`. `sender` is the account that originated the contract call: - if using `revokeRole`, it is the admin role bearer - if using `renounceRole`, it is the role bearer (i.e. `account`)"}},"kind":"dev","methods":{"getRoleAdmin(bytes32)":{"details":"Returns the admin role that controls `role`. See {grantRole} and {revokeRole}. To change a role's admin, use {_setRoleAdmin}."},"getRoleMember(bytes32,uint256)":{"details":"Returns one of the accounts that have `role`. `index` must be a value between 0 and {getRoleMemberCount}, non-inclusive. Role bearers are not sorted in any particular way, and their ordering may change at any point. WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure you perform all queries on the same block. See the following https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post] for more information."},"getRoleMemberCount(bytes32)":{"details":"Returns the number of accounts that have `role`. Can be used together with {getRoleMember} to enumerate all bearers of a role."},"grantRole(bytes32,address)":{"details":"Grants `role` to `account`. If `account` had not been already granted `role`, emits a {RoleGranted} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleGranted} event."},"hasRole(bytes32,address)":{"details":"Returns `true` if `account` has been granted `role`."},"renounceRole(bytes32,address)":{"details":"Revokes `role` from the calling account. Roles are often managed via {grantRole} and {revokeRole}: this function's purpose is to provide a mechanism for accounts to lose their privileges if they are compromised (such as when a trusted device is misplaced). If the calling account had been revoked `role`, emits a {RoleRevoked} event. Requirements: - the caller must be `callerConfirmation`. May emit a {RoleRevoked} event."},"revokeRole(bytes32,address)":{"details":"Revokes `role` from `account`. If `account` had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleRevoked} event."},"supportsInterface(bytes4)":{"details":"See {IERC165-supportsInterface}."}},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[],\"name\":\"AccessControlBadConfirmation\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"neededRole\",\"type\":\"bytes32\"}],\"name\":\"AccessControlUnauthorizedAccount\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"previousAdminRole\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"newAdminRole\",\"type\":\"bytes32\"}],\"name\":\"RoleAdminChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleGranted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleRevoked\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"DEFAULT_ADMIN_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"}],\"name\":\"getRoleAdmin\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"index\",\"type\":\"uint256\"}],\"name\":\"getRoleMember\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"}],\"name\":\"getRoleMemberCount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"grantRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"hasRole\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"callerConfirmation\",\"type\":\"address\"}],\"name\":\"renounceRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"revokeRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes4\",\"name\":\"interfaceId\",\"type\":\"bytes4\"}],\"name\":\"supportsInterface\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"}],\"devdoc\":{\"details\":\"Extension of {AccessControl} that allows enumerating the members of each role.\",\"errors\":{\"AccessControlBadConfirmation()\":[{\"details\":\"The caller of a function is not the expected one. NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\"}],\"AccessControlUnauthorizedAccount(address,bytes32)\":[{\"details\":\"The `account` is missing a role.\"}]},\"events\":{\"RoleAdminChanged(bytes32,bytes32,bytes32)\":{\"details\":\"Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole` `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite {RoleAdminChanged} not being emitted signaling this.\"},\"RoleGranted(bytes32,address,address)\":{\"details\":\"Emitted when `account` is granted `role`. `sender` is the account that originated the contract call, an admin role bearer except when using {AccessControl-_setupRole}.\"},\"RoleRevoked(bytes32,address,address)\":{\"details\":\"Emitted when `account` is revoked `role`. `sender` is the account that originated the contract call: - if using `revokeRole`, it is the admin role bearer - if using `renounceRole`, it is the role bearer (i.e. `account`)\"}},\"kind\":\"dev\",\"methods\":{\"getRoleAdmin(bytes32)\":{\"details\":\"Returns the admin role that controls `role`. See {grantRole} and {revokeRole}. To change a role's admin, use {_setRoleAdmin}.\"},\"getRoleMember(bytes32,uint256)\":{\"details\":\"Returns one of the accounts that have `role`. `index` must be a value between 0 and {getRoleMemberCount}, non-inclusive. Role bearers are not sorted in any particular way, and their ordering may change at any point. WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure you perform all queries on the same block. See the following https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post] for more information.\"},\"getRoleMemberCount(bytes32)\":{\"details\":\"Returns the number of accounts that have `role`. Can be used together with {getRoleMember} to enumerate all bearers of a role.\"},\"grantRole(bytes32,address)\":{\"details\":\"Grants `role` to `account`. If `account` had not been already granted `role`, emits a {RoleGranted} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleGranted} event.\"},\"hasRole(bytes32,address)\":{\"details\":\"Returns `true` if `account` has been granted `role`.\"},\"renounceRole(bytes32,address)\":{\"details\":\"Revokes `role` from the calling account. Roles are often managed via {grantRole} and {revokeRole}: this function's purpose is to provide a mechanism for accounts to lose their privileges if they are compromised (such as when a trusted device is misplaced). If the calling account had been revoked `role`, emits a {RoleRevoked} event. Requirements: - the caller must be `callerConfirmation`. May emit a {RoleRevoked} event.\"},\"revokeRole(bytes32,address)\":{\"details\":\"Revokes `role` from `account`. If `account` had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleRevoked} event.\"},\"supportsInterface(bytes4)\":{\"details\":\"See {IERC165-supportsInterface}.\"}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeV2.sol\":\"AccessControlEnumerable\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeV2.sol\":{\"keccak256\":\"0x7cd0f885e80e2bdaa638bc32ae7af7d2e248f99ce4b354c217d0f0f7d7302e0a\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://7ccf28df0bd7b4606986585acd8622ed9b4e81379690061bb66088f0a2270af1\",\"dweb:/ipfs/QmTf7HNdHZkK6vmx8ZgewycQEb72oLD9nPwBpsM5reMstQ\"]}},\"version\":1}"},"hashes":{"DEFAULT_ADMIN_ROLE()":"a217fddf","getRoleAdmin(bytes32)":"248a9ca3","getRoleMember(bytes32,uint256)":"9010d07c","getRoleMemberCount(bytes32)":"ca15c873","grantRole(bytes32,address)":"2f2ff15d","hasRole(bytes32,address)":"91d14854","renounceRole(bytes32,address)":"36568abe","revokeRole(bytes32,address)":"d547741f","supportsInterface(bytes4)":"01ffc9a7"}},"solidity/FastBridgeV2.sol:Address":{"code":"0x60566037600b82828239805160001a607314602a57634e487b7160e01b600052600060045260246000fd5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600080fdfea26469706673582212209373c953367c76b94c1908124544fbcf053f6653eb651760b4d42f0f487710d864736f6c63430008180033","runtime-code":"0x73000000000000000000000000000000000000000030146080604052600080fdfea26469706673582212209373c953367c76b94c1908124544fbcf053f6653eb651760b4d42f0f487710d864736f6c63430008180033","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.24 ^0.8.0 ^0.8.20;\n\n// contracts/interfaces/IAdmin.sol\n\ninterface IAdmin {\n // ============ Events ============\n\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n event ChainGasAmountUpdated(uint256 oldChainGasAmount, uint256 newChainGasAmount);\n\n // ============ Methods ============\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n\n function setChainGasAmount(uint256 newChainGasAmount) external;\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IFastBridgeRecipient.sol\n\ninterface IFastBridgeRecipient {\n function fastBridgeTransferReceived(\n address token,\n uint256 amount,\n bytes memory callParams\n )\n external\n payable\n returns (bytes4);\n}\n\n// contracts/interfaces/IFastBridgeV2Errors.sol\n\ninterface IFastBridgeV2Errors {\n error AmountIncorrect();\n error CallParamsLengthAboveMax();\n error ChainIncorrect();\n error ExclusivityParamsIncorrect();\n error MsgValueIncorrect();\n error NativeTokenCallValueNotSupported();\n error SenderIncorrect();\n error StatusIncorrect();\n error ZeroAddress();\n\n error RecipientIncorrectReturnValue();\n error RecipientNoReturnValue();\n\n error DeadlineExceeded();\n error DeadlineNotExceeded();\n error DeadlineTooShort();\n error DisputePeriodNotPassed();\n error DisputePeriodPassed();\n error ExclusivityPeriodNotPassed();\n\n error TransactionRelayed();\n}\n\n// contracts/libs/Errors.sol\n\nerror DeadlineExceeded();\nerror DeadlineNotExceeded();\nerror DeadlineTooShort();\nerror InsufficientOutputAmount();\n\nerror MsgValueIncorrect();\nerror PoolNotFound();\nerror TokenAddressMismatch();\nerror TokenNotContract();\nerror TokenNotETH();\nerror TokensIdentical();\n\nerror ChainIncorrect();\nerror AmountIncorrect();\nerror ZeroAddress();\n\nerror DisputePeriodNotPassed();\nerror DisputePeriodPassed();\nerror SenderIncorrect();\nerror StatusIncorrect();\nerror TransactionIdIncorrect();\nerror TransactionRelayed();\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// contracts/interfaces/IFastBridgeV2.sol\n\ninterface IFastBridgeV2 is IFastBridge {\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n struct BridgeTxDetails {\n BridgeStatus status;\n uint40 proofBlockTimestamp;\n uint48 proofBlockNumber;\n address proofRelayer;\n }\n\n struct BridgeRelay {\n uint48 blockNumber;\n uint48 blockTimestamp;\n address relayer;\n }\n\n /// @notice New params introduced in the FastBridgeV2.\n /// We are passing fields from the older BridgeParams struct outside of this struct\n /// for backwards compatibility.\n /// Note: quoteRelayer and quoteExclusivitySeconds are either both zero (indicating no exclusivity)\n /// or both non-zero (indicating exclusivity for the given period).\n /// Note: callValue \u003e 0 can NOT be used with destToken = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE (ETH_ADDRESS)\n /// @param quoteRelayer Relayer that provided the quote for the transaction\n /// @param quoteExclusivitySeconds Period of time the quote relayer is guaranteed exclusivity after user's deposit\n /// @param quoteId Unique quote identifier used for tracking the quote\n /// @param callValue ETH value to send to the recipient (if any)\n /// @param callParams Parameters for the arbitrary call to the destination recipient (if any)\n struct BridgeParamsV2 {\n address quoteRelayer;\n int256 quoteExclusivitySeconds;\n bytes quoteId;\n uint256 callValue;\n bytes callParams;\n }\n\n /// @notice Updated bridge transaction struct to include parameters introduced in FastBridgeV2.\n /// Note: only `exclusivityRelayer` can fill such a transaction until `exclusivityEndTime`.\n /// TODO: consider changing the encoding scheme to prevent spending extra gas on decoding.\n struct BridgeTransactionV2 {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n uint256 callValue; // ETH value to send to the recipient (if any) - replaces V1's sendChainGas flag\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n address exclusivityRelayer;\n uint256 exclusivityEndTime;\n bytes callParams;\n }\n\n event BridgeQuoteDetails(bytes32 indexed transactionId, bytes quoteId);\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability\n /// to provide temporary exclusivity fill rights for the quote relayer.\n /// @param params The parameters required to bridge\n /// @param paramsV2 The parameters for exclusivity fill rights (optional, can be left empty)\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function relay(bytes memory request, address relayer) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param transactionId The transaction id associated with the encoded bridge transaction to prove\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital.\n /// @notice Can only send funds to the relayer address on the proof.\n /// @param request The encoded bridge transaction to claim on origin chain\n function claim(bytes memory request) external;\n /// @notice Checks if a transaction has been relayed\n /// @param transactionId The ID of the transaction to check\n /// @return True if the transaction has been relayed, false otherwise\n function bridgeRelays(bytes32 transactionId) external view returns (bool);\n\n /// @notice Returns the status of a bridge transaction\n /// @param transactionId The ID of the bridge transaction\n /// @return BridgeStatus Status of the bridge transaction\n function bridgeStatuses(bytes32 transactionId) external view returns (BridgeStatus);\n\n /// @notice Returns the timestamp and relayer of a bridge proof\n /// @param transactionId The ID of the bridge transaction\n /// @return timestamp The timestamp of the bridge proof\n /// @return relayer The relayer address of the bridge proof\n function bridgeProofs(bytes32 transactionId) external view returns (uint96 timestamp, address relayer);\n\n /// @notice Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\n /// @param request The bridge request to decode\n function getBridgeTransactionV2(bytes memory request) external view returns (BridgeTransactionV2 memory);\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// contracts/libs/UniversalToken.sol\n\nlibrary UniversalTokenLib {\n using SafeERC20 for IERC20;\n\n address internal constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Transfers tokens to the given account. Reverts if transfer is not successful.\n /// @dev This might trigger fallback, if ETH is transferred to the contract.\n /// Make sure this can not lead to reentrancy attacks.\n function universalTransfer(address token, address to, uint256 value) internal {\n // Don't do anything, if need to send tokens to this address\n if (to == address(this)) return;\n // Don't do anything, if trying to send zero value\n if (value == 0) return;\n if (token == ETH_ADDRESS) {\n /// @dev Note: this can potentially lead to executing code in `to`.\n // solhint-disable-next-line avoid-low-level-calls\n (bool success,) = to.call{value: value}(\"\");\n require(success, \"ETH transfer failed\");\n } else {\n IERC20(token).safeTransfer(to, value);\n }\n }\n\n /// @notice Issues an infinite allowance to the spender, if the current allowance is insufficient\n /// to spend the given amount.\n function universalApproveInfinity(address token, address spender, uint256 amountToSpend) internal {\n // ETH Chad doesn't require your approval\n if (token == ETH_ADDRESS) return;\n // No-op if allowance is already sufficient\n uint256 allowance = IERC20(token).allowance(address(this), spender);\n if (allowance \u003e= amountToSpend) return;\n // Otherwise, reset approval to 0 and set to max allowance\n if (allowance \u003e 0) IERC20(token).safeDecreaseAllowance(spender, allowance);\n IERC20(token).safeIncreaseAllowance(spender, type(uint256).max);\n }\n\n /// @notice Returns the balance of the given token (or native ETH) for the given account.\n function universalBalanceOf(address token, address account) internal view returns (uint256) {\n if (token == ETH_ADDRESS) {\n return account.balance;\n } else {\n return IERC20(token).balanceOf(account);\n }\n }\n\n /// @dev Checks that token is a contract and not ETH_ADDRESS.\n function assertIsContract(address token) internal view {\n // Check that ETH_ADDRESS was not used (in case this is a predeploy on any of the chains)\n if (token == UniversalTokenLib.ETH_ADDRESS) revert TokenNotContract();\n // Check that token is not an EOA\n if (token.code.length == 0) revert TokenNotContract();\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/Admin.sol\n\ncontract Admin is IAdmin, AccessControlEnumerable {\n using UniversalTokenLib for address;\n\n bytes32 public constant RELAYER_ROLE = keccak256(\"RELAYER_ROLE\");\n bytes32 public constant REFUNDER_ROLE = keccak256(\"REFUNDER_ROLE\");\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n uint256 public constant FEE_BPS = 1e6;\n uint256 public constant FEE_RATE_MAX = 0.01e6; // max 1% on origin amount\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Chain gas amount to forward as rebate if requested\n uint256 public chainGasAmount;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n }\n\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n require(newFeeRate \u003c= FEE_RATE_MAX, \"newFeeRate \u003e max\");\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n token.universalTransfer(recipient, feeAmount);\n emit FeesSwept(token, recipient, feeAmount);\n }\n\n function setChainGasAmount(uint256 newChainGasAmount) external onlyRole(GOVERNOR_ROLE) {\n uint256 oldChainGasAmount = chainGasAmount;\n chainGasAmount = newChainGasAmount;\n emit ChainGasAmountUpdated(oldChainGasAmount, newChainGasAmount);\n }\n}\n\n// contracts/FastBridgeV2.sol\n\n/// @notice FastBridgeV2 is a contract for bridging tokens across chains.\ncontract FastBridgeV2 is Admin, IFastBridgeV2, IFastBridgeV2Errors {\n using SafeERC20 for IERC20;\n using UniversalTokenLib for address;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Delay for a transaction after which it could be permisionlessly refunded\n uint256 public constant REFUND_DELAY = 7 days;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n /// @notice Maximum length of accepted callParams\n uint256 public constant MAX_CALL_PARAMS_LENGTH = 2 ** 16 - 1;\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeTxDetails) public bridgeTxDetails;\n /// @notice Relay details on destination chain\n mapping(bytes32 =\u003e BridgeRelay) public bridgeRelayDetails;\n /// @notice Unique bridge nonces tracked per originSender\n mapping(address =\u003e uint256) public senderNonces;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Replaced by senderNonces\n uint256 public immutable nonce = 0;\n /// @notice the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n bridge({\n params: params,\n paramsV2: BridgeParamsV2({\n quoteRelayer: address(0),\n quoteExclusivitySeconds: 0,\n quoteId: bytes(\"\"),\n callValue: 0,\n callParams: bytes(\"\")\n })\n });\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes memory request) external payable {\n relay({request: request, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes memory request, bytes32 destTxHash) external {\n prove({transactionId: keccak256(request), destTxHash: destTxHash, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridgeV2\n function claim(bytes memory request) external {\n claim({request: request, to: address(0)});\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003e DISPUTE_PERIOD) {\n revert DisputePeriodPassed();\n }\n\n // @dev relayer gets slashed effectively if dest relay has gone thru\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n bridgeTxDetails[transactionId].proofRelayer = address(0);\n bridgeTxDetails[transactionId].proofBlockTimestamp = 0;\n bridgeTxDetails[transactionId].proofBlockNumber = 0;\n\n emit BridgeProofDisputed(transactionId, msg.sender);\n }\n\n /// @inheritdoc IFastBridge\n function refund(bytes memory request) external {\n bytes32 transactionId = keccak256(request);\n\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n\n if (bridgeTxDetails[transactionId].status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n\n if (hasRole(REFUNDER_ROLE, msg.sender)) {\n // Refunder can refund if deadline has passed\n if (block.timestamp \u003c= transaction.deadline) revert DeadlineNotExceeded();\n } else {\n // Permissionless refund is allowed after REFUND_DELAY\n if (block.timestamp \u003c= transaction.deadline + REFUND_DELAY) revert DeadlineNotExceeded();\n }\n\n // if all checks passed, set to REFUNDED status\n bridgeTxDetails[transactionId].status = BridgeStatus.REFUNDED;\n\n // transfer origin collateral back to original sender\n address to = transaction.originSender;\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount + transaction.originFeeAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (bridgeTxDetails[transactionId].proofRelayer != relayer) revert SenderIncorrect();\n return _timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n /// @dev This method is added to achieve backwards compatibility with decoding requests into V1 structs:\n /// - `callValue` is partially reported as a zero/non-zero flag\n /// - `callParams` is ignored\n /// In order to process all kinds of requests use getBridgeTransactionV2 instead.\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory) {\n // Try decoding into V2 struct first. This will revert if V1 struct is passed\n try this.getBridgeTransactionV2(request) returns (BridgeTransactionV2 memory txV2) {\n // Note: we entirely ignore the callParams field, as it was not present in V1\n return BridgeTransaction({\n originChainId: txV2.originChainId,\n destChainId: txV2.destChainId,\n originSender: txV2.originSender,\n destRecipient: txV2.destRecipient,\n originToken: txV2.originToken,\n destToken: txV2.destToken,\n originAmount: txV2.originAmount,\n destAmount: txV2.destAmount,\n originFeeAmount: txV2.originFeeAmount,\n sendChainGas: txV2.callValue != 0,\n deadline: txV2.deadline,\n nonce: txV2.nonce\n });\n } catch {\n // Fallback to V1 struct\n return abi.decode(request, (BridgeTransaction));\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) public payable {\n int256 exclusivityEndTime = int256(block.timestamp) + paramsV2.quoteExclusivitySeconds;\n _validateBridgeParams(params, paramsV2, exclusivityEndTime);\n\n // transfer tokens to bridge contract\n /// @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _pullToken(params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n\n // set status to requested\n bytes memory request = abi.encode(\n BridgeTransactionV2({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n callValue: paramsV2.callValue,\n deadline: params.deadline,\n nonce: senderNonces[params.sender]++, // increment nonce on every bridge\n exclusivityRelayer: paramsV2.quoteRelayer,\n // We checked exclusivityEndTime to be in range (0 .. params.deadline] above, so can safely cast\n exclusivityEndTime: uint256(exclusivityEndTime),\n callParams: paramsV2.callParams\n })\n );\n bytes32 transactionId = keccak256(request);\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n\n emit BridgeRequested({\n transactionId: transactionId,\n sender: params.sender,\n request: request,\n destChainId: params.dstChainId,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n sendChainGas: paramsV2.callValue != 0\n });\n emit BridgeQuoteDetails(transactionId, paramsV2.quoteId);\n }\n\n /// @inheritdoc IFastBridgeV2\n function relay(bytes memory request, address relayer) public payable {\n bytes32 transactionId = keccak256(request);\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n _validateRelayParams(transaction, transactionId, relayer);\n // mark bridge transaction as relayed\n bridgeRelayDetails[transactionId] =\n BridgeRelay({blockNumber: uint48(block.number), blockTimestamp: uint48(block.timestamp), relayer: relayer});\n\n // transfer tokens to recipient on destination chain and do an arbitrary call if requested\n address to = transaction.destRecipient;\n address token = transaction.destToken;\n uint256 amount = transaction.destAmount;\n\n // All state changes have been done at this point, can proceed to the external calls.\n // This follows the checks-effects-interactions pattern to mitigate potential reentrancy attacks.\n if (token == UniversalTokenLib.ETH_ADDRESS) {\n // For ETH non-zero callValue is not allowed\n if (transaction.callValue != 0) revert NativeTokenCallValueNotSupported();\n // Check that the correct msg.value was sent\n if (msg.value != amount) revert MsgValueIncorrect();\n } else {\n // For ERC20s, we check that the correct msg.value was sent\n if (msg.value != transaction.callValue) revert MsgValueIncorrect();\n // We need to transfer the tokens from the Relayer to the recipient first before performing an\n // optional post-transfer arbitrary call.\n IERC20(token).safeTransferFrom(msg.sender, to, amount);\n }\n\n if (transaction.callParams.length != 0) {\n // Arbitrary call requested, perform it while supplying full msg.value to the recipient\n // Note: if token has a fee on transfers, the recipient will have received less than `amount`.\n // This is a very niche edge case and should be handled by the recipient contract.\n _checkedCallRecipient({recipient: to, token: token, amount: amount, callParams: transaction.callParams});\n } else if (msg.value != 0) {\n // No arbitrary call requested, but msg.value was sent. This is either a relay with ETH,\n // or a non-zero callValue request with an ERC20. In both cases, transfer the ETH to the recipient.\n Address.sendValue(payable(to), msg.value);\n }\n\n emit BridgeRelayed({\n transactionId: transactionId,\n relayer: relayer,\n to: to,\n originChainId: transaction.originChainId,\n originToken: transaction.originToken,\n destToken: transaction.destToken,\n originAmount: transaction.originAmount,\n destAmount: transaction.destAmount,\n chainGasAmount: transaction.callValue\n });\n }\n\n /// @inheritdoc IFastBridgeV2\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) public onlyRole(RELAYER_ROLE) {\n // update bridge tx status given proof provided\n if (bridgeTxDetails[transactionId].status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n bridgeTxDetails[transactionId].status = BridgeStatus.RELAYER_PROVED;\n bridgeTxDetails[transactionId].proofBlockTimestamp = uint40(block.timestamp);\n bridgeTxDetails[transactionId].proofBlockNumber = uint48(block.number);\n bridgeTxDetails[transactionId].proofRelayer = relayer;\n\n emit BridgeProofProvided(transactionId, relayer, destTxHash);\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes memory request, address to) public {\n bytes32 transactionId = keccak256(request);\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n\n // update bridge tx status if able to claim origin collateral\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n\n // if \"to\" is zero addr, permissionlessly send funds to proven relayer\n if (to == address(0)) {\n to = bridgeTxDetails[transactionId].proofRelayer;\n } else if (bridgeTxDetails[transactionId].proofRelayer != msg.sender) {\n revert SenderIncorrect();\n }\n\n if (_timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003c= DISPUTE_PERIOD) {\n revert DisputePeriodNotPassed();\n }\n\n bridgeTxDetails[transactionId].status = BridgeStatus.RELAYER_CLAIMED;\n\n // update protocol fees if origin fee amount exists\n if (transaction.originFeeAmount \u003e 0) protocolFees[transaction.originToken] += transaction.originFeeAmount;\n\n // transfer origin collateral less fee to specified address\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositClaimed(transactionId, bridgeTxDetails[transactionId].proofRelayer, to, token, amount);\n }\n\n function bridgeStatuses(bytes32 transactionId) public view returns (BridgeStatus status) {\n return bridgeTxDetails[transactionId].status;\n }\n\n function bridgeProofs(bytes32 transactionId) public view returns (uint96 timestamp, address relayer) {\n timestamp = bridgeTxDetails[transactionId].proofBlockTimestamp;\n relayer = bridgeTxDetails[transactionId].proofRelayer;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeRelays(bytes32 transactionId) public view returns (bool) {\n // has this transactionId been relayed?\n return bridgeRelayDetails[transactionId].relayer != address(0);\n }\n\n /// @inheritdoc IFastBridgeV2\n function getBridgeTransactionV2(bytes memory request) public pure returns (BridgeTransactionV2 memory) {\n return abi.decode(request, (BridgeTransactionV2));\n }\n\n /// @notice Pulls a requested token from the user to this contract.\n function _pullToken(address token, uint256 amount) internal returns (uint256 amountPulled) {\n if (token == UniversalTokenLib.ETH_ADDRESS) {\n // For ETH we just need to check that the supplied msg.value is correct\n if (amount != msg.value) revert MsgValueIncorrect();\n amountPulled = msg.value;\n } else {\n token.assertIsContract();\n // Record token balance before transfer\n amountPulled = IERC20(token).balanceOf(address(this));\n // Token needs to be pulled only if msg.value is zero\n // This way user can specify WETH as the origin asset\n IERC20(token).safeTransferFrom(msg.sender, address(this), amount);\n // Use the difference between the recorded balance and the current balance as the amountPulled\n amountPulled = IERC20(token).balanceOf(address(this)) - amountPulled;\n }\n }\n\n /// @notice Calls the Recipient's hook function with the specified callParams and performs\n /// all the necessary checks for the returned value.\n function _checkedCallRecipient(\n address recipient,\n address token,\n uint256 amount,\n bytes memory callParams\n )\n internal\n {\n bytes memory hookData =\n abi.encodeCall(IFastBridgeRecipient.fastBridgeTransferReceived, (token, amount, callParams));\n // This will bubble any revert messages from the hook function\n bytes memory returnData = Address.functionCallWithValue({target: recipient, data: hookData, value: msg.value});\n // Explicit revert if no return data at all\n if (returnData.length == 0) revert RecipientNoReturnValue();\n // Check that exactly a single return value was returned\n if (returnData.length != 32) revert RecipientIncorrectReturnValue();\n // Return value should be abi-encoded hook function selector\n if (bytes32(returnData) != bytes32(IFastBridgeRecipient.fastBridgeTransferReceived.selector)) {\n revert RecipientIncorrectReturnValue();\n }\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint40(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint40).max but\n /// proof.timestamp \u003c type(uint40).max via unchecked statement\n /// @param proofBlockTimestamp The bridge proof block timestamp\n /// @return delta Time delta since proof submitted\n function _timeSince(uint40 proofBlockTimestamp) internal view returns (uint256 delta) {\n unchecked {\n delta = uint40(block.timestamp) - proofBlockTimestamp;\n }\n }\n\n /// @notice Performs all the necessary checks for a bridge to happen.\n /// @dev There's no good way to refactor this function to reduce cyclomatic complexity due to\n /// the number of checks that need to be performed, so we skip the code-complexity rule here.\n // solhint-disable-next-line code-complexity\n function _validateBridgeParams(\n BridgeParams memory params,\n BridgeParamsV2 memory paramsV2,\n int256 exclusivityEndTime\n )\n internal\n view\n {\n // Check V1 (legacy) params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.sender == address(0) || params.to == address(0)) revert ZeroAddress();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n // Check V2 params\n if (paramsV2.callParams.length \u003e MAX_CALL_PARAMS_LENGTH) revert CallParamsLengthAboveMax();\n if (paramsV2.callValue != 0 \u0026\u0026 params.destToken == UniversalTokenLib.ETH_ADDRESS) {\n revert NativeTokenCallValueNotSupported();\n }\n // exclusivityEndTime must be in range (0 .. params.deadline]\n if (exclusivityEndTime \u003c= 0 || exclusivityEndTime \u003e int256(params.deadline)) {\n revert ExclusivityParamsIncorrect();\n }\n }\n\n /// @notice Performs all the necessary checks for a relay to happen.\n function _validateRelayParams(\n BridgeTransactionV2 memory transaction,\n bytes32 transactionId,\n address relayer\n )\n internal\n view\n {\n if (relayer == address(0)) revert ZeroAddress();\n // Check if the transaction has already been relayed\n if (bridgeRelays(transactionId)) revert TransactionRelayed();\n if (transaction.destChainId != uint32(block.chainid)) revert ChainIncorrect();\n // Check the deadline for relay to happen\n if (block.timestamp \u003e transaction.deadline) revert DeadlineExceeded();\n // Check the exclusivity period, if it is still ongoing\n // forgefmt: disable-next-item\n if (\n transaction.exclusivityRelayer != address(0) \u0026\u0026\n transaction.exclusivityRelayer != relayer \u0026\u0026\n block.timestamp \u003c= transaction.exclusivityEndTime\n ) {\n revert ExclusivityPeriodNotPassed();\n }\n }\n}\n","language":"Solidity","languageVersion":"0.8.24","compilerVersion":"0.8.24","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"16564:6066:0:-:0;;;;;;;;;;;;;;;-1:-1:-1;;;16564:6066:0;;;;;;;;;;;;;;;;;","srcMapRuntime":"16564:6066:0:-:0;;;;;;;;","abiDefinition":[{"inputs":[{"internalType":"address","name":"target","type":"address"}],"name":"AddressEmptyCode","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"AddressInsufficientBalance","type":"error"},{"inputs":[],"name":"FailedInnerCall","type":"error"}],"userDoc":{"kind":"user","methods":{},"version":1},"developerDoc":{"details":"Collection of functions related to the address type","errors":{"AddressEmptyCode(address)":[{"details":"There's no code at `target` (it is not a contract)."}],"AddressInsufficientBalance(address)":[{"details":"The ETH balance of the account is not enough to perform the operation."}],"FailedInnerCall()":[{"details":"A call to an address target failed. The target may have reverted."}]},"kind":"dev","methods":{},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"}],\"name\":\"AddressEmptyCode\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"AddressInsufficientBalance\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"FailedInnerCall\",\"type\":\"error\"}],\"devdoc\":{\"details\":\"Collection of functions related to the address type\",\"errors\":{\"AddressEmptyCode(address)\":[{\"details\":\"There's no code at `target` (it is not a contract).\"}],\"AddressInsufficientBalance(address)\":[{\"details\":\"The ETH balance of the account is not enough to perform the operation.\"}],\"FailedInnerCall()\":[{\"details\":\"A call to an address target failed. The target may have reverted.\"}]},\"kind\":\"dev\",\"methods\":{},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeV2.sol\":\"Address\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeV2.sol\":{\"keccak256\":\"0x7cd0f885e80e2bdaa638bc32ae7af7d2e248f99ce4b354c217d0f0f7d7302e0a\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://7ccf28df0bd7b4606986585acd8622ed9b4e81379690061bb66088f0a2270af1\",\"dweb:/ipfs/QmTf7HNdHZkK6vmx8ZgewycQEb72oLD9nPwBpsM5reMstQ\"]}},\"version\":1}"},"hashes":{}},"solidity/FastBridgeV2.sol:Admin":{"code":"0x60806040523480156200001157600080fd5b50604051620014123803806200141283398101604081905262000034916200018e565b6200004160008262000049565b5050620001b9565b60008062000058848462000086565b905080156200007d5760008481526001602052604090206200007b908462000134565b505b90505b92915050565b6000828152602081815260408083206001600160a01b038516845290915281205460ff166200012b576000838152602081815260408083206001600160a01b03861684529091529020805460ff19166001179055620000e23390565b6001600160a01b0316826001600160a01b0316847f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a450600162000080565b50600062000080565b60006200007d836001600160a01b03841660008181526001830160205260408120546200012b5750815460018181018455600084815260208082209093018490558454848252828601909352604090209190915562000080565b600060208284031215620001a157600080fd5b81516001600160a01b03811681146200007d57600080fd5b61124980620001c96000396000f3fe608060405234801561001057600080fd5b50600436106101775760003560e01c806391d14854116100d8578063bf333f2c1161008c578063d547741f11610066578063d547741f14610385578063dcf844a714610398578063e00a83e0146103b857600080fd5b8063bf333f2c14610341578063ca15c8731461034b578063ccc574901461035e57600080fd5b8063a217fddf116100bd578063a217fddf14610313578063b13aa2d61461031b578063b250fe6b1461032e57600080fd5b806391d14854146102a8578063926d7d7f146102ec57600080fd5b80632f2ff15d1161012f57806358f858801161011457806358f85880146102405780635960ccf2146102495780639010d07c1461027057600080fd5b80632f2ff15d1461021a57806336568abe1461022d57600080fd5b806306f333f21161016057806306f333f2146101d95780630f5f6ed7146101ee578063248a9ca3146101f757600080fd5b806301ffc9a71461017c57806303ed0ee5146101a4575b600080fd5b61018f61018a366004611013565b6103c1565b60405190151581526020015b60405180910390f35b6101cb7f043c983c49d46f0e102151eaf8085d4a2e6571d5df2d47b013f39bddfd4a639d81565b60405190815260200161019b565b6101ec6101e736600461107e565b61041d565b005b6101cb61271081565b6101cb6102053660046110b1565b60009081526020819052604090206001015490565b6101ec6102283660046110ca565b61050b565b6101ec61023b3660046110ca565b610536565b6101cb60025481565b6101cb7fdb9556138406326f00296e13ea2ad7db24ba82381212d816b1a40c23b466b32781565b61028361027e3660046110ed565b61058f565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200161019b565b61018f6102b63660046110ca565b60009182526020828152604080842073ffffffffffffffffffffffffffffffffffffffff93909316845291905290205460ff1690565b6101cb7fe2b7fb3b832174769106daebcfd6d1970523240dda11281102db9363b83b0dc481565b6101cb600081565b6101ec6103293660046110b1565b6105ae565b6101ec61033c3660046110b1565b610690565b6101cb620f424081565b6101cb6103593660046110b1565b6106f8565b6101cb7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f5581565b6101ec6103933660046110ca565b61070f565b6101cb6103a636600461110f565b60036020526000908152604090205481565b6101cb60045481565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f5a05180f000000000000000000000000000000000000000000000000000000001480610417575061041782610734565b92915050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f55610447816107cb565b73ffffffffffffffffffffffffffffffffffffffff83166000908152600360205260408120549081900361047b5750505050565b73ffffffffffffffffffffffffffffffffffffffff84166000818152600360205260408120556104ac9084836107d8565b6040805173ffffffffffffffffffffffffffffffffffffffff8087168252851660208201529081018290527f244e51bc38c1452fa8aaf487bcb4bca36c2baa3a5fbdb776b1eabd8dc6d277cd9060600160405180910390a1505b505050565b600082815260208190526040902060010154610526816107cb565b610530838361092f565b50505050565b73ffffffffffffffffffffffffffffffffffffffff81163314610585576040517f6697b23200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6105068282610964565b60008281526001602052604081206105a79083610991565b9392505050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f556105d8816107cb565b612710821115610649576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f6e657746656552617465203e206d61780000000000000000000000000000000060448201526064015b60405180910390fd5b600280549083905560408051828152602081018590527f14914da2bf76024616fbe1859783fcd4dbddcb179b1f3a854949fbf920dcb95791015b60405180910390a1505050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f556106ba816107cb565b600480549083905560408051828152602081018590527f5cf09b12f3f56b4c564d51b25b40360af6d795198adb61ae0806a36c294323fa9101610683565b60008181526001602052604081206104179061099d565b60008281526020819052604090206001015461072a816107cb565b6105308383610964565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f7965db0b00000000000000000000000000000000000000000000000000000000148061041757507f01ffc9a7000000000000000000000000000000000000000000000000000000007fffffffff00000000000000000000000000000000000000000000000000000000831614610417565b6107d581336109a7565b50565b3073ffffffffffffffffffffffffffffffffffffffff8316036107fa57505050565b8060000361080757505050565b7fffffffffffffffffffffffff111111111111111111111111111111111111111273ffffffffffffffffffffffffffffffffffffffff84160161090e5760008273ffffffffffffffffffffffffffffffffffffffff168260405160006040518083038185875af1925050503d806000811461089e576040519150601f19603f3d011682016040523d82523d6000602084013e6108a3565b606091505b5050905080610530576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f455448207472616e73666572206661696c6564000000000000000000000000006044820152606401610640565b61050673ffffffffffffffffffffffffffffffffffffffff84168383610a31565b60008061093c8484610abe565b905080156105a757600084815260016020526040902061095c9084610bba565b509392505050565b6000806109718484610bdc565b905080156105a757600084815260016020526040902061095c9084610c97565b60006105a78383610cb9565b6000610417825490565b60008281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915290205460ff16610a2d576040517fe2517d3f00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8216600482015260248101839052604401610640565b5050565b6040805173ffffffffffffffffffffffffffffffffffffffff8416602482015260448082018490528251808303909101815260649091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fa9059cbb00000000000000000000000000000000000000000000000000000000179052610506908490610ce3565b60008281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915281205460ff16610bb25760008381526020818152604080832073ffffffffffffffffffffffffffffffffffffffff86168452909152902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055610b503390565b73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16847f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a4506001610417565b506000610417565b60006105a78373ffffffffffffffffffffffffffffffffffffffff8416610d79565b60008281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915281205460ff1615610bb25760008381526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8616808552925280832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016905551339286917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a4506001610417565b60006105a78373ffffffffffffffffffffffffffffffffffffffff8416610dc0565b6000826000018281548110610cd057610cd061112a565b9060005260206000200154905092915050565b6000610d0573ffffffffffffffffffffffffffffffffffffffff841683610eb3565b90508051600014158015610d2a575080806020019051810190610d289190611159565b155b15610506576040517f5274afe700000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff84166004820152602401610640565b6000818152600183016020526040812054610bb257508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155610417565b60008181526001830160205260408120548015610ea9576000610de460018361117b565b8554909150600090610df89060019061117b565b9050808214610e5d576000866000018281548110610e1857610e1861112a565b9060005260206000200154905080876000018481548110610e3b57610e3b61112a565b6000918252602080832090910192909255918252600188019052604090208390555b8554869080610e6e57610e6e6111b5565b600190038181906000526020600020016000905590558560010160008681526020019081526020016000206000905560019350505050610417565b6000915050610417565b60606105a783836000846000808573ffffffffffffffffffffffffffffffffffffffff168486604051610ee691906111e4565b60006040518083038185875af1925050503d8060008114610f23576040519150601f19603f3d011682016040523d82523d6000602084013e610f28565b606091505b5091509150610f38868383610f42565b9695505050505050565b606082610f5757610f5282610fd1565b6105a7565b8151158015610f7b575073ffffffffffffffffffffffffffffffffffffffff84163b155b15610fca576040517f9996b31500000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff85166004820152602401610640565b50806105a7565b805115610fe15780518082602001fd5b6040517f1425ea4200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006020828403121561102557600080fd5b81357fffffffff00000000000000000000000000000000000000000000000000000000811681146105a757600080fd5b803573ffffffffffffffffffffffffffffffffffffffff8116811461107957600080fd5b919050565b6000806040838503121561109157600080fd5b61109a83611055565b91506110a860208401611055565b90509250929050565b6000602082840312156110c357600080fd5b5035919050565b600080604083850312156110dd57600080fd5b823591506110a860208401611055565b6000806040838503121561110057600080fd5b50508035926020909101359150565b60006020828403121561112157600080fd5b6105a782611055565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60006020828403121561116b57600080fd5b815180151581146105a757600080fd5b81810381811115610417577f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fd5b6000825160005b8181101561120557602081860181015185830152016111eb565b50600092019182525091905056fea2646970667358221220e128d8a06a9c2200c4304cd29f76ba6d8295d2c98b16f4a06921d33d0cebefd764736f6c63430008180033","runtime-code":"0x608060405234801561001057600080fd5b50600436106101775760003560e01c806391d14854116100d8578063bf333f2c1161008c578063d547741f11610066578063d547741f14610385578063dcf844a714610398578063e00a83e0146103b857600080fd5b8063bf333f2c14610341578063ca15c8731461034b578063ccc574901461035e57600080fd5b8063a217fddf116100bd578063a217fddf14610313578063b13aa2d61461031b578063b250fe6b1461032e57600080fd5b806391d14854146102a8578063926d7d7f146102ec57600080fd5b80632f2ff15d1161012f57806358f858801161011457806358f85880146102405780635960ccf2146102495780639010d07c1461027057600080fd5b80632f2ff15d1461021a57806336568abe1461022d57600080fd5b806306f333f21161016057806306f333f2146101d95780630f5f6ed7146101ee578063248a9ca3146101f757600080fd5b806301ffc9a71461017c57806303ed0ee5146101a4575b600080fd5b61018f61018a366004611013565b6103c1565b60405190151581526020015b60405180910390f35b6101cb7f043c983c49d46f0e102151eaf8085d4a2e6571d5df2d47b013f39bddfd4a639d81565b60405190815260200161019b565b6101ec6101e736600461107e565b61041d565b005b6101cb61271081565b6101cb6102053660046110b1565b60009081526020819052604090206001015490565b6101ec6102283660046110ca565b61050b565b6101ec61023b3660046110ca565b610536565b6101cb60025481565b6101cb7fdb9556138406326f00296e13ea2ad7db24ba82381212d816b1a40c23b466b32781565b61028361027e3660046110ed565b61058f565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200161019b565b61018f6102b63660046110ca565b60009182526020828152604080842073ffffffffffffffffffffffffffffffffffffffff93909316845291905290205460ff1690565b6101cb7fe2b7fb3b832174769106daebcfd6d1970523240dda11281102db9363b83b0dc481565b6101cb600081565b6101ec6103293660046110b1565b6105ae565b6101ec61033c3660046110b1565b610690565b6101cb620f424081565b6101cb6103593660046110b1565b6106f8565b6101cb7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f5581565b6101ec6103933660046110ca565b61070f565b6101cb6103a636600461110f565b60036020526000908152604090205481565b6101cb60045481565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f5a05180f000000000000000000000000000000000000000000000000000000001480610417575061041782610734565b92915050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f55610447816107cb565b73ffffffffffffffffffffffffffffffffffffffff83166000908152600360205260408120549081900361047b5750505050565b73ffffffffffffffffffffffffffffffffffffffff84166000818152600360205260408120556104ac9084836107d8565b6040805173ffffffffffffffffffffffffffffffffffffffff8087168252851660208201529081018290527f244e51bc38c1452fa8aaf487bcb4bca36c2baa3a5fbdb776b1eabd8dc6d277cd9060600160405180910390a1505b505050565b600082815260208190526040902060010154610526816107cb565b610530838361092f565b50505050565b73ffffffffffffffffffffffffffffffffffffffff81163314610585576040517f6697b23200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6105068282610964565b60008281526001602052604081206105a79083610991565b9392505050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f556105d8816107cb565b612710821115610649576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f6e657746656552617465203e206d61780000000000000000000000000000000060448201526064015b60405180910390fd5b600280549083905560408051828152602081018590527f14914da2bf76024616fbe1859783fcd4dbddcb179b1f3a854949fbf920dcb95791015b60405180910390a1505050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f556106ba816107cb565b600480549083905560408051828152602081018590527f5cf09b12f3f56b4c564d51b25b40360af6d795198adb61ae0806a36c294323fa9101610683565b60008181526001602052604081206104179061099d565b60008281526020819052604090206001015461072a816107cb565b6105308383610964565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f7965db0b00000000000000000000000000000000000000000000000000000000148061041757507f01ffc9a7000000000000000000000000000000000000000000000000000000007fffffffff00000000000000000000000000000000000000000000000000000000831614610417565b6107d581336109a7565b50565b3073ffffffffffffffffffffffffffffffffffffffff8316036107fa57505050565b8060000361080757505050565b7fffffffffffffffffffffffff111111111111111111111111111111111111111273ffffffffffffffffffffffffffffffffffffffff84160161090e5760008273ffffffffffffffffffffffffffffffffffffffff168260405160006040518083038185875af1925050503d806000811461089e576040519150601f19603f3d011682016040523d82523d6000602084013e6108a3565b606091505b5050905080610530576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f455448207472616e73666572206661696c6564000000000000000000000000006044820152606401610640565b61050673ffffffffffffffffffffffffffffffffffffffff84168383610a31565b60008061093c8484610abe565b905080156105a757600084815260016020526040902061095c9084610bba565b509392505050565b6000806109718484610bdc565b905080156105a757600084815260016020526040902061095c9084610c97565b60006105a78383610cb9565b6000610417825490565b60008281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915290205460ff16610a2d576040517fe2517d3f00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8216600482015260248101839052604401610640565b5050565b6040805173ffffffffffffffffffffffffffffffffffffffff8416602482015260448082018490528251808303909101815260649091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fa9059cbb00000000000000000000000000000000000000000000000000000000179052610506908490610ce3565b60008281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915281205460ff16610bb25760008381526020818152604080832073ffffffffffffffffffffffffffffffffffffffff86168452909152902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055610b503390565b73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16847f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a4506001610417565b506000610417565b60006105a78373ffffffffffffffffffffffffffffffffffffffff8416610d79565b60008281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915281205460ff1615610bb25760008381526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8616808552925280832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016905551339286917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a4506001610417565b60006105a78373ffffffffffffffffffffffffffffffffffffffff8416610dc0565b6000826000018281548110610cd057610cd061112a565b9060005260206000200154905092915050565b6000610d0573ffffffffffffffffffffffffffffffffffffffff841683610eb3565b90508051600014158015610d2a575080806020019051810190610d289190611159565b155b15610506576040517f5274afe700000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff84166004820152602401610640565b6000818152600183016020526040812054610bb257508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155610417565b60008181526001830160205260408120548015610ea9576000610de460018361117b565b8554909150600090610df89060019061117b565b9050808214610e5d576000866000018281548110610e1857610e1861112a565b9060005260206000200154905080876000018481548110610e3b57610e3b61112a565b6000918252602080832090910192909255918252600188019052604090208390555b8554869080610e6e57610e6e6111b5565b600190038181906000526020600020016000905590558560010160008681526020019081526020016000206000905560019350505050610417565b6000915050610417565b60606105a783836000846000808573ffffffffffffffffffffffffffffffffffffffff168486604051610ee691906111e4565b60006040518083038185875af1925050503d8060008114610f23576040519150601f19603f3d011682016040523d82523d6000602084013e610f28565b606091505b5091509150610f38868383610f42565b9695505050505050565b606082610f5757610f5282610fd1565b6105a7565b8151158015610f7b575073ffffffffffffffffffffffffffffffffffffffff84163b155b15610fca576040517f9996b31500000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff85166004820152602401610640565b50806105a7565b805115610fe15780518082602001fd5b6040517f1425ea4200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006020828403121561102557600080fd5b81357fffffffff00000000000000000000000000000000000000000000000000000000811681146105a757600080fd5b803573ffffffffffffffffffffffffffffffffffffffff8116811461107957600080fd5b919050565b6000806040838503121561109157600080fd5b61109a83611055565b91506110a860208401611055565b90509250929050565b6000602082840312156110c357600080fd5b5035919050565b600080604083850312156110dd57600080fd5b823591506110a860208401611055565b6000806040838503121561110057600080fd5b50508035926020909101359150565b60006020828403121561112157600080fd5b6105a782611055565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60006020828403121561116b57600080fd5b815180151581146105a757600080fd5b81810381811115610417577f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fd5b6000825160005b8181101561120557602081860181015185830152016111eb565b50600092019182525091905056fea2646970667358221220e128d8a06a9c2200c4304cd29f76ba6d8295d2c98b16f4a06921d33d0cebefd764736f6c63430008180033","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.24 ^0.8.0 ^0.8.20;\n\n// contracts/interfaces/IAdmin.sol\n\ninterface IAdmin {\n // ============ Events ============\n\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n event ChainGasAmountUpdated(uint256 oldChainGasAmount, uint256 newChainGasAmount);\n\n // ============ Methods ============\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n\n function setChainGasAmount(uint256 newChainGasAmount) external;\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IFastBridgeRecipient.sol\n\ninterface IFastBridgeRecipient {\n function fastBridgeTransferReceived(\n address token,\n uint256 amount,\n bytes memory callParams\n )\n external\n payable\n returns (bytes4);\n}\n\n// contracts/interfaces/IFastBridgeV2Errors.sol\n\ninterface IFastBridgeV2Errors {\n error AmountIncorrect();\n error CallParamsLengthAboveMax();\n error ChainIncorrect();\n error ExclusivityParamsIncorrect();\n error MsgValueIncorrect();\n error NativeTokenCallValueNotSupported();\n error SenderIncorrect();\n error StatusIncorrect();\n error ZeroAddress();\n\n error RecipientIncorrectReturnValue();\n error RecipientNoReturnValue();\n\n error DeadlineExceeded();\n error DeadlineNotExceeded();\n error DeadlineTooShort();\n error DisputePeriodNotPassed();\n error DisputePeriodPassed();\n error ExclusivityPeriodNotPassed();\n\n error TransactionRelayed();\n}\n\n// contracts/libs/Errors.sol\n\nerror DeadlineExceeded();\nerror DeadlineNotExceeded();\nerror DeadlineTooShort();\nerror InsufficientOutputAmount();\n\nerror MsgValueIncorrect();\nerror PoolNotFound();\nerror TokenAddressMismatch();\nerror TokenNotContract();\nerror TokenNotETH();\nerror TokensIdentical();\n\nerror ChainIncorrect();\nerror AmountIncorrect();\nerror ZeroAddress();\n\nerror DisputePeriodNotPassed();\nerror DisputePeriodPassed();\nerror SenderIncorrect();\nerror StatusIncorrect();\nerror TransactionIdIncorrect();\nerror TransactionRelayed();\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// contracts/interfaces/IFastBridgeV2.sol\n\ninterface IFastBridgeV2 is IFastBridge {\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n struct BridgeTxDetails {\n BridgeStatus status;\n uint40 proofBlockTimestamp;\n uint48 proofBlockNumber;\n address proofRelayer;\n }\n\n struct BridgeRelay {\n uint48 blockNumber;\n uint48 blockTimestamp;\n address relayer;\n }\n\n /// @notice New params introduced in the FastBridgeV2.\n /// We are passing fields from the older BridgeParams struct outside of this struct\n /// for backwards compatibility.\n /// Note: quoteRelayer and quoteExclusivitySeconds are either both zero (indicating no exclusivity)\n /// or both non-zero (indicating exclusivity for the given period).\n /// Note: callValue \u003e 0 can NOT be used with destToken = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE (ETH_ADDRESS)\n /// @param quoteRelayer Relayer that provided the quote for the transaction\n /// @param quoteExclusivitySeconds Period of time the quote relayer is guaranteed exclusivity after user's deposit\n /// @param quoteId Unique quote identifier used for tracking the quote\n /// @param callValue ETH value to send to the recipient (if any)\n /// @param callParams Parameters for the arbitrary call to the destination recipient (if any)\n struct BridgeParamsV2 {\n address quoteRelayer;\n int256 quoteExclusivitySeconds;\n bytes quoteId;\n uint256 callValue;\n bytes callParams;\n }\n\n /// @notice Updated bridge transaction struct to include parameters introduced in FastBridgeV2.\n /// Note: only `exclusivityRelayer` can fill such a transaction until `exclusivityEndTime`.\n /// TODO: consider changing the encoding scheme to prevent spending extra gas on decoding.\n struct BridgeTransactionV2 {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n uint256 callValue; // ETH value to send to the recipient (if any) - replaces V1's sendChainGas flag\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n address exclusivityRelayer;\n uint256 exclusivityEndTime;\n bytes callParams;\n }\n\n event BridgeQuoteDetails(bytes32 indexed transactionId, bytes quoteId);\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability\n /// to provide temporary exclusivity fill rights for the quote relayer.\n /// @param params The parameters required to bridge\n /// @param paramsV2 The parameters for exclusivity fill rights (optional, can be left empty)\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function relay(bytes memory request, address relayer) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param transactionId The transaction id associated with the encoded bridge transaction to prove\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital.\n /// @notice Can only send funds to the relayer address on the proof.\n /// @param request The encoded bridge transaction to claim on origin chain\n function claim(bytes memory request) external;\n /// @notice Checks if a transaction has been relayed\n /// @param transactionId The ID of the transaction to check\n /// @return True if the transaction has been relayed, false otherwise\n function bridgeRelays(bytes32 transactionId) external view returns (bool);\n\n /// @notice Returns the status of a bridge transaction\n /// @param transactionId The ID of the bridge transaction\n /// @return BridgeStatus Status of the bridge transaction\n function bridgeStatuses(bytes32 transactionId) external view returns (BridgeStatus);\n\n /// @notice Returns the timestamp and relayer of a bridge proof\n /// @param transactionId The ID of the bridge transaction\n /// @return timestamp The timestamp of the bridge proof\n /// @return relayer The relayer address of the bridge proof\n function bridgeProofs(bytes32 transactionId) external view returns (uint96 timestamp, address relayer);\n\n /// @notice Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\n /// @param request The bridge request to decode\n function getBridgeTransactionV2(bytes memory request) external view returns (BridgeTransactionV2 memory);\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// contracts/libs/UniversalToken.sol\n\nlibrary UniversalTokenLib {\n using SafeERC20 for IERC20;\n\n address internal constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Transfers tokens to the given account. Reverts if transfer is not successful.\n /// @dev This might trigger fallback, if ETH is transferred to the contract.\n /// Make sure this can not lead to reentrancy attacks.\n function universalTransfer(address token, address to, uint256 value) internal {\n // Don't do anything, if need to send tokens to this address\n if (to == address(this)) return;\n // Don't do anything, if trying to send zero value\n if (value == 0) return;\n if (token == ETH_ADDRESS) {\n /// @dev Note: this can potentially lead to executing code in `to`.\n // solhint-disable-next-line avoid-low-level-calls\n (bool success,) = to.call{value: value}(\"\");\n require(success, \"ETH transfer failed\");\n } else {\n IERC20(token).safeTransfer(to, value);\n }\n }\n\n /// @notice Issues an infinite allowance to the spender, if the current allowance is insufficient\n /// to spend the given amount.\n function universalApproveInfinity(address token, address spender, uint256 amountToSpend) internal {\n // ETH Chad doesn't require your approval\n if (token == ETH_ADDRESS) return;\n // No-op if allowance is already sufficient\n uint256 allowance = IERC20(token).allowance(address(this), spender);\n if (allowance \u003e= amountToSpend) return;\n // Otherwise, reset approval to 0 and set to max allowance\n if (allowance \u003e 0) IERC20(token).safeDecreaseAllowance(spender, allowance);\n IERC20(token).safeIncreaseAllowance(spender, type(uint256).max);\n }\n\n /// @notice Returns the balance of the given token (or native ETH) for the given account.\n function universalBalanceOf(address token, address account) internal view returns (uint256) {\n if (token == ETH_ADDRESS) {\n return account.balance;\n } else {\n return IERC20(token).balanceOf(account);\n }\n }\n\n /// @dev Checks that token is a contract and not ETH_ADDRESS.\n function assertIsContract(address token) internal view {\n // Check that ETH_ADDRESS was not used (in case this is a predeploy on any of the chains)\n if (token == UniversalTokenLib.ETH_ADDRESS) revert TokenNotContract();\n // Check that token is not an EOA\n if (token.code.length == 0) revert TokenNotContract();\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/Admin.sol\n\ncontract Admin is IAdmin, AccessControlEnumerable {\n using UniversalTokenLib for address;\n\n bytes32 public constant RELAYER_ROLE = keccak256(\"RELAYER_ROLE\");\n bytes32 public constant REFUNDER_ROLE = keccak256(\"REFUNDER_ROLE\");\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n uint256 public constant FEE_BPS = 1e6;\n uint256 public constant FEE_RATE_MAX = 0.01e6; // max 1% on origin amount\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Chain gas amount to forward as rebate if requested\n uint256 public chainGasAmount;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n }\n\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n require(newFeeRate \u003c= FEE_RATE_MAX, \"newFeeRate \u003e max\");\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n token.universalTransfer(recipient, feeAmount);\n emit FeesSwept(token, recipient, feeAmount);\n }\n\n function setChainGasAmount(uint256 newChainGasAmount) external onlyRole(GOVERNOR_ROLE) {\n uint256 oldChainGasAmount = chainGasAmount;\n chainGasAmount = newChainGasAmount;\n emit ChainGasAmountUpdated(oldChainGasAmount, newChainGasAmount);\n }\n}\n\n// contracts/FastBridgeV2.sol\n\n/// @notice FastBridgeV2 is a contract for bridging tokens across chains.\ncontract FastBridgeV2 is Admin, IFastBridgeV2, IFastBridgeV2Errors {\n using SafeERC20 for IERC20;\n using UniversalTokenLib for address;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Delay for a transaction after which it could be permisionlessly refunded\n uint256 public constant REFUND_DELAY = 7 days;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n /// @notice Maximum length of accepted callParams\n uint256 public constant MAX_CALL_PARAMS_LENGTH = 2 ** 16 - 1;\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeTxDetails) public bridgeTxDetails;\n /// @notice Relay details on destination chain\n mapping(bytes32 =\u003e BridgeRelay) public bridgeRelayDetails;\n /// @notice Unique bridge nonces tracked per originSender\n mapping(address =\u003e uint256) public senderNonces;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Replaced by senderNonces\n uint256 public immutable nonce = 0;\n /// @notice the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n bridge({\n params: params,\n paramsV2: BridgeParamsV2({\n quoteRelayer: address(0),\n quoteExclusivitySeconds: 0,\n quoteId: bytes(\"\"),\n callValue: 0,\n callParams: bytes(\"\")\n })\n });\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes memory request) external payable {\n relay({request: request, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes memory request, bytes32 destTxHash) external {\n prove({transactionId: keccak256(request), destTxHash: destTxHash, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridgeV2\n function claim(bytes memory request) external {\n claim({request: request, to: address(0)});\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003e DISPUTE_PERIOD) {\n revert DisputePeriodPassed();\n }\n\n // @dev relayer gets slashed effectively if dest relay has gone thru\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n bridgeTxDetails[transactionId].proofRelayer = address(0);\n bridgeTxDetails[transactionId].proofBlockTimestamp = 0;\n bridgeTxDetails[transactionId].proofBlockNumber = 0;\n\n emit BridgeProofDisputed(transactionId, msg.sender);\n }\n\n /// @inheritdoc IFastBridge\n function refund(bytes memory request) external {\n bytes32 transactionId = keccak256(request);\n\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n\n if (bridgeTxDetails[transactionId].status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n\n if (hasRole(REFUNDER_ROLE, msg.sender)) {\n // Refunder can refund if deadline has passed\n if (block.timestamp \u003c= transaction.deadline) revert DeadlineNotExceeded();\n } else {\n // Permissionless refund is allowed after REFUND_DELAY\n if (block.timestamp \u003c= transaction.deadline + REFUND_DELAY) revert DeadlineNotExceeded();\n }\n\n // if all checks passed, set to REFUNDED status\n bridgeTxDetails[transactionId].status = BridgeStatus.REFUNDED;\n\n // transfer origin collateral back to original sender\n address to = transaction.originSender;\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount + transaction.originFeeAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (bridgeTxDetails[transactionId].proofRelayer != relayer) revert SenderIncorrect();\n return _timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n /// @dev This method is added to achieve backwards compatibility with decoding requests into V1 structs:\n /// - `callValue` is partially reported as a zero/non-zero flag\n /// - `callParams` is ignored\n /// In order to process all kinds of requests use getBridgeTransactionV2 instead.\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory) {\n // Try decoding into V2 struct first. This will revert if V1 struct is passed\n try this.getBridgeTransactionV2(request) returns (BridgeTransactionV2 memory txV2) {\n // Note: we entirely ignore the callParams field, as it was not present in V1\n return BridgeTransaction({\n originChainId: txV2.originChainId,\n destChainId: txV2.destChainId,\n originSender: txV2.originSender,\n destRecipient: txV2.destRecipient,\n originToken: txV2.originToken,\n destToken: txV2.destToken,\n originAmount: txV2.originAmount,\n destAmount: txV2.destAmount,\n originFeeAmount: txV2.originFeeAmount,\n sendChainGas: txV2.callValue != 0,\n deadline: txV2.deadline,\n nonce: txV2.nonce\n });\n } catch {\n // Fallback to V1 struct\n return abi.decode(request, (BridgeTransaction));\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) public payable {\n int256 exclusivityEndTime = int256(block.timestamp) + paramsV2.quoteExclusivitySeconds;\n _validateBridgeParams(params, paramsV2, exclusivityEndTime);\n\n // transfer tokens to bridge contract\n /// @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _pullToken(params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n\n // set status to requested\n bytes memory request = abi.encode(\n BridgeTransactionV2({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n callValue: paramsV2.callValue,\n deadline: params.deadline,\n nonce: senderNonces[params.sender]++, // increment nonce on every bridge\n exclusivityRelayer: paramsV2.quoteRelayer,\n // We checked exclusivityEndTime to be in range (0 .. params.deadline] above, so can safely cast\n exclusivityEndTime: uint256(exclusivityEndTime),\n callParams: paramsV2.callParams\n })\n );\n bytes32 transactionId = keccak256(request);\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n\n emit BridgeRequested({\n transactionId: transactionId,\n sender: params.sender,\n request: request,\n destChainId: params.dstChainId,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n sendChainGas: paramsV2.callValue != 0\n });\n emit BridgeQuoteDetails(transactionId, paramsV2.quoteId);\n }\n\n /// @inheritdoc IFastBridgeV2\n function relay(bytes memory request, address relayer) public payable {\n bytes32 transactionId = keccak256(request);\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n _validateRelayParams(transaction, transactionId, relayer);\n // mark bridge transaction as relayed\n bridgeRelayDetails[transactionId] =\n BridgeRelay({blockNumber: uint48(block.number), blockTimestamp: uint48(block.timestamp), relayer: relayer});\n\n // transfer tokens to recipient on destination chain and do an arbitrary call if requested\n address to = transaction.destRecipient;\n address token = transaction.destToken;\n uint256 amount = transaction.destAmount;\n\n // All state changes have been done at this point, can proceed to the external calls.\n // This follows the checks-effects-interactions pattern to mitigate potential reentrancy attacks.\n if (token == UniversalTokenLib.ETH_ADDRESS) {\n // For ETH non-zero callValue is not allowed\n if (transaction.callValue != 0) revert NativeTokenCallValueNotSupported();\n // Check that the correct msg.value was sent\n if (msg.value != amount) revert MsgValueIncorrect();\n } else {\n // For ERC20s, we check that the correct msg.value was sent\n if (msg.value != transaction.callValue) revert MsgValueIncorrect();\n // We need to transfer the tokens from the Relayer to the recipient first before performing an\n // optional post-transfer arbitrary call.\n IERC20(token).safeTransferFrom(msg.sender, to, amount);\n }\n\n if (transaction.callParams.length != 0) {\n // Arbitrary call requested, perform it while supplying full msg.value to the recipient\n // Note: if token has a fee on transfers, the recipient will have received less than `amount`.\n // This is a very niche edge case and should be handled by the recipient contract.\n _checkedCallRecipient({recipient: to, token: token, amount: amount, callParams: transaction.callParams});\n } else if (msg.value != 0) {\n // No arbitrary call requested, but msg.value was sent. This is either a relay with ETH,\n // or a non-zero callValue request with an ERC20. In both cases, transfer the ETH to the recipient.\n Address.sendValue(payable(to), msg.value);\n }\n\n emit BridgeRelayed({\n transactionId: transactionId,\n relayer: relayer,\n to: to,\n originChainId: transaction.originChainId,\n originToken: transaction.originToken,\n destToken: transaction.destToken,\n originAmount: transaction.originAmount,\n destAmount: transaction.destAmount,\n chainGasAmount: transaction.callValue\n });\n }\n\n /// @inheritdoc IFastBridgeV2\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) public onlyRole(RELAYER_ROLE) {\n // update bridge tx status given proof provided\n if (bridgeTxDetails[transactionId].status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n bridgeTxDetails[transactionId].status = BridgeStatus.RELAYER_PROVED;\n bridgeTxDetails[transactionId].proofBlockTimestamp = uint40(block.timestamp);\n bridgeTxDetails[transactionId].proofBlockNumber = uint48(block.number);\n bridgeTxDetails[transactionId].proofRelayer = relayer;\n\n emit BridgeProofProvided(transactionId, relayer, destTxHash);\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes memory request, address to) public {\n bytes32 transactionId = keccak256(request);\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n\n // update bridge tx status if able to claim origin collateral\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n\n // if \"to\" is zero addr, permissionlessly send funds to proven relayer\n if (to == address(0)) {\n to = bridgeTxDetails[transactionId].proofRelayer;\n } else if (bridgeTxDetails[transactionId].proofRelayer != msg.sender) {\n revert SenderIncorrect();\n }\n\n if (_timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003c= DISPUTE_PERIOD) {\n revert DisputePeriodNotPassed();\n }\n\n bridgeTxDetails[transactionId].status = BridgeStatus.RELAYER_CLAIMED;\n\n // update protocol fees if origin fee amount exists\n if (transaction.originFeeAmount \u003e 0) protocolFees[transaction.originToken] += transaction.originFeeAmount;\n\n // transfer origin collateral less fee to specified address\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositClaimed(transactionId, bridgeTxDetails[transactionId].proofRelayer, to, token, amount);\n }\n\n function bridgeStatuses(bytes32 transactionId) public view returns (BridgeStatus status) {\n return bridgeTxDetails[transactionId].status;\n }\n\n function bridgeProofs(bytes32 transactionId) public view returns (uint96 timestamp, address relayer) {\n timestamp = bridgeTxDetails[transactionId].proofBlockTimestamp;\n relayer = bridgeTxDetails[transactionId].proofRelayer;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeRelays(bytes32 transactionId) public view returns (bool) {\n // has this transactionId been relayed?\n return bridgeRelayDetails[transactionId].relayer != address(0);\n }\n\n /// @inheritdoc IFastBridgeV2\n function getBridgeTransactionV2(bytes memory request) public pure returns (BridgeTransactionV2 memory) {\n return abi.decode(request, (BridgeTransactionV2));\n }\n\n /// @notice Pulls a requested token from the user to this contract.\n function _pullToken(address token, uint256 amount) internal returns (uint256 amountPulled) {\n if (token == UniversalTokenLib.ETH_ADDRESS) {\n // For ETH we just need to check that the supplied msg.value is correct\n if (amount != msg.value) revert MsgValueIncorrect();\n amountPulled = msg.value;\n } else {\n token.assertIsContract();\n // Record token balance before transfer\n amountPulled = IERC20(token).balanceOf(address(this));\n // Token needs to be pulled only if msg.value is zero\n // This way user can specify WETH as the origin asset\n IERC20(token).safeTransferFrom(msg.sender, address(this), amount);\n // Use the difference between the recorded balance and the current balance as the amountPulled\n amountPulled = IERC20(token).balanceOf(address(this)) - amountPulled;\n }\n }\n\n /// @notice Calls the Recipient's hook function with the specified callParams and performs\n /// all the necessary checks for the returned value.\n function _checkedCallRecipient(\n address recipient,\n address token,\n uint256 amount,\n bytes memory callParams\n )\n internal\n {\n bytes memory hookData =\n abi.encodeCall(IFastBridgeRecipient.fastBridgeTransferReceived, (token, amount, callParams));\n // This will bubble any revert messages from the hook function\n bytes memory returnData = Address.functionCallWithValue({target: recipient, data: hookData, value: msg.value});\n // Explicit revert if no return data at all\n if (returnData.length == 0) revert RecipientNoReturnValue();\n // Check that exactly a single return value was returned\n if (returnData.length != 32) revert RecipientIncorrectReturnValue();\n // Return value should be abi-encoded hook function selector\n if (bytes32(returnData) != bytes32(IFastBridgeRecipient.fastBridgeTransferReceived.selector)) {\n revert RecipientIncorrectReturnValue();\n }\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint40(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint40).max but\n /// proof.timestamp \u003c type(uint40).max via unchecked statement\n /// @param proofBlockTimestamp The bridge proof block timestamp\n /// @return delta Time delta since proof submitted\n function _timeSince(uint40 proofBlockTimestamp) internal view returns (uint256 delta) {\n unchecked {\n delta = uint40(block.timestamp) - proofBlockTimestamp;\n }\n }\n\n /// @notice Performs all the necessary checks for a bridge to happen.\n /// @dev There's no good way to refactor this function to reduce cyclomatic complexity due to\n /// the number of checks that need to be performed, so we skip the code-complexity rule here.\n // solhint-disable-next-line code-complexity\n function _validateBridgeParams(\n BridgeParams memory params,\n BridgeParamsV2 memory paramsV2,\n int256 exclusivityEndTime\n )\n internal\n view\n {\n // Check V1 (legacy) params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.sender == address(0) || params.to == address(0)) revert ZeroAddress();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n // Check V2 params\n if (paramsV2.callParams.length \u003e MAX_CALL_PARAMS_LENGTH) revert CallParamsLengthAboveMax();\n if (paramsV2.callValue != 0 \u0026\u0026 params.destToken == UniversalTokenLib.ETH_ADDRESS) {\n revert NativeTokenCallValueNotSupported();\n }\n // exclusivityEndTime must be in range (0 .. params.deadline]\n if (exclusivityEndTime \u003c= 0 || exclusivityEndTime \u003e int256(params.deadline)) {\n revert ExclusivityParamsIncorrect();\n }\n }\n\n /// @notice Performs all the necessary checks for a relay to happen.\n function _validateRelayParams(\n BridgeTransactionV2 memory transaction,\n bytes32 transactionId,\n address relayer\n )\n internal\n view\n {\n if (relayer == address(0)) revert ZeroAddress();\n // Check if the transaction has already been relayed\n if (bridgeRelays(transactionId)) revert TransactionRelayed();\n if (transaction.destChainId != uint32(block.chainid)) revert ChainIncorrect();\n // Check the deadline for relay to happen\n if (block.timestamp \u003e transaction.deadline) revert DeadlineExceeded();\n // Check the exclusivity period, if it is still ongoing\n // forgefmt: disable-next-item\n if (\n transaction.exclusivityRelayer != address(0) \u0026\u0026\n transaction.exclusivityRelayer != relayer \u0026\u0026\n block.timestamp \u003c= transaction.exclusivityEndTime\n ) {\n revert ExclusivityPeriodNotPassed();\n }\n }\n}\n","language":"Solidity","languageVersion":"0.8.24","compilerVersion":"0.8.24","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"62810:1843:0:-:0;;;63637:83;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;63675:38;52847:4;63706:6;63675:10;:38::i;:::-;;63637:83;62810:1843;;62160:257;62246:4;;62277:31;62294:4;62300:7;62277:16;:31::i;:::-;62262:46;;62322:7;62318:69;;;62345:18;;;;:12;:18;;;;;:31;;62368:7;62345:22;:31::i;:::-;;62318:69;62403:7;-1:-1:-1;62160:257:0;;;;;:::o;56794:316::-;56871:4;53569:12;;;;;;;;;;;-1:-1:-1;;;;;53569:29:0;;;;;;;;;;;;56887:217;;56930:6;:12;;;;;;;;;;;-1:-1:-1;;;;;56930:29:0;;;;;;;;;:36;;-1:-1:-1;;56930:36:0;56962:4;56930:36;;;57012:12;23368:10;;23289:96;57012:12;-1:-1:-1;;;;;56985:40:0;57003:7;-1:-1:-1;;;;;56985:40:0;56997:4;56985:40;;;;;;;;;;-1:-1:-1;57046:4:0;57039:11;;56887:217;-1:-1:-1;57088:5:0;57081:12;;32813:150;32883:4;32906:50;32911:3;-1:-1:-1;;;;;32931:23:0;;26801:4;28857:21;;;:14;;;:21;;;;;;26817:321;;-1:-1:-1;26859:23:0;;;;;;;;:11;:23;;;;;;;;;;;;;27041:18;;27017:21;;;:14;;;:21;;;;;;:42;;;;27073:11;;14:290:1;84:6;137:2;125:9;116:7;112:23;108:32;105:52;;;153:1;150;143:12;105:52;179:16;;-1:-1:-1;;;;;224:31:1;;214:42;;204:70;;270:1;267;260:12;14:290;62810:1843:0;;;;;;","srcMapRuntime":"62810:1843:0:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;60820:212;;;;;;:::i;:::-;;:::i;:::-;;;516:14:1;;509:22;491:41;;479:2;464:18;60820:212:0;;;;;;;;63050:60;;63087:23;63050:60;;;;;689:25:1;;;677:2;662:18;63050:60:0;543:177:1;64022:359:0;;;;;;:::i;:::-;;:::i;:::-;;63232:45;;63271:6;63232:45;;54425:120;;;;;;:::i;:::-;54490:7;54516:12;;;;;;;;;;:22;;;;54425:120;54841:136;;;;;;:::i;:::-;;:::i;55943:245::-;;;;;;:::i;:::-;;:::i;63394:30::-;;;;;;62978:66;;63018:26;62978:66;;61617:142;;;;;;:::i;:::-;;:::i;:::-;;;2246:42:1;2234:55;;;2216:74;;2204:2;2189:18;61617:142:0;2070:226:1;53469:136:0;;;;;;:::i;:::-;53546:4;53569:12;;;;;;;;;;;:29;;;;;;;;;;;;;;;;53469:136;62908:64;;62947:25;62908:64;;52802:49;;52847:4;52802:49;;63726:290;;;;;;:::i;:::-;;:::i;64387:264::-;;;;;;:::i;:::-;;:::i;63189:37::-;;63223:3;63189:37;;61927:131;;;;;;:::i;:::-;;:::i;63116:66::-;;63156:26;63116:66;;55257:138;;;;;;:::i;:::-;;:::i;63480:47::-;;;;;;:::i;:::-;;;;;;;;;;;;;;63601:29;;;;;;60820:212;60905:4;60928:57;;;60943:42;60928:57;;:97;;;60989:36;61013:11;60989:23;:36::i;:::-;60921:104;60820:212;-1:-1:-1;;60820:212:0:o;64022:359::-;63156:26;53079:16;53090:4;53079:10;:16::i;:::-;64146:19:::1;::::0;::::1;64126:17;64146:19:::0;;;:12:::1;:19;::::0;;;;;;64179:14;;;64175:27:::1;;64195:7;64022:359:::0;;;:::o;64175:27::-:1;64243:19;::::0;::::1;64265:1;64243:19:::0;;;:12:::1;:19;::::0;;;;:23;64276:45:::1;::::0;64300:9;64311;64276:23:::1;:45::i;:::-;64336:38;::::0;;2889:42:1;2958:15;;;2940:34;;3010:15;;3005:2;2990:18;;2983:43;3042:18;;;3035:34;;;64336:38:0::1;::::0;2867:2:1;2852:18;64336:38:0::1;;;;;;;64116:265;53105:1;64022:359:::0;;;:::o;54841:136::-;54490:7;54516:12;;;;;;;;;;:22;;;53079:16;53090:4;53079:10;:16::i;:::-;54945:25:::1;54956:4;54962:7;54945:10;:25::i;:::-;;54841:136:::0;;;:::o;55943:245::-;56036:34;;;23368:10;56036:34;56032:102;;56093:30;;;;;;;;;;;;;;56032:102;56144:37;56156:4;56162:18;56144:11;:37::i;61617:142::-;61698:7;61724:18;;;:12;:18;;;;;:28;;61746:5;61724:21;:28::i;:::-;61717:35;61617:142;-1:-1:-1;;;61617:142:0:o;63726:290::-;63156:26;53079:16;53090:4;53079:10;:16::i;:::-;63271:6:::1;63825:10;:26;;63817:55;;;::::0;::::1;::::0;;3282:2:1;63817:55:0::1;::::0;::::1;3264:21:1::0;3321:2;3301:18;;;3294:30;3360:18;3340;;;3333:46;3396:18;;63817:55:0::1;;;;;;;;;63903:15;::::0;;63928:28;;;;63971:38:::1;::::0;;3599:25:1;;;3655:2;3640:18;;3633:34;;;63971:38:0::1;::::0;3572:18:1;63971:38:0::1;;;;;;;;63807:209;63726:290:::0;;:::o;64387:264::-;63156:26;53079:16;53090:4;53079:10;:16::i;:::-;64512:14:::1;::::0;;64536:34;;;;64585:59:::1;::::0;;3599:25:1;;;3655:2;3640:18;;3633:34;;;64585:59:0::1;::::0;3572:18:1;64585:59:0::1;3425:248:1::0;61927:131:0;61998:7;62024:18;;;:12;:18;;;;;:27;;:25;:27::i;55257:138::-;54490:7;54516:12;;;;;;;;;;:22;;;53079:16;53090:4;53079:10;:16::i;:::-;55362:26:::1;55374:4;55380:7;55362:11;:26::i;53180:202::-:0;53265:4;53288:47;;;53303:32;53288:47;;:87;;-1:-1:-1;45095:25:0;45080:40;;;;53339:36;44981:146;53814:103;53880:30;53891:4;23368:10;53880;:30::i;:::-;53814:103;:::o;58092:653::-;58267:4;58253:19;;;;58249:32;;58092:653;;;:::o;58249:32::-;58353:5;58362:1;58353:10;58349:23;;58092:653;;;:::o;58349:23::-;58385:20;;;;;58381:358;;58565:12;58582:2;:7;;58597:5;58582:25;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;58564:43;;;58629:7;58621:39;;;;;;;4090:2:1;58621:39:0;;;4072:21:1;4129:2;4109:18;;;4102:30;4168:21;4148:18;;;4141:49;4207:18;;58621:39:0;3888:343:1;58381:358:0;58691:37;:26;;;58718:2;58722:5;58691:26;:37::i;62160:257::-;62246:4;62262:12;62277:31;62294:4;62300:7;62277:16;:31::i;:::-;62262:46;;62322:7;62318:69;;;62345:18;;;;:12;:18;;;;;:31;;62368:7;62345:22;:31::i;:::-;;62403:7;62160:257;-1:-1:-1;;;62160:257:0:o;62520:262::-;62607:4;62623:12;62638:32;62656:4;62662:7;62638:17;:32::i;:::-;62623:47;;62684:7;62680:72;;;62707:18;;;;:12;:18;;;;;:34;;62733:7;62707:25;:34::i;34071:156::-;34145:7;34195:22;34199:3;34211:5;34195:3;:22::i;33614:115::-;33677:7;33703:19;33711:3;29053:18;;28971:107;54047:197;53546:4;53569:12;;;;;;;;;;;:29;;;;;;;;;;;;;54130:108;;54180:47;;;;;4440:42:1;4428:55;;54180:47:0;;;4410:74:1;4500:18;;;4493:34;;;4383:18;;54180:47:0;4236:297:1;54130:108:0;54047:197;;:::o;46297:160::-;46406:43;;;46421:14;4428:55:1;;46406:43:0;;;4410:74:1;4500:18;;;;4493:34;;;46406:43:0;;;;;;;;;;4383:18:1;;;;46406:43:0;;;;;;;;;;;;;;46379:71;;46399:5;;46379:19;:71::i;56794:316::-;56871:4;53569:12;;;;;;;;;;;:29;;;;;;;;;;;;;56887:217;;56930:6;:12;;;;;;;;;;;:29;;;;;;;;;;:36;;;;56962:4;56930:36;;;57012:12;23368:10;;23289:96;57012:12;56985:40;;57003:7;56985:40;;56997:4;56985:40;;;;;;;;;;-1:-1:-1;57046:4:0;57039:11;;56887:217;-1:-1:-1;57088:5:0;57081:12;;32813:150;32883:4;32906:50;32911:3;32931:23;;;32906:4;:50::i;57345:317::-;57423:4;53569:12;;;;;;;;;;;:29;;;;;;;;;;;;;57439:217;;;57513:5;57481:12;;;;;;;;;;;:29;;;;;;;;;;;:37;;;;;;57537:40;23368:10;;57481:12;;57537:40;;57513:5;57537:40;-1:-1:-1;57598:4:0;57591:11;;33131:156;33204:4;33227:53;33235:3;33255:23;;;33227:7;:53::i;29420:118::-;29487:7;29513:3;:11;;29525:5;29513:18;;;;;;;;:::i;:::-;;;;;;;;;29506:25;;29420:118;;;;:::o;49053:629::-;49472:23;49498:33;:27;;;49526:4;49498:27;:33::i;:::-;49472:59;;49545:10;:17;49566:1;49545:22;;:57;;;;;49583:10;49572:30;;;;;;;;;;;;:::i;:::-;49571:31;49545:57;49541:135;;;49625:40;;;;;2246:42:1;2234:55;;49625:40:0;;;2216:74:1;2189:18;;49625:40:0;2070:226:1;26738:406:0;26801:4;28857:21;;;:14;;;:21;;;;;;26817:321;;-1:-1:-1;26859:23:0;;;;;;;;:11;:23;;;;;;;;;;;;;27041:18;;27017:21;;;:14;;;:21;;;;;;:42;;;;27073:11;;27312:1368;27378:4;27507:21;;;:14;;;:21;;;;;;27543:13;;27539:1135;;27910:18;27931:12;27942:1;27931:8;:12;:::i;:::-;27977:18;;27910:33;;-1:-1:-1;27957:17:0;;27977:22;;27998:1;;27977:22;:::i;:::-;27957:42;;28032:9;28018:10;:23;28014:378;;28061:17;28081:3;:11;;28093:9;28081:22;;;;;;;;:::i;:::-;;;;;;;;;28061:42;;28228:9;28202:3;:11;;28214:10;28202:23;;;;;;;;:::i;:::-;;;;;;;;;;;;:35;;;;28341:25;;;:14;;;:25;;;;;:36;;;28014:378;28470:17;;:3;;:17;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;28573:3;:14;;:21;28588:5;28573:21;;;;;;;;;;;28566:28;;;28616:4;28609:11;;;;;;;27539:1135;28658:5;28651:12;;;;;19074:151;19149:12;19180:38;19202:6;19210:4;19216:1;19149:12;19790;19804:23;19831:6;:11;;19850:5;19857:4;19831:31;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;19789:73;;;;19879:55;19906:6;19914:7;19923:10;19879:26;:55::i;:::-;19872:62;19549:392;-1:-1:-1;;;;;;19549:392:0:o;20994:582::-;21138:12;21167:7;21162:408;;21190:19;21198:10;21190:7;:19::i;:::-;21162:408;;;21414:17;;:22;:49;;;;-1:-1:-1;21440:18:0;;;;:23;21414:49;21410:119;;;21490:24;;;;;2246:42:1;2234:55;;21490:24:0;;;2216:74:1;2189:18;;21490:24:0;2070:226:1;21410:119:0;-1:-1:-1;21549:10:0;21542:17;;22112:516;22243:17;;:21;22239:383;;22471:10;22465:17;22527:15;22514:10;22510:2;22506:19;22499:44;22239:383;22594:17;;;;;;;;;;;;;;14:332:1;72:6;125:2;113:9;104:7;100:23;96:32;93:52;;;141:1;138;131:12;93:52;180:9;167:23;230:66;223:5;219:78;212:5;209:89;199:117;;312:1;309;302:12;725:196;793:20;;853:42;842:54;;832:65;;822:93;;911:1;908;901:12;822:93;725:196;;;:::o;926:260::-;994:6;1002;1055:2;1043:9;1034:7;1030:23;1026:32;1023:52;;;1071:1;1068;1061:12;1023:52;1094:29;1113:9;1094:29;:::i;:::-;1084:39;;1142:38;1176:2;1165:9;1161:18;1142:38;:::i;:::-;1132:48;;926:260;;;;;:::o;1373:180::-;1432:6;1485:2;1473:9;1464:7;1460:23;1456:32;1453:52;;;1501:1;1498;1491:12;1453:52;-1:-1:-1;1524:23:1;;1373:180;-1:-1:-1;1373:180:1:o;1558:254::-;1626:6;1634;1687:2;1675:9;1666:7;1662:23;1658:32;1655:52;;;1703:1;1700;1693:12;1655:52;1739:9;1726:23;1716:33;;1768:38;1802:2;1791:9;1787:18;1768:38;:::i;1817:248::-;1885:6;1893;1946:2;1934:9;1925:7;1921:23;1917:32;1914:52;;;1962:1;1959;1952:12;1914:52;-1:-1:-1;;1985:23:1;;;2055:2;2040:18;;;2027:32;;-1:-1:-1;1817:248:1:o;2486:186::-;2545:6;2598:2;2586:9;2577:7;2573:23;2569:32;2566:52;;;2614:1;2611;2604:12;2566:52;2637:29;2656:9;2637:29;:::i;4840:184::-;4892:77;4889:1;4882:88;4989:4;4986:1;4979:15;5013:4;5010:1;5003:15;5029:277;5096:6;5149:2;5137:9;5128:7;5124:23;5120:32;5117:52;;;5165:1;5162;5155:12;5117:52;5197:9;5191:16;5250:5;5243:13;5236:21;5229:5;5226:32;5216:60;;5272:1;5269;5262:12;5311:282;5378:9;;;5399:11;;;5396:191;;;5443:77;5440:1;5433:88;5544:4;5541:1;5534:15;5572:4;5569:1;5562:15;5598:184;5650:77;5647:1;5640:88;5747:4;5744:1;5737:15;5771:4;5768:1;5761:15;5787:412;5916:3;5954:6;5948:13;5979:1;5989:129;6003:6;6000:1;5997:13;5989:129;;;6101:4;6085:14;;;6081:25;;6075:32;6062:11;;;6055:53;6018:12;5989:129;;;-1:-1:-1;6173:1:1;6137:16;;6162:13;;;-1:-1:-1;6137:16:1;5787:412;-1:-1:-1;5787:412:1:o","abiDefinition":[{"inputs":[{"internalType":"address","name":"_owner","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AccessControlBadConfirmation","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"bytes32","name":"neededRole","type":"bytes32"}],"name":"AccessControlUnauthorizedAccount","type":"error"},{"inputs":[{"internalType":"address","name":"target","type":"address"}],"name":"AddressEmptyCode","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"AddressInsufficientBalance","type":"error"},{"inputs":[],"name":"FailedInnerCall","type":"error"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"SafeERC20FailedOperation","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldChainGasAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newChainGasAmount","type":"uint256"}],"name":"ChainGasAmountUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldFeeRate","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newFeeRate","type":"uint256"}],"name":"FeeRateUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"address","name":"recipient","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"FeesSwept","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"previousAdminRole","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"newAdminRole","type":"bytes32"}],"name":"RoleAdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleRevoked","type":"event"},{"inputs":[],"name":"DEFAULT_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"FEE_BPS","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"FEE_RATE_MAX","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"GOVERNOR_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"GUARD_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"REFUNDER_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"RELAYER_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"chainGasAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleAdmin","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"uint256","name":"index","type":"uint256"}],"name":"getRoleMember","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleMemberCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"grantRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"hasRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"protocolFeeRate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"protocolFees","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"callerConfirmation","type":"address"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"revokeRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"newChainGasAmount","type":"uint256"}],"name":"setChainGasAmount","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"newFeeRate","type":"uint256"}],"name":"setProtocolFeeRate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"address","name":"recipient","type":"address"}],"name":"sweepProtocolFees","outputs":[],"stateMutability":"nonpayable","type":"function"}],"userDoc":{"kind":"user","methods":{"chainGasAmount()":{"notice":"Chain gas amount to forward as rebate if requested"},"protocolFeeRate()":{"notice":"Protocol fee rate taken on origin amount deposited in origin chain"},"protocolFees(address)":{"notice":"Protocol fee amounts accumulated"}},"version":1},"developerDoc":{"errors":{"AccessControlBadConfirmation()":[{"details":"The caller of a function is not the expected one. NOTE: Don't confuse with {AccessControlUnauthorizedAccount}."}],"AccessControlUnauthorizedAccount(address,bytes32)":[{"details":"The `account` is missing a role."}],"AddressEmptyCode(address)":[{"details":"There's no code at `target` (it is not a contract)."}],"AddressInsufficientBalance(address)":[{"details":"The ETH balance of the account is not enough to perform the operation."}],"FailedInnerCall()":[{"details":"A call to an address target failed. The target may have reverted."}],"SafeERC20FailedOperation(address)":[{"details":"An operation with an ERC20 token failed."}]},"events":{"RoleAdminChanged(bytes32,bytes32,bytes32)":{"details":"Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole` `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite {RoleAdminChanged} not being emitted signaling this."},"RoleGranted(bytes32,address,address)":{"details":"Emitted when `account` is granted `role`. `sender` is the account that originated the contract call, an admin role bearer except when using {AccessControl-_setupRole}."},"RoleRevoked(bytes32,address,address)":{"details":"Emitted when `account` is revoked `role`. `sender` is the account that originated the contract call: - if using `revokeRole`, it is the admin role bearer - if using `renounceRole`, it is the role bearer (i.e. `account`)"}},"kind":"dev","methods":{"getRoleAdmin(bytes32)":{"details":"Returns the admin role that controls `role`. See {grantRole} and {revokeRole}. To change a role's admin, use {_setRoleAdmin}."},"getRoleMember(bytes32,uint256)":{"details":"Returns one of the accounts that have `role`. `index` must be a value between 0 and {getRoleMemberCount}, non-inclusive. Role bearers are not sorted in any particular way, and their ordering may change at any point. WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure you perform all queries on the same block. See the following https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post] for more information."},"getRoleMemberCount(bytes32)":{"details":"Returns the number of accounts that have `role`. Can be used together with {getRoleMember} to enumerate all bearers of a role."},"grantRole(bytes32,address)":{"details":"Grants `role` to `account`. If `account` had not been already granted `role`, emits a {RoleGranted} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleGranted} event."},"hasRole(bytes32,address)":{"details":"Returns `true` if `account` has been granted `role`."},"renounceRole(bytes32,address)":{"details":"Revokes `role` from the calling account. Roles are often managed via {grantRole} and {revokeRole}: this function's purpose is to provide a mechanism for accounts to lose their privileges if they are compromised (such as when a trusted device is misplaced). If the calling account had been revoked `role`, emits a {RoleRevoked} event. Requirements: - the caller must be `callerConfirmation`. May emit a {RoleRevoked} event."},"revokeRole(bytes32,address)":{"details":"Revokes `role` from `account`. If `account` had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleRevoked} event."},"supportsInterface(bytes4)":{"details":"See {IERC165-supportsInterface}."}},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_owner\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"AccessControlBadConfirmation\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"neededRole\",\"type\":\"bytes32\"}],\"name\":\"AccessControlUnauthorizedAccount\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"}],\"name\":\"AddressEmptyCode\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"AddressInsufficientBalance\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"FailedInnerCall\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"}],\"name\":\"SafeERC20FailedOperation\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"oldChainGasAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newChainGasAmount\",\"type\":\"uint256\"}],\"name\":\"ChainGasAmountUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"oldFeeRate\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newFeeRate\",\"type\":\"uint256\"}],\"name\":\"FeeRateUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"FeesSwept\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"previousAdminRole\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"newAdminRole\",\"type\":\"bytes32\"}],\"name\":\"RoleAdminChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleGranted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleRevoked\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"DEFAULT_ADMIN_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"FEE_BPS\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"FEE_RATE_MAX\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"GOVERNOR_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"GUARD_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"REFUNDER_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"RELAYER_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"chainGasAmount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"}],\"name\":\"getRoleAdmin\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"index\",\"type\":\"uint256\"}],\"name\":\"getRoleMember\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"}],\"name\":\"getRoleMemberCount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"grantRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"hasRole\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"protocolFeeRate\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"protocolFees\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"callerConfirmation\",\"type\":\"address\"}],\"name\":\"renounceRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"revokeRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"newChainGasAmount\",\"type\":\"uint256\"}],\"name\":\"setChainGasAmount\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"newFeeRate\",\"type\":\"uint256\"}],\"name\":\"setProtocolFeeRate\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes4\",\"name\":\"interfaceId\",\"type\":\"bytes4\"}],\"name\":\"supportsInterface\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"}],\"name\":\"sweepProtocolFees\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"errors\":{\"AccessControlBadConfirmation()\":[{\"details\":\"The caller of a function is not the expected one. NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\"}],\"AccessControlUnauthorizedAccount(address,bytes32)\":[{\"details\":\"The `account` is missing a role.\"}],\"AddressEmptyCode(address)\":[{\"details\":\"There's no code at `target` (it is not a contract).\"}],\"AddressInsufficientBalance(address)\":[{\"details\":\"The ETH balance of the account is not enough to perform the operation.\"}],\"FailedInnerCall()\":[{\"details\":\"A call to an address target failed. The target may have reverted.\"}],\"SafeERC20FailedOperation(address)\":[{\"details\":\"An operation with an ERC20 token failed.\"}]},\"events\":{\"RoleAdminChanged(bytes32,bytes32,bytes32)\":{\"details\":\"Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole` `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite {RoleAdminChanged} not being emitted signaling this.\"},\"RoleGranted(bytes32,address,address)\":{\"details\":\"Emitted when `account` is granted `role`. `sender` is the account that originated the contract call, an admin role bearer except when using {AccessControl-_setupRole}.\"},\"RoleRevoked(bytes32,address,address)\":{\"details\":\"Emitted when `account` is revoked `role`. `sender` is the account that originated the contract call: - if using `revokeRole`, it is the admin role bearer - if using `renounceRole`, it is the role bearer (i.e. `account`)\"}},\"kind\":\"dev\",\"methods\":{\"getRoleAdmin(bytes32)\":{\"details\":\"Returns the admin role that controls `role`. See {grantRole} and {revokeRole}. To change a role's admin, use {_setRoleAdmin}.\"},\"getRoleMember(bytes32,uint256)\":{\"details\":\"Returns one of the accounts that have `role`. `index` must be a value between 0 and {getRoleMemberCount}, non-inclusive. Role bearers are not sorted in any particular way, and their ordering may change at any point. WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure you perform all queries on the same block. See the following https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post] for more information.\"},\"getRoleMemberCount(bytes32)\":{\"details\":\"Returns the number of accounts that have `role`. Can be used together with {getRoleMember} to enumerate all bearers of a role.\"},\"grantRole(bytes32,address)\":{\"details\":\"Grants `role` to `account`. If `account` had not been already granted `role`, emits a {RoleGranted} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleGranted} event.\"},\"hasRole(bytes32,address)\":{\"details\":\"Returns `true` if `account` has been granted `role`.\"},\"renounceRole(bytes32,address)\":{\"details\":\"Revokes `role` from the calling account. Roles are often managed via {grantRole} and {revokeRole}: this function's purpose is to provide a mechanism for accounts to lose their privileges if they are compromised (such as when a trusted device is misplaced). If the calling account had been revoked `role`, emits a {RoleRevoked} event. Requirements: - the caller must be `callerConfirmation`. May emit a {RoleRevoked} event.\"},\"revokeRole(bytes32,address)\":{\"details\":\"Revokes `role` from `account`. If `account` had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleRevoked} event.\"},\"supportsInterface(bytes4)\":{\"details\":\"See {IERC165-supportsInterface}.\"}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"chainGasAmount()\":{\"notice\":\"Chain gas amount to forward as rebate if requested\"},\"protocolFeeRate()\":{\"notice\":\"Protocol fee rate taken on origin amount deposited in origin chain\"},\"protocolFees(address)\":{\"notice\":\"Protocol fee amounts accumulated\"}},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeV2.sol\":\"Admin\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeV2.sol\":{\"keccak256\":\"0x7cd0f885e80e2bdaa638bc32ae7af7d2e248f99ce4b354c217d0f0f7d7302e0a\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://7ccf28df0bd7b4606986585acd8622ed9b4e81379690061bb66088f0a2270af1\",\"dweb:/ipfs/QmTf7HNdHZkK6vmx8ZgewycQEb72oLD9nPwBpsM5reMstQ\"]}},\"version\":1}"},"hashes":{"DEFAULT_ADMIN_ROLE()":"a217fddf","FEE_BPS()":"bf333f2c","FEE_RATE_MAX()":"0f5f6ed7","GOVERNOR_ROLE()":"ccc57490","GUARD_ROLE()":"03ed0ee5","REFUNDER_ROLE()":"5960ccf2","RELAYER_ROLE()":"926d7d7f","chainGasAmount()":"e00a83e0","getRoleAdmin(bytes32)":"248a9ca3","getRoleMember(bytes32,uint256)":"9010d07c","getRoleMemberCount(bytes32)":"ca15c873","grantRole(bytes32,address)":"2f2ff15d","hasRole(bytes32,address)":"91d14854","protocolFeeRate()":"58f85880","protocolFees(address)":"dcf844a7","renounceRole(bytes32,address)":"36568abe","revokeRole(bytes32,address)":"d547741f","setChainGasAmount(uint256)":"b250fe6b","setProtocolFeeRate(uint256)":"b13aa2d6","supportsInterface(bytes4)":"01ffc9a7","sweepProtocolFees(address,address)":"06f333f2"}},"solidity/FastBridgeV2.sol:Context":{"code":"0x","runtime-code":"0x","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.24 ^0.8.0 ^0.8.20;\n\n// contracts/interfaces/IAdmin.sol\n\ninterface IAdmin {\n // ============ Events ============\n\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n event ChainGasAmountUpdated(uint256 oldChainGasAmount, uint256 newChainGasAmount);\n\n // ============ Methods ============\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n\n function setChainGasAmount(uint256 newChainGasAmount) external;\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IFastBridgeRecipient.sol\n\ninterface IFastBridgeRecipient {\n function fastBridgeTransferReceived(\n address token,\n uint256 amount,\n bytes memory callParams\n )\n external\n payable\n returns (bytes4);\n}\n\n// contracts/interfaces/IFastBridgeV2Errors.sol\n\ninterface IFastBridgeV2Errors {\n error AmountIncorrect();\n error CallParamsLengthAboveMax();\n error ChainIncorrect();\n error ExclusivityParamsIncorrect();\n error MsgValueIncorrect();\n error NativeTokenCallValueNotSupported();\n error SenderIncorrect();\n error StatusIncorrect();\n error ZeroAddress();\n\n error RecipientIncorrectReturnValue();\n error RecipientNoReturnValue();\n\n error DeadlineExceeded();\n error DeadlineNotExceeded();\n error DeadlineTooShort();\n error DisputePeriodNotPassed();\n error DisputePeriodPassed();\n error ExclusivityPeriodNotPassed();\n\n error TransactionRelayed();\n}\n\n// contracts/libs/Errors.sol\n\nerror DeadlineExceeded();\nerror DeadlineNotExceeded();\nerror DeadlineTooShort();\nerror InsufficientOutputAmount();\n\nerror MsgValueIncorrect();\nerror PoolNotFound();\nerror TokenAddressMismatch();\nerror TokenNotContract();\nerror TokenNotETH();\nerror TokensIdentical();\n\nerror ChainIncorrect();\nerror AmountIncorrect();\nerror ZeroAddress();\n\nerror DisputePeriodNotPassed();\nerror DisputePeriodPassed();\nerror SenderIncorrect();\nerror StatusIncorrect();\nerror TransactionIdIncorrect();\nerror TransactionRelayed();\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// contracts/interfaces/IFastBridgeV2.sol\n\ninterface IFastBridgeV2 is IFastBridge {\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n struct BridgeTxDetails {\n BridgeStatus status;\n uint40 proofBlockTimestamp;\n uint48 proofBlockNumber;\n address proofRelayer;\n }\n\n struct BridgeRelay {\n uint48 blockNumber;\n uint48 blockTimestamp;\n address relayer;\n }\n\n /// @notice New params introduced in the FastBridgeV2.\n /// We are passing fields from the older BridgeParams struct outside of this struct\n /// for backwards compatibility.\n /// Note: quoteRelayer and quoteExclusivitySeconds are either both zero (indicating no exclusivity)\n /// or both non-zero (indicating exclusivity for the given period).\n /// Note: callValue \u003e 0 can NOT be used with destToken = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE (ETH_ADDRESS)\n /// @param quoteRelayer Relayer that provided the quote for the transaction\n /// @param quoteExclusivitySeconds Period of time the quote relayer is guaranteed exclusivity after user's deposit\n /// @param quoteId Unique quote identifier used for tracking the quote\n /// @param callValue ETH value to send to the recipient (if any)\n /// @param callParams Parameters for the arbitrary call to the destination recipient (if any)\n struct BridgeParamsV2 {\n address quoteRelayer;\n int256 quoteExclusivitySeconds;\n bytes quoteId;\n uint256 callValue;\n bytes callParams;\n }\n\n /// @notice Updated bridge transaction struct to include parameters introduced in FastBridgeV2.\n /// Note: only `exclusivityRelayer` can fill such a transaction until `exclusivityEndTime`.\n /// TODO: consider changing the encoding scheme to prevent spending extra gas on decoding.\n struct BridgeTransactionV2 {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n uint256 callValue; // ETH value to send to the recipient (if any) - replaces V1's sendChainGas flag\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n address exclusivityRelayer;\n uint256 exclusivityEndTime;\n bytes callParams;\n }\n\n event BridgeQuoteDetails(bytes32 indexed transactionId, bytes quoteId);\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability\n /// to provide temporary exclusivity fill rights for the quote relayer.\n /// @param params The parameters required to bridge\n /// @param paramsV2 The parameters for exclusivity fill rights (optional, can be left empty)\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function relay(bytes memory request, address relayer) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param transactionId The transaction id associated with the encoded bridge transaction to prove\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital.\n /// @notice Can only send funds to the relayer address on the proof.\n /// @param request The encoded bridge transaction to claim on origin chain\n function claim(bytes memory request) external;\n /// @notice Checks if a transaction has been relayed\n /// @param transactionId The ID of the transaction to check\n /// @return True if the transaction has been relayed, false otherwise\n function bridgeRelays(bytes32 transactionId) external view returns (bool);\n\n /// @notice Returns the status of a bridge transaction\n /// @param transactionId The ID of the bridge transaction\n /// @return BridgeStatus Status of the bridge transaction\n function bridgeStatuses(bytes32 transactionId) external view returns (BridgeStatus);\n\n /// @notice Returns the timestamp and relayer of a bridge proof\n /// @param transactionId The ID of the bridge transaction\n /// @return timestamp The timestamp of the bridge proof\n /// @return relayer The relayer address of the bridge proof\n function bridgeProofs(bytes32 transactionId) external view returns (uint96 timestamp, address relayer);\n\n /// @notice Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\n /// @param request The bridge request to decode\n function getBridgeTransactionV2(bytes memory request) external view returns (BridgeTransactionV2 memory);\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// contracts/libs/UniversalToken.sol\n\nlibrary UniversalTokenLib {\n using SafeERC20 for IERC20;\n\n address internal constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Transfers tokens to the given account. Reverts if transfer is not successful.\n /// @dev This might trigger fallback, if ETH is transferred to the contract.\n /// Make sure this can not lead to reentrancy attacks.\n function universalTransfer(address token, address to, uint256 value) internal {\n // Don't do anything, if need to send tokens to this address\n if (to == address(this)) return;\n // Don't do anything, if trying to send zero value\n if (value == 0) return;\n if (token == ETH_ADDRESS) {\n /// @dev Note: this can potentially lead to executing code in `to`.\n // solhint-disable-next-line avoid-low-level-calls\n (bool success,) = to.call{value: value}(\"\");\n require(success, \"ETH transfer failed\");\n } else {\n IERC20(token).safeTransfer(to, value);\n }\n }\n\n /// @notice Issues an infinite allowance to the spender, if the current allowance is insufficient\n /// to spend the given amount.\n function universalApproveInfinity(address token, address spender, uint256 amountToSpend) internal {\n // ETH Chad doesn't require your approval\n if (token == ETH_ADDRESS) return;\n // No-op if allowance is already sufficient\n uint256 allowance = IERC20(token).allowance(address(this), spender);\n if (allowance \u003e= amountToSpend) return;\n // Otherwise, reset approval to 0 and set to max allowance\n if (allowance \u003e 0) IERC20(token).safeDecreaseAllowance(spender, allowance);\n IERC20(token).safeIncreaseAllowance(spender, type(uint256).max);\n }\n\n /// @notice Returns the balance of the given token (or native ETH) for the given account.\n function universalBalanceOf(address token, address account) internal view returns (uint256) {\n if (token == ETH_ADDRESS) {\n return account.balance;\n } else {\n return IERC20(token).balanceOf(account);\n }\n }\n\n /// @dev Checks that token is a contract and not ETH_ADDRESS.\n function assertIsContract(address token) internal view {\n // Check that ETH_ADDRESS was not used (in case this is a predeploy on any of the chains)\n if (token == UniversalTokenLib.ETH_ADDRESS) revert TokenNotContract();\n // Check that token is not an EOA\n if (token.code.length == 0) revert TokenNotContract();\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/Admin.sol\n\ncontract Admin is IAdmin, AccessControlEnumerable {\n using UniversalTokenLib for address;\n\n bytes32 public constant RELAYER_ROLE = keccak256(\"RELAYER_ROLE\");\n bytes32 public constant REFUNDER_ROLE = keccak256(\"REFUNDER_ROLE\");\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n uint256 public constant FEE_BPS = 1e6;\n uint256 public constant FEE_RATE_MAX = 0.01e6; // max 1% on origin amount\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Chain gas amount to forward as rebate if requested\n uint256 public chainGasAmount;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n }\n\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n require(newFeeRate \u003c= FEE_RATE_MAX, \"newFeeRate \u003e max\");\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n token.universalTransfer(recipient, feeAmount);\n emit FeesSwept(token, recipient, feeAmount);\n }\n\n function setChainGasAmount(uint256 newChainGasAmount) external onlyRole(GOVERNOR_ROLE) {\n uint256 oldChainGasAmount = chainGasAmount;\n chainGasAmount = newChainGasAmount;\n emit ChainGasAmountUpdated(oldChainGasAmount, newChainGasAmount);\n }\n}\n\n// contracts/FastBridgeV2.sol\n\n/// @notice FastBridgeV2 is a contract for bridging tokens across chains.\ncontract FastBridgeV2 is Admin, IFastBridgeV2, IFastBridgeV2Errors {\n using SafeERC20 for IERC20;\n using UniversalTokenLib for address;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Delay for a transaction after which it could be permisionlessly refunded\n uint256 public constant REFUND_DELAY = 7 days;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n /// @notice Maximum length of accepted callParams\n uint256 public constant MAX_CALL_PARAMS_LENGTH = 2 ** 16 - 1;\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeTxDetails) public bridgeTxDetails;\n /// @notice Relay details on destination chain\n mapping(bytes32 =\u003e BridgeRelay) public bridgeRelayDetails;\n /// @notice Unique bridge nonces tracked per originSender\n mapping(address =\u003e uint256) public senderNonces;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Replaced by senderNonces\n uint256 public immutable nonce = 0;\n /// @notice the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n bridge({\n params: params,\n paramsV2: BridgeParamsV2({\n quoteRelayer: address(0),\n quoteExclusivitySeconds: 0,\n quoteId: bytes(\"\"),\n callValue: 0,\n callParams: bytes(\"\")\n })\n });\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes memory request) external payable {\n relay({request: request, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes memory request, bytes32 destTxHash) external {\n prove({transactionId: keccak256(request), destTxHash: destTxHash, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridgeV2\n function claim(bytes memory request) external {\n claim({request: request, to: address(0)});\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003e DISPUTE_PERIOD) {\n revert DisputePeriodPassed();\n }\n\n // @dev relayer gets slashed effectively if dest relay has gone thru\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n bridgeTxDetails[transactionId].proofRelayer = address(0);\n bridgeTxDetails[transactionId].proofBlockTimestamp = 0;\n bridgeTxDetails[transactionId].proofBlockNumber = 0;\n\n emit BridgeProofDisputed(transactionId, msg.sender);\n }\n\n /// @inheritdoc IFastBridge\n function refund(bytes memory request) external {\n bytes32 transactionId = keccak256(request);\n\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n\n if (bridgeTxDetails[transactionId].status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n\n if (hasRole(REFUNDER_ROLE, msg.sender)) {\n // Refunder can refund if deadline has passed\n if (block.timestamp \u003c= transaction.deadline) revert DeadlineNotExceeded();\n } else {\n // Permissionless refund is allowed after REFUND_DELAY\n if (block.timestamp \u003c= transaction.deadline + REFUND_DELAY) revert DeadlineNotExceeded();\n }\n\n // if all checks passed, set to REFUNDED status\n bridgeTxDetails[transactionId].status = BridgeStatus.REFUNDED;\n\n // transfer origin collateral back to original sender\n address to = transaction.originSender;\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount + transaction.originFeeAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (bridgeTxDetails[transactionId].proofRelayer != relayer) revert SenderIncorrect();\n return _timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n /// @dev This method is added to achieve backwards compatibility with decoding requests into V1 structs:\n /// - `callValue` is partially reported as a zero/non-zero flag\n /// - `callParams` is ignored\n /// In order to process all kinds of requests use getBridgeTransactionV2 instead.\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory) {\n // Try decoding into V2 struct first. This will revert if V1 struct is passed\n try this.getBridgeTransactionV2(request) returns (BridgeTransactionV2 memory txV2) {\n // Note: we entirely ignore the callParams field, as it was not present in V1\n return BridgeTransaction({\n originChainId: txV2.originChainId,\n destChainId: txV2.destChainId,\n originSender: txV2.originSender,\n destRecipient: txV2.destRecipient,\n originToken: txV2.originToken,\n destToken: txV2.destToken,\n originAmount: txV2.originAmount,\n destAmount: txV2.destAmount,\n originFeeAmount: txV2.originFeeAmount,\n sendChainGas: txV2.callValue != 0,\n deadline: txV2.deadline,\n nonce: txV2.nonce\n });\n } catch {\n // Fallback to V1 struct\n return abi.decode(request, (BridgeTransaction));\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) public payable {\n int256 exclusivityEndTime = int256(block.timestamp) + paramsV2.quoteExclusivitySeconds;\n _validateBridgeParams(params, paramsV2, exclusivityEndTime);\n\n // transfer tokens to bridge contract\n /// @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _pullToken(params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n\n // set status to requested\n bytes memory request = abi.encode(\n BridgeTransactionV2({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n callValue: paramsV2.callValue,\n deadline: params.deadline,\n nonce: senderNonces[params.sender]++, // increment nonce on every bridge\n exclusivityRelayer: paramsV2.quoteRelayer,\n // We checked exclusivityEndTime to be in range (0 .. params.deadline] above, so can safely cast\n exclusivityEndTime: uint256(exclusivityEndTime),\n callParams: paramsV2.callParams\n })\n );\n bytes32 transactionId = keccak256(request);\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n\n emit BridgeRequested({\n transactionId: transactionId,\n sender: params.sender,\n request: request,\n destChainId: params.dstChainId,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n sendChainGas: paramsV2.callValue != 0\n });\n emit BridgeQuoteDetails(transactionId, paramsV2.quoteId);\n }\n\n /// @inheritdoc IFastBridgeV2\n function relay(bytes memory request, address relayer) public payable {\n bytes32 transactionId = keccak256(request);\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n _validateRelayParams(transaction, transactionId, relayer);\n // mark bridge transaction as relayed\n bridgeRelayDetails[transactionId] =\n BridgeRelay({blockNumber: uint48(block.number), blockTimestamp: uint48(block.timestamp), relayer: relayer});\n\n // transfer tokens to recipient on destination chain and do an arbitrary call if requested\n address to = transaction.destRecipient;\n address token = transaction.destToken;\n uint256 amount = transaction.destAmount;\n\n // All state changes have been done at this point, can proceed to the external calls.\n // This follows the checks-effects-interactions pattern to mitigate potential reentrancy attacks.\n if (token == UniversalTokenLib.ETH_ADDRESS) {\n // For ETH non-zero callValue is not allowed\n if (transaction.callValue != 0) revert NativeTokenCallValueNotSupported();\n // Check that the correct msg.value was sent\n if (msg.value != amount) revert MsgValueIncorrect();\n } else {\n // For ERC20s, we check that the correct msg.value was sent\n if (msg.value != transaction.callValue) revert MsgValueIncorrect();\n // We need to transfer the tokens from the Relayer to the recipient first before performing an\n // optional post-transfer arbitrary call.\n IERC20(token).safeTransferFrom(msg.sender, to, amount);\n }\n\n if (transaction.callParams.length != 0) {\n // Arbitrary call requested, perform it while supplying full msg.value to the recipient\n // Note: if token has a fee on transfers, the recipient will have received less than `amount`.\n // This is a very niche edge case and should be handled by the recipient contract.\n _checkedCallRecipient({recipient: to, token: token, amount: amount, callParams: transaction.callParams});\n } else if (msg.value != 0) {\n // No arbitrary call requested, but msg.value was sent. This is either a relay with ETH,\n // or a non-zero callValue request with an ERC20. In both cases, transfer the ETH to the recipient.\n Address.sendValue(payable(to), msg.value);\n }\n\n emit BridgeRelayed({\n transactionId: transactionId,\n relayer: relayer,\n to: to,\n originChainId: transaction.originChainId,\n originToken: transaction.originToken,\n destToken: transaction.destToken,\n originAmount: transaction.originAmount,\n destAmount: transaction.destAmount,\n chainGasAmount: transaction.callValue\n });\n }\n\n /// @inheritdoc IFastBridgeV2\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) public onlyRole(RELAYER_ROLE) {\n // update bridge tx status given proof provided\n if (bridgeTxDetails[transactionId].status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n bridgeTxDetails[transactionId].status = BridgeStatus.RELAYER_PROVED;\n bridgeTxDetails[transactionId].proofBlockTimestamp = uint40(block.timestamp);\n bridgeTxDetails[transactionId].proofBlockNumber = uint48(block.number);\n bridgeTxDetails[transactionId].proofRelayer = relayer;\n\n emit BridgeProofProvided(transactionId, relayer, destTxHash);\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes memory request, address to) public {\n bytes32 transactionId = keccak256(request);\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n\n // update bridge tx status if able to claim origin collateral\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n\n // if \"to\" is zero addr, permissionlessly send funds to proven relayer\n if (to == address(0)) {\n to = bridgeTxDetails[transactionId].proofRelayer;\n } else if (bridgeTxDetails[transactionId].proofRelayer != msg.sender) {\n revert SenderIncorrect();\n }\n\n if (_timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003c= DISPUTE_PERIOD) {\n revert DisputePeriodNotPassed();\n }\n\n bridgeTxDetails[transactionId].status = BridgeStatus.RELAYER_CLAIMED;\n\n // update protocol fees if origin fee amount exists\n if (transaction.originFeeAmount \u003e 0) protocolFees[transaction.originToken] += transaction.originFeeAmount;\n\n // transfer origin collateral less fee to specified address\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositClaimed(transactionId, bridgeTxDetails[transactionId].proofRelayer, to, token, amount);\n }\n\n function bridgeStatuses(bytes32 transactionId) public view returns (BridgeStatus status) {\n return bridgeTxDetails[transactionId].status;\n }\n\n function bridgeProofs(bytes32 transactionId) public view returns (uint96 timestamp, address relayer) {\n timestamp = bridgeTxDetails[transactionId].proofBlockTimestamp;\n relayer = bridgeTxDetails[transactionId].proofRelayer;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeRelays(bytes32 transactionId) public view returns (bool) {\n // has this transactionId been relayed?\n return bridgeRelayDetails[transactionId].relayer != address(0);\n }\n\n /// @inheritdoc IFastBridgeV2\n function getBridgeTransactionV2(bytes memory request) public pure returns (BridgeTransactionV2 memory) {\n return abi.decode(request, (BridgeTransactionV2));\n }\n\n /// @notice Pulls a requested token from the user to this contract.\n function _pullToken(address token, uint256 amount) internal returns (uint256 amountPulled) {\n if (token == UniversalTokenLib.ETH_ADDRESS) {\n // For ETH we just need to check that the supplied msg.value is correct\n if (amount != msg.value) revert MsgValueIncorrect();\n amountPulled = msg.value;\n } else {\n token.assertIsContract();\n // Record token balance before transfer\n amountPulled = IERC20(token).balanceOf(address(this));\n // Token needs to be pulled only if msg.value is zero\n // This way user can specify WETH as the origin asset\n IERC20(token).safeTransferFrom(msg.sender, address(this), amount);\n // Use the difference between the recorded balance and the current balance as the amountPulled\n amountPulled = IERC20(token).balanceOf(address(this)) - amountPulled;\n }\n }\n\n /// @notice Calls the Recipient's hook function with the specified callParams and performs\n /// all the necessary checks for the returned value.\n function _checkedCallRecipient(\n address recipient,\n address token,\n uint256 amount,\n bytes memory callParams\n )\n internal\n {\n bytes memory hookData =\n abi.encodeCall(IFastBridgeRecipient.fastBridgeTransferReceived, (token, amount, callParams));\n // This will bubble any revert messages from the hook function\n bytes memory returnData = Address.functionCallWithValue({target: recipient, data: hookData, value: msg.value});\n // Explicit revert if no return data at all\n if (returnData.length == 0) revert RecipientNoReturnValue();\n // Check that exactly a single return value was returned\n if (returnData.length != 32) revert RecipientIncorrectReturnValue();\n // Return value should be abi-encoded hook function selector\n if (bytes32(returnData) != bytes32(IFastBridgeRecipient.fastBridgeTransferReceived.selector)) {\n revert RecipientIncorrectReturnValue();\n }\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint40(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint40).max but\n /// proof.timestamp \u003c type(uint40).max via unchecked statement\n /// @param proofBlockTimestamp The bridge proof block timestamp\n /// @return delta Time delta since proof submitted\n function _timeSince(uint40 proofBlockTimestamp) internal view returns (uint256 delta) {\n unchecked {\n delta = uint40(block.timestamp) - proofBlockTimestamp;\n }\n }\n\n /// @notice Performs all the necessary checks for a bridge to happen.\n /// @dev There's no good way to refactor this function to reduce cyclomatic complexity due to\n /// the number of checks that need to be performed, so we skip the code-complexity rule here.\n // solhint-disable-next-line code-complexity\n function _validateBridgeParams(\n BridgeParams memory params,\n BridgeParamsV2 memory paramsV2,\n int256 exclusivityEndTime\n )\n internal\n view\n {\n // Check V1 (legacy) params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.sender == address(0) || params.to == address(0)) revert ZeroAddress();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n // Check V2 params\n if (paramsV2.callParams.length \u003e MAX_CALL_PARAMS_LENGTH) revert CallParamsLengthAboveMax();\n if (paramsV2.callValue != 0 \u0026\u0026 params.destToken == UniversalTokenLib.ETH_ADDRESS) {\n revert NativeTokenCallValueNotSupported();\n }\n // exclusivityEndTime must be in range (0 .. params.deadline]\n if (exclusivityEndTime \u003c= 0 || exclusivityEndTime \u003e int256(params.deadline)) {\n revert ExclusivityParamsIncorrect();\n }\n }\n\n /// @notice Performs all the necessary checks for a relay to happen.\n function _validateRelayParams(\n BridgeTransactionV2 memory transaction,\n bytes32 transactionId,\n address relayer\n )\n internal\n view\n {\n if (relayer == address(0)) revert ZeroAddress();\n // Check if the transaction has already been relayed\n if (bridgeRelays(transactionId)) revert TransactionRelayed();\n if (transaction.destChainId != uint32(block.chainid)) revert ChainIncorrect();\n // Check the deadline for relay to happen\n if (block.timestamp \u003e transaction.deadline) revert DeadlineExceeded();\n // Check the exclusivity period, if it is still ongoing\n // forgefmt: disable-next-item\n if (\n transaction.exclusivityRelayer != address(0) \u0026\u0026\n transaction.exclusivityRelayer != relayer \u0026\u0026\n block.timestamp \u003c= transaction.exclusivityEndTime\n ) {\n revert ExclusivityPeriodNotPassed();\n }\n }\n}\n","language":"Solidity","languageVersion":"0.8.24","compilerVersion":"0.8.24","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"","srcMapRuntime":"","abiDefinition":[],"userDoc":{"kind":"user","methods":{},"version":1},"developerDoc":{"details":"Provides information about the current execution context, including the sender of the transaction and its data. While these are generally available via msg.sender and msg.data, they should not be accessed in such a direct manner, since when dealing with meta-transactions the account sending and paying for execution may not be the actual sender (as far as an application is concerned). This contract is only required for intermediate, library-like contracts.","kind":"dev","methods":{},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[],\"devdoc\":{\"details\":\"Provides information about the current execution context, including the sender of the transaction and its data. While these are generally available via msg.sender and msg.data, they should not be accessed in such a direct manner, since when dealing with meta-transactions the account sending and paying for execution may not be the actual sender (as far as an application is concerned). This contract is only required for intermediate, library-like contracts.\",\"kind\":\"dev\",\"methods\":{},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeV2.sol\":\"Context\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeV2.sol\":{\"keccak256\":\"0x7cd0f885e80e2bdaa638bc32ae7af7d2e248f99ce4b354c217d0f0f7d7302e0a\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://7ccf28df0bd7b4606986585acd8622ed9b4e81379690061bb66088f0a2270af1\",\"dweb:/ipfs/QmTf7HNdHZkK6vmx8ZgewycQEb72oLD9nPwBpsM5reMstQ\"]}},\"version\":1}"},"hashes":{}},"solidity/FastBridgeV2.sol:ERC165":{"code":"0x","runtime-code":"0x","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.24 ^0.8.0 ^0.8.20;\n\n// contracts/interfaces/IAdmin.sol\n\ninterface IAdmin {\n // ============ Events ============\n\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n event ChainGasAmountUpdated(uint256 oldChainGasAmount, uint256 newChainGasAmount);\n\n // ============ Methods ============\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n\n function setChainGasAmount(uint256 newChainGasAmount) external;\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IFastBridgeRecipient.sol\n\ninterface IFastBridgeRecipient {\n function fastBridgeTransferReceived(\n address token,\n uint256 amount,\n bytes memory callParams\n )\n external\n payable\n returns (bytes4);\n}\n\n// contracts/interfaces/IFastBridgeV2Errors.sol\n\ninterface IFastBridgeV2Errors {\n error AmountIncorrect();\n error CallParamsLengthAboveMax();\n error ChainIncorrect();\n error ExclusivityParamsIncorrect();\n error MsgValueIncorrect();\n error NativeTokenCallValueNotSupported();\n error SenderIncorrect();\n error StatusIncorrect();\n error ZeroAddress();\n\n error RecipientIncorrectReturnValue();\n error RecipientNoReturnValue();\n\n error DeadlineExceeded();\n error DeadlineNotExceeded();\n error DeadlineTooShort();\n error DisputePeriodNotPassed();\n error DisputePeriodPassed();\n error ExclusivityPeriodNotPassed();\n\n error TransactionRelayed();\n}\n\n// contracts/libs/Errors.sol\n\nerror DeadlineExceeded();\nerror DeadlineNotExceeded();\nerror DeadlineTooShort();\nerror InsufficientOutputAmount();\n\nerror MsgValueIncorrect();\nerror PoolNotFound();\nerror TokenAddressMismatch();\nerror TokenNotContract();\nerror TokenNotETH();\nerror TokensIdentical();\n\nerror ChainIncorrect();\nerror AmountIncorrect();\nerror ZeroAddress();\n\nerror DisputePeriodNotPassed();\nerror DisputePeriodPassed();\nerror SenderIncorrect();\nerror StatusIncorrect();\nerror TransactionIdIncorrect();\nerror TransactionRelayed();\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// contracts/interfaces/IFastBridgeV2.sol\n\ninterface IFastBridgeV2 is IFastBridge {\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n struct BridgeTxDetails {\n BridgeStatus status;\n uint40 proofBlockTimestamp;\n uint48 proofBlockNumber;\n address proofRelayer;\n }\n\n struct BridgeRelay {\n uint48 blockNumber;\n uint48 blockTimestamp;\n address relayer;\n }\n\n /// @notice New params introduced in the FastBridgeV2.\n /// We are passing fields from the older BridgeParams struct outside of this struct\n /// for backwards compatibility.\n /// Note: quoteRelayer and quoteExclusivitySeconds are either both zero (indicating no exclusivity)\n /// or both non-zero (indicating exclusivity for the given period).\n /// Note: callValue \u003e 0 can NOT be used with destToken = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE (ETH_ADDRESS)\n /// @param quoteRelayer Relayer that provided the quote for the transaction\n /// @param quoteExclusivitySeconds Period of time the quote relayer is guaranteed exclusivity after user's deposit\n /// @param quoteId Unique quote identifier used for tracking the quote\n /// @param callValue ETH value to send to the recipient (if any)\n /// @param callParams Parameters for the arbitrary call to the destination recipient (if any)\n struct BridgeParamsV2 {\n address quoteRelayer;\n int256 quoteExclusivitySeconds;\n bytes quoteId;\n uint256 callValue;\n bytes callParams;\n }\n\n /// @notice Updated bridge transaction struct to include parameters introduced in FastBridgeV2.\n /// Note: only `exclusivityRelayer` can fill such a transaction until `exclusivityEndTime`.\n /// TODO: consider changing the encoding scheme to prevent spending extra gas on decoding.\n struct BridgeTransactionV2 {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n uint256 callValue; // ETH value to send to the recipient (if any) - replaces V1's sendChainGas flag\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n address exclusivityRelayer;\n uint256 exclusivityEndTime;\n bytes callParams;\n }\n\n event BridgeQuoteDetails(bytes32 indexed transactionId, bytes quoteId);\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability\n /// to provide temporary exclusivity fill rights for the quote relayer.\n /// @param params The parameters required to bridge\n /// @param paramsV2 The parameters for exclusivity fill rights (optional, can be left empty)\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function relay(bytes memory request, address relayer) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param transactionId The transaction id associated with the encoded bridge transaction to prove\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital.\n /// @notice Can only send funds to the relayer address on the proof.\n /// @param request The encoded bridge transaction to claim on origin chain\n function claim(bytes memory request) external;\n /// @notice Checks if a transaction has been relayed\n /// @param transactionId The ID of the transaction to check\n /// @return True if the transaction has been relayed, false otherwise\n function bridgeRelays(bytes32 transactionId) external view returns (bool);\n\n /// @notice Returns the status of a bridge transaction\n /// @param transactionId The ID of the bridge transaction\n /// @return BridgeStatus Status of the bridge transaction\n function bridgeStatuses(bytes32 transactionId) external view returns (BridgeStatus);\n\n /// @notice Returns the timestamp and relayer of a bridge proof\n /// @param transactionId The ID of the bridge transaction\n /// @return timestamp The timestamp of the bridge proof\n /// @return relayer The relayer address of the bridge proof\n function bridgeProofs(bytes32 transactionId) external view returns (uint96 timestamp, address relayer);\n\n /// @notice Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\n /// @param request The bridge request to decode\n function getBridgeTransactionV2(bytes memory request) external view returns (BridgeTransactionV2 memory);\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// contracts/libs/UniversalToken.sol\n\nlibrary UniversalTokenLib {\n using SafeERC20 for IERC20;\n\n address internal constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Transfers tokens to the given account. Reverts if transfer is not successful.\n /// @dev This might trigger fallback, if ETH is transferred to the contract.\n /// Make sure this can not lead to reentrancy attacks.\n function universalTransfer(address token, address to, uint256 value) internal {\n // Don't do anything, if need to send tokens to this address\n if (to == address(this)) return;\n // Don't do anything, if trying to send zero value\n if (value == 0) return;\n if (token == ETH_ADDRESS) {\n /// @dev Note: this can potentially lead to executing code in `to`.\n // solhint-disable-next-line avoid-low-level-calls\n (bool success,) = to.call{value: value}(\"\");\n require(success, \"ETH transfer failed\");\n } else {\n IERC20(token).safeTransfer(to, value);\n }\n }\n\n /// @notice Issues an infinite allowance to the spender, if the current allowance is insufficient\n /// to spend the given amount.\n function universalApproveInfinity(address token, address spender, uint256 amountToSpend) internal {\n // ETH Chad doesn't require your approval\n if (token == ETH_ADDRESS) return;\n // No-op if allowance is already sufficient\n uint256 allowance = IERC20(token).allowance(address(this), spender);\n if (allowance \u003e= amountToSpend) return;\n // Otherwise, reset approval to 0 and set to max allowance\n if (allowance \u003e 0) IERC20(token).safeDecreaseAllowance(spender, allowance);\n IERC20(token).safeIncreaseAllowance(spender, type(uint256).max);\n }\n\n /// @notice Returns the balance of the given token (or native ETH) for the given account.\n function universalBalanceOf(address token, address account) internal view returns (uint256) {\n if (token == ETH_ADDRESS) {\n return account.balance;\n } else {\n return IERC20(token).balanceOf(account);\n }\n }\n\n /// @dev Checks that token is a contract and not ETH_ADDRESS.\n function assertIsContract(address token) internal view {\n // Check that ETH_ADDRESS was not used (in case this is a predeploy on any of the chains)\n if (token == UniversalTokenLib.ETH_ADDRESS) revert TokenNotContract();\n // Check that token is not an EOA\n if (token.code.length == 0) revert TokenNotContract();\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/Admin.sol\n\ncontract Admin is IAdmin, AccessControlEnumerable {\n using UniversalTokenLib for address;\n\n bytes32 public constant RELAYER_ROLE = keccak256(\"RELAYER_ROLE\");\n bytes32 public constant REFUNDER_ROLE = keccak256(\"REFUNDER_ROLE\");\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n uint256 public constant FEE_BPS = 1e6;\n uint256 public constant FEE_RATE_MAX = 0.01e6; // max 1% on origin amount\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Chain gas amount to forward as rebate if requested\n uint256 public chainGasAmount;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n }\n\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n require(newFeeRate \u003c= FEE_RATE_MAX, \"newFeeRate \u003e max\");\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n token.universalTransfer(recipient, feeAmount);\n emit FeesSwept(token, recipient, feeAmount);\n }\n\n function setChainGasAmount(uint256 newChainGasAmount) external onlyRole(GOVERNOR_ROLE) {\n uint256 oldChainGasAmount = chainGasAmount;\n chainGasAmount = newChainGasAmount;\n emit ChainGasAmountUpdated(oldChainGasAmount, newChainGasAmount);\n }\n}\n\n// contracts/FastBridgeV2.sol\n\n/// @notice FastBridgeV2 is a contract for bridging tokens across chains.\ncontract FastBridgeV2 is Admin, IFastBridgeV2, IFastBridgeV2Errors {\n using SafeERC20 for IERC20;\n using UniversalTokenLib for address;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Delay for a transaction after which it could be permisionlessly refunded\n uint256 public constant REFUND_DELAY = 7 days;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n /// @notice Maximum length of accepted callParams\n uint256 public constant MAX_CALL_PARAMS_LENGTH = 2 ** 16 - 1;\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeTxDetails) public bridgeTxDetails;\n /// @notice Relay details on destination chain\n mapping(bytes32 =\u003e BridgeRelay) public bridgeRelayDetails;\n /// @notice Unique bridge nonces tracked per originSender\n mapping(address =\u003e uint256) public senderNonces;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Replaced by senderNonces\n uint256 public immutable nonce = 0;\n /// @notice the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n bridge({\n params: params,\n paramsV2: BridgeParamsV2({\n quoteRelayer: address(0),\n quoteExclusivitySeconds: 0,\n quoteId: bytes(\"\"),\n callValue: 0,\n callParams: bytes(\"\")\n })\n });\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes memory request) external payable {\n relay({request: request, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes memory request, bytes32 destTxHash) external {\n prove({transactionId: keccak256(request), destTxHash: destTxHash, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridgeV2\n function claim(bytes memory request) external {\n claim({request: request, to: address(0)});\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003e DISPUTE_PERIOD) {\n revert DisputePeriodPassed();\n }\n\n // @dev relayer gets slashed effectively if dest relay has gone thru\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n bridgeTxDetails[transactionId].proofRelayer = address(0);\n bridgeTxDetails[transactionId].proofBlockTimestamp = 0;\n bridgeTxDetails[transactionId].proofBlockNumber = 0;\n\n emit BridgeProofDisputed(transactionId, msg.sender);\n }\n\n /// @inheritdoc IFastBridge\n function refund(bytes memory request) external {\n bytes32 transactionId = keccak256(request);\n\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n\n if (bridgeTxDetails[transactionId].status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n\n if (hasRole(REFUNDER_ROLE, msg.sender)) {\n // Refunder can refund if deadline has passed\n if (block.timestamp \u003c= transaction.deadline) revert DeadlineNotExceeded();\n } else {\n // Permissionless refund is allowed after REFUND_DELAY\n if (block.timestamp \u003c= transaction.deadline + REFUND_DELAY) revert DeadlineNotExceeded();\n }\n\n // if all checks passed, set to REFUNDED status\n bridgeTxDetails[transactionId].status = BridgeStatus.REFUNDED;\n\n // transfer origin collateral back to original sender\n address to = transaction.originSender;\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount + transaction.originFeeAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (bridgeTxDetails[transactionId].proofRelayer != relayer) revert SenderIncorrect();\n return _timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n /// @dev This method is added to achieve backwards compatibility with decoding requests into V1 structs:\n /// - `callValue` is partially reported as a zero/non-zero flag\n /// - `callParams` is ignored\n /// In order to process all kinds of requests use getBridgeTransactionV2 instead.\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory) {\n // Try decoding into V2 struct first. This will revert if V1 struct is passed\n try this.getBridgeTransactionV2(request) returns (BridgeTransactionV2 memory txV2) {\n // Note: we entirely ignore the callParams field, as it was not present in V1\n return BridgeTransaction({\n originChainId: txV2.originChainId,\n destChainId: txV2.destChainId,\n originSender: txV2.originSender,\n destRecipient: txV2.destRecipient,\n originToken: txV2.originToken,\n destToken: txV2.destToken,\n originAmount: txV2.originAmount,\n destAmount: txV2.destAmount,\n originFeeAmount: txV2.originFeeAmount,\n sendChainGas: txV2.callValue != 0,\n deadline: txV2.deadline,\n nonce: txV2.nonce\n });\n } catch {\n // Fallback to V1 struct\n return abi.decode(request, (BridgeTransaction));\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) public payable {\n int256 exclusivityEndTime = int256(block.timestamp) + paramsV2.quoteExclusivitySeconds;\n _validateBridgeParams(params, paramsV2, exclusivityEndTime);\n\n // transfer tokens to bridge contract\n /// @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _pullToken(params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n\n // set status to requested\n bytes memory request = abi.encode(\n BridgeTransactionV2({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n callValue: paramsV2.callValue,\n deadline: params.deadline,\n nonce: senderNonces[params.sender]++, // increment nonce on every bridge\n exclusivityRelayer: paramsV2.quoteRelayer,\n // We checked exclusivityEndTime to be in range (0 .. params.deadline] above, so can safely cast\n exclusivityEndTime: uint256(exclusivityEndTime),\n callParams: paramsV2.callParams\n })\n );\n bytes32 transactionId = keccak256(request);\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n\n emit BridgeRequested({\n transactionId: transactionId,\n sender: params.sender,\n request: request,\n destChainId: params.dstChainId,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n sendChainGas: paramsV2.callValue != 0\n });\n emit BridgeQuoteDetails(transactionId, paramsV2.quoteId);\n }\n\n /// @inheritdoc IFastBridgeV2\n function relay(bytes memory request, address relayer) public payable {\n bytes32 transactionId = keccak256(request);\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n _validateRelayParams(transaction, transactionId, relayer);\n // mark bridge transaction as relayed\n bridgeRelayDetails[transactionId] =\n BridgeRelay({blockNumber: uint48(block.number), blockTimestamp: uint48(block.timestamp), relayer: relayer});\n\n // transfer tokens to recipient on destination chain and do an arbitrary call if requested\n address to = transaction.destRecipient;\n address token = transaction.destToken;\n uint256 amount = transaction.destAmount;\n\n // All state changes have been done at this point, can proceed to the external calls.\n // This follows the checks-effects-interactions pattern to mitigate potential reentrancy attacks.\n if (token == UniversalTokenLib.ETH_ADDRESS) {\n // For ETH non-zero callValue is not allowed\n if (transaction.callValue != 0) revert NativeTokenCallValueNotSupported();\n // Check that the correct msg.value was sent\n if (msg.value != amount) revert MsgValueIncorrect();\n } else {\n // For ERC20s, we check that the correct msg.value was sent\n if (msg.value != transaction.callValue) revert MsgValueIncorrect();\n // We need to transfer the tokens from the Relayer to the recipient first before performing an\n // optional post-transfer arbitrary call.\n IERC20(token).safeTransferFrom(msg.sender, to, amount);\n }\n\n if (transaction.callParams.length != 0) {\n // Arbitrary call requested, perform it while supplying full msg.value to the recipient\n // Note: if token has a fee on transfers, the recipient will have received less than `amount`.\n // This is a very niche edge case and should be handled by the recipient contract.\n _checkedCallRecipient({recipient: to, token: token, amount: amount, callParams: transaction.callParams});\n } else if (msg.value != 0) {\n // No arbitrary call requested, but msg.value was sent. This is either a relay with ETH,\n // or a non-zero callValue request with an ERC20. In both cases, transfer the ETH to the recipient.\n Address.sendValue(payable(to), msg.value);\n }\n\n emit BridgeRelayed({\n transactionId: transactionId,\n relayer: relayer,\n to: to,\n originChainId: transaction.originChainId,\n originToken: transaction.originToken,\n destToken: transaction.destToken,\n originAmount: transaction.originAmount,\n destAmount: transaction.destAmount,\n chainGasAmount: transaction.callValue\n });\n }\n\n /// @inheritdoc IFastBridgeV2\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) public onlyRole(RELAYER_ROLE) {\n // update bridge tx status given proof provided\n if (bridgeTxDetails[transactionId].status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n bridgeTxDetails[transactionId].status = BridgeStatus.RELAYER_PROVED;\n bridgeTxDetails[transactionId].proofBlockTimestamp = uint40(block.timestamp);\n bridgeTxDetails[transactionId].proofBlockNumber = uint48(block.number);\n bridgeTxDetails[transactionId].proofRelayer = relayer;\n\n emit BridgeProofProvided(transactionId, relayer, destTxHash);\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes memory request, address to) public {\n bytes32 transactionId = keccak256(request);\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n\n // update bridge tx status if able to claim origin collateral\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n\n // if \"to\" is zero addr, permissionlessly send funds to proven relayer\n if (to == address(0)) {\n to = bridgeTxDetails[transactionId].proofRelayer;\n } else if (bridgeTxDetails[transactionId].proofRelayer != msg.sender) {\n revert SenderIncorrect();\n }\n\n if (_timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003c= DISPUTE_PERIOD) {\n revert DisputePeriodNotPassed();\n }\n\n bridgeTxDetails[transactionId].status = BridgeStatus.RELAYER_CLAIMED;\n\n // update protocol fees if origin fee amount exists\n if (transaction.originFeeAmount \u003e 0) protocolFees[transaction.originToken] += transaction.originFeeAmount;\n\n // transfer origin collateral less fee to specified address\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositClaimed(transactionId, bridgeTxDetails[transactionId].proofRelayer, to, token, amount);\n }\n\n function bridgeStatuses(bytes32 transactionId) public view returns (BridgeStatus status) {\n return bridgeTxDetails[transactionId].status;\n }\n\n function bridgeProofs(bytes32 transactionId) public view returns (uint96 timestamp, address relayer) {\n timestamp = bridgeTxDetails[transactionId].proofBlockTimestamp;\n relayer = bridgeTxDetails[transactionId].proofRelayer;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeRelays(bytes32 transactionId) public view returns (bool) {\n // has this transactionId been relayed?\n return bridgeRelayDetails[transactionId].relayer != address(0);\n }\n\n /// @inheritdoc IFastBridgeV2\n function getBridgeTransactionV2(bytes memory request) public pure returns (BridgeTransactionV2 memory) {\n return abi.decode(request, (BridgeTransactionV2));\n }\n\n /// @notice Pulls a requested token from the user to this contract.\n function _pullToken(address token, uint256 amount) internal returns (uint256 amountPulled) {\n if (token == UniversalTokenLib.ETH_ADDRESS) {\n // For ETH we just need to check that the supplied msg.value is correct\n if (amount != msg.value) revert MsgValueIncorrect();\n amountPulled = msg.value;\n } else {\n token.assertIsContract();\n // Record token balance before transfer\n amountPulled = IERC20(token).balanceOf(address(this));\n // Token needs to be pulled only if msg.value is zero\n // This way user can specify WETH as the origin asset\n IERC20(token).safeTransferFrom(msg.sender, address(this), amount);\n // Use the difference between the recorded balance and the current balance as the amountPulled\n amountPulled = IERC20(token).balanceOf(address(this)) - amountPulled;\n }\n }\n\n /// @notice Calls the Recipient's hook function with the specified callParams and performs\n /// all the necessary checks for the returned value.\n function _checkedCallRecipient(\n address recipient,\n address token,\n uint256 amount,\n bytes memory callParams\n )\n internal\n {\n bytes memory hookData =\n abi.encodeCall(IFastBridgeRecipient.fastBridgeTransferReceived, (token, amount, callParams));\n // This will bubble any revert messages from the hook function\n bytes memory returnData = Address.functionCallWithValue({target: recipient, data: hookData, value: msg.value});\n // Explicit revert if no return data at all\n if (returnData.length == 0) revert RecipientNoReturnValue();\n // Check that exactly a single return value was returned\n if (returnData.length != 32) revert RecipientIncorrectReturnValue();\n // Return value should be abi-encoded hook function selector\n if (bytes32(returnData) != bytes32(IFastBridgeRecipient.fastBridgeTransferReceived.selector)) {\n revert RecipientIncorrectReturnValue();\n }\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint40(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint40).max but\n /// proof.timestamp \u003c type(uint40).max via unchecked statement\n /// @param proofBlockTimestamp The bridge proof block timestamp\n /// @return delta Time delta since proof submitted\n function _timeSince(uint40 proofBlockTimestamp) internal view returns (uint256 delta) {\n unchecked {\n delta = uint40(block.timestamp) - proofBlockTimestamp;\n }\n }\n\n /// @notice Performs all the necessary checks for a bridge to happen.\n /// @dev There's no good way to refactor this function to reduce cyclomatic complexity due to\n /// the number of checks that need to be performed, so we skip the code-complexity rule here.\n // solhint-disable-next-line code-complexity\n function _validateBridgeParams(\n BridgeParams memory params,\n BridgeParamsV2 memory paramsV2,\n int256 exclusivityEndTime\n )\n internal\n view\n {\n // Check V1 (legacy) params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.sender == address(0) || params.to == address(0)) revert ZeroAddress();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n // Check V2 params\n if (paramsV2.callParams.length \u003e MAX_CALL_PARAMS_LENGTH) revert CallParamsLengthAboveMax();\n if (paramsV2.callValue != 0 \u0026\u0026 params.destToken == UniversalTokenLib.ETH_ADDRESS) {\n revert NativeTokenCallValueNotSupported();\n }\n // exclusivityEndTime must be in range (0 .. params.deadline]\n if (exclusivityEndTime \u003c= 0 || exclusivityEndTime \u003e int256(params.deadline)) {\n revert ExclusivityParamsIncorrect();\n }\n }\n\n /// @notice Performs all the necessary checks for a relay to happen.\n function _validateRelayParams(\n BridgeTransactionV2 memory transaction,\n bytes32 transactionId,\n address relayer\n )\n internal\n view\n {\n if (relayer == address(0)) revert ZeroAddress();\n // Check if the transaction has already been relayed\n if (bridgeRelays(transactionId)) revert TransactionRelayed();\n if (transaction.destChainId != uint32(block.chainid)) revert ChainIncorrect();\n // Check the deadline for relay to happen\n if (block.timestamp \u003e transaction.deadline) revert DeadlineExceeded();\n // Check the exclusivity period, if it is still ongoing\n // forgefmt: disable-next-item\n if (\n transaction.exclusivityRelayer != address(0) \u0026\u0026\n transaction.exclusivityRelayer != relayer \u0026\u0026\n block.timestamp \u003c= transaction.exclusivityEndTime\n ) {\n revert ExclusivityPeriodNotPassed();\n }\n }\n}\n","language":"Solidity","languageVersion":"0.8.24","compilerVersion":"0.8.24","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"","srcMapRuntime":"","abiDefinition":[{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"}],"userDoc":{"kind":"user","methods":{},"version":1},"developerDoc":{"details":"Implementation of the {IERC165} interface. Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check for the additional interface id that will be supported. For example: ```solidity function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId); } ```","kind":"dev","methods":{"supportsInterface(bytes4)":{"details":"See {IERC165-supportsInterface}."}},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"bytes4\",\"name\":\"interfaceId\",\"type\":\"bytes4\"}],\"name\":\"supportsInterface\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"}],\"devdoc\":{\"details\":\"Implementation of the {IERC165} interface. Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check for the additional interface id that will be supported. For example: ```solidity function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId); } ```\",\"kind\":\"dev\",\"methods\":{\"supportsInterface(bytes4)\":{\"details\":\"See {IERC165-supportsInterface}.\"}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeV2.sol\":\"ERC165\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeV2.sol\":{\"keccak256\":\"0x7cd0f885e80e2bdaa638bc32ae7af7d2e248f99ce4b354c217d0f0f7d7302e0a\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://7ccf28df0bd7b4606986585acd8622ed9b4e81379690061bb66088f0a2270af1\",\"dweb:/ipfs/QmTf7HNdHZkK6vmx8ZgewycQEb72oLD9nPwBpsM5reMstQ\"]}},\"version\":1}"},"hashes":{"supportsInterface(bytes4)":"01ffc9a7"}},"solidity/FastBridgeV2.sol:EnumerableSet":{"code":"0x60566037600b82828239805160001a607314602a57634e487b7160e01b600052600060045260246000fd5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600080fdfea2646970667358221220c93e0a4d209c73a0e712af3f8fe75c461fc5f2c8421cf7a3112f43749245c31a64736f6c63430008180033","runtime-code":"0x73000000000000000000000000000000000000000030146080604052600080fdfea2646970667358221220c93e0a4d209c73a0e712af3f8fe75c461fc5f2c8421cf7a3112f43749245c31a64736f6c63430008180033","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.24 ^0.8.0 ^0.8.20;\n\n// contracts/interfaces/IAdmin.sol\n\ninterface IAdmin {\n // ============ Events ============\n\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n event ChainGasAmountUpdated(uint256 oldChainGasAmount, uint256 newChainGasAmount);\n\n // ============ Methods ============\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n\n function setChainGasAmount(uint256 newChainGasAmount) external;\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IFastBridgeRecipient.sol\n\ninterface IFastBridgeRecipient {\n function fastBridgeTransferReceived(\n address token,\n uint256 amount,\n bytes memory callParams\n )\n external\n payable\n returns (bytes4);\n}\n\n// contracts/interfaces/IFastBridgeV2Errors.sol\n\ninterface IFastBridgeV2Errors {\n error AmountIncorrect();\n error CallParamsLengthAboveMax();\n error ChainIncorrect();\n error ExclusivityParamsIncorrect();\n error MsgValueIncorrect();\n error NativeTokenCallValueNotSupported();\n error SenderIncorrect();\n error StatusIncorrect();\n error ZeroAddress();\n\n error RecipientIncorrectReturnValue();\n error RecipientNoReturnValue();\n\n error DeadlineExceeded();\n error DeadlineNotExceeded();\n error DeadlineTooShort();\n error DisputePeriodNotPassed();\n error DisputePeriodPassed();\n error ExclusivityPeriodNotPassed();\n\n error TransactionRelayed();\n}\n\n// contracts/libs/Errors.sol\n\nerror DeadlineExceeded();\nerror DeadlineNotExceeded();\nerror DeadlineTooShort();\nerror InsufficientOutputAmount();\n\nerror MsgValueIncorrect();\nerror PoolNotFound();\nerror TokenAddressMismatch();\nerror TokenNotContract();\nerror TokenNotETH();\nerror TokensIdentical();\n\nerror ChainIncorrect();\nerror AmountIncorrect();\nerror ZeroAddress();\n\nerror DisputePeriodNotPassed();\nerror DisputePeriodPassed();\nerror SenderIncorrect();\nerror StatusIncorrect();\nerror TransactionIdIncorrect();\nerror TransactionRelayed();\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// contracts/interfaces/IFastBridgeV2.sol\n\ninterface IFastBridgeV2 is IFastBridge {\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n struct BridgeTxDetails {\n BridgeStatus status;\n uint40 proofBlockTimestamp;\n uint48 proofBlockNumber;\n address proofRelayer;\n }\n\n struct BridgeRelay {\n uint48 blockNumber;\n uint48 blockTimestamp;\n address relayer;\n }\n\n /// @notice New params introduced in the FastBridgeV2.\n /// We are passing fields from the older BridgeParams struct outside of this struct\n /// for backwards compatibility.\n /// Note: quoteRelayer and quoteExclusivitySeconds are either both zero (indicating no exclusivity)\n /// or both non-zero (indicating exclusivity for the given period).\n /// Note: callValue \u003e 0 can NOT be used with destToken = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE (ETH_ADDRESS)\n /// @param quoteRelayer Relayer that provided the quote for the transaction\n /// @param quoteExclusivitySeconds Period of time the quote relayer is guaranteed exclusivity after user's deposit\n /// @param quoteId Unique quote identifier used for tracking the quote\n /// @param callValue ETH value to send to the recipient (if any)\n /// @param callParams Parameters for the arbitrary call to the destination recipient (if any)\n struct BridgeParamsV2 {\n address quoteRelayer;\n int256 quoteExclusivitySeconds;\n bytes quoteId;\n uint256 callValue;\n bytes callParams;\n }\n\n /// @notice Updated bridge transaction struct to include parameters introduced in FastBridgeV2.\n /// Note: only `exclusivityRelayer` can fill such a transaction until `exclusivityEndTime`.\n /// TODO: consider changing the encoding scheme to prevent spending extra gas on decoding.\n struct BridgeTransactionV2 {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n uint256 callValue; // ETH value to send to the recipient (if any) - replaces V1's sendChainGas flag\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n address exclusivityRelayer;\n uint256 exclusivityEndTime;\n bytes callParams;\n }\n\n event BridgeQuoteDetails(bytes32 indexed transactionId, bytes quoteId);\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability\n /// to provide temporary exclusivity fill rights for the quote relayer.\n /// @param params The parameters required to bridge\n /// @param paramsV2 The parameters for exclusivity fill rights (optional, can be left empty)\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function relay(bytes memory request, address relayer) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param transactionId The transaction id associated with the encoded bridge transaction to prove\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital.\n /// @notice Can only send funds to the relayer address on the proof.\n /// @param request The encoded bridge transaction to claim on origin chain\n function claim(bytes memory request) external;\n /// @notice Checks if a transaction has been relayed\n /// @param transactionId The ID of the transaction to check\n /// @return True if the transaction has been relayed, false otherwise\n function bridgeRelays(bytes32 transactionId) external view returns (bool);\n\n /// @notice Returns the status of a bridge transaction\n /// @param transactionId The ID of the bridge transaction\n /// @return BridgeStatus Status of the bridge transaction\n function bridgeStatuses(bytes32 transactionId) external view returns (BridgeStatus);\n\n /// @notice Returns the timestamp and relayer of a bridge proof\n /// @param transactionId The ID of the bridge transaction\n /// @return timestamp The timestamp of the bridge proof\n /// @return relayer The relayer address of the bridge proof\n function bridgeProofs(bytes32 transactionId) external view returns (uint96 timestamp, address relayer);\n\n /// @notice Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\n /// @param request The bridge request to decode\n function getBridgeTransactionV2(bytes memory request) external view returns (BridgeTransactionV2 memory);\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// contracts/libs/UniversalToken.sol\n\nlibrary UniversalTokenLib {\n using SafeERC20 for IERC20;\n\n address internal constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Transfers tokens to the given account. Reverts if transfer is not successful.\n /// @dev This might trigger fallback, if ETH is transferred to the contract.\n /// Make sure this can not lead to reentrancy attacks.\n function universalTransfer(address token, address to, uint256 value) internal {\n // Don't do anything, if need to send tokens to this address\n if (to == address(this)) return;\n // Don't do anything, if trying to send zero value\n if (value == 0) return;\n if (token == ETH_ADDRESS) {\n /// @dev Note: this can potentially lead to executing code in `to`.\n // solhint-disable-next-line avoid-low-level-calls\n (bool success,) = to.call{value: value}(\"\");\n require(success, \"ETH transfer failed\");\n } else {\n IERC20(token).safeTransfer(to, value);\n }\n }\n\n /// @notice Issues an infinite allowance to the spender, if the current allowance is insufficient\n /// to spend the given amount.\n function universalApproveInfinity(address token, address spender, uint256 amountToSpend) internal {\n // ETH Chad doesn't require your approval\n if (token == ETH_ADDRESS) return;\n // No-op if allowance is already sufficient\n uint256 allowance = IERC20(token).allowance(address(this), spender);\n if (allowance \u003e= amountToSpend) return;\n // Otherwise, reset approval to 0 and set to max allowance\n if (allowance \u003e 0) IERC20(token).safeDecreaseAllowance(spender, allowance);\n IERC20(token).safeIncreaseAllowance(spender, type(uint256).max);\n }\n\n /// @notice Returns the balance of the given token (or native ETH) for the given account.\n function universalBalanceOf(address token, address account) internal view returns (uint256) {\n if (token == ETH_ADDRESS) {\n return account.balance;\n } else {\n return IERC20(token).balanceOf(account);\n }\n }\n\n /// @dev Checks that token is a contract and not ETH_ADDRESS.\n function assertIsContract(address token) internal view {\n // Check that ETH_ADDRESS was not used (in case this is a predeploy on any of the chains)\n if (token == UniversalTokenLib.ETH_ADDRESS) revert TokenNotContract();\n // Check that token is not an EOA\n if (token.code.length == 0) revert TokenNotContract();\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/Admin.sol\n\ncontract Admin is IAdmin, AccessControlEnumerable {\n using UniversalTokenLib for address;\n\n bytes32 public constant RELAYER_ROLE = keccak256(\"RELAYER_ROLE\");\n bytes32 public constant REFUNDER_ROLE = keccak256(\"REFUNDER_ROLE\");\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n uint256 public constant FEE_BPS = 1e6;\n uint256 public constant FEE_RATE_MAX = 0.01e6; // max 1% on origin amount\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Chain gas amount to forward as rebate if requested\n uint256 public chainGasAmount;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n }\n\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n require(newFeeRate \u003c= FEE_RATE_MAX, \"newFeeRate \u003e max\");\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n token.universalTransfer(recipient, feeAmount);\n emit FeesSwept(token, recipient, feeAmount);\n }\n\n function setChainGasAmount(uint256 newChainGasAmount) external onlyRole(GOVERNOR_ROLE) {\n uint256 oldChainGasAmount = chainGasAmount;\n chainGasAmount = newChainGasAmount;\n emit ChainGasAmountUpdated(oldChainGasAmount, newChainGasAmount);\n }\n}\n\n// contracts/FastBridgeV2.sol\n\n/// @notice FastBridgeV2 is a contract for bridging tokens across chains.\ncontract FastBridgeV2 is Admin, IFastBridgeV2, IFastBridgeV2Errors {\n using SafeERC20 for IERC20;\n using UniversalTokenLib for address;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Delay for a transaction after which it could be permisionlessly refunded\n uint256 public constant REFUND_DELAY = 7 days;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n /// @notice Maximum length of accepted callParams\n uint256 public constant MAX_CALL_PARAMS_LENGTH = 2 ** 16 - 1;\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeTxDetails) public bridgeTxDetails;\n /// @notice Relay details on destination chain\n mapping(bytes32 =\u003e BridgeRelay) public bridgeRelayDetails;\n /// @notice Unique bridge nonces tracked per originSender\n mapping(address =\u003e uint256) public senderNonces;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Replaced by senderNonces\n uint256 public immutable nonce = 0;\n /// @notice the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n bridge({\n params: params,\n paramsV2: BridgeParamsV2({\n quoteRelayer: address(0),\n quoteExclusivitySeconds: 0,\n quoteId: bytes(\"\"),\n callValue: 0,\n callParams: bytes(\"\")\n })\n });\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes memory request) external payable {\n relay({request: request, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes memory request, bytes32 destTxHash) external {\n prove({transactionId: keccak256(request), destTxHash: destTxHash, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridgeV2\n function claim(bytes memory request) external {\n claim({request: request, to: address(0)});\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003e DISPUTE_PERIOD) {\n revert DisputePeriodPassed();\n }\n\n // @dev relayer gets slashed effectively if dest relay has gone thru\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n bridgeTxDetails[transactionId].proofRelayer = address(0);\n bridgeTxDetails[transactionId].proofBlockTimestamp = 0;\n bridgeTxDetails[transactionId].proofBlockNumber = 0;\n\n emit BridgeProofDisputed(transactionId, msg.sender);\n }\n\n /// @inheritdoc IFastBridge\n function refund(bytes memory request) external {\n bytes32 transactionId = keccak256(request);\n\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n\n if (bridgeTxDetails[transactionId].status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n\n if (hasRole(REFUNDER_ROLE, msg.sender)) {\n // Refunder can refund if deadline has passed\n if (block.timestamp \u003c= transaction.deadline) revert DeadlineNotExceeded();\n } else {\n // Permissionless refund is allowed after REFUND_DELAY\n if (block.timestamp \u003c= transaction.deadline + REFUND_DELAY) revert DeadlineNotExceeded();\n }\n\n // if all checks passed, set to REFUNDED status\n bridgeTxDetails[transactionId].status = BridgeStatus.REFUNDED;\n\n // transfer origin collateral back to original sender\n address to = transaction.originSender;\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount + transaction.originFeeAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (bridgeTxDetails[transactionId].proofRelayer != relayer) revert SenderIncorrect();\n return _timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n /// @dev This method is added to achieve backwards compatibility with decoding requests into V1 structs:\n /// - `callValue` is partially reported as a zero/non-zero flag\n /// - `callParams` is ignored\n /// In order to process all kinds of requests use getBridgeTransactionV2 instead.\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory) {\n // Try decoding into V2 struct first. This will revert if V1 struct is passed\n try this.getBridgeTransactionV2(request) returns (BridgeTransactionV2 memory txV2) {\n // Note: we entirely ignore the callParams field, as it was not present in V1\n return BridgeTransaction({\n originChainId: txV2.originChainId,\n destChainId: txV2.destChainId,\n originSender: txV2.originSender,\n destRecipient: txV2.destRecipient,\n originToken: txV2.originToken,\n destToken: txV2.destToken,\n originAmount: txV2.originAmount,\n destAmount: txV2.destAmount,\n originFeeAmount: txV2.originFeeAmount,\n sendChainGas: txV2.callValue != 0,\n deadline: txV2.deadline,\n nonce: txV2.nonce\n });\n } catch {\n // Fallback to V1 struct\n return abi.decode(request, (BridgeTransaction));\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) public payable {\n int256 exclusivityEndTime = int256(block.timestamp) + paramsV2.quoteExclusivitySeconds;\n _validateBridgeParams(params, paramsV2, exclusivityEndTime);\n\n // transfer tokens to bridge contract\n /// @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _pullToken(params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n\n // set status to requested\n bytes memory request = abi.encode(\n BridgeTransactionV2({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n callValue: paramsV2.callValue,\n deadline: params.deadline,\n nonce: senderNonces[params.sender]++, // increment nonce on every bridge\n exclusivityRelayer: paramsV2.quoteRelayer,\n // We checked exclusivityEndTime to be in range (0 .. params.deadline] above, so can safely cast\n exclusivityEndTime: uint256(exclusivityEndTime),\n callParams: paramsV2.callParams\n })\n );\n bytes32 transactionId = keccak256(request);\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n\n emit BridgeRequested({\n transactionId: transactionId,\n sender: params.sender,\n request: request,\n destChainId: params.dstChainId,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n sendChainGas: paramsV2.callValue != 0\n });\n emit BridgeQuoteDetails(transactionId, paramsV2.quoteId);\n }\n\n /// @inheritdoc IFastBridgeV2\n function relay(bytes memory request, address relayer) public payable {\n bytes32 transactionId = keccak256(request);\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n _validateRelayParams(transaction, transactionId, relayer);\n // mark bridge transaction as relayed\n bridgeRelayDetails[transactionId] =\n BridgeRelay({blockNumber: uint48(block.number), blockTimestamp: uint48(block.timestamp), relayer: relayer});\n\n // transfer tokens to recipient on destination chain and do an arbitrary call if requested\n address to = transaction.destRecipient;\n address token = transaction.destToken;\n uint256 amount = transaction.destAmount;\n\n // All state changes have been done at this point, can proceed to the external calls.\n // This follows the checks-effects-interactions pattern to mitigate potential reentrancy attacks.\n if (token == UniversalTokenLib.ETH_ADDRESS) {\n // For ETH non-zero callValue is not allowed\n if (transaction.callValue != 0) revert NativeTokenCallValueNotSupported();\n // Check that the correct msg.value was sent\n if (msg.value != amount) revert MsgValueIncorrect();\n } else {\n // For ERC20s, we check that the correct msg.value was sent\n if (msg.value != transaction.callValue) revert MsgValueIncorrect();\n // We need to transfer the tokens from the Relayer to the recipient first before performing an\n // optional post-transfer arbitrary call.\n IERC20(token).safeTransferFrom(msg.sender, to, amount);\n }\n\n if (transaction.callParams.length != 0) {\n // Arbitrary call requested, perform it while supplying full msg.value to the recipient\n // Note: if token has a fee on transfers, the recipient will have received less than `amount`.\n // This is a very niche edge case and should be handled by the recipient contract.\n _checkedCallRecipient({recipient: to, token: token, amount: amount, callParams: transaction.callParams});\n } else if (msg.value != 0) {\n // No arbitrary call requested, but msg.value was sent. This is either a relay with ETH,\n // or a non-zero callValue request with an ERC20. In both cases, transfer the ETH to the recipient.\n Address.sendValue(payable(to), msg.value);\n }\n\n emit BridgeRelayed({\n transactionId: transactionId,\n relayer: relayer,\n to: to,\n originChainId: transaction.originChainId,\n originToken: transaction.originToken,\n destToken: transaction.destToken,\n originAmount: transaction.originAmount,\n destAmount: transaction.destAmount,\n chainGasAmount: transaction.callValue\n });\n }\n\n /// @inheritdoc IFastBridgeV2\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) public onlyRole(RELAYER_ROLE) {\n // update bridge tx status given proof provided\n if (bridgeTxDetails[transactionId].status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n bridgeTxDetails[transactionId].status = BridgeStatus.RELAYER_PROVED;\n bridgeTxDetails[transactionId].proofBlockTimestamp = uint40(block.timestamp);\n bridgeTxDetails[transactionId].proofBlockNumber = uint48(block.number);\n bridgeTxDetails[transactionId].proofRelayer = relayer;\n\n emit BridgeProofProvided(transactionId, relayer, destTxHash);\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes memory request, address to) public {\n bytes32 transactionId = keccak256(request);\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n\n // update bridge tx status if able to claim origin collateral\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n\n // if \"to\" is zero addr, permissionlessly send funds to proven relayer\n if (to == address(0)) {\n to = bridgeTxDetails[transactionId].proofRelayer;\n } else if (bridgeTxDetails[transactionId].proofRelayer != msg.sender) {\n revert SenderIncorrect();\n }\n\n if (_timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003c= DISPUTE_PERIOD) {\n revert DisputePeriodNotPassed();\n }\n\n bridgeTxDetails[transactionId].status = BridgeStatus.RELAYER_CLAIMED;\n\n // update protocol fees if origin fee amount exists\n if (transaction.originFeeAmount \u003e 0) protocolFees[transaction.originToken] += transaction.originFeeAmount;\n\n // transfer origin collateral less fee to specified address\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositClaimed(transactionId, bridgeTxDetails[transactionId].proofRelayer, to, token, amount);\n }\n\n function bridgeStatuses(bytes32 transactionId) public view returns (BridgeStatus status) {\n return bridgeTxDetails[transactionId].status;\n }\n\n function bridgeProofs(bytes32 transactionId) public view returns (uint96 timestamp, address relayer) {\n timestamp = bridgeTxDetails[transactionId].proofBlockTimestamp;\n relayer = bridgeTxDetails[transactionId].proofRelayer;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeRelays(bytes32 transactionId) public view returns (bool) {\n // has this transactionId been relayed?\n return bridgeRelayDetails[transactionId].relayer != address(0);\n }\n\n /// @inheritdoc IFastBridgeV2\n function getBridgeTransactionV2(bytes memory request) public pure returns (BridgeTransactionV2 memory) {\n return abi.decode(request, (BridgeTransactionV2));\n }\n\n /// @notice Pulls a requested token from the user to this contract.\n function _pullToken(address token, uint256 amount) internal returns (uint256 amountPulled) {\n if (token == UniversalTokenLib.ETH_ADDRESS) {\n // For ETH we just need to check that the supplied msg.value is correct\n if (amount != msg.value) revert MsgValueIncorrect();\n amountPulled = msg.value;\n } else {\n token.assertIsContract();\n // Record token balance before transfer\n amountPulled = IERC20(token).balanceOf(address(this));\n // Token needs to be pulled only if msg.value is zero\n // This way user can specify WETH as the origin asset\n IERC20(token).safeTransferFrom(msg.sender, address(this), amount);\n // Use the difference between the recorded balance and the current balance as the amountPulled\n amountPulled = IERC20(token).balanceOf(address(this)) - amountPulled;\n }\n }\n\n /// @notice Calls the Recipient's hook function with the specified callParams and performs\n /// all the necessary checks for the returned value.\n function _checkedCallRecipient(\n address recipient,\n address token,\n uint256 amount,\n bytes memory callParams\n )\n internal\n {\n bytes memory hookData =\n abi.encodeCall(IFastBridgeRecipient.fastBridgeTransferReceived, (token, amount, callParams));\n // This will bubble any revert messages from the hook function\n bytes memory returnData = Address.functionCallWithValue({target: recipient, data: hookData, value: msg.value});\n // Explicit revert if no return data at all\n if (returnData.length == 0) revert RecipientNoReturnValue();\n // Check that exactly a single return value was returned\n if (returnData.length != 32) revert RecipientIncorrectReturnValue();\n // Return value should be abi-encoded hook function selector\n if (bytes32(returnData) != bytes32(IFastBridgeRecipient.fastBridgeTransferReceived.selector)) {\n revert RecipientIncorrectReturnValue();\n }\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint40(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint40).max but\n /// proof.timestamp \u003c type(uint40).max via unchecked statement\n /// @param proofBlockTimestamp The bridge proof block timestamp\n /// @return delta Time delta since proof submitted\n function _timeSince(uint40 proofBlockTimestamp) internal view returns (uint256 delta) {\n unchecked {\n delta = uint40(block.timestamp) - proofBlockTimestamp;\n }\n }\n\n /// @notice Performs all the necessary checks for a bridge to happen.\n /// @dev There's no good way to refactor this function to reduce cyclomatic complexity due to\n /// the number of checks that need to be performed, so we skip the code-complexity rule here.\n // solhint-disable-next-line code-complexity\n function _validateBridgeParams(\n BridgeParams memory params,\n BridgeParamsV2 memory paramsV2,\n int256 exclusivityEndTime\n )\n internal\n view\n {\n // Check V1 (legacy) params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.sender == address(0) || params.to == address(0)) revert ZeroAddress();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n // Check V2 params\n if (paramsV2.callParams.length \u003e MAX_CALL_PARAMS_LENGTH) revert CallParamsLengthAboveMax();\n if (paramsV2.callValue != 0 \u0026\u0026 params.destToken == UniversalTokenLib.ETH_ADDRESS) {\n revert NativeTokenCallValueNotSupported();\n }\n // exclusivityEndTime must be in range (0 .. params.deadline]\n if (exclusivityEndTime \u003c= 0 || exclusivityEndTime \u003e int256(params.deadline)) {\n revert ExclusivityParamsIncorrect();\n }\n }\n\n /// @notice Performs all the necessary checks for a relay to happen.\n function _validateRelayParams(\n BridgeTransactionV2 memory transaction,\n bytes32 transactionId,\n address relayer\n )\n internal\n view\n {\n if (relayer == address(0)) revert ZeroAddress();\n // Check if the transaction has already been relayed\n if (bridgeRelays(transactionId)) revert TransactionRelayed();\n if (transaction.destChainId != uint32(block.chainid)) revert ChainIncorrect();\n // Check the deadline for relay to happen\n if (block.timestamp \u003e transaction.deadline) revert DeadlineExceeded();\n // Check the exclusivity period, if it is still ongoing\n // forgefmt: disable-next-item\n if (\n transaction.exclusivityRelayer != address(0) \u0026\u0026\n transaction.exclusivityRelayer != relayer \u0026\u0026\n block.timestamp \u003c= transaction.exclusivityEndTime\n ) {\n revert ExclusivityPeriodNotPassed();\n }\n }\n}\n","language":"Solidity","languageVersion":"0.8.24","compilerVersion":"0.8.24","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"25827:11640:0:-:0;;;;;;;;;;;;;;;-1:-1:-1;;;25827:11640:0;;;;;;;;;;;;;;;;;","srcMapRuntime":"25827:11640:0:-:0;;;;;;;;","abiDefinition":[],"userDoc":{"kind":"user","methods":{},"version":1},"developerDoc":{"details":"Library for managing https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive types. Sets have the following properties: - Elements are added, removed, and checked for existence in constant time (O(1)). - Elements are enumerated in O(n). No guarantees are made on the ordering. ```solidity contract Example { // Add the library methods using EnumerableSet for EnumerableSet.AddressSet; // Declare a set state variable EnumerableSet.AddressSet private mySet; } ``` As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`) and `uint256` (`UintSet`) are supported. [WARNING] ==== Trying to delete such a structure from storage will likely result in data corruption, rendering the structure unusable. See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info. In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an array of EnumerableSet. ====","kind":"dev","methods":{},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[],\"devdoc\":{\"details\":\"Library for managing https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive types. Sets have the following properties: - Elements are added, removed, and checked for existence in constant time (O(1)). - Elements are enumerated in O(n). No guarantees are made on the ordering. ```solidity contract Example { // Add the library methods using EnumerableSet for EnumerableSet.AddressSet; // Declare a set state variable EnumerableSet.AddressSet private mySet; } ``` As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`) and `uint256` (`UintSet`) are supported. [WARNING] ==== Trying to delete such a structure from storage will likely result in data corruption, rendering the structure unusable. See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info. In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an array of EnumerableSet. ====\",\"kind\":\"dev\",\"methods\":{},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeV2.sol\":\"EnumerableSet\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeV2.sol\":{\"keccak256\":\"0x7cd0f885e80e2bdaa638bc32ae7af7d2e248f99ce4b354c217d0f0f7d7302e0a\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://7ccf28df0bd7b4606986585acd8622ed9b4e81379690061bb66088f0a2270af1\",\"dweb:/ipfs/QmTf7HNdHZkK6vmx8ZgewycQEb72oLD9nPwBpsM5reMstQ\"]}},\"version\":1}"},"hashes":{}},"solidity/FastBridgeV2.sol:FastBridgeV2":{"code":"0x60c060405260006080523480156200001657600080fd5b5060405162003e5a38038062003e5a833981016040819052620000399162000199565b806200004760008262000054565b50504360a05250620001c4565b60008062000063848462000091565b90508015620000885760008481526001602052604090206200008690846200013f565b505b90505b92915050565b6000828152602081815260408083206001600160a01b038516845290915281205460ff1662000136576000838152602081815260408083206001600160a01b03861684529091529020805460ff19166001179055620000ed3390565b6001600160a01b0316826001600160a01b0316847f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45060016200008b565b5060006200008b565b600062000088836001600160a01b038416600081815260018301602052604081205462000136575081546001818101845560008481526020808220909301849055845484825282860190935260409020919091556200008b565b600060208284031215620001ac57600080fd5b81516001600160a01b03811681146200008857600080fd5b60805160a051613c70620001ea6000396000610802015260006108a30152613c706000f3fe6080604052600436106102fd5760003560e01c806391ad50391161018f578063b13aa2d6116100e1578063ca15c8731161008a578063dcf844a711610064578063dcf844a714610a50578063df36bb1314610a7d578063e00a83e014610a9357600080fd5b8063ca15c873146109dc578063ccc57490146109fc578063d547741f14610a3057600080fd5b8063bfc7c607116100bb578063bfc7c6071461091c578063c63ff8dd1461092f578063c79371b11461094f57600080fd5b8063b13aa2d6146108c5578063b250fe6b146108e5578063bf333f2c1461090557600080fd5b8063a3ec191a11610143578063ac11fb1a1161011d578063ac11fb1a14610844578063add98c7014610871578063affed0e01461089157600080fd5b8063a3ec191a146107f0578063a5bbe22b14610607578063aa9641ab1461082457600080fd5b8063926d7d7f11610174578063926d7d7f146107945780639c9545f0146107c8578063a217fddf146107db57600080fd5b806391ad5039146106d057806391d148541461075057600080fd5b806341fcb6121161025357806363787e52116101fc578063886d36ff116101d6578063886d36ff146106655780638f0d6f17146106855780639010d07c1461069857600080fd5b806363787e521461058c578063820688d5146106075780638379a24f1461061d57600080fd5b80635960ccf21161022d5780635960ccf21461050b5780635aa6ccba1461053f5780635eb7d9461461056c57600080fd5b806341fcb612146104c257806345851694146104e257806358f85880146104f557600080fd5b806318e4357d116102b5578063295710ff1161028f578063295710ff146104555780632f2ff15d1461048257806336568abe146104a257600080fd5b806318e4357d146103ee578063190da5951461040e578063248a9ca31461042557600080fd5b8063051287bc116102e6578063051287bc1461037957806306f333f2146103b65780630f5f6ed7146103d857600080fd5b806301ffc9a71461030257806303ed0ee514610337575b600080fd5b34801561030e57600080fd5b5061032261031d366004612ee8565b610aa9565b60405190151581526020015b60405180910390f35b34801561034357600080fd5b5061036b7f043c983c49d46f0e102151eaf8085d4a2e6571d5df2d47b013f39bddfd4a639d81565b60405190815260200161032e565b34801561038557600080fd5b506103a9610394366004612f2a565b60009081526005602052604090205460ff1690565b60405161032e9190612fad565b3480156103c257600080fd5b506103d66103d1366004612fdb565b610b05565b005b3480156103e457600080fd5b5061036b61271081565b3480156103fa57600080fd5b506103d6610409366004613014565b610bcc565b34801561041a57600080fd5b5061036b62093a8081565b34801561043157600080fd5b5061036b610440366004612f2a565b60009081526020819052604090206001015490565b34801561046157600080fd5b5061036b61047036600461304d565b60076020526000908152604090205481565b34801561048e57600080fd5b506103d661049d36600461306a565b610d39565b3480156104ae57600080fd5b506103d66104bd36600461306a565b610d64565b3480156104ce57600080fd5b506103d66104dd366004613202565b610db0565b6103d66104f0366004613322565b611026565b34801561050157600080fd5b5061036b60025481565b34801561051757600080fd5b5061036b7fdb9556138406326f00296e13ea2ad7db24ba82381212d816b1a40c23b466b32781565b34801561054b57600080fd5b5061055f61055a36600461333f565b611083565b60405161032e91906133cc565b34801561057857600080fd5b506103d661058736600461333f565b611149565b34801561059857600080fd5b506105f76105a7366004612f2a565b60056020526000908152604090205460ff811690610100810464ffffffffff16906601000000000000810465ffffffffffff16906c0100000000000000000000000090046001600160a01b031684565b60405161032e94939291906134e1565b34801561061357600080fd5b5061036b61070881565b34801561062957600080fd5b50610322610638366004612f2a565b6000908152600660205260409020546c0100000000000000000000000090046001600160a01b0316151590565b34801561067157600080fd5b506103d6610680366004613522565b61133e565b6103d661069336600461333f565b611354565b3480156106a457600080fd5b506106b86106b3366004613567565b61135e565b6040516001600160a01b03909116815260200161032e565b3480156106dc57600080fd5b506107246106eb366004612f2a565b600090815260056020526040902054610100810464ffffffffff16916c010000000000000000000000009091046001600160a01b031690565b604080516bffffffffffffffffffffffff90931683526001600160a01b0390911660208301520161032e565b34801561075c57600080fd5b5061032261076b36600461306a565b6000918252602082815260408084206001600160a01b0393909316845291905290205460ff1690565b3480156107a057600080fd5b5061036b7fe2b7fb3b832174769106daebcfd6d1970523240dda11281102db9363b83b0dc481565b6103d66107d6366004613202565b61137d565b3480156107e757600080fd5b5061036b600081565b3480156107fc57600080fd5b5061036b7f000000000000000000000000000000000000000000000000000000000000000081565b34801561083057600080fd5b5061032261083f36600461306a565b61162e565b34801561085057600080fd5b5061086461085f36600461333f565b611719565b60405161032e9190613589565b34801561087d57600080fd5b506103d661088c366004612f2a565b6118d1565b34801561089d57600080fd5b5061036b7f000000000000000000000000000000000000000000000000000000000000000081565b3480156108d157600080fd5b506103d66108e0366004612f2a565b6119f3565b3480156108f157600080fd5b506103d6610900366004612f2a565b611ad5565b34801561091157600080fd5b5061036b620f424081565b6103d661092a36600461366f565b611b3d565b34801561093b57600080fd5b506103d661094a36600461333f565b611dbf565b34801561095b57600080fd5b506109ae61096a366004612f2a565b60066020526000908152604090205465ffffffffffff8082169166010000000000008104909116906c0100000000000000000000000090046001600160a01b031683565b6040805165ffffffffffff94851681529390921660208401526001600160a01b03169082015260600161032e565b3480156109e857600080fd5b5061036b6109f7366004612f2a565b611dca565b348015610a0857600080fd5b5061036b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f5581565b348015610a3c57600080fd5b506103d6610a4b36600461306a565b611de1565b348015610a5c57600080fd5b5061036b610a6b36600461304d565b60036020526000908152604090205481565b348015610a8957600080fd5b5061036b61ffff81565b348015610a9f57600080fd5b5061036b60045481565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f5a05180f000000000000000000000000000000000000000000000000000000001480610aff5750610aff82611e06565b92915050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f55610b2f81611e9d565b6001600160a01b03831660009081526003602052604081205490819003610b565750505050565b6001600160a01b038416600081815260036020526040812055610b7a908483611ea7565b604080516001600160a01b038087168252851660208201529081018290527f244e51bc38c1452fa8aaf487bcb4bca36c2baa3a5fbdb776b1eabd8dc6d277cd9060600160405180910390a1505b505050565b7fe2b7fb3b832174769106daebcfd6d1970523240dda11281102db9363b83b0dc4610bf681611e9d565b600160008581526005602052604090205460ff166004811115610c1b57610c1b612f43565b14610c52576040517f4145817200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600084815260056020908152604091829020805460027fffffffffffffffffffffffffffffffffffffffff0000000000000000000000009091166101004264ffffffffff16027fffffffffffffffffffffffffffffffffffffffff000000000000ffffffffffff161766010000000000004365ffffffffffff160217176bffffffffffffffffffffffff166c010000000000000000000000006001600160a01b0387169081029190911790915582518681529251909287927f4ac8af8a2cd87193d64dfc7a3b8d9923b714ec528b18725d080aa1299be0c5e492918290030190a350505050565b600082815260208190526040902060010154610d5481611e9d565b610d5e8383611fca565b50505050565b6001600160a01b0381163314610da6576040517f6697b23200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610bc78282611fff565b815160208301206000610dc284611083565b9050600260008381526005602052604090205460ff166004811115610de957610de9612f43565b14610e20576040517f4145817200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600160a01b038316610e5d576000828152600560205260409020546c0100000000000000000000000090046001600160a01b03169250610ebd565b6000828152600560205260409020546c0100000000000000000000000090046001600160a01b03163314610ebd576040517f4af43a9000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008281526005602052604090205461070890610100900464ffffffffff90811642031611610f18576040517f1992d0bd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600082815260056020526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016600317905561010081015115610f925761010081015160808201516001600160a01b031660009081526003602052604081208054909190610f8c90849061376c565b90915550505b608081015160c0820151610fb06001600160a01b0383168683611ea7565b6000848152600560209081526040918290205482516001600160a01b038681168252928101859052888316936c010000000000000000000000009092049092169187917f582211c35a2139ac3bbaac74663c6a1f56c6cbb658b41fe11fd45a82074ac678910160405180910390a4505050505050565b611080816040518060a0016040528060006001600160a01b03168152602001600081526020016040518060200160405280600081525081526020016000815260200160405180602001604052806000815250815250611b3d565b50565b611135604051806101e00160405280600063ffffffff168152602001600063ffffffff16815260200160006001600160a01b0316815260200160006001600160a01b0316815260200160006001600160a01b0316815260200160006001600160a01b0316815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160006001600160a01b0316815260200160008152602001606081525090565b81806020019051810190610aff91906137da565b80516020820120600061115b83611083565b9050600160008381526005602052604090205460ff16600481111561118257611182612f43565b146111b9576040517f4145817200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b3360009081527fd2043bf65931af3dbecf60d0db8f40e4160406d7beb00522f4200cf4944a1eb8602052604090205460ff161561123357806101400151421161122e576040517fe15ff9ea00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61127f565b62093a80816101400151611247919061376c565b421161127f576040517fe15ff9ea00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008281526005602052604080822080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166004179055820151608083015161010084015160c0850151929391926112d8919061376c565b90506112ee6001600160a01b0383168483611ea7565b604080516001600160a01b0384811682526020820184905285169187917fb4c55c0c9bc613519b920e88748090150b890a875d307f21bea7d4fb2e8bc958910160405180910390a3505050505050565b61135082805190602001208233610bcc565b5050565b611080813361137d565b6000828152600160205260408120611376908361202c565b9392505050565b81516020830120600061138f84611083565b905061139c818385612038565b604080516060808201835265ffffffffffff438116835242811660208085019182526001600160a01b03808a1686880190815260008a8152600690935296909120945185549251965182166c01000000000000000000000000026bffffffffffffffffffffffff9785166601000000000000027fffffffffffffffffffffffffffffffffffffffff000000000000000000000000909416919094161791909117949094161790915582015160a083015160e084015191929091907fffffffffffffffffffffffff1111111111111111111111111111111111111112908316016114fa57610120840151156114bc576040517f2598ad2e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8034146114f5576040517f81de0bf300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61154d565b8361012001513414611538576040517f81de0bf300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61154d6001600160a01b0383163385846121db565b6101c0840151511561156f5761156a838383876101c00151612257565b61157f565b341561157f5761157f83346123b6565b826001600160a01b0316866001600160a01b0316867ff8ae392d784b1ea5e8881bfa586d81abf07ef4f1e2fc75f7fe51c90f05199a5c876000015188608001518960a001518a60c001518b60e001518c610120015160405161161d9695949392919063ffffffff9690961686526001600160a01b0394851660208701529290931660408501526060840152608083019190915260a082015260c00190565b60405180910390a450505050505050565b6000600260008481526005602052604090205460ff16600481111561165557611655612f43565b1461168c576040517f4145817200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000838152600560205260409020546001600160a01b038381166c0100000000000000000000000090920416146116ef576040517f4af43a9000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b505060009081526005602052604090205461070861010090910464ffffffffff9081164203161190565b6040805161018081018252600080825260208201819052818301819052606082018190526080820181905260a0820181905260c0820181905260e0820181905261010082018190526101208201819052610140820181905261016082015290517f5aa6ccba0000000000000000000000000000000000000000000000000000000081523090635aa6ccba906117b290859060040161390f565b600060405180830381865afa9250505080156117f057506040513d6000823e601f3d908101601f191682016040526117ed91908101906137da565b60015b6118085781806020019051810190610aff919061392d565b604051806101800160405280826000015163ffffffff168152602001826020015163ffffffff16815260200182604001516001600160a01b0316815260200182606001516001600160a01b0316815260200182608001516001600160a01b031681526020018260a001516001600160a01b031681526020018260c0015181526020018260e001518152602001826101000151815260200182610120015160001415151581526020018261014001518152602001826101600151815250915050919050565b919050565b7f043c983c49d46f0e102151eaf8085d4a2e6571d5df2d47b013f39bddfd4a639d6118fb81611e9d565b600260008381526005602052604090205460ff16600481111561192057611920612f43565b14611957576040517f4145817200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008281526005602052604090205461070890610100900464ffffffffff90811642031611156119b3576040517f3e908aac00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000828152600560205260408082206001905551339184917f0695cf1d39b3055dcd0fe02d8b47eaf0d5a13e1996de925de59d0ef9b7f7fad49190a35050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f55611a1d81611e9d565b612710821115611a8e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f6e657746656552617465203e206d61780000000000000000000000000000000060448201526064015b60405180910390fd5b600280549083905560408051828152602081018590527f14914da2bf76024616fbe1859783fcd4dbddcb179b1f3a854949fbf920dcb95791015b60405180910390a1505050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f55611aff81611e9d565b600480549083905560408051828152602081018590527f5cf09b12f3f56b4c564d51b25b40360af6d795198adb61ae0806a36c294323fa9101611ac8565b6000816020015142611b4f91906139f9565b9050611b5c83838361247f565b6000611b7084606001518560a00151612704565b90506000806002541115611b9d57620f424060025483611b909190613a21565b611b9a9190613a38565b90505b611ba78183613a73565b91506000604051806101e001604052804663ffffffff168152602001876000015163ffffffff16815260200187602001516001600160a01b0316815260200187604001516001600160a01b0316815260200187606001516001600160a01b0316815260200187608001516001600160a01b031681526020018481526020018760c0015181526020018381526020018660600151815260200187610100015181526020016007600089602001516001600160a01b03166001600160a01b031681526020019081526020016000206000815480929190611c8490613a86565b91905055815260200186600001516001600160a01b031681526020018581526020018660800151815250604051602001611cbe91906133cc565b60408051808303601f1901815282825280516020808301919091206000818152600583529390932080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016600117905589015189516060808c015160808d015160c08e0151928d015195985095966001600160a01b039094169587957f120ea0364f36cdac7983bcfdd55270ca09d7f9b314a2ebc425a3b01ab1d6403a95611d72958b95909493928e9290151590613abe565b60405180910390a3807f3120e2bb59c86aca6890191a589a96af3662838efa374fbdcdf4c95bfe4a6c0e8760400151604051611dae919061390f565b60405180910390a250505050505050565b611080816000610db0565b6000818152600160205260408120610aff906128ad565b600082815260208190526040902060010154611dfc81611e9d565b610d5e8383611fff565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f7965db0b000000000000000000000000000000000000000000000000000000001480610aff57507f01ffc9a7000000000000000000000000000000000000000000000000000000007fffffffff00000000000000000000000000000000000000000000000000000000831614610aff565b61108081336128b7565b306001600160a01b03831603611ebc57505050565b80600003611ec957505050565b7fffffffffffffffffffffffff11111111111111111111111111111111111111126001600160a01b03841601611fb6576000826001600160a01b03168260405160006040518083038185875af1925050503d8060008114611f46576040519150601f19603f3d011682016040523d82523d6000602084013e611f4b565b606091505b5050905080610d5e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f455448207472616e73666572206661696c6564000000000000000000000000006044820152606401611a85565b610bc76001600160a01b0384168383612923565b600080611fd78484612954565b90508015611376576000848152600160205260409020611ff79084612a1c565b509392505050565b60008061200c8484612a31565b90508015611376576000848152600160205260409020611ff79084612ad2565b60006113768383612ae7565b6001600160a01b038116612078576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000828152600660205260409020546c0100000000000000000000000090046001600160a01b0316156120d7576040517fbef7bb7d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b4663ffffffff16836020015163ffffffff1614612120576040517f7029fdf900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b82610140015142111561215f576040517f559895a300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6101808301516001600160a01b0316158015906121935750806001600160a01b03168361018001516001600160a01b031614155b80156121a45750826101a001514211155b15610bc7576040517f14be123200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040516001600160a01b038481166024830152838116604483015260648201839052610d5e9186918216906323b872dd906084015b604051602081830303815290604052915060e01b6020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8381831617835250505050612b11565b600083838360405160240161226e93929190613b14565b60408051601f198184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f461e0c2100000000000000000000000000000000000000000000000000000000179052905060006122d5868334612b8d565b90508051600003612312576040517f1a95ad2600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b805160201461234d576040517ff3725cca00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f461e0c210000000000000000000000000000000000000000000000000000000061237782613b45565b146123ae576040517ff3725cca00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b505050505050565b804710156123f2576040517fcd786059000000000000000000000000000000000000000000000000000000008152306004820152602401611a85565b6000826001600160a01b03168260405160006040518083038185875af1925050503d806000811461243f576040519150601f19603f3d011682016040523d82523d6000602084013e612444565b606091505b5050905080610bc7576040517f1425ea4200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b46836000015163ffffffff16036124c2576040517f7029fdf900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60a083015115806124d5575060c0830151155b1561250c576040517fe38820c800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60208301516001600160a01b03161580612531575060408301516001600160a01b0316155b15612568576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60608301516001600160a01b0316158061258d575060808301516001600160a01b0316155b156125c4576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6125d06107084261376c565b836101000151101561260e576040517f04b7fcc800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61ffff826080015151111561264f576040517ffbe24d4900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b606082015115801590612682575060808301516001600160a01b031673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee145b156126b9576040517f2598ad2e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000811315806126cd575082610100015181135b15610bc7576040517f352807b900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60007fffffffffffffffffffffffff11111111111111111111111111111111111111126001600160a01b038416016127765734821461276f576040517f81de0bf300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5034610aff565b612788836001600160a01b0316612c43565b6040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201526001600160a01b038416906370a0823190602401602060405180830381865afa1580156127e5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128099190613b8a565b90506128206001600160a01b0384163330856121db565b6040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015281906001600160a01b038516906370a0823190602401602060405180830381865afa15801561287f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128a39190613b8a565b6113769190613a73565b6000610aff825490565b6000828152602081815260408083206001600160a01b038516845290915290205460ff16611350576040517fe2517d3f0000000000000000000000000000000000000000000000000000000081526001600160a01b038216600482015260248101839052604401611a85565b6040516001600160a01b03838116602483015260448201839052610bc791859182169063a9059cbb90606401612210565b6000828152602081815260408083206001600160a01b038516845290915281205460ff16612a14576000838152602081815260408083206001600160a01b0386168452909152902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790556129cc3390565b6001600160a01b0316826001600160a01b0316847f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a4506001610aff565b506000610aff565b6000611376836001600160a01b038416612ce9565b6000828152602081815260408083206001600160a01b038516845290915281205460ff1615612a14576000838152602081815260408083206001600160a01b038616808552925280832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016905551339286917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a4506001610aff565b6000611376836001600160a01b038416612d30565b6000826000018281548110612afe57612afe613ba3565b9060005260206000200154905092915050565b6000612b266001600160a01b03841683612e23565b90508051600014158015612b4b575080806020019051810190612b499190613bd2565b155b15610bc7576040517f5274afe70000000000000000000000000000000000000000000000000000000081526001600160a01b0384166004820152602401611a85565b606081471015612bcb576040517fcd786059000000000000000000000000000000000000000000000000000000008152306004820152602401611a85565b600080856001600160a01b03168486604051612be79190613bef565b60006040518083038185875af1925050503d8060008114612c24576040519150601f19603f3d011682016040523d82523d6000602084013e612c29565b606091505b5091509150612c39868383612e31565b9695505050505050565b7fffffffffffffffffffffffff11111111111111111111111111111111111111126001600160a01b03821601612ca5576040517f7f523fe800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b806001600160a01b03163b600003611080576040517f7f523fe800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000818152600183016020526040812054612a1457508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155610aff565b60008181526001830160205260408120548015612e19576000612d54600183613a73565b8554909150600090612d6890600190613a73565b9050808214612dcd576000866000018281548110612d8857612d88613ba3565b9060005260206000200154905080876000018481548110612dab57612dab613ba3565b6000918252602080832090910192909255918252600188019052604090208390555b8554869080612dde57612dde613c0b565b600190038181906000526020600020016000905590558560010160008681526020019081526020016000206000905560019350505050610aff565b6000915050610aff565b606061137683836000612b8d565b606082612e4657612e4182612ea6565b611376565b8151158015612e5d57506001600160a01b0384163b155b15612e9f576040517f9996b3150000000000000000000000000000000000000000000000000000000081526001600160a01b0385166004820152602401611a85565b5080611376565b805115612eb65780518082602001fd5b6040517f1425ea4200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600060208284031215612efa57600080fd5b81357fffffffff000000000000000000000000000000000000000000000000000000008116811461137657600080fd5b600060208284031215612f3c57600080fd5b5035919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b60058110612fa9577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b9052565b60208101610aff8284612f72565b6001600160a01b038116811461108057600080fd5b80356118cc81612fbb565b60008060408385031215612fee57600080fd5b8235612ff981612fbb565b9150602083013561300981612fbb565b809150509250929050565b60008060006060848603121561302957600080fd5b8335925060208401359150604084013561304281612fbb565b809150509250925092565b60006020828403121561305f57600080fd5b813561137681612fbb565b6000806040838503121561307d57600080fd5b82359150602083013561300981612fbb565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051610120810167ffffffffffffffff811182821017156130e2576130e261308f565b60405290565b60405160a0810167ffffffffffffffff811182821017156130e2576130e261308f565b6040516101e0810167ffffffffffffffff811182821017156130e2576130e261308f565b604051610180810167ffffffffffffffff811182821017156130e2576130e261308f565b604051601f8201601f1916810167ffffffffffffffff8111828210171561317c5761317c61308f565b604052919050565b600067ffffffffffffffff82111561319e5761319e61308f565b50601f01601f191660200190565b600082601f8301126131bd57600080fd5b81356131d06131cb82613184565b613153565b8181528460208386010111156131e557600080fd5b816020850160208301376000918101602001919091529392505050565b6000806040838503121561321557600080fd5b823567ffffffffffffffff81111561322c57600080fd5b613238858286016131ac565b925050602083013561300981612fbb565b63ffffffff8116811461108057600080fd5b80356118cc81613249565b801515811461108057600080fd5b80356118cc81613266565b6000610120828403121561329257600080fd5b61329a6130be565b90506132a58261325b565b81526132b360208301612fd0565b60208201526132c460408301612fd0565b60408201526132d560608301612fd0565b60608201526132e660808301612fd0565b608082015260a082013560a082015260c082013560c082015261330b60e08301613274565b60e082015261010080830135818301525092915050565b6000610120828403121561333557600080fd5b611376838361327f565b60006020828403121561335157600080fd5b813567ffffffffffffffff81111561336857600080fd5b613374848285016131ac565b949350505050565b60005b8381101561339757818101518382015260200161337f565b50506000910152565b600081518084526133b881602086016020860161337c565b601f01601f19169290920160200192915050565b602081526133e360208201835163ffffffff169052565b600060208301516133fc604084018263ffffffff169052565b5060408301516001600160a01b03811660608401525060608301516001600160a01b03811660808401525060808301516001600160a01b03811660a08401525060a08301516001600160a01b03811660c08401525060c083015160e08381019190915283015161010080840191909152830151610120808401919091528301516101408084019190915283015161016080840191909152830151610180808401919091528301516101a06134ba818501836001600160a01b03169052565b8401516101c0848101919091528401516101e08085015290506133746102008401826133a0565b608081016134ef8287612f72565b64ffffffffff8516602083015265ffffffffffff841660408301526001600160a01b038316606083015295945050505050565b6000806040838503121561353557600080fd5b823567ffffffffffffffff81111561354c57600080fd5b613558858286016131ac565b95602094909401359450505050565b6000806040838503121561357a57600080fd5b50508035926020909101359150565b815163ffffffff168152610180810160208301516135af602084018263ffffffff169052565b5060408301516135ca60408401826001600160a01b03169052565b5060608301516135e560608401826001600160a01b03169052565b50608083015161360060808401826001600160a01b03169052565b5060a083015161361b60a08401826001600160a01b03169052565b5060c083015160c083015260e083015160e0830152610100808401518184015250610120808401516136508285018215159052565b5050610140838101519083015261016092830151929091019190915290565b600080610140838503121561368357600080fd5b61368d848461327f565b915061012083013567ffffffffffffffff808211156136ab57600080fd5b9084019060a082870312156136bf57600080fd5b6136c76130e8565b82356136d281612fbb565b8152602083810135908201526040830135828111156136f057600080fd5b6136fc888286016131ac565b6040830152506060830135606082015260808301358281111561371e57600080fd5b61372a888286016131ac565b6080830152508093505050509250929050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b80820180821115610aff57610aff61373d565b80516118cc81613249565b80516118cc81612fbb565b600082601f8301126137a657600080fd5b81516137b46131cb82613184565b8181528460208386010111156137c957600080fd5b61337482602083016020870161337c565b6000602082840312156137ec57600080fd5b815167ffffffffffffffff8082111561380457600080fd5b908301906101e0828603121561381957600080fd5b61382161310b565b61382a8361377f565b81526138386020840161377f565b60208201526138496040840161378a565b604082015261385a6060840161378a565b606082015261386b6080840161378a565b608082015261387c60a0840161378a565b60a082015260c0838101519082015260e0808401519082015261010080840151908201526101208084015190820152610140808401519082015261016080840151908201526101806138cf81850161378a565b908201526101a083810151908201526101c080840151838111156138f257600080fd5b6138fe88828701613795565b918301919091525095945050505050565b60208152600061137660208301846133a0565b80516118cc81613266565b6000610180828403121561394057600080fd5b61394861312f565b6139518361377f565b815261395f6020840161377f565b60208201526139706040840161378a565b60408201526139816060840161378a565b60608201526139926080840161378a565b60808201526139a360a0840161378a565b60a082015260c083015160c082015260e083015160e08201526101008084015181830152506101206139d6818501613922565b908201526101408381015190820152610160928301519281019290925250919050565b8082018281126000831280158216821582161715613a1957613a1961373d565b505092915050565b8082028115828204841417610aff57610aff61373d565b600082613a6e577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b81810381811115610aff57610aff61373d565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203613ab757613ab761373d565b5060010190565b60e081526000613ad160e083018a6133a0565b63ffffffff989098166020830152506001600160a01b039586166040820152939094166060840152608083019190915260a082015290151560c090910152919050565b6001600160a01b0384168152826020820152606060408201526000613b3c60608301846133a0565b95945050505050565b80516020808301519190811015613b84577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8160200360031b1b821691505b50919050565b600060208284031215613b9c57600080fd5b5051919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b600060208284031215613be457600080fd5b815161137681613266565b60008251613c0181846020870161337c565b9190910192915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fdfea2646970667358221220a3680a17873f4c46b682e496f075c28aef799dbfefc67679607c7ecbffed72b464736f6c63430008180033","runtime-code":"0x6080604052600436106102fd5760003560e01c806391ad50391161018f578063b13aa2d6116100e1578063ca15c8731161008a578063dcf844a711610064578063dcf844a714610a50578063df36bb1314610a7d578063e00a83e014610a9357600080fd5b8063ca15c873146109dc578063ccc57490146109fc578063d547741f14610a3057600080fd5b8063bfc7c607116100bb578063bfc7c6071461091c578063c63ff8dd1461092f578063c79371b11461094f57600080fd5b8063b13aa2d6146108c5578063b250fe6b146108e5578063bf333f2c1461090557600080fd5b8063a3ec191a11610143578063ac11fb1a1161011d578063ac11fb1a14610844578063add98c7014610871578063affed0e01461089157600080fd5b8063a3ec191a146107f0578063a5bbe22b14610607578063aa9641ab1461082457600080fd5b8063926d7d7f11610174578063926d7d7f146107945780639c9545f0146107c8578063a217fddf146107db57600080fd5b806391ad5039146106d057806391d148541461075057600080fd5b806341fcb6121161025357806363787e52116101fc578063886d36ff116101d6578063886d36ff146106655780638f0d6f17146106855780639010d07c1461069857600080fd5b806363787e521461058c578063820688d5146106075780638379a24f1461061d57600080fd5b80635960ccf21161022d5780635960ccf21461050b5780635aa6ccba1461053f5780635eb7d9461461056c57600080fd5b806341fcb612146104c257806345851694146104e257806358f85880146104f557600080fd5b806318e4357d116102b5578063295710ff1161028f578063295710ff146104555780632f2ff15d1461048257806336568abe146104a257600080fd5b806318e4357d146103ee578063190da5951461040e578063248a9ca31461042557600080fd5b8063051287bc116102e6578063051287bc1461037957806306f333f2146103b65780630f5f6ed7146103d857600080fd5b806301ffc9a71461030257806303ed0ee514610337575b600080fd5b34801561030e57600080fd5b5061032261031d366004612ee8565b610aa9565b60405190151581526020015b60405180910390f35b34801561034357600080fd5b5061036b7f043c983c49d46f0e102151eaf8085d4a2e6571d5df2d47b013f39bddfd4a639d81565b60405190815260200161032e565b34801561038557600080fd5b506103a9610394366004612f2a565b60009081526005602052604090205460ff1690565b60405161032e9190612fad565b3480156103c257600080fd5b506103d66103d1366004612fdb565b610b05565b005b3480156103e457600080fd5b5061036b61271081565b3480156103fa57600080fd5b506103d6610409366004613014565b610bcc565b34801561041a57600080fd5b5061036b62093a8081565b34801561043157600080fd5b5061036b610440366004612f2a565b60009081526020819052604090206001015490565b34801561046157600080fd5b5061036b61047036600461304d565b60076020526000908152604090205481565b34801561048e57600080fd5b506103d661049d36600461306a565b610d39565b3480156104ae57600080fd5b506103d66104bd36600461306a565b610d64565b3480156104ce57600080fd5b506103d66104dd366004613202565b610db0565b6103d66104f0366004613322565b611026565b34801561050157600080fd5b5061036b60025481565b34801561051757600080fd5b5061036b7fdb9556138406326f00296e13ea2ad7db24ba82381212d816b1a40c23b466b32781565b34801561054b57600080fd5b5061055f61055a36600461333f565b611083565b60405161032e91906133cc565b34801561057857600080fd5b506103d661058736600461333f565b611149565b34801561059857600080fd5b506105f76105a7366004612f2a565b60056020526000908152604090205460ff811690610100810464ffffffffff16906601000000000000810465ffffffffffff16906c0100000000000000000000000090046001600160a01b031684565b60405161032e94939291906134e1565b34801561061357600080fd5b5061036b61070881565b34801561062957600080fd5b50610322610638366004612f2a565b6000908152600660205260409020546c0100000000000000000000000090046001600160a01b0316151590565b34801561067157600080fd5b506103d6610680366004613522565b61133e565b6103d661069336600461333f565b611354565b3480156106a457600080fd5b506106b86106b3366004613567565b61135e565b6040516001600160a01b03909116815260200161032e565b3480156106dc57600080fd5b506107246106eb366004612f2a565b600090815260056020526040902054610100810464ffffffffff16916c010000000000000000000000009091046001600160a01b031690565b604080516bffffffffffffffffffffffff90931683526001600160a01b0390911660208301520161032e565b34801561075c57600080fd5b5061032261076b36600461306a565b6000918252602082815260408084206001600160a01b0393909316845291905290205460ff1690565b3480156107a057600080fd5b5061036b7fe2b7fb3b832174769106daebcfd6d1970523240dda11281102db9363b83b0dc481565b6103d66107d6366004613202565b61137d565b3480156107e757600080fd5b5061036b600081565b3480156107fc57600080fd5b5061036b7f000000000000000000000000000000000000000000000000000000000000000081565b34801561083057600080fd5b5061032261083f36600461306a565b61162e565b34801561085057600080fd5b5061086461085f36600461333f565b611719565b60405161032e9190613589565b34801561087d57600080fd5b506103d661088c366004612f2a565b6118d1565b34801561089d57600080fd5b5061036b7f000000000000000000000000000000000000000000000000000000000000000081565b3480156108d157600080fd5b506103d66108e0366004612f2a565b6119f3565b3480156108f157600080fd5b506103d6610900366004612f2a565b611ad5565b34801561091157600080fd5b5061036b620f424081565b6103d661092a36600461366f565b611b3d565b34801561093b57600080fd5b506103d661094a36600461333f565b611dbf565b34801561095b57600080fd5b506109ae61096a366004612f2a565b60066020526000908152604090205465ffffffffffff8082169166010000000000008104909116906c0100000000000000000000000090046001600160a01b031683565b6040805165ffffffffffff94851681529390921660208401526001600160a01b03169082015260600161032e565b3480156109e857600080fd5b5061036b6109f7366004612f2a565b611dca565b348015610a0857600080fd5b5061036b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f5581565b348015610a3c57600080fd5b506103d6610a4b36600461306a565b611de1565b348015610a5c57600080fd5b5061036b610a6b36600461304d565b60036020526000908152604090205481565b348015610a8957600080fd5b5061036b61ffff81565b348015610a9f57600080fd5b5061036b60045481565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f5a05180f000000000000000000000000000000000000000000000000000000001480610aff5750610aff82611e06565b92915050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f55610b2f81611e9d565b6001600160a01b03831660009081526003602052604081205490819003610b565750505050565b6001600160a01b038416600081815260036020526040812055610b7a908483611ea7565b604080516001600160a01b038087168252851660208201529081018290527f244e51bc38c1452fa8aaf487bcb4bca36c2baa3a5fbdb776b1eabd8dc6d277cd9060600160405180910390a1505b505050565b7fe2b7fb3b832174769106daebcfd6d1970523240dda11281102db9363b83b0dc4610bf681611e9d565b600160008581526005602052604090205460ff166004811115610c1b57610c1b612f43565b14610c52576040517f4145817200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600084815260056020908152604091829020805460027fffffffffffffffffffffffffffffffffffffffff0000000000000000000000009091166101004264ffffffffff16027fffffffffffffffffffffffffffffffffffffffff000000000000ffffffffffff161766010000000000004365ffffffffffff160217176bffffffffffffffffffffffff166c010000000000000000000000006001600160a01b0387169081029190911790915582518681529251909287927f4ac8af8a2cd87193d64dfc7a3b8d9923b714ec528b18725d080aa1299be0c5e492918290030190a350505050565b600082815260208190526040902060010154610d5481611e9d565b610d5e8383611fca565b50505050565b6001600160a01b0381163314610da6576040517f6697b23200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610bc78282611fff565b815160208301206000610dc284611083565b9050600260008381526005602052604090205460ff166004811115610de957610de9612f43565b14610e20576040517f4145817200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600160a01b038316610e5d576000828152600560205260409020546c0100000000000000000000000090046001600160a01b03169250610ebd565b6000828152600560205260409020546c0100000000000000000000000090046001600160a01b03163314610ebd576040517f4af43a9000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008281526005602052604090205461070890610100900464ffffffffff90811642031611610f18576040517f1992d0bd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600082815260056020526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016600317905561010081015115610f925761010081015160808201516001600160a01b031660009081526003602052604081208054909190610f8c90849061376c565b90915550505b608081015160c0820151610fb06001600160a01b0383168683611ea7565b6000848152600560209081526040918290205482516001600160a01b038681168252928101859052888316936c010000000000000000000000009092049092169187917f582211c35a2139ac3bbaac74663c6a1f56c6cbb658b41fe11fd45a82074ac678910160405180910390a4505050505050565b611080816040518060a0016040528060006001600160a01b03168152602001600081526020016040518060200160405280600081525081526020016000815260200160405180602001604052806000815250815250611b3d565b50565b611135604051806101e00160405280600063ffffffff168152602001600063ffffffff16815260200160006001600160a01b0316815260200160006001600160a01b0316815260200160006001600160a01b0316815260200160006001600160a01b0316815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160006001600160a01b0316815260200160008152602001606081525090565b81806020019051810190610aff91906137da565b80516020820120600061115b83611083565b9050600160008381526005602052604090205460ff16600481111561118257611182612f43565b146111b9576040517f4145817200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b3360009081527fd2043bf65931af3dbecf60d0db8f40e4160406d7beb00522f4200cf4944a1eb8602052604090205460ff161561123357806101400151421161122e576040517fe15ff9ea00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61127f565b62093a80816101400151611247919061376c565b421161127f576040517fe15ff9ea00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008281526005602052604080822080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166004179055820151608083015161010084015160c0850151929391926112d8919061376c565b90506112ee6001600160a01b0383168483611ea7565b604080516001600160a01b0384811682526020820184905285169187917fb4c55c0c9bc613519b920e88748090150b890a875d307f21bea7d4fb2e8bc958910160405180910390a3505050505050565b61135082805190602001208233610bcc565b5050565b611080813361137d565b6000828152600160205260408120611376908361202c565b9392505050565b81516020830120600061138f84611083565b905061139c818385612038565b604080516060808201835265ffffffffffff438116835242811660208085019182526001600160a01b03808a1686880190815260008a8152600690935296909120945185549251965182166c01000000000000000000000000026bffffffffffffffffffffffff9785166601000000000000027fffffffffffffffffffffffffffffffffffffffff000000000000000000000000909416919094161791909117949094161790915582015160a083015160e084015191929091907fffffffffffffffffffffffff1111111111111111111111111111111111111112908316016114fa57610120840151156114bc576040517f2598ad2e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8034146114f5576040517f81de0bf300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61154d565b8361012001513414611538576040517f81de0bf300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61154d6001600160a01b0383163385846121db565b6101c0840151511561156f5761156a838383876101c00151612257565b61157f565b341561157f5761157f83346123b6565b826001600160a01b0316866001600160a01b0316867ff8ae392d784b1ea5e8881bfa586d81abf07ef4f1e2fc75f7fe51c90f05199a5c876000015188608001518960a001518a60c001518b60e001518c610120015160405161161d9695949392919063ffffffff9690961686526001600160a01b0394851660208701529290931660408501526060840152608083019190915260a082015260c00190565b60405180910390a450505050505050565b6000600260008481526005602052604090205460ff16600481111561165557611655612f43565b1461168c576040517f4145817200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000838152600560205260409020546001600160a01b038381166c0100000000000000000000000090920416146116ef576040517f4af43a9000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b505060009081526005602052604090205461070861010090910464ffffffffff9081164203161190565b6040805161018081018252600080825260208201819052818301819052606082018190526080820181905260a0820181905260c0820181905260e0820181905261010082018190526101208201819052610140820181905261016082015290517f5aa6ccba0000000000000000000000000000000000000000000000000000000081523090635aa6ccba906117b290859060040161390f565b600060405180830381865afa9250505080156117f057506040513d6000823e601f3d908101601f191682016040526117ed91908101906137da565b60015b6118085781806020019051810190610aff919061392d565b604051806101800160405280826000015163ffffffff168152602001826020015163ffffffff16815260200182604001516001600160a01b0316815260200182606001516001600160a01b0316815260200182608001516001600160a01b031681526020018260a001516001600160a01b031681526020018260c0015181526020018260e001518152602001826101000151815260200182610120015160001415151581526020018261014001518152602001826101600151815250915050919050565b919050565b7f043c983c49d46f0e102151eaf8085d4a2e6571d5df2d47b013f39bddfd4a639d6118fb81611e9d565b600260008381526005602052604090205460ff16600481111561192057611920612f43565b14611957576040517f4145817200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008281526005602052604090205461070890610100900464ffffffffff90811642031611156119b3576040517f3e908aac00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000828152600560205260408082206001905551339184917f0695cf1d39b3055dcd0fe02d8b47eaf0d5a13e1996de925de59d0ef9b7f7fad49190a35050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f55611a1d81611e9d565b612710821115611a8e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f6e657746656552617465203e206d61780000000000000000000000000000000060448201526064015b60405180910390fd5b600280549083905560408051828152602081018590527f14914da2bf76024616fbe1859783fcd4dbddcb179b1f3a854949fbf920dcb95791015b60405180910390a1505050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f55611aff81611e9d565b600480549083905560408051828152602081018590527f5cf09b12f3f56b4c564d51b25b40360af6d795198adb61ae0806a36c294323fa9101611ac8565b6000816020015142611b4f91906139f9565b9050611b5c83838361247f565b6000611b7084606001518560a00151612704565b90506000806002541115611b9d57620f424060025483611b909190613a21565b611b9a9190613a38565b90505b611ba78183613a73565b91506000604051806101e001604052804663ffffffff168152602001876000015163ffffffff16815260200187602001516001600160a01b0316815260200187604001516001600160a01b0316815260200187606001516001600160a01b0316815260200187608001516001600160a01b031681526020018481526020018760c0015181526020018381526020018660600151815260200187610100015181526020016007600089602001516001600160a01b03166001600160a01b031681526020019081526020016000206000815480929190611c8490613a86565b91905055815260200186600001516001600160a01b031681526020018581526020018660800151815250604051602001611cbe91906133cc565b60408051808303601f1901815282825280516020808301919091206000818152600583529390932080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016600117905589015189516060808c015160808d015160c08e0151928d015195985095966001600160a01b039094169587957f120ea0364f36cdac7983bcfdd55270ca09d7f9b314a2ebc425a3b01ab1d6403a95611d72958b95909493928e9290151590613abe565b60405180910390a3807f3120e2bb59c86aca6890191a589a96af3662838efa374fbdcdf4c95bfe4a6c0e8760400151604051611dae919061390f565b60405180910390a250505050505050565b611080816000610db0565b6000818152600160205260408120610aff906128ad565b600082815260208190526040902060010154611dfc81611e9d565b610d5e8383611fff565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f7965db0b000000000000000000000000000000000000000000000000000000001480610aff57507f01ffc9a7000000000000000000000000000000000000000000000000000000007fffffffff00000000000000000000000000000000000000000000000000000000831614610aff565b61108081336128b7565b306001600160a01b03831603611ebc57505050565b80600003611ec957505050565b7fffffffffffffffffffffffff11111111111111111111111111111111111111126001600160a01b03841601611fb6576000826001600160a01b03168260405160006040518083038185875af1925050503d8060008114611f46576040519150601f19603f3d011682016040523d82523d6000602084013e611f4b565b606091505b5050905080610d5e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f455448207472616e73666572206661696c6564000000000000000000000000006044820152606401611a85565b610bc76001600160a01b0384168383612923565b600080611fd78484612954565b90508015611376576000848152600160205260409020611ff79084612a1c565b509392505050565b60008061200c8484612a31565b90508015611376576000848152600160205260409020611ff79084612ad2565b60006113768383612ae7565b6001600160a01b038116612078576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000828152600660205260409020546c0100000000000000000000000090046001600160a01b0316156120d7576040517fbef7bb7d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b4663ffffffff16836020015163ffffffff1614612120576040517f7029fdf900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b82610140015142111561215f576040517f559895a300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6101808301516001600160a01b0316158015906121935750806001600160a01b03168361018001516001600160a01b031614155b80156121a45750826101a001514211155b15610bc7576040517f14be123200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040516001600160a01b038481166024830152838116604483015260648201839052610d5e9186918216906323b872dd906084015b604051602081830303815290604052915060e01b6020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8381831617835250505050612b11565b600083838360405160240161226e93929190613b14565b60408051601f198184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f461e0c2100000000000000000000000000000000000000000000000000000000179052905060006122d5868334612b8d565b90508051600003612312576040517f1a95ad2600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b805160201461234d576040517ff3725cca00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f461e0c210000000000000000000000000000000000000000000000000000000061237782613b45565b146123ae576040517ff3725cca00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b505050505050565b804710156123f2576040517fcd786059000000000000000000000000000000000000000000000000000000008152306004820152602401611a85565b6000826001600160a01b03168260405160006040518083038185875af1925050503d806000811461243f576040519150601f19603f3d011682016040523d82523d6000602084013e612444565b606091505b5050905080610bc7576040517f1425ea4200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b46836000015163ffffffff16036124c2576040517f7029fdf900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60a083015115806124d5575060c0830151155b1561250c576040517fe38820c800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60208301516001600160a01b03161580612531575060408301516001600160a01b0316155b15612568576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60608301516001600160a01b0316158061258d575060808301516001600160a01b0316155b156125c4576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6125d06107084261376c565b836101000151101561260e576040517f04b7fcc800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61ffff826080015151111561264f576040517ffbe24d4900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b606082015115801590612682575060808301516001600160a01b031673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee145b156126b9576040517f2598ad2e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000811315806126cd575082610100015181135b15610bc7576040517f352807b900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60007fffffffffffffffffffffffff11111111111111111111111111111111111111126001600160a01b038416016127765734821461276f576040517f81de0bf300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5034610aff565b612788836001600160a01b0316612c43565b6040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201526001600160a01b038416906370a0823190602401602060405180830381865afa1580156127e5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128099190613b8a565b90506128206001600160a01b0384163330856121db565b6040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015281906001600160a01b038516906370a0823190602401602060405180830381865afa15801561287f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128a39190613b8a565b6113769190613a73565b6000610aff825490565b6000828152602081815260408083206001600160a01b038516845290915290205460ff16611350576040517fe2517d3f0000000000000000000000000000000000000000000000000000000081526001600160a01b038216600482015260248101839052604401611a85565b6040516001600160a01b03838116602483015260448201839052610bc791859182169063a9059cbb90606401612210565b6000828152602081815260408083206001600160a01b038516845290915281205460ff16612a14576000838152602081815260408083206001600160a01b0386168452909152902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790556129cc3390565b6001600160a01b0316826001600160a01b0316847f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a4506001610aff565b506000610aff565b6000611376836001600160a01b038416612ce9565b6000828152602081815260408083206001600160a01b038516845290915281205460ff1615612a14576000838152602081815260408083206001600160a01b038616808552925280832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016905551339286917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a4506001610aff565b6000611376836001600160a01b038416612d30565b6000826000018281548110612afe57612afe613ba3565b9060005260206000200154905092915050565b6000612b266001600160a01b03841683612e23565b90508051600014158015612b4b575080806020019051810190612b499190613bd2565b155b15610bc7576040517f5274afe70000000000000000000000000000000000000000000000000000000081526001600160a01b0384166004820152602401611a85565b606081471015612bcb576040517fcd786059000000000000000000000000000000000000000000000000000000008152306004820152602401611a85565b600080856001600160a01b03168486604051612be79190613bef565b60006040518083038185875af1925050503d8060008114612c24576040519150601f19603f3d011682016040523d82523d6000602084013e612c29565b606091505b5091509150612c39868383612e31565b9695505050505050565b7fffffffffffffffffffffffff11111111111111111111111111111111111111126001600160a01b03821601612ca5576040517f7f523fe800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b806001600160a01b03163b600003611080576040517f7f523fe800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000818152600183016020526040812054612a1457508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155610aff565b60008181526001830160205260408120548015612e19576000612d54600183613a73565b8554909150600090612d6890600190613a73565b9050808214612dcd576000866000018281548110612d8857612d88613ba3565b9060005260206000200154905080876000018481548110612dab57612dab613ba3565b6000918252602080832090910192909255918252600188019052604090208390555b8554869080612dde57612dde613c0b565b600190038181906000526020600020016000905590558560010160008681526020019081526020016000206000905560019350505050610aff565b6000915050610aff565b606061137683836000612b8d565b606082612e4657612e4182612ea6565b611376565b8151158015612e5d57506001600160a01b0384163b155b15612e9f576040517f9996b3150000000000000000000000000000000000000000000000000000000081526001600160a01b0385166004820152602401611a85565b5080611376565b805115612eb65780518082602001fd5b6040517f1425ea4200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600060208284031215612efa57600080fd5b81357fffffffff000000000000000000000000000000000000000000000000000000008116811461137657600080fd5b600060208284031215612f3c57600080fd5b5035919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b60058110612fa9577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b9052565b60208101610aff8284612f72565b6001600160a01b038116811461108057600080fd5b80356118cc81612fbb565b60008060408385031215612fee57600080fd5b8235612ff981612fbb565b9150602083013561300981612fbb565b809150509250929050565b60008060006060848603121561302957600080fd5b8335925060208401359150604084013561304281612fbb565b809150509250925092565b60006020828403121561305f57600080fd5b813561137681612fbb565b6000806040838503121561307d57600080fd5b82359150602083013561300981612fbb565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051610120810167ffffffffffffffff811182821017156130e2576130e261308f565b60405290565b60405160a0810167ffffffffffffffff811182821017156130e2576130e261308f565b6040516101e0810167ffffffffffffffff811182821017156130e2576130e261308f565b604051610180810167ffffffffffffffff811182821017156130e2576130e261308f565b604051601f8201601f1916810167ffffffffffffffff8111828210171561317c5761317c61308f565b604052919050565b600067ffffffffffffffff82111561319e5761319e61308f565b50601f01601f191660200190565b600082601f8301126131bd57600080fd5b81356131d06131cb82613184565b613153565b8181528460208386010111156131e557600080fd5b816020850160208301376000918101602001919091529392505050565b6000806040838503121561321557600080fd5b823567ffffffffffffffff81111561322c57600080fd5b613238858286016131ac565b925050602083013561300981612fbb565b63ffffffff8116811461108057600080fd5b80356118cc81613249565b801515811461108057600080fd5b80356118cc81613266565b6000610120828403121561329257600080fd5b61329a6130be565b90506132a58261325b565b81526132b360208301612fd0565b60208201526132c460408301612fd0565b60408201526132d560608301612fd0565b60608201526132e660808301612fd0565b608082015260a082013560a082015260c082013560c082015261330b60e08301613274565b60e082015261010080830135818301525092915050565b6000610120828403121561333557600080fd5b611376838361327f565b60006020828403121561335157600080fd5b813567ffffffffffffffff81111561336857600080fd5b613374848285016131ac565b949350505050565b60005b8381101561339757818101518382015260200161337f565b50506000910152565b600081518084526133b881602086016020860161337c565b601f01601f19169290920160200192915050565b602081526133e360208201835163ffffffff169052565b600060208301516133fc604084018263ffffffff169052565b5060408301516001600160a01b03811660608401525060608301516001600160a01b03811660808401525060808301516001600160a01b03811660a08401525060a08301516001600160a01b03811660c08401525060c083015160e08381019190915283015161010080840191909152830151610120808401919091528301516101408084019190915283015161016080840191909152830151610180808401919091528301516101a06134ba818501836001600160a01b03169052565b8401516101c0848101919091528401516101e08085015290506133746102008401826133a0565b608081016134ef8287612f72565b64ffffffffff8516602083015265ffffffffffff841660408301526001600160a01b038316606083015295945050505050565b6000806040838503121561353557600080fd5b823567ffffffffffffffff81111561354c57600080fd5b613558858286016131ac565b95602094909401359450505050565b6000806040838503121561357a57600080fd5b50508035926020909101359150565b815163ffffffff168152610180810160208301516135af602084018263ffffffff169052565b5060408301516135ca60408401826001600160a01b03169052565b5060608301516135e560608401826001600160a01b03169052565b50608083015161360060808401826001600160a01b03169052565b5060a083015161361b60a08401826001600160a01b03169052565b5060c083015160c083015260e083015160e0830152610100808401518184015250610120808401516136508285018215159052565b5050610140838101519083015261016092830151929091019190915290565b600080610140838503121561368357600080fd5b61368d848461327f565b915061012083013567ffffffffffffffff808211156136ab57600080fd5b9084019060a082870312156136bf57600080fd5b6136c76130e8565b82356136d281612fbb565b8152602083810135908201526040830135828111156136f057600080fd5b6136fc888286016131ac565b6040830152506060830135606082015260808301358281111561371e57600080fd5b61372a888286016131ac565b6080830152508093505050509250929050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b80820180821115610aff57610aff61373d565b80516118cc81613249565b80516118cc81612fbb565b600082601f8301126137a657600080fd5b81516137b46131cb82613184565b8181528460208386010111156137c957600080fd5b61337482602083016020870161337c565b6000602082840312156137ec57600080fd5b815167ffffffffffffffff8082111561380457600080fd5b908301906101e0828603121561381957600080fd5b61382161310b565b61382a8361377f565b81526138386020840161377f565b60208201526138496040840161378a565b604082015261385a6060840161378a565b606082015261386b6080840161378a565b608082015261387c60a0840161378a565b60a082015260c0838101519082015260e0808401519082015261010080840151908201526101208084015190820152610140808401519082015261016080840151908201526101806138cf81850161378a565b908201526101a083810151908201526101c080840151838111156138f257600080fd5b6138fe88828701613795565b918301919091525095945050505050565b60208152600061137660208301846133a0565b80516118cc81613266565b6000610180828403121561394057600080fd5b61394861312f565b6139518361377f565b815261395f6020840161377f565b60208201526139706040840161378a565b60408201526139816060840161378a565b60608201526139926080840161378a565b60808201526139a360a0840161378a565b60a082015260c083015160c082015260e083015160e08201526101008084015181830152506101206139d6818501613922565b908201526101408381015190820152610160928301519281019290925250919050565b8082018281126000831280158216821582161715613a1957613a1961373d565b505092915050565b8082028115828204841417610aff57610aff61373d565b600082613a6e577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b81810381811115610aff57610aff61373d565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203613ab757613ab761373d565b5060010190565b60e081526000613ad160e083018a6133a0565b63ffffffff989098166020830152506001600160a01b039586166040820152939094166060840152608083019190915260a082015290151560c090910152919050565b6001600160a01b0384168152826020820152606060408201526000613b3c60608301846133a0565b95945050505050565b80516020808301519190811015613b84577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8160200360031b1b821691505b50919050565b600060208284031215613b9c57600080fd5b5051919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b600060208284031215613be457600080fd5b815161137681613266565b60008251613c0181846020870161337c565b9190910192915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fdfea2646970667358221220a3680a17873f4c46b682e496f075c28aef799dbfefc67679607c7ecbffed72b464736f6c63430008180033","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.24 ^0.8.0 ^0.8.20;\n\n// contracts/interfaces/IAdmin.sol\n\ninterface IAdmin {\n // ============ Events ============\n\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n event ChainGasAmountUpdated(uint256 oldChainGasAmount, uint256 newChainGasAmount);\n\n // ============ Methods ============\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n\n function setChainGasAmount(uint256 newChainGasAmount) external;\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IFastBridgeRecipient.sol\n\ninterface IFastBridgeRecipient {\n function fastBridgeTransferReceived(\n address token,\n uint256 amount,\n bytes memory callParams\n )\n external\n payable\n returns (bytes4);\n}\n\n// contracts/interfaces/IFastBridgeV2Errors.sol\n\ninterface IFastBridgeV2Errors {\n error AmountIncorrect();\n error CallParamsLengthAboveMax();\n error ChainIncorrect();\n error ExclusivityParamsIncorrect();\n error MsgValueIncorrect();\n error NativeTokenCallValueNotSupported();\n error SenderIncorrect();\n error StatusIncorrect();\n error ZeroAddress();\n\n error RecipientIncorrectReturnValue();\n error RecipientNoReturnValue();\n\n error DeadlineExceeded();\n error DeadlineNotExceeded();\n error DeadlineTooShort();\n error DisputePeriodNotPassed();\n error DisputePeriodPassed();\n error ExclusivityPeriodNotPassed();\n\n error TransactionRelayed();\n}\n\n// contracts/libs/Errors.sol\n\nerror DeadlineExceeded();\nerror DeadlineNotExceeded();\nerror DeadlineTooShort();\nerror InsufficientOutputAmount();\n\nerror MsgValueIncorrect();\nerror PoolNotFound();\nerror TokenAddressMismatch();\nerror TokenNotContract();\nerror TokenNotETH();\nerror TokensIdentical();\n\nerror ChainIncorrect();\nerror AmountIncorrect();\nerror ZeroAddress();\n\nerror DisputePeriodNotPassed();\nerror DisputePeriodPassed();\nerror SenderIncorrect();\nerror StatusIncorrect();\nerror TransactionIdIncorrect();\nerror TransactionRelayed();\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// contracts/interfaces/IFastBridgeV2.sol\n\ninterface IFastBridgeV2 is IFastBridge {\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n struct BridgeTxDetails {\n BridgeStatus status;\n uint40 proofBlockTimestamp;\n uint48 proofBlockNumber;\n address proofRelayer;\n }\n\n struct BridgeRelay {\n uint48 blockNumber;\n uint48 blockTimestamp;\n address relayer;\n }\n\n /// @notice New params introduced in the FastBridgeV2.\n /// We are passing fields from the older BridgeParams struct outside of this struct\n /// for backwards compatibility.\n /// Note: quoteRelayer and quoteExclusivitySeconds are either both zero (indicating no exclusivity)\n /// or both non-zero (indicating exclusivity for the given period).\n /// Note: callValue \u003e 0 can NOT be used with destToken = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE (ETH_ADDRESS)\n /// @param quoteRelayer Relayer that provided the quote for the transaction\n /// @param quoteExclusivitySeconds Period of time the quote relayer is guaranteed exclusivity after user's deposit\n /// @param quoteId Unique quote identifier used for tracking the quote\n /// @param callValue ETH value to send to the recipient (if any)\n /// @param callParams Parameters for the arbitrary call to the destination recipient (if any)\n struct BridgeParamsV2 {\n address quoteRelayer;\n int256 quoteExclusivitySeconds;\n bytes quoteId;\n uint256 callValue;\n bytes callParams;\n }\n\n /// @notice Updated bridge transaction struct to include parameters introduced in FastBridgeV2.\n /// Note: only `exclusivityRelayer` can fill such a transaction until `exclusivityEndTime`.\n /// TODO: consider changing the encoding scheme to prevent spending extra gas on decoding.\n struct BridgeTransactionV2 {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n uint256 callValue; // ETH value to send to the recipient (if any) - replaces V1's sendChainGas flag\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n address exclusivityRelayer;\n uint256 exclusivityEndTime;\n bytes callParams;\n }\n\n event BridgeQuoteDetails(bytes32 indexed transactionId, bytes quoteId);\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability\n /// to provide temporary exclusivity fill rights for the quote relayer.\n /// @param params The parameters required to bridge\n /// @param paramsV2 The parameters for exclusivity fill rights (optional, can be left empty)\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function relay(bytes memory request, address relayer) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param transactionId The transaction id associated with the encoded bridge transaction to prove\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital.\n /// @notice Can only send funds to the relayer address on the proof.\n /// @param request The encoded bridge transaction to claim on origin chain\n function claim(bytes memory request) external;\n /// @notice Checks if a transaction has been relayed\n /// @param transactionId The ID of the transaction to check\n /// @return True if the transaction has been relayed, false otherwise\n function bridgeRelays(bytes32 transactionId) external view returns (bool);\n\n /// @notice Returns the status of a bridge transaction\n /// @param transactionId The ID of the bridge transaction\n /// @return BridgeStatus Status of the bridge transaction\n function bridgeStatuses(bytes32 transactionId) external view returns (BridgeStatus);\n\n /// @notice Returns the timestamp and relayer of a bridge proof\n /// @param transactionId The ID of the bridge transaction\n /// @return timestamp The timestamp of the bridge proof\n /// @return relayer The relayer address of the bridge proof\n function bridgeProofs(bytes32 transactionId) external view returns (uint96 timestamp, address relayer);\n\n /// @notice Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\n /// @param request The bridge request to decode\n function getBridgeTransactionV2(bytes memory request) external view returns (BridgeTransactionV2 memory);\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// contracts/libs/UniversalToken.sol\n\nlibrary UniversalTokenLib {\n using SafeERC20 for IERC20;\n\n address internal constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Transfers tokens to the given account. Reverts if transfer is not successful.\n /// @dev This might trigger fallback, if ETH is transferred to the contract.\n /// Make sure this can not lead to reentrancy attacks.\n function universalTransfer(address token, address to, uint256 value) internal {\n // Don't do anything, if need to send tokens to this address\n if (to == address(this)) return;\n // Don't do anything, if trying to send zero value\n if (value == 0) return;\n if (token == ETH_ADDRESS) {\n /// @dev Note: this can potentially lead to executing code in `to`.\n // solhint-disable-next-line avoid-low-level-calls\n (bool success,) = to.call{value: value}(\"\");\n require(success, \"ETH transfer failed\");\n } else {\n IERC20(token).safeTransfer(to, value);\n }\n }\n\n /// @notice Issues an infinite allowance to the spender, if the current allowance is insufficient\n /// to spend the given amount.\n function universalApproveInfinity(address token, address spender, uint256 amountToSpend) internal {\n // ETH Chad doesn't require your approval\n if (token == ETH_ADDRESS) return;\n // No-op if allowance is already sufficient\n uint256 allowance = IERC20(token).allowance(address(this), spender);\n if (allowance \u003e= amountToSpend) return;\n // Otherwise, reset approval to 0 and set to max allowance\n if (allowance \u003e 0) IERC20(token).safeDecreaseAllowance(spender, allowance);\n IERC20(token).safeIncreaseAllowance(spender, type(uint256).max);\n }\n\n /// @notice Returns the balance of the given token (or native ETH) for the given account.\n function universalBalanceOf(address token, address account) internal view returns (uint256) {\n if (token == ETH_ADDRESS) {\n return account.balance;\n } else {\n return IERC20(token).balanceOf(account);\n }\n }\n\n /// @dev Checks that token is a contract and not ETH_ADDRESS.\n function assertIsContract(address token) internal view {\n // Check that ETH_ADDRESS was not used (in case this is a predeploy on any of the chains)\n if (token == UniversalTokenLib.ETH_ADDRESS) revert TokenNotContract();\n // Check that token is not an EOA\n if (token.code.length == 0) revert TokenNotContract();\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/Admin.sol\n\ncontract Admin is IAdmin, AccessControlEnumerable {\n using UniversalTokenLib for address;\n\n bytes32 public constant RELAYER_ROLE = keccak256(\"RELAYER_ROLE\");\n bytes32 public constant REFUNDER_ROLE = keccak256(\"REFUNDER_ROLE\");\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n uint256 public constant FEE_BPS = 1e6;\n uint256 public constant FEE_RATE_MAX = 0.01e6; // max 1% on origin amount\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Chain gas amount to forward as rebate if requested\n uint256 public chainGasAmount;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n }\n\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n require(newFeeRate \u003c= FEE_RATE_MAX, \"newFeeRate \u003e max\");\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n token.universalTransfer(recipient, feeAmount);\n emit FeesSwept(token, recipient, feeAmount);\n }\n\n function setChainGasAmount(uint256 newChainGasAmount) external onlyRole(GOVERNOR_ROLE) {\n uint256 oldChainGasAmount = chainGasAmount;\n chainGasAmount = newChainGasAmount;\n emit ChainGasAmountUpdated(oldChainGasAmount, newChainGasAmount);\n }\n}\n\n// contracts/FastBridgeV2.sol\n\n/// @notice FastBridgeV2 is a contract for bridging tokens across chains.\ncontract FastBridgeV2 is Admin, IFastBridgeV2, IFastBridgeV2Errors {\n using SafeERC20 for IERC20;\n using UniversalTokenLib for address;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Delay for a transaction after which it could be permisionlessly refunded\n uint256 public constant REFUND_DELAY = 7 days;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n /// @notice Maximum length of accepted callParams\n uint256 public constant MAX_CALL_PARAMS_LENGTH = 2 ** 16 - 1;\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeTxDetails) public bridgeTxDetails;\n /// @notice Relay details on destination chain\n mapping(bytes32 =\u003e BridgeRelay) public bridgeRelayDetails;\n /// @notice Unique bridge nonces tracked per originSender\n mapping(address =\u003e uint256) public senderNonces;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Replaced by senderNonces\n uint256 public immutable nonce = 0;\n /// @notice the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n bridge({\n params: params,\n paramsV2: BridgeParamsV2({\n quoteRelayer: address(0),\n quoteExclusivitySeconds: 0,\n quoteId: bytes(\"\"),\n callValue: 0,\n callParams: bytes(\"\")\n })\n });\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes memory request) external payable {\n relay({request: request, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes memory request, bytes32 destTxHash) external {\n prove({transactionId: keccak256(request), destTxHash: destTxHash, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridgeV2\n function claim(bytes memory request) external {\n claim({request: request, to: address(0)});\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003e DISPUTE_PERIOD) {\n revert DisputePeriodPassed();\n }\n\n // @dev relayer gets slashed effectively if dest relay has gone thru\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n bridgeTxDetails[transactionId].proofRelayer = address(0);\n bridgeTxDetails[transactionId].proofBlockTimestamp = 0;\n bridgeTxDetails[transactionId].proofBlockNumber = 0;\n\n emit BridgeProofDisputed(transactionId, msg.sender);\n }\n\n /// @inheritdoc IFastBridge\n function refund(bytes memory request) external {\n bytes32 transactionId = keccak256(request);\n\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n\n if (bridgeTxDetails[transactionId].status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n\n if (hasRole(REFUNDER_ROLE, msg.sender)) {\n // Refunder can refund if deadline has passed\n if (block.timestamp \u003c= transaction.deadline) revert DeadlineNotExceeded();\n } else {\n // Permissionless refund is allowed after REFUND_DELAY\n if (block.timestamp \u003c= transaction.deadline + REFUND_DELAY) revert DeadlineNotExceeded();\n }\n\n // if all checks passed, set to REFUNDED status\n bridgeTxDetails[transactionId].status = BridgeStatus.REFUNDED;\n\n // transfer origin collateral back to original sender\n address to = transaction.originSender;\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount + transaction.originFeeAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (bridgeTxDetails[transactionId].proofRelayer != relayer) revert SenderIncorrect();\n return _timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n /// @dev This method is added to achieve backwards compatibility with decoding requests into V1 structs:\n /// - `callValue` is partially reported as a zero/non-zero flag\n /// - `callParams` is ignored\n /// In order to process all kinds of requests use getBridgeTransactionV2 instead.\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory) {\n // Try decoding into V2 struct first. This will revert if V1 struct is passed\n try this.getBridgeTransactionV2(request) returns (BridgeTransactionV2 memory txV2) {\n // Note: we entirely ignore the callParams field, as it was not present in V1\n return BridgeTransaction({\n originChainId: txV2.originChainId,\n destChainId: txV2.destChainId,\n originSender: txV2.originSender,\n destRecipient: txV2.destRecipient,\n originToken: txV2.originToken,\n destToken: txV2.destToken,\n originAmount: txV2.originAmount,\n destAmount: txV2.destAmount,\n originFeeAmount: txV2.originFeeAmount,\n sendChainGas: txV2.callValue != 0,\n deadline: txV2.deadline,\n nonce: txV2.nonce\n });\n } catch {\n // Fallback to V1 struct\n return abi.decode(request, (BridgeTransaction));\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) public payable {\n int256 exclusivityEndTime = int256(block.timestamp) + paramsV2.quoteExclusivitySeconds;\n _validateBridgeParams(params, paramsV2, exclusivityEndTime);\n\n // transfer tokens to bridge contract\n /// @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _pullToken(params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n\n // set status to requested\n bytes memory request = abi.encode(\n BridgeTransactionV2({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n callValue: paramsV2.callValue,\n deadline: params.deadline,\n nonce: senderNonces[params.sender]++, // increment nonce on every bridge\n exclusivityRelayer: paramsV2.quoteRelayer,\n // We checked exclusivityEndTime to be in range (0 .. params.deadline] above, so can safely cast\n exclusivityEndTime: uint256(exclusivityEndTime),\n callParams: paramsV2.callParams\n })\n );\n bytes32 transactionId = keccak256(request);\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n\n emit BridgeRequested({\n transactionId: transactionId,\n sender: params.sender,\n request: request,\n destChainId: params.dstChainId,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n sendChainGas: paramsV2.callValue != 0\n });\n emit BridgeQuoteDetails(transactionId, paramsV2.quoteId);\n }\n\n /// @inheritdoc IFastBridgeV2\n function relay(bytes memory request, address relayer) public payable {\n bytes32 transactionId = keccak256(request);\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n _validateRelayParams(transaction, transactionId, relayer);\n // mark bridge transaction as relayed\n bridgeRelayDetails[transactionId] =\n BridgeRelay({blockNumber: uint48(block.number), blockTimestamp: uint48(block.timestamp), relayer: relayer});\n\n // transfer tokens to recipient on destination chain and do an arbitrary call if requested\n address to = transaction.destRecipient;\n address token = transaction.destToken;\n uint256 amount = transaction.destAmount;\n\n // All state changes have been done at this point, can proceed to the external calls.\n // This follows the checks-effects-interactions pattern to mitigate potential reentrancy attacks.\n if (token == UniversalTokenLib.ETH_ADDRESS) {\n // For ETH non-zero callValue is not allowed\n if (transaction.callValue != 0) revert NativeTokenCallValueNotSupported();\n // Check that the correct msg.value was sent\n if (msg.value != amount) revert MsgValueIncorrect();\n } else {\n // For ERC20s, we check that the correct msg.value was sent\n if (msg.value != transaction.callValue) revert MsgValueIncorrect();\n // We need to transfer the tokens from the Relayer to the recipient first before performing an\n // optional post-transfer arbitrary call.\n IERC20(token).safeTransferFrom(msg.sender, to, amount);\n }\n\n if (transaction.callParams.length != 0) {\n // Arbitrary call requested, perform it while supplying full msg.value to the recipient\n // Note: if token has a fee on transfers, the recipient will have received less than `amount`.\n // This is a very niche edge case and should be handled by the recipient contract.\n _checkedCallRecipient({recipient: to, token: token, amount: amount, callParams: transaction.callParams});\n } else if (msg.value != 0) {\n // No arbitrary call requested, but msg.value was sent. This is either a relay with ETH,\n // or a non-zero callValue request with an ERC20. In both cases, transfer the ETH to the recipient.\n Address.sendValue(payable(to), msg.value);\n }\n\n emit BridgeRelayed({\n transactionId: transactionId,\n relayer: relayer,\n to: to,\n originChainId: transaction.originChainId,\n originToken: transaction.originToken,\n destToken: transaction.destToken,\n originAmount: transaction.originAmount,\n destAmount: transaction.destAmount,\n chainGasAmount: transaction.callValue\n });\n }\n\n /// @inheritdoc IFastBridgeV2\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) public onlyRole(RELAYER_ROLE) {\n // update bridge tx status given proof provided\n if (bridgeTxDetails[transactionId].status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n bridgeTxDetails[transactionId].status = BridgeStatus.RELAYER_PROVED;\n bridgeTxDetails[transactionId].proofBlockTimestamp = uint40(block.timestamp);\n bridgeTxDetails[transactionId].proofBlockNumber = uint48(block.number);\n bridgeTxDetails[transactionId].proofRelayer = relayer;\n\n emit BridgeProofProvided(transactionId, relayer, destTxHash);\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes memory request, address to) public {\n bytes32 transactionId = keccak256(request);\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n\n // update bridge tx status if able to claim origin collateral\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n\n // if \"to\" is zero addr, permissionlessly send funds to proven relayer\n if (to == address(0)) {\n to = bridgeTxDetails[transactionId].proofRelayer;\n } else if (bridgeTxDetails[transactionId].proofRelayer != msg.sender) {\n revert SenderIncorrect();\n }\n\n if (_timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003c= DISPUTE_PERIOD) {\n revert DisputePeriodNotPassed();\n }\n\n bridgeTxDetails[transactionId].status = BridgeStatus.RELAYER_CLAIMED;\n\n // update protocol fees if origin fee amount exists\n if (transaction.originFeeAmount \u003e 0) protocolFees[transaction.originToken] += transaction.originFeeAmount;\n\n // transfer origin collateral less fee to specified address\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositClaimed(transactionId, bridgeTxDetails[transactionId].proofRelayer, to, token, amount);\n }\n\n function bridgeStatuses(bytes32 transactionId) public view returns (BridgeStatus status) {\n return bridgeTxDetails[transactionId].status;\n }\n\n function bridgeProofs(bytes32 transactionId) public view returns (uint96 timestamp, address relayer) {\n timestamp = bridgeTxDetails[transactionId].proofBlockTimestamp;\n relayer = bridgeTxDetails[transactionId].proofRelayer;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeRelays(bytes32 transactionId) public view returns (bool) {\n // has this transactionId been relayed?\n return bridgeRelayDetails[transactionId].relayer != address(0);\n }\n\n /// @inheritdoc IFastBridgeV2\n function getBridgeTransactionV2(bytes memory request) public pure returns (BridgeTransactionV2 memory) {\n return abi.decode(request, (BridgeTransactionV2));\n }\n\n /// @notice Pulls a requested token from the user to this contract.\n function _pullToken(address token, uint256 amount) internal returns (uint256 amountPulled) {\n if (token == UniversalTokenLib.ETH_ADDRESS) {\n // For ETH we just need to check that the supplied msg.value is correct\n if (amount != msg.value) revert MsgValueIncorrect();\n amountPulled = msg.value;\n } else {\n token.assertIsContract();\n // Record token balance before transfer\n amountPulled = IERC20(token).balanceOf(address(this));\n // Token needs to be pulled only if msg.value is zero\n // This way user can specify WETH as the origin asset\n IERC20(token).safeTransferFrom(msg.sender, address(this), amount);\n // Use the difference between the recorded balance and the current balance as the amountPulled\n amountPulled = IERC20(token).balanceOf(address(this)) - amountPulled;\n }\n }\n\n /// @notice Calls the Recipient's hook function with the specified callParams and performs\n /// all the necessary checks for the returned value.\n function _checkedCallRecipient(\n address recipient,\n address token,\n uint256 amount,\n bytes memory callParams\n )\n internal\n {\n bytes memory hookData =\n abi.encodeCall(IFastBridgeRecipient.fastBridgeTransferReceived, (token, amount, callParams));\n // This will bubble any revert messages from the hook function\n bytes memory returnData = Address.functionCallWithValue({target: recipient, data: hookData, value: msg.value});\n // Explicit revert if no return data at all\n if (returnData.length == 0) revert RecipientNoReturnValue();\n // Check that exactly a single return value was returned\n if (returnData.length != 32) revert RecipientIncorrectReturnValue();\n // Return value should be abi-encoded hook function selector\n if (bytes32(returnData) != bytes32(IFastBridgeRecipient.fastBridgeTransferReceived.selector)) {\n revert RecipientIncorrectReturnValue();\n }\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint40(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint40).max but\n /// proof.timestamp \u003c type(uint40).max via unchecked statement\n /// @param proofBlockTimestamp The bridge proof block timestamp\n /// @return delta Time delta since proof submitted\n function _timeSince(uint40 proofBlockTimestamp) internal view returns (uint256 delta) {\n unchecked {\n delta = uint40(block.timestamp) - proofBlockTimestamp;\n }\n }\n\n /// @notice Performs all the necessary checks for a bridge to happen.\n /// @dev There's no good way to refactor this function to reduce cyclomatic complexity due to\n /// the number of checks that need to be performed, so we skip the code-complexity rule here.\n // solhint-disable-next-line code-complexity\n function _validateBridgeParams(\n BridgeParams memory params,\n BridgeParamsV2 memory paramsV2,\n int256 exclusivityEndTime\n )\n internal\n view\n {\n // Check V1 (legacy) params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.sender == address(0) || params.to == address(0)) revert ZeroAddress();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n // Check V2 params\n if (paramsV2.callParams.length \u003e MAX_CALL_PARAMS_LENGTH) revert CallParamsLengthAboveMax();\n if (paramsV2.callValue != 0 \u0026\u0026 params.destToken == UniversalTokenLib.ETH_ADDRESS) {\n revert NativeTokenCallValueNotSupported();\n }\n // exclusivityEndTime must be in range (0 .. params.deadline]\n if (exclusivityEndTime \u003c= 0 || exclusivityEndTime \u003e int256(params.deadline)) {\n revert ExclusivityParamsIncorrect();\n }\n }\n\n /// @notice Performs all the necessary checks for a relay to happen.\n function _validateRelayParams(\n BridgeTransactionV2 memory transaction,\n bytes32 transactionId,\n address relayer\n )\n internal\n view\n {\n if (relayer == address(0)) revert ZeroAddress();\n // Check if the transaction has already been relayed\n if (bridgeRelays(transactionId)) revert TransactionRelayed();\n if (transaction.destChainId != uint32(block.chainid)) revert ChainIncorrect();\n // Check the deadline for relay to happen\n if (block.timestamp \u003e transaction.deadline) revert DeadlineExceeded();\n // Check the exclusivity period, if it is still ongoing\n // forgefmt: disable-next-item\n if (\n transaction.exclusivityRelayer != address(0) \u0026\u0026\n transaction.exclusivityRelayer != relayer \u0026\u0026\n block.timestamp \u003c= transaction.exclusivityEndTime\n ) {\n revert ExclusivityPeriodNotPassed();\n }\n }\n}\n","language":"Solidity","languageVersion":"0.8.24","compilerVersion":"0.8.24","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"64760:19813:0:-:0;;;65906:1;65873:34;;66011:85;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;66045:6;63675:38;52847:4;66045:6;63675:10;:38::i;:::-;-1:-1:-1;;66077:12:0::1;66063:26;::::0;-1:-1:-1;64760:19813:0;;62160:257;62246:4;;62277:31;62294:4;62300:7;62277:16;:31::i;:::-;62262:46;;62322:7;62318:69;;;62345:18;;;;:12;:18;;;;;:31;;62368:7;62345:22;:31::i;:::-;;62318:69;62403:7;-1:-1:-1;62160:257:0;;;;;:::o;56794:316::-;56871:4;53569:12;;;;;;;;;;;-1:-1:-1;;;;;53569:29:0;;;;;;;;;;;;56887:217;;56930:6;:12;;;;;;;;;;;-1:-1:-1;;;;;56930:29:0;;;;;;;;;:36;;-1:-1:-1;;56930:36:0;56962:4;56930:36;;;57012:12;23368:10;;23289:96;57012:12;-1:-1:-1;;;;;56985:40:0;57003:7;-1:-1:-1;;;;;56985:40:0;56997:4;56985:40;;;;;;;;;;-1:-1:-1;57046:4:0;57039:11;;56887:217;-1:-1:-1;57088:5:0;57081:12;;32813:150;32883:4;32906:50;32911:3;-1:-1:-1;;;;;32931:23:0;;26801:4;28857:21;;;:14;;;:21;;;;;;26817:321;;-1:-1:-1;26859:23:0;;;;;;;;:11;:23;;;;;;;;;;;;;27041:18;;27017:21;;;:14;;;:21;;;;;;:42;;;;27073:11;;14:290:1;84:6;137:2;125:9;116:7;112:23;108:32;105:52;;;153:1;150;143:12;105:52;179:16;;-1:-1:-1;;;;;224:31:1;;214:42;;204:70;;270:1;267;260:12;14:290;64760:19813:0;;;;;;;;;;;;;;;;;;","srcMapRuntime":"64760:19813:0:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;60820:212;;;;;;;;;;-1:-1:-1;60820:212:0;;;;;:::i;:::-;;:::i;:::-;;;612:14:1;;605:22;587:41;;575:2;560:18;60820:212:0;;;;;;;;63050:60;;;;;;;;;;;;63087:23;63050:60;;;;;785:25:1;;;773:2;758:18;63050:60:0;639:177:1;78381:150:0;;;;;;;;;;-1:-1:-1;78381:150:0;;;;;:::i;:::-;78449:19;78487:30;;;:15;:30;;;;;:37;;;;78381:150;;;;;;;;:::i;64022:359::-;;;;;;;;;;-1:-1:-1;64022:359:0;;;;;:::i;:::-;;:::i;:::-;;63232:45;;;;;;;;;;;;63271:6;63232:45;;76275:648;;;;;;;;;;-1:-1:-1;76275:648:0;;;;;:::i;:::-;;:::i;65110:45::-;;;;;;;;;;;;65149:6;65110:45;;54425:120;;;;;;;;;;-1:-1:-1;54425:120:0;;;;;:::i;:::-;54490:7;54516:12;;;;;;;;;;:22;;;;54425:120;65722:47;;;;;;;;;;-1:-1:-1;65722:47:0;;;;;:::i;:::-;;;;;;;;;;;;;;54841:136;;;;;;;;;;-1:-1:-1;54841:136:0;;;;;:::i;:::-;;:::i;55943:245::-;;;;;;;;;;-1:-1:-1;55943:245:0;;;;;:::i;:::-;;:::i;76961:1414::-;;;;;;;;;;-1:-1:-1;76961:1414:0;;;;;:::i;:::-;;:::i;66134:369::-;;;;;;:::i;:::-;;:::i;63394:30::-;;;;;;;;;;;;;;;;62978:66;;;;;;;;;;;;63018:26;62978:66;;79059:169;;;;;;;;;;-1:-1:-1;79059:169:0;;;;;:::i;:::-;;:::i;:::-;;;;;;;:::i;67821:1169::-;;;;;;;;;;-1:-1:-1;67821:1169:0;;;;;:::i;:::-;;:::i;65482:58::-;;;;;;;;;;-1:-1:-1;65482:58:0;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;65482:58:0;;;;;;;;;;;;;:::i;65242:56::-;;;;;;;;;;;;65288:10;65242:56;;78820:199;;;;;;;;;;-1:-1:-1;78820:199:0;;;;;:::i;:::-;78886:4;78957:33;;;:18;:33;;;;;:41;;;;-1:-1:-1;;;;;78957:41:0;:55;;;78820:199;66696:170;;;;;;;;;;-1:-1:-1;66696:170:0;;;;;:::i;:::-;;:::i;66541:117::-;;;;;;:::i;:::-;;:::i;61617:142::-;;;;;;;;;;-1:-1:-1;61617:142:0;;;;;:::i;:::-;;:::i;:::-;;;-1:-1:-1;;;;;12205:55:1;;;12187:74;;12175:2;12160:18;61617:142:0;12041:226:1;78537:243:0;;;;;;;;;;-1:-1:-1;78537:243:0;;;;;:::i;:::-;78603:16;78660:30;;;:15;:30;;;;;:50;;;;;;;78730:43;;;;-1:-1:-1;;;;;78730:43:0;;78537:243;;;;;12474:26:1;12462:39;;;12444:58;;-1:-1:-1;;;;;12538:55:1;;;12533:2;12518:18;;12511:83;12417:18;78537:243:0;12272:328:1;53469:136:0;;;;;;;;;;-1:-1:-1;53469:136:0;;;;;:::i;:::-;53546:4;53569:12;;;;;;;;;;;-1:-1:-1;;;;;53569:29:0;;;;;;;;;;;;;;;53469:136;62908:64;;;;;;;;;;;;62947:25;62908:64;;73354:2881;;;;;;:::i;:::-;;:::i;52802:49::-;;;;;;;;;;-1:-1:-1;52802:49:0;52847:4;52802:49;;65968:36;;;;;;;;;;;;;;;69028:392;;;;;;;;;;-1:-1:-1;69028:392:0;;;;;:::i;:::-;;:::i;69755:1121::-;;;;;;;;;;-1:-1:-1;69755:1121:0;;;;;:::i;:::-;;:::i;:::-;;;;;;;:::i;67048:735::-;;;;;;;;;;-1:-1:-1;67048:735:0;;;;;:::i;:::-;;:::i;65873:34::-;;;;;;;;;;;;;;;63726:290;;;;;;;;;;-1:-1:-1;63726:290:0;;;;;:::i;:::-;;:::i;64387:264::-;;;;;;;;;;-1:-1:-1;64387:264:0;;;;;:::i;:::-;;:::i;63189:37::-;;;;;;;;;;;;63223:3;63189:37;;70916:2398;;;;;;:::i;:::-;;:::i;66906:104::-;;;;;;;;;;-1:-1:-1;66906:104:0;;;;;:::i;:::-;;:::i;65597:57::-;;;;;;;;;;-1:-1:-1;65597:57:0;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;65597:57:0;;;;;;;15543:14:1;15584:15;;;15566:34;;15636:15;;;;15631:2;15616:18;;15609:43;-1:-1:-1;;;;;15688:55:1;15668:18;;;15661:83;15521:2;15506:18;65597:57:0;15335:415:1;61927:131:0;;;;;;;;;;-1:-1:-1;61927:131:0;;;;;:::i;:::-;;:::i;63116:66::-;;;;;;;;;;;;63156:26;63116:66;;55257:138;;;;;;;;;;-1:-1:-1;55257:138:0;;;;;:::i;:::-;;:::i;63480:47::-;;;;;;;;;;-1:-1:-1;63480:47:0;;;;;:::i;:::-;;;;;;;;;;;;;;65359:60;;;;;;;;;;;;65408:11;65359:60;;63601:29;;;;;;;;;;;;;;;;60820:212;60905:4;60928:57;;;60943:42;60928:57;;:97;;;60989:36;61013:11;60989:23;:36::i;:::-;60921:104;60820:212;-1:-1:-1;;60820:212:0:o;64022:359::-;63156:26;53079:16;53090:4;53079:10;:16::i;:::-;-1:-1:-1;;;;;64146:19:0;::::1;64126:17;64146:19:::0;;;:12:::1;:19;::::0;;;;;;64179:14;;;64175:27:::1;;64195:7;64022:359:::0;;;:::o;64175:27::-:1;-1:-1:-1::0;;;;;64243:19:0;::::1;64265:1;64243:19:::0;;;:12:::1;:19;::::0;;;;:23;64276:45:::1;::::0;64300:9;64311;64276:23:::1;:45::i;:::-;64336:38;::::0;;-1:-1:-1;;;;;16036:15:1;;;16018:34;;16088:15;;16083:2;16068:18;;16061:43;16120:18;;;16113:34;;;64336:38:0::1;::::0;15945:2:1;15930:18;64336:38:0::1;;;;;;;64116:265;53105:1;64022:359:::0;;;:::o;76275:648::-;62947:25;53079:16;53090:4;53079:10;:16::i;:::-;76491:22:::1;76450:30;::::0;;;:15:::1;:30;::::0;;;;:37;::::1;;:63;::::0;::::1;;;;;;:::i;:::-;;76446:93;;76522:17;;;;;;;;;;;;;;76446:93;76549:30;::::0;;;:15:::1;:30;::::0;;;;;;;;:67;;76589:27:::1;76712:70:::0;;;;76626:76:::1;76686:15;76626:76;;;76712:70:::0;;;;76769:12:::1;76712:70;;;::::0;;76792:53;::::1;::::0;-1:-1:-1;;;;;76792:53:0;::::1;::::0;;::::1;::::0;;;::::1;::::0;;;76861:55;;785:25:1;;;76861:55:0;;76792:53;;76549:30;;76861:55:::1;::::0;;;;;;;::::1;76275:648:::0;;;;:::o;54841:136::-;54490:7;54516:12;;;;;;;;;;:22;;;53079:16;53090:4;53079:10;:16::i;:::-;54945:25:::1;54956:4;54962:7;54945:10;:25::i;:::-;;54841:136:::0;;;:::o;55943:245::-;-1:-1:-1;;;;;56036:34:0;;23368:10;56036:34;56032:102;;56093:30;;;;;;;;;;;;;;56032:102;56144:37;56156:4;56162:18;56144:11;:37::i;76961:1414::-;77051:18;;;;;;77027:21;77120:31;77061:7;77120:22;:31::i;:::-;77079:72;-1:-1:-1;77277:27:0;77236:30;;;;:15;:30;;;;;:37;;;:68;;;;;;;;:::i;:::-;;77232:98;;77313:17;;;;;;;;;;;;;;77232:98;-1:-1:-1;;;;;77424:16:0;;77420:213;;77461:30;;;;:15;:30;;;;;:43;;;;-1:-1:-1;;;;;77461:43:0;;-1:-1:-1;77420:213:0;;;77525:30;;;;:15;:30;;;;;:43;;;;-1:-1:-1;;;;;77525:43:0;77572:10;77525:57;77521:112;;77605:17;;;;;;;;;;;;;;77521:112;77658:30;;;;:15;:30;;;;;:50;65004:10;;77658:50;;;;;;;81985:15;81978:45;81970:53;77647:80;77643:142;;77750:24;;;;;;;;;;;;;;77643:142;77795:30;;;;:15;:30;;;;;:68;;;;77835:28;77795:68;;;77938:27;;;;:31;77934:105;;78012:27;;;;77984:23;;;;-1:-1:-1;;;;;77971:37:0;;;;;:12;:37;;;;;:68;;:37;;;:68;;78012:27;;77971:68;:::i;:::-;;;;-1:-1:-1;;77934:105:0;78134:23;;;;78184:24;;;;78218:35;-1:-1:-1;;;;;78218:23:0;;78242:2;78184:24;78218:23;:35::i;:::-;78305:30;;;;:15;:30;;;;;;;;;:43;78269:99;;-1:-1:-1;;;;;16669:55:1;;;16651:74;;16741:18;;;16734:34;;;78269:99:0;;;;78305:43;;;;;;;;:30;;78269:99;;16624:18:1;78269:99:0;;;;;;;77017:1358;;;;76961:1414;;:::o;66134:369::-;66205:291;66234:6;66264:221;;;;;;;;66319:1;-1:-1:-1;;;;;66264:221:0;;;;;66364:1;66264:221;;;;66392:9;;;;;;;;;;;;66264:221;;;;66430:1;66264:221;;;;66461:9;;;;;;;;;;;;66264:221;;;66205:6;:291::i;:::-;66134:369;:::o;79059:169::-;79134:26;-1:-1:-1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;79134:26:0;79190:7;79179:42;;;;;;;;;;;;:::i;67821:1169::-;67902:18;;;;;;67878:21;67972:31;67912:7;67972:22;:31::i;:::-;67931:72;-1:-1:-1;68059:22:0;68018:30;;;;:15;:30;;;;;:37;;;:63;;;;;;;;:::i;:::-;;68014:93;;68090:17;;;;;;;;;;;;;;68014:93;68145:10;53546:4;53569:29;;;:12;;:29;:12;:29;;;;;68118:382;;;68253:11;:20;;;68234:15;:39;68230:73;;68282:21;;;;;;;;;;;;;;68230:73;68118:382;;;65149:6;68424:11;:20;;;:35;;;;:::i;:::-;68405:15;:54;68401:88;;68468:21;;;;;;;;;;;;;;68401:88;68566:30;;;;:15;:30;;;;;;:61;;;;68606:21;68566:61;;;68713:24;;;68763:23;;;;68840:27;;;;68813:24;;;;68713;;68763:23;;68813:54;;68840:27;68813:54;:::i;:::-;68796:71;-1:-1:-1;68877:35:0;-1:-1:-1;;;;;68877:23:0;;68901:2;68796:71;68877:23;:35::i;:::-;68928:55;;;-1:-1:-1;;;;;16669:55:1;;;16651:74;;16756:2;16741:18;;16734:34;;;68928:55:0;;;68950:13;;68928:55;;16624:18:1;68928:55:0;;;;;;;67868:1122;;;;;67821:1169;:::o;66696:170::-;66772:87;66804:7;66794:18;;;;;;66826:10;66847;66772:5;:87::i;:::-;66696:170;;:::o;66541:117::-;66605:46;66621:7;66639:10;66605:5;:46::i;61617:142::-;61698:7;61724:18;;;:12;:18;;;;;:28;;61746:5;61724:21;:28::i;:::-;61717:35;61617:142;-1:-1:-1;;;61617:142:0:o;73354:2881::-;73457:18;;;;;;73433:21;73526:31;73467:7;73526:22;:31::i;:::-;73485:72;;73567:57;73588:11;73601:13;73616:7;73567:20;:57::i;:::-;73728:107;;;;;;;;;;73761:12;73728:107;;;;73799:15;73728:107;;;;;;;;;-1:-1:-1;;;;;73728:107:0;;;;;;;;;-1:-1:-1;73680:33:0;;;:18;:33;;;;;;;:155;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;73958:25;;;74009:21;;;;74057:22;;;;73958:25;;74009:21;;74057:22;74294:38;;;;;74290:719;;74409:21;;;;:26;74405:73;;74444:34;;;;;;;;;;;;;;74405:73;74566:6;74553:9;:19;74549:51;;74581:19;;;;;;;;;;;;;;74549:51;74290:719;;;74720:11;:21;;;74707:9;:34;74703:66;;74750:19;;;;;;;;;;;;;;74703:66;74944:54;-1:-1:-1;;;;;74944:30:0;;74975:10;74987:2;74991:6;74944:30;:54::i;:::-;75023:22;;;;:29;:34;75019:776;;75375:104;75409:2;75420:5;75435:6;75455:11;:22;;;75375:21;:104::i;:::-;75019:776;;;75500:9;:14;75496:299;;75743:41;75769:2;75774:9;75743:17;:41::i;:::-;75914:2;-1:-1:-1;;;;;75810:418:0;75889:7;-1:-1:-1;;;;;75810:418:0;75853:13;75810:418;75945:11;:25;;;75997:11;:23;;;76045:11;:21;;;76094:11;:24;;;76144:11;:22;;;76196:11;:21;;;75810:418;;;;;;;;;;19501:10:1;19489:23;;;;19471:42;;-1:-1:-1;;;;;19610:15:1;;;19605:2;19590:18;;19583:43;19662:15;;;;19657:2;19642:18;;19635:43;19709:2;19694:18;;19687:34;19752:3;19737:19;;19730:35;;;;19796:3;19781:19;;19774:35;19458:3;19443:19;;19186:629;75810:418:0;;;;;;;;73423:2812;;;;;73354:2881;;:::o;69028:392::-;69109:4;69170:27;69129:30;;;;:15;:30;;;;;:37;;;:68;;;;;;;;:::i;:::-;;69125:98;;69206:17;;;;;;;;;;;;;;69125:98;69237:30;;;;:15;:30;;;;;:43;-1:-1:-1;;;;;69237:54:0;;;:43;;;;;:54;69233:84;;69300:17;;;;;;;;;;;;;;69233:84;-1:-1:-1;;69345:30:0;;;;:15;:30;;;;;:50;65004:10;69345:50;;;;;;;;81985:15;81978:45;81970:53;69334:79;;69028:392::o;69755:1121::-;-1:-1:-1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;69956:36:0;;;;;:4;;:27;;:36;;69984:7;;69956:36;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;69956:36:0;;;;;;;;;;;;:::i;:::-;;;69952:918;;70830:7;70819:40;;;;;;;;;;;;:::i;69952:918::-;70146:597;;;;;;;;70197:4;:18;;;70146:597;;;;;;70246:4;:16;;;70146:597;;;;;;70294:4;:17;;;-1:-1:-1;;;;;70146:597:0;;;;;70344:4;:18;;;-1:-1:-1;;;;;70146:597:0;;;;;70393:4;:16;;;-1:-1:-1;;;;;70146:597:0;;;;;70438:4;:14;;;-1:-1:-1;;;;;70146:597:0;;;;;70484:4;:17;;;70146:597;;;;70531:4;:15;;;70146:597;;;;70581:4;:20;;;70146:597;;;;70633:4;:14;;;70651:1;70633:19;;70146:597;;;;;;70680:4;:13;;;70146:597;;;;70718:4;:10;;;70146:597;;;70139:604;;;69755:1121;;;:::o;69952:918::-;69755:1121;;;:::o;67048:735::-;63087:23;53079:16;53090:4;53079:10;:16::i;:::-;67173:27:::1;67132:30;::::0;;;:15:::1;:30;::::0;;;;:37;::::1;;:68;::::0;::::1;;;;;;:::i;:::-;;67128:98;;67209:17;;;;;;;;;;;;;;67128:98;67251:30;::::0;;;:15:::1;:30;::::0;;;;:50;65004:10:::1;::::0;67251:50:::1;::::0;::::1;;::::0;;::::1;81985:15:::0;81978:45;81970:53;67240:79:::1;67236:138;;;67342:21;;;;;;;;;;;;;;67236:138;67461:30;::::0;;;:15:::1;:30;::::0;;;;;67501:22:::1;67663:51:::0;;67730:46;67765:10:::1;::::0;67461:30;;67730:46:::1;::::0;67461:30;67730:46:::1;67048:735:::0;;:::o;63726:290::-;63156:26;53079:16;53090:4;53079:10;:16::i;:::-;63271:6:::1;63825:10;:26;;63817:55;;;::::0;::::1;::::0;;21574:2:1;63817:55:0::1;::::0;::::1;21556:21:1::0;21613:2;21593:18;;;21586:30;21652:18;21632;;;21625:46;21688:18;;63817:55:0::1;;;;;;;;;63903:15;::::0;;63928:28;;;;63971:38:::1;::::0;;21891:25:1;;;21947:2;21932:18;;21925:34;;;63971:38:0::1;::::0;21864:18:1;63971:38:0::1;;;;;;;;63807:209;63726:290:::0;;:::o;64387:264::-;63156:26;53079:16;53090:4;53079:10;:16::i;:::-;64512:14:::1;::::0;;64536:34;;;;64585:59:::1;::::0;;21891:25:1;;;21947:2;21932:18;;21925:34;;;64585:59:0::1;::::0;21864:18:1;64585:59:0::1;21717:248:1::0;70916:2398:0;71017:25;71071:8;:32;;;71052:15;71045:58;;;;:::i;:::-;71017:86;;71113:59;71135:6;71143:8;71153:18;71113:21;:59::i;:::-;71308:20;71331:51;71342:6;:18;;;71362:6;:19;;;71331:10;:51::i;:::-;71308:74;;71450:23;71505:1;71487:15;;:19;71483:85;;;63223:3;71542:15;;71527:12;:30;;;;:::i;:::-;71526:42;;;;:::i;:::-;71508:60;;71483:85;71578:31;71594:15;71578:31;;:::i;:::-;;;71722:20;71769:924;;;;;;;;71829:13;71769:924;;;;;;71874:6;:17;;;71769:924;;;;;;71923:6;:13;;;-1:-1:-1;;;;;71769:924:0;;;;;71969:6;:9;;;-1:-1:-1;;;;;71769:924:0;;;;;72009:6;:18;;;-1:-1:-1;;;;;71769:924:0;;;;;72056:6;:16;;;-1:-1:-1;;;;;71769:924:0;;;;;72104:12;71769:924;;;;72146:6;:17;;;71769:924;;;;72198:15;71769:924;;;;72242:8;:18;;;71769:924;;;;72288:6;:15;;;71769:924;;;;72328:12;:27;72341:6;:13;;;-1:-1:-1;;;;;72328:27:0;-1:-1:-1;;;;;72328:27:0;;;;;;;;;;;;;:29;;;;;;;;;:::i;:::-;;;;;71769:924;;;;72430:8;:21;;;-1:-1:-1;;;;;71769:924:0;;;;;72610:18;71769:924;;;;72659:8;:19;;;71769:924;;;71745:958;;;;;;;;:::i;:::-;;;;;;;-1:-1:-1;;71745:958:0;;;;;;72737:18;;71745:958;72737:18;;;;;;;72713:21;72765:30;;;:15;:30;;;;;;:62;;;;72805:22;72765:62;;;72923:13;;;72993:17;;73037:18;;;;;73080:16;;;;73162:17;;;;73207:18;;;;71745:958;;-1:-1:-1;72737:18:0;;-1:-1:-1;;;;;72843:398:0;;;;72737:18;;72843:398;;;;71745:958;;72993:17;;73037:18;73080:16;73124:12;;73207:23;;;;72843:398;:::i;:::-;;;;;;;;73275:13;73256:51;73290:8;:16;;;73256:51;;;;;;:::i;:::-;;;;;;;;71007:2307;;;;;70916:2398;;:::o;66906:104::-;66962:41;66978:7;66999:1;66962:5;:41::i;61927:131::-;61998:7;62024:18;;;:12;:18;;;;;:27;;:25;:27::i;55257:138::-;54490:7;54516:12;;;;;;;;;;:22;;;53079:16;53090:4;53079:10;:16::i;:::-;55362:26:::1;55374:4;55380:7;55362:11;:26::i;53180:202::-:0;53265:4;53288:47;;;53303:32;53288:47;;:87;;-1:-1:-1;45095:25:0;45080:40;;;;53339:36;44981:146;53814:103;53880:30;53891:4;23368:10;53880;:30::i;58092:653::-;58267:4;-1:-1:-1;;;;;58253:19:0;;;58249:32;;58092:653;;;:::o;58249:32::-;58353:5;58362:1;58353:10;58349:23;;58092:653;;;:::o;58349:23::-;58385:20;-1:-1:-1;;;;;58385:20:0;;;58381:358;;58565:12;58582:2;-1:-1:-1;;;;;58582:7:0;58597:5;58582:25;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;58564:43;;;58629:7;58621:39;;;;;;;24145:2:1;58621:39:0;;;24127:21:1;24184:2;24164:18;;;24157:30;24223:21;24203:18;;;24196:49;24262:18;;58621:39:0;23943:343:1;58381:358:0;58691:37;-1:-1:-1;;;;;58691:26:0;;58718:2;58722:5;58691:26;:37::i;62160:257::-;62246:4;62262:12;62277:31;62294:4;62300:7;62277:16;:31::i;:::-;62262:46;;62322:7;62318:69;;;62345:18;;;;:12;:18;;;;;:31;;62368:7;62345:22;:31::i;:::-;;62403:7;62160:257;-1:-1:-1;;;62160:257:0:o;62520:262::-;62607:4;62623:12;62638:32;62656:4;62662:7;62638:17;:32::i;:::-;62623:47;;62684:7;62680:72;;;62707:18;;;;:12;:18;;;;;:34;;62733:7;62707:25;:34::i;34071:156::-;34145:7;34195:22;34199:3;34211:5;34195:3;:22::i;83620:951::-;-1:-1:-1;;;;;83808:21:0;;83804:47;;83838:13;;;;;;;;;;;;;;83804:47;78886:4;78957:33;;;:18;:33;;;;;:41;;;;-1:-1:-1;;;;;78957:41:0;:55;83922:60;;83962:20;;;;;;;;;;;;;;83922:60;84030:13;83996:48;;:11;:23;;;:48;;;83992:77;;84053:16;;;;;;;;;;;;;;83992:77;84151:11;:20;;;84133:15;:38;84129:69;;;84180:18;;;;;;;;;;;;;;84129:69;84328:30;;;;-1:-1:-1;;;;;84328:44:0;;;;;:101;;;84422:7;-1:-1:-1;;;;;84388:41:0;:11;:30;;;-1:-1:-1;;;;;84388:41:0;;;84328:101;:166;;;;;84464:11;:30;;;84445:15;:49;;84328:166;84311:254;;;84526:28;;;;;;;;;;;;;;46696:188;46823:53;;-1:-1:-1;;;;;16036:15:1;;;46823:53:0;;;16018:34:1;16088:15;;;16068:18;;;16061:43;16120:18;;;16113:34;;;46796:81:0;;46816:5;;46838:18;;;;;15930::1;;46823:53:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;46796:19;:81::i;80387:999::-;80562:21;80663:5;80670:6;80678:10;80598:92;;;;;;;;;;:::i;:::-;;;;-1:-1:-1;;80598:92:0;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;80797:84:0;80836:9;80598:92;80870:9;80797:29;:84::i;:::-;80771:110;;80947:10;:17;80968:1;80947:22;80943:59;;80978:24;;;;;;;;;;;;;;80943:59;81081:10;:17;81102:2;81081:23;81077:67;;81113:31;;;;;;;;;;;;;;81077:67;81258:56;81227:19;81235:10;81227:19;:::i;:::-;:88;81223:157;;81338:31;;;;;;;;;;;;;;81223:157;80552:834;;80387:999;;;;:::o;17900:331::-;18009:6;17985:21;:30;17981:109;;;18038:41;;;;;18073:4;18038:41;;;12187:74:1;12160:18;;18038:41:0;12041:226:1;17981:109:0;18101:12;18119:9;-1:-1:-1;;;;;18119:14:0;18141:6;18119:33;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;18100:52;;;18167:7;18162:63;;18197:17;;;;;;;;;;;;;;82365:1176;82618:13;82597:6;:17;;;:34;;;82593:63;;82640:16;;;;;;;;;;;;;;82593:63;82670:19;;;;:24;;:50;;-1:-1:-1;82698:17:0;;;;:22;82670:50;82666:80;;;82729:17;;;;;;;;;;;;;;82666:80;82760:13;;;;-1:-1:-1;;;;;82760:27:0;;;:54;;-1:-1:-1;82791:9:0;;;;-1:-1:-1;;;;;82791:23:0;;82760:54;82756:80;;;82823:13;;;;;;;;;;;;;;82756:80;82850:18;;;;-1:-1:-1;;;;;82850:32:0;;;:66;;-1:-1:-1;82886:16:0;;;;-1:-1:-1;;;;;82886:30:0;;82850:66;82846:92;;;82925:13;;;;;;;;;;;;;;82846:92;82970:37;65288:10;82970:15;:37;:::i;:::-;82952:6;:15;;;:55;82948:86;;;83016:18;;;;;;;;;;;;;;82948:86;65408:11;83075:8;:19;;;:26;:51;83071:90;;;83135:26;;;;;;;;;;;;;;83071:90;83175:18;;;;:23;;;;:76;;-1:-1:-1;83202:16:0;;;;-1:-1:-1;;;;;83202:49:0;57809:42;83202:49;83175:76;83171:148;;;83274:34;;;;;;;;;;;;;;83171:148;83424:1;83402:18;:23;;:71;;;;83457:6;:15;;;83429:18;:44;83402:71;83398:137;;;83496:28;;;;;;;;;;;;;;79306:923;79375:20;79411:38;-1:-1:-1;;;;;79411:38:0;;;79407:816;;79563:9;79553:6;:19;79549:51;;79581:19;;;;;;;;;;;;;;79549:51;-1:-1:-1;79629:9:0;79407:816;;;79669:24;:5;-1:-1:-1;;;;;79669:22:0;;:24::i;:::-;79774:38;;;;;79806:4;79774:38;;;12187:74:1;-1:-1:-1;;;;;79774:23:0;;;;;12160:18:1;;79774:38:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;79759:53;-1:-1:-1;79958:65:0;-1:-1:-1;;;;;79958:30:0;;79989:10;80009:4;80016:6;79958:30;:65::i;:::-;80159:38;;;;;80191:4;80159:38;;;12187:74:1;80200:12:0;;-1:-1:-1;;;;;80159:23:0;;;;;12160:18:1;;80159:38:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;:53;;;;:::i;33614:115::-;33677:7;33703:19;33711:3;29053:18;;28971:107;54047:197;53546:4;53569:12;;;;;;;;;;;-1:-1:-1;;;;;53569:29:0;;;;;;;;;;;;54130:108;;54180:47;;;;;-1:-1:-1;;;;;16669:55:1;;54180:47:0;;;16651:74:1;16741:18;;;16734:34;;;16624:18;;54180:47:0;16477:297:1;46297:160:0;46406:43;;-1:-1:-1;;;;;16669:55:1;;;46406:43:0;;;16651:74:1;16741:18;;;16734:34;;;46379:71:0;;46399:5;;46421:14;;;;;16624:18:1;;46406:43:0;16477:297:1;56794:316:0;56871:4;53569:12;;;;;;;;;;;-1:-1:-1;;;;;53569:29:0;;;;;;;;;;;;56887:217;;56930:6;:12;;;;;;;;;;;-1:-1:-1;;;;;56930:29:0;;;;;;;;;:36;;;;56962:4;56930:36;;;57012:12;23368:10;;23289:96;57012:12;-1:-1:-1;;;;;56985:40:0;57003:7;-1:-1:-1;;;;;56985:40:0;56997:4;56985:40;;;;;;;;;;-1:-1:-1;57046:4:0;57039:11;;56887:217;-1:-1:-1;57088:5:0;57081:12;;32813:150;32883:4;32906:50;32911:3;-1:-1:-1;;;;;32931:23:0;;32906:4;:50::i;57345:317::-;57423:4;53569:12;;;;;;;;;;;-1:-1:-1;;;;;53569:29:0;;;;;;;;;;;;57439:217;;;57513:5;57481:12;;;;;;;;;;;-1:-1:-1;;;;;57481:29:0;;;;;;;;;;:37;;;;;;57537:40;23368:10;;57481:12;;57537:40;;57513:5;57537:40;-1:-1:-1;57598:4:0;57591:11;;33131:156;33204:4;33227:53;33235:3;-1:-1:-1;;;;;33255:23:0;;33227:7;:53::i;29420:118::-;29487:7;29513:3;:11;;29525:5;29513:18;;;;;;;;:::i;:::-;;;;;;;;;29506:25;;29420:118;;;;:::o;49053:629::-;49472:23;49498:33;-1:-1:-1;;;;;49498:27:0;;49526:4;49498:27;:33::i;:::-;49472:59;;49545:10;:17;49566:1;49545:22;;:57;;;;;49583:10;49572:30;;;;;;;;;;;;:::i;:::-;49571:31;49545:57;49541:135;;;49625:40;;;;;-1:-1:-1;;;;;12205:55:1;;49625:40:0;;;12187:74:1;12160:18;;49625:40:0;12041:226:1;19549:392:0;19648:12;19700:5;19676:21;:29;19672:108;;;19728:41;;;;;19763:4;19728:41;;;12187:74:1;12160:18;;19728:41:0;12041:226:1;19672:108:0;19790:12;19804:23;19831:6;-1:-1:-1;;;;;19831:11:0;19850:5;19857:4;19831:31;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;19789:73;;;;19879:55;19906:6;19914:7;19923:10;19879:26;:55::i;:::-;19872:62;19549:392;-1:-1:-1;;;;;;19549:392:0:o;59909:344::-;60076:38;-1:-1:-1;;;;;60076:38:0;;;60072:69;;60123:18;;;;;;;;;;;;;;60072:69;60197:5;-1:-1:-1;;;;;60197:17:0;;60218:1;60197:22;60193:53;;60228:18;;;;;;;;;;;;;;26738:406;26801:4;28857:21;;;:14;;;:21;;;;;;26817:321;;-1:-1:-1;26859:23:0;;;;;;;;:11;:23;;;;;;;;;;;;;27041:18;;27017:21;;;:14;;;:21;;;;;;:42;;;;27073:11;;27312:1368;27378:4;27507:21;;;:14;;;:21;;;;;;27543:13;;27539:1135;;27910:18;27931:12;27942:1;27931:8;:12;:::i;:::-;27977:18;;27910:33;;-1:-1:-1;27957:17:0;;27977:22;;27998:1;;27977:22;:::i;:::-;27957:42;;28032:9;28018:10;:23;28014:378;;28061:17;28081:3;:11;;28093:9;28081:22;;;;;;;;:::i;:::-;;;;;;;;;28061:42;;28228:9;28202:3;:11;;28214:10;28202:23;;;;;;;;:::i;:::-;;;;;;;;;;;;:35;;;;28341:25;;;:14;;;:25;;;;;:36;;;28014:378;28470:17;;:3;;:17;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;28573:3;:14;;:21;28588:5;28573:21;;;;;;;;;;;28566:28;;;28616:4;28609:11;;;;;;;27539:1135;28658:5;28651:12;;;;;19074:151;19149:12;19180:38;19202:6;19210:4;19216:1;19180:21;:38::i;20994:582::-;21138:12;21167:7;21162:408;;21190:19;21198:10;21190:7;:19::i;:::-;21162:408;;;21414:17;;:22;:49;;;;-1:-1:-1;;;;;;21440:18:0;;;:23;21414:49;21410:119;;;21490:24;;;;;-1:-1:-1;;;;;12205:55:1;;21490:24:0;;;12187:74:1;12160:18;;21490:24:0;12041:226:1;21410:119:0;-1:-1:-1;21549:10:0;21542:17;;22112:516;22243:17;;:21;22239:383;;22471:10;22465:17;22527:15;22514:10;22510:2;22506:19;22499:44;22239:383;22594:17;;;;;;;;;;;;;;14:332:1;72:6;125:2;113:9;104:7;100:23;96:32;93:52;;;141:1;138;131:12;93:52;180:9;167:23;230:66;223:5;219:78;212:5;209:89;199:117;;312:1;309;302:12;821:180;880:6;933:2;921:9;912:7;908:23;904:32;901:52;;;949:1;946;939:12;901:52;-1:-1:-1;972:23:1;;821:180;-1:-1:-1;821:180:1:o;1006:184::-;1058:77;1055:1;1048:88;1155:4;1152:1;1145:15;1179:4;1176:1;1169:15;1195:297;1279:1;1272:5;1269:12;1259:200;;1315:77;1312:1;1305:88;1416:4;1413:1;1406:15;1444:4;1441:1;1434:15;1259:200;1468:18;;1195:297::o;1497:214::-;1646:2;1631:18;;1658:47;1635:9;1687:6;1658:47;:::i;1716:154::-;-1:-1:-1;;;;;1795:5:1;1791:54;1784:5;1781:65;1771:93;;1860:1;1857;1850:12;1875:134;1943:20;;1972:31;1943:20;1972:31;:::i;2014:388::-;2082:6;2090;2143:2;2131:9;2122:7;2118:23;2114:32;2111:52;;;2159:1;2156;2149:12;2111:52;2198:9;2185:23;2217:31;2242:5;2217:31;:::i;:::-;2267:5;-1:-1:-1;2324:2:1;2309:18;;2296:32;2337:33;2296:32;2337:33;:::i;:::-;2389:7;2379:17;;;2014:388;;;;;:::o;2589:383::-;2666:6;2674;2682;2735:2;2723:9;2714:7;2710:23;2706:32;2703:52;;;2751:1;2748;2741:12;2703:52;2787:9;2774:23;2764:33;;2844:2;2833:9;2829:18;2816:32;2806:42;;2898:2;2887:9;2883:18;2870:32;2911:31;2936:5;2911:31;:::i;:::-;2961:5;2951:15;;;2589:383;;;;;:::o;2977:247::-;3036:6;3089:2;3077:9;3068:7;3064:23;3060:32;3057:52;;;3105:1;3102;3095:12;3057:52;3144:9;3131:23;3163:31;3188:5;3163:31;:::i;3229:315::-;3297:6;3305;3358:2;3346:9;3337:7;3333:23;3329:32;3326:52;;;3374:1;3371;3364:12;3326:52;3410:9;3397:23;3387:33;;3470:2;3459:9;3455:18;3442:32;3483:31;3508:5;3483:31;:::i;3549:184::-;3601:77;3598:1;3591:88;3698:4;3695:1;3688:15;3722:4;3719:1;3712:15;3738:255;3810:2;3804:9;3852:6;3840:19;;3889:18;3874:34;;3910:22;;;3871:62;3868:88;;;3936:18;;:::i;:::-;3972:2;3965:22;3738:255;:::o;3998:253::-;4070:2;4064:9;4112:4;4100:17;;4147:18;4132:34;;4168:22;;;4129:62;4126:88;;;4194:18;;:::i;4256:255::-;4328:2;4322:9;4370:6;4358:19;;4407:18;4392:34;;4428:22;;;4389:62;4386:88;;;4454:18;;:::i;4516:252::-;4588:2;4582:9;4630:3;4618:16;;4664:18;4649:34;;4685:22;;;4646:62;4643:88;;;4711:18;;:::i;4773:334::-;4844:2;4838:9;4900:2;4890:13;;-1:-1:-1;;4886:86:1;4874:99;;5003:18;4988:34;;5024:22;;;4985:62;4982:88;;;5050:18;;:::i;:::-;5086:2;5079:22;4773:334;;-1:-1:-1;4773:334:1:o;5112:245::-;5160:4;5193:18;5185:6;5182:30;5179:56;;;5215:18;;:::i;:::-;-1:-1:-1;5272:2:1;5260:15;-1:-1:-1;;5256:88:1;5346:4;5252:99;;5112:245::o;5362:462::-;5404:5;5457:3;5450:4;5442:6;5438:17;5434:27;5424:55;;5475:1;5472;5465:12;5424:55;5511:6;5498:20;5542:48;5558:31;5586:2;5558:31;:::i;:::-;5542:48;:::i;:::-;5615:2;5606:7;5599:19;5661:3;5654:4;5649:2;5641:6;5637:15;5633:26;5630:35;5627:55;;;5678:1;5675;5668:12;5627:55;5743:2;5736:4;5728:6;5724:17;5717:4;5708:7;5704:18;5691:55;5791:1;5766:16;;;5784:4;5762:27;5755:38;;;;5770:7;5362:462;-1:-1:-1;;;5362:462:1:o;5829:455::-;5906:6;5914;5967:2;5955:9;5946:7;5942:23;5938:32;5935:52;;;5983:1;5980;5973:12;5935:52;6023:9;6010:23;6056:18;6048:6;6045:30;6042:50;;;6088:1;6085;6078:12;6042:50;6111:49;6152:7;6143:6;6132:9;6128:22;6111:49;:::i;:::-;6101:59;;;6210:2;6199:9;6195:18;6182:32;6223:31;6248:5;6223:31;:::i;6289:121::-;6374:10;6367:5;6363:22;6356:5;6353:33;6343:61;;6400:1;6397;6390:12;6415:132;6482:20;;6511:30;6482:20;6511:30;:::i;6552:118::-;6638:5;6631:13;6624:21;6617:5;6614:32;6604:60;;6660:1;6657;6650:12;6675:128;6740:20;;6769:28;6740:20;6769:28;:::i;6808:806::-;6867:5;6915:6;6903:9;6898:3;6894:19;6890:32;6887:52;;;6935:1;6932;6925:12;6887:52;6957:22;;:::i;:::-;6948:31;;7002:28;7020:9;7002:28;:::i;:::-;6995:5;6988:43;7063:38;7097:2;7086:9;7082:18;7063:38;:::i;:::-;7058:2;7051:5;7047:14;7040:62;7134:38;7168:2;7157:9;7153:18;7134:38;:::i;:::-;7129:2;7122:5;7118:14;7111:62;7205:38;7239:2;7228:9;7224:18;7205:38;:::i;:::-;7200:2;7193:5;7189:14;7182:62;7277:39;7311:3;7300:9;7296:19;7277:39;:::i;:::-;7271:3;7264:5;7260:15;7253:64;7378:3;7367:9;7363:19;7350:33;7344:3;7337:5;7333:15;7326:58;7445:3;7434:9;7430:19;7417:33;7411:3;7404:5;7400:15;7393:58;7484:36;7515:3;7504:9;7500:19;7484:36;:::i;:::-;7478:3;7471:5;7467:15;7460:61;7540:3;7603:2;7592:9;7588:18;7575:32;7570:2;7563:5;7559:14;7552:56;;6808:806;;;;:::o;7619:237::-;7707:6;7760:3;7748:9;7739:7;7735:23;7731:33;7728:53;;;7777:1;7774;7767:12;7728:53;7800:50;7842:7;7831:9;7800:50;:::i;7861:320::-;7929:6;7982:2;7970:9;7961:7;7957:23;7953:32;7950:52;;;7998:1;7995;7988:12;7950:52;8038:9;8025:23;8071:18;8063:6;8060:30;8057:50;;;8103:1;8100;8093:12;8057:50;8126:49;8167:7;8158:6;8147:9;8143:22;8126:49;:::i;:::-;8116:59;7861:320;-1:-1:-1;;;;7861:320:1:o;8417:250::-;8502:1;8512:113;8526:6;8523:1;8520:13;8512:113;;;8602:11;;;8596:18;8583:11;;;8576:39;8548:2;8541:10;8512:113;;;-1:-1:-1;;8659:1:1;8641:16;;8634:27;8417:250::o;8672:329::-;8713:3;8751:5;8745:12;8778:6;8773:3;8766:19;8794:76;8863:6;8856:4;8851:3;8847:14;8840:4;8833:5;8829:16;8794:76;:::i;:::-;8915:2;8903:15;-1:-1:-1;;8899:88:1;8890:98;;;;8990:4;8886:109;;8672:329;-1:-1:-1;;8672:329:1:o;9006:1866::-;9209:2;9198:9;9191:21;9221:52;9269:2;9258:9;9254:18;9245:6;9239:13;8262:10;8251:22;8239:35;;8186:94;9221:52;9172:4;9320:2;9312:6;9308:15;9302:22;9333:51;9380:2;9369:9;9365:18;9351:12;8262:10;8251:22;8239:35;;8186:94;9333:51;-1:-1:-1;9433:2:1;9421:15;;9415:22;-1:-1:-1;;;;;8351:54:1;;9496:2;9481:18;;8339:67;-1:-1:-1;9549:2:1;9537:15;;9531:22;-1:-1:-1;;;;;8351:54:1;;9612:3;9597:19;;8339:67;-1:-1:-1;9666:3:1;9654:16;;9648:23;-1:-1:-1;;;;;8351:54:1;;9730:3;9715:19;;8339:67;-1:-1:-1;9784:3:1;9772:16;;9766:23;-1:-1:-1;;;;;8351:54:1;;9848:3;9833:19;;8339:67;-1:-1:-1;9908:3:1;9896:16;;9890:23;9884:3;9869:19;;;9862:52;;;;9939:16;;9933:23;9975:3;9994:18;;;9987:30;;;;10042:15;;10036:22;10077:3;10096:18;;;10089:30;;;;10144:15;;10138:22;10179:3;10198:18;;;10191:30;;;;10246:15;;10240:22;10281:3;10300:18;;;10293:30;;;;10348:15;;10342:22;10384:3;10403:19;;;10396:31;;;;10464:16;;10458:23;10501:3;10513:55;10548:19;;;10458:23;-1:-1:-1;;;;;8351:54:1;8339:67;;8285:127;10513:55;10594:16;;10588:23;10631:3;10650:19;;;10643:32;;;;10712:16;;10706:23;10749:6;10771:19;;;10764:32;10706:23;-1:-1:-1;10813:53:1;10861:3;10846:19;;10706:23;10813:53;:::i;10877:513::-;11106:3;11091:19;;11119:47;11095:9;11148:6;11119:47;:::i;:::-;11214:12;11206:6;11202:25;11197:2;11186:9;11182:18;11175:53;11276:14;11268:6;11264:27;11259:2;11248:9;11244:18;11237:55;-1:-1:-1;;;;;11332:6:1;11328:55;11323:2;11312:9;11308:18;11301:83;10877:513;;;;;;;:::o;11395:388::-;11472:6;11480;11533:2;11521:9;11512:7;11508:23;11504:32;11501:52;;;11549:1;11546;11539:12;11501:52;11589:9;11576:23;11622:18;11614:6;11611:30;11608:50;;;11654:1;11651;11644:12;11608:50;11677:49;11718:7;11709:6;11698:9;11694:22;11677:49;:::i;:::-;11667:59;11773:2;11758:18;;;;11745:32;;-1:-1:-1;;;;11395:388:1:o;11788:248::-;11856:6;11864;11917:2;11905:9;11896:7;11892:23;11888:32;11885:52;;;11933:1;11930;11923:12;11885:52;-1:-1:-1;;11956:23:1;;;12026:2;12011:18;;;11998:32;;-1:-1:-1;11788:248:1:o;12605:1373::-;12836:13;;8262:10;8251:22;8239:35;;12805:3;12790:19;;12908:4;12900:6;12896:17;12890:24;12923:53;12970:4;12959:9;12955:20;12941:12;8262:10;8251:22;8239:35;;8186:94;12923:53;;13025:4;13017:6;13013:17;13007:24;13040:56;13090:4;13079:9;13075:20;13059:14;-1:-1:-1;;;;;8351:54:1;8339:67;;8285:127;13040:56;;13145:4;13137:6;13133:17;13127:24;13160:56;13210:4;13199:9;13195:20;13179:14;-1:-1:-1;;;;;8351:54:1;8339:67;;8285:127;13160:56;;13265:4;13257:6;13253:17;13247:24;13280:56;13330:4;13319:9;13315:20;13299:14;-1:-1:-1;;;;;8351:54:1;8339:67;;8285:127;13280:56;;13385:4;13377:6;13373:17;13367:24;13400:56;13450:4;13439:9;13435:20;13419:14;-1:-1:-1;;;;;8351:54:1;8339:67;;8285:127;13400:56;;13512:4;13504:6;13500:17;13494:24;13487:4;13476:9;13472:20;13465:54;13575:4;13567:6;13563:17;13557:24;13550:4;13539:9;13535:20;13528:54;13601:6;13661:2;13653:6;13649:15;13643:22;13638:2;13627:9;13623:18;13616:50;;13685:6;13740:2;13732:6;13728:15;13722:22;13753:51;13800:2;13789:9;13785:18;13769:14;421:13;414:21;402:34;;351:91;13753:51;-1:-1:-1;;13823:6:1;13871:15;;;13865:22;13845:18;;;13838:50;13907:6;13955:15;;;13949:22;13929:18;;;;13922:50;;;;12605:1373;:::o;14168:1162::-;14297:6;14305;14358:3;14346:9;14337:7;14333:23;14329:33;14326:53;;;14375:1;14372;14365:12;14326:53;14398:50;14440:7;14429:9;14398:50;:::i;:::-;14388:60;;14499:3;14488:9;14484:19;14471:33;14523:18;14564:2;14556:6;14553:14;14550:34;;;14580:1;14577;14570:12;14550:34;14603:22;;;;14659:4;14641:16;;;14637:27;14634:47;;;14677:1;14674;14667:12;14634:47;14703:22;;:::i;:::-;14762:2;14749:16;14774:33;14799:7;14774:33;:::i;:::-;14816:22;;14891:2;14883:11;;;14870:25;14854:14;;;14847:49;14942:2;14934:11;;14921:25;14958:16;;;14955:36;;;14987:1;14984;14977:12;14955:36;15023:44;15059:7;15048:8;15044:2;15040:17;15023:44;:::i;:::-;15018:2;15011:5;15007:14;15000:68;;15121:2;15117;15113:11;15100:25;15095:2;15088:5;15084:14;15077:49;15172:3;15168:2;15164:12;15151:26;15202:2;15192:8;15189:16;15186:36;;;15218:1;15215;15208:12;15186:36;15255:44;15291:7;15280:8;15276:2;15272:17;15255:44;:::i;:::-;15249:3;15242:5;15238:15;15231:69;;15319:5;15309:15;;;;;14168:1162;;;;;:::o;16158:184::-;16210:77;16207:1;16200:88;16307:4;16304:1;16297:15;16331:4;16328:1;16321:15;16347:125;16412:9;;;16433:10;;;16430:36;;;16446:18;;:::i;16779:136::-;16857:13;;16879:30;16857:13;16879:30;:::i;16920:138::-;16999:13;;17021:31;16999:13;17021:31;:::i;17063:441::-;17116:5;17169:3;17162:4;17154:6;17150:17;17146:27;17136:55;;17187:1;17184;17177:12;17136:55;17216:6;17210:13;17247:48;17263:31;17291:2;17263:31;:::i;17247:48::-;17320:2;17311:7;17304:19;17366:3;17359:4;17354:2;17346:6;17342:15;17338:26;17335:35;17332:55;;;17383:1;17380;17373:12;17332:55;17396:77;17470:2;17463:4;17454:7;17450:18;17443:4;17435:6;17431:17;17396:77;:::i;17509:1672::-;17616:6;17669:2;17657:9;17648:7;17644:23;17640:32;17637:52;;;17685:1;17682;17675:12;17637:52;17718:9;17712:16;17747:18;17788:2;17780:6;17777:14;17774:34;;;17804:1;17801;17794:12;17774:34;17827:22;;;;17883:6;17865:16;;;17861:29;17858:49;;;17903:1;17900;17893:12;17858:49;17929:22;;:::i;:::-;17974:32;18003:2;17974:32;:::i;:::-;17967:5;17960:47;18039:41;18076:2;18072;18068:11;18039:41;:::i;:::-;18034:2;18027:5;18023:14;18016:65;18113:42;18151:2;18147;18143:11;18113:42;:::i;:::-;18108:2;18101:5;18097:14;18090:66;18188:42;18226:2;18222;18218:11;18188:42;:::i;:::-;18183:2;18176:5;18172:14;18165:66;18264:43;18302:3;18298:2;18294:12;18264:43;:::i;:::-;18258:3;18251:5;18247:15;18240:68;18341:43;18379:3;18375:2;18371:12;18341:43;:::i;:::-;18335:3;18324:15;;18317:68;18432:3;18424:12;;;18418:19;18401:15;;;18394:44;18485:3;18477:12;;;18471:19;18454:15;;;18447:44;18510:3;18551:11;;;18545:18;18529:14;;;18522:42;18583:3;18624:11;;;18618:18;18602:14;;;18595:42;18656:3;18697:11;;;18691:18;18675:14;;;18668:42;18729:3;18770:11;;;18764:18;18748:14;;;18741:42;18802:3;18837:42;18867:11;;;18837:42;:::i;:::-;18821:14;;;18814:66;18899:3;18940:11;;;18934:18;18918:14;;;18911:42;18972:3;19006:11;;;19000:18;19030:16;;;19027:36;;;19059:1;19056;19049:12;19027:36;19095:55;19142:7;19131:8;19127:2;19123:17;19095:55;:::i;:::-;19079:14;;;19072:79;;;;-1:-1:-1;19083:5:1;17509:1672;-1:-1:-1;;;;;17509:1672:1:o;19820:217::-;19967:2;19956:9;19949:21;19930:4;19987:44;20027:2;20016:9;20012:18;20004:6;19987:44;:::i;20042:132::-;20118:13;;20140:28;20118:13;20140:28;:::i;20179:1188::-;20282:6;20335:3;20323:9;20314:7;20310:23;20306:33;20303:53;;;20352:1;20349;20342:12;20303:53;20378:22;;:::i;:::-;20423:39;20452:9;20423:39;:::i;:::-;20416:5;20409:54;20495:48;20539:2;20528:9;20524:18;20495:48;:::i;:::-;20490:2;20483:5;20479:14;20472:72;20576:49;20621:2;20610:9;20606:18;20576:49;:::i;:::-;20571:2;20564:5;20560:14;20553:73;20658:49;20703:2;20692:9;20688:18;20658:49;:::i;:::-;20653:2;20646:5;20642:14;20635:73;20741:50;20786:3;20775:9;20771:19;20741:50;:::i;:::-;20735:3;20728:5;20724:15;20717:75;20825:50;20870:3;20859:9;20855:19;20825:50;:::i;:::-;20819:3;20812:5;20808:15;20801:75;20930:3;20919:9;20915:19;20909:26;20903:3;20896:5;20892:15;20885:51;20990:3;20979:9;20975:19;20969:26;20963:3;20956:5;20952:15;20945:51;21015:3;21071:2;21060:9;21056:18;21050:25;21045:2;21038:5;21034:14;21027:49;;21095:3;21130:46;21172:2;21161:9;21157:18;21130:46;:::i;:::-;21114:14;;;21107:70;21196:3;21237:18;;;21231:25;21215:14;;;21208:49;21276:3;21317:18;;;21311:25;21295:14;;;21288:49;;;;-1:-1:-1;21118:5:1;20179:1188;-1:-1:-1;20179:1188:1:o;21970:216::-;22034:9;;;22062:11;;;22009:3;22092:9;;22120:10;;22116:19;;22145:10;;22137:19;;22113:44;22110:70;;;22160:18;;:::i;:::-;22110:70;;21970:216;;;;:::o;22191:168::-;22264:9;;;22295;;22312:15;;;22306:22;;22292:37;22282:71;;22333:18;;:::i;22364:274::-;22404:1;22430;22420:189;;22465:77;22462:1;22455:88;22566:4;22563:1;22556:15;22594:4;22591:1;22584:15;22420:189;-1:-1:-1;22623:9:1;;22364:274::o;22643:128::-;22710:9;;;22731:11;;;22728:37;;;22745:18;;:::i;22776:195::-;22815:3;22846:66;22839:5;22836:77;22833:103;;22916:18;;:::i;:::-;-1:-1:-1;22963:1:1;22952:13;;22776:195::o;22976:752::-;23283:3;23272:9;23265:22;23246:4;23304:45;23344:3;23333:9;23329:19;23321:6;23304:45;:::i;:::-;23397:10;23385:23;;;;23380:2;23365:18;;23358:51;-1:-1:-1;;;;;;23506:15:1;;;23501:2;23486:18;;23479:43;23558:15;;;;23553:2;23538:18;;23531:43;23605:3;23590:19;;23583:35;;;;23649:3;23634:19;;23627:35;23706:14;;23699:22;23693:3;23678:19;;;23671:51;23296:53;22976:752;-1:-1:-1;22976:752:1:o;24291:408::-;-1:-1:-1;;;;;24498:6:1;24494:55;24483:9;24476:74;24586:6;24581:2;24570:9;24566:18;24559:34;24629:2;24624;24613:9;24609:18;24602:30;24457:4;24649:44;24689:2;24678:9;24674:18;24666:6;24649:44;:::i;:::-;24641:52;24291:408;-1:-1:-1;;;;;24291:408:1:o;24704:357::-;24822:12;;24869:4;24858:16;;;24852:23;;24822:12;24887:16;;24884:171;;;24977:66;24967:6;24961:4;24957:17;24954:1;24950:25;24946:98;24939:5;24935:110;24926:119;;24884:171;;24704:357;;;:::o;25066:184::-;25136:6;25189:2;25177:9;25168:7;25164:23;25160:32;25157:52;;;25205:1;25202;25195:12;25157:52;-1:-1:-1;25228:16:1;;25066:184;-1:-1:-1;25066:184:1:o;25557:::-;25609:77;25606:1;25599:88;25706:4;25703:1;25696:15;25730:4;25727:1;25720:15;25746:245;25813:6;25866:2;25854:9;25845:7;25841:23;25837:32;25834:52;;;25882:1;25879;25872:12;25834:52;25914:9;25908:16;25933:28;25955:5;25933:28;:::i;25996:287::-;26125:3;26163:6;26157:13;26179:66;26238:6;26233:3;26226:4;26218:6;26214:17;26179:66;:::i;:::-;26261:16;;;;;25996:287;-1:-1:-1;;25996:287:1:o;26288:184::-;26340:77;26337:1;26330:88;26437:4;26434:1;26427:15;26461:4;26458:1;26451:15","abiDefinition":[{"inputs":[{"internalType":"address","name":"_owner","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AccessControlBadConfirmation","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"bytes32","name":"neededRole","type":"bytes32"}],"name":"AccessControlUnauthorizedAccount","type":"error"},{"inputs":[{"internalType":"address","name":"target","type":"address"}],"name":"AddressEmptyCode","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"AddressInsufficientBalance","type":"error"},{"inputs":[],"name":"AmountIncorrect","type":"error"},{"inputs":[],"name":"CallParamsLengthAboveMax","type":"error"},{"inputs":[],"name":"ChainIncorrect","type":"error"},{"inputs":[],"name":"DeadlineExceeded","type":"error"},{"inputs":[],"name":"DeadlineNotExceeded","type":"error"},{"inputs":[],"name":"DeadlineTooShort","type":"error"},{"inputs":[],"name":"DisputePeriodNotPassed","type":"error"},{"inputs":[],"name":"DisputePeriodPassed","type":"error"},{"inputs":[],"name":"ExclusivityParamsIncorrect","type":"error"},{"inputs":[],"name":"ExclusivityPeriodNotPassed","type":"error"},{"inputs":[],"name":"FailedInnerCall","type":"error"},{"inputs":[],"name":"MsgValueIncorrect","type":"error"},{"inputs":[],"name":"NativeTokenCallValueNotSupported","type":"error"},{"inputs":[],"name":"RecipientIncorrectReturnValue","type":"error"},{"inputs":[],"name":"RecipientNoReturnValue","type":"error"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"SafeERC20FailedOperation","type":"error"},{"inputs":[],"name":"SenderIncorrect","type":"error"},{"inputs":[],"name":"StatusIncorrect","type":"error"},{"inputs":[],"name":"TokenNotContract","type":"error"},{"inputs":[],"name":"TransactionRelayed","type":"error"},{"inputs":[],"name":"ZeroAddress","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"relayer","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"BridgeDepositClaimed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"BridgeDepositRefunded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"relayer","type":"address"}],"name":"BridgeProofDisputed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"relayer","type":"address"},{"indexed":false,"internalType":"bytes32","name":"transactionHash","type":"bytes32"}],"name":"BridgeProofProvided","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":false,"internalType":"bytes","name":"quoteId","type":"bytes"}],"name":"BridgeQuoteDetails","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"relayer","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint32","name":"originChainId","type":"uint32"},{"indexed":false,"internalType":"address","name":"originToken","type":"address"},{"indexed":false,"internalType":"address","name":"destToken","type":"address"},{"indexed":false,"internalType":"uint256","name":"originAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"destAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"chainGasAmount","type":"uint256"}],"name":"BridgeRelayed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"bytes","name":"request","type":"bytes"},{"indexed":false,"internalType":"uint32","name":"destChainId","type":"uint32"},{"indexed":false,"internalType":"address","name":"originToken","type":"address"},{"indexed":false,"internalType":"address","name":"destToken","type":"address"},{"indexed":false,"internalType":"uint256","name":"originAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"destAmount","type":"uint256"},{"indexed":false,"internalType":"bool","name":"sendChainGas","type":"bool"}],"name":"BridgeRequested","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldChainGasAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newChainGasAmount","type":"uint256"}],"name":"ChainGasAmountUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldFeeRate","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newFeeRate","type":"uint256"}],"name":"FeeRateUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"address","name":"recipient","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"FeesSwept","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"previousAdminRole","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"newAdminRole","type":"bytes32"}],"name":"RoleAdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleRevoked","type":"event"},{"inputs":[],"name":"DEFAULT_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"DISPUTE_PERIOD","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"FEE_BPS","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"FEE_RATE_MAX","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"GOVERNOR_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"GUARD_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_CALL_PARAMS_LENGTH","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MIN_DEADLINE_PERIOD","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"REFUNDER_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"REFUND_DELAY","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"RELAYER_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"uint32","name":"dstChainId","type":"uint32"},{"internalType":"address","name":"sender","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"address","name":"originToken","type":"address"},{"internalType":"address","name":"destToken","type":"address"},{"internalType":"uint256","name":"originAmount","type":"uint256"},{"internalType":"uint256","name":"destAmount","type":"uint256"},{"internalType":"bool","name":"sendChainGas","type":"bool"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"internalType":"struct IFastBridge.BridgeParams","name":"params","type":"tuple"}],"name":"bridge","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"uint32","name":"dstChainId","type":"uint32"},{"internalType":"address","name":"sender","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"address","name":"originToken","type":"address"},{"internalType":"address","name":"destToken","type":"address"},{"internalType":"uint256","name":"originAmount","type":"uint256"},{"internalType":"uint256","name":"destAmount","type":"uint256"},{"internalType":"bool","name":"sendChainGas","type":"bool"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"internalType":"struct IFastBridge.BridgeParams","name":"params","type":"tuple"},{"components":[{"internalType":"address","name":"quoteRelayer","type":"address"},{"internalType":"int256","name":"quoteExclusivitySeconds","type":"int256"},{"internalType":"bytes","name":"quoteId","type":"bytes"},{"internalType":"uint256","name":"callValue","type":"uint256"},{"internalType":"bytes","name":"callParams","type":"bytes"}],"internalType":"struct IFastBridgeV2.BridgeParamsV2","name":"paramsV2","type":"tuple"}],"name":"bridge","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"transactionId","type":"bytes32"}],"name":"bridgeProofs","outputs":[{"internalType":"uint96","name":"timestamp","type":"uint96"},{"internalType":"address","name":"relayer","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"bridgeRelayDetails","outputs":[{"internalType":"uint48","name":"blockNumber","type":"uint48"},{"internalType":"uint48","name":"blockTimestamp","type":"uint48"},{"internalType":"address","name":"relayer","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"transactionId","type":"bytes32"}],"name":"bridgeRelays","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"transactionId","type":"bytes32"}],"name":"bridgeStatuses","outputs":[{"internalType":"enum IFastBridgeV2.BridgeStatus","name":"status","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"bridgeTxDetails","outputs":[{"internalType":"enum IFastBridgeV2.BridgeStatus","name":"status","type":"uint8"},{"internalType":"uint40","name":"proofBlockTimestamp","type":"uint40"},{"internalType":"uint48","name":"proofBlockNumber","type":"uint48"},{"internalType":"address","name":"proofRelayer","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"internalType":"address","name":"relayer","type":"address"}],"name":"canClaim","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"chainGasAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"},{"internalType":"address","name":"to","type":"address"}],"name":"claim","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"}],"name":"claim","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"deployBlock","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"transactionId","type":"bytes32"}],"name":"dispute","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"}],"name":"getBridgeTransaction","outputs":[{"components":[{"internalType":"uint32","name":"originChainId","type":"uint32"},{"internalType":"uint32","name":"destChainId","type":"uint32"},{"internalType":"address","name":"originSender","type":"address"},{"internalType":"address","name":"destRecipient","type":"address"},{"internalType":"address","name":"originToken","type":"address"},{"internalType":"address","name":"destToken","type":"address"},{"internalType":"uint256","name":"originAmount","type":"uint256"},{"internalType":"uint256","name":"destAmount","type":"uint256"},{"internalType":"uint256","name":"originFeeAmount","type":"uint256"},{"internalType":"bool","name":"sendChainGas","type":"bool"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint256","name":"nonce","type":"uint256"}],"internalType":"struct IFastBridge.BridgeTransaction","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"}],"name":"getBridgeTransactionV2","outputs":[{"components":[{"internalType":"uint32","name":"originChainId","type":"uint32"},{"internalType":"uint32","name":"destChainId","type":"uint32"},{"internalType":"address","name":"originSender","type":"address"},{"internalType":"address","name":"destRecipient","type":"address"},{"internalType":"address","name":"originToken","type":"address"},{"internalType":"address","name":"destToken","type":"address"},{"internalType":"uint256","name":"originAmount","type":"uint256"},{"internalType":"uint256","name":"destAmount","type":"uint256"},{"internalType":"uint256","name":"originFeeAmount","type":"uint256"},{"internalType":"uint256","name":"callValue","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"address","name":"exclusivityRelayer","type":"address"},{"internalType":"uint256","name":"exclusivityEndTime","type":"uint256"},{"internalType":"bytes","name":"callParams","type":"bytes"}],"internalType":"struct IFastBridgeV2.BridgeTransactionV2","name":"","type":"tuple"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleAdmin","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"uint256","name":"index","type":"uint256"}],"name":"getRoleMember","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleMemberCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"grantRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"hasRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"nonce","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"protocolFeeRate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"protocolFees","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"internalType":"bytes32","name":"destTxHash","type":"bytes32"},{"internalType":"address","name":"relayer","type":"address"}],"name":"prove","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"},{"internalType":"bytes32","name":"destTxHash","type":"bytes32"}],"name":"prove","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"}],"name":"refund","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"}],"name":"relay","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"},{"internalType":"address","name":"relayer","type":"address"}],"name":"relay","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"callerConfirmation","type":"address"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"revokeRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"senderNonces","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"newChainGasAmount","type":"uint256"}],"name":"setChainGasAmount","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"newFeeRate","type":"uint256"}],"name":"setProtocolFeeRate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"address","name":"recipient","type":"address"}],"name":"sweepProtocolFees","outputs":[],"stateMutability":"nonpayable","type":"function"}],"userDoc":{"kind":"user","methods":{"DISPUTE_PERIOD()":{"notice":"Dispute period for relayed transactions"},"MAX_CALL_PARAMS_LENGTH()":{"notice":"Maximum length of accepted callParams"},"MIN_DEADLINE_PERIOD()":{"notice":"Minimum deadline period to relay a requested bridge transaction"},"REFUND_DELAY()":{"notice":"Delay for a transaction after which it could be permisionlessly refunded"},"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256))":{"notice":"Initiates bridge on origin chain to be relayed by off-chain relayer"},"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256),(address,int256,bytes,uint256,bytes))":{"notice":"Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability to provide temporary exclusivity fill rights for the quote relayer."},"bridgeProofs(bytes32)":{"notice":"Returns the timestamp and relayer of a bridge proof"},"bridgeRelayDetails(bytes32)":{"notice":"Relay details on destination chain"},"bridgeRelays(bytes32)":{"notice":"Checks if a transaction has been relayed"},"bridgeStatuses(bytes32)":{"notice":"Returns the status of a bridge transaction"},"bridgeTxDetails(bytes32)":{"notice":"Status of the bridge tx on origin chain"},"canClaim(bytes32,address)":{"notice":"Checks if the dispute period has passed so bridge deposit can be claimed"},"chainGasAmount()":{"notice":"Chain gas amount to forward as rebate if requested"},"claim(bytes)":{"notice":"Completes bridge transaction on origin chain by claiming originally deposited capital.Can only send funds to the relayer address on the proof."},"claim(bytes,address)":{"notice":"Completes bridge transaction on origin chain by claiming originally deposited capital"},"deployBlock()":{"notice":"the block the contract was deployed at"},"dispute(bytes32)":{"notice":"Disputes an outstanding proof in case relayer provided dest chain tx is invalid"},"getBridgeTransaction(bytes)":{"notice":"Decodes bridge request into a bridge transaction"},"getBridgeTransactionV2(bytes)":{"notice":"Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2"},"nonce()":{"notice":"This is deprecated and should not be used."},"protocolFeeRate()":{"notice":"Protocol fee rate taken on origin amount deposited in origin chain"},"protocolFees(address)":{"notice":"Protocol fee amounts accumulated"},"prove(bytes,bytes32)":{"notice":"Provides proof on origin side that relayer provided funds on destination side of bridge transaction"},"prove(bytes32,bytes32,address)":{"notice":"Provides proof on origin side that relayer provided funds on destination side of bridge transaction"},"refund(bytes)":{"notice":"Refunds an outstanding bridge transaction in case optimistic bridging failed"},"relay(bytes)":{"notice":"Relays destination side of bridge transaction by off-chain relayer"},"relay(bytes,address)":{"notice":"Relays destination side of bridge transaction by off-chain relayer"},"senderNonces(address)":{"notice":"Unique bridge nonces tracked per originSender"}},"notice":"FastBridgeV2 is a contract for bridging tokens across chains.","version":1},"developerDoc":{"errors":{"AccessControlBadConfirmation()":[{"details":"The caller of a function is not the expected one. NOTE: Don't confuse with {AccessControlUnauthorizedAccount}."}],"AccessControlUnauthorizedAccount(address,bytes32)":[{"details":"The `account` is missing a role."}],"AddressEmptyCode(address)":[{"details":"There's no code at `target` (it is not a contract)."}],"AddressInsufficientBalance(address)":[{"details":"The ETH balance of the account is not enough to perform the operation."}],"FailedInnerCall()":[{"details":"A call to an address target failed. The target may have reverted."}],"SafeERC20FailedOperation(address)":[{"details":"An operation with an ERC20 token failed."}]},"events":{"RoleAdminChanged(bytes32,bytes32,bytes32)":{"details":"Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole` `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite {RoleAdminChanged} not being emitted signaling this."},"RoleGranted(bytes32,address,address)":{"details":"Emitted when `account` is granted `role`. `sender` is the account that originated the contract call, an admin role bearer except when using {AccessControl-_setupRole}."},"RoleRevoked(bytes32,address,address)":{"details":"Emitted when `account` is revoked `role`. `sender` is the account that originated the contract call: - if using `revokeRole`, it is the admin role bearer - if using `renounceRole`, it is the role bearer (i.e. `account`)"}},"kind":"dev","methods":{"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256))":{"params":{"params":"The parameters required to bridge"}},"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256),(address,int256,bytes,uint256,bytes))":{"params":{"params":"The parameters required to bridge","paramsV2":"The parameters for exclusivity fill rights (optional, can be left empty)"}},"bridgeProofs(bytes32)":{"params":{"transactionId":"The ID of the bridge transaction"},"returns":{"relayer":"The relayer address of the bridge proof","timestamp":"The timestamp of the bridge proof"}},"bridgeRelays(bytes32)":{"params":{"transactionId":"The ID of the transaction to check"},"returns":{"_0":"True if the transaction has been relayed, false otherwise"}},"bridgeStatuses(bytes32)":{"params":{"transactionId":"The ID of the bridge transaction"},"returns":{"status":"BridgeStatus Status of the bridge transaction"}},"canClaim(bytes32,address)":{"params":{"relayer":"The address of the relayer attempting to claim","transactionId":"The transaction id associated with the encoded bridge transaction to check"}},"claim(bytes)":{"params":{"request":"The encoded bridge transaction to claim on origin chain"}},"claim(bytes,address)":{"params":{"request":"The encoded bridge transaction to claim on origin chain","to":"The recipient address of the funds"}},"dispute(bytes32)":{"params":{"transactionId":"The transaction id associated with the encoded bridge transaction to dispute"}},"getBridgeTransaction(bytes)":{"details":"This method is added to achieve backwards compatibility with decoding requests into V1 structs: - `callValue` is partially reported as a zero/non-zero flag - `callParams` is ignored In order to process all kinds of requests use getBridgeTransactionV2 instead.","params":{"request":"The bridge request to decode"}},"getBridgeTransactionV2(bytes)":{"params":{"request":"The bridge request to decode"}},"getRoleAdmin(bytes32)":{"details":"Returns the admin role that controls `role`. See {grantRole} and {revokeRole}. To change a role's admin, use {_setRoleAdmin}."},"getRoleMember(bytes32,uint256)":{"details":"Returns one of the accounts that have `role`. `index` must be a value between 0 and {getRoleMemberCount}, non-inclusive. Role bearers are not sorted in any particular way, and their ordering may change at any point. WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure you perform all queries on the same block. See the following https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post] for more information."},"getRoleMemberCount(bytes32)":{"details":"Returns the number of accounts that have `role`. Can be used together with {getRoleMember} to enumerate all bearers of a role."},"grantRole(bytes32,address)":{"details":"Grants `role` to `account`. If `account` had not been already granted `role`, emits a {RoleGranted} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleGranted} event."},"hasRole(bytes32,address)":{"details":"Returns `true` if `account` has been granted `role`."},"prove(bytes,bytes32)":{"params":{"destTxHash":"The destination tx hash proving bridge transaction was relayed","request":"The encoded bridge transaction to prove on origin chain"}},"prove(bytes32,bytes32,address)":{"params":{"destTxHash":"The destination tx hash proving bridge transaction was relayed","relayer":"The address of the relaying entity which should have control of the origin funds when claimed","transactionId":"The transaction id associated with the encoded bridge transaction to prove"}},"refund(bytes)":{"params":{"request":"The encoded bridge transaction to refund"}},"relay(bytes)":{"params":{"request":"The encoded bridge transaction to relay on destination chain"}},"relay(bytes,address)":{"params":{"relayer":"The address of the relaying entity which should have control of the origin funds when claimed","request":"The encoded bridge transaction to relay on destination chain"}},"renounceRole(bytes32,address)":{"details":"Revokes `role` from the calling account. Roles are often managed via {grantRole} and {revokeRole}: this function's purpose is to provide a mechanism for accounts to lose their privileges if they are compromised (such as when a trusted device is misplaced). If the calling account had been revoked `role`, emits a {RoleRevoked} event. Requirements: - the caller must be `callerConfirmation`. May emit a {RoleRevoked} event."},"revokeRole(bytes32,address)":{"details":"Revokes `role` from `account`. If `account` had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleRevoked} event."},"supportsInterface(bytes4)":{"details":"See {IERC165-supportsInterface}."}},"stateVariables":{"nonce":{"details":"Replaced by senderNonces"}},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_owner\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"AccessControlBadConfirmation\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"neededRole\",\"type\":\"bytes32\"}],\"name\":\"AccessControlUnauthorizedAccount\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"}],\"name\":\"AddressEmptyCode\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"AddressInsufficientBalance\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"AmountIncorrect\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"CallParamsLengthAboveMax\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ChainIncorrect\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DeadlineExceeded\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DeadlineNotExceeded\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DeadlineTooShort\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DisputePeriodNotPassed\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DisputePeriodPassed\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ExclusivityParamsIncorrect\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ExclusivityPeriodNotPassed\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"FailedInnerCall\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"MsgValueIncorrect\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"NativeTokenCallValueNotSupported\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"RecipientIncorrectReturnValue\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"RecipientNoReturnValue\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"}],\"name\":\"SafeERC20FailedOperation\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"SenderIncorrect\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"StatusIncorrect\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"TokenNotContract\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"TransactionRelayed\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ZeroAddress\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"BridgeDepositClaimed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"BridgeDepositRefunded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"name\":\"BridgeProofDisputed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"transactionHash\",\"type\":\"bytes32\"}],\"name\":\"BridgeProofProvided\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"quoteId\",\"type\":\"bytes\"}],\"name\":\"BridgeQuoteDetails\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"originChainId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"chainGasAmount\",\"type\":\"uint256\"}],\"name\":\"BridgeRelayed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"destChainId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"sendChainGas\",\"type\":\"bool\"}],\"name\":\"BridgeRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"oldChainGasAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newChainGasAmount\",\"type\":\"uint256\"}],\"name\":\"ChainGasAmountUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"oldFeeRate\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newFeeRate\",\"type\":\"uint256\"}],\"name\":\"FeeRateUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"FeesSwept\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"previousAdminRole\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"newAdminRole\",\"type\":\"bytes32\"}],\"name\":\"RoleAdminChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleGranted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleRevoked\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"DEFAULT_ADMIN_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"DISPUTE_PERIOD\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"FEE_BPS\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"FEE_RATE_MAX\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"GOVERNOR_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"GUARD_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"MAX_CALL_PARAMS_LENGTH\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"MIN_DEADLINE_PERIOD\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"REFUNDER_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"REFUND_DELAY\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"RELAYER_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"dstChainId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"sendChainGas\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"}],\"internalType\":\"struct IFastBridge.BridgeParams\",\"name\":\"params\",\"type\":\"tuple\"}],\"name\":\"bridge\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"dstChainId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"sendChainGas\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"}],\"internalType\":\"struct IFastBridge.BridgeParams\",\"name\":\"params\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"quoteRelayer\",\"type\":\"address\"},{\"internalType\":\"int256\",\"name\":\"quoteExclusivitySeconds\",\"type\":\"int256\"},{\"internalType\":\"bytes\",\"name\":\"quoteId\",\"type\":\"bytes\"},{\"internalType\":\"uint256\",\"name\":\"callValue\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"callParams\",\"type\":\"bytes\"}],\"internalType\":\"struct IFastBridgeV2.BridgeParamsV2\",\"name\":\"paramsV2\",\"type\":\"tuple\"}],\"name\":\"bridge\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"}],\"name\":\"bridgeProofs\",\"outputs\":[{\"internalType\":\"uint96\",\"name\":\"timestamp\",\"type\":\"uint96\"},{\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"bridgeRelayDetails\",\"outputs\":[{\"internalType\":\"uint48\",\"name\":\"blockNumber\",\"type\":\"uint48\"},{\"internalType\":\"uint48\",\"name\":\"blockTimestamp\",\"type\":\"uint48\"},{\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"}],\"name\":\"bridgeRelays\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"}],\"name\":\"bridgeStatuses\",\"outputs\":[{\"internalType\":\"enum IFastBridgeV2.BridgeStatus\",\"name\":\"status\",\"type\":\"uint8\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"bridgeTxDetails\",\"outputs\":[{\"internalType\":\"enum IFastBridgeV2.BridgeStatus\",\"name\":\"status\",\"type\":\"uint8\"},{\"internalType\":\"uint40\",\"name\":\"proofBlockTimestamp\",\"type\":\"uint40\"},{\"internalType\":\"uint48\",\"name\":\"proofBlockNumber\",\"type\":\"uint48\"},{\"internalType\":\"address\",\"name\":\"proofRelayer\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"name\":\"canClaim\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"chainGasAmount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"claim\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"claim\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"deployBlock\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"}],\"name\":\"dispute\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"getBridgeTransaction\",\"outputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"originChainId\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"destChainId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"originSender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destRecipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"originFeeAmount\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"sendChainGas\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"}],\"internalType\":\"struct IFastBridge.BridgeTransaction\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"getBridgeTransactionV2\",\"outputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"originChainId\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"destChainId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"originSender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destRecipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"originFeeAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"callValue\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"exclusivityRelayer\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"exclusivityEndTime\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"callParams\",\"type\":\"bytes\"}],\"internalType\":\"struct IFastBridgeV2.BridgeTransactionV2\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"}],\"name\":\"getRoleAdmin\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"index\",\"type\":\"uint256\"}],\"name\":\"getRoleMember\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"}],\"name\":\"getRoleMemberCount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"grantRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"hasRole\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"nonce\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"protocolFeeRate\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"protocolFees\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"destTxHash\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"name\":\"prove\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"},{\"internalType\":\"bytes32\",\"name\":\"destTxHash\",\"type\":\"bytes32\"}],\"name\":\"prove\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"refund\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"relay\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"},{\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"name\":\"relay\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"callerConfirmation\",\"type\":\"address\"}],\"name\":\"renounceRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"revokeRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"senderNonces\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"newChainGasAmount\",\"type\":\"uint256\"}],\"name\":\"setChainGasAmount\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"newFeeRate\",\"type\":\"uint256\"}],\"name\":\"setProtocolFeeRate\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes4\",\"name\":\"interfaceId\",\"type\":\"bytes4\"}],\"name\":\"supportsInterface\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"}],\"name\":\"sweepProtocolFees\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"errors\":{\"AccessControlBadConfirmation()\":[{\"details\":\"The caller of a function is not the expected one. NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\"}],\"AccessControlUnauthorizedAccount(address,bytes32)\":[{\"details\":\"The `account` is missing a role.\"}],\"AddressEmptyCode(address)\":[{\"details\":\"There's no code at `target` (it is not a contract).\"}],\"AddressInsufficientBalance(address)\":[{\"details\":\"The ETH balance of the account is not enough to perform the operation.\"}],\"FailedInnerCall()\":[{\"details\":\"A call to an address target failed. The target may have reverted.\"}],\"SafeERC20FailedOperation(address)\":[{\"details\":\"An operation with an ERC20 token failed.\"}]},\"events\":{\"RoleAdminChanged(bytes32,bytes32,bytes32)\":{\"details\":\"Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole` `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite {RoleAdminChanged} not being emitted signaling this.\"},\"RoleGranted(bytes32,address,address)\":{\"details\":\"Emitted when `account` is granted `role`. `sender` is the account that originated the contract call, an admin role bearer except when using {AccessControl-_setupRole}.\"},\"RoleRevoked(bytes32,address,address)\":{\"details\":\"Emitted when `account` is revoked `role`. `sender` is the account that originated the contract call: - if using `revokeRole`, it is the admin role bearer - if using `renounceRole`, it is the role bearer (i.e. `account`)\"}},\"kind\":\"dev\",\"methods\":{\"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256))\":{\"params\":{\"params\":\"The parameters required to bridge\"}},\"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256),(address,int256,bytes,uint256,bytes))\":{\"params\":{\"params\":\"The parameters required to bridge\",\"paramsV2\":\"The parameters for exclusivity fill rights (optional, can be left empty)\"}},\"bridgeProofs(bytes32)\":{\"params\":{\"transactionId\":\"The ID of the bridge transaction\"},\"returns\":{\"relayer\":\"The relayer address of the bridge proof\",\"timestamp\":\"The timestamp of the bridge proof\"}},\"bridgeRelays(bytes32)\":{\"params\":{\"transactionId\":\"The ID of the transaction to check\"},\"returns\":{\"_0\":\"True if the transaction has been relayed, false otherwise\"}},\"bridgeStatuses(bytes32)\":{\"params\":{\"transactionId\":\"The ID of the bridge transaction\"},\"returns\":{\"status\":\"BridgeStatus Status of the bridge transaction\"}},\"canClaim(bytes32,address)\":{\"params\":{\"relayer\":\"The address of the relayer attempting to claim\",\"transactionId\":\"The transaction id associated with the encoded bridge transaction to check\"}},\"claim(bytes)\":{\"params\":{\"request\":\"The encoded bridge transaction to claim on origin chain\"}},\"claim(bytes,address)\":{\"params\":{\"request\":\"The encoded bridge transaction to claim on origin chain\",\"to\":\"The recipient address of the funds\"}},\"dispute(bytes32)\":{\"params\":{\"transactionId\":\"The transaction id associated with the encoded bridge transaction to dispute\"}},\"getBridgeTransaction(bytes)\":{\"details\":\"This method is added to achieve backwards compatibility with decoding requests into V1 structs: - `callValue` is partially reported as a zero/non-zero flag - `callParams` is ignored In order to process all kinds of requests use getBridgeTransactionV2 instead.\",\"params\":{\"request\":\"The bridge request to decode\"}},\"getBridgeTransactionV2(bytes)\":{\"params\":{\"request\":\"The bridge request to decode\"}},\"getRoleAdmin(bytes32)\":{\"details\":\"Returns the admin role that controls `role`. See {grantRole} and {revokeRole}. To change a role's admin, use {_setRoleAdmin}.\"},\"getRoleMember(bytes32,uint256)\":{\"details\":\"Returns one of the accounts that have `role`. `index` must be a value between 0 and {getRoleMemberCount}, non-inclusive. Role bearers are not sorted in any particular way, and their ordering may change at any point. WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure you perform all queries on the same block. See the following https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post] for more information.\"},\"getRoleMemberCount(bytes32)\":{\"details\":\"Returns the number of accounts that have `role`. Can be used together with {getRoleMember} to enumerate all bearers of a role.\"},\"grantRole(bytes32,address)\":{\"details\":\"Grants `role` to `account`. If `account` had not been already granted `role`, emits a {RoleGranted} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleGranted} event.\"},\"hasRole(bytes32,address)\":{\"details\":\"Returns `true` if `account` has been granted `role`.\"},\"prove(bytes,bytes32)\":{\"params\":{\"destTxHash\":\"The destination tx hash proving bridge transaction was relayed\",\"request\":\"The encoded bridge transaction to prove on origin chain\"}},\"prove(bytes32,bytes32,address)\":{\"params\":{\"destTxHash\":\"The destination tx hash proving bridge transaction was relayed\",\"relayer\":\"The address of the relaying entity which should have control of the origin funds when claimed\",\"transactionId\":\"The transaction id associated with the encoded bridge transaction to prove\"}},\"refund(bytes)\":{\"params\":{\"request\":\"The encoded bridge transaction to refund\"}},\"relay(bytes)\":{\"params\":{\"request\":\"The encoded bridge transaction to relay on destination chain\"}},\"relay(bytes,address)\":{\"params\":{\"relayer\":\"The address of the relaying entity which should have control of the origin funds when claimed\",\"request\":\"The encoded bridge transaction to relay on destination chain\"}},\"renounceRole(bytes32,address)\":{\"details\":\"Revokes `role` from the calling account. Roles are often managed via {grantRole} and {revokeRole}: this function's purpose is to provide a mechanism for accounts to lose their privileges if they are compromised (such as when a trusted device is misplaced). If the calling account had been revoked `role`, emits a {RoleRevoked} event. Requirements: - the caller must be `callerConfirmation`. May emit a {RoleRevoked} event.\"},\"revokeRole(bytes32,address)\":{\"details\":\"Revokes `role` from `account`. If `account` had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleRevoked} event.\"},\"supportsInterface(bytes4)\":{\"details\":\"See {IERC165-supportsInterface}.\"}},\"stateVariables\":{\"nonce\":{\"details\":\"Replaced by senderNonces\"}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"DISPUTE_PERIOD()\":{\"notice\":\"Dispute period for relayed transactions\"},\"MAX_CALL_PARAMS_LENGTH()\":{\"notice\":\"Maximum length of accepted callParams\"},\"MIN_DEADLINE_PERIOD()\":{\"notice\":\"Minimum deadline period to relay a requested bridge transaction\"},\"REFUND_DELAY()\":{\"notice\":\"Delay for a transaction after which it could be permisionlessly refunded\"},\"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256))\":{\"notice\":\"Initiates bridge on origin chain to be relayed by off-chain relayer\"},\"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256),(address,int256,bytes,uint256,bytes))\":{\"notice\":\"Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability to provide temporary exclusivity fill rights for the quote relayer.\"},\"bridgeProofs(bytes32)\":{\"notice\":\"Returns the timestamp and relayer of a bridge proof\"},\"bridgeRelayDetails(bytes32)\":{\"notice\":\"Relay details on destination chain\"},\"bridgeRelays(bytes32)\":{\"notice\":\"Checks if a transaction has been relayed\"},\"bridgeStatuses(bytes32)\":{\"notice\":\"Returns the status of a bridge transaction\"},\"bridgeTxDetails(bytes32)\":{\"notice\":\"Status of the bridge tx on origin chain\"},\"canClaim(bytes32,address)\":{\"notice\":\"Checks if the dispute period has passed so bridge deposit can be claimed\"},\"chainGasAmount()\":{\"notice\":\"Chain gas amount to forward as rebate if requested\"},\"claim(bytes)\":{\"notice\":\"Completes bridge transaction on origin chain by claiming originally deposited capital.Can only send funds to the relayer address on the proof.\"},\"claim(bytes,address)\":{\"notice\":\"Completes bridge transaction on origin chain by claiming originally deposited capital\"},\"deployBlock()\":{\"notice\":\"the block the contract was deployed at\"},\"dispute(bytes32)\":{\"notice\":\"Disputes an outstanding proof in case relayer provided dest chain tx is invalid\"},\"getBridgeTransaction(bytes)\":{\"notice\":\"Decodes bridge request into a bridge transaction\"},\"getBridgeTransactionV2(bytes)\":{\"notice\":\"Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\"},\"nonce()\":{\"notice\":\"This is deprecated and should not be used.\"},\"protocolFeeRate()\":{\"notice\":\"Protocol fee rate taken on origin amount deposited in origin chain\"},\"protocolFees(address)\":{\"notice\":\"Protocol fee amounts accumulated\"},\"prove(bytes,bytes32)\":{\"notice\":\"Provides proof on origin side that relayer provided funds on destination side of bridge transaction\"},\"prove(bytes32,bytes32,address)\":{\"notice\":\"Provides proof on origin side that relayer provided funds on destination side of bridge transaction\"},\"refund(bytes)\":{\"notice\":\"Refunds an outstanding bridge transaction in case optimistic bridging failed\"},\"relay(bytes)\":{\"notice\":\"Relays destination side of bridge transaction by off-chain relayer\"},\"relay(bytes,address)\":{\"notice\":\"Relays destination side of bridge transaction by off-chain relayer\"},\"senderNonces(address)\":{\"notice\":\"Unique bridge nonces tracked per originSender\"}},\"notice\":\"FastBridgeV2 is a contract for bridging tokens across chains.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeV2.sol\":\"FastBridgeV2\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeV2.sol\":{\"keccak256\":\"0x7cd0f885e80e2bdaa638bc32ae7af7d2e248f99ce4b354c217d0f0f7d7302e0a\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://7ccf28df0bd7b4606986585acd8622ed9b4e81379690061bb66088f0a2270af1\",\"dweb:/ipfs/QmTf7HNdHZkK6vmx8ZgewycQEb72oLD9nPwBpsM5reMstQ\"]}},\"version\":1}"},"hashes":{"DEFAULT_ADMIN_ROLE()":"a217fddf","DISPUTE_PERIOD()":"a5bbe22b","FEE_BPS()":"bf333f2c","FEE_RATE_MAX()":"0f5f6ed7","GOVERNOR_ROLE()":"ccc57490","GUARD_ROLE()":"03ed0ee5","MAX_CALL_PARAMS_LENGTH()":"df36bb13","MIN_DEADLINE_PERIOD()":"820688d5","REFUNDER_ROLE()":"5960ccf2","REFUND_DELAY()":"190da595","RELAYER_ROLE()":"926d7d7f","bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256))":"45851694","bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256),(address,int256,bytes,uint256,bytes))":"bfc7c607","bridgeProofs(bytes32)":"91ad5039","bridgeRelayDetails(bytes32)":"c79371b1","bridgeRelays(bytes32)":"8379a24f","bridgeStatuses(bytes32)":"051287bc","bridgeTxDetails(bytes32)":"63787e52","canClaim(bytes32,address)":"aa9641ab","chainGasAmount()":"e00a83e0","claim(bytes)":"c63ff8dd","claim(bytes,address)":"41fcb612","deployBlock()":"a3ec191a","dispute(bytes32)":"add98c70","getBridgeTransaction(bytes)":"ac11fb1a","getBridgeTransactionV2(bytes)":"5aa6ccba","getRoleAdmin(bytes32)":"248a9ca3","getRoleMember(bytes32,uint256)":"9010d07c","getRoleMemberCount(bytes32)":"ca15c873","grantRole(bytes32,address)":"2f2ff15d","hasRole(bytes32,address)":"91d14854","nonce()":"affed0e0","protocolFeeRate()":"58f85880","protocolFees(address)":"dcf844a7","prove(bytes,bytes32)":"886d36ff","prove(bytes32,bytes32,address)":"18e4357d","refund(bytes)":"5eb7d946","relay(bytes)":"8f0d6f17","relay(bytes,address)":"9c9545f0","renounceRole(bytes32,address)":"36568abe","revokeRole(bytes32,address)":"d547741f","senderNonces(address)":"295710ff","setChainGasAmount(uint256)":"b250fe6b","setProtocolFeeRate(uint256)":"b13aa2d6","supportsInterface(bytes4)":"01ffc9a7","sweepProtocolFees(address,address)":"06f333f2"}},"solidity/FastBridgeV2.sol:IAccessControl":{"code":"0x","runtime-code":"0x","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.24 ^0.8.0 ^0.8.20;\n\n// contracts/interfaces/IAdmin.sol\n\ninterface IAdmin {\n // ============ Events ============\n\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n event ChainGasAmountUpdated(uint256 oldChainGasAmount, uint256 newChainGasAmount);\n\n // ============ Methods ============\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n\n function setChainGasAmount(uint256 newChainGasAmount) external;\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IFastBridgeRecipient.sol\n\ninterface IFastBridgeRecipient {\n function fastBridgeTransferReceived(\n address token,\n uint256 amount,\n bytes memory callParams\n )\n external\n payable\n returns (bytes4);\n}\n\n// contracts/interfaces/IFastBridgeV2Errors.sol\n\ninterface IFastBridgeV2Errors {\n error AmountIncorrect();\n error CallParamsLengthAboveMax();\n error ChainIncorrect();\n error ExclusivityParamsIncorrect();\n error MsgValueIncorrect();\n error NativeTokenCallValueNotSupported();\n error SenderIncorrect();\n error StatusIncorrect();\n error ZeroAddress();\n\n error RecipientIncorrectReturnValue();\n error RecipientNoReturnValue();\n\n error DeadlineExceeded();\n error DeadlineNotExceeded();\n error DeadlineTooShort();\n error DisputePeriodNotPassed();\n error DisputePeriodPassed();\n error ExclusivityPeriodNotPassed();\n\n error TransactionRelayed();\n}\n\n// contracts/libs/Errors.sol\n\nerror DeadlineExceeded();\nerror DeadlineNotExceeded();\nerror DeadlineTooShort();\nerror InsufficientOutputAmount();\n\nerror MsgValueIncorrect();\nerror PoolNotFound();\nerror TokenAddressMismatch();\nerror TokenNotContract();\nerror TokenNotETH();\nerror TokensIdentical();\n\nerror ChainIncorrect();\nerror AmountIncorrect();\nerror ZeroAddress();\n\nerror DisputePeriodNotPassed();\nerror DisputePeriodPassed();\nerror SenderIncorrect();\nerror StatusIncorrect();\nerror TransactionIdIncorrect();\nerror TransactionRelayed();\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// contracts/interfaces/IFastBridgeV2.sol\n\ninterface IFastBridgeV2 is IFastBridge {\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n struct BridgeTxDetails {\n BridgeStatus status;\n uint40 proofBlockTimestamp;\n uint48 proofBlockNumber;\n address proofRelayer;\n }\n\n struct BridgeRelay {\n uint48 blockNumber;\n uint48 blockTimestamp;\n address relayer;\n }\n\n /// @notice New params introduced in the FastBridgeV2.\n /// We are passing fields from the older BridgeParams struct outside of this struct\n /// for backwards compatibility.\n /// Note: quoteRelayer and quoteExclusivitySeconds are either both zero (indicating no exclusivity)\n /// or both non-zero (indicating exclusivity for the given period).\n /// Note: callValue \u003e 0 can NOT be used with destToken = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE (ETH_ADDRESS)\n /// @param quoteRelayer Relayer that provided the quote for the transaction\n /// @param quoteExclusivitySeconds Period of time the quote relayer is guaranteed exclusivity after user's deposit\n /// @param quoteId Unique quote identifier used for tracking the quote\n /// @param callValue ETH value to send to the recipient (if any)\n /// @param callParams Parameters for the arbitrary call to the destination recipient (if any)\n struct BridgeParamsV2 {\n address quoteRelayer;\n int256 quoteExclusivitySeconds;\n bytes quoteId;\n uint256 callValue;\n bytes callParams;\n }\n\n /// @notice Updated bridge transaction struct to include parameters introduced in FastBridgeV2.\n /// Note: only `exclusivityRelayer` can fill such a transaction until `exclusivityEndTime`.\n /// TODO: consider changing the encoding scheme to prevent spending extra gas on decoding.\n struct BridgeTransactionV2 {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n uint256 callValue; // ETH value to send to the recipient (if any) - replaces V1's sendChainGas flag\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n address exclusivityRelayer;\n uint256 exclusivityEndTime;\n bytes callParams;\n }\n\n event BridgeQuoteDetails(bytes32 indexed transactionId, bytes quoteId);\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability\n /// to provide temporary exclusivity fill rights for the quote relayer.\n /// @param params The parameters required to bridge\n /// @param paramsV2 The parameters for exclusivity fill rights (optional, can be left empty)\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function relay(bytes memory request, address relayer) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param transactionId The transaction id associated with the encoded bridge transaction to prove\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital.\n /// @notice Can only send funds to the relayer address on the proof.\n /// @param request The encoded bridge transaction to claim on origin chain\n function claim(bytes memory request) external;\n /// @notice Checks if a transaction has been relayed\n /// @param transactionId The ID of the transaction to check\n /// @return True if the transaction has been relayed, false otherwise\n function bridgeRelays(bytes32 transactionId) external view returns (bool);\n\n /// @notice Returns the status of a bridge transaction\n /// @param transactionId The ID of the bridge transaction\n /// @return BridgeStatus Status of the bridge transaction\n function bridgeStatuses(bytes32 transactionId) external view returns (BridgeStatus);\n\n /// @notice Returns the timestamp and relayer of a bridge proof\n /// @param transactionId The ID of the bridge transaction\n /// @return timestamp The timestamp of the bridge proof\n /// @return relayer The relayer address of the bridge proof\n function bridgeProofs(bytes32 transactionId) external view returns (uint96 timestamp, address relayer);\n\n /// @notice Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\n /// @param request The bridge request to decode\n function getBridgeTransactionV2(bytes memory request) external view returns (BridgeTransactionV2 memory);\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// contracts/libs/UniversalToken.sol\n\nlibrary UniversalTokenLib {\n using SafeERC20 for IERC20;\n\n address internal constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Transfers tokens to the given account. Reverts if transfer is not successful.\n /// @dev This might trigger fallback, if ETH is transferred to the contract.\n /// Make sure this can not lead to reentrancy attacks.\n function universalTransfer(address token, address to, uint256 value) internal {\n // Don't do anything, if need to send tokens to this address\n if (to == address(this)) return;\n // Don't do anything, if trying to send zero value\n if (value == 0) return;\n if (token == ETH_ADDRESS) {\n /// @dev Note: this can potentially lead to executing code in `to`.\n // solhint-disable-next-line avoid-low-level-calls\n (bool success,) = to.call{value: value}(\"\");\n require(success, \"ETH transfer failed\");\n } else {\n IERC20(token).safeTransfer(to, value);\n }\n }\n\n /// @notice Issues an infinite allowance to the spender, if the current allowance is insufficient\n /// to spend the given amount.\n function universalApproveInfinity(address token, address spender, uint256 amountToSpend) internal {\n // ETH Chad doesn't require your approval\n if (token == ETH_ADDRESS) return;\n // No-op if allowance is already sufficient\n uint256 allowance = IERC20(token).allowance(address(this), spender);\n if (allowance \u003e= amountToSpend) return;\n // Otherwise, reset approval to 0 and set to max allowance\n if (allowance \u003e 0) IERC20(token).safeDecreaseAllowance(spender, allowance);\n IERC20(token).safeIncreaseAllowance(spender, type(uint256).max);\n }\n\n /// @notice Returns the balance of the given token (or native ETH) for the given account.\n function universalBalanceOf(address token, address account) internal view returns (uint256) {\n if (token == ETH_ADDRESS) {\n return account.balance;\n } else {\n return IERC20(token).balanceOf(account);\n }\n }\n\n /// @dev Checks that token is a contract and not ETH_ADDRESS.\n function assertIsContract(address token) internal view {\n // Check that ETH_ADDRESS was not used (in case this is a predeploy on any of the chains)\n if (token == UniversalTokenLib.ETH_ADDRESS) revert TokenNotContract();\n // Check that token is not an EOA\n if (token.code.length == 0) revert TokenNotContract();\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/Admin.sol\n\ncontract Admin is IAdmin, AccessControlEnumerable {\n using UniversalTokenLib for address;\n\n bytes32 public constant RELAYER_ROLE = keccak256(\"RELAYER_ROLE\");\n bytes32 public constant REFUNDER_ROLE = keccak256(\"REFUNDER_ROLE\");\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n uint256 public constant FEE_BPS = 1e6;\n uint256 public constant FEE_RATE_MAX = 0.01e6; // max 1% on origin amount\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Chain gas amount to forward as rebate if requested\n uint256 public chainGasAmount;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n }\n\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n require(newFeeRate \u003c= FEE_RATE_MAX, \"newFeeRate \u003e max\");\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n token.universalTransfer(recipient, feeAmount);\n emit FeesSwept(token, recipient, feeAmount);\n }\n\n function setChainGasAmount(uint256 newChainGasAmount) external onlyRole(GOVERNOR_ROLE) {\n uint256 oldChainGasAmount = chainGasAmount;\n chainGasAmount = newChainGasAmount;\n emit ChainGasAmountUpdated(oldChainGasAmount, newChainGasAmount);\n }\n}\n\n// contracts/FastBridgeV2.sol\n\n/// @notice FastBridgeV2 is a contract for bridging tokens across chains.\ncontract FastBridgeV2 is Admin, IFastBridgeV2, IFastBridgeV2Errors {\n using SafeERC20 for IERC20;\n using UniversalTokenLib for address;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Delay for a transaction after which it could be permisionlessly refunded\n uint256 public constant REFUND_DELAY = 7 days;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n /// @notice Maximum length of accepted callParams\n uint256 public constant MAX_CALL_PARAMS_LENGTH = 2 ** 16 - 1;\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeTxDetails) public bridgeTxDetails;\n /// @notice Relay details on destination chain\n mapping(bytes32 =\u003e BridgeRelay) public bridgeRelayDetails;\n /// @notice Unique bridge nonces tracked per originSender\n mapping(address =\u003e uint256) public senderNonces;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Replaced by senderNonces\n uint256 public immutable nonce = 0;\n /// @notice the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n bridge({\n params: params,\n paramsV2: BridgeParamsV2({\n quoteRelayer: address(0),\n quoteExclusivitySeconds: 0,\n quoteId: bytes(\"\"),\n callValue: 0,\n callParams: bytes(\"\")\n })\n });\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes memory request) external payable {\n relay({request: request, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes memory request, bytes32 destTxHash) external {\n prove({transactionId: keccak256(request), destTxHash: destTxHash, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridgeV2\n function claim(bytes memory request) external {\n claim({request: request, to: address(0)});\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003e DISPUTE_PERIOD) {\n revert DisputePeriodPassed();\n }\n\n // @dev relayer gets slashed effectively if dest relay has gone thru\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n bridgeTxDetails[transactionId].proofRelayer = address(0);\n bridgeTxDetails[transactionId].proofBlockTimestamp = 0;\n bridgeTxDetails[transactionId].proofBlockNumber = 0;\n\n emit BridgeProofDisputed(transactionId, msg.sender);\n }\n\n /// @inheritdoc IFastBridge\n function refund(bytes memory request) external {\n bytes32 transactionId = keccak256(request);\n\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n\n if (bridgeTxDetails[transactionId].status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n\n if (hasRole(REFUNDER_ROLE, msg.sender)) {\n // Refunder can refund if deadline has passed\n if (block.timestamp \u003c= transaction.deadline) revert DeadlineNotExceeded();\n } else {\n // Permissionless refund is allowed after REFUND_DELAY\n if (block.timestamp \u003c= transaction.deadline + REFUND_DELAY) revert DeadlineNotExceeded();\n }\n\n // if all checks passed, set to REFUNDED status\n bridgeTxDetails[transactionId].status = BridgeStatus.REFUNDED;\n\n // transfer origin collateral back to original sender\n address to = transaction.originSender;\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount + transaction.originFeeAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (bridgeTxDetails[transactionId].proofRelayer != relayer) revert SenderIncorrect();\n return _timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n /// @dev This method is added to achieve backwards compatibility with decoding requests into V1 structs:\n /// - `callValue` is partially reported as a zero/non-zero flag\n /// - `callParams` is ignored\n /// In order to process all kinds of requests use getBridgeTransactionV2 instead.\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory) {\n // Try decoding into V2 struct first. This will revert if V1 struct is passed\n try this.getBridgeTransactionV2(request) returns (BridgeTransactionV2 memory txV2) {\n // Note: we entirely ignore the callParams field, as it was not present in V1\n return BridgeTransaction({\n originChainId: txV2.originChainId,\n destChainId: txV2.destChainId,\n originSender: txV2.originSender,\n destRecipient: txV2.destRecipient,\n originToken: txV2.originToken,\n destToken: txV2.destToken,\n originAmount: txV2.originAmount,\n destAmount: txV2.destAmount,\n originFeeAmount: txV2.originFeeAmount,\n sendChainGas: txV2.callValue != 0,\n deadline: txV2.deadline,\n nonce: txV2.nonce\n });\n } catch {\n // Fallback to V1 struct\n return abi.decode(request, (BridgeTransaction));\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) public payable {\n int256 exclusivityEndTime = int256(block.timestamp) + paramsV2.quoteExclusivitySeconds;\n _validateBridgeParams(params, paramsV2, exclusivityEndTime);\n\n // transfer tokens to bridge contract\n /// @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _pullToken(params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n\n // set status to requested\n bytes memory request = abi.encode(\n BridgeTransactionV2({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n callValue: paramsV2.callValue,\n deadline: params.deadline,\n nonce: senderNonces[params.sender]++, // increment nonce on every bridge\n exclusivityRelayer: paramsV2.quoteRelayer,\n // We checked exclusivityEndTime to be in range (0 .. params.deadline] above, so can safely cast\n exclusivityEndTime: uint256(exclusivityEndTime),\n callParams: paramsV2.callParams\n })\n );\n bytes32 transactionId = keccak256(request);\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n\n emit BridgeRequested({\n transactionId: transactionId,\n sender: params.sender,\n request: request,\n destChainId: params.dstChainId,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n sendChainGas: paramsV2.callValue != 0\n });\n emit BridgeQuoteDetails(transactionId, paramsV2.quoteId);\n }\n\n /// @inheritdoc IFastBridgeV2\n function relay(bytes memory request, address relayer) public payable {\n bytes32 transactionId = keccak256(request);\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n _validateRelayParams(transaction, transactionId, relayer);\n // mark bridge transaction as relayed\n bridgeRelayDetails[transactionId] =\n BridgeRelay({blockNumber: uint48(block.number), blockTimestamp: uint48(block.timestamp), relayer: relayer});\n\n // transfer tokens to recipient on destination chain and do an arbitrary call if requested\n address to = transaction.destRecipient;\n address token = transaction.destToken;\n uint256 amount = transaction.destAmount;\n\n // All state changes have been done at this point, can proceed to the external calls.\n // This follows the checks-effects-interactions pattern to mitigate potential reentrancy attacks.\n if (token == UniversalTokenLib.ETH_ADDRESS) {\n // For ETH non-zero callValue is not allowed\n if (transaction.callValue != 0) revert NativeTokenCallValueNotSupported();\n // Check that the correct msg.value was sent\n if (msg.value != amount) revert MsgValueIncorrect();\n } else {\n // For ERC20s, we check that the correct msg.value was sent\n if (msg.value != transaction.callValue) revert MsgValueIncorrect();\n // We need to transfer the tokens from the Relayer to the recipient first before performing an\n // optional post-transfer arbitrary call.\n IERC20(token).safeTransferFrom(msg.sender, to, amount);\n }\n\n if (transaction.callParams.length != 0) {\n // Arbitrary call requested, perform it while supplying full msg.value to the recipient\n // Note: if token has a fee on transfers, the recipient will have received less than `amount`.\n // This is a very niche edge case and should be handled by the recipient contract.\n _checkedCallRecipient({recipient: to, token: token, amount: amount, callParams: transaction.callParams});\n } else if (msg.value != 0) {\n // No arbitrary call requested, but msg.value was sent. This is either a relay with ETH,\n // or a non-zero callValue request with an ERC20. In both cases, transfer the ETH to the recipient.\n Address.sendValue(payable(to), msg.value);\n }\n\n emit BridgeRelayed({\n transactionId: transactionId,\n relayer: relayer,\n to: to,\n originChainId: transaction.originChainId,\n originToken: transaction.originToken,\n destToken: transaction.destToken,\n originAmount: transaction.originAmount,\n destAmount: transaction.destAmount,\n chainGasAmount: transaction.callValue\n });\n }\n\n /// @inheritdoc IFastBridgeV2\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) public onlyRole(RELAYER_ROLE) {\n // update bridge tx status given proof provided\n if (bridgeTxDetails[transactionId].status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n bridgeTxDetails[transactionId].status = BridgeStatus.RELAYER_PROVED;\n bridgeTxDetails[transactionId].proofBlockTimestamp = uint40(block.timestamp);\n bridgeTxDetails[transactionId].proofBlockNumber = uint48(block.number);\n bridgeTxDetails[transactionId].proofRelayer = relayer;\n\n emit BridgeProofProvided(transactionId, relayer, destTxHash);\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes memory request, address to) public {\n bytes32 transactionId = keccak256(request);\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n\n // update bridge tx status if able to claim origin collateral\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n\n // if \"to\" is zero addr, permissionlessly send funds to proven relayer\n if (to == address(0)) {\n to = bridgeTxDetails[transactionId].proofRelayer;\n } else if (bridgeTxDetails[transactionId].proofRelayer != msg.sender) {\n revert SenderIncorrect();\n }\n\n if (_timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003c= DISPUTE_PERIOD) {\n revert DisputePeriodNotPassed();\n }\n\n bridgeTxDetails[transactionId].status = BridgeStatus.RELAYER_CLAIMED;\n\n // update protocol fees if origin fee amount exists\n if (transaction.originFeeAmount \u003e 0) protocolFees[transaction.originToken] += transaction.originFeeAmount;\n\n // transfer origin collateral less fee to specified address\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositClaimed(transactionId, bridgeTxDetails[transactionId].proofRelayer, to, token, amount);\n }\n\n function bridgeStatuses(bytes32 transactionId) public view returns (BridgeStatus status) {\n return bridgeTxDetails[transactionId].status;\n }\n\n function bridgeProofs(bytes32 transactionId) public view returns (uint96 timestamp, address relayer) {\n timestamp = bridgeTxDetails[transactionId].proofBlockTimestamp;\n relayer = bridgeTxDetails[transactionId].proofRelayer;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeRelays(bytes32 transactionId) public view returns (bool) {\n // has this transactionId been relayed?\n return bridgeRelayDetails[transactionId].relayer != address(0);\n }\n\n /// @inheritdoc IFastBridgeV2\n function getBridgeTransactionV2(bytes memory request) public pure returns (BridgeTransactionV2 memory) {\n return abi.decode(request, (BridgeTransactionV2));\n }\n\n /// @notice Pulls a requested token from the user to this contract.\n function _pullToken(address token, uint256 amount) internal returns (uint256 amountPulled) {\n if (token == UniversalTokenLib.ETH_ADDRESS) {\n // For ETH we just need to check that the supplied msg.value is correct\n if (amount != msg.value) revert MsgValueIncorrect();\n amountPulled = msg.value;\n } else {\n token.assertIsContract();\n // Record token balance before transfer\n amountPulled = IERC20(token).balanceOf(address(this));\n // Token needs to be pulled only if msg.value is zero\n // This way user can specify WETH as the origin asset\n IERC20(token).safeTransferFrom(msg.sender, address(this), amount);\n // Use the difference between the recorded balance and the current balance as the amountPulled\n amountPulled = IERC20(token).balanceOf(address(this)) - amountPulled;\n }\n }\n\n /// @notice Calls the Recipient's hook function with the specified callParams and performs\n /// all the necessary checks for the returned value.\n function _checkedCallRecipient(\n address recipient,\n address token,\n uint256 amount,\n bytes memory callParams\n )\n internal\n {\n bytes memory hookData =\n abi.encodeCall(IFastBridgeRecipient.fastBridgeTransferReceived, (token, amount, callParams));\n // This will bubble any revert messages from the hook function\n bytes memory returnData = Address.functionCallWithValue({target: recipient, data: hookData, value: msg.value});\n // Explicit revert if no return data at all\n if (returnData.length == 0) revert RecipientNoReturnValue();\n // Check that exactly a single return value was returned\n if (returnData.length != 32) revert RecipientIncorrectReturnValue();\n // Return value should be abi-encoded hook function selector\n if (bytes32(returnData) != bytes32(IFastBridgeRecipient.fastBridgeTransferReceived.selector)) {\n revert RecipientIncorrectReturnValue();\n }\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint40(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint40).max but\n /// proof.timestamp \u003c type(uint40).max via unchecked statement\n /// @param proofBlockTimestamp The bridge proof block timestamp\n /// @return delta Time delta since proof submitted\n function _timeSince(uint40 proofBlockTimestamp) internal view returns (uint256 delta) {\n unchecked {\n delta = uint40(block.timestamp) - proofBlockTimestamp;\n }\n }\n\n /// @notice Performs all the necessary checks for a bridge to happen.\n /// @dev There's no good way to refactor this function to reduce cyclomatic complexity due to\n /// the number of checks that need to be performed, so we skip the code-complexity rule here.\n // solhint-disable-next-line code-complexity\n function _validateBridgeParams(\n BridgeParams memory params,\n BridgeParamsV2 memory paramsV2,\n int256 exclusivityEndTime\n )\n internal\n view\n {\n // Check V1 (legacy) params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.sender == address(0) || params.to == address(0)) revert ZeroAddress();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n // Check V2 params\n if (paramsV2.callParams.length \u003e MAX_CALL_PARAMS_LENGTH) revert CallParamsLengthAboveMax();\n if (paramsV2.callValue != 0 \u0026\u0026 params.destToken == UniversalTokenLib.ETH_ADDRESS) {\n revert NativeTokenCallValueNotSupported();\n }\n // exclusivityEndTime must be in range (0 .. params.deadline]\n if (exclusivityEndTime \u003c= 0 || exclusivityEndTime \u003e int256(params.deadline)) {\n revert ExclusivityParamsIncorrect();\n }\n }\n\n /// @notice Performs all the necessary checks for a relay to happen.\n function _validateRelayParams(\n BridgeTransactionV2 memory transaction,\n bytes32 transactionId,\n address relayer\n )\n internal\n view\n {\n if (relayer == address(0)) revert ZeroAddress();\n // Check if the transaction has already been relayed\n if (bridgeRelays(transactionId)) revert TransactionRelayed();\n if (transaction.destChainId != uint32(block.chainid)) revert ChainIncorrect();\n // Check the deadline for relay to happen\n if (block.timestamp \u003e transaction.deadline) revert DeadlineExceeded();\n // Check the exclusivity period, if it is still ongoing\n // forgefmt: disable-next-item\n if (\n transaction.exclusivityRelayer != address(0) \u0026\u0026\n transaction.exclusivityRelayer != relayer \u0026\u0026\n block.timestamp \u003c= transaction.exclusivityEndTime\n ) {\n revert ExclusivityPeriodNotPassed();\n }\n }\n}\n","language":"Solidity","languageVersion":"0.8.24","compilerVersion":"0.8.24","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"","srcMapRuntime":"","abiDefinition":[{"inputs":[],"name":"AccessControlBadConfirmation","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"bytes32","name":"neededRole","type":"bytes32"}],"name":"AccessControlUnauthorizedAccount","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"previousAdminRole","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"newAdminRole","type":"bytes32"}],"name":"RoleAdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleRevoked","type":"event"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleAdmin","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"grantRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"hasRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"callerConfirmation","type":"address"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"revokeRole","outputs":[],"stateMutability":"nonpayable","type":"function"}],"userDoc":{"kind":"user","methods":{},"version":1},"developerDoc":{"details":"External interface of AccessControl declared to support ERC165 detection.","errors":{"AccessControlBadConfirmation()":[{"details":"The caller of a function is not the expected one. NOTE: Don't confuse with {AccessControlUnauthorizedAccount}."}],"AccessControlUnauthorizedAccount(address,bytes32)":[{"details":"The `account` is missing a role."}]},"events":{"RoleAdminChanged(bytes32,bytes32,bytes32)":{"details":"Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole` `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite {RoleAdminChanged} not being emitted signaling this."},"RoleGranted(bytes32,address,address)":{"details":"Emitted when `account` is granted `role`. `sender` is the account that originated the contract call, an admin role bearer except when using {AccessControl-_setupRole}."},"RoleRevoked(bytes32,address,address)":{"details":"Emitted when `account` is revoked `role`. `sender` is the account that originated the contract call: - if using `revokeRole`, it is the admin role bearer - if using `renounceRole`, it is the role bearer (i.e. `account`)"}},"kind":"dev","methods":{"getRoleAdmin(bytes32)":{"details":"Returns the admin role that controls `role`. See {grantRole} and {revokeRole}. To change a role's admin, use {AccessControl-_setRoleAdmin}."},"grantRole(bytes32,address)":{"details":"Grants `role` to `account`. If `account` had not been already granted `role`, emits a {RoleGranted} event. Requirements: - the caller must have ``role``'s admin role."},"hasRole(bytes32,address)":{"details":"Returns `true` if `account` has been granted `role`."},"renounceRole(bytes32,address)":{"details":"Revokes `role` from the calling account. Roles are often managed via {grantRole} and {revokeRole}: this function's purpose is to provide a mechanism for accounts to lose their privileges if they are compromised (such as when a trusted device is misplaced). If the calling account had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must be `callerConfirmation`."},"revokeRole(bytes32,address)":{"details":"Revokes `role` from `account`. If `account` had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must have ``role``'s admin role."}},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[],\"name\":\"AccessControlBadConfirmation\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"neededRole\",\"type\":\"bytes32\"}],\"name\":\"AccessControlUnauthorizedAccount\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"previousAdminRole\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"newAdminRole\",\"type\":\"bytes32\"}],\"name\":\"RoleAdminChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleGranted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleRevoked\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"}],\"name\":\"getRoleAdmin\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"grantRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"hasRole\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"callerConfirmation\",\"type\":\"address\"}],\"name\":\"renounceRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"revokeRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"details\":\"External interface of AccessControl declared to support ERC165 detection.\",\"errors\":{\"AccessControlBadConfirmation()\":[{\"details\":\"The caller of a function is not the expected one. NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\"}],\"AccessControlUnauthorizedAccount(address,bytes32)\":[{\"details\":\"The `account` is missing a role.\"}]},\"events\":{\"RoleAdminChanged(bytes32,bytes32,bytes32)\":{\"details\":\"Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole` `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite {RoleAdminChanged} not being emitted signaling this.\"},\"RoleGranted(bytes32,address,address)\":{\"details\":\"Emitted when `account` is granted `role`. `sender` is the account that originated the contract call, an admin role bearer except when using {AccessControl-_setupRole}.\"},\"RoleRevoked(bytes32,address,address)\":{\"details\":\"Emitted when `account` is revoked `role`. `sender` is the account that originated the contract call: - if using `revokeRole`, it is the admin role bearer - if using `renounceRole`, it is the role bearer (i.e. `account`)\"}},\"kind\":\"dev\",\"methods\":{\"getRoleAdmin(bytes32)\":{\"details\":\"Returns the admin role that controls `role`. See {grantRole} and {revokeRole}. To change a role's admin, use {AccessControl-_setRoleAdmin}.\"},\"grantRole(bytes32,address)\":{\"details\":\"Grants `role` to `account`. If `account` had not been already granted `role`, emits a {RoleGranted} event. Requirements: - the caller must have ``role``'s admin role.\"},\"hasRole(bytes32,address)\":{\"details\":\"Returns `true` if `account` has been granted `role`.\"},\"renounceRole(bytes32,address)\":{\"details\":\"Revokes `role` from the calling account. Roles are often managed via {grantRole} and {revokeRole}: this function's purpose is to provide a mechanism for accounts to lose their privileges if they are compromised (such as when a trusted device is misplaced). If the calling account had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must be `callerConfirmation`.\"},\"revokeRole(bytes32,address)\":{\"details\":\"Revokes `role` from `account`. If `account` had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must have ``role``'s admin role.\"}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeV2.sol\":\"IAccessControl\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeV2.sol\":{\"keccak256\":\"0x7cd0f885e80e2bdaa638bc32ae7af7d2e248f99ce4b354c217d0f0f7d7302e0a\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://7ccf28df0bd7b4606986585acd8622ed9b4e81379690061bb66088f0a2270af1\",\"dweb:/ipfs/QmTf7HNdHZkK6vmx8ZgewycQEb72oLD9nPwBpsM5reMstQ\"]}},\"version\":1}"},"hashes":{"getRoleAdmin(bytes32)":"248a9ca3","grantRole(bytes32,address)":"2f2ff15d","hasRole(bytes32,address)":"91d14854","renounceRole(bytes32,address)":"36568abe","revokeRole(bytes32,address)":"d547741f"}},"solidity/FastBridgeV2.sol:IAccessControlEnumerable":{"code":"0x","runtime-code":"0x","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.24 ^0.8.0 ^0.8.20;\n\n// contracts/interfaces/IAdmin.sol\n\ninterface IAdmin {\n // ============ Events ============\n\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n event ChainGasAmountUpdated(uint256 oldChainGasAmount, uint256 newChainGasAmount);\n\n // ============ Methods ============\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n\n function setChainGasAmount(uint256 newChainGasAmount) external;\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IFastBridgeRecipient.sol\n\ninterface IFastBridgeRecipient {\n function fastBridgeTransferReceived(\n address token,\n uint256 amount,\n bytes memory callParams\n )\n external\n payable\n returns (bytes4);\n}\n\n// contracts/interfaces/IFastBridgeV2Errors.sol\n\ninterface IFastBridgeV2Errors {\n error AmountIncorrect();\n error CallParamsLengthAboveMax();\n error ChainIncorrect();\n error ExclusivityParamsIncorrect();\n error MsgValueIncorrect();\n error NativeTokenCallValueNotSupported();\n error SenderIncorrect();\n error StatusIncorrect();\n error ZeroAddress();\n\n error RecipientIncorrectReturnValue();\n error RecipientNoReturnValue();\n\n error DeadlineExceeded();\n error DeadlineNotExceeded();\n error DeadlineTooShort();\n error DisputePeriodNotPassed();\n error DisputePeriodPassed();\n error ExclusivityPeriodNotPassed();\n\n error TransactionRelayed();\n}\n\n// contracts/libs/Errors.sol\n\nerror DeadlineExceeded();\nerror DeadlineNotExceeded();\nerror DeadlineTooShort();\nerror InsufficientOutputAmount();\n\nerror MsgValueIncorrect();\nerror PoolNotFound();\nerror TokenAddressMismatch();\nerror TokenNotContract();\nerror TokenNotETH();\nerror TokensIdentical();\n\nerror ChainIncorrect();\nerror AmountIncorrect();\nerror ZeroAddress();\n\nerror DisputePeriodNotPassed();\nerror DisputePeriodPassed();\nerror SenderIncorrect();\nerror StatusIncorrect();\nerror TransactionIdIncorrect();\nerror TransactionRelayed();\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// contracts/interfaces/IFastBridgeV2.sol\n\ninterface IFastBridgeV2 is IFastBridge {\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n struct BridgeTxDetails {\n BridgeStatus status;\n uint40 proofBlockTimestamp;\n uint48 proofBlockNumber;\n address proofRelayer;\n }\n\n struct BridgeRelay {\n uint48 blockNumber;\n uint48 blockTimestamp;\n address relayer;\n }\n\n /// @notice New params introduced in the FastBridgeV2.\n /// We are passing fields from the older BridgeParams struct outside of this struct\n /// for backwards compatibility.\n /// Note: quoteRelayer and quoteExclusivitySeconds are either both zero (indicating no exclusivity)\n /// or both non-zero (indicating exclusivity for the given period).\n /// Note: callValue \u003e 0 can NOT be used with destToken = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE (ETH_ADDRESS)\n /// @param quoteRelayer Relayer that provided the quote for the transaction\n /// @param quoteExclusivitySeconds Period of time the quote relayer is guaranteed exclusivity after user's deposit\n /// @param quoteId Unique quote identifier used for tracking the quote\n /// @param callValue ETH value to send to the recipient (if any)\n /// @param callParams Parameters for the arbitrary call to the destination recipient (if any)\n struct BridgeParamsV2 {\n address quoteRelayer;\n int256 quoteExclusivitySeconds;\n bytes quoteId;\n uint256 callValue;\n bytes callParams;\n }\n\n /// @notice Updated bridge transaction struct to include parameters introduced in FastBridgeV2.\n /// Note: only `exclusivityRelayer` can fill such a transaction until `exclusivityEndTime`.\n /// TODO: consider changing the encoding scheme to prevent spending extra gas on decoding.\n struct BridgeTransactionV2 {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n uint256 callValue; // ETH value to send to the recipient (if any) - replaces V1's sendChainGas flag\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n address exclusivityRelayer;\n uint256 exclusivityEndTime;\n bytes callParams;\n }\n\n event BridgeQuoteDetails(bytes32 indexed transactionId, bytes quoteId);\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability\n /// to provide temporary exclusivity fill rights for the quote relayer.\n /// @param params The parameters required to bridge\n /// @param paramsV2 The parameters for exclusivity fill rights (optional, can be left empty)\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function relay(bytes memory request, address relayer) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param transactionId The transaction id associated with the encoded bridge transaction to prove\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital.\n /// @notice Can only send funds to the relayer address on the proof.\n /// @param request The encoded bridge transaction to claim on origin chain\n function claim(bytes memory request) external;\n /// @notice Checks if a transaction has been relayed\n /// @param transactionId The ID of the transaction to check\n /// @return True if the transaction has been relayed, false otherwise\n function bridgeRelays(bytes32 transactionId) external view returns (bool);\n\n /// @notice Returns the status of a bridge transaction\n /// @param transactionId The ID of the bridge transaction\n /// @return BridgeStatus Status of the bridge transaction\n function bridgeStatuses(bytes32 transactionId) external view returns (BridgeStatus);\n\n /// @notice Returns the timestamp and relayer of a bridge proof\n /// @param transactionId The ID of the bridge transaction\n /// @return timestamp The timestamp of the bridge proof\n /// @return relayer The relayer address of the bridge proof\n function bridgeProofs(bytes32 transactionId) external view returns (uint96 timestamp, address relayer);\n\n /// @notice Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\n /// @param request The bridge request to decode\n function getBridgeTransactionV2(bytes memory request) external view returns (BridgeTransactionV2 memory);\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// contracts/libs/UniversalToken.sol\n\nlibrary UniversalTokenLib {\n using SafeERC20 for IERC20;\n\n address internal constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Transfers tokens to the given account. Reverts if transfer is not successful.\n /// @dev This might trigger fallback, if ETH is transferred to the contract.\n /// Make sure this can not lead to reentrancy attacks.\n function universalTransfer(address token, address to, uint256 value) internal {\n // Don't do anything, if need to send tokens to this address\n if (to == address(this)) return;\n // Don't do anything, if trying to send zero value\n if (value == 0) return;\n if (token == ETH_ADDRESS) {\n /// @dev Note: this can potentially lead to executing code in `to`.\n // solhint-disable-next-line avoid-low-level-calls\n (bool success,) = to.call{value: value}(\"\");\n require(success, \"ETH transfer failed\");\n } else {\n IERC20(token).safeTransfer(to, value);\n }\n }\n\n /// @notice Issues an infinite allowance to the spender, if the current allowance is insufficient\n /// to spend the given amount.\n function universalApproveInfinity(address token, address spender, uint256 amountToSpend) internal {\n // ETH Chad doesn't require your approval\n if (token == ETH_ADDRESS) return;\n // No-op if allowance is already sufficient\n uint256 allowance = IERC20(token).allowance(address(this), spender);\n if (allowance \u003e= amountToSpend) return;\n // Otherwise, reset approval to 0 and set to max allowance\n if (allowance \u003e 0) IERC20(token).safeDecreaseAllowance(spender, allowance);\n IERC20(token).safeIncreaseAllowance(spender, type(uint256).max);\n }\n\n /// @notice Returns the balance of the given token (or native ETH) for the given account.\n function universalBalanceOf(address token, address account) internal view returns (uint256) {\n if (token == ETH_ADDRESS) {\n return account.balance;\n } else {\n return IERC20(token).balanceOf(account);\n }\n }\n\n /// @dev Checks that token is a contract and not ETH_ADDRESS.\n function assertIsContract(address token) internal view {\n // Check that ETH_ADDRESS was not used (in case this is a predeploy on any of the chains)\n if (token == UniversalTokenLib.ETH_ADDRESS) revert TokenNotContract();\n // Check that token is not an EOA\n if (token.code.length == 0) revert TokenNotContract();\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/Admin.sol\n\ncontract Admin is IAdmin, AccessControlEnumerable {\n using UniversalTokenLib for address;\n\n bytes32 public constant RELAYER_ROLE = keccak256(\"RELAYER_ROLE\");\n bytes32 public constant REFUNDER_ROLE = keccak256(\"REFUNDER_ROLE\");\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n uint256 public constant FEE_BPS = 1e6;\n uint256 public constant FEE_RATE_MAX = 0.01e6; // max 1% on origin amount\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Chain gas amount to forward as rebate if requested\n uint256 public chainGasAmount;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n }\n\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n require(newFeeRate \u003c= FEE_RATE_MAX, \"newFeeRate \u003e max\");\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n token.universalTransfer(recipient, feeAmount);\n emit FeesSwept(token, recipient, feeAmount);\n }\n\n function setChainGasAmount(uint256 newChainGasAmount) external onlyRole(GOVERNOR_ROLE) {\n uint256 oldChainGasAmount = chainGasAmount;\n chainGasAmount = newChainGasAmount;\n emit ChainGasAmountUpdated(oldChainGasAmount, newChainGasAmount);\n }\n}\n\n// contracts/FastBridgeV2.sol\n\n/// @notice FastBridgeV2 is a contract for bridging tokens across chains.\ncontract FastBridgeV2 is Admin, IFastBridgeV2, IFastBridgeV2Errors {\n using SafeERC20 for IERC20;\n using UniversalTokenLib for address;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Delay for a transaction after which it could be permisionlessly refunded\n uint256 public constant REFUND_DELAY = 7 days;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n /// @notice Maximum length of accepted callParams\n uint256 public constant MAX_CALL_PARAMS_LENGTH = 2 ** 16 - 1;\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeTxDetails) public bridgeTxDetails;\n /// @notice Relay details on destination chain\n mapping(bytes32 =\u003e BridgeRelay) public bridgeRelayDetails;\n /// @notice Unique bridge nonces tracked per originSender\n mapping(address =\u003e uint256) public senderNonces;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Replaced by senderNonces\n uint256 public immutable nonce = 0;\n /// @notice the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n bridge({\n params: params,\n paramsV2: BridgeParamsV2({\n quoteRelayer: address(0),\n quoteExclusivitySeconds: 0,\n quoteId: bytes(\"\"),\n callValue: 0,\n callParams: bytes(\"\")\n })\n });\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes memory request) external payable {\n relay({request: request, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes memory request, bytes32 destTxHash) external {\n prove({transactionId: keccak256(request), destTxHash: destTxHash, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridgeV2\n function claim(bytes memory request) external {\n claim({request: request, to: address(0)});\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003e DISPUTE_PERIOD) {\n revert DisputePeriodPassed();\n }\n\n // @dev relayer gets slashed effectively if dest relay has gone thru\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n bridgeTxDetails[transactionId].proofRelayer = address(0);\n bridgeTxDetails[transactionId].proofBlockTimestamp = 0;\n bridgeTxDetails[transactionId].proofBlockNumber = 0;\n\n emit BridgeProofDisputed(transactionId, msg.sender);\n }\n\n /// @inheritdoc IFastBridge\n function refund(bytes memory request) external {\n bytes32 transactionId = keccak256(request);\n\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n\n if (bridgeTxDetails[transactionId].status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n\n if (hasRole(REFUNDER_ROLE, msg.sender)) {\n // Refunder can refund if deadline has passed\n if (block.timestamp \u003c= transaction.deadline) revert DeadlineNotExceeded();\n } else {\n // Permissionless refund is allowed after REFUND_DELAY\n if (block.timestamp \u003c= transaction.deadline + REFUND_DELAY) revert DeadlineNotExceeded();\n }\n\n // if all checks passed, set to REFUNDED status\n bridgeTxDetails[transactionId].status = BridgeStatus.REFUNDED;\n\n // transfer origin collateral back to original sender\n address to = transaction.originSender;\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount + transaction.originFeeAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (bridgeTxDetails[transactionId].proofRelayer != relayer) revert SenderIncorrect();\n return _timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n /// @dev This method is added to achieve backwards compatibility with decoding requests into V1 structs:\n /// - `callValue` is partially reported as a zero/non-zero flag\n /// - `callParams` is ignored\n /// In order to process all kinds of requests use getBridgeTransactionV2 instead.\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory) {\n // Try decoding into V2 struct first. This will revert if V1 struct is passed\n try this.getBridgeTransactionV2(request) returns (BridgeTransactionV2 memory txV2) {\n // Note: we entirely ignore the callParams field, as it was not present in V1\n return BridgeTransaction({\n originChainId: txV2.originChainId,\n destChainId: txV2.destChainId,\n originSender: txV2.originSender,\n destRecipient: txV2.destRecipient,\n originToken: txV2.originToken,\n destToken: txV2.destToken,\n originAmount: txV2.originAmount,\n destAmount: txV2.destAmount,\n originFeeAmount: txV2.originFeeAmount,\n sendChainGas: txV2.callValue != 0,\n deadline: txV2.deadline,\n nonce: txV2.nonce\n });\n } catch {\n // Fallback to V1 struct\n return abi.decode(request, (BridgeTransaction));\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) public payable {\n int256 exclusivityEndTime = int256(block.timestamp) + paramsV2.quoteExclusivitySeconds;\n _validateBridgeParams(params, paramsV2, exclusivityEndTime);\n\n // transfer tokens to bridge contract\n /// @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _pullToken(params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n\n // set status to requested\n bytes memory request = abi.encode(\n BridgeTransactionV2({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n callValue: paramsV2.callValue,\n deadline: params.deadline,\n nonce: senderNonces[params.sender]++, // increment nonce on every bridge\n exclusivityRelayer: paramsV2.quoteRelayer,\n // We checked exclusivityEndTime to be in range (0 .. params.deadline] above, so can safely cast\n exclusivityEndTime: uint256(exclusivityEndTime),\n callParams: paramsV2.callParams\n })\n );\n bytes32 transactionId = keccak256(request);\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n\n emit BridgeRequested({\n transactionId: transactionId,\n sender: params.sender,\n request: request,\n destChainId: params.dstChainId,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n sendChainGas: paramsV2.callValue != 0\n });\n emit BridgeQuoteDetails(transactionId, paramsV2.quoteId);\n }\n\n /// @inheritdoc IFastBridgeV2\n function relay(bytes memory request, address relayer) public payable {\n bytes32 transactionId = keccak256(request);\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n _validateRelayParams(transaction, transactionId, relayer);\n // mark bridge transaction as relayed\n bridgeRelayDetails[transactionId] =\n BridgeRelay({blockNumber: uint48(block.number), blockTimestamp: uint48(block.timestamp), relayer: relayer});\n\n // transfer tokens to recipient on destination chain and do an arbitrary call if requested\n address to = transaction.destRecipient;\n address token = transaction.destToken;\n uint256 amount = transaction.destAmount;\n\n // All state changes have been done at this point, can proceed to the external calls.\n // This follows the checks-effects-interactions pattern to mitigate potential reentrancy attacks.\n if (token == UniversalTokenLib.ETH_ADDRESS) {\n // For ETH non-zero callValue is not allowed\n if (transaction.callValue != 0) revert NativeTokenCallValueNotSupported();\n // Check that the correct msg.value was sent\n if (msg.value != amount) revert MsgValueIncorrect();\n } else {\n // For ERC20s, we check that the correct msg.value was sent\n if (msg.value != transaction.callValue) revert MsgValueIncorrect();\n // We need to transfer the tokens from the Relayer to the recipient first before performing an\n // optional post-transfer arbitrary call.\n IERC20(token).safeTransferFrom(msg.sender, to, amount);\n }\n\n if (transaction.callParams.length != 0) {\n // Arbitrary call requested, perform it while supplying full msg.value to the recipient\n // Note: if token has a fee on transfers, the recipient will have received less than `amount`.\n // This is a very niche edge case and should be handled by the recipient contract.\n _checkedCallRecipient({recipient: to, token: token, amount: amount, callParams: transaction.callParams});\n } else if (msg.value != 0) {\n // No arbitrary call requested, but msg.value was sent. This is either a relay with ETH,\n // or a non-zero callValue request with an ERC20. In both cases, transfer the ETH to the recipient.\n Address.sendValue(payable(to), msg.value);\n }\n\n emit BridgeRelayed({\n transactionId: transactionId,\n relayer: relayer,\n to: to,\n originChainId: transaction.originChainId,\n originToken: transaction.originToken,\n destToken: transaction.destToken,\n originAmount: transaction.originAmount,\n destAmount: transaction.destAmount,\n chainGasAmount: transaction.callValue\n });\n }\n\n /// @inheritdoc IFastBridgeV2\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) public onlyRole(RELAYER_ROLE) {\n // update bridge tx status given proof provided\n if (bridgeTxDetails[transactionId].status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n bridgeTxDetails[transactionId].status = BridgeStatus.RELAYER_PROVED;\n bridgeTxDetails[transactionId].proofBlockTimestamp = uint40(block.timestamp);\n bridgeTxDetails[transactionId].proofBlockNumber = uint48(block.number);\n bridgeTxDetails[transactionId].proofRelayer = relayer;\n\n emit BridgeProofProvided(transactionId, relayer, destTxHash);\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes memory request, address to) public {\n bytes32 transactionId = keccak256(request);\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n\n // update bridge tx status if able to claim origin collateral\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n\n // if \"to\" is zero addr, permissionlessly send funds to proven relayer\n if (to == address(0)) {\n to = bridgeTxDetails[transactionId].proofRelayer;\n } else if (bridgeTxDetails[transactionId].proofRelayer != msg.sender) {\n revert SenderIncorrect();\n }\n\n if (_timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003c= DISPUTE_PERIOD) {\n revert DisputePeriodNotPassed();\n }\n\n bridgeTxDetails[transactionId].status = BridgeStatus.RELAYER_CLAIMED;\n\n // update protocol fees if origin fee amount exists\n if (transaction.originFeeAmount \u003e 0) protocolFees[transaction.originToken] += transaction.originFeeAmount;\n\n // transfer origin collateral less fee to specified address\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositClaimed(transactionId, bridgeTxDetails[transactionId].proofRelayer, to, token, amount);\n }\n\n function bridgeStatuses(bytes32 transactionId) public view returns (BridgeStatus status) {\n return bridgeTxDetails[transactionId].status;\n }\n\n function bridgeProofs(bytes32 transactionId) public view returns (uint96 timestamp, address relayer) {\n timestamp = bridgeTxDetails[transactionId].proofBlockTimestamp;\n relayer = bridgeTxDetails[transactionId].proofRelayer;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeRelays(bytes32 transactionId) public view returns (bool) {\n // has this transactionId been relayed?\n return bridgeRelayDetails[transactionId].relayer != address(0);\n }\n\n /// @inheritdoc IFastBridgeV2\n function getBridgeTransactionV2(bytes memory request) public pure returns (BridgeTransactionV2 memory) {\n return abi.decode(request, (BridgeTransactionV2));\n }\n\n /// @notice Pulls a requested token from the user to this contract.\n function _pullToken(address token, uint256 amount) internal returns (uint256 amountPulled) {\n if (token == UniversalTokenLib.ETH_ADDRESS) {\n // For ETH we just need to check that the supplied msg.value is correct\n if (amount != msg.value) revert MsgValueIncorrect();\n amountPulled = msg.value;\n } else {\n token.assertIsContract();\n // Record token balance before transfer\n amountPulled = IERC20(token).balanceOf(address(this));\n // Token needs to be pulled only if msg.value is zero\n // This way user can specify WETH as the origin asset\n IERC20(token).safeTransferFrom(msg.sender, address(this), amount);\n // Use the difference between the recorded balance and the current balance as the amountPulled\n amountPulled = IERC20(token).balanceOf(address(this)) - amountPulled;\n }\n }\n\n /// @notice Calls the Recipient's hook function with the specified callParams and performs\n /// all the necessary checks for the returned value.\n function _checkedCallRecipient(\n address recipient,\n address token,\n uint256 amount,\n bytes memory callParams\n )\n internal\n {\n bytes memory hookData =\n abi.encodeCall(IFastBridgeRecipient.fastBridgeTransferReceived, (token, amount, callParams));\n // This will bubble any revert messages from the hook function\n bytes memory returnData = Address.functionCallWithValue({target: recipient, data: hookData, value: msg.value});\n // Explicit revert if no return data at all\n if (returnData.length == 0) revert RecipientNoReturnValue();\n // Check that exactly a single return value was returned\n if (returnData.length != 32) revert RecipientIncorrectReturnValue();\n // Return value should be abi-encoded hook function selector\n if (bytes32(returnData) != bytes32(IFastBridgeRecipient.fastBridgeTransferReceived.selector)) {\n revert RecipientIncorrectReturnValue();\n }\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint40(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint40).max but\n /// proof.timestamp \u003c type(uint40).max via unchecked statement\n /// @param proofBlockTimestamp The bridge proof block timestamp\n /// @return delta Time delta since proof submitted\n function _timeSince(uint40 proofBlockTimestamp) internal view returns (uint256 delta) {\n unchecked {\n delta = uint40(block.timestamp) - proofBlockTimestamp;\n }\n }\n\n /// @notice Performs all the necessary checks for a bridge to happen.\n /// @dev There's no good way to refactor this function to reduce cyclomatic complexity due to\n /// the number of checks that need to be performed, so we skip the code-complexity rule here.\n // solhint-disable-next-line code-complexity\n function _validateBridgeParams(\n BridgeParams memory params,\n BridgeParamsV2 memory paramsV2,\n int256 exclusivityEndTime\n )\n internal\n view\n {\n // Check V1 (legacy) params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.sender == address(0) || params.to == address(0)) revert ZeroAddress();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n // Check V2 params\n if (paramsV2.callParams.length \u003e MAX_CALL_PARAMS_LENGTH) revert CallParamsLengthAboveMax();\n if (paramsV2.callValue != 0 \u0026\u0026 params.destToken == UniversalTokenLib.ETH_ADDRESS) {\n revert NativeTokenCallValueNotSupported();\n }\n // exclusivityEndTime must be in range (0 .. params.deadline]\n if (exclusivityEndTime \u003c= 0 || exclusivityEndTime \u003e int256(params.deadline)) {\n revert ExclusivityParamsIncorrect();\n }\n }\n\n /// @notice Performs all the necessary checks for a relay to happen.\n function _validateRelayParams(\n BridgeTransactionV2 memory transaction,\n bytes32 transactionId,\n address relayer\n )\n internal\n view\n {\n if (relayer == address(0)) revert ZeroAddress();\n // Check if the transaction has already been relayed\n if (bridgeRelays(transactionId)) revert TransactionRelayed();\n if (transaction.destChainId != uint32(block.chainid)) revert ChainIncorrect();\n // Check the deadline for relay to happen\n if (block.timestamp \u003e transaction.deadline) revert DeadlineExceeded();\n // Check the exclusivity period, if it is still ongoing\n // forgefmt: disable-next-item\n if (\n transaction.exclusivityRelayer != address(0) \u0026\u0026\n transaction.exclusivityRelayer != relayer \u0026\u0026\n block.timestamp \u003c= transaction.exclusivityEndTime\n ) {\n revert ExclusivityPeriodNotPassed();\n }\n }\n}\n","language":"Solidity","languageVersion":"0.8.24","compilerVersion":"0.8.24","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"","srcMapRuntime":"","abiDefinition":[{"inputs":[],"name":"AccessControlBadConfirmation","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"bytes32","name":"neededRole","type":"bytes32"}],"name":"AccessControlUnauthorizedAccount","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"previousAdminRole","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"newAdminRole","type":"bytes32"}],"name":"RoleAdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleRevoked","type":"event"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleAdmin","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"uint256","name":"index","type":"uint256"}],"name":"getRoleMember","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleMemberCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"grantRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"hasRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"callerConfirmation","type":"address"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"revokeRole","outputs":[],"stateMutability":"nonpayable","type":"function"}],"userDoc":{"kind":"user","methods":{},"version":1},"developerDoc":{"details":"External interface of AccessControlEnumerable declared to support ERC165 detection.","errors":{"AccessControlBadConfirmation()":[{"details":"The caller of a function is not the expected one. NOTE: Don't confuse with {AccessControlUnauthorizedAccount}."}],"AccessControlUnauthorizedAccount(address,bytes32)":[{"details":"The `account` is missing a role."}]},"events":{"RoleAdminChanged(bytes32,bytes32,bytes32)":{"details":"Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole` `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite {RoleAdminChanged} not being emitted signaling this."},"RoleGranted(bytes32,address,address)":{"details":"Emitted when `account` is granted `role`. `sender` is the account that originated the contract call, an admin role bearer except when using {AccessControl-_setupRole}."},"RoleRevoked(bytes32,address,address)":{"details":"Emitted when `account` is revoked `role`. `sender` is the account that originated the contract call: - if using `revokeRole`, it is the admin role bearer - if using `renounceRole`, it is the role bearer (i.e. `account`)"}},"kind":"dev","methods":{"getRoleAdmin(bytes32)":{"details":"Returns the admin role that controls `role`. See {grantRole} and {revokeRole}. To change a role's admin, use {AccessControl-_setRoleAdmin}."},"getRoleMember(bytes32,uint256)":{"details":"Returns one of the accounts that have `role`. `index` must be a value between 0 and {getRoleMemberCount}, non-inclusive. Role bearers are not sorted in any particular way, and their ordering may change at any point. WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure you perform all queries on the same block. See the following https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post] for more information."},"getRoleMemberCount(bytes32)":{"details":"Returns the number of accounts that have `role`. Can be used together with {getRoleMember} to enumerate all bearers of a role."},"grantRole(bytes32,address)":{"details":"Grants `role` to `account`. If `account` had not been already granted `role`, emits a {RoleGranted} event. Requirements: - the caller must have ``role``'s admin role."},"hasRole(bytes32,address)":{"details":"Returns `true` if `account` has been granted `role`."},"renounceRole(bytes32,address)":{"details":"Revokes `role` from the calling account. Roles are often managed via {grantRole} and {revokeRole}: this function's purpose is to provide a mechanism for accounts to lose their privileges if they are compromised (such as when a trusted device is misplaced). If the calling account had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must be `callerConfirmation`."},"revokeRole(bytes32,address)":{"details":"Revokes `role` from `account`. If `account` had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must have ``role``'s admin role."}},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[],\"name\":\"AccessControlBadConfirmation\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"neededRole\",\"type\":\"bytes32\"}],\"name\":\"AccessControlUnauthorizedAccount\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"previousAdminRole\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"newAdminRole\",\"type\":\"bytes32\"}],\"name\":\"RoleAdminChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleGranted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleRevoked\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"}],\"name\":\"getRoleAdmin\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"index\",\"type\":\"uint256\"}],\"name\":\"getRoleMember\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"}],\"name\":\"getRoleMemberCount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"grantRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"hasRole\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"callerConfirmation\",\"type\":\"address\"}],\"name\":\"renounceRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"revokeRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"details\":\"External interface of AccessControlEnumerable declared to support ERC165 detection.\",\"errors\":{\"AccessControlBadConfirmation()\":[{\"details\":\"The caller of a function is not the expected one. NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\"}],\"AccessControlUnauthorizedAccount(address,bytes32)\":[{\"details\":\"The `account` is missing a role.\"}]},\"events\":{\"RoleAdminChanged(bytes32,bytes32,bytes32)\":{\"details\":\"Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole` `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite {RoleAdminChanged} not being emitted signaling this.\"},\"RoleGranted(bytes32,address,address)\":{\"details\":\"Emitted when `account` is granted `role`. `sender` is the account that originated the contract call, an admin role bearer except when using {AccessControl-_setupRole}.\"},\"RoleRevoked(bytes32,address,address)\":{\"details\":\"Emitted when `account` is revoked `role`. `sender` is the account that originated the contract call: - if using `revokeRole`, it is the admin role bearer - if using `renounceRole`, it is the role bearer (i.e. `account`)\"}},\"kind\":\"dev\",\"methods\":{\"getRoleAdmin(bytes32)\":{\"details\":\"Returns the admin role that controls `role`. See {grantRole} and {revokeRole}. To change a role's admin, use {AccessControl-_setRoleAdmin}.\"},\"getRoleMember(bytes32,uint256)\":{\"details\":\"Returns one of the accounts that have `role`. `index` must be a value between 0 and {getRoleMemberCount}, non-inclusive. Role bearers are not sorted in any particular way, and their ordering may change at any point. WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure you perform all queries on the same block. See the following https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post] for more information.\"},\"getRoleMemberCount(bytes32)\":{\"details\":\"Returns the number of accounts that have `role`. Can be used together with {getRoleMember} to enumerate all bearers of a role.\"},\"grantRole(bytes32,address)\":{\"details\":\"Grants `role` to `account`. If `account` had not been already granted `role`, emits a {RoleGranted} event. Requirements: - the caller must have ``role``'s admin role.\"},\"hasRole(bytes32,address)\":{\"details\":\"Returns `true` if `account` has been granted `role`.\"},\"renounceRole(bytes32,address)\":{\"details\":\"Revokes `role` from the calling account. Roles are often managed via {grantRole} and {revokeRole}: this function's purpose is to provide a mechanism for accounts to lose their privileges if they are compromised (such as when a trusted device is misplaced). If the calling account had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must be `callerConfirmation`.\"},\"revokeRole(bytes32,address)\":{\"details\":\"Revokes `role` from `account`. If `account` had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must have ``role``'s admin role.\"}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeV2.sol\":\"IAccessControlEnumerable\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeV2.sol\":{\"keccak256\":\"0x7cd0f885e80e2bdaa638bc32ae7af7d2e248f99ce4b354c217d0f0f7d7302e0a\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://7ccf28df0bd7b4606986585acd8622ed9b4e81379690061bb66088f0a2270af1\",\"dweb:/ipfs/QmTf7HNdHZkK6vmx8ZgewycQEb72oLD9nPwBpsM5reMstQ\"]}},\"version\":1}"},"hashes":{"getRoleAdmin(bytes32)":"248a9ca3","getRoleMember(bytes32,uint256)":"9010d07c","getRoleMemberCount(bytes32)":"ca15c873","grantRole(bytes32,address)":"2f2ff15d","hasRole(bytes32,address)":"91d14854","renounceRole(bytes32,address)":"36568abe","revokeRole(bytes32,address)":"d547741f"}},"solidity/FastBridgeV2.sol:IAdmin":{"code":"0x","runtime-code":"0x","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.24 ^0.8.0 ^0.8.20;\n\n// contracts/interfaces/IAdmin.sol\n\ninterface IAdmin {\n // ============ Events ============\n\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n event ChainGasAmountUpdated(uint256 oldChainGasAmount, uint256 newChainGasAmount);\n\n // ============ Methods ============\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n\n function setChainGasAmount(uint256 newChainGasAmount) external;\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IFastBridgeRecipient.sol\n\ninterface IFastBridgeRecipient {\n function fastBridgeTransferReceived(\n address token,\n uint256 amount,\n bytes memory callParams\n )\n external\n payable\n returns (bytes4);\n}\n\n// contracts/interfaces/IFastBridgeV2Errors.sol\n\ninterface IFastBridgeV2Errors {\n error AmountIncorrect();\n error CallParamsLengthAboveMax();\n error ChainIncorrect();\n error ExclusivityParamsIncorrect();\n error MsgValueIncorrect();\n error NativeTokenCallValueNotSupported();\n error SenderIncorrect();\n error StatusIncorrect();\n error ZeroAddress();\n\n error RecipientIncorrectReturnValue();\n error RecipientNoReturnValue();\n\n error DeadlineExceeded();\n error DeadlineNotExceeded();\n error DeadlineTooShort();\n error DisputePeriodNotPassed();\n error DisputePeriodPassed();\n error ExclusivityPeriodNotPassed();\n\n error TransactionRelayed();\n}\n\n// contracts/libs/Errors.sol\n\nerror DeadlineExceeded();\nerror DeadlineNotExceeded();\nerror DeadlineTooShort();\nerror InsufficientOutputAmount();\n\nerror MsgValueIncorrect();\nerror PoolNotFound();\nerror TokenAddressMismatch();\nerror TokenNotContract();\nerror TokenNotETH();\nerror TokensIdentical();\n\nerror ChainIncorrect();\nerror AmountIncorrect();\nerror ZeroAddress();\n\nerror DisputePeriodNotPassed();\nerror DisputePeriodPassed();\nerror SenderIncorrect();\nerror StatusIncorrect();\nerror TransactionIdIncorrect();\nerror TransactionRelayed();\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// contracts/interfaces/IFastBridgeV2.sol\n\ninterface IFastBridgeV2 is IFastBridge {\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n struct BridgeTxDetails {\n BridgeStatus status;\n uint40 proofBlockTimestamp;\n uint48 proofBlockNumber;\n address proofRelayer;\n }\n\n struct BridgeRelay {\n uint48 blockNumber;\n uint48 blockTimestamp;\n address relayer;\n }\n\n /// @notice New params introduced in the FastBridgeV2.\n /// We are passing fields from the older BridgeParams struct outside of this struct\n /// for backwards compatibility.\n /// Note: quoteRelayer and quoteExclusivitySeconds are either both zero (indicating no exclusivity)\n /// or both non-zero (indicating exclusivity for the given period).\n /// Note: callValue \u003e 0 can NOT be used with destToken = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE (ETH_ADDRESS)\n /// @param quoteRelayer Relayer that provided the quote for the transaction\n /// @param quoteExclusivitySeconds Period of time the quote relayer is guaranteed exclusivity after user's deposit\n /// @param quoteId Unique quote identifier used for tracking the quote\n /// @param callValue ETH value to send to the recipient (if any)\n /// @param callParams Parameters for the arbitrary call to the destination recipient (if any)\n struct BridgeParamsV2 {\n address quoteRelayer;\n int256 quoteExclusivitySeconds;\n bytes quoteId;\n uint256 callValue;\n bytes callParams;\n }\n\n /// @notice Updated bridge transaction struct to include parameters introduced in FastBridgeV2.\n /// Note: only `exclusivityRelayer` can fill such a transaction until `exclusivityEndTime`.\n /// TODO: consider changing the encoding scheme to prevent spending extra gas on decoding.\n struct BridgeTransactionV2 {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n uint256 callValue; // ETH value to send to the recipient (if any) - replaces V1's sendChainGas flag\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n address exclusivityRelayer;\n uint256 exclusivityEndTime;\n bytes callParams;\n }\n\n event BridgeQuoteDetails(bytes32 indexed transactionId, bytes quoteId);\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability\n /// to provide temporary exclusivity fill rights for the quote relayer.\n /// @param params The parameters required to bridge\n /// @param paramsV2 The parameters for exclusivity fill rights (optional, can be left empty)\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function relay(bytes memory request, address relayer) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param transactionId The transaction id associated with the encoded bridge transaction to prove\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital.\n /// @notice Can only send funds to the relayer address on the proof.\n /// @param request The encoded bridge transaction to claim on origin chain\n function claim(bytes memory request) external;\n /// @notice Checks if a transaction has been relayed\n /// @param transactionId The ID of the transaction to check\n /// @return True if the transaction has been relayed, false otherwise\n function bridgeRelays(bytes32 transactionId) external view returns (bool);\n\n /// @notice Returns the status of a bridge transaction\n /// @param transactionId The ID of the bridge transaction\n /// @return BridgeStatus Status of the bridge transaction\n function bridgeStatuses(bytes32 transactionId) external view returns (BridgeStatus);\n\n /// @notice Returns the timestamp and relayer of a bridge proof\n /// @param transactionId The ID of the bridge transaction\n /// @return timestamp The timestamp of the bridge proof\n /// @return relayer The relayer address of the bridge proof\n function bridgeProofs(bytes32 transactionId) external view returns (uint96 timestamp, address relayer);\n\n /// @notice Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\n /// @param request The bridge request to decode\n function getBridgeTransactionV2(bytes memory request) external view returns (BridgeTransactionV2 memory);\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// contracts/libs/UniversalToken.sol\n\nlibrary UniversalTokenLib {\n using SafeERC20 for IERC20;\n\n address internal constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Transfers tokens to the given account. Reverts if transfer is not successful.\n /// @dev This might trigger fallback, if ETH is transferred to the contract.\n /// Make sure this can not lead to reentrancy attacks.\n function universalTransfer(address token, address to, uint256 value) internal {\n // Don't do anything, if need to send tokens to this address\n if (to == address(this)) return;\n // Don't do anything, if trying to send zero value\n if (value == 0) return;\n if (token == ETH_ADDRESS) {\n /// @dev Note: this can potentially lead to executing code in `to`.\n // solhint-disable-next-line avoid-low-level-calls\n (bool success,) = to.call{value: value}(\"\");\n require(success, \"ETH transfer failed\");\n } else {\n IERC20(token).safeTransfer(to, value);\n }\n }\n\n /// @notice Issues an infinite allowance to the spender, if the current allowance is insufficient\n /// to spend the given amount.\n function universalApproveInfinity(address token, address spender, uint256 amountToSpend) internal {\n // ETH Chad doesn't require your approval\n if (token == ETH_ADDRESS) return;\n // No-op if allowance is already sufficient\n uint256 allowance = IERC20(token).allowance(address(this), spender);\n if (allowance \u003e= amountToSpend) return;\n // Otherwise, reset approval to 0 and set to max allowance\n if (allowance \u003e 0) IERC20(token).safeDecreaseAllowance(spender, allowance);\n IERC20(token).safeIncreaseAllowance(spender, type(uint256).max);\n }\n\n /// @notice Returns the balance of the given token (or native ETH) for the given account.\n function universalBalanceOf(address token, address account) internal view returns (uint256) {\n if (token == ETH_ADDRESS) {\n return account.balance;\n } else {\n return IERC20(token).balanceOf(account);\n }\n }\n\n /// @dev Checks that token is a contract and not ETH_ADDRESS.\n function assertIsContract(address token) internal view {\n // Check that ETH_ADDRESS was not used (in case this is a predeploy on any of the chains)\n if (token == UniversalTokenLib.ETH_ADDRESS) revert TokenNotContract();\n // Check that token is not an EOA\n if (token.code.length == 0) revert TokenNotContract();\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/Admin.sol\n\ncontract Admin is IAdmin, AccessControlEnumerable {\n using UniversalTokenLib for address;\n\n bytes32 public constant RELAYER_ROLE = keccak256(\"RELAYER_ROLE\");\n bytes32 public constant REFUNDER_ROLE = keccak256(\"REFUNDER_ROLE\");\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n uint256 public constant FEE_BPS = 1e6;\n uint256 public constant FEE_RATE_MAX = 0.01e6; // max 1% on origin amount\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Chain gas amount to forward as rebate if requested\n uint256 public chainGasAmount;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n }\n\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n require(newFeeRate \u003c= FEE_RATE_MAX, \"newFeeRate \u003e max\");\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n token.universalTransfer(recipient, feeAmount);\n emit FeesSwept(token, recipient, feeAmount);\n }\n\n function setChainGasAmount(uint256 newChainGasAmount) external onlyRole(GOVERNOR_ROLE) {\n uint256 oldChainGasAmount = chainGasAmount;\n chainGasAmount = newChainGasAmount;\n emit ChainGasAmountUpdated(oldChainGasAmount, newChainGasAmount);\n }\n}\n\n// contracts/FastBridgeV2.sol\n\n/// @notice FastBridgeV2 is a contract for bridging tokens across chains.\ncontract FastBridgeV2 is Admin, IFastBridgeV2, IFastBridgeV2Errors {\n using SafeERC20 for IERC20;\n using UniversalTokenLib for address;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Delay for a transaction after which it could be permisionlessly refunded\n uint256 public constant REFUND_DELAY = 7 days;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n /// @notice Maximum length of accepted callParams\n uint256 public constant MAX_CALL_PARAMS_LENGTH = 2 ** 16 - 1;\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeTxDetails) public bridgeTxDetails;\n /// @notice Relay details on destination chain\n mapping(bytes32 =\u003e BridgeRelay) public bridgeRelayDetails;\n /// @notice Unique bridge nonces tracked per originSender\n mapping(address =\u003e uint256) public senderNonces;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Replaced by senderNonces\n uint256 public immutable nonce = 0;\n /// @notice the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n bridge({\n params: params,\n paramsV2: BridgeParamsV2({\n quoteRelayer: address(0),\n quoteExclusivitySeconds: 0,\n quoteId: bytes(\"\"),\n callValue: 0,\n callParams: bytes(\"\")\n })\n });\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes memory request) external payable {\n relay({request: request, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes memory request, bytes32 destTxHash) external {\n prove({transactionId: keccak256(request), destTxHash: destTxHash, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridgeV2\n function claim(bytes memory request) external {\n claim({request: request, to: address(0)});\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003e DISPUTE_PERIOD) {\n revert DisputePeriodPassed();\n }\n\n // @dev relayer gets slashed effectively if dest relay has gone thru\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n bridgeTxDetails[transactionId].proofRelayer = address(0);\n bridgeTxDetails[transactionId].proofBlockTimestamp = 0;\n bridgeTxDetails[transactionId].proofBlockNumber = 0;\n\n emit BridgeProofDisputed(transactionId, msg.sender);\n }\n\n /// @inheritdoc IFastBridge\n function refund(bytes memory request) external {\n bytes32 transactionId = keccak256(request);\n\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n\n if (bridgeTxDetails[transactionId].status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n\n if (hasRole(REFUNDER_ROLE, msg.sender)) {\n // Refunder can refund if deadline has passed\n if (block.timestamp \u003c= transaction.deadline) revert DeadlineNotExceeded();\n } else {\n // Permissionless refund is allowed after REFUND_DELAY\n if (block.timestamp \u003c= transaction.deadline + REFUND_DELAY) revert DeadlineNotExceeded();\n }\n\n // if all checks passed, set to REFUNDED status\n bridgeTxDetails[transactionId].status = BridgeStatus.REFUNDED;\n\n // transfer origin collateral back to original sender\n address to = transaction.originSender;\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount + transaction.originFeeAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (bridgeTxDetails[transactionId].proofRelayer != relayer) revert SenderIncorrect();\n return _timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n /// @dev This method is added to achieve backwards compatibility with decoding requests into V1 structs:\n /// - `callValue` is partially reported as a zero/non-zero flag\n /// - `callParams` is ignored\n /// In order to process all kinds of requests use getBridgeTransactionV2 instead.\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory) {\n // Try decoding into V2 struct first. This will revert if V1 struct is passed\n try this.getBridgeTransactionV2(request) returns (BridgeTransactionV2 memory txV2) {\n // Note: we entirely ignore the callParams field, as it was not present in V1\n return BridgeTransaction({\n originChainId: txV2.originChainId,\n destChainId: txV2.destChainId,\n originSender: txV2.originSender,\n destRecipient: txV2.destRecipient,\n originToken: txV2.originToken,\n destToken: txV2.destToken,\n originAmount: txV2.originAmount,\n destAmount: txV2.destAmount,\n originFeeAmount: txV2.originFeeAmount,\n sendChainGas: txV2.callValue != 0,\n deadline: txV2.deadline,\n nonce: txV2.nonce\n });\n } catch {\n // Fallback to V1 struct\n return abi.decode(request, (BridgeTransaction));\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) public payable {\n int256 exclusivityEndTime = int256(block.timestamp) + paramsV2.quoteExclusivitySeconds;\n _validateBridgeParams(params, paramsV2, exclusivityEndTime);\n\n // transfer tokens to bridge contract\n /// @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _pullToken(params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n\n // set status to requested\n bytes memory request = abi.encode(\n BridgeTransactionV2({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n callValue: paramsV2.callValue,\n deadline: params.deadline,\n nonce: senderNonces[params.sender]++, // increment nonce on every bridge\n exclusivityRelayer: paramsV2.quoteRelayer,\n // We checked exclusivityEndTime to be in range (0 .. params.deadline] above, so can safely cast\n exclusivityEndTime: uint256(exclusivityEndTime),\n callParams: paramsV2.callParams\n })\n );\n bytes32 transactionId = keccak256(request);\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n\n emit BridgeRequested({\n transactionId: transactionId,\n sender: params.sender,\n request: request,\n destChainId: params.dstChainId,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n sendChainGas: paramsV2.callValue != 0\n });\n emit BridgeQuoteDetails(transactionId, paramsV2.quoteId);\n }\n\n /// @inheritdoc IFastBridgeV2\n function relay(bytes memory request, address relayer) public payable {\n bytes32 transactionId = keccak256(request);\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n _validateRelayParams(transaction, transactionId, relayer);\n // mark bridge transaction as relayed\n bridgeRelayDetails[transactionId] =\n BridgeRelay({blockNumber: uint48(block.number), blockTimestamp: uint48(block.timestamp), relayer: relayer});\n\n // transfer tokens to recipient on destination chain and do an arbitrary call if requested\n address to = transaction.destRecipient;\n address token = transaction.destToken;\n uint256 amount = transaction.destAmount;\n\n // All state changes have been done at this point, can proceed to the external calls.\n // This follows the checks-effects-interactions pattern to mitigate potential reentrancy attacks.\n if (token == UniversalTokenLib.ETH_ADDRESS) {\n // For ETH non-zero callValue is not allowed\n if (transaction.callValue != 0) revert NativeTokenCallValueNotSupported();\n // Check that the correct msg.value was sent\n if (msg.value != amount) revert MsgValueIncorrect();\n } else {\n // For ERC20s, we check that the correct msg.value was sent\n if (msg.value != transaction.callValue) revert MsgValueIncorrect();\n // We need to transfer the tokens from the Relayer to the recipient first before performing an\n // optional post-transfer arbitrary call.\n IERC20(token).safeTransferFrom(msg.sender, to, amount);\n }\n\n if (transaction.callParams.length != 0) {\n // Arbitrary call requested, perform it while supplying full msg.value to the recipient\n // Note: if token has a fee on transfers, the recipient will have received less than `amount`.\n // This is a very niche edge case and should be handled by the recipient contract.\n _checkedCallRecipient({recipient: to, token: token, amount: amount, callParams: transaction.callParams});\n } else if (msg.value != 0) {\n // No arbitrary call requested, but msg.value was sent. This is either a relay with ETH,\n // or a non-zero callValue request with an ERC20. In both cases, transfer the ETH to the recipient.\n Address.sendValue(payable(to), msg.value);\n }\n\n emit BridgeRelayed({\n transactionId: transactionId,\n relayer: relayer,\n to: to,\n originChainId: transaction.originChainId,\n originToken: transaction.originToken,\n destToken: transaction.destToken,\n originAmount: transaction.originAmount,\n destAmount: transaction.destAmount,\n chainGasAmount: transaction.callValue\n });\n }\n\n /// @inheritdoc IFastBridgeV2\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) public onlyRole(RELAYER_ROLE) {\n // update bridge tx status given proof provided\n if (bridgeTxDetails[transactionId].status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n bridgeTxDetails[transactionId].status = BridgeStatus.RELAYER_PROVED;\n bridgeTxDetails[transactionId].proofBlockTimestamp = uint40(block.timestamp);\n bridgeTxDetails[transactionId].proofBlockNumber = uint48(block.number);\n bridgeTxDetails[transactionId].proofRelayer = relayer;\n\n emit BridgeProofProvided(transactionId, relayer, destTxHash);\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes memory request, address to) public {\n bytes32 transactionId = keccak256(request);\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n\n // update bridge tx status if able to claim origin collateral\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n\n // if \"to\" is zero addr, permissionlessly send funds to proven relayer\n if (to == address(0)) {\n to = bridgeTxDetails[transactionId].proofRelayer;\n } else if (bridgeTxDetails[transactionId].proofRelayer != msg.sender) {\n revert SenderIncorrect();\n }\n\n if (_timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003c= DISPUTE_PERIOD) {\n revert DisputePeriodNotPassed();\n }\n\n bridgeTxDetails[transactionId].status = BridgeStatus.RELAYER_CLAIMED;\n\n // update protocol fees if origin fee amount exists\n if (transaction.originFeeAmount \u003e 0) protocolFees[transaction.originToken] += transaction.originFeeAmount;\n\n // transfer origin collateral less fee to specified address\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositClaimed(transactionId, bridgeTxDetails[transactionId].proofRelayer, to, token, amount);\n }\n\n function bridgeStatuses(bytes32 transactionId) public view returns (BridgeStatus status) {\n return bridgeTxDetails[transactionId].status;\n }\n\n function bridgeProofs(bytes32 transactionId) public view returns (uint96 timestamp, address relayer) {\n timestamp = bridgeTxDetails[transactionId].proofBlockTimestamp;\n relayer = bridgeTxDetails[transactionId].proofRelayer;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeRelays(bytes32 transactionId) public view returns (bool) {\n // has this transactionId been relayed?\n return bridgeRelayDetails[transactionId].relayer != address(0);\n }\n\n /// @inheritdoc IFastBridgeV2\n function getBridgeTransactionV2(bytes memory request) public pure returns (BridgeTransactionV2 memory) {\n return abi.decode(request, (BridgeTransactionV2));\n }\n\n /// @notice Pulls a requested token from the user to this contract.\n function _pullToken(address token, uint256 amount) internal returns (uint256 amountPulled) {\n if (token == UniversalTokenLib.ETH_ADDRESS) {\n // For ETH we just need to check that the supplied msg.value is correct\n if (amount != msg.value) revert MsgValueIncorrect();\n amountPulled = msg.value;\n } else {\n token.assertIsContract();\n // Record token balance before transfer\n amountPulled = IERC20(token).balanceOf(address(this));\n // Token needs to be pulled only if msg.value is zero\n // This way user can specify WETH as the origin asset\n IERC20(token).safeTransferFrom(msg.sender, address(this), amount);\n // Use the difference between the recorded balance and the current balance as the amountPulled\n amountPulled = IERC20(token).balanceOf(address(this)) - amountPulled;\n }\n }\n\n /// @notice Calls the Recipient's hook function with the specified callParams and performs\n /// all the necessary checks for the returned value.\n function _checkedCallRecipient(\n address recipient,\n address token,\n uint256 amount,\n bytes memory callParams\n )\n internal\n {\n bytes memory hookData =\n abi.encodeCall(IFastBridgeRecipient.fastBridgeTransferReceived, (token, amount, callParams));\n // This will bubble any revert messages from the hook function\n bytes memory returnData = Address.functionCallWithValue({target: recipient, data: hookData, value: msg.value});\n // Explicit revert if no return data at all\n if (returnData.length == 0) revert RecipientNoReturnValue();\n // Check that exactly a single return value was returned\n if (returnData.length != 32) revert RecipientIncorrectReturnValue();\n // Return value should be abi-encoded hook function selector\n if (bytes32(returnData) != bytes32(IFastBridgeRecipient.fastBridgeTransferReceived.selector)) {\n revert RecipientIncorrectReturnValue();\n }\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint40(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint40).max but\n /// proof.timestamp \u003c type(uint40).max via unchecked statement\n /// @param proofBlockTimestamp The bridge proof block timestamp\n /// @return delta Time delta since proof submitted\n function _timeSince(uint40 proofBlockTimestamp) internal view returns (uint256 delta) {\n unchecked {\n delta = uint40(block.timestamp) - proofBlockTimestamp;\n }\n }\n\n /// @notice Performs all the necessary checks for a bridge to happen.\n /// @dev There's no good way to refactor this function to reduce cyclomatic complexity due to\n /// the number of checks that need to be performed, so we skip the code-complexity rule here.\n // solhint-disable-next-line code-complexity\n function _validateBridgeParams(\n BridgeParams memory params,\n BridgeParamsV2 memory paramsV2,\n int256 exclusivityEndTime\n )\n internal\n view\n {\n // Check V1 (legacy) params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.sender == address(0) || params.to == address(0)) revert ZeroAddress();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n // Check V2 params\n if (paramsV2.callParams.length \u003e MAX_CALL_PARAMS_LENGTH) revert CallParamsLengthAboveMax();\n if (paramsV2.callValue != 0 \u0026\u0026 params.destToken == UniversalTokenLib.ETH_ADDRESS) {\n revert NativeTokenCallValueNotSupported();\n }\n // exclusivityEndTime must be in range (0 .. params.deadline]\n if (exclusivityEndTime \u003c= 0 || exclusivityEndTime \u003e int256(params.deadline)) {\n revert ExclusivityParamsIncorrect();\n }\n }\n\n /// @notice Performs all the necessary checks for a relay to happen.\n function _validateRelayParams(\n BridgeTransactionV2 memory transaction,\n bytes32 transactionId,\n address relayer\n )\n internal\n view\n {\n if (relayer == address(0)) revert ZeroAddress();\n // Check if the transaction has already been relayed\n if (bridgeRelays(transactionId)) revert TransactionRelayed();\n if (transaction.destChainId != uint32(block.chainid)) revert ChainIncorrect();\n // Check the deadline for relay to happen\n if (block.timestamp \u003e transaction.deadline) revert DeadlineExceeded();\n // Check the exclusivity period, if it is still ongoing\n // forgefmt: disable-next-item\n if (\n transaction.exclusivityRelayer != address(0) \u0026\u0026\n transaction.exclusivityRelayer != relayer \u0026\u0026\n block.timestamp \u003c= transaction.exclusivityEndTime\n ) {\n revert ExclusivityPeriodNotPassed();\n }\n }\n}\n","language":"Solidity","languageVersion":"0.8.24","compilerVersion":"0.8.24","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"","srcMapRuntime":"","abiDefinition":[{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldChainGasAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newChainGasAmount","type":"uint256"}],"name":"ChainGasAmountUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldFeeRate","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newFeeRate","type":"uint256"}],"name":"FeeRateUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"address","name":"recipient","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"FeesSwept","type":"event"},{"inputs":[{"internalType":"uint256","name":"newChainGasAmount","type":"uint256"}],"name":"setChainGasAmount","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"newFeeRate","type":"uint256"}],"name":"setProtocolFeeRate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"address","name":"recipient","type":"address"}],"name":"sweepProtocolFees","outputs":[],"stateMutability":"nonpayable","type":"function"}],"userDoc":{"kind":"user","methods":{},"version":1},"developerDoc":{"kind":"dev","methods":{},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"oldChainGasAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newChainGasAmount\",\"type\":\"uint256\"}],\"name\":\"ChainGasAmountUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"oldFeeRate\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newFeeRate\",\"type\":\"uint256\"}],\"name\":\"FeeRateUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"FeesSwept\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"newChainGasAmount\",\"type\":\"uint256\"}],\"name\":\"setChainGasAmount\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"newFeeRate\",\"type\":\"uint256\"}],\"name\":\"setProtocolFeeRate\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"}],\"name\":\"sweepProtocolFees\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeV2.sol\":\"IAdmin\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeV2.sol\":{\"keccak256\":\"0x7cd0f885e80e2bdaa638bc32ae7af7d2e248f99ce4b354c217d0f0f7d7302e0a\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://7ccf28df0bd7b4606986585acd8622ed9b4e81379690061bb66088f0a2270af1\",\"dweb:/ipfs/QmTf7HNdHZkK6vmx8ZgewycQEb72oLD9nPwBpsM5reMstQ\"]}},\"version\":1}"},"hashes":{"setChainGasAmount(uint256)":"b250fe6b","setProtocolFeeRate(uint256)":"b13aa2d6","sweepProtocolFees(address,address)":"06f333f2"}},"solidity/FastBridgeV2.sol:IERC165":{"code":"0x","runtime-code":"0x","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.24 ^0.8.0 ^0.8.20;\n\n// contracts/interfaces/IAdmin.sol\n\ninterface IAdmin {\n // ============ Events ============\n\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n event ChainGasAmountUpdated(uint256 oldChainGasAmount, uint256 newChainGasAmount);\n\n // ============ Methods ============\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n\n function setChainGasAmount(uint256 newChainGasAmount) external;\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IFastBridgeRecipient.sol\n\ninterface IFastBridgeRecipient {\n function fastBridgeTransferReceived(\n address token,\n uint256 amount,\n bytes memory callParams\n )\n external\n payable\n returns (bytes4);\n}\n\n// contracts/interfaces/IFastBridgeV2Errors.sol\n\ninterface IFastBridgeV2Errors {\n error AmountIncorrect();\n error CallParamsLengthAboveMax();\n error ChainIncorrect();\n error ExclusivityParamsIncorrect();\n error MsgValueIncorrect();\n error NativeTokenCallValueNotSupported();\n error SenderIncorrect();\n error StatusIncorrect();\n error ZeroAddress();\n\n error RecipientIncorrectReturnValue();\n error RecipientNoReturnValue();\n\n error DeadlineExceeded();\n error DeadlineNotExceeded();\n error DeadlineTooShort();\n error DisputePeriodNotPassed();\n error DisputePeriodPassed();\n error ExclusivityPeriodNotPassed();\n\n error TransactionRelayed();\n}\n\n// contracts/libs/Errors.sol\n\nerror DeadlineExceeded();\nerror DeadlineNotExceeded();\nerror DeadlineTooShort();\nerror InsufficientOutputAmount();\n\nerror MsgValueIncorrect();\nerror PoolNotFound();\nerror TokenAddressMismatch();\nerror TokenNotContract();\nerror TokenNotETH();\nerror TokensIdentical();\n\nerror ChainIncorrect();\nerror AmountIncorrect();\nerror ZeroAddress();\n\nerror DisputePeriodNotPassed();\nerror DisputePeriodPassed();\nerror SenderIncorrect();\nerror StatusIncorrect();\nerror TransactionIdIncorrect();\nerror TransactionRelayed();\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// contracts/interfaces/IFastBridgeV2.sol\n\ninterface IFastBridgeV2 is IFastBridge {\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n struct BridgeTxDetails {\n BridgeStatus status;\n uint40 proofBlockTimestamp;\n uint48 proofBlockNumber;\n address proofRelayer;\n }\n\n struct BridgeRelay {\n uint48 blockNumber;\n uint48 blockTimestamp;\n address relayer;\n }\n\n /// @notice New params introduced in the FastBridgeV2.\n /// We are passing fields from the older BridgeParams struct outside of this struct\n /// for backwards compatibility.\n /// Note: quoteRelayer and quoteExclusivitySeconds are either both zero (indicating no exclusivity)\n /// or both non-zero (indicating exclusivity for the given period).\n /// Note: callValue \u003e 0 can NOT be used with destToken = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE (ETH_ADDRESS)\n /// @param quoteRelayer Relayer that provided the quote for the transaction\n /// @param quoteExclusivitySeconds Period of time the quote relayer is guaranteed exclusivity after user's deposit\n /// @param quoteId Unique quote identifier used for tracking the quote\n /// @param callValue ETH value to send to the recipient (if any)\n /// @param callParams Parameters for the arbitrary call to the destination recipient (if any)\n struct BridgeParamsV2 {\n address quoteRelayer;\n int256 quoteExclusivitySeconds;\n bytes quoteId;\n uint256 callValue;\n bytes callParams;\n }\n\n /// @notice Updated bridge transaction struct to include parameters introduced in FastBridgeV2.\n /// Note: only `exclusivityRelayer` can fill such a transaction until `exclusivityEndTime`.\n /// TODO: consider changing the encoding scheme to prevent spending extra gas on decoding.\n struct BridgeTransactionV2 {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n uint256 callValue; // ETH value to send to the recipient (if any) - replaces V1's sendChainGas flag\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n address exclusivityRelayer;\n uint256 exclusivityEndTime;\n bytes callParams;\n }\n\n event BridgeQuoteDetails(bytes32 indexed transactionId, bytes quoteId);\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability\n /// to provide temporary exclusivity fill rights for the quote relayer.\n /// @param params The parameters required to bridge\n /// @param paramsV2 The parameters for exclusivity fill rights (optional, can be left empty)\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function relay(bytes memory request, address relayer) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param transactionId The transaction id associated with the encoded bridge transaction to prove\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital.\n /// @notice Can only send funds to the relayer address on the proof.\n /// @param request The encoded bridge transaction to claim on origin chain\n function claim(bytes memory request) external;\n /// @notice Checks if a transaction has been relayed\n /// @param transactionId The ID of the transaction to check\n /// @return True if the transaction has been relayed, false otherwise\n function bridgeRelays(bytes32 transactionId) external view returns (bool);\n\n /// @notice Returns the status of a bridge transaction\n /// @param transactionId The ID of the bridge transaction\n /// @return BridgeStatus Status of the bridge transaction\n function bridgeStatuses(bytes32 transactionId) external view returns (BridgeStatus);\n\n /// @notice Returns the timestamp and relayer of a bridge proof\n /// @param transactionId The ID of the bridge transaction\n /// @return timestamp The timestamp of the bridge proof\n /// @return relayer The relayer address of the bridge proof\n function bridgeProofs(bytes32 transactionId) external view returns (uint96 timestamp, address relayer);\n\n /// @notice Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\n /// @param request The bridge request to decode\n function getBridgeTransactionV2(bytes memory request) external view returns (BridgeTransactionV2 memory);\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// contracts/libs/UniversalToken.sol\n\nlibrary UniversalTokenLib {\n using SafeERC20 for IERC20;\n\n address internal constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Transfers tokens to the given account. Reverts if transfer is not successful.\n /// @dev This might trigger fallback, if ETH is transferred to the contract.\n /// Make sure this can not lead to reentrancy attacks.\n function universalTransfer(address token, address to, uint256 value) internal {\n // Don't do anything, if need to send tokens to this address\n if (to == address(this)) return;\n // Don't do anything, if trying to send zero value\n if (value == 0) return;\n if (token == ETH_ADDRESS) {\n /// @dev Note: this can potentially lead to executing code in `to`.\n // solhint-disable-next-line avoid-low-level-calls\n (bool success,) = to.call{value: value}(\"\");\n require(success, \"ETH transfer failed\");\n } else {\n IERC20(token).safeTransfer(to, value);\n }\n }\n\n /// @notice Issues an infinite allowance to the spender, if the current allowance is insufficient\n /// to spend the given amount.\n function universalApproveInfinity(address token, address spender, uint256 amountToSpend) internal {\n // ETH Chad doesn't require your approval\n if (token == ETH_ADDRESS) return;\n // No-op if allowance is already sufficient\n uint256 allowance = IERC20(token).allowance(address(this), spender);\n if (allowance \u003e= amountToSpend) return;\n // Otherwise, reset approval to 0 and set to max allowance\n if (allowance \u003e 0) IERC20(token).safeDecreaseAllowance(spender, allowance);\n IERC20(token).safeIncreaseAllowance(spender, type(uint256).max);\n }\n\n /// @notice Returns the balance of the given token (or native ETH) for the given account.\n function universalBalanceOf(address token, address account) internal view returns (uint256) {\n if (token == ETH_ADDRESS) {\n return account.balance;\n } else {\n return IERC20(token).balanceOf(account);\n }\n }\n\n /// @dev Checks that token is a contract and not ETH_ADDRESS.\n function assertIsContract(address token) internal view {\n // Check that ETH_ADDRESS was not used (in case this is a predeploy on any of the chains)\n if (token == UniversalTokenLib.ETH_ADDRESS) revert TokenNotContract();\n // Check that token is not an EOA\n if (token.code.length == 0) revert TokenNotContract();\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/Admin.sol\n\ncontract Admin is IAdmin, AccessControlEnumerable {\n using UniversalTokenLib for address;\n\n bytes32 public constant RELAYER_ROLE = keccak256(\"RELAYER_ROLE\");\n bytes32 public constant REFUNDER_ROLE = keccak256(\"REFUNDER_ROLE\");\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n uint256 public constant FEE_BPS = 1e6;\n uint256 public constant FEE_RATE_MAX = 0.01e6; // max 1% on origin amount\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Chain gas amount to forward as rebate if requested\n uint256 public chainGasAmount;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n }\n\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n require(newFeeRate \u003c= FEE_RATE_MAX, \"newFeeRate \u003e max\");\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n token.universalTransfer(recipient, feeAmount);\n emit FeesSwept(token, recipient, feeAmount);\n }\n\n function setChainGasAmount(uint256 newChainGasAmount) external onlyRole(GOVERNOR_ROLE) {\n uint256 oldChainGasAmount = chainGasAmount;\n chainGasAmount = newChainGasAmount;\n emit ChainGasAmountUpdated(oldChainGasAmount, newChainGasAmount);\n }\n}\n\n// contracts/FastBridgeV2.sol\n\n/// @notice FastBridgeV2 is a contract for bridging tokens across chains.\ncontract FastBridgeV2 is Admin, IFastBridgeV2, IFastBridgeV2Errors {\n using SafeERC20 for IERC20;\n using UniversalTokenLib for address;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Delay for a transaction after which it could be permisionlessly refunded\n uint256 public constant REFUND_DELAY = 7 days;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n /// @notice Maximum length of accepted callParams\n uint256 public constant MAX_CALL_PARAMS_LENGTH = 2 ** 16 - 1;\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeTxDetails) public bridgeTxDetails;\n /// @notice Relay details on destination chain\n mapping(bytes32 =\u003e BridgeRelay) public bridgeRelayDetails;\n /// @notice Unique bridge nonces tracked per originSender\n mapping(address =\u003e uint256) public senderNonces;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Replaced by senderNonces\n uint256 public immutable nonce = 0;\n /// @notice the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n bridge({\n params: params,\n paramsV2: BridgeParamsV2({\n quoteRelayer: address(0),\n quoteExclusivitySeconds: 0,\n quoteId: bytes(\"\"),\n callValue: 0,\n callParams: bytes(\"\")\n })\n });\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes memory request) external payable {\n relay({request: request, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes memory request, bytes32 destTxHash) external {\n prove({transactionId: keccak256(request), destTxHash: destTxHash, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridgeV2\n function claim(bytes memory request) external {\n claim({request: request, to: address(0)});\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003e DISPUTE_PERIOD) {\n revert DisputePeriodPassed();\n }\n\n // @dev relayer gets slashed effectively if dest relay has gone thru\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n bridgeTxDetails[transactionId].proofRelayer = address(0);\n bridgeTxDetails[transactionId].proofBlockTimestamp = 0;\n bridgeTxDetails[transactionId].proofBlockNumber = 0;\n\n emit BridgeProofDisputed(transactionId, msg.sender);\n }\n\n /// @inheritdoc IFastBridge\n function refund(bytes memory request) external {\n bytes32 transactionId = keccak256(request);\n\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n\n if (bridgeTxDetails[transactionId].status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n\n if (hasRole(REFUNDER_ROLE, msg.sender)) {\n // Refunder can refund if deadline has passed\n if (block.timestamp \u003c= transaction.deadline) revert DeadlineNotExceeded();\n } else {\n // Permissionless refund is allowed after REFUND_DELAY\n if (block.timestamp \u003c= transaction.deadline + REFUND_DELAY) revert DeadlineNotExceeded();\n }\n\n // if all checks passed, set to REFUNDED status\n bridgeTxDetails[transactionId].status = BridgeStatus.REFUNDED;\n\n // transfer origin collateral back to original sender\n address to = transaction.originSender;\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount + transaction.originFeeAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (bridgeTxDetails[transactionId].proofRelayer != relayer) revert SenderIncorrect();\n return _timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n /// @dev This method is added to achieve backwards compatibility with decoding requests into V1 structs:\n /// - `callValue` is partially reported as a zero/non-zero flag\n /// - `callParams` is ignored\n /// In order to process all kinds of requests use getBridgeTransactionV2 instead.\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory) {\n // Try decoding into V2 struct first. This will revert if V1 struct is passed\n try this.getBridgeTransactionV2(request) returns (BridgeTransactionV2 memory txV2) {\n // Note: we entirely ignore the callParams field, as it was not present in V1\n return BridgeTransaction({\n originChainId: txV2.originChainId,\n destChainId: txV2.destChainId,\n originSender: txV2.originSender,\n destRecipient: txV2.destRecipient,\n originToken: txV2.originToken,\n destToken: txV2.destToken,\n originAmount: txV2.originAmount,\n destAmount: txV2.destAmount,\n originFeeAmount: txV2.originFeeAmount,\n sendChainGas: txV2.callValue != 0,\n deadline: txV2.deadline,\n nonce: txV2.nonce\n });\n } catch {\n // Fallback to V1 struct\n return abi.decode(request, (BridgeTransaction));\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) public payable {\n int256 exclusivityEndTime = int256(block.timestamp) + paramsV2.quoteExclusivitySeconds;\n _validateBridgeParams(params, paramsV2, exclusivityEndTime);\n\n // transfer tokens to bridge contract\n /// @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _pullToken(params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n\n // set status to requested\n bytes memory request = abi.encode(\n BridgeTransactionV2({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n callValue: paramsV2.callValue,\n deadline: params.deadline,\n nonce: senderNonces[params.sender]++, // increment nonce on every bridge\n exclusivityRelayer: paramsV2.quoteRelayer,\n // We checked exclusivityEndTime to be in range (0 .. params.deadline] above, so can safely cast\n exclusivityEndTime: uint256(exclusivityEndTime),\n callParams: paramsV2.callParams\n })\n );\n bytes32 transactionId = keccak256(request);\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n\n emit BridgeRequested({\n transactionId: transactionId,\n sender: params.sender,\n request: request,\n destChainId: params.dstChainId,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n sendChainGas: paramsV2.callValue != 0\n });\n emit BridgeQuoteDetails(transactionId, paramsV2.quoteId);\n }\n\n /// @inheritdoc IFastBridgeV2\n function relay(bytes memory request, address relayer) public payable {\n bytes32 transactionId = keccak256(request);\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n _validateRelayParams(transaction, transactionId, relayer);\n // mark bridge transaction as relayed\n bridgeRelayDetails[transactionId] =\n BridgeRelay({blockNumber: uint48(block.number), blockTimestamp: uint48(block.timestamp), relayer: relayer});\n\n // transfer tokens to recipient on destination chain and do an arbitrary call if requested\n address to = transaction.destRecipient;\n address token = transaction.destToken;\n uint256 amount = transaction.destAmount;\n\n // All state changes have been done at this point, can proceed to the external calls.\n // This follows the checks-effects-interactions pattern to mitigate potential reentrancy attacks.\n if (token == UniversalTokenLib.ETH_ADDRESS) {\n // For ETH non-zero callValue is not allowed\n if (transaction.callValue != 0) revert NativeTokenCallValueNotSupported();\n // Check that the correct msg.value was sent\n if (msg.value != amount) revert MsgValueIncorrect();\n } else {\n // For ERC20s, we check that the correct msg.value was sent\n if (msg.value != transaction.callValue) revert MsgValueIncorrect();\n // We need to transfer the tokens from the Relayer to the recipient first before performing an\n // optional post-transfer arbitrary call.\n IERC20(token).safeTransferFrom(msg.sender, to, amount);\n }\n\n if (transaction.callParams.length != 0) {\n // Arbitrary call requested, perform it while supplying full msg.value to the recipient\n // Note: if token has a fee on transfers, the recipient will have received less than `amount`.\n // This is a very niche edge case and should be handled by the recipient contract.\n _checkedCallRecipient({recipient: to, token: token, amount: amount, callParams: transaction.callParams});\n } else if (msg.value != 0) {\n // No arbitrary call requested, but msg.value was sent. This is either a relay with ETH,\n // or a non-zero callValue request with an ERC20. In both cases, transfer the ETH to the recipient.\n Address.sendValue(payable(to), msg.value);\n }\n\n emit BridgeRelayed({\n transactionId: transactionId,\n relayer: relayer,\n to: to,\n originChainId: transaction.originChainId,\n originToken: transaction.originToken,\n destToken: transaction.destToken,\n originAmount: transaction.originAmount,\n destAmount: transaction.destAmount,\n chainGasAmount: transaction.callValue\n });\n }\n\n /// @inheritdoc IFastBridgeV2\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) public onlyRole(RELAYER_ROLE) {\n // update bridge tx status given proof provided\n if (bridgeTxDetails[transactionId].status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n bridgeTxDetails[transactionId].status = BridgeStatus.RELAYER_PROVED;\n bridgeTxDetails[transactionId].proofBlockTimestamp = uint40(block.timestamp);\n bridgeTxDetails[transactionId].proofBlockNumber = uint48(block.number);\n bridgeTxDetails[transactionId].proofRelayer = relayer;\n\n emit BridgeProofProvided(transactionId, relayer, destTxHash);\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes memory request, address to) public {\n bytes32 transactionId = keccak256(request);\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n\n // update bridge tx status if able to claim origin collateral\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n\n // if \"to\" is zero addr, permissionlessly send funds to proven relayer\n if (to == address(0)) {\n to = bridgeTxDetails[transactionId].proofRelayer;\n } else if (bridgeTxDetails[transactionId].proofRelayer != msg.sender) {\n revert SenderIncorrect();\n }\n\n if (_timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003c= DISPUTE_PERIOD) {\n revert DisputePeriodNotPassed();\n }\n\n bridgeTxDetails[transactionId].status = BridgeStatus.RELAYER_CLAIMED;\n\n // update protocol fees if origin fee amount exists\n if (transaction.originFeeAmount \u003e 0) protocolFees[transaction.originToken] += transaction.originFeeAmount;\n\n // transfer origin collateral less fee to specified address\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositClaimed(transactionId, bridgeTxDetails[transactionId].proofRelayer, to, token, amount);\n }\n\n function bridgeStatuses(bytes32 transactionId) public view returns (BridgeStatus status) {\n return bridgeTxDetails[transactionId].status;\n }\n\n function bridgeProofs(bytes32 transactionId) public view returns (uint96 timestamp, address relayer) {\n timestamp = bridgeTxDetails[transactionId].proofBlockTimestamp;\n relayer = bridgeTxDetails[transactionId].proofRelayer;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeRelays(bytes32 transactionId) public view returns (bool) {\n // has this transactionId been relayed?\n return bridgeRelayDetails[transactionId].relayer != address(0);\n }\n\n /// @inheritdoc IFastBridgeV2\n function getBridgeTransactionV2(bytes memory request) public pure returns (BridgeTransactionV2 memory) {\n return abi.decode(request, (BridgeTransactionV2));\n }\n\n /// @notice Pulls a requested token from the user to this contract.\n function _pullToken(address token, uint256 amount) internal returns (uint256 amountPulled) {\n if (token == UniversalTokenLib.ETH_ADDRESS) {\n // For ETH we just need to check that the supplied msg.value is correct\n if (amount != msg.value) revert MsgValueIncorrect();\n amountPulled = msg.value;\n } else {\n token.assertIsContract();\n // Record token balance before transfer\n amountPulled = IERC20(token).balanceOf(address(this));\n // Token needs to be pulled only if msg.value is zero\n // This way user can specify WETH as the origin asset\n IERC20(token).safeTransferFrom(msg.sender, address(this), amount);\n // Use the difference between the recorded balance and the current balance as the amountPulled\n amountPulled = IERC20(token).balanceOf(address(this)) - amountPulled;\n }\n }\n\n /// @notice Calls the Recipient's hook function with the specified callParams and performs\n /// all the necessary checks for the returned value.\n function _checkedCallRecipient(\n address recipient,\n address token,\n uint256 amount,\n bytes memory callParams\n )\n internal\n {\n bytes memory hookData =\n abi.encodeCall(IFastBridgeRecipient.fastBridgeTransferReceived, (token, amount, callParams));\n // This will bubble any revert messages from the hook function\n bytes memory returnData = Address.functionCallWithValue({target: recipient, data: hookData, value: msg.value});\n // Explicit revert if no return data at all\n if (returnData.length == 0) revert RecipientNoReturnValue();\n // Check that exactly a single return value was returned\n if (returnData.length != 32) revert RecipientIncorrectReturnValue();\n // Return value should be abi-encoded hook function selector\n if (bytes32(returnData) != bytes32(IFastBridgeRecipient.fastBridgeTransferReceived.selector)) {\n revert RecipientIncorrectReturnValue();\n }\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint40(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint40).max but\n /// proof.timestamp \u003c type(uint40).max via unchecked statement\n /// @param proofBlockTimestamp The bridge proof block timestamp\n /// @return delta Time delta since proof submitted\n function _timeSince(uint40 proofBlockTimestamp) internal view returns (uint256 delta) {\n unchecked {\n delta = uint40(block.timestamp) - proofBlockTimestamp;\n }\n }\n\n /// @notice Performs all the necessary checks for a bridge to happen.\n /// @dev There's no good way to refactor this function to reduce cyclomatic complexity due to\n /// the number of checks that need to be performed, so we skip the code-complexity rule here.\n // solhint-disable-next-line code-complexity\n function _validateBridgeParams(\n BridgeParams memory params,\n BridgeParamsV2 memory paramsV2,\n int256 exclusivityEndTime\n )\n internal\n view\n {\n // Check V1 (legacy) params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.sender == address(0) || params.to == address(0)) revert ZeroAddress();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n // Check V2 params\n if (paramsV2.callParams.length \u003e MAX_CALL_PARAMS_LENGTH) revert CallParamsLengthAboveMax();\n if (paramsV2.callValue != 0 \u0026\u0026 params.destToken == UniversalTokenLib.ETH_ADDRESS) {\n revert NativeTokenCallValueNotSupported();\n }\n // exclusivityEndTime must be in range (0 .. params.deadline]\n if (exclusivityEndTime \u003c= 0 || exclusivityEndTime \u003e int256(params.deadline)) {\n revert ExclusivityParamsIncorrect();\n }\n }\n\n /// @notice Performs all the necessary checks for a relay to happen.\n function _validateRelayParams(\n BridgeTransactionV2 memory transaction,\n bytes32 transactionId,\n address relayer\n )\n internal\n view\n {\n if (relayer == address(0)) revert ZeroAddress();\n // Check if the transaction has already been relayed\n if (bridgeRelays(transactionId)) revert TransactionRelayed();\n if (transaction.destChainId != uint32(block.chainid)) revert ChainIncorrect();\n // Check the deadline for relay to happen\n if (block.timestamp \u003e transaction.deadline) revert DeadlineExceeded();\n // Check the exclusivity period, if it is still ongoing\n // forgefmt: disable-next-item\n if (\n transaction.exclusivityRelayer != address(0) \u0026\u0026\n transaction.exclusivityRelayer != relayer \u0026\u0026\n block.timestamp \u003c= transaction.exclusivityEndTime\n ) {\n revert ExclusivityPeriodNotPassed();\n }\n }\n}\n","language":"Solidity","languageVersion":"0.8.24","compilerVersion":"0.8.24","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"","srcMapRuntime":"","abiDefinition":[{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"}],"userDoc":{"kind":"user","methods":{},"version":1},"developerDoc":{"details":"Interface of the ERC165 standard, as defined in the https://eips.ethereum.org/EIPS/eip-165[EIP]. Implementers can declare support of contract interfaces, which can then be queried by others ({ERC165Checker}). For an implementation, see {ERC165}.","kind":"dev","methods":{"supportsInterface(bytes4)":{"details":"Returns true if this contract implements the interface defined by `interfaceId`. See the corresponding https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section] to learn more about how these ids are created. This function call must use less than 30 000 gas."}},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"bytes4\",\"name\":\"interfaceId\",\"type\":\"bytes4\"}],\"name\":\"supportsInterface\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"}],\"devdoc\":{\"details\":\"Interface of the ERC165 standard, as defined in the https://eips.ethereum.org/EIPS/eip-165[EIP]. Implementers can declare support of contract interfaces, which can then be queried by others ({ERC165Checker}). For an implementation, see {ERC165}.\",\"kind\":\"dev\",\"methods\":{\"supportsInterface(bytes4)\":{\"details\":\"Returns true if this contract implements the interface defined by `interfaceId`. See the corresponding https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section] to learn more about how these ids are created. This function call must use less than 30 000 gas.\"}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeV2.sol\":\"IERC165\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeV2.sol\":{\"keccak256\":\"0x7cd0f885e80e2bdaa638bc32ae7af7d2e248f99ce4b354c217d0f0f7d7302e0a\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://7ccf28df0bd7b4606986585acd8622ed9b4e81379690061bb66088f0a2270af1\",\"dweb:/ipfs/QmTf7HNdHZkK6vmx8ZgewycQEb72oLD9nPwBpsM5reMstQ\"]}},\"version\":1}"},"hashes":{"supportsInterface(bytes4)":"01ffc9a7"}},"solidity/FastBridgeV2.sol:IERC20":{"code":"0x","runtime-code":"0x","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.24 ^0.8.0 ^0.8.20;\n\n// contracts/interfaces/IAdmin.sol\n\ninterface IAdmin {\n // ============ Events ============\n\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n event ChainGasAmountUpdated(uint256 oldChainGasAmount, uint256 newChainGasAmount);\n\n // ============ Methods ============\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n\n function setChainGasAmount(uint256 newChainGasAmount) external;\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IFastBridgeRecipient.sol\n\ninterface IFastBridgeRecipient {\n function fastBridgeTransferReceived(\n address token,\n uint256 amount,\n bytes memory callParams\n )\n external\n payable\n returns (bytes4);\n}\n\n// contracts/interfaces/IFastBridgeV2Errors.sol\n\ninterface IFastBridgeV2Errors {\n error AmountIncorrect();\n error CallParamsLengthAboveMax();\n error ChainIncorrect();\n error ExclusivityParamsIncorrect();\n error MsgValueIncorrect();\n error NativeTokenCallValueNotSupported();\n error SenderIncorrect();\n error StatusIncorrect();\n error ZeroAddress();\n\n error RecipientIncorrectReturnValue();\n error RecipientNoReturnValue();\n\n error DeadlineExceeded();\n error DeadlineNotExceeded();\n error DeadlineTooShort();\n error DisputePeriodNotPassed();\n error DisputePeriodPassed();\n error ExclusivityPeriodNotPassed();\n\n error TransactionRelayed();\n}\n\n// contracts/libs/Errors.sol\n\nerror DeadlineExceeded();\nerror DeadlineNotExceeded();\nerror DeadlineTooShort();\nerror InsufficientOutputAmount();\n\nerror MsgValueIncorrect();\nerror PoolNotFound();\nerror TokenAddressMismatch();\nerror TokenNotContract();\nerror TokenNotETH();\nerror TokensIdentical();\n\nerror ChainIncorrect();\nerror AmountIncorrect();\nerror ZeroAddress();\n\nerror DisputePeriodNotPassed();\nerror DisputePeriodPassed();\nerror SenderIncorrect();\nerror StatusIncorrect();\nerror TransactionIdIncorrect();\nerror TransactionRelayed();\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// contracts/interfaces/IFastBridgeV2.sol\n\ninterface IFastBridgeV2 is IFastBridge {\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n struct BridgeTxDetails {\n BridgeStatus status;\n uint40 proofBlockTimestamp;\n uint48 proofBlockNumber;\n address proofRelayer;\n }\n\n struct BridgeRelay {\n uint48 blockNumber;\n uint48 blockTimestamp;\n address relayer;\n }\n\n /// @notice New params introduced in the FastBridgeV2.\n /// We are passing fields from the older BridgeParams struct outside of this struct\n /// for backwards compatibility.\n /// Note: quoteRelayer and quoteExclusivitySeconds are either both zero (indicating no exclusivity)\n /// or both non-zero (indicating exclusivity for the given period).\n /// Note: callValue \u003e 0 can NOT be used with destToken = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE (ETH_ADDRESS)\n /// @param quoteRelayer Relayer that provided the quote for the transaction\n /// @param quoteExclusivitySeconds Period of time the quote relayer is guaranteed exclusivity after user's deposit\n /// @param quoteId Unique quote identifier used for tracking the quote\n /// @param callValue ETH value to send to the recipient (if any)\n /// @param callParams Parameters for the arbitrary call to the destination recipient (if any)\n struct BridgeParamsV2 {\n address quoteRelayer;\n int256 quoteExclusivitySeconds;\n bytes quoteId;\n uint256 callValue;\n bytes callParams;\n }\n\n /// @notice Updated bridge transaction struct to include parameters introduced in FastBridgeV2.\n /// Note: only `exclusivityRelayer` can fill such a transaction until `exclusivityEndTime`.\n /// TODO: consider changing the encoding scheme to prevent spending extra gas on decoding.\n struct BridgeTransactionV2 {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n uint256 callValue; // ETH value to send to the recipient (if any) - replaces V1's sendChainGas flag\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n address exclusivityRelayer;\n uint256 exclusivityEndTime;\n bytes callParams;\n }\n\n event BridgeQuoteDetails(bytes32 indexed transactionId, bytes quoteId);\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability\n /// to provide temporary exclusivity fill rights for the quote relayer.\n /// @param params The parameters required to bridge\n /// @param paramsV2 The parameters for exclusivity fill rights (optional, can be left empty)\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function relay(bytes memory request, address relayer) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param transactionId The transaction id associated with the encoded bridge transaction to prove\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital.\n /// @notice Can only send funds to the relayer address on the proof.\n /// @param request The encoded bridge transaction to claim on origin chain\n function claim(bytes memory request) external;\n /// @notice Checks if a transaction has been relayed\n /// @param transactionId The ID of the transaction to check\n /// @return True if the transaction has been relayed, false otherwise\n function bridgeRelays(bytes32 transactionId) external view returns (bool);\n\n /// @notice Returns the status of a bridge transaction\n /// @param transactionId The ID of the bridge transaction\n /// @return BridgeStatus Status of the bridge transaction\n function bridgeStatuses(bytes32 transactionId) external view returns (BridgeStatus);\n\n /// @notice Returns the timestamp and relayer of a bridge proof\n /// @param transactionId The ID of the bridge transaction\n /// @return timestamp The timestamp of the bridge proof\n /// @return relayer The relayer address of the bridge proof\n function bridgeProofs(bytes32 transactionId) external view returns (uint96 timestamp, address relayer);\n\n /// @notice Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\n /// @param request The bridge request to decode\n function getBridgeTransactionV2(bytes memory request) external view returns (BridgeTransactionV2 memory);\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// contracts/libs/UniversalToken.sol\n\nlibrary UniversalTokenLib {\n using SafeERC20 for IERC20;\n\n address internal constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Transfers tokens to the given account. Reverts if transfer is not successful.\n /// @dev This might trigger fallback, if ETH is transferred to the contract.\n /// Make sure this can not lead to reentrancy attacks.\n function universalTransfer(address token, address to, uint256 value) internal {\n // Don't do anything, if need to send tokens to this address\n if (to == address(this)) return;\n // Don't do anything, if trying to send zero value\n if (value == 0) return;\n if (token == ETH_ADDRESS) {\n /// @dev Note: this can potentially lead to executing code in `to`.\n // solhint-disable-next-line avoid-low-level-calls\n (bool success,) = to.call{value: value}(\"\");\n require(success, \"ETH transfer failed\");\n } else {\n IERC20(token).safeTransfer(to, value);\n }\n }\n\n /// @notice Issues an infinite allowance to the spender, if the current allowance is insufficient\n /// to spend the given amount.\n function universalApproveInfinity(address token, address spender, uint256 amountToSpend) internal {\n // ETH Chad doesn't require your approval\n if (token == ETH_ADDRESS) return;\n // No-op if allowance is already sufficient\n uint256 allowance = IERC20(token).allowance(address(this), spender);\n if (allowance \u003e= amountToSpend) return;\n // Otherwise, reset approval to 0 and set to max allowance\n if (allowance \u003e 0) IERC20(token).safeDecreaseAllowance(spender, allowance);\n IERC20(token).safeIncreaseAllowance(spender, type(uint256).max);\n }\n\n /// @notice Returns the balance of the given token (or native ETH) for the given account.\n function universalBalanceOf(address token, address account) internal view returns (uint256) {\n if (token == ETH_ADDRESS) {\n return account.balance;\n } else {\n return IERC20(token).balanceOf(account);\n }\n }\n\n /// @dev Checks that token is a contract and not ETH_ADDRESS.\n function assertIsContract(address token) internal view {\n // Check that ETH_ADDRESS was not used (in case this is a predeploy on any of the chains)\n if (token == UniversalTokenLib.ETH_ADDRESS) revert TokenNotContract();\n // Check that token is not an EOA\n if (token.code.length == 0) revert TokenNotContract();\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/Admin.sol\n\ncontract Admin is IAdmin, AccessControlEnumerable {\n using UniversalTokenLib for address;\n\n bytes32 public constant RELAYER_ROLE = keccak256(\"RELAYER_ROLE\");\n bytes32 public constant REFUNDER_ROLE = keccak256(\"REFUNDER_ROLE\");\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n uint256 public constant FEE_BPS = 1e6;\n uint256 public constant FEE_RATE_MAX = 0.01e6; // max 1% on origin amount\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Chain gas amount to forward as rebate if requested\n uint256 public chainGasAmount;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n }\n\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n require(newFeeRate \u003c= FEE_RATE_MAX, \"newFeeRate \u003e max\");\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n token.universalTransfer(recipient, feeAmount);\n emit FeesSwept(token, recipient, feeAmount);\n }\n\n function setChainGasAmount(uint256 newChainGasAmount) external onlyRole(GOVERNOR_ROLE) {\n uint256 oldChainGasAmount = chainGasAmount;\n chainGasAmount = newChainGasAmount;\n emit ChainGasAmountUpdated(oldChainGasAmount, newChainGasAmount);\n }\n}\n\n// contracts/FastBridgeV2.sol\n\n/// @notice FastBridgeV2 is a contract for bridging tokens across chains.\ncontract FastBridgeV2 is Admin, IFastBridgeV2, IFastBridgeV2Errors {\n using SafeERC20 for IERC20;\n using UniversalTokenLib for address;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Delay for a transaction after which it could be permisionlessly refunded\n uint256 public constant REFUND_DELAY = 7 days;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n /// @notice Maximum length of accepted callParams\n uint256 public constant MAX_CALL_PARAMS_LENGTH = 2 ** 16 - 1;\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeTxDetails) public bridgeTxDetails;\n /// @notice Relay details on destination chain\n mapping(bytes32 =\u003e BridgeRelay) public bridgeRelayDetails;\n /// @notice Unique bridge nonces tracked per originSender\n mapping(address =\u003e uint256) public senderNonces;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Replaced by senderNonces\n uint256 public immutable nonce = 0;\n /// @notice the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n bridge({\n params: params,\n paramsV2: BridgeParamsV2({\n quoteRelayer: address(0),\n quoteExclusivitySeconds: 0,\n quoteId: bytes(\"\"),\n callValue: 0,\n callParams: bytes(\"\")\n })\n });\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes memory request) external payable {\n relay({request: request, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes memory request, bytes32 destTxHash) external {\n prove({transactionId: keccak256(request), destTxHash: destTxHash, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridgeV2\n function claim(bytes memory request) external {\n claim({request: request, to: address(0)});\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003e DISPUTE_PERIOD) {\n revert DisputePeriodPassed();\n }\n\n // @dev relayer gets slashed effectively if dest relay has gone thru\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n bridgeTxDetails[transactionId].proofRelayer = address(0);\n bridgeTxDetails[transactionId].proofBlockTimestamp = 0;\n bridgeTxDetails[transactionId].proofBlockNumber = 0;\n\n emit BridgeProofDisputed(transactionId, msg.sender);\n }\n\n /// @inheritdoc IFastBridge\n function refund(bytes memory request) external {\n bytes32 transactionId = keccak256(request);\n\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n\n if (bridgeTxDetails[transactionId].status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n\n if (hasRole(REFUNDER_ROLE, msg.sender)) {\n // Refunder can refund if deadline has passed\n if (block.timestamp \u003c= transaction.deadline) revert DeadlineNotExceeded();\n } else {\n // Permissionless refund is allowed after REFUND_DELAY\n if (block.timestamp \u003c= transaction.deadline + REFUND_DELAY) revert DeadlineNotExceeded();\n }\n\n // if all checks passed, set to REFUNDED status\n bridgeTxDetails[transactionId].status = BridgeStatus.REFUNDED;\n\n // transfer origin collateral back to original sender\n address to = transaction.originSender;\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount + transaction.originFeeAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (bridgeTxDetails[transactionId].proofRelayer != relayer) revert SenderIncorrect();\n return _timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n /// @dev This method is added to achieve backwards compatibility with decoding requests into V1 structs:\n /// - `callValue` is partially reported as a zero/non-zero flag\n /// - `callParams` is ignored\n /// In order to process all kinds of requests use getBridgeTransactionV2 instead.\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory) {\n // Try decoding into V2 struct first. This will revert if V1 struct is passed\n try this.getBridgeTransactionV2(request) returns (BridgeTransactionV2 memory txV2) {\n // Note: we entirely ignore the callParams field, as it was not present in V1\n return BridgeTransaction({\n originChainId: txV2.originChainId,\n destChainId: txV2.destChainId,\n originSender: txV2.originSender,\n destRecipient: txV2.destRecipient,\n originToken: txV2.originToken,\n destToken: txV2.destToken,\n originAmount: txV2.originAmount,\n destAmount: txV2.destAmount,\n originFeeAmount: txV2.originFeeAmount,\n sendChainGas: txV2.callValue != 0,\n deadline: txV2.deadline,\n nonce: txV2.nonce\n });\n } catch {\n // Fallback to V1 struct\n return abi.decode(request, (BridgeTransaction));\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) public payable {\n int256 exclusivityEndTime = int256(block.timestamp) + paramsV2.quoteExclusivitySeconds;\n _validateBridgeParams(params, paramsV2, exclusivityEndTime);\n\n // transfer tokens to bridge contract\n /// @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _pullToken(params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n\n // set status to requested\n bytes memory request = abi.encode(\n BridgeTransactionV2({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n callValue: paramsV2.callValue,\n deadline: params.deadline,\n nonce: senderNonces[params.sender]++, // increment nonce on every bridge\n exclusivityRelayer: paramsV2.quoteRelayer,\n // We checked exclusivityEndTime to be in range (0 .. params.deadline] above, so can safely cast\n exclusivityEndTime: uint256(exclusivityEndTime),\n callParams: paramsV2.callParams\n })\n );\n bytes32 transactionId = keccak256(request);\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n\n emit BridgeRequested({\n transactionId: transactionId,\n sender: params.sender,\n request: request,\n destChainId: params.dstChainId,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n sendChainGas: paramsV2.callValue != 0\n });\n emit BridgeQuoteDetails(transactionId, paramsV2.quoteId);\n }\n\n /// @inheritdoc IFastBridgeV2\n function relay(bytes memory request, address relayer) public payable {\n bytes32 transactionId = keccak256(request);\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n _validateRelayParams(transaction, transactionId, relayer);\n // mark bridge transaction as relayed\n bridgeRelayDetails[transactionId] =\n BridgeRelay({blockNumber: uint48(block.number), blockTimestamp: uint48(block.timestamp), relayer: relayer});\n\n // transfer tokens to recipient on destination chain and do an arbitrary call if requested\n address to = transaction.destRecipient;\n address token = transaction.destToken;\n uint256 amount = transaction.destAmount;\n\n // All state changes have been done at this point, can proceed to the external calls.\n // This follows the checks-effects-interactions pattern to mitigate potential reentrancy attacks.\n if (token == UniversalTokenLib.ETH_ADDRESS) {\n // For ETH non-zero callValue is not allowed\n if (transaction.callValue != 0) revert NativeTokenCallValueNotSupported();\n // Check that the correct msg.value was sent\n if (msg.value != amount) revert MsgValueIncorrect();\n } else {\n // For ERC20s, we check that the correct msg.value was sent\n if (msg.value != transaction.callValue) revert MsgValueIncorrect();\n // We need to transfer the tokens from the Relayer to the recipient first before performing an\n // optional post-transfer arbitrary call.\n IERC20(token).safeTransferFrom(msg.sender, to, amount);\n }\n\n if (transaction.callParams.length != 0) {\n // Arbitrary call requested, perform it while supplying full msg.value to the recipient\n // Note: if token has a fee on transfers, the recipient will have received less than `amount`.\n // This is a very niche edge case and should be handled by the recipient contract.\n _checkedCallRecipient({recipient: to, token: token, amount: amount, callParams: transaction.callParams});\n } else if (msg.value != 0) {\n // No arbitrary call requested, but msg.value was sent. This is either a relay with ETH,\n // or a non-zero callValue request with an ERC20. In both cases, transfer the ETH to the recipient.\n Address.sendValue(payable(to), msg.value);\n }\n\n emit BridgeRelayed({\n transactionId: transactionId,\n relayer: relayer,\n to: to,\n originChainId: transaction.originChainId,\n originToken: transaction.originToken,\n destToken: transaction.destToken,\n originAmount: transaction.originAmount,\n destAmount: transaction.destAmount,\n chainGasAmount: transaction.callValue\n });\n }\n\n /// @inheritdoc IFastBridgeV2\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) public onlyRole(RELAYER_ROLE) {\n // update bridge tx status given proof provided\n if (bridgeTxDetails[transactionId].status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n bridgeTxDetails[transactionId].status = BridgeStatus.RELAYER_PROVED;\n bridgeTxDetails[transactionId].proofBlockTimestamp = uint40(block.timestamp);\n bridgeTxDetails[transactionId].proofBlockNumber = uint48(block.number);\n bridgeTxDetails[transactionId].proofRelayer = relayer;\n\n emit BridgeProofProvided(transactionId, relayer, destTxHash);\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes memory request, address to) public {\n bytes32 transactionId = keccak256(request);\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n\n // update bridge tx status if able to claim origin collateral\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n\n // if \"to\" is zero addr, permissionlessly send funds to proven relayer\n if (to == address(0)) {\n to = bridgeTxDetails[transactionId].proofRelayer;\n } else if (bridgeTxDetails[transactionId].proofRelayer != msg.sender) {\n revert SenderIncorrect();\n }\n\n if (_timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003c= DISPUTE_PERIOD) {\n revert DisputePeriodNotPassed();\n }\n\n bridgeTxDetails[transactionId].status = BridgeStatus.RELAYER_CLAIMED;\n\n // update protocol fees if origin fee amount exists\n if (transaction.originFeeAmount \u003e 0) protocolFees[transaction.originToken] += transaction.originFeeAmount;\n\n // transfer origin collateral less fee to specified address\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositClaimed(transactionId, bridgeTxDetails[transactionId].proofRelayer, to, token, amount);\n }\n\n function bridgeStatuses(bytes32 transactionId) public view returns (BridgeStatus status) {\n return bridgeTxDetails[transactionId].status;\n }\n\n function bridgeProofs(bytes32 transactionId) public view returns (uint96 timestamp, address relayer) {\n timestamp = bridgeTxDetails[transactionId].proofBlockTimestamp;\n relayer = bridgeTxDetails[transactionId].proofRelayer;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeRelays(bytes32 transactionId) public view returns (bool) {\n // has this transactionId been relayed?\n return bridgeRelayDetails[transactionId].relayer != address(0);\n }\n\n /// @inheritdoc IFastBridgeV2\n function getBridgeTransactionV2(bytes memory request) public pure returns (BridgeTransactionV2 memory) {\n return abi.decode(request, (BridgeTransactionV2));\n }\n\n /// @notice Pulls a requested token from the user to this contract.\n function _pullToken(address token, uint256 amount) internal returns (uint256 amountPulled) {\n if (token == UniversalTokenLib.ETH_ADDRESS) {\n // For ETH we just need to check that the supplied msg.value is correct\n if (amount != msg.value) revert MsgValueIncorrect();\n amountPulled = msg.value;\n } else {\n token.assertIsContract();\n // Record token balance before transfer\n amountPulled = IERC20(token).balanceOf(address(this));\n // Token needs to be pulled only if msg.value is zero\n // This way user can specify WETH as the origin asset\n IERC20(token).safeTransferFrom(msg.sender, address(this), amount);\n // Use the difference between the recorded balance and the current balance as the amountPulled\n amountPulled = IERC20(token).balanceOf(address(this)) - amountPulled;\n }\n }\n\n /// @notice Calls the Recipient's hook function with the specified callParams and performs\n /// all the necessary checks for the returned value.\n function _checkedCallRecipient(\n address recipient,\n address token,\n uint256 amount,\n bytes memory callParams\n )\n internal\n {\n bytes memory hookData =\n abi.encodeCall(IFastBridgeRecipient.fastBridgeTransferReceived, (token, amount, callParams));\n // This will bubble any revert messages from the hook function\n bytes memory returnData = Address.functionCallWithValue({target: recipient, data: hookData, value: msg.value});\n // Explicit revert if no return data at all\n if (returnData.length == 0) revert RecipientNoReturnValue();\n // Check that exactly a single return value was returned\n if (returnData.length != 32) revert RecipientIncorrectReturnValue();\n // Return value should be abi-encoded hook function selector\n if (bytes32(returnData) != bytes32(IFastBridgeRecipient.fastBridgeTransferReceived.selector)) {\n revert RecipientIncorrectReturnValue();\n }\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint40(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint40).max but\n /// proof.timestamp \u003c type(uint40).max via unchecked statement\n /// @param proofBlockTimestamp The bridge proof block timestamp\n /// @return delta Time delta since proof submitted\n function _timeSince(uint40 proofBlockTimestamp) internal view returns (uint256 delta) {\n unchecked {\n delta = uint40(block.timestamp) - proofBlockTimestamp;\n }\n }\n\n /// @notice Performs all the necessary checks for a bridge to happen.\n /// @dev There's no good way to refactor this function to reduce cyclomatic complexity due to\n /// the number of checks that need to be performed, so we skip the code-complexity rule here.\n // solhint-disable-next-line code-complexity\n function _validateBridgeParams(\n BridgeParams memory params,\n BridgeParamsV2 memory paramsV2,\n int256 exclusivityEndTime\n )\n internal\n view\n {\n // Check V1 (legacy) params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.sender == address(0) || params.to == address(0)) revert ZeroAddress();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n // Check V2 params\n if (paramsV2.callParams.length \u003e MAX_CALL_PARAMS_LENGTH) revert CallParamsLengthAboveMax();\n if (paramsV2.callValue != 0 \u0026\u0026 params.destToken == UniversalTokenLib.ETH_ADDRESS) {\n revert NativeTokenCallValueNotSupported();\n }\n // exclusivityEndTime must be in range (0 .. params.deadline]\n if (exclusivityEndTime \u003c= 0 || exclusivityEndTime \u003e int256(params.deadline)) {\n revert ExclusivityParamsIncorrect();\n }\n }\n\n /// @notice Performs all the necessary checks for a relay to happen.\n function _validateRelayParams(\n BridgeTransactionV2 memory transaction,\n bytes32 transactionId,\n address relayer\n )\n internal\n view\n {\n if (relayer == address(0)) revert ZeroAddress();\n // Check if the transaction has already been relayed\n if (bridgeRelays(transactionId)) revert TransactionRelayed();\n if (transaction.destChainId != uint32(block.chainid)) revert ChainIncorrect();\n // Check the deadline for relay to happen\n if (block.timestamp \u003e transaction.deadline) revert DeadlineExceeded();\n // Check the exclusivity period, if it is still ongoing\n // forgefmt: disable-next-item\n if (\n transaction.exclusivityRelayer != address(0) \u0026\u0026\n transaction.exclusivityRelayer != relayer \u0026\u0026\n block.timestamp \u003c= transaction.exclusivityEndTime\n ) {\n revert ExclusivityPeriodNotPassed();\n }\n }\n}\n","language":"Solidity","languageVersion":"0.8.24","compilerVersion":"0.8.24","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"","srcMapRuntime":"","abiDefinition":[{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Transfer","type":"event"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"}],"userDoc":{"kind":"user","methods":{},"version":1},"developerDoc":{"details":"Interface of the ERC20 standard as defined in the EIP.","events":{"Approval(address,address,uint256)":{"details":"Emitted when the allowance of a `spender` for an `owner` is set by a call to {approve}. `value` is the new allowance."},"Transfer(address,address,uint256)":{"details":"Emitted when `value` tokens are moved from one account (`from`) to another (`to`). Note that `value` may be zero."}},"kind":"dev","methods":{"allowance(address,address)":{"details":"Returns the remaining number of tokens that `spender` will be allowed to spend on behalf of `owner` through {transferFrom}. This is zero by default. This value changes when {approve} or {transferFrom} are called."},"approve(address,uint256)":{"details":"Sets a `value` amount of tokens as the allowance of `spender` over the caller's tokens. Returns a boolean value indicating whether the operation succeeded. IMPORTANT: Beware that changing an allowance with this method brings the risk that someone may use both the old and the new allowance by unfortunate transaction ordering. One possible solution to mitigate this race condition is to first reduce the spender's allowance to 0 and set the desired value afterwards: https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 Emits an {Approval} event."},"balanceOf(address)":{"details":"Returns the value of tokens owned by `account`."},"totalSupply()":{"details":"Returns the value of tokens in existence."},"transfer(address,uint256)":{"details":"Moves a `value` amount of tokens from the caller's account to `to`. Returns a boolean value indicating whether the operation succeeded. Emits a {Transfer} event."},"transferFrom(address,address,uint256)":{"details":"Moves a `value` amount of tokens from `from` to `to` using the allowance mechanism. `value` is then deducted from the caller's allowance. Returns a boolean value indicating whether the operation succeeded. Emits a {Transfer} event."}},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"Approval\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"Transfer\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"}],\"name\":\"allowance\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"approve\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"balanceOf\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"totalSupply\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"transfer\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"transferFrom\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"details\":\"Interface of the ERC20 standard as defined in the EIP.\",\"events\":{\"Approval(address,address,uint256)\":{\"details\":\"Emitted when the allowance of a `spender` for an `owner` is set by a call to {approve}. `value` is the new allowance.\"},\"Transfer(address,address,uint256)\":{\"details\":\"Emitted when `value` tokens are moved from one account (`from`) to another (`to`). Note that `value` may be zero.\"}},\"kind\":\"dev\",\"methods\":{\"allowance(address,address)\":{\"details\":\"Returns the remaining number of tokens that `spender` will be allowed to spend on behalf of `owner` through {transferFrom}. This is zero by default. This value changes when {approve} or {transferFrom} are called.\"},\"approve(address,uint256)\":{\"details\":\"Sets a `value` amount of tokens as the allowance of `spender` over the caller's tokens. Returns a boolean value indicating whether the operation succeeded. IMPORTANT: Beware that changing an allowance with this method brings the risk that someone may use both the old and the new allowance by unfortunate transaction ordering. One possible solution to mitigate this race condition is to first reduce the spender's allowance to 0 and set the desired value afterwards: https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 Emits an {Approval} event.\"},\"balanceOf(address)\":{\"details\":\"Returns the value of tokens owned by `account`.\"},\"totalSupply()\":{\"details\":\"Returns the value of tokens in existence.\"},\"transfer(address,uint256)\":{\"details\":\"Moves a `value` amount of tokens from the caller's account to `to`. Returns a boolean value indicating whether the operation succeeded. Emits a {Transfer} event.\"},\"transferFrom(address,address,uint256)\":{\"details\":\"Moves a `value` amount of tokens from `from` to `to` using the allowance mechanism. `value` is then deducted from the caller's allowance. Returns a boolean value indicating whether the operation succeeded. Emits a {Transfer} event.\"}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeV2.sol\":\"IERC20\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeV2.sol\":{\"keccak256\":\"0x7cd0f885e80e2bdaa638bc32ae7af7d2e248f99ce4b354c217d0f0f7d7302e0a\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://7ccf28df0bd7b4606986585acd8622ed9b4e81379690061bb66088f0a2270af1\",\"dweb:/ipfs/QmTf7HNdHZkK6vmx8ZgewycQEb72oLD9nPwBpsM5reMstQ\"]}},\"version\":1}"},"hashes":{"allowance(address,address)":"dd62ed3e","approve(address,uint256)":"095ea7b3","balanceOf(address)":"70a08231","totalSupply()":"18160ddd","transfer(address,uint256)":"a9059cbb","transferFrom(address,address,uint256)":"23b872dd"}},"solidity/FastBridgeV2.sol:IERC20Permit":{"code":"0x","runtime-code":"0x","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.24 ^0.8.0 ^0.8.20;\n\n// contracts/interfaces/IAdmin.sol\n\ninterface IAdmin {\n // ============ Events ============\n\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n event ChainGasAmountUpdated(uint256 oldChainGasAmount, uint256 newChainGasAmount);\n\n // ============ Methods ============\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n\n function setChainGasAmount(uint256 newChainGasAmount) external;\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IFastBridgeRecipient.sol\n\ninterface IFastBridgeRecipient {\n function fastBridgeTransferReceived(\n address token,\n uint256 amount,\n bytes memory callParams\n )\n external\n payable\n returns (bytes4);\n}\n\n// contracts/interfaces/IFastBridgeV2Errors.sol\n\ninterface IFastBridgeV2Errors {\n error AmountIncorrect();\n error CallParamsLengthAboveMax();\n error ChainIncorrect();\n error ExclusivityParamsIncorrect();\n error MsgValueIncorrect();\n error NativeTokenCallValueNotSupported();\n error SenderIncorrect();\n error StatusIncorrect();\n error ZeroAddress();\n\n error RecipientIncorrectReturnValue();\n error RecipientNoReturnValue();\n\n error DeadlineExceeded();\n error DeadlineNotExceeded();\n error DeadlineTooShort();\n error DisputePeriodNotPassed();\n error DisputePeriodPassed();\n error ExclusivityPeriodNotPassed();\n\n error TransactionRelayed();\n}\n\n// contracts/libs/Errors.sol\n\nerror DeadlineExceeded();\nerror DeadlineNotExceeded();\nerror DeadlineTooShort();\nerror InsufficientOutputAmount();\n\nerror MsgValueIncorrect();\nerror PoolNotFound();\nerror TokenAddressMismatch();\nerror TokenNotContract();\nerror TokenNotETH();\nerror TokensIdentical();\n\nerror ChainIncorrect();\nerror AmountIncorrect();\nerror ZeroAddress();\n\nerror DisputePeriodNotPassed();\nerror DisputePeriodPassed();\nerror SenderIncorrect();\nerror StatusIncorrect();\nerror TransactionIdIncorrect();\nerror TransactionRelayed();\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// contracts/interfaces/IFastBridgeV2.sol\n\ninterface IFastBridgeV2 is IFastBridge {\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n struct BridgeTxDetails {\n BridgeStatus status;\n uint40 proofBlockTimestamp;\n uint48 proofBlockNumber;\n address proofRelayer;\n }\n\n struct BridgeRelay {\n uint48 blockNumber;\n uint48 blockTimestamp;\n address relayer;\n }\n\n /// @notice New params introduced in the FastBridgeV2.\n /// We are passing fields from the older BridgeParams struct outside of this struct\n /// for backwards compatibility.\n /// Note: quoteRelayer and quoteExclusivitySeconds are either both zero (indicating no exclusivity)\n /// or both non-zero (indicating exclusivity for the given period).\n /// Note: callValue \u003e 0 can NOT be used with destToken = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE (ETH_ADDRESS)\n /// @param quoteRelayer Relayer that provided the quote for the transaction\n /// @param quoteExclusivitySeconds Period of time the quote relayer is guaranteed exclusivity after user's deposit\n /// @param quoteId Unique quote identifier used for tracking the quote\n /// @param callValue ETH value to send to the recipient (if any)\n /// @param callParams Parameters for the arbitrary call to the destination recipient (if any)\n struct BridgeParamsV2 {\n address quoteRelayer;\n int256 quoteExclusivitySeconds;\n bytes quoteId;\n uint256 callValue;\n bytes callParams;\n }\n\n /// @notice Updated bridge transaction struct to include parameters introduced in FastBridgeV2.\n /// Note: only `exclusivityRelayer` can fill such a transaction until `exclusivityEndTime`.\n /// TODO: consider changing the encoding scheme to prevent spending extra gas on decoding.\n struct BridgeTransactionV2 {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n uint256 callValue; // ETH value to send to the recipient (if any) - replaces V1's sendChainGas flag\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n address exclusivityRelayer;\n uint256 exclusivityEndTime;\n bytes callParams;\n }\n\n event BridgeQuoteDetails(bytes32 indexed transactionId, bytes quoteId);\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability\n /// to provide temporary exclusivity fill rights for the quote relayer.\n /// @param params The parameters required to bridge\n /// @param paramsV2 The parameters for exclusivity fill rights (optional, can be left empty)\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function relay(bytes memory request, address relayer) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param transactionId The transaction id associated with the encoded bridge transaction to prove\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital.\n /// @notice Can only send funds to the relayer address on the proof.\n /// @param request The encoded bridge transaction to claim on origin chain\n function claim(bytes memory request) external;\n /// @notice Checks if a transaction has been relayed\n /// @param transactionId The ID of the transaction to check\n /// @return True if the transaction has been relayed, false otherwise\n function bridgeRelays(bytes32 transactionId) external view returns (bool);\n\n /// @notice Returns the status of a bridge transaction\n /// @param transactionId The ID of the bridge transaction\n /// @return BridgeStatus Status of the bridge transaction\n function bridgeStatuses(bytes32 transactionId) external view returns (BridgeStatus);\n\n /// @notice Returns the timestamp and relayer of a bridge proof\n /// @param transactionId The ID of the bridge transaction\n /// @return timestamp The timestamp of the bridge proof\n /// @return relayer The relayer address of the bridge proof\n function bridgeProofs(bytes32 transactionId) external view returns (uint96 timestamp, address relayer);\n\n /// @notice Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\n /// @param request The bridge request to decode\n function getBridgeTransactionV2(bytes memory request) external view returns (BridgeTransactionV2 memory);\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// contracts/libs/UniversalToken.sol\n\nlibrary UniversalTokenLib {\n using SafeERC20 for IERC20;\n\n address internal constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Transfers tokens to the given account. Reverts if transfer is not successful.\n /// @dev This might trigger fallback, if ETH is transferred to the contract.\n /// Make sure this can not lead to reentrancy attacks.\n function universalTransfer(address token, address to, uint256 value) internal {\n // Don't do anything, if need to send tokens to this address\n if (to == address(this)) return;\n // Don't do anything, if trying to send zero value\n if (value == 0) return;\n if (token == ETH_ADDRESS) {\n /// @dev Note: this can potentially lead to executing code in `to`.\n // solhint-disable-next-line avoid-low-level-calls\n (bool success,) = to.call{value: value}(\"\");\n require(success, \"ETH transfer failed\");\n } else {\n IERC20(token).safeTransfer(to, value);\n }\n }\n\n /// @notice Issues an infinite allowance to the spender, if the current allowance is insufficient\n /// to spend the given amount.\n function universalApproveInfinity(address token, address spender, uint256 amountToSpend) internal {\n // ETH Chad doesn't require your approval\n if (token == ETH_ADDRESS) return;\n // No-op if allowance is already sufficient\n uint256 allowance = IERC20(token).allowance(address(this), spender);\n if (allowance \u003e= amountToSpend) return;\n // Otherwise, reset approval to 0 and set to max allowance\n if (allowance \u003e 0) IERC20(token).safeDecreaseAllowance(spender, allowance);\n IERC20(token).safeIncreaseAllowance(spender, type(uint256).max);\n }\n\n /// @notice Returns the balance of the given token (or native ETH) for the given account.\n function universalBalanceOf(address token, address account) internal view returns (uint256) {\n if (token == ETH_ADDRESS) {\n return account.balance;\n } else {\n return IERC20(token).balanceOf(account);\n }\n }\n\n /// @dev Checks that token is a contract and not ETH_ADDRESS.\n function assertIsContract(address token) internal view {\n // Check that ETH_ADDRESS was not used (in case this is a predeploy on any of the chains)\n if (token == UniversalTokenLib.ETH_ADDRESS) revert TokenNotContract();\n // Check that token is not an EOA\n if (token.code.length == 0) revert TokenNotContract();\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/Admin.sol\n\ncontract Admin is IAdmin, AccessControlEnumerable {\n using UniversalTokenLib for address;\n\n bytes32 public constant RELAYER_ROLE = keccak256(\"RELAYER_ROLE\");\n bytes32 public constant REFUNDER_ROLE = keccak256(\"REFUNDER_ROLE\");\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n uint256 public constant FEE_BPS = 1e6;\n uint256 public constant FEE_RATE_MAX = 0.01e6; // max 1% on origin amount\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Chain gas amount to forward as rebate if requested\n uint256 public chainGasAmount;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n }\n\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n require(newFeeRate \u003c= FEE_RATE_MAX, \"newFeeRate \u003e max\");\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n token.universalTransfer(recipient, feeAmount);\n emit FeesSwept(token, recipient, feeAmount);\n }\n\n function setChainGasAmount(uint256 newChainGasAmount) external onlyRole(GOVERNOR_ROLE) {\n uint256 oldChainGasAmount = chainGasAmount;\n chainGasAmount = newChainGasAmount;\n emit ChainGasAmountUpdated(oldChainGasAmount, newChainGasAmount);\n }\n}\n\n// contracts/FastBridgeV2.sol\n\n/// @notice FastBridgeV2 is a contract for bridging tokens across chains.\ncontract FastBridgeV2 is Admin, IFastBridgeV2, IFastBridgeV2Errors {\n using SafeERC20 for IERC20;\n using UniversalTokenLib for address;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Delay for a transaction after which it could be permisionlessly refunded\n uint256 public constant REFUND_DELAY = 7 days;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n /// @notice Maximum length of accepted callParams\n uint256 public constant MAX_CALL_PARAMS_LENGTH = 2 ** 16 - 1;\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeTxDetails) public bridgeTxDetails;\n /// @notice Relay details on destination chain\n mapping(bytes32 =\u003e BridgeRelay) public bridgeRelayDetails;\n /// @notice Unique bridge nonces tracked per originSender\n mapping(address =\u003e uint256) public senderNonces;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Replaced by senderNonces\n uint256 public immutable nonce = 0;\n /// @notice the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n bridge({\n params: params,\n paramsV2: BridgeParamsV2({\n quoteRelayer: address(0),\n quoteExclusivitySeconds: 0,\n quoteId: bytes(\"\"),\n callValue: 0,\n callParams: bytes(\"\")\n })\n });\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes memory request) external payable {\n relay({request: request, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes memory request, bytes32 destTxHash) external {\n prove({transactionId: keccak256(request), destTxHash: destTxHash, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridgeV2\n function claim(bytes memory request) external {\n claim({request: request, to: address(0)});\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003e DISPUTE_PERIOD) {\n revert DisputePeriodPassed();\n }\n\n // @dev relayer gets slashed effectively if dest relay has gone thru\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n bridgeTxDetails[transactionId].proofRelayer = address(0);\n bridgeTxDetails[transactionId].proofBlockTimestamp = 0;\n bridgeTxDetails[transactionId].proofBlockNumber = 0;\n\n emit BridgeProofDisputed(transactionId, msg.sender);\n }\n\n /// @inheritdoc IFastBridge\n function refund(bytes memory request) external {\n bytes32 transactionId = keccak256(request);\n\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n\n if (bridgeTxDetails[transactionId].status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n\n if (hasRole(REFUNDER_ROLE, msg.sender)) {\n // Refunder can refund if deadline has passed\n if (block.timestamp \u003c= transaction.deadline) revert DeadlineNotExceeded();\n } else {\n // Permissionless refund is allowed after REFUND_DELAY\n if (block.timestamp \u003c= transaction.deadline + REFUND_DELAY) revert DeadlineNotExceeded();\n }\n\n // if all checks passed, set to REFUNDED status\n bridgeTxDetails[transactionId].status = BridgeStatus.REFUNDED;\n\n // transfer origin collateral back to original sender\n address to = transaction.originSender;\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount + transaction.originFeeAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (bridgeTxDetails[transactionId].proofRelayer != relayer) revert SenderIncorrect();\n return _timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n /// @dev This method is added to achieve backwards compatibility with decoding requests into V1 structs:\n /// - `callValue` is partially reported as a zero/non-zero flag\n /// - `callParams` is ignored\n /// In order to process all kinds of requests use getBridgeTransactionV2 instead.\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory) {\n // Try decoding into V2 struct first. This will revert if V1 struct is passed\n try this.getBridgeTransactionV2(request) returns (BridgeTransactionV2 memory txV2) {\n // Note: we entirely ignore the callParams field, as it was not present in V1\n return BridgeTransaction({\n originChainId: txV2.originChainId,\n destChainId: txV2.destChainId,\n originSender: txV2.originSender,\n destRecipient: txV2.destRecipient,\n originToken: txV2.originToken,\n destToken: txV2.destToken,\n originAmount: txV2.originAmount,\n destAmount: txV2.destAmount,\n originFeeAmount: txV2.originFeeAmount,\n sendChainGas: txV2.callValue != 0,\n deadline: txV2.deadline,\n nonce: txV2.nonce\n });\n } catch {\n // Fallback to V1 struct\n return abi.decode(request, (BridgeTransaction));\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) public payable {\n int256 exclusivityEndTime = int256(block.timestamp) + paramsV2.quoteExclusivitySeconds;\n _validateBridgeParams(params, paramsV2, exclusivityEndTime);\n\n // transfer tokens to bridge contract\n /// @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _pullToken(params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n\n // set status to requested\n bytes memory request = abi.encode(\n BridgeTransactionV2({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n callValue: paramsV2.callValue,\n deadline: params.deadline,\n nonce: senderNonces[params.sender]++, // increment nonce on every bridge\n exclusivityRelayer: paramsV2.quoteRelayer,\n // We checked exclusivityEndTime to be in range (0 .. params.deadline] above, so can safely cast\n exclusivityEndTime: uint256(exclusivityEndTime),\n callParams: paramsV2.callParams\n })\n );\n bytes32 transactionId = keccak256(request);\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n\n emit BridgeRequested({\n transactionId: transactionId,\n sender: params.sender,\n request: request,\n destChainId: params.dstChainId,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n sendChainGas: paramsV2.callValue != 0\n });\n emit BridgeQuoteDetails(transactionId, paramsV2.quoteId);\n }\n\n /// @inheritdoc IFastBridgeV2\n function relay(bytes memory request, address relayer) public payable {\n bytes32 transactionId = keccak256(request);\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n _validateRelayParams(transaction, transactionId, relayer);\n // mark bridge transaction as relayed\n bridgeRelayDetails[transactionId] =\n BridgeRelay({blockNumber: uint48(block.number), blockTimestamp: uint48(block.timestamp), relayer: relayer});\n\n // transfer tokens to recipient on destination chain and do an arbitrary call if requested\n address to = transaction.destRecipient;\n address token = transaction.destToken;\n uint256 amount = transaction.destAmount;\n\n // All state changes have been done at this point, can proceed to the external calls.\n // This follows the checks-effects-interactions pattern to mitigate potential reentrancy attacks.\n if (token == UniversalTokenLib.ETH_ADDRESS) {\n // For ETH non-zero callValue is not allowed\n if (transaction.callValue != 0) revert NativeTokenCallValueNotSupported();\n // Check that the correct msg.value was sent\n if (msg.value != amount) revert MsgValueIncorrect();\n } else {\n // For ERC20s, we check that the correct msg.value was sent\n if (msg.value != transaction.callValue) revert MsgValueIncorrect();\n // We need to transfer the tokens from the Relayer to the recipient first before performing an\n // optional post-transfer arbitrary call.\n IERC20(token).safeTransferFrom(msg.sender, to, amount);\n }\n\n if (transaction.callParams.length != 0) {\n // Arbitrary call requested, perform it while supplying full msg.value to the recipient\n // Note: if token has a fee on transfers, the recipient will have received less than `amount`.\n // This is a very niche edge case and should be handled by the recipient contract.\n _checkedCallRecipient({recipient: to, token: token, amount: amount, callParams: transaction.callParams});\n } else if (msg.value != 0) {\n // No arbitrary call requested, but msg.value was sent. This is either a relay with ETH,\n // or a non-zero callValue request with an ERC20. In both cases, transfer the ETH to the recipient.\n Address.sendValue(payable(to), msg.value);\n }\n\n emit BridgeRelayed({\n transactionId: transactionId,\n relayer: relayer,\n to: to,\n originChainId: transaction.originChainId,\n originToken: transaction.originToken,\n destToken: transaction.destToken,\n originAmount: transaction.originAmount,\n destAmount: transaction.destAmount,\n chainGasAmount: transaction.callValue\n });\n }\n\n /// @inheritdoc IFastBridgeV2\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) public onlyRole(RELAYER_ROLE) {\n // update bridge tx status given proof provided\n if (bridgeTxDetails[transactionId].status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n bridgeTxDetails[transactionId].status = BridgeStatus.RELAYER_PROVED;\n bridgeTxDetails[transactionId].proofBlockTimestamp = uint40(block.timestamp);\n bridgeTxDetails[transactionId].proofBlockNumber = uint48(block.number);\n bridgeTxDetails[transactionId].proofRelayer = relayer;\n\n emit BridgeProofProvided(transactionId, relayer, destTxHash);\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes memory request, address to) public {\n bytes32 transactionId = keccak256(request);\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n\n // update bridge tx status if able to claim origin collateral\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n\n // if \"to\" is zero addr, permissionlessly send funds to proven relayer\n if (to == address(0)) {\n to = bridgeTxDetails[transactionId].proofRelayer;\n } else if (bridgeTxDetails[transactionId].proofRelayer != msg.sender) {\n revert SenderIncorrect();\n }\n\n if (_timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003c= DISPUTE_PERIOD) {\n revert DisputePeriodNotPassed();\n }\n\n bridgeTxDetails[transactionId].status = BridgeStatus.RELAYER_CLAIMED;\n\n // update protocol fees if origin fee amount exists\n if (transaction.originFeeAmount \u003e 0) protocolFees[transaction.originToken] += transaction.originFeeAmount;\n\n // transfer origin collateral less fee to specified address\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositClaimed(transactionId, bridgeTxDetails[transactionId].proofRelayer, to, token, amount);\n }\n\n function bridgeStatuses(bytes32 transactionId) public view returns (BridgeStatus status) {\n return bridgeTxDetails[transactionId].status;\n }\n\n function bridgeProofs(bytes32 transactionId) public view returns (uint96 timestamp, address relayer) {\n timestamp = bridgeTxDetails[transactionId].proofBlockTimestamp;\n relayer = bridgeTxDetails[transactionId].proofRelayer;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeRelays(bytes32 transactionId) public view returns (bool) {\n // has this transactionId been relayed?\n return bridgeRelayDetails[transactionId].relayer != address(0);\n }\n\n /// @inheritdoc IFastBridgeV2\n function getBridgeTransactionV2(bytes memory request) public pure returns (BridgeTransactionV2 memory) {\n return abi.decode(request, (BridgeTransactionV2));\n }\n\n /// @notice Pulls a requested token from the user to this contract.\n function _pullToken(address token, uint256 amount) internal returns (uint256 amountPulled) {\n if (token == UniversalTokenLib.ETH_ADDRESS) {\n // For ETH we just need to check that the supplied msg.value is correct\n if (amount != msg.value) revert MsgValueIncorrect();\n amountPulled = msg.value;\n } else {\n token.assertIsContract();\n // Record token balance before transfer\n amountPulled = IERC20(token).balanceOf(address(this));\n // Token needs to be pulled only if msg.value is zero\n // This way user can specify WETH as the origin asset\n IERC20(token).safeTransferFrom(msg.sender, address(this), amount);\n // Use the difference between the recorded balance and the current balance as the amountPulled\n amountPulled = IERC20(token).balanceOf(address(this)) - amountPulled;\n }\n }\n\n /// @notice Calls the Recipient's hook function with the specified callParams and performs\n /// all the necessary checks for the returned value.\n function _checkedCallRecipient(\n address recipient,\n address token,\n uint256 amount,\n bytes memory callParams\n )\n internal\n {\n bytes memory hookData =\n abi.encodeCall(IFastBridgeRecipient.fastBridgeTransferReceived, (token, amount, callParams));\n // This will bubble any revert messages from the hook function\n bytes memory returnData = Address.functionCallWithValue({target: recipient, data: hookData, value: msg.value});\n // Explicit revert if no return data at all\n if (returnData.length == 0) revert RecipientNoReturnValue();\n // Check that exactly a single return value was returned\n if (returnData.length != 32) revert RecipientIncorrectReturnValue();\n // Return value should be abi-encoded hook function selector\n if (bytes32(returnData) != bytes32(IFastBridgeRecipient.fastBridgeTransferReceived.selector)) {\n revert RecipientIncorrectReturnValue();\n }\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint40(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint40).max but\n /// proof.timestamp \u003c type(uint40).max via unchecked statement\n /// @param proofBlockTimestamp The bridge proof block timestamp\n /// @return delta Time delta since proof submitted\n function _timeSince(uint40 proofBlockTimestamp) internal view returns (uint256 delta) {\n unchecked {\n delta = uint40(block.timestamp) - proofBlockTimestamp;\n }\n }\n\n /// @notice Performs all the necessary checks for a bridge to happen.\n /// @dev There's no good way to refactor this function to reduce cyclomatic complexity due to\n /// the number of checks that need to be performed, so we skip the code-complexity rule here.\n // solhint-disable-next-line code-complexity\n function _validateBridgeParams(\n BridgeParams memory params,\n BridgeParamsV2 memory paramsV2,\n int256 exclusivityEndTime\n )\n internal\n view\n {\n // Check V1 (legacy) params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.sender == address(0) || params.to == address(0)) revert ZeroAddress();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n // Check V2 params\n if (paramsV2.callParams.length \u003e MAX_CALL_PARAMS_LENGTH) revert CallParamsLengthAboveMax();\n if (paramsV2.callValue != 0 \u0026\u0026 params.destToken == UniversalTokenLib.ETH_ADDRESS) {\n revert NativeTokenCallValueNotSupported();\n }\n // exclusivityEndTime must be in range (0 .. params.deadline]\n if (exclusivityEndTime \u003c= 0 || exclusivityEndTime \u003e int256(params.deadline)) {\n revert ExclusivityParamsIncorrect();\n }\n }\n\n /// @notice Performs all the necessary checks for a relay to happen.\n function _validateRelayParams(\n BridgeTransactionV2 memory transaction,\n bytes32 transactionId,\n address relayer\n )\n internal\n view\n {\n if (relayer == address(0)) revert ZeroAddress();\n // Check if the transaction has already been relayed\n if (bridgeRelays(transactionId)) revert TransactionRelayed();\n if (transaction.destChainId != uint32(block.chainid)) revert ChainIncorrect();\n // Check the deadline for relay to happen\n if (block.timestamp \u003e transaction.deadline) revert DeadlineExceeded();\n // Check the exclusivity period, if it is still ongoing\n // forgefmt: disable-next-item\n if (\n transaction.exclusivityRelayer != address(0) \u0026\u0026\n transaction.exclusivityRelayer != relayer \u0026\u0026\n block.timestamp \u003c= transaction.exclusivityEndTime\n ) {\n revert ExclusivityPeriodNotPassed();\n }\n }\n}\n","language":"Solidity","languageVersion":"0.8.24","compilerVersion":"0.8.24","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"","srcMapRuntime":"","abiDefinition":[{"inputs":[],"name":"DOMAIN_SEPARATOR","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"nonces","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"permit","outputs":[],"stateMutability":"nonpayable","type":"function"}],"userDoc":{"kind":"user","methods":{},"version":1},"developerDoc":{"details":"Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in https://eips.ethereum.org/EIPS/eip-2612[EIP-2612]. Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't need to send a transaction, and thus is not required to hold Ether at all. ==== Security Considerations There are two important considerations concerning the use of `permit`. The first is that a valid permit signature expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be considered as an intention to spend the allowance in any specific way. The second is that because permits have built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be generally recommended is: ```solidity function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public { try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {} doThing(..., value); } function doThing(..., uint256 value) public { token.safeTransferFrom(msg.sender, address(this), value); ... } ``` Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also {SafeERC20-safeTransferFrom}). Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so contracts should have entry points that don't rely on permit.","kind":"dev","methods":{"DOMAIN_SEPARATOR()":{"details":"Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}."},"nonces(address)":{"details":"Returns the current nonce for `owner`. This value must be included whenever a signature is generated for {permit}. Every successful call to {permit} increases ``owner``'s nonce by one. This prevents a signature from being used multiple times."},"permit(address,address,uint256,uint256,uint8,bytes32,bytes32)":{"details":"Sets `value` as the allowance of `spender` over ``owner``'s tokens, given ``owner``'s signed approval. IMPORTANT: The same issues {IERC20-approve} has related to transaction ordering also apply here. Emits an {Approval} event. Requirements: - `spender` cannot be the zero address. - `deadline` must be a timestamp in the future. - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner` over the EIP712-formatted function arguments. - the signature must use ``owner``'s current nonce (see {nonces}). For more information on the signature format, see the https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP section]. CAUTION: See Security Considerations above."}},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[],\"name\":\"DOMAIN_SEPARATOR\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"}],\"name\":\"nonces\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"},{\"internalType\":\"uint8\",\"name\":\"v\",\"type\":\"uint8\"},{\"internalType\":\"bytes32\",\"name\":\"r\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"s\",\"type\":\"bytes32\"}],\"name\":\"permit\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"details\":\"Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in https://eips.ethereum.org/EIPS/eip-2612[EIP-2612]. Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't need to send a transaction, and thus is not required to hold Ether at all. ==== Security Considerations There are two important considerations concerning the use of `permit`. The first is that a valid permit signature expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be considered as an intention to spend the allowance in any specific way. The second is that because permits have built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be generally recommended is: ```solidity function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public { try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {} doThing(..., value); } function doThing(..., uint256 value) public { token.safeTransferFrom(msg.sender, address(this), value); ... } ``` Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also {SafeERC20-safeTransferFrom}). Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so contracts should have entry points that don't rely on permit.\",\"kind\":\"dev\",\"methods\":{\"DOMAIN_SEPARATOR()\":{\"details\":\"Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\"},\"nonces(address)\":{\"details\":\"Returns the current nonce for `owner`. This value must be included whenever a signature is generated for {permit}. Every successful call to {permit} increases ``owner``'s nonce by one. This prevents a signature from being used multiple times.\"},\"permit(address,address,uint256,uint256,uint8,bytes32,bytes32)\":{\"details\":\"Sets `value` as the allowance of `spender` over ``owner``'s tokens, given ``owner``'s signed approval. IMPORTANT: The same issues {IERC20-approve} has related to transaction ordering also apply here. Emits an {Approval} event. Requirements: - `spender` cannot be the zero address. - `deadline` must be a timestamp in the future. - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner` over the EIP712-formatted function arguments. - the signature must use ``owner``'s current nonce (see {nonces}). For more information on the signature format, see the https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP section]. CAUTION: See Security Considerations above.\"}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeV2.sol\":\"IERC20Permit\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeV2.sol\":{\"keccak256\":\"0x7cd0f885e80e2bdaa638bc32ae7af7d2e248f99ce4b354c217d0f0f7d7302e0a\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://7ccf28df0bd7b4606986585acd8622ed9b4e81379690061bb66088f0a2270af1\",\"dweb:/ipfs/QmTf7HNdHZkK6vmx8ZgewycQEb72oLD9nPwBpsM5reMstQ\"]}},\"version\":1}"},"hashes":{"DOMAIN_SEPARATOR()":"3644e515","nonces(address)":"7ecebe00","permit(address,address,uint256,uint256,uint8,bytes32,bytes32)":"d505accf"}},"solidity/FastBridgeV2.sol:IFastBridge":{"code":"0x","runtime-code":"0x","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.24 ^0.8.0 ^0.8.20;\n\n// contracts/interfaces/IAdmin.sol\n\ninterface IAdmin {\n // ============ Events ============\n\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n event ChainGasAmountUpdated(uint256 oldChainGasAmount, uint256 newChainGasAmount);\n\n // ============ Methods ============\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n\n function setChainGasAmount(uint256 newChainGasAmount) external;\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IFastBridgeRecipient.sol\n\ninterface IFastBridgeRecipient {\n function fastBridgeTransferReceived(\n address token,\n uint256 amount,\n bytes memory callParams\n )\n external\n payable\n returns (bytes4);\n}\n\n// contracts/interfaces/IFastBridgeV2Errors.sol\n\ninterface IFastBridgeV2Errors {\n error AmountIncorrect();\n error CallParamsLengthAboveMax();\n error ChainIncorrect();\n error ExclusivityParamsIncorrect();\n error MsgValueIncorrect();\n error NativeTokenCallValueNotSupported();\n error SenderIncorrect();\n error StatusIncorrect();\n error ZeroAddress();\n\n error RecipientIncorrectReturnValue();\n error RecipientNoReturnValue();\n\n error DeadlineExceeded();\n error DeadlineNotExceeded();\n error DeadlineTooShort();\n error DisputePeriodNotPassed();\n error DisputePeriodPassed();\n error ExclusivityPeriodNotPassed();\n\n error TransactionRelayed();\n}\n\n// contracts/libs/Errors.sol\n\nerror DeadlineExceeded();\nerror DeadlineNotExceeded();\nerror DeadlineTooShort();\nerror InsufficientOutputAmount();\n\nerror MsgValueIncorrect();\nerror PoolNotFound();\nerror TokenAddressMismatch();\nerror TokenNotContract();\nerror TokenNotETH();\nerror TokensIdentical();\n\nerror ChainIncorrect();\nerror AmountIncorrect();\nerror ZeroAddress();\n\nerror DisputePeriodNotPassed();\nerror DisputePeriodPassed();\nerror SenderIncorrect();\nerror StatusIncorrect();\nerror TransactionIdIncorrect();\nerror TransactionRelayed();\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// contracts/interfaces/IFastBridgeV2.sol\n\ninterface IFastBridgeV2 is IFastBridge {\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n struct BridgeTxDetails {\n BridgeStatus status;\n uint40 proofBlockTimestamp;\n uint48 proofBlockNumber;\n address proofRelayer;\n }\n\n struct BridgeRelay {\n uint48 blockNumber;\n uint48 blockTimestamp;\n address relayer;\n }\n\n /// @notice New params introduced in the FastBridgeV2.\n /// We are passing fields from the older BridgeParams struct outside of this struct\n /// for backwards compatibility.\n /// Note: quoteRelayer and quoteExclusivitySeconds are either both zero (indicating no exclusivity)\n /// or both non-zero (indicating exclusivity for the given period).\n /// Note: callValue \u003e 0 can NOT be used with destToken = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE (ETH_ADDRESS)\n /// @param quoteRelayer Relayer that provided the quote for the transaction\n /// @param quoteExclusivitySeconds Period of time the quote relayer is guaranteed exclusivity after user's deposit\n /// @param quoteId Unique quote identifier used for tracking the quote\n /// @param callValue ETH value to send to the recipient (if any)\n /// @param callParams Parameters for the arbitrary call to the destination recipient (if any)\n struct BridgeParamsV2 {\n address quoteRelayer;\n int256 quoteExclusivitySeconds;\n bytes quoteId;\n uint256 callValue;\n bytes callParams;\n }\n\n /// @notice Updated bridge transaction struct to include parameters introduced in FastBridgeV2.\n /// Note: only `exclusivityRelayer` can fill such a transaction until `exclusivityEndTime`.\n /// TODO: consider changing the encoding scheme to prevent spending extra gas on decoding.\n struct BridgeTransactionV2 {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n uint256 callValue; // ETH value to send to the recipient (if any) - replaces V1's sendChainGas flag\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n address exclusivityRelayer;\n uint256 exclusivityEndTime;\n bytes callParams;\n }\n\n event BridgeQuoteDetails(bytes32 indexed transactionId, bytes quoteId);\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability\n /// to provide temporary exclusivity fill rights for the quote relayer.\n /// @param params The parameters required to bridge\n /// @param paramsV2 The parameters for exclusivity fill rights (optional, can be left empty)\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function relay(bytes memory request, address relayer) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param transactionId The transaction id associated with the encoded bridge transaction to prove\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital.\n /// @notice Can only send funds to the relayer address on the proof.\n /// @param request The encoded bridge transaction to claim on origin chain\n function claim(bytes memory request) external;\n /// @notice Checks if a transaction has been relayed\n /// @param transactionId The ID of the transaction to check\n /// @return True if the transaction has been relayed, false otherwise\n function bridgeRelays(bytes32 transactionId) external view returns (bool);\n\n /// @notice Returns the status of a bridge transaction\n /// @param transactionId The ID of the bridge transaction\n /// @return BridgeStatus Status of the bridge transaction\n function bridgeStatuses(bytes32 transactionId) external view returns (BridgeStatus);\n\n /// @notice Returns the timestamp and relayer of a bridge proof\n /// @param transactionId The ID of the bridge transaction\n /// @return timestamp The timestamp of the bridge proof\n /// @return relayer The relayer address of the bridge proof\n function bridgeProofs(bytes32 transactionId) external view returns (uint96 timestamp, address relayer);\n\n /// @notice Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\n /// @param request The bridge request to decode\n function getBridgeTransactionV2(bytes memory request) external view returns (BridgeTransactionV2 memory);\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// contracts/libs/UniversalToken.sol\n\nlibrary UniversalTokenLib {\n using SafeERC20 for IERC20;\n\n address internal constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Transfers tokens to the given account. Reverts if transfer is not successful.\n /// @dev This might trigger fallback, if ETH is transferred to the contract.\n /// Make sure this can not lead to reentrancy attacks.\n function universalTransfer(address token, address to, uint256 value) internal {\n // Don't do anything, if need to send tokens to this address\n if (to == address(this)) return;\n // Don't do anything, if trying to send zero value\n if (value == 0) return;\n if (token == ETH_ADDRESS) {\n /// @dev Note: this can potentially lead to executing code in `to`.\n // solhint-disable-next-line avoid-low-level-calls\n (bool success,) = to.call{value: value}(\"\");\n require(success, \"ETH transfer failed\");\n } else {\n IERC20(token).safeTransfer(to, value);\n }\n }\n\n /// @notice Issues an infinite allowance to the spender, if the current allowance is insufficient\n /// to spend the given amount.\n function universalApproveInfinity(address token, address spender, uint256 amountToSpend) internal {\n // ETH Chad doesn't require your approval\n if (token == ETH_ADDRESS) return;\n // No-op if allowance is already sufficient\n uint256 allowance = IERC20(token).allowance(address(this), spender);\n if (allowance \u003e= amountToSpend) return;\n // Otherwise, reset approval to 0 and set to max allowance\n if (allowance \u003e 0) IERC20(token).safeDecreaseAllowance(spender, allowance);\n IERC20(token).safeIncreaseAllowance(spender, type(uint256).max);\n }\n\n /// @notice Returns the balance of the given token (or native ETH) for the given account.\n function universalBalanceOf(address token, address account) internal view returns (uint256) {\n if (token == ETH_ADDRESS) {\n return account.balance;\n } else {\n return IERC20(token).balanceOf(account);\n }\n }\n\n /// @dev Checks that token is a contract and not ETH_ADDRESS.\n function assertIsContract(address token) internal view {\n // Check that ETH_ADDRESS was not used (in case this is a predeploy on any of the chains)\n if (token == UniversalTokenLib.ETH_ADDRESS) revert TokenNotContract();\n // Check that token is not an EOA\n if (token.code.length == 0) revert TokenNotContract();\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/Admin.sol\n\ncontract Admin is IAdmin, AccessControlEnumerable {\n using UniversalTokenLib for address;\n\n bytes32 public constant RELAYER_ROLE = keccak256(\"RELAYER_ROLE\");\n bytes32 public constant REFUNDER_ROLE = keccak256(\"REFUNDER_ROLE\");\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n uint256 public constant FEE_BPS = 1e6;\n uint256 public constant FEE_RATE_MAX = 0.01e6; // max 1% on origin amount\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Chain gas amount to forward as rebate if requested\n uint256 public chainGasAmount;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n }\n\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n require(newFeeRate \u003c= FEE_RATE_MAX, \"newFeeRate \u003e max\");\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n token.universalTransfer(recipient, feeAmount);\n emit FeesSwept(token, recipient, feeAmount);\n }\n\n function setChainGasAmount(uint256 newChainGasAmount) external onlyRole(GOVERNOR_ROLE) {\n uint256 oldChainGasAmount = chainGasAmount;\n chainGasAmount = newChainGasAmount;\n emit ChainGasAmountUpdated(oldChainGasAmount, newChainGasAmount);\n }\n}\n\n// contracts/FastBridgeV2.sol\n\n/// @notice FastBridgeV2 is a contract for bridging tokens across chains.\ncontract FastBridgeV2 is Admin, IFastBridgeV2, IFastBridgeV2Errors {\n using SafeERC20 for IERC20;\n using UniversalTokenLib for address;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Delay for a transaction after which it could be permisionlessly refunded\n uint256 public constant REFUND_DELAY = 7 days;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n /// @notice Maximum length of accepted callParams\n uint256 public constant MAX_CALL_PARAMS_LENGTH = 2 ** 16 - 1;\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeTxDetails) public bridgeTxDetails;\n /// @notice Relay details on destination chain\n mapping(bytes32 =\u003e BridgeRelay) public bridgeRelayDetails;\n /// @notice Unique bridge nonces tracked per originSender\n mapping(address =\u003e uint256) public senderNonces;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Replaced by senderNonces\n uint256 public immutable nonce = 0;\n /// @notice the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n bridge({\n params: params,\n paramsV2: BridgeParamsV2({\n quoteRelayer: address(0),\n quoteExclusivitySeconds: 0,\n quoteId: bytes(\"\"),\n callValue: 0,\n callParams: bytes(\"\")\n })\n });\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes memory request) external payable {\n relay({request: request, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes memory request, bytes32 destTxHash) external {\n prove({transactionId: keccak256(request), destTxHash: destTxHash, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridgeV2\n function claim(bytes memory request) external {\n claim({request: request, to: address(0)});\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003e DISPUTE_PERIOD) {\n revert DisputePeriodPassed();\n }\n\n // @dev relayer gets slashed effectively if dest relay has gone thru\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n bridgeTxDetails[transactionId].proofRelayer = address(0);\n bridgeTxDetails[transactionId].proofBlockTimestamp = 0;\n bridgeTxDetails[transactionId].proofBlockNumber = 0;\n\n emit BridgeProofDisputed(transactionId, msg.sender);\n }\n\n /// @inheritdoc IFastBridge\n function refund(bytes memory request) external {\n bytes32 transactionId = keccak256(request);\n\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n\n if (bridgeTxDetails[transactionId].status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n\n if (hasRole(REFUNDER_ROLE, msg.sender)) {\n // Refunder can refund if deadline has passed\n if (block.timestamp \u003c= transaction.deadline) revert DeadlineNotExceeded();\n } else {\n // Permissionless refund is allowed after REFUND_DELAY\n if (block.timestamp \u003c= transaction.deadline + REFUND_DELAY) revert DeadlineNotExceeded();\n }\n\n // if all checks passed, set to REFUNDED status\n bridgeTxDetails[transactionId].status = BridgeStatus.REFUNDED;\n\n // transfer origin collateral back to original sender\n address to = transaction.originSender;\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount + transaction.originFeeAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (bridgeTxDetails[transactionId].proofRelayer != relayer) revert SenderIncorrect();\n return _timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n /// @dev This method is added to achieve backwards compatibility with decoding requests into V1 structs:\n /// - `callValue` is partially reported as a zero/non-zero flag\n /// - `callParams` is ignored\n /// In order to process all kinds of requests use getBridgeTransactionV2 instead.\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory) {\n // Try decoding into V2 struct first. This will revert if V1 struct is passed\n try this.getBridgeTransactionV2(request) returns (BridgeTransactionV2 memory txV2) {\n // Note: we entirely ignore the callParams field, as it was not present in V1\n return BridgeTransaction({\n originChainId: txV2.originChainId,\n destChainId: txV2.destChainId,\n originSender: txV2.originSender,\n destRecipient: txV2.destRecipient,\n originToken: txV2.originToken,\n destToken: txV2.destToken,\n originAmount: txV2.originAmount,\n destAmount: txV2.destAmount,\n originFeeAmount: txV2.originFeeAmount,\n sendChainGas: txV2.callValue != 0,\n deadline: txV2.deadline,\n nonce: txV2.nonce\n });\n } catch {\n // Fallback to V1 struct\n return abi.decode(request, (BridgeTransaction));\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) public payable {\n int256 exclusivityEndTime = int256(block.timestamp) + paramsV2.quoteExclusivitySeconds;\n _validateBridgeParams(params, paramsV2, exclusivityEndTime);\n\n // transfer tokens to bridge contract\n /// @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _pullToken(params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n\n // set status to requested\n bytes memory request = abi.encode(\n BridgeTransactionV2({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n callValue: paramsV2.callValue,\n deadline: params.deadline,\n nonce: senderNonces[params.sender]++, // increment nonce on every bridge\n exclusivityRelayer: paramsV2.quoteRelayer,\n // We checked exclusivityEndTime to be in range (0 .. params.deadline] above, so can safely cast\n exclusivityEndTime: uint256(exclusivityEndTime),\n callParams: paramsV2.callParams\n })\n );\n bytes32 transactionId = keccak256(request);\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n\n emit BridgeRequested({\n transactionId: transactionId,\n sender: params.sender,\n request: request,\n destChainId: params.dstChainId,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n sendChainGas: paramsV2.callValue != 0\n });\n emit BridgeQuoteDetails(transactionId, paramsV2.quoteId);\n }\n\n /// @inheritdoc IFastBridgeV2\n function relay(bytes memory request, address relayer) public payable {\n bytes32 transactionId = keccak256(request);\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n _validateRelayParams(transaction, transactionId, relayer);\n // mark bridge transaction as relayed\n bridgeRelayDetails[transactionId] =\n BridgeRelay({blockNumber: uint48(block.number), blockTimestamp: uint48(block.timestamp), relayer: relayer});\n\n // transfer tokens to recipient on destination chain and do an arbitrary call if requested\n address to = transaction.destRecipient;\n address token = transaction.destToken;\n uint256 amount = transaction.destAmount;\n\n // All state changes have been done at this point, can proceed to the external calls.\n // This follows the checks-effects-interactions pattern to mitigate potential reentrancy attacks.\n if (token == UniversalTokenLib.ETH_ADDRESS) {\n // For ETH non-zero callValue is not allowed\n if (transaction.callValue != 0) revert NativeTokenCallValueNotSupported();\n // Check that the correct msg.value was sent\n if (msg.value != amount) revert MsgValueIncorrect();\n } else {\n // For ERC20s, we check that the correct msg.value was sent\n if (msg.value != transaction.callValue) revert MsgValueIncorrect();\n // We need to transfer the tokens from the Relayer to the recipient first before performing an\n // optional post-transfer arbitrary call.\n IERC20(token).safeTransferFrom(msg.sender, to, amount);\n }\n\n if (transaction.callParams.length != 0) {\n // Arbitrary call requested, perform it while supplying full msg.value to the recipient\n // Note: if token has a fee on transfers, the recipient will have received less than `amount`.\n // This is a very niche edge case and should be handled by the recipient contract.\n _checkedCallRecipient({recipient: to, token: token, amount: amount, callParams: transaction.callParams});\n } else if (msg.value != 0) {\n // No arbitrary call requested, but msg.value was sent. This is either a relay with ETH,\n // or a non-zero callValue request with an ERC20. In both cases, transfer the ETH to the recipient.\n Address.sendValue(payable(to), msg.value);\n }\n\n emit BridgeRelayed({\n transactionId: transactionId,\n relayer: relayer,\n to: to,\n originChainId: transaction.originChainId,\n originToken: transaction.originToken,\n destToken: transaction.destToken,\n originAmount: transaction.originAmount,\n destAmount: transaction.destAmount,\n chainGasAmount: transaction.callValue\n });\n }\n\n /// @inheritdoc IFastBridgeV2\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) public onlyRole(RELAYER_ROLE) {\n // update bridge tx status given proof provided\n if (bridgeTxDetails[transactionId].status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n bridgeTxDetails[transactionId].status = BridgeStatus.RELAYER_PROVED;\n bridgeTxDetails[transactionId].proofBlockTimestamp = uint40(block.timestamp);\n bridgeTxDetails[transactionId].proofBlockNumber = uint48(block.number);\n bridgeTxDetails[transactionId].proofRelayer = relayer;\n\n emit BridgeProofProvided(transactionId, relayer, destTxHash);\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes memory request, address to) public {\n bytes32 transactionId = keccak256(request);\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n\n // update bridge tx status if able to claim origin collateral\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n\n // if \"to\" is zero addr, permissionlessly send funds to proven relayer\n if (to == address(0)) {\n to = bridgeTxDetails[transactionId].proofRelayer;\n } else if (bridgeTxDetails[transactionId].proofRelayer != msg.sender) {\n revert SenderIncorrect();\n }\n\n if (_timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003c= DISPUTE_PERIOD) {\n revert DisputePeriodNotPassed();\n }\n\n bridgeTxDetails[transactionId].status = BridgeStatus.RELAYER_CLAIMED;\n\n // update protocol fees if origin fee amount exists\n if (transaction.originFeeAmount \u003e 0) protocolFees[transaction.originToken] += transaction.originFeeAmount;\n\n // transfer origin collateral less fee to specified address\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositClaimed(transactionId, bridgeTxDetails[transactionId].proofRelayer, to, token, amount);\n }\n\n function bridgeStatuses(bytes32 transactionId) public view returns (BridgeStatus status) {\n return bridgeTxDetails[transactionId].status;\n }\n\n function bridgeProofs(bytes32 transactionId) public view returns (uint96 timestamp, address relayer) {\n timestamp = bridgeTxDetails[transactionId].proofBlockTimestamp;\n relayer = bridgeTxDetails[transactionId].proofRelayer;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeRelays(bytes32 transactionId) public view returns (bool) {\n // has this transactionId been relayed?\n return bridgeRelayDetails[transactionId].relayer != address(0);\n }\n\n /// @inheritdoc IFastBridgeV2\n function getBridgeTransactionV2(bytes memory request) public pure returns (BridgeTransactionV2 memory) {\n return abi.decode(request, (BridgeTransactionV2));\n }\n\n /// @notice Pulls a requested token from the user to this contract.\n function _pullToken(address token, uint256 amount) internal returns (uint256 amountPulled) {\n if (token == UniversalTokenLib.ETH_ADDRESS) {\n // For ETH we just need to check that the supplied msg.value is correct\n if (amount != msg.value) revert MsgValueIncorrect();\n amountPulled = msg.value;\n } else {\n token.assertIsContract();\n // Record token balance before transfer\n amountPulled = IERC20(token).balanceOf(address(this));\n // Token needs to be pulled only if msg.value is zero\n // This way user can specify WETH as the origin asset\n IERC20(token).safeTransferFrom(msg.sender, address(this), amount);\n // Use the difference between the recorded balance and the current balance as the amountPulled\n amountPulled = IERC20(token).balanceOf(address(this)) - amountPulled;\n }\n }\n\n /// @notice Calls the Recipient's hook function with the specified callParams and performs\n /// all the necessary checks for the returned value.\n function _checkedCallRecipient(\n address recipient,\n address token,\n uint256 amount,\n bytes memory callParams\n )\n internal\n {\n bytes memory hookData =\n abi.encodeCall(IFastBridgeRecipient.fastBridgeTransferReceived, (token, amount, callParams));\n // This will bubble any revert messages from the hook function\n bytes memory returnData = Address.functionCallWithValue({target: recipient, data: hookData, value: msg.value});\n // Explicit revert if no return data at all\n if (returnData.length == 0) revert RecipientNoReturnValue();\n // Check that exactly a single return value was returned\n if (returnData.length != 32) revert RecipientIncorrectReturnValue();\n // Return value should be abi-encoded hook function selector\n if (bytes32(returnData) != bytes32(IFastBridgeRecipient.fastBridgeTransferReceived.selector)) {\n revert RecipientIncorrectReturnValue();\n }\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint40(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint40).max but\n /// proof.timestamp \u003c type(uint40).max via unchecked statement\n /// @param proofBlockTimestamp The bridge proof block timestamp\n /// @return delta Time delta since proof submitted\n function _timeSince(uint40 proofBlockTimestamp) internal view returns (uint256 delta) {\n unchecked {\n delta = uint40(block.timestamp) - proofBlockTimestamp;\n }\n }\n\n /// @notice Performs all the necessary checks for a bridge to happen.\n /// @dev There's no good way to refactor this function to reduce cyclomatic complexity due to\n /// the number of checks that need to be performed, so we skip the code-complexity rule here.\n // solhint-disable-next-line code-complexity\n function _validateBridgeParams(\n BridgeParams memory params,\n BridgeParamsV2 memory paramsV2,\n int256 exclusivityEndTime\n )\n internal\n view\n {\n // Check V1 (legacy) params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.sender == address(0) || params.to == address(0)) revert ZeroAddress();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n // Check V2 params\n if (paramsV2.callParams.length \u003e MAX_CALL_PARAMS_LENGTH) revert CallParamsLengthAboveMax();\n if (paramsV2.callValue != 0 \u0026\u0026 params.destToken == UniversalTokenLib.ETH_ADDRESS) {\n revert NativeTokenCallValueNotSupported();\n }\n // exclusivityEndTime must be in range (0 .. params.deadline]\n if (exclusivityEndTime \u003c= 0 || exclusivityEndTime \u003e int256(params.deadline)) {\n revert ExclusivityParamsIncorrect();\n }\n }\n\n /// @notice Performs all the necessary checks for a relay to happen.\n function _validateRelayParams(\n BridgeTransactionV2 memory transaction,\n bytes32 transactionId,\n address relayer\n )\n internal\n view\n {\n if (relayer == address(0)) revert ZeroAddress();\n // Check if the transaction has already been relayed\n if (bridgeRelays(transactionId)) revert TransactionRelayed();\n if (transaction.destChainId != uint32(block.chainid)) revert ChainIncorrect();\n // Check the deadline for relay to happen\n if (block.timestamp \u003e transaction.deadline) revert DeadlineExceeded();\n // Check the exclusivity period, if it is still ongoing\n // forgefmt: disable-next-item\n if (\n transaction.exclusivityRelayer != address(0) \u0026\u0026\n transaction.exclusivityRelayer != relayer \u0026\u0026\n block.timestamp \u003c= transaction.exclusivityEndTime\n ) {\n revert ExclusivityPeriodNotPassed();\n }\n }\n}\n","language":"Solidity","languageVersion":"0.8.24","compilerVersion":"0.8.24","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"","srcMapRuntime":"","abiDefinition":[{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"relayer","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"BridgeDepositClaimed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"BridgeDepositRefunded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"relayer","type":"address"}],"name":"BridgeProofDisputed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"relayer","type":"address"},{"indexed":false,"internalType":"bytes32","name":"transactionHash","type":"bytes32"}],"name":"BridgeProofProvided","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"relayer","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint32","name":"originChainId","type":"uint32"},{"indexed":false,"internalType":"address","name":"originToken","type":"address"},{"indexed":false,"internalType":"address","name":"destToken","type":"address"},{"indexed":false,"internalType":"uint256","name":"originAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"destAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"chainGasAmount","type":"uint256"}],"name":"BridgeRelayed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"bytes","name":"request","type":"bytes"},{"indexed":false,"internalType":"uint32","name":"destChainId","type":"uint32"},{"indexed":false,"internalType":"address","name":"originToken","type":"address"},{"indexed":false,"internalType":"address","name":"destToken","type":"address"},{"indexed":false,"internalType":"uint256","name":"originAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"destAmount","type":"uint256"},{"indexed":false,"internalType":"bool","name":"sendChainGas","type":"bool"}],"name":"BridgeRequested","type":"event"},{"inputs":[{"components":[{"internalType":"uint32","name":"dstChainId","type":"uint32"},{"internalType":"address","name":"sender","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"address","name":"originToken","type":"address"},{"internalType":"address","name":"destToken","type":"address"},{"internalType":"uint256","name":"originAmount","type":"uint256"},{"internalType":"uint256","name":"destAmount","type":"uint256"},{"internalType":"bool","name":"sendChainGas","type":"bool"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"internalType":"struct IFastBridge.BridgeParams","name":"params","type":"tuple"}],"name":"bridge","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"internalType":"address","name":"relayer","type":"address"}],"name":"canClaim","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"},{"internalType":"address","name":"to","type":"address"}],"name":"claim","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"transactionId","type":"bytes32"}],"name":"dispute","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"}],"name":"getBridgeTransaction","outputs":[{"components":[{"internalType":"uint32","name":"originChainId","type":"uint32"},{"internalType":"uint32","name":"destChainId","type":"uint32"},{"internalType":"address","name":"originSender","type":"address"},{"internalType":"address","name":"destRecipient","type":"address"},{"internalType":"address","name":"originToken","type":"address"},{"internalType":"address","name":"destToken","type":"address"},{"internalType":"uint256","name":"originAmount","type":"uint256"},{"internalType":"uint256","name":"destAmount","type":"uint256"},{"internalType":"uint256","name":"originFeeAmount","type":"uint256"},{"internalType":"bool","name":"sendChainGas","type":"bool"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint256","name":"nonce","type":"uint256"}],"internalType":"struct IFastBridge.BridgeTransaction","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"},{"internalType":"bytes32","name":"destTxHash","type":"bytes32"}],"name":"prove","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"}],"name":"refund","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"}],"name":"relay","outputs":[],"stateMutability":"payable","type":"function"}],"userDoc":{"kind":"user","methods":{"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256))":{"notice":"Initiates bridge on origin chain to be relayed by off-chain relayer"},"canClaim(bytes32,address)":{"notice":"Checks if the dispute period has passed so bridge deposit can be claimed"},"claim(bytes,address)":{"notice":"Completes bridge transaction on origin chain by claiming originally deposited capital"},"dispute(bytes32)":{"notice":"Disputes an outstanding proof in case relayer provided dest chain tx is invalid"},"getBridgeTransaction(bytes)":{"notice":"Decodes bridge request into a bridge transaction"},"prove(bytes,bytes32)":{"notice":"Provides proof on origin side that relayer provided funds on destination side of bridge transaction"},"refund(bytes)":{"notice":"Refunds an outstanding bridge transaction in case optimistic bridging failed"},"relay(bytes)":{"notice":"Relays destination side of bridge transaction by off-chain relayer"}},"version":1},"developerDoc":{"kind":"dev","methods":{"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256))":{"params":{"params":"The parameters required to bridge"}},"canClaim(bytes32,address)":{"params":{"relayer":"The address of the relayer attempting to claim","transactionId":"The transaction id associated with the encoded bridge transaction to check"}},"claim(bytes,address)":{"params":{"request":"The encoded bridge transaction to claim on origin chain","to":"The recipient address of the funds"}},"dispute(bytes32)":{"params":{"transactionId":"The transaction id associated with the encoded bridge transaction to dispute"}},"getBridgeTransaction(bytes)":{"params":{"request":"The bridge request to decode"}},"prove(bytes,bytes32)":{"params":{"destTxHash":"The destination tx hash proving bridge transaction was relayed","request":"The encoded bridge transaction to prove on origin chain"}},"refund(bytes)":{"params":{"request":"The encoded bridge transaction to refund"}},"relay(bytes)":{"params":{"request":"The encoded bridge transaction to relay on destination chain"}}},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"BridgeDepositClaimed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"BridgeDepositRefunded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"name\":\"BridgeProofDisputed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"transactionHash\",\"type\":\"bytes32\"}],\"name\":\"BridgeProofProvided\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"originChainId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"chainGasAmount\",\"type\":\"uint256\"}],\"name\":\"BridgeRelayed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"destChainId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"sendChainGas\",\"type\":\"bool\"}],\"name\":\"BridgeRequested\",\"type\":\"event\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"dstChainId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"sendChainGas\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"}],\"internalType\":\"struct IFastBridge.BridgeParams\",\"name\":\"params\",\"type\":\"tuple\"}],\"name\":\"bridge\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"name\":\"canClaim\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"claim\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"}],\"name\":\"dispute\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"getBridgeTransaction\",\"outputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"originChainId\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"destChainId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"originSender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destRecipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"originFeeAmount\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"sendChainGas\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"}],\"internalType\":\"struct IFastBridge.BridgeTransaction\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"},{\"internalType\":\"bytes32\",\"name\":\"destTxHash\",\"type\":\"bytes32\"}],\"name\":\"prove\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"refund\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"relay\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{\"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256))\":{\"params\":{\"params\":\"The parameters required to bridge\"}},\"canClaim(bytes32,address)\":{\"params\":{\"relayer\":\"The address of the relayer attempting to claim\",\"transactionId\":\"The transaction id associated with the encoded bridge transaction to check\"}},\"claim(bytes,address)\":{\"params\":{\"request\":\"The encoded bridge transaction to claim on origin chain\",\"to\":\"The recipient address of the funds\"}},\"dispute(bytes32)\":{\"params\":{\"transactionId\":\"The transaction id associated with the encoded bridge transaction to dispute\"}},\"getBridgeTransaction(bytes)\":{\"params\":{\"request\":\"The bridge request to decode\"}},\"prove(bytes,bytes32)\":{\"params\":{\"destTxHash\":\"The destination tx hash proving bridge transaction was relayed\",\"request\":\"The encoded bridge transaction to prove on origin chain\"}},\"refund(bytes)\":{\"params\":{\"request\":\"The encoded bridge transaction to refund\"}},\"relay(bytes)\":{\"params\":{\"request\":\"The encoded bridge transaction to relay on destination chain\"}}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256))\":{\"notice\":\"Initiates bridge on origin chain to be relayed by off-chain relayer\"},\"canClaim(bytes32,address)\":{\"notice\":\"Checks if the dispute period has passed so bridge deposit can be claimed\"},\"claim(bytes,address)\":{\"notice\":\"Completes bridge transaction on origin chain by claiming originally deposited capital\"},\"dispute(bytes32)\":{\"notice\":\"Disputes an outstanding proof in case relayer provided dest chain tx is invalid\"},\"getBridgeTransaction(bytes)\":{\"notice\":\"Decodes bridge request into a bridge transaction\"},\"prove(bytes,bytes32)\":{\"notice\":\"Provides proof on origin side that relayer provided funds on destination side of bridge transaction\"},\"refund(bytes)\":{\"notice\":\"Refunds an outstanding bridge transaction in case optimistic bridging failed\"},\"relay(bytes)\":{\"notice\":\"Relays destination side of bridge transaction by off-chain relayer\"}},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeV2.sol\":\"IFastBridge\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeV2.sol\":{\"keccak256\":\"0x7cd0f885e80e2bdaa638bc32ae7af7d2e248f99ce4b354c217d0f0f7d7302e0a\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://7ccf28df0bd7b4606986585acd8622ed9b4e81379690061bb66088f0a2270af1\",\"dweb:/ipfs/QmTf7HNdHZkK6vmx8ZgewycQEb72oLD9nPwBpsM5reMstQ\"]}},\"version\":1}"},"hashes":{"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256))":"45851694","canClaim(bytes32,address)":"aa9641ab","claim(bytes,address)":"41fcb612","dispute(bytes32)":"add98c70","getBridgeTransaction(bytes)":"ac11fb1a","prove(bytes,bytes32)":"886d36ff","refund(bytes)":"5eb7d946","relay(bytes)":"8f0d6f17"}},"solidity/FastBridgeV2.sol:IFastBridgeRecipient":{"code":"0x","runtime-code":"0x","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.24 ^0.8.0 ^0.8.20;\n\n// contracts/interfaces/IAdmin.sol\n\ninterface IAdmin {\n // ============ Events ============\n\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n event ChainGasAmountUpdated(uint256 oldChainGasAmount, uint256 newChainGasAmount);\n\n // ============ Methods ============\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n\n function setChainGasAmount(uint256 newChainGasAmount) external;\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IFastBridgeRecipient.sol\n\ninterface IFastBridgeRecipient {\n function fastBridgeTransferReceived(\n address token,\n uint256 amount,\n bytes memory callParams\n )\n external\n payable\n returns (bytes4);\n}\n\n// contracts/interfaces/IFastBridgeV2Errors.sol\n\ninterface IFastBridgeV2Errors {\n error AmountIncorrect();\n error CallParamsLengthAboveMax();\n error ChainIncorrect();\n error ExclusivityParamsIncorrect();\n error MsgValueIncorrect();\n error NativeTokenCallValueNotSupported();\n error SenderIncorrect();\n error StatusIncorrect();\n error ZeroAddress();\n\n error RecipientIncorrectReturnValue();\n error RecipientNoReturnValue();\n\n error DeadlineExceeded();\n error DeadlineNotExceeded();\n error DeadlineTooShort();\n error DisputePeriodNotPassed();\n error DisputePeriodPassed();\n error ExclusivityPeriodNotPassed();\n\n error TransactionRelayed();\n}\n\n// contracts/libs/Errors.sol\n\nerror DeadlineExceeded();\nerror DeadlineNotExceeded();\nerror DeadlineTooShort();\nerror InsufficientOutputAmount();\n\nerror MsgValueIncorrect();\nerror PoolNotFound();\nerror TokenAddressMismatch();\nerror TokenNotContract();\nerror TokenNotETH();\nerror TokensIdentical();\n\nerror ChainIncorrect();\nerror AmountIncorrect();\nerror ZeroAddress();\n\nerror DisputePeriodNotPassed();\nerror DisputePeriodPassed();\nerror SenderIncorrect();\nerror StatusIncorrect();\nerror TransactionIdIncorrect();\nerror TransactionRelayed();\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// contracts/interfaces/IFastBridgeV2.sol\n\ninterface IFastBridgeV2 is IFastBridge {\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n struct BridgeTxDetails {\n BridgeStatus status;\n uint40 proofBlockTimestamp;\n uint48 proofBlockNumber;\n address proofRelayer;\n }\n\n struct BridgeRelay {\n uint48 blockNumber;\n uint48 blockTimestamp;\n address relayer;\n }\n\n /// @notice New params introduced in the FastBridgeV2.\n /// We are passing fields from the older BridgeParams struct outside of this struct\n /// for backwards compatibility.\n /// Note: quoteRelayer and quoteExclusivitySeconds are either both zero (indicating no exclusivity)\n /// or both non-zero (indicating exclusivity for the given period).\n /// Note: callValue \u003e 0 can NOT be used with destToken = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE (ETH_ADDRESS)\n /// @param quoteRelayer Relayer that provided the quote for the transaction\n /// @param quoteExclusivitySeconds Period of time the quote relayer is guaranteed exclusivity after user's deposit\n /// @param quoteId Unique quote identifier used for tracking the quote\n /// @param callValue ETH value to send to the recipient (if any)\n /// @param callParams Parameters for the arbitrary call to the destination recipient (if any)\n struct BridgeParamsV2 {\n address quoteRelayer;\n int256 quoteExclusivitySeconds;\n bytes quoteId;\n uint256 callValue;\n bytes callParams;\n }\n\n /// @notice Updated bridge transaction struct to include parameters introduced in FastBridgeV2.\n /// Note: only `exclusivityRelayer` can fill such a transaction until `exclusivityEndTime`.\n /// TODO: consider changing the encoding scheme to prevent spending extra gas on decoding.\n struct BridgeTransactionV2 {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n uint256 callValue; // ETH value to send to the recipient (if any) - replaces V1's sendChainGas flag\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n address exclusivityRelayer;\n uint256 exclusivityEndTime;\n bytes callParams;\n }\n\n event BridgeQuoteDetails(bytes32 indexed transactionId, bytes quoteId);\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability\n /// to provide temporary exclusivity fill rights for the quote relayer.\n /// @param params The parameters required to bridge\n /// @param paramsV2 The parameters for exclusivity fill rights (optional, can be left empty)\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function relay(bytes memory request, address relayer) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param transactionId The transaction id associated with the encoded bridge transaction to prove\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital.\n /// @notice Can only send funds to the relayer address on the proof.\n /// @param request The encoded bridge transaction to claim on origin chain\n function claim(bytes memory request) external;\n /// @notice Checks if a transaction has been relayed\n /// @param transactionId The ID of the transaction to check\n /// @return True if the transaction has been relayed, false otherwise\n function bridgeRelays(bytes32 transactionId) external view returns (bool);\n\n /// @notice Returns the status of a bridge transaction\n /// @param transactionId The ID of the bridge transaction\n /// @return BridgeStatus Status of the bridge transaction\n function bridgeStatuses(bytes32 transactionId) external view returns (BridgeStatus);\n\n /// @notice Returns the timestamp and relayer of a bridge proof\n /// @param transactionId The ID of the bridge transaction\n /// @return timestamp The timestamp of the bridge proof\n /// @return relayer The relayer address of the bridge proof\n function bridgeProofs(bytes32 transactionId) external view returns (uint96 timestamp, address relayer);\n\n /// @notice Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\n /// @param request The bridge request to decode\n function getBridgeTransactionV2(bytes memory request) external view returns (BridgeTransactionV2 memory);\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// contracts/libs/UniversalToken.sol\n\nlibrary UniversalTokenLib {\n using SafeERC20 for IERC20;\n\n address internal constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Transfers tokens to the given account. Reverts if transfer is not successful.\n /// @dev This might trigger fallback, if ETH is transferred to the contract.\n /// Make sure this can not lead to reentrancy attacks.\n function universalTransfer(address token, address to, uint256 value) internal {\n // Don't do anything, if need to send tokens to this address\n if (to == address(this)) return;\n // Don't do anything, if trying to send zero value\n if (value == 0) return;\n if (token == ETH_ADDRESS) {\n /// @dev Note: this can potentially lead to executing code in `to`.\n // solhint-disable-next-line avoid-low-level-calls\n (bool success,) = to.call{value: value}(\"\");\n require(success, \"ETH transfer failed\");\n } else {\n IERC20(token).safeTransfer(to, value);\n }\n }\n\n /// @notice Issues an infinite allowance to the spender, if the current allowance is insufficient\n /// to spend the given amount.\n function universalApproveInfinity(address token, address spender, uint256 amountToSpend) internal {\n // ETH Chad doesn't require your approval\n if (token == ETH_ADDRESS) return;\n // No-op if allowance is already sufficient\n uint256 allowance = IERC20(token).allowance(address(this), spender);\n if (allowance \u003e= amountToSpend) return;\n // Otherwise, reset approval to 0 and set to max allowance\n if (allowance \u003e 0) IERC20(token).safeDecreaseAllowance(spender, allowance);\n IERC20(token).safeIncreaseAllowance(spender, type(uint256).max);\n }\n\n /// @notice Returns the balance of the given token (or native ETH) for the given account.\n function universalBalanceOf(address token, address account) internal view returns (uint256) {\n if (token == ETH_ADDRESS) {\n return account.balance;\n } else {\n return IERC20(token).balanceOf(account);\n }\n }\n\n /// @dev Checks that token is a contract and not ETH_ADDRESS.\n function assertIsContract(address token) internal view {\n // Check that ETH_ADDRESS was not used (in case this is a predeploy on any of the chains)\n if (token == UniversalTokenLib.ETH_ADDRESS) revert TokenNotContract();\n // Check that token is not an EOA\n if (token.code.length == 0) revert TokenNotContract();\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/Admin.sol\n\ncontract Admin is IAdmin, AccessControlEnumerable {\n using UniversalTokenLib for address;\n\n bytes32 public constant RELAYER_ROLE = keccak256(\"RELAYER_ROLE\");\n bytes32 public constant REFUNDER_ROLE = keccak256(\"REFUNDER_ROLE\");\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n uint256 public constant FEE_BPS = 1e6;\n uint256 public constant FEE_RATE_MAX = 0.01e6; // max 1% on origin amount\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Chain gas amount to forward as rebate if requested\n uint256 public chainGasAmount;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n }\n\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n require(newFeeRate \u003c= FEE_RATE_MAX, \"newFeeRate \u003e max\");\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n token.universalTransfer(recipient, feeAmount);\n emit FeesSwept(token, recipient, feeAmount);\n }\n\n function setChainGasAmount(uint256 newChainGasAmount) external onlyRole(GOVERNOR_ROLE) {\n uint256 oldChainGasAmount = chainGasAmount;\n chainGasAmount = newChainGasAmount;\n emit ChainGasAmountUpdated(oldChainGasAmount, newChainGasAmount);\n }\n}\n\n// contracts/FastBridgeV2.sol\n\n/// @notice FastBridgeV2 is a contract for bridging tokens across chains.\ncontract FastBridgeV2 is Admin, IFastBridgeV2, IFastBridgeV2Errors {\n using SafeERC20 for IERC20;\n using UniversalTokenLib for address;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Delay for a transaction after which it could be permisionlessly refunded\n uint256 public constant REFUND_DELAY = 7 days;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n /// @notice Maximum length of accepted callParams\n uint256 public constant MAX_CALL_PARAMS_LENGTH = 2 ** 16 - 1;\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeTxDetails) public bridgeTxDetails;\n /// @notice Relay details on destination chain\n mapping(bytes32 =\u003e BridgeRelay) public bridgeRelayDetails;\n /// @notice Unique bridge nonces tracked per originSender\n mapping(address =\u003e uint256) public senderNonces;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Replaced by senderNonces\n uint256 public immutable nonce = 0;\n /// @notice the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n bridge({\n params: params,\n paramsV2: BridgeParamsV2({\n quoteRelayer: address(0),\n quoteExclusivitySeconds: 0,\n quoteId: bytes(\"\"),\n callValue: 0,\n callParams: bytes(\"\")\n })\n });\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes memory request) external payable {\n relay({request: request, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes memory request, bytes32 destTxHash) external {\n prove({transactionId: keccak256(request), destTxHash: destTxHash, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridgeV2\n function claim(bytes memory request) external {\n claim({request: request, to: address(0)});\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003e DISPUTE_PERIOD) {\n revert DisputePeriodPassed();\n }\n\n // @dev relayer gets slashed effectively if dest relay has gone thru\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n bridgeTxDetails[transactionId].proofRelayer = address(0);\n bridgeTxDetails[transactionId].proofBlockTimestamp = 0;\n bridgeTxDetails[transactionId].proofBlockNumber = 0;\n\n emit BridgeProofDisputed(transactionId, msg.sender);\n }\n\n /// @inheritdoc IFastBridge\n function refund(bytes memory request) external {\n bytes32 transactionId = keccak256(request);\n\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n\n if (bridgeTxDetails[transactionId].status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n\n if (hasRole(REFUNDER_ROLE, msg.sender)) {\n // Refunder can refund if deadline has passed\n if (block.timestamp \u003c= transaction.deadline) revert DeadlineNotExceeded();\n } else {\n // Permissionless refund is allowed after REFUND_DELAY\n if (block.timestamp \u003c= transaction.deadline + REFUND_DELAY) revert DeadlineNotExceeded();\n }\n\n // if all checks passed, set to REFUNDED status\n bridgeTxDetails[transactionId].status = BridgeStatus.REFUNDED;\n\n // transfer origin collateral back to original sender\n address to = transaction.originSender;\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount + transaction.originFeeAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (bridgeTxDetails[transactionId].proofRelayer != relayer) revert SenderIncorrect();\n return _timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n /// @dev This method is added to achieve backwards compatibility with decoding requests into V1 structs:\n /// - `callValue` is partially reported as a zero/non-zero flag\n /// - `callParams` is ignored\n /// In order to process all kinds of requests use getBridgeTransactionV2 instead.\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory) {\n // Try decoding into V2 struct first. This will revert if V1 struct is passed\n try this.getBridgeTransactionV2(request) returns (BridgeTransactionV2 memory txV2) {\n // Note: we entirely ignore the callParams field, as it was not present in V1\n return BridgeTransaction({\n originChainId: txV2.originChainId,\n destChainId: txV2.destChainId,\n originSender: txV2.originSender,\n destRecipient: txV2.destRecipient,\n originToken: txV2.originToken,\n destToken: txV2.destToken,\n originAmount: txV2.originAmount,\n destAmount: txV2.destAmount,\n originFeeAmount: txV2.originFeeAmount,\n sendChainGas: txV2.callValue != 0,\n deadline: txV2.deadline,\n nonce: txV2.nonce\n });\n } catch {\n // Fallback to V1 struct\n return abi.decode(request, (BridgeTransaction));\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) public payable {\n int256 exclusivityEndTime = int256(block.timestamp) + paramsV2.quoteExclusivitySeconds;\n _validateBridgeParams(params, paramsV2, exclusivityEndTime);\n\n // transfer tokens to bridge contract\n /// @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _pullToken(params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n\n // set status to requested\n bytes memory request = abi.encode(\n BridgeTransactionV2({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n callValue: paramsV2.callValue,\n deadline: params.deadline,\n nonce: senderNonces[params.sender]++, // increment nonce on every bridge\n exclusivityRelayer: paramsV2.quoteRelayer,\n // We checked exclusivityEndTime to be in range (0 .. params.deadline] above, so can safely cast\n exclusivityEndTime: uint256(exclusivityEndTime),\n callParams: paramsV2.callParams\n })\n );\n bytes32 transactionId = keccak256(request);\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n\n emit BridgeRequested({\n transactionId: transactionId,\n sender: params.sender,\n request: request,\n destChainId: params.dstChainId,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n sendChainGas: paramsV2.callValue != 0\n });\n emit BridgeQuoteDetails(transactionId, paramsV2.quoteId);\n }\n\n /// @inheritdoc IFastBridgeV2\n function relay(bytes memory request, address relayer) public payable {\n bytes32 transactionId = keccak256(request);\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n _validateRelayParams(transaction, transactionId, relayer);\n // mark bridge transaction as relayed\n bridgeRelayDetails[transactionId] =\n BridgeRelay({blockNumber: uint48(block.number), blockTimestamp: uint48(block.timestamp), relayer: relayer});\n\n // transfer tokens to recipient on destination chain and do an arbitrary call if requested\n address to = transaction.destRecipient;\n address token = transaction.destToken;\n uint256 amount = transaction.destAmount;\n\n // All state changes have been done at this point, can proceed to the external calls.\n // This follows the checks-effects-interactions pattern to mitigate potential reentrancy attacks.\n if (token == UniversalTokenLib.ETH_ADDRESS) {\n // For ETH non-zero callValue is not allowed\n if (transaction.callValue != 0) revert NativeTokenCallValueNotSupported();\n // Check that the correct msg.value was sent\n if (msg.value != amount) revert MsgValueIncorrect();\n } else {\n // For ERC20s, we check that the correct msg.value was sent\n if (msg.value != transaction.callValue) revert MsgValueIncorrect();\n // We need to transfer the tokens from the Relayer to the recipient first before performing an\n // optional post-transfer arbitrary call.\n IERC20(token).safeTransferFrom(msg.sender, to, amount);\n }\n\n if (transaction.callParams.length != 0) {\n // Arbitrary call requested, perform it while supplying full msg.value to the recipient\n // Note: if token has a fee on transfers, the recipient will have received less than `amount`.\n // This is a very niche edge case and should be handled by the recipient contract.\n _checkedCallRecipient({recipient: to, token: token, amount: amount, callParams: transaction.callParams});\n } else if (msg.value != 0) {\n // No arbitrary call requested, but msg.value was sent. This is either a relay with ETH,\n // or a non-zero callValue request with an ERC20. In both cases, transfer the ETH to the recipient.\n Address.sendValue(payable(to), msg.value);\n }\n\n emit BridgeRelayed({\n transactionId: transactionId,\n relayer: relayer,\n to: to,\n originChainId: transaction.originChainId,\n originToken: transaction.originToken,\n destToken: transaction.destToken,\n originAmount: transaction.originAmount,\n destAmount: transaction.destAmount,\n chainGasAmount: transaction.callValue\n });\n }\n\n /// @inheritdoc IFastBridgeV2\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) public onlyRole(RELAYER_ROLE) {\n // update bridge tx status given proof provided\n if (bridgeTxDetails[transactionId].status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n bridgeTxDetails[transactionId].status = BridgeStatus.RELAYER_PROVED;\n bridgeTxDetails[transactionId].proofBlockTimestamp = uint40(block.timestamp);\n bridgeTxDetails[transactionId].proofBlockNumber = uint48(block.number);\n bridgeTxDetails[transactionId].proofRelayer = relayer;\n\n emit BridgeProofProvided(transactionId, relayer, destTxHash);\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes memory request, address to) public {\n bytes32 transactionId = keccak256(request);\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n\n // update bridge tx status if able to claim origin collateral\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n\n // if \"to\" is zero addr, permissionlessly send funds to proven relayer\n if (to == address(0)) {\n to = bridgeTxDetails[transactionId].proofRelayer;\n } else if (bridgeTxDetails[transactionId].proofRelayer != msg.sender) {\n revert SenderIncorrect();\n }\n\n if (_timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003c= DISPUTE_PERIOD) {\n revert DisputePeriodNotPassed();\n }\n\n bridgeTxDetails[transactionId].status = BridgeStatus.RELAYER_CLAIMED;\n\n // update protocol fees if origin fee amount exists\n if (transaction.originFeeAmount \u003e 0) protocolFees[transaction.originToken] += transaction.originFeeAmount;\n\n // transfer origin collateral less fee to specified address\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositClaimed(transactionId, bridgeTxDetails[transactionId].proofRelayer, to, token, amount);\n }\n\n function bridgeStatuses(bytes32 transactionId) public view returns (BridgeStatus status) {\n return bridgeTxDetails[transactionId].status;\n }\n\n function bridgeProofs(bytes32 transactionId) public view returns (uint96 timestamp, address relayer) {\n timestamp = bridgeTxDetails[transactionId].proofBlockTimestamp;\n relayer = bridgeTxDetails[transactionId].proofRelayer;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeRelays(bytes32 transactionId) public view returns (bool) {\n // has this transactionId been relayed?\n return bridgeRelayDetails[transactionId].relayer != address(0);\n }\n\n /// @inheritdoc IFastBridgeV2\n function getBridgeTransactionV2(bytes memory request) public pure returns (BridgeTransactionV2 memory) {\n return abi.decode(request, (BridgeTransactionV2));\n }\n\n /// @notice Pulls a requested token from the user to this contract.\n function _pullToken(address token, uint256 amount) internal returns (uint256 amountPulled) {\n if (token == UniversalTokenLib.ETH_ADDRESS) {\n // For ETH we just need to check that the supplied msg.value is correct\n if (amount != msg.value) revert MsgValueIncorrect();\n amountPulled = msg.value;\n } else {\n token.assertIsContract();\n // Record token balance before transfer\n amountPulled = IERC20(token).balanceOf(address(this));\n // Token needs to be pulled only if msg.value is zero\n // This way user can specify WETH as the origin asset\n IERC20(token).safeTransferFrom(msg.sender, address(this), amount);\n // Use the difference between the recorded balance and the current balance as the amountPulled\n amountPulled = IERC20(token).balanceOf(address(this)) - amountPulled;\n }\n }\n\n /// @notice Calls the Recipient's hook function with the specified callParams and performs\n /// all the necessary checks for the returned value.\n function _checkedCallRecipient(\n address recipient,\n address token,\n uint256 amount,\n bytes memory callParams\n )\n internal\n {\n bytes memory hookData =\n abi.encodeCall(IFastBridgeRecipient.fastBridgeTransferReceived, (token, amount, callParams));\n // This will bubble any revert messages from the hook function\n bytes memory returnData = Address.functionCallWithValue({target: recipient, data: hookData, value: msg.value});\n // Explicit revert if no return data at all\n if (returnData.length == 0) revert RecipientNoReturnValue();\n // Check that exactly a single return value was returned\n if (returnData.length != 32) revert RecipientIncorrectReturnValue();\n // Return value should be abi-encoded hook function selector\n if (bytes32(returnData) != bytes32(IFastBridgeRecipient.fastBridgeTransferReceived.selector)) {\n revert RecipientIncorrectReturnValue();\n }\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint40(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint40).max but\n /// proof.timestamp \u003c type(uint40).max via unchecked statement\n /// @param proofBlockTimestamp The bridge proof block timestamp\n /// @return delta Time delta since proof submitted\n function _timeSince(uint40 proofBlockTimestamp) internal view returns (uint256 delta) {\n unchecked {\n delta = uint40(block.timestamp) - proofBlockTimestamp;\n }\n }\n\n /// @notice Performs all the necessary checks for a bridge to happen.\n /// @dev There's no good way to refactor this function to reduce cyclomatic complexity due to\n /// the number of checks that need to be performed, so we skip the code-complexity rule here.\n // solhint-disable-next-line code-complexity\n function _validateBridgeParams(\n BridgeParams memory params,\n BridgeParamsV2 memory paramsV2,\n int256 exclusivityEndTime\n )\n internal\n view\n {\n // Check V1 (legacy) params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.sender == address(0) || params.to == address(0)) revert ZeroAddress();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n // Check V2 params\n if (paramsV2.callParams.length \u003e MAX_CALL_PARAMS_LENGTH) revert CallParamsLengthAboveMax();\n if (paramsV2.callValue != 0 \u0026\u0026 params.destToken == UniversalTokenLib.ETH_ADDRESS) {\n revert NativeTokenCallValueNotSupported();\n }\n // exclusivityEndTime must be in range (0 .. params.deadline]\n if (exclusivityEndTime \u003c= 0 || exclusivityEndTime \u003e int256(params.deadline)) {\n revert ExclusivityParamsIncorrect();\n }\n }\n\n /// @notice Performs all the necessary checks for a relay to happen.\n function _validateRelayParams(\n BridgeTransactionV2 memory transaction,\n bytes32 transactionId,\n address relayer\n )\n internal\n view\n {\n if (relayer == address(0)) revert ZeroAddress();\n // Check if the transaction has already been relayed\n if (bridgeRelays(transactionId)) revert TransactionRelayed();\n if (transaction.destChainId != uint32(block.chainid)) revert ChainIncorrect();\n // Check the deadline for relay to happen\n if (block.timestamp \u003e transaction.deadline) revert DeadlineExceeded();\n // Check the exclusivity period, if it is still ongoing\n // forgefmt: disable-next-item\n if (\n transaction.exclusivityRelayer != address(0) \u0026\u0026\n transaction.exclusivityRelayer != relayer \u0026\u0026\n block.timestamp \u003c= transaction.exclusivityEndTime\n ) {\n revert ExclusivityPeriodNotPassed();\n }\n }\n}\n","language":"Solidity","languageVersion":"0.8.24","compilerVersion":"0.8.24","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"","srcMapRuntime":"","abiDefinition":[{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"bytes","name":"callParams","type":"bytes"}],"name":"fastBridgeTransferReceived","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"payable","type":"function"}],"userDoc":{"kind":"user","methods":{},"version":1},"developerDoc":{"kind":"dev","methods":{},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"callParams\",\"type\":\"bytes\"}],\"name\":\"fastBridgeTransferReceived\",\"outputs\":[{\"internalType\":\"bytes4\",\"name\":\"\",\"type\":\"bytes4\"}],\"stateMutability\":\"payable\",\"type\":\"function\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeV2.sol\":\"IFastBridgeRecipient\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeV2.sol\":{\"keccak256\":\"0x7cd0f885e80e2bdaa638bc32ae7af7d2e248f99ce4b354c217d0f0f7d7302e0a\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://7ccf28df0bd7b4606986585acd8622ed9b4e81379690061bb66088f0a2270af1\",\"dweb:/ipfs/QmTf7HNdHZkK6vmx8ZgewycQEb72oLD9nPwBpsM5reMstQ\"]}},\"version\":1}"},"hashes":{"fastBridgeTransferReceived(address,uint256,bytes)":"461e0c21"}},"solidity/FastBridgeV2.sol:IFastBridgeV2":{"code":"0x","runtime-code":"0x","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.24 ^0.8.0 ^0.8.20;\n\n// contracts/interfaces/IAdmin.sol\n\ninterface IAdmin {\n // ============ Events ============\n\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n event ChainGasAmountUpdated(uint256 oldChainGasAmount, uint256 newChainGasAmount);\n\n // ============ Methods ============\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n\n function setChainGasAmount(uint256 newChainGasAmount) external;\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IFastBridgeRecipient.sol\n\ninterface IFastBridgeRecipient {\n function fastBridgeTransferReceived(\n address token,\n uint256 amount,\n bytes memory callParams\n )\n external\n payable\n returns (bytes4);\n}\n\n// contracts/interfaces/IFastBridgeV2Errors.sol\n\ninterface IFastBridgeV2Errors {\n error AmountIncorrect();\n error CallParamsLengthAboveMax();\n error ChainIncorrect();\n error ExclusivityParamsIncorrect();\n error MsgValueIncorrect();\n error NativeTokenCallValueNotSupported();\n error SenderIncorrect();\n error StatusIncorrect();\n error ZeroAddress();\n\n error RecipientIncorrectReturnValue();\n error RecipientNoReturnValue();\n\n error DeadlineExceeded();\n error DeadlineNotExceeded();\n error DeadlineTooShort();\n error DisputePeriodNotPassed();\n error DisputePeriodPassed();\n error ExclusivityPeriodNotPassed();\n\n error TransactionRelayed();\n}\n\n// contracts/libs/Errors.sol\n\nerror DeadlineExceeded();\nerror DeadlineNotExceeded();\nerror DeadlineTooShort();\nerror InsufficientOutputAmount();\n\nerror MsgValueIncorrect();\nerror PoolNotFound();\nerror TokenAddressMismatch();\nerror TokenNotContract();\nerror TokenNotETH();\nerror TokensIdentical();\n\nerror ChainIncorrect();\nerror AmountIncorrect();\nerror ZeroAddress();\n\nerror DisputePeriodNotPassed();\nerror DisputePeriodPassed();\nerror SenderIncorrect();\nerror StatusIncorrect();\nerror TransactionIdIncorrect();\nerror TransactionRelayed();\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// contracts/interfaces/IFastBridgeV2.sol\n\ninterface IFastBridgeV2 is IFastBridge {\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n struct BridgeTxDetails {\n BridgeStatus status;\n uint40 proofBlockTimestamp;\n uint48 proofBlockNumber;\n address proofRelayer;\n }\n\n struct BridgeRelay {\n uint48 blockNumber;\n uint48 blockTimestamp;\n address relayer;\n }\n\n /// @notice New params introduced in the FastBridgeV2.\n /// We are passing fields from the older BridgeParams struct outside of this struct\n /// for backwards compatibility.\n /// Note: quoteRelayer and quoteExclusivitySeconds are either both zero (indicating no exclusivity)\n /// or both non-zero (indicating exclusivity for the given period).\n /// Note: callValue \u003e 0 can NOT be used with destToken = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE (ETH_ADDRESS)\n /// @param quoteRelayer Relayer that provided the quote for the transaction\n /// @param quoteExclusivitySeconds Period of time the quote relayer is guaranteed exclusivity after user's deposit\n /// @param quoteId Unique quote identifier used for tracking the quote\n /// @param callValue ETH value to send to the recipient (if any)\n /// @param callParams Parameters for the arbitrary call to the destination recipient (if any)\n struct BridgeParamsV2 {\n address quoteRelayer;\n int256 quoteExclusivitySeconds;\n bytes quoteId;\n uint256 callValue;\n bytes callParams;\n }\n\n /// @notice Updated bridge transaction struct to include parameters introduced in FastBridgeV2.\n /// Note: only `exclusivityRelayer` can fill such a transaction until `exclusivityEndTime`.\n /// TODO: consider changing the encoding scheme to prevent spending extra gas on decoding.\n struct BridgeTransactionV2 {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n uint256 callValue; // ETH value to send to the recipient (if any) - replaces V1's sendChainGas flag\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n address exclusivityRelayer;\n uint256 exclusivityEndTime;\n bytes callParams;\n }\n\n event BridgeQuoteDetails(bytes32 indexed transactionId, bytes quoteId);\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability\n /// to provide temporary exclusivity fill rights for the quote relayer.\n /// @param params The parameters required to bridge\n /// @param paramsV2 The parameters for exclusivity fill rights (optional, can be left empty)\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function relay(bytes memory request, address relayer) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param transactionId The transaction id associated with the encoded bridge transaction to prove\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital.\n /// @notice Can only send funds to the relayer address on the proof.\n /// @param request The encoded bridge transaction to claim on origin chain\n function claim(bytes memory request) external;\n /// @notice Checks if a transaction has been relayed\n /// @param transactionId The ID of the transaction to check\n /// @return True if the transaction has been relayed, false otherwise\n function bridgeRelays(bytes32 transactionId) external view returns (bool);\n\n /// @notice Returns the status of a bridge transaction\n /// @param transactionId The ID of the bridge transaction\n /// @return BridgeStatus Status of the bridge transaction\n function bridgeStatuses(bytes32 transactionId) external view returns (BridgeStatus);\n\n /// @notice Returns the timestamp and relayer of a bridge proof\n /// @param transactionId The ID of the bridge transaction\n /// @return timestamp The timestamp of the bridge proof\n /// @return relayer The relayer address of the bridge proof\n function bridgeProofs(bytes32 transactionId) external view returns (uint96 timestamp, address relayer);\n\n /// @notice Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\n /// @param request The bridge request to decode\n function getBridgeTransactionV2(bytes memory request) external view returns (BridgeTransactionV2 memory);\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// contracts/libs/UniversalToken.sol\n\nlibrary UniversalTokenLib {\n using SafeERC20 for IERC20;\n\n address internal constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Transfers tokens to the given account. Reverts if transfer is not successful.\n /// @dev This might trigger fallback, if ETH is transferred to the contract.\n /// Make sure this can not lead to reentrancy attacks.\n function universalTransfer(address token, address to, uint256 value) internal {\n // Don't do anything, if need to send tokens to this address\n if (to == address(this)) return;\n // Don't do anything, if trying to send zero value\n if (value == 0) return;\n if (token == ETH_ADDRESS) {\n /// @dev Note: this can potentially lead to executing code in `to`.\n // solhint-disable-next-line avoid-low-level-calls\n (bool success,) = to.call{value: value}(\"\");\n require(success, \"ETH transfer failed\");\n } else {\n IERC20(token).safeTransfer(to, value);\n }\n }\n\n /// @notice Issues an infinite allowance to the spender, if the current allowance is insufficient\n /// to spend the given amount.\n function universalApproveInfinity(address token, address spender, uint256 amountToSpend) internal {\n // ETH Chad doesn't require your approval\n if (token == ETH_ADDRESS) return;\n // No-op if allowance is already sufficient\n uint256 allowance = IERC20(token).allowance(address(this), spender);\n if (allowance \u003e= amountToSpend) return;\n // Otherwise, reset approval to 0 and set to max allowance\n if (allowance \u003e 0) IERC20(token).safeDecreaseAllowance(spender, allowance);\n IERC20(token).safeIncreaseAllowance(spender, type(uint256).max);\n }\n\n /// @notice Returns the balance of the given token (or native ETH) for the given account.\n function universalBalanceOf(address token, address account) internal view returns (uint256) {\n if (token == ETH_ADDRESS) {\n return account.balance;\n } else {\n return IERC20(token).balanceOf(account);\n }\n }\n\n /// @dev Checks that token is a contract and not ETH_ADDRESS.\n function assertIsContract(address token) internal view {\n // Check that ETH_ADDRESS was not used (in case this is a predeploy on any of the chains)\n if (token == UniversalTokenLib.ETH_ADDRESS) revert TokenNotContract();\n // Check that token is not an EOA\n if (token.code.length == 0) revert TokenNotContract();\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/Admin.sol\n\ncontract Admin is IAdmin, AccessControlEnumerable {\n using UniversalTokenLib for address;\n\n bytes32 public constant RELAYER_ROLE = keccak256(\"RELAYER_ROLE\");\n bytes32 public constant REFUNDER_ROLE = keccak256(\"REFUNDER_ROLE\");\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n uint256 public constant FEE_BPS = 1e6;\n uint256 public constant FEE_RATE_MAX = 0.01e6; // max 1% on origin amount\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Chain gas amount to forward as rebate if requested\n uint256 public chainGasAmount;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n }\n\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n require(newFeeRate \u003c= FEE_RATE_MAX, \"newFeeRate \u003e max\");\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n token.universalTransfer(recipient, feeAmount);\n emit FeesSwept(token, recipient, feeAmount);\n }\n\n function setChainGasAmount(uint256 newChainGasAmount) external onlyRole(GOVERNOR_ROLE) {\n uint256 oldChainGasAmount = chainGasAmount;\n chainGasAmount = newChainGasAmount;\n emit ChainGasAmountUpdated(oldChainGasAmount, newChainGasAmount);\n }\n}\n\n// contracts/FastBridgeV2.sol\n\n/// @notice FastBridgeV2 is a contract for bridging tokens across chains.\ncontract FastBridgeV2 is Admin, IFastBridgeV2, IFastBridgeV2Errors {\n using SafeERC20 for IERC20;\n using UniversalTokenLib for address;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Delay for a transaction after which it could be permisionlessly refunded\n uint256 public constant REFUND_DELAY = 7 days;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n /// @notice Maximum length of accepted callParams\n uint256 public constant MAX_CALL_PARAMS_LENGTH = 2 ** 16 - 1;\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeTxDetails) public bridgeTxDetails;\n /// @notice Relay details on destination chain\n mapping(bytes32 =\u003e BridgeRelay) public bridgeRelayDetails;\n /// @notice Unique bridge nonces tracked per originSender\n mapping(address =\u003e uint256) public senderNonces;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Replaced by senderNonces\n uint256 public immutable nonce = 0;\n /// @notice the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n bridge({\n params: params,\n paramsV2: BridgeParamsV2({\n quoteRelayer: address(0),\n quoteExclusivitySeconds: 0,\n quoteId: bytes(\"\"),\n callValue: 0,\n callParams: bytes(\"\")\n })\n });\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes memory request) external payable {\n relay({request: request, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes memory request, bytes32 destTxHash) external {\n prove({transactionId: keccak256(request), destTxHash: destTxHash, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridgeV2\n function claim(bytes memory request) external {\n claim({request: request, to: address(0)});\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003e DISPUTE_PERIOD) {\n revert DisputePeriodPassed();\n }\n\n // @dev relayer gets slashed effectively if dest relay has gone thru\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n bridgeTxDetails[transactionId].proofRelayer = address(0);\n bridgeTxDetails[transactionId].proofBlockTimestamp = 0;\n bridgeTxDetails[transactionId].proofBlockNumber = 0;\n\n emit BridgeProofDisputed(transactionId, msg.sender);\n }\n\n /// @inheritdoc IFastBridge\n function refund(bytes memory request) external {\n bytes32 transactionId = keccak256(request);\n\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n\n if (bridgeTxDetails[transactionId].status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n\n if (hasRole(REFUNDER_ROLE, msg.sender)) {\n // Refunder can refund if deadline has passed\n if (block.timestamp \u003c= transaction.deadline) revert DeadlineNotExceeded();\n } else {\n // Permissionless refund is allowed after REFUND_DELAY\n if (block.timestamp \u003c= transaction.deadline + REFUND_DELAY) revert DeadlineNotExceeded();\n }\n\n // if all checks passed, set to REFUNDED status\n bridgeTxDetails[transactionId].status = BridgeStatus.REFUNDED;\n\n // transfer origin collateral back to original sender\n address to = transaction.originSender;\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount + transaction.originFeeAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (bridgeTxDetails[transactionId].proofRelayer != relayer) revert SenderIncorrect();\n return _timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n /// @dev This method is added to achieve backwards compatibility with decoding requests into V1 structs:\n /// - `callValue` is partially reported as a zero/non-zero flag\n /// - `callParams` is ignored\n /// In order to process all kinds of requests use getBridgeTransactionV2 instead.\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory) {\n // Try decoding into V2 struct first. This will revert if V1 struct is passed\n try this.getBridgeTransactionV2(request) returns (BridgeTransactionV2 memory txV2) {\n // Note: we entirely ignore the callParams field, as it was not present in V1\n return BridgeTransaction({\n originChainId: txV2.originChainId,\n destChainId: txV2.destChainId,\n originSender: txV2.originSender,\n destRecipient: txV2.destRecipient,\n originToken: txV2.originToken,\n destToken: txV2.destToken,\n originAmount: txV2.originAmount,\n destAmount: txV2.destAmount,\n originFeeAmount: txV2.originFeeAmount,\n sendChainGas: txV2.callValue != 0,\n deadline: txV2.deadline,\n nonce: txV2.nonce\n });\n } catch {\n // Fallback to V1 struct\n return abi.decode(request, (BridgeTransaction));\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) public payable {\n int256 exclusivityEndTime = int256(block.timestamp) + paramsV2.quoteExclusivitySeconds;\n _validateBridgeParams(params, paramsV2, exclusivityEndTime);\n\n // transfer tokens to bridge contract\n /// @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _pullToken(params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n\n // set status to requested\n bytes memory request = abi.encode(\n BridgeTransactionV2({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n callValue: paramsV2.callValue,\n deadline: params.deadline,\n nonce: senderNonces[params.sender]++, // increment nonce on every bridge\n exclusivityRelayer: paramsV2.quoteRelayer,\n // We checked exclusivityEndTime to be in range (0 .. params.deadline] above, so can safely cast\n exclusivityEndTime: uint256(exclusivityEndTime),\n callParams: paramsV2.callParams\n })\n );\n bytes32 transactionId = keccak256(request);\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n\n emit BridgeRequested({\n transactionId: transactionId,\n sender: params.sender,\n request: request,\n destChainId: params.dstChainId,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n sendChainGas: paramsV2.callValue != 0\n });\n emit BridgeQuoteDetails(transactionId, paramsV2.quoteId);\n }\n\n /// @inheritdoc IFastBridgeV2\n function relay(bytes memory request, address relayer) public payable {\n bytes32 transactionId = keccak256(request);\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n _validateRelayParams(transaction, transactionId, relayer);\n // mark bridge transaction as relayed\n bridgeRelayDetails[transactionId] =\n BridgeRelay({blockNumber: uint48(block.number), blockTimestamp: uint48(block.timestamp), relayer: relayer});\n\n // transfer tokens to recipient on destination chain and do an arbitrary call if requested\n address to = transaction.destRecipient;\n address token = transaction.destToken;\n uint256 amount = transaction.destAmount;\n\n // All state changes have been done at this point, can proceed to the external calls.\n // This follows the checks-effects-interactions pattern to mitigate potential reentrancy attacks.\n if (token == UniversalTokenLib.ETH_ADDRESS) {\n // For ETH non-zero callValue is not allowed\n if (transaction.callValue != 0) revert NativeTokenCallValueNotSupported();\n // Check that the correct msg.value was sent\n if (msg.value != amount) revert MsgValueIncorrect();\n } else {\n // For ERC20s, we check that the correct msg.value was sent\n if (msg.value != transaction.callValue) revert MsgValueIncorrect();\n // We need to transfer the tokens from the Relayer to the recipient first before performing an\n // optional post-transfer arbitrary call.\n IERC20(token).safeTransferFrom(msg.sender, to, amount);\n }\n\n if (transaction.callParams.length != 0) {\n // Arbitrary call requested, perform it while supplying full msg.value to the recipient\n // Note: if token has a fee on transfers, the recipient will have received less than `amount`.\n // This is a very niche edge case and should be handled by the recipient contract.\n _checkedCallRecipient({recipient: to, token: token, amount: amount, callParams: transaction.callParams});\n } else if (msg.value != 0) {\n // No arbitrary call requested, but msg.value was sent. This is either a relay with ETH,\n // or a non-zero callValue request with an ERC20. In both cases, transfer the ETH to the recipient.\n Address.sendValue(payable(to), msg.value);\n }\n\n emit BridgeRelayed({\n transactionId: transactionId,\n relayer: relayer,\n to: to,\n originChainId: transaction.originChainId,\n originToken: transaction.originToken,\n destToken: transaction.destToken,\n originAmount: transaction.originAmount,\n destAmount: transaction.destAmount,\n chainGasAmount: transaction.callValue\n });\n }\n\n /// @inheritdoc IFastBridgeV2\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) public onlyRole(RELAYER_ROLE) {\n // update bridge tx status given proof provided\n if (bridgeTxDetails[transactionId].status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n bridgeTxDetails[transactionId].status = BridgeStatus.RELAYER_PROVED;\n bridgeTxDetails[transactionId].proofBlockTimestamp = uint40(block.timestamp);\n bridgeTxDetails[transactionId].proofBlockNumber = uint48(block.number);\n bridgeTxDetails[transactionId].proofRelayer = relayer;\n\n emit BridgeProofProvided(transactionId, relayer, destTxHash);\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes memory request, address to) public {\n bytes32 transactionId = keccak256(request);\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n\n // update bridge tx status if able to claim origin collateral\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n\n // if \"to\" is zero addr, permissionlessly send funds to proven relayer\n if (to == address(0)) {\n to = bridgeTxDetails[transactionId].proofRelayer;\n } else if (bridgeTxDetails[transactionId].proofRelayer != msg.sender) {\n revert SenderIncorrect();\n }\n\n if (_timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003c= DISPUTE_PERIOD) {\n revert DisputePeriodNotPassed();\n }\n\n bridgeTxDetails[transactionId].status = BridgeStatus.RELAYER_CLAIMED;\n\n // update protocol fees if origin fee amount exists\n if (transaction.originFeeAmount \u003e 0) protocolFees[transaction.originToken] += transaction.originFeeAmount;\n\n // transfer origin collateral less fee to specified address\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositClaimed(transactionId, bridgeTxDetails[transactionId].proofRelayer, to, token, amount);\n }\n\n function bridgeStatuses(bytes32 transactionId) public view returns (BridgeStatus status) {\n return bridgeTxDetails[transactionId].status;\n }\n\n function bridgeProofs(bytes32 transactionId) public view returns (uint96 timestamp, address relayer) {\n timestamp = bridgeTxDetails[transactionId].proofBlockTimestamp;\n relayer = bridgeTxDetails[transactionId].proofRelayer;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeRelays(bytes32 transactionId) public view returns (bool) {\n // has this transactionId been relayed?\n return bridgeRelayDetails[transactionId].relayer != address(0);\n }\n\n /// @inheritdoc IFastBridgeV2\n function getBridgeTransactionV2(bytes memory request) public pure returns (BridgeTransactionV2 memory) {\n return abi.decode(request, (BridgeTransactionV2));\n }\n\n /// @notice Pulls a requested token from the user to this contract.\n function _pullToken(address token, uint256 amount) internal returns (uint256 amountPulled) {\n if (token == UniversalTokenLib.ETH_ADDRESS) {\n // For ETH we just need to check that the supplied msg.value is correct\n if (amount != msg.value) revert MsgValueIncorrect();\n amountPulled = msg.value;\n } else {\n token.assertIsContract();\n // Record token balance before transfer\n amountPulled = IERC20(token).balanceOf(address(this));\n // Token needs to be pulled only if msg.value is zero\n // This way user can specify WETH as the origin asset\n IERC20(token).safeTransferFrom(msg.sender, address(this), amount);\n // Use the difference between the recorded balance and the current balance as the amountPulled\n amountPulled = IERC20(token).balanceOf(address(this)) - amountPulled;\n }\n }\n\n /// @notice Calls the Recipient's hook function with the specified callParams and performs\n /// all the necessary checks for the returned value.\n function _checkedCallRecipient(\n address recipient,\n address token,\n uint256 amount,\n bytes memory callParams\n )\n internal\n {\n bytes memory hookData =\n abi.encodeCall(IFastBridgeRecipient.fastBridgeTransferReceived, (token, amount, callParams));\n // This will bubble any revert messages from the hook function\n bytes memory returnData = Address.functionCallWithValue({target: recipient, data: hookData, value: msg.value});\n // Explicit revert if no return data at all\n if (returnData.length == 0) revert RecipientNoReturnValue();\n // Check that exactly a single return value was returned\n if (returnData.length != 32) revert RecipientIncorrectReturnValue();\n // Return value should be abi-encoded hook function selector\n if (bytes32(returnData) != bytes32(IFastBridgeRecipient.fastBridgeTransferReceived.selector)) {\n revert RecipientIncorrectReturnValue();\n }\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint40(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint40).max but\n /// proof.timestamp \u003c type(uint40).max via unchecked statement\n /// @param proofBlockTimestamp The bridge proof block timestamp\n /// @return delta Time delta since proof submitted\n function _timeSince(uint40 proofBlockTimestamp) internal view returns (uint256 delta) {\n unchecked {\n delta = uint40(block.timestamp) - proofBlockTimestamp;\n }\n }\n\n /// @notice Performs all the necessary checks for a bridge to happen.\n /// @dev There's no good way to refactor this function to reduce cyclomatic complexity due to\n /// the number of checks that need to be performed, so we skip the code-complexity rule here.\n // solhint-disable-next-line code-complexity\n function _validateBridgeParams(\n BridgeParams memory params,\n BridgeParamsV2 memory paramsV2,\n int256 exclusivityEndTime\n )\n internal\n view\n {\n // Check V1 (legacy) params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.sender == address(0) || params.to == address(0)) revert ZeroAddress();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n // Check V2 params\n if (paramsV2.callParams.length \u003e MAX_CALL_PARAMS_LENGTH) revert CallParamsLengthAboveMax();\n if (paramsV2.callValue != 0 \u0026\u0026 params.destToken == UniversalTokenLib.ETH_ADDRESS) {\n revert NativeTokenCallValueNotSupported();\n }\n // exclusivityEndTime must be in range (0 .. params.deadline]\n if (exclusivityEndTime \u003c= 0 || exclusivityEndTime \u003e int256(params.deadline)) {\n revert ExclusivityParamsIncorrect();\n }\n }\n\n /// @notice Performs all the necessary checks for a relay to happen.\n function _validateRelayParams(\n BridgeTransactionV2 memory transaction,\n bytes32 transactionId,\n address relayer\n )\n internal\n view\n {\n if (relayer == address(0)) revert ZeroAddress();\n // Check if the transaction has already been relayed\n if (bridgeRelays(transactionId)) revert TransactionRelayed();\n if (transaction.destChainId != uint32(block.chainid)) revert ChainIncorrect();\n // Check the deadline for relay to happen\n if (block.timestamp \u003e transaction.deadline) revert DeadlineExceeded();\n // Check the exclusivity period, if it is still ongoing\n // forgefmt: disable-next-item\n if (\n transaction.exclusivityRelayer != address(0) \u0026\u0026\n transaction.exclusivityRelayer != relayer \u0026\u0026\n block.timestamp \u003c= transaction.exclusivityEndTime\n ) {\n revert ExclusivityPeriodNotPassed();\n }\n }\n}\n","language":"Solidity","languageVersion":"0.8.24","compilerVersion":"0.8.24","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"","srcMapRuntime":"","abiDefinition":[{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"relayer","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"BridgeDepositClaimed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"BridgeDepositRefunded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"relayer","type":"address"}],"name":"BridgeProofDisputed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"relayer","type":"address"},{"indexed":false,"internalType":"bytes32","name":"transactionHash","type":"bytes32"}],"name":"BridgeProofProvided","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":false,"internalType":"bytes","name":"quoteId","type":"bytes"}],"name":"BridgeQuoteDetails","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"relayer","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint32","name":"originChainId","type":"uint32"},{"indexed":false,"internalType":"address","name":"originToken","type":"address"},{"indexed":false,"internalType":"address","name":"destToken","type":"address"},{"indexed":false,"internalType":"uint256","name":"originAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"destAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"chainGasAmount","type":"uint256"}],"name":"BridgeRelayed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"bytes","name":"request","type":"bytes"},{"indexed":false,"internalType":"uint32","name":"destChainId","type":"uint32"},{"indexed":false,"internalType":"address","name":"originToken","type":"address"},{"indexed":false,"internalType":"address","name":"destToken","type":"address"},{"indexed":false,"internalType":"uint256","name":"originAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"destAmount","type":"uint256"},{"indexed":false,"internalType":"bool","name":"sendChainGas","type":"bool"}],"name":"BridgeRequested","type":"event"},{"inputs":[{"components":[{"internalType":"uint32","name":"dstChainId","type":"uint32"},{"internalType":"address","name":"sender","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"address","name":"originToken","type":"address"},{"internalType":"address","name":"destToken","type":"address"},{"internalType":"uint256","name":"originAmount","type":"uint256"},{"internalType":"uint256","name":"destAmount","type":"uint256"},{"internalType":"bool","name":"sendChainGas","type":"bool"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"internalType":"struct IFastBridge.BridgeParams","name":"params","type":"tuple"}],"name":"bridge","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"uint32","name":"dstChainId","type":"uint32"},{"internalType":"address","name":"sender","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"address","name":"originToken","type":"address"},{"internalType":"address","name":"destToken","type":"address"},{"internalType":"uint256","name":"originAmount","type":"uint256"},{"internalType":"uint256","name":"destAmount","type":"uint256"},{"internalType":"bool","name":"sendChainGas","type":"bool"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"internalType":"struct IFastBridge.BridgeParams","name":"params","type":"tuple"},{"components":[{"internalType":"address","name":"quoteRelayer","type":"address"},{"internalType":"int256","name":"quoteExclusivitySeconds","type":"int256"},{"internalType":"bytes","name":"quoteId","type":"bytes"},{"internalType":"uint256","name":"callValue","type":"uint256"},{"internalType":"bytes","name":"callParams","type":"bytes"}],"internalType":"struct IFastBridgeV2.BridgeParamsV2","name":"paramsV2","type":"tuple"}],"name":"bridge","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"transactionId","type":"bytes32"}],"name":"bridgeProofs","outputs":[{"internalType":"uint96","name":"timestamp","type":"uint96"},{"internalType":"address","name":"relayer","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"transactionId","type":"bytes32"}],"name":"bridgeRelays","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"transactionId","type":"bytes32"}],"name":"bridgeStatuses","outputs":[{"internalType":"enum IFastBridgeV2.BridgeStatus","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"internalType":"address","name":"relayer","type":"address"}],"name":"canClaim","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"},{"internalType":"address","name":"to","type":"address"}],"name":"claim","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"}],"name":"claim","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"transactionId","type":"bytes32"}],"name":"dispute","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"}],"name":"getBridgeTransaction","outputs":[{"components":[{"internalType":"uint32","name":"originChainId","type":"uint32"},{"internalType":"uint32","name":"destChainId","type":"uint32"},{"internalType":"address","name":"originSender","type":"address"},{"internalType":"address","name":"destRecipient","type":"address"},{"internalType":"address","name":"originToken","type":"address"},{"internalType":"address","name":"destToken","type":"address"},{"internalType":"uint256","name":"originAmount","type":"uint256"},{"internalType":"uint256","name":"destAmount","type":"uint256"},{"internalType":"uint256","name":"originFeeAmount","type":"uint256"},{"internalType":"bool","name":"sendChainGas","type":"bool"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint256","name":"nonce","type":"uint256"}],"internalType":"struct IFastBridge.BridgeTransaction","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"}],"name":"getBridgeTransactionV2","outputs":[{"components":[{"internalType":"uint32","name":"originChainId","type":"uint32"},{"internalType":"uint32","name":"destChainId","type":"uint32"},{"internalType":"address","name":"originSender","type":"address"},{"internalType":"address","name":"destRecipient","type":"address"},{"internalType":"address","name":"originToken","type":"address"},{"internalType":"address","name":"destToken","type":"address"},{"internalType":"uint256","name":"originAmount","type":"uint256"},{"internalType":"uint256","name":"destAmount","type":"uint256"},{"internalType":"uint256","name":"originFeeAmount","type":"uint256"},{"internalType":"uint256","name":"callValue","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"address","name":"exclusivityRelayer","type":"address"},{"internalType":"uint256","name":"exclusivityEndTime","type":"uint256"},{"internalType":"bytes","name":"callParams","type":"bytes"}],"internalType":"struct IFastBridgeV2.BridgeTransactionV2","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"internalType":"bytes32","name":"destTxHash","type":"bytes32"},{"internalType":"address","name":"relayer","type":"address"}],"name":"prove","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"},{"internalType":"bytes32","name":"destTxHash","type":"bytes32"}],"name":"prove","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"}],"name":"refund","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"}],"name":"relay","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"},{"internalType":"address","name":"relayer","type":"address"}],"name":"relay","outputs":[],"stateMutability":"payable","type":"function"}],"userDoc":{"kind":"user","methods":{"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256))":{"notice":"Initiates bridge on origin chain to be relayed by off-chain relayer"},"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256),(address,int256,bytes,uint256,bytes))":{"notice":"Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability to provide temporary exclusivity fill rights for the quote relayer."},"bridgeProofs(bytes32)":{"notice":"Returns the timestamp and relayer of a bridge proof"},"bridgeRelays(bytes32)":{"notice":"Checks if a transaction has been relayed"},"bridgeStatuses(bytes32)":{"notice":"Returns the status of a bridge transaction"},"canClaim(bytes32,address)":{"notice":"Checks if the dispute period has passed so bridge deposit can be claimed"},"claim(bytes)":{"notice":"Completes bridge transaction on origin chain by claiming originally deposited capital.Can only send funds to the relayer address on the proof."},"claim(bytes,address)":{"notice":"Completes bridge transaction on origin chain by claiming originally deposited capital"},"dispute(bytes32)":{"notice":"Disputes an outstanding proof in case relayer provided dest chain tx is invalid"},"getBridgeTransaction(bytes)":{"notice":"Decodes bridge request into a bridge transaction"},"getBridgeTransactionV2(bytes)":{"notice":"Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2"},"prove(bytes,bytes32)":{"notice":"Provides proof on origin side that relayer provided funds on destination side of bridge transaction"},"prove(bytes32,bytes32,address)":{"notice":"Provides proof on origin side that relayer provided funds on destination side of bridge transaction"},"refund(bytes)":{"notice":"Refunds an outstanding bridge transaction in case optimistic bridging failed"},"relay(bytes)":{"notice":"Relays destination side of bridge transaction by off-chain relayer"},"relay(bytes,address)":{"notice":"Relays destination side of bridge transaction by off-chain relayer"}},"version":1},"developerDoc":{"kind":"dev","methods":{"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256))":{"params":{"params":"The parameters required to bridge"}},"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256),(address,int256,bytes,uint256,bytes))":{"params":{"params":"The parameters required to bridge","paramsV2":"The parameters for exclusivity fill rights (optional, can be left empty)"}},"bridgeProofs(bytes32)":{"params":{"transactionId":"The ID of the bridge transaction"},"returns":{"relayer":"The relayer address of the bridge proof","timestamp":"The timestamp of the bridge proof"}},"bridgeRelays(bytes32)":{"params":{"transactionId":"The ID of the transaction to check"},"returns":{"_0":"True if the transaction has been relayed, false otherwise"}},"bridgeStatuses(bytes32)":{"params":{"transactionId":"The ID of the bridge transaction"},"returns":{"_0":"BridgeStatus Status of the bridge transaction"}},"canClaim(bytes32,address)":{"params":{"relayer":"The address of the relayer attempting to claim","transactionId":"The transaction id associated with the encoded bridge transaction to check"}},"claim(bytes)":{"params":{"request":"The encoded bridge transaction to claim on origin chain"}},"claim(bytes,address)":{"params":{"request":"The encoded bridge transaction to claim on origin chain","to":"The recipient address of the funds"}},"dispute(bytes32)":{"params":{"transactionId":"The transaction id associated with the encoded bridge transaction to dispute"}},"getBridgeTransaction(bytes)":{"params":{"request":"The bridge request to decode"}},"getBridgeTransactionV2(bytes)":{"params":{"request":"The bridge request to decode"}},"prove(bytes,bytes32)":{"params":{"destTxHash":"The destination tx hash proving bridge transaction was relayed","request":"The encoded bridge transaction to prove on origin chain"}},"prove(bytes32,bytes32,address)":{"params":{"destTxHash":"The destination tx hash proving bridge transaction was relayed","relayer":"The address of the relaying entity which should have control of the origin funds when claimed","transactionId":"The transaction id associated with the encoded bridge transaction to prove"}},"refund(bytes)":{"params":{"request":"The encoded bridge transaction to refund"}},"relay(bytes)":{"params":{"request":"The encoded bridge transaction to relay on destination chain"}},"relay(bytes,address)":{"params":{"relayer":"The address of the relaying entity which should have control of the origin funds when claimed","request":"The encoded bridge transaction to relay on destination chain"}}},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"BridgeDepositClaimed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"BridgeDepositRefunded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"name\":\"BridgeProofDisputed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"transactionHash\",\"type\":\"bytes32\"}],\"name\":\"BridgeProofProvided\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"quoteId\",\"type\":\"bytes\"}],\"name\":\"BridgeQuoteDetails\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"originChainId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"chainGasAmount\",\"type\":\"uint256\"}],\"name\":\"BridgeRelayed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"destChainId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"sendChainGas\",\"type\":\"bool\"}],\"name\":\"BridgeRequested\",\"type\":\"event\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"dstChainId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"sendChainGas\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"}],\"internalType\":\"struct IFastBridge.BridgeParams\",\"name\":\"params\",\"type\":\"tuple\"}],\"name\":\"bridge\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"dstChainId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"sendChainGas\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"}],\"internalType\":\"struct IFastBridge.BridgeParams\",\"name\":\"params\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"quoteRelayer\",\"type\":\"address\"},{\"internalType\":\"int256\",\"name\":\"quoteExclusivitySeconds\",\"type\":\"int256\"},{\"internalType\":\"bytes\",\"name\":\"quoteId\",\"type\":\"bytes\"},{\"internalType\":\"uint256\",\"name\":\"callValue\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"callParams\",\"type\":\"bytes\"}],\"internalType\":\"struct IFastBridgeV2.BridgeParamsV2\",\"name\":\"paramsV2\",\"type\":\"tuple\"}],\"name\":\"bridge\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"}],\"name\":\"bridgeProofs\",\"outputs\":[{\"internalType\":\"uint96\",\"name\":\"timestamp\",\"type\":\"uint96\"},{\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"}],\"name\":\"bridgeRelays\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"}],\"name\":\"bridgeStatuses\",\"outputs\":[{\"internalType\":\"enum IFastBridgeV2.BridgeStatus\",\"name\":\"\",\"type\":\"uint8\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"name\":\"canClaim\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"claim\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"claim\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"}],\"name\":\"dispute\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"getBridgeTransaction\",\"outputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"originChainId\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"destChainId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"originSender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destRecipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"originFeeAmount\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"sendChainGas\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"}],\"internalType\":\"struct IFastBridge.BridgeTransaction\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"getBridgeTransactionV2\",\"outputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"originChainId\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"destChainId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"originSender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destRecipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"originFeeAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"callValue\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"exclusivityRelayer\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"exclusivityEndTime\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"callParams\",\"type\":\"bytes\"}],\"internalType\":\"struct IFastBridgeV2.BridgeTransactionV2\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"destTxHash\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"name\":\"prove\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"},{\"internalType\":\"bytes32\",\"name\":\"destTxHash\",\"type\":\"bytes32\"}],\"name\":\"prove\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"refund\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"relay\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"},{\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"name\":\"relay\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{\"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256))\":{\"params\":{\"params\":\"The parameters required to bridge\"}},\"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256),(address,int256,bytes,uint256,bytes))\":{\"params\":{\"params\":\"The parameters required to bridge\",\"paramsV2\":\"The parameters for exclusivity fill rights (optional, can be left empty)\"}},\"bridgeProofs(bytes32)\":{\"params\":{\"transactionId\":\"The ID of the bridge transaction\"},\"returns\":{\"relayer\":\"The relayer address of the bridge proof\",\"timestamp\":\"The timestamp of the bridge proof\"}},\"bridgeRelays(bytes32)\":{\"params\":{\"transactionId\":\"The ID of the transaction to check\"},\"returns\":{\"_0\":\"True if the transaction has been relayed, false otherwise\"}},\"bridgeStatuses(bytes32)\":{\"params\":{\"transactionId\":\"The ID of the bridge transaction\"},\"returns\":{\"_0\":\"BridgeStatus Status of the bridge transaction\"}},\"canClaim(bytes32,address)\":{\"params\":{\"relayer\":\"The address of the relayer attempting to claim\",\"transactionId\":\"The transaction id associated with the encoded bridge transaction to check\"}},\"claim(bytes)\":{\"params\":{\"request\":\"The encoded bridge transaction to claim on origin chain\"}},\"claim(bytes,address)\":{\"params\":{\"request\":\"The encoded bridge transaction to claim on origin chain\",\"to\":\"The recipient address of the funds\"}},\"dispute(bytes32)\":{\"params\":{\"transactionId\":\"The transaction id associated with the encoded bridge transaction to dispute\"}},\"getBridgeTransaction(bytes)\":{\"params\":{\"request\":\"The bridge request to decode\"}},\"getBridgeTransactionV2(bytes)\":{\"params\":{\"request\":\"The bridge request to decode\"}},\"prove(bytes,bytes32)\":{\"params\":{\"destTxHash\":\"The destination tx hash proving bridge transaction was relayed\",\"request\":\"The encoded bridge transaction to prove on origin chain\"}},\"prove(bytes32,bytes32,address)\":{\"params\":{\"destTxHash\":\"The destination tx hash proving bridge transaction was relayed\",\"relayer\":\"The address of the relaying entity which should have control of the origin funds when claimed\",\"transactionId\":\"The transaction id associated with the encoded bridge transaction to prove\"}},\"refund(bytes)\":{\"params\":{\"request\":\"The encoded bridge transaction to refund\"}},\"relay(bytes)\":{\"params\":{\"request\":\"The encoded bridge transaction to relay on destination chain\"}},\"relay(bytes,address)\":{\"params\":{\"relayer\":\"The address of the relaying entity which should have control of the origin funds when claimed\",\"request\":\"The encoded bridge transaction to relay on destination chain\"}}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256))\":{\"notice\":\"Initiates bridge on origin chain to be relayed by off-chain relayer\"},\"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256),(address,int256,bytes,uint256,bytes))\":{\"notice\":\"Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability to provide temporary exclusivity fill rights for the quote relayer.\"},\"bridgeProofs(bytes32)\":{\"notice\":\"Returns the timestamp and relayer of a bridge proof\"},\"bridgeRelays(bytes32)\":{\"notice\":\"Checks if a transaction has been relayed\"},\"bridgeStatuses(bytes32)\":{\"notice\":\"Returns the status of a bridge transaction\"},\"canClaim(bytes32,address)\":{\"notice\":\"Checks if the dispute period has passed so bridge deposit can be claimed\"},\"claim(bytes)\":{\"notice\":\"Completes bridge transaction on origin chain by claiming originally deposited capital.Can only send funds to the relayer address on the proof.\"},\"claim(bytes,address)\":{\"notice\":\"Completes bridge transaction on origin chain by claiming originally deposited capital\"},\"dispute(bytes32)\":{\"notice\":\"Disputes an outstanding proof in case relayer provided dest chain tx is invalid\"},\"getBridgeTransaction(bytes)\":{\"notice\":\"Decodes bridge request into a bridge transaction\"},\"getBridgeTransactionV2(bytes)\":{\"notice\":\"Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\"},\"prove(bytes,bytes32)\":{\"notice\":\"Provides proof on origin side that relayer provided funds on destination side of bridge transaction\"},\"prove(bytes32,bytes32,address)\":{\"notice\":\"Provides proof on origin side that relayer provided funds on destination side of bridge transaction\"},\"refund(bytes)\":{\"notice\":\"Refunds an outstanding bridge transaction in case optimistic bridging failed\"},\"relay(bytes)\":{\"notice\":\"Relays destination side of bridge transaction by off-chain relayer\"},\"relay(bytes,address)\":{\"notice\":\"Relays destination side of bridge transaction by off-chain relayer\"}},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeV2.sol\":\"IFastBridgeV2\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeV2.sol\":{\"keccak256\":\"0x7cd0f885e80e2bdaa638bc32ae7af7d2e248f99ce4b354c217d0f0f7d7302e0a\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://7ccf28df0bd7b4606986585acd8622ed9b4e81379690061bb66088f0a2270af1\",\"dweb:/ipfs/QmTf7HNdHZkK6vmx8ZgewycQEb72oLD9nPwBpsM5reMstQ\"]}},\"version\":1}"},"hashes":{"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256))":"45851694","bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256),(address,int256,bytes,uint256,bytes))":"bfc7c607","bridgeProofs(bytes32)":"91ad5039","bridgeRelays(bytes32)":"8379a24f","bridgeStatuses(bytes32)":"051287bc","canClaim(bytes32,address)":"aa9641ab","claim(bytes)":"c63ff8dd","claim(bytes,address)":"41fcb612","dispute(bytes32)":"add98c70","getBridgeTransaction(bytes)":"ac11fb1a","getBridgeTransactionV2(bytes)":"5aa6ccba","prove(bytes,bytes32)":"886d36ff","prove(bytes32,bytes32,address)":"18e4357d","refund(bytes)":"5eb7d946","relay(bytes)":"8f0d6f17","relay(bytes,address)":"9c9545f0"}},"solidity/FastBridgeV2.sol:IFastBridgeV2Errors":{"code":"0x","runtime-code":"0x","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.24 ^0.8.0 ^0.8.20;\n\n// contracts/interfaces/IAdmin.sol\n\ninterface IAdmin {\n // ============ Events ============\n\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n event ChainGasAmountUpdated(uint256 oldChainGasAmount, uint256 newChainGasAmount);\n\n // ============ Methods ============\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n\n function setChainGasAmount(uint256 newChainGasAmount) external;\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IFastBridgeRecipient.sol\n\ninterface IFastBridgeRecipient {\n function fastBridgeTransferReceived(\n address token,\n uint256 amount,\n bytes memory callParams\n )\n external\n payable\n returns (bytes4);\n}\n\n// contracts/interfaces/IFastBridgeV2Errors.sol\n\ninterface IFastBridgeV2Errors {\n error AmountIncorrect();\n error CallParamsLengthAboveMax();\n error ChainIncorrect();\n error ExclusivityParamsIncorrect();\n error MsgValueIncorrect();\n error NativeTokenCallValueNotSupported();\n error SenderIncorrect();\n error StatusIncorrect();\n error ZeroAddress();\n\n error RecipientIncorrectReturnValue();\n error RecipientNoReturnValue();\n\n error DeadlineExceeded();\n error DeadlineNotExceeded();\n error DeadlineTooShort();\n error DisputePeriodNotPassed();\n error DisputePeriodPassed();\n error ExclusivityPeriodNotPassed();\n\n error TransactionRelayed();\n}\n\n// contracts/libs/Errors.sol\n\nerror DeadlineExceeded();\nerror DeadlineNotExceeded();\nerror DeadlineTooShort();\nerror InsufficientOutputAmount();\n\nerror MsgValueIncorrect();\nerror PoolNotFound();\nerror TokenAddressMismatch();\nerror TokenNotContract();\nerror TokenNotETH();\nerror TokensIdentical();\n\nerror ChainIncorrect();\nerror AmountIncorrect();\nerror ZeroAddress();\n\nerror DisputePeriodNotPassed();\nerror DisputePeriodPassed();\nerror SenderIncorrect();\nerror StatusIncorrect();\nerror TransactionIdIncorrect();\nerror TransactionRelayed();\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// contracts/interfaces/IFastBridgeV2.sol\n\ninterface IFastBridgeV2 is IFastBridge {\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n struct BridgeTxDetails {\n BridgeStatus status;\n uint40 proofBlockTimestamp;\n uint48 proofBlockNumber;\n address proofRelayer;\n }\n\n struct BridgeRelay {\n uint48 blockNumber;\n uint48 blockTimestamp;\n address relayer;\n }\n\n /// @notice New params introduced in the FastBridgeV2.\n /// We are passing fields from the older BridgeParams struct outside of this struct\n /// for backwards compatibility.\n /// Note: quoteRelayer and quoteExclusivitySeconds are either both zero (indicating no exclusivity)\n /// or both non-zero (indicating exclusivity for the given period).\n /// Note: callValue \u003e 0 can NOT be used with destToken = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE (ETH_ADDRESS)\n /// @param quoteRelayer Relayer that provided the quote for the transaction\n /// @param quoteExclusivitySeconds Period of time the quote relayer is guaranteed exclusivity after user's deposit\n /// @param quoteId Unique quote identifier used for tracking the quote\n /// @param callValue ETH value to send to the recipient (if any)\n /// @param callParams Parameters for the arbitrary call to the destination recipient (if any)\n struct BridgeParamsV2 {\n address quoteRelayer;\n int256 quoteExclusivitySeconds;\n bytes quoteId;\n uint256 callValue;\n bytes callParams;\n }\n\n /// @notice Updated bridge transaction struct to include parameters introduced in FastBridgeV2.\n /// Note: only `exclusivityRelayer` can fill such a transaction until `exclusivityEndTime`.\n /// TODO: consider changing the encoding scheme to prevent spending extra gas on decoding.\n struct BridgeTransactionV2 {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n uint256 callValue; // ETH value to send to the recipient (if any) - replaces V1's sendChainGas flag\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n address exclusivityRelayer;\n uint256 exclusivityEndTime;\n bytes callParams;\n }\n\n event BridgeQuoteDetails(bytes32 indexed transactionId, bytes quoteId);\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability\n /// to provide temporary exclusivity fill rights for the quote relayer.\n /// @param params The parameters required to bridge\n /// @param paramsV2 The parameters for exclusivity fill rights (optional, can be left empty)\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function relay(bytes memory request, address relayer) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param transactionId The transaction id associated with the encoded bridge transaction to prove\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital.\n /// @notice Can only send funds to the relayer address on the proof.\n /// @param request The encoded bridge transaction to claim on origin chain\n function claim(bytes memory request) external;\n /// @notice Checks if a transaction has been relayed\n /// @param transactionId The ID of the transaction to check\n /// @return True if the transaction has been relayed, false otherwise\n function bridgeRelays(bytes32 transactionId) external view returns (bool);\n\n /// @notice Returns the status of a bridge transaction\n /// @param transactionId The ID of the bridge transaction\n /// @return BridgeStatus Status of the bridge transaction\n function bridgeStatuses(bytes32 transactionId) external view returns (BridgeStatus);\n\n /// @notice Returns the timestamp and relayer of a bridge proof\n /// @param transactionId The ID of the bridge transaction\n /// @return timestamp The timestamp of the bridge proof\n /// @return relayer The relayer address of the bridge proof\n function bridgeProofs(bytes32 transactionId) external view returns (uint96 timestamp, address relayer);\n\n /// @notice Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\n /// @param request The bridge request to decode\n function getBridgeTransactionV2(bytes memory request) external view returns (BridgeTransactionV2 memory);\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// contracts/libs/UniversalToken.sol\n\nlibrary UniversalTokenLib {\n using SafeERC20 for IERC20;\n\n address internal constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Transfers tokens to the given account. Reverts if transfer is not successful.\n /// @dev This might trigger fallback, if ETH is transferred to the contract.\n /// Make sure this can not lead to reentrancy attacks.\n function universalTransfer(address token, address to, uint256 value) internal {\n // Don't do anything, if need to send tokens to this address\n if (to == address(this)) return;\n // Don't do anything, if trying to send zero value\n if (value == 0) return;\n if (token == ETH_ADDRESS) {\n /// @dev Note: this can potentially lead to executing code in `to`.\n // solhint-disable-next-line avoid-low-level-calls\n (bool success,) = to.call{value: value}(\"\");\n require(success, \"ETH transfer failed\");\n } else {\n IERC20(token).safeTransfer(to, value);\n }\n }\n\n /// @notice Issues an infinite allowance to the spender, if the current allowance is insufficient\n /// to spend the given amount.\n function universalApproveInfinity(address token, address spender, uint256 amountToSpend) internal {\n // ETH Chad doesn't require your approval\n if (token == ETH_ADDRESS) return;\n // No-op if allowance is already sufficient\n uint256 allowance = IERC20(token).allowance(address(this), spender);\n if (allowance \u003e= amountToSpend) return;\n // Otherwise, reset approval to 0 and set to max allowance\n if (allowance \u003e 0) IERC20(token).safeDecreaseAllowance(spender, allowance);\n IERC20(token).safeIncreaseAllowance(spender, type(uint256).max);\n }\n\n /// @notice Returns the balance of the given token (or native ETH) for the given account.\n function universalBalanceOf(address token, address account) internal view returns (uint256) {\n if (token == ETH_ADDRESS) {\n return account.balance;\n } else {\n return IERC20(token).balanceOf(account);\n }\n }\n\n /// @dev Checks that token is a contract and not ETH_ADDRESS.\n function assertIsContract(address token) internal view {\n // Check that ETH_ADDRESS was not used (in case this is a predeploy on any of the chains)\n if (token == UniversalTokenLib.ETH_ADDRESS) revert TokenNotContract();\n // Check that token is not an EOA\n if (token.code.length == 0) revert TokenNotContract();\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/Admin.sol\n\ncontract Admin is IAdmin, AccessControlEnumerable {\n using UniversalTokenLib for address;\n\n bytes32 public constant RELAYER_ROLE = keccak256(\"RELAYER_ROLE\");\n bytes32 public constant REFUNDER_ROLE = keccak256(\"REFUNDER_ROLE\");\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n uint256 public constant FEE_BPS = 1e6;\n uint256 public constant FEE_RATE_MAX = 0.01e6; // max 1% on origin amount\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Chain gas amount to forward as rebate if requested\n uint256 public chainGasAmount;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n }\n\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n require(newFeeRate \u003c= FEE_RATE_MAX, \"newFeeRate \u003e max\");\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n token.universalTransfer(recipient, feeAmount);\n emit FeesSwept(token, recipient, feeAmount);\n }\n\n function setChainGasAmount(uint256 newChainGasAmount) external onlyRole(GOVERNOR_ROLE) {\n uint256 oldChainGasAmount = chainGasAmount;\n chainGasAmount = newChainGasAmount;\n emit ChainGasAmountUpdated(oldChainGasAmount, newChainGasAmount);\n }\n}\n\n// contracts/FastBridgeV2.sol\n\n/// @notice FastBridgeV2 is a contract for bridging tokens across chains.\ncontract FastBridgeV2 is Admin, IFastBridgeV2, IFastBridgeV2Errors {\n using SafeERC20 for IERC20;\n using UniversalTokenLib for address;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Delay for a transaction after which it could be permisionlessly refunded\n uint256 public constant REFUND_DELAY = 7 days;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n /// @notice Maximum length of accepted callParams\n uint256 public constant MAX_CALL_PARAMS_LENGTH = 2 ** 16 - 1;\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeTxDetails) public bridgeTxDetails;\n /// @notice Relay details on destination chain\n mapping(bytes32 =\u003e BridgeRelay) public bridgeRelayDetails;\n /// @notice Unique bridge nonces tracked per originSender\n mapping(address =\u003e uint256) public senderNonces;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Replaced by senderNonces\n uint256 public immutable nonce = 0;\n /// @notice the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n bridge({\n params: params,\n paramsV2: BridgeParamsV2({\n quoteRelayer: address(0),\n quoteExclusivitySeconds: 0,\n quoteId: bytes(\"\"),\n callValue: 0,\n callParams: bytes(\"\")\n })\n });\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes memory request) external payable {\n relay({request: request, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes memory request, bytes32 destTxHash) external {\n prove({transactionId: keccak256(request), destTxHash: destTxHash, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridgeV2\n function claim(bytes memory request) external {\n claim({request: request, to: address(0)});\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003e DISPUTE_PERIOD) {\n revert DisputePeriodPassed();\n }\n\n // @dev relayer gets slashed effectively if dest relay has gone thru\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n bridgeTxDetails[transactionId].proofRelayer = address(0);\n bridgeTxDetails[transactionId].proofBlockTimestamp = 0;\n bridgeTxDetails[transactionId].proofBlockNumber = 0;\n\n emit BridgeProofDisputed(transactionId, msg.sender);\n }\n\n /// @inheritdoc IFastBridge\n function refund(bytes memory request) external {\n bytes32 transactionId = keccak256(request);\n\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n\n if (bridgeTxDetails[transactionId].status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n\n if (hasRole(REFUNDER_ROLE, msg.sender)) {\n // Refunder can refund if deadline has passed\n if (block.timestamp \u003c= transaction.deadline) revert DeadlineNotExceeded();\n } else {\n // Permissionless refund is allowed after REFUND_DELAY\n if (block.timestamp \u003c= transaction.deadline + REFUND_DELAY) revert DeadlineNotExceeded();\n }\n\n // if all checks passed, set to REFUNDED status\n bridgeTxDetails[transactionId].status = BridgeStatus.REFUNDED;\n\n // transfer origin collateral back to original sender\n address to = transaction.originSender;\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount + transaction.originFeeAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (bridgeTxDetails[transactionId].proofRelayer != relayer) revert SenderIncorrect();\n return _timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n /// @dev This method is added to achieve backwards compatibility with decoding requests into V1 structs:\n /// - `callValue` is partially reported as a zero/non-zero flag\n /// - `callParams` is ignored\n /// In order to process all kinds of requests use getBridgeTransactionV2 instead.\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory) {\n // Try decoding into V2 struct first. This will revert if V1 struct is passed\n try this.getBridgeTransactionV2(request) returns (BridgeTransactionV2 memory txV2) {\n // Note: we entirely ignore the callParams field, as it was not present in V1\n return BridgeTransaction({\n originChainId: txV2.originChainId,\n destChainId: txV2.destChainId,\n originSender: txV2.originSender,\n destRecipient: txV2.destRecipient,\n originToken: txV2.originToken,\n destToken: txV2.destToken,\n originAmount: txV2.originAmount,\n destAmount: txV2.destAmount,\n originFeeAmount: txV2.originFeeAmount,\n sendChainGas: txV2.callValue != 0,\n deadline: txV2.deadline,\n nonce: txV2.nonce\n });\n } catch {\n // Fallback to V1 struct\n return abi.decode(request, (BridgeTransaction));\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) public payable {\n int256 exclusivityEndTime = int256(block.timestamp) + paramsV2.quoteExclusivitySeconds;\n _validateBridgeParams(params, paramsV2, exclusivityEndTime);\n\n // transfer tokens to bridge contract\n /// @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _pullToken(params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n\n // set status to requested\n bytes memory request = abi.encode(\n BridgeTransactionV2({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n callValue: paramsV2.callValue,\n deadline: params.deadline,\n nonce: senderNonces[params.sender]++, // increment nonce on every bridge\n exclusivityRelayer: paramsV2.quoteRelayer,\n // We checked exclusivityEndTime to be in range (0 .. params.deadline] above, so can safely cast\n exclusivityEndTime: uint256(exclusivityEndTime),\n callParams: paramsV2.callParams\n })\n );\n bytes32 transactionId = keccak256(request);\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n\n emit BridgeRequested({\n transactionId: transactionId,\n sender: params.sender,\n request: request,\n destChainId: params.dstChainId,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n sendChainGas: paramsV2.callValue != 0\n });\n emit BridgeQuoteDetails(transactionId, paramsV2.quoteId);\n }\n\n /// @inheritdoc IFastBridgeV2\n function relay(bytes memory request, address relayer) public payable {\n bytes32 transactionId = keccak256(request);\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n _validateRelayParams(transaction, transactionId, relayer);\n // mark bridge transaction as relayed\n bridgeRelayDetails[transactionId] =\n BridgeRelay({blockNumber: uint48(block.number), blockTimestamp: uint48(block.timestamp), relayer: relayer});\n\n // transfer tokens to recipient on destination chain and do an arbitrary call if requested\n address to = transaction.destRecipient;\n address token = transaction.destToken;\n uint256 amount = transaction.destAmount;\n\n // All state changes have been done at this point, can proceed to the external calls.\n // This follows the checks-effects-interactions pattern to mitigate potential reentrancy attacks.\n if (token == UniversalTokenLib.ETH_ADDRESS) {\n // For ETH non-zero callValue is not allowed\n if (transaction.callValue != 0) revert NativeTokenCallValueNotSupported();\n // Check that the correct msg.value was sent\n if (msg.value != amount) revert MsgValueIncorrect();\n } else {\n // For ERC20s, we check that the correct msg.value was sent\n if (msg.value != transaction.callValue) revert MsgValueIncorrect();\n // We need to transfer the tokens from the Relayer to the recipient first before performing an\n // optional post-transfer arbitrary call.\n IERC20(token).safeTransferFrom(msg.sender, to, amount);\n }\n\n if (transaction.callParams.length != 0) {\n // Arbitrary call requested, perform it while supplying full msg.value to the recipient\n // Note: if token has a fee on transfers, the recipient will have received less than `amount`.\n // This is a very niche edge case and should be handled by the recipient contract.\n _checkedCallRecipient({recipient: to, token: token, amount: amount, callParams: transaction.callParams});\n } else if (msg.value != 0) {\n // No arbitrary call requested, but msg.value was sent. This is either a relay with ETH,\n // or a non-zero callValue request with an ERC20. In both cases, transfer the ETH to the recipient.\n Address.sendValue(payable(to), msg.value);\n }\n\n emit BridgeRelayed({\n transactionId: transactionId,\n relayer: relayer,\n to: to,\n originChainId: transaction.originChainId,\n originToken: transaction.originToken,\n destToken: transaction.destToken,\n originAmount: transaction.originAmount,\n destAmount: transaction.destAmount,\n chainGasAmount: transaction.callValue\n });\n }\n\n /// @inheritdoc IFastBridgeV2\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) public onlyRole(RELAYER_ROLE) {\n // update bridge tx status given proof provided\n if (bridgeTxDetails[transactionId].status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n bridgeTxDetails[transactionId].status = BridgeStatus.RELAYER_PROVED;\n bridgeTxDetails[transactionId].proofBlockTimestamp = uint40(block.timestamp);\n bridgeTxDetails[transactionId].proofBlockNumber = uint48(block.number);\n bridgeTxDetails[transactionId].proofRelayer = relayer;\n\n emit BridgeProofProvided(transactionId, relayer, destTxHash);\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes memory request, address to) public {\n bytes32 transactionId = keccak256(request);\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n\n // update bridge tx status if able to claim origin collateral\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n\n // if \"to\" is zero addr, permissionlessly send funds to proven relayer\n if (to == address(0)) {\n to = bridgeTxDetails[transactionId].proofRelayer;\n } else if (bridgeTxDetails[transactionId].proofRelayer != msg.sender) {\n revert SenderIncorrect();\n }\n\n if (_timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003c= DISPUTE_PERIOD) {\n revert DisputePeriodNotPassed();\n }\n\n bridgeTxDetails[transactionId].status = BridgeStatus.RELAYER_CLAIMED;\n\n // update protocol fees if origin fee amount exists\n if (transaction.originFeeAmount \u003e 0) protocolFees[transaction.originToken] += transaction.originFeeAmount;\n\n // transfer origin collateral less fee to specified address\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositClaimed(transactionId, bridgeTxDetails[transactionId].proofRelayer, to, token, amount);\n }\n\n function bridgeStatuses(bytes32 transactionId) public view returns (BridgeStatus status) {\n return bridgeTxDetails[transactionId].status;\n }\n\n function bridgeProofs(bytes32 transactionId) public view returns (uint96 timestamp, address relayer) {\n timestamp = bridgeTxDetails[transactionId].proofBlockTimestamp;\n relayer = bridgeTxDetails[transactionId].proofRelayer;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeRelays(bytes32 transactionId) public view returns (bool) {\n // has this transactionId been relayed?\n return bridgeRelayDetails[transactionId].relayer != address(0);\n }\n\n /// @inheritdoc IFastBridgeV2\n function getBridgeTransactionV2(bytes memory request) public pure returns (BridgeTransactionV2 memory) {\n return abi.decode(request, (BridgeTransactionV2));\n }\n\n /// @notice Pulls a requested token from the user to this contract.\n function _pullToken(address token, uint256 amount) internal returns (uint256 amountPulled) {\n if (token == UniversalTokenLib.ETH_ADDRESS) {\n // For ETH we just need to check that the supplied msg.value is correct\n if (amount != msg.value) revert MsgValueIncorrect();\n amountPulled = msg.value;\n } else {\n token.assertIsContract();\n // Record token balance before transfer\n amountPulled = IERC20(token).balanceOf(address(this));\n // Token needs to be pulled only if msg.value is zero\n // This way user can specify WETH as the origin asset\n IERC20(token).safeTransferFrom(msg.sender, address(this), amount);\n // Use the difference between the recorded balance and the current balance as the amountPulled\n amountPulled = IERC20(token).balanceOf(address(this)) - amountPulled;\n }\n }\n\n /// @notice Calls the Recipient's hook function with the specified callParams and performs\n /// all the necessary checks for the returned value.\n function _checkedCallRecipient(\n address recipient,\n address token,\n uint256 amount,\n bytes memory callParams\n )\n internal\n {\n bytes memory hookData =\n abi.encodeCall(IFastBridgeRecipient.fastBridgeTransferReceived, (token, amount, callParams));\n // This will bubble any revert messages from the hook function\n bytes memory returnData = Address.functionCallWithValue({target: recipient, data: hookData, value: msg.value});\n // Explicit revert if no return data at all\n if (returnData.length == 0) revert RecipientNoReturnValue();\n // Check that exactly a single return value was returned\n if (returnData.length != 32) revert RecipientIncorrectReturnValue();\n // Return value should be abi-encoded hook function selector\n if (bytes32(returnData) != bytes32(IFastBridgeRecipient.fastBridgeTransferReceived.selector)) {\n revert RecipientIncorrectReturnValue();\n }\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint40(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint40).max but\n /// proof.timestamp \u003c type(uint40).max via unchecked statement\n /// @param proofBlockTimestamp The bridge proof block timestamp\n /// @return delta Time delta since proof submitted\n function _timeSince(uint40 proofBlockTimestamp) internal view returns (uint256 delta) {\n unchecked {\n delta = uint40(block.timestamp) - proofBlockTimestamp;\n }\n }\n\n /// @notice Performs all the necessary checks for a bridge to happen.\n /// @dev There's no good way to refactor this function to reduce cyclomatic complexity due to\n /// the number of checks that need to be performed, so we skip the code-complexity rule here.\n // solhint-disable-next-line code-complexity\n function _validateBridgeParams(\n BridgeParams memory params,\n BridgeParamsV2 memory paramsV2,\n int256 exclusivityEndTime\n )\n internal\n view\n {\n // Check V1 (legacy) params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.sender == address(0) || params.to == address(0)) revert ZeroAddress();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n // Check V2 params\n if (paramsV2.callParams.length \u003e MAX_CALL_PARAMS_LENGTH) revert CallParamsLengthAboveMax();\n if (paramsV2.callValue != 0 \u0026\u0026 params.destToken == UniversalTokenLib.ETH_ADDRESS) {\n revert NativeTokenCallValueNotSupported();\n }\n // exclusivityEndTime must be in range (0 .. params.deadline]\n if (exclusivityEndTime \u003c= 0 || exclusivityEndTime \u003e int256(params.deadline)) {\n revert ExclusivityParamsIncorrect();\n }\n }\n\n /// @notice Performs all the necessary checks for a relay to happen.\n function _validateRelayParams(\n BridgeTransactionV2 memory transaction,\n bytes32 transactionId,\n address relayer\n )\n internal\n view\n {\n if (relayer == address(0)) revert ZeroAddress();\n // Check if the transaction has already been relayed\n if (bridgeRelays(transactionId)) revert TransactionRelayed();\n if (transaction.destChainId != uint32(block.chainid)) revert ChainIncorrect();\n // Check the deadline for relay to happen\n if (block.timestamp \u003e transaction.deadline) revert DeadlineExceeded();\n // Check the exclusivity period, if it is still ongoing\n // forgefmt: disable-next-item\n if (\n transaction.exclusivityRelayer != address(0) \u0026\u0026\n transaction.exclusivityRelayer != relayer \u0026\u0026\n block.timestamp \u003c= transaction.exclusivityEndTime\n ) {\n revert ExclusivityPeriodNotPassed();\n }\n }\n}\n","language":"Solidity","languageVersion":"0.8.24","compilerVersion":"0.8.24","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"","srcMapRuntime":"","abiDefinition":[{"inputs":[],"name":"AmountIncorrect","type":"error"},{"inputs":[],"name":"CallParamsLengthAboveMax","type":"error"},{"inputs":[],"name":"ChainIncorrect","type":"error"},{"inputs":[],"name":"DeadlineExceeded","type":"error"},{"inputs":[],"name":"DeadlineNotExceeded","type":"error"},{"inputs":[],"name":"DeadlineTooShort","type":"error"},{"inputs":[],"name":"DisputePeriodNotPassed","type":"error"},{"inputs":[],"name":"DisputePeriodPassed","type":"error"},{"inputs":[],"name":"ExclusivityParamsIncorrect","type":"error"},{"inputs":[],"name":"ExclusivityPeriodNotPassed","type":"error"},{"inputs":[],"name":"MsgValueIncorrect","type":"error"},{"inputs":[],"name":"NativeTokenCallValueNotSupported","type":"error"},{"inputs":[],"name":"RecipientIncorrectReturnValue","type":"error"},{"inputs":[],"name":"RecipientNoReturnValue","type":"error"},{"inputs":[],"name":"SenderIncorrect","type":"error"},{"inputs":[],"name":"StatusIncorrect","type":"error"},{"inputs":[],"name":"TransactionRelayed","type":"error"},{"inputs":[],"name":"ZeroAddress","type":"error"}],"userDoc":{"kind":"user","methods":{},"version":1},"developerDoc":{"kind":"dev","methods":{},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[],\"name\":\"AmountIncorrect\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"CallParamsLengthAboveMax\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ChainIncorrect\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DeadlineExceeded\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DeadlineNotExceeded\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DeadlineTooShort\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DisputePeriodNotPassed\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DisputePeriodPassed\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ExclusivityParamsIncorrect\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ExclusivityPeriodNotPassed\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"MsgValueIncorrect\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"NativeTokenCallValueNotSupported\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"RecipientIncorrectReturnValue\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"RecipientNoReturnValue\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"SenderIncorrect\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"StatusIncorrect\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"TransactionRelayed\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ZeroAddress\",\"type\":\"error\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeV2.sol\":\"IFastBridgeV2Errors\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeV2.sol\":{\"keccak256\":\"0x7cd0f885e80e2bdaa638bc32ae7af7d2e248f99ce4b354c217d0f0f7d7302e0a\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://7ccf28df0bd7b4606986585acd8622ed9b4e81379690061bb66088f0a2270af1\",\"dweb:/ipfs/QmTf7HNdHZkK6vmx8ZgewycQEb72oLD9nPwBpsM5reMstQ\"]}},\"version\":1}"},"hashes":{}},"solidity/FastBridgeV2.sol:SafeERC20":{"code":"0x60566037600b82828239805160001a607314602a57634e487b7160e01b600052600060045260246000fd5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600080fdfea26469706673582212202e6244574a9418b179bbe1f5d6f1483cf0da887e64158bb04463fae84495de4464736f6c63430008180033","runtime-code":"0x73000000000000000000000000000000000000000030146080604052600080fdfea26469706673582212202e6244574a9418b179bbe1f5d6f1483cf0da887e64158bb04463fae84495de4464736f6c63430008180033","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.24 ^0.8.0 ^0.8.20;\n\n// contracts/interfaces/IAdmin.sol\n\ninterface IAdmin {\n // ============ Events ============\n\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n event ChainGasAmountUpdated(uint256 oldChainGasAmount, uint256 newChainGasAmount);\n\n // ============ Methods ============\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n\n function setChainGasAmount(uint256 newChainGasAmount) external;\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IFastBridgeRecipient.sol\n\ninterface IFastBridgeRecipient {\n function fastBridgeTransferReceived(\n address token,\n uint256 amount,\n bytes memory callParams\n )\n external\n payable\n returns (bytes4);\n}\n\n// contracts/interfaces/IFastBridgeV2Errors.sol\n\ninterface IFastBridgeV2Errors {\n error AmountIncorrect();\n error CallParamsLengthAboveMax();\n error ChainIncorrect();\n error ExclusivityParamsIncorrect();\n error MsgValueIncorrect();\n error NativeTokenCallValueNotSupported();\n error SenderIncorrect();\n error StatusIncorrect();\n error ZeroAddress();\n\n error RecipientIncorrectReturnValue();\n error RecipientNoReturnValue();\n\n error DeadlineExceeded();\n error DeadlineNotExceeded();\n error DeadlineTooShort();\n error DisputePeriodNotPassed();\n error DisputePeriodPassed();\n error ExclusivityPeriodNotPassed();\n\n error TransactionRelayed();\n}\n\n// contracts/libs/Errors.sol\n\nerror DeadlineExceeded();\nerror DeadlineNotExceeded();\nerror DeadlineTooShort();\nerror InsufficientOutputAmount();\n\nerror MsgValueIncorrect();\nerror PoolNotFound();\nerror TokenAddressMismatch();\nerror TokenNotContract();\nerror TokenNotETH();\nerror TokensIdentical();\n\nerror ChainIncorrect();\nerror AmountIncorrect();\nerror ZeroAddress();\n\nerror DisputePeriodNotPassed();\nerror DisputePeriodPassed();\nerror SenderIncorrect();\nerror StatusIncorrect();\nerror TransactionIdIncorrect();\nerror TransactionRelayed();\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// contracts/interfaces/IFastBridgeV2.sol\n\ninterface IFastBridgeV2 is IFastBridge {\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n struct BridgeTxDetails {\n BridgeStatus status;\n uint40 proofBlockTimestamp;\n uint48 proofBlockNumber;\n address proofRelayer;\n }\n\n struct BridgeRelay {\n uint48 blockNumber;\n uint48 blockTimestamp;\n address relayer;\n }\n\n /// @notice New params introduced in the FastBridgeV2.\n /// We are passing fields from the older BridgeParams struct outside of this struct\n /// for backwards compatibility.\n /// Note: quoteRelayer and quoteExclusivitySeconds are either both zero (indicating no exclusivity)\n /// or both non-zero (indicating exclusivity for the given period).\n /// Note: callValue \u003e 0 can NOT be used with destToken = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE (ETH_ADDRESS)\n /// @param quoteRelayer Relayer that provided the quote for the transaction\n /// @param quoteExclusivitySeconds Period of time the quote relayer is guaranteed exclusivity after user's deposit\n /// @param quoteId Unique quote identifier used for tracking the quote\n /// @param callValue ETH value to send to the recipient (if any)\n /// @param callParams Parameters for the arbitrary call to the destination recipient (if any)\n struct BridgeParamsV2 {\n address quoteRelayer;\n int256 quoteExclusivitySeconds;\n bytes quoteId;\n uint256 callValue;\n bytes callParams;\n }\n\n /// @notice Updated bridge transaction struct to include parameters introduced in FastBridgeV2.\n /// Note: only `exclusivityRelayer` can fill such a transaction until `exclusivityEndTime`.\n /// TODO: consider changing the encoding scheme to prevent spending extra gas on decoding.\n struct BridgeTransactionV2 {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n uint256 callValue; // ETH value to send to the recipient (if any) - replaces V1's sendChainGas flag\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n address exclusivityRelayer;\n uint256 exclusivityEndTime;\n bytes callParams;\n }\n\n event BridgeQuoteDetails(bytes32 indexed transactionId, bytes quoteId);\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability\n /// to provide temporary exclusivity fill rights for the quote relayer.\n /// @param params The parameters required to bridge\n /// @param paramsV2 The parameters for exclusivity fill rights (optional, can be left empty)\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function relay(bytes memory request, address relayer) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param transactionId The transaction id associated with the encoded bridge transaction to prove\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital.\n /// @notice Can only send funds to the relayer address on the proof.\n /// @param request The encoded bridge transaction to claim on origin chain\n function claim(bytes memory request) external;\n /// @notice Checks if a transaction has been relayed\n /// @param transactionId The ID of the transaction to check\n /// @return True if the transaction has been relayed, false otherwise\n function bridgeRelays(bytes32 transactionId) external view returns (bool);\n\n /// @notice Returns the status of a bridge transaction\n /// @param transactionId The ID of the bridge transaction\n /// @return BridgeStatus Status of the bridge transaction\n function bridgeStatuses(bytes32 transactionId) external view returns (BridgeStatus);\n\n /// @notice Returns the timestamp and relayer of a bridge proof\n /// @param transactionId The ID of the bridge transaction\n /// @return timestamp The timestamp of the bridge proof\n /// @return relayer The relayer address of the bridge proof\n function bridgeProofs(bytes32 transactionId) external view returns (uint96 timestamp, address relayer);\n\n /// @notice Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\n /// @param request The bridge request to decode\n function getBridgeTransactionV2(bytes memory request) external view returns (BridgeTransactionV2 memory);\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// contracts/libs/UniversalToken.sol\n\nlibrary UniversalTokenLib {\n using SafeERC20 for IERC20;\n\n address internal constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Transfers tokens to the given account. Reverts if transfer is not successful.\n /// @dev This might trigger fallback, if ETH is transferred to the contract.\n /// Make sure this can not lead to reentrancy attacks.\n function universalTransfer(address token, address to, uint256 value) internal {\n // Don't do anything, if need to send tokens to this address\n if (to == address(this)) return;\n // Don't do anything, if trying to send zero value\n if (value == 0) return;\n if (token == ETH_ADDRESS) {\n /// @dev Note: this can potentially lead to executing code in `to`.\n // solhint-disable-next-line avoid-low-level-calls\n (bool success,) = to.call{value: value}(\"\");\n require(success, \"ETH transfer failed\");\n } else {\n IERC20(token).safeTransfer(to, value);\n }\n }\n\n /// @notice Issues an infinite allowance to the spender, if the current allowance is insufficient\n /// to spend the given amount.\n function universalApproveInfinity(address token, address spender, uint256 amountToSpend) internal {\n // ETH Chad doesn't require your approval\n if (token == ETH_ADDRESS) return;\n // No-op if allowance is already sufficient\n uint256 allowance = IERC20(token).allowance(address(this), spender);\n if (allowance \u003e= amountToSpend) return;\n // Otherwise, reset approval to 0 and set to max allowance\n if (allowance \u003e 0) IERC20(token).safeDecreaseAllowance(spender, allowance);\n IERC20(token).safeIncreaseAllowance(spender, type(uint256).max);\n }\n\n /// @notice Returns the balance of the given token (or native ETH) for the given account.\n function universalBalanceOf(address token, address account) internal view returns (uint256) {\n if (token == ETH_ADDRESS) {\n return account.balance;\n } else {\n return IERC20(token).balanceOf(account);\n }\n }\n\n /// @dev Checks that token is a contract and not ETH_ADDRESS.\n function assertIsContract(address token) internal view {\n // Check that ETH_ADDRESS was not used (in case this is a predeploy on any of the chains)\n if (token == UniversalTokenLib.ETH_ADDRESS) revert TokenNotContract();\n // Check that token is not an EOA\n if (token.code.length == 0) revert TokenNotContract();\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/Admin.sol\n\ncontract Admin is IAdmin, AccessControlEnumerable {\n using UniversalTokenLib for address;\n\n bytes32 public constant RELAYER_ROLE = keccak256(\"RELAYER_ROLE\");\n bytes32 public constant REFUNDER_ROLE = keccak256(\"REFUNDER_ROLE\");\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n uint256 public constant FEE_BPS = 1e6;\n uint256 public constant FEE_RATE_MAX = 0.01e6; // max 1% on origin amount\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Chain gas amount to forward as rebate if requested\n uint256 public chainGasAmount;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n }\n\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n require(newFeeRate \u003c= FEE_RATE_MAX, \"newFeeRate \u003e max\");\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n token.universalTransfer(recipient, feeAmount);\n emit FeesSwept(token, recipient, feeAmount);\n }\n\n function setChainGasAmount(uint256 newChainGasAmount) external onlyRole(GOVERNOR_ROLE) {\n uint256 oldChainGasAmount = chainGasAmount;\n chainGasAmount = newChainGasAmount;\n emit ChainGasAmountUpdated(oldChainGasAmount, newChainGasAmount);\n }\n}\n\n// contracts/FastBridgeV2.sol\n\n/// @notice FastBridgeV2 is a contract for bridging tokens across chains.\ncontract FastBridgeV2 is Admin, IFastBridgeV2, IFastBridgeV2Errors {\n using SafeERC20 for IERC20;\n using UniversalTokenLib for address;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Delay for a transaction after which it could be permisionlessly refunded\n uint256 public constant REFUND_DELAY = 7 days;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n /// @notice Maximum length of accepted callParams\n uint256 public constant MAX_CALL_PARAMS_LENGTH = 2 ** 16 - 1;\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeTxDetails) public bridgeTxDetails;\n /// @notice Relay details on destination chain\n mapping(bytes32 =\u003e BridgeRelay) public bridgeRelayDetails;\n /// @notice Unique bridge nonces tracked per originSender\n mapping(address =\u003e uint256) public senderNonces;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Replaced by senderNonces\n uint256 public immutable nonce = 0;\n /// @notice the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n bridge({\n params: params,\n paramsV2: BridgeParamsV2({\n quoteRelayer: address(0),\n quoteExclusivitySeconds: 0,\n quoteId: bytes(\"\"),\n callValue: 0,\n callParams: bytes(\"\")\n })\n });\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes memory request) external payable {\n relay({request: request, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes memory request, bytes32 destTxHash) external {\n prove({transactionId: keccak256(request), destTxHash: destTxHash, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridgeV2\n function claim(bytes memory request) external {\n claim({request: request, to: address(0)});\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003e DISPUTE_PERIOD) {\n revert DisputePeriodPassed();\n }\n\n // @dev relayer gets slashed effectively if dest relay has gone thru\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n bridgeTxDetails[transactionId].proofRelayer = address(0);\n bridgeTxDetails[transactionId].proofBlockTimestamp = 0;\n bridgeTxDetails[transactionId].proofBlockNumber = 0;\n\n emit BridgeProofDisputed(transactionId, msg.sender);\n }\n\n /// @inheritdoc IFastBridge\n function refund(bytes memory request) external {\n bytes32 transactionId = keccak256(request);\n\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n\n if (bridgeTxDetails[transactionId].status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n\n if (hasRole(REFUNDER_ROLE, msg.sender)) {\n // Refunder can refund if deadline has passed\n if (block.timestamp \u003c= transaction.deadline) revert DeadlineNotExceeded();\n } else {\n // Permissionless refund is allowed after REFUND_DELAY\n if (block.timestamp \u003c= transaction.deadline + REFUND_DELAY) revert DeadlineNotExceeded();\n }\n\n // if all checks passed, set to REFUNDED status\n bridgeTxDetails[transactionId].status = BridgeStatus.REFUNDED;\n\n // transfer origin collateral back to original sender\n address to = transaction.originSender;\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount + transaction.originFeeAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (bridgeTxDetails[transactionId].proofRelayer != relayer) revert SenderIncorrect();\n return _timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n /// @dev This method is added to achieve backwards compatibility with decoding requests into V1 structs:\n /// - `callValue` is partially reported as a zero/non-zero flag\n /// - `callParams` is ignored\n /// In order to process all kinds of requests use getBridgeTransactionV2 instead.\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory) {\n // Try decoding into V2 struct first. This will revert if V1 struct is passed\n try this.getBridgeTransactionV2(request) returns (BridgeTransactionV2 memory txV2) {\n // Note: we entirely ignore the callParams field, as it was not present in V1\n return BridgeTransaction({\n originChainId: txV2.originChainId,\n destChainId: txV2.destChainId,\n originSender: txV2.originSender,\n destRecipient: txV2.destRecipient,\n originToken: txV2.originToken,\n destToken: txV2.destToken,\n originAmount: txV2.originAmount,\n destAmount: txV2.destAmount,\n originFeeAmount: txV2.originFeeAmount,\n sendChainGas: txV2.callValue != 0,\n deadline: txV2.deadline,\n nonce: txV2.nonce\n });\n } catch {\n // Fallback to V1 struct\n return abi.decode(request, (BridgeTransaction));\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) public payable {\n int256 exclusivityEndTime = int256(block.timestamp) + paramsV2.quoteExclusivitySeconds;\n _validateBridgeParams(params, paramsV2, exclusivityEndTime);\n\n // transfer tokens to bridge contract\n /// @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _pullToken(params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n\n // set status to requested\n bytes memory request = abi.encode(\n BridgeTransactionV2({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n callValue: paramsV2.callValue,\n deadline: params.deadline,\n nonce: senderNonces[params.sender]++, // increment nonce on every bridge\n exclusivityRelayer: paramsV2.quoteRelayer,\n // We checked exclusivityEndTime to be in range (0 .. params.deadline] above, so can safely cast\n exclusivityEndTime: uint256(exclusivityEndTime),\n callParams: paramsV2.callParams\n })\n );\n bytes32 transactionId = keccak256(request);\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n\n emit BridgeRequested({\n transactionId: transactionId,\n sender: params.sender,\n request: request,\n destChainId: params.dstChainId,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n sendChainGas: paramsV2.callValue != 0\n });\n emit BridgeQuoteDetails(transactionId, paramsV2.quoteId);\n }\n\n /// @inheritdoc IFastBridgeV2\n function relay(bytes memory request, address relayer) public payable {\n bytes32 transactionId = keccak256(request);\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n _validateRelayParams(transaction, transactionId, relayer);\n // mark bridge transaction as relayed\n bridgeRelayDetails[transactionId] =\n BridgeRelay({blockNumber: uint48(block.number), blockTimestamp: uint48(block.timestamp), relayer: relayer});\n\n // transfer tokens to recipient on destination chain and do an arbitrary call if requested\n address to = transaction.destRecipient;\n address token = transaction.destToken;\n uint256 amount = transaction.destAmount;\n\n // All state changes have been done at this point, can proceed to the external calls.\n // This follows the checks-effects-interactions pattern to mitigate potential reentrancy attacks.\n if (token == UniversalTokenLib.ETH_ADDRESS) {\n // For ETH non-zero callValue is not allowed\n if (transaction.callValue != 0) revert NativeTokenCallValueNotSupported();\n // Check that the correct msg.value was sent\n if (msg.value != amount) revert MsgValueIncorrect();\n } else {\n // For ERC20s, we check that the correct msg.value was sent\n if (msg.value != transaction.callValue) revert MsgValueIncorrect();\n // We need to transfer the tokens from the Relayer to the recipient first before performing an\n // optional post-transfer arbitrary call.\n IERC20(token).safeTransferFrom(msg.sender, to, amount);\n }\n\n if (transaction.callParams.length != 0) {\n // Arbitrary call requested, perform it while supplying full msg.value to the recipient\n // Note: if token has a fee on transfers, the recipient will have received less than `amount`.\n // This is a very niche edge case and should be handled by the recipient contract.\n _checkedCallRecipient({recipient: to, token: token, amount: amount, callParams: transaction.callParams});\n } else if (msg.value != 0) {\n // No arbitrary call requested, but msg.value was sent. This is either a relay with ETH,\n // or a non-zero callValue request with an ERC20. In both cases, transfer the ETH to the recipient.\n Address.sendValue(payable(to), msg.value);\n }\n\n emit BridgeRelayed({\n transactionId: transactionId,\n relayer: relayer,\n to: to,\n originChainId: transaction.originChainId,\n originToken: transaction.originToken,\n destToken: transaction.destToken,\n originAmount: transaction.originAmount,\n destAmount: transaction.destAmount,\n chainGasAmount: transaction.callValue\n });\n }\n\n /// @inheritdoc IFastBridgeV2\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) public onlyRole(RELAYER_ROLE) {\n // update bridge tx status given proof provided\n if (bridgeTxDetails[transactionId].status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n bridgeTxDetails[transactionId].status = BridgeStatus.RELAYER_PROVED;\n bridgeTxDetails[transactionId].proofBlockTimestamp = uint40(block.timestamp);\n bridgeTxDetails[transactionId].proofBlockNumber = uint48(block.number);\n bridgeTxDetails[transactionId].proofRelayer = relayer;\n\n emit BridgeProofProvided(transactionId, relayer, destTxHash);\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes memory request, address to) public {\n bytes32 transactionId = keccak256(request);\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n\n // update bridge tx status if able to claim origin collateral\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n\n // if \"to\" is zero addr, permissionlessly send funds to proven relayer\n if (to == address(0)) {\n to = bridgeTxDetails[transactionId].proofRelayer;\n } else if (bridgeTxDetails[transactionId].proofRelayer != msg.sender) {\n revert SenderIncorrect();\n }\n\n if (_timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003c= DISPUTE_PERIOD) {\n revert DisputePeriodNotPassed();\n }\n\n bridgeTxDetails[transactionId].status = BridgeStatus.RELAYER_CLAIMED;\n\n // update protocol fees if origin fee amount exists\n if (transaction.originFeeAmount \u003e 0) protocolFees[transaction.originToken] += transaction.originFeeAmount;\n\n // transfer origin collateral less fee to specified address\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositClaimed(transactionId, bridgeTxDetails[transactionId].proofRelayer, to, token, amount);\n }\n\n function bridgeStatuses(bytes32 transactionId) public view returns (BridgeStatus status) {\n return bridgeTxDetails[transactionId].status;\n }\n\n function bridgeProofs(bytes32 transactionId) public view returns (uint96 timestamp, address relayer) {\n timestamp = bridgeTxDetails[transactionId].proofBlockTimestamp;\n relayer = bridgeTxDetails[transactionId].proofRelayer;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeRelays(bytes32 transactionId) public view returns (bool) {\n // has this transactionId been relayed?\n return bridgeRelayDetails[transactionId].relayer != address(0);\n }\n\n /// @inheritdoc IFastBridgeV2\n function getBridgeTransactionV2(bytes memory request) public pure returns (BridgeTransactionV2 memory) {\n return abi.decode(request, (BridgeTransactionV2));\n }\n\n /// @notice Pulls a requested token from the user to this contract.\n function _pullToken(address token, uint256 amount) internal returns (uint256 amountPulled) {\n if (token == UniversalTokenLib.ETH_ADDRESS) {\n // For ETH we just need to check that the supplied msg.value is correct\n if (amount != msg.value) revert MsgValueIncorrect();\n amountPulled = msg.value;\n } else {\n token.assertIsContract();\n // Record token balance before transfer\n amountPulled = IERC20(token).balanceOf(address(this));\n // Token needs to be pulled only if msg.value is zero\n // This way user can specify WETH as the origin asset\n IERC20(token).safeTransferFrom(msg.sender, address(this), amount);\n // Use the difference between the recorded balance and the current balance as the amountPulled\n amountPulled = IERC20(token).balanceOf(address(this)) - amountPulled;\n }\n }\n\n /// @notice Calls the Recipient's hook function with the specified callParams and performs\n /// all the necessary checks for the returned value.\n function _checkedCallRecipient(\n address recipient,\n address token,\n uint256 amount,\n bytes memory callParams\n )\n internal\n {\n bytes memory hookData =\n abi.encodeCall(IFastBridgeRecipient.fastBridgeTransferReceived, (token, amount, callParams));\n // This will bubble any revert messages from the hook function\n bytes memory returnData = Address.functionCallWithValue({target: recipient, data: hookData, value: msg.value});\n // Explicit revert if no return data at all\n if (returnData.length == 0) revert RecipientNoReturnValue();\n // Check that exactly a single return value was returned\n if (returnData.length != 32) revert RecipientIncorrectReturnValue();\n // Return value should be abi-encoded hook function selector\n if (bytes32(returnData) != bytes32(IFastBridgeRecipient.fastBridgeTransferReceived.selector)) {\n revert RecipientIncorrectReturnValue();\n }\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint40(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint40).max but\n /// proof.timestamp \u003c type(uint40).max via unchecked statement\n /// @param proofBlockTimestamp The bridge proof block timestamp\n /// @return delta Time delta since proof submitted\n function _timeSince(uint40 proofBlockTimestamp) internal view returns (uint256 delta) {\n unchecked {\n delta = uint40(block.timestamp) - proofBlockTimestamp;\n }\n }\n\n /// @notice Performs all the necessary checks for a bridge to happen.\n /// @dev There's no good way to refactor this function to reduce cyclomatic complexity due to\n /// the number of checks that need to be performed, so we skip the code-complexity rule here.\n // solhint-disable-next-line code-complexity\n function _validateBridgeParams(\n BridgeParams memory params,\n BridgeParamsV2 memory paramsV2,\n int256 exclusivityEndTime\n )\n internal\n view\n {\n // Check V1 (legacy) params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.sender == address(0) || params.to == address(0)) revert ZeroAddress();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n // Check V2 params\n if (paramsV2.callParams.length \u003e MAX_CALL_PARAMS_LENGTH) revert CallParamsLengthAboveMax();\n if (paramsV2.callValue != 0 \u0026\u0026 params.destToken == UniversalTokenLib.ETH_ADDRESS) {\n revert NativeTokenCallValueNotSupported();\n }\n // exclusivityEndTime must be in range (0 .. params.deadline]\n if (exclusivityEndTime \u003c= 0 || exclusivityEndTime \u003e int256(params.deadline)) {\n revert ExclusivityParamsIncorrect();\n }\n }\n\n /// @notice Performs all the necessary checks for a relay to happen.\n function _validateRelayParams(\n BridgeTransactionV2 memory transaction,\n bytes32 transactionId,\n address relayer\n )\n internal\n view\n {\n if (relayer == address(0)) revert ZeroAddress();\n // Check if the transaction has already been relayed\n if (bridgeRelays(transactionId)) revert TransactionRelayed();\n if (transaction.destChainId != uint32(block.chainid)) revert ChainIncorrect();\n // Check the deadline for relay to happen\n if (block.timestamp \u003e transaction.deadline) revert DeadlineExceeded();\n // Check the exclusivity period, if it is still ongoing\n // forgefmt: disable-next-item\n if (\n transaction.exclusivityRelayer != address(0) \u0026\u0026\n transaction.exclusivityRelayer != relayer \u0026\u0026\n block.timestamp \u003c= transaction.exclusivityEndTime\n ) {\n revert ExclusivityPeriodNotPassed();\n }\n }\n}\n","language":"Solidity","languageVersion":"0.8.24","compilerVersion":"0.8.24","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"45745:5018:0:-:0;;;;;;;;;;;;;;;-1:-1:-1;;;45745:5018:0;;;;;;;;;;;;;;;;;","srcMapRuntime":"45745:5018:0:-:0;;;;;;;;","abiDefinition":[{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"currentAllowance","type":"uint256"},{"internalType":"uint256","name":"requestedDecrease","type":"uint256"}],"name":"SafeERC20FailedDecreaseAllowance","type":"error"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"SafeERC20FailedOperation","type":"error"}],"userDoc":{"kind":"user","methods":{},"version":1},"developerDoc":{"details":"Wrappers around ERC20 operations that throw on failure (when the token contract returns false). Tokens that return no value (and instead revert or throw on failure) are also supported, non-reverting calls are assumed to be successful. To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract, which allows you to call the safe operations as `token.safeTransfer(...)`, etc.","errors":{"SafeERC20FailedDecreaseAllowance(address,uint256,uint256)":[{"details":"Indicates a failed `decreaseAllowance` request."}],"SafeERC20FailedOperation(address)":[{"details":"An operation with an ERC20 token failed."}]},"kind":"dev","methods":{},"title":"SafeERC20","version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"currentAllowance\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"requestedDecrease\",\"type\":\"uint256\"}],\"name\":\"SafeERC20FailedDecreaseAllowance\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"}],\"name\":\"SafeERC20FailedOperation\",\"type\":\"error\"}],\"devdoc\":{\"details\":\"Wrappers around ERC20 operations that throw on failure (when the token contract returns false). Tokens that return no value (and instead revert or throw on failure) are also supported, non-reverting calls are assumed to be successful. To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract, which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\",\"errors\":{\"SafeERC20FailedDecreaseAllowance(address,uint256,uint256)\":[{\"details\":\"Indicates a failed `decreaseAllowance` request.\"}],\"SafeERC20FailedOperation(address)\":[{\"details\":\"An operation with an ERC20 token failed.\"}]},\"kind\":\"dev\",\"methods\":{},\"title\":\"SafeERC20\",\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeV2.sol\":\"SafeERC20\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeV2.sol\":{\"keccak256\":\"0x7cd0f885e80e2bdaa638bc32ae7af7d2e248f99ce4b354c217d0f0f7d7302e0a\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://7ccf28df0bd7b4606986585acd8622ed9b4e81379690061bb66088f0a2270af1\",\"dweb:/ipfs/QmTf7HNdHZkK6vmx8ZgewycQEb72oLD9nPwBpsM5reMstQ\"]}},\"version\":1}"},"hashes":{}},"solidity/FastBridgeV2.sol:UniversalTokenLib":{"code":"0x60566037600b82828239805160001a607314602a57634e487b7160e01b600052600060045260246000fd5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600080fdfea2646970667358221220f32c0660d6e44933a56619135234122fa7c42eeae2b3df059ed3d1e4d3c16aa264736f6c63430008180033","runtime-code":"0x73000000000000000000000000000000000000000030146080604052600080fdfea2646970667358221220f32c0660d6e44933a56619135234122fa7c42eeae2b3df059ed3d1e4d3c16aa264736f6c63430008180033","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.24 ^0.8.0 ^0.8.20;\n\n// contracts/interfaces/IAdmin.sol\n\ninterface IAdmin {\n // ============ Events ============\n\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n event ChainGasAmountUpdated(uint256 oldChainGasAmount, uint256 newChainGasAmount);\n\n // ============ Methods ============\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n\n function setChainGasAmount(uint256 newChainGasAmount) external;\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IFastBridgeRecipient.sol\n\ninterface IFastBridgeRecipient {\n function fastBridgeTransferReceived(\n address token,\n uint256 amount,\n bytes memory callParams\n )\n external\n payable\n returns (bytes4);\n}\n\n// contracts/interfaces/IFastBridgeV2Errors.sol\n\ninterface IFastBridgeV2Errors {\n error AmountIncorrect();\n error CallParamsLengthAboveMax();\n error ChainIncorrect();\n error ExclusivityParamsIncorrect();\n error MsgValueIncorrect();\n error NativeTokenCallValueNotSupported();\n error SenderIncorrect();\n error StatusIncorrect();\n error ZeroAddress();\n\n error RecipientIncorrectReturnValue();\n error RecipientNoReturnValue();\n\n error DeadlineExceeded();\n error DeadlineNotExceeded();\n error DeadlineTooShort();\n error DisputePeriodNotPassed();\n error DisputePeriodPassed();\n error ExclusivityPeriodNotPassed();\n\n error TransactionRelayed();\n}\n\n// contracts/libs/Errors.sol\n\nerror DeadlineExceeded();\nerror DeadlineNotExceeded();\nerror DeadlineTooShort();\nerror InsufficientOutputAmount();\n\nerror MsgValueIncorrect();\nerror PoolNotFound();\nerror TokenAddressMismatch();\nerror TokenNotContract();\nerror TokenNotETH();\nerror TokensIdentical();\n\nerror ChainIncorrect();\nerror AmountIncorrect();\nerror ZeroAddress();\n\nerror DisputePeriodNotPassed();\nerror DisputePeriodPassed();\nerror SenderIncorrect();\nerror StatusIncorrect();\nerror TransactionIdIncorrect();\nerror TransactionRelayed();\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// contracts/interfaces/IFastBridgeV2.sol\n\ninterface IFastBridgeV2 is IFastBridge {\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n struct BridgeTxDetails {\n BridgeStatus status;\n uint40 proofBlockTimestamp;\n uint48 proofBlockNumber;\n address proofRelayer;\n }\n\n struct BridgeRelay {\n uint48 blockNumber;\n uint48 blockTimestamp;\n address relayer;\n }\n\n /// @notice New params introduced in the FastBridgeV2.\n /// We are passing fields from the older BridgeParams struct outside of this struct\n /// for backwards compatibility.\n /// Note: quoteRelayer and quoteExclusivitySeconds are either both zero (indicating no exclusivity)\n /// or both non-zero (indicating exclusivity for the given period).\n /// Note: callValue \u003e 0 can NOT be used with destToken = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE (ETH_ADDRESS)\n /// @param quoteRelayer Relayer that provided the quote for the transaction\n /// @param quoteExclusivitySeconds Period of time the quote relayer is guaranteed exclusivity after user's deposit\n /// @param quoteId Unique quote identifier used for tracking the quote\n /// @param callValue ETH value to send to the recipient (if any)\n /// @param callParams Parameters for the arbitrary call to the destination recipient (if any)\n struct BridgeParamsV2 {\n address quoteRelayer;\n int256 quoteExclusivitySeconds;\n bytes quoteId;\n uint256 callValue;\n bytes callParams;\n }\n\n /// @notice Updated bridge transaction struct to include parameters introduced in FastBridgeV2.\n /// Note: only `exclusivityRelayer` can fill such a transaction until `exclusivityEndTime`.\n /// TODO: consider changing the encoding scheme to prevent spending extra gas on decoding.\n struct BridgeTransactionV2 {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n uint256 callValue; // ETH value to send to the recipient (if any) - replaces V1's sendChainGas flag\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n address exclusivityRelayer;\n uint256 exclusivityEndTime;\n bytes callParams;\n }\n\n event BridgeQuoteDetails(bytes32 indexed transactionId, bytes quoteId);\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability\n /// to provide temporary exclusivity fill rights for the quote relayer.\n /// @param params The parameters required to bridge\n /// @param paramsV2 The parameters for exclusivity fill rights (optional, can be left empty)\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function relay(bytes memory request, address relayer) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param transactionId The transaction id associated with the encoded bridge transaction to prove\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital.\n /// @notice Can only send funds to the relayer address on the proof.\n /// @param request The encoded bridge transaction to claim on origin chain\n function claim(bytes memory request) external;\n /// @notice Checks if a transaction has been relayed\n /// @param transactionId The ID of the transaction to check\n /// @return True if the transaction has been relayed, false otherwise\n function bridgeRelays(bytes32 transactionId) external view returns (bool);\n\n /// @notice Returns the status of a bridge transaction\n /// @param transactionId The ID of the bridge transaction\n /// @return BridgeStatus Status of the bridge transaction\n function bridgeStatuses(bytes32 transactionId) external view returns (BridgeStatus);\n\n /// @notice Returns the timestamp and relayer of a bridge proof\n /// @param transactionId The ID of the bridge transaction\n /// @return timestamp The timestamp of the bridge proof\n /// @return relayer The relayer address of the bridge proof\n function bridgeProofs(bytes32 transactionId) external view returns (uint96 timestamp, address relayer);\n\n /// @notice Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\n /// @param request The bridge request to decode\n function getBridgeTransactionV2(bytes memory request) external view returns (BridgeTransactionV2 memory);\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// contracts/libs/UniversalToken.sol\n\nlibrary UniversalTokenLib {\n using SafeERC20 for IERC20;\n\n address internal constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Transfers tokens to the given account. Reverts if transfer is not successful.\n /// @dev This might trigger fallback, if ETH is transferred to the contract.\n /// Make sure this can not lead to reentrancy attacks.\n function universalTransfer(address token, address to, uint256 value) internal {\n // Don't do anything, if need to send tokens to this address\n if (to == address(this)) return;\n // Don't do anything, if trying to send zero value\n if (value == 0) return;\n if (token == ETH_ADDRESS) {\n /// @dev Note: this can potentially lead to executing code in `to`.\n // solhint-disable-next-line avoid-low-level-calls\n (bool success,) = to.call{value: value}(\"\");\n require(success, \"ETH transfer failed\");\n } else {\n IERC20(token).safeTransfer(to, value);\n }\n }\n\n /// @notice Issues an infinite allowance to the spender, if the current allowance is insufficient\n /// to spend the given amount.\n function universalApproveInfinity(address token, address spender, uint256 amountToSpend) internal {\n // ETH Chad doesn't require your approval\n if (token == ETH_ADDRESS) return;\n // No-op if allowance is already sufficient\n uint256 allowance = IERC20(token).allowance(address(this), spender);\n if (allowance \u003e= amountToSpend) return;\n // Otherwise, reset approval to 0 and set to max allowance\n if (allowance \u003e 0) IERC20(token).safeDecreaseAllowance(spender, allowance);\n IERC20(token).safeIncreaseAllowance(spender, type(uint256).max);\n }\n\n /// @notice Returns the balance of the given token (or native ETH) for the given account.\n function universalBalanceOf(address token, address account) internal view returns (uint256) {\n if (token == ETH_ADDRESS) {\n return account.balance;\n } else {\n return IERC20(token).balanceOf(account);\n }\n }\n\n /// @dev Checks that token is a contract and not ETH_ADDRESS.\n function assertIsContract(address token) internal view {\n // Check that ETH_ADDRESS was not used (in case this is a predeploy on any of the chains)\n if (token == UniversalTokenLib.ETH_ADDRESS) revert TokenNotContract();\n // Check that token is not an EOA\n if (token.code.length == 0) revert TokenNotContract();\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/Admin.sol\n\ncontract Admin is IAdmin, AccessControlEnumerable {\n using UniversalTokenLib for address;\n\n bytes32 public constant RELAYER_ROLE = keccak256(\"RELAYER_ROLE\");\n bytes32 public constant REFUNDER_ROLE = keccak256(\"REFUNDER_ROLE\");\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n uint256 public constant FEE_BPS = 1e6;\n uint256 public constant FEE_RATE_MAX = 0.01e6; // max 1% on origin amount\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Chain gas amount to forward as rebate if requested\n uint256 public chainGasAmount;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n }\n\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n require(newFeeRate \u003c= FEE_RATE_MAX, \"newFeeRate \u003e max\");\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n token.universalTransfer(recipient, feeAmount);\n emit FeesSwept(token, recipient, feeAmount);\n }\n\n function setChainGasAmount(uint256 newChainGasAmount) external onlyRole(GOVERNOR_ROLE) {\n uint256 oldChainGasAmount = chainGasAmount;\n chainGasAmount = newChainGasAmount;\n emit ChainGasAmountUpdated(oldChainGasAmount, newChainGasAmount);\n }\n}\n\n// contracts/FastBridgeV2.sol\n\n/// @notice FastBridgeV2 is a contract for bridging tokens across chains.\ncontract FastBridgeV2 is Admin, IFastBridgeV2, IFastBridgeV2Errors {\n using SafeERC20 for IERC20;\n using UniversalTokenLib for address;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Delay for a transaction after which it could be permisionlessly refunded\n uint256 public constant REFUND_DELAY = 7 days;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n /// @notice Maximum length of accepted callParams\n uint256 public constant MAX_CALL_PARAMS_LENGTH = 2 ** 16 - 1;\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeTxDetails) public bridgeTxDetails;\n /// @notice Relay details on destination chain\n mapping(bytes32 =\u003e BridgeRelay) public bridgeRelayDetails;\n /// @notice Unique bridge nonces tracked per originSender\n mapping(address =\u003e uint256) public senderNonces;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Replaced by senderNonces\n uint256 public immutable nonce = 0;\n /// @notice the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n bridge({\n params: params,\n paramsV2: BridgeParamsV2({\n quoteRelayer: address(0),\n quoteExclusivitySeconds: 0,\n quoteId: bytes(\"\"),\n callValue: 0,\n callParams: bytes(\"\")\n })\n });\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes memory request) external payable {\n relay({request: request, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes memory request, bytes32 destTxHash) external {\n prove({transactionId: keccak256(request), destTxHash: destTxHash, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridgeV2\n function claim(bytes memory request) external {\n claim({request: request, to: address(0)});\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003e DISPUTE_PERIOD) {\n revert DisputePeriodPassed();\n }\n\n // @dev relayer gets slashed effectively if dest relay has gone thru\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n bridgeTxDetails[transactionId].proofRelayer = address(0);\n bridgeTxDetails[transactionId].proofBlockTimestamp = 0;\n bridgeTxDetails[transactionId].proofBlockNumber = 0;\n\n emit BridgeProofDisputed(transactionId, msg.sender);\n }\n\n /// @inheritdoc IFastBridge\n function refund(bytes memory request) external {\n bytes32 transactionId = keccak256(request);\n\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n\n if (bridgeTxDetails[transactionId].status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n\n if (hasRole(REFUNDER_ROLE, msg.sender)) {\n // Refunder can refund if deadline has passed\n if (block.timestamp \u003c= transaction.deadline) revert DeadlineNotExceeded();\n } else {\n // Permissionless refund is allowed after REFUND_DELAY\n if (block.timestamp \u003c= transaction.deadline + REFUND_DELAY) revert DeadlineNotExceeded();\n }\n\n // if all checks passed, set to REFUNDED status\n bridgeTxDetails[transactionId].status = BridgeStatus.REFUNDED;\n\n // transfer origin collateral back to original sender\n address to = transaction.originSender;\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount + transaction.originFeeAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (bridgeTxDetails[transactionId].proofRelayer != relayer) revert SenderIncorrect();\n return _timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n /// @dev This method is added to achieve backwards compatibility with decoding requests into V1 structs:\n /// - `callValue` is partially reported as a zero/non-zero flag\n /// - `callParams` is ignored\n /// In order to process all kinds of requests use getBridgeTransactionV2 instead.\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory) {\n // Try decoding into V2 struct first. This will revert if V1 struct is passed\n try this.getBridgeTransactionV2(request) returns (BridgeTransactionV2 memory txV2) {\n // Note: we entirely ignore the callParams field, as it was not present in V1\n return BridgeTransaction({\n originChainId: txV2.originChainId,\n destChainId: txV2.destChainId,\n originSender: txV2.originSender,\n destRecipient: txV2.destRecipient,\n originToken: txV2.originToken,\n destToken: txV2.destToken,\n originAmount: txV2.originAmount,\n destAmount: txV2.destAmount,\n originFeeAmount: txV2.originFeeAmount,\n sendChainGas: txV2.callValue != 0,\n deadline: txV2.deadline,\n nonce: txV2.nonce\n });\n } catch {\n // Fallback to V1 struct\n return abi.decode(request, (BridgeTransaction));\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) public payable {\n int256 exclusivityEndTime = int256(block.timestamp) + paramsV2.quoteExclusivitySeconds;\n _validateBridgeParams(params, paramsV2, exclusivityEndTime);\n\n // transfer tokens to bridge contract\n /// @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _pullToken(params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n\n // set status to requested\n bytes memory request = abi.encode(\n BridgeTransactionV2({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n callValue: paramsV2.callValue,\n deadline: params.deadline,\n nonce: senderNonces[params.sender]++, // increment nonce on every bridge\n exclusivityRelayer: paramsV2.quoteRelayer,\n // We checked exclusivityEndTime to be in range (0 .. params.deadline] above, so can safely cast\n exclusivityEndTime: uint256(exclusivityEndTime),\n callParams: paramsV2.callParams\n })\n );\n bytes32 transactionId = keccak256(request);\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n\n emit BridgeRequested({\n transactionId: transactionId,\n sender: params.sender,\n request: request,\n destChainId: params.dstChainId,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n sendChainGas: paramsV2.callValue != 0\n });\n emit BridgeQuoteDetails(transactionId, paramsV2.quoteId);\n }\n\n /// @inheritdoc IFastBridgeV2\n function relay(bytes memory request, address relayer) public payable {\n bytes32 transactionId = keccak256(request);\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n _validateRelayParams(transaction, transactionId, relayer);\n // mark bridge transaction as relayed\n bridgeRelayDetails[transactionId] =\n BridgeRelay({blockNumber: uint48(block.number), blockTimestamp: uint48(block.timestamp), relayer: relayer});\n\n // transfer tokens to recipient on destination chain and do an arbitrary call if requested\n address to = transaction.destRecipient;\n address token = transaction.destToken;\n uint256 amount = transaction.destAmount;\n\n // All state changes have been done at this point, can proceed to the external calls.\n // This follows the checks-effects-interactions pattern to mitigate potential reentrancy attacks.\n if (token == UniversalTokenLib.ETH_ADDRESS) {\n // For ETH non-zero callValue is not allowed\n if (transaction.callValue != 0) revert NativeTokenCallValueNotSupported();\n // Check that the correct msg.value was sent\n if (msg.value != amount) revert MsgValueIncorrect();\n } else {\n // For ERC20s, we check that the correct msg.value was sent\n if (msg.value != transaction.callValue) revert MsgValueIncorrect();\n // We need to transfer the tokens from the Relayer to the recipient first before performing an\n // optional post-transfer arbitrary call.\n IERC20(token).safeTransferFrom(msg.sender, to, amount);\n }\n\n if (transaction.callParams.length != 0) {\n // Arbitrary call requested, perform it while supplying full msg.value to the recipient\n // Note: if token has a fee on transfers, the recipient will have received less than `amount`.\n // This is a very niche edge case and should be handled by the recipient contract.\n _checkedCallRecipient({recipient: to, token: token, amount: amount, callParams: transaction.callParams});\n } else if (msg.value != 0) {\n // No arbitrary call requested, but msg.value was sent. This is either a relay with ETH,\n // or a non-zero callValue request with an ERC20. In both cases, transfer the ETH to the recipient.\n Address.sendValue(payable(to), msg.value);\n }\n\n emit BridgeRelayed({\n transactionId: transactionId,\n relayer: relayer,\n to: to,\n originChainId: transaction.originChainId,\n originToken: transaction.originToken,\n destToken: transaction.destToken,\n originAmount: transaction.originAmount,\n destAmount: transaction.destAmount,\n chainGasAmount: transaction.callValue\n });\n }\n\n /// @inheritdoc IFastBridgeV2\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) public onlyRole(RELAYER_ROLE) {\n // update bridge tx status given proof provided\n if (bridgeTxDetails[transactionId].status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n bridgeTxDetails[transactionId].status = BridgeStatus.RELAYER_PROVED;\n bridgeTxDetails[transactionId].proofBlockTimestamp = uint40(block.timestamp);\n bridgeTxDetails[transactionId].proofBlockNumber = uint48(block.number);\n bridgeTxDetails[transactionId].proofRelayer = relayer;\n\n emit BridgeProofProvided(transactionId, relayer, destTxHash);\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes memory request, address to) public {\n bytes32 transactionId = keccak256(request);\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n\n // update bridge tx status if able to claim origin collateral\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n\n // if \"to\" is zero addr, permissionlessly send funds to proven relayer\n if (to == address(0)) {\n to = bridgeTxDetails[transactionId].proofRelayer;\n } else if (bridgeTxDetails[transactionId].proofRelayer != msg.sender) {\n revert SenderIncorrect();\n }\n\n if (_timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003c= DISPUTE_PERIOD) {\n revert DisputePeriodNotPassed();\n }\n\n bridgeTxDetails[transactionId].status = BridgeStatus.RELAYER_CLAIMED;\n\n // update protocol fees if origin fee amount exists\n if (transaction.originFeeAmount \u003e 0) protocolFees[transaction.originToken] += transaction.originFeeAmount;\n\n // transfer origin collateral less fee to specified address\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositClaimed(transactionId, bridgeTxDetails[transactionId].proofRelayer, to, token, amount);\n }\n\n function bridgeStatuses(bytes32 transactionId) public view returns (BridgeStatus status) {\n return bridgeTxDetails[transactionId].status;\n }\n\n function bridgeProofs(bytes32 transactionId) public view returns (uint96 timestamp, address relayer) {\n timestamp = bridgeTxDetails[transactionId].proofBlockTimestamp;\n relayer = bridgeTxDetails[transactionId].proofRelayer;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeRelays(bytes32 transactionId) public view returns (bool) {\n // has this transactionId been relayed?\n return bridgeRelayDetails[transactionId].relayer != address(0);\n }\n\n /// @inheritdoc IFastBridgeV2\n function getBridgeTransactionV2(bytes memory request) public pure returns (BridgeTransactionV2 memory) {\n return abi.decode(request, (BridgeTransactionV2));\n }\n\n /// @notice Pulls a requested token from the user to this contract.\n function _pullToken(address token, uint256 amount) internal returns (uint256 amountPulled) {\n if (token == UniversalTokenLib.ETH_ADDRESS) {\n // For ETH we just need to check that the supplied msg.value is correct\n if (amount != msg.value) revert MsgValueIncorrect();\n amountPulled = msg.value;\n } else {\n token.assertIsContract();\n // Record token balance before transfer\n amountPulled = IERC20(token).balanceOf(address(this));\n // Token needs to be pulled only if msg.value is zero\n // This way user can specify WETH as the origin asset\n IERC20(token).safeTransferFrom(msg.sender, address(this), amount);\n // Use the difference between the recorded balance and the current balance as the amountPulled\n amountPulled = IERC20(token).balanceOf(address(this)) - amountPulled;\n }\n }\n\n /// @notice Calls the Recipient's hook function with the specified callParams and performs\n /// all the necessary checks for the returned value.\n function _checkedCallRecipient(\n address recipient,\n address token,\n uint256 amount,\n bytes memory callParams\n )\n internal\n {\n bytes memory hookData =\n abi.encodeCall(IFastBridgeRecipient.fastBridgeTransferReceived, (token, amount, callParams));\n // This will bubble any revert messages from the hook function\n bytes memory returnData = Address.functionCallWithValue({target: recipient, data: hookData, value: msg.value});\n // Explicit revert if no return data at all\n if (returnData.length == 0) revert RecipientNoReturnValue();\n // Check that exactly a single return value was returned\n if (returnData.length != 32) revert RecipientIncorrectReturnValue();\n // Return value should be abi-encoded hook function selector\n if (bytes32(returnData) != bytes32(IFastBridgeRecipient.fastBridgeTransferReceived.selector)) {\n revert RecipientIncorrectReturnValue();\n }\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint40(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint40).max but\n /// proof.timestamp \u003c type(uint40).max via unchecked statement\n /// @param proofBlockTimestamp The bridge proof block timestamp\n /// @return delta Time delta since proof submitted\n function _timeSince(uint40 proofBlockTimestamp) internal view returns (uint256 delta) {\n unchecked {\n delta = uint40(block.timestamp) - proofBlockTimestamp;\n }\n }\n\n /// @notice Performs all the necessary checks for a bridge to happen.\n /// @dev There's no good way to refactor this function to reduce cyclomatic complexity due to\n /// the number of checks that need to be performed, so we skip the code-complexity rule here.\n // solhint-disable-next-line code-complexity\n function _validateBridgeParams(\n BridgeParams memory params,\n BridgeParamsV2 memory paramsV2,\n int256 exclusivityEndTime\n )\n internal\n view\n {\n // Check V1 (legacy) params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.sender == address(0) || params.to == address(0)) revert ZeroAddress();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n // Check V2 params\n if (paramsV2.callParams.length \u003e MAX_CALL_PARAMS_LENGTH) revert CallParamsLengthAboveMax();\n if (paramsV2.callValue != 0 \u0026\u0026 params.destToken == UniversalTokenLib.ETH_ADDRESS) {\n revert NativeTokenCallValueNotSupported();\n }\n // exclusivityEndTime must be in range (0 .. params.deadline]\n if (exclusivityEndTime \u003c= 0 || exclusivityEndTime \u003e int256(params.deadline)) {\n revert ExclusivityParamsIncorrect();\n }\n }\n\n /// @notice Performs all the necessary checks for a relay to happen.\n function _validateRelayParams(\n BridgeTransactionV2 memory transaction,\n bytes32 transactionId,\n address relayer\n )\n internal\n view\n {\n if (relayer == address(0)) revert ZeroAddress();\n // Check if the transaction has already been relayed\n if (bridgeRelays(transactionId)) revert TransactionRelayed();\n if (transaction.destChainId != uint32(block.chainid)) revert ChainIncorrect();\n // Check the deadline for relay to happen\n if (block.timestamp \u003e transaction.deadline) revert DeadlineExceeded();\n // Check the exclusivity period, if it is still ongoing\n // forgefmt: disable-next-item\n if (\n transaction.exclusivityRelayer != address(0) \u0026\u0026\n transaction.exclusivityRelayer != relayer \u0026\u0026\n block.timestamp \u003c= transaction.exclusivityEndTime\n ) {\n revert ExclusivityPeriodNotPassed();\n }\n }\n}\n","language":"Solidity","languageVersion":"0.8.24","compilerVersion":"0.8.24","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"57704:2551:0:-:0;;;;;;;;;;;;;;;-1:-1:-1;;;57704:2551:0;;;;;;;;;;;;;;;;;","srcMapRuntime":"57704:2551:0:-:0;;;;;;;;","abiDefinition":[],"userDoc":{"kind":"user","methods":{},"version":1},"developerDoc":{"kind":"dev","methods":{},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[],\"devdoc\":{\"kind\":\"dev\",\"methods\":{},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeV2.sol\":\"UniversalTokenLib\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeV2.sol\":{\"keccak256\":\"0x7cd0f885e80e2bdaa638bc32ae7af7d2e248f99ce4b354c217d0f0f7d7302e0a\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://7ccf28df0bd7b4606986585acd8622ed9b4e81379690061bb66088f0a2270af1\",\"dweb:/ipfs/QmTf7HNdHZkK6vmx8ZgewycQEb72oLD9nPwBpsM5reMstQ\"]}},\"version\":1}"},"hashes":{}}} \ No newline at end of file diff --git a/services/rfq/contracts/fastbridgev2/generate.go b/services/rfq/contracts/fastbridgev2/generate.go index 6f9caefe60..752d9897fe 100644 --- a/services/rfq/contracts/fastbridgev2/generate.go +++ b/services/rfq/contracts/fastbridgev2/generate.go @@ -1,3 +1,3 @@ package fastbridgev2 -//go:generate go run github.com/synapsecns/sanguine/tools/abigen generate --sol ../../../../packages/contracts-rfq/flattened/FastBridgeV2.sol --pkg fastbridgev2 --sol-version 0.8.20 --filename fastbridgev2 --evm-version istanbul +//go:generate go run github.com/synapsecns/sanguine/tools/abigen generate --sol ../../../../packages/contracts-rfq/flattened/FastBridgeV2.sol --pkg fastbridgev2 --sol-version 0.8.24 --filename fastbridgev2 --evm-version istanbul From 93d9b7dc3b965d86db8ba6f5e8458db77cb74175 Mon Sep 17 00:00:00 2001 From: Daniel Wasserman Date: Tue, 8 Oct 2024 14:54:10 -0500 Subject: [PATCH 20/85] Fix: bridge enum test --- .../fastbridgev2/bridgestatus_string.go | 27 ++++++++++ .../rfq/contracts/fastbridgev2/export_test.go | 6 +++ services/rfq/contracts/fastbridgev2/status.go | 39 +++++++++++++++ .../rfq/contracts/fastbridgev2/status_test.go | 49 +++++++++++++++++++ 4 files changed, 121 insertions(+) create mode 100644 services/rfq/contracts/fastbridgev2/bridgestatus_string.go create mode 100644 services/rfq/contracts/fastbridgev2/export_test.go create mode 100644 services/rfq/contracts/fastbridgev2/status.go create mode 100644 services/rfq/contracts/fastbridgev2/status_test.go diff --git a/services/rfq/contracts/fastbridgev2/bridgestatus_string.go b/services/rfq/contracts/fastbridgev2/bridgestatus_string.go new file mode 100644 index 0000000000..252653b386 --- /dev/null +++ b/services/rfq/contracts/fastbridgev2/bridgestatus_string.go @@ -0,0 +1,27 @@ +// Code generated by "stringer -type=BridgeStatus -linecomment"; DO NOT EDIT. + +package fastbridgev2 + +import "strconv" + +func _() { + // An "invalid array index" compiler error signifies that the constant values have changed. + // Re-run the stringer command to generate them again. + var x [1]struct{} + _ = x[NULL-0] + _ = x[REQUESTED-1] + _ = x[RelayerProved-2] + _ = x[RelayerClaimed-3] + _ = x[REFUNDED-4] +} + +const _BridgeStatus_name = "NULLREQUESTEDRELAYER_PROVEDRELAYER_CLAIMEDREFUNDED" + +var _BridgeStatus_index = [...]uint8{0, 4, 13, 27, 42, 50} + +func (i BridgeStatus) String() string { + if i >= BridgeStatus(len(_BridgeStatus_index)-1) { + return "BridgeStatus(" + strconv.FormatInt(int64(i), 10) + ")" + } + return _BridgeStatus_name[_BridgeStatus_index[i]:_BridgeStatus_index[i+1]] +} diff --git a/services/rfq/contracts/fastbridgev2/export_test.go b/services/rfq/contracts/fastbridgev2/export_test.go new file mode 100644 index 0000000000..7502b676d6 --- /dev/null +++ b/services/rfq/contracts/fastbridgev2/export_test.go @@ -0,0 +1,6 @@ +package fastbridgev2 + +// GetAllBridgeStatuses exports all bridge statuses for testing. +func GetAllBridgeStatuses() []BridgeStatus { + return allBridgeStatuses +} diff --git a/services/rfq/contracts/fastbridgev2/status.go b/services/rfq/contracts/fastbridgev2/status.go new file mode 100644 index 0000000000..fa285fb77d --- /dev/null +++ b/services/rfq/contracts/fastbridgev2/status.go @@ -0,0 +1,39 @@ +package fastbridgev2 + +// BridgeStatus is an enum for the on-chain status of a request +// +//go:generate go run golang.org/x/tools/cmd/stringer -type=BridgeStatus -linecomment +type BridgeStatus uint8 + +// DO NOT USE IOTA! These are meant to reflect on chain statuses. +const ( + // NULL is the default value for a bridge status. + NULL BridgeStatus = 0 // NULL + // REQUESTED is the status for a request that has been made. + REQUESTED BridgeStatus = 1 // REQUESTED + // RelayerProved is the status for a request that has been proved by a relayer. + RelayerProved BridgeStatus = 2 // RELAYER_PROVED + // RelayerClaimed is the status for a request that has been claimed by a relayer. + RelayerClaimed BridgeStatus = 3 // RELAYER_CLAIMED + // REFUNDED is the status for a request that has been refunded. + REFUNDED BridgeStatus = 4 // REFUNDED +) + +// Int returns the int value of the bridge status. +func (b BridgeStatus) Int() uint8 { + return uint8(b) +} + +// set all contact types. +func init() { + for i := 0; i < len(_BridgeStatus_index)-1; i++ { + contractType := BridgeStatus(i) + allBridgeStatuses = append(allBridgeStatuses, contractType) + // assert type is correct + } +} + +// allBridgeStatuses is a list of all bridge statuses Since we use stringer and this is a testing library, instead +// // of manually copying all these out we pull the names out of stringer. In order to make sure stringer is updated, we panic on +// // any method called where the index is higher than the stringer array length. +var allBridgeStatuses []BridgeStatus diff --git a/services/rfq/contracts/fastbridgev2/status_test.go b/services/rfq/contracts/fastbridgev2/status_test.go new file mode 100644 index 0000000000..038f85717e --- /dev/null +++ b/services/rfq/contracts/fastbridgev2/status_test.go @@ -0,0 +1,49 @@ +package fastbridgev2_test + +import ( + "math/big" + "testing" + + "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/stretchr/testify/suite" + "github.com/synapsecns/sanguine/core/testsuite" + "github.com/synapsecns/sanguine/ethergo/backends" + "github.com/synapsecns/sanguine/ethergo/backends/simulated" + "github.com/synapsecns/sanguine/services/rfq/contracts/fastbridgev2" + "github.com/synapsecns/sanguine/services/rfq/testutil" +) + +// FastBridgeSuite tests the basic test suite. +type FastBridgeSuite struct { + *testsuite.TestSuite + backend backends.SimulatedTestBackend + manager *testutil.DeployManager +} + +// NewFastBridgeSuite creates a new FastBridge suite. +func NewFastBridgeSuite(tb testing.TB) *FastBridgeSuite { + tb.Helper() + return &FastBridgeSuite{ + TestSuite: testsuite.NewTestSuite(tb), + } +} + +func TestFastBridgeSuite(t *testing.T) { + suite.Run(t, NewFastBridgeSuite(t)) +} + +func (s *FastBridgeSuite) SetupTest() { + s.TestSuite.SetupTest() + s.backend = simulated.NewSimulatedBackendWithChainID(s.GetTestContext(), s.T(), big.NewInt(1)) + s.manager = testutil.NewDeployManager(s.T()) +} + +// TestStatusEnum makes sure. +func (s *FastBridgeSuite) TestStatusEnum() { + _, fb := s.manager.GetMockFastBridge(s.GetTestContext(), s.backend) + for _, status := range fastbridgev2.GetAllBridgeStatuses() { + solstatus, err := fb.GetEnumKeyByValue(&bind.CallOpts{Context: s.GetTestContext()}, status.Int()) + s.Require().NoError(err, "error getting enum key by value") + s.Require().Equal(solstatus, status.String(), "status %s does not match. BridgeStatus enums out of sync.", status) + } +} From e34a08b65ae95a46c3858fb11b1c3fabace36699 Mon Sep 17 00:00:00 2001 From: Daniel Wasserman Date: Tue, 8 Oct 2024 15:09:41 -0500 Subject: [PATCH 21/85] Feat: relayer integrates fastbridgev2 --- services/rfq/relayer/chain/chain.go | 2 +- services/rfq/relayer/reldb/base/model.go | 49 +++++++++++++------- services/rfq/relayer/reldb/db.go | 4 +- services/rfq/relayer/service/chainindexer.go | 16 +++---- services/rfq/relayer/service/handlers.go | 26 +++++------ services/rfq/relayer/service/relayer.go | 4 +- services/rfq/relayer/service/suite_test.go | 14 +++--- 7 files changed, 65 insertions(+), 50 deletions(-) diff --git a/services/rfq/relayer/chain/chain.go b/services/rfq/relayer/chain/chain.go index 43a14b0d0b..7f29843ad2 100644 --- a/services/rfq/relayer/chain/chain.go +++ b/services/rfq/relayer/chain/chain.go @@ -77,7 +77,7 @@ func (c Chain) SubmitRelay(ctx context.Context, request reldb.QuoteRequest) (uin // Check to see if ETH should be sent to destination if util.IsGasToken(request.Transaction.DestToken) { gasAmount = request.Transaction.DestAmount - } else if request.Transaction.SendChainGas { + } else if request.Transaction.CallValue != nil && request.Transaction.CallValue.Sign() > 0 { gasAmount, err = c.Bridge.ChainGasAmount(&bind.CallOpts{Context: ctx}) if err != nil { return 0, nil, fmt.Errorf("could not get chain gas amount: %w", err) diff --git a/services/rfq/relayer/reldb/base/model.go b/services/rfq/relayer/reldb/base/model.go index c25681fc36..c61db88385 100644 --- a/services/rfq/relayer/reldb/base/model.go +++ b/services/rfq/relayer/reldb/base/model.go @@ -12,7 +12,7 @@ import ( "github.com/ethereum/go-ethereum/common/hexutil" "github.com/shopspring/decimal" "github.com/synapsecns/sanguine/core/dbcommon" - "github.com/synapsecns/sanguine/services/rfq/contracts/fastbridge" + "github.com/synapsecns/sanguine/services/rfq/contracts/fastbridgev2" "github.com/synapsecns/sanguine/services/rfq/relayer/reldb" ) @@ -76,6 +76,10 @@ type RequestForQuote struct { DestAmountOriginal string // DestAmountOriginal is the original destination amount DestAmount decimal.Decimal `gorm:"index"` + // OriginFeeAmount is the origin fee amount + OriginFeeAmount decimal.Decimal + // CallValue is the call value + CallValue decimal.Decimal // DestTxHash is the destination tx hash DestTxHash sql.NullString // Deadline is the deadline for the relay @@ -83,14 +87,18 @@ type RequestForQuote struct { // OriginNonce is the nonce on the origin chain in the app. // this is not effected by the message.sender nonce. OriginNonce int `gorm:"index"` + // ExclusivityRelayer is the exclusivity relayer + ExclusivityRelayer string + // ExclusivityEndTime is the exclusivity end time + ExclusivityEndTime time.Time + // CallParams is the call params + CallParams []byte // Status is the current status of the event Status reldb.QuoteRequestStatus // BlockNumber is the block number of the event BlockNumber uint64 // RawRequest is the raw request, hex encoded. RawRequest string - // SendChainGas is true if the chain should send gas - SendChainGas bool // RelayNonce is the nonce for the relay transaction. RelayNonce uint64 } @@ -124,7 +132,8 @@ func FromQuoteRequest(request reldb.QuoteRequest) RequestForQuote { OriginTokenDecimals: request.OriginTokenDecimals, OriginTxHash: stringToNullString(request.OriginTxHash.String()), RawRequest: hexutil.Encode(request.RawRequest), - SendChainGas: request.Transaction.SendChainGas, + ExclusivityRelayer: request.Transaction.ExclusivityRelayer.String(), + ExclusivityEndTime: time.Unix(int64(request.Transaction.ExclusivityEndTime.Uint64()), 0), DestTokenDecimals: request.DestTokenDecimals, DestToken: request.Transaction.DestToken.String(), DestTxHash: stringToNullString(request.DestTxHash.String()), @@ -132,6 +141,9 @@ func FromQuoteRequest(request reldb.QuoteRequest) RequestForQuote { OriginAmount: decimal.NewFromBigInt(request.Transaction.OriginAmount, int32(request.OriginTokenDecimals)), DestAmountOriginal: request.Transaction.DestAmount.String(), DestAmount: decimal.NewFromBigInt(request.Transaction.DestAmount, int32(request.DestTokenDecimals)), + OriginFeeAmount: decimal.NewFromBigInt(request.Transaction.OriginFeeAmount, int32(request.OriginTokenDecimals)), + CallValue: decimal.NewFromBigInt(request.Transaction.CallValue, int32(request.OriginTokenDecimals)), + CallParams: request.Transaction.CallParams, Deadline: time.Unix(int64(request.Transaction.Deadline.Uint64()), 0), OriginNonce: int(request.Transaction.Nonce.Uint64()), Status: request.Status, @@ -207,19 +219,22 @@ func (r RequestForQuote) ToQuoteRequest() (*reldb.QuoteRequest, error) { RawRequest: req, Sender: common.HexToAddress(r.OriginSender), BlockNumber: r.BlockNumber, - Transaction: fastbridge.IFastBridgeBridgeTransaction{ - OriginChainId: r.OriginChainID, - DestChainId: r.DestChainID, - OriginSender: common.HexToAddress(r.OriginSender), - DestRecipient: common.HexToAddress(r.DestRecipient), - OriginToken: common.HexToAddress(r.OriginToken), - SendChainGas: r.SendChainGas, - DestToken: common.HexToAddress(r.DestToken), - OriginAmount: new(big.Int).Div(r.OriginAmount.BigInt(), big.NewInt(int64(math.Pow10(int(r.OriginTokenDecimals))))), - // OriginAmount: new(big.Int).Div(r.OriginAmount.BigInt(), big.NewInt(int64(r.OriginTokenDecimals))), - DestAmount: new(big.Int).Div(r.DestAmount.BigInt(), big.NewInt(int64(math.Pow10(int(r.DestTokenDecimals))))), - Deadline: big.NewInt(r.Deadline.Unix()), - Nonce: big.NewInt(int64(r.OriginNonce)), + Transaction: fastbridgev2.IFastBridgeV2BridgeTransactionV2{ + OriginChainId: r.OriginChainID, + DestChainId: r.DestChainID, + OriginSender: common.HexToAddress(r.OriginSender), + DestRecipient: common.HexToAddress(r.DestRecipient), + OriginToken: common.HexToAddress(r.OriginToken), + DestToken: common.HexToAddress(r.DestToken), + OriginAmount: new(big.Int).Div(r.OriginAmount.BigInt(), big.NewInt(int64(math.Pow10(int(r.OriginTokenDecimals))))), + DestAmount: new(big.Int).Div(r.DestAmount.BigInt(), big.NewInt(int64(math.Pow10(int(r.DestTokenDecimals))))), + OriginFeeAmount: new(big.Int).Div(r.OriginFeeAmount.BigInt(), big.NewInt(int64(math.Pow10(int(r.OriginTokenDecimals))))), + CallValue: new(big.Int).Div(r.CallValue.BigInt(), big.NewInt(int64(math.Pow10(int(r.OriginTokenDecimals))))), + ExclusivityRelayer: common.HexToAddress(r.ExclusivityRelayer), + ExclusivityEndTime: big.NewInt(r.ExclusivityEndTime.Unix()), + CallParams: r.CallParams, + Deadline: big.NewInt(r.Deadline.Unix()), + Nonce: big.NewInt(int64(r.OriginNonce)), }, Status: r.Status, OriginTxHash: common.HexToHash(r.OriginTxHash.String), diff --git a/services/rfq/relayer/reldb/db.go b/services/rfq/relayer/reldb/db.go index f4ce0293d6..441129ea32 100644 --- a/services/rfq/relayer/reldb/db.go +++ b/services/rfq/relayer/reldb/db.go @@ -13,7 +13,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/synapsecns/sanguine/core/dbcommon" submitterDB "github.com/synapsecns/sanguine/ethergo/submitter/db" - "github.com/synapsecns/sanguine/services/rfq/contracts/fastbridge" + "github.com/synapsecns/sanguine/services/rfq/contracts/fastbridgev2" ) // Writer is the interface for writing to the database. @@ -81,7 +81,7 @@ type QuoteRequest struct { DestTokenDecimals uint8 TransactionID [32]byte Sender common.Address - Transaction fastbridge.IFastBridgeBridgeTransaction + Transaction fastbridgev2.IFastBridgeV2BridgeTransactionV2 // Status is the quote request status Status QuoteRequestStatus OriginTxHash common.Hash diff --git a/services/rfq/relayer/service/chainindexer.go b/services/rfq/relayer/service/chainindexer.go index 60ab86ee90..6201360b01 100644 --- a/services/rfq/relayer/service/chainindexer.go +++ b/services/rfq/relayer/service/chainindexer.go @@ -11,7 +11,7 @@ import ( "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/core/types" "github.com/synapsecns/sanguine/core/metrics" - "github.com/synapsecns/sanguine/services/rfq/contracts/fastbridge" + "github.com/synapsecns/sanguine/services/rfq/contracts/fastbridgev2" "github.com/synapsecns/sanguine/services/rfq/contracts/ierc20" "github.com/synapsecns/sanguine/services/rfq/relayer/reldb" "github.com/synapsecns/sanguine/services/rfq/util" @@ -46,7 +46,7 @@ func (r *Relayer) startChainIndexers(ctx context.Context) error { func (r *Relayer) runChainIndexer(ctx context.Context, chainID int) (err error) { chainListener := r.chainListeners[chainID] - parser, err := fastbridge.NewParser(chainListener.Address()) + parser, err := fastbridgev2.NewParser(chainListener.Address()) if err != nil { return fmt.Errorf("could not parse: %w", err) } @@ -74,12 +74,12 @@ func (r *Relayer) runChainIndexer(ctx context.Context, chainID int) (err error) }() switch event := parsedEvent.(type) { - case *fastbridge.FastBridgeBridgeRequested: + case *fastbridgev2.FastBridgeV2BridgeRequested: err = r.handleBridgeRequestedLog(ctx, event, uint64(chainID)) if err != nil { return fmt.Errorf("could not handle request: %w", err) } - case *fastbridge.FastBridgeBridgeRelayed: + case *fastbridgev2.FastBridgeV2BridgeRelayed: // blocking lock on the txid mutex to ensure state transitions are not overrwitten unlocker := r.handlerMtx.Lock(hexutil.Encode(event.TransactionId[:])) defer unlocker.Unlock() @@ -94,7 +94,7 @@ func (r *Relayer) runChainIndexer(ctx context.Context, chainID int) (err error) if err != nil { return fmt.Errorf("could not handle relay: %w", err) } - case *fastbridge.FastBridgeBridgeProofProvided: + case *fastbridgev2.FastBridgeV2BridgeProofProvided: unlocker := r.handlerMtx.Lock(hexutil.Encode(event.TransactionId[:])) defer unlocker.Unlock() @@ -108,7 +108,7 @@ func (r *Relayer) runChainIndexer(ctx context.Context, chainID int) (err error) if err != nil { return fmt.Errorf("could not handle proof provided: %w", err) } - case *fastbridge.FastBridgeBridgeDepositClaimed: + case *fastbridgev2.FastBridgeV2BridgeDepositClaimed: unlocker := r.handlerMtx.Lock(hexutil.Encode(event.TransactionId[:])) defer unlocker.Unlock() @@ -136,7 +136,7 @@ func (r *Relayer) runChainIndexer(ctx context.Context, chainID int) (err error) var ethDecimals uint8 = 18 // getDecimals gets the decimals for the origin and dest tokens. -func (r *Relayer) getDecimalsFromBridgeTx(parentCtx context.Context, bridgeTx fastbridge.IFastBridgeBridgeTransaction) (originDecimals *uint8, destDecimals *uint8, err error) { +func (r *Relayer) getDecimalsFromBridgeTx(parentCtx context.Context, bridgeTx fastbridgev2.IFastBridgeV2BridgeTransactionV2) (originDecimals *uint8, destDecimals *uint8, err error) { ctx, span := r.metrics.Tracer().Start(parentCtx, "getDecimals", trace.WithAttributes( attribute.String("sender", bridgeTx.OriginSender.String()), )) @@ -207,7 +207,7 @@ func getDecimalsKey(addr common.Address, chainID uint32) string { return fmt.Sprintf("%s-%d", addr.Hex(), chainID) } -func (r *Relayer) handleDepositClaimed(ctx context.Context, event *fastbridge.FastBridgeBridgeDepositClaimed) error { +func (r *Relayer) handleDepositClaimed(ctx context.Context, event *fastbridgev2.FastBridgeV2BridgeDepositClaimed) error { err := r.db.UpdateQuoteRequestStatus(ctx, event.TransactionId, reldb.ClaimCompleted, nil) if err != nil { return fmt.Errorf("could not update request status: %w", err) diff --git a/services/rfq/relayer/service/handlers.go b/services/rfq/relayer/service/handlers.go index fc1bc1abe8..0da15fdbf5 100644 --- a/services/rfq/relayer/service/handlers.go +++ b/services/rfq/relayer/service/handlers.go @@ -13,7 +13,7 @@ import ( "github.com/synapsecns/sanguine/core/metrics" "github.com/synapsecns/sanguine/core/retry" "github.com/synapsecns/sanguine/services/rfq/api/model" - "github.com/synapsecns/sanguine/services/rfq/contracts/fastbridge" + "github.com/synapsecns/sanguine/services/rfq/contracts/fastbridgev2" "github.com/synapsecns/sanguine/services/rfq/relayer/inventory" "github.com/synapsecns/sanguine/services/rfq/relayer/reldb" "go.opentelemetry.io/otel/attribute" @@ -31,7 +31,7 @@ var ( // This is the first event emitted in the bridge process. It is emitted when a user calls bridge on chain. // To process it, we decode the bridge transaction and store all the data, marking it as seen. // This marks the event as seen. -func (r *Relayer) handleBridgeRequestedLog(parentCtx context.Context, req *fastbridge.FastBridgeBridgeRequested, chainID uint64) (err error) { +func (r *Relayer) handleBridgeRequestedLog(parentCtx context.Context, req *fastbridgev2.FastBridgeV2BridgeRequested, chainID uint64) (err error) { ctx, span := r.metrics.Tracer().Start(parentCtx, "handleBridgeRequestedLog", trace.WithAttributes( attribute.String("transaction_id", hexutil.Encode(req.TransactionId[:])), )) @@ -68,14 +68,14 @@ func (r *Relayer) handleBridgeRequestedLog(parentCtx context.Context, req *fastb return fmt.Errorf("could not get correct omnirpc client: %w", err) } - fastBridge, err := fastbridge.NewFastBridgeRef(req.Raw.Address, originClient) + fastBridge, err := fastbridgev2.NewFastBridgeV2Ref(req.Raw.Address, originClient) if err != nil { return fmt.Errorf("could not get correct fast bridge: %w", err) } - var bridgeTx fastbridge.IFastBridgeBridgeTransaction + var bridgeTx fastbridgev2.IFastBridgeV2BridgeTransactionV2 call := func(ctx context.Context) error { - bridgeTx, err = fastBridge.GetBridgeTransaction(&bind.CallOpts{Context: ctx}, req.Request) + bridgeTx, err = fastBridge.GetBridgeTransactionV2(&bind.CallOpts{Context: ctx}, req.Request) if err != nil { return fmt.Errorf("could not get bridge transaction: %w", err) } @@ -312,10 +312,10 @@ func (q *QuoteRequestHandler) handleCommitPending(ctx context.Context, span trac return fmt.Errorf("could not make contract call: %w", err) } - span.AddEvent("status_check", trace.WithAttributes(attribute.String("chain_bridge_status", fastbridge.BridgeStatus(bs).String()))) + span.AddEvent("status_check", trace.WithAttributes(attribute.String("chain_bridge_status", fastbridgev2.BridgeStatus(bs).String()))) // sanity check to make sure it's still requested. - if bs != fastbridge.REQUESTED.Int() { + if bs != fastbridgev2.REQUESTED.Int() { return nil } @@ -368,7 +368,7 @@ func (q *QuoteRequestHandler) handleCommitConfirmed(ctx context.Context, span tr // // This is the fifth step in the bridge process. Here we check if the relay has been completed on the destination chain. // Notably, this is polled from the chain listener rather than the database since we wait for the log to show up. -func (r *Relayer) handleRelayLog(parentCtx context.Context, req *fastbridge.FastBridgeBridgeRelayed) (err error) { +func (r *Relayer) handleRelayLog(parentCtx context.Context, req *fastbridgev2.FastBridgeV2BridgeRelayed) (err error) { ctx, span := r.metrics.Tracer().Start(parentCtx, "handleRelayLog", trace.WithAttributes(attribute.String("transaction_id", hexutil.Encode(req.TransactionId[:]))), ) @@ -470,7 +470,7 @@ func (q *QuoteRequestHandler) getRelayBlockNumber(ctx context.Context, request r if err != nil { return blockNumber, fmt.Errorf("could not get receipt: %w", err) } - parser, err := fastbridge.NewParser(q.Dest.Bridge.Address()) + parser, err := fastbridgev2.NewParser(q.Dest.Bridge.Address()) if err != nil { return blockNumber, fmt.Errorf("could not create parser: %w", err) } @@ -484,7 +484,7 @@ func (q *QuoteRequestHandler) getRelayBlockNumber(ctx context.Context, request r if !ok { continue } - _, ok = parsedEvent.(*fastbridge.FastBridgeBridgeRelayed) + _, ok = parsedEvent.(*fastbridgev2.FastBridgeV2BridgeRelayed) if ok { return receipt.BlockNumber.Uint64(), nil } @@ -497,7 +497,7 @@ func (q *QuoteRequestHandler) getRelayBlockNumber(ctx context.Context, request r // Step 7: ProvePosted // // This is the seventh step in the bridge process. Here we process the event that the proof was posted on chain. -func (r *Relayer) handleProofProvided(ctx context.Context, req *fastbridge.FastBridgeBridgeProofProvided) (err error) { +func (r *Relayer) handleProofProvided(ctx context.Context, req *fastbridgev2.FastBridgeV2BridgeProofProvided) (err error) { if req.Relayer != r.signer.Address() { return nil } @@ -538,9 +538,9 @@ func (q *QuoteRequestHandler) handleProofPosted(ctx context.Context, span trace. return fmt.Errorf("could not make contract call: %w", err) } switch bs { - case fastbridge.RelayerProved.Int(): + case fastbridgev2.RelayerProved.Int(): // no op - case fastbridge.RelayerClaimed.Int(): + case fastbridgev2.RelayerClaimed.Int(): err = q.db.UpdateQuoteRequestStatus(ctx, request.TransactionID, reldb.ClaimCompleted, &request.Status) if err != nil { return fmt.Errorf("could not update request status: %w", err) diff --git a/services/rfq/relayer/service/relayer.go b/services/rfq/relayer/service/relayer.go index 38fdc4b701..bda410b6aa 100644 --- a/services/rfq/relayer/service/relayer.go +++ b/services/rfq/relayer/service/relayer.go @@ -26,7 +26,7 @@ import ( "github.com/synapsecns/sanguine/services/cctp-relayer/relayer" omniClient "github.com/synapsecns/sanguine/services/omnirpc/client" rfqAPIClient "github.com/synapsecns/sanguine/services/rfq/api/client" - "github.com/synapsecns/sanguine/services/rfq/contracts/fastbridge" + "github.com/synapsecns/sanguine/services/rfq/contracts/fastbridgev2" "github.com/synapsecns/sanguine/services/rfq/guard/guardconfig" serviceGuard "github.com/synapsecns/sanguine/services/rfq/guard/service" "github.com/synapsecns/sanguine/services/rfq/relayer/inventory" @@ -99,7 +99,7 @@ func NewRelayer(ctx context.Context, metricHandler metrics.Handler, cfg relconfi return nil, fmt.Errorf("could not get chain client: %w", err) } - contract, err := fastbridge.NewFastBridgeRef(rfqAddr, chainClient) + contract, err := fastbridgev2.NewFastBridgeV2Ref(rfqAddr, chainClient) if err != nil { return nil, fmt.Errorf("could not create fast bridge contract at address %s: %w", contract.Address(), err) } diff --git a/services/rfq/relayer/service/suite_test.go b/services/rfq/relayer/service/suite_test.go index 6cdebefa06..d02a7dac97 100644 --- a/services/rfq/relayer/service/suite_test.go +++ b/services/rfq/relayer/service/suite_test.go @@ -16,7 +16,7 @@ import ( "github.com/synapsecns/sanguine/ethergo/backends/geth" "github.com/synapsecns/sanguine/ethergo/mocks" omnirpcHelper "github.com/synapsecns/sanguine/services/omnirpc/testhelper" - "github.com/synapsecns/sanguine/services/rfq/contracts/testcontracts/fastbridgemock" + "github.com/synapsecns/sanguine/services/rfq/contracts/testcontracts/fastbridgev2mock" "github.com/synapsecns/sanguine/services/rfq/relayer/relconfig" "github.com/synapsecns/sanguine/services/rfq/relayer/service" "github.com/synapsecns/sanguine/services/rfq/testutil" @@ -60,8 +60,8 @@ func (r *RelayerTestSuite) SetupTest() { serverURL := omnirpcHelper.NewOmnirpcServer(r.GetTestContext(), r.T(), r.destBackend, r.originBackend) - originContract, _ := r.manager.GetMockFastBridge(r.GetTestContext(), r.originBackend) - destContract, _ := r.manager.GetMockFastBridge(r.GetTestContext(), r.destBackend) + originContract, _ := r.manager.GetMockFastBridgeV2(r.GetTestContext(), r.originBackend) + destContract, _ := r.manager.GetMockFastBridgeV2(r.GetTestContext(), r.destBackend) r.cfg = relconfig.Config{ Database: relconfig.DatabaseConfig{ Type: dbcommon.Sqlite.String(), @@ -89,7 +89,7 @@ func (r *RelayerTestSuite) TestStore() { r.NoError(rel.StartChainParser(r.GetTestContext())) }() - _, oc := r.manager.GetMockFastBridge(r.GetTestContext(), r.originBackend) + _, oc := r.manager.GetMockFastBridgeV2(r.GetTestContext(), r.originBackend) auth := r.originBackend.GetTxContext(r.GetTestContext(), nil) @@ -100,7 +100,7 @@ func (r *RelayerTestSuite) TestStore() { r.NoError(err) //nolint: typecheck - tx, err := oc.MockBridgeRequest(auth.TransactOpts, [32]byte(crypto.Keccak256([]byte("3"))), mocks.MockAddress(), fastbridgemock.IFastBridgeBridgeParams{ + tx, err := oc.MockBridgeRequest(auth.TransactOpts, [32]byte(crypto.Keccak256([]byte("3"))), mocks.MockAddress(), fastbridgev2mock.IFastBridgeV2BridgeParams{ DstChainId: uint32(r.destBackend.GetChainID()), To: mocks.MockAddress(), OriginToken: originToken.Address(), @@ -126,7 +126,7 @@ func (r *RelayerTestSuite) TestCommit() { r.NoError(rel.StartChainParser(r.GetTestContext())) }() - _, oc := r.manager.GetMockFastBridge(r.GetTestContext(), r.originBackend) + _, oc := r.manager.GetMockFastBridgeV2(r.GetTestContext(), r.originBackend) auth := r.originBackend.GetTxContext(r.GetTestContext(), nil) @@ -137,7 +137,7 @@ func (r *RelayerTestSuite) TestCommit() { r.NoError(err) //nolint: typecheck - tx, err := oc.MockBridgeRequest(auth.TransactOpts, [32]byte(crypto.Keccak256([]byte("3"))), mocks.MockAddress(), fastbridgemock.IFastBridgeBridgeParams{ + tx, err := oc.MockBridgeRequest(auth.TransactOpts, [32]byte(crypto.Keccak256([]byte("3"))), mocks.MockAddress(), fastbridgev2mock.IFastBridgeV2BridgeParams{ DstChainId: uint32(r.destBackend.GetChainID()), To: mocks.MockAddress(), OriginToken: originToken.Address(), From 1056ef18b6eb53d4780eff6358f14cde9cf27ef1 Mon Sep 17 00:00:00 2001 From: Daniel Wasserman Date: Tue, 8 Oct 2024 15:19:07 -0500 Subject: [PATCH 22/85] Feat: testutils uses v2 --- services/rfq/testutil/typecast.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/services/rfq/testutil/typecast.go b/services/rfq/testutil/typecast.go index fd096d497b..8d5280c35f 100644 --- a/services/rfq/testutil/typecast.go +++ b/services/rfq/testutil/typecast.go @@ -6,7 +6,7 @@ import ( "github.com/synapsecns/sanguine/ethergo/backends" "github.com/synapsecns/sanguine/ethergo/contracts" "github.com/synapsecns/sanguine/ethergo/manager" - "github.com/synapsecns/sanguine/services/rfq/contracts/fastbridge" + "github.com/synapsecns/sanguine/services/rfq/contracts/fastbridgev2" "github.com/synapsecns/sanguine/services/rfq/contracts/testcontracts/dai" "github.com/synapsecns/sanguine/services/rfq/contracts/testcontracts/fastbridgemock" "github.com/synapsecns/sanguine/services/rfq/contracts/testcontracts/mockerc20" @@ -16,10 +16,10 @@ import ( ) // GetFastBridge gets the pre-created fast bridge contract. -func (d *DeployManager) GetFastBridge(ctx context.Context, backend backends.SimulatedTestBackend) (contract contracts.DeployedContract, handle *fastbridge.FastBridgeRef) { +func (d *DeployManager) GetFastBridge(ctx context.Context, backend backends.SimulatedTestBackend) (contract contracts.DeployedContract, handle *fastbridgev2.FastBridgeV2Ref) { d.T().Helper() - return manager.GetContract[*fastbridge.FastBridgeRef](ctx, d.T(), d, backend, FastBridgeType) + return manager.GetContract[*fastbridgev2.FastBridgeV2Ref](ctx, d.T(), d, backend, FastBridgeType) } // GetMockERC20 gets a mock erc20 deployed on a chain. From 130127038312db535543fd813c1ad77df389cb04 Mon Sep 17 00:00:00 2001 From: Daniel Wasserman Date: Tue, 8 Oct 2024 15:36:12 -0500 Subject: [PATCH 23/85] Fix: deployer uses v2 --- services/rfq/testutil/deployers.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/services/rfq/testutil/deployers.go b/services/rfq/testutil/deployers.go index 79ae1538e8..1d046b7424 100644 --- a/services/rfq/testutil/deployers.go +++ b/services/rfq/testutil/deployers.go @@ -14,7 +14,7 @@ import ( "github.com/synapsecns/sanguine/ethergo/contracts" "github.com/synapsecns/sanguine/ethergo/deployer" "github.com/synapsecns/sanguine/ethergo/manager" - "github.com/synapsecns/sanguine/services/rfq/contracts/fastbridge" + "github.com/synapsecns/sanguine/services/rfq/contracts/fastbridgev2" "github.com/synapsecns/sanguine/services/rfq/contracts/testcontracts/fastbridgemock" ) @@ -113,9 +113,9 @@ func NewFastBridgeDeployer(registry deployer.GetOnlyContractRegistry, backend ba // Deploy deploys the fast bridge contract. func (f FastBridgeDeployer) Deploy(ctx context.Context) (contracts.DeployedContract, error) { return f.DeploySimpleContract(ctx, func(transactOps *bind.TransactOpts, backend bind.ContractBackend) (common.Address, *types.Transaction, interface{}, error) { - return fastbridge.DeployFastBridge(transactOps, backend, transactOps.From) + return fastbridgev2.DeployFastBridgeV2(transactOps, backend, transactOps.From) }, func(address common.Address, backend bind.ContractBackend) (interface{}, error) { - return fastbridge.NewFastBridgeRef(address, backend) + return fastbridgev2.NewFastBridgeV2Ref(address, backend) }) } From 1081e0ae7ba68577ad20e6bec76e86e4bee6ab41 Mon Sep 17 00:00:00 2001 From: Daniel Wasserman Date: Tue, 8 Oct 2024 16:04:28 -0500 Subject: [PATCH 24/85] Fix: current e2e tests with v2 bridge --- services/rfq/e2e/rfq_test.go | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/services/rfq/e2e/rfq_test.go b/services/rfq/e2e/rfq_test.go index 3612451667..01d6b84f4f 100644 --- a/services/rfq/e2e/rfq_test.go +++ b/services/rfq/e2e/rfq_test.go @@ -22,6 +22,7 @@ import ( omnirpcClient "github.com/synapsecns/sanguine/services/omnirpc/client" "github.com/synapsecns/sanguine/services/rfq/api/client" "github.com/synapsecns/sanguine/services/rfq/contracts/fastbridge" + "github.com/synapsecns/sanguine/services/rfq/contracts/fastbridgev2" "github.com/synapsecns/sanguine/services/rfq/guard/guarddb" guardService "github.com/synapsecns/sanguine/services/rfq/guard/service" "github.com/synapsecns/sanguine/services/rfq/relayer/reldb" @@ -166,11 +167,12 @@ func (i *IntegrationSuite) TestUSDCtoUSDC() { // now we can send the money _, originFastBridge := i.manager.GetFastBridge(i.GetTestContext(), i.originBackend) auth := i.originBackend.GetTxContext(i.GetTestContext(), i.userWallet.AddressPtr()) - tx, err = originFastBridge.Bridge(auth.TransactOpts, fastbridge.IFastBridgeBridgeParams{ + tx, err = originFastBridge.Bridge(auth.TransactOpts, fastbridgev2.IFastBridgeBridgeParams{ DstChainId: uint32(i.destBackend.GetChainID()), + Sender: i.userWallet.Address(), To: i.userWallet.Address(), OriginToken: originUSDC.Address(), - SendChainGas: true, + SendChainGas: false, DestToken: destUSDC.Address(), OriginAmount: realRFQAmount, DestAmount: new(big.Int).Sub(realRFQAmount, big.NewInt(10_000_000)), @@ -320,8 +322,9 @@ func (i *IntegrationSuite) TestETHtoETH() { auth := i.originBackend.GetTxContext(i.GetTestContext(), i.userWallet.AddressPtr()) auth.TransactOpts.Value = realWantAmount // we want 499 ETH for 500 requested within a day - tx, err := originFastBridge.Bridge(auth.TransactOpts, fastbridge.IFastBridgeBridgeParams{ + tx, err := originFastBridge.Bridge(auth.TransactOpts, fastbridgev2.IFastBridgeBridgeParams{ DstChainId: uint32(i.destBackend.GetChainID()), + Sender: i.userWallet.Address(), To: i.userWallet.Address(), OriginToken: util.EthAddress, SendChainGas: true, @@ -430,8 +433,9 @@ func (i *IntegrationSuite) TestDispute() { _, originFastBridge := i.manager.GetFastBridge(i.GetTestContext(), i.originBackend) auth := i.originBackend.GetTxContext(i.GetTestContext(), i.userWallet.AddressPtr()) // we want 499 usdc for 500 requested within a day - tx, err = originFastBridge.Bridge(auth.TransactOpts, fastbridge.IFastBridgeBridgeParams{ + tx, err = originFastBridge.Bridge(auth.TransactOpts, fastbridgev2.IFastBridgeBridgeParams{ DstChainId: uint32(i.destBackend.GetChainID()), + Sender: i.userWallet.Address(), To: i.userWallet.Address(), OriginToken: originUSDC.Address(), SendChainGas: true, @@ -445,7 +449,6 @@ func (i *IntegrationSuite) TestDispute() { // fetch the txid and raw request var txID [32]byte - var rawRequest []byte parser, err := fastbridge.NewParser(originFastBridge.Address()) i.NoError(err) i.Eventually(func() bool { @@ -458,7 +461,6 @@ func (i *IntegrationSuite) TestDispute() { } event, ok := parsedEvent.(*fastbridge.FastBridgeBridgeRequested) if ok { - rawRequest = event.Request txID = event.TransactionId return true } @@ -469,7 +471,7 @@ func (i *IntegrationSuite) TestDispute() { // call prove() from the relayer wallet before relay actually occurred on dest relayerAuth := i.originBackend.GetTxContext(i.GetTestContext(), i.relayerWallet.AddressPtr()) fakeHash := common.HexToHash("0xdeadbeef") - tx, err = originFastBridge.Prove(relayerAuth.TransactOpts, rawRequest, fakeHash) + tx, err = originFastBridge.Prove(relayerAuth.TransactOpts, txID, fakeHash, relayerAuth.From) i.NoError(err) i.originBackend.WaitForConfirmation(i.GetTestContext(), tx) @@ -561,8 +563,9 @@ func (i *IntegrationSuite) TestConcurrentBridges() { txMux.Lock() auth.TransactOpts.Nonce = nonce defer txMux.Unlock() - tx, err = originFastBridge.Bridge(auth.TransactOpts, fastbridge.IFastBridgeBridgeParams{ + tx, err = originFastBridge.Bridge(auth.TransactOpts, fastbridgev2.IFastBridgeBridgeParams{ DstChainId: uint32(i.destBackend.GetChainID()), + Sender: i.userWallet.Address(), To: i.userWallet.Address(), OriginToken: originUSDC.Address(), SendChainGas: true, From 467d5c7eeac72fdafc7bc203b4d47743cacd4cee Mon Sep 17 00:00:00 2001 From: Daniel Wasserman Date: Wed, 9 Oct 2024 11:51:39 -0500 Subject: [PATCH 25/85] Feat: add recipient mock test contract --- .../testcontracts/recipientmock/generate.go | 3 + .../testcontracts/recipientmock/helper.go | 35 ++ .../recipientmock/recipientmock.abigen.go | 431 ++++++++++++++++++ .../recipientmock.contractinfo.json | 1 + .../recipientmock/recipientmock.metadata.go | 25 + services/rfq/testutil/contracttype.go | 5 + .../rfq/testutil/contracttypeimpl_string.go | 13 +- services/rfq/testutil/deployers.go | 26 +- services/rfq/testutil/typecast.go | 8 + 9 files changed, 539 insertions(+), 8 deletions(-) create mode 100644 services/rfq/contracts/testcontracts/recipientmock/generate.go create mode 100644 services/rfq/contracts/testcontracts/recipientmock/helper.go create mode 100644 services/rfq/contracts/testcontracts/recipientmock/recipientmock.abigen.go create mode 100644 services/rfq/contracts/testcontracts/recipientmock/recipientmock.contractinfo.json create mode 100644 services/rfq/contracts/testcontracts/recipientmock/recipientmock.metadata.go diff --git a/services/rfq/contracts/testcontracts/recipientmock/generate.go b/services/rfq/contracts/testcontracts/recipientmock/generate.go new file mode 100644 index 0000000000..5ab34dea53 --- /dev/null +++ b/services/rfq/contracts/testcontracts/recipientmock/generate.go @@ -0,0 +1,3 @@ +package recipientmock + +//go:generate go run github.com/synapsecns/sanguine/tools/abigen generate --sol ../../../../../packages/contracts-rfq/flattened/RecipientMock.sol --pkg recipientmock --sol-version 0.8.20 --filename recipientmock --evm-version istanbul diff --git a/services/rfq/contracts/testcontracts/recipientmock/helper.go b/services/rfq/contracts/testcontracts/recipientmock/helper.go new file mode 100644 index 0000000000..e91ac32dfd --- /dev/null +++ b/services/rfq/contracts/testcontracts/recipientmock/helper.go @@ -0,0 +1,35 @@ +package recipientmock + +import ( + "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/vm" +) + +// RecipientMockRef is a bound fast bridge contract that returns the address of the contract. +// +//nolint:golint +type RecipientMockRef struct { + *RecipientMock + address common.Address +} + +// Address gets the ocntract address. +func (f *RecipientMockRef) Address() common.Address { + return f.address +} + +// NewRecipientMockRef creates a new fast bridge mock contract with a ref. +func NewRecipientMockRef(address common.Address, backend bind.ContractBackend) (*RecipientMockRef, error) { + recipientmock, err := NewRecipientMock(address, backend) + if err != nil { + return nil, err + } + + return &RecipientMockRef{ + RecipientMock: recipientmock, + address: address, + }, nil +} + +var _ vm.ContractRef = &RecipientMockRef{} diff --git a/services/rfq/contracts/testcontracts/recipientmock/recipientmock.abigen.go b/services/rfq/contracts/testcontracts/recipientmock/recipientmock.abigen.go new file mode 100644 index 0000000000..05fdb417a5 --- /dev/null +++ b/services/rfq/contracts/testcontracts/recipientmock/recipientmock.abigen.go @@ -0,0 +1,431 @@ +// Code generated - DO NOT EDIT. +// This file is a generated binding and any manual changes will be lost. + +package recipientmock + +import ( + "errors" + "math/big" + "strings" + + ethereum "github.com/ethereum/go-ethereum" + "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/event" +) + +// Reference imports to suppress errors if they are not otherwise used. +var ( + _ = errors.New + _ = big.NewInt + _ = strings.NewReader + _ = ethereum.NotFound + _ = bind.Bind + _ = common.Big1 + _ = types.BloomLookup + _ = event.NewSubscription + _ = abi.ConvertType +) + +// IFastBridgeRecipientMetaData contains all meta data concerning the IFastBridgeRecipient contract. +var IFastBridgeRecipientMetaData = &bind.MetaData{ + ABI: "[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"callParams\",\"type\":\"bytes\"}],\"name\":\"fastBridgeTransferReceived\",\"outputs\":[{\"internalType\":\"bytes4\",\"name\":\"\",\"type\":\"bytes4\"}],\"stateMutability\":\"payable\",\"type\":\"function\"}]", + Sigs: map[string]string{ + "461e0c21": "fastBridgeTransferReceived(address,uint256,bytes)", + }, +} + +// IFastBridgeRecipientABI is the input ABI used to generate the binding from. +// Deprecated: Use IFastBridgeRecipientMetaData.ABI instead. +var IFastBridgeRecipientABI = IFastBridgeRecipientMetaData.ABI + +// Deprecated: Use IFastBridgeRecipientMetaData.Sigs instead. +// IFastBridgeRecipientFuncSigs maps the 4-byte function signature to its string representation. +var IFastBridgeRecipientFuncSigs = IFastBridgeRecipientMetaData.Sigs + +// IFastBridgeRecipient is an auto generated Go binding around an Ethereum contract. +type IFastBridgeRecipient struct { + IFastBridgeRecipientCaller // Read-only binding to the contract + IFastBridgeRecipientTransactor // Write-only binding to the contract + IFastBridgeRecipientFilterer // Log filterer for contract events +} + +// IFastBridgeRecipientCaller is an auto generated read-only Go binding around an Ethereum contract. +type IFastBridgeRecipientCaller struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// IFastBridgeRecipientTransactor is an auto generated write-only Go binding around an Ethereum contract. +type IFastBridgeRecipientTransactor struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// IFastBridgeRecipientFilterer is an auto generated log filtering Go binding around an Ethereum contract events. +type IFastBridgeRecipientFilterer struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// IFastBridgeRecipientSession is an auto generated Go binding around an Ethereum contract, +// with pre-set call and transact options. +type IFastBridgeRecipientSession struct { + Contract *IFastBridgeRecipient // Generic contract binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// IFastBridgeRecipientCallerSession is an auto generated read-only Go binding around an Ethereum contract, +// with pre-set call options. +type IFastBridgeRecipientCallerSession struct { + Contract *IFastBridgeRecipientCaller // Generic contract caller binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session +} + +// IFastBridgeRecipientTransactorSession is an auto generated write-only Go binding around an Ethereum contract, +// with pre-set transact options. +type IFastBridgeRecipientTransactorSession struct { + Contract *IFastBridgeRecipientTransactor // Generic contract transactor binding to set the session for + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// IFastBridgeRecipientRaw is an auto generated low-level Go binding around an Ethereum contract. +type IFastBridgeRecipientRaw struct { + Contract *IFastBridgeRecipient // Generic contract binding to access the raw methods on +} + +// IFastBridgeRecipientCallerRaw is an auto generated low-level read-only Go binding around an Ethereum contract. +type IFastBridgeRecipientCallerRaw struct { + Contract *IFastBridgeRecipientCaller // Generic read-only contract binding to access the raw methods on +} + +// IFastBridgeRecipientTransactorRaw is an auto generated low-level write-only Go binding around an Ethereum contract. +type IFastBridgeRecipientTransactorRaw struct { + Contract *IFastBridgeRecipientTransactor // Generic write-only contract binding to access the raw methods on +} + +// NewIFastBridgeRecipient creates a new instance of IFastBridgeRecipient, bound to a specific deployed contract. +func NewIFastBridgeRecipient(address common.Address, backend bind.ContractBackend) (*IFastBridgeRecipient, error) { + contract, err := bindIFastBridgeRecipient(address, backend, backend, backend) + if err != nil { + return nil, err + } + return &IFastBridgeRecipient{IFastBridgeRecipientCaller: IFastBridgeRecipientCaller{contract: contract}, IFastBridgeRecipientTransactor: IFastBridgeRecipientTransactor{contract: contract}, IFastBridgeRecipientFilterer: IFastBridgeRecipientFilterer{contract: contract}}, nil +} + +// NewIFastBridgeRecipientCaller creates a new read-only instance of IFastBridgeRecipient, bound to a specific deployed contract. +func NewIFastBridgeRecipientCaller(address common.Address, caller bind.ContractCaller) (*IFastBridgeRecipientCaller, error) { + contract, err := bindIFastBridgeRecipient(address, caller, nil, nil) + if err != nil { + return nil, err + } + return &IFastBridgeRecipientCaller{contract: contract}, nil +} + +// NewIFastBridgeRecipientTransactor creates a new write-only instance of IFastBridgeRecipient, bound to a specific deployed contract. +func NewIFastBridgeRecipientTransactor(address common.Address, transactor bind.ContractTransactor) (*IFastBridgeRecipientTransactor, error) { + contract, err := bindIFastBridgeRecipient(address, nil, transactor, nil) + if err != nil { + return nil, err + } + return &IFastBridgeRecipientTransactor{contract: contract}, nil +} + +// NewIFastBridgeRecipientFilterer creates a new log filterer instance of IFastBridgeRecipient, bound to a specific deployed contract. +func NewIFastBridgeRecipientFilterer(address common.Address, filterer bind.ContractFilterer) (*IFastBridgeRecipientFilterer, error) { + contract, err := bindIFastBridgeRecipient(address, nil, nil, filterer) + if err != nil { + return nil, err + } + return &IFastBridgeRecipientFilterer{contract: contract}, nil +} + +// bindIFastBridgeRecipient binds a generic wrapper to an already deployed contract. +func bindIFastBridgeRecipient(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) { + parsed, err := IFastBridgeRecipientMetaData.GetAbi() + if err != nil { + return nil, err + } + return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil +} + +// Call invokes the (constant) contract method with params as input values and +// sets the output to result. The result type might be a single field for simple +// returns, a slice of interfaces for anonymous returns and a struct for named +// returns. +func (_IFastBridgeRecipient *IFastBridgeRecipientRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _IFastBridgeRecipient.Contract.IFastBridgeRecipientCaller.contract.Call(opts, result, method, params...) +} + +// Transfer initiates a plain transaction to move funds to the contract, calling +// its default method if one is available. +func (_IFastBridgeRecipient *IFastBridgeRecipientRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _IFastBridgeRecipient.Contract.IFastBridgeRecipientTransactor.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_IFastBridgeRecipient *IFastBridgeRecipientRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _IFastBridgeRecipient.Contract.IFastBridgeRecipientTransactor.contract.Transact(opts, method, params...) +} + +// Call invokes the (constant) contract method with params as input values and +// sets the output to result. The result type might be a single field for simple +// returns, a slice of interfaces for anonymous returns and a struct for named +// returns. +func (_IFastBridgeRecipient *IFastBridgeRecipientCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _IFastBridgeRecipient.Contract.contract.Call(opts, result, method, params...) +} + +// Transfer initiates a plain transaction to move funds to the contract, calling +// its default method if one is available. +func (_IFastBridgeRecipient *IFastBridgeRecipientTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _IFastBridgeRecipient.Contract.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_IFastBridgeRecipient *IFastBridgeRecipientTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _IFastBridgeRecipient.Contract.contract.Transact(opts, method, params...) +} + +// FastBridgeTransferReceived is a paid mutator transaction binding the contract method 0x461e0c21. +// +// Solidity: function fastBridgeTransferReceived(address token, uint256 amount, bytes callParams) payable returns(bytes4) +func (_IFastBridgeRecipient *IFastBridgeRecipientTransactor) FastBridgeTransferReceived(opts *bind.TransactOpts, token common.Address, amount *big.Int, callParams []byte) (*types.Transaction, error) { + return _IFastBridgeRecipient.contract.Transact(opts, "fastBridgeTransferReceived", token, amount, callParams) +} + +// FastBridgeTransferReceived is a paid mutator transaction binding the contract method 0x461e0c21. +// +// Solidity: function fastBridgeTransferReceived(address token, uint256 amount, bytes callParams) payable returns(bytes4) +func (_IFastBridgeRecipient *IFastBridgeRecipientSession) FastBridgeTransferReceived(token common.Address, amount *big.Int, callParams []byte) (*types.Transaction, error) { + return _IFastBridgeRecipient.Contract.FastBridgeTransferReceived(&_IFastBridgeRecipient.TransactOpts, token, amount, callParams) +} + +// FastBridgeTransferReceived is a paid mutator transaction binding the contract method 0x461e0c21. +// +// Solidity: function fastBridgeTransferReceived(address token, uint256 amount, bytes callParams) payable returns(bytes4) +func (_IFastBridgeRecipient *IFastBridgeRecipientTransactorSession) FastBridgeTransferReceived(token common.Address, amount *big.Int, callParams []byte) (*types.Transaction, error) { + return _IFastBridgeRecipient.Contract.FastBridgeTransferReceived(&_IFastBridgeRecipient.TransactOpts, token, amount, callParams) +} + +// RecipientMockMetaData contains all meta data concerning the RecipientMock contract. +var RecipientMockMetaData = &bind.MetaData{ + ABI: "[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"name\":\"fastBridgeTransferReceived\",\"outputs\":[{\"internalType\":\"bytes4\",\"name\":\"\",\"type\":\"bytes4\"}],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"stateMutability\":\"payable\",\"type\":\"receive\"}]", + Sigs: map[string]string{ + "461e0c21": "fastBridgeTransferReceived(address,uint256,bytes)", + }, + Bin: "0x608060405234801561001057600080fd5b50610202806100206000396000f3fe6080604052600436106100225760003560e01c8063461e0c211461002e57600080fd5b3661002957005b600080fd5b61006461003c3660046100c8565b7f461e0c21000000000000000000000000000000000000000000000000000000009392505050565b6040517fffffffff00000000000000000000000000000000000000000000000000000000909116815260200160405180910390f35b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6000806000606084860312156100dd57600080fd5b833573ffffffffffffffffffffffffffffffffffffffff8116811461010157600080fd5b925060208401359150604084013567ffffffffffffffff8082111561012557600080fd5b818601915086601f83011261013957600080fd5b81358181111561014b5761014b610099565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f0116810190838211818310171561019157610191610099565b816040528281528960208487010111156101aa57600080fd5b826020860160208301376000602084830101528095505050505050925092509256fea2646970667358221220f1a74d56eefc9976c67d52f3119adaca862e91740662087e97a8e47c248fbb1d64736f6c63430008140033", +} + +// RecipientMockABI is the input ABI used to generate the binding from. +// Deprecated: Use RecipientMockMetaData.ABI instead. +var RecipientMockABI = RecipientMockMetaData.ABI + +// Deprecated: Use RecipientMockMetaData.Sigs instead. +// RecipientMockFuncSigs maps the 4-byte function signature to its string representation. +var RecipientMockFuncSigs = RecipientMockMetaData.Sigs + +// RecipientMockBin is the compiled bytecode used for deploying new contracts. +// Deprecated: Use RecipientMockMetaData.Bin instead. +var RecipientMockBin = RecipientMockMetaData.Bin + +// DeployRecipientMock deploys a new Ethereum contract, binding an instance of RecipientMock to it. +func DeployRecipientMock(auth *bind.TransactOpts, backend bind.ContractBackend) (common.Address, *types.Transaction, *RecipientMock, error) { + parsed, err := RecipientMockMetaData.GetAbi() + if err != nil { + return common.Address{}, nil, nil, err + } + if parsed == nil { + return common.Address{}, nil, nil, errors.New("GetABI returned nil") + } + + address, tx, contract, err := bind.DeployContract(auth, *parsed, common.FromHex(RecipientMockBin), backend) + if err != nil { + return common.Address{}, nil, nil, err + } + return address, tx, &RecipientMock{RecipientMockCaller: RecipientMockCaller{contract: contract}, RecipientMockTransactor: RecipientMockTransactor{contract: contract}, RecipientMockFilterer: RecipientMockFilterer{contract: contract}}, nil +} + +// RecipientMock is an auto generated Go binding around an Ethereum contract. +type RecipientMock struct { + RecipientMockCaller // Read-only binding to the contract + RecipientMockTransactor // Write-only binding to the contract + RecipientMockFilterer // Log filterer for contract events +} + +// RecipientMockCaller is an auto generated read-only Go binding around an Ethereum contract. +type RecipientMockCaller struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// RecipientMockTransactor is an auto generated write-only Go binding around an Ethereum contract. +type RecipientMockTransactor struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// RecipientMockFilterer is an auto generated log filtering Go binding around an Ethereum contract events. +type RecipientMockFilterer struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// RecipientMockSession is an auto generated Go binding around an Ethereum contract, +// with pre-set call and transact options. +type RecipientMockSession struct { + Contract *RecipientMock // Generic contract binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// RecipientMockCallerSession is an auto generated read-only Go binding around an Ethereum contract, +// with pre-set call options. +type RecipientMockCallerSession struct { + Contract *RecipientMockCaller // Generic contract caller binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session +} + +// RecipientMockTransactorSession is an auto generated write-only Go binding around an Ethereum contract, +// with pre-set transact options. +type RecipientMockTransactorSession struct { + Contract *RecipientMockTransactor // Generic contract transactor binding to set the session for + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// RecipientMockRaw is an auto generated low-level Go binding around an Ethereum contract. +type RecipientMockRaw struct { + Contract *RecipientMock // Generic contract binding to access the raw methods on +} + +// RecipientMockCallerRaw is an auto generated low-level read-only Go binding around an Ethereum contract. +type RecipientMockCallerRaw struct { + Contract *RecipientMockCaller // Generic read-only contract binding to access the raw methods on +} + +// RecipientMockTransactorRaw is an auto generated low-level write-only Go binding around an Ethereum contract. +type RecipientMockTransactorRaw struct { + Contract *RecipientMockTransactor // Generic write-only contract binding to access the raw methods on +} + +// NewRecipientMock creates a new instance of RecipientMock, bound to a specific deployed contract. +func NewRecipientMock(address common.Address, backend bind.ContractBackend) (*RecipientMock, error) { + contract, err := bindRecipientMock(address, backend, backend, backend) + if err != nil { + return nil, err + } + return &RecipientMock{RecipientMockCaller: RecipientMockCaller{contract: contract}, RecipientMockTransactor: RecipientMockTransactor{contract: contract}, RecipientMockFilterer: RecipientMockFilterer{contract: contract}}, nil +} + +// NewRecipientMockCaller creates a new read-only instance of RecipientMock, bound to a specific deployed contract. +func NewRecipientMockCaller(address common.Address, caller bind.ContractCaller) (*RecipientMockCaller, error) { + contract, err := bindRecipientMock(address, caller, nil, nil) + if err != nil { + return nil, err + } + return &RecipientMockCaller{contract: contract}, nil +} + +// NewRecipientMockTransactor creates a new write-only instance of RecipientMock, bound to a specific deployed contract. +func NewRecipientMockTransactor(address common.Address, transactor bind.ContractTransactor) (*RecipientMockTransactor, error) { + contract, err := bindRecipientMock(address, nil, transactor, nil) + if err != nil { + return nil, err + } + return &RecipientMockTransactor{contract: contract}, nil +} + +// NewRecipientMockFilterer creates a new log filterer instance of RecipientMock, bound to a specific deployed contract. +func NewRecipientMockFilterer(address common.Address, filterer bind.ContractFilterer) (*RecipientMockFilterer, error) { + contract, err := bindRecipientMock(address, nil, nil, filterer) + if err != nil { + return nil, err + } + return &RecipientMockFilterer{contract: contract}, nil +} + +// bindRecipientMock binds a generic wrapper to an already deployed contract. +func bindRecipientMock(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) { + parsed, err := RecipientMockMetaData.GetAbi() + if err != nil { + return nil, err + } + return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil +} + +// Call invokes the (constant) contract method with params as input values and +// sets the output to result. The result type might be a single field for simple +// returns, a slice of interfaces for anonymous returns and a struct for named +// returns. +func (_RecipientMock *RecipientMockRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _RecipientMock.Contract.RecipientMockCaller.contract.Call(opts, result, method, params...) +} + +// Transfer initiates a plain transaction to move funds to the contract, calling +// its default method if one is available. +func (_RecipientMock *RecipientMockRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _RecipientMock.Contract.RecipientMockTransactor.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_RecipientMock *RecipientMockRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _RecipientMock.Contract.RecipientMockTransactor.contract.Transact(opts, method, params...) +} + +// Call invokes the (constant) contract method with params as input values and +// sets the output to result. The result type might be a single field for simple +// returns, a slice of interfaces for anonymous returns and a struct for named +// returns. +func (_RecipientMock *RecipientMockCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _RecipientMock.Contract.contract.Call(opts, result, method, params...) +} + +// Transfer initiates a plain transaction to move funds to the contract, calling +// its default method if one is available. +func (_RecipientMock *RecipientMockTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _RecipientMock.Contract.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_RecipientMock *RecipientMockTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _RecipientMock.Contract.contract.Transact(opts, method, params...) +} + +// FastBridgeTransferReceived is a paid mutator transaction binding the contract method 0x461e0c21. +// +// Solidity: function fastBridgeTransferReceived(address , uint256 , bytes ) payable returns(bytes4) +func (_RecipientMock *RecipientMockTransactor) FastBridgeTransferReceived(opts *bind.TransactOpts, arg0 common.Address, arg1 *big.Int, arg2 []byte) (*types.Transaction, error) { + return _RecipientMock.contract.Transact(opts, "fastBridgeTransferReceived", arg0, arg1, arg2) +} + +// FastBridgeTransferReceived is a paid mutator transaction binding the contract method 0x461e0c21. +// +// Solidity: function fastBridgeTransferReceived(address , uint256 , bytes ) payable returns(bytes4) +func (_RecipientMock *RecipientMockSession) FastBridgeTransferReceived(arg0 common.Address, arg1 *big.Int, arg2 []byte) (*types.Transaction, error) { + return _RecipientMock.Contract.FastBridgeTransferReceived(&_RecipientMock.TransactOpts, arg0, arg1, arg2) +} + +// FastBridgeTransferReceived is a paid mutator transaction binding the contract method 0x461e0c21. +// +// Solidity: function fastBridgeTransferReceived(address , uint256 , bytes ) payable returns(bytes4) +func (_RecipientMock *RecipientMockTransactorSession) FastBridgeTransferReceived(arg0 common.Address, arg1 *big.Int, arg2 []byte) (*types.Transaction, error) { + return _RecipientMock.Contract.FastBridgeTransferReceived(&_RecipientMock.TransactOpts, arg0, arg1, arg2) +} + +// Receive is a paid mutator transaction binding the contract receive function. +// +// Solidity: receive() payable returns() +func (_RecipientMock *RecipientMockTransactor) Receive(opts *bind.TransactOpts) (*types.Transaction, error) { + return _RecipientMock.contract.RawTransact(opts, nil) // calldata is disallowed for receive function +} + +// Receive is a paid mutator transaction binding the contract receive function. +// +// Solidity: receive() payable returns() +func (_RecipientMock *RecipientMockSession) Receive() (*types.Transaction, error) { + return _RecipientMock.Contract.Receive(&_RecipientMock.TransactOpts) +} + +// Receive is a paid mutator transaction binding the contract receive function. +// +// Solidity: receive() payable returns() +func (_RecipientMock *RecipientMockTransactorSession) Receive() (*types.Transaction, error) { + return _RecipientMock.Contract.Receive(&_RecipientMock.TransactOpts) +} diff --git a/services/rfq/contracts/testcontracts/recipientmock/recipientmock.contractinfo.json b/services/rfq/contracts/testcontracts/recipientmock/recipientmock.contractinfo.json new file mode 100644 index 0000000000..9db7be468b --- /dev/null +++ b/services/rfq/contracts/testcontracts/recipientmock/recipientmock.contractinfo.json @@ -0,0 +1 @@ +{"solidity/RecipientMock.sol:IFastBridgeRecipient":{"code":"0x","runtime-code":"0x","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\n// contracts/interfaces/IFastBridgeRecipient.sol\n\ninterface IFastBridgeRecipient {\n function fastBridgeTransferReceived(\n address token,\n uint256 amount,\n bytes memory callParams\n )\n external\n payable\n returns (bytes4);\n}\n\n// test/mocks/RecipientMock.sol\n\n/// @notice Recipient mock for testing purposes. DO NOT USE IN PRODUCTION.\ncontract RecipientMock is IFastBridgeRecipient {\n /// @notice Mock needs to accept ETH\n receive() external payable {}\n\n /// @notice Minimal viable implementation of the fastBridgeTransferReceived hook.\n function fastBridgeTransferReceived(address, uint256, bytes memory) external payable returns (bytes4) {\n return IFastBridgeRecipient.fastBridgeTransferReceived.selector;\n }\n}\n","language":"Solidity","languageVersion":"0.8.20","compilerVersion":"0.8.20","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"","srcMapRuntime":"","abiDefinition":[{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"bytes","name":"callParams","type":"bytes"}],"name":"fastBridgeTransferReceived","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"payable","type":"function"}],"userDoc":{"kind":"user","methods":{},"version":1},"developerDoc":{"kind":"dev","methods":{},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.20+commit.a1b79de6\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"callParams\",\"type\":\"bytes\"}],\"name\":\"fastBridgeTransferReceived\",\"outputs\":[{\"internalType\":\"bytes4\",\"name\":\"\",\"type\":\"bytes4\"}],\"stateMutability\":\"payable\",\"type\":\"function\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/RecipientMock.sol\":\"IFastBridgeRecipient\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/RecipientMock.sol\":{\"keccak256\":\"0xb8f940be952dc310c5d546785516c6d77f8abe7f6a852ee6ab4b3f1c33534b41\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://fb32a814c5a9088d1881eec57e12c3ebe91503be5b6be1c0c212b46bdbca89a7\",\"dweb:/ipfs/QmTQFfCjLPqVsxw7B6c4CNZMbtKJrg6mctRsTwaXqVDeLe\"]}},\"version\":1}"},"hashes":{"fastBridgeTransferReceived(address,uint256,bytes)":"461e0c21"}},"solidity/RecipientMock.sol:RecipientMock":{"code":"0x608060405234801561001057600080fd5b50610202806100206000396000f3fe6080604052600436106100225760003560e01c8063461e0c211461002e57600080fd5b3661002957005b600080fd5b61006461003c3660046100c8565b7f461e0c21000000000000000000000000000000000000000000000000000000009392505050565b6040517fffffffff00000000000000000000000000000000000000000000000000000000909116815260200160405180910390f35b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6000806000606084860312156100dd57600080fd5b833573ffffffffffffffffffffffffffffffffffffffff8116811461010157600080fd5b925060208401359150604084013567ffffffffffffffff8082111561012557600080fd5b818601915086601f83011261013957600080fd5b81358181111561014b5761014b610099565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f0116810190838211818310171561019157610191610099565b816040528281528960208487010111156101aa57600080fd5b826020860160208301376000602084830101528095505050505050925092509256fea2646970667358221220f1a74d56eefc9976c67d52f3119adaca862e91740662087e97a8e47c248fbb1d64736f6c63430008140033","runtime-code":"0x6080604052600436106100225760003560e01c8063461e0c211461002e57600080fd5b3661002957005b600080fd5b61006461003c3660046100c8565b7f461e0c21000000000000000000000000000000000000000000000000000000009392505050565b6040517fffffffff00000000000000000000000000000000000000000000000000000000909116815260200160405180910390f35b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6000806000606084860312156100dd57600080fd5b833573ffffffffffffffffffffffffffffffffffffffff8116811461010157600080fd5b925060208401359150604084013567ffffffffffffffff8082111561012557600080fd5b818601915086601f83011261013957600080fd5b81358181111561014b5761014b610099565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f0116810190838211818310171561019157610191610099565b816040528281528960208487010111156101aa57600080fd5b826020860160208301376000602084830101528095505050505050925092509256fea2646970667358221220f1a74d56eefc9976c67d52f3119adaca862e91740662087e97a8e47c248fbb1d64736f6c63430008140033","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\n// contracts/interfaces/IFastBridgeRecipient.sol\n\ninterface IFastBridgeRecipient {\n function fastBridgeTransferReceived(\n address token,\n uint256 amount,\n bytes memory callParams\n )\n external\n payable\n returns (bytes4);\n}\n\n// test/mocks/RecipientMock.sol\n\n/// @notice Recipient mock for testing purposes. DO NOT USE IN PRODUCTION.\ncontract RecipientMock is IFastBridgeRecipient {\n /// @notice Mock needs to accept ETH\n receive() external payable {}\n\n /// @notice Minimal viable implementation of the fastBridgeTransferReceived hook.\n function fastBridgeTransferReceived(address, uint256, bytes memory) external payable returns (bytes4) {\n return IFastBridgeRecipient.fastBridgeTransferReceived.selector;\n }\n}\n","language":"Solidity","languageVersion":"0.8.20","compilerVersion":"0.8.20","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"436:399:0:-:0;;;;;;;;;;;;;;;;;;;","srcMapRuntime":"436:399:0:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;651:182;;;;;;:::i;:::-;770:56;651:182;;;;;;;;;1627:66:1;1615:79;;;1597:98;;1585:2;1570:18;651:182:0;;;;;;;14:184:1;66:77;63:1;56:88;163:4;160:1;153:15;187:4;184:1;177:15;203:1245;289:6;297;305;358:2;346:9;337:7;333:23;329:32;326:52;;;374:1;371;364:12;326:52;413:9;400:23;463:42;456:5;452:54;445:5;442:65;432:93;;521:1;518;511:12;432:93;544:5;-1:-1:-1;596:2:1;581:18;;568:32;;-1:-1:-1;651:2:1;636:18;;623:32;674:18;704:14;;;701:34;;;731:1;728;721:12;701:34;769:6;758:9;754:22;744:32;;814:7;807:4;803:2;799:13;795:27;785:55;;836:1;833;826:12;785:55;872:2;859:16;894:2;890;887:10;884:36;;;900:18;;:::i;:::-;1034:2;1028:9;1096:4;1088:13;;939:66;1084:22;;;1108:2;1080:31;1076:40;1064:53;;;1132:18;;;1152:22;;;1129:46;1126:72;;;1178:18;;:::i;:::-;1218:10;1214:2;1207:22;1253:2;1245:6;1238:18;1293:7;1288:2;1283;1279;1275:11;1271:20;1268:33;1265:53;;;1314:1;1311;1304:12;1265:53;1370:2;1365;1361;1357:11;1352:2;1344:6;1340:15;1327:46;1415:1;1410:2;1405;1397:6;1393:15;1389:24;1382:35;1436:6;1426:16;;;;;;;203:1245;;;;;:::o","abiDefinition":[{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"bytes","name":"","type":"bytes"}],"name":"fastBridgeTransferReceived","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"payable","type":"function"},{"stateMutability":"payable","type":"receive"}],"userDoc":{"kind":"user","methods":{"fastBridgeTransferReceived(address,uint256,bytes)":{"notice":"Minimal viable implementation of the fastBridgeTransferReceived hook."}},"notice":"Recipient mock for testing purposes. DO NOT USE IN PRODUCTION.","version":1},"developerDoc":{"kind":"dev","methods":{},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.20+commit.a1b79de6\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"name\":\"fastBridgeTransferReceived\",\"outputs\":[{\"internalType\":\"bytes4\",\"name\":\"\",\"type\":\"bytes4\"}],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"stateMutability\":\"payable\",\"type\":\"receive\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"fastBridgeTransferReceived(address,uint256,bytes)\":{\"notice\":\"Minimal viable implementation of the fastBridgeTransferReceived hook.\"}},\"notice\":\"Recipient mock for testing purposes. DO NOT USE IN PRODUCTION.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/RecipientMock.sol\":\"RecipientMock\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/RecipientMock.sol\":{\"keccak256\":\"0xb8f940be952dc310c5d546785516c6d77f8abe7f6a852ee6ab4b3f1c33534b41\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://fb32a814c5a9088d1881eec57e12c3ebe91503be5b6be1c0c212b46bdbca89a7\",\"dweb:/ipfs/QmTQFfCjLPqVsxw7B6c4CNZMbtKJrg6mctRsTwaXqVDeLe\"]}},\"version\":1}"},"hashes":{"fastBridgeTransferReceived(address,uint256,bytes)":"461e0c21"}}} \ No newline at end of file diff --git a/services/rfq/contracts/testcontracts/recipientmock/recipientmock.metadata.go b/services/rfq/contracts/testcontracts/recipientmock/recipientmock.metadata.go new file mode 100644 index 0000000000..b1d05a6ee0 --- /dev/null +++ b/services/rfq/contracts/testcontracts/recipientmock/recipientmock.metadata.go @@ -0,0 +1,25 @@ +// Code generated by synapse abigen DO NOT EDIT. +package recipientmock + +import ( + _ "embed" + "encoding/json" + "github.com/ethereum/go-ethereum/common/compiler" +) + +// rawContracts are the json we use to derive the processed contracts +// +//go:embed recipientmock.contractinfo.json +var rawContracts []byte + +// Contracts are unmarshalled on start +var Contracts map[string]*compiler.Contract + +func init() { + // load contract metadata + var err error + err = json.Unmarshal(rawContracts, &Contracts) + if err != nil { + panic(err) + } +} diff --git a/services/rfq/testutil/contracttype.go b/services/rfq/testutil/contracttype.go index 5cf16d3c14..a1d82ccbcf 100644 --- a/services/rfq/testutil/contracttype.go +++ b/services/rfq/testutil/contracttype.go @@ -8,6 +8,7 @@ import ( "github.com/synapsecns/sanguine/services/rfq/contracts/testcontracts/dai" "github.com/synapsecns/sanguine/services/rfq/contracts/testcontracts/fastbridgemock" "github.com/synapsecns/sanguine/services/rfq/contracts/testcontracts/mockerc20" + "github.com/synapsecns/sanguine/services/rfq/contracts/testcontracts/recipientmock" "github.com/synapsecns/sanguine/services/rfq/contracts/testcontracts/usdc" "github.com/synapsecns/sanguine/services/rfq/contracts/testcontracts/weth9" ) @@ -55,6 +56,8 @@ const ( // FastBridgeMockType is a mock contract for testing fast bridge interactions // TODO: rename contract to MockFastBridge. FastBridgeMockType // FastBridgeMock + // RecipientMockType is a mock contract for testing fast bridge interactions + RecipientMockType // RecipientMock // WETH9Type is the weth 9 contract. WETH9Type // WETH9 // USDTType is the tether type. @@ -95,6 +98,8 @@ func (c contractTypeImpl) ContractInfo() *compiler.Contract { return mockerc20.Contracts["solidity/MockERC20.sol:MockERC20"] case FastBridgeMockType: return fastbridgemock.Contracts["solidity/FastBridgeMock.sol:FastBridgeMock"] + case RecipientMockType: + return recipientmock.Contracts["solidity/RecipientMock.sol:RecipientMock"] case WETH9Type: return weth9.Contracts["/solidity/WETH9.sol:WETH9"] case USDTType: diff --git a/services/rfq/testutil/contracttypeimpl_string.go b/services/rfq/testutil/contracttypeimpl_string.go index 662533a3be..ea177a0db3 100644 --- a/services/rfq/testutil/contracttypeimpl_string.go +++ b/services/rfq/testutil/contracttypeimpl_string.go @@ -11,15 +11,16 @@ func _() { _ = x[FastBridgeType-1] _ = x[MockERC20Type-2] _ = x[FastBridgeMockType-3] - _ = x[WETH9Type-4] - _ = x[USDTType-5] - _ = x[USDCType-6] - _ = x[DAIType-7] + _ = x[RecipientMockType-4] + _ = x[WETH9Type-5] + _ = x[USDTType-6] + _ = x[USDCType-7] + _ = x[DAIType-8] } -const _contractTypeImpl_name = "FastBridgeMockERC20FastBridgeMockWETH9USDTUSDCDAI" +const _contractTypeImpl_name = "FastBridgeMockERC20FastBridgeMockRecipientMockWETH9USDTUSDCDAI" -var _contractTypeImpl_index = [...]uint8{0, 10, 19, 33, 38, 42, 46, 49} +var _contractTypeImpl_index = [...]uint8{0, 10, 19, 33, 46, 51, 55, 59, 62} func (i contractTypeImpl) String() string { i -= 1 diff --git a/services/rfq/testutil/deployers.go b/services/rfq/testutil/deployers.go index 1d046b7424..0921cdddd2 100644 --- a/services/rfq/testutil/deployers.go +++ b/services/rfq/testutil/deployers.go @@ -16,6 +16,7 @@ import ( "github.com/synapsecns/sanguine/ethergo/manager" "github.com/synapsecns/sanguine/services/rfq/contracts/fastbridgev2" "github.com/synapsecns/sanguine/services/rfq/contracts/testcontracts/fastbridgemock" + "github.com/synapsecns/sanguine/services/rfq/contracts/testcontracts/recipientmock" ) // DeployManager wraps DeployManager and allows typed contract handles to be returned. @@ -27,7 +28,7 @@ type DeployManager struct { func NewDeployManager(t *testing.T) *DeployManager { t.Helper() - parentManager := manager.NewDeployerManager(t, NewFastBridgeDeployer, NewMockERC20Deployer, NewMockFastBridgeDeployer, NewWETH9Deployer, NewUSDTDeployer, NewUSDCDeployer, NewDAIDeployer) + parentManager := manager.NewDeployerManager(t, NewFastBridgeDeployer, NewMockERC20Deployer, NewMockFastBridgeDeployer, NewRecipientMockDeployer, NewWETH9Deployer, NewUSDTDeployer, NewUSDCDeployer, NewDAIDeployer) return &DeployManager{parentManager} } @@ -127,7 +128,7 @@ type MockFastBridgeDeployer struct { // NewMockFastBridgeDeployer deploys a mock fast bridge contract. func NewMockFastBridgeDeployer(registry deployer.GetOnlyContractRegistry, backend backends.SimulatedTestBackend) deployer.ContractDeployer { return MockFastBridgeDeployer{ - deployer.NewSimpleDeployer(registry, backend, FastBridgeMockType), + deployer.NewSimpleDeployer(registry, backend, RecipientMockType), } } @@ -139,3 +140,24 @@ func (m MockFastBridgeDeployer) Deploy(ctx context.Context) (contracts.DeployedC return fastbridgemock.NewFastBridgeMockRef(address, backend) }) } + +// RecipientMockDeployer deploys a mock recipient contract for testing. +type RecipientMockDeployer struct { + *deployer.BaseDeployer +} + +// NewRecipientMockDeployer deploys a mock recipient contract. +func NewRecipientMockDeployer(registry deployer.GetOnlyContractRegistry, backend backends.SimulatedTestBackend) deployer.ContractDeployer { + return RecipientMockDeployer{ + deployer.NewSimpleDeployer(registry, backend, RecipientMockType), + } +} + +// Deploy deploys the recipient mock contract. +func (m RecipientMockDeployer) Deploy(ctx context.Context) (contracts.DeployedContract, error) { + return m.DeploySimpleContract(ctx, func(transactOps *bind.TransactOpts, backend bind.ContractBackend) (common.Address, *types.Transaction, interface{}, error) { + return recipientmock.DeployRecipientMock(transactOps, backend) + }, func(address common.Address, backend bind.ContractBackend) (interface{}, error) { + return recipientmock.NewRecipientMockRef(address, backend) + }) +} diff --git a/services/rfq/testutil/typecast.go b/services/rfq/testutil/typecast.go index 8d5280c35f..6ba1f612e2 100644 --- a/services/rfq/testutil/typecast.go +++ b/services/rfq/testutil/typecast.go @@ -10,6 +10,7 @@ import ( "github.com/synapsecns/sanguine/services/rfq/contracts/testcontracts/dai" "github.com/synapsecns/sanguine/services/rfq/contracts/testcontracts/fastbridgemock" "github.com/synapsecns/sanguine/services/rfq/contracts/testcontracts/mockerc20" + "github.com/synapsecns/sanguine/services/rfq/contracts/testcontracts/recipientmock" "github.com/synapsecns/sanguine/services/rfq/contracts/testcontracts/usdc" "github.com/synapsecns/sanguine/services/rfq/contracts/testcontracts/usdt" "github.com/synapsecns/sanguine/services/rfq/contracts/testcontracts/weth9" @@ -36,6 +37,13 @@ func (d *DeployManager) GetMockFastBridge(ctx context.Context, backend backends. return manager.GetContract[*fastbridgemock.FastBridgeMockRef](ctx, d.T(), d, backend, FastBridgeMockType) } +// GetMockRecipient gets the mock recipient. +func (d *DeployManager) GetRecipientMock(ctx context.Context, backend backends.SimulatedTestBackend) (contract contracts.DeployedContract, handle *recipientmock.RecipientMockRef) { + d.T().Helper() + + return manager.GetContract[*recipientmock.RecipientMockRef](ctx, d.T(), d, backend, RecipientMockType) +} + // GetWETH9 gets the weth9 contract. func (d *DeployManager) GetWETH9(ctx context.Context, backend backends.SimulatedTestBackend) (contract contracts.DeployedContract, handle *weth9.Weth9Ref) { d.T().Helper() From f456bb79306701fb298e4653d99f1b2d57e80592 Mon Sep 17 00:00:00 2001 From: Daniel Wasserman Date: Wed, 9 Oct 2024 11:52:52 -0500 Subject: [PATCH 26/85] Feat: add TestUSDCtoUSDCWithCallData --- services/rfq/e2e/rfq_test.go | 125 ++++++++++++++++++++++++++++ services/rfq/e2e/setup_test.go | 18 ++++ services/rfq/relayer/chain/chain.go | 8 +- 3 files changed, 146 insertions(+), 5 deletions(-) diff --git a/services/rfq/e2e/rfq_test.go b/services/rfq/e2e/rfq_test.go index 01d6b84f4f..c861876913 100644 --- a/services/rfq/e2e/rfq_test.go +++ b/services/rfq/e2e/rfq_test.go @@ -393,6 +393,131 @@ func (i *IntegrationSuite) TestETHtoETH() { }) } +func (i *IntegrationSuite) TestUSDCtoUSDCWithCallData() { + // start the relayer and guard + go func() { + _ = i.relayer.Start(i.GetTestContext()) + }() + go func() { + _ = i.guard.Start(i.GetTestContext()) + }() + + // load token contracts + const startAmount = 1000 + const rfqAmount = 900 + opts := i.destBackend.GetTxContext(i.GetTestContext(), nil) + destUSDC, destUSDCHandle := i.cctpDeployManager.GetMockMintBurnTokenType(i.GetTestContext(), i.destBackend) + realStartAmount, err := testutil.AdjustAmount(i.GetTestContext(), big.NewInt(startAmount), destUSDC.ContractHandle()) + i.NoError(err) + realRFQAmount, err := testutil.AdjustAmount(i.GetTestContext(), big.NewInt(rfqAmount), destUSDC.ContractHandle()) + i.NoError(err) + + // add initial usdc to relayer on destination + tx, err := destUSDCHandle.MintPublic(opts.TransactOpts, i.relayerWallet.Address(), realStartAmount) + i.Nil(err) + i.destBackend.WaitForConfirmation(i.GetTestContext(), tx) + i.Approve(i.destBackend, destUSDC, i.relayerWallet) + + // add initial USDC to relayer on origin + optsOrigin := i.originBackend.GetTxContext(i.GetTestContext(), nil) + originUSDC, originUSDCHandle := i.cctpDeployManager.GetMockMintBurnTokenType(i.GetTestContext(), i.originBackend) + tx, err = originUSDCHandle.MintPublic(optsOrigin.TransactOpts, i.relayerWallet.Address(), realStartAmount) + i.Nil(err) + i.originBackend.WaitForConfirmation(i.GetTestContext(), tx) + i.Approve(i.originBackend, originUSDC, i.relayerWallet) + + // add initial USDC to user on origin + tx, err = originUSDCHandle.MintPublic(optsOrigin.TransactOpts, i.userWallet.Address(), realRFQAmount) + i.Nil(err) + i.originBackend.WaitForConfirmation(i.GetTestContext(), tx) + i.Approve(i.originBackend, originUSDC, i.userWallet) + + // non decimal adjusted user want amount + // now our friendly user is going to check the quote and send us some USDC on the origin chain. + i.Eventually(func() bool { + // first he's gonna check the quotes. + userAPIClient, err := client.NewAuthenticatedClient(metrics.Get(), i.apiServer, localsigner.NewSigner(i.userWallet.PrivateKey())) + i.NoError(err) + + allQuotes, err := userAPIClient.GetAllQuotes(i.GetTestContext()) + i.NoError(err) + + // let's figure out the amount of usdc we need + for _, quote := range allQuotes { + if common.HexToAddress(quote.DestTokenAddr) == destUSDC.Address() { + destAmountBigInt, _ := new(big.Int).SetString(quote.DestAmount, 10) + if destAmountBigInt.Cmp(realRFQAmount) > 0 { + // we found our quote! + // now we can move on + return true + } + } + } + return false + }) + + // now we can send the money + _, originFastBridge := i.manager.GetFastBridge(i.GetTestContext(), i.originBackend) + _, destRecipient := i.manager.GetRecipientMock(i.GetTestContext(), i.destBackend) + auth := i.originBackend.GetTxContext(i.GetTestContext(), i.userWallet.AddressPtr()) + params := fastbridgev2.IFastBridgeBridgeParams{ + DstChainId: uint32(i.destBackend.GetChainID()), + Sender: i.userWallet.Address(), + To: destRecipient.Address(), + OriginToken: originUSDC.Address(), + SendChainGas: true, + DestToken: destUSDC.Address(), + OriginAmount: realRFQAmount, + DestAmount: new(big.Int).Sub(realRFQAmount, big.NewInt(10_000_000)), + Deadline: new(big.Int).SetInt64(time.Now().Add(time.Hour * 24).Unix()), + } + paramsV2 := fastbridgev2.IFastBridgeV2BridgeParamsV2{ + QuoteRelayer: i.relayerWallet.Address(), + QuoteExclusivitySeconds: new(big.Int).SetInt64(30), + CallParams: []byte("Hello, world!"), + CallValue: big.NewInt(1_337_420), + } + tx, err = originFastBridge.Bridge0(auth.TransactOpts, params, paramsV2) + i.NoError(err) + i.originBackend.WaitForConfirmation(i.GetTestContext(), tx) + + // TODO: this, but cleaner + anvilClient, err := anvil.Dial(i.GetTestContext(), i.originBackend.RPCAddress()) + i.NoError(err) + + go func() { + for { + select { + case <-i.GetTestContext().Done(): + return + case <-time.After(time.Second * 4): + // increase time by 30 mintutes every second, should be enough to get us a fastish e2e test + // we don't need to worry about deadline since we're only doing this on origin + err = anvilClient.IncreaseTime(i.GetTestContext(), 60*30) + i.NoError(err) + + // because can claim works on last block timestamp, we need to do something + err = anvilClient.Mine(i.GetTestContext(), 1) + i.NoError(err) + } + } + + }() + + i.Eventually(func() bool { + destUSDCBalance, err := destUSDCHandle.BalanceOf(&bind.CallOpts{Context: i.GetTestContext()}, destRecipient.Address()) + i.NoError(err) + return destUSDCBalance.Cmp(big.NewInt(0)) > 0 + }) + + // i.Eventually(func() bool { + // // verify that the guard has marked the tx as validated + // results, err := i.guardStore.GetPendingProvensByStatus(i.GetTestContext(), guarddb.Validated) + // i.NoError(err) + // return len(results) == 1 + // }) +} + func (i *IntegrationSuite) TestDispute() { // start the guard go func() { diff --git a/services/rfq/e2e/setup_test.go b/services/rfq/e2e/setup_test.go index d95366642d..c3a2cf9e7b 100644 --- a/services/rfq/e2e/setup_test.go +++ b/services/rfq/e2e/setup_test.go @@ -138,6 +138,7 @@ func (i *IntegrationSuite) setupBackends() { i.omniClient = omnirpcClient.NewOmnirpcClient(i.omniServer, i.metrics, omnirpcClient.WithCaptureReqRes()) i.setupCCTP() + i.setupRecipientMock() } // setupBe sets up one backend @@ -222,6 +223,23 @@ func (i *IntegrationSuite) setupCCTP() { } } +func (i *IntegrationSuite) setupRecipientMock() { + testBackends := core.ToSlice(i.originBackend, i.destBackend) + + for _, b := range testBackends { + backend := b + err := retry.WithBackoff(i.GetTestContext(), func(_ context.Context) (err error) { + handle := i.manager.Get(i.GetTestContext(), backend, testutil.RecipientMockType) + err = i.waitForContractDeployment(i.GetTestContext(), backend, handle.Address()) + if err != nil { + return fmt.Errorf("failed to wait for contract deployment: %w", err) + } + return nil + }, retry.WithMaxTotalTime(30*time.Second)) + i.NoError(err) + } +} + // addressToBytes32 converts an address to a bytes32. func addressToBytes32(addr common.Address) [32]byte { var buf [32]byte diff --git a/services/rfq/relayer/chain/chain.go b/services/rfq/relayer/chain/chain.go index 7f29843ad2..aee14e9096 100644 --- a/services/rfq/relayer/chain/chain.go +++ b/services/rfq/relayer/chain/chain.go @@ -77,12 +77,10 @@ func (c Chain) SubmitRelay(ctx context.Context, request reldb.QuoteRequest) (uin // Check to see if ETH should be sent to destination if util.IsGasToken(request.Transaction.DestToken) { gasAmount = request.Transaction.DestAmount - } else if request.Transaction.CallValue != nil && request.Transaction.CallValue.Sign() > 0 { - gasAmount, err = c.Bridge.ChainGasAmount(&bind.CallOpts{Context: ctx}) - if err != nil { - return 0, nil, fmt.Errorf("could not get chain gas amount: %w", err) - } + } else if request.Transaction.CallValue != nil { + gasAmount = request.Transaction.CallValue } + //TODO: handle SendChainGas case when TransactionV1 is in QuoteRequest nonce, err := c.SubmitTransaction(ctx, func(transactor *bind.TransactOpts) (tx *types.Transaction, err error) { transactor.Value = core.CopyBigInt(gasAmount) From de621a73b0079c45035d07e0853b3619c9a503e8 Mon Sep 17 00:00:00 2001 From: Daniel Wasserman Date: Wed, 9 Oct 2024 11:53:20 -0500 Subject: [PATCH 27/85] Rename: TestArbitraryCall --- services/rfq/e2e/rfq_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/rfq/e2e/rfq_test.go b/services/rfq/e2e/rfq_test.go index c861876913..772b3c4f2a 100644 --- a/services/rfq/e2e/rfq_test.go +++ b/services/rfq/e2e/rfq_test.go @@ -393,7 +393,7 @@ func (i *IntegrationSuite) TestETHtoETH() { }) } -func (i *IntegrationSuite) TestUSDCtoUSDCWithCallData() { +func (i *IntegrationSuite) TestArbitraryCall() { // start the relayer and guard go func() { _ = i.relayer.Start(i.GetTestContext()) From e3c1604e06a6c3919f4cfe60550d6ecd58450191 Mon Sep 17 00:00:00 2001 From: Daniel Wasserman Date: Wed, 9 Oct 2024 12:01:28 -0500 Subject: [PATCH 28/85] Feat: add TransactionV1 in QuoteRequest struct for access to SendChainGas --- services/rfq/relayer/chain/chain.go | 6 +++++- services/rfq/relayer/reldb/base/model.go | 6 ++++++ services/rfq/relayer/reldb/db.go | 5 ++++- services/rfq/relayer/service/handlers.go | 14 ++++++++++++++ 4 files changed, 29 insertions(+), 2 deletions(-) diff --git a/services/rfq/relayer/chain/chain.go b/services/rfq/relayer/chain/chain.go index aee14e9096..99e72ec180 100644 --- a/services/rfq/relayer/chain/chain.go +++ b/services/rfq/relayer/chain/chain.go @@ -79,8 +79,12 @@ func (c Chain) SubmitRelay(ctx context.Context, request reldb.QuoteRequest) (uin gasAmount = request.Transaction.DestAmount } else if request.Transaction.CallValue != nil { gasAmount = request.Transaction.CallValue + } else if request.TransactionV1.SendChainGas { + gasAmount, err = c.Bridge.ChainGasAmount(&bind.CallOpts{Context: ctx}) + if err != nil { + return 0, nil, fmt.Errorf("could not get chain gas amount: %w", err) + } } - //TODO: handle SendChainGas case when TransactionV1 is in QuoteRequest nonce, err := c.SubmitTransaction(ctx, func(transactor *bind.TransactOpts) (tx *types.Transaction, err error) { transactor.Value = core.CopyBigInt(gasAmount) diff --git a/services/rfq/relayer/reldb/base/model.go b/services/rfq/relayer/reldb/base/model.go index c61db88385..1ae4a38ec8 100644 --- a/services/rfq/relayer/reldb/base/model.go +++ b/services/rfq/relayer/reldb/base/model.go @@ -93,6 +93,8 @@ type RequestForQuote struct { ExclusivityEndTime time.Time // CallParams is the call params CallParams []byte + // SendChainGas is whether the relay should send gas to the destination chain + SendChainGas bool // Status is the current status of the event Status reldb.QuoteRequestStatus // BlockNumber is the block number of the event @@ -146,6 +148,7 @@ func FromQuoteRequest(request reldb.QuoteRequest) RequestForQuote { CallParams: request.Transaction.CallParams, Deadline: time.Unix(int64(request.Transaction.Deadline.Uint64()), 0), OriginNonce: int(request.Transaction.Nonce.Uint64()), + SendChainGas: request.TransactionV1.SendChainGas, Status: request.Status, BlockNumber: request.BlockNumber, RelayNonce: request.RelayNonce, @@ -219,6 +222,9 @@ func (r RequestForQuote) ToQuoteRequest() (*reldb.QuoteRequest, error) { RawRequest: req, Sender: common.HexToAddress(r.OriginSender), BlockNumber: r.BlockNumber, + TransactionV1: fastbridgev2.IFastBridgeBridgeTransaction{ + SendChainGas: r.SendChainGas, + }, Transaction: fastbridgev2.IFastBridgeV2BridgeTransactionV2{ OriginChainId: r.OriginChainID, DestChainId: r.DestChainID, diff --git a/services/rfq/relayer/reldb/db.go b/services/rfq/relayer/reldb/db.go index 441129ea32..8df8260bee 100644 --- a/services/rfq/relayer/reldb/db.go +++ b/services/rfq/relayer/reldb/db.go @@ -81,7 +81,10 @@ type QuoteRequest struct { DestTokenDecimals uint8 TransactionID [32]byte Sender common.Address - Transaction fastbridgev2.IFastBridgeV2BridgeTransactionV2 + // For now, SendChainGas is the only distinction between v1 and v2, + // so no need to duplicate other fields within TransactionV1. + TransactionV1 fastbridgev2.IFastBridgeBridgeTransaction + Transaction fastbridgev2.IFastBridgeV2BridgeTransactionV2 // Status is the quote request status Status QuoteRequestStatus OriginTxHash common.Hash diff --git a/services/rfq/relayer/service/handlers.go b/services/rfq/relayer/service/handlers.go index 0da15fdbf5..378f33789f 100644 --- a/services/rfq/relayer/service/handlers.go +++ b/services/rfq/relayer/service/handlers.go @@ -86,6 +86,19 @@ func (r *Relayer) handleBridgeRequestedLog(parentCtx context.Context, req *fastb return fmt.Errorf("could not make call: %w", err) } + var bridgeTxV1 fastbridgev2.IFastBridgeBridgeTransaction + call = func(ctx context.Context) error { + bridgeTxV1, err = fastBridge.GetBridgeTransaction(&bind.CallOpts{Context: ctx}, req.Request) + if err != nil { + return fmt.Errorf("could not get bridge transaction: %w", err) + } + return nil + } + err = retry.WithBackoff(ctx, call, retry.WithMaxTotalTime(maxRPCRetryTime)) + if err != nil { + return fmt.Errorf("could not make call: %w", err) + } + // TODO: you can just pull these out of inventory. If they don't exist mark as invalid. originDecimals, destDecimals, err := r.getDecimalsFromBridgeTx(ctx, bridgeTx) // can't use errors.is here @@ -105,6 +118,7 @@ func (r *Relayer) handleBridgeRequestedLog(parentCtx context.Context, req *fastb DestTokenDecimals: *destDecimals, TransactionID: req.TransactionId, Sender: req.Sender, + TransactionV1: bridgeTxV1, Transaction: bridgeTx, Status: reldb.Seen, OriginTxHash: req.Raw.TxHash, From bff4f72a4339ec8ea9964c151568ca6fb15be932 Mon Sep 17 00:00:00 2001 From: Daniel Wasserman Date: Wed, 9 Oct 2024 12:11:46 -0500 Subject: [PATCH 29/85] Cleanup: bridge tx fetching --- services/rfq/relayer/service/handlers.go | 70 +++++++++++++----------- 1 file changed, 39 insertions(+), 31 deletions(-) diff --git a/services/rfq/relayer/service/handlers.go b/services/rfq/relayer/service/handlers.go index 378f33789f..f309106a99 100644 --- a/services/rfq/relayer/service/handlers.go +++ b/services/rfq/relayer/service/handlers.go @@ -12,6 +12,7 @@ import ( "github.com/ethereum/go-ethereum/core/types" "github.com/synapsecns/sanguine/core/metrics" "github.com/synapsecns/sanguine/core/retry" + "github.com/synapsecns/sanguine/ethergo/client" "github.com/synapsecns/sanguine/services/rfq/api/model" "github.com/synapsecns/sanguine/services/rfq/contracts/fastbridgev2" "github.com/synapsecns/sanguine/services/rfq/relayer/inventory" @@ -68,39 +69,13 @@ func (r *Relayer) handleBridgeRequestedLog(parentCtx context.Context, req *fastb return fmt.Errorf("could not get correct omnirpc client: %w", err) } - fastBridge, err := fastbridgev2.NewFastBridgeV2Ref(req.Raw.Address, originClient) - if err != nil { - return fmt.Errorf("could not get correct fast bridge: %w", err) - } - - var bridgeTx fastbridgev2.IFastBridgeV2BridgeTransactionV2 - call := func(ctx context.Context) error { - bridgeTx, err = fastBridge.GetBridgeTransactionV2(&bind.CallOpts{Context: ctx}, req.Request) - if err != nil { - return fmt.Errorf("could not get bridge transaction: %w", err) - } - return nil - } - err = retry.WithBackoff(ctx, call, retry.WithMaxTotalTime(maxRPCRetryTime)) - if err != nil { - return fmt.Errorf("could not make call: %w", err) - } - - var bridgeTxV1 fastbridgev2.IFastBridgeBridgeTransaction - call = func(ctx context.Context) error { - bridgeTxV1, err = fastBridge.GetBridgeTransaction(&bind.CallOpts{Context: ctx}, req.Request) - if err != nil { - return fmt.Errorf("could not get bridge transaction: %w", err) - } - return nil - } - err = retry.WithBackoff(ctx, call, retry.WithMaxTotalTime(maxRPCRetryTime)) + txV1, txV2, err := r.getBridgeTxs(ctx, req, originClient) if err != nil { - return fmt.Errorf("could not make call: %w", err) + return fmt.Errorf("could not get bridge txs: %w", err) } // TODO: you can just pull these out of inventory. If they don't exist mark as invalid. - originDecimals, destDecimals, err := r.getDecimalsFromBridgeTx(ctx, bridgeTx) + originDecimals, destDecimals, err := r.getDecimalsFromBridgeTx(ctx, txV2) // can't use errors.is here if err != nil && strings.Contains(err.Error(), "no contract code at given address") { logger.Warnf("invalid token, skipping") @@ -118,8 +93,8 @@ func (r *Relayer) handleBridgeRequestedLog(parentCtx context.Context, req *fastb DestTokenDecimals: *destDecimals, TransactionID: req.TransactionId, Sender: req.Sender, - TransactionV1: bridgeTxV1, - Transaction: bridgeTx, + TransactionV1: txV1, + Transaction: txV2, Status: reldb.Seen, OriginTxHash: req.Raw.TxHash, } @@ -144,6 +119,39 @@ func (r *Relayer) handleBridgeRequestedLog(parentCtx context.Context, req *fastb return nil } +func (r *Relayer) getBridgeTxs(ctx context.Context, req *fastbridgev2.FastBridgeV2BridgeRequested, originClient client.EVM) (txV1 fastbridgev2.IFastBridgeBridgeTransaction, txV2 fastbridgev2.IFastBridgeV2BridgeTransactionV2, err error) { + fastBridge, err := fastbridgev2.NewFastBridgeV2Ref(req.Raw.Address, originClient) + if err != nil { + return txV1, txV2, fmt.Errorf("could not get correct fast bridge: %w", err) + } + + calls := []func(ctx context.Context) error{ + func(ctx context.Context) error { + txV1, err = fastBridge.GetBridgeTransaction(&bind.CallOpts{Context: ctx}, req.Request) + if err != nil { + return fmt.Errorf("could not get bridge transaction: %w", err) + } + return nil + }, + func(ctx context.Context) error { + txV2, err = fastBridge.GetBridgeTransactionV2(&bind.CallOpts{Context: ctx}, req.Request) + if err != nil { + return fmt.Errorf("could not get bridge transaction: %w", err) + } + return nil + }, + } + + for _, call := range calls { + err = retry.WithBackoff(ctx, call, retry.WithMaxTotalTime(maxRPCRetryTime)) + if err != nil { + return txV1, txV2, fmt.Errorf("could not make call: %w", err) + } + } + + return txV1, txV2, nil +} + // handleSeen handles the seen status. // Step 2: CommittedPending // Possible Errors: WillNotProcess, NotEnoughInventory From 4ed813b57f2433b9caaca40ddaf6e70c29fe1949 Mon Sep 17 00:00:00 2001 From: Daniel Wasserman Date: Wed, 9 Oct 2024 12:14:14 -0500 Subject: [PATCH 30/85] Cleanup: remove guard check for now --- services/rfq/e2e/rfq_test.go | 7 ------- 1 file changed, 7 deletions(-) diff --git a/services/rfq/e2e/rfq_test.go b/services/rfq/e2e/rfq_test.go index 772b3c4f2a..76d5d33eac 100644 --- a/services/rfq/e2e/rfq_test.go +++ b/services/rfq/e2e/rfq_test.go @@ -509,13 +509,6 @@ func (i *IntegrationSuite) TestArbitraryCall() { i.NoError(err) return destUSDCBalance.Cmp(big.NewInt(0)) > 0 }) - - // i.Eventually(func() bool { - // // verify that the guard has marked the tx as validated - // results, err := i.guardStore.GetPendingProvensByStatus(i.GetTestContext(), guarddb.Validated) - // i.NoError(err) - // return len(results) == 1 - // }) } func (i *IntegrationSuite) TestDispute() { From 5b6ec120272e6a14f0e239925b7a36786e458c29 Mon Sep 17 00:00:00 2001 From: Daniel Wasserman Date: Fri, 11 Oct 2024 13:58:00 -0500 Subject: [PATCH 31/85] Feat: add v2 of fastbridgemock --- .../fastbridgemockv2.abigen.go | 15215 ++++++++++++++++ .../fastbridgemockv2.contractinfo.json | 1 + .../fastbridgemockv2.metadata.go | 25 + .../fastbridgemockv2/generate.go | 3 + .../testcontracts/fastbridgemockv2/helper.go | 35 + 5 files changed, 15279 insertions(+) create mode 100644 services/rfq/contracts/testcontracts/fastbridgemockv2/fastbridgemockv2.abigen.go create mode 100644 services/rfq/contracts/testcontracts/fastbridgemockv2/fastbridgemockv2.contractinfo.json create mode 100644 services/rfq/contracts/testcontracts/fastbridgemockv2/fastbridgemockv2.metadata.go create mode 100644 services/rfq/contracts/testcontracts/fastbridgemockv2/generate.go create mode 100644 services/rfq/contracts/testcontracts/fastbridgemockv2/helper.go diff --git a/services/rfq/contracts/testcontracts/fastbridgemockv2/fastbridgemockv2.abigen.go b/services/rfq/contracts/testcontracts/fastbridgemockv2/fastbridgemockv2.abigen.go new file mode 100644 index 0000000000..31056fdacd --- /dev/null +++ b/services/rfq/contracts/testcontracts/fastbridgemockv2/fastbridgemockv2.abigen.go @@ -0,0 +1,15215 @@ +// Code generated - DO NOT EDIT. +// This file is a generated binding and any manual changes will be lost. + +package fastbridgemockv2 + +import ( + "errors" + "math/big" + "strings" + + ethereum "github.com/ethereum/go-ethereum" + "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/event" +) + +// Reference imports to suppress errors if they are not otherwise used. +var ( + _ = errors.New + _ = big.NewInt + _ = strings.NewReader + _ = ethereum.NotFound + _ = bind.Bind + _ = common.Big1 + _ = types.BloomLookup + _ = event.NewSubscription + _ = abi.ConvertType +) + +// IFastBridgeBridgeParams is an auto generated low-level Go binding around an user-defined struct. +type IFastBridgeBridgeParams struct { + DstChainId uint32 + Sender common.Address + To common.Address + OriginToken common.Address + DestToken common.Address + OriginAmount *big.Int + DestAmount *big.Int + SendChainGas bool + Deadline *big.Int +} + +// IFastBridgeBridgeTransaction is an auto generated low-level Go binding around an user-defined struct. +type IFastBridgeBridgeTransaction struct { + OriginChainId uint32 + DestChainId uint32 + OriginSender common.Address + DestRecipient common.Address + OriginToken common.Address + DestToken common.Address + OriginAmount *big.Int + DestAmount *big.Int + OriginFeeAmount *big.Int + SendChainGas bool + Deadline *big.Int + Nonce *big.Int +} + +// AccessControlMetaData contains all meta data concerning the AccessControl contract. +var AccessControlMetaData = &bind.MetaData{ + ABI: "[{\"inputs\":[],\"name\":\"AccessControlBadConfirmation\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"neededRole\",\"type\":\"bytes32\"}],\"name\":\"AccessControlUnauthorizedAccount\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"previousAdminRole\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"newAdminRole\",\"type\":\"bytes32\"}],\"name\":\"RoleAdminChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleGranted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleRevoked\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"DEFAULT_ADMIN_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"}],\"name\":\"getRoleAdmin\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"grantRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"hasRole\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"callerConfirmation\",\"type\":\"address\"}],\"name\":\"renounceRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"revokeRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes4\",\"name\":\"interfaceId\",\"type\":\"bytes4\"}],\"name\":\"supportsInterface\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"}]", + Sigs: map[string]string{ + "a217fddf": "DEFAULT_ADMIN_ROLE()", + "248a9ca3": "getRoleAdmin(bytes32)", + "2f2ff15d": "grantRole(bytes32,address)", + "91d14854": "hasRole(bytes32,address)", + "36568abe": "renounceRole(bytes32,address)", + "d547741f": "revokeRole(bytes32,address)", + "01ffc9a7": "supportsInterface(bytes4)", + }, +} + +// AccessControlABI is the input ABI used to generate the binding from. +// Deprecated: Use AccessControlMetaData.ABI instead. +var AccessControlABI = AccessControlMetaData.ABI + +// Deprecated: Use AccessControlMetaData.Sigs instead. +// AccessControlFuncSigs maps the 4-byte function signature to its string representation. +var AccessControlFuncSigs = AccessControlMetaData.Sigs + +// AccessControl is an auto generated Go binding around an Ethereum contract. +type AccessControl struct { + AccessControlCaller // Read-only binding to the contract + AccessControlTransactor // Write-only binding to the contract + AccessControlFilterer // Log filterer for contract events +} + +// AccessControlCaller is an auto generated read-only Go binding around an Ethereum contract. +type AccessControlCaller struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// AccessControlTransactor is an auto generated write-only Go binding around an Ethereum contract. +type AccessControlTransactor struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// AccessControlFilterer is an auto generated log filtering Go binding around an Ethereum contract events. +type AccessControlFilterer struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// AccessControlSession is an auto generated Go binding around an Ethereum contract, +// with pre-set call and transact options. +type AccessControlSession struct { + Contract *AccessControl // Generic contract binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// AccessControlCallerSession is an auto generated read-only Go binding around an Ethereum contract, +// with pre-set call options. +type AccessControlCallerSession struct { + Contract *AccessControlCaller // Generic contract caller binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session +} + +// AccessControlTransactorSession is an auto generated write-only Go binding around an Ethereum contract, +// with pre-set transact options. +type AccessControlTransactorSession struct { + Contract *AccessControlTransactor // Generic contract transactor binding to set the session for + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// AccessControlRaw is an auto generated low-level Go binding around an Ethereum contract. +type AccessControlRaw struct { + Contract *AccessControl // Generic contract binding to access the raw methods on +} + +// AccessControlCallerRaw is an auto generated low-level read-only Go binding around an Ethereum contract. +type AccessControlCallerRaw struct { + Contract *AccessControlCaller // Generic read-only contract binding to access the raw methods on +} + +// AccessControlTransactorRaw is an auto generated low-level write-only Go binding around an Ethereum contract. +type AccessControlTransactorRaw struct { + Contract *AccessControlTransactor // Generic write-only contract binding to access the raw methods on +} + +// NewAccessControl creates a new instance of AccessControl, bound to a specific deployed contract. +func NewAccessControl(address common.Address, backend bind.ContractBackend) (*AccessControl, error) { + contract, err := bindAccessControl(address, backend, backend, backend) + if err != nil { + return nil, err + } + return &AccessControl{AccessControlCaller: AccessControlCaller{contract: contract}, AccessControlTransactor: AccessControlTransactor{contract: contract}, AccessControlFilterer: AccessControlFilterer{contract: contract}}, nil +} + +// NewAccessControlCaller creates a new read-only instance of AccessControl, bound to a specific deployed contract. +func NewAccessControlCaller(address common.Address, caller bind.ContractCaller) (*AccessControlCaller, error) { + contract, err := bindAccessControl(address, caller, nil, nil) + if err != nil { + return nil, err + } + return &AccessControlCaller{contract: contract}, nil +} + +// NewAccessControlTransactor creates a new write-only instance of AccessControl, bound to a specific deployed contract. +func NewAccessControlTransactor(address common.Address, transactor bind.ContractTransactor) (*AccessControlTransactor, error) { + contract, err := bindAccessControl(address, nil, transactor, nil) + if err != nil { + return nil, err + } + return &AccessControlTransactor{contract: contract}, nil +} + +// NewAccessControlFilterer creates a new log filterer instance of AccessControl, bound to a specific deployed contract. +func NewAccessControlFilterer(address common.Address, filterer bind.ContractFilterer) (*AccessControlFilterer, error) { + contract, err := bindAccessControl(address, nil, nil, filterer) + if err != nil { + return nil, err + } + return &AccessControlFilterer{contract: contract}, nil +} + +// bindAccessControl binds a generic wrapper to an already deployed contract. +func bindAccessControl(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) { + parsed, err := AccessControlMetaData.GetAbi() + if err != nil { + return nil, err + } + return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil +} + +// Call invokes the (constant) contract method with params as input values and +// sets the output to result. The result type might be a single field for simple +// returns, a slice of interfaces for anonymous returns and a struct for named +// returns. +func (_AccessControl *AccessControlRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _AccessControl.Contract.AccessControlCaller.contract.Call(opts, result, method, params...) +} + +// Transfer initiates a plain transaction to move funds to the contract, calling +// its default method if one is available. +func (_AccessControl *AccessControlRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _AccessControl.Contract.AccessControlTransactor.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_AccessControl *AccessControlRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _AccessControl.Contract.AccessControlTransactor.contract.Transact(opts, method, params...) +} + +// Call invokes the (constant) contract method with params as input values and +// sets the output to result. The result type might be a single field for simple +// returns, a slice of interfaces for anonymous returns and a struct for named +// returns. +func (_AccessControl *AccessControlCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _AccessControl.Contract.contract.Call(opts, result, method, params...) +} + +// Transfer initiates a plain transaction to move funds to the contract, calling +// its default method if one is available. +func (_AccessControl *AccessControlTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _AccessControl.Contract.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_AccessControl *AccessControlTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _AccessControl.Contract.contract.Transact(opts, method, params...) +} + +// DEFAULTADMINROLE is a free data retrieval call binding the contract method 0xa217fddf. +// +// Solidity: function DEFAULT_ADMIN_ROLE() view returns(bytes32) +func (_AccessControl *AccessControlCaller) DEFAULTADMINROLE(opts *bind.CallOpts) ([32]byte, error) { + var out []interface{} + err := _AccessControl.contract.Call(opts, &out, "DEFAULT_ADMIN_ROLE") + + if err != nil { + return *new([32]byte), err + } + + out0 := *abi.ConvertType(out[0], new([32]byte)).(*[32]byte) + + return out0, err + +} + +// DEFAULTADMINROLE is a free data retrieval call binding the contract method 0xa217fddf. +// +// Solidity: function DEFAULT_ADMIN_ROLE() view returns(bytes32) +func (_AccessControl *AccessControlSession) DEFAULTADMINROLE() ([32]byte, error) { + return _AccessControl.Contract.DEFAULTADMINROLE(&_AccessControl.CallOpts) +} + +// DEFAULTADMINROLE is a free data retrieval call binding the contract method 0xa217fddf. +// +// Solidity: function DEFAULT_ADMIN_ROLE() view returns(bytes32) +func (_AccessControl *AccessControlCallerSession) DEFAULTADMINROLE() ([32]byte, error) { + return _AccessControl.Contract.DEFAULTADMINROLE(&_AccessControl.CallOpts) +} + +// GetRoleAdmin is a free data retrieval call binding the contract method 0x248a9ca3. +// +// Solidity: function getRoleAdmin(bytes32 role) view returns(bytes32) +func (_AccessControl *AccessControlCaller) GetRoleAdmin(opts *bind.CallOpts, role [32]byte) ([32]byte, error) { + var out []interface{} + err := _AccessControl.contract.Call(opts, &out, "getRoleAdmin", role) + + if err != nil { + return *new([32]byte), err + } + + out0 := *abi.ConvertType(out[0], new([32]byte)).(*[32]byte) + + return out0, err + +} + +// GetRoleAdmin is a free data retrieval call binding the contract method 0x248a9ca3. +// +// Solidity: function getRoleAdmin(bytes32 role) view returns(bytes32) +func (_AccessControl *AccessControlSession) GetRoleAdmin(role [32]byte) ([32]byte, error) { + return _AccessControl.Contract.GetRoleAdmin(&_AccessControl.CallOpts, role) +} + +// GetRoleAdmin is a free data retrieval call binding the contract method 0x248a9ca3. +// +// Solidity: function getRoleAdmin(bytes32 role) view returns(bytes32) +func (_AccessControl *AccessControlCallerSession) GetRoleAdmin(role [32]byte) ([32]byte, error) { + return _AccessControl.Contract.GetRoleAdmin(&_AccessControl.CallOpts, role) +} + +// HasRole is a free data retrieval call binding the contract method 0x91d14854. +// +// Solidity: function hasRole(bytes32 role, address account) view returns(bool) +func (_AccessControl *AccessControlCaller) HasRole(opts *bind.CallOpts, role [32]byte, account common.Address) (bool, error) { + var out []interface{} + err := _AccessControl.contract.Call(opts, &out, "hasRole", role, account) + + if err != nil { + return *new(bool), err + } + + out0 := *abi.ConvertType(out[0], new(bool)).(*bool) + + return out0, err + +} + +// HasRole is a free data retrieval call binding the contract method 0x91d14854. +// +// Solidity: function hasRole(bytes32 role, address account) view returns(bool) +func (_AccessControl *AccessControlSession) HasRole(role [32]byte, account common.Address) (bool, error) { + return _AccessControl.Contract.HasRole(&_AccessControl.CallOpts, role, account) +} + +// HasRole is a free data retrieval call binding the contract method 0x91d14854. +// +// Solidity: function hasRole(bytes32 role, address account) view returns(bool) +func (_AccessControl *AccessControlCallerSession) HasRole(role [32]byte, account common.Address) (bool, error) { + return _AccessControl.Contract.HasRole(&_AccessControl.CallOpts, role, account) +} + +// SupportsInterface is a free data retrieval call binding the contract method 0x01ffc9a7. +// +// Solidity: function supportsInterface(bytes4 interfaceId) view returns(bool) +func (_AccessControl *AccessControlCaller) SupportsInterface(opts *bind.CallOpts, interfaceId [4]byte) (bool, error) { + var out []interface{} + err := _AccessControl.contract.Call(opts, &out, "supportsInterface", interfaceId) + + if err != nil { + return *new(bool), err + } + + out0 := *abi.ConvertType(out[0], new(bool)).(*bool) + + return out0, err + +} + +// SupportsInterface is a free data retrieval call binding the contract method 0x01ffc9a7. +// +// Solidity: function supportsInterface(bytes4 interfaceId) view returns(bool) +func (_AccessControl *AccessControlSession) SupportsInterface(interfaceId [4]byte) (bool, error) { + return _AccessControl.Contract.SupportsInterface(&_AccessControl.CallOpts, interfaceId) +} + +// SupportsInterface is a free data retrieval call binding the contract method 0x01ffc9a7. +// +// Solidity: function supportsInterface(bytes4 interfaceId) view returns(bool) +func (_AccessControl *AccessControlCallerSession) SupportsInterface(interfaceId [4]byte) (bool, error) { + return _AccessControl.Contract.SupportsInterface(&_AccessControl.CallOpts, interfaceId) +} + +// GrantRole is a paid mutator transaction binding the contract method 0x2f2ff15d. +// +// Solidity: function grantRole(bytes32 role, address account) returns() +func (_AccessControl *AccessControlTransactor) GrantRole(opts *bind.TransactOpts, role [32]byte, account common.Address) (*types.Transaction, error) { + return _AccessControl.contract.Transact(opts, "grantRole", role, account) +} + +// GrantRole is a paid mutator transaction binding the contract method 0x2f2ff15d. +// +// Solidity: function grantRole(bytes32 role, address account) returns() +func (_AccessControl *AccessControlSession) GrantRole(role [32]byte, account common.Address) (*types.Transaction, error) { + return _AccessControl.Contract.GrantRole(&_AccessControl.TransactOpts, role, account) +} + +// GrantRole is a paid mutator transaction binding the contract method 0x2f2ff15d. +// +// Solidity: function grantRole(bytes32 role, address account) returns() +func (_AccessControl *AccessControlTransactorSession) GrantRole(role [32]byte, account common.Address) (*types.Transaction, error) { + return _AccessControl.Contract.GrantRole(&_AccessControl.TransactOpts, role, account) +} + +// RenounceRole is a paid mutator transaction binding the contract method 0x36568abe. +// +// Solidity: function renounceRole(bytes32 role, address callerConfirmation) returns() +func (_AccessControl *AccessControlTransactor) RenounceRole(opts *bind.TransactOpts, role [32]byte, callerConfirmation common.Address) (*types.Transaction, error) { + return _AccessControl.contract.Transact(opts, "renounceRole", role, callerConfirmation) +} + +// RenounceRole is a paid mutator transaction binding the contract method 0x36568abe. +// +// Solidity: function renounceRole(bytes32 role, address callerConfirmation) returns() +func (_AccessControl *AccessControlSession) RenounceRole(role [32]byte, callerConfirmation common.Address) (*types.Transaction, error) { + return _AccessControl.Contract.RenounceRole(&_AccessControl.TransactOpts, role, callerConfirmation) +} + +// RenounceRole is a paid mutator transaction binding the contract method 0x36568abe. +// +// Solidity: function renounceRole(bytes32 role, address callerConfirmation) returns() +func (_AccessControl *AccessControlTransactorSession) RenounceRole(role [32]byte, callerConfirmation common.Address) (*types.Transaction, error) { + return _AccessControl.Contract.RenounceRole(&_AccessControl.TransactOpts, role, callerConfirmation) +} + +// RevokeRole is a paid mutator transaction binding the contract method 0xd547741f. +// +// Solidity: function revokeRole(bytes32 role, address account) returns() +func (_AccessControl *AccessControlTransactor) RevokeRole(opts *bind.TransactOpts, role [32]byte, account common.Address) (*types.Transaction, error) { + return _AccessControl.contract.Transact(opts, "revokeRole", role, account) +} + +// RevokeRole is a paid mutator transaction binding the contract method 0xd547741f. +// +// Solidity: function revokeRole(bytes32 role, address account) returns() +func (_AccessControl *AccessControlSession) RevokeRole(role [32]byte, account common.Address) (*types.Transaction, error) { + return _AccessControl.Contract.RevokeRole(&_AccessControl.TransactOpts, role, account) +} + +// RevokeRole is a paid mutator transaction binding the contract method 0xd547741f. +// +// Solidity: function revokeRole(bytes32 role, address account) returns() +func (_AccessControl *AccessControlTransactorSession) RevokeRole(role [32]byte, account common.Address) (*types.Transaction, error) { + return _AccessControl.Contract.RevokeRole(&_AccessControl.TransactOpts, role, account) +} + +// AccessControlRoleAdminChangedIterator is returned from FilterRoleAdminChanged and is used to iterate over the raw logs and unpacked data for RoleAdminChanged events raised by the AccessControl contract. +type AccessControlRoleAdminChangedIterator struct { + Event *AccessControlRoleAdminChanged // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *AccessControlRoleAdminChangedIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(AccessControlRoleAdminChanged) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(AccessControlRoleAdminChanged) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *AccessControlRoleAdminChangedIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *AccessControlRoleAdminChangedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// AccessControlRoleAdminChanged represents a RoleAdminChanged event raised by the AccessControl contract. +type AccessControlRoleAdminChanged struct { + Role [32]byte + PreviousAdminRole [32]byte + NewAdminRole [32]byte + Raw types.Log // Blockchain specific contextual infos +} + +// FilterRoleAdminChanged is a free log retrieval operation binding the contract event 0xbd79b86ffe0ab8e8776151514217cd7cacd52c909f66475c3af44e129f0b00ff. +// +// Solidity: event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole) +func (_AccessControl *AccessControlFilterer) FilterRoleAdminChanged(opts *bind.FilterOpts, role [][32]byte, previousAdminRole [][32]byte, newAdminRole [][32]byte) (*AccessControlRoleAdminChangedIterator, error) { + + var roleRule []interface{} + for _, roleItem := range role { + roleRule = append(roleRule, roleItem) + } + var previousAdminRoleRule []interface{} + for _, previousAdminRoleItem := range previousAdminRole { + previousAdminRoleRule = append(previousAdminRoleRule, previousAdminRoleItem) + } + var newAdminRoleRule []interface{} + for _, newAdminRoleItem := range newAdminRole { + newAdminRoleRule = append(newAdminRoleRule, newAdminRoleItem) + } + + logs, sub, err := _AccessControl.contract.FilterLogs(opts, "RoleAdminChanged", roleRule, previousAdminRoleRule, newAdminRoleRule) + if err != nil { + return nil, err + } + return &AccessControlRoleAdminChangedIterator{contract: _AccessControl.contract, event: "RoleAdminChanged", logs: logs, sub: sub}, nil +} + +// WatchRoleAdminChanged is a free log subscription operation binding the contract event 0xbd79b86ffe0ab8e8776151514217cd7cacd52c909f66475c3af44e129f0b00ff. +// +// Solidity: event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole) +func (_AccessControl *AccessControlFilterer) WatchRoleAdminChanged(opts *bind.WatchOpts, sink chan<- *AccessControlRoleAdminChanged, role [][32]byte, previousAdminRole [][32]byte, newAdminRole [][32]byte) (event.Subscription, error) { + + var roleRule []interface{} + for _, roleItem := range role { + roleRule = append(roleRule, roleItem) + } + var previousAdminRoleRule []interface{} + for _, previousAdminRoleItem := range previousAdminRole { + previousAdminRoleRule = append(previousAdminRoleRule, previousAdminRoleItem) + } + var newAdminRoleRule []interface{} + for _, newAdminRoleItem := range newAdminRole { + newAdminRoleRule = append(newAdminRoleRule, newAdminRoleItem) + } + + logs, sub, err := _AccessControl.contract.WatchLogs(opts, "RoleAdminChanged", roleRule, previousAdminRoleRule, newAdminRoleRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(AccessControlRoleAdminChanged) + if err := _AccessControl.contract.UnpackLog(event, "RoleAdminChanged", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseRoleAdminChanged is a log parse operation binding the contract event 0xbd79b86ffe0ab8e8776151514217cd7cacd52c909f66475c3af44e129f0b00ff. +// +// Solidity: event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole) +func (_AccessControl *AccessControlFilterer) ParseRoleAdminChanged(log types.Log) (*AccessControlRoleAdminChanged, error) { + event := new(AccessControlRoleAdminChanged) + if err := _AccessControl.contract.UnpackLog(event, "RoleAdminChanged", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// AccessControlRoleGrantedIterator is returned from FilterRoleGranted and is used to iterate over the raw logs and unpacked data for RoleGranted events raised by the AccessControl contract. +type AccessControlRoleGrantedIterator struct { + Event *AccessControlRoleGranted // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *AccessControlRoleGrantedIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(AccessControlRoleGranted) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(AccessControlRoleGranted) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *AccessControlRoleGrantedIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *AccessControlRoleGrantedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// AccessControlRoleGranted represents a RoleGranted event raised by the AccessControl contract. +type AccessControlRoleGranted struct { + Role [32]byte + Account common.Address + Sender common.Address + Raw types.Log // Blockchain specific contextual infos +} + +// FilterRoleGranted is a free log retrieval operation binding the contract event 0x2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d. +// +// Solidity: event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender) +func (_AccessControl *AccessControlFilterer) FilterRoleGranted(opts *bind.FilterOpts, role [][32]byte, account []common.Address, sender []common.Address) (*AccessControlRoleGrantedIterator, error) { + + var roleRule []interface{} + for _, roleItem := range role { + roleRule = append(roleRule, roleItem) + } + var accountRule []interface{} + for _, accountItem := range account { + accountRule = append(accountRule, accountItem) + } + var senderRule []interface{} + for _, senderItem := range sender { + senderRule = append(senderRule, senderItem) + } + + logs, sub, err := _AccessControl.contract.FilterLogs(opts, "RoleGranted", roleRule, accountRule, senderRule) + if err != nil { + return nil, err + } + return &AccessControlRoleGrantedIterator{contract: _AccessControl.contract, event: "RoleGranted", logs: logs, sub: sub}, nil +} + +// WatchRoleGranted is a free log subscription operation binding the contract event 0x2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d. +// +// Solidity: event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender) +func (_AccessControl *AccessControlFilterer) WatchRoleGranted(opts *bind.WatchOpts, sink chan<- *AccessControlRoleGranted, role [][32]byte, account []common.Address, sender []common.Address) (event.Subscription, error) { + + var roleRule []interface{} + for _, roleItem := range role { + roleRule = append(roleRule, roleItem) + } + var accountRule []interface{} + for _, accountItem := range account { + accountRule = append(accountRule, accountItem) + } + var senderRule []interface{} + for _, senderItem := range sender { + senderRule = append(senderRule, senderItem) + } + + logs, sub, err := _AccessControl.contract.WatchLogs(opts, "RoleGranted", roleRule, accountRule, senderRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(AccessControlRoleGranted) + if err := _AccessControl.contract.UnpackLog(event, "RoleGranted", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseRoleGranted is a log parse operation binding the contract event 0x2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d. +// +// Solidity: event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender) +func (_AccessControl *AccessControlFilterer) ParseRoleGranted(log types.Log) (*AccessControlRoleGranted, error) { + event := new(AccessControlRoleGranted) + if err := _AccessControl.contract.UnpackLog(event, "RoleGranted", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// AccessControlRoleRevokedIterator is returned from FilterRoleRevoked and is used to iterate over the raw logs and unpacked data for RoleRevoked events raised by the AccessControl contract. +type AccessControlRoleRevokedIterator struct { + Event *AccessControlRoleRevoked // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *AccessControlRoleRevokedIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(AccessControlRoleRevoked) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(AccessControlRoleRevoked) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *AccessControlRoleRevokedIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *AccessControlRoleRevokedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// AccessControlRoleRevoked represents a RoleRevoked event raised by the AccessControl contract. +type AccessControlRoleRevoked struct { + Role [32]byte + Account common.Address + Sender common.Address + Raw types.Log // Blockchain specific contextual infos +} + +// FilterRoleRevoked is a free log retrieval operation binding the contract event 0xf6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b. +// +// Solidity: event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender) +func (_AccessControl *AccessControlFilterer) FilterRoleRevoked(opts *bind.FilterOpts, role [][32]byte, account []common.Address, sender []common.Address) (*AccessControlRoleRevokedIterator, error) { + + var roleRule []interface{} + for _, roleItem := range role { + roleRule = append(roleRule, roleItem) + } + var accountRule []interface{} + for _, accountItem := range account { + accountRule = append(accountRule, accountItem) + } + var senderRule []interface{} + for _, senderItem := range sender { + senderRule = append(senderRule, senderItem) + } + + logs, sub, err := _AccessControl.contract.FilterLogs(opts, "RoleRevoked", roleRule, accountRule, senderRule) + if err != nil { + return nil, err + } + return &AccessControlRoleRevokedIterator{contract: _AccessControl.contract, event: "RoleRevoked", logs: logs, sub: sub}, nil +} + +// WatchRoleRevoked is a free log subscription operation binding the contract event 0xf6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b. +// +// Solidity: event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender) +func (_AccessControl *AccessControlFilterer) WatchRoleRevoked(opts *bind.WatchOpts, sink chan<- *AccessControlRoleRevoked, role [][32]byte, account []common.Address, sender []common.Address) (event.Subscription, error) { + + var roleRule []interface{} + for _, roleItem := range role { + roleRule = append(roleRule, roleItem) + } + var accountRule []interface{} + for _, accountItem := range account { + accountRule = append(accountRule, accountItem) + } + var senderRule []interface{} + for _, senderItem := range sender { + senderRule = append(senderRule, senderItem) + } + + logs, sub, err := _AccessControl.contract.WatchLogs(opts, "RoleRevoked", roleRule, accountRule, senderRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(AccessControlRoleRevoked) + if err := _AccessControl.contract.UnpackLog(event, "RoleRevoked", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseRoleRevoked is a log parse operation binding the contract event 0xf6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b. +// +// Solidity: event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender) +func (_AccessControl *AccessControlFilterer) ParseRoleRevoked(log types.Log) (*AccessControlRoleRevoked, error) { + event := new(AccessControlRoleRevoked) + if err := _AccessControl.contract.UnpackLog(event, "RoleRevoked", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// AccessControlEnumerableMetaData contains all meta data concerning the AccessControlEnumerable contract. +var AccessControlEnumerableMetaData = &bind.MetaData{ + ABI: "[{\"inputs\":[],\"name\":\"AccessControlBadConfirmation\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"neededRole\",\"type\":\"bytes32\"}],\"name\":\"AccessControlUnauthorizedAccount\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"previousAdminRole\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"newAdminRole\",\"type\":\"bytes32\"}],\"name\":\"RoleAdminChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleGranted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleRevoked\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"DEFAULT_ADMIN_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"}],\"name\":\"getRoleAdmin\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"index\",\"type\":\"uint256\"}],\"name\":\"getRoleMember\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"}],\"name\":\"getRoleMemberCount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"grantRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"hasRole\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"callerConfirmation\",\"type\":\"address\"}],\"name\":\"renounceRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"revokeRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes4\",\"name\":\"interfaceId\",\"type\":\"bytes4\"}],\"name\":\"supportsInterface\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"}]", + Sigs: map[string]string{ + "a217fddf": "DEFAULT_ADMIN_ROLE()", + "248a9ca3": "getRoleAdmin(bytes32)", + "9010d07c": "getRoleMember(bytes32,uint256)", + "ca15c873": "getRoleMemberCount(bytes32)", + "2f2ff15d": "grantRole(bytes32,address)", + "91d14854": "hasRole(bytes32,address)", + "36568abe": "renounceRole(bytes32,address)", + "d547741f": "revokeRole(bytes32,address)", + "01ffc9a7": "supportsInterface(bytes4)", + }, +} + +// AccessControlEnumerableABI is the input ABI used to generate the binding from. +// Deprecated: Use AccessControlEnumerableMetaData.ABI instead. +var AccessControlEnumerableABI = AccessControlEnumerableMetaData.ABI + +// Deprecated: Use AccessControlEnumerableMetaData.Sigs instead. +// AccessControlEnumerableFuncSigs maps the 4-byte function signature to its string representation. +var AccessControlEnumerableFuncSigs = AccessControlEnumerableMetaData.Sigs + +// AccessControlEnumerable is an auto generated Go binding around an Ethereum contract. +type AccessControlEnumerable struct { + AccessControlEnumerableCaller // Read-only binding to the contract + AccessControlEnumerableTransactor // Write-only binding to the contract + AccessControlEnumerableFilterer // Log filterer for contract events +} + +// AccessControlEnumerableCaller is an auto generated read-only Go binding around an Ethereum contract. +type AccessControlEnumerableCaller struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// AccessControlEnumerableTransactor is an auto generated write-only Go binding around an Ethereum contract. +type AccessControlEnumerableTransactor struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// AccessControlEnumerableFilterer is an auto generated log filtering Go binding around an Ethereum contract events. +type AccessControlEnumerableFilterer struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// AccessControlEnumerableSession is an auto generated Go binding around an Ethereum contract, +// with pre-set call and transact options. +type AccessControlEnumerableSession struct { + Contract *AccessControlEnumerable // Generic contract binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// AccessControlEnumerableCallerSession is an auto generated read-only Go binding around an Ethereum contract, +// with pre-set call options. +type AccessControlEnumerableCallerSession struct { + Contract *AccessControlEnumerableCaller // Generic contract caller binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session +} + +// AccessControlEnumerableTransactorSession is an auto generated write-only Go binding around an Ethereum contract, +// with pre-set transact options. +type AccessControlEnumerableTransactorSession struct { + Contract *AccessControlEnumerableTransactor // Generic contract transactor binding to set the session for + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// AccessControlEnumerableRaw is an auto generated low-level Go binding around an Ethereum contract. +type AccessControlEnumerableRaw struct { + Contract *AccessControlEnumerable // Generic contract binding to access the raw methods on +} + +// AccessControlEnumerableCallerRaw is an auto generated low-level read-only Go binding around an Ethereum contract. +type AccessControlEnumerableCallerRaw struct { + Contract *AccessControlEnumerableCaller // Generic read-only contract binding to access the raw methods on +} + +// AccessControlEnumerableTransactorRaw is an auto generated low-level write-only Go binding around an Ethereum contract. +type AccessControlEnumerableTransactorRaw struct { + Contract *AccessControlEnumerableTransactor // Generic write-only contract binding to access the raw methods on +} + +// NewAccessControlEnumerable creates a new instance of AccessControlEnumerable, bound to a specific deployed contract. +func NewAccessControlEnumerable(address common.Address, backend bind.ContractBackend) (*AccessControlEnumerable, error) { + contract, err := bindAccessControlEnumerable(address, backend, backend, backend) + if err != nil { + return nil, err + } + return &AccessControlEnumerable{AccessControlEnumerableCaller: AccessControlEnumerableCaller{contract: contract}, AccessControlEnumerableTransactor: AccessControlEnumerableTransactor{contract: contract}, AccessControlEnumerableFilterer: AccessControlEnumerableFilterer{contract: contract}}, nil +} + +// NewAccessControlEnumerableCaller creates a new read-only instance of AccessControlEnumerable, bound to a specific deployed contract. +func NewAccessControlEnumerableCaller(address common.Address, caller bind.ContractCaller) (*AccessControlEnumerableCaller, error) { + contract, err := bindAccessControlEnumerable(address, caller, nil, nil) + if err != nil { + return nil, err + } + return &AccessControlEnumerableCaller{contract: contract}, nil +} + +// NewAccessControlEnumerableTransactor creates a new write-only instance of AccessControlEnumerable, bound to a specific deployed contract. +func NewAccessControlEnumerableTransactor(address common.Address, transactor bind.ContractTransactor) (*AccessControlEnumerableTransactor, error) { + contract, err := bindAccessControlEnumerable(address, nil, transactor, nil) + if err != nil { + return nil, err + } + return &AccessControlEnumerableTransactor{contract: contract}, nil +} + +// NewAccessControlEnumerableFilterer creates a new log filterer instance of AccessControlEnumerable, bound to a specific deployed contract. +func NewAccessControlEnumerableFilterer(address common.Address, filterer bind.ContractFilterer) (*AccessControlEnumerableFilterer, error) { + contract, err := bindAccessControlEnumerable(address, nil, nil, filterer) + if err != nil { + return nil, err + } + return &AccessControlEnumerableFilterer{contract: contract}, nil +} + +// bindAccessControlEnumerable binds a generic wrapper to an already deployed contract. +func bindAccessControlEnumerable(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) { + parsed, err := AccessControlEnumerableMetaData.GetAbi() + if err != nil { + return nil, err + } + return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil +} + +// Call invokes the (constant) contract method with params as input values and +// sets the output to result. The result type might be a single field for simple +// returns, a slice of interfaces for anonymous returns and a struct for named +// returns. +func (_AccessControlEnumerable *AccessControlEnumerableRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _AccessControlEnumerable.Contract.AccessControlEnumerableCaller.contract.Call(opts, result, method, params...) +} + +// Transfer initiates a plain transaction to move funds to the contract, calling +// its default method if one is available. +func (_AccessControlEnumerable *AccessControlEnumerableRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _AccessControlEnumerable.Contract.AccessControlEnumerableTransactor.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_AccessControlEnumerable *AccessControlEnumerableRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _AccessControlEnumerable.Contract.AccessControlEnumerableTransactor.contract.Transact(opts, method, params...) +} + +// Call invokes the (constant) contract method with params as input values and +// sets the output to result. The result type might be a single field for simple +// returns, a slice of interfaces for anonymous returns and a struct for named +// returns. +func (_AccessControlEnumerable *AccessControlEnumerableCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _AccessControlEnumerable.Contract.contract.Call(opts, result, method, params...) +} + +// Transfer initiates a plain transaction to move funds to the contract, calling +// its default method if one is available. +func (_AccessControlEnumerable *AccessControlEnumerableTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _AccessControlEnumerable.Contract.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_AccessControlEnumerable *AccessControlEnumerableTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _AccessControlEnumerable.Contract.contract.Transact(opts, method, params...) +} + +// DEFAULTADMINROLE is a free data retrieval call binding the contract method 0xa217fddf. +// +// Solidity: function DEFAULT_ADMIN_ROLE() view returns(bytes32) +func (_AccessControlEnumerable *AccessControlEnumerableCaller) DEFAULTADMINROLE(opts *bind.CallOpts) ([32]byte, error) { + var out []interface{} + err := _AccessControlEnumerable.contract.Call(opts, &out, "DEFAULT_ADMIN_ROLE") + + if err != nil { + return *new([32]byte), err + } + + out0 := *abi.ConvertType(out[0], new([32]byte)).(*[32]byte) + + return out0, err + +} + +// DEFAULTADMINROLE is a free data retrieval call binding the contract method 0xa217fddf. +// +// Solidity: function DEFAULT_ADMIN_ROLE() view returns(bytes32) +func (_AccessControlEnumerable *AccessControlEnumerableSession) DEFAULTADMINROLE() ([32]byte, error) { + return _AccessControlEnumerable.Contract.DEFAULTADMINROLE(&_AccessControlEnumerable.CallOpts) +} + +// DEFAULTADMINROLE is a free data retrieval call binding the contract method 0xa217fddf. +// +// Solidity: function DEFAULT_ADMIN_ROLE() view returns(bytes32) +func (_AccessControlEnumerable *AccessControlEnumerableCallerSession) DEFAULTADMINROLE() ([32]byte, error) { + return _AccessControlEnumerable.Contract.DEFAULTADMINROLE(&_AccessControlEnumerable.CallOpts) +} + +// GetRoleAdmin is a free data retrieval call binding the contract method 0x248a9ca3. +// +// Solidity: function getRoleAdmin(bytes32 role) view returns(bytes32) +func (_AccessControlEnumerable *AccessControlEnumerableCaller) GetRoleAdmin(opts *bind.CallOpts, role [32]byte) ([32]byte, error) { + var out []interface{} + err := _AccessControlEnumerable.contract.Call(opts, &out, "getRoleAdmin", role) + + if err != nil { + return *new([32]byte), err + } + + out0 := *abi.ConvertType(out[0], new([32]byte)).(*[32]byte) + + return out0, err + +} + +// GetRoleAdmin is a free data retrieval call binding the contract method 0x248a9ca3. +// +// Solidity: function getRoleAdmin(bytes32 role) view returns(bytes32) +func (_AccessControlEnumerable *AccessControlEnumerableSession) GetRoleAdmin(role [32]byte) ([32]byte, error) { + return _AccessControlEnumerable.Contract.GetRoleAdmin(&_AccessControlEnumerable.CallOpts, role) +} + +// GetRoleAdmin is a free data retrieval call binding the contract method 0x248a9ca3. +// +// Solidity: function getRoleAdmin(bytes32 role) view returns(bytes32) +func (_AccessControlEnumerable *AccessControlEnumerableCallerSession) GetRoleAdmin(role [32]byte) ([32]byte, error) { + return _AccessControlEnumerable.Contract.GetRoleAdmin(&_AccessControlEnumerable.CallOpts, role) +} + +// GetRoleMember is a free data retrieval call binding the contract method 0x9010d07c. +// +// Solidity: function getRoleMember(bytes32 role, uint256 index) view returns(address) +func (_AccessControlEnumerable *AccessControlEnumerableCaller) GetRoleMember(opts *bind.CallOpts, role [32]byte, index *big.Int) (common.Address, error) { + var out []interface{} + err := _AccessControlEnumerable.contract.Call(opts, &out, "getRoleMember", role, index) + + if err != nil { + return *new(common.Address), err + } + + out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) + + return out0, err + +} + +// GetRoleMember is a free data retrieval call binding the contract method 0x9010d07c. +// +// Solidity: function getRoleMember(bytes32 role, uint256 index) view returns(address) +func (_AccessControlEnumerable *AccessControlEnumerableSession) GetRoleMember(role [32]byte, index *big.Int) (common.Address, error) { + return _AccessControlEnumerable.Contract.GetRoleMember(&_AccessControlEnumerable.CallOpts, role, index) +} + +// GetRoleMember is a free data retrieval call binding the contract method 0x9010d07c. +// +// Solidity: function getRoleMember(bytes32 role, uint256 index) view returns(address) +func (_AccessControlEnumerable *AccessControlEnumerableCallerSession) GetRoleMember(role [32]byte, index *big.Int) (common.Address, error) { + return _AccessControlEnumerable.Contract.GetRoleMember(&_AccessControlEnumerable.CallOpts, role, index) +} + +// GetRoleMemberCount is a free data retrieval call binding the contract method 0xca15c873. +// +// Solidity: function getRoleMemberCount(bytes32 role) view returns(uint256) +func (_AccessControlEnumerable *AccessControlEnumerableCaller) GetRoleMemberCount(opts *bind.CallOpts, role [32]byte) (*big.Int, error) { + var out []interface{} + err := _AccessControlEnumerable.contract.Call(opts, &out, "getRoleMemberCount", role) + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// GetRoleMemberCount is a free data retrieval call binding the contract method 0xca15c873. +// +// Solidity: function getRoleMemberCount(bytes32 role) view returns(uint256) +func (_AccessControlEnumerable *AccessControlEnumerableSession) GetRoleMemberCount(role [32]byte) (*big.Int, error) { + return _AccessControlEnumerable.Contract.GetRoleMemberCount(&_AccessControlEnumerable.CallOpts, role) +} + +// GetRoleMemberCount is a free data retrieval call binding the contract method 0xca15c873. +// +// Solidity: function getRoleMemberCount(bytes32 role) view returns(uint256) +func (_AccessControlEnumerable *AccessControlEnumerableCallerSession) GetRoleMemberCount(role [32]byte) (*big.Int, error) { + return _AccessControlEnumerable.Contract.GetRoleMemberCount(&_AccessControlEnumerable.CallOpts, role) +} + +// HasRole is a free data retrieval call binding the contract method 0x91d14854. +// +// Solidity: function hasRole(bytes32 role, address account) view returns(bool) +func (_AccessControlEnumerable *AccessControlEnumerableCaller) HasRole(opts *bind.CallOpts, role [32]byte, account common.Address) (bool, error) { + var out []interface{} + err := _AccessControlEnumerable.contract.Call(opts, &out, "hasRole", role, account) + + if err != nil { + return *new(bool), err + } + + out0 := *abi.ConvertType(out[0], new(bool)).(*bool) + + return out0, err + +} + +// HasRole is a free data retrieval call binding the contract method 0x91d14854. +// +// Solidity: function hasRole(bytes32 role, address account) view returns(bool) +func (_AccessControlEnumerable *AccessControlEnumerableSession) HasRole(role [32]byte, account common.Address) (bool, error) { + return _AccessControlEnumerable.Contract.HasRole(&_AccessControlEnumerable.CallOpts, role, account) +} + +// HasRole is a free data retrieval call binding the contract method 0x91d14854. +// +// Solidity: function hasRole(bytes32 role, address account) view returns(bool) +func (_AccessControlEnumerable *AccessControlEnumerableCallerSession) HasRole(role [32]byte, account common.Address) (bool, error) { + return _AccessControlEnumerable.Contract.HasRole(&_AccessControlEnumerable.CallOpts, role, account) +} + +// SupportsInterface is a free data retrieval call binding the contract method 0x01ffc9a7. +// +// Solidity: function supportsInterface(bytes4 interfaceId) view returns(bool) +func (_AccessControlEnumerable *AccessControlEnumerableCaller) SupportsInterface(opts *bind.CallOpts, interfaceId [4]byte) (bool, error) { + var out []interface{} + err := _AccessControlEnumerable.contract.Call(opts, &out, "supportsInterface", interfaceId) + + if err != nil { + return *new(bool), err + } + + out0 := *abi.ConvertType(out[0], new(bool)).(*bool) + + return out0, err + +} + +// SupportsInterface is a free data retrieval call binding the contract method 0x01ffc9a7. +// +// Solidity: function supportsInterface(bytes4 interfaceId) view returns(bool) +func (_AccessControlEnumerable *AccessControlEnumerableSession) SupportsInterface(interfaceId [4]byte) (bool, error) { + return _AccessControlEnumerable.Contract.SupportsInterface(&_AccessControlEnumerable.CallOpts, interfaceId) +} + +// SupportsInterface is a free data retrieval call binding the contract method 0x01ffc9a7. +// +// Solidity: function supportsInterface(bytes4 interfaceId) view returns(bool) +func (_AccessControlEnumerable *AccessControlEnumerableCallerSession) SupportsInterface(interfaceId [4]byte) (bool, error) { + return _AccessControlEnumerable.Contract.SupportsInterface(&_AccessControlEnumerable.CallOpts, interfaceId) +} + +// GrantRole is a paid mutator transaction binding the contract method 0x2f2ff15d. +// +// Solidity: function grantRole(bytes32 role, address account) returns() +func (_AccessControlEnumerable *AccessControlEnumerableTransactor) GrantRole(opts *bind.TransactOpts, role [32]byte, account common.Address) (*types.Transaction, error) { + return _AccessControlEnumerable.contract.Transact(opts, "grantRole", role, account) +} + +// GrantRole is a paid mutator transaction binding the contract method 0x2f2ff15d. +// +// Solidity: function grantRole(bytes32 role, address account) returns() +func (_AccessControlEnumerable *AccessControlEnumerableSession) GrantRole(role [32]byte, account common.Address) (*types.Transaction, error) { + return _AccessControlEnumerable.Contract.GrantRole(&_AccessControlEnumerable.TransactOpts, role, account) +} + +// GrantRole is a paid mutator transaction binding the contract method 0x2f2ff15d. +// +// Solidity: function grantRole(bytes32 role, address account) returns() +func (_AccessControlEnumerable *AccessControlEnumerableTransactorSession) GrantRole(role [32]byte, account common.Address) (*types.Transaction, error) { + return _AccessControlEnumerable.Contract.GrantRole(&_AccessControlEnumerable.TransactOpts, role, account) +} + +// RenounceRole is a paid mutator transaction binding the contract method 0x36568abe. +// +// Solidity: function renounceRole(bytes32 role, address callerConfirmation) returns() +func (_AccessControlEnumerable *AccessControlEnumerableTransactor) RenounceRole(opts *bind.TransactOpts, role [32]byte, callerConfirmation common.Address) (*types.Transaction, error) { + return _AccessControlEnumerable.contract.Transact(opts, "renounceRole", role, callerConfirmation) +} + +// RenounceRole is a paid mutator transaction binding the contract method 0x36568abe. +// +// Solidity: function renounceRole(bytes32 role, address callerConfirmation) returns() +func (_AccessControlEnumerable *AccessControlEnumerableSession) RenounceRole(role [32]byte, callerConfirmation common.Address) (*types.Transaction, error) { + return _AccessControlEnumerable.Contract.RenounceRole(&_AccessControlEnumerable.TransactOpts, role, callerConfirmation) +} + +// RenounceRole is a paid mutator transaction binding the contract method 0x36568abe. +// +// Solidity: function renounceRole(bytes32 role, address callerConfirmation) returns() +func (_AccessControlEnumerable *AccessControlEnumerableTransactorSession) RenounceRole(role [32]byte, callerConfirmation common.Address) (*types.Transaction, error) { + return _AccessControlEnumerable.Contract.RenounceRole(&_AccessControlEnumerable.TransactOpts, role, callerConfirmation) +} + +// RevokeRole is a paid mutator transaction binding the contract method 0xd547741f. +// +// Solidity: function revokeRole(bytes32 role, address account) returns() +func (_AccessControlEnumerable *AccessControlEnumerableTransactor) RevokeRole(opts *bind.TransactOpts, role [32]byte, account common.Address) (*types.Transaction, error) { + return _AccessControlEnumerable.contract.Transact(opts, "revokeRole", role, account) +} + +// RevokeRole is a paid mutator transaction binding the contract method 0xd547741f. +// +// Solidity: function revokeRole(bytes32 role, address account) returns() +func (_AccessControlEnumerable *AccessControlEnumerableSession) RevokeRole(role [32]byte, account common.Address) (*types.Transaction, error) { + return _AccessControlEnumerable.Contract.RevokeRole(&_AccessControlEnumerable.TransactOpts, role, account) +} + +// RevokeRole is a paid mutator transaction binding the contract method 0xd547741f. +// +// Solidity: function revokeRole(bytes32 role, address account) returns() +func (_AccessControlEnumerable *AccessControlEnumerableTransactorSession) RevokeRole(role [32]byte, account common.Address) (*types.Transaction, error) { + return _AccessControlEnumerable.Contract.RevokeRole(&_AccessControlEnumerable.TransactOpts, role, account) +} + +// AccessControlEnumerableRoleAdminChangedIterator is returned from FilterRoleAdminChanged and is used to iterate over the raw logs and unpacked data for RoleAdminChanged events raised by the AccessControlEnumerable contract. +type AccessControlEnumerableRoleAdminChangedIterator struct { + Event *AccessControlEnumerableRoleAdminChanged // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *AccessControlEnumerableRoleAdminChangedIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(AccessControlEnumerableRoleAdminChanged) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(AccessControlEnumerableRoleAdminChanged) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *AccessControlEnumerableRoleAdminChangedIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *AccessControlEnumerableRoleAdminChangedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// AccessControlEnumerableRoleAdminChanged represents a RoleAdminChanged event raised by the AccessControlEnumerable contract. +type AccessControlEnumerableRoleAdminChanged struct { + Role [32]byte + PreviousAdminRole [32]byte + NewAdminRole [32]byte + Raw types.Log // Blockchain specific contextual infos +} + +// FilterRoleAdminChanged is a free log retrieval operation binding the contract event 0xbd79b86ffe0ab8e8776151514217cd7cacd52c909f66475c3af44e129f0b00ff. +// +// Solidity: event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole) +func (_AccessControlEnumerable *AccessControlEnumerableFilterer) FilterRoleAdminChanged(opts *bind.FilterOpts, role [][32]byte, previousAdminRole [][32]byte, newAdminRole [][32]byte) (*AccessControlEnumerableRoleAdminChangedIterator, error) { + + var roleRule []interface{} + for _, roleItem := range role { + roleRule = append(roleRule, roleItem) + } + var previousAdminRoleRule []interface{} + for _, previousAdminRoleItem := range previousAdminRole { + previousAdminRoleRule = append(previousAdminRoleRule, previousAdminRoleItem) + } + var newAdminRoleRule []interface{} + for _, newAdminRoleItem := range newAdminRole { + newAdminRoleRule = append(newAdminRoleRule, newAdminRoleItem) + } + + logs, sub, err := _AccessControlEnumerable.contract.FilterLogs(opts, "RoleAdminChanged", roleRule, previousAdminRoleRule, newAdminRoleRule) + if err != nil { + return nil, err + } + return &AccessControlEnumerableRoleAdminChangedIterator{contract: _AccessControlEnumerable.contract, event: "RoleAdminChanged", logs: logs, sub: sub}, nil +} + +// WatchRoleAdminChanged is a free log subscription operation binding the contract event 0xbd79b86ffe0ab8e8776151514217cd7cacd52c909f66475c3af44e129f0b00ff. +// +// Solidity: event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole) +func (_AccessControlEnumerable *AccessControlEnumerableFilterer) WatchRoleAdminChanged(opts *bind.WatchOpts, sink chan<- *AccessControlEnumerableRoleAdminChanged, role [][32]byte, previousAdminRole [][32]byte, newAdminRole [][32]byte) (event.Subscription, error) { + + var roleRule []interface{} + for _, roleItem := range role { + roleRule = append(roleRule, roleItem) + } + var previousAdminRoleRule []interface{} + for _, previousAdminRoleItem := range previousAdminRole { + previousAdminRoleRule = append(previousAdminRoleRule, previousAdminRoleItem) + } + var newAdminRoleRule []interface{} + for _, newAdminRoleItem := range newAdminRole { + newAdminRoleRule = append(newAdminRoleRule, newAdminRoleItem) + } + + logs, sub, err := _AccessControlEnumerable.contract.WatchLogs(opts, "RoleAdminChanged", roleRule, previousAdminRoleRule, newAdminRoleRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(AccessControlEnumerableRoleAdminChanged) + if err := _AccessControlEnumerable.contract.UnpackLog(event, "RoleAdminChanged", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseRoleAdminChanged is a log parse operation binding the contract event 0xbd79b86ffe0ab8e8776151514217cd7cacd52c909f66475c3af44e129f0b00ff. +// +// Solidity: event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole) +func (_AccessControlEnumerable *AccessControlEnumerableFilterer) ParseRoleAdminChanged(log types.Log) (*AccessControlEnumerableRoleAdminChanged, error) { + event := new(AccessControlEnumerableRoleAdminChanged) + if err := _AccessControlEnumerable.contract.UnpackLog(event, "RoleAdminChanged", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// AccessControlEnumerableRoleGrantedIterator is returned from FilterRoleGranted and is used to iterate over the raw logs and unpacked data for RoleGranted events raised by the AccessControlEnumerable contract. +type AccessControlEnumerableRoleGrantedIterator struct { + Event *AccessControlEnumerableRoleGranted // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *AccessControlEnumerableRoleGrantedIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(AccessControlEnumerableRoleGranted) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(AccessControlEnumerableRoleGranted) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *AccessControlEnumerableRoleGrantedIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *AccessControlEnumerableRoleGrantedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// AccessControlEnumerableRoleGranted represents a RoleGranted event raised by the AccessControlEnumerable contract. +type AccessControlEnumerableRoleGranted struct { + Role [32]byte + Account common.Address + Sender common.Address + Raw types.Log // Blockchain specific contextual infos +} + +// FilterRoleGranted is a free log retrieval operation binding the contract event 0x2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d. +// +// Solidity: event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender) +func (_AccessControlEnumerable *AccessControlEnumerableFilterer) FilterRoleGranted(opts *bind.FilterOpts, role [][32]byte, account []common.Address, sender []common.Address) (*AccessControlEnumerableRoleGrantedIterator, error) { + + var roleRule []interface{} + for _, roleItem := range role { + roleRule = append(roleRule, roleItem) + } + var accountRule []interface{} + for _, accountItem := range account { + accountRule = append(accountRule, accountItem) + } + var senderRule []interface{} + for _, senderItem := range sender { + senderRule = append(senderRule, senderItem) + } + + logs, sub, err := _AccessControlEnumerable.contract.FilterLogs(opts, "RoleGranted", roleRule, accountRule, senderRule) + if err != nil { + return nil, err + } + return &AccessControlEnumerableRoleGrantedIterator{contract: _AccessControlEnumerable.contract, event: "RoleGranted", logs: logs, sub: sub}, nil +} + +// WatchRoleGranted is a free log subscription operation binding the contract event 0x2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d. +// +// Solidity: event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender) +func (_AccessControlEnumerable *AccessControlEnumerableFilterer) WatchRoleGranted(opts *bind.WatchOpts, sink chan<- *AccessControlEnumerableRoleGranted, role [][32]byte, account []common.Address, sender []common.Address) (event.Subscription, error) { + + var roleRule []interface{} + for _, roleItem := range role { + roleRule = append(roleRule, roleItem) + } + var accountRule []interface{} + for _, accountItem := range account { + accountRule = append(accountRule, accountItem) + } + var senderRule []interface{} + for _, senderItem := range sender { + senderRule = append(senderRule, senderItem) + } + + logs, sub, err := _AccessControlEnumerable.contract.WatchLogs(opts, "RoleGranted", roleRule, accountRule, senderRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(AccessControlEnumerableRoleGranted) + if err := _AccessControlEnumerable.contract.UnpackLog(event, "RoleGranted", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseRoleGranted is a log parse operation binding the contract event 0x2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d. +// +// Solidity: event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender) +func (_AccessControlEnumerable *AccessControlEnumerableFilterer) ParseRoleGranted(log types.Log) (*AccessControlEnumerableRoleGranted, error) { + event := new(AccessControlEnumerableRoleGranted) + if err := _AccessControlEnumerable.contract.UnpackLog(event, "RoleGranted", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// AccessControlEnumerableRoleRevokedIterator is returned from FilterRoleRevoked and is used to iterate over the raw logs and unpacked data for RoleRevoked events raised by the AccessControlEnumerable contract. +type AccessControlEnumerableRoleRevokedIterator struct { + Event *AccessControlEnumerableRoleRevoked // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *AccessControlEnumerableRoleRevokedIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(AccessControlEnumerableRoleRevoked) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(AccessControlEnumerableRoleRevoked) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *AccessControlEnumerableRoleRevokedIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *AccessControlEnumerableRoleRevokedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// AccessControlEnumerableRoleRevoked represents a RoleRevoked event raised by the AccessControlEnumerable contract. +type AccessControlEnumerableRoleRevoked struct { + Role [32]byte + Account common.Address + Sender common.Address + Raw types.Log // Blockchain specific contextual infos +} + +// FilterRoleRevoked is a free log retrieval operation binding the contract event 0xf6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b. +// +// Solidity: event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender) +func (_AccessControlEnumerable *AccessControlEnumerableFilterer) FilterRoleRevoked(opts *bind.FilterOpts, role [][32]byte, account []common.Address, sender []common.Address) (*AccessControlEnumerableRoleRevokedIterator, error) { + + var roleRule []interface{} + for _, roleItem := range role { + roleRule = append(roleRule, roleItem) + } + var accountRule []interface{} + for _, accountItem := range account { + accountRule = append(accountRule, accountItem) + } + var senderRule []interface{} + for _, senderItem := range sender { + senderRule = append(senderRule, senderItem) + } + + logs, sub, err := _AccessControlEnumerable.contract.FilterLogs(opts, "RoleRevoked", roleRule, accountRule, senderRule) + if err != nil { + return nil, err + } + return &AccessControlEnumerableRoleRevokedIterator{contract: _AccessControlEnumerable.contract, event: "RoleRevoked", logs: logs, sub: sub}, nil +} + +// WatchRoleRevoked is a free log subscription operation binding the contract event 0xf6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b. +// +// Solidity: event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender) +func (_AccessControlEnumerable *AccessControlEnumerableFilterer) WatchRoleRevoked(opts *bind.WatchOpts, sink chan<- *AccessControlEnumerableRoleRevoked, role [][32]byte, account []common.Address, sender []common.Address) (event.Subscription, error) { + + var roleRule []interface{} + for _, roleItem := range role { + roleRule = append(roleRule, roleItem) + } + var accountRule []interface{} + for _, accountItem := range account { + accountRule = append(accountRule, accountItem) + } + var senderRule []interface{} + for _, senderItem := range sender { + senderRule = append(senderRule, senderItem) + } + + logs, sub, err := _AccessControlEnumerable.contract.WatchLogs(opts, "RoleRevoked", roleRule, accountRule, senderRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(AccessControlEnumerableRoleRevoked) + if err := _AccessControlEnumerable.contract.UnpackLog(event, "RoleRevoked", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseRoleRevoked is a log parse operation binding the contract event 0xf6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b. +// +// Solidity: event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender) +func (_AccessControlEnumerable *AccessControlEnumerableFilterer) ParseRoleRevoked(log types.Log) (*AccessControlEnumerableRoleRevoked, error) { + event := new(AccessControlEnumerableRoleRevoked) + if err := _AccessControlEnumerable.contract.UnpackLog(event, "RoleRevoked", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// AddressMetaData contains all meta data concerning the Address contract. +var AddressMetaData = &bind.MetaData{ + ABI: "[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"}],\"name\":\"AddressEmptyCode\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"AddressInsufficientBalance\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"FailedInnerCall\",\"type\":\"error\"}]", + Bin: "0x60566037600b82828239805160001a607314602a57634e487b7160e01b600052600060045260246000fd5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600080fdfea264697066735822122083549ae8a6625896ee7f9ad3afb09c83f8f6b7f2c10b67bf18def7b2b300f36a64736f6c63430008140033", +} + +// AddressABI is the input ABI used to generate the binding from. +// Deprecated: Use AddressMetaData.ABI instead. +var AddressABI = AddressMetaData.ABI + +// AddressBin is the compiled bytecode used for deploying new contracts. +// Deprecated: Use AddressMetaData.Bin instead. +var AddressBin = AddressMetaData.Bin + +// DeployAddress deploys a new Ethereum contract, binding an instance of Address to it. +func DeployAddress(auth *bind.TransactOpts, backend bind.ContractBackend) (common.Address, *types.Transaction, *Address, error) { + parsed, err := AddressMetaData.GetAbi() + if err != nil { + return common.Address{}, nil, nil, err + } + if parsed == nil { + return common.Address{}, nil, nil, errors.New("GetABI returned nil") + } + + address, tx, contract, err := bind.DeployContract(auth, *parsed, common.FromHex(AddressBin), backend) + if err != nil { + return common.Address{}, nil, nil, err + } + return address, tx, &Address{AddressCaller: AddressCaller{contract: contract}, AddressTransactor: AddressTransactor{contract: contract}, AddressFilterer: AddressFilterer{contract: contract}}, nil +} + +// Address is an auto generated Go binding around an Ethereum contract. +type Address struct { + AddressCaller // Read-only binding to the contract + AddressTransactor // Write-only binding to the contract + AddressFilterer // Log filterer for contract events +} + +// AddressCaller is an auto generated read-only Go binding around an Ethereum contract. +type AddressCaller struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// AddressTransactor is an auto generated write-only Go binding around an Ethereum contract. +type AddressTransactor struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// AddressFilterer is an auto generated log filtering Go binding around an Ethereum contract events. +type AddressFilterer struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// AddressSession is an auto generated Go binding around an Ethereum contract, +// with pre-set call and transact options. +type AddressSession struct { + Contract *Address // Generic contract binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// AddressCallerSession is an auto generated read-only Go binding around an Ethereum contract, +// with pre-set call options. +type AddressCallerSession struct { + Contract *AddressCaller // Generic contract caller binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session +} + +// AddressTransactorSession is an auto generated write-only Go binding around an Ethereum contract, +// with pre-set transact options. +type AddressTransactorSession struct { + Contract *AddressTransactor // Generic contract transactor binding to set the session for + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// AddressRaw is an auto generated low-level Go binding around an Ethereum contract. +type AddressRaw struct { + Contract *Address // Generic contract binding to access the raw methods on +} + +// AddressCallerRaw is an auto generated low-level read-only Go binding around an Ethereum contract. +type AddressCallerRaw struct { + Contract *AddressCaller // Generic read-only contract binding to access the raw methods on +} + +// AddressTransactorRaw is an auto generated low-level write-only Go binding around an Ethereum contract. +type AddressTransactorRaw struct { + Contract *AddressTransactor // Generic write-only contract binding to access the raw methods on +} + +// NewAddress creates a new instance of Address, bound to a specific deployed contract. +func NewAddress(address common.Address, backend bind.ContractBackend) (*Address, error) { + contract, err := bindAddress(address, backend, backend, backend) + if err != nil { + return nil, err + } + return &Address{AddressCaller: AddressCaller{contract: contract}, AddressTransactor: AddressTransactor{contract: contract}, AddressFilterer: AddressFilterer{contract: contract}}, nil +} + +// NewAddressCaller creates a new read-only instance of Address, bound to a specific deployed contract. +func NewAddressCaller(address common.Address, caller bind.ContractCaller) (*AddressCaller, error) { + contract, err := bindAddress(address, caller, nil, nil) + if err != nil { + return nil, err + } + return &AddressCaller{contract: contract}, nil +} + +// NewAddressTransactor creates a new write-only instance of Address, bound to a specific deployed contract. +func NewAddressTransactor(address common.Address, transactor bind.ContractTransactor) (*AddressTransactor, error) { + contract, err := bindAddress(address, nil, transactor, nil) + if err != nil { + return nil, err + } + return &AddressTransactor{contract: contract}, nil +} + +// NewAddressFilterer creates a new log filterer instance of Address, bound to a specific deployed contract. +func NewAddressFilterer(address common.Address, filterer bind.ContractFilterer) (*AddressFilterer, error) { + contract, err := bindAddress(address, nil, nil, filterer) + if err != nil { + return nil, err + } + return &AddressFilterer{contract: contract}, nil +} + +// bindAddress binds a generic wrapper to an already deployed contract. +func bindAddress(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) { + parsed, err := AddressMetaData.GetAbi() + if err != nil { + return nil, err + } + return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil +} + +// Call invokes the (constant) contract method with params as input values and +// sets the output to result. The result type might be a single field for simple +// returns, a slice of interfaces for anonymous returns and a struct for named +// returns. +func (_Address *AddressRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _Address.Contract.AddressCaller.contract.Call(opts, result, method, params...) +} + +// Transfer initiates a plain transaction to move funds to the contract, calling +// its default method if one is available. +func (_Address *AddressRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _Address.Contract.AddressTransactor.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_Address *AddressRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _Address.Contract.AddressTransactor.contract.Transact(opts, method, params...) +} + +// Call invokes the (constant) contract method with params as input values and +// sets the output to result. The result type might be a single field for simple +// returns, a slice of interfaces for anonymous returns and a struct for named +// returns. +func (_Address *AddressCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _Address.Contract.contract.Call(opts, result, method, params...) +} + +// Transfer initiates a plain transaction to move funds to the contract, calling +// its default method if one is available. +func (_Address *AddressTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _Address.Contract.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_Address *AddressTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _Address.Contract.contract.Transact(opts, method, params...) +} + +// AdminMetaData contains all meta data concerning the Admin contract. +var AdminMetaData = &bind.MetaData{ + ABI: "[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_owner\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"AccessControlBadConfirmation\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"neededRole\",\"type\":\"bytes32\"}],\"name\":\"AccessControlUnauthorizedAccount\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"}],\"name\":\"AddressEmptyCode\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"AddressInsufficientBalance\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"FailedInnerCall\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"}],\"name\":\"SafeERC20FailedOperation\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"oldChainGasAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newChainGasAmount\",\"type\":\"uint256\"}],\"name\":\"ChainGasAmountUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"oldFeeRate\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newFeeRate\",\"type\":\"uint256\"}],\"name\":\"FeeRateUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"FeesSwept\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"previousAdminRole\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"newAdminRole\",\"type\":\"bytes32\"}],\"name\":\"RoleAdminChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleGranted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleRevoked\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"DEFAULT_ADMIN_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"FEE_BPS\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"FEE_RATE_MAX\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"GOVERNOR_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"GUARD_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"REFUNDER_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"RELAYER_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"chainGasAmount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"}],\"name\":\"getRoleAdmin\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"index\",\"type\":\"uint256\"}],\"name\":\"getRoleMember\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"}],\"name\":\"getRoleMemberCount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"grantRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"hasRole\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"protocolFeeRate\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"protocolFees\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"callerConfirmation\",\"type\":\"address\"}],\"name\":\"renounceRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"revokeRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"newChainGasAmount\",\"type\":\"uint256\"}],\"name\":\"setChainGasAmount\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"newFeeRate\",\"type\":\"uint256\"}],\"name\":\"setProtocolFeeRate\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes4\",\"name\":\"interfaceId\",\"type\":\"bytes4\"}],\"name\":\"supportsInterface\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"}],\"name\":\"sweepProtocolFees\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", + Sigs: map[string]string{ + "a217fddf": "DEFAULT_ADMIN_ROLE()", + "bf333f2c": "FEE_BPS()", + "0f5f6ed7": "FEE_RATE_MAX()", + "ccc57490": "GOVERNOR_ROLE()", + "03ed0ee5": "GUARD_ROLE()", + "5960ccf2": "REFUNDER_ROLE()", + "926d7d7f": "RELAYER_ROLE()", + "e00a83e0": "chainGasAmount()", + "248a9ca3": "getRoleAdmin(bytes32)", + "9010d07c": "getRoleMember(bytes32,uint256)", + "ca15c873": "getRoleMemberCount(bytes32)", + "2f2ff15d": "grantRole(bytes32,address)", + "91d14854": "hasRole(bytes32,address)", + "58f85880": "protocolFeeRate()", + "dcf844a7": "protocolFees(address)", + "36568abe": "renounceRole(bytes32,address)", + "d547741f": "revokeRole(bytes32,address)", + "b250fe6b": "setChainGasAmount(uint256)", + "b13aa2d6": "setProtocolFeeRate(uint256)", + "01ffc9a7": "supportsInterface(bytes4)", + "06f333f2": "sweepProtocolFees(address,address)", + }, + Bin: "0x60806040523480156200001157600080fd5b50604051620014123803806200141283398101604081905262000034916200018e565b6200004160008262000049565b5050620001b9565b60008062000058848462000086565b905080156200007d5760008481526001602052604090206200007b908462000134565b505b90505b92915050565b6000828152602081815260408083206001600160a01b038516845290915281205460ff166200012b576000838152602081815260408083206001600160a01b03861684529091529020805460ff19166001179055620000e23390565b6001600160a01b0316826001600160a01b0316847f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a450600162000080565b50600062000080565b60006200007d836001600160a01b03841660008181526001830160205260408120546200012b5750815460018181018455600084815260208082209093018490558454848252828601909352604090209190915562000080565b600060208284031215620001a157600080fd5b81516001600160a01b03811681146200007d57600080fd5b61124980620001c96000396000f3fe608060405234801561001057600080fd5b50600436106101775760003560e01c806391d14854116100d8578063bf333f2c1161008c578063d547741f11610066578063d547741f14610385578063dcf844a714610398578063e00a83e0146103b857600080fd5b8063bf333f2c14610341578063ca15c8731461034b578063ccc574901461035e57600080fd5b8063a217fddf116100bd578063a217fddf14610313578063b13aa2d61461031b578063b250fe6b1461032e57600080fd5b806391d14854146102a8578063926d7d7f146102ec57600080fd5b80632f2ff15d1161012f57806358f858801161011457806358f85880146102405780635960ccf2146102495780639010d07c1461027057600080fd5b80632f2ff15d1461021a57806336568abe1461022d57600080fd5b806306f333f21161016057806306f333f2146101d95780630f5f6ed7146101ee578063248a9ca3146101f757600080fd5b806301ffc9a71461017c57806303ed0ee5146101a4575b600080fd5b61018f61018a366004611013565b6103c1565b60405190151581526020015b60405180910390f35b6101cb7f043c983c49d46f0e102151eaf8085d4a2e6571d5df2d47b013f39bddfd4a639d81565b60405190815260200161019b565b6101ec6101e736600461107e565b61041d565b005b6101cb61271081565b6101cb6102053660046110b1565b60009081526020819052604090206001015490565b6101ec6102283660046110ca565b61050b565b6101ec61023b3660046110ca565b610536565b6101cb60025481565b6101cb7fdb9556138406326f00296e13ea2ad7db24ba82381212d816b1a40c23b466b32781565b61028361027e3660046110ed565b61058f565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200161019b565b61018f6102b63660046110ca565b60009182526020828152604080842073ffffffffffffffffffffffffffffffffffffffff93909316845291905290205460ff1690565b6101cb7fe2b7fb3b832174769106daebcfd6d1970523240dda11281102db9363b83b0dc481565b6101cb600081565b6101ec6103293660046110b1565b6105ae565b6101ec61033c3660046110b1565b610690565b6101cb620f424081565b6101cb6103593660046110b1565b6106f8565b6101cb7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f5581565b6101ec6103933660046110ca565b61070f565b6101cb6103a636600461110f565b60036020526000908152604090205481565b6101cb60045481565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f5a05180f000000000000000000000000000000000000000000000000000000001480610417575061041782610734565b92915050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f55610447816107cb565b73ffffffffffffffffffffffffffffffffffffffff83166000908152600360205260408120549081900361047b5750505050565b73ffffffffffffffffffffffffffffffffffffffff84166000818152600360205260408120556104ac9084836107d8565b6040805173ffffffffffffffffffffffffffffffffffffffff8087168252851660208201529081018290527f244e51bc38c1452fa8aaf487bcb4bca36c2baa3a5fbdb776b1eabd8dc6d277cd9060600160405180910390a1505b505050565b600082815260208190526040902060010154610526816107cb565b610530838361092f565b50505050565b73ffffffffffffffffffffffffffffffffffffffff81163314610585576040517f6697b23200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6105068282610964565b60008281526001602052604081206105a79083610991565b9392505050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f556105d8816107cb565b612710821115610649576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f6e657746656552617465203e206d61780000000000000000000000000000000060448201526064015b60405180910390fd5b600280549083905560408051828152602081018590527f14914da2bf76024616fbe1859783fcd4dbddcb179b1f3a854949fbf920dcb95791015b60405180910390a1505050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f556106ba816107cb565b600480549083905560408051828152602081018590527f5cf09b12f3f56b4c564d51b25b40360af6d795198adb61ae0806a36c294323fa9101610683565b60008181526001602052604081206104179061099d565b60008281526020819052604090206001015461072a816107cb565b6105308383610964565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f7965db0b00000000000000000000000000000000000000000000000000000000148061041757507f01ffc9a7000000000000000000000000000000000000000000000000000000007fffffffff00000000000000000000000000000000000000000000000000000000831614610417565b6107d581336109a7565b50565b3073ffffffffffffffffffffffffffffffffffffffff8316036107fa57505050565b8060000361080757505050565b7fffffffffffffffffffffffff111111111111111111111111111111111111111273ffffffffffffffffffffffffffffffffffffffff84160161090e5760008273ffffffffffffffffffffffffffffffffffffffff168260405160006040518083038185875af1925050503d806000811461089e576040519150601f19603f3d011682016040523d82523d6000602084013e6108a3565b606091505b5050905080610530576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f455448207472616e73666572206661696c6564000000000000000000000000006044820152606401610640565b61050673ffffffffffffffffffffffffffffffffffffffff84168383610a31565b60008061093c8484610abe565b905080156105a757600084815260016020526040902061095c9084610bba565b509392505050565b6000806109718484610bdc565b905080156105a757600084815260016020526040902061095c9084610c97565b60006105a78383610cb9565b6000610417825490565b60008281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915290205460ff16610a2d576040517fe2517d3f00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8216600482015260248101839052604401610640565b5050565b6040805173ffffffffffffffffffffffffffffffffffffffff8416602482015260448082018490528251808303909101815260649091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fa9059cbb00000000000000000000000000000000000000000000000000000000179052610506908490610ce3565b60008281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915281205460ff16610bb25760008381526020818152604080832073ffffffffffffffffffffffffffffffffffffffff86168452909152902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055610b503390565b73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16847f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a4506001610417565b506000610417565b60006105a78373ffffffffffffffffffffffffffffffffffffffff8416610d79565b60008281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915281205460ff1615610bb25760008381526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8616808552925280832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016905551339286917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a4506001610417565b60006105a78373ffffffffffffffffffffffffffffffffffffffff8416610dc0565b6000826000018281548110610cd057610cd061112a565b9060005260206000200154905092915050565b6000610d0573ffffffffffffffffffffffffffffffffffffffff841683610eb3565b90508051600014158015610d2a575080806020019051810190610d289190611159565b155b15610506576040517f5274afe700000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff84166004820152602401610640565b6000818152600183016020526040812054610bb257508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155610417565b60008181526001830160205260408120548015610ea9576000610de460018361117b565b8554909150600090610df89060019061117b565b9050808214610e5d576000866000018281548110610e1857610e1861112a565b9060005260206000200154905080876000018481548110610e3b57610e3b61112a565b6000918252602080832090910192909255918252600188019052604090208390555b8554869080610e6e57610e6e6111b5565b600190038181906000526020600020016000905590558560010160008681526020019081526020016000206000905560019350505050610417565b6000915050610417565b60606105a783836000846000808573ffffffffffffffffffffffffffffffffffffffff168486604051610ee691906111e4565b60006040518083038185875af1925050503d8060008114610f23576040519150601f19603f3d011682016040523d82523d6000602084013e610f28565b606091505b5091509150610f38868383610f42565b9695505050505050565b606082610f5757610f5282610fd1565b6105a7565b8151158015610f7b575073ffffffffffffffffffffffffffffffffffffffff84163b155b15610fca576040517f9996b31500000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff85166004820152602401610640565b50806105a7565b805115610fe15780518082602001fd5b6040517f1425ea4200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006020828403121561102557600080fd5b81357fffffffff00000000000000000000000000000000000000000000000000000000811681146105a757600080fd5b803573ffffffffffffffffffffffffffffffffffffffff8116811461107957600080fd5b919050565b6000806040838503121561109157600080fd5b61109a83611055565b91506110a860208401611055565b90509250929050565b6000602082840312156110c357600080fd5b5035919050565b600080604083850312156110dd57600080fd5b823591506110a860208401611055565b6000806040838503121561110057600080fd5b50508035926020909101359150565b60006020828403121561112157600080fd5b6105a782611055565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60006020828403121561116b57600080fd5b815180151581146105a757600080fd5b81810381811115610417577f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fd5b6000825160005b8181101561120557602081860181015185830152016111eb565b50600092019182525091905056fea264697066735822122079131b92a1423b929ce85a16df536bfcfda7bffbb7079337b796201173ad4a2264736f6c63430008140033", +} + +// AdminABI is the input ABI used to generate the binding from. +// Deprecated: Use AdminMetaData.ABI instead. +var AdminABI = AdminMetaData.ABI + +// Deprecated: Use AdminMetaData.Sigs instead. +// AdminFuncSigs maps the 4-byte function signature to its string representation. +var AdminFuncSigs = AdminMetaData.Sigs + +// AdminBin is the compiled bytecode used for deploying new contracts. +// Deprecated: Use AdminMetaData.Bin instead. +var AdminBin = AdminMetaData.Bin + +// DeployAdmin deploys a new Ethereum contract, binding an instance of Admin to it. +func DeployAdmin(auth *bind.TransactOpts, backend bind.ContractBackend, _owner common.Address) (common.Address, *types.Transaction, *Admin, error) { + parsed, err := AdminMetaData.GetAbi() + if err != nil { + return common.Address{}, nil, nil, err + } + if parsed == nil { + return common.Address{}, nil, nil, errors.New("GetABI returned nil") + } + + address, tx, contract, err := bind.DeployContract(auth, *parsed, common.FromHex(AdminBin), backend, _owner) + if err != nil { + return common.Address{}, nil, nil, err + } + return address, tx, &Admin{AdminCaller: AdminCaller{contract: contract}, AdminTransactor: AdminTransactor{contract: contract}, AdminFilterer: AdminFilterer{contract: contract}}, nil +} + +// Admin is an auto generated Go binding around an Ethereum contract. +type Admin struct { + AdminCaller // Read-only binding to the contract + AdminTransactor // Write-only binding to the contract + AdminFilterer // Log filterer for contract events +} + +// AdminCaller is an auto generated read-only Go binding around an Ethereum contract. +type AdminCaller struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// AdminTransactor is an auto generated write-only Go binding around an Ethereum contract. +type AdminTransactor struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// AdminFilterer is an auto generated log filtering Go binding around an Ethereum contract events. +type AdminFilterer struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// AdminSession is an auto generated Go binding around an Ethereum contract, +// with pre-set call and transact options. +type AdminSession struct { + Contract *Admin // Generic contract binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// AdminCallerSession is an auto generated read-only Go binding around an Ethereum contract, +// with pre-set call options. +type AdminCallerSession struct { + Contract *AdminCaller // Generic contract caller binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session +} + +// AdminTransactorSession is an auto generated write-only Go binding around an Ethereum contract, +// with pre-set transact options. +type AdminTransactorSession struct { + Contract *AdminTransactor // Generic contract transactor binding to set the session for + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// AdminRaw is an auto generated low-level Go binding around an Ethereum contract. +type AdminRaw struct { + Contract *Admin // Generic contract binding to access the raw methods on +} + +// AdminCallerRaw is an auto generated low-level read-only Go binding around an Ethereum contract. +type AdminCallerRaw struct { + Contract *AdminCaller // Generic read-only contract binding to access the raw methods on +} + +// AdminTransactorRaw is an auto generated low-level write-only Go binding around an Ethereum contract. +type AdminTransactorRaw struct { + Contract *AdminTransactor // Generic write-only contract binding to access the raw methods on +} + +// NewAdmin creates a new instance of Admin, bound to a specific deployed contract. +func NewAdmin(address common.Address, backend bind.ContractBackend) (*Admin, error) { + contract, err := bindAdmin(address, backend, backend, backend) + if err != nil { + return nil, err + } + return &Admin{AdminCaller: AdminCaller{contract: contract}, AdminTransactor: AdminTransactor{contract: contract}, AdminFilterer: AdminFilterer{contract: contract}}, nil +} + +// NewAdminCaller creates a new read-only instance of Admin, bound to a specific deployed contract. +func NewAdminCaller(address common.Address, caller bind.ContractCaller) (*AdminCaller, error) { + contract, err := bindAdmin(address, caller, nil, nil) + if err != nil { + return nil, err + } + return &AdminCaller{contract: contract}, nil +} + +// NewAdminTransactor creates a new write-only instance of Admin, bound to a specific deployed contract. +func NewAdminTransactor(address common.Address, transactor bind.ContractTransactor) (*AdminTransactor, error) { + contract, err := bindAdmin(address, nil, transactor, nil) + if err != nil { + return nil, err + } + return &AdminTransactor{contract: contract}, nil +} + +// NewAdminFilterer creates a new log filterer instance of Admin, bound to a specific deployed contract. +func NewAdminFilterer(address common.Address, filterer bind.ContractFilterer) (*AdminFilterer, error) { + contract, err := bindAdmin(address, nil, nil, filterer) + if err != nil { + return nil, err + } + return &AdminFilterer{contract: contract}, nil +} + +// bindAdmin binds a generic wrapper to an already deployed contract. +func bindAdmin(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) { + parsed, err := AdminMetaData.GetAbi() + if err != nil { + return nil, err + } + return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil +} + +// Call invokes the (constant) contract method with params as input values and +// sets the output to result. The result type might be a single field for simple +// returns, a slice of interfaces for anonymous returns and a struct for named +// returns. +func (_Admin *AdminRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _Admin.Contract.AdminCaller.contract.Call(opts, result, method, params...) +} + +// Transfer initiates a plain transaction to move funds to the contract, calling +// its default method if one is available. +func (_Admin *AdminRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _Admin.Contract.AdminTransactor.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_Admin *AdminRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _Admin.Contract.AdminTransactor.contract.Transact(opts, method, params...) +} + +// Call invokes the (constant) contract method with params as input values and +// sets the output to result. The result type might be a single field for simple +// returns, a slice of interfaces for anonymous returns and a struct for named +// returns. +func (_Admin *AdminCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _Admin.Contract.contract.Call(opts, result, method, params...) +} + +// Transfer initiates a plain transaction to move funds to the contract, calling +// its default method if one is available. +func (_Admin *AdminTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _Admin.Contract.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_Admin *AdminTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _Admin.Contract.contract.Transact(opts, method, params...) +} + +// DEFAULTADMINROLE is a free data retrieval call binding the contract method 0xa217fddf. +// +// Solidity: function DEFAULT_ADMIN_ROLE() view returns(bytes32) +func (_Admin *AdminCaller) DEFAULTADMINROLE(opts *bind.CallOpts) ([32]byte, error) { + var out []interface{} + err := _Admin.contract.Call(opts, &out, "DEFAULT_ADMIN_ROLE") + + if err != nil { + return *new([32]byte), err + } + + out0 := *abi.ConvertType(out[0], new([32]byte)).(*[32]byte) + + return out0, err + +} + +// DEFAULTADMINROLE is a free data retrieval call binding the contract method 0xa217fddf. +// +// Solidity: function DEFAULT_ADMIN_ROLE() view returns(bytes32) +func (_Admin *AdminSession) DEFAULTADMINROLE() ([32]byte, error) { + return _Admin.Contract.DEFAULTADMINROLE(&_Admin.CallOpts) +} + +// DEFAULTADMINROLE is a free data retrieval call binding the contract method 0xa217fddf. +// +// Solidity: function DEFAULT_ADMIN_ROLE() view returns(bytes32) +func (_Admin *AdminCallerSession) DEFAULTADMINROLE() ([32]byte, error) { + return _Admin.Contract.DEFAULTADMINROLE(&_Admin.CallOpts) +} + +// FEEBPS is a free data retrieval call binding the contract method 0xbf333f2c. +// +// Solidity: function FEE_BPS() view returns(uint256) +func (_Admin *AdminCaller) FEEBPS(opts *bind.CallOpts) (*big.Int, error) { + var out []interface{} + err := _Admin.contract.Call(opts, &out, "FEE_BPS") + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// FEEBPS is a free data retrieval call binding the contract method 0xbf333f2c. +// +// Solidity: function FEE_BPS() view returns(uint256) +func (_Admin *AdminSession) FEEBPS() (*big.Int, error) { + return _Admin.Contract.FEEBPS(&_Admin.CallOpts) +} + +// FEEBPS is a free data retrieval call binding the contract method 0xbf333f2c. +// +// Solidity: function FEE_BPS() view returns(uint256) +func (_Admin *AdminCallerSession) FEEBPS() (*big.Int, error) { + return _Admin.Contract.FEEBPS(&_Admin.CallOpts) +} + +// FEERATEMAX is a free data retrieval call binding the contract method 0x0f5f6ed7. +// +// Solidity: function FEE_RATE_MAX() view returns(uint256) +func (_Admin *AdminCaller) FEERATEMAX(opts *bind.CallOpts) (*big.Int, error) { + var out []interface{} + err := _Admin.contract.Call(opts, &out, "FEE_RATE_MAX") + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// FEERATEMAX is a free data retrieval call binding the contract method 0x0f5f6ed7. +// +// Solidity: function FEE_RATE_MAX() view returns(uint256) +func (_Admin *AdminSession) FEERATEMAX() (*big.Int, error) { + return _Admin.Contract.FEERATEMAX(&_Admin.CallOpts) +} + +// FEERATEMAX is a free data retrieval call binding the contract method 0x0f5f6ed7. +// +// Solidity: function FEE_RATE_MAX() view returns(uint256) +func (_Admin *AdminCallerSession) FEERATEMAX() (*big.Int, error) { + return _Admin.Contract.FEERATEMAX(&_Admin.CallOpts) +} + +// GOVERNORROLE is a free data retrieval call binding the contract method 0xccc57490. +// +// Solidity: function GOVERNOR_ROLE() view returns(bytes32) +func (_Admin *AdminCaller) GOVERNORROLE(opts *bind.CallOpts) ([32]byte, error) { + var out []interface{} + err := _Admin.contract.Call(opts, &out, "GOVERNOR_ROLE") + + if err != nil { + return *new([32]byte), err + } + + out0 := *abi.ConvertType(out[0], new([32]byte)).(*[32]byte) + + return out0, err + +} + +// GOVERNORROLE is a free data retrieval call binding the contract method 0xccc57490. +// +// Solidity: function GOVERNOR_ROLE() view returns(bytes32) +func (_Admin *AdminSession) GOVERNORROLE() ([32]byte, error) { + return _Admin.Contract.GOVERNORROLE(&_Admin.CallOpts) +} + +// GOVERNORROLE is a free data retrieval call binding the contract method 0xccc57490. +// +// Solidity: function GOVERNOR_ROLE() view returns(bytes32) +func (_Admin *AdminCallerSession) GOVERNORROLE() ([32]byte, error) { + return _Admin.Contract.GOVERNORROLE(&_Admin.CallOpts) +} + +// GUARDROLE is a free data retrieval call binding the contract method 0x03ed0ee5. +// +// Solidity: function GUARD_ROLE() view returns(bytes32) +func (_Admin *AdminCaller) GUARDROLE(opts *bind.CallOpts) ([32]byte, error) { + var out []interface{} + err := _Admin.contract.Call(opts, &out, "GUARD_ROLE") + + if err != nil { + return *new([32]byte), err + } + + out0 := *abi.ConvertType(out[0], new([32]byte)).(*[32]byte) + + return out0, err + +} + +// GUARDROLE is a free data retrieval call binding the contract method 0x03ed0ee5. +// +// Solidity: function GUARD_ROLE() view returns(bytes32) +func (_Admin *AdminSession) GUARDROLE() ([32]byte, error) { + return _Admin.Contract.GUARDROLE(&_Admin.CallOpts) +} + +// GUARDROLE is a free data retrieval call binding the contract method 0x03ed0ee5. +// +// Solidity: function GUARD_ROLE() view returns(bytes32) +func (_Admin *AdminCallerSession) GUARDROLE() ([32]byte, error) { + return _Admin.Contract.GUARDROLE(&_Admin.CallOpts) +} + +// REFUNDERROLE is a free data retrieval call binding the contract method 0x5960ccf2. +// +// Solidity: function REFUNDER_ROLE() view returns(bytes32) +func (_Admin *AdminCaller) REFUNDERROLE(opts *bind.CallOpts) ([32]byte, error) { + var out []interface{} + err := _Admin.contract.Call(opts, &out, "REFUNDER_ROLE") + + if err != nil { + return *new([32]byte), err + } + + out0 := *abi.ConvertType(out[0], new([32]byte)).(*[32]byte) + + return out0, err + +} + +// REFUNDERROLE is a free data retrieval call binding the contract method 0x5960ccf2. +// +// Solidity: function REFUNDER_ROLE() view returns(bytes32) +func (_Admin *AdminSession) REFUNDERROLE() ([32]byte, error) { + return _Admin.Contract.REFUNDERROLE(&_Admin.CallOpts) +} + +// REFUNDERROLE is a free data retrieval call binding the contract method 0x5960ccf2. +// +// Solidity: function REFUNDER_ROLE() view returns(bytes32) +func (_Admin *AdminCallerSession) REFUNDERROLE() ([32]byte, error) { + return _Admin.Contract.REFUNDERROLE(&_Admin.CallOpts) +} + +// RELAYERROLE is a free data retrieval call binding the contract method 0x926d7d7f. +// +// Solidity: function RELAYER_ROLE() view returns(bytes32) +func (_Admin *AdminCaller) RELAYERROLE(opts *bind.CallOpts) ([32]byte, error) { + var out []interface{} + err := _Admin.contract.Call(opts, &out, "RELAYER_ROLE") + + if err != nil { + return *new([32]byte), err + } + + out0 := *abi.ConvertType(out[0], new([32]byte)).(*[32]byte) + + return out0, err + +} + +// RELAYERROLE is a free data retrieval call binding the contract method 0x926d7d7f. +// +// Solidity: function RELAYER_ROLE() view returns(bytes32) +func (_Admin *AdminSession) RELAYERROLE() ([32]byte, error) { + return _Admin.Contract.RELAYERROLE(&_Admin.CallOpts) +} + +// RELAYERROLE is a free data retrieval call binding the contract method 0x926d7d7f. +// +// Solidity: function RELAYER_ROLE() view returns(bytes32) +func (_Admin *AdminCallerSession) RELAYERROLE() ([32]byte, error) { + return _Admin.Contract.RELAYERROLE(&_Admin.CallOpts) +} + +// ChainGasAmount is a free data retrieval call binding the contract method 0xe00a83e0. +// +// Solidity: function chainGasAmount() view returns(uint256) +func (_Admin *AdminCaller) ChainGasAmount(opts *bind.CallOpts) (*big.Int, error) { + var out []interface{} + err := _Admin.contract.Call(opts, &out, "chainGasAmount") + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// ChainGasAmount is a free data retrieval call binding the contract method 0xe00a83e0. +// +// Solidity: function chainGasAmount() view returns(uint256) +func (_Admin *AdminSession) ChainGasAmount() (*big.Int, error) { + return _Admin.Contract.ChainGasAmount(&_Admin.CallOpts) +} + +// ChainGasAmount is a free data retrieval call binding the contract method 0xe00a83e0. +// +// Solidity: function chainGasAmount() view returns(uint256) +func (_Admin *AdminCallerSession) ChainGasAmount() (*big.Int, error) { + return _Admin.Contract.ChainGasAmount(&_Admin.CallOpts) +} + +// GetRoleAdmin is a free data retrieval call binding the contract method 0x248a9ca3. +// +// Solidity: function getRoleAdmin(bytes32 role) view returns(bytes32) +func (_Admin *AdminCaller) GetRoleAdmin(opts *bind.CallOpts, role [32]byte) ([32]byte, error) { + var out []interface{} + err := _Admin.contract.Call(opts, &out, "getRoleAdmin", role) + + if err != nil { + return *new([32]byte), err + } + + out0 := *abi.ConvertType(out[0], new([32]byte)).(*[32]byte) + + return out0, err + +} + +// GetRoleAdmin is a free data retrieval call binding the contract method 0x248a9ca3. +// +// Solidity: function getRoleAdmin(bytes32 role) view returns(bytes32) +func (_Admin *AdminSession) GetRoleAdmin(role [32]byte) ([32]byte, error) { + return _Admin.Contract.GetRoleAdmin(&_Admin.CallOpts, role) +} + +// GetRoleAdmin is a free data retrieval call binding the contract method 0x248a9ca3. +// +// Solidity: function getRoleAdmin(bytes32 role) view returns(bytes32) +func (_Admin *AdminCallerSession) GetRoleAdmin(role [32]byte) ([32]byte, error) { + return _Admin.Contract.GetRoleAdmin(&_Admin.CallOpts, role) +} + +// GetRoleMember is a free data retrieval call binding the contract method 0x9010d07c. +// +// Solidity: function getRoleMember(bytes32 role, uint256 index) view returns(address) +func (_Admin *AdminCaller) GetRoleMember(opts *bind.CallOpts, role [32]byte, index *big.Int) (common.Address, error) { + var out []interface{} + err := _Admin.contract.Call(opts, &out, "getRoleMember", role, index) + + if err != nil { + return *new(common.Address), err + } + + out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) + + return out0, err + +} + +// GetRoleMember is a free data retrieval call binding the contract method 0x9010d07c. +// +// Solidity: function getRoleMember(bytes32 role, uint256 index) view returns(address) +func (_Admin *AdminSession) GetRoleMember(role [32]byte, index *big.Int) (common.Address, error) { + return _Admin.Contract.GetRoleMember(&_Admin.CallOpts, role, index) +} + +// GetRoleMember is a free data retrieval call binding the contract method 0x9010d07c. +// +// Solidity: function getRoleMember(bytes32 role, uint256 index) view returns(address) +func (_Admin *AdminCallerSession) GetRoleMember(role [32]byte, index *big.Int) (common.Address, error) { + return _Admin.Contract.GetRoleMember(&_Admin.CallOpts, role, index) +} + +// GetRoleMemberCount is a free data retrieval call binding the contract method 0xca15c873. +// +// Solidity: function getRoleMemberCount(bytes32 role) view returns(uint256) +func (_Admin *AdminCaller) GetRoleMemberCount(opts *bind.CallOpts, role [32]byte) (*big.Int, error) { + var out []interface{} + err := _Admin.contract.Call(opts, &out, "getRoleMemberCount", role) + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// GetRoleMemberCount is a free data retrieval call binding the contract method 0xca15c873. +// +// Solidity: function getRoleMemberCount(bytes32 role) view returns(uint256) +func (_Admin *AdminSession) GetRoleMemberCount(role [32]byte) (*big.Int, error) { + return _Admin.Contract.GetRoleMemberCount(&_Admin.CallOpts, role) +} + +// GetRoleMemberCount is a free data retrieval call binding the contract method 0xca15c873. +// +// Solidity: function getRoleMemberCount(bytes32 role) view returns(uint256) +func (_Admin *AdminCallerSession) GetRoleMemberCount(role [32]byte) (*big.Int, error) { + return _Admin.Contract.GetRoleMemberCount(&_Admin.CallOpts, role) +} + +// HasRole is a free data retrieval call binding the contract method 0x91d14854. +// +// Solidity: function hasRole(bytes32 role, address account) view returns(bool) +func (_Admin *AdminCaller) HasRole(opts *bind.CallOpts, role [32]byte, account common.Address) (bool, error) { + var out []interface{} + err := _Admin.contract.Call(opts, &out, "hasRole", role, account) + + if err != nil { + return *new(bool), err + } + + out0 := *abi.ConvertType(out[0], new(bool)).(*bool) + + return out0, err + +} + +// HasRole is a free data retrieval call binding the contract method 0x91d14854. +// +// Solidity: function hasRole(bytes32 role, address account) view returns(bool) +func (_Admin *AdminSession) HasRole(role [32]byte, account common.Address) (bool, error) { + return _Admin.Contract.HasRole(&_Admin.CallOpts, role, account) +} + +// HasRole is a free data retrieval call binding the contract method 0x91d14854. +// +// Solidity: function hasRole(bytes32 role, address account) view returns(bool) +func (_Admin *AdminCallerSession) HasRole(role [32]byte, account common.Address) (bool, error) { + return _Admin.Contract.HasRole(&_Admin.CallOpts, role, account) +} + +// ProtocolFeeRate is a free data retrieval call binding the contract method 0x58f85880. +// +// Solidity: function protocolFeeRate() view returns(uint256) +func (_Admin *AdminCaller) ProtocolFeeRate(opts *bind.CallOpts) (*big.Int, error) { + var out []interface{} + err := _Admin.contract.Call(opts, &out, "protocolFeeRate") + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// ProtocolFeeRate is a free data retrieval call binding the contract method 0x58f85880. +// +// Solidity: function protocolFeeRate() view returns(uint256) +func (_Admin *AdminSession) ProtocolFeeRate() (*big.Int, error) { + return _Admin.Contract.ProtocolFeeRate(&_Admin.CallOpts) +} + +// ProtocolFeeRate is a free data retrieval call binding the contract method 0x58f85880. +// +// Solidity: function protocolFeeRate() view returns(uint256) +func (_Admin *AdminCallerSession) ProtocolFeeRate() (*big.Int, error) { + return _Admin.Contract.ProtocolFeeRate(&_Admin.CallOpts) +} + +// ProtocolFees is a free data retrieval call binding the contract method 0xdcf844a7. +// +// Solidity: function protocolFees(address ) view returns(uint256) +func (_Admin *AdminCaller) ProtocolFees(opts *bind.CallOpts, arg0 common.Address) (*big.Int, error) { + var out []interface{} + err := _Admin.contract.Call(opts, &out, "protocolFees", arg0) + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// ProtocolFees is a free data retrieval call binding the contract method 0xdcf844a7. +// +// Solidity: function protocolFees(address ) view returns(uint256) +func (_Admin *AdminSession) ProtocolFees(arg0 common.Address) (*big.Int, error) { + return _Admin.Contract.ProtocolFees(&_Admin.CallOpts, arg0) +} + +// ProtocolFees is a free data retrieval call binding the contract method 0xdcf844a7. +// +// Solidity: function protocolFees(address ) view returns(uint256) +func (_Admin *AdminCallerSession) ProtocolFees(arg0 common.Address) (*big.Int, error) { + return _Admin.Contract.ProtocolFees(&_Admin.CallOpts, arg0) +} + +// SupportsInterface is a free data retrieval call binding the contract method 0x01ffc9a7. +// +// Solidity: function supportsInterface(bytes4 interfaceId) view returns(bool) +func (_Admin *AdminCaller) SupportsInterface(opts *bind.CallOpts, interfaceId [4]byte) (bool, error) { + var out []interface{} + err := _Admin.contract.Call(opts, &out, "supportsInterface", interfaceId) + + if err != nil { + return *new(bool), err + } + + out0 := *abi.ConvertType(out[0], new(bool)).(*bool) + + return out0, err + +} + +// SupportsInterface is a free data retrieval call binding the contract method 0x01ffc9a7. +// +// Solidity: function supportsInterface(bytes4 interfaceId) view returns(bool) +func (_Admin *AdminSession) SupportsInterface(interfaceId [4]byte) (bool, error) { + return _Admin.Contract.SupportsInterface(&_Admin.CallOpts, interfaceId) +} + +// SupportsInterface is a free data retrieval call binding the contract method 0x01ffc9a7. +// +// Solidity: function supportsInterface(bytes4 interfaceId) view returns(bool) +func (_Admin *AdminCallerSession) SupportsInterface(interfaceId [4]byte) (bool, error) { + return _Admin.Contract.SupportsInterface(&_Admin.CallOpts, interfaceId) +} + +// GrantRole is a paid mutator transaction binding the contract method 0x2f2ff15d. +// +// Solidity: function grantRole(bytes32 role, address account) returns() +func (_Admin *AdminTransactor) GrantRole(opts *bind.TransactOpts, role [32]byte, account common.Address) (*types.Transaction, error) { + return _Admin.contract.Transact(opts, "grantRole", role, account) +} + +// GrantRole is a paid mutator transaction binding the contract method 0x2f2ff15d. +// +// Solidity: function grantRole(bytes32 role, address account) returns() +func (_Admin *AdminSession) GrantRole(role [32]byte, account common.Address) (*types.Transaction, error) { + return _Admin.Contract.GrantRole(&_Admin.TransactOpts, role, account) +} + +// GrantRole is a paid mutator transaction binding the contract method 0x2f2ff15d. +// +// Solidity: function grantRole(bytes32 role, address account) returns() +func (_Admin *AdminTransactorSession) GrantRole(role [32]byte, account common.Address) (*types.Transaction, error) { + return _Admin.Contract.GrantRole(&_Admin.TransactOpts, role, account) +} + +// RenounceRole is a paid mutator transaction binding the contract method 0x36568abe. +// +// Solidity: function renounceRole(bytes32 role, address callerConfirmation) returns() +func (_Admin *AdminTransactor) RenounceRole(opts *bind.TransactOpts, role [32]byte, callerConfirmation common.Address) (*types.Transaction, error) { + return _Admin.contract.Transact(opts, "renounceRole", role, callerConfirmation) +} + +// RenounceRole is a paid mutator transaction binding the contract method 0x36568abe. +// +// Solidity: function renounceRole(bytes32 role, address callerConfirmation) returns() +func (_Admin *AdminSession) RenounceRole(role [32]byte, callerConfirmation common.Address) (*types.Transaction, error) { + return _Admin.Contract.RenounceRole(&_Admin.TransactOpts, role, callerConfirmation) +} + +// RenounceRole is a paid mutator transaction binding the contract method 0x36568abe. +// +// Solidity: function renounceRole(bytes32 role, address callerConfirmation) returns() +func (_Admin *AdminTransactorSession) RenounceRole(role [32]byte, callerConfirmation common.Address) (*types.Transaction, error) { + return _Admin.Contract.RenounceRole(&_Admin.TransactOpts, role, callerConfirmation) +} + +// RevokeRole is a paid mutator transaction binding the contract method 0xd547741f. +// +// Solidity: function revokeRole(bytes32 role, address account) returns() +func (_Admin *AdminTransactor) RevokeRole(opts *bind.TransactOpts, role [32]byte, account common.Address) (*types.Transaction, error) { + return _Admin.contract.Transact(opts, "revokeRole", role, account) +} + +// RevokeRole is a paid mutator transaction binding the contract method 0xd547741f. +// +// Solidity: function revokeRole(bytes32 role, address account) returns() +func (_Admin *AdminSession) RevokeRole(role [32]byte, account common.Address) (*types.Transaction, error) { + return _Admin.Contract.RevokeRole(&_Admin.TransactOpts, role, account) +} + +// RevokeRole is a paid mutator transaction binding the contract method 0xd547741f. +// +// Solidity: function revokeRole(bytes32 role, address account) returns() +func (_Admin *AdminTransactorSession) RevokeRole(role [32]byte, account common.Address) (*types.Transaction, error) { + return _Admin.Contract.RevokeRole(&_Admin.TransactOpts, role, account) +} + +// SetChainGasAmount is a paid mutator transaction binding the contract method 0xb250fe6b. +// +// Solidity: function setChainGasAmount(uint256 newChainGasAmount) returns() +func (_Admin *AdminTransactor) SetChainGasAmount(opts *bind.TransactOpts, newChainGasAmount *big.Int) (*types.Transaction, error) { + return _Admin.contract.Transact(opts, "setChainGasAmount", newChainGasAmount) +} + +// SetChainGasAmount is a paid mutator transaction binding the contract method 0xb250fe6b. +// +// Solidity: function setChainGasAmount(uint256 newChainGasAmount) returns() +func (_Admin *AdminSession) SetChainGasAmount(newChainGasAmount *big.Int) (*types.Transaction, error) { + return _Admin.Contract.SetChainGasAmount(&_Admin.TransactOpts, newChainGasAmount) +} + +// SetChainGasAmount is a paid mutator transaction binding the contract method 0xb250fe6b. +// +// Solidity: function setChainGasAmount(uint256 newChainGasAmount) returns() +func (_Admin *AdminTransactorSession) SetChainGasAmount(newChainGasAmount *big.Int) (*types.Transaction, error) { + return _Admin.Contract.SetChainGasAmount(&_Admin.TransactOpts, newChainGasAmount) +} + +// SetProtocolFeeRate is a paid mutator transaction binding the contract method 0xb13aa2d6. +// +// Solidity: function setProtocolFeeRate(uint256 newFeeRate) returns() +func (_Admin *AdminTransactor) SetProtocolFeeRate(opts *bind.TransactOpts, newFeeRate *big.Int) (*types.Transaction, error) { + return _Admin.contract.Transact(opts, "setProtocolFeeRate", newFeeRate) +} + +// SetProtocolFeeRate is a paid mutator transaction binding the contract method 0xb13aa2d6. +// +// Solidity: function setProtocolFeeRate(uint256 newFeeRate) returns() +func (_Admin *AdminSession) SetProtocolFeeRate(newFeeRate *big.Int) (*types.Transaction, error) { + return _Admin.Contract.SetProtocolFeeRate(&_Admin.TransactOpts, newFeeRate) +} + +// SetProtocolFeeRate is a paid mutator transaction binding the contract method 0xb13aa2d6. +// +// Solidity: function setProtocolFeeRate(uint256 newFeeRate) returns() +func (_Admin *AdminTransactorSession) SetProtocolFeeRate(newFeeRate *big.Int) (*types.Transaction, error) { + return _Admin.Contract.SetProtocolFeeRate(&_Admin.TransactOpts, newFeeRate) +} + +// SweepProtocolFees is a paid mutator transaction binding the contract method 0x06f333f2. +// +// Solidity: function sweepProtocolFees(address token, address recipient) returns() +func (_Admin *AdminTransactor) SweepProtocolFees(opts *bind.TransactOpts, token common.Address, recipient common.Address) (*types.Transaction, error) { + return _Admin.contract.Transact(opts, "sweepProtocolFees", token, recipient) +} + +// SweepProtocolFees is a paid mutator transaction binding the contract method 0x06f333f2. +// +// Solidity: function sweepProtocolFees(address token, address recipient) returns() +func (_Admin *AdminSession) SweepProtocolFees(token common.Address, recipient common.Address) (*types.Transaction, error) { + return _Admin.Contract.SweepProtocolFees(&_Admin.TransactOpts, token, recipient) +} + +// SweepProtocolFees is a paid mutator transaction binding the contract method 0x06f333f2. +// +// Solidity: function sweepProtocolFees(address token, address recipient) returns() +func (_Admin *AdminTransactorSession) SweepProtocolFees(token common.Address, recipient common.Address) (*types.Transaction, error) { + return _Admin.Contract.SweepProtocolFees(&_Admin.TransactOpts, token, recipient) +} + +// AdminChainGasAmountUpdatedIterator is returned from FilterChainGasAmountUpdated and is used to iterate over the raw logs and unpacked data for ChainGasAmountUpdated events raised by the Admin contract. +type AdminChainGasAmountUpdatedIterator struct { + Event *AdminChainGasAmountUpdated // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *AdminChainGasAmountUpdatedIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(AdminChainGasAmountUpdated) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(AdminChainGasAmountUpdated) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *AdminChainGasAmountUpdatedIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *AdminChainGasAmountUpdatedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// AdminChainGasAmountUpdated represents a ChainGasAmountUpdated event raised by the Admin contract. +type AdminChainGasAmountUpdated struct { + OldChainGasAmount *big.Int + NewChainGasAmount *big.Int + Raw types.Log // Blockchain specific contextual infos +} + +// FilterChainGasAmountUpdated is a free log retrieval operation binding the contract event 0x5cf09b12f3f56b4c564d51b25b40360af6d795198adb61ae0806a36c294323fa. +// +// Solidity: event ChainGasAmountUpdated(uint256 oldChainGasAmount, uint256 newChainGasAmount) +func (_Admin *AdminFilterer) FilterChainGasAmountUpdated(opts *bind.FilterOpts) (*AdminChainGasAmountUpdatedIterator, error) { + + logs, sub, err := _Admin.contract.FilterLogs(opts, "ChainGasAmountUpdated") + if err != nil { + return nil, err + } + return &AdminChainGasAmountUpdatedIterator{contract: _Admin.contract, event: "ChainGasAmountUpdated", logs: logs, sub: sub}, nil +} + +// WatchChainGasAmountUpdated is a free log subscription operation binding the contract event 0x5cf09b12f3f56b4c564d51b25b40360af6d795198adb61ae0806a36c294323fa. +// +// Solidity: event ChainGasAmountUpdated(uint256 oldChainGasAmount, uint256 newChainGasAmount) +func (_Admin *AdminFilterer) WatchChainGasAmountUpdated(opts *bind.WatchOpts, sink chan<- *AdminChainGasAmountUpdated) (event.Subscription, error) { + + logs, sub, err := _Admin.contract.WatchLogs(opts, "ChainGasAmountUpdated") + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(AdminChainGasAmountUpdated) + if err := _Admin.contract.UnpackLog(event, "ChainGasAmountUpdated", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseChainGasAmountUpdated is a log parse operation binding the contract event 0x5cf09b12f3f56b4c564d51b25b40360af6d795198adb61ae0806a36c294323fa. +// +// Solidity: event ChainGasAmountUpdated(uint256 oldChainGasAmount, uint256 newChainGasAmount) +func (_Admin *AdminFilterer) ParseChainGasAmountUpdated(log types.Log) (*AdminChainGasAmountUpdated, error) { + event := new(AdminChainGasAmountUpdated) + if err := _Admin.contract.UnpackLog(event, "ChainGasAmountUpdated", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// AdminFeeRateUpdatedIterator is returned from FilterFeeRateUpdated and is used to iterate over the raw logs and unpacked data for FeeRateUpdated events raised by the Admin contract. +type AdminFeeRateUpdatedIterator struct { + Event *AdminFeeRateUpdated // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *AdminFeeRateUpdatedIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(AdminFeeRateUpdated) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(AdminFeeRateUpdated) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *AdminFeeRateUpdatedIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *AdminFeeRateUpdatedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// AdminFeeRateUpdated represents a FeeRateUpdated event raised by the Admin contract. +type AdminFeeRateUpdated struct { + OldFeeRate *big.Int + NewFeeRate *big.Int + Raw types.Log // Blockchain specific contextual infos +} + +// FilterFeeRateUpdated is a free log retrieval operation binding the contract event 0x14914da2bf76024616fbe1859783fcd4dbddcb179b1f3a854949fbf920dcb957. +// +// Solidity: event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate) +func (_Admin *AdminFilterer) FilterFeeRateUpdated(opts *bind.FilterOpts) (*AdminFeeRateUpdatedIterator, error) { + + logs, sub, err := _Admin.contract.FilterLogs(opts, "FeeRateUpdated") + if err != nil { + return nil, err + } + return &AdminFeeRateUpdatedIterator{contract: _Admin.contract, event: "FeeRateUpdated", logs: logs, sub: sub}, nil +} + +// WatchFeeRateUpdated is a free log subscription operation binding the contract event 0x14914da2bf76024616fbe1859783fcd4dbddcb179b1f3a854949fbf920dcb957. +// +// Solidity: event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate) +func (_Admin *AdminFilterer) WatchFeeRateUpdated(opts *bind.WatchOpts, sink chan<- *AdminFeeRateUpdated) (event.Subscription, error) { + + logs, sub, err := _Admin.contract.WatchLogs(opts, "FeeRateUpdated") + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(AdminFeeRateUpdated) + if err := _Admin.contract.UnpackLog(event, "FeeRateUpdated", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseFeeRateUpdated is a log parse operation binding the contract event 0x14914da2bf76024616fbe1859783fcd4dbddcb179b1f3a854949fbf920dcb957. +// +// Solidity: event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate) +func (_Admin *AdminFilterer) ParseFeeRateUpdated(log types.Log) (*AdminFeeRateUpdated, error) { + event := new(AdminFeeRateUpdated) + if err := _Admin.contract.UnpackLog(event, "FeeRateUpdated", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// AdminFeesSweptIterator is returned from FilterFeesSwept and is used to iterate over the raw logs and unpacked data for FeesSwept events raised by the Admin contract. +type AdminFeesSweptIterator struct { + Event *AdminFeesSwept // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *AdminFeesSweptIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(AdminFeesSwept) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(AdminFeesSwept) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *AdminFeesSweptIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *AdminFeesSweptIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// AdminFeesSwept represents a FeesSwept event raised by the Admin contract. +type AdminFeesSwept struct { + Token common.Address + Recipient common.Address + Amount *big.Int + Raw types.Log // Blockchain specific contextual infos +} + +// FilterFeesSwept is a free log retrieval operation binding the contract event 0x244e51bc38c1452fa8aaf487bcb4bca36c2baa3a5fbdb776b1eabd8dc6d277cd. +// +// Solidity: event FeesSwept(address token, address recipient, uint256 amount) +func (_Admin *AdminFilterer) FilterFeesSwept(opts *bind.FilterOpts) (*AdminFeesSweptIterator, error) { + + logs, sub, err := _Admin.contract.FilterLogs(opts, "FeesSwept") + if err != nil { + return nil, err + } + return &AdminFeesSweptIterator{contract: _Admin.contract, event: "FeesSwept", logs: logs, sub: sub}, nil +} + +// WatchFeesSwept is a free log subscription operation binding the contract event 0x244e51bc38c1452fa8aaf487bcb4bca36c2baa3a5fbdb776b1eabd8dc6d277cd. +// +// Solidity: event FeesSwept(address token, address recipient, uint256 amount) +func (_Admin *AdminFilterer) WatchFeesSwept(opts *bind.WatchOpts, sink chan<- *AdminFeesSwept) (event.Subscription, error) { + + logs, sub, err := _Admin.contract.WatchLogs(opts, "FeesSwept") + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(AdminFeesSwept) + if err := _Admin.contract.UnpackLog(event, "FeesSwept", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseFeesSwept is a log parse operation binding the contract event 0x244e51bc38c1452fa8aaf487bcb4bca36c2baa3a5fbdb776b1eabd8dc6d277cd. +// +// Solidity: event FeesSwept(address token, address recipient, uint256 amount) +func (_Admin *AdminFilterer) ParseFeesSwept(log types.Log) (*AdminFeesSwept, error) { + event := new(AdminFeesSwept) + if err := _Admin.contract.UnpackLog(event, "FeesSwept", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// AdminRoleAdminChangedIterator is returned from FilterRoleAdminChanged and is used to iterate over the raw logs and unpacked data for RoleAdminChanged events raised by the Admin contract. +type AdminRoleAdminChangedIterator struct { + Event *AdminRoleAdminChanged // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *AdminRoleAdminChangedIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(AdminRoleAdminChanged) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(AdminRoleAdminChanged) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *AdminRoleAdminChangedIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *AdminRoleAdminChangedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// AdminRoleAdminChanged represents a RoleAdminChanged event raised by the Admin contract. +type AdminRoleAdminChanged struct { + Role [32]byte + PreviousAdminRole [32]byte + NewAdminRole [32]byte + Raw types.Log // Blockchain specific contextual infos +} + +// FilterRoleAdminChanged is a free log retrieval operation binding the contract event 0xbd79b86ffe0ab8e8776151514217cd7cacd52c909f66475c3af44e129f0b00ff. +// +// Solidity: event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole) +func (_Admin *AdminFilterer) FilterRoleAdminChanged(opts *bind.FilterOpts, role [][32]byte, previousAdminRole [][32]byte, newAdminRole [][32]byte) (*AdminRoleAdminChangedIterator, error) { + + var roleRule []interface{} + for _, roleItem := range role { + roleRule = append(roleRule, roleItem) + } + var previousAdminRoleRule []interface{} + for _, previousAdminRoleItem := range previousAdminRole { + previousAdminRoleRule = append(previousAdminRoleRule, previousAdminRoleItem) + } + var newAdminRoleRule []interface{} + for _, newAdminRoleItem := range newAdminRole { + newAdminRoleRule = append(newAdminRoleRule, newAdminRoleItem) + } + + logs, sub, err := _Admin.contract.FilterLogs(opts, "RoleAdminChanged", roleRule, previousAdminRoleRule, newAdminRoleRule) + if err != nil { + return nil, err + } + return &AdminRoleAdminChangedIterator{contract: _Admin.contract, event: "RoleAdminChanged", logs: logs, sub: sub}, nil +} + +// WatchRoleAdminChanged is a free log subscription operation binding the contract event 0xbd79b86ffe0ab8e8776151514217cd7cacd52c909f66475c3af44e129f0b00ff. +// +// Solidity: event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole) +func (_Admin *AdminFilterer) WatchRoleAdminChanged(opts *bind.WatchOpts, sink chan<- *AdminRoleAdminChanged, role [][32]byte, previousAdminRole [][32]byte, newAdminRole [][32]byte) (event.Subscription, error) { + + var roleRule []interface{} + for _, roleItem := range role { + roleRule = append(roleRule, roleItem) + } + var previousAdminRoleRule []interface{} + for _, previousAdminRoleItem := range previousAdminRole { + previousAdminRoleRule = append(previousAdminRoleRule, previousAdminRoleItem) + } + var newAdminRoleRule []interface{} + for _, newAdminRoleItem := range newAdminRole { + newAdminRoleRule = append(newAdminRoleRule, newAdminRoleItem) + } + + logs, sub, err := _Admin.contract.WatchLogs(opts, "RoleAdminChanged", roleRule, previousAdminRoleRule, newAdminRoleRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(AdminRoleAdminChanged) + if err := _Admin.contract.UnpackLog(event, "RoleAdminChanged", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseRoleAdminChanged is a log parse operation binding the contract event 0xbd79b86ffe0ab8e8776151514217cd7cacd52c909f66475c3af44e129f0b00ff. +// +// Solidity: event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole) +func (_Admin *AdminFilterer) ParseRoleAdminChanged(log types.Log) (*AdminRoleAdminChanged, error) { + event := new(AdminRoleAdminChanged) + if err := _Admin.contract.UnpackLog(event, "RoleAdminChanged", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// AdminRoleGrantedIterator is returned from FilterRoleGranted and is used to iterate over the raw logs and unpacked data for RoleGranted events raised by the Admin contract. +type AdminRoleGrantedIterator struct { + Event *AdminRoleGranted // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *AdminRoleGrantedIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(AdminRoleGranted) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(AdminRoleGranted) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *AdminRoleGrantedIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *AdminRoleGrantedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// AdminRoleGranted represents a RoleGranted event raised by the Admin contract. +type AdminRoleGranted struct { + Role [32]byte + Account common.Address + Sender common.Address + Raw types.Log // Blockchain specific contextual infos +} + +// FilterRoleGranted is a free log retrieval operation binding the contract event 0x2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d. +// +// Solidity: event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender) +func (_Admin *AdminFilterer) FilterRoleGranted(opts *bind.FilterOpts, role [][32]byte, account []common.Address, sender []common.Address) (*AdminRoleGrantedIterator, error) { + + var roleRule []interface{} + for _, roleItem := range role { + roleRule = append(roleRule, roleItem) + } + var accountRule []interface{} + for _, accountItem := range account { + accountRule = append(accountRule, accountItem) + } + var senderRule []interface{} + for _, senderItem := range sender { + senderRule = append(senderRule, senderItem) + } + + logs, sub, err := _Admin.contract.FilterLogs(opts, "RoleGranted", roleRule, accountRule, senderRule) + if err != nil { + return nil, err + } + return &AdminRoleGrantedIterator{contract: _Admin.contract, event: "RoleGranted", logs: logs, sub: sub}, nil +} + +// WatchRoleGranted is a free log subscription operation binding the contract event 0x2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d. +// +// Solidity: event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender) +func (_Admin *AdminFilterer) WatchRoleGranted(opts *bind.WatchOpts, sink chan<- *AdminRoleGranted, role [][32]byte, account []common.Address, sender []common.Address) (event.Subscription, error) { + + var roleRule []interface{} + for _, roleItem := range role { + roleRule = append(roleRule, roleItem) + } + var accountRule []interface{} + for _, accountItem := range account { + accountRule = append(accountRule, accountItem) + } + var senderRule []interface{} + for _, senderItem := range sender { + senderRule = append(senderRule, senderItem) + } + + logs, sub, err := _Admin.contract.WatchLogs(opts, "RoleGranted", roleRule, accountRule, senderRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(AdminRoleGranted) + if err := _Admin.contract.UnpackLog(event, "RoleGranted", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseRoleGranted is a log parse operation binding the contract event 0x2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d. +// +// Solidity: event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender) +func (_Admin *AdminFilterer) ParseRoleGranted(log types.Log) (*AdminRoleGranted, error) { + event := new(AdminRoleGranted) + if err := _Admin.contract.UnpackLog(event, "RoleGranted", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// AdminRoleRevokedIterator is returned from FilterRoleRevoked and is used to iterate over the raw logs and unpacked data for RoleRevoked events raised by the Admin contract. +type AdminRoleRevokedIterator struct { + Event *AdminRoleRevoked // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *AdminRoleRevokedIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(AdminRoleRevoked) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(AdminRoleRevoked) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *AdminRoleRevokedIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *AdminRoleRevokedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// AdminRoleRevoked represents a RoleRevoked event raised by the Admin contract. +type AdminRoleRevoked struct { + Role [32]byte + Account common.Address + Sender common.Address + Raw types.Log // Blockchain specific contextual infos +} + +// FilterRoleRevoked is a free log retrieval operation binding the contract event 0xf6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b. +// +// Solidity: event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender) +func (_Admin *AdminFilterer) FilterRoleRevoked(opts *bind.FilterOpts, role [][32]byte, account []common.Address, sender []common.Address) (*AdminRoleRevokedIterator, error) { + + var roleRule []interface{} + for _, roleItem := range role { + roleRule = append(roleRule, roleItem) + } + var accountRule []interface{} + for _, accountItem := range account { + accountRule = append(accountRule, accountItem) + } + var senderRule []interface{} + for _, senderItem := range sender { + senderRule = append(senderRule, senderItem) + } + + logs, sub, err := _Admin.contract.FilterLogs(opts, "RoleRevoked", roleRule, accountRule, senderRule) + if err != nil { + return nil, err + } + return &AdminRoleRevokedIterator{contract: _Admin.contract, event: "RoleRevoked", logs: logs, sub: sub}, nil +} + +// WatchRoleRevoked is a free log subscription operation binding the contract event 0xf6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b. +// +// Solidity: event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender) +func (_Admin *AdminFilterer) WatchRoleRevoked(opts *bind.WatchOpts, sink chan<- *AdminRoleRevoked, role [][32]byte, account []common.Address, sender []common.Address) (event.Subscription, error) { + + var roleRule []interface{} + for _, roleItem := range role { + roleRule = append(roleRule, roleItem) + } + var accountRule []interface{} + for _, accountItem := range account { + accountRule = append(accountRule, accountItem) + } + var senderRule []interface{} + for _, senderItem := range sender { + senderRule = append(senderRule, senderItem) + } + + logs, sub, err := _Admin.contract.WatchLogs(opts, "RoleRevoked", roleRule, accountRule, senderRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(AdminRoleRevoked) + if err := _Admin.contract.UnpackLog(event, "RoleRevoked", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseRoleRevoked is a log parse operation binding the contract event 0xf6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b. +// +// Solidity: event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender) +func (_Admin *AdminFilterer) ParseRoleRevoked(log types.Log) (*AdminRoleRevoked, error) { + event := new(AdminRoleRevoked) + if err := _Admin.contract.UnpackLog(event, "RoleRevoked", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// ContextMetaData contains all meta data concerning the Context contract. +var ContextMetaData = &bind.MetaData{ + ABI: "[]", +} + +// ContextABI is the input ABI used to generate the binding from. +// Deprecated: Use ContextMetaData.ABI instead. +var ContextABI = ContextMetaData.ABI + +// Context is an auto generated Go binding around an Ethereum contract. +type Context struct { + ContextCaller // Read-only binding to the contract + ContextTransactor // Write-only binding to the contract + ContextFilterer // Log filterer for contract events +} + +// ContextCaller is an auto generated read-only Go binding around an Ethereum contract. +type ContextCaller struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// ContextTransactor is an auto generated write-only Go binding around an Ethereum contract. +type ContextTransactor struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// ContextFilterer is an auto generated log filtering Go binding around an Ethereum contract events. +type ContextFilterer struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// ContextSession is an auto generated Go binding around an Ethereum contract, +// with pre-set call and transact options. +type ContextSession struct { + Contract *Context // Generic contract binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// ContextCallerSession is an auto generated read-only Go binding around an Ethereum contract, +// with pre-set call options. +type ContextCallerSession struct { + Contract *ContextCaller // Generic contract caller binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session +} + +// ContextTransactorSession is an auto generated write-only Go binding around an Ethereum contract, +// with pre-set transact options. +type ContextTransactorSession struct { + Contract *ContextTransactor // Generic contract transactor binding to set the session for + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// ContextRaw is an auto generated low-level Go binding around an Ethereum contract. +type ContextRaw struct { + Contract *Context // Generic contract binding to access the raw methods on +} + +// ContextCallerRaw is an auto generated low-level read-only Go binding around an Ethereum contract. +type ContextCallerRaw struct { + Contract *ContextCaller // Generic read-only contract binding to access the raw methods on +} + +// ContextTransactorRaw is an auto generated low-level write-only Go binding around an Ethereum contract. +type ContextTransactorRaw struct { + Contract *ContextTransactor // Generic write-only contract binding to access the raw methods on +} + +// NewContext creates a new instance of Context, bound to a specific deployed contract. +func NewContext(address common.Address, backend bind.ContractBackend) (*Context, error) { + contract, err := bindContext(address, backend, backend, backend) + if err != nil { + return nil, err + } + return &Context{ContextCaller: ContextCaller{contract: contract}, ContextTransactor: ContextTransactor{contract: contract}, ContextFilterer: ContextFilterer{contract: contract}}, nil +} + +// NewContextCaller creates a new read-only instance of Context, bound to a specific deployed contract. +func NewContextCaller(address common.Address, caller bind.ContractCaller) (*ContextCaller, error) { + contract, err := bindContext(address, caller, nil, nil) + if err != nil { + return nil, err + } + return &ContextCaller{contract: contract}, nil +} + +// NewContextTransactor creates a new write-only instance of Context, bound to a specific deployed contract. +func NewContextTransactor(address common.Address, transactor bind.ContractTransactor) (*ContextTransactor, error) { + contract, err := bindContext(address, nil, transactor, nil) + if err != nil { + return nil, err + } + return &ContextTransactor{contract: contract}, nil +} + +// NewContextFilterer creates a new log filterer instance of Context, bound to a specific deployed contract. +func NewContextFilterer(address common.Address, filterer bind.ContractFilterer) (*ContextFilterer, error) { + contract, err := bindContext(address, nil, nil, filterer) + if err != nil { + return nil, err + } + return &ContextFilterer{contract: contract}, nil +} + +// bindContext binds a generic wrapper to an already deployed contract. +func bindContext(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) { + parsed, err := ContextMetaData.GetAbi() + if err != nil { + return nil, err + } + return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil +} + +// Call invokes the (constant) contract method with params as input values and +// sets the output to result. The result type might be a single field for simple +// returns, a slice of interfaces for anonymous returns and a struct for named +// returns. +func (_Context *ContextRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _Context.Contract.ContextCaller.contract.Call(opts, result, method, params...) +} + +// Transfer initiates a plain transaction to move funds to the contract, calling +// its default method if one is available. +func (_Context *ContextRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _Context.Contract.ContextTransactor.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_Context *ContextRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _Context.Contract.ContextTransactor.contract.Transact(opts, method, params...) +} + +// Call invokes the (constant) contract method with params as input values and +// sets the output to result. The result type might be a single field for simple +// returns, a slice of interfaces for anonymous returns and a struct for named +// returns. +func (_Context *ContextCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _Context.Contract.contract.Call(opts, result, method, params...) +} + +// Transfer initiates a plain transaction to move funds to the contract, calling +// its default method if one is available. +func (_Context *ContextTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _Context.Contract.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_Context *ContextTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _Context.Contract.contract.Transact(opts, method, params...) +} + +// ERC165MetaData contains all meta data concerning the ERC165 contract. +var ERC165MetaData = &bind.MetaData{ + ABI: "[{\"inputs\":[{\"internalType\":\"bytes4\",\"name\":\"interfaceId\",\"type\":\"bytes4\"}],\"name\":\"supportsInterface\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"}]", + Sigs: map[string]string{ + "01ffc9a7": "supportsInterface(bytes4)", + }, +} + +// ERC165ABI is the input ABI used to generate the binding from. +// Deprecated: Use ERC165MetaData.ABI instead. +var ERC165ABI = ERC165MetaData.ABI + +// Deprecated: Use ERC165MetaData.Sigs instead. +// ERC165FuncSigs maps the 4-byte function signature to its string representation. +var ERC165FuncSigs = ERC165MetaData.Sigs + +// ERC165 is an auto generated Go binding around an Ethereum contract. +type ERC165 struct { + ERC165Caller // Read-only binding to the contract + ERC165Transactor // Write-only binding to the contract + ERC165Filterer // Log filterer for contract events +} + +// ERC165Caller is an auto generated read-only Go binding around an Ethereum contract. +type ERC165Caller struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// ERC165Transactor is an auto generated write-only Go binding around an Ethereum contract. +type ERC165Transactor struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// ERC165Filterer is an auto generated log filtering Go binding around an Ethereum contract events. +type ERC165Filterer struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// ERC165Session is an auto generated Go binding around an Ethereum contract, +// with pre-set call and transact options. +type ERC165Session struct { + Contract *ERC165 // Generic contract binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// ERC165CallerSession is an auto generated read-only Go binding around an Ethereum contract, +// with pre-set call options. +type ERC165CallerSession struct { + Contract *ERC165Caller // Generic contract caller binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session +} + +// ERC165TransactorSession is an auto generated write-only Go binding around an Ethereum contract, +// with pre-set transact options. +type ERC165TransactorSession struct { + Contract *ERC165Transactor // Generic contract transactor binding to set the session for + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// ERC165Raw is an auto generated low-level Go binding around an Ethereum contract. +type ERC165Raw struct { + Contract *ERC165 // Generic contract binding to access the raw methods on +} + +// ERC165CallerRaw is an auto generated low-level read-only Go binding around an Ethereum contract. +type ERC165CallerRaw struct { + Contract *ERC165Caller // Generic read-only contract binding to access the raw methods on +} + +// ERC165TransactorRaw is an auto generated low-level write-only Go binding around an Ethereum contract. +type ERC165TransactorRaw struct { + Contract *ERC165Transactor // Generic write-only contract binding to access the raw methods on +} + +// NewERC165 creates a new instance of ERC165, bound to a specific deployed contract. +func NewERC165(address common.Address, backend bind.ContractBackend) (*ERC165, error) { + contract, err := bindERC165(address, backend, backend, backend) + if err != nil { + return nil, err + } + return &ERC165{ERC165Caller: ERC165Caller{contract: contract}, ERC165Transactor: ERC165Transactor{contract: contract}, ERC165Filterer: ERC165Filterer{contract: contract}}, nil +} + +// NewERC165Caller creates a new read-only instance of ERC165, bound to a specific deployed contract. +func NewERC165Caller(address common.Address, caller bind.ContractCaller) (*ERC165Caller, error) { + contract, err := bindERC165(address, caller, nil, nil) + if err != nil { + return nil, err + } + return &ERC165Caller{contract: contract}, nil +} + +// NewERC165Transactor creates a new write-only instance of ERC165, bound to a specific deployed contract. +func NewERC165Transactor(address common.Address, transactor bind.ContractTransactor) (*ERC165Transactor, error) { + contract, err := bindERC165(address, nil, transactor, nil) + if err != nil { + return nil, err + } + return &ERC165Transactor{contract: contract}, nil +} + +// NewERC165Filterer creates a new log filterer instance of ERC165, bound to a specific deployed contract. +func NewERC165Filterer(address common.Address, filterer bind.ContractFilterer) (*ERC165Filterer, error) { + contract, err := bindERC165(address, nil, nil, filterer) + if err != nil { + return nil, err + } + return &ERC165Filterer{contract: contract}, nil +} + +// bindERC165 binds a generic wrapper to an already deployed contract. +func bindERC165(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) { + parsed, err := ERC165MetaData.GetAbi() + if err != nil { + return nil, err + } + return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil +} + +// Call invokes the (constant) contract method with params as input values and +// sets the output to result. The result type might be a single field for simple +// returns, a slice of interfaces for anonymous returns and a struct for named +// returns. +func (_ERC165 *ERC165Raw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _ERC165.Contract.ERC165Caller.contract.Call(opts, result, method, params...) +} + +// Transfer initiates a plain transaction to move funds to the contract, calling +// its default method if one is available. +func (_ERC165 *ERC165Raw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _ERC165.Contract.ERC165Transactor.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_ERC165 *ERC165Raw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _ERC165.Contract.ERC165Transactor.contract.Transact(opts, method, params...) +} + +// Call invokes the (constant) contract method with params as input values and +// sets the output to result. The result type might be a single field for simple +// returns, a slice of interfaces for anonymous returns and a struct for named +// returns. +func (_ERC165 *ERC165CallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _ERC165.Contract.contract.Call(opts, result, method, params...) +} + +// Transfer initiates a plain transaction to move funds to the contract, calling +// its default method if one is available. +func (_ERC165 *ERC165TransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _ERC165.Contract.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_ERC165 *ERC165TransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _ERC165.Contract.contract.Transact(opts, method, params...) +} + +// SupportsInterface is a free data retrieval call binding the contract method 0x01ffc9a7. +// +// Solidity: function supportsInterface(bytes4 interfaceId) view returns(bool) +func (_ERC165 *ERC165Caller) SupportsInterface(opts *bind.CallOpts, interfaceId [4]byte) (bool, error) { + var out []interface{} + err := _ERC165.contract.Call(opts, &out, "supportsInterface", interfaceId) + + if err != nil { + return *new(bool), err + } + + out0 := *abi.ConvertType(out[0], new(bool)).(*bool) + + return out0, err + +} + +// SupportsInterface is a free data retrieval call binding the contract method 0x01ffc9a7. +// +// Solidity: function supportsInterface(bytes4 interfaceId) view returns(bool) +func (_ERC165 *ERC165Session) SupportsInterface(interfaceId [4]byte) (bool, error) { + return _ERC165.Contract.SupportsInterface(&_ERC165.CallOpts, interfaceId) +} + +// SupportsInterface is a free data retrieval call binding the contract method 0x01ffc9a7. +// +// Solidity: function supportsInterface(bytes4 interfaceId) view returns(bool) +func (_ERC165 *ERC165CallerSession) SupportsInterface(interfaceId [4]byte) (bool, error) { + return _ERC165.Contract.SupportsInterface(&_ERC165.CallOpts, interfaceId) +} + +// EnumerableSetMetaData contains all meta data concerning the EnumerableSet contract. +var EnumerableSetMetaData = &bind.MetaData{ + ABI: "[]", + Bin: "0x60566037600b82828239805160001a607314602a57634e487b7160e01b600052600060045260246000fd5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600080fdfea264697066735822122061192eb5b75fa46e55c42a092ec06111165ec29e2ac6d00c6d247f0df8ba17fd64736f6c63430008140033", +} + +// EnumerableSetABI is the input ABI used to generate the binding from. +// Deprecated: Use EnumerableSetMetaData.ABI instead. +var EnumerableSetABI = EnumerableSetMetaData.ABI + +// EnumerableSetBin is the compiled bytecode used for deploying new contracts. +// Deprecated: Use EnumerableSetMetaData.Bin instead. +var EnumerableSetBin = EnumerableSetMetaData.Bin + +// DeployEnumerableSet deploys a new Ethereum contract, binding an instance of EnumerableSet to it. +func DeployEnumerableSet(auth *bind.TransactOpts, backend bind.ContractBackend) (common.Address, *types.Transaction, *EnumerableSet, error) { + parsed, err := EnumerableSetMetaData.GetAbi() + if err != nil { + return common.Address{}, nil, nil, err + } + if parsed == nil { + return common.Address{}, nil, nil, errors.New("GetABI returned nil") + } + + address, tx, contract, err := bind.DeployContract(auth, *parsed, common.FromHex(EnumerableSetBin), backend) + if err != nil { + return common.Address{}, nil, nil, err + } + return address, tx, &EnumerableSet{EnumerableSetCaller: EnumerableSetCaller{contract: contract}, EnumerableSetTransactor: EnumerableSetTransactor{contract: contract}, EnumerableSetFilterer: EnumerableSetFilterer{contract: contract}}, nil +} + +// EnumerableSet is an auto generated Go binding around an Ethereum contract. +type EnumerableSet struct { + EnumerableSetCaller // Read-only binding to the contract + EnumerableSetTransactor // Write-only binding to the contract + EnumerableSetFilterer // Log filterer for contract events +} + +// EnumerableSetCaller is an auto generated read-only Go binding around an Ethereum contract. +type EnumerableSetCaller struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// EnumerableSetTransactor is an auto generated write-only Go binding around an Ethereum contract. +type EnumerableSetTransactor struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// EnumerableSetFilterer is an auto generated log filtering Go binding around an Ethereum contract events. +type EnumerableSetFilterer struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// EnumerableSetSession is an auto generated Go binding around an Ethereum contract, +// with pre-set call and transact options. +type EnumerableSetSession struct { + Contract *EnumerableSet // Generic contract binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// EnumerableSetCallerSession is an auto generated read-only Go binding around an Ethereum contract, +// with pre-set call options. +type EnumerableSetCallerSession struct { + Contract *EnumerableSetCaller // Generic contract caller binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session +} + +// EnumerableSetTransactorSession is an auto generated write-only Go binding around an Ethereum contract, +// with pre-set transact options. +type EnumerableSetTransactorSession struct { + Contract *EnumerableSetTransactor // Generic contract transactor binding to set the session for + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// EnumerableSetRaw is an auto generated low-level Go binding around an Ethereum contract. +type EnumerableSetRaw struct { + Contract *EnumerableSet // Generic contract binding to access the raw methods on +} + +// EnumerableSetCallerRaw is an auto generated low-level read-only Go binding around an Ethereum contract. +type EnumerableSetCallerRaw struct { + Contract *EnumerableSetCaller // Generic read-only contract binding to access the raw methods on +} + +// EnumerableSetTransactorRaw is an auto generated low-level write-only Go binding around an Ethereum contract. +type EnumerableSetTransactorRaw struct { + Contract *EnumerableSetTransactor // Generic write-only contract binding to access the raw methods on +} + +// NewEnumerableSet creates a new instance of EnumerableSet, bound to a specific deployed contract. +func NewEnumerableSet(address common.Address, backend bind.ContractBackend) (*EnumerableSet, error) { + contract, err := bindEnumerableSet(address, backend, backend, backend) + if err != nil { + return nil, err + } + return &EnumerableSet{EnumerableSetCaller: EnumerableSetCaller{contract: contract}, EnumerableSetTransactor: EnumerableSetTransactor{contract: contract}, EnumerableSetFilterer: EnumerableSetFilterer{contract: contract}}, nil +} + +// NewEnumerableSetCaller creates a new read-only instance of EnumerableSet, bound to a specific deployed contract. +func NewEnumerableSetCaller(address common.Address, caller bind.ContractCaller) (*EnumerableSetCaller, error) { + contract, err := bindEnumerableSet(address, caller, nil, nil) + if err != nil { + return nil, err + } + return &EnumerableSetCaller{contract: contract}, nil +} + +// NewEnumerableSetTransactor creates a new write-only instance of EnumerableSet, bound to a specific deployed contract. +func NewEnumerableSetTransactor(address common.Address, transactor bind.ContractTransactor) (*EnumerableSetTransactor, error) { + contract, err := bindEnumerableSet(address, nil, transactor, nil) + if err != nil { + return nil, err + } + return &EnumerableSetTransactor{contract: contract}, nil +} + +// NewEnumerableSetFilterer creates a new log filterer instance of EnumerableSet, bound to a specific deployed contract. +func NewEnumerableSetFilterer(address common.Address, filterer bind.ContractFilterer) (*EnumerableSetFilterer, error) { + contract, err := bindEnumerableSet(address, nil, nil, filterer) + if err != nil { + return nil, err + } + return &EnumerableSetFilterer{contract: contract}, nil +} + +// bindEnumerableSet binds a generic wrapper to an already deployed contract. +func bindEnumerableSet(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) { + parsed, err := EnumerableSetMetaData.GetAbi() + if err != nil { + return nil, err + } + return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil +} + +// Call invokes the (constant) contract method with params as input values and +// sets the output to result. The result type might be a single field for simple +// returns, a slice of interfaces for anonymous returns and a struct for named +// returns. +func (_EnumerableSet *EnumerableSetRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _EnumerableSet.Contract.EnumerableSetCaller.contract.Call(opts, result, method, params...) +} + +// Transfer initiates a plain transaction to move funds to the contract, calling +// its default method if one is available. +func (_EnumerableSet *EnumerableSetRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _EnumerableSet.Contract.EnumerableSetTransactor.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_EnumerableSet *EnumerableSetRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _EnumerableSet.Contract.EnumerableSetTransactor.contract.Transact(opts, method, params...) +} + +// Call invokes the (constant) contract method with params as input values and +// sets the output to result. The result type might be a single field for simple +// returns, a slice of interfaces for anonymous returns and a struct for named +// returns. +func (_EnumerableSet *EnumerableSetCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _EnumerableSet.Contract.contract.Call(opts, result, method, params...) +} + +// Transfer initiates a plain transaction to move funds to the contract, calling +// its default method if one is available. +func (_EnumerableSet *EnumerableSetTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _EnumerableSet.Contract.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_EnumerableSet *EnumerableSetTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _EnumerableSet.Contract.contract.Transact(opts, method, params...) +} + +// FastBridgeMetaData contains all meta data concerning the FastBridge contract. +var FastBridgeMetaData = &bind.MetaData{ + ABI: "[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_owner\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"AccessControlBadConfirmation\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"neededRole\",\"type\":\"bytes32\"}],\"name\":\"AccessControlUnauthorizedAccount\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"}],\"name\":\"AddressEmptyCode\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"AddressInsufficientBalance\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"AmountIncorrect\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ChainIncorrect\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DeadlineExceeded\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DeadlineNotExceeded\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DeadlineTooShort\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DisputePeriodNotPassed\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DisputePeriodPassed\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"FailedInnerCall\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"MsgValueIncorrect\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"}],\"name\":\"SafeERC20FailedOperation\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"SenderIncorrect\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"StatusIncorrect\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"TokenNotContract\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"TransactionRelayed\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ZeroAddress\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"BridgeDepositClaimed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"BridgeDepositRefunded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"name\":\"BridgeProofDisputed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"transactionHash\",\"type\":\"bytes32\"}],\"name\":\"BridgeProofProvided\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"originChainId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"chainGasAmount\",\"type\":\"uint256\"}],\"name\":\"BridgeRelayed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"destChainId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"sendChainGas\",\"type\":\"bool\"}],\"name\":\"BridgeRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"oldChainGasAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newChainGasAmount\",\"type\":\"uint256\"}],\"name\":\"ChainGasAmountUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"oldFeeRate\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newFeeRate\",\"type\":\"uint256\"}],\"name\":\"FeeRateUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"FeesSwept\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"previousAdminRole\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"newAdminRole\",\"type\":\"bytes32\"}],\"name\":\"RoleAdminChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleGranted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleRevoked\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"DEFAULT_ADMIN_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"DISPUTE_PERIOD\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"FEE_BPS\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"FEE_RATE_MAX\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"GOVERNOR_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"GUARD_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"MIN_DEADLINE_PERIOD\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"REFUNDER_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"REFUND_DELAY\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"RELAYER_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"dstChainId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"sendChainGas\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"}],\"internalType\":\"structIFastBridge.BridgeParams\",\"name\":\"params\",\"type\":\"tuple\"}],\"name\":\"bridge\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"bridgeProofs\",\"outputs\":[{\"internalType\":\"uint96\",\"name\":\"timestamp\",\"type\":\"uint96\"},{\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"bridgeRelays\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"bridgeStatuses\",\"outputs\":[{\"internalType\":\"enumFastBridge.BridgeStatus\",\"name\":\"\",\"type\":\"uint8\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"name\":\"canClaim\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"chainGasAmount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"claim\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"deployBlock\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"}],\"name\":\"dispute\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"getBridgeTransaction\",\"outputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"originChainId\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"destChainId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"originSender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destRecipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"originFeeAmount\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"sendChainGas\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"}],\"internalType\":\"structIFastBridge.BridgeTransaction\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"}],\"name\":\"getRoleAdmin\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"index\",\"type\":\"uint256\"}],\"name\":\"getRoleMember\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"}],\"name\":\"getRoleMemberCount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"grantRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"hasRole\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"nonce\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"protocolFeeRate\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"protocolFees\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"},{\"internalType\":\"bytes32\",\"name\":\"destTxHash\",\"type\":\"bytes32\"}],\"name\":\"prove\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"refund\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"relay\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"callerConfirmation\",\"type\":\"address\"}],\"name\":\"renounceRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"revokeRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"newChainGasAmount\",\"type\":\"uint256\"}],\"name\":\"setChainGasAmount\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"newFeeRate\",\"type\":\"uint256\"}],\"name\":\"setProtocolFeeRate\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes4\",\"name\":\"interfaceId\",\"type\":\"bytes4\"}],\"name\":\"supportsInterface\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"}],\"name\":\"sweepProtocolFees\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", + Sigs: map[string]string{ + "a217fddf": "DEFAULT_ADMIN_ROLE()", + "a5bbe22b": "DISPUTE_PERIOD()", + "bf333f2c": "FEE_BPS()", + "0f5f6ed7": "FEE_RATE_MAX()", + "ccc57490": "GOVERNOR_ROLE()", + "03ed0ee5": "GUARD_ROLE()", + "820688d5": "MIN_DEADLINE_PERIOD()", + "5960ccf2": "REFUNDER_ROLE()", + "190da595": "REFUND_DELAY()", + "926d7d7f": "RELAYER_ROLE()", + "45851694": "bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256))", + "91ad5039": "bridgeProofs(bytes32)", + "8379a24f": "bridgeRelays(bytes32)", + "051287bc": "bridgeStatuses(bytes32)", + "aa9641ab": "canClaim(bytes32,address)", + "e00a83e0": "chainGasAmount()", + "41fcb612": "claim(bytes,address)", + "a3ec191a": "deployBlock()", + "add98c70": "dispute(bytes32)", + "ac11fb1a": "getBridgeTransaction(bytes)", + "248a9ca3": "getRoleAdmin(bytes32)", + "9010d07c": "getRoleMember(bytes32,uint256)", + "ca15c873": "getRoleMemberCount(bytes32)", + "2f2ff15d": "grantRole(bytes32,address)", + "91d14854": "hasRole(bytes32,address)", + "affed0e0": "nonce()", + "58f85880": "protocolFeeRate()", + "dcf844a7": "protocolFees(address)", + "886d36ff": "prove(bytes,bytes32)", + "5eb7d946": "refund(bytes)", + "8f0d6f17": "relay(bytes)", + "36568abe": "renounceRole(bytes32,address)", + "d547741f": "revokeRole(bytes32,address)", + "b250fe6b": "setChainGasAmount(uint256)", + "b13aa2d6": "setProtocolFeeRate(uint256)", + "01ffc9a7": "supportsInterface(bytes4)", + "06f333f2": "sweepProtocolFees(address,address)", + }, + Bin: "0x60a06040523480156200001157600080fd5b5060405162002d7a38038062002d7a833981016040819052620000349162000194565b80620000426000826200004f565b50504360805250620001bf565b6000806200005e84846200008c565b90508015620000835760008481526001602052604090206200008190846200013a565b505b90505b92915050565b6000828152602081815260408083206001600160a01b038516845290915281205460ff1662000131576000838152602081815260408083206001600160a01b03861684529091529020805460ff19166001179055620000e83390565b6001600160a01b0316826001600160a01b0316847f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a450600162000086565b50600062000086565b600062000083836001600160a01b0384166000818152600183016020526040812054620001315750815460018181018455600084815260208082209093018490558454848252828601909352604090209190915562000086565b600060208284031215620001a757600080fd5b81516001600160a01b03811681146200008357600080fd5b608051612b9f620001db60003960006106510152612b9f6000f3fe60806040526004361061026a5760003560e01c80639010d07c11610153578063add98c70116100cb578063ca15c8731161007f578063d547741f11610064578063d547741f146107a1578063dcf844a7146107c1578063e00a83e0146107ee57600080fd5b8063ca15c8731461074d578063ccc574901461076d57600080fd5b8063b13aa2d6116100b0578063b13aa2d6146106f6578063b250fe6b14610716578063bf333f2c1461073657600080fd5b8063add98c70146106c0578063affed0e0146106e057600080fd5b8063a217fddf11610122578063a5bbe22b11610107578063a5bbe22b1461047f578063aa9641ab14610673578063ac11fb1a1461069357600080fd5b8063a217fddf1461062a578063a3ec191a1461063f57600080fd5b80639010d07c146104f857806391ad50391461053057806391d14854146105b2578063926d7d7f146105f657600080fd5b806341fcb612116101e65780635eb7d946116101b55780638379a24f1161019a5780638379a24f14610495578063886d36ff146104c55780638f0d6f17146104e557600080fd5b80635eb7d9461461045f578063820688d51461047f57600080fd5b806341fcb612146103e2578063458516941461040257806358f85880146104155780635960ccf21461042b57600080fd5b80630f5f6ed71161023d578063248a9ca311610222578063248a9ca3146103725780632f2ff15d146103a257806336568abe146103c257600080fd5b80630f5f6ed714610345578063190da5951461035b57600080fd5b806301ffc9a71461026f57806303ed0ee5146102a4578063051287bc146102e657806306f333f214610323575b600080fd5b34801561027b57600080fd5b5061028f61028a3660046122fc565b610804565b60405190151581526020015b60405180910390f35b3480156102b057600080fd5b506102d87f043c983c49d46f0e102151eaf8085d4a2e6571d5df2d47b013f39bddfd4a639d81565b60405190815260200161029b565b3480156102f257600080fd5b5061031661030136600461233e565b60056020526000908152604090205460ff1681565b60405161029b9190612386565b34801561032f57600080fd5b5061034361033e3660046123ec565b610860565b005b34801561035157600080fd5b506102d861271081565b34801561036757600080fd5b506102d862093a8081565b34801561037e57600080fd5b506102d861038d36600461233e565b60009081526020819052604090206001015490565b3480156103ae57600080fd5b506103436103bd366004612425565b610927565b3480156103ce57600080fd5b506103436103dd366004612425565b610952565b3480156103ee57600080fd5b506103436103fd366004612572565b61099e565b6103436104103660046125ef565b610bd7565b34801561042157600080fd5b506102d860025481565b34801561043757600080fd5b506102d87fdb9556138406326f00296e13ea2ad7db24ba82381212d816b1a40c23b466b32781565b34801561046b57600080fd5b5061034361047a366004612692565b610ee5565b34801561048b57600080fd5b506102d861070881565b3480156104a157600080fd5b5061028f6104b036600461233e565b60076020526000908152604090205460ff1681565b3480156104d157600080fd5b506103436104e03660046126cf565b6110bd565b6103436104f3366004612692565b6111f0565b34801561050457600080fd5b50610518610513366004612714565b611437565b6040516001600160a01b03909116815260200161029b565b34801561053c57600080fd5b5061058661054b36600461233e565b6006602052600090815260409020546bffffffffffffffffffffffff8116906c0100000000000000000000000090046001600160a01b031682565b604080516bffffffffffffffffffffffff90931683526001600160a01b0390911660208301520161029b565b3480156105be57600080fd5b5061028f6105cd366004612425565b6000918252602082815260408084206001600160a01b0393909316845291905290205460ff1690565b34801561060257600080fd5b506102d87fe2b7fb3b832174769106daebcfd6d1970523240dda11281102db9363b83b0dc481565b34801561063657600080fd5b506102d8600081565b34801561064b57600080fd5b506102d87f000000000000000000000000000000000000000000000000000000000000000081565b34801561067f57600080fd5b5061028f61068e366004612425565b611456565b34801561069f57600080fd5b506106b36106ae366004612692565b611559565b60405161029b9190612736565b3480156106cc57600080fd5b506103436106db36600461233e565b6115cc565b3480156106ec57600080fd5b506102d860085481565b34801561070257600080fd5b5061034361071136600461233e565b611735565b34801561072257600080fd5b5061034361073136600461233e565b611817565b34801561074257600080fd5b506102d8620f424081565b34801561075957600080fd5b506102d861076836600461233e565b61187f565b34801561077957600080fd5b506102d87f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f5581565b3480156107ad57600080fd5b506103436107bc366004612425565b611896565b3480156107cd57600080fd5b506102d86107dc36600461281c565b60036020526000908152604090205481565b3480156107fa57600080fd5b506102d860045481565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f5a05180f00000000000000000000000000000000000000000000000000000000148061085a575061085a826118bb565b92915050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f5561088a81611952565b6001600160a01b038316600090815260036020526040812054908190036108b15750505050565b6001600160a01b0384166000818152600360205260408120556108d590848361195f565b604080516001600160a01b038087168252851660208201529081018290527f244e51bc38c1452fa8aaf487bcb4bca36c2baa3a5fbdb776b1eabd8dc6d277cd9060600160405180910390a1505b505050565b60008281526020819052604090206001015461094281611952565b61094c8383611a82565b50505050565b6001600160a01b0381163314610994576040517f6697b23200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6109228282611ab7565b7fe2b7fb3b832174769106daebcfd6d1970523240dda11281102db9363b83b0dc46109c881611952565b8251602084012060006109da85611559565b9050600260008381526005602052604090205460ff166004811115610a0157610a01612357565b14610a38576040517f4145817200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000828152600660209081526040918290208251808401909352546bffffffffffffffffffffffff811683526c0100000000000000000000000090046001600160a01b03169082018190523314610abb576040517f4af43a9000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80516107089042036bffffffffffffffffffffffff1611610b08576040517f1992d0bd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000838152600560205260409020805460ff1916600317905561010082015115610b645761010082015160808301516001600160a01b031660009081526003602052604081208054909190610b5e908490612868565b90915550505b608082015160c0830151610b826001600160a01b038316888361195f565b604080516001600160a01b03848116825260208201849052891691339188917f582211c35a2139ac3bbaac74663c6a1f56c6cbb658b41fe11fd45a82074ac67891015b60405180910390a45050505050505050565b46816000015163ffffffff1603610c1a576040517f7029fdf900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60a08101511580610c2d575060c0810151155b15610c64576040517fe38820c800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60608101516001600160a01b03161580610c89575060808101516001600160a01b0316155b15610cc0576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610ccc61070842612868565b8161010001511015610d0a576040517f04b7fcc800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000610d1f3083606001518460a00151611ae4565b90506000806002541115610d4c57620f424060025483610d3f919061287b565b610d499190612892565b90505b610d5681836128cd565b915060006040518061018001604052804663ffffffff168152602001856000015163ffffffff16815260200185602001516001600160a01b0316815260200185604001516001600160a01b0316815260200185606001516001600160a01b0316815260200185608001516001600160a01b031681526020018481526020018560c0015181526020018381526020018560e0015115158152602001856101000151815260200160086000815480929190610e0e906128e0565b909155509052604051610e249190602001612736565b604080518083037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0018152828252805160208083019190912060008181526005835293909320805460ff191660011790558701518751606089015160808a015160c08b015160e08c015195985095966001600160a01b039094169587957f120ea0364f36cdac7983bcfdd55270ca09d7f9b314a2ebc425a3b01ab1d6403a95610ed6958b959094909390928e9261293c565b60405180910390a35050505050565b805160208201206000610ef783611559565b3360009081527fd2043bf65931af3dbecf60d0db8f40e4160406d7beb00522f4200cf4944a1eb8602052604090205490915060ff1615610f74578061014001514211610f6f576040517fe15ff9ea00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610fc0565b62093a80816101400151610f889190612868565b4211610fc0576040517fe15ff9ea00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600160008381526005602052604090205460ff166004811115610fe557610fe5612357565b1461101c576040517f4145817200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600082815260056020526040808220805460ff19166004179055820151608083015161010084015160c0850151929391926110579190612868565b905061106d6001600160a01b038316848361195f565b604080516001600160a01b0384811682526020820184905285169187917fb4c55c0c9bc613519b920e88748090150b890a875d307f21bea7d4fb2e8bc958910160405180910390a3505050505050565b7fe2b7fb3b832174769106daebcfd6d1970523240dda11281102db9363b83b0dc46110e781611952565b82516020840120600160008281526005602052604090205460ff16600481111561111357611113612357565b1461114a576040517f4145817200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008181526005602090815260408083208054600260ff19909116179055805180820182526bffffffffffffffffffffffff4281168252338285018181528787526006865295849020925195516001600160a01b03166c0100000000000000000000000002959091169490941790555185815283917f4ac8af8a2cd87193d64dfc7a3b8d9923b714ec528b18725d080aa1299be0c5e4910160405180910390a350505050565b7fe2b7fb3b832174769106daebcfd6d1970523240dda11281102db9363b83b0dc461121a81611952565b81516020830120600061122c84611559565b90504663ffffffff16816020015163ffffffff1614611277576040517f7029fdf900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8061014001514211156112b6576040517f559895a300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008281526007602052604090205460ff16156112ff576040517fbef7bb7d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000828152600760205260409020805460ff19166001179055606081015160a082015160e083015160045461012085015161134857506000611342848484611ae4565b506113b9565b7fffffffffffffffffffffffff11111111111111111111111111111111111111126001600160a01b0384160161138c5761134284846113878486612868565b611ae4565b611397848484611ae4565b506113b78473eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee83611ae4565b505b845160808087015160a08089015160c0808b015160e08c01516040805163ffffffff90991689526001600160a01b0396871660208a0152938616938801939093526060870152938501528301849052861691339189917ff8ae392d784b1ea5e8881bfa586d81abf07ef4f1e2fc75f7fe51c90f05199a5c9101610bc5565b600082815260016020526040812061144f9083611cb3565b9392505050565b6000600260008481526005602052604090205460ff16600481111561147d5761147d612357565b146114b4576040517f4145817200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000838152600660209081526040918290208251808401909352546bffffffffffffffffffffffff811683526001600160a01b036c01000000000000000000000000909104811691830182905284161461153a576040517f4af43a9000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80516107089042036bffffffffffffffffffffffff1611949350505050565b604080516101808101825260008082526020808301829052928201819052606082018190526080820181905260a0820181905260c0820181905260e082018190526101008201819052610120820181905261014082018190526101608201528251909161085a91840181019084016129ed565b7f043c983c49d46f0e102151eaf8085d4a2e6571d5df2d47b013f39bddfd4a639d6115f681611952565b600260008381526005602052604090205460ff16600481111561161b5761161b612357565b14611652576040517f4145817200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000828152600660209081526040918290208251808401909352546bffffffffffffffffffffffff8082168085526c010000000000000000000000009092046001600160a01b031693909201929092526107089142031611156116e1576040517f3e908aac00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000828152600560209081526040808320805460ff19166001179055600690915280822082905551339184917f0695cf1d39b3055dcd0fe02d8b47eaf0d5a13e1996de925de59d0ef9b7f7fad49190a35050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f5561175f81611952565b6127108211156117d0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f6e657746656552617465203e206d61780000000000000000000000000000000060448201526064015b60405180910390fd5b600280549083905560408051828152602081018590527f14914da2bf76024616fbe1859783fcd4dbddcb179b1f3a854949fbf920dcb95791015b60405180910390a1505050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f5561184181611952565b600480549083905560408051828152602081018590527f5cf09b12f3f56b4c564d51b25b40360af6d795198adb61ae0806a36c294323fa910161180a565b600081815260016020526040812061085a90611cbf565b6000828152602081905260409020600101546118b181611952565b61094c8383611ab7565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f7965db0b00000000000000000000000000000000000000000000000000000000148061085a57507f01ffc9a7000000000000000000000000000000000000000000000000000000007fffffffff0000000000000000000000000000000000000000000000000000000083161461085a565b61195c8133611cc9565b50565b306001600160a01b0383160361197457505050565b8060000361198157505050565b7fffffffffffffffffffffffff11111111111111111111111111111111111111126001600160a01b03841601611a6e576000826001600160a01b03168260405160006040518083038185875af1925050503d80600081146119fe576040519150601f19603f3d011682016040523d82523d6000602084013e611a03565b606091505b505090508061094c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f455448207472616e73666572206661696c65640000000000000000000000000060448201526064016117c7565b6109226001600160a01b0384168383611d39565b600080611a8f8484611dad565b9050801561144f576000848152600160205260409020611aaf9084611e57565b509392505050565b600080611ac48484611e6c565b9050801561144f576000848152600160205260409020611aaf9084611eef565b60006001600160a01b03831673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee14611c4d57611b1c836001600160a01b0316611f04565b6040517f70a082310000000000000000000000000000000000000000000000000000000081526001600160a01b0385811660048301528416906370a0823190602401602060405180830381865afa158015611b7b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b9f9190612ab9565b9050611bb66001600160a01b038416338685611faa565b6040517f70a082310000000000000000000000000000000000000000000000000000000081526001600160a01b0385811660048301528291908516906370a0823190602401602060405180830381865afa158015611c18573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c3c9190612ab9565b611c4691906128cd565b905061144f565b348214611c86576040517f81de0bf300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600160a01b0384163014611caa57611caa6001600160a01b038416858461195f565b50349392505050565b600061144f8383611fe3565b600061085a825490565b6000828152602081815260408083206001600160a01b038516845290915290205460ff16611d35576040517fe2517d3f0000000000000000000000000000000000000000000000000000000081526001600160a01b0382166004820152602481018390526044016117c7565b5050565b6040516001600160a01b0383811660248301526044820183905261092291859182169063a9059cbb906064015b604051602081830303815290604052915060e01b6020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff838183161783525050505061200d565b6000828152602081815260408083206001600160a01b038516845290915281205460ff16611e4f576000838152602081815260408083206001600160a01b03861684529091529020805460ff19166001179055611e073390565b6001600160a01b0316826001600160a01b0316847f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a450600161085a565b50600061085a565b600061144f836001600160a01b038416612089565b6000828152602081815260408083206001600160a01b038516845290915281205460ff1615611e4f576000838152602081815260408083206001600160a01b0386168085529252808320805460ff1916905551339286917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a450600161085a565b600061144f836001600160a01b0384166120d0565b7fffffffffffffffffffffffff11111111111111111111111111111111111111126001600160a01b03821601611f66576040517f7f523fe800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b806001600160a01b03163b60000361195c576040517f7f523fe800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040516001600160a01b03848116602483015283811660448301526064820183905261094c9186918216906323b872dd90608401611d66565b6000826000018281548110611ffa57611ffa612ad2565b9060005260206000200154905092915050565b60006120226001600160a01b038416836121c3565b905080516000141580156120475750808060200190518101906120459190612b01565b155b15610922576040517f5274afe70000000000000000000000000000000000000000000000000000000081526001600160a01b03841660048201526024016117c7565b6000818152600183016020526040812054611e4f5750815460018181018455600084815260208082209093018490558454848252828601909352604090209190915561085a565b600081815260018301602052604081205480156121b95760006120f46001836128cd565b8554909150600090612108906001906128cd565b905080821461216d57600086600001828154811061212857612128612ad2565b906000526020600020015490508087600001848154811061214b5761214b612ad2565b6000918252602080832090910192909255918252600188019052604090208390555b855486908061217e5761217e612b1e565b60019003818190600052602060002001600090559055856001016000868152602001908152602001600020600090556001935050505061085a565b600091505061085a565b606061144f8383600084600080856001600160a01b031684866040516121e99190612b4d565b60006040518083038185875af1925050503d8060008114612226576040519150601f19603f3d011682016040523d82523d6000602084013e61222b565b606091505b509150915061223b868383612245565b9695505050505050565b60608261225a57612255826122ba565b61144f565b815115801561227157506001600160a01b0384163b155b156122b3576040517f9996b3150000000000000000000000000000000000000000000000000000000081526001600160a01b03851660048201526024016117c7565b508061144f565b8051156122ca5780518082602001fd5b6040517f1425ea4200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006020828403121561230e57600080fd5b81357fffffffff000000000000000000000000000000000000000000000000000000008116811461144f57600080fd5b60006020828403121561235057600080fd5b5035919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b60208101600583106123c1577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b91905290565b6001600160a01b038116811461195c57600080fd5b80356123e7816123c7565b919050565b600080604083850312156123ff57600080fd5b823561240a816123c7565b9150602083013561241a816123c7565b809150509250929050565b6000806040838503121561243857600080fd5b82359150602083013561241a816123c7565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051610120810167ffffffffffffffff8111828210171561249d5761249d61244a565b60405290565b604051610180810167ffffffffffffffff8111828210171561249d5761249d61244a565b600082601f8301126124d857600080fd5b813567ffffffffffffffff808211156124f3576124f361244a565b604051601f83017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f011681019082821181831017156125395761253961244a565b8160405283815286602085880101111561255257600080fd5b836020870160208301376000602085830101528094505050505092915050565b6000806040838503121561258557600080fd5b823567ffffffffffffffff81111561259c57600080fd5b6125a8858286016124c7565b925050602083013561241a816123c7565b63ffffffff8116811461195c57600080fd5b80356123e7816125b9565b801515811461195c57600080fd5b80356123e7816125d6565b6000610120828403121561260257600080fd5b61260a612479565b612613836125cb565b8152612621602084016123dc565b6020820152612632604084016123dc565b6040820152612643606084016123dc565b6060820152612654608084016123dc565b608082015260a083013560a082015260c083013560c082015261267960e084016125e4565b60e0820152610100928301359281019290925250919050565b6000602082840312156126a457600080fd5b813567ffffffffffffffff8111156126bb57600080fd5b6126c7848285016124c7565b949350505050565b600080604083850312156126e257600080fd5b823567ffffffffffffffff8111156126f957600080fd5b612705858286016124c7565b95602094909401359450505050565b6000806040838503121561272757600080fd5b50508035926020909101359150565b815163ffffffff1681526101808101602083015161275c602084018263ffffffff169052565b50604083015161277760408401826001600160a01b03169052565b50606083015161279260608401826001600160a01b03169052565b5060808301516127ad60808401826001600160a01b03169052565b5060a08301516127c860a08401826001600160a01b03169052565b5060c083015160c083015260e083015160e0830152610100808401518184015250610120808401516127fd8285018215159052565b5050610140838101519083015261016092830151929091019190915290565b60006020828403121561282e57600080fd5b813561144f816123c7565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b8082018082111561085a5761085a612839565b808202811582820484141761085a5761085a612839565b6000826128c8577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b8181038181111561085a5761085a612839565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820361291157612911612839565b5060010190565b60005b8381101561293357818101518382015260200161291b565b50506000910152565b60e08152600088518060e084015261010061295d8282860160208e01612918565b63ffffffff9990991660208401526001600160a01b039788166040840152959096166060820152608081019390935260a0830191909152151560c0820152601f9091017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0160190910192915050565b80516123e7816125b9565b80516123e7816123c7565b80516123e7816125d6565b60006101808284031215612a0057600080fd5b612a086124a3565b612a11836129cc565b8152612a1f602084016129cc565b6020820152612a30604084016129d7565b6040820152612a41606084016129d7565b6060820152612a52608084016129d7565b6080820152612a6360a084016129d7565b60a082015260c083015160c082015260e083015160e0820152610100808401518183015250610120612a968185016129e2565b908201526101408381015190820152610160928301519281019290925250919050565b600060208284031215612acb57600080fd5b5051919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b600060208284031215612b1357600080fd5b815161144f816125d6565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fd5b60008251612b5f818460208701612918565b919091019291505056fea26469706673582212202ed7e54598f559f515fc7a3d92c2ad3ddbadbeb6d23e4975b013050318c9925564736f6c63430008140033", +} + +// FastBridgeABI is the input ABI used to generate the binding from. +// Deprecated: Use FastBridgeMetaData.ABI instead. +var FastBridgeABI = FastBridgeMetaData.ABI + +// Deprecated: Use FastBridgeMetaData.Sigs instead. +// FastBridgeFuncSigs maps the 4-byte function signature to its string representation. +var FastBridgeFuncSigs = FastBridgeMetaData.Sigs + +// FastBridgeBin is the compiled bytecode used for deploying new contracts. +// Deprecated: Use FastBridgeMetaData.Bin instead. +var FastBridgeBin = FastBridgeMetaData.Bin + +// DeployFastBridge deploys a new Ethereum contract, binding an instance of FastBridge to it. +func DeployFastBridge(auth *bind.TransactOpts, backend bind.ContractBackend, _owner common.Address) (common.Address, *types.Transaction, *FastBridge, error) { + parsed, err := FastBridgeMetaData.GetAbi() + if err != nil { + return common.Address{}, nil, nil, err + } + if parsed == nil { + return common.Address{}, nil, nil, errors.New("GetABI returned nil") + } + + address, tx, contract, err := bind.DeployContract(auth, *parsed, common.FromHex(FastBridgeBin), backend, _owner) + if err != nil { + return common.Address{}, nil, nil, err + } + return address, tx, &FastBridge{FastBridgeCaller: FastBridgeCaller{contract: contract}, FastBridgeTransactor: FastBridgeTransactor{contract: contract}, FastBridgeFilterer: FastBridgeFilterer{contract: contract}}, nil +} + +// FastBridge is an auto generated Go binding around an Ethereum contract. +type FastBridge struct { + FastBridgeCaller // Read-only binding to the contract + FastBridgeTransactor // Write-only binding to the contract + FastBridgeFilterer // Log filterer for contract events +} + +// FastBridgeCaller is an auto generated read-only Go binding around an Ethereum contract. +type FastBridgeCaller struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// FastBridgeTransactor is an auto generated write-only Go binding around an Ethereum contract. +type FastBridgeTransactor struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// FastBridgeFilterer is an auto generated log filtering Go binding around an Ethereum contract events. +type FastBridgeFilterer struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// FastBridgeSession is an auto generated Go binding around an Ethereum contract, +// with pre-set call and transact options. +type FastBridgeSession struct { + Contract *FastBridge // Generic contract binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// FastBridgeCallerSession is an auto generated read-only Go binding around an Ethereum contract, +// with pre-set call options. +type FastBridgeCallerSession struct { + Contract *FastBridgeCaller // Generic contract caller binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session +} + +// FastBridgeTransactorSession is an auto generated write-only Go binding around an Ethereum contract, +// with pre-set transact options. +type FastBridgeTransactorSession struct { + Contract *FastBridgeTransactor // Generic contract transactor binding to set the session for + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// FastBridgeRaw is an auto generated low-level Go binding around an Ethereum contract. +type FastBridgeRaw struct { + Contract *FastBridge // Generic contract binding to access the raw methods on +} + +// FastBridgeCallerRaw is an auto generated low-level read-only Go binding around an Ethereum contract. +type FastBridgeCallerRaw struct { + Contract *FastBridgeCaller // Generic read-only contract binding to access the raw methods on +} + +// FastBridgeTransactorRaw is an auto generated low-level write-only Go binding around an Ethereum contract. +type FastBridgeTransactorRaw struct { + Contract *FastBridgeTransactor // Generic write-only contract binding to access the raw methods on +} + +// NewFastBridge creates a new instance of FastBridge, bound to a specific deployed contract. +func NewFastBridge(address common.Address, backend bind.ContractBackend) (*FastBridge, error) { + contract, err := bindFastBridge(address, backend, backend, backend) + if err != nil { + return nil, err + } + return &FastBridge{FastBridgeCaller: FastBridgeCaller{contract: contract}, FastBridgeTransactor: FastBridgeTransactor{contract: contract}, FastBridgeFilterer: FastBridgeFilterer{contract: contract}}, nil +} + +// NewFastBridgeCaller creates a new read-only instance of FastBridge, bound to a specific deployed contract. +func NewFastBridgeCaller(address common.Address, caller bind.ContractCaller) (*FastBridgeCaller, error) { + contract, err := bindFastBridge(address, caller, nil, nil) + if err != nil { + return nil, err + } + return &FastBridgeCaller{contract: contract}, nil +} + +// NewFastBridgeTransactor creates a new write-only instance of FastBridge, bound to a specific deployed contract. +func NewFastBridgeTransactor(address common.Address, transactor bind.ContractTransactor) (*FastBridgeTransactor, error) { + contract, err := bindFastBridge(address, nil, transactor, nil) + if err != nil { + return nil, err + } + return &FastBridgeTransactor{contract: contract}, nil +} + +// NewFastBridgeFilterer creates a new log filterer instance of FastBridge, bound to a specific deployed contract. +func NewFastBridgeFilterer(address common.Address, filterer bind.ContractFilterer) (*FastBridgeFilterer, error) { + contract, err := bindFastBridge(address, nil, nil, filterer) + if err != nil { + return nil, err + } + return &FastBridgeFilterer{contract: contract}, nil +} + +// bindFastBridge binds a generic wrapper to an already deployed contract. +func bindFastBridge(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) { + parsed, err := FastBridgeMetaData.GetAbi() + if err != nil { + return nil, err + } + return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil +} + +// Call invokes the (constant) contract method with params as input values and +// sets the output to result. The result type might be a single field for simple +// returns, a slice of interfaces for anonymous returns and a struct for named +// returns. +func (_FastBridge *FastBridgeRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _FastBridge.Contract.FastBridgeCaller.contract.Call(opts, result, method, params...) +} + +// Transfer initiates a plain transaction to move funds to the contract, calling +// its default method if one is available. +func (_FastBridge *FastBridgeRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _FastBridge.Contract.FastBridgeTransactor.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_FastBridge *FastBridgeRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _FastBridge.Contract.FastBridgeTransactor.contract.Transact(opts, method, params...) +} + +// Call invokes the (constant) contract method with params as input values and +// sets the output to result. The result type might be a single field for simple +// returns, a slice of interfaces for anonymous returns and a struct for named +// returns. +func (_FastBridge *FastBridgeCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _FastBridge.Contract.contract.Call(opts, result, method, params...) +} + +// Transfer initiates a plain transaction to move funds to the contract, calling +// its default method if one is available. +func (_FastBridge *FastBridgeTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _FastBridge.Contract.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_FastBridge *FastBridgeTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _FastBridge.Contract.contract.Transact(opts, method, params...) +} + +// DEFAULTADMINROLE is a free data retrieval call binding the contract method 0xa217fddf. +// +// Solidity: function DEFAULT_ADMIN_ROLE() view returns(bytes32) +func (_FastBridge *FastBridgeCaller) DEFAULTADMINROLE(opts *bind.CallOpts) ([32]byte, error) { + var out []interface{} + err := _FastBridge.contract.Call(opts, &out, "DEFAULT_ADMIN_ROLE") + + if err != nil { + return *new([32]byte), err + } + + out0 := *abi.ConvertType(out[0], new([32]byte)).(*[32]byte) + + return out0, err + +} + +// DEFAULTADMINROLE is a free data retrieval call binding the contract method 0xa217fddf. +// +// Solidity: function DEFAULT_ADMIN_ROLE() view returns(bytes32) +func (_FastBridge *FastBridgeSession) DEFAULTADMINROLE() ([32]byte, error) { + return _FastBridge.Contract.DEFAULTADMINROLE(&_FastBridge.CallOpts) +} + +// DEFAULTADMINROLE is a free data retrieval call binding the contract method 0xa217fddf. +// +// Solidity: function DEFAULT_ADMIN_ROLE() view returns(bytes32) +func (_FastBridge *FastBridgeCallerSession) DEFAULTADMINROLE() ([32]byte, error) { + return _FastBridge.Contract.DEFAULTADMINROLE(&_FastBridge.CallOpts) +} + +// DISPUTEPERIOD is a free data retrieval call binding the contract method 0xa5bbe22b. +// +// Solidity: function DISPUTE_PERIOD() view returns(uint256) +func (_FastBridge *FastBridgeCaller) DISPUTEPERIOD(opts *bind.CallOpts) (*big.Int, error) { + var out []interface{} + err := _FastBridge.contract.Call(opts, &out, "DISPUTE_PERIOD") + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// DISPUTEPERIOD is a free data retrieval call binding the contract method 0xa5bbe22b. +// +// Solidity: function DISPUTE_PERIOD() view returns(uint256) +func (_FastBridge *FastBridgeSession) DISPUTEPERIOD() (*big.Int, error) { + return _FastBridge.Contract.DISPUTEPERIOD(&_FastBridge.CallOpts) +} + +// DISPUTEPERIOD is a free data retrieval call binding the contract method 0xa5bbe22b. +// +// Solidity: function DISPUTE_PERIOD() view returns(uint256) +func (_FastBridge *FastBridgeCallerSession) DISPUTEPERIOD() (*big.Int, error) { + return _FastBridge.Contract.DISPUTEPERIOD(&_FastBridge.CallOpts) +} + +// FEEBPS is a free data retrieval call binding the contract method 0xbf333f2c. +// +// Solidity: function FEE_BPS() view returns(uint256) +func (_FastBridge *FastBridgeCaller) FEEBPS(opts *bind.CallOpts) (*big.Int, error) { + var out []interface{} + err := _FastBridge.contract.Call(opts, &out, "FEE_BPS") + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// FEEBPS is a free data retrieval call binding the contract method 0xbf333f2c. +// +// Solidity: function FEE_BPS() view returns(uint256) +func (_FastBridge *FastBridgeSession) FEEBPS() (*big.Int, error) { + return _FastBridge.Contract.FEEBPS(&_FastBridge.CallOpts) +} + +// FEEBPS is a free data retrieval call binding the contract method 0xbf333f2c. +// +// Solidity: function FEE_BPS() view returns(uint256) +func (_FastBridge *FastBridgeCallerSession) FEEBPS() (*big.Int, error) { + return _FastBridge.Contract.FEEBPS(&_FastBridge.CallOpts) +} + +// FEERATEMAX is a free data retrieval call binding the contract method 0x0f5f6ed7. +// +// Solidity: function FEE_RATE_MAX() view returns(uint256) +func (_FastBridge *FastBridgeCaller) FEERATEMAX(opts *bind.CallOpts) (*big.Int, error) { + var out []interface{} + err := _FastBridge.contract.Call(opts, &out, "FEE_RATE_MAX") + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// FEERATEMAX is a free data retrieval call binding the contract method 0x0f5f6ed7. +// +// Solidity: function FEE_RATE_MAX() view returns(uint256) +func (_FastBridge *FastBridgeSession) FEERATEMAX() (*big.Int, error) { + return _FastBridge.Contract.FEERATEMAX(&_FastBridge.CallOpts) +} + +// FEERATEMAX is a free data retrieval call binding the contract method 0x0f5f6ed7. +// +// Solidity: function FEE_RATE_MAX() view returns(uint256) +func (_FastBridge *FastBridgeCallerSession) FEERATEMAX() (*big.Int, error) { + return _FastBridge.Contract.FEERATEMAX(&_FastBridge.CallOpts) +} + +// GOVERNORROLE is a free data retrieval call binding the contract method 0xccc57490. +// +// Solidity: function GOVERNOR_ROLE() view returns(bytes32) +func (_FastBridge *FastBridgeCaller) GOVERNORROLE(opts *bind.CallOpts) ([32]byte, error) { + var out []interface{} + err := _FastBridge.contract.Call(opts, &out, "GOVERNOR_ROLE") + + if err != nil { + return *new([32]byte), err + } + + out0 := *abi.ConvertType(out[0], new([32]byte)).(*[32]byte) + + return out0, err + +} + +// GOVERNORROLE is a free data retrieval call binding the contract method 0xccc57490. +// +// Solidity: function GOVERNOR_ROLE() view returns(bytes32) +func (_FastBridge *FastBridgeSession) GOVERNORROLE() ([32]byte, error) { + return _FastBridge.Contract.GOVERNORROLE(&_FastBridge.CallOpts) +} + +// GOVERNORROLE is a free data retrieval call binding the contract method 0xccc57490. +// +// Solidity: function GOVERNOR_ROLE() view returns(bytes32) +func (_FastBridge *FastBridgeCallerSession) GOVERNORROLE() ([32]byte, error) { + return _FastBridge.Contract.GOVERNORROLE(&_FastBridge.CallOpts) +} + +// GUARDROLE is a free data retrieval call binding the contract method 0x03ed0ee5. +// +// Solidity: function GUARD_ROLE() view returns(bytes32) +func (_FastBridge *FastBridgeCaller) GUARDROLE(opts *bind.CallOpts) ([32]byte, error) { + var out []interface{} + err := _FastBridge.contract.Call(opts, &out, "GUARD_ROLE") + + if err != nil { + return *new([32]byte), err + } + + out0 := *abi.ConvertType(out[0], new([32]byte)).(*[32]byte) + + return out0, err + +} + +// GUARDROLE is a free data retrieval call binding the contract method 0x03ed0ee5. +// +// Solidity: function GUARD_ROLE() view returns(bytes32) +func (_FastBridge *FastBridgeSession) GUARDROLE() ([32]byte, error) { + return _FastBridge.Contract.GUARDROLE(&_FastBridge.CallOpts) +} + +// GUARDROLE is a free data retrieval call binding the contract method 0x03ed0ee5. +// +// Solidity: function GUARD_ROLE() view returns(bytes32) +func (_FastBridge *FastBridgeCallerSession) GUARDROLE() ([32]byte, error) { + return _FastBridge.Contract.GUARDROLE(&_FastBridge.CallOpts) +} + +// MINDEADLINEPERIOD is a free data retrieval call binding the contract method 0x820688d5. +// +// Solidity: function MIN_DEADLINE_PERIOD() view returns(uint256) +func (_FastBridge *FastBridgeCaller) MINDEADLINEPERIOD(opts *bind.CallOpts) (*big.Int, error) { + var out []interface{} + err := _FastBridge.contract.Call(opts, &out, "MIN_DEADLINE_PERIOD") + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// MINDEADLINEPERIOD is a free data retrieval call binding the contract method 0x820688d5. +// +// Solidity: function MIN_DEADLINE_PERIOD() view returns(uint256) +func (_FastBridge *FastBridgeSession) MINDEADLINEPERIOD() (*big.Int, error) { + return _FastBridge.Contract.MINDEADLINEPERIOD(&_FastBridge.CallOpts) +} + +// MINDEADLINEPERIOD is a free data retrieval call binding the contract method 0x820688d5. +// +// Solidity: function MIN_DEADLINE_PERIOD() view returns(uint256) +func (_FastBridge *FastBridgeCallerSession) MINDEADLINEPERIOD() (*big.Int, error) { + return _FastBridge.Contract.MINDEADLINEPERIOD(&_FastBridge.CallOpts) +} + +// REFUNDERROLE is a free data retrieval call binding the contract method 0x5960ccf2. +// +// Solidity: function REFUNDER_ROLE() view returns(bytes32) +func (_FastBridge *FastBridgeCaller) REFUNDERROLE(opts *bind.CallOpts) ([32]byte, error) { + var out []interface{} + err := _FastBridge.contract.Call(opts, &out, "REFUNDER_ROLE") + + if err != nil { + return *new([32]byte), err + } + + out0 := *abi.ConvertType(out[0], new([32]byte)).(*[32]byte) + + return out0, err + +} + +// REFUNDERROLE is a free data retrieval call binding the contract method 0x5960ccf2. +// +// Solidity: function REFUNDER_ROLE() view returns(bytes32) +func (_FastBridge *FastBridgeSession) REFUNDERROLE() ([32]byte, error) { + return _FastBridge.Contract.REFUNDERROLE(&_FastBridge.CallOpts) +} + +// REFUNDERROLE is a free data retrieval call binding the contract method 0x5960ccf2. +// +// Solidity: function REFUNDER_ROLE() view returns(bytes32) +func (_FastBridge *FastBridgeCallerSession) REFUNDERROLE() ([32]byte, error) { + return _FastBridge.Contract.REFUNDERROLE(&_FastBridge.CallOpts) +} + +// REFUNDDELAY is a free data retrieval call binding the contract method 0x190da595. +// +// Solidity: function REFUND_DELAY() view returns(uint256) +func (_FastBridge *FastBridgeCaller) REFUNDDELAY(opts *bind.CallOpts) (*big.Int, error) { + var out []interface{} + err := _FastBridge.contract.Call(opts, &out, "REFUND_DELAY") + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// REFUNDDELAY is a free data retrieval call binding the contract method 0x190da595. +// +// Solidity: function REFUND_DELAY() view returns(uint256) +func (_FastBridge *FastBridgeSession) REFUNDDELAY() (*big.Int, error) { + return _FastBridge.Contract.REFUNDDELAY(&_FastBridge.CallOpts) +} + +// REFUNDDELAY is a free data retrieval call binding the contract method 0x190da595. +// +// Solidity: function REFUND_DELAY() view returns(uint256) +func (_FastBridge *FastBridgeCallerSession) REFUNDDELAY() (*big.Int, error) { + return _FastBridge.Contract.REFUNDDELAY(&_FastBridge.CallOpts) +} + +// RELAYERROLE is a free data retrieval call binding the contract method 0x926d7d7f. +// +// Solidity: function RELAYER_ROLE() view returns(bytes32) +func (_FastBridge *FastBridgeCaller) RELAYERROLE(opts *bind.CallOpts) ([32]byte, error) { + var out []interface{} + err := _FastBridge.contract.Call(opts, &out, "RELAYER_ROLE") + + if err != nil { + return *new([32]byte), err + } + + out0 := *abi.ConvertType(out[0], new([32]byte)).(*[32]byte) + + return out0, err + +} + +// RELAYERROLE is a free data retrieval call binding the contract method 0x926d7d7f. +// +// Solidity: function RELAYER_ROLE() view returns(bytes32) +func (_FastBridge *FastBridgeSession) RELAYERROLE() ([32]byte, error) { + return _FastBridge.Contract.RELAYERROLE(&_FastBridge.CallOpts) +} + +// RELAYERROLE is a free data retrieval call binding the contract method 0x926d7d7f. +// +// Solidity: function RELAYER_ROLE() view returns(bytes32) +func (_FastBridge *FastBridgeCallerSession) RELAYERROLE() ([32]byte, error) { + return _FastBridge.Contract.RELAYERROLE(&_FastBridge.CallOpts) +} + +// BridgeProofs is a free data retrieval call binding the contract method 0x91ad5039. +// +// Solidity: function bridgeProofs(bytes32 ) view returns(uint96 timestamp, address relayer) +func (_FastBridge *FastBridgeCaller) BridgeProofs(opts *bind.CallOpts, arg0 [32]byte) (struct { + Timestamp *big.Int + Relayer common.Address +}, error) { + var out []interface{} + err := _FastBridge.contract.Call(opts, &out, "bridgeProofs", arg0) + + outstruct := new(struct { + Timestamp *big.Int + Relayer common.Address + }) + if err != nil { + return *outstruct, err + } + + outstruct.Timestamp = *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + outstruct.Relayer = *abi.ConvertType(out[1], new(common.Address)).(*common.Address) + + return *outstruct, err + +} + +// BridgeProofs is a free data retrieval call binding the contract method 0x91ad5039. +// +// Solidity: function bridgeProofs(bytes32 ) view returns(uint96 timestamp, address relayer) +func (_FastBridge *FastBridgeSession) BridgeProofs(arg0 [32]byte) (struct { + Timestamp *big.Int + Relayer common.Address +}, error) { + return _FastBridge.Contract.BridgeProofs(&_FastBridge.CallOpts, arg0) +} + +// BridgeProofs is a free data retrieval call binding the contract method 0x91ad5039. +// +// Solidity: function bridgeProofs(bytes32 ) view returns(uint96 timestamp, address relayer) +func (_FastBridge *FastBridgeCallerSession) BridgeProofs(arg0 [32]byte) (struct { + Timestamp *big.Int + Relayer common.Address +}, error) { + return _FastBridge.Contract.BridgeProofs(&_FastBridge.CallOpts, arg0) +} + +// BridgeRelays is a free data retrieval call binding the contract method 0x8379a24f. +// +// Solidity: function bridgeRelays(bytes32 ) view returns(bool) +func (_FastBridge *FastBridgeCaller) BridgeRelays(opts *bind.CallOpts, arg0 [32]byte) (bool, error) { + var out []interface{} + err := _FastBridge.contract.Call(opts, &out, "bridgeRelays", arg0) + + if err != nil { + return *new(bool), err + } + + out0 := *abi.ConvertType(out[0], new(bool)).(*bool) + + return out0, err + +} + +// BridgeRelays is a free data retrieval call binding the contract method 0x8379a24f. +// +// Solidity: function bridgeRelays(bytes32 ) view returns(bool) +func (_FastBridge *FastBridgeSession) BridgeRelays(arg0 [32]byte) (bool, error) { + return _FastBridge.Contract.BridgeRelays(&_FastBridge.CallOpts, arg0) +} + +// BridgeRelays is a free data retrieval call binding the contract method 0x8379a24f. +// +// Solidity: function bridgeRelays(bytes32 ) view returns(bool) +func (_FastBridge *FastBridgeCallerSession) BridgeRelays(arg0 [32]byte) (bool, error) { + return _FastBridge.Contract.BridgeRelays(&_FastBridge.CallOpts, arg0) +} + +// BridgeStatuses is a free data retrieval call binding the contract method 0x051287bc. +// +// Solidity: function bridgeStatuses(bytes32 ) view returns(uint8) +func (_FastBridge *FastBridgeCaller) BridgeStatuses(opts *bind.CallOpts, arg0 [32]byte) (uint8, error) { + var out []interface{} + err := _FastBridge.contract.Call(opts, &out, "bridgeStatuses", arg0) + + if err != nil { + return *new(uint8), err + } + + out0 := *abi.ConvertType(out[0], new(uint8)).(*uint8) + + return out0, err + +} + +// BridgeStatuses is a free data retrieval call binding the contract method 0x051287bc. +// +// Solidity: function bridgeStatuses(bytes32 ) view returns(uint8) +func (_FastBridge *FastBridgeSession) BridgeStatuses(arg0 [32]byte) (uint8, error) { + return _FastBridge.Contract.BridgeStatuses(&_FastBridge.CallOpts, arg0) +} + +// BridgeStatuses is a free data retrieval call binding the contract method 0x051287bc. +// +// Solidity: function bridgeStatuses(bytes32 ) view returns(uint8) +func (_FastBridge *FastBridgeCallerSession) BridgeStatuses(arg0 [32]byte) (uint8, error) { + return _FastBridge.Contract.BridgeStatuses(&_FastBridge.CallOpts, arg0) +} + +// CanClaim is a free data retrieval call binding the contract method 0xaa9641ab. +// +// Solidity: function canClaim(bytes32 transactionId, address relayer) view returns(bool) +func (_FastBridge *FastBridgeCaller) CanClaim(opts *bind.CallOpts, transactionId [32]byte, relayer common.Address) (bool, error) { + var out []interface{} + err := _FastBridge.contract.Call(opts, &out, "canClaim", transactionId, relayer) + + if err != nil { + return *new(bool), err + } + + out0 := *abi.ConvertType(out[0], new(bool)).(*bool) + + return out0, err + +} + +// CanClaim is a free data retrieval call binding the contract method 0xaa9641ab. +// +// Solidity: function canClaim(bytes32 transactionId, address relayer) view returns(bool) +func (_FastBridge *FastBridgeSession) CanClaim(transactionId [32]byte, relayer common.Address) (bool, error) { + return _FastBridge.Contract.CanClaim(&_FastBridge.CallOpts, transactionId, relayer) +} + +// CanClaim is a free data retrieval call binding the contract method 0xaa9641ab. +// +// Solidity: function canClaim(bytes32 transactionId, address relayer) view returns(bool) +func (_FastBridge *FastBridgeCallerSession) CanClaim(transactionId [32]byte, relayer common.Address) (bool, error) { + return _FastBridge.Contract.CanClaim(&_FastBridge.CallOpts, transactionId, relayer) +} + +// ChainGasAmount is a free data retrieval call binding the contract method 0xe00a83e0. +// +// Solidity: function chainGasAmount() view returns(uint256) +func (_FastBridge *FastBridgeCaller) ChainGasAmount(opts *bind.CallOpts) (*big.Int, error) { + var out []interface{} + err := _FastBridge.contract.Call(opts, &out, "chainGasAmount") + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// ChainGasAmount is a free data retrieval call binding the contract method 0xe00a83e0. +// +// Solidity: function chainGasAmount() view returns(uint256) +func (_FastBridge *FastBridgeSession) ChainGasAmount() (*big.Int, error) { + return _FastBridge.Contract.ChainGasAmount(&_FastBridge.CallOpts) +} + +// ChainGasAmount is a free data retrieval call binding the contract method 0xe00a83e0. +// +// Solidity: function chainGasAmount() view returns(uint256) +func (_FastBridge *FastBridgeCallerSession) ChainGasAmount() (*big.Int, error) { + return _FastBridge.Contract.ChainGasAmount(&_FastBridge.CallOpts) +} + +// DeployBlock is a free data retrieval call binding the contract method 0xa3ec191a. +// +// Solidity: function deployBlock() view returns(uint256) +func (_FastBridge *FastBridgeCaller) DeployBlock(opts *bind.CallOpts) (*big.Int, error) { + var out []interface{} + err := _FastBridge.contract.Call(opts, &out, "deployBlock") + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// DeployBlock is a free data retrieval call binding the contract method 0xa3ec191a. +// +// Solidity: function deployBlock() view returns(uint256) +func (_FastBridge *FastBridgeSession) DeployBlock() (*big.Int, error) { + return _FastBridge.Contract.DeployBlock(&_FastBridge.CallOpts) +} + +// DeployBlock is a free data retrieval call binding the contract method 0xa3ec191a. +// +// Solidity: function deployBlock() view returns(uint256) +func (_FastBridge *FastBridgeCallerSession) DeployBlock() (*big.Int, error) { + return _FastBridge.Contract.DeployBlock(&_FastBridge.CallOpts) +} + +// GetBridgeTransaction is a free data retrieval call binding the contract method 0xac11fb1a. +// +// Solidity: function getBridgeTransaction(bytes request) pure returns((uint32,uint32,address,address,address,address,uint256,uint256,uint256,bool,uint256,uint256)) +func (_FastBridge *FastBridgeCaller) GetBridgeTransaction(opts *bind.CallOpts, request []byte) (IFastBridgeBridgeTransaction, error) { + var out []interface{} + err := _FastBridge.contract.Call(opts, &out, "getBridgeTransaction", request) + + if err != nil { + return *new(IFastBridgeBridgeTransaction), err + } + + out0 := *abi.ConvertType(out[0], new(IFastBridgeBridgeTransaction)).(*IFastBridgeBridgeTransaction) + + return out0, err + +} + +// GetBridgeTransaction is a free data retrieval call binding the contract method 0xac11fb1a. +// +// Solidity: function getBridgeTransaction(bytes request) pure returns((uint32,uint32,address,address,address,address,uint256,uint256,uint256,bool,uint256,uint256)) +func (_FastBridge *FastBridgeSession) GetBridgeTransaction(request []byte) (IFastBridgeBridgeTransaction, error) { + return _FastBridge.Contract.GetBridgeTransaction(&_FastBridge.CallOpts, request) +} + +// GetBridgeTransaction is a free data retrieval call binding the contract method 0xac11fb1a. +// +// Solidity: function getBridgeTransaction(bytes request) pure returns((uint32,uint32,address,address,address,address,uint256,uint256,uint256,bool,uint256,uint256)) +func (_FastBridge *FastBridgeCallerSession) GetBridgeTransaction(request []byte) (IFastBridgeBridgeTransaction, error) { + return _FastBridge.Contract.GetBridgeTransaction(&_FastBridge.CallOpts, request) +} + +// GetRoleAdmin is a free data retrieval call binding the contract method 0x248a9ca3. +// +// Solidity: function getRoleAdmin(bytes32 role) view returns(bytes32) +func (_FastBridge *FastBridgeCaller) GetRoleAdmin(opts *bind.CallOpts, role [32]byte) ([32]byte, error) { + var out []interface{} + err := _FastBridge.contract.Call(opts, &out, "getRoleAdmin", role) + + if err != nil { + return *new([32]byte), err + } + + out0 := *abi.ConvertType(out[0], new([32]byte)).(*[32]byte) + + return out0, err + +} + +// GetRoleAdmin is a free data retrieval call binding the contract method 0x248a9ca3. +// +// Solidity: function getRoleAdmin(bytes32 role) view returns(bytes32) +func (_FastBridge *FastBridgeSession) GetRoleAdmin(role [32]byte) ([32]byte, error) { + return _FastBridge.Contract.GetRoleAdmin(&_FastBridge.CallOpts, role) +} + +// GetRoleAdmin is a free data retrieval call binding the contract method 0x248a9ca3. +// +// Solidity: function getRoleAdmin(bytes32 role) view returns(bytes32) +func (_FastBridge *FastBridgeCallerSession) GetRoleAdmin(role [32]byte) ([32]byte, error) { + return _FastBridge.Contract.GetRoleAdmin(&_FastBridge.CallOpts, role) +} + +// GetRoleMember is a free data retrieval call binding the contract method 0x9010d07c. +// +// Solidity: function getRoleMember(bytes32 role, uint256 index) view returns(address) +func (_FastBridge *FastBridgeCaller) GetRoleMember(opts *bind.CallOpts, role [32]byte, index *big.Int) (common.Address, error) { + var out []interface{} + err := _FastBridge.contract.Call(opts, &out, "getRoleMember", role, index) + + if err != nil { + return *new(common.Address), err + } + + out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) + + return out0, err + +} + +// GetRoleMember is a free data retrieval call binding the contract method 0x9010d07c. +// +// Solidity: function getRoleMember(bytes32 role, uint256 index) view returns(address) +func (_FastBridge *FastBridgeSession) GetRoleMember(role [32]byte, index *big.Int) (common.Address, error) { + return _FastBridge.Contract.GetRoleMember(&_FastBridge.CallOpts, role, index) +} + +// GetRoleMember is a free data retrieval call binding the contract method 0x9010d07c. +// +// Solidity: function getRoleMember(bytes32 role, uint256 index) view returns(address) +func (_FastBridge *FastBridgeCallerSession) GetRoleMember(role [32]byte, index *big.Int) (common.Address, error) { + return _FastBridge.Contract.GetRoleMember(&_FastBridge.CallOpts, role, index) +} + +// GetRoleMemberCount is a free data retrieval call binding the contract method 0xca15c873. +// +// Solidity: function getRoleMemberCount(bytes32 role) view returns(uint256) +func (_FastBridge *FastBridgeCaller) GetRoleMemberCount(opts *bind.CallOpts, role [32]byte) (*big.Int, error) { + var out []interface{} + err := _FastBridge.contract.Call(opts, &out, "getRoleMemberCount", role) + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// GetRoleMemberCount is a free data retrieval call binding the contract method 0xca15c873. +// +// Solidity: function getRoleMemberCount(bytes32 role) view returns(uint256) +func (_FastBridge *FastBridgeSession) GetRoleMemberCount(role [32]byte) (*big.Int, error) { + return _FastBridge.Contract.GetRoleMemberCount(&_FastBridge.CallOpts, role) +} + +// GetRoleMemberCount is a free data retrieval call binding the contract method 0xca15c873. +// +// Solidity: function getRoleMemberCount(bytes32 role) view returns(uint256) +func (_FastBridge *FastBridgeCallerSession) GetRoleMemberCount(role [32]byte) (*big.Int, error) { + return _FastBridge.Contract.GetRoleMemberCount(&_FastBridge.CallOpts, role) +} + +// HasRole is a free data retrieval call binding the contract method 0x91d14854. +// +// Solidity: function hasRole(bytes32 role, address account) view returns(bool) +func (_FastBridge *FastBridgeCaller) HasRole(opts *bind.CallOpts, role [32]byte, account common.Address) (bool, error) { + var out []interface{} + err := _FastBridge.contract.Call(opts, &out, "hasRole", role, account) + + if err != nil { + return *new(bool), err + } + + out0 := *abi.ConvertType(out[0], new(bool)).(*bool) + + return out0, err + +} + +// HasRole is a free data retrieval call binding the contract method 0x91d14854. +// +// Solidity: function hasRole(bytes32 role, address account) view returns(bool) +func (_FastBridge *FastBridgeSession) HasRole(role [32]byte, account common.Address) (bool, error) { + return _FastBridge.Contract.HasRole(&_FastBridge.CallOpts, role, account) +} + +// HasRole is a free data retrieval call binding the contract method 0x91d14854. +// +// Solidity: function hasRole(bytes32 role, address account) view returns(bool) +func (_FastBridge *FastBridgeCallerSession) HasRole(role [32]byte, account common.Address) (bool, error) { + return _FastBridge.Contract.HasRole(&_FastBridge.CallOpts, role, account) +} + +// Nonce is a free data retrieval call binding the contract method 0xaffed0e0. +// +// Solidity: function nonce() view returns(uint256) +func (_FastBridge *FastBridgeCaller) Nonce(opts *bind.CallOpts) (*big.Int, error) { + var out []interface{} + err := _FastBridge.contract.Call(opts, &out, "nonce") + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// Nonce is a free data retrieval call binding the contract method 0xaffed0e0. +// +// Solidity: function nonce() view returns(uint256) +func (_FastBridge *FastBridgeSession) Nonce() (*big.Int, error) { + return _FastBridge.Contract.Nonce(&_FastBridge.CallOpts) +} + +// Nonce is a free data retrieval call binding the contract method 0xaffed0e0. +// +// Solidity: function nonce() view returns(uint256) +func (_FastBridge *FastBridgeCallerSession) Nonce() (*big.Int, error) { + return _FastBridge.Contract.Nonce(&_FastBridge.CallOpts) +} + +// ProtocolFeeRate is a free data retrieval call binding the contract method 0x58f85880. +// +// Solidity: function protocolFeeRate() view returns(uint256) +func (_FastBridge *FastBridgeCaller) ProtocolFeeRate(opts *bind.CallOpts) (*big.Int, error) { + var out []interface{} + err := _FastBridge.contract.Call(opts, &out, "protocolFeeRate") + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// ProtocolFeeRate is a free data retrieval call binding the contract method 0x58f85880. +// +// Solidity: function protocolFeeRate() view returns(uint256) +func (_FastBridge *FastBridgeSession) ProtocolFeeRate() (*big.Int, error) { + return _FastBridge.Contract.ProtocolFeeRate(&_FastBridge.CallOpts) +} + +// ProtocolFeeRate is a free data retrieval call binding the contract method 0x58f85880. +// +// Solidity: function protocolFeeRate() view returns(uint256) +func (_FastBridge *FastBridgeCallerSession) ProtocolFeeRate() (*big.Int, error) { + return _FastBridge.Contract.ProtocolFeeRate(&_FastBridge.CallOpts) +} + +// ProtocolFees is a free data retrieval call binding the contract method 0xdcf844a7. +// +// Solidity: function protocolFees(address ) view returns(uint256) +func (_FastBridge *FastBridgeCaller) ProtocolFees(opts *bind.CallOpts, arg0 common.Address) (*big.Int, error) { + var out []interface{} + err := _FastBridge.contract.Call(opts, &out, "protocolFees", arg0) + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// ProtocolFees is a free data retrieval call binding the contract method 0xdcf844a7. +// +// Solidity: function protocolFees(address ) view returns(uint256) +func (_FastBridge *FastBridgeSession) ProtocolFees(arg0 common.Address) (*big.Int, error) { + return _FastBridge.Contract.ProtocolFees(&_FastBridge.CallOpts, arg0) +} + +// ProtocolFees is a free data retrieval call binding the contract method 0xdcf844a7. +// +// Solidity: function protocolFees(address ) view returns(uint256) +func (_FastBridge *FastBridgeCallerSession) ProtocolFees(arg0 common.Address) (*big.Int, error) { + return _FastBridge.Contract.ProtocolFees(&_FastBridge.CallOpts, arg0) +} + +// SupportsInterface is a free data retrieval call binding the contract method 0x01ffc9a7. +// +// Solidity: function supportsInterface(bytes4 interfaceId) view returns(bool) +func (_FastBridge *FastBridgeCaller) SupportsInterface(opts *bind.CallOpts, interfaceId [4]byte) (bool, error) { + var out []interface{} + err := _FastBridge.contract.Call(opts, &out, "supportsInterface", interfaceId) + + if err != nil { + return *new(bool), err + } + + out0 := *abi.ConvertType(out[0], new(bool)).(*bool) + + return out0, err + +} + +// SupportsInterface is a free data retrieval call binding the contract method 0x01ffc9a7. +// +// Solidity: function supportsInterface(bytes4 interfaceId) view returns(bool) +func (_FastBridge *FastBridgeSession) SupportsInterface(interfaceId [4]byte) (bool, error) { + return _FastBridge.Contract.SupportsInterface(&_FastBridge.CallOpts, interfaceId) +} + +// SupportsInterface is a free data retrieval call binding the contract method 0x01ffc9a7. +// +// Solidity: function supportsInterface(bytes4 interfaceId) view returns(bool) +func (_FastBridge *FastBridgeCallerSession) SupportsInterface(interfaceId [4]byte) (bool, error) { + return _FastBridge.Contract.SupportsInterface(&_FastBridge.CallOpts, interfaceId) +} + +// Bridge is a paid mutator transaction binding the contract method 0x45851694. +// +// Solidity: function bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256) params) payable returns() +func (_FastBridge *FastBridgeTransactor) Bridge(opts *bind.TransactOpts, params IFastBridgeBridgeParams) (*types.Transaction, error) { + return _FastBridge.contract.Transact(opts, "bridge", params) +} + +// Bridge is a paid mutator transaction binding the contract method 0x45851694. +// +// Solidity: function bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256) params) payable returns() +func (_FastBridge *FastBridgeSession) Bridge(params IFastBridgeBridgeParams) (*types.Transaction, error) { + return _FastBridge.Contract.Bridge(&_FastBridge.TransactOpts, params) +} + +// Bridge is a paid mutator transaction binding the contract method 0x45851694. +// +// Solidity: function bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256) params) payable returns() +func (_FastBridge *FastBridgeTransactorSession) Bridge(params IFastBridgeBridgeParams) (*types.Transaction, error) { + return _FastBridge.Contract.Bridge(&_FastBridge.TransactOpts, params) +} + +// Claim is a paid mutator transaction binding the contract method 0x41fcb612. +// +// Solidity: function claim(bytes request, address to) returns() +func (_FastBridge *FastBridgeTransactor) Claim(opts *bind.TransactOpts, request []byte, to common.Address) (*types.Transaction, error) { + return _FastBridge.contract.Transact(opts, "claim", request, to) +} + +// Claim is a paid mutator transaction binding the contract method 0x41fcb612. +// +// Solidity: function claim(bytes request, address to) returns() +func (_FastBridge *FastBridgeSession) Claim(request []byte, to common.Address) (*types.Transaction, error) { + return _FastBridge.Contract.Claim(&_FastBridge.TransactOpts, request, to) +} + +// Claim is a paid mutator transaction binding the contract method 0x41fcb612. +// +// Solidity: function claim(bytes request, address to) returns() +func (_FastBridge *FastBridgeTransactorSession) Claim(request []byte, to common.Address) (*types.Transaction, error) { + return _FastBridge.Contract.Claim(&_FastBridge.TransactOpts, request, to) +} + +// Dispute is a paid mutator transaction binding the contract method 0xadd98c70. +// +// Solidity: function dispute(bytes32 transactionId) returns() +func (_FastBridge *FastBridgeTransactor) Dispute(opts *bind.TransactOpts, transactionId [32]byte) (*types.Transaction, error) { + return _FastBridge.contract.Transact(opts, "dispute", transactionId) +} + +// Dispute is a paid mutator transaction binding the contract method 0xadd98c70. +// +// Solidity: function dispute(bytes32 transactionId) returns() +func (_FastBridge *FastBridgeSession) Dispute(transactionId [32]byte) (*types.Transaction, error) { + return _FastBridge.Contract.Dispute(&_FastBridge.TransactOpts, transactionId) +} + +// Dispute is a paid mutator transaction binding the contract method 0xadd98c70. +// +// Solidity: function dispute(bytes32 transactionId) returns() +func (_FastBridge *FastBridgeTransactorSession) Dispute(transactionId [32]byte) (*types.Transaction, error) { + return _FastBridge.Contract.Dispute(&_FastBridge.TransactOpts, transactionId) +} + +// GrantRole is a paid mutator transaction binding the contract method 0x2f2ff15d. +// +// Solidity: function grantRole(bytes32 role, address account) returns() +func (_FastBridge *FastBridgeTransactor) GrantRole(opts *bind.TransactOpts, role [32]byte, account common.Address) (*types.Transaction, error) { + return _FastBridge.contract.Transact(opts, "grantRole", role, account) +} + +// GrantRole is a paid mutator transaction binding the contract method 0x2f2ff15d. +// +// Solidity: function grantRole(bytes32 role, address account) returns() +func (_FastBridge *FastBridgeSession) GrantRole(role [32]byte, account common.Address) (*types.Transaction, error) { + return _FastBridge.Contract.GrantRole(&_FastBridge.TransactOpts, role, account) +} + +// GrantRole is a paid mutator transaction binding the contract method 0x2f2ff15d. +// +// Solidity: function grantRole(bytes32 role, address account) returns() +func (_FastBridge *FastBridgeTransactorSession) GrantRole(role [32]byte, account common.Address) (*types.Transaction, error) { + return _FastBridge.Contract.GrantRole(&_FastBridge.TransactOpts, role, account) +} + +// Prove is a paid mutator transaction binding the contract method 0x886d36ff. +// +// Solidity: function prove(bytes request, bytes32 destTxHash) returns() +func (_FastBridge *FastBridgeTransactor) Prove(opts *bind.TransactOpts, request []byte, destTxHash [32]byte) (*types.Transaction, error) { + return _FastBridge.contract.Transact(opts, "prove", request, destTxHash) +} + +// Prove is a paid mutator transaction binding the contract method 0x886d36ff. +// +// Solidity: function prove(bytes request, bytes32 destTxHash) returns() +func (_FastBridge *FastBridgeSession) Prove(request []byte, destTxHash [32]byte) (*types.Transaction, error) { + return _FastBridge.Contract.Prove(&_FastBridge.TransactOpts, request, destTxHash) +} + +// Prove is a paid mutator transaction binding the contract method 0x886d36ff. +// +// Solidity: function prove(bytes request, bytes32 destTxHash) returns() +func (_FastBridge *FastBridgeTransactorSession) Prove(request []byte, destTxHash [32]byte) (*types.Transaction, error) { + return _FastBridge.Contract.Prove(&_FastBridge.TransactOpts, request, destTxHash) +} + +// Refund is a paid mutator transaction binding the contract method 0x5eb7d946. +// +// Solidity: function refund(bytes request) returns() +func (_FastBridge *FastBridgeTransactor) Refund(opts *bind.TransactOpts, request []byte) (*types.Transaction, error) { + return _FastBridge.contract.Transact(opts, "refund", request) +} + +// Refund is a paid mutator transaction binding the contract method 0x5eb7d946. +// +// Solidity: function refund(bytes request) returns() +func (_FastBridge *FastBridgeSession) Refund(request []byte) (*types.Transaction, error) { + return _FastBridge.Contract.Refund(&_FastBridge.TransactOpts, request) +} + +// Refund is a paid mutator transaction binding the contract method 0x5eb7d946. +// +// Solidity: function refund(bytes request) returns() +func (_FastBridge *FastBridgeTransactorSession) Refund(request []byte) (*types.Transaction, error) { + return _FastBridge.Contract.Refund(&_FastBridge.TransactOpts, request) +} + +// Relay is a paid mutator transaction binding the contract method 0x8f0d6f17. +// +// Solidity: function relay(bytes request) payable returns() +func (_FastBridge *FastBridgeTransactor) Relay(opts *bind.TransactOpts, request []byte) (*types.Transaction, error) { + return _FastBridge.contract.Transact(opts, "relay", request) +} + +// Relay is a paid mutator transaction binding the contract method 0x8f0d6f17. +// +// Solidity: function relay(bytes request) payable returns() +func (_FastBridge *FastBridgeSession) Relay(request []byte) (*types.Transaction, error) { + return _FastBridge.Contract.Relay(&_FastBridge.TransactOpts, request) +} + +// Relay is a paid mutator transaction binding the contract method 0x8f0d6f17. +// +// Solidity: function relay(bytes request) payable returns() +func (_FastBridge *FastBridgeTransactorSession) Relay(request []byte) (*types.Transaction, error) { + return _FastBridge.Contract.Relay(&_FastBridge.TransactOpts, request) +} + +// RenounceRole is a paid mutator transaction binding the contract method 0x36568abe. +// +// Solidity: function renounceRole(bytes32 role, address callerConfirmation) returns() +func (_FastBridge *FastBridgeTransactor) RenounceRole(opts *bind.TransactOpts, role [32]byte, callerConfirmation common.Address) (*types.Transaction, error) { + return _FastBridge.contract.Transact(opts, "renounceRole", role, callerConfirmation) +} + +// RenounceRole is a paid mutator transaction binding the contract method 0x36568abe. +// +// Solidity: function renounceRole(bytes32 role, address callerConfirmation) returns() +func (_FastBridge *FastBridgeSession) RenounceRole(role [32]byte, callerConfirmation common.Address) (*types.Transaction, error) { + return _FastBridge.Contract.RenounceRole(&_FastBridge.TransactOpts, role, callerConfirmation) +} + +// RenounceRole is a paid mutator transaction binding the contract method 0x36568abe. +// +// Solidity: function renounceRole(bytes32 role, address callerConfirmation) returns() +func (_FastBridge *FastBridgeTransactorSession) RenounceRole(role [32]byte, callerConfirmation common.Address) (*types.Transaction, error) { + return _FastBridge.Contract.RenounceRole(&_FastBridge.TransactOpts, role, callerConfirmation) +} + +// RevokeRole is a paid mutator transaction binding the contract method 0xd547741f. +// +// Solidity: function revokeRole(bytes32 role, address account) returns() +func (_FastBridge *FastBridgeTransactor) RevokeRole(opts *bind.TransactOpts, role [32]byte, account common.Address) (*types.Transaction, error) { + return _FastBridge.contract.Transact(opts, "revokeRole", role, account) +} + +// RevokeRole is a paid mutator transaction binding the contract method 0xd547741f. +// +// Solidity: function revokeRole(bytes32 role, address account) returns() +func (_FastBridge *FastBridgeSession) RevokeRole(role [32]byte, account common.Address) (*types.Transaction, error) { + return _FastBridge.Contract.RevokeRole(&_FastBridge.TransactOpts, role, account) +} + +// RevokeRole is a paid mutator transaction binding the contract method 0xd547741f. +// +// Solidity: function revokeRole(bytes32 role, address account) returns() +func (_FastBridge *FastBridgeTransactorSession) RevokeRole(role [32]byte, account common.Address) (*types.Transaction, error) { + return _FastBridge.Contract.RevokeRole(&_FastBridge.TransactOpts, role, account) +} + +// SetChainGasAmount is a paid mutator transaction binding the contract method 0xb250fe6b. +// +// Solidity: function setChainGasAmount(uint256 newChainGasAmount) returns() +func (_FastBridge *FastBridgeTransactor) SetChainGasAmount(opts *bind.TransactOpts, newChainGasAmount *big.Int) (*types.Transaction, error) { + return _FastBridge.contract.Transact(opts, "setChainGasAmount", newChainGasAmount) +} + +// SetChainGasAmount is a paid mutator transaction binding the contract method 0xb250fe6b. +// +// Solidity: function setChainGasAmount(uint256 newChainGasAmount) returns() +func (_FastBridge *FastBridgeSession) SetChainGasAmount(newChainGasAmount *big.Int) (*types.Transaction, error) { + return _FastBridge.Contract.SetChainGasAmount(&_FastBridge.TransactOpts, newChainGasAmount) +} + +// SetChainGasAmount is a paid mutator transaction binding the contract method 0xb250fe6b. +// +// Solidity: function setChainGasAmount(uint256 newChainGasAmount) returns() +func (_FastBridge *FastBridgeTransactorSession) SetChainGasAmount(newChainGasAmount *big.Int) (*types.Transaction, error) { + return _FastBridge.Contract.SetChainGasAmount(&_FastBridge.TransactOpts, newChainGasAmount) +} + +// SetProtocolFeeRate is a paid mutator transaction binding the contract method 0xb13aa2d6. +// +// Solidity: function setProtocolFeeRate(uint256 newFeeRate) returns() +func (_FastBridge *FastBridgeTransactor) SetProtocolFeeRate(opts *bind.TransactOpts, newFeeRate *big.Int) (*types.Transaction, error) { + return _FastBridge.contract.Transact(opts, "setProtocolFeeRate", newFeeRate) +} + +// SetProtocolFeeRate is a paid mutator transaction binding the contract method 0xb13aa2d6. +// +// Solidity: function setProtocolFeeRate(uint256 newFeeRate) returns() +func (_FastBridge *FastBridgeSession) SetProtocolFeeRate(newFeeRate *big.Int) (*types.Transaction, error) { + return _FastBridge.Contract.SetProtocolFeeRate(&_FastBridge.TransactOpts, newFeeRate) +} + +// SetProtocolFeeRate is a paid mutator transaction binding the contract method 0xb13aa2d6. +// +// Solidity: function setProtocolFeeRate(uint256 newFeeRate) returns() +func (_FastBridge *FastBridgeTransactorSession) SetProtocolFeeRate(newFeeRate *big.Int) (*types.Transaction, error) { + return _FastBridge.Contract.SetProtocolFeeRate(&_FastBridge.TransactOpts, newFeeRate) +} + +// SweepProtocolFees is a paid mutator transaction binding the contract method 0x06f333f2. +// +// Solidity: function sweepProtocolFees(address token, address recipient) returns() +func (_FastBridge *FastBridgeTransactor) SweepProtocolFees(opts *bind.TransactOpts, token common.Address, recipient common.Address) (*types.Transaction, error) { + return _FastBridge.contract.Transact(opts, "sweepProtocolFees", token, recipient) +} + +// SweepProtocolFees is a paid mutator transaction binding the contract method 0x06f333f2. +// +// Solidity: function sweepProtocolFees(address token, address recipient) returns() +func (_FastBridge *FastBridgeSession) SweepProtocolFees(token common.Address, recipient common.Address) (*types.Transaction, error) { + return _FastBridge.Contract.SweepProtocolFees(&_FastBridge.TransactOpts, token, recipient) +} + +// SweepProtocolFees is a paid mutator transaction binding the contract method 0x06f333f2. +// +// Solidity: function sweepProtocolFees(address token, address recipient) returns() +func (_FastBridge *FastBridgeTransactorSession) SweepProtocolFees(token common.Address, recipient common.Address) (*types.Transaction, error) { + return _FastBridge.Contract.SweepProtocolFees(&_FastBridge.TransactOpts, token, recipient) +} + +// FastBridgeBridgeDepositClaimedIterator is returned from FilterBridgeDepositClaimed and is used to iterate over the raw logs and unpacked data for BridgeDepositClaimed events raised by the FastBridge contract. +type FastBridgeBridgeDepositClaimedIterator struct { + Event *FastBridgeBridgeDepositClaimed // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *FastBridgeBridgeDepositClaimedIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(FastBridgeBridgeDepositClaimed) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(FastBridgeBridgeDepositClaimed) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *FastBridgeBridgeDepositClaimedIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *FastBridgeBridgeDepositClaimedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// FastBridgeBridgeDepositClaimed represents a BridgeDepositClaimed event raised by the FastBridge contract. +type FastBridgeBridgeDepositClaimed struct { + TransactionId [32]byte + Relayer common.Address + To common.Address + Token common.Address + Amount *big.Int + Raw types.Log // Blockchain specific contextual infos +} + +// FilterBridgeDepositClaimed is a free log retrieval operation binding the contract event 0x582211c35a2139ac3bbaac74663c6a1f56c6cbb658b41fe11fd45a82074ac678. +// +// Solidity: event BridgeDepositClaimed(bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount) +func (_FastBridge *FastBridgeFilterer) FilterBridgeDepositClaimed(opts *bind.FilterOpts, transactionId [][32]byte, relayer []common.Address, to []common.Address) (*FastBridgeBridgeDepositClaimedIterator, error) { + + var transactionIdRule []interface{} + for _, transactionIdItem := range transactionId { + transactionIdRule = append(transactionIdRule, transactionIdItem) + } + var relayerRule []interface{} + for _, relayerItem := range relayer { + relayerRule = append(relayerRule, relayerItem) + } + var toRule []interface{} + for _, toItem := range to { + toRule = append(toRule, toItem) + } + + logs, sub, err := _FastBridge.contract.FilterLogs(opts, "BridgeDepositClaimed", transactionIdRule, relayerRule, toRule) + if err != nil { + return nil, err + } + return &FastBridgeBridgeDepositClaimedIterator{contract: _FastBridge.contract, event: "BridgeDepositClaimed", logs: logs, sub: sub}, nil +} + +// WatchBridgeDepositClaimed is a free log subscription operation binding the contract event 0x582211c35a2139ac3bbaac74663c6a1f56c6cbb658b41fe11fd45a82074ac678. +// +// Solidity: event BridgeDepositClaimed(bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount) +func (_FastBridge *FastBridgeFilterer) WatchBridgeDepositClaimed(opts *bind.WatchOpts, sink chan<- *FastBridgeBridgeDepositClaimed, transactionId [][32]byte, relayer []common.Address, to []common.Address) (event.Subscription, error) { + + var transactionIdRule []interface{} + for _, transactionIdItem := range transactionId { + transactionIdRule = append(transactionIdRule, transactionIdItem) + } + var relayerRule []interface{} + for _, relayerItem := range relayer { + relayerRule = append(relayerRule, relayerItem) + } + var toRule []interface{} + for _, toItem := range to { + toRule = append(toRule, toItem) + } + + logs, sub, err := _FastBridge.contract.WatchLogs(opts, "BridgeDepositClaimed", transactionIdRule, relayerRule, toRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(FastBridgeBridgeDepositClaimed) + if err := _FastBridge.contract.UnpackLog(event, "BridgeDepositClaimed", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseBridgeDepositClaimed is a log parse operation binding the contract event 0x582211c35a2139ac3bbaac74663c6a1f56c6cbb658b41fe11fd45a82074ac678. +// +// Solidity: event BridgeDepositClaimed(bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount) +func (_FastBridge *FastBridgeFilterer) ParseBridgeDepositClaimed(log types.Log) (*FastBridgeBridgeDepositClaimed, error) { + event := new(FastBridgeBridgeDepositClaimed) + if err := _FastBridge.contract.UnpackLog(event, "BridgeDepositClaimed", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// FastBridgeBridgeDepositRefundedIterator is returned from FilterBridgeDepositRefunded and is used to iterate over the raw logs and unpacked data for BridgeDepositRefunded events raised by the FastBridge contract. +type FastBridgeBridgeDepositRefundedIterator struct { + Event *FastBridgeBridgeDepositRefunded // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *FastBridgeBridgeDepositRefundedIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(FastBridgeBridgeDepositRefunded) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(FastBridgeBridgeDepositRefunded) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *FastBridgeBridgeDepositRefundedIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *FastBridgeBridgeDepositRefundedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// FastBridgeBridgeDepositRefunded represents a BridgeDepositRefunded event raised by the FastBridge contract. +type FastBridgeBridgeDepositRefunded struct { + TransactionId [32]byte + To common.Address + Token common.Address + Amount *big.Int + Raw types.Log // Blockchain specific contextual infos +} + +// FilterBridgeDepositRefunded is a free log retrieval operation binding the contract event 0xb4c55c0c9bc613519b920e88748090150b890a875d307f21bea7d4fb2e8bc958. +// +// Solidity: event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount) +func (_FastBridge *FastBridgeFilterer) FilterBridgeDepositRefunded(opts *bind.FilterOpts, transactionId [][32]byte, to []common.Address) (*FastBridgeBridgeDepositRefundedIterator, error) { + + var transactionIdRule []interface{} + for _, transactionIdItem := range transactionId { + transactionIdRule = append(transactionIdRule, transactionIdItem) + } + var toRule []interface{} + for _, toItem := range to { + toRule = append(toRule, toItem) + } + + logs, sub, err := _FastBridge.contract.FilterLogs(opts, "BridgeDepositRefunded", transactionIdRule, toRule) + if err != nil { + return nil, err + } + return &FastBridgeBridgeDepositRefundedIterator{contract: _FastBridge.contract, event: "BridgeDepositRefunded", logs: logs, sub: sub}, nil +} + +// WatchBridgeDepositRefunded is a free log subscription operation binding the contract event 0xb4c55c0c9bc613519b920e88748090150b890a875d307f21bea7d4fb2e8bc958. +// +// Solidity: event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount) +func (_FastBridge *FastBridgeFilterer) WatchBridgeDepositRefunded(opts *bind.WatchOpts, sink chan<- *FastBridgeBridgeDepositRefunded, transactionId [][32]byte, to []common.Address) (event.Subscription, error) { + + var transactionIdRule []interface{} + for _, transactionIdItem := range transactionId { + transactionIdRule = append(transactionIdRule, transactionIdItem) + } + var toRule []interface{} + for _, toItem := range to { + toRule = append(toRule, toItem) + } + + logs, sub, err := _FastBridge.contract.WatchLogs(opts, "BridgeDepositRefunded", transactionIdRule, toRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(FastBridgeBridgeDepositRefunded) + if err := _FastBridge.contract.UnpackLog(event, "BridgeDepositRefunded", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseBridgeDepositRefunded is a log parse operation binding the contract event 0xb4c55c0c9bc613519b920e88748090150b890a875d307f21bea7d4fb2e8bc958. +// +// Solidity: event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount) +func (_FastBridge *FastBridgeFilterer) ParseBridgeDepositRefunded(log types.Log) (*FastBridgeBridgeDepositRefunded, error) { + event := new(FastBridgeBridgeDepositRefunded) + if err := _FastBridge.contract.UnpackLog(event, "BridgeDepositRefunded", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// FastBridgeBridgeProofDisputedIterator is returned from FilterBridgeProofDisputed and is used to iterate over the raw logs and unpacked data for BridgeProofDisputed events raised by the FastBridge contract. +type FastBridgeBridgeProofDisputedIterator struct { + Event *FastBridgeBridgeProofDisputed // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *FastBridgeBridgeProofDisputedIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(FastBridgeBridgeProofDisputed) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(FastBridgeBridgeProofDisputed) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *FastBridgeBridgeProofDisputedIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *FastBridgeBridgeProofDisputedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// FastBridgeBridgeProofDisputed represents a BridgeProofDisputed event raised by the FastBridge contract. +type FastBridgeBridgeProofDisputed struct { + TransactionId [32]byte + Relayer common.Address + Raw types.Log // Blockchain specific contextual infos +} + +// FilterBridgeProofDisputed is a free log retrieval operation binding the contract event 0x0695cf1d39b3055dcd0fe02d8b47eaf0d5a13e1996de925de59d0ef9b7f7fad4. +// +// Solidity: event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer) +func (_FastBridge *FastBridgeFilterer) FilterBridgeProofDisputed(opts *bind.FilterOpts, transactionId [][32]byte, relayer []common.Address) (*FastBridgeBridgeProofDisputedIterator, error) { + + var transactionIdRule []interface{} + for _, transactionIdItem := range transactionId { + transactionIdRule = append(transactionIdRule, transactionIdItem) + } + var relayerRule []interface{} + for _, relayerItem := range relayer { + relayerRule = append(relayerRule, relayerItem) + } + + logs, sub, err := _FastBridge.contract.FilterLogs(opts, "BridgeProofDisputed", transactionIdRule, relayerRule) + if err != nil { + return nil, err + } + return &FastBridgeBridgeProofDisputedIterator{contract: _FastBridge.contract, event: "BridgeProofDisputed", logs: logs, sub: sub}, nil +} + +// WatchBridgeProofDisputed is a free log subscription operation binding the contract event 0x0695cf1d39b3055dcd0fe02d8b47eaf0d5a13e1996de925de59d0ef9b7f7fad4. +// +// Solidity: event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer) +func (_FastBridge *FastBridgeFilterer) WatchBridgeProofDisputed(opts *bind.WatchOpts, sink chan<- *FastBridgeBridgeProofDisputed, transactionId [][32]byte, relayer []common.Address) (event.Subscription, error) { + + var transactionIdRule []interface{} + for _, transactionIdItem := range transactionId { + transactionIdRule = append(transactionIdRule, transactionIdItem) + } + var relayerRule []interface{} + for _, relayerItem := range relayer { + relayerRule = append(relayerRule, relayerItem) + } + + logs, sub, err := _FastBridge.contract.WatchLogs(opts, "BridgeProofDisputed", transactionIdRule, relayerRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(FastBridgeBridgeProofDisputed) + if err := _FastBridge.contract.UnpackLog(event, "BridgeProofDisputed", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseBridgeProofDisputed is a log parse operation binding the contract event 0x0695cf1d39b3055dcd0fe02d8b47eaf0d5a13e1996de925de59d0ef9b7f7fad4. +// +// Solidity: event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer) +func (_FastBridge *FastBridgeFilterer) ParseBridgeProofDisputed(log types.Log) (*FastBridgeBridgeProofDisputed, error) { + event := new(FastBridgeBridgeProofDisputed) + if err := _FastBridge.contract.UnpackLog(event, "BridgeProofDisputed", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// FastBridgeBridgeProofProvidedIterator is returned from FilterBridgeProofProvided and is used to iterate over the raw logs and unpacked data for BridgeProofProvided events raised by the FastBridge contract. +type FastBridgeBridgeProofProvidedIterator struct { + Event *FastBridgeBridgeProofProvided // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *FastBridgeBridgeProofProvidedIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(FastBridgeBridgeProofProvided) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(FastBridgeBridgeProofProvided) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *FastBridgeBridgeProofProvidedIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *FastBridgeBridgeProofProvidedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// FastBridgeBridgeProofProvided represents a BridgeProofProvided event raised by the FastBridge contract. +type FastBridgeBridgeProofProvided struct { + TransactionId [32]byte + Relayer common.Address + TransactionHash [32]byte + Raw types.Log // Blockchain specific contextual infos +} + +// FilterBridgeProofProvided is a free log retrieval operation binding the contract event 0x4ac8af8a2cd87193d64dfc7a3b8d9923b714ec528b18725d080aa1299be0c5e4. +// +// Solidity: event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash) +func (_FastBridge *FastBridgeFilterer) FilterBridgeProofProvided(opts *bind.FilterOpts, transactionId [][32]byte, relayer []common.Address) (*FastBridgeBridgeProofProvidedIterator, error) { + + var transactionIdRule []interface{} + for _, transactionIdItem := range transactionId { + transactionIdRule = append(transactionIdRule, transactionIdItem) + } + var relayerRule []interface{} + for _, relayerItem := range relayer { + relayerRule = append(relayerRule, relayerItem) + } + + logs, sub, err := _FastBridge.contract.FilterLogs(opts, "BridgeProofProvided", transactionIdRule, relayerRule) + if err != nil { + return nil, err + } + return &FastBridgeBridgeProofProvidedIterator{contract: _FastBridge.contract, event: "BridgeProofProvided", logs: logs, sub: sub}, nil +} + +// WatchBridgeProofProvided is a free log subscription operation binding the contract event 0x4ac8af8a2cd87193d64dfc7a3b8d9923b714ec528b18725d080aa1299be0c5e4. +// +// Solidity: event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash) +func (_FastBridge *FastBridgeFilterer) WatchBridgeProofProvided(opts *bind.WatchOpts, sink chan<- *FastBridgeBridgeProofProvided, transactionId [][32]byte, relayer []common.Address) (event.Subscription, error) { + + var transactionIdRule []interface{} + for _, transactionIdItem := range transactionId { + transactionIdRule = append(transactionIdRule, transactionIdItem) + } + var relayerRule []interface{} + for _, relayerItem := range relayer { + relayerRule = append(relayerRule, relayerItem) + } + + logs, sub, err := _FastBridge.contract.WatchLogs(opts, "BridgeProofProvided", transactionIdRule, relayerRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(FastBridgeBridgeProofProvided) + if err := _FastBridge.contract.UnpackLog(event, "BridgeProofProvided", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseBridgeProofProvided is a log parse operation binding the contract event 0x4ac8af8a2cd87193d64dfc7a3b8d9923b714ec528b18725d080aa1299be0c5e4. +// +// Solidity: event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash) +func (_FastBridge *FastBridgeFilterer) ParseBridgeProofProvided(log types.Log) (*FastBridgeBridgeProofProvided, error) { + event := new(FastBridgeBridgeProofProvided) + if err := _FastBridge.contract.UnpackLog(event, "BridgeProofProvided", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// FastBridgeBridgeRelayedIterator is returned from FilterBridgeRelayed and is used to iterate over the raw logs and unpacked data for BridgeRelayed events raised by the FastBridge contract. +type FastBridgeBridgeRelayedIterator struct { + Event *FastBridgeBridgeRelayed // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *FastBridgeBridgeRelayedIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(FastBridgeBridgeRelayed) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(FastBridgeBridgeRelayed) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *FastBridgeBridgeRelayedIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *FastBridgeBridgeRelayedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// FastBridgeBridgeRelayed represents a BridgeRelayed event raised by the FastBridge contract. +type FastBridgeBridgeRelayed struct { + TransactionId [32]byte + Relayer common.Address + To common.Address + OriginChainId uint32 + OriginToken common.Address + DestToken common.Address + OriginAmount *big.Int + DestAmount *big.Int + ChainGasAmount *big.Int + Raw types.Log // Blockchain specific contextual infos +} + +// FilterBridgeRelayed is a free log retrieval operation binding the contract event 0xf8ae392d784b1ea5e8881bfa586d81abf07ef4f1e2fc75f7fe51c90f05199a5c. +// +// Solidity: event BridgeRelayed(bytes32 indexed transactionId, address indexed relayer, address indexed to, uint32 originChainId, address originToken, address destToken, uint256 originAmount, uint256 destAmount, uint256 chainGasAmount) +func (_FastBridge *FastBridgeFilterer) FilterBridgeRelayed(opts *bind.FilterOpts, transactionId [][32]byte, relayer []common.Address, to []common.Address) (*FastBridgeBridgeRelayedIterator, error) { + + var transactionIdRule []interface{} + for _, transactionIdItem := range transactionId { + transactionIdRule = append(transactionIdRule, transactionIdItem) + } + var relayerRule []interface{} + for _, relayerItem := range relayer { + relayerRule = append(relayerRule, relayerItem) + } + var toRule []interface{} + for _, toItem := range to { + toRule = append(toRule, toItem) + } + + logs, sub, err := _FastBridge.contract.FilterLogs(opts, "BridgeRelayed", transactionIdRule, relayerRule, toRule) + if err != nil { + return nil, err + } + return &FastBridgeBridgeRelayedIterator{contract: _FastBridge.contract, event: "BridgeRelayed", logs: logs, sub: sub}, nil +} + +// WatchBridgeRelayed is a free log subscription operation binding the contract event 0xf8ae392d784b1ea5e8881bfa586d81abf07ef4f1e2fc75f7fe51c90f05199a5c. +// +// Solidity: event BridgeRelayed(bytes32 indexed transactionId, address indexed relayer, address indexed to, uint32 originChainId, address originToken, address destToken, uint256 originAmount, uint256 destAmount, uint256 chainGasAmount) +func (_FastBridge *FastBridgeFilterer) WatchBridgeRelayed(opts *bind.WatchOpts, sink chan<- *FastBridgeBridgeRelayed, transactionId [][32]byte, relayer []common.Address, to []common.Address) (event.Subscription, error) { + + var transactionIdRule []interface{} + for _, transactionIdItem := range transactionId { + transactionIdRule = append(transactionIdRule, transactionIdItem) + } + var relayerRule []interface{} + for _, relayerItem := range relayer { + relayerRule = append(relayerRule, relayerItem) + } + var toRule []interface{} + for _, toItem := range to { + toRule = append(toRule, toItem) + } + + logs, sub, err := _FastBridge.contract.WatchLogs(opts, "BridgeRelayed", transactionIdRule, relayerRule, toRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(FastBridgeBridgeRelayed) + if err := _FastBridge.contract.UnpackLog(event, "BridgeRelayed", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseBridgeRelayed is a log parse operation binding the contract event 0xf8ae392d784b1ea5e8881bfa586d81abf07ef4f1e2fc75f7fe51c90f05199a5c. +// +// Solidity: event BridgeRelayed(bytes32 indexed transactionId, address indexed relayer, address indexed to, uint32 originChainId, address originToken, address destToken, uint256 originAmount, uint256 destAmount, uint256 chainGasAmount) +func (_FastBridge *FastBridgeFilterer) ParseBridgeRelayed(log types.Log) (*FastBridgeBridgeRelayed, error) { + event := new(FastBridgeBridgeRelayed) + if err := _FastBridge.contract.UnpackLog(event, "BridgeRelayed", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// FastBridgeBridgeRequestedIterator is returned from FilterBridgeRequested and is used to iterate over the raw logs and unpacked data for BridgeRequested events raised by the FastBridge contract. +type FastBridgeBridgeRequestedIterator struct { + Event *FastBridgeBridgeRequested // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *FastBridgeBridgeRequestedIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(FastBridgeBridgeRequested) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(FastBridgeBridgeRequested) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *FastBridgeBridgeRequestedIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *FastBridgeBridgeRequestedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// FastBridgeBridgeRequested represents a BridgeRequested event raised by the FastBridge contract. +type FastBridgeBridgeRequested struct { + TransactionId [32]byte + Sender common.Address + Request []byte + DestChainId uint32 + OriginToken common.Address + DestToken common.Address + OriginAmount *big.Int + DestAmount *big.Int + SendChainGas bool + Raw types.Log // Blockchain specific contextual infos +} + +// FilterBridgeRequested is a free log retrieval operation binding the contract event 0x120ea0364f36cdac7983bcfdd55270ca09d7f9b314a2ebc425a3b01ab1d6403a. +// +// Solidity: event BridgeRequested(bytes32 indexed transactionId, address indexed sender, bytes request, uint32 destChainId, address originToken, address destToken, uint256 originAmount, uint256 destAmount, bool sendChainGas) +func (_FastBridge *FastBridgeFilterer) FilterBridgeRequested(opts *bind.FilterOpts, transactionId [][32]byte, sender []common.Address) (*FastBridgeBridgeRequestedIterator, error) { + + var transactionIdRule []interface{} + for _, transactionIdItem := range transactionId { + transactionIdRule = append(transactionIdRule, transactionIdItem) + } + var senderRule []interface{} + for _, senderItem := range sender { + senderRule = append(senderRule, senderItem) + } + + logs, sub, err := _FastBridge.contract.FilterLogs(opts, "BridgeRequested", transactionIdRule, senderRule) + if err != nil { + return nil, err + } + return &FastBridgeBridgeRequestedIterator{contract: _FastBridge.contract, event: "BridgeRequested", logs: logs, sub: sub}, nil +} + +// WatchBridgeRequested is a free log subscription operation binding the contract event 0x120ea0364f36cdac7983bcfdd55270ca09d7f9b314a2ebc425a3b01ab1d6403a. +// +// Solidity: event BridgeRequested(bytes32 indexed transactionId, address indexed sender, bytes request, uint32 destChainId, address originToken, address destToken, uint256 originAmount, uint256 destAmount, bool sendChainGas) +func (_FastBridge *FastBridgeFilterer) WatchBridgeRequested(opts *bind.WatchOpts, sink chan<- *FastBridgeBridgeRequested, transactionId [][32]byte, sender []common.Address) (event.Subscription, error) { + + var transactionIdRule []interface{} + for _, transactionIdItem := range transactionId { + transactionIdRule = append(transactionIdRule, transactionIdItem) + } + var senderRule []interface{} + for _, senderItem := range sender { + senderRule = append(senderRule, senderItem) + } + + logs, sub, err := _FastBridge.contract.WatchLogs(opts, "BridgeRequested", transactionIdRule, senderRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(FastBridgeBridgeRequested) + if err := _FastBridge.contract.UnpackLog(event, "BridgeRequested", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseBridgeRequested is a log parse operation binding the contract event 0x120ea0364f36cdac7983bcfdd55270ca09d7f9b314a2ebc425a3b01ab1d6403a. +// +// Solidity: event BridgeRequested(bytes32 indexed transactionId, address indexed sender, bytes request, uint32 destChainId, address originToken, address destToken, uint256 originAmount, uint256 destAmount, bool sendChainGas) +func (_FastBridge *FastBridgeFilterer) ParseBridgeRequested(log types.Log) (*FastBridgeBridgeRequested, error) { + event := new(FastBridgeBridgeRequested) + if err := _FastBridge.contract.UnpackLog(event, "BridgeRequested", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// FastBridgeChainGasAmountUpdatedIterator is returned from FilterChainGasAmountUpdated and is used to iterate over the raw logs and unpacked data for ChainGasAmountUpdated events raised by the FastBridge contract. +type FastBridgeChainGasAmountUpdatedIterator struct { + Event *FastBridgeChainGasAmountUpdated // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *FastBridgeChainGasAmountUpdatedIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(FastBridgeChainGasAmountUpdated) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(FastBridgeChainGasAmountUpdated) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *FastBridgeChainGasAmountUpdatedIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *FastBridgeChainGasAmountUpdatedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// FastBridgeChainGasAmountUpdated represents a ChainGasAmountUpdated event raised by the FastBridge contract. +type FastBridgeChainGasAmountUpdated struct { + OldChainGasAmount *big.Int + NewChainGasAmount *big.Int + Raw types.Log // Blockchain specific contextual infos +} + +// FilterChainGasAmountUpdated is a free log retrieval operation binding the contract event 0x5cf09b12f3f56b4c564d51b25b40360af6d795198adb61ae0806a36c294323fa. +// +// Solidity: event ChainGasAmountUpdated(uint256 oldChainGasAmount, uint256 newChainGasAmount) +func (_FastBridge *FastBridgeFilterer) FilterChainGasAmountUpdated(opts *bind.FilterOpts) (*FastBridgeChainGasAmountUpdatedIterator, error) { + + logs, sub, err := _FastBridge.contract.FilterLogs(opts, "ChainGasAmountUpdated") + if err != nil { + return nil, err + } + return &FastBridgeChainGasAmountUpdatedIterator{contract: _FastBridge.contract, event: "ChainGasAmountUpdated", logs: logs, sub: sub}, nil +} + +// WatchChainGasAmountUpdated is a free log subscription operation binding the contract event 0x5cf09b12f3f56b4c564d51b25b40360af6d795198adb61ae0806a36c294323fa. +// +// Solidity: event ChainGasAmountUpdated(uint256 oldChainGasAmount, uint256 newChainGasAmount) +func (_FastBridge *FastBridgeFilterer) WatchChainGasAmountUpdated(opts *bind.WatchOpts, sink chan<- *FastBridgeChainGasAmountUpdated) (event.Subscription, error) { + + logs, sub, err := _FastBridge.contract.WatchLogs(opts, "ChainGasAmountUpdated") + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(FastBridgeChainGasAmountUpdated) + if err := _FastBridge.contract.UnpackLog(event, "ChainGasAmountUpdated", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseChainGasAmountUpdated is a log parse operation binding the contract event 0x5cf09b12f3f56b4c564d51b25b40360af6d795198adb61ae0806a36c294323fa. +// +// Solidity: event ChainGasAmountUpdated(uint256 oldChainGasAmount, uint256 newChainGasAmount) +func (_FastBridge *FastBridgeFilterer) ParseChainGasAmountUpdated(log types.Log) (*FastBridgeChainGasAmountUpdated, error) { + event := new(FastBridgeChainGasAmountUpdated) + if err := _FastBridge.contract.UnpackLog(event, "ChainGasAmountUpdated", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// FastBridgeFeeRateUpdatedIterator is returned from FilterFeeRateUpdated and is used to iterate over the raw logs and unpacked data for FeeRateUpdated events raised by the FastBridge contract. +type FastBridgeFeeRateUpdatedIterator struct { + Event *FastBridgeFeeRateUpdated // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *FastBridgeFeeRateUpdatedIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(FastBridgeFeeRateUpdated) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(FastBridgeFeeRateUpdated) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *FastBridgeFeeRateUpdatedIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *FastBridgeFeeRateUpdatedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// FastBridgeFeeRateUpdated represents a FeeRateUpdated event raised by the FastBridge contract. +type FastBridgeFeeRateUpdated struct { + OldFeeRate *big.Int + NewFeeRate *big.Int + Raw types.Log // Blockchain specific contextual infos +} + +// FilterFeeRateUpdated is a free log retrieval operation binding the contract event 0x14914da2bf76024616fbe1859783fcd4dbddcb179b1f3a854949fbf920dcb957. +// +// Solidity: event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate) +func (_FastBridge *FastBridgeFilterer) FilterFeeRateUpdated(opts *bind.FilterOpts) (*FastBridgeFeeRateUpdatedIterator, error) { + + logs, sub, err := _FastBridge.contract.FilterLogs(opts, "FeeRateUpdated") + if err != nil { + return nil, err + } + return &FastBridgeFeeRateUpdatedIterator{contract: _FastBridge.contract, event: "FeeRateUpdated", logs: logs, sub: sub}, nil +} + +// WatchFeeRateUpdated is a free log subscription operation binding the contract event 0x14914da2bf76024616fbe1859783fcd4dbddcb179b1f3a854949fbf920dcb957. +// +// Solidity: event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate) +func (_FastBridge *FastBridgeFilterer) WatchFeeRateUpdated(opts *bind.WatchOpts, sink chan<- *FastBridgeFeeRateUpdated) (event.Subscription, error) { + + logs, sub, err := _FastBridge.contract.WatchLogs(opts, "FeeRateUpdated") + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(FastBridgeFeeRateUpdated) + if err := _FastBridge.contract.UnpackLog(event, "FeeRateUpdated", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseFeeRateUpdated is a log parse operation binding the contract event 0x14914da2bf76024616fbe1859783fcd4dbddcb179b1f3a854949fbf920dcb957. +// +// Solidity: event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate) +func (_FastBridge *FastBridgeFilterer) ParseFeeRateUpdated(log types.Log) (*FastBridgeFeeRateUpdated, error) { + event := new(FastBridgeFeeRateUpdated) + if err := _FastBridge.contract.UnpackLog(event, "FeeRateUpdated", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// FastBridgeFeesSweptIterator is returned from FilterFeesSwept and is used to iterate over the raw logs and unpacked data for FeesSwept events raised by the FastBridge contract. +type FastBridgeFeesSweptIterator struct { + Event *FastBridgeFeesSwept // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *FastBridgeFeesSweptIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(FastBridgeFeesSwept) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(FastBridgeFeesSwept) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *FastBridgeFeesSweptIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *FastBridgeFeesSweptIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// FastBridgeFeesSwept represents a FeesSwept event raised by the FastBridge contract. +type FastBridgeFeesSwept struct { + Token common.Address + Recipient common.Address + Amount *big.Int + Raw types.Log // Blockchain specific contextual infos +} + +// FilterFeesSwept is a free log retrieval operation binding the contract event 0x244e51bc38c1452fa8aaf487bcb4bca36c2baa3a5fbdb776b1eabd8dc6d277cd. +// +// Solidity: event FeesSwept(address token, address recipient, uint256 amount) +func (_FastBridge *FastBridgeFilterer) FilterFeesSwept(opts *bind.FilterOpts) (*FastBridgeFeesSweptIterator, error) { + + logs, sub, err := _FastBridge.contract.FilterLogs(opts, "FeesSwept") + if err != nil { + return nil, err + } + return &FastBridgeFeesSweptIterator{contract: _FastBridge.contract, event: "FeesSwept", logs: logs, sub: sub}, nil +} + +// WatchFeesSwept is a free log subscription operation binding the contract event 0x244e51bc38c1452fa8aaf487bcb4bca36c2baa3a5fbdb776b1eabd8dc6d277cd. +// +// Solidity: event FeesSwept(address token, address recipient, uint256 amount) +func (_FastBridge *FastBridgeFilterer) WatchFeesSwept(opts *bind.WatchOpts, sink chan<- *FastBridgeFeesSwept) (event.Subscription, error) { + + logs, sub, err := _FastBridge.contract.WatchLogs(opts, "FeesSwept") + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(FastBridgeFeesSwept) + if err := _FastBridge.contract.UnpackLog(event, "FeesSwept", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseFeesSwept is a log parse operation binding the contract event 0x244e51bc38c1452fa8aaf487bcb4bca36c2baa3a5fbdb776b1eabd8dc6d277cd. +// +// Solidity: event FeesSwept(address token, address recipient, uint256 amount) +func (_FastBridge *FastBridgeFilterer) ParseFeesSwept(log types.Log) (*FastBridgeFeesSwept, error) { + event := new(FastBridgeFeesSwept) + if err := _FastBridge.contract.UnpackLog(event, "FeesSwept", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// FastBridgeRoleAdminChangedIterator is returned from FilterRoleAdminChanged and is used to iterate over the raw logs and unpacked data for RoleAdminChanged events raised by the FastBridge contract. +type FastBridgeRoleAdminChangedIterator struct { + Event *FastBridgeRoleAdminChanged // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *FastBridgeRoleAdminChangedIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(FastBridgeRoleAdminChanged) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(FastBridgeRoleAdminChanged) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *FastBridgeRoleAdminChangedIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *FastBridgeRoleAdminChangedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// FastBridgeRoleAdminChanged represents a RoleAdminChanged event raised by the FastBridge contract. +type FastBridgeRoleAdminChanged struct { + Role [32]byte + PreviousAdminRole [32]byte + NewAdminRole [32]byte + Raw types.Log // Blockchain specific contextual infos +} + +// FilterRoleAdminChanged is a free log retrieval operation binding the contract event 0xbd79b86ffe0ab8e8776151514217cd7cacd52c909f66475c3af44e129f0b00ff. +// +// Solidity: event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole) +func (_FastBridge *FastBridgeFilterer) FilterRoleAdminChanged(opts *bind.FilterOpts, role [][32]byte, previousAdminRole [][32]byte, newAdminRole [][32]byte) (*FastBridgeRoleAdminChangedIterator, error) { + + var roleRule []interface{} + for _, roleItem := range role { + roleRule = append(roleRule, roleItem) + } + var previousAdminRoleRule []interface{} + for _, previousAdminRoleItem := range previousAdminRole { + previousAdminRoleRule = append(previousAdminRoleRule, previousAdminRoleItem) + } + var newAdminRoleRule []interface{} + for _, newAdminRoleItem := range newAdminRole { + newAdminRoleRule = append(newAdminRoleRule, newAdminRoleItem) + } + + logs, sub, err := _FastBridge.contract.FilterLogs(opts, "RoleAdminChanged", roleRule, previousAdminRoleRule, newAdminRoleRule) + if err != nil { + return nil, err + } + return &FastBridgeRoleAdminChangedIterator{contract: _FastBridge.contract, event: "RoleAdminChanged", logs: logs, sub: sub}, nil +} + +// WatchRoleAdminChanged is a free log subscription operation binding the contract event 0xbd79b86ffe0ab8e8776151514217cd7cacd52c909f66475c3af44e129f0b00ff. +// +// Solidity: event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole) +func (_FastBridge *FastBridgeFilterer) WatchRoleAdminChanged(opts *bind.WatchOpts, sink chan<- *FastBridgeRoleAdminChanged, role [][32]byte, previousAdminRole [][32]byte, newAdminRole [][32]byte) (event.Subscription, error) { + + var roleRule []interface{} + for _, roleItem := range role { + roleRule = append(roleRule, roleItem) + } + var previousAdminRoleRule []interface{} + for _, previousAdminRoleItem := range previousAdminRole { + previousAdminRoleRule = append(previousAdminRoleRule, previousAdminRoleItem) + } + var newAdminRoleRule []interface{} + for _, newAdminRoleItem := range newAdminRole { + newAdminRoleRule = append(newAdminRoleRule, newAdminRoleItem) + } + + logs, sub, err := _FastBridge.contract.WatchLogs(opts, "RoleAdminChanged", roleRule, previousAdminRoleRule, newAdminRoleRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(FastBridgeRoleAdminChanged) + if err := _FastBridge.contract.UnpackLog(event, "RoleAdminChanged", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseRoleAdminChanged is a log parse operation binding the contract event 0xbd79b86ffe0ab8e8776151514217cd7cacd52c909f66475c3af44e129f0b00ff. +// +// Solidity: event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole) +func (_FastBridge *FastBridgeFilterer) ParseRoleAdminChanged(log types.Log) (*FastBridgeRoleAdminChanged, error) { + event := new(FastBridgeRoleAdminChanged) + if err := _FastBridge.contract.UnpackLog(event, "RoleAdminChanged", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// FastBridgeRoleGrantedIterator is returned from FilterRoleGranted and is used to iterate over the raw logs and unpacked data for RoleGranted events raised by the FastBridge contract. +type FastBridgeRoleGrantedIterator struct { + Event *FastBridgeRoleGranted // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *FastBridgeRoleGrantedIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(FastBridgeRoleGranted) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(FastBridgeRoleGranted) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *FastBridgeRoleGrantedIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *FastBridgeRoleGrantedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// FastBridgeRoleGranted represents a RoleGranted event raised by the FastBridge contract. +type FastBridgeRoleGranted struct { + Role [32]byte + Account common.Address + Sender common.Address + Raw types.Log // Blockchain specific contextual infos +} + +// FilterRoleGranted is a free log retrieval operation binding the contract event 0x2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d. +// +// Solidity: event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender) +func (_FastBridge *FastBridgeFilterer) FilterRoleGranted(opts *bind.FilterOpts, role [][32]byte, account []common.Address, sender []common.Address) (*FastBridgeRoleGrantedIterator, error) { + + var roleRule []interface{} + for _, roleItem := range role { + roleRule = append(roleRule, roleItem) + } + var accountRule []interface{} + for _, accountItem := range account { + accountRule = append(accountRule, accountItem) + } + var senderRule []interface{} + for _, senderItem := range sender { + senderRule = append(senderRule, senderItem) + } + + logs, sub, err := _FastBridge.contract.FilterLogs(opts, "RoleGranted", roleRule, accountRule, senderRule) + if err != nil { + return nil, err + } + return &FastBridgeRoleGrantedIterator{contract: _FastBridge.contract, event: "RoleGranted", logs: logs, sub: sub}, nil +} + +// WatchRoleGranted is a free log subscription operation binding the contract event 0x2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d. +// +// Solidity: event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender) +func (_FastBridge *FastBridgeFilterer) WatchRoleGranted(opts *bind.WatchOpts, sink chan<- *FastBridgeRoleGranted, role [][32]byte, account []common.Address, sender []common.Address) (event.Subscription, error) { + + var roleRule []interface{} + for _, roleItem := range role { + roleRule = append(roleRule, roleItem) + } + var accountRule []interface{} + for _, accountItem := range account { + accountRule = append(accountRule, accountItem) + } + var senderRule []interface{} + for _, senderItem := range sender { + senderRule = append(senderRule, senderItem) + } + + logs, sub, err := _FastBridge.contract.WatchLogs(opts, "RoleGranted", roleRule, accountRule, senderRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(FastBridgeRoleGranted) + if err := _FastBridge.contract.UnpackLog(event, "RoleGranted", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseRoleGranted is a log parse operation binding the contract event 0x2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d. +// +// Solidity: event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender) +func (_FastBridge *FastBridgeFilterer) ParseRoleGranted(log types.Log) (*FastBridgeRoleGranted, error) { + event := new(FastBridgeRoleGranted) + if err := _FastBridge.contract.UnpackLog(event, "RoleGranted", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// FastBridgeRoleRevokedIterator is returned from FilterRoleRevoked and is used to iterate over the raw logs and unpacked data for RoleRevoked events raised by the FastBridge contract. +type FastBridgeRoleRevokedIterator struct { + Event *FastBridgeRoleRevoked // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *FastBridgeRoleRevokedIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(FastBridgeRoleRevoked) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(FastBridgeRoleRevoked) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *FastBridgeRoleRevokedIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *FastBridgeRoleRevokedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// FastBridgeRoleRevoked represents a RoleRevoked event raised by the FastBridge contract. +type FastBridgeRoleRevoked struct { + Role [32]byte + Account common.Address + Sender common.Address + Raw types.Log // Blockchain specific contextual infos +} + +// FilterRoleRevoked is a free log retrieval operation binding the contract event 0xf6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b. +// +// Solidity: event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender) +func (_FastBridge *FastBridgeFilterer) FilterRoleRevoked(opts *bind.FilterOpts, role [][32]byte, account []common.Address, sender []common.Address) (*FastBridgeRoleRevokedIterator, error) { + + var roleRule []interface{} + for _, roleItem := range role { + roleRule = append(roleRule, roleItem) + } + var accountRule []interface{} + for _, accountItem := range account { + accountRule = append(accountRule, accountItem) + } + var senderRule []interface{} + for _, senderItem := range sender { + senderRule = append(senderRule, senderItem) + } + + logs, sub, err := _FastBridge.contract.FilterLogs(opts, "RoleRevoked", roleRule, accountRule, senderRule) + if err != nil { + return nil, err + } + return &FastBridgeRoleRevokedIterator{contract: _FastBridge.contract, event: "RoleRevoked", logs: logs, sub: sub}, nil +} + +// WatchRoleRevoked is a free log subscription operation binding the contract event 0xf6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b. +// +// Solidity: event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender) +func (_FastBridge *FastBridgeFilterer) WatchRoleRevoked(opts *bind.WatchOpts, sink chan<- *FastBridgeRoleRevoked, role [][32]byte, account []common.Address, sender []common.Address) (event.Subscription, error) { + + var roleRule []interface{} + for _, roleItem := range role { + roleRule = append(roleRule, roleItem) + } + var accountRule []interface{} + for _, accountItem := range account { + accountRule = append(accountRule, accountItem) + } + var senderRule []interface{} + for _, senderItem := range sender { + senderRule = append(senderRule, senderItem) + } + + logs, sub, err := _FastBridge.contract.WatchLogs(opts, "RoleRevoked", roleRule, accountRule, senderRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(FastBridgeRoleRevoked) + if err := _FastBridge.contract.UnpackLog(event, "RoleRevoked", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseRoleRevoked is a log parse operation binding the contract event 0xf6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b. +// +// Solidity: event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender) +func (_FastBridge *FastBridgeFilterer) ParseRoleRevoked(log types.Log) (*FastBridgeRoleRevoked, error) { + event := new(FastBridgeRoleRevoked) + if err := _FastBridge.contract.UnpackLog(event, "RoleRevoked", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// FastBridgeMockMetaData contains all meta data concerning the FastBridgeMock contract. +var FastBridgeMockMetaData = &bind.MetaData{ + ABI: "[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_owner\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"AccessControlBadConfirmation\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"neededRole\",\"type\":\"bytes32\"}],\"name\":\"AccessControlUnauthorizedAccount\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"}],\"name\":\"AddressEmptyCode\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"AddressInsufficientBalance\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"FailedInnerCall\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"}],\"name\":\"SafeERC20FailedOperation\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"BridgeDepositClaimed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"BridgeDepositRefunded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"name\":\"BridgeProofDisputed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"transactionHash\",\"type\":\"bytes32\"}],\"name\":\"BridgeProofProvided\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"originChainId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"chainGasAmount\",\"type\":\"uint256\"}],\"name\":\"BridgeRelayed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"destChainId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"sendChainGas\",\"type\":\"bool\"}],\"name\":\"BridgeRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"oldChainGasAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newChainGasAmount\",\"type\":\"uint256\"}],\"name\":\"ChainGasAmountUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"oldFeeRate\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newFeeRate\",\"type\":\"uint256\"}],\"name\":\"FeeRateUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"FeesSwept\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"previousAdminRole\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"newAdminRole\",\"type\":\"bytes32\"}],\"name\":\"RoleAdminChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleGranted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleRevoked\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"DEFAULT_ADMIN_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"FEE_BPS\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"FEE_RATE_MAX\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"GOVERNOR_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"GUARD_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"REFUNDER_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"RELAYER_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"dstChainId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"sendChainGas\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"}],\"internalType\":\"structIFastBridge.BridgeParams\",\"name\":\"params\",\"type\":\"tuple\"}],\"name\":\"bridge\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionid\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"name\":\"canClaim\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"chainGasAmount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"claim\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"deployBlock\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"}],\"name\":\"dispute\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"getBridgeTransaction\",\"outputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"originChainId\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"destChainId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"originSender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destRecipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"originFeeAmount\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"sendChainGas\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"}],\"internalType\":\"structIFastBridge.BridgeTransaction\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"enumFastBridge.BridgeStatus\",\"name\":\"keyValue\",\"type\":\"uint8\"}],\"name\":\"getEnumKeyByValue\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"}],\"name\":\"getRoleAdmin\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"index\",\"type\":\"uint256\"}],\"name\":\"getRoleMember\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"}],\"name\":\"getRoleMemberCount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"grantRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"hasRole\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"uint32\",\"name\":\"originChainId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"chainGasAmount\",\"type\":\"uint256\"}],\"name\":\"mockBridgeRelayer\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"components\":[{\"internalType\":\"uint32\",\"name\":\"dstChainId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"sendChainGas\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"}],\"internalType\":\"structIFastBridge.BridgeParams\",\"name\":\"params\",\"type\":\"tuple\"}],\"name\":\"mockBridgeRequest\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"mockBridgeRequestRaw\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"nonce\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"protocolFeeRate\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"protocolFees\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"},{\"internalType\":\"bytes32\",\"name\":\"destTxHash\",\"type\":\"bytes32\"}],\"name\":\"prove\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"refund\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"relay\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"callerConfirmation\",\"type\":\"address\"}],\"name\":\"renounceRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"revokeRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"newChainGasAmount\",\"type\":\"uint256\"}],\"name\":\"setChainGasAmount\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"newFeeRate\",\"type\":\"uint256\"}],\"name\":\"setProtocolFeeRate\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes4\",\"name\":\"interfaceId\",\"type\":\"bytes4\"}],\"name\":\"supportsInterface\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"}],\"name\":\"sweepProtocolFees\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", + Sigs: map[string]string{ + "a217fddf": "DEFAULT_ADMIN_ROLE()", + "bf333f2c": "FEE_BPS()", + "0f5f6ed7": "FEE_RATE_MAX()", + "ccc57490": "GOVERNOR_ROLE()", + "03ed0ee5": "GUARD_ROLE()", + "5960ccf2": "REFUNDER_ROLE()", + "926d7d7f": "RELAYER_ROLE()", + "45851694": "bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256))", + "aa9641ab": "canClaim(bytes32,address)", + "e00a83e0": "chainGasAmount()", + "41fcb612": "claim(bytes,address)", + "a3ec191a": "deployBlock()", + "add98c70": "dispute(bytes32)", + "ac11fb1a": "getBridgeTransaction(bytes)", + "85ad903d": "getEnumKeyByValue(uint8)", + "248a9ca3": "getRoleAdmin(bytes32)", + "9010d07c": "getRoleMember(bytes32,uint256)", + "ca15c873": "getRoleMemberCount(bytes32)", + "2f2ff15d": "grantRole(bytes32,address)", + "91d14854": "hasRole(bytes32,address)", + "c72870cc": "mockBridgeRelayer(bytes32,address,address,uint32,address,address,uint256,uint256,uint256)", + "acaebbf1": "mockBridgeRequest(bytes32,address,(uint32,address,address,address,address,uint256,uint256,bool,uint256))", + "aedf009d": "mockBridgeRequestRaw(bytes32,address,bytes)", + "affed0e0": "nonce()", + "58f85880": "protocolFeeRate()", + "dcf844a7": "protocolFees(address)", + "886d36ff": "prove(bytes,bytes32)", + "5eb7d946": "refund(bytes)", + "8f0d6f17": "relay(bytes)", + "36568abe": "renounceRole(bytes32,address)", + "d547741f": "revokeRole(bytes32,address)", + "b250fe6b": "setChainGasAmount(uint256)", + "b13aa2d6": "setProtocolFeeRate(uint256)", + "01ffc9a7": "supportsInterface(bytes4)", + "06f333f2": "sweepProtocolFees(address,address)", + }, + Bin: "0x60a06040523480156200001157600080fd5b506040516200254e3803806200254e833981016040819052620000349162000194565b80620000426000826200004f565b50504360805250620001bf565b6000806200005e84846200008c565b90508015620000835760008481526001602052604090206200008190846200013a565b505b90505b92915050565b6000828152602081815260408083206001600160a01b038516845290915281205460ff1662000131576000838152602081815260408083206001600160a01b03861684529091529020805460ff19166001179055620000e83390565b6001600160a01b0316826001600160a01b0316847f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a450600162000086565b50600062000086565b600062000083836001600160a01b0384166000818152600183016020526040812054620001315750815460018181018455600084815260208082209093018490558454848252828601909352604090209190915562000086565b600060208284031215620001a757600080fd5b81516001600160a01b03811681146200008357600080fd5b608051612373620001db600039600061053201526123736000f3fe6080604052600436106102345760003560e01c8063926d7d7f11610138578063b13aa2d6116100b0578063ca15c8731161007f578063d547741f11610064578063d547741f146106dd578063dcf844a7146106fd578063e00a83e01461072a57600080fd5b8063ca15c87314610689578063ccc57490146106a957600080fd5b8063b13aa2d614610612578063b250fe6b14610632578063bf333f2c14610652578063c72870cc1461066957600080fd5b8063ac11fb1a11610107578063add98c70116100ec578063add98c70146105c1578063aedf009d146105dc578063affed0e0146105fc57600080fd5b8063ac11fb1a14610574578063acaebbf1146105a157600080fd5b8063926d7d7f146104d7578063a217fddf1461050b578063a3ec191a14610520578063aa9641ab1461055457600080fd5b806345851694116101cb57806385ad903d1161019a5780638f0d6f171161017f5780638f0d6f17146104335780639010d07c1461044157806391d148541461048657600080fd5b806385ad903d146103eb578063886d36ff1461041857600080fd5b8063458516941461037857806358f85880146103865780635960ccf21461039c5780635eb7d946146103d057600080fd5b8063248a9ca311610207578063248a9ca3146102e85780632f2ff15d1461031857806336568abe1461033857806341fcb6121461035857600080fd5b806301ffc9a71461023957806303ed0ee51461026e57806306f333f2146102b05780630f5f6ed7146102d2575b600080fd5b34801561024557600080fd5b5061025961025436600461195d565b610740565b60405190151581526020015b60405180910390f35b34801561027a57600080fd5b506102a27f043c983c49d46f0e102151eaf8085d4a2e6571d5df2d47b013f39bddfd4a639d81565b604051908152602001610265565b3480156102bc57600080fd5b506102d06102cb3660046119d1565b61079c565b005b3480156102de57600080fd5b506102a261271081565b3480156102f457600080fd5b506102a2610303366004611a0a565b60009081526020819052604090206001015490565b34801561032457600080fd5b506102d0610333366004611a23565b61088a565b34801561034457600080fd5b506102d0610353366004611a23565b6108b5565b34801561036457600080fd5b506102d0610373366004611b70565b61090e565b6102d0610373366004611c90565b34801561039257600080fd5b506102a260025481565b3480156103a857600080fd5b506102a27fdb9556138406326f00296e13ea2ad7db24ba82381212d816b1a40c23b466b32781565b3480156103dc57600080fd5b506102d0610373366004611cad565b3480156103f757600080fd5b5061040b610406366004611cea565b610975565b6040516102659190611d79565b34801561042457600080fd5b506102d0610373366004611d8c565b6102d0610373366004611cad565b34801561044d57600080fd5b5061046161045c366004611dd1565b610b25565b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610265565b34801561049257600080fd5b506102596104a1366004611a23565b60009182526020828152604080842073ffffffffffffffffffffffffffffffffffffffff93909316845291905290205460ff1690565b3480156104e357600080fd5b506102a27fe2b7fb3b832174769106daebcfd6d1970523240dda11281102db9363b83b0dc481565b34801561051757600080fd5b506102a2600081565b34801561052c57600080fd5b506102a27f000000000000000000000000000000000000000000000000000000000000000081565b34801561056057600080fd5b5061025961056f366004611a23565b610b44565b34801561058057600080fd5b5061059461058f366004611cad565b610ba9565b6040516102659190611df3565b3480156105ad57600080fd5b506102d06105bc366004611f0d565b610c1c565b3480156105cd57600080fd5b506102d0610373366004611a0a565b3480156105e857600080fd5b506102d06105f7366004611f4d565b610dec565b34801561060857600080fd5b506102a260055481565b34801561061e57600080fd5b506102d061062d366004611a0a565b610e77565b34801561063e57600080fd5b506102d061064d366004611a0a565b610f54565b34801561065e57600080fd5b506102a2620f424081565b34801561067557600080fd5b506102d0610684366004611fa6565b610fbc565b34801561069557600080fd5b506102a26106a4366004611a0a565b611042565b3480156106b557600080fd5b506102a27f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f5581565b3480156106e957600080fd5b506102d06106f8366004611a23565b611059565b34801561070957600080fd5b506102a261071836600461203e565b60036020526000908152604090205481565b34801561073657600080fd5b506102a260045481565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f5a05180f00000000000000000000000000000000000000000000000000000000148061079657506107968261107e565b92915050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f556107c681611115565b73ffffffffffffffffffffffffffffffffffffffff8316600090815260036020526040812054908190036107fa5750505050565b73ffffffffffffffffffffffffffffffffffffffff841660008181526003602052604081205561082b908483611122565b6040805173ffffffffffffffffffffffffffffffffffffffff8087168252851660208201529081018290527f244e51bc38c1452fa8aaf487bcb4bca36c2baa3a5fbdb776b1eabd8dc6d277cd9060600160405180910390a1505b505050565b6000828152602081905260409020600101546108a581611115565b6108af8383611279565b50505050565b73ffffffffffffffffffffffffffffffffffffffff81163314610904576040517f6697b23200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61088582826112ae565b6040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f6e6f7420696d706c656d656e746564000000000000000000000000000000000060448201526064015b60405180910390fd5b60608160048111156109895761098961205b565b6000036109c957505060408051808201909152600481527f4e554c4c00000000000000000000000000000000000000000000000000000000602082015290565b8160048111156109db576109db61205b565b600103610a1b57505060408051808201909152600981527f5245515545535445440000000000000000000000000000000000000000000000602082015290565b816004811115610a2d57610a2d61205b565b600203610a6d57505060408051808201909152600e81527f52454c415945525f50524f564544000000000000000000000000000000000000602082015290565b816004811115610a7f57610a7f61205b565b600303610abf57505060408051808201909152600f81527f52454c415945525f434c41494d45440000000000000000000000000000000000602082015290565b816004811115610ad157610ad161205b565b600403610b1157505060408051808201909152600881527f524546554e444544000000000000000000000000000000000000000000000000602082015290565b505060408051602081019091526000815290565b6000828152600160205260408120610b3d90836112db565b9392505050565b6040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f6e6f7420696d706c656d656e7465640000000000000000000000000000000000604482015260009060640161096c565b604080516101808101825260008082526020808301829052928201819052606082018190526080820181905260a0820181905260c0820181905260e082018190526101008201819052610120820181905261014082018190526101608201528251909161079691840181019084016120ab565b6000620f42406002548360a00151610c3491906121a6565b610c3e91906121bd565b9050808260a001818151610c5291906121f8565b9150818152505060006040518061018001604052804663ffffffff168152602001846000015163ffffffff168152602001846020015173ffffffffffffffffffffffffffffffffffffffff168152602001846040015173ffffffffffffffffffffffffffffffffffffffff168152602001846060015173ffffffffffffffffffffffffffffffffffffffff168152602001846080015173ffffffffffffffffffffffffffffffffffffffff1681526020018460a0015181526020018460c0015181526020018381526020018460e0015115158152602001846101000151815260200160056000815480929190610d479061220b565b909155509052604051610d5d9190602001611df3565b6040516020818303038152906040529050826020015173ffffffffffffffffffffffffffffffffffffffff16857f120ea0364f36cdac7983bcfdd55270ca09d7f9b314a2ebc425a3b01ab1d6403a838660000151876060015188608001518960a001518a60c001518b60e00151604051610ddd9796959493929190612243565b60405180910390a35050505050565b6000610df782610ba9565b9050806040015173ffffffffffffffffffffffffffffffffffffffff16847f120ea0364f36cdac7983bcfdd55270ca09d7f9b314a2ebc425a3b01ab1d6403a84846020015185608001518660a001518760c001518860e00151896101200151604051610e699796959493929190612243565b60405180910390a350505050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f55610ea181611115565b612710821115610f0d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f6e657746656552617465203e206d617800000000000000000000000000000000604482015260640161096c565b600280549083905560408051828152602081018590527f14914da2bf76024616fbe1859783fcd4dbddcb179b1f3a854949fbf920dcb95791015b60405180910390a1505050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f55610f7e81611115565b600480549083905560408051828152602081018590527f5cf09b12f3f56b4c564d51b25b40360af6d795198adb61ae0806a36c294323fa9101610f47565b6040805163ffffffff8816815273ffffffffffffffffffffffffffffffffffffffff878116602083015286811682840152606082018690526080820185905260a082018490529151898316928b16918c917ff8ae392d784b1ea5e8881bfa586d81abf07ef4f1e2fc75f7fe51c90f05199a5c9181900360c00190a4505050505050505050565b6000818152600160205260408120610796906112e7565b60008281526020819052604090206001015461107481611115565b6108af83836112ae565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f7965db0b00000000000000000000000000000000000000000000000000000000148061079657507f01ffc9a7000000000000000000000000000000000000000000000000000000007fffffffff00000000000000000000000000000000000000000000000000000000831614610796565b61111f81336112f1565b50565b3073ffffffffffffffffffffffffffffffffffffffff83160361114457505050565b8060000361115157505050565b7fffffffffffffffffffffffff111111111111111111111111111111111111111273ffffffffffffffffffffffffffffffffffffffff8416016112585760008273ffffffffffffffffffffffffffffffffffffffff168260405160006040518083038185875af1925050503d80600081146111e8576040519150601f19603f3d011682016040523d82523d6000602084013e6111ed565b606091505b50509050806108af576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f455448207472616e73666572206661696c656400000000000000000000000000604482015260640161096c565b61088573ffffffffffffffffffffffffffffffffffffffff8416838361137b565b6000806112868484611408565b90508015610b3d5760008481526001602052604090206112a69084611504565b509392505050565b6000806112bb8484611526565b90508015610b3d5760008481526001602052604090206112a690846115e1565b6000610b3d8383611603565b6000610796825490565b60008281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915290205460ff16611377576040517fe2517d3f00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff821660048201526024810183905260440161096c565b5050565b6040805173ffffffffffffffffffffffffffffffffffffffff8416602482015260448082018490528251808303909101815260649091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fa9059cbb0000000000000000000000000000000000000000000000000000000017905261088590849061162d565b60008281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915281205460ff166114fc5760008381526020818152604080832073ffffffffffffffffffffffffffffffffffffffff86168452909152902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016600117905561149a3390565b73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16847f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a4506001610796565b506000610796565b6000610b3d8373ffffffffffffffffffffffffffffffffffffffff84166116c3565b60008281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915281205460ff16156114fc5760008381526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8616808552925280832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016905551339286917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a4506001610796565b6000610b3d8373ffffffffffffffffffffffffffffffffffffffff841661170a565b600082600001828154811061161a5761161a6122a6565b9060005260206000200154905092915050565b600061164f73ffffffffffffffffffffffffffffffffffffffff8416836117fd565b9050805160001415801561167457508080602001905181019061167291906122d5565b155b15610885576040517f5274afe700000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8416600482015260240161096c565b60008181526001830160205260408120546114fc57508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155610796565b600081815260018301602052604081205480156117f357600061172e6001836121f8565b8554909150600090611742906001906121f8565b90508082146117a7576000866000018281548110611762576117626122a6565b9060005260206000200154905080876000018481548110611785576117856122a6565b6000918252602080832090910192909255918252600188019052604090208390555b85548690806117b8576117b86122f2565b600190038181906000526020600020016000905590558560010160008681526020019081526020016000206000905560019350505050610796565b6000915050610796565b6060610b3d83836000846000808573ffffffffffffffffffffffffffffffffffffffff1684866040516118309190612321565b60006040518083038185875af1925050503d806000811461186d576040519150601f19603f3d011682016040523d82523d6000602084013e611872565b606091505b509150915061188286838361188c565b9695505050505050565b6060826118a15761189c8261191b565b610b3d565b81511580156118c5575073ffffffffffffffffffffffffffffffffffffffff84163b155b15611914576040517f9996b31500000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8516600482015260240161096c565b5080610b3d565b80511561192b5780518082602001fd5b6040517f1425ea4200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006020828403121561196f57600080fd5b81357fffffffff0000000000000000000000000000000000000000000000000000000081168114610b3d57600080fd5b73ffffffffffffffffffffffffffffffffffffffff8116811461111f57600080fd5b80356119cc8161199f565b919050565b600080604083850312156119e457600080fd5b82356119ef8161199f565b915060208301356119ff8161199f565b809150509250929050565b600060208284031215611a1c57600080fd5b5035919050565b60008060408385031215611a3657600080fd5b8235915060208301356119ff8161199f565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051610120810167ffffffffffffffff81118282101715611a9b57611a9b611a48565b60405290565b604051610180810167ffffffffffffffff81118282101715611a9b57611a9b611a48565b600082601f830112611ad657600080fd5b813567ffffffffffffffff80821115611af157611af1611a48565b604051601f83017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f01168101908282118183101715611b3757611b37611a48565b81604052838152866020858801011115611b5057600080fd5b836020870160208301376000602085830101528094505050505092915050565b60008060408385031215611b8357600080fd5b823567ffffffffffffffff811115611b9a57600080fd5b611ba685828601611ac5565b92505060208301356119ff8161199f565b63ffffffff8116811461111f57600080fd5b80356119cc81611bb7565b801515811461111f57600080fd5b80356119cc81611bd4565b60006101208284031215611c0057600080fd5b611c08611a77565b9050611c1382611bc9565b8152611c21602083016119c1565b6020820152611c32604083016119c1565b6040820152611c43606083016119c1565b6060820152611c54608083016119c1565b608082015260a082013560a082015260c082013560c0820152611c7960e08301611be2565b60e082015261010080830135818301525092915050565b60006101208284031215611ca357600080fd5b610b3d8383611bed565b600060208284031215611cbf57600080fd5b813567ffffffffffffffff811115611cd657600080fd5b611ce284828501611ac5565b949350505050565b600060208284031215611cfc57600080fd5b813560058110610b3d57600080fd5b60005b83811015611d26578181015183820152602001611d0e565b50506000910152565b60008151808452611d47816020860160208601611d0b565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b602081526000610b3d6020830184611d2f565b60008060408385031215611d9f57600080fd5b823567ffffffffffffffff811115611db657600080fd5b611dc285828601611ac5565b95602094909401359450505050565b60008060408385031215611de457600080fd5b50508035926020909101359150565b815163ffffffff16815261018081016020830151611e19602084018263ffffffff169052565b506040830151611e41604084018273ffffffffffffffffffffffffffffffffffffffff169052565b506060830151611e69606084018273ffffffffffffffffffffffffffffffffffffffff169052565b506080830151611e91608084018273ffffffffffffffffffffffffffffffffffffffff169052565b5060a0830151611eb960a084018273ffffffffffffffffffffffffffffffffffffffff169052565b5060c083015160c083015260e083015160e083015261010080840151818401525061012080840151611eee8285018215159052565b5050610140838101519083015261016092830151929091019190915290565b60008060006101608486031215611f2357600080fd5b833592506020840135611f358161199f565b9150611f448560408601611bed565b90509250925092565b600080600060608486031215611f6257600080fd5b833592506020840135611f748161199f565b9150604084013567ffffffffffffffff811115611f9057600080fd5b611f9c86828701611ac5565b9150509250925092565b60008060008060008060008060006101208a8c031215611fc557600080fd5b8935985060208a0135611fd78161199f565b975060408a0135611fe78161199f565b965060608a0135611ff781611bb7565b955060808a01356120078161199f565b945060a08a01356120178161199f565b8094505060c08a0135925060e08a013591506101008a013590509295985092959850929598565b60006020828403121561205057600080fd5b8135610b3d8161199f565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b80516119cc81611bb7565b80516119cc8161199f565b80516119cc81611bd4565b600061018082840312156120be57600080fd5b6120c6611aa1565b6120cf8361208a565b81526120dd6020840161208a565b60208201526120ee60408401612095565b60408201526120ff60608401612095565b606082015261211060808401612095565b608082015261212160a08401612095565b60a082015260c083015160c082015260e083015160e08201526101008084015181830152506101206121548185016120a0565b908201526101408381015190820152610160928301519281019290925250919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b808202811582820484141761079657610796612177565b6000826121f3577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b8181038181111561079657610796612177565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820361223c5761223c612177565b5060010190565b60e08152600061225660e083018a611d2f565b63ffffffff9890981660208301525073ffffffffffffffffffffffffffffffffffffffff9586166040820152939094166060840152608083019190915260a082015290151560c090910152919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b6000602082840312156122e757600080fd5b8151610b3d81611bd4565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fd5b60008251612333818460208701611d0b565b919091019291505056fea2646970667358221220b683b83c62d39501bf0f8c7280114538e17cdaba91a577c85b1d7b2b6a51230c64736f6c63430008140033", +} + +// FastBridgeMockABI is the input ABI used to generate the binding from. +// Deprecated: Use FastBridgeMockMetaData.ABI instead. +var FastBridgeMockABI = FastBridgeMockMetaData.ABI + +// Deprecated: Use FastBridgeMockMetaData.Sigs instead. +// FastBridgeMockFuncSigs maps the 4-byte function signature to its string representation. +var FastBridgeMockFuncSigs = FastBridgeMockMetaData.Sigs + +// FastBridgeMockBin is the compiled bytecode used for deploying new contracts. +// Deprecated: Use FastBridgeMockMetaData.Bin instead. +var FastBridgeMockBin = FastBridgeMockMetaData.Bin + +// DeployFastBridgeMock deploys a new Ethereum contract, binding an instance of FastBridgeMock to it. +func DeployFastBridgeMock(auth *bind.TransactOpts, backend bind.ContractBackend, _owner common.Address) (common.Address, *types.Transaction, *FastBridgeMock, error) { + parsed, err := FastBridgeMockMetaData.GetAbi() + if err != nil { + return common.Address{}, nil, nil, err + } + if parsed == nil { + return common.Address{}, nil, nil, errors.New("GetABI returned nil") + } + + address, tx, contract, err := bind.DeployContract(auth, *parsed, common.FromHex(FastBridgeMockBin), backend, _owner) + if err != nil { + return common.Address{}, nil, nil, err + } + return address, tx, &FastBridgeMock{FastBridgeMockCaller: FastBridgeMockCaller{contract: contract}, FastBridgeMockTransactor: FastBridgeMockTransactor{contract: contract}, FastBridgeMockFilterer: FastBridgeMockFilterer{contract: contract}}, nil +} + +// FastBridgeMock is an auto generated Go binding around an Ethereum contract. +type FastBridgeMock struct { + FastBridgeMockCaller // Read-only binding to the contract + FastBridgeMockTransactor // Write-only binding to the contract + FastBridgeMockFilterer // Log filterer for contract events +} + +// FastBridgeMockCaller is an auto generated read-only Go binding around an Ethereum contract. +type FastBridgeMockCaller struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// FastBridgeMockTransactor is an auto generated write-only Go binding around an Ethereum contract. +type FastBridgeMockTransactor struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// FastBridgeMockFilterer is an auto generated log filtering Go binding around an Ethereum contract events. +type FastBridgeMockFilterer struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// FastBridgeMockSession is an auto generated Go binding around an Ethereum contract, +// with pre-set call and transact options. +type FastBridgeMockSession struct { + Contract *FastBridgeMock // Generic contract binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// FastBridgeMockCallerSession is an auto generated read-only Go binding around an Ethereum contract, +// with pre-set call options. +type FastBridgeMockCallerSession struct { + Contract *FastBridgeMockCaller // Generic contract caller binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session +} + +// FastBridgeMockTransactorSession is an auto generated write-only Go binding around an Ethereum contract, +// with pre-set transact options. +type FastBridgeMockTransactorSession struct { + Contract *FastBridgeMockTransactor // Generic contract transactor binding to set the session for + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// FastBridgeMockRaw is an auto generated low-level Go binding around an Ethereum contract. +type FastBridgeMockRaw struct { + Contract *FastBridgeMock // Generic contract binding to access the raw methods on +} + +// FastBridgeMockCallerRaw is an auto generated low-level read-only Go binding around an Ethereum contract. +type FastBridgeMockCallerRaw struct { + Contract *FastBridgeMockCaller // Generic read-only contract binding to access the raw methods on +} + +// FastBridgeMockTransactorRaw is an auto generated low-level write-only Go binding around an Ethereum contract. +type FastBridgeMockTransactorRaw struct { + Contract *FastBridgeMockTransactor // Generic write-only contract binding to access the raw methods on +} + +// NewFastBridgeMock creates a new instance of FastBridgeMock, bound to a specific deployed contract. +func NewFastBridgeMock(address common.Address, backend bind.ContractBackend) (*FastBridgeMock, error) { + contract, err := bindFastBridgeMock(address, backend, backend, backend) + if err != nil { + return nil, err + } + return &FastBridgeMock{FastBridgeMockCaller: FastBridgeMockCaller{contract: contract}, FastBridgeMockTransactor: FastBridgeMockTransactor{contract: contract}, FastBridgeMockFilterer: FastBridgeMockFilterer{contract: contract}}, nil +} + +// NewFastBridgeMockCaller creates a new read-only instance of FastBridgeMock, bound to a specific deployed contract. +func NewFastBridgeMockCaller(address common.Address, caller bind.ContractCaller) (*FastBridgeMockCaller, error) { + contract, err := bindFastBridgeMock(address, caller, nil, nil) + if err != nil { + return nil, err + } + return &FastBridgeMockCaller{contract: contract}, nil +} + +// NewFastBridgeMockTransactor creates a new write-only instance of FastBridgeMock, bound to a specific deployed contract. +func NewFastBridgeMockTransactor(address common.Address, transactor bind.ContractTransactor) (*FastBridgeMockTransactor, error) { + contract, err := bindFastBridgeMock(address, nil, transactor, nil) + if err != nil { + return nil, err + } + return &FastBridgeMockTransactor{contract: contract}, nil +} + +// NewFastBridgeMockFilterer creates a new log filterer instance of FastBridgeMock, bound to a specific deployed contract. +func NewFastBridgeMockFilterer(address common.Address, filterer bind.ContractFilterer) (*FastBridgeMockFilterer, error) { + contract, err := bindFastBridgeMock(address, nil, nil, filterer) + if err != nil { + return nil, err + } + return &FastBridgeMockFilterer{contract: contract}, nil +} + +// bindFastBridgeMock binds a generic wrapper to an already deployed contract. +func bindFastBridgeMock(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) { + parsed, err := FastBridgeMockMetaData.GetAbi() + if err != nil { + return nil, err + } + return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil +} + +// Call invokes the (constant) contract method with params as input values and +// sets the output to result. The result type might be a single field for simple +// returns, a slice of interfaces for anonymous returns and a struct for named +// returns. +func (_FastBridgeMock *FastBridgeMockRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _FastBridgeMock.Contract.FastBridgeMockCaller.contract.Call(opts, result, method, params...) +} + +// Transfer initiates a plain transaction to move funds to the contract, calling +// its default method if one is available. +func (_FastBridgeMock *FastBridgeMockRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _FastBridgeMock.Contract.FastBridgeMockTransactor.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_FastBridgeMock *FastBridgeMockRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _FastBridgeMock.Contract.FastBridgeMockTransactor.contract.Transact(opts, method, params...) +} + +// Call invokes the (constant) contract method with params as input values and +// sets the output to result. The result type might be a single field for simple +// returns, a slice of interfaces for anonymous returns and a struct for named +// returns. +func (_FastBridgeMock *FastBridgeMockCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _FastBridgeMock.Contract.contract.Call(opts, result, method, params...) +} + +// Transfer initiates a plain transaction to move funds to the contract, calling +// its default method if one is available. +func (_FastBridgeMock *FastBridgeMockTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _FastBridgeMock.Contract.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_FastBridgeMock *FastBridgeMockTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _FastBridgeMock.Contract.contract.Transact(opts, method, params...) +} + +// DEFAULTADMINROLE is a free data retrieval call binding the contract method 0xa217fddf. +// +// Solidity: function DEFAULT_ADMIN_ROLE() view returns(bytes32) +func (_FastBridgeMock *FastBridgeMockCaller) DEFAULTADMINROLE(opts *bind.CallOpts) ([32]byte, error) { + var out []interface{} + err := _FastBridgeMock.contract.Call(opts, &out, "DEFAULT_ADMIN_ROLE") + + if err != nil { + return *new([32]byte), err + } + + out0 := *abi.ConvertType(out[0], new([32]byte)).(*[32]byte) + + return out0, err + +} + +// DEFAULTADMINROLE is a free data retrieval call binding the contract method 0xa217fddf. +// +// Solidity: function DEFAULT_ADMIN_ROLE() view returns(bytes32) +func (_FastBridgeMock *FastBridgeMockSession) DEFAULTADMINROLE() ([32]byte, error) { + return _FastBridgeMock.Contract.DEFAULTADMINROLE(&_FastBridgeMock.CallOpts) +} + +// DEFAULTADMINROLE is a free data retrieval call binding the contract method 0xa217fddf. +// +// Solidity: function DEFAULT_ADMIN_ROLE() view returns(bytes32) +func (_FastBridgeMock *FastBridgeMockCallerSession) DEFAULTADMINROLE() ([32]byte, error) { + return _FastBridgeMock.Contract.DEFAULTADMINROLE(&_FastBridgeMock.CallOpts) +} + +// FEEBPS is a free data retrieval call binding the contract method 0xbf333f2c. +// +// Solidity: function FEE_BPS() view returns(uint256) +func (_FastBridgeMock *FastBridgeMockCaller) FEEBPS(opts *bind.CallOpts) (*big.Int, error) { + var out []interface{} + err := _FastBridgeMock.contract.Call(opts, &out, "FEE_BPS") + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// FEEBPS is a free data retrieval call binding the contract method 0xbf333f2c. +// +// Solidity: function FEE_BPS() view returns(uint256) +func (_FastBridgeMock *FastBridgeMockSession) FEEBPS() (*big.Int, error) { + return _FastBridgeMock.Contract.FEEBPS(&_FastBridgeMock.CallOpts) +} + +// FEEBPS is a free data retrieval call binding the contract method 0xbf333f2c. +// +// Solidity: function FEE_BPS() view returns(uint256) +func (_FastBridgeMock *FastBridgeMockCallerSession) FEEBPS() (*big.Int, error) { + return _FastBridgeMock.Contract.FEEBPS(&_FastBridgeMock.CallOpts) +} + +// FEERATEMAX is a free data retrieval call binding the contract method 0x0f5f6ed7. +// +// Solidity: function FEE_RATE_MAX() view returns(uint256) +func (_FastBridgeMock *FastBridgeMockCaller) FEERATEMAX(opts *bind.CallOpts) (*big.Int, error) { + var out []interface{} + err := _FastBridgeMock.contract.Call(opts, &out, "FEE_RATE_MAX") + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// FEERATEMAX is a free data retrieval call binding the contract method 0x0f5f6ed7. +// +// Solidity: function FEE_RATE_MAX() view returns(uint256) +func (_FastBridgeMock *FastBridgeMockSession) FEERATEMAX() (*big.Int, error) { + return _FastBridgeMock.Contract.FEERATEMAX(&_FastBridgeMock.CallOpts) +} + +// FEERATEMAX is a free data retrieval call binding the contract method 0x0f5f6ed7. +// +// Solidity: function FEE_RATE_MAX() view returns(uint256) +func (_FastBridgeMock *FastBridgeMockCallerSession) FEERATEMAX() (*big.Int, error) { + return _FastBridgeMock.Contract.FEERATEMAX(&_FastBridgeMock.CallOpts) +} + +// GOVERNORROLE is a free data retrieval call binding the contract method 0xccc57490. +// +// Solidity: function GOVERNOR_ROLE() view returns(bytes32) +func (_FastBridgeMock *FastBridgeMockCaller) GOVERNORROLE(opts *bind.CallOpts) ([32]byte, error) { + var out []interface{} + err := _FastBridgeMock.contract.Call(opts, &out, "GOVERNOR_ROLE") + + if err != nil { + return *new([32]byte), err + } + + out0 := *abi.ConvertType(out[0], new([32]byte)).(*[32]byte) + + return out0, err + +} + +// GOVERNORROLE is a free data retrieval call binding the contract method 0xccc57490. +// +// Solidity: function GOVERNOR_ROLE() view returns(bytes32) +func (_FastBridgeMock *FastBridgeMockSession) GOVERNORROLE() ([32]byte, error) { + return _FastBridgeMock.Contract.GOVERNORROLE(&_FastBridgeMock.CallOpts) +} + +// GOVERNORROLE is a free data retrieval call binding the contract method 0xccc57490. +// +// Solidity: function GOVERNOR_ROLE() view returns(bytes32) +func (_FastBridgeMock *FastBridgeMockCallerSession) GOVERNORROLE() ([32]byte, error) { + return _FastBridgeMock.Contract.GOVERNORROLE(&_FastBridgeMock.CallOpts) +} + +// GUARDROLE is a free data retrieval call binding the contract method 0x03ed0ee5. +// +// Solidity: function GUARD_ROLE() view returns(bytes32) +func (_FastBridgeMock *FastBridgeMockCaller) GUARDROLE(opts *bind.CallOpts) ([32]byte, error) { + var out []interface{} + err := _FastBridgeMock.contract.Call(opts, &out, "GUARD_ROLE") + + if err != nil { + return *new([32]byte), err + } + + out0 := *abi.ConvertType(out[0], new([32]byte)).(*[32]byte) + + return out0, err + +} + +// GUARDROLE is a free data retrieval call binding the contract method 0x03ed0ee5. +// +// Solidity: function GUARD_ROLE() view returns(bytes32) +func (_FastBridgeMock *FastBridgeMockSession) GUARDROLE() ([32]byte, error) { + return _FastBridgeMock.Contract.GUARDROLE(&_FastBridgeMock.CallOpts) +} + +// GUARDROLE is a free data retrieval call binding the contract method 0x03ed0ee5. +// +// Solidity: function GUARD_ROLE() view returns(bytes32) +func (_FastBridgeMock *FastBridgeMockCallerSession) GUARDROLE() ([32]byte, error) { + return _FastBridgeMock.Contract.GUARDROLE(&_FastBridgeMock.CallOpts) +} + +// REFUNDERROLE is a free data retrieval call binding the contract method 0x5960ccf2. +// +// Solidity: function REFUNDER_ROLE() view returns(bytes32) +func (_FastBridgeMock *FastBridgeMockCaller) REFUNDERROLE(opts *bind.CallOpts) ([32]byte, error) { + var out []interface{} + err := _FastBridgeMock.contract.Call(opts, &out, "REFUNDER_ROLE") + + if err != nil { + return *new([32]byte), err + } + + out0 := *abi.ConvertType(out[0], new([32]byte)).(*[32]byte) + + return out0, err + +} + +// REFUNDERROLE is a free data retrieval call binding the contract method 0x5960ccf2. +// +// Solidity: function REFUNDER_ROLE() view returns(bytes32) +func (_FastBridgeMock *FastBridgeMockSession) REFUNDERROLE() ([32]byte, error) { + return _FastBridgeMock.Contract.REFUNDERROLE(&_FastBridgeMock.CallOpts) +} + +// REFUNDERROLE is a free data retrieval call binding the contract method 0x5960ccf2. +// +// Solidity: function REFUNDER_ROLE() view returns(bytes32) +func (_FastBridgeMock *FastBridgeMockCallerSession) REFUNDERROLE() ([32]byte, error) { + return _FastBridgeMock.Contract.REFUNDERROLE(&_FastBridgeMock.CallOpts) +} + +// RELAYERROLE is a free data retrieval call binding the contract method 0x926d7d7f. +// +// Solidity: function RELAYER_ROLE() view returns(bytes32) +func (_FastBridgeMock *FastBridgeMockCaller) RELAYERROLE(opts *bind.CallOpts) ([32]byte, error) { + var out []interface{} + err := _FastBridgeMock.contract.Call(opts, &out, "RELAYER_ROLE") + + if err != nil { + return *new([32]byte), err + } + + out0 := *abi.ConvertType(out[0], new([32]byte)).(*[32]byte) + + return out0, err + +} + +// RELAYERROLE is a free data retrieval call binding the contract method 0x926d7d7f. +// +// Solidity: function RELAYER_ROLE() view returns(bytes32) +func (_FastBridgeMock *FastBridgeMockSession) RELAYERROLE() ([32]byte, error) { + return _FastBridgeMock.Contract.RELAYERROLE(&_FastBridgeMock.CallOpts) +} + +// RELAYERROLE is a free data retrieval call binding the contract method 0x926d7d7f. +// +// Solidity: function RELAYER_ROLE() view returns(bytes32) +func (_FastBridgeMock *FastBridgeMockCallerSession) RELAYERROLE() ([32]byte, error) { + return _FastBridgeMock.Contract.RELAYERROLE(&_FastBridgeMock.CallOpts) +} + +// CanClaim is a free data retrieval call binding the contract method 0xaa9641ab. +// +// Solidity: function canClaim(bytes32 transactionid, address relayer) view returns(bool) +func (_FastBridgeMock *FastBridgeMockCaller) CanClaim(opts *bind.CallOpts, transactionid [32]byte, relayer common.Address) (bool, error) { + var out []interface{} + err := _FastBridgeMock.contract.Call(opts, &out, "canClaim", transactionid, relayer) + + if err != nil { + return *new(bool), err + } + + out0 := *abi.ConvertType(out[0], new(bool)).(*bool) + + return out0, err + +} + +// CanClaim is a free data retrieval call binding the contract method 0xaa9641ab. +// +// Solidity: function canClaim(bytes32 transactionid, address relayer) view returns(bool) +func (_FastBridgeMock *FastBridgeMockSession) CanClaim(transactionid [32]byte, relayer common.Address) (bool, error) { + return _FastBridgeMock.Contract.CanClaim(&_FastBridgeMock.CallOpts, transactionid, relayer) +} + +// CanClaim is a free data retrieval call binding the contract method 0xaa9641ab. +// +// Solidity: function canClaim(bytes32 transactionid, address relayer) view returns(bool) +func (_FastBridgeMock *FastBridgeMockCallerSession) CanClaim(transactionid [32]byte, relayer common.Address) (bool, error) { + return _FastBridgeMock.Contract.CanClaim(&_FastBridgeMock.CallOpts, transactionid, relayer) +} + +// ChainGasAmount is a free data retrieval call binding the contract method 0xe00a83e0. +// +// Solidity: function chainGasAmount() view returns(uint256) +func (_FastBridgeMock *FastBridgeMockCaller) ChainGasAmount(opts *bind.CallOpts) (*big.Int, error) { + var out []interface{} + err := _FastBridgeMock.contract.Call(opts, &out, "chainGasAmount") + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// ChainGasAmount is a free data retrieval call binding the contract method 0xe00a83e0. +// +// Solidity: function chainGasAmount() view returns(uint256) +func (_FastBridgeMock *FastBridgeMockSession) ChainGasAmount() (*big.Int, error) { + return _FastBridgeMock.Contract.ChainGasAmount(&_FastBridgeMock.CallOpts) +} + +// ChainGasAmount is a free data retrieval call binding the contract method 0xe00a83e0. +// +// Solidity: function chainGasAmount() view returns(uint256) +func (_FastBridgeMock *FastBridgeMockCallerSession) ChainGasAmount() (*big.Int, error) { + return _FastBridgeMock.Contract.ChainGasAmount(&_FastBridgeMock.CallOpts) +} + +// DeployBlock is a free data retrieval call binding the contract method 0xa3ec191a. +// +// Solidity: function deployBlock() view returns(uint256) +func (_FastBridgeMock *FastBridgeMockCaller) DeployBlock(opts *bind.CallOpts) (*big.Int, error) { + var out []interface{} + err := _FastBridgeMock.contract.Call(opts, &out, "deployBlock") + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// DeployBlock is a free data retrieval call binding the contract method 0xa3ec191a. +// +// Solidity: function deployBlock() view returns(uint256) +func (_FastBridgeMock *FastBridgeMockSession) DeployBlock() (*big.Int, error) { + return _FastBridgeMock.Contract.DeployBlock(&_FastBridgeMock.CallOpts) +} + +// DeployBlock is a free data retrieval call binding the contract method 0xa3ec191a. +// +// Solidity: function deployBlock() view returns(uint256) +func (_FastBridgeMock *FastBridgeMockCallerSession) DeployBlock() (*big.Int, error) { + return _FastBridgeMock.Contract.DeployBlock(&_FastBridgeMock.CallOpts) +} + +// GetBridgeTransaction is a free data retrieval call binding the contract method 0xac11fb1a. +// +// Solidity: function getBridgeTransaction(bytes request) pure returns((uint32,uint32,address,address,address,address,uint256,uint256,uint256,bool,uint256,uint256)) +func (_FastBridgeMock *FastBridgeMockCaller) GetBridgeTransaction(opts *bind.CallOpts, request []byte) (IFastBridgeBridgeTransaction, error) { + var out []interface{} + err := _FastBridgeMock.contract.Call(opts, &out, "getBridgeTransaction", request) + + if err != nil { + return *new(IFastBridgeBridgeTransaction), err + } + + out0 := *abi.ConvertType(out[0], new(IFastBridgeBridgeTransaction)).(*IFastBridgeBridgeTransaction) + + return out0, err + +} + +// GetBridgeTransaction is a free data retrieval call binding the contract method 0xac11fb1a. +// +// Solidity: function getBridgeTransaction(bytes request) pure returns((uint32,uint32,address,address,address,address,uint256,uint256,uint256,bool,uint256,uint256)) +func (_FastBridgeMock *FastBridgeMockSession) GetBridgeTransaction(request []byte) (IFastBridgeBridgeTransaction, error) { + return _FastBridgeMock.Contract.GetBridgeTransaction(&_FastBridgeMock.CallOpts, request) +} + +// GetBridgeTransaction is a free data retrieval call binding the contract method 0xac11fb1a. +// +// Solidity: function getBridgeTransaction(bytes request) pure returns((uint32,uint32,address,address,address,address,uint256,uint256,uint256,bool,uint256,uint256)) +func (_FastBridgeMock *FastBridgeMockCallerSession) GetBridgeTransaction(request []byte) (IFastBridgeBridgeTransaction, error) { + return _FastBridgeMock.Contract.GetBridgeTransaction(&_FastBridgeMock.CallOpts, request) +} + +// GetEnumKeyByValue is a free data retrieval call binding the contract method 0x85ad903d. +// +// Solidity: function getEnumKeyByValue(uint8 keyValue) pure returns(string) +func (_FastBridgeMock *FastBridgeMockCaller) GetEnumKeyByValue(opts *bind.CallOpts, keyValue uint8) (string, error) { + var out []interface{} + err := _FastBridgeMock.contract.Call(opts, &out, "getEnumKeyByValue", keyValue) + + if err != nil { + return *new(string), err + } + + out0 := *abi.ConvertType(out[0], new(string)).(*string) + + return out0, err + +} + +// GetEnumKeyByValue is a free data retrieval call binding the contract method 0x85ad903d. +// +// Solidity: function getEnumKeyByValue(uint8 keyValue) pure returns(string) +func (_FastBridgeMock *FastBridgeMockSession) GetEnumKeyByValue(keyValue uint8) (string, error) { + return _FastBridgeMock.Contract.GetEnumKeyByValue(&_FastBridgeMock.CallOpts, keyValue) +} + +// GetEnumKeyByValue is a free data retrieval call binding the contract method 0x85ad903d. +// +// Solidity: function getEnumKeyByValue(uint8 keyValue) pure returns(string) +func (_FastBridgeMock *FastBridgeMockCallerSession) GetEnumKeyByValue(keyValue uint8) (string, error) { + return _FastBridgeMock.Contract.GetEnumKeyByValue(&_FastBridgeMock.CallOpts, keyValue) +} + +// GetRoleAdmin is a free data retrieval call binding the contract method 0x248a9ca3. +// +// Solidity: function getRoleAdmin(bytes32 role) view returns(bytes32) +func (_FastBridgeMock *FastBridgeMockCaller) GetRoleAdmin(opts *bind.CallOpts, role [32]byte) ([32]byte, error) { + var out []interface{} + err := _FastBridgeMock.contract.Call(opts, &out, "getRoleAdmin", role) + + if err != nil { + return *new([32]byte), err + } + + out0 := *abi.ConvertType(out[0], new([32]byte)).(*[32]byte) + + return out0, err + +} + +// GetRoleAdmin is a free data retrieval call binding the contract method 0x248a9ca3. +// +// Solidity: function getRoleAdmin(bytes32 role) view returns(bytes32) +func (_FastBridgeMock *FastBridgeMockSession) GetRoleAdmin(role [32]byte) ([32]byte, error) { + return _FastBridgeMock.Contract.GetRoleAdmin(&_FastBridgeMock.CallOpts, role) +} + +// GetRoleAdmin is a free data retrieval call binding the contract method 0x248a9ca3. +// +// Solidity: function getRoleAdmin(bytes32 role) view returns(bytes32) +func (_FastBridgeMock *FastBridgeMockCallerSession) GetRoleAdmin(role [32]byte) ([32]byte, error) { + return _FastBridgeMock.Contract.GetRoleAdmin(&_FastBridgeMock.CallOpts, role) +} + +// GetRoleMember is a free data retrieval call binding the contract method 0x9010d07c. +// +// Solidity: function getRoleMember(bytes32 role, uint256 index) view returns(address) +func (_FastBridgeMock *FastBridgeMockCaller) GetRoleMember(opts *bind.CallOpts, role [32]byte, index *big.Int) (common.Address, error) { + var out []interface{} + err := _FastBridgeMock.contract.Call(opts, &out, "getRoleMember", role, index) + + if err != nil { + return *new(common.Address), err + } + + out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) + + return out0, err + +} + +// GetRoleMember is a free data retrieval call binding the contract method 0x9010d07c. +// +// Solidity: function getRoleMember(bytes32 role, uint256 index) view returns(address) +func (_FastBridgeMock *FastBridgeMockSession) GetRoleMember(role [32]byte, index *big.Int) (common.Address, error) { + return _FastBridgeMock.Contract.GetRoleMember(&_FastBridgeMock.CallOpts, role, index) +} + +// GetRoleMember is a free data retrieval call binding the contract method 0x9010d07c. +// +// Solidity: function getRoleMember(bytes32 role, uint256 index) view returns(address) +func (_FastBridgeMock *FastBridgeMockCallerSession) GetRoleMember(role [32]byte, index *big.Int) (common.Address, error) { + return _FastBridgeMock.Contract.GetRoleMember(&_FastBridgeMock.CallOpts, role, index) +} + +// GetRoleMemberCount is a free data retrieval call binding the contract method 0xca15c873. +// +// Solidity: function getRoleMemberCount(bytes32 role) view returns(uint256) +func (_FastBridgeMock *FastBridgeMockCaller) GetRoleMemberCount(opts *bind.CallOpts, role [32]byte) (*big.Int, error) { + var out []interface{} + err := _FastBridgeMock.contract.Call(opts, &out, "getRoleMemberCount", role) + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// GetRoleMemberCount is a free data retrieval call binding the contract method 0xca15c873. +// +// Solidity: function getRoleMemberCount(bytes32 role) view returns(uint256) +func (_FastBridgeMock *FastBridgeMockSession) GetRoleMemberCount(role [32]byte) (*big.Int, error) { + return _FastBridgeMock.Contract.GetRoleMemberCount(&_FastBridgeMock.CallOpts, role) +} + +// GetRoleMemberCount is a free data retrieval call binding the contract method 0xca15c873. +// +// Solidity: function getRoleMemberCount(bytes32 role) view returns(uint256) +func (_FastBridgeMock *FastBridgeMockCallerSession) GetRoleMemberCount(role [32]byte) (*big.Int, error) { + return _FastBridgeMock.Contract.GetRoleMemberCount(&_FastBridgeMock.CallOpts, role) +} + +// HasRole is a free data retrieval call binding the contract method 0x91d14854. +// +// Solidity: function hasRole(bytes32 role, address account) view returns(bool) +func (_FastBridgeMock *FastBridgeMockCaller) HasRole(opts *bind.CallOpts, role [32]byte, account common.Address) (bool, error) { + var out []interface{} + err := _FastBridgeMock.contract.Call(opts, &out, "hasRole", role, account) + + if err != nil { + return *new(bool), err + } + + out0 := *abi.ConvertType(out[0], new(bool)).(*bool) + + return out0, err + +} + +// HasRole is a free data retrieval call binding the contract method 0x91d14854. +// +// Solidity: function hasRole(bytes32 role, address account) view returns(bool) +func (_FastBridgeMock *FastBridgeMockSession) HasRole(role [32]byte, account common.Address) (bool, error) { + return _FastBridgeMock.Contract.HasRole(&_FastBridgeMock.CallOpts, role, account) +} + +// HasRole is a free data retrieval call binding the contract method 0x91d14854. +// +// Solidity: function hasRole(bytes32 role, address account) view returns(bool) +func (_FastBridgeMock *FastBridgeMockCallerSession) HasRole(role [32]byte, account common.Address) (bool, error) { + return _FastBridgeMock.Contract.HasRole(&_FastBridgeMock.CallOpts, role, account) +} + +// Nonce is a free data retrieval call binding the contract method 0xaffed0e0. +// +// Solidity: function nonce() view returns(uint256) +func (_FastBridgeMock *FastBridgeMockCaller) Nonce(opts *bind.CallOpts) (*big.Int, error) { + var out []interface{} + err := _FastBridgeMock.contract.Call(opts, &out, "nonce") + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// Nonce is a free data retrieval call binding the contract method 0xaffed0e0. +// +// Solidity: function nonce() view returns(uint256) +func (_FastBridgeMock *FastBridgeMockSession) Nonce() (*big.Int, error) { + return _FastBridgeMock.Contract.Nonce(&_FastBridgeMock.CallOpts) +} + +// Nonce is a free data retrieval call binding the contract method 0xaffed0e0. +// +// Solidity: function nonce() view returns(uint256) +func (_FastBridgeMock *FastBridgeMockCallerSession) Nonce() (*big.Int, error) { + return _FastBridgeMock.Contract.Nonce(&_FastBridgeMock.CallOpts) +} + +// ProtocolFeeRate is a free data retrieval call binding the contract method 0x58f85880. +// +// Solidity: function protocolFeeRate() view returns(uint256) +func (_FastBridgeMock *FastBridgeMockCaller) ProtocolFeeRate(opts *bind.CallOpts) (*big.Int, error) { + var out []interface{} + err := _FastBridgeMock.contract.Call(opts, &out, "protocolFeeRate") + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// ProtocolFeeRate is a free data retrieval call binding the contract method 0x58f85880. +// +// Solidity: function protocolFeeRate() view returns(uint256) +func (_FastBridgeMock *FastBridgeMockSession) ProtocolFeeRate() (*big.Int, error) { + return _FastBridgeMock.Contract.ProtocolFeeRate(&_FastBridgeMock.CallOpts) +} + +// ProtocolFeeRate is a free data retrieval call binding the contract method 0x58f85880. +// +// Solidity: function protocolFeeRate() view returns(uint256) +func (_FastBridgeMock *FastBridgeMockCallerSession) ProtocolFeeRate() (*big.Int, error) { + return _FastBridgeMock.Contract.ProtocolFeeRate(&_FastBridgeMock.CallOpts) +} + +// ProtocolFees is a free data retrieval call binding the contract method 0xdcf844a7. +// +// Solidity: function protocolFees(address ) view returns(uint256) +func (_FastBridgeMock *FastBridgeMockCaller) ProtocolFees(opts *bind.CallOpts, arg0 common.Address) (*big.Int, error) { + var out []interface{} + err := _FastBridgeMock.contract.Call(opts, &out, "protocolFees", arg0) + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// ProtocolFees is a free data retrieval call binding the contract method 0xdcf844a7. +// +// Solidity: function protocolFees(address ) view returns(uint256) +func (_FastBridgeMock *FastBridgeMockSession) ProtocolFees(arg0 common.Address) (*big.Int, error) { + return _FastBridgeMock.Contract.ProtocolFees(&_FastBridgeMock.CallOpts, arg0) +} + +// ProtocolFees is a free data retrieval call binding the contract method 0xdcf844a7. +// +// Solidity: function protocolFees(address ) view returns(uint256) +func (_FastBridgeMock *FastBridgeMockCallerSession) ProtocolFees(arg0 common.Address) (*big.Int, error) { + return _FastBridgeMock.Contract.ProtocolFees(&_FastBridgeMock.CallOpts, arg0) +} + +// SupportsInterface is a free data retrieval call binding the contract method 0x01ffc9a7. +// +// Solidity: function supportsInterface(bytes4 interfaceId) view returns(bool) +func (_FastBridgeMock *FastBridgeMockCaller) SupportsInterface(opts *bind.CallOpts, interfaceId [4]byte) (bool, error) { + var out []interface{} + err := _FastBridgeMock.contract.Call(opts, &out, "supportsInterface", interfaceId) + + if err != nil { + return *new(bool), err + } + + out0 := *abi.ConvertType(out[0], new(bool)).(*bool) + + return out0, err + +} + +// SupportsInterface is a free data retrieval call binding the contract method 0x01ffc9a7. +// +// Solidity: function supportsInterface(bytes4 interfaceId) view returns(bool) +func (_FastBridgeMock *FastBridgeMockSession) SupportsInterface(interfaceId [4]byte) (bool, error) { + return _FastBridgeMock.Contract.SupportsInterface(&_FastBridgeMock.CallOpts, interfaceId) +} + +// SupportsInterface is a free data retrieval call binding the contract method 0x01ffc9a7. +// +// Solidity: function supportsInterface(bytes4 interfaceId) view returns(bool) +func (_FastBridgeMock *FastBridgeMockCallerSession) SupportsInterface(interfaceId [4]byte) (bool, error) { + return _FastBridgeMock.Contract.SupportsInterface(&_FastBridgeMock.CallOpts, interfaceId) +} + +// Bridge is a paid mutator transaction binding the contract method 0x45851694. +// +// Solidity: function bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256) params) payable returns() +func (_FastBridgeMock *FastBridgeMockTransactor) Bridge(opts *bind.TransactOpts, params IFastBridgeBridgeParams) (*types.Transaction, error) { + return _FastBridgeMock.contract.Transact(opts, "bridge", params) +} + +// Bridge is a paid mutator transaction binding the contract method 0x45851694. +// +// Solidity: function bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256) params) payable returns() +func (_FastBridgeMock *FastBridgeMockSession) Bridge(params IFastBridgeBridgeParams) (*types.Transaction, error) { + return _FastBridgeMock.Contract.Bridge(&_FastBridgeMock.TransactOpts, params) +} + +// Bridge is a paid mutator transaction binding the contract method 0x45851694. +// +// Solidity: function bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256) params) payable returns() +func (_FastBridgeMock *FastBridgeMockTransactorSession) Bridge(params IFastBridgeBridgeParams) (*types.Transaction, error) { + return _FastBridgeMock.Contract.Bridge(&_FastBridgeMock.TransactOpts, params) +} + +// Claim is a paid mutator transaction binding the contract method 0x41fcb612. +// +// Solidity: function claim(bytes request, address to) returns() +func (_FastBridgeMock *FastBridgeMockTransactor) Claim(opts *bind.TransactOpts, request []byte, to common.Address) (*types.Transaction, error) { + return _FastBridgeMock.contract.Transact(opts, "claim", request, to) +} + +// Claim is a paid mutator transaction binding the contract method 0x41fcb612. +// +// Solidity: function claim(bytes request, address to) returns() +func (_FastBridgeMock *FastBridgeMockSession) Claim(request []byte, to common.Address) (*types.Transaction, error) { + return _FastBridgeMock.Contract.Claim(&_FastBridgeMock.TransactOpts, request, to) +} + +// Claim is a paid mutator transaction binding the contract method 0x41fcb612. +// +// Solidity: function claim(bytes request, address to) returns() +func (_FastBridgeMock *FastBridgeMockTransactorSession) Claim(request []byte, to common.Address) (*types.Transaction, error) { + return _FastBridgeMock.Contract.Claim(&_FastBridgeMock.TransactOpts, request, to) +} + +// Dispute is a paid mutator transaction binding the contract method 0xadd98c70. +// +// Solidity: function dispute(bytes32 transactionId) returns() +func (_FastBridgeMock *FastBridgeMockTransactor) Dispute(opts *bind.TransactOpts, transactionId [32]byte) (*types.Transaction, error) { + return _FastBridgeMock.contract.Transact(opts, "dispute", transactionId) +} + +// Dispute is a paid mutator transaction binding the contract method 0xadd98c70. +// +// Solidity: function dispute(bytes32 transactionId) returns() +func (_FastBridgeMock *FastBridgeMockSession) Dispute(transactionId [32]byte) (*types.Transaction, error) { + return _FastBridgeMock.Contract.Dispute(&_FastBridgeMock.TransactOpts, transactionId) +} + +// Dispute is a paid mutator transaction binding the contract method 0xadd98c70. +// +// Solidity: function dispute(bytes32 transactionId) returns() +func (_FastBridgeMock *FastBridgeMockTransactorSession) Dispute(transactionId [32]byte) (*types.Transaction, error) { + return _FastBridgeMock.Contract.Dispute(&_FastBridgeMock.TransactOpts, transactionId) +} + +// GrantRole is a paid mutator transaction binding the contract method 0x2f2ff15d. +// +// Solidity: function grantRole(bytes32 role, address account) returns() +func (_FastBridgeMock *FastBridgeMockTransactor) GrantRole(opts *bind.TransactOpts, role [32]byte, account common.Address) (*types.Transaction, error) { + return _FastBridgeMock.contract.Transact(opts, "grantRole", role, account) +} + +// GrantRole is a paid mutator transaction binding the contract method 0x2f2ff15d. +// +// Solidity: function grantRole(bytes32 role, address account) returns() +func (_FastBridgeMock *FastBridgeMockSession) GrantRole(role [32]byte, account common.Address) (*types.Transaction, error) { + return _FastBridgeMock.Contract.GrantRole(&_FastBridgeMock.TransactOpts, role, account) +} + +// GrantRole is a paid mutator transaction binding the contract method 0x2f2ff15d. +// +// Solidity: function grantRole(bytes32 role, address account) returns() +func (_FastBridgeMock *FastBridgeMockTransactorSession) GrantRole(role [32]byte, account common.Address) (*types.Transaction, error) { + return _FastBridgeMock.Contract.GrantRole(&_FastBridgeMock.TransactOpts, role, account) +} + +// MockBridgeRelayer is a paid mutator transaction binding the contract method 0xc72870cc. +// +// Solidity: function mockBridgeRelayer(bytes32 transactionId, address relayer, address to, uint32 originChainId, address originToken, address destToken, uint256 originAmount, uint256 destAmount, uint256 chainGasAmount) returns() +func (_FastBridgeMock *FastBridgeMockTransactor) MockBridgeRelayer(opts *bind.TransactOpts, transactionId [32]byte, relayer common.Address, to common.Address, originChainId uint32, originToken common.Address, destToken common.Address, originAmount *big.Int, destAmount *big.Int, chainGasAmount *big.Int) (*types.Transaction, error) { + return _FastBridgeMock.contract.Transact(opts, "mockBridgeRelayer", transactionId, relayer, to, originChainId, originToken, destToken, originAmount, destAmount, chainGasAmount) +} + +// MockBridgeRelayer is a paid mutator transaction binding the contract method 0xc72870cc. +// +// Solidity: function mockBridgeRelayer(bytes32 transactionId, address relayer, address to, uint32 originChainId, address originToken, address destToken, uint256 originAmount, uint256 destAmount, uint256 chainGasAmount) returns() +func (_FastBridgeMock *FastBridgeMockSession) MockBridgeRelayer(transactionId [32]byte, relayer common.Address, to common.Address, originChainId uint32, originToken common.Address, destToken common.Address, originAmount *big.Int, destAmount *big.Int, chainGasAmount *big.Int) (*types.Transaction, error) { + return _FastBridgeMock.Contract.MockBridgeRelayer(&_FastBridgeMock.TransactOpts, transactionId, relayer, to, originChainId, originToken, destToken, originAmount, destAmount, chainGasAmount) +} + +// MockBridgeRelayer is a paid mutator transaction binding the contract method 0xc72870cc. +// +// Solidity: function mockBridgeRelayer(bytes32 transactionId, address relayer, address to, uint32 originChainId, address originToken, address destToken, uint256 originAmount, uint256 destAmount, uint256 chainGasAmount) returns() +func (_FastBridgeMock *FastBridgeMockTransactorSession) MockBridgeRelayer(transactionId [32]byte, relayer common.Address, to common.Address, originChainId uint32, originToken common.Address, destToken common.Address, originAmount *big.Int, destAmount *big.Int, chainGasAmount *big.Int) (*types.Transaction, error) { + return _FastBridgeMock.Contract.MockBridgeRelayer(&_FastBridgeMock.TransactOpts, transactionId, relayer, to, originChainId, originToken, destToken, originAmount, destAmount, chainGasAmount) +} + +// MockBridgeRequest is a paid mutator transaction binding the contract method 0xacaebbf1. +// +// Solidity: function mockBridgeRequest(bytes32 transactionId, address sender, (uint32,address,address,address,address,uint256,uint256,bool,uint256) params) returns() +func (_FastBridgeMock *FastBridgeMockTransactor) MockBridgeRequest(opts *bind.TransactOpts, transactionId [32]byte, sender common.Address, params IFastBridgeBridgeParams) (*types.Transaction, error) { + return _FastBridgeMock.contract.Transact(opts, "mockBridgeRequest", transactionId, sender, params) +} + +// MockBridgeRequest is a paid mutator transaction binding the contract method 0xacaebbf1. +// +// Solidity: function mockBridgeRequest(bytes32 transactionId, address sender, (uint32,address,address,address,address,uint256,uint256,bool,uint256) params) returns() +func (_FastBridgeMock *FastBridgeMockSession) MockBridgeRequest(transactionId [32]byte, sender common.Address, params IFastBridgeBridgeParams) (*types.Transaction, error) { + return _FastBridgeMock.Contract.MockBridgeRequest(&_FastBridgeMock.TransactOpts, transactionId, sender, params) +} + +// MockBridgeRequest is a paid mutator transaction binding the contract method 0xacaebbf1. +// +// Solidity: function mockBridgeRequest(bytes32 transactionId, address sender, (uint32,address,address,address,address,uint256,uint256,bool,uint256) params) returns() +func (_FastBridgeMock *FastBridgeMockTransactorSession) MockBridgeRequest(transactionId [32]byte, sender common.Address, params IFastBridgeBridgeParams) (*types.Transaction, error) { + return _FastBridgeMock.Contract.MockBridgeRequest(&_FastBridgeMock.TransactOpts, transactionId, sender, params) +} + +// MockBridgeRequestRaw is a paid mutator transaction binding the contract method 0xaedf009d. +// +// Solidity: function mockBridgeRequestRaw(bytes32 transactionId, address sender, bytes request) returns() +func (_FastBridgeMock *FastBridgeMockTransactor) MockBridgeRequestRaw(opts *bind.TransactOpts, transactionId [32]byte, sender common.Address, request []byte) (*types.Transaction, error) { + return _FastBridgeMock.contract.Transact(opts, "mockBridgeRequestRaw", transactionId, sender, request) +} + +// MockBridgeRequestRaw is a paid mutator transaction binding the contract method 0xaedf009d. +// +// Solidity: function mockBridgeRequestRaw(bytes32 transactionId, address sender, bytes request) returns() +func (_FastBridgeMock *FastBridgeMockSession) MockBridgeRequestRaw(transactionId [32]byte, sender common.Address, request []byte) (*types.Transaction, error) { + return _FastBridgeMock.Contract.MockBridgeRequestRaw(&_FastBridgeMock.TransactOpts, transactionId, sender, request) +} + +// MockBridgeRequestRaw is a paid mutator transaction binding the contract method 0xaedf009d. +// +// Solidity: function mockBridgeRequestRaw(bytes32 transactionId, address sender, bytes request) returns() +func (_FastBridgeMock *FastBridgeMockTransactorSession) MockBridgeRequestRaw(transactionId [32]byte, sender common.Address, request []byte) (*types.Transaction, error) { + return _FastBridgeMock.Contract.MockBridgeRequestRaw(&_FastBridgeMock.TransactOpts, transactionId, sender, request) +} + +// Prove is a paid mutator transaction binding the contract method 0x886d36ff. +// +// Solidity: function prove(bytes request, bytes32 destTxHash) returns() +func (_FastBridgeMock *FastBridgeMockTransactor) Prove(opts *bind.TransactOpts, request []byte, destTxHash [32]byte) (*types.Transaction, error) { + return _FastBridgeMock.contract.Transact(opts, "prove", request, destTxHash) +} + +// Prove is a paid mutator transaction binding the contract method 0x886d36ff. +// +// Solidity: function prove(bytes request, bytes32 destTxHash) returns() +func (_FastBridgeMock *FastBridgeMockSession) Prove(request []byte, destTxHash [32]byte) (*types.Transaction, error) { + return _FastBridgeMock.Contract.Prove(&_FastBridgeMock.TransactOpts, request, destTxHash) +} + +// Prove is a paid mutator transaction binding the contract method 0x886d36ff. +// +// Solidity: function prove(bytes request, bytes32 destTxHash) returns() +func (_FastBridgeMock *FastBridgeMockTransactorSession) Prove(request []byte, destTxHash [32]byte) (*types.Transaction, error) { + return _FastBridgeMock.Contract.Prove(&_FastBridgeMock.TransactOpts, request, destTxHash) +} + +// Refund is a paid mutator transaction binding the contract method 0x5eb7d946. +// +// Solidity: function refund(bytes request) returns() +func (_FastBridgeMock *FastBridgeMockTransactor) Refund(opts *bind.TransactOpts, request []byte) (*types.Transaction, error) { + return _FastBridgeMock.contract.Transact(opts, "refund", request) +} + +// Refund is a paid mutator transaction binding the contract method 0x5eb7d946. +// +// Solidity: function refund(bytes request) returns() +func (_FastBridgeMock *FastBridgeMockSession) Refund(request []byte) (*types.Transaction, error) { + return _FastBridgeMock.Contract.Refund(&_FastBridgeMock.TransactOpts, request) +} + +// Refund is a paid mutator transaction binding the contract method 0x5eb7d946. +// +// Solidity: function refund(bytes request) returns() +func (_FastBridgeMock *FastBridgeMockTransactorSession) Refund(request []byte) (*types.Transaction, error) { + return _FastBridgeMock.Contract.Refund(&_FastBridgeMock.TransactOpts, request) +} + +// Relay is a paid mutator transaction binding the contract method 0x8f0d6f17. +// +// Solidity: function relay(bytes request) payable returns() +func (_FastBridgeMock *FastBridgeMockTransactor) Relay(opts *bind.TransactOpts, request []byte) (*types.Transaction, error) { + return _FastBridgeMock.contract.Transact(opts, "relay", request) +} + +// Relay is a paid mutator transaction binding the contract method 0x8f0d6f17. +// +// Solidity: function relay(bytes request) payable returns() +func (_FastBridgeMock *FastBridgeMockSession) Relay(request []byte) (*types.Transaction, error) { + return _FastBridgeMock.Contract.Relay(&_FastBridgeMock.TransactOpts, request) +} + +// Relay is a paid mutator transaction binding the contract method 0x8f0d6f17. +// +// Solidity: function relay(bytes request) payable returns() +func (_FastBridgeMock *FastBridgeMockTransactorSession) Relay(request []byte) (*types.Transaction, error) { + return _FastBridgeMock.Contract.Relay(&_FastBridgeMock.TransactOpts, request) +} + +// RenounceRole is a paid mutator transaction binding the contract method 0x36568abe. +// +// Solidity: function renounceRole(bytes32 role, address callerConfirmation) returns() +func (_FastBridgeMock *FastBridgeMockTransactor) RenounceRole(opts *bind.TransactOpts, role [32]byte, callerConfirmation common.Address) (*types.Transaction, error) { + return _FastBridgeMock.contract.Transact(opts, "renounceRole", role, callerConfirmation) +} + +// RenounceRole is a paid mutator transaction binding the contract method 0x36568abe. +// +// Solidity: function renounceRole(bytes32 role, address callerConfirmation) returns() +func (_FastBridgeMock *FastBridgeMockSession) RenounceRole(role [32]byte, callerConfirmation common.Address) (*types.Transaction, error) { + return _FastBridgeMock.Contract.RenounceRole(&_FastBridgeMock.TransactOpts, role, callerConfirmation) +} + +// RenounceRole is a paid mutator transaction binding the contract method 0x36568abe. +// +// Solidity: function renounceRole(bytes32 role, address callerConfirmation) returns() +func (_FastBridgeMock *FastBridgeMockTransactorSession) RenounceRole(role [32]byte, callerConfirmation common.Address) (*types.Transaction, error) { + return _FastBridgeMock.Contract.RenounceRole(&_FastBridgeMock.TransactOpts, role, callerConfirmation) +} + +// RevokeRole is a paid mutator transaction binding the contract method 0xd547741f. +// +// Solidity: function revokeRole(bytes32 role, address account) returns() +func (_FastBridgeMock *FastBridgeMockTransactor) RevokeRole(opts *bind.TransactOpts, role [32]byte, account common.Address) (*types.Transaction, error) { + return _FastBridgeMock.contract.Transact(opts, "revokeRole", role, account) +} + +// RevokeRole is a paid mutator transaction binding the contract method 0xd547741f. +// +// Solidity: function revokeRole(bytes32 role, address account) returns() +func (_FastBridgeMock *FastBridgeMockSession) RevokeRole(role [32]byte, account common.Address) (*types.Transaction, error) { + return _FastBridgeMock.Contract.RevokeRole(&_FastBridgeMock.TransactOpts, role, account) +} + +// RevokeRole is a paid mutator transaction binding the contract method 0xd547741f. +// +// Solidity: function revokeRole(bytes32 role, address account) returns() +func (_FastBridgeMock *FastBridgeMockTransactorSession) RevokeRole(role [32]byte, account common.Address) (*types.Transaction, error) { + return _FastBridgeMock.Contract.RevokeRole(&_FastBridgeMock.TransactOpts, role, account) +} + +// SetChainGasAmount is a paid mutator transaction binding the contract method 0xb250fe6b. +// +// Solidity: function setChainGasAmount(uint256 newChainGasAmount) returns() +func (_FastBridgeMock *FastBridgeMockTransactor) SetChainGasAmount(opts *bind.TransactOpts, newChainGasAmount *big.Int) (*types.Transaction, error) { + return _FastBridgeMock.contract.Transact(opts, "setChainGasAmount", newChainGasAmount) +} + +// SetChainGasAmount is a paid mutator transaction binding the contract method 0xb250fe6b. +// +// Solidity: function setChainGasAmount(uint256 newChainGasAmount) returns() +func (_FastBridgeMock *FastBridgeMockSession) SetChainGasAmount(newChainGasAmount *big.Int) (*types.Transaction, error) { + return _FastBridgeMock.Contract.SetChainGasAmount(&_FastBridgeMock.TransactOpts, newChainGasAmount) +} + +// SetChainGasAmount is a paid mutator transaction binding the contract method 0xb250fe6b. +// +// Solidity: function setChainGasAmount(uint256 newChainGasAmount) returns() +func (_FastBridgeMock *FastBridgeMockTransactorSession) SetChainGasAmount(newChainGasAmount *big.Int) (*types.Transaction, error) { + return _FastBridgeMock.Contract.SetChainGasAmount(&_FastBridgeMock.TransactOpts, newChainGasAmount) +} + +// SetProtocolFeeRate is a paid mutator transaction binding the contract method 0xb13aa2d6. +// +// Solidity: function setProtocolFeeRate(uint256 newFeeRate) returns() +func (_FastBridgeMock *FastBridgeMockTransactor) SetProtocolFeeRate(opts *bind.TransactOpts, newFeeRate *big.Int) (*types.Transaction, error) { + return _FastBridgeMock.contract.Transact(opts, "setProtocolFeeRate", newFeeRate) +} + +// SetProtocolFeeRate is a paid mutator transaction binding the contract method 0xb13aa2d6. +// +// Solidity: function setProtocolFeeRate(uint256 newFeeRate) returns() +func (_FastBridgeMock *FastBridgeMockSession) SetProtocolFeeRate(newFeeRate *big.Int) (*types.Transaction, error) { + return _FastBridgeMock.Contract.SetProtocolFeeRate(&_FastBridgeMock.TransactOpts, newFeeRate) +} + +// SetProtocolFeeRate is a paid mutator transaction binding the contract method 0xb13aa2d6. +// +// Solidity: function setProtocolFeeRate(uint256 newFeeRate) returns() +func (_FastBridgeMock *FastBridgeMockTransactorSession) SetProtocolFeeRate(newFeeRate *big.Int) (*types.Transaction, error) { + return _FastBridgeMock.Contract.SetProtocolFeeRate(&_FastBridgeMock.TransactOpts, newFeeRate) +} + +// SweepProtocolFees is a paid mutator transaction binding the contract method 0x06f333f2. +// +// Solidity: function sweepProtocolFees(address token, address recipient) returns() +func (_FastBridgeMock *FastBridgeMockTransactor) SweepProtocolFees(opts *bind.TransactOpts, token common.Address, recipient common.Address) (*types.Transaction, error) { + return _FastBridgeMock.contract.Transact(opts, "sweepProtocolFees", token, recipient) +} + +// SweepProtocolFees is a paid mutator transaction binding the contract method 0x06f333f2. +// +// Solidity: function sweepProtocolFees(address token, address recipient) returns() +func (_FastBridgeMock *FastBridgeMockSession) SweepProtocolFees(token common.Address, recipient common.Address) (*types.Transaction, error) { + return _FastBridgeMock.Contract.SweepProtocolFees(&_FastBridgeMock.TransactOpts, token, recipient) +} + +// SweepProtocolFees is a paid mutator transaction binding the contract method 0x06f333f2. +// +// Solidity: function sweepProtocolFees(address token, address recipient) returns() +func (_FastBridgeMock *FastBridgeMockTransactorSession) SweepProtocolFees(token common.Address, recipient common.Address) (*types.Transaction, error) { + return _FastBridgeMock.Contract.SweepProtocolFees(&_FastBridgeMock.TransactOpts, token, recipient) +} + +// FastBridgeMockBridgeDepositClaimedIterator is returned from FilterBridgeDepositClaimed and is used to iterate over the raw logs and unpacked data for BridgeDepositClaimed events raised by the FastBridgeMock contract. +type FastBridgeMockBridgeDepositClaimedIterator struct { + Event *FastBridgeMockBridgeDepositClaimed // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *FastBridgeMockBridgeDepositClaimedIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(FastBridgeMockBridgeDepositClaimed) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(FastBridgeMockBridgeDepositClaimed) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *FastBridgeMockBridgeDepositClaimedIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *FastBridgeMockBridgeDepositClaimedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// FastBridgeMockBridgeDepositClaimed represents a BridgeDepositClaimed event raised by the FastBridgeMock contract. +type FastBridgeMockBridgeDepositClaimed struct { + TransactionId [32]byte + Relayer common.Address + To common.Address + Token common.Address + Amount *big.Int + Raw types.Log // Blockchain specific contextual infos +} + +// FilterBridgeDepositClaimed is a free log retrieval operation binding the contract event 0x582211c35a2139ac3bbaac74663c6a1f56c6cbb658b41fe11fd45a82074ac678. +// +// Solidity: event BridgeDepositClaimed(bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount) +func (_FastBridgeMock *FastBridgeMockFilterer) FilterBridgeDepositClaimed(opts *bind.FilterOpts, transactionId [][32]byte, relayer []common.Address, to []common.Address) (*FastBridgeMockBridgeDepositClaimedIterator, error) { + + var transactionIdRule []interface{} + for _, transactionIdItem := range transactionId { + transactionIdRule = append(transactionIdRule, transactionIdItem) + } + var relayerRule []interface{} + for _, relayerItem := range relayer { + relayerRule = append(relayerRule, relayerItem) + } + var toRule []interface{} + for _, toItem := range to { + toRule = append(toRule, toItem) + } + + logs, sub, err := _FastBridgeMock.contract.FilterLogs(opts, "BridgeDepositClaimed", transactionIdRule, relayerRule, toRule) + if err != nil { + return nil, err + } + return &FastBridgeMockBridgeDepositClaimedIterator{contract: _FastBridgeMock.contract, event: "BridgeDepositClaimed", logs: logs, sub: sub}, nil +} + +// WatchBridgeDepositClaimed is a free log subscription operation binding the contract event 0x582211c35a2139ac3bbaac74663c6a1f56c6cbb658b41fe11fd45a82074ac678. +// +// Solidity: event BridgeDepositClaimed(bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount) +func (_FastBridgeMock *FastBridgeMockFilterer) WatchBridgeDepositClaimed(opts *bind.WatchOpts, sink chan<- *FastBridgeMockBridgeDepositClaimed, transactionId [][32]byte, relayer []common.Address, to []common.Address) (event.Subscription, error) { + + var transactionIdRule []interface{} + for _, transactionIdItem := range transactionId { + transactionIdRule = append(transactionIdRule, transactionIdItem) + } + var relayerRule []interface{} + for _, relayerItem := range relayer { + relayerRule = append(relayerRule, relayerItem) + } + var toRule []interface{} + for _, toItem := range to { + toRule = append(toRule, toItem) + } + + logs, sub, err := _FastBridgeMock.contract.WatchLogs(opts, "BridgeDepositClaimed", transactionIdRule, relayerRule, toRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(FastBridgeMockBridgeDepositClaimed) + if err := _FastBridgeMock.contract.UnpackLog(event, "BridgeDepositClaimed", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseBridgeDepositClaimed is a log parse operation binding the contract event 0x582211c35a2139ac3bbaac74663c6a1f56c6cbb658b41fe11fd45a82074ac678. +// +// Solidity: event BridgeDepositClaimed(bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount) +func (_FastBridgeMock *FastBridgeMockFilterer) ParseBridgeDepositClaimed(log types.Log) (*FastBridgeMockBridgeDepositClaimed, error) { + event := new(FastBridgeMockBridgeDepositClaimed) + if err := _FastBridgeMock.contract.UnpackLog(event, "BridgeDepositClaimed", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// FastBridgeMockBridgeDepositRefundedIterator is returned from FilterBridgeDepositRefunded and is used to iterate over the raw logs and unpacked data for BridgeDepositRefunded events raised by the FastBridgeMock contract. +type FastBridgeMockBridgeDepositRefundedIterator struct { + Event *FastBridgeMockBridgeDepositRefunded // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *FastBridgeMockBridgeDepositRefundedIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(FastBridgeMockBridgeDepositRefunded) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(FastBridgeMockBridgeDepositRefunded) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *FastBridgeMockBridgeDepositRefundedIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *FastBridgeMockBridgeDepositRefundedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// FastBridgeMockBridgeDepositRefunded represents a BridgeDepositRefunded event raised by the FastBridgeMock contract. +type FastBridgeMockBridgeDepositRefunded struct { + TransactionId [32]byte + To common.Address + Token common.Address + Amount *big.Int + Raw types.Log // Blockchain specific contextual infos +} + +// FilterBridgeDepositRefunded is a free log retrieval operation binding the contract event 0xb4c55c0c9bc613519b920e88748090150b890a875d307f21bea7d4fb2e8bc958. +// +// Solidity: event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount) +func (_FastBridgeMock *FastBridgeMockFilterer) FilterBridgeDepositRefunded(opts *bind.FilterOpts, transactionId [][32]byte, to []common.Address) (*FastBridgeMockBridgeDepositRefundedIterator, error) { + + var transactionIdRule []interface{} + for _, transactionIdItem := range transactionId { + transactionIdRule = append(transactionIdRule, transactionIdItem) + } + var toRule []interface{} + for _, toItem := range to { + toRule = append(toRule, toItem) + } + + logs, sub, err := _FastBridgeMock.contract.FilterLogs(opts, "BridgeDepositRefunded", transactionIdRule, toRule) + if err != nil { + return nil, err + } + return &FastBridgeMockBridgeDepositRefundedIterator{contract: _FastBridgeMock.contract, event: "BridgeDepositRefunded", logs: logs, sub: sub}, nil +} + +// WatchBridgeDepositRefunded is a free log subscription operation binding the contract event 0xb4c55c0c9bc613519b920e88748090150b890a875d307f21bea7d4fb2e8bc958. +// +// Solidity: event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount) +func (_FastBridgeMock *FastBridgeMockFilterer) WatchBridgeDepositRefunded(opts *bind.WatchOpts, sink chan<- *FastBridgeMockBridgeDepositRefunded, transactionId [][32]byte, to []common.Address) (event.Subscription, error) { + + var transactionIdRule []interface{} + for _, transactionIdItem := range transactionId { + transactionIdRule = append(transactionIdRule, transactionIdItem) + } + var toRule []interface{} + for _, toItem := range to { + toRule = append(toRule, toItem) + } + + logs, sub, err := _FastBridgeMock.contract.WatchLogs(opts, "BridgeDepositRefunded", transactionIdRule, toRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(FastBridgeMockBridgeDepositRefunded) + if err := _FastBridgeMock.contract.UnpackLog(event, "BridgeDepositRefunded", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseBridgeDepositRefunded is a log parse operation binding the contract event 0xb4c55c0c9bc613519b920e88748090150b890a875d307f21bea7d4fb2e8bc958. +// +// Solidity: event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount) +func (_FastBridgeMock *FastBridgeMockFilterer) ParseBridgeDepositRefunded(log types.Log) (*FastBridgeMockBridgeDepositRefunded, error) { + event := new(FastBridgeMockBridgeDepositRefunded) + if err := _FastBridgeMock.contract.UnpackLog(event, "BridgeDepositRefunded", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// FastBridgeMockBridgeProofDisputedIterator is returned from FilterBridgeProofDisputed and is used to iterate over the raw logs and unpacked data for BridgeProofDisputed events raised by the FastBridgeMock contract. +type FastBridgeMockBridgeProofDisputedIterator struct { + Event *FastBridgeMockBridgeProofDisputed // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *FastBridgeMockBridgeProofDisputedIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(FastBridgeMockBridgeProofDisputed) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(FastBridgeMockBridgeProofDisputed) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *FastBridgeMockBridgeProofDisputedIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *FastBridgeMockBridgeProofDisputedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// FastBridgeMockBridgeProofDisputed represents a BridgeProofDisputed event raised by the FastBridgeMock contract. +type FastBridgeMockBridgeProofDisputed struct { + TransactionId [32]byte + Relayer common.Address + Raw types.Log // Blockchain specific contextual infos +} + +// FilterBridgeProofDisputed is a free log retrieval operation binding the contract event 0x0695cf1d39b3055dcd0fe02d8b47eaf0d5a13e1996de925de59d0ef9b7f7fad4. +// +// Solidity: event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer) +func (_FastBridgeMock *FastBridgeMockFilterer) FilterBridgeProofDisputed(opts *bind.FilterOpts, transactionId [][32]byte, relayer []common.Address) (*FastBridgeMockBridgeProofDisputedIterator, error) { + + var transactionIdRule []interface{} + for _, transactionIdItem := range transactionId { + transactionIdRule = append(transactionIdRule, transactionIdItem) + } + var relayerRule []interface{} + for _, relayerItem := range relayer { + relayerRule = append(relayerRule, relayerItem) + } + + logs, sub, err := _FastBridgeMock.contract.FilterLogs(opts, "BridgeProofDisputed", transactionIdRule, relayerRule) + if err != nil { + return nil, err + } + return &FastBridgeMockBridgeProofDisputedIterator{contract: _FastBridgeMock.contract, event: "BridgeProofDisputed", logs: logs, sub: sub}, nil +} + +// WatchBridgeProofDisputed is a free log subscription operation binding the contract event 0x0695cf1d39b3055dcd0fe02d8b47eaf0d5a13e1996de925de59d0ef9b7f7fad4. +// +// Solidity: event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer) +func (_FastBridgeMock *FastBridgeMockFilterer) WatchBridgeProofDisputed(opts *bind.WatchOpts, sink chan<- *FastBridgeMockBridgeProofDisputed, transactionId [][32]byte, relayer []common.Address) (event.Subscription, error) { + + var transactionIdRule []interface{} + for _, transactionIdItem := range transactionId { + transactionIdRule = append(transactionIdRule, transactionIdItem) + } + var relayerRule []interface{} + for _, relayerItem := range relayer { + relayerRule = append(relayerRule, relayerItem) + } + + logs, sub, err := _FastBridgeMock.contract.WatchLogs(opts, "BridgeProofDisputed", transactionIdRule, relayerRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(FastBridgeMockBridgeProofDisputed) + if err := _FastBridgeMock.contract.UnpackLog(event, "BridgeProofDisputed", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseBridgeProofDisputed is a log parse operation binding the contract event 0x0695cf1d39b3055dcd0fe02d8b47eaf0d5a13e1996de925de59d0ef9b7f7fad4. +// +// Solidity: event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer) +func (_FastBridgeMock *FastBridgeMockFilterer) ParseBridgeProofDisputed(log types.Log) (*FastBridgeMockBridgeProofDisputed, error) { + event := new(FastBridgeMockBridgeProofDisputed) + if err := _FastBridgeMock.contract.UnpackLog(event, "BridgeProofDisputed", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// FastBridgeMockBridgeProofProvidedIterator is returned from FilterBridgeProofProvided and is used to iterate over the raw logs and unpacked data for BridgeProofProvided events raised by the FastBridgeMock contract. +type FastBridgeMockBridgeProofProvidedIterator struct { + Event *FastBridgeMockBridgeProofProvided // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *FastBridgeMockBridgeProofProvidedIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(FastBridgeMockBridgeProofProvided) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(FastBridgeMockBridgeProofProvided) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *FastBridgeMockBridgeProofProvidedIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *FastBridgeMockBridgeProofProvidedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// FastBridgeMockBridgeProofProvided represents a BridgeProofProvided event raised by the FastBridgeMock contract. +type FastBridgeMockBridgeProofProvided struct { + TransactionId [32]byte + Relayer common.Address + TransactionHash [32]byte + Raw types.Log // Blockchain specific contextual infos +} + +// FilterBridgeProofProvided is a free log retrieval operation binding the contract event 0x4ac8af8a2cd87193d64dfc7a3b8d9923b714ec528b18725d080aa1299be0c5e4. +// +// Solidity: event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash) +func (_FastBridgeMock *FastBridgeMockFilterer) FilterBridgeProofProvided(opts *bind.FilterOpts, transactionId [][32]byte, relayer []common.Address) (*FastBridgeMockBridgeProofProvidedIterator, error) { + + var transactionIdRule []interface{} + for _, transactionIdItem := range transactionId { + transactionIdRule = append(transactionIdRule, transactionIdItem) + } + var relayerRule []interface{} + for _, relayerItem := range relayer { + relayerRule = append(relayerRule, relayerItem) + } + + logs, sub, err := _FastBridgeMock.contract.FilterLogs(opts, "BridgeProofProvided", transactionIdRule, relayerRule) + if err != nil { + return nil, err + } + return &FastBridgeMockBridgeProofProvidedIterator{contract: _FastBridgeMock.contract, event: "BridgeProofProvided", logs: logs, sub: sub}, nil +} + +// WatchBridgeProofProvided is a free log subscription operation binding the contract event 0x4ac8af8a2cd87193d64dfc7a3b8d9923b714ec528b18725d080aa1299be0c5e4. +// +// Solidity: event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash) +func (_FastBridgeMock *FastBridgeMockFilterer) WatchBridgeProofProvided(opts *bind.WatchOpts, sink chan<- *FastBridgeMockBridgeProofProvided, transactionId [][32]byte, relayer []common.Address) (event.Subscription, error) { + + var transactionIdRule []interface{} + for _, transactionIdItem := range transactionId { + transactionIdRule = append(transactionIdRule, transactionIdItem) + } + var relayerRule []interface{} + for _, relayerItem := range relayer { + relayerRule = append(relayerRule, relayerItem) + } + + logs, sub, err := _FastBridgeMock.contract.WatchLogs(opts, "BridgeProofProvided", transactionIdRule, relayerRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(FastBridgeMockBridgeProofProvided) + if err := _FastBridgeMock.contract.UnpackLog(event, "BridgeProofProvided", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseBridgeProofProvided is a log parse operation binding the contract event 0x4ac8af8a2cd87193d64dfc7a3b8d9923b714ec528b18725d080aa1299be0c5e4. +// +// Solidity: event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash) +func (_FastBridgeMock *FastBridgeMockFilterer) ParseBridgeProofProvided(log types.Log) (*FastBridgeMockBridgeProofProvided, error) { + event := new(FastBridgeMockBridgeProofProvided) + if err := _FastBridgeMock.contract.UnpackLog(event, "BridgeProofProvided", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// FastBridgeMockBridgeRelayedIterator is returned from FilterBridgeRelayed and is used to iterate over the raw logs and unpacked data for BridgeRelayed events raised by the FastBridgeMock contract. +type FastBridgeMockBridgeRelayedIterator struct { + Event *FastBridgeMockBridgeRelayed // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *FastBridgeMockBridgeRelayedIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(FastBridgeMockBridgeRelayed) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(FastBridgeMockBridgeRelayed) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *FastBridgeMockBridgeRelayedIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *FastBridgeMockBridgeRelayedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// FastBridgeMockBridgeRelayed represents a BridgeRelayed event raised by the FastBridgeMock contract. +type FastBridgeMockBridgeRelayed struct { + TransactionId [32]byte + Relayer common.Address + To common.Address + OriginChainId uint32 + OriginToken common.Address + DestToken common.Address + OriginAmount *big.Int + DestAmount *big.Int + ChainGasAmount *big.Int + Raw types.Log // Blockchain specific contextual infos +} + +// FilterBridgeRelayed is a free log retrieval operation binding the contract event 0xf8ae392d784b1ea5e8881bfa586d81abf07ef4f1e2fc75f7fe51c90f05199a5c. +// +// Solidity: event BridgeRelayed(bytes32 indexed transactionId, address indexed relayer, address indexed to, uint32 originChainId, address originToken, address destToken, uint256 originAmount, uint256 destAmount, uint256 chainGasAmount) +func (_FastBridgeMock *FastBridgeMockFilterer) FilterBridgeRelayed(opts *bind.FilterOpts, transactionId [][32]byte, relayer []common.Address, to []common.Address) (*FastBridgeMockBridgeRelayedIterator, error) { + + var transactionIdRule []interface{} + for _, transactionIdItem := range transactionId { + transactionIdRule = append(transactionIdRule, transactionIdItem) + } + var relayerRule []interface{} + for _, relayerItem := range relayer { + relayerRule = append(relayerRule, relayerItem) + } + var toRule []interface{} + for _, toItem := range to { + toRule = append(toRule, toItem) + } + + logs, sub, err := _FastBridgeMock.contract.FilterLogs(opts, "BridgeRelayed", transactionIdRule, relayerRule, toRule) + if err != nil { + return nil, err + } + return &FastBridgeMockBridgeRelayedIterator{contract: _FastBridgeMock.contract, event: "BridgeRelayed", logs: logs, sub: sub}, nil +} + +// WatchBridgeRelayed is a free log subscription operation binding the contract event 0xf8ae392d784b1ea5e8881bfa586d81abf07ef4f1e2fc75f7fe51c90f05199a5c. +// +// Solidity: event BridgeRelayed(bytes32 indexed transactionId, address indexed relayer, address indexed to, uint32 originChainId, address originToken, address destToken, uint256 originAmount, uint256 destAmount, uint256 chainGasAmount) +func (_FastBridgeMock *FastBridgeMockFilterer) WatchBridgeRelayed(opts *bind.WatchOpts, sink chan<- *FastBridgeMockBridgeRelayed, transactionId [][32]byte, relayer []common.Address, to []common.Address) (event.Subscription, error) { + + var transactionIdRule []interface{} + for _, transactionIdItem := range transactionId { + transactionIdRule = append(transactionIdRule, transactionIdItem) + } + var relayerRule []interface{} + for _, relayerItem := range relayer { + relayerRule = append(relayerRule, relayerItem) + } + var toRule []interface{} + for _, toItem := range to { + toRule = append(toRule, toItem) + } + + logs, sub, err := _FastBridgeMock.contract.WatchLogs(opts, "BridgeRelayed", transactionIdRule, relayerRule, toRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(FastBridgeMockBridgeRelayed) + if err := _FastBridgeMock.contract.UnpackLog(event, "BridgeRelayed", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseBridgeRelayed is a log parse operation binding the contract event 0xf8ae392d784b1ea5e8881bfa586d81abf07ef4f1e2fc75f7fe51c90f05199a5c. +// +// Solidity: event BridgeRelayed(bytes32 indexed transactionId, address indexed relayer, address indexed to, uint32 originChainId, address originToken, address destToken, uint256 originAmount, uint256 destAmount, uint256 chainGasAmount) +func (_FastBridgeMock *FastBridgeMockFilterer) ParseBridgeRelayed(log types.Log) (*FastBridgeMockBridgeRelayed, error) { + event := new(FastBridgeMockBridgeRelayed) + if err := _FastBridgeMock.contract.UnpackLog(event, "BridgeRelayed", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// FastBridgeMockBridgeRequestedIterator is returned from FilterBridgeRequested and is used to iterate over the raw logs and unpacked data for BridgeRequested events raised by the FastBridgeMock contract. +type FastBridgeMockBridgeRequestedIterator struct { + Event *FastBridgeMockBridgeRequested // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *FastBridgeMockBridgeRequestedIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(FastBridgeMockBridgeRequested) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(FastBridgeMockBridgeRequested) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *FastBridgeMockBridgeRequestedIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *FastBridgeMockBridgeRequestedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// FastBridgeMockBridgeRequested represents a BridgeRequested event raised by the FastBridgeMock contract. +type FastBridgeMockBridgeRequested struct { + TransactionId [32]byte + Sender common.Address + Request []byte + DestChainId uint32 + OriginToken common.Address + DestToken common.Address + OriginAmount *big.Int + DestAmount *big.Int + SendChainGas bool + Raw types.Log // Blockchain specific contextual infos +} + +// FilterBridgeRequested is a free log retrieval operation binding the contract event 0x120ea0364f36cdac7983bcfdd55270ca09d7f9b314a2ebc425a3b01ab1d6403a. +// +// Solidity: event BridgeRequested(bytes32 indexed transactionId, address indexed sender, bytes request, uint32 destChainId, address originToken, address destToken, uint256 originAmount, uint256 destAmount, bool sendChainGas) +func (_FastBridgeMock *FastBridgeMockFilterer) FilterBridgeRequested(opts *bind.FilterOpts, transactionId [][32]byte, sender []common.Address) (*FastBridgeMockBridgeRequestedIterator, error) { + + var transactionIdRule []interface{} + for _, transactionIdItem := range transactionId { + transactionIdRule = append(transactionIdRule, transactionIdItem) + } + var senderRule []interface{} + for _, senderItem := range sender { + senderRule = append(senderRule, senderItem) + } + + logs, sub, err := _FastBridgeMock.contract.FilterLogs(opts, "BridgeRequested", transactionIdRule, senderRule) + if err != nil { + return nil, err + } + return &FastBridgeMockBridgeRequestedIterator{contract: _FastBridgeMock.contract, event: "BridgeRequested", logs: logs, sub: sub}, nil +} + +// WatchBridgeRequested is a free log subscription operation binding the contract event 0x120ea0364f36cdac7983bcfdd55270ca09d7f9b314a2ebc425a3b01ab1d6403a. +// +// Solidity: event BridgeRequested(bytes32 indexed transactionId, address indexed sender, bytes request, uint32 destChainId, address originToken, address destToken, uint256 originAmount, uint256 destAmount, bool sendChainGas) +func (_FastBridgeMock *FastBridgeMockFilterer) WatchBridgeRequested(opts *bind.WatchOpts, sink chan<- *FastBridgeMockBridgeRequested, transactionId [][32]byte, sender []common.Address) (event.Subscription, error) { + + var transactionIdRule []interface{} + for _, transactionIdItem := range transactionId { + transactionIdRule = append(transactionIdRule, transactionIdItem) + } + var senderRule []interface{} + for _, senderItem := range sender { + senderRule = append(senderRule, senderItem) + } + + logs, sub, err := _FastBridgeMock.contract.WatchLogs(opts, "BridgeRequested", transactionIdRule, senderRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(FastBridgeMockBridgeRequested) + if err := _FastBridgeMock.contract.UnpackLog(event, "BridgeRequested", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseBridgeRequested is a log parse operation binding the contract event 0x120ea0364f36cdac7983bcfdd55270ca09d7f9b314a2ebc425a3b01ab1d6403a. +// +// Solidity: event BridgeRequested(bytes32 indexed transactionId, address indexed sender, bytes request, uint32 destChainId, address originToken, address destToken, uint256 originAmount, uint256 destAmount, bool sendChainGas) +func (_FastBridgeMock *FastBridgeMockFilterer) ParseBridgeRequested(log types.Log) (*FastBridgeMockBridgeRequested, error) { + event := new(FastBridgeMockBridgeRequested) + if err := _FastBridgeMock.contract.UnpackLog(event, "BridgeRequested", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// FastBridgeMockChainGasAmountUpdatedIterator is returned from FilterChainGasAmountUpdated and is used to iterate over the raw logs and unpacked data for ChainGasAmountUpdated events raised by the FastBridgeMock contract. +type FastBridgeMockChainGasAmountUpdatedIterator struct { + Event *FastBridgeMockChainGasAmountUpdated // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *FastBridgeMockChainGasAmountUpdatedIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(FastBridgeMockChainGasAmountUpdated) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(FastBridgeMockChainGasAmountUpdated) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *FastBridgeMockChainGasAmountUpdatedIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *FastBridgeMockChainGasAmountUpdatedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// FastBridgeMockChainGasAmountUpdated represents a ChainGasAmountUpdated event raised by the FastBridgeMock contract. +type FastBridgeMockChainGasAmountUpdated struct { + OldChainGasAmount *big.Int + NewChainGasAmount *big.Int + Raw types.Log // Blockchain specific contextual infos +} + +// FilterChainGasAmountUpdated is a free log retrieval operation binding the contract event 0x5cf09b12f3f56b4c564d51b25b40360af6d795198adb61ae0806a36c294323fa. +// +// Solidity: event ChainGasAmountUpdated(uint256 oldChainGasAmount, uint256 newChainGasAmount) +func (_FastBridgeMock *FastBridgeMockFilterer) FilterChainGasAmountUpdated(opts *bind.FilterOpts) (*FastBridgeMockChainGasAmountUpdatedIterator, error) { + + logs, sub, err := _FastBridgeMock.contract.FilterLogs(opts, "ChainGasAmountUpdated") + if err != nil { + return nil, err + } + return &FastBridgeMockChainGasAmountUpdatedIterator{contract: _FastBridgeMock.contract, event: "ChainGasAmountUpdated", logs: logs, sub: sub}, nil +} + +// WatchChainGasAmountUpdated is a free log subscription operation binding the contract event 0x5cf09b12f3f56b4c564d51b25b40360af6d795198adb61ae0806a36c294323fa. +// +// Solidity: event ChainGasAmountUpdated(uint256 oldChainGasAmount, uint256 newChainGasAmount) +func (_FastBridgeMock *FastBridgeMockFilterer) WatchChainGasAmountUpdated(opts *bind.WatchOpts, sink chan<- *FastBridgeMockChainGasAmountUpdated) (event.Subscription, error) { + + logs, sub, err := _FastBridgeMock.contract.WatchLogs(opts, "ChainGasAmountUpdated") + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(FastBridgeMockChainGasAmountUpdated) + if err := _FastBridgeMock.contract.UnpackLog(event, "ChainGasAmountUpdated", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseChainGasAmountUpdated is a log parse operation binding the contract event 0x5cf09b12f3f56b4c564d51b25b40360af6d795198adb61ae0806a36c294323fa. +// +// Solidity: event ChainGasAmountUpdated(uint256 oldChainGasAmount, uint256 newChainGasAmount) +func (_FastBridgeMock *FastBridgeMockFilterer) ParseChainGasAmountUpdated(log types.Log) (*FastBridgeMockChainGasAmountUpdated, error) { + event := new(FastBridgeMockChainGasAmountUpdated) + if err := _FastBridgeMock.contract.UnpackLog(event, "ChainGasAmountUpdated", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// FastBridgeMockFeeRateUpdatedIterator is returned from FilterFeeRateUpdated and is used to iterate over the raw logs and unpacked data for FeeRateUpdated events raised by the FastBridgeMock contract. +type FastBridgeMockFeeRateUpdatedIterator struct { + Event *FastBridgeMockFeeRateUpdated // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *FastBridgeMockFeeRateUpdatedIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(FastBridgeMockFeeRateUpdated) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(FastBridgeMockFeeRateUpdated) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *FastBridgeMockFeeRateUpdatedIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *FastBridgeMockFeeRateUpdatedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// FastBridgeMockFeeRateUpdated represents a FeeRateUpdated event raised by the FastBridgeMock contract. +type FastBridgeMockFeeRateUpdated struct { + OldFeeRate *big.Int + NewFeeRate *big.Int + Raw types.Log // Blockchain specific contextual infos +} + +// FilterFeeRateUpdated is a free log retrieval operation binding the contract event 0x14914da2bf76024616fbe1859783fcd4dbddcb179b1f3a854949fbf920dcb957. +// +// Solidity: event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate) +func (_FastBridgeMock *FastBridgeMockFilterer) FilterFeeRateUpdated(opts *bind.FilterOpts) (*FastBridgeMockFeeRateUpdatedIterator, error) { + + logs, sub, err := _FastBridgeMock.contract.FilterLogs(opts, "FeeRateUpdated") + if err != nil { + return nil, err + } + return &FastBridgeMockFeeRateUpdatedIterator{contract: _FastBridgeMock.contract, event: "FeeRateUpdated", logs: logs, sub: sub}, nil +} + +// WatchFeeRateUpdated is a free log subscription operation binding the contract event 0x14914da2bf76024616fbe1859783fcd4dbddcb179b1f3a854949fbf920dcb957. +// +// Solidity: event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate) +func (_FastBridgeMock *FastBridgeMockFilterer) WatchFeeRateUpdated(opts *bind.WatchOpts, sink chan<- *FastBridgeMockFeeRateUpdated) (event.Subscription, error) { + + logs, sub, err := _FastBridgeMock.contract.WatchLogs(opts, "FeeRateUpdated") + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(FastBridgeMockFeeRateUpdated) + if err := _FastBridgeMock.contract.UnpackLog(event, "FeeRateUpdated", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseFeeRateUpdated is a log parse operation binding the contract event 0x14914da2bf76024616fbe1859783fcd4dbddcb179b1f3a854949fbf920dcb957. +// +// Solidity: event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate) +func (_FastBridgeMock *FastBridgeMockFilterer) ParseFeeRateUpdated(log types.Log) (*FastBridgeMockFeeRateUpdated, error) { + event := new(FastBridgeMockFeeRateUpdated) + if err := _FastBridgeMock.contract.UnpackLog(event, "FeeRateUpdated", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// FastBridgeMockFeesSweptIterator is returned from FilterFeesSwept and is used to iterate over the raw logs and unpacked data for FeesSwept events raised by the FastBridgeMock contract. +type FastBridgeMockFeesSweptIterator struct { + Event *FastBridgeMockFeesSwept // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *FastBridgeMockFeesSweptIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(FastBridgeMockFeesSwept) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(FastBridgeMockFeesSwept) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *FastBridgeMockFeesSweptIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *FastBridgeMockFeesSweptIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// FastBridgeMockFeesSwept represents a FeesSwept event raised by the FastBridgeMock contract. +type FastBridgeMockFeesSwept struct { + Token common.Address + Recipient common.Address + Amount *big.Int + Raw types.Log // Blockchain specific contextual infos +} + +// FilterFeesSwept is a free log retrieval operation binding the contract event 0x244e51bc38c1452fa8aaf487bcb4bca36c2baa3a5fbdb776b1eabd8dc6d277cd. +// +// Solidity: event FeesSwept(address token, address recipient, uint256 amount) +func (_FastBridgeMock *FastBridgeMockFilterer) FilterFeesSwept(opts *bind.FilterOpts) (*FastBridgeMockFeesSweptIterator, error) { + + logs, sub, err := _FastBridgeMock.contract.FilterLogs(opts, "FeesSwept") + if err != nil { + return nil, err + } + return &FastBridgeMockFeesSweptIterator{contract: _FastBridgeMock.contract, event: "FeesSwept", logs: logs, sub: sub}, nil +} + +// WatchFeesSwept is a free log subscription operation binding the contract event 0x244e51bc38c1452fa8aaf487bcb4bca36c2baa3a5fbdb776b1eabd8dc6d277cd. +// +// Solidity: event FeesSwept(address token, address recipient, uint256 amount) +func (_FastBridgeMock *FastBridgeMockFilterer) WatchFeesSwept(opts *bind.WatchOpts, sink chan<- *FastBridgeMockFeesSwept) (event.Subscription, error) { + + logs, sub, err := _FastBridgeMock.contract.WatchLogs(opts, "FeesSwept") + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(FastBridgeMockFeesSwept) + if err := _FastBridgeMock.contract.UnpackLog(event, "FeesSwept", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseFeesSwept is a log parse operation binding the contract event 0x244e51bc38c1452fa8aaf487bcb4bca36c2baa3a5fbdb776b1eabd8dc6d277cd. +// +// Solidity: event FeesSwept(address token, address recipient, uint256 amount) +func (_FastBridgeMock *FastBridgeMockFilterer) ParseFeesSwept(log types.Log) (*FastBridgeMockFeesSwept, error) { + event := new(FastBridgeMockFeesSwept) + if err := _FastBridgeMock.contract.UnpackLog(event, "FeesSwept", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// FastBridgeMockRoleAdminChangedIterator is returned from FilterRoleAdminChanged and is used to iterate over the raw logs and unpacked data for RoleAdminChanged events raised by the FastBridgeMock contract. +type FastBridgeMockRoleAdminChangedIterator struct { + Event *FastBridgeMockRoleAdminChanged // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *FastBridgeMockRoleAdminChangedIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(FastBridgeMockRoleAdminChanged) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(FastBridgeMockRoleAdminChanged) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *FastBridgeMockRoleAdminChangedIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *FastBridgeMockRoleAdminChangedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// FastBridgeMockRoleAdminChanged represents a RoleAdminChanged event raised by the FastBridgeMock contract. +type FastBridgeMockRoleAdminChanged struct { + Role [32]byte + PreviousAdminRole [32]byte + NewAdminRole [32]byte + Raw types.Log // Blockchain specific contextual infos +} + +// FilterRoleAdminChanged is a free log retrieval operation binding the contract event 0xbd79b86ffe0ab8e8776151514217cd7cacd52c909f66475c3af44e129f0b00ff. +// +// Solidity: event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole) +func (_FastBridgeMock *FastBridgeMockFilterer) FilterRoleAdminChanged(opts *bind.FilterOpts, role [][32]byte, previousAdminRole [][32]byte, newAdminRole [][32]byte) (*FastBridgeMockRoleAdminChangedIterator, error) { + + var roleRule []interface{} + for _, roleItem := range role { + roleRule = append(roleRule, roleItem) + } + var previousAdminRoleRule []interface{} + for _, previousAdminRoleItem := range previousAdminRole { + previousAdminRoleRule = append(previousAdminRoleRule, previousAdminRoleItem) + } + var newAdminRoleRule []interface{} + for _, newAdminRoleItem := range newAdminRole { + newAdminRoleRule = append(newAdminRoleRule, newAdminRoleItem) + } + + logs, sub, err := _FastBridgeMock.contract.FilterLogs(opts, "RoleAdminChanged", roleRule, previousAdminRoleRule, newAdminRoleRule) + if err != nil { + return nil, err + } + return &FastBridgeMockRoleAdminChangedIterator{contract: _FastBridgeMock.contract, event: "RoleAdminChanged", logs: logs, sub: sub}, nil +} + +// WatchRoleAdminChanged is a free log subscription operation binding the contract event 0xbd79b86ffe0ab8e8776151514217cd7cacd52c909f66475c3af44e129f0b00ff. +// +// Solidity: event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole) +func (_FastBridgeMock *FastBridgeMockFilterer) WatchRoleAdminChanged(opts *bind.WatchOpts, sink chan<- *FastBridgeMockRoleAdminChanged, role [][32]byte, previousAdminRole [][32]byte, newAdminRole [][32]byte) (event.Subscription, error) { + + var roleRule []interface{} + for _, roleItem := range role { + roleRule = append(roleRule, roleItem) + } + var previousAdminRoleRule []interface{} + for _, previousAdminRoleItem := range previousAdminRole { + previousAdminRoleRule = append(previousAdminRoleRule, previousAdminRoleItem) + } + var newAdminRoleRule []interface{} + for _, newAdminRoleItem := range newAdminRole { + newAdminRoleRule = append(newAdminRoleRule, newAdminRoleItem) + } + + logs, sub, err := _FastBridgeMock.contract.WatchLogs(opts, "RoleAdminChanged", roleRule, previousAdminRoleRule, newAdminRoleRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(FastBridgeMockRoleAdminChanged) + if err := _FastBridgeMock.contract.UnpackLog(event, "RoleAdminChanged", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseRoleAdminChanged is a log parse operation binding the contract event 0xbd79b86ffe0ab8e8776151514217cd7cacd52c909f66475c3af44e129f0b00ff. +// +// Solidity: event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole) +func (_FastBridgeMock *FastBridgeMockFilterer) ParseRoleAdminChanged(log types.Log) (*FastBridgeMockRoleAdminChanged, error) { + event := new(FastBridgeMockRoleAdminChanged) + if err := _FastBridgeMock.contract.UnpackLog(event, "RoleAdminChanged", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// FastBridgeMockRoleGrantedIterator is returned from FilterRoleGranted and is used to iterate over the raw logs and unpacked data for RoleGranted events raised by the FastBridgeMock contract. +type FastBridgeMockRoleGrantedIterator struct { + Event *FastBridgeMockRoleGranted // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *FastBridgeMockRoleGrantedIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(FastBridgeMockRoleGranted) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(FastBridgeMockRoleGranted) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *FastBridgeMockRoleGrantedIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *FastBridgeMockRoleGrantedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// FastBridgeMockRoleGranted represents a RoleGranted event raised by the FastBridgeMock contract. +type FastBridgeMockRoleGranted struct { + Role [32]byte + Account common.Address + Sender common.Address + Raw types.Log // Blockchain specific contextual infos +} + +// FilterRoleGranted is a free log retrieval operation binding the contract event 0x2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d. +// +// Solidity: event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender) +func (_FastBridgeMock *FastBridgeMockFilterer) FilterRoleGranted(opts *bind.FilterOpts, role [][32]byte, account []common.Address, sender []common.Address) (*FastBridgeMockRoleGrantedIterator, error) { + + var roleRule []interface{} + for _, roleItem := range role { + roleRule = append(roleRule, roleItem) + } + var accountRule []interface{} + for _, accountItem := range account { + accountRule = append(accountRule, accountItem) + } + var senderRule []interface{} + for _, senderItem := range sender { + senderRule = append(senderRule, senderItem) + } + + logs, sub, err := _FastBridgeMock.contract.FilterLogs(opts, "RoleGranted", roleRule, accountRule, senderRule) + if err != nil { + return nil, err + } + return &FastBridgeMockRoleGrantedIterator{contract: _FastBridgeMock.contract, event: "RoleGranted", logs: logs, sub: sub}, nil +} + +// WatchRoleGranted is a free log subscription operation binding the contract event 0x2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d. +// +// Solidity: event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender) +func (_FastBridgeMock *FastBridgeMockFilterer) WatchRoleGranted(opts *bind.WatchOpts, sink chan<- *FastBridgeMockRoleGranted, role [][32]byte, account []common.Address, sender []common.Address) (event.Subscription, error) { + + var roleRule []interface{} + for _, roleItem := range role { + roleRule = append(roleRule, roleItem) + } + var accountRule []interface{} + for _, accountItem := range account { + accountRule = append(accountRule, accountItem) + } + var senderRule []interface{} + for _, senderItem := range sender { + senderRule = append(senderRule, senderItem) + } + + logs, sub, err := _FastBridgeMock.contract.WatchLogs(opts, "RoleGranted", roleRule, accountRule, senderRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(FastBridgeMockRoleGranted) + if err := _FastBridgeMock.contract.UnpackLog(event, "RoleGranted", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseRoleGranted is a log parse operation binding the contract event 0x2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d. +// +// Solidity: event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender) +func (_FastBridgeMock *FastBridgeMockFilterer) ParseRoleGranted(log types.Log) (*FastBridgeMockRoleGranted, error) { + event := new(FastBridgeMockRoleGranted) + if err := _FastBridgeMock.contract.UnpackLog(event, "RoleGranted", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// FastBridgeMockRoleRevokedIterator is returned from FilterRoleRevoked and is used to iterate over the raw logs and unpacked data for RoleRevoked events raised by the FastBridgeMock contract. +type FastBridgeMockRoleRevokedIterator struct { + Event *FastBridgeMockRoleRevoked // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *FastBridgeMockRoleRevokedIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(FastBridgeMockRoleRevoked) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(FastBridgeMockRoleRevoked) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *FastBridgeMockRoleRevokedIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *FastBridgeMockRoleRevokedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// FastBridgeMockRoleRevoked represents a RoleRevoked event raised by the FastBridgeMock contract. +type FastBridgeMockRoleRevoked struct { + Role [32]byte + Account common.Address + Sender common.Address + Raw types.Log // Blockchain specific contextual infos +} + +// FilterRoleRevoked is a free log retrieval operation binding the contract event 0xf6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b. +// +// Solidity: event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender) +func (_FastBridgeMock *FastBridgeMockFilterer) FilterRoleRevoked(opts *bind.FilterOpts, role [][32]byte, account []common.Address, sender []common.Address) (*FastBridgeMockRoleRevokedIterator, error) { + + var roleRule []interface{} + for _, roleItem := range role { + roleRule = append(roleRule, roleItem) + } + var accountRule []interface{} + for _, accountItem := range account { + accountRule = append(accountRule, accountItem) + } + var senderRule []interface{} + for _, senderItem := range sender { + senderRule = append(senderRule, senderItem) + } + + logs, sub, err := _FastBridgeMock.contract.FilterLogs(opts, "RoleRevoked", roleRule, accountRule, senderRule) + if err != nil { + return nil, err + } + return &FastBridgeMockRoleRevokedIterator{contract: _FastBridgeMock.contract, event: "RoleRevoked", logs: logs, sub: sub}, nil +} + +// WatchRoleRevoked is a free log subscription operation binding the contract event 0xf6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b. +// +// Solidity: event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender) +func (_FastBridgeMock *FastBridgeMockFilterer) WatchRoleRevoked(opts *bind.WatchOpts, sink chan<- *FastBridgeMockRoleRevoked, role [][32]byte, account []common.Address, sender []common.Address) (event.Subscription, error) { + + var roleRule []interface{} + for _, roleItem := range role { + roleRule = append(roleRule, roleItem) + } + var accountRule []interface{} + for _, accountItem := range account { + accountRule = append(accountRule, accountItem) + } + var senderRule []interface{} + for _, senderItem := range sender { + senderRule = append(senderRule, senderItem) + } + + logs, sub, err := _FastBridgeMock.contract.WatchLogs(opts, "RoleRevoked", roleRule, accountRule, senderRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(FastBridgeMockRoleRevoked) + if err := _FastBridgeMock.contract.UnpackLog(event, "RoleRevoked", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseRoleRevoked is a log parse operation binding the contract event 0xf6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b. +// +// Solidity: event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender) +func (_FastBridgeMock *FastBridgeMockFilterer) ParseRoleRevoked(log types.Log) (*FastBridgeMockRoleRevoked, error) { + event := new(FastBridgeMockRoleRevoked) + if err := _FastBridgeMock.contract.UnpackLog(event, "RoleRevoked", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// IAccessControlMetaData contains all meta data concerning the IAccessControl contract. +var IAccessControlMetaData = &bind.MetaData{ + ABI: "[{\"inputs\":[],\"name\":\"AccessControlBadConfirmation\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"neededRole\",\"type\":\"bytes32\"}],\"name\":\"AccessControlUnauthorizedAccount\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"previousAdminRole\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"newAdminRole\",\"type\":\"bytes32\"}],\"name\":\"RoleAdminChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleGranted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleRevoked\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"}],\"name\":\"getRoleAdmin\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"grantRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"hasRole\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"callerConfirmation\",\"type\":\"address\"}],\"name\":\"renounceRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"revokeRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", + Sigs: map[string]string{ + "248a9ca3": "getRoleAdmin(bytes32)", + "2f2ff15d": "grantRole(bytes32,address)", + "91d14854": "hasRole(bytes32,address)", + "36568abe": "renounceRole(bytes32,address)", + "d547741f": "revokeRole(bytes32,address)", + }, +} + +// IAccessControlABI is the input ABI used to generate the binding from. +// Deprecated: Use IAccessControlMetaData.ABI instead. +var IAccessControlABI = IAccessControlMetaData.ABI + +// Deprecated: Use IAccessControlMetaData.Sigs instead. +// IAccessControlFuncSigs maps the 4-byte function signature to its string representation. +var IAccessControlFuncSigs = IAccessControlMetaData.Sigs + +// IAccessControl is an auto generated Go binding around an Ethereum contract. +type IAccessControl struct { + IAccessControlCaller // Read-only binding to the contract + IAccessControlTransactor // Write-only binding to the contract + IAccessControlFilterer // Log filterer for contract events +} + +// IAccessControlCaller is an auto generated read-only Go binding around an Ethereum contract. +type IAccessControlCaller struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// IAccessControlTransactor is an auto generated write-only Go binding around an Ethereum contract. +type IAccessControlTransactor struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// IAccessControlFilterer is an auto generated log filtering Go binding around an Ethereum contract events. +type IAccessControlFilterer struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// IAccessControlSession is an auto generated Go binding around an Ethereum contract, +// with pre-set call and transact options. +type IAccessControlSession struct { + Contract *IAccessControl // Generic contract binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// IAccessControlCallerSession is an auto generated read-only Go binding around an Ethereum contract, +// with pre-set call options. +type IAccessControlCallerSession struct { + Contract *IAccessControlCaller // Generic contract caller binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session +} + +// IAccessControlTransactorSession is an auto generated write-only Go binding around an Ethereum contract, +// with pre-set transact options. +type IAccessControlTransactorSession struct { + Contract *IAccessControlTransactor // Generic contract transactor binding to set the session for + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// IAccessControlRaw is an auto generated low-level Go binding around an Ethereum contract. +type IAccessControlRaw struct { + Contract *IAccessControl // Generic contract binding to access the raw methods on +} + +// IAccessControlCallerRaw is an auto generated low-level read-only Go binding around an Ethereum contract. +type IAccessControlCallerRaw struct { + Contract *IAccessControlCaller // Generic read-only contract binding to access the raw methods on +} + +// IAccessControlTransactorRaw is an auto generated low-level write-only Go binding around an Ethereum contract. +type IAccessControlTransactorRaw struct { + Contract *IAccessControlTransactor // Generic write-only contract binding to access the raw methods on +} + +// NewIAccessControl creates a new instance of IAccessControl, bound to a specific deployed contract. +func NewIAccessControl(address common.Address, backend bind.ContractBackend) (*IAccessControl, error) { + contract, err := bindIAccessControl(address, backend, backend, backend) + if err != nil { + return nil, err + } + return &IAccessControl{IAccessControlCaller: IAccessControlCaller{contract: contract}, IAccessControlTransactor: IAccessControlTransactor{contract: contract}, IAccessControlFilterer: IAccessControlFilterer{contract: contract}}, nil +} + +// NewIAccessControlCaller creates a new read-only instance of IAccessControl, bound to a specific deployed contract. +func NewIAccessControlCaller(address common.Address, caller bind.ContractCaller) (*IAccessControlCaller, error) { + contract, err := bindIAccessControl(address, caller, nil, nil) + if err != nil { + return nil, err + } + return &IAccessControlCaller{contract: contract}, nil +} + +// NewIAccessControlTransactor creates a new write-only instance of IAccessControl, bound to a specific deployed contract. +func NewIAccessControlTransactor(address common.Address, transactor bind.ContractTransactor) (*IAccessControlTransactor, error) { + contract, err := bindIAccessControl(address, nil, transactor, nil) + if err != nil { + return nil, err + } + return &IAccessControlTransactor{contract: contract}, nil +} + +// NewIAccessControlFilterer creates a new log filterer instance of IAccessControl, bound to a specific deployed contract. +func NewIAccessControlFilterer(address common.Address, filterer bind.ContractFilterer) (*IAccessControlFilterer, error) { + contract, err := bindIAccessControl(address, nil, nil, filterer) + if err != nil { + return nil, err + } + return &IAccessControlFilterer{contract: contract}, nil +} + +// bindIAccessControl binds a generic wrapper to an already deployed contract. +func bindIAccessControl(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) { + parsed, err := IAccessControlMetaData.GetAbi() + if err != nil { + return nil, err + } + return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil +} + +// Call invokes the (constant) contract method with params as input values and +// sets the output to result. The result type might be a single field for simple +// returns, a slice of interfaces for anonymous returns and a struct for named +// returns. +func (_IAccessControl *IAccessControlRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _IAccessControl.Contract.IAccessControlCaller.contract.Call(opts, result, method, params...) +} + +// Transfer initiates a plain transaction to move funds to the contract, calling +// its default method if one is available. +func (_IAccessControl *IAccessControlRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _IAccessControl.Contract.IAccessControlTransactor.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_IAccessControl *IAccessControlRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _IAccessControl.Contract.IAccessControlTransactor.contract.Transact(opts, method, params...) +} + +// Call invokes the (constant) contract method with params as input values and +// sets the output to result. The result type might be a single field for simple +// returns, a slice of interfaces for anonymous returns and a struct for named +// returns. +func (_IAccessControl *IAccessControlCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _IAccessControl.Contract.contract.Call(opts, result, method, params...) +} + +// Transfer initiates a plain transaction to move funds to the contract, calling +// its default method if one is available. +func (_IAccessControl *IAccessControlTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _IAccessControl.Contract.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_IAccessControl *IAccessControlTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _IAccessControl.Contract.contract.Transact(opts, method, params...) +} + +// GetRoleAdmin is a free data retrieval call binding the contract method 0x248a9ca3. +// +// Solidity: function getRoleAdmin(bytes32 role) view returns(bytes32) +func (_IAccessControl *IAccessControlCaller) GetRoleAdmin(opts *bind.CallOpts, role [32]byte) ([32]byte, error) { + var out []interface{} + err := _IAccessControl.contract.Call(opts, &out, "getRoleAdmin", role) + + if err != nil { + return *new([32]byte), err + } + + out0 := *abi.ConvertType(out[0], new([32]byte)).(*[32]byte) + + return out0, err + +} + +// GetRoleAdmin is a free data retrieval call binding the contract method 0x248a9ca3. +// +// Solidity: function getRoleAdmin(bytes32 role) view returns(bytes32) +func (_IAccessControl *IAccessControlSession) GetRoleAdmin(role [32]byte) ([32]byte, error) { + return _IAccessControl.Contract.GetRoleAdmin(&_IAccessControl.CallOpts, role) +} + +// GetRoleAdmin is a free data retrieval call binding the contract method 0x248a9ca3. +// +// Solidity: function getRoleAdmin(bytes32 role) view returns(bytes32) +func (_IAccessControl *IAccessControlCallerSession) GetRoleAdmin(role [32]byte) ([32]byte, error) { + return _IAccessControl.Contract.GetRoleAdmin(&_IAccessControl.CallOpts, role) +} + +// HasRole is a free data retrieval call binding the contract method 0x91d14854. +// +// Solidity: function hasRole(bytes32 role, address account) view returns(bool) +func (_IAccessControl *IAccessControlCaller) HasRole(opts *bind.CallOpts, role [32]byte, account common.Address) (bool, error) { + var out []interface{} + err := _IAccessControl.contract.Call(opts, &out, "hasRole", role, account) + + if err != nil { + return *new(bool), err + } + + out0 := *abi.ConvertType(out[0], new(bool)).(*bool) + + return out0, err + +} + +// HasRole is a free data retrieval call binding the contract method 0x91d14854. +// +// Solidity: function hasRole(bytes32 role, address account) view returns(bool) +func (_IAccessControl *IAccessControlSession) HasRole(role [32]byte, account common.Address) (bool, error) { + return _IAccessControl.Contract.HasRole(&_IAccessControl.CallOpts, role, account) +} + +// HasRole is a free data retrieval call binding the contract method 0x91d14854. +// +// Solidity: function hasRole(bytes32 role, address account) view returns(bool) +func (_IAccessControl *IAccessControlCallerSession) HasRole(role [32]byte, account common.Address) (bool, error) { + return _IAccessControl.Contract.HasRole(&_IAccessControl.CallOpts, role, account) +} + +// GrantRole is a paid mutator transaction binding the contract method 0x2f2ff15d. +// +// Solidity: function grantRole(bytes32 role, address account) returns() +func (_IAccessControl *IAccessControlTransactor) GrantRole(opts *bind.TransactOpts, role [32]byte, account common.Address) (*types.Transaction, error) { + return _IAccessControl.contract.Transact(opts, "grantRole", role, account) +} + +// GrantRole is a paid mutator transaction binding the contract method 0x2f2ff15d. +// +// Solidity: function grantRole(bytes32 role, address account) returns() +func (_IAccessControl *IAccessControlSession) GrantRole(role [32]byte, account common.Address) (*types.Transaction, error) { + return _IAccessControl.Contract.GrantRole(&_IAccessControl.TransactOpts, role, account) +} + +// GrantRole is a paid mutator transaction binding the contract method 0x2f2ff15d. +// +// Solidity: function grantRole(bytes32 role, address account) returns() +func (_IAccessControl *IAccessControlTransactorSession) GrantRole(role [32]byte, account common.Address) (*types.Transaction, error) { + return _IAccessControl.Contract.GrantRole(&_IAccessControl.TransactOpts, role, account) +} + +// RenounceRole is a paid mutator transaction binding the contract method 0x36568abe. +// +// Solidity: function renounceRole(bytes32 role, address callerConfirmation) returns() +func (_IAccessControl *IAccessControlTransactor) RenounceRole(opts *bind.TransactOpts, role [32]byte, callerConfirmation common.Address) (*types.Transaction, error) { + return _IAccessControl.contract.Transact(opts, "renounceRole", role, callerConfirmation) +} + +// RenounceRole is a paid mutator transaction binding the contract method 0x36568abe. +// +// Solidity: function renounceRole(bytes32 role, address callerConfirmation) returns() +func (_IAccessControl *IAccessControlSession) RenounceRole(role [32]byte, callerConfirmation common.Address) (*types.Transaction, error) { + return _IAccessControl.Contract.RenounceRole(&_IAccessControl.TransactOpts, role, callerConfirmation) +} + +// RenounceRole is a paid mutator transaction binding the contract method 0x36568abe. +// +// Solidity: function renounceRole(bytes32 role, address callerConfirmation) returns() +func (_IAccessControl *IAccessControlTransactorSession) RenounceRole(role [32]byte, callerConfirmation common.Address) (*types.Transaction, error) { + return _IAccessControl.Contract.RenounceRole(&_IAccessControl.TransactOpts, role, callerConfirmation) +} + +// RevokeRole is a paid mutator transaction binding the contract method 0xd547741f. +// +// Solidity: function revokeRole(bytes32 role, address account) returns() +func (_IAccessControl *IAccessControlTransactor) RevokeRole(opts *bind.TransactOpts, role [32]byte, account common.Address) (*types.Transaction, error) { + return _IAccessControl.contract.Transact(opts, "revokeRole", role, account) +} + +// RevokeRole is a paid mutator transaction binding the contract method 0xd547741f. +// +// Solidity: function revokeRole(bytes32 role, address account) returns() +func (_IAccessControl *IAccessControlSession) RevokeRole(role [32]byte, account common.Address) (*types.Transaction, error) { + return _IAccessControl.Contract.RevokeRole(&_IAccessControl.TransactOpts, role, account) +} + +// RevokeRole is a paid mutator transaction binding the contract method 0xd547741f. +// +// Solidity: function revokeRole(bytes32 role, address account) returns() +func (_IAccessControl *IAccessControlTransactorSession) RevokeRole(role [32]byte, account common.Address) (*types.Transaction, error) { + return _IAccessControl.Contract.RevokeRole(&_IAccessControl.TransactOpts, role, account) +} + +// IAccessControlRoleAdminChangedIterator is returned from FilterRoleAdminChanged and is used to iterate over the raw logs and unpacked data for RoleAdminChanged events raised by the IAccessControl contract. +type IAccessControlRoleAdminChangedIterator struct { + Event *IAccessControlRoleAdminChanged // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *IAccessControlRoleAdminChangedIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(IAccessControlRoleAdminChanged) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(IAccessControlRoleAdminChanged) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *IAccessControlRoleAdminChangedIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *IAccessControlRoleAdminChangedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// IAccessControlRoleAdminChanged represents a RoleAdminChanged event raised by the IAccessControl contract. +type IAccessControlRoleAdminChanged struct { + Role [32]byte + PreviousAdminRole [32]byte + NewAdminRole [32]byte + Raw types.Log // Blockchain specific contextual infos +} + +// FilterRoleAdminChanged is a free log retrieval operation binding the contract event 0xbd79b86ffe0ab8e8776151514217cd7cacd52c909f66475c3af44e129f0b00ff. +// +// Solidity: event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole) +func (_IAccessControl *IAccessControlFilterer) FilterRoleAdminChanged(opts *bind.FilterOpts, role [][32]byte, previousAdminRole [][32]byte, newAdminRole [][32]byte) (*IAccessControlRoleAdminChangedIterator, error) { + + var roleRule []interface{} + for _, roleItem := range role { + roleRule = append(roleRule, roleItem) + } + var previousAdminRoleRule []interface{} + for _, previousAdminRoleItem := range previousAdminRole { + previousAdminRoleRule = append(previousAdminRoleRule, previousAdminRoleItem) + } + var newAdminRoleRule []interface{} + for _, newAdminRoleItem := range newAdminRole { + newAdminRoleRule = append(newAdminRoleRule, newAdminRoleItem) + } + + logs, sub, err := _IAccessControl.contract.FilterLogs(opts, "RoleAdminChanged", roleRule, previousAdminRoleRule, newAdminRoleRule) + if err != nil { + return nil, err + } + return &IAccessControlRoleAdminChangedIterator{contract: _IAccessControl.contract, event: "RoleAdminChanged", logs: logs, sub: sub}, nil +} + +// WatchRoleAdminChanged is a free log subscription operation binding the contract event 0xbd79b86ffe0ab8e8776151514217cd7cacd52c909f66475c3af44e129f0b00ff. +// +// Solidity: event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole) +func (_IAccessControl *IAccessControlFilterer) WatchRoleAdminChanged(opts *bind.WatchOpts, sink chan<- *IAccessControlRoleAdminChanged, role [][32]byte, previousAdminRole [][32]byte, newAdminRole [][32]byte) (event.Subscription, error) { + + var roleRule []interface{} + for _, roleItem := range role { + roleRule = append(roleRule, roleItem) + } + var previousAdminRoleRule []interface{} + for _, previousAdminRoleItem := range previousAdminRole { + previousAdminRoleRule = append(previousAdminRoleRule, previousAdminRoleItem) + } + var newAdminRoleRule []interface{} + for _, newAdminRoleItem := range newAdminRole { + newAdminRoleRule = append(newAdminRoleRule, newAdminRoleItem) + } + + logs, sub, err := _IAccessControl.contract.WatchLogs(opts, "RoleAdminChanged", roleRule, previousAdminRoleRule, newAdminRoleRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(IAccessControlRoleAdminChanged) + if err := _IAccessControl.contract.UnpackLog(event, "RoleAdminChanged", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseRoleAdminChanged is a log parse operation binding the contract event 0xbd79b86ffe0ab8e8776151514217cd7cacd52c909f66475c3af44e129f0b00ff. +// +// Solidity: event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole) +func (_IAccessControl *IAccessControlFilterer) ParseRoleAdminChanged(log types.Log) (*IAccessControlRoleAdminChanged, error) { + event := new(IAccessControlRoleAdminChanged) + if err := _IAccessControl.contract.UnpackLog(event, "RoleAdminChanged", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// IAccessControlRoleGrantedIterator is returned from FilterRoleGranted and is used to iterate over the raw logs and unpacked data for RoleGranted events raised by the IAccessControl contract. +type IAccessControlRoleGrantedIterator struct { + Event *IAccessControlRoleGranted // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *IAccessControlRoleGrantedIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(IAccessControlRoleGranted) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(IAccessControlRoleGranted) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *IAccessControlRoleGrantedIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *IAccessControlRoleGrantedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// IAccessControlRoleGranted represents a RoleGranted event raised by the IAccessControl contract. +type IAccessControlRoleGranted struct { + Role [32]byte + Account common.Address + Sender common.Address + Raw types.Log // Blockchain specific contextual infos +} + +// FilterRoleGranted is a free log retrieval operation binding the contract event 0x2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d. +// +// Solidity: event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender) +func (_IAccessControl *IAccessControlFilterer) FilterRoleGranted(opts *bind.FilterOpts, role [][32]byte, account []common.Address, sender []common.Address) (*IAccessControlRoleGrantedIterator, error) { + + var roleRule []interface{} + for _, roleItem := range role { + roleRule = append(roleRule, roleItem) + } + var accountRule []interface{} + for _, accountItem := range account { + accountRule = append(accountRule, accountItem) + } + var senderRule []interface{} + for _, senderItem := range sender { + senderRule = append(senderRule, senderItem) + } + + logs, sub, err := _IAccessControl.contract.FilterLogs(opts, "RoleGranted", roleRule, accountRule, senderRule) + if err != nil { + return nil, err + } + return &IAccessControlRoleGrantedIterator{contract: _IAccessControl.contract, event: "RoleGranted", logs: logs, sub: sub}, nil +} + +// WatchRoleGranted is a free log subscription operation binding the contract event 0x2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d. +// +// Solidity: event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender) +func (_IAccessControl *IAccessControlFilterer) WatchRoleGranted(opts *bind.WatchOpts, sink chan<- *IAccessControlRoleGranted, role [][32]byte, account []common.Address, sender []common.Address) (event.Subscription, error) { + + var roleRule []interface{} + for _, roleItem := range role { + roleRule = append(roleRule, roleItem) + } + var accountRule []interface{} + for _, accountItem := range account { + accountRule = append(accountRule, accountItem) + } + var senderRule []interface{} + for _, senderItem := range sender { + senderRule = append(senderRule, senderItem) + } + + logs, sub, err := _IAccessControl.contract.WatchLogs(opts, "RoleGranted", roleRule, accountRule, senderRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(IAccessControlRoleGranted) + if err := _IAccessControl.contract.UnpackLog(event, "RoleGranted", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseRoleGranted is a log parse operation binding the contract event 0x2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d. +// +// Solidity: event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender) +func (_IAccessControl *IAccessControlFilterer) ParseRoleGranted(log types.Log) (*IAccessControlRoleGranted, error) { + event := new(IAccessControlRoleGranted) + if err := _IAccessControl.contract.UnpackLog(event, "RoleGranted", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// IAccessControlRoleRevokedIterator is returned from FilterRoleRevoked and is used to iterate over the raw logs and unpacked data for RoleRevoked events raised by the IAccessControl contract. +type IAccessControlRoleRevokedIterator struct { + Event *IAccessControlRoleRevoked // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *IAccessControlRoleRevokedIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(IAccessControlRoleRevoked) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(IAccessControlRoleRevoked) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *IAccessControlRoleRevokedIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *IAccessControlRoleRevokedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// IAccessControlRoleRevoked represents a RoleRevoked event raised by the IAccessControl contract. +type IAccessControlRoleRevoked struct { + Role [32]byte + Account common.Address + Sender common.Address + Raw types.Log // Blockchain specific contextual infos +} + +// FilterRoleRevoked is a free log retrieval operation binding the contract event 0xf6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b. +// +// Solidity: event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender) +func (_IAccessControl *IAccessControlFilterer) FilterRoleRevoked(opts *bind.FilterOpts, role [][32]byte, account []common.Address, sender []common.Address) (*IAccessControlRoleRevokedIterator, error) { + + var roleRule []interface{} + for _, roleItem := range role { + roleRule = append(roleRule, roleItem) + } + var accountRule []interface{} + for _, accountItem := range account { + accountRule = append(accountRule, accountItem) + } + var senderRule []interface{} + for _, senderItem := range sender { + senderRule = append(senderRule, senderItem) + } + + logs, sub, err := _IAccessControl.contract.FilterLogs(opts, "RoleRevoked", roleRule, accountRule, senderRule) + if err != nil { + return nil, err + } + return &IAccessControlRoleRevokedIterator{contract: _IAccessControl.contract, event: "RoleRevoked", logs: logs, sub: sub}, nil +} + +// WatchRoleRevoked is a free log subscription operation binding the contract event 0xf6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b. +// +// Solidity: event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender) +func (_IAccessControl *IAccessControlFilterer) WatchRoleRevoked(opts *bind.WatchOpts, sink chan<- *IAccessControlRoleRevoked, role [][32]byte, account []common.Address, sender []common.Address) (event.Subscription, error) { + + var roleRule []interface{} + for _, roleItem := range role { + roleRule = append(roleRule, roleItem) + } + var accountRule []interface{} + for _, accountItem := range account { + accountRule = append(accountRule, accountItem) + } + var senderRule []interface{} + for _, senderItem := range sender { + senderRule = append(senderRule, senderItem) + } + + logs, sub, err := _IAccessControl.contract.WatchLogs(opts, "RoleRevoked", roleRule, accountRule, senderRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(IAccessControlRoleRevoked) + if err := _IAccessControl.contract.UnpackLog(event, "RoleRevoked", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseRoleRevoked is a log parse operation binding the contract event 0xf6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b. +// +// Solidity: event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender) +func (_IAccessControl *IAccessControlFilterer) ParseRoleRevoked(log types.Log) (*IAccessControlRoleRevoked, error) { + event := new(IAccessControlRoleRevoked) + if err := _IAccessControl.contract.UnpackLog(event, "RoleRevoked", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// IAccessControlEnumerableMetaData contains all meta data concerning the IAccessControlEnumerable contract. +var IAccessControlEnumerableMetaData = &bind.MetaData{ + ABI: "[{\"inputs\":[],\"name\":\"AccessControlBadConfirmation\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"neededRole\",\"type\":\"bytes32\"}],\"name\":\"AccessControlUnauthorizedAccount\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"previousAdminRole\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"newAdminRole\",\"type\":\"bytes32\"}],\"name\":\"RoleAdminChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleGranted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleRevoked\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"}],\"name\":\"getRoleAdmin\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"index\",\"type\":\"uint256\"}],\"name\":\"getRoleMember\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"}],\"name\":\"getRoleMemberCount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"grantRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"hasRole\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"callerConfirmation\",\"type\":\"address\"}],\"name\":\"renounceRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"revokeRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", + Sigs: map[string]string{ + "248a9ca3": "getRoleAdmin(bytes32)", + "9010d07c": "getRoleMember(bytes32,uint256)", + "ca15c873": "getRoleMemberCount(bytes32)", + "2f2ff15d": "grantRole(bytes32,address)", + "91d14854": "hasRole(bytes32,address)", + "36568abe": "renounceRole(bytes32,address)", + "d547741f": "revokeRole(bytes32,address)", + }, +} + +// IAccessControlEnumerableABI is the input ABI used to generate the binding from. +// Deprecated: Use IAccessControlEnumerableMetaData.ABI instead. +var IAccessControlEnumerableABI = IAccessControlEnumerableMetaData.ABI + +// Deprecated: Use IAccessControlEnumerableMetaData.Sigs instead. +// IAccessControlEnumerableFuncSigs maps the 4-byte function signature to its string representation. +var IAccessControlEnumerableFuncSigs = IAccessControlEnumerableMetaData.Sigs + +// IAccessControlEnumerable is an auto generated Go binding around an Ethereum contract. +type IAccessControlEnumerable struct { + IAccessControlEnumerableCaller // Read-only binding to the contract + IAccessControlEnumerableTransactor // Write-only binding to the contract + IAccessControlEnumerableFilterer // Log filterer for contract events +} + +// IAccessControlEnumerableCaller is an auto generated read-only Go binding around an Ethereum contract. +type IAccessControlEnumerableCaller struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// IAccessControlEnumerableTransactor is an auto generated write-only Go binding around an Ethereum contract. +type IAccessControlEnumerableTransactor struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// IAccessControlEnumerableFilterer is an auto generated log filtering Go binding around an Ethereum contract events. +type IAccessControlEnumerableFilterer struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// IAccessControlEnumerableSession is an auto generated Go binding around an Ethereum contract, +// with pre-set call and transact options. +type IAccessControlEnumerableSession struct { + Contract *IAccessControlEnumerable // Generic contract binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// IAccessControlEnumerableCallerSession is an auto generated read-only Go binding around an Ethereum contract, +// with pre-set call options. +type IAccessControlEnumerableCallerSession struct { + Contract *IAccessControlEnumerableCaller // Generic contract caller binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session +} + +// IAccessControlEnumerableTransactorSession is an auto generated write-only Go binding around an Ethereum contract, +// with pre-set transact options. +type IAccessControlEnumerableTransactorSession struct { + Contract *IAccessControlEnumerableTransactor // Generic contract transactor binding to set the session for + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// IAccessControlEnumerableRaw is an auto generated low-level Go binding around an Ethereum contract. +type IAccessControlEnumerableRaw struct { + Contract *IAccessControlEnumerable // Generic contract binding to access the raw methods on +} + +// IAccessControlEnumerableCallerRaw is an auto generated low-level read-only Go binding around an Ethereum contract. +type IAccessControlEnumerableCallerRaw struct { + Contract *IAccessControlEnumerableCaller // Generic read-only contract binding to access the raw methods on +} + +// IAccessControlEnumerableTransactorRaw is an auto generated low-level write-only Go binding around an Ethereum contract. +type IAccessControlEnumerableTransactorRaw struct { + Contract *IAccessControlEnumerableTransactor // Generic write-only contract binding to access the raw methods on +} + +// NewIAccessControlEnumerable creates a new instance of IAccessControlEnumerable, bound to a specific deployed contract. +func NewIAccessControlEnumerable(address common.Address, backend bind.ContractBackend) (*IAccessControlEnumerable, error) { + contract, err := bindIAccessControlEnumerable(address, backend, backend, backend) + if err != nil { + return nil, err + } + return &IAccessControlEnumerable{IAccessControlEnumerableCaller: IAccessControlEnumerableCaller{contract: contract}, IAccessControlEnumerableTransactor: IAccessControlEnumerableTransactor{contract: contract}, IAccessControlEnumerableFilterer: IAccessControlEnumerableFilterer{contract: contract}}, nil +} + +// NewIAccessControlEnumerableCaller creates a new read-only instance of IAccessControlEnumerable, bound to a specific deployed contract. +func NewIAccessControlEnumerableCaller(address common.Address, caller bind.ContractCaller) (*IAccessControlEnumerableCaller, error) { + contract, err := bindIAccessControlEnumerable(address, caller, nil, nil) + if err != nil { + return nil, err + } + return &IAccessControlEnumerableCaller{contract: contract}, nil +} + +// NewIAccessControlEnumerableTransactor creates a new write-only instance of IAccessControlEnumerable, bound to a specific deployed contract. +func NewIAccessControlEnumerableTransactor(address common.Address, transactor bind.ContractTransactor) (*IAccessControlEnumerableTransactor, error) { + contract, err := bindIAccessControlEnumerable(address, nil, transactor, nil) + if err != nil { + return nil, err + } + return &IAccessControlEnumerableTransactor{contract: contract}, nil +} + +// NewIAccessControlEnumerableFilterer creates a new log filterer instance of IAccessControlEnumerable, bound to a specific deployed contract. +func NewIAccessControlEnumerableFilterer(address common.Address, filterer bind.ContractFilterer) (*IAccessControlEnumerableFilterer, error) { + contract, err := bindIAccessControlEnumerable(address, nil, nil, filterer) + if err != nil { + return nil, err + } + return &IAccessControlEnumerableFilterer{contract: contract}, nil +} + +// bindIAccessControlEnumerable binds a generic wrapper to an already deployed contract. +func bindIAccessControlEnumerable(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) { + parsed, err := IAccessControlEnumerableMetaData.GetAbi() + if err != nil { + return nil, err + } + return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil +} + +// Call invokes the (constant) contract method with params as input values and +// sets the output to result. The result type might be a single field for simple +// returns, a slice of interfaces for anonymous returns and a struct for named +// returns. +func (_IAccessControlEnumerable *IAccessControlEnumerableRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _IAccessControlEnumerable.Contract.IAccessControlEnumerableCaller.contract.Call(opts, result, method, params...) +} + +// Transfer initiates a plain transaction to move funds to the contract, calling +// its default method if one is available. +func (_IAccessControlEnumerable *IAccessControlEnumerableRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _IAccessControlEnumerable.Contract.IAccessControlEnumerableTransactor.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_IAccessControlEnumerable *IAccessControlEnumerableRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _IAccessControlEnumerable.Contract.IAccessControlEnumerableTransactor.contract.Transact(opts, method, params...) +} + +// Call invokes the (constant) contract method with params as input values and +// sets the output to result. The result type might be a single field for simple +// returns, a slice of interfaces for anonymous returns and a struct for named +// returns. +func (_IAccessControlEnumerable *IAccessControlEnumerableCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _IAccessControlEnumerable.Contract.contract.Call(opts, result, method, params...) +} + +// Transfer initiates a plain transaction to move funds to the contract, calling +// its default method if one is available. +func (_IAccessControlEnumerable *IAccessControlEnumerableTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _IAccessControlEnumerable.Contract.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_IAccessControlEnumerable *IAccessControlEnumerableTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _IAccessControlEnumerable.Contract.contract.Transact(opts, method, params...) +} + +// GetRoleAdmin is a free data retrieval call binding the contract method 0x248a9ca3. +// +// Solidity: function getRoleAdmin(bytes32 role) view returns(bytes32) +func (_IAccessControlEnumerable *IAccessControlEnumerableCaller) GetRoleAdmin(opts *bind.CallOpts, role [32]byte) ([32]byte, error) { + var out []interface{} + err := _IAccessControlEnumerable.contract.Call(opts, &out, "getRoleAdmin", role) + + if err != nil { + return *new([32]byte), err + } + + out0 := *abi.ConvertType(out[0], new([32]byte)).(*[32]byte) + + return out0, err + +} + +// GetRoleAdmin is a free data retrieval call binding the contract method 0x248a9ca3. +// +// Solidity: function getRoleAdmin(bytes32 role) view returns(bytes32) +func (_IAccessControlEnumerable *IAccessControlEnumerableSession) GetRoleAdmin(role [32]byte) ([32]byte, error) { + return _IAccessControlEnumerable.Contract.GetRoleAdmin(&_IAccessControlEnumerable.CallOpts, role) +} + +// GetRoleAdmin is a free data retrieval call binding the contract method 0x248a9ca3. +// +// Solidity: function getRoleAdmin(bytes32 role) view returns(bytes32) +func (_IAccessControlEnumerable *IAccessControlEnumerableCallerSession) GetRoleAdmin(role [32]byte) ([32]byte, error) { + return _IAccessControlEnumerable.Contract.GetRoleAdmin(&_IAccessControlEnumerable.CallOpts, role) +} + +// GetRoleMember is a free data retrieval call binding the contract method 0x9010d07c. +// +// Solidity: function getRoleMember(bytes32 role, uint256 index) view returns(address) +func (_IAccessControlEnumerable *IAccessControlEnumerableCaller) GetRoleMember(opts *bind.CallOpts, role [32]byte, index *big.Int) (common.Address, error) { + var out []interface{} + err := _IAccessControlEnumerable.contract.Call(opts, &out, "getRoleMember", role, index) + + if err != nil { + return *new(common.Address), err + } + + out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) + + return out0, err + +} + +// GetRoleMember is a free data retrieval call binding the contract method 0x9010d07c. +// +// Solidity: function getRoleMember(bytes32 role, uint256 index) view returns(address) +func (_IAccessControlEnumerable *IAccessControlEnumerableSession) GetRoleMember(role [32]byte, index *big.Int) (common.Address, error) { + return _IAccessControlEnumerable.Contract.GetRoleMember(&_IAccessControlEnumerable.CallOpts, role, index) +} + +// GetRoleMember is a free data retrieval call binding the contract method 0x9010d07c. +// +// Solidity: function getRoleMember(bytes32 role, uint256 index) view returns(address) +func (_IAccessControlEnumerable *IAccessControlEnumerableCallerSession) GetRoleMember(role [32]byte, index *big.Int) (common.Address, error) { + return _IAccessControlEnumerable.Contract.GetRoleMember(&_IAccessControlEnumerable.CallOpts, role, index) +} + +// GetRoleMemberCount is a free data retrieval call binding the contract method 0xca15c873. +// +// Solidity: function getRoleMemberCount(bytes32 role) view returns(uint256) +func (_IAccessControlEnumerable *IAccessControlEnumerableCaller) GetRoleMemberCount(opts *bind.CallOpts, role [32]byte) (*big.Int, error) { + var out []interface{} + err := _IAccessControlEnumerable.contract.Call(opts, &out, "getRoleMemberCount", role) + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// GetRoleMemberCount is a free data retrieval call binding the contract method 0xca15c873. +// +// Solidity: function getRoleMemberCount(bytes32 role) view returns(uint256) +func (_IAccessControlEnumerable *IAccessControlEnumerableSession) GetRoleMemberCount(role [32]byte) (*big.Int, error) { + return _IAccessControlEnumerable.Contract.GetRoleMemberCount(&_IAccessControlEnumerable.CallOpts, role) +} + +// GetRoleMemberCount is a free data retrieval call binding the contract method 0xca15c873. +// +// Solidity: function getRoleMemberCount(bytes32 role) view returns(uint256) +func (_IAccessControlEnumerable *IAccessControlEnumerableCallerSession) GetRoleMemberCount(role [32]byte) (*big.Int, error) { + return _IAccessControlEnumerable.Contract.GetRoleMemberCount(&_IAccessControlEnumerable.CallOpts, role) +} + +// HasRole is a free data retrieval call binding the contract method 0x91d14854. +// +// Solidity: function hasRole(bytes32 role, address account) view returns(bool) +func (_IAccessControlEnumerable *IAccessControlEnumerableCaller) HasRole(opts *bind.CallOpts, role [32]byte, account common.Address) (bool, error) { + var out []interface{} + err := _IAccessControlEnumerable.contract.Call(opts, &out, "hasRole", role, account) + + if err != nil { + return *new(bool), err + } + + out0 := *abi.ConvertType(out[0], new(bool)).(*bool) + + return out0, err + +} + +// HasRole is a free data retrieval call binding the contract method 0x91d14854. +// +// Solidity: function hasRole(bytes32 role, address account) view returns(bool) +func (_IAccessControlEnumerable *IAccessControlEnumerableSession) HasRole(role [32]byte, account common.Address) (bool, error) { + return _IAccessControlEnumerable.Contract.HasRole(&_IAccessControlEnumerable.CallOpts, role, account) +} + +// HasRole is a free data retrieval call binding the contract method 0x91d14854. +// +// Solidity: function hasRole(bytes32 role, address account) view returns(bool) +func (_IAccessControlEnumerable *IAccessControlEnumerableCallerSession) HasRole(role [32]byte, account common.Address) (bool, error) { + return _IAccessControlEnumerable.Contract.HasRole(&_IAccessControlEnumerable.CallOpts, role, account) +} + +// GrantRole is a paid mutator transaction binding the contract method 0x2f2ff15d. +// +// Solidity: function grantRole(bytes32 role, address account) returns() +func (_IAccessControlEnumerable *IAccessControlEnumerableTransactor) GrantRole(opts *bind.TransactOpts, role [32]byte, account common.Address) (*types.Transaction, error) { + return _IAccessControlEnumerable.contract.Transact(opts, "grantRole", role, account) +} + +// GrantRole is a paid mutator transaction binding the contract method 0x2f2ff15d. +// +// Solidity: function grantRole(bytes32 role, address account) returns() +func (_IAccessControlEnumerable *IAccessControlEnumerableSession) GrantRole(role [32]byte, account common.Address) (*types.Transaction, error) { + return _IAccessControlEnumerable.Contract.GrantRole(&_IAccessControlEnumerable.TransactOpts, role, account) +} + +// GrantRole is a paid mutator transaction binding the contract method 0x2f2ff15d. +// +// Solidity: function grantRole(bytes32 role, address account) returns() +func (_IAccessControlEnumerable *IAccessControlEnumerableTransactorSession) GrantRole(role [32]byte, account common.Address) (*types.Transaction, error) { + return _IAccessControlEnumerable.Contract.GrantRole(&_IAccessControlEnumerable.TransactOpts, role, account) +} + +// RenounceRole is a paid mutator transaction binding the contract method 0x36568abe. +// +// Solidity: function renounceRole(bytes32 role, address callerConfirmation) returns() +func (_IAccessControlEnumerable *IAccessControlEnumerableTransactor) RenounceRole(opts *bind.TransactOpts, role [32]byte, callerConfirmation common.Address) (*types.Transaction, error) { + return _IAccessControlEnumerable.contract.Transact(opts, "renounceRole", role, callerConfirmation) +} + +// RenounceRole is a paid mutator transaction binding the contract method 0x36568abe. +// +// Solidity: function renounceRole(bytes32 role, address callerConfirmation) returns() +func (_IAccessControlEnumerable *IAccessControlEnumerableSession) RenounceRole(role [32]byte, callerConfirmation common.Address) (*types.Transaction, error) { + return _IAccessControlEnumerable.Contract.RenounceRole(&_IAccessControlEnumerable.TransactOpts, role, callerConfirmation) +} + +// RenounceRole is a paid mutator transaction binding the contract method 0x36568abe. +// +// Solidity: function renounceRole(bytes32 role, address callerConfirmation) returns() +func (_IAccessControlEnumerable *IAccessControlEnumerableTransactorSession) RenounceRole(role [32]byte, callerConfirmation common.Address) (*types.Transaction, error) { + return _IAccessControlEnumerable.Contract.RenounceRole(&_IAccessControlEnumerable.TransactOpts, role, callerConfirmation) +} + +// RevokeRole is a paid mutator transaction binding the contract method 0xd547741f. +// +// Solidity: function revokeRole(bytes32 role, address account) returns() +func (_IAccessControlEnumerable *IAccessControlEnumerableTransactor) RevokeRole(opts *bind.TransactOpts, role [32]byte, account common.Address) (*types.Transaction, error) { + return _IAccessControlEnumerable.contract.Transact(opts, "revokeRole", role, account) +} + +// RevokeRole is a paid mutator transaction binding the contract method 0xd547741f. +// +// Solidity: function revokeRole(bytes32 role, address account) returns() +func (_IAccessControlEnumerable *IAccessControlEnumerableSession) RevokeRole(role [32]byte, account common.Address) (*types.Transaction, error) { + return _IAccessControlEnumerable.Contract.RevokeRole(&_IAccessControlEnumerable.TransactOpts, role, account) +} + +// RevokeRole is a paid mutator transaction binding the contract method 0xd547741f. +// +// Solidity: function revokeRole(bytes32 role, address account) returns() +func (_IAccessControlEnumerable *IAccessControlEnumerableTransactorSession) RevokeRole(role [32]byte, account common.Address) (*types.Transaction, error) { + return _IAccessControlEnumerable.Contract.RevokeRole(&_IAccessControlEnumerable.TransactOpts, role, account) +} + +// IAccessControlEnumerableRoleAdminChangedIterator is returned from FilterRoleAdminChanged and is used to iterate over the raw logs and unpacked data for RoleAdminChanged events raised by the IAccessControlEnumerable contract. +type IAccessControlEnumerableRoleAdminChangedIterator struct { + Event *IAccessControlEnumerableRoleAdminChanged // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *IAccessControlEnumerableRoleAdminChangedIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(IAccessControlEnumerableRoleAdminChanged) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(IAccessControlEnumerableRoleAdminChanged) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *IAccessControlEnumerableRoleAdminChangedIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *IAccessControlEnumerableRoleAdminChangedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// IAccessControlEnumerableRoleAdminChanged represents a RoleAdminChanged event raised by the IAccessControlEnumerable contract. +type IAccessControlEnumerableRoleAdminChanged struct { + Role [32]byte + PreviousAdminRole [32]byte + NewAdminRole [32]byte + Raw types.Log // Blockchain specific contextual infos +} + +// FilterRoleAdminChanged is a free log retrieval operation binding the contract event 0xbd79b86ffe0ab8e8776151514217cd7cacd52c909f66475c3af44e129f0b00ff. +// +// Solidity: event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole) +func (_IAccessControlEnumerable *IAccessControlEnumerableFilterer) FilterRoleAdminChanged(opts *bind.FilterOpts, role [][32]byte, previousAdminRole [][32]byte, newAdminRole [][32]byte) (*IAccessControlEnumerableRoleAdminChangedIterator, error) { + + var roleRule []interface{} + for _, roleItem := range role { + roleRule = append(roleRule, roleItem) + } + var previousAdminRoleRule []interface{} + for _, previousAdminRoleItem := range previousAdminRole { + previousAdminRoleRule = append(previousAdminRoleRule, previousAdminRoleItem) + } + var newAdminRoleRule []interface{} + for _, newAdminRoleItem := range newAdminRole { + newAdminRoleRule = append(newAdminRoleRule, newAdminRoleItem) + } + + logs, sub, err := _IAccessControlEnumerable.contract.FilterLogs(opts, "RoleAdminChanged", roleRule, previousAdminRoleRule, newAdminRoleRule) + if err != nil { + return nil, err + } + return &IAccessControlEnumerableRoleAdminChangedIterator{contract: _IAccessControlEnumerable.contract, event: "RoleAdminChanged", logs: logs, sub: sub}, nil +} + +// WatchRoleAdminChanged is a free log subscription operation binding the contract event 0xbd79b86ffe0ab8e8776151514217cd7cacd52c909f66475c3af44e129f0b00ff. +// +// Solidity: event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole) +func (_IAccessControlEnumerable *IAccessControlEnumerableFilterer) WatchRoleAdminChanged(opts *bind.WatchOpts, sink chan<- *IAccessControlEnumerableRoleAdminChanged, role [][32]byte, previousAdminRole [][32]byte, newAdminRole [][32]byte) (event.Subscription, error) { + + var roleRule []interface{} + for _, roleItem := range role { + roleRule = append(roleRule, roleItem) + } + var previousAdminRoleRule []interface{} + for _, previousAdminRoleItem := range previousAdminRole { + previousAdminRoleRule = append(previousAdminRoleRule, previousAdminRoleItem) + } + var newAdminRoleRule []interface{} + for _, newAdminRoleItem := range newAdminRole { + newAdminRoleRule = append(newAdminRoleRule, newAdminRoleItem) + } + + logs, sub, err := _IAccessControlEnumerable.contract.WatchLogs(opts, "RoleAdminChanged", roleRule, previousAdminRoleRule, newAdminRoleRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(IAccessControlEnumerableRoleAdminChanged) + if err := _IAccessControlEnumerable.contract.UnpackLog(event, "RoleAdminChanged", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseRoleAdminChanged is a log parse operation binding the contract event 0xbd79b86ffe0ab8e8776151514217cd7cacd52c909f66475c3af44e129f0b00ff. +// +// Solidity: event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole) +func (_IAccessControlEnumerable *IAccessControlEnumerableFilterer) ParseRoleAdminChanged(log types.Log) (*IAccessControlEnumerableRoleAdminChanged, error) { + event := new(IAccessControlEnumerableRoleAdminChanged) + if err := _IAccessControlEnumerable.contract.UnpackLog(event, "RoleAdminChanged", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// IAccessControlEnumerableRoleGrantedIterator is returned from FilterRoleGranted and is used to iterate over the raw logs and unpacked data for RoleGranted events raised by the IAccessControlEnumerable contract. +type IAccessControlEnumerableRoleGrantedIterator struct { + Event *IAccessControlEnumerableRoleGranted // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *IAccessControlEnumerableRoleGrantedIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(IAccessControlEnumerableRoleGranted) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(IAccessControlEnumerableRoleGranted) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *IAccessControlEnumerableRoleGrantedIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *IAccessControlEnumerableRoleGrantedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// IAccessControlEnumerableRoleGranted represents a RoleGranted event raised by the IAccessControlEnumerable contract. +type IAccessControlEnumerableRoleGranted struct { + Role [32]byte + Account common.Address + Sender common.Address + Raw types.Log // Blockchain specific contextual infos +} + +// FilterRoleGranted is a free log retrieval operation binding the contract event 0x2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d. +// +// Solidity: event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender) +func (_IAccessControlEnumerable *IAccessControlEnumerableFilterer) FilterRoleGranted(opts *bind.FilterOpts, role [][32]byte, account []common.Address, sender []common.Address) (*IAccessControlEnumerableRoleGrantedIterator, error) { + + var roleRule []interface{} + for _, roleItem := range role { + roleRule = append(roleRule, roleItem) + } + var accountRule []interface{} + for _, accountItem := range account { + accountRule = append(accountRule, accountItem) + } + var senderRule []interface{} + for _, senderItem := range sender { + senderRule = append(senderRule, senderItem) + } + + logs, sub, err := _IAccessControlEnumerable.contract.FilterLogs(opts, "RoleGranted", roleRule, accountRule, senderRule) + if err != nil { + return nil, err + } + return &IAccessControlEnumerableRoleGrantedIterator{contract: _IAccessControlEnumerable.contract, event: "RoleGranted", logs: logs, sub: sub}, nil +} + +// WatchRoleGranted is a free log subscription operation binding the contract event 0x2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d. +// +// Solidity: event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender) +func (_IAccessControlEnumerable *IAccessControlEnumerableFilterer) WatchRoleGranted(opts *bind.WatchOpts, sink chan<- *IAccessControlEnumerableRoleGranted, role [][32]byte, account []common.Address, sender []common.Address) (event.Subscription, error) { + + var roleRule []interface{} + for _, roleItem := range role { + roleRule = append(roleRule, roleItem) + } + var accountRule []interface{} + for _, accountItem := range account { + accountRule = append(accountRule, accountItem) + } + var senderRule []interface{} + for _, senderItem := range sender { + senderRule = append(senderRule, senderItem) + } + + logs, sub, err := _IAccessControlEnumerable.contract.WatchLogs(opts, "RoleGranted", roleRule, accountRule, senderRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(IAccessControlEnumerableRoleGranted) + if err := _IAccessControlEnumerable.contract.UnpackLog(event, "RoleGranted", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseRoleGranted is a log parse operation binding the contract event 0x2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d. +// +// Solidity: event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender) +func (_IAccessControlEnumerable *IAccessControlEnumerableFilterer) ParseRoleGranted(log types.Log) (*IAccessControlEnumerableRoleGranted, error) { + event := new(IAccessControlEnumerableRoleGranted) + if err := _IAccessControlEnumerable.contract.UnpackLog(event, "RoleGranted", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// IAccessControlEnumerableRoleRevokedIterator is returned from FilterRoleRevoked and is used to iterate over the raw logs and unpacked data for RoleRevoked events raised by the IAccessControlEnumerable contract. +type IAccessControlEnumerableRoleRevokedIterator struct { + Event *IAccessControlEnumerableRoleRevoked // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *IAccessControlEnumerableRoleRevokedIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(IAccessControlEnumerableRoleRevoked) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(IAccessControlEnumerableRoleRevoked) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *IAccessControlEnumerableRoleRevokedIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *IAccessControlEnumerableRoleRevokedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// IAccessControlEnumerableRoleRevoked represents a RoleRevoked event raised by the IAccessControlEnumerable contract. +type IAccessControlEnumerableRoleRevoked struct { + Role [32]byte + Account common.Address + Sender common.Address + Raw types.Log // Blockchain specific contextual infos +} + +// FilterRoleRevoked is a free log retrieval operation binding the contract event 0xf6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b. +// +// Solidity: event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender) +func (_IAccessControlEnumerable *IAccessControlEnumerableFilterer) FilterRoleRevoked(opts *bind.FilterOpts, role [][32]byte, account []common.Address, sender []common.Address) (*IAccessControlEnumerableRoleRevokedIterator, error) { + + var roleRule []interface{} + for _, roleItem := range role { + roleRule = append(roleRule, roleItem) + } + var accountRule []interface{} + for _, accountItem := range account { + accountRule = append(accountRule, accountItem) + } + var senderRule []interface{} + for _, senderItem := range sender { + senderRule = append(senderRule, senderItem) + } + + logs, sub, err := _IAccessControlEnumerable.contract.FilterLogs(opts, "RoleRevoked", roleRule, accountRule, senderRule) + if err != nil { + return nil, err + } + return &IAccessControlEnumerableRoleRevokedIterator{contract: _IAccessControlEnumerable.contract, event: "RoleRevoked", logs: logs, sub: sub}, nil +} + +// WatchRoleRevoked is a free log subscription operation binding the contract event 0xf6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b. +// +// Solidity: event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender) +func (_IAccessControlEnumerable *IAccessControlEnumerableFilterer) WatchRoleRevoked(opts *bind.WatchOpts, sink chan<- *IAccessControlEnumerableRoleRevoked, role [][32]byte, account []common.Address, sender []common.Address) (event.Subscription, error) { + + var roleRule []interface{} + for _, roleItem := range role { + roleRule = append(roleRule, roleItem) + } + var accountRule []interface{} + for _, accountItem := range account { + accountRule = append(accountRule, accountItem) + } + var senderRule []interface{} + for _, senderItem := range sender { + senderRule = append(senderRule, senderItem) + } + + logs, sub, err := _IAccessControlEnumerable.contract.WatchLogs(opts, "RoleRevoked", roleRule, accountRule, senderRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(IAccessControlEnumerableRoleRevoked) + if err := _IAccessControlEnumerable.contract.UnpackLog(event, "RoleRevoked", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseRoleRevoked is a log parse operation binding the contract event 0xf6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b. +// +// Solidity: event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender) +func (_IAccessControlEnumerable *IAccessControlEnumerableFilterer) ParseRoleRevoked(log types.Log) (*IAccessControlEnumerableRoleRevoked, error) { + event := new(IAccessControlEnumerableRoleRevoked) + if err := _IAccessControlEnumerable.contract.UnpackLog(event, "RoleRevoked", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// IAdminMetaData contains all meta data concerning the IAdmin contract. +var IAdminMetaData = &bind.MetaData{ + ABI: "[{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"oldChainGasAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newChainGasAmount\",\"type\":\"uint256\"}],\"name\":\"ChainGasAmountUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"oldFeeRate\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newFeeRate\",\"type\":\"uint256\"}],\"name\":\"FeeRateUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"FeesSwept\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"newChainGasAmount\",\"type\":\"uint256\"}],\"name\":\"setChainGasAmount\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"newFeeRate\",\"type\":\"uint256\"}],\"name\":\"setProtocolFeeRate\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"}],\"name\":\"sweepProtocolFees\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", + Sigs: map[string]string{ + "b250fe6b": "setChainGasAmount(uint256)", + "b13aa2d6": "setProtocolFeeRate(uint256)", + "06f333f2": "sweepProtocolFees(address,address)", + }, +} + +// IAdminABI is the input ABI used to generate the binding from. +// Deprecated: Use IAdminMetaData.ABI instead. +var IAdminABI = IAdminMetaData.ABI + +// Deprecated: Use IAdminMetaData.Sigs instead. +// IAdminFuncSigs maps the 4-byte function signature to its string representation. +var IAdminFuncSigs = IAdminMetaData.Sigs + +// IAdmin is an auto generated Go binding around an Ethereum contract. +type IAdmin struct { + IAdminCaller // Read-only binding to the contract + IAdminTransactor // Write-only binding to the contract + IAdminFilterer // Log filterer for contract events +} + +// IAdminCaller is an auto generated read-only Go binding around an Ethereum contract. +type IAdminCaller struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// IAdminTransactor is an auto generated write-only Go binding around an Ethereum contract. +type IAdminTransactor struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// IAdminFilterer is an auto generated log filtering Go binding around an Ethereum contract events. +type IAdminFilterer struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// IAdminSession is an auto generated Go binding around an Ethereum contract, +// with pre-set call and transact options. +type IAdminSession struct { + Contract *IAdmin // Generic contract binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// IAdminCallerSession is an auto generated read-only Go binding around an Ethereum contract, +// with pre-set call options. +type IAdminCallerSession struct { + Contract *IAdminCaller // Generic contract caller binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session +} + +// IAdminTransactorSession is an auto generated write-only Go binding around an Ethereum contract, +// with pre-set transact options. +type IAdminTransactorSession struct { + Contract *IAdminTransactor // Generic contract transactor binding to set the session for + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// IAdminRaw is an auto generated low-level Go binding around an Ethereum contract. +type IAdminRaw struct { + Contract *IAdmin // Generic contract binding to access the raw methods on +} + +// IAdminCallerRaw is an auto generated low-level read-only Go binding around an Ethereum contract. +type IAdminCallerRaw struct { + Contract *IAdminCaller // Generic read-only contract binding to access the raw methods on +} + +// IAdminTransactorRaw is an auto generated low-level write-only Go binding around an Ethereum contract. +type IAdminTransactorRaw struct { + Contract *IAdminTransactor // Generic write-only contract binding to access the raw methods on +} + +// NewIAdmin creates a new instance of IAdmin, bound to a specific deployed contract. +func NewIAdmin(address common.Address, backend bind.ContractBackend) (*IAdmin, error) { + contract, err := bindIAdmin(address, backend, backend, backend) + if err != nil { + return nil, err + } + return &IAdmin{IAdminCaller: IAdminCaller{contract: contract}, IAdminTransactor: IAdminTransactor{contract: contract}, IAdminFilterer: IAdminFilterer{contract: contract}}, nil +} + +// NewIAdminCaller creates a new read-only instance of IAdmin, bound to a specific deployed contract. +func NewIAdminCaller(address common.Address, caller bind.ContractCaller) (*IAdminCaller, error) { + contract, err := bindIAdmin(address, caller, nil, nil) + if err != nil { + return nil, err + } + return &IAdminCaller{contract: contract}, nil +} + +// NewIAdminTransactor creates a new write-only instance of IAdmin, bound to a specific deployed contract. +func NewIAdminTransactor(address common.Address, transactor bind.ContractTransactor) (*IAdminTransactor, error) { + contract, err := bindIAdmin(address, nil, transactor, nil) + if err != nil { + return nil, err + } + return &IAdminTransactor{contract: contract}, nil +} + +// NewIAdminFilterer creates a new log filterer instance of IAdmin, bound to a specific deployed contract. +func NewIAdminFilterer(address common.Address, filterer bind.ContractFilterer) (*IAdminFilterer, error) { + contract, err := bindIAdmin(address, nil, nil, filterer) + if err != nil { + return nil, err + } + return &IAdminFilterer{contract: contract}, nil +} + +// bindIAdmin binds a generic wrapper to an already deployed contract. +func bindIAdmin(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) { + parsed, err := IAdminMetaData.GetAbi() + if err != nil { + return nil, err + } + return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil +} + +// Call invokes the (constant) contract method with params as input values and +// sets the output to result. The result type might be a single field for simple +// returns, a slice of interfaces for anonymous returns and a struct for named +// returns. +func (_IAdmin *IAdminRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _IAdmin.Contract.IAdminCaller.contract.Call(opts, result, method, params...) +} + +// Transfer initiates a plain transaction to move funds to the contract, calling +// its default method if one is available. +func (_IAdmin *IAdminRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _IAdmin.Contract.IAdminTransactor.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_IAdmin *IAdminRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _IAdmin.Contract.IAdminTransactor.contract.Transact(opts, method, params...) +} + +// Call invokes the (constant) contract method with params as input values and +// sets the output to result. The result type might be a single field for simple +// returns, a slice of interfaces for anonymous returns and a struct for named +// returns. +func (_IAdmin *IAdminCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _IAdmin.Contract.contract.Call(opts, result, method, params...) +} + +// Transfer initiates a plain transaction to move funds to the contract, calling +// its default method if one is available. +func (_IAdmin *IAdminTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _IAdmin.Contract.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_IAdmin *IAdminTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _IAdmin.Contract.contract.Transact(opts, method, params...) +} + +// SetChainGasAmount is a paid mutator transaction binding the contract method 0xb250fe6b. +// +// Solidity: function setChainGasAmount(uint256 newChainGasAmount) returns() +func (_IAdmin *IAdminTransactor) SetChainGasAmount(opts *bind.TransactOpts, newChainGasAmount *big.Int) (*types.Transaction, error) { + return _IAdmin.contract.Transact(opts, "setChainGasAmount", newChainGasAmount) +} + +// SetChainGasAmount is a paid mutator transaction binding the contract method 0xb250fe6b. +// +// Solidity: function setChainGasAmount(uint256 newChainGasAmount) returns() +func (_IAdmin *IAdminSession) SetChainGasAmount(newChainGasAmount *big.Int) (*types.Transaction, error) { + return _IAdmin.Contract.SetChainGasAmount(&_IAdmin.TransactOpts, newChainGasAmount) +} + +// SetChainGasAmount is a paid mutator transaction binding the contract method 0xb250fe6b. +// +// Solidity: function setChainGasAmount(uint256 newChainGasAmount) returns() +func (_IAdmin *IAdminTransactorSession) SetChainGasAmount(newChainGasAmount *big.Int) (*types.Transaction, error) { + return _IAdmin.Contract.SetChainGasAmount(&_IAdmin.TransactOpts, newChainGasAmount) +} + +// SetProtocolFeeRate is a paid mutator transaction binding the contract method 0xb13aa2d6. +// +// Solidity: function setProtocolFeeRate(uint256 newFeeRate) returns() +func (_IAdmin *IAdminTransactor) SetProtocolFeeRate(opts *bind.TransactOpts, newFeeRate *big.Int) (*types.Transaction, error) { + return _IAdmin.contract.Transact(opts, "setProtocolFeeRate", newFeeRate) +} + +// SetProtocolFeeRate is a paid mutator transaction binding the contract method 0xb13aa2d6. +// +// Solidity: function setProtocolFeeRate(uint256 newFeeRate) returns() +func (_IAdmin *IAdminSession) SetProtocolFeeRate(newFeeRate *big.Int) (*types.Transaction, error) { + return _IAdmin.Contract.SetProtocolFeeRate(&_IAdmin.TransactOpts, newFeeRate) +} + +// SetProtocolFeeRate is a paid mutator transaction binding the contract method 0xb13aa2d6. +// +// Solidity: function setProtocolFeeRate(uint256 newFeeRate) returns() +func (_IAdmin *IAdminTransactorSession) SetProtocolFeeRate(newFeeRate *big.Int) (*types.Transaction, error) { + return _IAdmin.Contract.SetProtocolFeeRate(&_IAdmin.TransactOpts, newFeeRate) +} + +// SweepProtocolFees is a paid mutator transaction binding the contract method 0x06f333f2. +// +// Solidity: function sweepProtocolFees(address token, address recipient) returns() +func (_IAdmin *IAdminTransactor) SweepProtocolFees(opts *bind.TransactOpts, token common.Address, recipient common.Address) (*types.Transaction, error) { + return _IAdmin.contract.Transact(opts, "sweepProtocolFees", token, recipient) +} + +// SweepProtocolFees is a paid mutator transaction binding the contract method 0x06f333f2. +// +// Solidity: function sweepProtocolFees(address token, address recipient) returns() +func (_IAdmin *IAdminSession) SweepProtocolFees(token common.Address, recipient common.Address) (*types.Transaction, error) { + return _IAdmin.Contract.SweepProtocolFees(&_IAdmin.TransactOpts, token, recipient) +} + +// SweepProtocolFees is a paid mutator transaction binding the contract method 0x06f333f2. +// +// Solidity: function sweepProtocolFees(address token, address recipient) returns() +func (_IAdmin *IAdminTransactorSession) SweepProtocolFees(token common.Address, recipient common.Address) (*types.Transaction, error) { + return _IAdmin.Contract.SweepProtocolFees(&_IAdmin.TransactOpts, token, recipient) +} + +// IAdminChainGasAmountUpdatedIterator is returned from FilterChainGasAmountUpdated and is used to iterate over the raw logs and unpacked data for ChainGasAmountUpdated events raised by the IAdmin contract. +type IAdminChainGasAmountUpdatedIterator struct { + Event *IAdminChainGasAmountUpdated // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *IAdminChainGasAmountUpdatedIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(IAdminChainGasAmountUpdated) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(IAdminChainGasAmountUpdated) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *IAdminChainGasAmountUpdatedIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *IAdminChainGasAmountUpdatedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// IAdminChainGasAmountUpdated represents a ChainGasAmountUpdated event raised by the IAdmin contract. +type IAdminChainGasAmountUpdated struct { + OldChainGasAmount *big.Int + NewChainGasAmount *big.Int + Raw types.Log // Blockchain specific contextual infos +} + +// FilterChainGasAmountUpdated is a free log retrieval operation binding the contract event 0x5cf09b12f3f56b4c564d51b25b40360af6d795198adb61ae0806a36c294323fa. +// +// Solidity: event ChainGasAmountUpdated(uint256 oldChainGasAmount, uint256 newChainGasAmount) +func (_IAdmin *IAdminFilterer) FilterChainGasAmountUpdated(opts *bind.FilterOpts) (*IAdminChainGasAmountUpdatedIterator, error) { + + logs, sub, err := _IAdmin.contract.FilterLogs(opts, "ChainGasAmountUpdated") + if err != nil { + return nil, err + } + return &IAdminChainGasAmountUpdatedIterator{contract: _IAdmin.contract, event: "ChainGasAmountUpdated", logs: logs, sub: sub}, nil +} + +// WatchChainGasAmountUpdated is a free log subscription operation binding the contract event 0x5cf09b12f3f56b4c564d51b25b40360af6d795198adb61ae0806a36c294323fa. +// +// Solidity: event ChainGasAmountUpdated(uint256 oldChainGasAmount, uint256 newChainGasAmount) +func (_IAdmin *IAdminFilterer) WatchChainGasAmountUpdated(opts *bind.WatchOpts, sink chan<- *IAdminChainGasAmountUpdated) (event.Subscription, error) { + + logs, sub, err := _IAdmin.contract.WatchLogs(opts, "ChainGasAmountUpdated") + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(IAdminChainGasAmountUpdated) + if err := _IAdmin.contract.UnpackLog(event, "ChainGasAmountUpdated", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseChainGasAmountUpdated is a log parse operation binding the contract event 0x5cf09b12f3f56b4c564d51b25b40360af6d795198adb61ae0806a36c294323fa. +// +// Solidity: event ChainGasAmountUpdated(uint256 oldChainGasAmount, uint256 newChainGasAmount) +func (_IAdmin *IAdminFilterer) ParseChainGasAmountUpdated(log types.Log) (*IAdminChainGasAmountUpdated, error) { + event := new(IAdminChainGasAmountUpdated) + if err := _IAdmin.contract.UnpackLog(event, "ChainGasAmountUpdated", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// IAdminFeeRateUpdatedIterator is returned from FilterFeeRateUpdated and is used to iterate over the raw logs and unpacked data for FeeRateUpdated events raised by the IAdmin contract. +type IAdminFeeRateUpdatedIterator struct { + Event *IAdminFeeRateUpdated // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *IAdminFeeRateUpdatedIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(IAdminFeeRateUpdated) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(IAdminFeeRateUpdated) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *IAdminFeeRateUpdatedIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *IAdminFeeRateUpdatedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// IAdminFeeRateUpdated represents a FeeRateUpdated event raised by the IAdmin contract. +type IAdminFeeRateUpdated struct { + OldFeeRate *big.Int + NewFeeRate *big.Int + Raw types.Log // Blockchain specific contextual infos +} + +// FilterFeeRateUpdated is a free log retrieval operation binding the contract event 0x14914da2bf76024616fbe1859783fcd4dbddcb179b1f3a854949fbf920dcb957. +// +// Solidity: event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate) +func (_IAdmin *IAdminFilterer) FilterFeeRateUpdated(opts *bind.FilterOpts) (*IAdminFeeRateUpdatedIterator, error) { + + logs, sub, err := _IAdmin.contract.FilterLogs(opts, "FeeRateUpdated") + if err != nil { + return nil, err + } + return &IAdminFeeRateUpdatedIterator{contract: _IAdmin.contract, event: "FeeRateUpdated", logs: logs, sub: sub}, nil +} + +// WatchFeeRateUpdated is a free log subscription operation binding the contract event 0x14914da2bf76024616fbe1859783fcd4dbddcb179b1f3a854949fbf920dcb957. +// +// Solidity: event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate) +func (_IAdmin *IAdminFilterer) WatchFeeRateUpdated(opts *bind.WatchOpts, sink chan<- *IAdminFeeRateUpdated) (event.Subscription, error) { + + logs, sub, err := _IAdmin.contract.WatchLogs(opts, "FeeRateUpdated") + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(IAdminFeeRateUpdated) + if err := _IAdmin.contract.UnpackLog(event, "FeeRateUpdated", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseFeeRateUpdated is a log parse operation binding the contract event 0x14914da2bf76024616fbe1859783fcd4dbddcb179b1f3a854949fbf920dcb957. +// +// Solidity: event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate) +func (_IAdmin *IAdminFilterer) ParseFeeRateUpdated(log types.Log) (*IAdminFeeRateUpdated, error) { + event := new(IAdminFeeRateUpdated) + if err := _IAdmin.contract.UnpackLog(event, "FeeRateUpdated", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// IAdminFeesSweptIterator is returned from FilterFeesSwept and is used to iterate over the raw logs and unpacked data for FeesSwept events raised by the IAdmin contract. +type IAdminFeesSweptIterator struct { + Event *IAdminFeesSwept // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *IAdminFeesSweptIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(IAdminFeesSwept) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(IAdminFeesSwept) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *IAdminFeesSweptIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *IAdminFeesSweptIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// IAdminFeesSwept represents a FeesSwept event raised by the IAdmin contract. +type IAdminFeesSwept struct { + Token common.Address + Recipient common.Address + Amount *big.Int + Raw types.Log // Blockchain specific contextual infos +} + +// FilterFeesSwept is a free log retrieval operation binding the contract event 0x244e51bc38c1452fa8aaf487bcb4bca36c2baa3a5fbdb776b1eabd8dc6d277cd. +// +// Solidity: event FeesSwept(address token, address recipient, uint256 amount) +func (_IAdmin *IAdminFilterer) FilterFeesSwept(opts *bind.FilterOpts) (*IAdminFeesSweptIterator, error) { + + logs, sub, err := _IAdmin.contract.FilterLogs(opts, "FeesSwept") + if err != nil { + return nil, err + } + return &IAdminFeesSweptIterator{contract: _IAdmin.contract, event: "FeesSwept", logs: logs, sub: sub}, nil +} + +// WatchFeesSwept is a free log subscription operation binding the contract event 0x244e51bc38c1452fa8aaf487bcb4bca36c2baa3a5fbdb776b1eabd8dc6d277cd. +// +// Solidity: event FeesSwept(address token, address recipient, uint256 amount) +func (_IAdmin *IAdminFilterer) WatchFeesSwept(opts *bind.WatchOpts, sink chan<- *IAdminFeesSwept) (event.Subscription, error) { + + logs, sub, err := _IAdmin.contract.WatchLogs(opts, "FeesSwept") + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(IAdminFeesSwept) + if err := _IAdmin.contract.UnpackLog(event, "FeesSwept", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseFeesSwept is a log parse operation binding the contract event 0x244e51bc38c1452fa8aaf487bcb4bca36c2baa3a5fbdb776b1eabd8dc6d277cd. +// +// Solidity: event FeesSwept(address token, address recipient, uint256 amount) +func (_IAdmin *IAdminFilterer) ParseFeesSwept(log types.Log) (*IAdminFeesSwept, error) { + event := new(IAdminFeesSwept) + if err := _IAdmin.contract.UnpackLog(event, "FeesSwept", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// IERC165MetaData contains all meta data concerning the IERC165 contract. +var IERC165MetaData = &bind.MetaData{ + ABI: "[{\"inputs\":[{\"internalType\":\"bytes4\",\"name\":\"interfaceId\",\"type\":\"bytes4\"}],\"name\":\"supportsInterface\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"}]", + Sigs: map[string]string{ + "01ffc9a7": "supportsInterface(bytes4)", + }, +} + +// IERC165ABI is the input ABI used to generate the binding from. +// Deprecated: Use IERC165MetaData.ABI instead. +var IERC165ABI = IERC165MetaData.ABI + +// Deprecated: Use IERC165MetaData.Sigs instead. +// IERC165FuncSigs maps the 4-byte function signature to its string representation. +var IERC165FuncSigs = IERC165MetaData.Sigs + +// IERC165 is an auto generated Go binding around an Ethereum contract. +type IERC165 struct { + IERC165Caller // Read-only binding to the contract + IERC165Transactor // Write-only binding to the contract + IERC165Filterer // Log filterer for contract events +} + +// IERC165Caller is an auto generated read-only Go binding around an Ethereum contract. +type IERC165Caller struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// IERC165Transactor is an auto generated write-only Go binding around an Ethereum contract. +type IERC165Transactor struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// IERC165Filterer is an auto generated log filtering Go binding around an Ethereum contract events. +type IERC165Filterer struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// IERC165Session is an auto generated Go binding around an Ethereum contract, +// with pre-set call and transact options. +type IERC165Session struct { + Contract *IERC165 // Generic contract binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// IERC165CallerSession is an auto generated read-only Go binding around an Ethereum contract, +// with pre-set call options. +type IERC165CallerSession struct { + Contract *IERC165Caller // Generic contract caller binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session +} + +// IERC165TransactorSession is an auto generated write-only Go binding around an Ethereum contract, +// with pre-set transact options. +type IERC165TransactorSession struct { + Contract *IERC165Transactor // Generic contract transactor binding to set the session for + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// IERC165Raw is an auto generated low-level Go binding around an Ethereum contract. +type IERC165Raw struct { + Contract *IERC165 // Generic contract binding to access the raw methods on +} + +// IERC165CallerRaw is an auto generated low-level read-only Go binding around an Ethereum contract. +type IERC165CallerRaw struct { + Contract *IERC165Caller // Generic read-only contract binding to access the raw methods on +} + +// IERC165TransactorRaw is an auto generated low-level write-only Go binding around an Ethereum contract. +type IERC165TransactorRaw struct { + Contract *IERC165Transactor // Generic write-only contract binding to access the raw methods on +} + +// NewIERC165 creates a new instance of IERC165, bound to a specific deployed contract. +func NewIERC165(address common.Address, backend bind.ContractBackend) (*IERC165, error) { + contract, err := bindIERC165(address, backend, backend, backend) + if err != nil { + return nil, err + } + return &IERC165{IERC165Caller: IERC165Caller{contract: contract}, IERC165Transactor: IERC165Transactor{contract: contract}, IERC165Filterer: IERC165Filterer{contract: contract}}, nil +} + +// NewIERC165Caller creates a new read-only instance of IERC165, bound to a specific deployed contract. +func NewIERC165Caller(address common.Address, caller bind.ContractCaller) (*IERC165Caller, error) { + contract, err := bindIERC165(address, caller, nil, nil) + if err != nil { + return nil, err + } + return &IERC165Caller{contract: contract}, nil +} + +// NewIERC165Transactor creates a new write-only instance of IERC165, bound to a specific deployed contract. +func NewIERC165Transactor(address common.Address, transactor bind.ContractTransactor) (*IERC165Transactor, error) { + contract, err := bindIERC165(address, nil, transactor, nil) + if err != nil { + return nil, err + } + return &IERC165Transactor{contract: contract}, nil +} + +// NewIERC165Filterer creates a new log filterer instance of IERC165, bound to a specific deployed contract. +func NewIERC165Filterer(address common.Address, filterer bind.ContractFilterer) (*IERC165Filterer, error) { + contract, err := bindIERC165(address, nil, nil, filterer) + if err != nil { + return nil, err + } + return &IERC165Filterer{contract: contract}, nil +} + +// bindIERC165 binds a generic wrapper to an already deployed contract. +func bindIERC165(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) { + parsed, err := IERC165MetaData.GetAbi() + if err != nil { + return nil, err + } + return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil +} + +// Call invokes the (constant) contract method with params as input values and +// sets the output to result. The result type might be a single field for simple +// returns, a slice of interfaces for anonymous returns and a struct for named +// returns. +func (_IERC165 *IERC165Raw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _IERC165.Contract.IERC165Caller.contract.Call(opts, result, method, params...) +} + +// Transfer initiates a plain transaction to move funds to the contract, calling +// its default method if one is available. +func (_IERC165 *IERC165Raw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _IERC165.Contract.IERC165Transactor.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_IERC165 *IERC165Raw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _IERC165.Contract.IERC165Transactor.contract.Transact(opts, method, params...) +} + +// Call invokes the (constant) contract method with params as input values and +// sets the output to result. The result type might be a single field for simple +// returns, a slice of interfaces for anonymous returns and a struct for named +// returns. +func (_IERC165 *IERC165CallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _IERC165.Contract.contract.Call(opts, result, method, params...) +} + +// Transfer initiates a plain transaction to move funds to the contract, calling +// its default method if one is available. +func (_IERC165 *IERC165TransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _IERC165.Contract.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_IERC165 *IERC165TransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _IERC165.Contract.contract.Transact(opts, method, params...) +} + +// SupportsInterface is a free data retrieval call binding the contract method 0x01ffc9a7. +// +// Solidity: function supportsInterface(bytes4 interfaceId) view returns(bool) +func (_IERC165 *IERC165Caller) SupportsInterface(opts *bind.CallOpts, interfaceId [4]byte) (bool, error) { + var out []interface{} + err := _IERC165.contract.Call(opts, &out, "supportsInterface", interfaceId) + + if err != nil { + return *new(bool), err + } + + out0 := *abi.ConvertType(out[0], new(bool)).(*bool) + + return out0, err + +} + +// SupportsInterface is a free data retrieval call binding the contract method 0x01ffc9a7. +// +// Solidity: function supportsInterface(bytes4 interfaceId) view returns(bool) +func (_IERC165 *IERC165Session) SupportsInterface(interfaceId [4]byte) (bool, error) { + return _IERC165.Contract.SupportsInterface(&_IERC165.CallOpts, interfaceId) +} + +// SupportsInterface is a free data retrieval call binding the contract method 0x01ffc9a7. +// +// Solidity: function supportsInterface(bytes4 interfaceId) view returns(bool) +func (_IERC165 *IERC165CallerSession) SupportsInterface(interfaceId [4]byte) (bool, error) { + return _IERC165.Contract.SupportsInterface(&_IERC165.CallOpts, interfaceId) +} + +// IERC20MetaData contains all meta data concerning the IERC20 contract. +var IERC20MetaData = &bind.MetaData{ + ABI: "[{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"Approval\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"Transfer\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"}],\"name\":\"allowance\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"approve\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"balanceOf\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"totalSupply\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"transfer\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"transferFrom\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", + Sigs: map[string]string{ + "dd62ed3e": "allowance(address,address)", + "095ea7b3": "approve(address,uint256)", + "70a08231": "balanceOf(address)", + "18160ddd": "totalSupply()", + "a9059cbb": "transfer(address,uint256)", + "23b872dd": "transferFrom(address,address,uint256)", + }, +} + +// IERC20ABI is the input ABI used to generate the binding from. +// Deprecated: Use IERC20MetaData.ABI instead. +var IERC20ABI = IERC20MetaData.ABI + +// Deprecated: Use IERC20MetaData.Sigs instead. +// IERC20FuncSigs maps the 4-byte function signature to its string representation. +var IERC20FuncSigs = IERC20MetaData.Sigs + +// IERC20 is an auto generated Go binding around an Ethereum contract. +type IERC20 struct { + IERC20Caller // Read-only binding to the contract + IERC20Transactor // Write-only binding to the contract + IERC20Filterer // Log filterer for contract events +} + +// IERC20Caller is an auto generated read-only Go binding around an Ethereum contract. +type IERC20Caller struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// IERC20Transactor is an auto generated write-only Go binding around an Ethereum contract. +type IERC20Transactor struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// IERC20Filterer is an auto generated log filtering Go binding around an Ethereum contract events. +type IERC20Filterer struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// IERC20Session is an auto generated Go binding around an Ethereum contract, +// with pre-set call and transact options. +type IERC20Session struct { + Contract *IERC20 // Generic contract binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// IERC20CallerSession is an auto generated read-only Go binding around an Ethereum contract, +// with pre-set call options. +type IERC20CallerSession struct { + Contract *IERC20Caller // Generic contract caller binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session +} + +// IERC20TransactorSession is an auto generated write-only Go binding around an Ethereum contract, +// with pre-set transact options. +type IERC20TransactorSession struct { + Contract *IERC20Transactor // Generic contract transactor binding to set the session for + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// IERC20Raw is an auto generated low-level Go binding around an Ethereum contract. +type IERC20Raw struct { + Contract *IERC20 // Generic contract binding to access the raw methods on +} + +// IERC20CallerRaw is an auto generated low-level read-only Go binding around an Ethereum contract. +type IERC20CallerRaw struct { + Contract *IERC20Caller // Generic read-only contract binding to access the raw methods on +} + +// IERC20TransactorRaw is an auto generated low-level write-only Go binding around an Ethereum contract. +type IERC20TransactorRaw struct { + Contract *IERC20Transactor // Generic write-only contract binding to access the raw methods on +} + +// NewIERC20 creates a new instance of IERC20, bound to a specific deployed contract. +func NewIERC20(address common.Address, backend bind.ContractBackend) (*IERC20, error) { + contract, err := bindIERC20(address, backend, backend, backend) + if err != nil { + return nil, err + } + return &IERC20{IERC20Caller: IERC20Caller{contract: contract}, IERC20Transactor: IERC20Transactor{contract: contract}, IERC20Filterer: IERC20Filterer{contract: contract}}, nil +} + +// NewIERC20Caller creates a new read-only instance of IERC20, bound to a specific deployed contract. +func NewIERC20Caller(address common.Address, caller bind.ContractCaller) (*IERC20Caller, error) { + contract, err := bindIERC20(address, caller, nil, nil) + if err != nil { + return nil, err + } + return &IERC20Caller{contract: contract}, nil +} + +// NewIERC20Transactor creates a new write-only instance of IERC20, bound to a specific deployed contract. +func NewIERC20Transactor(address common.Address, transactor bind.ContractTransactor) (*IERC20Transactor, error) { + contract, err := bindIERC20(address, nil, transactor, nil) + if err != nil { + return nil, err + } + return &IERC20Transactor{contract: contract}, nil +} + +// NewIERC20Filterer creates a new log filterer instance of IERC20, bound to a specific deployed contract. +func NewIERC20Filterer(address common.Address, filterer bind.ContractFilterer) (*IERC20Filterer, error) { + contract, err := bindIERC20(address, nil, nil, filterer) + if err != nil { + return nil, err + } + return &IERC20Filterer{contract: contract}, nil +} + +// bindIERC20 binds a generic wrapper to an already deployed contract. +func bindIERC20(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) { + parsed, err := IERC20MetaData.GetAbi() + if err != nil { + return nil, err + } + return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil +} + +// Call invokes the (constant) contract method with params as input values and +// sets the output to result. The result type might be a single field for simple +// returns, a slice of interfaces for anonymous returns and a struct for named +// returns. +func (_IERC20 *IERC20Raw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _IERC20.Contract.IERC20Caller.contract.Call(opts, result, method, params...) +} + +// Transfer initiates a plain transaction to move funds to the contract, calling +// its default method if one is available. +func (_IERC20 *IERC20Raw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _IERC20.Contract.IERC20Transactor.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_IERC20 *IERC20Raw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _IERC20.Contract.IERC20Transactor.contract.Transact(opts, method, params...) +} + +// Call invokes the (constant) contract method with params as input values and +// sets the output to result. The result type might be a single field for simple +// returns, a slice of interfaces for anonymous returns and a struct for named +// returns. +func (_IERC20 *IERC20CallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _IERC20.Contract.contract.Call(opts, result, method, params...) +} + +// Transfer initiates a plain transaction to move funds to the contract, calling +// its default method if one is available. +func (_IERC20 *IERC20TransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _IERC20.Contract.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_IERC20 *IERC20TransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _IERC20.Contract.contract.Transact(opts, method, params...) +} + +// Allowance is a free data retrieval call binding the contract method 0xdd62ed3e. +// +// Solidity: function allowance(address owner, address spender) view returns(uint256) +func (_IERC20 *IERC20Caller) Allowance(opts *bind.CallOpts, owner common.Address, spender common.Address) (*big.Int, error) { + var out []interface{} + err := _IERC20.contract.Call(opts, &out, "allowance", owner, spender) + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// Allowance is a free data retrieval call binding the contract method 0xdd62ed3e. +// +// Solidity: function allowance(address owner, address spender) view returns(uint256) +func (_IERC20 *IERC20Session) Allowance(owner common.Address, spender common.Address) (*big.Int, error) { + return _IERC20.Contract.Allowance(&_IERC20.CallOpts, owner, spender) +} + +// Allowance is a free data retrieval call binding the contract method 0xdd62ed3e. +// +// Solidity: function allowance(address owner, address spender) view returns(uint256) +func (_IERC20 *IERC20CallerSession) Allowance(owner common.Address, spender common.Address) (*big.Int, error) { + return _IERC20.Contract.Allowance(&_IERC20.CallOpts, owner, spender) +} + +// BalanceOf is a free data retrieval call binding the contract method 0x70a08231. +// +// Solidity: function balanceOf(address account) view returns(uint256) +func (_IERC20 *IERC20Caller) BalanceOf(opts *bind.CallOpts, account common.Address) (*big.Int, error) { + var out []interface{} + err := _IERC20.contract.Call(opts, &out, "balanceOf", account) + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// BalanceOf is a free data retrieval call binding the contract method 0x70a08231. +// +// Solidity: function balanceOf(address account) view returns(uint256) +func (_IERC20 *IERC20Session) BalanceOf(account common.Address) (*big.Int, error) { + return _IERC20.Contract.BalanceOf(&_IERC20.CallOpts, account) +} + +// BalanceOf is a free data retrieval call binding the contract method 0x70a08231. +// +// Solidity: function balanceOf(address account) view returns(uint256) +func (_IERC20 *IERC20CallerSession) BalanceOf(account common.Address) (*big.Int, error) { + return _IERC20.Contract.BalanceOf(&_IERC20.CallOpts, account) +} + +// TotalSupply is a free data retrieval call binding the contract method 0x18160ddd. +// +// Solidity: function totalSupply() view returns(uint256) +func (_IERC20 *IERC20Caller) TotalSupply(opts *bind.CallOpts) (*big.Int, error) { + var out []interface{} + err := _IERC20.contract.Call(opts, &out, "totalSupply") + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// TotalSupply is a free data retrieval call binding the contract method 0x18160ddd. +// +// Solidity: function totalSupply() view returns(uint256) +func (_IERC20 *IERC20Session) TotalSupply() (*big.Int, error) { + return _IERC20.Contract.TotalSupply(&_IERC20.CallOpts) +} + +// TotalSupply is a free data retrieval call binding the contract method 0x18160ddd. +// +// Solidity: function totalSupply() view returns(uint256) +func (_IERC20 *IERC20CallerSession) TotalSupply() (*big.Int, error) { + return _IERC20.Contract.TotalSupply(&_IERC20.CallOpts) +} + +// Approve is a paid mutator transaction binding the contract method 0x095ea7b3. +// +// Solidity: function approve(address spender, uint256 value) returns(bool) +func (_IERC20 *IERC20Transactor) Approve(opts *bind.TransactOpts, spender common.Address, value *big.Int) (*types.Transaction, error) { + return _IERC20.contract.Transact(opts, "approve", spender, value) +} + +// Approve is a paid mutator transaction binding the contract method 0x095ea7b3. +// +// Solidity: function approve(address spender, uint256 value) returns(bool) +func (_IERC20 *IERC20Session) Approve(spender common.Address, value *big.Int) (*types.Transaction, error) { + return _IERC20.Contract.Approve(&_IERC20.TransactOpts, spender, value) +} + +// Approve is a paid mutator transaction binding the contract method 0x095ea7b3. +// +// Solidity: function approve(address spender, uint256 value) returns(bool) +func (_IERC20 *IERC20TransactorSession) Approve(spender common.Address, value *big.Int) (*types.Transaction, error) { + return _IERC20.Contract.Approve(&_IERC20.TransactOpts, spender, value) +} + +// Transfer is a paid mutator transaction binding the contract method 0xa9059cbb. +// +// Solidity: function transfer(address to, uint256 value) returns(bool) +func (_IERC20 *IERC20Transactor) Transfer(opts *bind.TransactOpts, to common.Address, value *big.Int) (*types.Transaction, error) { + return _IERC20.contract.Transact(opts, "transfer", to, value) +} + +// Transfer is a paid mutator transaction binding the contract method 0xa9059cbb. +// +// Solidity: function transfer(address to, uint256 value) returns(bool) +func (_IERC20 *IERC20Session) Transfer(to common.Address, value *big.Int) (*types.Transaction, error) { + return _IERC20.Contract.Transfer(&_IERC20.TransactOpts, to, value) +} + +// Transfer is a paid mutator transaction binding the contract method 0xa9059cbb. +// +// Solidity: function transfer(address to, uint256 value) returns(bool) +func (_IERC20 *IERC20TransactorSession) Transfer(to common.Address, value *big.Int) (*types.Transaction, error) { + return _IERC20.Contract.Transfer(&_IERC20.TransactOpts, to, value) +} + +// TransferFrom is a paid mutator transaction binding the contract method 0x23b872dd. +// +// Solidity: function transferFrom(address from, address to, uint256 value) returns(bool) +func (_IERC20 *IERC20Transactor) TransferFrom(opts *bind.TransactOpts, from common.Address, to common.Address, value *big.Int) (*types.Transaction, error) { + return _IERC20.contract.Transact(opts, "transferFrom", from, to, value) +} + +// TransferFrom is a paid mutator transaction binding the contract method 0x23b872dd. +// +// Solidity: function transferFrom(address from, address to, uint256 value) returns(bool) +func (_IERC20 *IERC20Session) TransferFrom(from common.Address, to common.Address, value *big.Int) (*types.Transaction, error) { + return _IERC20.Contract.TransferFrom(&_IERC20.TransactOpts, from, to, value) +} + +// TransferFrom is a paid mutator transaction binding the contract method 0x23b872dd. +// +// Solidity: function transferFrom(address from, address to, uint256 value) returns(bool) +func (_IERC20 *IERC20TransactorSession) TransferFrom(from common.Address, to common.Address, value *big.Int) (*types.Transaction, error) { + return _IERC20.Contract.TransferFrom(&_IERC20.TransactOpts, from, to, value) +} + +// IERC20ApprovalIterator is returned from FilterApproval and is used to iterate over the raw logs and unpacked data for Approval events raised by the IERC20 contract. +type IERC20ApprovalIterator struct { + Event *IERC20Approval // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *IERC20ApprovalIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(IERC20Approval) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(IERC20Approval) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *IERC20ApprovalIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *IERC20ApprovalIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// IERC20Approval represents a Approval event raised by the IERC20 contract. +type IERC20Approval struct { + Owner common.Address + Spender common.Address + Value *big.Int + Raw types.Log // Blockchain specific contextual infos +} + +// FilterApproval is a free log retrieval operation binding the contract event 0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925. +// +// Solidity: event Approval(address indexed owner, address indexed spender, uint256 value) +func (_IERC20 *IERC20Filterer) FilterApproval(opts *bind.FilterOpts, owner []common.Address, spender []common.Address) (*IERC20ApprovalIterator, error) { + + var ownerRule []interface{} + for _, ownerItem := range owner { + ownerRule = append(ownerRule, ownerItem) + } + var spenderRule []interface{} + for _, spenderItem := range spender { + spenderRule = append(spenderRule, spenderItem) + } + + logs, sub, err := _IERC20.contract.FilterLogs(opts, "Approval", ownerRule, spenderRule) + if err != nil { + return nil, err + } + return &IERC20ApprovalIterator{contract: _IERC20.contract, event: "Approval", logs: logs, sub: sub}, nil +} + +// WatchApproval is a free log subscription operation binding the contract event 0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925. +// +// Solidity: event Approval(address indexed owner, address indexed spender, uint256 value) +func (_IERC20 *IERC20Filterer) WatchApproval(opts *bind.WatchOpts, sink chan<- *IERC20Approval, owner []common.Address, spender []common.Address) (event.Subscription, error) { + + var ownerRule []interface{} + for _, ownerItem := range owner { + ownerRule = append(ownerRule, ownerItem) + } + var spenderRule []interface{} + for _, spenderItem := range spender { + spenderRule = append(spenderRule, spenderItem) + } + + logs, sub, err := _IERC20.contract.WatchLogs(opts, "Approval", ownerRule, spenderRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(IERC20Approval) + if err := _IERC20.contract.UnpackLog(event, "Approval", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseApproval is a log parse operation binding the contract event 0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925. +// +// Solidity: event Approval(address indexed owner, address indexed spender, uint256 value) +func (_IERC20 *IERC20Filterer) ParseApproval(log types.Log) (*IERC20Approval, error) { + event := new(IERC20Approval) + if err := _IERC20.contract.UnpackLog(event, "Approval", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// IERC20TransferIterator is returned from FilterTransfer and is used to iterate over the raw logs and unpacked data for Transfer events raised by the IERC20 contract. +type IERC20TransferIterator struct { + Event *IERC20Transfer // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *IERC20TransferIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(IERC20Transfer) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(IERC20Transfer) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *IERC20TransferIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *IERC20TransferIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// IERC20Transfer represents a Transfer event raised by the IERC20 contract. +type IERC20Transfer struct { + From common.Address + To common.Address + Value *big.Int + Raw types.Log // Blockchain specific contextual infos +} + +// FilterTransfer is a free log retrieval operation binding the contract event 0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef. +// +// Solidity: event Transfer(address indexed from, address indexed to, uint256 value) +func (_IERC20 *IERC20Filterer) FilterTransfer(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*IERC20TransferIterator, error) { + + var fromRule []interface{} + for _, fromItem := range from { + fromRule = append(fromRule, fromItem) + } + var toRule []interface{} + for _, toItem := range to { + toRule = append(toRule, toItem) + } + + logs, sub, err := _IERC20.contract.FilterLogs(opts, "Transfer", fromRule, toRule) + if err != nil { + return nil, err + } + return &IERC20TransferIterator{contract: _IERC20.contract, event: "Transfer", logs: logs, sub: sub}, nil +} + +// WatchTransfer is a free log subscription operation binding the contract event 0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef. +// +// Solidity: event Transfer(address indexed from, address indexed to, uint256 value) +func (_IERC20 *IERC20Filterer) WatchTransfer(opts *bind.WatchOpts, sink chan<- *IERC20Transfer, from []common.Address, to []common.Address) (event.Subscription, error) { + + var fromRule []interface{} + for _, fromItem := range from { + fromRule = append(fromRule, fromItem) + } + var toRule []interface{} + for _, toItem := range to { + toRule = append(toRule, toItem) + } + + logs, sub, err := _IERC20.contract.WatchLogs(opts, "Transfer", fromRule, toRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(IERC20Transfer) + if err := _IERC20.contract.UnpackLog(event, "Transfer", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseTransfer is a log parse operation binding the contract event 0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef. +// +// Solidity: event Transfer(address indexed from, address indexed to, uint256 value) +func (_IERC20 *IERC20Filterer) ParseTransfer(log types.Log) (*IERC20Transfer, error) { + event := new(IERC20Transfer) + if err := _IERC20.contract.UnpackLog(event, "Transfer", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// IERC20PermitMetaData contains all meta data concerning the IERC20Permit contract. +var IERC20PermitMetaData = &bind.MetaData{ + ABI: "[{\"inputs\":[],\"name\":\"DOMAIN_SEPARATOR\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"}],\"name\":\"nonces\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"},{\"internalType\":\"uint8\",\"name\":\"v\",\"type\":\"uint8\"},{\"internalType\":\"bytes32\",\"name\":\"r\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"s\",\"type\":\"bytes32\"}],\"name\":\"permit\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", + Sigs: map[string]string{ + "3644e515": "DOMAIN_SEPARATOR()", + "7ecebe00": "nonces(address)", + "d505accf": "permit(address,address,uint256,uint256,uint8,bytes32,bytes32)", + }, +} + +// IERC20PermitABI is the input ABI used to generate the binding from. +// Deprecated: Use IERC20PermitMetaData.ABI instead. +var IERC20PermitABI = IERC20PermitMetaData.ABI + +// Deprecated: Use IERC20PermitMetaData.Sigs instead. +// IERC20PermitFuncSigs maps the 4-byte function signature to its string representation. +var IERC20PermitFuncSigs = IERC20PermitMetaData.Sigs + +// IERC20Permit is an auto generated Go binding around an Ethereum contract. +type IERC20Permit struct { + IERC20PermitCaller // Read-only binding to the contract + IERC20PermitTransactor // Write-only binding to the contract + IERC20PermitFilterer // Log filterer for contract events +} + +// IERC20PermitCaller is an auto generated read-only Go binding around an Ethereum contract. +type IERC20PermitCaller struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// IERC20PermitTransactor is an auto generated write-only Go binding around an Ethereum contract. +type IERC20PermitTransactor struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// IERC20PermitFilterer is an auto generated log filtering Go binding around an Ethereum contract events. +type IERC20PermitFilterer struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// IERC20PermitSession is an auto generated Go binding around an Ethereum contract, +// with pre-set call and transact options. +type IERC20PermitSession struct { + Contract *IERC20Permit // Generic contract binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// IERC20PermitCallerSession is an auto generated read-only Go binding around an Ethereum contract, +// with pre-set call options. +type IERC20PermitCallerSession struct { + Contract *IERC20PermitCaller // Generic contract caller binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session +} + +// IERC20PermitTransactorSession is an auto generated write-only Go binding around an Ethereum contract, +// with pre-set transact options. +type IERC20PermitTransactorSession struct { + Contract *IERC20PermitTransactor // Generic contract transactor binding to set the session for + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// IERC20PermitRaw is an auto generated low-level Go binding around an Ethereum contract. +type IERC20PermitRaw struct { + Contract *IERC20Permit // Generic contract binding to access the raw methods on +} + +// IERC20PermitCallerRaw is an auto generated low-level read-only Go binding around an Ethereum contract. +type IERC20PermitCallerRaw struct { + Contract *IERC20PermitCaller // Generic read-only contract binding to access the raw methods on +} + +// IERC20PermitTransactorRaw is an auto generated low-level write-only Go binding around an Ethereum contract. +type IERC20PermitTransactorRaw struct { + Contract *IERC20PermitTransactor // Generic write-only contract binding to access the raw methods on +} + +// NewIERC20Permit creates a new instance of IERC20Permit, bound to a specific deployed contract. +func NewIERC20Permit(address common.Address, backend bind.ContractBackend) (*IERC20Permit, error) { + contract, err := bindIERC20Permit(address, backend, backend, backend) + if err != nil { + return nil, err + } + return &IERC20Permit{IERC20PermitCaller: IERC20PermitCaller{contract: contract}, IERC20PermitTransactor: IERC20PermitTransactor{contract: contract}, IERC20PermitFilterer: IERC20PermitFilterer{contract: contract}}, nil +} + +// NewIERC20PermitCaller creates a new read-only instance of IERC20Permit, bound to a specific deployed contract. +func NewIERC20PermitCaller(address common.Address, caller bind.ContractCaller) (*IERC20PermitCaller, error) { + contract, err := bindIERC20Permit(address, caller, nil, nil) + if err != nil { + return nil, err + } + return &IERC20PermitCaller{contract: contract}, nil +} + +// NewIERC20PermitTransactor creates a new write-only instance of IERC20Permit, bound to a specific deployed contract. +func NewIERC20PermitTransactor(address common.Address, transactor bind.ContractTransactor) (*IERC20PermitTransactor, error) { + contract, err := bindIERC20Permit(address, nil, transactor, nil) + if err != nil { + return nil, err + } + return &IERC20PermitTransactor{contract: contract}, nil +} + +// NewIERC20PermitFilterer creates a new log filterer instance of IERC20Permit, bound to a specific deployed contract. +func NewIERC20PermitFilterer(address common.Address, filterer bind.ContractFilterer) (*IERC20PermitFilterer, error) { + contract, err := bindIERC20Permit(address, nil, nil, filterer) + if err != nil { + return nil, err + } + return &IERC20PermitFilterer{contract: contract}, nil +} + +// bindIERC20Permit binds a generic wrapper to an already deployed contract. +func bindIERC20Permit(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) { + parsed, err := IERC20PermitMetaData.GetAbi() + if err != nil { + return nil, err + } + return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil +} + +// Call invokes the (constant) contract method with params as input values and +// sets the output to result. The result type might be a single field for simple +// returns, a slice of interfaces for anonymous returns and a struct for named +// returns. +func (_IERC20Permit *IERC20PermitRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _IERC20Permit.Contract.IERC20PermitCaller.contract.Call(opts, result, method, params...) +} + +// Transfer initiates a plain transaction to move funds to the contract, calling +// its default method if one is available. +func (_IERC20Permit *IERC20PermitRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _IERC20Permit.Contract.IERC20PermitTransactor.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_IERC20Permit *IERC20PermitRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _IERC20Permit.Contract.IERC20PermitTransactor.contract.Transact(opts, method, params...) +} + +// Call invokes the (constant) contract method with params as input values and +// sets the output to result. The result type might be a single field for simple +// returns, a slice of interfaces for anonymous returns and a struct for named +// returns. +func (_IERC20Permit *IERC20PermitCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _IERC20Permit.Contract.contract.Call(opts, result, method, params...) +} + +// Transfer initiates a plain transaction to move funds to the contract, calling +// its default method if one is available. +func (_IERC20Permit *IERC20PermitTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _IERC20Permit.Contract.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_IERC20Permit *IERC20PermitTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _IERC20Permit.Contract.contract.Transact(opts, method, params...) +} + +// DOMAINSEPARATOR is a free data retrieval call binding the contract method 0x3644e515. +// +// Solidity: function DOMAIN_SEPARATOR() view returns(bytes32) +func (_IERC20Permit *IERC20PermitCaller) DOMAINSEPARATOR(opts *bind.CallOpts) ([32]byte, error) { + var out []interface{} + err := _IERC20Permit.contract.Call(opts, &out, "DOMAIN_SEPARATOR") + + if err != nil { + return *new([32]byte), err + } + + out0 := *abi.ConvertType(out[0], new([32]byte)).(*[32]byte) + + return out0, err + +} + +// DOMAINSEPARATOR is a free data retrieval call binding the contract method 0x3644e515. +// +// Solidity: function DOMAIN_SEPARATOR() view returns(bytes32) +func (_IERC20Permit *IERC20PermitSession) DOMAINSEPARATOR() ([32]byte, error) { + return _IERC20Permit.Contract.DOMAINSEPARATOR(&_IERC20Permit.CallOpts) +} + +// DOMAINSEPARATOR is a free data retrieval call binding the contract method 0x3644e515. +// +// Solidity: function DOMAIN_SEPARATOR() view returns(bytes32) +func (_IERC20Permit *IERC20PermitCallerSession) DOMAINSEPARATOR() ([32]byte, error) { + return _IERC20Permit.Contract.DOMAINSEPARATOR(&_IERC20Permit.CallOpts) +} + +// Nonces is a free data retrieval call binding the contract method 0x7ecebe00. +// +// Solidity: function nonces(address owner) view returns(uint256) +func (_IERC20Permit *IERC20PermitCaller) Nonces(opts *bind.CallOpts, owner common.Address) (*big.Int, error) { + var out []interface{} + err := _IERC20Permit.contract.Call(opts, &out, "nonces", owner) + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// Nonces is a free data retrieval call binding the contract method 0x7ecebe00. +// +// Solidity: function nonces(address owner) view returns(uint256) +func (_IERC20Permit *IERC20PermitSession) Nonces(owner common.Address) (*big.Int, error) { + return _IERC20Permit.Contract.Nonces(&_IERC20Permit.CallOpts, owner) +} + +// Nonces is a free data retrieval call binding the contract method 0x7ecebe00. +// +// Solidity: function nonces(address owner) view returns(uint256) +func (_IERC20Permit *IERC20PermitCallerSession) Nonces(owner common.Address) (*big.Int, error) { + return _IERC20Permit.Contract.Nonces(&_IERC20Permit.CallOpts, owner) +} + +// Permit is a paid mutator transaction binding the contract method 0xd505accf. +// +// Solidity: function permit(address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) returns() +func (_IERC20Permit *IERC20PermitTransactor) Permit(opts *bind.TransactOpts, owner common.Address, spender common.Address, value *big.Int, deadline *big.Int, v uint8, r [32]byte, s [32]byte) (*types.Transaction, error) { + return _IERC20Permit.contract.Transact(opts, "permit", owner, spender, value, deadline, v, r, s) +} + +// Permit is a paid mutator transaction binding the contract method 0xd505accf. +// +// Solidity: function permit(address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) returns() +func (_IERC20Permit *IERC20PermitSession) Permit(owner common.Address, spender common.Address, value *big.Int, deadline *big.Int, v uint8, r [32]byte, s [32]byte) (*types.Transaction, error) { + return _IERC20Permit.Contract.Permit(&_IERC20Permit.TransactOpts, owner, spender, value, deadline, v, r, s) +} + +// Permit is a paid mutator transaction binding the contract method 0xd505accf. +// +// Solidity: function permit(address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) returns() +func (_IERC20Permit *IERC20PermitTransactorSession) Permit(owner common.Address, spender common.Address, value *big.Int, deadline *big.Int, v uint8, r [32]byte, s [32]byte) (*types.Transaction, error) { + return _IERC20Permit.Contract.Permit(&_IERC20Permit.TransactOpts, owner, spender, value, deadline, v, r, s) +} + +// IFastBridgeMetaData contains all meta data concerning the IFastBridge contract. +var IFastBridgeMetaData = &bind.MetaData{ + ABI: "[{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"BridgeDepositClaimed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"BridgeDepositRefunded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"name\":\"BridgeProofDisputed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"transactionHash\",\"type\":\"bytes32\"}],\"name\":\"BridgeProofProvided\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"originChainId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"chainGasAmount\",\"type\":\"uint256\"}],\"name\":\"BridgeRelayed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"destChainId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"sendChainGas\",\"type\":\"bool\"}],\"name\":\"BridgeRequested\",\"type\":\"event\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"dstChainId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"sendChainGas\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"}],\"internalType\":\"structIFastBridge.BridgeParams\",\"name\":\"params\",\"type\":\"tuple\"}],\"name\":\"bridge\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"name\":\"canClaim\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"claim\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"}],\"name\":\"dispute\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"getBridgeTransaction\",\"outputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"originChainId\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"destChainId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"originSender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destRecipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"originFeeAmount\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"sendChainGas\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"}],\"internalType\":\"structIFastBridge.BridgeTransaction\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"},{\"internalType\":\"bytes32\",\"name\":\"destTxHash\",\"type\":\"bytes32\"}],\"name\":\"prove\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"refund\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"relay\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"}]", + Sigs: map[string]string{ + "45851694": "bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256))", + "aa9641ab": "canClaim(bytes32,address)", + "41fcb612": "claim(bytes,address)", + "add98c70": "dispute(bytes32)", + "ac11fb1a": "getBridgeTransaction(bytes)", + "886d36ff": "prove(bytes,bytes32)", + "5eb7d946": "refund(bytes)", + "8f0d6f17": "relay(bytes)", + }, +} + +// IFastBridgeABI is the input ABI used to generate the binding from. +// Deprecated: Use IFastBridgeMetaData.ABI instead. +var IFastBridgeABI = IFastBridgeMetaData.ABI + +// Deprecated: Use IFastBridgeMetaData.Sigs instead. +// IFastBridgeFuncSigs maps the 4-byte function signature to its string representation. +var IFastBridgeFuncSigs = IFastBridgeMetaData.Sigs + +// IFastBridge is an auto generated Go binding around an Ethereum contract. +type IFastBridge struct { + IFastBridgeCaller // Read-only binding to the contract + IFastBridgeTransactor // Write-only binding to the contract + IFastBridgeFilterer // Log filterer for contract events +} + +// IFastBridgeCaller is an auto generated read-only Go binding around an Ethereum contract. +type IFastBridgeCaller struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// IFastBridgeTransactor is an auto generated write-only Go binding around an Ethereum contract. +type IFastBridgeTransactor struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// IFastBridgeFilterer is an auto generated log filtering Go binding around an Ethereum contract events. +type IFastBridgeFilterer struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// IFastBridgeSession is an auto generated Go binding around an Ethereum contract, +// with pre-set call and transact options. +type IFastBridgeSession struct { + Contract *IFastBridge // Generic contract binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// IFastBridgeCallerSession is an auto generated read-only Go binding around an Ethereum contract, +// with pre-set call options. +type IFastBridgeCallerSession struct { + Contract *IFastBridgeCaller // Generic contract caller binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session +} + +// IFastBridgeTransactorSession is an auto generated write-only Go binding around an Ethereum contract, +// with pre-set transact options. +type IFastBridgeTransactorSession struct { + Contract *IFastBridgeTransactor // Generic contract transactor binding to set the session for + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// IFastBridgeRaw is an auto generated low-level Go binding around an Ethereum contract. +type IFastBridgeRaw struct { + Contract *IFastBridge // Generic contract binding to access the raw methods on +} + +// IFastBridgeCallerRaw is an auto generated low-level read-only Go binding around an Ethereum contract. +type IFastBridgeCallerRaw struct { + Contract *IFastBridgeCaller // Generic read-only contract binding to access the raw methods on +} + +// IFastBridgeTransactorRaw is an auto generated low-level write-only Go binding around an Ethereum contract. +type IFastBridgeTransactorRaw struct { + Contract *IFastBridgeTransactor // Generic write-only contract binding to access the raw methods on +} + +// NewIFastBridge creates a new instance of IFastBridge, bound to a specific deployed contract. +func NewIFastBridge(address common.Address, backend bind.ContractBackend) (*IFastBridge, error) { + contract, err := bindIFastBridge(address, backend, backend, backend) + if err != nil { + return nil, err + } + return &IFastBridge{IFastBridgeCaller: IFastBridgeCaller{contract: contract}, IFastBridgeTransactor: IFastBridgeTransactor{contract: contract}, IFastBridgeFilterer: IFastBridgeFilterer{contract: contract}}, nil +} + +// NewIFastBridgeCaller creates a new read-only instance of IFastBridge, bound to a specific deployed contract. +func NewIFastBridgeCaller(address common.Address, caller bind.ContractCaller) (*IFastBridgeCaller, error) { + contract, err := bindIFastBridge(address, caller, nil, nil) + if err != nil { + return nil, err + } + return &IFastBridgeCaller{contract: contract}, nil +} + +// NewIFastBridgeTransactor creates a new write-only instance of IFastBridge, bound to a specific deployed contract. +func NewIFastBridgeTransactor(address common.Address, transactor bind.ContractTransactor) (*IFastBridgeTransactor, error) { + contract, err := bindIFastBridge(address, nil, transactor, nil) + if err != nil { + return nil, err + } + return &IFastBridgeTransactor{contract: contract}, nil +} + +// NewIFastBridgeFilterer creates a new log filterer instance of IFastBridge, bound to a specific deployed contract. +func NewIFastBridgeFilterer(address common.Address, filterer bind.ContractFilterer) (*IFastBridgeFilterer, error) { + contract, err := bindIFastBridge(address, nil, nil, filterer) + if err != nil { + return nil, err + } + return &IFastBridgeFilterer{contract: contract}, nil +} + +// bindIFastBridge binds a generic wrapper to an already deployed contract. +func bindIFastBridge(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) { + parsed, err := IFastBridgeMetaData.GetAbi() + if err != nil { + return nil, err + } + return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil +} + +// Call invokes the (constant) contract method with params as input values and +// sets the output to result. The result type might be a single field for simple +// returns, a slice of interfaces for anonymous returns and a struct for named +// returns. +func (_IFastBridge *IFastBridgeRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _IFastBridge.Contract.IFastBridgeCaller.contract.Call(opts, result, method, params...) +} + +// Transfer initiates a plain transaction to move funds to the contract, calling +// its default method if one is available. +func (_IFastBridge *IFastBridgeRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _IFastBridge.Contract.IFastBridgeTransactor.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_IFastBridge *IFastBridgeRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _IFastBridge.Contract.IFastBridgeTransactor.contract.Transact(opts, method, params...) +} + +// Call invokes the (constant) contract method with params as input values and +// sets the output to result. The result type might be a single field for simple +// returns, a slice of interfaces for anonymous returns and a struct for named +// returns. +func (_IFastBridge *IFastBridgeCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _IFastBridge.Contract.contract.Call(opts, result, method, params...) +} + +// Transfer initiates a plain transaction to move funds to the contract, calling +// its default method if one is available. +func (_IFastBridge *IFastBridgeTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _IFastBridge.Contract.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_IFastBridge *IFastBridgeTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _IFastBridge.Contract.contract.Transact(opts, method, params...) +} + +// CanClaim is a free data retrieval call binding the contract method 0xaa9641ab. +// +// Solidity: function canClaim(bytes32 transactionId, address relayer) view returns(bool) +func (_IFastBridge *IFastBridgeCaller) CanClaim(opts *bind.CallOpts, transactionId [32]byte, relayer common.Address) (bool, error) { + var out []interface{} + err := _IFastBridge.contract.Call(opts, &out, "canClaim", transactionId, relayer) + + if err != nil { + return *new(bool), err + } + + out0 := *abi.ConvertType(out[0], new(bool)).(*bool) + + return out0, err + +} + +// CanClaim is a free data retrieval call binding the contract method 0xaa9641ab. +// +// Solidity: function canClaim(bytes32 transactionId, address relayer) view returns(bool) +func (_IFastBridge *IFastBridgeSession) CanClaim(transactionId [32]byte, relayer common.Address) (bool, error) { + return _IFastBridge.Contract.CanClaim(&_IFastBridge.CallOpts, transactionId, relayer) +} + +// CanClaim is a free data retrieval call binding the contract method 0xaa9641ab. +// +// Solidity: function canClaim(bytes32 transactionId, address relayer) view returns(bool) +func (_IFastBridge *IFastBridgeCallerSession) CanClaim(transactionId [32]byte, relayer common.Address) (bool, error) { + return _IFastBridge.Contract.CanClaim(&_IFastBridge.CallOpts, transactionId, relayer) +} + +// GetBridgeTransaction is a free data retrieval call binding the contract method 0xac11fb1a. +// +// Solidity: function getBridgeTransaction(bytes request) view returns((uint32,uint32,address,address,address,address,uint256,uint256,uint256,bool,uint256,uint256)) +func (_IFastBridge *IFastBridgeCaller) GetBridgeTransaction(opts *bind.CallOpts, request []byte) (IFastBridgeBridgeTransaction, error) { + var out []interface{} + err := _IFastBridge.contract.Call(opts, &out, "getBridgeTransaction", request) + + if err != nil { + return *new(IFastBridgeBridgeTransaction), err + } + + out0 := *abi.ConvertType(out[0], new(IFastBridgeBridgeTransaction)).(*IFastBridgeBridgeTransaction) + + return out0, err + +} + +// GetBridgeTransaction is a free data retrieval call binding the contract method 0xac11fb1a. +// +// Solidity: function getBridgeTransaction(bytes request) view returns((uint32,uint32,address,address,address,address,uint256,uint256,uint256,bool,uint256,uint256)) +func (_IFastBridge *IFastBridgeSession) GetBridgeTransaction(request []byte) (IFastBridgeBridgeTransaction, error) { + return _IFastBridge.Contract.GetBridgeTransaction(&_IFastBridge.CallOpts, request) +} + +// GetBridgeTransaction is a free data retrieval call binding the contract method 0xac11fb1a. +// +// Solidity: function getBridgeTransaction(bytes request) view returns((uint32,uint32,address,address,address,address,uint256,uint256,uint256,bool,uint256,uint256)) +func (_IFastBridge *IFastBridgeCallerSession) GetBridgeTransaction(request []byte) (IFastBridgeBridgeTransaction, error) { + return _IFastBridge.Contract.GetBridgeTransaction(&_IFastBridge.CallOpts, request) +} + +// Bridge is a paid mutator transaction binding the contract method 0x45851694. +// +// Solidity: function bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256) params) payable returns() +func (_IFastBridge *IFastBridgeTransactor) Bridge(opts *bind.TransactOpts, params IFastBridgeBridgeParams) (*types.Transaction, error) { + return _IFastBridge.contract.Transact(opts, "bridge", params) +} + +// Bridge is a paid mutator transaction binding the contract method 0x45851694. +// +// Solidity: function bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256) params) payable returns() +func (_IFastBridge *IFastBridgeSession) Bridge(params IFastBridgeBridgeParams) (*types.Transaction, error) { + return _IFastBridge.Contract.Bridge(&_IFastBridge.TransactOpts, params) +} + +// Bridge is a paid mutator transaction binding the contract method 0x45851694. +// +// Solidity: function bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256) params) payable returns() +func (_IFastBridge *IFastBridgeTransactorSession) Bridge(params IFastBridgeBridgeParams) (*types.Transaction, error) { + return _IFastBridge.Contract.Bridge(&_IFastBridge.TransactOpts, params) +} + +// Claim is a paid mutator transaction binding the contract method 0x41fcb612. +// +// Solidity: function claim(bytes request, address to) returns() +func (_IFastBridge *IFastBridgeTransactor) Claim(opts *bind.TransactOpts, request []byte, to common.Address) (*types.Transaction, error) { + return _IFastBridge.contract.Transact(opts, "claim", request, to) +} + +// Claim is a paid mutator transaction binding the contract method 0x41fcb612. +// +// Solidity: function claim(bytes request, address to) returns() +func (_IFastBridge *IFastBridgeSession) Claim(request []byte, to common.Address) (*types.Transaction, error) { + return _IFastBridge.Contract.Claim(&_IFastBridge.TransactOpts, request, to) +} + +// Claim is a paid mutator transaction binding the contract method 0x41fcb612. +// +// Solidity: function claim(bytes request, address to) returns() +func (_IFastBridge *IFastBridgeTransactorSession) Claim(request []byte, to common.Address) (*types.Transaction, error) { + return _IFastBridge.Contract.Claim(&_IFastBridge.TransactOpts, request, to) +} + +// Dispute is a paid mutator transaction binding the contract method 0xadd98c70. +// +// Solidity: function dispute(bytes32 transactionId) returns() +func (_IFastBridge *IFastBridgeTransactor) Dispute(opts *bind.TransactOpts, transactionId [32]byte) (*types.Transaction, error) { + return _IFastBridge.contract.Transact(opts, "dispute", transactionId) +} + +// Dispute is a paid mutator transaction binding the contract method 0xadd98c70. +// +// Solidity: function dispute(bytes32 transactionId) returns() +func (_IFastBridge *IFastBridgeSession) Dispute(transactionId [32]byte) (*types.Transaction, error) { + return _IFastBridge.Contract.Dispute(&_IFastBridge.TransactOpts, transactionId) +} + +// Dispute is a paid mutator transaction binding the contract method 0xadd98c70. +// +// Solidity: function dispute(bytes32 transactionId) returns() +func (_IFastBridge *IFastBridgeTransactorSession) Dispute(transactionId [32]byte) (*types.Transaction, error) { + return _IFastBridge.Contract.Dispute(&_IFastBridge.TransactOpts, transactionId) +} + +// Prove is a paid mutator transaction binding the contract method 0x886d36ff. +// +// Solidity: function prove(bytes request, bytes32 destTxHash) returns() +func (_IFastBridge *IFastBridgeTransactor) Prove(opts *bind.TransactOpts, request []byte, destTxHash [32]byte) (*types.Transaction, error) { + return _IFastBridge.contract.Transact(opts, "prove", request, destTxHash) +} + +// Prove is a paid mutator transaction binding the contract method 0x886d36ff. +// +// Solidity: function prove(bytes request, bytes32 destTxHash) returns() +func (_IFastBridge *IFastBridgeSession) Prove(request []byte, destTxHash [32]byte) (*types.Transaction, error) { + return _IFastBridge.Contract.Prove(&_IFastBridge.TransactOpts, request, destTxHash) +} + +// Prove is a paid mutator transaction binding the contract method 0x886d36ff. +// +// Solidity: function prove(bytes request, bytes32 destTxHash) returns() +func (_IFastBridge *IFastBridgeTransactorSession) Prove(request []byte, destTxHash [32]byte) (*types.Transaction, error) { + return _IFastBridge.Contract.Prove(&_IFastBridge.TransactOpts, request, destTxHash) +} + +// Refund is a paid mutator transaction binding the contract method 0x5eb7d946. +// +// Solidity: function refund(bytes request) returns() +func (_IFastBridge *IFastBridgeTransactor) Refund(opts *bind.TransactOpts, request []byte) (*types.Transaction, error) { + return _IFastBridge.contract.Transact(opts, "refund", request) +} + +// Refund is a paid mutator transaction binding the contract method 0x5eb7d946. +// +// Solidity: function refund(bytes request) returns() +func (_IFastBridge *IFastBridgeSession) Refund(request []byte) (*types.Transaction, error) { + return _IFastBridge.Contract.Refund(&_IFastBridge.TransactOpts, request) +} + +// Refund is a paid mutator transaction binding the contract method 0x5eb7d946. +// +// Solidity: function refund(bytes request) returns() +func (_IFastBridge *IFastBridgeTransactorSession) Refund(request []byte) (*types.Transaction, error) { + return _IFastBridge.Contract.Refund(&_IFastBridge.TransactOpts, request) +} + +// Relay is a paid mutator transaction binding the contract method 0x8f0d6f17. +// +// Solidity: function relay(bytes request) payable returns() +func (_IFastBridge *IFastBridgeTransactor) Relay(opts *bind.TransactOpts, request []byte) (*types.Transaction, error) { + return _IFastBridge.contract.Transact(opts, "relay", request) +} + +// Relay is a paid mutator transaction binding the contract method 0x8f0d6f17. +// +// Solidity: function relay(bytes request) payable returns() +func (_IFastBridge *IFastBridgeSession) Relay(request []byte) (*types.Transaction, error) { + return _IFastBridge.Contract.Relay(&_IFastBridge.TransactOpts, request) +} + +// Relay is a paid mutator transaction binding the contract method 0x8f0d6f17. +// +// Solidity: function relay(bytes request) payable returns() +func (_IFastBridge *IFastBridgeTransactorSession) Relay(request []byte) (*types.Transaction, error) { + return _IFastBridge.Contract.Relay(&_IFastBridge.TransactOpts, request) +} + +// IFastBridgeBridgeDepositClaimedIterator is returned from FilterBridgeDepositClaimed and is used to iterate over the raw logs and unpacked data for BridgeDepositClaimed events raised by the IFastBridge contract. +type IFastBridgeBridgeDepositClaimedIterator struct { + Event *IFastBridgeBridgeDepositClaimed // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *IFastBridgeBridgeDepositClaimedIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(IFastBridgeBridgeDepositClaimed) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(IFastBridgeBridgeDepositClaimed) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *IFastBridgeBridgeDepositClaimedIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *IFastBridgeBridgeDepositClaimedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// IFastBridgeBridgeDepositClaimed represents a BridgeDepositClaimed event raised by the IFastBridge contract. +type IFastBridgeBridgeDepositClaimed struct { + TransactionId [32]byte + Relayer common.Address + To common.Address + Token common.Address + Amount *big.Int + Raw types.Log // Blockchain specific contextual infos +} + +// FilterBridgeDepositClaimed is a free log retrieval operation binding the contract event 0x582211c35a2139ac3bbaac74663c6a1f56c6cbb658b41fe11fd45a82074ac678. +// +// Solidity: event BridgeDepositClaimed(bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount) +func (_IFastBridge *IFastBridgeFilterer) FilterBridgeDepositClaimed(opts *bind.FilterOpts, transactionId [][32]byte, relayer []common.Address, to []common.Address) (*IFastBridgeBridgeDepositClaimedIterator, error) { + + var transactionIdRule []interface{} + for _, transactionIdItem := range transactionId { + transactionIdRule = append(transactionIdRule, transactionIdItem) + } + var relayerRule []interface{} + for _, relayerItem := range relayer { + relayerRule = append(relayerRule, relayerItem) + } + var toRule []interface{} + for _, toItem := range to { + toRule = append(toRule, toItem) + } + + logs, sub, err := _IFastBridge.contract.FilterLogs(opts, "BridgeDepositClaimed", transactionIdRule, relayerRule, toRule) + if err != nil { + return nil, err + } + return &IFastBridgeBridgeDepositClaimedIterator{contract: _IFastBridge.contract, event: "BridgeDepositClaimed", logs: logs, sub: sub}, nil +} + +// WatchBridgeDepositClaimed is a free log subscription operation binding the contract event 0x582211c35a2139ac3bbaac74663c6a1f56c6cbb658b41fe11fd45a82074ac678. +// +// Solidity: event BridgeDepositClaimed(bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount) +func (_IFastBridge *IFastBridgeFilterer) WatchBridgeDepositClaimed(opts *bind.WatchOpts, sink chan<- *IFastBridgeBridgeDepositClaimed, transactionId [][32]byte, relayer []common.Address, to []common.Address) (event.Subscription, error) { + + var transactionIdRule []interface{} + for _, transactionIdItem := range transactionId { + transactionIdRule = append(transactionIdRule, transactionIdItem) + } + var relayerRule []interface{} + for _, relayerItem := range relayer { + relayerRule = append(relayerRule, relayerItem) + } + var toRule []interface{} + for _, toItem := range to { + toRule = append(toRule, toItem) + } + + logs, sub, err := _IFastBridge.contract.WatchLogs(opts, "BridgeDepositClaimed", transactionIdRule, relayerRule, toRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(IFastBridgeBridgeDepositClaimed) + if err := _IFastBridge.contract.UnpackLog(event, "BridgeDepositClaimed", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseBridgeDepositClaimed is a log parse operation binding the contract event 0x582211c35a2139ac3bbaac74663c6a1f56c6cbb658b41fe11fd45a82074ac678. +// +// Solidity: event BridgeDepositClaimed(bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount) +func (_IFastBridge *IFastBridgeFilterer) ParseBridgeDepositClaimed(log types.Log) (*IFastBridgeBridgeDepositClaimed, error) { + event := new(IFastBridgeBridgeDepositClaimed) + if err := _IFastBridge.contract.UnpackLog(event, "BridgeDepositClaimed", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// IFastBridgeBridgeDepositRefundedIterator is returned from FilterBridgeDepositRefunded and is used to iterate over the raw logs and unpacked data for BridgeDepositRefunded events raised by the IFastBridge contract. +type IFastBridgeBridgeDepositRefundedIterator struct { + Event *IFastBridgeBridgeDepositRefunded // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *IFastBridgeBridgeDepositRefundedIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(IFastBridgeBridgeDepositRefunded) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(IFastBridgeBridgeDepositRefunded) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *IFastBridgeBridgeDepositRefundedIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *IFastBridgeBridgeDepositRefundedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// IFastBridgeBridgeDepositRefunded represents a BridgeDepositRefunded event raised by the IFastBridge contract. +type IFastBridgeBridgeDepositRefunded struct { + TransactionId [32]byte + To common.Address + Token common.Address + Amount *big.Int + Raw types.Log // Blockchain specific contextual infos +} + +// FilterBridgeDepositRefunded is a free log retrieval operation binding the contract event 0xb4c55c0c9bc613519b920e88748090150b890a875d307f21bea7d4fb2e8bc958. +// +// Solidity: event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount) +func (_IFastBridge *IFastBridgeFilterer) FilterBridgeDepositRefunded(opts *bind.FilterOpts, transactionId [][32]byte, to []common.Address) (*IFastBridgeBridgeDepositRefundedIterator, error) { + + var transactionIdRule []interface{} + for _, transactionIdItem := range transactionId { + transactionIdRule = append(transactionIdRule, transactionIdItem) + } + var toRule []interface{} + for _, toItem := range to { + toRule = append(toRule, toItem) + } + + logs, sub, err := _IFastBridge.contract.FilterLogs(opts, "BridgeDepositRefunded", transactionIdRule, toRule) + if err != nil { + return nil, err + } + return &IFastBridgeBridgeDepositRefundedIterator{contract: _IFastBridge.contract, event: "BridgeDepositRefunded", logs: logs, sub: sub}, nil +} + +// WatchBridgeDepositRefunded is a free log subscription operation binding the contract event 0xb4c55c0c9bc613519b920e88748090150b890a875d307f21bea7d4fb2e8bc958. +// +// Solidity: event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount) +func (_IFastBridge *IFastBridgeFilterer) WatchBridgeDepositRefunded(opts *bind.WatchOpts, sink chan<- *IFastBridgeBridgeDepositRefunded, transactionId [][32]byte, to []common.Address) (event.Subscription, error) { + + var transactionIdRule []interface{} + for _, transactionIdItem := range transactionId { + transactionIdRule = append(transactionIdRule, transactionIdItem) + } + var toRule []interface{} + for _, toItem := range to { + toRule = append(toRule, toItem) + } + + logs, sub, err := _IFastBridge.contract.WatchLogs(opts, "BridgeDepositRefunded", transactionIdRule, toRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(IFastBridgeBridgeDepositRefunded) + if err := _IFastBridge.contract.UnpackLog(event, "BridgeDepositRefunded", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseBridgeDepositRefunded is a log parse operation binding the contract event 0xb4c55c0c9bc613519b920e88748090150b890a875d307f21bea7d4fb2e8bc958. +// +// Solidity: event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount) +func (_IFastBridge *IFastBridgeFilterer) ParseBridgeDepositRefunded(log types.Log) (*IFastBridgeBridgeDepositRefunded, error) { + event := new(IFastBridgeBridgeDepositRefunded) + if err := _IFastBridge.contract.UnpackLog(event, "BridgeDepositRefunded", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// IFastBridgeBridgeProofDisputedIterator is returned from FilterBridgeProofDisputed and is used to iterate over the raw logs and unpacked data for BridgeProofDisputed events raised by the IFastBridge contract. +type IFastBridgeBridgeProofDisputedIterator struct { + Event *IFastBridgeBridgeProofDisputed // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *IFastBridgeBridgeProofDisputedIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(IFastBridgeBridgeProofDisputed) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(IFastBridgeBridgeProofDisputed) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *IFastBridgeBridgeProofDisputedIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *IFastBridgeBridgeProofDisputedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// IFastBridgeBridgeProofDisputed represents a BridgeProofDisputed event raised by the IFastBridge contract. +type IFastBridgeBridgeProofDisputed struct { + TransactionId [32]byte + Relayer common.Address + Raw types.Log // Blockchain specific contextual infos +} + +// FilterBridgeProofDisputed is a free log retrieval operation binding the contract event 0x0695cf1d39b3055dcd0fe02d8b47eaf0d5a13e1996de925de59d0ef9b7f7fad4. +// +// Solidity: event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer) +func (_IFastBridge *IFastBridgeFilterer) FilterBridgeProofDisputed(opts *bind.FilterOpts, transactionId [][32]byte, relayer []common.Address) (*IFastBridgeBridgeProofDisputedIterator, error) { + + var transactionIdRule []interface{} + for _, transactionIdItem := range transactionId { + transactionIdRule = append(transactionIdRule, transactionIdItem) + } + var relayerRule []interface{} + for _, relayerItem := range relayer { + relayerRule = append(relayerRule, relayerItem) + } + + logs, sub, err := _IFastBridge.contract.FilterLogs(opts, "BridgeProofDisputed", transactionIdRule, relayerRule) + if err != nil { + return nil, err + } + return &IFastBridgeBridgeProofDisputedIterator{contract: _IFastBridge.contract, event: "BridgeProofDisputed", logs: logs, sub: sub}, nil +} + +// WatchBridgeProofDisputed is a free log subscription operation binding the contract event 0x0695cf1d39b3055dcd0fe02d8b47eaf0d5a13e1996de925de59d0ef9b7f7fad4. +// +// Solidity: event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer) +func (_IFastBridge *IFastBridgeFilterer) WatchBridgeProofDisputed(opts *bind.WatchOpts, sink chan<- *IFastBridgeBridgeProofDisputed, transactionId [][32]byte, relayer []common.Address) (event.Subscription, error) { + + var transactionIdRule []interface{} + for _, transactionIdItem := range transactionId { + transactionIdRule = append(transactionIdRule, transactionIdItem) + } + var relayerRule []interface{} + for _, relayerItem := range relayer { + relayerRule = append(relayerRule, relayerItem) + } + + logs, sub, err := _IFastBridge.contract.WatchLogs(opts, "BridgeProofDisputed", transactionIdRule, relayerRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(IFastBridgeBridgeProofDisputed) + if err := _IFastBridge.contract.UnpackLog(event, "BridgeProofDisputed", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseBridgeProofDisputed is a log parse operation binding the contract event 0x0695cf1d39b3055dcd0fe02d8b47eaf0d5a13e1996de925de59d0ef9b7f7fad4. +// +// Solidity: event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer) +func (_IFastBridge *IFastBridgeFilterer) ParseBridgeProofDisputed(log types.Log) (*IFastBridgeBridgeProofDisputed, error) { + event := new(IFastBridgeBridgeProofDisputed) + if err := _IFastBridge.contract.UnpackLog(event, "BridgeProofDisputed", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// IFastBridgeBridgeProofProvidedIterator is returned from FilterBridgeProofProvided and is used to iterate over the raw logs and unpacked data for BridgeProofProvided events raised by the IFastBridge contract. +type IFastBridgeBridgeProofProvidedIterator struct { + Event *IFastBridgeBridgeProofProvided // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *IFastBridgeBridgeProofProvidedIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(IFastBridgeBridgeProofProvided) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(IFastBridgeBridgeProofProvided) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *IFastBridgeBridgeProofProvidedIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *IFastBridgeBridgeProofProvidedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// IFastBridgeBridgeProofProvided represents a BridgeProofProvided event raised by the IFastBridge contract. +type IFastBridgeBridgeProofProvided struct { + TransactionId [32]byte + Relayer common.Address + TransactionHash [32]byte + Raw types.Log // Blockchain specific contextual infos +} + +// FilterBridgeProofProvided is a free log retrieval operation binding the contract event 0x4ac8af8a2cd87193d64dfc7a3b8d9923b714ec528b18725d080aa1299be0c5e4. +// +// Solidity: event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash) +func (_IFastBridge *IFastBridgeFilterer) FilterBridgeProofProvided(opts *bind.FilterOpts, transactionId [][32]byte, relayer []common.Address) (*IFastBridgeBridgeProofProvidedIterator, error) { + + var transactionIdRule []interface{} + for _, transactionIdItem := range transactionId { + transactionIdRule = append(transactionIdRule, transactionIdItem) + } + var relayerRule []interface{} + for _, relayerItem := range relayer { + relayerRule = append(relayerRule, relayerItem) + } + + logs, sub, err := _IFastBridge.contract.FilterLogs(opts, "BridgeProofProvided", transactionIdRule, relayerRule) + if err != nil { + return nil, err + } + return &IFastBridgeBridgeProofProvidedIterator{contract: _IFastBridge.contract, event: "BridgeProofProvided", logs: logs, sub: sub}, nil +} + +// WatchBridgeProofProvided is a free log subscription operation binding the contract event 0x4ac8af8a2cd87193d64dfc7a3b8d9923b714ec528b18725d080aa1299be0c5e4. +// +// Solidity: event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash) +func (_IFastBridge *IFastBridgeFilterer) WatchBridgeProofProvided(opts *bind.WatchOpts, sink chan<- *IFastBridgeBridgeProofProvided, transactionId [][32]byte, relayer []common.Address) (event.Subscription, error) { + + var transactionIdRule []interface{} + for _, transactionIdItem := range transactionId { + transactionIdRule = append(transactionIdRule, transactionIdItem) + } + var relayerRule []interface{} + for _, relayerItem := range relayer { + relayerRule = append(relayerRule, relayerItem) + } + + logs, sub, err := _IFastBridge.contract.WatchLogs(opts, "BridgeProofProvided", transactionIdRule, relayerRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(IFastBridgeBridgeProofProvided) + if err := _IFastBridge.contract.UnpackLog(event, "BridgeProofProvided", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseBridgeProofProvided is a log parse operation binding the contract event 0x4ac8af8a2cd87193d64dfc7a3b8d9923b714ec528b18725d080aa1299be0c5e4. +// +// Solidity: event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash) +func (_IFastBridge *IFastBridgeFilterer) ParseBridgeProofProvided(log types.Log) (*IFastBridgeBridgeProofProvided, error) { + event := new(IFastBridgeBridgeProofProvided) + if err := _IFastBridge.contract.UnpackLog(event, "BridgeProofProvided", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// IFastBridgeBridgeRelayedIterator is returned from FilterBridgeRelayed and is used to iterate over the raw logs and unpacked data for BridgeRelayed events raised by the IFastBridge contract. +type IFastBridgeBridgeRelayedIterator struct { + Event *IFastBridgeBridgeRelayed // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *IFastBridgeBridgeRelayedIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(IFastBridgeBridgeRelayed) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(IFastBridgeBridgeRelayed) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *IFastBridgeBridgeRelayedIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *IFastBridgeBridgeRelayedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// IFastBridgeBridgeRelayed represents a BridgeRelayed event raised by the IFastBridge contract. +type IFastBridgeBridgeRelayed struct { + TransactionId [32]byte + Relayer common.Address + To common.Address + OriginChainId uint32 + OriginToken common.Address + DestToken common.Address + OriginAmount *big.Int + DestAmount *big.Int + ChainGasAmount *big.Int + Raw types.Log // Blockchain specific contextual infos +} + +// FilterBridgeRelayed is a free log retrieval operation binding the contract event 0xf8ae392d784b1ea5e8881bfa586d81abf07ef4f1e2fc75f7fe51c90f05199a5c. +// +// Solidity: event BridgeRelayed(bytes32 indexed transactionId, address indexed relayer, address indexed to, uint32 originChainId, address originToken, address destToken, uint256 originAmount, uint256 destAmount, uint256 chainGasAmount) +func (_IFastBridge *IFastBridgeFilterer) FilterBridgeRelayed(opts *bind.FilterOpts, transactionId [][32]byte, relayer []common.Address, to []common.Address) (*IFastBridgeBridgeRelayedIterator, error) { + + var transactionIdRule []interface{} + for _, transactionIdItem := range transactionId { + transactionIdRule = append(transactionIdRule, transactionIdItem) + } + var relayerRule []interface{} + for _, relayerItem := range relayer { + relayerRule = append(relayerRule, relayerItem) + } + var toRule []interface{} + for _, toItem := range to { + toRule = append(toRule, toItem) + } + + logs, sub, err := _IFastBridge.contract.FilterLogs(opts, "BridgeRelayed", transactionIdRule, relayerRule, toRule) + if err != nil { + return nil, err + } + return &IFastBridgeBridgeRelayedIterator{contract: _IFastBridge.contract, event: "BridgeRelayed", logs: logs, sub: sub}, nil +} + +// WatchBridgeRelayed is a free log subscription operation binding the contract event 0xf8ae392d784b1ea5e8881bfa586d81abf07ef4f1e2fc75f7fe51c90f05199a5c. +// +// Solidity: event BridgeRelayed(bytes32 indexed transactionId, address indexed relayer, address indexed to, uint32 originChainId, address originToken, address destToken, uint256 originAmount, uint256 destAmount, uint256 chainGasAmount) +func (_IFastBridge *IFastBridgeFilterer) WatchBridgeRelayed(opts *bind.WatchOpts, sink chan<- *IFastBridgeBridgeRelayed, transactionId [][32]byte, relayer []common.Address, to []common.Address) (event.Subscription, error) { + + var transactionIdRule []interface{} + for _, transactionIdItem := range transactionId { + transactionIdRule = append(transactionIdRule, transactionIdItem) + } + var relayerRule []interface{} + for _, relayerItem := range relayer { + relayerRule = append(relayerRule, relayerItem) + } + var toRule []interface{} + for _, toItem := range to { + toRule = append(toRule, toItem) + } + + logs, sub, err := _IFastBridge.contract.WatchLogs(opts, "BridgeRelayed", transactionIdRule, relayerRule, toRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(IFastBridgeBridgeRelayed) + if err := _IFastBridge.contract.UnpackLog(event, "BridgeRelayed", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseBridgeRelayed is a log parse operation binding the contract event 0xf8ae392d784b1ea5e8881bfa586d81abf07ef4f1e2fc75f7fe51c90f05199a5c. +// +// Solidity: event BridgeRelayed(bytes32 indexed transactionId, address indexed relayer, address indexed to, uint32 originChainId, address originToken, address destToken, uint256 originAmount, uint256 destAmount, uint256 chainGasAmount) +func (_IFastBridge *IFastBridgeFilterer) ParseBridgeRelayed(log types.Log) (*IFastBridgeBridgeRelayed, error) { + event := new(IFastBridgeBridgeRelayed) + if err := _IFastBridge.contract.UnpackLog(event, "BridgeRelayed", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// IFastBridgeBridgeRequestedIterator is returned from FilterBridgeRequested and is used to iterate over the raw logs and unpacked data for BridgeRequested events raised by the IFastBridge contract. +type IFastBridgeBridgeRequestedIterator struct { + Event *IFastBridgeBridgeRequested // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *IFastBridgeBridgeRequestedIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(IFastBridgeBridgeRequested) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(IFastBridgeBridgeRequested) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *IFastBridgeBridgeRequestedIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *IFastBridgeBridgeRequestedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// IFastBridgeBridgeRequested represents a BridgeRequested event raised by the IFastBridge contract. +type IFastBridgeBridgeRequested struct { + TransactionId [32]byte + Sender common.Address + Request []byte + DestChainId uint32 + OriginToken common.Address + DestToken common.Address + OriginAmount *big.Int + DestAmount *big.Int + SendChainGas bool + Raw types.Log // Blockchain specific contextual infos +} + +// FilterBridgeRequested is a free log retrieval operation binding the contract event 0x120ea0364f36cdac7983bcfdd55270ca09d7f9b314a2ebc425a3b01ab1d6403a. +// +// Solidity: event BridgeRequested(bytes32 indexed transactionId, address indexed sender, bytes request, uint32 destChainId, address originToken, address destToken, uint256 originAmount, uint256 destAmount, bool sendChainGas) +func (_IFastBridge *IFastBridgeFilterer) FilterBridgeRequested(opts *bind.FilterOpts, transactionId [][32]byte, sender []common.Address) (*IFastBridgeBridgeRequestedIterator, error) { + + var transactionIdRule []interface{} + for _, transactionIdItem := range transactionId { + transactionIdRule = append(transactionIdRule, transactionIdItem) + } + var senderRule []interface{} + for _, senderItem := range sender { + senderRule = append(senderRule, senderItem) + } + + logs, sub, err := _IFastBridge.contract.FilterLogs(opts, "BridgeRequested", transactionIdRule, senderRule) + if err != nil { + return nil, err + } + return &IFastBridgeBridgeRequestedIterator{contract: _IFastBridge.contract, event: "BridgeRequested", logs: logs, sub: sub}, nil +} + +// WatchBridgeRequested is a free log subscription operation binding the contract event 0x120ea0364f36cdac7983bcfdd55270ca09d7f9b314a2ebc425a3b01ab1d6403a. +// +// Solidity: event BridgeRequested(bytes32 indexed transactionId, address indexed sender, bytes request, uint32 destChainId, address originToken, address destToken, uint256 originAmount, uint256 destAmount, bool sendChainGas) +func (_IFastBridge *IFastBridgeFilterer) WatchBridgeRequested(opts *bind.WatchOpts, sink chan<- *IFastBridgeBridgeRequested, transactionId [][32]byte, sender []common.Address) (event.Subscription, error) { + + var transactionIdRule []interface{} + for _, transactionIdItem := range transactionId { + transactionIdRule = append(transactionIdRule, transactionIdItem) + } + var senderRule []interface{} + for _, senderItem := range sender { + senderRule = append(senderRule, senderItem) + } + + logs, sub, err := _IFastBridge.contract.WatchLogs(opts, "BridgeRequested", transactionIdRule, senderRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(IFastBridgeBridgeRequested) + if err := _IFastBridge.contract.UnpackLog(event, "BridgeRequested", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseBridgeRequested is a log parse operation binding the contract event 0x120ea0364f36cdac7983bcfdd55270ca09d7f9b314a2ebc425a3b01ab1d6403a. +// +// Solidity: event BridgeRequested(bytes32 indexed transactionId, address indexed sender, bytes request, uint32 destChainId, address originToken, address destToken, uint256 originAmount, uint256 destAmount, bool sendChainGas) +func (_IFastBridge *IFastBridgeFilterer) ParseBridgeRequested(log types.Log) (*IFastBridgeBridgeRequested, error) { + event := new(IFastBridgeBridgeRequested) + if err := _IFastBridge.contract.UnpackLog(event, "BridgeRequested", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// SafeERC20MetaData contains all meta data concerning the SafeERC20 contract. +var SafeERC20MetaData = &bind.MetaData{ + ABI: "[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"currentAllowance\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"requestedDecrease\",\"type\":\"uint256\"}],\"name\":\"SafeERC20FailedDecreaseAllowance\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"}],\"name\":\"SafeERC20FailedOperation\",\"type\":\"error\"}]", + Bin: "0x60566037600b82828239805160001a607314602a57634e487b7160e01b600052600060045260246000fd5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600080fdfea2646970667358221220c9ee2b1c91328c4f3496cd535cd06e2517aa82f2297fd1e3b5006b41112840f764736f6c63430008140033", +} + +// SafeERC20ABI is the input ABI used to generate the binding from. +// Deprecated: Use SafeERC20MetaData.ABI instead. +var SafeERC20ABI = SafeERC20MetaData.ABI + +// SafeERC20Bin is the compiled bytecode used for deploying new contracts. +// Deprecated: Use SafeERC20MetaData.Bin instead. +var SafeERC20Bin = SafeERC20MetaData.Bin + +// DeploySafeERC20 deploys a new Ethereum contract, binding an instance of SafeERC20 to it. +func DeploySafeERC20(auth *bind.TransactOpts, backend bind.ContractBackend) (common.Address, *types.Transaction, *SafeERC20, error) { + parsed, err := SafeERC20MetaData.GetAbi() + if err != nil { + return common.Address{}, nil, nil, err + } + if parsed == nil { + return common.Address{}, nil, nil, errors.New("GetABI returned nil") + } + + address, tx, contract, err := bind.DeployContract(auth, *parsed, common.FromHex(SafeERC20Bin), backend) + if err != nil { + return common.Address{}, nil, nil, err + } + return address, tx, &SafeERC20{SafeERC20Caller: SafeERC20Caller{contract: contract}, SafeERC20Transactor: SafeERC20Transactor{contract: contract}, SafeERC20Filterer: SafeERC20Filterer{contract: contract}}, nil +} + +// SafeERC20 is an auto generated Go binding around an Ethereum contract. +type SafeERC20 struct { + SafeERC20Caller // Read-only binding to the contract + SafeERC20Transactor // Write-only binding to the contract + SafeERC20Filterer // Log filterer for contract events +} + +// SafeERC20Caller is an auto generated read-only Go binding around an Ethereum contract. +type SafeERC20Caller struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// SafeERC20Transactor is an auto generated write-only Go binding around an Ethereum contract. +type SafeERC20Transactor struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// SafeERC20Filterer is an auto generated log filtering Go binding around an Ethereum contract events. +type SafeERC20Filterer struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// SafeERC20Session is an auto generated Go binding around an Ethereum contract, +// with pre-set call and transact options. +type SafeERC20Session struct { + Contract *SafeERC20 // Generic contract binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// SafeERC20CallerSession is an auto generated read-only Go binding around an Ethereum contract, +// with pre-set call options. +type SafeERC20CallerSession struct { + Contract *SafeERC20Caller // Generic contract caller binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session +} + +// SafeERC20TransactorSession is an auto generated write-only Go binding around an Ethereum contract, +// with pre-set transact options. +type SafeERC20TransactorSession struct { + Contract *SafeERC20Transactor // Generic contract transactor binding to set the session for + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// SafeERC20Raw is an auto generated low-level Go binding around an Ethereum contract. +type SafeERC20Raw struct { + Contract *SafeERC20 // Generic contract binding to access the raw methods on +} + +// SafeERC20CallerRaw is an auto generated low-level read-only Go binding around an Ethereum contract. +type SafeERC20CallerRaw struct { + Contract *SafeERC20Caller // Generic read-only contract binding to access the raw methods on +} + +// SafeERC20TransactorRaw is an auto generated low-level write-only Go binding around an Ethereum contract. +type SafeERC20TransactorRaw struct { + Contract *SafeERC20Transactor // Generic write-only contract binding to access the raw methods on +} + +// NewSafeERC20 creates a new instance of SafeERC20, bound to a specific deployed contract. +func NewSafeERC20(address common.Address, backend bind.ContractBackend) (*SafeERC20, error) { + contract, err := bindSafeERC20(address, backend, backend, backend) + if err != nil { + return nil, err + } + return &SafeERC20{SafeERC20Caller: SafeERC20Caller{contract: contract}, SafeERC20Transactor: SafeERC20Transactor{contract: contract}, SafeERC20Filterer: SafeERC20Filterer{contract: contract}}, nil +} + +// NewSafeERC20Caller creates a new read-only instance of SafeERC20, bound to a specific deployed contract. +func NewSafeERC20Caller(address common.Address, caller bind.ContractCaller) (*SafeERC20Caller, error) { + contract, err := bindSafeERC20(address, caller, nil, nil) + if err != nil { + return nil, err + } + return &SafeERC20Caller{contract: contract}, nil +} + +// NewSafeERC20Transactor creates a new write-only instance of SafeERC20, bound to a specific deployed contract. +func NewSafeERC20Transactor(address common.Address, transactor bind.ContractTransactor) (*SafeERC20Transactor, error) { + contract, err := bindSafeERC20(address, nil, transactor, nil) + if err != nil { + return nil, err + } + return &SafeERC20Transactor{contract: contract}, nil +} + +// NewSafeERC20Filterer creates a new log filterer instance of SafeERC20, bound to a specific deployed contract. +func NewSafeERC20Filterer(address common.Address, filterer bind.ContractFilterer) (*SafeERC20Filterer, error) { + contract, err := bindSafeERC20(address, nil, nil, filterer) + if err != nil { + return nil, err + } + return &SafeERC20Filterer{contract: contract}, nil +} + +// bindSafeERC20 binds a generic wrapper to an already deployed contract. +func bindSafeERC20(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) { + parsed, err := SafeERC20MetaData.GetAbi() + if err != nil { + return nil, err + } + return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil +} + +// Call invokes the (constant) contract method with params as input values and +// sets the output to result. The result type might be a single field for simple +// returns, a slice of interfaces for anonymous returns and a struct for named +// returns. +func (_SafeERC20 *SafeERC20Raw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _SafeERC20.Contract.SafeERC20Caller.contract.Call(opts, result, method, params...) +} + +// Transfer initiates a plain transaction to move funds to the contract, calling +// its default method if one is available. +func (_SafeERC20 *SafeERC20Raw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _SafeERC20.Contract.SafeERC20Transactor.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_SafeERC20 *SafeERC20Raw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _SafeERC20.Contract.SafeERC20Transactor.contract.Transact(opts, method, params...) +} + +// Call invokes the (constant) contract method with params as input values and +// sets the output to result. The result type might be a single field for simple +// returns, a slice of interfaces for anonymous returns and a struct for named +// returns. +func (_SafeERC20 *SafeERC20CallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _SafeERC20.Contract.contract.Call(opts, result, method, params...) +} + +// Transfer initiates a plain transaction to move funds to the contract, calling +// its default method if one is available. +func (_SafeERC20 *SafeERC20TransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _SafeERC20.Contract.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_SafeERC20 *SafeERC20TransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _SafeERC20.Contract.contract.Transact(opts, method, params...) +} + +// UniversalTokenLibMetaData contains all meta data concerning the UniversalTokenLib contract. +var UniversalTokenLibMetaData = &bind.MetaData{ + ABI: "[]", + Bin: "0x60566037600b82828239805160001a607314602a57634e487b7160e01b600052600060045260246000fd5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600080fdfea26469706673582212202023f39864841dc931462dc7b8bdf9ede1735f580a13a3476b5bff0f5f9ca81b64736f6c63430008140033", +} + +// UniversalTokenLibABI is the input ABI used to generate the binding from. +// Deprecated: Use UniversalTokenLibMetaData.ABI instead. +var UniversalTokenLibABI = UniversalTokenLibMetaData.ABI + +// UniversalTokenLibBin is the compiled bytecode used for deploying new contracts. +// Deprecated: Use UniversalTokenLibMetaData.Bin instead. +var UniversalTokenLibBin = UniversalTokenLibMetaData.Bin + +// DeployUniversalTokenLib deploys a new Ethereum contract, binding an instance of UniversalTokenLib to it. +func DeployUniversalTokenLib(auth *bind.TransactOpts, backend bind.ContractBackend) (common.Address, *types.Transaction, *UniversalTokenLib, error) { + parsed, err := UniversalTokenLibMetaData.GetAbi() + if err != nil { + return common.Address{}, nil, nil, err + } + if parsed == nil { + return common.Address{}, nil, nil, errors.New("GetABI returned nil") + } + + address, tx, contract, err := bind.DeployContract(auth, *parsed, common.FromHex(UniversalTokenLibBin), backend) + if err != nil { + return common.Address{}, nil, nil, err + } + return address, tx, &UniversalTokenLib{UniversalTokenLibCaller: UniversalTokenLibCaller{contract: contract}, UniversalTokenLibTransactor: UniversalTokenLibTransactor{contract: contract}, UniversalTokenLibFilterer: UniversalTokenLibFilterer{contract: contract}}, nil +} + +// UniversalTokenLib is an auto generated Go binding around an Ethereum contract. +type UniversalTokenLib struct { + UniversalTokenLibCaller // Read-only binding to the contract + UniversalTokenLibTransactor // Write-only binding to the contract + UniversalTokenLibFilterer // Log filterer for contract events +} + +// UniversalTokenLibCaller is an auto generated read-only Go binding around an Ethereum contract. +type UniversalTokenLibCaller struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// UniversalTokenLibTransactor is an auto generated write-only Go binding around an Ethereum contract. +type UniversalTokenLibTransactor struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// UniversalTokenLibFilterer is an auto generated log filtering Go binding around an Ethereum contract events. +type UniversalTokenLibFilterer struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// UniversalTokenLibSession is an auto generated Go binding around an Ethereum contract, +// with pre-set call and transact options. +type UniversalTokenLibSession struct { + Contract *UniversalTokenLib // Generic contract binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// UniversalTokenLibCallerSession is an auto generated read-only Go binding around an Ethereum contract, +// with pre-set call options. +type UniversalTokenLibCallerSession struct { + Contract *UniversalTokenLibCaller // Generic contract caller binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session +} + +// UniversalTokenLibTransactorSession is an auto generated write-only Go binding around an Ethereum contract, +// with pre-set transact options. +type UniversalTokenLibTransactorSession struct { + Contract *UniversalTokenLibTransactor // Generic contract transactor binding to set the session for + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// UniversalTokenLibRaw is an auto generated low-level Go binding around an Ethereum contract. +type UniversalTokenLibRaw struct { + Contract *UniversalTokenLib // Generic contract binding to access the raw methods on +} + +// UniversalTokenLibCallerRaw is an auto generated low-level read-only Go binding around an Ethereum contract. +type UniversalTokenLibCallerRaw struct { + Contract *UniversalTokenLibCaller // Generic read-only contract binding to access the raw methods on +} + +// UniversalTokenLibTransactorRaw is an auto generated low-level write-only Go binding around an Ethereum contract. +type UniversalTokenLibTransactorRaw struct { + Contract *UniversalTokenLibTransactor // Generic write-only contract binding to access the raw methods on +} + +// NewUniversalTokenLib creates a new instance of UniversalTokenLib, bound to a specific deployed contract. +func NewUniversalTokenLib(address common.Address, backend bind.ContractBackend) (*UniversalTokenLib, error) { + contract, err := bindUniversalTokenLib(address, backend, backend, backend) + if err != nil { + return nil, err + } + return &UniversalTokenLib{UniversalTokenLibCaller: UniversalTokenLibCaller{contract: contract}, UniversalTokenLibTransactor: UniversalTokenLibTransactor{contract: contract}, UniversalTokenLibFilterer: UniversalTokenLibFilterer{contract: contract}}, nil +} + +// NewUniversalTokenLibCaller creates a new read-only instance of UniversalTokenLib, bound to a specific deployed contract. +func NewUniversalTokenLibCaller(address common.Address, caller bind.ContractCaller) (*UniversalTokenLibCaller, error) { + contract, err := bindUniversalTokenLib(address, caller, nil, nil) + if err != nil { + return nil, err + } + return &UniversalTokenLibCaller{contract: contract}, nil +} + +// NewUniversalTokenLibTransactor creates a new write-only instance of UniversalTokenLib, bound to a specific deployed contract. +func NewUniversalTokenLibTransactor(address common.Address, transactor bind.ContractTransactor) (*UniversalTokenLibTransactor, error) { + contract, err := bindUniversalTokenLib(address, nil, transactor, nil) + if err != nil { + return nil, err + } + return &UniversalTokenLibTransactor{contract: contract}, nil +} + +// NewUniversalTokenLibFilterer creates a new log filterer instance of UniversalTokenLib, bound to a specific deployed contract. +func NewUniversalTokenLibFilterer(address common.Address, filterer bind.ContractFilterer) (*UniversalTokenLibFilterer, error) { + contract, err := bindUniversalTokenLib(address, nil, nil, filterer) + if err != nil { + return nil, err + } + return &UniversalTokenLibFilterer{contract: contract}, nil +} + +// bindUniversalTokenLib binds a generic wrapper to an already deployed contract. +func bindUniversalTokenLib(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) { + parsed, err := UniversalTokenLibMetaData.GetAbi() + if err != nil { + return nil, err + } + return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil +} + +// Call invokes the (constant) contract method with params as input values and +// sets the output to result. The result type might be a single field for simple +// returns, a slice of interfaces for anonymous returns and a struct for named +// returns. +func (_UniversalTokenLib *UniversalTokenLibRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _UniversalTokenLib.Contract.UniversalTokenLibCaller.contract.Call(opts, result, method, params...) +} + +// Transfer initiates a plain transaction to move funds to the contract, calling +// its default method if one is available. +func (_UniversalTokenLib *UniversalTokenLibRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _UniversalTokenLib.Contract.UniversalTokenLibTransactor.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_UniversalTokenLib *UniversalTokenLibRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _UniversalTokenLib.Contract.UniversalTokenLibTransactor.contract.Transact(opts, method, params...) +} + +// Call invokes the (constant) contract method with params as input values and +// sets the output to result. The result type might be a single field for simple +// returns, a slice of interfaces for anonymous returns and a struct for named +// returns. +func (_UniversalTokenLib *UniversalTokenLibCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _UniversalTokenLib.Contract.contract.Call(opts, result, method, params...) +} + +// Transfer initiates a plain transaction to move funds to the contract, calling +// its default method if one is available. +func (_UniversalTokenLib *UniversalTokenLibTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _UniversalTokenLib.Contract.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_UniversalTokenLib *UniversalTokenLibTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _UniversalTokenLib.Contract.contract.Transact(opts, method, params...) +} diff --git a/services/rfq/contracts/testcontracts/fastbridgemockv2/fastbridgemockv2.contractinfo.json b/services/rfq/contracts/testcontracts/fastbridgemockv2/fastbridgemockv2.contractinfo.json new file mode 100644 index 0000000000..63ccf6945f --- /dev/null +++ b/services/rfq/contracts/testcontracts/fastbridgemockv2/fastbridgemockv2.contractinfo.json @@ -0,0 +1 @@ +{"solidity/FastBridgeMock.sol:AccessControl":{"code":"0x","runtime-code":"0x","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.20 ^0.8.20;\n\n// contracts/interfaces/IAdmin.sol\n\ninterface IAdmin {\n // ============ Events ============\n\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n event ChainGasAmountUpdated(uint256 oldChainGasAmount, uint256 newChainGasAmount);\n\n // ============ Methods ============\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n\n function setChainGasAmount(uint256 newChainGasAmount) external;\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/libs/Errors.sol\n\nerror DeadlineExceeded();\nerror DeadlineNotExceeded();\nerror DeadlineTooShort();\nerror InsufficientOutputAmount();\n\nerror MsgValueIncorrect();\nerror PoolNotFound();\nerror TokenAddressMismatch();\nerror TokenNotContract();\nerror TokenNotETH();\nerror TokensIdentical();\n\nerror ChainIncorrect();\nerror AmountIncorrect();\nerror ZeroAddress();\n\nerror DisputePeriodNotPassed();\nerror DisputePeriodPassed();\nerror SenderIncorrect();\nerror StatusIncorrect();\nerror TransactionIdIncorrect();\nerror TransactionRelayed();\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// contracts/libs/UniversalToken.sol\n\nlibrary UniversalTokenLib {\n using SafeERC20 for IERC20;\n\n address internal constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Transfers tokens to the given account. Reverts if transfer is not successful.\n /// @dev This might trigger fallback, if ETH is transferred to the contract.\n /// Make sure this can not lead to reentrancy attacks.\n function universalTransfer(address token, address to, uint256 value) internal {\n // Don't do anything, if need to send tokens to this address\n if (to == address(this)) return;\n // Don't do anything, if trying to send zero value\n if (value == 0) return;\n if (token == ETH_ADDRESS) {\n /// @dev Note: this can potentially lead to executing code in `to`.\n // solhint-disable-next-line avoid-low-level-calls\n (bool success,) = to.call{value: value}(\"\");\n require(success, \"ETH transfer failed\");\n } else {\n IERC20(token).safeTransfer(to, value);\n }\n }\n\n /// @notice Issues an infinite allowance to the spender, if the current allowance is insufficient\n /// to spend the given amount.\n function universalApproveInfinity(address token, address spender, uint256 amountToSpend) internal {\n // ETH Chad doesn't require your approval\n if (token == ETH_ADDRESS) return;\n // No-op if allowance is already sufficient\n uint256 allowance = IERC20(token).allowance(address(this), spender);\n if (allowance \u003e= amountToSpend) return;\n // Otherwise, reset approval to 0 and set to max allowance\n if (allowance \u003e 0) IERC20(token).safeDecreaseAllowance(spender, allowance);\n IERC20(token).safeIncreaseAllowance(spender, type(uint256).max);\n }\n\n /// @notice Returns the balance of the given token (or native ETH) for the given account.\n function universalBalanceOf(address token, address account) internal view returns (uint256) {\n if (token == ETH_ADDRESS) {\n return account.balance;\n } else {\n return IERC20(token).balanceOf(account);\n }\n }\n\n /// @dev Checks that token is a contract and not ETH_ADDRESS.\n function assertIsContract(address token) internal view {\n // Check that ETH_ADDRESS was not used (in case this is a predeploy on any of the chains)\n if (token == UniversalTokenLib.ETH_ADDRESS) revert TokenNotContract();\n // Check that token is not an EOA\n if (token.code.length == 0) revert TokenNotContract();\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/Admin.sol\n\ncontract Admin is IAdmin, AccessControlEnumerable {\n using UniversalTokenLib for address;\n\n bytes32 public constant RELAYER_ROLE = keccak256(\"RELAYER_ROLE\");\n bytes32 public constant REFUNDER_ROLE = keccak256(\"REFUNDER_ROLE\");\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n uint256 public constant FEE_BPS = 1e6;\n uint256 public constant FEE_RATE_MAX = 0.01e6; // max 1% on origin amount\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Chain gas amount to forward as rebate if requested\n uint256 public chainGasAmount;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n }\n\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n require(newFeeRate \u003c= FEE_RATE_MAX, \"newFeeRate \u003e max\");\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n token.universalTransfer(recipient, feeAmount);\n emit FeesSwept(token, recipient, feeAmount);\n }\n\n function setChainGasAmount(uint256 newChainGasAmount) external onlyRole(GOVERNOR_ROLE) {\n uint256 oldChainGasAmount = chainGasAmount;\n chainGasAmount = newChainGasAmount;\n emit ChainGasAmountUpdated(oldChainGasAmount, newChainGasAmount);\n }\n}\n\n// contracts/FastBridge.sol\n\ncontract FastBridge is IFastBridge, Admin {\n using SafeERC20 for IERC20;\n using UniversalTokenLib for address;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Delay for a transaction after which it could be permisionlessly refunded\n uint256 public constant REFUND_DELAY = 7 days;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeStatus) public bridgeStatuses;\n /// @notice Proof of relayed bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeProof) public bridgeProofs;\n /// @notice Whether bridge has been relayed on destination chain\n mapping(bytes32 =\u003e bool) public bridgeRelays;\n\n /// @dev to prevent replays\n uint256 public nonce;\n // @dev the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @notice Pulls a requested token from the user to the requested recipient.\n /// @dev Be careful of re-entrancy issues when msg.value \u003e 0 and recipient != address(this)\n function _pullToken(address recipient, address token, uint256 amount) internal returns (uint256 amountPulled) {\n if (token != UniversalTokenLib.ETH_ADDRESS) {\n token.assertIsContract();\n // Record token balance before transfer\n amountPulled = IERC20(token).balanceOf(recipient);\n // Token needs to be pulled only if msg.value is zero\n // This way user can specify WETH as the origin asset\n IERC20(token).safeTransferFrom(msg.sender, recipient, amount);\n // Use the difference between the recorded balance and the current balance as the amountPulled\n amountPulled = IERC20(token).balanceOf(recipient) - amountPulled;\n } else {\n // Otherwise, we need to check that ETH amount matches msg.value\n if (amount != msg.value) revert MsgValueIncorrect();\n // Transfer value to recipient if not this address\n if (recipient != address(this)) token.universalTransfer(recipient, amount);\n // We will forward msg.value in the external call later, if recipient is not this contract\n amountPulled = msg.value;\n }\n }\n\n /// @inheritdoc IFastBridge\n function getBridgeTransaction(bytes memory request) public pure returns (BridgeTransaction memory) {\n return abi.decode(request, (BridgeTransaction));\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n // check bridge params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n\n // transfer tokens to bridge contract\n // @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _pullToken(address(this), params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n\n // set status to requested\n bytes memory request = abi.encode(\n BridgeTransaction({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n sendChainGas: params.sendChainGas,\n deadline: params.deadline,\n nonce: nonce++ // increment nonce on every bridge\n })\n );\n bytes32 transactionId = keccak256(request);\n bridgeStatuses[transactionId] = BridgeStatus.REQUESTED;\n\n emit BridgeRequested(\n transactionId,\n params.sender,\n request,\n params.dstChainId,\n params.originToken,\n params.destToken,\n originAmount,\n params.destAmount,\n params.sendChainGas\n );\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes memory request) external payable onlyRole(RELAYER_ROLE) {\n bytes32 transactionId = keccak256(request);\n BridgeTransaction memory transaction = getBridgeTransaction(request);\n if (transaction.destChainId != uint32(block.chainid)) revert ChainIncorrect();\n\n // check haven't exceeded deadline for relay to happen\n if (block.timestamp \u003e transaction.deadline) revert DeadlineExceeded();\n\n // mark bridge transaction as relayed\n if (bridgeRelays[transactionId]) revert TransactionRelayed();\n bridgeRelays[transactionId] = true;\n\n // transfer tokens to recipient on destination chain and gas rebate if requested\n address to = transaction.destRecipient;\n address token = transaction.destToken;\n uint256 amount = transaction.destAmount;\n\n uint256 rebate = chainGasAmount;\n if (!transaction.sendChainGas) {\n // forward erc20\n rebate = 0;\n _pullToken(to, token, amount);\n } else if (token == UniversalTokenLib.ETH_ADDRESS) {\n // lump in gas rebate into amount in native gas token\n _pullToken(to, token, amount + rebate);\n } else {\n // forward erc20 then forward gas rebate in native gas token\n _pullToken(to, token, amount);\n _pullToken(to, UniversalTokenLib.ETH_ADDRESS, rebate);\n }\n\n emit BridgeRelayed(\n transactionId,\n msg.sender,\n to,\n transaction.originChainId,\n transaction.originToken,\n transaction.destToken,\n transaction.originAmount,\n transaction.destAmount,\n rebate\n );\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes memory request, bytes32 destTxHash) external onlyRole(RELAYER_ROLE) {\n bytes32 transactionId = keccak256(request);\n // update bridge tx status given proof provided\n if (bridgeStatuses[transactionId] != BridgeStatus.REQUESTED) revert StatusIncorrect();\n bridgeStatuses[transactionId] = BridgeStatus.RELAYER_PROVED;\n bridgeProofs[transactionId] = BridgeProof({timestamp: uint96(block.timestamp), relayer: msg.sender}); // overflow ok\n\n emit BridgeProofProvided(transactionId, msg.sender, destTxHash);\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint96(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint96).max but\n /// proof.timestamp \u003c type(uint96).max via unchecked statement\n /// @param proof The bridge proof\n /// @return delta Time delta since proof submitted\n function _timeSince(BridgeProof memory proof) internal view returns (uint256 delta) {\n unchecked {\n delta = uint96(block.timestamp) - proof.timestamp;\n }\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n if (bridgeStatuses[transactionId] != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n BridgeProof memory proof = bridgeProofs[transactionId];\n if (proof.relayer != relayer) revert SenderIncorrect();\n return _timeSince(proof) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes memory request, address to) external onlyRole(RELAYER_ROLE) {\n bytes32 transactionId = keccak256(request);\n BridgeTransaction memory transaction = getBridgeTransaction(request);\n\n // update bridge tx status if able to claim origin collateral\n if (bridgeStatuses[transactionId] != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n\n BridgeProof memory proof = bridgeProofs[transactionId];\n if (proof.relayer != msg.sender) revert SenderIncorrect();\n if (_timeSince(proof) \u003c= DISPUTE_PERIOD) revert DisputePeriodNotPassed();\n\n bridgeStatuses[transactionId] = BridgeStatus.RELAYER_CLAIMED;\n\n // update protocol fees if origin fee amount exists\n if (transaction.originFeeAmount \u003e 0) protocolFees[transaction.originToken] += transaction.originFeeAmount;\n\n // transfer origin collateral less fee to specified address\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositClaimed(transactionId, msg.sender, to, token, amount);\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n if (bridgeStatuses[transactionId] != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(bridgeProofs[transactionId]) \u003e DISPUTE_PERIOD) revert DisputePeriodPassed();\n\n // @dev relayer gets slashed effectively if dest relay has gone thru\n bridgeStatuses[transactionId] = BridgeStatus.REQUESTED;\n delete bridgeProofs[transactionId];\n\n emit BridgeProofDisputed(transactionId, msg.sender);\n }\n\n /// @inheritdoc IFastBridge\n function refund(bytes memory request) external {\n bytes32 transactionId = keccak256(request);\n BridgeTransaction memory transaction = getBridgeTransaction(request);\n\n if (hasRole(REFUNDER_ROLE, msg.sender)) {\n // Refunder can refund if deadline has passed\n if (block.timestamp \u003c= transaction.deadline) revert DeadlineNotExceeded();\n } else {\n // Permissionless refund is allowed after REFUND_DELAY\n if (block.timestamp \u003c= transaction.deadline + REFUND_DELAY) revert DeadlineNotExceeded();\n }\n\n // set status to refunded if still in requested state\n if (bridgeStatuses[transactionId] != BridgeStatus.REQUESTED) revert StatusIncorrect();\n bridgeStatuses[transactionId] = BridgeStatus.REFUNDED;\n\n // transfer origin collateral back to original sender\n address to = transaction.originSender;\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount + transaction.originFeeAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n }\n}\n\n// test/FastBridgeMock.sol\n\ncontract FastBridgeMock is IFastBridge, Admin {\n // @dev the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @dev to prevent replays\n uint256 public nonce;\n\n function getBridgeTransaction(bytes memory request) public pure returns (BridgeTransaction memory) {\n return abi.decode(request, (BridgeTransaction));\n }\n\n // used for testing in go.\n // see: https://ethereum.stackexchange.com/questions/21155/how-to-expose-enum-in-solidity-contract\n // make sure to update fastbridge/status.go if this changes\n // or underliyng enum changes.\n //\n // TODO: a foundry test should be added to ensure this is always in sync.\n function getEnumKeyByValue(FastBridge.BridgeStatus keyValue) public pure returns (string memory) {\n if (FastBridge.BridgeStatus.NULL == keyValue) return \"NULL\";\n if (FastBridge.BridgeStatus.REQUESTED == keyValue) return \"REQUESTED\";\n if (FastBridge.BridgeStatus.RELAYER_PROVED == keyValue) return \"RELAYER_PROVED\";\n if (FastBridge.BridgeStatus.RELAYER_CLAIMED == keyValue) return \"RELAYER_CLAIMED\";\n if (FastBridge.BridgeStatus.REFUNDED == keyValue) return \"REFUNDED\";\n return \"\";\n }\n\n function mockBridgeRequest(bytes32 transactionId, address sender, BridgeParams memory params) external {\n uint256 originFeeAmount = (params.originAmount * protocolFeeRate) / FEE_BPS;\n params.originAmount -= originFeeAmount;\n\n bytes memory request = abi.encode(\n BridgeTransaction({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: params.originAmount, // includes relayer fee\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n sendChainGas: params.sendChainGas,\n deadline: params.deadline,\n nonce: nonce++ // increment nonce on every bridge\n })\n );\n\n emit BridgeRequested(\n transactionId,\n params.sender,\n request,\n params.dstChainId,\n params.originToken,\n params.destToken,\n params.originAmount,\n params.destAmount,\n params.sendChainGas\n );\n }\n\n function mockBridgeRequestRaw(bytes32 transactionId, address sender, bytes memory request) external {\n BridgeTransaction memory transaction = getBridgeTransaction(request);\n emit BridgeRequested(\n transactionId,\n transaction.originSender,\n request,\n transaction.destChainId,\n transaction.originToken,\n transaction.destToken,\n transaction.originAmount,\n transaction.destAmount,\n transaction.sendChainGas\n );\n }\n\n function mockBridgeRelayer(\n bytes32 transactionId,\n address relayer,\n address to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n )\n external\n {\n emit BridgeRelayed(\n transactionId, relayer, to, originChainId, originToken, destToken, originAmount, destAmount, chainGasAmount\n );\n }\n\n function bridge(BridgeParams memory params) external payable {\n revert(\"not implemented\");\n }\n\n function relay(bytes memory request) external payable {\n revert(\"not implemented\");\n }\n\n function prove(bytes memory request, bytes32 destTxHash) external {\n revert(\"not implemented\");\n }\n\n function canClaim(bytes32 transactionid, address relayer) external view returns (bool) {\n revert(\"not implemented\");\n }\n\n function claim(bytes memory request, address to) external {\n revert(\"not implemented\");\n }\n\n function dispute(bytes32 transactionId) external {\n revert(\"not implemented\");\n }\n\n function refund(bytes memory request) external {\n revert(\"not implemented\");\n }\n}\n","language":"Solidity","languageVersion":"0.8.20","compilerVersion":"0.8.20","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"","srcMapRuntime":"","abiDefinition":[{"inputs":[],"name":"AccessControlBadConfirmation","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"bytes32","name":"neededRole","type":"bytes32"}],"name":"AccessControlUnauthorizedAccount","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"previousAdminRole","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"newAdminRole","type":"bytes32"}],"name":"RoleAdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleRevoked","type":"event"},{"inputs":[],"name":"DEFAULT_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleAdmin","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"grantRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"hasRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"callerConfirmation","type":"address"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"revokeRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"}],"userDoc":{"kind":"user","methods":{},"version":1},"developerDoc":{"details":"Contract module that allows children to implement role-based access control mechanisms. This is a lightweight version that doesn't allow enumerating role members except through off-chain means by accessing the contract event logs. Some applications may benefit from on-chain enumerability, for those cases see {AccessControlEnumerable}. Roles are referred to by their `bytes32` identifier. These should be exposed in the external API and be unique. The best way to achieve this is by using `public constant` hash digests: ```solidity bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\"); ``` Roles can be used to represent a set of permissions. To restrict access to a function call, use {hasRole}: ```solidity function foo() public { require(hasRole(MY_ROLE, msg.sender)); ... } ``` Roles can be granted and revoked dynamically via the {grantRole} and {revokeRole} functions. Each role has an associated admin role, and only accounts that have a role's admin role can call {grantRole} and {revokeRole}. By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means that only accounts with this role will be able to grant or revoke other roles. More complex role relationships can be created by using {_setRoleAdmin}. WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to grant and revoke this role. Extra precautions should be taken to secure accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules} to enforce additional security measures for this role.","errors":{"AccessControlBadConfirmation()":[{"details":"The caller of a function is not the expected one. NOTE: Don't confuse with {AccessControlUnauthorizedAccount}."}],"AccessControlUnauthorizedAccount(address,bytes32)":[{"details":"The `account` is missing a role."}]},"events":{"RoleAdminChanged(bytes32,bytes32,bytes32)":{"details":"Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole` `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite {RoleAdminChanged} not being emitted signaling this."},"RoleGranted(bytes32,address,address)":{"details":"Emitted when `account` is granted `role`. `sender` is the account that originated the contract call, an admin role bearer except when using {AccessControl-_setupRole}."},"RoleRevoked(bytes32,address,address)":{"details":"Emitted when `account` is revoked `role`. `sender` is the account that originated the contract call: - if using `revokeRole`, it is the admin role bearer - if using `renounceRole`, it is the role bearer (i.e. `account`)"}},"kind":"dev","methods":{"getRoleAdmin(bytes32)":{"details":"Returns the admin role that controls `role`. See {grantRole} and {revokeRole}. To change a role's admin, use {_setRoleAdmin}."},"grantRole(bytes32,address)":{"details":"Grants `role` to `account`. If `account` had not been already granted `role`, emits a {RoleGranted} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleGranted} event."},"hasRole(bytes32,address)":{"details":"Returns `true` if `account` has been granted `role`."},"renounceRole(bytes32,address)":{"details":"Revokes `role` from the calling account. Roles are often managed via {grantRole} and {revokeRole}: this function's purpose is to provide a mechanism for accounts to lose their privileges if they are compromised (such as when a trusted device is misplaced). If the calling account had been revoked `role`, emits a {RoleRevoked} event. Requirements: - the caller must be `callerConfirmation`. May emit a {RoleRevoked} event."},"revokeRole(bytes32,address)":{"details":"Revokes `role` from `account`. If `account` had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleRevoked} event."},"supportsInterface(bytes4)":{"details":"See {IERC165-supportsInterface}."}},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.20+commit.a1b79de6\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[],\"name\":\"AccessControlBadConfirmation\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"neededRole\",\"type\":\"bytes32\"}],\"name\":\"AccessControlUnauthorizedAccount\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"previousAdminRole\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"newAdminRole\",\"type\":\"bytes32\"}],\"name\":\"RoleAdminChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleGranted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleRevoked\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"DEFAULT_ADMIN_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"}],\"name\":\"getRoleAdmin\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"grantRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"hasRole\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"callerConfirmation\",\"type\":\"address\"}],\"name\":\"renounceRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"revokeRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes4\",\"name\":\"interfaceId\",\"type\":\"bytes4\"}],\"name\":\"supportsInterface\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"}],\"devdoc\":{\"details\":\"Contract module that allows children to implement role-based access control mechanisms. This is a lightweight version that doesn't allow enumerating role members except through off-chain means by accessing the contract event logs. Some applications may benefit from on-chain enumerability, for those cases see {AccessControlEnumerable}. Roles are referred to by their `bytes32` identifier. These should be exposed in the external API and be unique. The best way to achieve this is by using `public constant` hash digests: ```solidity bytes32 public constant MY_ROLE = keccak256(\\\"MY_ROLE\\\"); ``` Roles can be used to represent a set of permissions. To restrict access to a function call, use {hasRole}: ```solidity function foo() public { require(hasRole(MY_ROLE, msg.sender)); ... } ``` Roles can be granted and revoked dynamically via the {grantRole} and {revokeRole} functions. Each role has an associated admin role, and only accounts that have a role's admin role can call {grantRole} and {revokeRole}. By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means that only accounts with this role will be able to grant or revoke other roles. More complex role relationships can be created by using {_setRoleAdmin}. WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to grant and revoke this role. Extra precautions should be taken to secure accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules} to enforce additional security measures for this role.\",\"errors\":{\"AccessControlBadConfirmation()\":[{\"details\":\"The caller of a function is not the expected one. NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\"}],\"AccessControlUnauthorizedAccount(address,bytes32)\":[{\"details\":\"The `account` is missing a role.\"}]},\"events\":{\"RoleAdminChanged(bytes32,bytes32,bytes32)\":{\"details\":\"Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole` `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite {RoleAdminChanged} not being emitted signaling this.\"},\"RoleGranted(bytes32,address,address)\":{\"details\":\"Emitted when `account` is granted `role`. `sender` is the account that originated the contract call, an admin role bearer except when using {AccessControl-_setupRole}.\"},\"RoleRevoked(bytes32,address,address)\":{\"details\":\"Emitted when `account` is revoked `role`. `sender` is the account that originated the contract call: - if using `revokeRole`, it is the admin role bearer - if using `renounceRole`, it is the role bearer (i.e. `account`)\"}},\"kind\":\"dev\",\"methods\":{\"getRoleAdmin(bytes32)\":{\"details\":\"Returns the admin role that controls `role`. See {grantRole} and {revokeRole}. To change a role's admin, use {_setRoleAdmin}.\"},\"grantRole(bytes32,address)\":{\"details\":\"Grants `role` to `account`. If `account` had not been already granted `role`, emits a {RoleGranted} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleGranted} event.\"},\"hasRole(bytes32,address)\":{\"details\":\"Returns `true` if `account` has been granted `role`.\"},\"renounceRole(bytes32,address)\":{\"details\":\"Revokes `role` from the calling account. Roles are often managed via {grantRole} and {revokeRole}: this function's purpose is to provide a mechanism for accounts to lose their privileges if they are compromised (such as when a trusted device is misplaced). If the calling account had been revoked `role`, emits a {RoleRevoked} event. Requirements: - the caller must be `callerConfirmation`. May emit a {RoleRevoked} event.\"},\"revokeRole(bytes32,address)\":{\"details\":\"Revokes `role` from `account`. If `account` had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleRevoked} event.\"},\"supportsInterface(bytes4)\":{\"details\":\"See {IERC165-supportsInterface}.\"}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeMock.sol\":\"AccessControl\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeMock.sol\":{\"keccak256\":\"0x620e81214ecd324ae8b971219291f176c454ce76fb1c01d656428096da8f1366\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://18e556772c12e13aa2d52a50cc7c48e676c8d5af22b90adaf7befb39cdd08e64\",\"dweb:/ipfs/QmPrQc98TxHCFMeuFNADyjr6Nqo52rHhHy1LBcsVdMRXjL\"]}},\"version\":1}"},"hashes":{"DEFAULT_ADMIN_ROLE()":"a217fddf","getRoleAdmin(bytes32)":"248a9ca3","grantRole(bytes32,address)":"2f2ff15d","hasRole(bytes32,address)":"91d14854","renounceRole(bytes32,address)":"36568abe","revokeRole(bytes32,address)":"d547741f","supportsInterface(bytes4)":"01ffc9a7"}},"solidity/FastBridgeMock.sol:AccessControlEnumerable":{"code":"0x","runtime-code":"0x","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.20 ^0.8.20;\n\n// contracts/interfaces/IAdmin.sol\n\ninterface IAdmin {\n // ============ Events ============\n\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n event ChainGasAmountUpdated(uint256 oldChainGasAmount, uint256 newChainGasAmount);\n\n // ============ Methods ============\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n\n function setChainGasAmount(uint256 newChainGasAmount) external;\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/libs/Errors.sol\n\nerror DeadlineExceeded();\nerror DeadlineNotExceeded();\nerror DeadlineTooShort();\nerror InsufficientOutputAmount();\n\nerror MsgValueIncorrect();\nerror PoolNotFound();\nerror TokenAddressMismatch();\nerror TokenNotContract();\nerror TokenNotETH();\nerror TokensIdentical();\n\nerror ChainIncorrect();\nerror AmountIncorrect();\nerror ZeroAddress();\n\nerror DisputePeriodNotPassed();\nerror DisputePeriodPassed();\nerror SenderIncorrect();\nerror StatusIncorrect();\nerror TransactionIdIncorrect();\nerror TransactionRelayed();\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// contracts/libs/UniversalToken.sol\n\nlibrary UniversalTokenLib {\n using SafeERC20 for IERC20;\n\n address internal constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Transfers tokens to the given account. Reverts if transfer is not successful.\n /// @dev This might trigger fallback, if ETH is transferred to the contract.\n /// Make sure this can not lead to reentrancy attacks.\n function universalTransfer(address token, address to, uint256 value) internal {\n // Don't do anything, if need to send tokens to this address\n if (to == address(this)) return;\n // Don't do anything, if trying to send zero value\n if (value == 0) return;\n if (token == ETH_ADDRESS) {\n /// @dev Note: this can potentially lead to executing code in `to`.\n // solhint-disable-next-line avoid-low-level-calls\n (bool success,) = to.call{value: value}(\"\");\n require(success, \"ETH transfer failed\");\n } else {\n IERC20(token).safeTransfer(to, value);\n }\n }\n\n /// @notice Issues an infinite allowance to the spender, if the current allowance is insufficient\n /// to spend the given amount.\n function universalApproveInfinity(address token, address spender, uint256 amountToSpend) internal {\n // ETH Chad doesn't require your approval\n if (token == ETH_ADDRESS) return;\n // No-op if allowance is already sufficient\n uint256 allowance = IERC20(token).allowance(address(this), spender);\n if (allowance \u003e= amountToSpend) return;\n // Otherwise, reset approval to 0 and set to max allowance\n if (allowance \u003e 0) IERC20(token).safeDecreaseAllowance(spender, allowance);\n IERC20(token).safeIncreaseAllowance(spender, type(uint256).max);\n }\n\n /// @notice Returns the balance of the given token (or native ETH) for the given account.\n function universalBalanceOf(address token, address account) internal view returns (uint256) {\n if (token == ETH_ADDRESS) {\n return account.balance;\n } else {\n return IERC20(token).balanceOf(account);\n }\n }\n\n /// @dev Checks that token is a contract and not ETH_ADDRESS.\n function assertIsContract(address token) internal view {\n // Check that ETH_ADDRESS was not used (in case this is a predeploy on any of the chains)\n if (token == UniversalTokenLib.ETH_ADDRESS) revert TokenNotContract();\n // Check that token is not an EOA\n if (token.code.length == 0) revert TokenNotContract();\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/Admin.sol\n\ncontract Admin is IAdmin, AccessControlEnumerable {\n using UniversalTokenLib for address;\n\n bytes32 public constant RELAYER_ROLE = keccak256(\"RELAYER_ROLE\");\n bytes32 public constant REFUNDER_ROLE = keccak256(\"REFUNDER_ROLE\");\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n uint256 public constant FEE_BPS = 1e6;\n uint256 public constant FEE_RATE_MAX = 0.01e6; // max 1% on origin amount\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Chain gas amount to forward as rebate if requested\n uint256 public chainGasAmount;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n }\n\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n require(newFeeRate \u003c= FEE_RATE_MAX, \"newFeeRate \u003e max\");\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n token.universalTransfer(recipient, feeAmount);\n emit FeesSwept(token, recipient, feeAmount);\n }\n\n function setChainGasAmount(uint256 newChainGasAmount) external onlyRole(GOVERNOR_ROLE) {\n uint256 oldChainGasAmount = chainGasAmount;\n chainGasAmount = newChainGasAmount;\n emit ChainGasAmountUpdated(oldChainGasAmount, newChainGasAmount);\n }\n}\n\n// contracts/FastBridge.sol\n\ncontract FastBridge is IFastBridge, Admin {\n using SafeERC20 for IERC20;\n using UniversalTokenLib for address;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Delay for a transaction after which it could be permisionlessly refunded\n uint256 public constant REFUND_DELAY = 7 days;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeStatus) public bridgeStatuses;\n /// @notice Proof of relayed bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeProof) public bridgeProofs;\n /// @notice Whether bridge has been relayed on destination chain\n mapping(bytes32 =\u003e bool) public bridgeRelays;\n\n /// @dev to prevent replays\n uint256 public nonce;\n // @dev the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @notice Pulls a requested token from the user to the requested recipient.\n /// @dev Be careful of re-entrancy issues when msg.value \u003e 0 and recipient != address(this)\n function _pullToken(address recipient, address token, uint256 amount) internal returns (uint256 amountPulled) {\n if (token != UniversalTokenLib.ETH_ADDRESS) {\n token.assertIsContract();\n // Record token balance before transfer\n amountPulled = IERC20(token).balanceOf(recipient);\n // Token needs to be pulled only if msg.value is zero\n // This way user can specify WETH as the origin asset\n IERC20(token).safeTransferFrom(msg.sender, recipient, amount);\n // Use the difference between the recorded balance and the current balance as the amountPulled\n amountPulled = IERC20(token).balanceOf(recipient) - amountPulled;\n } else {\n // Otherwise, we need to check that ETH amount matches msg.value\n if (amount != msg.value) revert MsgValueIncorrect();\n // Transfer value to recipient if not this address\n if (recipient != address(this)) token.universalTransfer(recipient, amount);\n // We will forward msg.value in the external call later, if recipient is not this contract\n amountPulled = msg.value;\n }\n }\n\n /// @inheritdoc IFastBridge\n function getBridgeTransaction(bytes memory request) public pure returns (BridgeTransaction memory) {\n return abi.decode(request, (BridgeTransaction));\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n // check bridge params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n\n // transfer tokens to bridge contract\n // @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _pullToken(address(this), params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n\n // set status to requested\n bytes memory request = abi.encode(\n BridgeTransaction({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n sendChainGas: params.sendChainGas,\n deadline: params.deadline,\n nonce: nonce++ // increment nonce on every bridge\n })\n );\n bytes32 transactionId = keccak256(request);\n bridgeStatuses[transactionId] = BridgeStatus.REQUESTED;\n\n emit BridgeRequested(\n transactionId,\n params.sender,\n request,\n params.dstChainId,\n params.originToken,\n params.destToken,\n originAmount,\n params.destAmount,\n params.sendChainGas\n );\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes memory request) external payable onlyRole(RELAYER_ROLE) {\n bytes32 transactionId = keccak256(request);\n BridgeTransaction memory transaction = getBridgeTransaction(request);\n if (transaction.destChainId != uint32(block.chainid)) revert ChainIncorrect();\n\n // check haven't exceeded deadline for relay to happen\n if (block.timestamp \u003e transaction.deadline) revert DeadlineExceeded();\n\n // mark bridge transaction as relayed\n if (bridgeRelays[transactionId]) revert TransactionRelayed();\n bridgeRelays[transactionId] = true;\n\n // transfer tokens to recipient on destination chain and gas rebate if requested\n address to = transaction.destRecipient;\n address token = transaction.destToken;\n uint256 amount = transaction.destAmount;\n\n uint256 rebate = chainGasAmount;\n if (!transaction.sendChainGas) {\n // forward erc20\n rebate = 0;\n _pullToken(to, token, amount);\n } else if (token == UniversalTokenLib.ETH_ADDRESS) {\n // lump in gas rebate into amount in native gas token\n _pullToken(to, token, amount + rebate);\n } else {\n // forward erc20 then forward gas rebate in native gas token\n _pullToken(to, token, amount);\n _pullToken(to, UniversalTokenLib.ETH_ADDRESS, rebate);\n }\n\n emit BridgeRelayed(\n transactionId,\n msg.sender,\n to,\n transaction.originChainId,\n transaction.originToken,\n transaction.destToken,\n transaction.originAmount,\n transaction.destAmount,\n rebate\n );\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes memory request, bytes32 destTxHash) external onlyRole(RELAYER_ROLE) {\n bytes32 transactionId = keccak256(request);\n // update bridge tx status given proof provided\n if (bridgeStatuses[transactionId] != BridgeStatus.REQUESTED) revert StatusIncorrect();\n bridgeStatuses[transactionId] = BridgeStatus.RELAYER_PROVED;\n bridgeProofs[transactionId] = BridgeProof({timestamp: uint96(block.timestamp), relayer: msg.sender}); // overflow ok\n\n emit BridgeProofProvided(transactionId, msg.sender, destTxHash);\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint96(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint96).max but\n /// proof.timestamp \u003c type(uint96).max via unchecked statement\n /// @param proof The bridge proof\n /// @return delta Time delta since proof submitted\n function _timeSince(BridgeProof memory proof) internal view returns (uint256 delta) {\n unchecked {\n delta = uint96(block.timestamp) - proof.timestamp;\n }\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n if (bridgeStatuses[transactionId] != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n BridgeProof memory proof = bridgeProofs[transactionId];\n if (proof.relayer != relayer) revert SenderIncorrect();\n return _timeSince(proof) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes memory request, address to) external onlyRole(RELAYER_ROLE) {\n bytes32 transactionId = keccak256(request);\n BridgeTransaction memory transaction = getBridgeTransaction(request);\n\n // update bridge tx status if able to claim origin collateral\n if (bridgeStatuses[transactionId] != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n\n BridgeProof memory proof = bridgeProofs[transactionId];\n if (proof.relayer != msg.sender) revert SenderIncorrect();\n if (_timeSince(proof) \u003c= DISPUTE_PERIOD) revert DisputePeriodNotPassed();\n\n bridgeStatuses[transactionId] = BridgeStatus.RELAYER_CLAIMED;\n\n // update protocol fees if origin fee amount exists\n if (transaction.originFeeAmount \u003e 0) protocolFees[transaction.originToken] += transaction.originFeeAmount;\n\n // transfer origin collateral less fee to specified address\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositClaimed(transactionId, msg.sender, to, token, amount);\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n if (bridgeStatuses[transactionId] != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(bridgeProofs[transactionId]) \u003e DISPUTE_PERIOD) revert DisputePeriodPassed();\n\n // @dev relayer gets slashed effectively if dest relay has gone thru\n bridgeStatuses[transactionId] = BridgeStatus.REQUESTED;\n delete bridgeProofs[transactionId];\n\n emit BridgeProofDisputed(transactionId, msg.sender);\n }\n\n /// @inheritdoc IFastBridge\n function refund(bytes memory request) external {\n bytes32 transactionId = keccak256(request);\n BridgeTransaction memory transaction = getBridgeTransaction(request);\n\n if (hasRole(REFUNDER_ROLE, msg.sender)) {\n // Refunder can refund if deadline has passed\n if (block.timestamp \u003c= transaction.deadline) revert DeadlineNotExceeded();\n } else {\n // Permissionless refund is allowed after REFUND_DELAY\n if (block.timestamp \u003c= transaction.deadline + REFUND_DELAY) revert DeadlineNotExceeded();\n }\n\n // set status to refunded if still in requested state\n if (bridgeStatuses[transactionId] != BridgeStatus.REQUESTED) revert StatusIncorrect();\n bridgeStatuses[transactionId] = BridgeStatus.REFUNDED;\n\n // transfer origin collateral back to original sender\n address to = transaction.originSender;\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount + transaction.originFeeAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n }\n}\n\n// test/FastBridgeMock.sol\n\ncontract FastBridgeMock is IFastBridge, Admin {\n // @dev the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @dev to prevent replays\n uint256 public nonce;\n\n function getBridgeTransaction(bytes memory request) public pure returns (BridgeTransaction memory) {\n return abi.decode(request, (BridgeTransaction));\n }\n\n // used for testing in go.\n // see: https://ethereum.stackexchange.com/questions/21155/how-to-expose-enum-in-solidity-contract\n // make sure to update fastbridge/status.go if this changes\n // or underliyng enum changes.\n //\n // TODO: a foundry test should be added to ensure this is always in sync.\n function getEnumKeyByValue(FastBridge.BridgeStatus keyValue) public pure returns (string memory) {\n if (FastBridge.BridgeStatus.NULL == keyValue) return \"NULL\";\n if (FastBridge.BridgeStatus.REQUESTED == keyValue) return \"REQUESTED\";\n if (FastBridge.BridgeStatus.RELAYER_PROVED == keyValue) return \"RELAYER_PROVED\";\n if (FastBridge.BridgeStatus.RELAYER_CLAIMED == keyValue) return \"RELAYER_CLAIMED\";\n if (FastBridge.BridgeStatus.REFUNDED == keyValue) return \"REFUNDED\";\n return \"\";\n }\n\n function mockBridgeRequest(bytes32 transactionId, address sender, BridgeParams memory params) external {\n uint256 originFeeAmount = (params.originAmount * protocolFeeRate) / FEE_BPS;\n params.originAmount -= originFeeAmount;\n\n bytes memory request = abi.encode(\n BridgeTransaction({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: params.originAmount, // includes relayer fee\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n sendChainGas: params.sendChainGas,\n deadline: params.deadline,\n nonce: nonce++ // increment nonce on every bridge\n })\n );\n\n emit BridgeRequested(\n transactionId,\n params.sender,\n request,\n params.dstChainId,\n params.originToken,\n params.destToken,\n params.originAmount,\n params.destAmount,\n params.sendChainGas\n );\n }\n\n function mockBridgeRequestRaw(bytes32 transactionId, address sender, bytes memory request) external {\n BridgeTransaction memory transaction = getBridgeTransaction(request);\n emit BridgeRequested(\n transactionId,\n transaction.originSender,\n request,\n transaction.destChainId,\n transaction.originToken,\n transaction.destToken,\n transaction.originAmount,\n transaction.destAmount,\n transaction.sendChainGas\n );\n }\n\n function mockBridgeRelayer(\n bytes32 transactionId,\n address relayer,\n address to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n )\n external\n {\n emit BridgeRelayed(\n transactionId, relayer, to, originChainId, originToken, destToken, originAmount, destAmount, chainGasAmount\n );\n }\n\n function bridge(BridgeParams memory params) external payable {\n revert(\"not implemented\");\n }\n\n function relay(bytes memory request) external payable {\n revert(\"not implemented\");\n }\n\n function prove(bytes memory request, bytes32 destTxHash) external {\n revert(\"not implemented\");\n }\n\n function canClaim(bytes32 transactionid, address relayer) external view returns (bool) {\n revert(\"not implemented\");\n }\n\n function claim(bytes memory request, address to) external {\n revert(\"not implemented\");\n }\n\n function dispute(bytes32 transactionId) external {\n revert(\"not implemented\");\n }\n\n function refund(bytes memory request) external {\n revert(\"not implemented\");\n }\n}\n","language":"Solidity","languageVersion":"0.8.20","compilerVersion":"0.8.20","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"","srcMapRuntime":"","abiDefinition":[{"inputs":[],"name":"AccessControlBadConfirmation","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"bytes32","name":"neededRole","type":"bytes32"}],"name":"AccessControlUnauthorizedAccount","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"previousAdminRole","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"newAdminRole","type":"bytes32"}],"name":"RoleAdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleRevoked","type":"event"},{"inputs":[],"name":"DEFAULT_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleAdmin","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"uint256","name":"index","type":"uint256"}],"name":"getRoleMember","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleMemberCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"grantRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"hasRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"callerConfirmation","type":"address"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"revokeRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"}],"userDoc":{"kind":"user","methods":{},"version":1},"developerDoc":{"details":"Extension of {AccessControl} that allows enumerating the members of each role.","errors":{"AccessControlBadConfirmation()":[{"details":"The caller of a function is not the expected one. NOTE: Don't confuse with {AccessControlUnauthorizedAccount}."}],"AccessControlUnauthorizedAccount(address,bytes32)":[{"details":"The `account` is missing a role."}]},"events":{"RoleAdminChanged(bytes32,bytes32,bytes32)":{"details":"Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole` `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite {RoleAdminChanged} not being emitted signaling this."},"RoleGranted(bytes32,address,address)":{"details":"Emitted when `account` is granted `role`. `sender` is the account that originated the contract call, an admin role bearer except when using {AccessControl-_setupRole}."},"RoleRevoked(bytes32,address,address)":{"details":"Emitted when `account` is revoked `role`. `sender` is the account that originated the contract call: - if using `revokeRole`, it is the admin role bearer - if using `renounceRole`, it is the role bearer (i.e. `account`)"}},"kind":"dev","methods":{"getRoleAdmin(bytes32)":{"details":"Returns the admin role that controls `role`. See {grantRole} and {revokeRole}. To change a role's admin, use {_setRoleAdmin}."},"getRoleMember(bytes32,uint256)":{"details":"Returns one of the accounts that have `role`. `index` must be a value between 0 and {getRoleMemberCount}, non-inclusive. Role bearers are not sorted in any particular way, and their ordering may change at any point. WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure you perform all queries on the same block. See the following https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post] for more information."},"getRoleMemberCount(bytes32)":{"details":"Returns the number of accounts that have `role`. Can be used together with {getRoleMember} to enumerate all bearers of a role."},"grantRole(bytes32,address)":{"details":"Grants `role` to `account`. If `account` had not been already granted `role`, emits a {RoleGranted} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleGranted} event."},"hasRole(bytes32,address)":{"details":"Returns `true` if `account` has been granted `role`."},"renounceRole(bytes32,address)":{"details":"Revokes `role` from the calling account. Roles are often managed via {grantRole} and {revokeRole}: this function's purpose is to provide a mechanism for accounts to lose their privileges if they are compromised (such as when a trusted device is misplaced). If the calling account had been revoked `role`, emits a {RoleRevoked} event. Requirements: - the caller must be `callerConfirmation`. May emit a {RoleRevoked} event."},"revokeRole(bytes32,address)":{"details":"Revokes `role` from `account`. If `account` had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleRevoked} event."},"supportsInterface(bytes4)":{"details":"See {IERC165-supportsInterface}."}},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.20+commit.a1b79de6\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[],\"name\":\"AccessControlBadConfirmation\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"neededRole\",\"type\":\"bytes32\"}],\"name\":\"AccessControlUnauthorizedAccount\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"previousAdminRole\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"newAdminRole\",\"type\":\"bytes32\"}],\"name\":\"RoleAdminChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleGranted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleRevoked\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"DEFAULT_ADMIN_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"}],\"name\":\"getRoleAdmin\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"index\",\"type\":\"uint256\"}],\"name\":\"getRoleMember\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"}],\"name\":\"getRoleMemberCount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"grantRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"hasRole\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"callerConfirmation\",\"type\":\"address\"}],\"name\":\"renounceRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"revokeRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes4\",\"name\":\"interfaceId\",\"type\":\"bytes4\"}],\"name\":\"supportsInterface\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"}],\"devdoc\":{\"details\":\"Extension of {AccessControl} that allows enumerating the members of each role.\",\"errors\":{\"AccessControlBadConfirmation()\":[{\"details\":\"The caller of a function is not the expected one. NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\"}],\"AccessControlUnauthorizedAccount(address,bytes32)\":[{\"details\":\"The `account` is missing a role.\"}]},\"events\":{\"RoleAdminChanged(bytes32,bytes32,bytes32)\":{\"details\":\"Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole` `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite {RoleAdminChanged} not being emitted signaling this.\"},\"RoleGranted(bytes32,address,address)\":{\"details\":\"Emitted when `account` is granted `role`. `sender` is the account that originated the contract call, an admin role bearer except when using {AccessControl-_setupRole}.\"},\"RoleRevoked(bytes32,address,address)\":{\"details\":\"Emitted when `account` is revoked `role`. `sender` is the account that originated the contract call: - if using `revokeRole`, it is the admin role bearer - if using `renounceRole`, it is the role bearer (i.e. `account`)\"}},\"kind\":\"dev\",\"methods\":{\"getRoleAdmin(bytes32)\":{\"details\":\"Returns the admin role that controls `role`. See {grantRole} and {revokeRole}. To change a role's admin, use {_setRoleAdmin}.\"},\"getRoleMember(bytes32,uint256)\":{\"details\":\"Returns one of the accounts that have `role`. `index` must be a value between 0 and {getRoleMemberCount}, non-inclusive. Role bearers are not sorted in any particular way, and their ordering may change at any point. WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure you perform all queries on the same block. See the following https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post] for more information.\"},\"getRoleMemberCount(bytes32)\":{\"details\":\"Returns the number of accounts that have `role`. Can be used together with {getRoleMember} to enumerate all bearers of a role.\"},\"grantRole(bytes32,address)\":{\"details\":\"Grants `role` to `account`. If `account` had not been already granted `role`, emits a {RoleGranted} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleGranted} event.\"},\"hasRole(bytes32,address)\":{\"details\":\"Returns `true` if `account` has been granted `role`.\"},\"renounceRole(bytes32,address)\":{\"details\":\"Revokes `role` from the calling account. Roles are often managed via {grantRole} and {revokeRole}: this function's purpose is to provide a mechanism for accounts to lose their privileges if they are compromised (such as when a trusted device is misplaced). If the calling account had been revoked `role`, emits a {RoleRevoked} event. Requirements: - the caller must be `callerConfirmation`. May emit a {RoleRevoked} event.\"},\"revokeRole(bytes32,address)\":{\"details\":\"Revokes `role` from `account`. If `account` had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleRevoked} event.\"},\"supportsInterface(bytes4)\":{\"details\":\"See {IERC165-supportsInterface}.\"}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeMock.sol\":\"AccessControlEnumerable\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeMock.sol\":{\"keccak256\":\"0x620e81214ecd324ae8b971219291f176c454ce76fb1c01d656428096da8f1366\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://18e556772c12e13aa2d52a50cc7c48e676c8d5af22b90adaf7befb39cdd08e64\",\"dweb:/ipfs/QmPrQc98TxHCFMeuFNADyjr6Nqo52rHhHy1LBcsVdMRXjL\"]}},\"version\":1}"},"hashes":{"DEFAULT_ADMIN_ROLE()":"a217fddf","getRoleAdmin(bytes32)":"248a9ca3","getRoleMember(bytes32,uint256)":"9010d07c","getRoleMemberCount(bytes32)":"ca15c873","grantRole(bytes32,address)":"2f2ff15d","hasRole(bytes32,address)":"91d14854","renounceRole(bytes32,address)":"36568abe","revokeRole(bytes32,address)":"d547741f","supportsInterface(bytes4)":"01ffc9a7"}},"solidity/FastBridgeMock.sol:Address":{"code":"0x60566037600b82828239805160001a607314602a57634e487b7160e01b600052600060045260246000fd5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600080fdfea264697066735822122083549ae8a6625896ee7f9ad3afb09c83f8f6b7f2c10b67bf18def7b2b300f36a64736f6c63430008140033","runtime-code":"0x73000000000000000000000000000000000000000030146080604052600080fdfea264697066735822122083549ae8a6625896ee7f9ad3afb09c83f8f6b7f2c10b67bf18def7b2b300f36a64736f6c63430008140033","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.20 ^0.8.20;\n\n// contracts/interfaces/IAdmin.sol\n\ninterface IAdmin {\n // ============ Events ============\n\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n event ChainGasAmountUpdated(uint256 oldChainGasAmount, uint256 newChainGasAmount);\n\n // ============ Methods ============\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n\n function setChainGasAmount(uint256 newChainGasAmount) external;\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/libs/Errors.sol\n\nerror DeadlineExceeded();\nerror DeadlineNotExceeded();\nerror DeadlineTooShort();\nerror InsufficientOutputAmount();\n\nerror MsgValueIncorrect();\nerror PoolNotFound();\nerror TokenAddressMismatch();\nerror TokenNotContract();\nerror TokenNotETH();\nerror TokensIdentical();\n\nerror ChainIncorrect();\nerror AmountIncorrect();\nerror ZeroAddress();\n\nerror DisputePeriodNotPassed();\nerror DisputePeriodPassed();\nerror SenderIncorrect();\nerror StatusIncorrect();\nerror TransactionIdIncorrect();\nerror TransactionRelayed();\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// contracts/libs/UniversalToken.sol\n\nlibrary UniversalTokenLib {\n using SafeERC20 for IERC20;\n\n address internal constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Transfers tokens to the given account. Reverts if transfer is not successful.\n /// @dev This might trigger fallback, if ETH is transferred to the contract.\n /// Make sure this can not lead to reentrancy attacks.\n function universalTransfer(address token, address to, uint256 value) internal {\n // Don't do anything, if need to send tokens to this address\n if (to == address(this)) return;\n // Don't do anything, if trying to send zero value\n if (value == 0) return;\n if (token == ETH_ADDRESS) {\n /// @dev Note: this can potentially lead to executing code in `to`.\n // solhint-disable-next-line avoid-low-level-calls\n (bool success,) = to.call{value: value}(\"\");\n require(success, \"ETH transfer failed\");\n } else {\n IERC20(token).safeTransfer(to, value);\n }\n }\n\n /// @notice Issues an infinite allowance to the spender, if the current allowance is insufficient\n /// to spend the given amount.\n function universalApproveInfinity(address token, address spender, uint256 amountToSpend) internal {\n // ETH Chad doesn't require your approval\n if (token == ETH_ADDRESS) return;\n // No-op if allowance is already sufficient\n uint256 allowance = IERC20(token).allowance(address(this), spender);\n if (allowance \u003e= amountToSpend) return;\n // Otherwise, reset approval to 0 and set to max allowance\n if (allowance \u003e 0) IERC20(token).safeDecreaseAllowance(spender, allowance);\n IERC20(token).safeIncreaseAllowance(spender, type(uint256).max);\n }\n\n /// @notice Returns the balance of the given token (or native ETH) for the given account.\n function universalBalanceOf(address token, address account) internal view returns (uint256) {\n if (token == ETH_ADDRESS) {\n return account.balance;\n } else {\n return IERC20(token).balanceOf(account);\n }\n }\n\n /// @dev Checks that token is a contract and not ETH_ADDRESS.\n function assertIsContract(address token) internal view {\n // Check that ETH_ADDRESS was not used (in case this is a predeploy on any of the chains)\n if (token == UniversalTokenLib.ETH_ADDRESS) revert TokenNotContract();\n // Check that token is not an EOA\n if (token.code.length == 0) revert TokenNotContract();\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/Admin.sol\n\ncontract Admin is IAdmin, AccessControlEnumerable {\n using UniversalTokenLib for address;\n\n bytes32 public constant RELAYER_ROLE = keccak256(\"RELAYER_ROLE\");\n bytes32 public constant REFUNDER_ROLE = keccak256(\"REFUNDER_ROLE\");\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n uint256 public constant FEE_BPS = 1e6;\n uint256 public constant FEE_RATE_MAX = 0.01e6; // max 1% on origin amount\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Chain gas amount to forward as rebate if requested\n uint256 public chainGasAmount;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n }\n\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n require(newFeeRate \u003c= FEE_RATE_MAX, \"newFeeRate \u003e max\");\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n token.universalTransfer(recipient, feeAmount);\n emit FeesSwept(token, recipient, feeAmount);\n }\n\n function setChainGasAmount(uint256 newChainGasAmount) external onlyRole(GOVERNOR_ROLE) {\n uint256 oldChainGasAmount = chainGasAmount;\n chainGasAmount = newChainGasAmount;\n emit ChainGasAmountUpdated(oldChainGasAmount, newChainGasAmount);\n }\n}\n\n// contracts/FastBridge.sol\n\ncontract FastBridge is IFastBridge, Admin {\n using SafeERC20 for IERC20;\n using UniversalTokenLib for address;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Delay for a transaction after which it could be permisionlessly refunded\n uint256 public constant REFUND_DELAY = 7 days;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeStatus) public bridgeStatuses;\n /// @notice Proof of relayed bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeProof) public bridgeProofs;\n /// @notice Whether bridge has been relayed on destination chain\n mapping(bytes32 =\u003e bool) public bridgeRelays;\n\n /// @dev to prevent replays\n uint256 public nonce;\n // @dev the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @notice Pulls a requested token from the user to the requested recipient.\n /// @dev Be careful of re-entrancy issues when msg.value \u003e 0 and recipient != address(this)\n function _pullToken(address recipient, address token, uint256 amount) internal returns (uint256 amountPulled) {\n if (token != UniversalTokenLib.ETH_ADDRESS) {\n token.assertIsContract();\n // Record token balance before transfer\n amountPulled = IERC20(token).balanceOf(recipient);\n // Token needs to be pulled only if msg.value is zero\n // This way user can specify WETH as the origin asset\n IERC20(token).safeTransferFrom(msg.sender, recipient, amount);\n // Use the difference between the recorded balance and the current balance as the amountPulled\n amountPulled = IERC20(token).balanceOf(recipient) - amountPulled;\n } else {\n // Otherwise, we need to check that ETH amount matches msg.value\n if (amount != msg.value) revert MsgValueIncorrect();\n // Transfer value to recipient if not this address\n if (recipient != address(this)) token.universalTransfer(recipient, amount);\n // We will forward msg.value in the external call later, if recipient is not this contract\n amountPulled = msg.value;\n }\n }\n\n /// @inheritdoc IFastBridge\n function getBridgeTransaction(bytes memory request) public pure returns (BridgeTransaction memory) {\n return abi.decode(request, (BridgeTransaction));\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n // check bridge params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n\n // transfer tokens to bridge contract\n // @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _pullToken(address(this), params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n\n // set status to requested\n bytes memory request = abi.encode(\n BridgeTransaction({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n sendChainGas: params.sendChainGas,\n deadline: params.deadline,\n nonce: nonce++ // increment nonce on every bridge\n })\n );\n bytes32 transactionId = keccak256(request);\n bridgeStatuses[transactionId] = BridgeStatus.REQUESTED;\n\n emit BridgeRequested(\n transactionId,\n params.sender,\n request,\n params.dstChainId,\n params.originToken,\n params.destToken,\n originAmount,\n params.destAmount,\n params.sendChainGas\n );\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes memory request) external payable onlyRole(RELAYER_ROLE) {\n bytes32 transactionId = keccak256(request);\n BridgeTransaction memory transaction = getBridgeTransaction(request);\n if (transaction.destChainId != uint32(block.chainid)) revert ChainIncorrect();\n\n // check haven't exceeded deadline for relay to happen\n if (block.timestamp \u003e transaction.deadline) revert DeadlineExceeded();\n\n // mark bridge transaction as relayed\n if (bridgeRelays[transactionId]) revert TransactionRelayed();\n bridgeRelays[transactionId] = true;\n\n // transfer tokens to recipient on destination chain and gas rebate if requested\n address to = transaction.destRecipient;\n address token = transaction.destToken;\n uint256 amount = transaction.destAmount;\n\n uint256 rebate = chainGasAmount;\n if (!transaction.sendChainGas) {\n // forward erc20\n rebate = 0;\n _pullToken(to, token, amount);\n } else if (token == UniversalTokenLib.ETH_ADDRESS) {\n // lump in gas rebate into amount in native gas token\n _pullToken(to, token, amount + rebate);\n } else {\n // forward erc20 then forward gas rebate in native gas token\n _pullToken(to, token, amount);\n _pullToken(to, UniversalTokenLib.ETH_ADDRESS, rebate);\n }\n\n emit BridgeRelayed(\n transactionId,\n msg.sender,\n to,\n transaction.originChainId,\n transaction.originToken,\n transaction.destToken,\n transaction.originAmount,\n transaction.destAmount,\n rebate\n );\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes memory request, bytes32 destTxHash) external onlyRole(RELAYER_ROLE) {\n bytes32 transactionId = keccak256(request);\n // update bridge tx status given proof provided\n if (bridgeStatuses[transactionId] != BridgeStatus.REQUESTED) revert StatusIncorrect();\n bridgeStatuses[transactionId] = BridgeStatus.RELAYER_PROVED;\n bridgeProofs[transactionId] = BridgeProof({timestamp: uint96(block.timestamp), relayer: msg.sender}); // overflow ok\n\n emit BridgeProofProvided(transactionId, msg.sender, destTxHash);\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint96(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint96).max but\n /// proof.timestamp \u003c type(uint96).max via unchecked statement\n /// @param proof The bridge proof\n /// @return delta Time delta since proof submitted\n function _timeSince(BridgeProof memory proof) internal view returns (uint256 delta) {\n unchecked {\n delta = uint96(block.timestamp) - proof.timestamp;\n }\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n if (bridgeStatuses[transactionId] != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n BridgeProof memory proof = bridgeProofs[transactionId];\n if (proof.relayer != relayer) revert SenderIncorrect();\n return _timeSince(proof) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes memory request, address to) external onlyRole(RELAYER_ROLE) {\n bytes32 transactionId = keccak256(request);\n BridgeTransaction memory transaction = getBridgeTransaction(request);\n\n // update bridge tx status if able to claim origin collateral\n if (bridgeStatuses[transactionId] != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n\n BridgeProof memory proof = bridgeProofs[transactionId];\n if (proof.relayer != msg.sender) revert SenderIncorrect();\n if (_timeSince(proof) \u003c= DISPUTE_PERIOD) revert DisputePeriodNotPassed();\n\n bridgeStatuses[transactionId] = BridgeStatus.RELAYER_CLAIMED;\n\n // update protocol fees if origin fee amount exists\n if (transaction.originFeeAmount \u003e 0) protocolFees[transaction.originToken] += transaction.originFeeAmount;\n\n // transfer origin collateral less fee to specified address\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositClaimed(transactionId, msg.sender, to, token, amount);\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n if (bridgeStatuses[transactionId] != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(bridgeProofs[transactionId]) \u003e DISPUTE_PERIOD) revert DisputePeriodPassed();\n\n // @dev relayer gets slashed effectively if dest relay has gone thru\n bridgeStatuses[transactionId] = BridgeStatus.REQUESTED;\n delete bridgeProofs[transactionId];\n\n emit BridgeProofDisputed(transactionId, msg.sender);\n }\n\n /// @inheritdoc IFastBridge\n function refund(bytes memory request) external {\n bytes32 transactionId = keccak256(request);\n BridgeTransaction memory transaction = getBridgeTransaction(request);\n\n if (hasRole(REFUNDER_ROLE, msg.sender)) {\n // Refunder can refund if deadline has passed\n if (block.timestamp \u003c= transaction.deadline) revert DeadlineNotExceeded();\n } else {\n // Permissionless refund is allowed after REFUND_DELAY\n if (block.timestamp \u003c= transaction.deadline + REFUND_DELAY) revert DeadlineNotExceeded();\n }\n\n // set status to refunded if still in requested state\n if (bridgeStatuses[transactionId] != BridgeStatus.REQUESTED) revert StatusIncorrect();\n bridgeStatuses[transactionId] = BridgeStatus.REFUNDED;\n\n // transfer origin collateral back to original sender\n address to = transaction.originSender;\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount + transaction.originFeeAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n }\n}\n\n// test/FastBridgeMock.sol\n\ncontract FastBridgeMock is IFastBridge, Admin {\n // @dev the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @dev to prevent replays\n uint256 public nonce;\n\n function getBridgeTransaction(bytes memory request) public pure returns (BridgeTransaction memory) {\n return abi.decode(request, (BridgeTransaction));\n }\n\n // used for testing in go.\n // see: https://ethereum.stackexchange.com/questions/21155/how-to-expose-enum-in-solidity-contract\n // make sure to update fastbridge/status.go if this changes\n // or underliyng enum changes.\n //\n // TODO: a foundry test should be added to ensure this is always in sync.\n function getEnumKeyByValue(FastBridge.BridgeStatus keyValue) public pure returns (string memory) {\n if (FastBridge.BridgeStatus.NULL == keyValue) return \"NULL\";\n if (FastBridge.BridgeStatus.REQUESTED == keyValue) return \"REQUESTED\";\n if (FastBridge.BridgeStatus.RELAYER_PROVED == keyValue) return \"RELAYER_PROVED\";\n if (FastBridge.BridgeStatus.RELAYER_CLAIMED == keyValue) return \"RELAYER_CLAIMED\";\n if (FastBridge.BridgeStatus.REFUNDED == keyValue) return \"REFUNDED\";\n return \"\";\n }\n\n function mockBridgeRequest(bytes32 transactionId, address sender, BridgeParams memory params) external {\n uint256 originFeeAmount = (params.originAmount * protocolFeeRate) / FEE_BPS;\n params.originAmount -= originFeeAmount;\n\n bytes memory request = abi.encode(\n BridgeTransaction({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: params.originAmount, // includes relayer fee\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n sendChainGas: params.sendChainGas,\n deadline: params.deadline,\n nonce: nonce++ // increment nonce on every bridge\n })\n );\n\n emit BridgeRequested(\n transactionId,\n params.sender,\n request,\n params.dstChainId,\n params.originToken,\n params.destToken,\n params.originAmount,\n params.destAmount,\n params.sendChainGas\n );\n }\n\n function mockBridgeRequestRaw(bytes32 transactionId, address sender, bytes memory request) external {\n BridgeTransaction memory transaction = getBridgeTransaction(request);\n emit BridgeRequested(\n transactionId,\n transaction.originSender,\n request,\n transaction.destChainId,\n transaction.originToken,\n transaction.destToken,\n transaction.originAmount,\n transaction.destAmount,\n transaction.sendChainGas\n );\n }\n\n function mockBridgeRelayer(\n bytes32 transactionId,\n address relayer,\n address to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n )\n external\n {\n emit BridgeRelayed(\n transactionId, relayer, to, originChainId, originToken, destToken, originAmount, destAmount, chainGasAmount\n );\n }\n\n function bridge(BridgeParams memory params) external payable {\n revert(\"not implemented\");\n }\n\n function relay(bytes memory request) external payable {\n revert(\"not implemented\");\n }\n\n function prove(bytes memory request, bytes32 destTxHash) external {\n revert(\"not implemented\");\n }\n\n function canClaim(bytes32 transactionid, address relayer) external view returns (bool) {\n revert(\"not implemented\");\n }\n\n function claim(bytes memory request, address to) external {\n revert(\"not implemented\");\n }\n\n function dispute(bytes32 transactionId) external {\n revert(\"not implemented\");\n }\n\n function refund(bytes memory request) external {\n revert(\"not implemented\");\n }\n}\n","language":"Solidity","languageVersion":"0.8.20","compilerVersion":"0.8.20","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"15591:6066:0:-:0;;;;;;;;;;;;;;;-1:-1:-1;;;15591:6066:0;;;;;;;;;;;;;;;;;","srcMapRuntime":"15591:6066:0:-:0;;;;;;;;","abiDefinition":[{"inputs":[{"internalType":"address","name":"target","type":"address"}],"name":"AddressEmptyCode","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"AddressInsufficientBalance","type":"error"},{"inputs":[],"name":"FailedInnerCall","type":"error"}],"userDoc":{"kind":"user","methods":{},"version":1},"developerDoc":{"details":"Collection of functions related to the address type","errors":{"AddressEmptyCode(address)":[{"details":"There's no code at `target` (it is not a contract)."}],"AddressInsufficientBalance(address)":[{"details":"The ETH balance of the account is not enough to perform the operation."}],"FailedInnerCall()":[{"details":"A call to an address target failed. The target may have reverted."}]},"kind":"dev","methods":{},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.20+commit.a1b79de6\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"}],\"name\":\"AddressEmptyCode\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"AddressInsufficientBalance\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"FailedInnerCall\",\"type\":\"error\"}],\"devdoc\":{\"details\":\"Collection of functions related to the address type\",\"errors\":{\"AddressEmptyCode(address)\":[{\"details\":\"There's no code at `target` (it is not a contract).\"}],\"AddressInsufficientBalance(address)\":[{\"details\":\"The ETH balance of the account is not enough to perform the operation.\"}],\"FailedInnerCall()\":[{\"details\":\"A call to an address target failed. The target may have reverted.\"}]},\"kind\":\"dev\",\"methods\":{},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeMock.sol\":\"Address\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeMock.sol\":{\"keccak256\":\"0x620e81214ecd324ae8b971219291f176c454ce76fb1c01d656428096da8f1366\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://18e556772c12e13aa2d52a50cc7c48e676c8d5af22b90adaf7befb39cdd08e64\",\"dweb:/ipfs/QmPrQc98TxHCFMeuFNADyjr6Nqo52rHhHy1LBcsVdMRXjL\"]}},\"version\":1}"},"hashes":{}},"solidity/FastBridgeMock.sol:Admin":{"code":"0x60806040523480156200001157600080fd5b50604051620014123803806200141283398101604081905262000034916200018e565b6200004160008262000049565b5050620001b9565b60008062000058848462000086565b905080156200007d5760008481526001602052604090206200007b908462000134565b505b90505b92915050565b6000828152602081815260408083206001600160a01b038516845290915281205460ff166200012b576000838152602081815260408083206001600160a01b03861684529091529020805460ff19166001179055620000e23390565b6001600160a01b0316826001600160a01b0316847f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a450600162000080565b50600062000080565b60006200007d836001600160a01b03841660008181526001830160205260408120546200012b5750815460018181018455600084815260208082209093018490558454848252828601909352604090209190915562000080565b600060208284031215620001a157600080fd5b81516001600160a01b03811681146200007d57600080fd5b61124980620001c96000396000f3fe608060405234801561001057600080fd5b50600436106101775760003560e01c806391d14854116100d8578063bf333f2c1161008c578063d547741f11610066578063d547741f14610385578063dcf844a714610398578063e00a83e0146103b857600080fd5b8063bf333f2c14610341578063ca15c8731461034b578063ccc574901461035e57600080fd5b8063a217fddf116100bd578063a217fddf14610313578063b13aa2d61461031b578063b250fe6b1461032e57600080fd5b806391d14854146102a8578063926d7d7f146102ec57600080fd5b80632f2ff15d1161012f57806358f858801161011457806358f85880146102405780635960ccf2146102495780639010d07c1461027057600080fd5b80632f2ff15d1461021a57806336568abe1461022d57600080fd5b806306f333f21161016057806306f333f2146101d95780630f5f6ed7146101ee578063248a9ca3146101f757600080fd5b806301ffc9a71461017c57806303ed0ee5146101a4575b600080fd5b61018f61018a366004611013565b6103c1565b60405190151581526020015b60405180910390f35b6101cb7f043c983c49d46f0e102151eaf8085d4a2e6571d5df2d47b013f39bddfd4a639d81565b60405190815260200161019b565b6101ec6101e736600461107e565b61041d565b005b6101cb61271081565b6101cb6102053660046110b1565b60009081526020819052604090206001015490565b6101ec6102283660046110ca565b61050b565b6101ec61023b3660046110ca565b610536565b6101cb60025481565b6101cb7fdb9556138406326f00296e13ea2ad7db24ba82381212d816b1a40c23b466b32781565b61028361027e3660046110ed565b61058f565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200161019b565b61018f6102b63660046110ca565b60009182526020828152604080842073ffffffffffffffffffffffffffffffffffffffff93909316845291905290205460ff1690565b6101cb7fe2b7fb3b832174769106daebcfd6d1970523240dda11281102db9363b83b0dc481565b6101cb600081565b6101ec6103293660046110b1565b6105ae565b6101ec61033c3660046110b1565b610690565b6101cb620f424081565b6101cb6103593660046110b1565b6106f8565b6101cb7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f5581565b6101ec6103933660046110ca565b61070f565b6101cb6103a636600461110f565b60036020526000908152604090205481565b6101cb60045481565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f5a05180f000000000000000000000000000000000000000000000000000000001480610417575061041782610734565b92915050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f55610447816107cb565b73ffffffffffffffffffffffffffffffffffffffff83166000908152600360205260408120549081900361047b5750505050565b73ffffffffffffffffffffffffffffffffffffffff84166000818152600360205260408120556104ac9084836107d8565b6040805173ffffffffffffffffffffffffffffffffffffffff8087168252851660208201529081018290527f244e51bc38c1452fa8aaf487bcb4bca36c2baa3a5fbdb776b1eabd8dc6d277cd9060600160405180910390a1505b505050565b600082815260208190526040902060010154610526816107cb565b610530838361092f565b50505050565b73ffffffffffffffffffffffffffffffffffffffff81163314610585576040517f6697b23200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6105068282610964565b60008281526001602052604081206105a79083610991565b9392505050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f556105d8816107cb565b612710821115610649576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f6e657746656552617465203e206d61780000000000000000000000000000000060448201526064015b60405180910390fd5b600280549083905560408051828152602081018590527f14914da2bf76024616fbe1859783fcd4dbddcb179b1f3a854949fbf920dcb95791015b60405180910390a1505050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f556106ba816107cb565b600480549083905560408051828152602081018590527f5cf09b12f3f56b4c564d51b25b40360af6d795198adb61ae0806a36c294323fa9101610683565b60008181526001602052604081206104179061099d565b60008281526020819052604090206001015461072a816107cb565b6105308383610964565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f7965db0b00000000000000000000000000000000000000000000000000000000148061041757507f01ffc9a7000000000000000000000000000000000000000000000000000000007fffffffff00000000000000000000000000000000000000000000000000000000831614610417565b6107d581336109a7565b50565b3073ffffffffffffffffffffffffffffffffffffffff8316036107fa57505050565b8060000361080757505050565b7fffffffffffffffffffffffff111111111111111111111111111111111111111273ffffffffffffffffffffffffffffffffffffffff84160161090e5760008273ffffffffffffffffffffffffffffffffffffffff168260405160006040518083038185875af1925050503d806000811461089e576040519150601f19603f3d011682016040523d82523d6000602084013e6108a3565b606091505b5050905080610530576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f455448207472616e73666572206661696c6564000000000000000000000000006044820152606401610640565b61050673ffffffffffffffffffffffffffffffffffffffff84168383610a31565b60008061093c8484610abe565b905080156105a757600084815260016020526040902061095c9084610bba565b509392505050565b6000806109718484610bdc565b905080156105a757600084815260016020526040902061095c9084610c97565b60006105a78383610cb9565b6000610417825490565b60008281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915290205460ff16610a2d576040517fe2517d3f00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8216600482015260248101839052604401610640565b5050565b6040805173ffffffffffffffffffffffffffffffffffffffff8416602482015260448082018490528251808303909101815260649091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fa9059cbb00000000000000000000000000000000000000000000000000000000179052610506908490610ce3565b60008281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915281205460ff16610bb25760008381526020818152604080832073ffffffffffffffffffffffffffffffffffffffff86168452909152902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055610b503390565b73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16847f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a4506001610417565b506000610417565b60006105a78373ffffffffffffffffffffffffffffffffffffffff8416610d79565b60008281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915281205460ff1615610bb25760008381526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8616808552925280832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016905551339286917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a4506001610417565b60006105a78373ffffffffffffffffffffffffffffffffffffffff8416610dc0565b6000826000018281548110610cd057610cd061112a565b9060005260206000200154905092915050565b6000610d0573ffffffffffffffffffffffffffffffffffffffff841683610eb3565b90508051600014158015610d2a575080806020019051810190610d289190611159565b155b15610506576040517f5274afe700000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff84166004820152602401610640565b6000818152600183016020526040812054610bb257508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155610417565b60008181526001830160205260408120548015610ea9576000610de460018361117b565b8554909150600090610df89060019061117b565b9050808214610e5d576000866000018281548110610e1857610e1861112a565b9060005260206000200154905080876000018481548110610e3b57610e3b61112a565b6000918252602080832090910192909255918252600188019052604090208390555b8554869080610e6e57610e6e6111b5565b600190038181906000526020600020016000905590558560010160008681526020019081526020016000206000905560019350505050610417565b6000915050610417565b60606105a783836000846000808573ffffffffffffffffffffffffffffffffffffffff168486604051610ee691906111e4565b60006040518083038185875af1925050503d8060008114610f23576040519150601f19603f3d011682016040523d82523d6000602084013e610f28565b606091505b5091509150610f38868383610f42565b9695505050505050565b606082610f5757610f5282610fd1565b6105a7565b8151158015610f7b575073ffffffffffffffffffffffffffffffffffffffff84163b155b15610fca576040517f9996b31500000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff85166004820152602401610640565b50806105a7565b805115610fe15780518082602001fd5b6040517f1425ea4200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006020828403121561102557600080fd5b81357fffffffff00000000000000000000000000000000000000000000000000000000811681146105a757600080fd5b803573ffffffffffffffffffffffffffffffffffffffff8116811461107957600080fd5b919050565b6000806040838503121561109157600080fd5b61109a83611055565b91506110a860208401611055565b90509250929050565b6000602082840312156110c357600080fd5b5035919050565b600080604083850312156110dd57600080fd5b823591506110a860208401611055565b6000806040838503121561110057600080fd5b50508035926020909101359150565b60006020828403121561112157600080fd5b6105a782611055565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60006020828403121561116b57600080fd5b815180151581146105a757600080fd5b81810381811115610417577f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fd5b6000825160005b8181101561120557602081860181015185830152016111eb565b50600092019182525091905056fea264697066735822122079131b92a1423b929ce85a16df536bfcfda7bffbb7079337b796201173ad4a2264736f6c63430008140033","runtime-code":"0x608060405234801561001057600080fd5b50600436106101775760003560e01c806391d14854116100d8578063bf333f2c1161008c578063d547741f11610066578063d547741f14610385578063dcf844a714610398578063e00a83e0146103b857600080fd5b8063bf333f2c14610341578063ca15c8731461034b578063ccc574901461035e57600080fd5b8063a217fddf116100bd578063a217fddf14610313578063b13aa2d61461031b578063b250fe6b1461032e57600080fd5b806391d14854146102a8578063926d7d7f146102ec57600080fd5b80632f2ff15d1161012f57806358f858801161011457806358f85880146102405780635960ccf2146102495780639010d07c1461027057600080fd5b80632f2ff15d1461021a57806336568abe1461022d57600080fd5b806306f333f21161016057806306f333f2146101d95780630f5f6ed7146101ee578063248a9ca3146101f757600080fd5b806301ffc9a71461017c57806303ed0ee5146101a4575b600080fd5b61018f61018a366004611013565b6103c1565b60405190151581526020015b60405180910390f35b6101cb7f043c983c49d46f0e102151eaf8085d4a2e6571d5df2d47b013f39bddfd4a639d81565b60405190815260200161019b565b6101ec6101e736600461107e565b61041d565b005b6101cb61271081565b6101cb6102053660046110b1565b60009081526020819052604090206001015490565b6101ec6102283660046110ca565b61050b565b6101ec61023b3660046110ca565b610536565b6101cb60025481565b6101cb7fdb9556138406326f00296e13ea2ad7db24ba82381212d816b1a40c23b466b32781565b61028361027e3660046110ed565b61058f565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200161019b565b61018f6102b63660046110ca565b60009182526020828152604080842073ffffffffffffffffffffffffffffffffffffffff93909316845291905290205460ff1690565b6101cb7fe2b7fb3b832174769106daebcfd6d1970523240dda11281102db9363b83b0dc481565b6101cb600081565b6101ec6103293660046110b1565b6105ae565b6101ec61033c3660046110b1565b610690565b6101cb620f424081565b6101cb6103593660046110b1565b6106f8565b6101cb7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f5581565b6101ec6103933660046110ca565b61070f565b6101cb6103a636600461110f565b60036020526000908152604090205481565b6101cb60045481565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f5a05180f000000000000000000000000000000000000000000000000000000001480610417575061041782610734565b92915050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f55610447816107cb565b73ffffffffffffffffffffffffffffffffffffffff83166000908152600360205260408120549081900361047b5750505050565b73ffffffffffffffffffffffffffffffffffffffff84166000818152600360205260408120556104ac9084836107d8565b6040805173ffffffffffffffffffffffffffffffffffffffff8087168252851660208201529081018290527f244e51bc38c1452fa8aaf487bcb4bca36c2baa3a5fbdb776b1eabd8dc6d277cd9060600160405180910390a1505b505050565b600082815260208190526040902060010154610526816107cb565b610530838361092f565b50505050565b73ffffffffffffffffffffffffffffffffffffffff81163314610585576040517f6697b23200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6105068282610964565b60008281526001602052604081206105a79083610991565b9392505050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f556105d8816107cb565b612710821115610649576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f6e657746656552617465203e206d61780000000000000000000000000000000060448201526064015b60405180910390fd5b600280549083905560408051828152602081018590527f14914da2bf76024616fbe1859783fcd4dbddcb179b1f3a854949fbf920dcb95791015b60405180910390a1505050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f556106ba816107cb565b600480549083905560408051828152602081018590527f5cf09b12f3f56b4c564d51b25b40360af6d795198adb61ae0806a36c294323fa9101610683565b60008181526001602052604081206104179061099d565b60008281526020819052604090206001015461072a816107cb565b6105308383610964565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f7965db0b00000000000000000000000000000000000000000000000000000000148061041757507f01ffc9a7000000000000000000000000000000000000000000000000000000007fffffffff00000000000000000000000000000000000000000000000000000000831614610417565b6107d581336109a7565b50565b3073ffffffffffffffffffffffffffffffffffffffff8316036107fa57505050565b8060000361080757505050565b7fffffffffffffffffffffffff111111111111111111111111111111111111111273ffffffffffffffffffffffffffffffffffffffff84160161090e5760008273ffffffffffffffffffffffffffffffffffffffff168260405160006040518083038185875af1925050503d806000811461089e576040519150601f19603f3d011682016040523d82523d6000602084013e6108a3565b606091505b5050905080610530576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f455448207472616e73666572206661696c6564000000000000000000000000006044820152606401610640565b61050673ffffffffffffffffffffffffffffffffffffffff84168383610a31565b60008061093c8484610abe565b905080156105a757600084815260016020526040902061095c9084610bba565b509392505050565b6000806109718484610bdc565b905080156105a757600084815260016020526040902061095c9084610c97565b60006105a78383610cb9565b6000610417825490565b60008281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915290205460ff16610a2d576040517fe2517d3f00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8216600482015260248101839052604401610640565b5050565b6040805173ffffffffffffffffffffffffffffffffffffffff8416602482015260448082018490528251808303909101815260649091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fa9059cbb00000000000000000000000000000000000000000000000000000000179052610506908490610ce3565b60008281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915281205460ff16610bb25760008381526020818152604080832073ffffffffffffffffffffffffffffffffffffffff86168452909152902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055610b503390565b73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16847f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a4506001610417565b506000610417565b60006105a78373ffffffffffffffffffffffffffffffffffffffff8416610d79565b60008281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915281205460ff1615610bb25760008381526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8616808552925280832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016905551339286917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a4506001610417565b60006105a78373ffffffffffffffffffffffffffffffffffffffff8416610dc0565b6000826000018281548110610cd057610cd061112a565b9060005260206000200154905092915050565b6000610d0573ffffffffffffffffffffffffffffffffffffffff841683610eb3565b90508051600014158015610d2a575080806020019051810190610d289190611159565b155b15610506576040517f5274afe700000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff84166004820152602401610640565b6000818152600183016020526040812054610bb257508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155610417565b60008181526001830160205260408120548015610ea9576000610de460018361117b565b8554909150600090610df89060019061117b565b9050808214610e5d576000866000018281548110610e1857610e1861112a565b9060005260206000200154905080876000018481548110610e3b57610e3b61112a565b6000918252602080832090910192909255918252600188019052604090208390555b8554869080610e6e57610e6e6111b5565b600190038181906000526020600020016000905590558560010160008681526020019081526020016000206000905560019350505050610417565b6000915050610417565b60606105a783836000846000808573ffffffffffffffffffffffffffffffffffffffff168486604051610ee691906111e4565b60006040518083038185875af1925050503d8060008114610f23576040519150601f19603f3d011682016040523d82523d6000602084013e610f28565b606091505b5091509150610f38868383610f42565b9695505050505050565b606082610f5757610f5282610fd1565b6105a7565b8151158015610f7b575073ffffffffffffffffffffffffffffffffffffffff84163b155b15610fca576040517f9996b31500000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff85166004820152602401610640565b50806105a7565b805115610fe15780518082602001fd5b6040517f1425ea4200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006020828403121561102557600080fd5b81357fffffffff00000000000000000000000000000000000000000000000000000000811681146105a757600080fd5b803573ffffffffffffffffffffffffffffffffffffffff8116811461107957600080fd5b919050565b6000806040838503121561109157600080fd5b61109a83611055565b91506110a860208401611055565b90509250929050565b6000602082840312156110c357600080fd5b5035919050565b600080604083850312156110dd57600080fd5b823591506110a860208401611055565b6000806040838503121561110057600080fd5b50508035926020909101359150565b60006020828403121561112157600080fd5b6105a782611055565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60006020828403121561116b57600080fd5b815180151581146105a757600080fd5b81810381811115610417577f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fd5b6000825160005b8181101561120557602081860181015185830152016111eb565b50600092019182525091905056fea264697066735822122079131b92a1423b929ce85a16df536bfcfda7bffbb7079337b796201173ad4a2264736f6c63430008140033","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.20 ^0.8.20;\n\n// contracts/interfaces/IAdmin.sol\n\ninterface IAdmin {\n // ============ Events ============\n\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n event ChainGasAmountUpdated(uint256 oldChainGasAmount, uint256 newChainGasAmount);\n\n // ============ Methods ============\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n\n function setChainGasAmount(uint256 newChainGasAmount) external;\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/libs/Errors.sol\n\nerror DeadlineExceeded();\nerror DeadlineNotExceeded();\nerror DeadlineTooShort();\nerror InsufficientOutputAmount();\n\nerror MsgValueIncorrect();\nerror PoolNotFound();\nerror TokenAddressMismatch();\nerror TokenNotContract();\nerror TokenNotETH();\nerror TokensIdentical();\n\nerror ChainIncorrect();\nerror AmountIncorrect();\nerror ZeroAddress();\n\nerror DisputePeriodNotPassed();\nerror DisputePeriodPassed();\nerror SenderIncorrect();\nerror StatusIncorrect();\nerror TransactionIdIncorrect();\nerror TransactionRelayed();\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// contracts/libs/UniversalToken.sol\n\nlibrary UniversalTokenLib {\n using SafeERC20 for IERC20;\n\n address internal constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Transfers tokens to the given account. Reverts if transfer is not successful.\n /// @dev This might trigger fallback, if ETH is transferred to the contract.\n /// Make sure this can not lead to reentrancy attacks.\n function universalTransfer(address token, address to, uint256 value) internal {\n // Don't do anything, if need to send tokens to this address\n if (to == address(this)) return;\n // Don't do anything, if trying to send zero value\n if (value == 0) return;\n if (token == ETH_ADDRESS) {\n /// @dev Note: this can potentially lead to executing code in `to`.\n // solhint-disable-next-line avoid-low-level-calls\n (bool success,) = to.call{value: value}(\"\");\n require(success, \"ETH transfer failed\");\n } else {\n IERC20(token).safeTransfer(to, value);\n }\n }\n\n /// @notice Issues an infinite allowance to the spender, if the current allowance is insufficient\n /// to spend the given amount.\n function universalApproveInfinity(address token, address spender, uint256 amountToSpend) internal {\n // ETH Chad doesn't require your approval\n if (token == ETH_ADDRESS) return;\n // No-op if allowance is already sufficient\n uint256 allowance = IERC20(token).allowance(address(this), spender);\n if (allowance \u003e= amountToSpend) return;\n // Otherwise, reset approval to 0 and set to max allowance\n if (allowance \u003e 0) IERC20(token).safeDecreaseAllowance(spender, allowance);\n IERC20(token).safeIncreaseAllowance(spender, type(uint256).max);\n }\n\n /// @notice Returns the balance of the given token (or native ETH) for the given account.\n function universalBalanceOf(address token, address account) internal view returns (uint256) {\n if (token == ETH_ADDRESS) {\n return account.balance;\n } else {\n return IERC20(token).balanceOf(account);\n }\n }\n\n /// @dev Checks that token is a contract and not ETH_ADDRESS.\n function assertIsContract(address token) internal view {\n // Check that ETH_ADDRESS was not used (in case this is a predeploy on any of the chains)\n if (token == UniversalTokenLib.ETH_ADDRESS) revert TokenNotContract();\n // Check that token is not an EOA\n if (token.code.length == 0) revert TokenNotContract();\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/Admin.sol\n\ncontract Admin is IAdmin, AccessControlEnumerable {\n using UniversalTokenLib for address;\n\n bytes32 public constant RELAYER_ROLE = keccak256(\"RELAYER_ROLE\");\n bytes32 public constant REFUNDER_ROLE = keccak256(\"REFUNDER_ROLE\");\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n uint256 public constant FEE_BPS = 1e6;\n uint256 public constant FEE_RATE_MAX = 0.01e6; // max 1% on origin amount\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Chain gas amount to forward as rebate if requested\n uint256 public chainGasAmount;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n }\n\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n require(newFeeRate \u003c= FEE_RATE_MAX, \"newFeeRate \u003e max\");\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n token.universalTransfer(recipient, feeAmount);\n emit FeesSwept(token, recipient, feeAmount);\n }\n\n function setChainGasAmount(uint256 newChainGasAmount) external onlyRole(GOVERNOR_ROLE) {\n uint256 oldChainGasAmount = chainGasAmount;\n chainGasAmount = newChainGasAmount;\n emit ChainGasAmountUpdated(oldChainGasAmount, newChainGasAmount);\n }\n}\n\n// contracts/FastBridge.sol\n\ncontract FastBridge is IFastBridge, Admin {\n using SafeERC20 for IERC20;\n using UniversalTokenLib for address;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Delay for a transaction after which it could be permisionlessly refunded\n uint256 public constant REFUND_DELAY = 7 days;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeStatus) public bridgeStatuses;\n /// @notice Proof of relayed bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeProof) public bridgeProofs;\n /// @notice Whether bridge has been relayed on destination chain\n mapping(bytes32 =\u003e bool) public bridgeRelays;\n\n /// @dev to prevent replays\n uint256 public nonce;\n // @dev the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @notice Pulls a requested token from the user to the requested recipient.\n /// @dev Be careful of re-entrancy issues when msg.value \u003e 0 and recipient != address(this)\n function _pullToken(address recipient, address token, uint256 amount) internal returns (uint256 amountPulled) {\n if (token != UniversalTokenLib.ETH_ADDRESS) {\n token.assertIsContract();\n // Record token balance before transfer\n amountPulled = IERC20(token).balanceOf(recipient);\n // Token needs to be pulled only if msg.value is zero\n // This way user can specify WETH as the origin asset\n IERC20(token).safeTransferFrom(msg.sender, recipient, amount);\n // Use the difference between the recorded balance and the current balance as the amountPulled\n amountPulled = IERC20(token).balanceOf(recipient) - amountPulled;\n } else {\n // Otherwise, we need to check that ETH amount matches msg.value\n if (amount != msg.value) revert MsgValueIncorrect();\n // Transfer value to recipient if not this address\n if (recipient != address(this)) token.universalTransfer(recipient, amount);\n // We will forward msg.value in the external call later, if recipient is not this contract\n amountPulled = msg.value;\n }\n }\n\n /// @inheritdoc IFastBridge\n function getBridgeTransaction(bytes memory request) public pure returns (BridgeTransaction memory) {\n return abi.decode(request, (BridgeTransaction));\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n // check bridge params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n\n // transfer tokens to bridge contract\n // @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _pullToken(address(this), params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n\n // set status to requested\n bytes memory request = abi.encode(\n BridgeTransaction({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n sendChainGas: params.sendChainGas,\n deadline: params.deadline,\n nonce: nonce++ // increment nonce on every bridge\n })\n );\n bytes32 transactionId = keccak256(request);\n bridgeStatuses[transactionId] = BridgeStatus.REQUESTED;\n\n emit BridgeRequested(\n transactionId,\n params.sender,\n request,\n params.dstChainId,\n params.originToken,\n params.destToken,\n originAmount,\n params.destAmount,\n params.sendChainGas\n );\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes memory request) external payable onlyRole(RELAYER_ROLE) {\n bytes32 transactionId = keccak256(request);\n BridgeTransaction memory transaction = getBridgeTransaction(request);\n if (transaction.destChainId != uint32(block.chainid)) revert ChainIncorrect();\n\n // check haven't exceeded deadline for relay to happen\n if (block.timestamp \u003e transaction.deadline) revert DeadlineExceeded();\n\n // mark bridge transaction as relayed\n if (bridgeRelays[transactionId]) revert TransactionRelayed();\n bridgeRelays[transactionId] = true;\n\n // transfer tokens to recipient on destination chain and gas rebate if requested\n address to = transaction.destRecipient;\n address token = transaction.destToken;\n uint256 amount = transaction.destAmount;\n\n uint256 rebate = chainGasAmount;\n if (!transaction.sendChainGas) {\n // forward erc20\n rebate = 0;\n _pullToken(to, token, amount);\n } else if (token == UniversalTokenLib.ETH_ADDRESS) {\n // lump in gas rebate into amount in native gas token\n _pullToken(to, token, amount + rebate);\n } else {\n // forward erc20 then forward gas rebate in native gas token\n _pullToken(to, token, amount);\n _pullToken(to, UniversalTokenLib.ETH_ADDRESS, rebate);\n }\n\n emit BridgeRelayed(\n transactionId,\n msg.sender,\n to,\n transaction.originChainId,\n transaction.originToken,\n transaction.destToken,\n transaction.originAmount,\n transaction.destAmount,\n rebate\n );\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes memory request, bytes32 destTxHash) external onlyRole(RELAYER_ROLE) {\n bytes32 transactionId = keccak256(request);\n // update bridge tx status given proof provided\n if (bridgeStatuses[transactionId] != BridgeStatus.REQUESTED) revert StatusIncorrect();\n bridgeStatuses[transactionId] = BridgeStatus.RELAYER_PROVED;\n bridgeProofs[transactionId] = BridgeProof({timestamp: uint96(block.timestamp), relayer: msg.sender}); // overflow ok\n\n emit BridgeProofProvided(transactionId, msg.sender, destTxHash);\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint96(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint96).max but\n /// proof.timestamp \u003c type(uint96).max via unchecked statement\n /// @param proof The bridge proof\n /// @return delta Time delta since proof submitted\n function _timeSince(BridgeProof memory proof) internal view returns (uint256 delta) {\n unchecked {\n delta = uint96(block.timestamp) - proof.timestamp;\n }\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n if (bridgeStatuses[transactionId] != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n BridgeProof memory proof = bridgeProofs[transactionId];\n if (proof.relayer != relayer) revert SenderIncorrect();\n return _timeSince(proof) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes memory request, address to) external onlyRole(RELAYER_ROLE) {\n bytes32 transactionId = keccak256(request);\n BridgeTransaction memory transaction = getBridgeTransaction(request);\n\n // update bridge tx status if able to claim origin collateral\n if (bridgeStatuses[transactionId] != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n\n BridgeProof memory proof = bridgeProofs[transactionId];\n if (proof.relayer != msg.sender) revert SenderIncorrect();\n if (_timeSince(proof) \u003c= DISPUTE_PERIOD) revert DisputePeriodNotPassed();\n\n bridgeStatuses[transactionId] = BridgeStatus.RELAYER_CLAIMED;\n\n // update protocol fees if origin fee amount exists\n if (transaction.originFeeAmount \u003e 0) protocolFees[transaction.originToken] += transaction.originFeeAmount;\n\n // transfer origin collateral less fee to specified address\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositClaimed(transactionId, msg.sender, to, token, amount);\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n if (bridgeStatuses[transactionId] != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(bridgeProofs[transactionId]) \u003e DISPUTE_PERIOD) revert DisputePeriodPassed();\n\n // @dev relayer gets slashed effectively if dest relay has gone thru\n bridgeStatuses[transactionId] = BridgeStatus.REQUESTED;\n delete bridgeProofs[transactionId];\n\n emit BridgeProofDisputed(transactionId, msg.sender);\n }\n\n /// @inheritdoc IFastBridge\n function refund(bytes memory request) external {\n bytes32 transactionId = keccak256(request);\n BridgeTransaction memory transaction = getBridgeTransaction(request);\n\n if (hasRole(REFUNDER_ROLE, msg.sender)) {\n // Refunder can refund if deadline has passed\n if (block.timestamp \u003c= transaction.deadline) revert DeadlineNotExceeded();\n } else {\n // Permissionless refund is allowed after REFUND_DELAY\n if (block.timestamp \u003c= transaction.deadline + REFUND_DELAY) revert DeadlineNotExceeded();\n }\n\n // set status to refunded if still in requested state\n if (bridgeStatuses[transactionId] != BridgeStatus.REQUESTED) revert StatusIncorrect();\n bridgeStatuses[transactionId] = BridgeStatus.REFUNDED;\n\n // transfer origin collateral back to original sender\n address to = transaction.originSender;\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount + transaction.originFeeAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n }\n}\n\n// test/FastBridgeMock.sol\n\ncontract FastBridgeMock is IFastBridge, Admin {\n // @dev the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @dev to prevent replays\n uint256 public nonce;\n\n function getBridgeTransaction(bytes memory request) public pure returns (BridgeTransaction memory) {\n return abi.decode(request, (BridgeTransaction));\n }\n\n // used for testing in go.\n // see: https://ethereum.stackexchange.com/questions/21155/how-to-expose-enum-in-solidity-contract\n // make sure to update fastbridge/status.go if this changes\n // or underliyng enum changes.\n //\n // TODO: a foundry test should be added to ensure this is always in sync.\n function getEnumKeyByValue(FastBridge.BridgeStatus keyValue) public pure returns (string memory) {\n if (FastBridge.BridgeStatus.NULL == keyValue) return \"NULL\";\n if (FastBridge.BridgeStatus.REQUESTED == keyValue) return \"REQUESTED\";\n if (FastBridge.BridgeStatus.RELAYER_PROVED == keyValue) return \"RELAYER_PROVED\";\n if (FastBridge.BridgeStatus.RELAYER_CLAIMED == keyValue) return \"RELAYER_CLAIMED\";\n if (FastBridge.BridgeStatus.REFUNDED == keyValue) return \"REFUNDED\";\n return \"\";\n }\n\n function mockBridgeRequest(bytes32 transactionId, address sender, BridgeParams memory params) external {\n uint256 originFeeAmount = (params.originAmount * protocolFeeRate) / FEE_BPS;\n params.originAmount -= originFeeAmount;\n\n bytes memory request = abi.encode(\n BridgeTransaction({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: params.originAmount, // includes relayer fee\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n sendChainGas: params.sendChainGas,\n deadline: params.deadline,\n nonce: nonce++ // increment nonce on every bridge\n })\n );\n\n emit BridgeRequested(\n transactionId,\n params.sender,\n request,\n params.dstChainId,\n params.originToken,\n params.destToken,\n params.originAmount,\n params.destAmount,\n params.sendChainGas\n );\n }\n\n function mockBridgeRequestRaw(bytes32 transactionId, address sender, bytes memory request) external {\n BridgeTransaction memory transaction = getBridgeTransaction(request);\n emit BridgeRequested(\n transactionId,\n transaction.originSender,\n request,\n transaction.destChainId,\n transaction.originToken,\n transaction.destToken,\n transaction.originAmount,\n transaction.destAmount,\n transaction.sendChainGas\n );\n }\n\n function mockBridgeRelayer(\n bytes32 transactionId,\n address relayer,\n address to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n )\n external\n {\n emit BridgeRelayed(\n transactionId, relayer, to, originChainId, originToken, destToken, originAmount, destAmount, chainGasAmount\n );\n }\n\n function bridge(BridgeParams memory params) external payable {\n revert(\"not implemented\");\n }\n\n function relay(bytes memory request) external payable {\n revert(\"not implemented\");\n }\n\n function prove(bytes memory request, bytes32 destTxHash) external {\n revert(\"not implemented\");\n }\n\n function canClaim(bytes32 transactionid, address relayer) external view returns (bool) {\n revert(\"not implemented\");\n }\n\n function claim(bytes memory request, address to) external {\n revert(\"not implemented\");\n }\n\n function dispute(bytes32 transactionId) external {\n revert(\"not implemented\");\n }\n\n function refund(bytes memory request) external {\n revert(\"not implemented\");\n }\n}\n","language":"Solidity","languageVersion":"0.8.20","compilerVersion":"0.8.20","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"56315:1843:0:-:0;;;57142:83;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;57180:38;46352:4;57211:6;57180:10;:38::i;:::-;;57142:83;56315:1843;;55665:257;55751:4;;55782:31;55799:4;55805:7;55782:16;:31::i;:::-;55767:46;;55827:7;55823:69;;;55850:18;;;;:12;:18;;;;;:31;;55873:7;55850:22;:31::i;:::-;;55823:69;55908:7;-1:-1:-1;55665:257:0;;;;;:::o;50299:316::-;50376:4;47074:12;;;;;;;;;;;-1:-1:-1;;;;;47074:29:0;;;;;;;;;;;;50392:217;;50435:6;:12;;;;;;;;;;;-1:-1:-1;;;;;50435:29:0;;;;;;;;;:36;;-1:-1:-1;;50435:36:0;50467:4;50435:36;;;50517:12;22395:10;;22316:96;50517:12;-1:-1:-1;;;;;50490:40:0;50508:7;-1:-1:-1;;;;;50490:40:0;50502:4;50490:40;;;;;;;;;;-1:-1:-1;50551:4:0;50544:11;;50392:217;-1:-1:-1;50593:5:0;50586:12;;31840:150;31910:4;31933:50;31938:3;-1:-1:-1;;;;;31958:23:0;;25828:4;27884:21;;;:14;;;:21;;;;;;25844:321;;-1:-1:-1;25886:23:0;;;;;;;;:11;:23;;;;;;;;;;;;;26068:18;;26044:21;;;:14;;;:21;;;;;;:42;;;;26100:11;;14:290:1;84:6;137:2;125:9;116:7;112:23;108:32;105:52;;;153:1;150;143:12;105:52;179:16;;-1:-1:-1;;;;;224:31:1;;214:42;;204:70;;270:1;267;260:12;14:290;56315:1843:0;;;;;;","srcMapRuntime":"56315:1843:0:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;54325:212;;;;;;:::i;:::-;;:::i;:::-;;;516:14:1;;509:22;491:41;;479:2;464:18;54325:212:0;;;;;;;;56555:60;;56592:23;56555:60;;;;;689:25:1;;;677:2;662:18;56555:60:0;543:177:1;57527:359:0;;;;;;:::i;:::-;;:::i;:::-;;56737:45;;56776:6;56737:45;;47930:120;;;;;;:::i;:::-;47995:7;48021:12;;;;;;;;;;:22;;;;47930:120;48346:136;;;;;;:::i;:::-;;:::i;49448:245::-;;;;;;:::i;:::-;;:::i;56899:30::-;;;;;;56483:66;;56523:26;56483:66;;55122:142;;;;;;:::i;:::-;;:::i;:::-;;;2246:42:1;2234:55;;;2216:74;;2204:2;2189:18;55122:142:0;2070:226:1;46974:136:0;;;;;;:::i;:::-;47051:4;47074:12;;;;;;;;;;;:29;;;;;;;;;;;;;;;;46974:136;56413:64;;56452:25;56413:64;;46307:49;;46352:4;46307:49;;57231:290;;;;;;:::i;:::-;;:::i;57892:264::-;;;;;;:::i;:::-;;:::i;56694:37::-;;56728:3;56694:37;;55432:131;;;;;;:::i;:::-;;:::i;56621:66::-;;56661:26;56621:66;;48762:138;;;;;;:::i;:::-;;:::i;56985:47::-;;;;;;:::i;:::-;;;;;;;;;;;;;;57106:29;;;;;;54325:212;54410:4;54433:57;;;54448:42;54433:57;;:97;;;54494:36;54518:11;54494:23;:36::i;:::-;54426:104;54325:212;-1:-1:-1;;54325:212:0:o;57527:359::-;56661:26;46584:16;46595:4;46584:10;:16::i;:::-;57651:19:::1;::::0;::::1;57631:17;57651:19:::0;;;:12:::1;:19;::::0;;;;;;57684:14;;;57680:27:::1;;57700:7;57527:359:::0;;;:::o;57680:27::-:1;57748:19;::::0;::::1;57770:1;57748:19:::0;;;:12:::1;:19;::::0;;;;:23;57781:45:::1;::::0;57805:9;57816;57781:23:::1;:45::i;:::-;57841:38;::::0;;2889:42:1;2958:15;;;2940:34;;3010:15;;3005:2;2990:18;;2983:43;3042:18;;;3035:34;;;57841:38:0::1;::::0;2867:2:1;2852:18;57841:38:0::1;;;;;;;57621:265;46610:1;57527:359:::0;;;:::o;48346:136::-;47995:7;48021:12;;;;;;;;;;:22;;;46584:16;46595:4;46584:10;:16::i;:::-;48450:25:::1;48461:4;48467:7;48450:10;:25::i;:::-;;48346:136:::0;;;:::o;49448:245::-;49541:34;;;22395:10;49541:34;49537:102;;49598:30;;;;;;;;;;;;;;49537:102;49649:37;49661:4;49667:18;49649:11;:37::i;55122:142::-;55203:7;55229:18;;;:12;:18;;;;;:28;;55251:5;55229:21;:28::i;:::-;55222:35;55122:142;-1:-1:-1;;;55122:142:0:o;57231:290::-;56661:26;46584:16;46595:4;46584:10;:16::i;:::-;56776:6:::1;57330:10;:26;;57322:55;;;::::0;::::1;::::0;;3282:2:1;57322:55:0::1;::::0;::::1;3264:21:1::0;3321:2;3301:18;;;3294:30;3360:18;3340;;;3333:46;3396:18;;57322:55:0::1;;;;;;;;;57408:15;::::0;;57433:28;;;;57476:38:::1;::::0;;3599:25:1;;;3655:2;3640:18;;3633:34;;;57476:38:0::1;::::0;3572:18:1;57476:38:0::1;;;;;;;;57312:209;57231:290:::0;;:::o;57892:264::-;56661:26;46584:16;46595:4;46584:10;:16::i;:::-;58017:14:::1;::::0;;58041:34;;;;58090:59:::1;::::0;;3599:25:1;;;3655:2;3640:18;;3633:34;;;58090:59:0::1;::::0;3572:18:1;58090:59:0::1;3425:248:1::0;55432:131:0;55503:7;55529:18;;;:12;:18;;;;;:27;;:25;:27::i;48762:138::-;47995:7;48021:12;;;;;;;;;;:22;;;46584:16;46595:4;46584:10;:16::i;:::-;48867:26:::1;48879:4;48885:7;48867:11;:26::i;46685:202::-:0;46770:4;46793:47;;;46808:32;46793:47;;:87;;-1:-1:-1;38600:25:0;38585:40;;;;46844:36;38486:146;47319:103;47385:30;47396:4;22395:10;47385;:30::i;:::-;47319:103;:::o;51597:653::-;51772:4;51758:19;;;;51754:32;;51597:653;;;:::o;51754:32::-;51858:5;51867:1;51858:10;51854:23;;51597:653;;;:::o;51854:23::-;51890:20;;;;;51886:358;;52070:12;52087:2;:7;;52102:5;52087:25;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;52069:43;;;52134:7;52126:39;;;;;;;4090:2:1;52126:39:0;;;4072:21:1;4129:2;4109:18;;;4102:30;4168:21;4148:18;;;4141:49;4207:18;;52126:39:0;3888:343:1;51886:358:0;52196:37;:26;;;52223:2;52227:5;52196:26;:37::i;55665:257::-;55751:4;55767:12;55782:31;55799:4;55805:7;55782:16;:31::i;:::-;55767:46;;55827:7;55823:69;;;55850:18;;;;:12;:18;;;;;:31;;55873:7;55850:22;:31::i;:::-;;55908:7;55665:257;-1:-1:-1;;;55665:257:0:o;56025:262::-;56112:4;56128:12;56143:32;56161:4;56167:7;56143:17;:32::i;:::-;56128:47;;56189:7;56185:72;;;56212:18;;;;:12;:18;;;;;:34;;56238:7;56212:25;:34::i;33098:156::-;33172:7;33222:22;33226:3;33238:5;33222:3;:22::i;32641:115::-;32704:7;32730:19;32738:3;28080:18;;27998:107;47552:197;47051:4;47074:12;;;;;;;;;;;:29;;;;;;;;;;;;;47635:108;;47685:47;;;;;4440:42:1;4428:55;;47685:47:0;;;4410:74:1;4500:18;;;4493:34;;;4383:18;;47685:47:0;4236:297:1;47635:108:0;47552:197;;:::o;39802:160::-;39911:43;;;39926:14;4428:55:1;;39911:43:0;;;4410:74:1;4500:18;;;;4493:34;;;39911:43:0;;;;;;;;;;4383:18:1;;;;39911:43:0;;;;;;;;;;;;;;39884:71;;39904:5;;39884:19;:71::i;50299:316::-;50376:4;47074:12;;;;;;;;;;;:29;;;;;;;;;;;;;50392:217;;50435:6;:12;;;;;;;;;;;:29;;;;;;;;;;:36;;;;50467:4;50435:36;;;50517:12;22395:10;;22316:96;50517:12;50490:40;;50508:7;50490:40;;50502:4;50490:40;;;;;;;;;;-1:-1:-1;50551:4:0;50544:11;;50392:217;-1:-1:-1;50593:5:0;50586:12;;31840:150;31910:4;31933:50;31938:3;31958:23;;;31933:4;:50::i;50850:317::-;50928:4;47074:12;;;;;;;;;;;:29;;;;;;;;;;;;;50944:217;;;51018:5;50986:12;;;;;;;;;;;:29;;;;;;;;;;;:37;;;;;;51042:40;22395:10;;50986:12;;51042:40;;51018:5;51042:40;-1:-1:-1;51103:4:0;51096:11;;32158:156;32231:4;32254:53;32262:3;32282:23;;;32254:7;:53::i;28447:118::-;28514:7;28540:3;:11;;28552:5;28540:18;;;;;;;;:::i;:::-;;;;;;;;;28533:25;;28447:118;;;;:::o;42558:629::-;42977:23;43003:33;:27;;;43031:4;43003:27;:33::i;:::-;42977:59;;43050:10;:17;43071:1;43050:22;;:57;;;;;43088:10;43077:30;;;;;;;;;;;;:::i;:::-;43076:31;43050:57;43046:135;;;43130:40;;;;;2246:42:1;2234:55;;43130:40:0;;;2216:74:1;2189:18;;43130:40:0;2070:226:1;25765:406:0;25828:4;27884:21;;;:14;;;:21;;;;;;25844:321;;-1:-1:-1;25886:23:0;;;;;;;;:11;:23;;;;;;;;;;;;;26068:18;;26044:21;;;:14;;;:21;;;;;;:42;;;;26100:11;;26339:1368;26405:4;26534:21;;;:14;;;:21;;;;;;26570:13;;26566:1135;;26937:18;26958:12;26969:1;26958:8;:12;:::i;:::-;27004:18;;26937:33;;-1:-1:-1;26984:17:0;;27004:22;;27025:1;;27004:22;:::i;:::-;26984:42;;27059:9;27045:10;:23;27041:378;;27088:17;27108:3;:11;;27120:9;27108:22;;;;;;;;:::i;:::-;;;;;;;;;27088:42;;27255:9;27229:3;:11;;27241:10;27229:23;;;;;;;;:::i;:::-;;;;;;;;;;;;:35;;;;27368:25;;;:14;;;:25;;;;;:36;;;27041:378;27497:17;;:3;;:17;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;27600:3;:14;;:21;27615:5;27600:21;;;;;;;;;;;27593:28;;;27643:4;27636:11;;;;;;;26566:1135;27685:5;27678:12;;;;;18101:151;18176:12;18207:38;18229:6;18237:4;18243:1;18176:12;18817;18831:23;18858:6;:11;;18877:5;18884:4;18858:31;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;18816:73;;;;18906:55;18933:6;18941:7;18950:10;18906:26;:55::i;:::-;18899:62;18576:392;-1:-1:-1;;;;;;18576:392:0:o;20021:582::-;20165:12;20194:7;20189:408;;20217:19;20225:10;20217:7;:19::i;:::-;20189:408;;;20441:17;;:22;:49;;;;-1:-1:-1;20467:18:0;;;;:23;20441:49;20437:119;;;20517:24;;;;;2246:42:1;2234:55;;20517:24:0;;;2216:74:1;2189:18;;20517:24:0;2070:226:1;20437:119:0;-1:-1:-1;20576:10:0;20569:17;;21139:516;21270:17;;:21;21266:383;;21498:10;21492:17;21554:15;21541:10;21537:2;21533:19;21526:44;21266:383;21621:17;;;;;;;;;;;;;;14:332:1;72:6;125:2;113:9;104:7;100:23;96:32;93:52;;;141:1;138;131:12;93:52;180:9;167:23;230:66;223:5;219:78;212:5;209:89;199:117;;312:1;309;302:12;725:196;793:20;;853:42;842:54;;832:65;;822:93;;911:1;908;901:12;822:93;725:196;;;:::o;926:260::-;994:6;1002;1055:2;1043:9;1034:7;1030:23;1026:32;1023:52;;;1071:1;1068;1061:12;1023:52;1094:29;1113:9;1094:29;:::i;:::-;1084:39;;1142:38;1176:2;1165:9;1161:18;1142:38;:::i;:::-;1132:48;;926:260;;;;;:::o;1373:180::-;1432:6;1485:2;1473:9;1464:7;1460:23;1456:32;1453:52;;;1501:1;1498;1491:12;1453:52;-1:-1:-1;1524:23:1;;1373:180;-1:-1:-1;1373:180:1:o;1558:254::-;1626:6;1634;1687:2;1675:9;1666:7;1662:23;1658:32;1655:52;;;1703:1;1700;1693:12;1655:52;1739:9;1726:23;1716:33;;1768:38;1802:2;1791:9;1787:18;1768:38;:::i;1817:248::-;1885:6;1893;1946:2;1934:9;1925:7;1921:23;1917:32;1914:52;;;1962:1;1959;1952:12;1914:52;-1:-1:-1;;1985:23:1;;;2055:2;2040:18;;;2027:32;;-1:-1:-1;1817:248:1:o;2486:186::-;2545:6;2598:2;2586:9;2577:7;2573:23;2569:32;2566:52;;;2614:1;2611;2604:12;2566:52;2637:29;2656:9;2637:29;:::i;4840:184::-;4892:77;4889:1;4882:88;4989:4;4986:1;4979:15;5013:4;5010:1;5003:15;5029:277;5096:6;5149:2;5137:9;5128:7;5124:23;5120:32;5117:52;;;5165:1;5162;5155:12;5117:52;5197:9;5191:16;5250:5;5243:13;5236:21;5229:5;5226:32;5216:60;;5272:1;5269;5262:12;5311:282;5378:9;;;5399:11;;;5396:191;;;5443:77;5440:1;5433:88;5544:4;5541:1;5534:15;5572:4;5569:1;5562:15;5598:184;5650:77;5647:1;5640:88;5747:4;5744:1;5737:15;5771:4;5768:1;5761:15;5787:412;5916:3;5954:6;5948:13;5979:1;5989:129;6003:6;6000:1;5997:13;5989:129;;;6101:4;6085:14;;;6081:25;;6075:32;6062:11;;;6055:53;6018:12;5989:129;;;-1:-1:-1;6173:1:1;6137:16;;6162:13;;;-1:-1:-1;6137:16:1;5787:412;-1:-1:-1;5787:412:1:o","abiDefinition":[{"inputs":[{"internalType":"address","name":"_owner","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AccessControlBadConfirmation","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"bytes32","name":"neededRole","type":"bytes32"}],"name":"AccessControlUnauthorizedAccount","type":"error"},{"inputs":[{"internalType":"address","name":"target","type":"address"}],"name":"AddressEmptyCode","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"AddressInsufficientBalance","type":"error"},{"inputs":[],"name":"FailedInnerCall","type":"error"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"SafeERC20FailedOperation","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldChainGasAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newChainGasAmount","type":"uint256"}],"name":"ChainGasAmountUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldFeeRate","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newFeeRate","type":"uint256"}],"name":"FeeRateUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"address","name":"recipient","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"FeesSwept","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"previousAdminRole","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"newAdminRole","type":"bytes32"}],"name":"RoleAdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleRevoked","type":"event"},{"inputs":[],"name":"DEFAULT_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"FEE_BPS","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"FEE_RATE_MAX","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"GOVERNOR_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"GUARD_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"REFUNDER_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"RELAYER_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"chainGasAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleAdmin","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"uint256","name":"index","type":"uint256"}],"name":"getRoleMember","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleMemberCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"grantRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"hasRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"protocolFeeRate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"protocolFees","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"callerConfirmation","type":"address"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"revokeRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"newChainGasAmount","type":"uint256"}],"name":"setChainGasAmount","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"newFeeRate","type":"uint256"}],"name":"setProtocolFeeRate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"address","name":"recipient","type":"address"}],"name":"sweepProtocolFees","outputs":[],"stateMutability":"nonpayable","type":"function"}],"userDoc":{"kind":"user","methods":{"chainGasAmount()":{"notice":"Chain gas amount to forward as rebate if requested"},"protocolFeeRate()":{"notice":"Protocol fee rate taken on origin amount deposited in origin chain"},"protocolFees(address)":{"notice":"Protocol fee amounts accumulated"}},"version":1},"developerDoc":{"errors":{"AccessControlBadConfirmation()":[{"details":"The caller of a function is not the expected one. NOTE: Don't confuse with {AccessControlUnauthorizedAccount}."}],"AccessControlUnauthorizedAccount(address,bytes32)":[{"details":"The `account` is missing a role."}],"AddressEmptyCode(address)":[{"details":"There's no code at `target` (it is not a contract)."}],"AddressInsufficientBalance(address)":[{"details":"The ETH balance of the account is not enough to perform the operation."}],"FailedInnerCall()":[{"details":"A call to an address target failed. The target may have reverted."}],"SafeERC20FailedOperation(address)":[{"details":"An operation with an ERC20 token failed."}]},"events":{"RoleAdminChanged(bytes32,bytes32,bytes32)":{"details":"Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole` `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite {RoleAdminChanged} not being emitted signaling this."},"RoleGranted(bytes32,address,address)":{"details":"Emitted when `account` is granted `role`. `sender` is the account that originated the contract call, an admin role bearer except when using {AccessControl-_setupRole}."},"RoleRevoked(bytes32,address,address)":{"details":"Emitted when `account` is revoked `role`. `sender` is the account that originated the contract call: - if using `revokeRole`, it is the admin role bearer - if using `renounceRole`, it is the role bearer (i.e. `account`)"}},"kind":"dev","methods":{"getRoleAdmin(bytes32)":{"details":"Returns the admin role that controls `role`. See {grantRole} and {revokeRole}. To change a role's admin, use {_setRoleAdmin}."},"getRoleMember(bytes32,uint256)":{"details":"Returns one of the accounts that have `role`. `index` must be a value between 0 and {getRoleMemberCount}, non-inclusive. Role bearers are not sorted in any particular way, and their ordering may change at any point. WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure you perform all queries on the same block. See the following https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post] for more information."},"getRoleMemberCount(bytes32)":{"details":"Returns the number of accounts that have `role`. Can be used together with {getRoleMember} to enumerate all bearers of a role."},"grantRole(bytes32,address)":{"details":"Grants `role` to `account`. If `account` had not been already granted `role`, emits a {RoleGranted} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleGranted} event."},"hasRole(bytes32,address)":{"details":"Returns `true` if `account` has been granted `role`."},"renounceRole(bytes32,address)":{"details":"Revokes `role` from the calling account. Roles are often managed via {grantRole} and {revokeRole}: this function's purpose is to provide a mechanism for accounts to lose their privileges if they are compromised (such as when a trusted device is misplaced). If the calling account had been revoked `role`, emits a {RoleRevoked} event. Requirements: - the caller must be `callerConfirmation`. May emit a {RoleRevoked} event."},"revokeRole(bytes32,address)":{"details":"Revokes `role` from `account`. If `account` had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleRevoked} event."},"supportsInterface(bytes4)":{"details":"See {IERC165-supportsInterface}."}},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.20+commit.a1b79de6\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_owner\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"AccessControlBadConfirmation\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"neededRole\",\"type\":\"bytes32\"}],\"name\":\"AccessControlUnauthorizedAccount\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"}],\"name\":\"AddressEmptyCode\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"AddressInsufficientBalance\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"FailedInnerCall\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"}],\"name\":\"SafeERC20FailedOperation\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"oldChainGasAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newChainGasAmount\",\"type\":\"uint256\"}],\"name\":\"ChainGasAmountUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"oldFeeRate\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newFeeRate\",\"type\":\"uint256\"}],\"name\":\"FeeRateUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"FeesSwept\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"previousAdminRole\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"newAdminRole\",\"type\":\"bytes32\"}],\"name\":\"RoleAdminChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleGranted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleRevoked\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"DEFAULT_ADMIN_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"FEE_BPS\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"FEE_RATE_MAX\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"GOVERNOR_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"GUARD_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"REFUNDER_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"RELAYER_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"chainGasAmount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"}],\"name\":\"getRoleAdmin\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"index\",\"type\":\"uint256\"}],\"name\":\"getRoleMember\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"}],\"name\":\"getRoleMemberCount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"grantRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"hasRole\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"protocolFeeRate\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"protocolFees\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"callerConfirmation\",\"type\":\"address\"}],\"name\":\"renounceRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"revokeRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"newChainGasAmount\",\"type\":\"uint256\"}],\"name\":\"setChainGasAmount\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"newFeeRate\",\"type\":\"uint256\"}],\"name\":\"setProtocolFeeRate\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes4\",\"name\":\"interfaceId\",\"type\":\"bytes4\"}],\"name\":\"supportsInterface\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"}],\"name\":\"sweepProtocolFees\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"errors\":{\"AccessControlBadConfirmation()\":[{\"details\":\"The caller of a function is not the expected one. NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\"}],\"AccessControlUnauthorizedAccount(address,bytes32)\":[{\"details\":\"The `account` is missing a role.\"}],\"AddressEmptyCode(address)\":[{\"details\":\"There's no code at `target` (it is not a contract).\"}],\"AddressInsufficientBalance(address)\":[{\"details\":\"The ETH balance of the account is not enough to perform the operation.\"}],\"FailedInnerCall()\":[{\"details\":\"A call to an address target failed. The target may have reverted.\"}],\"SafeERC20FailedOperation(address)\":[{\"details\":\"An operation with an ERC20 token failed.\"}]},\"events\":{\"RoleAdminChanged(bytes32,bytes32,bytes32)\":{\"details\":\"Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole` `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite {RoleAdminChanged} not being emitted signaling this.\"},\"RoleGranted(bytes32,address,address)\":{\"details\":\"Emitted when `account` is granted `role`. `sender` is the account that originated the contract call, an admin role bearer except when using {AccessControl-_setupRole}.\"},\"RoleRevoked(bytes32,address,address)\":{\"details\":\"Emitted when `account` is revoked `role`. `sender` is the account that originated the contract call: - if using `revokeRole`, it is the admin role bearer - if using `renounceRole`, it is the role bearer (i.e. `account`)\"}},\"kind\":\"dev\",\"methods\":{\"getRoleAdmin(bytes32)\":{\"details\":\"Returns the admin role that controls `role`. See {grantRole} and {revokeRole}. To change a role's admin, use {_setRoleAdmin}.\"},\"getRoleMember(bytes32,uint256)\":{\"details\":\"Returns one of the accounts that have `role`. `index` must be a value between 0 and {getRoleMemberCount}, non-inclusive. Role bearers are not sorted in any particular way, and their ordering may change at any point. WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure you perform all queries on the same block. See the following https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post] for more information.\"},\"getRoleMemberCount(bytes32)\":{\"details\":\"Returns the number of accounts that have `role`. Can be used together with {getRoleMember} to enumerate all bearers of a role.\"},\"grantRole(bytes32,address)\":{\"details\":\"Grants `role` to `account`. If `account` had not been already granted `role`, emits a {RoleGranted} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleGranted} event.\"},\"hasRole(bytes32,address)\":{\"details\":\"Returns `true` if `account` has been granted `role`.\"},\"renounceRole(bytes32,address)\":{\"details\":\"Revokes `role` from the calling account. Roles are often managed via {grantRole} and {revokeRole}: this function's purpose is to provide a mechanism for accounts to lose their privileges if they are compromised (such as when a trusted device is misplaced). If the calling account had been revoked `role`, emits a {RoleRevoked} event. Requirements: - the caller must be `callerConfirmation`. May emit a {RoleRevoked} event.\"},\"revokeRole(bytes32,address)\":{\"details\":\"Revokes `role` from `account`. If `account` had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleRevoked} event.\"},\"supportsInterface(bytes4)\":{\"details\":\"See {IERC165-supportsInterface}.\"}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"chainGasAmount()\":{\"notice\":\"Chain gas amount to forward as rebate if requested\"},\"protocolFeeRate()\":{\"notice\":\"Protocol fee rate taken on origin amount deposited in origin chain\"},\"protocolFees(address)\":{\"notice\":\"Protocol fee amounts accumulated\"}},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeMock.sol\":\"Admin\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeMock.sol\":{\"keccak256\":\"0x620e81214ecd324ae8b971219291f176c454ce76fb1c01d656428096da8f1366\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://18e556772c12e13aa2d52a50cc7c48e676c8d5af22b90adaf7befb39cdd08e64\",\"dweb:/ipfs/QmPrQc98TxHCFMeuFNADyjr6Nqo52rHhHy1LBcsVdMRXjL\"]}},\"version\":1}"},"hashes":{"DEFAULT_ADMIN_ROLE()":"a217fddf","FEE_BPS()":"bf333f2c","FEE_RATE_MAX()":"0f5f6ed7","GOVERNOR_ROLE()":"ccc57490","GUARD_ROLE()":"03ed0ee5","REFUNDER_ROLE()":"5960ccf2","RELAYER_ROLE()":"926d7d7f","chainGasAmount()":"e00a83e0","getRoleAdmin(bytes32)":"248a9ca3","getRoleMember(bytes32,uint256)":"9010d07c","getRoleMemberCount(bytes32)":"ca15c873","grantRole(bytes32,address)":"2f2ff15d","hasRole(bytes32,address)":"91d14854","protocolFeeRate()":"58f85880","protocolFees(address)":"dcf844a7","renounceRole(bytes32,address)":"36568abe","revokeRole(bytes32,address)":"d547741f","setChainGasAmount(uint256)":"b250fe6b","setProtocolFeeRate(uint256)":"b13aa2d6","supportsInterface(bytes4)":"01ffc9a7","sweepProtocolFees(address,address)":"06f333f2"}},"solidity/FastBridgeMock.sol:Context":{"code":"0x","runtime-code":"0x","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.20 ^0.8.20;\n\n// contracts/interfaces/IAdmin.sol\n\ninterface IAdmin {\n // ============ Events ============\n\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n event ChainGasAmountUpdated(uint256 oldChainGasAmount, uint256 newChainGasAmount);\n\n // ============ Methods ============\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n\n function setChainGasAmount(uint256 newChainGasAmount) external;\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/libs/Errors.sol\n\nerror DeadlineExceeded();\nerror DeadlineNotExceeded();\nerror DeadlineTooShort();\nerror InsufficientOutputAmount();\n\nerror MsgValueIncorrect();\nerror PoolNotFound();\nerror TokenAddressMismatch();\nerror TokenNotContract();\nerror TokenNotETH();\nerror TokensIdentical();\n\nerror ChainIncorrect();\nerror AmountIncorrect();\nerror ZeroAddress();\n\nerror DisputePeriodNotPassed();\nerror DisputePeriodPassed();\nerror SenderIncorrect();\nerror StatusIncorrect();\nerror TransactionIdIncorrect();\nerror TransactionRelayed();\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// contracts/libs/UniversalToken.sol\n\nlibrary UniversalTokenLib {\n using SafeERC20 for IERC20;\n\n address internal constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Transfers tokens to the given account. Reverts if transfer is not successful.\n /// @dev This might trigger fallback, if ETH is transferred to the contract.\n /// Make sure this can not lead to reentrancy attacks.\n function universalTransfer(address token, address to, uint256 value) internal {\n // Don't do anything, if need to send tokens to this address\n if (to == address(this)) return;\n // Don't do anything, if trying to send zero value\n if (value == 0) return;\n if (token == ETH_ADDRESS) {\n /// @dev Note: this can potentially lead to executing code in `to`.\n // solhint-disable-next-line avoid-low-level-calls\n (bool success,) = to.call{value: value}(\"\");\n require(success, \"ETH transfer failed\");\n } else {\n IERC20(token).safeTransfer(to, value);\n }\n }\n\n /// @notice Issues an infinite allowance to the spender, if the current allowance is insufficient\n /// to spend the given amount.\n function universalApproveInfinity(address token, address spender, uint256 amountToSpend) internal {\n // ETH Chad doesn't require your approval\n if (token == ETH_ADDRESS) return;\n // No-op if allowance is already sufficient\n uint256 allowance = IERC20(token).allowance(address(this), spender);\n if (allowance \u003e= amountToSpend) return;\n // Otherwise, reset approval to 0 and set to max allowance\n if (allowance \u003e 0) IERC20(token).safeDecreaseAllowance(spender, allowance);\n IERC20(token).safeIncreaseAllowance(spender, type(uint256).max);\n }\n\n /// @notice Returns the balance of the given token (or native ETH) for the given account.\n function universalBalanceOf(address token, address account) internal view returns (uint256) {\n if (token == ETH_ADDRESS) {\n return account.balance;\n } else {\n return IERC20(token).balanceOf(account);\n }\n }\n\n /// @dev Checks that token is a contract and not ETH_ADDRESS.\n function assertIsContract(address token) internal view {\n // Check that ETH_ADDRESS was not used (in case this is a predeploy on any of the chains)\n if (token == UniversalTokenLib.ETH_ADDRESS) revert TokenNotContract();\n // Check that token is not an EOA\n if (token.code.length == 0) revert TokenNotContract();\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/Admin.sol\n\ncontract Admin is IAdmin, AccessControlEnumerable {\n using UniversalTokenLib for address;\n\n bytes32 public constant RELAYER_ROLE = keccak256(\"RELAYER_ROLE\");\n bytes32 public constant REFUNDER_ROLE = keccak256(\"REFUNDER_ROLE\");\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n uint256 public constant FEE_BPS = 1e6;\n uint256 public constant FEE_RATE_MAX = 0.01e6; // max 1% on origin amount\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Chain gas amount to forward as rebate if requested\n uint256 public chainGasAmount;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n }\n\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n require(newFeeRate \u003c= FEE_RATE_MAX, \"newFeeRate \u003e max\");\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n token.universalTransfer(recipient, feeAmount);\n emit FeesSwept(token, recipient, feeAmount);\n }\n\n function setChainGasAmount(uint256 newChainGasAmount) external onlyRole(GOVERNOR_ROLE) {\n uint256 oldChainGasAmount = chainGasAmount;\n chainGasAmount = newChainGasAmount;\n emit ChainGasAmountUpdated(oldChainGasAmount, newChainGasAmount);\n }\n}\n\n// contracts/FastBridge.sol\n\ncontract FastBridge is IFastBridge, Admin {\n using SafeERC20 for IERC20;\n using UniversalTokenLib for address;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Delay for a transaction after which it could be permisionlessly refunded\n uint256 public constant REFUND_DELAY = 7 days;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeStatus) public bridgeStatuses;\n /// @notice Proof of relayed bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeProof) public bridgeProofs;\n /// @notice Whether bridge has been relayed on destination chain\n mapping(bytes32 =\u003e bool) public bridgeRelays;\n\n /// @dev to prevent replays\n uint256 public nonce;\n // @dev the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @notice Pulls a requested token from the user to the requested recipient.\n /// @dev Be careful of re-entrancy issues when msg.value \u003e 0 and recipient != address(this)\n function _pullToken(address recipient, address token, uint256 amount) internal returns (uint256 amountPulled) {\n if (token != UniversalTokenLib.ETH_ADDRESS) {\n token.assertIsContract();\n // Record token balance before transfer\n amountPulled = IERC20(token).balanceOf(recipient);\n // Token needs to be pulled only if msg.value is zero\n // This way user can specify WETH as the origin asset\n IERC20(token).safeTransferFrom(msg.sender, recipient, amount);\n // Use the difference between the recorded balance and the current balance as the amountPulled\n amountPulled = IERC20(token).balanceOf(recipient) - amountPulled;\n } else {\n // Otherwise, we need to check that ETH amount matches msg.value\n if (amount != msg.value) revert MsgValueIncorrect();\n // Transfer value to recipient if not this address\n if (recipient != address(this)) token.universalTransfer(recipient, amount);\n // We will forward msg.value in the external call later, if recipient is not this contract\n amountPulled = msg.value;\n }\n }\n\n /// @inheritdoc IFastBridge\n function getBridgeTransaction(bytes memory request) public pure returns (BridgeTransaction memory) {\n return abi.decode(request, (BridgeTransaction));\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n // check bridge params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n\n // transfer tokens to bridge contract\n // @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _pullToken(address(this), params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n\n // set status to requested\n bytes memory request = abi.encode(\n BridgeTransaction({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n sendChainGas: params.sendChainGas,\n deadline: params.deadline,\n nonce: nonce++ // increment nonce on every bridge\n })\n );\n bytes32 transactionId = keccak256(request);\n bridgeStatuses[transactionId] = BridgeStatus.REQUESTED;\n\n emit BridgeRequested(\n transactionId,\n params.sender,\n request,\n params.dstChainId,\n params.originToken,\n params.destToken,\n originAmount,\n params.destAmount,\n params.sendChainGas\n );\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes memory request) external payable onlyRole(RELAYER_ROLE) {\n bytes32 transactionId = keccak256(request);\n BridgeTransaction memory transaction = getBridgeTransaction(request);\n if (transaction.destChainId != uint32(block.chainid)) revert ChainIncorrect();\n\n // check haven't exceeded deadline for relay to happen\n if (block.timestamp \u003e transaction.deadline) revert DeadlineExceeded();\n\n // mark bridge transaction as relayed\n if (bridgeRelays[transactionId]) revert TransactionRelayed();\n bridgeRelays[transactionId] = true;\n\n // transfer tokens to recipient on destination chain and gas rebate if requested\n address to = transaction.destRecipient;\n address token = transaction.destToken;\n uint256 amount = transaction.destAmount;\n\n uint256 rebate = chainGasAmount;\n if (!transaction.sendChainGas) {\n // forward erc20\n rebate = 0;\n _pullToken(to, token, amount);\n } else if (token == UniversalTokenLib.ETH_ADDRESS) {\n // lump in gas rebate into amount in native gas token\n _pullToken(to, token, amount + rebate);\n } else {\n // forward erc20 then forward gas rebate in native gas token\n _pullToken(to, token, amount);\n _pullToken(to, UniversalTokenLib.ETH_ADDRESS, rebate);\n }\n\n emit BridgeRelayed(\n transactionId,\n msg.sender,\n to,\n transaction.originChainId,\n transaction.originToken,\n transaction.destToken,\n transaction.originAmount,\n transaction.destAmount,\n rebate\n );\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes memory request, bytes32 destTxHash) external onlyRole(RELAYER_ROLE) {\n bytes32 transactionId = keccak256(request);\n // update bridge tx status given proof provided\n if (bridgeStatuses[transactionId] != BridgeStatus.REQUESTED) revert StatusIncorrect();\n bridgeStatuses[transactionId] = BridgeStatus.RELAYER_PROVED;\n bridgeProofs[transactionId] = BridgeProof({timestamp: uint96(block.timestamp), relayer: msg.sender}); // overflow ok\n\n emit BridgeProofProvided(transactionId, msg.sender, destTxHash);\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint96(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint96).max but\n /// proof.timestamp \u003c type(uint96).max via unchecked statement\n /// @param proof The bridge proof\n /// @return delta Time delta since proof submitted\n function _timeSince(BridgeProof memory proof) internal view returns (uint256 delta) {\n unchecked {\n delta = uint96(block.timestamp) - proof.timestamp;\n }\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n if (bridgeStatuses[transactionId] != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n BridgeProof memory proof = bridgeProofs[transactionId];\n if (proof.relayer != relayer) revert SenderIncorrect();\n return _timeSince(proof) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes memory request, address to) external onlyRole(RELAYER_ROLE) {\n bytes32 transactionId = keccak256(request);\n BridgeTransaction memory transaction = getBridgeTransaction(request);\n\n // update bridge tx status if able to claim origin collateral\n if (bridgeStatuses[transactionId] != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n\n BridgeProof memory proof = bridgeProofs[transactionId];\n if (proof.relayer != msg.sender) revert SenderIncorrect();\n if (_timeSince(proof) \u003c= DISPUTE_PERIOD) revert DisputePeriodNotPassed();\n\n bridgeStatuses[transactionId] = BridgeStatus.RELAYER_CLAIMED;\n\n // update protocol fees if origin fee amount exists\n if (transaction.originFeeAmount \u003e 0) protocolFees[transaction.originToken] += transaction.originFeeAmount;\n\n // transfer origin collateral less fee to specified address\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositClaimed(transactionId, msg.sender, to, token, amount);\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n if (bridgeStatuses[transactionId] != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(bridgeProofs[transactionId]) \u003e DISPUTE_PERIOD) revert DisputePeriodPassed();\n\n // @dev relayer gets slashed effectively if dest relay has gone thru\n bridgeStatuses[transactionId] = BridgeStatus.REQUESTED;\n delete bridgeProofs[transactionId];\n\n emit BridgeProofDisputed(transactionId, msg.sender);\n }\n\n /// @inheritdoc IFastBridge\n function refund(bytes memory request) external {\n bytes32 transactionId = keccak256(request);\n BridgeTransaction memory transaction = getBridgeTransaction(request);\n\n if (hasRole(REFUNDER_ROLE, msg.sender)) {\n // Refunder can refund if deadline has passed\n if (block.timestamp \u003c= transaction.deadline) revert DeadlineNotExceeded();\n } else {\n // Permissionless refund is allowed after REFUND_DELAY\n if (block.timestamp \u003c= transaction.deadline + REFUND_DELAY) revert DeadlineNotExceeded();\n }\n\n // set status to refunded if still in requested state\n if (bridgeStatuses[transactionId] != BridgeStatus.REQUESTED) revert StatusIncorrect();\n bridgeStatuses[transactionId] = BridgeStatus.REFUNDED;\n\n // transfer origin collateral back to original sender\n address to = transaction.originSender;\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount + transaction.originFeeAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n }\n}\n\n// test/FastBridgeMock.sol\n\ncontract FastBridgeMock is IFastBridge, Admin {\n // @dev the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @dev to prevent replays\n uint256 public nonce;\n\n function getBridgeTransaction(bytes memory request) public pure returns (BridgeTransaction memory) {\n return abi.decode(request, (BridgeTransaction));\n }\n\n // used for testing in go.\n // see: https://ethereum.stackexchange.com/questions/21155/how-to-expose-enum-in-solidity-contract\n // make sure to update fastbridge/status.go if this changes\n // or underliyng enum changes.\n //\n // TODO: a foundry test should be added to ensure this is always in sync.\n function getEnumKeyByValue(FastBridge.BridgeStatus keyValue) public pure returns (string memory) {\n if (FastBridge.BridgeStatus.NULL == keyValue) return \"NULL\";\n if (FastBridge.BridgeStatus.REQUESTED == keyValue) return \"REQUESTED\";\n if (FastBridge.BridgeStatus.RELAYER_PROVED == keyValue) return \"RELAYER_PROVED\";\n if (FastBridge.BridgeStatus.RELAYER_CLAIMED == keyValue) return \"RELAYER_CLAIMED\";\n if (FastBridge.BridgeStatus.REFUNDED == keyValue) return \"REFUNDED\";\n return \"\";\n }\n\n function mockBridgeRequest(bytes32 transactionId, address sender, BridgeParams memory params) external {\n uint256 originFeeAmount = (params.originAmount * protocolFeeRate) / FEE_BPS;\n params.originAmount -= originFeeAmount;\n\n bytes memory request = abi.encode(\n BridgeTransaction({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: params.originAmount, // includes relayer fee\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n sendChainGas: params.sendChainGas,\n deadline: params.deadline,\n nonce: nonce++ // increment nonce on every bridge\n })\n );\n\n emit BridgeRequested(\n transactionId,\n params.sender,\n request,\n params.dstChainId,\n params.originToken,\n params.destToken,\n params.originAmount,\n params.destAmount,\n params.sendChainGas\n );\n }\n\n function mockBridgeRequestRaw(bytes32 transactionId, address sender, bytes memory request) external {\n BridgeTransaction memory transaction = getBridgeTransaction(request);\n emit BridgeRequested(\n transactionId,\n transaction.originSender,\n request,\n transaction.destChainId,\n transaction.originToken,\n transaction.destToken,\n transaction.originAmount,\n transaction.destAmount,\n transaction.sendChainGas\n );\n }\n\n function mockBridgeRelayer(\n bytes32 transactionId,\n address relayer,\n address to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n )\n external\n {\n emit BridgeRelayed(\n transactionId, relayer, to, originChainId, originToken, destToken, originAmount, destAmount, chainGasAmount\n );\n }\n\n function bridge(BridgeParams memory params) external payable {\n revert(\"not implemented\");\n }\n\n function relay(bytes memory request) external payable {\n revert(\"not implemented\");\n }\n\n function prove(bytes memory request, bytes32 destTxHash) external {\n revert(\"not implemented\");\n }\n\n function canClaim(bytes32 transactionid, address relayer) external view returns (bool) {\n revert(\"not implemented\");\n }\n\n function claim(bytes memory request, address to) external {\n revert(\"not implemented\");\n }\n\n function dispute(bytes32 transactionId) external {\n revert(\"not implemented\");\n }\n\n function refund(bytes memory request) external {\n revert(\"not implemented\");\n }\n}\n","language":"Solidity","languageVersion":"0.8.20","compilerVersion":"0.8.20","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"","srcMapRuntime":"","abiDefinition":[],"userDoc":{"kind":"user","methods":{},"version":1},"developerDoc":{"details":"Provides information about the current execution context, including the sender of the transaction and its data. While these are generally available via msg.sender and msg.data, they should not be accessed in such a direct manner, since when dealing with meta-transactions the account sending and paying for execution may not be the actual sender (as far as an application is concerned). This contract is only required for intermediate, library-like contracts.","kind":"dev","methods":{},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.20+commit.a1b79de6\"},\"language\":\"Solidity\",\"output\":{\"abi\":[],\"devdoc\":{\"details\":\"Provides information about the current execution context, including the sender of the transaction and its data. While these are generally available via msg.sender and msg.data, they should not be accessed in such a direct manner, since when dealing with meta-transactions the account sending and paying for execution may not be the actual sender (as far as an application is concerned). This contract is only required for intermediate, library-like contracts.\",\"kind\":\"dev\",\"methods\":{},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeMock.sol\":\"Context\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeMock.sol\":{\"keccak256\":\"0x620e81214ecd324ae8b971219291f176c454ce76fb1c01d656428096da8f1366\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://18e556772c12e13aa2d52a50cc7c48e676c8d5af22b90adaf7befb39cdd08e64\",\"dweb:/ipfs/QmPrQc98TxHCFMeuFNADyjr6Nqo52rHhHy1LBcsVdMRXjL\"]}},\"version\":1}"},"hashes":{}},"solidity/FastBridgeMock.sol:ERC165":{"code":"0x","runtime-code":"0x","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.20 ^0.8.20;\n\n// contracts/interfaces/IAdmin.sol\n\ninterface IAdmin {\n // ============ Events ============\n\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n event ChainGasAmountUpdated(uint256 oldChainGasAmount, uint256 newChainGasAmount);\n\n // ============ Methods ============\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n\n function setChainGasAmount(uint256 newChainGasAmount) external;\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/libs/Errors.sol\n\nerror DeadlineExceeded();\nerror DeadlineNotExceeded();\nerror DeadlineTooShort();\nerror InsufficientOutputAmount();\n\nerror MsgValueIncorrect();\nerror PoolNotFound();\nerror TokenAddressMismatch();\nerror TokenNotContract();\nerror TokenNotETH();\nerror TokensIdentical();\n\nerror ChainIncorrect();\nerror AmountIncorrect();\nerror ZeroAddress();\n\nerror DisputePeriodNotPassed();\nerror DisputePeriodPassed();\nerror SenderIncorrect();\nerror StatusIncorrect();\nerror TransactionIdIncorrect();\nerror TransactionRelayed();\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// contracts/libs/UniversalToken.sol\n\nlibrary UniversalTokenLib {\n using SafeERC20 for IERC20;\n\n address internal constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Transfers tokens to the given account. Reverts if transfer is not successful.\n /// @dev This might trigger fallback, if ETH is transferred to the contract.\n /// Make sure this can not lead to reentrancy attacks.\n function universalTransfer(address token, address to, uint256 value) internal {\n // Don't do anything, if need to send tokens to this address\n if (to == address(this)) return;\n // Don't do anything, if trying to send zero value\n if (value == 0) return;\n if (token == ETH_ADDRESS) {\n /// @dev Note: this can potentially lead to executing code in `to`.\n // solhint-disable-next-line avoid-low-level-calls\n (bool success,) = to.call{value: value}(\"\");\n require(success, \"ETH transfer failed\");\n } else {\n IERC20(token).safeTransfer(to, value);\n }\n }\n\n /// @notice Issues an infinite allowance to the spender, if the current allowance is insufficient\n /// to spend the given amount.\n function universalApproveInfinity(address token, address spender, uint256 amountToSpend) internal {\n // ETH Chad doesn't require your approval\n if (token == ETH_ADDRESS) return;\n // No-op if allowance is already sufficient\n uint256 allowance = IERC20(token).allowance(address(this), spender);\n if (allowance \u003e= amountToSpend) return;\n // Otherwise, reset approval to 0 and set to max allowance\n if (allowance \u003e 0) IERC20(token).safeDecreaseAllowance(spender, allowance);\n IERC20(token).safeIncreaseAllowance(spender, type(uint256).max);\n }\n\n /// @notice Returns the balance of the given token (or native ETH) for the given account.\n function universalBalanceOf(address token, address account) internal view returns (uint256) {\n if (token == ETH_ADDRESS) {\n return account.balance;\n } else {\n return IERC20(token).balanceOf(account);\n }\n }\n\n /// @dev Checks that token is a contract and not ETH_ADDRESS.\n function assertIsContract(address token) internal view {\n // Check that ETH_ADDRESS was not used (in case this is a predeploy on any of the chains)\n if (token == UniversalTokenLib.ETH_ADDRESS) revert TokenNotContract();\n // Check that token is not an EOA\n if (token.code.length == 0) revert TokenNotContract();\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/Admin.sol\n\ncontract Admin is IAdmin, AccessControlEnumerable {\n using UniversalTokenLib for address;\n\n bytes32 public constant RELAYER_ROLE = keccak256(\"RELAYER_ROLE\");\n bytes32 public constant REFUNDER_ROLE = keccak256(\"REFUNDER_ROLE\");\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n uint256 public constant FEE_BPS = 1e6;\n uint256 public constant FEE_RATE_MAX = 0.01e6; // max 1% on origin amount\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Chain gas amount to forward as rebate if requested\n uint256 public chainGasAmount;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n }\n\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n require(newFeeRate \u003c= FEE_RATE_MAX, \"newFeeRate \u003e max\");\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n token.universalTransfer(recipient, feeAmount);\n emit FeesSwept(token, recipient, feeAmount);\n }\n\n function setChainGasAmount(uint256 newChainGasAmount) external onlyRole(GOVERNOR_ROLE) {\n uint256 oldChainGasAmount = chainGasAmount;\n chainGasAmount = newChainGasAmount;\n emit ChainGasAmountUpdated(oldChainGasAmount, newChainGasAmount);\n }\n}\n\n// contracts/FastBridge.sol\n\ncontract FastBridge is IFastBridge, Admin {\n using SafeERC20 for IERC20;\n using UniversalTokenLib for address;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Delay for a transaction after which it could be permisionlessly refunded\n uint256 public constant REFUND_DELAY = 7 days;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeStatus) public bridgeStatuses;\n /// @notice Proof of relayed bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeProof) public bridgeProofs;\n /// @notice Whether bridge has been relayed on destination chain\n mapping(bytes32 =\u003e bool) public bridgeRelays;\n\n /// @dev to prevent replays\n uint256 public nonce;\n // @dev the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @notice Pulls a requested token from the user to the requested recipient.\n /// @dev Be careful of re-entrancy issues when msg.value \u003e 0 and recipient != address(this)\n function _pullToken(address recipient, address token, uint256 amount) internal returns (uint256 amountPulled) {\n if (token != UniversalTokenLib.ETH_ADDRESS) {\n token.assertIsContract();\n // Record token balance before transfer\n amountPulled = IERC20(token).balanceOf(recipient);\n // Token needs to be pulled only if msg.value is zero\n // This way user can specify WETH as the origin asset\n IERC20(token).safeTransferFrom(msg.sender, recipient, amount);\n // Use the difference between the recorded balance and the current balance as the amountPulled\n amountPulled = IERC20(token).balanceOf(recipient) - amountPulled;\n } else {\n // Otherwise, we need to check that ETH amount matches msg.value\n if (amount != msg.value) revert MsgValueIncorrect();\n // Transfer value to recipient if not this address\n if (recipient != address(this)) token.universalTransfer(recipient, amount);\n // We will forward msg.value in the external call later, if recipient is not this contract\n amountPulled = msg.value;\n }\n }\n\n /// @inheritdoc IFastBridge\n function getBridgeTransaction(bytes memory request) public pure returns (BridgeTransaction memory) {\n return abi.decode(request, (BridgeTransaction));\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n // check bridge params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n\n // transfer tokens to bridge contract\n // @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _pullToken(address(this), params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n\n // set status to requested\n bytes memory request = abi.encode(\n BridgeTransaction({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n sendChainGas: params.sendChainGas,\n deadline: params.deadline,\n nonce: nonce++ // increment nonce on every bridge\n })\n );\n bytes32 transactionId = keccak256(request);\n bridgeStatuses[transactionId] = BridgeStatus.REQUESTED;\n\n emit BridgeRequested(\n transactionId,\n params.sender,\n request,\n params.dstChainId,\n params.originToken,\n params.destToken,\n originAmount,\n params.destAmount,\n params.sendChainGas\n );\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes memory request) external payable onlyRole(RELAYER_ROLE) {\n bytes32 transactionId = keccak256(request);\n BridgeTransaction memory transaction = getBridgeTransaction(request);\n if (transaction.destChainId != uint32(block.chainid)) revert ChainIncorrect();\n\n // check haven't exceeded deadline for relay to happen\n if (block.timestamp \u003e transaction.deadline) revert DeadlineExceeded();\n\n // mark bridge transaction as relayed\n if (bridgeRelays[transactionId]) revert TransactionRelayed();\n bridgeRelays[transactionId] = true;\n\n // transfer tokens to recipient on destination chain and gas rebate if requested\n address to = transaction.destRecipient;\n address token = transaction.destToken;\n uint256 amount = transaction.destAmount;\n\n uint256 rebate = chainGasAmount;\n if (!transaction.sendChainGas) {\n // forward erc20\n rebate = 0;\n _pullToken(to, token, amount);\n } else if (token == UniversalTokenLib.ETH_ADDRESS) {\n // lump in gas rebate into amount in native gas token\n _pullToken(to, token, amount + rebate);\n } else {\n // forward erc20 then forward gas rebate in native gas token\n _pullToken(to, token, amount);\n _pullToken(to, UniversalTokenLib.ETH_ADDRESS, rebate);\n }\n\n emit BridgeRelayed(\n transactionId,\n msg.sender,\n to,\n transaction.originChainId,\n transaction.originToken,\n transaction.destToken,\n transaction.originAmount,\n transaction.destAmount,\n rebate\n );\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes memory request, bytes32 destTxHash) external onlyRole(RELAYER_ROLE) {\n bytes32 transactionId = keccak256(request);\n // update bridge tx status given proof provided\n if (bridgeStatuses[transactionId] != BridgeStatus.REQUESTED) revert StatusIncorrect();\n bridgeStatuses[transactionId] = BridgeStatus.RELAYER_PROVED;\n bridgeProofs[transactionId] = BridgeProof({timestamp: uint96(block.timestamp), relayer: msg.sender}); // overflow ok\n\n emit BridgeProofProvided(transactionId, msg.sender, destTxHash);\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint96(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint96).max but\n /// proof.timestamp \u003c type(uint96).max via unchecked statement\n /// @param proof The bridge proof\n /// @return delta Time delta since proof submitted\n function _timeSince(BridgeProof memory proof) internal view returns (uint256 delta) {\n unchecked {\n delta = uint96(block.timestamp) - proof.timestamp;\n }\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n if (bridgeStatuses[transactionId] != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n BridgeProof memory proof = bridgeProofs[transactionId];\n if (proof.relayer != relayer) revert SenderIncorrect();\n return _timeSince(proof) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes memory request, address to) external onlyRole(RELAYER_ROLE) {\n bytes32 transactionId = keccak256(request);\n BridgeTransaction memory transaction = getBridgeTransaction(request);\n\n // update bridge tx status if able to claim origin collateral\n if (bridgeStatuses[transactionId] != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n\n BridgeProof memory proof = bridgeProofs[transactionId];\n if (proof.relayer != msg.sender) revert SenderIncorrect();\n if (_timeSince(proof) \u003c= DISPUTE_PERIOD) revert DisputePeriodNotPassed();\n\n bridgeStatuses[transactionId] = BridgeStatus.RELAYER_CLAIMED;\n\n // update protocol fees if origin fee amount exists\n if (transaction.originFeeAmount \u003e 0) protocolFees[transaction.originToken] += transaction.originFeeAmount;\n\n // transfer origin collateral less fee to specified address\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositClaimed(transactionId, msg.sender, to, token, amount);\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n if (bridgeStatuses[transactionId] != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(bridgeProofs[transactionId]) \u003e DISPUTE_PERIOD) revert DisputePeriodPassed();\n\n // @dev relayer gets slashed effectively if dest relay has gone thru\n bridgeStatuses[transactionId] = BridgeStatus.REQUESTED;\n delete bridgeProofs[transactionId];\n\n emit BridgeProofDisputed(transactionId, msg.sender);\n }\n\n /// @inheritdoc IFastBridge\n function refund(bytes memory request) external {\n bytes32 transactionId = keccak256(request);\n BridgeTransaction memory transaction = getBridgeTransaction(request);\n\n if (hasRole(REFUNDER_ROLE, msg.sender)) {\n // Refunder can refund if deadline has passed\n if (block.timestamp \u003c= transaction.deadline) revert DeadlineNotExceeded();\n } else {\n // Permissionless refund is allowed after REFUND_DELAY\n if (block.timestamp \u003c= transaction.deadline + REFUND_DELAY) revert DeadlineNotExceeded();\n }\n\n // set status to refunded if still in requested state\n if (bridgeStatuses[transactionId] != BridgeStatus.REQUESTED) revert StatusIncorrect();\n bridgeStatuses[transactionId] = BridgeStatus.REFUNDED;\n\n // transfer origin collateral back to original sender\n address to = transaction.originSender;\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount + transaction.originFeeAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n }\n}\n\n// test/FastBridgeMock.sol\n\ncontract FastBridgeMock is IFastBridge, Admin {\n // @dev the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @dev to prevent replays\n uint256 public nonce;\n\n function getBridgeTransaction(bytes memory request) public pure returns (BridgeTransaction memory) {\n return abi.decode(request, (BridgeTransaction));\n }\n\n // used for testing in go.\n // see: https://ethereum.stackexchange.com/questions/21155/how-to-expose-enum-in-solidity-contract\n // make sure to update fastbridge/status.go if this changes\n // or underliyng enum changes.\n //\n // TODO: a foundry test should be added to ensure this is always in sync.\n function getEnumKeyByValue(FastBridge.BridgeStatus keyValue) public pure returns (string memory) {\n if (FastBridge.BridgeStatus.NULL == keyValue) return \"NULL\";\n if (FastBridge.BridgeStatus.REQUESTED == keyValue) return \"REQUESTED\";\n if (FastBridge.BridgeStatus.RELAYER_PROVED == keyValue) return \"RELAYER_PROVED\";\n if (FastBridge.BridgeStatus.RELAYER_CLAIMED == keyValue) return \"RELAYER_CLAIMED\";\n if (FastBridge.BridgeStatus.REFUNDED == keyValue) return \"REFUNDED\";\n return \"\";\n }\n\n function mockBridgeRequest(bytes32 transactionId, address sender, BridgeParams memory params) external {\n uint256 originFeeAmount = (params.originAmount * protocolFeeRate) / FEE_BPS;\n params.originAmount -= originFeeAmount;\n\n bytes memory request = abi.encode(\n BridgeTransaction({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: params.originAmount, // includes relayer fee\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n sendChainGas: params.sendChainGas,\n deadline: params.deadline,\n nonce: nonce++ // increment nonce on every bridge\n })\n );\n\n emit BridgeRequested(\n transactionId,\n params.sender,\n request,\n params.dstChainId,\n params.originToken,\n params.destToken,\n params.originAmount,\n params.destAmount,\n params.sendChainGas\n );\n }\n\n function mockBridgeRequestRaw(bytes32 transactionId, address sender, bytes memory request) external {\n BridgeTransaction memory transaction = getBridgeTransaction(request);\n emit BridgeRequested(\n transactionId,\n transaction.originSender,\n request,\n transaction.destChainId,\n transaction.originToken,\n transaction.destToken,\n transaction.originAmount,\n transaction.destAmount,\n transaction.sendChainGas\n );\n }\n\n function mockBridgeRelayer(\n bytes32 transactionId,\n address relayer,\n address to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n )\n external\n {\n emit BridgeRelayed(\n transactionId, relayer, to, originChainId, originToken, destToken, originAmount, destAmount, chainGasAmount\n );\n }\n\n function bridge(BridgeParams memory params) external payable {\n revert(\"not implemented\");\n }\n\n function relay(bytes memory request) external payable {\n revert(\"not implemented\");\n }\n\n function prove(bytes memory request, bytes32 destTxHash) external {\n revert(\"not implemented\");\n }\n\n function canClaim(bytes32 transactionid, address relayer) external view returns (bool) {\n revert(\"not implemented\");\n }\n\n function claim(bytes memory request, address to) external {\n revert(\"not implemented\");\n }\n\n function dispute(bytes32 transactionId) external {\n revert(\"not implemented\");\n }\n\n function refund(bytes memory request) external {\n revert(\"not implemented\");\n }\n}\n","language":"Solidity","languageVersion":"0.8.20","compilerVersion":"0.8.20","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"","srcMapRuntime":"","abiDefinition":[{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"}],"userDoc":{"kind":"user","methods":{},"version":1},"developerDoc":{"details":"Implementation of the {IERC165} interface. Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check for the additional interface id that will be supported. For example: ```solidity function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId); } ```","kind":"dev","methods":{"supportsInterface(bytes4)":{"details":"See {IERC165-supportsInterface}."}},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.20+commit.a1b79de6\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"bytes4\",\"name\":\"interfaceId\",\"type\":\"bytes4\"}],\"name\":\"supportsInterface\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"}],\"devdoc\":{\"details\":\"Implementation of the {IERC165} interface. Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check for the additional interface id that will be supported. For example: ```solidity function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId); } ```\",\"kind\":\"dev\",\"methods\":{\"supportsInterface(bytes4)\":{\"details\":\"See {IERC165-supportsInterface}.\"}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeMock.sol\":\"ERC165\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeMock.sol\":{\"keccak256\":\"0x620e81214ecd324ae8b971219291f176c454ce76fb1c01d656428096da8f1366\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://18e556772c12e13aa2d52a50cc7c48e676c8d5af22b90adaf7befb39cdd08e64\",\"dweb:/ipfs/QmPrQc98TxHCFMeuFNADyjr6Nqo52rHhHy1LBcsVdMRXjL\"]}},\"version\":1}"},"hashes":{"supportsInterface(bytes4)":"01ffc9a7"}},"solidity/FastBridgeMock.sol:EnumerableSet":{"code":"0x60566037600b82828239805160001a607314602a57634e487b7160e01b600052600060045260246000fd5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600080fdfea264697066735822122061192eb5b75fa46e55c42a092ec06111165ec29e2ac6d00c6d247f0df8ba17fd64736f6c63430008140033","runtime-code":"0x73000000000000000000000000000000000000000030146080604052600080fdfea264697066735822122061192eb5b75fa46e55c42a092ec06111165ec29e2ac6d00c6d247f0df8ba17fd64736f6c63430008140033","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.20 ^0.8.20;\n\n// contracts/interfaces/IAdmin.sol\n\ninterface IAdmin {\n // ============ Events ============\n\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n event ChainGasAmountUpdated(uint256 oldChainGasAmount, uint256 newChainGasAmount);\n\n // ============ Methods ============\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n\n function setChainGasAmount(uint256 newChainGasAmount) external;\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/libs/Errors.sol\n\nerror DeadlineExceeded();\nerror DeadlineNotExceeded();\nerror DeadlineTooShort();\nerror InsufficientOutputAmount();\n\nerror MsgValueIncorrect();\nerror PoolNotFound();\nerror TokenAddressMismatch();\nerror TokenNotContract();\nerror TokenNotETH();\nerror TokensIdentical();\n\nerror ChainIncorrect();\nerror AmountIncorrect();\nerror ZeroAddress();\n\nerror DisputePeriodNotPassed();\nerror DisputePeriodPassed();\nerror SenderIncorrect();\nerror StatusIncorrect();\nerror TransactionIdIncorrect();\nerror TransactionRelayed();\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// contracts/libs/UniversalToken.sol\n\nlibrary UniversalTokenLib {\n using SafeERC20 for IERC20;\n\n address internal constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Transfers tokens to the given account. Reverts if transfer is not successful.\n /// @dev This might trigger fallback, if ETH is transferred to the contract.\n /// Make sure this can not lead to reentrancy attacks.\n function universalTransfer(address token, address to, uint256 value) internal {\n // Don't do anything, if need to send tokens to this address\n if (to == address(this)) return;\n // Don't do anything, if trying to send zero value\n if (value == 0) return;\n if (token == ETH_ADDRESS) {\n /// @dev Note: this can potentially lead to executing code in `to`.\n // solhint-disable-next-line avoid-low-level-calls\n (bool success,) = to.call{value: value}(\"\");\n require(success, \"ETH transfer failed\");\n } else {\n IERC20(token).safeTransfer(to, value);\n }\n }\n\n /// @notice Issues an infinite allowance to the spender, if the current allowance is insufficient\n /// to spend the given amount.\n function universalApproveInfinity(address token, address spender, uint256 amountToSpend) internal {\n // ETH Chad doesn't require your approval\n if (token == ETH_ADDRESS) return;\n // No-op if allowance is already sufficient\n uint256 allowance = IERC20(token).allowance(address(this), spender);\n if (allowance \u003e= amountToSpend) return;\n // Otherwise, reset approval to 0 and set to max allowance\n if (allowance \u003e 0) IERC20(token).safeDecreaseAllowance(spender, allowance);\n IERC20(token).safeIncreaseAllowance(spender, type(uint256).max);\n }\n\n /// @notice Returns the balance of the given token (or native ETH) for the given account.\n function universalBalanceOf(address token, address account) internal view returns (uint256) {\n if (token == ETH_ADDRESS) {\n return account.balance;\n } else {\n return IERC20(token).balanceOf(account);\n }\n }\n\n /// @dev Checks that token is a contract and not ETH_ADDRESS.\n function assertIsContract(address token) internal view {\n // Check that ETH_ADDRESS was not used (in case this is a predeploy on any of the chains)\n if (token == UniversalTokenLib.ETH_ADDRESS) revert TokenNotContract();\n // Check that token is not an EOA\n if (token.code.length == 0) revert TokenNotContract();\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/Admin.sol\n\ncontract Admin is IAdmin, AccessControlEnumerable {\n using UniversalTokenLib for address;\n\n bytes32 public constant RELAYER_ROLE = keccak256(\"RELAYER_ROLE\");\n bytes32 public constant REFUNDER_ROLE = keccak256(\"REFUNDER_ROLE\");\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n uint256 public constant FEE_BPS = 1e6;\n uint256 public constant FEE_RATE_MAX = 0.01e6; // max 1% on origin amount\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Chain gas amount to forward as rebate if requested\n uint256 public chainGasAmount;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n }\n\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n require(newFeeRate \u003c= FEE_RATE_MAX, \"newFeeRate \u003e max\");\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n token.universalTransfer(recipient, feeAmount);\n emit FeesSwept(token, recipient, feeAmount);\n }\n\n function setChainGasAmount(uint256 newChainGasAmount) external onlyRole(GOVERNOR_ROLE) {\n uint256 oldChainGasAmount = chainGasAmount;\n chainGasAmount = newChainGasAmount;\n emit ChainGasAmountUpdated(oldChainGasAmount, newChainGasAmount);\n }\n}\n\n// contracts/FastBridge.sol\n\ncontract FastBridge is IFastBridge, Admin {\n using SafeERC20 for IERC20;\n using UniversalTokenLib for address;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Delay for a transaction after which it could be permisionlessly refunded\n uint256 public constant REFUND_DELAY = 7 days;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeStatus) public bridgeStatuses;\n /// @notice Proof of relayed bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeProof) public bridgeProofs;\n /// @notice Whether bridge has been relayed on destination chain\n mapping(bytes32 =\u003e bool) public bridgeRelays;\n\n /// @dev to prevent replays\n uint256 public nonce;\n // @dev the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @notice Pulls a requested token from the user to the requested recipient.\n /// @dev Be careful of re-entrancy issues when msg.value \u003e 0 and recipient != address(this)\n function _pullToken(address recipient, address token, uint256 amount) internal returns (uint256 amountPulled) {\n if (token != UniversalTokenLib.ETH_ADDRESS) {\n token.assertIsContract();\n // Record token balance before transfer\n amountPulled = IERC20(token).balanceOf(recipient);\n // Token needs to be pulled only if msg.value is zero\n // This way user can specify WETH as the origin asset\n IERC20(token).safeTransferFrom(msg.sender, recipient, amount);\n // Use the difference between the recorded balance and the current balance as the amountPulled\n amountPulled = IERC20(token).balanceOf(recipient) - amountPulled;\n } else {\n // Otherwise, we need to check that ETH amount matches msg.value\n if (amount != msg.value) revert MsgValueIncorrect();\n // Transfer value to recipient if not this address\n if (recipient != address(this)) token.universalTransfer(recipient, amount);\n // We will forward msg.value in the external call later, if recipient is not this contract\n amountPulled = msg.value;\n }\n }\n\n /// @inheritdoc IFastBridge\n function getBridgeTransaction(bytes memory request) public pure returns (BridgeTransaction memory) {\n return abi.decode(request, (BridgeTransaction));\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n // check bridge params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n\n // transfer tokens to bridge contract\n // @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _pullToken(address(this), params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n\n // set status to requested\n bytes memory request = abi.encode(\n BridgeTransaction({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n sendChainGas: params.sendChainGas,\n deadline: params.deadline,\n nonce: nonce++ // increment nonce on every bridge\n })\n );\n bytes32 transactionId = keccak256(request);\n bridgeStatuses[transactionId] = BridgeStatus.REQUESTED;\n\n emit BridgeRequested(\n transactionId,\n params.sender,\n request,\n params.dstChainId,\n params.originToken,\n params.destToken,\n originAmount,\n params.destAmount,\n params.sendChainGas\n );\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes memory request) external payable onlyRole(RELAYER_ROLE) {\n bytes32 transactionId = keccak256(request);\n BridgeTransaction memory transaction = getBridgeTransaction(request);\n if (transaction.destChainId != uint32(block.chainid)) revert ChainIncorrect();\n\n // check haven't exceeded deadline for relay to happen\n if (block.timestamp \u003e transaction.deadline) revert DeadlineExceeded();\n\n // mark bridge transaction as relayed\n if (bridgeRelays[transactionId]) revert TransactionRelayed();\n bridgeRelays[transactionId] = true;\n\n // transfer tokens to recipient on destination chain and gas rebate if requested\n address to = transaction.destRecipient;\n address token = transaction.destToken;\n uint256 amount = transaction.destAmount;\n\n uint256 rebate = chainGasAmount;\n if (!transaction.sendChainGas) {\n // forward erc20\n rebate = 0;\n _pullToken(to, token, amount);\n } else if (token == UniversalTokenLib.ETH_ADDRESS) {\n // lump in gas rebate into amount in native gas token\n _pullToken(to, token, amount + rebate);\n } else {\n // forward erc20 then forward gas rebate in native gas token\n _pullToken(to, token, amount);\n _pullToken(to, UniversalTokenLib.ETH_ADDRESS, rebate);\n }\n\n emit BridgeRelayed(\n transactionId,\n msg.sender,\n to,\n transaction.originChainId,\n transaction.originToken,\n transaction.destToken,\n transaction.originAmount,\n transaction.destAmount,\n rebate\n );\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes memory request, bytes32 destTxHash) external onlyRole(RELAYER_ROLE) {\n bytes32 transactionId = keccak256(request);\n // update bridge tx status given proof provided\n if (bridgeStatuses[transactionId] != BridgeStatus.REQUESTED) revert StatusIncorrect();\n bridgeStatuses[transactionId] = BridgeStatus.RELAYER_PROVED;\n bridgeProofs[transactionId] = BridgeProof({timestamp: uint96(block.timestamp), relayer: msg.sender}); // overflow ok\n\n emit BridgeProofProvided(transactionId, msg.sender, destTxHash);\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint96(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint96).max but\n /// proof.timestamp \u003c type(uint96).max via unchecked statement\n /// @param proof The bridge proof\n /// @return delta Time delta since proof submitted\n function _timeSince(BridgeProof memory proof) internal view returns (uint256 delta) {\n unchecked {\n delta = uint96(block.timestamp) - proof.timestamp;\n }\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n if (bridgeStatuses[transactionId] != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n BridgeProof memory proof = bridgeProofs[transactionId];\n if (proof.relayer != relayer) revert SenderIncorrect();\n return _timeSince(proof) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes memory request, address to) external onlyRole(RELAYER_ROLE) {\n bytes32 transactionId = keccak256(request);\n BridgeTransaction memory transaction = getBridgeTransaction(request);\n\n // update bridge tx status if able to claim origin collateral\n if (bridgeStatuses[transactionId] != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n\n BridgeProof memory proof = bridgeProofs[transactionId];\n if (proof.relayer != msg.sender) revert SenderIncorrect();\n if (_timeSince(proof) \u003c= DISPUTE_PERIOD) revert DisputePeriodNotPassed();\n\n bridgeStatuses[transactionId] = BridgeStatus.RELAYER_CLAIMED;\n\n // update protocol fees if origin fee amount exists\n if (transaction.originFeeAmount \u003e 0) protocolFees[transaction.originToken] += transaction.originFeeAmount;\n\n // transfer origin collateral less fee to specified address\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositClaimed(transactionId, msg.sender, to, token, amount);\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n if (bridgeStatuses[transactionId] != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(bridgeProofs[transactionId]) \u003e DISPUTE_PERIOD) revert DisputePeriodPassed();\n\n // @dev relayer gets slashed effectively if dest relay has gone thru\n bridgeStatuses[transactionId] = BridgeStatus.REQUESTED;\n delete bridgeProofs[transactionId];\n\n emit BridgeProofDisputed(transactionId, msg.sender);\n }\n\n /// @inheritdoc IFastBridge\n function refund(bytes memory request) external {\n bytes32 transactionId = keccak256(request);\n BridgeTransaction memory transaction = getBridgeTransaction(request);\n\n if (hasRole(REFUNDER_ROLE, msg.sender)) {\n // Refunder can refund if deadline has passed\n if (block.timestamp \u003c= transaction.deadline) revert DeadlineNotExceeded();\n } else {\n // Permissionless refund is allowed after REFUND_DELAY\n if (block.timestamp \u003c= transaction.deadline + REFUND_DELAY) revert DeadlineNotExceeded();\n }\n\n // set status to refunded if still in requested state\n if (bridgeStatuses[transactionId] != BridgeStatus.REQUESTED) revert StatusIncorrect();\n bridgeStatuses[transactionId] = BridgeStatus.REFUNDED;\n\n // transfer origin collateral back to original sender\n address to = transaction.originSender;\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount + transaction.originFeeAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n }\n}\n\n// test/FastBridgeMock.sol\n\ncontract FastBridgeMock is IFastBridge, Admin {\n // @dev the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @dev to prevent replays\n uint256 public nonce;\n\n function getBridgeTransaction(bytes memory request) public pure returns (BridgeTransaction memory) {\n return abi.decode(request, (BridgeTransaction));\n }\n\n // used for testing in go.\n // see: https://ethereum.stackexchange.com/questions/21155/how-to-expose-enum-in-solidity-contract\n // make sure to update fastbridge/status.go if this changes\n // or underliyng enum changes.\n //\n // TODO: a foundry test should be added to ensure this is always in sync.\n function getEnumKeyByValue(FastBridge.BridgeStatus keyValue) public pure returns (string memory) {\n if (FastBridge.BridgeStatus.NULL == keyValue) return \"NULL\";\n if (FastBridge.BridgeStatus.REQUESTED == keyValue) return \"REQUESTED\";\n if (FastBridge.BridgeStatus.RELAYER_PROVED == keyValue) return \"RELAYER_PROVED\";\n if (FastBridge.BridgeStatus.RELAYER_CLAIMED == keyValue) return \"RELAYER_CLAIMED\";\n if (FastBridge.BridgeStatus.REFUNDED == keyValue) return \"REFUNDED\";\n return \"\";\n }\n\n function mockBridgeRequest(bytes32 transactionId, address sender, BridgeParams memory params) external {\n uint256 originFeeAmount = (params.originAmount * protocolFeeRate) / FEE_BPS;\n params.originAmount -= originFeeAmount;\n\n bytes memory request = abi.encode(\n BridgeTransaction({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: params.originAmount, // includes relayer fee\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n sendChainGas: params.sendChainGas,\n deadline: params.deadline,\n nonce: nonce++ // increment nonce on every bridge\n })\n );\n\n emit BridgeRequested(\n transactionId,\n params.sender,\n request,\n params.dstChainId,\n params.originToken,\n params.destToken,\n params.originAmount,\n params.destAmount,\n params.sendChainGas\n );\n }\n\n function mockBridgeRequestRaw(bytes32 transactionId, address sender, bytes memory request) external {\n BridgeTransaction memory transaction = getBridgeTransaction(request);\n emit BridgeRequested(\n transactionId,\n transaction.originSender,\n request,\n transaction.destChainId,\n transaction.originToken,\n transaction.destToken,\n transaction.originAmount,\n transaction.destAmount,\n transaction.sendChainGas\n );\n }\n\n function mockBridgeRelayer(\n bytes32 transactionId,\n address relayer,\n address to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n )\n external\n {\n emit BridgeRelayed(\n transactionId, relayer, to, originChainId, originToken, destToken, originAmount, destAmount, chainGasAmount\n );\n }\n\n function bridge(BridgeParams memory params) external payable {\n revert(\"not implemented\");\n }\n\n function relay(bytes memory request) external payable {\n revert(\"not implemented\");\n }\n\n function prove(bytes memory request, bytes32 destTxHash) external {\n revert(\"not implemented\");\n }\n\n function canClaim(bytes32 transactionid, address relayer) external view returns (bool) {\n revert(\"not implemented\");\n }\n\n function claim(bytes memory request, address to) external {\n revert(\"not implemented\");\n }\n\n function dispute(bytes32 transactionId) external {\n revert(\"not implemented\");\n }\n\n function refund(bytes memory request) external {\n revert(\"not implemented\");\n }\n}\n","language":"Solidity","languageVersion":"0.8.20","compilerVersion":"0.8.20","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"24854:11640:0:-:0;;;;;;;;;;;;;;;-1:-1:-1;;;24854:11640:0;;;;;;;;;;;;;;;;;","srcMapRuntime":"24854:11640:0:-:0;;;;;;;;","abiDefinition":[],"userDoc":{"kind":"user","methods":{},"version":1},"developerDoc":{"details":"Library for managing https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive types. Sets have the following properties: - Elements are added, removed, and checked for existence in constant time (O(1)). - Elements are enumerated in O(n). No guarantees are made on the ordering. ```solidity contract Example { // Add the library methods using EnumerableSet for EnumerableSet.AddressSet; // Declare a set state variable EnumerableSet.AddressSet private mySet; } ``` As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`) and `uint256` (`UintSet`) are supported. [WARNING] ==== Trying to delete such a structure from storage will likely result in data corruption, rendering the structure unusable. See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info. In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an array of EnumerableSet. ====","kind":"dev","methods":{},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.20+commit.a1b79de6\"},\"language\":\"Solidity\",\"output\":{\"abi\":[],\"devdoc\":{\"details\":\"Library for managing https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive types. Sets have the following properties: - Elements are added, removed, and checked for existence in constant time (O(1)). - Elements are enumerated in O(n). No guarantees are made on the ordering. ```solidity contract Example { // Add the library methods using EnumerableSet for EnumerableSet.AddressSet; // Declare a set state variable EnumerableSet.AddressSet private mySet; } ``` As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`) and `uint256` (`UintSet`) are supported. [WARNING] ==== Trying to delete such a structure from storage will likely result in data corruption, rendering the structure unusable. See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info. In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an array of EnumerableSet. ====\",\"kind\":\"dev\",\"methods\":{},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeMock.sol\":\"EnumerableSet\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeMock.sol\":{\"keccak256\":\"0x620e81214ecd324ae8b971219291f176c454ce76fb1c01d656428096da8f1366\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://18e556772c12e13aa2d52a50cc7c48e676c8d5af22b90adaf7befb39cdd08e64\",\"dweb:/ipfs/QmPrQc98TxHCFMeuFNADyjr6Nqo52rHhHy1LBcsVdMRXjL\"]}},\"version\":1}"},"hashes":{}},"solidity/FastBridgeMock.sol:FastBridge":{"code":"0x60a06040523480156200001157600080fd5b5060405162002d7a38038062002d7a833981016040819052620000349162000194565b80620000426000826200004f565b50504360805250620001bf565b6000806200005e84846200008c565b90508015620000835760008481526001602052604090206200008190846200013a565b505b90505b92915050565b6000828152602081815260408083206001600160a01b038516845290915281205460ff1662000131576000838152602081815260408083206001600160a01b03861684529091529020805460ff19166001179055620000e83390565b6001600160a01b0316826001600160a01b0316847f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a450600162000086565b50600062000086565b600062000083836001600160a01b0384166000818152600183016020526040812054620001315750815460018181018455600084815260208082209093018490558454848252828601909352604090209190915562000086565b600060208284031215620001a757600080fd5b81516001600160a01b03811681146200008357600080fd5b608051612b9f620001db60003960006106510152612b9f6000f3fe60806040526004361061026a5760003560e01c80639010d07c11610153578063add98c70116100cb578063ca15c8731161007f578063d547741f11610064578063d547741f146107a1578063dcf844a7146107c1578063e00a83e0146107ee57600080fd5b8063ca15c8731461074d578063ccc574901461076d57600080fd5b8063b13aa2d6116100b0578063b13aa2d6146106f6578063b250fe6b14610716578063bf333f2c1461073657600080fd5b8063add98c70146106c0578063affed0e0146106e057600080fd5b8063a217fddf11610122578063a5bbe22b11610107578063a5bbe22b1461047f578063aa9641ab14610673578063ac11fb1a1461069357600080fd5b8063a217fddf1461062a578063a3ec191a1461063f57600080fd5b80639010d07c146104f857806391ad50391461053057806391d14854146105b2578063926d7d7f146105f657600080fd5b806341fcb612116101e65780635eb7d946116101b55780638379a24f1161019a5780638379a24f14610495578063886d36ff146104c55780638f0d6f17146104e557600080fd5b80635eb7d9461461045f578063820688d51461047f57600080fd5b806341fcb612146103e2578063458516941461040257806358f85880146104155780635960ccf21461042b57600080fd5b80630f5f6ed71161023d578063248a9ca311610222578063248a9ca3146103725780632f2ff15d146103a257806336568abe146103c257600080fd5b80630f5f6ed714610345578063190da5951461035b57600080fd5b806301ffc9a71461026f57806303ed0ee5146102a4578063051287bc146102e657806306f333f214610323575b600080fd5b34801561027b57600080fd5b5061028f61028a3660046122fc565b610804565b60405190151581526020015b60405180910390f35b3480156102b057600080fd5b506102d87f043c983c49d46f0e102151eaf8085d4a2e6571d5df2d47b013f39bddfd4a639d81565b60405190815260200161029b565b3480156102f257600080fd5b5061031661030136600461233e565b60056020526000908152604090205460ff1681565b60405161029b9190612386565b34801561032f57600080fd5b5061034361033e3660046123ec565b610860565b005b34801561035157600080fd5b506102d861271081565b34801561036757600080fd5b506102d862093a8081565b34801561037e57600080fd5b506102d861038d36600461233e565b60009081526020819052604090206001015490565b3480156103ae57600080fd5b506103436103bd366004612425565b610927565b3480156103ce57600080fd5b506103436103dd366004612425565b610952565b3480156103ee57600080fd5b506103436103fd366004612572565b61099e565b6103436104103660046125ef565b610bd7565b34801561042157600080fd5b506102d860025481565b34801561043757600080fd5b506102d87fdb9556138406326f00296e13ea2ad7db24ba82381212d816b1a40c23b466b32781565b34801561046b57600080fd5b5061034361047a366004612692565b610ee5565b34801561048b57600080fd5b506102d861070881565b3480156104a157600080fd5b5061028f6104b036600461233e565b60076020526000908152604090205460ff1681565b3480156104d157600080fd5b506103436104e03660046126cf565b6110bd565b6103436104f3366004612692565b6111f0565b34801561050457600080fd5b50610518610513366004612714565b611437565b6040516001600160a01b03909116815260200161029b565b34801561053c57600080fd5b5061058661054b36600461233e565b6006602052600090815260409020546bffffffffffffffffffffffff8116906c0100000000000000000000000090046001600160a01b031682565b604080516bffffffffffffffffffffffff90931683526001600160a01b0390911660208301520161029b565b3480156105be57600080fd5b5061028f6105cd366004612425565b6000918252602082815260408084206001600160a01b0393909316845291905290205460ff1690565b34801561060257600080fd5b506102d87fe2b7fb3b832174769106daebcfd6d1970523240dda11281102db9363b83b0dc481565b34801561063657600080fd5b506102d8600081565b34801561064b57600080fd5b506102d87f000000000000000000000000000000000000000000000000000000000000000081565b34801561067f57600080fd5b5061028f61068e366004612425565b611456565b34801561069f57600080fd5b506106b36106ae366004612692565b611559565b60405161029b9190612736565b3480156106cc57600080fd5b506103436106db36600461233e565b6115cc565b3480156106ec57600080fd5b506102d860085481565b34801561070257600080fd5b5061034361071136600461233e565b611735565b34801561072257600080fd5b5061034361073136600461233e565b611817565b34801561074257600080fd5b506102d8620f424081565b34801561075957600080fd5b506102d861076836600461233e565b61187f565b34801561077957600080fd5b506102d87f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f5581565b3480156107ad57600080fd5b506103436107bc366004612425565b611896565b3480156107cd57600080fd5b506102d86107dc36600461281c565b60036020526000908152604090205481565b3480156107fa57600080fd5b506102d860045481565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f5a05180f00000000000000000000000000000000000000000000000000000000148061085a575061085a826118bb565b92915050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f5561088a81611952565b6001600160a01b038316600090815260036020526040812054908190036108b15750505050565b6001600160a01b0384166000818152600360205260408120556108d590848361195f565b604080516001600160a01b038087168252851660208201529081018290527f244e51bc38c1452fa8aaf487bcb4bca36c2baa3a5fbdb776b1eabd8dc6d277cd9060600160405180910390a1505b505050565b60008281526020819052604090206001015461094281611952565b61094c8383611a82565b50505050565b6001600160a01b0381163314610994576040517f6697b23200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6109228282611ab7565b7fe2b7fb3b832174769106daebcfd6d1970523240dda11281102db9363b83b0dc46109c881611952565b8251602084012060006109da85611559565b9050600260008381526005602052604090205460ff166004811115610a0157610a01612357565b14610a38576040517f4145817200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000828152600660209081526040918290208251808401909352546bffffffffffffffffffffffff811683526c0100000000000000000000000090046001600160a01b03169082018190523314610abb576040517f4af43a9000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80516107089042036bffffffffffffffffffffffff1611610b08576040517f1992d0bd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000838152600560205260409020805460ff1916600317905561010082015115610b645761010082015160808301516001600160a01b031660009081526003602052604081208054909190610b5e908490612868565b90915550505b608082015160c0830151610b826001600160a01b038316888361195f565b604080516001600160a01b03848116825260208201849052891691339188917f582211c35a2139ac3bbaac74663c6a1f56c6cbb658b41fe11fd45a82074ac67891015b60405180910390a45050505050505050565b46816000015163ffffffff1603610c1a576040517f7029fdf900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60a08101511580610c2d575060c0810151155b15610c64576040517fe38820c800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60608101516001600160a01b03161580610c89575060808101516001600160a01b0316155b15610cc0576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610ccc61070842612868565b8161010001511015610d0a576040517f04b7fcc800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000610d1f3083606001518460a00151611ae4565b90506000806002541115610d4c57620f424060025483610d3f919061287b565b610d499190612892565b90505b610d5681836128cd565b915060006040518061018001604052804663ffffffff168152602001856000015163ffffffff16815260200185602001516001600160a01b0316815260200185604001516001600160a01b0316815260200185606001516001600160a01b0316815260200185608001516001600160a01b031681526020018481526020018560c0015181526020018381526020018560e0015115158152602001856101000151815260200160086000815480929190610e0e906128e0565b909155509052604051610e249190602001612736565b604080518083037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0018152828252805160208083019190912060008181526005835293909320805460ff191660011790558701518751606089015160808a015160c08b015160e08c015195985095966001600160a01b039094169587957f120ea0364f36cdac7983bcfdd55270ca09d7f9b314a2ebc425a3b01ab1d6403a95610ed6958b959094909390928e9261293c565b60405180910390a35050505050565b805160208201206000610ef783611559565b3360009081527fd2043bf65931af3dbecf60d0db8f40e4160406d7beb00522f4200cf4944a1eb8602052604090205490915060ff1615610f74578061014001514211610f6f576040517fe15ff9ea00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610fc0565b62093a80816101400151610f889190612868565b4211610fc0576040517fe15ff9ea00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600160008381526005602052604090205460ff166004811115610fe557610fe5612357565b1461101c576040517f4145817200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600082815260056020526040808220805460ff19166004179055820151608083015161010084015160c0850151929391926110579190612868565b905061106d6001600160a01b038316848361195f565b604080516001600160a01b0384811682526020820184905285169187917fb4c55c0c9bc613519b920e88748090150b890a875d307f21bea7d4fb2e8bc958910160405180910390a3505050505050565b7fe2b7fb3b832174769106daebcfd6d1970523240dda11281102db9363b83b0dc46110e781611952565b82516020840120600160008281526005602052604090205460ff16600481111561111357611113612357565b1461114a576040517f4145817200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008181526005602090815260408083208054600260ff19909116179055805180820182526bffffffffffffffffffffffff4281168252338285018181528787526006865295849020925195516001600160a01b03166c0100000000000000000000000002959091169490941790555185815283917f4ac8af8a2cd87193d64dfc7a3b8d9923b714ec528b18725d080aa1299be0c5e4910160405180910390a350505050565b7fe2b7fb3b832174769106daebcfd6d1970523240dda11281102db9363b83b0dc461121a81611952565b81516020830120600061122c84611559565b90504663ffffffff16816020015163ffffffff1614611277576040517f7029fdf900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8061014001514211156112b6576040517f559895a300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008281526007602052604090205460ff16156112ff576040517fbef7bb7d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000828152600760205260409020805460ff19166001179055606081015160a082015160e083015160045461012085015161134857506000611342848484611ae4565b506113b9565b7fffffffffffffffffffffffff11111111111111111111111111111111111111126001600160a01b0384160161138c5761134284846113878486612868565b611ae4565b611397848484611ae4565b506113b78473eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee83611ae4565b505b845160808087015160a08089015160c0808b015160e08c01516040805163ffffffff90991689526001600160a01b0396871660208a0152938616938801939093526060870152938501528301849052861691339189917ff8ae392d784b1ea5e8881bfa586d81abf07ef4f1e2fc75f7fe51c90f05199a5c9101610bc5565b600082815260016020526040812061144f9083611cb3565b9392505050565b6000600260008481526005602052604090205460ff16600481111561147d5761147d612357565b146114b4576040517f4145817200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000838152600660209081526040918290208251808401909352546bffffffffffffffffffffffff811683526001600160a01b036c01000000000000000000000000909104811691830182905284161461153a576040517f4af43a9000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80516107089042036bffffffffffffffffffffffff1611949350505050565b604080516101808101825260008082526020808301829052928201819052606082018190526080820181905260a0820181905260c0820181905260e082018190526101008201819052610120820181905261014082018190526101608201528251909161085a91840181019084016129ed565b7f043c983c49d46f0e102151eaf8085d4a2e6571d5df2d47b013f39bddfd4a639d6115f681611952565b600260008381526005602052604090205460ff16600481111561161b5761161b612357565b14611652576040517f4145817200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000828152600660209081526040918290208251808401909352546bffffffffffffffffffffffff8082168085526c010000000000000000000000009092046001600160a01b031693909201929092526107089142031611156116e1576040517f3e908aac00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000828152600560209081526040808320805460ff19166001179055600690915280822082905551339184917f0695cf1d39b3055dcd0fe02d8b47eaf0d5a13e1996de925de59d0ef9b7f7fad49190a35050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f5561175f81611952565b6127108211156117d0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f6e657746656552617465203e206d61780000000000000000000000000000000060448201526064015b60405180910390fd5b600280549083905560408051828152602081018590527f14914da2bf76024616fbe1859783fcd4dbddcb179b1f3a854949fbf920dcb95791015b60405180910390a1505050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f5561184181611952565b600480549083905560408051828152602081018590527f5cf09b12f3f56b4c564d51b25b40360af6d795198adb61ae0806a36c294323fa910161180a565b600081815260016020526040812061085a90611cbf565b6000828152602081905260409020600101546118b181611952565b61094c8383611ab7565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f7965db0b00000000000000000000000000000000000000000000000000000000148061085a57507f01ffc9a7000000000000000000000000000000000000000000000000000000007fffffffff0000000000000000000000000000000000000000000000000000000083161461085a565b61195c8133611cc9565b50565b306001600160a01b0383160361197457505050565b8060000361198157505050565b7fffffffffffffffffffffffff11111111111111111111111111111111111111126001600160a01b03841601611a6e576000826001600160a01b03168260405160006040518083038185875af1925050503d80600081146119fe576040519150601f19603f3d011682016040523d82523d6000602084013e611a03565b606091505b505090508061094c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f455448207472616e73666572206661696c65640000000000000000000000000060448201526064016117c7565b6109226001600160a01b0384168383611d39565b600080611a8f8484611dad565b9050801561144f576000848152600160205260409020611aaf9084611e57565b509392505050565b600080611ac48484611e6c565b9050801561144f576000848152600160205260409020611aaf9084611eef565b60006001600160a01b03831673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee14611c4d57611b1c836001600160a01b0316611f04565b6040517f70a082310000000000000000000000000000000000000000000000000000000081526001600160a01b0385811660048301528416906370a0823190602401602060405180830381865afa158015611b7b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b9f9190612ab9565b9050611bb66001600160a01b038416338685611faa565b6040517f70a082310000000000000000000000000000000000000000000000000000000081526001600160a01b0385811660048301528291908516906370a0823190602401602060405180830381865afa158015611c18573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c3c9190612ab9565b611c4691906128cd565b905061144f565b348214611c86576040517f81de0bf300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600160a01b0384163014611caa57611caa6001600160a01b038416858461195f565b50349392505050565b600061144f8383611fe3565b600061085a825490565b6000828152602081815260408083206001600160a01b038516845290915290205460ff16611d35576040517fe2517d3f0000000000000000000000000000000000000000000000000000000081526001600160a01b0382166004820152602481018390526044016117c7565b5050565b6040516001600160a01b0383811660248301526044820183905261092291859182169063a9059cbb906064015b604051602081830303815290604052915060e01b6020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff838183161783525050505061200d565b6000828152602081815260408083206001600160a01b038516845290915281205460ff16611e4f576000838152602081815260408083206001600160a01b03861684529091529020805460ff19166001179055611e073390565b6001600160a01b0316826001600160a01b0316847f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a450600161085a565b50600061085a565b600061144f836001600160a01b038416612089565b6000828152602081815260408083206001600160a01b038516845290915281205460ff1615611e4f576000838152602081815260408083206001600160a01b0386168085529252808320805460ff1916905551339286917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a450600161085a565b600061144f836001600160a01b0384166120d0565b7fffffffffffffffffffffffff11111111111111111111111111111111111111126001600160a01b03821601611f66576040517f7f523fe800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b806001600160a01b03163b60000361195c576040517f7f523fe800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040516001600160a01b03848116602483015283811660448301526064820183905261094c9186918216906323b872dd90608401611d66565b6000826000018281548110611ffa57611ffa612ad2565b9060005260206000200154905092915050565b60006120226001600160a01b038416836121c3565b905080516000141580156120475750808060200190518101906120459190612b01565b155b15610922576040517f5274afe70000000000000000000000000000000000000000000000000000000081526001600160a01b03841660048201526024016117c7565b6000818152600183016020526040812054611e4f5750815460018181018455600084815260208082209093018490558454848252828601909352604090209190915561085a565b600081815260018301602052604081205480156121b95760006120f46001836128cd565b8554909150600090612108906001906128cd565b905080821461216d57600086600001828154811061212857612128612ad2565b906000526020600020015490508087600001848154811061214b5761214b612ad2565b6000918252602080832090910192909255918252600188019052604090208390555b855486908061217e5761217e612b1e565b60019003818190600052602060002001600090559055856001016000868152602001908152602001600020600090556001935050505061085a565b600091505061085a565b606061144f8383600084600080856001600160a01b031684866040516121e99190612b4d565b60006040518083038185875af1925050503d8060008114612226576040519150601f19603f3d011682016040523d82523d6000602084013e61222b565b606091505b509150915061223b868383612245565b9695505050505050565b60608261225a57612255826122ba565b61144f565b815115801561227157506001600160a01b0384163b155b156122b3576040517f9996b3150000000000000000000000000000000000000000000000000000000081526001600160a01b03851660048201526024016117c7565b508061144f565b8051156122ca5780518082602001fd5b6040517f1425ea4200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006020828403121561230e57600080fd5b81357fffffffff000000000000000000000000000000000000000000000000000000008116811461144f57600080fd5b60006020828403121561235057600080fd5b5035919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b60208101600583106123c1577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b91905290565b6001600160a01b038116811461195c57600080fd5b80356123e7816123c7565b919050565b600080604083850312156123ff57600080fd5b823561240a816123c7565b9150602083013561241a816123c7565b809150509250929050565b6000806040838503121561243857600080fd5b82359150602083013561241a816123c7565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051610120810167ffffffffffffffff8111828210171561249d5761249d61244a565b60405290565b604051610180810167ffffffffffffffff8111828210171561249d5761249d61244a565b600082601f8301126124d857600080fd5b813567ffffffffffffffff808211156124f3576124f361244a565b604051601f83017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f011681019082821181831017156125395761253961244a565b8160405283815286602085880101111561255257600080fd5b836020870160208301376000602085830101528094505050505092915050565b6000806040838503121561258557600080fd5b823567ffffffffffffffff81111561259c57600080fd5b6125a8858286016124c7565b925050602083013561241a816123c7565b63ffffffff8116811461195c57600080fd5b80356123e7816125b9565b801515811461195c57600080fd5b80356123e7816125d6565b6000610120828403121561260257600080fd5b61260a612479565b612613836125cb565b8152612621602084016123dc565b6020820152612632604084016123dc565b6040820152612643606084016123dc565b6060820152612654608084016123dc565b608082015260a083013560a082015260c083013560c082015261267960e084016125e4565b60e0820152610100928301359281019290925250919050565b6000602082840312156126a457600080fd5b813567ffffffffffffffff8111156126bb57600080fd5b6126c7848285016124c7565b949350505050565b600080604083850312156126e257600080fd5b823567ffffffffffffffff8111156126f957600080fd5b612705858286016124c7565b95602094909401359450505050565b6000806040838503121561272757600080fd5b50508035926020909101359150565b815163ffffffff1681526101808101602083015161275c602084018263ffffffff169052565b50604083015161277760408401826001600160a01b03169052565b50606083015161279260608401826001600160a01b03169052565b5060808301516127ad60808401826001600160a01b03169052565b5060a08301516127c860a08401826001600160a01b03169052565b5060c083015160c083015260e083015160e0830152610100808401518184015250610120808401516127fd8285018215159052565b5050610140838101519083015261016092830151929091019190915290565b60006020828403121561282e57600080fd5b813561144f816123c7565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b8082018082111561085a5761085a612839565b808202811582820484141761085a5761085a612839565b6000826128c8577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b8181038181111561085a5761085a612839565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820361291157612911612839565b5060010190565b60005b8381101561293357818101518382015260200161291b565b50506000910152565b60e08152600088518060e084015261010061295d8282860160208e01612918565b63ffffffff9990991660208401526001600160a01b039788166040840152959096166060820152608081019390935260a0830191909152151560c0820152601f9091017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0160190910192915050565b80516123e7816125b9565b80516123e7816123c7565b80516123e7816125d6565b60006101808284031215612a0057600080fd5b612a086124a3565b612a11836129cc565b8152612a1f602084016129cc565b6020820152612a30604084016129d7565b6040820152612a41606084016129d7565b6060820152612a52608084016129d7565b6080820152612a6360a084016129d7565b60a082015260c083015160c082015260e083015160e0820152610100808401518183015250610120612a968185016129e2565b908201526101408381015190820152610160928301519281019290925250919050565b600060208284031215612acb57600080fd5b5051919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b600060208284031215612b1357600080fd5b815161144f816125d6565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fd5b60008251612b5f818460208701612918565b919091019291505056fea26469706673582212202ed7e54598f559f515fc7a3d92c2ad3ddbadbeb6d23e4975b013050318c9925564736f6c63430008140033","runtime-code":"0x60806040526004361061026a5760003560e01c80639010d07c11610153578063add98c70116100cb578063ca15c8731161007f578063d547741f11610064578063d547741f146107a1578063dcf844a7146107c1578063e00a83e0146107ee57600080fd5b8063ca15c8731461074d578063ccc574901461076d57600080fd5b8063b13aa2d6116100b0578063b13aa2d6146106f6578063b250fe6b14610716578063bf333f2c1461073657600080fd5b8063add98c70146106c0578063affed0e0146106e057600080fd5b8063a217fddf11610122578063a5bbe22b11610107578063a5bbe22b1461047f578063aa9641ab14610673578063ac11fb1a1461069357600080fd5b8063a217fddf1461062a578063a3ec191a1461063f57600080fd5b80639010d07c146104f857806391ad50391461053057806391d14854146105b2578063926d7d7f146105f657600080fd5b806341fcb612116101e65780635eb7d946116101b55780638379a24f1161019a5780638379a24f14610495578063886d36ff146104c55780638f0d6f17146104e557600080fd5b80635eb7d9461461045f578063820688d51461047f57600080fd5b806341fcb612146103e2578063458516941461040257806358f85880146104155780635960ccf21461042b57600080fd5b80630f5f6ed71161023d578063248a9ca311610222578063248a9ca3146103725780632f2ff15d146103a257806336568abe146103c257600080fd5b80630f5f6ed714610345578063190da5951461035b57600080fd5b806301ffc9a71461026f57806303ed0ee5146102a4578063051287bc146102e657806306f333f214610323575b600080fd5b34801561027b57600080fd5b5061028f61028a3660046122fc565b610804565b60405190151581526020015b60405180910390f35b3480156102b057600080fd5b506102d87f043c983c49d46f0e102151eaf8085d4a2e6571d5df2d47b013f39bddfd4a639d81565b60405190815260200161029b565b3480156102f257600080fd5b5061031661030136600461233e565b60056020526000908152604090205460ff1681565b60405161029b9190612386565b34801561032f57600080fd5b5061034361033e3660046123ec565b610860565b005b34801561035157600080fd5b506102d861271081565b34801561036757600080fd5b506102d862093a8081565b34801561037e57600080fd5b506102d861038d36600461233e565b60009081526020819052604090206001015490565b3480156103ae57600080fd5b506103436103bd366004612425565b610927565b3480156103ce57600080fd5b506103436103dd366004612425565b610952565b3480156103ee57600080fd5b506103436103fd366004612572565b61099e565b6103436104103660046125ef565b610bd7565b34801561042157600080fd5b506102d860025481565b34801561043757600080fd5b506102d87fdb9556138406326f00296e13ea2ad7db24ba82381212d816b1a40c23b466b32781565b34801561046b57600080fd5b5061034361047a366004612692565b610ee5565b34801561048b57600080fd5b506102d861070881565b3480156104a157600080fd5b5061028f6104b036600461233e565b60076020526000908152604090205460ff1681565b3480156104d157600080fd5b506103436104e03660046126cf565b6110bd565b6103436104f3366004612692565b6111f0565b34801561050457600080fd5b50610518610513366004612714565b611437565b6040516001600160a01b03909116815260200161029b565b34801561053c57600080fd5b5061058661054b36600461233e565b6006602052600090815260409020546bffffffffffffffffffffffff8116906c0100000000000000000000000090046001600160a01b031682565b604080516bffffffffffffffffffffffff90931683526001600160a01b0390911660208301520161029b565b3480156105be57600080fd5b5061028f6105cd366004612425565b6000918252602082815260408084206001600160a01b0393909316845291905290205460ff1690565b34801561060257600080fd5b506102d87fe2b7fb3b832174769106daebcfd6d1970523240dda11281102db9363b83b0dc481565b34801561063657600080fd5b506102d8600081565b34801561064b57600080fd5b506102d87f000000000000000000000000000000000000000000000000000000000000000081565b34801561067f57600080fd5b5061028f61068e366004612425565b611456565b34801561069f57600080fd5b506106b36106ae366004612692565b611559565b60405161029b9190612736565b3480156106cc57600080fd5b506103436106db36600461233e565b6115cc565b3480156106ec57600080fd5b506102d860085481565b34801561070257600080fd5b5061034361071136600461233e565b611735565b34801561072257600080fd5b5061034361073136600461233e565b611817565b34801561074257600080fd5b506102d8620f424081565b34801561075957600080fd5b506102d861076836600461233e565b61187f565b34801561077957600080fd5b506102d87f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f5581565b3480156107ad57600080fd5b506103436107bc366004612425565b611896565b3480156107cd57600080fd5b506102d86107dc36600461281c565b60036020526000908152604090205481565b3480156107fa57600080fd5b506102d860045481565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f5a05180f00000000000000000000000000000000000000000000000000000000148061085a575061085a826118bb565b92915050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f5561088a81611952565b6001600160a01b038316600090815260036020526040812054908190036108b15750505050565b6001600160a01b0384166000818152600360205260408120556108d590848361195f565b604080516001600160a01b038087168252851660208201529081018290527f244e51bc38c1452fa8aaf487bcb4bca36c2baa3a5fbdb776b1eabd8dc6d277cd9060600160405180910390a1505b505050565b60008281526020819052604090206001015461094281611952565b61094c8383611a82565b50505050565b6001600160a01b0381163314610994576040517f6697b23200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6109228282611ab7565b7fe2b7fb3b832174769106daebcfd6d1970523240dda11281102db9363b83b0dc46109c881611952565b8251602084012060006109da85611559565b9050600260008381526005602052604090205460ff166004811115610a0157610a01612357565b14610a38576040517f4145817200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000828152600660209081526040918290208251808401909352546bffffffffffffffffffffffff811683526c0100000000000000000000000090046001600160a01b03169082018190523314610abb576040517f4af43a9000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80516107089042036bffffffffffffffffffffffff1611610b08576040517f1992d0bd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000838152600560205260409020805460ff1916600317905561010082015115610b645761010082015160808301516001600160a01b031660009081526003602052604081208054909190610b5e908490612868565b90915550505b608082015160c0830151610b826001600160a01b038316888361195f565b604080516001600160a01b03848116825260208201849052891691339188917f582211c35a2139ac3bbaac74663c6a1f56c6cbb658b41fe11fd45a82074ac67891015b60405180910390a45050505050505050565b46816000015163ffffffff1603610c1a576040517f7029fdf900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60a08101511580610c2d575060c0810151155b15610c64576040517fe38820c800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60608101516001600160a01b03161580610c89575060808101516001600160a01b0316155b15610cc0576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610ccc61070842612868565b8161010001511015610d0a576040517f04b7fcc800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000610d1f3083606001518460a00151611ae4565b90506000806002541115610d4c57620f424060025483610d3f919061287b565b610d499190612892565b90505b610d5681836128cd565b915060006040518061018001604052804663ffffffff168152602001856000015163ffffffff16815260200185602001516001600160a01b0316815260200185604001516001600160a01b0316815260200185606001516001600160a01b0316815260200185608001516001600160a01b031681526020018481526020018560c0015181526020018381526020018560e0015115158152602001856101000151815260200160086000815480929190610e0e906128e0565b909155509052604051610e249190602001612736565b604080518083037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0018152828252805160208083019190912060008181526005835293909320805460ff191660011790558701518751606089015160808a015160c08b015160e08c015195985095966001600160a01b039094169587957f120ea0364f36cdac7983bcfdd55270ca09d7f9b314a2ebc425a3b01ab1d6403a95610ed6958b959094909390928e9261293c565b60405180910390a35050505050565b805160208201206000610ef783611559565b3360009081527fd2043bf65931af3dbecf60d0db8f40e4160406d7beb00522f4200cf4944a1eb8602052604090205490915060ff1615610f74578061014001514211610f6f576040517fe15ff9ea00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610fc0565b62093a80816101400151610f889190612868565b4211610fc0576040517fe15ff9ea00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600160008381526005602052604090205460ff166004811115610fe557610fe5612357565b1461101c576040517f4145817200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600082815260056020526040808220805460ff19166004179055820151608083015161010084015160c0850151929391926110579190612868565b905061106d6001600160a01b038316848361195f565b604080516001600160a01b0384811682526020820184905285169187917fb4c55c0c9bc613519b920e88748090150b890a875d307f21bea7d4fb2e8bc958910160405180910390a3505050505050565b7fe2b7fb3b832174769106daebcfd6d1970523240dda11281102db9363b83b0dc46110e781611952565b82516020840120600160008281526005602052604090205460ff16600481111561111357611113612357565b1461114a576040517f4145817200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008181526005602090815260408083208054600260ff19909116179055805180820182526bffffffffffffffffffffffff4281168252338285018181528787526006865295849020925195516001600160a01b03166c0100000000000000000000000002959091169490941790555185815283917f4ac8af8a2cd87193d64dfc7a3b8d9923b714ec528b18725d080aa1299be0c5e4910160405180910390a350505050565b7fe2b7fb3b832174769106daebcfd6d1970523240dda11281102db9363b83b0dc461121a81611952565b81516020830120600061122c84611559565b90504663ffffffff16816020015163ffffffff1614611277576040517f7029fdf900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8061014001514211156112b6576040517f559895a300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008281526007602052604090205460ff16156112ff576040517fbef7bb7d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000828152600760205260409020805460ff19166001179055606081015160a082015160e083015160045461012085015161134857506000611342848484611ae4565b506113b9565b7fffffffffffffffffffffffff11111111111111111111111111111111111111126001600160a01b0384160161138c5761134284846113878486612868565b611ae4565b611397848484611ae4565b506113b78473eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee83611ae4565b505b845160808087015160a08089015160c0808b015160e08c01516040805163ffffffff90991689526001600160a01b0396871660208a0152938616938801939093526060870152938501528301849052861691339189917ff8ae392d784b1ea5e8881bfa586d81abf07ef4f1e2fc75f7fe51c90f05199a5c9101610bc5565b600082815260016020526040812061144f9083611cb3565b9392505050565b6000600260008481526005602052604090205460ff16600481111561147d5761147d612357565b146114b4576040517f4145817200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000838152600660209081526040918290208251808401909352546bffffffffffffffffffffffff811683526001600160a01b036c01000000000000000000000000909104811691830182905284161461153a576040517f4af43a9000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80516107089042036bffffffffffffffffffffffff1611949350505050565b604080516101808101825260008082526020808301829052928201819052606082018190526080820181905260a0820181905260c0820181905260e082018190526101008201819052610120820181905261014082018190526101608201528251909161085a91840181019084016129ed565b7f043c983c49d46f0e102151eaf8085d4a2e6571d5df2d47b013f39bddfd4a639d6115f681611952565b600260008381526005602052604090205460ff16600481111561161b5761161b612357565b14611652576040517f4145817200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000828152600660209081526040918290208251808401909352546bffffffffffffffffffffffff8082168085526c010000000000000000000000009092046001600160a01b031693909201929092526107089142031611156116e1576040517f3e908aac00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000828152600560209081526040808320805460ff19166001179055600690915280822082905551339184917f0695cf1d39b3055dcd0fe02d8b47eaf0d5a13e1996de925de59d0ef9b7f7fad49190a35050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f5561175f81611952565b6127108211156117d0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f6e657746656552617465203e206d61780000000000000000000000000000000060448201526064015b60405180910390fd5b600280549083905560408051828152602081018590527f14914da2bf76024616fbe1859783fcd4dbddcb179b1f3a854949fbf920dcb95791015b60405180910390a1505050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f5561184181611952565b600480549083905560408051828152602081018590527f5cf09b12f3f56b4c564d51b25b40360af6d795198adb61ae0806a36c294323fa910161180a565b600081815260016020526040812061085a90611cbf565b6000828152602081905260409020600101546118b181611952565b61094c8383611ab7565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f7965db0b00000000000000000000000000000000000000000000000000000000148061085a57507f01ffc9a7000000000000000000000000000000000000000000000000000000007fffffffff0000000000000000000000000000000000000000000000000000000083161461085a565b61195c8133611cc9565b50565b306001600160a01b0383160361197457505050565b8060000361198157505050565b7fffffffffffffffffffffffff11111111111111111111111111111111111111126001600160a01b03841601611a6e576000826001600160a01b03168260405160006040518083038185875af1925050503d80600081146119fe576040519150601f19603f3d011682016040523d82523d6000602084013e611a03565b606091505b505090508061094c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f455448207472616e73666572206661696c65640000000000000000000000000060448201526064016117c7565b6109226001600160a01b0384168383611d39565b600080611a8f8484611dad565b9050801561144f576000848152600160205260409020611aaf9084611e57565b509392505050565b600080611ac48484611e6c565b9050801561144f576000848152600160205260409020611aaf9084611eef565b60006001600160a01b03831673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee14611c4d57611b1c836001600160a01b0316611f04565b6040517f70a082310000000000000000000000000000000000000000000000000000000081526001600160a01b0385811660048301528416906370a0823190602401602060405180830381865afa158015611b7b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b9f9190612ab9565b9050611bb66001600160a01b038416338685611faa565b6040517f70a082310000000000000000000000000000000000000000000000000000000081526001600160a01b0385811660048301528291908516906370a0823190602401602060405180830381865afa158015611c18573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c3c9190612ab9565b611c4691906128cd565b905061144f565b348214611c86576040517f81de0bf300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600160a01b0384163014611caa57611caa6001600160a01b038416858461195f565b50349392505050565b600061144f8383611fe3565b600061085a825490565b6000828152602081815260408083206001600160a01b038516845290915290205460ff16611d35576040517fe2517d3f0000000000000000000000000000000000000000000000000000000081526001600160a01b0382166004820152602481018390526044016117c7565b5050565b6040516001600160a01b0383811660248301526044820183905261092291859182169063a9059cbb906064015b604051602081830303815290604052915060e01b6020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff838183161783525050505061200d565b6000828152602081815260408083206001600160a01b038516845290915281205460ff16611e4f576000838152602081815260408083206001600160a01b03861684529091529020805460ff19166001179055611e073390565b6001600160a01b0316826001600160a01b0316847f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a450600161085a565b50600061085a565b600061144f836001600160a01b038416612089565b6000828152602081815260408083206001600160a01b038516845290915281205460ff1615611e4f576000838152602081815260408083206001600160a01b0386168085529252808320805460ff1916905551339286917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a450600161085a565b600061144f836001600160a01b0384166120d0565b7fffffffffffffffffffffffff11111111111111111111111111111111111111126001600160a01b03821601611f66576040517f7f523fe800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b806001600160a01b03163b60000361195c576040517f7f523fe800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040516001600160a01b03848116602483015283811660448301526064820183905261094c9186918216906323b872dd90608401611d66565b6000826000018281548110611ffa57611ffa612ad2565b9060005260206000200154905092915050565b60006120226001600160a01b038416836121c3565b905080516000141580156120475750808060200190518101906120459190612b01565b155b15610922576040517f5274afe70000000000000000000000000000000000000000000000000000000081526001600160a01b03841660048201526024016117c7565b6000818152600183016020526040812054611e4f5750815460018181018455600084815260208082209093018490558454848252828601909352604090209190915561085a565b600081815260018301602052604081205480156121b95760006120f46001836128cd565b8554909150600090612108906001906128cd565b905080821461216d57600086600001828154811061212857612128612ad2565b906000526020600020015490508087600001848154811061214b5761214b612ad2565b6000918252602080832090910192909255918252600188019052604090208390555b855486908061217e5761217e612b1e565b60019003818190600052602060002001600090559055856001016000868152602001908152602001600020600090556001935050505061085a565b600091505061085a565b606061144f8383600084600080856001600160a01b031684866040516121e99190612b4d565b60006040518083038185875af1925050503d8060008114612226576040519150601f19603f3d011682016040523d82523d6000602084013e61222b565b606091505b509150915061223b868383612245565b9695505050505050565b60608261225a57612255826122ba565b61144f565b815115801561227157506001600160a01b0384163b155b156122b3576040517f9996b3150000000000000000000000000000000000000000000000000000000081526001600160a01b03851660048201526024016117c7565b508061144f565b8051156122ca5780518082602001fd5b6040517f1425ea4200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006020828403121561230e57600080fd5b81357fffffffff000000000000000000000000000000000000000000000000000000008116811461144f57600080fd5b60006020828403121561235057600080fd5b5035919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b60208101600583106123c1577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b91905290565b6001600160a01b038116811461195c57600080fd5b80356123e7816123c7565b919050565b600080604083850312156123ff57600080fd5b823561240a816123c7565b9150602083013561241a816123c7565b809150509250929050565b6000806040838503121561243857600080fd5b82359150602083013561241a816123c7565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051610120810167ffffffffffffffff8111828210171561249d5761249d61244a565b60405290565b604051610180810167ffffffffffffffff8111828210171561249d5761249d61244a565b600082601f8301126124d857600080fd5b813567ffffffffffffffff808211156124f3576124f361244a565b604051601f83017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f011681019082821181831017156125395761253961244a565b8160405283815286602085880101111561255257600080fd5b836020870160208301376000602085830101528094505050505092915050565b6000806040838503121561258557600080fd5b823567ffffffffffffffff81111561259c57600080fd5b6125a8858286016124c7565b925050602083013561241a816123c7565b63ffffffff8116811461195c57600080fd5b80356123e7816125b9565b801515811461195c57600080fd5b80356123e7816125d6565b6000610120828403121561260257600080fd5b61260a612479565b612613836125cb565b8152612621602084016123dc565b6020820152612632604084016123dc565b6040820152612643606084016123dc565b6060820152612654608084016123dc565b608082015260a083013560a082015260c083013560c082015261267960e084016125e4565b60e0820152610100928301359281019290925250919050565b6000602082840312156126a457600080fd5b813567ffffffffffffffff8111156126bb57600080fd5b6126c7848285016124c7565b949350505050565b600080604083850312156126e257600080fd5b823567ffffffffffffffff8111156126f957600080fd5b612705858286016124c7565b95602094909401359450505050565b6000806040838503121561272757600080fd5b50508035926020909101359150565b815163ffffffff1681526101808101602083015161275c602084018263ffffffff169052565b50604083015161277760408401826001600160a01b03169052565b50606083015161279260608401826001600160a01b03169052565b5060808301516127ad60808401826001600160a01b03169052565b5060a08301516127c860a08401826001600160a01b03169052565b5060c083015160c083015260e083015160e0830152610100808401518184015250610120808401516127fd8285018215159052565b5050610140838101519083015261016092830151929091019190915290565b60006020828403121561282e57600080fd5b813561144f816123c7565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b8082018082111561085a5761085a612839565b808202811582820484141761085a5761085a612839565b6000826128c8577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b8181038181111561085a5761085a612839565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820361291157612911612839565b5060010190565b60005b8381101561293357818101518382015260200161291b565b50506000910152565b60e08152600088518060e084015261010061295d8282860160208e01612918565b63ffffffff9990991660208401526001600160a01b039788166040840152959096166060820152608081019390935260a0830191909152151560c0820152601f9091017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0160190910192915050565b80516123e7816125b9565b80516123e7816123c7565b80516123e7816125d6565b60006101808284031215612a0057600080fd5b612a086124a3565b612a11836129cc565b8152612a1f602084016129cc565b6020820152612a30604084016129d7565b6040820152612a41606084016129d7565b6060820152612a52608084016129d7565b6080820152612a6360a084016129d7565b60a082015260c083015160c082015260e083015160e0820152610100808401518183015250610120612a968185016129e2565b908201526101408381015190820152610160928301519281019290925250919050565b600060208284031215612acb57600080fd5b5051919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b600060208284031215612b1357600080fd5b815161144f816125d6565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fd5b60008251612b5f818460208701612918565b919091019291505056fea26469706673582212202ed7e54598f559f515fc7a3d92c2ad3ddbadbeb6d23e4975b013050318c9925564736f6c63430008140033","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.20 ^0.8.20;\n\n// contracts/interfaces/IAdmin.sol\n\ninterface IAdmin {\n // ============ Events ============\n\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n event ChainGasAmountUpdated(uint256 oldChainGasAmount, uint256 newChainGasAmount);\n\n // ============ Methods ============\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n\n function setChainGasAmount(uint256 newChainGasAmount) external;\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/libs/Errors.sol\n\nerror DeadlineExceeded();\nerror DeadlineNotExceeded();\nerror DeadlineTooShort();\nerror InsufficientOutputAmount();\n\nerror MsgValueIncorrect();\nerror PoolNotFound();\nerror TokenAddressMismatch();\nerror TokenNotContract();\nerror TokenNotETH();\nerror TokensIdentical();\n\nerror ChainIncorrect();\nerror AmountIncorrect();\nerror ZeroAddress();\n\nerror DisputePeriodNotPassed();\nerror DisputePeriodPassed();\nerror SenderIncorrect();\nerror StatusIncorrect();\nerror TransactionIdIncorrect();\nerror TransactionRelayed();\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// contracts/libs/UniversalToken.sol\n\nlibrary UniversalTokenLib {\n using SafeERC20 for IERC20;\n\n address internal constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Transfers tokens to the given account. Reverts if transfer is not successful.\n /// @dev This might trigger fallback, if ETH is transferred to the contract.\n /// Make sure this can not lead to reentrancy attacks.\n function universalTransfer(address token, address to, uint256 value) internal {\n // Don't do anything, if need to send tokens to this address\n if (to == address(this)) return;\n // Don't do anything, if trying to send zero value\n if (value == 0) return;\n if (token == ETH_ADDRESS) {\n /// @dev Note: this can potentially lead to executing code in `to`.\n // solhint-disable-next-line avoid-low-level-calls\n (bool success,) = to.call{value: value}(\"\");\n require(success, \"ETH transfer failed\");\n } else {\n IERC20(token).safeTransfer(to, value);\n }\n }\n\n /// @notice Issues an infinite allowance to the spender, if the current allowance is insufficient\n /// to spend the given amount.\n function universalApproveInfinity(address token, address spender, uint256 amountToSpend) internal {\n // ETH Chad doesn't require your approval\n if (token == ETH_ADDRESS) return;\n // No-op if allowance is already sufficient\n uint256 allowance = IERC20(token).allowance(address(this), spender);\n if (allowance \u003e= amountToSpend) return;\n // Otherwise, reset approval to 0 and set to max allowance\n if (allowance \u003e 0) IERC20(token).safeDecreaseAllowance(spender, allowance);\n IERC20(token).safeIncreaseAllowance(spender, type(uint256).max);\n }\n\n /// @notice Returns the balance of the given token (or native ETH) for the given account.\n function universalBalanceOf(address token, address account) internal view returns (uint256) {\n if (token == ETH_ADDRESS) {\n return account.balance;\n } else {\n return IERC20(token).balanceOf(account);\n }\n }\n\n /// @dev Checks that token is a contract and not ETH_ADDRESS.\n function assertIsContract(address token) internal view {\n // Check that ETH_ADDRESS was not used (in case this is a predeploy on any of the chains)\n if (token == UniversalTokenLib.ETH_ADDRESS) revert TokenNotContract();\n // Check that token is not an EOA\n if (token.code.length == 0) revert TokenNotContract();\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/Admin.sol\n\ncontract Admin is IAdmin, AccessControlEnumerable {\n using UniversalTokenLib for address;\n\n bytes32 public constant RELAYER_ROLE = keccak256(\"RELAYER_ROLE\");\n bytes32 public constant REFUNDER_ROLE = keccak256(\"REFUNDER_ROLE\");\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n uint256 public constant FEE_BPS = 1e6;\n uint256 public constant FEE_RATE_MAX = 0.01e6; // max 1% on origin amount\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Chain gas amount to forward as rebate if requested\n uint256 public chainGasAmount;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n }\n\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n require(newFeeRate \u003c= FEE_RATE_MAX, \"newFeeRate \u003e max\");\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n token.universalTransfer(recipient, feeAmount);\n emit FeesSwept(token, recipient, feeAmount);\n }\n\n function setChainGasAmount(uint256 newChainGasAmount) external onlyRole(GOVERNOR_ROLE) {\n uint256 oldChainGasAmount = chainGasAmount;\n chainGasAmount = newChainGasAmount;\n emit ChainGasAmountUpdated(oldChainGasAmount, newChainGasAmount);\n }\n}\n\n// contracts/FastBridge.sol\n\ncontract FastBridge is IFastBridge, Admin {\n using SafeERC20 for IERC20;\n using UniversalTokenLib for address;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Delay for a transaction after which it could be permisionlessly refunded\n uint256 public constant REFUND_DELAY = 7 days;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeStatus) public bridgeStatuses;\n /// @notice Proof of relayed bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeProof) public bridgeProofs;\n /// @notice Whether bridge has been relayed on destination chain\n mapping(bytes32 =\u003e bool) public bridgeRelays;\n\n /// @dev to prevent replays\n uint256 public nonce;\n // @dev the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @notice Pulls a requested token from the user to the requested recipient.\n /// @dev Be careful of re-entrancy issues when msg.value \u003e 0 and recipient != address(this)\n function _pullToken(address recipient, address token, uint256 amount) internal returns (uint256 amountPulled) {\n if (token != UniversalTokenLib.ETH_ADDRESS) {\n token.assertIsContract();\n // Record token balance before transfer\n amountPulled = IERC20(token).balanceOf(recipient);\n // Token needs to be pulled only if msg.value is zero\n // This way user can specify WETH as the origin asset\n IERC20(token).safeTransferFrom(msg.sender, recipient, amount);\n // Use the difference between the recorded balance and the current balance as the amountPulled\n amountPulled = IERC20(token).balanceOf(recipient) - amountPulled;\n } else {\n // Otherwise, we need to check that ETH amount matches msg.value\n if (amount != msg.value) revert MsgValueIncorrect();\n // Transfer value to recipient if not this address\n if (recipient != address(this)) token.universalTransfer(recipient, amount);\n // We will forward msg.value in the external call later, if recipient is not this contract\n amountPulled = msg.value;\n }\n }\n\n /// @inheritdoc IFastBridge\n function getBridgeTransaction(bytes memory request) public pure returns (BridgeTransaction memory) {\n return abi.decode(request, (BridgeTransaction));\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n // check bridge params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n\n // transfer tokens to bridge contract\n // @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _pullToken(address(this), params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n\n // set status to requested\n bytes memory request = abi.encode(\n BridgeTransaction({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n sendChainGas: params.sendChainGas,\n deadline: params.deadline,\n nonce: nonce++ // increment nonce on every bridge\n })\n );\n bytes32 transactionId = keccak256(request);\n bridgeStatuses[transactionId] = BridgeStatus.REQUESTED;\n\n emit BridgeRequested(\n transactionId,\n params.sender,\n request,\n params.dstChainId,\n params.originToken,\n params.destToken,\n originAmount,\n params.destAmount,\n params.sendChainGas\n );\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes memory request) external payable onlyRole(RELAYER_ROLE) {\n bytes32 transactionId = keccak256(request);\n BridgeTransaction memory transaction = getBridgeTransaction(request);\n if (transaction.destChainId != uint32(block.chainid)) revert ChainIncorrect();\n\n // check haven't exceeded deadline for relay to happen\n if (block.timestamp \u003e transaction.deadline) revert DeadlineExceeded();\n\n // mark bridge transaction as relayed\n if (bridgeRelays[transactionId]) revert TransactionRelayed();\n bridgeRelays[transactionId] = true;\n\n // transfer tokens to recipient on destination chain and gas rebate if requested\n address to = transaction.destRecipient;\n address token = transaction.destToken;\n uint256 amount = transaction.destAmount;\n\n uint256 rebate = chainGasAmount;\n if (!transaction.sendChainGas) {\n // forward erc20\n rebate = 0;\n _pullToken(to, token, amount);\n } else if (token == UniversalTokenLib.ETH_ADDRESS) {\n // lump in gas rebate into amount in native gas token\n _pullToken(to, token, amount + rebate);\n } else {\n // forward erc20 then forward gas rebate in native gas token\n _pullToken(to, token, amount);\n _pullToken(to, UniversalTokenLib.ETH_ADDRESS, rebate);\n }\n\n emit BridgeRelayed(\n transactionId,\n msg.sender,\n to,\n transaction.originChainId,\n transaction.originToken,\n transaction.destToken,\n transaction.originAmount,\n transaction.destAmount,\n rebate\n );\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes memory request, bytes32 destTxHash) external onlyRole(RELAYER_ROLE) {\n bytes32 transactionId = keccak256(request);\n // update bridge tx status given proof provided\n if (bridgeStatuses[transactionId] != BridgeStatus.REQUESTED) revert StatusIncorrect();\n bridgeStatuses[transactionId] = BridgeStatus.RELAYER_PROVED;\n bridgeProofs[transactionId] = BridgeProof({timestamp: uint96(block.timestamp), relayer: msg.sender}); // overflow ok\n\n emit BridgeProofProvided(transactionId, msg.sender, destTxHash);\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint96(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint96).max but\n /// proof.timestamp \u003c type(uint96).max via unchecked statement\n /// @param proof The bridge proof\n /// @return delta Time delta since proof submitted\n function _timeSince(BridgeProof memory proof) internal view returns (uint256 delta) {\n unchecked {\n delta = uint96(block.timestamp) - proof.timestamp;\n }\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n if (bridgeStatuses[transactionId] != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n BridgeProof memory proof = bridgeProofs[transactionId];\n if (proof.relayer != relayer) revert SenderIncorrect();\n return _timeSince(proof) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes memory request, address to) external onlyRole(RELAYER_ROLE) {\n bytes32 transactionId = keccak256(request);\n BridgeTransaction memory transaction = getBridgeTransaction(request);\n\n // update bridge tx status if able to claim origin collateral\n if (bridgeStatuses[transactionId] != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n\n BridgeProof memory proof = bridgeProofs[transactionId];\n if (proof.relayer != msg.sender) revert SenderIncorrect();\n if (_timeSince(proof) \u003c= DISPUTE_PERIOD) revert DisputePeriodNotPassed();\n\n bridgeStatuses[transactionId] = BridgeStatus.RELAYER_CLAIMED;\n\n // update protocol fees if origin fee amount exists\n if (transaction.originFeeAmount \u003e 0) protocolFees[transaction.originToken] += transaction.originFeeAmount;\n\n // transfer origin collateral less fee to specified address\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositClaimed(transactionId, msg.sender, to, token, amount);\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n if (bridgeStatuses[transactionId] != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(bridgeProofs[transactionId]) \u003e DISPUTE_PERIOD) revert DisputePeriodPassed();\n\n // @dev relayer gets slashed effectively if dest relay has gone thru\n bridgeStatuses[transactionId] = BridgeStatus.REQUESTED;\n delete bridgeProofs[transactionId];\n\n emit BridgeProofDisputed(transactionId, msg.sender);\n }\n\n /// @inheritdoc IFastBridge\n function refund(bytes memory request) external {\n bytes32 transactionId = keccak256(request);\n BridgeTransaction memory transaction = getBridgeTransaction(request);\n\n if (hasRole(REFUNDER_ROLE, msg.sender)) {\n // Refunder can refund if deadline has passed\n if (block.timestamp \u003c= transaction.deadline) revert DeadlineNotExceeded();\n } else {\n // Permissionless refund is allowed after REFUND_DELAY\n if (block.timestamp \u003c= transaction.deadline + REFUND_DELAY) revert DeadlineNotExceeded();\n }\n\n // set status to refunded if still in requested state\n if (bridgeStatuses[transactionId] != BridgeStatus.REQUESTED) revert StatusIncorrect();\n bridgeStatuses[transactionId] = BridgeStatus.REFUNDED;\n\n // transfer origin collateral back to original sender\n address to = transaction.originSender;\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount + transaction.originFeeAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n }\n}\n\n// test/FastBridgeMock.sol\n\ncontract FastBridgeMock is IFastBridge, Admin {\n // @dev the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @dev to prevent replays\n uint256 public nonce;\n\n function getBridgeTransaction(bytes memory request) public pure returns (BridgeTransaction memory) {\n return abi.decode(request, (BridgeTransaction));\n }\n\n // used for testing in go.\n // see: https://ethereum.stackexchange.com/questions/21155/how-to-expose-enum-in-solidity-contract\n // make sure to update fastbridge/status.go if this changes\n // or underliyng enum changes.\n //\n // TODO: a foundry test should be added to ensure this is always in sync.\n function getEnumKeyByValue(FastBridge.BridgeStatus keyValue) public pure returns (string memory) {\n if (FastBridge.BridgeStatus.NULL == keyValue) return \"NULL\";\n if (FastBridge.BridgeStatus.REQUESTED == keyValue) return \"REQUESTED\";\n if (FastBridge.BridgeStatus.RELAYER_PROVED == keyValue) return \"RELAYER_PROVED\";\n if (FastBridge.BridgeStatus.RELAYER_CLAIMED == keyValue) return \"RELAYER_CLAIMED\";\n if (FastBridge.BridgeStatus.REFUNDED == keyValue) return \"REFUNDED\";\n return \"\";\n }\n\n function mockBridgeRequest(bytes32 transactionId, address sender, BridgeParams memory params) external {\n uint256 originFeeAmount = (params.originAmount * protocolFeeRate) / FEE_BPS;\n params.originAmount -= originFeeAmount;\n\n bytes memory request = abi.encode(\n BridgeTransaction({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: params.originAmount, // includes relayer fee\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n sendChainGas: params.sendChainGas,\n deadline: params.deadline,\n nonce: nonce++ // increment nonce on every bridge\n })\n );\n\n emit BridgeRequested(\n transactionId,\n params.sender,\n request,\n params.dstChainId,\n params.originToken,\n params.destToken,\n params.originAmount,\n params.destAmount,\n params.sendChainGas\n );\n }\n\n function mockBridgeRequestRaw(bytes32 transactionId, address sender, bytes memory request) external {\n BridgeTransaction memory transaction = getBridgeTransaction(request);\n emit BridgeRequested(\n transactionId,\n transaction.originSender,\n request,\n transaction.destChainId,\n transaction.originToken,\n transaction.destToken,\n transaction.originAmount,\n transaction.destAmount,\n transaction.sendChainGas\n );\n }\n\n function mockBridgeRelayer(\n bytes32 transactionId,\n address relayer,\n address to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n )\n external\n {\n emit BridgeRelayed(\n transactionId, relayer, to, originChainId, originToken, destToken, originAmount, destAmount, chainGasAmount\n );\n }\n\n function bridge(BridgeParams memory params) external payable {\n revert(\"not implemented\");\n }\n\n function relay(bytes memory request) external payable {\n revert(\"not implemented\");\n }\n\n function prove(bytes memory request, bytes32 destTxHash) external {\n revert(\"not implemented\");\n }\n\n function canClaim(bytes32 transactionid, address relayer) external view returns (bool) {\n revert(\"not implemented\");\n }\n\n function claim(bytes memory request, address to) external {\n revert(\"not implemented\");\n }\n\n function dispute(bytes32 transactionId) external {\n revert(\"not implemented\");\n }\n\n function refund(bytes memory request) external {\n revert(\"not implemented\");\n }\n}\n","language":"Solidity","languageVersion":"0.8.20","compilerVersion":"0.8.20","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"58189:11304:0:-:0;;;59364:85;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;59398:6;57180:38;46352:4;59398:6;57180:10;:38::i;:::-;-1:-1:-1;;59430:12:0::1;59416:26;::::0;-1:-1:-1;58189:11304:0;;55665:257;55751:4;;55782:31;55799:4;55805:7;55782:16;:31::i;:::-;55767:46;;55827:7;55823:69;;;55850:18;;;;:12;:18;;;;;:31;;55873:7;55850:22;:31::i;:::-;;55823:69;55908:7;-1:-1:-1;55665:257:0;;;;;:::o;50299:316::-;50376:4;47074:12;;;;;;;;;;;-1:-1:-1;;;;;47074:29:0;;;;;;;;;;;;50392:217;;50435:6;:12;;;;;;;;;;;-1:-1:-1;;;;;50435:29:0;;;;;;;;;:36;;-1:-1:-1;;50435:36:0;50467:4;50435:36;;;50517:12;22395:10;;22316:96;50517:12;-1:-1:-1;;;;;50490:40:0;50508:7;-1:-1:-1;;;;;50490:40:0;50502:4;50490:40;;;;;;;;;;-1:-1:-1;50551:4:0;50544:11;;50392:217;-1:-1:-1;50593:5:0;50586:12;;31840:150;31910:4;31933:50;31938:3;-1:-1:-1;;;;;31958:23:0;;25828:4;27884:21;;;:14;;;:21;;;;;;25844:321;;-1:-1:-1;25886:23:0;;;;;;;;:11;:23;;;;;;;;;;;;;26068:18;;26044:21;;;:14;;;:21;;;;;;:42;;;;26100:11;;14:290:1;84:6;137:2;125:9;116:7;112:23;108:32;105:52;;;153:1;150;143:12;105:52;179:16;;-1:-1:-1;;;;;224:31:1;;214:42;;204:70;;270:1;267;260:12;14:290;58189:11304:0;;;;;;;;;;;;","srcMapRuntime":"58189:11304:0:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;54325:212;;;;;;;;;;-1:-1:-1;54325:212:0;;;;;:::i;:::-;;:::i;:::-;;;612:14:1;;605:22;587:41;;575:2;560:18;54325:212:0;;;;;;;;56555:60;;;;;;;;;;;;56592:23;56555:60;;;;;785:25:1;;;773:2;758:18;56555:60:0;639:177:1;58916:54:0;;;;;;;;;;-1:-1:-1;58916:54:0;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;:::i;57527:359::-;;;;;;;;;;-1:-1:-1;57527:359:0;;;;;:::i;:::-;;:::i;:::-;;56737:45;;;;;;;;;;;;56776:6;56737:45;;58514;;;;;;;;;;;;58553:6;58514:45;;47930:120;;;;;;;;;;-1:-1:-1;47930:120:0;;;;;:::i;:::-;47995:7;48021:12;;;;;;;;;;:22;;;;47930:120;48346:136;;;;;;;;;;-1:-1:-1;48346:136:0;;;;;:::i;:::-;;:::i;49448:245::-;;;;;;;;;;-1:-1:-1;49448:245:0;;;;;:::i;:::-;;:::i;66591:1146::-;;;;;;;;;;-1:-1:-1;66591:1146:0;;;;;:::i;:::-;;:::i;61049:2114::-;;;;;;:::i;:::-;;:::i;56899:30::-;;;;;;;;;;;;;;;;56483:66;;;;;;;;;;;;56523:26;56483:66;;68338:1153;;;;;;;;;;-1:-1:-1;68338:1153:0;;;;;:::i;:::-;;:::i;58646:56::-;;;;;;;;;;;;58692:10;58646:56;;59161:44;;;;;;;;;;-1:-1:-1;59161:44:0;;;;;:::i;:::-;;;;;;;;;;;;;;;;64957:567;;;;;;;;;;-1:-1:-1;64957:567:0;;;;;:::i;:::-;;:::i;63201:1718::-;;;;;;:::i;:::-;;:::i;55122:142::-;;;;;;;;;;-1:-1:-1;55122:142:0;;;;;:::i;:::-;;:::i;:::-;;;-1:-1:-1;;;;;7391:55:1;;;7373:74;;7361:2;7346:18;55122:142:0;7227:226:1;59035:51:0;;;;;;;;;;-1:-1:-1;59035:51:0;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;59035:51:0;;;;;;;7660:26:1;7648:39;;;7630:58;;-1:-1:-1;;;;;7724:55:1;;;7719:2;7704:18;;7697:83;7603:18;59035:51:0;7458:328:1;46974:136:0;;;;;;;;;;-1:-1:-1;46974:136:0;;;;;:::i;:::-;47051:4;47074:12;;;;;;;;;;;-1:-1:-1;;;;;47074:29:0;;;;;;;;;;;;;;;46974:136;56413:64;;;;;;;;;;;;56452:25;56413:64;;46307:49;;;;;;;;;;-1:-1:-1;46307:49:0;46352:4;46307:49;;59321:36;;;;;;;;;;;;;;;66180:373;;;;;;;;;;-1:-1:-1;66180:373:0;;;;;:::i;:::-;;:::i;60848:163::-;;;;;;;;;;-1:-1:-1;60848:163:0;;;;;:::i;:::-;;:::i;:::-;;;;;;;:::i;67775:525::-;;;;;;;;;;-1:-1:-1;67775:525:0;;;;;:::i;:::-;;:::i;59244:20::-;;;;;;;;;;;;;;;;57231:290;;;;;;;;;;-1:-1:-1;57231:290:0;;;;;:::i;:::-;;:::i;57892:264::-;;;;;;;;;;-1:-1:-1;57892:264:0;;;;;:::i;:::-;;:::i;56694:37::-;;;;;;;;;;;;56728:3;56694:37;;55432:131;;;;;;;;;;-1:-1:-1;55432:131:0;;;;;:::i;:::-;;:::i;56621:66::-;;;;;;;;;;;;56661:26;56621:66;;48762:138;;;;;;;;;;-1:-1:-1;48762:138:0;;;;;:::i;:::-;;:::i;56985:47::-;;;;;;;;;;-1:-1:-1;56985:47:0;;;;;:::i;:::-;;;;;;;;;;;;;;57106:29;;;;;;;;;;;;;;;;54325:212;54410:4;54433:57;;;54448:42;54433:57;;:97;;;54494:36;54518:11;54494:23;:36::i;:::-;54426:104;54325:212;-1:-1:-1;;54325:212:0:o;57527:359::-;56661:26;46584:16;46595:4;46584:10;:16::i;:::-;-1:-1:-1;;;;;57651:19:0;::::1;57631:17;57651:19:::0;;;:12:::1;:19;::::0;;;;;;57684:14;;;57680:27:::1;;57700:7;57527:359:::0;;;:::o;57680:27::-:1;-1:-1:-1::0;;;;;57748:19:0;::::1;57770:1;57748:19:::0;;;:12:::1;:19;::::0;;;;:23;57781:45:::1;::::0;57805:9;57816;57781:23:::1;:45::i;:::-;57841:38;::::0;;-1:-1:-1;;;;;9986:15:1;;;9968:34;;10038:15;;10033:2;10018:18;;10011:43;10070:18;;;10063:34;;;57841:38:0::1;::::0;9895:2:1;9880:18;57841:38:0::1;;;;;;;57621:265;46610:1;57527:359:::0;;;:::o;48346:136::-;47995:7;48021:12;;;;;;;;;;:22;;;46584:16;46595:4;46584:10;:16::i;:::-;48450:25:::1;48461:4;48467:7;48450:10;:25::i;:::-;;48346:136:::0;;;:::o;49448:245::-;-1:-1:-1;;;;;49541:34:0;;22395:10;49541:34;49537:102;;49598:30;;;;;;;;;;;;;;49537:102;49649:37;49661:4;49667:18;49649:11;:37::i;66591:1146::-;56452:25;46584:16;46595:4;46584:10;:16::i;:::-;66706:18;;::::1;::::0;::::1;::::0;66682:21:::1;66773:29;66716:7:::0;66773:20:::1;:29::i;:::-;66734:68:::0;-1:-1:-1;66920:27:0::1;66887:29;::::0;;;:14:::1;:29;::::0;;;;;::::1;;:60;::::0;::::1;;;;;;:::i;:::-;;66883:90;;66956:17;;;;;;;;;;;;;;66883:90;66984:24;67011:27:::0;;;:12:::1;:27;::::0;;;;;;;;66984:54;;;;::::1;::::0;;;;::::1;::::0;::::1;::::0;;;;::::1;-1:-1:-1::0;;;;;66984:54:0::1;::::0;;::::1;::::0;;;67069:10:::1;67052:27;67048:57;;67088:17;;;;;;;;;;;;;;67048:57;66110:15:::0;;58408:10:::1;::::0;66091:15;66084:41;66076:49;;67119:35:::1;67115:72;;67163:24;;;;;;;;;;;;;;67115:72;67198:29;::::0;;;:14:::1;:29;::::0;;;;:60;;-1:-1:-1;;67198:60:0::1;67230:28;67198:60;::::0;;67333:27:::1;::::0;::::1;::::0;:31;67329:105:::1;;67407:27;::::0;::::1;::::0;67379:23:::1;::::0;::::1;::::0;-1:-1:-1;;;;;67366:37:0::1;;::::0;;;:12:::1;:37;::::0;;;;:68;;:37;;;:68:::1;::::0;67407:27;;67366:68:::1;:::i;:::-;::::0;;;-1:-1:-1;;67329:105:0::1;67529:23;::::0;::::1;::::0;67579:24:::1;::::0;::::1;::::0;67613:35:::1;-1:-1:-1::0;;;;;67613:23:0;::::1;67637:2:::0;67579:24;67613:23:::1;:35::i;:::-;67664:66;::::0;;-1:-1:-1;;;;;10619:55:1;;;10601:74;;10706:2;10691:18;;10684:34;;;67664:66:0;::::1;::::0;67700:10:::1;::::0;67685:13;;67664:66:::1;::::0;10574:18:1;67664:66:0::1;;;;;;;;66672:1065;;;;;66591:1146:::0;;;:::o;61049:2114::-;61176:13;61155:6;:17;;;:34;;;61151:63;;61198:16;;;;;;;;;;;;;;61151:63;61228:19;;;;:24;;:50;;-1:-1:-1;61256:17:0;;;;:22;61228:50;61224:80;;;61287:17;;;;;;;;;;;;;;61224:80;61318:18;;;;-1:-1:-1;;;;;61318:32:0;;;:66;;-1:-1:-1;61354:16:0;;;;-1:-1:-1;;;;;61354:30:0;;61318:66;61314:92;;;61393:13;;;;;;;;;;;;;;61314:92;61438:37;58692:10;61438:15;:37;:::i;:::-;61420:6;:15;;;:55;61416:86;;;61484:18;;;;;;;;;;;;;;61416:86;61637:20;61660:66;61679:4;61686:6;:18;;;61706:6;:19;;;61660:10;:66::i;:::-;61637:89;;61794:23;61849:1;61831:15;;:19;61827:85;;;56728:3;61886:15;;61871:12;:30;;;;:::i;:::-;61870:42;;;;:::i;:::-;61852:60;;61827:85;61922:31;61938:15;61922:31;;:::i;:::-;;;62066:20;62113:618;;;;;;;;62171:13;62113:618;;;;;;62216:6;:17;;;62113:618;;;;;;62265:6;:13;;;-1:-1:-1;;;;;62113:618:0;;;;;62311:6;:9;;;-1:-1:-1;;;;;62113:618:0;;;;;62351:6;:18;;;-1:-1:-1;;;;;62113:618:0;;;;;62398:6;:16;;;-1:-1:-1;;;;;62113:618:0;;;;;62446:12;62113:618;;;;62488:6;:17;;;62113:618;;;;62540:15;62113:618;;;;62587:6;:19;;;62113:618;;;;;;62634:6;:15;;;62113:618;;;;62674:5;;:7;;;;;;;;;:::i;:::-;;;;-1:-1:-1;62113:618:0;;62089:652;;;;;;;;:::i;:::-;;;;;;;;;;;;;;62775:18;;62089:652;62775:18;;;;;;;62751:21;62803:29;;;:14;:29;;;;;;:54;;-1:-1:-1;;62803:54:0;62835:22;62803:54;;;62929:13;;;62977:17;;63008:18;;;;63040:16;;;;63096:17;;;;63127:19;;;;62089:652;;-1:-1:-1;62775:18:0;;-1:-1:-1;;;;;62873:283:0;;;;62775:18;;62873:283;;;;62089:652;;62977:17;;63008:18;;63040:16;;63070:12;;62873:283;:::i;:::-;;;;;;;;61110:2053;;;;61049:2114;:::o;68338:1153::-;68419:18;;;;;;68395:21;68486:29;68429:7;68486:20;:29::i;:::-;68553:10;47051:4;47074:29;;;:12;;:29;:12;:29;;;68447:68;;-1:-1:-1;47074:29:0;;68526:382;;;68661:11;:20;;;68642:15;:39;68638:73;;68690:21;;;;;;;;;;;;;;68638:73;68526:382;;;58553:6;68832:11;:20;;;:35;;;;:::i;:::-;68813:15;:54;68809:88;;68876:21;;;;;;;;;;;;;;68809:88;69017:22;68984:29;;;;:14;:29;;;;;;;;:55;;;;;;;;:::i;:::-;;68980:85;;69048:17;;;;;;;;;;;;;;68980:85;69075:29;;;;:14;:29;;;;;;:53;;-1:-1:-1;;69075:53:0;69107:21;69075:53;;;69214:24;;;69264:23;;;;69341:27;;;;69314:24;;;;69214;;69264:23;;69314:54;;69341:27;69314:54;:::i;:::-;69297:71;-1:-1:-1;69378:35:0;-1:-1:-1;;;;;69378:23:0;;69402:2;69297:71;69378:23;:35::i;:::-;69429:55;;;-1:-1:-1;;;;;10619:55:1;;;10601:74;;10706:2;10691:18;;10684:34;;;69429:55:0;;;69451:13;;69429:55;;10574:18:1;69429:55:0;;;;;;;68385:1106;;;;;68338:1153;:::o;64957:567::-;56452:25;46584:16;46595:4;46584:10;:16::i;:::-;65080:18;;::::1;::::0;::::1;::::0;65201:22:::1;65168:29;::::0;;;:14:::1;:29;::::0;;;;;::::1;;:55;::::0;::::1;;;;;;:::i;:::-;;65164:85;;65232:17;;;;;;;;;;;;;;65164:85;65259:29;::::0;;;:14:::1;:29;::::0;;;;;;;:59;;65291:27:::1;-1:-1:-1::0;;65259:59:0;;::::1;;::::0;;65358:70;;;;::::1;::::0;;::::1;65389:15;65358:70:::0;::::1;::::0;;65416:10:::1;65358:70:::0;;::::1;::::0;;;65328:27;;;:12:::1;:27:::0;;;;;;:100;;;;-1:-1:-1;;;;;65328:100:0::1;::::0;::::1;::::0;;;::::1;::::0;;;::::1;::::0;;65459:58;785:25:1;;;65259:29:0;;65459:58:::1;::::0;758:18:1;65459:58:0::1;;;;;;;65046:478;64957:567:::0;;;:::o;63201:1718::-;56452:25;46584:16;46595:4;46584:10;:16::i;:::-;63312:18;;::::1;::::0;::::1;::::0;63288:21:::1;63379:29;63322:7:::0;63379:20:::1;:29::i;:::-;63340:68;;63456:13;63422:48;;:11;:23;;;:48;;;63418:77;;63479:16;;;;;;;;;;;;;;63418:77;63591:11;:20;;;63573:15;:38;63569:69;;;63620:18;;;;;;;;;;;;;;63569:69;63699:27;::::0;;;:12:::1;:27;::::0;;;;;::::1;;63695:60;;;63735:20;;;;;;;;;;;;;;63695:60;63765:27;::::0;;;:12:::1;:27;::::0;;;;:34;;-1:-1:-1;;63765:34:0::1;63795:4;63765:34;::::0;;63912:25:::1;::::0;::::1;::::0;63963:21:::1;::::0;::::1;::::0;64011:22:::1;::::0;::::1;::::0;64061:14:::1;::::0;64090:24:::1;::::0;::::1;::::0;64085:517:::1;;-1:-1:-1::0;64168:1:0::1;64183:29;64194:2:::0;64198:5;64205:6;64183:10:::1;:29::i;:::-;;64085:517;;;64233:38:::0;-1:-1:-1;;;;;64233:38:0;::::1;::::0;64229:373:::1;;64353:38;64364:2:::0;64368:5;64375:15:::1;64384:6:::0;64375;:15:::1;:::i;:::-;64353:10;:38::i;64229:373::-;64495:29;64506:2;64510:5;64517:6;64495:10;:29::i;:::-;;64538:53;64549:2;51314:42;64584:6;64538:10;:53::i;:::-;;64229:373;64711:25:::0;;64750:23:::1;::::0;;::::1;::::0;64787:21:::1;::::0;;::::1;::::0;64822:24:::1;::::0;;::::1;::::0;64860:22:::1;::::0;::::1;::::0;64617:295:::1;::::0;;13103:10:1;13091:23;;;13073:42;;-1:-1:-1;;;;;13212:15:1;;;13207:2;13192:18;;13185:43;13264:15;;;13244:18;;;13237:43;;;;13311:2;13296:18;;13289:34;13339:19;;;13332:35;13383:19;;13376:35;;;64617:295:0;::::1;::::0;64671:10:::1;::::0;64644:13;;64617:295:::1;::::0;13045:19:1;64617:295:0::1;12788:629:1::0;55122:142:0;55203:7;55229:18;;;:12;:18;;;;;:28;;55251:5;55229:21;:28::i;:::-;55222:35;55122:142;-1:-1:-1;;;55122:142:0:o;66180:373::-;66261:4;66314:27;66281:29;;;;:14;:29;;;;;;;;:60;;;;;;;;:::i;:::-;;66277:90;;66350:17;;;;;;;;;;;;;;66277:90;66377:24;66404:27;;;:12;:27;;;;;;;;;66377:54;;;;;;;;;;;;;;-1:-1:-1;;;;;66377:54:0;;;;;;;;;;;;66445:24;;;66441:54;;66478:17;;;;;;;;;;;;;;66441:54;66110:15;;58408:10;;66091:15;66084:41;66076:49;;66512:34;;66180:373;-1:-1:-1;;;;66180:373:0:o;60848:163::-;-1:-1:-1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;60964:40:0;;-1:-1:-1;;60964:40:0;;;;;;;;;;:::i;67775:525::-;56592:23;46584:16;46595:4;46584:10;:16::i;:::-;67892:27:::1;67859:29;::::0;;;:14:::1;:29;::::0;;;;;::::1;;:60;::::0;::::1;;;;;;:::i;:::-;;67855:90;;67928:17;;;;;;;;;;;;;;67855:90;67970:27;::::0;;;:12:::1;:27;::::0;;;;;;;;67959:39;;;;::::1;::::0;;;;::::1;::::0;;::::1;::::0;;;;;;::::1;-1:-1:-1::0;;;;;67959:39:0::1;::::0;;;::::1;::::0;;;;58408:10:::1;::::0;66091:15;66084:41;66076:49;67959:56:::1;67955:90;;;68024:21;;;;;;;;;;;;;;67955:90;68133:29;::::0;;;:14:::1;:29;::::0;;;;;;;:54;;-1:-1:-1;;68133:54:0::1;68165:22;68133:54;::::0;;68204:12:::1;:27:::0;;;;;;68197:34;;;68247:46;68282:10:::1;::::0;68133:29;;68247:46:::1;::::0;68133:29;68247:46:::1;67775:525:::0;;:::o;57231:290::-;56661:26;46584:16;46595:4;46584:10;:16::i;:::-;56776:6:::1;57330:10;:26;;57322:55;;;::::0;::::1;::::0;;15233:2:1;57322:55:0::1;::::0;::::1;15215:21:1::0;15272:2;15252:18;;;15245:30;15311:18;15291;;;15284:46;15347:18;;57322:55:0::1;;;;;;;;;57408:15;::::0;;57433:28;;;;57476:38:::1;::::0;;15550:25:1;;;15606:2;15591:18;;15584:34;;;57476:38:0::1;::::0;15523:18:1;57476:38:0::1;;;;;;;;57312:209;57231:290:::0;;:::o;57892:264::-;56661:26;46584:16;46595:4;46584:10;:16::i;:::-;58017:14:::1;::::0;;58041:34;;;;58090:59:::1;::::0;;15550:25:1;;;15606:2;15591:18;;15584:34;;;58090:59:0::1;::::0;15523:18:1;58090:59:0::1;15376:248:1::0;55432:131:0;55503:7;55529:18;;;:12;:18;;;;;:27;;:25;:27::i;48762:138::-;47995:7;48021:12;;;;;;;;;;:22;;;46584:16;46595:4;46584:10;:16::i;:::-;48867:26:::1;48879:4;48885:7;48867:11;:26::i;46685:202::-:0;46770:4;46793:47;;;46808:32;46793:47;;:87;;-1:-1:-1;38600:25:0;38585:40;;;;46844:36;38486:146;47319:103;47385:30;47396:4;22395:10;47385;:30::i;:::-;47319:103;:::o;51597:653::-;51772:4;-1:-1:-1;;;;;51758:19:0;;;51754:32;;51597:653;;;:::o;51754:32::-;51858:5;51867:1;51858:10;51854:23;;51597:653;;;:::o;51854:23::-;51890:20;-1:-1:-1;;;;;51890:20:0;;;51886:358;;52070:12;52087:2;-1:-1:-1;;;;;52087:7:0;52102:5;52087:25;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;52069:43;;;52134:7;52126:39;;;;;;;16041:2:1;52126:39:0;;;16023:21:1;16080:2;16060:18;;;16053:30;16119:21;16099:18;;;16092:49;16158:18;;52126:39:0;15839:343:1;51886:358:0;52196:37;-1:-1:-1;;;;;52196:26:0;;52223:2;52227:5;52196:26;:37::i;55665:257::-;55751:4;55767:12;55782:31;55799:4;55805:7;55782:16;:31::i;:::-;55767:46;;55827:7;55823:69;;;55850:18;;;;:12;:18;;;;;:31;;55873:7;55850:22;:31::i;:::-;;55908:7;55665:257;-1:-1:-1;;;55665:257:0:o;56025:262::-;56112:4;56128:12;56143:32;56161:4;56167:7;56143:17;:32::i;:::-;56128:47;;56189:7;56185:72;;;56212:18;;;;:12;:18;;;;;:34;;56238:7;56212:25;:34::i;59633:1177::-;59721:20;-1:-1:-1;;;;;59757:38:0;;51314:42;59757:38;59753:1051;;59811:24;:5;-1:-1:-1;;;;;59811:22:0;;:24::i;:::-;59916:34;;;;;-1:-1:-1;;;;;7391:55:1;;;59916:34:0;;;7373:74:1;59916:23:0;;;;;7346:18:1;;59916:34:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;59901:49;-1:-1:-1;60096:61:0;-1:-1:-1;;;;;60096:30:0;;60127:10;60139:9;60150:6;60096:30;:61::i;:::-;60293:34;;;;;-1:-1:-1;;;;;7391:55:1;;;60293:34:0;;;7373:74:1;60330:12:0;;60293:23;;;;;;7346:18:1;;60293:34:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;:49;;;;:::i;:::-;60278:64;;59753:1051;;;60464:9;60454:6;:19;60450:51;;60482:19;;;;;;;;;;;;;;60450:51;-1:-1:-1;;;;;60582:26:0;;60603:4;60582:26;60578:74;;60610:42;-1:-1:-1;;;;;60610:23:0;;60634:9;60645:6;60610:23;:42::i;:::-;-1:-1:-1;60784:9:0;59633:1177;;;;;:::o;33098:156::-;33172:7;33222:22;33226:3;33238:5;33222:3;:22::i;32641:115::-;32704:7;32730:19;32738:3;28080:18;;27998:107;47552:197;47051:4;47074:12;;;;;;;;;;;-1:-1:-1;;;;;47074:29:0;;;;;;;;;;;;47635:108;;47685:47;;;;;-1:-1:-1;;;;;10619:55:1;;47685:47:0;;;10601:74:1;10691:18;;;10684:34;;;10574:18;;47685:47:0;10427:297:1;47635:108:0;47552:197;;:::o;39802:160::-;39911:43;;-1:-1:-1;;;;;10619:55:1;;;39911:43:0;;;10601:74:1;10691:18;;;10684:34;;;39884:71:0;;39904:5;;39926:14;;;;;10574:18:1;;39911:43:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;39884:19;:71::i;50299:316::-;50376:4;47074:12;;;;;;;;;;;-1:-1:-1;;;;;47074:29:0;;;;;;;;;;;;50392:217;;50435:6;:12;;;;;;;;;;;-1:-1:-1;;;;;50435:29:0;;;;;;;;;:36;;-1:-1:-1;;50435:36:0;50467:4;50435:36;;;50517:12;22395:10;;22316:96;50517:12;-1:-1:-1;;;;;50490:40:0;50508:7;-1:-1:-1;;;;;50490:40:0;50502:4;50490:40;;;;;;;;;;-1:-1:-1;50551:4:0;50544:11;;50392:217;-1:-1:-1;50593:5:0;50586:12;;31840:150;31910:4;31933:50;31938:3;-1:-1:-1;;;;;31958:23:0;;31933:4;:50::i;50850:317::-;50928:4;47074:12;;;;;;;;;;;-1:-1:-1;;;;;47074:29:0;;;;;;;;;;;;50944:217;;;51018:5;50986:12;;;;;;;;;;;-1:-1:-1;;;;;50986:29:0;;;;;;;;;;:37;;-1:-1:-1;;50986:37:0;;;51042:40;22395:10;;50986:12;;51042:40;;51018:5;51042:40;-1:-1:-1;51103:4:0;51096:11;;32158:156;32231:4;32254:53;32262:3;-1:-1:-1;;;;;32282:23:0;;32254:7;:53::i;53414:344::-;53581:38;-1:-1:-1;;;;;53581:38:0;;;53577:69;;53628:18;;;;;;;;;;;;;;53577:69;53702:5;-1:-1:-1;;;;;53702:17:0;;53723:1;53702:22;53698:53;;53733:18;;;;;;;;;;;;;;40201:188;40328:53;;-1:-1:-1;;;;;9986:15:1;;;40328:53:0;;;9968:34:1;10038:15;;;10018:18;;;10011:43;10070:18;;;10063:34;;;40301:81:0;;40321:5;;40343:18;;;;;9880::1;;40328:53:0;9705:398:1;28447:118:0;28514:7;28540:3;:11;;28552:5;28540:18;;;;;;;;:::i;:::-;;;;;;;;;28533:25;;28447:118;;;;:::o;42558:629::-;42977:23;43003:33;-1:-1:-1;;;;;43003:27:0;;43031:4;43003:27;:33::i;:::-;42977:59;;43050:10;:17;43071:1;43050:22;;:57;;;;;43088:10;43077:30;;;;;;;;;;;;:::i;:::-;43076:31;43050:57;43046:135;;;43130:40;;;;;-1:-1:-1;;;;;7391:55:1;;43130:40:0;;;7373:74:1;7346:18;;43130:40:0;7227:226:1;25765:406:0;25828:4;27884:21;;;:14;;;:21;;;;;;25844:321;;-1:-1:-1;25886:23:0;;;;;;;;:11;:23;;;;;;;;;;;;;26068:18;;26044:21;;;:14;;;:21;;;;;;:42;;;;26100:11;;26339:1368;26405:4;26534:21;;;:14;;;:21;;;;;;26570:13;;26566:1135;;26937:18;26958:12;26969:1;26958:8;:12;:::i;:::-;27004:18;;26937:33;;-1:-1:-1;26984:17:0;;27004:22;;27025:1;;27004:22;:::i;:::-;26984:42;;27059:9;27045:10;:23;27041:378;;27088:17;27108:3;:11;;27120:9;27108:22;;;;;;;;:::i;:::-;;;;;;;;;27088:42;;27255:9;27229:3;:11;;27241:10;27229:23;;;;;;;;:::i;:::-;;;;;;;;;;;;:35;;;;27368:25;;;:14;;;:25;;;;;:36;;;27041:378;27497:17;;:3;;:17;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;27600:3;:14;;:21;27615:5;27600:21;;;;;;;;;;;27593:28;;;27643:4;27636:11;;;;;;;26566:1135;27685:5;27678:12;;;;;18101:151;18176:12;18207:38;18229:6;18237:4;18243:1;18176:12;18817;18831:23;18858:6;-1:-1:-1;;;;;18858:11:0;18877:5;18884:4;18858:31;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;18816:73;;;;18906:55;18933:6;18941:7;18950:10;18906:26;:55::i;:::-;18899:62;18576:392;-1:-1:-1;;;;;;18576:392:0:o;20021:582::-;20165:12;20194:7;20189:408;;20217:19;20225:10;20217:7;:19::i;:::-;20189:408;;;20441:17;;:22;:49;;;;-1:-1:-1;;;;;;20467:18:0;;;:23;20441:49;20437:119;;;20517:24;;;;;-1:-1:-1;;;;;7391:55:1;;20517:24:0;;;7373:74:1;7346:18;;20517:24:0;7227:226:1;20437:119:0;-1:-1:-1;20576:10:0;20569:17;;21139:516;21270:17;;:21;21266:383;;21498:10;21492:17;21554:15;21541:10;21537:2;21533:19;21526:44;21266:383;21621:17;;;;;;;;;;;;;;14:332:1;72:6;125:2;113:9;104:7;100:23;96:32;93:52;;;141:1;138;131:12;93:52;180:9;167:23;230:66;223:5;219:78;212:5;209:89;199:117;;312:1;309;302:12;821:180;880:6;933:2;921:9;912:7;908:23;904:32;901:52;;;949:1;946;939:12;901:52;-1:-1:-1;972:23:1;;821:180;-1:-1:-1;821:180:1:o;1006:184::-;1058:77;1055:1;1048:88;1155:4;1152:1;1145:15;1179:4;1176:1;1169:15;1195:402;1344:2;1329:18;;1377:1;1366:13;;1356:201;;1413:77;1410:1;1403:88;1514:4;1511:1;1504:15;1542:4;1539:1;1532:15;1356:201;1566:25;;;1195:402;:::o;1602:154::-;-1:-1:-1;;;;;1681:5:1;1677:54;1670:5;1667:65;1657:93;;1746:1;1743;1736:12;1761:134;1829:20;;1858:31;1829:20;1858:31;:::i;:::-;1761:134;;;:::o;1900:388::-;1968:6;1976;2029:2;2017:9;2008:7;2004:23;2000:32;1997:52;;;2045:1;2042;2035:12;1997:52;2084:9;2071:23;2103:31;2128:5;2103:31;:::i;:::-;2153:5;-1:-1:-1;2210:2:1;2195:18;;2182:32;2223:33;2182:32;2223:33;:::i;:::-;2275:7;2265:17;;;1900:388;;;;;:::o;2475:315::-;2543:6;2551;2604:2;2592:9;2583:7;2579:23;2575:32;2572:52;;;2620:1;2617;2610:12;2572:52;2656:9;2643:23;2633:33;;2716:2;2705:9;2701:18;2688:32;2729:31;2754:5;2729:31;:::i;2795:184::-;2847:77;2844:1;2837:88;2944:4;2941:1;2934:15;2968:4;2965:1;2958:15;2984:252;3056:2;3050:9;3098:3;3086:16;;3132:18;3117:34;;3153:22;;;3114:62;3111:88;;;3179:18;;:::i;:::-;3215:2;3208:22;2984:252;:::o;3241:247::-;3308:2;3302:9;3350:3;3338:16;;3384:18;3369:34;;3405:22;;;3366:62;3363:88;;;3431:18;;:::i;3493:777::-;3535:5;3588:3;3581:4;3573:6;3569:17;3565:27;3555:55;;3606:1;3603;3596:12;3555:55;3642:6;3629:20;3668:18;3705:2;3701;3698:10;3695:36;;;3711:18;;:::i;:::-;3845:2;3839:9;3907:4;3899:13;;3750:66;3895:22;;;3919:2;3891:31;3887:40;3875:53;;;3943:18;;;3963:22;;;3940:46;3937:72;;;3989:18;;:::i;:::-;4029:10;4025:2;4018:22;4064:2;4056:6;4049:18;4110:3;4103:4;4098:2;4090:6;4086:15;4082:26;4079:35;4076:55;;;4127:1;4124;4117:12;4076:55;4191:2;4184:4;4176:6;4172:17;4165:4;4157:6;4153:17;4140:54;4238:1;4231:4;4226:2;4218:6;4214:15;4210:26;4203:37;4258:6;4249:15;;;;;;3493:777;;;;:::o;4275:455::-;4352:6;4360;4413:2;4401:9;4392:7;4388:23;4384:32;4381:52;;;4429:1;4426;4419:12;4381:52;4469:9;4456:23;4502:18;4494:6;4491:30;4488:50;;;4534:1;4531;4524:12;4488:50;4557:49;4598:7;4589:6;4578:9;4574:22;4557:49;:::i;:::-;4547:59;;;4656:2;4645:9;4641:18;4628:32;4669:31;4694:5;4669:31;:::i;4735:121::-;4820:10;4813:5;4809:22;4802:5;4799:33;4789:61;;4846:1;4843;4836:12;4861:132;4928:20;;4957:30;4928:20;4957:30;:::i;4998:118::-;5084:5;5077:13;5070:21;5063:5;5060:32;5050:60;;5106:1;5103;5096:12;5121:128;5186:20;;5215:28;5186:20;5215:28;:::i;5254:865::-;5342:6;5395:3;5383:9;5374:7;5370:23;5366:33;5363:53;;;5412:1;5409;5402:12;5363:53;5438:22;;:::i;:::-;5483:28;5501:9;5483:28;:::i;:::-;5476:5;5469:43;5544:38;5578:2;5567:9;5563:18;5544:38;:::i;:::-;5539:2;5532:5;5528:14;5521:62;5615:38;5649:2;5638:9;5634:18;5615:38;:::i;:::-;5610:2;5603:5;5599:14;5592:62;5686:38;5720:2;5709:9;5705:18;5686:38;:::i;:::-;5681:2;5674:5;5670:14;5663:62;5758:39;5792:3;5781:9;5777:19;5758:39;:::i;:::-;5752:3;5745:5;5741:15;5734:64;5859:3;5848:9;5844:19;5831:33;5825:3;5818:5;5814:15;5807:58;5926:3;5915:9;5911:19;5898:33;5892:3;5885:5;5881:15;5874:58;5965:36;5996:3;5985:9;5981:19;5965:36;:::i;:::-;5959:3;5948:15;;5941:61;6021:3;6069:18;;;6056:32;6040:14;;;6033:56;;;;-1:-1:-1;5952:5:1;5254:865;-1:-1:-1;5254:865:1:o;6124:320::-;6192:6;6245:2;6233:9;6224:7;6220:23;6216:32;6213:52;;;6261:1;6258;6251:12;6213:52;6301:9;6288:23;6334:18;6326:6;6323:30;6320:50;;;6366:1;6363;6356:12;6320:50;6389:49;6430:7;6421:6;6410:9;6406:22;6389:49;:::i;:::-;6379:59;6124:320;-1:-1:-1;;;;6124:320:1:o;6449:388::-;6526:6;6534;6587:2;6575:9;6566:7;6562:23;6558:32;6555:52;;;6603:1;6600;6593:12;6555:52;6643:9;6630:23;6676:18;6668:6;6665:30;6662:50;;;6708:1;6705;6698:12;6662:50;6731:49;6772:7;6763:6;6752:9;6748:22;6731:49;:::i;:::-;6721:59;6827:2;6812:18;;;;6799:32;;-1:-1:-1;;;;6449:388:1:o;6842:248::-;6910:6;6918;6971:2;6959:9;6950:7;6946:23;6942:32;6939:52;;;6987:1;6984;6977:12;6939:52;-1:-1:-1;;7010:23:1;;;7080:2;7065:18;;;7052:32;;-1:-1:-1;6842:248:1:o;7890:1373::-;8121:13;;7867:10;7856:22;7844:35;;8090:3;8075:19;;8193:4;8185:6;8181:17;8175:24;8208:53;8255:4;8244:9;8240:20;8226:12;7867:10;7856:22;7844:35;;7791:94;8208:53;;8310:4;8302:6;8298:17;8292:24;8325:56;8375:4;8364:9;8360:20;8344:14;-1:-1:-1;;;;;7161:54:1;7149:67;;7095:127;8325:56;;8430:4;8422:6;8418:17;8412:24;8445:56;8495:4;8484:9;8480:20;8464:14;-1:-1:-1;;;;;7161:54:1;7149:67;;7095:127;8445:56;;8550:4;8542:6;8538:17;8532:24;8565:56;8615:4;8604:9;8600:20;8584:14;-1:-1:-1;;;;;7161:54:1;7149:67;;7095:127;8565:56;;8670:4;8662:6;8658:17;8652:24;8685:56;8735:4;8724:9;8720:20;8704:14;-1:-1:-1;;;;;7161:54:1;7149:67;;7095:127;8685:56;;8797:4;8789:6;8785:17;8779:24;8772:4;8761:9;8757:20;8750:54;8860:4;8852:6;8848:17;8842:24;8835:4;8824:9;8820:20;8813:54;8886:6;8946:2;8938:6;8934:15;8928:22;8923:2;8912:9;8908:18;8901:50;;8970:6;9025:2;9017:6;9013:15;9007:22;9038:51;9085:2;9074:9;9070:18;9054:14;421:13;414:21;402:34;;351:91;9038:51;-1:-1:-1;;9108:6:1;9156:15;;;9150:22;9130:18;;;9123:50;9192:6;9240:15;;;9234:22;9214:18;;;;9207:50;;;;7890:1373;:::o;9453:247::-;9512:6;9565:2;9553:9;9544:7;9540:23;9536:32;9533:52;;;9581:1;9578;9571:12;9533:52;9620:9;9607:23;9639:31;9664:5;9639:31;:::i;10108:184::-;10160:77;10157:1;10150:88;10257:4;10254:1;10247:15;10281:4;10278:1;10271:15;10297:125;10362:9;;;10383:10;;;10380:36;;;10396:18;;:::i;10729:168::-;10802:9;;;10833;;10850:15;;;10844:22;;10830:37;10820:71;;10871:18;;:::i;10902:274::-;10942:1;10968;10958:189;;11003:77;11000:1;10993:88;11104:4;11101:1;11094:15;11132:4;11129:1;11122:15;10958:189;-1:-1:-1;11161:9:1;;10902:274::o;11181:128::-;11248:9;;;11269:11;;;11266:37;;;11283:18;;:::i;11314:195::-;11353:3;11384:66;11377:5;11374:77;11371:103;;11454:18;;:::i;:::-;-1:-1:-1;11501:1:1;11490:13;;11314:195::o;11514:250::-;11599:1;11609:113;11623:6;11620:1;11617:13;11609:113;;;11699:11;;;11693:18;11680:11;;;11673:39;11645:2;11638:10;11609:113;;;-1:-1:-1;;11756:1:1;11738:16;;11731:27;11514:250::o;11769:1014::-;12076:3;12065:9;12058:22;12039:4;12109:6;12103:13;12153:6;12147:3;12136:9;12132:19;12125:35;12179:3;12191:81;12265:6;12260:2;12249:9;12245:18;12238:4;12230:6;12226:17;12191:81;:::i;:::-;12452:10;12440:23;;;;12433:4;12418:20;;12411:53;-1:-1:-1;;;;;12561:15:1;;;12556:2;12541:18;;12534:43;12613:15;;;;12608:2;12593:18;;12586:43;12660:3;12645:19;;12638:35;;;;12704:3;12689:19;;12682:35;;;;12761:14;12754:22;12748:3;12733:19;;12726:51;12324:2;12312:15;;;-1:-1:-1;12308:88:1;12293:104;12289:113;;;;;-1:-1:-1;;11769:1014:1:o;13422:136::-;13500:13;;13522:30;13500:13;13522:30;:::i;13563:138::-;13642:13;;13664:31;13642:13;13664:31;:::i;13706:132::-;13782:13;;13804:28;13782:13;13804:28;:::i;13843:1183::-;13946:6;13999:3;13987:9;13978:7;13974:23;13970:33;13967:53;;;14016:1;14013;14006:12;13967:53;14042:17;;:::i;:::-;14082:39;14111:9;14082:39;:::i;:::-;14075:5;14068:54;14154:48;14198:2;14187:9;14183:18;14154:48;:::i;:::-;14149:2;14142:5;14138:14;14131:72;14235:49;14280:2;14269:9;14265:18;14235:49;:::i;:::-;14230:2;14223:5;14219:14;14212:73;14317:49;14362:2;14351:9;14347:18;14317:49;:::i;:::-;14312:2;14305:5;14301:14;14294:73;14400:50;14445:3;14434:9;14430:19;14400:50;:::i;:::-;14394:3;14387:5;14383:15;14376:75;14484:50;14529:3;14518:9;14514:19;14484:50;:::i;:::-;14478:3;14471:5;14467:15;14460:75;14589:3;14578:9;14574:19;14568:26;14562:3;14555:5;14551:15;14544:51;14649:3;14638:9;14634:19;14628:26;14622:3;14615:5;14611:15;14604:51;14674:3;14730:2;14719:9;14715:18;14709:25;14704:2;14697:5;14693:14;14686:49;;14754:3;14789:46;14831:2;14820:9;14816:18;14789:46;:::i;:::-;14773:14;;;14766:70;14855:3;14896:18;;;14890:25;14874:14;;;14867:49;14935:3;14976:18;;;14970:25;14954:14;;;14947:49;;;;-1:-1:-1;14777:5:1;13843:1183;-1:-1:-1;13843:1183:1:o;16187:184::-;16257:6;16310:2;16298:9;16289:7;16285:23;16281:32;16278:52;;;16326:1;16323;16316:12;16278:52;-1:-1:-1;16349:16:1;;16187:184;-1:-1:-1;16187:184:1:o;16678:::-;16730:77;16727:1;16720:88;16827:4;16824:1;16817:15;16851:4;16848:1;16841:15;16867:245;16934:6;16987:2;16975:9;16966:7;16962:23;16958:32;16955:52;;;17003:1;17000;16993:12;16955:52;17035:9;17029:16;17054:28;17076:5;17054:28;:::i;17117:184::-;17169:77;17166:1;17159:88;17266:4;17263:1;17256:15;17290:4;17287:1;17280:15;17306:287;17435:3;17473:6;17467:13;17489:66;17548:6;17543:3;17536:4;17528:6;17524:17;17489:66;:::i;:::-;17571:16;;;;;17306:287;-1:-1:-1;;17306:287:1:o","abiDefinition":[{"inputs":[{"internalType":"address","name":"_owner","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AccessControlBadConfirmation","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"bytes32","name":"neededRole","type":"bytes32"}],"name":"AccessControlUnauthorizedAccount","type":"error"},{"inputs":[{"internalType":"address","name":"target","type":"address"}],"name":"AddressEmptyCode","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"AddressInsufficientBalance","type":"error"},{"inputs":[],"name":"AmountIncorrect","type":"error"},{"inputs":[],"name":"ChainIncorrect","type":"error"},{"inputs":[],"name":"DeadlineExceeded","type":"error"},{"inputs":[],"name":"DeadlineNotExceeded","type":"error"},{"inputs":[],"name":"DeadlineTooShort","type":"error"},{"inputs":[],"name":"DisputePeriodNotPassed","type":"error"},{"inputs":[],"name":"DisputePeriodPassed","type":"error"},{"inputs":[],"name":"FailedInnerCall","type":"error"},{"inputs":[],"name":"MsgValueIncorrect","type":"error"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"SafeERC20FailedOperation","type":"error"},{"inputs":[],"name":"SenderIncorrect","type":"error"},{"inputs":[],"name":"StatusIncorrect","type":"error"},{"inputs":[],"name":"TokenNotContract","type":"error"},{"inputs":[],"name":"TransactionRelayed","type":"error"},{"inputs":[],"name":"ZeroAddress","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"relayer","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"BridgeDepositClaimed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"BridgeDepositRefunded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"relayer","type":"address"}],"name":"BridgeProofDisputed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"relayer","type":"address"},{"indexed":false,"internalType":"bytes32","name":"transactionHash","type":"bytes32"}],"name":"BridgeProofProvided","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"relayer","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint32","name":"originChainId","type":"uint32"},{"indexed":false,"internalType":"address","name":"originToken","type":"address"},{"indexed":false,"internalType":"address","name":"destToken","type":"address"},{"indexed":false,"internalType":"uint256","name":"originAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"destAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"chainGasAmount","type":"uint256"}],"name":"BridgeRelayed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"bytes","name":"request","type":"bytes"},{"indexed":false,"internalType":"uint32","name":"destChainId","type":"uint32"},{"indexed":false,"internalType":"address","name":"originToken","type":"address"},{"indexed":false,"internalType":"address","name":"destToken","type":"address"},{"indexed":false,"internalType":"uint256","name":"originAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"destAmount","type":"uint256"},{"indexed":false,"internalType":"bool","name":"sendChainGas","type":"bool"}],"name":"BridgeRequested","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldChainGasAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newChainGasAmount","type":"uint256"}],"name":"ChainGasAmountUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldFeeRate","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newFeeRate","type":"uint256"}],"name":"FeeRateUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"address","name":"recipient","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"FeesSwept","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"previousAdminRole","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"newAdminRole","type":"bytes32"}],"name":"RoleAdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleRevoked","type":"event"},{"inputs":[],"name":"DEFAULT_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"DISPUTE_PERIOD","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"FEE_BPS","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"FEE_RATE_MAX","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"GOVERNOR_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"GUARD_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MIN_DEADLINE_PERIOD","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"REFUNDER_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"REFUND_DELAY","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"RELAYER_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"uint32","name":"dstChainId","type":"uint32"},{"internalType":"address","name":"sender","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"address","name":"originToken","type":"address"},{"internalType":"address","name":"destToken","type":"address"},{"internalType":"uint256","name":"originAmount","type":"uint256"},{"internalType":"uint256","name":"destAmount","type":"uint256"},{"internalType":"bool","name":"sendChainGas","type":"bool"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"internalType":"struct IFastBridge.BridgeParams","name":"params","type":"tuple"}],"name":"bridge","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"bridgeProofs","outputs":[{"internalType":"uint96","name":"timestamp","type":"uint96"},{"internalType":"address","name":"relayer","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"bridgeRelays","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"bridgeStatuses","outputs":[{"internalType":"enum FastBridge.BridgeStatus","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"internalType":"address","name":"relayer","type":"address"}],"name":"canClaim","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"chainGasAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"},{"internalType":"address","name":"to","type":"address"}],"name":"claim","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"deployBlock","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"transactionId","type":"bytes32"}],"name":"dispute","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"}],"name":"getBridgeTransaction","outputs":[{"components":[{"internalType":"uint32","name":"originChainId","type":"uint32"},{"internalType":"uint32","name":"destChainId","type":"uint32"},{"internalType":"address","name":"originSender","type":"address"},{"internalType":"address","name":"destRecipient","type":"address"},{"internalType":"address","name":"originToken","type":"address"},{"internalType":"address","name":"destToken","type":"address"},{"internalType":"uint256","name":"originAmount","type":"uint256"},{"internalType":"uint256","name":"destAmount","type":"uint256"},{"internalType":"uint256","name":"originFeeAmount","type":"uint256"},{"internalType":"bool","name":"sendChainGas","type":"bool"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint256","name":"nonce","type":"uint256"}],"internalType":"struct IFastBridge.BridgeTransaction","name":"","type":"tuple"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleAdmin","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"uint256","name":"index","type":"uint256"}],"name":"getRoleMember","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleMemberCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"grantRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"hasRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"nonce","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"protocolFeeRate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"protocolFees","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"},{"internalType":"bytes32","name":"destTxHash","type":"bytes32"}],"name":"prove","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"}],"name":"refund","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"}],"name":"relay","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"callerConfirmation","type":"address"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"revokeRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"newChainGasAmount","type":"uint256"}],"name":"setChainGasAmount","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"newFeeRate","type":"uint256"}],"name":"setProtocolFeeRate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"address","name":"recipient","type":"address"}],"name":"sweepProtocolFees","outputs":[],"stateMutability":"nonpayable","type":"function"}],"userDoc":{"kind":"user","methods":{"DISPUTE_PERIOD()":{"notice":"Dispute period for relayed transactions"},"MIN_DEADLINE_PERIOD()":{"notice":"Minimum deadline period to relay a requested bridge transaction"},"REFUND_DELAY()":{"notice":"Delay for a transaction after which it could be permisionlessly refunded"},"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256))":{"notice":"Initiates bridge on origin chain to be relayed by off-chain relayer"},"bridgeProofs(bytes32)":{"notice":"Proof of relayed bridge tx on origin chain"},"bridgeRelays(bytes32)":{"notice":"Whether bridge has been relayed on destination chain"},"bridgeStatuses(bytes32)":{"notice":"Status of the bridge tx on origin chain"},"canClaim(bytes32,address)":{"notice":"Checks if the dispute period has passed so bridge deposit can be claimed"},"chainGasAmount()":{"notice":"Chain gas amount to forward as rebate if requested"},"claim(bytes,address)":{"notice":"Completes bridge transaction on origin chain by claiming originally deposited capital"},"dispute(bytes32)":{"notice":"Disputes an outstanding proof in case relayer provided dest chain tx is invalid"},"getBridgeTransaction(bytes)":{"notice":"Decodes bridge request into a bridge transaction"},"protocolFeeRate()":{"notice":"Protocol fee rate taken on origin amount deposited in origin chain"},"protocolFees(address)":{"notice":"Protocol fee amounts accumulated"},"prove(bytes,bytes32)":{"notice":"Provides proof on origin side that relayer provided funds on destination side of bridge transaction"},"refund(bytes)":{"notice":"Refunds an outstanding bridge transaction in case optimistic bridging failed"},"relay(bytes)":{"notice":"Relays destination side of bridge transaction by off-chain relayer"}},"version":1},"developerDoc":{"errors":{"AccessControlBadConfirmation()":[{"details":"The caller of a function is not the expected one. NOTE: Don't confuse with {AccessControlUnauthorizedAccount}."}],"AccessControlUnauthorizedAccount(address,bytes32)":[{"details":"The `account` is missing a role."}],"AddressEmptyCode(address)":[{"details":"There's no code at `target` (it is not a contract)."}],"AddressInsufficientBalance(address)":[{"details":"The ETH balance of the account is not enough to perform the operation."}],"FailedInnerCall()":[{"details":"A call to an address target failed. The target may have reverted."}],"SafeERC20FailedOperation(address)":[{"details":"An operation with an ERC20 token failed."}]},"events":{"RoleAdminChanged(bytes32,bytes32,bytes32)":{"details":"Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole` `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite {RoleAdminChanged} not being emitted signaling this."},"RoleGranted(bytes32,address,address)":{"details":"Emitted when `account` is granted `role`. `sender` is the account that originated the contract call, an admin role bearer except when using {AccessControl-_setupRole}."},"RoleRevoked(bytes32,address,address)":{"details":"Emitted when `account` is revoked `role`. `sender` is the account that originated the contract call: - if using `revokeRole`, it is the admin role bearer - if using `renounceRole`, it is the role bearer (i.e. `account`)"}},"kind":"dev","methods":{"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256))":{"params":{"params":"The parameters required to bridge"}},"canClaim(bytes32,address)":{"params":{"relayer":"The address of the relayer attempting to claim","transactionId":"The transaction id associated with the encoded bridge transaction to check"}},"claim(bytes,address)":{"params":{"request":"The encoded bridge transaction to claim on origin chain","to":"The recipient address of the funds"}},"dispute(bytes32)":{"params":{"transactionId":"The transaction id associated with the encoded bridge transaction to dispute"}},"getBridgeTransaction(bytes)":{"params":{"request":"The bridge request to decode"}},"getRoleAdmin(bytes32)":{"details":"Returns the admin role that controls `role`. See {grantRole} and {revokeRole}. To change a role's admin, use {_setRoleAdmin}."},"getRoleMember(bytes32,uint256)":{"details":"Returns one of the accounts that have `role`. `index` must be a value between 0 and {getRoleMemberCount}, non-inclusive. Role bearers are not sorted in any particular way, and their ordering may change at any point. WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure you perform all queries on the same block. See the following https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post] for more information."},"getRoleMemberCount(bytes32)":{"details":"Returns the number of accounts that have `role`. Can be used together with {getRoleMember} to enumerate all bearers of a role."},"grantRole(bytes32,address)":{"details":"Grants `role` to `account`. If `account` had not been already granted `role`, emits a {RoleGranted} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleGranted} event."},"hasRole(bytes32,address)":{"details":"Returns `true` if `account` has been granted `role`."},"prove(bytes,bytes32)":{"params":{"destTxHash":"The destination tx hash proving bridge transaction was relayed","request":"The encoded bridge transaction to prove on origin chain"}},"refund(bytes)":{"params":{"request":"The encoded bridge transaction to refund"}},"relay(bytes)":{"params":{"request":"The encoded bridge transaction to relay on destination chain"}},"renounceRole(bytes32,address)":{"details":"Revokes `role` from the calling account. Roles are often managed via {grantRole} and {revokeRole}: this function's purpose is to provide a mechanism for accounts to lose their privileges if they are compromised (such as when a trusted device is misplaced). If the calling account had been revoked `role`, emits a {RoleRevoked} event. Requirements: - the caller must be `callerConfirmation`. May emit a {RoleRevoked} event."},"revokeRole(bytes32,address)":{"details":"Revokes `role` from `account`. If `account` had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleRevoked} event."},"supportsInterface(bytes4)":{"details":"See {IERC165-supportsInterface}."}},"stateVariables":{"nonce":{"details":"to prevent replays"}},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.20+commit.a1b79de6\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_owner\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"AccessControlBadConfirmation\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"neededRole\",\"type\":\"bytes32\"}],\"name\":\"AccessControlUnauthorizedAccount\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"}],\"name\":\"AddressEmptyCode\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"AddressInsufficientBalance\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"AmountIncorrect\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ChainIncorrect\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DeadlineExceeded\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DeadlineNotExceeded\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DeadlineTooShort\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DisputePeriodNotPassed\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DisputePeriodPassed\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"FailedInnerCall\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"MsgValueIncorrect\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"}],\"name\":\"SafeERC20FailedOperation\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"SenderIncorrect\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"StatusIncorrect\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"TokenNotContract\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"TransactionRelayed\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ZeroAddress\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"BridgeDepositClaimed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"BridgeDepositRefunded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"name\":\"BridgeProofDisputed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"transactionHash\",\"type\":\"bytes32\"}],\"name\":\"BridgeProofProvided\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"originChainId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"chainGasAmount\",\"type\":\"uint256\"}],\"name\":\"BridgeRelayed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"destChainId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"sendChainGas\",\"type\":\"bool\"}],\"name\":\"BridgeRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"oldChainGasAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newChainGasAmount\",\"type\":\"uint256\"}],\"name\":\"ChainGasAmountUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"oldFeeRate\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newFeeRate\",\"type\":\"uint256\"}],\"name\":\"FeeRateUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"FeesSwept\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"previousAdminRole\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"newAdminRole\",\"type\":\"bytes32\"}],\"name\":\"RoleAdminChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleGranted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleRevoked\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"DEFAULT_ADMIN_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"DISPUTE_PERIOD\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"FEE_BPS\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"FEE_RATE_MAX\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"GOVERNOR_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"GUARD_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"MIN_DEADLINE_PERIOD\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"REFUNDER_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"REFUND_DELAY\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"RELAYER_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"dstChainId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"sendChainGas\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"}],\"internalType\":\"struct IFastBridge.BridgeParams\",\"name\":\"params\",\"type\":\"tuple\"}],\"name\":\"bridge\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"bridgeProofs\",\"outputs\":[{\"internalType\":\"uint96\",\"name\":\"timestamp\",\"type\":\"uint96\"},{\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"bridgeRelays\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"bridgeStatuses\",\"outputs\":[{\"internalType\":\"enum FastBridge.BridgeStatus\",\"name\":\"\",\"type\":\"uint8\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"name\":\"canClaim\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"chainGasAmount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"claim\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"deployBlock\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"}],\"name\":\"dispute\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"getBridgeTransaction\",\"outputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"originChainId\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"destChainId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"originSender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destRecipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"originFeeAmount\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"sendChainGas\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"}],\"internalType\":\"struct IFastBridge.BridgeTransaction\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"}],\"name\":\"getRoleAdmin\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"index\",\"type\":\"uint256\"}],\"name\":\"getRoleMember\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"}],\"name\":\"getRoleMemberCount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"grantRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"hasRole\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"nonce\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"protocolFeeRate\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"protocolFees\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"},{\"internalType\":\"bytes32\",\"name\":\"destTxHash\",\"type\":\"bytes32\"}],\"name\":\"prove\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"refund\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"relay\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"callerConfirmation\",\"type\":\"address\"}],\"name\":\"renounceRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"revokeRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"newChainGasAmount\",\"type\":\"uint256\"}],\"name\":\"setChainGasAmount\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"newFeeRate\",\"type\":\"uint256\"}],\"name\":\"setProtocolFeeRate\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes4\",\"name\":\"interfaceId\",\"type\":\"bytes4\"}],\"name\":\"supportsInterface\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"}],\"name\":\"sweepProtocolFees\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"errors\":{\"AccessControlBadConfirmation()\":[{\"details\":\"The caller of a function is not the expected one. NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\"}],\"AccessControlUnauthorizedAccount(address,bytes32)\":[{\"details\":\"The `account` is missing a role.\"}],\"AddressEmptyCode(address)\":[{\"details\":\"There's no code at `target` (it is not a contract).\"}],\"AddressInsufficientBalance(address)\":[{\"details\":\"The ETH balance of the account is not enough to perform the operation.\"}],\"FailedInnerCall()\":[{\"details\":\"A call to an address target failed. The target may have reverted.\"}],\"SafeERC20FailedOperation(address)\":[{\"details\":\"An operation with an ERC20 token failed.\"}]},\"events\":{\"RoleAdminChanged(bytes32,bytes32,bytes32)\":{\"details\":\"Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole` `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite {RoleAdminChanged} not being emitted signaling this.\"},\"RoleGranted(bytes32,address,address)\":{\"details\":\"Emitted when `account` is granted `role`. `sender` is the account that originated the contract call, an admin role bearer except when using {AccessControl-_setupRole}.\"},\"RoleRevoked(bytes32,address,address)\":{\"details\":\"Emitted when `account` is revoked `role`. `sender` is the account that originated the contract call: - if using `revokeRole`, it is the admin role bearer - if using `renounceRole`, it is the role bearer (i.e. `account`)\"}},\"kind\":\"dev\",\"methods\":{\"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256))\":{\"params\":{\"params\":\"The parameters required to bridge\"}},\"canClaim(bytes32,address)\":{\"params\":{\"relayer\":\"The address of the relayer attempting to claim\",\"transactionId\":\"The transaction id associated with the encoded bridge transaction to check\"}},\"claim(bytes,address)\":{\"params\":{\"request\":\"The encoded bridge transaction to claim on origin chain\",\"to\":\"The recipient address of the funds\"}},\"dispute(bytes32)\":{\"params\":{\"transactionId\":\"The transaction id associated with the encoded bridge transaction to dispute\"}},\"getBridgeTransaction(bytes)\":{\"params\":{\"request\":\"The bridge request to decode\"}},\"getRoleAdmin(bytes32)\":{\"details\":\"Returns the admin role that controls `role`. See {grantRole} and {revokeRole}. To change a role's admin, use {_setRoleAdmin}.\"},\"getRoleMember(bytes32,uint256)\":{\"details\":\"Returns one of the accounts that have `role`. `index` must be a value between 0 and {getRoleMemberCount}, non-inclusive. Role bearers are not sorted in any particular way, and their ordering may change at any point. WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure you perform all queries on the same block. See the following https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post] for more information.\"},\"getRoleMemberCount(bytes32)\":{\"details\":\"Returns the number of accounts that have `role`. Can be used together with {getRoleMember} to enumerate all bearers of a role.\"},\"grantRole(bytes32,address)\":{\"details\":\"Grants `role` to `account`. If `account` had not been already granted `role`, emits a {RoleGranted} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleGranted} event.\"},\"hasRole(bytes32,address)\":{\"details\":\"Returns `true` if `account` has been granted `role`.\"},\"prove(bytes,bytes32)\":{\"params\":{\"destTxHash\":\"The destination tx hash proving bridge transaction was relayed\",\"request\":\"The encoded bridge transaction to prove on origin chain\"}},\"refund(bytes)\":{\"params\":{\"request\":\"The encoded bridge transaction to refund\"}},\"relay(bytes)\":{\"params\":{\"request\":\"The encoded bridge transaction to relay on destination chain\"}},\"renounceRole(bytes32,address)\":{\"details\":\"Revokes `role` from the calling account. Roles are often managed via {grantRole} and {revokeRole}: this function's purpose is to provide a mechanism for accounts to lose their privileges if they are compromised (such as when a trusted device is misplaced). If the calling account had been revoked `role`, emits a {RoleRevoked} event. Requirements: - the caller must be `callerConfirmation`. May emit a {RoleRevoked} event.\"},\"revokeRole(bytes32,address)\":{\"details\":\"Revokes `role` from `account`. If `account` had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleRevoked} event.\"},\"supportsInterface(bytes4)\":{\"details\":\"See {IERC165-supportsInterface}.\"}},\"stateVariables\":{\"nonce\":{\"details\":\"to prevent replays\"}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"DISPUTE_PERIOD()\":{\"notice\":\"Dispute period for relayed transactions\"},\"MIN_DEADLINE_PERIOD()\":{\"notice\":\"Minimum deadline period to relay a requested bridge transaction\"},\"REFUND_DELAY()\":{\"notice\":\"Delay for a transaction after which it could be permisionlessly refunded\"},\"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256))\":{\"notice\":\"Initiates bridge on origin chain to be relayed by off-chain relayer\"},\"bridgeProofs(bytes32)\":{\"notice\":\"Proof of relayed bridge tx on origin chain\"},\"bridgeRelays(bytes32)\":{\"notice\":\"Whether bridge has been relayed on destination chain\"},\"bridgeStatuses(bytes32)\":{\"notice\":\"Status of the bridge tx on origin chain\"},\"canClaim(bytes32,address)\":{\"notice\":\"Checks if the dispute period has passed so bridge deposit can be claimed\"},\"chainGasAmount()\":{\"notice\":\"Chain gas amount to forward as rebate if requested\"},\"claim(bytes,address)\":{\"notice\":\"Completes bridge transaction on origin chain by claiming originally deposited capital\"},\"dispute(bytes32)\":{\"notice\":\"Disputes an outstanding proof in case relayer provided dest chain tx is invalid\"},\"getBridgeTransaction(bytes)\":{\"notice\":\"Decodes bridge request into a bridge transaction\"},\"protocolFeeRate()\":{\"notice\":\"Protocol fee rate taken on origin amount deposited in origin chain\"},\"protocolFees(address)\":{\"notice\":\"Protocol fee amounts accumulated\"},\"prove(bytes,bytes32)\":{\"notice\":\"Provides proof on origin side that relayer provided funds on destination side of bridge transaction\"},\"refund(bytes)\":{\"notice\":\"Refunds an outstanding bridge transaction in case optimistic bridging failed\"},\"relay(bytes)\":{\"notice\":\"Relays destination side of bridge transaction by off-chain relayer\"}},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeMock.sol\":\"FastBridge\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeMock.sol\":{\"keccak256\":\"0x620e81214ecd324ae8b971219291f176c454ce76fb1c01d656428096da8f1366\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://18e556772c12e13aa2d52a50cc7c48e676c8d5af22b90adaf7befb39cdd08e64\",\"dweb:/ipfs/QmPrQc98TxHCFMeuFNADyjr6Nqo52rHhHy1LBcsVdMRXjL\"]}},\"version\":1}"},"hashes":{"DEFAULT_ADMIN_ROLE()":"a217fddf","DISPUTE_PERIOD()":"a5bbe22b","FEE_BPS()":"bf333f2c","FEE_RATE_MAX()":"0f5f6ed7","GOVERNOR_ROLE()":"ccc57490","GUARD_ROLE()":"03ed0ee5","MIN_DEADLINE_PERIOD()":"820688d5","REFUNDER_ROLE()":"5960ccf2","REFUND_DELAY()":"190da595","RELAYER_ROLE()":"926d7d7f","bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256))":"45851694","bridgeProofs(bytes32)":"91ad5039","bridgeRelays(bytes32)":"8379a24f","bridgeStatuses(bytes32)":"051287bc","canClaim(bytes32,address)":"aa9641ab","chainGasAmount()":"e00a83e0","claim(bytes,address)":"41fcb612","deployBlock()":"a3ec191a","dispute(bytes32)":"add98c70","getBridgeTransaction(bytes)":"ac11fb1a","getRoleAdmin(bytes32)":"248a9ca3","getRoleMember(bytes32,uint256)":"9010d07c","getRoleMemberCount(bytes32)":"ca15c873","grantRole(bytes32,address)":"2f2ff15d","hasRole(bytes32,address)":"91d14854","nonce()":"affed0e0","protocolFeeRate()":"58f85880","protocolFees(address)":"dcf844a7","prove(bytes,bytes32)":"886d36ff","refund(bytes)":"5eb7d946","relay(bytes)":"8f0d6f17","renounceRole(bytes32,address)":"36568abe","revokeRole(bytes32,address)":"d547741f","setChainGasAmount(uint256)":"b250fe6b","setProtocolFeeRate(uint256)":"b13aa2d6","supportsInterface(bytes4)":"01ffc9a7","sweepProtocolFees(address,address)":"06f333f2"}},"solidity/FastBridgeMock.sol:FastBridgeMock":{"code":"0x60a06040523480156200001157600080fd5b506040516200254e3803806200254e833981016040819052620000349162000194565b80620000426000826200004f565b50504360805250620001bf565b6000806200005e84846200008c565b90508015620000835760008481526001602052604090206200008190846200013a565b505b90505b92915050565b6000828152602081815260408083206001600160a01b038516845290915281205460ff1662000131576000838152602081815260408083206001600160a01b03861684529091529020805460ff19166001179055620000e83390565b6001600160a01b0316826001600160a01b0316847f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a450600162000086565b50600062000086565b600062000083836001600160a01b0384166000818152600183016020526040812054620001315750815460018181018455600084815260208082209093018490558454848252828601909352604090209190915562000086565b600060208284031215620001a757600080fd5b81516001600160a01b03811681146200008357600080fd5b608051612373620001db600039600061053201526123736000f3fe6080604052600436106102345760003560e01c8063926d7d7f11610138578063b13aa2d6116100b0578063ca15c8731161007f578063d547741f11610064578063d547741f146106dd578063dcf844a7146106fd578063e00a83e01461072a57600080fd5b8063ca15c87314610689578063ccc57490146106a957600080fd5b8063b13aa2d614610612578063b250fe6b14610632578063bf333f2c14610652578063c72870cc1461066957600080fd5b8063ac11fb1a11610107578063add98c70116100ec578063add98c70146105c1578063aedf009d146105dc578063affed0e0146105fc57600080fd5b8063ac11fb1a14610574578063acaebbf1146105a157600080fd5b8063926d7d7f146104d7578063a217fddf1461050b578063a3ec191a14610520578063aa9641ab1461055457600080fd5b806345851694116101cb57806385ad903d1161019a5780638f0d6f171161017f5780638f0d6f17146104335780639010d07c1461044157806391d148541461048657600080fd5b806385ad903d146103eb578063886d36ff1461041857600080fd5b8063458516941461037857806358f85880146103865780635960ccf21461039c5780635eb7d946146103d057600080fd5b8063248a9ca311610207578063248a9ca3146102e85780632f2ff15d1461031857806336568abe1461033857806341fcb6121461035857600080fd5b806301ffc9a71461023957806303ed0ee51461026e57806306f333f2146102b05780630f5f6ed7146102d2575b600080fd5b34801561024557600080fd5b5061025961025436600461195d565b610740565b60405190151581526020015b60405180910390f35b34801561027a57600080fd5b506102a27f043c983c49d46f0e102151eaf8085d4a2e6571d5df2d47b013f39bddfd4a639d81565b604051908152602001610265565b3480156102bc57600080fd5b506102d06102cb3660046119d1565b61079c565b005b3480156102de57600080fd5b506102a261271081565b3480156102f457600080fd5b506102a2610303366004611a0a565b60009081526020819052604090206001015490565b34801561032457600080fd5b506102d0610333366004611a23565b61088a565b34801561034457600080fd5b506102d0610353366004611a23565b6108b5565b34801561036457600080fd5b506102d0610373366004611b70565b61090e565b6102d0610373366004611c90565b34801561039257600080fd5b506102a260025481565b3480156103a857600080fd5b506102a27fdb9556138406326f00296e13ea2ad7db24ba82381212d816b1a40c23b466b32781565b3480156103dc57600080fd5b506102d0610373366004611cad565b3480156103f757600080fd5b5061040b610406366004611cea565b610975565b6040516102659190611d79565b34801561042457600080fd5b506102d0610373366004611d8c565b6102d0610373366004611cad565b34801561044d57600080fd5b5061046161045c366004611dd1565b610b25565b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610265565b34801561049257600080fd5b506102596104a1366004611a23565b60009182526020828152604080842073ffffffffffffffffffffffffffffffffffffffff93909316845291905290205460ff1690565b3480156104e357600080fd5b506102a27fe2b7fb3b832174769106daebcfd6d1970523240dda11281102db9363b83b0dc481565b34801561051757600080fd5b506102a2600081565b34801561052c57600080fd5b506102a27f000000000000000000000000000000000000000000000000000000000000000081565b34801561056057600080fd5b5061025961056f366004611a23565b610b44565b34801561058057600080fd5b5061059461058f366004611cad565b610ba9565b6040516102659190611df3565b3480156105ad57600080fd5b506102d06105bc366004611f0d565b610c1c565b3480156105cd57600080fd5b506102d0610373366004611a0a565b3480156105e857600080fd5b506102d06105f7366004611f4d565b610dec565b34801561060857600080fd5b506102a260055481565b34801561061e57600080fd5b506102d061062d366004611a0a565b610e77565b34801561063e57600080fd5b506102d061064d366004611a0a565b610f54565b34801561065e57600080fd5b506102a2620f424081565b34801561067557600080fd5b506102d0610684366004611fa6565b610fbc565b34801561069557600080fd5b506102a26106a4366004611a0a565b611042565b3480156106b557600080fd5b506102a27f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f5581565b3480156106e957600080fd5b506102d06106f8366004611a23565b611059565b34801561070957600080fd5b506102a261071836600461203e565b60036020526000908152604090205481565b34801561073657600080fd5b506102a260045481565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f5a05180f00000000000000000000000000000000000000000000000000000000148061079657506107968261107e565b92915050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f556107c681611115565b73ffffffffffffffffffffffffffffffffffffffff8316600090815260036020526040812054908190036107fa5750505050565b73ffffffffffffffffffffffffffffffffffffffff841660008181526003602052604081205561082b908483611122565b6040805173ffffffffffffffffffffffffffffffffffffffff8087168252851660208201529081018290527f244e51bc38c1452fa8aaf487bcb4bca36c2baa3a5fbdb776b1eabd8dc6d277cd9060600160405180910390a1505b505050565b6000828152602081905260409020600101546108a581611115565b6108af8383611279565b50505050565b73ffffffffffffffffffffffffffffffffffffffff81163314610904576040517f6697b23200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61088582826112ae565b6040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f6e6f7420696d706c656d656e746564000000000000000000000000000000000060448201526064015b60405180910390fd5b60608160048111156109895761098961205b565b6000036109c957505060408051808201909152600481527f4e554c4c00000000000000000000000000000000000000000000000000000000602082015290565b8160048111156109db576109db61205b565b600103610a1b57505060408051808201909152600981527f5245515545535445440000000000000000000000000000000000000000000000602082015290565b816004811115610a2d57610a2d61205b565b600203610a6d57505060408051808201909152600e81527f52454c415945525f50524f564544000000000000000000000000000000000000602082015290565b816004811115610a7f57610a7f61205b565b600303610abf57505060408051808201909152600f81527f52454c415945525f434c41494d45440000000000000000000000000000000000602082015290565b816004811115610ad157610ad161205b565b600403610b1157505060408051808201909152600881527f524546554e444544000000000000000000000000000000000000000000000000602082015290565b505060408051602081019091526000815290565b6000828152600160205260408120610b3d90836112db565b9392505050565b6040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f6e6f7420696d706c656d656e7465640000000000000000000000000000000000604482015260009060640161096c565b604080516101808101825260008082526020808301829052928201819052606082018190526080820181905260a0820181905260c0820181905260e082018190526101008201819052610120820181905261014082018190526101608201528251909161079691840181019084016120ab565b6000620f42406002548360a00151610c3491906121a6565b610c3e91906121bd565b9050808260a001818151610c5291906121f8565b9150818152505060006040518061018001604052804663ffffffff168152602001846000015163ffffffff168152602001846020015173ffffffffffffffffffffffffffffffffffffffff168152602001846040015173ffffffffffffffffffffffffffffffffffffffff168152602001846060015173ffffffffffffffffffffffffffffffffffffffff168152602001846080015173ffffffffffffffffffffffffffffffffffffffff1681526020018460a0015181526020018460c0015181526020018381526020018460e0015115158152602001846101000151815260200160056000815480929190610d479061220b565b909155509052604051610d5d9190602001611df3565b6040516020818303038152906040529050826020015173ffffffffffffffffffffffffffffffffffffffff16857f120ea0364f36cdac7983bcfdd55270ca09d7f9b314a2ebc425a3b01ab1d6403a838660000151876060015188608001518960a001518a60c001518b60e00151604051610ddd9796959493929190612243565b60405180910390a35050505050565b6000610df782610ba9565b9050806040015173ffffffffffffffffffffffffffffffffffffffff16847f120ea0364f36cdac7983bcfdd55270ca09d7f9b314a2ebc425a3b01ab1d6403a84846020015185608001518660a001518760c001518860e00151896101200151604051610e699796959493929190612243565b60405180910390a350505050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f55610ea181611115565b612710821115610f0d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f6e657746656552617465203e206d617800000000000000000000000000000000604482015260640161096c565b600280549083905560408051828152602081018590527f14914da2bf76024616fbe1859783fcd4dbddcb179b1f3a854949fbf920dcb95791015b60405180910390a1505050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f55610f7e81611115565b600480549083905560408051828152602081018590527f5cf09b12f3f56b4c564d51b25b40360af6d795198adb61ae0806a36c294323fa9101610f47565b6040805163ffffffff8816815273ffffffffffffffffffffffffffffffffffffffff878116602083015286811682840152606082018690526080820185905260a082018490529151898316928b16918c917ff8ae392d784b1ea5e8881bfa586d81abf07ef4f1e2fc75f7fe51c90f05199a5c9181900360c00190a4505050505050505050565b6000818152600160205260408120610796906112e7565b60008281526020819052604090206001015461107481611115565b6108af83836112ae565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f7965db0b00000000000000000000000000000000000000000000000000000000148061079657507f01ffc9a7000000000000000000000000000000000000000000000000000000007fffffffff00000000000000000000000000000000000000000000000000000000831614610796565b61111f81336112f1565b50565b3073ffffffffffffffffffffffffffffffffffffffff83160361114457505050565b8060000361115157505050565b7fffffffffffffffffffffffff111111111111111111111111111111111111111273ffffffffffffffffffffffffffffffffffffffff8416016112585760008273ffffffffffffffffffffffffffffffffffffffff168260405160006040518083038185875af1925050503d80600081146111e8576040519150601f19603f3d011682016040523d82523d6000602084013e6111ed565b606091505b50509050806108af576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f455448207472616e73666572206661696c656400000000000000000000000000604482015260640161096c565b61088573ffffffffffffffffffffffffffffffffffffffff8416838361137b565b6000806112868484611408565b90508015610b3d5760008481526001602052604090206112a69084611504565b509392505050565b6000806112bb8484611526565b90508015610b3d5760008481526001602052604090206112a690846115e1565b6000610b3d8383611603565b6000610796825490565b60008281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915290205460ff16611377576040517fe2517d3f00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff821660048201526024810183905260440161096c565b5050565b6040805173ffffffffffffffffffffffffffffffffffffffff8416602482015260448082018490528251808303909101815260649091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fa9059cbb0000000000000000000000000000000000000000000000000000000017905261088590849061162d565b60008281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915281205460ff166114fc5760008381526020818152604080832073ffffffffffffffffffffffffffffffffffffffff86168452909152902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016600117905561149a3390565b73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16847f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a4506001610796565b506000610796565b6000610b3d8373ffffffffffffffffffffffffffffffffffffffff84166116c3565b60008281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915281205460ff16156114fc5760008381526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8616808552925280832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016905551339286917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a4506001610796565b6000610b3d8373ffffffffffffffffffffffffffffffffffffffff841661170a565b600082600001828154811061161a5761161a6122a6565b9060005260206000200154905092915050565b600061164f73ffffffffffffffffffffffffffffffffffffffff8416836117fd565b9050805160001415801561167457508080602001905181019061167291906122d5565b155b15610885576040517f5274afe700000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8416600482015260240161096c565b60008181526001830160205260408120546114fc57508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155610796565b600081815260018301602052604081205480156117f357600061172e6001836121f8565b8554909150600090611742906001906121f8565b90508082146117a7576000866000018281548110611762576117626122a6565b9060005260206000200154905080876000018481548110611785576117856122a6565b6000918252602080832090910192909255918252600188019052604090208390555b85548690806117b8576117b86122f2565b600190038181906000526020600020016000905590558560010160008681526020019081526020016000206000905560019350505050610796565b6000915050610796565b6060610b3d83836000846000808573ffffffffffffffffffffffffffffffffffffffff1684866040516118309190612321565b60006040518083038185875af1925050503d806000811461186d576040519150601f19603f3d011682016040523d82523d6000602084013e611872565b606091505b509150915061188286838361188c565b9695505050505050565b6060826118a15761189c8261191b565b610b3d565b81511580156118c5575073ffffffffffffffffffffffffffffffffffffffff84163b155b15611914576040517f9996b31500000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8516600482015260240161096c565b5080610b3d565b80511561192b5780518082602001fd5b6040517f1425ea4200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006020828403121561196f57600080fd5b81357fffffffff0000000000000000000000000000000000000000000000000000000081168114610b3d57600080fd5b73ffffffffffffffffffffffffffffffffffffffff8116811461111f57600080fd5b80356119cc8161199f565b919050565b600080604083850312156119e457600080fd5b82356119ef8161199f565b915060208301356119ff8161199f565b809150509250929050565b600060208284031215611a1c57600080fd5b5035919050565b60008060408385031215611a3657600080fd5b8235915060208301356119ff8161199f565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051610120810167ffffffffffffffff81118282101715611a9b57611a9b611a48565b60405290565b604051610180810167ffffffffffffffff81118282101715611a9b57611a9b611a48565b600082601f830112611ad657600080fd5b813567ffffffffffffffff80821115611af157611af1611a48565b604051601f83017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f01168101908282118183101715611b3757611b37611a48565b81604052838152866020858801011115611b5057600080fd5b836020870160208301376000602085830101528094505050505092915050565b60008060408385031215611b8357600080fd5b823567ffffffffffffffff811115611b9a57600080fd5b611ba685828601611ac5565b92505060208301356119ff8161199f565b63ffffffff8116811461111f57600080fd5b80356119cc81611bb7565b801515811461111f57600080fd5b80356119cc81611bd4565b60006101208284031215611c0057600080fd5b611c08611a77565b9050611c1382611bc9565b8152611c21602083016119c1565b6020820152611c32604083016119c1565b6040820152611c43606083016119c1565b6060820152611c54608083016119c1565b608082015260a082013560a082015260c082013560c0820152611c7960e08301611be2565b60e082015261010080830135818301525092915050565b60006101208284031215611ca357600080fd5b610b3d8383611bed565b600060208284031215611cbf57600080fd5b813567ffffffffffffffff811115611cd657600080fd5b611ce284828501611ac5565b949350505050565b600060208284031215611cfc57600080fd5b813560058110610b3d57600080fd5b60005b83811015611d26578181015183820152602001611d0e565b50506000910152565b60008151808452611d47816020860160208601611d0b565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b602081526000610b3d6020830184611d2f565b60008060408385031215611d9f57600080fd5b823567ffffffffffffffff811115611db657600080fd5b611dc285828601611ac5565b95602094909401359450505050565b60008060408385031215611de457600080fd5b50508035926020909101359150565b815163ffffffff16815261018081016020830151611e19602084018263ffffffff169052565b506040830151611e41604084018273ffffffffffffffffffffffffffffffffffffffff169052565b506060830151611e69606084018273ffffffffffffffffffffffffffffffffffffffff169052565b506080830151611e91608084018273ffffffffffffffffffffffffffffffffffffffff169052565b5060a0830151611eb960a084018273ffffffffffffffffffffffffffffffffffffffff169052565b5060c083015160c083015260e083015160e083015261010080840151818401525061012080840151611eee8285018215159052565b5050610140838101519083015261016092830151929091019190915290565b60008060006101608486031215611f2357600080fd5b833592506020840135611f358161199f565b9150611f448560408601611bed565b90509250925092565b600080600060608486031215611f6257600080fd5b833592506020840135611f748161199f565b9150604084013567ffffffffffffffff811115611f9057600080fd5b611f9c86828701611ac5565b9150509250925092565b60008060008060008060008060006101208a8c031215611fc557600080fd5b8935985060208a0135611fd78161199f565b975060408a0135611fe78161199f565b965060608a0135611ff781611bb7565b955060808a01356120078161199f565b945060a08a01356120178161199f565b8094505060c08a0135925060e08a013591506101008a013590509295985092959850929598565b60006020828403121561205057600080fd5b8135610b3d8161199f565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b80516119cc81611bb7565b80516119cc8161199f565b80516119cc81611bd4565b600061018082840312156120be57600080fd5b6120c6611aa1565b6120cf8361208a565b81526120dd6020840161208a565b60208201526120ee60408401612095565b60408201526120ff60608401612095565b606082015261211060808401612095565b608082015261212160a08401612095565b60a082015260c083015160c082015260e083015160e08201526101008084015181830152506101206121548185016120a0565b908201526101408381015190820152610160928301519281019290925250919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b808202811582820484141761079657610796612177565b6000826121f3577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b8181038181111561079657610796612177565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820361223c5761223c612177565b5060010190565b60e08152600061225660e083018a611d2f565b63ffffffff9890981660208301525073ffffffffffffffffffffffffffffffffffffffff9586166040820152939094166060840152608083019190915260a082015290151560c090910152919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b6000602082840312156122e757600080fd5b8151610b3d81611bd4565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fd5b60008251612333818460208701611d0b565b919091019291505056fea2646970667358221220b683b83c62d39501bf0f8c7280114538e17cdaba91a577c85b1d7b2b6a51230c64736f6c63430008140033","runtime-code":"0x6080604052600436106102345760003560e01c8063926d7d7f11610138578063b13aa2d6116100b0578063ca15c8731161007f578063d547741f11610064578063d547741f146106dd578063dcf844a7146106fd578063e00a83e01461072a57600080fd5b8063ca15c87314610689578063ccc57490146106a957600080fd5b8063b13aa2d614610612578063b250fe6b14610632578063bf333f2c14610652578063c72870cc1461066957600080fd5b8063ac11fb1a11610107578063add98c70116100ec578063add98c70146105c1578063aedf009d146105dc578063affed0e0146105fc57600080fd5b8063ac11fb1a14610574578063acaebbf1146105a157600080fd5b8063926d7d7f146104d7578063a217fddf1461050b578063a3ec191a14610520578063aa9641ab1461055457600080fd5b806345851694116101cb57806385ad903d1161019a5780638f0d6f171161017f5780638f0d6f17146104335780639010d07c1461044157806391d148541461048657600080fd5b806385ad903d146103eb578063886d36ff1461041857600080fd5b8063458516941461037857806358f85880146103865780635960ccf21461039c5780635eb7d946146103d057600080fd5b8063248a9ca311610207578063248a9ca3146102e85780632f2ff15d1461031857806336568abe1461033857806341fcb6121461035857600080fd5b806301ffc9a71461023957806303ed0ee51461026e57806306f333f2146102b05780630f5f6ed7146102d2575b600080fd5b34801561024557600080fd5b5061025961025436600461195d565b610740565b60405190151581526020015b60405180910390f35b34801561027a57600080fd5b506102a27f043c983c49d46f0e102151eaf8085d4a2e6571d5df2d47b013f39bddfd4a639d81565b604051908152602001610265565b3480156102bc57600080fd5b506102d06102cb3660046119d1565b61079c565b005b3480156102de57600080fd5b506102a261271081565b3480156102f457600080fd5b506102a2610303366004611a0a565b60009081526020819052604090206001015490565b34801561032457600080fd5b506102d0610333366004611a23565b61088a565b34801561034457600080fd5b506102d0610353366004611a23565b6108b5565b34801561036457600080fd5b506102d0610373366004611b70565b61090e565b6102d0610373366004611c90565b34801561039257600080fd5b506102a260025481565b3480156103a857600080fd5b506102a27fdb9556138406326f00296e13ea2ad7db24ba82381212d816b1a40c23b466b32781565b3480156103dc57600080fd5b506102d0610373366004611cad565b3480156103f757600080fd5b5061040b610406366004611cea565b610975565b6040516102659190611d79565b34801561042457600080fd5b506102d0610373366004611d8c565b6102d0610373366004611cad565b34801561044d57600080fd5b5061046161045c366004611dd1565b610b25565b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610265565b34801561049257600080fd5b506102596104a1366004611a23565b60009182526020828152604080842073ffffffffffffffffffffffffffffffffffffffff93909316845291905290205460ff1690565b3480156104e357600080fd5b506102a27fe2b7fb3b832174769106daebcfd6d1970523240dda11281102db9363b83b0dc481565b34801561051757600080fd5b506102a2600081565b34801561052c57600080fd5b506102a27f000000000000000000000000000000000000000000000000000000000000000081565b34801561056057600080fd5b5061025961056f366004611a23565b610b44565b34801561058057600080fd5b5061059461058f366004611cad565b610ba9565b6040516102659190611df3565b3480156105ad57600080fd5b506102d06105bc366004611f0d565b610c1c565b3480156105cd57600080fd5b506102d0610373366004611a0a565b3480156105e857600080fd5b506102d06105f7366004611f4d565b610dec565b34801561060857600080fd5b506102a260055481565b34801561061e57600080fd5b506102d061062d366004611a0a565b610e77565b34801561063e57600080fd5b506102d061064d366004611a0a565b610f54565b34801561065e57600080fd5b506102a2620f424081565b34801561067557600080fd5b506102d0610684366004611fa6565b610fbc565b34801561069557600080fd5b506102a26106a4366004611a0a565b611042565b3480156106b557600080fd5b506102a27f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f5581565b3480156106e957600080fd5b506102d06106f8366004611a23565b611059565b34801561070957600080fd5b506102a261071836600461203e565b60036020526000908152604090205481565b34801561073657600080fd5b506102a260045481565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f5a05180f00000000000000000000000000000000000000000000000000000000148061079657506107968261107e565b92915050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f556107c681611115565b73ffffffffffffffffffffffffffffffffffffffff8316600090815260036020526040812054908190036107fa5750505050565b73ffffffffffffffffffffffffffffffffffffffff841660008181526003602052604081205561082b908483611122565b6040805173ffffffffffffffffffffffffffffffffffffffff8087168252851660208201529081018290527f244e51bc38c1452fa8aaf487bcb4bca36c2baa3a5fbdb776b1eabd8dc6d277cd9060600160405180910390a1505b505050565b6000828152602081905260409020600101546108a581611115565b6108af8383611279565b50505050565b73ffffffffffffffffffffffffffffffffffffffff81163314610904576040517f6697b23200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61088582826112ae565b6040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f6e6f7420696d706c656d656e746564000000000000000000000000000000000060448201526064015b60405180910390fd5b60608160048111156109895761098961205b565b6000036109c957505060408051808201909152600481527f4e554c4c00000000000000000000000000000000000000000000000000000000602082015290565b8160048111156109db576109db61205b565b600103610a1b57505060408051808201909152600981527f5245515545535445440000000000000000000000000000000000000000000000602082015290565b816004811115610a2d57610a2d61205b565b600203610a6d57505060408051808201909152600e81527f52454c415945525f50524f564544000000000000000000000000000000000000602082015290565b816004811115610a7f57610a7f61205b565b600303610abf57505060408051808201909152600f81527f52454c415945525f434c41494d45440000000000000000000000000000000000602082015290565b816004811115610ad157610ad161205b565b600403610b1157505060408051808201909152600881527f524546554e444544000000000000000000000000000000000000000000000000602082015290565b505060408051602081019091526000815290565b6000828152600160205260408120610b3d90836112db565b9392505050565b6040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f6e6f7420696d706c656d656e7465640000000000000000000000000000000000604482015260009060640161096c565b604080516101808101825260008082526020808301829052928201819052606082018190526080820181905260a0820181905260c0820181905260e082018190526101008201819052610120820181905261014082018190526101608201528251909161079691840181019084016120ab565b6000620f42406002548360a00151610c3491906121a6565b610c3e91906121bd565b9050808260a001818151610c5291906121f8565b9150818152505060006040518061018001604052804663ffffffff168152602001846000015163ffffffff168152602001846020015173ffffffffffffffffffffffffffffffffffffffff168152602001846040015173ffffffffffffffffffffffffffffffffffffffff168152602001846060015173ffffffffffffffffffffffffffffffffffffffff168152602001846080015173ffffffffffffffffffffffffffffffffffffffff1681526020018460a0015181526020018460c0015181526020018381526020018460e0015115158152602001846101000151815260200160056000815480929190610d479061220b565b909155509052604051610d5d9190602001611df3565b6040516020818303038152906040529050826020015173ffffffffffffffffffffffffffffffffffffffff16857f120ea0364f36cdac7983bcfdd55270ca09d7f9b314a2ebc425a3b01ab1d6403a838660000151876060015188608001518960a001518a60c001518b60e00151604051610ddd9796959493929190612243565b60405180910390a35050505050565b6000610df782610ba9565b9050806040015173ffffffffffffffffffffffffffffffffffffffff16847f120ea0364f36cdac7983bcfdd55270ca09d7f9b314a2ebc425a3b01ab1d6403a84846020015185608001518660a001518760c001518860e00151896101200151604051610e699796959493929190612243565b60405180910390a350505050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f55610ea181611115565b612710821115610f0d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f6e657746656552617465203e206d617800000000000000000000000000000000604482015260640161096c565b600280549083905560408051828152602081018590527f14914da2bf76024616fbe1859783fcd4dbddcb179b1f3a854949fbf920dcb95791015b60405180910390a1505050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f55610f7e81611115565b600480549083905560408051828152602081018590527f5cf09b12f3f56b4c564d51b25b40360af6d795198adb61ae0806a36c294323fa9101610f47565b6040805163ffffffff8816815273ffffffffffffffffffffffffffffffffffffffff878116602083015286811682840152606082018690526080820185905260a082018490529151898316928b16918c917ff8ae392d784b1ea5e8881bfa586d81abf07ef4f1e2fc75f7fe51c90f05199a5c9181900360c00190a4505050505050505050565b6000818152600160205260408120610796906112e7565b60008281526020819052604090206001015461107481611115565b6108af83836112ae565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f7965db0b00000000000000000000000000000000000000000000000000000000148061079657507f01ffc9a7000000000000000000000000000000000000000000000000000000007fffffffff00000000000000000000000000000000000000000000000000000000831614610796565b61111f81336112f1565b50565b3073ffffffffffffffffffffffffffffffffffffffff83160361114457505050565b8060000361115157505050565b7fffffffffffffffffffffffff111111111111111111111111111111111111111273ffffffffffffffffffffffffffffffffffffffff8416016112585760008273ffffffffffffffffffffffffffffffffffffffff168260405160006040518083038185875af1925050503d80600081146111e8576040519150601f19603f3d011682016040523d82523d6000602084013e6111ed565b606091505b50509050806108af576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f455448207472616e73666572206661696c656400000000000000000000000000604482015260640161096c565b61088573ffffffffffffffffffffffffffffffffffffffff8416838361137b565b6000806112868484611408565b90508015610b3d5760008481526001602052604090206112a69084611504565b509392505050565b6000806112bb8484611526565b90508015610b3d5760008481526001602052604090206112a690846115e1565b6000610b3d8383611603565b6000610796825490565b60008281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915290205460ff16611377576040517fe2517d3f00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff821660048201526024810183905260440161096c565b5050565b6040805173ffffffffffffffffffffffffffffffffffffffff8416602482015260448082018490528251808303909101815260649091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fa9059cbb0000000000000000000000000000000000000000000000000000000017905261088590849061162d565b60008281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915281205460ff166114fc5760008381526020818152604080832073ffffffffffffffffffffffffffffffffffffffff86168452909152902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016600117905561149a3390565b73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16847f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a4506001610796565b506000610796565b6000610b3d8373ffffffffffffffffffffffffffffffffffffffff84166116c3565b60008281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915281205460ff16156114fc5760008381526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8616808552925280832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016905551339286917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a4506001610796565b6000610b3d8373ffffffffffffffffffffffffffffffffffffffff841661170a565b600082600001828154811061161a5761161a6122a6565b9060005260206000200154905092915050565b600061164f73ffffffffffffffffffffffffffffffffffffffff8416836117fd565b9050805160001415801561167457508080602001905181019061167291906122d5565b155b15610885576040517f5274afe700000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8416600482015260240161096c565b60008181526001830160205260408120546114fc57508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155610796565b600081815260018301602052604081205480156117f357600061172e6001836121f8565b8554909150600090611742906001906121f8565b90508082146117a7576000866000018281548110611762576117626122a6565b9060005260206000200154905080876000018481548110611785576117856122a6565b6000918252602080832090910192909255918252600188019052604090208390555b85548690806117b8576117b86122f2565b600190038181906000526020600020016000905590558560010160008681526020019081526020016000206000905560019350505050610796565b6000915050610796565b6060610b3d83836000846000808573ffffffffffffffffffffffffffffffffffffffff1684866040516118309190612321565b60006040518083038185875af1925050503d806000811461186d576040519150601f19603f3d011682016040523d82523d6000602084013e611872565b606091505b509150915061188286838361188c565b9695505050505050565b6060826118a15761189c8261191b565b610b3d565b81511580156118c5575073ffffffffffffffffffffffffffffffffffffffff84163b155b15611914576040517f9996b31500000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8516600482015260240161096c565b5080610b3d565b80511561192b5780518082602001fd5b6040517f1425ea4200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006020828403121561196f57600080fd5b81357fffffffff0000000000000000000000000000000000000000000000000000000081168114610b3d57600080fd5b73ffffffffffffffffffffffffffffffffffffffff8116811461111f57600080fd5b80356119cc8161199f565b919050565b600080604083850312156119e457600080fd5b82356119ef8161199f565b915060208301356119ff8161199f565b809150509250929050565b600060208284031215611a1c57600080fd5b5035919050565b60008060408385031215611a3657600080fd5b8235915060208301356119ff8161199f565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051610120810167ffffffffffffffff81118282101715611a9b57611a9b611a48565b60405290565b604051610180810167ffffffffffffffff81118282101715611a9b57611a9b611a48565b600082601f830112611ad657600080fd5b813567ffffffffffffffff80821115611af157611af1611a48565b604051601f83017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f01168101908282118183101715611b3757611b37611a48565b81604052838152866020858801011115611b5057600080fd5b836020870160208301376000602085830101528094505050505092915050565b60008060408385031215611b8357600080fd5b823567ffffffffffffffff811115611b9a57600080fd5b611ba685828601611ac5565b92505060208301356119ff8161199f565b63ffffffff8116811461111f57600080fd5b80356119cc81611bb7565b801515811461111f57600080fd5b80356119cc81611bd4565b60006101208284031215611c0057600080fd5b611c08611a77565b9050611c1382611bc9565b8152611c21602083016119c1565b6020820152611c32604083016119c1565b6040820152611c43606083016119c1565b6060820152611c54608083016119c1565b608082015260a082013560a082015260c082013560c0820152611c7960e08301611be2565b60e082015261010080830135818301525092915050565b60006101208284031215611ca357600080fd5b610b3d8383611bed565b600060208284031215611cbf57600080fd5b813567ffffffffffffffff811115611cd657600080fd5b611ce284828501611ac5565b949350505050565b600060208284031215611cfc57600080fd5b813560058110610b3d57600080fd5b60005b83811015611d26578181015183820152602001611d0e565b50506000910152565b60008151808452611d47816020860160208601611d0b565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b602081526000610b3d6020830184611d2f565b60008060408385031215611d9f57600080fd5b823567ffffffffffffffff811115611db657600080fd5b611dc285828601611ac5565b95602094909401359450505050565b60008060408385031215611de457600080fd5b50508035926020909101359150565b815163ffffffff16815261018081016020830151611e19602084018263ffffffff169052565b506040830151611e41604084018273ffffffffffffffffffffffffffffffffffffffff169052565b506060830151611e69606084018273ffffffffffffffffffffffffffffffffffffffff169052565b506080830151611e91608084018273ffffffffffffffffffffffffffffffffffffffff169052565b5060a0830151611eb960a084018273ffffffffffffffffffffffffffffffffffffffff169052565b5060c083015160c083015260e083015160e083015261010080840151818401525061012080840151611eee8285018215159052565b5050610140838101519083015261016092830151929091019190915290565b60008060006101608486031215611f2357600080fd5b833592506020840135611f358161199f565b9150611f448560408601611bed565b90509250925092565b600080600060608486031215611f6257600080fd5b833592506020840135611f748161199f565b9150604084013567ffffffffffffffff811115611f9057600080fd5b611f9c86828701611ac5565b9150509250925092565b60008060008060008060008060006101208a8c031215611fc557600080fd5b8935985060208a0135611fd78161199f565b975060408a0135611fe78161199f565b965060608a0135611ff781611bb7565b955060808a01356120078161199f565b945060a08a01356120178161199f565b8094505060c08a0135925060e08a013591506101008a013590509295985092959850929598565b60006020828403121561205057600080fd5b8135610b3d8161199f565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b80516119cc81611bb7565b80516119cc8161199f565b80516119cc81611bd4565b600061018082840312156120be57600080fd5b6120c6611aa1565b6120cf8361208a565b81526120dd6020840161208a565b60208201526120ee60408401612095565b60408201526120ff60608401612095565b606082015261211060808401612095565b608082015261212160a08401612095565b60a082015260c083015160c082015260e083015160e08201526101008084015181830152506101206121548185016120a0565b908201526101408381015190820152610160928301519281019290925250919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b808202811582820484141761079657610796612177565b6000826121f3577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b8181038181111561079657610796612177565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820361223c5761223c612177565b5060010190565b60e08152600061225660e083018a611d2f565b63ffffffff9890981660208301525073ffffffffffffffffffffffffffffffffffffffff9586166040820152939094166060840152608083019190915260a082015290151560c090910152919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b6000602082840312156122e757600080fd5b8151610b3d81611bd4565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fd5b60008251612333818460208701611d0b565b919091019291505056fea2646970667358221220b683b83c62d39501bf0f8c7280114538e17cdaba91a577c85b1d7b2b6a51230c64736f6c63430008140033","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.20 ^0.8.20;\n\n// contracts/interfaces/IAdmin.sol\n\ninterface IAdmin {\n // ============ Events ============\n\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n event ChainGasAmountUpdated(uint256 oldChainGasAmount, uint256 newChainGasAmount);\n\n // ============ Methods ============\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n\n function setChainGasAmount(uint256 newChainGasAmount) external;\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/libs/Errors.sol\n\nerror DeadlineExceeded();\nerror DeadlineNotExceeded();\nerror DeadlineTooShort();\nerror InsufficientOutputAmount();\n\nerror MsgValueIncorrect();\nerror PoolNotFound();\nerror TokenAddressMismatch();\nerror TokenNotContract();\nerror TokenNotETH();\nerror TokensIdentical();\n\nerror ChainIncorrect();\nerror AmountIncorrect();\nerror ZeroAddress();\n\nerror DisputePeriodNotPassed();\nerror DisputePeriodPassed();\nerror SenderIncorrect();\nerror StatusIncorrect();\nerror TransactionIdIncorrect();\nerror TransactionRelayed();\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// contracts/libs/UniversalToken.sol\n\nlibrary UniversalTokenLib {\n using SafeERC20 for IERC20;\n\n address internal constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Transfers tokens to the given account. Reverts if transfer is not successful.\n /// @dev This might trigger fallback, if ETH is transferred to the contract.\n /// Make sure this can not lead to reentrancy attacks.\n function universalTransfer(address token, address to, uint256 value) internal {\n // Don't do anything, if need to send tokens to this address\n if (to == address(this)) return;\n // Don't do anything, if trying to send zero value\n if (value == 0) return;\n if (token == ETH_ADDRESS) {\n /// @dev Note: this can potentially lead to executing code in `to`.\n // solhint-disable-next-line avoid-low-level-calls\n (bool success,) = to.call{value: value}(\"\");\n require(success, \"ETH transfer failed\");\n } else {\n IERC20(token).safeTransfer(to, value);\n }\n }\n\n /// @notice Issues an infinite allowance to the spender, if the current allowance is insufficient\n /// to spend the given amount.\n function universalApproveInfinity(address token, address spender, uint256 amountToSpend) internal {\n // ETH Chad doesn't require your approval\n if (token == ETH_ADDRESS) return;\n // No-op if allowance is already sufficient\n uint256 allowance = IERC20(token).allowance(address(this), spender);\n if (allowance \u003e= amountToSpend) return;\n // Otherwise, reset approval to 0 and set to max allowance\n if (allowance \u003e 0) IERC20(token).safeDecreaseAllowance(spender, allowance);\n IERC20(token).safeIncreaseAllowance(spender, type(uint256).max);\n }\n\n /// @notice Returns the balance of the given token (or native ETH) for the given account.\n function universalBalanceOf(address token, address account) internal view returns (uint256) {\n if (token == ETH_ADDRESS) {\n return account.balance;\n } else {\n return IERC20(token).balanceOf(account);\n }\n }\n\n /// @dev Checks that token is a contract and not ETH_ADDRESS.\n function assertIsContract(address token) internal view {\n // Check that ETH_ADDRESS was not used (in case this is a predeploy on any of the chains)\n if (token == UniversalTokenLib.ETH_ADDRESS) revert TokenNotContract();\n // Check that token is not an EOA\n if (token.code.length == 0) revert TokenNotContract();\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/Admin.sol\n\ncontract Admin is IAdmin, AccessControlEnumerable {\n using UniversalTokenLib for address;\n\n bytes32 public constant RELAYER_ROLE = keccak256(\"RELAYER_ROLE\");\n bytes32 public constant REFUNDER_ROLE = keccak256(\"REFUNDER_ROLE\");\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n uint256 public constant FEE_BPS = 1e6;\n uint256 public constant FEE_RATE_MAX = 0.01e6; // max 1% on origin amount\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Chain gas amount to forward as rebate if requested\n uint256 public chainGasAmount;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n }\n\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n require(newFeeRate \u003c= FEE_RATE_MAX, \"newFeeRate \u003e max\");\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n token.universalTransfer(recipient, feeAmount);\n emit FeesSwept(token, recipient, feeAmount);\n }\n\n function setChainGasAmount(uint256 newChainGasAmount) external onlyRole(GOVERNOR_ROLE) {\n uint256 oldChainGasAmount = chainGasAmount;\n chainGasAmount = newChainGasAmount;\n emit ChainGasAmountUpdated(oldChainGasAmount, newChainGasAmount);\n }\n}\n\n// contracts/FastBridge.sol\n\ncontract FastBridge is IFastBridge, Admin {\n using SafeERC20 for IERC20;\n using UniversalTokenLib for address;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Delay for a transaction after which it could be permisionlessly refunded\n uint256 public constant REFUND_DELAY = 7 days;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeStatus) public bridgeStatuses;\n /// @notice Proof of relayed bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeProof) public bridgeProofs;\n /// @notice Whether bridge has been relayed on destination chain\n mapping(bytes32 =\u003e bool) public bridgeRelays;\n\n /// @dev to prevent replays\n uint256 public nonce;\n // @dev the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @notice Pulls a requested token from the user to the requested recipient.\n /// @dev Be careful of re-entrancy issues when msg.value \u003e 0 and recipient != address(this)\n function _pullToken(address recipient, address token, uint256 amount) internal returns (uint256 amountPulled) {\n if (token != UniversalTokenLib.ETH_ADDRESS) {\n token.assertIsContract();\n // Record token balance before transfer\n amountPulled = IERC20(token).balanceOf(recipient);\n // Token needs to be pulled only if msg.value is zero\n // This way user can specify WETH as the origin asset\n IERC20(token).safeTransferFrom(msg.sender, recipient, amount);\n // Use the difference between the recorded balance and the current balance as the amountPulled\n amountPulled = IERC20(token).balanceOf(recipient) - amountPulled;\n } else {\n // Otherwise, we need to check that ETH amount matches msg.value\n if (amount != msg.value) revert MsgValueIncorrect();\n // Transfer value to recipient if not this address\n if (recipient != address(this)) token.universalTransfer(recipient, amount);\n // We will forward msg.value in the external call later, if recipient is not this contract\n amountPulled = msg.value;\n }\n }\n\n /// @inheritdoc IFastBridge\n function getBridgeTransaction(bytes memory request) public pure returns (BridgeTransaction memory) {\n return abi.decode(request, (BridgeTransaction));\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n // check bridge params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n\n // transfer tokens to bridge contract\n // @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _pullToken(address(this), params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n\n // set status to requested\n bytes memory request = abi.encode(\n BridgeTransaction({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n sendChainGas: params.sendChainGas,\n deadline: params.deadline,\n nonce: nonce++ // increment nonce on every bridge\n })\n );\n bytes32 transactionId = keccak256(request);\n bridgeStatuses[transactionId] = BridgeStatus.REQUESTED;\n\n emit BridgeRequested(\n transactionId,\n params.sender,\n request,\n params.dstChainId,\n params.originToken,\n params.destToken,\n originAmount,\n params.destAmount,\n params.sendChainGas\n );\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes memory request) external payable onlyRole(RELAYER_ROLE) {\n bytes32 transactionId = keccak256(request);\n BridgeTransaction memory transaction = getBridgeTransaction(request);\n if (transaction.destChainId != uint32(block.chainid)) revert ChainIncorrect();\n\n // check haven't exceeded deadline for relay to happen\n if (block.timestamp \u003e transaction.deadline) revert DeadlineExceeded();\n\n // mark bridge transaction as relayed\n if (bridgeRelays[transactionId]) revert TransactionRelayed();\n bridgeRelays[transactionId] = true;\n\n // transfer tokens to recipient on destination chain and gas rebate if requested\n address to = transaction.destRecipient;\n address token = transaction.destToken;\n uint256 amount = transaction.destAmount;\n\n uint256 rebate = chainGasAmount;\n if (!transaction.sendChainGas) {\n // forward erc20\n rebate = 0;\n _pullToken(to, token, amount);\n } else if (token == UniversalTokenLib.ETH_ADDRESS) {\n // lump in gas rebate into amount in native gas token\n _pullToken(to, token, amount + rebate);\n } else {\n // forward erc20 then forward gas rebate in native gas token\n _pullToken(to, token, amount);\n _pullToken(to, UniversalTokenLib.ETH_ADDRESS, rebate);\n }\n\n emit BridgeRelayed(\n transactionId,\n msg.sender,\n to,\n transaction.originChainId,\n transaction.originToken,\n transaction.destToken,\n transaction.originAmount,\n transaction.destAmount,\n rebate\n );\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes memory request, bytes32 destTxHash) external onlyRole(RELAYER_ROLE) {\n bytes32 transactionId = keccak256(request);\n // update bridge tx status given proof provided\n if (bridgeStatuses[transactionId] != BridgeStatus.REQUESTED) revert StatusIncorrect();\n bridgeStatuses[transactionId] = BridgeStatus.RELAYER_PROVED;\n bridgeProofs[transactionId] = BridgeProof({timestamp: uint96(block.timestamp), relayer: msg.sender}); // overflow ok\n\n emit BridgeProofProvided(transactionId, msg.sender, destTxHash);\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint96(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint96).max but\n /// proof.timestamp \u003c type(uint96).max via unchecked statement\n /// @param proof The bridge proof\n /// @return delta Time delta since proof submitted\n function _timeSince(BridgeProof memory proof) internal view returns (uint256 delta) {\n unchecked {\n delta = uint96(block.timestamp) - proof.timestamp;\n }\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n if (bridgeStatuses[transactionId] != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n BridgeProof memory proof = bridgeProofs[transactionId];\n if (proof.relayer != relayer) revert SenderIncorrect();\n return _timeSince(proof) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes memory request, address to) external onlyRole(RELAYER_ROLE) {\n bytes32 transactionId = keccak256(request);\n BridgeTransaction memory transaction = getBridgeTransaction(request);\n\n // update bridge tx status if able to claim origin collateral\n if (bridgeStatuses[transactionId] != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n\n BridgeProof memory proof = bridgeProofs[transactionId];\n if (proof.relayer != msg.sender) revert SenderIncorrect();\n if (_timeSince(proof) \u003c= DISPUTE_PERIOD) revert DisputePeriodNotPassed();\n\n bridgeStatuses[transactionId] = BridgeStatus.RELAYER_CLAIMED;\n\n // update protocol fees if origin fee amount exists\n if (transaction.originFeeAmount \u003e 0) protocolFees[transaction.originToken] += transaction.originFeeAmount;\n\n // transfer origin collateral less fee to specified address\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositClaimed(transactionId, msg.sender, to, token, amount);\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n if (bridgeStatuses[transactionId] != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(bridgeProofs[transactionId]) \u003e DISPUTE_PERIOD) revert DisputePeriodPassed();\n\n // @dev relayer gets slashed effectively if dest relay has gone thru\n bridgeStatuses[transactionId] = BridgeStatus.REQUESTED;\n delete bridgeProofs[transactionId];\n\n emit BridgeProofDisputed(transactionId, msg.sender);\n }\n\n /// @inheritdoc IFastBridge\n function refund(bytes memory request) external {\n bytes32 transactionId = keccak256(request);\n BridgeTransaction memory transaction = getBridgeTransaction(request);\n\n if (hasRole(REFUNDER_ROLE, msg.sender)) {\n // Refunder can refund if deadline has passed\n if (block.timestamp \u003c= transaction.deadline) revert DeadlineNotExceeded();\n } else {\n // Permissionless refund is allowed after REFUND_DELAY\n if (block.timestamp \u003c= transaction.deadline + REFUND_DELAY) revert DeadlineNotExceeded();\n }\n\n // set status to refunded if still in requested state\n if (bridgeStatuses[transactionId] != BridgeStatus.REQUESTED) revert StatusIncorrect();\n bridgeStatuses[transactionId] = BridgeStatus.REFUNDED;\n\n // transfer origin collateral back to original sender\n address to = transaction.originSender;\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount + transaction.originFeeAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n }\n}\n\n// test/FastBridgeMock.sol\n\ncontract FastBridgeMock is IFastBridge, Admin {\n // @dev the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @dev to prevent replays\n uint256 public nonce;\n\n function getBridgeTransaction(bytes memory request) public pure returns (BridgeTransaction memory) {\n return abi.decode(request, (BridgeTransaction));\n }\n\n // used for testing in go.\n // see: https://ethereum.stackexchange.com/questions/21155/how-to-expose-enum-in-solidity-contract\n // make sure to update fastbridge/status.go if this changes\n // or underliyng enum changes.\n //\n // TODO: a foundry test should be added to ensure this is always in sync.\n function getEnumKeyByValue(FastBridge.BridgeStatus keyValue) public pure returns (string memory) {\n if (FastBridge.BridgeStatus.NULL == keyValue) return \"NULL\";\n if (FastBridge.BridgeStatus.REQUESTED == keyValue) return \"REQUESTED\";\n if (FastBridge.BridgeStatus.RELAYER_PROVED == keyValue) return \"RELAYER_PROVED\";\n if (FastBridge.BridgeStatus.RELAYER_CLAIMED == keyValue) return \"RELAYER_CLAIMED\";\n if (FastBridge.BridgeStatus.REFUNDED == keyValue) return \"REFUNDED\";\n return \"\";\n }\n\n function mockBridgeRequest(bytes32 transactionId, address sender, BridgeParams memory params) external {\n uint256 originFeeAmount = (params.originAmount * protocolFeeRate) / FEE_BPS;\n params.originAmount -= originFeeAmount;\n\n bytes memory request = abi.encode(\n BridgeTransaction({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: params.originAmount, // includes relayer fee\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n sendChainGas: params.sendChainGas,\n deadline: params.deadline,\n nonce: nonce++ // increment nonce on every bridge\n })\n );\n\n emit BridgeRequested(\n transactionId,\n params.sender,\n request,\n params.dstChainId,\n params.originToken,\n params.destToken,\n params.originAmount,\n params.destAmount,\n params.sendChainGas\n );\n }\n\n function mockBridgeRequestRaw(bytes32 transactionId, address sender, bytes memory request) external {\n BridgeTransaction memory transaction = getBridgeTransaction(request);\n emit BridgeRequested(\n transactionId,\n transaction.originSender,\n request,\n transaction.destChainId,\n transaction.originToken,\n transaction.destToken,\n transaction.originAmount,\n transaction.destAmount,\n transaction.sendChainGas\n );\n }\n\n function mockBridgeRelayer(\n bytes32 transactionId,\n address relayer,\n address to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n )\n external\n {\n emit BridgeRelayed(\n transactionId, relayer, to, originChainId, originToken, destToken, originAmount, destAmount, chainGasAmount\n );\n }\n\n function bridge(BridgeParams memory params) external payable {\n revert(\"not implemented\");\n }\n\n function relay(bytes memory request) external payable {\n revert(\"not implemented\");\n }\n\n function prove(bytes memory request, bytes32 destTxHash) external {\n revert(\"not implemented\");\n }\n\n function canClaim(bytes32 transactionid, address relayer) external view returns (bool) {\n revert(\"not implemented\");\n }\n\n function claim(bytes memory request, address to) external {\n revert(\"not implemented\");\n }\n\n function dispute(bytes32 transactionId) external {\n revert(\"not implemented\");\n }\n\n function refund(bytes memory request) external {\n revert(\"not implemented\");\n }\n}\n","language":"Solidity","languageVersion":"0.8.20","compilerVersion":"0.8.20","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"69523:4359:0:-:0;;;69669:85;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;69703:6;57180:38;46352:4;69703:6;57180:10;:38::i;:::-;-1:-1:-1;;69735:12:0::1;69721:26;::::0;-1:-1:-1;69523:4359:0;;55665:257;55751:4;;55782:31;55799:4;55805:7;55782:16;:31::i;:::-;55767:46;;55827:7;55823:69;;;55850:18;;;;:12;:18;;;;;:31;;55873:7;55850:22;:31::i;:::-;;55823:69;55908:7;-1:-1:-1;55665:257:0;;;;;:::o;50299:316::-;50376:4;47074:12;;;;;;;;;;;-1:-1:-1;;;;;47074:29:0;;;;;;;;;;;;50392:217;;50435:6;:12;;;;;;;;;;;-1:-1:-1;;;;;50435:29:0;;;;;;;;;:36;;-1:-1:-1;;50435:36:0;50467:4;50435:36;;;50517:12;22395:10;;22316:96;50517:12;-1:-1:-1;;;;;50490:40:0;50508:7;-1:-1:-1;;;;;50490:40:0;50502:4;50490:40;;;;;;;;;;-1:-1:-1;50551:4:0;50544:11;;50392:217;-1:-1:-1;50593:5:0;50586:12;;31840:150;31910:4;31933:50;31938:3;-1:-1:-1;;;;;31958:23:0;;25828:4;27884:21;;;:14;;;:21;;;;;;25844:321;;-1:-1:-1;25886:23:0;;;;;;;;:11;:23;;;;;;;;;;;;;26068:18;;26044:21;;;:14;;;:21;;;;;;:42;;;;26100:11;;14:290:1;84:6;137:2;125:9;116:7;112:23;108:32;105:52;;;153:1;150;143:12;105:52;179:16;;-1:-1:-1;;;;;224:31:1;;214:42;;204:70;;270:1;267;260:12;14:290;69523:4359:0;;;;;;;;;;;;","srcMapRuntime":"69523:4359:0:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;54325:212;;;;;;;;;;-1:-1:-1;54325:212:0;;;;;:::i;:::-;;:::i;:::-;;;612:14:1;;605:22;587:41;;575:2;560:18;54325:212:0;;;;;;;;56555:60;;;;;;;;;;;;56592:23;56555:60;;;;;785:25:1;;;773:2;758:18;56555:60:0;639:177:1;57527:359:0;;;;;;;;;;-1:-1:-1;57527:359:0;;;;;:::i;:::-;;:::i;:::-;;56737:45;;;;;;;;;;;;56776:6;56737:45;;47930:120;;;;;;;;;;-1:-1:-1;47930:120:0;;;;;:::i;:::-;47995:7;48021:12;;;;;;;;;;:22;;;;47930:120;48346:136;;;;;;;;;;-1:-1:-1;48346:136:0;;;;;:::i;:::-;;:::i;49448:245::-;;;;;;;;;;-1:-1:-1;49448:245:0;;;;;:::i;:::-;;:::i;73588:100::-;;;;;;;;;;-1:-1:-1;73588:100:0;;;;;:::i;:::-;;:::i;73128:103::-;;;;;;:::i;56899:30::-;;;;;;;;;;;;;;;;56483:66;;;;;;;;;;;;56523:26;56483:66;;73791:89;;;;;;;;;;-1:-1:-1;73791:89:0;;;;;:::i;70306:528::-;;;;;;;;;;-1:-1:-1;70306:528:0;;;;;:::i;:::-;;:::i;:::-;;;;;;;:::i;73339:108::-;;;;;;;;;;-1:-1:-1;73339:108:0;;;;;:::i;73237:96::-;;;;;;:::i;55122:142::-;;;;;;;;;;-1:-1:-1;55122:142:0;;;;;:::i;:::-;;:::i;:::-;;;8086:42:1;8074:55;;;8056:74;;8044:2;8029:18;55122:142:0;7910:226:1;46974:136:0;;;;;;;;;;-1:-1:-1;46974:136:0;;;;;:::i;:::-;47051:4;47074:12;;;;;;;;;;;:29;;;;;;;;;;;;;;;;46974:136;56413:64;;;;;;;;;;;;56452:25;56413:64;;46307:49;;;;;;;;;;-1:-1:-1;46307:49:0;46352:4;46307:49;;69626:36;;;;;;;;;;;;;;;73453:129;;;;;;;;;;-1:-1:-1;73453:129:0;;;;;:::i;:::-;;:::i;69819:163::-;;;;;;;;;;-1:-1:-1;69819:163:0;;;;;:::i;:::-;;:::i;:::-;;;;;;;:::i;70840:1266::-;;;;;;;;;;-1:-1:-1;70840:1266:0;;;;;:::i;:::-;;:::i;73694:91::-;;;;;;;;;;-1:-1:-1;73694:91:0;;;;;:::i;72112:532::-;;;;;;;;;;-1:-1:-1;72112:532:0;;;;;:::i;:::-;;:::i;69792:20::-;;;;;;;;;;;;;;;;57231:290;;;;;;;;;;-1:-1:-1;57231:290:0;;;;;:::i;:::-;;:::i;57892:264::-;;;;;;;;;;-1:-1:-1;57892:264:0;;;;;:::i;:::-;;:::i;56694:37::-;;;;;;;;;;;;56728:3;56694:37;;72650:472;;;;;;;;;;-1:-1:-1;72650:472:0;;;;;:::i;:::-;;:::i;55432:131::-;;;;;;;;;;-1:-1:-1;55432:131:0;;;;;:::i;:::-;;:::i;56621:66::-;;;;;;;;;;;;56661:26;56621:66;;48762:138;;;;;;;;;;-1:-1:-1;48762:138:0;;;;;:::i;:::-;;:::i;56985:47::-;;;;;;;;;;-1:-1:-1;56985:47:0;;;;;:::i;:::-;;;;;;;;;;;;;;57106:29;;;;;;;;;;;;;;;;54325:212;54410:4;54433:57;;;54448:42;54433:57;;:97;;;54494:36;54518:11;54494:23;:36::i;:::-;54426:104;54325:212;-1:-1:-1;;54325:212:0:o;57527:359::-;56661:26;46584:16;46595:4;46584:10;:16::i;:::-;57651:19:::1;::::0;::::1;57631:17;57651:19:::0;;;:12:::1;:19;::::0;;;;;;57684:14;;;57680:27:::1;;57700:7;57527:359:::0;;;:::o;57680:27::-:1;57748:19;::::0;::::1;57770:1;57748:19:::0;;;:12:::1;:19;::::0;;;;:23;57781:45:::1;::::0;57805:9;57816;57781:23:::1;:45::i;:::-;57841:38;::::0;;12332:42:1;12401:15;;;12383:34;;12453:15;;12448:2;12433:18;;12426:43;12485:18;;;12478:34;;;57841:38:0::1;::::0;12310:2:1;12295:18;57841:38:0::1;;;;;;;57621:265;46610:1;57527:359:::0;;;:::o;48346:136::-;47995:7;48021:12;;;;;;;;;;:22;;;46584:16;46595:4;46584:10;:16::i;:::-;48450:25:::1;48461:4;48467:7;48450:10;:25::i;:::-;;48346:136:::0;;;:::o;49448:245::-;49541:34;;;22395:10;49541:34;49537:102;;49598:30;;;;;;;;;;;;;;49537:102;49649:37;49661:4;49667:18;49649:11;:37::i;73588:100::-;73656:25;;;;;12725:2:1;73656:25:0;;;12707:21:1;12764:2;12744:18;;;12737:30;12803:17;12783:18;;;12776:45;12838:18;;73656:25:0;;;;;;;;70306:528;70388:13;70449:8;70417:40;;;;;;;;:::i;:::-;:28;:40;70413:59;;-1:-1:-1;;70459:13:0;;;;;;;;;;;;;;;;;;70306:528::o;70413:59::-;70523:8;70486:45;;;;;;;;:::i;:::-;:33;:45;70482:69;;-1:-1:-1;;70533:18:0;;;;;;;;;;;;;;;;;;70306:528::o;70482:69::-;70607:8;70565:50;;;;;;;;:::i;:::-;:38;:50;70561:79;;-1:-1:-1;;70617:23:0;;;;;;;;;;;;;;;;;;70306:528::o;70561:79::-;70697:8;70654:51;;;;;;;;:::i;:::-;:39;:51;70650:81;;-1:-1:-1;;70707:24:0;;;;;;;;;;;;;;;;;;70306:528::o;70650:81::-;70781:8;70745:44;;;;;;;;:::i;:::-;:32;:44;70741:67;;-1:-1:-1;;70791:17:0;;;;;;;;;;;;;;;;;;70306:528::o;70741:67::-;-1:-1:-1;;70818:9:0;;;;;;;;;-1:-1:-1;70818:9:0;;;70306:528::o;55122:142::-;55203:7;55229:18;;;:12;:18;;;;;:28;;55251:5;55229:21;:28::i;:::-;55222:35;55122:142;-1:-1:-1;;;55122:142:0:o;73453:129::-;73550:25;;;;;12725:2:1;73550:25:0;;;12707:21:1;12764:2;12744:18;;;12737:30;12803:17;12783:18;;;12776:45;73534:4:0;;12838:18:1;;73550:25:0;12523:339:1;69819:163:0;-1:-1:-1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;69935:40:0;;-1:-1:-1;;69935:40:0;;;;;;;;;;:::i;70840:1266::-;70953:23;56728:3;71002:15;;70980:6;:19;;;:37;;;;:::i;:::-;70979:49;;;;:::i;:::-;70953:75;;71061:15;71038:6;:19;;:38;;;;;;;:::i;:::-;;;;;;;;71087:20;71134:649;;;;;;;;71192:13;71134:649;;;;;;71237:6;:17;;;71134:649;;;;;;71286:6;:13;;;71134:649;;;;;;71332:6;:9;;;71134:649;;;;;;71372:6;:18;;;71134:649;;;;;;71419:6;:16;;;71134:649;;;;;;71467:6;:19;;;71134:649;;;;71540:6;:17;;;71134:649;;;;71592:15;71134:649;;;;71639:6;:19;;;71134:649;;;;;;71686:6;:15;;;71134:649;;;;71726:5;;:7;;;;;;;;;:::i;:::-;;;;-1:-1:-1;71134:649:0;;71110:683;;;;;;;;:::i;:::-;;;;;;;;;;;;;71087:706;;71865:6;:13;;;71809:290;;71838:13;71809:290;71892:7;71913:6;:17;;;71944:6;:18;;;71976:6;:16;;;72006:6;:19;;;72039:6;:17;;;72070:6;:19;;;71809:290;;;;;;;;;;;;:::i;:::-;;;;;;;;70943:1163;;70840:1266;;;:::o;72112:532::-;72222:36;72261:29;72282:7;72261:20;:29::i;:::-;72222:68;;72361:11;:24;;;72305:332;;72334:13;72305:332;72399:7;72420:11;:23;;;72457:11;:23;;;72494:11;:21;;;72529:11;:24;;;72567:11;:22;;;72603:11;:24;;;72305:332;;;;;;;;;;;;:::i;:::-;;;;;;;;72212:432;72112:532;;;:::o;57231:290::-;56661:26;46584:16;46595:4;46584:10;:16::i;:::-;56776:6:::1;57330:10;:26;;57322:55;;;::::0;::::1;::::0;;16599:2:1;57322:55:0::1;::::0;::::1;16581:21:1::0;16638:2;16618:18;;;16611:30;16677:18;16657;;;16650:46;16713:18;;57322:55:0::1;16397:340:1::0;57322:55:0::1;57408:15;::::0;;57433:28;;;;57476:38:::1;::::0;;16916:25:1;;;16972:2;16957:18;;16950:34;;;57476:38:0::1;::::0;16889:18:1;57476:38:0::1;;;;;;;;57312:209;57231:290:::0;;:::o;57892:264::-;56661:26;46584:16;46595:4;46584:10;:16::i;:::-;58017:14:::1;::::0;;58041:34;;;;58090:59:::1;::::0;;16916:25:1;;;16972:2;16957:18;;16950:34;;;58090:59:0::1;::::0;16889:18:1;58090:59:0::1;16742:248:1::0;72650:472:0;72971:144;;;17310:10:1;17298:23;;17280:42;;72971:144:0;17419:15:1;;;17414:2;17399:18;;17392:43;17471:15;;;17451:18;;;17444:43;17518:2;17503:18;;17496:34;;;17561:3;17546:19;;17539:35;;;17605:3;17590:19;;17583:35;;;72971:144:0;;;;;;;;;72998:13;;72971:144;;;;;17267:3:1;72971:144:0;;;72650:472;;;;;;;;;:::o;55432:131::-;55503:7;55529:18;;;:12;:18;;;;;:27;;:25;:27::i;48762:138::-;47995:7;48021:12;;;;;;;;;;:22;;;46584:16;46595:4;46584:10;:16::i;:::-;48867:26:::1;48879:4;48885:7;48867:11;:26::i;46685:202::-:0;46770:4;46793:47;;;46808:32;46793:47;;:87;;-1:-1:-1;38600:25:0;38585:40;;;;46844:36;38486:146;47319:103;47385:30;47396:4;22395:10;47385;:30::i;:::-;47319:103;:::o;51597:653::-;51772:4;51758:19;;;;51754:32;;51597:653;;;:::o;51754:32::-;51858:5;51867:1;51858:10;51854:23;;51597:653;;;:::o;51854:23::-;51890:20;;;;;51886:358;;52070:12;52087:2;:7;;52102:5;52087:25;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;52069:43;;;52134:7;52126:39;;;;;;;18041:2:1;52126:39:0;;;18023:21:1;18080:2;18060:18;;;18053:30;18119:21;18099:18;;;18092:49;18158:18;;52126:39:0;17839:343:1;51886:358:0;52196:37;:26;;;52223:2;52227:5;52196:26;:37::i;55665:257::-;55751:4;55767:12;55782:31;55799:4;55805:7;55782:16;:31::i;:::-;55767:46;;55827:7;55823:69;;;55850:18;;;;:12;:18;;;;;:31;;55873:7;55850:22;:31::i;:::-;;55908:7;55665:257;-1:-1:-1;;;55665:257:0:o;56025:262::-;56112:4;56128:12;56143:32;56161:4;56167:7;56143:17;:32::i;:::-;56128:47;;56189:7;56185:72;;;56212:18;;;;:12;:18;;;;;:34;;56238:7;56212:25;:34::i;33098:156::-;33172:7;33222:22;33226:3;33238:5;33222:3;:22::i;32641:115::-;32704:7;32730:19;32738:3;28080:18;;27998:107;47552:197;47051:4;47074:12;;;;;;;;;;;:29;;;;;;;;;;;;;47635:108;;47685:47;;;;;18391:42:1;18379:55;;47685:47:0;;;18361:74:1;18451:18;;;18444:34;;;18334:18;;47685:47:0;18187:297:1;47635:108:0;47552:197;;:::o;39802:160::-;39911:43;;;39926:14;18379:55:1;;39911:43:0;;;18361:74:1;18451:18;;;;18444:34;;;39911:43:0;;;;;;;;;;18334:18:1;;;;39911:43:0;;;;;;;;;;;;;;39884:71;;39904:5;;39884:19;:71::i;50299:316::-;50376:4;47074:12;;;;;;;;;;;:29;;;;;;;;;;;;;50392:217;;50435:6;:12;;;;;;;;;;;:29;;;;;;;;;;:36;;;;50467:4;50435:36;;;50517:12;22395:10;;22316:96;50517:12;50490:40;;50508:7;50490:40;;50502:4;50490:40;;;;;;;;;;-1:-1:-1;50551:4:0;50544:11;;50392:217;-1:-1:-1;50593:5:0;50586:12;;31840:150;31910:4;31933:50;31938:3;31958:23;;;31933:4;:50::i;50850:317::-;50928:4;47074:12;;;;;;;;;;;:29;;;;;;;;;;;;;50944:217;;;51018:5;50986:12;;;;;;;;;;;:29;;;;;;;;;;;:37;;;;;;51042:40;22395:10;;50986:12;;51042:40;;51018:5;51042:40;-1:-1:-1;51103:4:0;51096:11;;32158:156;32231:4;32254:53;32262:3;32282:23;;;32254:7;:53::i;28447:118::-;28514:7;28540:3;:11;;28552:5;28540:18;;;;;;;;:::i;:::-;;;;;;;;;28533:25;;28447:118;;;;:::o;42558:629::-;42977:23;43003:33;:27;;;43031:4;43003:27;:33::i;:::-;42977:59;;43050:10;:17;43071:1;43050:22;;:57;;;;;43088:10;43077:30;;;;;;;;;;;;:::i;:::-;43076:31;43050:57;43046:135;;;43130:40;;;;;8086:42:1;8074:55;;43130:40:0;;;8056:74:1;8029:18;;43130:40:0;7910:226:1;25765:406:0;25828:4;27884:21;;;:14;;;:21;;;;;;25844:321;;-1:-1:-1;25886:23:0;;;;;;;;:11;:23;;;;;;;;;;;;;26068:18;;26044:21;;;:14;;;:21;;;;;;:42;;;;26100:11;;26339:1368;26405:4;26534:21;;;:14;;;:21;;;;;;26570:13;;26566:1135;;26937:18;26958:12;26969:1;26958:8;:12;:::i;:::-;27004:18;;26937:33;;-1:-1:-1;26984:17:0;;27004:22;;27025:1;;27004:22;:::i;:::-;26984:42;;27059:9;27045:10;:23;27041:378;;27088:17;27108:3;:11;;27120:9;27108:22;;;;;;;;:::i;:::-;;;;;;;;;27088:42;;27255:9;27229:3;:11;;27241:10;27229:23;;;;;;;;:::i;:::-;;;;;;;;;;;;:35;;;;27368:25;;;:14;;;:25;;;;;:36;;;27041:378;27497:17;;:3;;:17;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;27600:3;:14;;:21;27615:5;27600:21;;;;;;;;;;;27593:28;;;27643:4;27636:11;;;;;;;26566:1135;27685:5;27678:12;;;;;18101:151;18176:12;18207:38;18229:6;18237:4;18243:1;18176:12;18817;18831:23;18858:6;:11;;18877:5;18884:4;18858:31;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;18816:73;;;;18906:55;18933:6;18941:7;18950:10;18906:26;:55::i;:::-;18899:62;18576:392;-1:-1:-1;;;;;;18576:392:0:o;20021:582::-;20165:12;20194:7;20189:408;;20217:19;20225:10;20217:7;:19::i;:::-;20189:408;;;20441:17;;:22;:49;;;;-1:-1:-1;20467:18:0;;;;:23;20441:49;20437:119;;;20517:24;;;;;8086:42:1;8074:55;;20517:24:0;;;8056:74:1;8029:18;;20517:24:0;7910:226:1;20437:119:0;-1:-1:-1;20576:10:0;20569:17;;21139:516;21270:17;;:21;21266:383;;21498:10;21492:17;21554:15;21541:10;21537:2;21533:19;21526:44;21266:383;21621:17;;;;;;;;;;;;;;14:332:1;72:6;125:2;113:9;104:7;100:23;96:32;93:52;;;141:1;138;131:12;93:52;180:9;167:23;230:66;223:5;219:78;212:5;209:89;199:117;;312:1;309;302:12;821:154;907:42;900:5;896:54;889:5;886:65;876:93;;965:1;962;955:12;980:134;1048:20;;1077:31;1048:20;1077:31;:::i;:::-;980:134;;;:::o;1119:388::-;1187:6;1195;1248:2;1236:9;1227:7;1223:23;1219:32;1216:52;;;1264:1;1261;1254:12;1216:52;1303:9;1290:23;1322:31;1347:5;1322:31;:::i;:::-;1372:5;-1:-1:-1;1429:2:1;1414:18;;1401:32;1442:33;1401:32;1442:33;:::i;:::-;1494:7;1484:17;;;1119:388;;;;;:::o;1694:180::-;1753:6;1806:2;1794:9;1785:7;1781:23;1777:32;1774:52;;;1822:1;1819;1812:12;1774:52;-1:-1:-1;1845:23:1;;1694:180;-1:-1:-1;1694:180:1:o;1879:315::-;1947:6;1955;2008:2;1996:9;1987:7;1983:23;1979:32;1976:52;;;2024:1;2021;2014:12;1976:52;2060:9;2047:23;2037:33;;2120:2;2109:9;2105:18;2092:32;2133:31;2158:5;2133:31;:::i;2199:184::-;2251:77;2248:1;2241:88;2348:4;2345:1;2338:15;2372:4;2369:1;2362:15;2388:255;2460:2;2454:9;2502:6;2490:19;;2539:18;2524:34;;2560:22;;;2521:62;2518:88;;;2586:18;;:::i;:::-;2622:2;2615:22;2388:255;:::o;2648:247::-;2715:2;2709:9;2757:3;2745:16;;2791:18;2776:34;;2812:22;;;2773:62;2770:88;;;2838:18;;:::i;2900:777::-;2942:5;2995:3;2988:4;2980:6;2976:17;2972:27;2962:55;;3013:1;3010;3003:12;2962:55;3049:6;3036:20;3075:18;3112:2;3108;3105:10;3102:36;;;3118:18;;:::i;:::-;3252:2;3246:9;3314:4;3306:13;;3157:66;3302:22;;;3326:2;3298:31;3294:40;3282:53;;;3350:18;;;3370:22;;;3347:46;3344:72;;;3396:18;;:::i;:::-;3436:10;3432:2;3425:22;3471:2;3463:6;3456:18;3517:3;3510:4;3505:2;3497:6;3493:15;3489:26;3486:35;3483:55;;;3534:1;3531;3524:12;3483:55;3598:2;3591:4;3583:6;3579:17;3572:4;3564:6;3560:17;3547:54;3645:1;3638:4;3633:2;3625:6;3621:15;3617:26;3610:37;3665:6;3656:15;;;;;;2900:777;;;;:::o;3682:455::-;3759:6;3767;3820:2;3808:9;3799:7;3795:23;3791:32;3788:52;;;3836:1;3833;3826:12;3788:52;3876:9;3863:23;3909:18;3901:6;3898:30;3895:50;;;3941:1;3938;3931:12;3895:50;3964:49;4005:7;3996:6;3985:9;3981:22;3964:49;:::i;:::-;3954:59;;;4063:2;4052:9;4048:18;4035:32;4076:31;4101:5;4076:31;:::i;4142:121::-;4227:10;4220:5;4216:22;4209:5;4206:33;4196:61;;4253:1;4250;4243:12;4268:132;4335:20;;4364:30;4335:20;4364:30;:::i;4405:118::-;4491:5;4484:13;4477:21;4470:5;4467:32;4457:60;;4513:1;4510;4503:12;4528:128;4593:20;;4622:28;4593:20;4622:28;:::i;4661:806::-;4720:5;4768:6;4756:9;4751:3;4747:19;4743:32;4740:52;;;4788:1;4785;4778:12;4740:52;4810:22;;:::i;:::-;4801:31;;4855:28;4873:9;4855:28;:::i;:::-;4848:5;4841:43;4916:38;4950:2;4939:9;4935:18;4916:38;:::i;:::-;4911:2;4904:5;4900:14;4893:62;4987:38;5021:2;5010:9;5006:18;4987:38;:::i;:::-;4982:2;4975:5;4971:14;4964:62;5058:38;5092:2;5081:9;5077:18;5058:38;:::i;:::-;5053:2;5046:5;5042:14;5035:62;5130:39;5164:3;5153:9;5149:19;5130:39;:::i;:::-;5124:3;5117:5;5113:15;5106:64;5231:3;5220:9;5216:19;5203:33;5197:3;5190:5;5186:15;5179:58;5298:3;5287:9;5283:19;5270:33;5264:3;5257:5;5253:15;5246:58;5337:36;5368:3;5357:9;5353:19;5337:36;:::i;:::-;5331:3;5324:5;5320:15;5313:61;5393:3;5456:2;5445:9;5441:18;5428:32;5423:2;5416:5;5412:14;5405:56;;4661:806;;;;:::o;5472:237::-;5560:6;5613:3;5601:9;5592:7;5588:23;5584:33;5581:53;;;5630:1;5627;5620:12;5581:53;5653:50;5695:7;5684:9;5653:50;:::i;5714:320::-;5782:6;5835:2;5823:9;5814:7;5810:23;5806:32;5803:52;;;5851:1;5848;5841:12;5803:52;5891:9;5878:23;5924:18;5916:6;5913:30;5910:50;;;5956:1;5953;5946:12;5910:50;5979:49;6020:7;6011:6;6000:9;5996:22;5979:49;:::i;:::-;5969:59;5714:320;-1:-1:-1;;;;5714:320:1:o;6039:273::-;6115:6;6168:2;6156:9;6147:7;6143:23;6139:32;6136:52;;;6184:1;6181;6174:12;6136:52;6223:9;6210:23;6262:1;6255:5;6252:12;6242:40;;6278:1;6275;6268:12;6317:250;6402:1;6412:113;6426:6;6423:1;6420:13;6412:113;;;6502:11;;;6496:18;6483:11;;;6476:39;6448:2;6441:10;6412:113;;;-1:-1:-1;;6559:1:1;6541:16;;6534:27;6317:250::o;6572:330::-;6614:3;6652:5;6646:12;6679:6;6674:3;6667:19;6695:76;6764:6;6757:4;6752:3;6748:14;6741:4;6734:5;6730:16;6695:76;:::i;:::-;6816:2;6804:15;6821:66;6800:88;6791:98;;;;6891:4;6787:109;;6572:330;-1:-1:-1;;6572:330:1:o;6907:220::-;7056:2;7045:9;7038:21;7019:4;7076:45;7117:2;7106:9;7102:18;7094:6;7076:45;:::i;7132:388::-;7209:6;7217;7270:2;7258:9;7249:7;7245:23;7241:32;7238:52;;;7286:1;7283;7276:12;7238:52;7326:9;7313:23;7359:18;7351:6;7348:30;7345:50;;;7391:1;7388;7381:12;7345:50;7414:49;7455:7;7446:6;7435:9;7431:22;7414:49;:::i;:::-;7404:59;7510:2;7495:18;;;;7482:32;;-1:-1:-1;;;;7132:388:1:o;7525:248::-;7593:6;7601;7654:2;7642:9;7633:7;7629:23;7625:32;7622:52;;;7670:1;7667;7660:12;7622:52;-1:-1:-1;;7693:23:1;;;7763:2;7748:18;;;7735:32;;-1:-1:-1;7525:248:1:o;8240:1373::-;8471:13;;8217:10;8206:22;8194:35;;8440:3;8425:19;;8543:4;8535:6;8531:17;8525:24;8558:53;8605:4;8594:9;8590:20;8576:12;8217:10;8206:22;8194:35;;8141:94;8558:53;;8660:4;8652:6;8648:17;8642:24;8675:56;8725:4;8714:9;8710:20;8694:14;7855:42;7844:54;7832:67;;7778:127;8675:56;;8780:4;8772:6;8768:17;8762:24;8795:56;8845:4;8834:9;8830:20;8814:14;7855:42;7844:54;7832:67;;7778:127;8795:56;;8900:4;8892:6;8888:17;8882:24;8915:56;8965:4;8954:9;8950:20;8934:14;7855:42;7844:54;7832:67;;7778:127;8915:56;;9020:4;9012:6;9008:17;9002:24;9035:56;9085:4;9074:9;9070:20;9054:14;7855:42;7844:54;7832:67;;7778:127;9035:56;;9147:4;9139:6;9135:17;9129:24;9122:4;9111:9;9107:20;9100:54;9210:4;9202:6;9198:17;9192:24;9185:4;9174:9;9170:20;9163:54;9236:6;9296:2;9288:6;9284:15;9278:22;9273:2;9262:9;9258:18;9251:50;;9320:6;9375:2;9367:6;9363:15;9357:22;9388:51;9435:2;9424:9;9420:18;9404:14;421:13;414:21;402:34;;351:91;9388:51;-1:-1:-1;;9458:6:1;9506:15;;;9500:22;9480:18;;;9473:50;9542:6;9590:15;;;9584:22;9564:18;;;;9557:50;;;;8240:1373;:::o;9618:440::-;9724:6;9732;9740;9793:3;9781:9;9772:7;9768:23;9764:33;9761:53;;;9810:1;9807;9800:12;9761:53;9846:9;9833:23;9823:33;;9906:2;9895:9;9891:18;9878:32;9919:31;9944:5;9919:31;:::i;:::-;9969:5;-1:-1:-1;9993:59:1;10044:7;10039:2;10024:18;;9993:59;:::i;:::-;9983:69;;9618:440;;;;;:::o;10063:523::-;10149:6;10157;10165;10218:2;10206:9;10197:7;10193:23;10189:32;10186:52;;;10234:1;10231;10224:12;10186:52;10270:9;10257:23;10247:33;;10330:2;10319:9;10315:18;10302:32;10343:31;10368:5;10343:31;:::i;:::-;10393:5;-1:-1:-1;10449:2:1;10434:18;;10421:32;10476:18;10465:30;;10462:50;;;10508:1;10505;10498:12;10462:50;10531:49;10572:7;10563:6;10552:9;10548:22;10531:49;:::i;:::-;10521:59;;;10063:523;;;;;:::o;10776:1087::-;10906:6;10914;10922;10930;10938;10946;10954;10962;10970;11023:3;11011:9;11002:7;10998:23;10994:33;10991:53;;;11040:1;11037;11030:12;10991:53;11076:9;11063:23;11053:33;;11136:2;11125:9;11121:18;11108:32;11149:31;11174:5;11149:31;:::i;:::-;11199:5;-1:-1:-1;11256:2:1;11241:18;;11228:32;11269:33;11228:32;11269:33;:::i;:::-;11321:7;-1:-1:-1;11380:2:1;11365:18;;11352:32;11393;11352;11393;:::i;:::-;11444:7;-1:-1:-1;11503:3:1;11488:19;;11475:33;11517;11475;11517;:::i;:::-;11569:7;-1:-1:-1;11628:3:1;11613:19;;11600:33;11642;11600;11642;:::i;:::-;11694:7;11684:17;;;11748:3;11737:9;11733:19;11720:33;11710:43;;11800:3;11789:9;11785:19;11772:33;11762:43;;11852:3;11841:9;11837:19;11824:33;11814:43;;10776:1087;;;;;;;;;;;:::o;11868:247::-;11927:6;11980:2;11968:9;11959:7;11955:23;11951:32;11948:52;;;11996:1;11993;11986:12;11948:52;12035:9;12022:23;12054:31;12079:5;12054:31;:::i;12867:184::-;12919:77;12916:1;12909:88;13016:4;13013:1;13006:15;13040:4;13037:1;13030:15;13056:136;13134:13;;13156:30;13134:13;13156:30;:::i;13197:138::-;13276:13;;13298:31;13276:13;13298:31;:::i;13340:132::-;13416:13;;13438:28;13416:13;13438:28;:::i;13477:1183::-;13580:6;13633:3;13621:9;13612:7;13608:23;13604:33;13601:53;;;13650:1;13647;13640:12;13601:53;13676:17;;:::i;:::-;13716:39;13745:9;13716:39;:::i;:::-;13709:5;13702:54;13788:48;13832:2;13821:9;13817:18;13788:48;:::i;:::-;13783:2;13776:5;13772:14;13765:72;13869:49;13914:2;13903:9;13899:18;13869:49;:::i;:::-;13864:2;13857:5;13853:14;13846:73;13951:49;13996:2;13985:9;13981:18;13951:49;:::i;:::-;13946:2;13939:5;13935:14;13928:73;14034:50;14079:3;14068:9;14064:19;14034:50;:::i;:::-;14028:3;14021:5;14017:15;14010:75;14118:50;14163:3;14152:9;14148:19;14118:50;:::i;:::-;14112:3;14105:5;14101:15;14094:75;14223:3;14212:9;14208:19;14202:26;14196:3;14189:5;14185:15;14178:51;14283:3;14272:9;14268:19;14262:26;14256:3;14249:5;14245:15;14238:51;14308:3;14364:2;14353:9;14349:18;14343:25;14338:2;14331:5;14327:14;14320:49;;14388:3;14423:46;14465:2;14454:9;14450:18;14423:46;:::i;:::-;14407:14;;;14400:70;14489:3;14530:18;;;14524:25;14508:14;;;14501:49;14569:3;14610:18;;;14604:25;14588:14;;;14581:49;;;;-1:-1:-1;14411:5:1;13477:1183;-1:-1:-1;13477:1183:1:o;14665:184::-;14717:77;14714:1;14707:88;14814:4;14811:1;14804:15;14838:4;14835:1;14828:15;14854:168;14927:9;;;14958;;14975:15;;;14969:22;;14955:37;14945:71;;14996:18;;:::i;15027:274::-;15067:1;15093;15083:189;;15128:77;15125:1;15118:88;15229:4;15226:1;15219:15;15257:4;15254:1;15247:15;15083:189;-1:-1:-1;15286:9:1;;15027:274::o;15306:128::-;15373:9;;;15394:11;;;15391:37;;;15408:18;;:::i;15439:195::-;15478:3;15509:66;15502:5;15499:77;15496:103;;15579:18;;:::i;:::-;-1:-1:-1;15626:1:1;15615:13;;15439:195::o;15639:753::-;15946:3;15935:9;15928:22;15909:4;15967:46;16008:3;15997:9;15993:19;15985:6;15967:46;:::i;:::-;16061:10;16049:23;;;;16044:2;16029:18;;16022:51;-1:-1:-1;16092:42:1;16170:15;;;16165:2;16150:18;;16143:43;16222:15;;;;16217:2;16202:18;;16195:43;16269:3;16254:19;;16247:35;;;;16313:3;16298:19;;16291:35;16370:14;;16363:22;16357:3;16342:19;;;16335:51;15959:54;15639:753;-1:-1:-1;15639:753:1:o;18791:184::-;18843:77;18840:1;18833:88;18940:4;18937:1;18930:15;18964:4;18961:1;18954:15;18980:245;19047:6;19100:2;19088:9;19079:7;19075:23;19071:32;19068:52;;;19116:1;19113;19106:12;19068:52;19148:9;19142:16;19167:28;19189:5;19167:28;:::i;19230:184::-;19282:77;19279:1;19272:88;19379:4;19376:1;19369:15;19403:4;19400:1;19393:15;19419:287;19548:3;19586:6;19580:13;19602:66;19661:6;19656:3;19649:4;19641:6;19637:17;19602:66;:::i;:::-;19684:16;;;;;19419:287;-1:-1:-1;;19419:287:1:o","abiDefinition":[{"inputs":[{"internalType":"address","name":"_owner","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AccessControlBadConfirmation","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"bytes32","name":"neededRole","type":"bytes32"}],"name":"AccessControlUnauthorizedAccount","type":"error"},{"inputs":[{"internalType":"address","name":"target","type":"address"}],"name":"AddressEmptyCode","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"AddressInsufficientBalance","type":"error"},{"inputs":[],"name":"FailedInnerCall","type":"error"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"SafeERC20FailedOperation","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"relayer","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"BridgeDepositClaimed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"BridgeDepositRefunded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"relayer","type":"address"}],"name":"BridgeProofDisputed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"relayer","type":"address"},{"indexed":false,"internalType":"bytes32","name":"transactionHash","type":"bytes32"}],"name":"BridgeProofProvided","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"relayer","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint32","name":"originChainId","type":"uint32"},{"indexed":false,"internalType":"address","name":"originToken","type":"address"},{"indexed":false,"internalType":"address","name":"destToken","type":"address"},{"indexed":false,"internalType":"uint256","name":"originAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"destAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"chainGasAmount","type":"uint256"}],"name":"BridgeRelayed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"bytes","name":"request","type":"bytes"},{"indexed":false,"internalType":"uint32","name":"destChainId","type":"uint32"},{"indexed":false,"internalType":"address","name":"originToken","type":"address"},{"indexed":false,"internalType":"address","name":"destToken","type":"address"},{"indexed":false,"internalType":"uint256","name":"originAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"destAmount","type":"uint256"},{"indexed":false,"internalType":"bool","name":"sendChainGas","type":"bool"}],"name":"BridgeRequested","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldChainGasAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newChainGasAmount","type":"uint256"}],"name":"ChainGasAmountUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldFeeRate","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newFeeRate","type":"uint256"}],"name":"FeeRateUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"address","name":"recipient","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"FeesSwept","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"previousAdminRole","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"newAdminRole","type":"bytes32"}],"name":"RoleAdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleRevoked","type":"event"},{"inputs":[],"name":"DEFAULT_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"FEE_BPS","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"FEE_RATE_MAX","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"GOVERNOR_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"GUARD_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"REFUNDER_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"RELAYER_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"uint32","name":"dstChainId","type":"uint32"},{"internalType":"address","name":"sender","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"address","name":"originToken","type":"address"},{"internalType":"address","name":"destToken","type":"address"},{"internalType":"uint256","name":"originAmount","type":"uint256"},{"internalType":"uint256","name":"destAmount","type":"uint256"},{"internalType":"bool","name":"sendChainGas","type":"bool"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"internalType":"struct IFastBridge.BridgeParams","name":"params","type":"tuple"}],"name":"bridge","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"transactionid","type":"bytes32"},{"internalType":"address","name":"relayer","type":"address"}],"name":"canClaim","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"chainGasAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"},{"internalType":"address","name":"to","type":"address"}],"name":"claim","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"deployBlock","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"transactionId","type":"bytes32"}],"name":"dispute","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"}],"name":"getBridgeTransaction","outputs":[{"components":[{"internalType":"uint32","name":"originChainId","type":"uint32"},{"internalType":"uint32","name":"destChainId","type":"uint32"},{"internalType":"address","name":"originSender","type":"address"},{"internalType":"address","name":"destRecipient","type":"address"},{"internalType":"address","name":"originToken","type":"address"},{"internalType":"address","name":"destToken","type":"address"},{"internalType":"uint256","name":"originAmount","type":"uint256"},{"internalType":"uint256","name":"destAmount","type":"uint256"},{"internalType":"uint256","name":"originFeeAmount","type":"uint256"},{"internalType":"bool","name":"sendChainGas","type":"bool"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint256","name":"nonce","type":"uint256"}],"internalType":"struct IFastBridge.BridgeTransaction","name":"","type":"tuple"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"enum FastBridge.BridgeStatus","name":"keyValue","type":"uint8"}],"name":"getEnumKeyByValue","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleAdmin","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"uint256","name":"index","type":"uint256"}],"name":"getRoleMember","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleMemberCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"grantRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"hasRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"internalType":"address","name":"relayer","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint32","name":"originChainId","type":"uint32"},{"internalType":"address","name":"originToken","type":"address"},{"internalType":"address","name":"destToken","type":"address"},{"internalType":"uint256","name":"originAmount","type":"uint256"},{"internalType":"uint256","name":"destAmount","type":"uint256"},{"internalType":"uint256","name":"chainGasAmount","type":"uint256"}],"name":"mockBridgeRelayer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"internalType":"address","name":"sender","type":"address"},{"components":[{"internalType":"uint32","name":"dstChainId","type":"uint32"},{"internalType":"address","name":"sender","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"address","name":"originToken","type":"address"},{"internalType":"address","name":"destToken","type":"address"},{"internalType":"uint256","name":"originAmount","type":"uint256"},{"internalType":"uint256","name":"destAmount","type":"uint256"},{"internalType":"bool","name":"sendChainGas","type":"bool"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"internalType":"struct IFastBridge.BridgeParams","name":"params","type":"tuple"}],"name":"mockBridgeRequest","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"internalType":"address","name":"sender","type":"address"},{"internalType":"bytes","name":"request","type":"bytes"}],"name":"mockBridgeRequestRaw","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"nonce","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"protocolFeeRate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"protocolFees","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"},{"internalType":"bytes32","name":"destTxHash","type":"bytes32"}],"name":"prove","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"}],"name":"refund","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"}],"name":"relay","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"callerConfirmation","type":"address"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"revokeRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"newChainGasAmount","type":"uint256"}],"name":"setChainGasAmount","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"newFeeRate","type":"uint256"}],"name":"setProtocolFeeRate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"address","name":"recipient","type":"address"}],"name":"sweepProtocolFees","outputs":[],"stateMutability":"nonpayable","type":"function"}],"userDoc":{"kind":"user","methods":{"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256))":{"notice":"Initiates bridge on origin chain to be relayed by off-chain relayer"},"chainGasAmount()":{"notice":"Chain gas amount to forward as rebate if requested"},"claim(bytes,address)":{"notice":"Completes bridge transaction on origin chain by claiming originally deposited capital"},"dispute(bytes32)":{"notice":"Disputes an outstanding proof in case relayer provided dest chain tx is invalid"},"getBridgeTransaction(bytes)":{"notice":"Decodes bridge request into a bridge transaction"},"protocolFeeRate()":{"notice":"Protocol fee rate taken on origin amount deposited in origin chain"},"protocolFees(address)":{"notice":"Protocol fee amounts accumulated"},"prove(bytes,bytes32)":{"notice":"Provides proof on origin side that relayer provided funds on destination side of bridge transaction"},"refund(bytes)":{"notice":"Refunds an outstanding bridge transaction in case optimistic bridging failed"},"relay(bytes)":{"notice":"Relays destination side of bridge transaction by off-chain relayer"}},"version":1},"developerDoc":{"errors":{"AccessControlBadConfirmation()":[{"details":"The caller of a function is not the expected one. NOTE: Don't confuse with {AccessControlUnauthorizedAccount}."}],"AccessControlUnauthorizedAccount(address,bytes32)":[{"details":"The `account` is missing a role."}],"AddressEmptyCode(address)":[{"details":"There's no code at `target` (it is not a contract)."}],"AddressInsufficientBalance(address)":[{"details":"The ETH balance of the account is not enough to perform the operation."}],"FailedInnerCall()":[{"details":"A call to an address target failed. The target may have reverted."}],"SafeERC20FailedOperation(address)":[{"details":"An operation with an ERC20 token failed."}]},"events":{"RoleAdminChanged(bytes32,bytes32,bytes32)":{"details":"Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole` `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite {RoleAdminChanged} not being emitted signaling this."},"RoleGranted(bytes32,address,address)":{"details":"Emitted when `account` is granted `role`. `sender` is the account that originated the contract call, an admin role bearer except when using {AccessControl-_setupRole}."},"RoleRevoked(bytes32,address,address)":{"details":"Emitted when `account` is revoked `role`. `sender` is the account that originated the contract call: - if using `revokeRole`, it is the admin role bearer - if using `renounceRole`, it is the role bearer (i.e. `account`)"}},"kind":"dev","methods":{"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256))":{"params":{"params":"The parameters required to bridge"}},"claim(bytes,address)":{"params":{"request":"The encoded bridge transaction to claim on origin chain","to":"The recipient address of the funds"}},"dispute(bytes32)":{"params":{"transactionId":"The transaction id associated with the encoded bridge transaction to dispute"}},"getBridgeTransaction(bytes)":{"params":{"request":"The bridge request to decode"}},"getRoleAdmin(bytes32)":{"details":"Returns the admin role that controls `role`. See {grantRole} and {revokeRole}. To change a role's admin, use {_setRoleAdmin}."},"getRoleMember(bytes32,uint256)":{"details":"Returns one of the accounts that have `role`. `index` must be a value between 0 and {getRoleMemberCount}, non-inclusive. Role bearers are not sorted in any particular way, and their ordering may change at any point. WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure you perform all queries on the same block. See the following https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post] for more information."},"getRoleMemberCount(bytes32)":{"details":"Returns the number of accounts that have `role`. Can be used together with {getRoleMember} to enumerate all bearers of a role."},"grantRole(bytes32,address)":{"details":"Grants `role` to `account`. If `account` had not been already granted `role`, emits a {RoleGranted} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleGranted} event."},"hasRole(bytes32,address)":{"details":"Returns `true` if `account` has been granted `role`."},"prove(bytes,bytes32)":{"params":{"destTxHash":"The destination tx hash proving bridge transaction was relayed","request":"The encoded bridge transaction to prove on origin chain"}},"refund(bytes)":{"params":{"request":"The encoded bridge transaction to refund"}},"relay(bytes)":{"params":{"request":"The encoded bridge transaction to relay on destination chain"}},"renounceRole(bytes32,address)":{"details":"Revokes `role` from the calling account. Roles are often managed via {grantRole} and {revokeRole}: this function's purpose is to provide a mechanism for accounts to lose their privileges if they are compromised (such as when a trusted device is misplaced). If the calling account had been revoked `role`, emits a {RoleRevoked} event. Requirements: - the caller must be `callerConfirmation`. May emit a {RoleRevoked} event."},"revokeRole(bytes32,address)":{"details":"Revokes `role` from `account`. If `account` had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleRevoked} event."},"supportsInterface(bytes4)":{"details":"See {IERC165-supportsInterface}."}},"stateVariables":{"nonce":{"details":"to prevent replays"}},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.20+commit.a1b79de6\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_owner\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"AccessControlBadConfirmation\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"neededRole\",\"type\":\"bytes32\"}],\"name\":\"AccessControlUnauthorizedAccount\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"}],\"name\":\"AddressEmptyCode\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"AddressInsufficientBalance\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"FailedInnerCall\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"}],\"name\":\"SafeERC20FailedOperation\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"BridgeDepositClaimed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"BridgeDepositRefunded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"name\":\"BridgeProofDisputed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"transactionHash\",\"type\":\"bytes32\"}],\"name\":\"BridgeProofProvided\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"originChainId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"chainGasAmount\",\"type\":\"uint256\"}],\"name\":\"BridgeRelayed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"destChainId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"sendChainGas\",\"type\":\"bool\"}],\"name\":\"BridgeRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"oldChainGasAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newChainGasAmount\",\"type\":\"uint256\"}],\"name\":\"ChainGasAmountUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"oldFeeRate\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newFeeRate\",\"type\":\"uint256\"}],\"name\":\"FeeRateUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"FeesSwept\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"previousAdminRole\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"newAdminRole\",\"type\":\"bytes32\"}],\"name\":\"RoleAdminChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleGranted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleRevoked\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"DEFAULT_ADMIN_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"FEE_BPS\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"FEE_RATE_MAX\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"GOVERNOR_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"GUARD_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"REFUNDER_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"RELAYER_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"dstChainId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"sendChainGas\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"}],\"internalType\":\"struct IFastBridge.BridgeParams\",\"name\":\"params\",\"type\":\"tuple\"}],\"name\":\"bridge\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionid\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"name\":\"canClaim\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"chainGasAmount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"claim\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"deployBlock\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"}],\"name\":\"dispute\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"getBridgeTransaction\",\"outputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"originChainId\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"destChainId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"originSender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destRecipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"originFeeAmount\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"sendChainGas\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"}],\"internalType\":\"struct IFastBridge.BridgeTransaction\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"enum FastBridge.BridgeStatus\",\"name\":\"keyValue\",\"type\":\"uint8\"}],\"name\":\"getEnumKeyByValue\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"}],\"name\":\"getRoleAdmin\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"index\",\"type\":\"uint256\"}],\"name\":\"getRoleMember\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"}],\"name\":\"getRoleMemberCount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"grantRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"hasRole\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"uint32\",\"name\":\"originChainId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"chainGasAmount\",\"type\":\"uint256\"}],\"name\":\"mockBridgeRelayer\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"components\":[{\"internalType\":\"uint32\",\"name\":\"dstChainId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"sendChainGas\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"}],\"internalType\":\"struct IFastBridge.BridgeParams\",\"name\":\"params\",\"type\":\"tuple\"}],\"name\":\"mockBridgeRequest\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"mockBridgeRequestRaw\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"nonce\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"protocolFeeRate\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"protocolFees\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"},{\"internalType\":\"bytes32\",\"name\":\"destTxHash\",\"type\":\"bytes32\"}],\"name\":\"prove\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"refund\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"relay\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"callerConfirmation\",\"type\":\"address\"}],\"name\":\"renounceRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"revokeRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"newChainGasAmount\",\"type\":\"uint256\"}],\"name\":\"setChainGasAmount\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"newFeeRate\",\"type\":\"uint256\"}],\"name\":\"setProtocolFeeRate\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes4\",\"name\":\"interfaceId\",\"type\":\"bytes4\"}],\"name\":\"supportsInterface\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"}],\"name\":\"sweepProtocolFees\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"errors\":{\"AccessControlBadConfirmation()\":[{\"details\":\"The caller of a function is not the expected one. NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\"}],\"AccessControlUnauthorizedAccount(address,bytes32)\":[{\"details\":\"The `account` is missing a role.\"}],\"AddressEmptyCode(address)\":[{\"details\":\"There's no code at `target` (it is not a contract).\"}],\"AddressInsufficientBalance(address)\":[{\"details\":\"The ETH balance of the account is not enough to perform the operation.\"}],\"FailedInnerCall()\":[{\"details\":\"A call to an address target failed. The target may have reverted.\"}],\"SafeERC20FailedOperation(address)\":[{\"details\":\"An operation with an ERC20 token failed.\"}]},\"events\":{\"RoleAdminChanged(bytes32,bytes32,bytes32)\":{\"details\":\"Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole` `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite {RoleAdminChanged} not being emitted signaling this.\"},\"RoleGranted(bytes32,address,address)\":{\"details\":\"Emitted when `account` is granted `role`. `sender` is the account that originated the contract call, an admin role bearer except when using {AccessControl-_setupRole}.\"},\"RoleRevoked(bytes32,address,address)\":{\"details\":\"Emitted when `account` is revoked `role`. `sender` is the account that originated the contract call: - if using `revokeRole`, it is the admin role bearer - if using `renounceRole`, it is the role bearer (i.e. `account`)\"}},\"kind\":\"dev\",\"methods\":{\"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256))\":{\"params\":{\"params\":\"The parameters required to bridge\"}},\"claim(bytes,address)\":{\"params\":{\"request\":\"The encoded bridge transaction to claim on origin chain\",\"to\":\"The recipient address of the funds\"}},\"dispute(bytes32)\":{\"params\":{\"transactionId\":\"The transaction id associated with the encoded bridge transaction to dispute\"}},\"getBridgeTransaction(bytes)\":{\"params\":{\"request\":\"The bridge request to decode\"}},\"getRoleAdmin(bytes32)\":{\"details\":\"Returns the admin role that controls `role`. See {grantRole} and {revokeRole}. To change a role's admin, use {_setRoleAdmin}.\"},\"getRoleMember(bytes32,uint256)\":{\"details\":\"Returns one of the accounts that have `role`. `index` must be a value between 0 and {getRoleMemberCount}, non-inclusive. Role bearers are not sorted in any particular way, and their ordering may change at any point. WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure you perform all queries on the same block. See the following https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post] for more information.\"},\"getRoleMemberCount(bytes32)\":{\"details\":\"Returns the number of accounts that have `role`. Can be used together with {getRoleMember} to enumerate all bearers of a role.\"},\"grantRole(bytes32,address)\":{\"details\":\"Grants `role` to `account`. If `account` had not been already granted `role`, emits a {RoleGranted} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleGranted} event.\"},\"hasRole(bytes32,address)\":{\"details\":\"Returns `true` if `account` has been granted `role`.\"},\"prove(bytes,bytes32)\":{\"params\":{\"destTxHash\":\"The destination tx hash proving bridge transaction was relayed\",\"request\":\"The encoded bridge transaction to prove on origin chain\"}},\"refund(bytes)\":{\"params\":{\"request\":\"The encoded bridge transaction to refund\"}},\"relay(bytes)\":{\"params\":{\"request\":\"The encoded bridge transaction to relay on destination chain\"}},\"renounceRole(bytes32,address)\":{\"details\":\"Revokes `role` from the calling account. Roles are often managed via {grantRole} and {revokeRole}: this function's purpose is to provide a mechanism for accounts to lose their privileges if they are compromised (such as when a trusted device is misplaced). If the calling account had been revoked `role`, emits a {RoleRevoked} event. Requirements: - the caller must be `callerConfirmation`. May emit a {RoleRevoked} event.\"},\"revokeRole(bytes32,address)\":{\"details\":\"Revokes `role` from `account`. If `account` had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleRevoked} event.\"},\"supportsInterface(bytes4)\":{\"details\":\"See {IERC165-supportsInterface}.\"}},\"stateVariables\":{\"nonce\":{\"details\":\"to prevent replays\"}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256))\":{\"notice\":\"Initiates bridge on origin chain to be relayed by off-chain relayer\"},\"chainGasAmount()\":{\"notice\":\"Chain gas amount to forward as rebate if requested\"},\"claim(bytes,address)\":{\"notice\":\"Completes bridge transaction on origin chain by claiming originally deposited capital\"},\"dispute(bytes32)\":{\"notice\":\"Disputes an outstanding proof in case relayer provided dest chain tx is invalid\"},\"getBridgeTransaction(bytes)\":{\"notice\":\"Decodes bridge request into a bridge transaction\"},\"protocolFeeRate()\":{\"notice\":\"Protocol fee rate taken on origin amount deposited in origin chain\"},\"protocolFees(address)\":{\"notice\":\"Protocol fee amounts accumulated\"},\"prove(bytes,bytes32)\":{\"notice\":\"Provides proof on origin side that relayer provided funds on destination side of bridge transaction\"},\"refund(bytes)\":{\"notice\":\"Refunds an outstanding bridge transaction in case optimistic bridging failed\"},\"relay(bytes)\":{\"notice\":\"Relays destination side of bridge transaction by off-chain relayer\"}},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeMock.sol\":\"FastBridgeMock\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeMock.sol\":{\"keccak256\":\"0x620e81214ecd324ae8b971219291f176c454ce76fb1c01d656428096da8f1366\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://18e556772c12e13aa2d52a50cc7c48e676c8d5af22b90adaf7befb39cdd08e64\",\"dweb:/ipfs/QmPrQc98TxHCFMeuFNADyjr6Nqo52rHhHy1LBcsVdMRXjL\"]}},\"version\":1}"},"hashes":{"DEFAULT_ADMIN_ROLE()":"a217fddf","FEE_BPS()":"bf333f2c","FEE_RATE_MAX()":"0f5f6ed7","GOVERNOR_ROLE()":"ccc57490","GUARD_ROLE()":"03ed0ee5","REFUNDER_ROLE()":"5960ccf2","RELAYER_ROLE()":"926d7d7f","bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256))":"45851694","canClaim(bytes32,address)":"aa9641ab","chainGasAmount()":"e00a83e0","claim(bytes,address)":"41fcb612","deployBlock()":"a3ec191a","dispute(bytes32)":"add98c70","getBridgeTransaction(bytes)":"ac11fb1a","getEnumKeyByValue(uint8)":"85ad903d","getRoleAdmin(bytes32)":"248a9ca3","getRoleMember(bytes32,uint256)":"9010d07c","getRoleMemberCount(bytes32)":"ca15c873","grantRole(bytes32,address)":"2f2ff15d","hasRole(bytes32,address)":"91d14854","mockBridgeRelayer(bytes32,address,address,uint32,address,address,uint256,uint256,uint256)":"c72870cc","mockBridgeRequest(bytes32,address,(uint32,address,address,address,address,uint256,uint256,bool,uint256))":"acaebbf1","mockBridgeRequestRaw(bytes32,address,bytes)":"aedf009d","nonce()":"affed0e0","protocolFeeRate()":"58f85880","protocolFees(address)":"dcf844a7","prove(bytes,bytes32)":"886d36ff","refund(bytes)":"5eb7d946","relay(bytes)":"8f0d6f17","renounceRole(bytes32,address)":"36568abe","revokeRole(bytes32,address)":"d547741f","setChainGasAmount(uint256)":"b250fe6b","setProtocolFeeRate(uint256)":"b13aa2d6","supportsInterface(bytes4)":"01ffc9a7","sweepProtocolFees(address,address)":"06f333f2"}},"solidity/FastBridgeMock.sol:IAccessControl":{"code":"0x","runtime-code":"0x","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.20 ^0.8.20;\n\n// contracts/interfaces/IAdmin.sol\n\ninterface IAdmin {\n // ============ Events ============\n\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n event ChainGasAmountUpdated(uint256 oldChainGasAmount, uint256 newChainGasAmount);\n\n // ============ Methods ============\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n\n function setChainGasAmount(uint256 newChainGasAmount) external;\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/libs/Errors.sol\n\nerror DeadlineExceeded();\nerror DeadlineNotExceeded();\nerror DeadlineTooShort();\nerror InsufficientOutputAmount();\n\nerror MsgValueIncorrect();\nerror PoolNotFound();\nerror TokenAddressMismatch();\nerror TokenNotContract();\nerror TokenNotETH();\nerror TokensIdentical();\n\nerror ChainIncorrect();\nerror AmountIncorrect();\nerror ZeroAddress();\n\nerror DisputePeriodNotPassed();\nerror DisputePeriodPassed();\nerror SenderIncorrect();\nerror StatusIncorrect();\nerror TransactionIdIncorrect();\nerror TransactionRelayed();\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// contracts/libs/UniversalToken.sol\n\nlibrary UniversalTokenLib {\n using SafeERC20 for IERC20;\n\n address internal constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Transfers tokens to the given account. Reverts if transfer is not successful.\n /// @dev This might trigger fallback, if ETH is transferred to the contract.\n /// Make sure this can not lead to reentrancy attacks.\n function universalTransfer(address token, address to, uint256 value) internal {\n // Don't do anything, if need to send tokens to this address\n if (to == address(this)) return;\n // Don't do anything, if trying to send zero value\n if (value == 0) return;\n if (token == ETH_ADDRESS) {\n /// @dev Note: this can potentially lead to executing code in `to`.\n // solhint-disable-next-line avoid-low-level-calls\n (bool success,) = to.call{value: value}(\"\");\n require(success, \"ETH transfer failed\");\n } else {\n IERC20(token).safeTransfer(to, value);\n }\n }\n\n /// @notice Issues an infinite allowance to the spender, if the current allowance is insufficient\n /// to spend the given amount.\n function universalApproveInfinity(address token, address spender, uint256 amountToSpend) internal {\n // ETH Chad doesn't require your approval\n if (token == ETH_ADDRESS) return;\n // No-op if allowance is already sufficient\n uint256 allowance = IERC20(token).allowance(address(this), spender);\n if (allowance \u003e= amountToSpend) return;\n // Otherwise, reset approval to 0 and set to max allowance\n if (allowance \u003e 0) IERC20(token).safeDecreaseAllowance(spender, allowance);\n IERC20(token).safeIncreaseAllowance(spender, type(uint256).max);\n }\n\n /// @notice Returns the balance of the given token (or native ETH) for the given account.\n function universalBalanceOf(address token, address account) internal view returns (uint256) {\n if (token == ETH_ADDRESS) {\n return account.balance;\n } else {\n return IERC20(token).balanceOf(account);\n }\n }\n\n /// @dev Checks that token is a contract and not ETH_ADDRESS.\n function assertIsContract(address token) internal view {\n // Check that ETH_ADDRESS was not used (in case this is a predeploy on any of the chains)\n if (token == UniversalTokenLib.ETH_ADDRESS) revert TokenNotContract();\n // Check that token is not an EOA\n if (token.code.length == 0) revert TokenNotContract();\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/Admin.sol\n\ncontract Admin is IAdmin, AccessControlEnumerable {\n using UniversalTokenLib for address;\n\n bytes32 public constant RELAYER_ROLE = keccak256(\"RELAYER_ROLE\");\n bytes32 public constant REFUNDER_ROLE = keccak256(\"REFUNDER_ROLE\");\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n uint256 public constant FEE_BPS = 1e6;\n uint256 public constant FEE_RATE_MAX = 0.01e6; // max 1% on origin amount\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Chain gas amount to forward as rebate if requested\n uint256 public chainGasAmount;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n }\n\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n require(newFeeRate \u003c= FEE_RATE_MAX, \"newFeeRate \u003e max\");\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n token.universalTransfer(recipient, feeAmount);\n emit FeesSwept(token, recipient, feeAmount);\n }\n\n function setChainGasAmount(uint256 newChainGasAmount) external onlyRole(GOVERNOR_ROLE) {\n uint256 oldChainGasAmount = chainGasAmount;\n chainGasAmount = newChainGasAmount;\n emit ChainGasAmountUpdated(oldChainGasAmount, newChainGasAmount);\n }\n}\n\n// contracts/FastBridge.sol\n\ncontract FastBridge is IFastBridge, Admin {\n using SafeERC20 for IERC20;\n using UniversalTokenLib for address;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Delay for a transaction after which it could be permisionlessly refunded\n uint256 public constant REFUND_DELAY = 7 days;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeStatus) public bridgeStatuses;\n /// @notice Proof of relayed bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeProof) public bridgeProofs;\n /// @notice Whether bridge has been relayed on destination chain\n mapping(bytes32 =\u003e bool) public bridgeRelays;\n\n /// @dev to prevent replays\n uint256 public nonce;\n // @dev the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @notice Pulls a requested token from the user to the requested recipient.\n /// @dev Be careful of re-entrancy issues when msg.value \u003e 0 and recipient != address(this)\n function _pullToken(address recipient, address token, uint256 amount) internal returns (uint256 amountPulled) {\n if (token != UniversalTokenLib.ETH_ADDRESS) {\n token.assertIsContract();\n // Record token balance before transfer\n amountPulled = IERC20(token).balanceOf(recipient);\n // Token needs to be pulled only if msg.value is zero\n // This way user can specify WETH as the origin asset\n IERC20(token).safeTransferFrom(msg.sender, recipient, amount);\n // Use the difference between the recorded balance and the current balance as the amountPulled\n amountPulled = IERC20(token).balanceOf(recipient) - amountPulled;\n } else {\n // Otherwise, we need to check that ETH amount matches msg.value\n if (amount != msg.value) revert MsgValueIncorrect();\n // Transfer value to recipient if not this address\n if (recipient != address(this)) token.universalTransfer(recipient, amount);\n // We will forward msg.value in the external call later, if recipient is not this contract\n amountPulled = msg.value;\n }\n }\n\n /// @inheritdoc IFastBridge\n function getBridgeTransaction(bytes memory request) public pure returns (BridgeTransaction memory) {\n return abi.decode(request, (BridgeTransaction));\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n // check bridge params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n\n // transfer tokens to bridge contract\n // @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _pullToken(address(this), params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n\n // set status to requested\n bytes memory request = abi.encode(\n BridgeTransaction({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n sendChainGas: params.sendChainGas,\n deadline: params.deadline,\n nonce: nonce++ // increment nonce on every bridge\n })\n );\n bytes32 transactionId = keccak256(request);\n bridgeStatuses[transactionId] = BridgeStatus.REQUESTED;\n\n emit BridgeRequested(\n transactionId,\n params.sender,\n request,\n params.dstChainId,\n params.originToken,\n params.destToken,\n originAmount,\n params.destAmount,\n params.sendChainGas\n );\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes memory request) external payable onlyRole(RELAYER_ROLE) {\n bytes32 transactionId = keccak256(request);\n BridgeTransaction memory transaction = getBridgeTransaction(request);\n if (transaction.destChainId != uint32(block.chainid)) revert ChainIncorrect();\n\n // check haven't exceeded deadline for relay to happen\n if (block.timestamp \u003e transaction.deadline) revert DeadlineExceeded();\n\n // mark bridge transaction as relayed\n if (bridgeRelays[transactionId]) revert TransactionRelayed();\n bridgeRelays[transactionId] = true;\n\n // transfer tokens to recipient on destination chain and gas rebate if requested\n address to = transaction.destRecipient;\n address token = transaction.destToken;\n uint256 amount = transaction.destAmount;\n\n uint256 rebate = chainGasAmount;\n if (!transaction.sendChainGas) {\n // forward erc20\n rebate = 0;\n _pullToken(to, token, amount);\n } else if (token == UniversalTokenLib.ETH_ADDRESS) {\n // lump in gas rebate into amount in native gas token\n _pullToken(to, token, amount + rebate);\n } else {\n // forward erc20 then forward gas rebate in native gas token\n _pullToken(to, token, amount);\n _pullToken(to, UniversalTokenLib.ETH_ADDRESS, rebate);\n }\n\n emit BridgeRelayed(\n transactionId,\n msg.sender,\n to,\n transaction.originChainId,\n transaction.originToken,\n transaction.destToken,\n transaction.originAmount,\n transaction.destAmount,\n rebate\n );\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes memory request, bytes32 destTxHash) external onlyRole(RELAYER_ROLE) {\n bytes32 transactionId = keccak256(request);\n // update bridge tx status given proof provided\n if (bridgeStatuses[transactionId] != BridgeStatus.REQUESTED) revert StatusIncorrect();\n bridgeStatuses[transactionId] = BridgeStatus.RELAYER_PROVED;\n bridgeProofs[transactionId] = BridgeProof({timestamp: uint96(block.timestamp), relayer: msg.sender}); // overflow ok\n\n emit BridgeProofProvided(transactionId, msg.sender, destTxHash);\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint96(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint96).max but\n /// proof.timestamp \u003c type(uint96).max via unchecked statement\n /// @param proof The bridge proof\n /// @return delta Time delta since proof submitted\n function _timeSince(BridgeProof memory proof) internal view returns (uint256 delta) {\n unchecked {\n delta = uint96(block.timestamp) - proof.timestamp;\n }\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n if (bridgeStatuses[transactionId] != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n BridgeProof memory proof = bridgeProofs[transactionId];\n if (proof.relayer != relayer) revert SenderIncorrect();\n return _timeSince(proof) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes memory request, address to) external onlyRole(RELAYER_ROLE) {\n bytes32 transactionId = keccak256(request);\n BridgeTransaction memory transaction = getBridgeTransaction(request);\n\n // update bridge tx status if able to claim origin collateral\n if (bridgeStatuses[transactionId] != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n\n BridgeProof memory proof = bridgeProofs[transactionId];\n if (proof.relayer != msg.sender) revert SenderIncorrect();\n if (_timeSince(proof) \u003c= DISPUTE_PERIOD) revert DisputePeriodNotPassed();\n\n bridgeStatuses[transactionId] = BridgeStatus.RELAYER_CLAIMED;\n\n // update protocol fees if origin fee amount exists\n if (transaction.originFeeAmount \u003e 0) protocolFees[transaction.originToken] += transaction.originFeeAmount;\n\n // transfer origin collateral less fee to specified address\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositClaimed(transactionId, msg.sender, to, token, amount);\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n if (bridgeStatuses[transactionId] != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(bridgeProofs[transactionId]) \u003e DISPUTE_PERIOD) revert DisputePeriodPassed();\n\n // @dev relayer gets slashed effectively if dest relay has gone thru\n bridgeStatuses[transactionId] = BridgeStatus.REQUESTED;\n delete bridgeProofs[transactionId];\n\n emit BridgeProofDisputed(transactionId, msg.sender);\n }\n\n /// @inheritdoc IFastBridge\n function refund(bytes memory request) external {\n bytes32 transactionId = keccak256(request);\n BridgeTransaction memory transaction = getBridgeTransaction(request);\n\n if (hasRole(REFUNDER_ROLE, msg.sender)) {\n // Refunder can refund if deadline has passed\n if (block.timestamp \u003c= transaction.deadline) revert DeadlineNotExceeded();\n } else {\n // Permissionless refund is allowed after REFUND_DELAY\n if (block.timestamp \u003c= transaction.deadline + REFUND_DELAY) revert DeadlineNotExceeded();\n }\n\n // set status to refunded if still in requested state\n if (bridgeStatuses[transactionId] != BridgeStatus.REQUESTED) revert StatusIncorrect();\n bridgeStatuses[transactionId] = BridgeStatus.REFUNDED;\n\n // transfer origin collateral back to original sender\n address to = transaction.originSender;\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount + transaction.originFeeAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n }\n}\n\n// test/FastBridgeMock.sol\n\ncontract FastBridgeMock is IFastBridge, Admin {\n // @dev the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @dev to prevent replays\n uint256 public nonce;\n\n function getBridgeTransaction(bytes memory request) public pure returns (BridgeTransaction memory) {\n return abi.decode(request, (BridgeTransaction));\n }\n\n // used for testing in go.\n // see: https://ethereum.stackexchange.com/questions/21155/how-to-expose-enum-in-solidity-contract\n // make sure to update fastbridge/status.go if this changes\n // or underliyng enum changes.\n //\n // TODO: a foundry test should be added to ensure this is always in sync.\n function getEnumKeyByValue(FastBridge.BridgeStatus keyValue) public pure returns (string memory) {\n if (FastBridge.BridgeStatus.NULL == keyValue) return \"NULL\";\n if (FastBridge.BridgeStatus.REQUESTED == keyValue) return \"REQUESTED\";\n if (FastBridge.BridgeStatus.RELAYER_PROVED == keyValue) return \"RELAYER_PROVED\";\n if (FastBridge.BridgeStatus.RELAYER_CLAIMED == keyValue) return \"RELAYER_CLAIMED\";\n if (FastBridge.BridgeStatus.REFUNDED == keyValue) return \"REFUNDED\";\n return \"\";\n }\n\n function mockBridgeRequest(bytes32 transactionId, address sender, BridgeParams memory params) external {\n uint256 originFeeAmount = (params.originAmount * protocolFeeRate) / FEE_BPS;\n params.originAmount -= originFeeAmount;\n\n bytes memory request = abi.encode(\n BridgeTransaction({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: params.originAmount, // includes relayer fee\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n sendChainGas: params.sendChainGas,\n deadline: params.deadline,\n nonce: nonce++ // increment nonce on every bridge\n })\n );\n\n emit BridgeRequested(\n transactionId,\n params.sender,\n request,\n params.dstChainId,\n params.originToken,\n params.destToken,\n params.originAmount,\n params.destAmount,\n params.sendChainGas\n );\n }\n\n function mockBridgeRequestRaw(bytes32 transactionId, address sender, bytes memory request) external {\n BridgeTransaction memory transaction = getBridgeTransaction(request);\n emit BridgeRequested(\n transactionId,\n transaction.originSender,\n request,\n transaction.destChainId,\n transaction.originToken,\n transaction.destToken,\n transaction.originAmount,\n transaction.destAmount,\n transaction.sendChainGas\n );\n }\n\n function mockBridgeRelayer(\n bytes32 transactionId,\n address relayer,\n address to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n )\n external\n {\n emit BridgeRelayed(\n transactionId, relayer, to, originChainId, originToken, destToken, originAmount, destAmount, chainGasAmount\n );\n }\n\n function bridge(BridgeParams memory params) external payable {\n revert(\"not implemented\");\n }\n\n function relay(bytes memory request) external payable {\n revert(\"not implemented\");\n }\n\n function prove(bytes memory request, bytes32 destTxHash) external {\n revert(\"not implemented\");\n }\n\n function canClaim(bytes32 transactionid, address relayer) external view returns (bool) {\n revert(\"not implemented\");\n }\n\n function claim(bytes memory request, address to) external {\n revert(\"not implemented\");\n }\n\n function dispute(bytes32 transactionId) external {\n revert(\"not implemented\");\n }\n\n function refund(bytes memory request) external {\n revert(\"not implemented\");\n }\n}\n","language":"Solidity","languageVersion":"0.8.20","compilerVersion":"0.8.20","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"","srcMapRuntime":"","abiDefinition":[{"inputs":[],"name":"AccessControlBadConfirmation","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"bytes32","name":"neededRole","type":"bytes32"}],"name":"AccessControlUnauthorizedAccount","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"previousAdminRole","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"newAdminRole","type":"bytes32"}],"name":"RoleAdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleRevoked","type":"event"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleAdmin","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"grantRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"hasRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"callerConfirmation","type":"address"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"revokeRole","outputs":[],"stateMutability":"nonpayable","type":"function"}],"userDoc":{"kind":"user","methods":{},"version":1},"developerDoc":{"details":"External interface of AccessControl declared to support ERC165 detection.","errors":{"AccessControlBadConfirmation()":[{"details":"The caller of a function is not the expected one. NOTE: Don't confuse with {AccessControlUnauthorizedAccount}."}],"AccessControlUnauthorizedAccount(address,bytes32)":[{"details":"The `account` is missing a role."}]},"events":{"RoleAdminChanged(bytes32,bytes32,bytes32)":{"details":"Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole` `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite {RoleAdminChanged} not being emitted signaling this."},"RoleGranted(bytes32,address,address)":{"details":"Emitted when `account` is granted `role`. `sender` is the account that originated the contract call, an admin role bearer except when using {AccessControl-_setupRole}."},"RoleRevoked(bytes32,address,address)":{"details":"Emitted when `account` is revoked `role`. `sender` is the account that originated the contract call: - if using `revokeRole`, it is the admin role bearer - if using `renounceRole`, it is the role bearer (i.e. `account`)"}},"kind":"dev","methods":{"getRoleAdmin(bytes32)":{"details":"Returns the admin role that controls `role`. See {grantRole} and {revokeRole}. To change a role's admin, use {AccessControl-_setRoleAdmin}."},"grantRole(bytes32,address)":{"details":"Grants `role` to `account`. If `account` had not been already granted `role`, emits a {RoleGranted} event. Requirements: - the caller must have ``role``'s admin role."},"hasRole(bytes32,address)":{"details":"Returns `true` if `account` has been granted `role`."},"renounceRole(bytes32,address)":{"details":"Revokes `role` from the calling account. Roles are often managed via {grantRole} and {revokeRole}: this function's purpose is to provide a mechanism for accounts to lose their privileges if they are compromised (such as when a trusted device is misplaced). If the calling account had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must be `callerConfirmation`."},"revokeRole(bytes32,address)":{"details":"Revokes `role` from `account`. If `account` had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must have ``role``'s admin role."}},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.20+commit.a1b79de6\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[],\"name\":\"AccessControlBadConfirmation\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"neededRole\",\"type\":\"bytes32\"}],\"name\":\"AccessControlUnauthorizedAccount\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"previousAdminRole\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"newAdminRole\",\"type\":\"bytes32\"}],\"name\":\"RoleAdminChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleGranted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleRevoked\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"}],\"name\":\"getRoleAdmin\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"grantRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"hasRole\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"callerConfirmation\",\"type\":\"address\"}],\"name\":\"renounceRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"revokeRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"details\":\"External interface of AccessControl declared to support ERC165 detection.\",\"errors\":{\"AccessControlBadConfirmation()\":[{\"details\":\"The caller of a function is not the expected one. NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\"}],\"AccessControlUnauthorizedAccount(address,bytes32)\":[{\"details\":\"The `account` is missing a role.\"}]},\"events\":{\"RoleAdminChanged(bytes32,bytes32,bytes32)\":{\"details\":\"Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole` `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite {RoleAdminChanged} not being emitted signaling this.\"},\"RoleGranted(bytes32,address,address)\":{\"details\":\"Emitted when `account` is granted `role`. `sender` is the account that originated the contract call, an admin role bearer except when using {AccessControl-_setupRole}.\"},\"RoleRevoked(bytes32,address,address)\":{\"details\":\"Emitted when `account` is revoked `role`. `sender` is the account that originated the contract call: - if using `revokeRole`, it is the admin role bearer - if using `renounceRole`, it is the role bearer (i.e. `account`)\"}},\"kind\":\"dev\",\"methods\":{\"getRoleAdmin(bytes32)\":{\"details\":\"Returns the admin role that controls `role`. See {grantRole} and {revokeRole}. To change a role's admin, use {AccessControl-_setRoleAdmin}.\"},\"grantRole(bytes32,address)\":{\"details\":\"Grants `role` to `account`. If `account` had not been already granted `role`, emits a {RoleGranted} event. Requirements: - the caller must have ``role``'s admin role.\"},\"hasRole(bytes32,address)\":{\"details\":\"Returns `true` if `account` has been granted `role`.\"},\"renounceRole(bytes32,address)\":{\"details\":\"Revokes `role` from the calling account. Roles are often managed via {grantRole} and {revokeRole}: this function's purpose is to provide a mechanism for accounts to lose their privileges if they are compromised (such as when a trusted device is misplaced). If the calling account had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must be `callerConfirmation`.\"},\"revokeRole(bytes32,address)\":{\"details\":\"Revokes `role` from `account`. If `account` had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must have ``role``'s admin role.\"}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeMock.sol\":\"IAccessControl\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeMock.sol\":{\"keccak256\":\"0x620e81214ecd324ae8b971219291f176c454ce76fb1c01d656428096da8f1366\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://18e556772c12e13aa2d52a50cc7c48e676c8d5af22b90adaf7befb39cdd08e64\",\"dweb:/ipfs/QmPrQc98TxHCFMeuFNADyjr6Nqo52rHhHy1LBcsVdMRXjL\"]}},\"version\":1}"},"hashes":{"getRoleAdmin(bytes32)":"248a9ca3","grantRole(bytes32,address)":"2f2ff15d","hasRole(bytes32,address)":"91d14854","renounceRole(bytes32,address)":"36568abe","revokeRole(bytes32,address)":"d547741f"}},"solidity/FastBridgeMock.sol:IAccessControlEnumerable":{"code":"0x","runtime-code":"0x","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.20 ^0.8.20;\n\n// contracts/interfaces/IAdmin.sol\n\ninterface IAdmin {\n // ============ Events ============\n\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n event ChainGasAmountUpdated(uint256 oldChainGasAmount, uint256 newChainGasAmount);\n\n // ============ Methods ============\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n\n function setChainGasAmount(uint256 newChainGasAmount) external;\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/libs/Errors.sol\n\nerror DeadlineExceeded();\nerror DeadlineNotExceeded();\nerror DeadlineTooShort();\nerror InsufficientOutputAmount();\n\nerror MsgValueIncorrect();\nerror PoolNotFound();\nerror TokenAddressMismatch();\nerror TokenNotContract();\nerror TokenNotETH();\nerror TokensIdentical();\n\nerror ChainIncorrect();\nerror AmountIncorrect();\nerror ZeroAddress();\n\nerror DisputePeriodNotPassed();\nerror DisputePeriodPassed();\nerror SenderIncorrect();\nerror StatusIncorrect();\nerror TransactionIdIncorrect();\nerror TransactionRelayed();\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// contracts/libs/UniversalToken.sol\n\nlibrary UniversalTokenLib {\n using SafeERC20 for IERC20;\n\n address internal constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Transfers tokens to the given account. Reverts if transfer is not successful.\n /// @dev This might trigger fallback, if ETH is transferred to the contract.\n /// Make sure this can not lead to reentrancy attacks.\n function universalTransfer(address token, address to, uint256 value) internal {\n // Don't do anything, if need to send tokens to this address\n if (to == address(this)) return;\n // Don't do anything, if trying to send zero value\n if (value == 0) return;\n if (token == ETH_ADDRESS) {\n /// @dev Note: this can potentially lead to executing code in `to`.\n // solhint-disable-next-line avoid-low-level-calls\n (bool success,) = to.call{value: value}(\"\");\n require(success, \"ETH transfer failed\");\n } else {\n IERC20(token).safeTransfer(to, value);\n }\n }\n\n /// @notice Issues an infinite allowance to the spender, if the current allowance is insufficient\n /// to spend the given amount.\n function universalApproveInfinity(address token, address spender, uint256 amountToSpend) internal {\n // ETH Chad doesn't require your approval\n if (token == ETH_ADDRESS) return;\n // No-op if allowance is already sufficient\n uint256 allowance = IERC20(token).allowance(address(this), spender);\n if (allowance \u003e= amountToSpend) return;\n // Otherwise, reset approval to 0 and set to max allowance\n if (allowance \u003e 0) IERC20(token).safeDecreaseAllowance(spender, allowance);\n IERC20(token).safeIncreaseAllowance(spender, type(uint256).max);\n }\n\n /// @notice Returns the balance of the given token (or native ETH) for the given account.\n function universalBalanceOf(address token, address account) internal view returns (uint256) {\n if (token == ETH_ADDRESS) {\n return account.balance;\n } else {\n return IERC20(token).balanceOf(account);\n }\n }\n\n /// @dev Checks that token is a contract and not ETH_ADDRESS.\n function assertIsContract(address token) internal view {\n // Check that ETH_ADDRESS was not used (in case this is a predeploy on any of the chains)\n if (token == UniversalTokenLib.ETH_ADDRESS) revert TokenNotContract();\n // Check that token is not an EOA\n if (token.code.length == 0) revert TokenNotContract();\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/Admin.sol\n\ncontract Admin is IAdmin, AccessControlEnumerable {\n using UniversalTokenLib for address;\n\n bytes32 public constant RELAYER_ROLE = keccak256(\"RELAYER_ROLE\");\n bytes32 public constant REFUNDER_ROLE = keccak256(\"REFUNDER_ROLE\");\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n uint256 public constant FEE_BPS = 1e6;\n uint256 public constant FEE_RATE_MAX = 0.01e6; // max 1% on origin amount\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Chain gas amount to forward as rebate if requested\n uint256 public chainGasAmount;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n }\n\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n require(newFeeRate \u003c= FEE_RATE_MAX, \"newFeeRate \u003e max\");\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n token.universalTransfer(recipient, feeAmount);\n emit FeesSwept(token, recipient, feeAmount);\n }\n\n function setChainGasAmount(uint256 newChainGasAmount) external onlyRole(GOVERNOR_ROLE) {\n uint256 oldChainGasAmount = chainGasAmount;\n chainGasAmount = newChainGasAmount;\n emit ChainGasAmountUpdated(oldChainGasAmount, newChainGasAmount);\n }\n}\n\n// contracts/FastBridge.sol\n\ncontract FastBridge is IFastBridge, Admin {\n using SafeERC20 for IERC20;\n using UniversalTokenLib for address;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Delay for a transaction after which it could be permisionlessly refunded\n uint256 public constant REFUND_DELAY = 7 days;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeStatus) public bridgeStatuses;\n /// @notice Proof of relayed bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeProof) public bridgeProofs;\n /// @notice Whether bridge has been relayed on destination chain\n mapping(bytes32 =\u003e bool) public bridgeRelays;\n\n /// @dev to prevent replays\n uint256 public nonce;\n // @dev the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @notice Pulls a requested token from the user to the requested recipient.\n /// @dev Be careful of re-entrancy issues when msg.value \u003e 0 and recipient != address(this)\n function _pullToken(address recipient, address token, uint256 amount) internal returns (uint256 amountPulled) {\n if (token != UniversalTokenLib.ETH_ADDRESS) {\n token.assertIsContract();\n // Record token balance before transfer\n amountPulled = IERC20(token).balanceOf(recipient);\n // Token needs to be pulled only if msg.value is zero\n // This way user can specify WETH as the origin asset\n IERC20(token).safeTransferFrom(msg.sender, recipient, amount);\n // Use the difference between the recorded balance and the current balance as the amountPulled\n amountPulled = IERC20(token).balanceOf(recipient) - amountPulled;\n } else {\n // Otherwise, we need to check that ETH amount matches msg.value\n if (amount != msg.value) revert MsgValueIncorrect();\n // Transfer value to recipient if not this address\n if (recipient != address(this)) token.universalTransfer(recipient, amount);\n // We will forward msg.value in the external call later, if recipient is not this contract\n amountPulled = msg.value;\n }\n }\n\n /// @inheritdoc IFastBridge\n function getBridgeTransaction(bytes memory request) public pure returns (BridgeTransaction memory) {\n return abi.decode(request, (BridgeTransaction));\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n // check bridge params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n\n // transfer tokens to bridge contract\n // @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _pullToken(address(this), params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n\n // set status to requested\n bytes memory request = abi.encode(\n BridgeTransaction({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n sendChainGas: params.sendChainGas,\n deadline: params.deadline,\n nonce: nonce++ // increment nonce on every bridge\n })\n );\n bytes32 transactionId = keccak256(request);\n bridgeStatuses[transactionId] = BridgeStatus.REQUESTED;\n\n emit BridgeRequested(\n transactionId,\n params.sender,\n request,\n params.dstChainId,\n params.originToken,\n params.destToken,\n originAmount,\n params.destAmount,\n params.sendChainGas\n );\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes memory request) external payable onlyRole(RELAYER_ROLE) {\n bytes32 transactionId = keccak256(request);\n BridgeTransaction memory transaction = getBridgeTransaction(request);\n if (transaction.destChainId != uint32(block.chainid)) revert ChainIncorrect();\n\n // check haven't exceeded deadline for relay to happen\n if (block.timestamp \u003e transaction.deadline) revert DeadlineExceeded();\n\n // mark bridge transaction as relayed\n if (bridgeRelays[transactionId]) revert TransactionRelayed();\n bridgeRelays[transactionId] = true;\n\n // transfer tokens to recipient on destination chain and gas rebate if requested\n address to = transaction.destRecipient;\n address token = transaction.destToken;\n uint256 amount = transaction.destAmount;\n\n uint256 rebate = chainGasAmount;\n if (!transaction.sendChainGas) {\n // forward erc20\n rebate = 0;\n _pullToken(to, token, amount);\n } else if (token == UniversalTokenLib.ETH_ADDRESS) {\n // lump in gas rebate into amount in native gas token\n _pullToken(to, token, amount + rebate);\n } else {\n // forward erc20 then forward gas rebate in native gas token\n _pullToken(to, token, amount);\n _pullToken(to, UniversalTokenLib.ETH_ADDRESS, rebate);\n }\n\n emit BridgeRelayed(\n transactionId,\n msg.sender,\n to,\n transaction.originChainId,\n transaction.originToken,\n transaction.destToken,\n transaction.originAmount,\n transaction.destAmount,\n rebate\n );\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes memory request, bytes32 destTxHash) external onlyRole(RELAYER_ROLE) {\n bytes32 transactionId = keccak256(request);\n // update bridge tx status given proof provided\n if (bridgeStatuses[transactionId] != BridgeStatus.REQUESTED) revert StatusIncorrect();\n bridgeStatuses[transactionId] = BridgeStatus.RELAYER_PROVED;\n bridgeProofs[transactionId] = BridgeProof({timestamp: uint96(block.timestamp), relayer: msg.sender}); // overflow ok\n\n emit BridgeProofProvided(transactionId, msg.sender, destTxHash);\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint96(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint96).max but\n /// proof.timestamp \u003c type(uint96).max via unchecked statement\n /// @param proof The bridge proof\n /// @return delta Time delta since proof submitted\n function _timeSince(BridgeProof memory proof) internal view returns (uint256 delta) {\n unchecked {\n delta = uint96(block.timestamp) - proof.timestamp;\n }\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n if (bridgeStatuses[transactionId] != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n BridgeProof memory proof = bridgeProofs[transactionId];\n if (proof.relayer != relayer) revert SenderIncorrect();\n return _timeSince(proof) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes memory request, address to) external onlyRole(RELAYER_ROLE) {\n bytes32 transactionId = keccak256(request);\n BridgeTransaction memory transaction = getBridgeTransaction(request);\n\n // update bridge tx status if able to claim origin collateral\n if (bridgeStatuses[transactionId] != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n\n BridgeProof memory proof = bridgeProofs[transactionId];\n if (proof.relayer != msg.sender) revert SenderIncorrect();\n if (_timeSince(proof) \u003c= DISPUTE_PERIOD) revert DisputePeriodNotPassed();\n\n bridgeStatuses[transactionId] = BridgeStatus.RELAYER_CLAIMED;\n\n // update protocol fees if origin fee amount exists\n if (transaction.originFeeAmount \u003e 0) protocolFees[transaction.originToken] += transaction.originFeeAmount;\n\n // transfer origin collateral less fee to specified address\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositClaimed(transactionId, msg.sender, to, token, amount);\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n if (bridgeStatuses[transactionId] != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(bridgeProofs[transactionId]) \u003e DISPUTE_PERIOD) revert DisputePeriodPassed();\n\n // @dev relayer gets slashed effectively if dest relay has gone thru\n bridgeStatuses[transactionId] = BridgeStatus.REQUESTED;\n delete bridgeProofs[transactionId];\n\n emit BridgeProofDisputed(transactionId, msg.sender);\n }\n\n /// @inheritdoc IFastBridge\n function refund(bytes memory request) external {\n bytes32 transactionId = keccak256(request);\n BridgeTransaction memory transaction = getBridgeTransaction(request);\n\n if (hasRole(REFUNDER_ROLE, msg.sender)) {\n // Refunder can refund if deadline has passed\n if (block.timestamp \u003c= transaction.deadline) revert DeadlineNotExceeded();\n } else {\n // Permissionless refund is allowed after REFUND_DELAY\n if (block.timestamp \u003c= transaction.deadline + REFUND_DELAY) revert DeadlineNotExceeded();\n }\n\n // set status to refunded if still in requested state\n if (bridgeStatuses[transactionId] != BridgeStatus.REQUESTED) revert StatusIncorrect();\n bridgeStatuses[transactionId] = BridgeStatus.REFUNDED;\n\n // transfer origin collateral back to original sender\n address to = transaction.originSender;\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount + transaction.originFeeAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n }\n}\n\n// test/FastBridgeMock.sol\n\ncontract FastBridgeMock is IFastBridge, Admin {\n // @dev the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @dev to prevent replays\n uint256 public nonce;\n\n function getBridgeTransaction(bytes memory request) public pure returns (BridgeTransaction memory) {\n return abi.decode(request, (BridgeTransaction));\n }\n\n // used for testing in go.\n // see: https://ethereum.stackexchange.com/questions/21155/how-to-expose-enum-in-solidity-contract\n // make sure to update fastbridge/status.go if this changes\n // or underliyng enum changes.\n //\n // TODO: a foundry test should be added to ensure this is always in sync.\n function getEnumKeyByValue(FastBridge.BridgeStatus keyValue) public pure returns (string memory) {\n if (FastBridge.BridgeStatus.NULL == keyValue) return \"NULL\";\n if (FastBridge.BridgeStatus.REQUESTED == keyValue) return \"REQUESTED\";\n if (FastBridge.BridgeStatus.RELAYER_PROVED == keyValue) return \"RELAYER_PROVED\";\n if (FastBridge.BridgeStatus.RELAYER_CLAIMED == keyValue) return \"RELAYER_CLAIMED\";\n if (FastBridge.BridgeStatus.REFUNDED == keyValue) return \"REFUNDED\";\n return \"\";\n }\n\n function mockBridgeRequest(bytes32 transactionId, address sender, BridgeParams memory params) external {\n uint256 originFeeAmount = (params.originAmount * protocolFeeRate) / FEE_BPS;\n params.originAmount -= originFeeAmount;\n\n bytes memory request = abi.encode(\n BridgeTransaction({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: params.originAmount, // includes relayer fee\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n sendChainGas: params.sendChainGas,\n deadline: params.deadline,\n nonce: nonce++ // increment nonce on every bridge\n })\n );\n\n emit BridgeRequested(\n transactionId,\n params.sender,\n request,\n params.dstChainId,\n params.originToken,\n params.destToken,\n params.originAmount,\n params.destAmount,\n params.sendChainGas\n );\n }\n\n function mockBridgeRequestRaw(bytes32 transactionId, address sender, bytes memory request) external {\n BridgeTransaction memory transaction = getBridgeTransaction(request);\n emit BridgeRequested(\n transactionId,\n transaction.originSender,\n request,\n transaction.destChainId,\n transaction.originToken,\n transaction.destToken,\n transaction.originAmount,\n transaction.destAmount,\n transaction.sendChainGas\n );\n }\n\n function mockBridgeRelayer(\n bytes32 transactionId,\n address relayer,\n address to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n )\n external\n {\n emit BridgeRelayed(\n transactionId, relayer, to, originChainId, originToken, destToken, originAmount, destAmount, chainGasAmount\n );\n }\n\n function bridge(BridgeParams memory params) external payable {\n revert(\"not implemented\");\n }\n\n function relay(bytes memory request) external payable {\n revert(\"not implemented\");\n }\n\n function prove(bytes memory request, bytes32 destTxHash) external {\n revert(\"not implemented\");\n }\n\n function canClaim(bytes32 transactionid, address relayer) external view returns (bool) {\n revert(\"not implemented\");\n }\n\n function claim(bytes memory request, address to) external {\n revert(\"not implemented\");\n }\n\n function dispute(bytes32 transactionId) external {\n revert(\"not implemented\");\n }\n\n function refund(bytes memory request) external {\n revert(\"not implemented\");\n }\n}\n","language":"Solidity","languageVersion":"0.8.20","compilerVersion":"0.8.20","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"","srcMapRuntime":"","abiDefinition":[{"inputs":[],"name":"AccessControlBadConfirmation","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"bytes32","name":"neededRole","type":"bytes32"}],"name":"AccessControlUnauthorizedAccount","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"previousAdminRole","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"newAdminRole","type":"bytes32"}],"name":"RoleAdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleRevoked","type":"event"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleAdmin","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"uint256","name":"index","type":"uint256"}],"name":"getRoleMember","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleMemberCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"grantRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"hasRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"callerConfirmation","type":"address"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"revokeRole","outputs":[],"stateMutability":"nonpayable","type":"function"}],"userDoc":{"kind":"user","methods":{},"version":1},"developerDoc":{"details":"External interface of AccessControlEnumerable declared to support ERC165 detection.","errors":{"AccessControlBadConfirmation()":[{"details":"The caller of a function is not the expected one. NOTE: Don't confuse with {AccessControlUnauthorizedAccount}."}],"AccessControlUnauthorizedAccount(address,bytes32)":[{"details":"The `account` is missing a role."}]},"events":{"RoleAdminChanged(bytes32,bytes32,bytes32)":{"details":"Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole` `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite {RoleAdminChanged} not being emitted signaling this."},"RoleGranted(bytes32,address,address)":{"details":"Emitted when `account` is granted `role`. `sender` is the account that originated the contract call, an admin role bearer except when using {AccessControl-_setupRole}."},"RoleRevoked(bytes32,address,address)":{"details":"Emitted when `account` is revoked `role`. `sender` is the account that originated the contract call: - if using `revokeRole`, it is the admin role bearer - if using `renounceRole`, it is the role bearer (i.e. `account`)"}},"kind":"dev","methods":{"getRoleAdmin(bytes32)":{"details":"Returns the admin role that controls `role`. See {grantRole} and {revokeRole}. To change a role's admin, use {AccessControl-_setRoleAdmin}."},"getRoleMember(bytes32,uint256)":{"details":"Returns one of the accounts that have `role`. `index` must be a value between 0 and {getRoleMemberCount}, non-inclusive. Role bearers are not sorted in any particular way, and their ordering may change at any point. WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure you perform all queries on the same block. See the following https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post] for more information."},"getRoleMemberCount(bytes32)":{"details":"Returns the number of accounts that have `role`. Can be used together with {getRoleMember} to enumerate all bearers of a role."},"grantRole(bytes32,address)":{"details":"Grants `role` to `account`. If `account` had not been already granted `role`, emits a {RoleGranted} event. Requirements: - the caller must have ``role``'s admin role."},"hasRole(bytes32,address)":{"details":"Returns `true` if `account` has been granted `role`."},"renounceRole(bytes32,address)":{"details":"Revokes `role` from the calling account. Roles are often managed via {grantRole} and {revokeRole}: this function's purpose is to provide a mechanism for accounts to lose their privileges if they are compromised (such as when a trusted device is misplaced). If the calling account had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must be `callerConfirmation`."},"revokeRole(bytes32,address)":{"details":"Revokes `role` from `account`. If `account` had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must have ``role``'s admin role."}},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.20+commit.a1b79de6\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[],\"name\":\"AccessControlBadConfirmation\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"neededRole\",\"type\":\"bytes32\"}],\"name\":\"AccessControlUnauthorizedAccount\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"previousAdminRole\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"newAdminRole\",\"type\":\"bytes32\"}],\"name\":\"RoleAdminChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleGranted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleRevoked\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"}],\"name\":\"getRoleAdmin\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"index\",\"type\":\"uint256\"}],\"name\":\"getRoleMember\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"}],\"name\":\"getRoleMemberCount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"grantRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"hasRole\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"callerConfirmation\",\"type\":\"address\"}],\"name\":\"renounceRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"revokeRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"details\":\"External interface of AccessControlEnumerable declared to support ERC165 detection.\",\"errors\":{\"AccessControlBadConfirmation()\":[{\"details\":\"The caller of a function is not the expected one. NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\"}],\"AccessControlUnauthorizedAccount(address,bytes32)\":[{\"details\":\"The `account` is missing a role.\"}]},\"events\":{\"RoleAdminChanged(bytes32,bytes32,bytes32)\":{\"details\":\"Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole` `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite {RoleAdminChanged} not being emitted signaling this.\"},\"RoleGranted(bytes32,address,address)\":{\"details\":\"Emitted when `account` is granted `role`. `sender` is the account that originated the contract call, an admin role bearer except when using {AccessControl-_setupRole}.\"},\"RoleRevoked(bytes32,address,address)\":{\"details\":\"Emitted when `account` is revoked `role`. `sender` is the account that originated the contract call: - if using `revokeRole`, it is the admin role bearer - if using `renounceRole`, it is the role bearer (i.e. `account`)\"}},\"kind\":\"dev\",\"methods\":{\"getRoleAdmin(bytes32)\":{\"details\":\"Returns the admin role that controls `role`. See {grantRole} and {revokeRole}. To change a role's admin, use {AccessControl-_setRoleAdmin}.\"},\"getRoleMember(bytes32,uint256)\":{\"details\":\"Returns one of the accounts that have `role`. `index` must be a value between 0 and {getRoleMemberCount}, non-inclusive. Role bearers are not sorted in any particular way, and their ordering may change at any point. WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure you perform all queries on the same block. See the following https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post] for more information.\"},\"getRoleMemberCount(bytes32)\":{\"details\":\"Returns the number of accounts that have `role`. Can be used together with {getRoleMember} to enumerate all bearers of a role.\"},\"grantRole(bytes32,address)\":{\"details\":\"Grants `role` to `account`. If `account` had not been already granted `role`, emits a {RoleGranted} event. Requirements: - the caller must have ``role``'s admin role.\"},\"hasRole(bytes32,address)\":{\"details\":\"Returns `true` if `account` has been granted `role`.\"},\"renounceRole(bytes32,address)\":{\"details\":\"Revokes `role` from the calling account. Roles are often managed via {grantRole} and {revokeRole}: this function's purpose is to provide a mechanism for accounts to lose their privileges if they are compromised (such as when a trusted device is misplaced). If the calling account had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must be `callerConfirmation`.\"},\"revokeRole(bytes32,address)\":{\"details\":\"Revokes `role` from `account`. If `account` had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must have ``role``'s admin role.\"}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeMock.sol\":\"IAccessControlEnumerable\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeMock.sol\":{\"keccak256\":\"0x620e81214ecd324ae8b971219291f176c454ce76fb1c01d656428096da8f1366\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://18e556772c12e13aa2d52a50cc7c48e676c8d5af22b90adaf7befb39cdd08e64\",\"dweb:/ipfs/QmPrQc98TxHCFMeuFNADyjr6Nqo52rHhHy1LBcsVdMRXjL\"]}},\"version\":1}"},"hashes":{"getRoleAdmin(bytes32)":"248a9ca3","getRoleMember(bytes32,uint256)":"9010d07c","getRoleMemberCount(bytes32)":"ca15c873","grantRole(bytes32,address)":"2f2ff15d","hasRole(bytes32,address)":"91d14854","renounceRole(bytes32,address)":"36568abe","revokeRole(bytes32,address)":"d547741f"}},"solidity/FastBridgeMock.sol:IAdmin":{"code":"0x","runtime-code":"0x","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.20 ^0.8.20;\n\n// contracts/interfaces/IAdmin.sol\n\ninterface IAdmin {\n // ============ Events ============\n\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n event ChainGasAmountUpdated(uint256 oldChainGasAmount, uint256 newChainGasAmount);\n\n // ============ Methods ============\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n\n function setChainGasAmount(uint256 newChainGasAmount) external;\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/libs/Errors.sol\n\nerror DeadlineExceeded();\nerror DeadlineNotExceeded();\nerror DeadlineTooShort();\nerror InsufficientOutputAmount();\n\nerror MsgValueIncorrect();\nerror PoolNotFound();\nerror TokenAddressMismatch();\nerror TokenNotContract();\nerror TokenNotETH();\nerror TokensIdentical();\n\nerror ChainIncorrect();\nerror AmountIncorrect();\nerror ZeroAddress();\n\nerror DisputePeriodNotPassed();\nerror DisputePeriodPassed();\nerror SenderIncorrect();\nerror StatusIncorrect();\nerror TransactionIdIncorrect();\nerror TransactionRelayed();\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// contracts/libs/UniversalToken.sol\n\nlibrary UniversalTokenLib {\n using SafeERC20 for IERC20;\n\n address internal constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Transfers tokens to the given account. Reverts if transfer is not successful.\n /// @dev This might trigger fallback, if ETH is transferred to the contract.\n /// Make sure this can not lead to reentrancy attacks.\n function universalTransfer(address token, address to, uint256 value) internal {\n // Don't do anything, if need to send tokens to this address\n if (to == address(this)) return;\n // Don't do anything, if trying to send zero value\n if (value == 0) return;\n if (token == ETH_ADDRESS) {\n /// @dev Note: this can potentially lead to executing code in `to`.\n // solhint-disable-next-line avoid-low-level-calls\n (bool success,) = to.call{value: value}(\"\");\n require(success, \"ETH transfer failed\");\n } else {\n IERC20(token).safeTransfer(to, value);\n }\n }\n\n /// @notice Issues an infinite allowance to the spender, if the current allowance is insufficient\n /// to spend the given amount.\n function universalApproveInfinity(address token, address spender, uint256 amountToSpend) internal {\n // ETH Chad doesn't require your approval\n if (token == ETH_ADDRESS) return;\n // No-op if allowance is already sufficient\n uint256 allowance = IERC20(token).allowance(address(this), spender);\n if (allowance \u003e= amountToSpend) return;\n // Otherwise, reset approval to 0 and set to max allowance\n if (allowance \u003e 0) IERC20(token).safeDecreaseAllowance(spender, allowance);\n IERC20(token).safeIncreaseAllowance(spender, type(uint256).max);\n }\n\n /// @notice Returns the balance of the given token (or native ETH) for the given account.\n function universalBalanceOf(address token, address account) internal view returns (uint256) {\n if (token == ETH_ADDRESS) {\n return account.balance;\n } else {\n return IERC20(token).balanceOf(account);\n }\n }\n\n /// @dev Checks that token is a contract and not ETH_ADDRESS.\n function assertIsContract(address token) internal view {\n // Check that ETH_ADDRESS was not used (in case this is a predeploy on any of the chains)\n if (token == UniversalTokenLib.ETH_ADDRESS) revert TokenNotContract();\n // Check that token is not an EOA\n if (token.code.length == 0) revert TokenNotContract();\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/Admin.sol\n\ncontract Admin is IAdmin, AccessControlEnumerable {\n using UniversalTokenLib for address;\n\n bytes32 public constant RELAYER_ROLE = keccak256(\"RELAYER_ROLE\");\n bytes32 public constant REFUNDER_ROLE = keccak256(\"REFUNDER_ROLE\");\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n uint256 public constant FEE_BPS = 1e6;\n uint256 public constant FEE_RATE_MAX = 0.01e6; // max 1% on origin amount\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Chain gas amount to forward as rebate if requested\n uint256 public chainGasAmount;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n }\n\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n require(newFeeRate \u003c= FEE_RATE_MAX, \"newFeeRate \u003e max\");\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n token.universalTransfer(recipient, feeAmount);\n emit FeesSwept(token, recipient, feeAmount);\n }\n\n function setChainGasAmount(uint256 newChainGasAmount) external onlyRole(GOVERNOR_ROLE) {\n uint256 oldChainGasAmount = chainGasAmount;\n chainGasAmount = newChainGasAmount;\n emit ChainGasAmountUpdated(oldChainGasAmount, newChainGasAmount);\n }\n}\n\n// contracts/FastBridge.sol\n\ncontract FastBridge is IFastBridge, Admin {\n using SafeERC20 for IERC20;\n using UniversalTokenLib for address;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Delay for a transaction after which it could be permisionlessly refunded\n uint256 public constant REFUND_DELAY = 7 days;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeStatus) public bridgeStatuses;\n /// @notice Proof of relayed bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeProof) public bridgeProofs;\n /// @notice Whether bridge has been relayed on destination chain\n mapping(bytes32 =\u003e bool) public bridgeRelays;\n\n /// @dev to prevent replays\n uint256 public nonce;\n // @dev the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @notice Pulls a requested token from the user to the requested recipient.\n /// @dev Be careful of re-entrancy issues when msg.value \u003e 0 and recipient != address(this)\n function _pullToken(address recipient, address token, uint256 amount) internal returns (uint256 amountPulled) {\n if (token != UniversalTokenLib.ETH_ADDRESS) {\n token.assertIsContract();\n // Record token balance before transfer\n amountPulled = IERC20(token).balanceOf(recipient);\n // Token needs to be pulled only if msg.value is zero\n // This way user can specify WETH as the origin asset\n IERC20(token).safeTransferFrom(msg.sender, recipient, amount);\n // Use the difference between the recorded balance and the current balance as the amountPulled\n amountPulled = IERC20(token).balanceOf(recipient) - amountPulled;\n } else {\n // Otherwise, we need to check that ETH amount matches msg.value\n if (amount != msg.value) revert MsgValueIncorrect();\n // Transfer value to recipient if not this address\n if (recipient != address(this)) token.universalTransfer(recipient, amount);\n // We will forward msg.value in the external call later, if recipient is not this contract\n amountPulled = msg.value;\n }\n }\n\n /// @inheritdoc IFastBridge\n function getBridgeTransaction(bytes memory request) public pure returns (BridgeTransaction memory) {\n return abi.decode(request, (BridgeTransaction));\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n // check bridge params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n\n // transfer tokens to bridge contract\n // @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _pullToken(address(this), params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n\n // set status to requested\n bytes memory request = abi.encode(\n BridgeTransaction({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n sendChainGas: params.sendChainGas,\n deadline: params.deadline,\n nonce: nonce++ // increment nonce on every bridge\n })\n );\n bytes32 transactionId = keccak256(request);\n bridgeStatuses[transactionId] = BridgeStatus.REQUESTED;\n\n emit BridgeRequested(\n transactionId,\n params.sender,\n request,\n params.dstChainId,\n params.originToken,\n params.destToken,\n originAmount,\n params.destAmount,\n params.sendChainGas\n );\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes memory request) external payable onlyRole(RELAYER_ROLE) {\n bytes32 transactionId = keccak256(request);\n BridgeTransaction memory transaction = getBridgeTransaction(request);\n if (transaction.destChainId != uint32(block.chainid)) revert ChainIncorrect();\n\n // check haven't exceeded deadline for relay to happen\n if (block.timestamp \u003e transaction.deadline) revert DeadlineExceeded();\n\n // mark bridge transaction as relayed\n if (bridgeRelays[transactionId]) revert TransactionRelayed();\n bridgeRelays[transactionId] = true;\n\n // transfer tokens to recipient on destination chain and gas rebate if requested\n address to = transaction.destRecipient;\n address token = transaction.destToken;\n uint256 amount = transaction.destAmount;\n\n uint256 rebate = chainGasAmount;\n if (!transaction.sendChainGas) {\n // forward erc20\n rebate = 0;\n _pullToken(to, token, amount);\n } else if (token == UniversalTokenLib.ETH_ADDRESS) {\n // lump in gas rebate into amount in native gas token\n _pullToken(to, token, amount + rebate);\n } else {\n // forward erc20 then forward gas rebate in native gas token\n _pullToken(to, token, amount);\n _pullToken(to, UniversalTokenLib.ETH_ADDRESS, rebate);\n }\n\n emit BridgeRelayed(\n transactionId,\n msg.sender,\n to,\n transaction.originChainId,\n transaction.originToken,\n transaction.destToken,\n transaction.originAmount,\n transaction.destAmount,\n rebate\n );\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes memory request, bytes32 destTxHash) external onlyRole(RELAYER_ROLE) {\n bytes32 transactionId = keccak256(request);\n // update bridge tx status given proof provided\n if (bridgeStatuses[transactionId] != BridgeStatus.REQUESTED) revert StatusIncorrect();\n bridgeStatuses[transactionId] = BridgeStatus.RELAYER_PROVED;\n bridgeProofs[transactionId] = BridgeProof({timestamp: uint96(block.timestamp), relayer: msg.sender}); // overflow ok\n\n emit BridgeProofProvided(transactionId, msg.sender, destTxHash);\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint96(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint96).max but\n /// proof.timestamp \u003c type(uint96).max via unchecked statement\n /// @param proof The bridge proof\n /// @return delta Time delta since proof submitted\n function _timeSince(BridgeProof memory proof) internal view returns (uint256 delta) {\n unchecked {\n delta = uint96(block.timestamp) - proof.timestamp;\n }\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n if (bridgeStatuses[transactionId] != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n BridgeProof memory proof = bridgeProofs[transactionId];\n if (proof.relayer != relayer) revert SenderIncorrect();\n return _timeSince(proof) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes memory request, address to) external onlyRole(RELAYER_ROLE) {\n bytes32 transactionId = keccak256(request);\n BridgeTransaction memory transaction = getBridgeTransaction(request);\n\n // update bridge tx status if able to claim origin collateral\n if (bridgeStatuses[transactionId] != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n\n BridgeProof memory proof = bridgeProofs[transactionId];\n if (proof.relayer != msg.sender) revert SenderIncorrect();\n if (_timeSince(proof) \u003c= DISPUTE_PERIOD) revert DisputePeriodNotPassed();\n\n bridgeStatuses[transactionId] = BridgeStatus.RELAYER_CLAIMED;\n\n // update protocol fees if origin fee amount exists\n if (transaction.originFeeAmount \u003e 0) protocolFees[transaction.originToken] += transaction.originFeeAmount;\n\n // transfer origin collateral less fee to specified address\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositClaimed(transactionId, msg.sender, to, token, amount);\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n if (bridgeStatuses[transactionId] != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(bridgeProofs[transactionId]) \u003e DISPUTE_PERIOD) revert DisputePeriodPassed();\n\n // @dev relayer gets slashed effectively if dest relay has gone thru\n bridgeStatuses[transactionId] = BridgeStatus.REQUESTED;\n delete bridgeProofs[transactionId];\n\n emit BridgeProofDisputed(transactionId, msg.sender);\n }\n\n /// @inheritdoc IFastBridge\n function refund(bytes memory request) external {\n bytes32 transactionId = keccak256(request);\n BridgeTransaction memory transaction = getBridgeTransaction(request);\n\n if (hasRole(REFUNDER_ROLE, msg.sender)) {\n // Refunder can refund if deadline has passed\n if (block.timestamp \u003c= transaction.deadline) revert DeadlineNotExceeded();\n } else {\n // Permissionless refund is allowed after REFUND_DELAY\n if (block.timestamp \u003c= transaction.deadline + REFUND_DELAY) revert DeadlineNotExceeded();\n }\n\n // set status to refunded if still in requested state\n if (bridgeStatuses[transactionId] != BridgeStatus.REQUESTED) revert StatusIncorrect();\n bridgeStatuses[transactionId] = BridgeStatus.REFUNDED;\n\n // transfer origin collateral back to original sender\n address to = transaction.originSender;\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount + transaction.originFeeAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n }\n}\n\n// test/FastBridgeMock.sol\n\ncontract FastBridgeMock is IFastBridge, Admin {\n // @dev the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @dev to prevent replays\n uint256 public nonce;\n\n function getBridgeTransaction(bytes memory request) public pure returns (BridgeTransaction memory) {\n return abi.decode(request, (BridgeTransaction));\n }\n\n // used for testing in go.\n // see: https://ethereum.stackexchange.com/questions/21155/how-to-expose-enum-in-solidity-contract\n // make sure to update fastbridge/status.go if this changes\n // or underliyng enum changes.\n //\n // TODO: a foundry test should be added to ensure this is always in sync.\n function getEnumKeyByValue(FastBridge.BridgeStatus keyValue) public pure returns (string memory) {\n if (FastBridge.BridgeStatus.NULL == keyValue) return \"NULL\";\n if (FastBridge.BridgeStatus.REQUESTED == keyValue) return \"REQUESTED\";\n if (FastBridge.BridgeStatus.RELAYER_PROVED == keyValue) return \"RELAYER_PROVED\";\n if (FastBridge.BridgeStatus.RELAYER_CLAIMED == keyValue) return \"RELAYER_CLAIMED\";\n if (FastBridge.BridgeStatus.REFUNDED == keyValue) return \"REFUNDED\";\n return \"\";\n }\n\n function mockBridgeRequest(bytes32 transactionId, address sender, BridgeParams memory params) external {\n uint256 originFeeAmount = (params.originAmount * protocolFeeRate) / FEE_BPS;\n params.originAmount -= originFeeAmount;\n\n bytes memory request = abi.encode(\n BridgeTransaction({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: params.originAmount, // includes relayer fee\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n sendChainGas: params.sendChainGas,\n deadline: params.deadline,\n nonce: nonce++ // increment nonce on every bridge\n })\n );\n\n emit BridgeRequested(\n transactionId,\n params.sender,\n request,\n params.dstChainId,\n params.originToken,\n params.destToken,\n params.originAmount,\n params.destAmount,\n params.sendChainGas\n );\n }\n\n function mockBridgeRequestRaw(bytes32 transactionId, address sender, bytes memory request) external {\n BridgeTransaction memory transaction = getBridgeTransaction(request);\n emit BridgeRequested(\n transactionId,\n transaction.originSender,\n request,\n transaction.destChainId,\n transaction.originToken,\n transaction.destToken,\n transaction.originAmount,\n transaction.destAmount,\n transaction.sendChainGas\n );\n }\n\n function mockBridgeRelayer(\n bytes32 transactionId,\n address relayer,\n address to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n )\n external\n {\n emit BridgeRelayed(\n transactionId, relayer, to, originChainId, originToken, destToken, originAmount, destAmount, chainGasAmount\n );\n }\n\n function bridge(BridgeParams memory params) external payable {\n revert(\"not implemented\");\n }\n\n function relay(bytes memory request) external payable {\n revert(\"not implemented\");\n }\n\n function prove(bytes memory request, bytes32 destTxHash) external {\n revert(\"not implemented\");\n }\n\n function canClaim(bytes32 transactionid, address relayer) external view returns (bool) {\n revert(\"not implemented\");\n }\n\n function claim(bytes memory request, address to) external {\n revert(\"not implemented\");\n }\n\n function dispute(bytes32 transactionId) external {\n revert(\"not implemented\");\n }\n\n function refund(bytes memory request) external {\n revert(\"not implemented\");\n }\n}\n","language":"Solidity","languageVersion":"0.8.20","compilerVersion":"0.8.20","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"","srcMapRuntime":"","abiDefinition":[{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldChainGasAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newChainGasAmount","type":"uint256"}],"name":"ChainGasAmountUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldFeeRate","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newFeeRate","type":"uint256"}],"name":"FeeRateUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"address","name":"recipient","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"FeesSwept","type":"event"},{"inputs":[{"internalType":"uint256","name":"newChainGasAmount","type":"uint256"}],"name":"setChainGasAmount","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"newFeeRate","type":"uint256"}],"name":"setProtocolFeeRate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"address","name":"recipient","type":"address"}],"name":"sweepProtocolFees","outputs":[],"stateMutability":"nonpayable","type":"function"}],"userDoc":{"kind":"user","methods":{},"version":1},"developerDoc":{"kind":"dev","methods":{},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.20+commit.a1b79de6\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"oldChainGasAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newChainGasAmount\",\"type\":\"uint256\"}],\"name\":\"ChainGasAmountUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"oldFeeRate\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newFeeRate\",\"type\":\"uint256\"}],\"name\":\"FeeRateUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"FeesSwept\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"newChainGasAmount\",\"type\":\"uint256\"}],\"name\":\"setChainGasAmount\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"newFeeRate\",\"type\":\"uint256\"}],\"name\":\"setProtocolFeeRate\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"}],\"name\":\"sweepProtocolFees\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeMock.sol\":\"IAdmin\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeMock.sol\":{\"keccak256\":\"0x620e81214ecd324ae8b971219291f176c454ce76fb1c01d656428096da8f1366\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://18e556772c12e13aa2d52a50cc7c48e676c8d5af22b90adaf7befb39cdd08e64\",\"dweb:/ipfs/QmPrQc98TxHCFMeuFNADyjr6Nqo52rHhHy1LBcsVdMRXjL\"]}},\"version\":1}"},"hashes":{"setChainGasAmount(uint256)":"b250fe6b","setProtocolFeeRate(uint256)":"b13aa2d6","sweepProtocolFees(address,address)":"06f333f2"}},"solidity/FastBridgeMock.sol:IERC165":{"code":"0x","runtime-code":"0x","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.20 ^0.8.20;\n\n// contracts/interfaces/IAdmin.sol\n\ninterface IAdmin {\n // ============ Events ============\n\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n event ChainGasAmountUpdated(uint256 oldChainGasAmount, uint256 newChainGasAmount);\n\n // ============ Methods ============\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n\n function setChainGasAmount(uint256 newChainGasAmount) external;\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/libs/Errors.sol\n\nerror DeadlineExceeded();\nerror DeadlineNotExceeded();\nerror DeadlineTooShort();\nerror InsufficientOutputAmount();\n\nerror MsgValueIncorrect();\nerror PoolNotFound();\nerror TokenAddressMismatch();\nerror TokenNotContract();\nerror TokenNotETH();\nerror TokensIdentical();\n\nerror ChainIncorrect();\nerror AmountIncorrect();\nerror ZeroAddress();\n\nerror DisputePeriodNotPassed();\nerror DisputePeriodPassed();\nerror SenderIncorrect();\nerror StatusIncorrect();\nerror TransactionIdIncorrect();\nerror TransactionRelayed();\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// contracts/libs/UniversalToken.sol\n\nlibrary UniversalTokenLib {\n using SafeERC20 for IERC20;\n\n address internal constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Transfers tokens to the given account. Reverts if transfer is not successful.\n /// @dev This might trigger fallback, if ETH is transferred to the contract.\n /// Make sure this can not lead to reentrancy attacks.\n function universalTransfer(address token, address to, uint256 value) internal {\n // Don't do anything, if need to send tokens to this address\n if (to == address(this)) return;\n // Don't do anything, if trying to send zero value\n if (value == 0) return;\n if (token == ETH_ADDRESS) {\n /// @dev Note: this can potentially lead to executing code in `to`.\n // solhint-disable-next-line avoid-low-level-calls\n (bool success,) = to.call{value: value}(\"\");\n require(success, \"ETH transfer failed\");\n } else {\n IERC20(token).safeTransfer(to, value);\n }\n }\n\n /// @notice Issues an infinite allowance to the spender, if the current allowance is insufficient\n /// to spend the given amount.\n function universalApproveInfinity(address token, address spender, uint256 amountToSpend) internal {\n // ETH Chad doesn't require your approval\n if (token == ETH_ADDRESS) return;\n // No-op if allowance is already sufficient\n uint256 allowance = IERC20(token).allowance(address(this), spender);\n if (allowance \u003e= amountToSpend) return;\n // Otherwise, reset approval to 0 and set to max allowance\n if (allowance \u003e 0) IERC20(token).safeDecreaseAllowance(spender, allowance);\n IERC20(token).safeIncreaseAllowance(spender, type(uint256).max);\n }\n\n /// @notice Returns the balance of the given token (or native ETH) for the given account.\n function universalBalanceOf(address token, address account) internal view returns (uint256) {\n if (token == ETH_ADDRESS) {\n return account.balance;\n } else {\n return IERC20(token).balanceOf(account);\n }\n }\n\n /// @dev Checks that token is a contract and not ETH_ADDRESS.\n function assertIsContract(address token) internal view {\n // Check that ETH_ADDRESS was not used (in case this is a predeploy on any of the chains)\n if (token == UniversalTokenLib.ETH_ADDRESS) revert TokenNotContract();\n // Check that token is not an EOA\n if (token.code.length == 0) revert TokenNotContract();\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/Admin.sol\n\ncontract Admin is IAdmin, AccessControlEnumerable {\n using UniversalTokenLib for address;\n\n bytes32 public constant RELAYER_ROLE = keccak256(\"RELAYER_ROLE\");\n bytes32 public constant REFUNDER_ROLE = keccak256(\"REFUNDER_ROLE\");\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n uint256 public constant FEE_BPS = 1e6;\n uint256 public constant FEE_RATE_MAX = 0.01e6; // max 1% on origin amount\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Chain gas amount to forward as rebate if requested\n uint256 public chainGasAmount;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n }\n\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n require(newFeeRate \u003c= FEE_RATE_MAX, \"newFeeRate \u003e max\");\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n token.universalTransfer(recipient, feeAmount);\n emit FeesSwept(token, recipient, feeAmount);\n }\n\n function setChainGasAmount(uint256 newChainGasAmount) external onlyRole(GOVERNOR_ROLE) {\n uint256 oldChainGasAmount = chainGasAmount;\n chainGasAmount = newChainGasAmount;\n emit ChainGasAmountUpdated(oldChainGasAmount, newChainGasAmount);\n }\n}\n\n// contracts/FastBridge.sol\n\ncontract FastBridge is IFastBridge, Admin {\n using SafeERC20 for IERC20;\n using UniversalTokenLib for address;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Delay for a transaction after which it could be permisionlessly refunded\n uint256 public constant REFUND_DELAY = 7 days;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeStatus) public bridgeStatuses;\n /// @notice Proof of relayed bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeProof) public bridgeProofs;\n /// @notice Whether bridge has been relayed on destination chain\n mapping(bytes32 =\u003e bool) public bridgeRelays;\n\n /// @dev to prevent replays\n uint256 public nonce;\n // @dev the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @notice Pulls a requested token from the user to the requested recipient.\n /// @dev Be careful of re-entrancy issues when msg.value \u003e 0 and recipient != address(this)\n function _pullToken(address recipient, address token, uint256 amount) internal returns (uint256 amountPulled) {\n if (token != UniversalTokenLib.ETH_ADDRESS) {\n token.assertIsContract();\n // Record token balance before transfer\n amountPulled = IERC20(token).balanceOf(recipient);\n // Token needs to be pulled only if msg.value is zero\n // This way user can specify WETH as the origin asset\n IERC20(token).safeTransferFrom(msg.sender, recipient, amount);\n // Use the difference between the recorded balance and the current balance as the amountPulled\n amountPulled = IERC20(token).balanceOf(recipient) - amountPulled;\n } else {\n // Otherwise, we need to check that ETH amount matches msg.value\n if (amount != msg.value) revert MsgValueIncorrect();\n // Transfer value to recipient if not this address\n if (recipient != address(this)) token.universalTransfer(recipient, amount);\n // We will forward msg.value in the external call later, if recipient is not this contract\n amountPulled = msg.value;\n }\n }\n\n /// @inheritdoc IFastBridge\n function getBridgeTransaction(bytes memory request) public pure returns (BridgeTransaction memory) {\n return abi.decode(request, (BridgeTransaction));\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n // check bridge params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n\n // transfer tokens to bridge contract\n // @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _pullToken(address(this), params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n\n // set status to requested\n bytes memory request = abi.encode(\n BridgeTransaction({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n sendChainGas: params.sendChainGas,\n deadline: params.deadline,\n nonce: nonce++ // increment nonce on every bridge\n })\n );\n bytes32 transactionId = keccak256(request);\n bridgeStatuses[transactionId] = BridgeStatus.REQUESTED;\n\n emit BridgeRequested(\n transactionId,\n params.sender,\n request,\n params.dstChainId,\n params.originToken,\n params.destToken,\n originAmount,\n params.destAmount,\n params.sendChainGas\n );\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes memory request) external payable onlyRole(RELAYER_ROLE) {\n bytes32 transactionId = keccak256(request);\n BridgeTransaction memory transaction = getBridgeTransaction(request);\n if (transaction.destChainId != uint32(block.chainid)) revert ChainIncorrect();\n\n // check haven't exceeded deadline for relay to happen\n if (block.timestamp \u003e transaction.deadline) revert DeadlineExceeded();\n\n // mark bridge transaction as relayed\n if (bridgeRelays[transactionId]) revert TransactionRelayed();\n bridgeRelays[transactionId] = true;\n\n // transfer tokens to recipient on destination chain and gas rebate if requested\n address to = transaction.destRecipient;\n address token = transaction.destToken;\n uint256 amount = transaction.destAmount;\n\n uint256 rebate = chainGasAmount;\n if (!transaction.sendChainGas) {\n // forward erc20\n rebate = 0;\n _pullToken(to, token, amount);\n } else if (token == UniversalTokenLib.ETH_ADDRESS) {\n // lump in gas rebate into amount in native gas token\n _pullToken(to, token, amount + rebate);\n } else {\n // forward erc20 then forward gas rebate in native gas token\n _pullToken(to, token, amount);\n _pullToken(to, UniversalTokenLib.ETH_ADDRESS, rebate);\n }\n\n emit BridgeRelayed(\n transactionId,\n msg.sender,\n to,\n transaction.originChainId,\n transaction.originToken,\n transaction.destToken,\n transaction.originAmount,\n transaction.destAmount,\n rebate\n );\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes memory request, bytes32 destTxHash) external onlyRole(RELAYER_ROLE) {\n bytes32 transactionId = keccak256(request);\n // update bridge tx status given proof provided\n if (bridgeStatuses[transactionId] != BridgeStatus.REQUESTED) revert StatusIncorrect();\n bridgeStatuses[transactionId] = BridgeStatus.RELAYER_PROVED;\n bridgeProofs[transactionId] = BridgeProof({timestamp: uint96(block.timestamp), relayer: msg.sender}); // overflow ok\n\n emit BridgeProofProvided(transactionId, msg.sender, destTxHash);\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint96(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint96).max but\n /// proof.timestamp \u003c type(uint96).max via unchecked statement\n /// @param proof The bridge proof\n /// @return delta Time delta since proof submitted\n function _timeSince(BridgeProof memory proof) internal view returns (uint256 delta) {\n unchecked {\n delta = uint96(block.timestamp) - proof.timestamp;\n }\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n if (bridgeStatuses[transactionId] != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n BridgeProof memory proof = bridgeProofs[transactionId];\n if (proof.relayer != relayer) revert SenderIncorrect();\n return _timeSince(proof) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes memory request, address to) external onlyRole(RELAYER_ROLE) {\n bytes32 transactionId = keccak256(request);\n BridgeTransaction memory transaction = getBridgeTransaction(request);\n\n // update bridge tx status if able to claim origin collateral\n if (bridgeStatuses[transactionId] != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n\n BridgeProof memory proof = bridgeProofs[transactionId];\n if (proof.relayer != msg.sender) revert SenderIncorrect();\n if (_timeSince(proof) \u003c= DISPUTE_PERIOD) revert DisputePeriodNotPassed();\n\n bridgeStatuses[transactionId] = BridgeStatus.RELAYER_CLAIMED;\n\n // update protocol fees if origin fee amount exists\n if (transaction.originFeeAmount \u003e 0) protocolFees[transaction.originToken] += transaction.originFeeAmount;\n\n // transfer origin collateral less fee to specified address\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositClaimed(transactionId, msg.sender, to, token, amount);\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n if (bridgeStatuses[transactionId] != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(bridgeProofs[transactionId]) \u003e DISPUTE_PERIOD) revert DisputePeriodPassed();\n\n // @dev relayer gets slashed effectively if dest relay has gone thru\n bridgeStatuses[transactionId] = BridgeStatus.REQUESTED;\n delete bridgeProofs[transactionId];\n\n emit BridgeProofDisputed(transactionId, msg.sender);\n }\n\n /// @inheritdoc IFastBridge\n function refund(bytes memory request) external {\n bytes32 transactionId = keccak256(request);\n BridgeTransaction memory transaction = getBridgeTransaction(request);\n\n if (hasRole(REFUNDER_ROLE, msg.sender)) {\n // Refunder can refund if deadline has passed\n if (block.timestamp \u003c= transaction.deadline) revert DeadlineNotExceeded();\n } else {\n // Permissionless refund is allowed after REFUND_DELAY\n if (block.timestamp \u003c= transaction.deadline + REFUND_DELAY) revert DeadlineNotExceeded();\n }\n\n // set status to refunded if still in requested state\n if (bridgeStatuses[transactionId] != BridgeStatus.REQUESTED) revert StatusIncorrect();\n bridgeStatuses[transactionId] = BridgeStatus.REFUNDED;\n\n // transfer origin collateral back to original sender\n address to = transaction.originSender;\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount + transaction.originFeeAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n }\n}\n\n// test/FastBridgeMock.sol\n\ncontract FastBridgeMock is IFastBridge, Admin {\n // @dev the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @dev to prevent replays\n uint256 public nonce;\n\n function getBridgeTransaction(bytes memory request) public pure returns (BridgeTransaction memory) {\n return abi.decode(request, (BridgeTransaction));\n }\n\n // used for testing in go.\n // see: https://ethereum.stackexchange.com/questions/21155/how-to-expose-enum-in-solidity-contract\n // make sure to update fastbridge/status.go if this changes\n // or underliyng enum changes.\n //\n // TODO: a foundry test should be added to ensure this is always in sync.\n function getEnumKeyByValue(FastBridge.BridgeStatus keyValue) public pure returns (string memory) {\n if (FastBridge.BridgeStatus.NULL == keyValue) return \"NULL\";\n if (FastBridge.BridgeStatus.REQUESTED == keyValue) return \"REQUESTED\";\n if (FastBridge.BridgeStatus.RELAYER_PROVED == keyValue) return \"RELAYER_PROVED\";\n if (FastBridge.BridgeStatus.RELAYER_CLAIMED == keyValue) return \"RELAYER_CLAIMED\";\n if (FastBridge.BridgeStatus.REFUNDED == keyValue) return \"REFUNDED\";\n return \"\";\n }\n\n function mockBridgeRequest(bytes32 transactionId, address sender, BridgeParams memory params) external {\n uint256 originFeeAmount = (params.originAmount * protocolFeeRate) / FEE_BPS;\n params.originAmount -= originFeeAmount;\n\n bytes memory request = abi.encode(\n BridgeTransaction({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: params.originAmount, // includes relayer fee\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n sendChainGas: params.sendChainGas,\n deadline: params.deadline,\n nonce: nonce++ // increment nonce on every bridge\n })\n );\n\n emit BridgeRequested(\n transactionId,\n params.sender,\n request,\n params.dstChainId,\n params.originToken,\n params.destToken,\n params.originAmount,\n params.destAmount,\n params.sendChainGas\n );\n }\n\n function mockBridgeRequestRaw(bytes32 transactionId, address sender, bytes memory request) external {\n BridgeTransaction memory transaction = getBridgeTransaction(request);\n emit BridgeRequested(\n transactionId,\n transaction.originSender,\n request,\n transaction.destChainId,\n transaction.originToken,\n transaction.destToken,\n transaction.originAmount,\n transaction.destAmount,\n transaction.sendChainGas\n );\n }\n\n function mockBridgeRelayer(\n bytes32 transactionId,\n address relayer,\n address to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n )\n external\n {\n emit BridgeRelayed(\n transactionId, relayer, to, originChainId, originToken, destToken, originAmount, destAmount, chainGasAmount\n );\n }\n\n function bridge(BridgeParams memory params) external payable {\n revert(\"not implemented\");\n }\n\n function relay(bytes memory request) external payable {\n revert(\"not implemented\");\n }\n\n function prove(bytes memory request, bytes32 destTxHash) external {\n revert(\"not implemented\");\n }\n\n function canClaim(bytes32 transactionid, address relayer) external view returns (bool) {\n revert(\"not implemented\");\n }\n\n function claim(bytes memory request, address to) external {\n revert(\"not implemented\");\n }\n\n function dispute(bytes32 transactionId) external {\n revert(\"not implemented\");\n }\n\n function refund(bytes memory request) external {\n revert(\"not implemented\");\n }\n}\n","language":"Solidity","languageVersion":"0.8.20","compilerVersion":"0.8.20","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"","srcMapRuntime":"","abiDefinition":[{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"}],"userDoc":{"kind":"user","methods":{},"version":1},"developerDoc":{"details":"Interface of the ERC165 standard, as defined in the https://eips.ethereum.org/EIPS/eip-165[EIP]. Implementers can declare support of contract interfaces, which can then be queried by others ({ERC165Checker}). For an implementation, see {ERC165}.","kind":"dev","methods":{"supportsInterface(bytes4)":{"details":"Returns true if this contract implements the interface defined by `interfaceId`. See the corresponding https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section] to learn more about how these ids are created. This function call must use less than 30 000 gas."}},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.20+commit.a1b79de6\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"bytes4\",\"name\":\"interfaceId\",\"type\":\"bytes4\"}],\"name\":\"supportsInterface\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"}],\"devdoc\":{\"details\":\"Interface of the ERC165 standard, as defined in the https://eips.ethereum.org/EIPS/eip-165[EIP]. Implementers can declare support of contract interfaces, which can then be queried by others ({ERC165Checker}). For an implementation, see {ERC165}.\",\"kind\":\"dev\",\"methods\":{\"supportsInterface(bytes4)\":{\"details\":\"Returns true if this contract implements the interface defined by `interfaceId`. See the corresponding https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section] to learn more about how these ids are created. This function call must use less than 30 000 gas.\"}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeMock.sol\":\"IERC165\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeMock.sol\":{\"keccak256\":\"0x620e81214ecd324ae8b971219291f176c454ce76fb1c01d656428096da8f1366\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://18e556772c12e13aa2d52a50cc7c48e676c8d5af22b90adaf7befb39cdd08e64\",\"dweb:/ipfs/QmPrQc98TxHCFMeuFNADyjr6Nqo52rHhHy1LBcsVdMRXjL\"]}},\"version\":1}"},"hashes":{"supportsInterface(bytes4)":"01ffc9a7"}},"solidity/FastBridgeMock.sol:IERC20":{"code":"0x","runtime-code":"0x","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.20 ^0.8.20;\n\n// contracts/interfaces/IAdmin.sol\n\ninterface IAdmin {\n // ============ Events ============\n\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n event ChainGasAmountUpdated(uint256 oldChainGasAmount, uint256 newChainGasAmount);\n\n // ============ Methods ============\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n\n function setChainGasAmount(uint256 newChainGasAmount) external;\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/libs/Errors.sol\n\nerror DeadlineExceeded();\nerror DeadlineNotExceeded();\nerror DeadlineTooShort();\nerror InsufficientOutputAmount();\n\nerror MsgValueIncorrect();\nerror PoolNotFound();\nerror TokenAddressMismatch();\nerror TokenNotContract();\nerror TokenNotETH();\nerror TokensIdentical();\n\nerror ChainIncorrect();\nerror AmountIncorrect();\nerror ZeroAddress();\n\nerror DisputePeriodNotPassed();\nerror DisputePeriodPassed();\nerror SenderIncorrect();\nerror StatusIncorrect();\nerror TransactionIdIncorrect();\nerror TransactionRelayed();\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// contracts/libs/UniversalToken.sol\n\nlibrary UniversalTokenLib {\n using SafeERC20 for IERC20;\n\n address internal constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Transfers tokens to the given account. Reverts if transfer is not successful.\n /// @dev This might trigger fallback, if ETH is transferred to the contract.\n /// Make sure this can not lead to reentrancy attacks.\n function universalTransfer(address token, address to, uint256 value) internal {\n // Don't do anything, if need to send tokens to this address\n if (to == address(this)) return;\n // Don't do anything, if trying to send zero value\n if (value == 0) return;\n if (token == ETH_ADDRESS) {\n /// @dev Note: this can potentially lead to executing code in `to`.\n // solhint-disable-next-line avoid-low-level-calls\n (bool success,) = to.call{value: value}(\"\");\n require(success, \"ETH transfer failed\");\n } else {\n IERC20(token).safeTransfer(to, value);\n }\n }\n\n /// @notice Issues an infinite allowance to the spender, if the current allowance is insufficient\n /// to spend the given amount.\n function universalApproveInfinity(address token, address spender, uint256 amountToSpend) internal {\n // ETH Chad doesn't require your approval\n if (token == ETH_ADDRESS) return;\n // No-op if allowance is already sufficient\n uint256 allowance = IERC20(token).allowance(address(this), spender);\n if (allowance \u003e= amountToSpend) return;\n // Otherwise, reset approval to 0 and set to max allowance\n if (allowance \u003e 0) IERC20(token).safeDecreaseAllowance(spender, allowance);\n IERC20(token).safeIncreaseAllowance(spender, type(uint256).max);\n }\n\n /// @notice Returns the balance of the given token (or native ETH) for the given account.\n function universalBalanceOf(address token, address account) internal view returns (uint256) {\n if (token == ETH_ADDRESS) {\n return account.balance;\n } else {\n return IERC20(token).balanceOf(account);\n }\n }\n\n /// @dev Checks that token is a contract and not ETH_ADDRESS.\n function assertIsContract(address token) internal view {\n // Check that ETH_ADDRESS was not used (in case this is a predeploy on any of the chains)\n if (token == UniversalTokenLib.ETH_ADDRESS) revert TokenNotContract();\n // Check that token is not an EOA\n if (token.code.length == 0) revert TokenNotContract();\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/Admin.sol\n\ncontract Admin is IAdmin, AccessControlEnumerable {\n using UniversalTokenLib for address;\n\n bytes32 public constant RELAYER_ROLE = keccak256(\"RELAYER_ROLE\");\n bytes32 public constant REFUNDER_ROLE = keccak256(\"REFUNDER_ROLE\");\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n uint256 public constant FEE_BPS = 1e6;\n uint256 public constant FEE_RATE_MAX = 0.01e6; // max 1% on origin amount\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Chain gas amount to forward as rebate if requested\n uint256 public chainGasAmount;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n }\n\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n require(newFeeRate \u003c= FEE_RATE_MAX, \"newFeeRate \u003e max\");\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n token.universalTransfer(recipient, feeAmount);\n emit FeesSwept(token, recipient, feeAmount);\n }\n\n function setChainGasAmount(uint256 newChainGasAmount) external onlyRole(GOVERNOR_ROLE) {\n uint256 oldChainGasAmount = chainGasAmount;\n chainGasAmount = newChainGasAmount;\n emit ChainGasAmountUpdated(oldChainGasAmount, newChainGasAmount);\n }\n}\n\n// contracts/FastBridge.sol\n\ncontract FastBridge is IFastBridge, Admin {\n using SafeERC20 for IERC20;\n using UniversalTokenLib for address;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Delay for a transaction after which it could be permisionlessly refunded\n uint256 public constant REFUND_DELAY = 7 days;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeStatus) public bridgeStatuses;\n /// @notice Proof of relayed bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeProof) public bridgeProofs;\n /// @notice Whether bridge has been relayed on destination chain\n mapping(bytes32 =\u003e bool) public bridgeRelays;\n\n /// @dev to prevent replays\n uint256 public nonce;\n // @dev the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @notice Pulls a requested token from the user to the requested recipient.\n /// @dev Be careful of re-entrancy issues when msg.value \u003e 0 and recipient != address(this)\n function _pullToken(address recipient, address token, uint256 amount) internal returns (uint256 amountPulled) {\n if (token != UniversalTokenLib.ETH_ADDRESS) {\n token.assertIsContract();\n // Record token balance before transfer\n amountPulled = IERC20(token).balanceOf(recipient);\n // Token needs to be pulled only if msg.value is zero\n // This way user can specify WETH as the origin asset\n IERC20(token).safeTransferFrom(msg.sender, recipient, amount);\n // Use the difference between the recorded balance and the current balance as the amountPulled\n amountPulled = IERC20(token).balanceOf(recipient) - amountPulled;\n } else {\n // Otherwise, we need to check that ETH amount matches msg.value\n if (amount != msg.value) revert MsgValueIncorrect();\n // Transfer value to recipient if not this address\n if (recipient != address(this)) token.universalTransfer(recipient, amount);\n // We will forward msg.value in the external call later, if recipient is not this contract\n amountPulled = msg.value;\n }\n }\n\n /// @inheritdoc IFastBridge\n function getBridgeTransaction(bytes memory request) public pure returns (BridgeTransaction memory) {\n return abi.decode(request, (BridgeTransaction));\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n // check bridge params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n\n // transfer tokens to bridge contract\n // @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _pullToken(address(this), params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n\n // set status to requested\n bytes memory request = abi.encode(\n BridgeTransaction({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n sendChainGas: params.sendChainGas,\n deadline: params.deadline,\n nonce: nonce++ // increment nonce on every bridge\n })\n );\n bytes32 transactionId = keccak256(request);\n bridgeStatuses[transactionId] = BridgeStatus.REQUESTED;\n\n emit BridgeRequested(\n transactionId,\n params.sender,\n request,\n params.dstChainId,\n params.originToken,\n params.destToken,\n originAmount,\n params.destAmount,\n params.sendChainGas\n );\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes memory request) external payable onlyRole(RELAYER_ROLE) {\n bytes32 transactionId = keccak256(request);\n BridgeTransaction memory transaction = getBridgeTransaction(request);\n if (transaction.destChainId != uint32(block.chainid)) revert ChainIncorrect();\n\n // check haven't exceeded deadline for relay to happen\n if (block.timestamp \u003e transaction.deadline) revert DeadlineExceeded();\n\n // mark bridge transaction as relayed\n if (bridgeRelays[transactionId]) revert TransactionRelayed();\n bridgeRelays[transactionId] = true;\n\n // transfer tokens to recipient on destination chain and gas rebate if requested\n address to = transaction.destRecipient;\n address token = transaction.destToken;\n uint256 amount = transaction.destAmount;\n\n uint256 rebate = chainGasAmount;\n if (!transaction.sendChainGas) {\n // forward erc20\n rebate = 0;\n _pullToken(to, token, amount);\n } else if (token == UniversalTokenLib.ETH_ADDRESS) {\n // lump in gas rebate into amount in native gas token\n _pullToken(to, token, amount + rebate);\n } else {\n // forward erc20 then forward gas rebate in native gas token\n _pullToken(to, token, amount);\n _pullToken(to, UniversalTokenLib.ETH_ADDRESS, rebate);\n }\n\n emit BridgeRelayed(\n transactionId,\n msg.sender,\n to,\n transaction.originChainId,\n transaction.originToken,\n transaction.destToken,\n transaction.originAmount,\n transaction.destAmount,\n rebate\n );\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes memory request, bytes32 destTxHash) external onlyRole(RELAYER_ROLE) {\n bytes32 transactionId = keccak256(request);\n // update bridge tx status given proof provided\n if (bridgeStatuses[transactionId] != BridgeStatus.REQUESTED) revert StatusIncorrect();\n bridgeStatuses[transactionId] = BridgeStatus.RELAYER_PROVED;\n bridgeProofs[transactionId] = BridgeProof({timestamp: uint96(block.timestamp), relayer: msg.sender}); // overflow ok\n\n emit BridgeProofProvided(transactionId, msg.sender, destTxHash);\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint96(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint96).max but\n /// proof.timestamp \u003c type(uint96).max via unchecked statement\n /// @param proof The bridge proof\n /// @return delta Time delta since proof submitted\n function _timeSince(BridgeProof memory proof) internal view returns (uint256 delta) {\n unchecked {\n delta = uint96(block.timestamp) - proof.timestamp;\n }\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n if (bridgeStatuses[transactionId] != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n BridgeProof memory proof = bridgeProofs[transactionId];\n if (proof.relayer != relayer) revert SenderIncorrect();\n return _timeSince(proof) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes memory request, address to) external onlyRole(RELAYER_ROLE) {\n bytes32 transactionId = keccak256(request);\n BridgeTransaction memory transaction = getBridgeTransaction(request);\n\n // update bridge tx status if able to claim origin collateral\n if (bridgeStatuses[transactionId] != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n\n BridgeProof memory proof = bridgeProofs[transactionId];\n if (proof.relayer != msg.sender) revert SenderIncorrect();\n if (_timeSince(proof) \u003c= DISPUTE_PERIOD) revert DisputePeriodNotPassed();\n\n bridgeStatuses[transactionId] = BridgeStatus.RELAYER_CLAIMED;\n\n // update protocol fees if origin fee amount exists\n if (transaction.originFeeAmount \u003e 0) protocolFees[transaction.originToken] += transaction.originFeeAmount;\n\n // transfer origin collateral less fee to specified address\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositClaimed(transactionId, msg.sender, to, token, amount);\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n if (bridgeStatuses[transactionId] != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(bridgeProofs[transactionId]) \u003e DISPUTE_PERIOD) revert DisputePeriodPassed();\n\n // @dev relayer gets slashed effectively if dest relay has gone thru\n bridgeStatuses[transactionId] = BridgeStatus.REQUESTED;\n delete bridgeProofs[transactionId];\n\n emit BridgeProofDisputed(transactionId, msg.sender);\n }\n\n /// @inheritdoc IFastBridge\n function refund(bytes memory request) external {\n bytes32 transactionId = keccak256(request);\n BridgeTransaction memory transaction = getBridgeTransaction(request);\n\n if (hasRole(REFUNDER_ROLE, msg.sender)) {\n // Refunder can refund if deadline has passed\n if (block.timestamp \u003c= transaction.deadline) revert DeadlineNotExceeded();\n } else {\n // Permissionless refund is allowed after REFUND_DELAY\n if (block.timestamp \u003c= transaction.deadline + REFUND_DELAY) revert DeadlineNotExceeded();\n }\n\n // set status to refunded if still in requested state\n if (bridgeStatuses[transactionId] != BridgeStatus.REQUESTED) revert StatusIncorrect();\n bridgeStatuses[transactionId] = BridgeStatus.REFUNDED;\n\n // transfer origin collateral back to original sender\n address to = transaction.originSender;\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount + transaction.originFeeAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n }\n}\n\n// test/FastBridgeMock.sol\n\ncontract FastBridgeMock is IFastBridge, Admin {\n // @dev the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @dev to prevent replays\n uint256 public nonce;\n\n function getBridgeTransaction(bytes memory request) public pure returns (BridgeTransaction memory) {\n return abi.decode(request, (BridgeTransaction));\n }\n\n // used for testing in go.\n // see: https://ethereum.stackexchange.com/questions/21155/how-to-expose-enum-in-solidity-contract\n // make sure to update fastbridge/status.go if this changes\n // or underliyng enum changes.\n //\n // TODO: a foundry test should be added to ensure this is always in sync.\n function getEnumKeyByValue(FastBridge.BridgeStatus keyValue) public pure returns (string memory) {\n if (FastBridge.BridgeStatus.NULL == keyValue) return \"NULL\";\n if (FastBridge.BridgeStatus.REQUESTED == keyValue) return \"REQUESTED\";\n if (FastBridge.BridgeStatus.RELAYER_PROVED == keyValue) return \"RELAYER_PROVED\";\n if (FastBridge.BridgeStatus.RELAYER_CLAIMED == keyValue) return \"RELAYER_CLAIMED\";\n if (FastBridge.BridgeStatus.REFUNDED == keyValue) return \"REFUNDED\";\n return \"\";\n }\n\n function mockBridgeRequest(bytes32 transactionId, address sender, BridgeParams memory params) external {\n uint256 originFeeAmount = (params.originAmount * protocolFeeRate) / FEE_BPS;\n params.originAmount -= originFeeAmount;\n\n bytes memory request = abi.encode(\n BridgeTransaction({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: params.originAmount, // includes relayer fee\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n sendChainGas: params.sendChainGas,\n deadline: params.deadline,\n nonce: nonce++ // increment nonce on every bridge\n })\n );\n\n emit BridgeRequested(\n transactionId,\n params.sender,\n request,\n params.dstChainId,\n params.originToken,\n params.destToken,\n params.originAmount,\n params.destAmount,\n params.sendChainGas\n );\n }\n\n function mockBridgeRequestRaw(bytes32 transactionId, address sender, bytes memory request) external {\n BridgeTransaction memory transaction = getBridgeTransaction(request);\n emit BridgeRequested(\n transactionId,\n transaction.originSender,\n request,\n transaction.destChainId,\n transaction.originToken,\n transaction.destToken,\n transaction.originAmount,\n transaction.destAmount,\n transaction.sendChainGas\n );\n }\n\n function mockBridgeRelayer(\n bytes32 transactionId,\n address relayer,\n address to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n )\n external\n {\n emit BridgeRelayed(\n transactionId, relayer, to, originChainId, originToken, destToken, originAmount, destAmount, chainGasAmount\n );\n }\n\n function bridge(BridgeParams memory params) external payable {\n revert(\"not implemented\");\n }\n\n function relay(bytes memory request) external payable {\n revert(\"not implemented\");\n }\n\n function prove(bytes memory request, bytes32 destTxHash) external {\n revert(\"not implemented\");\n }\n\n function canClaim(bytes32 transactionid, address relayer) external view returns (bool) {\n revert(\"not implemented\");\n }\n\n function claim(bytes memory request, address to) external {\n revert(\"not implemented\");\n }\n\n function dispute(bytes32 transactionId) external {\n revert(\"not implemented\");\n }\n\n function refund(bytes memory request) external {\n revert(\"not implemented\");\n }\n}\n","language":"Solidity","languageVersion":"0.8.20","compilerVersion":"0.8.20","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"","srcMapRuntime":"","abiDefinition":[{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Transfer","type":"event"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"}],"userDoc":{"kind":"user","methods":{},"version":1},"developerDoc":{"details":"Interface of the ERC20 standard as defined in the EIP.","events":{"Approval(address,address,uint256)":{"details":"Emitted when the allowance of a `spender` for an `owner` is set by a call to {approve}. `value` is the new allowance."},"Transfer(address,address,uint256)":{"details":"Emitted when `value` tokens are moved from one account (`from`) to another (`to`). Note that `value` may be zero."}},"kind":"dev","methods":{"allowance(address,address)":{"details":"Returns the remaining number of tokens that `spender` will be allowed to spend on behalf of `owner` through {transferFrom}. This is zero by default. This value changes when {approve} or {transferFrom} are called."},"approve(address,uint256)":{"details":"Sets a `value` amount of tokens as the allowance of `spender` over the caller's tokens. Returns a boolean value indicating whether the operation succeeded. IMPORTANT: Beware that changing an allowance with this method brings the risk that someone may use both the old and the new allowance by unfortunate transaction ordering. One possible solution to mitigate this race condition is to first reduce the spender's allowance to 0 and set the desired value afterwards: https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 Emits an {Approval} event."},"balanceOf(address)":{"details":"Returns the value of tokens owned by `account`."},"totalSupply()":{"details":"Returns the value of tokens in existence."},"transfer(address,uint256)":{"details":"Moves a `value` amount of tokens from the caller's account to `to`. Returns a boolean value indicating whether the operation succeeded. Emits a {Transfer} event."},"transferFrom(address,address,uint256)":{"details":"Moves a `value` amount of tokens from `from` to `to` using the allowance mechanism. `value` is then deducted from the caller's allowance. Returns a boolean value indicating whether the operation succeeded. Emits a {Transfer} event."}},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.20+commit.a1b79de6\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"Approval\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"Transfer\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"}],\"name\":\"allowance\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"approve\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"balanceOf\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"totalSupply\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"transfer\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"transferFrom\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"details\":\"Interface of the ERC20 standard as defined in the EIP.\",\"events\":{\"Approval(address,address,uint256)\":{\"details\":\"Emitted when the allowance of a `spender` for an `owner` is set by a call to {approve}. `value` is the new allowance.\"},\"Transfer(address,address,uint256)\":{\"details\":\"Emitted when `value` tokens are moved from one account (`from`) to another (`to`). Note that `value` may be zero.\"}},\"kind\":\"dev\",\"methods\":{\"allowance(address,address)\":{\"details\":\"Returns the remaining number of tokens that `spender` will be allowed to spend on behalf of `owner` through {transferFrom}. This is zero by default. This value changes when {approve} or {transferFrom} are called.\"},\"approve(address,uint256)\":{\"details\":\"Sets a `value` amount of tokens as the allowance of `spender` over the caller's tokens. Returns a boolean value indicating whether the operation succeeded. IMPORTANT: Beware that changing an allowance with this method brings the risk that someone may use both the old and the new allowance by unfortunate transaction ordering. One possible solution to mitigate this race condition is to first reduce the spender's allowance to 0 and set the desired value afterwards: https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 Emits an {Approval} event.\"},\"balanceOf(address)\":{\"details\":\"Returns the value of tokens owned by `account`.\"},\"totalSupply()\":{\"details\":\"Returns the value of tokens in existence.\"},\"transfer(address,uint256)\":{\"details\":\"Moves a `value` amount of tokens from the caller's account to `to`. Returns a boolean value indicating whether the operation succeeded. Emits a {Transfer} event.\"},\"transferFrom(address,address,uint256)\":{\"details\":\"Moves a `value` amount of tokens from `from` to `to` using the allowance mechanism. `value` is then deducted from the caller's allowance. Returns a boolean value indicating whether the operation succeeded. Emits a {Transfer} event.\"}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeMock.sol\":\"IERC20\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeMock.sol\":{\"keccak256\":\"0x620e81214ecd324ae8b971219291f176c454ce76fb1c01d656428096da8f1366\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://18e556772c12e13aa2d52a50cc7c48e676c8d5af22b90adaf7befb39cdd08e64\",\"dweb:/ipfs/QmPrQc98TxHCFMeuFNADyjr6Nqo52rHhHy1LBcsVdMRXjL\"]}},\"version\":1}"},"hashes":{"allowance(address,address)":"dd62ed3e","approve(address,uint256)":"095ea7b3","balanceOf(address)":"70a08231","totalSupply()":"18160ddd","transfer(address,uint256)":"a9059cbb","transferFrom(address,address,uint256)":"23b872dd"}},"solidity/FastBridgeMock.sol:IERC20Permit":{"code":"0x","runtime-code":"0x","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.20 ^0.8.20;\n\n// contracts/interfaces/IAdmin.sol\n\ninterface IAdmin {\n // ============ Events ============\n\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n event ChainGasAmountUpdated(uint256 oldChainGasAmount, uint256 newChainGasAmount);\n\n // ============ Methods ============\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n\n function setChainGasAmount(uint256 newChainGasAmount) external;\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/libs/Errors.sol\n\nerror DeadlineExceeded();\nerror DeadlineNotExceeded();\nerror DeadlineTooShort();\nerror InsufficientOutputAmount();\n\nerror MsgValueIncorrect();\nerror PoolNotFound();\nerror TokenAddressMismatch();\nerror TokenNotContract();\nerror TokenNotETH();\nerror TokensIdentical();\n\nerror ChainIncorrect();\nerror AmountIncorrect();\nerror ZeroAddress();\n\nerror DisputePeriodNotPassed();\nerror DisputePeriodPassed();\nerror SenderIncorrect();\nerror StatusIncorrect();\nerror TransactionIdIncorrect();\nerror TransactionRelayed();\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// contracts/libs/UniversalToken.sol\n\nlibrary UniversalTokenLib {\n using SafeERC20 for IERC20;\n\n address internal constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Transfers tokens to the given account. Reverts if transfer is not successful.\n /// @dev This might trigger fallback, if ETH is transferred to the contract.\n /// Make sure this can not lead to reentrancy attacks.\n function universalTransfer(address token, address to, uint256 value) internal {\n // Don't do anything, if need to send tokens to this address\n if (to == address(this)) return;\n // Don't do anything, if trying to send zero value\n if (value == 0) return;\n if (token == ETH_ADDRESS) {\n /// @dev Note: this can potentially lead to executing code in `to`.\n // solhint-disable-next-line avoid-low-level-calls\n (bool success,) = to.call{value: value}(\"\");\n require(success, \"ETH transfer failed\");\n } else {\n IERC20(token).safeTransfer(to, value);\n }\n }\n\n /// @notice Issues an infinite allowance to the spender, if the current allowance is insufficient\n /// to spend the given amount.\n function universalApproveInfinity(address token, address spender, uint256 amountToSpend) internal {\n // ETH Chad doesn't require your approval\n if (token == ETH_ADDRESS) return;\n // No-op if allowance is already sufficient\n uint256 allowance = IERC20(token).allowance(address(this), spender);\n if (allowance \u003e= amountToSpend) return;\n // Otherwise, reset approval to 0 and set to max allowance\n if (allowance \u003e 0) IERC20(token).safeDecreaseAllowance(spender, allowance);\n IERC20(token).safeIncreaseAllowance(spender, type(uint256).max);\n }\n\n /// @notice Returns the balance of the given token (or native ETH) for the given account.\n function universalBalanceOf(address token, address account) internal view returns (uint256) {\n if (token == ETH_ADDRESS) {\n return account.balance;\n } else {\n return IERC20(token).balanceOf(account);\n }\n }\n\n /// @dev Checks that token is a contract and not ETH_ADDRESS.\n function assertIsContract(address token) internal view {\n // Check that ETH_ADDRESS was not used (in case this is a predeploy on any of the chains)\n if (token == UniversalTokenLib.ETH_ADDRESS) revert TokenNotContract();\n // Check that token is not an EOA\n if (token.code.length == 0) revert TokenNotContract();\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/Admin.sol\n\ncontract Admin is IAdmin, AccessControlEnumerable {\n using UniversalTokenLib for address;\n\n bytes32 public constant RELAYER_ROLE = keccak256(\"RELAYER_ROLE\");\n bytes32 public constant REFUNDER_ROLE = keccak256(\"REFUNDER_ROLE\");\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n uint256 public constant FEE_BPS = 1e6;\n uint256 public constant FEE_RATE_MAX = 0.01e6; // max 1% on origin amount\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Chain gas amount to forward as rebate if requested\n uint256 public chainGasAmount;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n }\n\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n require(newFeeRate \u003c= FEE_RATE_MAX, \"newFeeRate \u003e max\");\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n token.universalTransfer(recipient, feeAmount);\n emit FeesSwept(token, recipient, feeAmount);\n }\n\n function setChainGasAmount(uint256 newChainGasAmount) external onlyRole(GOVERNOR_ROLE) {\n uint256 oldChainGasAmount = chainGasAmount;\n chainGasAmount = newChainGasAmount;\n emit ChainGasAmountUpdated(oldChainGasAmount, newChainGasAmount);\n }\n}\n\n// contracts/FastBridge.sol\n\ncontract FastBridge is IFastBridge, Admin {\n using SafeERC20 for IERC20;\n using UniversalTokenLib for address;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Delay for a transaction after which it could be permisionlessly refunded\n uint256 public constant REFUND_DELAY = 7 days;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeStatus) public bridgeStatuses;\n /// @notice Proof of relayed bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeProof) public bridgeProofs;\n /// @notice Whether bridge has been relayed on destination chain\n mapping(bytes32 =\u003e bool) public bridgeRelays;\n\n /// @dev to prevent replays\n uint256 public nonce;\n // @dev the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @notice Pulls a requested token from the user to the requested recipient.\n /// @dev Be careful of re-entrancy issues when msg.value \u003e 0 and recipient != address(this)\n function _pullToken(address recipient, address token, uint256 amount) internal returns (uint256 amountPulled) {\n if (token != UniversalTokenLib.ETH_ADDRESS) {\n token.assertIsContract();\n // Record token balance before transfer\n amountPulled = IERC20(token).balanceOf(recipient);\n // Token needs to be pulled only if msg.value is zero\n // This way user can specify WETH as the origin asset\n IERC20(token).safeTransferFrom(msg.sender, recipient, amount);\n // Use the difference between the recorded balance and the current balance as the amountPulled\n amountPulled = IERC20(token).balanceOf(recipient) - amountPulled;\n } else {\n // Otherwise, we need to check that ETH amount matches msg.value\n if (amount != msg.value) revert MsgValueIncorrect();\n // Transfer value to recipient if not this address\n if (recipient != address(this)) token.universalTransfer(recipient, amount);\n // We will forward msg.value in the external call later, if recipient is not this contract\n amountPulled = msg.value;\n }\n }\n\n /// @inheritdoc IFastBridge\n function getBridgeTransaction(bytes memory request) public pure returns (BridgeTransaction memory) {\n return abi.decode(request, (BridgeTransaction));\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n // check bridge params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n\n // transfer tokens to bridge contract\n // @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _pullToken(address(this), params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n\n // set status to requested\n bytes memory request = abi.encode(\n BridgeTransaction({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n sendChainGas: params.sendChainGas,\n deadline: params.deadline,\n nonce: nonce++ // increment nonce on every bridge\n })\n );\n bytes32 transactionId = keccak256(request);\n bridgeStatuses[transactionId] = BridgeStatus.REQUESTED;\n\n emit BridgeRequested(\n transactionId,\n params.sender,\n request,\n params.dstChainId,\n params.originToken,\n params.destToken,\n originAmount,\n params.destAmount,\n params.sendChainGas\n );\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes memory request) external payable onlyRole(RELAYER_ROLE) {\n bytes32 transactionId = keccak256(request);\n BridgeTransaction memory transaction = getBridgeTransaction(request);\n if (transaction.destChainId != uint32(block.chainid)) revert ChainIncorrect();\n\n // check haven't exceeded deadline for relay to happen\n if (block.timestamp \u003e transaction.deadline) revert DeadlineExceeded();\n\n // mark bridge transaction as relayed\n if (bridgeRelays[transactionId]) revert TransactionRelayed();\n bridgeRelays[transactionId] = true;\n\n // transfer tokens to recipient on destination chain and gas rebate if requested\n address to = transaction.destRecipient;\n address token = transaction.destToken;\n uint256 amount = transaction.destAmount;\n\n uint256 rebate = chainGasAmount;\n if (!transaction.sendChainGas) {\n // forward erc20\n rebate = 0;\n _pullToken(to, token, amount);\n } else if (token == UniversalTokenLib.ETH_ADDRESS) {\n // lump in gas rebate into amount in native gas token\n _pullToken(to, token, amount + rebate);\n } else {\n // forward erc20 then forward gas rebate in native gas token\n _pullToken(to, token, amount);\n _pullToken(to, UniversalTokenLib.ETH_ADDRESS, rebate);\n }\n\n emit BridgeRelayed(\n transactionId,\n msg.sender,\n to,\n transaction.originChainId,\n transaction.originToken,\n transaction.destToken,\n transaction.originAmount,\n transaction.destAmount,\n rebate\n );\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes memory request, bytes32 destTxHash) external onlyRole(RELAYER_ROLE) {\n bytes32 transactionId = keccak256(request);\n // update bridge tx status given proof provided\n if (bridgeStatuses[transactionId] != BridgeStatus.REQUESTED) revert StatusIncorrect();\n bridgeStatuses[transactionId] = BridgeStatus.RELAYER_PROVED;\n bridgeProofs[transactionId] = BridgeProof({timestamp: uint96(block.timestamp), relayer: msg.sender}); // overflow ok\n\n emit BridgeProofProvided(transactionId, msg.sender, destTxHash);\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint96(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint96).max but\n /// proof.timestamp \u003c type(uint96).max via unchecked statement\n /// @param proof The bridge proof\n /// @return delta Time delta since proof submitted\n function _timeSince(BridgeProof memory proof) internal view returns (uint256 delta) {\n unchecked {\n delta = uint96(block.timestamp) - proof.timestamp;\n }\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n if (bridgeStatuses[transactionId] != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n BridgeProof memory proof = bridgeProofs[transactionId];\n if (proof.relayer != relayer) revert SenderIncorrect();\n return _timeSince(proof) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes memory request, address to) external onlyRole(RELAYER_ROLE) {\n bytes32 transactionId = keccak256(request);\n BridgeTransaction memory transaction = getBridgeTransaction(request);\n\n // update bridge tx status if able to claim origin collateral\n if (bridgeStatuses[transactionId] != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n\n BridgeProof memory proof = bridgeProofs[transactionId];\n if (proof.relayer != msg.sender) revert SenderIncorrect();\n if (_timeSince(proof) \u003c= DISPUTE_PERIOD) revert DisputePeriodNotPassed();\n\n bridgeStatuses[transactionId] = BridgeStatus.RELAYER_CLAIMED;\n\n // update protocol fees if origin fee amount exists\n if (transaction.originFeeAmount \u003e 0) protocolFees[transaction.originToken] += transaction.originFeeAmount;\n\n // transfer origin collateral less fee to specified address\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositClaimed(transactionId, msg.sender, to, token, amount);\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n if (bridgeStatuses[transactionId] != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(bridgeProofs[transactionId]) \u003e DISPUTE_PERIOD) revert DisputePeriodPassed();\n\n // @dev relayer gets slashed effectively if dest relay has gone thru\n bridgeStatuses[transactionId] = BridgeStatus.REQUESTED;\n delete bridgeProofs[transactionId];\n\n emit BridgeProofDisputed(transactionId, msg.sender);\n }\n\n /// @inheritdoc IFastBridge\n function refund(bytes memory request) external {\n bytes32 transactionId = keccak256(request);\n BridgeTransaction memory transaction = getBridgeTransaction(request);\n\n if (hasRole(REFUNDER_ROLE, msg.sender)) {\n // Refunder can refund if deadline has passed\n if (block.timestamp \u003c= transaction.deadline) revert DeadlineNotExceeded();\n } else {\n // Permissionless refund is allowed after REFUND_DELAY\n if (block.timestamp \u003c= transaction.deadline + REFUND_DELAY) revert DeadlineNotExceeded();\n }\n\n // set status to refunded if still in requested state\n if (bridgeStatuses[transactionId] != BridgeStatus.REQUESTED) revert StatusIncorrect();\n bridgeStatuses[transactionId] = BridgeStatus.REFUNDED;\n\n // transfer origin collateral back to original sender\n address to = transaction.originSender;\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount + transaction.originFeeAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n }\n}\n\n// test/FastBridgeMock.sol\n\ncontract FastBridgeMock is IFastBridge, Admin {\n // @dev the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @dev to prevent replays\n uint256 public nonce;\n\n function getBridgeTransaction(bytes memory request) public pure returns (BridgeTransaction memory) {\n return abi.decode(request, (BridgeTransaction));\n }\n\n // used for testing in go.\n // see: https://ethereum.stackexchange.com/questions/21155/how-to-expose-enum-in-solidity-contract\n // make sure to update fastbridge/status.go if this changes\n // or underliyng enum changes.\n //\n // TODO: a foundry test should be added to ensure this is always in sync.\n function getEnumKeyByValue(FastBridge.BridgeStatus keyValue) public pure returns (string memory) {\n if (FastBridge.BridgeStatus.NULL == keyValue) return \"NULL\";\n if (FastBridge.BridgeStatus.REQUESTED == keyValue) return \"REQUESTED\";\n if (FastBridge.BridgeStatus.RELAYER_PROVED == keyValue) return \"RELAYER_PROVED\";\n if (FastBridge.BridgeStatus.RELAYER_CLAIMED == keyValue) return \"RELAYER_CLAIMED\";\n if (FastBridge.BridgeStatus.REFUNDED == keyValue) return \"REFUNDED\";\n return \"\";\n }\n\n function mockBridgeRequest(bytes32 transactionId, address sender, BridgeParams memory params) external {\n uint256 originFeeAmount = (params.originAmount * protocolFeeRate) / FEE_BPS;\n params.originAmount -= originFeeAmount;\n\n bytes memory request = abi.encode(\n BridgeTransaction({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: params.originAmount, // includes relayer fee\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n sendChainGas: params.sendChainGas,\n deadline: params.deadline,\n nonce: nonce++ // increment nonce on every bridge\n })\n );\n\n emit BridgeRequested(\n transactionId,\n params.sender,\n request,\n params.dstChainId,\n params.originToken,\n params.destToken,\n params.originAmount,\n params.destAmount,\n params.sendChainGas\n );\n }\n\n function mockBridgeRequestRaw(bytes32 transactionId, address sender, bytes memory request) external {\n BridgeTransaction memory transaction = getBridgeTransaction(request);\n emit BridgeRequested(\n transactionId,\n transaction.originSender,\n request,\n transaction.destChainId,\n transaction.originToken,\n transaction.destToken,\n transaction.originAmount,\n transaction.destAmount,\n transaction.sendChainGas\n );\n }\n\n function mockBridgeRelayer(\n bytes32 transactionId,\n address relayer,\n address to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n )\n external\n {\n emit BridgeRelayed(\n transactionId, relayer, to, originChainId, originToken, destToken, originAmount, destAmount, chainGasAmount\n );\n }\n\n function bridge(BridgeParams memory params) external payable {\n revert(\"not implemented\");\n }\n\n function relay(bytes memory request) external payable {\n revert(\"not implemented\");\n }\n\n function prove(bytes memory request, bytes32 destTxHash) external {\n revert(\"not implemented\");\n }\n\n function canClaim(bytes32 transactionid, address relayer) external view returns (bool) {\n revert(\"not implemented\");\n }\n\n function claim(bytes memory request, address to) external {\n revert(\"not implemented\");\n }\n\n function dispute(bytes32 transactionId) external {\n revert(\"not implemented\");\n }\n\n function refund(bytes memory request) external {\n revert(\"not implemented\");\n }\n}\n","language":"Solidity","languageVersion":"0.8.20","compilerVersion":"0.8.20","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"","srcMapRuntime":"","abiDefinition":[{"inputs":[],"name":"DOMAIN_SEPARATOR","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"nonces","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"permit","outputs":[],"stateMutability":"nonpayable","type":"function"}],"userDoc":{"kind":"user","methods":{},"version":1},"developerDoc":{"details":"Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in https://eips.ethereum.org/EIPS/eip-2612[EIP-2612]. Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't need to send a transaction, and thus is not required to hold Ether at all. ==== Security Considerations There are two important considerations concerning the use of `permit`. The first is that a valid permit signature expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be considered as an intention to spend the allowance in any specific way. The second is that because permits have built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be generally recommended is: ```solidity function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public { try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {} doThing(..., value); } function doThing(..., uint256 value) public { token.safeTransferFrom(msg.sender, address(this), value); ... } ``` Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also {SafeERC20-safeTransferFrom}). Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so contracts should have entry points that don't rely on permit.","kind":"dev","methods":{"DOMAIN_SEPARATOR()":{"details":"Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}."},"nonces(address)":{"details":"Returns the current nonce for `owner`. This value must be included whenever a signature is generated for {permit}. Every successful call to {permit} increases ``owner``'s nonce by one. This prevents a signature from being used multiple times."},"permit(address,address,uint256,uint256,uint8,bytes32,bytes32)":{"details":"Sets `value` as the allowance of `spender` over ``owner``'s tokens, given ``owner``'s signed approval. IMPORTANT: The same issues {IERC20-approve} has related to transaction ordering also apply here. Emits an {Approval} event. Requirements: - `spender` cannot be the zero address. - `deadline` must be a timestamp in the future. - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner` over the EIP712-formatted function arguments. - the signature must use ``owner``'s current nonce (see {nonces}). For more information on the signature format, see the https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP section]. CAUTION: See Security Considerations above."}},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.20+commit.a1b79de6\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[],\"name\":\"DOMAIN_SEPARATOR\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"}],\"name\":\"nonces\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"},{\"internalType\":\"uint8\",\"name\":\"v\",\"type\":\"uint8\"},{\"internalType\":\"bytes32\",\"name\":\"r\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"s\",\"type\":\"bytes32\"}],\"name\":\"permit\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"details\":\"Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in https://eips.ethereum.org/EIPS/eip-2612[EIP-2612]. Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't need to send a transaction, and thus is not required to hold Ether at all. ==== Security Considerations There are two important considerations concerning the use of `permit`. The first is that a valid permit signature expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be considered as an intention to spend the allowance in any specific way. The second is that because permits have built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be generally recommended is: ```solidity function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public { try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {} doThing(..., value); } function doThing(..., uint256 value) public { token.safeTransferFrom(msg.sender, address(this), value); ... } ``` Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also {SafeERC20-safeTransferFrom}). Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so contracts should have entry points that don't rely on permit.\",\"kind\":\"dev\",\"methods\":{\"DOMAIN_SEPARATOR()\":{\"details\":\"Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\"},\"nonces(address)\":{\"details\":\"Returns the current nonce for `owner`. This value must be included whenever a signature is generated for {permit}. Every successful call to {permit} increases ``owner``'s nonce by one. This prevents a signature from being used multiple times.\"},\"permit(address,address,uint256,uint256,uint8,bytes32,bytes32)\":{\"details\":\"Sets `value` as the allowance of `spender` over ``owner``'s tokens, given ``owner``'s signed approval. IMPORTANT: The same issues {IERC20-approve} has related to transaction ordering also apply here. Emits an {Approval} event. Requirements: - `spender` cannot be the zero address. - `deadline` must be a timestamp in the future. - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner` over the EIP712-formatted function arguments. - the signature must use ``owner``'s current nonce (see {nonces}). For more information on the signature format, see the https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP section]. CAUTION: See Security Considerations above.\"}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeMock.sol\":\"IERC20Permit\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeMock.sol\":{\"keccak256\":\"0x620e81214ecd324ae8b971219291f176c454ce76fb1c01d656428096da8f1366\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://18e556772c12e13aa2d52a50cc7c48e676c8d5af22b90adaf7befb39cdd08e64\",\"dweb:/ipfs/QmPrQc98TxHCFMeuFNADyjr6Nqo52rHhHy1LBcsVdMRXjL\"]}},\"version\":1}"},"hashes":{"DOMAIN_SEPARATOR()":"3644e515","nonces(address)":"7ecebe00","permit(address,address,uint256,uint256,uint8,bytes32,bytes32)":"d505accf"}},"solidity/FastBridgeMock.sol:IFastBridge":{"code":"0x","runtime-code":"0x","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.20 ^0.8.20;\n\n// contracts/interfaces/IAdmin.sol\n\ninterface IAdmin {\n // ============ Events ============\n\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n event ChainGasAmountUpdated(uint256 oldChainGasAmount, uint256 newChainGasAmount);\n\n // ============ Methods ============\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n\n function setChainGasAmount(uint256 newChainGasAmount) external;\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/libs/Errors.sol\n\nerror DeadlineExceeded();\nerror DeadlineNotExceeded();\nerror DeadlineTooShort();\nerror InsufficientOutputAmount();\n\nerror MsgValueIncorrect();\nerror PoolNotFound();\nerror TokenAddressMismatch();\nerror TokenNotContract();\nerror TokenNotETH();\nerror TokensIdentical();\n\nerror ChainIncorrect();\nerror AmountIncorrect();\nerror ZeroAddress();\n\nerror DisputePeriodNotPassed();\nerror DisputePeriodPassed();\nerror SenderIncorrect();\nerror StatusIncorrect();\nerror TransactionIdIncorrect();\nerror TransactionRelayed();\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// contracts/libs/UniversalToken.sol\n\nlibrary UniversalTokenLib {\n using SafeERC20 for IERC20;\n\n address internal constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Transfers tokens to the given account. Reverts if transfer is not successful.\n /// @dev This might trigger fallback, if ETH is transferred to the contract.\n /// Make sure this can not lead to reentrancy attacks.\n function universalTransfer(address token, address to, uint256 value) internal {\n // Don't do anything, if need to send tokens to this address\n if (to == address(this)) return;\n // Don't do anything, if trying to send zero value\n if (value == 0) return;\n if (token == ETH_ADDRESS) {\n /// @dev Note: this can potentially lead to executing code in `to`.\n // solhint-disable-next-line avoid-low-level-calls\n (bool success,) = to.call{value: value}(\"\");\n require(success, \"ETH transfer failed\");\n } else {\n IERC20(token).safeTransfer(to, value);\n }\n }\n\n /// @notice Issues an infinite allowance to the spender, if the current allowance is insufficient\n /// to spend the given amount.\n function universalApproveInfinity(address token, address spender, uint256 amountToSpend) internal {\n // ETH Chad doesn't require your approval\n if (token == ETH_ADDRESS) return;\n // No-op if allowance is already sufficient\n uint256 allowance = IERC20(token).allowance(address(this), spender);\n if (allowance \u003e= amountToSpend) return;\n // Otherwise, reset approval to 0 and set to max allowance\n if (allowance \u003e 0) IERC20(token).safeDecreaseAllowance(spender, allowance);\n IERC20(token).safeIncreaseAllowance(spender, type(uint256).max);\n }\n\n /// @notice Returns the balance of the given token (or native ETH) for the given account.\n function universalBalanceOf(address token, address account) internal view returns (uint256) {\n if (token == ETH_ADDRESS) {\n return account.balance;\n } else {\n return IERC20(token).balanceOf(account);\n }\n }\n\n /// @dev Checks that token is a contract and not ETH_ADDRESS.\n function assertIsContract(address token) internal view {\n // Check that ETH_ADDRESS was not used (in case this is a predeploy on any of the chains)\n if (token == UniversalTokenLib.ETH_ADDRESS) revert TokenNotContract();\n // Check that token is not an EOA\n if (token.code.length == 0) revert TokenNotContract();\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/Admin.sol\n\ncontract Admin is IAdmin, AccessControlEnumerable {\n using UniversalTokenLib for address;\n\n bytes32 public constant RELAYER_ROLE = keccak256(\"RELAYER_ROLE\");\n bytes32 public constant REFUNDER_ROLE = keccak256(\"REFUNDER_ROLE\");\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n uint256 public constant FEE_BPS = 1e6;\n uint256 public constant FEE_RATE_MAX = 0.01e6; // max 1% on origin amount\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Chain gas amount to forward as rebate if requested\n uint256 public chainGasAmount;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n }\n\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n require(newFeeRate \u003c= FEE_RATE_MAX, \"newFeeRate \u003e max\");\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n token.universalTransfer(recipient, feeAmount);\n emit FeesSwept(token, recipient, feeAmount);\n }\n\n function setChainGasAmount(uint256 newChainGasAmount) external onlyRole(GOVERNOR_ROLE) {\n uint256 oldChainGasAmount = chainGasAmount;\n chainGasAmount = newChainGasAmount;\n emit ChainGasAmountUpdated(oldChainGasAmount, newChainGasAmount);\n }\n}\n\n// contracts/FastBridge.sol\n\ncontract FastBridge is IFastBridge, Admin {\n using SafeERC20 for IERC20;\n using UniversalTokenLib for address;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Delay for a transaction after which it could be permisionlessly refunded\n uint256 public constant REFUND_DELAY = 7 days;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeStatus) public bridgeStatuses;\n /// @notice Proof of relayed bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeProof) public bridgeProofs;\n /// @notice Whether bridge has been relayed on destination chain\n mapping(bytes32 =\u003e bool) public bridgeRelays;\n\n /// @dev to prevent replays\n uint256 public nonce;\n // @dev the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @notice Pulls a requested token from the user to the requested recipient.\n /// @dev Be careful of re-entrancy issues when msg.value \u003e 0 and recipient != address(this)\n function _pullToken(address recipient, address token, uint256 amount) internal returns (uint256 amountPulled) {\n if (token != UniversalTokenLib.ETH_ADDRESS) {\n token.assertIsContract();\n // Record token balance before transfer\n amountPulled = IERC20(token).balanceOf(recipient);\n // Token needs to be pulled only if msg.value is zero\n // This way user can specify WETH as the origin asset\n IERC20(token).safeTransferFrom(msg.sender, recipient, amount);\n // Use the difference between the recorded balance and the current balance as the amountPulled\n amountPulled = IERC20(token).balanceOf(recipient) - amountPulled;\n } else {\n // Otherwise, we need to check that ETH amount matches msg.value\n if (amount != msg.value) revert MsgValueIncorrect();\n // Transfer value to recipient if not this address\n if (recipient != address(this)) token.universalTransfer(recipient, amount);\n // We will forward msg.value in the external call later, if recipient is not this contract\n amountPulled = msg.value;\n }\n }\n\n /// @inheritdoc IFastBridge\n function getBridgeTransaction(bytes memory request) public pure returns (BridgeTransaction memory) {\n return abi.decode(request, (BridgeTransaction));\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n // check bridge params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n\n // transfer tokens to bridge contract\n // @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _pullToken(address(this), params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n\n // set status to requested\n bytes memory request = abi.encode(\n BridgeTransaction({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n sendChainGas: params.sendChainGas,\n deadline: params.deadline,\n nonce: nonce++ // increment nonce on every bridge\n })\n );\n bytes32 transactionId = keccak256(request);\n bridgeStatuses[transactionId] = BridgeStatus.REQUESTED;\n\n emit BridgeRequested(\n transactionId,\n params.sender,\n request,\n params.dstChainId,\n params.originToken,\n params.destToken,\n originAmount,\n params.destAmount,\n params.sendChainGas\n );\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes memory request) external payable onlyRole(RELAYER_ROLE) {\n bytes32 transactionId = keccak256(request);\n BridgeTransaction memory transaction = getBridgeTransaction(request);\n if (transaction.destChainId != uint32(block.chainid)) revert ChainIncorrect();\n\n // check haven't exceeded deadline for relay to happen\n if (block.timestamp \u003e transaction.deadline) revert DeadlineExceeded();\n\n // mark bridge transaction as relayed\n if (bridgeRelays[transactionId]) revert TransactionRelayed();\n bridgeRelays[transactionId] = true;\n\n // transfer tokens to recipient on destination chain and gas rebate if requested\n address to = transaction.destRecipient;\n address token = transaction.destToken;\n uint256 amount = transaction.destAmount;\n\n uint256 rebate = chainGasAmount;\n if (!transaction.sendChainGas) {\n // forward erc20\n rebate = 0;\n _pullToken(to, token, amount);\n } else if (token == UniversalTokenLib.ETH_ADDRESS) {\n // lump in gas rebate into amount in native gas token\n _pullToken(to, token, amount + rebate);\n } else {\n // forward erc20 then forward gas rebate in native gas token\n _pullToken(to, token, amount);\n _pullToken(to, UniversalTokenLib.ETH_ADDRESS, rebate);\n }\n\n emit BridgeRelayed(\n transactionId,\n msg.sender,\n to,\n transaction.originChainId,\n transaction.originToken,\n transaction.destToken,\n transaction.originAmount,\n transaction.destAmount,\n rebate\n );\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes memory request, bytes32 destTxHash) external onlyRole(RELAYER_ROLE) {\n bytes32 transactionId = keccak256(request);\n // update bridge tx status given proof provided\n if (bridgeStatuses[transactionId] != BridgeStatus.REQUESTED) revert StatusIncorrect();\n bridgeStatuses[transactionId] = BridgeStatus.RELAYER_PROVED;\n bridgeProofs[transactionId] = BridgeProof({timestamp: uint96(block.timestamp), relayer: msg.sender}); // overflow ok\n\n emit BridgeProofProvided(transactionId, msg.sender, destTxHash);\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint96(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint96).max but\n /// proof.timestamp \u003c type(uint96).max via unchecked statement\n /// @param proof The bridge proof\n /// @return delta Time delta since proof submitted\n function _timeSince(BridgeProof memory proof) internal view returns (uint256 delta) {\n unchecked {\n delta = uint96(block.timestamp) - proof.timestamp;\n }\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n if (bridgeStatuses[transactionId] != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n BridgeProof memory proof = bridgeProofs[transactionId];\n if (proof.relayer != relayer) revert SenderIncorrect();\n return _timeSince(proof) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes memory request, address to) external onlyRole(RELAYER_ROLE) {\n bytes32 transactionId = keccak256(request);\n BridgeTransaction memory transaction = getBridgeTransaction(request);\n\n // update bridge tx status if able to claim origin collateral\n if (bridgeStatuses[transactionId] != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n\n BridgeProof memory proof = bridgeProofs[transactionId];\n if (proof.relayer != msg.sender) revert SenderIncorrect();\n if (_timeSince(proof) \u003c= DISPUTE_PERIOD) revert DisputePeriodNotPassed();\n\n bridgeStatuses[transactionId] = BridgeStatus.RELAYER_CLAIMED;\n\n // update protocol fees if origin fee amount exists\n if (transaction.originFeeAmount \u003e 0) protocolFees[transaction.originToken] += transaction.originFeeAmount;\n\n // transfer origin collateral less fee to specified address\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositClaimed(transactionId, msg.sender, to, token, amount);\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n if (bridgeStatuses[transactionId] != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(bridgeProofs[transactionId]) \u003e DISPUTE_PERIOD) revert DisputePeriodPassed();\n\n // @dev relayer gets slashed effectively if dest relay has gone thru\n bridgeStatuses[transactionId] = BridgeStatus.REQUESTED;\n delete bridgeProofs[transactionId];\n\n emit BridgeProofDisputed(transactionId, msg.sender);\n }\n\n /// @inheritdoc IFastBridge\n function refund(bytes memory request) external {\n bytes32 transactionId = keccak256(request);\n BridgeTransaction memory transaction = getBridgeTransaction(request);\n\n if (hasRole(REFUNDER_ROLE, msg.sender)) {\n // Refunder can refund if deadline has passed\n if (block.timestamp \u003c= transaction.deadline) revert DeadlineNotExceeded();\n } else {\n // Permissionless refund is allowed after REFUND_DELAY\n if (block.timestamp \u003c= transaction.deadline + REFUND_DELAY) revert DeadlineNotExceeded();\n }\n\n // set status to refunded if still in requested state\n if (bridgeStatuses[transactionId] != BridgeStatus.REQUESTED) revert StatusIncorrect();\n bridgeStatuses[transactionId] = BridgeStatus.REFUNDED;\n\n // transfer origin collateral back to original sender\n address to = transaction.originSender;\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount + transaction.originFeeAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n }\n}\n\n// test/FastBridgeMock.sol\n\ncontract FastBridgeMock is IFastBridge, Admin {\n // @dev the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @dev to prevent replays\n uint256 public nonce;\n\n function getBridgeTransaction(bytes memory request) public pure returns (BridgeTransaction memory) {\n return abi.decode(request, (BridgeTransaction));\n }\n\n // used for testing in go.\n // see: https://ethereum.stackexchange.com/questions/21155/how-to-expose-enum-in-solidity-contract\n // make sure to update fastbridge/status.go if this changes\n // or underliyng enum changes.\n //\n // TODO: a foundry test should be added to ensure this is always in sync.\n function getEnumKeyByValue(FastBridge.BridgeStatus keyValue) public pure returns (string memory) {\n if (FastBridge.BridgeStatus.NULL == keyValue) return \"NULL\";\n if (FastBridge.BridgeStatus.REQUESTED == keyValue) return \"REQUESTED\";\n if (FastBridge.BridgeStatus.RELAYER_PROVED == keyValue) return \"RELAYER_PROVED\";\n if (FastBridge.BridgeStatus.RELAYER_CLAIMED == keyValue) return \"RELAYER_CLAIMED\";\n if (FastBridge.BridgeStatus.REFUNDED == keyValue) return \"REFUNDED\";\n return \"\";\n }\n\n function mockBridgeRequest(bytes32 transactionId, address sender, BridgeParams memory params) external {\n uint256 originFeeAmount = (params.originAmount * protocolFeeRate) / FEE_BPS;\n params.originAmount -= originFeeAmount;\n\n bytes memory request = abi.encode(\n BridgeTransaction({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: params.originAmount, // includes relayer fee\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n sendChainGas: params.sendChainGas,\n deadline: params.deadline,\n nonce: nonce++ // increment nonce on every bridge\n })\n );\n\n emit BridgeRequested(\n transactionId,\n params.sender,\n request,\n params.dstChainId,\n params.originToken,\n params.destToken,\n params.originAmount,\n params.destAmount,\n params.sendChainGas\n );\n }\n\n function mockBridgeRequestRaw(bytes32 transactionId, address sender, bytes memory request) external {\n BridgeTransaction memory transaction = getBridgeTransaction(request);\n emit BridgeRequested(\n transactionId,\n transaction.originSender,\n request,\n transaction.destChainId,\n transaction.originToken,\n transaction.destToken,\n transaction.originAmount,\n transaction.destAmount,\n transaction.sendChainGas\n );\n }\n\n function mockBridgeRelayer(\n bytes32 transactionId,\n address relayer,\n address to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n )\n external\n {\n emit BridgeRelayed(\n transactionId, relayer, to, originChainId, originToken, destToken, originAmount, destAmount, chainGasAmount\n );\n }\n\n function bridge(BridgeParams memory params) external payable {\n revert(\"not implemented\");\n }\n\n function relay(bytes memory request) external payable {\n revert(\"not implemented\");\n }\n\n function prove(bytes memory request, bytes32 destTxHash) external {\n revert(\"not implemented\");\n }\n\n function canClaim(bytes32 transactionid, address relayer) external view returns (bool) {\n revert(\"not implemented\");\n }\n\n function claim(bytes memory request, address to) external {\n revert(\"not implemented\");\n }\n\n function dispute(bytes32 transactionId) external {\n revert(\"not implemented\");\n }\n\n function refund(bytes memory request) external {\n revert(\"not implemented\");\n }\n}\n","language":"Solidity","languageVersion":"0.8.20","compilerVersion":"0.8.20","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"","srcMapRuntime":"","abiDefinition":[{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"relayer","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"BridgeDepositClaimed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"BridgeDepositRefunded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"relayer","type":"address"}],"name":"BridgeProofDisputed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"relayer","type":"address"},{"indexed":false,"internalType":"bytes32","name":"transactionHash","type":"bytes32"}],"name":"BridgeProofProvided","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"relayer","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint32","name":"originChainId","type":"uint32"},{"indexed":false,"internalType":"address","name":"originToken","type":"address"},{"indexed":false,"internalType":"address","name":"destToken","type":"address"},{"indexed":false,"internalType":"uint256","name":"originAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"destAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"chainGasAmount","type":"uint256"}],"name":"BridgeRelayed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"bytes","name":"request","type":"bytes"},{"indexed":false,"internalType":"uint32","name":"destChainId","type":"uint32"},{"indexed":false,"internalType":"address","name":"originToken","type":"address"},{"indexed":false,"internalType":"address","name":"destToken","type":"address"},{"indexed":false,"internalType":"uint256","name":"originAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"destAmount","type":"uint256"},{"indexed":false,"internalType":"bool","name":"sendChainGas","type":"bool"}],"name":"BridgeRequested","type":"event"},{"inputs":[{"components":[{"internalType":"uint32","name":"dstChainId","type":"uint32"},{"internalType":"address","name":"sender","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"address","name":"originToken","type":"address"},{"internalType":"address","name":"destToken","type":"address"},{"internalType":"uint256","name":"originAmount","type":"uint256"},{"internalType":"uint256","name":"destAmount","type":"uint256"},{"internalType":"bool","name":"sendChainGas","type":"bool"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"internalType":"struct IFastBridge.BridgeParams","name":"params","type":"tuple"}],"name":"bridge","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"internalType":"address","name":"relayer","type":"address"}],"name":"canClaim","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"},{"internalType":"address","name":"to","type":"address"}],"name":"claim","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"transactionId","type":"bytes32"}],"name":"dispute","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"}],"name":"getBridgeTransaction","outputs":[{"components":[{"internalType":"uint32","name":"originChainId","type":"uint32"},{"internalType":"uint32","name":"destChainId","type":"uint32"},{"internalType":"address","name":"originSender","type":"address"},{"internalType":"address","name":"destRecipient","type":"address"},{"internalType":"address","name":"originToken","type":"address"},{"internalType":"address","name":"destToken","type":"address"},{"internalType":"uint256","name":"originAmount","type":"uint256"},{"internalType":"uint256","name":"destAmount","type":"uint256"},{"internalType":"uint256","name":"originFeeAmount","type":"uint256"},{"internalType":"bool","name":"sendChainGas","type":"bool"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint256","name":"nonce","type":"uint256"}],"internalType":"struct IFastBridge.BridgeTransaction","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"},{"internalType":"bytes32","name":"destTxHash","type":"bytes32"}],"name":"prove","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"}],"name":"refund","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"}],"name":"relay","outputs":[],"stateMutability":"payable","type":"function"}],"userDoc":{"kind":"user","methods":{"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256))":{"notice":"Initiates bridge on origin chain to be relayed by off-chain relayer"},"canClaim(bytes32,address)":{"notice":"Checks if the dispute period has passed so bridge deposit can be claimed"},"claim(bytes,address)":{"notice":"Completes bridge transaction on origin chain by claiming originally deposited capital"},"dispute(bytes32)":{"notice":"Disputes an outstanding proof in case relayer provided dest chain tx is invalid"},"getBridgeTransaction(bytes)":{"notice":"Decodes bridge request into a bridge transaction"},"prove(bytes,bytes32)":{"notice":"Provides proof on origin side that relayer provided funds on destination side of bridge transaction"},"refund(bytes)":{"notice":"Refunds an outstanding bridge transaction in case optimistic bridging failed"},"relay(bytes)":{"notice":"Relays destination side of bridge transaction by off-chain relayer"}},"version":1},"developerDoc":{"kind":"dev","methods":{"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256))":{"params":{"params":"The parameters required to bridge"}},"canClaim(bytes32,address)":{"params":{"relayer":"The address of the relayer attempting to claim","transactionId":"The transaction id associated with the encoded bridge transaction to check"}},"claim(bytes,address)":{"params":{"request":"The encoded bridge transaction to claim on origin chain","to":"The recipient address of the funds"}},"dispute(bytes32)":{"params":{"transactionId":"The transaction id associated with the encoded bridge transaction to dispute"}},"getBridgeTransaction(bytes)":{"params":{"request":"The bridge request to decode"}},"prove(bytes,bytes32)":{"params":{"destTxHash":"The destination tx hash proving bridge transaction was relayed","request":"The encoded bridge transaction to prove on origin chain"}},"refund(bytes)":{"params":{"request":"The encoded bridge transaction to refund"}},"relay(bytes)":{"params":{"request":"The encoded bridge transaction to relay on destination chain"}}},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.20+commit.a1b79de6\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"BridgeDepositClaimed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"BridgeDepositRefunded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"name\":\"BridgeProofDisputed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"transactionHash\",\"type\":\"bytes32\"}],\"name\":\"BridgeProofProvided\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"originChainId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"chainGasAmount\",\"type\":\"uint256\"}],\"name\":\"BridgeRelayed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"destChainId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"sendChainGas\",\"type\":\"bool\"}],\"name\":\"BridgeRequested\",\"type\":\"event\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"dstChainId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"sendChainGas\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"}],\"internalType\":\"struct IFastBridge.BridgeParams\",\"name\":\"params\",\"type\":\"tuple\"}],\"name\":\"bridge\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"name\":\"canClaim\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"claim\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"}],\"name\":\"dispute\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"getBridgeTransaction\",\"outputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"originChainId\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"destChainId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"originSender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destRecipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"originFeeAmount\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"sendChainGas\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"}],\"internalType\":\"struct IFastBridge.BridgeTransaction\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"},{\"internalType\":\"bytes32\",\"name\":\"destTxHash\",\"type\":\"bytes32\"}],\"name\":\"prove\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"refund\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"relay\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{\"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256))\":{\"params\":{\"params\":\"The parameters required to bridge\"}},\"canClaim(bytes32,address)\":{\"params\":{\"relayer\":\"The address of the relayer attempting to claim\",\"transactionId\":\"The transaction id associated with the encoded bridge transaction to check\"}},\"claim(bytes,address)\":{\"params\":{\"request\":\"The encoded bridge transaction to claim on origin chain\",\"to\":\"The recipient address of the funds\"}},\"dispute(bytes32)\":{\"params\":{\"transactionId\":\"The transaction id associated with the encoded bridge transaction to dispute\"}},\"getBridgeTransaction(bytes)\":{\"params\":{\"request\":\"The bridge request to decode\"}},\"prove(bytes,bytes32)\":{\"params\":{\"destTxHash\":\"The destination tx hash proving bridge transaction was relayed\",\"request\":\"The encoded bridge transaction to prove on origin chain\"}},\"refund(bytes)\":{\"params\":{\"request\":\"The encoded bridge transaction to refund\"}},\"relay(bytes)\":{\"params\":{\"request\":\"The encoded bridge transaction to relay on destination chain\"}}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256))\":{\"notice\":\"Initiates bridge on origin chain to be relayed by off-chain relayer\"},\"canClaim(bytes32,address)\":{\"notice\":\"Checks if the dispute period has passed so bridge deposit can be claimed\"},\"claim(bytes,address)\":{\"notice\":\"Completes bridge transaction on origin chain by claiming originally deposited capital\"},\"dispute(bytes32)\":{\"notice\":\"Disputes an outstanding proof in case relayer provided dest chain tx is invalid\"},\"getBridgeTransaction(bytes)\":{\"notice\":\"Decodes bridge request into a bridge transaction\"},\"prove(bytes,bytes32)\":{\"notice\":\"Provides proof on origin side that relayer provided funds on destination side of bridge transaction\"},\"refund(bytes)\":{\"notice\":\"Refunds an outstanding bridge transaction in case optimistic bridging failed\"},\"relay(bytes)\":{\"notice\":\"Relays destination side of bridge transaction by off-chain relayer\"}},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeMock.sol\":\"IFastBridge\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeMock.sol\":{\"keccak256\":\"0x620e81214ecd324ae8b971219291f176c454ce76fb1c01d656428096da8f1366\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://18e556772c12e13aa2d52a50cc7c48e676c8d5af22b90adaf7befb39cdd08e64\",\"dweb:/ipfs/QmPrQc98TxHCFMeuFNADyjr6Nqo52rHhHy1LBcsVdMRXjL\"]}},\"version\":1}"},"hashes":{"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256))":"45851694","canClaim(bytes32,address)":"aa9641ab","claim(bytes,address)":"41fcb612","dispute(bytes32)":"add98c70","getBridgeTransaction(bytes)":"ac11fb1a","prove(bytes,bytes32)":"886d36ff","refund(bytes)":"5eb7d946","relay(bytes)":"8f0d6f17"}},"solidity/FastBridgeMock.sol:SafeERC20":{"code":"0x60566037600b82828239805160001a607314602a57634e487b7160e01b600052600060045260246000fd5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600080fdfea2646970667358221220c9ee2b1c91328c4f3496cd535cd06e2517aa82f2297fd1e3b5006b41112840f764736f6c63430008140033","runtime-code":"0x73000000000000000000000000000000000000000030146080604052600080fdfea2646970667358221220c9ee2b1c91328c4f3496cd535cd06e2517aa82f2297fd1e3b5006b41112840f764736f6c63430008140033","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.20 ^0.8.20;\n\n// contracts/interfaces/IAdmin.sol\n\ninterface IAdmin {\n // ============ Events ============\n\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n event ChainGasAmountUpdated(uint256 oldChainGasAmount, uint256 newChainGasAmount);\n\n // ============ Methods ============\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n\n function setChainGasAmount(uint256 newChainGasAmount) external;\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/libs/Errors.sol\n\nerror DeadlineExceeded();\nerror DeadlineNotExceeded();\nerror DeadlineTooShort();\nerror InsufficientOutputAmount();\n\nerror MsgValueIncorrect();\nerror PoolNotFound();\nerror TokenAddressMismatch();\nerror TokenNotContract();\nerror TokenNotETH();\nerror TokensIdentical();\n\nerror ChainIncorrect();\nerror AmountIncorrect();\nerror ZeroAddress();\n\nerror DisputePeriodNotPassed();\nerror DisputePeriodPassed();\nerror SenderIncorrect();\nerror StatusIncorrect();\nerror TransactionIdIncorrect();\nerror TransactionRelayed();\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// contracts/libs/UniversalToken.sol\n\nlibrary UniversalTokenLib {\n using SafeERC20 for IERC20;\n\n address internal constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Transfers tokens to the given account. Reverts if transfer is not successful.\n /// @dev This might trigger fallback, if ETH is transferred to the contract.\n /// Make sure this can not lead to reentrancy attacks.\n function universalTransfer(address token, address to, uint256 value) internal {\n // Don't do anything, if need to send tokens to this address\n if (to == address(this)) return;\n // Don't do anything, if trying to send zero value\n if (value == 0) return;\n if (token == ETH_ADDRESS) {\n /// @dev Note: this can potentially lead to executing code in `to`.\n // solhint-disable-next-line avoid-low-level-calls\n (bool success,) = to.call{value: value}(\"\");\n require(success, \"ETH transfer failed\");\n } else {\n IERC20(token).safeTransfer(to, value);\n }\n }\n\n /// @notice Issues an infinite allowance to the spender, if the current allowance is insufficient\n /// to spend the given amount.\n function universalApproveInfinity(address token, address spender, uint256 amountToSpend) internal {\n // ETH Chad doesn't require your approval\n if (token == ETH_ADDRESS) return;\n // No-op if allowance is already sufficient\n uint256 allowance = IERC20(token).allowance(address(this), spender);\n if (allowance \u003e= amountToSpend) return;\n // Otherwise, reset approval to 0 and set to max allowance\n if (allowance \u003e 0) IERC20(token).safeDecreaseAllowance(spender, allowance);\n IERC20(token).safeIncreaseAllowance(spender, type(uint256).max);\n }\n\n /// @notice Returns the balance of the given token (or native ETH) for the given account.\n function universalBalanceOf(address token, address account) internal view returns (uint256) {\n if (token == ETH_ADDRESS) {\n return account.balance;\n } else {\n return IERC20(token).balanceOf(account);\n }\n }\n\n /// @dev Checks that token is a contract and not ETH_ADDRESS.\n function assertIsContract(address token) internal view {\n // Check that ETH_ADDRESS was not used (in case this is a predeploy on any of the chains)\n if (token == UniversalTokenLib.ETH_ADDRESS) revert TokenNotContract();\n // Check that token is not an EOA\n if (token.code.length == 0) revert TokenNotContract();\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/Admin.sol\n\ncontract Admin is IAdmin, AccessControlEnumerable {\n using UniversalTokenLib for address;\n\n bytes32 public constant RELAYER_ROLE = keccak256(\"RELAYER_ROLE\");\n bytes32 public constant REFUNDER_ROLE = keccak256(\"REFUNDER_ROLE\");\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n uint256 public constant FEE_BPS = 1e6;\n uint256 public constant FEE_RATE_MAX = 0.01e6; // max 1% on origin amount\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Chain gas amount to forward as rebate if requested\n uint256 public chainGasAmount;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n }\n\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n require(newFeeRate \u003c= FEE_RATE_MAX, \"newFeeRate \u003e max\");\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n token.universalTransfer(recipient, feeAmount);\n emit FeesSwept(token, recipient, feeAmount);\n }\n\n function setChainGasAmount(uint256 newChainGasAmount) external onlyRole(GOVERNOR_ROLE) {\n uint256 oldChainGasAmount = chainGasAmount;\n chainGasAmount = newChainGasAmount;\n emit ChainGasAmountUpdated(oldChainGasAmount, newChainGasAmount);\n }\n}\n\n// contracts/FastBridge.sol\n\ncontract FastBridge is IFastBridge, Admin {\n using SafeERC20 for IERC20;\n using UniversalTokenLib for address;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Delay for a transaction after which it could be permisionlessly refunded\n uint256 public constant REFUND_DELAY = 7 days;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeStatus) public bridgeStatuses;\n /// @notice Proof of relayed bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeProof) public bridgeProofs;\n /// @notice Whether bridge has been relayed on destination chain\n mapping(bytes32 =\u003e bool) public bridgeRelays;\n\n /// @dev to prevent replays\n uint256 public nonce;\n // @dev the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @notice Pulls a requested token from the user to the requested recipient.\n /// @dev Be careful of re-entrancy issues when msg.value \u003e 0 and recipient != address(this)\n function _pullToken(address recipient, address token, uint256 amount) internal returns (uint256 amountPulled) {\n if (token != UniversalTokenLib.ETH_ADDRESS) {\n token.assertIsContract();\n // Record token balance before transfer\n amountPulled = IERC20(token).balanceOf(recipient);\n // Token needs to be pulled only if msg.value is zero\n // This way user can specify WETH as the origin asset\n IERC20(token).safeTransferFrom(msg.sender, recipient, amount);\n // Use the difference between the recorded balance and the current balance as the amountPulled\n amountPulled = IERC20(token).balanceOf(recipient) - amountPulled;\n } else {\n // Otherwise, we need to check that ETH amount matches msg.value\n if (amount != msg.value) revert MsgValueIncorrect();\n // Transfer value to recipient if not this address\n if (recipient != address(this)) token.universalTransfer(recipient, amount);\n // We will forward msg.value in the external call later, if recipient is not this contract\n amountPulled = msg.value;\n }\n }\n\n /// @inheritdoc IFastBridge\n function getBridgeTransaction(bytes memory request) public pure returns (BridgeTransaction memory) {\n return abi.decode(request, (BridgeTransaction));\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n // check bridge params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n\n // transfer tokens to bridge contract\n // @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _pullToken(address(this), params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n\n // set status to requested\n bytes memory request = abi.encode(\n BridgeTransaction({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n sendChainGas: params.sendChainGas,\n deadline: params.deadline,\n nonce: nonce++ // increment nonce on every bridge\n })\n );\n bytes32 transactionId = keccak256(request);\n bridgeStatuses[transactionId] = BridgeStatus.REQUESTED;\n\n emit BridgeRequested(\n transactionId,\n params.sender,\n request,\n params.dstChainId,\n params.originToken,\n params.destToken,\n originAmount,\n params.destAmount,\n params.sendChainGas\n );\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes memory request) external payable onlyRole(RELAYER_ROLE) {\n bytes32 transactionId = keccak256(request);\n BridgeTransaction memory transaction = getBridgeTransaction(request);\n if (transaction.destChainId != uint32(block.chainid)) revert ChainIncorrect();\n\n // check haven't exceeded deadline for relay to happen\n if (block.timestamp \u003e transaction.deadline) revert DeadlineExceeded();\n\n // mark bridge transaction as relayed\n if (bridgeRelays[transactionId]) revert TransactionRelayed();\n bridgeRelays[transactionId] = true;\n\n // transfer tokens to recipient on destination chain and gas rebate if requested\n address to = transaction.destRecipient;\n address token = transaction.destToken;\n uint256 amount = transaction.destAmount;\n\n uint256 rebate = chainGasAmount;\n if (!transaction.sendChainGas) {\n // forward erc20\n rebate = 0;\n _pullToken(to, token, amount);\n } else if (token == UniversalTokenLib.ETH_ADDRESS) {\n // lump in gas rebate into amount in native gas token\n _pullToken(to, token, amount + rebate);\n } else {\n // forward erc20 then forward gas rebate in native gas token\n _pullToken(to, token, amount);\n _pullToken(to, UniversalTokenLib.ETH_ADDRESS, rebate);\n }\n\n emit BridgeRelayed(\n transactionId,\n msg.sender,\n to,\n transaction.originChainId,\n transaction.originToken,\n transaction.destToken,\n transaction.originAmount,\n transaction.destAmount,\n rebate\n );\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes memory request, bytes32 destTxHash) external onlyRole(RELAYER_ROLE) {\n bytes32 transactionId = keccak256(request);\n // update bridge tx status given proof provided\n if (bridgeStatuses[transactionId] != BridgeStatus.REQUESTED) revert StatusIncorrect();\n bridgeStatuses[transactionId] = BridgeStatus.RELAYER_PROVED;\n bridgeProofs[transactionId] = BridgeProof({timestamp: uint96(block.timestamp), relayer: msg.sender}); // overflow ok\n\n emit BridgeProofProvided(transactionId, msg.sender, destTxHash);\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint96(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint96).max but\n /// proof.timestamp \u003c type(uint96).max via unchecked statement\n /// @param proof The bridge proof\n /// @return delta Time delta since proof submitted\n function _timeSince(BridgeProof memory proof) internal view returns (uint256 delta) {\n unchecked {\n delta = uint96(block.timestamp) - proof.timestamp;\n }\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n if (bridgeStatuses[transactionId] != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n BridgeProof memory proof = bridgeProofs[transactionId];\n if (proof.relayer != relayer) revert SenderIncorrect();\n return _timeSince(proof) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes memory request, address to) external onlyRole(RELAYER_ROLE) {\n bytes32 transactionId = keccak256(request);\n BridgeTransaction memory transaction = getBridgeTransaction(request);\n\n // update bridge tx status if able to claim origin collateral\n if (bridgeStatuses[transactionId] != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n\n BridgeProof memory proof = bridgeProofs[transactionId];\n if (proof.relayer != msg.sender) revert SenderIncorrect();\n if (_timeSince(proof) \u003c= DISPUTE_PERIOD) revert DisputePeriodNotPassed();\n\n bridgeStatuses[transactionId] = BridgeStatus.RELAYER_CLAIMED;\n\n // update protocol fees if origin fee amount exists\n if (transaction.originFeeAmount \u003e 0) protocolFees[transaction.originToken] += transaction.originFeeAmount;\n\n // transfer origin collateral less fee to specified address\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositClaimed(transactionId, msg.sender, to, token, amount);\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n if (bridgeStatuses[transactionId] != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(bridgeProofs[transactionId]) \u003e DISPUTE_PERIOD) revert DisputePeriodPassed();\n\n // @dev relayer gets slashed effectively if dest relay has gone thru\n bridgeStatuses[transactionId] = BridgeStatus.REQUESTED;\n delete bridgeProofs[transactionId];\n\n emit BridgeProofDisputed(transactionId, msg.sender);\n }\n\n /// @inheritdoc IFastBridge\n function refund(bytes memory request) external {\n bytes32 transactionId = keccak256(request);\n BridgeTransaction memory transaction = getBridgeTransaction(request);\n\n if (hasRole(REFUNDER_ROLE, msg.sender)) {\n // Refunder can refund if deadline has passed\n if (block.timestamp \u003c= transaction.deadline) revert DeadlineNotExceeded();\n } else {\n // Permissionless refund is allowed after REFUND_DELAY\n if (block.timestamp \u003c= transaction.deadline + REFUND_DELAY) revert DeadlineNotExceeded();\n }\n\n // set status to refunded if still in requested state\n if (bridgeStatuses[transactionId] != BridgeStatus.REQUESTED) revert StatusIncorrect();\n bridgeStatuses[transactionId] = BridgeStatus.REFUNDED;\n\n // transfer origin collateral back to original sender\n address to = transaction.originSender;\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount + transaction.originFeeAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n }\n}\n\n// test/FastBridgeMock.sol\n\ncontract FastBridgeMock is IFastBridge, Admin {\n // @dev the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @dev to prevent replays\n uint256 public nonce;\n\n function getBridgeTransaction(bytes memory request) public pure returns (BridgeTransaction memory) {\n return abi.decode(request, (BridgeTransaction));\n }\n\n // used for testing in go.\n // see: https://ethereum.stackexchange.com/questions/21155/how-to-expose-enum-in-solidity-contract\n // make sure to update fastbridge/status.go if this changes\n // or underliyng enum changes.\n //\n // TODO: a foundry test should be added to ensure this is always in sync.\n function getEnumKeyByValue(FastBridge.BridgeStatus keyValue) public pure returns (string memory) {\n if (FastBridge.BridgeStatus.NULL == keyValue) return \"NULL\";\n if (FastBridge.BridgeStatus.REQUESTED == keyValue) return \"REQUESTED\";\n if (FastBridge.BridgeStatus.RELAYER_PROVED == keyValue) return \"RELAYER_PROVED\";\n if (FastBridge.BridgeStatus.RELAYER_CLAIMED == keyValue) return \"RELAYER_CLAIMED\";\n if (FastBridge.BridgeStatus.REFUNDED == keyValue) return \"REFUNDED\";\n return \"\";\n }\n\n function mockBridgeRequest(bytes32 transactionId, address sender, BridgeParams memory params) external {\n uint256 originFeeAmount = (params.originAmount * protocolFeeRate) / FEE_BPS;\n params.originAmount -= originFeeAmount;\n\n bytes memory request = abi.encode(\n BridgeTransaction({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: params.originAmount, // includes relayer fee\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n sendChainGas: params.sendChainGas,\n deadline: params.deadline,\n nonce: nonce++ // increment nonce on every bridge\n })\n );\n\n emit BridgeRequested(\n transactionId,\n params.sender,\n request,\n params.dstChainId,\n params.originToken,\n params.destToken,\n params.originAmount,\n params.destAmount,\n params.sendChainGas\n );\n }\n\n function mockBridgeRequestRaw(bytes32 transactionId, address sender, bytes memory request) external {\n BridgeTransaction memory transaction = getBridgeTransaction(request);\n emit BridgeRequested(\n transactionId,\n transaction.originSender,\n request,\n transaction.destChainId,\n transaction.originToken,\n transaction.destToken,\n transaction.originAmount,\n transaction.destAmount,\n transaction.sendChainGas\n );\n }\n\n function mockBridgeRelayer(\n bytes32 transactionId,\n address relayer,\n address to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n )\n external\n {\n emit BridgeRelayed(\n transactionId, relayer, to, originChainId, originToken, destToken, originAmount, destAmount, chainGasAmount\n );\n }\n\n function bridge(BridgeParams memory params) external payable {\n revert(\"not implemented\");\n }\n\n function relay(bytes memory request) external payable {\n revert(\"not implemented\");\n }\n\n function prove(bytes memory request, bytes32 destTxHash) external {\n revert(\"not implemented\");\n }\n\n function canClaim(bytes32 transactionid, address relayer) external view returns (bool) {\n revert(\"not implemented\");\n }\n\n function claim(bytes memory request, address to) external {\n revert(\"not implemented\");\n }\n\n function dispute(bytes32 transactionId) external {\n revert(\"not implemented\");\n }\n\n function refund(bytes memory request) external {\n revert(\"not implemented\");\n }\n}\n","language":"Solidity","languageVersion":"0.8.20","compilerVersion":"0.8.20","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"39250:5018:0:-:0;;;;;;;;;;;;;;;-1:-1:-1;;;39250:5018:0;;;;;;;;;;;;;;;;;","srcMapRuntime":"39250:5018:0:-:0;;;;;;;;","abiDefinition":[{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"currentAllowance","type":"uint256"},{"internalType":"uint256","name":"requestedDecrease","type":"uint256"}],"name":"SafeERC20FailedDecreaseAllowance","type":"error"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"SafeERC20FailedOperation","type":"error"}],"userDoc":{"kind":"user","methods":{},"version":1},"developerDoc":{"details":"Wrappers around ERC20 operations that throw on failure (when the token contract returns false). Tokens that return no value (and instead revert or throw on failure) are also supported, non-reverting calls are assumed to be successful. To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract, which allows you to call the safe operations as `token.safeTransfer(...)`, etc.","errors":{"SafeERC20FailedDecreaseAllowance(address,uint256,uint256)":[{"details":"Indicates a failed `decreaseAllowance` request."}],"SafeERC20FailedOperation(address)":[{"details":"An operation with an ERC20 token failed."}]},"kind":"dev","methods":{},"title":"SafeERC20","version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.20+commit.a1b79de6\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"currentAllowance\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"requestedDecrease\",\"type\":\"uint256\"}],\"name\":\"SafeERC20FailedDecreaseAllowance\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"}],\"name\":\"SafeERC20FailedOperation\",\"type\":\"error\"}],\"devdoc\":{\"details\":\"Wrappers around ERC20 operations that throw on failure (when the token contract returns false). Tokens that return no value (and instead revert or throw on failure) are also supported, non-reverting calls are assumed to be successful. To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract, which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\",\"errors\":{\"SafeERC20FailedDecreaseAllowance(address,uint256,uint256)\":[{\"details\":\"Indicates a failed `decreaseAllowance` request.\"}],\"SafeERC20FailedOperation(address)\":[{\"details\":\"An operation with an ERC20 token failed.\"}]},\"kind\":\"dev\",\"methods\":{},\"title\":\"SafeERC20\",\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeMock.sol\":\"SafeERC20\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeMock.sol\":{\"keccak256\":\"0x620e81214ecd324ae8b971219291f176c454ce76fb1c01d656428096da8f1366\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://18e556772c12e13aa2d52a50cc7c48e676c8d5af22b90adaf7befb39cdd08e64\",\"dweb:/ipfs/QmPrQc98TxHCFMeuFNADyjr6Nqo52rHhHy1LBcsVdMRXjL\"]}},\"version\":1}"},"hashes":{}},"solidity/FastBridgeMock.sol:UniversalTokenLib":{"code":"0x60566037600b82828239805160001a607314602a57634e487b7160e01b600052600060045260246000fd5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600080fdfea26469706673582212202023f39864841dc931462dc7b8bdf9ede1735f580a13a3476b5bff0f5f9ca81b64736f6c63430008140033","runtime-code":"0x73000000000000000000000000000000000000000030146080604052600080fdfea26469706673582212202023f39864841dc931462dc7b8bdf9ede1735f580a13a3476b5bff0f5f9ca81b64736f6c63430008140033","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.20 ^0.8.20;\n\n// contracts/interfaces/IAdmin.sol\n\ninterface IAdmin {\n // ============ Events ============\n\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n event ChainGasAmountUpdated(uint256 oldChainGasAmount, uint256 newChainGasAmount);\n\n // ============ Methods ============\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n\n function setChainGasAmount(uint256 newChainGasAmount) external;\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/libs/Errors.sol\n\nerror DeadlineExceeded();\nerror DeadlineNotExceeded();\nerror DeadlineTooShort();\nerror InsufficientOutputAmount();\n\nerror MsgValueIncorrect();\nerror PoolNotFound();\nerror TokenAddressMismatch();\nerror TokenNotContract();\nerror TokenNotETH();\nerror TokensIdentical();\n\nerror ChainIncorrect();\nerror AmountIncorrect();\nerror ZeroAddress();\n\nerror DisputePeriodNotPassed();\nerror DisputePeriodPassed();\nerror SenderIncorrect();\nerror StatusIncorrect();\nerror TransactionIdIncorrect();\nerror TransactionRelayed();\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// contracts/libs/UniversalToken.sol\n\nlibrary UniversalTokenLib {\n using SafeERC20 for IERC20;\n\n address internal constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Transfers tokens to the given account. Reverts if transfer is not successful.\n /// @dev This might trigger fallback, if ETH is transferred to the contract.\n /// Make sure this can not lead to reentrancy attacks.\n function universalTransfer(address token, address to, uint256 value) internal {\n // Don't do anything, if need to send tokens to this address\n if (to == address(this)) return;\n // Don't do anything, if trying to send zero value\n if (value == 0) return;\n if (token == ETH_ADDRESS) {\n /// @dev Note: this can potentially lead to executing code in `to`.\n // solhint-disable-next-line avoid-low-level-calls\n (bool success,) = to.call{value: value}(\"\");\n require(success, \"ETH transfer failed\");\n } else {\n IERC20(token).safeTransfer(to, value);\n }\n }\n\n /// @notice Issues an infinite allowance to the spender, if the current allowance is insufficient\n /// to spend the given amount.\n function universalApproveInfinity(address token, address spender, uint256 amountToSpend) internal {\n // ETH Chad doesn't require your approval\n if (token == ETH_ADDRESS) return;\n // No-op if allowance is already sufficient\n uint256 allowance = IERC20(token).allowance(address(this), spender);\n if (allowance \u003e= amountToSpend) return;\n // Otherwise, reset approval to 0 and set to max allowance\n if (allowance \u003e 0) IERC20(token).safeDecreaseAllowance(spender, allowance);\n IERC20(token).safeIncreaseAllowance(spender, type(uint256).max);\n }\n\n /// @notice Returns the balance of the given token (or native ETH) for the given account.\n function universalBalanceOf(address token, address account) internal view returns (uint256) {\n if (token == ETH_ADDRESS) {\n return account.balance;\n } else {\n return IERC20(token).balanceOf(account);\n }\n }\n\n /// @dev Checks that token is a contract and not ETH_ADDRESS.\n function assertIsContract(address token) internal view {\n // Check that ETH_ADDRESS was not used (in case this is a predeploy on any of the chains)\n if (token == UniversalTokenLib.ETH_ADDRESS) revert TokenNotContract();\n // Check that token is not an EOA\n if (token.code.length == 0) revert TokenNotContract();\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/Admin.sol\n\ncontract Admin is IAdmin, AccessControlEnumerable {\n using UniversalTokenLib for address;\n\n bytes32 public constant RELAYER_ROLE = keccak256(\"RELAYER_ROLE\");\n bytes32 public constant REFUNDER_ROLE = keccak256(\"REFUNDER_ROLE\");\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n uint256 public constant FEE_BPS = 1e6;\n uint256 public constant FEE_RATE_MAX = 0.01e6; // max 1% on origin amount\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Chain gas amount to forward as rebate if requested\n uint256 public chainGasAmount;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n }\n\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n require(newFeeRate \u003c= FEE_RATE_MAX, \"newFeeRate \u003e max\");\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n token.universalTransfer(recipient, feeAmount);\n emit FeesSwept(token, recipient, feeAmount);\n }\n\n function setChainGasAmount(uint256 newChainGasAmount) external onlyRole(GOVERNOR_ROLE) {\n uint256 oldChainGasAmount = chainGasAmount;\n chainGasAmount = newChainGasAmount;\n emit ChainGasAmountUpdated(oldChainGasAmount, newChainGasAmount);\n }\n}\n\n// contracts/FastBridge.sol\n\ncontract FastBridge is IFastBridge, Admin {\n using SafeERC20 for IERC20;\n using UniversalTokenLib for address;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Delay for a transaction after which it could be permisionlessly refunded\n uint256 public constant REFUND_DELAY = 7 days;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeStatus) public bridgeStatuses;\n /// @notice Proof of relayed bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeProof) public bridgeProofs;\n /// @notice Whether bridge has been relayed on destination chain\n mapping(bytes32 =\u003e bool) public bridgeRelays;\n\n /// @dev to prevent replays\n uint256 public nonce;\n // @dev the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @notice Pulls a requested token from the user to the requested recipient.\n /// @dev Be careful of re-entrancy issues when msg.value \u003e 0 and recipient != address(this)\n function _pullToken(address recipient, address token, uint256 amount) internal returns (uint256 amountPulled) {\n if (token != UniversalTokenLib.ETH_ADDRESS) {\n token.assertIsContract();\n // Record token balance before transfer\n amountPulled = IERC20(token).balanceOf(recipient);\n // Token needs to be pulled only if msg.value is zero\n // This way user can specify WETH as the origin asset\n IERC20(token).safeTransferFrom(msg.sender, recipient, amount);\n // Use the difference between the recorded balance and the current balance as the amountPulled\n amountPulled = IERC20(token).balanceOf(recipient) - amountPulled;\n } else {\n // Otherwise, we need to check that ETH amount matches msg.value\n if (amount != msg.value) revert MsgValueIncorrect();\n // Transfer value to recipient if not this address\n if (recipient != address(this)) token.universalTransfer(recipient, amount);\n // We will forward msg.value in the external call later, if recipient is not this contract\n amountPulled = msg.value;\n }\n }\n\n /// @inheritdoc IFastBridge\n function getBridgeTransaction(bytes memory request) public pure returns (BridgeTransaction memory) {\n return abi.decode(request, (BridgeTransaction));\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n // check bridge params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n\n // transfer tokens to bridge contract\n // @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _pullToken(address(this), params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n\n // set status to requested\n bytes memory request = abi.encode(\n BridgeTransaction({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n sendChainGas: params.sendChainGas,\n deadline: params.deadline,\n nonce: nonce++ // increment nonce on every bridge\n })\n );\n bytes32 transactionId = keccak256(request);\n bridgeStatuses[transactionId] = BridgeStatus.REQUESTED;\n\n emit BridgeRequested(\n transactionId,\n params.sender,\n request,\n params.dstChainId,\n params.originToken,\n params.destToken,\n originAmount,\n params.destAmount,\n params.sendChainGas\n );\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes memory request) external payable onlyRole(RELAYER_ROLE) {\n bytes32 transactionId = keccak256(request);\n BridgeTransaction memory transaction = getBridgeTransaction(request);\n if (transaction.destChainId != uint32(block.chainid)) revert ChainIncorrect();\n\n // check haven't exceeded deadline for relay to happen\n if (block.timestamp \u003e transaction.deadline) revert DeadlineExceeded();\n\n // mark bridge transaction as relayed\n if (bridgeRelays[transactionId]) revert TransactionRelayed();\n bridgeRelays[transactionId] = true;\n\n // transfer tokens to recipient on destination chain and gas rebate if requested\n address to = transaction.destRecipient;\n address token = transaction.destToken;\n uint256 amount = transaction.destAmount;\n\n uint256 rebate = chainGasAmount;\n if (!transaction.sendChainGas) {\n // forward erc20\n rebate = 0;\n _pullToken(to, token, amount);\n } else if (token == UniversalTokenLib.ETH_ADDRESS) {\n // lump in gas rebate into amount in native gas token\n _pullToken(to, token, amount + rebate);\n } else {\n // forward erc20 then forward gas rebate in native gas token\n _pullToken(to, token, amount);\n _pullToken(to, UniversalTokenLib.ETH_ADDRESS, rebate);\n }\n\n emit BridgeRelayed(\n transactionId,\n msg.sender,\n to,\n transaction.originChainId,\n transaction.originToken,\n transaction.destToken,\n transaction.originAmount,\n transaction.destAmount,\n rebate\n );\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes memory request, bytes32 destTxHash) external onlyRole(RELAYER_ROLE) {\n bytes32 transactionId = keccak256(request);\n // update bridge tx status given proof provided\n if (bridgeStatuses[transactionId] != BridgeStatus.REQUESTED) revert StatusIncorrect();\n bridgeStatuses[transactionId] = BridgeStatus.RELAYER_PROVED;\n bridgeProofs[transactionId] = BridgeProof({timestamp: uint96(block.timestamp), relayer: msg.sender}); // overflow ok\n\n emit BridgeProofProvided(transactionId, msg.sender, destTxHash);\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint96(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint96).max but\n /// proof.timestamp \u003c type(uint96).max via unchecked statement\n /// @param proof The bridge proof\n /// @return delta Time delta since proof submitted\n function _timeSince(BridgeProof memory proof) internal view returns (uint256 delta) {\n unchecked {\n delta = uint96(block.timestamp) - proof.timestamp;\n }\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n if (bridgeStatuses[transactionId] != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n BridgeProof memory proof = bridgeProofs[transactionId];\n if (proof.relayer != relayer) revert SenderIncorrect();\n return _timeSince(proof) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes memory request, address to) external onlyRole(RELAYER_ROLE) {\n bytes32 transactionId = keccak256(request);\n BridgeTransaction memory transaction = getBridgeTransaction(request);\n\n // update bridge tx status if able to claim origin collateral\n if (bridgeStatuses[transactionId] != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n\n BridgeProof memory proof = bridgeProofs[transactionId];\n if (proof.relayer != msg.sender) revert SenderIncorrect();\n if (_timeSince(proof) \u003c= DISPUTE_PERIOD) revert DisputePeriodNotPassed();\n\n bridgeStatuses[transactionId] = BridgeStatus.RELAYER_CLAIMED;\n\n // update protocol fees if origin fee amount exists\n if (transaction.originFeeAmount \u003e 0) protocolFees[transaction.originToken] += transaction.originFeeAmount;\n\n // transfer origin collateral less fee to specified address\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositClaimed(transactionId, msg.sender, to, token, amount);\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n if (bridgeStatuses[transactionId] != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(bridgeProofs[transactionId]) \u003e DISPUTE_PERIOD) revert DisputePeriodPassed();\n\n // @dev relayer gets slashed effectively if dest relay has gone thru\n bridgeStatuses[transactionId] = BridgeStatus.REQUESTED;\n delete bridgeProofs[transactionId];\n\n emit BridgeProofDisputed(transactionId, msg.sender);\n }\n\n /// @inheritdoc IFastBridge\n function refund(bytes memory request) external {\n bytes32 transactionId = keccak256(request);\n BridgeTransaction memory transaction = getBridgeTransaction(request);\n\n if (hasRole(REFUNDER_ROLE, msg.sender)) {\n // Refunder can refund if deadline has passed\n if (block.timestamp \u003c= transaction.deadline) revert DeadlineNotExceeded();\n } else {\n // Permissionless refund is allowed after REFUND_DELAY\n if (block.timestamp \u003c= transaction.deadline + REFUND_DELAY) revert DeadlineNotExceeded();\n }\n\n // set status to refunded if still in requested state\n if (bridgeStatuses[transactionId] != BridgeStatus.REQUESTED) revert StatusIncorrect();\n bridgeStatuses[transactionId] = BridgeStatus.REFUNDED;\n\n // transfer origin collateral back to original sender\n address to = transaction.originSender;\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount + transaction.originFeeAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n }\n}\n\n// test/FastBridgeMock.sol\n\ncontract FastBridgeMock is IFastBridge, Admin {\n // @dev the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @dev to prevent replays\n uint256 public nonce;\n\n function getBridgeTransaction(bytes memory request) public pure returns (BridgeTransaction memory) {\n return abi.decode(request, (BridgeTransaction));\n }\n\n // used for testing in go.\n // see: https://ethereum.stackexchange.com/questions/21155/how-to-expose-enum-in-solidity-contract\n // make sure to update fastbridge/status.go if this changes\n // or underliyng enum changes.\n //\n // TODO: a foundry test should be added to ensure this is always in sync.\n function getEnumKeyByValue(FastBridge.BridgeStatus keyValue) public pure returns (string memory) {\n if (FastBridge.BridgeStatus.NULL == keyValue) return \"NULL\";\n if (FastBridge.BridgeStatus.REQUESTED == keyValue) return \"REQUESTED\";\n if (FastBridge.BridgeStatus.RELAYER_PROVED == keyValue) return \"RELAYER_PROVED\";\n if (FastBridge.BridgeStatus.RELAYER_CLAIMED == keyValue) return \"RELAYER_CLAIMED\";\n if (FastBridge.BridgeStatus.REFUNDED == keyValue) return \"REFUNDED\";\n return \"\";\n }\n\n function mockBridgeRequest(bytes32 transactionId, address sender, BridgeParams memory params) external {\n uint256 originFeeAmount = (params.originAmount * protocolFeeRate) / FEE_BPS;\n params.originAmount -= originFeeAmount;\n\n bytes memory request = abi.encode(\n BridgeTransaction({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: params.originAmount, // includes relayer fee\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n sendChainGas: params.sendChainGas,\n deadline: params.deadline,\n nonce: nonce++ // increment nonce on every bridge\n })\n );\n\n emit BridgeRequested(\n transactionId,\n params.sender,\n request,\n params.dstChainId,\n params.originToken,\n params.destToken,\n params.originAmount,\n params.destAmount,\n params.sendChainGas\n );\n }\n\n function mockBridgeRequestRaw(bytes32 transactionId, address sender, bytes memory request) external {\n BridgeTransaction memory transaction = getBridgeTransaction(request);\n emit BridgeRequested(\n transactionId,\n transaction.originSender,\n request,\n transaction.destChainId,\n transaction.originToken,\n transaction.destToken,\n transaction.originAmount,\n transaction.destAmount,\n transaction.sendChainGas\n );\n }\n\n function mockBridgeRelayer(\n bytes32 transactionId,\n address relayer,\n address to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n )\n external\n {\n emit BridgeRelayed(\n transactionId, relayer, to, originChainId, originToken, destToken, originAmount, destAmount, chainGasAmount\n );\n }\n\n function bridge(BridgeParams memory params) external payable {\n revert(\"not implemented\");\n }\n\n function relay(bytes memory request) external payable {\n revert(\"not implemented\");\n }\n\n function prove(bytes memory request, bytes32 destTxHash) external {\n revert(\"not implemented\");\n }\n\n function canClaim(bytes32 transactionid, address relayer) external view returns (bool) {\n revert(\"not implemented\");\n }\n\n function claim(bytes memory request, address to) external {\n revert(\"not implemented\");\n }\n\n function dispute(bytes32 transactionId) external {\n revert(\"not implemented\");\n }\n\n function refund(bytes memory request) external {\n revert(\"not implemented\");\n }\n}\n","language":"Solidity","languageVersion":"0.8.20","compilerVersion":"0.8.20","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"51209:2551:0:-:0;;;;;;;;;;;;;;;-1:-1:-1;;;51209:2551:0;;;;;;;;;;;;;;;;;","srcMapRuntime":"51209:2551:0:-:0;;;;;;;;","abiDefinition":[],"userDoc":{"kind":"user","methods":{},"version":1},"developerDoc":{"kind":"dev","methods":{},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.20+commit.a1b79de6\"},\"language\":\"Solidity\",\"output\":{\"abi\":[],\"devdoc\":{\"kind\":\"dev\",\"methods\":{},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeMock.sol\":\"UniversalTokenLib\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeMock.sol\":{\"keccak256\":\"0x620e81214ecd324ae8b971219291f176c454ce76fb1c01d656428096da8f1366\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://18e556772c12e13aa2d52a50cc7c48e676c8d5af22b90adaf7befb39cdd08e64\",\"dweb:/ipfs/QmPrQc98TxHCFMeuFNADyjr6Nqo52rHhHy1LBcsVdMRXjL\"]}},\"version\":1}"},"hashes":{}}} \ No newline at end of file diff --git a/services/rfq/contracts/testcontracts/fastbridgemockv2/fastbridgemockv2.metadata.go b/services/rfq/contracts/testcontracts/fastbridgemockv2/fastbridgemockv2.metadata.go new file mode 100644 index 0000000000..5af90ae50a --- /dev/null +++ b/services/rfq/contracts/testcontracts/fastbridgemockv2/fastbridgemockv2.metadata.go @@ -0,0 +1,25 @@ +// Code generated by synapse abigen DO NOT EDIT. +package fastbridgemockv2 + +import ( + _ "embed" + "encoding/json" + "github.com/ethereum/go-ethereum/common/compiler" +) + +// rawContracts are the json we use to derive the processed contracts +// +//go:embed fastbridgemockv2.contractinfo.json +var rawContracts []byte + +// Contracts are unmarshalled on start +var Contracts map[string]*compiler.Contract + +func init() { + // load contract metadata + var err error + err = json.Unmarshal(rawContracts, &Contracts) + if err != nil { + panic(err) + } +} diff --git a/services/rfq/contracts/testcontracts/fastbridgemockv2/generate.go b/services/rfq/contracts/testcontracts/fastbridgemockv2/generate.go new file mode 100644 index 0000000000..aab3d2f5d2 --- /dev/null +++ b/services/rfq/contracts/testcontracts/fastbridgemockv2/generate.go @@ -0,0 +1,3 @@ +package fastbridgemockv2 + +//go:generate go run github.com/synapsecns/sanguine/tools/abigen generate --sol ../../../../../packages/contracts-rfq/flattened/FastBridgeMock.sol --pkg fastbridgemockv2 --sol-version 0.8.20 --filename fastbridgemockv2 --evm-version istanbul diff --git a/services/rfq/contracts/testcontracts/fastbridgemockv2/helper.go b/services/rfq/contracts/testcontracts/fastbridgemockv2/helper.go new file mode 100644 index 0000000000..2f1cd07d3e --- /dev/null +++ b/services/rfq/contracts/testcontracts/fastbridgemockv2/helper.go @@ -0,0 +1,35 @@ +package fastbridgemockv2 + +import ( + "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/vm" +) + +// FastBridgeMockRef is a bound fast bridge contract that returns the address of the contract. +// +//nolint:golint +type FastBridgeMockRef struct { + *FastBridgeMock + address common.Address +} + +// Address gets the ocntract address. +func (f *FastBridgeMockRef) Address() common.Address { + return f.address +} + +// NewFastBridgeMockRef creates a new fast bridge mock contract with a ref. +func NewFastBridgeMockRef(address common.Address, backend bind.ContractBackend) (*FastBridgeMockRef, error) { + fastbridgemock, err := NewFastBridgeMock(address, backend) + if err != nil { + return nil, err + } + + return &FastBridgeMockRef{ + FastBridgeMock: fastbridgemock, + address: address, + }, nil +} + +var _ vm.ContractRef = &FastBridgeMockRef{} From d3dbeb0f5817a2e9015ed46ec1b7ff594c438a7f Mon Sep 17 00:00:00 2001 From: Daniel Wasserman Date: Fri, 11 Oct 2024 13:58:10 -0500 Subject: [PATCH 32/85] Fix: build --- services/rfq/relayer/limiter/limiter_test.go | 10 +++++----- services/rfq/relayer/quoter/quoter_test.go | 6 +++--- services/rfq/relayer/relapi/server_test.go | 4 ++-- services/rfq/relayer/reldb/base/model_test.go | 4 ++-- services/rfq/relayer/service/suite_test.go | 14 +++++++------- services/rfq/testutil/contracttype.go | 4 ++-- services/rfq/testutil/deployers.go | 6 +++--- services/rfq/testutil/typecast.go | 6 +++--- 8 files changed, 27 insertions(+), 27 deletions(-) diff --git a/services/rfq/relayer/limiter/limiter_test.go b/services/rfq/relayer/limiter/limiter_test.go index 03e224ed99..4ed7328730 100644 --- a/services/rfq/relayer/limiter/limiter_test.go +++ b/services/rfq/relayer/limiter/limiter_test.go @@ -7,7 +7,7 @@ import ( "github.com/ethereum/go-ethereum/params" "github.com/stretchr/testify/mock" listenerMock "github.com/synapsecns/sanguine/ethergo/listener/mocks" - "github.com/synapsecns/sanguine/services/rfq/contracts/fastbridge" + "github.com/synapsecns/sanguine/services/rfq/contracts/fastbridgev2" "github.com/synapsecns/sanguine/services/rfq/relayer/limiter" "github.com/synapsecns/sanguine/services/rfq/relayer/quoter/mocks" "github.com/synapsecns/sanguine/services/rfq/relayer/reldb" @@ -22,7 +22,7 @@ func (l *LimiterSuite) TestOverLimitEnoughConfirmations() { quote := reldb.QuoteRequest{ BlockNumber: 5, - Transaction: fastbridge.IFastBridgeBridgeTransaction{ + Transaction: fastbridgev2.IFastBridgeV2BridgeTransactionV2{ OriginChainId: 1, DestChainId: 2, OriginToken: util.EthAddress, @@ -46,7 +46,7 @@ func (l *LimiterSuite) TestUnderLimitEnoughConfirmations() { quote := reldb.QuoteRequest{ BlockNumber: 5, - Transaction: fastbridge.IFastBridgeBridgeTransaction{ + Transaction: fastbridgev2.IFastBridgeV2BridgeTransactionV2{ OriginChainId: 1, DestChainId: 2, OriginToken: util.EthAddress, @@ -67,7 +67,7 @@ func (l *LimiterSuite) TestUnderLimitNotEnoughConfirmations() { quote := reldb.QuoteRequest{ BlockNumber: 1, // same block number,but shouldnt matter - Transaction: fastbridge.IFastBridgeBridgeTransaction{ + Transaction: fastbridgev2.IFastBridgeV2BridgeTransactionV2{ OriginChainId: 1, DestChainId: 2, OriginToken: util.EthAddress, @@ -92,7 +92,7 @@ func (l *LimiterSuite) TestOverLimitNotEnoughConfirmations() { quote := reldb.QuoteRequest{ BlockNumber: 4, - Transaction: fastbridge.IFastBridgeBridgeTransaction{ + Transaction: fastbridgev2.IFastBridgeV2BridgeTransactionV2{ OriginChainId: 1, DestChainId: 2, OriginToken: util.EthAddress, diff --git a/services/rfq/relayer/quoter/quoter_test.go b/services/rfq/relayer/quoter/quoter_test.go index 1d6a52c7de..f60784e143 100644 --- a/services/rfq/relayer/quoter/quoter_test.go +++ b/services/rfq/relayer/quoter/quoter_test.go @@ -10,7 +10,7 @@ import ( "github.com/synapsecns/sanguine/core/testsuite" fetcherMocks "github.com/synapsecns/sanguine/ethergo/submitter/mocks" "github.com/synapsecns/sanguine/services/rfq/api/model" - "github.com/synapsecns/sanguine/services/rfq/contracts/fastbridge" + "github.com/synapsecns/sanguine/services/rfq/contracts/fastbridgev2" inventoryMocks "github.com/synapsecns/sanguine/services/rfq/relayer/inventory/mocks" "github.com/synapsecns/sanguine/services/rfq/relayer/pricer" priceMocks "github.com/synapsecns/sanguine/services/rfq/relayer/pricer/mocks" @@ -115,7 +115,7 @@ func (s *QuoterSuite) TestShouldProcess() { BlockNumber: 1, OriginTokenDecimals: 6, DestTokenDecimals: 6, - Transaction: fastbridge.IFastBridgeBridgeTransaction{ + Transaction: fastbridgev2.IFastBridgeV2BridgeTransactionV2{ OriginChainId: s.origin, DestChainId: s.destination, OriginToken: common.HexToAddress("0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48"), @@ -146,7 +146,7 @@ func (s *QuoterSuite) TestIsProfitable() { BlockNumber: 1, OriginTokenDecimals: 6, DestTokenDecimals: 6, - Transaction: fastbridge.IFastBridgeBridgeTransaction{ + Transaction: fastbridgev2.IFastBridgeV2BridgeTransactionV2{ OriginChainId: s.origin, DestChainId: s.destination, OriginToken: common.HexToAddress("0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48"), diff --git a/services/rfq/relayer/relapi/server_test.go b/services/rfq/relayer/relapi/server_test.go index be4ffe0600..f9dd83717c 100644 --- a/services/rfq/relayer/relapi/server_test.go +++ b/services/rfq/relayer/relapi/server_test.go @@ -17,7 +17,7 @@ import ( "github.com/ethereum/go-ethereum/crypto" "github.com/synapsecns/sanguine/core/retry" submitterdb "github.com/synapsecns/sanguine/ethergo/submitter/db" - "github.com/synapsecns/sanguine/services/rfq/contracts/fastbridge" + "github.com/synapsecns/sanguine/services/rfq/contracts/fastbridgev2" "github.com/synapsecns/sanguine/services/rfq/relayer/relapi" "github.com/synapsecns/sanguine/services/rfq/relayer/reldb" ) @@ -202,7 +202,7 @@ func (c *RelayerServerSuite) getTestQuoteRequest(status reldb.QuoteRequestStatus DestTokenDecimals: 6, TransactionID: txID, Status: status, - Transaction: fastbridge.IFastBridgeBridgeTransaction{ + Transaction: fastbridgev2.IFastBridgeV2BridgeTransactionV2{ OriginChainId: c.originChainID, DestChainId: c.destChainID, OriginAmount: big.NewInt(100), diff --git a/services/rfq/relayer/reldb/base/model_test.go b/services/rfq/relayer/reldb/base/model_test.go index e7a1508115..99b98baae1 100644 --- a/services/rfq/relayer/reldb/base/model_test.go +++ b/services/rfq/relayer/reldb/base/model_test.go @@ -9,7 +9,7 @@ import ( "github.com/brianvoe/gofakeit/v6" "github.com/ethereum/go-ethereum/common" - "github.com/synapsecns/sanguine/services/rfq/contracts/fastbridge" + "github.com/synapsecns/sanguine/services/rfq/contracts/fastbridgev2" "github.com/synapsecns/sanguine/services/rfq/relayer/reldb" "github.com/synapsecns/sanguine/services/rfq/relayer/reldb/base" ) @@ -23,7 +23,7 @@ func TestRoundtripBetweenFromQuoteRequestAndToQuoteRequest(t *testing.T) { TransactionID: [32]byte{}, RawRequest: []byte(gofakeit.Paragraph(1, 2, 3, " ")), Sender: common.Address{}, - Transaction: fastbridge.IFastBridgeBridgeTransaction{ + Transaction: fastbridgev2.IFastBridgeV2BridgeTransactionV2{ OriginChainId: 1, DestChainId: 2, OriginSender: common.Address{}, diff --git a/services/rfq/relayer/service/suite_test.go b/services/rfq/relayer/service/suite_test.go index d02a7dac97..b172c08d28 100644 --- a/services/rfq/relayer/service/suite_test.go +++ b/services/rfq/relayer/service/suite_test.go @@ -16,7 +16,7 @@ import ( "github.com/synapsecns/sanguine/ethergo/backends/geth" "github.com/synapsecns/sanguine/ethergo/mocks" omnirpcHelper "github.com/synapsecns/sanguine/services/omnirpc/testhelper" - "github.com/synapsecns/sanguine/services/rfq/contracts/testcontracts/fastbridgev2mock" + "github.com/synapsecns/sanguine/services/rfq/contracts/testcontracts/fastbridgemockv2" "github.com/synapsecns/sanguine/services/rfq/relayer/relconfig" "github.com/synapsecns/sanguine/services/rfq/relayer/service" "github.com/synapsecns/sanguine/services/rfq/testutil" @@ -60,8 +60,8 @@ func (r *RelayerTestSuite) SetupTest() { serverURL := omnirpcHelper.NewOmnirpcServer(r.GetTestContext(), r.T(), r.destBackend, r.originBackend) - originContract, _ := r.manager.GetMockFastBridgeV2(r.GetTestContext(), r.originBackend) - destContract, _ := r.manager.GetMockFastBridgeV2(r.GetTestContext(), r.destBackend) + originContract, _ := r.manager.GetMockFastBridge(r.GetTestContext(), r.originBackend) + destContract, _ := r.manager.GetMockFastBridge(r.GetTestContext(), r.destBackend) r.cfg = relconfig.Config{ Database: relconfig.DatabaseConfig{ Type: dbcommon.Sqlite.String(), @@ -89,7 +89,7 @@ func (r *RelayerTestSuite) TestStore() { r.NoError(rel.StartChainParser(r.GetTestContext())) }() - _, oc := r.manager.GetMockFastBridgeV2(r.GetTestContext(), r.originBackend) + _, oc := r.manager.GetMockFastBridge(r.GetTestContext(), r.originBackend) auth := r.originBackend.GetTxContext(r.GetTestContext(), nil) @@ -100,7 +100,7 @@ func (r *RelayerTestSuite) TestStore() { r.NoError(err) //nolint: typecheck - tx, err := oc.MockBridgeRequest(auth.TransactOpts, [32]byte(crypto.Keccak256([]byte("3"))), mocks.MockAddress(), fastbridgev2mock.IFastBridgeV2BridgeParams{ + tx, err := oc.MockBridgeRequest(auth.TransactOpts, [32]byte(crypto.Keccak256([]byte("3"))), mocks.MockAddress(), fastbridgemockv2.IFastBridgeBridgeParams{ DstChainId: uint32(r.destBackend.GetChainID()), To: mocks.MockAddress(), OriginToken: originToken.Address(), @@ -126,7 +126,7 @@ func (r *RelayerTestSuite) TestCommit() { r.NoError(rel.StartChainParser(r.GetTestContext())) }() - _, oc := r.manager.GetMockFastBridgeV2(r.GetTestContext(), r.originBackend) + _, oc := r.manager.GetMockFastBridge(r.GetTestContext(), r.originBackend) auth := r.originBackend.GetTxContext(r.GetTestContext(), nil) @@ -137,7 +137,7 @@ func (r *RelayerTestSuite) TestCommit() { r.NoError(err) //nolint: typecheck - tx, err := oc.MockBridgeRequest(auth.TransactOpts, [32]byte(crypto.Keccak256([]byte("3"))), mocks.MockAddress(), fastbridgev2mock.IFastBridgeV2BridgeParams{ + tx, err := oc.MockBridgeRequest(auth.TransactOpts, [32]byte(crypto.Keccak256([]byte("3"))), mocks.MockAddress(), fastbridgemockv2.IFastBridgeBridgeParams{ DstChainId: uint32(r.destBackend.GetChainID()), To: mocks.MockAddress(), OriginToken: originToken.Address(), diff --git a/services/rfq/testutil/contracttype.go b/services/rfq/testutil/contracttype.go index a1d82ccbcf..1080d34896 100644 --- a/services/rfq/testutil/contracttype.go +++ b/services/rfq/testutil/contracttype.go @@ -6,7 +6,7 @@ import ( "github.com/synapsecns/sanguine/ethergo/contracts" "github.com/synapsecns/sanguine/services/rfq/contracts/fastbridge" "github.com/synapsecns/sanguine/services/rfq/contracts/testcontracts/dai" - "github.com/synapsecns/sanguine/services/rfq/contracts/testcontracts/fastbridgemock" + "github.com/synapsecns/sanguine/services/rfq/contracts/testcontracts/fastbridgemockv2" "github.com/synapsecns/sanguine/services/rfq/contracts/testcontracts/mockerc20" "github.com/synapsecns/sanguine/services/rfq/contracts/testcontracts/recipientmock" "github.com/synapsecns/sanguine/services/rfq/contracts/testcontracts/usdc" @@ -97,7 +97,7 @@ func (c contractTypeImpl) ContractInfo() *compiler.Contract { case MockERC20Type: return mockerc20.Contracts["solidity/MockERC20.sol:MockERC20"] case FastBridgeMockType: - return fastbridgemock.Contracts["solidity/FastBridgeMock.sol:FastBridgeMock"] + return fastbridgemockv2.Contracts["solidity/FastBridgeMock.sol:FastBridgeMock"] case RecipientMockType: return recipientmock.Contracts["solidity/RecipientMock.sol:RecipientMock"] case WETH9Type: diff --git a/services/rfq/testutil/deployers.go b/services/rfq/testutil/deployers.go index 0921cdddd2..492408c41f 100644 --- a/services/rfq/testutil/deployers.go +++ b/services/rfq/testutil/deployers.go @@ -15,7 +15,7 @@ import ( "github.com/synapsecns/sanguine/ethergo/deployer" "github.com/synapsecns/sanguine/ethergo/manager" "github.com/synapsecns/sanguine/services/rfq/contracts/fastbridgev2" - "github.com/synapsecns/sanguine/services/rfq/contracts/testcontracts/fastbridgemock" + "github.com/synapsecns/sanguine/services/rfq/contracts/testcontracts/fastbridgemockv2" "github.com/synapsecns/sanguine/services/rfq/contracts/testcontracts/recipientmock" ) @@ -135,9 +135,9 @@ func NewMockFastBridgeDeployer(registry deployer.GetOnlyContractRegistry, backen // Deploy deploys the mock fast bridge contract. func (m MockFastBridgeDeployer) Deploy(ctx context.Context) (contracts.DeployedContract, error) { return m.DeploySimpleContract(ctx, func(transactOps *bind.TransactOpts, backend bind.ContractBackend) (common.Address, *types.Transaction, interface{}, error) { - return fastbridgemock.DeployFastBridgeMock(transactOps, backend, transactOps.From) + return fastbridgemockv2.DeployFastBridgeMock(transactOps, backend, transactOps.From) }, func(address common.Address, backend bind.ContractBackend) (interface{}, error) { - return fastbridgemock.NewFastBridgeMockRef(address, backend) + return fastbridgemockv2.NewFastBridgeMockRef(address, backend) }) } diff --git a/services/rfq/testutil/typecast.go b/services/rfq/testutil/typecast.go index 6ba1f612e2..0e6a99fb92 100644 --- a/services/rfq/testutil/typecast.go +++ b/services/rfq/testutil/typecast.go @@ -8,7 +8,7 @@ import ( "github.com/synapsecns/sanguine/ethergo/manager" "github.com/synapsecns/sanguine/services/rfq/contracts/fastbridgev2" "github.com/synapsecns/sanguine/services/rfq/contracts/testcontracts/dai" - "github.com/synapsecns/sanguine/services/rfq/contracts/testcontracts/fastbridgemock" + "github.com/synapsecns/sanguine/services/rfq/contracts/testcontracts/fastbridgemockv2" "github.com/synapsecns/sanguine/services/rfq/contracts/testcontracts/mockerc20" "github.com/synapsecns/sanguine/services/rfq/contracts/testcontracts/recipientmock" "github.com/synapsecns/sanguine/services/rfq/contracts/testcontracts/usdc" @@ -31,10 +31,10 @@ func (d *DeployManager) GetMockERC20(ctx context.Context, backend backends.Simul } // GetMockFastBridge gets the mock fast bridge. -func (d *DeployManager) GetMockFastBridge(ctx context.Context, backend backends.SimulatedTestBackend) (contract contracts.DeployedContract, handle *fastbridgemock.FastBridgeMockRef) { +func (d *DeployManager) GetMockFastBridge(ctx context.Context, backend backends.SimulatedTestBackend) (contract contracts.DeployedContract, handle *fastbridgemockv2.FastBridgeMockRef) { d.T().Helper() - return manager.GetContract[*fastbridgemock.FastBridgeMockRef](ctx, d.T(), d, backend, FastBridgeMockType) + return manager.GetContract[*fastbridgemockv2.FastBridgeMockRef](ctx, d.T(), d, backend, FastBridgeMockType) } // GetMockRecipient gets the mock recipient. From 0bc22c58644a883d76eb13715ec8aea8e008491c Mon Sep 17 00:00:00 2001 From: Daniel Wasserman Date: Fri, 11 Oct 2024 14:09:32 -0500 Subject: [PATCH 33/85] Cleanup: lint --- services/rfq/contracts/fastbridge/status.go | 2 ++ services/rfq/contracts/fastbridgev2/generate.go | 1 + services/rfq/contracts/fastbridgev2/parser.go | 1 - services/rfq/contracts/fastbridgev2/status.go | 2 ++ .../contracts/testcontracts/fastbridgemockv2/generate.go | 1 + .../rfq/contracts/testcontracts/recipientmock/generate.go | 1 + services/rfq/e2e/rfq_test.go | 2 +- services/rfq/relayer/reldb/base/model.go | 2 ++ services/rfq/relayer/service/handlers.go | 2 ++ services/rfq/relayer/service/suite_test.go | 2 ++ services/rfq/testutil/contracttype.go | 6 +++--- services/rfq/testutil/typecast.go | 2 +- 12 files changed, 18 insertions(+), 6 deletions(-) diff --git a/services/rfq/contracts/fastbridge/status.go b/services/rfq/contracts/fastbridge/status.go index 1a8b9605fc..82867f471d 100644 --- a/services/rfq/contracts/fastbridge/status.go +++ b/services/rfq/contracts/fastbridge/status.go @@ -25,6 +25,8 @@ func (b BridgeStatus) Int() uint8 { } // set all contact types. +// +//nolint:gosec,intrange func init() { for i := 0; i < len(_BridgeStatus_index)-1; i++ { contractType := BridgeStatus(i) diff --git a/services/rfq/contracts/fastbridgev2/generate.go b/services/rfq/contracts/fastbridgev2/generate.go index 752d9897fe..5b3b63cdbf 100644 --- a/services/rfq/contracts/fastbridgev2/generate.go +++ b/services/rfq/contracts/fastbridgev2/generate.go @@ -1,3 +1,4 @@ +// Package fastbridgev2 is the fast bridge v2 contract. package fastbridgev2 //go:generate go run github.com/synapsecns/sanguine/tools/abigen generate --sol ../../../../packages/contracts-rfq/flattened/FastBridgeV2.sol --pkg fastbridgev2 --sol-version 0.8.24 --filename fastbridgev2 --evm-version istanbul diff --git a/services/rfq/contracts/fastbridgev2/parser.go b/services/rfq/contracts/fastbridgev2/parser.go index 15a662b4b9..c6e5fd429d 100644 --- a/services/rfq/contracts/fastbridgev2/parser.go +++ b/services/rfq/contracts/fastbridgev2/parser.go @@ -91,7 +91,6 @@ func (p parserImpl) ParseEvent(log ethTypes.Log) (_ EventType, event interface{} return noOpEvent, nil, false } return eventType, disputed, true - } return eventType, nil, true diff --git a/services/rfq/contracts/fastbridgev2/status.go b/services/rfq/contracts/fastbridgev2/status.go index fa285fb77d..0b19532aae 100644 --- a/services/rfq/contracts/fastbridgev2/status.go +++ b/services/rfq/contracts/fastbridgev2/status.go @@ -25,6 +25,8 @@ func (b BridgeStatus) Int() uint8 { } // set all contact types. +// +//nolint:gosec,intrange func init() { for i := 0; i < len(_BridgeStatus_index)-1; i++ { contractType := BridgeStatus(i) diff --git a/services/rfq/contracts/testcontracts/fastbridgemockv2/generate.go b/services/rfq/contracts/testcontracts/fastbridgemockv2/generate.go index aab3d2f5d2..54040d842e 100644 --- a/services/rfq/contracts/testcontracts/fastbridgemockv2/generate.go +++ b/services/rfq/contracts/testcontracts/fastbridgemockv2/generate.go @@ -1,3 +1,4 @@ +// Package fastbridgemockv2 is a mock fast bridge contract for testing fast bridge interactions. package fastbridgemockv2 //go:generate go run github.com/synapsecns/sanguine/tools/abigen generate --sol ../../../../../packages/contracts-rfq/flattened/FastBridgeMock.sol --pkg fastbridgemockv2 --sol-version 0.8.20 --filename fastbridgemockv2 --evm-version istanbul diff --git a/services/rfq/contracts/testcontracts/recipientmock/generate.go b/services/rfq/contracts/testcontracts/recipientmock/generate.go index 5ab34dea53..fd7bb1fed8 100644 --- a/services/rfq/contracts/testcontracts/recipientmock/generate.go +++ b/services/rfq/contracts/testcontracts/recipientmock/generate.go @@ -1,3 +1,4 @@ +// Package recipientmock is a mock recipient contract for testing fast bridge interactions. package recipientmock //go:generate go run github.com/synapsecns/sanguine/tools/abigen generate --sol ../../../../../packages/contracts-rfq/flattened/RecipientMock.sol --pkg recipientmock --sol-version 0.8.20 --filename recipientmock --evm-version istanbul diff --git a/services/rfq/e2e/rfq_test.go b/services/rfq/e2e/rfq_test.go index 76d5d33eac..c5a777079f 100644 --- a/services/rfq/e2e/rfq_test.go +++ b/services/rfq/e2e/rfq_test.go @@ -393,6 +393,7 @@ func (i *IntegrationSuite) TestETHtoETH() { }) } +//nolint:gosec func (i *IntegrationSuite) TestArbitraryCall() { // start the relayer and guard go func() { @@ -501,7 +502,6 @@ func (i *IntegrationSuite) TestArbitraryCall() { i.NoError(err) } } - }() i.Eventually(func() bool { diff --git a/services/rfq/relayer/reldb/base/model.go b/services/rfq/relayer/reldb/base/model.go index 1ae4a38ec8..465bac64e2 100644 --- a/services/rfq/relayer/reldb/base/model.go +++ b/services/rfq/relayer/reldb/base/model.go @@ -123,6 +123,8 @@ type Rebalance struct { // FromQuoteRequest converts a quote request to an object that can be stored in the db. // TODO: add validation for deadline > uint64 // TODO: roundtripper test. +// +//nolint:gosec func FromQuoteRequest(request reldb.QuoteRequest) RequestForQuote { return RequestForQuote{ TransactionID: hexutil.Encode(request.TransactionID[:]), diff --git a/services/rfq/relayer/service/handlers.go b/services/rfq/relayer/service/handlers.go index f309106a99..23ffb8eeea 100644 --- a/services/rfq/relayer/service/handlers.go +++ b/services/rfq/relayer/service/handlers.go @@ -32,6 +32,8 @@ var ( // This is the first event emitted in the bridge process. It is emitted when a user calls bridge on chain. // To process it, we decode the bridge transaction and store all the data, marking it as seen. // This marks the event as seen. +// +//nolint:cyclop func (r *Relayer) handleBridgeRequestedLog(parentCtx context.Context, req *fastbridgev2.FastBridgeV2BridgeRequested, chainID uint64) (err error) { ctx, span := r.metrics.Tracer().Start(parentCtx, "handleBridgeRequestedLog", trace.WithAttributes( attribute.String("transaction_id", hexutil.Encode(req.TransactionId[:])), diff --git a/services/rfq/relayer/service/suite_test.go b/services/rfq/relayer/service/suite_test.go index b172c08d28..f46d2f54d5 100644 --- a/services/rfq/relayer/service/suite_test.go +++ b/services/rfq/relayer/service/suite_test.go @@ -109,6 +109,7 @@ func (r *RelayerTestSuite) TestStore() { DestAmount: big.NewInt(2), Deadline: big.NewInt(3), }) + r.NoError(err) r.originBackend.WaitForConfirmation(r.GetTestContext(), tx) r.T().Skip("TODO, test storage") @@ -146,6 +147,7 @@ func (r *RelayerTestSuite) TestCommit() { DestAmount: big.NewInt(2), Deadline: big.NewInt(3), }) + r.NoError(err) r.originBackend.WaitForConfirmation(r.GetTestContext(), tx) r.T().Skip("TODO, test storage") diff --git a/services/rfq/testutil/contracttype.go b/services/rfq/testutil/contracttype.go index 1080d34896..dd163fb789 100644 --- a/services/rfq/testutil/contracttype.go +++ b/services/rfq/testutil/contracttype.go @@ -53,10 +53,10 @@ const ( FastBridgeType contractTypeImpl = iota + 1 // FastBridge // MockERC20Type is a mock erc20 contract. MockERC20Type // MockERC20 - // FastBridgeMockType is a mock contract for testing fast bridge interactions - // TODO: rename contract to MockFastBridge. + // FastBridgeMockType is a mock contract for testing fast bridge interactions. + // TODO: rename contract to MockFastBridge. FastBridgeMockType // FastBridgeMock - // RecipientMockType is a mock contract for testing fast bridge interactions + // RecipientMockType is a mock contract for testing fast bridge interactions. RecipientMockType // RecipientMock // WETH9Type is the weth 9 contract. WETH9Type // WETH9 diff --git a/services/rfq/testutil/typecast.go b/services/rfq/testutil/typecast.go index 0e6a99fb92..1c4b14269f 100644 --- a/services/rfq/testutil/typecast.go +++ b/services/rfq/testutil/typecast.go @@ -37,7 +37,7 @@ func (d *DeployManager) GetMockFastBridge(ctx context.Context, backend backends. return manager.GetContract[*fastbridgemockv2.FastBridgeMockRef](ctx, d.T(), d, backend, FastBridgeMockType) } -// GetMockRecipient gets the mock recipient. +// GetRecipientMock gets the mock recipient. func (d *DeployManager) GetRecipientMock(ctx context.Context, backend backends.SimulatedTestBackend) (contract contracts.DeployedContract, handle *recipientmock.RecipientMockRef) { d.T().Helper() From 117ce5937ebfbc2aca754dd2a6bdc08e34827b65 Mon Sep 17 00:00:00 2001 From: Daniel Wasserman Date: Fri, 11 Oct 2024 14:33:27 -0500 Subject: [PATCH 34/85] Cleanup: remove unnecessary test --- .../rfq/contracts/fastbridge/status_test.go | 48 ------------------- 1 file changed, 48 deletions(-) delete mode 100644 services/rfq/contracts/fastbridge/status_test.go diff --git a/services/rfq/contracts/fastbridge/status_test.go b/services/rfq/contracts/fastbridge/status_test.go deleted file mode 100644 index 3028e6d245..0000000000 --- a/services/rfq/contracts/fastbridge/status_test.go +++ /dev/null @@ -1,48 +0,0 @@ -package fastbridge_test - -import ( - "github.com/ethereum/go-ethereum/accounts/abi/bind" - "github.com/stretchr/testify/suite" - "github.com/synapsecns/sanguine/core/testsuite" - "github.com/synapsecns/sanguine/ethergo/backends" - "github.com/synapsecns/sanguine/ethergo/backends/simulated" - "github.com/synapsecns/sanguine/services/rfq/contracts/fastbridge" - "github.com/synapsecns/sanguine/services/rfq/testutil" - "math/big" - "testing" -) - -// FastBridgeSuite tests the basic test suite. -type FastBridgeSuite struct { - *testsuite.TestSuite - backend backends.SimulatedTestBackend - manager *testutil.DeployManager -} - -// NewFastBridgeSuite creates a new FastBridge suite. -func NewFastBridgeSuite(tb testing.TB) *FastBridgeSuite { - tb.Helper() - return &FastBridgeSuite{ - TestSuite: testsuite.NewTestSuite(tb), - } -} - -func TestFastBridgeSuite(t *testing.T) { - suite.Run(t, NewFastBridgeSuite(t)) -} - -func (s *FastBridgeSuite) SetupTest() { - s.TestSuite.SetupTest() - s.backend = simulated.NewSimulatedBackendWithChainID(s.GetTestContext(), s.T(), big.NewInt(1)) - s.manager = testutil.NewDeployManager(s.T()) -} - -// TestStatusEnum makes sure. -func (s *FastBridgeSuite) TestStatusEnum() { - _, fb := s.manager.GetMockFastBridge(s.GetTestContext(), s.backend) - for _, status := range fastbridge.GetAllBridgeStatuses() { - solstatus, err := fb.GetEnumKeyByValue(&bind.CallOpts{Context: s.GetTestContext()}, status.Int()) - s.Require().NoError(err, "error getting enum key by value") - s.Require().Equal(solstatus, status.String(), "status %s does not match. BridgeStatus enums out of sync.", status) - } -} From 6dee3d1fe3062324daaf34ff474700fb59099d77 Mon Sep 17 00:00:00 2001 From: Daniel Wasserman Date: Fri, 11 Oct 2024 14:45:45 -0500 Subject: [PATCH 35/85] Fix: mock fast bridge deployer --- services/rfq/testutil/deployers.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/rfq/testutil/deployers.go b/services/rfq/testutil/deployers.go index 492408c41f..bdeb0917bb 100644 --- a/services/rfq/testutil/deployers.go +++ b/services/rfq/testutil/deployers.go @@ -128,7 +128,7 @@ type MockFastBridgeDeployer struct { // NewMockFastBridgeDeployer deploys a mock fast bridge contract. func NewMockFastBridgeDeployer(registry deployer.GetOnlyContractRegistry, backend backends.SimulatedTestBackend) deployer.ContractDeployer { return MockFastBridgeDeployer{ - deployer.NewSimpleDeployer(registry, backend, RecipientMockType), + deployer.NewSimpleDeployer(registry, backend, FastBridgeMockType), } } From f57312b631384399db61360aea95fc635d415b59 Mon Sep 17 00:00:00 2001 From: Daniel Wasserman Date: Fri, 11 Oct 2024 14:45:52 -0500 Subject: [PATCH 36/85] Revert "Cleanup: remove unnecessary test" This reverts commit 117ce5937ebfbc2aca754dd2a6bdc08e34827b65. --- .../rfq/contracts/fastbridge/status_test.go | 48 +++++++++++++++++++ 1 file changed, 48 insertions(+) create mode 100644 services/rfq/contracts/fastbridge/status_test.go diff --git a/services/rfq/contracts/fastbridge/status_test.go b/services/rfq/contracts/fastbridge/status_test.go new file mode 100644 index 0000000000..3028e6d245 --- /dev/null +++ b/services/rfq/contracts/fastbridge/status_test.go @@ -0,0 +1,48 @@ +package fastbridge_test + +import ( + "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/stretchr/testify/suite" + "github.com/synapsecns/sanguine/core/testsuite" + "github.com/synapsecns/sanguine/ethergo/backends" + "github.com/synapsecns/sanguine/ethergo/backends/simulated" + "github.com/synapsecns/sanguine/services/rfq/contracts/fastbridge" + "github.com/synapsecns/sanguine/services/rfq/testutil" + "math/big" + "testing" +) + +// FastBridgeSuite tests the basic test suite. +type FastBridgeSuite struct { + *testsuite.TestSuite + backend backends.SimulatedTestBackend + manager *testutil.DeployManager +} + +// NewFastBridgeSuite creates a new FastBridge suite. +func NewFastBridgeSuite(tb testing.TB) *FastBridgeSuite { + tb.Helper() + return &FastBridgeSuite{ + TestSuite: testsuite.NewTestSuite(tb), + } +} + +func TestFastBridgeSuite(t *testing.T) { + suite.Run(t, NewFastBridgeSuite(t)) +} + +func (s *FastBridgeSuite) SetupTest() { + s.TestSuite.SetupTest() + s.backend = simulated.NewSimulatedBackendWithChainID(s.GetTestContext(), s.T(), big.NewInt(1)) + s.manager = testutil.NewDeployManager(s.T()) +} + +// TestStatusEnum makes sure. +func (s *FastBridgeSuite) TestStatusEnum() { + _, fb := s.manager.GetMockFastBridge(s.GetTestContext(), s.backend) + for _, status := range fastbridge.GetAllBridgeStatuses() { + solstatus, err := fb.GetEnumKeyByValue(&bind.CallOpts{Context: s.GetTestContext()}, status.Int()) + s.Require().NoError(err, "error getting enum key by value") + s.Require().Equal(solstatus, status.String(), "status %s does not match. BridgeStatus enums out of sync.", status) + } +} From 4b8dc684092d14249ab018f17c1b550b51ce6f80 Mon Sep 17 00:00:00 2001 From: Daniel Wasserman Date: Fri, 11 Oct 2024 15:17:11 -0500 Subject: [PATCH 37/85] Fix: flatten all files --- packages/contracts-rfq/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/contracts-rfq/package.json b/packages/contracts-rfq/package.json index 83164f1f24..7913885be3 100644 --- a/packages/contracts-rfq/package.json +++ b/packages/contracts-rfq/package.json @@ -23,7 +23,7 @@ "lint": "forge fmt && npm run solhint", "lint:check": "forge fmt --check && npm run solhint:check", "ci:lint": "npm run lint:check", - "build:go": "./flatten.sh contracts/*.sol test/*.sol", + "build:go": "./flatten.sh contracts/**/*.sol test/**/*.sol", "solhint": "solhint '{contracts,script,test}/**/*.sol' --fix --noPrompt --max-warnings 3", "solhint:check": "solhint '{contracts,script,test}/**/*.sol' --max-warnings 3" } From b24d31d1969db18dcf4f7999615e3887078d10bc Mon Sep 17 00:00:00 2001 From: Daniel Wasserman Date: Fri, 11 Oct 2024 15:50:53 -0500 Subject: [PATCH 38/85] Revert "Fix: flatten all files" This reverts commit 4b8dc684092d14249ab018f17c1b550b51ce6f80. --- packages/contracts-rfq/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/contracts-rfq/package.json b/packages/contracts-rfq/package.json index 7913885be3..83164f1f24 100644 --- a/packages/contracts-rfq/package.json +++ b/packages/contracts-rfq/package.json @@ -23,7 +23,7 @@ "lint": "forge fmt && npm run solhint", "lint:check": "forge fmt --check && npm run solhint:check", "ci:lint": "npm run lint:check", - "build:go": "./flatten.sh contracts/**/*.sol test/**/*.sol", + "build:go": "./flatten.sh contracts/*.sol test/*.sol", "solhint": "solhint '{contracts,script,test}/**/*.sol' --fix --noPrompt --max-warnings 3", "solhint:check": "solhint '{contracts,script,test}/**/*.sol' --max-warnings 3" } From 91a6b8f383264e21d11df518c2104d8ed80f32e9 Mon Sep 17 00:00:00 2001 From: Daniel Wasserman Date: Fri, 11 Oct 2024 15:51:41 -0500 Subject: [PATCH 39/85] Feat: flatten mocks --- packages/contracts-rfq/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/contracts-rfq/package.json b/packages/contracts-rfq/package.json index 83164f1f24..cb1ded589c 100644 --- a/packages/contracts-rfq/package.json +++ b/packages/contracts-rfq/package.json @@ -23,7 +23,7 @@ "lint": "forge fmt && npm run solhint", "lint:check": "forge fmt --check && npm run solhint:check", "ci:lint": "npm run lint:check", - "build:go": "./flatten.sh contracts/*.sol test/*.sol", + "build:go": "./flatten.sh contracts/*.sol test/*.sol test/mocks/*.sol", "solhint": "solhint '{contracts,script,test}/**/*.sol' --fix --noPrompt --max-warnings 3", "solhint:check": "solhint '{contracts,script,test}/**/*.sol' --max-warnings 3" } From b6a4609f1aba4675f8144c548176a651ec4448a1 Mon Sep 17 00:00:00 2001 From: Daniel Wasserman Date: Fri, 11 Oct 2024 16:53:51 -0500 Subject: [PATCH 40/85] Fix: tests --- services/rfq/relayer/relapi/server_test.go | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/services/rfq/relayer/relapi/server_test.go b/services/rfq/relayer/relapi/server_test.go index f9dd83717c..e269f4b32c 100644 --- a/services/rfq/relayer/relapi/server_test.go +++ b/services/rfq/relayer/relapi/server_test.go @@ -203,12 +203,16 @@ func (c *RelayerServerSuite) getTestQuoteRequest(status reldb.QuoteRequestStatus TransactionID: txID, Status: status, Transaction: fastbridgev2.IFastBridgeV2BridgeTransactionV2{ - OriginChainId: c.originChainID, - DestChainId: c.destChainID, - OriginAmount: big.NewInt(100), - DestAmount: big.NewInt(100), - Deadline: big.NewInt(time.Now().Unix()), - Nonce: big.NewInt(0), + OriginChainId: c.originChainID, + DestChainId: c.destChainID, + OriginAmount: big.NewInt(100), + DestAmount: big.NewInt(100), + Deadline: big.NewInt(time.Now().Unix()), + Nonce: big.NewInt(0), + ExclusivityEndTime: big.NewInt(0), + OriginFeeAmount: big.NewInt(0), + CallValue: big.NewInt(0), + CallParams: []byte{}, }, OriginTxHash: common.HexToHash("0x0000000"), DestTxHash: common.HexToHash("0x0000001"), From 05ab3dd8c62f3a724e14ddf2384f7cf76f1dc7d6 Mon Sep 17 00:00:00 2001 From: Daniel Wasserman Date: Fri, 11 Oct 2024 16:58:28 -0500 Subject: [PATCH 41/85] Fix: test --- services/rfq/relayer/reldb/base/model_test.go | 24 +++++++++++-------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/services/rfq/relayer/reldb/base/model_test.go b/services/rfq/relayer/reldb/base/model_test.go index 99b98baae1..505a555633 100644 --- a/services/rfq/relayer/reldb/base/model_test.go +++ b/services/rfq/relayer/reldb/base/model_test.go @@ -24,16 +24,20 @@ func TestRoundtripBetweenFromQuoteRequestAndToQuoteRequest(t *testing.T) { RawRequest: []byte(gofakeit.Paragraph(1, 2, 3, " ")), Sender: common.Address{}, Transaction: fastbridgev2.IFastBridgeV2BridgeTransactionV2{ - OriginChainId: 1, - DestChainId: 2, - OriginSender: common.Address{}, - DestRecipient: common.Address{}, - OriginToken: common.Address{}, - DestToken: common.Address{}, - OriginAmount: big.NewInt(1000), - DestAmount: big.NewInt(2000), - Deadline: big.NewInt(time.Now().Unix()), - Nonce: big.NewInt(1), + OriginChainId: 1, + DestChainId: 2, + OriginSender: common.Address{}, + DestRecipient: common.Address{}, + OriginToken: common.Address{}, + DestToken: common.Address{}, + OriginAmount: big.NewInt(1000), + DestAmount: big.NewInt(2000), + Deadline: big.NewInt(time.Now().Unix()), + Nonce: big.NewInt(1), + ExclusivityEndTime: big.NewInt(0), + OriginFeeAmount: big.NewInt(0), + CallValue: big.NewInt(0), + CallParams: []byte{}, }, Status: reldb.QuoteRequestStatus(1), } From 94ee810455b277ed48dfaf050c23dc4144320355 Mon Sep 17 00:00:00 2001 From: Daniel Wasserman Date: Tue, 15 Oct 2024 13:50:18 -0500 Subject: [PATCH 42/85] Fix: use nativeTokenDecimals instead of origin decimals for call value --- services/rfq/relayer/reldb/base/model.go | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/services/rfq/relayer/reldb/base/model.go b/services/rfq/relayer/reldb/base/model.go index 465bac64e2..52e95bab08 100644 --- a/services/rfq/relayer/reldb/base/model.go +++ b/services/rfq/relayer/reldb/base/model.go @@ -120,6 +120,8 @@ type Rebalance struct { TokenName string } +const nativeTokenDecimals = 18 + // FromQuoteRequest converts a quote request to an object that can be stored in the db. // TODO: add validation for deadline > uint64 // TODO: roundtripper test. @@ -144,7 +146,7 @@ func FromQuoteRequest(request reldb.QuoteRequest) RequestForQuote { OriginAmountOriginal: request.Transaction.OriginAmount.String(), OriginAmount: decimal.NewFromBigInt(request.Transaction.OriginAmount, int32(request.OriginTokenDecimals)), DestAmountOriginal: request.Transaction.DestAmount.String(), - DestAmount: decimal.NewFromBigInt(request.Transaction.DestAmount, int32(request.DestTokenDecimals)), + DestAmount: decimal.NewFromBigInt(request.Transaction.DestAmount, int32(nativeTokenDecimals)), OriginFeeAmount: decimal.NewFromBigInt(request.Transaction.OriginFeeAmount, int32(request.OriginTokenDecimals)), CallValue: decimal.NewFromBigInt(request.Transaction.CallValue, int32(request.OriginTokenDecimals)), CallParams: request.Transaction.CallParams, @@ -237,7 +239,7 @@ func (r RequestForQuote) ToQuoteRequest() (*reldb.QuoteRequest, error) { OriginAmount: new(big.Int).Div(r.OriginAmount.BigInt(), big.NewInt(int64(math.Pow10(int(r.OriginTokenDecimals))))), DestAmount: new(big.Int).Div(r.DestAmount.BigInt(), big.NewInt(int64(math.Pow10(int(r.DestTokenDecimals))))), OriginFeeAmount: new(big.Int).Div(r.OriginFeeAmount.BigInt(), big.NewInt(int64(math.Pow10(int(r.OriginTokenDecimals))))), - CallValue: new(big.Int).Div(r.CallValue.BigInt(), big.NewInt(int64(math.Pow10(int(r.OriginTokenDecimals))))), + CallValue: new(big.Int).Div(r.CallValue.BigInt(), big.NewInt(int64(math.Pow10(int(nativeTokenDecimals))))), ExclusivityRelayer: common.HexToAddress(r.ExclusivityRelayer), ExclusivityEndTime: big.NewInt(r.ExclusivityEndTime.Unix()), CallParams: r.CallParams, From 87593180544add01550360ba08521d4a37bbfdd4 Mon Sep 17 00:00:00 2001 From: Daniel Wasserman Date: Tue, 15 Oct 2024 13:53:46 -0500 Subject: [PATCH 43/85] Update abigen --- .../contracts/fastbridgev2/fastbridgev2.abigen.go | 12 ++++++------ .../fastbridgev2/fastbridgev2.contractinfo.json | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/services/rfq/contracts/fastbridgev2/fastbridgev2.abigen.go b/services/rfq/contracts/fastbridgev2/fastbridgev2.abigen.go index 3975f8a673..a6518eff27 100644 --- a/services/rfq/contracts/fastbridgev2/fastbridgev2.abigen.go +++ b/services/rfq/contracts/fastbridgev2/fastbridgev2.abigen.go @@ -1827,7 +1827,7 @@ func (_AccessControlEnumerable *AccessControlEnumerableFilterer) ParseRoleRevoke // AddressMetaData contains all meta data concerning the Address contract. var AddressMetaData = &bind.MetaData{ ABI: "[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"}],\"name\":\"AddressEmptyCode\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"AddressInsufficientBalance\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"FailedInnerCall\",\"type\":\"error\"}]", - Bin: "0x60566037600b82828239805160001a607314602a57634e487b7160e01b600052600060045260246000fd5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600080fdfea26469706673582212209373c953367c76b94c1908124544fbcf053f6653eb651760b4d42f0f487710d864736f6c63430008180033", + Bin: "0x60566037600b82828239805160001a607314602a57634e487b7160e01b600052600060045260246000fd5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600080fdfea2646970667358221220ac16750f49f1b9ced08b049feacc7b593708109660ad4859d5e0cc87a7718b8d64736f6c63430008180033", } // AddressABI is the input ABI used to generate the binding from. @@ -2023,7 +2023,7 @@ var AdminMetaData = &bind.MetaData{ "01ffc9a7": "supportsInterface(bytes4)", "06f333f2": "sweepProtocolFees(address,address)", }, - Bin: "0x60806040523480156200001157600080fd5b50604051620014123803806200141283398101604081905262000034916200018e565b6200004160008262000049565b5050620001b9565b60008062000058848462000086565b905080156200007d5760008481526001602052604090206200007b908462000134565b505b90505b92915050565b6000828152602081815260408083206001600160a01b038516845290915281205460ff166200012b576000838152602081815260408083206001600160a01b03861684529091529020805460ff19166001179055620000e23390565b6001600160a01b0316826001600160a01b0316847f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a450600162000080565b50600062000080565b60006200007d836001600160a01b03841660008181526001830160205260408120546200012b5750815460018181018455600084815260208082209093018490558454848252828601909352604090209190915562000080565b600060208284031215620001a157600080fd5b81516001600160a01b03811681146200007d57600080fd5b61124980620001c96000396000f3fe608060405234801561001057600080fd5b50600436106101775760003560e01c806391d14854116100d8578063bf333f2c1161008c578063d547741f11610066578063d547741f14610385578063dcf844a714610398578063e00a83e0146103b857600080fd5b8063bf333f2c14610341578063ca15c8731461034b578063ccc574901461035e57600080fd5b8063a217fddf116100bd578063a217fddf14610313578063b13aa2d61461031b578063b250fe6b1461032e57600080fd5b806391d14854146102a8578063926d7d7f146102ec57600080fd5b80632f2ff15d1161012f57806358f858801161011457806358f85880146102405780635960ccf2146102495780639010d07c1461027057600080fd5b80632f2ff15d1461021a57806336568abe1461022d57600080fd5b806306f333f21161016057806306f333f2146101d95780630f5f6ed7146101ee578063248a9ca3146101f757600080fd5b806301ffc9a71461017c57806303ed0ee5146101a4575b600080fd5b61018f61018a366004611013565b6103c1565b60405190151581526020015b60405180910390f35b6101cb7f043c983c49d46f0e102151eaf8085d4a2e6571d5df2d47b013f39bddfd4a639d81565b60405190815260200161019b565b6101ec6101e736600461107e565b61041d565b005b6101cb61271081565b6101cb6102053660046110b1565b60009081526020819052604090206001015490565b6101ec6102283660046110ca565b61050b565b6101ec61023b3660046110ca565b610536565b6101cb60025481565b6101cb7fdb9556138406326f00296e13ea2ad7db24ba82381212d816b1a40c23b466b32781565b61028361027e3660046110ed565b61058f565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200161019b565b61018f6102b63660046110ca565b60009182526020828152604080842073ffffffffffffffffffffffffffffffffffffffff93909316845291905290205460ff1690565b6101cb7fe2b7fb3b832174769106daebcfd6d1970523240dda11281102db9363b83b0dc481565b6101cb600081565b6101ec6103293660046110b1565b6105ae565b6101ec61033c3660046110b1565b610690565b6101cb620f424081565b6101cb6103593660046110b1565b6106f8565b6101cb7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f5581565b6101ec6103933660046110ca565b61070f565b6101cb6103a636600461110f565b60036020526000908152604090205481565b6101cb60045481565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f5a05180f000000000000000000000000000000000000000000000000000000001480610417575061041782610734565b92915050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f55610447816107cb565b73ffffffffffffffffffffffffffffffffffffffff83166000908152600360205260408120549081900361047b5750505050565b73ffffffffffffffffffffffffffffffffffffffff84166000818152600360205260408120556104ac9084836107d8565b6040805173ffffffffffffffffffffffffffffffffffffffff8087168252851660208201529081018290527f244e51bc38c1452fa8aaf487bcb4bca36c2baa3a5fbdb776b1eabd8dc6d277cd9060600160405180910390a1505b505050565b600082815260208190526040902060010154610526816107cb565b610530838361092f565b50505050565b73ffffffffffffffffffffffffffffffffffffffff81163314610585576040517f6697b23200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6105068282610964565b60008281526001602052604081206105a79083610991565b9392505050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f556105d8816107cb565b612710821115610649576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f6e657746656552617465203e206d61780000000000000000000000000000000060448201526064015b60405180910390fd5b600280549083905560408051828152602081018590527f14914da2bf76024616fbe1859783fcd4dbddcb179b1f3a854949fbf920dcb95791015b60405180910390a1505050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f556106ba816107cb565b600480549083905560408051828152602081018590527f5cf09b12f3f56b4c564d51b25b40360af6d795198adb61ae0806a36c294323fa9101610683565b60008181526001602052604081206104179061099d565b60008281526020819052604090206001015461072a816107cb565b6105308383610964565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f7965db0b00000000000000000000000000000000000000000000000000000000148061041757507f01ffc9a7000000000000000000000000000000000000000000000000000000007fffffffff00000000000000000000000000000000000000000000000000000000831614610417565b6107d581336109a7565b50565b3073ffffffffffffffffffffffffffffffffffffffff8316036107fa57505050565b8060000361080757505050565b7fffffffffffffffffffffffff111111111111111111111111111111111111111273ffffffffffffffffffffffffffffffffffffffff84160161090e5760008273ffffffffffffffffffffffffffffffffffffffff168260405160006040518083038185875af1925050503d806000811461089e576040519150601f19603f3d011682016040523d82523d6000602084013e6108a3565b606091505b5050905080610530576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f455448207472616e73666572206661696c6564000000000000000000000000006044820152606401610640565b61050673ffffffffffffffffffffffffffffffffffffffff84168383610a31565b60008061093c8484610abe565b905080156105a757600084815260016020526040902061095c9084610bba565b509392505050565b6000806109718484610bdc565b905080156105a757600084815260016020526040902061095c9084610c97565b60006105a78383610cb9565b6000610417825490565b60008281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915290205460ff16610a2d576040517fe2517d3f00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8216600482015260248101839052604401610640565b5050565b6040805173ffffffffffffffffffffffffffffffffffffffff8416602482015260448082018490528251808303909101815260649091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fa9059cbb00000000000000000000000000000000000000000000000000000000179052610506908490610ce3565b60008281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915281205460ff16610bb25760008381526020818152604080832073ffffffffffffffffffffffffffffffffffffffff86168452909152902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055610b503390565b73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16847f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a4506001610417565b506000610417565b60006105a78373ffffffffffffffffffffffffffffffffffffffff8416610d79565b60008281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915281205460ff1615610bb25760008381526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8616808552925280832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016905551339286917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a4506001610417565b60006105a78373ffffffffffffffffffffffffffffffffffffffff8416610dc0565b6000826000018281548110610cd057610cd061112a565b9060005260206000200154905092915050565b6000610d0573ffffffffffffffffffffffffffffffffffffffff841683610eb3565b90508051600014158015610d2a575080806020019051810190610d289190611159565b155b15610506576040517f5274afe700000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff84166004820152602401610640565b6000818152600183016020526040812054610bb257508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155610417565b60008181526001830160205260408120548015610ea9576000610de460018361117b565b8554909150600090610df89060019061117b565b9050808214610e5d576000866000018281548110610e1857610e1861112a565b9060005260206000200154905080876000018481548110610e3b57610e3b61112a565b6000918252602080832090910192909255918252600188019052604090208390555b8554869080610e6e57610e6e6111b5565b600190038181906000526020600020016000905590558560010160008681526020019081526020016000206000905560019350505050610417565b6000915050610417565b60606105a783836000846000808573ffffffffffffffffffffffffffffffffffffffff168486604051610ee691906111e4565b60006040518083038185875af1925050503d8060008114610f23576040519150601f19603f3d011682016040523d82523d6000602084013e610f28565b606091505b5091509150610f38868383610f42565b9695505050505050565b606082610f5757610f5282610fd1565b6105a7565b8151158015610f7b575073ffffffffffffffffffffffffffffffffffffffff84163b155b15610fca576040517f9996b31500000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff85166004820152602401610640565b50806105a7565b805115610fe15780518082602001fd5b6040517f1425ea4200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006020828403121561102557600080fd5b81357fffffffff00000000000000000000000000000000000000000000000000000000811681146105a757600080fd5b803573ffffffffffffffffffffffffffffffffffffffff8116811461107957600080fd5b919050565b6000806040838503121561109157600080fd5b61109a83611055565b91506110a860208401611055565b90509250929050565b6000602082840312156110c357600080fd5b5035919050565b600080604083850312156110dd57600080fd5b823591506110a860208401611055565b6000806040838503121561110057600080fd5b50508035926020909101359150565b60006020828403121561112157600080fd5b6105a782611055565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60006020828403121561116b57600080fd5b815180151581146105a757600080fd5b81810381811115610417577f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fd5b6000825160005b8181101561120557602081860181015185830152016111eb565b50600092019182525091905056fea2646970667358221220e128d8a06a9c2200c4304cd29f76ba6d8295d2c98b16f4a06921d33d0cebefd764736f6c63430008180033", + Bin: "0x60806040523480156200001157600080fd5b50604051620014123803806200141283398101604081905262000034916200018e565b6200004160008262000049565b5050620001b9565b60008062000058848462000086565b905080156200007d5760008481526001602052604090206200007b908462000134565b505b90505b92915050565b6000828152602081815260408083206001600160a01b038516845290915281205460ff166200012b576000838152602081815260408083206001600160a01b03861684529091529020805460ff19166001179055620000e23390565b6001600160a01b0316826001600160a01b0316847f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a450600162000080565b50600062000080565b60006200007d836001600160a01b03841660008181526001830160205260408120546200012b5750815460018181018455600084815260208082209093018490558454848252828601909352604090209190915562000080565b600060208284031215620001a157600080fd5b81516001600160a01b03811681146200007d57600080fd5b61124980620001c96000396000f3fe608060405234801561001057600080fd5b50600436106101775760003560e01c806391d14854116100d8578063bf333f2c1161008c578063d547741f11610066578063d547741f14610385578063dcf844a714610398578063e00a83e0146103b857600080fd5b8063bf333f2c14610341578063ca15c8731461034b578063ccc574901461035e57600080fd5b8063a217fddf116100bd578063a217fddf14610313578063b13aa2d61461031b578063b250fe6b1461032e57600080fd5b806391d14854146102a8578063926d7d7f146102ec57600080fd5b80632f2ff15d1161012f57806358f858801161011457806358f85880146102405780635960ccf2146102495780639010d07c1461027057600080fd5b80632f2ff15d1461021a57806336568abe1461022d57600080fd5b806306f333f21161016057806306f333f2146101d95780630f5f6ed7146101ee578063248a9ca3146101f757600080fd5b806301ffc9a71461017c57806303ed0ee5146101a4575b600080fd5b61018f61018a366004611013565b6103c1565b60405190151581526020015b60405180910390f35b6101cb7f043c983c49d46f0e102151eaf8085d4a2e6571d5df2d47b013f39bddfd4a639d81565b60405190815260200161019b565b6101ec6101e736600461107e565b61041d565b005b6101cb61271081565b6101cb6102053660046110b1565b60009081526020819052604090206001015490565b6101ec6102283660046110ca565b61050b565b6101ec61023b3660046110ca565b610536565b6101cb60025481565b6101cb7fdb9556138406326f00296e13ea2ad7db24ba82381212d816b1a40c23b466b32781565b61028361027e3660046110ed565b61058f565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200161019b565b61018f6102b63660046110ca565b60009182526020828152604080842073ffffffffffffffffffffffffffffffffffffffff93909316845291905290205460ff1690565b6101cb7fe2b7fb3b832174769106daebcfd6d1970523240dda11281102db9363b83b0dc481565b6101cb600081565b6101ec6103293660046110b1565b6105ae565b6101ec61033c3660046110b1565b610690565b6101cb620f424081565b6101cb6103593660046110b1565b6106f8565b6101cb7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f5581565b6101ec6103933660046110ca565b61070f565b6101cb6103a636600461110f565b60036020526000908152604090205481565b6101cb60045481565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f5a05180f000000000000000000000000000000000000000000000000000000001480610417575061041782610734565b92915050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f55610447816107cb565b73ffffffffffffffffffffffffffffffffffffffff83166000908152600360205260408120549081900361047b5750505050565b73ffffffffffffffffffffffffffffffffffffffff84166000818152600360205260408120556104ac9084836107d8565b6040805173ffffffffffffffffffffffffffffffffffffffff8087168252851660208201529081018290527f244e51bc38c1452fa8aaf487bcb4bca36c2baa3a5fbdb776b1eabd8dc6d277cd9060600160405180910390a1505b505050565b600082815260208190526040902060010154610526816107cb565b610530838361092f565b50505050565b73ffffffffffffffffffffffffffffffffffffffff81163314610585576040517f6697b23200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6105068282610964565b60008281526001602052604081206105a79083610991565b9392505050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f556105d8816107cb565b612710821115610649576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f6e657746656552617465203e206d61780000000000000000000000000000000060448201526064015b60405180910390fd5b600280549083905560408051828152602081018590527f14914da2bf76024616fbe1859783fcd4dbddcb179b1f3a854949fbf920dcb95791015b60405180910390a1505050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f556106ba816107cb565b600480549083905560408051828152602081018590527f5cf09b12f3f56b4c564d51b25b40360af6d795198adb61ae0806a36c294323fa9101610683565b60008181526001602052604081206104179061099d565b60008281526020819052604090206001015461072a816107cb565b6105308383610964565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f7965db0b00000000000000000000000000000000000000000000000000000000148061041757507f01ffc9a7000000000000000000000000000000000000000000000000000000007fffffffff00000000000000000000000000000000000000000000000000000000831614610417565b6107d581336109a7565b50565b3073ffffffffffffffffffffffffffffffffffffffff8316036107fa57505050565b8060000361080757505050565b7fffffffffffffffffffffffff111111111111111111111111111111111111111273ffffffffffffffffffffffffffffffffffffffff84160161090e5760008273ffffffffffffffffffffffffffffffffffffffff168260405160006040518083038185875af1925050503d806000811461089e576040519150601f19603f3d011682016040523d82523d6000602084013e6108a3565b606091505b5050905080610530576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f455448207472616e73666572206661696c6564000000000000000000000000006044820152606401610640565b61050673ffffffffffffffffffffffffffffffffffffffff84168383610a31565b60008061093c8484610abe565b905080156105a757600084815260016020526040902061095c9084610bba565b509392505050565b6000806109718484610bdc565b905080156105a757600084815260016020526040902061095c9084610c97565b60006105a78383610cb9565b6000610417825490565b60008281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915290205460ff16610a2d576040517fe2517d3f00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8216600482015260248101839052604401610640565b5050565b6040805173ffffffffffffffffffffffffffffffffffffffff8416602482015260448082018490528251808303909101815260649091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fa9059cbb00000000000000000000000000000000000000000000000000000000179052610506908490610ce3565b60008281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915281205460ff16610bb25760008381526020818152604080832073ffffffffffffffffffffffffffffffffffffffff86168452909152902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055610b503390565b73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16847f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a4506001610417565b506000610417565b60006105a78373ffffffffffffffffffffffffffffffffffffffff8416610d79565b60008281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915281205460ff1615610bb25760008381526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8616808552925280832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016905551339286917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a4506001610417565b60006105a78373ffffffffffffffffffffffffffffffffffffffff8416610dc0565b6000826000018281548110610cd057610cd061112a565b9060005260206000200154905092915050565b6000610d0573ffffffffffffffffffffffffffffffffffffffff841683610eb3565b90508051600014158015610d2a575080806020019051810190610d289190611159565b155b15610506576040517f5274afe700000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff84166004820152602401610640565b6000818152600183016020526040812054610bb257508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155610417565b60008181526001830160205260408120548015610ea9576000610de460018361117b565b8554909150600090610df89060019061117b565b9050808214610e5d576000866000018281548110610e1857610e1861112a565b9060005260206000200154905080876000018481548110610e3b57610e3b61112a565b6000918252602080832090910192909255918252600188019052604090208390555b8554869080610e6e57610e6e6111b5565b600190038181906000526020600020016000905590558560010160008681526020019081526020016000206000905560019350505050610417565b6000915050610417565b60606105a783836000846000808573ffffffffffffffffffffffffffffffffffffffff168486604051610ee691906111e4565b60006040518083038185875af1925050503d8060008114610f23576040519150601f19603f3d011682016040523d82523d6000602084013e610f28565b606091505b5091509150610f38868383610f42565b9695505050505050565b606082610f5757610f5282610fd1565b6105a7565b8151158015610f7b575073ffffffffffffffffffffffffffffffffffffffff84163b155b15610fca576040517f9996b31500000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff85166004820152602401610640565b50806105a7565b805115610fe15780518082602001fd5b6040517f1425ea4200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006020828403121561102557600080fd5b81357fffffffff00000000000000000000000000000000000000000000000000000000811681146105a757600080fd5b803573ffffffffffffffffffffffffffffffffffffffff8116811461107957600080fd5b919050565b6000806040838503121561109157600080fd5b61109a83611055565b91506110a860208401611055565b90509250929050565b6000602082840312156110c357600080fd5b5035919050565b600080604083850312156110dd57600080fd5b823591506110a860208401611055565b6000806040838503121561110057600080fd5b50508035926020909101359150565b60006020828403121561112157600080fd5b6105a782611055565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60006020828403121561116b57600080fd5b815180151581146105a757600080fd5b81810381811115610417577f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fd5b6000825160005b8181101561120557602081860181015185830152016111eb565b50600092019182525091905056fea2646970667358221220b13443229221519c0fdb3ac2db22c34ccdfff8fd9f142c9a058dcefb00a5a9d864736f6c63430008180033", } // AdminABI is the input ABI used to generate the binding from. @@ -4023,7 +4023,7 @@ func (_ERC165 *ERC165CallerSession) SupportsInterface(interfaceId [4]byte) (bool // EnumerableSetMetaData contains all meta data concerning the EnumerableSet contract. var EnumerableSetMetaData = &bind.MetaData{ ABI: "[]", - Bin: "0x60566037600b82828239805160001a607314602a57634e487b7160e01b600052600060045260246000fd5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600080fdfea2646970667358221220c93e0a4d209c73a0e712af3f8fe75c461fc5f2c8421cf7a3112f43749245c31a64736f6c63430008180033", + Bin: "0x60566037600b82828239805160001a607314602a57634e487b7160e01b600052600060045260246000fd5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600080fdfea264697066735822122096938e347a6ad7c9db19e62e3fe085fcb6b4b02d667bfa2b5db09e30538dd3cd64736f6c63430008180033", } // EnumerableSetABI is the input ABI used to generate the binding from. @@ -4244,7 +4244,7 @@ var FastBridgeV2MetaData = &bind.MetaData{ "01ffc9a7": "supportsInterface(bytes4)", "06f333f2": "sweepProtocolFees(address,address)", }, - Bin: "0x60c060405260006080523480156200001657600080fd5b5060405162003e5a38038062003e5a833981016040819052620000399162000199565b806200004760008262000054565b50504360a05250620001c4565b60008062000063848462000091565b90508015620000885760008481526001602052604090206200008690846200013f565b505b90505b92915050565b6000828152602081815260408083206001600160a01b038516845290915281205460ff1662000136576000838152602081815260408083206001600160a01b03861684529091529020805460ff19166001179055620000ed3390565b6001600160a01b0316826001600160a01b0316847f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45060016200008b565b5060006200008b565b600062000088836001600160a01b038416600081815260018301602052604081205462000136575081546001818101845560008481526020808220909301849055845484825282860190935260409020919091556200008b565b600060208284031215620001ac57600080fd5b81516001600160a01b03811681146200008857600080fd5b60805160a051613c70620001ea6000396000610802015260006108a30152613c706000f3fe6080604052600436106102fd5760003560e01c806391ad50391161018f578063b13aa2d6116100e1578063ca15c8731161008a578063dcf844a711610064578063dcf844a714610a50578063df36bb1314610a7d578063e00a83e014610a9357600080fd5b8063ca15c873146109dc578063ccc57490146109fc578063d547741f14610a3057600080fd5b8063bfc7c607116100bb578063bfc7c6071461091c578063c63ff8dd1461092f578063c79371b11461094f57600080fd5b8063b13aa2d6146108c5578063b250fe6b146108e5578063bf333f2c1461090557600080fd5b8063a3ec191a11610143578063ac11fb1a1161011d578063ac11fb1a14610844578063add98c7014610871578063affed0e01461089157600080fd5b8063a3ec191a146107f0578063a5bbe22b14610607578063aa9641ab1461082457600080fd5b8063926d7d7f11610174578063926d7d7f146107945780639c9545f0146107c8578063a217fddf146107db57600080fd5b806391ad5039146106d057806391d148541461075057600080fd5b806341fcb6121161025357806363787e52116101fc578063886d36ff116101d6578063886d36ff146106655780638f0d6f17146106855780639010d07c1461069857600080fd5b806363787e521461058c578063820688d5146106075780638379a24f1461061d57600080fd5b80635960ccf21161022d5780635960ccf21461050b5780635aa6ccba1461053f5780635eb7d9461461056c57600080fd5b806341fcb612146104c257806345851694146104e257806358f85880146104f557600080fd5b806318e4357d116102b5578063295710ff1161028f578063295710ff146104555780632f2ff15d1461048257806336568abe146104a257600080fd5b806318e4357d146103ee578063190da5951461040e578063248a9ca31461042557600080fd5b8063051287bc116102e6578063051287bc1461037957806306f333f2146103b65780630f5f6ed7146103d857600080fd5b806301ffc9a71461030257806303ed0ee514610337575b600080fd5b34801561030e57600080fd5b5061032261031d366004612ee8565b610aa9565b60405190151581526020015b60405180910390f35b34801561034357600080fd5b5061036b7f043c983c49d46f0e102151eaf8085d4a2e6571d5df2d47b013f39bddfd4a639d81565b60405190815260200161032e565b34801561038557600080fd5b506103a9610394366004612f2a565b60009081526005602052604090205460ff1690565b60405161032e9190612fad565b3480156103c257600080fd5b506103d66103d1366004612fdb565b610b05565b005b3480156103e457600080fd5b5061036b61271081565b3480156103fa57600080fd5b506103d6610409366004613014565b610bcc565b34801561041a57600080fd5b5061036b62093a8081565b34801561043157600080fd5b5061036b610440366004612f2a565b60009081526020819052604090206001015490565b34801561046157600080fd5b5061036b61047036600461304d565b60076020526000908152604090205481565b34801561048e57600080fd5b506103d661049d36600461306a565b610d39565b3480156104ae57600080fd5b506103d66104bd36600461306a565b610d64565b3480156104ce57600080fd5b506103d66104dd366004613202565b610db0565b6103d66104f0366004613322565b611026565b34801561050157600080fd5b5061036b60025481565b34801561051757600080fd5b5061036b7fdb9556138406326f00296e13ea2ad7db24ba82381212d816b1a40c23b466b32781565b34801561054b57600080fd5b5061055f61055a36600461333f565b611083565b60405161032e91906133cc565b34801561057857600080fd5b506103d661058736600461333f565b611149565b34801561059857600080fd5b506105f76105a7366004612f2a565b60056020526000908152604090205460ff811690610100810464ffffffffff16906601000000000000810465ffffffffffff16906c0100000000000000000000000090046001600160a01b031684565b60405161032e94939291906134e1565b34801561061357600080fd5b5061036b61070881565b34801561062957600080fd5b50610322610638366004612f2a565b6000908152600660205260409020546c0100000000000000000000000090046001600160a01b0316151590565b34801561067157600080fd5b506103d6610680366004613522565b61133e565b6103d661069336600461333f565b611354565b3480156106a457600080fd5b506106b86106b3366004613567565b61135e565b6040516001600160a01b03909116815260200161032e565b3480156106dc57600080fd5b506107246106eb366004612f2a565b600090815260056020526040902054610100810464ffffffffff16916c010000000000000000000000009091046001600160a01b031690565b604080516bffffffffffffffffffffffff90931683526001600160a01b0390911660208301520161032e565b34801561075c57600080fd5b5061032261076b36600461306a565b6000918252602082815260408084206001600160a01b0393909316845291905290205460ff1690565b3480156107a057600080fd5b5061036b7fe2b7fb3b832174769106daebcfd6d1970523240dda11281102db9363b83b0dc481565b6103d66107d6366004613202565b61137d565b3480156107e757600080fd5b5061036b600081565b3480156107fc57600080fd5b5061036b7f000000000000000000000000000000000000000000000000000000000000000081565b34801561083057600080fd5b5061032261083f36600461306a565b61162e565b34801561085057600080fd5b5061086461085f36600461333f565b611719565b60405161032e9190613589565b34801561087d57600080fd5b506103d661088c366004612f2a565b6118d1565b34801561089d57600080fd5b5061036b7f000000000000000000000000000000000000000000000000000000000000000081565b3480156108d157600080fd5b506103d66108e0366004612f2a565b6119f3565b3480156108f157600080fd5b506103d6610900366004612f2a565b611ad5565b34801561091157600080fd5b5061036b620f424081565b6103d661092a36600461366f565b611b3d565b34801561093b57600080fd5b506103d661094a36600461333f565b611dbf565b34801561095b57600080fd5b506109ae61096a366004612f2a565b60066020526000908152604090205465ffffffffffff8082169166010000000000008104909116906c0100000000000000000000000090046001600160a01b031683565b6040805165ffffffffffff94851681529390921660208401526001600160a01b03169082015260600161032e565b3480156109e857600080fd5b5061036b6109f7366004612f2a565b611dca565b348015610a0857600080fd5b5061036b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f5581565b348015610a3c57600080fd5b506103d6610a4b36600461306a565b611de1565b348015610a5c57600080fd5b5061036b610a6b36600461304d565b60036020526000908152604090205481565b348015610a8957600080fd5b5061036b61ffff81565b348015610a9f57600080fd5b5061036b60045481565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f5a05180f000000000000000000000000000000000000000000000000000000001480610aff5750610aff82611e06565b92915050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f55610b2f81611e9d565b6001600160a01b03831660009081526003602052604081205490819003610b565750505050565b6001600160a01b038416600081815260036020526040812055610b7a908483611ea7565b604080516001600160a01b038087168252851660208201529081018290527f244e51bc38c1452fa8aaf487bcb4bca36c2baa3a5fbdb776b1eabd8dc6d277cd9060600160405180910390a1505b505050565b7fe2b7fb3b832174769106daebcfd6d1970523240dda11281102db9363b83b0dc4610bf681611e9d565b600160008581526005602052604090205460ff166004811115610c1b57610c1b612f43565b14610c52576040517f4145817200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600084815260056020908152604091829020805460027fffffffffffffffffffffffffffffffffffffffff0000000000000000000000009091166101004264ffffffffff16027fffffffffffffffffffffffffffffffffffffffff000000000000ffffffffffff161766010000000000004365ffffffffffff160217176bffffffffffffffffffffffff166c010000000000000000000000006001600160a01b0387169081029190911790915582518681529251909287927f4ac8af8a2cd87193d64dfc7a3b8d9923b714ec528b18725d080aa1299be0c5e492918290030190a350505050565b600082815260208190526040902060010154610d5481611e9d565b610d5e8383611fca565b50505050565b6001600160a01b0381163314610da6576040517f6697b23200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610bc78282611fff565b815160208301206000610dc284611083565b9050600260008381526005602052604090205460ff166004811115610de957610de9612f43565b14610e20576040517f4145817200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600160a01b038316610e5d576000828152600560205260409020546c0100000000000000000000000090046001600160a01b03169250610ebd565b6000828152600560205260409020546c0100000000000000000000000090046001600160a01b03163314610ebd576040517f4af43a9000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008281526005602052604090205461070890610100900464ffffffffff90811642031611610f18576040517f1992d0bd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600082815260056020526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016600317905561010081015115610f925761010081015160808201516001600160a01b031660009081526003602052604081208054909190610f8c90849061376c565b90915550505b608081015160c0820151610fb06001600160a01b0383168683611ea7565b6000848152600560209081526040918290205482516001600160a01b038681168252928101859052888316936c010000000000000000000000009092049092169187917f582211c35a2139ac3bbaac74663c6a1f56c6cbb658b41fe11fd45a82074ac678910160405180910390a4505050505050565b611080816040518060a0016040528060006001600160a01b03168152602001600081526020016040518060200160405280600081525081526020016000815260200160405180602001604052806000815250815250611b3d565b50565b611135604051806101e00160405280600063ffffffff168152602001600063ffffffff16815260200160006001600160a01b0316815260200160006001600160a01b0316815260200160006001600160a01b0316815260200160006001600160a01b0316815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160006001600160a01b0316815260200160008152602001606081525090565b81806020019051810190610aff91906137da565b80516020820120600061115b83611083565b9050600160008381526005602052604090205460ff16600481111561118257611182612f43565b146111b9576040517f4145817200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b3360009081527fd2043bf65931af3dbecf60d0db8f40e4160406d7beb00522f4200cf4944a1eb8602052604090205460ff161561123357806101400151421161122e576040517fe15ff9ea00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61127f565b62093a80816101400151611247919061376c565b421161127f576040517fe15ff9ea00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008281526005602052604080822080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166004179055820151608083015161010084015160c0850151929391926112d8919061376c565b90506112ee6001600160a01b0383168483611ea7565b604080516001600160a01b0384811682526020820184905285169187917fb4c55c0c9bc613519b920e88748090150b890a875d307f21bea7d4fb2e8bc958910160405180910390a3505050505050565b61135082805190602001208233610bcc565b5050565b611080813361137d565b6000828152600160205260408120611376908361202c565b9392505050565b81516020830120600061138f84611083565b905061139c818385612038565b604080516060808201835265ffffffffffff438116835242811660208085019182526001600160a01b03808a1686880190815260008a8152600690935296909120945185549251965182166c01000000000000000000000000026bffffffffffffffffffffffff9785166601000000000000027fffffffffffffffffffffffffffffffffffffffff000000000000000000000000909416919094161791909117949094161790915582015160a083015160e084015191929091907fffffffffffffffffffffffff1111111111111111111111111111111111111112908316016114fa57610120840151156114bc576040517f2598ad2e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8034146114f5576040517f81de0bf300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61154d565b8361012001513414611538576040517f81de0bf300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61154d6001600160a01b0383163385846121db565b6101c0840151511561156f5761156a838383876101c00151612257565b61157f565b341561157f5761157f83346123b6565b826001600160a01b0316866001600160a01b0316867ff8ae392d784b1ea5e8881bfa586d81abf07ef4f1e2fc75f7fe51c90f05199a5c876000015188608001518960a001518a60c001518b60e001518c610120015160405161161d9695949392919063ffffffff9690961686526001600160a01b0394851660208701529290931660408501526060840152608083019190915260a082015260c00190565b60405180910390a450505050505050565b6000600260008481526005602052604090205460ff16600481111561165557611655612f43565b1461168c576040517f4145817200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000838152600560205260409020546001600160a01b038381166c0100000000000000000000000090920416146116ef576040517f4af43a9000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b505060009081526005602052604090205461070861010090910464ffffffffff9081164203161190565b6040805161018081018252600080825260208201819052818301819052606082018190526080820181905260a0820181905260c0820181905260e0820181905261010082018190526101208201819052610140820181905261016082015290517f5aa6ccba0000000000000000000000000000000000000000000000000000000081523090635aa6ccba906117b290859060040161390f565b600060405180830381865afa9250505080156117f057506040513d6000823e601f3d908101601f191682016040526117ed91908101906137da565b60015b6118085781806020019051810190610aff919061392d565b604051806101800160405280826000015163ffffffff168152602001826020015163ffffffff16815260200182604001516001600160a01b0316815260200182606001516001600160a01b0316815260200182608001516001600160a01b031681526020018260a001516001600160a01b031681526020018260c0015181526020018260e001518152602001826101000151815260200182610120015160001415151581526020018261014001518152602001826101600151815250915050919050565b919050565b7f043c983c49d46f0e102151eaf8085d4a2e6571d5df2d47b013f39bddfd4a639d6118fb81611e9d565b600260008381526005602052604090205460ff16600481111561192057611920612f43565b14611957576040517f4145817200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008281526005602052604090205461070890610100900464ffffffffff90811642031611156119b3576040517f3e908aac00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000828152600560205260408082206001905551339184917f0695cf1d39b3055dcd0fe02d8b47eaf0d5a13e1996de925de59d0ef9b7f7fad49190a35050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f55611a1d81611e9d565b612710821115611a8e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f6e657746656552617465203e206d61780000000000000000000000000000000060448201526064015b60405180910390fd5b600280549083905560408051828152602081018590527f14914da2bf76024616fbe1859783fcd4dbddcb179b1f3a854949fbf920dcb95791015b60405180910390a1505050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f55611aff81611e9d565b600480549083905560408051828152602081018590527f5cf09b12f3f56b4c564d51b25b40360af6d795198adb61ae0806a36c294323fa9101611ac8565b6000816020015142611b4f91906139f9565b9050611b5c83838361247f565b6000611b7084606001518560a00151612704565b90506000806002541115611b9d57620f424060025483611b909190613a21565b611b9a9190613a38565b90505b611ba78183613a73565b91506000604051806101e001604052804663ffffffff168152602001876000015163ffffffff16815260200187602001516001600160a01b0316815260200187604001516001600160a01b0316815260200187606001516001600160a01b0316815260200187608001516001600160a01b031681526020018481526020018760c0015181526020018381526020018660600151815260200187610100015181526020016007600089602001516001600160a01b03166001600160a01b031681526020019081526020016000206000815480929190611c8490613a86565b91905055815260200186600001516001600160a01b031681526020018581526020018660800151815250604051602001611cbe91906133cc565b60408051808303601f1901815282825280516020808301919091206000818152600583529390932080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016600117905589015189516060808c015160808d015160c08e0151928d015195985095966001600160a01b039094169587957f120ea0364f36cdac7983bcfdd55270ca09d7f9b314a2ebc425a3b01ab1d6403a95611d72958b95909493928e9290151590613abe565b60405180910390a3807f3120e2bb59c86aca6890191a589a96af3662838efa374fbdcdf4c95bfe4a6c0e8760400151604051611dae919061390f565b60405180910390a250505050505050565b611080816000610db0565b6000818152600160205260408120610aff906128ad565b600082815260208190526040902060010154611dfc81611e9d565b610d5e8383611fff565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f7965db0b000000000000000000000000000000000000000000000000000000001480610aff57507f01ffc9a7000000000000000000000000000000000000000000000000000000007fffffffff00000000000000000000000000000000000000000000000000000000831614610aff565b61108081336128b7565b306001600160a01b03831603611ebc57505050565b80600003611ec957505050565b7fffffffffffffffffffffffff11111111111111111111111111111111111111126001600160a01b03841601611fb6576000826001600160a01b03168260405160006040518083038185875af1925050503d8060008114611f46576040519150601f19603f3d011682016040523d82523d6000602084013e611f4b565b606091505b5050905080610d5e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f455448207472616e73666572206661696c6564000000000000000000000000006044820152606401611a85565b610bc76001600160a01b0384168383612923565b600080611fd78484612954565b90508015611376576000848152600160205260409020611ff79084612a1c565b509392505050565b60008061200c8484612a31565b90508015611376576000848152600160205260409020611ff79084612ad2565b60006113768383612ae7565b6001600160a01b038116612078576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000828152600660205260409020546c0100000000000000000000000090046001600160a01b0316156120d7576040517fbef7bb7d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b4663ffffffff16836020015163ffffffff1614612120576040517f7029fdf900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b82610140015142111561215f576040517f559895a300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6101808301516001600160a01b0316158015906121935750806001600160a01b03168361018001516001600160a01b031614155b80156121a45750826101a001514211155b15610bc7576040517f14be123200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040516001600160a01b038481166024830152838116604483015260648201839052610d5e9186918216906323b872dd906084015b604051602081830303815290604052915060e01b6020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8381831617835250505050612b11565b600083838360405160240161226e93929190613b14565b60408051601f198184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f461e0c2100000000000000000000000000000000000000000000000000000000179052905060006122d5868334612b8d565b90508051600003612312576040517f1a95ad2600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b805160201461234d576040517ff3725cca00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f461e0c210000000000000000000000000000000000000000000000000000000061237782613b45565b146123ae576040517ff3725cca00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b505050505050565b804710156123f2576040517fcd786059000000000000000000000000000000000000000000000000000000008152306004820152602401611a85565b6000826001600160a01b03168260405160006040518083038185875af1925050503d806000811461243f576040519150601f19603f3d011682016040523d82523d6000602084013e612444565b606091505b5050905080610bc7576040517f1425ea4200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b46836000015163ffffffff16036124c2576040517f7029fdf900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60a083015115806124d5575060c0830151155b1561250c576040517fe38820c800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60208301516001600160a01b03161580612531575060408301516001600160a01b0316155b15612568576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60608301516001600160a01b0316158061258d575060808301516001600160a01b0316155b156125c4576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6125d06107084261376c565b836101000151101561260e576040517f04b7fcc800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61ffff826080015151111561264f576040517ffbe24d4900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b606082015115801590612682575060808301516001600160a01b031673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee145b156126b9576040517f2598ad2e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000811315806126cd575082610100015181135b15610bc7576040517f352807b900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60007fffffffffffffffffffffffff11111111111111111111111111111111111111126001600160a01b038416016127765734821461276f576040517f81de0bf300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5034610aff565b612788836001600160a01b0316612c43565b6040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201526001600160a01b038416906370a0823190602401602060405180830381865afa1580156127e5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128099190613b8a565b90506128206001600160a01b0384163330856121db565b6040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015281906001600160a01b038516906370a0823190602401602060405180830381865afa15801561287f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128a39190613b8a565b6113769190613a73565b6000610aff825490565b6000828152602081815260408083206001600160a01b038516845290915290205460ff16611350576040517fe2517d3f0000000000000000000000000000000000000000000000000000000081526001600160a01b038216600482015260248101839052604401611a85565b6040516001600160a01b03838116602483015260448201839052610bc791859182169063a9059cbb90606401612210565b6000828152602081815260408083206001600160a01b038516845290915281205460ff16612a14576000838152602081815260408083206001600160a01b0386168452909152902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790556129cc3390565b6001600160a01b0316826001600160a01b0316847f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a4506001610aff565b506000610aff565b6000611376836001600160a01b038416612ce9565b6000828152602081815260408083206001600160a01b038516845290915281205460ff1615612a14576000838152602081815260408083206001600160a01b038616808552925280832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016905551339286917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a4506001610aff565b6000611376836001600160a01b038416612d30565b6000826000018281548110612afe57612afe613ba3565b9060005260206000200154905092915050565b6000612b266001600160a01b03841683612e23565b90508051600014158015612b4b575080806020019051810190612b499190613bd2565b155b15610bc7576040517f5274afe70000000000000000000000000000000000000000000000000000000081526001600160a01b0384166004820152602401611a85565b606081471015612bcb576040517fcd786059000000000000000000000000000000000000000000000000000000008152306004820152602401611a85565b600080856001600160a01b03168486604051612be79190613bef565b60006040518083038185875af1925050503d8060008114612c24576040519150601f19603f3d011682016040523d82523d6000602084013e612c29565b606091505b5091509150612c39868383612e31565b9695505050505050565b7fffffffffffffffffffffffff11111111111111111111111111111111111111126001600160a01b03821601612ca5576040517f7f523fe800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b806001600160a01b03163b600003611080576040517f7f523fe800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000818152600183016020526040812054612a1457508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155610aff565b60008181526001830160205260408120548015612e19576000612d54600183613a73565b8554909150600090612d6890600190613a73565b9050808214612dcd576000866000018281548110612d8857612d88613ba3565b9060005260206000200154905080876000018481548110612dab57612dab613ba3565b6000918252602080832090910192909255918252600188019052604090208390555b8554869080612dde57612dde613c0b565b600190038181906000526020600020016000905590558560010160008681526020019081526020016000206000905560019350505050610aff565b6000915050610aff565b606061137683836000612b8d565b606082612e4657612e4182612ea6565b611376565b8151158015612e5d57506001600160a01b0384163b155b15612e9f576040517f9996b3150000000000000000000000000000000000000000000000000000000081526001600160a01b0385166004820152602401611a85565b5080611376565b805115612eb65780518082602001fd5b6040517f1425ea4200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600060208284031215612efa57600080fd5b81357fffffffff000000000000000000000000000000000000000000000000000000008116811461137657600080fd5b600060208284031215612f3c57600080fd5b5035919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b60058110612fa9577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b9052565b60208101610aff8284612f72565b6001600160a01b038116811461108057600080fd5b80356118cc81612fbb565b60008060408385031215612fee57600080fd5b8235612ff981612fbb565b9150602083013561300981612fbb565b809150509250929050565b60008060006060848603121561302957600080fd5b8335925060208401359150604084013561304281612fbb565b809150509250925092565b60006020828403121561305f57600080fd5b813561137681612fbb565b6000806040838503121561307d57600080fd5b82359150602083013561300981612fbb565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051610120810167ffffffffffffffff811182821017156130e2576130e261308f565b60405290565b60405160a0810167ffffffffffffffff811182821017156130e2576130e261308f565b6040516101e0810167ffffffffffffffff811182821017156130e2576130e261308f565b604051610180810167ffffffffffffffff811182821017156130e2576130e261308f565b604051601f8201601f1916810167ffffffffffffffff8111828210171561317c5761317c61308f565b604052919050565b600067ffffffffffffffff82111561319e5761319e61308f565b50601f01601f191660200190565b600082601f8301126131bd57600080fd5b81356131d06131cb82613184565b613153565b8181528460208386010111156131e557600080fd5b816020850160208301376000918101602001919091529392505050565b6000806040838503121561321557600080fd5b823567ffffffffffffffff81111561322c57600080fd5b613238858286016131ac565b925050602083013561300981612fbb565b63ffffffff8116811461108057600080fd5b80356118cc81613249565b801515811461108057600080fd5b80356118cc81613266565b6000610120828403121561329257600080fd5b61329a6130be565b90506132a58261325b565b81526132b360208301612fd0565b60208201526132c460408301612fd0565b60408201526132d560608301612fd0565b60608201526132e660808301612fd0565b608082015260a082013560a082015260c082013560c082015261330b60e08301613274565b60e082015261010080830135818301525092915050565b6000610120828403121561333557600080fd5b611376838361327f565b60006020828403121561335157600080fd5b813567ffffffffffffffff81111561336857600080fd5b613374848285016131ac565b949350505050565b60005b8381101561339757818101518382015260200161337f565b50506000910152565b600081518084526133b881602086016020860161337c565b601f01601f19169290920160200192915050565b602081526133e360208201835163ffffffff169052565b600060208301516133fc604084018263ffffffff169052565b5060408301516001600160a01b03811660608401525060608301516001600160a01b03811660808401525060808301516001600160a01b03811660a08401525060a08301516001600160a01b03811660c08401525060c083015160e08381019190915283015161010080840191909152830151610120808401919091528301516101408084019190915283015161016080840191909152830151610180808401919091528301516101a06134ba818501836001600160a01b03169052565b8401516101c0848101919091528401516101e08085015290506133746102008401826133a0565b608081016134ef8287612f72565b64ffffffffff8516602083015265ffffffffffff841660408301526001600160a01b038316606083015295945050505050565b6000806040838503121561353557600080fd5b823567ffffffffffffffff81111561354c57600080fd5b613558858286016131ac565b95602094909401359450505050565b6000806040838503121561357a57600080fd5b50508035926020909101359150565b815163ffffffff168152610180810160208301516135af602084018263ffffffff169052565b5060408301516135ca60408401826001600160a01b03169052565b5060608301516135e560608401826001600160a01b03169052565b50608083015161360060808401826001600160a01b03169052565b5060a083015161361b60a08401826001600160a01b03169052565b5060c083015160c083015260e083015160e0830152610100808401518184015250610120808401516136508285018215159052565b5050610140838101519083015261016092830151929091019190915290565b600080610140838503121561368357600080fd5b61368d848461327f565b915061012083013567ffffffffffffffff808211156136ab57600080fd5b9084019060a082870312156136bf57600080fd5b6136c76130e8565b82356136d281612fbb565b8152602083810135908201526040830135828111156136f057600080fd5b6136fc888286016131ac565b6040830152506060830135606082015260808301358281111561371e57600080fd5b61372a888286016131ac565b6080830152508093505050509250929050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b80820180821115610aff57610aff61373d565b80516118cc81613249565b80516118cc81612fbb565b600082601f8301126137a657600080fd5b81516137b46131cb82613184565b8181528460208386010111156137c957600080fd5b61337482602083016020870161337c565b6000602082840312156137ec57600080fd5b815167ffffffffffffffff8082111561380457600080fd5b908301906101e0828603121561381957600080fd5b61382161310b565b61382a8361377f565b81526138386020840161377f565b60208201526138496040840161378a565b604082015261385a6060840161378a565b606082015261386b6080840161378a565b608082015261387c60a0840161378a565b60a082015260c0838101519082015260e0808401519082015261010080840151908201526101208084015190820152610140808401519082015261016080840151908201526101806138cf81850161378a565b908201526101a083810151908201526101c080840151838111156138f257600080fd5b6138fe88828701613795565b918301919091525095945050505050565b60208152600061137660208301846133a0565b80516118cc81613266565b6000610180828403121561394057600080fd5b61394861312f565b6139518361377f565b815261395f6020840161377f565b60208201526139706040840161378a565b60408201526139816060840161378a565b60608201526139926080840161378a565b60808201526139a360a0840161378a565b60a082015260c083015160c082015260e083015160e08201526101008084015181830152506101206139d6818501613922565b908201526101408381015190820152610160928301519281019290925250919050565b8082018281126000831280158216821582161715613a1957613a1961373d565b505092915050565b8082028115828204841417610aff57610aff61373d565b600082613a6e577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b81810381811115610aff57610aff61373d565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203613ab757613ab761373d565b5060010190565b60e081526000613ad160e083018a6133a0565b63ffffffff989098166020830152506001600160a01b039586166040820152939094166060840152608083019190915260a082015290151560c090910152919050565b6001600160a01b0384168152826020820152606060408201526000613b3c60608301846133a0565b95945050505050565b80516020808301519190811015613b84577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8160200360031b1b821691505b50919050565b600060208284031215613b9c57600080fd5b5051919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b600060208284031215613be457600080fd5b815161137681613266565b60008251613c0181846020870161337c565b9190910192915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fdfea2646970667358221220a3680a17873f4c46b682e496f075c28aef799dbfefc67679607c7ecbffed72b464736f6c63430008180033", + Bin: "0x60c060405260006080523480156200001657600080fd5b5060405162003e6138038062003e61833981016040819052620000399162000199565b806200004760008262000054565b50504360a05250620001c4565b60008062000063848462000091565b90508015620000885760008481526001602052604090206200008690846200013f565b505b90505b92915050565b6000828152602081815260408083206001600160a01b038516845290915281205460ff1662000136576000838152602081815260408083206001600160a01b03861684529091529020805460ff19166001179055620000ed3390565b6001600160a01b0316826001600160a01b0316847f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45060016200008b565b5060006200008b565b600062000088836001600160a01b038416600081815260018301602052604081205462000136575081546001818101845560008481526020808220909301849055845484825282860190935260409020919091556200008b565b600060208284031215620001ac57600080fd5b81516001600160a01b03811681146200008857600080fd5b60805160a051613c77620001ea6000396000610802015260006108a30152613c776000f3fe6080604052600436106102fd5760003560e01c806391ad50391161018f578063b13aa2d6116100e1578063ca15c8731161008a578063dcf844a711610064578063dcf844a714610a50578063df36bb1314610a7d578063e00a83e014610a9357600080fd5b8063ca15c873146109dc578063ccc57490146109fc578063d547741f14610a3057600080fd5b8063bfc7c607116100bb578063bfc7c6071461091c578063c63ff8dd1461092f578063c79371b11461094f57600080fd5b8063b13aa2d6146108c5578063b250fe6b146108e5578063bf333f2c1461090557600080fd5b8063a3ec191a11610143578063ac11fb1a1161011d578063ac11fb1a14610844578063add98c7014610871578063affed0e01461089157600080fd5b8063a3ec191a146107f0578063a5bbe22b14610607578063aa9641ab1461082457600080fd5b8063926d7d7f11610174578063926d7d7f146107945780639c9545f0146107c8578063a217fddf146107db57600080fd5b806391ad5039146106d057806391d148541461075057600080fd5b806341fcb6121161025357806363787e52116101fc578063886d36ff116101d6578063886d36ff146106655780638f0d6f17146106855780639010d07c1461069857600080fd5b806363787e521461058c578063820688d5146106075780638379a24f1461061d57600080fd5b80635960ccf21161022d5780635960ccf21461050b5780635aa6ccba1461053f5780635eb7d9461461056c57600080fd5b806341fcb612146104c257806345851694146104e257806358f85880146104f557600080fd5b806318e4357d116102b5578063295710ff1161028f578063295710ff146104555780632f2ff15d1461048257806336568abe146104a257600080fd5b806318e4357d146103ee578063190da5951461040e578063248a9ca31461042557600080fd5b8063051287bc116102e6578063051287bc1461037957806306f333f2146103b65780630f5f6ed7146103d857600080fd5b806301ffc9a71461030257806303ed0ee514610337575b600080fd5b34801561030e57600080fd5b5061032261031d366004612eef565b610aa9565b60405190151581526020015b60405180910390f35b34801561034357600080fd5b5061036b7f043c983c49d46f0e102151eaf8085d4a2e6571d5df2d47b013f39bddfd4a639d81565b60405190815260200161032e565b34801561038557600080fd5b506103a9610394366004612f31565b60009081526005602052604090205460ff1690565b60405161032e9190612fb4565b3480156103c257600080fd5b506103d66103d1366004612fe2565b610b05565b005b3480156103e457600080fd5b5061036b61271081565b3480156103fa57600080fd5b506103d661040936600461301b565b610bcc565b34801561041a57600080fd5b5061036b62093a8081565b34801561043157600080fd5b5061036b610440366004612f31565b60009081526020819052604090206001015490565b34801561046157600080fd5b5061036b610470366004613054565b60076020526000908152604090205481565b34801561048e57600080fd5b506103d661049d366004613071565b610d39565b3480156104ae57600080fd5b506103d66104bd366004613071565b610d64565b3480156104ce57600080fd5b506103d66104dd366004613209565b610db0565b6103d66104f0366004613329565b611026565b34801561050157600080fd5b5061036b60025481565b34801561051757600080fd5b5061036b7fdb9556138406326f00296e13ea2ad7db24ba82381212d816b1a40c23b466b32781565b34801561054b57600080fd5b5061055f61055a366004613346565b611083565b60405161032e91906133d3565b34801561057857600080fd5b506103d6610587366004613346565b611149565b34801561059857600080fd5b506105f76105a7366004612f31565b60056020526000908152604090205460ff811690610100810464ffffffffff16906601000000000000810465ffffffffffff16906c0100000000000000000000000090046001600160a01b031684565b60405161032e94939291906134e8565b34801561061357600080fd5b5061036b61070881565b34801561062957600080fd5b50610322610638366004612f31565b6000908152600660205260409020546c0100000000000000000000000090046001600160a01b0316151590565b34801561067157600080fd5b506103d6610680366004613529565b61133e565b6103d6610693366004613346565b611354565b3480156106a457600080fd5b506106b86106b336600461356e565b61135e565b6040516001600160a01b03909116815260200161032e565b3480156106dc57600080fd5b506107246106eb366004612f31565b600090815260056020526040902054610100810464ffffffffff16916c010000000000000000000000009091046001600160a01b031690565b604080516bffffffffffffffffffffffff90931683526001600160a01b0390911660208301520161032e565b34801561075c57600080fd5b5061032261076b366004613071565b6000918252602082815260408084206001600160a01b0393909316845291905290205460ff1690565b3480156107a057600080fd5b5061036b7fe2b7fb3b832174769106daebcfd6d1970523240dda11281102db9363b83b0dc481565b6103d66107d6366004613209565b61137d565b3480156107e757600080fd5b5061036b600081565b3480156107fc57600080fd5b5061036b7f000000000000000000000000000000000000000000000000000000000000000081565b34801561083057600080fd5b5061032261083f366004613071565b611603565b34801561085057600080fd5b5061086461085f366004613346565b6116ee565b60405161032e9190613590565b34801561087d57600080fd5b506103d661088c366004612f31565b6118a6565b34801561089d57600080fd5b5061036b7f000000000000000000000000000000000000000000000000000000000000000081565b3480156108d157600080fd5b506103d66108e0366004612f31565b6119c8565b3480156108f157600080fd5b506103d6610900366004612f31565b611aaa565b34801561091157600080fd5b5061036b620f424081565b6103d661092a366004613676565b611b12565b34801561093b57600080fd5b506103d661094a366004613346565b611d94565b34801561095b57600080fd5b506109ae61096a366004612f31565b60066020526000908152604090205465ffffffffffff8082169166010000000000008104909116906c0100000000000000000000000090046001600160a01b031683565b6040805165ffffffffffff94851681529390921660208401526001600160a01b03169082015260600161032e565b3480156109e857600080fd5b5061036b6109f7366004612f31565b611d9f565b348015610a0857600080fd5b5061036b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f5581565b348015610a3c57600080fd5b506103d6610a4b366004613071565b611db6565b348015610a5c57600080fd5b5061036b610a6b366004613054565b60036020526000908152604090205481565b348015610a8957600080fd5b5061036b61ffff81565b348015610a9f57600080fd5b5061036b60045481565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f5a05180f000000000000000000000000000000000000000000000000000000001480610aff5750610aff82611ddb565b92915050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f55610b2f81611e72565b6001600160a01b03831660009081526003602052604081205490819003610b565750505050565b6001600160a01b038416600081815260036020526040812055610b7a908483611e7c565b604080516001600160a01b038087168252851660208201529081018290527f244e51bc38c1452fa8aaf487bcb4bca36c2baa3a5fbdb776b1eabd8dc6d277cd9060600160405180910390a1505b505050565b7fe2b7fb3b832174769106daebcfd6d1970523240dda11281102db9363b83b0dc4610bf681611e72565b600160008581526005602052604090205460ff166004811115610c1b57610c1b612f4a565b14610c52576040517f4145817200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600084815260056020908152604091829020805460027fffffffffffffffffffffffffffffffffffffffff0000000000000000000000009091166101004264ffffffffff16027fffffffffffffffffffffffffffffffffffffffff000000000000ffffffffffff161766010000000000004365ffffffffffff160217176bffffffffffffffffffffffff166c010000000000000000000000006001600160a01b0387169081029190911790915582518681529251909287927f4ac8af8a2cd87193d64dfc7a3b8d9923b714ec528b18725d080aa1299be0c5e492918290030190a350505050565b600082815260208190526040902060010154610d5481611e72565b610d5e8383611f9f565b50505050565b6001600160a01b0381163314610da6576040517f6697b23200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610bc78282611fd4565b815160208301206000610dc284611083565b9050600260008381526005602052604090205460ff166004811115610de957610de9612f4a565b14610e20576040517f4145817200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600160a01b038316610e5d576000828152600560205260409020546c0100000000000000000000000090046001600160a01b03169250610ebd565b6000828152600560205260409020546c0100000000000000000000000090046001600160a01b03163314610ebd576040517f4af43a9000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008281526005602052604090205461070890610100900464ffffffffff90811642031611610f18576040517f1992d0bd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600082815260056020526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016600317905561010081015115610f925761010081015160808201516001600160a01b031660009081526003602052604081208054909190610f8c908490613773565b90915550505b608081015160c0820151610fb06001600160a01b0383168683611e7c565b6000848152600560209081526040918290205482516001600160a01b038681168252928101859052888316936c010000000000000000000000009092049092169187917f582211c35a2139ac3bbaac74663c6a1f56c6cbb658b41fe11fd45a82074ac678910160405180910390a4505050505050565b611080816040518060a0016040528060006001600160a01b03168152602001600081526020016040518060200160405280600081525081526020016000815260200160405180602001604052806000815250815250611b12565b50565b611135604051806101e00160405280600063ffffffff168152602001600063ffffffff16815260200160006001600160a01b0316815260200160006001600160a01b0316815260200160006001600160a01b0316815260200160006001600160a01b0316815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160006001600160a01b0316815260200160008152602001606081525090565b81806020019051810190610aff91906137e1565b80516020820120600061115b83611083565b9050600160008381526005602052604090205460ff16600481111561118257611182612f4a565b146111b9576040517f4145817200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b3360009081527fd2043bf65931af3dbecf60d0db8f40e4160406d7beb00522f4200cf4944a1eb8602052604090205460ff161561123357806101400151421161122e576040517fe15ff9ea00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61127f565b62093a808161014001516112479190613773565b421161127f576040517fe15ff9ea00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008281526005602052604080822080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166004179055820151608083015161010084015160c0850151929391926112d89190613773565b90506112ee6001600160a01b0383168483611e7c565b604080516001600160a01b0384811682526020820184905285169187917fb4c55c0c9bc613519b920e88748090150b890a875d307f21bea7d4fb2e8bc958910160405180910390a3505050505050565b61135082805190602001208233610bcc565b5050565b611080813361137d565b60008281526001602052604081206113769083612001565b9392505050565b81516020830120600061138f84611083565b905061139c81838561200d565b604080516060808201835265ffffffffffff438116835242811660208085019182526001600160a01b0389811686880181815260008b815260068552899020975188549551915184166c01000000000000000000000000026bffffffffffffffffffffffff9288166601000000000000027fffffffffffffffffffffffffffffffffffffffff00000000000000000000000090971691909716179490941793909316939093179094558583015160a08088015160e08901516101208a01518a516080808d015160c0808f01518e5163ffffffff9095168552918b169c84019c909c52858a169c83019c909c529881019a909a52968901819052918801869052919691959094938716929189917ff8ae392d784b1ea5e8881bfa586d81abf07ef4f1e2fc75f7fe51c90f05199a5c910160405180910390a47fffffffffffffffffffffffff11111111111111111111111111111111111111126001600160a01b0384160161157957801561153b576040517f2598ad2e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b813414611574576040517f81de0bf300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6115c7565b8034146115b2576040517f81de0bf300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6115c76001600160a01b0384163386856121aa565b6101c085015151156115e9576115e4848484886101c00151612226565b6115f9565b34156115f9576115f98434612385565b5050505050505050565b6000600260008481526005602052604090205460ff16600481111561162a5761162a612f4a565b14611661576040517f4145817200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000838152600560205260409020546001600160a01b038381166c0100000000000000000000000090920416146116c4576040517f4af43a9000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b505060009081526005602052604090205461070861010090910464ffffffffff9081164203161190565b6040805161018081018252600080825260208201819052818301819052606082018190526080820181905260a0820181905260c0820181905260e0820181905261010082018190526101208201819052610140820181905261016082015290517f5aa6ccba0000000000000000000000000000000000000000000000000000000081523090635aa6ccba90611787908590600401613916565b600060405180830381865afa9250505080156117c557506040513d6000823e601f3d908101601f191682016040526117c291908101906137e1565b60015b6117dd5781806020019051810190610aff9190613934565b604051806101800160405280826000015163ffffffff168152602001826020015163ffffffff16815260200182604001516001600160a01b0316815260200182606001516001600160a01b0316815260200182608001516001600160a01b031681526020018260a001516001600160a01b031681526020018260c0015181526020018260e001518152602001826101000151815260200182610120015160001415151581526020018261014001518152602001826101600151815250915050919050565b919050565b7f043c983c49d46f0e102151eaf8085d4a2e6571d5df2d47b013f39bddfd4a639d6118d081611e72565b600260008381526005602052604090205460ff1660048111156118f5576118f5612f4a565b1461192c576040517f4145817200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008281526005602052604090205461070890610100900464ffffffffff9081164203161115611988576040517f3e908aac00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000828152600560205260408082206001905551339184917f0695cf1d39b3055dcd0fe02d8b47eaf0d5a13e1996de925de59d0ef9b7f7fad49190a35050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f556119f281611e72565b612710821115611a63576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f6e657746656552617465203e206d61780000000000000000000000000000000060448201526064015b60405180910390fd5b600280549083905560408051828152602081018590527f14914da2bf76024616fbe1859783fcd4dbddcb179b1f3a854949fbf920dcb95791015b60405180910390a1505050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f55611ad481611e72565b600480549083905560408051828152602081018590527f5cf09b12f3f56b4c564d51b25b40360af6d795198adb61ae0806a36c294323fa9101611a9d565b6000816020015142611b249190613a00565b9050611b3183838361244e565b6000611b4584606001518560a001516126d3565b90506000806002541115611b7257620f424060025483611b659190613a28565b611b6f9190613a3f565b90505b611b7c8183613a7a565b91506000604051806101e001604052804663ffffffff168152602001876000015163ffffffff16815260200187602001516001600160a01b0316815260200187604001516001600160a01b0316815260200187606001516001600160a01b0316815260200187608001516001600160a01b031681526020018481526020018760c0015181526020018381526020018660600151815260200187610100015181526020016007600089602001516001600160a01b03166001600160a01b031681526020019081526020016000206000815480929190611c5990613a8d565b91905055815260200186600001516001600160a01b031681526020018581526020018660800151815250604051602001611c9391906133d3565b60408051808303601f1901815282825280516020808301919091206000818152600583529390932080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016600117905589015189516060808c015160808d015160c08e0151928d015195985095966001600160a01b039094169587957f120ea0364f36cdac7983bcfdd55270ca09d7f9b314a2ebc425a3b01ab1d6403a95611d47958b95909493928e9290151590613ac5565b60405180910390a3807f3120e2bb59c86aca6890191a589a96af3662838efa374fbdcdf4c95bfe4a6c0e8760400151604051611d839190613916565b60405180910390a250505050505050565b611080816000610db0565b6000818152600160205260408120610aff906128b4565b600082815260208190526040902060010154611dd181611e72565b610d5e8383611fd4565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f7965db0b000000000000000000000000000000000000000000000000000000001480610aff57507f01ffc9a7000000000000000000000000000000000000000000000000000000007fffffffff00000000000000000000000000000000000000000000000000000000831614610aff565b61108081336128be565b306001600160a01b03831603611e9157505050565b80600003611e9e57505050565b7fffffffffffffffffffffffff11111111111111111111111111111111111111126001600160a01b03841601611f8b576000826001600160a01b03168260405160006040518083038185875af1925050503d8060008114611f1b576040519150601f19603f3d011682016040523d82523d6000602084013e611f20565b606091505b5050905080610d5e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f455448207472616e73666572206661696c6564000000000000000000000000006044820152606401611a5a565b610bc76001600160a01b038416838361292a565b600080611fac848461295b565b90508015611376576000848152600160205260409020611fcc9084612a23565b509392505050565b600080611fe18484612a38565b90508015611376576000848152600160205260409020611fcc9084612ad9565b60006113768383612aee565b6001600160a01b03811661204d576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000828152600660205260409020546c0100000000000000000000000090046001600160a01b0316156120ac576040517fbef7bb7d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b46836020015163ffffffff16146120ef576040517f7029fdf900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b82610140015142111561212e576040517f559895a300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6101808301516001600160a01b0316158015906121625750806001600160a01b03168361018001516001600160a01b031614155b80156121735750826101a001514211155b15610bc7576040517f14be123200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040516001600160a01b038481166024830152838116604483015260648201839052610d5e9186918216906323b872dd906084015b604051602081830303815290604052915060e01b6020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8381831617835250505050612b18565b600083838360405160240161223d93929190613b1b565b60408051601f198184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f461e0c2100000000000000000000000000000000000000000000000000000000179052905060006122a4868334612b94565b905080516000036122e1576040517f1a95ad2600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b805160201461231c576040517ff3725cca00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f461e0c210000000000000000000000000000000000000000000000000000000061234682613b4c565b1461237d576040517ff3725cca00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b505050505050565b804710156123c1576040517fcd786059000000000000000000000000000000000000000000000000000000008152306004820152602401611a5a565b6000826001600160a01b03168260405160006040518083038185875af1925050503d806000811461240e576040519150601f19603f3d011682016040523d82523d6000602084013e612413565b606091505b5050905080610bc7576040517f1425ea4200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b46836000015163ffffffff1603612491576040517f7029fdf900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60a083015115806124a4575060c0830151155b156124db576040517fe38820c800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60208301516001600160a01b03161580612500575060408301516001600160a01b0316155b15612537576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60608301516001600160a01b0316158061255c575060808301516001600160a01b0316155b15612593576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61259f61070842613773565b83610100015110156125dd576040517f04b7fcc800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61ffff826080015151111561261e576040517ffbe24d4900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b606082015115801590612651575060808301516001600160a01b031673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee145b15612688576040517f2598ad2e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008113158061269c575082610100015181135b15610bc7576040517f352807b900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60007fffffffffffffffffffffffff11111111111111111111111111111111111111126001600160a01b038416016127455734821461273e576040517f81de0bf300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5034610aff565b612757836001600160a01b0316612c4a565b341561278f576040517f81de0bf300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201526001600160a01b038416906370a0823190602401602060405180830381865afa1580156127ec573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128109190613b91565b90506128276001600160a01b0384163330856121aa565b6040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015281906001600160a01b038516906370a0823190602401602060405180830381865afa158015612886573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128aa9190613b91565b6113769190613a7a565b6000610aff825490565b6000828152602081815260408083206001600160a01b038516845290915290205460ff16611350576040517fe2517d3f0000000000000000000000000000000000000000000000000000000081526001600160a01b038216600482015260248101839052604401611a5a565b6040516001600160a01b03838116602483015260448201839052610bc791859182169063a9059cbb906064016121df565b6000828152602081815260408083206001600160a01b038516845290915281205460ff16612a1b576000838152602081815260408083206001600160a01b0386168452909152902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790556129d33390565b6001600160a01b0316826001600160a01b0316847f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a4506001610aff565b506000610aff565b6000611376836001600160a01b038416612cf0565b6000828152602081815260408083206001600160a01b038516845290915281205460ff1615612a1b576000838152602081815260408083206001600160a01b038616808552925280832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016905551339286917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a4506001610aff565b6000611376836001600160a01b038416612d37565b6000826000018281548110612b0557612b05613baa565b9060005260206000200154905092915050565b6000612b2d6001600160a01b03841683612e2a565b90508051600014158015612b52575080806020019051810190612b509190613bd9565b155b15610bc7576040517f5274afe70000000000000000000000000000000000000000000000000000000081526001600160a01b0384166004820152602401611a5a565b606081471015612bd2576040517fcd786059000000000000000000000000000000000000000000000000000000008152306004820152602401611a5a565b600080856001600160a01b03168486604051612bee9190613bf6565b60006040518083038185875af1925050503d8060008114612c2b576040519150601f19603f3d011682016040523d82523d6000602084013e612c30565b606091505b5091509150612c40868383612e38565b9695505050505050565b7fffffffffffffffffffffffff11111111111111111111111111111111111111126001600160a01b03821601612cac576040517f7f523fe800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b806001600160a01b03163b600003611080576040517f7f523fe800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000818152600183016020526040812054612a1b57508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155610aff565b60008181526001830160205260408120548015612e20576000612d5b600183613a7a565b8554909150600090612d6f90600190613a7a565b9050808214612dd4576000866000018281548110612d8f57612d8f613baa565b9060005260206000200154905080876000018481548110612db257612db2613baa565b6000918252602080832090910192909255918252600188019052604090208390555b8554869080612de557612de5613c12565b600190038181906000526020600020016000905590558560010160008681526020019081526020016000206000905560019350505050610aff565b6000915050610aff565b606061137683836000612b94565b606082612e4d57612e4882612ead565b611376565b8151158015612e6457506001600160a01b0384163b155b15612ea6576040517f9996b3150000000000000000000000000000000000000000000000000000000081526001600160a01b0385166004820152602401611a5a565b5080611376565b805115612ebd5780518082602001fd5b6040517f1425ea4200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600060208284031215612f0157600080fd5b81357fffffffff000000000000000000000000000000000000000000000000000000008116811461137657600080fd5b600060208284031215612f4357600080fd5b5035919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b60058110612fb0577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b9052565b60208101610aff8284612f79565b6001600160a01b038116811461108057600080fd5b80356118a181612fc2565b60008060408385031215612ff557600080fd5b823561300081612fc2565b9150602083013561301081612fc2565b809150509250929050565b60008060006060848603121561303057600080fd5b8335925060208401359150604084013561304981612fc2565b809150509250925092565b60006020828403121561306657600080fd5b813561137681612fc2565b6000806040838503121561308457600080fd5b82359150602083013561301081612fc2565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051610120810167ffffffffffffffff811182821017156130e9576130e9613096565b60405290565b60405160a0810167ffffffffffffffff811182821017156130e9576130e9613096565b6040516101e0810167ffffffffffffffff811182821017156130e9576130e9613096565b604051610180810167ffffffffffffffff811182821017156130e9576130e9613096565b604051601f8201601f1916810167ffffffffffffffff8111828210171561318357613183613096565b604052919050565b600067ffffffffffffffff8211156131a5576131a5613096565b50601f01601f191660200190565b600082601f8301126131c457600080fd5b81356131d76131d28261318b565b61315a565b8181528460208386010111156131ec57600080fd5b816020850160208301376000918101602001919091529392505050565b6000806040838503121561321c57600080fd5b823567ffffffffffffffff81111561323357600080fd5b61323f858286016131b3565b925050602083013561301081612fc2565b63ffffffff8116811461108057600080fd5b80356118a181613250565b801515811461108057600080fd5b80356118a18161326d565b6000610120828403121561329957600080fd5b6132a16130c5565b90506132ac82613262565b81526132ba60208301612fd7565b60208201526132cb60408301612fd7565b60408201526132dc60608301612fd7565b60608201526132ed60808301612fd7565b608082015260a082013560a082015260c082013560c082015261331260e0830161327b565b60e082015261010080830135818301525092915050565b6000610120828403121561333c57600080fd5b6113768383613286565b60006020828403121561335857600080fd5b813567ffffffffffffffff81111561336f57600080fd5b61337b848285016131b3565b949350505050565b60005b8381101561339e578181015183820152602001613386565b50506000910152565b600081518084526133bf816020860160208601613383565b601f01601f19169290920160200192915050565b602081526133ea60208201835163ffffffff169052565b60006020830151613403604084018263ffffffff169052565b5060408301516001600160a01b03811660608401525060608301516001600160a01b03811660808401525060808301516001600160a01b03811660a08401525060a08301516001600160a01b03811660c08401525060c083015160e08381019190915283015161010080840191909152830151610120808401919091528301516101408084019190915283015161016080840191909152830151610180808401919091528301516101a06134c1818501836001600160a01b03169052565b8401516101c0848101919091528401516101e080850152905061337b6102008401826133a7565b608081016134f68287612f79565b64ffffffffff8516602083015265ffffffffffff841660408301526001600160a01b038316606083015295945050505050565b6000806040838503121561353c57600080fd5b823567ffffffffffffffff81111561355357600080fd5b61355f858286016131b3565b95602094909401359450505050565b6000806040838503121561358157600080fd5b50508035926020909101359150565b815163ffffffff168152610180810160208301516135b6602084018263ffffffff169052565b5060408301516135d160408401826001600160a01b03169052565b5060608301516135ec60608401826001600160a01b03169052565b50608083015161360760808401826001600160a01b03169052565b5060a083015161362260a08401826001600160a01b03169052565b5060c083015160c083015260e083015160e0830152610100808401518184015250610120808401516136578285018215159052565b5050610140838101519083015261016092830151929091019190915290565b600080610140838503121561368a57600080fd5b6136948484613286565b915061012083013567ffffffffffffffff808211156136b257600080fd5b9084019060a082870312156136c657600080fd5b6136ce6130ef565b82356136d981612fc2565b8152602083810135908201526040830135828111156136f757600080fd5b613703888286016131b3565b6040830152506060830135606082015260808301358281111561372557600080fd5b613731888286016131b3565b6080830152508093505050509250929050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b80820180821115610aff57610aff613744565b80516118a181613250565b80516118a181612fc2565b600082601f8301126137ad57600080fd5b81516137bb6131d28261318b565b8181528460208386010111156137d057600080fd5b61337b826020830160208701613383565b6000602082840312156137f357600080fd5b815167ffffffffffffffff8082111561380b57600080fd5b908301906101e0828603121561382057600080fd5b613828613112565b61383183613786565b815261383f60208401613786565b602082015261385060408401613791565b604082015261386160608401613791565b606082015261387260808401613791565b608082015261388360a08401613791565b60a082015260c0838101519082015260e0808401519082015261010080840151908201526101208084015190820152610140808401519082015261016080840151908201526101806138d6818501613791565b908201526101a083810151908201526101c080840151838111156138f957600080fd5b6139058882870161379c565b918301919091525095945050505050565b60208152600061137660208301846133a7565b80516118a18161326d565b6000610180828403121561394757600080fd5b61394f613136565b61395883613786565b815261396660208401613786565b602082015261397760408401613791565b604082015261398860608401613791565b606082015261399960808401613791565b60808201526139aa60a08401613791565b60a082015260c083015160c082015260e083015160e08201526101008084015181830152506101206139dd818501613929565b908201526101408381015190820152610160928301519281019290925250919050565b8082018281126000831280158216821582161715613a2057613a20613744565b505092915050565b8082028115828204841417610aff57610aff613744565b600082613a75577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b81810381811115610aff57610aff613744565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203613abe57613abe613744565b5060010190565b60e081526000613ad860e083018a6133a7565b63ffffffff989098166020830152506001600160a01b039586166040820152939094166060840152608083019190915260a082015290151560c090910152919050565b6001600160a01b0384168152826020820152606060408201526000613b4360608301846133a7565b95945050505050565b80516020808301519190811015613b8b577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8160200360031b1b821691505b50919050565b600060208284031215613ba357600080fd5b5051919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b600060208284031215613beb57600080fd5b81516113768161326d565b60008251613c08818460208701613383565b9190910192915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fdfea2646970667358221220fef42b85b97e95ca087836390d97d99307ec60b38cd20d26ea0f113c18a0660d64736f6c63430008180033", } // FastBridgeV2ABI is the input ABI used to generate the binding from. @@ -14352,7 +14352,7 @@ func (_IFastBridgeV2Errors *IFastBridgeV2ErrorsTransactorRaw) Transact(opts *bin // SafeERC20MetaData contains all meta data concerning the SafeERC20 contract. var SafeERC20MetaData = &bind.MetaData{ ABI: "[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"currentAllowance\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"requestedDecrease\",\"type\":\"uint256\"}],\"name\":\"SafeERC20FailedDecreaseAllowance\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"}],\"name\":\"SafeERC20FailedOperation\",\"type\":\"error\"}]", - Bin: "0x60566037600b82828239805160001a607314602a57634e487b7160e01b600052600060045260246000fd5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600080fdfea26469706673582212202e6244574a9418b179bbe1f5d6f1483cf0da887e64158bb04463fae84495de4464736f6c63430008180033", + Bin: "0x60566037600b82828239805160001a607314602a57634e487b7160e01b600052600060045260246000fd5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600080fdfea2646970667358221220bf9b4d830342bc19a7972f35e2bc28e74742724839e41d049e96167e6d81d6ea64736f6c63430008180033", } // SafeERC20ABI is the input ABI used to generate the binding from. @@ -14525,7 +14525,7 @@ func (_SafeERC20 *SafeERC20TransactorRaw) Transact(opts *bind.TransactOpts, meth // UniversalTokenLibMetaData contains all meta data concerning the UniversalTokenLib contract. var UniversalTokenLibMetaData = &bind.MetaData{ ABI: "[]", - Bin: "0x60566037600b82828239805160001a607314602a57634e487b7160e01b600052600060045260246000fd5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600080fdfea2646970667358221220f32c0660d6e44933a56619135234122fa7c42eeae2b3df059ed3d1e4d3c16aa264736f6c63430008180033", + Bin: "0x60566037600b82828239805160001a607314602a57634e487b7160e01b600052600060045260246000fd5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600080fdfea264697066735822122030abe7c99e33645ff08fba6fd46ebf752f2157cc4f5e930a35e81633f8aacbb864736f6c63430008180033", } // UniversalTokenLibABI is the input ABI used to generate the binding from. diff --git a/services/rfq/contracts/fastbridgev2/fastbridgev2.contractinfo.json b/services/rfq/contracts/fastbridgev2/fastbridgev2.contractinfo.json index f7b2869bb1..1ead51fc19 100644 --- a/services/rfq/contracts/fastbridgev2/fastbridgev2.contractinfo.json +++ b/services/rfq/contracts/fastbridgev2/fastbridgev2.contractinfo.json @@ -1 +1 @@ -{"solidity/FastBridgeV2.sol:AccessControl":{"code":"0x","runtime-code":"0x","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.24 ^0.8.0 ^0.8.20;\n\n// contracts/interfaces/IAdmin.sol\n\ninterface IAdmin {\n // ============ Events ============\n\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n event ChainGasAmountUpdated(uint256 oldChainGasAmount, uint256 newChainGasAmount);\n\n // ============ Methods ============\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n\n function setChainGasAmount(uint256 newChainGasAmount) external;\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IFastBridgeRecipient.sol\n\ninterface IFastBridgeRecipient {\n function fastBridgeTransferReceived(\n address token,\n uint256 amount,\n bytes memory callParams\n )\n external\n payable\n returns (bytes4);\n}\n\n// contracts/interfaces/IFastBridgeV2Errors.sol\n\ninterface IFastBridgeV2Errors {\n error AmountIncorrect();\n error CallParamsLengthAboveMax();\n error ChainIncorrect();\n error ExclusivityParamsIncorrect();\n error MsgValueIncorrect();\n error NativeTokenCallValueNotSupported();\n error SenderIncorrect();\n error StatusIncorrect();\n error ZeroAddress();\n\n error RecipientIncorrectReturnValue();\n error RecipientNoReturnValue();\n\n error DeadlineExceeded();\n error DeadlineNotExceeded();\n error DeadlineTooShort();\n error DisputePeriodNotPassed();\n error DisputePeriodPassed();\n error ExclusivityPeriodNotPassed();\n\n error TransactionRelayed();\n}\n\n// contracts/libs/Errors.sol\n\nerror DeadlineExceeded();\nerror DeadlineNotExceeded();\nerror DeadlineTooShort();\nerror InsufficientOutputAmount();\n\nerror MsgValueIncorrect();\nerror PoolNotFound();\nerror TokenAddressMismatch();\nerror TokenNotContract();\nerror TokenNotETH();\nerror TokensIdentical();\n\nerror ChainIncorrect();\nerror AmountIncorrect();\nerror ZeroAddress();\n\nerror DisputePeriodNotPassed();\nerror DisputePeriodPassed();\nerror SenderIncorrect();\nerror StatusIncorrect();\nerror TransactionIdIncorrect();\nerror TransactionRelayed();\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// contracts/interfaces/IFastBridgeV2.sol\n\ninterface IFastBridgeV2 is IFastBridge {\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n struct BridgeTxDetails {\n BridgeStatus status;\n uint40 proofBlockTimestamp;\n uint48 proofBlockNumber;\n address proofRelayer;\n }\n\n struct BridgeRelay {\n uint48 blockNumber;\n uint48 blockTimestamp;\n address relayer;\n }\n\n /// @notice New params introduced in the FastBridgeV2.\n /// We are passing fields from the older BridgeParams struct outside of this struct\n /// for backwards compatibility.\n /// Note: quoteRelayer and quoteExclusivitySeconds are either both zero (indicating no exclusivity)\n /// or both non-zero (indicating exclusivity for the given period).\n /// Note: callValue \u003e 0 can NOT be used with destToken = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE (ETH_ADDRESS)\n /// @param quoteRelayer Relayer that provided the quote for the transaction\n /// @param quoteExclusivitySeconds Period of time the quote relayer is guaranteed exclusivity after user's deposit\n /// @param quoteId Unique quote identifier used for tracking the quote\n /// @param callValue ETH value to send to the recipient (if any)\n /// @param callParams Parameters for the arbitrary call to the destination recipient (if any)\n struct BridgeParamsV2 {\n address quoteRelayer;\n int256 quoteExclusivitySeconds;\n bytes quoteId;\n uint256 callValue;\n bytes callParams;\n }\n\n /// @notice Updated bridge transaction struct to include parameters introduced in FastBridgeV2.\n /// Note: only `exclusivityRelayer` can fill such a transaction until `exclusivityEndTime`.\n /// TODO: consider changing the encoding scheme to prevent spending extra gas on decoding.\n struct BridgeTransactionV2 {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n uint256 callValue; // ETH value to send to the recipient (if any) - replaces V1's sendChainGas flag\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n address exclusivityRelayer;\n uint256 exclusivityEndTime;\n bytes callParams;\n }\n\n event BridgeQuoteDetails(bytes32 indexed transactionId, bytes quoteId);\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability\n /// to provide temporary exclusivity fill rights for the quote relayer.\n /// @param params The parameters required to bridge\n /// @param paramsV2 The parameters for exclusivity fill rights (optional, can be left empty)\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function relay(bytes memory request, address relayer) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param transactionId The transaction id associated with the encoded bridge transaction to prove\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital.\n /// @notice Can only send funds to the relayer address on the proof.\n /// @param request The encoded bridge transaction to claim on origin chain\n function claim(bytes memory request) external;\n /// @notice Checks if a transaction has been relayed\n /// @param transactionId The ID of the transaction to check\n /// @return True if the transaction has been relayed, false otherwise\n function bridgeRelays(bytes32 transactionId) external view returns (bool);\n\n /// @notice Returns the status of a bridge transaction\n /// @param transactionId The ID of the bridge transaction\n /// @return BridgeStatus Status of the bridge transaction\n function bridgeStatuses(bytes32 transactionId) external view returns (BridgeStatus);\n\n /// @notice Returns the timestamp and relayer of a bridge proof\n /// @param transactionId The ID of the bridge transaction\n /// @return timestamp The timestamp of the bridge proof\n /// @return relayer The relayer address of the bridge proof\n function bridgeProofs(bytes32 transactionId) external view returns (uint96 timestamp, address relayer);\n\n /// @notice Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\n /// @param request The bridge request to decode\n function getBridgeTransactionV2(bytes memory request) external view returns (BridgeTransactionV2 memory);\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// contracts/libs/UniversalToken.sol\n\nlibrary UniversalTokenLib {\n using SafeERC20 for IERC20;\n\n address internal constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Transfers tokens to the given account. Reverts if transfer is not successful.\n /// @dev This might trigger fallback, if ETH is transferred to the contract.\n /// Make sure this can not lead to reentrancy attacks.\n function universalTransfer(address token, address to, uint256 value) internal {\n // Don't do anything, if need to send tokens to this address\n if (to == address(this)) return;\n // Don't do anything, if trying to send zero value\n if (value == 0) return;\n if (token == ETH_ADDRESS) {\n /// @dev Note: this can potentially lead to executing code in `to`.\n // solhint-disable-next-line avoid-low-level-calls\n (bool success,) = to.call{value: value}(\"\");\n require(success, \"ETH transfer failed\");\n } else {\n IERC20(token).safeTransfer(to, value);\n }\n }\n\n /// @notice Issues an infinite allowance to the spender, if the current allowance is insufficient\n /// to spend the given amount.\n function universalApproveInfinity(address token, address spender, uint256 amountToSpend) internal {\n // ETH Chad doesn't require your approval\n if (token == ETH_ADDRESS) return;\n // No-op if allowance is already sufficient\n uint256 allowance = IERC20(token).allowance(address(this), spender);\n if (allowance \u003e= amountToSpend) return;\n // Otherwise, reset approval to 0 and set to max allowance\n if (allowance \u003e 0) IERC20(token).safeDecreaseAllowance(spender, allowance);\n IERC20(token).safeIncreaseAllowance(spender, type(uint256).max);\n }\n\n /// @notice Returns the balance of the given token (or native ETH) for the given account.\n function universalBalanceOf(address token, address account) internal view returns (uint256) {\n if (token == ETH_ADDRESS) {\n return account.balance;\n } else {\n return IERC20(token).balanceOf(account);\n }\n }\n\n /// @dev Checks that token is a contract and not ETH_ADDRESS.\n function assertIsContract(address token) internal view {\n // Check that ETH_ADDRESS was not used (in case this is a predeploy on any of the chains)\n if (token == UniversalTokenLib.ETH_ADDRESS) revert TokenNotContract();\n // Check that token is not an EOA\n if (token.code.length == 0) revert TokenNotContract();\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/Admin.sol\n\ncontract Admin is IAdmin, AccessControlEnumerable {\n using UniversalTokenLib for address;\n\n bytes32 public constant RELAYER_ROLE = keccak256(\"RELAYER_ROLE\");\n bytes32 public constant REFUNDER_ROLE = keccak256(\"REFUNDER_ROLE\");\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n uint256 public constant FEE_BPS = 1e6;\n uint256 public constant FEE_RATE_MAX = 0.01e6; // max 1% on origin amount\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Chain gas amount to forward as rebate if requested\n uint256 public chainGasAmount;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n }\n\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n require(newFeeRate \u003c= FEE_RATE_MAX, \"newFeeRate \u003e max\");\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n token.universalTransfer(recipient, feeAmount);\n emit FeesSwept(token, recipient, feeAmount);\n }\n\n function setChainGasAmount(uint256 newChainGasAmount) external onlyRole(GOVERNOR_ROLE) {\n uint256 oldChainGasAmount = chainGasAmount;\n chainGasAmount = newChainGasAmount;\n emit ChainGasAmountUpdated(oldChainGasAmount, newChainGasAmount);\n }\n}\n\n// contracts/FastBridgeV2.sol\n\n/// @notice FastBridgeV2 is a contract for bridging tokens across chains.\ncontract FastBridgeV2 is Admin, IFastBridgeV2, IFastBridgeV2Errors {\n using SafeERC20 for IERC20;\n using UniversalTokenLib for address;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Delay for a transaction after which it could be permisionlessly refunded\n uint256 public constant REFUND_DELAY = 7 days;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n /// @notice Maximum length of accepted callParams\n uint256 public constant MAX_CALL_PARAMS_LENGTH = 2 ** 16 - 1;\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeTxDetails) public bridgeTxDetails;\n /// @notice Relay details on destination chain\n mapping(bytes32 =\u003e BridgeRelay) public bridgeRelayDetails;\n /// @notice Unique bridge nonces tracked per originSender\n mapping(address =\u003e uint256) public senderNonces;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Replaced by senderNonces\n uint256 public immutable nonce = 0;\n /// @notice the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n bridge({\n params: params,\n paramsV2: BridgeParamsV2({\n quoteRelayer: address(0),\n quoteExclusivitySeconds: 0,\n quoteId: bytes(\"\"),\n callValue: 0,\n callParams: bytes(\"\")\n })\n });\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes memory request) external payable {\n relay({request: request, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes memory request, bytes32 destTxHash) external {\n prove({transactionId: keccak256(request), destTxHash: destTxHash, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridgeV2\n function claim(bytes memory request) external {\n claim({request: request, to: address(0)});\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003e DISPUTE_PERIOD) {\n revert DisputePeriodPassed();\n }\n\n // @dev relayer gets slashed effectively if dest relay has gone thru\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n bridgeTxDetails[transactionId].proofRelayer = address(0);\n bridgeTxDetails[transactionId].proofBlockTimestamp = 0;\n bridgeTxDetails[transactionId].proofBlockNumber = 0;\n\n emit BridgeProofDisputed(transactionId, msg.sender);\n }\n\n /// @inheritdoc IFastBridge\n function refund(bytes memory request) external {\n bytes32 transactionId = keccak256(request);\n\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n\n if (bridgeTxDetails[transactionId].status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n\n if (hasRole(REFUNDER_ROLE, msg.sender)) {\n // Refunder can refund if deadline has passed\n if (block.timestamp \u003c= transaction.deadline) revert DeadlineNotExceeded();\n } else {\n // Permissionless refund is allowed after REFUND_DELAY\n if (block.timestamp \u003c= transaction.deadline + REFUND_DELAY) revert DeadlineNotExceeded();\n }\n\n // if all checks passed, set to REFUNDED status\n bridgeTxDetails[transactionId].status = BridgeStatus.REFUNDED;\n\n // transfer origin collateral back to original sender\n address to = transaction.originSender;\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount + transaction.originFeeAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (bridgeTxDetails[transactionId].proofRelayer != relayer) revert SenderIncorrect();\n return _timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n /// @dev This method is added to achieve backwards compatibility with decoding requests into V1 structs:\n /// - `callValue` is partially reported as a zero/non-zero flag\n /// - `callParams` is ignored\n /// In order to process all kinds of requests use getBridgeTransactionV2 instead.\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory) {\n // Try decoding into V2 struct first. This will revert if V1 struct is passed\n try this.getBridgeTransactionV2(request) returns (BridgeTransactionV2 memory txV2) {\n // Note: we entirely ignore the callParams field, as it was not present in V1\n return BridgeTransaction({\n originChainId: txV2.originChainId,\n destChainId: txV2.destChainId,\n originSender: txV2.originSender,\n destRecipient: txV2.destRecipient,\n originToken: txV2.originToken,\n destToken: txV2.destToken,\n originAmount: txV2.originAmount,\n destAmount: txV2.destAmount,\n originFeeAmount: txV2.originFeeAmount,\n sendChainGas: txV2.callValue != 0,\n deadline: txV2.deadline,\n nonce: txV2.nonce\n });\n } catch {\n // Fallback to V1 struct\n return abi.decode(request, (BridgeTransaction));\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) public payable {\n int256 exclusivityEndTime = int256(block.timestamp) + paramsV2.quoteExclusivitySeconds;\n _validateBridgeParams(params, paramsV2, exclusivityEndTime);\n\n // transfer tokens to bridge contract\n /// @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _pullToken(params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n\n // set status to requested\n bytes memory request = abi.encode(\n BridgeTransactionV2({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n callValue: paramsV2.callValue,\n deadline: params.deadline,\n nonce: senderNonces[params.sender]++, // increment nonce on every bridge\n exclusivityRelayer: paramsV2.quoteRelayer,\n // We checked exclusivityEndTime to be in range (0 .. params.deadline] above, so can safely cast\n exclusivityEndTime: uint256(exclusivityEndTime),\n callParams: paramsV2.callParams\n })\n );\n bytes32 transactionId = keccak256(request);\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n\n emit BridgeRequested({\n transactionId: transactionId,\n sender: params.sender,\n request: request,\n destChainId: params.dstChainId,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n sendChainGas: paramsV2.callValue != 0\n });\n emit BridgeQuoteDetails(transactionId, paramsV2.quoteId);\n }\n\n /// @inheritdoc IFastBridgeV2\n function relay(bytes memory request, address relayer) public payable {\n bytes32 transactionId = keccak256(request);\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n _validateRelayParams(transaction, transactionId, relayer);\n // mark bridge transaction as relayed\n bridgeRelayDetails[transactionId] =\n BridgeRelay({blockNumber: uint48(block.number), blockTimestamp: uint48(block.timestamp), relayer: relayer});\n\n // transfer tokens to recipient on destination chain and do an arbitrary call if requested\n address to = transaction.destRecipient;\n address token = transaction.destToken;\n uint256 amount = transaction.destAmount;\n\n // All state changes have been done at this point, can proceed to the external calls.\n // This follows the checks-effects-interactions pattern to mitigate potential reentrancy attacks.\n if (token == UniversalTokenLib.ETH_ADDRESS) {\n // For ETH non-zero callValue is not allowed\n if (transaction.callValue != 0) revert NativeTokenCallValueNotSupported();\n // Check that the correct msg.value was sent\n if (msg.value != amount) revert MsgValueIncorrect();\n } else {\n // For ERC20s, we check that the correct msg.value was sent\n if (msg.value != transaction.callValue) revert MsgValueIncorrect();\n // We need to transfer the tokens from the Relayer to the recipient first before performing an\n // optional post-transfer arbitrary call.\n IERC20(token).safeTransferFrom(msg.sender, to, amount);\n }\n\n if (transaction.callParams.length != 0) {\n // Arbitrary call requested, perform it while supplying full msg.value to the recipient\n // Note: if token has a fee on transfers, the recipient will have received less than `amount`.\n // This is a very niche edge case and should be handled by the recipient contract.\n _checkedCallRecipient({recipient: to, token: token, amount: amount, callParams: transaction.callParams});\n } else if (msg.value != 0) {\n // No arbitrary call requested, but msg.value was sent. This is either a relay with ETH,\n // or a non-zero callValue request with an ERC20. In both cases, transfer the ETH to the recipient.\n Address.sendValue(payable(to), msg.value);\n }\n\n emit BridgeRelayed({\n transactionId: transactionId,\n relayer: relayer,\n to: to,\n originChainId: transaction.originChainId,\n originToken: transaction.originToken,\n destToken: transaction.destToken,\n originAmount: transaction.originAmount,\n destAmount: transaction.destAmount,\n chainGasAmount: transaction.callValue\n });\n }\n\n /// @inheritdoc IFastBridgeV2\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) public onlyRole(RELAYER_ROLE) {\n // update bridge tx status given proof provided\n if (bridgeTxDetails[transactionId].status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n bridgeTxDetails[transactionId].status = BridgeStatus.RELAYER_PROVED;\n bridgeTxDetails[transactionId].proofBlockTimestamp = uint40(block.timestamp);\n bridgeTxDetails[transactionId].proofBlockNumber = uint48(block.number);\n bridgeTxDetails[transactionId].proofRelayer = relayer;\n\n emit BridgeProofProvided(transactionId, relayer, destTxHash);\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes memory request, address to) public {\n bytes32 transactionId = keccak256(request);\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n\n // update bridge tx status if able to claim origin collateral\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n\n // if \"to\" is zero addr, permissionlessly send funds to proven relayer\n if (to == address(0)) {\n to = bridgeTxDetails[transactionId].proofRelayer;\n } else if (bridgeTxDetails[transactionId].proofRelayer != msg.sender) {\n revert SenderIncorrect();\n }\n\n if (_timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003c= DISPUTE_PERIOD) {\n revert DisputePeriodNotPassed();\n }\n\n bridgeTxDetails[transactionId].status = BridgeStatus.RELAYER_CLAIMED;\n\n // update protocol fees if origin fee amount exists\n if (transaction.originFeeAmount \u003e 0) protocolFees[transaction.originToken] += transaction.originFeeAmount;\n\n // transfer origin collateral less fee to specified address\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositClaimed(transactionId, bridgeTxDetails[transactionId].proofRelayer, to, token, amount);\n }\n\n function bridgeStatuses(bytes32 transactionId) public view returns (BridgeStatus status) {\n return bridgeTxDetails[transactionId].status;\n }\n\n function bridgeProofs(bytes32 transactionId) public view returns (uint96 timestamp, address relayer) {\n timestamp = bridgeTxDetails[transactionId].proofBlockTimestamp;\n relayer = bridgeTxDetails[transactionId].proofRelayer;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeRelays(bytes32 transactionId) public view returns (bool) {\n // has this transactionId been relayed?\n return bridgeRelayDetails[transactionId].relayer != address(0);\n }\n\n /// @inheritdoc IFastBridgeV2\n function getBridgeTransactionV2(bytes memory request) public pure returns (BridgeTransactionV2 memory) {\n return abi.decode(request, (BridgeTransactionV2));\n }\n\n /// @notice Pulls a requested token from the user to this contract.\n function _pullToken(address token, uint256 amount) internal returns (uint256 amountPulled) {\n if (token == UniversalTokenLib.ETH_ADDRESS) {\n // For ETH we just need to check that the supplied msg.value is correct\n if (amount != msg.value) revert MsgValueIncorrect();\n amountPulled = msg.value;\n } else {\n token.assertIsContract();\n // Record token balance before transfer\n amountPulled = IERC20(token).balanceOf(address(this));\n // Token needs to be pulled only if msg.value is zero\n // This way user can specify WETH as the origin asset\n IERC20(token).safeTransferFrom(msg.sender, address(this), amount);\n // Use the difference between the recorded balance and the current balance as the amountPulled\n amountPulled = IERC20(token).balanceOf(address(this)) - amountPulled;\n }\n }\n\n /// @notice Calls the Recipient's hook function with the specified callParams and performs\n /// all the necessary checks for the returned value.\n function _checkedCallRecipient(\n address recipient,\n address token,\n uint256 amount,\n bytes memory callParams\n )\n internal\n {\n bytes memory hookData =\n abi.encodeCall(IFastBridgeRecipient.fastBridgeTransferReceived, (token, amount, callParams));\n // This will bubble any revert messages from the hook function\n bytes memory returnData = Address.functionCallWithValue({target: recipient, data: hookData, value: msg.value});\n // Explicit revert if no return data at all\n if (returnData.length == 0) revert RecipientNoReturnValue();\n // Check that exactly a single return value was returned\n if (returnData.length != 32) revert RecipientIncorrectReturnValue();\n // Return value should be abi-encoded hook function selector\n if (bytes32(returnData) != bytes32(IFastBridgeRecipient.fastBridgeTransferReceived.selector)) {\n revert RecipientIncorrectReturnValue();\n }\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint40(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint40).max but\n /// proof.timestamp \u003c type(uint40).max via unchecked statement\n /// @param proofBlockTimestamp The bridge proof block timestamp\n /// @return delta Time delta since proof submitted\n function _timeSince(uint40 proofBlockTimestamp) internal view returns (uint256 delta) {\n unchecked {\n delta = uint40(block.timestamp) - proofBlockTimestamp;\n }\n }\n\n /// @notice Performs all the necessary checks for a bridge to happen.\n /// @dev There's no good way to refactor this function to reduce cyclomatic complexity due to\n /// the number of checks that need to be performed, so we skip the code-complexity rule here.\n // solhint-disable-next-line code-complexity\n function _validateBridgeParams(\n BridgeParams memory params,\n BridgeParamsV2 memory paramsV2,\n int256 exclusivityEndTime\n )\n internal\n view\n {\n // Check V1 (legacy) params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.sender == address(0) || params.to == address(0)) revert ZeroAddress();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n // Check V2 params\n if (paramsV2.callParams.length \u003e MAX_CALL_PARAMS_LENGTH) revert CallParamsLengthAboveMax();\n if (paramsV2.callValue != 0 \u0026\u0026 params.destToken == UniversalTokenLib.ETH_ADDRESS) {\n revert NativeTokenCallValueNotSupported();\n }\n // exclusivityEndTime must be in range (0 .. params.deadline]\n if (exclusivityEndTime \u003c= 0 || exclusivityEndTime \u003e int256(params.deadline)) {\n revert ExclusivityParamsIncorrect();\n }\n }\n\n /// @notice Performs all the necessary checks for a relay to happen.\n function _validateRelayParams(\n BridgeTransactionV2 memory transaction,\n bytes32 transactionId,\n address relayer\n )\n internal\n view\n {\n if (relayer == address(0)) revert ZeroAddress();\n // Check if the transaction has already been relayed\n if (bridgeRelays(transactionId)) revert TransactionRelayed();\n if (transaction.destChainId != uint32(block.chainid)) revert ChainIncorrect();\n // Check the deadline for relay to happen\n if (block.timestamp \u003e transaction.deadline) revert DeadlineExceeded();\n // Check the exclusivity period, if it is still ongoing\n // forgefmt: disable-next-item\n if (\n transaction.exclusivityRelayer != address(0) \u0026\u0026\n transaction.exclusivityRelayer != relayer \u0026\u0026\n block.timestamp \u003c= transaction.exclusivityEndTime\n ) {\n revert ExclusivityPeriodNotPassed();\n }\n }\n}\n","language":"Solidity","languageVersion":"0.8.24","compilerVersion":"0.8.24","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"","srcMapRuntime":"","abiDefinition":[{"inputs":[],"name":"AccessControlBadConfirmation","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"bytes32","name":"neededRole","type":"bytes32"}],"name":"AccessControlUnauthorizedAccount","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"previousAdminRole","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"newAdminRole","type":"bytes32"}],"name":"RoleAdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleRevoked","type":"event"},{"inputs":[],"name":"DEFAULT_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleAdmin","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"grantRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"hasRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"callerConfirmation","type":"address"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"revokeRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"}],"userDoc":{"kind":"user","methods":{},"version":1},"developerDoc":{"details":"Contract module that allows children to implement role-based access control mechanisms. This is a lightweight version that doesn't allow enumerating role members except through off-chain means by accessing the contract event logs. Some applications may benefit from on-chain enumerability, for those cases see {AccessControlEnumerable}. Roles are referred to by their `bytes32` identifier. These should be exposed in the external API and be unique. The best way to achieve this is by using `public constant` hash digests: ```solidity bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\"); ``` Roles can be used to represent a set of permissions. To restrict access to a function call, use {hasRole}: ```solidity function foo() public { require(hasRole(MY_ROLE, msg.sender)); ... } ``` Roles can be granted and revoked dynamically via the {grantRole} and {revokeRole} functions. Each role has an associated admin role, and only accounts that have a role's admin role can call {grantRole} and {revokeRole}. By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means that only accounts with this role will be able to grant or revoke other roles. More complex role relationships can be created by using {_setRoleAdmin}. WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to grant and revoke this role. Extra precautions should be taken to secure accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules} to enforce additional security measures for this role.","errors":{"AccessControlBadConfirmation()":[{"details":"The caller of a function is not the expected one. NOTE: Don't confuse with {AccessControlUnauthorizedAccount}."}],"AccessControlUnauthorizedAccount(address,bytes32)":[{"details":"The `account` is missing a role."}]},"events":{"RoleAdminChanged(bytes32,bytes32,bytes32)":{"details":"Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole` `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite {RoleAdminChanged} not being emitted signaling this."},"RoleGranted(bytes32,address,address)":{"details":"Emitted when `account` is granted `role`. `sender` is the account that originated the contract call, an admin role bearer except when using {AccessControl-_setupRole}."},"RoleRevoked(bytes32,address,address)":{"details":"Emitted when `account` is revoked `role`. `sender` is the account that originated the contract call: - if using `revokeRole`, it is the admin role bearer - if using `renounceRole`, it is the role bearer (i.e. `account`)"}},"kind":"dev","methods":{"getRoleAdmin(bytes32)":{"details":"Returns the admin role that controls `role`. See {grantRole} and {revokeRole}. To change a role's admin, use {_setRoleAdmin}."},"grantRole(bytes32,address)":{"details":"Grants `role` to `account`. If `account` had not been already granted `role`, emits a {RoleGranted} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleGranted} event."},"hasRole(bytes32,address)":{"details":"Returns `true` if `account` has been granted `role`."},"renounceRole(bytes32,address)":{"details":"Revokes `role` from the calling account. Roles are often managed via {grantRole} and {revokeRole}: this function's purpose is to provide a mechanism for accounts to lose their privileges if they are compromised (such as when a trusted device is misplaced). If the calling account had been revoked `role`, emits a {RoleRevoked} event. Requirements: - the caller must be `callerConfirmation`. May emit a {RoleRevoked} event."},"revokeRole(bytes32,address)":{"details":"Revokes `role` from `account`. If `account` had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleRevoked} event."},"supportsInterface(bytes4)":{"details":"See {IERC165-supportsInterface}."}},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[],\"name\":\"AccessControlBadConfirmation\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"neededRole\",\"type\":\"bytes32\"}],\"name\":\"AccessControlUnauthorizedAccount\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"previousAdminRole\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"newAdminRole\",\"type\":\"bytes32\"}],\"name\":\"RoleAdminChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleGranted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleRevoked\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"DEFAULT_ADMIN_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"}],\"name\":\"getRoleAdmin\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"grantRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"hasRole\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"callerConfirmation\",\"type\":\"address\"}],\"name\":\"renounceRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"revokeRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes4\",\"name\":\"interfaceId\",\"type\":\"bytes4\"}],\"name\":\"supportsInterface\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"}],\"devdoc\":{\"details\":\"Contract module that allows children to implement role-based access control mechanisms. This is a lightweight version that doesn't allow enumerating role members except through off-chain means by accessing the contract event logs. Some applications may benefit from on-chain enumerability, for those cases see {AccessControlEnumerable}. Roles are referred to by their `bytes32` identifier. These should be exposed in the external API and be unique. The best way to achieve this is by using `public constant` hash digests: ```solidity bytes32 public constant MY_ROLE = keccak256(\\\"MY_ROLE\\\"); ``` Roles can be used to represent a set of permissions. To restrict access to a function call, use {hasRole}: ```solidity function foo() public { require(hasRole(MY_ROLE, msg.sender)); ... } ``` Roles can be granted and revoked dynamically via the {grantRole} and {revokeRole} functions. Each role has an associated admin role, and only accounts that have a role's admin role can call {grantRole} and {revokeRole}. By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means that only accounts with this role will be able to grant or revoke other roles. More complex role relationships can be created by using {_setRoleAdmin}. WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to grant and revoke this role. Extra precautions should be taken to secure accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules} to enforce additional security measures for this role.\",\"errors\":{\"AccessControlBadConfirmation()\":[{\"details\":\"The caller of a function is not the expected one. NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\"}],\"AccessControlUnauthorizedAccount(address,bytes32)\":[{\"details\":\"The `account` is missing a role.\"}]},\"events\":{\"RoleAdminChanged(bytes32,bytes32,bytes32)\":{\"details\":\"Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole` `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite {RoleAdminChanged} not being emitted signaling this.\"},\"RoleGranted(bytes32,address,address)\":{\"details\":\"Emitted when `account` is granted `role`. `sender` is the account that originated the contract call, an admin role bearer except when using {AccessControl-_setupRole}.\"},\"RoleRevoked(bytes32,address,address)\":{\"details\":\"Emitted when `account` is revoked `role`. `sender` is the account that originated the contract call: - if using `revokeRole`, it is the admin role bearer - if using `renounceRole`, it is the role bearer (i.e. `account`)\"}},\"kind\":\"dev\",\"methods\":{\"getRoleAdmin(bytes32)\":{\"details\":\"Returns the admin role that controls `role`. See {grantRole} and {revokeRole}. To change a role's admin, use {_setRoleAdmin}.\"},\"grantRole(bytes32,address)\":{\"details\":\"Grants `role` to `account`. If `account` had not been already granted `role`, emits a {RoleGranted} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleGranted} event.\"},\"hasRole(bytes32,address)\":{\"details\":\"Returns `true` if `account` has been granted `role`.\"},\"renounceRole(bytes32,address)\":{\"details\":\"Revokes `role` from the calling account. Roles are often managed via {grantRole} and {revokeRole}: this function's purpose is to provide a mechanism for accounts to lose their privileges if they are compromised (such as when a trusted device is misplaced). If the calling account had been revoked `role`, emits a {RoleRevoked} event. Requirements: - the caller must be `callerConfirmation`. May emit a {RoleRevoked} event.\"},\"revokeRole(bytes32,address)\":{\"details\":\"Revokes `role` from `account`. If `account` had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleRevoked} event.\"},\"supportsInterface(bytes4)\":{\"details\":\"See {IERC165-supportsInterface}.\"}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeV2.sol\":\"AccessControl\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeV2.sol\":{\"keccak256\":\"0x7cd0f885e80e2bdaa638bc32ae7af7d2e248f99ce4b354c217d0f0f7d7302e0a\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://7ccf28df0bd7b4606986585acd8622ed9b4e81379690061bb66088f0a2270af1\",\"dweb:/ipfs/QmTf7HNdHZkK6vmx8ZgewycQEb72oLD9nPwBpsM5reMstQ\"]}},\"version\":1}"},"hashes":{"DEFAULT_ADMIN_ROLE()":"a217fddf","getRoleAdmin(bytes32)":"248a9ca3","grantRole(bytes32,address)":"2f2ff15d","hasRole(bytes32,address)":"91d14854","renounceRole(bytes32,address)":"36568abe","revokeRole(bytes32,address)":"d547741f","supportsInterface(bytes4)":"01ffc9a7"}},"solidity/FastBridgeV2.sol:AccessControlEnumerable":{"code":"0x","runtime-code":"0x","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.24 ^0.8.0 ^0.8.20;\n\n// contracts/interfaces/IAdmin.sol\n\ninterface IAdmin {\n // ============ Events ============\n\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n event ChainGasAmountUpdated(uint256 oldChainGasAmount, uint256 newChainGasAmount);\n\n // ============ Methods ============\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n\n function setChainGasAmount(uint256 newChainGasAmount) external;\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IFastBridgeRecipient.sol\n\ninterface IFastBridgeRecipient {\n function fastBridgeTransferReceived(\n address token,\n uint256 amount,\n bytes memory callParams\n )\n external\n payable\n returns (bytes4);\n}\n\n// contracts/interfaces/IFastBridgeV2Errors.sol\n\ninterface IFastBridgeV2Errors {\n error AmountIncorrect();\n error CallParamsLengthAboveMax();\n error ChainIncorrect();\n error ExclusivityParamsIncorrect();\n error MsgValueIncorrect();\n error NativeTokenCallValueNotSupported();\n error SenderIncorrect();\n error StatusIncorrect();\n error ZeroAddress();\n\n error RecipientIncorrectReturnValue();\n error RecipientNoReturnValue();\n\n error DeadlineExceeded();\n error DeadlineNotExceeded();\n error DeadlineTooShort();\n error DisputePeriodNotPassed();\n error DisputePeriodPassed();\n error ExclusivityPeriodNotPassed();\n\n error TransactionRelayed();\n}\n\n// contracts/libs/Errors.sol\n\nerror DeadlineExceeded();\nerror DeadlineNotExceeded();\nerror DeadlineTooShort();\nerror InsufficientOutputAmount();\n\nerror MsgValueIncorrect();\nerror PoolNotFound();\nerror TokenAddressMismatch();\nerror TokenNotContract();\nerror TokenNotETH();\nerror TokensIdentical();\n\nerror ChainIncorrect();\nerror AmountIncorrect();\nerror ZeroAddress();\n\nerror DisputePeriodNotPassed();\nerror DisputePeriodPassed();\nerror SenderIncorrect();\nerror StatusIncorrect();\nerror TransactionIdIncorrect();\nerror TransactionRelayed();\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// contracts/interfaces/IFastBridgeV2.sol\n\ninterface IFastBridgeV2 is IFastBridge {\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n struct BridgeTxDetails {\n BridgeStatus status;\n uint40 proofBlockTimestamp;\n uint48 proofBlockNumber;\n address proofRelayer;\n }\n\n struct BridgeRelay {\n uint48 blockNumber;\n uint48 blockTimestamp;\n address relayer;\n }\n\n /// @notice New params introduced in the FastBridgeV2.\n /// We are passing fields from the older BridgeParams struct outside of this struct\n /// for backwards compatibility.\n /// Note: quoteRelayer and quoteExclusivitySeconds are either both zero (indicating no exclusivity)\n /// or both non-zero (indicating exclusivity for the given period).\n /// Note: callValue \u003e 0 can NOT be used with destToken = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE (ETH_ADDRESS)\n /// @param quoteRelayer Relayer that provided the quote for the transaction\n /// @param quoteExclusivitySeconds Period of time the quote relayer is guaranteed exclusivity after user's deposit\n /// @param quoteId Unique quote identifier used for tracking the quote\n /// @param callValue ETH value to send to the recipient (if any)\n /// @param callParams Parameters for the arbitrary call to the destination recipient (if any)\n struct BridgeParamsV2 {\n address quoteRelayer;\n int256 quoteExclusivitySeconds;\n bytes quoteId;\n uint256 callValue;\n bytes callParams;\n }\n\n /// @notice Updated bridge transaction struct to include parameters introduced in FastBridgeV2.\n /// Note: only `exclusivityRelayer` can fill such a transaction until `exclusivityEndTime`.\n /// TODO: consider changing the encoding scheme to prevent spending extra gas on decoding.\n struct BridgeTransactionV2 {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n uint256 callValue; // ETH value to send to the recipient (if any) - replaces V1's sendChainGas flag\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n address exclusivityRelayer;\n uint256 exclusivityEndTime;\n bytes callParams;\n }\n\n event BridgeQuoteDetails(bytes32 indexed transactionId, bytes quoteId);\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability\n /// to provide temporary exclusivity fill rights for the quote relayer.\n /// @param params The parameters required to bridge\n /// @param paramsV2 The parameters for exclusivity fill rights (optional, can be left empty)\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function relay(bytes memory request, address relayer) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param transactionId The transaction id associated with the encoded bridge transaction to prove\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital.\n /// @notice Can only send funds to the relayer address on the proof.\n /// @param request The encoded bridge transaction to claim on origin chain\n function claim(bytes memory request) external;\n /// @notice Checks if a transaction has been relayed\n /// @param transactionId The ID of the transaction to check\n /// @return True if the transaction has been relayed, false otherwise\n function bridgeRelays(bytes32 transactionId) external view returns (bool);\n\n /// @notice Returns the status of a bridge transaction\n /// @param transactionId The ID of the bridge transaction\n /// @return BridgeStatus Status of the bridge transaction\n function bridgeStatuses(bytes32 transactionId) external view returns (BridgeStatus);\n\n /// @notice Returns the timestamp and relayer of a bridge proof\n /// @param transactionId The ID of the bridge transaction\n /// @return timestamp The timestamp of the bridge proof\n /// @return relayer The relayer address of the bridge proof\n function bridgeProofs(bytes32 transactionId) external view returns (uint96 timestamp, address relayer);\n\n /// @notice Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\n /// @param request The bridge request to decode\n function getBridgeTransactionV2(bytes memory request) external view returns (BridgeTransactionV2 memory);\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// contracts/libs/UniversalToken.sol\n\nlibrary UniversalTokenLib {\n using SafeERC20 for IERC20;\n\n address internal constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Transfers tokens to the given account. Reverts if transfer is not successful.\n /// @dev This might trigger fallback, if ETH is transferred to the contract.\n /// Make sure this can not lead to reentrancy attacks.\n function universalTransfer(address token, address to, uint256 value) internal {\n // Don't do anything, if need to send tokens to this address\n if (to == address(this)) return;\n // Don't do anything, if trying to send zero value\n if (value == 0) return;\n if (token == ETH_ADDRESS) {\n /// @dev Note: this can potentially lead to executing code in `to`.\n // solhint-disable-next-line avoid-low-level-calls\n (bool success,) = to.call{value: value}(\"\");\n require(success, \"ETH transfer failed\");\n } else {\n IERC20(token).safeTransfer(to, value);\n }\n }\n\n /// @notice Issues an infinite allowance to the spender, if the current allowance is insufficient\n /// to spend the given amount.\n function universalApproveInfinity(address token, address spender, uint256 amountToSpend) internal {\n // ETH Chad doesn't require your approval\n if (token == ETH_ADDRESS) return;\n // No-op if allowance is already sufficient\n uint256 allowance = IERC20(token).allowance(address(this), spender);\n if (allowance \u003e= amountToSpend) return;\n // Otherwise, reset approval to 0 and set to max allowance\n if (allowance \u003e 0) IERC20(token).safeDecreaseAllowance(spender, allowance);\n IERC20(token).safeIncreaseAllowance(spender, type(uint256).max);\n }\n\n /// @notice Returns the balance of the given token (or native ETH) for the given account.\n function universalBalanceOf(address token, address account) internal view returns (uint256) {\n if (token == ETH_ADDRESS) {\n return account.balance;\n } else {\n return IERC20(token).balanceOf(account);\n }\n }\n\n /// @dev Checks that token is a contract and not ETH_ADDRESS.\n function assertIsContract(address token) internal view {\n // Check that ETH_ADDRESS was not used (in case this is a predeploy on any of the chains)\n if (token == UniversalTokenLib.ETH_ADDRESS) revert TokenNotContract();\n // Check that token is not an EOA\n if (token.code.length == 0) revert TokenNotContract();\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/Admin.sol\n\ncontract Admin is IAdmin, AccessControlEnumerable {\n using UniversalTokenLib for address;\n\n bytes32 public constant RELAYER_ROLE = keccak256(\"RELAYER_ROLE\");\n bytes32 public constant REFUNDER_ROLE = keccak256(\"REFUNDER_ROLE\");\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n uint256 public constant FEE_BPS = 1e6;\n uint256 public constant FEE_RATE_MAX = 0.01e6; // max 1% on origin amount\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Chain gas amount to forward as rebate if requested\n uint256 public chainGasAmount;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n }\n\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n require(newFeeRate \u003c= FEE_RATE_MAX, \"newFeeRate \u003e max\");\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n token.universalTransfer(recipient, feeAmount);\n emit FeesSwept(token, recipient, feeAmount);\n }\n\n function setChainGasAmount(uint256 newChainGasAmount) external onlyRole(GOVERNOR_ROLE) {\n uint256 oldChainGasAmount = chainGasAmount;\n chainGasAmount = newChainGasAmount;\n emit ChainGasAmountUpdated(oldChainGasAmount, newChainGasAmount);\n }\n}\n\n// contracts/FastBridgeV2.sol\n\n/// @notice FastBridgeV2 is a contract for bridging tokens across chains.\ncontract FastBridgeV2 is Admin, IFastBridgeV2, IFastBridgeV2Errors {\n using SafeERC20 for IERC20;\n using UniversalTokenLib for address;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Delay for a transaction after which it could be permisionlessly refunded\n uint256 public constant REFUND_DELAY = 7 days;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n /// @notice Maximum length of accepted callParams\n uint256 public constant MAX_CALL_PARAMS_LENGTH = 2 ** 16 - 1;\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeTxDetails) public bridgeTxDetails;\n /// @notice Relay details on destination chain\n mapping(bytes32 =\u003e BridgeRelay) public bridgeRelayDetails;\n /// @notice Unique bridge nonces tracked per originSender\n mapping(address =\u003e uint256) public senderNonces;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Replaced by senderNonces\n uint256 public immutable nonce = 0;\n /// @notice the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n bridge({\n params: params,\n paramsV2: BridgeParamsV2({\n quoteRelayer: address(0),\n quoteExclusivitySeconds: 0,\n quoteId: bytes(\"\"),\n callValue: 0,\n callParams: bytes(\"\")\n })\n });\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes memory request) external payable {\n relay({request: request, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes memory request, bytes32 destTxHash) external {\n prove({transactionId: keccak256(request), destTxHash: destTxHash, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridgeV2\n function claim(bytes memory request) external {\n claim({request: request, to: address(0)});\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003e DISPUTE_PERIOD) {\n revert DisputePeriodPassed();\n }\n\n // @dev relayer gets slashed effectively if dest relay has gone thru\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n bridgeTxDetails[transactionId].proofRelayer = address(0);\n bridgeTxDetails[transactionId].proofBlockTimestamp = 0;\n bridgeTxDetails[transactionId].proofBlockNumber = 0;\n\n emit BridgeProofDisputed(transactionId, msg.sender);\n }\n\n /// @inheritdoc IFastBridge\n function refund(bytes memory request) external {\n bytes32 transactionId = keccak256(request);\n\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n\n if (bridgeTxDetails[transactionId].status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n\n if (hasRole(REFUNDER_ROLE, msg.sender)) {\n // Refunder can refund if deadline has passed\n if (block.timestamp \u003c= transaction.deadline) revert DeadlineNotExceeded();\n } else {\n // Permissionless refund is allowed after REFUND_DELAY\n if (block.timestamp \u003c= transaction.deadline + REFUND_DELAY) revert DeadlineNotExceeded();\n }\n\n // if all checks passed, set to REFUNDED status\n bridgeTxDetails[transactionId].status = BridgeStatus.REFUNDED;\n\n // transfer origin collateral back to original sender\n address to = transaction.originSender;\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount + transaction.originFeeAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (bridgeTxDetails[transactionId].proofRelayer != relayer) revert SenderIncorrect();\n return _timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n /// @dev This method is added to achieve backwards compatibility with decoding requests into V1 structs:\n /// - `callValue` is partially reported as a zero/non-zero flag\n /// - `callParams` is ignored\n /// In order to process all kinds of requests use getBridgeTransactionV2 instead.\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory) {\n // Try decoding into V2 struct first. This will revert if V1 struct is passed\n try this.getBridgeTransactionV2(request) returns (BridgeTransactionV2 memory txV2) {\n // Note: we entirely ignore the callParams field, as it was not present in V1\n return BridgeTransaction({\n originChainId: txV2.originChainId,\n destChainId: txV2.destChainId,\n originSender: txV2.originSender,\n destRecipient: txV2.destRecipient,\n originToken: txV2.originToken,\n destToken: txV2.destToken,\n originAmount: txV2.originAmount,\n destAmount: txV2.destAmount,\n originFeeAmount: txV2.originFeeAmount,\n sendChainGas: txV2.callValue != 0,\n deadline: txV2.deadline,\n nonce: txV2.nonce\n });\n } catch {\n // Fallback to V1 struct\n return abi.decode(request, (BridgeTransaction));\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) public payable {\n int256 exclusivityEndTime = int256(block.timestamp) + paramsV2.quoteExclusivitySeconds;\n _validateBridgeParams(params, paramsV2, exclusivityEndTime);\n\n // transfer tokens to bridge contract\n /// @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _pullToken(params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n\n // set status to requested\n bytes memory request = abi.encode(\n BridgeTransactionV2({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n callValue: paramsV2.callValue,\n deadline: params.deadline,\n nonce: senderNonces[params.sender]++, // increment nonce on every bridge\n exclusivityRelayer: paramsV2.quoteRelayer,\n // We checked exclusivityEndTime to be in range (0 .. params.deadline] above, so can safely cast\n exclusivityEndTime: uint256(exclusivityEndTime),\n callParams: paramsV2.callParams\n })\n );\n bytes32 transactionId = keccak256(request);\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n\n emit BridgeRequested({\n transactionId: transactionId,\n sender: params.sender,\n request: request,\n destChainId: params.dstChainId,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n sendChainGas: paramsV2.callValue != 0\n });\n emit BridgeQuoteDetails(transactionId, paramsV2.quoteId);\n }\n\n /// @inheritdoc IFastBridgeV2\n function relay(bytes memory request, address relayer) public payable {\n bytes32 transactionId = keccak256(request);\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n _validateRelayParams(transaction, transactionId, relayer);\n // mark bridge transaction as relayed\n bridgeRelayDetails[transactionId] =\n BridgeRelay({blockNumber: uint48(block.number), blockTimestamp: uint48(block.timestamp), relayer: relayer});\n\n // transfer tokens to recipient on destination chain and do an arbitrary call if requested\n address to = transaction.destRecipient;\n address token = transaction.destToken;\n uint256 amount = transaction.destAmount;\n\n // All state changes have been done at this point, can proceed to the external calls.\n // This follows the checks-effects-interactions pattern to mitigate potential reentrancy attacks.\n if (token == UniversalTokenLib.ETH_ADDRESS) {\n // For ETH non-zero callValue is not allowed\n if (transaction.callValue != 0) revert NativeTokenCallValueNotSupported();\n // Check that the correct msg.value was sent\n if (msg.value != amount) revert MsgValueIncorrect();\n } else {\n // For ERC20s, we check that the correct msg.value was sent\n if (msg.value != transaction.callValue) revert MsgValueIncorrect();\n // We need to transfer the tokens from the Relayer to the recipient first before performing an\n // optional post-transfer arbitrary call.\n IERC20(token).safeTransferFrom(msg.sender, to, amount);\n }\n\n if (transaction.callParams.length != 0) {\n // Arbitrary call requested, perform it while supplying full msg.value to the recipient\n // Note: if token has a fee on transfers, the recipient will have received less than `amount`.\n // This is a very niche edge case and should be handled by the recipient contract.\n _checkedCallRecipient({recipient: to, token: token, amount: amount, callParams: transaction.callParams});\n } else if (msg.value != 0) {\n // No arbitrary call requested, but msg.value was sent. This is either a relay with ETH,\n // or a non-zero callValue request with an ERC20. In both cases, transfer the ETH to the recipient.\n Address.sendValue(payable(to), msg.value);\n }\n\n emit BridgeRelayed({\n transactionId: transactionId,\n relayer: relayer,\n to: to,\n originChainId: transaction.originChainId,\n originToken: transaction.originToken,\n destToken: transaction.destToken,\n originAmount: transaction.originAmount,\n destAmount: transaction.destAmount,\n chainGasAmount: transaction.callValue\n });\n }\n\n /// @inheritdoc IFastBridgeV2\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) public onlyRole(RELAYER_ROLE) {\n // update bridge tx status given proof provided\n if (bridgeTxDetails[transactionId].status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n bridgeTxDetails[transactionId].status = BridgeStatus.RELAYER_PROVED;\n bridgeTxDetails[transactionId].proofBlockTimestamp = uint40(block.timestamp);\n bridgeTxDetails[transactionId].proofBlockNumber = uint48(block.number);\n bridgeTxDetails[transactionId].proofRelayer = relayer;\n\n emit BridgeProofProvided(transactionId, relayer, destTxHash);\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes memory request, address to) public {\n bytes32 transactionId = keccak256(request);\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n\n // update bridge tx status if able to claim origin collateral\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n\n // if \"to\" is zero addr, permissionlessly send funds to proven relayer\n if (to == address(0)) {\n to = bridgeTxDetails[transactionId].proofRelayer;\n } else if (bridgeTxDetails[transactionId].proofRelayer != msg.sender) {\n revert SenderIncorrect();\n }\n\n if (_timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003c= DISPUTE_PERIOD) {\n revert DisputePeriodNotPassed();\n }\n\n bridgeTxDetails[transactionId].status = BridgeStatus.RELAYER_CLAIMED;\n\n // update protocol fees if origin fee amount exists\n if (transaction.originFeeAmount \u003e 0) protocolFees[transaction.originToken] += transaction.originFeeAmount;\n\n // transfer origin collateral less fee to specified address\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositClaimed(transactionId, bridgeTxDetails[transactionId].proofRelayer, to, token, amount);\n }\n\n function bridgeStatuses(bytes32 transactionId) public view returns (BridgeStatus status) {\n return bridgeTxDetails[transactionId].status;\n }\n\n function bridgeProofs(bytes32 transactionId) public view returns (uint96 timestamp, address relayer) {\n timestamp = bridgeTxDetails[transactionId].proofBlockTimestamp;\n relayer = bridgeTxDetails[transactionId].proofRelayer;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeRelays(bytes32 transactionId) public view returns (bool) {\n // has this transactionId been relayed?\n return bridgeRelayDetails[transactionId].relayer != address(0);\n }\n\n /// @inheritdoc IFastBridgeV2\n function getBridgeTransactionV2(bytes memory request) public pure returns (BridgeTransactionV2 memory) {\n return abi.decode(request, (BridgeTransactionV2));\n }\n\n /// @notice Pulls a requested token from the user to this contract.\n function _pullToken(address token, uint256 amount) internal returns (uint256 amountPulled) {\n if (token == UniversalTokenLib.ETH_ADDRESS) {\n // For ETH we just need to check that the supplied msg.value is correct\n if (amount != msg.value) revert MsgValueIncorrect();\n amountPulled = msg.value;\n } else {\n token.assertIsContract();\n // Record token balance before transfer\n amountPulled = IERC20(token).balanceOf(address(this));\n // Token needs to be pulled only if msg.value is zero\n // This way user can specify WETH as the origin asset\n IERC20(token).safeTransferFrom(msg.sender, address(this), amount);\n // Use the difference between the recorded balance and the current balance as the amountPulled\n amountPulled = IERC20(token).balanceOf(address(this)) - amountPulled;\n }\n }\n\n /// @notice Calls the Recipient's hook function with the specified callParams and performs\n /// all the necessary checks for the returned value.\n function _checkedCallRecipient(\n address recipient,\n address token,\n uint256 amount,\n bytes memory callParams\n )\n internal\n {\n bytes memory hookData =\n abi.encodeCall(IFastBridgeRecipient.fastBridgeTransferReceived, (token, amount, callParams));\n // This will bubble any revert messages from the hook function\n bytes memory returnData = Address.functionCallWithValue({target: recipient, data: hookData, value: msg.value});\n // Explicit revert if no return data at all\n if (returnData.length == 0) revert RecipientNoReturnValue();\n // Check that exactly a single return value was returned\n if (returnData.length != 32) revert RecipientIncorrectReturnValue();\n // Return value should be abi-encoded hook function selector\n if (bytes32(returnData) != bytes32(IFastBridgeRecipient.fastBridgeTransferReceived.selector)) {\n revert RecipientIncorrectReturnValue();\n }\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint40(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint40).max but\n /// proof.timestamp \u003c type(uint40).max via unchecked statement\n /// @param proofBlockTimestamp The bridge proof block timestamp\n /// @return delta Time delta since proof submitted\n function _timeSince(uint40 proofBlockTimestamp) internal view returns (uint256 delta) {\n unchecked {\n delta = uint40(block.timestamp) - proofBlockTimestamp;\n }\n }\n\n /// @notice Performs all the necessary checks for a bridge to happen.\n /// @dev There's no good way to refactor this function to reduce cyclomatic complexity due to\n /// the number of checks that need to be performed, so we skip the code-complexity rule here.\n // solhint-disable-next-line code-complexity\n function _validateBridgeParams(\n BridgeParams memory params,\n BridgeParamsV2 memory paramsV2,\n int256 exclusivityEndTime\n )\n internal\n view\n {\n // Check V1 (legacy) params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.sender == address(0) || params.to == address(0)) revert ZeroAddress();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n // Check V2 params\n if (paramsV2.callParams.length \u003e MAX_CALL_PARAMS_LENGTH) revert CallParamsLengthAboveMax();\n if (paramsV2.callValue != 0 \u0026\u0026 params.destToken == UniversalTokenLib.ETH_ADDRESS) {\n revert NativeTokenCallValueNotSupported();\n }\n // exclusivityEndTime must be in range (0 .. params.deadline]\n if (exclusivityEndTime \u003c= 0 || exclusivityEndTime \u003e int256(params.deadline)) {\n revert ExclusivityParamsIncorrect();\n }\n }\n\n /// @notice Performs all the necessary checks for a relay to happen.\n function _validateRelayParams(\n BridgeTransactionV2 memory transaction,\n bytes32 transactionId,\n address relayer\n )\n internal\n view\n {\n if (relayer == address(0)) revert ZeroAddress();\n // Check if the transaction has already been relayed\n if (bridgeRelays(transactionId)) revert TransactionRelayed();\n if (transaction.destChainId != uint32(block.chainid)) revert ChainIncorrect();\n // Check the deadline for relay to happen\n if (block.timestamp \u003e transaction.deadline) revert DeadlineExceeded();\n // Check the exclusivity period, if it is still ongoing\n // forgefmt: disable-next-item\n if (\n transaction.exclusivityRelayer != address(0) \u0026\u0026\n transaction.exclusivityRelayer != relayer \u0026\u0026\n block.timestamp \u003c= transaction.exclusivityEndTime\n ) {\n revert ExclusivityPeriodNotPassed();\n }\n }\n}\n","language":"Solidity","languageVersion":"0.8.24","compilerVersion":"0.8.24","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"","srcMapRuntime":"","abiDefinition":[{"inputs":[],"name":"AccessControlBadConfirmation","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"bytes32","name":"neededRole","type":"bytes32"}],"name":"AccessControlUnauthorizedAccount","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"previousAdminRole","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"newAdminRole","type":"bytes32"}],"name":"RoleAdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleRevoked","type":"event"},{"inputs":[],"name":"DEFAULT_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleAdmin","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"uint256","name":"index","type":"uint256"}],"name":"getRoleMember","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleMemberCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"grantRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"hasRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"callerConfirmation","type":"address"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"revokeRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"}],"userDoc":{"kind":"user","methods":{},"version":1},"developerDoc":{"details":"Extension of {AccessControl} that allows enumerating the members of each role.","errors":{"AccessControlBadConfirmation()":[{"details":"The caller of a function is not the expected one. NOTE: Don't confuse with {AccessControlUnauthorizedAccount}."}],"AccessControlUnauthorizedAccount(address,bytes32)":[{"details":"The `account` is missing a role."}]},"events":{"RoleAdminChanged(bytes32,bytes32,bytes32)":{"details":"Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole` `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite {RoleAdminChanged} not being emitted signaling this."},"RoleGranted(bytes32,address,address)":{"details":"Emitted when `account` is granted `role`. `sender` is the account that originated the contract call, an admin role bearer except when using {AccessControl-_setupRole}."},"RoleRevoked(bytes32,address,address)":{"details":"Emitted when `account` is revoked `role`. `sender` is the account that originated the contract call: - if using `revokeRole`, it is the admin role bearer - if using `renounceRole`, it is the role bearer (i.e. `account`)"}},"kind":"dev","methods":{"getRoleAdmin(bytes32)":{"details":"Returns the admin role that controls `role`. See {grantRole} and {revokeRole}. To change a role's admin, use {_setRoleAdmin}."},"getRoleMember(bytes32,uint256)":{"details":"Returns one of the accounts that have `role`. `index` must be a value between 0 and {getRoleMemberCount}, non-inclusive. Role bearers are not sorted in any particular way, and their ordering may change at any point. WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure you perform all queries on the same block. See the following https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post] for more information."},"getRoleMemberCount(bytes32)":{"details":"Returns the number of accounts that have `role`. Can be used together with {getRoleMember} to enumerate all bearers of a role."},"grantRole(bytes32,address)":{"details":"Grants `role` to `account`. If `account` had not been already granted `role`, emits a {RoleGranted} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleGranted} event."},"hasRole(bytes32,address)":{"details":"Returns `true` if `account` has been granted `role`."},"renounceRole(bytes32,address)":{"details":"Revokes `role` from the calling account. Roles are often managed via {grantRole} and {revokeRole}: this function's purpose is to provide a mechanism for accounts to lose their privileges if they are compromised (such as when a trusted device is misplaced). If the calling account had been revoked `role`, emits a {RoleRevoked} event. Requirements: - the caller must be `callerConfirmation`. May emit a {RoleRevoked} event."},"revokeRole(bytes32,address)":{"details":"Revokes `role` from `account`. If `account` had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleRevoked} event."},"supportsInterface(bytes4)":{"details":"See {IERC165-supportsInterface}."}},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[],\"name\":\"AccessControlBadConfirmation\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"neededRole\",\"type\":\"bytes32\"}],\"name\":\"AccessControlUnauthorizedAccount\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"previousAdminRole\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"newAdminRole\",\"type\":\"bytes32\"}],\"name\":\"RoleAdminChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleGranted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleRevoked\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"DEFAULT_ADMIN_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"}],\"name\":\"getRoleAdmin\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"index\",\"type\":\"uint256\"}],\"name\":\"getRoleMember\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"}],\"name\":\"getRoleMemberCount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"grantRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"hasRole\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"callerConfirmation\",\"type\":\"address\"}],\"name\":\"renounceRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"revokeRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes4\",\"name\":\"interfaceId\",\"type\":\"bytes4\"}],\"name\":\"supportsInterface\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"}],\"devdoc\":{\"details\":\"Extension of {AccessControl} that allows enumerating the members of each role.\",\"errors\":{\"AccessControlBadConfirmation()\":[{\"details\":\"The caller of a function is not the expected one. NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\"}],\"AccessControlUnauthorizedAccount(address,bytes32)\":[{\"details\":\"The `account` is missing a role.\"}]},\"events\":{\"RoleAdminChanged(bytes32,bytes32,bytes32)\":{\"details\":\"Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole` `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite {RoleAdminChanged} not being emitted signaling this.\"},\"RoleGranted(bytes32,address,address)\":{\"details\":\"Emitted when `account` is granted `role`. `sender` is the account that originated the contract call, an admin role bearer except when using {AccessControl-_setupRole}.\"},\"RoleRevoked(bytes32,address,address)\":{\"details\":\"Emitted when `account` is revoked `role`. `sender` is the account that originated the contract call: - if using `revokeRole`, it is the admin role bearer - if using `renounceRole`, it is the role bearer (i.e. `account`)\"}},\"kind\":\"dev\",\"methods\":{\"getRoleAdmin(bytes32)\":{\"details\":\"Returns the admin role that controls `role`. See {grantRole} and {revokeRole}. To change a role's admin, use {_setRoleAdmin}.\"},\"getRoleMember(bytes32,uint256)\":{\"details\":\"Returns one of the accounts that have `role`. `index` must be a value between 0 and {getRoleMemberCount}, non-inclusive. Role bearers are not sorted in any particular way, and their ordering may change at any point. WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure you perform all queries on the same block. See the following https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post] for more information.\"},\"getRoleMemberCount(bytes32)\":{\"details\":\"Returns the number of accounts that have `role`. Can be used together with {getRoleMember} to enumerate all bearers of a role.\"},\"grantRole(bytes32,address)\":{\"details\":\"Grants `role` to `account`. If `account` had not been already granted `role`, emits a {RoleGranted} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleGranted} event.\"},\"hasRole(bytes32,address)\":{\"details\":\"Returns `true` if `account` has been granted `role`.\"},\"renounceRole(bytes32,address)\":{\"details\":\"Revokes `role` from the calling account. Roles are often managed via {grantRole} and {revokeRole}: this function's purpose is to provide a mechanism for accounts to lose their privileges if they are compromised (such as when a trusted device is misplaced). If the calling account had been revoked `role`, emits a {RoleRevoked} event. Requirements: - the caller must be `callerConfirmation`. May emit a {RoleRevoked} event.\"},\"revokeRole(bytes32,address)\":{\"details\":\"Revokes `role` from `account`. If `account` had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleRevoked} event.\"},\"supportsInterface(bytes4)\":{\"details\":\"See {IERC165-supportsInterface}.\"}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeV2.sol\":\"AccessControlEnumerable\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeV2.sol\":{\"keccak256\":\"0x7cd0f885e80e2bdaa638bc32ae7af7d2e248f99ce4b354c217d0f0f7d7302e0a\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://7ccf28df0bd7b4606986585acd8622ed9b4e81379690061bb66088f0a2270af1\",\"dweb:/ipfs/QmTf7HNdHZkK6vmx8ZgewycQEb72oLD9nPwBpsM5reMstQ\"]}},\"version\":1}"},"hashes":{"DEFAULT_ADMIN_ROLE()":"a217fddf","getRoleAdmin(bytes32)":"248a9ca3","getRoleMember(bytes32,uint256)":"9010d07c","getRoleMemberCount(bytes32)":"ca15c873","grantRole(bytes32,address)":"2f2ff15d","hasRole(bytes32,address)":"91d14854","renounceRole(bytes32,address)":"36568abe","revokeRole(bytes32,address)":"d547741f","supportsInterface(bytes4)":"01ffc9a7"}},"solidity/FastBridgeV2.sol:Address":{"code":"0x60566037600b82828239805160001a607314602a57634e487b7160e01b600052600060045260246000fd5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600080fdfea26469706673582212209373c953367c76b94c1908124544fbcf053f6653eb651760b4d42f0f487710d864736f6c63430008180033","runtime-code":"0x73000000000000000000000000000000000000000030146080604052600080fdfea26469706673582212209373c953367c76b94c1908124544fbcf053f6653eb651760b4d42f0f487710d864736f6c63430008180033","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.24 ^0.8.0 ^0.8.20;\n\n// contracts/interfaces/IAdmin.sol\n\ninterface IAdmin {\n // ============ Events ============\n\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n event ChainGasAmountUpdated(uint256 oldChainGasAmount, uint256 newChainGasAmount);\n\n // ============ Methods ============\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n\n function setChainGasAmount(uint256 newChainGasAmount) external;\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IFastBridgeRecipient.sol\n\ninterface IFastBridgeRecipient {\n function fastBridgeTransferReceived(\n address token,\n uint256 amount,\n bytes memory callParams\n )\n external\n payable\n returns (bytes4);\n}\n\n// contracts/interfaces/IFastBridgeV2Errors.sol\n\ninterface IFastBridgeV2Errors {\n error AmountIncorrect();\n error CallParamsLengthAboveMax();\n error ChainIncorrect();\n error ExclusivityParamsIncorrect();\n error MsgValueIncorrect();\n error NativeTokenCallValueNotSupported();\n error SenderIncorrect();\n error StatusIncorrect();\n error ZeroAddress();\n\n error RecipientIncorrectReturnValue();\n error RecipientNoReturnValue();\n\n error DeadlineExceeded();\n error DeadlineNotExceeded();\n error DeadlineTooShort();\n error DisputePeriodNotPassed();\n error DisputePeriodPassed();\n error ExclusivityPeriodNotPassed();\n\n error TransactionRelayed();\n}\n\n// contracts/libs/Errors.sol\n\nerror DeadlineExceeded();\nerror DeadlineNotExceeded();\nerror DeadlineTooShort();\nerror InsufficientOutputAmount();\n\nerror MsgValueIncorrect();\nerror PoolNotFound();\nerror TokenAddressMismatch();\nerror TokenNotContract();\nerror TokenNotETH();\nerror TokensIdentical();\n\nerror ChainIncorrect();\nerror AmountIncorrect();\nerror ZeroAddress();\n\nerror DisputePeriodNotPassed();\nerror DisputePeriodPassed();\nerror SenderIncorrect();\nerror StatusIncorrect();\nerror TransactionIdIncorrect();\nerror TransactionRelayed();\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// contracts/interfaces/IFastBridgeV2.sol\n\ninterface IFastBridgeV2 is IFastBridge {\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n struct BridgeTxDetails {\n BridgeStatus status;\n uint40 proofBlockTimestamp;\n uint48 proofBlockNumber;\n address proofRelayer;\n }\n\n struct BridgeRelay {\n uint48 blockNumber;\n uint48 blockTimestamp;\n address relayer;\n }\n\n /// @notice New params introduced in the FastBridgeV2.\n /// We are passing fields from the older BridgeParams struct outside of this struct\n /// for backwards compatibility.\n /// Note: quoteRelayer and quoteExclusivitySeconds are either both zero (indicating no exclusivity)\n /// or both non-zero (indicating exclusivity for the given period).\n /// Note: callValue \u003e 0 can NOT be used with destToken = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE (ETH_ADDRESS)\n /// @param quoteRelayer Relayer that provided the quote for the transaction\n /// @param quoteExclusivitySeconds Period of time the quote relayer is guaranteed exclusivity after user's deposit\n /// @param quoteId Unique quote identifier used for tracking the quote\n /// @param callValue ETH value to send to the recipient (if any)\n /// @param callParams Parameters for the arbitrary call to the destination recipient (if any)\n struct BridgeParamsV2 {\n address quoteRelayer;\n int256 quoteExclusivitySeconds;\n bytes quoteId;\n uint256 callValue;\n bytes callParams;\n }\n\n /// @notice Updated bridge transaction struct to include parameters introduced in FastBridgeV2.\n /// Note: only `exclusivityRelayer` can fill such a transaction until `exclusivityEndTime`.\n /// TODO: consider changing the encoding scheme to prevent spending extra gas on decoding.\n struct BridgeTransactionV2 {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n uint256 callValue; // ETH value to send to the recipient (if any) - replaces V1's sendChainGas flag\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n address exclusivityRelayer;\n uint256 exclusivityEndTime;\n bytes callParams;\n }\n\n event BridgeQuoteDetails(bytes32 indexed transactionId, bytes quoteId);\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability\n /// to provide temporary exclusivity fill rights for the quote relayer.\n /// @param params The parameters required to bridge\n /// @param paramsV2 The parameters for exclusivity fill rights (optional, can be left empty)\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function relay(bytes memory request, address relayer) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param transactionId The transaction id associated with the encoded bridge transaction to prove\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital.\n /// @notice Can only send funds to the relayer address on the proof.\n /// @param request The encoded bridge transaction to claim on origin chain\n function claim(bytes memory request) external;\n /// @notice Checks if a transaction has been relayed\n /// @param transactionId The ID of the transaction to check\n /// @return True if the transaction has been relayed, false otherwise\n function bridgeRelays(bytes32 transactionId) external view returns (bool);\n\n /// @notice Returns the status of a bridge transaction\n /// @param transactionId The ID of the bridge transaction\n /// @return BridgeStatus Status of the bridge transaction\n function bridgeStatuses(bytes32 transactionId) external view returns (BridgeStatus);\n\n /// @notice Returns the timestamp and relayer of a bridge proof\n /// @param transactionId The ID of the bridge transaction\n /// @return timestamp The timestamp of the bridge proof\n /// @return relayer The relayer address of the bridge proof\n function bridgeProofs(bytes32 transactionId) external view returns (uint96 timestamp, address relayer);\n\n /// @notice Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\n /// @param request The bridge request to decode\n function getBridgeTransactionV2(bytes memory request) external view returns (BridgeTransactionV2 memory);\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// contracts/libs/UniversalToken.sol\n\nlibrary UniversalTokenLib {\n using SafeERC20 for IERC20;\n\n address internal constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Transfers tokens to the given account. Reverts if transfer is not successful.\n /// @dev This might trigger fallback, if ETH is transferred to the contract.\n /// Make sure this can not lead to reentrancy attacks.\n function universalTransfer(address token, address to, uint256 value) internal {\n // Don't do anything, if need to send tokens to this address\n if (to == address(this)) return;\n // Don't do anything, if trying to send zero value\n if (value == 0) return;\n if (token == ETH_ADDRESS) {\n /// @dev Note: this can potentially lead to executing code in `to`.\n // solhint-disable-next-line avoid-low-level-calls\n (bool success,) = to.call{value: value}(\"\");\n require(success, \"ETH transfer failed\");\n } else {\n IERC20(token).safeTransfer(to, value);\n }\n }\n\n /// @notice Issues an infinite allowance to the spender, if the current allowance is insufficient\n /// to spend the given amount.\n function universalApproveInfinity(address token, address spender, uint256 amountToSpend) internal {\n // ETH Chad doesn't require your approval\n if (token == ETH_ADDRESS) return;\n // No-op if allowance is already sufficient\n uint256 allowance = IERC20(token).allowance(address(this), spender);\n if (allowance \u003e= amountToSpend) return;\n // Otherwise, reset approval to 0 and set to max allowance\n if (allowance \u003e 0) IERC20(token).safeDecreaseAllowance(spender, allowance);\n IERC20(token).safeIncreaseAllowance(spender, type(uint256).max);\n }\n\n /// @notice Returns the balance of the given token (or native ETH) for the given account.\n function universalBalanceOf(address token, address account) internal view returns (uint256) {\n if (token == ETH_ADDRESS) {\n return account.balance;\n } else {\n return IERC20(token).balanceOf(account);\n }\n }\n\n /// @dev Checks that token is a contract and not ETH_ADDRESS.\n function assertIsContract(address token) internal view {\n // Check that ETH_ADDRESS was not used (in case this is a predeploy on any of the chains)\n if (token == UniversalTokenLib.ETH_ADDRESS) revert TokenNotContract();\n // Check that token is not an EOA\n if (token.code.length == 0) revert TokenNotContract();\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/Admin.sol\n\ncontract Admin is IAdmin, AccessControlEnumerable {\n using UniversalTokenLib for address;\n\n bytes32 public constant RELAYER_ROLE = keccak256(\"RELAYER_ROLE\");\n bytes32 public constant REFUNDER_ROLE = keccak256(\"REFUNDER_ROLE\");\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n uint256 public constant FEE_BPS = 1e6;\n uint256 public constant FEE_RATE_MAX = 0.01e6; // max 1% on origin amount\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Chain gas amount to forward as rebate if requested\n uint256 public chainGasAmount;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n }\n\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n require(newFeeRate \u003c= FEE_RATE_MAX, \"newFeeRate \u003e max\");\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n token.universalTransfer(recipient, feeAmount);\n emit FeesSwept(token, recipient, feeAmount);\n }\n\n function setChainGasAmount(uint256 newChainGasAmount) external onlyRole(GOVERNOR_ROLE) {\n uint256 oldChainGasAmount = chainGasAmount;\n chainGasAmount = newChainGasAmount;\n emit ChainGasAmountUpdated(oldChainGasAmount, newChainGasAmount);\n }\n}\n\n// contracts/FastBridgeV2.sol\n\n/// @notice FastBridgeV2 is a contract for bridging tokens across chains.\ncontract FastBridgeV2 is Admin, IFastBridgeV2, IFastBridgeV2Errors {\n using SafeERC20 for IERC20;\n using UniversalTokenLib for address;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Delay for a transaction after which it could be permisionlessly refunded\n uint256 public constant REFUND_DELAY = 7 days;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n /// @notice Maximum length of accepted callParams\n uint256 public constant MAX_CALL_PARAMS_LENGTH = 2 ** 16 - 1;\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeTxDetails) public bridgeTxDetails;\n /// @notice Relay details on destination chain\n mapping(bytes32 =\u003e BridgeRelay) public bridgeRelayDetails;\n /// @notice Unique bridge nonces tracked per originSender\n mapping(address =\u003e uint256) public senderNonces;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Replaced by senderNonces\n uint256 public immutable nonce = 0;\n /// @notice the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n bridge({\n params: params,\n paramsV2: BridgeParamsV2({\n quoteRelayer: address(0),\n quoteExclusivitySeconds: 0,\n quoteId: bytes(\"\"),\n callValue: 0,\n callParams: bytes(\"\")\n })\n });\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes memory request) external payable {\n relay({request: request, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes memory request, bytes32 destTxHash) external {\n prove({transactionId: keccak256(request), destTxHash: destTxHash, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridgeV2\n function claim(bytes memory request) external {\n claim({request: request, to: address(0)});\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003e DISPUTE_PERIOD) {\n revert DisputePeriodPassed();\n }\n\n // @dev relayer gets slashed effectively if dest relay has gone thru\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n bridgeTxDetails[transactionId].proofRelayer = address(0);\n bridgeTxDetails[transactionId].proofBlockTimestamp = 0;\n bridgeTxDetails[transactionId].proofBlockNumber = 0;\n\n emit BridgeProofDisputed(transactionId, msg.sender);\n }\n\n /// @inheritdoc IFastBridge\n function refund(bytes memory request) external {\n bytes32 transactionId = keccak256(request);\n\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n\n if (bridgeTxDetails[transactionId].status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n\n if (hasRole(REFUNDER_ROLE, msg.sender)) {\n // Refunder can refund if deadline has passed\n if (block.timestamp \u003c= transaction.deadline) revert DeadlineNotExceeded();\n } else {\n // Permissionless refund is allowed after REFUND_DELAY\n if (block.timestamp \u003c= transaction.deadline + REFUND_DELAY) revert DeadlineNotExceeded();\n }\n\n // if all checks passed, set to REFUNDED status\n bridgeTxDetails[transactionId].status = BridgeStatus.REFUNDED;\n\n // transfer origin collateral back to original sender\n address to = transaction.originSender;\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount + transaction.originFeeAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (bridgeTxDetails[transactionId].proofRelayer != relayer) revert SenderIncorrect();\n return _timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n /// @dev This method is added to achieve backwards compatibility with decoding requests into V1 structs:\n /// - `callValue` is partially reported as a zero/non-zero flag\n /// - `callParams` is ignored\n /// In order to process all kinds of requests use getBridgeTransactionV2 instead.\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory) {\n // Try decoding into V2 struct first. This will revert if V1 struct is passed\n try this.getBridgeTransactionV2(request) returns (BridgeTransactionV2 memory txV2) {\n // Note: we entirely ignore the callParams field, as it was not present in V1\n return BridgeTransaction({\n originChainId: txV2.originChainId,\n destChainId: txV2.destChainId,\n originSender: txV2.originSender,\n destRecipient: txV2.destRecipient,\n originToken: txV2.originToken,\n destToken: txV2.destToken,\n originAmount: txV2.originAmount,\n destAmount: txV2.destAmount,\n originFeeAmount: txV2.originFeeAmount,\n sendChainGas: txV2.callValue != 0,\n deadline: txV2.deadline,\n nonce: txV2.nonce\n });\n } catch {\n // Fallback to V1 struct\n return abi.decode(request, (BridgeTransaction));\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) public payable {\n int256 exclusivityEndTime = int256(block.timestamp) + paramsV2.quoteExclusivitySeconds;\n _validateBridgeParams(params, paramsV2, exclusivityEndTime);\n\n // transfer tokens to bridge contract\n /// @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _pullToken(params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n\n // set status to requested\n bytes memory request = abi.encode(\n BridgeTransactionV2({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n callValue: paramsV2.callValue,\n deadline: params.deadline,\n nonce: senderNonces[params.sender]++, // increment nonce on every bridge\n exclusivityRelayer: paramsV2.quoteRelayer,\n // We checked exclusivityEndTime to be in range (0 .. params.deadline] above, so can safely cast\n exclusivityEndTime: uint256(exclusivityEndTime),\n callParams: paramsV2.callParams\n })\n );\n bytes32 transactionId = keccak256(request);\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n\n emit BridgeRequested({\n transactionId: transactionId,\n sender: params.sender,\n request: request,\n destChainId: params.dstChainId,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n sendChainGas: paramsV2.callValue != 0\n });\n emit BridgeQuoteDetails(transactionId, paramsV2.quoteId);\n }\n\n /// @inheritdoc IFastBridgeV2\n function relay(bytes memory request, address relayer) public payable {\n bytes32 transactionId = keccak256(request);\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n _validateRelayParams(transaction, transactionId, relayer);\n // mark bridge transaction as relayed\n bridgeRelayDetails[transactionId] =\n BridgeRelay({blockNumber: uint48(block.number), blockTimestamp: uint48(block.timestamp), relayer: relayer});\n\n // transfer tokens to recipient on destination chain and do an arbitrary call if requested\n address to = transaction.destRecipient;\n address token = transaction.destToken;\n uint256 amount = transaction.destAmount;\n\n // All state changes have been done at this point, can proceed to the external calls.\n // This follows the checks-effects-interactions pattern to mitigate potential reentrancy attacks.\n if (token == UniversalTokenLib.ETH_ADDRESS) {\n // For ETH non-zero callValue is not allowed\n if (transaction.callValue != 0) revert NativeTokenCallValueNotSupported();\n // Check that the correct msg.value was sent\n if (msg.value != amount) revert MsgValueIncorrect();\n } else {\n // For ERC20s, we check that the correct msg.value was sent\n if (msg.value != transaction.callValue) revert MsgValueIncorrect();\n // We need to transfer the tokens from the Relayer to the recipient first before performing an\n // optional post-transfer arbitrary call.\n IERC20(token).safeTransferFrom(msg.sender, to, amount);\n }\n\n if (transaction.callParams.length != 0) {\n // Arbitrary call requested, perform it while supplying full msg.value to the recipient\n // Note: if token has a fee on transfers, the recipient will have received less than `amount`.\n // This is a very niche edge case and should be handled by the recipient contract.\n _checkedCallRecipient({recipient: to, token: token, amount: amount, callParams: transaction.callParams});\n } else if (msg.value != 0) {\n // No arbitrary call requested, but msg.value was sent. This is either a relay with ETH,\n // or a non-zero callValue request with an ERC20. In both cases, transfer the ETH to the recipient.\n Address.sendValue(payable(to), msg.value);\n }\n\n emit BridgeRelayed({\n transactionId: transactionId,\n relayer: relayer,\n to: to,\n originChainId: transaction.originChainId,\n originToken: transaction.originToken,\n destToken: transaction.destToken,\n originAmount: transaction.originAmount,\n destAmount: transaction.destAmount,\n chainGasAmount: transaction.callValue\n });\n }\n\n /// @inheritdoc IFastBridgeV2\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) public onlyRole(RELAYER_ROLE) {\n // update bridge tx status given proof provided\n if (bridgeTxDetails[transactionId].status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n bridgeTxDetails[transactionId].status = BridgeStatus.RELAYER_PROVED;\n bridgeTxDetails[transactionId].proofBlockTimestamp = uint40(block.timestamp);\n bridgeTxDetails[transactionId].proofBlockNumber = uint48(block.number);\n bridgeTxDetails[transactionId].proofRelayer = relayer;\n\n emit BridgeProofProvided(transactionId, relayer, destTxHash);\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes memory request, address to) public {\n bytes32 transactionId = keccak256(request);\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n\n // update bridge tx status if able to claim origin collateral\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n\n // if \"to\" is zero addr, permissionlessly send funds to proven relayer\n if (to == address(0)) {\n to = bridgeTxDetails[transactionId].proofRelayer;\n } else if (bridgeTxDetails[transactionId].proofRelayer != msg.sender) {\n revert SenderIncorrect();\n }\n\n if (_timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003c= DISPUTE_PERIOD) {\n revert DisputePeriodNotPassed();\n }\n\n bridgeTxDetails[transactionId].status = BridgeStatus.RELAYER_CLAIMED;\n\n // update protocol fees if origin fee amount exists\n if (transaction.originFeeAmount \u003e 0) protocolFees[transaction.originToken] += transaction.originFeeAmount;\n\n // transfer origin collateral less fee to specified address\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositClaimed(transactionId, bridgeTxDetails[transactionId].proofRelayer, to, token, amount);\n }\n\n function bridgeStatuses(bytes32 transactionId) public view returns (BridgeStatus status) {\n return bridgeTxDetails[transactionId].status;\n }\n\n function bridgeProofs(bytes32 transactionId) public view returns (uint96 timestamp, address relayer) {\n timestamp = bridgeTxDetails[transactionId].proofBlockTimestamp;\n relayer = bridgeTxDetails[transactionId].proofRelayer;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeRelays(bytes32 transactionId) public view returns (bool) {\n // has this transactionId been relayed?\n return bridgeRelayDetails[transactionId].relayer != address(0);\n }\n\n /// @inheritdoc IFastBridgeV2\n function getBridgeTransactionV2(bytes memory request) public pure returns (BridgeTransactionV2 memory) {\n return abi.decode(request, (BridgeTransactionV2));\n }\n\n /// @notice Pulls a requested token from the user to this contract.\n function _pullToken(address token, uint256 amount) internal returns (uint256 amountPulled) {\n if (token == UniversalTokenLib.ETH_ADDRESS) {\n // For ETH we just need to check that the supplied msg.value is correct\n if (amount != msg.value) revert MsgValueIncorrect();\n amountPulled = msg.value;\n } else {\n token.assertIsContract();\n // Record token balance before transfer\n amountPulled = IERC20(token).balanceOf(address(this));\n // Token needs to be pulled only if msg.value is zero\n // This way user can specify WETH as the origin asset\n IERC20(token).safeTransferFrom(msg.sender, address(this), amount);\n // Use the difference between the recorded balance and the current balance as the amountPulled\n amountPulled = IERC20(token).balanceOf(address(this)) - amountPulled;\n }\n }\n\n /// @notice Calls the Recipient's hook function with the specified callParams and performs\n /// all the necessary checks for the returned value.\n function _checkedCallRecipient(\n address recipient,\n address token,\n uint256 amount,\n bytes memory callParams\n )\n internal\n {\n bytes memory hookData =\n abi.encodeCall(IFastBridgeRecipient.fastBridgeTransferReceived, (token, amount, callParams));\n // This will bubble any revert messages from the hook function\n bytes memory returnData = Address.functionCallWithValue({target: recipient, data: hookData, value: msg.value});\n // Explicit revert if no return data at all\n if (returnData.length == 0) revert RecipientNoReturnValue();\n // Check that exactly a single return value was returned\n if (returnData.length != 32) revert RecipientIncorrectReturnValue();\n // Return value should be abi-encoded hook function selector\n if (bytes32(returnData) != bytes32(IFastBridgeRecipient.fastBridgeTransferReceived.selector)) {\n revert RecipientIncorrectReturnValue();\n }\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint40(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint40).max but\n /// proof.timestamp \u003c type(uint40).max via unchecked statement\n /// @param proofBlockTimestamp The bridge proof block timestamp\n /// @return delta Time delta since proof submitted\n function _timeSince(uint40 proofBlockTimestamp) internal view returns (uint256 delta) {\n unchecked {\n delta = uint40(block.timestamp) - proofBlockTimestamp;\n }\n }\n\n /// @notice Performs all the necessary checks for a bridge to happen.\n /// @dev There's no good way to refactor this function to reduce cyclomatic complexity due to\n /// the number of checks that need to be performed, so we skip the code-complexity rule here.\n // solhint-disable-next-line code-complexity\n function _validateBridgeParams(\n BridgeParams memory params,\n BridgeParamsV2 memory paramsV2,\n int256 exclusivityEndTime\n )\n internal\n view\n {\n // Check V1 (legacy) params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.sender == address(0) || params.to == address(0)) revert ZeroAddress();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n // Check V2 params\n if (paramsV2.callParams.length \u003e MAX_CALL_PARAMS_LENGTH) revert CallParamsLengthAboveMax();\n if (paramsV2.callValue != 0 \u0026\u0026 params.destToken == UniversalTokenLib.ETH_ADDRESS) {\n revert NativeTokenCallValueNotSupported();\n }\n // exclusivityEndTime must be in range (0 .. params.deadline]\n if (exclusivityEndTime \u003c= 0 || exclusivityEndTime \u003e int256(params.deadline)) {\n revert ExclusivityParamsIncorrect();\n }\n }\n\n /// @notice Performs all the necessary checks for a relay to happen.\n function _validateRelayParams(\n BridgeTransactionV2 memory transaction,\n bytes32 transactionId,\n address relayer\n )\n internal\n view\n {\n if (relayer == address(0)) revert ZeroAddress();\n // Check if the transaction has already been relayed\n if (bridgeRelays(transactionId)) revert TransactionRelayed();\n if (transaction.destChainId != uint32(block.chainid)) revert ChainIncorrect();\n // Check the deadline for relay to happen\n if (block.timestamp \u003e transaction.deadline) revert DeadlineExceeded();\n // Check the exclusivity period, if it is still ongoing\n // forgefmt: disable-next-item\n if (\n transaction.exclusivityRelayer != address(0) \u0026\u0026\n transaction.exclusivityRelayer != relayer \u0026\u0026\n block.timestamp \u003c= transaction.exclusivityEndTime\n ) {\n revert ExclusivityPeriodNotPassed();\n }\n }\n}\n","language":"Solidity","languageVersion":"0.8.24","compilerVersion":"0.8.24","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"16564:6066:0:-:0;;;;;;;;;;;;;;;-1:-1:-1;;;16564:6066:0;;;;;;;;;;;;;;;;;","srcMapRuntime":"16564:6066:0:-:0;;;;;;;;","abiDefinition":[{"inputs":[{"internalType":"address","name":"target","type":"address"}],"name":"AddressEmptyCode","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"AddressInsufficientBalance","type":"error"},{"inputs":[],"name":"FailedInnerCall","type":"error"}],"userDoc":{"kind":"user","methods":{},"version":1},"developerDoc":{"details":"Collection of functions related to the address type","errors":{"AddressEmptyCode(address)":[{"details":"There's no code at `target` (it is not a contract)."}],"AddressInsufficientBalance(address)":[{"details":"The ETH balance of the account is not enough to perform the operation."}],"FailedInnerCall()":[{"details":"A call to an address target failed. The target may have reverted."}]},"kind":"dev","methods":{},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"}],\"name\":\"AddressEmptyCode\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"AddressInsufficientBalance\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"FailedInnerCall\",\"type\":\"error\"}],\"devdoc\":{\"details\":\"Collection of functions related to the address type\",\"errors\":{\"AddressEmptyCode(address)\":[{\"details\":\"There's no code at `target` (it is not a contract).\"}],\"AddressInsufficientBalance(address)\":[{\"details\":\"The ETH balance of the account is not enough to perform the operation.\"}],\"FailedInnerCall()\":[{\"details\":\"A call to an address target failed. The target may have reverted.\"}]},\"kind\":\"dev\",\"methods\":{},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeV2.sol\":\"Address\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeV2.sol\":{\"keccak256\":\"0x7cd0f885e80e2bdaa638bc32ae7af7d2e248f99ce4b354c217d0f0f7d7302e0a\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://7ccf28df0bd7b4606986585acd8622ed9b4e81379690061bb66088f0a2270af1\",\"dweb:/ipfs/QmTf7HNdHZkK6vmx8ZgewycQEb72oLD9nPwBpsM5reMstQ\"]}},\"version\":1}"},"hashes":{}},"solidity/FastBridgeV2.sol:Admin":{"code":"0x60806040523480156200001157600080fd5b50604051620014123803806200141283398101604081905262000034916200018e565b6200004160008262000049565b5050620001b9565b60008062000058848462000086565b905080156200007d5760008481526001602052604090206200007b908462000134565b505b90505b92915050565b6000828152602081815260408083206001600160a01b038516845290915281205460ff166200012b576000838152602081815260408083206001600160a01b03861684529091529020805460ff19166001179055620000e23390565b6001600160a01b0316826001600160a01b0316847f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a450600162000080565b50600062000080565b60006200007d836001600160a01b03841660008181526001830160205260408120546200012b5750815460018181018455600084815260208082209093018490558454848252828601909352604090209190915562000080565b600060208284031215620001a157600080fd5b81516001600160a01b03811681146200007d57600080fd5b61124980620001c96000396000f3fe608060405234801561001057600080fd5b50600436106101775760003560e01c806391d14854116100d8578063bf333f2c1161008c578063d547741f11610066578063d547741f14610385578063dcf844a714610398578063e00a83e0146103b857600080fd5b8063bf333f2c14610341578063ca15c8731461034b578063ccc574901461035e57600080fd5b8063a217fddf116100bd578063a217fddf14610313578063b13aa2d61461031b578063b250fe6b1461032e57600080fd5b806391d14854146102a8578063926d7d7f146102ec57600080fd5b80632f2ff15d1161012f57806358f858801161011457806358f85880146102405780635960ccf2146102495780639010d07c1461027057600080fd5b80632f2ff15d1461021a57806336568abe1461022d57600080fd5b806306f333f21161016057806306f333f2146101d95780630f5f6ed7146101ee578063248a9ca3146101f757600080fd5b806301ffc9a71461017c57806303ed0ee5146101a4575b600080fd5b61018f61018a366004611013565b6103c1565b60405190151581526020015b60405180910390f35b6101cb7f043c983c49d46f0e102151eaf8085d4a2e6571d5df2d47b013f39bddfd4a639d81565b60405190815260200161019b565b6101ec6101e736600461107e565b61041d565b005b6101cb61271081565b6101cb6102053660046110b1565b60009081526020819052604090206001015490565b6101ec6102283660046110ca565b61050b565b6101ec61023b3660046110ca565b610536565b6101cb60025481565b6101cb7fdb9556138406326f00296e13ea2ad7db24ba82381212d816b1a40c23b466b32781565b61028361027e3660046110ed565b61058f565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200161019b565b61018f6102b63660046110ca565b60009182526020828152604080842073ffffffffffffffffffffffffffffffffffffffff93909316845291905290205460ff1690565b6101cb7fe2b7fb3b832174769106daebcfd6d1970523240dda11281102db9363b83b0dc481565b6101cb600081565b6101ec6103293660046110b1565b6105ae565b6101ec61033c3660046110b1565b610690565b6101cb620f424081565b6101cb6103593660046110b1565b6106f8565b6101cb7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f5581565b6101ec6103933660046110ca565b61070f565b6101cb6103a636600461110f565b60036020526000908152604090205481565b6101cb60045481565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f5a05180f000000000000000000000000000000000000000000000000000000001480610417575061041782610734565b92915050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f55610447816107cb565b73ffffffffffffffffffffffffffffffffffffffff83166000908152600360205260408120549081900361047b5750505050565b73ffffffffffffffffffffffffffffffffffffffff84166000818152600360205260408120556104ac9084836107d8565b6040805173ffffffffffffffffffffffffffffffffffffffff8087168252851660208201529081018290527f244e51bc38c1452fa8aaf487bcb4bca36c2baa3a5fbdb776b1eabd8dc6d277cd9060600160405180910390a1505b505050565b600082815260208190526040902060010154610526816107cb565b610530838361092f565b50505050565b73ffffffffffffffffffffffffffffffffffffffff81163314610585576040517f6697b23200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6105068282610964565b60008281526001602052604081206105a79083610991565b9392505050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f556105d8816107cb565b612710821115610649576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f6e657746656552617465203e206d61780000000000000000000000000000000060448201526064015b60405180910390fd5b600280549083905560408051828152602081018590527f14914da2bf76024616fbe1859783fcd4dbddcb179b1f3a854949fbf920dcb95791015b60405180910390a1505050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f556106ba816107cb565b600480549083905560408051828152602081018590527f5cf09b12f3f56b4c564d51b25b40360af6d795198adb61ae0806a36c294323fa9101610683565b60008181526001602052604081206104179061099d565b60008281526020819052604090206001015461072a816107cb565b6105308383610964565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f7965db0b00000000000000000000000000000000000000000000000000000000148061041757507f01ffc9a7000000000000000000000000000000000000000000000000000000007fffffffff00000000000000000000000000000000000000000000000000000000831614610417565b6107d581336109a7565b50565b3073ffffffffffffffffffffffffffffffffffffffff8316036107fa57505050565b8060000361080757505050565b7fffffffffffffffffffffffff111111111111111111111111111111111111111273ffffffffffffffffffffffffffffffffffffffff84160161090e5760008273ffffffffffffffffffffffffffffffffffffffff168260405160006040518083038185875af1925050503d806000811461089e576040519150601f19603f3d011682016040523d82523d6000602084013e6108a3565b606091505b5050905080610530576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f455448207472616e73666572206661696c6564000000000000000000000000006044820152606401610640565b61050673ffffffffffffffffffffffffffffffffffffffff84168383610a31565b60008061093c8484610abe565b905080156105a757600084815260016020526040902061095c9084610bba565b509392505050565b6000806109718484610bdc565b905080156105a757600084815260016020526040902061095c9084610c97565b60006105a78383610cb9565b6000610417825490565b60008281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915290205460ff16610a2d576040517fe2517d3f00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8216600482015260248101839052604401610640565b5050565b6040805173ffffffffffffffffffffffffffffffffffffffff8416602482015260448082018490528251808303909101815260649091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fa9059cbb00000000000000000000000000000000000000000000000000000000179052610506908490610ce3565b60008281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915281205460ff16610bb25760008381526020818152604080832073ffffffffffffffffffffffffffffffffffffffff86168452909152902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055610b503390565b73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16847f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a4506001610417565b506000610417565b60006105a78373ffffffffffffffffffffffffffffffffffffffff8416610d79565b60008281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915281205460ff1615610bb25760008381526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8616808552925280832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016905551339286917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a4506001610417565b60006105a78373ffffffffffffffffffffffffffffffffffffffff8416610dc0565b6000826000018281548110610cd057610cd061112a565b9060005260206000200154905092915050565b6000610d0573ffffffffffffffffffffffffffffffffffffffff841683610eb3565b90508051600014158015610d2a575080806020019051810190610d289190611159565b155b15610506576040517f5274afe700000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff84166004820152602401610640565b6000818152600183016020526040812054610bb257508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155610417565b60008181526001830160205260408120548015610ea9576000610de460018361117b565b8554909150600090610df89060019061117b565b9050808214610e5d576000866000018281548110610e1857610e1861112a565b9060005260206000200154905080876000018481548110610e3b57610e3b61112a565b6000918252602080832090910192909255918252600188019052604090208390555b8554869080610e6e57610e6e6111b5565b600190038181906000526020600020016000905590558560010160008681526020019081526020016000206000905560019350505050610417565b6000915050610417565b60606105a783836000846000808573ffffffffffffffffffffffffffffffffffffffff168486604051610ee691906111e4565b60006040518083038185875af1925050503d8060008114610f23576040519150601f19603f3d011682016040523d82523d6000602084013e610f28565b606091505b5091509150610f38868383610f42565b9695505050505050565b606082610f5757610f5282610fd1565b6105a7565b8151158015610f7b575073ffffffffffffffffffffffffffffffffffffffff84163b155b15610fca576040517f9996b31500000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff85166004820152602401610640565b50806105a7565b805115610fe15780518082602001fd5b6040517f1425ea4200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006020828403121561102557600080fd5b81357fffffffff00000000000000000000000000000000000000000000000000000000811681146105a757600080fd5b803573ffffffffffffffffffffffffffffffffffffffff8116811461107957600080fd5b919050565b6000806040838503121561109157600080fd5b61109a83611055565b91506110a860208401611055565b90509250929050565b6000602082840312156110c357600080fd5b5035919050565b600080604083850312156110dd57600080fd5b823591506110a860208401611055565b6000806040838503121561110057600080fd5b50508035926020909101359150565b60006020828403121561112157600080fd5b6105a782611055565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60006020828403121561116b57600080fd5b815180151581146105a757600080fd5b81810381811115610417577f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fd5b6000825160005b8181101561120557602081860181015185830152016111eb565b50600092019182525091905056fea2646970667358221220e128d8a06a9c2200c4304cd29f76ba6d8295d2c98b16f4a06921d33d0cebefd764736f6c63430008180033","runtime-code":"0x608060405234801561001057600080fd5b50600436106101775760003560e01c806391d14854116100d8578063bf333f2c1161008c578063d547741f11610066578063d547741f14610385578063dcf844a714610398578063e00a83e0146103b857600080fd5b8063bf333f2c14610341578063ca15c8731461034b578063ccc574901461035e57600080fd5b8063a217fddf116100bd578063a217fddf14610313578063b13aa2d61461031b578063b250fe6b1461032e57600080fd5b806391d14854146102a8578063926d7d7f146102ec57600080fd5b80632f2ff15d1161012f57806358f858801161011457806358f85880146102405780635960ccf2146102495780639010d07c1461027057600080fd5b80632f2ff15d1461021a57806336568abe1461022d57600080fd5b806306f333f21161016057806306f333f2146101d95780630f5f6ed7146101ee578063248a9ca3146101f757600080fd5b806301ffc9a71461017c57806303ed0ee5146101a4575b600080fd5b61018f61018a366004611013565b6103c1565b60405190151581526020015b60405180910390f35b6101cb7f043c983c49d46f0e102151eaf8085d4a2e6571d5df2d47b013f39bddfd4a639d81565b60405190815260200161019b565b6101ec6101e736600461107e565b61041d565b005b6101cb61271081565b6101cb6102053660046110b1565b60009081526020819052604090206001015490565b6101ec6102283660046110ca565b61050b565b6101ec61023b3660046110ca565b610536565b6101cb60025481565b6101cb7fdb9556138406326f00296e13ea2ad7db24ba82381212d816b1a40c23b466b32781565b61028361027e3660046110ed565b61058f565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200161019b565b61018f6102b63660046110ca565b60009182526020828152604080842073ffffffffffffffffffffffffffffffffffffffff93909316845291905290205460ff1690565b6101cb7fe2b7fb3b832174769106daebcfd6d1970523240dda11281102db9363b83b0dc481565b6101cb600081565b6101ec6103293660046110b1565b6105ae565b6101ec61033c3660046110b1565b610690565b6101cb620f424081565b6101cb6103593660046110b1565b6106f8565b6101cb7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f5581565b6101ec6103933660046110ca565b61070f565b6101cb6103a636600461110f565b60036020526000908152604090205481565b6101cb60045481565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f5a05180f000000000000000000000000000000000000000000000000000000001480610417575061041782610734565b92915050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f55610447816107cb565b73ffffffffffffffffffffffffffffffffffffffff83166000908152600360205260408120549081900361047b5750505050565b73ffffffffffffffffffffffffffffffffffffffff84166000818152600360205260408120556104ac9084836107d8565b6040805173ffffffffffffffffffffffffffffffffffffffff8087168252851660208201529081018290527f244e51bc38c1452fa8aaf487bcb4bca36c2baa3a5fbdb776b1eabd8dc6d277cd9060600160405180910390a1505b505050565b600082815260208190526040902060010154610526816107cb565b610530838361092f565b50505050565b73ffffffffffffffffffffffffffffffffffffffff81163314610585576040517f6697b23200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6105068282610964565b60008281526001602052604081206105a79083610991565b9392505050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f556105d8816107cb565b612710821115610649576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f6e657746656552617465203e206d61780000000000000000000000000000000060448201526064015b60405180910390fd5b600280549083905560408051828152602081018590527f14914da2bf76024616fbe1859783fcd4dbddcb179b1f3a854949fbf920dcb95791015b60405180910390a1505050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f556106ba816107cb565b600480549083905560408051828152602081018590527f5cf09b12f3f56b4c564d51b25b40360af6d795198adb61ae0806a36c294323fa9101610683565b60008181526001602052604081206104179061099d565b60008281526020819052604090206001015461072a816107cb565b6105308383610964565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f7965db0b00000000000000000000000000000000000000000000000000000000148061041757507f01ffc9a7000000000000000000000000000000000000000000000000000000007fffffffff00000000000000000000000000000000000000000000000000000000831614610417565b6107d581336109a7565b50565b3073ffffffffffffffffffffffffffffffffffffffff8316036107fa57505050565b8060000361080757505050565b7fffffffffffffffffffffffff111111111111111111111111111111111111111273ffffffffffffffffffffffffffffffffffffffff84160161090e5760008273ffffffffffffffffffffffffffffffffffffffff168260405160006040518083038185875af1925050503d806000811461089e576040519150601f19603f3d011682016040523d82523d6000602084013e6108a3565b606091505b5050905080610530576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f455448207472616e73666572206661696c6564000000000000000000000000006044820152606401610640565b61050673ffffffffffffffffffffffffffffffffffffffff84168383610a31565b60008061093c8484610abe565b905080156105a757600084815260016020526040902061095c9084610bba565b509392505050565b6000806109718484610bdc565b905080156105a757600084815260016020526040902061095c9084610c97565b60006105a78383610cb9565b6000610417825490565b60008281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915290205460ff16610a2d576040517fe2517d3f00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8216600482015260248101839052604401610640565b5050565b6040805173ffffffffffffffffffffffffffffffffffffffff8416602482015260448082018490528251808303909101815260649091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fa9059cbb00000000000000000000000000000000000000000000000000000000179052610506908490610ce3565b60008281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915281205460ff16610bb25760008381526020818152604080832073ffffffffffffffffffffffffffffffffffffffff86168452909152902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055610b503390565b73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16847f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a4506001610417565b506000610417565b60006105a78373ffffffffffffffffffffffffffffffffffffffff8416610d79565b60008281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915281205460ff1615610bb25760008381526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8616808552925280832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016905551339286917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a4506001610417565b60006105a78373ffffffffffffffffffffffffffffffffffffffff8416610dc0565b6000826000018281548110610cd057610cd061112a565b9060005260206000200154905092915050565b6000610d0573ffffffffffffffffffffffffffffffffffffffff841683610eb3565b90508051600014158015610d2a575080806020019051810190610d289190611159565b155b15610506576040517f5274afe700000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff84166004820152602401610640565b6000818152600183016020526040812054610bb257508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155610417565b60008181526001830160205260408120548015610ea9576000610de460018361117b565b8554909150600090610df89060019061117b565b9050808214610e5d576000866000018281548110610e1857610e1861112a565b9060005260206000200154905080876000018481548110610e3b57610e3b61112a565b6000918252602080832090910192909255918252600188019052604090208390555b8554869080610e6e57610e6e6111b5565b600190038181906000526020600020016000905590558560010160008681526020019081526020016000206000905560019350505050610417565b6000915050610417565b60606105a783836000846000808573ffffffffffffffffffffffffffffffffffffffff168486604051610ee691906111e4565b60006040518083038185875af1925050503d8060008114610f23576040519150601f19603f3d011682016040523d82523d6000602084013e610f28565b606091505b5091509150610f38868383610f42565b9695505050505050565b606082610f5757610f5282610fd1565b6105a7565b8151158015610f7b575073ffffffffffffffffffffffffffffffffffffffff84163b155b15610fca576040517f9996b31500000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff85166004820152602401610640565b50806105a7565b805115610fe15780518082602001fd5b6040517f1425ea4200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006020828403121561102557600080fd5b81357fffffffff00000000000000000000000000000000000000000000000000000000811681146105a757600080fd5b803573ffffffffffffffffffffffffffffffffffffffff8116811461107957600080fd5b919050565b6000806040838503121561109157600080fd5b61109a83611055565b91506110a860208401611055565b90509250929050565b6000602082840312156110c357600080fd5b5035919050565b600080604083850312156110dd57600080fd5b823591506110a860208401611055565b6000806040838503121561110057600080fd5b50508035926020909101359150565b60006020828403121561112157600080fd5b6105a782611055565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60006020828403121561116b57600080fd5b815180151581146105a757600080fd5b81810381811115610417577f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fd5b6000825160005b8181101561120557602081860181015185830152016111eb565b50600092019182525091905056fea2646970667358221220e128d8a06a9c2200c4304cd29f76ba6d8295d2c98b16f4a06921d33d0cebefd764736f6c63430008180033","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.24 ^0.8.0 ^0.8.20;\n\n// contracts/interfaces/IAdmin.sol\n\ninterface IAdmin {\n // ============ Events ============\n\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n event ChainGasAmountUpdated(uint256 oldChainGasAmount, uint256 newChainGasAmount);\n\n // ============ Methods ============\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n\n function setChainGasAmount(uint256 newChainGasAmount) external;\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IFastBridgeRecipient.sol\n\ninterface IFastBridgeRecipient {\n function fastBridgeTransferReceived(\n address token,\n uint256 amount,\n bytes memory callParams\n )\n external\n payable\n returns (bytes4);\n}\n\n// contracts/interfaces/IFastBridgeV2Errors.sol\n\ninterface IFastBridgeV2Errors {\n error AmountIncorrect();\n error CallParamsLengthAboveMax();\n error ChainIncorrect();\n error ExclusivityParamsIncorrect();\n error MsgValueIncorrect();\n error NativeTokenCallValueNotSupported();\n error SenderIncorrect();\n error StatusIncorrect();\n error ZeroAddress();\n\n error RecipientIncorrectReturnValue();\n error RecipientNoReturnValue();\n\n error DeadlineExceeded();\n error DeadlineNotExceeded();\n error DeadlineTooShort();\n error DisputePeriodNotPassed();\n error DisputePeriodPassed();\n error ExclusivityPeriodNotPassed();\n\n error TransactionRelayed();\n}\n\n// contracts/libs/Errors.sol\n\nerror DeadlineExceeded();\nerror DeadlineNotExceeded();\nerror DeadlineTooShort();\nerror InsufficientOutputAmount();\n\nerror MsgValueIncorrect();\nerror PoolNotFound();\nerror TokenAddressMismatch();\nerror TokenNotContract();\nerror TokenNotETH();\nerror TokensIdentical();\n\nerror ChainIncorrect();\nerror AmountIncorrect();\nerror ZeroAddress();\n\nerror DisputePeriodNotPassed();\nerror DisputePeriodPassed();\nerror SenderIncorrect();\nerror StatusIncorrect();\nerror TransactionIdIncorrect();\nerror TransactionRelayed();\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// contracts/interfaces/IFastBridgeV2.sol\n\ninterface IFastBridgeV2 is IFastBridge {\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n struct BridgeTxDetails {\n BridgeStatus status;\n uint40 proofBlockTimestamp;\n uint48 proofBlockNumber;\n address proofRelayer;\n }\n\n struct BridgeRelay {\n uint48 blockNumber;\n uint48 blockTimestamp;\n address relayer;\n }\n\n /// @notice New params introduced in the FastBridgeV2.\n /// We are passing fields from the older BridgeParams struct outside of this struct\n /// for backwards compatibility.\n /// Note: quoteRelayer and quoteExclusivitySeconds are either both zero (indicating no exclusivity)\n /// or both non-zero (indicating exclusivity for the given period).\n /// Note: callValue \u003e 0 can NOT be used with destToken = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE (ETH_ADDRESS)\n /// @param quoteRelayer Relayer that provided the quote for the transaction\n /// @param quoteExclusivitySeconds Period of time the quote relayer is guaranteed exclusivity after user's deposit\n /// @param quoteId Unique quote identifier used for tracking the quote\n /// @param callValue ETH value to send to the recipient (if any)\n /// @param callParams Parameters for the arbitrary call to the destination recipient (if any)\n struct BridgeParamsV2 {\n address quoteRelayer;\n int256 quoteExclusivitySeconds;\n bytes quoteId;\n uint256 callValue;\n bytes callParams;\n }\n\n /// @notice Updated bridge transaction struct to include parameters introduced in FastBridgeV2.\n /// Note: only `exclusivityRelayer` can fill such a transaction until `exclusivityEndTime`.\n /// TODO: consider changing the encoding scheme to prevent spending extra gas on decoding.\n struct BridgeTransactionV2 {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n uint256 callValue; // ETH value to send to the recipient (if any) - replaces V1's sendChainGas flag\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n address exclusivityRelayer;\n uint256 exclusivityEndTime;\n bytes callParams;\n }\n\n event BridgeQuoteDetails(bytes32 indexed transactionId, bytes quoteId);\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability\n /// to provide temporary exclusivity fill rights for the quote relayer.\n /// @param params The parameters required to bridge\n /// @param paramsV2 The parameters for exclusivity fill rights (optional, can be left empty)\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function relay(bytes memory request, address relayer) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param transactionId The transaction id associated with the encoded bridge transaction to prove\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital.\n /// @notice Can only send funds to the relayer address on the proof.\n /// @param request The encoded bridge transaction to claim on origin chain\n function claim(bytes memory request) external;\n /// @notice Checks if a transaction has been relayed\n /// @param transactionId The ID of the transaction to check\n /// @return True if the transaction has been relayed, false otherwise\n function bridgeRelays(bytes32 transactionId) external view returns (bool);\n\n /// @notice Returns the status of a bridge transaction\n /// @param transactionId The ID of the bridge transaction\n /// @return BridgeStatus Status of the bridge transaction\n function bridgeStatuses(bytes32 transactionId) external view returns (BridgeStatus);\n\n /// @notice Returns the timestamp and relayer of a bridge proof\n /// @param transactionId The ID of the bridge transaction\n /// @return timestamp The timestamp of the bridge proof\n /// @return relayer The relayer address of the bridge proof\n function bridgeProofs(bytes32 transactionId) external view returns (uint96 timestamp, address relayer);\n\n /// @notice Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\n /// @param request The bridge request to decode\n function getBridgeTransactionV2(bytes memory request) external view returns (BridgeTransactionV2 memory);\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// contracts/libs/UniversalToken.sol\n\nlibrary UniversalTokenLib {\n using SafeERC20 for IERC20;\n\n address internal constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Transfers tokens to the given account. Reverts if transfer is not successful.\n /// @dev This might trigger fallback, if ETH is transferred to the contract.\n /// Make sure this can not lead to reentrancy attacks.\n function universalTransfer(address token, address to, uint256 value) internal {\n // Don't do anything, if need to send tokens to this address\n if (to == address(this)) return;\n // Don't do anything, if trying to send zero value\n if (value == 0) return;\n if (token == ETH_ADDRESS) {\n /// @dev Note: this can potentially lead to executing code in `to`.\n // solhint-disable-next-line avoid-low-level-calls\n (bool success,) = to.call{value: value}(\"\");\n require(success, \"ETH transfer failed\");\n } else {\n IERC20(token).safeTransfer(to, value);\n }\n }\n\n /// @notice Issues an infinite allowance to the spender, if the current allowance is insufficient\n /// to spend the given amount.\n function universalApproveInfinity(address token, address spender, uint256 amountToSpend) internal {\n // ETH Chad doesn't require your approval\n if (token == ETH_ADDRESS) return;\n // No-op if allowance is already sufficient\n uint256 allowance = IERC20(token).allowance(address(this), spender);\n if (allowance \u003e= amountToSpend) return;\n // Otherwise, reset approval to 0 and set to max allowance\n if (allowance \u003e 0) IERC20(token).safeDecreaseAllowance(spender, allowance);\n IERC20(token).safeIncreaseAllowance(spender, type(uint256).max);\n }\n\n /// @notice Returns the balance of the given token (or native ETH) for the given account.\n function universalBalanceOf(address token, address account) internal view returns (uint256) {\n if (token == ETH_ADDRESS) {\n return account.balance;\n } else {\n return IERC20(token).balanceOf(account);\n }\n }\n\n /// @dev Checks that token is a contract and not ETH_ADDRESS.\n function assertIsContract(address token) internal view {\n // Check that ETH_ADDRESS was not used (in case this is a predeploy on any of the chains)\n if (token == UniversalTokenLib.ETH_ADDRESS) revert TokenNotContract();\n // Check that token is not an EOA\n if (token.code.length == 0) revert TokenNotContract();\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/Admin.sol\n\ncontract Admin is IAdmin, AccessControlEnumerable {\n using UniversalTokenLib for address;\n\n bytes32 public constant RELAYER_ROLE = keccak256(\"RELAYER_ROLE\");\n bytes32 public constant REFUNDER_ROLE = keccak256(\"REFUNDER_ROLE\");\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n uint256 public constant FEE_BPS = 1e6;\n uint256 public constant FEE_RATE_MAX = 0.01e6; // max 1% on origin amount\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Chain gas amount to forward as rebate if requested\n uint256 public chainGasAmount;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n }\n\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n require(newFeeRate \u003c= FEE_RATE_MAX, \"newFeeRate \u003e max\");\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n token.universalTransfer(recipient, feeAmount);\n emit FeesSwept(token, recipient, feeAmount);\n }\n\n function setChainGasAmount(uint256 newChainGasAmount) external onlyRole(GOVERNOR_ROLE) {\n uint256 oldChainGasAmount = chainGasAmount;\n chainGasAmount = newChainGasAmount;\n emit ChainGasAmountUpdated(oldChainGasAmount, newChainGasAmount);\n }\n}\n\n// contracts/FastBridgeV2.sol\n\n/// @notice FastBridgeV2 is a contract for bridging tokens across chains.\ncontract FastBridgeV2 is Admin, IFastBridgeV2, IFastBridgeV2Errors {\n using SafeERC20 for IERC20;\n using UniversalTokenLib for address;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Delay for a transaction after which it could be permisionlessly refunded\n uint256 public constant REFUND_DELAY = 7 days;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n /// @notice Maximum length of accepted callParams\n uint256 public constant MAX_CALL_PARAMS_LENGTH = 2 ** 16 - 1;\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeTxDetails) public bridgeTxDetails;\n /// @notice Relay details on destination chain\n mapping(bytes32 =\u003e BridgeRelay) public bridgeRelayDetails;\n /// @notice Unique bridge nonces tracked per originSender\n mapping(address =\u003e uint256) public senderNonces;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Replaced by senderNonces\n uint256 public immutable nonce = 0;\n /// @notice the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n bridge({\n params: params,\n paramsV2: BridgeParamsV2({\n quoteRelayer: address(0),\n quoteExclusivitySeconds: 0,\n quoteId: bytes(\"\"),\n callValue: 0,\n callParams: bytes(\"\")\n })\n });\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes memory request) external payable {\n relay({request: request, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes memory request, bytes32 destTxHash) external {\n prove({transactionId: keccak256(request), destTxHash: destTxHash, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridgeV2\n function claim(bytes memory request) external {\n claim({request: request, to: address(0)});\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003e DISPUTE_PERIOD) {\n revert DisputePeriodPassed();\n }\n\n // @dev relayer gets slashed effectively if dest relay has gone thru\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n bridgeTxDetails[transactionId].proofRelayer = address(0);\n bridgeTxDetails[transactionId].proofBlockTimestamp = 0;\n bridgeTxDetails[transactionId].proofBlockNumber = 0;\n\n emit BridgeProofDisputed(transactionId, msg.sender);\n }\n\n /// @inheritdoc IFastBridge\n function refund(bytes memory request) external {\n bytes32 transactionId = keccak256(request);\n\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n\n if (bridgeTxDetails[transactionId].status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n\n if (hasRole(REFUNDER_ROLE, msg.sender)) {\n // Refunder can refund if deadline has passed\n if (block.timestamp \u003c= transaction.deadline) revert DeadlineNotExceeded();\n } else {\n // Permissionless refund is allowed after REFUND_DELAY\n if (block.timestamp \u003c= transaction.deadline + REFUND_DELAY) revert DeadlineNotExceeded();\n }\n\n // if all checks passed, set to REFUNDED status\n bridgeTxDetails[transactionId].status = BridgeStatus.REFUNDED;\n\n // transfer origin collateral back to original sender\n address to = transaction.originSender;\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount + transaction.originFeeAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (bridgeTxDetails[transactionId].proofRelayer != relayer) revert SenderIncorrect();\n return _timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n /// @dev This method is added to achieve backwards compatibility with decoding requests into V1 structs:\n /// - `callValue` is partially reported as a zero/non-zero flag\n /// - `callParams` is ignored\n /// In order to process all kinds of requests use getBridgeTransactionV2 instead.\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory) {\n // Try decoding into V2 struct first. This will revert if V1 struct is passed\n try this.getBridgeTransactionV2(request) returns (BridgeTransactionV2 memory txV2) {\n // Note: we entirely ignore the callParams field, as it was not present in V1\n return BridgeTransaction({\n originChainId: txV2.originChainId,\n destChainId: txV2.destChainId,\n originSender: txV2.originSender,\n destRecipient: txV2.destRecipient,\n originToken: txV2.originToken,\n destToken: txV2.destToken,\n originAmount: txV2.originAmount,\n destAmount: txV2.destAmount,\n originFeeAmount: txV2.originFeeAmount,\n sendChainGas: txV2.callValue != 0,\n deadline: txV2.deadline,\n nonce: txV2.nonce\n });\n } catch {\n // Fallback to V1 struct\n return abi.decode(request, (BridgeTransaction));\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) public payable {\n int256 exclusivityEndTime = int256(block.timestamp) + paramsV2.quoteExclusivitySeconds;\n _validateBridgeParams(params, paramsV2, exclusivityEndTime);\n\n // transfer tokens to bridge contract\n /// @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _pullToken(params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n\n // set status to requested\n bytes memory request = abi.encode(\n BridgeTransactionV2({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n callValue: paramsV2.callValue,\n deadline: params.deadline,\n nonce: senderNonces[params.sender]++, // increment nonce on every bridge\n exclusivityRelayer: paramsV2.quoteRelayer,\n // We checked exclusivityEndTime to be in range (0 .. params.deadline] above, so can safely cast\n exclusivityEndTime: uint256(exclusivityEndTime),\n callParams: paramsV2.callParams\n })\n );\n bytes32 transactionId = keccak256(request);\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n\n emit BridgeRequested({\n transactionId: transactionId,\n sender: params.sender,\n request: request,\n destChainId: params.dstChainId,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n sendChainGas: paramsV2.callValue != 0\n });\n emit BridgeQuoteDetails(transactionId, paramsV2.quoteId);\n }\n\n /// @inheritdoc IFastBridgeV2\n function relay(bytes memory request, address relayer) public payable {\n bytes32 transactionId = keccak256(request);\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n _validateRelayParams(transaction, transactionId, relayer);\n // mark bridge transaction as relayed\n bridgeRelayDetails[transactionId] =\n BridgeRelay({blockNumber: uint48(block.number), blockTimestamp: uint48(block.timestamp), relayer: relayer});\n\n // transfer tokens to recipient on destination chain and do an arbitrary call if requested\n address to = transaction.destRecipient;\n address token = transaction.destToken;\n uint256 amount = transaction.destAmount;\n\n // All state changes have been done at this point, can proceed to the external calls.\n // This follows the checks-effects-interactions pattern to mitigate potential reentrancy attacks.\n if (token == UniversalTokenLib.ETH_ADDRESS) {\n // For ETH non-zero callValue is not allowed\n if (transaction.callValue != 0) revert NativeTokenCallValueNotSupported();\n // Check that the correct msg.value was sent\n if (msg.value != amount) revert MsgValueIncorrect();\n } else {\n // For ERC20s, we check that the correct msg.value was sent\n if (msg.value != transaction.callValue) revert MsgValueIncorrect();\n // We need to transfer the tokens from the Relayer to the recipient first before performing an\n // optional post-transfer arbitrary call.\n IERC20(token).safeTransferFrom(msg.sender, to, amount);\n }\n\n if (transaction.callParams.length != 0) {\n // Arbitrary call requested, perform it while supplying full msg.value to the recipient\n // Note: if token has a fee on transfers, the recipient will have received less than `amount`.\n // This is a very niche edge case and should be handled by the recipient contract.\n _checkedCallRecipient({recipient: to, token: token, amount: amount, callParams: transaction.callParams});\n } else if (msg.value != 0) {\n // No arbitrary call requested, but msg.value was sent. This is either a relay with ETH,\n // or a non-zero callValue request with an ERC20. In both cases, transfer the ETH to the recipient.\n Address.sendValue(payable(to), msg.value);\n }\n\n emit BridgeRelayed({\n transactionId: transactionId,\n relayer: relayer,\n to: to,\n originChainId: transaction.originChainId,\n originToken: transaction.originToken,\n destToken: transaction.destToken,\n originAmount: transaction.originAmount,\n destAmount: transaction.destAmount,\n chainGasAmount: transaction.callValue\n });\n }\n\n /// @inheritdoc IFastBridgeV2\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) public onlyRole(RELAYER_ROLE) {\n // update bridge tx status given proof provided\n if (bridgeTxDetails[transactionId].status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n bridgeTxDetails[transactionId].status = BridgeStatus.RELAYER_PROVED;\n bridgeTxDetails[transactionId].proofBlockTimestamp = uint40(block.timestamp);\n bridgeTxDetails[transactionId].proofBlockNumber = uint48(block.number);\n bridgeTxDetails[transactionId].proofRelayer = relayer;\n\n emit BridgeProofProvided(transactionId, relayer, destTxHash);\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes memory request, address to) public {\n bytes32 transactionId = keccak256(request);\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n\n // update bridge tx status if able to claim origin collateral\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n\n // if \"to\" is zero addr, permissionlessly send funds to proven relayer\n if (to == address(0)) {\n to = bridgeTxDetails[transactionId].proofRelayer;\n } else if (bridgeTxDetails[transactionId].proofRelayer != msg.sender) {\n revert SenderIncorrect();\n }\n\n if (_timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003c= DISPUTE_PERIOD) {\n revert DisputePeriodNotPassed();\n }\n\n bridgeTxDetails[transactionId].status = BridgeStatus.RELAYER_CLAIMED;\n\n // update protocol fees if origin fee amount exists\n if (transaction.originFeeAmount \u003e 0) protocolFees[transaction.originToken] += transaction.originFeeAmount;\n\n // transfer origin collateral less fee to specified address\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositClaimed(transactionId, bridgeTxDetails[transactionId].proofRelayer, to, token, amount);\n }\n\n function bridgeStatuses(bytes32 transactionId) public view returns (BridgeStatus status) {\n return bridgeTxDetails[transactionId].status;\n }\n\n function bridgeProofs(bytes32 transactionId) public view returns (uint96 timestamp, address relayer) {\n timestamp = bridgeTxDetails[transactionId].proofBlockTimestamp;\n relayer = bridgeTxDetails[transactionId].proofRelayer;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeRelays(bytes32 transactionId) public view returns (bool) {\n // has this transactionId been relayed?\n return bridgeRelayDetails[transactionId].relayer != address(0);\n }\n\n /// @inheritdoc IFastBridgeV2\n function getBridgeTransactionV2(bytes memory request) public pure returns (BridgeTransactionV2 memory) {\n return abi.decode(request, (BridgeTransactionV2));\n }\n\n /// @notice Pulls a requested token from the user to this contract.\n function _pullToken(address token, uint256 amount) internal returns (uint256 amountPulled) {\n if (token == UniversalTokenLib.ETH_ADDRESS) {\n // For ETH we just need to check that the supplied msg.value is correct\n if (amount != msg.value) revert MsgValueIncorrect();\n amountPulled = msg.value;\n } else {\n token.assertIsContract();\n // Record token balance before transfer\n amountPulled = IERC20(token).balanceOf(address(this));\n // Token needs to be pulled only if msg.value is zero\n // This way user can specify WETH as the origin asset\n IERC20(token).safeTransferFrom(msg.sender, address(this), amount);\n // Use the difference between the recorded balance and the current balance as the amountPulled\n amountPulled = IERC20(token).balanceOf(address(this)) - amountPulled;\n }\n }\n\n /// @notice Calls the Recipient's hook function with the specified callParams and performs\n /// all the necessary checks for the returned value.\n function _checkedCallRecipient(\n address recipient,\n address token,\n uint256 amount,\n bytes memory callParams\n )\n internal\n {\n bytes memory hookData =\n abi.encodeCall(IFastBridgeRecipient.fastBridgeTransferReceived, (token, amount, callParams));\n // This will bubble any revert messages from the hook function\n bytes memory returnData = Address.functionCallWithValue({target: recipient, data: hookData, value: msg.value});\n // Explicit revert if no return data at all\n if (returnData.length == 0) revert RecipientNoReturnValue();\n // Check that exactly a single return value was returned\n if (returnData.length != 32) revert RecipientIncorrectReturnValue();\n // Return value should be abi-encoded hook function selector\n if (bytes32(returnData) != bytes32(IFastBridgeRecipient.fastBridgeTransferReceived.selector)) {\n revert RecipientIncorrectReturnValue();\n }\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint40(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint40).max but\n /// proof.timestamp \u003c type(uint40).max via unchecked statement\n /// @param proofBlockTimestamp The bridge proof block timestamp\n /// @return delta Time delta since proof submitted\n function _timeSince(uint40 proofBlockTimestamp) internal view returns (uint256 delta) {\n unchecked {\n delta = uint40(block.timestamp) - proofBlockTimestamp;\n }\n }\n\n /// @notice Performs all the necessary checks for a bridge to happen.\n /// @dev There's no good way to refactor this function to reduce cyclomatic complexity due to\n /// the number of checks that need to be performed, so we skip the code-complexity rule here.\n // solhint-disable-next-line code-complexity\n function _validateBridgeParams(\n BridgeParams memory params,\n BridgeParamsV2 memory paramsV2,\n int256 exclusivityEndTime\n )\n internal\n view\n {\n // Check V1 (legacy) params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.sender == address(0) || params.to == address(0)) revert ZeroAddress();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n // Check V2 params\n if (paramsV2.callParams.length \u003e MAX_CALL_PARAMS_LENGTH) revert CallParamsLengthAboveMax();\n if (paramsV2.callValue != 0 \u0026\u0026 params.destToken == UniversalTokenLib.ETH_ADDRESS) {\n revert NativeTokenCallValueNotSupported();\n }\n // exclusivityEndTime must be in range (0 .. params.deadline]\n if (exclusivityEndTime \u003c= 0 || exclusivityEndTime \u003e int256(params.deadline)) {\n revert ExclusivityParamsIncorrect();\n }\n }\n\n /// @notice Performs all the necessary checks for a relay to happen.\n function _validateRelayParams(\n BridgeTransactionV2 memory transaction,\n bytes32 transactionId,\n address relayer\n )\n internal\n view\n {\n if (relayer == address(0)) revert ZeroAddress();\n // Check if the transaction has already been relayed\n if (bridgeRelays(transactionId)) revert TransactionRelayed();\n if (transaction.destChainId != uint32(block.chainid)) revert ChainIncorrect();\n // Check the deadline for relay to happen\n if (block.timestamp \u003e transaction.deadline) revert DeadlineExceeded();\n // Check the exclusivity period, if it is still ongoing\n // forgefmt: disable-next-item\n if (\n transaction.exclusivityRelayer != address(0) \u0026\u0026\n transaction.exclusivityRelayer != relayer \u0026\u0026\n block.timestamp \u003c= transaction.exclusivityEndTime\n ) {\n revert ExclusivityPeriodNotPassed();\n }\n }\n}\n","language":"Solidity","languageVersion":"0.8.24","compilerVersion":"0.8.24","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"62810:1843:0:-:0;;;63637:83;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;63675:38;52847:4;63706:6;63675:10;:38::i;:::-;;63637:83;62810:1843;;62160:257;62246:4;;62277:31;62294:4;62300:7;62277:16;:31::i;:::-;62262:46;;62322:7;62318:69;;;62345:18;;;;:12;:18;;;;;:31;;62368:7;62345:22;:31::i;:::-;;62318:69;62403:7;-1:-1:-1;62160:257:0;;;;;:::o;56794:316::-;56871:4;53569:12;;;;;;;;;;;-1:-1:-1;;;;;53569:29:0;;;;;;;;;;;;56887:217;;56930:6;:12;;;;;;;;;;;-1:-1:-1;;;;;56930:29:0;;;;;;;;;:36;;-1:-1:-1;;56930:36:0;56962:4;56930:36;;;57012:12;23368:10;;23289:96;57012:12;-1:-1:-1;;;;;56985:40:0;57003:7;-1:-1:-1;;;;;56985:40:0;56997:4;56985:40;;;;;;;;;;-1:-1:-1;57046:4:0;57039:11;;56887:217;-1:-1:-1;57088:5:0;57081:12;;32813:150;32883:4;32906:50;32911:3;-1:-1:-1;;;;;32931:23:0;;26801:4;28857:21;;;:14;;;:21;;;;;;26817:321;;-1:-1:-1;26859:23:0;;;;;;;;:11;:23;;;;;;;;;;;;;27041:18;;27017:21;;;:14;;;:21;;;;;;:42;;;;27073:11;;14:290:1;84:6;137:2;125:9;116:7;112:23;108:32;105:52;;;153:1;150;143:12;105:52;179:16;;-1:-1:-1;;;;;224:31:1;;214:42;;204:70;;270:1;267;260:12;14:290;62810:1843:0;;;;;;","srcMapRuntime":"62810:1843:0:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;60820:212;;;;;;:::i;:::-;;:::i;:::-;;;516:14:1;;509:22;491:41;;479:2;464:18;60820:212:0;;;;;;;;63050:60;;63087:23;63050:60;;;;;689:25:1;;;677:2;662:18;63050:60:0;543:177:1;64022:359:0;;;;;;:::i;:::-;;:::i;:::-;;63232:45;;63271:6;63232:45;;54425:120;;;;;;:::i;:::-;54490:7;54516:12;;;;;;;;;;:22;;;;54425:120;54841:136;;;;;;:::i;:::-;;:::i;55943:245::-;;;;;;:::i;:::-;;:::i;63394:30::-;;;;;;62978:66;;63018:26;62978:66;;61617:142;;;;;;:::i;:::-;;:::i;:::-;;;2246:42:1;2234:55;;;2216:74;;2204:2;2189:18;61617:142:0;2070:226:1;53469:136:0;;;;;;:::i;:::-;53546:4;53569:12;;;;;;;;;;;:29;;;;;;;;;;;;;;;;53469:136;62908:64;;62947:25;62908:64;;52802:49;;52847:4;52802:49;;63726:290;;;;;;:::i;:::-;;:::i;64387:264::-;;;;;;:::i;:::-;;:::i;63189:37::-;;63223:3;63189:37;;61927:131;;;;;;:::i;:::-;;:::i;63116:66::-;;63156:26;63116:66;;55257:138;;;;;;:::i;:::-;;:::i;63480:47::-;;;;;;:::i;:::-;;;;;;;;;;;;;;63601:29;;;;;;60820:212;60905:4;60928:57;;;60943:42;60928:57;;:97;;;60989:36;61013:11;60989:23;:36::i;:::-;60921:104;60820:212;-1:-1:-1;;60820:212:0:o;64022:359::-;63156:26;53079:16;53090:4;53079:10;:16::i;:::-;64146:19:::1;::::0;::::1;64126:17;64146:19:::0;;;:12:::1;:19;::::0;;;;;;64179:14;;;64175:27:::1;;64195:7;64022:359:::0;;;:::o;64175:27::-:1;64243:19;::::0;::::1;64265:1;64243:19:::0;;;:12:::1;:19;::::0;;;;:23;64276:45:::1;::::0;64300:9;64311;64276:23:::1;:45::i;:::-;64336:38;::::0;;2889:42:1;2958:15;;;2940:34;;3010:15;;3005:2;2990:18;;2983:43;3042:18;;;3035:34;;;64336:38:0::1;::::0;2867:2:1;2852:18;64336:38:0::1;;;;;;;64116:265;53105:1;64022:359:::0;;;:::o;54841:136::-;54490:7;54516:12;;;;;;;;;;:22;;;53079:16;53090:4;53079:10;:16::i;:::-;54945:25:::1;54956:4;54962:7;54945:10;:25::i;:::-;;54841:136:::0;;;:::o;55943:245::-;56036:34;;;23368:10;56036:34;56032:102;;56093:30;;;;;;;;;;;;;;56032:102;56144:37;56156:4;56162:18;56144:11;:37::i;61617:142::-;61698:7;61724:18;;;:12;:18;;;;;:28;;61746:5;61724:21;:28::i;:::-;61717:35;61617:142;-1:-1:-1;;;61617:142:0:o;63726:290::-;63156:26;53079:16;53090:4;53079:10;:16::i;:::-;63271:6:::1;63825:10;:26;;63817:55;;;::::0;::::1;::::0;;3282:2:1;63817:55:0::1;::::0;::::1;3264:21:1::0;3321:2;3301:18;;;3294:30;3360:18;3340;;;3333:46;3396:18;;63817:55:0::1;;;;;;;;;63903:15;::::0;;63928:28;;;;63971:38:::1;::::0;;3599:25:1;;;3655:2;3640:18;;3633:34;;;63971:38:0::1;::::0;3572:18:1;63971:38:0::1;;;;;;;;63807:209;63726:290:::0;;:::o;64387:264::-;63156:26;53079:16;53090:4;53079:10;:16::i;:::-;64512:14:::1;::::0;;64536:34;;;;64585:59:::1;::::0;;3599:25:1;;;3655:2;3640:18;;3633:34;;;64585:59:0::1;::::0;3572:18:1;64585:59:0::1;3425:248:1::0;61927:131:0;61998:7;62024:18;;;:12;:18;;;;;:27;;:25;:27::i;55257:138::-;54490:7;54516:12;;;;;;;;;;:22;;;53079:16;53090:4;53079:10;:16::i;:::-;55362:26:::1;55374:4;55380:7;55362:11;:26::i;53180:202::-:0;53265:4;53288:47;;;53303:32;53288:47;;:87;;-1:-1:-1;45095:25:0;45080:40;;;;53339:36;44981:146;53814:103;53880:30;53891:4;23368:10;53880;:30::i;:::-;53814:103;:::o;58092:653::-;58267:4;58253:19;;;;58249:32;;58092:653;;;:::o;58249:32::-;58353:5;58362:1;58353:10;58349:23;;58092:653;;;:::o;58349:23::-;58385:20;;;;;58381:358;;58565:12;58582:2;:7;;58597:5;58582:25;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;58564:43;;;58629:7;58621:39;;;;;;;4090:2:1;58621:39:0;;;4072:21:1;4129:2;4109:18;;;4102:30;4168:21;4148:18;;;4141:49;4207:18;;58621:39:0;3888:343:1;58381:358:0;58691:37;:26;;;58718:2;58722:5;58691:26;:37::i;62160:257::-;62246:4;62262:12;62277:31;62294:4;62300:7;62277:16;:31::i;:::-;62262:46;;62322:7;62318:69;;;62345:18;;;;:12;:18;;;;;:31;;62368:7;62345:22;:31::i;:::-;;62403:7;62160:257;-1:-1:-1;;;62160:257:0:o;62520:262::-;62607:4;62623:12;62638:32;62656:4;62662:7;62638:17;:32::i;:::-;62623:47;;62684:7;62680:72;;;62707:18;;;;:12;:18;;;;;:34;;62733:7;62707:25;:34::i;34071:156::-;34145:7;34195:22;34199:3;34211:5;34195:3;:22::i;33614:115::-;33677:7;33703:19;33711:3;29053:18;;28971:107;54047:197;53546:4;53569:12;;;;;;;;;;;:29;;;;;;;;;;;;;54130:108;;54180:47;;;;;4440:42:1;4428:55;;54180:47:0;;;4410:74:1;4500:18;;;4493:34;;;4383:18;;54180:47:0;4236:297:1;54130:108:0;54047:197;;:::o;46297:160::-;46406:43;;;46421:14;4428:55:1;;46406:43:0;;;4410:74:1;4500:18;;;;4493:34;;;46406:43:0;;;;;;;;;;4383:18:1;;;;46406:43:0;;;;;;;;;;;;;;46379:71;;46399:5;;46379:19;:71::i;56794:316::-;56871:4;53569:12;;;;;;;;;;;:29;;;;;;;;;;;;;56887:217;;56930:6;:12;;;;;;;;;;;:29;;;;;;;;;;:36;;;;56962:4;56930:36;;;57012:12;23368:10;;23289:96;57012:12;56985:40;;57003:7;56985:40;;56997:4;56985:40;;;;;;;;;;-1:-1:-1;57046:4:0;57039:11;;56887:217;-1:-1:-1;57088:5:0;57081:12;;32813:150;32883:4;32906:50;32911:3;32931:23;;;32906:4;:50::i;57345:317::-;57423:4;53569:12;;;;;;;;;;;:29;;;;;;;;;;;;;57439:217;;;57513:5;57481:12;;;;;;;;;;;:29;;;;;;;;;;;:37;;;;;;57537:40;23368:10;;57481:12;;57537:40;;57513:5;57537:40;-1:-1:-1;57598:4:0;57591:11;;33131:156;33204:4;33227:53;33235:3;33255:23;;;33227:7;:53::i;29420:118::-;29487:7;29513:3;:11;;29525:5;29513:18;;;;;;;;:::i;:::-;;;;;;;;;29506:25;;29420:118;;;;:::o;49053:629::-;49472:23;49498:33;:27;;;49526:4;49498:27;:33::i;:::-;49472:59;;49545:10;:17;49566:1;49545:22;;:57;;;;;49583:10;49572:30;;;;;;;;;;;;:::i;:::-;49571:31;49545:57;49541:135;;;49625:40;;;;;2246:42:1;2234:55;;49625:40:0;;;2216:74:1;2189:18;;49625:40:0;2070:226:1;26738:406:0;26801:4;28857:21;;;:14;;;:21;;;;;;26817:321;;-1:-1:-1;26859:23:0;;;;;;;;:11;:23;;;;;;;;;;;;;27041:18;;27017:21;;;:14;;;:21;;;;;;:42;;;;27073:11;;27312:1368;27378:4;27507:21;;;:14;;;:21;;;;;;27543:13;;27539:1135;;27910:18;27931:12;27942:1;27931:8;:12;:::i;:::-;27977:18;;27910:33;;-1:-1:-1;27957:17:0;;27977:22;;27998:1;;27977:22;:::i;:::-;27957:42;;28032:9;28018:10;:23;28014:378;;28061:17;28081:3;:11;;28093:9;28081:22;;;;;;;;:::i;:::-;;;;;;;;;28061:42;;28228:9;28202:3;:11;;28214:10;28202:23;;;;;;;;:::i;:::-;;;;;;;;;;;;:35;;;;28341:25;;;:14;;;:25;;;;;:36;;;28014:378;28470:17;;:3;;:17;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;28573:3;:14;;:21;28588:5;28573:21;;;;;;;;;;;28566:28;;;28616:4;28609:11;;;;;;;27539:1135;28658:5;28651:12;;;;;19074:151;19149:12;19180:38;19202:6;19210:4;19216:1;19149:12;19790;19804:23;19831:6;:11;;19850:5;19857:4;19831:31;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;19789:73;;;;19879:55;19906:6;19914:7;19923:10;19879:26;:55::i;:::-;19872:62;19549:392;-1:-1:-1;;;;;;19549:392:0:o;20994:582::-;21138:12;21167:7;21162:408;;21190:19;21198:10;21190:7;:19::i;:::-;21162:408;;;21414:17;;:22;:49;;;;-1:-1:-1;21440:18:0;;;;:23;21414:49;21410:119;;;21490:24;;;;;2246:42:1;2234:55;;21490:24:0;;;2216:74:1;2189:18;;21490:24:0;2070:226:1;21410:119:0;-1:-1:-1;21549:10:0;21542:17;;22112:516;22243:17;;:21;22239:383;;22471:10;22465:17;22527:15;22514:10;22510:2;22506:19;22499:44;22239:383;22594:17;;;;;;;;;;;;;;14:332:1;72:6;125:2;113:9;104:7;100:23;96:32;93:52;;;141:1;138;131:12;93:52;180:9;167:23;230:66;223:5;219:78;212:5;209:89;199:117;;312:1;309;302:12;725:196;793:20;;853:42;842:54;;832:65;;822:93;;911:1;908;901:12;822:93;725:196;;;:::o;926:260::-;994:6;1002;1055:2;1043:9;1034:7;1030:23;1026:32;1023:52;;;1071:1;1068;1061:12;1023:52;1094:29;1113:9;1094:29;:::i;:::-;1084:39;;1142:38;1176:2;1165:9;1161:18;1142:38;:::i;:::-;1132:48;;926:260;;;;;:::o;1373:180::-;1432:6;1485:2;1473:9;1464:7;1460:23;1456:32;1453:52;;;1501:1;1498;1491:12;1453:52;-1:-1:-1;1524:23:1;;1373:180;-1:-1:-1;1373:180:1:o;1558:254::-;1626:6;1634;1687:2;1675:9;1666:7;1662:23;1658:32;1655:52;;;1703:1;1700;1693:12;1655:52;1739:9;1726:23;1716:33;;1768:38;1802:2;1791:9;1787:18;1768:38;:::i;1817:248::-;1885:6;1893;1946:2;1934:9;1925:7;1921:23;1917:32;1914:52;;;1962:1;1959;1952:12;1914:52;-1:-1:-1;;1985:23:1;;;2055:2;2040:18;;;2027:32;;-1:-1:-1;1817:248:1:o;2486:186::-;2545:6;2598:2;2586:9;2577:7;2573:23;2569:32;2566:52;;;2614:1;2611;2604:12;2566:52;2637:29;2656:9;2637:29;:::i;4840:184::-;4892:77;4889:1;4882:88;4989:4;4986:1;4979:15;5013:4;5010:1;5003:15;5029:277;5096:6;5149:2;5137:9;5128:7;5124:23;5120:32;5117:52;;;5165:1;5162;5155:12;5117:52;5197:9;5191:16;5250:5;5243:13;5236:21;5229:5;5226:32;5216:60;;5272:1;5269;5262:12;5311:282;5378:9;;;5399:11;;;5396:191;;;5443:77;5440:1;5433:88;5544:4;5541:1;5534:15;5572:4;5569:1;5562:15;5598:184;5650:77;5647:1;5640:88;5747:4;5744:1;5737:15;5771:4;5768:1;5761:15;5787:412;5916:3;5954:6;5948:13;5979:1;5989:129;6003:6;6000:1;5997:13;5989:129;;;6101:4;6085:14;;;6081:25;;6075:32;6062:11;;;6055:53;6018:12;5989:129;;;-1:-1:-1;6173:1:1;6137:16;;6162:13;;;-1:-1:-1;6137:16:1;5787:412;-1:-1:-1;5787:412:1:o","abiDefinition":[{"inputs":[{"internalType":"address","name":"_owner","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AccessControlBadConfirmation","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"bytes32","name":"neededRole","type":"bytes32"}],"name":"AccessControlUnauthorizedAccount","type":"error"},{"inputs":[{"internalType":"address","name":"target","type":"address"}],"name":"AddressEmptyCode","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"AddressInsufficientBalance","type":"error"},{"inputs":[],"name":"FailedInnerCall","type":"error"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"SafeERC20FailedOperation","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldChainGasAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newChainGasAmount","type":"uint256"}],"name":"ChainGasAmountUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldFeeRate","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newFeeRate","type":"uint256"}],"name":"FeeRateUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"address","name":"recipient","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"FeesSwept","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"previousAdminRole","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"newAdminRole","type":"bytes32"}],"name":"RoleAdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleRevoked","type":"event"},{"inputs":[],"name":"DEFAULT_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"FEE_BPS","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"FEE_RATE_MAX","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"GOVERNOR_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"GUARD_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"REFUNDER_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"RELAYER_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"chainGasAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleAdmin","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"uint256","name":"index","type":"uint256"}],"name":"getRoleMember","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleMemberCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"grantRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"hasRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"protocolFeeRate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"protocolFees","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"callerConfirmation","type":"address"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"revokeRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"newChainGasAmount","type":"uint256"}],"name":"setChainGasAmount","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"newFeeRate","type":"uint256"}],"name":"setProtocolFeeRate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"address","name":"recipient","type":"address"}],"name":"sweepProtocolFees","outputs":[],"stateMutability":"nonpayable","type":"function"}],"userDoc":{"kind":"user","methods":{"chainGasAmount()":{"notice":"Chain gas amount to forward as rebate if requested"},"protocolFeeRate()":{"notice":"Protocol fee rate taken on origin amount deposited in origin chain"},"protocolFees(address)":{"notice":"Protocol fee amounts accumulated"}},"version":1},"developerDoc":{"errors":{"AccessControlBadConfirmation()":[{"details":"The caller of a function is not the expected one. NOTE: Don't confuse with {AccessControlUnauthorizedAccount}."}],"AccessControlUnauthorizedAccount(address,bytes32)":[{"details":"The `account` is missing a role."}],"AddressEmptyCode(address)":[{"details":"There's no code at `target` (it is not a contract)."}],"AddressInsufficientBalance(address)":[{"details":"The ETH balance of the account is not enough to perform the operation."}],"FailedInnerCall()":[{"details":"A call to an address target failed. The target may have reverted."}],"SafeERC20FailedOperation(address)":[{"details":"An operation with an ERC20 token failed."}]},"events":{"RoleAdminChanged(bytes32,bytes32,bytes32)":{"details":"Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole` `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite {RoleAdminChanged} not being emitted signaling this."},"RoleGranted(bytes32,address,address)":{"details":"Emitted when `account` is granted `role`. `sender` is the account that originated the contract call, an admin role bearer except when using {AccessControl-_setupRole}."},"RoleRevoked(bytes32,address,address)":{"details":"Emitted when `account` is revoked `role`. `sender` is the account that originated the contract call: - if using `revokeRole`, it is the admin role bearer - if using `renounceRole`, it is the role bearer (i.e. `account`)"}},"kind":"dev","methods":{"getRoleAdmin(bytes32)":{"details":"Returns the admin role that controls `role`. See {grantRole} and {revokeRole}. To change a role's admin, use {_setRoleAdmin}."},"getRoleMember(bytes32,uint256)":{"details":"Returns one of the accounts that have `role`. `index` must be a value between 0 and {getRoleMemberCount}, non-inclusive. Role bearers are not sorted in any particular way, and their ordering may change at any point. WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure you perform all queries on the same block. See the following https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post] for more information."},"getRoleMemberCount(bytes32)":{"details":"Returns the number of accounts that have `role`. Can be used together with {getRoleMember} to enumerate all bearers of a role."},"grantRole(bytes32,address)":{"details":"Grants `role` to `account`. If `account` had not been already granted `role`, emits a {RoleGranted} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleGranted} event."},"hasRole(bytes32,address)":{"details":"Returns `true` if `account` has been granted `role`."},"renounceRole(bytes32,address)":{"details":"Revokes `role` from the calling account. Roles are often managed via {grantRole} and {revokeRole}: this function's purpose is to provide a mechanism for accounts to lose their privileges if they are compromised (such as when a trusted device is misplaced). If the calling account had been revoked `role`, emits a {RoleRevoked} event. Requirements: - the caller must be `callerConfirmation`. May emit a {RoleRevoked} event."},"revokeRole(bytes32,address)":{"details":"Revokes `role` from `account`. If `account` had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleRevoked} event."},"supportsInterface(bytes4)":{"details":"See {IERC165-supportsInterface}."}},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_owner\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"AccessControlBadConfirmation\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"neededRole\",\"type\":\"bytes32\"}],\"name\":\"AccessControlUnauthorizedAccount\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"}],\"name\":\"AddressEmptyCode\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"AddressInsufficientBalance\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"FailedInnerCall\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"}],\"name\":\"SafeERC20FailedOperation\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"oldChainGasAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newChainGasAmount\",\"type\":\"uint256\"}],\"name\":\"ChainGasAmountUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"oldFeeRate\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newFeeRate\",\"type\":\"uint256\"}],\"name\":\"FeeRateUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"FeesSwept\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"previousAdminRole\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"newAdminRole\",\"type\":\"bytes32\"}],\"name\":\"RoleAdminChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleGranted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleRevoked\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"DEFAULT_ADMIN_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"FEE_BPS\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"FEE_RATE_MAX\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"GOVERNOR_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"GUARD_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"REFUNDER_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"RELAYER_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"chainGasAmount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"}],\"name\":\"getRoleAdmin\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"index\",\"type\":\"uint256\"}],\"name\":\"getRoleMember\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"}],\"name\":\"getRoleMemberCount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"grantRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"hasRole\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"protocolFeeRate\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"protocolFees\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"callerConfirmation\",\"type\":\"address\"}],\"name\":\"renounceRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"revokeRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"newChainGasAmount\",\"type\":\"uint256\"}],\"name\":\"setChainGasAmount\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"newFeeRate\",\"type\":\"uint256\"}],\"name\":\"setProtocolFeeRate\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes4\",\"name\":\"interfaceId\",\"type\":\"bytes4\"}],\"name\":\"supportsInterface\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"}],\"name\":\"sweepProtocolFees\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"errors\":{\"AccessControlBadConfirmation()\":[{\"details\":\"The caller of a function is not the expected one. NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\"}],\"AccessControlUnauthorizedAccount(address,bytes32)\":[{\"details\":\"The `account` is missing a role.\"}],\"AddressEmptyCode(address)\":[{\"details\":\"There's no code at `target` (it is not a contract).\"}],\"AddressInsufficientBalance(address)\":[{\"details\":\"The ETH balance of the account is not enough to perform the operation.\"}],\"FailedInnerCall()\":[{\"details\":\"A call to an address target failed. The target may have reverted.\"}],\"SafeERC20FailedOperation(address)\":[{\"details\":\"An operation with an ERC20 token failed.\"}]},\"events\":{\"RoleAdminChanged(bytes32,bytes32,bytes32)\":{\"details\":\"Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole` `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite {RoleAdminChanged} not being emitted signaling this.\"},\"RoleGranted(bytes32,address,address)\":{\"details\":\"Emitted when `account` is granted `role`. `sender` is the account that originated the contract call, an admin role bearer except when using {AccessControl-_setupRole}.\"},\"RoleRevoked(bytes32,address,address)\":{\"details\":\"Emitted when `account` is revoked `role`. `sender` is the account that originated the contract call: - if using `revokeRole`, it is the admin role bearer - if using `renounceRole`, it is the role bearer (i.e. `account`)\"}},\"kind\":\"dev\",\"methods\":{\"getRoleAdmin(bytes32)\":{\"details\":\"Returns the admin role that controls `role`. See {grantRole} and {revokeRole}. To change a role's admin, use {_setRoleAdmin}.\"},\"getRoleMember(bytes32,uint256)\":{\"details\":\"Returns one of the accounts that have `role`. `index` must be a value between 0 and {getRoleMemberCount}, non-inclusive. Role bearers are not sorted in any particular way, and their ordering may change at any point. WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure you perform all queries on the same block. See the following https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post] for more information.\"},\"getRoleMemberCount(bytes32)\":{\"details\":\"Returns the number of accounts that have `role`. Can be used together with {getRoleMember} to enumerate all bearers of a role.\"},\"grantRole(bytes32,address)\":{\"details\":\"Grants `role` to `account`. If `account` had not been already granted `role`, emits a {RoleGranted} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleGranted} event.\"},\"hasRole(bytes32,address)\":{\"details\":\"Returns `true` if `account` has been granted `role`.\"},\"renounceRole(bytes32,address)\":{\"details\":\"Revokes `role` from the calling account. Roles are often managed via {grantRole} and {revokeRole}: this function's purpose is to provide a mechanism for accounts to lose their privileges if they are compromised (such as when a trusted device is misplaced). If the calling account had been revoked `role`, emits a {RoleRevoked} event. Requirements: - the caller must be `callerConfirmation`. May emit a {RoleRevoked} event.\"},\"revokeRole(bytes32,address)\":{\"details\":\"Revokes `role` from `account`. If `account` had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleRevoked} event.\"},\"supportsInterface(bytes4)\":{\"details\":\"See {IERC165-supportsInterface}.\"}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"chainGasAmount()\":{\"notice\":\"Chain gas amount to forward as rebate if requested\"},\"protocolFeeRate()\":{\"notice\":\"Protocol fee rate taken on origin amount deposited in origin chain\"},\"protocolFees(address)\":{\"notice\":\"Protocol fee amounts accumulated\"}},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeV2.sol\":\"Admin\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeV2.sol\":{\"keccak256\":\"0x7cd0f885e80e2bdaa638bc32ae7af7d2e248f99ce4b354c217d0f0f7d7302e0a\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://7ccf28df0bd7b4606986585acd8622ed9b4e81379690061bb66088f0a2270af1\",\"dweb:/ipfs/QmTf7HNdHZkK6vmx8ZgewycQEb72oLD9nPwBpsM5reMstQ\"]}},\"version\":1}"},"hashes":{"DEFAULT_ADMIN_ROLE()":"a217fddf","FEE_BPS()":"bf333f2c","FEE_RATE_MAX()":"0f5f6ed7","GOVERNOR_ROLE()":"ccc57490","GUARD_ROLE()":"03ed0ee5","REFUNDER_ROLE()":"5960ccf2","RELAYER_ROLE()":"926d7d7f","chainGasAmount()":"e00a83e0","getRoleAdmin(bytes32)":"248a9ca3","getRoleMember(bytes32,uint256)":"9010d07c","getRoleMemberCount(bytes32)":"ca15c873","grantRole(bytes32,address)":"2f2ff15d","hasRole(bytes32,address)":"91d14854","protocolFeeRate()":"58f85880","protocolFees(address)":"dcf844a7","renounceRole(bytes32,address)":"36568abe","revokeRole(bytes32,address)":"d547741f","setChainGasAmount(uint256)":"b250fe6b","setProtocolFeeRate(uint256)":"b13aa2d6","supportsInterface(bytes4)":"01ffc9a7","sweepProtocolFees(address,address)":"06f333f2"}},"solidity/FastBridgeV2.sol:Context":{"code":"0x","runtime-code":"0x","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.24 ^0.8.0 ^0.8.20;\n\n// contracts/interfaces/IAdmin.sol\n\ninterface IAdmin {\n // ============ Events ============\n\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n event ChainGasAmountUpdated(uint256 oldChainGasAmount, uint256 newChainGasAmount);\n\n // ============ Methods ============\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n\n function setChainGasAmount(uint256 newChainGasAmount) external;\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IFastBridgeRecipient.sol\n\ninterface IFastBridgeRecipient {\n function fastBridgeTransferReceived(\n address token,\n uint256 amount,\n bytes memory callParams\n )\n external\n payable\n returns (bytes4);\n}\n\n// contracts/interfaces/IFastBridgeV2Errors.sol\n\ninterface IFastBridgeV2Errors {\n error AmountIncorrect();\n error CallParamsLengthAboveMax();\n error ChainIncorrect();\n error ExclusivityParamsIncorrect();\n error MsgValueIncorrect();\n error NativeTokenCallValueNotSupported();\n error SenderIncorrect();\n error StatusIncorrect();\n error ZeroAddress();\n\n error RecipientIncorrectReturnValue();\n error RecipientNoReturnValue();\n\n error DeadlineExceeded();\n error DeadlineNotExceeded();\n error DeadlineTooShort();\n error DisputePeriodNotPassed();\n error DisputePeriodPassed();\n error ExclusivityPeriodNotPassed();\n\n error TransactionRelayed();\n}\n\n// contracts/libs/Errors.sol\n\nerror DeadlineExceeded();\nerror DeadlineNotExceeded();\nerror DeadlineTooShort();\nerror InsufficientOutputAmount();\n\nerror MsgValueIncorrect();\nerror PoolNotFound();\nerror TokenAddressMismatch();\nerror TokenNotContract();\nerror TokenNotETH();\nerror TokensIdentical();\n\nerror ChainIncorrect();\nerror AmountIncorrect();\nerror ZeroAddress();\n\nerror DisputePeriodNotPassed();\nerror DisputePeriodPassed();\nerror SenderIncorrect();\nerror StatusIncorrect();\nerror TransactionIdIncorrect();\nerror TransactionRelayed();\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// contracts/interfaces/IFastBridgeV2.sol\n\ninterface IFastBridgeV2 is IFastBridge {\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n struct BridgeTxDetails {\n BridgeStatus status;\n uint40 proofBlockTimestamp;\n uint48 proofBlockNumber;\n address proofRelayer;\n }\n\n struct BridgeRelay {\n uint48 blockNumber;\n uint48 blockTimestamp;\n address relayer;\n }\n\n /// @notice New params introduced in the FastBridgeV2.\n /// We are passing fields from the older BridgeParams struct outside of this struct\n /// for backwards compatibility.\n /// Note: quoteRelayer and quoteExclusivitySeconds are either both zero (indicating no exclusivity)\n /// or both non-zero (indicating exclusivity for the given period).\n /// Note: callValue \u003e 0 can NOT be used with destToken = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE (ETH_ADDRESS)\n /// @param quoteRelayer Relayer that provided the quote for the transaction\n /// @param quoteExclusivitySeconds Period of time the quote relayer is guaranteed exclusivity after user's deposit\n /// @param quoteId Unique quote identifier used for tracking the quote\n /// @param callValue ETH value to send to the recipient (if any)\n /// @param callParams Parameters for the arbitrary call to the destination recipient (if any)\n struct BridgeParamsV2 {\n address quoteRelayer;\n int256 quoteExclusivitySeconds;\n bytes quoteId;\n uint256 callValue;\n bytes callParams;\n }\n\n /// @notice Updated bridge transaction struct to include parameters introduced in FastBridgeV2.\n /// Note: only `exclusivityRelayer` can fill such a transaction until `exclusivityEndTime`.\n /// TODO: consider changing the encoding scheme to prevent spending extra gas on decoding.\n struct BridgeTransactionV2 {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n uint256 callValue; // ETH value to send to the recipient (if any) - replaces V1's sendChainGas flag\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n address exclusivityRelayer;\n uint256 exclusivityEndTime;\n bytes callParams;\n }\n\n event BridgeQuoteDetails(bytes32 indexed transactionId, bytes quoteId);\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability\n /// to provide temporary exclusivity fill rights for the quote relayer.\n /// @param params The parameters required to bridge\n /// @param paramsV2 The parameters for exclusivity fill rights (optional, can be left empty)\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function relay(bytes memory request, address relayer) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param transactionId The transaction id associated with the encoded bridge transaction to prove\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital.\n /// @notice Can only send funds to the relayer address on the proof.\n /// @param request The encoded bridge transaction to claim on origin chain\n function claim(bytes memory request) external;\n /// @notice Checks if a transaction has been relayed\n /// @param transactionId The ID of the transaction to check\n /// @return True if the transaction has been relayed, false otherwise\n function bridgeRelays(bytes32 transactionId) external view returns (bool);\n\n /// @notice Returns the status of a bridge transaction\n /// @param transactionId The ID of the bridge transaction\n /// @return BridgeStatus Status of the bridge transaction\n function bridgeStatuses(bytes32 transactionId) external view returns (BridgeStatus);\n\n /// @notice Returns the timestamp and relayer of a bridge proof\n /// @param transactionId The ID of the bridge transaction\n /// @return timestamp The timestamp of the bridge proof\n /// @return relayer The relayer address of the bridge proof\n function bridgeProofs(bytes32 transactionId) external view returns (uint96 timestamp, address relayer);\n\n /// @notice Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\n /// @param request The bridge request to decode\n function getBridgeTransactionV2(bytes memory request) external view returns (BridgeTransactionV2 memory);\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// contracts/libs/UniversalToken.sol\n\nlibrary UniversalTokenLib {\n using SafeERC20 for IERC20;\n\n address internal constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Transfers tokens to the given account. Reverts if transfer is not successful.\n /// @dev This might trigger fallback, if ETH is transferred to the contract.\n /// Make sure this can not lead to reentrancy attacks.\n function universalTransfer(address token, address to, uint256 value) internal {\n // Don't do anything, if need to send tokens to this address\n if (to == address(this)) return;\n // Don't do anything, if trying to send zero value\n if (value == 0) return;\n if (token == ETH_ADDRESS) {\n /// @dev Note: this can potentially lead to executing code in `to`.\n // solhint-disable-next-line avoid-low-level-calls\n (bool success,) = to.call{value: value}(\"\");\n require(success, \"ETH transfer failed\");\n } else {\n IERC20(token).safeTransfer(to, value);\n }\n }\n\n /// @notice Issues an infinite allowance to the spender, if the current allowance is insufficient\n /// to spend the given amount.\n function universalApproveInfinity(address token, address spender, uint256 amountToSpend) internal {\n // ETH Chad doesn't require your approval\n if (token == ETH_ADDRESS) return;\n // No-op if allowance is already sufficient\n uint256 allowance = IERC20(token).allowance(address(this), spender);\n if (allowance \u003e= amountToSpend) return;\n // Otherwise, reset approval to 0 and set to max allowance\n if (allowance \u003e 0) IERC20(token).safeDecreaseAllowance(spender, allowance);\n IERC20(token).safeIncreaseAllowance(spender, type(uint256).max);\n }\n\n /// @notice Returns the balance of the given token (or native ETH) for the given account.\n function universalBalanceOf(address token, address account) internal view returns (uint256) {\n if (token == ETH_ADDRESS) {\n return account.balance;\n } else {\n return IERC20(token).balanceOf(account);\n }\n }\n\n /// @dev Checks that token is a contract and not ETH_ADDRESS.\n function assertIsContract(address token) internal view {\n // Check that ETH_ADDRESS was not used (in case this is a predeploy on any of the chains)\n if (token == UniversalTokenLib.ETH_ADDRESS) revert TokenNotContract();\n // Check that token is not an EOA\n if (token.code.length == 0) revert TokenNotContract();\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/Admin.sol\n\ncontract Admin is IAdmin, AccessControlEnumerable {\n using UniversalTokenLib for address;\n\n bytes32 public constant RELAYER_ROLE = keccak256(\"RELAYER_ROLE\");\n bytes32 public constant REFUNDER_ROLE = keccak256(\"REFUNDER_ROLE\");\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n uint256 public constant FEE_BPS = 1e6;\n uint256 public constant FEE_RATE_MAX = 0.01e6; // max 1% on origin amount\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Chain gas amount to forward as rebate if requested\n uint256 public chainGasAmount;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n }\n\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n require(newFeeRate \u003c= FEE_RATE_MAX, \"newFeeRate \u003e max\");\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n token.universalTransfer(recipient, feeAmount);\n emit FeesSwept(token, recipient, feeAmount);\n }\n\n function setChainGasAmount(uint256 newChainGasAmount) external onlyRole(GOVERNOR_ROLE) {\n uint256 oldChainGasAmount = chainGasAmount;\n chainGasAmount = newChainGasAmount;\n emit ChainGasAmountUpdated(oldChainGasAmount, newChainGasAmount);\n }\n}\n\n// contracts/FastBridgeV2.sol\n\n/// @notice FastBridgeV2 is a contract for bridging tokens across chains.\ncontract FastBridgeV2 is Admin, IFastBridgeV2, IFastBridgeV2Errors {\n using SafeERC20 for IERC20;\n using UniversalTokenLib for address;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Delay for a transaction after which it could be permisionlessly refunded\n uint256 public constant REFUND_DELAY = 7 days;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n /// @notice Maximum length of accepted callParams\n uint256 public constant MAX_CALL_PARAMS_LENGTH = 2 ** 16 - 1;\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeTxDetails) public bridgeTxDetails;\n /// @notice Relay details on destination chain\n mapping(bytes32 =\u003e BridgeRelay) public bridgeRelayDetails;\n /// @notice Unique bridge nonces tracked per originSender\n mapping(address =\u003e uint256) public senderNonces;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Replaced by senderNonces\n uint256 public immutable nonce = 0;\n /// @notice the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n bridge({\n params: params,\n paramsV2: BridgeParamsV2({\n quoteRelayer: address(0),\n quoteExclusivitySeconds: 0,\n quoteId: bytes(\"\"),\n callValue: 0,\n callParams: bytes(\"\")\n })\n });\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes memory request) external payable {\n relay({request: request, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes memory request, bytes32 destTxHash) external {\n prove({transactionId: keccak256(request), destTxHash: destTxHash, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridgeV2\n function claim(bytes memory request) external {\n claim({request: request, to: address(0)});\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003e DISPUTE_PERIOD) {\n revert DisputePeriodPassed();\n }\n\n // @dev relayer gets slashed effectively if dest relay has gone thru\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n bridgeTxDetails[transactionId].proofRelayer = address(0);\n bridgeTxDetails[transactionId].proofBlockTimestamp = 0;\n bridgeTxDetails[transactionId].proofBlockNumber = 0;\n\n emit BridgeProofDisputed(transactionId, msg.sender);\n }\n\n /// @inheritdoc IFastBridge\n function refund(bytes memory request) external {\n bytes32 transactionId = keccak256(request);\n\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n\n if (bridgeTxDetails[transactionId].status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n\n if (hasRole(REFUNDER_ROLE, msg.sender)) {\n // Refunder can refund if deadline has passed\n if (block.timestamp \u003c= transaction.deadline) revert DeadlineNotExceeded();\n } else {\n // Permissionless refund is allowed after REFUND_DELAY\n if (block.timestamp \u003c= transaction.deadline + REFUND_DELAY) revert DeadlineNotExceeded();\n }\n\n // if all checks passed, set to REFUNDED status\n bridgeTxDetails[transactionId].status = BridgeStatus.REFUNDED;\n\n // transfer origin collateral back to original sender\n address to = transaction.originSender;\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount + transaction.originFeeAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (bridgeTxDetails[transactionId].proofRelayer != relayer) revert SenderIncorrect();\n return _timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n /// @dev This method is added to achieve backwards compatibility with decoding requests into V1 structs:\n /// - `callValue` is partially reported as a zero/non-zero flag\n /// - `callParams` is ignored\n /// In order to process all kinds of requests use getBridgeTransactionV2 instead.\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory) {\n // Try decoding into V2 struct first. This will revert if V1 struct is passed\n try this.getBridgeTransactionV2(request) returns (BridgeTransactionV2 memory txV2) {\n // Note: we entirely ignore the callParams field, as it was not present in V1\n return BridgeTransaction({\n originChainId: txV2.originChainId,\n destChainId: txV2.destChainId,\n originSender: txV2.originSender,\n destRecipient: txV2.destRecipient,\n originToken: txV2.originToken,\n destToken: txV2.destToken,\n originAmount: txV2.originAmount,\n destAmount: txV2.destAmount,\n originFeeAmount: txV2.originFeeAmount,\n sendChainGas: txV2.callValue != 0,\n deadline: txV2.deadline,\n nonce: txV2.nonce\n });\n } catch {\n // Fallback to V1 struct\n return abi.decode(request, (BridgeTransaction));\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) public payable {\n int256 exclusivityEndTime = int256(block.timestamp) + paramsV2.quoteExclusivitySeconds;\n _validateBridgeParams(params, paramsV2, exclusivityEndTime);\n\n // transfer tokens to bridge contract\n /// @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _pullToken(params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n\n // set status to requested\n bytes memory request = abi.encode(\n BridgeTransactionV2({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n callValue: paramsV2.callValue,\n deadline: params.deadline,\n nonce: senderNonces[params.sender]++, // increment nonce on every bridge\n exclusivityRelayer: paramsV2.quoteRelayer,\n // We checked exclusivityEndTime to be in range (0 .. params.deadline] above, so can safely cast\n exclusivityEndTime: uint256(exclusivityEndTime),\n callParams: paramsV2.callParams\n })\n );\n bytes32 transactionId = keccak256(request);\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n\n emit BridgeRequested({\n transactionId: transactionId,\n sender: params.sender,\n request: request,\n destChainId: params.dstChainId,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n sendChainGas: paramsV2.callValue != 0\n });\n emit BridgeQuoteDetails(transactionId, paramsV2.quoteId);\n }\n\n /// @inheritdoc IFastBridgeV2\n function relay(bytes memory request, address relayer) public payable {\n bytes32 transactionId = keccak256(request);\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n _validateRelayParams(transaction, transactionId, relayer);\n // mark bridge transaction as relayed\n bridgeRelayDetails[transactionId] =\n BridgeRelay({blockNumber: uint48(block.number), blockTimestamp: uint48(block.timestamp), relayer: relayer});\n\n // transfer tokens to recipient on destination chain and do an arbitrary call if requested\n address to = transaction.destRecipient;\n address token = transaction.destToken;\n uint256 amount = transaction.destAmount;\n\n // All state changes have been done at this point, can proceed to the external calls.\n // This follows the checks-effects-interactions pattern to mitigate potential reentrancy attacks.\n if (token == UniversalTokenLib.ETH_ADDRESS) {\n // For ETH non-zero callValue is not allowed\n if (transaction.callValue != 0) revert NativeTokenCallValueNotSupported();\n // Check that the correct msg.value was sent\n if (msg.value != amount) revert MsgValueIncorrect();\n } else {\n // For ERC20s, we check that the correct msg.value was sent\n if (msg.value != transaction.callValue) revert MsgValueIncorrect();\n // We need to transfer the tokens from the Relayer to the recipient first before performing an\n // optional post-transfer arbitrary call.\n IERC20(token).safeTransferFrom(msg.sender, to, amount);\n }\n\n if (transaction.callParams.length != 0) {\n // Arbitrary call requested, perform it while supplying full msg.value to the recipient\n // Note: if token has a fee on transfers, the recipient will have received less than `amount`.\n // This is a very niche edge case and should be handled by the recipient contract.\n _checkedCallRecipient({recipient: to, token: token, amount: amount, callParams: transaction.callParams});\n } else if (msg.value != 0) {\n // No arbitrary call requested, but msg.value was sent. This is either a relay with ETH,\n // or a non-zero callValue request with an ERC20. In both cases, transfer the ETH to the recipient.\n Address.sendValue(payable(to), msg.value);\n }\n\n emit BridgeRelayed({\n transactionId: transactionId,\n relayer: relayer,\n to: to,\n originChainId: transaction.originChainId,\n originToken: transaction.originToken,\n destToken: transaction.destToken,\n originAmount: transaction.originAmount,\n destAmount: transaction.destAmount,\n chainGasAmount: transaction.callValue\n });\n }\n\n /// @inheritdoc IFastBridgeV2\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) public onlyRole(RELAYER_ROLE) {\n // update bridge tx status given proof provided\n if (bridgeTxDetails[transactionId].status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n bridgeTxDetails[transactionId].status = BridgeStatus.RELAYER_PROVED;\n bridgeTxDetails[transactionId].proofBlockTimestamp = uint40(block.timestamp);\n bridgeTxDetails[transactionId].proofBlockNumber = uint48(block.number);\n bridgeTxDetails[transactionId].proofRelayer = relayer;\n\n emit BridgeProofProvided(transactionId, relayer, destTxHash);\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes memory request, address to) public {\n bytes32 transactionId = keccak256(request);\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n\n // update bridge tx status if able to claim origin collateral\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n\n // if \"to\" is zero addr, permissionlessly send funds to proven relayer\n if (to == address(0)) {\n to = bridgeTxDetails[transactionId].proofRelayer;\n } else if (bridgeTxDetails[transactionId].proofRelayer != msg.sender) {\n revert SenderIncorrect();\n }\n\n if (_timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003c= DISPUTE_PERIOD) {\n revert DisputePeriodNotPassed();\n }\n\n bridgeTxDetails[transactionId].status = BridgeStatus.RELAYER_CLAIMED;\n\n // update protocol fees if origin fee amount exists\n if (transaction.originFeeAmount \u003e 0) protocolFees[transaction.originToken] += transaction.originFeeAmount;\n\n // transfer origin collateral less fee to specified address\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositClaimed(transactionId, bridgeTxDetails[transactionId].proofRelayer, to, token, amount);\n }\n\n function bridgeStatuses(bytes32 transactionId) public view returns (BridgeStatus status) {\n return bridgeTxDetails[transactionId].status;\n }\n\n function bridgeProofs(bytes32 transactionId) public view returns (uint96 timestamp, address relayer) {\n timestamp = bridgeTxDetails[transactionId].proofBlockTimestamp;\n relayer = bridgeTxDetails[transactionId].proofRelayer;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeRelays(bytes32 transactionId) public view returns (bool) {\n // has this transactionId been relayed?\n return bridgeRelayDetails[transactionId].relayer != address(0);\n }\n\n /// @inheritdoc IFastBridgeV2\n function getBridgeTransactionV2(bytes memory request) public pure returns (BridgeTransactionV2 memory) {\n return abi.decode(request, (BridgeTransactionV2));\n }\n\n /// @notice Pulls a requested token from the user to this contract.\n function _pullToken(address token, uint256 amount) internal returns (uint256 amountPulled) {\n if (token == UniversalTokenLib.ETH_ADDRESS) {\n // For ETH we just need to check that the supplied msg.value is correct\n if (amount != msg.value) revert MsgValueIncorrect();\n amountPulled = msg.value;\n } else {\n token.assertIsContract();\n // Record token balance before transfer\n amountPulled = IERC20(token).balanceOf(address(this));\n // Token needs to be pulled only if msg.value is zero\n // This way user can specify WETH as the origin asset\n IERC20(token).safeTransferFrom(msg.sender, address(this), amount);\n // Use the difference between the recorded balance and the current balance as the amountPulled\n amountPulled = IERC20(token).balanceOf(address(this)) - amountPulled;\n }\n }\n\n /// @notice Calls the Recipient's hook function with the specified callParams and performs\n /// all the necessary checks for the returned value.\n function _checkedCallRecipient(\n address recipient,\n address token,\n uint256 amount,\n bytes memory callParams\n )\n internal\n {\n bytes memory hookData =\n abi.encodeCall(IFastBridgeRecipient.fastBridgeTransferReceived, (token, amount, callParams));\n // This will bubble any revert messages from the hook function\n bytes memory returnData = Address.functionCallWithValue({target: recipient, data: hookData, value: msg.value});\n // Explicit revert if no return data at all\n if (returnData.length == 0) revert RecipientNoReturnValue();\n // Check that exactly a single return value was returned\n if (returnData.length != 32) revert RecipientIncorrectReturnValue();\n // Return value should be abi-encoded hook function selector\n if (bytes32(returnData) != bytes32(IFastBridgeRecipient.fastBridgeTransferReceived.selector)) {\n revert RecipientIncorrectReturnValue();\n }\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint40(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint40).max but\n /// proof.timestamp \u003c type(uint40).max via unchecked statement\n /// @param proofBlockTimestamp The bridge proof block timestamp\n /// @return delta Time delta since proof submitted\n function _timeSince(uint40 proofBlockTimestamp) internal view returns (uint256 delta) {\n unchecked {\n delta = uint40(block.timestamp) - proofBlockTimestamp;\n }\n }\n\n /// @notice Performs all the necessary checks for a bridge to happen.\n /// @dev There's no good way to refactor this function to reduce cyclomatic complexity due to\n /// the number of checks that need to be performed, so we skip the code-complexity rule here.\n // solhint-disable-next-line code-complexity\n function _validateBridgeParams(\n BridgeParams memory params,\n BridgeParamsV2 memory paramsV2,\n int256 exclusivityEndTime\n )\n internal\n view\n {\n // Check V1 (legacy) params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.sender == address(0) || params.to == address(0)) revert ZeroAddress();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n // Check V2 params\n if (paramsV2.callParams.length \u003e MAX_CALL_PARAMS_LENGTH) revert CallParamsLengthAboveMax();\n if (paramsV2.callValue != 0 \u0026\u0026 params.destToken == UniversalTokenLib.ETH_ADDRESS) {\n revert NativeTokenCallValueNotSupported();\n }\n // exclusivityEndTime must be in range (0 .. params.deadline]\n if (exclusivityEndTime \u003c= 0 || exclusivityEndTime \u003e int256(params.deadline)) {\n revert ExclusivityParamsIncorrect();\n }\n }\n\n /// @notice Performs all the necessary checks for a relay to happen.\n function _validateRelayParams(\n BridgeTransactionV2 memory transaction,\n bytes32 transactionId,\n address relayer\n )\n internal\n view\n {\n if (relayer == address(0)) revert ZeroAddress();\n // Check if the transaction has already been relayed\n if (bridgeRelays(transactionId)) revert TransactionRelayed();\n if (transaction.destChainId != uint32(block.chainid)) revert ChainIncorrect();\n // Check the deadline for relay to happen\n if (block.timestamp \u003e transaction.deadline) revert DeadlineExceeded();\n // Check the exclusivity period, if it is still ongoing\n // forgefmt: disable-next-item\n if (\n transaction.exclusivityRelayer != address(0) \u0026\u0026\n transaction.exclusivityRelayer != relayer \u0026\u0026\n block.timestamp \u003c= transaction.exclusivityEndTime\n ) {\n revert ExclusivityPeriodNotPassed();\n }\n }\n}\n","language":"Solidity","languageVersion":"0.8.24","compilerVersion":"0.8.24","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"","srcMapRuntime":"","abiDefinition":[],"userDoc":{"kind":"user","methods":{},"version":1},"developerDoc":{"details":"Provides information about the current execution context, including the sender of the transaction and its data. While these are generally available via msg.sender and msg.data, they should not be accessed in such a direct manner, since when dealing with meta-transactions the account sending and paying for execution may not be the actual sender (as far as an application is concerned). This contract is only required for intermediate, library-like contracts.","kind":"dev","methods":{},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[],\"devdoc\":{\"details\":\"Provides information about the current execution context, including the sender of the transaction and its data. While these are generally available via msg.sender and msg.data, they should not be accessed in such a direct manner, since when dealing with meta-transactions the account sending and paying for execution may not be the actual sender (as far as an application is concerned). This contract is only required for intermediate, library-like contracts.\",\"kind\":\"dev\",\"methods\":{},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeV2.sol\":\"Context\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeV2.sol\":{\"keccak256\":\"0x7cd0f885e80e2bdaa638bc32ae7af7d2e248f99ce4b354c217d0f0f7d7302e0a\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://7ccf28df0bd7b4606986585acd8622ed9b4e81379690061bb66088f0a2270af1\",\"dweb:/ipfs/QmTf7HNdHZkK6vmx8ZgewycQEb72oLD9nPwBpsM5reMstQ\"]}},\"version\":1}"},"hashes":{}},"solidity/FastBridgeV2.sol:ERC165":{"code":"0x","runtime-code":"0x","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.24 ^0.8.0 ^0.8.20;\n\n// contracts/interfaces/IAdmin.sol\n\ninterface IAdmin {\n // ============ Events ============\n\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n event ChainGasAmountUpdated(uint256 oldChainGasAmount, uint256 newChainGasAmount);\n\n // ============ Methods ============\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n\n function setChainGasAmount(uint256 newChainGasAmount) external;\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IFastBridgeRecipient.sol\n\ninterface IFastBridgeRecipient {\n function fastBridgeTransferReceived(\n address token,\n uint256 amount,\n bytes memory callParams\n )\n external\n payable\n returns (bytes4);\n}\n\n// contracts/interfaces/IFastBridgeV2Errors.sol\n\ninterface IFastBridgeV2Errors {\n error AmountIncorrect();\n error CallParamsLengthAboveMax();\n error ChainIncorrect();\n error ExclusivityParamsIncorrect();\n error MsgValueIncorrect();\n error NativeTokenCallValueNotSupported();\n error SenderIncorrect();\n error StatusIncorrect();\n error ZeroAddress();\n\n error RecipientIncorrectReturnValue();\n error RecipientNoReturnValue();\n\n error DeadlineExceeded();\n error DeadlineNotExceeded();\n error DeadlineTooShort();\n error DisputePeriodNotPassed();\n error DisputePeriodPassed();\n error ExclusivityPeriodNotPassed();\n\n error TransactionRelayed();\n}\n\n// contracts/libs/Errors.sol\n\nerror DeadlineExceeded();\nerror DeadlineNotExceeded();\nerror DeadlineTooShort();\nerror InsufficientOutputAmount();\n\nerror MsgValueIncorrect();\nerror PoolNotFound();\nerror TokenAddressMismatch();\nerror TokenNotContract();\nerror TokenNotETH();\nerror TokensIdentical();\n\nerror ChainIncorrect();\nerror AmountIncorrect();\nerror ZeroAddress();\n\nerror DisputePeriodNotPassed();\nerror DisputePeriodPassed();\nerror SenderIncorrect();\nerror StatusIncorrect();\nerror TransactionIdIncorrect();\nerror TransactionRelayed();\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// contracts/interfaces/IFastBridgeV2.sol\n\ninterface IFastBridgeV2 is IFastBridge {\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n struct BridgeTxDetails {\n BridgeStatus status;\n uint40 proofBlockTimestamp;\n uint48 proofBlockNumber;\n address proofRelayer;\n }\n\n struct BridgeRelay {\n uint48 blockNumber;\n uint48 blockTimestamp;\n address relayer;\n }\n\n /// @notice New params introduced in the FastBridgeV2.\n /// We are passing fields from the older BridgeParams struct outside of this struct\n /// for backwards compatibility.\n /// Note: quoteRelayer and quoteExclusivitySeconds are either both zero (indicating no exclusivity)\n /// or both non-zero (indicating exclusivity for the given period).\n /// Note: callValue \u003e 0 can NOT be used with destToken = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE (ETH_ADDRESS)\n /// @param quoteRelayer Relayer that provided the quote for the transaction\n /// @param quoteExclusivitySeconds Period of time the quote relayer is guaranteed exclusivity after user's deposit\n /// @param quoteId Unique quote identifier used for tracking the quote\n /// @param callValue ETH value to send to the recipient (if any)\n /// @param callParams Parameters for the arbitrary call to the destination recipient (if any)\n struct BridgeParamsV2 {\n address quoteRelayer;\n int256 quoteExclusivitySeconds;\n bytes quoteId;\n uint256 callValue;\n bytes callParams;\n }\n\n /// @notice Updated bridge transaction struct to include parameters introduced in FastBridgeV2.\n /// Note: only `exclusivityRelayer` can fill such a transaction until `exclusivityEndTime`.\n /// TODO: consider changing the encoding scheme to prevent spending extra gas on decoding.\n struct BridgeTransactionV2 {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n uint256 callValue; // ETH value to send to the recipient (if any) - replaces V1's sendChainGas flag\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n address exclusivityRelayer;\n uint256 exclusivityEndTime;\n bytes callParams;\n }\n\n event BridgeQuoteDetails(bytes32 indexed transactionId, bytes quoteId);\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability\n /// to provide temporary exclusivity fill rights for the quote relayer.\n /// @param params The parameters required to bridge\n /// @param paramsV2 The parameters for exclusivity fill rights (optional, can be left empty)\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function relay(bytes memory request, address relayer) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param transactionId The transaction id associated with the encoded bridge transaction to prove\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital.\n /// @notice Can only send funds to the relayer address on the proof.\n /// @param request The encoded bridge transaction to claim on origin chain\n function claim(bytes memory request) external;\n /// @notice Checks if a transaction has been relayed\n /// @param transactionId The ID of the transaction to check\n /// @return True if the transaction has been relayed, false otherwise\n function bridgeRelays(bytes32 transactionId) external view returns (bool);\n\n /// @notice Returns the status of a bridge transaction\n /// @param transactionId The ID of the bridge transaction\n /// @return BridgeStatus Status of the bridge transaction\n function bridgeStatuses(bytes32 transactionId) external view returns (BridgeStatus);\n\n /// @notice Returns the timestamp and relayer of a bridge proof\n /// @param transactionId The ID of the bridge transaction\n /// @return timestamp The timestamp of the bridge proof\n /// @return relayer The relayer address of the bridge proof\n function bridgeProofs(bytes32 transactionId) external view returns (uint96 timestamp, address relayer);\n\n /// @notice Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\n /// @param request The bridge request to decode\n function getBridgeTransactionV2(bytes memory request) external view returns (BridgeTransactionV2 memory);\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// contracts/libs/UniversalToken.sol\n\nlibrary UniversalTokenLib {\n using SafeERC20 for IERC20;\n\n address internal constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Transfers tokens to the given account. Reverts if transfer is not successful.\n /// @dev This might trigger fallback, if ETH is transferred to the contract.\n /// Make sure this can not lead to reentrancy attacks.\n function universalTransfer(address token, address to, uint256 value) internal {\n // Don't do anything, if need to send tokens to this address\n if (to == address(this)) return;\n // Don't do anything, if trying to send zero value\n if (value == 0) return;\n if (token == ETH_ADDRESS) {\n /// @dev Note: this can potentially lead to executing code in `to`.\n // solhint-disable-next-line avoid-low-level-calls\n (bool success,) = to.call{value: value}(\"\");\n require(success, \"ETH transfer failed\");\n } else {\n IERC20(token).safeTransfer(to, value);\n }\n }\n\n /// @notice Issues an infinite allowance to the spender, if the current allowance is insufficient\n /// to spend the given amount.\n function universalApproveInfinity(address token, address spender, uint256 amountToSpend) internal {\n // ETH Chad doesn't require your approval\n if (token == ETH_ADDRESS) return;\n // No-op if allowance is already sufficient\n uint256 allowance = IERC20(token).allowance(address(this), spender);\n if (allowance \u003e= amountToSpend) return;\n // Otherwise, reset approval to 0 and set to max allowance\n if (allowance \u003e 0) IERC20(token).safeDecreaseAllowance(spender, allowance);\n IERC20(token).safeIncreaseAllowance(spender, type(uint256).max);\n }\n\n /// @notice Returns the balance of the given token (or native ETH) for the given account.\n function universalBalanceOf(address token, address account) internal view returns (uint256) {\n if (token == ETH_ADDRESS) {\n return account.balance;\n } else {\n return IERC20(token).balanceOf(account);\n }\n }\n\n /// @dev Checks that token is a contract and not ETH_ADDRESS.\n function assertIsContract(address token) internal view {\n // Check that ETH_ADDRESS was not used (in case this is a predeploy on any of the chains)\n if (token == UniversalTokenLib.ETH_ADDRESS) revert TokenNotContract();\n // Check that token is not an EOA\n if (token.code.length == 0) revert TokenNotContract();\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/Admin.sol\n\ncontract Admin is IAdmin, AccessControlEnumerable {\n using UniversalTokenLib for address;\n\n bytes32 public constant RELAYER_ROLE = keccak256(\"RELAYER_ROLE\");\n bytes32 public constant REFUNDER_ROLE = keccak256(\"REFUNDER_ROLE\");\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n uint256 public constant FEE_BPS = 1e6;\n uint256 public constant FEE_RATE_MAX = 0.01e6; // max 1% on origin amount\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Chain gas amount to forward as rebate if requested\n uint256 public chainGasAmount;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n }\n\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n require(newFeeRate \u003c= FEE_RATE_MAX, \"newFeeRate \u003e max\");\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n token.universalTransfer(recipient, feeAmount);\n emit FeesSwept(token, recipient, feeAmount);\n }\n\n function setChainGasAmount(uint256 newChainGasAmount) external onlyRole(GOVERNOR_ROLE) {\n uint256 oldChainGasAmount = chainGasAmount;\n chainGasAmount = newChainGasAmount;\n emit ChainGasAmountUpdated(oldChainGasAmount, newChainGasAmount);\n }\n}\n\n// contracts/FastBridgeV2.sol\n\n/// @notice FastBridgeV2 is a contract for bridging tokens across chains.\ncontract FastBridgeV2 is Admin, IFastBridgeV2, IFastBridgeV2Errors {\n using SafeERC20 for IERC20;\n using UniversalTokenLib for address;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Delay for a transaction after which it could be permisionlessly refunded\n uint256 public constant REFUND_DELAY = 7 days;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n /// @notice Maximum length of accepted callParams\n uint256 public constant MAX_CALL_PARAMS_LENGTH = 2 ** 16 - 1;\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeTxDetails) public bridgeTxDetails;\n /// @notice Relay details on destination chain\n mapping(bytes32 =\u003e BridgeRelay) public bridgeRelayDetails;\n /// @notice Unique bridge nonces tracked per originSender\n mapping(address =\u003e uint256) public senderNonces;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Replaced by senderNonces\n uint256 public immutable nonce = 0;\n /// @notice the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n bridge({\n params: params,\n paramsV2: BridgeParamsV2({\n quoteRelayer: address(0),\n quoteExclusivitySeconds: 0,\n quoteId: bytes(\"\"),\n callValue: 0,\n callParams: bytes(\"\")\n })\n });\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes memory request) external payable {\n relay({request: request, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes memory request, bytes32 destTxHash) external {\n prove({transactionId: keccak256(request), destTxHash: destTxHash, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridgeV2\n function claim(bytes memory request) external {\n claim({request: request, to: address(0)});\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003e DISPUTE_PERIOD) {\n revert DisputePeriodPassed();\n }\n\n // @dev relayer gets slashed effectively if dest relay has gone thru\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n bridgeTxDetails[transactionId].proofRelayer = address(0);\n bridgeTxDetails[transactionId].proofBlockTimestamp = 0;\n bridgeTxDetails[transactionId].proofBlockNumber = 0;\n\n emit BridgeProofDisputed(transactionId, msg.sender);\n }\n\n /// @inheritdoc IFastBridge\n function refund(bytes memory request) external {\n bytes32 transactionId = keccak256(request);\n\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n\n if (bridgeTxDetails[transactionId].status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n\n if (hasRole(REFUNDER_ROLE, msg.sender)) {\n // Refunder can refund if deadline has passed\n if (block.timestamp \u003c= transaction.deadline) revert DeadlineNotExceeded();\n } else {\n // Permissionless refund is allowed after REFUND_DELAY\n if (block.timestamp \u003c= transaction.deadline + REFUND_DELAY) revert DeadlineNotExceeded();\n }\n\n // if all checks passed, set to REFUNDED status\n bridgeTxDetails[transactionId].status = BridgeStatus.REFUNDED;\n\n // transfer origin collateral back to original sender\n address to = transaction.originSender;\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount + transaction.originFeeAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (bridgeTxDetails[transactionId].proofRelayer != relayer) revert SenderIncorrect();\n return _timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n /// @dev This method is added to achieve backwards compatibility with decoding requests into V1 structs:\n /// - `callValue` is partially reported as a zero/non-zero flag\n /// - `callParams` is ignored\n /// In order to process all kinds of requests use getBridgeTransactionV2 instead.\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory) {\n // Try decoding into V2 struct first. This will revert if V1 struct is passed\n try this.getBridgeTransactionV2(request) returns (BridgeTransactionV2 memory txV2) {\n // Note: we entirely ignore the callParams field, as it was not present in V1\n return BridgeTransaction({\n originChainId: txV2.originChainId,\n destChainId: txV2.destChainId,\n originSender: txV2.originSender,\n destRecipient: txV2.destRecipient,\n originToken: txV2.originToken,\n destToken: txV2.destToken,\n originAmount: txV2.originAmount,\n destAmount: txV2.destAmount,\n originFeeAmount: txV2.originFeeAmount,\n sendChainGas: txV2.callValue != 0,\n deadline: txV2.deadline,\n nonce: txV2.nonce\n });\n } catch {\n // Fallback to V1 struct\n return abi.decode(request, (BridgeTransaction));\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) public payable {\n int256 exclusivityEndTime = int256(block.timestamp) + paramsV2.quoteExclusivitySeconds;\n _validateBridgeParams(params, paramsV2, exclusivityEndTime);\n\n // transfer tokens to bridge contract\n /// @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _pullToken(params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n\n // set status to requested\n bytes memory request = abi.encode(\n BridgeTransactionV2({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n callValue: paramsV2.callValue,\n deadline: params.deadline,\n nonce: senderNonces[params.sender]++, // increment nonce on every bridge\n exclusivityRelayer: paramsV2.quoteRelayer,\n // We checked exclusivityEndTime to be in range (0 .. params.deadline] above, so can safely cast\n exclusivityEndTime: uint256(exclusivityEndTime),\n callParams: paramsV2.callParams\n })\n );\n bytes32 transactionId = keccak256(request);\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n\n emit BridgeRequested({\n transactionId: transactionId,\n sender: params.sender,\n request: request,\n destChainId: params.dstChainId,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n sendChainGas: paramsV2.callValue != 0\n });\n emit BridgeQuoteDetails(transactionId, paramsV2.quoteId);\n }\n\n /// @inheritdoc IFastBridgeV2\n function relay(bytes memory request, address relayer) public payable {\n bytes32 transactionId = keccak256(request);\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n _validateRelayParams(transaction, transactionId, relayer);\n // mark bridge transaction as relayed\n bridgeRelayDetails[transactionId] =\n BridgeRelay({blockNumber: uint48(block.number), blockTimestamp: uint48(block.timestamp), relayer: relayer});\n\n // transfer tokens to recipient on destination chain and do an arbitrary call if requested\n address to = transaction.destRecipient;\n address token = transaction.destToken;\n uint256 amount = transaction.destAmount;\n\n // All state changes have been done at this point, can proceed to the external calls.\n // This follows the checks-effects-interactions pattern to mitigate potential reentrancy attacks.\n if (token == UniversalTokenLib.ETH_ADDRESS) {\n // For ETH non-zero callValue is not allowed\n if (transaction.callValue != 0) revert NativeTokenCallValueNotSupported();\n // Check that the correct msg.value was sent\n if (msg.value != amount) revert MsgValueIncorrect();\n } else {\n // For ERC20s, we check that the correct msg.value was sent\n if (msg.value != transaction.callValue) revert MsgValueIncorrect();\n // We need to transfer the tokens from the Relayer to the recipient first before performing an\n // optional post-transfer arbitrary call.\n IERC20(token).safeTransferFrom(msg.sender, to, amount);\n }\n\n if (transaction.callParams.length != 0) {\n // Arbitrary call requested, perform it while supplying full msg.value to the recipient\n // Note: if token has a fee on transfers, the recipient will have received less than `amount`.\n // This is a very niche edge case and should be handled by the recipient contract.\n _checkedCallRecipient({recipient: to, token: token, amount: amount, callParams: transaction.callParams});\n } else if (msg.value != 0) {\n // No arbitrary call requested, but msg.value was sent. This is either a relay with ETH,\n // or a non-zero callValue request with an ERC20. In both cases, transfer the ETH to the recipient.\n Address.sendValue(payable(to), msg.value);\n }\n\n emit BridgeRelayed({\n transactionId: transactionId,\n relayer: relayer,\n to: to,\n originChainId: transaction.originChainId,\n originToken: transaction.originToken,\n destToken: transaction.destToken,\n originAmount: transaction.originAmount,\n destAmount: transaction.destAmount,\n chainGasAmount: transaction.callValue\n });\n }\n\n /// @inheritdoc IFastBridgeV2\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) public onlyRole(RELAYER_ROLE) {\n // update bridge tx status given proof provided\n if (bridgeTxDetails[transactionId].status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n bridgeTxDetails[transactionId].status = BridgeStatus.RELAYER_PROVED;\n bridgeTxDetails[transactionId].proofBlockTimestamp = uint40(block.timestamp);\n bridgeTxDetails[transactionId].proofBlockNumber = uint48(block.number);\n bridgeTxDetails[transactionId].proofRelayer = relayer;\n\n emit BridgeProofProvided(transactionId, relayer, destTxHash);\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes memory request, address to) public {\n bytes32 transactionId = keccak256(request);\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n\n // update bridge tx status if able to claim origin collateral\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n\n // if \"to\" is zero addr, permissionlessly send funds to proven relayer\n if (to == address(0)) {\n to = bridgeTxDetails[transactionId].proofRelayer;\n } else if (bridgeTxDetails[transactionId].proofRelayer != msg.sender) {\n revert SenderIncorrect();\n }\n\n if (_timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003c= DISPUTE_PERIOD) {\n revert DisputePeriodNotPassed();\n }\n\n bridgeTxDetails[transactionId].status = BridgeStatus.RELAYER_CLAIMED;\n\n // update protocol fees if origin fee amount exists\n if (transaction.originFeeAmount \u003e 0) protocolFees[transaction.originToken] += transaction.originFeeAmount;\n\n // transfer origin collateral less fee to specified address\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositClaimed(transactionId, bridgeTxDetails[transactionId].proofRelayer, to, token, amount);\n }\n\n function bridgeStatuses(bytes32 transactionId) public view returns (BridgeStatus status) {\n return bridgeTxDetails[transactionId].status;\n }\n\n function bridgeProofs(bytes32 transactionId) public view returns (uint96 timestamp, address relayer) {\n timestamp = bridgeTxDetails[transactionId].proofBlockTimestamp;\n relayer = bridgeTxDetails[transactionId].proofRelayer;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeRelays(bytes32 transactionId) public view returns (bool) {\n // has this transactionId been relayed?\n return bridgeRelayDetails[transactionId].relayer != address(0);\n }\n\n /// @inheritdoc IFastBridgeV2\n function getBridgeTransactionV2(bytes memory request) public pure returns (BridgeTransactionV2 memory) {\n return abi.decode(request, (BridgeTransactionV2));\n }\n\n /// @notice Pulls a requested token from the user to this contract.\n function _pullToken(address token, uint256 amount) internal returns (uint256 amountPulled) {\n if (token == UniversalTokenLib.ETH_ADDRESS) {\n // For ETH we just need to check that the supplied msg.value is correct\n if (amount != msg.value) revert MsgValueIncorrect();\n amountPulled = msg.value;\n } else {\n token.assertIsContract();\n // Record token balance before transfer\n amountPulled = IERC20(token).balanceOf(address(this));\n // Token needs to be pulled only if msg.value is zero\n // This way user can specify WETH as the origin asset\n IERC20(token).safeTransferFrom(msg.sender, address(this), amount);\n // Use the difference between the recorded balance and the current balance as the amountPulled\n amountPulled = IERC20(token).balanceOf(address(this)) - amountPulled;\n }\n }\n\n /// @notice Calls the Recipient's hook function with the specified callParams and performs\n /// all the necessary checks for the returned value.\n function _checkedCallRecipient(\n address recipient,\n address token,\n uint256 amount,\n bytes memory callParams\n )\n internal\n {\n bytes memory hookData =\n abi.encodeCall(IFastBridgeRecipient.fastBridgeTransferReceived, (token, amount, callParams));\n // This will bubble any revert messages from the hook function\n bytes memory returnData = Address.functionCallWithValue({target: recipient, data: hookData, value: msg.value});\n // Explicit revert if no return data at all\n if (returnData.length == 0) revert RecipientNoReturnValue();\n // Check that exactly a single return value was returned\n if (returnData.length != 32) revert RecipientIncorrectReturnValue();\n // Return value should be abi-encoded hook function selector\n if (bytes32(returnData) != bytes32(IFastBridgeRecipient.fastBridgeTransferReceived.selector)) {\n revert RecipientIncorrectReturnValue();\n }\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint40(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint40).max but\n /// proof.timestamp \u003c type(uint40).max via unchecked statement\n /// @param proofBlockTimestamp The bridge proof block timestamp\n /// @return delta Time delta since proof submitted\n function _timeSince(uint40 proofBlockTimestamp) internal view returns (uint256 delta) {\n unchecked {\n delta = uint40(block.timestamp) - proofBlockTimestamp;\n }\n }\n\n /// @notice Performs all the necessary checks for a bridge to happen.\n /// @dev There's no good way to refactor this function to reduce cyclomatic complexity due to\n /// the number of checks that need to be performed, so we skip the code-complexity rule here.\n // solhint-disable-next-line code-complexity\n function _validateBridgeParams(\n BridgeParams memory params,\n BridgeParamsV2 memory paramsV2,\n int256 exclusivityEndTime\n )\n internal\n view\n {\n // Check V1 (legacy) params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.sender == address(0) || params.to == address(0)) revert ZeroAddress();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n // Check V2 params\n if (paramsV2.callParams.length \u003e MAX_CALL_PARAMS_LENGTH) revert CallParamsLengthAboveMax();\n if (paramsV2.callValue != 0 \u0026\u0026 params.destToken == UniversalTokenLib.ETH_ADDRESS) {\n revert NativeTokenCallValueNotSupported();\n }\n // exclusivityEndTime must be in range (0 .. params.deadline]\n if (exclusivityEndTime \u003c= 0 || exclusivityEndTime \u003e int256(params.deadline)) {\n revert ExclusivityParamsIncorrect();\n }\n }\n\n /// @notice Performs all the necessary checks for a relay to happen.\n function _validateRelayParams(\n BridgeTransactionV2 memory transaction,\n bytes32 transactionId,\n address relayer\n )\n internal\n view\n {\n if (relayer == address(0)) revert ZeroAddress();\n // Check if the transaction has already been relayed\n if (bridgeRelays(transactionId)) revert TransactionRelayed();\n if (transaction.destChainId != uint32(block.chainid)) revert ChainIncorrect();\n // Check the deadline for relay to happen\n if (block.timestamp \u003e transaction.deadline) revert DeadlineExceeded();\n // Check the exclusivity period, if it is still ongoing\n // forgefmt: disable-next-item\n if (\n transaction.exclusivityRelayer != address(0) \u0026\u0026\n transaction.exclusivityRelayer != relayer \u0026\u0026\n block.timestamp \u003c= transaction.exclusivityEndTime\n ) {\n revert ExclusivityPeriodNotPassed();\n }\n }\n}\n","language":"Solidity","languageVersion":"0.8.24","compilerVersion":"0.8.24","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"","srcMapRuntime":"","abiDefinition":[{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"}],"userDoc":{"kind":"user","methods":{},"version":1},"developerDoc":{"details":"Implementation of the {IERC165} interface. Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check for the additional interface id that will be supported. For example: ```solidity function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId); } ```","kind":"dev","methods":{"supportsInterface(bytes4)":{"details":"See {IERC165-supportsInterface}."}},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"bytes4\",\"name\":\"interfaceId\",\"type\":\"bytes4\"}],\"name\":\"supportsInterface\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"}],\"devdoc\":{\"details\":\"Implementation of the {IERC165} interface. Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check for the additional interface id that will be supported. For example: ```solidity function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId); } ```\",\"kind\":\"dev\",\"methods\":{\"supportsInterface(bytes4)\":{\"details\":\"See {IERC165-supportsInterface}.\"}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeV2.sol\":\"ERC165\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeV2.sol\":{\"keccak256\":\"0x7cd0f885e80e2bdaa638bc32ae7af7d2e248f99ce4b354c217d0f0f7d7302e0a\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://7ccf28df0bd7b4606986585acd8622ed9b4e81379690061bb66088f0a2270af1\",\"dweb:/ipfs/QmTf7HNdHZkK6vmx8ZgewycQEb72oLD9nPwBpsM5reMstQ\"]}},\"version\":1}"},"hashes":{"supportsInterface(bytes4)":"01ffc9a7"}},"solidity/FastBridgeV2.sol:EnumerableSet":{"code":"0x60566037600b82828239805160001a607314602a57634e487b7160e01b600052600060045260246000fd5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600080fdfea2646970667358221220c93e0a4d209c73a0e712af3f8fe75c461fc5f2c8421cf7a3112f43749245c31a64736f6c63430008180033","runtime-code":"0x73000000000000000000000000000000000000000030146080604052600080fdfea2646970667358221220c93e0a4d209c73a0e712af3f8fe75c461fc5f2c8421cf7a3112f43749245c31a64736f6c63430008180033","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.24 ^0.8.0 ^0.8.20;\n\n// contracts/interfaces/IAdmin.sol\n\ninterface IAdmin {\n // ============ Events ============\n\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n event ChainGasAmountUpdated(uint256 oldChainGasAmount, uint256 newChainGasAmount);\n\n // ============ Methods ============\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n\n function setChainGasAmount(uint256 newChainGasAmount) external;\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IFastBridgeRecipient.sol\n\ninterface IFastBridgeRecipient {\n function fastBridgeTransferReceived(\n address token,\n uint256 amount,\n bytes memory callParams\n )\n external\n payable\n returns (bytes4);\n}\n\n// contracts/interfaces/IFastBridgeV2Errors.sol\n\ninterface IFastBridgeV2Errors {\n error AmountIncorrect();\n error CallParamsLengthAboveMax();\n error ChainIncorrect();\n error ExclusivityParamsIncorrect();\n error MsgValueIncorrect();\n error NativeTokenCallValueNotSupported();\n error SenderIncorrect();\n error StatusIncorrect();\n error ZeroAddress();\n\n error RecipientIncorrectReturnValue();\n error RecipientNoReturnValue();\n\n error DeadlineExceeded();\n error DeadlineNotExceeded();\n error DeadlineTooShort();\n error DisputePeriodNotPassed();\n error DisputePeriodPassed();\n error ExclusivityPeriodNotPassed();\n\n error TransactionRelayed();\n}\n\n// contracts/libs/Errors.sol\n\nerror DeadlineExceeded();\nerror DeadlineNotExceeded();\nerror DeadlineTooShort();\nerror InsufficientOutputAmount();\n\nerror MsgValueIncorrect();\nerror PoolNotFound();\nerror TokenAddressMismatch();\nerror TokenNotContract();\nerror TokenNotETH();\nerror TokensIdentical();\n\nerror ChainIncorrect();\nerror AmountIncorrect();\nerror ZeroAddress();\n\nerror DisputePeriodNotPassed();\nerror DisputePeriodPassed();\nerror SenderIncorrect();\nerror StatusIncorrect();\nerror TransactionIdIncorrect();\nerror TransactionRelayed();\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// contracts/interfaces/IFastBridgeV2.sol\n\ninterface IFastBridgeV2 is IFastBridge {\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n struct BridgeTxDetails {\n BridgeStatus status;\n uint40 proofBlockTimestamp;\n uint48 proofBlockNumber;\n address proofRelayer;\n }\n\n struct BridgeRelay {\n uint48 blockNumber;\n uint48 blockTimestamp;\n address relayer;\n }\n\n /// @notice New params introduced in the FastBridgeV2.\n /// We are passing fields from the older BridgeParams struct outside of this struct\n /// for backwards compatibility.\n /// Note: quoteRelayer and quoteExclusivitySeconds are either both zero (indicating no exclusivity)\n /// or both non-zero (indicating exclusivity for the given period).\n /// Note: callValue \u003e 0 can NOT be used with destToken = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE (ETH_ADDRESS)\n /// @param quoteRelayer Relayer that provided the quote for the transaction\n /// @param quoteExclusivitySeconds Period of time the quote relayer is guaranteed exclusivity after user's deposit\n /// @param quoteId Unique quote identifier used for tracking the quote\n /// @param callValue ETH value to send to the recipient (if any)\n /// @param callParams Parameters for the arbitrary call to the destination recipient (if any)\n struct BridgeParamsV2 {\n address quoteRelayer;\n int256 quoteExclusivitySeconds;\n bytes quoteId;\n uint256 callValue;\n bytes callParams;\n }\n\n /// @notice Updated bridge transaction struct to include parameters introduced in FastBridgeV2.\n /// Note: only `exclusivityRelayer` can fill such a transaction until `exclusivityEndTime`.\n /// TODO: consider changing the encoding scheme to prevent spending extra gas on decoding.\n struct BridgeTransactionV2 {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n uint256 callValue; // ETH value to send to the recipient (if any) - replaces V1's sendChainGas flag\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n address exclusivityRelayer;\n uint256 exclusivityEndTime;\n bytes callParams;\n }\n\n event BridgeQuoteDetails(bytes32 indexed transactionId, bytes quoteId);\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability\n /// to provide temporary exclusivity fill rights for the quote relayer.\n /// @param params The parameters required to bridge\n /// @param paramsV2 The parameters for exclusivity fill rights (optional, can be left empty)\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function relay(bytes memory request, address relayer) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param transactionId The transaction id associated with the encoded bridge transaction to prove\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital.\n /// @notice Can only send funds to the relayer address on the proof.\n /// @param request The encoded bridge transaction to claim on origin chain\n function claim(bytes memory request) external;\n /// @notice Checks if a transaction has been relayed\n /// @param transactionId The ID of the transaction to check\n /// @return True if the transaction has been relayed, false otherwise\n function bridgeRelays(bytes32 transactionId) external view returns (bool);\n\n /// @notice Returns the status of a bridge transaction\n /// @param transactionId The ID of the bridge transaction\n /// @return BridgeStatus Status of the bridge transaction\n function bridgeStatuses(bytes32 transactionId) external view returns (BridgeStatus);\n\n /// @notice Returns the timestamp and relayer of a bridge proof\n /// @param transactionId The ID of the bridge transaction\n /// @return timestamp The timestamp of the bridge proof\n /// @return relayer The relayer address of the bridge proof\n function bridgeProofs(bytes32 transactionId) external view returns (uint96 timestamp, address relayer);\n\n /// @notice Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\n /// @param request The bridge request to decode\n function getBridgeTransactionV2(bytes memory request) external view returns (BridgeTransactionV2 memory);\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// contracts/libs/UniversalToken.sol\n\nlibrary UniversalTokenLib {\n using SafeERC20 for IERC20;\n\n address internal constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Transfers tokens to the given account. Reverts if transfer is not successful.\n /// @dev This might trigger fallback, if ETH is transferred to the contract.\n /// Make sure this can not lead to reentrancy attacks.\n function universalTransfer(address token, address to, uint256 value) internal {\n // Don't do anything, if need to send tokens to this address\n if (to == address(this)) return;\n // Don't do anything, if trying to send zero value\n if (value == 0) return;\n if (token == ETH_ADDRESS) {\n /// @dev Note: this can potentially lead to executing code in `to`.\n // solhint-disable-next-line avoid-low-level-calls\n (bool success,) = to.call{value: value}(\"\");\n require(success, \"ETH transfer failed\");\n } else {\n IERC20(token).safeTransfer(to, value);\n }\n }\n\n /// @notice Issues an infinite allowance to the spender, if the current allowance is insufficient\n /// to spend the given amount.\n function universalApproveInfinity(address token, address spender, uint256 amountToSpend) internal {\n // ETH Chad doesn't require your approval\n if (token == ETH_ADDRESS) return;\n // No-op if allowance is already sufficient\n uint256 allowance = IERC20(token).allowance(address(this), spender);\n if (allowance \u003e= amountToSpend) return;\n // Otherwise, reset approval to 0 and set to max allowance\n if (allowance \u003e 0) IERC20(token).safeDecreaseAllowance(spender, allowance);\n IERC20(token).safeIncreaseAllowance(spender, type(uint256).max);\n }\n\n /// @notice Returns the balance of the given token (or native ETH) for the given account.\n function universalBalanceOf(address token, address account) internal view returns (uint256) {\n if (token == ETH_ADDRESS) {\n return account.balance;\n } else {\n return IERC20(token).balanceOf(account);\n }\n }\n\n /// @dev Checks that token is a contract and not ETH_ADDRESS.\n function assertIsContract(address token) internal view {\n // Check that ETH_ADDRESS was not used (in case this is a predeploy on any of the chains)\n if (token == UniversalTokenLib.ETH_ADDRESS) revert TokenNotContract();\n // Check that token is not an EOA\n if (token.code.length == 0) revert TokenNotContract();\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/Admin.sol\n\ncontract Admin is IAdmin, AccessControlEnumerable {\n using UniversalTokenLib for address;\n\n bytes32 public constant RELAYER_ROLE = keccak256(\"RELAYER_ROLE\");\n bytes32 public constant REFUNDER_ROLE = keccak256(\"REFUNDER_ROLE\");\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n uint256 public constant FEE_BPS = 1e6;\n uint256 public constant FEE_RATE_MAX = 0.01e6; // max 1% on origin amount\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Chain gas amount to forward as rebate if requested\n uint256 public chainGasAmount;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n }\n\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n require(newFeeRate \u003c= FEE_RATE_MAX, \"newFeeRate \u003e max\");\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n token.universalTransfer(recipient, feeAmount);\n emit FeesSwept(token, recipient, feeAmount);\n }\n\n function setChainGasAmount(uint256 newChainGasAmount) external onlyRole(GOVERNOR_ROLE) {\n uint256 oldChainGasAmount = chainGasAmount;\n chainGasAmount = newChainGasAmount;\n emit ChainGasAmountUpdated(oldChainGasAmount, newChainGasAmount);\n }\n}\n\n// contracts/FastBridgeV2.sol\n\n/// @notice FastBridgeV2 is a contract for bridging tokens across chains.\ncontract FastBridgeV2 is Admin, IFastBridgeV2, IFastBridgeV2Errors {\n using SafeERC20 for IERC20;\n using UniversalTokenLib for address;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Delay for a transaction after which it could be permisionlessly refunded\n uint256 public constant REFUND_DELAY = 7 days;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n /// @notice Maximum length of accepted callParams\n uint256 public constant MAX_CALL_PARAMS_LENGTH = 2 ** 16 - 1;\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeTxDetails) public bridgeTxDetails;\n /// @notice Relay details on destination chain\n mapping(bytes32 =\u003e BridgeRelay) public bridgeRelayDetails;\n /// @notice Unique bridge nonces tracked per originSender\n mapping(address =\u003e uint256) public senderNonces;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Replaced by senderNonces\n uint256 public immutable nonce = 0;\n /// @notice the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n bridge({\n params: params,\n paramsV2: BridgeParamsV2({\n quoteRelayer: address(0),\n quoteExclusivitySeconds: 0,\n quoteId: bytes(\"\"),\n callValue: 0,\n callParams: bytes(\"\")\n })\n });\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes memory request) external payable {\n relay({request: request, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes memory request, bytes32 destTxHash) external {\n prove({transactionId: keccak256(request), destTxHash: destTxHash, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridgeV2\n function claim(bytes memory request) external {\n claim({request: request, to: address(0)});\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003e DISPUTE_PERIOD) {\n revert DisputePeriodPassed();\n }\n\n // @dev relayer gets slashed effectively if dest relay has gone thru\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n bridgeTxDetails[transactionId].proofRelayer = address(0);\n bridgeTxDetails[transactionId].proofBlockTimestamp = 0;\n bridgeTxDetails[transactionId].proofBlockNumber = 0;\n\n emit BridgeProofDisputed(transactionId, msg.sender);\n }\n\n /// @inheritdoc IFastBridge\n function refund(bytes memory request) external {\n bytes32 transactionId = keccak256(request);\n\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n\n if (bridgeTxDetails[transactionId].status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n\n if (hasRole(REFUNDER_ROLE, msg.sender)) {\n // Refunder can refund if deadline has passed\n if (block.timestamp \u003c= transaction.deadline) revert DeadlineNotExceeded();\n } else {\n // Permissionless refund is allowed after REFUND_DELAY\n if (block.timestamp \u003c= transaction.deadline + REFUND_DELAY) revert DeadlineNotExceeded();\n }\n\n // if all checks passed, set to REFUNDED status\n bridgeTxDetails[transactionId].status = BridgeStatus.REFUNDED;\n\n // transfer origin collateral back to original sender\n address to = transaction.originSender;\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount + transaction.originFeeAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (bridgeTxDetails[transactionId].proofRelayer != relayer) revert SenderIncorrect();\n return _timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n /// @dev This method is added to achieve backwards compatibility with decoding requests into V1 structs:\n /// - `callValue` is partially reported as a zero/non-zero flag\n /// - `callParams` is ignored\n /// In order to process all kinds of requests use getBridgeTransactionV2 instead.\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory) {\n // Try decoding into V2 struct first. This will revert if V1 struct is passed\n try this.getBridgeTransactionV2(request) returns (BridgeTransactionV2 memory txV2) {\n // Note: we entirely ignore the callParams field, as it was not present in V1\n return BridgeTransaction({\n originChainId: txV2.originChainId,\n destChainId: txV2.destChainId,\n originSender: txV2.originSender,\n destRecipient: txV2.destRecipient,\n originToken: txV2.originToken,\n destToken: txV2.destToken,\n originAmount: txV2.originAmount,\n destAmount: txV2.destAmount,\n originFeeAmount: txV2.originFeeAmount,\n sendChainGas: txV2.callValue != 0,\n deadline: txV2.deadline,\n nonce: txV2.nonce\n });\n } catch {\n // Fallback to V1 struct\n return abi.decode(request, (BridgeTransaction));\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) public payable {\n int256 exclusivityEndTime = int256(block.timestamp) + paramsV2.quoteExclusivitySeconds;\n _validateBridgeParams(params, paramsV2, exclusivityEndTime);\n\n // transfer tokens to bridge contract\n /// @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _pullToken(params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n\n // set status to requested\n bytes memory request = abi.encode(\n BridgeTransactionV2({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n callValue: paramsV2.callValue,\n deadline: params.deadline,\n nonce: senderNonces[params.sender]++, // increment nonce on every bridge\n exclusivityRelayer: paramsV2.quoteRelayer,\n // We checked exclusivityEndTime to be in range (0 .. params.deadline] above, so can safely cast\n exclusivityEndTime: uint256(exclusivityEndTime),\n callParams: paramsV2.callParams\n })\n );\n bytes32 transactionId = keccak256(request);\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n\n emit BridgeRequested({\n transactionId: transactionId,\n sender: params.sender,\n request: request,\n destChainId: params.dstChainId,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n sendChainGas: paramsV2.callValue != 0\n });\n emit BridgeQuoteDetails(transactionId, paramsV2.quoteId);\n }\n\n /// @inheritdoc IFastBridgeV2\n function relay(bytes memory request, address relayer) public payable {\n bytes32 transactionId = keccak256(request);\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n _validateRelayParams(transaction, transactionId, relayer);\n // mark bridge transaction as relayed\n bridgeRelayDetails[transactionId] =\n BridgeRelay({blockNumber: uint48(block.number), blockTimestamp: uint48(block.timestamp), relayer: relayer});\n\n // transfer tokens to recipient on destination chain and do an arbitrary call if requested\n address to = transaction.destRecipient;\n address token = transaction.destToken;\n uint256 amount = transaction.destAmount;\n\n // All state changes have been done at this point, can proceed to the external calls.\n // This follows the checks-effects-interactions pattern to mitigate potential reentrancy attacks.\n if (token == UniversalTokenLib.ETH_ADDRESS) {\n // For ETH non-zero callValue is not allowed\n if (transaction.callValue != 0) revert NativeTokenCallValueNotSupported();\n // Check that the correct msg.value was sent\n if (msg.value != amount) revert MsgValueIncorrect();\n } else {\n // For ERC20s, we check that the correct msg.value was sent\n if (msg.value != transaction.callValue) revert MsgValueIncorrect();\n // We need to transfer the tokens from the Relayer to the recipient first before performing an\n // optional post-transfer arbitrary call.\n IERC20(token).safeTransferFrom(msg.sender, to, amount);\n }\n\n if (transaction.callParams.length != 0) {\n // Arbitrary call requested, perform it while supplying full msg.value to the recipient\n // Note: if token has a fee on transfers, the recipient will have received less than `amount`.\n // This is a very niche edge case and should be handled by the recipient contract.\n _checkedCallRecipient({recipient: to, token: token, amount: amount, callParams: transaction.callParams});\n } else if (msg.value != 0) {\n // No arbitrary call requested, but msg.value was sent. This is either a relay with ETH,\n // or a non-zero callValue request with an ERC20. In both cases, transfer the ETH to the recipient.\n Address.sendValue(payable(to), msg.value);\n }\n\n emit BridgeRelayed({\n transactionId: transactionId,\n relayer: relayer,\n to: to,\n originChainId: transaction.originChainId,\n originToken: transaction.originToken,\n destToken: transaction.destToken,\n originAmount: transaction.originAmount,\n destAmount: transaction.destAmount,\n chainGasAmount: transaction.callValue\n });\n }\n\n /// @inheritdoc IFastBridgeV2\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) public onlyRole(RELAYER_ROLE) {\n // update bridge tx status given proof provided\n if (bridgeTxDetails[transactionId].status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n bridgeTxDetails[transactionId].status = BridgeStatus.RELAYER_PROVED;\n bridgeTxDetails[transactionId].proofBlockTimestamp = uint40(block.timestamp);\n bridgeTxDetails[transactionId].proofBlockNumber = uint48(block.number);\n bridgeTxDetails[transactionId].proofRelayer = relayer;\n\n emit BridgeProofProvided(transactionId, relayer, destTxHash);\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes memory request, address to) public {\n bytes32 transactionId = keccak256(request);\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n\n // update bridge tx status if able to claim origin collateral\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n\n // if \"to\" is zero addr, permissionlessly send funds to proven relayer\n if (to == address(0)) {\n to = bridgeTxDetails[transactionId].proofRelayer;\n } else if (bridgeTxDetails[transactionId].proofRelayer != msg.sender) {\n revert SenderIncorrect();\n }\n\n if (_timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003c= DISPUTE_PERIOD) {\n revert DisputePeriodNotPassed();\n }\n\n bridgeTxDetails[transactionId].status = BridgeStatus.RELAYER_CLAIMED;\n\n // update protocol fees if origin fee amount exists\n if (transaction.originFeeAmount \u003e 0) protocolFees[transaction.originToken] += transaction.originFeeAmount;\n\n // transfer origin collateral less fee to specified address\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositClaimed(transactionId, bridgeTxDetails[transactionId].proofRelayer, to, token, amount);\n }\n\n function bridgeStatuses(bytes32 transactionId) public view returns (BridgeStatus status) {\n return bridgeTxDetails[transactionId].status;\n }\n\n function bridgeProofs(bytes32 transactionId) public view returns (uint96 timestamp, address relayer) {\n timestamp = bridgeTxDetails[transactionId].proofBlockTimestamp;\n relayer = bridgeTxDetails[transactionId].proofRelayer;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeRelays(bytes32 transactionId) public view returns (bool) {\n // has this transactionId been relayed?\n return bridgeRelayDetails[transactionId].relayer != address(0);\n }\n\n /// @inheritdoc IFastBridgeV2\n function getBridgeTransactionV2(bytes memory request) public pure returns (BridgeTransactionV2 memory) {\n return abi.decode(request, (BridgeTransactionV2));\n }\n\n /// @notice Pulls a requested token from the user to this contract.\n function _pullToken(address token, uint256 amount) internal returns (uint256 amountPulled) {\n if (token == UniversalTokenLib.ETH_ADDRESS) {\n // For ETH we just need to check that the supplied msg.value is correct\n if (amount != msg.value) revert MsgValueIncorrect();\n amountPulled = msg.value;\n } else {\n token.assertIsContract();\n // Record token balance before transfer\n amountPulled = IERC20(token).balanceOf(address(this));\n // Token needs to be pulled only if msg.value is zero\n // This way user can specify WETH as the origin asset\n IERC20(token).safeTransferFrom(msg.sender, address(this), amount);\n // Use the difference between the recorded balance and the current balance as the amountPulled\n amountPulled = IERC20(token).balanceOf(address(this)) - amountPulled;\n }\n }\n\n /// @notice Calls the Recipient's hook function with the specified callParams and performs\n /// all the necessary checks for the returned value.\n function _checkedCallRecipient(\n address recipient,\n address token,\n uint256 amount,\n bytes memory callParams\n )\n internal\n {\n bytes memory hookData =\n abi.encodeCall(IFastBridgeRecipient.fastBridgeTransferReceived, (token, amount, callParams));\n // This will bubble any revert messages from the hook function\n bytes memory returnData = Address.functionCallWithValue({target: recipient, data: hookData, value: msg.value});\n // Explicit revert if no return data at all\n if (returnData.length == 0) revert RecipientNoReturnValue();\n // Check that exactly a single return value was returned\n if (returnData.length != 32) revert RecipientIncorrectReturnValue();\n // Return value should be abi-encoded hook function selector\n if (bytes32(returnData) != bytes32(IFastBridgeRecipient.fastBridgeTransferReceived.selector)) {\n revert RecipientIncorrectReturnValue();\n }\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint40(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint40).max but\n /// proof.timestamp \u003c type(uint40).max via unchecked statement\n /// @param proofBlockTimestamp The bridge proof block timestamp\n /// @return delta Time delta since proof submitted\n function _timeSince(uint40 proofBlockTimestamp) internal view returns (uint256 delta) {\n unchecked {\n delta = uint40(block.timestamp) - proofBlockTimestamp;\n }\n }\n\n /// @notice Performs all the necessary checks for a bridge to happen.\n /// @dev There's no good way to refactor this function to reduce cyclomatic complexity due to\n /// the number of checks that need to be performed, so we skip the code-complexity rule here.\n // solhint-disable-next-line code-complexity\n function _validateBridgeParams(\n BridgeParams memory params,\n BridgeParamsV2 memory paramsV2,\n int256 exclusivityEndTime\n )\n internal\n view\n {\n // Check V1 (legacy) params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.sender == address(0) || params.to == address(0)) revert ZeroAddress();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n // Check V2 params\n if (paramsV2.callParams.length \u003e MAX_CALL_PARAMS_LENGTH) revert CallParamsLengthAboveMax();\n if (paramsV2.callValue != 0 \u0026\u0026 params.destToken == UniversalTokenLib.ETH_ADDRESS) {\n revert NativeTokenCallValueNotSupported();\n }\n // exclusivityEndTime must be in range (0 .. params.deadline]\n if (exclusivityEndTime \u003c= 0 || exclusivityEndTime \u003e int256(params.deadline)) {\n revert ExclusivityParamsIncorrect();\n }\n }\n\n /// @notice Performs all the necessary checks for a relay to happen.\n function _validateRelayParams(\n BridgeTransactionV2 memory transaction,\n bytes32 transactionId,\n address relayer\n )\n internal\n view\n {\n if (relayer == address(0)) revert ZeroAddress();\n // Check if the transaction has already been relayed\n if (bridgeRelays(transactionId)) revert TransactionRelayed();\n if (transaction.destChainId != uint32(block.chainid)) revert ChainIncorrect();\n // Check the deadline for relay to happen\n if (block.timestamp \u003e transaction.deadline) revert DeadlineExceeded();\n // Check the exclusivity period, if it is still ongoing\n // forgefmt: disable-next-item\n if (\n transaction.exclusivityRelayer != address(0) \u0026\u0026\n transaction.exclusivityRelayer != relayer \u0026\u0026\n block.timestamp \u003c= transaction.exclusivityEndTime\n ) {\n revert ExclusivityPeriodNotPassed();\n }\n }\n}\n","language":"Solidity","languageVersion":"0.8.24","compilerVersion":"0.8.24","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"25827:11640:0:-:0;;;;;;;;;;;;;;;-1:-1:-1;;;25827:11640:0;;;;;;;;;;;;;;;;;","srcMapRuntime":"25827:11640:0:-:0;;;;;;;;","abiDefinition":[],"userDoc":{"kind":"user","methods":{},"version":1},"developerDoc":{"details":"Library for managing https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive types. Sets have the following properties: - Elements are added, removed, and checked for existence in constant time (O(1)). - Elements are enumerated in O(n). No guarantees are made on the ordering. ```solidity contract Example { // Add the library methods using EnumerableSet for EnumerableSet.AddressSet; // Declare a set state variable EnumerableSet.AddressSet private mySet; } ``` As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`) and `uint256` (`UintSet`) are supported. [WARNING] ==== Trying to delete such a structure from storage will likely result in data corruption, rendering the structure unusable. See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info. In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an array of EnumerableSet. ====","kind":"dev","methods":{},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[],\"devdoc\":{\"details\":\"Library for managing https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive types. Sets have the following properties: - Elements are added, removed, and checked for existence in constant time (O(1)). - Elements are enumerated in O(n). No guarantees are made on the ordering. ```solidity contract Example { // Add the library methods using EnumerableSet for EnumerableSet.AddressSet; // Declare a set state variable EnumerableSet.AddressSet private mySet; } ``` As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`) and `uint256` (`UintSet`) are supported. [WARNING] ==== Trying to delete such a structure from storage will likely result in data corruption, rendering the structure unusable. See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info. In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an array of EnumerableSet. ====\",\"kind\":\"dev\",\"methods\":{},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeV2.sol\":\"EnumerableSet\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeV2.sol\":{\"keccak256\":\"0x7cd0f885e80e2bdaa638bc32ae7af7d2e248f99ce4b354c217d0f0f7d7302e0a\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://7ccf28df0bd7b4606986585acd8622ed9b4e81379690061bb66088f0a2270af1\",\"dweb:/ipfs/QmTf7HNdHZkK6vmx8ZgewycQEb72oLD9nPwBpsM5reMstQ\"]}},\"version\":1}"},"hashes":{}},"solidity/FastBridgeV2.sol:FastBridgeV2":{"code":"0x60c060405260006080523480156200001657600080fd5b5060405162003e5a38038062003e5a833981016040819052620000399162000199565b806200004760008262000054565b50504360a05250620001c4565b60008062000063848462000091565b90508015620000885760008481526001602052604090206200008690846200013f565b505b90505b92915050565b6000828152602081815260408083206001600160a01b038516845290915281205460ff1662000136576000838152602081815260408083206001600160a01b03861684529091529020805460ff19166001179055620000ed3390565b6001600160a01b0316826001600160a01b0316847f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45060016200008b565b5060006200008b565b600062000088836001600160a01b038416600081815260018301602052604081205462000136575081546001818101845560008481526020808220909301849055845484825282860190935260409020919091556200008b565b600060208284031215620001ac57600080fd5b81516001600160a01b03811681146200008857600080fd5b60805160a051613c70620001ea6000396000610802015260006108a30152613c706000f3fe6080604052600436106102fd5760003560e01c806391ad50391161018f578063b13aa2d6116100e1578063ca15c8731161008a578063dcf844a711610064578063dcf844a714610a50578063df36bb1314610a7d578063e00a83e014610a9357600080fd5b8063ca15c873146109dc578063ccc57490146109fc578063d547741f14610a3057600080fd5b8063bfc7c607116100bb578063bfc7c6071461091c578063c63ff8dd1461092f578063c79371b11461094f57600080fd5b8063b13aa2d6146108c5578063b250fe6b146108e5578063bf333f2c1461090557600080fd5b8063a3ec191a11610143578063ac11fb1a1161011d578063ac11fb1a14610844578063add98c7014610871578063affed0e01461089157600080fd5b8063a3ec191a146107f0578063a5bbe22b14610607578063aa9641ab1461082457600080fd5b8063926d7d7f11610174578063926d7d7f146107945780639c9545f0146107c8578063a217fddf146107db57600080fd5b806391ad5039146106d057806391d148541461075057600080fd5b806341fcb6121161025357806363787e52116101fc578063886d36ff116101d6578063886d36ff146106655780638f0d6f17146106855780639010d07c1461069857600080fd5b806363787e521461058c578063820688d5146106075780638379a24f1461061d57600080fd5b80635960ccf21161022d5780635960ccf21461050b5780635aa6ccba1461053f5780635eb7d9461461056c57600080fd5b806341fcb612146104c257806345851694146104e257806358f85880146104f557600080fd5b806318e4357d116102b5578063295710ff1161028f578063295710ff146104555780632f2ff15d1461048257806336568abe146104a257600080fd5b806318e4357d146103ee578063190da5951461040e578063248a9ca31461042557600080fd5b8063051287bc116102e6578063051287bc1461037957806306f333f2146103b65780630f5f6ed7146103d857600080fd5b806301ffc9a71461030257806303ed0ee514610337575b600080fd5b34801561030e57600080fd5b5061032261031d366004612ee8565b610aa9565b60405190151581526020015b60405180910390f35b34801561034357600080fd5b5061036b7f043c983c49d46f0e102151eaf8085d4a2e6571d5df2d47b013f39bddfd4a639d81565b60405190815260200161032e565b34801561038557600080fd5b506103a9610394366004612f2a565b60009081526005602052604090205460ff1690565b60405161032e9190612fad565b3480156103c257600080fd5b506103d66103d1366004612fdb565b610b05565b005b3480156103e457600080fd5b5061036b61271081565b3480156103fa57600080fd5b506103d6610409366004613014565b610bcc565b34801561041a57600080fd5b5061036b62093a8081565b34801561043157600080fd5b5061036b610440366004612f2a565b60009081526020819052604090206001015490565b34801561046157600080fd5b5061036b61047036600461304d565b60076020526000908152604090205481565b34801561048e57600080fd5b506103d661049d36600461306a565b610d39565b3480156104ae57600080fd5b506103d66104bd36600461306a565b610d64565b3480156104ce57600080fd5b506103d66104dd366004613202565b610db0565b6103d66104f0366004613322565b611026565b34801561050157600080fd5b5061036b60025481565b34801561051757600080fd5b5061036b7fdb9556138406326f00296e13ea2ad7db24ba82381212d816b1a40c23b466b32781565b34801561054b57600080fd5b5061055f61055a36600461333f565b611083565b60405161032e91906133cc565b34801561057857600080fd5b506103d661058736600461333f565b611149565b34801561059857600080fd5b506105f76105a7366004612f2a565b60056020526000908152604090205460ff811690610100810464ffffffffff16906601000000000000810465ffffffffffff16906c0100000000000000000000000090046001600160a01b031684565b60405161032e94939291906134e1565b34801561061357600080fd5b5061036b61070881565b34801561062957600080fd5b50610322610638366004612f2a565b6000908152600660205260409020546c0100000000000000000000000090046001600160a01b0316151590565b34801561067157600080fd5b506103d6610680366004613522565b61133e565b6103d661069336600461333f565b611354565b3480156106a457600080fd5b506106b86106b3366004613567565b61135e565b6040516001600160a01b03909116815260200161032e565b3480156106dc57600080fd5b506107246106eb366004612f2a565b600090815260056020526040902054610100810464ffffffffff16916c010000000000000000000000009091046001600160a01b031690565b604080516bffffffffffffffffffffffff90931683526001600160a01b0390911660208301520161032e565b34801561075c57600080fd5b5061032261076b36600461306a565b6000918252602082815260408084206001600160a01b0393909316845291905290205460ff1690565b3480156107a057600080fd5b5061036b7fe2b7fb3b832174769106daebcfd6d1970523240dda11281102db9363b83b0dc481565b6103d66107d6366004613202565b61137d565b3480156107e757600080fd5b5061036b600081565b3480156107fc57600080fd5b5061036b7f000000000000000000000000000000000000000000000000000000000000000081565b34801561083057600080fd5b5061032261083f36600461306a565b61162e565b34801561085057600080fd5b5061086461085f36600461333f565b611719565b60405161032e9190613589565b34801561087d57600080fd5b506103d661088c366004612f2a565b6118d1565b34801561089d57600080fd5b5061036b7f000000000000000000000000000000000000000000000000000000000000000081565b3480156108d157600080fd5b506103d66108e0366004612f2a565b6119f3565b3480156108f157600080fd5b506103d6610900366004612f2a565b611ad5565b34801561091157600080fd5b5061036b620f424081565b6103d661092a36600461366f565b611b3d565b34801561093b57600080fd5b506103d661094a36600461333f565b611dbf565b34801561095b57600080fd5b506109ae61096a366004612f2a565b60066020526000908152604090205465ffffffffffff8082169166010000000000008104909116906c0100000000000000000000000090046001600160a01b031683565b6040805165ffffffffffff94851681529390921660208401526001600160a01b03169082015260600161032e565b3480156109e857600080fd5b5061036b6109f7366004612f2a565b611dca565b348015610a0857600080fd5b5061036b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f5581565b348015610a3c57600080fd5b506103d6610a4b36600461306a565b611de1565b348015610a5c57600080fd5b5061036b610a6b36600461304d565b60036020526000908152604090205481565b348015610a8957600080fd5b5061036b61ffff81565b348015610a9f57600080fd5b5061036b60045481565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f5a05180f000000000000000000000000000000000000000000000000000000001480610aff5750610aff82611e06565b92915050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f55610b2f81611e9d565b6001600160a01b03831660009081526003602052604081205490819003610b565750505050565b6001600160a01b038416600081815260036020526040812055610b7a908483611ea7565b604080516001600160a01b038087168252851660208201529081018290527f244e51bc38c1452fa8aaf487bcb4bca36c2baa3a5fbdb776b1eabd8dc6d277cd9060600160405180910390a1505b505050565b7fe2b7fb3b832174769106daebcfd6d1970523240dda11281102db9363b83b0dc4610bf681611e9d565b600160008581526005602052604090205460ff166004811115610c1b57610c1b612f43565b14610c52576040517f4145817200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600084815260056020908152604091829020805460027fffffffffffffffffffffffffffffffffffffffff0000000000000000000000009091166101004264ffffffffff16027fffffffffffffffffffffffffffffffffffffffff000000000000ffffffffffff161766010000000000004365ffffffffffff160217176bffffffffffffffffffffffff166c010000000000000000000000006001600160a01b0387169081029190911790915582518681529251909287927f4ac8af8a2cd87193d64dfc7a3b8d9923b714ec528b18725d080aa1299be0c5e492918290030190a350505050565b600082815260208190526040902060010154610d5481611e9d565b610d5e8383611fca565b50505050565b6001600160a01b0381163314610da6576040517f6697b23200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610bc78282611fff565b815160208301206000610dc284611083565b9050600260008381526005602052604090205460ff166004811115610de957610de9612f43565b14610e20576040517f4145817200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600160a01b038316610e5d576000828152600560205260409020546c0100000000000000000000000090046001600160a01b03169250610ebd565b6000828152600560205260409020546c0100000000000000000000000090046001600160a01b03163314610ebd576040517f4af43a9000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008281526005602052604090205461070890610100900464ffffffffff90811642031611610f18576040517f1992d0bd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600082815260056020526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016600317905561010081015115610f925761010081015160808201516001600160a01b031660009081526003602052604081208054909190610f8c90849061376c565b90915550505b608081015160c0820151610fb06001600160a01b0383168683611ea7565b6000848152600560209081526040918290205482516001600160a01b038681168252928101859052888316936c010000000000000000000000009092049092169187917f582211c35a2139ac3bbaac74663c6a1f56c6cbb658b41fe11fd45a82074ac678910160405180910390a4505050505050565b611080816040518060a0016040528060006001600160a01b03168152602001600081526020016040518060200160405280600081525081526020016000815260200160405180602001604052806000815250815250611b3d565b50565b611135604051806101e00160405280600063ffffffff168152602001600063ffffffff16815260200160006001600160a01b0316815260200160006001600160a01b0316815260200160006001600160a01b0316815260200160006001600160a01b0316815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160006001600160a01b0316815260200160008152602001606081525090565b81806020019051810190610aff91906137da565b80516020820120600061115b83611083565b9050600160008381526005602052604090205460ff16600481111561118257611182612f43565b146111b9576040517f4145817200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b3360009081527fd2043bf65931af3dbecf60d0db8f40e4160406d7beb00522f4200cf4944a1eb8602052604090205460ff161561123357806101400151421161122e576040517fe15ff9ea00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61127f565b62093a80816101400151611247919061376c565b421161127f576040517fe15ff9ea00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008281526005602052604080822080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166004179055820151608083015161010084015160c0850151929391926112d8919061376c565b90506112ee6001600160a01b0383168483611ea7565b604080516001600160a01b0384811682526020820184905285169187917fb4c55c0c9bc613519b920e88748090150b890a875d307f21bea7d4fb2e8bc958910160405180910390a3505050505050565b61135082805190602001208233610bcc565b5050565b611080813361137d565b6000828152600160205260408120611376908361202c565b9392505050565b81516020830120600061138f84611083565b905061139c818385612038565b604080516060808201835265ffffffffffff438116835242811660208085019182526001600160a01b03808a1686880190815260008a8152600690935296909120945185549251965182166c01000000000000000000000000026bffffffffffffffffffffffff9785166601000000000000027fffffffffffffffffffffffffffffffffffffffff000000000000000000000000909416919094161791909117949094161790915582015160a083015160e084015191929091907fffffffffffffffffffffffff1111111111111111111111111111111111111112908316016114fa57610120840151156114bc576040517f2598ad2e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8034146114f5576040517f81de0bf300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61154d565b8361012001513414611538576040517f81de0bf300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61154d6001600160a01b0383163385846121db565b6101c0840151511561156f5761156a838383876101c00151612257565b61157f565b341561157f5761157f83346123b6565b826001600160a01b0316866001600160a01b0316867ff8ae392d784b1ea5e8881bfa586d81abf07ef4f1e2fc75f7fe51c90f05199a5c876000015188608001518960a001518a60c001518b60e001518c610120015160405161161d9695949392919063ffffffff9690961686526001600160a01b0394851660208701529290931660408501526060840152608083019190915260a082015260c00190565b60405180910390a450505050505050565b6000600260008481526005602052604090205460ff16600481111561165557611655612f43565b1461168c576040517f4145817200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000838152600560205260409020546001600160a01b038381166c0100000000000000000000000090920416146116ef576040517f4af43a9000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b505060009081526005602052604090205461070861010090910464ffffffffff9081164203161190565b6040805161018081018252600080825260208201819052818301819052606082018190526080820181905260a0820181905260c0820181905260e0820181905261010082018190526101208201819052610140820181905261016082015290517f5aa6ccba0000000000000000000000000000000000000000000000000000000081523090635aa6ccba906117b290859060040161390f565b600060405180830381865afa9250505080156117f057506040513d6000823e601f3d908101601f191682016040526117ed91908101906137da565b60015b6118085781806020019051810190610aff919061392d565b604051806101800160405280826000015163ffffffff168152602001826020015163ffffffff16815260200182604001516001600160a01b0316815260200182606001516001600160a01b0316815260200182608001516001600160a01b031681526020018260a001516001600160a01b031681526020018260c0015181526020018260e001518152602001826101000151815260200182610120015160001415151581526020018261014001518152602001826101600151815250915050919050565b919050565b7f043c983c49d46f0e102151eaf8085d4a2e6571d5df2d47b013f39bddfd4a639d6118fb81611e9d565b600260008381526005602052604090205460ff16600481111561192057611920612f43565b14611957576040517f4145817200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008281526005602052604090205461070890610100900464ffffffffff90811642031611156119b3576040517f3e908aac00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000828152600560205260408082206001905551339184917f0695cf1d39b3055dcd0fe02d8b47eaf0d5a13e1996de925de59d0ef9b7f7fad49190a35050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f55611a1d81611e9d565b612710821115611a8e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f6e657746656552617465203e206d61780000000000000000000000000000000060448201526064015b60405180910390fd5b600280549083905560408051828152602081018590527f14914da2bf76024616fbe1859783fcd4dbddcb179b1f3a854949fbf920dcb95791015b60405180910390a1505050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f55611aff81611e9d565b600480549083905560408051828152602081018590527f5cf09b12f3f56b4c564d51b25b40360af6d795198adb61ae0806a36c294323fa9101611ac8565b6000816020015142611b4f91906139f9565b9050611b5c83838361247f565b6000611b7084606001518560a00151612704565b90506000806002541115611b9d57620f424060025483611b909190613a21565b611b9a9190613a38565b90505b611ba78183613a73565b91506000604051806101e001604052804663ffffffff168152602001876000015163ffffffff16815260200187602001516001600160a01b0316815260200187604001516001600160a01b0316815260200187606001516001600160a01b0316815260200187608001516001600160a01b031681526020018481526020018760c0015181526020018381526020018660600151815260200187610100015181526020016007600089602001516001600160a01b03166001600160a01b031681526020019081526020016000206000815480929190611c8490613a86565b91905055815260200186600001516001600160a01b031681526020018581526020018660800151815250604051602001611cbe91906133cc565b60408051808303601f1901815282825280516020808301919091206000818152600583529390932080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016600117905589015189516060808c015160808d015160c08e0151928d015195985095966001600160a01b039094169587957f120ea0364f36cdac7983bcfdd55270ca09d7f9b314a2ebc425a3b01ab1d6403a95611d72958b95909493928e9290151590613abe565b60405180910390a3807f3120e2bb59c86aca6890191a589a96af3662838efa374fbdcdf4c95bfe4a6c0e8760400151604051611dae919061390f565b60405180910390a250505050505050565b611080816000610db0565b6000818152600160205260408120610aff906128ad565b600082815260208190526040902060010154611dfc81611e9d565b610d5e8383611fff565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f7965db0b000000000000000000000000000000000000000000000000000000001480610aff57507f01ffc9a7000000000000000000000000000000000000000000000000000000007fffffffff00000000000000000000000000000000000000000000000000000000831614610aff565b61108081336128b7565b306001600160a01b03831603611ebc57505050565b80600003611ec957505050565b7fffffffffffffffffffffffff11111111111111111111111111111111111111126001600160a01b03841601611fb6576000826001600160a01b03168260405160006040518083038185875af1925050503d8060008114611f46576040519150601f19603f3d011682016040523d82523d6000602084013e611f4b565b606091505b5050905080610d5e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f455448207472616e73666572206661696c6564000000000000000000000000006044820152606401611a85565b610bc76001600160a01b0384168383612923565b600080611fd78484612954565b90508015611376576000848152600160205260409020611ff79084612a1c565b509392505050565b60008061200c8484612a31565b90508015611376576000848152600160205260409020611ff79084612ad2565b60006113768383612ae7565b6001600160a01b038116612078576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000828152600660205260409020546c0100000000000000000000000090046001600160a01b0316156120d7576040517fbef7bb7d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b4663ffffffff16836020015163ffffffff1614612120576040517f7029fdf900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b82610140015142111561215f576040517f559895a300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6101808301516001600160a01b0316158015906121935750806001600160a01b03168361018001516001600160a01b031614155b80156121a45750826101a001514211155b15610bc7576040517f14be123200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040516001600160a01b038481166024830152838116604483015260648201839052610d5e9186918216906323b872dd906084015b604051602081830303815290604052915060e01b6020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8381831617835250505050612b11565b600083838360405160240161226e93929190613b14565b60408051601f198184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f461e0c2100000000000000000000000000000000000000000000000000000000179052905060006122d5868334612b8d565b90508051600003612312576040517f1a95ad2600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b805160201461234d576040517ff3725cca00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f461e0c210000000000000000000000000000000000000000000000000000000061237782613b45565b146123ae576040517ff3725cca00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b505050505050565b804710156123f2576040517fcd786059000000000000000000000000000000000000000000000000000000008152306004820152602401611a85565b6000826001600160a01b03168260405160006040518083038185875af1925050503d806000811461243f576040519150601f19603f3d011682016040523d82523d6000602084013e612444565b606091505b5050905080610bc7576040517f1425ea4200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b46836000015163ffffffff16036124c2576040517f7029fdf900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60a083015115806124d5575060c0830151155b1561250c576040517fe38820c800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60208301516001600160a01b03161580612531575060408301516001600160a01b0316155b15612568576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60608301516001600160a01b0316158061258d575060808301516001600160a01b0316155b156125c4576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6125d06107084261376c565b836101000151101561260e576040517f04b7fcc800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61ffff826080015151111561264f576040517ffbe24d4900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b606082015115801590612682575060808301516001600160a01b031673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee145b156126b9576040517f2598ad2e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000811315806126cd575082610100015181135b15610bc7576040517f352807b900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60007fffffffffffffffffffffffff11111111111111111111111111111111111111126001600160a01b038416016127765734821461276f576040517f81de0bf300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5034610aff565b612788836001600160a01b0316612c43565b6040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201526001600160a01b038416906370a0823190602401602060405180830381865afa1580156127e5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128099190613b8a565b90506128206001600160a01b0384163330856121db565b6040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015281906001600160a01b038516906370a0823190602401602060405180830381865afa15801561287f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128a39190613b8a565b6113769190613a73565b6000610aff825490565b6000828152602081815260408083206001600160a01b038516845290915290205460ff16611350576040517fe2517d3f0000000000000000000000000000000000000000000000000000000081526001600160a01b038216600482015260248101839052604401611a85565b6040516001600160a01b03838116602483015260448201839052610bc791859182169063a9059cbb90606401612210565b6000828152602081815260408083206001600160a01b038516845290915281205460ff16612a14576000838152602081815260408083206001600160a01b0386168452909152902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790556129cc3390565b6001600160a01b0316826001600160a01b0316847f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a4506001610aff565b506000610aff565b6000611376836001600160a01b038416612ce9565b6000828152602081815260408083206001600160a01b038516845290915281205460ff1615612a14576000838152602081815260408083206001600160a01b038616808552925280832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016905551339286917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a4506001610aff565b6000611376836001600160a01b038416612d30565b6000826000018281548110612afe57612afe613ba3565b9060005260206000200154905092915050565b6000612b266001600160a01b03841683612e23565b90508051600014158015612b4b575080806020019051810190612b499190613bd2565b155b15610bc7576040517f5274afe70000000000000000000000000000000000000000000000000000000081526001600160a01b0384166004820152602401611a85565b606081471015612bcb576040517fcd786059000000000000000000000000000000000000000000000000000000008152306004820152602401611a85565b600080856001600160a01b03168486604051612be79190613bef565b60006040518083038185875af1925050503d8060008114612c24576040519150601f19603f3d011682016040523d82523d6000602084013e612c29565b606091505b5091509150612c39868383612e31565b9695505050505050565b7fffffffffffffffffffffffff11111111111111111111111111111111111111126001600160a01b03821601612ca5576040517f7f523fe800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b806001600160a01b03163b600003611080576040517f7f523fe800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000818152600183016020526040812054612a1457508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155610aff565b60008181526001830160205260408120548015612e19576000612d54600183613a73565b8554909150600090612d6890600190613a73565b9050808214612dcd576000866000018281548110612d8857612d88613ba3565b9060005260206000200154905080876000018481548110612dab57612dab613ba3565b6000918252602080832090910192909255918252600188019052604090208390555b8554869080612dde57612dde613c0b565b600190038181906000526020600020016000905590558560010160008681526020019081526020016000206000905560019350505050610aff565b6000915050610aff565b606061137683836000612b8d565b606082612e4657612e4182612ea6565b611376565b8151158015612e5d57506001600160a01b0384163b155b15612e9f576040517f9996b3150000000000000000000000000000000000000000000000000000000081526001600160a01b0385166004820152602401611a85565b5080611376565b805115612eb65780518082602001fd5b6040517f1425ea4200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600060208284031215612efa57600080fd5b81357fffffffff000000000000000000000000000000000000000000000000000000008116811461137657600080fd5b600060208284031215612f3c57600080fd5b5035919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b60058110612fa9577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b9052565b60208101610aff8284612f72565b6001600160a01b038116811461108057600080fd5b80356118cc81612fbb565b60008060408385031215612fee57600080fd5b8235612ff981612fbb565b9150602083013561300981612fbb565b809150509250929050565b60008060006060848603121561302957600080fd5b8335925060208401359150604084013561304281612fbb565b809150509250925092565b60006020828403121561305f57600080fd5b813561137681612fbb565b6000806040838503121561307d57600080fd5b82359150602083013561300981612fbb565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051610120810167ffffffffffffffff811182821017156130e2576130e261308f565b60405290565b60405160a0810167ffffffffffffffff811182821017156130e2576130e261308f565b6040516101e0810167ffffffffffffffff811182821017156130e2576130e261308f565b604051610180810167ffffffffffffffff811182821017156130e2576130e261308f565b604051601f8201601f1916810167ffffffffffffffff8111828210171561317c5761317c61308f565b604052919050565b600067ffffffffffffffff82111561319e5761319e61308f565b50601f01601f191660200190565b600082601f8301126131bd57600080fd5b81356131d06131cb82613184565b613153565b8181528460208386010111156131e557600080fd5b816020850160208301376000918101602001919091529392505050565b6000806040838503121561321557600080fd5b823567ffffffffffffffff81111561322c57600080fd5b613238858286016131ac565b925050602083013561300981612fbb565b63ffffffff8116811461108057600080fd5b80356118cc81613249565b801515811461108057600080fd5b80356118cc81613266565b6000610120828403121561329257600080fd5b61329a6130be565b90506132a58261325b565b81526132b360208301612fd0565b60208201526132c460408301612fd0565b60408201526132d560608301612fd0565b60608201526132e660808301612fd0565b608082015260a082013560a082015260c082013560c082015261330b60e08301613274565b60e082015261010080830135818301525092915050565b6000610120828403121561333557600080fd5b611376838361327f565b60006020828403121561335157600080fd5b813567ffffffffffffffff81111561336857600080fd5b613374848285016131ac565b949350505050565b60005b8381101561339757818101518382015260200161337f565b50506000910152565b600081518084526133b881602086016020860161337c565b601f01601f19169290920160200192915050565b602081526133e360208201835163ffffffff169052565b600060208301516133fc604084018263ffffffff169052565b5060408301516001600160a01b03811660608401525060608301516001600160a01b03811660808401525060808301516001600160a01b03811660a08401525060a08301516001600160a01b03811660c08401525060c083015160e08381019190915283015161010080840191909152830151610120808401919091528301516101408084019190915283015161016080840191909152830151610180808401919091528301516101a06134ba818501836001600160a01b03169052565b8401516101c0848101919091528401516101e08085015290506133746102008401826133a0565b608081016134ef8287612f72565b64ffffffffff8516602083015265ffffffffffff841660408301526001600160a01b038316606083015295945050505050565b6000806040838503121561353557600080fd5b823567ffffffffffffffff81111561354c57600080fd5b613558858286016131ac565b95602094909401359450505050565b6000806040838503121561357a57600080fd5b50508035926020909101359150565b815163ffffffff168152610180810160208301516135af602084018263ffffffff169052565b5060408301516135ca60408401826001600160a01b03169052565b5060608301516135e560608401826001600160a01b03169052565b50608083015161360060808401826001600160a01b03169052565b5060a083015161361b60a08401826001600160a01b03169052565b5060c083015160c083015260e083015160e0830152610100808401518184015250610120808401516136508285018215159052565b5050610140838101519083015261016092830151929091019190915290565b600080610140838503121561368357600080fd5b61368d848461327f565b915061012083013567ffffffffffffffff808211156136ab57600080fd5b9084019060a082870312156136bf57600080fd5b6136c76130e8565b82356136d281612fbb565b8152602083810135908201526040830135828111156136f057600080fd5b6136fc888286016131ac565b6040830152506060830135606082015260808301358281111561371e57600080fd5b61372a888286016131ac565b6080830152508093505050509250929050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b80820180821115610aff57610aff61373d565b80516118cc81613249565b80516118cc81612fbb565b600082601f8301126137a657600080fd5b81516137b46131cb82613184565b8181528460208386010111156137c957600080fd5b61337482602083016020870161337c565b6000602082840312156137ec57600080fd5b815167ffffffffffffffff8082111561380457600080fd5b908301906101e0828603121561381957600080fd5b61382161310b565b61382a8361377f565b81526138386020840161377f565b60208201526138496040840161378a565b604082015261385a6060840161378a565b606082015261386b6080840161378a565b608082015261387c60a0840161378a565b60a082015260c0838101519082015260e0808401519082015261010080840151908201526101208084015190820152610140808401519082015261016080840151908201526101806138cf81850161378a565b908201526101a083810151908201526101c080840151838111156138f257600080fd5b6138fe88828701613795565b918301919091525095945050505050565b60208152600061137660208301846133a0565b80516118cc81613266565b6000610180828403121561394057600080fd5b61394861312f565b6139518361377f565b815261395f6020840161377f565b60208201526139706040840161378a565b60408201526139816060840161378a565b60608201526139926080840161378a565b60808201526139a360a0840161378a565b60a082015260c083015160c082015260e083015160e08201526101008084015181830152506101206139d6818501613922565b908201526101408381015190820152610160928301519281019290925250919050565b8082018281126000831280158216821582161715613a1957613a1961373d565b505092915050565b8082028115828204841417610aff57610aff61373d565b600082613a6e577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b81810381811115610aff57610aff61373d565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203613ab757613ab761373d565b5060010190565b60e081526000613ad160e083018a6133a0565b63ffffffff989098166020830152506001600160a01b039586166040820152939094166060840152608083019190915260a082015290151560c090910152919050565b6001600160a01b0384168152826020820152606060408201526000613b3c60608301846133a0565b95945050505050565b80516020808301519190811015613b84577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8160200360031b1b821691505b50919050565b600060208284031215613b9c57600080fd5b5051919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b600060208284031215613be457600080fd5b815161137681613266565b60008251613c0181846020870161337c565b9190910192915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fdfea2646970667358221220a3680a17873f4c46b682e496f075c28aef799dbfefc67679607c7ecbffed72b464736f6c63430008180033","runtime-code":"0x6080604052600436106102fd5760003560e01c806391ad50391161018f578063b13aa2d6116100e1578063ca15c8731161008a578063dcf844a711610064578063dcf844a714610a50578063df36bb1314610a7d578063e00a83e014610a9357600080fd5b8063ca15c873146109dc578063ccc57490146109fc578063d547741f14610a3057600080fd5b8063bfc7c607116100bb578063bfc7c6071461091c578063c63ff8dd1461092f578063c79371b11461094f57600080fd5b8063b13aa2d6146108c5578063b250fe6b146108e5578063bf333f2c1461090557600080fd5b8063a3ec191a11610143578063ac11fb1a1161011d578063ac11fb1a14610844578063add98c7014610871578063affed0e01461089157600080fd5b8063a3ec191a146107f0578063a5bbe22b14610607578063aa9641ab1461082457600080fd5b8063926d7d7f11610174578063926d7d7f146107945780639c9545f0146107c8578063a217fddf146107db57600080fd5b806391ad5039146106d057806391d148541461075057600080fd5b806341fcb6121161025357806363787e52116101fc578063886d36ff116101d6578063886d36ff146106655780638f0d6f17146106855780639010d07c1461069857600080fd5b806363787e521461058c578063820688d5146106075780638379a24f1461061d57600080fd5b80635960ccf21161022d5780635960ccf21461050b5780635aa6ccba1461053f5780635eb7d9461461056c57600080fd5b806341fcb612146104c257806345851694146104e257806358f85880146104f557600080fd5b806318e4357d116102b5578063295710ff1161028f578063295710ff146104555780632f2ff15d1461048257806336568abe146104a257600080fd5b806318e4357d146103ee578063190da5951461040e578063248a9ca31461042557600080fd5b8063051287bc116102e6578063051287bc1461037957806306f333f2146103b65780630f5f6ed7146103d857600080fd5b806301ffc9a71461030257806303ed0ee514610337575b600080fd5b34801561030e57600080fd5b5061032261031d366004612ee8565b610aa9565b60405190151581526020015b60405180910390f35b34801561034357600080fd5b5061036b7f043c983c49d46f0e102151eaf8085d4a2e6571d5df2d47b013f39bddfd4a639d81565b60405190815260200161032e565b34801561038557600080fd5b506103a9610394366004612f2a565b60009081526005602052604090205460ff1690565b60405161032e9190612fad565b3480156103c257600080fd5b506103d66103d1366004612fdb565b610b05565b005b3480156103e457600080fd5b5061036b61271081565b3480156103fa57600080fd5b506103d6610409366004613014565b610bcc565b34801561041a57600080fd5b5061036b62093a8081565b34801561043157600080fd5b5061036b610440366004612f2a565b60009081526020819052604090206001015490565b34801561046157600080fd5b5061036b61047036600461304d565b60076020526000908152604090205481565b34801561048e57600080fd5b506103d661049d36600461306a565b610d39565b3480156104ae57600080fd5b506103d66104bd36600461306a565b610d64565b3480156104ce57600080fd5b506103d66104dd366004613202565b610db0565b6103d66104f0366004613322565b611026565b34801561050157600080fd5b5061036b60025481565b34801561051757600080fd5b5061036b7fdb9556138406326f00296e13ea2ad7db24ba82381212d816b1a40c23b466b32781565b34801561054b57600080fd5b5061055f61055a36600461333f565b611083565b60405161032e91906133cc565b34801561057857600080fd5b506103d661058736600461333f565b611149565b34801561059857600080fd5b506105f76105a7366004612f2a565b60056020526000908152604090205460ff811690610100810464ffffffffff16906601000000000000810465ffffffffffff16906c0100000000000000000000000090046001600160a01b031684565b60405161032e94939291906134e1565b34801561061357600080fd5b5061036b61070881565b34801561062957600080fd5b50610322610638366004612f2a565b6000908152600660205260409020546c0100000000000000000000000090046001600160a01b0316151590565b34801561067157600080fd5b506103d6610680366004613522565b61133e565b6103d661069336600461333f565b611354565b3480156106a457600080fd5b506106b86106b3366004613567565b61135e565b6040516001600160a01b03909116815260200161032e565b3480156106dc57600080fd5b506107246106eb366004612f2a565b600090815260056020526040902054610100810464ffffffffff16916c010000000000000000000000009091046001600160a01b031690565b604080516bffffffffffffffffffffffff90931683526001600160a01b0390911660208301520161032e565b34801561075c57600080fd5b5061032261076b36600461306a565b6000918252602082815260408084206001600160a01b0393909316845291905290205460ff1690565b3480156107a057600080fd5b5061036b7fe2b7fb3b832174769106daebcfd6d1970523240dda11281102db9363b83b0dc481565b6103d66107d6366004613202565b61137d565b3480156107e757600080fd5b5061036b600081565b3480156107fc57600080fd5b5061036b7f000000000000000000000000000000000000000000000000000000000000000081565b34801561083057600080fd5b5061032261083f36600461306a565b61162e565b34801561085057600080fd5b5061086461085f36600461333f565b611719565b60405161032e9190613589565b34801561087d57600080fd5b506103d661088c366004612f2a565b6118d1565b34801561089d57600080fd5b5061036b7f000000000000000000000000000000000000000000000000000000000000000081565b3480156108d157600080fd5b506103d66108e0366004612f2a565b6119f3565b3480156108f157600080fd5b506103d6610900366004612f2a565b611ad5565b34801561091157600080fd5b5061036b620f424081565b6103d661092a36600461366f565b611b3d565b34801561093b57600080fd5b506103d661094a36600461333f565b611dbf565b34801561095b57600080fd5b506109ae61096a366004612f2a565b60066020526000908152604090205465ffffffffffff8082169166010000000000008104909116906c0100000000000000000000000090046001600160a01b031683565b6040805165ffffffffffff94851681529390921660208401526001600160a01b03169082015260600161032e565b3480156109e857600080fd5b5061036b6109f7366004612f2a565b611dca565b348015610a0857600080fd5b5061036b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f5581565b348015610a3c57600080fd5b506103d6610a4b36600461306a565b611de1565b348015610a5c57600080fd5b5061036b610a6b36600461304d565b60036020526000908152604090205481565b348015610a8957600080fd5b5061036b61ffff81565b348015610a9f57600080fd5b5061036b60045481565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f5a05180f000000000000000000000000000000000000000000000000000000001480610aff5750610aff82611e06565b92915050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f55610b2f81611e9d565b6001600160a01b03831660009081526003602052604081205490819003610b565750505050565b6001600160a01b038416600081815260036020526040812055610b7a908483611ea7565b604080516001600160a01b038087168252851660208201529081018290527f244e51bc38c1452fa8aaf487bcb4bca36c2baa3a5fbdb776b1eabd8dc6d277cd9060600160405180910390a1505b505050565b7fe2b7fb3b832174769106daebcfd6d1970523240dda11281102db9363b83b0dc4610bf681611e9d565b600160008581526005602052604090205460ff166004811115610c1b57610c1b612f43565b14610c52576040517f4145817200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600084815260056020908152604091829020805460027fffffffffffffffffffffffffffffffffffffffff0000000000000000000000009091166101004264ffffffffff16027fffffffffffffffffffffffffffffffffffffffff000000000000ffffffffffff161766010000000000004365ffffffffffff160217176bffffffffffffffffffffffff166c010000000000000000000000006001600160a01b0387169081029190911790915582518681529251909287927f4ac8af8a2cd87193d64dfc7a3b8d9923b714ec528b18725d080aa1299be0c5e492918290030190a350505050565b600082815260208190526040902060010154610d5481611e9d565b610d5e8383611fca565b50505050565b6001600160a01b0381163314610da6576040517f6697b23200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610bc78282611fff565b815160208301206000610dc284611083565b9050600260008381526005602052604090205460ff166004811115610de957610de9612f43565b14610e20576040517f4145817200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600160a01b038316610e5d576000828152600560205260409020546c0100000000000000000000000090046001600160a01b03169250610ebd565b6000828152600560205260409020546c0100000000000000000000000090046001600160a01b03163314610ebd576040517f4af43a9000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008281526005602052604090205461070890610100900464ffffffffff90811642031611610f18576040517f1992d0bd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600082815260056020526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016600317905561010081015115610f925761010081015160808201516001600160a01b031660009081526003602052604081208054909190610f8c90849061376c565b90915550505b608081015160c0820151610fb06001600160a01b0383168683611ea7565b6000848152600560209081526040918290205482516001600160a01b038681168252928101859052888316936c010000000000000000000000009092049092169187917f582211c35a2139ac3bbaac74663c6a1f56c6cbb658b41fe11fd45a82074ac678910160405180910390a4505050505050565b611080816040518060a0016040528060006001600160a01b03168152602001600081526020016040518060200160405280600081525081526020016000815260200160405180602001604052806000815250815250611b3d565b50565b611135604051806101e00160405280600063ffffffff168152602001600063ffffffff16815260200160006001600160a01b0316815260200160006001600160a01b0316815260200160006001600160a01b0316815260200160006001600160a01b0316815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160006001600160a01b0316815260200160008152602001606081525090565b81806020019051810190610aff91906137da565b80516020820120600061115b83611083565b9050600160008381526005602052604090205460ff16600481111561118257611182612f43565b146111b9576040517f4145817200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b3360009081527fd2043bf65931af3dbecf60d0db8f40e4160406d7beb00522f4200cf4944a1eb8602052604090205460ff161561123357806101400151421161122e576040517fe15ff9ea00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61127f565b62093a80816101400151611247919061376c565b421161127f576040517fe15ff9ea00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008281526005602052604080822080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166004179055820151608083015161010084015160c0850151929391926112d8919061376c565b90506112ee6001600160a01b0383168483611ea7565b604080516001600160a01b0384811682526020820184905285169187917fb4c55c0c9bc613519b920e88748090150b890a875d307f21bea7d4fb2e8bc958910160405180910390a3505050505050565b61135082805190602001208233610bcc565b5050565b611080813361137d565b6000828152600160205260408120611376908361202c565b9392505050565b81516020830120600061138f84611083565b905061139c818385612038565b604080516060808201835265ffffffffffff438116835242811660208085019182526001600160a01b03808a1686880190815260008a8152600690935296909120945185549251965182166c01000000000000000000000000026bffffffffffffffffffffffff9785166601000000000000027fffffffffffffffffffffffffffffffffffffffff000000000000000000000000909416919094161791909117949094161790915582015160a083015160e084015191929091907fffffffffffffffffffffffff1111111111111111111111111111111111111112908316016114fa57610120840151156114bc576040517f2598ad2e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8034146114f5576040517f81de0bf300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61154d565b8361012001513414611538576040517f81de0bf300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61154d6001600160a01b0383163385846121db565b6101c0840151511561156f5761156a838383876101c00151612257565b61157f565b341561157f5761157f83346123b6565b826001600160a01b0316866001600160a01b0316867ff8ae392d784b1ea5e8881bfa586d81abf07ef4f1e2fc75f7fe51c90f05199a5c876000015188608001518960a001518a60c001518b60e001518c610120015160405161161d9695949392919063ffffffff9690961686526001600160a01b0394851660208701529290931660408501526060840152608083019190915260a082015260c00190565b60405180910390a450505050505050565b6000600260008481526005602052604090205460ff16600481111561165557611655612f43565b1461168c576040517f4145817200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000838152600560205260409020546001600160a01b038381166c0100000000000000000000000090920416146116ef576040517f4af43a9000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b505060009081526005602052604090205461070861010090910464ffffffffff9081164203161190565b6040805161018081018252600080825260208201819052818301819052606082018190526080820181905260a0820181905260c0820181905260e0820181905261010082018190526101208201819052610140820181905261016082015290517f5aa6ccba0000000000000000000000000000000000000000000000000000000081523090635aa6ccba906117b290859060040161390f565b600060405180830381865afa9250505080156117f057506040513d6000823e601f3d908101601f191682016040526117ed91908101906137da565b60015b6118085781806020019051810190610aff919061392d565b604051806101800160405280826000015163ffffffff168152602001826020015163ffffffff16815260200182604001516001600160a01b0316815260200182606001516001600160a01b0316815260200182608001516001600160a01b031681526020018260a001516001600160a01b031681526020018260c0015181526020018260e001518152602001826101000151815260200182610120015160001415151581526020018261014001518152602001826101600151815250915050919050565b919050565b7f043c983c49d46f0e102151eaf8085d4a2e6571d5df2d47b013f39bddfd4a639d6118fb81611e9d565b600260008381526005602052604090205460ff16600481111561192057611920612f43565b14611957576040517f4145817200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008281526005602052604090205461070890610100900464ffffffffff90811642031611156119b3576040517f3e908aac00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000828152600560205260408082206001905551339184917f0695cf1d39b3055dcd0fe02d8b47eaf0d5a13e1996de925de59d0ef9b7f7fad49190a35050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f55611a1d81611e9d565b612710821115611a8e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f6e657746656552617465203e206d61780000000000000000000000000000000060448201526064015b60405180910390fd5b600280549083905560408051828152602081018590527f14914da2bf76024616fbe1859783fcd4dbddcb179b1f3a854949fbf920dcb95791015b60405180910390a1505050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f55611aff81611e9d565b600480549083905560408051828152602081018590527f5cf09b12f3f56b4c564d51b25b40360af6d795198adb61ae0806a36c294323fa9101611ac8565b6000816020015142611b4f91906139f9565b9050611b5c83838361247f565b6000611b7084606001518560a00151612704565b90506000806002541115611b9d57620f424060025483611b909190613a21565b611b9a9190613a38565b90505b611ba78183613a73565b91506000604051806101e001604052804663ffffffff168152602001876000015163ffffffff16815260200187602001516001600160a01b0316815260200187604001516001600160a01b0316815260200187606001516001600160a01b0316815260200187608001516001600160a01b031681526020018481526020018760c0015181526020018381526020018660600151815260200187610100015181526020016007600089602001516001600160a01b03166001600160a01b031681526020019081526020016000206000815480929190611c8490613a86565b91905055815260200186600001516001600160a01b031681526020018581526020018660800151815250604051602001611cbe91906133cc565b60408051808303601f1901815282825280516020808301919091206000818152600583529390932080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016600117905589015189516060808c015160808d015160c08e0151928d015195985095966001600160a01b039094169587957f120ea0364f36cdac7983bcfdd55270ca09d7f9b314a2ebc425a3b01ab1d6403a95611d72958b95909493928e9290151590613abe565b60405180910390a3807f3120e2bb59c86aca6890191a589a96af3662838efa374fbdcdf4c95bfe4a6c0e8760400151604051611dae919061390f565b60405180910390a250505050505050565b611080816000610db0565b6000818152600160205260408120610aff906128ad565b600082815260208190526040902060010154611dfc81611e9d565b610d5e8383611fff565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f7965db0b000000000000000000000000000000000000000000000000000000001480610aff57507f01ffc9a7000000000000000000000000000000000000000000000000000000007fffffffff00000000000000000000000000000000000000000000000000000000831614610aff565b61108081336128b7565b306001600160a01b03831603611ebc57505050565b80600003611ec957505050565b7fffffffffffffffffffffffff11111111111111111111111111111111111111126001600160a01b03841601611fb6576000826001600160a01b03168260405160006040518083038185875af1925050503d8060008114611f46576040519150601f19603f3d011682016040523d82523d6000602084013e611f4b565b606091505b5050905080610d5e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f455448207472616e73666572206661696c6564000000000000000000000000006044820152606401611a85565b610bc76001600160a01b0384168383612923565b600080611fd78484612954565b90508015611376576000848152600160205260409020611ff79084612a1c565b509392505050565b60008061200c8484612a31565b90508015611376576000848152600160205260409020611ff79084612ad2565b60006113768383612ae7565b6001600160a01b038116612078576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000828152600660205260409020546c0100000000000000000000000090046001600160a01b0316156120d7576040517fbef7bb7d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b4663ffffffff16836020015163ffffffff1614612120576040517f7029fdf900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b82610140015142111561215f576040517f559895a300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6101808301516001600160a01b0316158015906121935750806001600160a01b03168361018001516001600160a01b031614155b80156121a45750826101a001514211155b15610bc7576040517f14be123200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040516001600160a01b038481166024830152838116604483015260648201839052610d5e9186918216906323b872dd906084015b604051602081830303815290604052915060e01b6020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8381831617835250505050612b11565b600083838360405160240161226e93929190613b14565b60408051601f198184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f461e0c2100000000000000000000000000000000000000000000000000000000179052905060006122d5868334612b8d565b90508051600003612312576040517f1a95ad2600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b805160201461234d576040517ff3725cca00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f461e0c210000000000000000000000000000000000000000000000000000000061237782613b45565b146123ae576040517ff3725cca00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b505050505050565b804710156123f2576040517fcd786059000000000000000000000000000000000000000000000000000000008152306004820152602401611a85565b6000826001600160a01b03168260405160006040518083038185875af1925050503d806000811461243f576040519150601f19603f3d011682016040523d82523d6000602084013e612444565b606091505b5050905080610bc7576040517f1425ea4200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b46836000015163ffffffff16036124c2576040517f7029fdf900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60a083015115806124d5575060c0830151155b1561250c576040517fe38820c800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60208301516001600160a01b03161580612531575060408301516001600160a01b0316155b15612568576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60608301516001600160a01b0316158061258d575060808301516001600160a01b0316155b156125c4576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6125d06107084261376c565b836101000151101561260e576040517f04b7fcc800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61ffff826080015151111561264f576040517ffbe24d4900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b606082015115801590612682575060808301516001600160a01b031673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee145b156126b9576040517f2598ad2e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000811315806126cd575082610100015181135b15610bc7576040517f352807b900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60007fffffffffffffffffffffffff11111111111111111111111111111111111111126001600160a01b038416016127765734821461276f576040517f81de0bf300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5034610aff565b612788836001600160a01b0316612c43565b6040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201526001600160a01b038416906370a0823190602401602060405180830381865afa1580156127e5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128099190613b8a565b90506128206001600160a01b0384163330856121db565b6040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015281906001600160a01b038516906370a0823190602401602060405180830381865afa15801561287f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128a39190613b8a565b6113769190613a73565b6000610aff825490565b6000828152602081815260408083206001600160a01b038516845290915290205460ff16611350576040517fe2517d3f0000000000000000000000000000000000000000000000000000000081526001600160a01b038216600482015260248101839052604401611a85565b6040516001600160a01b03838116602483015260448201839052610bc791859182169063a9059cbb90606401612210565b6000828152602081815260408083206001600160a01b038516845290915281205460ff16612a14576000838152602081815260408083206001600160a01b0386168452909152902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790556129cc3390565b6001600160a01b0316826001600160a01b0316847f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a4506001610aff565b506000610aff565b6000611376836001600160a01b038416612ce9565b6000828152602081815260408083206001600160a01b038516845290915281205460ff1615612a14576000838152602081815260408083206001600160a01b038616808552925280832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016905551339286917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a4506001610aff565b6000611376836001600160a01b038416612d30565b6000826000018281548110612afe57612afe613ba3565b9060005260206000200154905092915050565b6000612b266001600160a01b03841683612e23565b90508051600014158015612b4b575080806020019051810190612b499190613bd2565b155b15610bc7576040517f5274afe70000000000000000000000000000000000000000000000000000000081526001600160a01b0384166004820152602401611a85565b606081471015612bcb576040517fcd786059000000000000000000000000000000000000000000000000000000008152306004820152602401611a85565b600080856001600160a01b03168486604051612be79190613bef565b60006040518083038185875af1925050503d8060008114612c24576040519150601f19603f3d011682016040523d82523d6000602084013e612c29565b606091505b5091509150612c39868383612e31565b9695505050505050565b7fffffffffffffffffffffffff11111111111111111111111111111111111111126001600160a01b03821601612ca5576040517f7f523fe800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b806001600160a01b03163b600003611080576040517f7f523fe800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000818152600183016020526040812054612a1457508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155610aff565b60008181526001830160205260408120548015612e19576000612d54600183613a73565b8554909150600090612d6890600190613a73565b9050808214612dcd576000866000018281548110612d8857612d88613ba3565b9060005260206000200154905080876000018481548110612dab57612dab613ba3565b6000918252602080832090910192909255918252600188019052604090208390555b8554869080612dde57612dde613c0b565b600190038181906000526020600020016000905590558560010160008681526020019081526020016000206000905560019350505050610aff565b6000915050610aff565b606061137683836000612b8d565b606082612e4657612e4182612ea6565b611376565b8151158015612e5d57506001600160a01b0384163b155b15612e9f576040517f9996b3150000000000000000000000000000000000000000000000000000000081526001600160a01b0385166004820152602401611a85565b5080611376565b805115612eb65780518082602001fd5b6040517f1425ea4200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600060208284031215612efa57600080fd5b81357fffffffff000000000000000000000000000000000000000000000000000000008116811461137657600080fd5b600060208284031215612f3c57600080fd5b5035919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b60058110612fa9577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b9052565b60208101610aff8284612f72565b6001600160a01b038116811461108057600080fd5b80356118cc81612fbb565b60008060408385031215612fee57600080fd5b8235612ff981612fbb565b9150602083013561300981612fbb565b809150509250929050565b60008060006060848603121561302957600080fd5b8335925060208401359150604084013561304281612fbb565b809150509250925092565b60006020828403121561305f57600080fd5b813561137681612fbb565b6000806040838503121561307d57600080fd5b82359150602083013561300981612fbb565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051610120810167ffffffffffffffff811182821017156130e2576130e261308f565b60405290565b60405160a0810167ffffffffffffffff811182821017156130e2576130e261308f565b6040516101e0810167ffffffffffffffff811182821017156130e2576130e261308f565b604051610180810167ffffffffffffffff811182821017156130e2576130e261308f565b604051601f8201601f1916810167ffffffffffffffff8111828210171561317c5761317c61308f565b604052919050565b600067ffffffffffffffff82111561319e5761319e61308f565b50601f01601f191660200190565b600082601f8301126131bd57600080fd5b81356131d06131cb82613184565b613153565b8181528460208386010111156131e557600080fd5b816020850160208301376000918101602001919091529392505050565b6000806040838503121561321557600080fd5b823567ffffffffffffffff81111561322c57600080fd5b613238858286016131ac565b925050602083013561300981612fbb565b63ffffffff8116811461108057600080fd5b80356118cc81613249565b801515811461108057600080fd5b80356118cc81613266565b6000610120828403121561329257600080fd5b61329a6130be565b90506132a58261325b565b81526132b360208301612fd0565b60208201526132c460408301612fd0565b60408201526132d560608301612fd0565b60608201526132e660808301612fd0565b608082015260a082013560a082015260c082013560c082015261330b60e08301613274565b60e082015261010080830135818301525092915050565b6000610120828403121561333557600080fd5b611376838361327f565b60006020828403121561335157600080fd5b813567ffffffffffffffff81111561336857600080fd5b613374848285016131ac565b949350505050565b60005b8381101561339757818101518382015260200161337f565b50506000910152565b600081518084526133b881602086016020860161337c565b601f01601f19169290920160200192915050565b602081526133e360208201835163ffffffff169052565b600060208301516133fc604084018263ffffffff169052565b5060408301516001600160a01b03811660608401525060608301516001600160a01b03811660808401525060808301516001600160a01b03811660a08401525060a08301516001600160a01b03811660c08401525060c083015160e08381019190915283015161010080840191909152830151610120808401919091528301516101408084019190915283015161016080840191909152830151610180808401919091528301516101a06134ba818501836001600160a01b03169052565b8401516101c0848101919091528401516101e08085015290506133746102008401826133a0565b608081016134ef8287612f72565b64ffffffffff8516602083015265ffffffffffff841660408301526001600160a01b038316606083015295945050505050565b6000806040838503121561353557600080fd5b823567ffffffffffffffff81111561354c57600080fd5b613558858286016131ac565b95602094909401359450505050565b6000806040838503121561357a57600080fd5b50508035926020909101359150565b815163ffffffff168152610180810160208301516135af602084018263ffffffff169052565b5060408301516135ca60408401826001600160a01b03169052565b5060608301516135e560608401826001600160a01b03169052565b50608083015161360060808401826001600160a01b03169052565b5060a083015161361b60a08401826001600160a01b03169052565b5060c083015160c083015260e083015160e0830152610100808401518184015250610120808401516136508285018215159052565b5050610140838101519083015261016092830151929091019190915290565b600080610140838503121561368357600080fd5b61368d848461327f565b915061012083013567ffffffffffffffff808211156136ab57600080fd5b9084019060a082870312156136bf57600080fd5b6136c76130e8565b82356136d281612fbb565b8152602083810135908201526040830135828111156136f057600080fd5b6136fc888286016131ac565b6040830152506060830135606082015260808301358281111561371e57600080fd5b61372a888286016131ac565b6080830152508093505050509250929050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b80820180821115610aff57610aff61373d565b80516118cc81613249565b80516118cc81612fbb565b600082601f8301126137a657600080fd5b81516137b46131cb82613184565b8181528460208386010111156137c957600080fd5b61337482602083016020870161337c565b6000602082840312156137ec57600080fd5b815167ffffffffffffffff8082111561380457600080fd5b908301906101e0828603121561381957600080fd5b61382161310b565b61382a8361377f565b81526138386020840161377f565b60208201526138496040840161378a565b604082015261385a6060840161378a565b606082015261386b6080840161378a565b608082015261387c60a0840161378a565b60a082015260c0838101519082015260e0808401519082015261010080840151908201526101208084015190820152610140808401519082015261016080840151908201526101806138cf81850161378a565b908201526101a083810151908201526101c080840151838111156138f257600080fd5b6138fe88828701613795565b918301919091525095945050505050565b60208152600061137660208301846133a0565b80516118cc81613266565b6000610180828403121561394057600080fd5b61394861312f565b6139518361377f565b815261395f6020840161377f565b60208201526139706040840161378a565b60408201526139816060840161378a565b60608201526139926080840161378a565b60808201526139a360a0840161378a565b60a082015260c083015160c082015260e083015160e08201526101008084015181830152506101206139d6818501613922565b908201526101408381015190820152610160928301519281019290925250919050565b8082018281126000831280158216821582161715613a1957613a1961373d565b505092915050565b8082028115828204841417610aff57610aff61373d565b600082613a6e577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b81810381811115610aff57610aff61373d565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203613ab757613ab761373d565b5060010190565b60e081526000613ad160e083018a6133a0565b63ffffffff989098166020830152506001600160a01b039586166040820152939094166060840152608083019190915260a082015290151560c090910152919050565b6001600160a01b0384168152826020820152606060408201526000613b3c60608301846133a0565b95945050505050565b80516020808301519190811015613b84577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8160200360031b1b821691505b50919050565b600060208284031215613b9c57600080fd5b5051919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b600060208284031215613be457600080fd5b815161137681613266565b60008251613c0181846020870161337c565b9190910192915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fdfea2646970667358221220a3680a17873f4c46b682e496f075c28aef799dbfefc67679607c7ecbffed72b464736f6c63430008180033","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.24 ^0.8.0 ^0.8.20;\n\n// contracts/interfaces/IAdmin.sol\n\ninterface IAdmin {\n // ============ Events ============\n\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n event ChainGasAmountUpdated(uint256 oldChainGasAmount, uint256 newChainGasAmount);\n\n // ============ Methods ============\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n\n function setChainGasAmount(uint256 newChainGasAmount) external;\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IFastBridgeRecipient.sol\n\ninterface IFastBridgeRecipient {\n function fastBridgeTransferReceived(\n address token,\n uint256 amount,\n bytes memory callParams\n )\n external\n payable\n returns (bytes4);\n}\n\n// contracts/interfaces/IFastBridgeV2Errors.sol\n\ninterface IFastBridgeV2Errors {\n error AmountIncorrect();\n error CallParamsLengthAboveMax();\n error ChainIncorrect();\n error ExclusivityParamsIncorrect();\n error MsgValueIncorrect();\n error NativeTokenCallValueNotSupported();\n error SenderIncorrect();\n error StatusIncorrect();\n error ZeroAddress();\n\n error RecipientIncorrectReturnValue();\n error RecipientNoReturnValue();\n\n error DeadlineExceeded();\n error DeadlineNotExceeded();\n error DeadlineTooShort();\n error DisputePeriodNotPassed();\n error DisputePeriodPassed();\n error ExclusivityPeriodNotPassed();\n\n error TransactionRelayed();\n}\n\n// contracts/libs/Errors.sol\n\nerror DeadlineExceeded();\nerror DeadlineNotExceeded();\nerror DeadlineTooShort();\nerror InsufficientOutputAmount();\n\nerror MsgValueIncorrect();\nerror PoolNotFound();\nerror TokenAddressMismatch();\nerror TokenNotContract();\nerror TokenNotETH();\nerror TokensIdentical();\n\nerror ChainIncorrect();\nerror AmountIncorrect();\nerror ZeroAddress();\n\nerror DisputePeriodNotPassed();\nerror DisputePeriodPassed();\nerror SenderIncorrect();\nerror StatusIncorrect();\nerror TransactionIdIncorrect();\nerror TransactionRelayed();\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// contracts/interfaces/IFastBridgeV2.sol\n\ninterface IFastBridgeV2 is IFastBridge {\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n struct BridgeTxDetails {\n BridgeStatus status;\n uint40 proofBlockTimestamp;\n uint48 proofBlockNumber;\n address proofRelayer;\n }\n\n struct BridgeRelay {\n uint48 blockNumber;\n uint48 blockTimestamp;\n address relayer;\n }\n\n /// @notice New params introduced in the FastBridgeV2.\n /// We are passing fields from the older BridgeParams struct outside of this struct\n /// for backwards compatibility.\n /// Note: quoteRelayer and quoteExclusivitySeconds are either both zero (indicating no exclusivity)\n /// or both non-zero (indicating exclusivity for the given period).\n /// Note: callValue \u003e 0 can NOT be used with destToken = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE (ETH_ADDRESS)\n /// @param quoteRelayer Relayer that provided the quote for the transaction\n /// @param quoteExclusivitySeconds Period of time the quote relayer is guaranteed exclusivity after user's deposit\n /// @param quoteId Unique quote identifier used for tracking the quote\n /// @param callValue ETH value to send to the recipient (if any)\n /// @param callParams Parameters for the arbitrary call to the destination recipient (if any)\n struct BridgeParamsV2 {\n address quoteRelayer;\n int256 quoteExclusivitySeconds;\n bytes quoteId;\n uint256 callValue;\n bytes callParams;\n }\n\n /// @notice Updated bridge transaction struct to include parameters introduced in FastBridgeV2.\n /// Note: only `exclusivityRelayer` can fill such a transaction until `exclusivityEndTime`.\n /// TODO: consider changing the encoding scheme to prevent spending extra gas on decoding.\n struct BridgeTransactionV2 {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n uint256 callValue; // ETH value to send to the recipient (if any) - replaces V1's sendChainGas flag\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n address exclusivityRelayer;\n uint256 exclusivityEndTime;\n bytes callParams;\n }\n\n event BridgeQuoteDetails(bytes32 indexed transactionId, bytes quoteId);\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability\n /// to provide temporary exclusivity fill rights for the quote relayer.\n /// @param params The parameters required to bridge\n /// @param paramsV2 The parameters for exclusivity fill rights (optional, can be left empty)\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function relay(bytes memory request, address relayer) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param transactionId The transaction id associated with the encoded bridge transaction to prove\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital.\n /// @notice Can only send funds to the relayer address on the proof.\n /// @param request The encoded bridge transaction to claim on origin chain\n function claim(bytes memory request) external;\n /// @notice Checks if a transaction has been relayed\n /// @param transactionId The ID of the transaction to check\n /// @return True if the transaction has been relayed, false otherwise\n function bridgeRelays(bytes32 transactionId) external view returns (bool);\n\n /// @notice Returns the status of a bridge transaction\n /// @param transactionId The ID of the bridge transaction\n /// @return BridgeStatus Status of the bridge transaction\n function bridgeStatuses(bytes32 transactionId) external view returns (BridgeStatus);\n\n /// @notice Returns the timestamp and relayer of a bridge proof\n /// @param transactionId The ID of the bridge transaction\n /// @return timestamp The timestamp of the bridge proof\n /// @return relayer The relayer address of the bridge proof\n function bridgeProofs(bytes32 transactionId) external view returns (uint96 timestamp, address relayer);\n\n /// @notice Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\n /// @param request The bridge request to decode\n function getBridgeTransactionV2(bytes memory request) external view returns (BridgeTransactionV2 memory);\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// contracts/libs/UniversalToken.sol\n\nlibrary UniversalTokenLib {\n using SafeERC20 for IERC20;\n\n address internal constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Transfers tokens to the given account. Reverts if transfer is not successful.\n /// @dev This might trigger fallback, if ETH is transferred to the contract.\n /// Make sure this can not lead to reentrancy attacks.\n function universalTransfer(address token, address to, uint256 value) internal {\n // Don't do anything, if need to send tokens to this address\n if (to == address(this)) return;\n // Don't do anything, if trying to send zero value\n if (value == 0) return;\n if (token == ETH_ADDRESS) {\n /// @dev Note: this can potentially lead to executing code in `to`.\n // solhint-disable-next-line avoid-low-level-calls\n (bool success,) = to.call{value: value}(\"\");\n require(success, \"ETH transfer failed\");\n } else {\n IERC20(token).safeTransfer(to, value);\n }\n }\n\n /// @notice Issues an infinite allowance to the spender, if the current allowance is insufficient\n /// to spend the given amount.\n function universalApproveInfinity(address token, address spender, uint256 amountToSpend) internal {\n // ETH Chad doesn't require your approval\n if (token == ETH_ADDRESS) return;\n // No-op if allowance is already sufficient\n uint256 allowance = IERC20(token).allowance(address(this), spender);\n if (allowance \u003e= amountToSpend) return;\n // Otherwise, reset approval to 0 and set to max allowance\n if (allowance \u003e 0) IERC20(token).safeDecreaseAllowance(spender, allowance);\n IERC20(token).safeIncreaseAllowance(spender, type(uint256).max);\n }\n\n /// @notice Returns the balance of the given token (or native ETH) for the given account.\n function universalBalanceOf(address token, address account) internal view returns (uint256) {\n if (token == ETH_ADDRESS) {\n return account.balance;\n } else {\n return IERC20(token).balanceOf(account);\n }\n }\n\n /// @dev Checks that token is a contract and not ETH_ADDRESS.\n function assertIsContract(address token) internal view {\n // Check that ETH_ADDRESS was not used (in case this is a predeploy on any of the chains)\n if (token == UniversalTokenLib.ETH_ADDRESS) revert TokenNotContract();\n // Check that token is not an EOA\n if (token.code.length == 0) revert TokenNotContract();\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/Admin.sol\n\ncontract Admin is IAdmin, AccessControlEnumerable {\n using UniversalTokenLib for address;\n\n bytes32 public constant RELAYER_ROLE = keccak256(\"RELAYER_ROLE\");\n bytes32 public constant REFUNDER_ROLE = keccak256(\"REFUNDER_ROLE\");\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n uint256 public constant FEE_BPS = 1e6;\n uint256 public constant FEE_RATE_MAX = 0.01e6; // max 1% on origin amount\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Chain gas amount to forward as rebate if requested\n uint256 public chainGasAmount;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n }\n\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n require(newFeeRate \u003c= FEE_RATE_MAX, \"newFeeRate \u003e max\");\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n token.universalTransfer(recipient, feeAmount);\n emit FeesSwept(token, recipient, feeAmount);\n }\n\n function setChainGasAmount(uint256 newChainGasAmount) external onlyRole(GOVERNOR_ROLE) {\n uint256 oldChainGasAmount = chainGasAmount;\n chainGasAmount = newChainGasAmount;\n emit ChainGasAmountUpdated(oldChainGasAmount, newChainGasAmount);\n }\n}\n\n// contracts/FastBridgeV2.sol\n\n/// @notice FastBridgeV2 is a contract for bridging tokens across chains.\ncontract FastBridgeV2 is Admin, IFastBridgeV2, IFastBridgeV2Errors {\n using SafeERC20 for IERC20;\n using UniversalTokenLib for address;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Delay for a transaction after which it could be permisionlessly refunded\n uint256 public constant REFUND_DELAY = 7 days;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n /// @notice Maximum length of accepted callParams\n uint256 public constant MAX_CALL_PARAMS_LENGTH = 2 ** 16 - 1;\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeTxDetails) public bridgeTxDetails;\n /// @notice Relay details on destination chain\n mapping(bytes32 =\u003e BridgeRelay) public bridgeRelayDetails;\n /// @notice Unique bridge nonces tracked per originSender\n mapping(address =\u003e uint256) public senderNonces;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Replaced by senderNonces\n uint256 public immutable nonce = 0;\n /// @notice the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n bridge({\n params: params,\n paramsV2: BridgeParamsV2({\n quoteRelayer: address(0),\n quoteExclusivitySeconds: 0,\n quoteId: bytes(\"\"),\n callValue: 0,\n callParams: bytes(\"\")\n })\n });\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes memory request) external payable {\n relay({request: request, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes memory request, bytes32 destTxHash) external {\n prove({transactionId: keccak256(request), destTxHash: destTxHash, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridgeV2\n function claim(bytes memory request) external {\n claim({request: request, to: address(0)});\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003e DISPUTE_PERIOD) {\n revert DisputePeriodPassed();\n }\n\n // @dev relayer gets slashed effectively if dest relay has gone thru\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n bridgeTxDetails[transactionId].proofRelayer = address(0);\n bridgeTxDetails[transactionId].proofBlockTimestamp = 0;\n bridgeTxDetails[transactionId].proofBlockNumber = 0;\n\n emit BridgeProofDisputed(transactionId, msg.sender);\n }\n\n /// @inheritdoc IFastBridge\n function refund(bytes memory request) external {\n bytes32 transactionId = keccak256(request);\n\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n\n if (bridgeTxDetails[transactionId].status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n\n if (hasRole(REFUNDER_ROLE, msg.sender)) {\n // Refunder can refund if deadline has passed\n if (block.timestamp \u003c= transaction.deadline) revert DeadlineNotExceeded();\n } else {\n // Permissionless refund is allowed after REFUND_DELAY\n if (block.timestamp \u003c= transaction.deadline + REFUND_DELAY) revert DeadlineNotExceeded();\n }\n\n // if all checks passed, set to REFUNDED status\n bridgeTxDetails[transactionId].status = BridgeStatus.REFUNDED;\n\n // transfer origin collateral back to original sender\n address to = transaction.originSender;\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount + transaction.originFeeAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (bridgeTxDetails[transactionId].proofRelayer != relayer) revert SenderIncorrect();\n return _timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n /// @dev This method is added to achieve backwards compatibility with decoding requests into V1 structs:\n /// - `callValue` is partially reported as a zero/non-zero flag\n /// - `callParams` is ignored\n /// In order to process all kinds of requests use getBridgeTransactionV2 instead.\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory) {\n // Try decoding into V2 struct first. This will revert if V1 struct is passed\n try this.getBridgeTransactionV2(request) returns (BridgeTransactionV2 memory txV2) {\n // Note: we entirely ignore the callParams field, as it was not present in V1\n return BridgeTransaction({\n originChainId: txV2.originChainId,\n destChainId: txV2.destChainId,\n originSender: txV2.originSender,\n destRecipient: txV2.destRecipient,\n originToken: txV2.originToken,\n destToken: txV2.destToken,\n originAmount: txV2.originAmount,\n destAmount: txV2.destAmount,\n originFeeAmount: txV2.originFeeAmount,\n sendChainGas: txV2.callValue != 0,\n deadline: txV2.deadline,\n nonce: txV2.nonce\n });\n } catch {\n // Fallback to V1 struct\n return abi.decode(request, (BridgeTransaction));\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) public payable {\n int256 exclusivityEndTime = int256(block.timestamp) + paramsV2.quoteExclusivitySeconds;\n _validateBridgeParams(params, paramsV2, exclusivityEndTime);\n\n // transfer tokens to bridge contract\n /// @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _pullToken(params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n\n // set status to requested\n bytes memory request = abi.encode(\n BridgeTransactionV2({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n callValue: paramsV2.callValue,\n deadline: params.deadline,\n nonce: senderNonces[params.sender]++, // increment nonce on every bridge\n exclusivityRelayer: paramsV2.quoteRelayer,\n // We checked exclusivityEndTime to be in range (0 .. params.deadline] above, so can safely cast\n exclusivityEndTime: uint256(exclusivityEndTime),\n callParams: paramsV2.callParams\n })\n );\n bytes32 transactionId = keccak256(request);\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n\n emit BridgeRequested({\n transactionId: transactionId,\n sender: params.sender,\n request: request,\n destChainId: params.dstChainId,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n sendChainGas: paramsV2.callValue != 0\n });\n emit BridgeQuoteDetails(transactionId, paramsV2.quoteId);\n }\n\n /// @inheritdoc IFastBridgeV2\n function relay(bytes memory request, address relayer) public payable {\n bytes32 transactionId = keccak256(request);\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n _validateRelayParams(transaction, transactionId, relayer);\n // mark bridge transaction as relayed\n bridgeRelayDetails[transactionId] =\n BridgeRelay({blockNumber: uint48(block.number), blockTimestamp: uint48(block.timestamp), relayer: relayer});\n\n // transfer tokens to recipient on destination chain and do an arbitrary call if requested\n address to = transaction.destRecipient;\n address token = transaction.destToken;\n uint256 amount = transaction.destAmount;\n\n // All state changes have been done at this point, can proceed to the external calls.\n // This follows the checks-effects-interactions pattern to mitigate potential reentrancy attacks.\n if (token == UniversalTokenLib.ETH_ADDRESS) {\n // For ETH non-zero callValue is not allowed\n if (transaction.callValue != 0) revert NativeTokenCallValueNotSupported();\n // Check that the correct msg.value was sent\n if (msg.value != amount) revert MsgValueIncorrect();\n } else {\n // For ERC20s, we check that the correct msg.value was sent\n if (msg.value != transaction.callValue) revert MsgValueIncorrect();\n // We need to transfer the tokens from the Relayer to the recipient first before performing an\n // optional post-transfer arbitrary call.\n IERC20(token).safeTransferFrom(msg.sender, to, amount);\n }\n\n if (transaction.callParams.length != 0) {\n // Arbitrary call requested, perform it while supplying full msg.value to the recipient\n // Note: if token has a fee on transfers, the recipient will have received less than `amount`.\n // This is a very niche edge case and should be handled by the recipient contract.\n _checkedCallRecipient({recipient: to, token: token, amount: amount, callParams: transaction.callParams});\n } else if (msg.value != 0) {\n // No arbitrary call requested, but msg.value was sent. This is either a relay with ETH,\n // or a non-zero callValue request with an ERC20. In both cases, transfer the ETH to the recipient.\n Address.sendValue(payable(to), msg.value);\n }\n\n emit BridgeRelayed({\n transactionId: transactionId,\n relayer: relayer,\n to: to,\n originChainId: transaction.originChainId,\n originToken: transaction.originToken,\n destToken: transaction.destToken,\n originAmount: transaction.originAmount,\n destAmount: transaction.destAmount,\n chainGasAmount: transaction.callValue\n });\n }\n\n /// @inheritdoc IFastBridgeV2\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) public onlyRole(RELAYER_ROLE) {\n // update bridge tx status given proof provided\n if (bridgeTxDetails[transactionId].status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n bridgeTxDetails[transactionId].status = BridgeStatus.RELAYER_PROVED;\n bridgeTxDetails[transactionId].proofBlockTimestamp = uint40(block.timestamp);\n bridgeTxDetails[transactionId].proofBlockNumber = uint48(block.number);\n bridgeTxDetails[transactionId].proofRelayer = relayer;\n\n emit BridgeProofProvided(transactionId, relayer, destTxHash);\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes memory request, address to) public {\n bytes32 transactionId = keccak256(request);\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n\n // update bridge tx status if able to claim origin collateral\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n\n // if \"to\" is zero addr, permissionlessly send funds to proven relayer\n if (to == address(0)) {\n to = bridgeTxDetails[transactionId].proofRelayer;\n } else if (bridgeTxDetails[transactionId].proofRelayer != msg.sender) {\n revert SenderIncorrect();\n }\n\n if (_timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003c= DISPUTE_PERIOD) {\n revert DisputePeriodNotPassed();\n }\n\n bridgeTxDetails[transactionId].status = BridgeStatus.RELAYER_CLAIMED;\n\n // update protocol fees if origin fee amount exists\n if (transaction.originFeeAmount \u003e 0) protocolFees[transaction.originToken] += transaction.originFeeAmount;\n\n // transfer origin collateral less fee to specified address\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositClaimed(transactionId, bridgeTxDetails[transactionId].proofRelayer, to, token, amount);\n }\n\n function bridgeStatuses(bytes32 transactionId) public view returns (BridgeStatus status) {\n return bridgeTxDetails[transactionId].status;\n }\n\n function bridgeProofs(bytes32 transactionId) public view returns (uint96 timestamp, address relayer) {\n timestamp = bridgeTxDetails[transactionId].proofBlockTimestamp;\n relayer = bridgeTxDetails[transactionId].proofRelayer;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeRelays(bytes32 transactionId) public view returns (bool) {\n // has this transactionId been relayed?\n return bridgeRelayDetails[transactionId].relayer != address(0);\n }\n\n /// @inheritdoc IFastBridgeV2\n function getBridgeTransactionV2(bytes memory request) public pure returns (BridgeTransactionV2 memory) {\n return abi.decode(request, (BridgeTransactionV2));\n }\n\n /// @notice Pulls a requested token from the user to this contract.\n function _pullToken(address token, uint256 amount) internal returns (uint256 amountPulled) {\n if (token == UniversalTokenLib.ETH_ADDRESS) {\n // For ETH we just need to check that the supplied msg.value is correct\n if (amount != msg.value) revert MsgValueIncorrect();\n amountPulled = msg.value;\n } else {\n token.assertIsContract();\n // Record token balance before transfer\n amountPulled = IERC20(token).balanceOf(address(this));\n // Token needs to be pulled only if msg.value is zero\n // This way user can specify WETH as the origin asset\n IERC20(token).safeTransferFrom(msg.sender, address(this), amount);\n // Use the difference between the recorded balance and the current balance as the amountPulled\n amountPulled = IERC20(token).balanceOf(address(this)) - amountPulled;\n }\n }\n\n /// @notice Calls the Recipient's hook function with the specified callParams and performs\n /// all the necessary checks for the returned value.\n function _checkedCallRecipient(\n address recipient,\n address token,\n uint256 amount,\n bytes memory callParams\n )\n internal\n {\n bytes memory hookData =\n abi.encodeCall(IFastBridgeRecipient.fastBridgeTransferReceived, (token, amount, callParams));\n // This will bubble any revert messages from the hook function\n bytes memory returnData = Address.functionCallWithValue({target: recipient, data: hookData, value: msg.value});\n // Explicit revert if no return data at all\n if (returnData.length == 0) revert RecipientNoReturnValue();\n // Check that exactly a single return value was returned\n if (returnData.length != 32) revert RecipientIncorrectReturnValue();\n // Return value should be abi-encoded hook function selector\n if (bytes32(returnData) != bytes32(IFastBridgeRecipient.fastBridgeTransferReceived.selector)) {\n revert RecipientIncorrectReturnValue();\n }\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint40(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint40).max but\n /// proof.timestamp \u003c type(uint40).max via unchecked statement\n /// @param proofBlockTimestamp The bridge proof block timestamp\n /// @return delta Time delta since proof submitted\n function _timeSince(uint40 proofBlockTimestamp) internal view returns (uint256 delta) {\n unchecked {\n delta = uint40(block.timestamp) - proofBlockTimestamp;\n }\n }\n\n /// @notice Performs all the necessary checks for a bridge to happen.\n /// @dev There's no good way to refactor this function to reduce cyclomatic complexity due to\n /// the number of checks that need to be performed, so we skip the code-complexity rule here.\n // solhint-disable-next-line code-complexity\n function _validateBridgeParams(\n BridgeParams memory params,\n BridgeParamsV2 memory paramsV2,\n int256 exclusivityEndTime\n )\n internal\n view\n {\n // Check V1 (legacy) params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.sender == address(0) || params.to == address(0)) revert ZeroAddress();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n // Check V2 params\n if (paramsV2.callParams.length \u003e MAX_CALL_PARAMS_LENGTH) revert CallParamsLengthAboveMax();\n if (paramsV2.callValue != 0 \u0026\u0026 params.destToken == UniversalTokenLib.ETH_ADDRESS) {\n revert NativeTokenCallValueNotSupported();\n }\n // exclusivityEndTime must be in range (0 .. params.deadline]\n if (exclusivityEndTime \u003c= 0 || exclusivityEndTime \u003e int256(params.deadline)) {\n revert ExclusivityParamsIncorrect();\n }\n }\n\n /// @notice Performs all the necessary checks for a relay to happen.\n function _validateRelayParams(\n BridgeTransactionV2 memory transaction,\n bytes32 transactionId,\n address relayer\n )\n internal\n view\n {\n if (relayer == address(0)) revert ZeroAddress();\n // Check if the transaction has already been relayed\n if (bridgeRelays(transactionId)) revert TransactionRelayed();\n if (transaction.destChainId != uint32(block.chainid)) revert ChainIncorrect();\n // Check the deadline for relay to happen\n if (block.timestamp \u003e transaction.deadline) revert DeadlineExceeded();\n // Check the exclusivity period, if it is still ongoing\n // forgefmt: disable-next-item\n if (\n transaction.exclusivityRelayer != address(0) \u0026\u0026\n transaction.exclusivityRelayer != relayer \u0026\u0026\n block.timestamp \u003c= transaction.exclusivityEndTime\n ) {\n revert ExclusivityPeriodNotPassed();\n }\n }\n}\n","language":"Solidity","languageVersion":"0.8.24","compilerVersion":"0.8.24","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"64760:19813:0:-:0;;;65906:1;65873:34;;66011:85;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;66045:6;63675:38;52847:4;66045:6;63675:10;:38::i;:::-;-1:-1:-1;;66077:12:0::1;66063:26;::::0;-1:-1:-1;64760:19813:0;;62160:257;62246:4;;62277:31;62294:4;62300:7;62277:16;:31::i;:::-;62262:46;;62322:7;62318:69;;;62345:18;;;;:12;:18;;;;;:31;;62368:7;62345:22;:31::i;:::-;;62318:69;62403:7;-1:-1:-1;62160:257:0;;;;;:::o;56794:316::-;56871:4;53569:12;;;;;;;;;;;-1:-1:-1;;;;;53569:29:0;;;;;;;;;;;;56887:217;;56930:6;:12;;;;;;;;;;;-1:-1:-1;;;;;56930:29:0;;;;;;;;;:36;;-1:-1:-1;;56930:36:0;56962:4;56930:36;;;57012:12;23368:10;;23289:96;57012:12;-1:-1:-1;;;;;56985:40:0;57003:7;-1:-1:-1;;;;;56985:40:0;56997:4;56985:40;;;;;;;;;;-1:-1:-1;57046:4:0;57039:11;;56887:217;-1:-1:-1;57088:5:0;57081:12;;32813:150;32883:4;32906:50;32911:3;-1:-1:-1;;;;;32931:23:0;;26801:4;28857:21;;;:14;;;:21;;;;;;26817:321;;-1:-1:-1;26859:23:0;;;;;;;;:11;:23;;;;;;;;;;;;;27041:18;;27017:21;;;:14;;;:21;;;;;;:42;;;;27073:11;;14:290:1;84:6;137:2;125:9;116:7;112:23;108:32;105:52;;;153:1;150;143:12;105:52;179:16;;-1:-1:-1;;;;;224:31:1;;214:42;;204:70;;270:1;267;260:12;14:290;64760:19813:0;;;;;;;;;;;;;;;;;;","srcMapRuntime":"64760:19813:0:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;60820:212;;;;;;;;;;-1:-1:-1;60820:212:0;;;;;:::i;:::-;;:::i;:::-;;;612:14:1;;605:22;587:41;;575:2;560:18;60820:212:0;;;;;;;;63050:60;;;;;;;;;;;;63087:23;63050:60;;;;;785:25:1;;;773:2;758:18;63050:60:0;639:177:1;78381:150:0;;;;;;;;;;-1:-1:-1;78381:150:0;;;;;:::i;:::-;78449:19;78487:30;;;:15;:30;;;;;:37;;;;78381:150;;;;;;;;:::i;64022:359::-;;;;;;;;;;-1:-1:-1;64022:359:0;;;;;:::i;:::-;;:::i;:::-;;63232:45;;;;;;;;;;;;63271:6;63232:45;;76275:648;;;;;;;;;;-1:-1:-1;76275:648:0;;;;;:::i;:::-;;:::i;65110:45::-;;;;;;;;;;;;65149:6;65110:45;;54425:120;;;;;;;;;;-1:-1:-1;54425:120:0;;;;;:::i;:::-;54490:7;54516:12;;;;;;;;;;:22;;;;54425:120;65722:47;;;;;;;;;;-1:-1:-1;65722:47:0;;;;;:::i;:::-;;;;;;;;;;;;;;54841:136;;;;;;;;;;-1:-1:-1;54841:136:0;;;;;:::i;:::-;;:::i;55943:245::-;;;;;;;;;;-1:-1:-1;55943:245:0;;;;;:::i;:::-;;:::i;76961:1414::-;;;;;;;;;;-1:-1:-1;76961:1414:0;;;;;:::i;:::-;;:::i;66134:369::-;;;;;;:::i;:::-;;:::i;63394:30::-;;;;;;;;;;;;;;;;62978:66;;;;;;;;;;;;63018:26;62978:66;;79059:169;;;;;;;;;;-1:-1:-1;79059:169:0;;;;;:::i;:::-;;:::i;:::-;;;;;;;:::i;67821:1169::-;;;;;;;;;;-1:-1:-1;67821:1169:0;;;;;:::i;:::-;;:::i;65482:58::-;;;;;;;;;;-1:-1:-1;65482:58:0;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;65482:58:0;;;;;;;;;;;;;:::i;65242:56::-;;;;;;;;;;;;65288:10;65242:56;;78820:199;;;;;;;;;;-1:-1:-1;78820:199:0;;;;;:::i;:::-;78886:4;78957:33;;;:18;:33;;;;;:41;;;;-1:-1:-1;;;;;78957:41:0;:55;;;78820:199;66696:170;;;;;;;;;;-1:-1:-1;66696:170:0;;;;;:::i;:::-;;:::i;66541:117::-;;;;;;:::i;:::-;;:::i;61617:142::-;;;;;;;;;;-1:-1:-1;61617:142:0;;;;;:::i;:::-;;:::i;:::-;;;-1:-1:-1;;;;;12205:55:1;;;12187:74;;12175:2;12160:18;61617:142:0;12041:226:1;78537:243:0;;;;;;;;;;-1:-1:-1;78537:243:0;;;;;:::i;:::-;78603:16;78660:30;;;:15;:30;;;;;:50;;;;;;;78730:43;;;;-1:-1:-1;;;;;78730:43:0;;78537:243;;;;;12474:26:1;12462:39;;;12444:58;;-1:-1:-1;;;;;12538:55:1;;;12533:2;12518:18;;12511:83;12417:18;78537:243:0;12272:328:1;53469:136:0;;;;;;;;;;-1:-1:-1;53469:136:0;;;;;:::i;:::-;53546:4;53569:12;;;;;;;;;;;-1:-1:-1;;;;;53569:29:0;;;;;;;;;;;;;;;53469:136;62908:64;;;;;;;;;;;;62947:25;62908:64;;73354:2881;;;;;;:::i;:::-;;:::i;52802:49::-;;;;;;;;;;-1:-1:-1;52802:49:0;52847:4;52802:49;;65968:36;;;;;;;;;;;;;;;69028:392;;;;;;;;;;-1:-1:-1;69028:392:0;;;;;:::i;:::-;;:::i;69755:1121::-;;;;;;;;;;-1:-1:-1;69755:1121:0;;;;;:::i;:::-;;:::i;:::-;;;;;;;:::i;67048:735::-;;;;;;;;;;-1:-1:-1;67048:735:0;;;;;:::i;:::-;;:::i;65873:34::-;;;;;;;;;;;;;;;63726:290;;;;;;;;;;-1:-1:-1;63726:290:0;;;;;:::i;:::-;;:::i;64387:264::-;;;;;;;;;;-1:-1:-1;64387:264:0;;;;;:::i;:::-;;:::i;63189:37::-;;;;;;;;;;;;63223:3;63189:37;;70916:2398;;;;;;:::i;:::-;;:::i;66906:104::-;;;;;;;;;;-1:-1:-1;66906:104:0;;;;;:::i;:::-;;:::i;65597:57::-;;;;;;;;;;-1:-1:-1;65597:57:0;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;65597:57:0;;;;;;;15543:14:1;15584:15;;;15566:34;;15636:15;;;;15631:2;15616:18;;15609:43;-1:-1:-1;;;;;15688:55:1;15668:18;;;15661:83;15521:2;15506:18;65597:57:0;15335:415:1;61927:131:0;;;;;;;;;;-1:-1:-1;61927:131:0;;;;;:::i;:::-;;:::i;63116:66::-;;;;;;;;;;;;63156:26;63116:66;;55257:138;;;;;;;;;;-1:-1:-1;55257:138:0;;;;;:::i;:::-;;:::i;63480:47::-;;;;;;;;;;-1:-1:-1;63480:47:0;;;;;:::i;:::-;;;;;;;;;;;;;;65359:60;;;;;;;;;;;;65408:11;65359:60;;63601:29;;;;;;;;;;;;;;;;60820:212;60905:4;60928:57;;;60943:42;60928:57;;:97;;;60989:36;61013:11;60989:23;:36::i;:::-;60921:104;60820:212;-1:-1:-1;;60820:212:0:o;64022:359::-;63156:26;53079:16;53090:4;53079:10;:16::i;:::-;-1:-1:-1;;;;;64146:19:0;::::1;64126:17;64146:19:::0;;;:12:::1;:19;::::0;;;;;;64179:14;;;64175:27:::1;;64195:7;64022:359:::0;;;:::o;64175:27::-:1;-1:-1:-1::0;;;;;64243:19:0;::::1;64265:1;64243:19:::0;;;:12:::1;:19;::::0;;;;:23;64276:45:::1;::::0;64300:9;64311;64276:23:::1;:45::i;:::-;64336:38;::::0;;-1:-1:-1;;;;;16036:15:1;;;16018:34;;16088:15;;16083:2;16068:18;;16061:43;16120:18;;;16113:34;;;64336:38:0::1;::::0;15945:2:1;15930:18;64336:38:0::1;;;;;;;64116:265;53105:1;64022:359:::0;;;:::o;76275:648::-;62947:25;53079:16;53090:4;53079:10;:16::i;:::-;76491:22:::1;76450:30;::::0;;;:15:::1;:30;::::0;;;;:37;::::1;;:63;::::0;::::1;;;;;;:::i;:::-;;76446:93;;76522:17;;;;;;;;;;;;;;76446:93;76549:30;::::0;;;:15:::1;:30;::::0;;;;;;;;:67;;76589:27:::1;76712:70:::0;;;;76626:76:::1;76686:15;76626:76;;;76712:70:::0;;;;76769:12:::1;76712:70;;;::::0;;76792:53;::::1;::::0;-1:-1:-1;;;;;76792:53:0;::::1;::::0;;::::1;::::0;;;::::1;::::0;;;76861:55;;785:25:1;;;76861:55:0;;76792:53;;76549:30;;76861:55:::1;::::0;;;;;;;::::1;76275:648:::0;;;;:::o;54841:136::-;54490:7;54516:12;;;;;;;;;;:22;;;53079:16;53090:4;53079:10;:16::i;:::-;54945:25:::1;54956:4;54962:7;54945:10;:25::i;:::-;;54841:136:::0;;;:::o;55943:245::-;-1:-1:-1;;;;;56036:34:0;;23368:10;56036:34;56032:102;;56093:30;;;;;;;;;;;;;;56032:102;56144:37;56156:4;56162:18;56144:11;:37::i;76961:1414::-;77051:18;;;;;;77027:21;77120:31;77061:7;77120:22;:31::i;:::-;77079:72;-1:-1:-1;77277:27:0;77236:30;;;;:15;:30;;;;;:37;;;:68;;;;;;;;:::i;:::-;;77232:98;;77313:17;;;;;;;;;;;;;;77232:98;-1:-1:-1;;;;;77424:16:0;;77420:213;;77461:30;;;;:15;:30;;;;;:43;;;;-1:-1:-1;;;;;77461:43:0;;-1:-1:-1;77420:213:0;;;77525:30;;;;:15;:30;;;;;:43;;;;-1:-1:-1;;;;;77525:43:0;77572:10;77525:57;77521:112;;77605:17;;;;;;;;;;;;;;77521:112;77658:30;;;;:15;:30;;;;;:50;65004:10;;77658:50;;;;;;;81985:15;81978:45;81970:53;77647:80;77643:142;;77750:24;;;;;;;;;;;;;;77643:142;77795:30;;;;:15;:30;;;;;:68;;;;77835:28;77795:68;;;77938:27;;;;:31;77934:105;;78012:27;;;;77984:23;;;;-1:-1:-1;;;;;77971:37:0;;;;;:12;:37;;;;;:68;;:37;;;:68;;78012:27;;77971:68;:::i;:::-;;;;-1:-1:-1;;77934:105:0;78134:23;;;;78184:24;;;;78218:35;-1:-1:-1;;;;;78218:23:0;;78242:2;78184:24;78218:23;:35::i;:::-;78305:30;;;;:15;:30;;;;;;;;;:43;78269:99;;-1:-1:-1;;;;;16669:55:1;;;16651:74;;16741:18;;;16734:34;;;78269:99:0;;;;78305:43;;;;;;;;:30;;78269:99;;16624:18:1;78269:99:0;;;;;;;77017:1358;;;;76961:1414;;:::o;66134:369::-;66205:291;66234:6;66264:221;;;;;;;;66319:1;-1:-1:-1;;;;;66264:221:0;;;;;66364:1;66264:221;;;;66392:9;;;;;;;;;;;;66264:221;;;;66430:1;66264:221;;;;66461:9;;;;;;;;;;;;66264:221;;;66205:6;:291::i;:::-;66134:369;:::o;79059:169::-;79134:26;-1:-1:-1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;79134:26:0;79190:7;79179:42;;;;;;;;;;;;:::i;67821:1169::-;67902:18;;;;;;67878:21;67972:31;67912:7;67972:22;:31::i;:::-;67931:72;-1:-1:-1;68059:22:0;68018:30;;;;:15;:30;;;;;:37;;;:63;;;;;;;;:::i;:::-;;68014:93;;68090:17;;;;;;;;;;;;;;68014:93;68145:10;53546:4;53569:29;;;:12;;:29;:12;:29;;;;;68118:382;;;68253:11;:20;;;68234:15;:39;68230:73;;68282:21;;;;;;;;;;;;;;68230:73;68118:382;;;65149:6;68424:11;:20;;;:35;;;;:::i;:::-;68405:15;:54;68401:88;;68468:21;;;;;;;;;;;;;;68401:88;68566:30;;;;:15;:30;;;;;;:61;;;;68606:21;68566:61;;;68713:24;;;68763:23;;;;68840:27;;;;68813:24;;;;68713;;68763:23;;68813:54;;68840:27;68813:54;:::i;:::-;68796:71;-1:-1:-1;68877:35:0;-1:-1:-1;;;;;68877:23:0;;68901:2;68796:71;68877:23;:35::i;:::-;68928:55;;;-1:-1:-1;;;;;16669:55:1;;;16651:74;;16756:2;16741:18;;16734:34;;;68928:55:0;;;68950:13;;68928:55;;16624:18:1;68928:55:0;;;;;;;67868:1122;;;;;67821:1169;:::o;66696:170::-;66772:87;66804:7;66794:18;;;;;;66826:10;66847;66772:5;:87::i;:::-;66696:170;;:::o;66541:117::-;66605:46;66621:7;66639:10;66605:5;:46::i;61617:142::-;61698:7;61724:18;;;:12;:18;;;;;:28;;61746:5;61724:21;:28::i;:::-;61717:35;61617:142;-1:-1:-1;;;61617:142:0:o;73354:2881::-;73457:18;;;;;;73433:21;73526:31;73467:7;73526:22;:31::i;:::-;73485:72;;73567:57;73588:11;73601:13;73616:7;73567:20;:57::i;:::-;73728:107;;;;;;;;;;73761:12;73728:107;;;;73799:15;73728:107;;;;;;;;;-1:-1:-1;;;;;73728:107:0;;;;;;;;;-1:-1:-1;73680:33:0;;;:18;:33;;;;;;;:155;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;73958:25;;;74009:21;;;;74057:22;;;;73958:25;;74009:21;;74057:22;74294:38;;;;;74290:719;;74409:21;;;;:26;74405:73;;74444:34;;;;;;;;;;;;;;74405:73;74566:6;74553:9;:19;74549:51;;74581:19;;;;;;;;;;;;;;74549:51;74290:719;;;74720:11;:21;;;74707:9;:34;74703:66;;74750:19;;;;;;;;;;;;;;74703:66;74944:54;-1:-1:-1;;;;;74944:30:0;;74975:10;74987:2;74991:6;74944:30;:54::i;:::-;75023:22;;;;:29;:34;75019:776;;75375:104;75409:2;75420:5;75435:6;75455:11;:22;;;75375:21;:104::i;:::-;75019:776;;;75500:9;:14;75496:299;;75743:41;75769:2;75774:9;75743:17;:41::i;:::-;75914:2;-1:-1:-1;;;;;75810:418:0;75889:7;-1:-1:-1;;;;;75810:418:0;75853:13;75810:418;75945:11;:25;;;75997:11;:23;;;76045:11;:21;;;76094:11;:24;;;76144:11;:22;;;76196:11;:21;;;75810:418;;;;;;;;;;19501:10:1;19489:23;;;;19471:42;;-1:-1:-1;;;;;19610:15:1;;;19605:2;19590:18;;19583:43;19662:15;;;;19657:2;19642:18;;19635:43;19709:2;19694:18;;19687:34;19752:3;19737:19;;19730:35;;;;19796:3;19781:19;;19774:35;19458:3;19443:19;;19186:629;75810:418:0;;;;;;;;73423:2812;;;;;73354:2881;;:::o;69028:392::-;69109:4;69170:27;69129:30;;;;:15;:30;;;;;:37;;;:68;;;;;;;;:::i;:::-;;69125:98;;69206:17;;;;;;;;;;;;;;69125:98;69237:30;;;;:15;:30;;;;;:43;-1:-1:-1;;;;;69237:54:0;;;:43;;;;;:54;69233:84;;69300:17;;;;;;;;;;;;;;69233:84;-1:-1:-1;;69345:30:0;;;;:15;:30;;;;;:50;65004:10;69345:50;;;;;;;;81985:15;81978:45;81970:53;69334:79;;69028:392::o;69755:1121::-;-1:-1:-1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;69956:36:0;;;;;:4;;:27;;:36;;69984:7;;69956:36;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;69956:36:0;;;;;;;;;;;;:::i;:::-;;;69952:918;;70830:7;70819:40;;;;;;;;;;;;:::i;69952:918::-;70146:597;;;;;;;;70197:4;:18;;;70146:597;;;;;;70246:4;:16;;;70146:597;;;;;;70294:4;:17;;;-1:-1:-1;;;;;70146:597:0;;;;;70344:4;:18;;;-1:-1:-1;;;;;70146:597:0;;;;;70393:4;:16;;;-1:-1:-1;;;;;70146:597:0;;;;;70438:4;:14;;;-1:-1:-1;;;;;70146:597:0;;;;;70484:4;:17;;;70146:597;;;;70531:4;:15;;;70146:597;;;;70581:4;:20;;;70146:597;;;;70633:4;:14;;;70651:1;70633:19;;70146:597;;;;;;70680:4;:13;;;70146:597;;;;70718:4;:10;;;70146:597;;;70139:604;;;69755:1121;;;:::o;69952:918::-;69755:1121;;;:::o;67048:735::-;63087:23;53079:16;53090:4;53079:10;:16::i;:::-;67173:27:::1;67132:30;::::0;;;:15:::1;:30;::::0;;;;:37;::::1;;:68;::::0;::::1;;;;;;:::i;:::-;;67128:98;;67209:17;;;;;;;;;;;;;;67128:98;67251:30;::::0;;;:15:::1;:30;::::0;;;;:50;65004:10:::1;::::0;67251:50:::1;::::0;::::1;;::::0;;::::1;81985:15:::0;81978:45;81970:53;67240:79:::1;67236:138;;;67342:21;;;;;;;;;;;;;;67236:138;67461:30;::::0;;;:15:::1;:30;::::0;;;;;67501:22:::1;67663:51:::0;;67730:46;67765:10:::1;::::0;67461:30;;67730:46:::1;::::0;67461:30;67730:46:::1;67048:735:::0;;:::o;63726:290::-;63156:26;53079:16;53090:4;53079:10;:16::i;:::-;63271:6:::1;63825:10;:26;;63817:55;;;::::0;::::1;::::0;;21574:2:1;63817:55:0::1;::::0;::::1;21556:21:1::0;21613:2;21593:18;;;21586:30;21652:18;21632;;;21625:46;21688:18;;63817:55:0::1;;;;;;;;;63903:15;::::0;;63928:28;;;;63971:38:::1;::::0;;21891:25:1;;;21947:2;21932:18;;21925:34;;;63971:38:0::1;::::0;21864:18:1;63971:38:0::1;;;;;;;;63807:209;63726:290:::0;;:::o;64387:264::-;63156:26;53079:16;53090:4;53079:10;:16::i;:::-;64512:14:::1;::::0;;64536:34;;;;64585:59:::1;::::0;;21891:25:1;;;21947:2;21932:18;;21925:34;;;64585:59:0::1;::::0;21864:18:1;64585:59:0::1;21717:248:1::0;70916:2398:0;71017:25;71071:8;:32;;;71052:15;71045:58;;;;:::i;:::-;71017:86;;71113:59;71135:6;71143:8;71153:18;71113:21;:59::i;:::-;71308:20;71331:51;71342:6;:18;;;71362:6;:19;;;71331:10;:51::i;:::-;71308:74;;71450:23;71505:1;71487:15;;:19;71483:85;;;63223:3;71542:15;;71527:12;:30;;;;:::i;:::-;71526:42;;;;:::i;:::-;71508:60;;71483:85;71578:31;71594:15;71578:31;;:::i;:::-;;;71722:20;71769:924;;;;;;;;71829:13;71769:924;;;;;;71874:6;:17;;;71769:924;;;;;;71923:6;:13;;;-1:-1:-1;;;;;71769:924:0;;;;;71969:6;:9;;;-1:-1:-1;;;;;71769:924:0;;;;;72009:6;:18;;;-1:-1:-1;;;;;71769:924:0;;;;;72056:6;:16;;;-1:-1:-1;;;;;71769:924:0;;;;;72104:12;71769:924;;;;72146:6;:17;;;71769:924;;;;72198:15;71769:924;;;;72242:8;:18;;;71769:924;;;;72288:6;:15;;;71769:924;;;;72328:12;:27;72341:6;:13;;;-1:-1:-1;;;;;72328:27:0;-1:-1:-1;;;;;72328:27:0;;;;;;;;;;;;;:29;;;;;;;;;:::i;:::-;;;;;71769:924;;;;72430:8;:21;;;-1:-1:-1;;;;;71769:924:0;;;;;72610:18;71769:924;;;;72659:8;:19;;;71769:924;;;71745:958;;;;;;;;:::i;:::-;;;;;;;-1:-1:-1;;71745:958:0;;;;;;72737:18;;71745:958;72737:18;;;;;;;72713:21;72765:30;;;:15;:30;;;;;;:62;;;;72805:22;72765:62;;;72923:13;;;72993:17;;73037:18;;;;;73080:16;;;;73162:17;;;;73207:18;;;;71745:958;;-1:-1:-1;72737:18:0;;-1:-1:-1;;;;;72843:398:0;;;;72737:18;;72843:398;;;;71745:958;;72993:17;;73037:18;73080:16;73124:12;;73207:23;;;;72843:398;:::i;:::-;;;;;;;;73275:13;73256:51;73290:8;:16;;;73256:51;;;;;;:::i;:::-;;;;;;;;71007:2307;;;;;70916:2398;;:::o;66906:104::-;66962:41;66978:7;66999:1;66962:5;:41::i;61927:131::-;61998:7;62024:18;;;:12;:18;;;;;:27;;:25;:27::i;55257:138::-;54490:7;54516:12;;;;;;;;;;:22;;;53079:16;53090:4;53079:10;:16::i;:::-;55362:26:::1;55374:4;55380:7;55362:11;:26::i;53180:202::-:0;53265:4;53288:47;;;53303:32;53288:47;;:87;;-1:-1:-1;45095:25:0;45080:40;;;;53339:36;44981:146;53814:103;53880:30;53891:4;23368:10;53880;:30::i;58092:653::-;58267:4;-1:-1:-1;;;;;58253:19:0;;;58249:32;;58092:653;;;:::o;58249:32::-;58353:5;58362:1;58353:10;58349:23;;58092:653;;;:::o;58349:23::-;58385:20;-1:-1:-1;;;;;58385:20:0;;;58381:358;;58565:12;58582:2;-1:-1:-1;;;;;58582:7:0;58597:5;58582:25;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;58564:43;;;58629:7;58621:39;;;;;;;24145:2:1;58621:39:0;;;24127:21:1;24184:2;24164:18;;;24157:30;24223:21;24203:18;;;24196:49;24262:18;;58621:39:0;23943:343:1;58381:358:0;58691:37;-1:-1:-1;;;;;58691:26:0;;58718:2;58722:5;58691:26;:37::i;62160:257::-;62246:4;62262:12;62277:31;62294:4;62300:7;62277:16;:31::i;:::-;62262:46;;62322:7;62318:69;;;62345:18;;;;:12;:18;;;;;:31;;62368:7;62345:22;:31::i;:::-;;62403:7;62160:257;-1:-1:-1;;;62160:257:0:o;62520:262::-;62607:4;62623:12;62638:32;62656:4;62662:7;62638:17;:32::i;:::-;62623:47;;62684:7;62680:72;;;62707:18;;;;:12;:18;;;;;:34;;62733:7;62707:25;:34::i;34071:156::-;34145:7;34195:22;34199:3;34211:5;34195:3;:22::i;83620:951::-;-1:-1:-1;;;;;83808:21:0;;83804:47;;83838:13;;;;;;;;;;;;;;83804:47;78886:4;78957:33;;;:18;:33;;;;;:41;;;;-1:-1:-1;;;;;78957:41:0;:55;83922:60;;83962:20;;;;;;;;;;;;;;83922:60;84030:13;83996:48;;:11;:23;;;:48;;;83992:77;;84053:16;;;;;;;;;;;;;;83992:77;84151:11;:20;;;84133:15;:38;84129:69;;;84180:18;;;;;;;;;;;;;;84129:69;84328:30;;;;-1:-1:-1;;;;;84328:44:0;;;;;:101;;;84422:7;-1:-1:-1;;;;;84388:41:0;:11;:30;;;-1:-1:-1;;;;;84388:41:0;;;84328:101;:166;;;;;84464:11;:30;;;84445:15;:49;;84328:166;84311:254;;;84526:28;;;;;;;;;;;;;;46696:188;46823:53;;-1:-1:-1;;;;;16036:15:1;;;46823:53:0;;;16018:34:1;16088:15;;;16068:18;;;16061:43;16120:18;;;16113:34;;;46796:81:0;;46816:5;;46838:18;;;;;15930::1;;46823:53:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;46796:19;:81::i;80387:999::-;80562:21;80663:5;80670:6;80678:10;80598:92;;;;;;;;;;:::i;:::-;;;;-1:-1:-1;;80598:92:0;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;80797:84:0;80836:9;80598:92;80870:9;80797:29;:84::i;:::-;80771:110;;80947:10;:17;80968:1;80947:22;80943:59;;80978:24;;;;;;;;;;;;;;80943:59;81081:10;:17;81102:2;81081:23;81077:67;;81113:31;;;;;;;;;;;;;;81077:67;81258:56;81227:19;81235:10;81227:19;:::i;:::-;:88;81223:157;;81338:31;;;;;;;;;;;;;;81223:157;80552:834;;80387:999;;;;:::o;17900:331::-;18009:6;17985:21;:30;17981:109;;;18038:41;;;;;18073:4;18038:41;;;12187:74:1;12160:18;;18038:41:0;12041:226:1;17981:109:0;18101:12;18119:9;-1:-1:-1;;;;;18119:14:0;18141:6;18119:33;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;18100:52;;;18167:7;18162:63;;18197:17;;;;;;;;;;;;;;82365:1176;82618:13;82597:6;:17;;;:34;;;82593:63;;82640:16;;;;;;;;;;;;;;82593:63;82670:19;;;;:24;;:50;;-1:-1:-1;82698:17:0;;;;:22;82670:50;82666:80;;;82729:17;;;;;;;;;;;;;;82666:80;82760:13;;;;-1:-1:-1;;;;;82760:27:0;;;:54;;-1:-1:-1;82791:9:0;;;;-1:-1:-1;;;;;82791:23:0;;82760:54;82756:80;;;82823:13;;;;;;;;;;;;;;82756:80;82850:18;;;;-1:-1:-1;;;;;82850:32:0;;;:66;;-1:-1:-1;82886:16:0;;;;-1:-1:-1;;;;;82886:30:0;;82850:66;82846:92;;;82925:13;;;;;;;;;;;;;;82846:92;82970:37;65288:10;82970:15;:37;:::i;:::-;82952:6;:15;;;:55;82948:86;;;83016:18;;;;;;;;;;;;;;82948:86;65408:11;83075:8;:19;;;:26;:51;83071:90;;;83135:26;;;;;;;;;;;;;;83071:90;83175:18;;;;:23;;;;:76;;-1:-1:-1;83202:16:0;;;;-1:-1:-1;;;;;83202:49:0;57809:42;83202:49;83175:76;83171:148;;;83274:34;;;;;;;;;;;;;;83171:148;83424:1;83402:18;:23;;:71;;;;83457:6;:15;;;83429:18;:44;83402:71;83398:137;;;83496:28;;;;;;;;;;;;;;79306:923;79375:20;79411:38;-1:-1:-1;;;;;79411:38:0;;;79407:816;;79563:9;79553:6;:19;79549:51;;79581:19;;;;;;;;;;;;;;79549:51;-1:-1:-1;79629:9:0;79407:816;;;79669:24;:5;-1:-1:-1;;;;;79669:22:0;;:24::i;:::-;79774:38;;;;;79806:4;79774:38;;;12187:74:1;-1:-1:-1;;;;;79774:23:0;;;;;12160:18:1;;79774:38:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;79759:53;-1:-1:-1;79958:65:0;-1:-1:-1;;;;;79958:30:0;;79989:10;80009:4;80016:6;79958:30;:65::i;:::-;80159:38;;;;;80191:4;80159:38;;;12187:74:1;80200:12:0;;-1:-1:-1;;;;;80159:23:0;;;;;12160:18:1;;80159:38:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;:53;;;;:::i;33614:115::-;33677:7;33703:19;33711:3;29053:18;;28971:107;54047:197;53546:4;53569:12;;;;;;;;;;;-1:-1:-1;;;;;53569:29:0;;;;;;;;;;;;54130:108;;54180:47;;;;;-1:-1:-1;;;;;16669:55:1;;54180:47:0;;;16651:74:1;16741:18;;;16734:34;;;16624:18;;54180:47:0;16477:297:1;46297:160:0;46406:43;;-1:-1:-1;;;;;16669:55:1;;;46406:43:0;;;16651:74:1;16741:18;;;16734:34;;;46379:71:0;;46399:5;;46421:14;;;;;16624:18:1;;46406:43:0;16477:297:1;56794:316:0;56871:4;53569:12;;;;;;;;;;;-1:-1:-1;;;;;53569:29:0;;;;;;;;;;;;56887:217;;56930:6;:12;;;;;;;;;;;-1:-1:-1;;;;;56930:29:0;;;;;;;;;:36;;;;56962:4;56930:36;;;57012:12;23368:10;;23289:96;57012:12;-1:-1:-1;;;;;56985:40:0;57003:7;-1:-1:-1;;;;;56985:40:0;56997:4;56985:40;;;;;;;;;;-1:-1:-1;57046:4:0;57039:11;;56887:217;-1:-1:-1;57088:5:0;57081:12;;32813:150;32883:4;32906:50;32911:3;-1:-1:-1;;;;;32931:23:0;;32906:4;:50::i;57345:317::-;57423:4;53569:12;;;;;;;;;;;-1:-1:-1;;;;;53569:29:0;;;;;;;;;;;;57439:217;;;57513:5;57481:12;;;;;;;;;;;-1:-1:-1;;;;;57481:29:0;;;;;;;;;;:37;;;;;;57537:40;23368:10;;57481:12;;57537:40;;57513:5;57537:40;-1:-1:-1;57598:4:0;57591:11;;33131:156;33204:4;33227:53;33235:3;-1:-1:-1;;;;;33255:23:0;;33227:7;:53::i;29420:118::-;29487:7;29513:3;:11;;29525:5;29513:18;;;;;;;;:::i;:::-;;;;;;;;;29506:25;;29420:118;;;;:::o;49053:629::-;49472:23;49498:33;-1:-1:-1;;;;;49498:27:0;;49526:4;49498:27;:33::i;:::-;49472:59;;49545:10;:17;49566:1;49545:22;;:57;;;;;49583:10;49572:30;;;;;;;;;;;;:::i;:::-;49571:31;49545:57;49541:135;;;49625:40;;;;;-1:-1:-1;;;;;12205:55:1;;49625:40:0;;;12187:74:1;12160:18;;49625:40:0;12041:226:1;19549:392:0;19648:12;19700:5;19676:21;:29;19672:108;;;19728:41;;;;;19763:4;19728:41;;;12187:74:1;12160:18;;19728:41:0;12041:226:1;19672:108:0;19790:12;19804:23;19831:6;-1:-1:-1;;;;;19831:11:0;19850:5;19857:4;19831:31;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;19789:73;;;;19879:55;19906:6;19914:7;19923:10;19879:26;:55::i;:::-;19872:62;19549:392;-1:-1:-1;;;;;;19549:392:0:o;59909:344::-;60076:38;-1:-1:-1;;;;;60076:38:0;;;60072:69;;60123:18;;;;;;;;;;;;;;60072:69;60197:5;-1:-1:-1;;;;;60197:17:0;;60218:1;60197:22;60193:53;;60228:18;;;;;;;;;;;;;;26738:406;26801:4;28857:21;;;:14;;;:21;;;;;;26817:321;;-1:-1:-1;26859:23:0;;;;;;;;:11;:23;;;;;;;;;;;;;27041:18;;27017:21;;;:14;;;:21;;;;;;:42;;;;27073:11;;27312:1368;27378:4;27507:21;;;:14;;;:21;;;;;;27543:13;;27539:1135;;27910:18;27931:12;27942:1;27931:8;:12;:::i;:::-;27977:18;;27910:33;;-1:-1:-1;27957:17:0;;27977:22;;27998:1;;27977:22;:::i;:::-;27957:42;;28032:9;28018:10;:23;28014:378;;28061:17;28081:3;:11;;28093:9;28081:22;;;;;;;;:::i;:::-;;;;;;;;;28061:42;;28228:9;28202:3;:11;;28214:10;28202:23;;;;;;;;:::i;:::-;;;;;;;;;;;;:35;;;;28341:25;;;:14;;;:25;;;;;:36;;;28014:378;28470:17;;:3;;:17;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;28573:3;:14;;:21;28588:5;28573:21;;;;;;;;;;;28566:28;;;28616:4;28609:11;;;;;;;27539:1135;28658:5;28651:12;;;;;19074:151;19149:12;19180:38;19202:6;19210:4;19216:1;19180:21;:38::i;20994:582::-;21138:12;21167:7;21162:408;;21190:19;21198:10;21190:7;:19::i;:::-;21162:408;;;21414:17;;:22;:49;;;;-1:-1:-1;;;;;;21440:18:0;;;:23;21414:49;21410:119;;;21490:24;;;;;-1:-1:-1;;;;;12205:55:1;;21490:24:0;;;12187:74:1;12160:18;;21490:24:0;12041:226:1;21410:119:0;-1:-1:-1;21549:10:0;21542:17;;22112:516;22243:17;;:21;22239:383;;22471:10;22465:17;22527:15;22514:10;22510:2;22506:19;22499:44;22239:383;22594:17;;;;;;;;;;;;;;14:332:1;72:6;125:2;113:9;104:7;100:23;96:32;93:52;;;141:1;138;131:12;93:52;180:9;167:23;230:66;223:5;219:78;212:5;209:89;199:117;;312:1;309;302:12;821:180;880:6;933:2;921:9;912:7;908:23;904:32;901:52;;;949:1;946;939:12;901:52;-1:-1:-1;972:23:1;;821:180;-1:-1:-1;821:180:1:o;1006:184::-;1058:77;1055:1;1048:88;1155:4;1152:1;1145:15;1179:4;1176:1;1169:15;1195:297;1279:1;1272:5;1269:12;1259:200;;1315:77;1312:1;1305:88;1416:4;1413:1;1406:15;1444:4;1441:1;1434:15;1259:200;1468:18;;1195:297::o;1497:214::-;1646:2;1631:18;;1658:47;1635:9;1687:6;1658:47;:::i;1716:154::-;-1:-1:-1;;;;;1795:5:1;1791:54;1784:5;1781:65;1771:93;;1860:1;1857;1850:12;1875:134;1943:20;;1972:31;1943:20;1972:31;:::i;2014:388::-;2082:6;2090;2143:2;2131:9;2122:7;2118:23;2114:32;2111:52;;;2159:1;2156;2149:12;2111:52;2198:9;2185:23;2217:31;2242:5;2217:31;:::i;:::-;2267:5;-1:-1:-1;2324:2:1;2309:18;;2296:32;2337:33;2296:32;2337:33;:::i;:::-;2389:7;2379:17;;;2014:388;;;;;:::o;2589:383::-;2666:6;2674;2682;2735:2;2723:9;2714:7;2710:23;2706:32;2703:52;;;2751:1;2748;2741:12;2703:52;2787:9;2774:23;2764:33;;2844:2;2833:9;2829:18;2816:32;2806:42;;2898:2;2887:9;2883:18;2870:32;2911:31;2936:5;2911:31;:::i;:::-;2961:5;2951:15;;;2589:383;;;;;:::o;2977:247::-;3036:6;3089:2;3077:9;3068:7;3064:23;3060:32;3057:52;;;3105:1;3102;3095:12;3057:52;3144:9;3131:23;3163:31;3188:5;3163:31;:::i;3229:315::-;3297:6;3305;3358:2;3346:9;3337:7;3333:23;3329:32;3326:52;;;3374:1;3371;3364:12;3326:52;3410:9;3397:23;3387:33;;3470:2;3459:9;3455:18;3442:32;3483:31;3508:5;3483:31;:::i;3549:184::-;3601:77;3598:1;3591:88;3698:4;3695:1;3688:15;3722:4;3719:1;3712:15;3738:255;3810:2;3804:9;3852:6;3840:19;;3889:18;3874:34;;3910:22;;;3871:62;3868:88;;;3936:18;;:::i;:::-;3972:2;3965:22;3738:255;:::o;3998:253::-;4070:2;4064:9;4112:4;4100:17;;4147:18;4132:34;;4168:22;;;4129:62;4126:88;;;4194:18;;:::i;4256:255::-;4328:2;4322:9;4370:6;4358:19;;4407:18;4392:34;;4428:22;;;4389:62;4386:88;;;4454:18;;:::i;4516:252::-;4588:2;4582:9;4630:3;4618:16;;4664:18;4649:34;;4685:22;;;4646:62;4643:88;;;4711:18;;:::i;4773:334::-;4844:2;4838:9;4900:2;4890:13;;-1:-1:-1;;4886:86:1;4874:99;;5003:18;4988:34;;5024:22;;;4985:62;4982:88;;;5050:18;;:::i;:::-;5086:2;5079:22;4773:334;;-1:-1:-1;4773:334:1:o;5112:245::-;5160:4;5193:18;5185:6;5182:30;5179:56;;;5215:18;;:::i;:::-;-1:-1:-1;5272:2:1;5260:15;-1:-1:-1;;5256:88:1;5346:4;5252:99;;5112:245::o;5362:462::-;5404:5;5457:3;5450:4;5442:6;5438:17;5434:27;5424:55;;5475:1;5472;5465:12;5424:55;5511:6;5498:20;5542:48;5558:31;5586:2;5558:31;:::i;:::-;5542:48;:::i;:::-;5615:2;5606:7;5599:19;5661:3;5654:4;5649:2;5641:6;5637:15;5633:26;5630:35;5627:55;;;5678:1;5675;5668:12;5627:55;5743:2;5736:4;5728:6;5724:17;5717:4;5708:7;5704:18;5691:55;5791:1;5766:16;;;5784:4;5762:27;5755:38;;;;5770:7;5362:462;-1:-1:-1;;;5362:462:1:o;5829:455::-;5906:6;5914;5967:2;5955:9;5946:7;5942:23;5938:32;5935:52;;;5983:1;5980;5973:12;5935:52;6023:9;6010:23;6056:18;6048:6;6045:30;6042:50;;;6088:1;6085;6078:12;6042:50;6111:49;6152:7;6143:6;6132:9;6128:22;6111:49;:::i;:::-;6101:59;;;6210:2;6199:9;6195:18;6182:32;6223:31;6248:5;6223:31;:::i;6289:121::-;6374:10;6367:5;6363:22;6356:5;6353:33;6343:61;;6400:1;6397;6390:12;6415:132;6482:20;;6511:30;6482:20;6511:30;:::i;6552:118::-;6638:5;6631:13;6624:21;6617:5;6614:32;6604:60;;6660:1;6657;6650:12;6675:128;6740:20;;6769:28;6740:20;6769:28;:::i;6808:806::-;6867:5;6915:6;6903:9;6898:3;6894:19;6890:32;6887:52;;;6935:1;6932;6925:12;6887:52;6957:22;;:::i;:::-;6948:31;;7002:28;7020:9;7002:28;:::i;:::-;6995:5;6988:43;7063:38;7097:2;7086:9;7082:18;7063:38;:::i;:::-;7058:2;7051:5;7047:14;7040:62;7134:38;7168:2;7157:9;7153:18;7134:38;:::i;:::-;7129:2;7122:5;7118:14;7111:62;7205:38;7239:2;7228:9;7224:18;7205:38;:::i;:::-;7200:2;7193:5;7189:14;7182:62;7277:39;7311:3;7300:9;7296:19;7277:39;:::i;:::-;7271:3;7264:5;7260:15;7253:64;7378:3;7367:9;7363:19;7350:33;7344:3;7337:5;7333:15;7326:58;7445:3;7434:9;7430:19;7417:33;7411:3;7404:5;7400:15;7393:58;7484:36;7515:3;7504:9;7500:19;7484:36;:::i;:::-;7478:3;7471:5;7467:15;7460:61;7540:3;7603:2;7592:9;7588:18;7575:32;7570:2;7563:5;7559:14;7552:56;;6808:806;;;;:::o;7619:237::-;7707:6;7760:3;7748:9;7739:7;7735:23;7731:33;7728:53;;;7777:1;7774;7767:12;7728:53;7800:50;7842:7;7831:9;7800:50;:::i;7861:320::-;7929:6;7982:2;7970:9;7961:7;7957:23;7953:32;7950:52;;;7998:1;7995;7988:12;7950:52;8038:9;8025:23;8071:18;8063:6;8060:30;8057:50;;;8103:1;8100;8093:12;8057:50;8126:49;8167:7;8158:6;8147:9;8143:22;8126:49;:::i;:::-;8116:59;7861:320;-1:-1:-1;;;;7861:320:1:o;8417:250::-;8502:1;8512:113;8526:6;8523:1;8520:13;8512:113;;;8602:11;;;8596:18;8583:11;;;8576:39;8548:2;8541:10;8512:113;;;-1:-1:-1;;8659:1:1;8641:16;;8634:27;8417:250::o;8672:329::-;8713:3;8751:5;8745:12;8778:6;8773:3;8766:19;8794:76;8863:6;8856:4;8851:3;8847:14;8840:4;8833:5;8829:16;8794:76;:::i;:::-;8915:2;8903:15;-1:-1:-1;;8899:88:1;8890:98;;;;8990:4;8886:109;;8672:329;-1:-1:-1;;8672:329:1:o;9006:1866::-;9209:2;9198:9;9191:21;9221:52;9269:2;9258:9;9254:18;9245:6;9239:13;8262:10;8251:22;8239:35;;8186:94;9221:52;9172:4;9320:2;9312:6;9308:15;9302:22;9333:51;9380:2;9369:9;9365:18;9351:12;8262:10;8251:22;8239:35;;8186:94;9333:51;-1:-1:-1;9433:2:1;9421:15;;9415:22;-1:-1:-1;;;;;8351:54:1;;9496:2;9481:18;;8339:67;-1:-1:-1;9549:2:1;9537:15;;9531:22;-1:-1:-1;;;;;8351:54:1;;9612:3;9597:19;;8339:67;-1:-1:-1;9666:3:1;9654:16;;9648:23;-1:-1:-1;;;;;8351:54:1;;9730:3;9715:19;;8339:67;-1:-1:-1;9784:3:1;9772:16;;9766:23;-1:-1:-1;;;;;8351:54:1;;9848:3;9833:19;;8339:67;-1:-1:-1;9908:3:1;9896:16;;9890:23;9884:3;9869:19;;;9862:52;;;;9939:16;;9933:23;9975:3;9994:18;;;9987:30;;;;10042:15;;10036:22;10077:3;10096:18;;;10089:30;;;;10144:15;;10138:22;10179:3;10198:18;;;10191:30;;;;10246:15;;10240:22;10281:3;10300:18;;;10293:30;;;;10348:15;;10342:22;10384:3;10403:19;;;10396:31;;;;10464:16;;10458:23;10501:3;10513:55;10548:19;;;10458:23;-1:-1:-1;;;;;8351:54:1;8339:67;;8285:127;10513:55;10594:16;;10588:23;10631:3;10650:19;;;10643:32;;;;10712:16;;10706:23;10749:6;10771:19;;;10764:32;10706:23;-1:-1:-1;10813:53:1;10861:3;10846:19;;10706:23;10813:53;:::i;10877:513::-;11106:3;11091:19;;11119:47;11095:9;11148:6;11119:47;:::i;:::-;11214:12;11206:6;11202:25;11197:2;11186:9;11182:18;11175:53;11276:14;11268:6;11264:27;11259:2;11248:9;11244:18;11237:55;-1:-1:-1;;;;;11332:6:1;11328:55;11323:2;11312:9;11308:18;11301:83;10877:513;;;;;;;:::o;11395:388::-;11472:6;11480;11533:2;11521:9;11512:7;11508:23;11504:32;11501:52;;;11549:1;11546;11539:12;11501:52;11589:9;11576:23;11622:18;11614:6;11611:30;11608:50;;;11654:1;11651;11644:12;11608:50;11677:49;11718:7;11709:6;11698:9;11694:22;11677:49;:::i;:::-;11667:59;11773:2;11758:18;;;;11745:32;;-1:-1:-1;;;;11395:388:1:o;11788:248::-;11856:6;11864;11917:2;11905:9;11896:7;11892:23;11888:32;11885:52;;;11933:1;11930;11923:12;11885:52;-1:-1:-1;;11956:23:1;;;12026:2;12011:18;;;11998:32;;-1:-1:-1;11788:248:1:o;12605:1373::-;12836:13;;8262:10;8251:22;8239:35;;12805:3;12790:19;;12908:4;12900:6;12896:17;12890:24;12923:53;12970:4;12959:9;12955:20;12941:12;8262:10;8251:22;8239:35;;8186:94;12923:53;;13025:4;13017:6;13013:17;13007:24;13040:56;13090:4;13079:9;13075:20;13059:14;-1:-1:-1;;;;;8351:54:1;8339:67;;8285:127;13040:56;;13145:4;13137:6;13133:17;13127:24;13160:56;13210:4;13199:9;13195:20;13179:14;-1:-1:-1;;;;;8351:54:1;8339:67;;8285:127;13160:56;;13265:4;13257:6;13253:17;13247:24;13280:56;13330:4;13319:9;13315:20;13299:14;-1:-1:-1;;;;;8351:54:1;8339:67;;8285:127;13280:56;;13385:4;13377:6;13373:17;13367:24;13400:56;13450:4;13439:9;13435:20;13419:14;-1:-1:-1;;;;;8351:54:1;8339:67;;8285:127;13400:56;;13512:4;13504:6;13500:17;13494:24;13487:4;13476:9;13472:20;13465:54;13575:4;13567:6;13563:17;13557:24;13550:4;13539:9;13535:20;13528:54;13601:6;13661:2;13653:6;13649:15;13643:22;13638:2;13627:9;13623:18;13616:50;;13685:6;13740:2;13732:6;13728:15;13722:22;13753:51;13800:2;13789:9;13785:18;13769:14;421:13;414:21;402:34;;351:91;13753:51;-1:-1:-1;;13823:6:1;13871:15;;;13865:22;13845:18;;;13838:50;13907:6;13955:15;;;13949:22;13929:18;;;;13922:50;;;;12605:1373;:::o;14168:1162::-;14297:6;14305;14358:3;14346:9;14337:7;14333:23;14329:33;14326:53;;;14375:1;14372;14365:12;14326:53;14398:50;14440:7;14429:9;14398:50;:::i;:::-;14388:60;;14499:3;14488:9;14484:19;14471:33;14523:18;14564:2;14556:6;14553:14;14550:34;;;14580:1;14577;14570:12;14550:34;14603:22;;;;14659:4;14641:16;;;14637:27;14634:47;;;14677:1;14674;14667:12;14634:47;14703:22;;:::i;:::-;14762:2;14749:16;14774:33;14799:7;14774:33;:::i;:::-;14816:22;;14891:2;14883:11;;;14870:25;14854:14;;;14847:49;14942:2;14934:11;;14921:25;14958:16;;;14955:36;;;14987:1;14984;14977:12;14955:36;15023:44;15059:7;15048:8;15044:2;15040:17;15023:44;:::i;:::-;15018:2;15011:5;15007:14;15000:68;;15121:2;15117;15113:11;15100:25;15095:2;15088:5;15084:14;15077:49;15172:3;15168:2;15164:12;15151:26;15202:2;15192:8;15189:16;15186:36;;;15218:1;15215;15208:12;15186:36;15255:44;15291:7;15280:8;15276:2;15272:17;15255:44;:::i;:::-;15249:3;15242:5;15238:15;15231:69;;15319:5;15309:15;;;;;14168:1162;;;;;:::o;16158:184::-;16210:77;16207:1;16200:88;16307:4;16304:1;16297:15;16331:4;16328:1;16321:15;16347:125;16412:9;;;16433:10;;;16430:36;;;16446:18;;:::i;16779:136::-;16857:13;;16879:30;16857:13;16879:30;:::i;16920:138::-;16999:13;;17021:31;16999:13;17021:31;:::i;17063:441::-;17116:5;17169:3;17162:4;17154:6;17150:17;17146:27;17136:55;;17187:1;17184;17177:12;17136:55;17216:6;17210:13;17247:48;17263:31;17291:2;17263:31;:::i;17247:48::-;17320:2;17311:7;17304:19;17366:3;17359:4;17354:2;17346:6;17342:15;17338:26;17335:35;17332:55;;;17383:1;17380;17373:12;17332:55;17396:77;17470:2;17463:4;17454:7;17450:18;17443:4;17435:6;17431:17;17396:77;:::i;17509:1672::-;17616:6;17669:2;17657:9;17648:7;17644:23;17640:32;17637:52;;;17685:1;17682;17675:12;17637:52;17718:9;17712:16;17747:18;17788:2;17780:6;17777:14;17774:34;;;17804:1;17801;17794:12;17774:34;17827:22;;;;17883:6;17865:16;;;17861:29;17858:49;;;17903:1;17900;17893:12;17858:49;17929:22;;:::i;:::-;17974:32;18003:2;17974:32;:::i;:::-;17967:5;17960:47;18039:41;18076:2;18072;18068:11;18039:41;:::i;:::-;18034:2;18027:5;18023:14;18016:65;18113:42;18151:2;18147;18143:11;18113:42;:::i;:::-;18108:2;18101:5;18097:14;18090:66;18188:42;18226:2;18222;18218:11;18188:42;:::i;:::-;18183:2;18176:5;18172:14;18165:66;18264:43;18302:3;18298:2;18294:12;18264:43;:::i;:::-;18258:3;18251:5;18247:15;18240:68;18341:43;18379:3;18375:2;18371:12;18341:43;:::i;:::-;18335:3;18324:15;;18317:68;18432:3;18424:12;;;18418:19;18401:15;;;18394:44;18485:3;18477:12;;;18471:19;18454:15;;;18447:44;18510:3;18551:11;;;18545:18;18529:14;;;18522:42;18583:3;18624:11;;;18618:18;18602:14;;;18595:42;18656:3;18697:11;;;18691:18;18675:14;;;18668:42;18729:3;18770:11;;;18764:18;18748:14;;;18741:42;18802:3;18837:42;18867:11;;;18837:42;:::i;:::-;18821:14;;;18814:66;18899:3;18940:11;;;18934:18;18918:14;;;18911:42;18972:3;19006:11;;;19000:18;19030:16;;;19027:36;;;19059:1;19056;19049:12;19027:36;19095:55;19142:7;19131:8;19127:2;19123:17;19095:55;:::i;:::-;19079:14;;;19072:79;;;;-1:-1:-1;19083:5:1;17509:1672;-1:-1:-1;;;;;17509:1672:1:o;19820:217::-;19967:2;19956:9;19949:21;19930:4;19987:44;20027:2;20016:9;20012:18;20004:6;19987:44;:::i;20042:132::-;20118:13;;20140:28;20118:13;20140:28;:::i;20179:1188::-;20282:6;20335:3;20323:9;20314:7;20310:23;20306:33;20303:53;;;20352:1;20349;20342:12;20303:53;20378:22;;:::i;:::-;20423:39;20452:9;20423:39;:::i;:::-;20416:5;20409:54;20495:48;20539:2;20528:9;20524:18;20495:48;:::i;:::-;20490:2;20483:5;20479:14;20472:72;20576:49;20621:2;20610:9;20606:18;20576:49;:::i;:::-;20571:2;20564:5;20560:14;20553:73;20658:49;20703:2;20692:9;20688:18;20658:49;:::i;:::-;20653:2;20646:5;20642:14;20635:73;20741:50;20786:3;20775:9;20771:19;20741:50;:::i;:::-;20735:3;20728:5;20724:15;20717:75;20825:50;20870:3;20859:9;20855:19;20825:50;:::i;:::-;20819:3;20812:5;20808:15;20801:75;20930:3;20919:9;20915:19;20909:26;20903:3;20896:5;20892:15;20885:51;20990:3;20979:9;20975:19;20969:26;20963:3;20956:5;20952:15;20945:51;21015:3;21071:2;21060:9;21056:18;21050:25;21045:2;21038:5;21034:14;21027:49;;21095:3;21130:46;21172:2;21161:9;21157:18;21130:46;:::i;:::-;21114:14;;;21107:70;21196:3;21237:18;;;21231:25;21215:14;;;21208:49;21276:3;21317:18;;;21311:25;21295:14;;;21288:49;;;;-1:-1:-1;21118:5:1;20179:1188;-1:-1:-1;20179:1188:1:o;21970:216::-;22034:9;;;22062:11;;;22009:3;22092:9;;22120:10;;22116:19;;22145:10;;22137:19;;22113:44;22110:70;;;22160:18;;:::i;:::-;22110:70;;21970:216;;;;:::o;22191:168::-;22264:9;;;22295;;22312:15;;;22306:22;;22292:37;22282:71;;22333:18;;:::i;22364:274::-;22404:1;22430;22420:189;;22465:77;22462:1;22455:88;22566:4;22563:1;22556:15;22594:4;22591:1;22584:15;22420:189;-1:-1:-1;22623:9:1;;22364:274::o;22643:128::-;22710:9;;;22731:11;;;22728:37;;;22745:18;;:::i;22776:195::-;22815:3;22846:66;22839:5;22836:77;22833:103;;22916:18;;:::i;:::-;-1:-1:-1;22963:1:1;22952:13;;22776:195::o;22976:752::-;23283:3;23272:9;23265:22;23246:4;23304:45;23344:3;23333:9;23329:19;23321:6;23304:45;:::i;:::-;23397:10;23385:23;;;;23380:2;23365:18;;23358:51;-1:-1:-1;;;;;;23506:15:1;;;23501:2;23486:18;;23479:43;23558:15;;;;23553:2;23538:18;;23531:43;23605:3;23590:19;;23583:35;;;;23649:3;23634:19;;23627:35;23706:14;;23699:22;23693:3;23678:19;;;23671:51;23296:53;22976:752;-1:-1:-1;22976:752:1:o;24291:408::-;-1:-1:-1;;;;;24498:6:1;24494:55;24483:9;24476:74;24586:6;24581:2;24570:9;24566:18;24559:34;24629:2;24624;24613:9;24609:18;24602:30;24457:4;24649:44;24689:2;24678:9;24674:18;24666:6;24649:44;:::i;:::-;24641:52;24291:408;-1:-1:-1;;;;;24291:408:1:o;24704:357::-;24822:12;;24869:4;24858:16;;;24852:23;;24822:12;24887:16;;24884:171;;;24977:66;24967:6;24961:4;24957:17;24954:1;24950:25;24946:98;24939:5;24935:110;24926:119;;24884:171;;24704:357;;;:::o;25066:184::-;25136:6;25189:2;25177:9;25168:7;25164:23;25160:32;25157:52;;;25205:1;25202;25195:12;25157:52;-1:-1:-1;25228:16:1;;25066:184;-1:-1:-1;25066:184:1:o;25557:::-;25609:77;25606:1;25599:88;25706:4;25703:1;25696:15;25730:4;25727:1;25720:15;25746:245;25813:6;25866:2;25854:9;25845:7;25841:23;25837:32;25834:52;;;25882:1;25879;25872:12;25834:52;25914:9;25908:16;25933:28;25955:5;25933:28;:::i;25996:287::-;26125:3;26163:6;26157:13;26179:66;26238:6;26233:3;26226:4;26218:6;26214:17;26179:66;:::i;:::-;26261:16;;;;;25996:287;-1:-1:-1;;25996:287:1:o;26288:184::-;26340:77;26337:1;26330:88;26437:4;26434:1;26427:15;26461:4;26458:1;26451:15","abiDefinition":[{"inputs":[{"internalType":"address","name":"_owner","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AccessControlBadConfirmation","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"bytes32","name":"neededRole","type":"bytes32"}],"name":"AccessControlUnauthorizedAccount","type":"error"},{"inputs":[{"internalType":"address","name":"target","type":"address"}],"name":"AddressEmptyCode","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"AddressInsufficientBalance","type":"error"},{"inputs":[],"name":"AmountIncorrect","type":"error"},{"inputs":[],"name":"CallParamsLengthAboveMax","type":"error"},{"inputs":[],"name":"ChainIncorrect","type":"error"},{"inputs":[],"name":"DeadlineExceeded","type":"error"},{"inputs":[],"name":"DeadlineNotExceeded","type":"error"},{"inputs":[],"name":"DeadlineTooShort","type":"error"},{"inputs":[],"name":"DisputePeriodNotPassed","type":"error"},{"inputs":[],"name":"DisputePeriodPassed","type":"error"},{"inputs":[],"name":"ExclusivityParamsIncorrect","type":"error"},{"inputs":[],"name":"ExclusivityPeriodNotPassed","type":"error"},{"inputs":[],"name":"FailedInnerCall","type":"error"},{"inputs":[],"name":"MsgValueIncorrect","type":"error"},{"inputs":[],"name":"NativeTokenCallValueNotSupported","type":"error"},{"inputs":[],"name":"RecipientIncorrectReturnValue","type":"error"},{"inputs":[],"name":"RecipientNoReturnValue","type":"error"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"SafeERC20FailedOperation","type":"error"},{"inputs":[],"name":"SenderIncorrect","type":"error"},{"inputs":[],"name":"StatusIncorrect","type":"error"},{"inputs":[],"name":"TokenNotContract","type":"error"},{"inputs":[],"name":"TransactionRelayed","type":"error"},{"inputs":[],"name":"ZeroAddress","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"relayer","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"BridgeDepositClaimed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"BridgeDepositRefunded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"relayer","type":"address"}],"name":"BridgeProofDisputed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"relayer","type":"address"},{"indexed":false,"internalType":"bytes32","name":"transactionHash","type":"bytes32"}],"name":"BridgeProofProvided","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":false,"internalType":"bytes","name":"quoteId","type":"bytes"}],"name":"BridgeQuoteDetails","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"relayer","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint32","name":"originChainId","type":"uint32"},{"indexed":false,"internalType":"address","name":"originToken","type":"address"},{"indexed":false,"internalType":"address","name":"destToken","type":"address"},{"indexed":false,"internalType":"uint256","name":"originAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"destAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"chainGasAmount","type":"uint256"}],"name":"BridgeRelayed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"bytes","name":"request","type":"bytes"},{"indexed":false,"internalType":"uint32","name":"destChainId","type":"uint32"},{"indexed":false,"internalType":"address","name":"originToken","type":"address"},{"indexed":false,"internalType":"address","name":"destToken","type":"address"},{"indexed":false,"internalType":"uint256","name":"originAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"destAmount","type":"uint256"},{"indexed":false,"internalType":"bool","name":"sendChainGas","type":"bool"}],"name":"BridgeRequested","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldChainGasAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newChainGasAmount","type":"uint256"}],"name":"ChainGasAmountUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldFeeRate","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newFeeRate","type":"uint256"}],"name":"FeeRateUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"address","name":"recipient","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"FeesSwept","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"previousAdminRole","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"newAdminRole","type":"bytes32"}],"name":"RoleAdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleRevoked","type":"event"},{"inputs":[],"name":"DEFAULT_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"DISPUTE_PERIOD","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"FEE_BPS","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"FEE_RATE_MAX","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"GOVERNOR_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"GUARD_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_CALL_PARAMS_LENGTH","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MIN_DEADLINE_PERIOD","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"REFUNDER_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"REFUND_DELAY","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"RELAYER_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"uint32","name":"dstChainId","type":"uint32"},{"internalType":"address","name":"sender","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"address","name":"originToken","type":"address"},{"internalType":"address","name":"destToken","type":"address"},{"internalType":"uint256","name":"originAmount","type":"uint256"},{"internalType":"uint256","name":"destAmount","type":"uint256"},{"internalType":"bool","name":"sendChainGas","type":"bool"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"internalType":"struct IFastBridge.BridgeParams","name":"params","type":"tuple"}],"name":"bridge","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"uint32","name":"dstChainId","type":"uint32"},{"internalType":"address","name":"sender","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"address","name":"originToken","type":"address"},{"internalType":"address","name":"destToken","type":"address"},{"internalType":"uint256","name":"originAmount","type":"uint256"},{"internalType":"uint256","name":"destAmount","type":"uint256"},{"internalType":"bool","name":"sendChainGas","type":"bool"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"internalType":"struct IFastBridge.BridgeParams","name":"params","type":"tuple"},{"components":[{"internalType":"address","name":"quoteRelayer","type":"address"},{"internalType":"int256","name":"quoteExclusivitySeconds","type":"int256"},{"internalType":"bytes","name":"quoteId","type":"bytes"},{"internalType":"uint256","name":"callValue","type":"uint256"},{"internalType":"bytes","name":"callParams","type":"bytes"}],"internalType":"struct IFastBridgeV2.BridgeParamsV2","name":"paramsV2","type":"tuple"}],"name":"bridge","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"transactionId","type":"bytes32"}],"name":"bridgeProofs","outputs":[{"internalType":"uint96","name":"timestamp","type":"uint96"},{"internalType":"address","name":"relayer","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"bridgeRelayDetails","outputs":[{"internalType":"uint48","name":"blockNumber","type":"uint48"},{"internalType":"uint48","name":"blockTimestamp","type":"uint48"},{"internalType":"address","name":"relayer","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"transactionId","type":"bytes32"}],"name":"bridgeRelays","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"transactionId","type":"bytes32"}],"name":"bridgeStatuses","outputs":[{"internalType":"enum IFastBridgeV2.BridgeStatus","name":"status","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"bridgeTxDetails","outputs":[{"internalType":"enum IFastBridgeV2.BridgeStatus","name":"status","type":"uint8"},{"internalType":"uint40","name":"proofBlockTimestamp","type":"uint40"},{"internalType":"uint48","name":"proofBlockNumber","type":"uint48"},{"internalType":"address","name":"proofRelayer","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"internalType":"address","name":"relayer","type":"address"}],"name":"canClaim","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"chainGasAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"},{"internalType":"address","name":"to","type":"address"}],"name":"claim","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"}],"name":"claim","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"deployBlock","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"transactionId","type":"bytes32"}],"name":"dispute","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"}],"name":"getBridgeTransaction","outputs":[{"components":[{"internalType":"uint32","name":"originChainId","type":"uint32"},{"internalType":"uint32","name":"destChainId","type":"uint32"},{"internalType":"address","name":"originSender","type":"address"},{"internalType":"address","name":"destRecipient","type":"address"},{"internalType":"address","name":"originToken","type":"address"},{"internalType":"address","name":"destToken","type":"address"},{"internalType":"uint256","name":"originAmount","type":"uint256"},{"internalType":"uint256","name":"destAmount","type":"uint256"},{"internalType":"uint256","name":"originFeeAmount","type":"uint256"},{"internalType":"bool","name":"sendChainGas","type":"bool"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint256","name":"nonce","type":"uint256"}],"internalType":"struct IFastBridge.BridgeTransaction","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"}],"name":"getBridgeTransactionV2","outputs":[{"components":[{"internalType":"uint32","name":"originChainId","type":"uint32"},{"internalType":"uint32","name":"destChainId","type":"uint32"},{"internalType":"address","name":"originSender","type":"address"},{"internalType":"address","name":"destRecipient","type":"address"},{"internalType":"address","name":"originToken","type":"address"},{"internalType":"address","name":"destToken","type":"address"},{"internalType":"uint256","name":"originAmount","type":"uint256"},{"internalType":"uint256","name":"destAmount","type":"uint256"},{"internalType":"uint256","name":"originFeeAmount","type":"uint256"},{"internalType":"uint256","name":"callValue","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"address","name":"exclusivityRelayer","type":"address"},{"internalType":"uint256","name":"exclusivityEndTime","type":"uint256"},{"internalType":"bytes","name":"callParams","type":"bytes"}],"internalType":"struct IFastBridgeV2.BridgeTransactionV2","name":"","type":"tuple"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleAdmin","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"uint256","name":"index","type":"uint256"}],"name":"getRoleMember","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleMemberCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"grantRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"hasRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"nonce","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"protocolFeeRate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"protocolFees","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"internalType":"bytes32","name":"destTxHash","type":"bytes32"},{"internalType":"address","name":"relayer","type":"address"}],"name":"prove","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"},{"internalType":"bytes32","name":"destTxHash","type":"bytes32"}],"name":"prove","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"}],"name":"refund","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"}],"name":"relay","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"},{"internalType":"address","name":"relayer","type":"address"}],"name":"relay","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"callerConfirmation","type":"address"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"revokeRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"senderNonces","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"newChainGasAmount","type":"uint256"}],"name":"setChainGasAmount","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"newFeeRate","type":"uint256"}],"name":"setProtocolFeeRate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"address","name":"recipient","type":"address"}],"name":"sweepProtocolFees","outputs":[],"stateMutability":"nonpayable","type":"function"}],"userDoc":{"kind":"user","methods":{"DISPUTE_PERIOD()":{"notice":"Dispute period for relayed transactions"},"MAX_CALL_PARAMS_LENGTH()":{"notice":"Maximum length of accepted callParams"},"MIN_DEADLINE_PERIOD()":{"notice":"Minimum deadline period to relay a requested bridge transaction"},"REFUND_DELAY()":{"notice":"Delay for a transaction after which it could be permisionlessly refunded"},"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256))":{"notice":"Initiates bridge on origin chain to be relayed by off-chain relayer"},"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256),(address,int256,bytes,uint256,bytes))":{"notice":"Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability to provide temporary exclusivity fill rights for the quote relayer."},"bridgeProofs(bytes32)":{"notice":"Returns the timestamp and relayer of a bridge proof"},"bridgeRelayDetails(bytes32)":{"notice":"Relay details on destination chain"},"bridgeRelays(bytes32)":{"notice":"Checks if a transaction has been relayed"},"bridgeStatuses(bytes32)":{"notice":"Returns the status of a bridge transaction"},"bridgeTxDetails(bytes32)":{"notice":"Status of the bridge tx on origin chain"},"canClaim(bytes32,address)":{"notice":"Checks if the dispute period has passed so bridge deposit can be claimed"},"chainGasAmount()":{"notice":"Chain gas amount to forward as rebate if requested"},"claim(bytes)":{"notice":"Completes bridge transaction on origin chain by claiming originally deposited capital.Can only send funds to the relayer address on the proof."},"claim(bytes,address)":{"notice":"Completes bridge transaction on origin chain by claiming originally deposited capital"},"deployBlock()":{"notice":"the block the contract was deployed at"},"dispute(bytes32)":{"notice":"Disputes an outstanding proof in case relayer provided dest chain tx is invalid"},"getBridgeTransaction(bytes)":{"notice":"Decodes bridge request into a bridge transaction"},"getBridgeTransactionV2(bytes)":{"notice":"Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2"},"nonce()":{"notice":"This is deprecated and should not be used."},"protocolFeeRate()":{"notice":"Protocol fee rate taken on origin amount deposited in origin chain"},"protocolFees(address)":{"notice":"Protocol fee amounts accumulated"},"prove(bytes,bytes32)":{"notice":"Provides proof on origin side that relayer provided funds on destination side of bridge transaction"},"prove(bytes32,bytes32,address)":{"notice":"Provides proof on origin side that relayer provided funds on destination side of bridge transaction"},"refund(bytes)":{"notice":"Refunds an outstanding bridge transaction in case optimistic bridging failed"},"relay(bytes)":{"notice":"Relays destination side of bridge transaction by off-chain relayer"},"relay(bytes,address)":{"notice":"Relays destination side of bridge transaction by off-chain relayer"},"senderNonces(address)":{"notice":"Unique bridge nonces tracked per originSender"}},"notice":"FastBridgeV2 is a contract for bridging tokens across chains.","version":1},"developerDoc":{"errors":{"AccessControlBadConfirmation()":[{"details":"The caller of a function is not the expected one. NOTE: Don't confuse with {AccessControlUnauthorizedAccount}."}],"AccessControlUnauthorizedAccount(address,bytes32)":[{"details":"The `account` is missing a role."}],"AddressEmptyCode(address)":[{"details":"There's no code at `target` (it is not a contract)."}],"AddressInsufficientBalance(address)":[{"details":"The ETH balance of the account is not enough to perform the operation."}],"FailedInnerCall()":[{"details":"A call to an address target failed. The target may have reverted."}],"SafeERC20FailedOperation(address)":[{"details":"An operation with an ERC20 token failed."}]},"events":{"RoleAdminChanged(bytes32,bytes32,bytes32)":{"details":"Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole` `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite {RoleAdminChanged} not being emitted signaling this."},"RoleGranted(bytes32,address,address)":{"details":"Emitted when `account` is granted `role`. `sender` is the account that originated the contract call, an admin role bearer except when using {AccessControl-_setupRole}."},"RoleRevoked(bytes32,address,address)":{"details":"Emitted when `account` is revoked `role`. `sender` is the account that originated the contract call: - if using `revokeRole`, it is the admin role bearer - if using `renounceRole`, it is the role bearer (i.e. `account`)"}},"kind":"dev","methods":{"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256))":{"params":{"params":"The parameters required to bridge"}},"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256),(address,int256,bytes,uint256,bytes))":{"params":{"params":"The parameters required to bridge","paramsV2":"The parameters for exclusivity fill rights (optional, can be left empty)"}},"bridgeProofs(bytes32)":{"params":{"transactionId":"The ID of the bridge transaction"},"returns":{"relayer":"The relayer address of the bridge proof","timestamp":"The timestamp of the bridge proof"}},"bridgeRelays(bytes32)":{"params":{"transactionId":"The ID of the transaction to check"},"returns":{"_0":"True if the transaction has been relayed, false otherwise"}},"bridgeStatuses(bytes32)":{"params":{"transactionId":"The ID of the bridge transaction"},"returns":{"status":"BridgeStatus Status of the bridge transaction"}},"canClaim(bytes32,address)":{"params":{"relayer":"The address of the relayer attempting to claim","transactionId":"The transaction id associated with the encoded bridge transaction to check"}},"claim(bytes)":{"params":{"request":"The encoded bridge transaction to claim on origin chain"}},"claim(bytes,address)":{"params":{"request":"The encoded bridge transaction to claim on origin chain","to":"The recipient address of the funds"}},"dispute(bytes32)":{"params":{"transactionId":"The transaction id associated with the encoded bridge transaction to dispute"}},"getBridgeTransaction(bytes)":{"details":"This method is added to achieve backwards compatibility with decoding requests into V1 structs: - `callValue` is partially reported as a zero/non-zero flag - `callParams` is ignored In order to process all kinds of requests use getBridgeTransactionV2 instead.","params":{"request":"The bridge request to decode"}},"getBridgeTransactionV2(bytes)":{"params":{"request":"The bridge request to decode"}},"getRoleAdmin(bytes32)":{"details":"Returns the admin role that controls `role`. See {grantRole} and {revokeRole}. To change a role's admin, use {_setRoleAdmin}."},"getRoleMember(bytes32,uint256)":{"details":"Returns one of the accounts that have `role`. `index` must be a value between 0 and {getRoleMemberCount}, non-inclusive. Role bearers are not sorted in any particular way, and their ordering may change at any point. WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure you perform all queries on the same block. See the following https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post] for more information."},"getRoleMemberCount(bytes32)":{"details":"Returns the number of accounts that have `role`. Can be used together with {getRoleMember} to enumerate all bearers of a role."},"grantRole(bytes32,address)":{"details":"Grants `role` to `account`. If `account` had not been already granted `role`, emits a {RoleGranted} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleGranted} event."},"hasRole(bytes32,address)":{"details":"Returns `true` if `account` has been granted `role`."},"prove(bytes,bytes32)":{"params":{"destTxHash":"The destination tx hash proving bridge transaction was relayed","request":"The encoded bridge transaction to prove on origin chain"}},"prove(bytes32,bytes32,address)":{"params":{"destTxHash":"The destination tx hash proving bridge transaction was relayed","relayer":"The address of the relaying entity which should have control of the origin funds when claimed","transactionId":"The transaction id associated with the encoded bridge transaction to prove"}},"refund(bytes)":{"params":{"request":"The encoded bridge transaction to refund"}},"relay(bytes)":{"params":{"request":"The encoded bridge transaction to relay on destination chain"}},"relay(bytes,address)":{"params":{"relayer":"The address of the relaying entity which should have control of the origin funds when claimed","request":"The encoded bridge transaction to relay on destination chain"}},"renounceRole(bytes32,address)":{"details":"Revokes `role` from the calling account. Roles are often managed via {grantRole} and {revokeRole}: this function's purpose is to provide a mechanism for accounts to lose their privileges if they are compromised (such as when a trusted device is misplaced). If the calling account had been revoked `role`, emits a {RoleRevoked} event. Requirements: - the caller must be `callerConfirmation`. May emit a {RoleRevoked} event."},"revokeRole(bytes32,address)":{"details":"Revokes `role` from `account`. If `account` had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleRevoked} event."},"supportsInterface(bytes4)":{"details":"See {IERC165-supportsInterface}."}},"stateVariables":{"nonce":{"details":"Replaced by senderNonces"}},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_owner\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"AccessControlBadConfirmation\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"neededRole\",\"type\":\"bytes32\"}],\"name\":\"AccessControlUnauthorizedAccount\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"}],\"name\":\"AddressEmptyCode\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"AddressInsufficientBalance\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"AmountIncorrect\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"CallParamsLengthAboveMax\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ChainIncorrect\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DeadlineExceeded\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DeadlineNotExceeded\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DeadlineTooShort\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DisputePeriodNotPassed\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DisputePeriodPassed\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ExclusivityParamsIncorrect\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ExclusivityPeriodNotPassed\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"FailedInnerCall\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"MsgValueIncorrect\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"NativeTokenCallValueNotSupported\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"RecipientIncorrectReturnValue\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"RecipientNoReturnValue\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"}],\"name\":\"SafeERC20FailedOperation\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"SenderIncorrect\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"StatusIncorrect\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"TokenNotContract\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"TransactionRelayed\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ZeroAddress\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"BridgeDepositClaimed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"BridgeDepositRefunded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"name\":\"BridgeProofDisputed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"transactionHash\",\"type\":\"bytes32\"}],\"name\":\"BridgeProofProvided\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"quoteId\",\"type\":\"bytes\"}],\"name\":\"BridgeQuoteDetails\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"originChainId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"chainGasAmount\",\"type\":\"uint256\"}],\"name\":\"BridgeRelayed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"destChainId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"sendChainGas\",\"type\":\"bool\"}],\"name\":\"BridgeRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"oldChainGasAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newChainGasAmount\",\"type\":\"uint256\"}],\"name\":\"ChainGasAmountUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"oldFeeRate\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newFeeRate\",\"type\":\"uint256\"}],\"name\":\"FeeRateUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"FeesSwept\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"previousAdminRole\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"newAdminRole\",\"type\":\"bytes32\"}],\"name\":\"RoleAdminChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleGranted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleRevoked\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"DEFAULT_ADMIN_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"DISPUTE_PERIOD\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"FEE_BPS\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"FEE_RATE_MAX\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"GOVERNOR_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"GUARD_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"MAX_CALL_PARAMS_LENGTH\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"MIN_DEADLINE_PERIOD\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"REFUNDER_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"REFUND_DELAY\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"RELAYER_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"dstChainId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"sendChainGas\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"}],\"internalType\":\"struct IFastBridge.BridgeParams\",\"name\":\"params\",\"type\":\"tuple\"}],\"name\":\"bridge\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"dstChainId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"sendChainGas\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"}],\"internalType\":\"struct IFastBridge.BridgeParams\",\"name\":\"params\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"quoteRelayer\",\"type\":\"address\"},{\"internalType\":\"int256\",\"name\":\"quoteExclusivitySeconds\",\"type\":\"int256\"},{\"internalType\":\"bytes\",\"name\":\"quoteId\",\"type\":\"bytes\"},{\"internalType\":\"uint256\",\"name\":\"callValue\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"callParams\",\"type\":\"bytes\"}],\"internalType\":\"struct IFastBridgeV2.BridgeParamsV2\",\"name\":\"paramsV2\",\"type\":\"tuple\"}],\"name\":\"bridge\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"}],\"name\":\"bridgeProofs\",\"outputs\":[{\"internalType\":\"uint96\",\"name\":\"timestamp\",\"type\":\"uint96\"},{\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"bridgeRelayDetails\",\"outputs\":[{\"internalType\":\"uint48\",\"name\":\"blockNumber\",\"type\":\"uint48\"},{\"internalType\":\"uint48\",\"name\":\"blockTimestamp\",\"type\":\"uint48\"},{\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"}],\"name\":\"bridgeRelays\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"}],\"name\":\"bridgeStatuses\",\"outputs\":[{\"internalType\":\"enum IFastBridgeV2.BridgeStatus\",\"name\":\"status\",\"type\":\"uint8\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"bridgeTxDetails\",\"outputs\":[{\"internalType\":\"enum IFastBridgeV2.BridgeStatus\",\"name\":\"status\",\"type\":\"uint8\"},{\"internalType\":\"uint40\",\"name\":\"proofBlockTimestamp\",\"type\":\"uint40\"},{\"internalType\":\"uint48\",\"name\":\"proofBlockNumber\",\"type\":\"uint48\"},{\"internalType\":\"address\",\"name\":\"proofRelayer\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"name\":\"canClaim\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"chainGasAmount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"claim\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"claim\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"deployBlock\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"}],\"name\":\"dispute\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"getBridgeTransaction\",\"outputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"originChainId\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"destChainId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"originSender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destRecipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"originFeeAmount\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"sendChainGas\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"}],\"internalType\":\"struct IFastBridge.BridgeTransaction\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"getBridgeTransactionV2\",\"outputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"originChainId\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"destChainId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"originSender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destRecipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"originFeeAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"callValue\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"exclusivityRelayer\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"exclusivityEndTime\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"callParams\",\"type\":\"bytes\"}],\"internalType\":\"struct IFastBridgeV2.BridgeTransactionV2\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"}],\"name\":\"getRoleAdmin\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"index\",\"type\":\"uint256\"}],\"name\":\"getRoleMember\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"}],\"name\":\"getRoleMemberCount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"grantRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"hasRole\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"nonce\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"protocolFeeRate\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"protocolFees\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"destTxHash\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"name\":\"prove\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"},{\"internalType\":\"bytes32\",\"name\":\"destTxHash\",\"type\":\"bytes32\"}],\"name\":\"prove\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"refund\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"relay\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"},{\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"name\":\"relay\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"callerConfirmation\",\"type\":\"address\"}],\"name\":\"renounceRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"revokeRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"senderNonces\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"newChainGasAmount\",\"type\":\"uint256\"}],\"name\":\"setChainGasAmount\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"newFeeRate\",\"type\":\"uint256\"}],\"name\":\"setProtocolFeeRate\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes4\",\"name\":\"interfaceId\",\"type\":\"bytes4\"}],\"name\":\"supportsInterface\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"}],\"name\":\"sweepProtocolFees\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"errors\":{\"AccessControlBadConfirmation()\":[{\"details\":\"The caller of a function is not the expected one. NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\"}],\"AccessControlUnauthorizedAccount(address,bytes32)\":[{\"details\":\"The `account` is missing a role.\"}],\"AddressEmptyCode(address)\":[{\"details\":\"There's no code at `target` (it is not a contract).\"}],\"AddressInsufficientBalance(address)\":[{\"details\":\"The ETH balance of the account is not enough to perform the operation.\"}],\"FailedInnerCall()\":[{\"details\":\"A call to an address target failed. The target may have reverted.\"}],\"SafeERC20FailedOperation(address)\":[{\"details\":\"An operation with an ERC20 token failed.\"}]},\"events\":{\"RoleAdminChanged(bytes32,bytes32,bytes32)\":{\"details\":\"Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole` `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite {RoleAdminChanged} not being emitted signaling this.\"},\"RoleGranted(bytes32,address,address)\":{\"details\":\"Emitted when `account` is granted `role`. `sender` is the account that originated the contract call, an admin role bearer except when using {AccessControl-_setupRole}.\"},\"RoleRevoked(bytes32,address,address)\":{\"details\":\"Emitted when `account` is revoked `role`. `sender` is the account that originated the contract call: - if using `revokeRole`, it is the admin role bearer - if using `renounceRole`, it is the role bearer (i.e. `account`)\"}},\"kind\":\"dev\",\"methods\":{\"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256))\":{\"params\":{\"params\":\"The parameters required to bridge\"}},\"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256),(address,int256,bytes,uint256,bytes))\":{\"params\":{\"params\":\"The parameters required to bridge\",\"paramsV2\":\"The parameters for exclusivity fill rights (optional, can be left empty)\"}},\"bridgeProofs(bytes32)\":{\"params\":{\"transactionId\":\"The ID of the bridge transaction\"},\"returns\":{\"relayer\":\"The relayer address of the bridge proof\",\"timestamp\":\"The timestamp of the bridge proof\"}},\"bridgeRelays(bytes32)\":{\"params\":{\"transactionId\":\"The ID of the transaction to check\"},\"returns\":{\"_0\":\"True if the transaction has been relayed, false otherwise\"}},\"bridgeStatuses(bytes32)\":{\"params\":{\"transactionId\":\"The ID of the bridge transaction\"},\"returns\":{\"status\":\"BridgeStatus Status of the bridge transaction\"}},\"canClaim(bytes32,address)\":{\"params\":{\"relayer\":\"The address of the relayer attempting to claim\",\"transactionId\":\"The transaction id associated with the encoded bridge transaction to check\"}},\"claim(bytes)\":{\"params\":{\"request\":\"The encoded bridge transaction to claim on origin chain\"}},\"claim(bytes,address)\":{\"params\":{\"request\":\"The encoded bridge transaction to claim on origin chain\",\"to\":\"The recipient address of the funds\"}},\"dispute(bytes32)\":{\"params\":{\"transactionId\":\"The transaction id associated with the encoded bridge transaction to dispute\"}},\"getBridgeTransaction(bytes)\":{\"details\":\"This method is added to achieve backwards compatibility with decoding requests into V1 structs: - `callValue` is partially reported as a zero/non-zero flag - `callParams` is ignored In order to process all kinds of requests use getBridgeTransactionV2 instead.\",\"params\":{\"request\":\"The bridge request to decode\"}},\"getBridgeTransactionV2(bytes)\":{\"params\":{\"request\":\"The bridge request to decode\"}},\"getRoleAdmin(bytes32)\":{\"details\":\"Returns the admin role that controls `role`. See {grantRole} and {revokeRole}. To change a role's admin, use {_setRoleAdmin}.\"},\"getRoleMember(bytes32,uint256)\":{\"details\":\"Returns one of the accounts that have `role`. `index` must be a value between 0 and {getRoleMemberCount}, non-inclusive. Role bearers are not sorted in any particular way, and their ordering may change at any point. WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure you perform all queries on the same block. See the following https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post] for more information.\"},\"getRoleMemberCount(bytes32)\":{\"details\":\"Returns the number of accounts that have `role`. Can be used together with {getRoleMember} to enumerate all bearers of a role.\"},\"grantRole(bytes32,address)\":{\"details\":\"Grants `role` to `account`. If `account` had not been already granted `role`, emits a {RoleGranted} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleGranted} event.\"},\"hasRole(bytes32,address)\":{\"details\":\"Returns `true` if `account` has been granted `role`.\"},\"prove(bytes,bytes32)\":{\"params\":{\"destTxHash\":\"The destination tx hash proving bridge transaction was relayed\",\"request\":\"The encoded bridge transaction to prove on origin chain\"}},\"prove(bytes32,bytes32,address)\":{\"params\":{\"destTxHash\":\"The destination tx hash proving bridge transaction was relayed\",\"relayer\":\"The address of the relaying entity which should have control of the origin funds when claimed\",\"transactionId\":\"The transaction id associated with the encoded bridge transaction to prove\"}},\"refund(bytes)\":{\"params\":{\"request\":\"The encoded bridge transaction to refund\"}},\"relay(bytes)\":{\"params\":{\"request\":\"The encoded bridge transaction to relay on destination chain\"}},\"relay(bytes,address)\":{\"params\":{\"relayer\":\"The address of the relaying entity which should have control of the origin funds when claimed\",\"request\":\"The encoded bridge transaction to relay on destination chain\"}},\"renounceRole(bytes32,address)\":{\"details\":\"Revokes `role` from the calling account. Roles are often managed via {grantRole} and {revokeRole}: this function's purpose is to provide a mechanism for accounts to lose their privileges if they are compromised (such as when a trusted device is misplaced). If the calling account had been revoked `role`, emits a {RoleRevoked} event. Requirements: - the caller must be `callerConfirmation`. May emit a {RoleRevoked} event.\"},\"revokeRole(bytes32,address)\":{\"details\":\"Revokes `role` from `account`. If `account` had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleRevoked} event.\"},\"supportsInterface(bytes4)\":{\"details\":\"See {IERC165-supportsInterface}.\"}},\"stateVariables\":{\"nonce\":{\"details\":\"Replaced by senderNonces\"}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"DISPUTE_PERIOD()\":{\"notice\":\"Dispute period for relayed transactions\"},\"MAX_CALL_PARAMS_LENGTH()\":{\"notice\":\"Maximum length of accepted callParams\"},\"MIN_DEADLINE_PERIOD()\":{\"notice\":\"Minimum deadline period to relay a requested bridge transaction\"},\"REFUND_DELAY()\":{\"notice\":\"Delay for a transaction after which it could be permisionlessly refunded\"},\"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256))\":{\"notice\":\"Initiates bridge on origin chain to be relayed by off-chain relayer\"},\"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256),(address,int256,bytes,uint256,bytes))\":{\"notice\":\"Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability to provide temporary exclusivity fill rights for the quote relayer.\"},\"bridgeProofs(bytes32)\":{\"notice\":\"Returns the timestamp and relayer of a bridge proof\"},\"bridgeRelayDetails(bytes32)\":{\"notice\":\"Relay details on destination chain\"},\"bridgeRelays(bytes32)\":{\"notice\":\"Checks if a transaction has been relayed\"},\"bridgeStatuses(bytes32)\":{\"notice\":\"Returns the status of a bridge transaction\"},\"bridgeTxDetails(bytes32)\":{\"notice\":\"Status of the bridge tx on origin chain\"},\"canClaim(bytes32,address)\":{\"notice\":\"Checks if the dispute period has passed so bridge deposit can be claimed\"},\"chainGasAmount()\":{\"notice\":\"Chain gas amount to forward as rebate if requested\"},\"claim(bytes)\":{\"notice\":\"Completes bridge transaction on origin chain by claiming originally deposited capital.Can only send funds to the relayer address on the proof.\"},\"claim(bytes,address)\":{\"notice\":\"Completes bridge transaction on origin chain by claiming originally deposited capital\"},\"deployBlock()\":{\"notice\":\"the block the contract was deployed at\"},\"dispute(bytes32)\":{\"notice\":\"Disputes an outstanding proof in case relayer provided dest chain tx is invalid\"},\"getBridgeTransaction(bytes)\":{\"notice\":\"Decodes bridge request into a bridge transaction\"},\"getBridgeTransactionV2(bytes)\":{\"notice\":\"Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\"},\"nonce()\":{\"notice\":\"This is deprecated and should not be used.\"},\"protocolFeeRate()\":{\"notice\":\"Protocol fee rate taken on origin amount deposited in origin chain\"},\"protocolFees(address)\":{\"notice\":\"Protocol fee amounts accumulated\"},\"prove(bytes,bytes32)\":{\"notice\":\"Provides proof on origin side that relayer provided funds on destination side of bridge transaction\"},\"prove(bytes32,bytes32,address)\":{\"notice\":\"Provides proof on origin side that relayer provided funds on destination side of bridge transaction\"},\"refund(bytes)\":{\"notice\":\"Refunds an outstanding bridge transaction in case optimistic bridging failed\"},\"relay(bytes)\":{\"notice\":\"Relays destination side of bridge transaction by off-chain relayer\"},\"relay(bytes,address)\":{\"notice\":\"Relays destination side of bridge transaction by off-chain relayer\"},\"senderNonces(address)\":{\"notice\":\"Unique bridge nonces tracked per originSender\"}},\"notice\":\"FastBridgeV2 is a contract for bridging tokens across chains.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeV2.sol\":\"FastBridgeV2\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeV2.sol\":{\"keccak256\":\"0x7cd0f885e80e2bdaa638bc32ae7af7d2e248f99ce4b354c217d0f0f7d7302e0a\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://7ccf28df0bd7b4606986585acd8622ed9b4e81379690061bb66088f0a2270af1\",\"dweb:/ipfs/QmTf7HNdHZkK6vmx8ZgewycQEb72oLD9nPwBpsM5reMstQ\"]}},\"version\":1}"},"hashes":{"DEFAULT_ADMIN_ROLE()":"a217fddf","DISPUTE_PERIOD()":"a5bbe22b","FEE_BPS()":"bf333f2c","FEE_RATE_MAX()":"0f5f6ed7","GOVERNOR_ROLE()":"ccc57490","GUARD_ROLE()":"03ed0ee5","MAX_CALL_PARAMS_LENGTH()":"df36bb13","MIN_DEADLINE_PERIOD()":"820688d5","REFUNDER_ROLE()":"5960ccf2","REFUND_DELAY()":"190da595","RELAYER_ROLE()":"926d7d7f","bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256))":"45851694","bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256),(address,int256,bytes,uint256,bytes))":"bfc7c607","bridgeProofs(bytes32)":"91ad5039","bridgeRelayDetails(bytes32)":"c79371b1","bridgeRelays(bytes32)":"8379a24f","bridgeStatuses(bytes32)":"051287bc","bridgeTxDetails(bytes32)":"63787e52","canClaim(bytes32,address)":"aa9641ab","chainGasAmount()":"e00a83e0","claim(bytes)":"c63ff8dd","claim(bytes,address)":"41fcb612","deployBlock()":"a3ec191a","dispute(bytes32)":"add98c70","getBridgeTransaction(bytes)":"ac11fb1a","getBridgeTransactionV2(bytes)":"5aa6ccba","getRoleAdmin(bytes32)":"248a9ca3","getRoleMember(bytes32,uint256)":"9010d07c","getRoleMemberCount(bytes32)":"ca15c873","grantRole(bytes32,address)":"2f2ff15d","hasRole(bytes32,address)":"91d14854","nonce()":"affed0e0","protocolFeeRate()":"58f85880","protocolFees(address)":"dcf844a7","prove(bytes,bytes32)":"886d36ff","prove(bytes32,bytes32,address)":"18e4357d","refund(bytes)":"5eb7d946","relay(bytes)":"8f0d6f17","relay(bytes,address)":"9c9545f0","renounceRole(bytes32,address)":"36568abe","revokeRole(bytes32,address)":"d547741f","senderNonces(address)":"295710ff","setChainGasAmount(uint256)":"b250fe6b","setProtocolFeeRate(uint256)":"b13aa2d6","supportsInterface(bytes4)":"01ffc9a7","sweepProtocolFees(address,address)":"06f333f2"}},"solidity/FastBridgeV2.sol:IAccessControl":{"code":"0x","runtime-code":"0x","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.24 ^0.8.0 ^0.8.20;\n\n// contracts/interfaces/IAdmin.sol\n\ninterface IAdmin {\n // ============ Events ============\n\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n event ChainGasAmountUpdated(uint256 oldChainGasAmount, uint256 newChainGasAmount);\n\n // ============ Methods ============\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n\n function setChainGasAmount(uint256 newChainGasAmount) external;\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IFastBridgeRecipient.sol\n\ninterface IFastBridgeRecipient {\n function fastBridgeTransferReceived(\n address token,\n uint256 amount,\n bytes memory callParams\n )\n external\n payable\n returns (bytes4);\n}\n\n// contracts/interfaces/IFastBridgeV2Errors.sol\n\ninterface IFastBridgeV2Errors {\n error AmountIncorrect();\n error CallParamsLengthAboveMax();\n error ChainIncorrect();\n error ExclusivityParamsIncorrect();\n error MsgValueIncorrect();\n error NativeTokenCallValueNotSupported();\n error SenderIncorrect();\n error StatusIncorrect();\n error ZeroAddress();\n\n error RecipientIncorrectReturnValue();\n error RecipientNoReturnValue();\n\n error DeadlineExceeded();\n error DeadlineNotExceeded();\n error DeadlineTooShort();\n error DisputePeriodNotPassed();\n error DisputePeriodPassed();\n error ExclusivityPeriodNotPassed();\n\n error TransactionRelayed();\n}\n\n// contracts/libs/Errors.sol\n\nerror DeadlineExceeded();\nerror DeadlineNotExceeded();\nerror DeadlineTooShort();\nerror InsufficientOutputAmount();\n\nerror MsgValueIncorrect();\nerror PoolNotFound();\nerror TokenAddressMismatch();\nerror TokenNotContract();\nerror TokenNotETH();\nerror TokensIdentical();\n\nerror ChainIncorrect();\nerror AmountIncorrect();\nerror ZeroAddress();\n\nerror DisputePeriodNotPassed();\nerror DisputePeriodPassed();\nerror SenderIncorrect();\nerror StatusIncorrect();\nerror TransactionIdIncorrect();\nerror TransactionRelayed();\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// contracts/interfaces/IFastBridgeV2.sol\n\ninterface IFastBridgeV2 is IFastBridge {\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n struct BridgeTxDetails {\n BridgeStatus status;\n uint40 proofBlockTimestamp;\n uint48 proofBlockNumber;\n address proofRelayer;\n }\n\n struct BridgeRelay {\n uint48 blockNumber;\n uint48 blockTimestamp;\n address relayer;\n }\n\n /// @notice New params introduced in the FastBridgeV2.\n /// We are passing fields from the older BridgeParams struct outside of this struct\n /// for backwards compatibility.\n /// Note: quoteRelayer and quoteExclusivitySeconds are either both zero (indicating no exclusivity)\n /// or both non-zero (indicating exclusivity for the given period).\n /// Note: callValue \u003e 0 can NOT be used with destToken = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE (ETH_ADDRESS)\n /// @param quoteRelayer Relayer that provided the quote for the transaction\n /// @param quoteExclusivitySeconds Period of time the quote relayer is guaranteed exclusivity after user's deposit\n /// @param quoteId Unique quote identifier used for tracking the quote\n /// @param callValue ETH value to send to the recipient (if any)\n /// @param callParams Parameters for the arbitrary call to the destination recipient (if any)\n struct BridgeParamsV2 {\n address quoteRelayer;\n int256 quoteExclusivitySeconds;\n bytes quoteId;\n uint256 callValue;\n bytes callParams;\n }\n\n /// @notice Updated bridge transaction struct to include parameters introduced in FastBridgeV2.\n /// Note: only `exclusivityRelayer` can fill such a transaction until `exclusivityEndTime`.\n /// TODO: consider changing the encoding scheme to prevent spending extra gas on decoding.\n struct BridgeTransactionV2 {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n uint256 callValue; // ETH value to send to the recipient (if any) - replaces V1's sendChainGas flag\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n address exclusivityRelayer;\n uint256 exclusivityEndTime;\n bytes callParams;\n }\n\n event BridgeQuoteDetails(bytes32 indexed transactionId, bytes quoteId);\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability\n /// to provide temporary exclusivity fill rights for the quote relayer.\n /// @param params The parameters required to bridge\n /// @param paramsV2 The parameters for exclusivity fill rights (optional, can be left empty)\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function relay(bytes memory request, address relayer) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param transactionId The transaction id associated with the encoded bridge transaction to prove\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital.\n /// @notice Can only send funds to the relayer address on the proof.\n /// @param request The encoded bridge transaction to claim on origin chain\n function claim(bytes memory request) external;\n /// @notice Checks if a transaction has been relayed\n /// @param transactionId The ID of the transaction to check\n /// @return True if the transaction has been relayed, false otherwise\n function bridgeRelays(bytes32 transactionId) external view returns (bool);\n\n /// @notice Returns the status of a bridge transaction\n /// @param transactionId The ID of the bridge transaction\n /// @return BridgeStatus Status of the bridge transaction\n function bridgeStatuses(bytes32 transactionId) external view returns (BridgeStatus);\n\n /// @notice Returns the timestamp and relayer of a bridge proof\n /// @param transactionId The ID of the bridge transaction\n /// @return timestamp The timestamp of the bridge proof\n /// @return relayer The relayer address of the bridge proof\n function bridgeProofs(bytes32 transactionId) external view returns (uint96 timestamp, address relayer);\n\n /// @notice Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\n /// @param request The bridge request to decode\n function getBridgeTransactionV2(bytes memory request) external view returns (BridgeTransactionV2 memory);\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// contracts/libs/UniversalToken.sol\n\nlibrary UniversalTokenLib {\n using SafeERC20 for IERC20;\n\n address internal constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Transfers tokens to the given account. Reverts if transfer is not successful.\n /// @dev This might trigger fallback, if ETH is transferred to the contract.\n /// Make sure this can not lead to reentrancy attacks.\n function universalTransfer(address token, address to, uint256 value) internal {\n // Don't do anything, if need to send tokens to this address\n if (to == address(this)) return;\n // Don't do anything, if trying to send zero value\n if (value == 0) return;\n if (token == ETH_ADDRESS) {\n /// @dev Note: this can potentially lead to executing code in `to`.\n // solhint-disable-next-line avoid-low-level-calls\n (bool success,) = to.call{value: value}(\"\");\n require(success, \"ETH transfer failed\");\n } else {\n IERC20(token).safeTransfer(to, value);\n }\n }\n\n /// @notice Issues an infinite allowance to the spender, if the current allowance is insufficient\n /// to spend the given amount.\n function universalApproveInfinity(address token, address spender, uint256 amountToSpend) internal {\n // ETH Chad doesn't require your approval\n if (token == ETH_ADDRESS) return;\n // No-op if allowance is already sufficient\n uint256 allowance = IERC20(token).allowance(address(this), spender);\n if (allowance \u003e= amountToSpend) return;\n // Otherwise, reset approval to 0 and set to max allowance\n if (allowance \u003e 0) IERC20(token).safeDecreaseAllowance(spender, allowance);\n IERC20(token).safeIncreaseAllowance(spender, type(uint256).max);\n }\n\n /// @notice Returns the balance of the given token (or native ETH) for the given account.\n function universalBalanceOf(address token, address account) internal view returns (uint256) {\n if (token == ETH_ADDRESS) {\n return account.balance;\n } else {\n return IERC20(token).balanceOf(account);\n }\n }\n\n /// @dev Checks that token is a contract and not ETH_ADDRESS.\n function assertIsContract(address token) internal view {\n // Check that ETH_ADDRESS was not used (in case this is a predeploy on any of the chains)\n if (token == UniversalTokenLib.ETH_ADDRESS) revert TokenNotContract();\n // Check that token is not an EOA\n if (token.code.length == 0) revert TokenNotContract();\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/Admin.sol\n\ncontract Admin is IAdmin, AccessControlEnumerable {\n using UniversalTokenLib for address;\n\n bytes32 public constant RELAYER_ROLE = keccak256(\"RELAYER_ROLE\");\n bytes32 public constant REFUNDER_ROLE = keccak256(\"REFUNDER_ROLE\");\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n uint256 public constant FEE_BPS = 1e6;\n uint256 public constant FEE_RATE_MAX = 0.01e6; // max 1% on origin amount\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Chain gas amount to forward as rebate if requested\n uint256 public chainGasAmount;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n }\n\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n require(newFeeRate \u003c= FEE_RATE_MAX, \"newFeeRate \u003e max\");\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n token.universalTransfer(recipient, feeAmount);\n emit FeesSwept(token, recipient, feeAmount);\n }\n\n function setChainGasAmount(uint256 newChainGasAmount) external onlyRole(GOVERNOR_ROLE) {\n uint256 oldChainGasAmount = chainGasAmount;\n chainGasAmount = newChainGasAmount;\n emit ChainGasAmountUpdated(oldChainGasAmount, newChainGasAmount);\n }\n}\n\n// contracts/FastBridgeV2.sol\n\n/// @notice FastBridgeV2 is a contract for bridging tokens across chains.\ncontract FastBridgeV2 is Admin, IFastBridgeV2, IFastBridgeV2Errors {\n using SafeERC20 for IERC20;\n using UniversalTokenLib for address;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Delay for a transaction after which it could be permisionlessly refunded\n uint256 public constant REFUND_DELAY = 7 days;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n /// @notice Maximum length of accepted callParams\n uint256 public constant MAX_CALL_PARAMS_LENGTH = 2 ** 16 - 1;\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeTxDetails) public bridgeTxDetails;\n /// @notice Relay details on destination chain\n mapping(bytes32 =\u003e BridgeRelay) public bridgeRelayDetails;\n /// @notice Unique bridge nonces tracked per originSender\n mapping(address =\u003e uint256) public senderNonces;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Replaced by senderNonces\n uint256 public immutable nonce = 0;\n /// @notice the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n bridge({\n params: params,\n paramsV2: BridgeParamsV2({\n quoteRelayer: address(0),\n quoteExclusivitySeconds: 0,\n quoteId: bytes(\"\"),\n callValue: 0,\n callParams: bytes(\"\")\n })\n });\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes memory request) external payable {\n relay({request: request, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes memory request, bytes32 destTxHash) external {\n prove({transactionId: keccak256(request), destTxHash: destTxHash, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridgeV2\n function claim(bytes memory request) external {\n claim({request: request, to: address(0)});\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003e DISPUTE_PERIOD) {\n revert DisputePeriodPassed();\n }\n\n // @dev relayer gets slashed effectively if dest relay has gone thru\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n bridgeTxDetails[transactionId].proofRelayer = address(0);\n bridgeTxDetails[transactionId].proofBlockTimestamp = 0;\n bridgeTxDetails[transactionId].proofBlockNumber = 0;\n\n emit BridgeProofDisputed(transactionId, msg.sender);\n }\n\n /// @inheritdoc IFastBridge\n function refund(bytes memory request) external {\n bytes32 transactionId = keccak256(request);\n\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n\n if (bridgeTxDetails[transactionId].status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n\n if (hasRole(REFUNDER_ROLE, msg.sender)) {\n // Refunder can refund if deadline has passed\n if (block.timestamp \u003c= transaction.deadline) revert DeadlineNotExceeded();\n } else {\n // Permissionless refund is allowed after REFUND_DELAY\n if (block.timestamp \u003c= transaction.deadline + REFUND_DELAY) revert DeadlineNotExceeded();\n }\n\n // if all checks passed, set to REFUNDED status\n bridgeTxDetails[transactionId].status = BridgeStatus.REFUNDED;\n\n // transfer origin collateral back to original sender\n address to = transaction.originSender;\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount + transaction.originFeeAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (bridgeTxDetails[transactionId].proofRelayer != relayer) revert SenderIncorrect();\n return _timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n /// @dev This method is added to achieve backwards compatibility with decoding requests into V1 structs:\n /// - `callValue` is partially reported as a zero/non-zero flag\n /// - `callParams` is ignored\n /// In order to process all kinds of requests use getBridgeTransactionV2 instead.\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory) {\n // Try decoding into V2 struct first. This will revert if V1 struct is passed\n try this.getBridgeTransactionV2(request) returns (BridgeTransactionV2 memory txV2) {\n // Note: we entirely ignore the callParams field, as it was not present in V1\n return BridgeTransaction({\n originChainId: txV2.originChainId,\n destChainId: txV2.destChainId,\n originSender: txV2.originSender,\n destRecipient: txV2.destRecipient,\n originToken: txV2.originToken,\n destToken: txV2.destToken,\n originAmount: txV2.originAmount,\n destAmount: txV2.destAmount,\n originFeeAmount: txV2.originFeeAmount,\n sendChainGas: txV2.callValue != 0,\n deadline: txV2.deadline,\n nonce: txV2.nonce\n });\n } catch {\n // Fallback to V1 struct\n return abi.decode(request, (BridgeTransaction));\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) public payable {\n int256 exclusivityEndTime = int256(block.timestamp) + paramsV2.quoteExclusivitySeconds;\n _validateBridgeParams(params, paramsV2, exclusivityEndTime);\n\n // transfer tokens to bridge contract\n /// @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _pullToken(params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n\n // set status to requested\n bytes memory request = abi.encode(\n BridgeTransactionV2({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n callValue: paramsV2.callValue,\n deadline: params.deadline,\n nonce: senderNonces[params.sender]++, // increment nonce on every bridge\n exclusivityRelayer: paramsV2.quoteRelayer,\n // We checked exclusivityEndTime to be in range (0 .. params.deadline] above, so can safely cast\n exclusivityEndTime: uint256(exclusivityEndTime),\n callParams: paramsV2.callParams\n })\n );\n bytes32 transactionId = keccak256(request);\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n\n emit BridgeRequested({\n transactionId: transactionId,\n sender: params.sender,\n request: request,\n destChainId: params.dstChainId,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n sendChainGas: paramsV2.callValue != 0\n });\n emit BridgeQuoteDetails(transactionId, paramsV2.quoteId);\n }\n\n /// @inheritdoc IFastBridgeV2\n function relay(bytes memory request, address relayer) public payable {\n bytes32 transactionId = keccak256(request);\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n _validateRelayParams(transaction, transactionId, relayer);\n // mark bridge transaction as relayed\n bridgeRelayDetails[transactionId] =\n BridgeRelay({blockNumber: uint48(block.number), blockTimestamp: uint48(block.timestamp), relayer: relayer});\n\n // transfer tokens to recipient on destination chain and do an arbitrary call if requested\n address to = transaction.destRecipient;\n address token = transaction.destToken;\n uint256 amount = transaction.destAmount;\n\n // All state changes have been done at this point, can proceed to the external calls.\n // This follows the checks-effects-interactions pattern to mitigate potential reentrancy attacks.\n if (token == UniversalTokenLib.ETH_ADDRESS) {\n // For ETH non-zero callValue is not allowed\n if (transaction.callValue != 0) revert NativeTokenCallValueNotSupported();\n // Check that the correct msg.value was sent\n if (msg.value != amount) revert MsgValueIncorrect();\n } else {\n // For ERC20s, we check that the correct msg.value was sent\n if (msg.value != transaction.callValue) revert MsgValueIncorrect();\n // We need to transfer the tokens from the Relayer to the recipient first before performing an\n // optional post-transfer arbitrary call.\n IERC20(token).safeTransferFrom(msg.sender, to, amount);\n }\n\n if (transaction.callParams.length != 0) {\n // Arbitrary call requested, perform it while supplying full msg.value to the recipient\n // Note: if token has a fee on transfers, the recipient will have received less than `amount`.\n // This is a very niche edge case and should be handled by the recipient contract.\n _checkedCallRecipient({recipient: to, token: token, amount: amount, callParams: transaction.callParams});\n } else if (msg.value != 0) {\n // No arbitrary call requested, but msg.value was sent. This is either a relay with ETH,\n // or a non-zero callValue request with an ERC20. In both cases, transfer the ETH to the recipient.\n Address.sendValue(payable(to), msg.value);\n }\n\n emit BridgeRelayed({\n transactionId: transactionId,\n relayer: relayer,\n to: to,\n originChainId: transaction.originChainId,\n originToken: transaction.originToken,\n destToken: transaction.destToken,\n originAmount: transaction.originAmount,\n destAmount: transaction.destAmount,\n chainGasAmount: transaction.callValue\n });\n }\n\n /// @inheritdoc IFastBridgeV2\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) public onlyRole(RELAYER_ROLE) {\n // update bridge tx status given proof provided\n if (bridgeTxDetails[transactionId].status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n bridgeTxDetails[transactionId].status = BridgeStatus.RELAYER_PROVED;\n bridgeTxDetails[transactionId].proofBlockTimestamp = uint40(block.timestamp);\n bridgeTxDetails[transactionId].proofBlockNumber = uint48(block.number);\n bridgeTxDetails[transactionId].proofRelayer = relayer;\n\n emit BridgeProofProvided(transactionId, relayer, destTxHash);\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes memory request, address to) public {\n bytes32 transactionId = keccak256(request);\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n\n // update bridge tx status if able to claim origin collateral\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n\n // if \"to\" is zero addr, permissionlessly send funds to proven relayer\n if (to == address(0)) {\n to = bridgeTxDetails[transactionId].proofRelayer;\n } else if (bridgeTxDetails[transactionId].proofRelayer != msg.sender) {\n revert SenderIncorrect();\n }\n\n if (_timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003c= DISPUTE_PERIOD) {\n revert DisputePeriodNotPassed();\n }\n\n bridgeTxDetails[transactionId].status = BridgeStatus.RELAYER_CLAIMED;\n\n // update protocol fees if origin fee amount exists\n if (transaction.originFeeAmount \u003e 0) protocolFees[transaction.originToken] += transaction.originFeeAmount;\n\n // transfer origin collateral less fee to specified address\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositClaimed(transactionId, bridgeTxDetails[transactionId].proofRelayer, to, token, amount);\n }\n\n function bridgeStatuses(bytes32 transactionId) public view returns (BridgeStatus status) {\n return bridgeTxDetails[transactionId].status;\n }\n\n function bridgeProofs(bytes32 transactionId) public view returns (uint96 timestamp, address relayer) {\n timestamp = bridgeTxDetails[transactionId].proofBlockTimestamp;\n relayer = bridgeTxDetails[transactionId].proofRelayer;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeRelays(bytes32 transactionId) public view returns (bool) {\n // has this transactionId been relayed?\n return bridgeRelayDetails[transactionId].relayer != address(0);\n }\n\n /// @inheritdoc IFastBridgeV2\n function getBridgeTransactionV2(bytes memory request) public pure returns (BridgeTransactionV2 memory) {\n return abi.decode(request, (BridgeTransactionV2));\n }\n\n /// @notice Pulls a requested token from the user to this contract.\n function _pullToken(address token, uint256 amount) internal returns (uint256 amountPulled) {\n if (token == UniversalTokenLib.ETH_ADDRESS) {\n // For ETH we just need to check that the supplied msg.value is correct\n if (amount != msg.value) revert MsgValueIncorrect();\n amountPulled = msg.value;\n } else {\n token.assertIsContract();\n // Record token balance before transfer\n amountPulled = IERC20(token).balanceOf(address(this));\n // Token needs to be pulled only if msg.value is zero\n // This way user can specify WETH as the origin asset\n IERC20(token).safeTransferFrom(msg.sender, address(this), amount);\n // Use the difference between the recorded balance and the current balance as the amountPulled\n amountPulled = IERC20(token).balanceOf(address(this)) - amountPulled;\n }\n }\n\n /// @notice Calls the Recipient's hook function with the specified callParams and performs\n /// all the necessary checks for the returned value.\n function _checkedCallRecipient(\n address recipient,\n address token,\n uint256 amount,\n bytes memory callParams\n )\n internal\n {\n bytes memory hookData =\n abi.encodeCall(IFastBridgeRecipient.fastBridgeTransferReceived, (token, amount, callParams));\n // This will bubble any revert messages from the hook function\n bytes memory returnData = Address.functionCallWithValue({target: recipient, data: hookData, value: msg.value});\n // Explicit revert if no return data at all\n if (returnData.length == 0) revert RecipientNoReturnValue();\n // Check that exactly a single return value was returned\n if (returnData.length != 32) revert RecipientIncorrectReturnValue();\n // Return value should be abi-encoded hook function selector\n if (bytes32(returnData) != bytes32(IFastBridgeRecipient.fastBridgeTransferReceived.selector)) {\n revert RecipientIncorrectReturnValue();\n }\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint40(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint40).max but\n /// proof.timestamp \u003c type(uint40).max via unchecked statement\n /// @param proofBlockTimestamp The bridge proof block timestamp\n /// @return delta Time delta since proof submitted\n function _timeSince(uint40 proofBlockTimestamp) internal view returns (uint256 delta) {\n unchecked {\n delta = uint40(block.timestamp) - proofBlockTimestamp;\n }\n }\n\n /// @notice Performs all the necessary checks for a bridge to happen.\n /// @dev There's no good way to refactor this function to reduce cyclomatic complexity due to\n /// the number of checks that need to be performed, so we skip the code-complexity rule here.\n // solhint-disable-next-line code-complexity\n function _validateBridgeParams(\n BridgeParams memory params,\n BridgeParamsV2 memory paramsV2,\n int256 exclusivityEndTime\n )\n internal\n view\n {\n // Check V1 (legacy) params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.sender == address(0) || params.to == address(0)) revert ZeroAddress();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n // Check V2 params\n if (paramsV2.callParams.length \u003e MAX_CALL_PARAMS_LENGTH) revert CallParamsLengthAboveMax();\n if (paramsV2.callValue != 0 \u0026\u0026 params.destToken == UniversalTokenLib.ETH_ADDRESS) {\n revert NativeTokenCallValueNotSupported();\n }\n // exclusivityEndTime must be in range (0 .. params.deadline]\n if (exclusivityEndTime \u003c= 0 || exclusivityEndTime \u003e int256(params.deadline)) {\n revert ExclusivityParamsIncorrect();\n }\n }\n\n /// @notice Performs all the necessary checks for a relay to happen.\n function _validateRelayParams(\n BridgeTransactionV2 memory transaction,\n bytes32 transactionId,\n address relayer\n )\n internal\n view\n {\n if (relayer == address(0)) revert ZeroAddress();\n // Check if the transaction has already been relayed\n if (bridgeRelays(transactionId)) revert TransactionRelayed();\n if (transaction.destChainId != uint32(block.chainid)) revert ChainIncorrect();\n // Check the deadline for relay to happen\n if (block.timestamp \u003e transaction.deadline) revert DeadlineExceeded();\n // Check the exclusivity period, if it is still ongoing\n // forgefmt: disable-next-item\n if (\n transaction.exclusivityRelayer != address(0) \u0026\u0026\n transaction.exclusivityRelayer != relayer \u0026\u0026\n block.timestamp \u003c= transaction.exclusivityEndTime\n ) {\n revert ExclusivityPeriodNotPassed();\n }\n }\n}\n","language":"Solidity","languageVersion":"0.8.24","compilerVersion":"0.8.24","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"","srcMapRuntime":"","abiDefinition":[{"inputs":[],"name":"AccessControlBadConfirmation","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"bytes32","name":"neededRole","type":"bytes32"}],"name":"AccessControlUnauthorizedAccount","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"previousAdminRole","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"newAdminRole","type":"bytes32"}],"name":"RoleAdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleRevoked","type":"event"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleAdmin","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"grantRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"hasRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"callerConfirmation","type":"address"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"revokeRole","outputs":[],"stateMutability":"nonpayable","type":"function"}],"userDoc":{"kind":"user","methods":{},"version":1},"developerDoc":{"details":"External interface of AccessControl declared to support ERC165 detection.","errors":{"AccessControlBadConfirmation()":[{"details":"The caller of a function is not the expected one. NOTE: Don't confuse with {AccessControlUnauthorizedAccount}."}],"AccessControlUnauthorizedAccount(address,bytes32)":[{"details":"The `account` is missing a role."}]},"events":{"RoleAdminChanged(bytes32,bytes32,bytes32)":{"details":"Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole` `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite {RoleAdminChanged} not being emitted signaling this."},"RoleGranted(bytes32,address,address)":{"details":"Emitted when `account` is granted `role`. `sender` is the account that originated the contract call, an admin role bearer except when using {AccessControl-_setupRole}."},"RoleRevoked(bytes32,address,address)":{"details":"Emitted when `account` is revoked `role`. `sender` is the account that originated the contract call: - if using `revokeRole`, it is the admin role bearer - if using `renounceRole`, it is the role bearer (i.e. `account`)"}},"kind":"dev","methods":{"getRoleAdmin(bytes32)":{"details":"Returns the admin role that controls `role`. See {grantRole} and {revokeRole}. To change a role's admin, use {AccessControl-_setRoleAdmin}."},"grantRole(bytes32,address)":{"details":"Grants `role` to `account`. If `account` had not been already granted `role`, emits a {RoleGranted} event. Requirements: - the caller must have ``role``'s admin role."},"hasRole(bytes32,address)":{"details":"Returns `true` if `account` has been granted `role`."},"renounceRole(bytes32,address)":{"details":"Revokes `role` from the calling account. Roles are often managed via {grantRole} and {revokeRole}: this function's purpose is to provide a mechanism for accounts to lose their privileges if they are compromised (such as when a trusted device is misplaced). If the calling account had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must be `callerConfirmation`."},"revokeRole(bytes32,address)":{"details":"Revokes `role` from `account`. If `account` had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must have ``role``'s admin role."}},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[],\"name\":\"AccessControlBadConfirmation\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"neededRole\",\"type\":\"bytes32\"}],\"name\":\"AccessControlUnauthorizedAccount\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"previousAdminRole\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"newAdminRole\",\"type\":\"bytes32\"}],\"name\":\"RoleAdminChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleGranted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleRevoked\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"}],\"name\":\"getRoleAdmin\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"grantRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"hasRole\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"callerConfirmation\",\"type\":\"address\"}],\"name\":\"renounceRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"revokeRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"details\":\"External interface of AccessControl declared to support ERC165 detection.\",\"errors\":{\"AccessControlBadConfirmation()\":[{\"details\":\"The caller of a function is not the expected one. NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\"}],\"AccessControlUnauthorizedAccount(address,bytes32)\":[{\"details\":\"The `account` is missing a role.\"}]},\"events\":{\"RoleAdminChanged(bytes32,bytes32,bytes32)\":{\"details\":\"Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole` `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite {RoleAdminChanged} not being emitted signaling this.\"},\"RoleGranted(bytes32,address,address)\":{\"details\":\"Emitted when `account` is granted `role`. `sender` is the account that originated the contract call, an admin role bearer except when using {AccessControl-_setupRole}.\"},\"RoleRevoked(bytes32,address,address)\":{\"details\":\"Emitted when `account` is revoked `role`. `sender` is the account that originated the contract call: - if using `revokeRole`, it is the admin role bearer - if using `renounceRole`, it is the role bearer (i.e. `account`)\"}},\"kind\":\"dev\",\"methods\":{\"getRoleAdmin(bytes32)\":{\"details\":\"Returns the admin role that controls `role`. See {grantRole} and {revokeRole}. To change a role's admin, use {AccessControl-_setRoleAdmin}.\"},\"grantRole(bytes32,address)\":{\"details\":\"Grants `role` to `account`. If `account` had not been already granted `role`, emits a {RoleGranted} event. Requirements: - the caller must have ``role``'s admin role.\"},\"hasRole(bytes32,address)\":{\"details\":\"Returns `true` if `account` has been granted `role`.\"},\"renounceRole(bytes32,address)\":{\"details\":\"Revokes `role` from the calling account. Roles are often managed via {grantRole} and {revokeRole}: this function's purpose is to provide a mechanism for accounts to lose their privileges if they are compromised (such as when a trusted device is misplaced). If the calling account had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must be `callerConfirmation`.\"},\"revokeRole(bytes32,address)\":{\"details\":\"Revokes `role` from `account`. If `account` had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must have ``role``'s admin role.\"}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeV2.sol\":\"IAccessControl\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeV2.sol\":{\"keccak256\":\"0x7cd0f885e80e2bdaa638bc32ae7af7d2e248f99ce4b354c217d0f0f7d7302e0a\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://7ccf28df0bd7b4606986585acd8622ed9b4e81379690061bb66088f0a2270af1\",\"dweb:/ipfs/QmTf7HNdHZkK6vmx8ZgewycQEb72oLD9nPwBpsM5reMstQ\"]}},\"version\":1}"},"hashes":{"getRoleAdmin(bytes32)":"248a9ca3","grantRole(bytes32,address)":"2f2ff15d","hasRole(bytes32,address)":"91d14854","renounceRole(bytes32,address)":"36568abe","revokeRole(bytes32,address)":"d547741f"}},"solidity/FastBridgeV2.sol:IAccessControlEnumerable":{"code":"0x","runtime-code":"0x","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.24 ^0.8.0 ^0.8.20;\n\n// contracts/interfaces/IAdmin.sol\n\ninterface IAdmin {\n // ============ Events ============\n\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n event ChainGasAmountUpdated(uint256 oldChainGasAmount, uint256 newChainGasAmount);\n\n // ============ Methods ============\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n\n function setChainGasAmount(uint256 newChainGasAmount) external;\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IFastBridgeRecipient.sol\n\ninterface IFastBridgeRecipient {\n function fastBridgeTransferReceived(\n address token,\n uint256 amount,\n bytes memory callParams\n )\n external\n payable\n returns (bytes4);\n}\n\n// contracts/interfaces/IFastBridgeV2Errors.sol\n\ninterface IFastBridgeV2Errors {\n error AmountIncorrect();\n error CallParamsLengthAboveMax();\n error ChainIncorrect();\n error ExclusivityParamsIncorrect();\n error MsgValueIncorrect();\n error NativeTokenCallValueNotSupported();\n error SenderIncorrect();\n error StatusIncorrect();\n error ZeroAddress();\n\n error RecipientIncorrectReturnValue();\n error RecipientNoReturnValue();\n\n error DeadlineExceeded();\n error DeadlineNotExceeded();\n error DeadlineTooShort();\n error DisputePeriodNotPassed();\n error DisputePeriodPassed();\n error ExclusivityPeriodNotPassed();\n\n error TransactionRelayed();\n}\n\n// contracts/libs/Errors.sol\n\nerror DeadlineExceeded();\nerror DeadlineNotExceeded();\nerror DeadlineTooShort();\nerror InsufficientOutputAmount();\n\nerror MsgValueIncorrect();\nerror PoolNotFound();\nerror TokenAddressMismatch();\nerror TokenNotContract();\nerror TokenNotETH();\nerror TokensIdentical();\n\nerror ChainIncorrect();\nerror AmountIncorrect();\nerror ZeroAddress();\n\nerror DisputePeriodNotPassed();\nerror DisputePeriodPassed();\nerror SenderIncorrect();\nerror StatusIncorrect();\nerror TransactionIdIncorrect();\nerror TransactionRelayed();\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// contracts/interfaces/IFastBridgeV2.sol\n\ninterface IFastBridgeV2 is IFastBridge {\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n struct BridgeTxDetails {\n BridgeStatus status;\n uint40 proofBlockTimestamp;\n uint48 proofBlockNumber;\n address proofRelayer;\n }\n\n struct BridgeRelay {\n uint48 blockNumber;\n uint48 blockTimestamp;\n address relayer;\n }\n\n /// @notice New params introduced in the FastBridgeV2.\n /// We are passing fields from the older BridgeParams struct outside of this struct\n /// for backwards compatibility.\n /// Note: quoteRelayer and quoteExclusivitySeconds are either both zero (indicating no exclusivity)\n /// or both non-zero (indicating exclusivity for the given period).\n /// Note: callValue \u003e 0 can NOT be used with destToken = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE (ETH_ADDRESS)\n /// @param quoteRelayer Relayer that provided the quote for the transaction\n /// @param quoteExclusivitySeconds Period of time the quote relayer is guaranteed exclusivity after user's deposit\n /// @param quoteId Unique quote identifier used for tracking the quote\n /// @param callValue ETH value to send to the recipient (if any)\n /// @param callParams Parameters for the arbitrary call to the destination recipient (if any)\n struct BridgeParamsV2 {\n address quoteRelayer;\n int256 quoteExclusivitySeconds;\n bytes quoteId;\n uint256 callValue;\n bytes callParams;\n }\n\n /// @notice Updated bridge transaction struct to include parameters introduced in FastBridgeV2.\n /// Note: only `exclusivityRelayer` can fill such a transaction until `exclusivityEndTime`.\n /// TODO: consider changing the encoding scheme to prevent spending extra gas on decoding.\n struct BridgeTransactionV2 {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n uint256 callValue; // ETH value to send to the recipient (if any) - replaces V1's sendChainGas flag\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n address exclusivityRelayer;\n uint256 exclusivityEndTime;\n bytes callParams;\n }\n\n event BridgeQuoteDetails(bytes32 indexed transactionId, bytes quoteId);\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability\n /// to provide temporary exclusivity fill rights for the quote relayer.\n /// @param params The parameters required to bridge\n /// @param paramsV2 The parameters for exclusivity fill rights (optional, can be left empty)\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function relay(bytes memory request, address relayer) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param transactionId The transaction id associated with the encoded bridge transaction to prove\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital.\n /// @notice Can only send funds to the relayer address on the proof.\n /// @param request The encoded bridge transaction to claim on origin chain\n function claim(bytes memory request) external;\n /// @notice Checks if a transaction has been relayed\n /// @param transactionId The ID of the transaction to check\n /// @return True if the transaction has been relayed, false otherwise\n function bridgeRelays(bytes32 transactionId) external view returns (bool);\n\n /// @notice Returns the status of a bridge transaction\n /// @param transactionId The ID of the bridge transaction\n /// @return BridgeStatus Status of the bridge transaction\n function bridgeStatuses(bytes32 transactionId) external view returns (BridgeStatus);\n\n /// @notice Returns the timestamp and relayer of a bridge proof\n /// @param transactionId The ID of the bridge transaction\n /// @return timestamp The timestamp of the bridge proof\n /// @return relayer The relayer address of the bridge proof\n function bridgeProofs(bytes32 transactionId) external view returns (uint96 timestamp, address relayer);\n\n /// @notice Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\n /// @param request The bridge request to decode\n function getBridgeTransactionV2(bytes memory request) external view returns (BridgeTransactionV2 memory);\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// contracts/libs/UniversalToken.sol\n\nlibrary UniversalTokenLib {\n using SafeERC20 for IERC20;\n\n address internal constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Transfers tokens to the given account. Reverts if transfer is not successful.\n /// @dev This might trigger fallback, if ETH is transferred to the contract.\n /// Make sure this can not lead to reentrancy attacks.\n function universalTransfer(address token, address to, uint256 value) internal {\n // Don't do anything, if need to send tokens to this address\n if (to == address(this)) return;\n // Don't do anything, if trying to send zero value\n if (value == 0) return;\n if (token == ETH_ADDRESS) {\n /// @dev Note: this can potentially lead to executing code in `to`.\n // solhint-disable-next-line avoid-low-level-calls\n (bool success,) = to.call{value: value}(\"\");\n require(success, \"ETH transfer failed\");\n } else {\n IERC20(token).safeTransfer(to, value);\n }\n }\n\n /// @notice Issues an infinite allowance to the spender, if the current allowance is insufficient\n /// to spend the given amount.\n function universalApproveInfinity(address token, address spender, uint256 amountToSpend) internal {\n // ETH Chad doesn't require your approval\n if (token == ETH_ADDRESS) return;\n // No-op if allowance is already sufficient\n uint256 allowance = IERC20(token).allowance(address(this), spender);\n if (allowance \u003e= amountToSpend) return;\n // Otherwise, reset approval to 0 and set to max allowance\n if (allowance \u003e 0) IERC20(token).safeDecreaseAllowance(spender, allowance);\n IERC20(token).safeIncreaseAllowance(spender, type(uint256).max);\n }\n\n /// @notice Returns the balance of the given token (or native ETH) for the given account.\n function universalBalanceOf(address token, address account) internal view returns (uint256) {\n if (token == ETH_ADDRESS) {\n return account.balance;\n } else {\n return IERC20(token).balanceOf(account);\n }\n }\n\n /// @dev Checks that token is a contract and not ETH_ADDRESS.\n function assertIsContract(address token) internal view {\n // Check that ETH_ADDRESS was not used (in case this is a predeploy on any of the chains)\n if (token == UniversalTokenLib.ETH_ADDRESS) revert TokenNotContract();\n // Check that token is not an EOA\n if (token.code.length == 0) revert TokenNotContract();\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/Admin.sol\n\ncontract Admin is IAdmin, AccessControlEnumerable {\n using UniversalTokenLib for address;\n\n bytes32 public constant RELAYER_ROLE = keccak256(\"RELAYER_ROLE\");\n bytes32 public constant REFUNDER_ROLE = keccak256(\"REFUNDER_ROLE\");\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n uint256 public constant FEE_BPS = 1e6;\n uint256 public constant FEE_RATE_MAX = 0.01e6; // max 1% on origin amount\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Chain gas amount to forward as rebate if requested\n uint256 public chainGasAmount;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n }\n\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n require(newFeeRate \u003c= FEE_RATE_MAX, \"newFeeRate \u003e max\");\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n token.universalTransfer(recipient, feeAmount);\n emit FeesSwept(token, recipient, feeAmount);\n }\n\n function setChainGasAmount(uint256 newChainGasAmount) external onlyRole(GOVERNOR_ROLE) {\n uint256 oldChainGasAmount = chainGasAmount;\n chainGasAmount = newChainGasAmount;\n emit ChainGasAmountUpdated(oldChainGasAmount, newChainGasAmount);\n }\n}\n\n// contracts/FastBridgeV2.sol\n\n/// @notice FastBridgeV2 is a contract for bridging tokens across chains.\ncontract FastBridgeV2 is Admin, IFastBridgeV2, IFastBridgeV2Errors {\n using SafeERC20 for IERC20;\n using UniversalTokenLib for address;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Delay for a transaction after which it could be permisionlessly refunded\n uint256 public constant REFUND_DELAY = 7 days;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n /// @notice Maximum length of accepted callParams\n uint256 public constant MAX_CALL_PARAMS_LENGTH = 2 ** 16 - 1;\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeTxDetails) public bridgeTxDetails;\n /// @notice Relay details on destination chain\n mapping(bytes32 =\u003e BridgeRelay) public bridgeRelayDetails;\n /// @notice Unique bridge nonces tracked per originSender\n mapping(address =\u003e uint256) public senderNonces;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Replaced by senderNonces\n uint256 public immutable nonce = 0;\n /// @notice the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n bridge({\n params: params,\n paramsV2: BridgeParamsV2({\n quoteRelayer: address(0),\n quoteExclusivitySeconds: 0,\n quoteId: bytes(\"\"),\n callValue: 0,\n callParams: bytes(\"\")\n })\n });\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes memory request) external payable {\n relay({request: request, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes memory request, bytes32 destTxHash) external {\n prove({transactionId: keccak256(request), destTxHash: destTxHash, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridgeV2\n function claim(bytes memory request) external {\n claim({request: request, to: address(0)});\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003e DISPUTE_PERIOD) {\n revert DisputePeriodPassed();\n }\n\n // @dev relayer gets slashed effectively if dest relay has gone thru\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n bridgeTxDetails[transactionId].proofRelayer = address(0);\n bridgeTxDetails[transactionId].proofBlockTimestamp = 0;\n bridgeTxDetails[transactionId].proofBlockNumber = 0;\n\n emit BridgeProofDisputed(transactionId, msg.sender);\n }\n\n /// @inheritdoc IFastBridge\n function refund(bytes memory request) external {\n bytes32 transactionId = keccak256(request);\n\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n\n if (bridgeTxDetails[transactionId].status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n\n if (hasRole(REFUNDER_ROLE, msg.sender)) {\n // Refunder can refund if deadline has passed\n if (block.timestamp \u003c= transaction.deadline) revert DeadlineNotExceeded();\n } else {\n // Permissionless refund is allowed after REFUND_DELAY\n if (block.timestamp \u003c= transaction.deadline + REFUND_DELAY) revert DeadlineNotExceeded();\n }\n\n // if all checks passed, set to REFUNDED status\n bridgeTxDetails[transactionId].status = BridgeStatus.REFUNDED;\n\n // transfer origin collateral back to original sender\n address to = transaction.originSender;\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount + transaction.originFeeAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (bridgeTxDetails[transactionId].proofRelayer != relayer) revert SenderIncorrect();\n return _timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n /// @dev This method is added to achieve backwards compatibility with decoding requests into V1 structs:\n /// - `callValue` is partially reported as a zero/non-zero flag\n /// - `callParams` is ignored\n /// In order to process all kinds of requests use getBridgeTransactionV2 instead.\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory) {\n // Try decoding into V2 struct first. This will revert if V1 struct is passed\n try this.getBridgeTransactionV2(request) returns (BridgeTransactionV2 memory txV2) {\n // Note: we entirely ignore the callParams field, as it was not present in V1\n return BridgeTransaction({\n originChainId: txV2.originChainId,\n destChainId: txV2.destChainId,\n originSender: txV2.originSender,\n destRecipient: txV2.destRecipient,\n originToken: txV2.originToken,\n destToken: txV2.destToken,\n originAmount: txV2.originAmount,\n destAmount: txV2.destAmount,\n originFeeAmount: txV2.originFeeAmount,\n sendChainGas: txV2.callValue != 0,\n deadline: txV2.deadline,\n nonce: txV2.nonce\n });\n } catch {\n // Fallback to V1 struct\n return abi.decode(request, (BridgeTransaction));\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) public payable {\n int256 exclusivityEndTime = int256(block.timestamp) + paramsV2.quoteExclusivitySeconds;\n _validateBridgeParams(params, paramsV2, exclusivityEndTime);\n\n // transfer tokens to bridge contract\n /// @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _pullToken(params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n\n // set status to requested\n bytes memory request = abi.encode(\n BridgeTransactionV2({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n callValue: paramsV2.callValue,\n deadline: params.deadline,\n nonce: senderNonces[params.sender]++, // increment nonce on every bridge\n exclusivityRelayer: paramsV2.quoteRelayer,\n // We checked exclusivityEndTime to be in range (0 .. params.deadline] above, so can safely cast\n exclusivityEndTime: uint256(exclusivityEndTime),\n callParams: paramsV2.callParams\n })\n );\n bytes32 transactionId = keccak256(request);\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n\n emit BridgeRequested({\n transactionId: transactionId,\n sender: params.sender,\n request: request,\n destChainId: params.dstChainId,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n sendChainGas: paramsV2.callValue != 0\n });\n emit BridgeQuoteDetails(transactionId, paramsV2.quoteId);\n }\n\n /// @inheritdoc IFastBridgeV2\n function relay(bytes memory request, address relayer) public payable {\n bytes32 transactionId = keccak256(request);\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n _validateRelayParams(transaction, transactionId, relayer);\n // mark bridge transaction as relayed\n bridgeRelayDetails[transactionId] =\n BridgeRelay({blockNumber: uint48(block.number), blockTimestamp: uint48(block.timestamp), relayer: relayer});\n\n // transfer tokens to recipient on destination chain and do an arbitrary call if requested\n address to = transaction.destRecipient;\n address token = transaction.destToken;\n uint256 amount = transaction.destAmount;\n\n // All state changes have been done at this point, can proceed to the external calls.\n // This follows the checks-effects-interactions pattern to mitigate potential reentrancy attacks.\n if (token == UniversalTokenLib.ETH_ADDRESS) {\n // For ETH non-zero callValue is not allowed\n if (transaction.callValue != 0) revert NativeTokenCallValueNotSupported();\n // Check that the correct msg.value was sent\n if (msg.value != amount) revert MsgValueIncorrect();\n } else {\n // For ERC20s, we check that the correct msg.value was sent\n if (msg.value != transaction.callValue) revert MsgValueIncorrect();\n // We need to transfer the tokens from the Relayer to the recipient first before performing an\n // optional post-transfer arbitrary call.\n IERC20(token).safeTransferFrom(msg.sender, to, amount);\n }\n\n if (transaction.callParams.length != 0) {\n // Arbitrary call requested, perform it while supplying full msg.value to the recipient\n // Note: if token has a fee on transfers, the recipient will have received less than `amount`.\n // This is a very niche edge case and should be handled by the recipient contract.\n _checkedCallRecipient({recipient: to, token: token, amount: amount, callParams: transaction.callParams});\n } else if (msg.value != 0) {\n // No arbitrary call requested, but msg.value was sent. This is either a relay with ETH,\n // or a non-zero callValue request with an ERC20. In both cases, transfer the ETH to the recipient.\n Address.sendValue(payable(to), msg.value);\n }\n\n emit BridgeRelayed({\n transactionId: transactionId,\n relayer: relayer,\n to: to,\n originChainId: transaction.originChainId,\n originToken: transaction.originToken,\n destToken: transaction.destToken,\n originAmount: transaction.originAmount,\n destAmount: transaction.destAmount,\n chainGasAmount: transaction.callValue\n });\n }\n\n /// @inheritdoc IFastBridgeV2\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) public onlyRole(RELAYER_ROLE) {\n // update bridge tx status given proof provided\n if (bridgeTxDetails[transactionId].status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n bridgeTxDetails[transactionId].status = BridgeStatus.RELAYER_PROVED;\n bridgeTxDetails[transactionId].proofBlockTimestamp = uint40(block.timestamp);\n bridgeTxDetails[transactionId].proofBlockNumber = uint48(block.number);\n bridgeTxDetails[transactionId].proofRelayer = relayer;\n\n emit BridgeProofProvided(transactionId, relayer, destTxHash);\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes memory request, address to) public {\n bytes32 transactionId = keccak256(request);\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n\n // update bridge tx status if able to claim origin collateral\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n\n // if \"to\" is zero addr, permissionlessly send funds to proven relayer\n if (to == address(0)) {\n to = bridgeTxDetails[transactionId].proofRelayer;\n } else if (bridgeTxDetails[transactionId].proofRelayer != msg.sender) {\n revert SenderIncorrect();\n }\n\n if (_timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003c= DISPUTE_PERIOD) {\n revert DisputePeriodNotPassed();\n }\n\n bridgeTxDetails[transactionId].status = BridgeStatus.RELAYER_CLAIMED;\n\n // update protocol fees if origin fee amount exists\n if (transaction.originFeeAmount \u003e 0) protocolFees[transaction.originToken] += transaction.originFeeAmount;\n\n // transfer origin collateral less fee to specified address\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositClaimed(transactionId, bridgeTxDetails[transactionId].proofRelayer, to, token, amount);\n }\n\n function bridgeStatuses(bytes32 transactionId) public view returns (BridgeStatus status) {\n return bridgeTxDetails[transactionId].status;\n }\n\n function bridgeProofs(bytes32 transactionId) public view returns (uint96 timestamp, address relayer) {\n timestamp = bridgeTxDetails[transactionId].proofBlockTimestamp;\n relayer = bridgeTxDetails[transactionId].proofRelayer;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeRelays(bytes32 transactionId) public view returns (bool) {\n // has this transactionId been relayed?\n return bridgeRelayDetails[transactionId].relayer != address(0);\n }\n\n /// @inheritdoc IFastBridgeV2\n function getBridgeTransactionV2(bytes memory request) public pure returns (BridgeTransactionV2 memory) {\n return abi.decode(request, (BridgeTransactionV2));\n }\n\n /// @notice Pulls a requested token from the user to this contract.\n function _pullToken(address token, uint256 amount) internal returns (uint256 amountPulled) {\n if (token == UniversalTokenLib.ETH_ADDRESS) {\n // For ETH we just need to check that the supplied msg.value is correct\n if (amount != msg.value) revert MsgValueIncorrect();\n amountPulled = msg.value;\n } else {\n token.assertIsContract();\n // Record token balance before transfer\n amountPulled = IERC20(token).balanceOf(address(this));\n // Token needs to be pulled only if msg.value is zero\n // This way user can specify WETH as the origin asset\n IERC20(token).safeTransferFrom(msg.sender, address(this), amount);\n // Use the difference between the recorded balance and the current balance as the amountPulled\n amountPulled = IERC20(token).balanceOf(address(this)) - amountPulled;\n }\n }\n\n /// @notice Calls the Recipient's hook function with the specified callParams and performs\n /// all the necessary checks for the returned value.\n function _checkedCallRecipient(\n address recipient,\n address token,\n uint256 amount,\n bytes memory callParams\n )\n internal\n {\n bytes memory hookData =\n abi.encodeCall(IFastBridgeRecipient.fastBridgeTransferReceived, (token, amount, callParams));\n // This will bubble any revert messages from the hook function\n bytes memory returnData = Address.functionCallWithValue({target: recipient, data: hookData, value: msg.value});\n // Explicit revert if no return data at all\n if (returnData.length == 0) revert RecipientNoReturnValue();\n // Check that exactly a single return value was returned\n if (returnData.length != 32) revert RecipientIncorrectReturnValue();\n // Return value should be abi-encoded hook function selector\n if (bytes32(returnData) != bytes32(IFastBridgeRecipient.fastBridgeTransferReceived.selector)) {\n revert RecipientIncorrectReturnValue();\n }\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint40(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint40).max but\n /// proof.timestamp \u003c type(uint40).max via unchecked statement\n /// @param proofBlockTimestamp The bridge proof block timestamp\n /// @return delta Time delta since proof submitted\n function _timeSince(uint40 proofBlockTimestamp) internal view returns (uint256 delta) {\n unchecked {\n delta = uint40(block.timestamp) - proofBlockTimestamp;\n }\n }\n\n /// @notice Performs all the necessary checks for a bridge to happen.\n /// @dev There's no good way to refactor this function to reduce cyclomatic complexity due to\n /// the number of checks that need to be performed, so we skip the code-complexity rule here.\n // solhint-disable-next-line code-complexity\n function _validateBridgeParams(\n BridgeParams memory params,\n BridgeParamsV2 memory paramsV2,\n int256 exclusivityEndTime\n )\n internal\n view\n {\n // Check V1 (legacy) params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.sender == address(0) || params.to == address(0)) revert ZeroAddress();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n // Check V2 params\n if (paramsV2.callParams.length \u003e MAX_CALL_PARAMS_LENGTH) revert CallParamsLengthAboveMax();\n if (paramsV2.callValue != 0 \u0026\u0026 params.destToken == UniversalTokenLib.ETH_ADDRESS) {\n revert NativeTokenCallValueNotSupported();\n }\n // exclusivityEndTime must be in range (0 .. params.deadline]\n if (exclusivityEndTime \u003c= 0 || exclusivityEndTime \u003e int256(params.deadline)) {\n revert ExclusivityParamsIncorrect();\n }\n }\n\n /// @notice Performs all the necessary checks for a relay to happen.\n function _validateRelayParams(\n BridgeTransactionV2 memory transaction,\n bytes32 transactionId,\n address relayer\n )\n internal\n view\n {\n if (relayer == address(0)) revert ZeroAddress();\n // Check if the transaction has already been relayed\n if (bridgeRelays(transactionId)) revert TransactionRelayed();\n if (transaction.destChainId != uint32(block.chainid)) revert ChainIncorrect();\n // Check the deadline for relay to happen\n if (block.timestamp \u003e transaction.deadline) revert DeadlineExceeded();\n // Check the exclusivity period, if it is still ongoing\n // forgefmt: disable-next-item\n if (\n transaction.exclusivityRelayer != address(0) \u0026\u0026\n transaction.exclusivityRelayer != relayer \u0026\u0026\n block.timestamp \u003c= transaction.exclusivityEndTime\n ) {\n revert ExclusivityPeriodNotPassed();\n }\n }\n}\n","language":"Solidity","languageVersion":"0.8.24","compilerVersion":"0.8.24","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"","srcMapRuntime":"","abiDefinition":[{"inputs":[],"name":"AccessControlBadConfirmation","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"bytes32","name":"neededRole","type":"bytes32"}],"name":"AccessControlUnauthorizedAccount","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"previousAdminRole","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"newAdminRole","type":"bytes32"}],"name":"RoleAdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleRevoked","type":"event"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleAdmin","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"uint256","name":"index","type":"uint256"}],"name":"getRoleMember","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleMemberCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"grantRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"hasRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"callerConfirmation","type":"address"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"revokeRole","outputs":[],"stateMutability":"nonpayable","type":"function"}],"userDoc":{"kind":"user","methods":{},"version":1},"developerDoc":{"details":"External interface of AccessControlEnumerable declared to support ERC165 detection.","errors":{"AccessControlBadConfirmation()":[{"details":"The caller of a function is not the expected one. NOTE: Don't confuse with {AccessControlUnauthorizedAccount}."}],"AccessControlUnauthorizedAccount(address,bytes32)":[{"details":"The `account` is missing a role."}]},"events":{"RoleAdminChanged(bytes32,bytes32,bytes32)":{"details":"Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole` `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite {RoleAdminChanged} not being emitted signaling this."},"RoleGranted(bytes32,address,address)":{"details":"Emitted when `account` is granted `role`. `sender` is the account that originated the contract call, an admin role bearer except when using {AccessControl-_setupRole}."},"RoleRevoked(bytes32,address,address)":{"details":"Emitted when `account` is revoked `role`. `sender` is the account that originated the contract call: - if using `revokeRole`, it is the admin role bearer - if using `renounceRole`, it is the role bearer (i.e. `account`)"}},"kind":"dev","methods":{"getRoleAdmin(bytes32)":{"details":"Returns the admin role that controls `role`. See {grantRole} and {revokeRole}. To change a role's admin, use {AccessControl-_setRoleAdmin}."},"getRoleMember(bytes32,uint256)":{"details":"Returns one of the accounts that have `role`. `index` must be a value between 0 and {getRoleMemberCount}, non-inclusive. Role bearers are not sorted in any particular way, and their ordering may change at any point. WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure you perform all queries on the same block. See the following https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post] for more information."},"getRoleMemberCount(bytes32)":{"details":"Returns the number of accounts that have `role`. Can be used together with {getRoleMember} to enumerate all bearers of a role."},"grantRole(bytes32,address)":{"details":"Grants `role` to `account`. If `account` had not been already granted `role`, emits a {RoleGranted} event. Requirements: - the caller must have ``role``'s admin role."},"hasRole(bytes32,address)":{"details":"Returns `true` if `account` has been granted `role`."},"renounceRole(bytes32,address)":{"details":"Revokes `role` from the calling account. Roles are often managed via {grantRole} and {revokeRole}: this function's purpose is to provide a mechanism for accounts to lose their privileges if they are compromised (such as when a trusted device is misplaced). If the calling account had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must be `callerConfirmation`."},"revokeRole(bytes32,address)":{"details":"Revokes `role` from `account`. If `account` had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must have ``role``'s admin role."}},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[],\"name\":\"AccessControlBadConfirmation\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"neededRole\",\"type\":\"bytes32\"}],\"name\":\"AccessControlUnauthorizedAccount\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"previousAdminRole\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"newAdminRole\",\"type\":\"bytes32\"}],\"name\":\"RoleAdminChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleGranted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleRevoked\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"}],\"name\":\"getRoleAdmin\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"index\",\"type\":\"uint256\"}],\"name\":\"getRoleMember\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"}],\"name\":\"getRoleMemberCount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"grantRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"hasRole\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"callerConfirmation\",\"type\":\"address\"}],\"name\":\"renounceRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"revokeRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"details\":\"External interface of AccessControlEnumerable declared to support ERC165 detection.\",\"errors\":{\"AccessControlBadConfirmation()\":[{\"details\":\"The caller of a function is not the expected one. NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\"}],\"AccessControlUnauthorizedAccount(address,bytes32)\":[{\"details\":\"The `account` is missing a role.\"}]},\"events\":{\"RoleAdminChanged(bytes32,bytes32,bytes32)\":{\"details\":\"Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole` `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite {RoleAdminChanged} not being emitted signaling this.\"},\"RoleGranted(bytes32,address,address)\":{\"details\":\"Emitted when `account` is granted `role`. `sender` is the account that originated the contract call, an admin role bearer except when using {AccessControl-_setupRole}.\"},\"RoleRevoked(bytes32,address,address)\":{\"details\":\"Emitted when `account` is revoked `role`. `sender` is the account that originated the contract call: - if using `revokeRole`, it is the admin role bearer - if using `renounceRole`, it is the role bearer (i.e. `account`)\"}},\"kind\":\"dev\",\"methods\":{\"getRoleAdmin(bytes32)\":{\"details\":\"Returns the admin role that controls `role`. See {grantRole} and {revokeRole}. To change a role's admin, use {AccessControl-_setRoleAdmin}.\"},\"getRoleMember(bytes32,uint256)\":{\"details\":\"Returns one of the accounts that have `role`. `index` must be a value between 0 and {getRoleMemberCount}, non-inclusive. Role bearers are not sorted in any particular way, and their ordering may change at any point. WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure you perform all queries on the same block. See the following https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post] for more information.\"},\"getRoleMemberCount(bytes32)\":{\"details\":\"Returns the number of accounts that have `role`. Can be used together with {getRoleMember} to enumerate all bearers of a role.\"},\"grantRole(bytes32,address)\":{\"details\":\"Grants `role` to `account`. If `account` had not been already granted `role`, emits a {RoleGranted} event. Requirements: - the caller must have ``role``'s admin role.\"},\"hasRole(bytes32,address)\":{\"details\":\"Returns `true` if `account` has been granted `role`.\"},\"renounceRole(bytes32,address)\":{\"details\":\"Revokes `role` from the calling account. Roles are often managed via {grantRole} and {revokeRole}: this function's purpose is to provide a mechanism for accounts to lose their privileges if they are compromised (such as when a trusted device is misplaced). If the calling account had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must be `callerConfirmation`.\"},\"revokeRole(bytes32,address)\":{\"details\":\"Revokes `role` from `account`. If `account` had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must have ``role``'s admin role.\"}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeV2.sol\":\"IAccessControlEnumerable\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeV2.sol\":{\"keccak256\":\"0x7cd0f885e80e2bdaa638bc32ae7af7d2e248f99ce4b354c217d0f0f7d7302e0a\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://7ccf28df0bd7b4606986585acd8622ed9b4e81379690061bb66088f0a2270af1\",\"dweb:/ipfs/QmTf7HNdHZkK6vmx8ZgewycQEb72oLD9nPwBpsM5reMstQ\"]}},\"version\":1}"},"hashes":{"getRoleAdmin(bytes32)":"248a9ca3","getRoleMember(bytes32,uint256)":"9010d07c","getRoleMemberCount(bytes32)":"ca15c873","grantRole(bytes32,address)":"2f2ff15d","hasRole(bytes32,address)":"91d14854","renounceRole(bytes32,address)":"36568abe","revokeRole(bytes32,address)":"d547741f"}},"solidity/FastBridgeV2.sol:IAdmin":{"code":"0x","runtime-code":"0x","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.24 ^0.8.0 ^0.8.20;\n\n// contracts/interfaces/IAdmin.sol\n\ninterface IAdmin {\n // ============ Events ============\n\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n event ChainGasAmountUpdated(uint256 oldChainGasAmount, uint256 newChainGasAmount);\n\n // ============ Methods ============\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n\n function setChainGasAmount(uint256 newChainGasAmount) external;\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IFastBridgeRecipient.sol\n\ninterface IFastBridgeRecipient {\n function fastBridgeTransferReceived(\n address token,\n uint256 amount,\n bytes memory callParams\n )\n external\n payable\n returns (bytes4);\n}\n\n// contracts/interfaces/IFastBridgeV2Errors.sol\n\ninterface IFastBridgeV2Errors {\n error AmountIncorrect();\n error CallParamsLengthAboveMax();\n error ChainIncorrect();\n error ExclusivityParamsIncorrect();\n error MsgValueIncorrect();\n error NativeTokenCallValueNotSupported();\n error SenderIncorrect();\n error StatusIncorrect();\n error ZeroAddress();\n\n error RecipientIncorrectReturnValue();\n error RecipientNoReturnValue();\n\n error DeadlineExceeded();\n error DeadlineNotExceeded();\n error DeadlineTooShort();\n error DisputePeriodNotPassed();\n error DisputePeriodPassed();\n error ExclusivityPeriodNotPassed();\n\n error TransactionRelayed();\n}\n\n// contracts/libs/Errors.sol\n\nerror DeadlineExceeded();\nerror DeadlineNotExceeded();\nerror DeadlineTooShort();\nerror InsufficientOutputAmount();\n\nerror MsgValueIncorrect();\nerror PoolNotFound();\nerror TokenAddressMismatch();\nerror TokenNotContract();\nerror TokenNotETH();\nerror TokensIdentical();\n\nerror ChainIncorrect();\nerror AmountIncorrect();\nerror ZeroAddress();\n\nerror DisputePeriodNotPassed();\nerror DisputePeriodPassed();\nerror SenderIncorrect();\nerror StatusIncorrect();\nerror TransactionIdIncorrect();\nerror TransactionRelayed();\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// contracts/interfaces/IFastBridgeV2.sol\n\ninterface IFastBridgeV2 is IFastBridge {\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n struct BridgeTxDetails {\n BridgeStatus status;\n uint40 proofBlockTimestamp;\n uint48 proofBlockNumber;\n address proofRelayer;\n }\n\n struct BridgeRelay {\n uint48 blockNumber;\n uint48 blockTimestamp;\n address relayer;\n }\n\n /// @notice New params introduced in the FastBridgeV2.\n /// We are passing fields from the older BridgeParams struct outside of this struct\n /// for backwards compatibility.\n /// Note: quoteRelayer and quoteExclusivitySeconds are either both zero (indicating no exclusivity)\n /// or both non-zero (indicating exclusivity for the given period).\n /// Note: callValue \u003e 0 can NOT be used with destToken = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE (ETH_ADDRESS)\n /// @param quoteRelayer Relayer that provided the quote for the transaction\n /// @param quoteExclusivitySeconds Period of time the quote relayer is guaranteed exclusivity after user's deposit\n /// @param quoteId Unique quote identifier used for tracking the quote\n /// @param callValue ETH value to send to the recipient (if any)\n /// @param callParams Parameters for the arbitrary call to the destination recipient (if any)\n struct BridgeParamsV2 {\n address quoteRelayer;\n int256 quoteExclusivitySeconds;\n bytes quoteId;\n uint256 callValue;\n bytes callParams;\n }\n\n /// @notice Updated bridge transaction struct to include parameters introduced in FastBridgeV2.\n /// Note: only `exclusivityRelayer` can fill such a transaction until `exclusivityEndTime`.\n /// TODO: consider changing the encoding scheme to prevent spending extra gas on decoding.\n struct BridgeTransactionV2 {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n uint256 callValue; // ETH value to send to the recipient (if any) - replaces V1's sendChainGas flag\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n address exclusivityRelayer;\n uint256 exclusivityEndTime;\n bytes callParams;\n }\n\n event BridgeQuoteDetails(bytes32 indexed transactionId, bytes quoteId);\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability\n /// to provide temporary exclusivity fill rights for the quote relayer.\n /// @param params The parameters required to bridge\n /// @param paramsV2 The parameters for exclusivity fill rights (optional, can be left empty)\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function relay(bytes memory request, address relayer) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param transactionId The transaction id associated with the encoded bridge transaction to prove\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital.\n /// @notice Can only send funds to the relayer address on the proof.\n /// @param request The encoded bridge transaction to claim on origin chain\n function claim(bytes memory request) external;\n /// @notice Checks if a transaction has been relayed\n /// @param transactionId The ID of the transaction to check\n /// @return True if the transaction has been relayed, false otherwise\n function bridgeRelays(bytes32 transactionId) external view returns (bool);\n\n /// @notice Returns the status of a bridge transaction\n /// @param transactionId The ID of the bridge transaction\n /// @return BridgeStatus Status of the bridge transaction\n function bridgeStatuses(bytes32 transactionId) external view returns (BridgeStatus);\n\n /// @notice Returns the timestamp and relayer of a bridge proof\n /// @param transactionId The ID of the bridge transaction\n /// @return timestamp The timestamp of the bridge proof\n /// @return relayer The relayer address of the bridge proof\n function bridgeProofs(bytes32 transactionId) external view returns (uint96 timestamp, address relayer);\n\n /// @notice Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\n /// @param request The bridge request to decode\n function getBridgeTransactionV2(bytes memory request) external view returns (BridgeTransactionV2 memory);\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// contracts/libs/UniversalToken.sol\n\nlibrary UniversalTokenLib {\n using SafeERC20 for IERC20;\n\n address internal constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Transfers tokens to the given account. Reverts if transfer is not successful.\n /// @dev This might trigger fallback, if ETH is transferred to the contract.\n /// Make sure this can not lead to reentrancy attacks.\n function universalTransfer(address token, address to, uint256 value) internal {\n // Don't do anything, if need to send tokens to this address\n if (to == address(this)) return;\n // Don't do anything, if trying to send zero value\n if (value == 0) return;\n if (token == ETH_ADDRESS) {\n /// @dev Note: this can potentially lead to executing code in `to`.\n // solhint-disable-next-line avoid-low-level-calls\n (bool success,) = to.call{value: value}(\"\");\n require(success, \"ETH transfer failed\");\n } else {\n IERC20(token).safeTransfer(to, value);\n }\n }\n\n /// @notice Issues an infinite allowance to the spender, if the current allowance is insufficient\n /// to spend the given amount.\n function universalApproveInfinity(address token, address spender, uint256 amountToSpend) internal {\n // ETH Chad doesn't require your approval\n if (token == ETH_ADDRESS) return;\n // No-op if allowance is already sufficient\n uint256 allowance = IERC20(token).allowance(address(this), spender);\n if (allowance \u003e= amountToSpend) return;\n // Otherwise, reset approval to 0 and set to max allowance\n if (allowance \u003e 0) IERC20(token).safeDecreaseAllowance(spender, allowance);\n IERC20(token).safeIncreaseAllowance(spender, type(uint256).max);\n }\n\n /// @notice Returns the balance of the given token (or native ETH) for the given account.\n function universalBalanceOf(address token, address account) internal view returns (uint256) {\n if (token == ETH_ADDRESS) {\n return account.balance;\n } else {\n return IERC20(token).balanceOf(account);\n }\n }\n\n /// @dev Checks that token is a contract and not ETH_ADDRESS.\n function assertIsContract(address token) internal view {\n // Check that ETH_ADDRESS was not used (in case this is a predeploy on any of the chains)\n if (token == UniversalTokenLib.ETH_ADDRESS) revert TokenNotContract();\n // Check that token is not an EOA\n if (token.code.length == 0) revert TokenNotContract();\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/Admin.sol\n\ncontract Admin is IAdmin, AccessControlEnumerable {\n using UniversalTokenLib for address;\n\n bytes32 public constant RELAYER_ROLE = keccak256(\"RELAYER_ROLE\");\n bytes32 public constant REFUNDER_ROLE = keccak256(\"REFUNDER_ROLE\");\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n uint256 public constant FEE_BPS = 1e6;\n uint256 public constant FEE_RATE_MAX = 0.01e6; // max 1% on origin amount\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Chain gas amount to forward as rebate if requested\n uint256 public chainGasAmount;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n }\n\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n require(newFeeRate \u003c= FEE_RATE_MAX, \"newFeeRate \u003e max\");\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n token.universalTransfer(recipient, feeAmount);\n emit FeesSwept(token, recipient, feeAmount);\n }\n\n function setChainGasAmount(uint256 newChainGasAmount) external onlyRole(GOVERNOR_ROLE) {\n uint256 oldChainGasAmount = chainGasAmount;\n chainGasAmount = newChainGasAmount;\n emit ChainGasAmountUpdated(oldChainGasAmount, newChainGasAmount);\n }\n}\n\n// contracts/FastBridgeV2.sol\n\n/// @notice FastBridgeV2 is a contract for bridging tokens across chains.\ncontract FastBridgeV2 is Admin, IFastBridgeV2, IFastBridgeV2Errors {\n using SafeERC20 for IERC20;\n using UniversalTokenLib for address;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Delay for a transaction after which it could be permisionlessly refunded\n uint256 public constant REFUND_DELAY = 7 days;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n /// @notice Maximum length of accepted callParams\n uint256 public constant MAX_CALL_PARAMS_LENGTH = 2 ** 16 - 1;\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeTxDetails) public bridgeTxDetails;\n /// @notice Relay details on destination chain\n mapping(bytes32 =\u003e BridgeRelay) public bridgeRelayDetails;\n /// @notice Unique bridge nonces tracked per originSender\n mapping(address =\u003e uint256) public senderNonces;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Replaced by senderNonces\n uint256 public immutable nonce = 0;\n /// @notice the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n bridge({\n params: params,\n paramsV2: BridgeParamsV2({\n quoteRelayer: address(0),\n quoteExclusivitySeconds: 0,\n quoteId: bytes(\"\"),\n callValue: 0,\n callParams: bytes(\"\")\n })\n });\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes memory request) external payable {\n relay({request: request, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes memory request, bytes32 destTxHash) external {\n prove({transactionId: keccak256(request), destTxHash: destTxHash, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridgeV2\n function claim(bytes memory request) external {\n claim({request: request, to: address(0)});\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003e DISPUTE_PERIOD) {\n revert DisputePeriodPassed();\n }\n\n // @dev relayer gets slashed effectively if dest relay has gone thru\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n bridgeTxDetails[transactionId].proofRelayer = address(0);\n bridgeTxDetails[transactionId].proofBlockTimestamp = 0;\n bridgeTxDetails[transactionId].proofBlockNumber = 0;\n\n emit BridgeProofDisputed(transactionId, msg.sender);\n }\n\n /// @inheritdoc IFastBridge\n function refund(bytes memory request) external {\n bytes32 transactionId = keccak256(request);\n\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n\n if (bridgeTxDetails[transactionId].status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n\n if (hasRole(REFUNDER_ROLE, msg.sender)) {\n // Refunder can refund if deadline has passed\n if (block.timestamp \u003c= transaction.deadline) revert DeadlineNotExceeded();\n } else {\n // Permissionless refund is allowed after REFUND_DELAY\n if (block.timestamp \u003c= transaction.deadline + REFUND_DELAY) revert DeadlineNotExceeded();\n }\n\n // if all checks passed, set to REFUNDED status\n bridgeTxDetails[transactionId].status = BridgeStatus.REFUNDED;\n\n // transfer origin collateral back to original sender\n address to = transaction.originSender;\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount + transaction.originFeeAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (bridgeTxDetails[transactionId].proofRelayer != relayer) revert SenderIncorrect();\n return _timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n /// @dev This method is added to achieve backwards compatibility with decoding requests into V1 structs:\n /// - `callValue` is partially reported as a zero/non-zero flag\n /// - `callParams` is ignored\n /// In order to process all kinds of requests use getBridgeTransactionV2 instead.\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory) {\n // Try decoding into V2 struct first. This will revert if V1 struct is passed\n try this.getBridgeTransactionV2(request) returns (BridgeTransactionV2 memory txV2) {\n // Note: we entirely ignore the callParams field, as it was not present in V1\n return BridgeTransaction({\n originChainId: txV2.originChainId,\n destChainId: txV2.destChainId,\n originSender: txV2.originSender,\n destRecipient: txV2.destRecipient,\n originToken: txV2.originToken,\n destToken: txV2.destToken,\n originAmount: txV2.originAmount,\n destAmount: txV2.destAmount,\n originFeeAmount: txV2.originFeeAmount,\n sendChainGas: txV2.callValue != 0,\n deadline: txV2.deadline,\n nonce: txV2.nonce\n });\n } catch {\n // Fallback to V1 struct\n return abi.decode(request, (BridgeTransaction));\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) public payable {\n int256 exclusivityEndTime = int256(block.timestamp) + paramsV2.quoteExclusivitySeconds;\n _validateBridgeParams(params, paramsV2, exclusivityEndTime);\n\n // transfer tokens to bridge contract\n /// @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _pullToken(params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n\n // set status to requested\n bytes memory request = abi.encode(\n BridgeTransactionV2({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n callValue: paramsV2.callValue,\n deadline: params.deadline,\n nonce: senderNonces[params.sender]++, // increment nonce on every bridge\n exclusivityRelayer: paramsV2.quoteRelayer,\n // We checked exclusivityEndTime to be in range (0 .. params.deadline] above, so can safely cast\n exclusivityEndTime: uint256(exclusivityEndTime),\n callParams: paramsV2.callParams\n })\n );\n bytes32 transactionId = keccak256(request);\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n\n emit BridgeRequested({\n transactionId: transactionId,\n sender: params.sender,\n request: request,\n destChainId: params.dstChainId,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n sendChainGas: paramsV2.callValue != 0\n });\n emit BridgeQuoteDetails(transactionId, paramsV2.quoteId);\n }\n\n /// @inheritdoc IFastBridgeV2\n function relay(bytes memory request, address relayer) public payable {\n bytes32 transactionId = keccak256(request);\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n _validateRelayParams(transaction, transactionId, relayer);\n // mark bridge transaction as relayed\n bridgeRelayDetails[transactionId] =\n BridgeRelay({blockNumber: uint48(block.number), blockTimestamp: uint48(block.timestamp), relayer: relayer});\n\n // transfer tokens to recipient on destination chain and do an arbitrary call if requested\n address to = transaction.destRecipient;\n address token = transaction.destToken;\n uint256 amount = transaction.destAmount;\n\n // All state changes have been done at this point, can proceed to the external calls.\n // This follows the checks-effects-interactions pattern to mitigate potential reentrancy attacks.\n if (token == UniversalTokenLib.ETH_ADDRESS) {\n // For ETH non-zero callValue is not allowed\n if (transaction.callValue != 0) revert NativeTokenCallValueNotSupported();\n // Check that the correct msg.value was sent\n if (msg.value != amount) revert MsgValueIncorrect();\n } else {\n // For ERC20s, we check that the correct msg.value was sent\n if (msg.value != transaction.callValue) revert MsgValueIncorrect();\n // We need to transfer the tokens from the Relayer to the recipient first before performing an\n // optional post-transfer arbitrary call.\n IERC20(token).safeTransferFrom(msg.sender, to, amount);\n }\n\n if (transaction.callParams.length != 0) {\n // Arbitrary call requested, perform it while supplying full msg.value to the recipient\n // Note: if token has a fee on transfers, the recipient will have received less than `amount`.\n // This is a very niche edge case and should be handled by the recipient contract.\n _checkedCallRecipient({recipient: to, token: token, amount: amount, callParams: transaction.callParams});\n } else if (msg.value != 0) {\n // No arbitrary call requested, but msg.value was sent. This is either a relay with ETH,\n // or a non-zero callValue request with an ERC20. In both cases, transfer the ETH to the recipient.\n Address.sendValue(payable(to), msg.value);\n }\n\n emit BridgeRelayed({\n transactionId: transactionId,\n relayer: relayer,\n to: to,\n originChainId: transaction.originChainId,\n originToken: transaction.originToken,\n destToken: transaction.destToken,\n originAmount: transaction.originAmount,\n destAmount: transaction.destAmount,\n chainGasAmount: transaction.callValue\n });\n }\n\n /// @inheritdoc IFastBridgeV2\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) public onlyRole(RELAYER_ROLE) {\n // update bridge tx status given proof provided\n if (bridgeTxDetails[transactionId].status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n bridgeTxDetails[transactionId].status = BridgeStatus.RELAYER_PROVED;\n bridgeTxDetails[transactionId].proofBlockTimestamp = uint40(block.timestamp);\n bridgeTxDetails[transactionId].proofBlockNumber = uint48(block.number);\n bridgeTxDetails[transactionId].proofRelayer = relayer;\n\n emit BridgeProofProvided(transactionId, relayer, destTxHash);\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes memory request, address to) public {\n bytes32 transactionId = keccak256(request);\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n\n // update bridge tx status if able to claim origin collateral\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n\n // if \"to\" is zero addr, permissionlessly send funds to proven relayer\n if (to == address(0)) {\n to = bridgeTxDetails[transactionId].proofRelayer;\n } else if (bridgeTxDetails[transactionId].proofRelayer != msg.sender) {\n revert SenderIncorrect();\n }\n\n if (_timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003c= DISPUTE_PERIOD) {\n revert DisputePeriodNotPassed();\n }\n\n bridgeTxDetails[transactionId].status = BridgeStatus.RELAYER_CLAIMED;\n\n // update protocol fees if origin fee amount exists\n if (transaction.originFeeAmount \u003e 0) protocolFees[transaction.originToken] += transaction.originFeeAmount;\n\n // transfer origin collateral less fee to specified address\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositClaimed(transactionId, bridgeTxDetails[transactionId].proofRelayer, to, token, amount);\n }\n\n function bridgeStatuses(bytes32 transactionId) public view returns (BridgeStatus status) {\n return bridgeTxDetails[transactionId].status;\n }\n\n function bridgeProofs(bytes32 transactionId) public view returns (uint96 timestamp, address relayer) {\n timestamp = bridgeTxDetails[transactionId].proofBlockTimestamp;\n relayer = bridgeTxDetails[transactionId].proofRelayer;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeRelays(bytes32 transactionId) public view returns (bool) {\n // has this transactionId been relayed?\n return bridgeRelayDetails[transactionId].relayer != address(0);\n }\n\n /// @inheritdoc IFastBridgeV2\n function getBridgeTransactionV2(bytes memory request) public pure returns (BridgeTransactionV2 memory) {\n return abi.decode(request, (BridgeTransactionV2));\n }\n\n /// @notice Pulls a requested token from the user to this contract.\n function _pullToken(address token, uint256 amount) internal returns (uint256 amountPulled) {\n if (token == UniversalTokenLib.ETH_ADDRESS) {\n // For ETH we just need to check that the supplied msg.value is correct\n if (amount != msg.value) revert MsgValueIncorrect();\n amountPulled = msg.value;\n } else {\n token.assertIsContract();\n // Record token balance before transfer\n amountPulled = IERC20(token).balanceOf(address(this));\n // Token needs to be pulled only if msg.value is zero\n // This way user can specify WETH as the origin asset\n IERC20(token).safeTransferFrom(msg.sender, address(this), amount);\n // Use the difference between the recorded balance and the current balance as the amountPulled\n amountPulled = IERC20(token).balanceOf(address(this)) - amountPulled;\n }\n }\n\n /// @notice Calls the Recipient's hook function with the specified callParams and performs\n /// all the necessary checks for the returned value.\n function _checkedCallRecipient(\n address recipient,\n address token,\n uint256 amount,\n bytes memory callParams\n )\n internal\n {\n bytes memory hookData =\n abi.encodeCall(IFastBridgeRecipient.fastBridgeTransferReceived, (token, amount, callParams));\n // This will bubble any revert messages from the hook function\n bytes memory returnData = Address.functionCallWithValue({target: recipient, data: hookData, value: msg.value});\n // Explicit revert if no return data at all\n if (returnData.length == 0) revert RecipientNoReturnValue();\n // Check that exactly a single return value was returned\n if (returnData.length != 32) revert RecipientIncorrectReturnValue();\n // Return value should be abi-encoded hook function selector\n if (bytes32(returnData) != bytes32(IFastBridgeRecipient.fastBridgeTransferReceived.selector)) {\n revert RecipientIncorrectReturnValue();\n }\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint40(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint40).max but\n /// proof.timestamp \u003c type(uint40).max via unchecked statement\n /// @param proofBlockTimestamp The bridge proof block timestamp\n /// @return delta Time delta since proof submitted\n function _timeSince(uint40 proofBlockTimestamp) internal view returns (uint256 delta) {\n unchecked {\n delta = uint40(block.timestamp) - proofBlockTimestamp;\n }\n }\n\n /// @notice Performs all the necessary checks for a bridge to happen.\n /// @dev There's no good way to refactor this function to reduce cyclomatic complexity due to\n /// the number of checks that need to be performed, so we skip the code-complexity rule here.\n // solhint-disable-next-line code-complexity\n function _validateBridgeParams(\n BridgeParams memory params,\n BridgeParamsV2 memory paramsV2,\n int256 exclusivityEndTime\n )\n internal\n view\n {\n // Check V1 (legacy) params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.sender == address(0) || params.to == address(0)) revert ZeroAddress();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n // Check V2 params\n if (paramsV2.callParams.length \u003e MAX_CALL_PARAMS_LENGTH) revert CallParamsLengthAboveMax();\n if (paramsV2.callValue != 0 \u0026\u0026 params.destToken == UniversalTokenLib.ETH_ADDRESS) {\n revert NativeTokenCallValueNotSupported();\n }\n // exclusivityEndTime must be in range (0 .. params.deadline]\n if (exclusivityEndTime \u003c= 0 || exclusivityEndTime \u003e int256(params.deadline)) {\n revert ExclusivityParamsIncorrect();\n }\n }\n\n /// @notice Performs all the necessary checks for a relay to happen.\n function _validateRelayParams(\n BridgeTransactionV2 memory transaction,\n bytes32 transactionId,\n address relayer\n )\n internal\n view\n {\n if (relayer == address(0)) revert ZeroAddress();\n // Check if the transaction has already been relayed\n if (bridgeRelays(transactionId)) revert TransactionRelayed();\n if (transaction.destChainId != uint32(block.chainid)) revert ChainIncorrect();\n // Check the deadline for relay to happen\n if (block.timestamp \u003e transaction.deadline) revert DeadlineExceeded();\n // Check the exclusivity period, if it is still ongoing\n // forgefmt: disable-next-item\n if (\n transaction.exclusivityRelayer != address(0) \u0026\u0026\n transaction.exclusivityRelayer != relayer \u0026\u0026\n block.timestamp \u003c= transaction.exclusivityEndTime\n ) {\n revert ExclusivityPeriodNotPassed();\n }\n }\n}\n","language":"Solidity","languageVersion":"0.8.24","compilerVersion":"0.8.24","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"","srcMapRuntime":"","abiDefinition":[{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldChainGasAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newChainGasAmount","type":"uint256"}],"name":"ChainGasAmountUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldFeeRate","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newFeeRate","type":"uint256"}],"name":"FeeRateUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"address","name":"recipient","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"FeesSwept","type":"event"},{"inputs":[{"internalType":"uint256","name":"newChainGasAmount","type":"uint256"}],"name":"setChainGasAmount","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"newFeeRate","type":"uint256"}],"name":"setProtocolFeeRate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"address","name":"recipient","type":"address"}],"name":"sweepProtocolFees","outputs":[],"stateMutability":"nonpayable","type":"function"}],"userDoc":{"kind":"user","methods":{},"version":1},"developerDoc":{"kind":"dev","methods":{},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"oldChainGasAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newChainGasAmount\",\"type\":\"uint256\"}],\"name\":\"ChainGasAmountUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"oldFeeRate\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newFeeRate\",\"type\":\"uint256\"}],\"name\":\"FeeRateUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"FeesSwept\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"newChainGasAmount\",\"type\":\"uint256\"}],\"name\":\"setChainGasAmount\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"newFeeRate\",\"type\":\"uint256\"}],\"name\":\"setProtocolFeeRate\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"}],\"name\":\"sweepProtocolFees\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeV2.sol\":\"IAdmin\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeV2.sol\":{\"keccak256\":\"0x7cd0f885e80e2bdaa638bc32ae7af7d2e248f99ce4b354c217d0f0f7d7302e0a\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://7ccf28df0bd7b4606986585acd8622ed9b4e81379690061bb66088f0a2270af1\",\"dweb:/ipfs/QmTf7HNdHZkK6vmx8ZgewycQEb72oLD9nPwBpsM5reMstQ\"]}},\"version\":1}"},"hashes":{"setChainGasAmount(uint256)":"b250fe6b","setProtocolFeeRate(uint256)":"b13aa2d6","sweepProtocolFees(address,address)":"06f333f2"}},"solidity/FastBridgeV2.sol:IERC165":{"code":"0x","runtime-code":"0x","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.24 ^0.8.0 ^0.8.20;\n\n// contracts/interfaces/IAdmin.sol\n\ninterface IAdmin {\n // ============ Events ============\n\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n event ChainGasAmountUpdated(uint256 oldChainGasAmount, uint256 newChainGasAmount);\n\n // ============ Methods ============\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n\n function setChainGasAmount(uint256 newChainGasAmount) external;\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IFastBridgeRecipient.sol\n\ninterface IFastBridgeRecipient {\n function fastBridgeTransferReceived(\n address token,\n uint256 amount,\n bytes memory callParams\n )\n external\n payable\n returns (bytes4);\n}\n\n// contracts/interfaces/IFastBridgeV2Errors.sol\n\ninterface IFastBridgeV2Errors {\n error AmountIncorrect();\n error CallParamsLengthAboveMax();\n error ChainIncorrect();\n error ExclusivityParamsIncorrect();\n error MsgValueIncorrect();\n error NativeTokenCallValueNotSupported();\n error SenderIncorrect();\n error StatusIncorrect();\n error ZeroAddress();\n\n error RecipientIncorrectReturnValue();\n error RecipientNoReturnValue();\n\n error DeadlineExceeded();\n error DeadlineNotExceeded();\n error DeadlineTooShort();\n error DisputePeriodNotPassed();\n error DisputePeriodPassed();\n error ExclusivityPeriodNotPassed();\n\n error TransactionRelayed();\n}\n\n// contracts/libs/Errors.sol\n\nerror DeadlineExceeded();\nerror DeadlineNotExceeded();\nerror DeadlineTooShort();\nerror InsufficientOutputAmount();\n\nerror MsgValueIncorrect();\nerror PoolNotFound();\nerror TokenAddressMismatch();\nerror TokenNotContract();\nerror TokenNotETH();\nerror TokensIdentical();\n\nerror ChainIncorrect();\nerror AmountIncorrect();\nerror ZeroAddress();\n\nerror DisputePeriodNotPassed();\nerror DisputePeriodPassed();\nerror SenderIncorrect();\nerror StatusIncorrect();\nerror TransactionIdIncorrect();\nerror TransactionRelayed();\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// contracts/interfaces/IFastBridgeV2.sol\n\ninterface IFastBridgeV2 is IFastBridge {\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n struct BridgeTxDetails {\n BridgeStatus status;\n uint40 proofBlockTimestamp;\n uint48 proofBlockNumber;\n address proofRelayer;\n }\n\n struct BridgeRelay {\n uint48 blockNumber;\n uint48 blockTimestamp;\n address relayer;\n }\n\n /// @notice New params introduced in the FastBridgeV2.\n /// We are passing fields from the older BridgeParams struct outside of this struct\n /// for backwards compatibility.\n /// Note: quoteRelayer and quoteExclusivitySeconds are either both zero (indicating no exclusivity)\n /// or both non-zero (indicating exclusivity for the given period).\n /// Note: callValue \u003e 0 can NOT be used with destToken = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE (ETH_ADDRESS)\n /// @param quoteRelayer Relayer that provided the quote for the transaction\n /// @param quoteExclusivitySeconds Period of time the quote relayer is guaranteed exclusivity after user's deposit\n /// @param quoteId Unique quote identifier used for tracking the quote\n /// @param callValue ETH value to send to the recipient (if any)\n /// @param callParams Parameters for the arbitrary call to the destination recipient (if any)\n struct BridgeParamsV2 {\n address quoteRelayer;\n int256 quoteExclusivitySeconds;\n bytes quoteId;\n uint256 callValue;\n bytes callParams;\n }\n\n /// @notice Updated bridge transaction struct to include parameters introduced in FastBridgeV2.\n /// Note: only `exclusivityRelayer` can fill such a transaction until `exclusivityEndTime`.\n /// TODO: consider changing the encoding scheme to prevent spending extra gas on decoding.\n struct BridgeTransactionV2 {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n uint256 callValue; // ETH value to send to the recipient (if any) - replaces V1's sendChainGas flag\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n address exclusivityRelayer;\n uint256 exclusivityEndTime;\n bytes callParams;\n }\n\n event BridgeQuoteDetails(bytes32 indexed transactionId, bytes quoteId);\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability\n /// to provide temporary exclusivity fill rights for the quote relayer.\n /// @param params The parameters required to bridge\n /// @param paramsV2 The parameters for exclusivity fill rights (optional, can be left empty)\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function relay(bytes memory request, address relayer) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param transactionId The transaction id associated with the encoded bridge transaction to prove\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital.\n /// @notice Can only send funds to the relayer address on the proof.\n /// @param request The encoded bridge transaction to claim on origin chain\n function claim(bytes memory request) external;\n /// @notice Checks if a transaction has been relayed\n /// @param transactionId The ID of the transaction to check\n /// @return True if the transaction has been relayed, false otherwise\n function bridgeRelays(bytes32 transactionId) external view returns (bool);\n\n /// @notice Returns the status of a bridge transaction\n /// @param transactionId The ID of the bridge transaction\n /// @return BridgeStatus Status of the bridge transaction\n function bridgeStatuses(bytes32 transactionId) external view returns (BridgeStatus);\n\n /// @notice Returns the timestamp and relayer of a bridge proof\n /// @param transactionId The ID of the bridge transaction\n /// @return timestamp The timestamp of the bridge proof\n /// @return relayer The relayer address of the bridge proof\n function bridgeProofs(bytes32 transactionId) external view returns (uint96 timestamp, address relayer);\n\n /// @notice Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\n /// @param request The bridge request to decode\n function getBridgeTransactionV2(bytes memory request) external view returns (BridgeTransactionV2 memory);\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// contracts/libs/UniversalToken.sol\n\nlibrary UniversalTokenLib {\n using SafeERC20 for IERC20;\n\n address internal constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Transfers tokens to the given account. Reverts if transfer is not successful.\n /// @dev This might trigger fallback, if ETH is transferred to the contract.\n /// Make sure this can not lead to reentrancy attacks.\n function universalTransfer(address token, address to, uint256 value) internal {\n // Don't do anything, if need to send tokens to this address\n if (to == address(this)) return;\n // Don't do anything, if trying to send zero value\n if (value == 0) return;\n if (token == ETH_ADDRESS) {\n /// @dev Note: this can potentially lead to executing code in `to`.\n // solhint-disable-next-line avoid-low-level-calls\n (bool success,) = to.call{value: value}(\"\");\n require(success, \"ETH transfer failed\");\n } else {\n IERC20(token).safeTransfer(to, value);\n }\n }\n\n /// @notice Issues an infinite allowance to the spender, if the current allowance is insufficient\n /// to spend the given amount.\n function universalApproveInfinity(address token, address spender, uint256 amountToSpend) internal {\n // ETH Chad doesn't require your approval\n if (token == ETH_ADDRESS) return;\n // No-op if allowance is already sufficient\n uint256 allowance = IERC20(token).allowance(address(this), spender);\n if (allowance \u003e= amountToSpend) return;\n // Otherwise, reset approval to 0 and set to max allowance\n if (allowance \u003e 0) IERC20(token).safeDecreaseAllowance(spender, allowance);\n IERC20(token).safeIncreaseAllowance(spender, type(uint256).max);\n }\n\n /// @notice Returns the balance of the given token (or native ETH) for the given account.\n function universalBalanceOf(address token, address account) internal view returns (uint256) {\n if (token == ETH_ADDRESS) {\n return account.balance;\n } else {\n return IERC20(token).balanceOf(account);\n }\n }\n\n /// @dev Checks that token is a contract and not ETH_ADDRESS.\n function assertIsContract(address token) internal view {\n // Check that ETH_ADDRESS was not used (in case this is a predeploy on any of the chains)\n if (token == UniversalTokenLib.ETH_ADDRESS) revert TokenNotContract();\n // Check that token is not an EOA\n if (token.code.length == 0) revert TokenNotContract();\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/Admin.sol\n\ncontract Admin is IAdmin, AccessControlEnumerable {\n using UniversalTokenLib for address;\n\n bytes32 public constant RELAYER_ROLE = keccak256(\"RELAYER_ROLE\");\n bytes32 public constant REFUNDER_ROLE = keccak256(\"REFUNDER_ROLE\");\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n uint256 public constant FEE_BPS = 1e6;\n uint256 public constant FEE_RATE_MAX = 0.01e6; // max 1% on origin amount\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Chain gas amount to forward as rebate if requested\n uint256 public chainGasAmount;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n }\n\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n require(newFeeRate \u003c= FEE_RATE_MAX, \"newFeeRate \u003e max\");\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n token.universalTransfer(recipient, feeAmount);\n emit FeesSwept(token, recipient, feeAmount);\n }\n\n function setChainGasAmount(uint256 newChainGasAmount) external onlyRole(GOVERNOR_ROLE) {\n uint256 oldChainGasAmount = chainGasAmount;\n chainGasAmount = newChainGasAmount;\n emit ChainGasAmountUpdated(oldChainGasAmount, newChainGasAmount);\n }\n}\n\n// contracts/FastBridgeV2.sol\n\n/// @notice FastBridgeV2 is a contract for bridging tokens across chains.\ncontract FastBridgeV2 is Admin, IFastBridgeV2, IFastBridgeV2Errors {\n using SafeERC20 for IERC20;\n using UniversalTokenLib for address;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Delay for a transaction after which it could be permisionlessly refunded\n uint256 public constant REFUND_DELAY = 7 days;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n /// @notice Maximum length of accepted callParams\n uint256 public constant MAX_CALL_PARAMS_LENGTH = 2 ** 16 - 1;\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeTxDetails) public bridgeTxDetails;\n /// @notice Relay details on destination chain\n mapping(bytes32 =\u003e BridgeRelay) public bridgeRelayDetails;\n /// @notice Unique bridge nonces tracked per originSender\n mapping(address =\u003e uint256) public senderNonces;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Replaced by senderNonces\n uint256 public immutable nonce = 0;\n /// @notice the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n bridge({\n params: params,\n paramsV2: BridgeParamsV2({\n quoteRelayer: address(0),\n quoteExclusivitySeconds: 0,\n quoteId: bytes(\"\"),\n callValue: 0,\n callParams: bytes(\"\")\n })\n });\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes memory request) external payable {\n relay({request: request, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes memory request, bytes32 destTxHash) external {\n prove({transactionId: keccak256(request), destTxHash: destTxHash, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridgeV2\n function claim(bytes memory request) external {\n claim({request: request, to: address(0)});\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003e DISPUTE_PERIOD) {\n revert DisputePeriodPassed();\n }\n\n // @dev relayer gets slashed effectively if dest relay has gone thru\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n bridgeTxDetails[transactionId].proofRelayer = address(0);\n bridgeTxDetails[transactionId].proofBlockTimestamp = 0;\n bridgeTxDetails[transactionId].proofBlockNumber = 0;\n\n emit BridgeProofDisputed(transactionId, msg.sender);\n }\n\n /// @inheritdoc IFastBridge\n function refund(bytes memory request) external {\n bytes32 transactionId = keccak256(request);\n\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n\n if (bridgeTxDetails[transactionId].status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n\n if (hasRole(REFUNDER_ROLE, msg.sender)) {\n // Refunder can refund if deadline has passed\n if (block.timestamp \u003c= transaction.deadline) revert DeadlineNotExceeded();\n } else {\n // Permissionless refund is allowed after REFUND_DELAY\n if (block.timestamp \u003c= transaction.deadline + REFUND_DELAY) revert DeadlineNotExceeded();\n }\n\n // if all checks passed, set to REFUNDED status\n bridgeTxDetails[transactionId].status = BridgeStatus.REFUNDED;\n\n // transfer origin collateral back to original sender\n address to = transaction.originSender;\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount + transaction.originFeeAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (bridgeTxDetails[transactionId].proofRelayer != relayer) revert SenderIncorrect();\n return _timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n /// @dev This method is added to achieve backwards compatibility with decoding requests into V1 structs:\n /// - `callValue` is partially reported as a zero/non-zero flag\n /// - `callParams` is ignored\n /// In order to process all kinds of requests use getBridgeTransactionV2 instead.\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory) {\n // Try decoding into V2 struct first. This will revert if V1 struct is passed\n try this.getBridgeTransactionV2(request) returns (BridgeTransactionV2 memory txV2) {\n // Note: we entirely ignore the callParams field, as it was not present in V1\n return BridgeTransaction({\n originChainId: txV2.originChainId,\n destChainId: txV2.destChainId,\n originSender: txV2.originSender,\n destRecipient: txV2.destRecipient,\n originToken: txV2.originToken,\n destToken: txV2.destToken,\n originAmount: txV2.originAmount,\n destAmount: txV2.destAmount,\n originFeeAmount: txV2.originFeeAmount,\n sendChainGas: txV2.callValue != 0,\n deadline: txV2.deadline,\n nonce: txV2.nonce\n });\n } catch {\n // Fallback to V1 struct\n return abi.decode(request, (BridgeTransaction));\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) public payable {\n int256 exclusivityEndTime = int256(block.timestamp) + paramsV2.quoteExclusivitySeconds;\n _validateBridgeParams(params, paramsV2, exclusivityEndTime);\n\n // transfer tokens to bridge contract\n /// @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _pullToken(params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n\n // set status to requested\n bytes memory request = abi.encode(\n BridgeTransactionV2({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n callValue: paramsV2.callValue,\n deadline: params.deadline,\n nonce: senderNonces[params.sender]++, // increment nonce on every bridge\n exclusivityRelayer: paramsV2.quoteRelayer,\n // We checked exclusivityEndTime to be in range (0 .. params.deadline] above, so can safely cast\n exclusivityEndTime: uint256(exclusivityEndTime),\n callParams: paramsV2.callParams\n })\n );\n bytes32 transactionId = keccak256(request);\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n\n emit BridgeRequested({\n transactionId: transactionId,\n sender: params.sender,\n request: request,\n destChainId: params.dstChainId,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n sendChainGas: paramsV2.callValue != 0\n });\n emit BridgeQuoteDetails(transactionId, paramsV2.quoteId);\n }\n\n /// @inheritdoc IFastBridgeV2\n function relay(bytes memory request, address relayer) public payable {\n bytes32 transactionId = keccak256(request);\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n _validateRelayParams(transaction, transactionId, relayer);\n // mark bridge transaction as relayed\n bridgeRelayDetails[transactionId] =\n BridgeRelay({blockNumber: uint48(block.number), blockTimestamp: uint48(block.timestamp), relayer: relayer});\n\n // transfer tokens to recipient on destination chain and do an arbitrary call if requested\n address to = transaction.destRecipient;\n address token = transaction.destToken;\n uint256 amount = transaction.destAmount;\n\n // All state changes have been done at this point, can proceed to the external calls.\n // This follows the checks-effects-interactions pattern to mitigate potential reentrancy attacks.\n if (token == UniversalTokenLib.ETH_ADDRESS) {\n // For ETH non-zero callValue is not allowed\n if (transaction.callValue != 0) revert NativeTokenCallValueNotSupported();\n // Check that the correct msg.value was sent\n if (msg.value != amount) revert MsgValueIncorrect();\n } else {\n // For ERC20s, we check that the correct msg.value was sent\n if (msg.value != transaction.callValue) revert MsgValueIncorrect();\n // We need to transfer the tokens from the Relayer to the recipient first before performing an\n // optional post-transfer arbitrary call.\n IERC20(token).safeTransferFrom(msg.sender, to, amount);\n }\n\n if (transaction.callParams.length != 0) {\n // Arbitrary call requested, perform it while supplying full msg.value to the recipient\n // Note: if token has a fee on transfers, the recipient will have received less than `amount`.\n // This is a very niche edge case and should be handled by the recipient contract.\n _checkedCallRecipient({recipient: to, token: token, amount: amount, callParams: transaction.callParams});\n } else if (msg.value != 0) {\n // No arbitrary call requested, but msg.value was sent. This is either a relay with ETH,\n // or a non-zero callValue request with an ERC20. In both cases, transfer the ETH to the recipient.\n Address.sendValue(payable(to), msg.value);\n }\n\n emit BridgeRelayed({\n transactionId: transactionId,\n relayer: relayer,\n to: to,\n originChainId: transaction.originChainId,\n originToken: transaction.originToken,\n destToken: transaction.destToken,\n originAmount: transaction.originAmount,\n destAmount: transaction.destAmount,\n chainGasAmount: transaction.callValue\n });\n }\n\n /// @inheritdoc IFastBridgeV2\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) public onlyRole(RELAYER_ROLE) {\n // update bridge tx status given proof provided\n if (bridgeTxDetails[transactionId].status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n bridgeTxDetails[transactionId].status = BridgeStatus.RELAYER_PROVED;\n bridgeTxDetails[transactionId].proofBlockTimestamp = uint40(block.timestamp);\n bridgeTxDetails[transactionId].proofBlockNumber = uint48(block.number);\n bridgeTxDetails[transactionId].proofRelayer = relayer;\n\n emit BridgeProofProvided(transactionId, relayer, destTxHash);\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes memory request, address to) public {\n bytes32 transactionId = keccak256(request);\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n\n // update bridge tx status if able to claim origin collateral\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n\n // if \"to\" is zero addr, permissionlessly send funds to proven relayer\n if (to == address(0)) {\n to = bridgeTxDetails[transactionId].proofRelayer;\n } else if (bridgeTxDetails[transactionId].proofRelayer != msg.sender) {\n revert SenderIncorrect();\n }\n\n if (_timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003c= DISPUTE_PERIOD) {\n revert DisputePeriodNotPassed();\n }\n\n bridgeTxDetails[transactionId].status = BridgeStatus.RELAYER_CLAIMED;\n\n // update protocol fees if origin fee amount exists\n if (transaction.originFeeAmount \u003e 0) protocolFees[transaction.originToken] += transaction.originFeeAmount;\n\n // transfer origin collateral less fee to specified address\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositClaimed(transactionId, bridgeTxDetails[transactionId].proofRelayer, to, token, amount);\n }\n\n function bridgeStatuses(bytes32 transactionId) public view returns (BridgeStatus status) {\n return bridgeTxDetails[transactionId].status;\n }\n\n function bridgeProofs(bytes32 transactionId) public view returns (uint96 timestamp, address relayer) {\n timestamp = bridgeTxDetails[transactionId].proofBlockTimestamp;\n relayer = bridgeTxDetails[transactionId].proofRelayer;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeRelays(bytes32 transactionId) public view returns (bool) {\n // has this transactionId been relayed?\n return bridgeRelayDetails[transactionId].relayer != address(0);\n }\n\n /// @inheritdoc IFastBridgeV2\n function getBridgeTransactionV2(bytes memory request) public pure returns (BridgeTransactionV2 memory) {\n return abi.decode(request, (BridgeTransactionV2));\n }\n\n /// @notice Pulls a requested token from the user to this contract.\n function _pullToken(address token, uint256 amount) internal returns (uint256 amountPulled) {\n if (token == UniversalTokenLib.ETH_ADDRESS) {\n // For ETH we just need to check that the supplied msg.value is correct\n if (amount != msg.value) revert MsgValueIncorrect();\n amountPulled = msg.value;\n } else {\n token.assertIsContract();\n // Record token balance before transfer\n amountPulled = IERC20(token).balanceOf(address(this));\n // Token needs to be pulled only if msg.value is zero\n // This way user can specify WETH as the origin asset\n IERC20(token).safeTransferFrom(msg.sender, address(this), amount);\n // Use the difference between the recorded balance and the current balance as the amountPulled\n amountPulled = IERC20(token).balanceOf(address(this)) - amountPulled;\n }\n }\n\n /// @notice Calls the Recipient's hook function with the specified callParams and performs\n /// all the necessary checks for the returned value.\n function _checkedCallRecipient(\n address recipient,\n address token,\n uint256 amount,\n bytes memory callParams\n )\n internal\n {\n bytes memory hookData =\n abi.encodeCall(IFastBridgeRecipient.fastBridgeTransferReceived, (token, amount, callParams));\n // This will bubble any revert messages from the hook function\n bytes memory returnData = Address.functionCallWithValue({target: recipient, data: hookData, value: msg.value});\n // Explicit revert if no return data at all\n if (returnData.length == 0) revert RecipientNoReturnValue();\n // Check that exactly a single return value was returned\n if (returnData.length != 32) revert RecipientIncorrectReturnValue();\n // Return value should be abi-encoded hook function selector\n if (bytes32(returnData) != bytes32(IFastBridgeRecipient.fastBridgeTransferReceived.selector)) {\n revert RecipientIncorrectReturnValue();\n }\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint40(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint40).max but\n /// proof.timestamp \u003c type(uint40).max via unchecked statement\n /// @param proofBlockTimestamp The bridge proof block timestamp\n /// @return delta Time delta since proof submitted\n function _timeSince(uint40 proofBlockTimestamp) internal view returns (uint256 delta) {\n unchecked {\n delta = uint40(block.timestamp) - proofBlockTimestamp;\n }\n }\n\n /// @notice Performs all the necessary checks for a bridge to happen.\n /// @dev There's no good way to refactor this function to reduce cyclomatic complexity due to\n /// the number of checks that need to be performed, so we skip the code-complexity rule here.\n // solhint-disable-next-line code-complexity\n function _validateBridgeParams(\n BridgeParams memory params,\n BridgeParamsV2 memory paramsV2,\n int256 exclusivityEndTime\n )\n internal\n view\n {\n // Check V1 (legacy) params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.sender == address(0) || params.to == address(0)) revert ZeroAddress();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n // Check V2 params\n if (paramsV2.callParams.length \u003e MAX_CALL_PARAMS_LENGTH) revert CallParamsLengthAboveMax();\n if (paramsV2.callValue != 0 \u0026\u0026 params.destToken == UniversalTokenLib.ETH_ADDRESS) {\n revert NativeTokenCallValueNotSupported();\n }\n // exclusivityEndTime must be in range (0 .. params.deadline]\n if (exclusivityEndTime \u003c= 0 || exclusivityEndTime \u003e int256(params.deadline)) {\n revert ExclusivityParamsIncorrect();\n }\n }\n\n /// @notice Performs all the necessary checks for a relay to happen.\n function _validateRelayParams(\n BridgeTransactionV2 memory transaction,\n bytes32 transactionId,\n address relayer\n )\n internal\n view\n {\n if (relayer == address(0)) revert ZeroAddress();\n // Check if the transaction has already been relayed\n if (bridgeRelays(transactionId)) revert TransactionRelayed();\n if (transaction.destChainId != uint32(block.chainid)) revert ChainIncorrect();\n // Check the deadline for relay to happen\n if (block.timestamp \u003e transaction.deadline) revert DeadlineExceeded();\n // Check the exclusivity period, if it is still ongoing\n // forgefmt: disable-next-item\n if (\n transaction.exclusivityRelayer != address(0) \u0026\u0026\n transaction.exclusivityRelayer != relayer \u0026\u0026\n block.timestamp \u003c= transaction.exclusivityEndTime\n ) {\n revert ExclusivityPeriodNotPassed();\n }\n }\n}\n","language":"Solidity","languageVersion":"0.8.24","compilerVersion":"0.8.24","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"","srcMapRuntime":"","abiDefinition":[{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"}],"userDoc":{"kind":"user","methods":{},"version":1},"developerDoc":{"details":"Interface of the ERC165 standard, as defined in the https://eips.ethereum.org/EIPS/eip-165[EIP]. Implementers can declare support of contract interfaces, which can then be queried by others ({ERC165Checker}). For an implementation, see {ERC165}.","kind":"dev","methods":{"supportsInterface(bytes4)":{"details":"Returns true if this contract implements the interface defined by `interfaceId`. See the corresponding https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section] to learn more about how these ids are created. This function call must use less than 30 000 gas."}},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"bytes4\",\"name\":\"interfaceId\",\"type\":\"bytes4\"}],\"name\":\"supportsInterface\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"}],\"devdoc\":{\"details\":\"Interface of the ERC165 standard, as defined in the https://eips.ethereum.org/EIPS/eip-165[EIP]. Implementers can declare support of contract interfaces, which can then be queried by others ({ERC165Checker}). For an implementation, see {ERC165}.\",\"kind\":\"dev\",\"methods\":{\"supportsInterface(bytes4)\":{\"details\":\"Returns true if this contract implements the interface defined by `interfaceId`. See the corresponding https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section] to learn more about how these ids are created. This function call must use less than 30 000 gas.\"}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeV2.sol\":\"IERC165\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeV2.sol\":{\"keccak256\":\"0x7cd0f885e80e2bdaa638bc32ae7af7d2e248f99ce4b354c217d0f0f7d7302e0a\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://7ccf28df0bd7b4606986585acd8622ed9b4e81379690061bb66088f0a2270af1\",\"dweb:/ipfs/QmTf7HNdHZkK6vmx8ZgewycQEb72oLD9nPwBpsM5reMstQ\"]}},\"version\":1}"},"hashes":{"supportsInterface(bytes4)":"01ffc9a7"}},"solidity/FastBridgeV2.sol:IERC20":{"code":"0x","runtime-code":"0x","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.24 ^0.8.0 ^0.8.20;\n\n// contracts/interfaces/IAdmin.sol\n\ninterface IAdmin {\n // ============ Events ============\n\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n event ChainGasAmountUpdated(uint256 oldChainGasAmount, uint256 newChainGasAmount);\n\n // ============ Methods ============\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n\n function setChainGasAmount(uint256 newChainGasAmount) external;\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IFastBridgeRecipient.sol\n\ninterface IFastBridgeRecipient {\n function fastBridgeTransferReceived(\n address token,\n uint256 amount,\n bytes memory callParams\n )\n external\n payable\n returns (bytes4);\n}\n\n// contracts/interfaces/IFastBridgeV2Errors.sol\n\ninterface IFastBridgeV2Errors {\n error AmountIncorrect();\n error CallParamsLengthAboveMax();\n error ChainIncorrect();\n error ExclusivityParamsIncorrect();\n error MsgValueIncorrect();\n error NativeTokenCallValueNotSupported();\n error SenderIncorrect();\n error StatusIncorrect();\n error ZeroAddress();\n\n error RecipientIncorrectReturnValue();\n error RecipientNoReturnValue();\n\n error DeadlineExceeded();\n error DeadlineNotExceeded();\n error DeadlineTooShort();\n error DisputePeriodNotPassed();\n error DisputePeriodPassed();\n error ExclusivityPeriodNotPassed();\n\n error TransactionRelayed();\n}\n\n// contracts/libs/Errors.sol\n\nerror DeadlineExceeded();\nerror DeadlineNotExceeded();\nerror DeadlineTooShort();\nerror InsufficientOutputAmount();\n\nerror MsgValueIncorrect();\nerror PoolNotFound();\nerror TokenAddressMismatch();\nerror TokenNotContract();\nerror TokenNotETH();\nerror TokensIdentical();\n\nerror ChainIncorrect();\nerror AmountIncorrect();\nerror ZeroAddress();\n\nerror DisputePeriodNotPassed();\nerror DisputePeriodPassed();\nerror SenderIncorrect();\nerror StatusIncorrect();\nerror TransactionIdIncorrect();\nerror TransactionRelayed();\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// contracts/interfaces/IFastBridgeV2.sol\n\ninterface IFastBridgeV2 is IFastBridge {\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n struct BridgeTxDetails {\n BridgeStatus status;\n uint40 proofBlockTimestamp;\n uint48 proofBlockNumber;\n address proofRelayer;\n }\n\n struct BridgeRelay {\n uint48 blockNumber;\n uint48 blockTimestamp;\n address relayer;\n }\n\n /// @notice New params introduced in the FastBridgeV2.\n /// We are passing fields from the older BridgeParams struct outside of this struct\n /// for backwards compatibility.\n /// Note: quoteRelayer and quoteExclusivitySeconds are either both zero (indicating no exclusivity)\n /// or both non-zero (indicating exclusivity for the given period).\n /// Note: callValue \u003e 0 can NOT be used with destToken = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE (ETH_ADDRESS)\n /// @param quoteRelayer Relayer that provided the quote for the transaction\n /// @param quoteExclusivitySeconds Period of time the quote relayer is guaranteed exclusivity after user's deposit\n /// @param quoteId Unique quote identifier used for tracking the quote\n /// @param callValue ETH value to send to the recipient (if any)\n /// @param callParams Parameters for the arbitrary call to the destination recipient (if any)\n struct BridgeParamsV2 {\n address quoteRelayer;\n int256 quoteExclusivitySeconds;\n bytes quoteId;\n uint256 callValue;\n bytes callParams;\n }\n\n /// @notice Updated bridge transaction struct to include parameters introduced in FastBridgeV2.\n /// Note: only `exclusivityRelayer` can fill such a transaction until `exclusivityEndTime`.\n /// TODO: consider changing the encoding scheme to prevent spending extra gas on decoding.\n struct BridgeTransactionV2 {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n uint256 callValue; // ETH value to send to the recipient (if any) - replaces V1's sendChainGas flag\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n address exclusivityRelayer;\n uint256 exclusivityEndTime;\n bytes callParams;\n }\n\n event BridgeQuoteDetails(bytes32 indexed transactionId, bytes quoteId);\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability\n /// to provide temporary exclusivity fill rights for the quote relayer.\n /// @param params The parameters required to bridge\n /// @param paramsV2 The parameters for exclusivity fill rights (optional, can be left empty)\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function relay(bytes memory request, address relayer) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param transactionId The transaction id associated with the encoded bridge transaction to prove\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital.\n /// @notice Can only send funds to the relayer address on the proof.\n /// @param request The encoded bridge transaction to claim on origin chain\n function claim(bytes memory request) external;\n /// @notice Checks if a transaction has been relayed\n /// @param transactionId The ID of the transaction to check\n /// @return True if the transaction has been relayed, false otherwise\n function bridgeRelays(bytes32 transactionId) external view returns (bool);\n\n /// @notice Returns the status of a bridge transaction\n /// @param transactionId The ID of the bridge transaction\n /// @return BridgeStatus Status of the bridge transaction\n function bridgeStatuses(bytes32 transactionId) external view returns (BridgeStatus);\n\n /// @notice Returns the timestamp and relayer of a bridge proof\n /// @param transactionId The ID of the bridge transaction\n /// @return timestamp The timestamp of the bridge proof\n /// @return relayer The relayer address of the bridge proof\n function bridgeProofs(bytes32 transactionId) external view returns (uint96 timestamp, address relayer);\n\n /// @notice Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\n /// @param request The bridge request to decode\n function getBridgeTransactionV2(bytes memory request) external view returns (BridgeTransactionV2 memory);\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// contracts/libs/UniversalToken.sol\n\nlibrary UniversalTokenLib {\n using SafeERC20 for IERC20;\n\n address internal constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Transfers tokens to the given account. Reverts if transfer is not successful.\n /// @dev This might trigger fallback, if ETH is transferred to the contract.\n /// Make sure this can not lead to reentrancy attacks.\n function universalTransfer(address token, address to, uint256 value) internal {\n // Don't do anything, if need to send tokens to this address\n if (to == address(this)) return;\n // Don't do anything, if trying to send zero value\n if (value == 0) return;\n if (token == ETH_ADDRESS) {\n /// @dev Note: this can potentially lead to executing code in `to`.\n // solhint-disable-next-line avoid-low-level-calls\n (bool success,) = to.call{value: value}(\"\");\n require(success, \"ETH transfer failed\");\n } else {\n IERC20(token).safeTransfer(to, value);\n }\n }\n\n /// @notice Issues an infinite allowance to the spender, if the current allowance is insufficient\n /// to spend the given amount.\n function universalApproveInfinity(address token, address spender, uint256 amountToSpend) internal {\n // ETH Chad doesn't require your approval\n if (token == ETH_ADDRESS) return;\n // No-op if allowance is already sufficient\n uint256 allowance = IERC20(token).allowance(address(this), spender);\n if (allowance \u003e= amountToSpend) return;\n // Otherwise, reset approval to 0 and set to max allowance\n if (allowance \u003e 0) IERC20(token).safeDecreaseAllowance(spender, allowance);\n IERC20(token).safeIncreaseAllowance(spender, type(uint256).max);\n }\n\n /// @notice Returns the balance of the given token (or native ETH) for the given account.\n function universalBalanceOf(address token, address account) internal view returns (uint256) {\n if (token == ETH_ADDRESS) {\n return account.balance;\n } else {\n return IERC20(token).balanceOf(account);\n }\n }\n\n /// @dev Checks that token is a contract and not ETH_ADDRESS.\n function assertIsContract(address token) internal view {\n // Check that ETH_ADDRESS was not used (in case this is a predeploy on any of the chains)\n if (token == UniversalTokenLib.ETH_ADDRESS) revert TokenNotContract();\n // Check that token is not an EOA\n if (token.code.length == 0) revert TokenNotContract();\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/Admin.sol\n\ncontract Admin is IAdmin, AccessControlEnumerable {\n using UniversalTokenLib for address;\n\n bytes32 public constant RELAYER_ROLE = keccak256(\"RELAYER_ROLE\");\n bytes32 public constant REFUNDER_ROLE = keccak256(\"REFUNDER_ROLE\");\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n uint256 public constant FEE_BPS = 1e6;\n uint256 public constant FEE_RATE_MAX = 0.01e6; // max 1% on origin amount\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Chain gas amount to forward as rebate if requested\n uint256 public chainGasAmount;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n }\n\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n require(newFeeRate \u003c= FEE_RATE_MAX, \"newFeeRate \u003e max\");\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n token.universalTransfer(recipient, feeAmount);\n emit FeesSwept(token, recipient, feeAmount);\n }\n\n function setChainGasAmount(uint256 newChainGasAmount) external onlyRole(GOVERNOR_ROLE) {\n uint256 oldChainGasAmount = chainGasAmount;\n chainGasAmount = newChainGasAmount;\n emit ChainGasAmountUpdated(oldChainGasAmount, newChainGasAmount);\n }\n}\n\n// contracts/FastBridgeV2.sol\n\n/// @notice FastBridgeV2 is a contract for bridging tokens across chains.\ncontract FastBridgeV2 is Admin, IFastBridgeV2, IFastBridgeV2Errors {\n using SafeERC20 for IERC20;\n using UniversalTokenLib for address;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Delay for a transaction after which it could be permisionlessly refunded\n uint256 public constant REFUND_DELAY = 7 days;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n /// @notice Maximum length of accepted callParams\n uint256 public constant MAX_CALL_PARAMS_LENGTH = 2 ** 16 - 1;\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeTxDetails) public bridgeTxDetails;\n /// @notice Relay details on destination chain\n mapping(bytes32 =\u003e BridgeRelay) public bridgeRelayDetails;\n /// @notice Unique bridge nonces tracked per originSender\n mapping(address =\u003e uint256) public senderNonces;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Replaced by senderNonces\n uint256 public immutable nonce = 0;\n /// @notice the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n bridge({\n params: params,\n paramsV2: BridgeParamsV2({\n quoteRelayer: address(0),\n quoteExclusivitySeconds: 0,\n quoteId: bytes(\"\"),\n callValue: 0,\n callParams: bytes(\"\")\n })\n });\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes memory request) external payable {\n relay({request: request, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes memory request, bytes32 destTxHash) external {\n prove({transactionId: keccak256(request), destTxHash: destTxHash, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridgeV2\n function claim(bytes memory request) external {\n claim({request: request, to: address(0)});\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003e DISPUTE_PERIOD) {\n revert DisputePeriodPassed();\n }\n\n // @dev relayer gets slashed effectively if dest relay has gone thru\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n bridgeTxDetails[transactionId].proofRelayer = address(0);\n bridgeTxDetails[transactionId].proofBlockTimestamp = 0;\n bridgeTxDetails[transactionId].proofBlockNumber = 0;\n\n emit BridgeProofDisputed(transactionId, msg.sender);\n }\n\n /// @inheritdoc IFastBridge\n function refund(bytes memory request) external {\n bytes32 transactionId = keccak256(request);\n\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n\n if (bridgeTxDetails[transactionId].status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n\n if (hasRole(REFUNDER_ROLE, msg.sender)) {\n // Refunder can refund if deadline has passed\n if (block.timestamp \u003c= transaction.deadline) revert DeadlineNotExceeded();\n } else {\n // Permissionless refund is allowed after REFUND_DELAY\n if (block.timestamp \u003c= transaction.deadline + REFUND_DELAY) revert DeadlineNotExceeded();\n }\n\n // if all checks passed, set to REFUNDED status\n bridgeTxDetails[transactionId].status = BridgeStatus.REFUNDED;\n\n // transfer origin collateral back to original sender\n address to = transaction.originSender;\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount + transaction.originFeeAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (bridgeTxDetails[transactionId].proofRelayer != relayer) revert SenderIncorrect();\n return _timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n /// @dev This method is added to achieve backwards compatibility with decoding requests into V1 structs:\n /// - `callValue` is partially reported as a zero/non-zero flag\n /// - `callParams` is ignored\n /// In order to process all kinds of requests use getBridgeTransactionV2 instead.\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory) {\n // Try decoding into V2 struct first. This will revert if V1 struct is passed\n try this.getBridgeTransactionV2(request) returns (BridgeTransactionV2 memory txV2) {\n // Note: we entirely ignore the callParams field, as it was not present in V1\n return BridgeTransaction({\n originChainId: txV2.originChainId,\n destChainId: txV2.destChainId,\n originSender: txV2.originSender,\n destRecipient: txV2.destRecipient,\n originToken: txV2.originToken,\n destToken: txV2.destToken,\n originAmount: txV2.originAmount,\n destAmount: txV2.destAmount,\n originFeeAmount: txV2.originFeeAmount,\n sendChainGas: txV2.callValue != 0,\n deadline: txV2.deadline,\n nonce: txV2.nonce\n });\n } catch {\n // Fallback to V1 struct\n return abi.decode(request, (BridgeTransaction));\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) public payable {\n int256 exclusivityEndTime = int256(block.timestamp) + paramsV2.quoteExclusivitySeconds;\n _validateBridgeParams(params, paramsV2, exclusivityEndTime);\n\n // transfer tokens to bridge contract\n /// @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _pullToken(params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n\n // set status to requested\n bytes memory request = abi.encode(\n BridgeTransactionV2({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n callValue: paramsV2.callValue,\n deadline: params.deadline,\n nonce: senderNonces[params.sender]++, // increment nonce on every bridge\n exclusivityRelayer: paramsV2.quoteRelayer,\n // We checked exclusivityEndTime to be in range (0 .. params.deadline] above, so can safely cast\n exclusivityEndTime: uint256(exclusivityEndTime),\n callParams: paramsV2.callParams\n })\n );\n bytes32 transactionId = keccak256(request);\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n\n emit BridgeRequested({\n transactionId: transactionId,\n sender: params.sender,\n request: request,\n destChainId: params.dstChainId,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n sendChainGas: paramsV2.callValue != 0\n });\n emit BridgeQuoteDetails(transactionId, paramsV2.quoteId);\n }\n\n /// @inheritdoc IFastBridgeV2\n function relay(bytes memory request, address relayer) public payable {\n bytes32 transactionId = keccak256(request);\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n _validateRelayParams(transaction, transactionId, relayer);\n // mark bridge transaction as relayed\n bridgeRelayDetails[transactionId] =\n BridgeRelay({blockNumber: uint48(block.number), blockTimestamp: uint48(block.timestamp), relayer: relayer});\n\n // transfer tokens to recipient on destination chain and do an arbitrary call if requested\n address to = transaction.destRecipient;\n address token = transaction.destToken;\n uint256 amount = transaction.destAmount;\n\n // All state changes have been done at this point, can proceed to the external calls.\n // This follows the checks-effects-interactions pattern to mitigate potential reentrancy attacks.\n if (token == UniversalTokenLib.ETH_ADDRESS) {\n // For ETH non-zero callValue is not allowed\n if (transaction.callValue != 0) revert NativeTokenCallValueNotSupported();\n // Check that the correct msg.value was sent\n if (msg.value != amount) revert MsgValueIncorrect();\n } else {\n // For ERC20s, we check that the correct msg.value was sent\n if (msg.value != transaction.callValue) revert MsgValueIncorrect();\n // We need to transfer the tokens from the Relayer to the recipient first before performing an\n // optional post-transfer arbitrary call.\n IERC20(token).safeTransferFrom(msg.sender, to, amount);\n }\n\n if (transaction.callParams.length != 0) {\n // Arbitrary call requested, perform it while supplying full msg.value to the recipient\n // Note: if token has a fee on transfers, the recipient will have received less than `amount`.\n // This is a very niche edge case and should be handled by the recipient contract.\n _checkedCallRecipient({recipient: to, token: token, amount: amount, callParams: transaction.callParams});\n } else if (msg.value != 0) {\n // No arbitrary call requested, but msg.value was sent. This is either a relay with ETH,\n // or a non-zero callValue request with an ERC20. In both cases, transfer the ETH to the recipient.\n Address.sendValue(payable(to), msg.value);\n }\n\n emit BridgeRelayed({\n transactionId: transactionId,\n relayer: relayer,\n to: to,\n originChainId: transaction.originChainId,\n originToken: transaction.originToken,\n destToken: transaction.destToken,\n originAmount: transaction.originAmount,\n destAmount: transaction.destAmount,\n chainGasAmount: transaction.callValue\n });\n }\n\n /// @inheritdoc IFastBridgeV2\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) public onlyRole(RELAYER_ROLE) {\n // update bridge tx status given proof provided\n if (bridgeTxDetails[transactionId].status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n bridgeTxDetails[transactionId].status = BridgeStatus.RELAYER_PROVED;\n bridgeTxDetails[transactionId].proofBlockTimestamp = uint40(block.timestamp);\n bridgeTxDetails[transactionId].proofBlockNumber = uint48(block.number);\n bridgeTxDetails[transactionId].proofRelayer = relayer;\n\n emit BridgeProofProvided(transactionId, relayer, destTxHash);\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes memory request, address to) public {\n bytes32 transactionId = keccak256(request);\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n\n // update bridge tx status if able to claim origin collateral\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n\n // if \"to\" is zero addr, permissionlessly send funds to proven relayer\n if (to == address(0)) {\n to = bridgeTxDetails[transactionId].proofRelayer;\n } else if (bridgeTxDetails[transactionId].proofRelayer != msg.sender) {\n revert SenderIncorrect();\n }\n\n if (_timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003c= DISPUTE_PERIOD) {\n revert DisputePeriodNotPassed();\n }\n\n bridgeTxDetails[transactionId].status = BridgeStatus.RELAYER_CLAIMED;\n\n // update protocol fees if origin fee amount exists\n if (transaction.originFeeAmount \u003e 0) protocolFees[transaction.originToken] += transaction.originFeeAmount;\n\n // transfer origin collateral less fee to specified address\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositClaimed(transactionId, bridgeTxDetails[transactionId].proofRelayer, to, token, amount);\n }\n\n function bridgeStatuses(bytes32 transactionId) public view returns (BridgeStatus status) {\n return bridgeTxDetails[transactionId].status;\n }\n\n function bridgeProofs(bytes32 transactionId) public view returns (uint96 timestamp, address relayer) {\n timestamp = bridgeTxDetails[transactionId].proofBlockTimestamp;\n relayer = bridgeTxDetails[transactionId].proofRelayer;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeRelays(bytes32 transactionId) public view returns (bool) {\n // has this transactionId been relayed?\n return bridgeRelayDetails[transactionId].relayer != address(0);\n }\n\n /// @inheritdoc IFastBridgeV2\n function getBridgeTransactionV2(bytes memory request) public pure returns (BridgeTransactionV2 memory) {\n return abi.decode(request, (BridgeTransactionV2));\n }\n\n /// @notice Pulls a requested token from the user to this contract.\n function _pullToken(address token, uint256 amount) internal returns (uint256 amountPulled) {\n if (token == UniversalTokenLib.ETH_ADDRESS) {\n // For ETH we just need to check that the supplied msg.value is correct\n if (amount != msg.value) revert MsgValueIncorrect();\n amountPulled = msg.value;\n } else {\n token.assertIsContract();\n // Record token balance before transfer\n amountPulled = IERC20(token).balanceOf(address(this));\n // Token needs to be pulled only if msg.value is zero\n // This way user can specify WETH as the origin asset\n IERC20(token).safeTransferFrom(msg.sender, address(this), amount);\n // Use the difference between the recorded balance and the current balance as the amountPulled\n amountPulled = IERC20(token).balanceOf(address(this)) - amountPulled;\n }\n }\n\n /// @notice Calls the Recipient's hook function with the specified callParams and performs\n /// all the necessary checks for the returned value.\n function _checkedCallRecipient(\n address recipient,\n address token,\n uint256 amount,\n bytes memory callParams\n )\n internal\n {\n bytes memory hookData =\n abi.encodeCall(IFastBridgeRecipient.fastBridgeTransferReceived, (token, amount, callParams));\n // This will bubble any revert messages from the hook function\n bytes memory returnData = Address.functionCallWithValue({target: recipient, data: hookData, value: msg.value});\n // Explicit revert if no return data at all\n if (returnData.length == 0) revert RecipientNoReturnValue();\n // Check that exactly a single return value was returned\n if (returnData.length != 32) revert RecipientIncorrectReturnValue();\n // Return value should be abi-encoded hook function selector\n if (bytes32(returnData) != bytes32(IFastBridgeRecipient.fastBridgeTransferReceived.selector)) {\n revert RecipientIncorrectReturnValue();\n }\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint40(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint40).max but\n /// proof.timestamp \u003c type(uint40).max via unchecked statement\n /// @param proofBlockTimestamp The bridge proof block timestamp\n /// @return delta Time delta since proof submitted\n function _timeSince(uint40 proofBlockTimestamp) internal view returns (uint256 delta) {\n unchecked {\n delta = uint40(block.timestamp) - proofBlockTimestamp;\n }\n }\n\n /// @notice Performs all the necessary checks for a bridge to happen.\n /// @dev There's no good way to refactor this function to reduce cyclomatic complexity due to\n /// the number of checks that need to be performed, so we skip the code-complexity rule here.\n // solhint-disable-next-line code-complexity\n function _validateBridgeParams(\n BridgeParams memory params,\n BridgeParamsV2 memory paramsV2,\n int256 exclusivityEndTime\n )\n internal\n view\n {\n // Check V1 (legacy) params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.sender == address(0) || params.to == address(0)) revert ZeroAddress();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n // Check V2 params\n if (paramsV2.callParams.length \u003e MAX_CALL_PARAMS_LENGTH) revert CallParamsLengthAboveMax();\n if (paramsV2.callValue != 0 \u0026\u0026 params.destToken == UniversalTokenLib.ETH_ADDRESS) {\n revert NativeTokenCallValueNotSupported();\n }\n // exclusivityEndTime must be in range (0 .. params.deadline]\n if (exclusivityEndTime \u003c= 0 || exclusivityEndTime \u003e int256(params.deadline)) {\n revert ExclusivityParamsIncorrect();\n }\n }\n\n /// @notice Performs all the necessary checks for a relay to happen.\n function _validateRelayParams(\n BridgeTransactionV2 memory transaction,\n bytes32 transactionId,\n address relayer\n )\n internal\n view\n {\n if (relayer == address(0)) revert ZeroAddress();\n // Check if the transaction has already been relayed\n if (bridgeRelays(transactionId)) revert TransactionRelayed();\n if (transaction.destChainId != uint32(block.chainid)) revert ChainIncorrect();\n // Check the deadline for relay to happen\n if (block.timestamp \u003e transaction.deadline) revert DeadlineExceeded();\n // Check the exclusivity period, if it is still ongoing\n // forgefmt: disable-next-item\n if (\n transaction.exclusivityRelayer != address(0) \u0026\u0026\n transaction.exclusivityRelayer != relayer \u0026\u0026\n block.timestamp \u003c= transaction.exclusivityEndTime\n ) {\n revert ExclusivityPeriodNotPassed();\n }\n }\n}\n","language":"Solidity","languageVersion":"0.8.24","compilerVersion":"0.8.24","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"","srcMapRuntime":"","abiDefinition":[{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Transfer","type":"event"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"}],"userDoc":{"kind":"user","methods":{},"version":1},"developerDoc":{"details":"Interface of the ERC20 standard as defined in the EIP.","events":{"Approval(address,address,uint256)":{"details":"Emitted when the allowance of a `spender` for an `owner` is set by a call to {approve}. `value` is the new allowance."},"Transfer(address,address,uint256)":{"details":"Emitted when `value` tokens are moved from one account (`from`) to another (`to`). Note that `value` may be zero."}},"kind":"dev","methods":{"allowance(address,address)":{"details":"Returns the remaining number of tokens that `spender` will be allowed to spend on behalf of `owner` through {transferFrom}. This is zero by default. This value changes when {approve} or {transferFrom} are called."},"approve(address,uint256)":{"details":"Sets a `value` amount of tokens as the allowance of `spender` over the caller's tokens. Returns a boolean value indicating whether the operation succeeded. IMPORTANT: Beware that changing an allowance with this method brings the risk that someone may use both the old and the new allowance by unfortunate transaction ordering. One possible solution to mitigate this race condition is to first reduce the spender's allowance to 0 and set the desired value afterwards: https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 Emits an {Approval} event."},"balanceOf(address)":{"details":"Returns the value of tokens owned by `account`."},"totalSupply()":{"details":"Returns the value of tokens in existence."},"transfer(address,uint256)":{"details":"Moves a `value` amount of tokens from the caller's account to `to`. Returns a boolean value indicating whether the operation succeeded. Emits a {Transfer} event."},"transferFrom(address,address,uint256)":{"details":"Moves a `value` amount of tokens from `from` to `to` using the allowance mechanism. `value` is then deducted from the caller's allowance. Returns a boolean value indicating whether the operation succeeded. Emits a {Transfer} event."}},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"Approval\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"Transfer\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"}],\"name\":\"allowance\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"approve\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"balanceOf\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"totalSupply\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"transfer\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"transferFrom\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"details\":\"Interface of the ERC20 standard as defined in the EIP.\",\"events\":{\"Approval(address,address,uint256)\":{\"details\":\"Emitted when the allowance of a `spender` for an `owner` is set by a call to {approve}. `value` is the new allowance.\"},\"Transfer(address,address,uint256)\":{\"details\":\"Emitted when `value` tokens are moved from one account (`from`) to another (`to`). Note that `value` may be zero.\"}},\"kind\":\"dev\",\"methods\":{\"allowance(address,address)\":{\"details\":\"Returns the remaining number of tokens that `spender` will be allowed to spend on behalf of `owner` through {transferFrom}. This is zero by default. This value changes when {approve} or {transferFrom} are called.\"},\"approve(address,uint256)\":{\"details\":\"Sets a `value` amount of tokens as the allowance of `spender` over the caller's tokens. Returns a boolean value indicating whether the operation succeeded. IMPORTANT: Beware that changing an allowance with this method brings the risk that someone may use both the old and the new allowance by unfortunate transaction ordering. One possible solution to mitigate this race condition is to first reduce the spender's allowance to 0 and set the desired value afterwards: https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 Emits an {Approval} event.\"},\"balanceOf(address)\":{\"details\":\"Returns the value of tokens owned by `account`.\"},\"totalSupply()\":{\"details\":\"Returns the value of tokens in existence.\"},\"transfer(address,uint256)\":{\"details\":\"Moves a `value` amount of tokens from the caller's account to `to`. Returns a boolean value indicating whether the operation succeeded. Emits a {Transfer} event.\"},\"transferFrom(address,address,uint256)\":{\"details\":\"Moves a `value` amount of tokens from `from` to `to` using the allowance mechanism. `value` is then deducted from the caller's allowance. Returns a boolean value indicating whether the operation succeeded. Emits a {Transfer} event.\"}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeV2.sol\":\"IERC20\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeV2.sol\":{\"keccak256\":\"0x7cd0f885e80e2bdaa638bc32ae7af7d2e248f99ce4b354c217d0f0f7d7302e0a\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://7ccf28df0bd7b4606986585acd8622ed9b4e81379690061bb66088f0a2270af1\",\"dweb:/ipfs/QmTf7HNdHZkK6vmx8ZgewycQEb72oLD9nPwBpsM5reMstQ\"]}},\"version\":1}"},"hashes":{"allowance(address,address)":"dd62ed3e","approve(address,uint256)":"095ea7b3","balanceOf(address)":"70a08231","totalSupply()":"18160ddd","transfer(address,uint256)":"a9059cbb","transferFrom(address,address,uint256)":"23b872dd"}},"solidity/FastBridgeV2.sol:IERC20Permit":{"code":"0x","runtime-code":"0x","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.24 ^0.8.0 ^0.8.20;\n\n// contracts/interfaces/IAdmin.sol\n\ninterface IAdmin {\n // ============ Events ============\n\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n event ChainGasAmountUpdated(uint256 oldChainGasAmount, uint256 newChainGasAmount);\n\n // ============ Methods ============\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n\n function setChainGasAmount(uint256 newChainGasAmount) external;\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IFastBridgeRecipient.sol\n\ninterface IFastBridgeRecipient {\n function fastBridgeTransferReceived(\n address token,\n uint256 amount,\n bytes memory callParams\n )\n external\n payable\n returns (bytes4);\n}\n\n// contracts/interfaces/IFastBridgeV2Errors.sol\n\ninterface IFastBridgeV2Errors {\n error AmountIncorrect();\n error CallParamsLengthAboveMax();\n error ChainIncorrect();\n error ExclusivityParamsIncorrect();\n error MsgValueIncorrect();\n error NativeTokenCallValueNotSupported();\n error SenderIncorrect();\n error StatusIncorrect();\n error ZeroAddress();\n\n error RecipientIncorrectReturnValue();\n error RecipientNoReturnValue();\n\n error DeadlineExceeded();\n error DeadlineNotExceeded();\n error DeadlineTooShort();\n error DisputePeriodNotPassed();\n error DisputePeriodPassed();\n error ExclusivityPeriodNotPassed();\n\n error TransactionRelayed();\n}\n\n// contracts/libs/Errors.sol\n\nerror DeadlineExceeded();\nerror DeadlineNotExceeded();\nerror DeadlineTooShort();\nerror InsufficientOutputAmount();\n\nerror MsgValueIncorrect();\nerror PoolNotFound();\nerror TokenAddressMismatch();\nerror TokenNotContract();\nerror TokenNotETH();\nerror TokensIdentical();\n\nerror ChainIncorrect();\nerror AmountIncorrect();\nerror ZeroAddress();\n\nerror DisputePeriodNotPassed();\nerror DisputePeriodPassed();\nerror SenderIncorrect();\nerror StatusIncorrect();\nerror TransactionIdIncorrect();\nerror TransactionRelayed();\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// contracts/interfaces/IFastBridgeV2.sol\n\ninterface IFastBridgeV2 is IFastBridge {\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n struct BridgeTxDetails {\n BridgeStatus status;\n uint40 proofBlockTimestamp;\n uint48 proofBlockNumber;\n address proofRelayer;\n }\n\n struct BridgeRelay {\n uint48 blockNumber;\n uint48 blockTimestamp;\n address relayer;\n }\n\n /// @notice New params introduced in the FastBridgeV2.\n /// We are passing fields from the older BridgeParams struct outside of this struct\n /// for backwards compatibility.\n /// Note: quoteRelayer and quoteExclusivitySeconds are either both zero (indicating no exclusivity)\n /// or both non-zero (indicating exclusivity for the given period).\n /// Note: callValue \u003e 0 can NOT be used with destToken = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE (ETH_ADDRESS)\n /// @param quoteRelayer Relayer that provided the quote for the transaction\n /// @param quoteExclusivitySeconds Period of time the quote relayer is guaranteed exclusivity after user's deposit\n /// @param quoteId Unique quote identifier used for tracking the quote\n /// @param callValue ETH value to send to the recipient (if any)\n /// @param callParams Parameters for the arbitrary call to the destination recipient (if any)\n struct BridgeParamsV2 {\n address quoteRelayer;\n int256 quoteExclusivitySeconds;\n bytes quoteId;\n uint256 callValue;\n bytes callParams;\n }\n\n /// @notice Updated bridge transaction struct to include parameters introduced in FastBridgeV2.\n /// Note: only `exclusivityRelayer` can fill such a transaction until `exclusivityEndTime`.\n /// TODO: consider changing the encoding scheme to prevent spending extra gas on decoding.\n struct BridgeTransactionV2 {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n uint256 callValue; // ETH value to send to the recipient (if any) - replaces V1's sendChainGas flag\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n address exclusivityRelayer;\n uint256 exclusivityEndTime;\n bytes callParams;\n }\n\n event BridgeQuoteDetails(bytes32 indexed transactionId, bytes quoteId);\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability\n /// to provide temporary exclusivity fill rights for the quote relayer.\n /// @param params The parameters required to bridge\n /// @param paramsV2 The parameters for exclusivity fill rights (optional, can be left empty)\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function relay(bytes memory request, address relayer) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param transactionId The transaction id associated with the encoded bridge transaction to prove\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital.\n /// @notice Can only send funds to the relayer address on the proof.\n /// @param request The encoded bridge transaction to claim on origin chain\n function claim(bytes memory request) external;\n /// @notice Checks if a transaction has been relayed\n /// @param transactionId The ID of the transaction to check\n /// @return True if the transaction has been relayed, false otherwise\n function bridgeRelays(bytes32 transactionId) external view returns (bool);\n\n /// @notice Returns the status of a bridge transaction\n /// @param transactionId The ID of the bridge transaction\n /// @return BridgeStatus Status of the bridge transaction\n function bridgeStatuses(bytes32 transactionId) external view returns (BridgeStatus);\n\n /// @notice Returns the timestamp and relayer of a bridge proof\n /// @param transactionId The ID of the bridge transaction\n /// @return timestamp The timestamp of the bridge proof\n /// @return relayer The relayer address of the bridge proof\n function bridgeProofs(bytes32 transactionId) external view returns (uint96 timestamp, address relayer);\n\n /// @notice Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\n /// @param request The bridge request to decode\n function getBridgeTransactionV2(bytes memory request) external view returns (BridgeTransactionV2 memory);\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// contracts/libs/UniversalToken.sol\n\nlibrary UniversalTokenLib {\n using SafeERC20 for IERC20;\n\n address internal constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Transfers tokens to the given account. Reverts if transfer is not successful.\n /// @dev This might trigger fallback, if ETH is transferred to the contract.\n /// Make sure this can not lead to reentrancy attacks.\n function universalTransfer(address token, address to, uint256 value) internal {\n // Don't do anything, if need to send tokens to this address\n if (to == address(this)) return;\n // Don't do anything, if trying to send zero value\n if (value == 0) return;\n if (token == ETH_ADDRESS) {\n /// @dev Note: this can potentially lead to executing code in `to`.\n // solhint-disable-next-line avoid-low-level-calls\n (bool success,) = to.call{value: value}(\"\");\n require(success, \"ETH transfer failed\");\n } else {\n IERC20(token).safeTransfer(to, value);\n }\n }\n\n /// @notice Issues an infinite allowance to the spender, if the current allowance is insufficient\n /// to spend the given amount.\n function universalApproveInfinity(address token, address spender, uint256 amountToSpend) internal {\n // ETH Chad doesn't require your approval\n if (token == ETH_ADDRESS) return;\n // No-op if allowance is already sufficient\n uint256 allowance = IERC20(token).allowance(address(this), spender);\n if (allowance \u003e= amountToSpend) return;\n // Otherwise, reset approval to 0 and set to max allowance\n if (allowance \u003e 0) IERC20(token).safeDecreaseAllowance(spender, allowance);\n IERC20(token).safeIncreaseAllowance(spender, type(uint256).max);\n }\n\n /// @notice Returns the balance of the given token (or native ETH) for the given account.\n function universalBalanceOf(address token, address account) internal view returns (uint256) {\n if (token == ETH_ADDRESS) {\n return account.balance;\n } else {\n return IERC20(token).balanceOf(account);\n }\n }\n\n /// @dev Checks that token is a contract and not ETH_ADDRESS.\n function assertIsContract(address token) internal view {\n // Check that ETH_ADDRESS was not used (in case this is a predeploy on any of the chains)\n if (token == UniversalTokenLib.ETH_ADDRESS) revert TokenNotContract();\n // Check that token is not an EOA\n if (token.code.length == 0) revert TokenNotContract();\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/Admin.sol\n\ncontract Admin is IAdmin, AccessControlEnumerable {\n using UniversalTokenLib for address;\n\n bytes32 public constant RELAYER_ROLE = keccak256(\"RELAYER_ROLE\");\n bytes32 public constant REFUNDER_ROLE = keccak256(\"REFUNDER_ROLE\");\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n uint256 public constant FEE_BPS = 1e6;\n uint256 public constant FEE_RATE_MAX = 0.01e6; // max 1% on origin amount\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Chain gas amount to forward as rebate if requested\n uint256 public chainGasAmount;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n }\n\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n require(newFeeRate \u003c= FEE_RATE_MAX, \"newFeeRate \u003e max\");\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n token.universalTransfer(recipient, feeAmount);\n emit FeesSwept(token, recipient, feeAmount);\n }\n\n function setChainGasAmount(uint256 newChainGasAmount) external onlyRole(GOVERNOR_ROLE) {\n uint256 oldChainGasAmount = chainGasAmount;\n chainGasAmount = newChainGasAmount;\n emit ChainGasAmountUpdated(oldChainGasAmount, newChainGasAmount);\n }\n}\n\n// contracts/FastBridgeV2.sol\n\n/// @notice FastBridgeV2 is a contract for bridging tokens across chains.\ncontract FastBridgeV2 is Admin, IFastBridgeV2, IFastBridgeV2Errors {\n using SafeERC20 for IERC20;\n using UniversalTokenLib for address;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Delay for a transaction after which it could be permisionlessly refunded\n uint256 public constant REFUND_DELAY = 7 days;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n /// @notice Maximum length of accepted callParams\n uint256 public constant MAX_CALL_PARAMS_LENGTH = 2 ** 16 - 1;\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeTxDetails) public bridgeTxDetails;\n /// @notice Relay details on destination chain\n mapping(bytes32 =\u003e BridgeRelay) public bridgeRelayDetails;\n /// @notice Unique bridge nonces tracked per originSender\n mapping(address =\u003e uint256) public senderNonces;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Replaced by senderNonces\n uint256 public immutable nonce = 0;\n /// @notice the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n bridge({\n params: params,\n paramsV2: BridgeParamsV2({\n quoteRelayer: address(0),\n quoteExclusivitySeconds: 0,\n quoteId: bytes(\"\"),\n callValue: 0,\n callParams: bytes(\"\")\n })\n });\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes memory request) external payable {\n relay({request: request, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes memory request, bytes32 destTxHash) external {\n prove({transactionId: keccak256(request), destTxHash: destTxHash, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridgeV2\n function claim(bytes memory request) external {\n claim({request: request, to: address(0)});\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003e DISPUTE_PERIOD) {\n revert DisputePeriodPassed();\n }\n\n // @dev relayer gets slashed effectively if dest relay has gone thru\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n bridgeTxDetails[transactionId].proofRelayer = address(0);\n bridgeTxDetails[transactionId].proofBlockTimestamp = 0;\n bridgeTxDetails[transactionId].proofBlockNumber = 0;\n\n emit BridgeProofDisputed(transactionId, msg.sender);\n }\n\n /// @inheritdoc IFastBridge\n function refund(bytes memory request) external {\n bytes32 transactionId = keccak256(request);\n\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n\n if (bridgeTxDetails[transactionId].status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n\n if (hasRole(REFUNDER_ROLE, msg.sender)) {\n // Refunder can refund if deadline has passed\n if (block.timestamp \u003c= transaction.deadline) revert DeadlineNotExceeded();\n } else {\n // Permissionless refund is allowed after REFUND_DELAY\n if (block.timestamp \u003c= transaction.deadline + REFUND_DELAY) revert DeadlineNotExceeded();\n }\n\n // if all checks passed, set to REFUNDED status\n bridgeTxDetails[transactionId].status = BridgeStatus.REFUNDED;\n\n // transfer origin collateral back to original sender\n address to = transaction.originSender;\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount + transaction.originFeeAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (bridgeTxDetails[transactionId].proofRelayer != relayer) revert SenderIncorrect();\n return _timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n /// @dev This method is added to achieve backwards compatibility with decoding requests into V1 structs:\n /// - `callValue` is partially reported as a zero/non-zero flag\n /// - `callParams` is ignored\n /// In order to process all kinds of requests use getBridgeTransactionV2 instead.\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory) {\n // Try decoding into V2 struct first. This will revert if V1 struct is passed\n try this.getBridgeTransactionV2(request) returns (BridgeTransactionV2 memory txV2) {\n // Note: we entirely ignore the callParams field, as it was not present in V1\n return BridgeTransaction({\n originChainId: txV2.originChainId,\n destChainId: txV2.destChainId,\n originSender: txV2.originSender,\n destRecipient: txV2.destRecipient,\n originToken: txV2.originToken,\n destToken: txV2.destToken,\n originAmount: txV2.originAmount,\n destAmount: txV2.destAmount,\n originFeeAmount: txV2.originFeeAmount,\n sendChainGas: txV2.callValue != 0,\n deadline: txV2.deadline,\n nonce: txV2.nonce\n });\n } catch {\n // Fallback to V1 struct\n return abi.decode(request, (BridgeTransaction));\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) public payable {\n int256 exclusivityEndTime = int256(block.timestamp) + paramsV2.quoteExclusivitySeconds;\n _validateBridgeParams(params, paramsV2, exclusivityEndTime);\n\n // transfer tokens to bridge contract\n /// @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _pullToken(params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n\n // set status to requested\n bytes memory request = abi.encode(\n BridgeTransactionV2({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n callValue: paramsV2.callValue,\n deadline: params.deadline,\n nonce: senderNonces[params.sender]++, // increment nonce on every bridge\n exclusivityRelayer: paramsV2.quoteRelayer,\n // We checked exclusivityEndTime to be in range (0 .. params.deadline] above, so can safely cast\n exclusivityEndTime: uint256(exclusivityEndTime),\n callParams: paramsV2.callParams\n })\n );\n bytes32 transactionId = keccak256(request);\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n\n emit BridgeRequested({\n transactionId: transactionId,\n sender: params.sender,\n request: request,\n destChainId: params.dstChainId,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n sendChainGas: paramsV2.callValue != 0\n });\n emit BridgeQuoteDetails(transactionId, paramsV2.quoteId);\n }\n\n /// @inheritdoc IFastBridgeV2\n function relay(bytes memory request, address relayer) public payable {\n bytes32 transactionId = keccak256(request);\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n _validateRelayParams(transaction, transactionId, relayer);\n // mark bridge transaction as relayed\n bridgeRelayDetails[transactionId] =\n BridgeRelay({blockNumber: uint48(block.number), blockTimestamp: uint48(block.timestamp), relayer: relayer});\n\n // transfer tokens to recipient on destination chain and do an arbitrary call if requested\n address to = transaction.destRecipient;\n address token = transaction.destToken;\n uint256 amount = transaction.destAmount;\n\n // All state changes have been done at this point, can proceed to the external calls.\n // This follows the checks-effects-interactions pattern to mitigate potential reentrancy attacks.\n if (token == UniversalTokenLib.ETH_ADDRESS) {\n // For ETH non-zero callValue is not allowed\n if (transaction.callValue != 0) revert NativeTokenCallValueNotSupported();\n // Check that the correct msg.value was sent\n if (msg.value != amount) revert MsgValueIncorrect();\n } else {\n // For ERC20s, we check that the correct msg.value was sent\n if (msg.value != transaction.callValue) revert MsgValueIncorrect();\n // We need to transfer the tokens from the Relayer to the recipient first before performing an\n // optional post-transfer arbitrary call.\n IERC20(token).safeTransferFrom(msg.sender, to, amount);\n }\n\n if (transaction.callParams.length != 0) {\n // Arbitrary call requested, perform it while supplying full msg.value to the recipient\n // Note: if token has a fee on transfers, the recipient will have received less than `amount`.\n // This is a very niche edge case and should be handled by the recipient contract.\n _checkedCallRecipient({recipient: to, token: token, amount: amount, callParams: transaction.callParams});\n } else if (msg.value != 0) {\n // No arbitrary call requested, but msg.value was sent. This is either a relay with ETH,\n // or a non-zero callValue request with an ERC20. In both cases, transfer the ETH to the recipient.\n Address.sendValue(payable(to), msg.value);\n }\n\n emit BridgeRelayed({\n transactionId: transactionId,\n relayer: relayer,\n to: to,\n originChainId: transaction.originChainId,\n originToken: transaction.originToken,\n destToken: transaction.destToken,\n originAmount: transaction.originAmount,\n destAmount: transaction.destAmount,\n chainGasAmount: transaction.callValue\n });\n }\n\n /// @inheritdoc IFastBridgeV2\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) public onlyRole(RELAYER_ROLE) {\n // update bridge tx status given proof provided\n if (bridgeTxDetails[transactionId].status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n bridgeTxDetails[transactionId].status = BridgeStatus.RELAYER_PROVED;\n bridgeTxDetails[transactionId].proofBlockTimestamp = uint40(block.timestamp);\n bridgeTxDetails[transactionId].proofBlockNumber = uint48(block.number);\n bridgeTxDetails[transactionId].proofRelayer = relayer;\n\n emit BridgeProofProvided(transactionId, relayer, destTxHash);\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes memory request, address to) public {\n bytes32 transactionId = keccak256(request);\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n\n // update bridge tx status if able to claim origin collateral\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n\n // if \"to\" is zero addr, permissionlessly send funds to proven relayer\n if (to == address(0)) {\n to = bridgeTxDetails[transactionId].proofRelayer;\n } else if (bridgeTxDetails[transactionId].proofRelayer != msg.sender) {\n revert SenderIncorrect();\n }\n\n if (_timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003c= DISPUTE_PERIOD) {\n revert DisputePeriodNotPassed();\n }\n\n bridgeTxDetails[transactionId].status = BridgeStatus.RELAYER_CLAIMED;\n\n // update protocol fees if origin fee amount exists\n if (transaction.originFeeAmount \u003e 0) protocolFees[transaction.originToken] += transaction.originFeeAmount;\n\n // transfer origin collateral less fee to specified address\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositClaimed(transactionId, bridgeTxDetails[transactionId].proofRelayer, to, token, amount);\n }\n\n function bridgeStatuses(bytes32 transactionId) public view returns (BridgeStatus status) {\n return bridgeTxDetails[transactionId].status;\n }\n\n function bridgeProofs(bytes32 transactionId) public view returns (uint96 timestamp, address relayer) {\n timestamp = bridgeTxDetails[transactionId].proofBlockTimestamp;\n relayer = bridgeTxDetails[transactionId].proofRelayer;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeRelays(bytes32 transactionId) public view returns (bool) {\n // has this transactionId been relayed?\n return bridgeRelayDetails[transactionId].relayer != address(0);\n }\n\n /// @inheritdoc IFastBridgeV2\n function getBridgeTransactionV2(bytes memory request) public pure returns (BridgeTransactionV2 memory) {\n return abi.decode(request, (BridgeTransactionV2));\n }\n\n /// @notice Pulls a requested token from the user to this contract.\n function _pullToken(address token, uint256 amount) internal returns (uint256 amountPulled) {\n if (token == UniversalTokenLib.ETH_ADDRESS) {\n // For ETH we just need to check that the supplied msg.value is correct\n if (amount != msg.value) revert MsgValueIncorrect();\n amountPulled = msg.value;\n } else {\n token.assertIsContract();\n // Record token balance before transfer\n amountPulled = IERC20(token).balanceOf(address(this));\n // Token needs to be pulled only if msg.value is zero\n // This way user can specify WETH as the origin asset\n IERC20(token).safeTransferFrom(msg.sender, address(this), amount);\n // Use the difference between the recorded balance and the current balance as the amountPulled\n amountPulled = IERC20(token).balanceOf(address(this)) - amountPulled;\n }\n }\n\n /// @notice Calls the Recipient's hook function with the specified callParams and performs\n /// all the necessary checks for the returned value.\n function _checkedCallRecipient(\n address recipient,\n address token,\n uint256 amount,\n bytes memory callParams\n )\n internal\n {\n bytes memory hookData =\n abi.encodeCall(IFastBridgeRecipient.fastBridgeTransferReceived, (token, amount, callParams));\n // This will bubble any revert messages from the hook function\n bytes memory returnData = Address.functionCallWithValue({target: recipient, data: hookData, value: msg.value});\n // Explicit revert if no return data at all\n if (returnData.length == 0) revert RecipientNoReturnValue();\n // Check that exactly a single return value was returned\n if (returnData.length != 32) revert RecipientIncorrectReturnValue();\n // Return value should be abi-encoded hook function selector\n if (bytes32(returnData) != bytes32(IFastBridgeRecipient.fastBridgeTransferReceived.selector)) {\n revert RecipientIncorrectReturnValue();\n }\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint40(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint40).max but\n /// proof.timestamp \u003c type(uint40).max via unchecked statement\n /// @param proofBlockTimestamp The bridge proof block timestamp\n /// @return delta Time delta since proof submitted\n function _timeSince(uint40 proofBlockTimestamp) internal view returns (uint256 delta) {\n unchecked {\n delta = uint40(block.timestamp) - proofBlockTimestamp;\n }\n }\n\n /// @notice Performs all the necessary checks for a bridge to happen.\n /// @dev There's no good way to refactor this function to reduce cyclomatic complexity due to\n /// the number of checks that need to be performed, so we skip the code-complexity rule here.\n // solhint-disable-next-line code-complexity\n function _validateBridgeParams(\n BridgeParams memory params,\n BridgeParamsV2 memory paramsV2,\n int256 exclusivityEndTime\n )\n internal\n view\n {\n // Check V1 (legacy) params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.sender == address(0) || params.to == address(0)) revert ZeroAddress();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n // Check V2 params\n if (paramsV2.callParams.length \u003e MAX_CALL_PARAMS_LENGTH) revert CallParamsLengthAboveMax();\n if (paramsV2.callValue != 0 \u0026\u0026 params.destToken == UniversalTokenLib.ETH_ADDRESS) {\n revert NativeTokenCallValueNotSupported();\n }\n // exclusivityEndTime must be in range (0 .. params.deadline]\n if (exclusivityEndTime \u003c= 0 || exclusivityEndTime \u003e int256(params.deadline)) {\n revert ExclusivityParamsIncorrect();\n }\n }\n\n /// @notice Performs all the necessary checks for a relay to happen.\n function _validateRelayParams(\n BridgeTransactionV2 memory transaction,\n bytes32 transactionId,\n address relayer\n )\n internal\n view\n {\n if (relayer == address(0)) revert ZeroAddress();\n // Check if the transaction has already been relayed\n if (bridgeRelays(transactionId)) revert TransactionRelayed();\n if (transaction.destChainId != uint32(block.chainid)) revert ChainIncorrect();\n // Check the deadline for relay to happen\n if (block.timestamp \u003e transaction.deadline) revert DeadlineExceeded();\n // Check the exclusivity period, if it is still ongoing\n // forgefmt: disable-next-item\n if (\n transaction.exclusivityRelayer != address(0) \u0026\u0026\n transaction.exclusivityRelayer != relayer \u0026\u0026\n block.timestamp \u003c= transaction.exclusivityEndTime\n ) {\n revert ExclusivityPeriodNotPassed();\n }\n }\n}\n","language":"Solidity","languageVersion":"0.8.24","compilerVersion":"0.8.24","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"","srcMapRuntime":"","abiDefinition":[{"inputs":[],"name":"DOMAIN_SEPARATOR","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"nonces","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"permit","outputs":[],"stateMutability":"nonpayable","type":"function"}],"userDoc":{"kind":"user","methods":{},"version":1},"developerDoc":{"details":"Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in https://eips.ethereum.org/EIPS/eip-2612[EIP-2612]. Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't need to send a transaction, and thus is not required to hold Ether at all. ==== Security Considerations There are two important considerations concerning the use of `permit`. The first is that a valid permit signature expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be considered as an intention to spend the allowance in any specific way. The second is that because permits have built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be generally recommended is: ```solidity function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public { try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {} doThing(..., value); } function doThing(..., uint256 value) public { token.safeTransferFrom(msg.sender, address(this), value); ... } ``` Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also {SafeERC20-safeTransferFrom}). Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so contracts should have entry points that don't rely on permit.","kind":"dev","methods":{"DOMAIN_SEPARATOR()":{"details":"Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}."},"nonces(address)":{"details":"Returns the current nonce for `owner`. This value must be included whenever a signature is generated for {permit}. Every successful call to {permit} increases ``owner``'s nonce by one. This prevents a signature from being used multiple times."},"permit(address,address,uint256,uint256,uint8,bytes32,bytes32)":{"details":"Sets `value` as the allowance of `spender` over ``owner``'s tokens, given ``owner``'s signed approval. IMPORTANT: The same issues {IERC20-approve} has related to transaction ordering also apply here. Emits an {Approval} event. Requirements: - `spender` cannot be the zero address. - `deadline` must be a timestamp in the future. - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner` over the EIP712-formatted function arguments. - the signature must use ``owner``'s current nonce (see {nonces}). For more information on the signature format, see the https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP section]. CAUTION: See Security Considerations above."}},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[],\"name\":\"DOMAIN_SEPARATOR\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"}],\"name\":\"nonces\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"},{\"internalType\":\"uint8\",\"name\":\"v\",\"type\":\"uint8\"},{\"internalType\":\"bytes32\",\"name\":\"r\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"s\",\"type\":\"bytes32\"}],\"name\":\"permit\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"details\":\"Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in https://eips.ethereum.org/EIPS/eip-2612[EIP-2612]. Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't need to send a transaction, and thus is not required to hold Ether at all. ==== Security Considerations There are two important considerations concerning the use of `permit`. The first is that a valid permit signature expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be considered as an intention to spend the allowance in any specific way. The second is that because permits have built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be generally recommended is: ```solidity function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public { try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {} doThing(..., value); } function doThing(..., uint256 value) public { token.safeTransferFrom(msg.sender, address(this), value); ... } ``` Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also {SafeERC20-safeTransferFrom}). Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so contracts should have entry points that don't rely on permit.\",\"kind\":\"dev\",\"methods\":{\"DOMAIN_SEPARATOR()\":{\"details\":\"Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\"},\"nonces(address)\":{\"details\":\"Returns the current nonce for `owner`. This value must be included whenever a signature is generated for {permit}. Every successful call to {permit} increases ``owner``'s nonce by one. This prevents a signature from being used multiple times.\"},\"permit(address,address,uint256,uint256,uint8,bytes32,bytes32)\":{\"details\":\"Sets `value` as the allowance of `spender` over ``owner``'s tokens, given ``owner``'s signed approval. IMPORTANT: The same issues {IERC20-approve} has related to transaction ordering also apply here. Emits an {Approval} event. Requirements: - `spender` cannot be the zero address. - `deadline` must be a timestamp in the future. - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner` over the EIP712-formatted function arguments. - the signature must use ``owner``'s current nonce (see {nonces}). For more information on the signature format, see the https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP section]. CAUTION: See Security Considerations above.\"}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeV2.sol\":\"IERC20Permit\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeV2.sol\":{\"keccak256\":\"0x7cd0f885e80e2bdaa638bc32ae7af7d2e248f99ce4b354c217d0f0f7d7302e0a\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://7ccf28df0bd7b4606986585acd8622ed9b4e81379690061bb66088f0a2270af1\",\"dweb:/ipfs/QmTf7HNdHZkK6vmx8ZgewycQEb72oLD9nPwBpsM5reMstQ\"]}},\"version\":1}"},"hashes":{"DOMAIN_SEPARATOR()":"3644e515","nonces(address)":"7ecebe00","permit(address,address,uint256,uint256,uint8,bytes32,bytes32)":"d505accf"}},"solidity/FastBridgeV2.sol:IFastBridge":{"code":"0x","runtime-code":"0x","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.24 ^0.8.0 ^0.8.20;\n\n// contracts/interfaces/IAdmin.sol\n\ninterface IAdmin {\n // ============ Events ============\n\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n event ChainGasAmountUpdated(uint256 oldChainGasAmount, uint256 newChainGasAmount);\n\n // ============ Methods ============\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n\n function setChainGasAmount(uint256 newChainGasAmount) external;\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IFastBridgeRecipient.sol\n\ninterface IFastBridgeRecipient {\n function fastBridgeTransferReceived(\n address token,\n uint256 amount,\n bytes memory callParams\n )\n external\n payable\n returns (bytes4);\n}\n\n// contracts/interfaces/IFastBridgeV2Errors.sol\n\ninterface IFastBridgeV2Errors {\n error AmountIncorrect();\n error CallParamsLengthAboveMax();\n error ChainIncorrect();\n error ExclusivityParamsIncorrect();\n error MsgValueIncorrect();\n error NativeTokenCallValueNotSupported();\n error SenderIncorrect();\n error StatusIncorrect();\n error ZeroAddress();\n\n error RecipientIncorrectReturnValue();\n error RecipientNoReturnValue();\n\n error DeadlineExceeded();\n error DeadlineNotExceeded();\n error DeadlineTooShort();\n error DisputePeriodNotPassed();\n error DisputePeriodPassed();\n error ExclusivityPeriodNotPassed();\n\n error TransactionRelayed();\n}\n\n// contracts/libs/Errors.sol\n\nerror DeadlineExceeded();\nerror DeadlineNotExceeded();\nerror DeadlineTooShort();\nerror InsufficientOutputAmount();\n\nerror MsgValueIncorrect();\nerror PoolNotFound();\nerror TokenAddressMismatch();\nerror TokenNotContract();\nerror TokenNotETH();\nerror TokensIdentical();\n\nerror ChainIncorrect();\nerror AmountIncorrect();\nerror ZeroAddress();\n\nerror DisputePeriodNotPassed();\nerror DisputePeriodPassed();\nerror SenderIncorrect();\nerror StatusIncorrect();\nerror TransactionIdIncorrect();\nerror TransactionRelayed();\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// contracts/interfaces/IFastBridgeV2.sol\n\ninterface IFastBridgeV2 is IFastBridge {\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n struct BridgeTxDetails {\n BridgeStatus status;\n uint40 proofBlockTimestamp;\n uint48 proofBlockNumber;\n address proofRelayer;\n }\n\n struct BridgeRelay {\n uint48 blockNumber;\n uint48 blockTimestamp;\n address relayer;\n }\n\n /// @notice New params introduced in the FastBridgeV2.\n /// We are passing fields from the older BridgeParams struct outside of this struct\n /// for backwards compatibility.\n /// Note: quoteRelayer and quoteExclusivitySeconds are either both zero (indicating no exclusivity)\n /// or both non-zero (indicating exclusivity for the given period).\n /// Note: callValue \u003e 0 can NOT be used with destToken = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE (ETH_ADDRESS)\n /// @param quoteRelayer Relayer that provided the quote for the transaction\n /// @param quoteExclusivitySeconds Period of time the quote relayer is guaranteed exclusivity after user's deposit\n /// @param quoteId Unique quote identifier used for tracking the quote\n /// @param callValue ETH value to send to the recipient (if any)\n /// @param callParams Parameters for the arbitrary call to the destination recipient (if any)\n struct BridgeParamsV2 {\n address quoteRelayer;\n int256 quoteExclusivitySeconds;\n bytes quoteId;\n uint256 callValue;\n bytes callParams;\n }\n\n /// @notice Updated bridge transaction struct to include parameters introduced in FastBridgeV2.\n /// Note: only `exclusivityRelayer` can fill such a transaction until `exclusivityEndTime`.\n /// TODO: consider changing the encoding scheme to prevent spending extra gas on decoding.\n struct BridgeTransactionV2 {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n uint256 callValue; // ETH value to send to the recipient (if any) - replaces V1's sendChainGas flag\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n address exclusivityRelayer;\n uint256 exclusivityEndTime;\n bytes callParams;\n }\n\n event BridgeQuoteDetails(bytes32 indexed transactionId, bytes quoteId);\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability\n /// to provide temporary exclusivity fill rights for the quote relayer.\n /// @param params The parameters required to bridge\n /// @param paramsV2 The parameters for exclusivity fill rights (optional, can be left empty)\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function relay(bytes memory request, address relayer) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param transactionId The transaction id associated with the encoded bridge transaction to prove\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital.\n /// @notice Can only send funds to the relayer address on the proof.\n /// @param request The encoded bridge transaction to claim on origin chain\n function claim(bytes memory request) external;\n /// @notice Checks if a transaction has been relayed\n /// @param transactionId The ID of the transaction to check\n /// @return True if the transaction has been relayed, false otherwise\n function bridgeRelays(bytes32 transactionId) external view returns (bool);\n\n /// @notice Returns the status of a bridge transaction\n /// @param transactionId The ID of the bridge transaction\n /// @return BridgeStatus Status of the bridge transaction\n function bridgeStatuses(bytes32 transactionId) external view returns (BridgeStatus);\n\n /// @notice Returns the timestamp and relayer of a bridge proof\n /// @param transactionId The ID of the bridge transaction\n /// @return timestamp The timestamp of the bridge proof\n /// @return relayer The relayer address of the bridge proof\n function bridgeProofs(bytes32 transactionId) external view returns (uint96 timestamp, address relayer);\n\n /// @notice Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\n /// @param request The bridge request to decode\n function getBridgeTransactionV2(bytes memory request) external view returns (BridgeTransactionV2 memory);\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// contracts/libs/UniversalToken.sol\n\nlibrary UniversalTokenLib {\n using SafeERC20 for IERC20;\n\n address internal constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Transfers tokens to the given account. Reverts if transfer is not successful.\n /// @dev This might trigger fallback, if ETH is transferred to the contract.\n /// Make sure this can not lead to reentrancy attacks.\n function universalTransfer(address token, address to, uint256 value) internal {\n // Don't do anything, if need to send tokens to this address\n if (to == address(this)) return;\n // Don't do anything, if trying to send zero value\n if (value == 0) return;\n if (token == ETH_ADDRESS) {\n /// @dev Note: this can potentially lead to executing code in `to`.\n // solhint-disable-next-line avoid-low-level-calls\n (bool success,) = to.call{value: value}(\"\");\n require(success, \"ETH transfer failed\");\n } else {\n IERC20(token).safeTransfer(to, value);\n }\n }\n\n /// @notice Issues an infinite allowance to the spender, if the current allowance is insufficient\n /// to spend the given amount.\n function universalApproveInfinity(address token, address spender, uint256 amountToSpend) internal {\n // ETH Chad doesn't require your approval\n if (token == ETH_ADDRESS) return;\n // No-op if allowance is already sufficient\n uint256 allowance = IERC20(token).allowance(address(this), spender);\n if (allowance \u003e= amountToSpend) return;\n // Otherwise, reset approval to 0 and set to max allowance\n if (allowance \u003e 0) IERC20(token).safeDecreaseAllowance(spender, allowance);\n IERC20(token).safeIncreaseAllowance(spender, type(uint256).max);\n }\n\n /// @notice Returns the balance of the given token (or native ETH) for the given account.\n function universalBalanceOf(address token, address account) internal view returns (uint256) {\n if (token == ETH_ADDRESS) {\n return account.balance;\n } else {\n return IERC20(token).balanceOf(account);\n }\n }\n\n /// @dev Checks that token is a contract and not ETH_ADDRESS.\n function assertIsContract(address token) internal view {\n // Check that ETH_ADDRESS was not used (in case this is a predeploy on any of the chains)\n if (token == UniversalTokenLib.ETH_ADDRESS) revert TokenNotContract();\n // Check that token is not an EOA\n if (token.code.length == 0) revert TokenNotContract();\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/Admin.sol\n\ncontract Admin is IAdmin, AccessControlEnumerable {\n using UniversalTokenLib for address;\n\n bytes32 public constant RELAYER_ROLE = keccak256(\"RELAYER_ROLE\");\n bytes32 public constant REFUNDER_ROLE = keccak256(\"REFUNDER_ROLE\");\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n uint256 public constant FEE_BPS = 1e6;\n uint256 public constant FEE_RATE_MAX = 0.01e6; // max 1% on origin amount\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Chain gas amount to forward as rebate if requested\n uint256 public chainGasAmount;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n }\n\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n require(newFeeRate \u003c= FEE_RATE_MAX, \"newFeeRate \u003e max\");\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n token.universalTransfer(recipient, feeAmount);\n emit FeesSwept(token, recipient, feeAmount);\n }\n\n function setChainGasAmount(uint256 newChainGasAmount) external onlyRole(GOVERNOR_ROLE) {\n uint256 oldChainGasAmount = chainGasAmount;\n chainGasAmount = newChainGasAmount;\n emit ChainGasAmountUpdated(oldChainGasAmount, newChainGasAmount);\n }\n}\n\n// contracts/FastBridgeV2.sol\n\n/// @notice FastBridgeV2 is a contract for bridging tokens across chains.\ncontract FastBridgeV2 is Admin, IFastBridgeV2, IFastBridgeV2Errors {\n using SafeERC20 for IERC20;\n using UniversalTokenLib for address;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Delay for a transaction after which it could be permisionlessly refunded\n uint256 public constant REFUND_DELAY = 7 days;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n /// @notice Maximum length of accepted callParams\n uint256 public constant MAX_CALL_PARAMS_LENGTH = 2 ** 16 - 1;\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeTxDetails) public bridgeTxDetails;\n /// @notice Relay details on destination chain\n mapping(bytes32 =\u003e BridgeRelay) public bridgeRelayDetails;\n /// @notice Unique bridge nonces tracked per originSender\n mapping(address =\u003e uint256) public senderNonces;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Replaced by senderNonces\n uint256 public immutable nonce = 0;\n /// @notice the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n bridge({\n params: params,\n paramsV2: BridgeParamsV2({\n quoteRelayer: address(0),\n quoteExclusivitySeconds: 0,\n quoteId: bytes(\"\"),\n callValue: 0,\n callParams: bytes(\"\")\n })\n });\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes memory request) external payable {\n relay({request: request, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes memory request, bytes32 destTxHash) external {\n prove({transactionId: keccak256(request), destTxHash: destTxHash, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridgeV2\n function claim(bytes memory request) external {\n claim({request: request, to: address(0)});\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003e DISPUTE_PERIOD) {\n revert DisputePeriodPassed();\n }\n\n // @dev relayer gets slashed effectively if dest relay has gone thru\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n bridgeTxDetails[transactionId].proofRelayer = address(0);\n bridgeTxDetails[transactionId].proofBlockTimestamp = 0;\n bridgeTxDetails[transactionId].proofBlockNumber = 0;\n\n emit BridgeProofDisputed(transactionId, msg.sender);\n }\n\n /// @inheritdoc IFastBridge\n function refund(bytes memory request) external {\n bytes32 transactionId = keccak256(request);\n\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n\n if (bridgeTxDetails[transactionId].status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n\n if (hasRole(REFUNDER_ROLE, msg.sender)) {\n // Refunder can refund if deadline has passed\n if (block.timestamp \u003c= transaction.deadline) revert DeadlineNotExceeded();\n } else {\n // Permissionless refund is allowed after REFUND_DELAY\n if (block.timestamp \u003c= transaction.deadline + REFUND_DELAY) revert DeadlineNotExceeded();\n }\n\n // if all checks passed, set to REFUNDED status\n bridgeTxDetails[transactionId].status = BridgeStatus.REFUNDED;\n\n // transfer origin collateral back to original sender\n address to = transaction.originSender;\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount + transaction.originFeeAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (bridgeTxDetails[transactionId].proofRelayer != relayer) revert SenderIncorrect();\n return _timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n /// @dev This method is added to achieve backwards compatibility with decoding requests into V1 structs:\n /// - `callValue` is partially reported as a zero/non-zero flag\n /// - `callParams` is ignored\n /// In order to process all kinds of requests use getBridgeTransactionV2 instead.\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory) {\n // Try decoding into V2 struct first. This will revert if V1 struct is passed\n try this.getBridgeTransactionV2(request) returns (BridgeTransactionV2 memory txV2) {\n // Note: we entirely ignore the callParams field, as it was not present in V1\n return BridgeTransaction({\n originChainId: txV2.originChainId,\n destChainId: txV2.destChainId,\n originSender: txV2.originSender,\n destRecipient: txV2.destRecipient,\n originToken: txV2.originToken,\n destToken: txV2.destToken,\n originAmount: txV2.originAmount,\n destAmount: txV2.destAmount,\n originFeeAmount: txV2.originFeeAmount,\n sendChainGas: txV2.callValue != 0,\n deadline: txV2.deadline,\n nonce: txV2.nonce\n });\n } catch {\n // Fallback to V1 struct\n return abi.decode(request, (BridgeTransaction));\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) public payable {\n int256 exclusivityEndTime = int256(block.timestamp) + paramsV2.quoteExclusivitySeconds;\n _validateBridgeParams(params, paramsV2, exclusivityEndTime);\n\n // transfer tokens to bridge contract\n /// @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _pullToken(params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n\n // set status to requested\n bytes memory request = abi.encode(\n BridgeTransactionV2({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n callValue: paramsV2.callValue,\n deadline: params.deadline,\n nonce: senderNonces[params.sender]++, // increment nonce on every bridge\n exclusivityRelayer: paramsV2.quoteRelayer,\n // We checked exclusivityEndTime to be in range (0 .. params.deadline] above, so can safely cast\n exclusivityEndTime: uint256(exclusivityEndTime),\n callParams: paramsV2.callParams\n })\n );\n bytes32 transactionId = keccak256(request);\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n\n emit BridgeRequested({\n transactionId: transactionId,\n sender: params.sender,\n request: request,\n destChainId: params.dstChainId,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n sendChainGas: paramsV2.callValue != 0\n });\n emit BridgeQuoteDetails(transactionId, paramsV2.quoteId);\n }\n\n /// @inheritdoc IFastBridgeV2\n function relay(bytes memory request, address relayer) public payable {\n bytes32 transactionId = keccak256(request);\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n _validateRelayParams(transaction, transactionId, relayer);\n // mark bridge transaction as relayed\n bridgeRelayDetails[transactionId] =\n BridgeRelay({blockNumber: uint48(block.number), blockTimestamp: uint48(block.timestamp), relayer: relayer});\n\n // transfer tokens to recipient on destination chain and do an arbitrary call if requested\n address to = transaction.destRecipient;\n address token = transaction.destToken;\n uint256 amount = transaction.destAmount;\n\n // All state changes have been done at this point, can proceed to the external calls.\n // This follows the checks-effects-interactions pattern to mitigate potential reentrancy attacks.\n if (token == UniversalTokenLib.ETH_ADDRESS) {\n // For ETH non-zero callValue is not allowed\n if (transaction.callValue != 0) revert NativeTokenCallValueNotSupported();\n // Check that the correct msg.value was sent\n if (msg.value != amount) revert MsgValueIncorrect();\n } else {\n // For ERC20s, we check that the correct msg.value was sent\n if (msg.value != transaction.callValue) revert MsgValueIncorrect();\n // We need to transfer the tokens from the Relayer to the recipient first before performing an\n // optional post-transfer arbitrary call.\n IERC20(token).safeTransferFrom(msg.sender, to, amount);\n }\n\n if (transaction.callParams.length != 0) {\n // Arbitrary call requested, perform it while supplying full msg.value to the recipient\n // Note: if token has a fee on transfers, the recipient will have received less than `amount`.\n // This is a very niche edge case and should be handled by the recipient contract.\n _checkedCallRecipient({recipient: to, token: token, amount: amount, callParams: transaction.callParams});\n } else if (msg.value != 0) {\n // No arbitrary call requested, but msg.value was sent. This is either a relay with ETH,\n // or a non-zero callValue request with an ERC20. In both cases, transfer the ETH to the recipient.\n Address.sendValue(payable(to), msg.value);\n }\n\n emit BridgeRelayed({\n transactionId: transactionId,\n relayer: relayer,\n to: to,\n originChainId: transaction.originChainId,\n originToken: transaction.originToken,\n destToken: transaction.destToken,\n originAmount: transaction.originAmount,\n destAmount: transaction.destAmount,\n chainGasAmount: transaction.callValue\n });\n }\n\n /// @inheritdoc IFastBridgeV2\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) public onlyRole(RELAYER_ROLE) {\n // update bridge tx status given proof provided\n if (bridgeTxDetails[transactionId].status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n bridgeTxDetails[transactionId].status = BridgeStatus.RELAYER_PROVED;\n bridgeTxDetails[transactionId].proofBlockTimestamp = uint40(block.timestamp);\n bridgeTxDetails[transactionId].proofBlockNumber = uint48(block.number);\n bridgeTxDetails[transactionId].proofRelayer = relayer;\n\n emit BridgeProofProvided(transactionId, relayer, destTxHash);\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes memory request, address to) public {\n bytes32 transactionId = keccak256(request);\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n\n // update bridge tx status if able to claim origin collateral\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n\n // if \"to\" is zero addr, permissionlessly send funds to proven relayer\n if (to == address(0)) {\n to = bridgeTxDetails[transactionId].proofRelayer;\n } else if (bridgeTxDetails[transactionId].proofRelayer != msg.sender) {\n revert SenderIncorrect();\n }\n\n if (_timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003c= DISPUTE_PERIOD) {\n revert DisputePeriodNotPassed();\n }\n\n bridgeTxDetails[transactionId].status = BridgeStatus.RELAYER_CLAIMED;\n\n // update protocol fees if origin fee amount exists\n if (transaction.originFeeAmount \u003e 0) protocolFees[transaction.originToken] += transaction.originFeeAmount;\n\n // transfer origin collateral less fee to specified address\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositClaimed(transactionId, bridgeTxDetails[transactionId].proofRelayer, to, token, amount);\n }\n\n function bridgeStatuses(bytes32 transactionId) public view returns (BridgeStatus status) {\n return bridgeTxDetails[transactionId].status;\n }\n\n function bridgeProofs(bytes32 transactionId) public view returns (uint96 timestamp, address relayer) {\n timestamp = bridgeTxDetails[transactionId].proofBlockTimestamp;\n relayer = bridgeTxDetails[transactionId].proofRelayer;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeRelays(bytes32 transactionId) public view returns (bool) {\n // has this transactionId been relayed?\n return bridgeRelayDetails[transactionId].relayer != address(0);\n }\n\n /// @inheritdoc IFastBridgeV2\n function getBridgeTransactionV2(bytes memory request) public pure returns (BridgeTransactionV2 memory) {\n return abi.decode(request, (BridgeTransactionV2));\n }\n\n /// @notice Pulls a requested token from the user to this contract.\n function _pullToken(address token, uint256 amount) internal returns (uint256 amountPulled) {\n if (token == UniversalTokenLib.ETH_ADDRESS) {\n // For ETH we just need to check that the supplied msg.value is correct\n if (amount != msg.value) revert MsgValueIncorrect();\n amountPulled = msg.value;\n } else {\n token.assertIsContract();\n // Record token balance before transfer\n amountPulled = IERC20(token).balanceOf(address(this));\n // Token needs to be pulled only if msg.value is zero\n // This way user can specify WETH as the origin asset\n IERC20(token).safeTransferFrom(msg.sender, address(this), amount);\n // Use the difference between the recorded balance and the current balance as the amountPulled\n amountPulled = IERC20(token).balanceOf(address(this)) - amountPulled;\n }\n }\n\n /// @notice Calls the Recipient's hook function with the specified callParams and performs\n /// all the necessary checks for the returned value.\n function _checkedCallRecipient(\n address recipient,\n address token,\n uint256 amount,\n bytes memory callParams\n )\n internal\n {\n bytes memory hookData =\n abi.encodeCall(IFastBridgeRecipient.fastBridgeTransferReceived, (token, amount, callParams));\n // This will bubble any revert messages from the hook function\n bytes memory returnData = Address.functionCallWithValue({target: recipient, data: hookData, value: msg.value});\n // Explicit revert if no return data at all\n if (returnData.length == 0) revert RecipientNoReturnValue();\n // Check that exactly a single return value was returned\n if (returnData.length != 32) revert RecipientIncorrectReturnValue();\n // Return value should be abi-encoded hook function selector\n if (bytes32(returnData) != bytes32(IFastBridgeRecipient.fastBridgeTransferReceived.selector)) {\n revert RecipientIncorrectReturnValue();\n }\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint40(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint40).max but\n /// proof.timestamp \u003c type(uint40).max via unchecked statement\n /// @param proofBlockTimestamp The bridge proof block timestamp\n /// @return delta Time delta since proof submitted\n function _timeSince(uint40 proofBlockTimestamp) internal view returns (uint256 delta) {\n unchecked {\n delta = uint40(block.timestamp) - proofBlockTimestamp;\n }\n }\n\n /// @notice Performs all the necessary checks for a bridge to happen.\n /// @dev There's no good way to refactor this function to reduce cyclomatic complexity due to\n /// the number of checks that need to be performed, so we skip the code-complexity rule here.\n // solhint-disable-next-line code-complexity\n function _validateBridgeParams(\n BridgeParams memory params,\n BridgeParamsV2 memory paramsV2,\n int256 exclusivityEndTime\n )\n internal\n view\n {\n // Check V1 (legacy) params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.sender == address(0) || params.to == address(0)) revert ZeroAddress();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n // Check V2 params\n if (paramsV2.callParams.length \u003e MAX_CALL_PARAMS_LENGTH) revert CallParamsLengthAboveMax();\n if (paramsV2.callValue != 0 \u0026\u0026 params.destToken == UniversalTokenLib.ETH_ADDRESS) {\n revert NativeTokenCallValueNotSupported();\n }\n // exclusivityEndTime must be in range (0 .. params.deadline]\n if (exclusivityEndTime \u003c= 0 || exclusivityEndTime \u003e int256(params.deadline)) {\n revert ExclusivityParamsIncorrect();\n }\n }\n\n /// @notice Performs all the necessary checks for a relay to happen.\n function _validateRelayParams(\n BridgeTransactionV2 memory transaction,\n bytes32 transactionId,\n address relayer\n )\n internal\n view\n {\n if (relayer == address(0)) revert ZeroAddress();\n // Check if the transaction has already been relayed\n if (bridgeRelays(transactionId)) revert TransactionRelayed();\n if (transaction.destChainId != uint32(block.chainid)) revert ChainIncorrect();\n // Check the deadline for relay to happen\n if (block.timestamp \u003e transaction.deadline) revert DeadlineExceeded();\n // Check the exclusivity period, if it is still ongoing\n // forgefmt: disable-next-item\n if (\n transaction.exclusivityRelayer != address(0) \u0026\u0026\n transaction.exclusivityRelayer != relayer \u0026\u0026\n block.timestamp \u003c= transaction.exclusivityEndTime\n ) {\n revert ExclusivityPeriodNotPassed();\n }\n }\n}\n","language":"Solidity","languageVersion":"0.8.24","compilerVersion":"0.8.24","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"","srcMapRuntime":"","abiDefinition":[{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"relayer","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"BridgeDepositClaimed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"BridgeDepositRefunded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"relayer","type":"address"}],"name":"BridgeProofDisputed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"relayer","type":"address"},{"indexed":false,"internalType":"bytes32","name":"transactionHash","type":"bytes32"}],"name":"BridgeProofProvided","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"relayer","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint32","name":"originChainId","type":"uint32"},{"indexed":false,"internalType":"address","name":"originToken","type":"address"},{"indexed":false,"internalType":"address","name":"destToken","type":"address"},{"indexed":false,"internalType":"uint256","name":"originAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"destAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"chainGasAmount","type":"uint256"}],"name":"BridgeRelayed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"bytes","name":"request","type":"bytes"},{"indexed":false,"internalType":"uint32","name":"destChainId","type":"uint32"},{"indexed":false,"internalType":"address","name":"originToken","type":"address"},{"indexed":false,"internalType":"address","name":"destToken","type":"address"},{"indexed":false,"internalType":"uint256","name":"originAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"destAmount","type":"uint256"},{"indexed":false,"internalType":"bool","name":"sendChainGas","type":"bool"}],"name":"BridgeRequested","type":"event"},{"inputs":[{"components":[{"internalType":"uint32","name":"dstChainId","type":"uint32"},{"internalType":"address","name":"sender","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"address","name":"originToken","type":"address"},{"internalType":"address","name":"destToken","type":"address"},{"internalType":"uint256","name":"originAmount","type":"uint256"},{"internalType":"uint256","name":"destAmount","type":"uint256"},{"internalType":"bool","name":"sendChainGas","type":"bool"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"internalType":"struct IFastBridge.BridgeParams","name":"params","type":"tuple"}],"name":"bridge","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"internalType":"address","name":"relayer","type":"address"}],"name":"canClaim","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"},{"internalType":"address","name":"to","type":"address"}],"name":"claim","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"transactionId","type":"bytes32"}],"name":"dispute","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"}],"name":"getBridgeTransaction","outputs":[{"components":[{"internalType":"uint32","name":"originChainId","type":"uint32"},{"internalType":"uint32","name":"destChainId","type":"uint32"},{"internalType":"address","name":"originSender","type":"address"},{"internalType":"address","name":"destRecipient","type":"address"},{"internalType":"address","name":"originToken","type":"address"},{"internalType":"address","name":"destToken","type":"address"},{"internalType":"uint256","name":"originAmount","type":"uint256"},{"internalType":"uint256","name":"destAmount","type":"uint256"},{"internalType":"uint256","name":"originFeeAmount","type":"uint256"},{"internalType":"bool","name":"sendChainGas","type":"bool"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint256","name":"nonce","type":"uint256"}],"internalType":"struct IFastBridge.BridgeTransaction","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"},{"internalType":"bytes32","name":"destTxHash","type":"bytes32"}],"name":"prove","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"}],"name":"refund","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"}],"name":"relay","outputs":[],"stateMutability":"payable","type":"function"}],"userDoc":{"kind":"user","methods":{"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256))":{"notice":"Initiates bridge on origin chain to be relayed by off-chain relayer"},"canClaim(bytes32,address)":{"notice":"Checks if the dispute period has passed so bridge deposit can be claimed"},"claim(bytes,address)":{"notice":"Completes bridge transaction on origin chain by claiming originally deposited capital"},"dispute(bytes32)":{"notice":"Disputes an outstanding proof in case relayer provided dest chain tx is invalid"},"getBridgeTransaction(bytes)":{"notice":"Decodes bridge request into a bridge transaction"},"prove(bytes,bytes32)":{"notice":"Provides proof on origin side that relayer provided funds on destination side of bridge transaction"},"refund(bytes)":{"notice":"Refunds an outstanding bridge transaction in case optimistic bridging failed"},"relay(bytes)":{"notice":"Relays destination side of bridge transaction by off-chain relayer"}},"version":1},"developerDoc":{"kind":"dev","methods":{"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256))":{"params":{"params":"The parameters required to bridge"}},"canClaim(bytes32,address)":{"params":{"relayer":"The address of the relayer attempting to claim","transactionId":"The transaction id associated with the encoded bridge transaction to check"}},"claim(bytes,address)":{"params":{"request":"The encoded bridge transaction to claim on origin chain","to":"The recipient address of the funds"}},"dispute(bytes32)":{"params":{"transactionId":"The transaction id associated with the encoded bridge transaction to dispute"}},"getBridgeTransaction(bytes)":{"params":{"request":"The bridge request to decode"}},"prove(bytes,bytes32)":{"params":{"destTxHash":"The destination tx hash proving bridge transaction was relayed","request":"The encoded bridge transaction to prove on origin chain"}},"refund(bytes)":{"params":{"request":"The encoded bridge transaction to refund"}},"relay(bytes)":{"params":{"request":"The encoded bridge transaction to relay on destination chain"}}},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"BridgeDepositClaimed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"BridgeDepositRefunded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"name\":\"BridgeProofDisputed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"transactionHash\",\"type\":\"bytes32\"}],\"name\":\"BridgeProofProvided\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"originChainId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"chainGasAmount\",\"type\":\"uint256\"}],\"name\":\"BridgeRelayed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"destChainId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"sendChainGas\",\"type\":\"bool\"}],\"name\":\"BridgeRequested\",\"type\":\"event\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"dstChainId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"sendChainGas\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"}],\"internalType\":\"struct IFastBridge.BridgeParams\",\"name\":\"params\",\"type\":\"tuple\"}],\"name\":\"bridge\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"name\":\"canClaim\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"claim\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"}],\"name\":\"dispute\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"getBridgeTransaction\",\"outputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"originChainId\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"destChainId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"originSender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destRecipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"originFeeAmount\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"sendChainGas\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"}],\"internalType\":\"struct IFastBridge.BridgeTransaction\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"},{\"internalType\":\"bytes32\",\"name\":\"destTxHash\",\"type\":\"bytes32\"}],\"name\":\"prove\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"refund\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"relay\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{\"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256))\":{\"params\":{\"params\":\"The parameters required to bridge\"}},\"canClaim(bytes32,address)\":{\"params\":{\"relayer\":\"The address of the relayer attempting to claim\",\"transactionId\":\"The transaction id associated with the encoded bridge transaction to check\"}},\"claim(bytes,address)\":{\"params\":{\"request\":\"The encoded bridge transaction to claim on origin chain\",\"to\":\"The recipient address of the funds\"}},\"dispute(bytes32)\":{\"params\":{\"transactionId\":\"The transaction id associated with the encoded bridge transaction to dispute\"}},\"getBridgeTransaction(bytes)\":{\"params\":{\"request\":\"The bridge request to decode\"}},\"prove(bytes,bytes32)\":{\"params\":{\"destTxHash\":\"The destination tx hash proving bridge transaction was relayed\",\"request\":\"The encoded bridge transaction to prove on origin chain\"}},\"refund(bytes)\":{\"params\":{\"request\":\"The encoded bridge transaction to refund\"}},\"relay(bytes)\":{\"params\":{\"request\":\"The encoded bridge transaction to relay on destination chain\"}}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256))\":{\"notice\":\"Initiates bridge on origin chain to be relayed by off-chain relayer\"},\"canClaim(bytes32,address)\":{\"notice\":\"Checks if the dispute period has passed so bridge deposit can be claimed\"},\"claim(bytes,address)\":{\"notice\":\"Completes bridge transaction on origin chain by claiming originally deposited capital\"},\"dispute(bytes32)\":{\"notice\":\"Disputes an outstanding proof in case relayer provided dest chain tx is invalid\"},\"getBridgeTransaction(bytes)\":{\"notice\":\"Decodes bridge request into a bridge transaction\"},\"prove(bytes,bytes32)\":{\"notice\":\"Provides proof on origin side that relayer provided funds on destination side of bridge transaction\"},\"refund(bytes)\":{\"notice\":\"Refunds an outstanding bridge transaction in case optimistic bridging failed\"},\"relay(bytes)\":{\"notice\":\"Relays destination side of bridge transaction by off-chain relayer\"}},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeV2.sol\":\"IFastBridge\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeV2.sol\":{\"keccak256\":\"0x7cd0f885e80e2bdaa638bc32ae7af7d2e248f99ce4b354c217d0f0f7d7302e0a\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://7ccf28df0bd7b4606986585acd8622ed9b4e81379690061bb66088f0a2270af1\",\"dweb:/ipfs/QmTf7HNdHZkK6vmx8ZgewycQEb72oLD9nPwBpsM5reMstQ\"]}},\"version\":1}"},"hashes":{"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256))":"45851694","canClaim(bytes32,address)":"aa9641ab","claim(bytes,address)":"41fcb612","dispute(bytes32)":"add98c70","getBridgeTransaction(bytes)":"ac11fb1a","prove(bytes,bytes32)":"886d36ff","refund(bytes)":"5eb7d946","relay(bytes)":"8f0d6f17"}},"solidity/FastBridgeV2.sol:IFastBridgeRecipient":{"code":"0x","runtime-code":"0x","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.24 ^0.8.0 ^0.8.20;\n\n// contracts/interfaces/IAdmin.sol\n\ninterface IAdmin {\n // ============ Events ============\n\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n event ChainGasAmountUpdated(uint256 oldChainGasAmount, uint256 newChainGasAmount);\n\n // ============ Methods ============\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n\n function setChainGasAmount(uint256 newChainGasAmount) external;\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IFastBridgeRecipient.sol\n\ninterface IFastBridgeRecipient {\n function fastBridgeTransferReceived(\n address token,\n uint256 amount,\n bytes memory callParams\n )\n external\n payable\n returns (bytes4);\n}\n\n// contracts/interfaces/IFastBridgeV2Errors.sol\n\ninterface IFastBridgeV2Errors {\n error AmountIncorrect();\n error CallParamsLengthAboveMax();\n error ChainIncorrect();\n error ExclusivityParamsIncorrect();\n error MsgValueIncorrect();\n error NativeTokenCallValueNotSupported();\n error SenderIncorrect();\n error StatusIncorrect();\n error ZeroAddress();\n\n error RecipientIncorrectReturnValue();\n error RecipientNoReturnValue();\n\n error DeadlineExceeded();\n error DeadlineNotExceeded();\n error DeadlineTooShort();\n error DisputePeriodNotPassed();\n error DisputePeriodPassed();\n error ExclusivityPeriodNotPassed();\n\n error TransactionRelayed();\n}\n\n// contracts/libs/Errors.sol\n\nerror DeadlineExceeded();\nerror DeadlineNotExceeded();\nerror DeadlineTooShort();\nerror InsufficientOutputAmount();\n\nerror MsgValueIncorrect();\nerror PoolNotFound();\nerror TokenAddressMismatch();\nerror TokenNotContract();\nerror TokenNotETH();\nerror TokensIdentical();\n\nerror ChainIncorrect();\nerror AmountIncorrect();\nerror ZeroAddress();\n\nerror DisputePeriodNotPassed();\nerror DisputePeriodPassed();\nerror SenderIncorrect();\nerror StatusIncorrect();\nerror TransactionIdIncorrect();\nerror TransactionRelayed();\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// contracts/interfaces/IFastBridgeV2.sol\n\ninterface IFastBridgeV2 is IFastBridge {\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n struct BridgeTxDetails {\n BridgeStatus status;\n uint40 proofBlockTimestamp;\n uint48 proofBlockNumber;\n address proofRelayer;\n }\n\n struct BridgeRelay {\n uint48 blockNumber;\n uint48 blockTimestamp;\n address relayer;\n }\n\n /// @notice New params introduced in the FastBridgeV2.\n /// We are passing fields from the older BridgeParams struct outside of this struct\n /// for backwards compatibility.\n /// Note: quoteRelayer and quoteExclusivitySeconds are either both zero (indicating no exclusivity)\n /// or both non-zero (indicating exclusivity for the given period).\n /// Note: callValue \u003e 0 can NOT be used with destToken = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE (ETH_ADDRESS)\n /// @param quoteRelayer Relayer that provided the quote for the transaction\n /// @param quoteExclusivitySeconds Period of time the quote relayer is guaranteed exclusivity after user's deposit\n /// @param quoteId Unique quote identifier used for tracking the quote\n /// @param callValue ETH value to send to the recipient (if any)\n /// @param callParams Parameters for the arbitrary call to the destination recipient (if any)\n struct BridgeParamsV2 {\n address quoteRelayer;\n int256 quoteExclusivitySeconds;\n bytes quoteId;\n uint256 callValue;\n bytes callParams;\n }\n\n /// @notice Updated bridge transaction struct to include parameters introduced in FastBridgeV2.\n /// Note: only `exclusivityRelayer` can fill such a transaction until `exclusivityEndTime`.\n /// TODO: consider changing the encoding scheme to prevent spending extra gas on decoding.\n struct BridgeTransactionV2 {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n uint256 callValue; // ETH value to send to the recipient (if any) - replaces V1's sendChainGas flag\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n address exclusivityRelayer;\n uint256 exclusivityEndTime;\n bytes callParams;\n }\n\n event BridgeQuoteDetails(bytes32 indexed transactionId, bytes quoteId);\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability\n /// to provide temporary exclusivity fill rights for the quote relayer.\n /// @param params The parameters required to bridge\n /// @param paramsV2 The parameters for exclusivity fill rights (optional, can be left empty)\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function relay(bytes memory request, address relayer) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param transactionId The transaction id associated with the encoded bridge transaction to prove\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital.\n /// @notice Can only send funds to the relayer address on the proof.\n /// @param request The encoded bridge transaction to claim on origin chain\n function claim(bytes memory request) external;\n /// @notice Checks if a transaction has been relayed\n /// @param transactionId The ID of the transaction to check\n /// @return True if the transaction has been relayed, false otherwise\n function bridgeRelays(bytes32 transactionId) external view returns (bool);\n\n /// @notice Returns the status of a bridge transaction\n /// @param transactionId The ID of the bridge transaction\n /// @return BridgeStatus Status of the bridge transaction\n function bridgeStatuses(bytes32 transactionId) external view returns (BridgeStatus);\n\n /// @notice Returns the timestamp and relayer of a bridge proof\n /// @param transactionId The ID of the bridge transaction\n /// @return timestamp The timestamp of the bridge proof\n /// @return relayer The relayer address of the bridge proof\n function bridgeProofs(bytes32 transactionId) external view returns (uint96 timestamp, address relayer);\n\n /// @notice Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\n /// @param request The bridge request to decode\n function getBridgeTransactionV2(bytes memory request) external view returns (BridgeTransactionV2 memory);\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// contracts/libs/UniversalToken.sol\n\nlibrary UniversalTokenLib {\n using SafeERC20 for IERC20;\n\n address internal constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Transfers tokens to the given account. Reverts if transfer is not successful.\n /// @dev This might trigger fallback, if ETH is transferred to the contract.\n /// Make sure this can not lead to reentrancy attacks.\n function universalTransfer(address token, address to, uint256 value) internal {\n // Don't do anything, if need to send tokens to this address\n if (to == address(this)) return;\n // Don't do anything, if trying to send zero value\n if (value == 0) return;\n if (token == ETH_ADDRESS) {\n /// @dev Note: this can potentially lead to executing code in `to`.\n // solhint-disable-next-line avoid-low-level-calls\n (bool success,) = to.call{value: value}(\"\");\n require(success, \"ETH transfer failed\");\n } else {\n IERC20(token).safeTransfer(to, value);\n }\n }\n\n /// @notice Issues an infinite allowance to the spender, if the current allowance is insufficient\n /// to spend the given amount.\n function universalApproveInfinity(address token, address spender, uint256 amountToSpend) internal {\n // ETH Chad doesn't require your approval\n if (token == ETH_ADDRESS) return;\n // No-op if allowance is already sufficient\n uint256 allowance = IERC20(token).allowance(address(this), spender);\n if (allowance \u003e= amountToSpend) return;\n // Otherwise, reset approval to 0 and set to max allowance\n if (allowance \u003e 0) IERC20(token).safeDecreaseAllowance(spender, allowance);\n IERC20(token).safeIncreaseAllowance(spender, type(uint256).max);\n }\n\n /// @notice Returns the balance of the given token (or native ETH) for the given account.\n function universalBalanceOf(address token, address account) internal view returns (uint256) {\n if (token == ETH_ADDRESS) {\n return account.balance;\n } else {\n return IERC20(token).balanceOf(account);\n }\n }\n\n /// @dev Checks that token is a contract and not ETH_ADDRESS.\n function assertIsContract(address token) internal view {\n // Check that ETH_ADDRESS was not used (in case this is a predeploy on any of the chains)\n if (token == UniversalTokenLib.ETH_ADDRESS) revert TokenNotContract();\n // Check that token is not an EOA\n if (token.code.length == 0) revert TokenNotContract();\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/Admin.sol\n\ncontract Admin is IAdmin, AccessControlEnumerable {\n using UniversalTokenLib for address;\n\n bytes32 public constant RELAYER_ROLE = keccak256(\"RELAYER_ROLE\");\n bytes32 public constant REFUNDER_ROLE = keccak256(\"REFUNDER_ROLE\");\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n uint256 public constant FEE_BPS = 1e6;\n uint256 public constant FEE_RATE_MAX = 0.01e6; // max 1% on origin amount\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Chain gas amount to forward as rebate if requested\n uint256 public chainGasAmount;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n }\n\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n require(newFeeRate \u003c= FEE_RATE_MAX, \"newFeeRate \u003e max\");\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n token.universalTransfer(recipient, feeAmount);\n emit FeesSwept(token, recipient, feeAmount);\n }\n\n function setChainGasAmount(uint256 newChainGasAmount) external onlyRole(GOVERNOR_ROLE) {\n uint256 oldChainGasAmount = chainGasAmount;\n chainGasAmount = newChainGasAmount;\n emit ChainGasAmountUpdated(oldChainGasAmount, newChainGasAmount);\n }\n}\n\n// contracts/FastBridgeV2.sol\n\n/// @notice FastBridgeV2 is a contract for bridging tokens across chains.\ncontract FastBridgeV2 is Admin, IFastBridgeV2, IFastBridgeV2Errors {\n using SafeERC20 for IERC20;\n using UniversalTokenLib for address;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Delay for a transaction after which it could be permisionlessly refunded\n uint256 public constant REFUND_DELAY = 7 days;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n /// @notice Maximum length of accepted callParams\n uint256 public constant MAX_CALL_PARAMS_LENGTH = 2 ** 16 - 1;\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeTxDetails) public bridgeTxDetails;\n /// @notice Relay details on destination chain\n mapping(bytes32 =\u003e BridgeRelay) public bridgeRelayDetails;\n /// @notice Unique bridge nonces tracked per originSender\n mapping(address =\u003e uint256) public senderNonces;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Replaced by senderNonces\n uint256 public immutable nonce = 0;\n /// @notice the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n bridge({\n params: params,\n paramsV2: BridgeParamsV2({\n quoteRelayer: address(0),\n quoteExclusivitySeconds: 0,\n quoteId: bytes(\"\"),\n callValue: 0,\n callParams: bytes(\"\")\n })\n });\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes memory request) external payable {\n relay({request: request, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes memory request, bytes32 destTxHash) external {\n prove({transactionId: keccak256(request), destTxHash: destTxHash, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridgeV2\n function claim(bytes memory request) external {\n claim({request: request, to: address(0)});\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003e DISPUTE_PERIOD) {\n revert DisputePeriodPassed();\n }\n\n // @dev relayer gets slashed effectively if dest relay has gone thru\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n bridgeTxDetails[transactionId].proofRelayer = address(0);\n bridgeTxDetails[transactionId].proofBlockTimestamp = 0;\n bridgeTxDetails[transactionId].proofBlockNumber = 0;\n\n emit BridgeProofDisputed(transactionId, msg.sender);\n }\n\n /// @inheritdoc IFastBridge\n function refund(bytes memory request) external {\n bytes32 transactionId = keccak256(request);\n\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n\n if (bridgeTxDetails[transactionId].status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n\n if (hasRole(REFUNDER_ROLE, msg.sender)) {\n // Refunder can refund if deadline has passed\n if (block.timestamp \u003c= transaction.deadline) revert DeadlineNotExceeded();\n } else {\n // Permissionless refund is allowed after REFUND_DELAY\n if (block.timestamp \u003c= transaction.deadline + REFUND_DELAY) revert DeadlineNotExceeded();\n }\n\n // if all checks passed, set to REFUNDED status\n bridgeTxDetails[transactionId].status = BridgeStatus.REFUNDED;\n\n // transfer origin collateral back to original sender\n address to = transaction.originSender;\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount + transaction.originFeeAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (bridgeTxDetails[transactionId].proofRelayer != relayer) revert SenderIncorrect();\n return _timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n /// @dev This method is added to achieve backwards compatibility with decoding requests into V1 structs:\n /// - `callValue` is partially reported as a zero/non-zero flag\n /// - `callParams` is ignored\n /// In order to process all kinds of requests use getBridgeTransactionV2 instead.\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory) {\n // Try decoding into V2 struct first. This will revert if V1 struct is passed\n try this.getBridgeTransactionV2(request) returns (BridgeTransactionV2 memory txV2) {\n // Note: we entirely ignore the callParams field, as it was not present in V1\n return BridgeTransaction({\n originChainId: txV2.originChainId,\n destChainId: txV2.destChainId,\n originSender: txV2.originSender,\n destRecipient: txV2.destRecipient,\n originToken: txV2.originToken,\n destToken: txV2.destToken,\n originAmount: txV2.originAmount,\n destAmount: txV2.destAmount,\n originFeeAmount: txV2.originFeeAmount,\n sendChainGas: txV2.callValue != 0,\n deadline: txV2.deadline,\n nonce: txV2.nonce\n });\n } catch {\n // Fallback to V1 struct\n return abi.decode(request, (BridgeTransaction));\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) public payable {\n int256 exclusivityEndTime = int256(block.timestamp) + paramsV2.quoteExclusivitySeconds;\n _validateBridgeParams(params, paramsV2, exclusivityEndTime);\n\n // transfer tokens to bridge contract\n /// @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _pullToken(params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n\n // set status to requested\n bytes memory request = abi.encode(\n BridgeTransactionV2({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n callValue: paramsV2.callValue,\n deadline: params.deadline,\n nonce: senderNonces[params.sender]++, // increment nonce on every bridge\n exclusivityRelayer: paramsV2.quoteRelayer,\n // We checked exclusivityEndTime to be in range (0 .. params.deadline] above, so can safely cast\n exclusivityEndTime: uint256(exclusivityEndTime),\n callParams: paramsV2.callParams\n })\n );\n bytes32 transactionId = keccak256(request);\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n\n emit BridgeRequested({\n transactionId: transactionId,\n sender: params.sender,\n request: request,\n destChainId: params.dstChainId,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n sendChainGas: paramsV2.callValue != 0\n });\n emit BridgeQuoteDetails(transactionId, paramsV2.quoteId);\n }\n\n /// @inheritdoc IFastBridgeV2\n function relay(bytes memory request, address relayer) public payable {\n bytes32 transactionId = keccak256(request);\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n _validateRelayParams(transaction, transactionId, relayer);\n // mark bridge transaction as relayed\n bridgeRelayDetails[transactionId] =\n BridgeRelay({blockNumber: uint48(block.number), blockTimestamp: uint48(block.timestamp), relayer: relayer});\n\n // transfer tokens to recipient on destination chain and do an arbitrary call if requested\n address to = transaction.destRecipient;\n address token = transaction.destToken;\n uint256 amount = transaction.destAmount;\n\n // All state changes have been done at this point, can proceed to the external calls.\n // This follows the checks-effects-interactions pattern to mitigate potential reentrancy attacks.\n if (token == UniversalTokenLib.ETH_ADDRESS) {\n // For ETH non-zero callValue is not allowed\n if (transaction.callValue != 0) revert NativeTokenCallValueNotSupported();\n // Check that the correct msg.value was sent\n if (msg.value != amount) revert MsgValueIncorrect();\n } else {\n // For ERC20s, we check that the correct msg.value was sent\n if (msg.value != transaction.callValue) revert MsgValueIncorrect();\n // We need to transfer the tokens from the Relayer to the recipient first before performing an\n // optional post-transfer arbitrary call.\n IERC20(token).safeTransferFrom(msg.sender, to, amount);\n }\n\n if (transaction.callParams.length != 0) {\n // Arbitrary call requested, perform it while supplying full msg.value to the recipient\n // Note: if token has a fee on transfers, the recipient will have received less than `amount`.\n // This is a very niche edge case and should be handled by the recipient contract.\n _checkedCallRecipient({recipient: to, token: token, amount: amount, callParams: transaction.callParams});\n } else if (msg.value != 0) {\n // No arbitrary call requested, but msg.value was sent. This is either a relay with ETH,\n // or a non-zero callValue request with an ERC20. In both cases, transfer the ETH to the recipient.\n Address.sendValue(payable(to), msg.value);\n }\n\n emit BridgeRelayed({\n transactionId: transactionId,\n relayer: relayer,\n to: to,\n originChainId: transaction.originChainId,\n originToken: transaction.originToken,\n destToken: transaction.destToken,\n originAmount: transaction.originAmount,\n destAmount: transaction.destAmount,\n chainGasAmount: transaction.callValue\n });\n }\n\n /// @inheritdoc IFastBridgeV2\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) public onlyRole(RELAYER_ROLE) {\n // update bridge tx status given proof provided\n if (bridgeTxDetails[transactionId].status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n bridgeTxDetails[transactionId].status = BridgeStatus.RELAYER_PROVED;\n bridgeTxDetails[transactionId].proofBlockTimestamp = uint40(block.timestamp);\n bridgeTxDetails[transactionId].proofBlockNumber = uint48(block.number);\n bridgeTxDetails[transactionId].proofRelayer = relayer;\n\n emit BridgeProofProvided(transactionId, relayer, destTxHash);\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes memory request, address to) public {\n bytes32 transactionId = keccak256(request);\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n\n // update bridge tx status if able to claim origin collateral\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n\n // if \"to\" is zero addr, permissionlessly send funds to proven relayer\n if (to == address(0)) {\n to = bridgeTxDetails[transactionId].proofRelayer;\n } else if (bridgeTxDetails[transactionId].proofRelayer != msg.sender) {\n revert SenderIncorrect();\n }\n\n if (_timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003c= DISPUTE_PERIOD) {\n revert DisputePeriodNotPassed();\n }\n\n bridgeTxDetails[transactionId].status = BridgeStatus.RELAYER_CLAIMED;\n\n // update protocol fees if origin fee amount exists\n if (transaction.originFeeAmount \u003e 0) protocolFees[transaction.originToken] += transaction.originFeeAmount;\n\n // transfer origin collateral less fee to specified address\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositClaimed(transactionId, bridgeTxDetails[transactionId].proofRelayer, to, token, amount);\n }\n\n function bridgeStatuses(bytes32 transactionId) public view returns (BridgeStatus status) {\n return bridgeTxDetails[transactionId].status;\n }\n\n function bridgeProofs(bytes32 transactionId) public view returns (uint96 timestamp, address relayer) {\n timestamp = bridgeTxDetails[transactionId].proofBlockTimestamp;\n relayer = bridgeTxDetails[transactionId].proofRelayer;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeRelays(bytes32 transactionId) public view returns (bool) {\n // has this transactionId been relayed?\n return bridgeRelayDetails[transactionId].relayer != address(0);\n }\n\n /// @inheritdoc IFastBridgeV2\n function getBridgeTransactionV2(bytes memory request) public pure returns (BridgeTransactionV2 memory) {\n return abi.decode(request, (BridgeTransactionV2));\n }\n\n /// @notice Pulls a requested token from the user to this contract.\n function _pullToken(address token, uint256 amount) internal returns (uint256 amountPulled) {\n if (token == UniversalTokenLib.ETH_ADDRESS) {\n // For ETH we just need to check that the supplied msg.value is correct\n if (amount != msg.value) revert MsgValueIncorrect();\n amountPulled = msg.value;\n } else {\n token.assertIsContract();\n // Record token balance before transfer\n amountPulled = IERC20(token).balanceOf(address(this));\n // Token needs to be pulled only if msg.value is zero\n // This way user can specify WETH as the origin asset\n IERC20(token).safeTransferFrom(msg.sender, address(this), amount);\n // Use the difference between the recorded balance and the current balance as the amountPulled\n amountPulled = IERC20(token).balanceOf(address(this)) - amountPulled;\n }\n }\n\n /// @notice Calls the Recipient's hook function with the specified callParams and performs\n /// all the necessary checks for the returned value.\n function _checkedCallRecipient(\n address recipient,\n address token,\n uint256 amount,\n bytes memory callParams\n )\n internal\n {\n bytes memory hookData =\n abi.encodeCall(IFastBridgeRecipient.fastBridgeTransferReceived, (token, amount, callParams));\n // This will bubble any revert messages from the hook function\n bytes memory returnData = Address.functionCallWithValue({target: recipient, data: hookData, value: msg.value});\n // Explicit revert if no return data at all\n if (returnData.length == 0) revert RecipientNoReturnValue();\n // Check that exactly a single return value was returned\n if (returnData.length != 32) revert RecipientIncorrectReturnValue();\n // Return value should be abi-encoded hook function selector\n if (bytes32(returnData) != bytes32(IFastBridgeRecipient.fastBridgeTransferReceived.selector)) {\n revert RecipientIncorrectReturnValue();\n }\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint40(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint40).max but\n /// proof.timestamp \u003c type(uint40).max via unchecked statement\n /// @param proofBlockTimestamp The bridge proof block timestamp\n /// @return delta Time delta since proof submitted\n function _timeSince(uint40 proofBlockTimestamp) internal view returns (uint256 delta) {\n unchecked {\n delta = uint40(block.timestamp) - proofBlockTimestamp;\n }\n }\n\n /// @notice Performs all the necessary checks for a bridge to happen.\n /// @dev There's no good way to refactor this function to reduce cyclomatic complexity due to\n /// the number of checks that need to be performed, so we skip the code-complexity rule here.\n // solhint-disable-next-line code-complexity\n function _validateBridgeParams(\n BridgeParams memory params,\n BridgeParamsV2 memory paramsV2,\n int256 exclusivityEndTime\n )\n internal\n view\n {\n // Check V1 (legacy) params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.sender == address(0) || params.to == address(0)) revert ZeroAddress();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n // Check V2 params\n if (paramsV2.callParams.length \u003e MAX_CALL_PARAMS_LENGTH) revert CallParamsLengthAboveMax();\n if (paramsV2.callValue != 0 \u0026\u0026 params.destToken == UniversalTokenLib.ETH_ADDRESS) {\n revert NativeTokenCallValueNotSupported();\n }\n // exclusivityEndTime must be in range (0 .. params.deadline]\n if (exclusivityEndTime \u003c= 0 || exclusivityEndTime \u003e int256(params.deadline)) {\n revert ExclusivityParamsIncorrect();\n }\n }\n\n /// @notice Performs all the necessary checks for a relay to happen.\n function _validateRelayParams(\n BridgeTransactionV2 memory transaction,\n bytes32 transactionId,\n address relayer\n )\n internal\n view\n {\n if (relayer == address(0)) revert ZeroAddress();\n // Check if the transaction has already been relayed\n if (bridgeRelays(transactionId)) revert TransactionRelayed();\n if (transaction.destChainId != uint32(block.chainid)) revert ChainIncorrect();\n // Check the deadline for relay to happen\n if (block.timestamp \u003e transaction.deadline) revert DeadlineExceeded();\n // Check the exclusivity period, if it is still ongoing\n // forgefmt: disable-next-item\n if (\n transaction.exclusivityRelayer != address(0) \u0026\u0026\n transaction.exclusivityRelayer != relayer \u0026\u0026\n block.timestamp \u003c= transaction.exclusivityEndTime\n ) {\n revert ExclusivityPeriodNotPassed();\n }\n }\n}\n","language":"Solidity","languageVersion":"0.8.24","compilerVersion":"0.8.24","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"","srcMapRuntime":"","abiDefinition":[{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"bytes","name":"callParams","type":"bytes"}],"name":"fastBridgeTransferReceived","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"payable","type":"function"}],"userDoc":{"kind":"user","methods":{},"version":1},"developerDoc":{"kind":"dev","methods":{},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"callParams\",\"type\":\"bytes\"}],\"name\":\"fastBridgeTransferReceived\",\"outputs\":[{\"internalType\":\"bytes4\",\"name\":\"\",\"type\":\"bytes4\"}],\"stateMutability\":\"payable\",\"type\":\"function\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeV2.sol\":\"IFastBridgeRecipient\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeV2.sol\":{\"keccak256\":\"0x7cd0f885e80e2bdaa638bc32ae7af7d2e248f99ce4b354c217d0f0f7d7302e0a\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://7ccf28df0bd7b4606986585acd8622ed9b4e81379690061bb66088f0a2270af1\",\"dweb:/ipfs/QmTf7HNdHZkK6vmx8ZgewycQEb72oLD9nPwBpsM5reMstQ\"]}},\"version\":1}"},"hashes":{"fastBridgeTransferReceived(address,uint256,bytes)":"461e0c21"}},"solidity/FastBridgeV2.sol:IFastBridgeV2":{"code":"0x","runtime-code":"0x","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.24 ^0.8.0 ^0.8.20;\n\n// contracts/interfaces/IAdmin.sol\n\ninterface IAdmin {\n // ============ Events ============\n\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n event ChainGasAmountUpdated(uint256 oldChainGasAmount, uint256 newChainGasAmount);\n\n // ============ Methods ============\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n\n function setChainGasAmount(uint256 newChainGasAmount) external;\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IFastBridgeRecipient.sol\n\ninterface IFastBridgeRecipient {\n function fastBridgeTransferReceived(\n address token,\n uint256 amount,\n bytes memory callParams\n )\n external\n payable\n returns (bytes4);\n}\n\n// contracts/interfaces/IFastBridgeV2Errors.sol\n\ninterface IFastBridgeV2Errors {\n error AmountIncorrect();\n error CallParamsLengthAboveMax();\n error ChainIncorrect();\n error ExclusivityParamsIncorrect();\n error MsgValueIncorrect();\n error NativeTokenCallValueNotSupported();\n error SenderIncorrect();\n error StatusIncorrect();\n error ZeroAddress();\n\n error RecipientIncorrectReturnValue();\n error RecipientNoReturnValue();\n\n error DeadlineExceeded();\n error DeadlineNotExceeded();\n error DeadlineTooShort();\n error DisputePeriodNotPassed();\n error DisputePeriodPassed();\n error ExclusivityPeriodNotPassed();\n\n error TransactionRelayed();\n}\n\n// contracts/libs/Errors.sol\n\nerror DeadlineExceeded();\nerror DeadlineNotExceeded();\nerror DeadlineTooShort();\nerror InsufficientOutputAmount();\n\nerror MsgValueIncorrect();\nerror PoolNotFound();\nerror TokenAddressMismatch();\nerror TokenNotContract();\nerror TokenNotETH();\nerror TokensIdentical();\n\nerror ChainIncorrect();\nerror AmountIncorrect();\nerror ZeroAddress();\n\nerror DisputePeriodNotPassed();\nerror DisputePeriodPassed();\nerror SenderIncorrect();\nerror StatusIncorrect();\nerror TransactionIdIncorrect();\nerror TransactionRelayed();\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// contracts/interfaces/IFastBridgeV2.sol\n\ninterface IFastBridgeV2 is IFastBridge {\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n struct BridgeTxDetails {\n BridgeStatus status;\n uint40 proofBlockTimestamp;\n uint48 proofBlockNumber;\n address proofRelayer;\n }\n\n struct BridgeRelay {\n uint48 blockNumber;\n uint48 blockTimestamp;\n address relayer;\n }\n\n /// @notice New params introduced in the FastBridgeV2.\n /// We are passing fields from the older BridgeParams struct outside of this struct\n /// for backwards compatibility.\n /// Note: quoteRelayer and quoteExclusivitySeconds are either both zero (indicating no exclusivity)\n /// or both non-zero (indicating exclusivity for the given period).\n /// Note: callValue \u003e 0 can NOT be used with destToken = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE (ETH_ADDRESS)\n /// @param quoteRelayer Relayer that provided the quote for the transaction\n /// @param quoteExclusivitySeconds Period of time the quote relayer is guaranteed exclusivity after user's deposit\n /// @param quoteId Unique quote identifier used for tracking the quote\n /// @param callValue ETH value to send to the recipient (if any)\n /// @param callParams Parameters for the arbitrary call to the destination recipient (if any)\n struct BridgeParamsV2 {\n address quoteRelayer;\n int256 quoteExclusivitySeconds;\n bytes quoteId;\n uint256 callValue;\n bytes callParams;\n }\n\n /// @notice Updated bridge transaction struct to include parameters introduced in FastBridgeV2.\n /// Note: only `exclusivityRelayer` can fill such a transaction until `exclusivityEndTime`.\n /// TODO: consider changing the encoding scheme to prevent spending extra gas on decoding.\n struct BridgeTransactionV2 {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n uint256 callValue; // ETH value to send to the recipient (if any) - replaces V1's sendChainGas flag\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n address exclusivityRelayer;\n uint256 exclusivityEndTime;\n bytes callParams;\n }\n\n event BridgeQuoteDetails(bytes32 indexed transactionId, bytes quoteId);\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability\n /// to provide temporary exclusivity fill rights for the quote relayer.\n /// @param params The parameters required to bridge\n /// @param paramsV2 The parameters for exclusivity fill rights (optional, can be left empty)\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function relay(bytes memory request, address relayer) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param transactionId The transaction id associated with the encoded bridge transaction to prove\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital.\n /// @notice Can only send funds to the relayer address on the proof.\n /// @param request The encoded bridge transaction to claim on origin chain\n function claim(bytes memory request) external;\n /// @notice Checks if a transaction has been relayed\n /// @param transactionId The ID of the transaction to check\n /// @return True if the transaction has been relayed, false otherwise\n function bridgeRelays(bytes32 transactionId) external view returns (bool);\n\n /// @notice Returns the status of a bridge transaction\n /// @param transactionId The ID of the bridge transaction\n /// @return BridgeStatus Status of the bridge transaction\n function bridgeStatuses(bytes32 transactionId) external view returns (BridgeStatus);\n\n /// @notice Returns the timestamp and relayer of a bridge proof\n /// @param transactionId The ID of the bridge transaction\n /// @return timestamp The timestamp of the bridge proof\n /// @return relayer The relayer address of the bridge proof\n function bridgeProofs(bytes32 transactionId) external view returns (uint96 timestamp, address relayer);\n\n /// @notice Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\n /// @param request The bridge request to decode\n function getBridgeTransactionV2(bytes memory request) external view returns (BridgeTransactionV2 memory);\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// contracts/libs/UniversalToken.sol\n\nlibrary UniversalTokenLib {\n using SafeERC20 for IERC20;\n\n address internal constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Transfers tokens to the given account. Reverts if transfer is not successful.\n /// @dev This might trigger fallback, if ETH is transferred to the contract.\n /// Make sure this can not lead to reentrancy attacks.\n function universalTransfer(address token, address to, uint256 value) internal {\n // Don't do anything, if need to send tokens to this address\n if (to == address(this)) return;\n // Don't do anything, if trying to send zero value\n if (value == 0) return;\n if (token == ETH_ADDRESS) {\n /// @dev Note: this can potentially lead to executing code in `to`.\n // solhint-disable-next-line avoid-low-level-calls\n (bool success,) = to.call{value: value}(\"\");\n require(success, \"ETH transfer failed\");\n } else {\n IERC20(token).safeTransfer(to, value);\n }\n }\n\n /// @notice Issues an infinite allowance to the spender, if the current allowance is insufficient\n /// to spend the given amount.\n function universalApproveInfinity(address token, address spender, uint256 amountToSpend) internal {\n // ETH Chad doesn't require your approval\n if (token == ETH_ADDRESS) return;\n // No-op if allowance is already sufficient\n uint256 allowance = IERC20(token).allowance(address(this), spender);\n if (allowance \u003e= amountToSpend) return;\n // Otherwise, reset approval to 0 and set to max allowance\n if (allowance \u003e 0) IERC20(token).safeDecreaseAllowance(spender, allowance);\n IERC20(token).safeIncreaseAllowance(spender, type(uint256).max);\n }\n\n /// @notice Returns the balance of the given token (or native ETH) for the given account.\n function universalBalanceOf(address token, address account) internal view returns (uint256) {\n if (token == ETH_ADDRESS) {\n return account.balance;\n } else {\n return IERC20(token).balanceOf(account);\n }\n }\n\n /// @dev Checks that token is a contract and not ETH_ADDRESS.\n function assertIsContract(address token) internal view {\n // Check that ETH_ADDRESS was not used (in case this is a predeploy on any of the chains)\n if (token == UniversalTokenLib.ETH_ADDRESS) revert TokenNotContract();\n // Check that token is not an EOA\n if (token.code.length == 0) revert TokenNotContract();\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/Admin.sol\n\ncontract Admin is IAdmin, AccessControlEnumerable {\n using UniversalTokenLib for address;\n\n bytes32 public constant RELAYER_ROLE = keccak256(\"RELAYER_ROLE\");\n bytes32 public constant REFUNDER_ROLE = keccak256(\"REFUNDER_ROLE\");\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n uint256 public constant FEE_BPS = 1e6;\n uint256 public constant FEE_RATE_MAX = 0.01e6; // max 1% on origin amount\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Chain gas amount to forward as rebate if requested\n uint256 public chainGasAmount;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n }\n\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n require(newFeeRate \u003c= FEE_RATE_MAX, \"newFeeRate \u003e max\");\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n token.universalTransfer(recipient, feeAmount);\n emit FeesSwept(token, recipient, feeAmount);\n }\n\n function setChainGasAmount(uint256 newChainGasAmount) external onlyRole(GOVERNOR_ROLE) {\n uint256 oldChainGasAmount = chainGasAmount;\n chainGasAmount = newChainGasAmount;\n emit ChainGasAmountUpdated(oldChainGasAmount, newChainGasAmount);\n }\n}\n\n// contracts/FastBridgeV2.sol\n\n/// @notice FastBridgeV2 is a contract for bridging tokens across chains.\ncontract FastBridgeV2 is Admin, IFastBridgeV2, IFastBridgeV2Errors {\n using SafeERC20 for IERC20;\n using UniversalTokenLib for address;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Delay for a transaction after which it could be permisionlessly refunded\n uint256 public constant REFUND_DELAY = 7 days;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n /// @notice Maximum length of accepted callParams\n uint256 public constant MAX_CALL_PARAMS_LENGTH = 2 ** 16 - 1;\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeTxDetails) public bridgeTxDetails;\n /// @notice Relay details on destination chain\n mapping(bytes32 =\u003e BridgeRelay) public bridgeRelayDetails;\n /// @notice Unique bridge nonces tracked per originSender\n mapping(address =\u003e uint256) public senderNonces;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Replaced by senderNonces\n uint256 public immutable nonce = 0;\n /// @notice the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n bridge({\n params: params,\n paramsV2: BridgeParamsV2({\n quoteRelayer: address(0),\n quoteExclusivitySeconds: 0,\n quoteId: bytes(\"\"),\n callValue: 0,\n callParams: bytes(\"\")\n })\n });\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes memory request) external payable {\n relay({request: request, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes memory request, bytes32 destTxHash) external {\n prove({transactionId: keccak256(request), destTxHash: destTxHash, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridgeV2\n function claim(bytes memory request) external {\n claim({request: request, to: address(0)});\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003e DISPUTE_PERIOD) {\n revert DisputePeriodPassed();\n }\n\n // @dev relayer gets slashed effectively if dest relay has gone thru\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n bridgeTxDetails[transactionId].proofRelayer = address(0);\n bridgeTxDetails[transactionId].proofBlockTimestamp = 0;\n bridgeTxDetails[transactionId].proofBlockNumber = 0;\n\n emit BridgeProofDisputed(transactionId, msg.sender);\n }\n\n /// @inheritdoc IFastBridge\n function refund(bytes memory request) external {\n bytes32 transactionId = keccak256(request);\n\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n\n if (bridgeTxDetails[transactionId].status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n\n if (hasRole(REFUNDER_ROLE, msg.sender)) {\n // Refunder can refund if deadline has passed\n if (block.timestamp \u003c= transaction.deadline) revert DeadlineNotExceeded();\n } else {\n // Permissionless refund is allowed after REFUND_DELAY\n if (block.timestamp \u003c= transaction.deadline + REFUND_DELAY) revert DeadlineNotExceeded();\n }\n\n // if all checks passed, set to REFUNDED status\n bridgeTxDetails[transactionId].status = BridgeStatus.REFUNDED;\n\n // transfer origin collateral back to original sender\n address to = transaction.originSender;\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount + transaction.originFeeAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (bridgeTxDetails[transactionId].proofRelayer != relayer) revert SenderIncorrect();\n return _timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n /// @dev This method is added to achieve backwards compatibility with decoding requests into V1 structs:\n /// - `callValue` is partially reported as a zero/non-zero flag\n /// - `callParams` is ignored\n /// In order to process all kinds of requests use getBridgeTransactionV2 instead.\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory) {\n // Try decoding into V2 struct first. This will revert if V1 struct is passed\n try this.getBridgeTransactionV2(request) returns (BridgeTransactionV2 memory txV2) {\n // Note: we entirely ignore the callParams field, as it was not present in V1\n return BridgeTransaction({\n originChainId: txV2.originChainId,\n destChainId: txV2.destChainId,\n originSender: txV2.originSender,\n destRecipient: txV2.destRecipient,\n originToken: txV2.originToken,\n destToken: txV2.destToken,\n originAmount: txV2.originAmount,\n destAmount: txV2.destAmount,\n originFeeAmount: txV2.originFeeAmount,\n sendChainGas: txV2.callValue != 0,\n deadline: txV2.deadline,\n nonce: txV2.nonce\n });\n } catch {\n // Fallback to V1 struct\n return abi.decode(request, (BridgeTransaction));\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) public payable {\n int256 exclusivityEndTime = int256(block.timestamp) + paramsV2.quoteExclusivitySeconds;\n _validateBridgeParams(params, paramsV2, exclusivityEndTime);\n\n // transfer tokens to bridge contract\n /// @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _pullToken(params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n\n // set status to requested\n bytes memory request = abi.encode(\n BridgeTransactionV2({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n callValue: paramsV2.callValue,\n deadline: params.deadline,\n nonce: senderNonces[params.sender]++, // increment nonce on every bridge\n exclusivityRelayer: paramsV2.quoteRelayer,\n // We checked exclusivityEndTime to be in range (0 .. params.deadline] above, so can safely cast\n exclusivityEndTime: uint256(exclusivityEndTime),\n callParams: paramsV2.callParams\n })\n );\n bytes32 transactionId = keccak256(request);\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n\n emit BridgeRequested({\n transactionId: transactionId,\n sender: params.sender,\n request: request,\n destChainId: params.dstChainId,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n sendChainGas: paramsV2.callValue != 0\n });\n emit BridgeQuoteDetails(transactionId, paramsV2.quoteId);\n }\n\n /// @inheritdoc IFastBridgeV2\n function relay(bytes memory request, address relayer) public payable {\n bytes32 transactionId = keccak256(request);\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n _validateRelayParams(transaction, transactionId, relayer);\n // mark bridge transaction as relayed\n bridgeRelayDetails[transactionId] =\n BridgeRelay({blockNumber: uint48(block.number), blockTimestamp: uint48(block.timestamp), relayer: relayer});\n\n // transfer tokens to recipient on destination chain and do an arbitrary call if requested\n address to = transaction.destRecipient;\n address token = transaction.destToken;\n uint256 amount = transaction.destAmount;\n\n // All state changes have been done at this point, can proceed to the external calls.\n // This follows the checks-effects-interactions pattern to mitigate potential reentrancy attacks.\n if (token == UniversalTokenLib.ETH_ADDRESS) {\n // For ETH non-zero callValue is not allowed\n if (transaction.callValue != 0) revert NativeTokenCallValueNotSupported();\n // Check that the correct msg.value was sent\n if (msg.value != amount) revert MsgValueIncorrect();\n } else {\n // For ERC20s, we check that the correct msg.value was sent\n if (msg.value != transaction.callValue) revert MsgValueIncorrect();\n // We need to transfer the tokens from the Relayer to the recipient first before performing an\n // optional post-transfer arbitrary call.\n IERC20(token).safeTransferFrom(msg.sender, to, amount);\n }\n\n if (transaction.callParams.length != 0) {\n // Arbitrary call requested, perform it while supplying full msg.value to the recipient\n // Note: if token has a fee on transfers, the recipient will have received less than `amount`.\n // This is a very niche edge case and should be handled by the recipient contract.\n _checkedCallRecipient({recipient: to, token: token, amount: amount, callParams: transaction.callParams});\n } else if (msg.value != 0) {\n // No arbitrary call requested, but msg.value was sent. This is either a relay with ETH,\n // or a non-zero callValue request with an ERC20. In both cases, transfer the ETH to the recipient.\n Address.sendValue(payable(to), msg.value);\n }\n\n emit BridgeRelayed({\n transactionId: transactionId,\n relayer: relayer,\n to: to,\n originChainId: transaction.originChainId,\n originToken: transaction.originToken,\n destToken: transaction.destToken,\n originAmount: transaction.originAmount,\n destAmount: transaction.destAmount,\n chainGasAmount: transaction.callValue\n });\n }\n\n /// @inheritdoc IFastBridgeV2\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) public onlyRole(RELAYER_ROLE) {\n // update bridge tx status given proof provided\n if (bridgeTxDetails[transactionId].status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n bridgeTxDetails[transactionId].status = BridgeStatus.RELAYER_PROVED;\n bridgeTxDetails[transactionId].proofBlockTimestamp = uint40(block.timestamp);\n bridgeTxDetails[transactionId].proofBlockNumber = uint48(block.number);\n bridgeTxDetails[transactionId].proofRelayer = relayer;\n\n emit BridgeProofProvided(transactionId, relayer, destTxHash);\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes memory request, address to) public {\n bytes32 transactionId = keccak256(request);\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n\n // update bridge tx status if able to claim origin collateral\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n\n // if \"to\" is zero addr, permissionlessly send funds to proven relayer\n if (to == address(0)) {\n to = bridgeTxDetails[transactionId].proofRelayer;\n } else if (bridgeTxDetails[transactionId].proofRelayer != msg.sender) {\n revert SenderIncorrect();\n }\n\n if (_timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003c= DISPUTE_PERIOD) {\n revert DisputePeriodNotPassed();\n }\n\n bridgeTxDetails[transactionId].status = BridgeStatus.RELAYER_CLAIMED;\n\n // update protocol fees if origin fee amount exists\n if (transaction.originFeeAmount \u003e 0) protocolFees[transaction.originToken] += transaction.originFeeAmount;\n\n // transfer origin collateral less fee to specified address\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositClaimed(transactionId, bridgeTxDetails[transactionId].proofRelayer, to, token, amount);\n }\n\n function bridgeStatuses(bytes32 transactionId) public view returns (BridgeStatus status) {\n return bridgeTxDetails[transactionId].status;\n }\n\n function bridgeProofs(bytes32 transactionId) public view returns (uint96 timestamp, address relayer) {\n timestamp = bridgeTxDetails[transactionId].proofBlockTimestamp;\n relayer = bridgeTxDetails[transactionId].proofRelayer;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeRelays(bytes32 transactionId) public view returns (bool) {\n // has this transactionId been relayed?\n return bridgeRelayDetails[transactionId].relayer != address(0);\n }\n\n /// @inheritdoc IFastBridgeV2\n function getBridgeTransactionV2(bytes memory request) public pure returns (BridgeTransactionV2 memory) {\n return abi.decode(request, (BridgeTransactionV2));\n }\n\n /// @notice Pulls a requested token from the user to this contract.\n function _pullToken(address token, uint256 amount) internal returns (uint256 amountPulled) {\n if (token == UniversalTokenLib.ETH_ADDRESS) {\n // For ETH we just need to check that the supplied msg.value is correct\n if (amount != msg.value) revert MsgValueIncorrect();\n amountPulled = msg.value;\n } else {\n token.assertIsContract();\n // Record token balance before transfer\n amountPulled = IERC20(token).balanceOf(address(this));\n // Token needs to be pulled only if msg.value is zero\n // This way user can specify WETH as the origin asset\n IERC20(token).safeTransferFrom(msg.sender, address(this), amount);\n // Use the difference between the recorded balance and the current balance as the amountPulled\n amountPulled = IERC20(token).balanceOf(address(this)) - amountPulled;\n }\n }\n\n /// @notice Calls the Recipient's hook function with the specified callParams and performs\n /// all the necessary checks for the returned value.\n function _checkedCallRecipient(\n address recipient,\n address token,\n uint256 amount,\n bytes memory callParams\n )\n internal\n {\n bytes memory hookData =\n abi.encodeCall(IFastBridgeRecipient.fastBridgeTransferReceived, (token, amount, callParams));\n // This will bubble any revert messages from the hook function\n bytes memory returnData = Address.functionCallWithValue({target: recipient, data: hookData, value: msg.value});\n // Explicit revert if no return data at all\n if (returnData.length == 0) revert RecipientNoReturnValue();\n // Check that exactly a single return value was returned\n if (returnData.length != 32) revert RecipientIncorrectReturnValue();\n // Return value should be abi-encoded hook function selector\n if (bytes32(returnData) != bytes32(IFastBridgeRecipient.fastBridgeTransferReceived.selector)) {\n revert RecipientIncorrectReturnValue();\n }\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint40(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint40).max but\n /// proof.timestamp \u003c type(uint40).max via unchecked statement\n /// @param proofBlockTimestamp The bridge proof block timestamp\n /// @return delta Time delta since proof submitted\n function _timeSince(uint40 proofBlockTimestamp) internal view returns (uint256 delta) {\n unchecked {\n delta = uint40(block.timestamp) - proofBlockTimestamp;\n }\n }\n\n /// @notice Performs all the necessary checks for a bridge to happen.\n /// @dev There's no good way to refactor this function to reduce cyclomatic complexity due to\n /// the number of checks that need to be performed, so we skip the code-complexity rule here.\n // solhint-disable-next-line code-complexity\n function _validateBridgeParams(\n BridgeParams memory params,\n BridgeParamsV2 memory paramsV2,\n int256 exclusivityEndTime\n )\n internal\n view\n {\n // Check V1 (legacy) params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.sender == address(0) || params.to == address(0)) revert ZeroAddress();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n // Check V2 params\n if (paramsV2.callParams.length \u003e MAX_CALL_PARAMS_LENGTH) revert CallParamsLengthAboveMax();\n if (paramsV2.callValue != 0 \u0026\u0026 params.destToken == UniversalTokenLib.ETH_ADDRESS) {\n revert NativeTokenCallValueNotSupported();\n }\n // exclusivityEndTime must be in range (0 .. params.deadline]\n if (exclusivityEndTime \u003c= 0 || exclusivityEndTime \u003e int256(params.deadline)) {\n revert ExclusivityParamsIncorrect();\n }\n }\n\n /// @notice Performs all the necessary checks for a relay to happen.\n function _validateRelayParams(\n BridgeTransactionV2 memory transaction,\n bytes32 transactionId,\n address relayer\n )\n internal\n view\n {\n if (relayer == address(0)) revert ZeroAddress();\n // Check if the transaction has already been relayed\n if (bridgeRelays(transactionId)) revert TransactionRelayed();\n if (transaction.destChainId != uint32(block.chainid)) revert ChainIncorrect();\n // Check the deadline for relay to happen\n if (block.timestamp \u003e transaction.deadline) revert DeadlineExceeded();\n // Check the exclusivity period, if it is still ongoing\n // forgefmt: disable-next-item\n if (\n transaction.exclusivityRelayer != address(0) \u0026\u0026\n transaction.exclusivityRelayer != relayer \u0026\u0026\n block.timestamp \u003c= transaction.exclusivityEndTime\n ) {\n revert ExclusivityPeriodNotPassed();\n }\n }\n}\n","language":"Solidity","languageVersion":"0.8.24","compilerVersion":"0.8.24","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"","srcMapRuntime":"","abiDefinition":[{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"relayer","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"BridgeDepositClaimed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"BridgeDepositRefunded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"relayer","type":"address"}],"name":"BridgeProofDisputed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"relayer","type":"address"},{"indexed":false,"internalType":"bytes32","name":"transactionHash","type":"bytes32"}],"name":"BridgeProofProvided","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":false,"internalType":"bytes","name":"quoteId","type":"bytes"}],"name":"BridgeQuoteDetails","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"relayer","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint32","name":"originChainId","type":"uint32"},{"indexed":false,"internalType":"address","name":"originToken","type":"address"},{"indexed":false,"internalType":"address","name":"destToken","type":"address"},{"indexed":false,"internalType":"uint256","name":"originAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"destAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"chainGasAmount","type":"uint256"}],"name":"BridgeRelayed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"bytes","name":"request","type":"bytes"},{"indexed":false,"internalType":"uint32","name":"destChainId","type":"uint32"},{"indexed":false,"internalType":"address","name":"originToken","type":"address"},{"indexed":false,"internalType":"address","name":"destToken","type":"address"},{"indexed":false,"internalType":"uint256","name":"originAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"destAmount","type":"uint256"},{"indexed":false,"internalType":"bool","name":"sendChainGas","type":"bool"}],"name":"BridgeRequested","type":"event"},{"inputs":[{"components":[{"internalType":"uint32","name":"dstChainId","type":"uint32"},{"internalType":"address","name":"sender","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"address","name":"originToken","type":"address"},{"internalType":"address","name":"destToken","type":"address"},{"internalType":"uint256","name":"originAmount","type":"uint256"},{"internalType":"uint256","name":"destAmount","type":"uint256"},{"internalType":"bool","name":"sendChainGas","type":"bool"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"internalType":"struct IFastBridge.BridgeParams","name":"params","type":"tuple"}],"name":"bridge","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"uint32","name":"dstChainId","type":"uint32"},{"internalType":"address","name":"sender","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"address","name":"originToken","type":"address"},{"internalType":"address","name":"destToken","type":"address"},{"internalType":"uint256","name":"originAmount","type":"uint256"},{"internalType":"uint256","name":"destAmount","type":"uint256"},{"internalType":"bool","name":"sendChainGas","type":"bool"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"internalType":"struct IFastBridge.BridgeParams","name":"params","type":"tuple"},{"components":[{"internalType":"address","name":"quoteRelayer","type":"address"},{"internalType":"int256","name":"quoteExclusivitySeconds","type":"int256"},{"internalType":"bytes","name":"quoteId","type":"bytes"},{"internalType":"uint256","name":"callValue","type":"uint256"},{"internalType":"bytes","name":"callParams","type":"bytes"}],"internalType":"struct IFastBridgeV2.BridgeParamsV2","name":"paramsV2","type":"tuple"}],"name":"bridge","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"transactionId","type":"bytes32"}],"name":"bridgeProofs","outputs":[{"internalType":"uint96","name":"timestamp","type":"uint96"},{"internalType":"address","name":"relayer","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"transactionId","type":"bytes32"}],"name":"bridgeRelays","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"transactionId","type":"bytes32"}],"name":"bridgeStatuses","outputs":[{"internalType":"enum IFastBridgeV2.BridgeStatus","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"internalType":"address","name":"relayer","type":"address"}],"name":"canClaim","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"},{"internalType":"address","name":"to","type":"address"}],"name":"claim","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"}],"name":"claim","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"transactionId","type":"bytes32"}],"name":"dispute","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"}],"name":"getBridgeTransaction","outputs":[{"components":[{"internalType":"uint32","name":"originChainId","type":"uint32"},{"internalType":"uint32","name":"destChainId","type":"uint32"},{"internalType":"address","name":"originSender","type":"address"},{"internalType":"address","name":"destRecipient","type":"address"},{"internalType":"address","name":"originToken","type":"address"},{"internalType":"address","name":"destToken","type":"address"},{"internalType":"uint256","name":"originAmount","type":"uint256"},{"internalType":"uint256","name":"destAmount","type":"uint256"},{"internalType":"uint256","name":"originFeeAmount","type":"uint256"},{"internalType":"bool","name":"sendChainGas","type":"bool"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint256","name":"nonce","type":"uint256"}],"internalType":"struct IFastBridge.BridgeTransaction","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"}],"name":"getBridgeTransactionV2","outputs":[{"components":[{"internalType":"uint32","name":"originChainId","type":"uint32"},{"internalType":"uint32","name":"destChainId","type":"uint32"},{"internalType":"address","name":"originSender","type":"address"},{"internalType":"address","name":"destRecipient","type":"address"},{"internalType":"address","name":"originToken","type":"address"},{"internalType":"address","name":"destToken","type":"address"},{"internalType":"uint256","name":"originAmount","type":"uint256"},{"internalType":"uint256","name":"destAmount","type":"uint256"},{"internalType":"uint256","name":"originFeeAmount","type":"uint256"},{"internalType":"uint256","name":"callValue","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"address","name":"exclusivityRelayer","type":"address"},{"internalType":"uint256","name":"exclusivityEndTime","type":"uint256"},{"internalType":"bytes","name":"callParams","type":"bytes"}],"internalType":"struct IFastBridgeV2.BridgeTransactionV2","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"internalType":"bytes32","name":"destTxHash","type":"bytes32"},{"internalType":"address","name":"relayer","type":"address"}],"name":"prove","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"},{"internalType":"bytes32","name":"destTxHash","type":"bytes32"}],"name":"prove","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"}],"name":"refund","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"}],"name":"relay","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"},{"internalType":"address","name":"relayer","type":"address"}],"name":"relay","outputs":[],"stateMutability":"payable","type":"function"}],"userDoc":{"kind":"user","methods":{"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256))":{"notice":"Initiates bridge on origin chain to be relayed by off-chain relayer"},"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256),(address,int256,bytes,uint256,bytes))":{"notice":"Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability to provide temporary exclusivity fill rights for the quote relayer."},"bridgeProofs(bytes32)":{"notice":"Returns the timestamp and relayer of a bridge proof"},"bridgeRelays(bytes32)":{"notice":"Checks if a transaction has been relayed"},"bridgeStatuses(bytes32)":{"notice":"Returns the status of a bridge transaction"},"canClaim(bytes32,address)":{"notice":"Checks if the dispute period has passed so bridge deposit can be claimed"},"claim(bytes)":{"notice":"Completes bridge transaction on origin chain by claiming originally deposited capital.Can only send funds to the relayer address on the proof."},"claim(bytes,address)":{"notice":"Completes bridge transaction on origin chain by claiming originally deposited capital"},"dispute(bytes32)":{"notice":"Disputes an outstanding proof in case relayer provided dest chain tx is invalid"},"getBridgeTransaction(bytes)":{"notice":"Decodes bridge request into a bridge transaction"},"getBridgeTransactionV2(bytes)":{"notice":"Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2"},"prove(bytes,bytes32)":{"notice":"Provides proof on origin side that relayer provided funds on destination side of bridge transaction"},"prove(bytes32,bytes32,address)":{"notice":"Provides proof on origin side that relayer provided funds on destination side of bridge transaction"},"refund(bytes)":{"notice":"Refunds an outstanding bridge transaction in case optimistic bridging failed"},"relay(bytes)":{"notice":"Relays destination side of bridge transaction by off-chain relayer"},"relay(bytes,address)":{"notice":"Relays destination side of bridge transaction by off-chain relayer"}},"version":1},"developerDoc":{"kind":"dev","methods":{"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256))":{"params":{"params":"The parameters required to bridge"}},"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256),(address,int256,bytes,uint256,bytes))":{"params":{"params":"The parameters required to bridge","paramsV2":"The parameters for exclusivity fill rights (optional, can be left empty)"}},"bridgeProofs(bytes32)":{"params":{"transactionId":"The ID of the bridge transaction"},"returns":{"relayer":"The relayer address of the bridge proof","timestamp":"The timestamp of the bridge proof"}},"bridgeRelays(bytes32)":{"params":{"transactionId":"The ID of the transaction to check"},"returns":{"_0":"True if the transaction has been relayed, false otherwise"}},"bridgeStatuses(bytes32)":{"params":{"transactionId":"The ID of the bridge transaction"},"returns":{"_0":"BridgeStatus Status of the bridge transaction"}},"canClaim(bytes32,address)":{"params":{"relayer":"The address of the relayer attempting to claim","transactionId":"The transaction id associated with the encoded bridge transaction to check"}},"claim(bytes)":{"params":{"request":"The encoded bridge transaction to claim on origin chain"}},"claim(bytes,address)":{"params":{"request":"The encoded bridge transaction to claim on origin chain","to":"The recipient address of the funds"}},"dispute(bytes32)":{"params":{"transactionId":"The transaction id associated with the encoded bridge transaction to dispute"}},"getBridgeTransaction(bytes)":{"params":{"request":"The bridge request to decode"}},"getBridgeTransactionV2(bytes)":{"params":{"request":"The bridge request to decode"}},"prove(bytes,bytes32)":{"params":{"destTxHash":"The destination tx hash proving bridge transaction was relayed","request":"The encoded bridge transaction to prove on origin chain"}},"prove(bytes32,bytes32,address)":{"params":{"destTxHash":"The destination tx hash proving bridge transaction was relayed","relayer":"The address of the relaying entity which should have control of the origin funds when claimed","transactionId":"The transaction id associated with the encoded bridge transaction to prove"}},"refund(bytes)":{"params":{"request":"The encoded bridge transaction to refund"}},"relay(bytes)":{"params":{"request":"The encoded bridge transaction to relay on destination chain"}},"relay(bytes,address)":{"params":{"relayer":"The address of the relaying entity which should have control of the origin funds when claimed","request":"The encoded bridge transaction to relay on destination chain"}}},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"BridgeDepositClaimed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"BridgeDepositRefunded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"name\":\"BridgeProofDisputed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"transactionHash\",\"type\":\"bytes32\"}],\"name\":\"BridgeProofProvided\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"quoteId\",\"type\":\"bytes\"}],\"name\":\"BridgeQuoteDetails\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"originChainId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"chainGasAmount\",\"type\":\"uint256\"}],\"name\":\"BridgeRelayed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"destChainId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"sendChainGas\",\"type\":\"bool\"}],\"name\":\"BridgeRequested\",\"type\":\"event\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"dstChainId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"sendChainGas\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"}],\"internalType\":\"struct IFastBridge.BridgeParams\",\"name\":\"params\",\"type\":\"tuple\"}],\"name\":\"bridge\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"dstChainId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"sendChainGas\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"}],\"internalType\":\"struct IFastBridge.BridgeParams\",\"name\":\"params\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"quoteRelayer\",\"type\":\"address\"},{\"internalType\":\"int256\",\"name\":\"quoteExclusivitySeconds\",\"type\":\"int256\"},{\"internalType\":\"bytes\",\"name\":\"quoteId\",\"type\":\"bytes\"},{\"internalType\":\"uint256\",\"name\":\"callValue\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"callParams\",\"type\":\"bytes\"}],\"internalType\":\"struct IFastBridgeV2.BridgeParamsV2\",\"name\":\"paramsV2\",\"type\":\"tuple\"}],\"name\":\"bridge\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"}],\"name\":\"bridgeProofs\",\"outputs\":[{\"internalType\":\"uint96\",\"name\":\"timestamp\",\"type\":\"uint96\"},{\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"}],\"name\":\"bridgeRelays\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"}],\"name\":\"bridgeStatuses\",\"outputs\":[{\"internalType\":\"enum IFastBridgeV2.BridgeStatus\",\"name\":\"\",\"type\":\"uint8\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"name\":\"canClaim\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"claim\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"claim\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"}],\"name\":\"dispute\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"getBridgeTransaction\",\"outputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"originChainId\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"destChainId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"originSender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destRecipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"originFeeAmount\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"sendChainGas\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"}],\"internalType\":\"struct IFastBridge.BridgeTransaction\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"getBridgeTransactionV2\",\"outputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"originChainId\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"destChainId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"originSender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destRecipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"originFeeAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"callValue\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"exclusivityRelayer\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"exclusivityEndTime\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"callParams\",\"type\":\"bytes\"}],\"internalType\":\"struct IFastBridgeV2.BridgeTransactionV2\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"destTxHash\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"name\":\"prove\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"},{\"internalType\":\"bytes32\",\"name\":\"destTxHash\",\"type\":\"bytes32\"}],\"name\":\"prove\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"refund\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"relay\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"},{\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"name\":\"relay\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{\"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256))\":{\"params\":{\"params\":\"The parameters required to bridge\"}},\"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256),(address,int256,bytes,uint256,bytes))\":{\"params\":{\"params\":\"The parameters required to bridge\",\"paramsV2\":\"The parameters for exclusivity fill rights (optional, can be left empty)\"}},\"bridgeProofs(bytes32)\":{\"params\":{\"transactionId\":\"The ID of the bridge transaction\"},\"returns\":{\"relayer\":\"The relayer address of the bridge proof\",\"timestamp\":\"The timestamp of the bridge proof\"}},\"bridgeRelays(bytes32)\":{\"params\":{\"transactionId\":\"The ID of the transaction to check\"},\"returns\":{\"_0\":\"True if the transaction has been relayed, false otherwise\"}},\"bridgeStatuses(bytes32)\":{\"params\":{\"transactionId\":\"The ID of the bridge transaction\"},\"returns\":{\"_0\":\"BridgeStatus Status of the bridge transaction\"}},\"canClaim(bytes32,address)\":{\"params\":{\"relayer\":\"The address of the relayer attempting to claim\",\"transactionId\":\"The transaction id associated with the encoded bridge transaction to check\"}},\"claim(bytes)\":{\"params\":{\"request\":\"The encoded bridge transaction to claim on origin chain\"}},\"claim(bytes,address)\":{\"params\":{\"request\":\"The encoded bridge transaction to claim on origin chain\",\"to\":\"The recipient address of the funds\"}},\"dispute(bytes32)\":{\"params\":{\"transactionId\":\"The transaction id associated with the encoded bridge transaction to dispute\"}},\"getBridgeTransaction(bytes)\":{\"params\":{\"request\":\"The bridge request to decode\"}},\"getBridgeTransactionV2(bytes)\":{\"params\":{\"request\":\"The bridge request to decode\"}},\"prove(bytes,bytes32)\":{\"params\":{\"destTxHash\":\"The destination tx hash proving bridge transaction was relayed\",\"request\":\"The encoded bridge transaction to prove on origin chain\"}},\"prove(bytes32,bytes32,address)\":{\"params\":{\"destTxHash\":\"The destination tx hash proving bridge transaction was relayed\",\"relayer\":\"The address of the relaying entity which should have control of the origin funds when claimed\",\"transactionId\":\"The transaction id associated with the encoded bridge transaction to prove\"}},\"refund(bytes)\":{\"params\":{\"request\":\"The encoded bridge transaction to refund\"}},\"relay(bytes)\":{\"params\":{\"request\":\"The encoded bridge transaction to relay on destination chain\"}},\"relay(bytes,address)\":{\"params\":{\"relayer\":\"The address of the relaying entity which should have control of the origin funds when claimed\",\"request\":\"The encoded bridge transaction to relay on destination chain\"}}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256))\":{\"notice\":\"Initiates bridge on origin chain to be relayed by off-chain relayer\"},\"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256),(address,int256,bytes,uint256,bytes))\":{\"notice\":\"Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability to provide temporary exclusivity fill rights for the quote relayer.\"},\"bridgeProofs(bytes32)\":{\"notice\":\"Returns the timestamp and relayer of a bridge proof\"},\"bridgeRelays(bytes32)\":{\"notice\":\"Checks if a transaction has been relayed\"},\"bridgeStatuses(bytes32)\":{\"notice\":\"Returns the status of a bridge transaction\"},\"canClaim(bytes32,address)\":{\"notice\":\"Checks if the dispute period has passed so bridge deposit can be claimed\"},\"claim(bytes)\":{\"notice\":\"Completes bridge transaction on origin chain by claiming originally deposited capital.Can only send funds to the relayer address on the proof.\"},\"claim(bytes,address)\":{\"notice\":\"Completes bridge transaction on origin chain by claiming originally deposited capital\"},\"dispute(bytes32)\":{\"notice\":\"Disputes an outstanding proof in case relayer provided dest chain tx is invalid\"},\"getBridgeTransaction(bytes)\":{\"notice\":\"Decodes bridge request into a bridge transaction\"},\"getBridgeTransactionV2(bytes)\":{\"notice\":\"Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\"},\"prove(bytes,bytes32)\":{\"notice\":\"Provides proof on origin side that relayer provided funds on destination side of bridge transaction\"},\"prove(bytes32,bytes32,address)\":{\"notice\":\"Provides proof on origin side that relayer provided funds on destination side of bridge transaction\"},\"refund(bytes)\":{\"notice\":\"Refunds an outstanding bridge transaction in case optimistic bridging failed\"},\"relay(bytes)\":{\"notice\":\"Relays destination side of bridge transaction by off-chain relayer\"},\"relay(bytes,address)\":{\"notice\":\"Relays destination side of bridge transaction by off-chain relayer\"}},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeV2.sol\":\"IFastBridgeV2\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeV2.sol\":{\"keccak256\":\"0x7cd0f885e80e2bdaa638bc32ae7af7d2e248f99ce4b354c217d0f0f7d7302e0a\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://7ccf28df0bd7b4606986585acd8622ed9b4e81379690061bb66088f0a2270af1\",\"dweb:/ipfs/QmTf7HNdHZkK6vmx8ZgewycQEb72oLD9nPwBpsM5reMstQ\"]}},\"version\":1}"},"hashes":{"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256))":"45851694","bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256),(address,int256,bytes,uint256,bytes))":"bfc7c607","bridgeProofs(bytes32)":"91ad5039","bridgeRelays(bytes32)":"8379a24f","bridgeStatuses(bytes32)":"051287bc","canClaim(bytes32,address)":"aa9641ab","claim(bytes)":"c63ff8dd","claim(bytes,address)":"41fcb612","dispute(bytes32)":"add98c70","getBridgeTransaction(bytes)":"ac11fb1a","getBridgeTransactionV2(bytes)":"5aa6ccba","prove(bytes,bytes32)":"886d36ff","prove(bytes32,bytes32,address)":"18e4357d","refund(bytes)":"5eb7d946","relay(bytes)":"8f0d6f17","relay(bytes,address)":"9c9545f0"}},"solidity/FastBridgeV2.sol:IFastBridgeV2Errors":{"code":"0x","runtime-code":"0x","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.24 ^0.8.0 ^0.8.20;\n\n// contracts/interfaces/IAdmin.sol\n\ninterface IAdmin {\n // ============ Events ============\n\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n event ChainGasAmountUpdated(uint256 oldChainGasAmount, uint256 newChainGasAmount);\n\n // ============ Methods ============\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n\n function setChainGasAmount(uint256 newChainGasAmount) external;\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IFastBridgeRecipient.sol\n\ninterface IFastBridgeRecipient {\n function fastBridgeTransferReceived(\n address token,\n uint256 amount,\n bytes memory callParams\n )\n external\n payable\n returns (bytes4);\n}\n\n// contracts/interfaces/IFastBridgeV2Errors.sol\n\ninterface IFastBridgeV2Errors {\n error AmountIncorrect();\n error CallParamsLengthAboveMax();\n error ChainIncorrect();\n error ExclusivityParamsIncorrect();\n error MsgValueIncorrect();\n error NativeTokenCallValueNotSupported();\n error SenderIncorrect();\n error StatusIncorrect();\n error ZeroAddress();\n\n error RecipientIncorrectReturnValue();\n error RecipientNoReturnValue();\n\n error DeadlineExceeded();\n error DeadlineNotExceeded();\n error DeadlineTooShort();\n error DisputePeriodNotPassed();\n error DisputePeriodPassed();\n error ExclusivityPeriodNotPassed();\n\n error TransactionRelayed();\n}\n\n// contracts/libs/Errors.sol\n\nerror DeadlineExceeded();\nerror DeadlineNotExceeded();\nerror DeadlineTooShort();\nerror InsufficientOutputAmount();\n\nerror MsgValueIncorrect();\nerror PoolNotFound();\nerror TokenAddressMismatch();\nerror TokenNotContract();\nerror TokenNotETH();\nerror TokensIdentical();\n\nerror ChainIncorrect();\nerror AmountIncorrect();\nerror ZeroAddress();\n\nerror DisputePeriodNotPassed();\nerror DisputePeriodPassed();\nerror SenderIncorrect();\nerror StatusIncorrect();\nerror TransactionIdIncorrect();\nerror TransactionRelayed();\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// contracts/interfaces/IFastBridgeV2.sol\n\ninterface IFastBridgeV2 is IFastBridge {\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n struct BridgeTxDetails {\n BridgeStatus status;\n uint40 proofBlockTimestamp;\n uint48 proofBlockNumber;\n address proofRelayer;\n }\n\n struct BridgeRelay {\n uint48 blockNumber;\n uint48 blockTimestamp;\n address relayer;\n }\n\n /// @notice New params introduced in the FastBridgeV2.\n /// We are passing fields from the older BridgeParams struct outside of this struct\n /// for backwards compatibility.\n /// Note: quoteRelayer and quoteExclusivitySeconds are either both zero (indicating no exclusivity)\n /// or both non-zero (indicating exclusivity for the given period).\n /// Note: callValue \u003e 0 can NOT be used with destToken = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE (ETH_ADDRESS)\n /// @param quoteRelayer Relayer that provided the quote for the transaction\n /// @param quoteExclusivitySeconds Period of time the quote relayer is guaranteed exclusivity after user's deposit\n /// @param quoteId Unique quote identifier used for tracking the quote\n /// @param callValue ETH value to send to the recipient (if any)\n /// @param callParams Parameters for the arbitrary call to the destination recipient (if any)\n struct BridgeParamsV2 {\n address quoteRelayer;\n int256 quoteExclusivitySeconds;\n bytes quoteId;\n uint256 callValue;\n bytes callParams;\n }\n\n /// @notice Updated bridge transaction struct to include parameters introduced in FastBridgeV2.\n /// Note: only `exclusivityRelayer` can fill such a transaction until `exclusivityEndTime`.\n /// TODO: consider changing the encoding scheme to prevent spending extra gas on decoding.\n struct BridgeTransactionV2 {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n uint256 callValue; // ETH value to send to the recipient (if any) - replaces V1's sendChainGas flag\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n address exclusivityRelayer;\n uint256 exclusivityEndTime;\n bytes callParams;\n }\n\n event BridgeQuoteDetails(bytes32 indexed transactionId, bytes quoteId);\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability\n /// to provide temporary exclusivity fill rights for the quote relayer.\n /// @param params The parameters required to bridge\n /// @param paramsV2 The parameters for exclusivity fill rights (optional, can be left empty)\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function relay(bytes memory request, address relayer) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param transactionId The transaction id associated with the encoded bridge transaction to prove\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital.\n /// @notice Can only send funds to the relayer address on the proof.\n /// @param request The encoded bridge transaction to claim on origin chain\n function claim(bytes memory request) external;\n /// @notice Checks if a transaction has been relayed\n /// @param transactionId The ID of the transaction to check\n /// @return True if the transaction has been relayed, false otherwise\n function bridgeRelays(bytes32 transactionId) external view returns (bool);\n\n /// @notice Returns the status of a bridge transaction\n /// @param transactionId The ID of the bridge transaction\n /// @return BridgeStatus Status of the bridge transaction\n function bridgeStatuses(bytes32 transactionId) external view returns (BridgeStatus);\n\n /// @notice Returns the timestamp and relayer of a bridge proof\n /// @param transactionId The ID of the bridge transaction\n /// @return timestamp The timestamp of the bridge proof\n /// @return relayer The relayer address of the bridge proof\n function bridgeProofs(bytes32 transactionId) external view returns (uint96 timestamp, address relayer);\n\n /// @notice Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\n /// @param request The bridge request to decode\n function getBridgeTransactionV2(bytes memory request) external view returns (BridgeTransactionV2 memory);\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// contracts/libs/UniversalToken.sol\n\nlibrary UniversalTokenLib {\n using SafeERC20 for IERC20;\n\n address internal constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Transfers tokens to the given account. Reverts if transfer is not successful.\n /// @dev This might trigger fallback, if ETH is transferred to the contract.\n /// Make sure this can not lead to reentrancy attacks.\n function universalTransfer(address token, address to, uint256 value) internal {\n // Don't do anything, if need to send tokens to this address\n if (to == address(this)) return;\n // Don't do anything, if trying to send zero value\n if (value == 0) return;\n if (token == ETH_ADDRESS) {\n /// @dev Note: this can potentially lead to executing code in `to`.\n // solhint-disable-next-line avoid-low-level-calls\n (bool success,) = to.call{value: value}(\"\");\n require(success, \"ETH transfer failed\");\n } else {\n IERC20(token).safeTransfer(to, value);\n }\n }\n\n /// @notice Issues an infinite allowance to the spender, if the current allowance is insufficient\n /// to spend the given amount.\n function universalApproveInfinity(address token, address spender, uint256 amountToSpend) internal {\n // ETH Chad doesn't require your approval\n if (token == ETH_ADDRESS) return;\n // No-op if allowance is already sufficient\n uint256 allowance = IERC20(token).allowance(address(this), spender);\n if (allowance \u003e= amountToSpend) return;\n // Otherwise, reset approval to 0 and set to max allowance\n if (allowance \u003e 0) IERC20(token).safeDecreaseAllowance(spender, allowance);\n IERC20(token).safeIncreaseAllowance(spender, type(uint256).max);\n }\n\n /// @notice Returns the balance of the given token (or native ETH) for the given account.\n function universalBalanceOf(address token, address account) internal view returns (uint256) {\n if (token == ETH_ADDRESS) {\n return account.balance;\n } else {\n return IERC20(token).balanceOf(account);\n }\n }\n\n /// @dev Checks that token is a contract and not ETH_ADDRESS.\n function assertIsContract(address token) internal view {\n // Check that ETH_ADDRESS was not used (in case this is a predeploy on any of the chains)\n if (token == UniversalTokenLib.ETH_ADDRESS) revert TokenNotContract();\n // Check that token is not an EOA\n if (token.code.length == 0) revert TokenNotContract();\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/Admin.sol\n\ncontract Admin is IAdmin, AccessControlEnumerable {\n using UniversalTokenLib for address;\n\n bytes32 public constant RELAYER_ROLE = keccak256(\"RELAYER_ROLE\");\n bytes32 public constant REFUNDER_ROLE = keccak256(\"REFUNDER_ROLE\");\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n uint256 public constant FEE_BPS = 1e6;\n uint256 public constant FEE_RATE_MAX = 0.01e6; // max 1% on origin amount\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Chain gas amount to forward as rebate if requested\n uint256 public chainGasAmount;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n }\n\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n require(newFeeRate \u003c= FEE_RATE_MAX, \"newFeeRate \u003e max\");\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n token.universalTransfer(recipient, feeAmount);\n emit FeesSwept(token, recipient, feeAmount);\n }\n\n function setChainGasAmount(uint256 newChainGasAmount) external onlyRole(GOVERNOR_ROLE) {\n uint256 oldChainGasAmount = chainGasAmount;\n chainGasAmount = newChainGasAmount;\n emit ChainGasAmountUpdated(oldChainGasAmount, newChainGasAmount);\n }\n}\n\n// contracts/FastBridgeV2.sol\n\n/// @notice FastBridgeV2 is a contract for bridging tokens across chains.\ncontract FastBridgeV2 is Admin, IFastBridgeV2, IFastBridgeV2Errors {\n using SafeERC20 for IERC20;\n using UniversalTokenLib for address;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Delay for a transaction after which it could be permisionlessly refunded\n uint256 public constant REFUND_DELAY = 7 days;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n /// @notice Maximum length of accepted callParams\n uint256 public constant MAX_CALL_PARAMS_LENGTH = 2 ** 16 - 1;\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeTxDetails) public bridgeTxDetails;\n /// @notice Relay details on destination chain\n mapping(bytes32 =\u003e BridgeRelay) public bridgeRelayDetails;\n /// @notice Unique bridge nonces tracked per originSender\n mapping(address =\u003e uint256) public senderNonces;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Replaced by senderNonces\n uint256 public immutable nonce = 0;\n /// @notice the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n bridge({\n params: params,\n paramsV2: BridgeParamsV2({\n quoteRelayer: address(0),\n quoteExclusivitySeconds: 0,\n quoteId: bytes(\"\"),\n callValue: 0,\n callParams: bytes(\"\")\n })\n });\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes memory request) external payable {\n relay({request: request, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes memory request, bytes32 destTxHash) external {\n prove({transactionId: keccak256(request), destTxHash: destTxHash, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridgeV2\n function claim(bytes memory request) external {\n claim({request: request, to: address(0)});\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003e DISPUTE_PERIOD) {\n revert DisputePeriodPassed();\n }\n\n // @dev relayer gets slashed effectively if dest relay has gone thru\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n bridgeTxDetails[transactionId].proofRelayer = address(0);\n bridgeTxDetails[transactionId].proofBlockTimestamp = 0;\n bridgeTxDetails[transactionId].proofBlockNumber = 0;\n\n emit BridgeProofDisputed(transactionId, msg.sender);\n }\n\n /// @inheritdoc IFastBridge\n function refund(bytes memory request) external {\n bytes32 transactionId = keccak256(request);\n\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n\n if (bridgeTxDetails[transactionId].status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n\n if (hasRole(REFUNDER_ROLE, msg.sender)) {\n // Refunder can refund if deadline has passed\n if (block.timestamp \u003c= transaction.deadline) revert DeadlineNotExceeded();\n } else {\n // Permissionless refund is allowed after REFUND_DELAY\n if (block.timestamp \u003c= transaction.deadline + REFUND_DELAY) revert DeadlineNotExceeded();\n }\n\n // if all checks passed, set to REFUNDED status\n bridgeTxDetails[transactionId].status = BridgeStatus.REFUNDED;\n\n // transfer origin collateral back to original sender\n address to = transaction.originSender;\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount + transaction.originFeeAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (bridgeTxDetails[transactionId].proofRelayer != relayer) revert SenderIncorrect();\n return _timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n /// @dev This method is added to achieve backwards compatibility with decoding requests into V1 structs:\n /// - `callValue` is partially reported as a zero/non-zero flag\n /// - `callParams` is ignored\n /// In order to process all kinds of requests use getBridgeTransactionV2 instead.\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory) {\n // Try decoding into V2 struct first. This will revert if V1 struct is passed\n try this.getBridgeTransactionV2(request) returns (BridgeTransactionV2 memory txV2) {\n // Note: we entirely ignore the callParams field, as it was not present in V1\n return BridgeTransaction({\n originChainId: txV2.originChainId,\n destChainId: txV2.destChainId,\n originSender: txV2.originSender,\n destRecipient: txV2.destRecipient,\n originToken: txV2.originToken,\n destToken: txV2.destToken,\n originAmount: txV2.originAmount,\n destAmount: txV2.destAmount,\n originFeeAmount: txV2.originFeeAmount,\n sendChainGas: txV2.callValue != 0,\n deadline: txV2.deadline,\n nonce: txV2.nonce\n });\n } catch {\n // Fallback to V1 struct\n return abi.decode(request, (BridgeTransaction));\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) public payable {\n int256 exclusivityEndTime = int256(block.timestamp) + paramsV2.quoteExclusivitySeconds;\n _validateBridgeParams(params, paramsV2, exclusivityEndTime);\n\n // transfer tokens to bridge contract\n /// @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _pullToken(params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n\n // set status to requested\n bytes memory request = abi.encode(\n BridgeTransactionV2({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n callValue: paramsV2.callValue,\n deadline: params.deadline,\n nonce: senderNonces[params.sender]++, // increment nonce on every bridge\n exclusivityRelayer: paramsV2.quoteRelayer,\n // We checked exclusivityEndTime to be in range (0 .. params.deadline] above, so can safely cast\n exclusivityEndTime: uint256(exclusivityEndTime),\n callParams: paramsV2.callParams\n })\n );\n bytes32 transactionId = keccak256(request);\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n\n emit BridgeRequested({\n transactionId: transactionId,\n sender: params.sender,\n request: request,\n destChainId: params.dstChainId,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n sendChainGas: paramsV2.callValue != 0\n });\n emit BridgeQuoteDetails(transactionId, paramsV2.quoteId);\n }\n\n /// @inheritdoc IFastBridgeV2\n function relay(bytes memory request, address relayer) public payable {\n bytes32 transactionId = keccak256(request);\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n _validateRelayParams(transaction, transactionId, relayer);\n // mark bridge transaction as relayed\n bridgeRelayDetails[transactionId] =\n BridgeRelay({blockNumber: uint48(block.number), blockTimestamp: uint48(block.timestamp), relayer: relayer});\n\n // transfer tokens to recipient on destination chain and do an arbitrary call if requested\n address to = transaction.destRecipient;\n address token = transaction.destToken;\n uint256 amount = transaction.destAmount;\n\n // All state changes have been done at this point, can proceed to the external calls.\n // This follows the checks-effects-interactions pattern to mitigate potential reentrancy attacks.\n if (token == UniversalTokenLib.ETH_ADDRESS) {\n // For ETH non-zero callValue is not allowed\n if (transaction.callValue != 0) revert NativeTokenCallValueNotSupported();\n // Check that the correct msg.value was sent\n if (msg.value != amount) revert MsgValueIncorrect();\n } else {\n // For ERC20s, we check that the correct msg.value was sent\n if (msg.value != transaction.callValue) revert MsgValueIncorrect();\n // We need to transfer the tokens from the Relayer to the recipient first before performing an\n // optional post-transfer arbitrary call.\n IERC20(token).safeTransferFrom(msg.sender, to, amount);\n }\n\n if (transaction.callParams.length != 0) {\n // Arbitrary call requested, perform it while supplying full msg.value to the recipient\n // Note: if token has a fee on transfers, the recipient will have received less than `amount`.\n // This is a very niche edge case and should be handled by the recipient contract.\n _checkedCallRecipient({recipient: to, token: token, amount: amount, callParams: transaction.callParams});\n } else if (msg.value != 0) {\n // No arbitrary call requested, but msg.value was sent. This is either a relay with ETH,\n // or a non-zero callValue request with an ERC20. In both cases, transfer the ETH to the recipient.\n Address.sendValue(payable(to), msg.value);\n }\n\n emit BridgeRelayed({\n transactionId: transactionId,\n relayer: relayer,\n to: to,\n originChainId: transaction.originChainId,\n originToken: transaction.originToken,\n destToken: transaction.destToken,\n originAmount: transaction.originAmount,\n destAmount: transaction.destAmount,\n chainGasAmount: transaction.callValue\n });\n }\n\n /// @inheritdoc IFastBridgeV2\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) public onlyRole(RELAYER_ROLE) {\n // update bridge tx status given proof provided\n if (bridgeTxDetails[transactionId].status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n bridgeTxDetails[transactionId].status = BridgeStatus.RELAYER_PROVED;\n bridgeTxDetails[transactionId].proofBlockTimestamp = uint40(block.timestamp);\n bridgeTxDetails[transactionId].proofBlockNumber = uint48(block.number);\n bridgeTxDetails[transactionId].proofRelayer = relayer;\n\n emit BridgeProofProvided(transactionId, relayer, destTxHash);\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes memory request, address to) public {\n bytes32 transactionId = keccak256(request);\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n\n // update bridge tx status if able to claim origin collateral\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n\n // if \"to\" is zero addr, permissionlessly send funds to proven relayer\n if (to == address(0)) {\n to = bridgeTxDetails[transactionId].proofRelayer;\n } else if (bridgeTxDetails[transactionId].proofRelayer != msg.sender) {\n revert SenderIncorrect();\n }\n\n if (_timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003c= DISPUTE_PERIOD) {\n revert DisputePeriodNotPassed();\n }\n\n bridgeTxDetails[transactionId].status = BridgeStatus.RELAYER_CLAIMED;\n\n // update protocol fees if origin fee amount exists\n if (transaction.originFeeAmount \u003e 0) protocolFees[transaction.originToken] += transaction.originFeeAmount;\n\n // transfer origin collateral less fee to specified address\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositClaimed(transactionId, bridgeTxDetails[transactionId].proofRelayer, to, token, amount);\n }\n\n function bridgeStatuses(bytes32 transactionId) public view returns (BridgeStatus status) {\n return bridgeTxDetails[transactionId].status;\n }\n\n function bridgeProofs(bytes32 transactionId) public view returns (uint96 timestamp, address relayer) {\n timestamp = bridgeTxDetails[transactionId].proofBlockTimestamp;\n relayer = bridgeTxDetails[transactionId].proofRelayer;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeRelays(bytes32 transactionId) public view returns (bool) {\n // has this transactionId been relayed?\n return bridgeRelayDetails[transactionId].relayer != address(0);\n }\n\n /// @inheritdoc IFastBridgeV2\n function getBridgeTransactionV2(bytes memory request) public pure returns (BridgeTransactionV2 memory) {\n return abi.decode(request, (BridgeTransactionV2));\n }\n\n /// @notice Pulls a requested token from the user to this contract.\n function _pullToken(address token, uint256 amount) internal returns (uint256 amountPulled) {\n if (token == UniversalTokenLib.ETH_ADDRESS) {\n // For ETH we just need to check that the supplied msg.value is correct\n if (amount != msg.value) revert MsgValueIncorrect();\n amountPulled = msg.value;\n } else {\n token.assertIsContract();\n // Record token balance before transfer\n amountPulled = IERC20(token).balanceOf(address(this));\n // Token needs to be pulled only if msg.value is zero\n // This way user can specify WETH as the origin asset\n IERC20(token).safeTransferFrom(msg.sender, address(this), amount);\n // Use the difference between the recorded balance and the current balance as the amountPulled\n amountPulled = IERC20(token).balanceOf(address(this)) - amountPulled;\n }\n }\n\n /// @notice Calls the Recipient's hook function with the specified callParams and performs\n /// all the necessary checks for the returned value.\n function _checkedCallRecipient(\n address recipient,\n address token,\n uint256 amount,\n bytes memory callParams\n )\n internal\n {\n bytes memory hookData =\n abi.encodeCall(IFastBridgeRecipient.fastBridgeTransferReceived, (token, amount, callParams));\n // This will bubble any revert messages from the hook function\n bytes memory returnData = Address.functionCallWithValue({target: recipient, data: hookData, value: msg.value});\n // Explicit revert if no return data at all\n if (returnData.length == 0) revert RecipientNoReturnValue();\n // Check that exactly a single return value was returned\n if (returnData.length != 32) revert RecipientIncorrectReturnValue();\n // Return value should be abi-encoded hook function selector\n if (bytes32(returnData) != bytes32(IFastBridgeRecipient.fastBridgeTransferReceived.selector)) {\n revert RecipientIncorrectReturnValue();\n }\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint40(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint40).max but\n /// proof.timestamp \u003c type(uint40).max via unchecked statement\n /// @param proofBlockTimestamp The bridge proof block timestamp\n /// @return delta Time delta since proof submitted\n function _timeSince(uint40 proofBlockTimestamp) internal view returns (uint256 delta) {\n unchecked {\n delta = uint40(block.timestamp) - proofBlockTimestamp;\n }\n }\n\n /// @notice Performs all the necessary checks for a bridge to happen.\n /// @dev There's no good way to refactor this function to reduce cyclomatic complexity due to\n /// the number of checks that need to be performed, so we skip the code-complexity rule here.\n // solhint-disable-next-line code-complexity\n function _validateBridgeParams(\n BridgeParams memory params,\n BridgeParamsV2 memory paramsV2,\n int256 exclusivityEndTime\n )\n internal\n view\n {\n // Check V1 (legacy) params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.sender == address(0) || params.to == address(0)) revert ZeroAddress();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n // Check V2 params\n if (paramsV2.callParams.length \u003e MAX_CALL_PARAMS_LENGTH) revert CallParamsLengthAboveMax();\n if (paramsV2.callValue != 0 \u0026\u0026 params.destToken == UniversalTokenLib.ETH_ADDRESS) {\n revert NativeTokenCallValueNotSupported();\n }\n // exclusivityEndTime must be in range (0 .. params.deadline]\n if (exclusivityEndTime \u003c= 0 || exclusivityEndTime \u003e int256(params.deadline)) {\n revert ExclusivityParamsIncorrect();\n }\n }\n\n /// @notice Performs all the necessary checks for a relay to happen.\n function _validateRelayParams(\n BridgeTransactionV2 memory transaction,\n bytes32 transactionId,\n address relayer\n )\n internal\n view\n {\n if (relayer == address(0)) revert ZeroAddress();\n // Check if the transaction has already been relayed\n if (bridgeRelays(transactionId)) revert TransactionRelayed();\n if (transaction.destChainId != uint32(block.chainid)) revert ChainIncorrect();\n // Check the deadline for relay to happen\n if (block.timestamp \u003e transaction.deadline) revert DeadlineExceeded();\n // Check the exclusivity period, if it is still ongoing\n // forgefmt: disable-next-item\n if (\n transaction.exclusivityRelayer != address(0) \u0026\u0026\n transaction.exclusivityRelayer != relayer \u0026\u0026\n block.timestamp \u003c= transaction.exclusivityEndTime\n ) {\n revert ExclusivityPeriodNotPassed();\n }\n }\n}\n","language":"Solidity","languageVersion":"0.8.24","compilerVersion":"0.8.24","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"","srcMapRuntime":"","abiDefinition":[{"inputs":[],"name":"AmountIncorrect","type":"error"},{"inputs":[],"name":"CallParamsLengthAboveMax","type":"error"},{"inputs":[],"name":"ChainIncorrect","type":"error"},{"inputs":[],"name":"DeadlineExceeded","type":"error"},{"inputs":[],"name":"DeadlineNotExceeded","type":"error"},{"inputs":[],"name":"DeadlineTooShort","type":"error"},{"inputs":[],"name":"DisputePeriodNotPassed","type":"error"},{"inputs":[],"name":"DisputePeriodPassed","type":"error"},{"inputs":[],"name":"ExclusivityParamsIncorrect","type":"error"},{"inputs":[],"name":"ExclusivityPeriodNotPassed","type":"error"},{"inputs":[],"name":"MsgValueIncorrect","type":"error"},{"inputs":[],"name":"NativeTokenCallValueNotSupported","type":"error"},{"inputs":[],"name":"RecipientIncorrectReturnValue","type":"error"},{"inputs":[],"name":"RecipientNoReturnValue","type":"error"},{"inputs":[],"name":"SenderIncorrect","type":"error"},{"inputs":[],"name":"StatusIncorrect","type":"error"},{"inputs":[],"name":"TransactionRelayed","type":"error"},{"inputs":[],"name":"ZeroAddress","type":"error"}],"userDoc":{"kind":"user","methods":{},"version":1},"developerDoc":{"kind":"dev","methods":{},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[],\"name\":\"AmountIncorrect\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"CallParamsLengthAboveMax\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ChainIncorrect\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DeadlineExceeded\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DeadlineNotExceeded\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DeadlineTooShort\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DisputePeriodNotPassed\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DisputePeriodPassed\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ExclusivityParamsIncorrect\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ExclusivityPeriodNotPassed\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"MsgValueIncorrect\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"NativeTokenCallValueNotSupported\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"RecipientIncorrectReturnValue\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"RecipientNoReturnValue\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"SenderIncorrect\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"StatusIncorrect\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"TransactionRelayed\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ZeroAddress\",\"type\":\"error\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeV2.sol\":\"IFastBridgeV2Errors\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeV2.sol\":{\"keccak256\":\"0x7cd0f885e80e2bdaa638bc32ae7af7d2e248f99ce4b354c217d0f0f7d7302e0a\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://7ccf28df0bd7b4606986585acd8622ed9b4e81379690061bb66088f0a2270af1\",\"dweb:/ipfs/QmTf7HNdHZkK6vmx8ZgewycQEb72oLD9nPwBpsM5reMstQ\"]}},\"version\":1}"},"hashes":{}},"solidity/FastBridgeV2.sol:SafeERC20":{"code":"0x60566037600b82828239805160001a607314602a57634e487b7160e01b600052600060045260246000fd5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600080fdfea26469706673582212202e6244574a9418b179bbe1f5d6f1483cf0da887e64158bb04463fae84495de4464736f6c63430008180033","runtime-code":"0x73000000000000000000000000000000000000000030146080604052600080fdfea26469706673582212202e6244574a9418b179bbe1f5d6f1483cf0da887e64158bb04463fae84495de4464736f6c63430008180033","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.24 ^0.8.0 ^0.8.20;\n\n// contracts/interfaces/IAdmin.sol\n\ninterface IAdmin {\n // ============ Events ============\n\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n event ChainGasAmountUpdated(uint256 oldChainGasAmount, uint256 newChainGasAmount);\n\n // ============ Methods ============\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n\n function setChainGasAmount(uint256 newChainGasAmount) external;\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IFastBridgeRecipient.sol\n\ninterface IFastBridgeRecipient {\n function fastBridgeTransferReceived(\n address token,\n uint256 amount,\n bytes memory callParams\n )\n external\n payable\n returns (bytes4);\n}\n\n// contracts/interfaces/IFastBridgeV2Errors.sol\n\ninterface IFastBridgeV2Errors {\n error AmountIncorrect();\n error CallParamsLengthAboveMax();\n error ChainIncorrect();\n error ExclusivityParamsIncorrect();\n error MsgValueIncorrect();\n error NativeTokenCallValueNotSupported();\n error SenderIncorrect();\n error StatusIncorrect();\n error ZeroAddress();\n\n error RecipientIncorrectReturnValue();\n error RecipientNoReturnValue();\n\n error DeadlineExceeded();\n error DeadlineNotExceeded();\n error DeadlineTooShort();\n error DisputePeriodNotPassed();\n error DisputePeriodPassed();\n error ExclusivityPeriodNotPassed();\n\n error TransactionRelayed();\n}\n\n// contracts/libs/Errors.sol\n\nerror DeadlineExceeded();\nerror DeadlineNotExceeded();\nerror DeadlineTooShort();\nerror InsufficientOutputAmount();\n\nerror MsgValueIncorrect();\nerror PoolNotFound();\nerror TokenAddressMismatch();\nerror TokenNotContract();\nerror TokenNotETH();\nerror TokensIdentical();\n\nerror ChainIncorrect();\nerror AmountIncorrect();\nerror ZeroAddress();\n\nerror DisputePeriodNotPassed();\nerror DisputePeriodPassed();\nerror SenderIncorrect();\nerror StatusIncorrect();\nerror TransactionIdIncorrect();\nerror TransactionRelayed();\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// contracts/interfaces/IFastBridgeV2.sol\n\ninterface IFastBridgeV2 is IFastBridge {\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n struct BridgeTxDetails {\n BridgeStatus status;\n uint40 proofBlockTimestamp;\n uint48 proofBlockNumber;\n address proofRelayer;\n }\n\n struct BridgeRelay {\n uint48 blockNumber;\n uint48 blockTimestamp;\n address relayer;\n }\n\n /// @notice New params introduced in the FastBridgeV2.\n /// We are passing fields from the older BridgeParams struct outside of this struct\n /// for backwards compatibility.\n /// Note: quoteRelayer and quoteExclusivitySeconds are either both zero (indicating no exclusivity)\n /// or both non-zero (indicating exclusivity for the given period).\n /// Note: callValue \u003e 0 can NOT be used with destToken = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE (ETH_ADDRESS)\n /// @param quoteRelayer Relayer that provided the quote for the transaction\n /// @param quoteExclusivitySeconds Period of time the quote relayer is guaranteed exclusivity after user's deposit\n /// @param quoteId Unique quote identifier used for tracking the quote\n /// @param callValue ETH value to send to the recipient (if any)\n /// @param callParams Parameters for the arbitrary call to the destination recipient (if any)\n struct BridgeParamsV2 {\n address quoteRelayer;\n int256 quoteExclusivitySeconds;\n bytes quoteId;\n uint256 callValue;\n bytes callParams;\n }\n\n /// @notice Updated bridge transaction struct to include parameters introduced in FastBridgeV2.\n /// Note: only `exclusivityRelayer` can fill such a transaction until `exclusivityEndTime`.\n /// TODO: consider changing the encoding scheme to prevent spending extra gas on decoding.\n struct BridgeTransactionV2 {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n uint256 callValue; // ETH value to send to the recipient (if any) - replaces V1's sendChainGas flag\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n address exclusivityRelayer;\n uint256 exclusivityEndTime;\n bytes callParams;\n }\n\n event BridgeQuoteDetails(bytes32 indexed transactionId, bytes quoteId);\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability\n /// to provide temporary exclusivity fill rights for the quote relayer.\n /// @param params The parameters required to bridge\n /// @param paramsV2 The parameters for exclusivity fill rights (optional, can be left empty)\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function relay(bytes memory request, address relayer) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param transactionId The transaction id associated with the encoded bridge transaction to prove\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital.\n /// @notice Can only send funds to the relayer address on the proof.\n /// @param request The encoded bridge transaction to claim on origin chain\n function claim(bytes memory request) external;\n /// @notice Checks if a transaction has been relayed\n /// @param transactionId The ID of the transaction to check\n /// @return True if the transaction has been relayed, false otherwise\n function bridgeRelays(bytes32 transactionId) external view returns (bool);\n\n /// @notice Returns the status of a bridge transaction\n /// @param transactionId The ID of the bridge transaction\n /// @return BridgeStatus Status of the bridge transaction\n function bridgeStatuses(bytes32 transactionId) external view returns (BridgeStatus);\n\n /// @notice Returns the timestamp and relayer of a bridge proof\n /// @param transactionId The ID of the bridge transaction\n /// @return timestamp The timestamp of the bridge proof\n /// @return relayer The relayer address of the bridge proof\n function bridgeProofs(bytes32 transactionId) external view returns (uint96 timestamp, address relayer);\n\n /// @notice Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\n /// @param request The bridge request to decode\n function getBridgeTransactionV2(bytes memory request) external view returns (BridgeTransactionV2 memory);\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// contracts/libs/UniversalToken.sol\n\nlibrary UniversalTokenLib {\n using SafeERC20 for IERC20;\n\n address internal constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Transfers tokens to the given account. Reverts if transfer is not successful.\n /// @dev This might trigger fallback, if ETH is transferred to the contract.\n /// Make sure this can not lead to reentrancy attacks.\n function universalTransfer(address token, address to, uint256 value) internal {\n // Don't do anything, if need to send tokens to this address\n if (to == address(this)) return;\n // Don't do anything, if trying to send zero value\n if (value == 0) return;\n if (token == ETH_ADDRESS) {\n /// @dev Note: this can potentially lead to executing code in `to`.\n // solhint-disable-next-line avoid-low-level-calls\n (bool success,) = to.call{value: value}(\"\");\n require(success, \"ETH transfer failed\");\n } else {\n IERC20(token).safeTransfer(to, value);\n }\n }\n\n /// @notice Issues an infinite allowance to the spender, if the current allowance is insufficient\n /// to spend the given amount.\n function universalApproveInfinity(address token, address spender, uint256 amountToSpend) internal {\n // ETH Chad doesn't require your approval\n if (token == ETH_ADDRESS) return;\n // No-op if allowance is already sufficient\n uint256 allowance = IERC20(token).allowance(address(this), spender);\n if (allowance \u003e= amountToSpend) return;\n // Otherwise, reset approval to 0 and set to max allowance\n if (allowance \u003e 0) IERC20(token).safeDecreaseAllowance(spender, allowance);\n IERC20(token).safeIncreaseAllowance(spender, type(uint256).max);\n }\n\n /// @notice Returns the balance of the given token (or native ETH) for the given account.\n function universalBalanceOf(address token, address account) internal view returns (uint256) {\n if (token == ETH_ADDRESS) {\n return account.balance;\n } else {\n return IERC20(token).balanceOf(account);\n }\n }\n\n /// @dev Checks that token is a contract and not ETH_ADDRESS.\n function assertIsContract(address token) internal view {\n // Check that ETH_ADDRESS was not used (in case this is a predeploy on any of the chains)\n if (token == UniversalTokenLib.ETH_ADDRESS) revert TokenNotContract();\n // Check that token is not an EOA\n if (token.code.length == 0) revert TokenNotContract();\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/Admin.sol\n\ncontract Admin is IAdmin, AccessControlEnumerable {\n using UniversalTokenLib for address;\n\n bytes32 public constant RELAYER_ROLE = keccak256(\"RELAYER_ROLE\");\n bytes32 public constant REFUNDER_ROLE = keccak256(\"REFUNDER_ROLE\");\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n uint256 public constant FEE_BPS = 1e6;\n uint256 public constant FEE_RATE_MAX = 0.01e6; // max 1% on origin amount\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Chain gas amount to forward as rebate if requested\n uint256 public chainGasAmount;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n }\n\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n require(newFeeRate \u003c= FEE_RATE_MAX, \"newFeeRate \u003e max\");\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n token.universalTransfer(recipient, feeAmount);\n emit FeesSwept(token, recipient, feeAmount);\n }\n\n function setChainGasAmount(uint256 newChainGasAmount) external onlyRole(GOVERNOR_ROLE) {\n uint256 oldChainGasAmount = chainGasAmount;\n chainGasAmount = newChainGasAmount;\n emit ChainGasAmountUpdated(oldChainGasAmount, newChainGasAmount);\n }\n}\n\n// contracts/FastBridgeV2.sol\n\n/// @notice FastBridgeV2 is a contract for bridging tokens across chains.\ncontract FastBridgeV2 is Admin, IFastBridgeV2, IFastBridgeV2Errors {\n using SafeERC20 for IERC20;\n using UniversalTokenLib for address;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Delay for a transaction after which it could be permisionlessly refunded\n uint256 public constant REFUND_DELAY = 7 days;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n /// @notice Maximum length of accepted callParams\n uint256 public constant MAX_CALL_PARAMS_LENGTH = 2 ** 16 - 1;\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeTxDetails) public bridgeTxDetails;\n /// @notice Relay details on destination chain\n mapping(bytes32 =\u003e BridgeRelay) public bridgeRelayDetails;\n /// @notice Unique bridge nonces tracked per originSender\n mapping(address =\u003e uint256) public senderNonces;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Replaced by senderNonces\n uint256 public immutable nonce = 0;\n /// @notice the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n bridge({\n params: params,\n paramsV2: BridgeParamsV2({\n quoteRelayer: address(0),\n quoteExclusivitySeconds: 0,\n quoteId: bytes(\"\"),\n callValue: 0,\n callParams: bytes(\"\")\n })\n });\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes memory request) external payable {\n relay({request: request, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes memory request, bytes32 destTxHash) external {\n prove({transactionId: keccak256(request), destTxHash: destTxHash, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridgeV2\n function claim(bytes memory request) external {\n claim({request: request, to: address(0)});\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003e DISPUTE_PERIOD) {\n revert DisputePeriodPassed();\n }\n\n // @dev relayer gets slashed effectively if dest relay has gone thru\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n bridgeTxDetails[transactionId].proofRelayer = address(0);\n bridgeTxDetails[transactionId].proofBlockTimestamp = 0;\n bridgeTxDetails[transactionId].proofBlockNumber = 0;\n\n emit BridgeProofDisputed(transactionId, msg.sender);\n }\n\n /// @inheritdoc IFastBridge\n function refund(bytes memory request) external {\n bytes32 transactionId = keccak256(request);\n\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n\n if (bridgeTxDetails[transactionId].status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n\n if (hasRole(REFUNDER_ROLE, msg.sender)) {\n // Refunder can refund if deadline has passed\n if (block.timestamp \u003c= transaction.deadline) revert DeadlineNotExceeded();\n } else {\n // Permissionless refund is allowed after REFUND_DELAY\n if (block.timestamp \u003c= transaction.deadline + REFUND_DELAY) revert DeadlineNotExceeded();\n }\n\n // if all checks passed, set to REFUNDED status\n bridgeTxDetails[transactionId].status = BridgeStatus.REFUNDED;\n\n // transfer origin collateral back to original sender\n address to = transaction.originSender;\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount + transaction.originFeeAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (bridgeTxDetails[transactionId].proofRelayer != relayer) revert SenderIncorrect();\n return _timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n /// @dev This method is added to achieve backwards compatibility with decoding requests into V1 structs:\n /// - `callValue` is partially reported as a zero/non-zero flag\n /// - `callParams` is ignored\n /// In order to process all kinds of requests use getBridgeTransactionV2 instead.\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory) {\n // Try decoding into V2 struct first. This will revert if V1 struct is passed\n try this.getBridgeTransactionV2(request) returns (BridgeTransactionV2 memory txV2) {\n // Note: we entirely ignore the callParams field, as it was not present in V1\n return BridgeTransaction({\n originChainId: txV2.originChainId,\n destChainId: txV2.destChainId,\n originSender: txV2.originSender,\n destRecipient: txV2.destRecipient,\n originToken: txV2.originToken,\n destToken: txV2.destToken,\n originAmount: txV2.originAmount,\n destAmount: txV2.destAmount,\n originFeeAmount: txV2.originFeeAmount,\n sendChainGas: txV2.callValue != 0,\n deadline: txV2.deadline,\n nonce: txV2.nonce\n });\n } catch {\n // Fallback to V1 struct\n return abi.decode(request, (BridgeTransaction));\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) public payable {\n int256 exclusivityEndTime = int256(block.timestamp) + paramsV2.quoteExclusivitySeconds;\n _validateBridgeParams(params, paramsV2, exclusivityEndTime);\n\n // transfer tokens to bridge contract\n /// @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _pullToken(params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n\n // set status to requested\n bytes memory request = abi.encode(\n BridgeTransactionV2({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n callValue: paramsV2.callValue,\n deadline: params.deadline,\n nonce: senderNonces[params.sender]++, // increment nonce on every bridge\n exclusivityRelayer: paramsV2.quoteRelayer,\n // We checked exclusivityEndTime to be in range (0 .. params.deadline] above, so can safely cast\n exclusivityEndTime: uint256(exclusivityEndTime),\n callParams: paramsV2.callParams\n })\n );\n bytes32 transactionId = keccak256(request);\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n\n emit BridgeRequested({\n transactionId: transactionId,\n sender: params.sender,\n request: request,\n destChainId: params.dstChainId,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n sendChainGas: paramsV2.callValue != 0\n });\n emit BridgeQuoteDetails(transactionId, paramsV2.quoteId);\n }\n\n /// @inheritdoc IFastBridgeV2\n function relay(bytes memory request, address relayer) public payable {\n bytes32 transactionId = keccak256(request);\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n _validateRelayParams(transaction, transactionId, relayer);\n // mark bridge transaction as relayed\n bridgeRelayDetails[transactionId] =\n BridgeRelay({blockNumber: uint48(block.number), blockTimestamp: uint48(block.timestamp), relayer: relayer});\n\n // transfer tokens to recipient on destination chain and do an arbitrary call if requested\n address to = transaction.destRecipient;\n address token = transaction.destToken;\n uint256 amount = transaction.destAmount;\n\n // All state changes have been done at this point, can proceed to the external calls.\n // This follows the checks-effects-interactions pattern to mitigate potential reentrancy attacks.\n if (token == UniversalTokenLib.ETH_ADDRESS) {\n // For ETH non-zero callValue is not allowed\n if (transaction.callValue != 0) revert NativeTokenCallValueNotSupported();\n // Check that the correct msg.value was sent\n if (msg.value != amount) revert MsgValueIncorrect();\n } else {\n // For ERC20s, we check that the correct msg.value was sent\n if (msg.value != transaction.callValue) revert MsgValueIncorrect();\n // We need to transfer the tokens from the Relayer to the recipient first before performing an\n // optional post-transfer arbitrary call.\n IERC20(token).safeTransferFrom(msg.sender, to, amount);\n }\n\n if (transaction.callParams.length != 0) {\n // Arbitrary call requested, perform it while supplying full msg.value to the recipient\n // Note: if token has a fee on transfers, the recipient will have received less than `amount`.\n // This is a very niche edge case and should be handled by the recipient contract.\n _checkedCallRecipient({recipient: to, token: token, amount: amount, callParams: transaction.callParams});\n } else if (msg.value != 0) {\n // No arbitrary call requested, but msg.value was sent. This is either a relay with ETH,\n // or a non-zero callValue request with an ERC20. In both cases, transfer the ETH to the recipient.\n Address.sendValue(payable(to), msg.value);\n }\n\n emit BridgeRelayed({\n transactionId: transactionId,\n relayer: relayer,\n to: to,\n originChainId: transaction.originChainId,\n originToken: transaction.originToken,\n destToken: transaction.destToken,\n originAmount: transaction.originAmount,\n destAmount: transaction.destAmount,\n chainGasAmount: transaction.callValue\n });\n }\n\n /// @inheritdoc IFastBridgeV2\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) public onlyRole(RELAYER_ROLE) {\n // update bridge tx status given proof provided\n if (bridgeTxDetails[transactionId].status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n bridgeTxDetails[transactionId].status = BridgeStatus.RELAYER_PROVED;\n bridgeTxDetails[transactionId].proofBlockTimestamp = uint40(block.timestamp);\n bridgeTxDetails[transactionId].proofBlockNumber = uint48(block.number);\n bridgeTxDetails[transactionId].proofRelayer = relayer;\n\n emit BridgeProofProvided(transactionId, relayer, destTxHash);\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes memory request, address to) public {\n bytes32 transactionId = keccak256(request);\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n\n // update bridge tx status if able to claim origin collateral\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n\n // if \"to\" is zero addr, permissionlessly send funds to proven relayer\n if (to == address(0)) {\n to = bridgeTxDetails[transactionId].proofRelayer;\n } else if (bridgeTxDetails[transactionId].proofRelayer != msg.sender) {\n revert SenderIncorrect();\n }\n\n if (_timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003c= DISPUTE_PERIOD) {\n revert DisputePeriodNotPassed();\n }\n\n bridgeTxDetails[transactionId].status = BridgeStatus.RELAYER_CLAIMED;\n\n // update protocol fees if origin fee amount exists\n if (transaction.originFeeAmount \u003e 0) protocolFees[transaction.originToken] += transaction.originFeeAmount;\n\n // transfer origin collateral less fee to specified address\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositClaimed(transactionId, bridgeTxDetails[transactionId].proofRelayer, to, token, amount);\n }\n\n function bridgeStatuses(bytes32 transactionId) public view returns (BridgeStatus status) {\n return bridgeTxDetails[transactionId].status;\n }\n\n function bridgeProofs(bytes32 transactionId) public view returns (uint96 timestamp, address relayer) {\n timestamp = bridgeTxDetails[transactionId].proofBlockTimestamp;\n relayer = bridgeTxDetails[transactionId].proofRelayer;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeRelays(bytes32 transactionId) public view returns (bool) {\n // has this transactionId been relayed?\n return bridgeRelayDetails[transactionId].relayer != address(0);\n }\n\n /// @inheritdoc IFastBridgeV2\n function getBridgeTransactionV2(bytes memory request) public pure returns (BridgeTransactionV2 memory) {\n return abi.decode(request, (BridgeTransactionV2));\n }\n\n /// @notice Pulls a requested token from the user to this contract.\n function _pullToken(address token, uint256 amount) internal returns (uint256 amountPulled) {\n if (token == UniversalTokenLib.ETH_ADDRESS) {\n // For ETH we just need to check that the supplied msg.value is correct\n if (amount != msg.value) revert MsgValueIncorrect();\n amountPulled = msg.value;\n } else {\n token.assertIsContract();\n // Record token balance before transfer\n amountPulled = IERC20(token).balanceOf(address(this));\n // Token needs to be pulled only if msg.value is zero\n // This way user can specify WETH as the origin asset\n IERC20(token).safeTransferFrom(msg.sender, address(this), amount);\n // Use the difference between the recorded balance and the current balance as the amountPulled\n amountPulled = IERC20(token).balanceOf(address(this)) - amountPulled;\n }\n }\n\n /// @notice Calls the Recipient's hook function with the specified callParams and performs\n /// all the necessary checks for the returned value.\n function _checkedCallRecipient(\n address recipient,\n address token,\n uint256 amount,\n bytes memory callParams\n )\n internal\n {\n bytes memory hookData =\n abi.encodeCall(IFastBridgeRecipient.fastBridgeTransferReceived, (token, amount, callParams));\n // This will bubble any revert messages from the hook function\n bytes memory returnData = Address.functionCallWithValue({target: recipient, data: hookData, value: msg.value});\n // Explicit revert if no return data at all\n if (returnData.length == 0) revert RecipientNoReturnValue();\n // Check that exactly a single return value was returned\n if (returnData.length != 32) revert RecipientIncorrectReturnValue();\n // Return value should be abi-encoded hook function selector\n if (bytes32(returnData) != bytes32(IFastBridgeRecipient.fastBridgeTransferReceived.selector)) {\n revert RecipientIncorrectReturnValue();\n }\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint40(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint40).max but\n /// proof.timestamp \u003c type(uint40).max via unchecked statement\n /// @param proofBlockTimestamp The bridge proof block timestamp\n /// @return delta Time delta since proof submitted\n function _timeSince(uint40 proofBlockTimestamp) internal view returns (uint256 delta) {\n unchecked {\n delta = uint40(block.timestamp) - proofBlockTimestamp;\n }\n }\n\n /// @notice Performs all the necessary checks for a bridge to happen.\n /// @dev There's no good way to refactor this function to reduce cyclomatic complexity due to\n /// the number of checks that need to be performed, so we skip the code-complexity rule here.\n // solhint-disable-next-line code-complexity\n function _validateBridgeParams(\n BridgeParams memory params,\n BridgeParamsV2 memory paramsV2,\n int256 exclusivityEndTime\n )\n internal\n view\n {\n // Check V1 (legacy) params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.sender == address(0) || params.to == address(0)) revert ZeroAddress();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n // Check V2 params\n if (paramsV2.callParams.length \u003e MAX_CALL_PARAMS_LENGTH) revert CallParamsLengthAboveMax();\n if (paramsV2.callValue != 0 \u0026\u0026 params.destToken == UniversalTokenLib.ETH_ADDRESS) {\n revert NativeTokenCallValueNotSupported();\n }\n // exclusivityEndTime must be in range (0 .. params.deadline]\n if (exclusivityEndTime \u003c= 0 || exclusivityEndTime \u003e int256(params.deadline)) {\n revert ExclusivityParamsIncorrect();\n }\n }\n\n /// @notice Performs all the necessary checks for a relay to happen.\n function _validateRelayParams(\n BridgeTransactionV2 memory transaction,\n bytes32 transactionId,\n address relayer\n )\n internal\n view\n {\n if (relayer == address(0)) revert ZeroAddress();\n // Check if the transaction has already been relayed\n if (bridgeRelays(transactionId)) revert TransactionRelayed();\n if (transaction.destChainId != uint32(block.chainid)) revert ChainIncorrect();\n // Check the deadline for relay to happen\n if (block.timestamp \u003e transaction.deadline) revert DeadlineExceeded();\n // Check the exclusivity period, if it is still ongoing\n // forgefmt: disable-next-item\n if (\n transaction.exclusivityRelayer != address(0) \u0026\u0026\n transaction.exclusivityRelayer != relayer \u0026\u0026\n block.timestamp \u003c= transaction.exclusivityEndTime\n ) {\n revert ExclusivityPeriodNotPassed();\n }\n }\n}\n","language":"Solidity","languageVersion":"0.8.24","compilerVersion":"0.8.24","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"45745:5018:0:-:0;;;;;;;;;;;;;;;-1:-1:-1;;;45745:5018:0;;;;;;;;;;;;;;;;;","srcMapRuntime":"45745:5018:0:-:0;;;;;;;;","abiDefinition":[{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"currentAllowance","type":"uint256"},{"internalType":"uint256","name":"requestedDecrease","type":"uint256"}],"name":"SafeERC20FailedDecreaseAllowance","type":"error"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"SafeERC20FailedOperation","type":"error"}],"userDoc":{"kind":"user","methods":{},"version":1},"developerDoc":{"details":"Wrappers around ERC20 operations that throw on failure (when the token contract returns false). Tokens that return no value (and instead revert or throw on failure) are also supported, non-reverting calls are assumed to be successful. To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract, which allows you to call the safe operations as `token.safeTransfer(...)`, etc.","errors":{"SafeERC20FailedDecreaseAllowance(address,uint256,uint256)":[{"details":"Indicates a failed `decreaseAllowance` request."}],"SafeERC20FailedOperation(address)":[{"details":"An operation with an ERC20 token failed."}]},"kind":"dev","methods":{},"title":"SafeERC20","version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"currentAllowance\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"requestedDecrease\",\"type\":\"uint256\"}],\"name\":\"SafeERC20FailedDecreaseAllowance\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"}],\"name\":\"SafeERC20FailedOperation\",\"type\":\"error\"}],\"devdoc\":{\"details\":\"Wrappers around ERC20 operations that throw on failure (when the token contract returns false). Tokens that return no value (and instead revert or throw on failure) are also supported, non-reverting calls are assumed to be successful. To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract, which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\",\"errors\":{\"SafeERC20FailedDecreaseAllowance(address,uint256,uint256)\":[{\"details\":\"Indicates a failed `decreaseAllowance` request.\"}],\"SafeERC20FailedOperation(address)\":[{\"details\":\"An operation with an ERC20 token failed.\"}]},\"kind\":\"dev\",\"methods\":{},\"title\":\"SafeERC20\",\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeV2.sol\":\"SafeERC20\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeV2.sol\":{\"keccak256\":\"0x7cd0f885e80e2bdaa638bc32ae7af7d2e248f99ce4b354c217d0f0f7d7302e0a\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://7ccf28df0bd7b4606986585acd8622ed9b4e81379690061bb66088f0a2270af1\",\"dweb:/ipfs/QmTf7HNdHZkK6vmx8ZgewycQEb72oLD9nPwBpsM5reMstQ\"]}},\"version\":1}"},"hashes":{}},"solidity/FastBridgeV2.sol:UniversalTokenLib":{"code":"0x60566037600b82828239805160001a607314602a57634e487b7160e01b600052600060045260246000fd5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600080fdfea2646970667358221220f32c0660d6e44933a56619135234122fa7c42eeae2b3df059ed3d1e4d3c16aa264736f6c63430008180033","runtime-code":"0x73000000000000000000000000000000000000000030146080604052600080fdfea2646970667358221220f32c0660d6e44933a56619135234122fa7c42eeae2b3df059ed3d1e4d3c16aa264736f6c63430008180033","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.24 ^0.8.0 ^0.8.20;\n\n// contracts/interfaces/IAdmin.sol\n\ninterface IAdmin {\n // ============ Events ============\n\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n event ChainGasAmountUpdated(uint256 oldChainGasAmount, uint256 newChainGasAmount);\n\n // ============ Methods ============\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n\n function setChainGasAmount(uint256 newChainGasAmount) external;\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IFastBridgeRecipient.sol\n\ninterface IFastBridgeRecipient {\n function fastBridgeTransferReceived(\n address token,\n uint256 amount,\n bytes memory callParams\n )\n external\n payable\n returns (bytes4);\n}\n\n// contracts/interfaces/IFastBridgeV2Errors.sol\n\ninterface IFastBridgeV2Errors {\n error AmountIncorrect();\n error CallParamsLengthAboveMax();\n error ChainIncorrect();\n error ExclusivityParamsIncorrect();\n error MsgValueIncorrect();\n error NativeTokenCallValueNotSupported();\n error SenderIncorrect();\n error StatusIncorrect();\n error ZeroAddress();\n\n error RecipientIncorrectReturnValue();\n error RecipientNoReturnValue();\n\n error DeadlineExceeded();\n error DeadlineNotExceeded();\n error DeadlineTooShort();\n error DisputePeriodNotPassed();\n error DisputePeriodPassed();\n error ExclusivityPeriodNotPassed();\n\n error TransactionRelayed();\n}\n\n// contracts/libs/Errors.sol\n\nerror DeadlineExceeded();\nerror DeadlineNotExceeded();\nerror DeadlineTooShort();\nerror InsufficientOutputAmount();\n\nerror MsgValueIncorrect();\nerror PoolNotFound();\nerror TokenAddressMismatch();\nerror TokenNotContract();\nerror TokenNotETH();\nerror TokensIdentical();\n\nerror ChainIncorrect();\nerror AmountIncorrect();\nerror ZeroAddress();\n\nerror DisputePeriodNotPassed();\nerror DisputePeriodPassed();\nerror SenderIncorrect();\nerror StatusIncorrect();\nerror TransactionIdIncorrect();\nerror TransactionRelayed();\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// contracts/interfaces/IFastBridgeV2.sol\n\ninterface IFastBridgeV2 is IFastBridge {\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n struct BridgeTxDetails {\n BridgeStatus status;\n uint40 proofBlockTimestamp;\n uint48 proofBlockNumber;\n address proofRelayer;\n }\n\n struct BridgeRelay {\n uint48 blockNumber;\n uint48 blockTimestamp;\n address relayer;\n }\n\n /// @notice New params introduced in the FastBridgeV2.\n /// We are passing fields from the older BridgeParams struct outside of this struct\n /// for backwards compatibility.\n /// Note: quoteRelayer and quoteExclusivitySeconds are either both zero (indicating no exclusivity)\n /// or both non-zero (indicating exclusivity for the given period).\n /// Note: callValue \u003e 0 can NOT be used with destToken = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE (ETH_ADDRESS)\n /// @param quoteRelayer Relayer that provided the quote for the transaction\n /// @param quoteExclusivitySeconds Period of time the quote relayer is guaranteed exclusivity after user's deposit\n /// @param quoteId Unique quote identifier used for tracking the quote\n /// @param callValue ETH value to send to the recipient (if any)\n /// @param callParams Parameters for the arbitrary call to the destination recipient (if any)\n struct BridgeParamsV2 {\n address quoteRelayer;\n int256 quoteExclusivitySeconds;\n bytes quoteId;\n uint256 callValue;\n bytes callParams;\n }\n\n /// @notice Updated bridge transaction struct to include parameters introduced in FastBridgeV2.\n /// Note: only `exclusivityRelayer` can fill such a transaction until `exclusivityEndTime`.\n /// TODO: consider changing the encoding scheme to prevent spending extra gas on decoding.\n struct BridgeTransactionV2 {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n uint256 callValue; // ETH value to send to the recipient (if any) - replaces V1's sendChainGas flag\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n address exclusivityRelayer;\n uint256 exclusivityEndTime;\n bytes callParams;\n }\n\n event BridgeQuoteDetails(bytes32 indexed transactionId, bytes quoteId);\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability\n /// to provide temporary exclusivity fill rights for the quote relayer.\n /// @param params The parameters required to bridge\n /// @param paramsV2 The parameters for exclusivity fill rights (optional, can be left empty)\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function relay(bytes memory request, address relayer) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param transactionId The transaction id associated with the encoded bridge transaction to prove\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital.\n /// @notice Can only send funds to the relayer address on the proof.\n /// @param request The encoded bridge transaction to claim on origin chain\n function claim(bytes memory request) external;\n /// @notice Checks if a transaction has been relayed\n /// @param transactionId The ID of the transaction to check\n /// @return True if the transaction has been relayed, false otherwise\n function bridgeRelays(bytes32 transactionId) external view returns (bool);\n\n /// @notice Returns the status of a bridge transaction\n /// @param transactionId The ID of the bridge transaction\n /// @return BridgeStatus Status of the bridge transaction\n function bridgeStatuses(bytes32 transactionId) external view returns (BridgeStatus);\n\n /// @notice Returns the timestamp and relayer of a bridge proof\n /// @param transactionId The ID of the bridge transaction\n /// @return timestamp The timestamp of the bridge proof\n /// @return relayer The relayer address of the bridge proof\n function bridgeProofs(bytes32 transactionId) external view returns (uint96 timestamp, address relayer);\n\n /// @notice Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\n /// @param request The bridge request to decode\n function getBridgeTransactionV2(bytes memory request) external view returns (BridgeTransactionV2 memory);\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// contracts/libs/UniversalToken.sol\n\nlibrary UniversalTokenLib {\n using SafeERC20 for IERC20;\n\n address internal constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Transfers tokens to the given account. Reverts if transfer is not successful.\n /// @dev This might trigger fallback, if ETH is transferred to the contract.\n /// Make sure this can not lead to reentrancy attacks.\n function universalTransfer(address token, address to, uint256 value) internal {\n // Don't do anything, if need to send tokens to this address\n if (to == address(this)) return;\n // Don't do anything, if trying to send zero value\n if (value == 0) return;\n if (token == ETH_ADDRESS) {\n /// @dev Note: this can potentially lead to executing code in `to`.\n // solhint-disable-next-line avoid-low-level-calls\n (bool success,) = to.call{value: value}(\"\");\n require(success, \"ETH transfer failed\");\n } else {\n IERC20(token).safeTransfer(to, value);\n }\n }\n\n /// @notice Issues an infinite allowance to the spender, if the current allowance is insufficient\n /// to spend the given amount.\n function universalApproveInfinity(address token, address spender, uint256 amountToSpend) internal {\n // ETH Chad doesn't require your approval\n if (token == ETH_ADDRESS) return;\n // No-op if allowance is already sufficient\n uint256 allowance = IERC20(token).allowance(address(this), spender);\n if (allowance \u003e= amountToSpend) return;\n // Otherwise, reset approval to 0 and set to max allowance\n if (allowance \u003e 0) IERC20(token).safeDecreaseAllowance(spender, allowance);\n IERC20(token).safeIncreaseAllowance(spender, type(uint256).max);\n }\n\n /// @notice Returns the balance of the given token (or native ETH) for the given account.\n function universalBalanceOf(address token, address account) internal view returns (uint256) {\n if (token == ETH_ADDRESS) {\n return account.balance;\n } else {\n return IERC20(token).balanceOf(account);\n }\n }\n\n /// @dev Checks that token is a contract and not ETH_ADDRESS.\n function assertIsContract(address token) internal view {\n // Check that ETH_ADDRESS was not used (in case this is a predeploy on any of the chains)\n if (token == UniversalTokenLib.ETH_ADDRESS) revert TokenNotContract();\n // Check that token is not an EOA\n if (token.code.length == 0) revert TokenNotContract();\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/Admin.sol\n\ncontract Admin is IAdmin, AccessControlEnumerable {\n using UniversalTokenLib for address;\n\n bytes32 public constant RELAYER_ROLE = keccak256(\"RELAYER_ROLE\");\n bytes32 public constant REFUNDER_ROLE = keccak256(\"REFUNDER_ROLE\");\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n uint256 public constant FEE_BPS = 1e6;\n uint256 public constant FEE_RATE_MAX = 0.01e6; // max 1% on origin amount\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Chain gas amount to forward as rebate if requested\n uint256 public chainGasAmount;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n }\n\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n require(newFeeRate \u003c= FEE_RATE_MAX, \"newFeeRate \u003e max\");\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n token.universalTransfer(recipient, feeAmount);\n emit FeesSwept(token, recipient, feeAmount);\n }\n\n function setChainGasAmount(uint256 newChainGasAmount) external onlyRole(GOVERNOR_ROLE) {\n uint256 oldChainGasAmount = chainGasAmount;\n chainGasAmount = newChainGasAmount;\n emit ChainGasAmountUpdated(oldChainGasAmount, newChainGasAmount);\n }\n}\n\n// contracts/FastBridgeV2.sol\n\n/// @notice FastBridgeV2 is a contract for bridging tokens across chains.\ncontract FastBridgeV2 is Admin, IFastBridgeV2, IFastBridgeV2Errors {\n using SafeERC20 for IERC20;\n using UniversalTokenLib for address;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Delay for a transaction after which it could be permisionlessly refunded\n uint256 public constant REFUND_DELAY = 7 days;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n /// @notice Maximum length of accepted callParams\n uint256 public constant MAX_CALL_PARAMS_LENGTH = 2 ** 16 - 1;\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeTxDetails) public bridgeTxDetails;\n /// @notice Relay details on destination chain\n mapping(bytes32 =\u003e BridgeRelay) public bridgeRelayDetails;\n /// @notice Unique bridge nonces tracked per originSender\n mapping(address =\u003e uint256) public senderNonces;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Replaced by senderNonces\n uint256 public immutable nonce = 0;\n /// @notice the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n bridge({\n params: params,\n paramsV2: BridgeParamsV2({\n quoteRelayer: address(0),\n quoteExclusivitySeconds: 0,\n quoteId: bytes(\"\"),\n callValue: 0,\n callParams: bytes(\"\")\n })\n });\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes memory request) external payable {\n relay({request: request, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes memory request, bytes32 destTxHash) external {\n prove({transactionId: keccak256(request), destTxHash: destTxHash, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridgeV2\n function claim(bytes memory request) external {\n claim({request: request, to: address(0)});\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003e DISPUTE_PERIOD) {\n revert DisputePeriodPassed();\n }\n\n // @dev relayer gets slashed effectively if dest relay has gone thru\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n bridgeTxDetails[transactionId].proofRelayer = address(0);\n bridgeTxDetails[transactionId].proofBlockTimestamp = 0;\n bridgeTxDetails[transactionId].proofBlockNumber = 0;\n\n emit BridgeProofDisputed(transactionId, msg.sender);\n }\n\n /// @inheritdoc IFastBridge\n function refund(bytes memory request) external {\n bytes32 transactionId = keccak256(request);\n\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n\n if (bridgeTxDetails[transactionId].status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n\n if (hasRole(REFUNDER_ROLE, msg.sender)) {\n // Refunder can refund if deadline has passed\n if (block.timestamp \u003c= transaction.deadline) revert DeadlineNotExceeded();\n } else {\n // Permissionless refund is allowed after REFUND_DELAY\n if (block.timestamp \u003c= transaction.deadline + REFUND_DELAY) revert DeadlineNotExceeded();\n }\n\n // if all checks passed, set to REFUNDED status\n bridgeTxDetails[transactionId].status = BridgeStatus.REFUNDED;\n\n // transfer origin collateral back to original sender\n address to = transaction.originSender;\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount + transaction.originFeeAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (bridgeTxDetails[transactionId].proofRelayer != relayer) revert SenderIncorrect();\n return _timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n /// @dev This method is added to achieve backwards compatibility with decoding requests into V1 structs:\n /// - `callValue` is partially reported as a zero/non-zero flag\n /// - `callParams` is ignored\n /// In order to process all kinds of requests use getBridgeTransactionV2 instead.\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory) {\n // Try decoding into V2 struct first. This will revert if V1 struct is passed\n try this.getBridgeTransactionV2(request) returns (BridgeTransactionV2 memory txV2) {\n // Note: we entirely ignore the callParams field, as it was not present in V1\n return BridgeTransaction({\n originChainId: txV2.originChainId,\n destChainId: txV2.destChainId,\n originSender: txV2.originSender,\n destRecipient: txV2.destRecipient,\n originToken: txV2.originToken,\n destToken: txV2.destToken,\n originAmount: txV2.originAmount,\n destAmount: txV2.destAmount,\n originFeeAmount: txV2.originFeeAmount,\n sendChainGas: txV2.callValue != 0,\n deadline: txV2.deadline,\n nonce: txV2.nonce\n });\n } catch {\n // Fallback to V1 struct\n return abi.decode(request, (BridgeTransaction));\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) public payable {\n int256 exclusivityEndTime = int256(block.timestamp) + paramsV2.quoteExclusivitySeconds;\n _validateBridgeParams(params, paramsV2, exclusivityEndTime);\n\n // transfer tokens to bridge contract\n /// @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _pullToken(params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n\n // set status to requested\n bytes memory request = abi.encode(\n BridgeTransactionV2({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n callValue: paramsV2.callValue,\n deadline: params.deadline,\n nonce: senderNonces[params.sender]++, // increment nonce on every bridge\n exclusivityRelayer: paramsV2.quoteRelayer,\n // We checked exclusivityEndTime to be in range (0 .. params.deadline] above, so can safely cast\n exclusivityEndTime: uint256(exclusivityEndTime),\n callParams: paramsV2.callParams\n })\n );\n bytes32 transactionId = keccak256(request);\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n\n emit BridgeRequested({\n transactionId: transactionId,\n sender: params.sender,\n request: request,\n destChainId: params.dstChainId,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n sendChainGas: paramsV2.callValue != 0\n });\n emit BridgeQuoteDetails(transactionId, paramsV2.quoteId);\n }\n\n /// @inheritdoc IFastBridgeV2\n function relay(bytes memory request, address relayer) public payable {\n bytes32 transactionId = keccak256(request);\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n _validateRelayParams(transaction, transactionId, relayer);\n // mark bridge transaction as relayed\n bridgeRelayDetails[transactionId] =\n BridgeRelay({blockNumber: uint48(block.number), blockTimestamp: uint48(block.timestamp), relayer: relayer});\n\n // transfer tokens to recipient on destination chain and do an arbitrary call if requested\n address to = transaction.destRecipient;\n address token = transaction.destToken;\n uint256 amount = transaction.destAmount;\n\n // All state changes have been done at this point, can proceed to the external calls.\n // This follows the checks-effects-interactions pattern to mitigate potential reentrancy attacks.\n if (token == UniversalTokenLib.ETH_ADDRESS) {\n // For ETH non-zero callValue is not allowed\n if (transaction.callValue != 0) revert NativeTokenCallValueNotSupported();\n // Check that the correct msg.value was sent\n if (msg.value != amount) revert MsgValueIncorrect();\n } else {\n // For ERC20s, we check that the correct msg.value was sent\n if (msg.value != transaction.callValue) revert MsgValueIncorrect();\n // We need to transfer the tokens from the Relayer to the recipient first before performing an\n // optional post-transfer arbitrary call.\n IERC20(token).safeTransferFrom(msg.sender, to, amount);\n }\n\n if (transaction.callParams.length != 0) {\n // Arbitrary call requested, perform it while supplying full msg.value to the recipient\n // Note: if token has a fee on transfers, the recipient will have received less than `amount`.\n // This is a very niche edge case and should be handled by the recipient contract.\n _checkedCallRecipient({recipient: to, token: token, amount: amount, callParams: transaction.callParams});\n } else if (msg.value != 0) {\n // No arbitrary call requested, but msg.value was sent. This is either a relay with ETH,\n // or a non-zero callValue request with an ERC20. In both cases, transfer the ETH to the recipient.\n Address.sendValue(payable(to), msg.value);\n }\n\n emit BridgeRelayed({\n transactionId: transactionId,\n relayer: relayer,\n to: to,\n originChainId: transaction.originChainId,\n originToken: transaction.originToken,\n destToken: transaction.destToken,\n originAmount: transaction.originAmount,\n destAmount: transaction.destAmount,\n chainGasAmount: transaction.callValue\n });\n }\n\n /// @inheritdoc IFastBridgeV2\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) public onlyRole(RELAYER_ROLE) {\n // update bridge tx status given proof provided\n if (bridgeTxDetails[transactionId].status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n bridgeTxDetails[transactionId].status = BridgeStatus.RELAYER_PROVED;\n bridgeTxDetails[transactionId].proofBlockTimestamp = uint40(block.timestamp);\n bridgeTxDetails[transactionId].proofBlockNumber = uint48(block.number);\n bridgeTxDetails[transactionId].proofRelayer = relayer;\n\n emit BridgeProofProvided(transactionId, relayer, destTxHash);\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes memory request, address to) public {\n bytes32 transactionId = keccak256(request);\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n\n // update bridge tx status if able to claim origin collateral\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n\n // if \"to\" is zero addr, permissionlessly send funds to proven relayer\n if (to == address(0)) {\n to = bridgeTxDetails[transactionId].proofRelayer;\n } else if (bridgeTxDetails[transactionId].proofRelayer != msg.sender) {\n revert SenderIncorrect();\n }\n\n if (_timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003c= DISPUTE_PERIOD) {\n revert DisputePeriodNotPassed();\n }\n\n bridgeTxDetails[transactionId].status = BridgeStatus.RELAYER_CLAIMED;\n\n // update protocol fees if origin fee amount exists\n if (transaction.originFeeAmount \u003e 0) protocolFees[transaction.originToken] += transaction.originFeeAmount;\n\n // transfer origin collateral less fee to specified address\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositClaimed(transactionId, bridgeTxDetails[transactionId].proofRelayer, to, token, amount);\n }\n\n function bridgeStatuses(bytes32 transactionId) public view returns (BridgeStatus status) {\n return bridgeTxDetails[transactionId].status;\n }\n\n function bridgeProofs(bytes32 transactionId) public view returns (uint96 timestamp, address relayer) {\n timestamp = bridgeTxDetails[transactionId].proofBlockTimestamp;\n relayer = bridgeTxDetails[transactionId].proofRelayer;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeRelays(bytes32 transactionId) public view returns (bool) {\n // has this transactionId been relayed?\n return bridgeRelayDetails[transactionId].relayer != address(0);\n }\n\n /// @inheritdoc IFastBridgeV2\n function getBridgeTransactionV2(bytes memory request) public pure returns (BridgeTransactionV2 memory) {\n return abi.decode(request, (BridgeTransactionV2));\n }\n\n /// @notice Pulls a requested token from the user to this contract.\n function _pullToken(address token, uint256 amount) internal returns (uint256 amountPulled) {\n if (token == UniversalTokenLib.ETH_ADDRESS) {\n // For ETH we just need to check that the supplied msg.value is correct\n if (amount != msg.value) revert MsgValueIncorrect();\n amountPulled = msg.value;\n } else {\n token.assertIsContract();\n // Record token balance before transfer\n amountPulled = IERC20(token).balanceOf(address(this));\n // Token needs to be pulled only if msg.value is zero\n // This way user can specify WETH as the origin asset\n IERC20(token).safeTransferFrom(msg.sender, address(this), amount);\n // Use the difference between the recorded balance and the current balance as the amountPulled\n amountPulled = IERC20(token).balanceOf(address(this)) - amountPulled;\n }\n }\n\n /// @notice Calls the Recipient's hook function with the specified callParams and performs\n /// all the necessary checks for the returned value.\n function _checkedCallRecipient(\n address recipient,\n address token,\n uint256 amount,\n bytes memory callParams\n )\n internal\n {\n bytes memory hookData =\n abi.encodeCall(IFastBridgeRecipient.fastBridgeTransferReceived, (token, amount, callParams));\n // This will bubble any revert messages from the hook function\n bytes memory returnData = Address.functionCallWithValue({target: recipient, data: hookData, value: msg.value});\n // Explicit revert if no return data at all\n if (returnData.length == 0) revert RecipientNoReturnValue();\n // Check that exactly a single return value was returned\n if (returnData.length != 32) revert RecipientIncorrectReturnValue();\n // Return value should be abi-encoded hook function selector\n if (bytes32(returnData) != bytes32(IFastBridgeRecipient.fastBridgeTransferReceived.selector)) {\n revert RecipientIncorrectReturnValue();\n }\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint40(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint40).max but\n /// proof.timestamp \u003c type(uint40).max via unchecked statement\n /// @param proofBlockTimestamp The bridge proof block timestamp\n /// @return delta Time delta since proof submitted\n function _timeSince(uint40 proofBlockTimestamp) internal view returns (uint256 delta) {\n unchecked {\n delta = uint40(block.timestamp) - proofBlockTimestamp;\n }\n }\n\n /// @notice Performs all the necessary checks for a bridge to happen.\n /// @dev There's no good way to refactor this function to reduce cyclomatic complexity due to\n /// the number of checks that need to be performed, so we skip the code-complexity rule here.\n // solhint-disable-next-line code-complexity\n function _validateBridgeParams(\n BridgeParams memory params,\n BridgeParamsV2 memory paramsV2,\n int256 exclusivityEndTime\n )\n internal\n view\n {\n // Check V1 (legacy) params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.sender == address(0) || params.to == address(0)) revert ZeroAddress();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n // Check V2 params\n if (paramsV2.callParams.length \u003e MAX_CALL_PARAMS_LENGTH) revert CallParamsLengthAboveMax();\n if (paramsV2.callValue != 0 \u0026\u0026 params.destToken == UniversalTokenLib.ETH_ADDRESS) {\n revert NativeTokenCallValueNotSupported();\n }\n // exclusivityEndTime must be in range (0 .. params.deadline]\n if (exclusivityEndTime \u003c= 0 || exclusivityEndTime \u003e int256(params.deadline)) {\n revert ExclusivityParamsIncorrect();\n }\n }\n\n /// @notice Performs all the necessary checks for a relay to happen.\n function _validateRelayParams(\n BridgeTransactionV2 memory transaction,\n bytes32 transactionId,\n address relayer\n )\n internal\n view\n {\n if (relayer == address(0)) revert ZeroAddress();\n // Check if the transaction has already been relayed\n if (bridgeRelays(transactionId)) revert TransactionRelayed();\n if (transaction.destChainId != uint32(block.chainid)) revert ChainIncorrect();\n // Check the deadline for relay to happen\n if (block.timestamp \u003e transaction.deadline) revert DeadlineExceeded();\n // Check the exclusivity period, if it is still ongoing\n // forgefmt: disable-next-item\n if (\n transaction.exclusivityRelayer != address(0) \u0026\u0026\n transaction.exclusivityRelayer != relayer \u0026\u0026\n block.timestamp \u003c= transaction.exclusivityEndTime\n ) {\n revert ExclusivityPeriodNotPassed();\n }\n }\n}\n","language":"Solidity","languageVersion":"0.8.24","compilerVersion":"0.8.24","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"57704:2551:0:-:0;;;;;;;;;;;;;;;-1:-1:-1;;;57704:2551:0;;;;;;;;;;;;;;;;;","srcMapRuntime":"57704:2551:0:-:0;;;;;;;;","abiDefinition":[],"userDoc":{"kind":"user","methods":{},"version":1},"developerDoc":{"kind":"dev","methods":{},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[],\"devdoc\":{\"kind\":\"dev\",\"methods\":{},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeV2.sol\":\"UniversalTokenLib\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeV2.sol\":{\"keccak256\":\"0x7cd0f885e80e2bdaa638bc32ae7af7d2e248f99ce4b354c217d0f0f7d7302e0a\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://7ccf28df0bd7b4606986585acd8622ed9b4e81379690061bb66088f0a2270af1\",\"dweb:/ipfs/QmTf7HNdHZkK6vmx8ZgewycQEb72oLD9nPwBpsM5reMstQ\"]}},\"version\":1}"},"hashes":{}}} \ No newline at end of file +{"solidity/FastBridgeV2.sol:AccessControl":{"code":"0x","runtime-code":"0x","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.24 ^0.8.0 ^0.8.20;\n\n// contracts/interfaces/IAdmin.sol\n\ninterface IAdmin {\n // ============ Events ============\n\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n event ChainGasAmountUpdated(uint256 oldChainGasAmount, uint256 newChainGasAmount);\n\n // ============ Methods ============\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n\n function setChainGasAmount(uint256 newChainGasAmount) external;\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IFastBridgeRecipient.sol\n\ninterface IFastBridgeRecipient {\n function fastBridgeTransferReceived(\n address token,\n uint256 amount,\n bytes memory callParams\n )\n external\n payable\n returns (bytes4);\n}\n\n// contracts/interfaces/IFastBridgeV2Errors.sol\n\ninterface IFastBridgeV2Errors {\n error AmountIncorrect();\n error CallParamsLengthAboveMax();\n error ChainIncorrect();\n error ExclusivityParamsIncorrect();\n error MsgValueIncorrect();\n error NativeTokenCallValueNotSupported();\n error SenderIncorrect();\n error StatusIncorrect();\n error ZeroAddress();\n\n error RecipientIncorrectReturnValue();\n error RecipientNoReturnValue();\n\n error DeadlineExceeded();\n error DeadlineNotExceeded();\n error DeadlineTooShort();\n error DisputePeriodNotPassed();\n error DisputePeriodPassed();\n error ExclusivityPeriodNotPassed();\n\n error TransactionRelayed();\n}\n\n// contracts/libs/Errors.sol\n\nerror DeadlineExceeded();\nerror DeadlineNotExceeded();\nerror DeadlineTooShort();\nerror InsufficientOutputAmount();\n\nerror MsgValueIncorrect();\nerror PoolNotFound();\nerror TokenAddressMismatch();\nerror TokenNotContract();\nerror TokenNotETH();\nerror TokensIdentical();\n\nerror ChainIncorrect();\nerror AmountIncorrect();\nerror ZeroAddress();\n\nerror DisputePeriodNotPassed();\nerror DisputePeriodPassed();\nerror SenderIncorrect();\nerror StatusIncorrect();\nerror TransactionIdIncorrect();\nerror TransactionRelayed();\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// contracts/interfaces/IFastBridgeV2.sol\n\ninterface IFastBridgeV2 is IFastBridge {\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n struct BridgeTxDetails {\n BridgeStatus status;\n uint40 proofBlockTimestamp;\n uint48 proofBlockNumber;\n address proofRelayer;\n }\n\n struct BridgeRelay {\n uint48 blockNumber;\n uint48 blockTimestamp;\n address relayer;\n }\n\n /// @notice New params introduced in the FastBridgeV2.\n /// We are passing fields from the older BridgeParams struct outside of this struct\n /// for backwards compatibility.\n /// Note: quoteRelayer and quoteExclusivitySeconds are either both zero (indicating no exclusivity)\n /// or both non-zero (indicating exclusivity for the given period).\n /// Note: callValue \u003e 0 can NOT be used with destToken = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE (ETH_ADDRESS)\n /// @param quoteRelayer Relayer that provided the quote for the transaction\n /// @param quoteExclusivitySeconds Period of time the quote relayer is guaranteed exclusivity after user's deposit\n /// @param quoteId Unique quote identifier used for tracking the quote\n /// @param callValue ETH value to send to the recipient (if any)\n /// @param callParams Parameters for the arbitrary call to the destination recipient (if any)\n struct BridgeParamsV2 {\n address quoteRelayer;\n int256 quoteExclusivitySeconds;\n bytes quoteId;\n uint256 callValue;\n bytes callParams;\n }\n\n /// @notice Updated bridge transaction struct to include parameters introduced in FastBridgeV2.\n /// Note: only `exclusivityRelayer` can fill such a transaction until `exclusivityEndTime`.\n /// TODO: consider changing the encoding scheme to prevent spending extra gas on decoding.\n struct BridgeTransactionV2 {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n uint256 callValue; // ETH value to send to the recipient (if any) - replaces V1's sendChainGas flag\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n address exclusivityRelayer;\n uint256 exclusivityEndTime;\n bytes callParams;\n }\n\n event BridgeQuoteDetails(bytes32 indexed transactionId, bytes quoteId);\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability\n /// to provide temporary exclusivity fill rights for the quote relayer.\n /// @param params The parameters required to bridge\n /// @param paramsV2 The parameters for exclusivity fill rights (optional, can be left empty)\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function relay(bytes memory request, address relayer) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param transactionId The transaction id associated with the encoded bridge transaction to prove\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital.\n /// @notice Can only send funds to the relayer address on the proof.\n /// @param request The encoded bridge transaction to claim on origin chain\n function claim(bytes memory request) external;\n /// @notice Checks if a transaction has been relayed\n /// @param transactionId The ID of the transaction to check\n /// @return True if the transaction has been relayed, false otherwise\n function bridgeRelays(bytes32 transactionId) external view returns (bool);\n\n /// @notice Returns the status of a bridge transaction\n /// @param transactionId The ID of the bridge transaction\n /// @return BridgeStatus Status of the bridge transaction\n function bridgeStatuses(bytes32 transactionId) external view returns (BridgeStatus);\n\n /// @notice Returns the timestamp and relayer of a bridge proof\n /// @param transactionId The ID of the bridge transaction\n /// @return timestamp The timestamp of the bridge proof\n /// @return relayer The relayer address of the bridge proof\n function bridgeProofs(bytes32 transactionId) external view returns (uint96 timestamp, address relayer);\n\n /// @notice Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\n /// @param request The bridge request to decode\n function getBridgeTransactionV2(bytes memory request) external view returns (BridgeTransactionV2 memory);\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// contracts/libs/UniversalToken.sol\n\nlibrary UniversalTokenLib {\n using SafeERC20 for IERC20;\n\n address internal constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Transfers tokens to the given account. Reverts if transfer is not successful.\n /// @dev This might trigger fallback, if ETH is transferred to the contract.\n /// Make sure this can not lead to reentrancy attacks.\n function universalTransfer(address token, address to, uint256 value) internal {\n // Don't do anything, if need to send tokens to this address\n if (to == address(this)) return;\n // Don't do anything, if trying to send zero value\n if (value == 0) return;\n if (token == ETH_ADDRESS) {\n /// @dev Note: this can potentially lead to executing code in `to`.\n // solhint-disable-next-line avoid-low-level-calls\n (bool success,) = to.call{value: value}(\"\");\n require(success, \"ETH transfer failed\");\n } else {\n IERC20(token).safeTransfer(to, value);\n }\n }\n\n /// @notice Issues an infinite allowance to the spender, if the current allowance is insufficient\n /// to spend the given amount.\n function universalApproveInfinity(address token, address spender, uint256 amountToSpend) internal {\n // ETH Chad doesn't require your approval\n if (token == ETH_ADDRESS) return;\n // No-op if allowance is already sufficient\n uint256 allowance = IERC20(token).allowance(address(this), spender);\n if (allowance \u003e= amountToSpend) return;\n // Otherwise, reset approval to 0 and set to max allowance\n if (allowance \u003e 0) IERC20(token).safeDecreaseAllowance(spender, allowance);\n IERC20(token).safeIncreaseAllowance(spender, type(uint256).max);\n }\n\n /// @notice Returns the balance of the given token (or native ETH) for the given account.\n function universalBalanceOf(address token, address account) internal view returns (uint256) {\n if (token == ETH_ADDRESS) {\n return account.balance;\n } else {\n return IERC20(token).balanceOf(account);\n }\n }\n\n /// @dev Checks that token is a contract and not ETH_ADDRESS.\n function assertIsContract(address token) internal view {\n // Check that ETH_ADDRESS was not used (in case this is a predeploy on any of the chains)\n if (token == UniversalTokenLib.ETH_ADDRESS) revert TokenNotContract();\n // Check that token is not an EOA\n if (token.code.length == 0) revert TokenNotContract();\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/Admin.sol\n\ncontract Admin is IAdmin, AccessControlEnumerable {\n using UniversalTokenLib for address;\n\n bytes32 public constant RELAYER_ROLE = keccak256(\"RELAYER_ROLE\");\n bytes32 public constant REFUNDER_ROLE = keccak256(\"REFUNDER_ROLE\");\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n uint256 public constant FEE_BPS = 1e6;\n uint256 public constant FEE_RATE_MAX = 0.01e6; // max 1% on origin amount\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Chain gas amount to forward as rebate if requested\n uint256 public chainGasAmount;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n }\n\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n require(newFeeRate \u003c= FEE_RATE_MAX, \"newFeeRate \u003e max\");\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n token.universalTransfer(recipient, feeAmount);\n emit FeesSwept(token, recipient, feeAmount);\n }\n\n function setChainGasAmount(uint256 newChainGasAmount) external onlyRole(GOVERNOR_ROLE) {\n uint256 oldChainGasAmount = chainGasAmount;\n chainGasAmount = newChainGasAmount;\n emit ChainGasAmountUpdated(oldChainGasAmount, newChainGasAmount);\n }\n}\n\n// contracts/FastBridgeV2.sol\n\n/// @notice FastBridgeV2 is a contract for bridging tokens across chains.\ncontract FastBridgeV2 is Admin, IFastBridgeV2, IFastBridgeV2Errors {\n using SafeERC20 for IERC20;\n using UniversalTokenLib for address;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Delay for a transaction after which it could be permisionlessly refunded\n uint256 public constant REFUND_DELAY = 7 days;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n /// @notice Maximum length of accepted callParams\n uint256 public constant MAX_CALL_PARAMS_LENGTH = 2 ** 16 - 1;\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeTxDetails) public bridgeTxDetails;\n /// @notice Relay details on destination chain\n mapping(bytes32 =\u003e BridgeRelay) public bridgeRelayDetails;\n /// @notice Unique bridge nonces tracked per originSender\n mapping(address =\u003e uint256) public senderNonces;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Replaced by senderNonces\n uint256 public immutable nonce = 0;\n /// @notice the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n bridge({\n params: params,\n paramsV2: BridgeParamsV2({\n quoteRelayer: address(0),\n quoteExclusivitySeconds: 0,\n quoteId: bytes(\"\"),\n callValue: 0,\n callParams: bytes(\"\")\n })\n });\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes memory request) external payable {\n relay({request: request, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes memory request, bytes32 destTxHash) external {\n prove({transactionId: keccak256(request), destTxHash: destTxHash, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridgeV2\n function claim(bytes memory request) external {\n claim({request: request, to: address(0)});\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003e DISPUTE_PERIOD) {\n revert DisputePeriodPassed();\n }\n\n // @dev relayer gets slashed effectively if dest relay has gone thru\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n bridgeTxDetails[transactionId].proofRelayer = address(0);\n bridgeTxDetails[transactionId].proofBlockTimestamp = 0;\n bridgeTxDetails[transactionId].proofBlockNumber = 0;\n\n emit BridgeProofDisputed(transactionId, msg.sender);\n }\n\n /// @inheritdoc IFastBridge\n function refund(bytes memory request) external {\n bytes32 transactionId = keccak256(request);\n\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n\n if (bridgeTxDetails[transactionId].status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n\n if (hasRole(REFUNDER_ROLE, msg.sender)) {\n // Refunder can refund if deadline has passed\n if (block.timestamp \u003c= transaction.deadline) revert DeadlineNotExceeded();\n } else {\n // Permissionless refund is allowed after REFUND_DELAY\n if (block.timestamp \u003c= transaction.deadline + REFUND_DELAY) revert DeadlineNotExceeded();\n }\n\n // if all checks passed, set to REFUNDED status\n bridgeTxDetails[transactionId].status = BridgeStatus.REFUNDED;\n\n // transfer origin collateral back to original sender\n address to = transaction.originSender;\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount + transaction.originFeeAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (bridgeTxDetails[transactionId].proofRelayer != relayer) revert SenderIncorrect();\n return _timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n /// @dev This method is added to achieve backwards compatibility with decoding requests into V1 structs:\n /// - `callValue` is partially reported as a zero/non-zero flag\n /// - `callParams` is ignored\n /// In order to process all kinds of requests use getBridgeTransactionV2 instead.\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory) {\n // Try decoding into V2 struct first. This will revert if V1 struct is passed\n try this.getBridgeTransactionV2(request) returns (BridgeTransactionV2 memory txV2) {\n // Note: we entirely ignore the callParams field, as it was not present in V1\n return BridgeTransaction({\n originChainId: txV2.originChainId,\n destChainId: txV2.destChainId,\n originSender: txV2.originSender,\n destRecipient: txV2.destRecipient,\n originToken: txV2.originToken,\n destToken: txV2.destToken,\n originAmount: txV2.originAmount,\n destAmount: txV2.destAmount,\n originFeeAmount: txV2.originFeeAmount,\n sendChainGas: txV2.callValue != 0,\n deadline: txV2.deadline,\n nonce: txV2.nonce\n });\n } catch {\n // Fallback to V1 struct\n return abi.decode(request, (BridgeTransaction));\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) public payable {\n int256 exclusivityEndTime = int256(block.timestamp) + paramsV2.quoteExclusivitySeconds;\n _validateBridgeParams(params, paramsV2, exclusivityEndTime);\n\n // transfer tokens to bridge contract\n /// @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _takeBridgedUserAsset(params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n\n // set status to requested\n bytes memory request = abi.encode(\n BridgeTransactionV2({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n callValue: paramsV2.callValue,\n deadline: params.deadline,\n nonce: senderNonces[params.sender]++, // increment nonce on every bridge\n exclusivityRelayer: paramsV2.quoteRelayer,\n // We checked exclusivityEndTime to be in range (0 .. params.deadline] above, so can safely cast\n exclusivityEndTime: uint256(exclusivityEndTime),\n callParams: paramsV2.callParams\n })\n );\n bytes32 transactionId = keccak256(request);\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n\n emit BridgeRequested({\n transactionId: transactionId,\n sender: params.sender,\n request: request,\n destChainId: params.dstChainId,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n sendChainGas: paramsV2.callValue != 0\n });\n emit BridgeQuoteDetails(transactionId, paramsV2.quoteId);\n }\n\n /// @inheritdoc IFastBridgeV2\n function relay(bytes memory request, address relayer) public payable {\n bytes32 transactionId = keccak256(request);\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n _validateRelayParams(transaction, transactionId, relayer);\n // mark bridge transaction as relayed\n bridgeRelayDetails[transactionId] =\n BridgeRelay({blockNumber: uint48(block.number), blockTimestamp: uint48(block.timestamp), relayer: relayer});\n\n // transfer tokens to recipient on destination chain and do an arbitrary call if requested\n address to = transaction.destRecipient;\n address token = transaction.destToken;\n uint256 amount = transaction.destAmount;\n uint256 callValue = transaction.callValue;\n\n // Emit the event before any external calls\n emit BridgeRelayed({\n transactionId: transactionId,\n relayer: relayer,\n to: to,\n originChainId: transaction.originChainId,\n originToken: transaction.originToken,\n destToken: token,\n originAmount: transaction.originAmount,\n destAmount: amount,\n chainGasAmount: callValue\n });\n\n // All state changes have been done at this point, can proceed to the external calls.\n // This follows the checks-effects-interactions pattern to mitigate potential reentrancy attacks.\n if (token == UniversalTokenLib.ETH_ADDRESS) {\n // For ETH non-zero callValue is not allowed\n if (callValue != 0) revert NativeTokenCallValueNotSupported();\n // Check that the correct msg.value was sent\n if (msg.value != amount) revert MsgValueIncorrect();\n } else {\n // For ERC20s, we check that the correct msg.value was sent\n if (msg.value != callValue) revert MsgValueIncorrect();\n // We need to transfer the tokens from the Relayer to the recipient first before performing an\n // optional post-transfer arbitrary call.\n IERC20(token).safeTransferFrom(msg.sender, to, amount);\n }\n\n if (transaction.callParams.length != 0) {\n // Arbitrary call requested, perform it while supplying full msg.value to the recipient\n // Note: if token has a fee on transfers, the recipient will have received less than `amount`.\n // This is a very niche edge case and should be handled by the recipient contract.\n _checkedCallRecipient({recipient: to, token: token, amount: amount, callParams: transaction.callParams});\n } else if (msg.value != 0) {\n // No arbitrary call requested, but msg.value was sent. This is either a relay with ETH,\n // or a non-zero callValue request with an ERC20. In both cases, transfer the ETH to the recipient.\n Address.sendValue(payable(to), msg.value);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) public onlyRole(RELAYER_ROLE) {\n // update bridge tx status given proof provided\n if (bridgeTxDetails[transactionId].status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n bridgeTxDetails[transactionId].status = BridgeStatus.RELAYER_PROVED;\n bridgeTxDetails[transactionId].proofBlockTimestamp = uint40(block.timestamp);\n bridgeTxDetails[transactionId].proofBlockNumber = uint48(block.number);\n bridgeTxDetails[transactionId].proofRelayer = relayer;\n\n emit BridgeProofProvided(transactionId, relayer, destTxHash);\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes memory request, address to) public {\n bytes32 transactionId = keccak256(request);\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n\n // update bridge tx status if able to claim origin collateral\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n\n // if \"to\" is zero addr, permissionlessly send funds to proven relayer\n if (to == address(0)) {\n to = bridgeTxDetails[transactionId].proofRelayer;\n } else if (bridgeTxDetails[transactionId].proofRelayer != msg.sender) {\n revert SenderIncorrect();\n }\n\n if (_timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003c= DISPUTE_PERIOD) {\n revert DisputePeriodNotPassed();\n }\n\n bridgeTxDetails[transactionId].status = BridgeStatus.RELAYER_CLAIMED;\n\n // update protocol fees if origin fee amount exists\n if (transaction.originFeeAmount \u003e 0) protocolFees[transaction.originToken] += transaction.originFeeAmount;\n\n // transfer origin collateral less fee to specified address\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositClaimed(transactionId, bridgeTxDetails[transactionId].proofRelayer, to, token, amount);\n }\n\n function bridgeStatuses(bytes32 transactionId) public view returns (BridgeStatus status) {\n return bridgeTxDetails[transactionId].status;\n }\n\n function bridgeProofs(bytes32 transactionId) public view returns (uint96 timestamp, address relayer) {\n timestamp = bridgeTxDetails[transactionId].proofBlockTimestamp;\n relayer = bridgeTxDetails[transactionId].proofRelayer;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeRelays(bytes32 transactionId) public view returns (bool) {\n // has this transactionId been relayed?\n return bridgeRelayDetails[transactionId].relayer != address(0);\n }\n\n /// @inheritdoc IFastBridgeV2\n function getBridgeTransactionV2(bytes memory request) public pure returns (BridgeTransactionV2 memory) {\n return abi.decode(request, (BridgeTransactionV2));\n }\n\n /// @notice Takes the bridged asset from the user into FastBridgeV2 custody. It will be later\n /// claimed by the relayer who completed the relay on destination chain, or refunded back to the user,\n /// should no one complete the relay.\n function _takeBridgedUserAsset(address token, uint256 amount) internal returns (uint256 amountTaken) {\n if (token == UniversalTokenLib.ETH_ADDRESS) {\n // For ETH we just need to check that the supplied msg.value is correct.\n // Supplied `msg.value` is already in FastBridgeV2 custody.\n if (amount != msg.value) revert MsgValueIncorrect();\n amountTaken = msg.value;\n } else {\n // For ERC20s, token is explicitly transferred from the user to FastBridgeV2.\n // We don't allow non-zero `msg.value` to avoid extra funds from being stuck in FastBridgeV2.\n token.assertIsContract();\n if (msg.value != 0) revert MsgValueIncorrect();\n amountTaken = IERC20(token).balanceOf(address(this));\n IERC20(token).safeTransferFrom(msg.sender, address(this), amount);\n // Use the balance difference as the amount taken in case of fee on transfer tokens.\n amountTaken = IERC20(token).balanceOf(address(this)) - amountTaken;\n }\n }\n\n /// @notice Calls the Recipient's hook function with the specified callParams and performs\n /// all the necessary checks for the returned value.\n function _checkedCallRecipient(\n address recipient,\n address token,\n uint256 amount,\n bytes memory callParams\n )\n internal\n {\n bytes memory hookData =\n abi.encodeCall(IFastBridgeRecipient.fastBridgeTransferReceived, (token, amount, callParams));\n // This will bubble any revert messages from the hook function\n bytes memory returnData = Address.functionCallWithValue({target: recipient, data: hookData, value: msg.value});\n // Explicit revert if no return data at all\n if (returnData.length == 0) revert RecipientNoReturnValue();\n // Check that exactly a single return value was returned\n if (returnData.length != 32) revert RecipientIncorrectReturnValue();\n // Return value should be abi-encoded hook function selector\n if (bytes32(returnData) != bytes32(IFastBridgeRecipient.fastBridgeTransferReceived.selector)) {\n revert RecipientIncorrectReturnValue();\n }\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint40(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint40).max but\n /// proof.timestamp \u003c type(uint40).max via unchecked statement\n /// @param proofBlockTimestamp The bridge proof block timestamp\n /// @return delta Time delta since proof submitted\n function _timeSince(uint40 proofBlockTimestamp) internal view returns (uint256 delta) {\n unchecked {\n delta = uint40(block.timestamp) - proofBlockTimestamp;\n }\n }\n\n /// @notice Performs all the necessary checks for a bridge to happen.\n /// @dev There's no good way to refactor this function to reduce cyclomatic complexity due to\n /// the number of checks that need to be performed, so we skip the code-complexity rule here.\n // solhint-disable-next-line code-complexity\n function _validateBridgeParams(\n BridgeParams memory params,\n BridgeParamsV2 memory paramsV2,\n int256 exclusivityEndTime\n )\n internal\n view\n {\n // Check V1 (legacy) params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.sender == address(0) || params.to == address(0)) revert ZeroAddress();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n // Check V2 params\n if (paramsV2.callParams.length \u003e MAX_CALL_PARAMS_LENGTH) revert CallParamsLengthAboveMax();\n if (paramsV2.callValue != 0 \u0026\u0026 params.destToken == UniversalTokenLib.ETH_ADDRESS) {\n revert NativeTokenCallValueNotSupported();\n }\n // exclusivityEndTime must be in range (0 .. params.deadline]\n if (exclusivityEndTime \u003c= 0 || exclusivityEndTime \u003e int256(params.deadline)) {\n revert ExclusivityParamsIncorrect();\n }\n }\n\n /// @notice Performs all the necessary checks for a relay to happen.\n function _validateRelayParams(\n BridgeTransactionV2 memory transaction,\n bytes32 transactionId,\n address relayer\n )\n internal\n view\n {\n if (relayer == address(0)) revert ZeroAddress();\n // Check if the transaction has already been relayed\n if (bridgeRelays(transactionId)) revert TransactionRelayed();\n if (transaction.destChainId != block.chainid) revert ChainIncorrect();\n // Check the deadline for relay to happen\n if (block.timestamp \u003e transaction.deadline) revert DeadlineExceeded();\n // Check the exclusivity period, if it is still ongoing\n // forgefmt: disable-next-item\n if (\n transaction.exclusivityRelayer != address(0) \u0026\u0026\n transaction.exclusivityRelayer != relayer \u0026\u0026\n block.timestamp \u003c= transaction.exclusivityEndTime\n ) {\n revert ExclusivityPeriodNotPassed();\n }\n }\n}\n","language":"Solidity","languageVersion":"0.8.24","compilerVersion":"0.8.24","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"","srcMapRuntime":"","abiDefinition":[{"inputs":[],"name":"AccessControlBadConfirmation","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"bytes32","name":"neededRole","type":"bytes32"}],"name":"AccessControlUnauthorizedAccount","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"previousAdminRole","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"newAdminRole","type":"bytes32"}],"name":"RoleAdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleRevoked","type":"event"},{"inputs":[],"name":"DEFAULT_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleAdmin","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"grantRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"hasRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"callerConfirmation","type":"address"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"revokeRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"}],"userDoc":{"kind":"user","methods":{},"version":1},"developerDoc":{"details":"Contract module that allows children to implement role-based access control mechanisms. This is a lightweight version that doesn't allow enumerating role members except through off-chain means by accessing the contract event logs. Some applications may benefit from on-chain enumerability, for those cases see {AccessControlEnumerable}. Roles are referred to by their `bytes32` identifier. These should be exposed in the external API and be unique. The best way to achieve this is by using `public constant` hash digests: ```solidity bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\"); ``` Roles can be used to represent a set of permissions. To restrict access to a function call, use {hasRole}: ```solidity function foo() public { require(hasRole(MY_ROLE, msg.sender)); ... } ``` Roles can be granted and revoked dynamically via the {grantRole} and {revokeRole} functions. Each role has an associated admin role, and only accounts that have a role's admin role can call {grantRole} and {revokeRole}. By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means that only accounts with this role will be able to grant or revoke other roles. More complex role relationships can be created by using {_setRoleAdmin}. WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to grant and revoke this role. Extra precautions should be taken to secure accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules} to enforce additional security measures for this role.","errors":{"AccessControlBadConfirmation()":[{"details":"The caller of a function is not the expected one. NOTE: Don't confuse with {AccessControlUnauthorizedAccount}."}],"AccessControlUnauthorizedAccount(address,bytes32)":[{"details":"The `account` is missing a role."}]},"events":{"RoleAdminChanged(bytes32,bytes32,bytes32)":{"details":"Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole` `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite {RoleAdminChanged} not being emitted signaling this."},"RoleGranted(bytes32,address,address)":{"details":"Emitted when `account` is granted `role`. `sender` is the account that originated the contract call, an admin role bearer except when using {AccessControl-_setupRole}."},"RoleRevoked(bytes32,address,address)":{"details":"Emitted when `account` is revoked `role`. `sender` is the account that originated the contract call: - if using `revokeRole`, it is the admin role bearer - if using `renounceRole`, it is the role bearer (i.e. `account`)"}},"kind":"dev","methods":{"getRoleAdmin(bytes32)":{"details":"Returns the admin role that controls `role`. See {grantRole} and {revokeRole}. To change a role's admin, use {_setRoleAdmin}."},"grantRole(bytes32,address)":{"details":"Grants `role` to `account`. If `account` had not been already granted `role`, emits a {RoleGranted} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleGranted} event."},"hasRole(bytes32,address)":{"details":"Returns `true` if `account` has been granted `role`."},"renounceRole(bytes32,address)":{"details":"Revokes `role` from the calling account. Roles are often managed via {grantRole} and {revokeRole}: this function's purpose is to provide a mechanism for accounts to lose their privileges if they are compromised (such as when a trusted device is misplaced). If the calling account had been revoked `role`, emits a {RoleRevoked} event. Requirements: - the caller must be `callerConfirmation`. May emit a {RoleRevoked} event."},"revokeRole(bytes32,address)":{"details":"Revokes `role` from `account`. If `account` had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleRevoked} event."},"supportsInterface(bytes4)":{"details":"See {IERC165-supportsInterface}."}},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[],\"name\":\"AccessControlBadConfirmation\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"neededRole\",\"type\":\"bytes32\"}],\"name\":\"AccessControlUnauthorizedAccount\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"previousAdminRole\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"newAdminRole\",\"type\":\"bytes32\"}],\"name\":\"RoleAdminChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleGranted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleRevoked\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"DEFAULT_ADMIN_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"}],\"name\":\"getRoleAdmin\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"grantRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"hasRole\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"callerConfirmation\",\"type\":\"address\"}],\"name\":\"renounceRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"revokeRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes4\",\"name\":\"interfaceId\",\"type\":\"bytes4\"}],\"name\":\"supportsInterface\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"}],\"devdoc\":{\"details\":\"Contract module that allows children to implement role-based access control mechanisms. This is a lightweight version that doesn't allow enumerating role members except through off-chain means by accessing the contract event logs. Some applications may benefit from on-chain enumerability, for those cases see {AccessControlEnumerable}. Roles are referred to by their `bytes32` identifier. These should be exposed in the external API and be unique. The best way to achieve this is by using `public constant` hash digests: ```solidity bytes32 public constant MY_ROLE = keccak256(\\\"MY_ROLE\\\"); ``` Roles can be used to represent a set of permissions. To restrict access to a function call, use {hasRole}: ```solidity function foo() public { require(hasRole(MY_ROLE, msg.sender)); ... } ``` Roles can be granted and revoked dynamically via the {grantRole} and {revokeRole} functions. Each role has an associated admin role, and only accounts that have a role's admin role can call {grantRole} and {revokeRole}. By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means that only accounts with this role will be able to grant or revoke other roles. More complex role relationships can be created by using {_setRoleAdmin}. WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to grant and revoke this role. Extra precautions should be taken to secure accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules} to enforce additional security measures for this role.\",\"errors\":{\"AccessControlBadConfirmation()\":[{\"details\":\"The caller of a function is not the expected one. NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\"}],\"AccessControlUnauthorizedAccount(address,bytes32)\":[{\"details\":\"The `account` is missing a role.\"}]},\"events\":{\"RoleAdminChanged(bytes32,bytes32,bytes32)\":{\"details\":\"Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole` `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite {RoleAdminChanged} not being emitted signaling this.\"},\"RoleGranted(bytes32,address,address)\":{\"details\":\"Emitted when `account` is granted `role`. `sender` is the account that originated the contract call, an admin role bearer except when using {AccessControl-_setupRole}.\"},\"RoleRevoked(bytes32,address,address)\":{\"details\":\"Emitted when `account` is revoked `role`. `sender` is the account that originated the contract call: - if using `revokeRole`, it is the admin role bearer - if using `renounceRole`, it is the role bearer (i.e. `account`)\"}},\"kind\":\"dev\",\"methods\":{\"getRoleAdmin(bytes32)\":{\"details\":\"Returns the admin role that controls `role`. See {grantRole} and {revokeRole}. To change a role's admin, use {_setRoleAdmin}.\"},\"grantRole(bytes32,address)\":{\"details\":\"Grants `role` to `account`. If `account` had not been already granted `role`, emits a {RoleGranted} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleGranted} event.\"},\"hasRole(bytes32,address)\":{\"details\":\"Returns `true` if `account` has been granted `role`.\"},\"renounceRole(bytes32,address)\":{\"details\":\"Revokes `role` from the calling account. Roles are often managed via {grantRole} and {revokeRole}: this function's purpose is to provide a mechanism for accounts to lose their privileges if they are compromised (such as when a trusted device is misplaced). If the calling account had been revoked `role`, emits a {RoleRevoked} event. Requirements: - the caller must be `callerConfirmation`. May emit a {RoleRevoked} event.\"},\"revokeRole(bytes32,address)\":{\"details\":\"Revokes `role` from `account`. If `account` had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleRevoked} event.\"},\"supportsInterface(bytes4)\":{\"details\":\"See {IERC165-supportsInterface}.\"}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeV2.sol\":\"AccessControl\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeV2.sol\":{\"keccak256\":\"0xfd916c030b1ffca5a136817827b8018c8ba42ca089905747f3de6148b73eb35e\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://18e6438c4096deb8ae453fb3365ba2b07d52944e93c08288fc5d012b71bf6bb3\",\"dweb:/ipfs/QmfEMqpT1zz6RRm7UuHLRowe1tds2cTGLrVonfm9XSCACj\"]}},\"version\":1}"},"hashes":{"DEFAULT_ADMIN_ROLE()":"a217fddf","getRoleAdmin(bytes32)":"248a9ca3","grantRole(bytes32,address)":"2f2ff15d","hasRole(bytes32,address)":"91d14854","renounceRole(bytes32,address)":"36568abe","revokeRole(bytes32,address)":"d547741f","supportsInterface(bytes4)":"01ffc9a7"}},"solidity/FastBridgeV2.sol:AccessControlEnumerable":{"code":"0x","runtime-code":"0x","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.24 ^0.8.0 ^0.8.20;\n\n// contracts/interfaces/IAdmin.sol\n\ninterface IAdmin {\n // ============ Events ============\n\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n event ChainGasAmountUpdated(uint256 oldChainGasAmount, uint256 newChainGasAmount);\n\n // ============ Methods ============\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n\n function setChainGasAmount(uint256 newChainGasAmount) external;\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IFastBridgeRecipient.sol\n\ninterface IFastBridgeRecipient {\n function fastBridgeTransferReceived(\n address token,\n uint256 amount,\n bytes memory callParams\n )\n external\n payable\n returns (bytes4);\n}\n\n// contracts/interfaces/IFastBridgeV2Errors.sol\n\ninterface IFastBridgeV2Errors {\n error AmountIncorrect();\n error CallParamsLengthAboveMax();\n error ChainIncorrect();\n error ExclusivityParamsIncorrect();\n error MsgValueIncorrect();\n error NativeTokenCallValueNotSupported();\n error SenderIncorrect();\n error StatusIncorrect();\n error ZeroAddress();\n\n error RecipientIncorrectReturnValue();\n error RecipientNoReturnValue();\n\n error DeadlineExceeded();\n error DeadlineNotExceeded();\n error DeadlineTooShort();\n error DisputePeriodNotPassed();\n error DisputePeriodPassed();\n error ExclusivityPeriodNotPassed();\n\n error TransactionRelayed();\n}\n\n// contracts/libs/Errors.sol\n\nerror DeadlineExceeded();\nerror DeadlineNotExceeded();\nerror DeadlineTooShort();\nerror InsufficientOutputAmount();\n\nerror MsgValueIncorrect();\nerror PoolNotFound();\nerror TokenAddressMismatch();\nerror TokenNotContract();\nerror TokenNotETH();\nerror TokensIdentical();\n\nerror ChainIncorrect();\nerror AmountIncorrect();\nerror ZeroAddress();\n\nerror DisputePeriodNotPassed();\nerror DisputePeriodPassed();\nerror SenderIncorrect();\nerror StatusIncorrect();\nerror TransactionIdIncorrect();\nerror TransactionRelayed();\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// contracts/interfaces/IFastBridgeV2.sol\n\ninterface IFastBridgeV2 is IFastBridge {\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n struct BridgeTxDetails {\n BridgeStatus status;\n uint40 proofBlockTimestamp;\n uint48 proofBlockNumber;\n address proofRelayer;\n }\n\n struct BridgeRelay {\n uint48 blockNumber;\n uint48 blockTimestamp;\n address relayer;\n }\n\n /// @notice New params introduced in the FastBridgeV2.\n /// We are passing fields from the older BridgeParams struct outside of this struct\n /// for backwards compatibility.\n /// Note: quoteRelayer and quoteExclusivitySeconds are either both zero (indicating no exclusivity)\n /// or both non-zero (indicating exclusivity for the given period).\n /// Note: callValue \u003e 0 can NOT be used with destToken = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE (ETH_ADDRESS)\n /// @param quoteRelayer Relayer that provided the quote for the transaction\n /// @param quoteExclusivitySeconds Period of time the quote relayer is guaranteed exclusivity after user's deposit\n /// @param quoteId Unique quote identifier used for tracking the quote\n /// @param callValue ETH value to send to the recipient (if any)\n /// @param callParams Parameters for the arbitrary call to the destination recipient (if any)\n struct BridgeParamsV2 {\n address quoteRelayer;\n int256 quoteExclusivitySeconds;\n bytes quoteId;\n uint256 callValue;\n bytes callParams;\n }\n\n /// @notice Updated bridge transaction struct to include parameters introduced in FastBridgeV2.\n /// Note: only `exclusivityRelayer` can fill such a transaction until `exclusivityEndTime`.\n /// TODO: consider changing the encoding scheme to prevent spending extra gas on decoding.\n struct BridgeTransactionV2 {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n uint256 callValue; // ETH value to send to the recipient (if any) - replaces V1's sendChainGas flag\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n address exclusivityRelayer;\n uint256 exclusivityEndTime;\n bytes callParams;\n }\n\n event BridgeQuoteDetails(bytes32 indexed transactionId, bytes quoteId);\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability\n /// to provide temporary exclusivity fill rights for the quote relayer.\n /// @param params The parameters required to bridge\n /// @param paramsV2 The parameters for exclusivity fill rights (optional, can be left empty)\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function relay(bytes memory request, address relayer) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param transactionId The transaction id associated with the encoded bridge transaction to prove\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital.\n /// @notice Can only send funds to the relayer address on the proof.\n /// @param request The encoded bridge transaction to claim on origin chain\n function claim(bytes memory request) external;\n /// @notice Checks if a transaction has been relayed\n /// @param transactionId The ID of the transaction to check\n /// @return True if the transaction has been relayed, false otherwise\n function bridgeRelays(bytes32 transactionId) external view returns (bool);\n\n /// @notice Returns the status of a bridge transaction\n /// @param transactionId The ID of the bridge transaction\n /// @return BridgeStatus Status of the bridge transaction\n function bridgeStatuses(bytes32 transactionId) external view returns (BridgeStatus);\n\n /// @notice Returns the timestamp and relayer of a bridge proof\n /// @param transactionId The ID of the bridge transaction\n /// @return timestamp The timestamp of the bridge proof\n /// @return relayer The relayer address of the bridge proof\n function bridgeProofs(bytes32 transactionId) external view returns (uint96 timestamp, address relayer);\n\n /// @notice Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\n /// @param request The bridge request to decode\n function getBridgeTransactionV2(bytes memory request) external view returns (BridgeTransactionV2 memory);\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// contracts/libs/UniversalToken.sol\n\nlibrary UniversalTokenLib {\n using SafeERC20 for IERC20;\n\n address internal constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Transfers tokens to the given account. Reverts if transfer is not successful.\n /// @dev This might trigger fallback, if ETH is transferred to the contract.\n /// Make sure this can not lead to reentrancy attacks.\n function universalTransfer(address token, address to, uint256 value) internal {\n // Don't do anything, if need to send tokens to this address\n if (to == address(this)) return;\n // Don't do anything, if trying to send zero value\n if (value == 0) return;\n if (token == ETH_ADDRESS) {\n /// @dev Note: this can potentially lead to executing code in `to`.\n // solhint-disable-next-line avoid-low-level-calls\n (bool success,) = to.call{value: value}(\"\");\n require(success, \"ETH transfer failed\");\n } else {\n IERC20(token).safeTransfer(to, value);\n }\n }\n\n /// @notice Issues an infinite allowance to the spender, if the current allowance is insufficient\n /// to spend the given amount.\n function universalApproveInfinity(address token, address spender, uint256 amountToSpend) internal {\n // ETH Chad doesn't require your approval\n if (token == ETH_ADDRESS) return;\n // No-op if allowance is already sufficient\n uint256 allowance = IERC20(token).allowance(address(this), spender);\n if (allowance \u003e= amountToSpend) return;\n // Otherwise, reset approval to 0 and set to max allowance\n if (allowance \u003e 0) IERC20(token).safeDecreaseAllowance(spender, allowance);\n IERC20(token).safeIncreaseAllowance(spender, type(uint256).max);\n }\n\n /// @notice Returns the balance of the given token (or native ETH) for the given account.\n function universalBalanceOf(address token, address account) internal view returns (uint256) {\n if (token == ETH_ADDRESS) {\n return account.balance;\n } else {\n return IERC20(token).balanceOf(account);\n }\n }\n\n /// @dev Checks that token is a contract and not ETH_ADDRESS.\n function assertIsContract(address token) internal view {\n // Check that ETH_ADDRESS was not used (in case this is a predeploy on any of the chains)\n if (token == UniversalTokenLib.ETH_ADDRESS) revert TokenNotContract();\n // Check that token is not an EOA\n if (token.code.length == 0) revert TokenNotContract();\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/Admin.sol\n\ncontract Admin is IAdmin, AccessControlEnumerable {\n using UniversalTokenLib for address;\n\n bytes32 public constant RELAYER_ROLE = keccak256(\"RELAYER_ROLE\");\n bytes32 public constant REFUNDER_ROLE = keccak256(\"REFUNDER_ROLE\");\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n uint256 public constant FEE_BPS = 1e6;\n uint256 public constant FEE_RATE_MAX = 0.01e6; // max 1% on origin amount\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Chain gas amount to forward as rebate if requested\n uint256 public chainGasAmount;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n }\n\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n require(newFeeRate \u003c= FEE_RATE_MAX, \"newFeeRate \u003e max\");\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n token.universalTransfer(recipient, feeAmount);\n emit FeesSwept(token, recipient, feeAmount);\n }\n\n function setChainGasAmount(uint256 newChainGasAmount) external onlyRole(GOVERNOR_ROLE) {\n uint256 oldChainGasAmount = chainGasAmount;\n chainGasAmount = newChainGasAmount;\n emit ChainGasAmountUpdated(oldChainGasAmount, newChainGasAmount);\n }\n}\n\n// contracts/FastBridgeV2.sol\n\n/// @notice FastBridgeV2 is a contract for bridging tokens across chains.\ncontract FastBridgeV2 is Admin, IFastBridgeV2, IFastBridgeV2Errors {\n using SafeERC20 for IERC20;\n using UniversalTokenLib for address;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Delay for a transaction after which it could be permisionlessly refunded\n uint256 public constant REFUND_DELAY = 7 days;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n /// @notice Maximum length of accepted callParams\n uint256 public constant MAX_CALL_PARAMS_LENGTH = 2 ** 16 - 1;\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeTxDetails) public bridgeTxDetails;\n /// @notice Relay details on destination chain\n mapping(bytes32 =\u003e BridgeRelay) public bridgeRelayDetails;\n /// @notice Unique bridge nonces tracked per originSender\n mapping(address =\u003e uint256) public senderNonces;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Replaced by senderNonces\n uint256 public immutable nonce = 0;\n /// @notice the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n bridge({\n params: params,\n paramsV2: BridgeParamsV2({\n quoteRelayer: address(0),\n quoteExclusivitySeconds: 0,\n quoteId: bytes(\"\"),\n callValue: 0,\n callParams: bytes(\"\")\n })\n });\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes memory request) external payable {\n relay({request: request, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes memory request, bytes32 destTxHash) external {\n prove({transactionId: keccak256(request), destTxHash: destTxHash, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridgeV2\n function claim(bytes memory request) external {\n claim({request: request, to: address(0)});\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003e DISPUTE_PERIOD) {\n revert DisputePeriodPassed();\n }\n\n // @dev relayer gets slashed effectively if dest relay has gone thru\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n bridgeTxDetails[transactionId].proofRelayer = address(0);\n bridgeTxDetails[transactionId].proofBlockTimestamp = 0;\n bridgeTxDetails[transactionId].proofBlockNumber = 0;\n\n emit BridgeProofDisputed(transactionId, msg.sender);\n }\n\n /// @inheritdoc IFastBridge\n function refund(bytes memory request) external {\n bytes32 transactionId = keccak256(request);\n\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n\n if (bridgeTxDetails[transactionId].status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n\n if (hasRole(REFUNDER_ROLE, msg.sender)) {\n // Refunder can refund if deadline has passed\n if (block.timestamp \u003c= transaction.deadline) revert DeadlineNotExceeded();\n } else {\n // Permissionless refund is allowed after REFUND_DELAY\n if (block.timestamp \u003c= transaction.deadline + REFUND_DELAY) revert DeadlineNotExceeded();\n }\n\n // if all checks passed, set to REFUNDED status\n bridgeTxDetails[transactionId].status = BridgeStatus.REFUNDED;\n\n // transfer origin collateral back to original sender\n address to = transaction.originSender;\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount + transaction.originFeeAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (bridgeTxDetails[transactionId].proofRelayer != relayer) revert SenderIncorrect();\n return _timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n /// @dev This method is added to achieve backwards compatibility with decoding requests into V1 structs:\n /// - `callValue` is partially reported as a zero/non-zero flag\n /// - `callParams` is ignored\n /// In order to process all kinds of requests use getBridgeTransactionV2 instead.\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory) {\n // Try decoding into V2 struct first. This will revert if V1 struct is passed\n try this.getBridgeTransactionV2(request) returns (BridgeTransactionV2 memory txV2) {\n // Note: we entirely ignore the callParams field, as it was not present in V1\n return BridgeTransaction({\n originChainId: txV2.originChainId,\n destChainId: txV2.destChainId,\n originSender: txV2.originSender,\n destRecipient: txV2.destRecipient,\n originToken: txV2.originToken,\n destToken: txV2.destToken,\n originAmount: txV2.originAmount,\n destAmount: txV2.destAmount,\n originFeeAmount: txV2.originFeeAmount,\n sendChainGas: txV2.callValue != 0,\n deadline: txV2.deadline,\n nonce: txV2.nonce\n });\n } catch {\n // Fallback to V1 struct\n return abi.decode(request, (BridgeTransaction));\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) public payable {\n int256 exclusivityEndTime = int256(block.timestamp) + paramsV2.quoteExclusivitySeconds;\n _validateBridgeParams(params, paramsV2, exclusivityEndTime);\n\n // transfer tokens to bridge contract\n /// @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _takeBridgedUserAsset(params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n\n // set status to requested\n bytes memory request = abi.encode(\n BridgeTransactionV2({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n callValue: paramsV2.callValue,\n deadline: params.deadline,\n nonce: senderNonces[params.sender]++, // increment nonce on every bridge\n exclusivityRelayer: paramsV2.quoteRelayer,\n // We checked exclusivityEndTime to be in range (0 .. params.deadline] above, so can safely cast\n exclusivityEndTime: uint256(exclusivityEndTime),\n callParams: paramsV2.callParams\n })\n );\n bytes32 transactionId = keccak256(request);\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n\n emit BridgeRequested({\n transactionId: transactionId,\n sender: params.sender,\n request: request,\n destChainId: params.dstChainId,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n sendChainGas: paramsV2.callValue != 0\n });\n emit BridgeQuoteDetails(transactionId, paramsV2.quoteId);\n }\n\n /// @inheritdoc IFastBridgeV2\n function relay(bytes memory request, address relayer) public payable {\n bytes32 transactionId = keccak256(request);\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n _validateRelayParams(transaction, transactionId, relayer);\n // mark bridge transaction as relayed\n bridgeRelayDetails[transactionId] =\n BridgeRelay({blockNumber: uint48(block.number), blockTimestamp: uint48(block.timestamp), relayer: relayer});\n\n // transfer tokens to recipient on destination chain and do an arbitrary call if requested\n address to = transaction.destRecipient;\n address token = transaction.destToken;\n uint256 amount = transaction.destAmount;\n uint256 callValue = transaction.callValue;\n\n // Emit the event before any external calls\n emit BridgeRelayed({\n transactionId: transactionId,\n relayer: relayer,\n to: to,\n originChainId: transaction.originChainId,\n originToken: transaction.originToken,\n destToken: token,\n originAmount: transaction.originAmount,\n destAmount: amount,\n chainGasAmount: callValue\n });\n\n // All state changes have been done at this point, can proceed to the external calls.\n // This follows the checks-effects-interactions pattern to mitigate potential reentrancy attacks.\n if (token == UniversalTokenLib.ETH_ADDRESS) {\n // For ETH non-zero callValue is not allowed\n if (callValue != 0) revert NativeTokenCallValueNotSupported();\n // Check that the correct msg.value was sent\n if (msg.value != amount) revert MsgValueIncorrect();\n } else {\n // For ERC20s, we check that the correct msg.value was sent\n if (msg.value != callValue) revert MsgValueIncorrect();\n // We need to transfer the tokens from the Relayer to the recipient first before performing an\n // optional post-transfer arbitrary call.\n IERC20(token).safeTransferFrom(msg.sender, to, amount);\n }\n\n if (transaction.callParams.length != 0) {\n // Arbitrary call requested, perform it while supplying full msg.value to the recipient\n // Note: if token has a fee on transfers, the recipient will have received less than `amount`.\n // This is a very niche edge case and should be handled by the recipient contract.\n _checkedCallRecipient({recipient: to, token: token, amount: amount, callParams: transaction.callParams});\n } else if (msg.value != 0) {\n // No arbitrary call requested, but msg.value was sent. This is either a relay with ETH,\n // or a non-zero callValue request with an ERC20. In both cases, transfer the ETH to the recipient.\n Address.sendValue(payable(to), msg.value);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) public onlyRole(RELAYER_ROLE) {\n // update bridge tx status given proof provided\n if (bridgeTxDetails[transactionId].status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n bridgeTxDetails[transactionId].status = BridgeStatus.RELAYER_PROVED;\n bridgeTxDetails[transactionId].proofBlockTimestamp = uint40(block.timestamp);\n bridgeTxDetails[transactionId].proofBlockNumber = uint48(block.number);\n bridgeTxDetails[transactionId].proofRelayer = relayer;\n\n emit BridgeProofProvided(transactionId, relayer, destTxHash);\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes memory request, address to) public {\n bytes32 transactionId = keccak256(request);\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n\n // update bridge tx status if able to claim origin collateral\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n\n // if \"to\" is zero addr, permissionlessly send funds to proven relayer\n if (to == address(0)) {\n to = bridgeTxDetails[transactionId].proofRelayer;\n } else if (bridgeTxDetails[transactionId].proofRelayer != msg.sender) {\n revert SenderIncorrect();\n }\n\n if (_timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003c= DISPUTE_PERIOD) {\n revert DisputePeriodNotPassed();\n }\n\n bridgeTxDetails[transactionId].status = BridgeStatus.RELAYER_CLAIMED;\n\n // update protocol fees if origin fee amount exists\n if (transaction.originFeeAmount \u003e 0) protocolFees[transaction.originToken] += transaction.originFeeAmount;\n\n // transfer origin collateral less fee to specified address\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositClaimed(transactionId, bridgeTxDetails[transactionId].proofRelayer, to, token, amount);\n }\n\n function bridgeStatuses(bytes32 transactionId) public view returns (BridgeStatus status) {\n return bridgeTxDetails[transactionId].status;\n }\n\n function bridgeProofs(bytes32 transactionId) public view returns (uint96 timestamp, address relayer) {\n timestamp = bridgeTxDetails[transactionId].proofBlockTimestamp;\n relayer = bridgeTxDetails[transactionId].proofRelayer;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeRelays(bytes32 transactionId) public view returns (bool) {\n // has this transactionId been relayed?\n return bridgeRelayDetails[transactionId].relayer != address(0);\n }\n\n /// @inheritdoc IFastBridgeV2\n function getBridgeTransactionV2(bytes memory request) public pure returns (BridgeTransactionV2 memory) {\n return abi.decode(request, (BridgeTransactionV2));\n }\n\n /// @notice Takes the bridged asset from the user into FastBridgeV2 custody. It will be later\n /// claimed by the relayer who completed the relay on destination chain, or refunded back to the user,\n /// should no one complete the relay.\n function _takeBridgedUserAsset(address token, uint256 amount) internal returns (uint256 amountTaken) {\n if (token == UniversalTokenLib.ETH_ADDRESS) {\n // For ETH we just need to check that the supplied msg.value is correct.\n // Supplied `msg.value` is already in FastBridgeV2 custody.\n if (amount != msg.value) revert MsgValueIncorrect();\n amountTaken = msg.value;\n } else {\n // For ERC20s, token is explicitly transferred from the user to FastBridgeV2.\n // We don't allow non-zero `msg.value` to avoid extra funds from being stuck in FastBridgeV2.\n token.assertIsContract();\n if (msg.value != 0) revert MsgValueIncorrect();\n amountTaken = IERC20(token).balanceOf(address(this));\n IERC20(token).safeTransferFrom(msg.sender, address(this), amount);\n // Use the balance difference as the amount taken in case of fee on transfer tokens.\n amountTaken = IERC20(token).balanceOf(address(this)) - amountTaken;\n }\n }\n\n /// @notice Calls the Recipient's hook function with the specified callParams and performs\n /// all the necessary checks for the returned value.\n function _checkedCallRecipient(\n address recipient,\n address token,\n uint256 amount,\n bytes memory callParams\n )\n internal\n {\n bytes memory hookData =\n abi.encodeCall(IFastBridgeRecipient.fastBridgeTransferReceived, (token, amount, callParams));\n // This will bubble any revert messages from the hook function\n bytes memory returnData = Address.functionCallWithValue({target: recipient, data: hookData, value: msg.value});\n // Explicit revert if no return data at all\n if (returnData.length == 0) revert RecipientNoReturnValue();\n // Check that exactly a single return value was returned\n if (returnData.length != 32) revert RecipientIncorrectReturnValue();\n // Return value should be abi-encoded hook function selector\n if (bytes32(returnData) != bytes32(IFastBridgeRecipient.fastBridgeTransferReceived.selector)) {\n revert RecipientIncorrectReturnValue();\n }\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint40(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint40).max but\n /// proof.timestamp \u003c type(uint40).max via unchecked statement\n /// @param proofBlockTimestamp The bridge proof block timestamp\n /// @return delta Time delta since proof submitted\n function _timeSince(uint40 proofBlockTimestamp) internal view returns (uint256 delta) {\n unchecked {\n delta = uint40(block.timestamp) - proofBlockTimestamp;\n }\n }\n\n /// @notice Performs all the necessary checks for a bridge to happen.\n /// @dev There's no good way to refactor this function to reduce cyclomatic complexity due to\n /// the number of checks that need to be performed, so we skip the code-complexity rule here.\n // solhint-disable-next-line code-complexity\n function _validateBridgeParams(\n BridgeParams memory params,\n BridgeParamsV2 memory paramsV2,\n int256 exclusivityEndTime\n )\n internal\n view\n {\n // Check V1 (legacy) params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.sender == address(0) || params.to == address(0)) revert ZeroAddress();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n // Check V2 params\n if (paramsV2.callParams.length \u003e MAX_CALL_PARAMS_LENGTH) revert CallParamsLengthAboveMax();\n if (paramsV2.callValue != 0 \u0026\u0026 params.destToken == UniversalTokenLib.ETH_ADDRESS) {\n revert NativeTokenCallValueNotSupported();\n }\n // exclusivityEndTime must be in range (0 .. params.deadline]\n if (exclusivityEndTime \u003c= 0 || exclusivityEndTime \u003e int256(params.deadline)) {\n revert ExclusivityParamsIncorrect();\n }\n }\n\n /// @notice Performs all the necessary checks for a relay to happen.\n function _validateRelayParams(\n BridgeTransactionV2 memory transaction,\n bytes32 transactionId,\n address relayer\n )\n internal\n view\n {\n if (relayer == address(0)) revert ZeroAddress();\n // Check if the transaction has already been relayed\n if (bridgeRelays(transactionId)) revert TransactionRelayed();\n if (transaction.destChainId != block.chainid) revert ChainIncorrect();\n // Check the deadline for relay to happen\n if (block.timestamp \u003e transaction.deadline) revert DeadlineExceeded();\n // Check the exclusivity period, if it is still ongoing\n // forgefmt: disable-next-item\n if (\n transaction.exclusivityRelayer != address(0) \u0026\u0026\n transaction.exclusivityRelayer != relayer \u0026\u0026\n block.timestamp \u003c= transaction.exclusivityEndTime\n ) {\n revert ExclusivityPeriodNotPassed();\n }\n }\n}\n","language":"Solidity","languageVersion":"0.8.24","compilerVersion":"0.8.24","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"","srcMapRuntime":"","abiDefinition":[{"inputs":[],"name":"AccessControlBadConfirmation","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"bytes32","name":"neededRole","type":"bytes32"}],"name":"AccessControlUnauthorizedAccount","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"previousAdminRole","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"newAdminRole","type":"bytes32"}],"name":"RoleAdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleRevoked","type":"event"},{"inputs":[],"name":"DEFAULT_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleAdmin","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"uint256","name":"index","type":"uint256"}],"name":"getRoleMember","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleMemberCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"grantRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"hasRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"callerConfirmation","type":"address"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"revokeRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"}],"userDoc":{"kind":"user","methods":{},"version":1},"developerDoc":{"details":"Extension of {AccessControl} that allows enumerating the members of each role.","errors":{"AccessControlBadConfirmation()":[{"details":"The caller of a function is not the expected one. NOTE: Don't confuse with {AccessControlUnauthorizedAccount}."}],"AccessControlUnauthorizedAccount(address,bytes32)":[{"details":"The `account` is missing a role."}]},"events":{"RoleAdminChanged(bytes32,bytes32,bytes32)":{"details":"Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole` `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite {RoleAdminChanged} not being emitted signaling this."},"RoleGranted(bytes32,address,address)":{"details":"Emitted when `account` is granted `role`. `sender` is the account that originated the contract call, an admin role bearer except when using {AccessControl-_setupRole}."},"RoleRevoked(bytes32,address,address)":{"details":"Emitted when `account` is revoked `role`. `sender` is the account that originated the contract call: - if using `revokeRole`, it is the admin role bearer - if using `renounceRole`, it is the role bearer (i.e. `account`)"}},"kind":"dev","methods":{"getRoleAdmin(bytes32)":{"details":"Returns the admin role that controls `role`. See {grantRole} and {revokeRole}. To change a role's admin, use {_setRoleAdmin}."},"getRoleMember(bytes32,uint256)":{"details":"Returns one of the accounts that have `role`. `index` must be a value between 0 and {getRoleMemberCount}, non-inclusive. Role bearers are not sorted in any particular way, and their ordering may change at any point. WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure you perform all queries on the same block. See the following https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post] for more information."},"getRoleMemberCount(bytes32)":{"details":"Returns the number of accounts that have `role`. Can be used together with {getRoleMember} to enumerate all bearers of a role."},"grantRole(bytes32,address)":{"details":"Grants `role` to `account`. If `account` had not been already granted `role`, emits a {RoleGranted} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleGranted} event."},"hasRole(bytes32,address)":{"details":"Returns `true` if `account` has been granted `role`."},"renounceRole(bytes32,address)":{"details":"Revokes `role` from the calling account. Roles are often managed via {grantRole} and {revokeRole}: this function's purpose is to provide a mechanism for accounts to lose their privileges if they are compromised (such as when a trusted device is misplaced). If the calling account had been revoked `role`, emits a {RoleRevoked} event. Requirements: - the caller must be `callerConfirmation`. May emit a {RoleRevoked} event."},"revokeRole(bytes32,address)":{"details":"Revokes `role` from `account`. If `account` had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleRevoked} event."},"supportsInterface(bytes4)":{"details":"See {IERC165-supportsInterface}."}},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[],\"name\":\"AccessControlBadConfirmation\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"neededRole\",\"type\":\"bytes32\"}],\"name\":\"AccessControlUnauthorizedAccount\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"previousAdminRole\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"newAdminRole\",\"type\":\"bytes32\"}],\"name\":\"RoleAdminChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleGranted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleRevoked\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"DEFAULT_ADMIN_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"}],\"name\":\"getRoleAdmin\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"index\",\"type\":\"uint256\"}],\"name\":\"getRoleMember\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"}],\"name\":\"getRoleMemberCount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"grantRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"hasRole\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"callerConfirmation\",\"type\":\"address\"}],\"name\":\"renounceRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"revokeRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes4\",\"name\":\"interfaceId\",\"type\":\"bytes4\"}],\"name\":\"supportsInterface\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"}],\"devdoc\":{\"details\":\"Extension of {AccessControl} that allows enumerating the members of each role.\",\"errors\":{\"AccessControlBadConfirmation()\":[{\"details\":\"The caller of a function is not the expected one. NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\"}],\"AccessControlUnauthorizedAccount(address,bytes32)\":[{\"details\":\"The `account` is missing a role.\"}]},\"events\":{\"RoleAdminChanged(bytes32,bytes32,bytes32)\":{\"details\":\"Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole` `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite {RoleAdminChanged} not being emitted signaling this.\"},\"RoleGranted(bytes32,address,address)\":{\"details\":\"Emitted when `account` is granted `role`. `sender` is the account that originated the contract call, an admin role bearer except when using {AccessControl-_setupRole}.\"},\"RoleRevoked(bytes32,address,address)\":{\"details\":\"Emitted when `account` is revoked `role`. `sender` is the account that originated the contract call: - if using `revokeRole`, it is the admin role bearer - if using `renounceRole`, it is the role bearer (i.e. `account`)\"}},\"kind\":\"dev\",\"methods\":{\"getRoleAdmin(bytes32)\":{\"details\":\"Returns the admin role that controls `role`. See {grantRole} and {revokeRole}. To change a role's admin, use {_setRoleAdmin}.\"},\"getRoleMember(bytes32,uint256)\":{\"details\":\"Returns one of the accounts that have `role`. `index` must be a value between 0 and {getRoleMemberCount}, non-inclusive. Role bearers are not sorted in any particular way, and their ordering may change at any point. WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure you perform all queries on the same block. See the following https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post] for more information.\"},\"getRoleMemberCount(bytes32)\":{\"details\":\"Returns the number of accounts that have `role`. Can be used together with {getRoleMember} to enumerate all bearers of a role.\"},\"grantRole(bytes32,address)\":{\"details\":\"Grants `role` to `account`. If `account` had not been already granted `role`, emits a {RoleGranted} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleGranted} event.\"},\"hasRole(bytes32,address)\":{\"details\":\"Returns `true` if `account` has been granted `role`.\"},\"renounceRole(bytes32,address)\":{\"details\":\"Revokes `role` from the calling account. Roles are often managed via {grantRole} and {revokeRole}: this function's purpose is to provide a mechanism for accounts to lose their privileges if they are compromised (such as when a trusted device is misplaced). If the calling account had been revoked `role`, emits a {RoleRevoked} event. Requirements: - the caller must be `callerConfirmation`. May emit a {RoleRevoked} event.\"},\"revokeRole(bytes32,address)\":{\"details\":\"Revokes `role` from `account`. If `account` had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleRevoked} event.\"},\"supportsInterface(bytes4)\":{\"details\":\"See {IERC165-supportsInterface}.\"}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeV2.sol\":\"AccessControlEnumerable\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeV2.sol\":{\"keccak256\":\"0xfd916c030b1ffca5a136817827b8018c8ba42ca089905747f3de6148b73eb35e\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://18e6438c4096deb8ae453fb3365ba2b07d52944e93c08288fc5d012b71bf6bb3\",\"dweb:/ipfs/QmfEMqpT1zz6RRm7UuHLRowe1tds2cTGLrVonfm9XSCACj\"]}},\"version\":1}"},"hashes":{"DEFAULT_ADMIN_ROLE()":"a217fddf","getRoleAdmin(bytes32)":"248a9ca3","getRoleMember(bytes32,uint256)":"9010d07c","getRoleMemberCount(bytes32)":"ca15c873","grantRole(bytes32,address)":"2f2ff15d","hasRole(bytes32,address)":"91d14854","renounceRole(bytes32,address)":"36568abe","revokeRole(bytes32,address)":"d547741f","supportsInterface(bytes4)":"01ffc9a7"}},"solidity/FastBridgeV2.sol:Address":{"code":"0x60566037600b82828239805160001a607314602a57634e487b7160e01b600052600060045260246000fd5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600080fdfea2646970667358221220ac16750f49f1b9ced08b049feacc7b593708109660ad4859d5e0cc87a7718b8d64736f6c63430008180033","runtime-code":"0x73000000000000000000000000000000000000000030146080604052600080fdfea2646970667358221220ac16750f49f1b9ced08b049feacc7b593708109660ad4859d5e0cc87a7718b8d64736f6c63430008180033","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.24 ^0.8.0 ^0.8.20;\n\n// contracts/interfaces/IAdmin.sol\n\ninterface IAdmin {\n // ============ Events ============\n\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n event ChainGasAmountUpdated(uint256 oldChainGasAmount, uint256 newChainGasAmount);\n\n // ============ Methods ============\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n\n function setChainGasAmount(uint256 newChainGasAmount) external;\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IFastBridgeRecipient.sol\n\ninterface IFastBridgeRecipient {\n function fastBridgeTransferReceived(\n address token,\n uint256 amount,\n bytes memory callParams\n )\n external\n payable\n returns (bytes4);\n}\n\n// contracts/interfaces/IFastBridgeV2Errors.sol\n\ninterface IFastBridgeV2Errors {\n error AmountIncorrect();\n error CallParamsLengthAboveMax();\n error ChainIncorrect();\n error ExclusivityParamsIncorrect();\n error MsgValueIncorrect();\n error NativeTokenCallValueNotSupported();\n error SenderIncorrect();\n error StatusIncorrect();\n error ZeroAddress();\n\n error RecipientIncorrectReturnValue();\n error RecipientNoReturnValue();\n\n error DeadlineExceeded();\n error DeadlineNotExceeded();\n error DeadlineTooShort();\n error DisputePeriodNotPassed();\n error DisputePeriodPassed();\n error ExclusivityPeriodNotPassed();\n\n error TransactionRelayed();\n}\n\n// contracts/libs/Errors.sol\n\nerror DeadlineExceeded();\nerror DeadlineNotExceeded();\nerror DeadlineTooShort();\nerror InsufficientOutputAmount();\n\nerror MsgValueIncorrect();\nerror PoolNotFound();\nerror TokenAddressMismatch();\nerror TokenNotContract();\nerror TokenNotETH();\nerror TokensIdentical();\n\nerror ChainIncorrect();\nerror AmountIncorrect();\nerror ZeroAddress();\n\nerror DisputePeriodNotPassed();\nerror DisputePeriodPassed();\nerror SenderIncorrect();\nerror StatusIncorrect();\nerror TransactionIdIncorrect();\nerror TransactionRelayed();\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// contracts/interfaces/IFastBridgeV2.sol\n\ninterface IFastBridgeV2 is IFastBridge {\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n struct BridgeTxDetails {\n BridgeStatus status;\n uint40 proofBlockTimestamp;\n uint48 proofBlockNumber;\n address proofRelayer;\n }\n\n struct BridgeRelay {\n uint48 blockNumber;\n uint48 blockTimestamp;\n address relayer;\n }\n\n /// @notice New params introduced in the FastBridgeV2.\n /// We are passing fields from the older BridgeParams struct outside of this struct\n /// for backwards compatibility.\n /// Note: quoteRelayer and quoteExclusivitySeconds are either both zero (indicating no exclusivity)\n /// or both non-zero (indicating exclusivity for the given period).\n /// Note: callValue \u003e 0 can NOT be used with destToken = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE (ETH_ADDRESS)\n /// @param quoteRelayer Relayer that provided the quote for the transaction\n /// @param quoteExclusivitySeconds Period of time the quote relayer is guaranteed exclusivity after user's deposit\n /// @param quoteId Unique quote identifier used for tracking the quote\n /// @param callValue ETH value to send to the recipient (if any)\n /// @param callParams Parameters for the arbitrary call to the destination recipient (if any)\n struct BridgeParamsV2 {\n address quoteRelayer;\n int256 quoteExclusivitySeconds;\n bytes quoteId;\n uint256 callValue;\n bytes callParams;\n }\n\n /// @notice Updated bridge transaction struct to include parameters introduced in FastBridgeV2.\n /// Note: only `exclusivityRelayer` can fill such a transaction until `exclusivityEndTime`.\n /// TODO: consider changing the encoding scheme to prevent spending extra gas on decoding.\n struct BridgeTransactionV2 {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n uint256 callValue; // ETH value to send to the recipient (if any) - replaces V1's sendChainGas flag\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n address exclusivityRelayer;\n uint256 exclusivityEndTime;\n bytes callParams;\n }\n\n event BridgeQuoteDetails(bytes32 indexed transactionId, bytes quoteId);\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability\n /// to provide temporary exclusivity fill rights for the quote relayer.\n /// @param params The parameters required to bridge\n /// @param paramsV2 The parameters for exclusivity fill rights (optional, can be left empty)\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function relay(bytes memory request, address relayer) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param transactionId The transaction id associated with the encoded bridge transaction to prove\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital.\n /// @notice Can only send funds to the relayer address on the proof.\n /// @param request The encoded bridge transaction to claim on origin chain\n function claim(bytes memory request) external;\n /// @notice Checks if a transaction has been relayed\n /// @param transactionId The ID of the transaction to check\n /// @return True if the transaction has been relayed, false otherwise\n function bridgeRelays(bytes32 transactionId) external view returns (bool);\n\n /// @notice Returns the status of a bridge transaction\n /// @param transactionId The ID of the bridge transaction\n /// @return BridgeStatus Status of the bridge transaction\n function bridgeStatuses(bytes32 transactionId) external view returns (BridgeStatus);\n\n /// @notice Returns the timestamp and relayer of a bridge proof\n /// @param transactionId The ID of the bridge transaction\n /// @return timestamp The timestamp of the bridge proof\n /// @return relayer The relayer address of the bridge proof\n function bridgeProofs(bytes32 transactionId) external view returns (uint96 timestamp, address relayer);\n\n /// @notice Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\n /// @param request The bridge request to decode\n function getBridgeTransactionV2(bytes memory request) external view returns (BridgeTransactionV2 memory);\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// contracts/libs/UniversalToken.sol\n\nlibrary UniversalTokenLib {\n using SafeERC20 for IERC20;\n\n address internal constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Transfers tokens to the given account. Reverts if transfer is not successful.\n /// @dev This might trigger fallback, if ETH is transferred to the contract.\n /// Make sure this can not lead to reentrancy attacks.\n function universalTransfer(address token, address to, uint256 value) internal {\n // Don't do anything, if need to send tokens to this address\n if (to == address(this)) return;\n // Don't do anything, if trying to send zero value\n if (value == 0) return;\n if (token == ETH_ADDRESS) {\n /// @dev Note: this can potentially lead to executing code in `to`.\n // solhint-disable-next-line avoid-low-level-calls\n (bool success,) = to.call{value: value}(\"\");\n require(success, \"ETH transfer failed\");\n } else {\n IERC20(token).safeTransfer(to, value);\n }\n }\n\n /// @notice Issues an infinite allowance to the spender, if the current allowance is insufficient\n /// to spend the given amount.\n function universalApproveInfinity(address token, address spender, uint256 amountToSpend) internal {\n // ETH Chad doesn't require your approval\n if (token == ETH_ADDRESS) return;\n // No-op if allowance is already sufficient\n uint256 allowance = IERC20(token).allowance(address(this), spender);\n if (allowance \u003e= amountToSpend) return;\n // Otherwise, reset approval to 0 and set to max allowance\n if (allowance \u003e 0) IERC20(token).safeDecreaseAllowance(spender, allowance);\n IERC20(token).safeIncreaseAllowance(spender, type(uint256).max);\n }\n\n /// @notice Returns the balance of the given token (or native ETH) for the given account.\n function universalBalanceOf(address token, address account) internal view returns (uint256) {\n if (token == ETH_ADDRESS) {\n return account.balance;\n } else {\n return IERC20(token).balanceOf(account);\n }\n }\n\n /// @dev Checks that token is a contract and not ETH_ADDRESS.\n function assertIsContract(address token) internal view {\n // Check that ETH_ADDRESS was not used (in case this is a predeploy on any of the chains)\n if (token == UniversalTokenLib.ETH_ADDRESS) revert TokenNotContract();\n // Check that token is not an EOA\n if (token.code.length == 0) revert TokenNotContract();\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/Admin.sol\n\ncontract Admin is IAdmin, AccessControlEnumerable {\n using UniversalTokenLib for address;\n\n bytes32 public constant RELAYER_ROLE = keccak256(\"RELAYER_ROLE\");\n bytes32 public constant REFUNDER_ROLE = keccak256(\"REFUNDER_ROLE\");\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n uint256 public constant FEE_BPS = 1e6;\n uint256 public constant FEE_RATE_MAX = 0.01e6; // max 1% on origin amount\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Chain gas amount to forward as rebate if requested\n uint256 public chainGasAmount;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n }\n\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n require(newFeeRate \u003c= FEE_RATE_MAX, \"newFeeRate \u003e max\");\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n token.universalTransfer(recipient, feeAmount);\n emit FeesSwept(token, recipient, feeAmount);\n }\n\n function setChainGasAmount(uint256 newChainGasAmount) external onlyRole(GOVERNOR_ROLE) {\n uint256 oldChainGasAmount = chainGasAmount;\n chainGasAmount = newChainGasAmount;\n emit ChainGasAmountUpdated(oldChainGasAmount, newChainGasAmount);\n }\n}\n\n// contracts/FastBridgeV2.sol\n\n/// @notice FastBridgeV2 is a contract for bridging tokens across chains.\ncontract FastBridgeV2 is Admin, IFastBridgeV2, IFastBridgeV2Errors {\n using SafeERC20 for IERC20;\n using UniversalTokenLib for address;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Delay for a transaction after which it could be permisionlessly refunded\n uint256 public constant REFUND_DELAY = 7 days;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n /// @notice Maximum length of accepted callParams\n uint256 public constant MAX_CALL_PARAMS_LENGTH = 2 ** 16 - 1;\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeTxDetails) public bridgeTxDetails;\n /// @notice Relay details on destination chain\n mapping(bytes32 =\u003e BridgeRelay) public bridgeRelayDetails;\n /// @notice Unique bridge nonces tracked per originSender\n mapping(address =\u003e uint256) public senderNonces;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Replaced by senderNonces\n uint256 public immutable nonce = 0;\n /// @notice the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n bridge({\n params: params,\n paramsV2: BridgeParamsV2({\n quoteRelayer: address(0),\n quoteExclusivitySeconds: 0,\n quoteId: bytes(\"\"),\n callValue: 0,\n callParams: bytes(\"\")\n })\n });\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes memory request) external payable {\n relay({request: request, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes memory request, bytes32 destTxHash) external {\n prove({transactionId: keccak256(request), destTxHash: destTxHash, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridgeV2\n function claim(bytes memory request) external {\n claim({request: request, to: address(0)});\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003e DISPUTE_PERIOD) {\n revert DisputePeriodPassed();\n }\n\n // @dev relayer gets slashed effectively if dest relay has gone thru\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n bridgeTxDetails[transactionId].proofRelayer = address(0);\n bridgeTxDetails[transactionId].proofBlockTimestamp = 0;\n bridgeTxDetails[transactionId].proofBlockNumber = 0;\n\n emit BridgeProofDisputed(transactionId, msg.sender);\n }\n\n /// @inheritdoc IFastBridge\n function refund(bytes memory request) external {\n bytes32 transactionId = keccak256(request);\n\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n\n if (bridgeTxDetails[transactionId].status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n\n if (hasRole(REFUNDER_ROLE, msg.sender)) {\n // Refunder can refund if deadline has passed\n if (block.timestamp \u003c= transaction.deadline) revert DeadlineNotExceeded();\n } else {\n // Permissionless refund is allowed after REFUND_DELAY\n if (block.timestamp \u003c= transaction.deadline + REFUND_DELAY) revert DeadlineNotExceeded();\n }\n\n // if all checks passed, set to REFUNDED status\n bridgeTxDetails[transactionId].status = BridgeStatus.REFUNDED;\n\n // transfer origin collateral back to original sender\n address to = transaction.originSender;\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount + transaction.originFeeAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (bridgeTxDetails[transactionId].proofRelayer != relayer) revert SenderIncorrect();\n return _timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n /// @dev This method is added to achieve backwards compatibility with decoding requests into V1 structs:\n /// - `callValue` is partially reported as a zero/non-zero flag\n /// - `callParams` is ignored\n /// In order to process all kinds of requests use getBridgeTransactionV2 instead.\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory) {\n // Try decoding into V2 struct first. This will revert if V1 struct is passed\n try this.getBridgeTransactionV2(request) returns (BridgeTransactionV2 memory txV2) {\n // Note: we entirely ignore the callParams field, as it was not present in V1\n return BridgeTransaction({\n originChainId: txV2.originChainId,\n destChainId: txV2.destChainId,\n originSender: txV2.originSender,\n destRecipient: txV2.destRecipient,\n originToken: txV2.originToken,\n destToken: txV2.destToken,\n originAmount: txV2.originAmount,\n destAmount: txV2.destAmount,\n originFeeAmount: txV2.originFeeAmount,\n sendChainGas: txV2.callValue != 0,\n deadline: txV2.deadline,\n nonce: txV2.nonce\n });\n } catch {\n // Fallback to V1 struct\n return abi.decode(request, (BridgeTransaction));\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) public payable {\n int256 exclusivityEndTime = int256(block.timestamp) + paramsV2.quoteExclusivitySeconds;\n _validateBridgeParams(params, paramsV2, exclusivityEndTime);\n\n // transfer tokens to bridge contract\n /// @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _takeBridgedUserAsset(params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n\n // set status to requested\n bytes memory request = abi.encode(\n BridgeTransactionV2({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n callValue: paramsV2.callValue,\n deadline: params.deadline,\n nonce: senderNonces[params.sender]++, // increment nonce on every bridge\n exclusivityRelayer: paramsV2.quoteRelayer,\n // We checked exclusivityEndTime to be in range (0 .. params.deadline] above, so can safely cast\n exclusivityEndTime: uint256(exclusivityEndTime),\n callParams: paramsV2.callParams\n })\n );\n bytes32 transactionId = keccak256(request);\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n\n emit BridgeRequested({\n transactionId: transactionId,\n sender: params.sender,\n request: request,\n destChainId: params.dstChainId,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n sendChainGas: paramsV2.callValue != 0\n });\n emit BridgeQuoteDetails(transactionId, paramsV2.quoteId);\n }\n\n /// @inheritdoc IFastBridgeV2\n function relay(bytes memory request, address relayer) public payable {\n bytes32 transactionId = keccak256(request);\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n _validateRelayParams(transaction, transactionId, relayer);\n // mark bridge transaction as relayed\n bridgeRelayDetails[transactionId] =\n BridgeRelay({blockNumber: uint48(block.number), blockTimestamp: uint48(block.timestamp), relayer: relayer});\n\n // transfer tokens to recipient on destination chain and do an arbitrary call if requested\n address to = transaction.destRecipient;\n address token = transaction.destToken;\n uint256 amount = transaction.destAmount;\n uint256 callValue = transaction.callValue;\n\n // Emit the event before any external calls\n emit BridgeRelayed({\n transactionId: transactionId,\n relayer: relayer,\n to: to,\n originChainId: transaction.originChainId,\n originToken: transaction.originToken,\n destToken: token,\n originAmount: transaction.originAmount,\n destAmount: amount,\n chainGasAmount: callValue\n });\n\n // All state changes have been done at this point, can proceed to the external calls.\n // This follows the checks-effects-interactions pattern to mitigate potential reentrancy attacks.\n if (token == UniversalTokenLib.ETH_ADDRESS) {\n // For ETH non-zero callValue is not allowed\n if (callValue != 0) revert NativeTokenCallValueNotSupported();\n // Check that the correct msg.value was sent\n if (msg.value != amount) revert MsgValueIncorrect();\n } else {\n // For ERC20s, we check that the correct msg.value was sent\n if (msg.value != callValue) revert MsgValueIncorrect();\n // We need to transfer the tokens from the Relayer to the recipient first before performing an\n // optional post-transfer arbitrary call.\n IERC20(token).safeTransferFrom(msg.sender, to, amount);\n }\n\n if (transaction.callParams.length != 0) {\n // Arbitrary call requested, perform it while supplying full msg.value to the recipient\n // Note: if token has a fee on transfers, the recipient will have received less than `amount`.\n // This is a very niche edge case and should be handled by the recipient contract.\n _checkedCallRecipient({recipient: to, token: token, amount: amount, callParams: transaction.callParams});\n } else if (msg.value != 0) {\n // No arbitrary call requested, but msg.value was sent. This is either a relay with ETH,\n // or a non-zero callValue request with an ERC20. In both cases, transfer the ETH to the recipient.\n Address.sendValue(payable(to), msg.value);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) public onlyRole(RELAYER_ROLE) {\n // update bridge tx status given proof provided\n if (bridgeTxDetails[transactionId].status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n bridgeTxDetails[transactionId].status = BridgeStatus.RELAYER_PROVED;\n bridgeTxDetails[transactionId].proofBlockTimestamp = uint40(block.timestamp);\n bridgeTxDetails[transactionId].proofBlockNumber = uint48(block.number);\n bridgeTxDetails[transactionId].proofRelayer = relayer;\n\n emit BridgeProofProvided(transactionId, relayer, destTxHash);\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes memory request, address to) public {\n bytes32 transactionId = keccak256(request);\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n\n // update bridge tx status if able to claim origin collateral\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n\n // if \"to\" is zero addr, permissionlessly send funds to proven relayer\n if (to == address(0)) {\n to = bridgeTxDetails[transactionId].proofRelayer;\n } else if (bridgeTxDetails[transactionId].proofRelayer != msg.sender) {\n revert SenderIncorrect();\n }\n\n if (_timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003c= DISPUTE_PERIOD) {\n revert DisputePeriodNotPassed();\n }\n\n bridgeTxDetails[transactionId].status = BridgeStatus.RELAYER_CLAIMED;\n\n // update protocol fees if origin fee amount exists\n if (transaction.originFeeAmount \u003e 0) protocolFees[transaction.originToken] += transaction.originFeeAmount;\n\n // transfer origin collateral less fee to specified address\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositClaimed(transactionId, bridgeTxDetails[transactionId].proofRelayer, to, token, amount);\n }\n\n function bridgeStatuses(bytes32 transactionId) public view returns (BridgeStatus status) {\n return bridgeTxDetails[transactionId].status;\n }\n\n function bridgeProofs(bytes32 transactionId) public view returns (uint96 timestamp, address relayer) {\n timestamp = bridgeTxDetails[transactionId].proofBlockTimestamp;\n relayer = bridgeTxDetails[transactionId].proofRelayer;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeRelays(bytes32 transactionId) public view returns (bool) {\n // has this transactionId been relayed?\n return bridgeRelayDetails[transactionId].relayer != address(0);\n }\n\n /// @inheritdoc IFastBridgeV2\n function getBridgeTransactionV2(bytes memory request) public pure returns (BridgeTransactionV2 memory) {\n return abi.decode(request, (BridgeTransactionV2));\n }\n\n /// @notice Takes the bridged asset from the user into FastBridgeV2 custody. It will be later\n /// claimed by the relayer who completed the relay on destination chain, or refunded back to the user,\n /// should no one complete the relay.\n function _takeBridgedUserAsset(address token, uint256 amount) internal returns (uint256 amountTaken) {\n if (token == UniversalTokenLib.ETH_ADDRESS) {\n // For ETH we just need to check that the supplied msg.value is correct.\n // Supplied `msg.value` is already in FastBridgeV2 custody.\n if (amount != msg.value) revert MsgValueIncorrect();\n amountTaken = msg.value;\n } else {\n // For ERC20s, token is explicitly transferred from the user to FastBridgeV2.\n // We don't allow non-zero `msg.value` to avoid extra funds from being stuck in FastBridgeV2.\n token.assertIsContract();\n if (msg.value != 0) revert MsgValueIncorrect();\n amountTaken = IERC20(token).balanceOf(address(this));\n IERC20(token).safeTransferFrom(msg.sender, address(this), amount);\n // Use the balance difference as the amount taken in case of fee on transfer tokens.\n amountTaken = IERC20(token).balanceOf(address(this)) - amountTaken;\n }\n }\n\n /// @notice Calls the Recipient's hook function with the specified callParams and performs\n /// all the necessary checks for the returned value.\n function _checkedCallRecipient(\n address recipient,\n address token,\n uint256 amount,\n bytes memory callParams\n )\n internal\n {\n bytes memory hookData =\n abi.encodeCall(IFastBridgeRecipient.fastBridgeTransferReceived, (token, amount, callParams));\n // This will bubble any revert messages from the hook function\n bytes memory returnData = Address.functionCallWithValue({target: recipient, data: hookData, value: msg.value});\n // Explicit revert if no return data at all\n if (returnData.length == 0) revert RecipientNoReturnValue();\n // Check that exactly a single return value was returned\n if (returnData.length != 32) revert RecipientIncorrectReturnValue();\n // Return value should be abi-encoded hook function selector\n if (bytes32(returnData) != bytes32(IFastBridgeRecipient.fastBridgeTransferReceived.selector)) {\n revert RecipientIncorrectReturnValue();\n }\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint40(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint40).max but\n /// proof.timestamp \u003c type(uint40).max via unchecked statement\n /// @param proofBlockTimestamp The bridge proof block timestamp\n /// @return delta Time delta since proof submitted\n function _timeSince(uint40 proofBlockTimestamp) internal view returns (uint256 delta) {\n unchecked {\n delta = uint40(block.timestamp) - proofBlockTimestamp;\n }\n }\n\n /// @notice Performs all the necessary checks for a bridge to happen.\n /// @dev There's no good way to refactor this function to reduce cyclomatic complexity due to\n /// the number of checks that need to be performed, so we skip the code-complexity rule here.\n // solhint-disable-next-line code-complexity\n function _validateBridgeParams(\n BridgeParams memory params,\n BridgeParamsV2 memory paramsV2,\n int256 exclusivityEndTime\n )\n internal\n view\n {\n // Check V1 (legacy) params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.sender == address(0) || params.to == address(0)) revert ZeroAddress();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n // Check V2 params\n if (paramsV2.callParams.length \u003e MAX_CALL_PARAMS_LENGTH) revert CallParamsLengthAboveMax();\n if (paramsV2.callValue != 0 \u0026\u0026 params.destToken == UniversalTokenLib.ETH_ADDRESS) {\n revert NativeTokenCallValueNotSupported();\n }\n // exclusivityEndTime must be in range (0 .. params.deadline]\n if (exclusivityEndTime \u003c= 0 || exclusivityEndTime \u003e int256(params.deadline)) {\n revert ExclusivityParamsIncorrect();\n }\n }\n\n /// @notice Performs all the necessary checks for a relay to happen.\n function _validateRelayParams(\n BridgeTransactionV2 memory transaction,\n bytes32 transactionId,\n address relayer\n )\n internal\n view\n {\n if (relayer == address(0)) revert ZeroAddress();\n // Check if the transaction has already been relayed\n if (bridgeRelays(transactionId)) revert TransactionRelayed();\n if (transaction.destChainId != block.chainid) revert ChainIncorrect();\n // Check the deadline for relay to happen\n if (block.timestamp \u003e transaction.deadline) revert DeadlineExceeded();\n // Check the exclusivity period, if it is still ongoing\n // forgefmt: disable-next-item\n if (\n transaction.exclusivityRelayer != address(0) \u0026\u0026\n transaction.exclusivityRelayer != relayer \u0026\u0026\n block.timestamp \u003c= transaction.exclusivityEndTime\n ) {\n revert ExclusivityPeriodNotPassed();\n }\n }\n}\n","language":"Solidity","languageVersion":"0.8.24","compilerVersion":"0.8.24","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"16564:6066:0:-:0;;;;;;;;;;;;;;;-1:-1:-1;;;16564:6066:0;;;;;;;;;;;;;;;;;","srcMapRuntime":"16564:6066:0:-:0;;;;;;;;","abiDefinition":[{"inputs":[{"internalType":"address","name":"target","type":"address"}],"name":"AddressEmptyCode","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"AddressInsufficientBalance","type":"error"},{"inputs":[],"name":"FailedInnerCall","type":"error"}],"userDoc":{"kind":"user","methods":{},"version":1},"developerDoc":{"details":"Collection of functions related to the address type","errors":{"AddressEmptyCode(address)":[{"details":"There's no code at `target` (it is not a contract)."}],"AddressInsufficientBalance(address)":[{"details":"The ETH balance of the account is not enough to perform the operation."}],"FailedInnerCall()":[{"details":"A call to an address target failed. The target may have reverted."}]},"kind":"dev","methods":{},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"}],\"name\":\"AddressEmptyCode\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"AddressInsufficientBalance\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"FailedInnerCall\",\"type\":\"error\"}],\"devdoc\":{\"details\":\"Collection of functions related to the address type\",\"errors\":{\"AddressEmptyCode(address)\":[{\"details\":\"There's no code at `target` (it is not a contract).\"}],\"AddressInsufficientBalance(address)\":[{\"details\":\"The ETH balance of the account is not enough to perform the operation.\"}],\"FailedInnerCall()\":[{\"details\":\"A call to an address target failed. The target may have reverted.\"}]},\"kind\":\"dev\",\"methods\":{},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeV2.sol\":\"Address\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeV2.sol\":{\"keccak256\":\"0xfd916c030b1ffca5a136817827b8018c8ba42ca089905747f3de6148b73eb35e\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://18e6438c4096deb8ae453fb3365ba2b07d52944e93c08288fc5d012b71bf6bb3\",\"dweb:/ipfs/QmfEMqpT1zz6RRm7UuHLRowe1tds2cTGLrVonfm9XSCACj\"]}},\"version\":1}"},"hashes":{}},"solidity/FastBridgeV2.sol:Admin":{"code":"0x60806040523480156200001157600080fd5b50604051620014123803806200141283398101604081905262000034916200018e565b6200004160008262000049565b5050620001b9565b60008062000058848462000086565b905080156200007d5760008481526001602052604090206200007b908462000134565b505b90505b92915050565b6000828152602081815260408083206001600160a01b038516845290915281205460ff166200012b576000838152602081815260408083206001600160a01b03861684529091529020805460ff19166001179055620000e23390565b6001600160a01b0316826001600160a01b0316847f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a450600162000080565b50600062000080565b60006200007d836001600160a01b03841660008181526001830160205260408120546200012b5750815460018181018455600084815260208082209093018490558454848252828601909352604090209190915562000080565b600060208284031215620001a157600080fd5b81516001600160a01b03811681146200007d57600080fd5b61124980620001c96000396000f3fe608060405234801561001057600080fd5b50600436106101775760003560e01c806391d14854116100d8578063bf333f2c1161008c578063d547741f11610066578063d547741f14610385578063dcf844a714610398578063e00a83e0146103b857600080fd5b8063bf333f2c14610341578063ca15c8731461034b578063ccc574901461035e57600080fd5b8063a217fddf116100bd578063a217fddf14610313578063b13aa2d61461031b578063b250fe6b1461032e57600080fd5b806391d14854146102a8578063926d7d7f146102ec57600080fd5b80632f2ff15d1161012f57806358f858801161011457806358f85880146102405780635960ccf2146102495780639010d07c1461027057600080fd5b80632f2ff15d1461021a57806336568abe1461022d57600080fd5b806306f333f21161016057806306f333f2146101d95780630f5f6ed7146101ee578063248a9ca3146101f757600080fd5b806301ffc9a71461017c57806303ed0ee5146101a4575b600080fd5b61018f61018a366004611013565b6103c1565b60405190151581526020015b60405180910390f35b6101cb7f043c983c49d46f0e102151eaf8085d4a2e6571d5df2d47b013f39bddfd4a639d81565b60405190815260200161019b565b6101ec6101e736600461107e565b61041d565b005b6101cb61271081565b6101cb6102053660046110b1565b60009081526020819052604090206001015490565b6101ec6102283660046110ca565b61050b565b6101ec61023b3660046110ca565b610536565b6101cb60025481565b6101cb7fdb9556138406326f00296e13ea2ad7db24ba82381212d816b1a40c23b466b32781565b61028361027e3660046110ed565b61058f565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200161019b565b61018f6102b63660046110ca565b60009182526020828152604080842073ffffffffffffffffffffffffffffffffffffffff93909316845291905290205460ff1690565b6101cb7fe2b7fb3b832174769106daebcfd6d1970523240dda11281102db9363b83b0dc481565b6101cb600081565b6101ec6103293660046110b1565b6105ae565b6101ec61033c3660046110b1565b610690565b6101cb620f424081565b6101cb6103593660046110b1565b6106f8565b6101cb7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f5581565b6101ec6103933660046110ca565b61070f565b6101cb6103a636600461110f565b60036020526000908152604090205481565b6101cb60045481565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f5a05180f000000000000000000000000000000000000000000000000000000001480610417575061041782610734565b92915050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f55610447816107cb565b73ffffffffffffffffffffffffffffffffffffffff83166000908152600360205260408120549081900361047b5750505050565b73ffffffffffffffffffffffffffffffffffffffff84166000818152600360205260408120556104ac9084836107d8565b6040805173ffffffffffffffffffffffffffffffffffffffff8087168252851660208201529081018290527f244e51bc38c1452fa8aaf487bcb4bca36c2baa3a5fbdb776b1eabd8dc6d277cd9060600160405180910390a1505b505050565b600082815260208190526040902060010154610526816107cb565b610530838361092f565b50505050565b73ffffffffffffffffffffffffffffffffffffffff81163314610585576040517f6697b23200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6105068282610964565b60008281526001602052604081206105a79083610991565b9392505050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f556105d8816107cb565b612710821115610649576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f6e657746656552617465203e206d61780000000000000000000000000000000060448201526064015b60405180910390fd5b600280549083905560408051828152602081018590527f14914da2bf76024616fbe1859783fcd4dbddcb179b1f3a854949fbf920dcb95791015b60405180910390a1505050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f556106ba816107cb565b600480549083905560408051828152602081018590527f5cf09b12f3f56b4c564d51b25b40360af6d795198adb61ae0806a36c294323fa9101610683565b60008181526001602052604081206104179061099d565b60008281526020819052604090206001015461072a816107cb565b6105308383610964565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f7965db0b00000000000000000000000000000000000000000000000000000000148061041757507f01ffc9a7000000000000000000000000000000000000000000000000000000007fffffffff00000000000000000000000000000000000000000000000000000000831614610417565b6107d581336109a7565b50565b3073ffffffffffffffffffffffffffffffffffffffff8316036107fa57505050565b8060000361080757505050565b7fffffffffffffffffffffffff111111111111111111111111111111111111111273ffffffffffffffffffffffffffffffffffffffff84160161090e5760008273ffffffffffffffffffffffffffffffffffffffff168260405160006040518083038185875af1925050503d806000811461089e576040519150601f19603f3d011682016040523d82523d6000602084013e6108a3565b606091505b5050905080610530576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f455448207472616e73666572206661696c6564000000000000000000000000006044820152606401610640565b61050673ffffffffffffffffffffffffffffffffffffffff84168383610a31565b60008061093c8484610abe565b905080156105a757600084815260016020526040902061095c9084610bba565b509392505050565b6000806109718484610bdc565b905080156105a757600084815260016020526040902061095c9084610c97565b60006105a78383610cb9565b6000610417825490565b60008281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915290205460ff16610a2d576040517fe2517d3f00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8216600482015260248101839052604401610640565b5050565b6040805173ffffffffffffffffffffffffffffffffffffffff8416602482015260448082018490528251808303909101815260649091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fa9059cbb00000000000000000000000000000000000000000000000000000000179052610506908490610ce3565b60008281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915281205460ff16610bb25760008381526020818152604080832073ffffffffffffffffffffffffffffffffffffffff86168452909152902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055610b503390565b73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16847f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a4506001610417565b506000610417565b60006105a78373ffffffffffffffffffffffffffffffffffffffff8416610d79565b60008281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915281205460ff1615610bb25760008381526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8616808552925280832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016905551339286917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a4506001610417565b60006105a78373ffffffffffffffffffffffffffffffffffffffff8416610dc0565b6000826000018281548110610cd057610cd061112a565b9060005260206000200154905092915050565b6000610d0573ffffffffffffffffffffffffffffffffffffffff841683610eb3565b90508051600014158015610d2a575080806020019051810190610d289190611159565b155b15610506576040517f5274afe700000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff84166004820152602401610640565b6000818152600183016020526040812054610bb257508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155610417565b60008181526001830160205260408120548015610ea9576000610de460018361117b565b8554909150600090610df89060019061117b565b9050808214610e5d576000866000018281548110610e1857610e1861112a565b9060005260206000200154905080876000018481548110610e3b57610e3b61112a565b6000918252602080832090910192909255918252600188019052604090208390555b8554869080610e6e57610e6e6111b5565b600190038181906000526020600020016000905590558560010160008681526020019081526020016000206000905560019350505050610417565b6000915050610417565b60606105a783836000846000808573ffffffffffffffffffffffffffffffffffffffff168486604051610ee691906111e4565b60006040518083038185875af1925050503d8060008114610f23576040519150601f19603f3d011682016040523d82523d6000602084013e610f28565b606091505b5091509150610f38868383610f42565b9695505050505050565b606082610f5757610f5282610fd1565b6105a7565b8151158015610f7b575073ffffffffffffffffffffffffffffffffffffffff84163b155b15610fca576040517f9996b31500000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff85166004820152602401610640565b50806105a7565b805115610fe15780518082602001fd5b6040517f1425ea4200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006020828403121561102557600080fd5b81357fffffffff00000000000000000000000000000000000000000000000000000000811681146105a757600080fd5b803573ffffffffffffffffffffffffffffffffffffffff8116811461107957600080fd5b919050565b6000806040838503121561109157600080fd5b61109a83611055565b91506110a860208401611055565b90509250929050565b6000602082840312156110c357600080fd5b5035919050565b600080604083850312156110dd57600080fd5b823591506110a860208401611055565b6000806040838503121561110057600080fd5b50508035926020909101359150565b60006020828403121561112157600080fd5b6105a782611055565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60006020828403121561116b57600080fd5b815180151581146105a757600080fd5b81810381811115610417577f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fd5b6000825160005b8181101561120557602081860181015185830152016111eb565b50600092019182525091905056fea2646970667358221220b13443229221519c0fdb3ac2db22c34ccdfff8fd9f142c9a058dcefb00a5a9d864736f6c63430008180033","runtime-code":"0x608060405234801561001057600080fd5b50600436106101775760003560e01c806391d14854116100d8578063bf333f2c1161008c578063d547741f11610066578063d547741f14610385578063dcf844a714610398578063e00a83e0146103b857600080fd5b8063bf333f2c14610341578063ca15c8731461034b578063ccc574901461035e57600080fd5b8063a217fddf116100bd578063a217fddf14610313578063b13aa2d61461031b578063b250fe6b1461032e57600080fd5b806391d14854146102a8578063926d7d7f146102ec57600080fd5b80632f2ff15d1161012f57806358f858801161011457806358f85880146102405780635960ccf2146102495780639010d07c1461027057600080fd5b80632f2ff15d1461021a57806336568abe1461022d57600080fd5b806306f333f21161016057806306f333f2146101d95780630f5f6ed7146101ee578063248a9ca3146101f757600080fd5b806301ffc9a71461017c57806303ed0ee5146101a4575b600080fd5b61018f61018a366004611013565b6103c1565b60405190151581526020015b60405180910390f35b6101cb7f043c983c49d46f0e102151eaf8085d4a2e6571d5df2d47b013f39bddfd4a639d81565b60405190815260200161019b565b6101ec6101e736600461107e565b61041d565b005b6101cb61271081565b6101cb6102053660046110b1565b60009081526020819052604090206001015490565b6101ec6102283660046110ca565b61050b565b6101ec61023b3660046110ca565b610536565b6101cb60025481565b6101cb7fdb9556138406326f00296e13ea2ad7db24ba82381212d816b1a40c23b466b32781565b61028361027e3660046110ed565b61058f565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200161019b565b61018f6102b63660046110ca565b60009182526020828152604080842073ffffffffffffffffffffffffffffffffffffffff93909316845291905290205460ff1690565b6101cb7fe2b7fb3b832174769106daebcfd6d1970523240dda11281102db9363b83b0dc481565b6101cb600081565b6101ec6103293660046110b1565b6105ae565b6101ec61033c3660046110b1565b610690565b6101cb620f424081565b6101cb6103593660046110b1565b6106f8565b6101cb7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f5581565b6101ec6103933660046110ca565b61070f565b6101cb6103a636600461110f565b60036020526000908152604090205481565b6101cb60045481565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f5a05180f000000000000000000000000000000000000000000000000000000001480610417575061041782610734565b92915050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f55610447816107cb565b73ffffffffffffffffffffffffffffffffffffffff83166000908152600360205260408120549081900361047b5750505050565b73ffffffffffffffffffffffffffffffffffffffff84166000818152600360205260408120556104ac9084836107d8565b6040805173ffffffffffffffffffffffffffffffffffffffff8087168252851660208201529081018290527f244e51bc38c1452fa8aaf487bcb4bca36c2baa3a5fbdb776b1eabd8dc6d277cd9060600160405180910390a1505b505050565b600082815260208190526040902060010154610526816107cb565b610530838361092f565b50505050565b73ffffffffffffffffffffffffffffffffffffffff81163314610585576040517f6697b23200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6105068282610964565b60008281526001602052604081206105a79083610991565b9392505050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f556105d8816107cb565b612710821115610649576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f6e657746656552617465203e206d61780000000000000000000000000000000060448201526064015b60405180910390fd5b600280549083905560408051828152602081018590527f14914da2bf76024616fbe1859783fcd4dbddcb179b1f3a854949fbf920dcb95791015b60405180910390a1505050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f556106ba816107cb565b600480549083905560408051828152602081018590527f5cf09b12f3f56b4c564d51b25b40360af6d795198adb61ae0806a36c294323fa9101610683565b60008181526001602052604081206104179061099d565b60008281526020819052604090206001015461072a816107cb565b6105308383610964565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f7965db0b00000000000000000000000000000000000000000000000000000000148061041757507f01ffc9a7000000000000000000000000000000000000000000000000000000007fffffffff00000000000000000000000000000000000000000000000000000000831614610417565b6107d581336109a7565b50565b3073ffffffffffffffffffffffffffffffffffffffff8316036107fa57505050565b8060000361080757505050565b7fffffffffffffffffffffffff111111111111111111111111111111111111111273ffffffffffffffffffffffffffffffffffffffff84160161090e5760008273ffffffffffffffffffffffffffffffffffffffff168260405160006040518083038185875af1925050503d806000811461089e576040519150601f19603f3d011682016040523d82523d6000602084013e6108a3565b606091505b5050905080610530576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f455448207472616e73666572206661696c6564000000000000000000000000006044820152606401610640565b61050673ffffffffffffffffffffffffffffffffffffffff84168383610a31565b60008061093c8484610abe565b905080156105a757600084815260016020526040902061095c9084610bba565b509392505050565b6000806109718484610bdc565b905080156105a757600084815260016020526040902061095c9084610c97565b60006105a78383610cb9565b6000610417825490565b60008281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915290205460ff16610a2d576040517fe2517d3f00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8216600482015260248101839052604401610640565b5050565b6040805173ffffffffffffffffffffffffffffffffffffffff8416602482015260448082018490528251808303909101815260649091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fa9059cbb00000000000000000000000000000000000000000000000000000000179052610506908490610ce3565b60008281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915281205460ff16610bb25760008381526020818152604080832073ffffffffffffffffffffffffffffffffffffffff86168452909152902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055610b503390565b73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16847f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a4506001610417565b506000610417565b60006105a78373ffffffffffffffffffffffffffffffffffffffff8416610d79565b60008281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915281205460ff1615610bb25760008381526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8616808552925280832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016905551339286917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a4506001610417565b60006105a78373ffffffffffffffffffffffffffffffffffffffff8416610dc0565b6000826000018281548110610cd057610cd061112a565b9060005260206000200154905092915050565b6000610d0573ffffffffffffffffffffffffffffffffffffffff841683610eb3565b90508051600014158015610d2a575080806020019051810190610d289190611159565b155b15610506576040517f5274afe700000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff84166004820152602401610640565b6000818152600183016020526040812054610bb257508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155610417565b60008181526001830160205260408120548015610ea9576000610de460018361117b565b8554909150600090610df89060019061117b565b9050808214610e5d576000866000018281548110610e1857610e1861112a565b9060005260206000200154905080876000018481548110610e3b57610e3b61112a565b6000918252602080832090910192909255918252600188019052604090208390555b8554869080610e6e57610e6e6111b5565b600190038181906000526020600020016000905590558560010160008681526020019081526020016000206000905560019350505050610417565b6000915050610417565b60606105a783836000846000808573ffffffffffffffffffffffffffffffffffffffff168486604051610ee691906111e4565b60006040518083038185875af1925050503d8060008114610f23576040519150601f19603f3d011682016040523d82523d6000602084013e610f28565b606091505b5091509150610f38868383610f42565b9695505050505050565b606082610f5757610f5282610fd1565b6105a7565b8151158015610f7b575073ffffffffffffffffffffffffffffffffffffffff84163b155b15610fca576040517f9996b31500000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff85166004820152602401610640565b50806105a7565b805115610fe15780518082602001fd5b6040517f1425ea4200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006020828403121561102557600080fd5b81357fffffffff00000000000000000000000000000000000000000000000000000000811681146105a757600080fd5b803573ffffffffffffffffffffffffffffffffffffffff8116811461107957600080fd5b919050565b6000806040838503121561109157600080fd5b61109a83611055565b91506110a860208401611055565b90509250929050565b6000602082840312156110c357600080fd5b5035919050565b600080604083850312156110dd57600080fd5b823591506110a860208401611055565b6000806040838503121561110057600080fd5b50508035926020909101359150565b60006020828403121561112157600080fd5b6105a782611055565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60006020828403121561116b57600080fd5b815180151581146105a757600080fd5b81810381811115610417577f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fd5b6000825160005b8181101561120557602081860181015185830152016111eb565b50600092019182525091905056fea2646970667358221220b13443229221519c0fdb3ac2db22c34ccdfff8fd9f142c9a058dcefb00a5a9d864736f6c63430008180033","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.24 ^0.8.0 ^0.8.20;\n\n// contracts/interfaces/IAdmin.sol\n\ninterface IAdmin {\n // ============ Events ============\n\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n event ChainGasAmountUpdated(uint256 oldChainGasAmount, uint256 newChainGasAmount);\n\n // ============ Methods ============\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n\n function setChainGasAmount(uint256 newChainGasAmount) external;\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IFastBridgeRecipient.sol\n\ninterface IFastBridgeRecipient {\n function fastBridgeTransferReceived(\n address token,\n uint256 amount,\n bytes memory callParams\n )\n external\n payable\n returns (bytes4);\n}\n\n// contracts/interfaces/IFastBridgeV2Errors.sol\n\ninterface IFastBridgeV2Errors {\n error AmountIncorrect();\n error CallParamsLengthAboveMax();\n error ChainIncorrect();\n error ExclusivityParamsIncorrect();\n error MsgValueIncorrect();\n error NativeTokenCallValueNotSupported();\n error SenderIncorrect();\n error StatusIncorrect();\n error ZeroAddress();\n\n error RecipientIncorrectReturnValue();\n error RecipientNoReturnValue();\n\n error DeadlineExceeded();\n error DeadlineNotExceeded();\n error DeadlineTooShort();\n error DisputePeriodNotPassed();\n error DisputePeriodPassed();\n error ExclusivityPeriodNotPassed();\n\n error TransactionRelayed();\n}\n\n// contracts/libs/Errors.sol\n\nerror DeadlineExceeded();\nerror DeadlineNotExceeded();\nerror DeadlineTooShort();\nerror InsufficientOutputAmount();\n\nerror MsgValueIncorrect();\nerror PoolNotFound();\nerror TokenAddressMismatch();\nerror TokenNotContract();\nerror TokenNotETH();\nerror TokensIdentical();\n\nerror ChainIncorrect();\nerror AmountIncorrect();\nerror ZeroAddress();\n\nerror DisputePeriodNotPassed();\nerror DisputePeriodPassed();\nerror SenderIncorrect();\nerror StatusIncorrect();\nerror TransactionIdIncorrect();\nerror TransactionRelayed();\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// contracts/interfaces/IFastBridgeV2.sol\n\ninterface IFastBridgeV2 is IFastBridge {\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n struct BridgeTxDetails {\n BridgeStatus status;\n uint40 proofBlockTimestamp;\n uint48 proofBlockNumber;\n address proofRelayer;\n }\n\n struct BridgeRelay {\n uint48 blockNumber;\n uint48 blockTimestamp;\n address relayer;\n }\n\n /// @notice New params introduced in the FastBridgeV2.\n /// We are passing fields from the older BridgeParams struct outside of this struct\n /// for backwards compatibility.\n /// Note: quoteRelayer and quoteExclusivitySeconds are either both zero (indicating no exclusivity)\n /// or both non-zero (indicating exclusivity for the given period).\n /// Note: callValue \u003e 0 can NOT be used with destToken = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE (ETH_ADDRESS)\n /// @param quoteRelayer Relayer that provided the quote for the transaction\n /// @param quoteExclusivitySeconds Period of time the quote relayer is guaranteed exclusivity after user's deposit\n /// @param quoteId Unique quote identifier used for tracking the quote\n /// @param callValue ETH value to send to the recipient (if any)\n /// @param callParams Parameters for the arbitrary call to the destination recipient (if any)\n struct BridgeParamsV2 {\n address quoteRelayer;\n int256 quoteExclusivitySeconds;\n bytes quoteId;\n uint256 callValue;\n bytes callParams;\n }\n\n /// @notice Updated bridge transaction struct to include parameters introduced in FastBridgeV2.\n /// Note: only `exclusivityRelayer` can fill such a transaction until `exclusivityEndTime`.\n /// TODO: consider changing the encoding scheme to prevent spending extra gas on decoding.\n struct BridgeTransactionV2 {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n uint256 callValue; // ETH value to send to the recipient (if any) - replaces V1's sendChainGas flag\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n address exclusivityRelayer;\n uint256 exclusivityEndTime;\n bytes callParams;\n }\n\n event BridgeQuoteDetails(bytes32 indexed transactionId, bytes quoteId);\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability\n /// to provide temporary exclusivity fill rights for the quote relayer.\n /// @param params The parameters required to bridge\n /// @param paramsV2 The parameters for exclusivity fill rights (optional, can be left empty)\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function relay(bytes memory request, address relayer) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param transactionId The transaction id associated with the encoded bridge transaction to prove\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital.\n /// @notice Can only send funds to the relayer address on the proof.\n /// @param request The encoded bridge transaction to claim on origin chain\n function claim(bytes memory request) external;\n /// @notice Checks if a transaction has been relayed\n /// @param transactionId The ID of the transaction to check\n /// @return True if the transaction has been relayed, false otherwise\n function bridgeRelays(bytes32 transactionId) external view returns (bool);\n\n /// @notice Returns the status of a bridge transaction\n /// @param transactionId The ID of the bridge transaction\n /// @return BridgeStatus Status of the bridge transaction\n function bridgeStatuses(bytes32 transactionId) external view returns (BridgeStatus);\n\n /// @notice Returns the timestamp and relayer of a bridge proof\n /// @param transactionId The ID of the bridge transaction\n /// @return timestamp The timestamp of the bridge proof\n /// @return relayer The relayer address of the bridge proof\n function bridgeProofs(bytes32 transactionId) external view returns (uint96 timestamp, address relayer);\n\n /// @notice Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\n /// @param request The bridge request to decode\n function getBridgeTransactionV2(bytes memory request) external view returns (BridgeTransactionV2 memory);\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// contracts/libs/UniversalToken.sol\n\nlibrary UniversalTokenLib {\n using SafeERC20 for IERC20;\n\n address internal constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Transfers tokens to the given account. Reverts if transfer is not successful.\n /// @dev This might trigger fallback, if ETH is transferred to the contract.\n /// Make sure this can not lead to reentrancy attacks.\n function universalTransfer(address token, address to, uint256 value) internal {\n // Don't do anything, if need to send tokens to this address\n if (to == address(this)) return;\n // Don't do anything, if trying to send zero value\n if (value == 0) return;\n if (token == ETH_ADDRESS) {\n /// @dev Note: this can potentially lead to executing code in `to`.\n // solhint-disable-next-line avoid-low-level-calls\n (bool success,) = to.call{value: value}(\"\");\n require(success, \"ETH transfer failed\");\n } else {\n IERC20(token).safeTransfer(to, value);\n }\n }\n\n /// @notice Issues an infinite allowance to the spender, if the current allowance is insufficient\n /// to spend the given amount.\n function universalApproveInfinity(address token, address spender, uint256 amountToSpend) internal {\n // ETH Chad doesn't require your approval\n if (token == ETH_ADDRESS) return;\n // No-op if allowance is already sufficient\n uint256 allowance = IERC20(token).allowance(address(this), spender);\n if (allowance \u003e= amountToSpend) return;\n // Otherwise, reset approval to 0 and set to max allowance\n if (allowance \u003e 0) IERC20(token).safeDecreaseAllowance(spender, allowance);\n IERC20(token).safeIncreaseAllowance(spender, type(uint256).max);\n }\n\n /// @notice Returns the balance of the given token (or native ETH) for the given account.\n function universalBalanceOf(address token, address account) internal view returns (uint256) {\n if (token == ETH_ADDRESS) {\n return account.balance;\n } else {\n return IERC20(token).balanceOf(account);\n }\n }\n\n /// @dev Checks that token is a contract and not ETH_ADDRESS.\n function assertIsContract(address token) internal view {\n // Check that ETH_ADDRESS was not used (in case this is a predeploy on any of the chains)\n if (token == UniversalTokenLib.ETH_ADDRESS) revert TokenNotContract();\n // Check that token is not an EOA\n if (token.code.length == 0) revert TokenNotContract();\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/Admin.sol\n\ncontract Admin is IAdmin, AccessControlEnumerable {\n using UniversalTokenLib for address;\n\n bytes32 public constant RELAYER_ROLE = keccak256(\"RELAYER_ROLE\");\n bytes32 public constant REFUNDER_ROLE = keccak256(\"REFUNDER_ROLE\");\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n uint256 public constant FEE_BPS = 1e6;\n uint256 public constant FEE_RATE_MAX = 0.01e6; // max 1% on origin amount\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Chain gas amount to forward as rebate if requested\n uint256 public chainGasAmount;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n }\n\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n require(newFeeRate \u003c= FEE_RATE_MAX, \"newFeeRate \u003e max\");\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n token.universalTransfer(recipient, feeAmount);\n emit FeesSwept(token, recipient, feeAmount);\n }\n\n function setChainGasAmount(uint256 newChainGasAmount) external onlyRole(GOVERNOR_ROLE) {\n uint256 oldChainGasAmount = chainGasAmount;\n chainGasAmount = newChainGasAmount;\n emit ChainGasAmountUpdated(oldChainGasAmount, newChainGasAmount);\n }\n}\n\n// contracts/FastBridgeV2.sol\n\n/// @notice FastBridgeV2 is a contract for bridging tokens across chains.\ncontract FastBridgeV2 is Admin, IFastBridgeV2, IFastBridgeV2Errors {\n using SafeERC20 for IERC20;\n using UniversalTokenLib for address;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Delay for a transaction after which it could be permisionlessly refunded\n uint256 public constant REFUND_DELAY = 7 days;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n /// @notice Maximum length of accepted callParams\n uint256 public constant MAX_CALL_PARAMS_LENGTH = 2 ** 16 - 1;\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeTxDetails) public bridgeTxDetails;\n /// @notice Relay details on destination chain\n mapping(bytes32 =\u003e BridgeRelay) public bridgeRelayDetails;\n /// @notice Unique bridge nonces tracked per originSender\n mapping(address =\u003e uint256) public senderNonces;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Replaced by senderNonces\n uint256 public immutable nonce = 0;\n /// @notice the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n bridge({\n params: params,\n paramsV2: BridgeParamsV2({\n quoteRelayer: address(0),\n quoteExclusivitySeconds: 0,\n quoteId: bytes(\"\"),\n callValue: 0,\n callParams: bytes(\"\")\n })\n });\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes memory request) external payable {\n relay({request: request, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes memory request, bytes32 destTxHash) external {\n prove({transactionId: keccak256(request), destTxHash: destTxHash, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridgeV2\n function claim(bytes memory request) external {\n claim({request: request, to: address(0)});\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003e DISPUTE_PERIOD) {\n revert DisputePeriodPassed();\n }\n\n // @dev relayer gets slashed effectively if dest relay has gone thru\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n bridgeTxDetails[transactionId].proofRelayer = address(0);\n bridgeTxDetails[transactionId].proofBlockTimestamp = 0;\n bridgeTxDetails[transactionId].proofBlockNumber = 0;\n\n emit BridgeProofDisputed(transactionId, msg.sender);\n }\n\n /// @inheritdoc IFastBridge\n function refund(bytes memory request) external {\n bytes32 transactionId = keccak256(request);\n\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n\n if (bridgeTxDetails[transactionId].status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n\n if (hasRole(REFUNDER_ROLE, msg.sender)) {\n // Refunder can refund if deadline has passed\n if (block.timestamp \u003c= transaction.deadline) revert DeadlineNotExceeded();\n } else {\n // Permissionless refund is allowed after REFUND_DELAY\n if (block.timestamp \u003c= transaction.deadline + REFUND_DELAY) revert DeadlineNotExceeded();\n }\n\n // if all checks passed, set to REFUNDED status\n bridgeTxDetails[transactionId].status = BridgeStatus.REFUNDED;\n\n // transfer origin collateral back to original sender\n address to = transaction.originSender;\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount + transaction.originFeeAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (bridgeTxDetails[transactionId].proofRelayer != relayer) revert SenderIncorrect();\n return _timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n /// @dev This method is added to achieve backwards compatibility with decoding requests into V1 structs:\n /// - `callValue` is partially reported as a zero/non-zero flag\n /// - `callParams` is ignored\n /// In order to process all kinds of requests use getBridgeTransactionV2 instead.\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory) {\n // Try decoding into V2 struct first. This will revert if V1 struct is passed\n try this.getBridgeTransactionV2(request) returns (BridgeTransactionV2 memory txV2) {\n // Note: we entirely ignore the callParams field, as it was not present in V1\n return BridgeTransaction({\n originChainId: txV2.originChainId,\n destChainId: txV2.destChainId,\n originSender: txV2.originSender,\n destRecipient: txV2.destRecipient,\n originToken: txV2.originToken,\n destToken: txV2.destToken,\n originAmount: txV2.originAmount,\n destAmount: txV2.destAmount,\n originFeeAmount: txV2.originFeeAmount,\n sendChainGas: txV2.callValue != 0,\n deadline: txV2.deadline,\n nonce: txV2.nonce\n });\n } catch {\n // Fallback to V1 struct\n return abi.decode(request, (BridgeTransaction));\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) public payable {\n int256 exclusivityEndTime = int256(block.timestamp) + paramsV2.quoteExclusivitySeconds;\n _validateBridgeParams(params, paramsV2, exclusivityEndTime);\n\n // transfer tokens to bridge contract\n /// @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _takeBridgedUserAsset(params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n\n // set status to requested\n bytes memory request = abi.encode(\n BridgeTransactionV2({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n callValue: paramsV2.callValue,\n deadline: params.deadline,\n nonce: senderNonces[params.sender]++, // increment nonce on every bridge\n exclusivityRelayer: paramsV2.quoteRelayer,\n // We checked exclusivityEndTime to be in range (0 .. params.deadline] above, so can safely cast\n exclusivityEndTime: uint256(exclusivityEndTime),\n callParams: paramsV2.callParams\n })\n );\n bytes32 transactionId = keccak256(request);\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n\n emit BridgeRequested({\n transactionId: transactionId,\n sender: params.sender,\n request: request,\n destChainId: params.dstChainId,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n sendChainGas: paramsV2.callValue != 0\n });\n emit BridgeQuoteDetails(transactionId, paramsV2.quoteId);\n }\n\n /// @inheritdoc IFastBridgeV2\n function relay(bytes memory request, address relayer) public payable {\n bytes32 transactionId = keccak256(request);\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n _validateRelayParams(transaction, transactionId, relayer);\n // mark bridge transaction as relayed\n bridgeRelayDetails[transactionId] =\n BridgeRelay({blockNumber: uint48(block.number), blockTimestamp: uint48(block.timestamp), relayer: relayer});\n\n // transfer tokens to recipient on destination chain and do an arbitrary call if requested\n address to = transaction.destRecipient;\n address token = transaction.destToken;\n uint256 amount = transaction.destAmount;\n uint256 callValue = transaction.callValue;\n\n // Emit the event before any external calls\n emit BridgeRelayed({\n transactionId: transactionId,\n relayer: relayer,\n to: to,\n originChainId: transaction.originChainId,\n originToken: transaction.originToken,\n destToken: token,\n originAmount: transaction.originAmount,\n destAmount: amount,\n chainGasAmount: callValue\n });\n\n // All state changes have been done at this point, can proceed to the external calls.\n // This follows the checks-effects-interactions pattern to mitigate potential reentrancy attacks.\n if (token == UniversalTokenLib.ETH_ADDRESS) {\n // For ETH non-zero callValue is not allowed\n if (callValue != 0) revert NativeTokenCallValueNotSupported();\n // Check that the correct msg.value was sent\n if (msg.value != amount) revert MsgValueIncorrect();\n } else {\n // For ERC20s, we check that the correct msg.value was sent\n if (msg.value != callValue) revert MsgValueIncorrect();\n // We need to transfer the tokens from the Relayer to the recipient first before performing an\n // optional post-transfer arbitrary call.\n IERC20(token).safeTransferFrom(msg.sender, to, amount);\n }\n\n if (transaction.callParams.length != 0) {\n // Arbitrary call requested, perform it while supplying full msg.value to the recipient\n // Note: if token has a fee on transfers, the recipient will have received less than `amount`.\n // This is a very niche edge case and should be handled by the recipient contract.\n _checkedCallRecipient({recipient: to, token: token, amount: amount, callParams: transaction.callParams});\n } else if (msg.value != 0) {\n // No arbitrary call requested, but msg.value was sent. This is either a relay with ETH,\n // or a non-zero callValue request with an ERC20. In both cases, transfer the ETH to the recipient.\n Address.sendValue(payable(to), msg.value);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) public onlyRole(RELAYER_ROLE) {\n // update bridge tx status given proof provided\n if (bridgeTxDetails[transactionId].status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n bridgeTxDetails[transactionId].status = BridgeStatus.RELAYER_PROVED;\n bridgeTxDetails[transactionId].proofBlockTimestamp = uint40(block.timestamp);\n bridgeTxDetails[transactionId].proofBlockNumber = uint48(block.number);\n bridgeTxDetails[transactionId].proofRelayer = relayer;\n\n emit BridgeProofProvided(transactionId, relayer, destTxHash);\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes memory request, address to) public {\n bytes32 transactionId = keccak256(request);\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n\n // update bridge tx status if able to claim origin collateral\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n\n // if \"to\" is zero addr, permissionlessly send funds to proven relayer\n if (to == address(0)) {\n to = bridgeTxDetails[transactionId].proofRelayer;\n } else if (bridgeTxDetails[transactionId].proofRelayer != msg.sender) {\n revert SenderIncorrect();\n }\n\n if (_timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003c= DISPUTE_PERIOD) {\n revert DisputePeriodNotPassed();\n }\n\n bridgeTxDetails[transactionId].status = BridgeStatus.RELAYER_CLAIMED;\n\n // update protocol fees if origin fee amount exists\n if (transaction.originFeeAmount \u003e 0) protocolFees[transaction.originToken] += transaction.originFeeAmount;\n\n // transfer origin collateral less fee to specified address\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositClaimed(transactionId, bridgeTxDetails[transactionId].proofRelayer, to, token, amount);\n }\n\n function bridgeStatuses(bytes32 transactionId) public view returns (BridgeStatus status) {\n return bridgeTxDetails[transactionId].status;\n }\n\n function bridgeProofs(bytes32 transactionId) public view returns (uint96 timestamp, address relayer) {\n timestamp = bridgeTxDetails[transactionId].proofBlockTimestamp;\n relayer = bridgeTxDetails[transactionId].proofRelayer;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeRelays(bytes32 transactionId) public view returns (bool) {\n // has this transactionId been relayed?\n return bridgeRelayDetails[transactionId].relayer != address(0);\n }\n\n /// @inheritdoc IFastBridgeV2\n function getBridgeTransactionV2(bytes memory request) public pure returns (BridgeTransactionV2 memory) {\n return abi.decode(request, (BridgeTransactionV2));\n }\n\n /// @notice Takes the bridged asset from the user into FastBridgeV2 custody. It will be later\n /// claimed by the relayer who completed the relay on destination chain, or refunded back to the user,\n /// should no one complete the relay.\n function _takeBridgedUserAsset(address token, uint256 amount) internal returns (uint256 amountTaken) {\n if (token == UniversalTokenLib.ETH_ADDRESS) {\n // For ETH we just need to check that the supplied msg.value is correct.\n // Supplied `msg.value` is already in FastBridgeV2 custody.\n if (amount != msg.value) revert MsgValueIncorrect();\n amountTaken = msg.value;\n } else {\n // For ERC20s, token is explicitly transferred from the user to FastBridgeV2.\n // We don't allow non-zero `msg.value` to avoid extra funds from being stuck in FastBridgeV2.\n token.assertIsContract();\n if (msg.value != 0) revert MsgValueIncorrect();\n amountTaken = IERC20(token).balanceOf(address(this));\n IERC20(token).safeTransferFrom(msg.sender, address(this), amount);\n // Use the balance difference as the amount taken in case of fee on transfer tokens.\n amountTaken = IERC20(token).balanceOf(address(this)) - amountTaken;\n }\n }\n\n /// @notice Calls the Recipient's hook function with the specified callParams and performs\n /// all the necessary checks for the returned value.\n function _checkedCallRecipient(\n address recipient,\n address token,\n uint256 amount,\n bytes memory callParams\n )\n internal\n {\n bytes memory hookData =\n abi.encodeCall(IFastBridgeRecipient.fastBridgeTransferReceived, (token, amount, callParams));\n // This will bubble any revert messages from the hook function\n bytes memory returnData = Address.functionCallWithValue({target: recipient, data: hookData, value: msg.value});\n // Explicit revert if no return data at all\n if (returnData.length == 0) revert RecipientNoReturnValue();\n // Check that exactly a single return value was returned\n if (returnData.length != 32) revert RecipientIncorrectReturnValue();\n // Return value should be abi-encoded hook function selector\n if (bytes32(returnData) != bytes32(IFastBridgeRecipient.fastBridgeTransferReceived.selector)) {\n revert RecipientIncorrectReturnValue();\n }\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint40(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint40).max but\n /// proof.timestamp \u003c type(uint40).max via unchecked statement\n /// @param proofBlockTimestamp The bridge proof block timestamp\n /// @return delta Time delta since proof submitted\n function _timeSince(uint40 proofBlockTimestamp) internal view returns (uint256 delta) {\n unchecked {\n delta = uint40(block.timestamp) - proofBlockTimestamp;\n }\n }\n\n /// @notice Performs all the necessary checks for a bridge to happen.\n /// @dev There's no good way to refactor this function to reduce cyclomatic complexity due to\n /// the number of checks that need to be performed, so we skip the code-complexity rule here.\n // solhint-disable-next-line code-complexity\n function _validateBridgeParams(\n BridgeParams memory params,\n BridgeParamsV2 memory paramsV2,\n int256 exclusivityEndTime\n )\n internal\n view\n {\n // Check V1 (legacy) params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.sender == address(0) || params.to == address(0)) revert ZeroAddress();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n // Check V2 params\n if (paramsV2.callParams.length \u003e MAX_CALL_PARAMS_LENGTH) revert CallParamsLengthAboveMax();\n if (paramsV2.callValue != 0 \u0026\u0026 params.destToken == UniversalTokenLib.ETH_ADDRESS) {\n revert NativeTokenCallValueNotSupported();\n }\n // exclusivityEndTime must be in range (0 .. params.deadline]\n if (exclusivityEndTime \u003c= 0 || exclusivityEndTime \u003e int256(params.deadline)) {\n revert ExclusivityParamsIncorrect();\n }\n }\n\n /// @notice Performs all the necessary checks for a relay to happen.\n function _validateRelayParams(\n BridgeTransactionV2 memory transaction,\n bytes32 transactionId,\n address relayer\n )\n internal\n view\n {\n if (relayer == address(0)) revert ZeroAddress();\n // Check if the transaction has already been relayed\n if (bridgeRelays(transactionId)) revert TransactionRelayed();\n if (transaction.destChainId != block.chainid) revert ChainIncorrect();\n // Check the deadline for relay to happen\n if (block.timestamp \u003e transaction.deadline) revert DeadlineExceeded();\n // Check the exclusivity period, if it is still ongoing\n // forgefmt: disable-next-item\n if (\n transaction.exclusivityRelayer != address(0) \u0026\u0026\n transaction.exclusivityRelayer != relayer \u0026\u0026\n block.timestamp \u003c= transaction.exclusivityEndTime\n ) {\n revert ExclusivityPeriodNotPassed();\n }\n }\n}\n","language":"Solidity","languageVersion":"0.8.24","compilerVersion":"0.8.24","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"62810:1843:0:-:0;;;63637:83;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;63675:38;52847:4;63706:6;63675:10;:38::i;:::-;;63637:83;62810:1843;;62160:257;62246:4;;62277:31;62294:4;62300:7;62277:16;:31::i;:::-;62262:46;;62322:7;62318:69;;;62345:18;;;;:12;:18;;;;;:31;;62368:7;62345:22;:31::i;:::-;;62318:69;62403:7;-1:-1:-1;62160:257:0;;;;;:::o;56794:316::-;56871:4;53569:12;;;;;;;;;;;-1:-1:-1;;;;;53569:29:0;;;;;;;;;;;;56887:217;;56930:6;:12;;;;;;;;;;;-1:-1:-1;;;;;56930:29:0;;;;;;;;;:36;;-1:-1:-1;;56930:36:0;56962:4;56930:36;;;57012:12;23368:10;;23289:96;57012:12;-1:-1:-1;;;;;56985:40:0;57003:7;-1:-1:-1;;;;;56985:40:0;56997:4;56985:40;;;;;;;;;;-1:-1:-1;57046:4:0;57039:11;;56887:217;-1:-1:-1;57088:5:0;57081:12;;32813:150;32883:4;32906:50;32911:3;-1:-1:-1;;;;;32931:23:0;;26801:4;28857:21;;;:14;;;:21;;;;;;26817:321;;-1:-1:-1;26859:23:0;;;;;;;;:11;:23;;;;;;;;;;;;;27041:18;;27017:21;;;:14;;;:21;;;;;;:42;;;;27073:11;;14:290:1;84:6;137:2;125:9;116:7;112:23;108:32;105:52;;;153:1;150;143:12;105:52;179:16;;-1:-1:-1;;;;;224:31:1;;214:42;;204:70;;270:1;267;260:12;14:290;62810:1843:0;;;;;;","srcMapRuntime":"62810:1843:0:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;60820:212;;;;;;:::i;:::-;;:::i;:::-;;;516:14:1;;509:22;491:41;;479:2;464:18;60820:212:0;;;;;;;;63050:60;;63087:23;63050:60;;;;;689:25:1;;;677:2;662:18;63050:60:0;543:177:1;64022:359:0;;;;;;:::i;:::-;;:::i;:::-;;63232:45;;63271:6;63232:45;;54425:120;;;;;;:::i;:::-;54490:7;54516:12;;;;;;;;;;:22;;;;54425:120;54841:136;;;;;;:::i;:::-;;:::i;55943:245::-;;;;;;:::i;:::-;;:::i;63394:30::-;;;;;;62978:66;;63018:26;62978:66;;61617:142;;;;;;:::i;:::-;;:::i;:::-;;;2246:42:1;2234:55;;;2216:74;;2204:2;2189:18;61617:142:0;2070:226:1;53469:136:0;;;;;;:::i;:::-;53546:4;53569:12;;;;;;;;;;;:29;;;;;;;;;;;;;;;;53469:136;62908:64;;62947:25;62908:64;;52802:49;;52847:4;52802:49;;63726:290;;;;;;:::i;:::-;;:::i;64387:264::-;;;;;;:::i;:::-;;:::i;63189:37::-;;63223:3;63189:37;;61927:131;;;;;;:::i;:::-;;:::i;63116:66::-;;63156:26;63116:66;;55257:138;;;;;;:::i;:::-;;:::i;63480:47::-;;;;;;:::i;:::-;;;;;;;;;;;;;;63601:29;;;;;;60820:212;60905:4;60928:57;;;60943:42;60928:57;;:97;;;60989:36;61013:11;60989:23;:36::i;:::-;60921:104;60820:212;-1:-1:-1;;60820:212:0:o;64022:359::-;63156:26;53079:16;53090:4;53079:10;:16::i;:::-;64146:19:::1;::::0;::::1;64126:17;64146:19:::0;;;:12:::1;:19;::::0;;;;;;64179:14;;;64175:27:::1;;64195:7;64022:359:::0;;;:::o;64175:27::-:1;64243:19;::::0;::::1;64265:1;64243:19:::0;;;:12:::1;:19;::::0;;;;:23;64276:45:::1;::::0;64300:9;64311;64276:23:::1;:45::i;:::-;64336:38;::::0;;2889:42:1;2958:15;;;2940:34;;3010:15;;3005:2;2990:18;;2983:43;3042:18;;;3035:34;;;64336:38:0::1;::::0;2867:2:1;2852:18;64336:38:0::1;;;;;;;64116:265;53105:1;64022:359:::0;;;:::o;54841:136::-;54490:7;54516:12;;;;;;;;;;:22;;;53079:16;53090:4;53079:10;:16::i;:::-;54945:25:::1;54956:4;54962:7;54945:10;:25::i;:::-;;54841:136:::0;;;:::o;55943:245::-;56036:34;;;23368:10;56036:34;56032:102;;56093:30;;;;;;;;;;;;;;56032:102;56144:37;56156:4;56162:18;56144:11;:37::i;61617:142::-;61698:7;61724:18;;;:12;:18;;;;;:28;;61746:5;61724:21;:28::i;:::-;61717:35;61617:142;-1:-1:-1;;;61617:142:0:o;63726:290::-;63156:26;53079:16;53090:4;53079:10;:16::i;:::-;63271:6:::1;63825:10;:26;;63817:55;;;::::0;::::1;::::0;;3282:2:1;63817:55:0::1;::::0;::::1;3264:21:1::0;3321:2;3301:18;;;3294:30;3360:18;3340;;;3333:46;3396:18;;63817:55:0::1;;;;;;;;;63903:15;::::0;;63928:28;;;;63971:38:::1;::::0;;3599:25:1;;;3655:2;3640:18;;3633:34;;;63971:38:0::1;::::0;3572:18:1;63971:38:0::1;;;;;;;;63807:209;63726:290:::0;;:::o;64387:264::-;63156:26;53079:16;53090:4;53079:10;:16::i;:::-;64512:14:::1;::::0;;64536:34;;;;64585:59:::1;::::0;;3599:25:1;;;3655:2;3640:18;;3633:34;;;64585:59:0::1;::::0;3572:18:1;64585:59:0::1;3425:248:1::0;61927:131:0;61998:7;62024:18;;;:12;:18;;;;;:27;;:25;:27::i;55257:138::-;54490:7;54516:12;;;;;;;;;;:22;;;53079:16;53090:4;53079:10;:16::i;:::-;55362:26:::1;55374:4;55380:7;55362:11;:26::i;53180:202::-:0;53265:4;53288:47;;;53303:32;53288:47;;:87;;-1:-1:-1;45095:25:0;45080:40;;;;53339:36;44981:146;53814:103;53880:30;53891:4;23368:10;53880;:30::i;:::-;53814:103;:::o;58092:653::-;58267:4;58253:19;;;;58249:32;;58092:653;;;:::o;58249:32::-;58353:5;58362:1;58353:10;58349:23;;58092:653;;;:::o;58349:23::-;58385:20;;;;;58381:358;;58565:12;58582:2;:7;;58597:5;58582:25;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;58564:43;;;58629:7;58621:39;;;;;;;4090:2:1;58621:39:0;;;4072:21:1;4129:2;4109:18;;;4102:30;4168:21;4148:18;;;4141:49;4207:18;;58621:39:0;3888:343:1;58381:358:0;58691:37;:26;;;58718:2;58722:5;58691:26;:37::i;62160:257::-;62246:4;62262:12;62277:31;62294:4;62300:7;62277:16;:31::i;:::-;62262:46;;62322:7;62318:69;;;62345:18;;;;:12;:18;;;;;:31;;62368:7;62345:22;:31::i;:::-;;62403:7;62160:257;-1:-1:-1;;;62160:257:0:o;62520:262::-;62607:4;62623:12;62638:32;62656:4;62662:7;62638:17;:32::i;:::-;62623:47;;62684:7;62680:72;;;62707:18;;;;:12;:18;;;;;:34;;62733:7;62707:25;:34::i;34071:156::-;34145:7;34195:22;34199:3;34211:5;34195:3;:22::i;33614:115::-;33677:7;33703:19;33711:3;29053:18;;28971:107;54047:197;53546:4;53569:12;;;;;;;;;;;:29;;;;;;;;;;;;;54130:108;;54180:47;;;;;4440:42:1;4428:55;;54180:47:0;;;4410:74:1;4500:18;;;4493:34;;;4383:18;;54180:47:0;4236:297:1;54130:108:0;54047:197;;:::o;46297:160::-;46406:43;;;46421:14;4428:55:1;;46406:43:0;;;4410:74:1;4500:18;;;;4493:34;;;46406:43:0;;;;;;;;;;4383:18:1;;;;46406:43:0;;;;;;;;;;;;;;46379:71;;46399:5;;46379:19;:71::i;56794:316::-;56871:4;53569:12;;;;;;;;;;;:29;;;;;;;;;;;;;56887:217;;56930:6;:12;;;;;;;;;;;:29;;;;;;;;;;:36;;;;56962:4;56930:36;;;57012:12;23368:10;;23289:96;57012:12;56985:40;;57003:7;56985:40;;56997:4;56985:40;;;;;;;;;;-1:-1:-1;57046:4:0;57039:11;;56887:217;-1:-1:-1;57088:5:0;57081:12;;32813:150;32883:4;32906:50;32911:3;32931:23;;;32906:4;:50::i;57345:317::-;57423:4;53569:12;;;;;;;;;;;:29;;;;;;;;;;;;;57439:217;;;57513:5;57481:12;;;;;;;;;;;:29;;;;;;;;;;;:37;;;;;;57537:40;23368:10;;57481:12;;57537:40;;57513:5;57537:40;-1:-1:-1;57598:4:0;57591:11;;33131:156;33204:4;33227:53;33235:3;33255:23;;;33227:7;:53::i;29420:118::-;29487:7;29513:3;:11;;29525:5;29513:18;;;;;;;;:::i;:::-;;;;;;;;;29506:25;;29420:118;;;;:::o;49053:629::-;49472:23;49498:33;:27;;;49526:4;49498:27;:33::i;:::-;49472:59;;49545:10;:17;49566:1;49545:22;;:57;;;;;49583:10;49572:30;;;;;;;;;;;;:::i;:::-;49571:31;49545:57;49541:135;;;49625:40;;;;;2246:42:1;2234:55;;49625:40:0;;;2216:74:1;2189:18;;49625:40:0;2070:226:1;26738:406:0;26801:4;28857:21;;;:14;;;:21;;;;;;26817:321;;-1:-1:-1;26859:23:0;;;;;;;;:11;:23;;;;;;;;;;;;;27041:18;;27017:21;;;:14;;;:21;;;;;;:42;;;;27073:11;;27312:1368;27378:4;27507:21;;;:14;;;:21;;;;;;27543:13;;27539:1135;;27910:18;27931:12;27942:1;27931:8;:12;:::i;:::-;27977:18;;27910:33;;-1:-1:-1;27957:17:0;;27977:22;;27998:1;;27977:22;:::i;:::-;27957:42;;28032:9;28018:10;:23;28014:378;;28061:17;28081:3;:11;;28093:9;28081:22;;;;;;;;:::i;:::-;;;;;;;;;28061:42;;28228:9;28202:3;:11;;28214:10;28202:23;;;;;;;;:::i;:::-;;;;;;;;;;;;:35;;;;28341:25;;;:14;;;:25;;;;;:36;;;28014:378;28470:17;;:3;;:17;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;28573:3;:14;;:21;28588:5;28573:21;;;;;;;;;;;28566:28;;;28616:4;28609:11;;;;;;;27539:1135;28658:5;28651:12;;;;;19074:151;19149:12;19180:38;19202:6;19210:4;19216:1;19149:12;19790;19804:23;19831:6;:11;;19850:5;19857:4;19831:31;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;19789:73;;;;19879:55;19906:6;19914:7;19923:10;19879:26;:55::i;:::-;19872:62;19549:392;-1:-1:-1;;;;;;19549:392:0:o;20994:582::-;21138:12;21167:7;21162:408;;21190:19;21198:10;21190:7;:19::i;:::-;21162:408;;;21414:17;;:22;:49;;;;-1:-1:-1;21440:18:0;;;;:23;21414:49;21410:119;;;21490:24;;;;;2246:42:1;2234:55;;21490:24:0;;;2216:74:1;2189:18;;21490:24:0;2070:226:1;21410:119:0;-1:-1:-1;21549:10:0;21542:17;;22112:516;22243:17;;:21;22239:383;;22471:10;22465:17;22527:15;22514:10;22510:2;22506:19;22499:44;22239:383;22594:17;;;;;;;;;;;;;;14:332:1;72:6;125:2;113:9;104:7;100:23;96:32;93:52;;;141:1;138;131:12;93:52;180:9;167:23;230:66;223:5;219:78;212:5;209:89;199:117;;312:1;309;302:12;725:196;793:20;;853:42;842:54;;832:65;;822:93;;911:1;908;901:12;822:93;725:196;;;:::o;926:260::-;994:6;1002;1055:2;1043:9;1034:7;1030:23;1026:32;1023:52;;;1071:1;1068;1061:12;1023:52;1094:29;1113:9;1094:29;:::i;:::-;1084:39;;1142:38;1176:2;1165:9;1161:18;1142:38;:::i;:::-;1132:48;;926:260;;;;;:::o;1373:180::-;1432:6;1485:2;1473:9;1464:7;1460:23;1456:32;1453:52;;;1501:1;1498;1491:12;1453:52;-1:-1:-1;1524:23:1;;1373:180;-1:-1:-1;1373:180:1:o;1558:254::-;1626:6;1634;1687:2;1675:9;1666:7;1662:23;1658:32;1655:52;;;1703:1;1700;1693:12;1655:52;1739:9;1726:23;1716:33;;1768:38;1802:2;1791:9;1787:18;1768:38;:::i;1817:248::-;1885:6;1893;1946:2;1934:9;1925:7;1921:23;1917:32;1914:52;;;1962:1;1959;1952:12;1914:52;-1:-1:-1;;1985:23:1;;;2055:2;2040:18;;;2027:32;;-1:-1:-1;1817:248:1:o;2486:186::-;2545:6;2598:2;2586:9;2577:7;2573:23;2569:32;2566:52;;;2614:1;2611;2604:12;2566:52;2637:29;2656:9;2637:29;:::i;4840:184::-;4892:77;4889:1;4882:88;4989:4;4986:1;4979:15;5013:4;5010:1;5003:15;5029:277;5096:6;5149:2;5137:9;5128:7;5124:23;5120:32;5117:52;;;5165:1;5162;5155:12;5117:52;5197:9;5191:16;5250:5;5243:13;5236:21;5229:5;5226:32;5216:60;;5272:1;5269;5262:12;5311:282;5378:9;;;5399:11;;;5396:191;;;5443:77;5440:1;5433:88;5544:4;5541:1;5534:15;5572:4;5569:1;5562:15;5598:184;5650:77;5647:1;5640:88;5747:4;5744:1;5737:15;5771:4;5768:1;5761:15;5787:412;5916:3;5954:6;5948:13;5979:1;5989:129;6003:6;6000:1;5997:13;5989:129;;;6101:4;6085:14;;;6081:25;;6075:32;6062:11;;;6055:53;6018:12;5989:129;;;-1:-1:-1;6173:1:1;6137:16;;6162:13;;;-1:-1:-1;6137:16:1;5787:412;-1:-1:-1;5787:412:1:o","abiDefinition":[{"inputs":[{"internalType":"address","name":"_owner","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AccessControlBadConfirmation","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"bytes32","name":"neededRole","type":"bytes32"}],"name":"AccessControlUnauthorizedAccount","type":"error"},{"inputs":[{"internalType":"address","name":"target","type":"address"}],"name":"AddressEmptyCode","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"AddressInsufficientBalance","type":"error"},{"inputs":[],"name":"FailedInnerCall","type":"error"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"SafeERC20FailedOperation","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldChainGasAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newChainGasAmount","type":"uint256"}],"name":"ChainGasAmountUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldFeeRate","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newFeeRate","type":"uint256"}],"name":"FeeRateUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"address","name":"recipient","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"FeesSwept","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"previousAdminRole","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"newAdminRole","type":"bytes32"}],"name":"RoleAdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleRevoked","type":"event"},{"inputs":[],"name":"DEFAULT_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"FEE_BPS","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"FEE_RATE_MAX","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"GOVERNOR_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"GUARD_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"REFUNDER_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"RELAYER_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"chainGasAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleAdmin","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"uint256","name":"index","type":"uint256"}],"name":"getRoleMember","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleMemberCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"grantRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"hasRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"protocolFeeRate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"protocolFees","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"callerConfirmation","type":"address"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"revokeRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"newChainGasAmount","type":"uint256"}],"name":"setChainGasAmount","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"newFeeRate","type":"uint256"}],"name":"setProtocolFeeRate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"address","name":"recipient","type":"address"}],"name":"sweepProtocolFees","outputs":[],"stateMutability":"nonpayable","type":"function"}],"userDoc":{"kind":"user","methods":{"chainGasAmount()":{"notice":"Chain gas amount to forward as rebate if requested"},"protocolFeeRate()":{"notice":"Protocol fee rate taken on origin amount deposited in origin chain"},"protocolFees(address)":{"notice":"Protocol fee amounts accumulated"}},"version":1},"developerDoc":{"errors":{"AccessControlBadConfirmation()":[{"details":"The caller of a function is not the expected one. NOTE: Don't confuse with {AccessControlUnauthorizedAccount}."}],"AccessControlUnauthorizedAccount(address,bytes32)":[{"details":"The `account` is missing a role."}],"AddressEmptyCode(address)":[{"details":"There's no code at `target` (it is not a contract)."}],"AddressInsufficientBalance(address)":[{"details":"The ETH balance of the account is not enough to perform the operation."}],"FailedInnerCall()":[{"details":"A call to an address target failed. The target may have reverted."}],"SafeERC20FailedOperation(address)":[{"details":"An operation with an ERC20 token failed."}]},"events":{"RoleAdminChanged(bytes32,bytes32,bytes32)":{"details":"Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole` `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite {RoleAdminChanged} not being emitted signaling this."},"RoleGranted(bytes32,address,address)":{"details":"Emitted when `account` is granted `role`. `sender` is the account that originated the contract call, an admin role bearer except when using {AccessControl-_setupRole}."},"RoleRevoked(bytes32,address,address)":{"details":"Emitted when `account` is revoked `role`. `sender` is the account that originated the contract call: - if using `revokeRole`, it is the admin role bearer - if using `renounceRole`, it is the role bearer (i.e. `account`)"}},"kind":"dev","methods":{"getRoleAdmin(bytes32)":{"details":"Returns the admin role that controls `role`. See {grantRole} and {revokeRole}. To change a role's admin, use {_setRoleAdmin}."},"getRoleMember(bytes32,uint256)":{"details":"Returns one of the accounts that have `role`. `index` must be a value between 0 and {getRoleMemberCount}, non-inclusive. Role bearers are not sorted in any particular way, and their ordering may change at any point. WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure you perform all queries on the same block. See the following https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post] for more information."},"getRoleMemberCount(bytes32)":{"details":"Returns the number of accounts that have `role`. Can be used together with {getRoleMember} to enumerate all bearers of a role."},"grantRole(bytes32,address)":{"details":"Grants `role` to `account`. If `account` had not been already granted `role`, emits a {RoleGranted} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleGranted} event."},"hasRole(bytes32,address)":{"details":"Returns `true` if `account` has been granted `role`."},"renounceRole(bytes32,address)":{"details":"Revokes `role` from the calling account. Roles are often managed via {grantRole} and {revokeRole}: this function's purpose is to provide a mechanism for accounts to lose their privileges if they are compromised (such as when a trusted device is misplaced). If the calling account had been revoked `role`, emits a {RoleRevoked} event. Requirements: - the caller must be `callerConfirmation`. May emit a {RoleRevoked} event."},"revokeRole(bytes32,address)":{"details":"Revokes `role` from `account`. If `account` had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleRevoked} event."},"supportsInterface(bytes4)":{"details":"See {IERC165-supportsInterface}."}},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_owner\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"AccessControlBadConfirmation\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"neededRole\",\"type\":\"bytes32\"}],\"name\":\"AccessControlUnauthorizedAccount\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"}],\"name\":\"AddressEmptyCode\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"AddressInsufficientBalance\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"FailedInnerCall\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"}],\"name\":\"SafeERC20FailedOperation\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"oldChainGasAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newChainGasAmount\",\"type\":\"uint256\"}],\"name\":\"ChainGasAmountUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"oldFeeRate\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newFeeRate\",\"type\":\"uint256\"}],\"name\":\"FeeRateUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"FeesSwept\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"previousAdminRole\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"newAdminRole\",\"type\":\"bytes32\"}],\"name\":\"RoleAdminChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleGranted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleRevoked\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"DEFAULT_ADMIN_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"FEE_BPS\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"FEE_RATE_MAX\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"GOVERNOR_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"GUARD_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"REFUNDER_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"RELAYER_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"chainGasAmount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"}],\"name\":\"getRoleAdmin\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"index\",\"type\":\"uint256\"}],\"name\":\"getRoleMember\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"}],\"name\":\"getRoleMemberCount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"grantRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"hasRole\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"protocolFeeRate\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"protocolFees\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"callerConfirmation\",\"type\":\"address\"}],\"name\":\"renounceRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"revokeRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"newChainGasAmount\",\"type\":\"uint256\"}],\"name\":\"setChainGasAmount\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"newFeeRate\",\"type\":\"uint256\"}],\"name\":\"setProtocolFeeRate\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes4\",\"name\":\"interfaceId\",\"type\":\"bytes4\"}],\"name\":\"supportsInterface\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"}],\"name\":\"sweepProtocolFees\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"errors\":{\"AccessControlBadConfirmation()\":[{\"details\":\"The caller of a function is not the expected one. NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\"}],\"AccessControlUnauthorizedAccount(address,bytes32)\":[{\"details\":\"The `account` is missing a role.\"}],\"AddressEmptyCode(address)\":[{\"details\":\"There's no code at `target` (it is not a contract).\"}],\"AddressInsufficientBalance(address)\":[{\"details\":\"The ETH balance of the account is not enough to perform the operation.\"}],\"FailedInnerCall()\":[{\"details\":\"A call to an address target failed. The target may have reverted.\"}],\"SafeERC20FailedOperation(address)\":[{\"details\":\"An operation with an ERC20 token failed.\"}]},\"events\":{\"RoleAdminChanged(bytes32,bytes32,bytes32)\":{\"details\":\"Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole` `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite {RoleAdminChanged} not being emitted signaling this.\"},\"RoleGranted(bytes32,address,address)\":{\"details\":\"Emitted when `account` is granted `role`. `sender` is the account that originated the contract call, an admin role bearer except when using {AccessControl-_setupRole}.\"},\"RoleRevoked(bytes32,address,address)\":{\"details\":\"Emitted when `account` is revoked `role`. `sender` is the account that originated the contract call: - if using `revokeRole`, it is the admin role bearer - if using `renounceRole`, it is the role bearer (i.e. `account`)\"}},\"kind\":\"dev\",\"methods\":{\"getRoleAdmin(bytes32)\":{\"details\":\"Returns the admin role that controls `role`. See {grantRole} and {revokeRole}. To change a role's admin, use {_setRoleAdmin}.\"},\"getRoleMember(bytes32,uint256)\":{\"details\":\"Returns one of the accounts that have `role`. `index` must be a value between 0 and {getRoleMemberCount}, non-inclusive. Role bearers are not sorted in any particular way, and their ordering may change at any point. WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure you perform all queries on the same block. See the following https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post] for more information.\"},\"getRoleMemberCount(bytes32)\":{\"details\":\"Returns the number of accounts that have `role`. Can be used together with {getRoleMember} to enumerate all bearers of a role.\"},\"grantRole(bytes32,address)\":{\"details\":\"Grants `role` to `account`. If `account` had not been already granted `role`, emits a {RoleGranted} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleGranted} event.\"},\"hasRole(bytes32,address)\":{\"details\":\"Returns `true` if `account` has been granted `role`.\"},\"renounceRole(bytes32,address)\":{\"details\":\"Revokes `role` from the calling account. Roles are often managed via {grantRole} and {revokeRole}: this function's purpose is to provide a mechanism for accounts to lose their privileges if they are compromised (such as when a trusted device is misplaced). If the calling account had been revoked `role`, emits a {RoleRevoked} event. Requirements: - the caller must be `callerConfirmation`. May emit a {RoleRevoked} event.\"},\"revokeRole(bytes32,address)\":{\"details\":\"Revokes `role` from `account`. If `account` had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleRevoked} event.\"},\"supportsInterface(bytes4)\":{\"details\":\"See {IERC165-supportsInterface}.\"}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"chainGasAmount()\":{\"notice\":\"Chain gas amount to forward as rebate if requested\"},\"protocolFeeRate()\":{\"notice\":\"Protocol fee rate taken on origin amount deposited in origin chain\"},\"protocolFees(address)\":{\"notice\":\"Protocol fee amounts accumulated\"}},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeV2.sol\":\"Admin\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeV2.sol\":{\"keccak256\":\"0xfd916c030b1ffca5a136817827b8018c8ba42ca089905747f3de6148b73eb35e\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://18e6438c4096deb8ae453fb3365ba2b07d52944e93c08288fc5d012b71bf6bb3\",\"dweb:/ipfs/QmfEMqpT1zz6RRm7UuHLRowe1tds2cTGLrVonfm9XSCACj\"]}},\"version\":1}"},"hashes":{"DEFAULT_ADMIN_ROLE()":"a217fddf","FEE_BPS()":"bf333f2c","FEE_RATE_MAX()":"0f5f6ed7","GOVERNOR_ROLE()":"ccc57490","GUARD_ROLE()":"03ed0ee5","REFUNDER_ROLE()":"5960ccf2","RELAYER_ROLE()":"926d7d7f","chainGasAmount()":"e00a83e0","getRoleAdmin(bytes32)":"248a9ca3","getRoleMember(bytes32,uint256)":"9010d07c","getRoleMemberCount(bytes32)":"ca15c873","grantRole(bytes32,address)":"2f2ff15d","hasRole(bytes32,address)":"91d14854","protocolFeeRate()":"58f85880","protocolFees(address)":"dcf844a7","renounceRole(bytes32,address)":"36568abe","revokeRole(bytes32,address)":"d547741f","setChainGasAmount(uint256)":"b250fe6b","setProtocolFeeRate(uint256)":"b13aa2d6","supportsInterface(bytes4)":"01ffc9a7","sweepProtocolFees(address,address)":"06f333f2"}},"solidity/FastBridgeV2.sol:Context":{"code":"0x","runtime-code":"0x","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.24 ^0.8.0 ^0.8.20;\n\n// contracts/interfaces/IAdmin.sol\n\ninterface IAdmin {\n // ============ Events ============\n\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n event ChainGasAmountUpdated(uint256 oldChainGasAmount, uint256 newChainGasAmount);\n\n // ============ Methods ============\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n\n function setChainGasAmount(uint256 newChainGasAmount) external;\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IFastBridgeRecipient.sol\n\ninterface IFastBridgeRecipient {\n function fastBridgeTransferReceived(\n address token,\n uint256 amount,\n bytes memory callParams\n )\n external\n payable\n returns (bytes4);\n}\n\n// contracts/interfaces/IFastBridgeV2Errors.sol\n\ninterface IFastBridgeV2Errors {\n error AmountIncorrect();\n error CallParamsLengthAboveMax();\n error ChainIncorrect();\n error ExclusivityParamsIncorrect();\n error MsgValueIncorrect();\n error NativeTokenCallValueNotSupported();\n error SenderIncorrect();\n error StatusIncorrect();\n error ZeroAddress();\n\n error RecipientIncorrectReturnValue();\n error RecipientNoReturnValue();\n\n error DeadlineExceeded();\n error DeadlineNotExceeded();\n error DeadlineTooShort();\n error DisputePeriodNotPassed();\n error DisputePeriodPassed();\n error ExclusivityPeriodNotPassed();\n\n error TransactionRelayed();\n}\n\n// contracts/libs/Errors.sol\n\nerror DeadlineExceeded();\nerror DeadlineNotExceeded();\nerror DeadlineTooShort();\nerror InsufficientOutputAmount();\n\nerror MsgValueIncorrect();\nerror PoolNotFound();\nerror TokenAddressMismatch();\nerror TokenNotContract();\nerror TokenNotETH();\nerror TokensIdentical();\n\nerror ChainIncorrect();\nerror AmountIncorrect();\nerror ZeroAddress();\n\nerror DisputePeriodNotPassed();\nerror DisputePeriodPassed();\nerror SenderIncorrect();\nerror StatusIncorrect();\nerror TransactionIdIncorrect();\nerror TransactionRelayed();\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// contracts/interfaces/IFastBridgeV2.sol\n\ninterface IFastBridgeV2 is IFastBridge {\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n struct BridgeTxDetails {\n BridgeStatus status;\n uint40 proofBlockTimestamp;\n uint48 proofBlockNumber;\n address proofRelayer;\n }\n\n struct BridgeRelay {\n uint48 blockNumber;\n uint48 blockTimestamp;\n address relayer;\n }\n\n /// @notice New params introduced in the FastBridgeV2.\n /// We are passing fields from the older BridgeParams struct outside of this struct\n /// for backwards compatibility.\n /// Note: quoteRelayer and quoteExclusivitySeconds are either both zero (indicating no exclusivity)\n /// or both non-zero (indicating exclusivity for the given period).\n /// Note: callValue \u003e 0 can NOT be used with destToken = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE (ETH_ADDRESS)\n /// @param quoteRelayer Relayer that provided the quote for the transaction\n /// @param quoteExclusivitySeconds Period of time the quote relayer is guaranteed exclusivity after user's deposit\n /// @param quoteId Unique quote identifier used for tracking the quote\n /// @param callValue ETH value to send to the recipient (if any)\n /// @param callParams Parameters for the arbitrary call to the destination recipient (if any)\n struct BridgeParamsV2 {\n address quoteRelayer;\n int256 quoteExclusivitySeconds;\n bytes quoteId;\n uint256 callValue;\n bytes callParams;\n }\n\n /// @notice Updated bridge transaction struct to include parameters introduced in FastBridgeV2.\n /// Note: only `exclusivityRelayer` can fill such a transaction until `exclusivityEndTime`.\n /// TODO: consider changing the encoding scheme to prevent spending extra gas on decoding.\n struct BridgeTransactionV2 {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n uint256 callValue; // ETH value to send to the recipient (if any) - replaces V1's sendChainGas flag\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n address exclusivityRelayer;\n uint256 exclusivityEndTime;\n bytes callParams;\n }\n\n event BridgeQuoteDetails(bytes32 indexed transactionId, bytes quoteId);\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability\n /// to provide temporary exclusivity fill rights for the quote relayer.\n /// @param params The parameters required to bridge\n /// @param paramsV2 The parameters for exclusivity fill rights (optional, can be left empty)\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function relay(bytes memory request, address relayer) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param transactionId The transaction id associated with the encoded bridge transaction to prove\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital.\n /// @notice Can only send funds to the relayer address on the proof.\n /// @param request The encoded bridge transaction to claim on origin chain\n function claim(bytes memory request) external;\n /// @notice Checks if a transaction has been relayed\n /// @param transactionId The ID of the transaction to check\n /// @return True if the transaction has been relayed, false otherwise\n function bridgeRelays(bytes32 transactionId) external view returns (bool);\n\n /// @notice Returns the status of a bridge transaction\n /// @param transactionId The ID of the bridge transaction\n /// @return BridgeStatus Status of the bridge transaction\n function bridgeStatuses(bytes32 transactionId) external view returns (BridgeStatus);\n\n /// @notice Returns the timestamp and relayer of a bridge proof\n /// @param transactionId The ID of the bridge transaction\n /// @return timestamp The timestamp of the bridge proof\n /// @return relayer The relayer address of the bridge proof\n function bridgeProofs(bytes32 transactionId) external view returns (uint96 timestamp, address relayer);\n\n /// @notice Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\n /// @param request The bridge request to decode\n function getBridgeTransactionV2(bytes memory request) external view returns (BridgeTransactionV2 memory);\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// contracts/libs/UniversalToken.sol\n\nlibrary UniversalTokenLib {\n using SafeERC20 for IERC20;\n\n address internal constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Transfers tokens to the given account. Reverts if transfer is not successful.\n /// @dev This might trigger fallback, if ETH is transferred to the contract.\n /// Make sure this can not lead to reentrancy attacks.\n function universalTransfer(address token, address to, uint256 value) internal {\n // Don't do anything, if need to send tokens to this address\n if (to == address(this)) return;\n // Don't do anything, if trying to send zero value\n if (value == 0) return;\n if (token == ETH_ADDRESS) {\n /// @dev Note: this can potentially lead to executing code in `to`.\n // solhint-disable-next-line avoid-low-level-calls\n (bool success,) = to.call{value: value}(\"\");\n require(success, \"ETH transfer failed\");\n } else {\n IERC20(token).safeTransfer(to, value);\n }\n }\n\n /// @notice Issues an infinite allowance to the spender, if the current allowance is insufficient\n /// to spend the given amount.\n function universalApproveInfinity(address token, address spender, uint256 amountToSpend) internal {\n // ETH Chad doesn't require your approval\n if (token == ETH_ADDRESS) return;\n // No-op if allowance is already sufficient\n uint256 allowance = IERC20(token).allowance(address(this), spender);\n if (allowance \u003e= amountToSpend) return;\n // Otherwise, reset approval to 0 and set to max allowance\n if (allowance \u003e 0) IERC20(token).safeDecreaseAllowance(spender, allowance);\n IERC20(token).safeIncreaseAllowance(spender, type(uint256).max);\n }\n\n /// @notice Returns the balance of the given token (or native ETH) for the given account.\n function universalBalanceOf(address token, address account) internal view returns (uint256) {\n if (token == ETH_ADDRESS) {\n return account.balance;\n } else {\n return IERC20(token).balanceOf(account);\n }\n }\n\n /// @dev Checks that token is a contract and not ETH_ADDRESS.\n function assertIsContract(address token) internal view {\n // Check that ETH_ADDRESS was not used (in case this is a predeploy on any of the chains)\n if (token == UniversalTokenLib.ETH_ADDRESS) revert TokenNotContract();\n // Check that token is not an EOA\n if (token.code.length == 0) revert TokenNotContract();\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/Admin.sol\n\ncontract Admin is IAdmin, AccessControlEnumerable {\n using UniversalTokenLib for address;\n\n bytes32 public constant RELAYER_ROLE = keccak256(\"RELAYER_ROLE\");\n bytes32 public constant REFUNDER_ROLE = keccak256(\"REFUNDER_ROLE\");\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n uint256 public constant FEE_BPS = 1e6;\n uint256 public constant FEE_RATE_MAX = 0.01e6; // max 1% on origin amount\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Chain gas amount to forward as rebate if requested\n uint256 public chainGasAmount;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n }\n\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n require(newFeeRate \u003c= FEE_RATE_MAX, \"newFeeRate \u003e max\");\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n token.universalTransfer(recipient, feeAmount);\n emit FeesSwept(token, recipient, feeAmount);\n }\n\n function setChainGasAmount(uint256 newChainGasAmount) external onlyRole(GOVERNOR_ROLE) {\n uint256 oldChainGasAmount = chainGasAmount;\n chainGasAmount = newChainGasAmount;\n emit ChainGasAmountUpdated(oldChainGasAmount, newChainGasAmount);\n }\n}\n\n// contracts/FastBridgeV2.sol\n\n/// @notice FastBridgeV2 is a contract for bridging tokens across chains.\ncontract FastBridgeV2 is Admin, IFastBridgeV2, IFastBridgeV2Errors {\n using SafeERC20 for IERC20;\n using UniversalTokenLib for address;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Delay for a transaction after which it could be permisionlessly refunded\n uint256 public constant REFUND_DELAY = 7 days;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n /// @notice Maximum length of accepted callParams\n uint256 public constant MAX_CALL_PARAMS_LENGTH = 2 ** 16 - 1;\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeTxDetails) public bridgeTxDetails;\n /// @notice Relay details on destination chain\n mapping(bytes32 =\u003e BridgeRelay) public bridgeRelayDetails;\n /// @notice Unique bridge nonces tracked per originSender\n mapping(address =\u003e uint256) public senderNonces;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Replaced by senderNonces\n uint256 public immutable nonce = 0;\n /// @notice the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n bridge({\n params: params,\n paramsV2: BridgeParamsV2({\n quoteRelayer: address(0),\n quoteExclusivitySeconds: 0,\n quoteId: bytes(\"\"),\n callValue: 0,\n callParams: bytes(\"\")\n })\n });\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes memory request) external payable {\n relay({request: request, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes memory request, bytes32 destTxHash) external {\n prove({transactionId: keccak256(request), destTxHash: destTxHash, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridgeV2\n function claim(bytes memory request) external {\n claim({request: request, to: address(0)});\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003e DISPUTE_PERIOD) {\n revert DisputePeriodPassed();\n }\n\n // @dev relayer gets slashed effectively if dest relay has gone thru\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n bridgeTxDetails[transactionId].proofRelayer = address(0);\n bridgeTxDetails[transactionId].proofBlockTimestamp = 0;\n bridgeTxDetails[transactionId].proofBlockNumber = 0;\n\n emit BridgeProofDisputed(transactionId, msg.sender);\n }\n\n /// @inheritdoc IFastBridge\n function refund(bytes memory request) external {\n bytes32 transactionId = keccak256(request);\n\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n\n if (bridgeTxDetails[transactionId].status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n\n if (hasRole(REFUNDER_ROLE, msg.sender)) {\n // Refunder can refund if deadline has passed\n if (block.timestamp \u003c= transaction.deadline) revert DeadlineNotExceeded();\n } else {\n // Permissionless refund is allowed after REFUND_DELAY\n if (block.timestamp \u003c= transaction.deadline + REFUND_DELAY) revert DeadlineNotExceeded();\n }\n\n // if all checks passed, set to REFUNDED status\n bridgeTxDetails[transactionId].status = BridgeStatus.REFUNDED;\n\n // transfer origin collateral back to original sender\n address to = transaction.originSender;\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount + transaction.originFeeAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (bridgeTxDetails[transactionId].proofRelayer != relayer) revert SenderIncorrect();\n return _timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n /// @dev This method is added to achieve backwards compatibility with decoding requests into V1 structs:\n /// - `callValue` is partially reported as a zero/non-zero flag\n /// - `callParams` is ignored\n /// In order to process all kinds of requests use getBridgeTransactionV2 instead.\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory) {\n // Try decoding into V2 struct first. This will revert if V1 struct is passed\n try this.getBridgeTransactionV2(request) returns (BridgeTransactionV2 memory txV2) {\n // Note: we entirely ignore the callParams field, as it was not present in V1\n return BridgeTransaction({\n originChainId: txV2.originChainId,\n destChainId: txV2.destChainId,\n originSender: txV2.originSender,\n destRecipient: txV2.destRecipient,\n originToken: txV2.originToken,\n destToken: txV2.destToken,\n originAmount: txV2.originAmount,\n destAmount: txV2.destAmount,\n originFeeAmount: txV2.originFeeAmount,\n sendChainGas: txV2.callValue != 0,\n deadline: txV2.deadline,\n nonce: txV2.nonce\n });\n } catch {\n // Fallback to V1 struct\n return abi.decode(request, (BridgeTransaction));\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) public payable {\n int256 exclusivityEndTime = int256(block.timestamp) + paramsV2.quoteExclusivitySeconds;\n _validateBridgeParams(params, paramsV2, exclusivityEndTime);\n\n // transfer tokens to bridge contract\n /// @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _takeBridgedUserAsset(params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n\n // set status to requested\n bytes memory request = abi.encode(\n BridgeTransactionV2({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n callValue: paramsV2.callValue,\n deadline: params.deadline,\n nonce: senderNonces[params.sender]++, // increment nonce on every bridge\n exclusivityRelayer: paramsV2.quoteRelayer,\n // We checked exclusivityEndTime to be in range (0 .. params.deadline] above, so can safely cast\n exclusivityEndTime: uint256(exclusivityEndTime),\n callParams: paramsV2.callParams\n })\n );\n bytes32 transactionId = keccak256(request);\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n\n emit BridgeRequested({\n transactionId: transactionId,\n sender: params.sender,\n request: request,\n destChainId: params.dstChainId,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n sendChainGas: paramsV2.callValue != 0\n });\n emit BridgeQuoteDetails(transactionId, paramsV2.quoteId);\n }\n\n /// @inheritdoc IFastBridgeV2\n function relay(bytes memory request, address relayer) public payable {\n bytes32 transactionId = keccak256(request);\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n _validateRelayParams(transaction, transactionId, relayer);\n // mark bridge transaction as relayed\n bridgeRelayDetails[transactionId] =\n BridgeRelay({blockNumber: uint48(block.number), blockTimestamp: uint48(block.timestamp), relayer: relayer});\n\n // transfer tokens to recipient on destination chain and do an arbitrary call if requested\n address to = transaction.destRecipient;\n address token = transaction.destToken;\n uint256 amount = transaction.destAmount;\n uint256 callValue = transaction.callValue;\n\n // Emit the event before any external calls\n emit BridgeRelayed({\n transactionId: transactionId,\n relayer: relayer,\n to: to,\n originChainId: transaction.originChainId,\n originToken: transaction.originToken,\n destToken: token,\n originAmount: transaction.originAmount,\n destAmount: amount,\n chainGasAmount: callValue\n });\n\n // All state changes have been done at this point, can proceed to the external calls.\n // This follows the checks-effects-interactions pattern to mitigate potential reentrancy attacks.\n if (token == UniversalTokenLib.ETH_ADDRESS) {\n // For ETH non-zero callValue is not allowed\n if (callValue != 0) revert NativeTokenCallValueNotSupported();\n // Check that the correct msg.value was sent\n if (msg.value != amount) revert MsgValueIncorrect();\n } else {\n // For ERC20s, we check that the correct msg.value was sent\n if (msg.value != callValue) revert MsgValueIncorrect();\n // We need to transfer the tokens from the Relayer to the recipient first before performing an\n // optional post-transfer arbitrary call.\n IERC20(token).safeTransferFrom(msg.sender, to, amount);\n }\n\n if (transaction.callParams.length != 0) {\n // Arbitrary call requested, perform it while supplying full msg.value to the recipient\n // Note: if token has a fee on transfers, the recipient will have received less than `amount`.\n // This is a very niche edge case and should be handled by the recipient contract.\n _checkedCallRecipient({recipient: to, token: token, amount: amount, callParams: transaction.callParams});\n } else if (msg.value != 0) {\n // No arbitrary call requested, but msg.value was sent. This is either a relay with ETH,\n // or a non-zero callValue request with an ERC20. In both cases, transfer the ETH to the recipient.\n Address.sendValue(payable(to), msg.value);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) public onlyRole(RELAYER_ROLE) {\n // update bridge tx status given proof provided\n if (bridgeTxDetails[transactionId].status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n bridgeTxDetails[transactionId].status = BridgeStatus.RELAYER_PROVED;\n bridgeTxDetails[transactionId].proofBlockTimestamp = uint40(block.timestamp);\n bridgeTxDetails[transactionId].proofBlockNumber = uint48(block.number);\n bridgeTxDetails[transactionId].proofRelayer = relayer;\n\n emit BridgeProofProvided(transactionId, relayer, destTxHash);\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes memory request, address to) public {\n bytes32 transactionId = keccak256(request);\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n\n // update bridge tx status if able to claim origin collateral\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n\n // if \"to\" is zero addr, permissionlessly send funds to proven relayer\n if (to == address(0)) {\n to = bridgeTxDetails[transactionId].proofRelayer;\n } else if (bridgeTxDetails[transactionId].proofRelayer != msg.sender) {\n revert SenderIncorrect();\n }\n\n if (_timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003c= DISPUTE_PERIOD) {\n revert DisputePeriodNotPassed();\n }\n\n bridgeTxDetails[transactionId].status = BridgeStatus.RELAYER_CLAIMED;\n\n // update protocol fees if origin fee amount exists\n if (transaction.originFeeAmount \u003e 0) protocolFees[transaction.originToken] += transaction.originFeeAmount;\n\n // transfer origin collateral less fee to specified address\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositClaimed(transactionId, bridgeTxDetails[transactionId].proofRelayer, to, token, amount);\n }\n\n function bridgeStatuses(bytes32 transactionId) public view returns (BridgeStatus status) {\n return bridgeTxDetails[transactionId].status;\n }\n\n function bridgeProofs(bytes32 transactionId) public view returns (uint96 timestamp, address relayer) {\n timestamp = bridgeTxDetails[transactionId].proofBlockTimestamp;\n relayer = bridgeTxDetails[transactionId].proofRelayer;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeRelays(bytes32 transactionId) public view returns (bool) {\n // has this transactionId been relayed?\n return bridgeRelayDetails[transactionId].relayer != address(0);\n }\n\n /// @inheritdoc IFastBridgeV2\n function getBridgeTransactionV2(bytes memory request) public pure returns (BridgeTransactionV2 memory) {\n return abi.decode(request, (BridgeTransactionV2));\n }\n\n /// @notice Takes the bridged asset from the user into FastBridgeV2 custody. It will be later\n /// claimed by the relayer who completed the relay on destination chain, or refunded back to the user,\n /// should no one complete the relay.\n function _takeBridgedUserAsset(address token, uint256 amount) internal returns (uint256 amountTaken) {\n if (token == UniversalTokenLib.ETH_ADDRESS) {\n // For ETH we just need to check that the supplied msg.value is correct.\n // Supplied `msg.value` is already in FastBridgeV2 custody.\n if (amount != msg.value) revert MsgValueIncorrect();\n amountTaken = msg.value;\n } else {\n // For ERC20s, token is explicitly transferred from the user to FastBridgeV2.\n // We don't allow non-zero `msg.value` to avoid extra funds from being stuck in FastBridgeV2.\n token.assertIsContract();\n if (msg.value != 0) revert MsgValueIncorrect();\n amountTaken = IERC20(token).balanceOf(address(this));\n IERC20(token).safeTransferFrom(msg.sender, address(this), amount);\n // Use the balance difference as the amount taken in case of fee on transfer tokens.\n amountTaken = IERC20(token).balanceOf(address(this)) - amountTaken;\n }\n }\n\n /// @notice Calls the Recipient's hook function with the specified callParams and performs\n /// all the necessary checks for the returned value.\n function _checkedCallRecipient(\n address recipient,\n address token,\n uint256 amount,\n bytes memory callParams\n )\n internal\n {\n bytes memory hookData =\n abi.encodeCall(IFastBridgeRecipient.fastBridgeTransferReceived, (token, amount, callParams));\n // This will bubble any revert messages from the hook function\n bytes memory returnData = Address.functionCallWithValue({target: recipient, data: hookData, value: msg.value});\n // Explicit revert if no return data at all\n if (returnData.length == 0) revert RecipientNoReturnValue();\n // Check that exactly a single return value was returned\n if (returnData.length != 32) revert RecipientIncorrectReturnValue();\n // Return value should be abi-encoded hook function selector\n if (bytes32(returnData) != bytes32(IFastBridgeRecipient.fastBridgeTransferReceived.selector)) {\n revert RecipientIncorrectReturnValue();\n }\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint40(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint40).max but\n /// proof.timestamp \u003c type(uint40).max via unchecked statement\n /// @param proofBlockTimestamp The bridge proof block timestamp\n /// @return delta Time delta since proof submitted\n function _timeSince(uint40 proofBlockTimestamp) internal view returns (uint256 delta) {\n unchecked {\n delta = uint40(block.timestamp) - proofBlockTimestamp;\n }\n }\n\n /// @notice Performs all the necessary checks for a bridge to happen.\n /// @dev There's no good way to refactor this function to reduce cyclomatic complexity due to\n /// the number of checks that need to be performed, so we skip the code-complexity rule here.\n // solhint-disable-next-line code-complexity\n function _validateBridgeParams(\n BridgeParams memory params,\n BridgeParamsV2 memory paramsV2,\n int256 exclusivityEndTime\n )\n internal\n view\n {\n // Check V1 (legacy) params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.sender == address(0) || params.to == address(0)) revert ZeroAddress();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n // Check V2 params\n if (paramsV2.callParams.length \u003e MAX_CALL_PARAMS_LENGTH) revert CallParamsLengthAboveMax();\n if (paramsV2.callValue != 0 \u0026\u0026 params.destToken == UniversalTokenLib.ETH_ADDRESS) {\n revert NativeTokenCallValueNotSupported();\n }\n // exclusivityEndTime must be in range (0 .. params.deadline]\n if (exclusivityEndTime \u003c= 0 || exclusivityEndTime \u003e int256(params.deadline)) {\n revert ExclusivityParamsIncorrect();\n }\n }\n\n /// @notice Performs all the necessary checks for a relay to happen.\n function _validateRelayParams(\n BridgeTransactionV2 memory transaction,\n bytes32 transactionId,\n address relayer\n )\n internal\n view\n {\n if (relayer == address(0)) revert ZeroAddress();\n // Check if the transaction has already been relayed\n if (bridgeRelays(transactionId)) revert TransactionRelayed();\n if (transaction.destChainId != block.chainid) revert ChainIncorrect();\n // Check the deadline for relay to happen\n if (block.timestamp \u003e transaction.deadline) revert DeadlineExceeded();\n // Check the exclusivity period, if it is still ongoing\n // forgefmt: disable-next-item\n if (\n transaction.exclusivityRelayer != address(0) \u0026\u0026\n transaction.exclusivityRelayer != relayer \u0026\u0026\n block.timestamp \u003c= transaction.exclusivityEndTime\n ) {\n revert ExclusivityPeriodNotPassed();\n }\n }\n}\n","language":"Solidity","languageVersion":"0.8.24","compilerVersion":"0.8.24","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"","srcMapRuntime":"","abiDefinition":[],"userDoc":{"kind":"user","methods":{},"version":1},"developerDoc":{"details":"Provides information about the current execution context, including the sender of the transaction and its data. While these are generally available via msg.sender and msg.data, they should not be accessed in such a direct manner, since when dealing with meta-transactions the account sending and paying for execution may not be the actual sender (as far as an application is concerned). This contract is only required for intermediate, library-like contracts.","kind":"dev","methods":{},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[],\"devdoc\":{\"details\":\"Provides information about the current execution context, including the sender of the transaction and its data. While these are generally available via msg.sender and msg.data, they should not be accessed in such a direct manner, since when dealing with meta-transactions the account sending and paying for execution may not be the actual sender (as far as an application is concerned). This contract is only required for intermediate, library-like contracts.\",\"kind\":\"dev\",\"methods\":{},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeV2.sol\":\"Context\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeV2.sol\":{\"keccak256\":\"0xfd916c030b1ffca5a136817827b8018c8ba42ca089905747f3de6148b73eb35e\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://18e6438c4096deb8ae453fb3365ba2b07d52944e93c08288fc5d012b71bf6bb3\",\"dweb:/ipfs/QmfEMqpT1zz6RRm7UuHLRowe1tds2cTGLrVonfm9XSCACj\"]}},\"version\":1}"},"hashes":{}},"solidity/FastBridgeV2.sol:ERC165":{"code":"0x","runtime-code":"0x","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.24 ^0.8.0 ^0.8.20;\n\n// contracts/interfaces/IAdmin.sol\n\ninterface IAdmin {\n // ============ Events ============\n\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n event ChainGasAmountUpdated(uint256 oldChainGasAmount, uint256 newChainGasAmount);\n\n // ============ Methods ============\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n\n function setChainGasAmount(uint256 newChainGasAmount) external;\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IFastBridgeRecipient.sol\n\ninterface IFastBridgeRecipient {\n function fastBridgeTransferReceived(\n address token,\n uint256 amount,\n bytes memory callParams\n )\n external\n payable\n returns (bytes4);\n}\n\n// contracts/interfaces/IFastBridgeV2Errors.sol\n\ninterface IFastBridgeV2Errors {\n error AmountIncorrect();\n error CallParamsLengthAboveMax();\n error ChainIncorrect();\n error ExclusivityParamsIncorrect();\n error MsgValueIncorrect();\n error NativeTokenCallValueNotSupported();\n error SenderIncorrect();\n error StatusIncorrect();\n error ZeroAddress();\n\n error RecipientIncorrectReturnValue();\n error RecipientNoReturnValue();\n\n error DeadlineExceeded();\n error DeadlineNotExceeded();\n error DeadlineTooShort();\n error DisputePeriodNotPassed();\n error DisputePeriodPassed();\n error ExclusivityPeriodNotPassed();\n\n error TransactionRelayed();\n}\n\n// contracts/libs/Errors.sol\n\nerror DeadlineExceeded();\nerror DeadlineNotExceeded();\nerror DeadlineTooShort();\nerror InsufficientOutputAmount();\n\nerror MsgValueIncorrect();\nerror PoolNotFound();\nerror TokenAddressMismatch();\nerror TokenNotContract();\nerror TokenNotETH();\nerror TokensIdentical();\n\nerror ChainIncorrect();\nerror AmountIncorrect();\nerror ZeroAddress();\n\nerror DisputePeriodNotPassed();\nerror DisputePeriodPassed();\nerror SenderIncorrect();\nerror StatusIncorrect();\nerror TransactionIdIncorrect();\nerror TransactionRelayed();\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// contracts/interfaces/IFastBridgeV2.sol\n\ninterface IFastBridgeV2 is IFastBridge {\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n struct BridgeTxDetails {\n BridgeStatus status;\n uint40 proofBlockTimestamp;\n uint48 proofBlockNumber;\n address proofRelayer;\n }\n\n struct BridgeRelay {\n uint48 blockNumber;\n uint48 blockTimestamp;\n address relayer;\n }\n\n /// @notice New params introduced in the FastBridgeV2.\n /// We are passing fields from the older BridgeParams struct outside of this struct\n /// for backwards compatibility.\n /// Note: quoteRelayer and quoteExclusivitySeconds are either both zero (indicating no exclusivity)\n /// or both non-zero (indicating exclusivity for the given period).\n /// Note: callValue \u003e 0 can NOT be used with destToken = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE (ETH_ADDRESS)\n /// @param quoteRelayer Relayer that provided the quote for the transaction\n /// @param quoteExclusivitySeconds Period of time the quote relayer is guaranteed exclusivity after user's deposit\n /// @param quoteId Unique quote identifier used for tracking the quote\n /// @param callValue ETH value to send to the recipient (if any)\n /// @param callParams Parameters for the arbitrary call to the destination recipient (if any)\n struct BridgeParamsV2 {\n address quoteRelayer;\n int256 quoteExclusivitySeconds;\n bytes quoteId;\n uint256 callValue;\n bytes callParams;\n }\n\n /// @notice Updated bridge transaction struct to include parameters introduced in FastBridgeV2.\n /// Note: only `exclusivityRelayer` can fill such a transaction until `exclusivityEndTime`.\n /// TODO: consider changing the encoding scheme to prevent spending extra gas on decoding.\n struct BridgeTransactionV2 {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n uint256 callValue; // ETH value to send to the recipient (if any) - replaces V1's sendChainGas flag\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n address exclusivityRelayer;\n uint256 exclusivityEndTime;\n bytes callParams;\n }\n\n event BridgeQuoteDetails(bytes32 indexed transactionId, bytes quoteId);\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability\n /// to provide temporary exclusivity fill rights for the quote relayer.\n /// @param params The parameters required to bridge\n /// @param paramsV2 The parameters for exclusivity fill rights (optional, can be left empty)\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function relay(bytes memory request, address relayer) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param transactionId The transaction id associated with the encoded bridge transaction to prove\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital.\n /// @notice Can only send funds to the relayer address on the proof.\n /// @param request The encoded bridge transaction to claim on origin chain\n function claim(bytes memory request) external;\n /// @notice Checks if a transaction has been relayed\n /// @param transactionId The ID of the transaction to check\n /// @return True if the transaction has been relayed, false otherwise\n function bridgeRelays(bytes32 transactionId) external view returns (bool);\n\n /// @notice Returns the status of a bridge transaction\n /// @param transactionId The ID of the bridge transaction\n /// @return BridgeStatus Status of the bridge transaction\n function bridgeStatuses(bytes32 transactionId) external view returns (BridgeStatus);\n\n /// @notice Returns the timestamp and relayer of a bridge proof\n /// @param transactionId The ID of the bridge transaction\n /// @return timestamp The timestamp of the bridge proof\n /// @return relayer The relayer address of the bridge proof\n function bridgeProofs(bytes32 transactionId) external view returns (uint96 timestamp, address relayer);\n\n /// @notice Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\n /// @param request The bridge request to decode\n function getBridgeTransactionV2(bytes memory request) external view returns (BridgeTransactionV2 memory);\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// contracts/libs/UniversalToken.sol\n\nlibrary UniversalTokenLib {\n using SafeERC20 for IERC20;\n\n address internal constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Transfers tokens to the given account. Reverts if transfer is not successful.\n /// @dev This might trigger fallback, if ETH is transferred to the contract.\n /// Make sure this can not lead to reentrancy attacks.\n function universalTransfer(address token, address to, uint256 value) internal {\n // Don't do anything, if need to send tokens to this address\n if (to == address(this)) return;\n // Don't do anything, if trying to send zero value\n if (value == 0) return;\n if (token == ETH_ADDRESS) {\n /// @dev Note: this can potentially lead to executing code in `to`.\n // solhint-disable-next-line avoid-low-level-calls\n (bool success,) = to.call{value: value}(\"\");\n require(success, \"ETH transfer failed\");\n } else {\n IERC20(token).safeTransfer(to, value);\n }\n }\n\n /// @notice Issues an infinite allowance to the spender, if the current allowance is insufficient\n /// to spend the given amount.\n function universalApproveInfinity(address token, address spender, uint256 amountToSpend) internal {\n // ETH Chad doesn't require your approval\n if (token == ETH_ADDRESS) return;\n // No-op if allowance is already sufficient\n uint256 allowance = IERC20(token).allowance(address(this), spender);\n if (allowance \u003e= amountToSpend) return;\n // Otherwise, reset approval to 0 and set to max allowance\n if (allowance \u003e 0) IERC20(token).safeDecreaseAllowance(spender, allowance);\n IERC20(token).safeIncreaseAllowance(spender, type(uint256).max);\n }\n\n /// @notice Returns the balance of the given token (or native ETH) for the given account.\n function universalBalanceOf(address token, address account) internal view returns (uint256) {\n if (token == ETH_ADDRESS) {\n return account.balance;\n } else {\n return IERC20(token).balanceOf(account);\n }\n }\n\n /// @dev Checks that token is a contract and not ETH_ADDRESS.\n function assertIsContract(address token) internal view {\n // Check that ETH_ADDRESS was not used (in case this is a predeploy on any of the chains)\n if (token == UniversalTokenLib.ETH_ADDRESS) revert TokenNotContract();\n // Check that token is not an EOA\n if (token.code.length == 0) revert TokenNotContract();\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/Admin.sol\n\ncontract Admin is IAdmin, AccessControlEnumerable {\n using UniversalTokenLib for address;\n\n bytes32 public constant RELAYER_ROLE = keccak256(\"RELAYER_ROLE\");\n bytes32 public constant REFUNDER_ROLE = keccak256(\"REFUNDER_ROLE\");\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n uint256 public constant FEE_BPS = 1e6;\n uint256 public constant FEE_RATE_MAX = 0.01e6; // max 1% on origin amount\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Chain gas amount to forward as rebate if requested\n uint256 public chainGasAmount;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n }\n\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n require(newFeeRate \u003c= FEE_RATE_MAX, \"newFeeRate \u003e max\");\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n token.universalTransfer(recipient, feeAmount);\n emit FeesSwept(token, recipient, feeAmount);\n }\n\n function setChainGasAmount(uint256 newChainGasAmount) external onlyRole(GOVERNOR_ROLE) {\n uint256 oldChainGasAmount = chainGasAmount;\n chainGasAmount = newChainGasAmount;\n emit ChainGasAmountUpdated(oldChainGasAmount, newChainGasAmount);\n }\n}\n\n// contracts/FastBridgeV2.sol\n\n/// @notice FastBridgeV2 is a contract for bridging tokens across chains.\ncontract FastBridgeV2 is Admin, IFastBridgeV2, IFastBridgeV2Errors {\n using SafeERC20 for IERC20;\n using UniversalTokenLib for address;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Delay for a transaction after which it could be permisionlessly refunded\n uint256 public constant REFUND_DELAY = 7 days;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n /// @notice Maximum length of accepted callParams\n uint256 public constant MAX_CALL_PARAMS_LENGTH = 2 ** 16 - 1;\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeTxDetails) public bridgeTxDetails;\n /// @notice Relay details on destination chain\n mapping(bytes32 =\u003e BridgeRelay) public bridgeRelayDetails;\n /// @notice Unique bridge nonces tracked per originSender\n mapping(address =\u003e uint256) public senderNonces;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Replaced by senderNonces\n uint256 public immutable nonce = 0;\n /// @notice the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n bridge({\n params: params,\n paramsV2: BridgeParamsV2({\n quoteRelayer: address(0),\n quoteExclusivitySeconds: 0,\n quoteId: bytes(\"\"),\n callValue: 0,\n callParams: bytes(\"\")\n })\n });\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes memory request) external payable {\n relay({request: request, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes memory request, bytes32 destTxHash) external {\n prove({transactionId: keccak256(request), destTxHash: destTxHash, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridgeV2\n function claim(bytes memory request) external {\n claim({request: request, to: address(0)});\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003e DISPUTE_PERIOD) {\n revert DisputePeriodPassed();\n }\n\n // @dev relayer gets slashed effectively if dest relay has gone thru\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n bridgeTxDetails[transactionId].proofRelayer = address(0);\n bridgeTxDetails[transactionId].proofBlockTimestamp = 0;\n bridgeTxDetails[transactionId].proofBlockNumber = 0;\n\n emit BridgeProofDisputed(transactionId, msg.sender);\n }\n\n /// @inheritdoc IFastBridge\n function refund(bytes memory request) external {\n bytes32 transactionId = keccak256(request);\n\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n\n if (bridgeTxDetails[transactionId].status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n\n if (hasRole(REFUNDER_ROLE, msg.sender)) {\n // Refunder can refund if deadline has passed\n if (block.timestamp \u003c= transaction.deadline) revert DeadlineNotExceeded();\n } else {\n // Permissionless refund is allowed after REFUND_DELAY\n if (block.timestamp \u003c= transaction.deadline + REFUND_DELAY) revert DeadlineNotExceeded();\n }\n\n // if all checks passed, set to REFUNDED status\n bridgeTxDetails[transactionId].status = BridgeStatus.REFUNDED;\n\n // transfer origin collateral back to original sender\n address to = transaction.originSender;\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount + transaction.originFeeAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (bridgeTxDetails[transactionId].proofRelayer != relayer) revert SenderIncorrect();\n return _timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n /// @dev This method is added to achieve backwards compatibility with decoding requests into V1 structs:\n /// - `callValue` is partially reported as a zero/non-zero flag\n /// - `callParams` is ignored\n /// In order to process all kinds of requests use getBridgeTransactionV2 instead.\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory) {\n // Try decoding into V2 struct first. This will revert if V1 struct is passed\n try this.getBridgeTransactionV2(request) returns (BridgeTransactionV2 memory txV2) {\n // Note: we entirely ignore the callParams field, as it was not present in V1\n return BridgeTransaction({\n originChainId: txV2.originChainId,\n destChainId: txV2.destChainId,\n originSender: txV2.originSender,\n destRecipient: txV2.destRecipient,\n originToken: txV2.originToken,\n destToken: txV2.destToken,\n originAmount: txV2.originAmount,\n destAmount: txV2.destAmount,\n originFeeAmount: txV2.originFeeAmount,\n sendChainGas: txV2.callValue != 0,\n deadline: txV2.deadline,\n nonce: txV2.nonce\n });\n } catch {\n // Fallback to V1 struct\n return abi.decode(request, (BridgeTransaction));\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) public payable {\n int256 exclusivityEndTime = int256(block.timestamp) + paramsV2.quoteExclusivitySeconds;\n _validateBridgeParams(params, paramsV2, exclusivityEndTime);\n\n // transfer tokens to bridge contract\n /// @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _takeBridgedUserAsset(params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n\n // set status to requested\n bytes memory request = abi.encode(\n BridgeTransactionV2({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n callValue: paramsV2.callValue,\n deadline: params.deadline,\n nonce: senderNonces[params.sender]++, // increment nonce on every bridge\n exclusivityRelayer: paramsV2.quoteRelayer,\n // We checked exclusivityEndTime to be in range (0 .. params.deadline] above, so can safely cast\n exclusivityEndTime: uint256(exclusivityEndTime),\n callParams: paramsV2.callParams\n })\n );\n bytes32 transactionId = keccak256(request);\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n\n emit BridgeRequested({\n transactionId: transactionId,\n sender: params.sender,\n request: request,\n destChainId: params.dstChainId,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n sendChainGas: paramsV2.callValue != 0\n });\n emit BridgeQuoteDetails(transactionId, paramsV2.quoteId);\n }\n\n /// @inheritdoc IFastBridgeV2\n function relay(bytes memory request, address relayer) public payable {\n bytes32 transactionId = keccak256(request);\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n _validateRelayParams(transaction, transactionId, relayer);\n // mark bridge transaction as relayed\n bridgeRelayDetails[transactionId] =\n BridgeRelay({blockNumber: uint48(block.number), blockTimestamp: uint48(block.timestamp), relayer: relayer});\n\n // transfer tokens to recipient on destination chain and do an arbitrary call if requested\n address to = transaction.destRecipient;\n address token = transaction.destToken;\n uint256 amount = transaction.destAmount;\n uint256 callValue = transaction.callValue;\n\n // Emit the event before any external calls\n emit BridgeRelayed({\n transactionId: transactionId,\n relayer: relayer,\n to: to,\n originChainId: transaction.originChainId,\n originToken: transaction.originToken,\n destToken: token,\n originAmount: transaction.originAmount,\n destAmount: amount,\n chainGasAmount: callValue\n });\n\n // All state changes have been done at this point, can proceed to the external calls.\n // This follows the checks-effects-interactions pattern to mitigate potential reentrancy attacks.\n if (token == UniversalTokenLib.ETH_ADDRESS) {\n // For ETH non-zero callValue is not allowed\n if (callValue != 0) revert NativeTokenCallValueNotSupported();\n // Check that the correct msg.value was sent\n if (msg.value != amount) revert MsgValueIncorrect();\n } else {\n // For ERC20s, we check that the correct msg.value was sent\n if (msg.value != callValue) revert MsgValueIncorrect();\n // We need to transfer the tokens from the Relayer to the recipient first before performing an\n // optional post-transfer arbitrary call.\n IERC20(token).safeTransferFrom(msg.sender, to, amount);\n }\n\n if (transaction.callParams.length != 0) {\n // Arbitrary call requested, perform it while supplying full msg.value to the recipient\n // Note: if token has a fee on transfers, the recipient will have received less than `amount`.\n // This is a very niche edge case and should be handled by the recipient contract.\n _checkedCallRecipient({recipient: to, token: token, amount: amount, callParams: transaction.callParams});\n } else if (msg.value != 0) {\n // No arbitrary call requested, but msg.value was sent. This is either a relay with ETH,\n // or a non-zero callValue request with an ERC20. In both cases, transfer the ETH to the recipient.\n Address.sendValue(payable(to), msg.value);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) public onlyRole(RELAYER_ROLE) {\n // update bridge tx status given proof provided\n if (bridgeTxDetails[transactionId].status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n bridgeTxDetails[transactionId].status = BridgeStatus.RELAYER_PROVED;\n bridgeTxDetails[transactionId].proofBlockTimestamp = uint40(block.timestamp);\n bridgeTxDetails[transactionId].proofBlockNumber = uint48(block.number);\n bridgeTxDetails[transactionId].proofRelayer = relayer;\n\n emit BridgeProofProvided(transactionId, relayer, destTxHash);\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes memory request, address to) public {\n bytes32 transactionId = keccak256(request);\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n\n // update bridge tx status if able to claim origin collateral\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n\n // if \"to\" is zero addr, permissionlessly send funds to proven relayer\n if (to == address(0)) {\n to = bridgeTxDetails[transactionId].proofRelayer;\n } else if (bridgeTxDetails[transactionId].proofRelayer != msg.sender) {\n revert SenderIncorrect();\n }\n\n if (_timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003c= DISPUTE_PERIOD) {\n revert DisputePeriodNotPassed();\n }\n\n bridgeTxDetails[transactionId].status = BridgeStatus.RELAYER_CLAIMED;\n\n // update protocol fees if origin fee amount exists\n if (transaction.originFeeAmount \u003e 0) protocolFees[transaction.originToken] += transaction.originFeeAmount;\n\n // transfer origin collateral less fee to specified address\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositClaimed(transactionId, bridgeTxDetails[transactionId].proofRelayer, to, token, amount);\n }\n\n function bridgeStatuses(bytes32 transactionId) public view returns (BridgeStatus status) {\n return bridgeTxDetails[transactionId].status;\n }\n\n function bridgeProofs(bytes32 transactionId) public view returns (uint96 timestamp, address relayer) {\n timestamp = bridgeTxDetails[transactionId].proofBlockTimestamp;\n relayer = bridgeTxDetails[transactionId].proofRelayer;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeRelays(bytes32 transactionId) public view returns (bool) {\n // has this transactionId been relayed?\n return bridgeRelayDetails[transactionId].relayer != address(0);\n }\n\n /// @inheritdoc IFastBridgeV2\n function getBridgeTransactionV2(bytes memory request) public pure returns (BridgeTransactionV2 memory) {\n return abi.decode(request, (BridgeTransactionV2));\n }\n\n /// @notice Takes the bridged asset from the user into FastBridgeV2 custody. It will be later\n /// claimed by the relayer who completed the relay on destination chain, or refunded back to the user,\n /// should no one complete the relay.\n function _takeBridgedUserAsset(address token, uint256 amount) internal returns (uint256 amountTaken) {\n if (token == UniversalTokenLib.ETH_ADDRESS) {\n // For ETH we just need to check that the supplied msg.value is correct.\n // Supplied `msg.value` is already in FastBridgeV2 custody.\n if (amount != msg.value) revert MsgValueIncorrect();\n amountTaken = msg.value;\n } else {\n // For ERC20s, token is explicitly transferred from the user to FastBridgeV2.\n // We don't allow non-zero `msg.value` to avoid extra funds from being stuck in FastBridgeV2.\n token.assertIsContract();\n if (msg.value != 0) revert MsgValueIncorrect();\n amountTaken = IERC20(token).balanceOf(address(this));\n IERC20(token).safeTransferFrom(msg.sender, address(this), amount);\n // Use the balance difference as the amount taken in case of fee on transfer tokens.\n amountTaken = IERC20(token).balanceOf(address(this)) - amountTaken;\n }\n }\n\n /// @notice Calls the Recipient's hook function with the specified callParams and performs\n /// all the necessary checks for the returned value.\n function _checkedCallRecipient(\n address recipient,\n address token,\n uint256 amount,\n bytes memory callParams\n )\n internal\n {\n bytes memory hookData =\n abi.encodeCall(IFastBridgeRecipient.fastBridgeTransferReceived, (token, amount, callParams));\n // This will bubble any revert messages from the hook function\n bytes memory returnData = Address.functionCallWithValue({target: recipient, data: hookData, value: msg.value});\n // Explicit revert if no return data at all\n if (returnData.length == 0) revert RecipientNoReturnValue();\n // Check that exactly a single return value was returned\n if (returnData.length != 32) revert RecipientIncorrectReturnValue();\n // Return value should be abi-encoded hook function selector\n if (bytes32(returnData) != bytes32(IFastBridgeRecipient.fastBridgeTransferReceived.selector)) {\n revert RecipientIncorrectReturnValue();\n }\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint40(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint40).max but\n /// proof.timestamp \u003c type(uint40).max via unchecked statement\n /// @param proofBlockTimestamp The bridge proof block timestamp\n /// @return delta Time delta since proof submitted\n function _timeSince(uint40 proofBlockTimestamp) internal view returns (uint256 delta) {\n unchecked {\n delta = uint40(block.timestamp) - proofBlockTimestamp;\n }\n }\n\n /// @notice Performs all the necessary checks for a bridge to happen.\n /// @dev There's no good way to refactor this function to reduce cyclomatic complexity due to\n /// the number of checks that need to be performed, so we skip the code-complexity rule here.\n // solhint-disable-next-line code-complexity\n function _validateBridgeParams(\n BridgeParams memory params,\n BridgeParamsV2 memory paramsV2,\n int256 exclusivityEndTime\n )\n internal\n view\n {\n // Check V1 (legacy) params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.sender == address(0) || params.to == address(0)) revert ZeroAddress();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n // Check V2 params\n if (paramsV2.callParams.length \u003e MAX_CALL_PARAMS_LENGTH) revert CallParamsLengthAboveMax();\n if (paramsV2.callValue != 0 \u0026\u0026 params.destToken == UniversalTokenLib.ETH_ADDRESS) {\n revert NativeTokenCallValueNotSupported();\n }\n // exclusivityEndTime must be in range (0 .. params.deadline]\n if (exclusivityEndTime \u003c= 0 || exclusivityEndTime \u003e int256(params.deadline)) {\n revert ExclusivityParamsIncorrect();\n }\n }\n\n /// @notice Performs all the necessary checks for a relay to happen.\n function _validateRelayParams(\n BridgeTransactionV2 memory transaction,\n bytes32 transactionId,\n address relayer\n )\n internal\n view\n {\n if (relayer == address(0)) revert ZeroAddress();\n // Check if the transaction has already been relayed\n if (bridgeRelays(transactionId)) revert TransactionRelayed();\n if (transaction.destChainId != block.chainid) revert ChainIncorrect();\n // Check the deadline for relay to happen\n if (block.timestamp \u003e transaction.deadline) revert DeadlineExceeded();\n // Check the exclusivity period, if it is still ongoing\n // forgefmt: disable-next-item\n if (\n transaction.exclusivityRelayer != address(0) \u0026\u0026\n transaction.exclusivityRelayer != relayer \u0026\u0026\n block.timestamp \u003c= transaction.exclusivityEndTime\n ) {\n revert ExclusivityPeriodNotPassed();\n }\n }\n}\n","language":"Solidity","languageVersion":"0.8.24","compilerVersion":"0.8.24","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"","srcMapRuntime":"","abiDefinition":[{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"}],"userDoc":{"kind":"user","methods":{},"version":1},"developerDoc":{"details":"Implementation of the {IERC165} interface. Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check for the additional interface id that will be supported. For example: ```solidity function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId); } ```","kind":"dev","methods":{"supportsInterface(bytes4)":{"details":"See {IERC165-supportsInterface}."}},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"bytes4\",\"name\":\"interfaceId\",\"type\":\"bytes4\"}],\"name\":\"supportsInterface\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"}],\"devdoc\":{\"details\":\"Implementation of the {IERC165} interface. Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check for the additional interface id that will be supported. For example: ```solidity function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId); } ```\",\"kind\":\"dev\",\"methods\":{\"supportsInterface(bytes4)\":{\"details\":\"See {IERC165-supportsInterface}.\"}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeV2.sol\":\"ERC165\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeV2.sol\":{\"keccak256\":\"0xfd916c030b1ffca5a136817827b8018c8ba42ca089905747f3de6148b73eb35e\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://18e6438c4096deb8ae453fb3365ba2b07d52944e93c08288fc5d012b71bf6bb3\",\"dweb:/ipfs/QmfEMqpT1zz6RRm7UuHLRowe1tds2cTGLrVonfm9XSCACj\"]}},\"version\":1}"},"hashes":{"supportsInterface(bytes4)":"01ffc9a7"}},"solidity/FastBridgeV2.sol:EnumerableSet":{"code":"0x60566037600b82828239805160001a607314602a57634e487b7160e01b600052600060045260246000fd5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600080fdfea264697066735822122096938e347a6ad7c9db19e62e3fe085fcb6b4b02d667bfa2b5db09e30538dd3cd64736f6c63430008180033","runtime-code":"0x73000000000000000000000000000000000000000030146080604052600080fdfea264697066735822122096938e347a6ad7c9db19e62e3fe085fcb6b4b02d667bfa2b5db09e30538dd3cd64736f6c63430008180033","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.24 ^0.8.0 ^0.8.20;\n\n// contracts/interfaces/IAdmin.sol\n\ninterface IAdmin {\n // ============ Events ============\n\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n event ChainGasAmountUpdated(uint256 oldChainGasAmount, uint256 newChainGasAmount);\n\n // ============ Methods ============\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n\n function setChainGasAmount(uint256 newChainGasAmount) external;\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IFastBridgeRecipient.sol\n\ninterface IFastBridgeRecipient {\n function fastBridgeTransferReceived(\n address token,\n uint256 amount,\n bytes memory callParams\n )\n external\n payable\n returns (bytes4);\n}\n\n// contracts/interfaces/IFastBridgeV2Errors.sol\n\ninterface IFastBridgeV2Errors {\n error AmountIncorrect();\n error CallParamsLengthAboveMax();\n error ChainIncorrect();\n error ExclusivityParamsIncorrect();\n error MsgValueIncorrect();\n error NativeTokenCallValueNotSupported();\n error SenderIncorrect();\n error StatusIncorrect();\n error ZeroAddress();\n\n error RecipientIncorrectReturnValue();\n error RecipientNoReturnValue();\n\n error DeadlineExceeded();\n error DeadlineNotExceeded();\n error DeadlineTooShort();\n error DisputePeriodNotPassed();\n error DisputePeriodPassed();\n error ExclusivityPeriodNotPassed();\n\n error TransactionRelayed();\n}\n\n// contracts/libs/Errors.sol\n\nerror DeadlineExceeded();\nerror DeadlineNotExceeded();\nerror DeadlineTooShort();\nerror InsufficientOutputAmount();\n\nerror MsgValueIncorrect();\nerror PoolNotFound();\nerror TokenAddressMismatch();\nerror TokenNotContract();\nerror TokenNotETH();\nerror TokensIdentical();\n\nerror ChainIncorrect();\nerror AmountIncorrect();\nerror ZeroAddress();\n\nerror DisputePeriodNotPassed();\nerror DisputePeriodPassed();\nerror SenderIncorrect();\nerror StatusIncorrect();\nerror TransactionIdIncorrect();\nerror TransactionRelayed();\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// contracts/interfaces/IFastBridgeV2.sol\n\ninterface IFastBridgeV2 is IFastBridge {\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n struct BridgeTxDetails {\n BridgeStatus status;\n uint40 proofBlockTimestamp;\n uint48 proofBlockNumber;\n address proofRelayer;\n }\n\n struct BridgeRelay {\n uint48 blockNumber;\n uint48 blockTimestamp;\n address relayer;\n }\n\n /// @notice New params introduced in the FastBridgeV2.\n /// We are passing fields from the older BridgeParams struct outside of this struct\n /// for backwards compatibility.\n /// Note: quoteRelayer and quoteExclusivitySeconds are either both zero (indicating no exclusivity)\n /// or both non-zero (indicating exclusivity for the given period).\n /// Note: callValue \u003e 0 can NOT be used with destToken = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE (ETH_ADDRESS)\n /// @param quoteRelayer Relayer that provided the quote for the transaction\n /// @param quoteExclusivitySeconds Period of time the quote relayer is guaranteed exclusivity after user's deposit\n /// @param quoteId Unique quote identifier used for tracking the quote\n /// @param callValue ETH value to send to the recipient (if any)\n /// @param callParams Parameters for the arbitrary call to the destination recipient (if any)\n struct BridgeParamsV2 {\n address quoteRelayer;\n int256 quoteExclusivitySeconds;\n bytes quoteId;\n uint256 callValue;\n bytes callParams;\n }\n\n /// @notice Updated bridge transaction struct to include parameters introduced in FastBridgeV2.\n /// Note: only `exclusivityRelayer` can fill such a transaction until `exclusivityEndTime`.\n /// TODO: consider changing the encoding scheme to prevent spending extra gas on decoding.\n struct BridgeTransactionV2 {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n uint256 callValue; // ETH value to send to the recipient (if any) - replaces V1's sendChainGas flag\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n address exclusivityRelayer;\n uint256 exclusivityEndTime;\n bytes callParams;\n }\n\n event BridgeQuoteDetails(bytes32 indexed transactionId, bytes quoteId);\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability\n /// to provide temporary exclusivity fill rights for the quote relayer.\n /// @param params The parameters required to bridge\n /// @param paramsV2 The parameters for exclusivity fill rights (optional, can be left empty)\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function relay(bytes memory request, address relayer) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param transactionId The transaction id associated with the encoded bridge transaction to prove\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital.\n /// @notice Can only send funds to the relayer address on the proof.\n /// @param request The encoded bridge transaction to claim on origin chain\n function claim(bytes memory request) external;\n /// @notice Checks if a transaction has been relayed\n /// @param transactionId The ID of the transaction to check\n /// @return True if the transaction has been relayed, false otherwise\n function bridgeRelays(bytes32 transactionId) external view returns (bool);\n\n /// @notice Returns the status of a bridge transaction\n /// @param transactionId The ID of the bridge transaction\n /// @return BridgeStatus Status of the bridge transaction\n function bridgeStatuses(bytes32 transactionId) external view returns (BridgeStatus);\n\n /// @notice Returns the timestamp and relayer of a bridge proof\n /// @param transactionId The ID of the bridge transaction\n /// @return timestamp The timestamp of the bridge proof\n /// @return relayer The relayer address of the bridge proof\n function bridgeProofs(bytes32 transactionId) external view returns (uint96 timestamp, address relayer);\n\n /// @notice Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\n /// @param request The bridge request to decode\n function getBridgeTransactionV2(bytes memory request) external view returns (BridgeTransactionV2 memory);\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// contracts/libs/UniversalToken.sol\n\nlibrary UniversalTokenLib {\n using SafeERC20 for IERC20;\n\n address internal constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Transfers tokens to the given account. Reverts if transfer is not successful.\n /// @dev This might trigger fallback, if ETH is transferred to the contract.\n /// Make sure this can not lead to reentrancy attacks.\n function universalTransfer(address token, address to, uint256 value) internal {\n // Don't do anything, if need to send tokens to this address\n if (to == address(this)) return;\n // Don't do anything, if trying to send zero value\n if (value == 0) return;\n if (token == ETH_ADDRESS) {\n /// @dev Note: this can potentially lead to executing code in `to`.\n // solhint-disable-next-line avoid-low-level-calls\n (bool success,) = to.call{value: value}(\"\");\n require(success, \"ETH transfer failed\");\n } else {\n IERC20(token).safeTransfer(to, value);\n }\n }\n\n /// @notice Issues an infinite allowance to the spender, if the current allowance is insufficient\n /// to spend the given amount.\n function universalApproveInfinity(address token, address spender, uint256 amountToSpend) internal {\n // ETH Chad doesn't require your approval\n if (token == ETH_ADDRESS) return;\n // No-op if allowance is already sufficient\n uint256 allowance = IERC20(token).allowance(address(this), spender);\n if (allowance \u003e= amountToSpend) return;\n // Otherwise, reset approval to 0 and set to max allowance\n if (allowance \u003e 0) IERC20(token).safeDecreaseAllowance(spender, allowance);\n IERC20(token).safeIncreaseAllowance(spender, type(uint256).max);\n }\n\n /// @notice Returns the balance of the given token (or native ETH) for the given account.\n function universalBalanceOf(address token, address account) internal view returns (uint256) {\n if (token == ETH_ADDRESS) {\n return account.balance;\n } else {\n return IERC20(token).balanceOf(account);\n }\n }\n\n /// @dev Checks that token is a contract and not ETH_ADDRESS.\n function assertIsContract(address token) internal view {\n // Check that ETH_ADDRESS was not used (in case this is a predeploy on any of the chains)\n if (token == UniversalTokenLib.ETH_ADDRESS) revert TokenNotContract();\n // Check that token is not an EOA\n if (token.code.length == 0) revert TokenNotContract();\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/Admin.sol\n\ncontract Admin is IAdmin, AccessControlEnumerable {\n using UniversalTokenLib for address;\n\n bytes32 public constant RELAYER_ROLE = keccak256(\"RELAYER_ROLE\");\n bytes32 public constant REFUNDER_ROLE = keccak256(\"REFUNDER_ROLE\");\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n uint256 public constant FEE_BPS = 1e6;\n uint256 public constant FEE_RATE_MAX = 0.01e6; // max 1% on origin amount\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Chain gas amount to forward as rebate if requested\n uint256 public chainGasAmount;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n }\n\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n require(newFeeRate \u003c= FEE_RATE_MAX, \"newFeeRate \u003e max\");\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n token.universalTransfer(recipient, feeAmount);\n emit FeesSwept(token, recipient, feeAmount);\n }\n\n function setChainGasAmount(uint256 newChainGasAmount) external onlyRole(GOVERNOR_ROLE) {\n uint256 oldChainGasAmount = chainGasAmount;\n chainGasAmount = newChainGasAmount;\n emit ChainGasAmountUpdated(oldChainGasAmount, newChainGasAmount);\n }\n}\n\n// contracts/FastBridgeV2.sol\n\n/// @notice FastBridgeV2 is a contract for bridging tokens across chains.\ncontract FastBridgeV2 is Admin, IFastBridgeV2, IFastBridgeV2Errors {\n using SafeERC20 for IERC20;\n using UniversalTokenLib for address;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Delay for a transaction after which it could be permisionlessly refunded\n uint256 public constant REFUND_DELAY = 7 days;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n /// @notice Maximum length of accepted callParams\n uint256 public constant MAX_CALL_PARAMS_LENGTH = 2 ** 16 - 1;\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeTxDetails) public bridgeTxDetails;\n /// @notice Relay details on destination chain\n mapping(bytes32 =\u003e BridgeRelay) public bridgeRelayDetails;\n /// @notice Unique bridge nonces tracked per originSender\n mapping(address =\u003e uint256) public senderNonces;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Replaced by senderNonces\n uint256 public immutable nonce = 0;\n /// @notice the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n bridge({\n params: params,\n paramsV2: BridgeParamsV2({\n quoteRelayer: address(0),\n quoteExclusivitySeconds: 0,\n quoteId: bytes(\"\"),\n callValue: 0,\n callParams: bytes(\"\")\n })\n });\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes memory request) external payable {\n relay({request: request, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes memory request, bytes32 destTxHash) external {\n prove({transactionId: keccak256(request), destTxHash: destTxHash, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridgeV2\n function claim(bytes memory request) external {\n claim({request: request, to: address(0)});\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003e DISPUTE_PERIOD) {\n revert DisputePeriodPassed();\n }\n\n // @dev relayer gets slashed effectively if dest relay has gone thru\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n bridgeTxDetails[transactionId].proofRelayer = address(0);\n bridgeTxDetails[transactionId].proofBlockTimestamp = 0;\n bridgeTxDetails[transactionId].proofBlockNumber = 0;\n\n emit BridgeProofDisputed(transactionId, msg.sender);\n }\n\n /// @inheritdoc IFastBridge\n function refund(bytes memory request) external {\n bytes32 transactionId = keccak256(request);\n\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n\n if (bridgeTxDetails[transactionId].status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n\n if (hasRole(REFUNDER_ROLE, msg.sender)) {\n // Refunder can refund if deadline has passed\n if (block.timestamp \u003c= transaction.deadline) revert DeadlineNotExceeded();\n } else {\n // Permissionless refund is allowed after REFUND_DELAY\n if (block.timestamp \u003c= transaction.deadline + REFUND_DELAY) revert DeadlineNotExceeded();\n }\n\n // if all checks passed, set to REFUNDED status\n bridgeTxDetails[transactionId].status = BridgeStatus.REFUNDED;\n\n // transfer origin collateral back to original sender\n address to = transaction.originSender;\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount + transaction.originFeeAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (bridgeTxDetails[transactionId].proofRelayer != relayer) revert SenderIncorrect();\n return _timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n /// @dev This method is added to achieve backwards compatibility with decoding requests into V1 structs:\n /// - `callValue` is partially reported as a zero/non-zero flag\n /// - `callParams` is ignored\n /// In order to process all kinds of requests use getBridgeTransactionV2 instead.\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory) {\n // Try decoding into V2 struct first. This will revert if V1 struct is passed\n try this.getBridgeTransactionV2(request) returns (BridgeTransactionV2 memory txV2) {\n // Note: we entirely ignore the callParams field, as it was not present in V1\n return BridgeTransaction({\n originChainId: txV2.originChainId,\n destChainId: txV2.destChainId,\n originSender: txV2.originSender,\n destRecipient: txV2.destRecipient,\n originToken: txV2.originToken,\n destToken: txV2.destToken,\n originAmount: txV2.originAmount,\n destAmount: txV2.destAmount,\n originFeeAmount: txV2.originFeeAmount,\n sendChainGas: txV2.callValue != 0,\n deadline: txV2.deadline,\n nonce: txV2.nonce\n });\n } catch {\n // Fallback to V1 struct\n return abi.decode(request, (BridgeTransaction));\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) public payable {\n int256 exclusivityEndTime = int256(block.timestamp) + paramsV2.quoteExclusivitySeconds;\n _validateBridgeParams(params, paramsV2, exclusivityEndTime);\n\n // transfer tokens to bridge contract\n /// @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _takeBridgedUserAsset(params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n\n // set status to requested\n bytes memory request = abi.encode(\n BridgeTransactionV2({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n callValue: paramsV2.callValue,\n deadline: params.deadline,\n nonce: senderNonces[params.sender]++, // increment nonce on every bridge\n exclusivityRelayer: paramsV2.quoteRelayer,\n // We checked exclusivityEndTime to be in range (0 .. params.deadline] above, so can safely cast\n exclusivityEndTime: uint256(exclusivityEndTime),\n callParams: paramsV2.callParams\n })\n );\n bytes32 transactionId = keccak256(request);\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n\n emit BridgeRequested({\n transactionId: transactionId,\n sender: params.sender,\n request: request,\n destChainId: params.dstChainId,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n sendChainGas: paramsV2.callValue != 0\n });\n emit BridgeQuoteDetails(transactionId, paramsV2.quoteId);\n }\n\n /// @inheritdoc IFastBridgeV2\n function relay(bytes memory request, address relayer) public payable {\n bytes32 transactionId = keccak256(request);\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n _validateRelayParams(transaction, transactionId, relayer);\n // mark bridge transaction as relayed\n bridgeRelayDetails[transactionId] =\n BridgeRelay({blockNumber: uint48(block.number), blockTimestamp: uint48(block.timestamp), relayer: relayer});\n\n // transfer tokens to recipient on destination chain and do an arbitrary call if requested\n address to = transaction.destRecipient;\n address token = transaction.destToken;\n uint256 amount = transaction.destAmount;\n uint256 callValue = transaction.callValue;\n\n // Emit the event before any external calls\n emit BridgeRelayed({\n transactionId: transactionId,\n relayer: relayer,\n to: to,\n originChainId: transaction.originChainId,\n originToken: transaction.originToken,\n destToken: token,\n originAmount: transaction.originAmount,\n destAmount: amount,\n chainGasAmount: callValue\n });\n\n // All state changes have been done at this point, can proceed to the external calls.\n // This follows the checks-effects-interactions pattern to mitigate potential reentrancy attacks.\n if (token == UniversalTokenLib.ETH_ADDRESS) {\n // For ETH non-zero callValue is not allowed\n if (callValue != 0) revert NativeTokenCallValueNotSupported();\n // Check that the correct msg.value was sent\n if (msg.value != amount) revert MsgValueIncorrect();\n } else {\n // For ERC20s, we check that the correct msg.value was sent\n if (msg.value != callValue) revert MsgValueIncorrect();\n // We need to transfer the tokens from the Relayer to the recipient first before performing an\n // optional post-transfer arbitrary call.\n IERC20(token).safeTransferFrom(msg.sender, to, amount);\n }\n\n if (transaction.callParams.length != 0) {\n // Arbitrary call requested, perform it while supplying full msg.value to the recipient\n // Note: if token has a fee on transfers, the recipient will have received less than `amount`.\n // This is a very niche edge case and should be handled by the recipient contract.\n _checkedCallRecipient({recipient: to, token: token, amount: amount, callParams: transaction.callParams});\n } else if (msg.value != 0) {\n // No arbitrary call requested, but msg.value was sent. This is either a relay with ETH,\n // or a non-zero callValue request with an ERC20. In both cases, transfer the ETH to the recipient.\n Address.sendValue(payable(to), msg.value);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) public onlyRole(RELAYER_ROLE) {\n // update bridge tx status given proof provided\n if (bridgeTxDetails[transactionId].status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n bridgeTxDetails[transactionId].status = BridgeStatus.RELAYER_PROVED;\n bridgeTxDetails[transactionId].proofBlockTimestamp = uint40(block.timestamp);\n bridgeTxDetails[transactionId].proofBlockNumber = uint48(block.number);\n bridgeTxDetails[transactionId].proofRelayer = relayer;\n\n emit BridgeProofProvided(transactionId, relayer, destTxHash);\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes memory request, address to) public {\n bytes32 transactionId = keccak256(request);\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n\n // update bridge tx status if able to claim origin collateral\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n\n // if \"to\" is zero addr, permissionlessly send funds to proven relayer\n if (to == address(0)) {\n to = bridgeTxDetails[transactionId].proofRelayer;\n } else if (bridgeTxDetails[transactionId].proofRelayer != msg.sender) {\n revert SenderIncorrect();\n }\n\n if (_timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003c= DISPUTE_PERIOD) {\n revert DisputePeriodNotPassed();\n }\n\n bridgeTxDetails[transactionId].status = BridgeStatus.RELAYER_CLAIMED;\n\n // update protocol fees if origin fee amount exists\n if (transaction.originFeeAmount \u003e 0) protocolFees[transaction.originToken] += transaction.originFeeAmount;\n\n // transfer origin collateral less fee to specified address\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositClaimed(transactionId, bridgeTxDetails[transactionId].proofRelayer, to, token, amount);\n }\n\n function bridgeStatuses(bytes32 transactionId) public view returns (BridgeStatus status) {\n return bridgeTxDetails[transactionId].status;\n }\n\n function bridgeProofs(bytes32 transactionId) public view returns (uint96 timestamp, address relayer) {\n timestamp = bridgeTxDetails[transactionId].proofBlockTimestamp;\n relayer = bridgeTxDetails[transactionId].proofRelayer;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeRelays(bytes32 transactionId) public view returns (bool) {\n // has this transactionId been relayed?\n return bridgeRelayDetails[transactionId].relayer != address(0);\n }\n\n /// @inheritdoc IFastBridgeV2\n function getBridgeTransactionV2(bytes memory request) public pure returns (BridgeTransactionV2 memory) {\n return abi.decode(request, (BridgeTransactionV2));\n }\n\n /// @notice Takes the bridged asset from the user into FastBridgeV2 custody. It will be later\n /// claimed by the relayer who completed the relay on destination chain, or refunded back to the user,\n /// should no one complete the relay.\n function _takeBridgedUserAsset(address token, uint256 amount) internal returns (uint256 amountTaken) {\n if (token == UniversalTokenLib.ETH_ADDRESS) {\n // For ETH we just need to check that the supplied msg.value is correct.\n // Supplied `msg.value` is already in FastBridgeV2 custody.\n if (amount != msg.value) revert MsgValueIncorrect();\n amountTaken = msg.value;\n } else {\n // For ERC20s, token is explicitly transferred from the user to FastBridgeV2.\n // We don't allow non-zero `msg.value` to avoid extra funds from being stuck in FastBridgeV2.\n token.assertIsContract();\n if (msg.value != 0) revert MsgValueIncorrect();\n amountTaken = IERC20(token).balanceOf(address(this));\n IERC20(token).safeTransferFrom(msg.sender, address(this), amount);\n // Use the balance difference as the amount taken in case of fee on transfer tokens.\n amountTaken = IERC20(token).balanceOf(address(this)) - amountTaken;\n }\n }\n\n /// @notice Calls the Recipient's hook function with the specified callParams and performs\n /// all the necessary checks for the returned value.\n function _checkedCallRecipient(\n address recipient,\n address token,\n uint256 amount,\n bytes memory callParams\n )\n internal\n {\n bytes memory hookData =\n abi.encodeCall(IFastBridgeRecipient.fastBridgeTransferReceived, (token, amount, callParams));\n // This will bubble any revert messages from the hook function\n bytes memory returnData = Address.functionCallWithValue({target: recipient, data: hookData, value: msg.value});\n // Explicit revert if no return data at all\n if (returnData.length == 0) revert RecipientNoReturnValue();\n // Check that exactly a single return value was returned\n if (returnData.length != 32) revert RecipientIncorrectReturnValue();\n // Return value should be abi-encoded hook function selector\n if (bytes32(returnData) != bytes32(IFastBridgeRecipient.fastBridgeTransferReceived.selector)) {\n revert RecipientIncorrectReturnValue();\n }\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint40(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint40).max but\n /// proof.timestamp \u003c type(uint40).max via unchecked statement\n /// @param proofBlockTimestamp The bridge proof block timestamp\n /// @return delta Time delta since proof submitted\n function _timeSince(uint40 proofBlockTimestamp) internal view returns (uint256 delta) {\n unchecked {\n delta = uint40(block.timestamp) - proofBlockTimestamp;\n }\n }\n\n /// @notice Performs all the necessary checks for a bridge to happen.\n /// @dev There's no good way to refactor this function to reduce cyclomatic complexity due to\n /// the number of checks that need to be performed, so we skip the code-complexity rule here.\n // solhint-disable-next-line code-complexity\n function _validateBridgeParams(\n BridgeParams memory params,\n BridgeParamsV2 memory paramsV2,\n int256 exclusivityEndTime\n )\n internal\n view\n {\n // Check V1 (legacy) params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.sender == address(0) || params.to == address(0)) revert ZeroAddress();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n // Check V2 params\n if (paramsV2.callParams.length \u003e MAX_CALL_PARAMS_LENGTH) revert CallParamsLengthAboveMax();\n if (paramsV2.callValue != 0 \u0026\u0026 params.destToken == UniversalTokenLib.ETH_ADDRESS) {\n revert NativeTokenCallValueNotSupported();\n }\n // exclusivityEndTime must be in range (0 .. params.deadline]\n if (exclusivityEndTime \u003c= 0 || exclusivityEndTime \u003e int256(params.deadline)) {\n revert ExclusivityParamsIncorrect();\n }\n }\n\n /// @notice Performs all the necessary checks for a relay to happen.\n function _validateRelayParams(\n BridgeTransactionV2 memory transaction,\n bytes32 transactionId,\n address relayer\n )\n internal\n view\n {\n if (relayer == address(0)) revert ZeroAddress();\n // Check if the transaction has already been relayed\n if (bridgeRelays(transactionId)) revert TransactionRelayed();\n if (transaction.destChainId != block.chainid) revert ChainIncorrect();\n // Check the deadline for relay to happen\n if (block.timestamp \u003e transaction.deadline) revert DeadlineExceeded();\n // Check the exclusivity period, if it is still ongoing\n // forgefmt: disable-next-item\n if (\n transaction.exclusivityRelayer != address(0) \u0026\u0026\n transaction.exclusivityRelayer != relayer \u0026\u0026\n block.timestamp \u003c= transaction.exclusivityEndTime\n ) {\n revert ExclusivityPeriodNotPassed();\n }\n }\n}\n","language":"Solidity","languageVersion":"0.8.24","compilerVersion":"0.8.24","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"25827:11640:0:-:0;;;;;;;;;;;;;;;-1:-1:-1;;;25827:11640:0;;;;;;;;;;;;;;;;;","srcMapRuntime":"25827:11640:0:-:0;;;;;;;;","abiDefinition":[],"userDoc":{"kind":"user","methods":{},"version":1},"developerDoc":{"details":"Library for managing https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive types. Sets have the following properties: - Elements are added, removed, and checked for existence in constant time (O(1)). - Elements are enumerated in O(n). No guarantees are made on the ordering. ```solidity contract Example { // Add the library methods using EnumerableSet for EnumerableSet.AddressSet; // Declare a set state variable EnumerableSet.AddressSet private mySet; } ``` As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`) and `uint256` (`UintSet`) are supported. [WARNING] ==== Trying to delete such a structure from storage will likely result in data corruption, rendering the structure unusable. See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info. In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an array of EnumerableSet. ====","kind":"dev","methods":{},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[],\"devdoc\":{\"details\":\"Library for managing https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive types. Sets have the following properties: - Elements are added, removed, and checked for existence in constant time (O(1)). - Elements are enumerated in O(n). No guarantees are made on the ordering. ```solidity contract Example { // Add the library methods using EnumerableSet for EnumerableSet.AddressSet; // Declare a set state variable EnumerableSet.AddressSet private mySet; } ``` As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`) and `uint256` (`UintSet`) are supported. [WARNING] ==== Trying to delete such a structure from storage will likely result in data corruption, rendering the structure unusable. See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info. In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an array of EnumerableSet. ====\",\"kind\":\"dev\",\"methods\":{},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeV2.sol\":\"EnumerableSet\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeV2.sol\":{\"keccak256\":\"0xfd916c030b1ffca5a136817827b8018c8ba42ca089905747f3de6148b73eb35e\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://18e6438c4096deb8ae453fb3365ba2b07d52944e93c08288fc5d012b71bf6bb3\",\"dweb:/ipfs/QmfEMqpT1zz6RRm7UuHLRowe1tds2cTGLrVonfm9XSCACj\"]}},\"version\":1}"},"hashes":{}},"solidity/FastBridgeV2.sol:FastBridgeV2":{"code":"0x60c060405260006080523480156200001657600080fd5b5060405162003e6138038062003e61833981016040819052620000399162000199565b806200004760008262000054565b50504360a05250620001c4565b60008062000063848462000091565b90508015620000885760008481526001602052604090206200008690846200013f565b505b90505b92915050565b6000828152602081815260408083206001600160a01b038516845290915281205460ff1662000136576000838152602081815260408083206001600160a01b03861684529091529020805460ff19166001179055620000ed3390565b6001600160a01b0316826001600160a01b0316847f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45060016200008b565b5060006200008b565b600062000088836001600160a01b038416600081815260018301602052604081205462000136575081546001818101845560008481526020808220909301849055845484825282860190935260409020919091556200008b565b600060208284031215620001ac57600080fd5b81516001600160a01b03811681146200008857600080fd5b60805160a051613c77620001ea6000396000610802015260006108a30152613c776000f3fe6080604052600436106102fd5760003560e01c806391ad50391161018f578063b13aa2d6116100e1578063ca15c8731161008a578063dcf844a711610064578063dcf844a714610a50578063df36bb1314610a7d578063e00a83e014610a9357600080fd5b8063ca15c873146109dc578063ccc57490146109fc578063d547741f14610a3057600080fd5b8063bfc7c607116100bb578063bfc7c6071461091c578063c63ff8dd1461092f578063c79371b11461094f57600080fd5b8063b13aa2d6146108c5578063b250fe6b146108e5578063bf333f2c1461090557600080fd5b8063a3ec191a11610143578063ac11fb1a1161011d578063ac11fb1a14610844578063add98c7014610871578063affed0e01461089157600080fd5b8063a3ec191a146107f0578063a5bbe22b14610607578063aa9641ab1461082457600080fd5b8063926d7d7f11610174578063926d7d7f146107945780639c9545f0146107c8578063a217fddf146107db57600080fd5b806391ad5039146106d057806391d148541461075057600080fd5b806341fcb6121161025357806363787e52116101fc578063886d36ff116101d6578063886d36ff146106655780638f0d6f17146106855780639010d07c1461069857600080fd5b806363787e521461058c578063820688d5146106075780638379a24f1461061d57600080fd5b80635960ccf21161022d5780635960ccf21461050b5780635aa6ccba1461053f5780635eb7d9461461056c57600080fd5b806341fcb612146104c257806345851694146104e257806358f85880146104f557600080fd5b806318e4357d116102b5578063295710ff1161028f578063295710ff146104555780632f2ff15d1461048257806336568abe146104a257600080fd5b806318e4357d146103ee578063190da5951461040e578063248a9ca31461042557600080fd5b8063051287bc116102e6578063051287bc1461037957806306f333f2146103b65780630f5f6ed7146103d857600080fd5b806301ffc9a71461030257806303ed0ee514610337575b600080fd5b34801561030e57600080fd5b5061032261031d366004612eef565b610aa9565b60405190151581526020015b60405180910390f35b34801561034357600080fd5b5061036b7f043c983c49d46f0e102151eaf8085d4a2e6571d5df2d47b013f39bddfd4a639d81565b60405190815260200161032e565b34801561038557600080fd5b506103a9610394366004612f31565b60009081526005602052604090205460ff1690565b60405161032e9190612fb4565b3480156103c257600080fd5b506103d66103d1366004612fe2565b610b05565b005b3480156103e457600080fd5b5061036b61271081565b3480156103fa57600080fd5b506103d661040936600461301b565b610bcc565b34801561041a57600080fd5b5061036b62093a8081565b34801561043157600080fd5b5061036b610440366004612f31565b60009081526020819052604090206001015490565b34801561046157600080fd5b5061036b610470366004613054565b60076020526000908152604090205481565b34801561048e57600080fd5b506103d661049d366004613071565b610d39565b3480156104ae57600080fd5b506103d66104bd366004613071565b610d64565b3480156104ce57600080fd5b506103d66104dd366004613209565b610db0565b6103d66104f0366004613329565b611026565b34801561050157600080fd5b5061036b60025481565b34801561051757600080fd5b5061036b7fdb9556138406326f00296e13ea2ad7db24ba82381212d816b1a40c23b466b32781565b34801561054b57600080fd5b5061055f61055a366004613346565b611083565b60405161032e91906133d3565b34801561057857600080fd5b506103d6610587366004613346565b611149565b34801561059857600080fd5b506105f76105a7366004612f31565b60056020526000908152604090205460ff811690610100810464ffffffffff16906601000000000000810465ffffffffffff16906c0100000000000000000000000090046001600160a01b031684565b60405161032e94939291906134e8565b34801561061357600080fd5b5061036b61070881565b34801561062957600080fd5b50610322610638366004612f31565b6000908152600660205260409020546c0100000000000000000000000090046001600160a01b0316151590565b34801561067157600080fd5b506103d6610680366004613529565b61133e565b6103d6610693366004613346565b611354565b3480156106a457600080fd5b506106b86106b336600461356e565b61135e565b6040516001600160a01b03909116815260200161032e565b3480156106dc57600080fd5b506107246106eb366004612f31565b600090815260056020526040902054610100810464ffffffffff16916c010000000000000000000000009091046001600160a01b031690565b604080516bffffffffffffffffffffffff90931683526001600160a01b0390911660208301520161032e565b34801561075c57600080fd5b5061032261076b366004613071565b6000918252602082815260408084206001600160a01b0393909316845291905290205460ff1690565b3480156107a057600080fd5b5061036b7fe2b7fb3b832174769106daebcfd6d1970523240dda11281102db9363b83b0dc481565b6103d66107d6366004613209565b61137d565b3480156107e757600080fd5b5061036b600081565b3480156107fc57600080fd5b5061036b7f000000000000000000000000000000000000000000000000000000000000000081565b34801561083057600080fd5b5061032261083f366004613071565b611603565b34801561085057600080fd5b5061086461085f366004613346565b6116ee565b60405161032e9190613590565b34801561087d57600080fd5b506103d661088c366004612f31565b6118a6565b34801561089d57600080fd5b5061036b7f000000000000000000000000000000000000000000000000000000000000000081565b3480156108d157600080fd5b506103d66108e0366004612f31565b6119c8565b3480156108f157600080fd5b506103d6610900366004612f31565b611aaa565b34801561091157600080fd5b5061036b620f424081565b6103d661092a366004613676565b611b12565b34801561093b57600080fd5b506103d661094a366004613346565b611d94565b34801561095b57600080fd5b506109ae61096a366004612f31565b60066020526000908152604090205465ffffffffffff8082169166010000000000008104909116906c0100000000000000000000000090046001600160a01b031683565b6040805165ffffffffffff94851681529390921660208401526001600160a01b03169082015260600161032e565b3480156109e857600080fd5b5061036b6109f7366004612f31565b611d9f565b348015610a0857600080fd5b5061036b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f5581565b348015610a3c57600080fd5b506103d6610a4b366004613071565b611db6565b348015610a5c57600080fd5b5061036b610a6b366004613054565b60036020526000908152604090205481565b348015610a8957600080fd5b5061036b61ffff81565b348015610a9f57600080fd5b5061036b60045481565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f5a05180f000000000000000000000000000000000000000000000000000000001480610aff5750610aff82611ddb565b92915050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f55610b2f81611e72565b6001600160a01b03831660009081526003602052604081205490819003610b565750505050565b6001600160a01b038416600081815260036020526040812055610b7a908483611e7c565b604080516001600160a01b038087168252851660208201529081018290527f244e51bc38c1452fa8aaf487bcb4bca36c2baa3a5fbdb776b1eabd8dc6d277cd9060600160405180910390a1505b505050565b7fe2b7fb3b832174769106daebcfd6d1970523240dda11281102db9363b83b0dc4610bf681611e72565b600160008581526005602052604090205460ff166004811115610c1b57610c1b612f4a565b14610c52576040517f4145817200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600084815260056020908152604091829020805460027fffffffffffffffffffffffffffffffffffffffff0000000000000000000000009091166101004264ffffffffff16027fffffffffffffffffffffffffffffffffffffffff000000000000ffffffffffff161766010000000000004365ffffffffffff160217176bffffffffffffffffffffffff166c010000000000000000000000006001600160a01b0387169081029190911790915582518681529251909287927f4ac8af8a2cd87193d64dfc7a3b8d9923b714ec528b18725d080aa1299be0c5e492918290030190a350505050565b600082815260208190526040902060010154610d5481611e72565b610d5e8383611f9f565b50505050565b6001600160a01b0381163314610da6576040517f6697b23200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610bc78282611fd4565b815160208301206000610dc284611083565b9050600260008381526005602052604090205460ff166004811115610de957610de9612f4a565b14610e20576040517f4145817200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600160a01b038316610e5d576000828152600560205260409020546c0100000000000000000000000090046001600160a01b03169250610ebd565b6000828152600560205260409020546c0100000000000000000000000090046001600160a01b03163314610ebd576040517f4af43a9000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008281526005602052604090205461070890610100900464ffffffffff90811642031611610f18576040517f1992d0bd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600082815260056020526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016600317905561010081015115610f925761010081015160808201516001600160a01b031660009081526003602052604081208054909190610f8c908490613773565b90915550505b608081015160c0820151610fb06001600160a01b0383168683611e7c565b6000848152600560209081526040918290205482516001600160a01b038681168252928101859052888316936c010000000000000000000000009092049092169187917f582211c35a2139ac3bbaac74663c6a1f56c6cbb658b41fe11fd45a82074ac678910160405180910390a4505050505050565b611080816040518060a0016040528060006001600160a01b03168152602001600081526020016040518060200160405280600081525081526020016000815260200160405180602001604052806000815250815250611b12565b50565b611135604051806101e00160405280600063ffffffff168152602001600063ffffffff16815260200160006001600160a01b0316815260200160006001600160a01b0316815260200160006001600160a01b0316815260200160006001600160a01b0316815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160006001600160a01b0316815260200160008152602001606081525090565b81806020019051810190610aff91906137e1565b80516020820120600061115b83611083565b9050600160008381526005602052604090205460ff16600481111561118257611182612f4a565b146111b9576040517f4145817200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b3360009081527fd2043bf65931af3dbecf60d0db8f40e4160406d7beb00522f4200cf4944a1eb8602052604090205460ff161561123357806101400151421161122e576040517fe15ff9ea00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61127f565b62093a808161014001516112479190613773565b421161127f576040517fe15ff9ea00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008281526005602052604080822080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166004179055820151608083015161010084015160c0850151929391926112d89190613773565b90506112ee6001600160a01b0383168483611e7c565b604080516001600160a01b0384811682526020820184905285169187917fb4c55c0c9bc613519b920e88748090150b890a875d307f21bea7d4fb2e8bc958910160405180910390a3505050505050565b61135082805190602001208233610bcc565b5050565b611080813361137d565b60008281526001602052604081206113769083612001565b9392505050565b81516020830120600061138f84611083565b905061139c81838561200d565b604080516060808201835265ffffffffffff438116835242811660208085019182526001600160a01b0389811686880181815260008b815260068552899020975188549551915184166c01000000000000000000000000026bffffffffffffffffffffffff9288166601000000000000027fffffffffffffffffffffffffffffffffffffffff00000000000000000000000090971691909716179490941793909316939093179094558583015160a08088015160e08901516101208a01518a516080808d015160c0808f01518e5163ffffffff9095168552918b169c84019c909c52858a169c83019c909c529881019a909a52968901819052918801869052919691959094938716929189917ff8ae392d784b1ea5e8881bfa586d81abf07ef4f1e2fc75f7fe51c90f05199a5c910160405180910390a47fffffffffffffffffffffffff11111111111111111111111111111111111111126001600160a01b0384160161157957801561153b576040517f2598ad2e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b813414611574576040517f81de0bf300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6115c7565b8034146115b2576040517f81de0bf300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6115c76001600160a01b0384163386856121aa565b6101c085015151156115e9576115e4848484886101c00151612226565b6115f9565b34156115f9576115f98434612385565b5050505050505050565b6000600260008481526005602052604090205460ff16600481111561162a5761162a612f4a565b14611661576040517f4145817200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000838152600560205260409020546001600160a01b038381166c0100000000000000000000000090920416146116c4576040517f4af43a9000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b505060009081526005602052604090205461070861010090910464ffffffffff9081164203161190565b6040805161018081018252600080825260208201819052818301819052606082018190526080820181905260a0820181905260c0820181905260e0820181905261010082018190526101208201819052610140820181905261016082015290517f5aa6ccba0000000000000000000000000000000000000000000000000000000081523090635aa6ccba90611787908590600401613916565b600060405180830381865afa9250505080156117c557506040513d6000823e601f3d908101601f191682016040526117c291908101906137e1565b60015b6117dd5781806020019051810190610aff9190613934565b604051806101800160405280826000015163ffffffff168152602001826020015163ffffffff16815260200182604001516001600160a01b0316815260200182606001516001600160a01b0316815260200182608001516001600160a01b031681526020018260a001516001600160a01b031681526020018260c0015181526020018260e001518152602001826101000151815260200182610120015160001415151581526020018261014001518152602001826101600151815250915050919050565b919050565b7f043c983c49d46f0e102151eaf8085d4a2e6571d5df2d47b013f39bddfd4a639d6118d081611e72565b600260008381526005602052604090205460ff1660048111156118f5576118f5612f4a565b1461192c576040517f4145817200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008281526005602052604090205461070890610100900464ffffffffff9081164203161115611988576040517f3e908aac00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000828152600560205260408082206001905551339184917f0695cf1d39b3055dcd0fe02d8b47eaf0d5a13e1996de925de59d0ef9b7f7fad49190a35050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f556119f281611e72565b612710821115611a63576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f6e657746656552617465203e206d61780000000000000000000000000000000060448201526064015b60405180910390fd5b600280549083905560408051828152602081018590527f14914da2bf76024616fbe1859783fcd4dbddcb179b1f3a854949fbf920dcb95791015b60405180910390a1505050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f55611ad481611e72565b600480549083905560408051828152602081018590527f5cf09b12f3f56b4c564d51b25b40360af6d795198adb61ae0806a36c294323fa9101611a9d565b6000816020015142611b249190613a00565b9050611b3183838361244e565b6000611b4584606001518560a001516126d3565b90506000806002541115611b7257620f424060025483611b659190613a28565b611b6f9190613a3f565b90505b611b7c8183613a7a565b91506000604051806101e001604052804663ffffffff168152602001876000015163ffffffff16815260200187602001516001600160a01b0316815260200187604001516001600160a01b0316815260200187606001516001600160a01b0316815260200187608001516001600160a01b031681526020018481526020018760c0015181526020018381526020018660600151815260200187610100015181526020016007600089602001516001600160a01b03166001600160a01b031681526020019081526020016000206000815480929190611c5990613a8d565b91905055815260200186600001516001600160a01b031681526020018581526020018660800151815250604051602001611c9391906133d3565b60408051808303601f1901815282825280516020808301919091206000818152600583529390932080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016600117905589015189516060808c015160808d015160c08e0151928d015195985095966001600160a01b039094169587957f120ea0364f36cdac7983bcfdd55270ca09d7f9b314a2ebc425a3b01ab1d6403a95611d47958b95909493928e9290151590613ac5565b60405180910390a3807f3120e2bb59c86aca6890191a589a96af3662838efa374fbdcdf4c95bfe4a6c0e8760400151604051611d839190613916565b60405180910390a250505050505050565b611080816000610db0565b6000818152600160205260408120610aff906128b4565b600082815260208190526040902060010154611dd181611e72565b610d5e8383611fd4565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f7965db0b000000000000000000000000000000000000000000000000000000001480610aff57507f01ffc9a7000000000000000000000000000000000000000000000000000000007fffffffff00000000000000000000000000000000000000000000000000000000831614610aff565b61108081336128be565b306001600160a01b03831603611e9157505050565b80600003611e9e57505050565b7fffffffffffffffffffffffff11111111111111111111111111111111111111126001600160a01b03841601611f8b576000826001600160a01b03168260405160006040518083038185875af1925050503d8060008114611f1b576040519150601f19603f3d011682016040523d82523d6000602084013e611f20565b606091505b5050905080610d5e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f455448207472616e73666572206661696c6564000000000000000000000000006044820152606401611a5a565b610bc76001600160a01b038416838361292a565b600080611fac848461295b565b90508015611376576000848152600160205260409020611fcc9084612a23565b509392505050565b600080611fe18484612a38565b90508015611376576000848152600160205260409020611fcc9084612ad9565b60006113768383612aee565b6001600160a01b03811661204d576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000828152600660205260409020546c0100000000000000000000000090046001600160a01b0316156120ac576040517fbef7bb7d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b46836020015163ffffffff16146120ef576040517f7029fdf900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b82610140015142111561212e576040517f559895a300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6101808301516001600160a01b0316158015906121625750806001600160a01b03168361018001516001600160a01b031614155b80156121735750826101a001514211155b15610bc7576040517f14be123200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040516001600160a01b038481166024830152838116604483015260648201839052610d5e9186918216906323b872dd906084015b604051602081830303815290604052915060e01b6020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8381831617835250505050612b18565b600083838360405160240161223d93929190613b1b565b60408051601f198184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f461e0c2100000000000000000000000000000000000000000000000000000000179052905060006122a4868334612b94565b905080516000036122e1576040517f1a95ad2600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b805160201461231c576040517ff3725cca00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f461e0c210000000000000000000000000000000000000000000000000000000061234682613b4c565b1461237d576040517ff3725cca00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b505050505050565b804710156123c1576040517fcd786059000000000000000000000000000000000000000000000000000000008152306004820152602401611a5a565b6000826001600160a01b03168260405160006040518083038185875af1925050503d806000811461240e576040519150601f19603f3d011682016040523d82523d6000602084013e612413565b606091505b5050905080610bc7576040517f1425ea4200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b46836000015163ffffffff1603612491576040517f7029fdf900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60a083015115806124a4575060c0830151155b156124db576040517fe38820c800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60208301516001600160a01b03161580612500575060408301516001600160a01b0316155b15612537576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60608301516001600160a01b0316158061255c575060808301516001600160a01b0316155b15612593576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61259f61070842613773565b83610100015110156125dd576040517f04b7fcc800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61ffff826080015151111561261e576040517ffbe24d4900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b606082015115801590612651575060808301516001600160a01b031673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee145b15612688576040517f2598ad2e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008113158061269c575082610100015181135b15610bc7576040517f352807b900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60007fffffffffffffffffffffffff11111111111111111111111111111111111111126001600160a01b038416016127455734821461273e576040517f81de0bf300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5034610aff565b612757836001600160a01b0316612c4a565b341561278f576040517f81de0bf300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201526001600160a01b038416906370a0823190602401602060405180830381865afa1580156127ec573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128109190613b91565b90506128276001600160a01b0384163330856121aa565b6040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015281906001600160a01b038516906370a0823190602401602060405180830381865afa158015612886573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128aa9190613b91565b6113769190613a7a565b6000610aff825490565b6000828152602081815260408083206001600160a01b038516845290915290205460ff16611350576040517fe2517d3f0000000000000000000000000000000000000000000000000000000081526001600160a01b038216600482015260248101839052604401611a5a565b6040516001600160a01b03838116602483015260448201839052610bc791859182169063a9059cbb906064016121df565b6000828152602081815260408083206001600160a01b038516845290915281205460ff16612a1b576000838152602081815260408083206001600160a01b0386168452909152902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790556129d33390565b6001600160a01b0316826001600160a01b0316847f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a4506001610aff565b506000610aff565b6000611376836001600160a01b038416612cf0565b6000828152602081815260408083206001600160a01b038516845290915281205460ff1615612a1b576000838152602081815260408083206001600160a01b038616808552925280832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016905551339286917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a4506001610aff565b6000611376836001600160a01b038416612d37565b6000826000018281548110612b0557612b05613baa565b9060005260206000200154905092915050565b6000612b2d6001600160a01b03841683612e2a565b90508051600014158015612b52575080806020019051810190612b509190613bd9565b155b15610bc7576040517f5274afe70000000000000000000000000000000000000000000000000000000081526001600160a01b0384166004820152602401611a5a565b606081471015612bd2576040517fcd786059000000000000000000000000000000000000000000000000000000008152306004820152602401611a5a565b600080856001600160a01b03168486604051612bee9190613bf6565b60006040518083038185875af1925050503d8060008114612c2b576040519150601f19603f3d011682016040523d82523d6000602084013e612c30565b606091505b5091509150612c40868383612e38565b9695505050505050565b7fffffffffffffffffffffffff11111111111111111111111111111111111111126001600160a01b03821601612cac576040517f7f523fe800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b806001600160a01b03163b600003611080576040517f7f523fe800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000818152600183016020526040812054612a1b57508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155610aff565b60008181526001830160205260408120548015612e20576000612d5b600183613a7a565b8554909150600090612d6f90600190613a7a565b9050808214612dd4576000866000018281548110612d8f57612d8f613baa565b9060005260206000200154905080876000018481548110612db257612db2613baa565b6000918252602080832090910192909255918252600188019052604090208390555b8554869080612de557612de5613c12565b600190038181906000526020600020016000905590558560010160008681526020019081526020016000206000905560019350505050610aff565b6000915050610aff565b606061137683836000612b94565b606082612e4d57612e4882612ead565b611376565b8151158015612e6457506001600160a01b0384163b155b15612ea6576040517f9996b3150000000000000000000000000000000000000000000000000000000081526001600160a01b0385166004820152602401611a5a565b5080611376565b805115612ebd5780518082602001fd5b6040517f1425ea4200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600060208284031215612f0157600080fd5b81357fffffffff000000000000000000000000000000000000000000000000000000008116811461137657600080fd5b600060208284031215612f4357600080fd5b5035919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b60058110612fb0577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b9052565b60208101610aff8284612f79565b6001600160a01b038116811461108057600080fd5b80356118a181612fc2565b60008060408385031215612ff557600080fd5b823561300081612fc2565b9150602083013561301081612fc2565b809150509250929050565b60008060006060848603121561303057600080fd5b8335925060208401359150604084013561304981612fc2565b809150509250925092565b60006020828403121561306657600080fd5b813561137681612fc2565b6000806040838503121561308457600080fd5b82359150602083013561301081612fc2565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051610120810167ffffffffffffffff811182821017156130e9576130e9613096565b60405290565b60405160a0810167ffffffffffffffff811182821017156130e9576130e9613096565b6040516101e0810167ffffffffffffffff811182821017156130e9576130e9613096565b604051610180810167ffffffffffffffff811182821017156130e9576130e9613096565b604051601f8201601f1916810167ffffffffffffffff8111828210171561318357613183613096565b604052919050565b600067ffffffffffffffff8211156131a5576131a5613096565b50601f01601f191660200190565b600082601f8301126131c457600080fd5b81356131d76131d28261318b565b61315a565b8181528460208386010111156131ec57600080fd5b816020850160208301376000918101602001919091529392505050565b6000806040838503121561321c57600080fd5b823567ffffffffffffffff81111561323357600080fd5b61323f858286016131b3565b925050602083013561301081612fc2565b63ffffffff8116811461108057600080fd5b80356118a181613250565b801515811461108057600080fd5b80356118a18161326d565b6000610120828403121561329957600080fd5b6132a16130c5565b90506132ac82613262565b81526132ba60208301612fd7565b60208201526132cb60408301612fd7565b60408201526132dc60608301612fd7565b60608201526132ed60808301612fd7565b608082015260a082013560a082015260c082013560c082015261331260e0830161327b565b60e082015261010080830135818301525092915050565b6000610120828403121561333c57600080fd5b6113768383613286565b60006020828403121561335857600080fd5b813567ffffffffffffffff81111561336f57600080fd5b61337b848285016131b3565b949350505050565b60005b8381101561339e578181015183820152602001613386565b50506000910152565b600081518084526133bf816020860160208601613383565b601f01601f19169290920160200192915050565b602081526133ea60208201835163ffffffff169052565b60006020830151613403604084018263ffffffff169052565b5060408301516001600160a01b03811660608401525060608301516001600160a01b03811660808401525060808301516001600160a01b03811660a08401525060a08301516001600160a01b03811660c08401525060c083015160e08381019190915283015161010080840191909152830151610120808401919091528301516101408084019190915283015161016080840191909152830151610180808401919091528301516101a06134c1818501836001600160a01b03169052565b8401516101c0848101919091528401516101e080850152905061337b6102008401826133a7565b608081016134f68287612f79565b64ffffffffff8516602083015265ffffffffffff841660408301526001600160a01b038316606083015295945050505050565b6000806040838503121561353c57600080fd5b823567ffffffffffffffff81111561355357600080fd5b61355f858286016131b3565b95602094909401359450505050565b6000806040838503121561358157600080fd5b50508035926020909101359150565b815163ffffffff168152610180810160208301516135b6602084018263ffffffff169052565b5060408301516135d160408401826001600160a01b03169052565b5060608301516135ec60608401826001600160a01b03169052565b50608083015161360760808401826001600160a01b03169052565b5060a083015161362260a08401826001600160a01b03169052565b5060c083015160c083015260e083015160e0830152610100808401518184015250610120808401516136578285018215159052565b5050610140838101519083015261016092830151929091019190915290565b600080610140838503121561368a57600080fd5b6136948484613286565b915061012083013567ffffffffffffffff808211156136b257600080fd5b9084019060a082870312156136c657600080fd5b6136ce6130ef565b82356136d981612fc2565b8152602083810135908201526040830135828111156136f757600080fd5b613703888286016131b3565b6040830152506060830135606082015260808301358281111561372557600080fd5b613731888286016131b3565b6080830152508093505050509250929050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b80820180821115610aff57610aff613744565b80516118a181613250565b80516118a181612fc2565b600082601f8301126137ad57600080fd5b81516137bb6131d28261318b565b8181528460208386010111156137d057600080fd5b61337b826020830160208701613383565b6000602082840312156137f357600080fd5b815167ffffffffffffffff8082111561380b57600080fd5b908301906101e0828603121561382057600080fd5b613828613112565b61383183613786565b815261383f60208401613786565b602082015261385060408401613791565b604082015261386160608401613791565b606082015261387260808401613791565b608082015261388360a08401613791565b60a082015260c0838101519082015260e0808401519082015261010080840151908201526101208084015190820152610140808401519082015261016080840151908201526101806138d6818501613791565b908201526101a083810151908201526101c080840151838111156138f957600080fd5b6139058882870161379c565b918301919091525095945050505050565b60208152600061137660208301846133a7565b80516118a18161326d565b6000610180828403121561394757600080fd5b61394f613136565b61395883613786565b815261396660208401613786565b602082015261397760408401613791565b604082015261398860608401613791565b606082015261399960808401613791565b60808201526139aa60a08401613791565b60a082015260c083015160c082015260e083015160e08201526101008084015181830152506101206139dd818501613929565b908201526101408381015190820152610160928301519281019290925250919050565b8082018281126000831280158216821582161715613a2057613a20613744565b505092915050565b8082028115828204841417610aff57610aff613744565b600082613a75577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b81810381811115610aff57610aff613744565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203613abe57613abe613744565b5060010190565b60e081526000613ad860e083018a6133a7565b63ffffffff989098166020830152506001600160a01b039586166040820152939094166060840152608083019190915260a082015290151560c090910152919050565b6001600160a01b0384168152826020820152606060408201526000613b4360608301846133a7565b95945050505050565b80516020808301519190811015613b8b577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8160200360031b1b821691505b50919050565b600060208284031215613ba357600080fd5b5051919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b600060208284031215613beb57600080fd5b81516113768161326d565b60008251613c08818460208701613383565b9190910192915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fdfea2646970667358221220fef42b85b97e95ca087836390d97d99307ec60b38cd20d26ea0f113c18a0660d64736f6c63430008180033","runtime-code":"0x6080604052600436106102fd5760003560e01c806391ad50391161018f578063b13aa2d6116100e1578063ca15c8731161008a578063dcf844a711610064578063dcf844a714610a50578063df36bb1314610a7d578063e00a83e014610a9357600080fd5b8063ca15c873146109dc578063ccc57490146109fc578063d547741f14610a3057600080fd5b8063bfc7c607116100bb578063bfc7c6071461091c578063c63ff8dd1461092f578063c79371b11461094f57600080fd5b8063b13aa2d6146108c5578063b250fe6b146108e5578063bf333f2c1461090557600080fd5b8063a3ec191a11610143578063ac11fb1a1161011d578063ac11fb1a14610844578063add98c7014610871578063affed0e01461089157600080fd5b8063a3ec191a146107f0578063a5bbe22b14610607578063aa9641ab1461082457600080fd5b8063926d7d7f11610174578063926d7d7f146107945780639c9545f0146107c8578063a217fddf146107db57600080fd5b806391ad5039146106d057806391d148541461075057600080fd5b806341fcb6121161025357806363787e52116101fc578063886d36ff116101d6578063886d36ff146106655780638f0d6f17146106855780639010d07c1461069857600080fd5b806363787e521461058c578063820688d5146106075780638379a24f1461061d57600080fd5b80635960ccf21161022d5780635960ccf21461050b5780635aa6ccba1461053f5780635eb7d9461461056c57600080fd5b806341fcb612146104c257806345851694146104e257806358f85880146104f557600080fd5b806318e4357d116102b5578063295710ff1161028f578063295710ff146104555780632f2ff15d1461048257806336568abe146104a257600080fd5b806318e4357d146103ee578063190da5951461040e578063248a9ca31461042557600080fd5b8063051287bc116102e6578063051287bc1461037957806306f333f2146103b65780630f5f6ed7146103d857600080fd5b806301ffc9a71461030257806303ed0ee514610337575b600080fd5b34801561030e57600080fd5b5061032261031d366004612eef565b610aa9565b60405190151581526020015b60405180910390f35b34801561034357600080fd5b5061036b7f043c983c49d46f0e102151eaf8085d4a2e6571d5df2d47b013f39bddfd4a639d81565b60405190815260200161032e565b34801561038557600080fd5b506103a9610394366004612f31565b60009081526005602052604090205460ff1690565b60405161032e9190612fb4565b3480156103c257600080fd5b506103d66103d1366004612fe2565b610b05565b005b3480156103e457600080fd5b5061036b61271081565b3480156103fa57600080fd5b506103d661040936600461301b565b610bcc565b34801561041a57600080fd5b5061036b62093a8081565b34801561043157600080fd5b5061036b610440366004612f31565b60009081526020819052604090206001015490565b34801561046157600080fd5b5061036b610470366004613054565b60076020526000908152604090205481565b34801561048e57600080fd5b506103d661049d366004613071565b610d39565b3480156104ae57600080fd5b506103d66104bd366004613071565b610d64565b3480156104ce57600080fd5b506103d66104dd366004613209565b610db0565b6103d66104f0366004613329565b611026565b34801561050157600080fd5b5061036b60025481565b34801561051757600080fd5b5061036b7fdb9556138406326f00296e13ea2ad7db24ba82381212d816b1a40c23b466b32781565b34801561054b57600080fd5b5061055f61055a366004613346565b611083565b60405161032e91906133d3565b34801561057857600080fd5b506103d6610587366004613346565b611149565b34801561059857600080fd5b506105f76105a7366004612f31565b60056020526000908152604090205460ff811690610100810464ffffffffff16906601000000000000810465ffffffffffff16906c0100000000000000000000000090046001600160a01b031684565b60405161032e94939291906134e8565b34801561061357600080fd5b5061036b61070881565b34801561062957600080fd5b50610322610638366004612f31565b6000908152600660205260409020546c0100000000000000000000000090046001600160a01b0316151590565b34801561067157600080fd5b506103d6610680366004613529565b61133e565b6103d6610693366004613346565b611354565b3480156106a457600080fd5b506106b86106b336600461356e565b61135e565b6040516001600160a01b03909116815260200161032e565b3480156106dc57600080fd5b506107246106eb366004612f31565b600090815260056020526040902054610100810464ffffffffff16916c010000000000000000000000009091046001600160a01b031690565b604080516bffffffffffffffffffffffff90931683526001600160a01b0390911660208301520161032e565b34801561075c57600080fd5b5061032261076b366004613071565b6000918252602082815260408084206001600160a01b0393909316845291905290205460ff1690565b3480156107a057600080fd5b5061036b7fe2b7fb3b832174769106daebcfd6d1970523240dda11281102db9363b83b0dc481565b6103d66107d6366004613209565b61137d565b3480156107e757600080fd5b5061036b600081565b3480156107fc57600080fd5b5061036b7f000000000000000000000000000000000000000000000000000000000000000081565b34801561083057600080fd5b5061032261083f366004613071565b611603565b34801561085057600080fd5b5061086461085f366004613346565b6116ee565b60405161032e9190613590565b34801561087d57600080fd5b506103d661088c366004612f31565b6118a6565b34801561089d57600080fd5b5061036b7f000000000000000000000000000000000000000000000000000000000000000081565b3480156108d157600080fd5b506103d66108e0366004612f31565b6119c8565b3480156108f157600080fd5b506103d6610900366004612f31565b611aaa565b34801561091157600080fd5b5061036b620f424081565b6103d661092a366004613676565b611b12565b34801561093b57600080fd5b506103d661094a366004613346565b611d94565b34801561095b57600080fd5b506109ae61096a366004612f31565b60066020526000908152604090205465ffffffffffff8082169166010000000000008104909116906c0100000000000000000000000090046001600160a01b031683565b6040805165ffffffffffff94851681529390921660208401526001600160a01b03169082015260600161032e565b3480156109e857600080fd5b5061036b6109f7366004612f31565b611d9f565b348015610a0857600080fd5b5061036b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f5581565b348015610a3c57600080fd5b506103d6610a4b366004613071565b611db6565b348015610a5c57600080fd5b5061036b610a6b366004613054565b60036020526000908152604090205481565b348015610a8957600080fd5b5061036b61ffff81565b348015610a9f57600080fd5b5061036b60045481565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f5a05180f000000000000000000000000000000000000000000000000000000001480610aff5750610aff82611ddb565b92915050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f55610b2f81611e72565b6001600160a01b03831660009081526003602052604081205490819003610b565750505050565b6001600160a01b038416600081815260036020526040812055610b7a908483611e7c565b604080516001600160a01b038087168252851660208201529081018290527f244e51bc38c1452fa8aaf487bcb4bca36c2baa3a5fbdb776b1eabd8dc6d277cd9060600160405180910390a1505b505050565b7fe2b7fb3b832174769106daebcfd6d1970523240dda11281102db9363b83b0dc4610bf681611e72565b600160008581526005602052604090205460ff166004811115610c1b57610c1b612f4a565b14610c52576040517f4145817200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600084815260056020908152604091829020805460027fffffffffffffffffffffffffffffffffffffffff0000000000000000000000009091166101004264ffffffffff16027fffffffffffffffffffffffffffffffffffffffff000000000000ffffffffffff161766010000000000004365ffffffffffff160217176bffffffffffffffffffffffff166c010000000000000000000000006001600160a01b0387169081029190911790915582518681529251909287927f4ac8af8a2cd87193d64dfc7a3b8d9923b714ec528b18725d080aa1299be0c5e492918290030190a350505050565b600082815260208190526040902060010154610d5481611e72565b610d5e8383611f9f565b50505050565b6001600160a01b0381163314610da6576040517f6697b23200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610bc78282611fd4565b815160208301206000610dc284611083565b9050600260008381526005602052604090205460ff166004811115610de957610de9612f4a565b14610e20576040517f4145817200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600160a01b038316610e5d576000828152600560205260409020546c0100000000000000000000000090046001600160a01b03169250610ebd565b6000828152600560205260409020546c0100000000000000000000000090046001600160a01b03163314610ebd576040517f4af43a9000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008281526005602052604090205461070890610100900464ffffffffff90811642031611610f18576040517f1992d0bd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600082815260056020526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016600317905561010081015115610f925761010081015160808201516001600160a01b031660009081526003602052604081208054909190610f8c908490613773565b90915550505b608081015160c0820151610fb06001600160a01b0383168683611e7c565b6000848152600560209081526040918290205482516001600160a01b038681168252928101859052888316936c010000000000000000000000009092049092169187917f582211c35a2139ac3bbaac74663c6a1f56c6cbb658b41fe11fd45a82074ac678910160405180910390a4505050505050565b611080816040518060a0016040528060006001600160a01b03168152602001600081526020016040518060200160405280600081525081526020016000815260200160405180602001604052806000815250815250611b12565b50565b611135604051806101e00160405280600063ffffffff168152602001600063ffffffff16815260200160006001600160a01b0316815260200160006001600160a01b0316815260200160006001600160a01b0316815260200160006001600160a01b0316815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160006001600160a01b0316815260200160008152602001606081525090565b81806020019051810190610aff91906137e1565b80516020820120600061115b83611083565b9050600160008381526005602052604090205460ff16600481111561118257611182612f4a565b146111b9576040517f4145817200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b3360009081527fd2043bf65931af3dbecf60d0db8f40e4160406d7beb00522f4200cf4944a1eb8602052604090205460ff161561123357806101400151421161122e576040517fe15ff9ea00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61127f565b62093a808161014001516112479190613773565b421161127f576040517fe15ff9ea00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008281526005602052604080822080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166004179055820151608083015161010084015160c0850151929391926112d89190613773565b90506112ee6001600160a01b0383168483611e7c565b604080516001600160a01b0384811682526020820184905285169187917fb4c55c0c9bc613519b920e88748090150b890a875d307f21bea7d4fb2e8bc958910160405180910390a3505050505050565b61135082805190602001208233610bcc565b5050565b611080813361137d565b60008281526001602052604081206113769083612001565b9392505050565b81516020830120600061138f84611083565b905061139c81838561200d565b604080516060808201835265ffffffffffff438116835242811660208085019182526001600160a01b0389811686880181815260008b815260068552899020975188549551915184166c01000000000000000000000000026bffffffffffffffffffffffff9288166601000000000000027fffffffffffffffffffffffffffffffffffffffff00000000000000000000000090971691909716179490941793909316939093179094558583015160a08088015160e08901516101208a01518a516080808d015160c0808f01518e5163ffffffff9095168552918b169c84019c909c52858a169c83019c909c529881019a909a52968901819052918801869052919691959094938716929189917ff8ae392d784b1ea5e8881bfa586d81abf07ef4f1e2fc75f7fe51c90f05199a5c910160405180910390a47fffffffffffffffffffffffff11111111111111111111111111111111111111126001600160a01b0384160161157957801561153b576040517f2598ad2e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b813414611574576040517f81de0bf300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6115c7565b8034146115b2576040517f81de0bf300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6115c76001600160a01b0384163386856121aa565b6101c085015151156115e9576115e4848484886101c00151612226565b6115f9565b34156115f9576115f98434612385565b5050505050505050565b6000600260008481526005602052604090205460ff16600481111561162a5761162a612f4a565b14611661576040517f4145817200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000838152600560205260409020546001600160a01b038381166c0100000000000000000000000090920416146116c4576040517f4af43a9000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b505060009081526005602052604090205461070861010090910464ffffffffff9081164203161190565b6040805161018081018252600080825260208201819052818301819052606082018190526080820181905260a0820181905260c0820181905260e0820181905261010082018190526101208201819052610140820181905261016082015290517f5aa6ccba0000000000000000000000000000000000000000000000000000000081523090635aa6ccba90611787908590600401613916565b600060405180830381865afa9250505080156117c557506040513d6000823e601f3d908101601f191682016040526117c291908101906137e1565b60015b6117dd5781806020019051810190610aff9190613934565b604051806101800160405280826000015163ffffffff168152602001826020015163ffffffff16815260200182604001516001600160a01b0316815260200182606001516001600160a01b0316815260200182608001516001600160a01b031681526020018260a001516001600160a01b031681526020018260c0015181526020018260e001518152602001826101000151815260200182610120015160001415151581526020018261014001518152602001826101600151815250915050919050565b919050565b7f043c983c49d46f0e102151eaf8085d4a2e6571d5df2d47b013f39bddfd4a639d6118d081611e72565b600260008381526005602052604090205460ff1660048111156118f5576118f5612f4a565b1461192c576040517f4145817200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008281526005602052604090205461070890610100900464ffffffffff9081164203161115611988576040517f3e908aac00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000828152600560205260408082206001905551339184917f0695cf1d39b3055dcd0fe02d8b47eaf0d5a13e1996de925de59d0ef9b7f7fad49190a35050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f556119f281611e72565b612710821115611a63576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f6e657746656552617465203e206d61780000000000000000000000000000000060448201526064015b60405180910390fd5b600280549083905560408051828152602081018590527f14914da2bf76024616fbe1859783fcd4dbddcb179b1f3a854949fbf920dcb95791015b60405180910390a1505050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f55611ad481611e72565b600480549083905560408051828152602081018590527f5cf09b12f3f56b4c564d51b25b40360af6d795198adb61ae0806a36c294323fa9101611a9d565b6000816020015142611b249190613a00565b9050611b3183838361244e565b6000611b4584606001518560a001516126d3565b90506000806002541115611b7257620f424060025483611b659190613a28565b611b6f9190613a3f565b90505b611b7c8183613a7a565b91506000604051806101e001604052804663ffffffff168152602001876000015163ffffffff16815260200187602001516001600160a01b0316815260200187604001516001600160a01b0316815260200187606001516001600160a01b0316815260200187608001516001600160a01b031681526020018481526020018760c0015181526020018381526020018660600151815260200187610100015181526020016007600089602001516001600160a01b03166001600160a01b031681526020019081526020016000206000815480929190611c5990613a8d565b91905055815260200186600001516001600160a01b031681526020018581526020018660800151815250604051602001611c9391906133d3565b60408051808303601f1901815282825280516020808301919091206000818152600583529390932080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016600117905589015189516060808c015160808d015160c08e0151928d015195985095966001600160a01b039094169587957f120ea0364f36cdac7983bcfdd55270ca09d7f9b314a2ebc425a3b01ab1d6403a95611d47958b95909493928e9290151590613ac5565b60405180910390a3807f3120e2bb59c86aca6890191a589a96af3662838efa374fbdcdf4c95bfe4a6c0e8760400151604051611d839190613916565b60405180910390a250505050505050565b611080816000610db0565b6000818152600160205260408120610aff906128b4565b600082815260208190526040902060010154611dd181611e72565b610d5e8383611fd4565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f7965db0b000000000000000000000000000000000000000000000000000000001480610aff57507f01ffc9a7000000000000000000000000000000000000000000000000000000007fffffffff00000000000000000000000000000000000000000000000000000000831614610aff565b61108081336128be565b306001600160a01b03831603611e9157505050565b80600003611e9e57505050565b7fffffffffffffffffffffffff11111111111111111111111111111111111111126001600160a01b03841601611f8b576000826001600160a01b03168260405160006040518083038185875af1925050503d8060008114611f1b576040519150601f19603f3d011682016040523d82523d6000602084013e611f20565b606091505b5050905080610d5e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f455448207472616e73666572206661696c6564000000000000000000000000006044820152606401611a5a565b610bc76001600160a01b038416838361292a565b600080611fac848461295b565b90508015611376576000848152600160205260409020611fcc9084612a23565b509392505050565b600080611fe18484612a38565b90508015611376576000848152600160205260409020611fcc9084612ad9565b60006113768383612aee565b6001600160a01b03811661204d576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000828152600660205260409020546c0100000000000000000000000090046001600160a01b0316156120ac576040517fbef7bb7d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b46836020015163ffffffff16146120ef576040517f7029fdf900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b82610140015142111561212e576040517f559895a300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6101808301516001600160a01b0316158015906121625750806001600160a01b03168361018001516001600160a01b031614155b80156121735750826101a001514211155b15610bc7576040517f14be123200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040516001600160a01b038481166024830152838116604483015260648201839052610d5e9186918216906323b872dd906084015b604051602081830303815290604052915060e01b6020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8381831617835250505050612b18565b600083838360405160240161223d93929190613b1b565b60408051601f198184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f461e0c2100000000000000000000000000000000000000000000000000000000179052905060006122a4868334612b94565b905080516000036122e1576040517f1a95ad2600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b805160201461231c576040517ff3725cca00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f461e0c210000000000000000000000000000000000000000000000000000000061234682613b4c565b1461237d576040517ff3725cca00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b505050505050565b804710156123c1576040517fcd786059000000000000000000000000000000000000000000000000000000008152306004820152602401611a5a565b6000826001600160a01b03168260405160006040518083038185875af1925050503d806000811461240e576040519150601f19603f3d011682016040523d82523d6000602084013e612413565b606091505b5050905080610bc7576040517f1425ea4200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b46836000015163ffffffff1603612491576040517f7029fdf900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60a083015115806124a4575060c0830151155b156124db576040517fe38820c800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60208301516001600160a01b03161580612500575060408301516001600160a01b0316155b15612537576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60608301516001600160a01b0316158061255c575060808301516001600160a01b0316155b15612593576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61259f61070842613773565b83610100015110156125dd576040517f04b7fcc800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61ffff826080015151111561261e576040517ffbe24d4900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b606082015115801590612651575060808301516001600160a01b031673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee145b15612688576040517f2598ad2e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008113158061269c575082610100015181135b15610bc7576040517f352807b900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60007fffffffffffffffffffffffff11111111111111111111111111111111111111126001600160a01b038416016127455734821461273e576040517f81de0bf300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5034610aff565b612757836001600160a01b0316612c4a565b341561278f576040517f81de0bf300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201526001600160a01b038416906370a0823190602401602060405180830381865afa1580156127ec573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128109190613b91565b90506128276001600160a01b0384163330856121aa565b6040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015281906001600160a01b038516906370a0823190602401602060405180830381865afa158015612886573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128aa9190613b91565b6113769190613a7a565b6000610aff825490565b6000828152602081815260408083206001600160a01b038516845290915290205460ff16611350576040517fe2517d3f0000000000000000000000000000000000000000000000000000000081526001600160a01b038216600482015260248101839052604401611a5a565b6040516001600160a01b03838116602483015260448201839052610bc791859182169063a9059cbb906064016121df565b6000828152602081815260408083206001600160a01b038516845290915281205460ff16612a1b576000838152602081815260408083206001600160a01b0386168452909152902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790556129d33390565b6001600160a01b0316826001600160a01b0316847f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a4506001610aff565b506000610aff565b6000611376836001600160a01b038416612cf0565b6000828152602081815260408083206001600160a01b038516845290915281205460ff1615612a1b576000838152602081815260408083206001600160a01b038616808552925280832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016905551339286917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a4506001610aff565b6000611376836001600160a01b038416612d37565b6000826000018281548110612b0557612b05613baa565b9060005260206000200154905092915050565b6000612b2d6001600160a01b03841683612e2a565b90508051600014158015612b52575080806020019051810190612b509190613bd9565b155b15610bc7576040517f5274afe70000000000000000000000000000000000000000000000000000000081526001600160a01b0384166004820152602401611a5a565b606081471015612bd2576040517fcd786059000000000000000000000000000000000000000000000000000000008152306004820152602401611a5a565b600080856001600160a01b03168486604051612bee9190613bf6565b60006040518083038185875af1925050503d8060008114612c2b576040519150601f19603f3d011682016040523d82523d6000602084013e612c30565b606091505b5091509150612c40868383612e38565b9695505050505050565b7fffffffffffffffffffffffff11111111111111111111111111111111111111126001600160a01b03821601612cac576040517f7f523fe800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b806001600160a01b03163b600003611080576040517f7f523fe800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000818152600183016020526040812054612a1b57508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155610aff565b60008181526001830160205260408120548015612e20576000612d5b600183613a7a565b8554909150600090612d6f90600190613a7a565b9050808214612dd4576000866000018281548110612d8f57612d8f613baa565b9060005260206000200154905080876000018481548110612db257612db2613baa565b6000918252602080832090910192909255918252600188019052604090208390555b8554869080612de557612de5613c12565b600190038181906000526020600020016000905590558560010160008681526020019081526020016000206000905560019350505050610aff565b6000915050610aff565b606061137683836000612b94565b606082612e4d57612e4882612ead565b611376565b8151158015612e6457506001600160a01b0384163b155b15612ea6576040517f9996b3150000000000000000000000000000000000000000000000000000000081526001600160a01b0385166004820152602401611a5a565b5080611376565b805115612ebd5780518082602001fd5b6040517f1425ea4200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600060208284031215612f0157600080fd5b81357fffffffff000000000000000000000000000000000000000000000000000000008116811461137657600080fd5b600060208284031215612f4357600080fd5b5035919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b60058110612fb0577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b9052565b60208101610aff8284612f79565b6001600160a01b038116811461108057600080fd5b80356118a181612fc2565b60008060408385031215612ff557600080fd5b823561300081612fc2565b9150602083013561301081612fc2565b809150509250929050565b60008060006060848603121561303057600080fd5b8335925060208401359150604084013561304981612fc2565b809150509250925092565b60006020828403121561306657600080fd5b813561137681612fc2565b6000806040838503121561308457600080fd5b82359150602083013561301081612fc2565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051610120810167ffffffffffffffff811182821017156130e9576130e9613096565b60405290565b60405160a0810167ffffffffffffffff811182821017156130e9576130e9613096565b6040516101e0810167ffffffffffffffff811182821017156130e9576130e9613096565b604051610180810167ffffffffffffffff811182821017156130e9576130e9613096565b604051601f8201601f1916810167ffffffffffffffff8111828210171561318357613183613096565b604052919050565b600067ffffffffffffffff8211156131a5576131a5613096565b50601f01601f191660200190565b600082601f8301126131c457600080fd5b81356131d76131d28261318b565b61315a565b8181528460208386010111156131ec57600080fd5b816020850160208301376000918101602001919091529392505050565b6000806040838503121561321c57600080fd5b823567ffffffffffffffff81111561323357600080fd5b61323f858286016131b3565b925050602083013561301081612fc2565b63ffffffff8116811461108057600080fd5b80356118a181613250565b801515811461108057600080fd5b80356118a18161326d565b6000610120828403121561329957600080fd5b6132a16130c5565b90506132ac82613262565b81526132ba60208301612fd7565b60208201526132cb60408301612fd7565b60408201526132dc60608301612fd7565b60608201526132ed60808301612fd7565b608082015260a082013560a082015260c082013560c082015261331260e0830161327b565b60e082015261010080830135818301525092915050565b6000610120828403121561333c57600080fd5b6113768383613286565b60006020828403121561335857600080fd5b813567ffffffffffffffff81111561336f57600080fd5b61337b848285016131b3565b949350505050565b60005b8381101561339e578181015183820152602001613386565b50506000910152565b600081518084526133bf816020860160208601613383565b601f01601f19169290920160200192915050565b602081526133ea60208201835163ffffffff169052565b60006020830151613403604084018263ffffffff169052565b5060408301516001600160a01b03811660608401525060608301516001600160a01b03811660808401525060808301516001600160a01b03811660a08401525060a08301516001600160a01b03811660c08401525060c083015160e08381019190915283015161010080840191909152830151610120808401919091528301516101408084019190915283015161016080840191909152830151610180808401919091528301516101a06134c1818501836001600160a01b03169052565b8401516101c0848101919091528401516101e080850152905061337b6102008401826133a7565b608081016134f68287612f79565b64ffffffffff8516602083015265ffffffffffff841660408301526001600160a01b038316606083015295945050505050565b6000806040838503121561353c57600080fd5b823567ffffffffffffffff81111561355357600080fd5b61355f858286016131b3565b95602094909401359450505050565b6000806040838503121561358157600080fd5b50508035926020909101359150565b815163ffffffff168152610180810160208301516135b6602084018263ffffffff169052565b5060408301516135d160408401826001600160a01b03169052565b5060608301516135ec60608401826001600160a01b03169052565b50608083015161360760808401826001600160a01b03169052565b5060a083015161362260a08401826001600160a01b03169052565b5060c083015160c083015260e083015160e0830152610100808401518184015250610120808401516136578285018215159052565b5050610140838101519083015261016092830151929091019190915290565b600080610140838503121561368a57600080fd5b6136948484613286565b915061012083013567ffffffffffffffff808211156136b257600080fd5b9084019060a082870312156136c657600080fd5b6136ce6130ef565b82356136d981612fc2565b8152602083810135908201526040830135828111156136f757600080fd5b613703888286016131b3565b6040830152506060830135606082015260808301358281111561372557600080fd5b613731888286016131b3565b6080830152508093505050509250929050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b80820180821115610aff57610aff613744565b80516118a181613250565b80516118a181612fc2565b600082601f8301126137ad57600080fd5b81516137bb6131d28261318b565b8181528460208386010111156137d057600080fd5b61337b826020830160208701613383565b6000602082840312156137f357600080fd5b815167ffffffffffffffff8082111561380b57600080fd5b908301906101e0828603121561382057600080fd5b613828613112565b61383183613786565b815261383f60208401613786565b602082015261385060408401613791565b604082015261386160608401613791565b606082015261387260808401613791565b608082015261388360a08401613791565b60a082015260c0838101519082015260e0808401519082015261010080840151908201526101208084015190820152610140808401519082015261016080840151908201526101806138d6818501613791565b908201526101a083810151908201526101c080840151838111156138f957600080fd5b6139058882870161379c565b918301919091525095945050505050565b60208152600061137660208301846133a7565b80516118a18161326d565b6000610180828403121561394757600080fd5b61394f613136565b61395883613786565b815261396660208401613786565b602082015261397760408401613791565b604082015261398860608401613791565b606082015261399960808401613791565b60808201526139aa60a08401613791565b60a082015260c083015160c082015260e083015160e08201526101008084015181830152506101206139dd818501613929565b908201526101408381015190820152610160928301519281019290925250919050565b8082018281126000831280158216821582161715613a2057613a20613744565b505092915050565b8082028115828204841417610aff57610aff613744565b600082613a75577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b81810381811115610aff57610aff613744565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203613abe57613abe613744565b5060010190565b60e081526000613ad860e083018a6133a7565b63ffffffff989098166020830152506001600160a01b039586166040820152939094166060840152608083019190915260a082015290151560c090910152919050565b6001600160a01b0384168152826020820152606060408201526000613b4360608301846133a7565b95945050505050565b80516020808301519190811015613b8b577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8160200360031b1b821691505b50919050565b600060208284031215613ba357600080fd5b5051919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b600060208284031215613beb57600080fd5b81516113768161326d565b60008251613c08818460208701613383565b9190910192915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fdfea2646970667358221220fef42b85b97e95ca087836390d97d99307ec60b38cd20d26ea0f113c18a0660d64736f6c63430008180033","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.24 ^0.8.0 ^0.8.20;\n\n// contracts/interfaces/IAdmin.sol\n\ninterface IAdmin {\n // ============ Events ============\n\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n event ChainGasAmountUpdated(uint256 oldChainGasAmount, uint256 newChainGasAmount);\n\n // ============ Methods ============\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n\n function setChainGasAmount(uint256 newChainGasAmount) external;\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IFastBridgeRecipient.sol\n\ninterface IFastBridgeRecipient {\n function fastBridgeTransferReceived(\n address token,\n uint256 amount,\n bytes memory callParams\n )\n external\n payable\n returns (bytes4);\n}\n\n// contracts/interfaces/IFastBridgeV2Errors.sol\n\ninterface IFastBridgeV2Errors {\n error AmountIncorrect();\n error CallParamsLengthAboveMax();\n error ChainIncorrect();\n error ExclusivityParamsIncorrect();\n error MsgValueIncorrect();\n error NativeTokenCallValueNotSupported();\n error SenderIncorrect();\n error StatusIncorrect();\n error ZeroAddress();\n\n error RecipientIncorrectReturnValue();\n error RecipientNoReturnValue();\n\n error DeadlineExceeded();\n error DeadlineNotExceeded();\n error DeadlineTooShort();\n error DisputePeriodNotPassed();\n error DisputePeriodPassed();\n error ExclusivityPeriodNotPassed();\n\n error TransactionRelayed();\n}\n\n// contracts/libs/Errors.sol\n\nerror DeadlineExceeded();\nerror DeadlineNotExceeded();\nerror DeadlineTooShort();\nerror InsufficientOutputAmount();\n\nerror MsgValueIncorrect();\nerror PoolNotFound();\nerror TokenAddressMismatch();\nerror TokenNotContract();\nerror TokenNotETH();\nerror TokensIdentical();\n\nerror ChainIncorrect();\nerror AmountIncorrect();\nerror ZeroAddress();\n\nerror DisputePeriodNotPassed();\nerror DisputePeriodPassed();\nerror SenderIncorrect();\nerror StatusIncorrect();\nerror TransactionIdIncorrect();\nerror TransactionRelayed();\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// contracts/interfaces/IFastBridgeV2.sol\n\ninterface IFastBridgeV2 is IFastBridge {\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n struct BridgeTxDetails {\n BridgeStatus status;\n uint40 proofBlockTimestamp;\n uint48 proofBlockNumber;\n address proofRelayer;\n }\n\n struct BridgeRelay {\n uint48 blockNumber;\n uint48 blockTimestamp;\n address relayer;\n }\n\n /// @notice New params introduced in the FastBridgeV2.\n /// We are passing fields from the older BridgeParams struct outside of this struct\n /// for backwards compatibility.\n /// Note: quoteRelayer and quoteExclusivitySeconds are either both zero (indicating no exclusivity)\n /// or both non-zero (indicating exclusivity for the given period).\n /// Note: callValue \u003e 0 can NOT be used with destToken = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE (ETH_ADDRESS)\n /// @param quoteRelayer Relayer that provided the quote for the transaction\n /// @param quoteExclusivitySeconds Period of time the quote relayer is guaranteed exclusivity after user's deposit\n /// @param quoteId Unique quote identifier used for tracking the quote\n /// @param callValue ETH value to send to the recipient (if any)\n /// @param callParams Parameters for the arbitrary call to the destination recipient (if any)\n struct BridgeParamsV2 {\n address quoteRelayer;\n int256 quoteExclusivitySeconds;\n bytes quoteId;\n uint256 callValue;\n bytes callParams;\n }\n\n /// @notice Updated bridge transaction struct to include parameters introduced in FastBridgeV2.\n /// Note: only `exclusivityRelayer` can fill such a transaction until `exclusivityEndTime`.\n /// TODO: consider changing the encoding scheme to prevent spending extra gas on decoding.\n struct BridgeTransactionV2 {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n uint256 callValue; // ETH value to send to the recipient (if any) - replaces V1's sendChainGas flag\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n address exclusivityRelayer;\n uint256 exclusivityEndTime;\n bytes callParams;\n }\n\n event BridgeQuoteDetails(bytes32 indexed transactionId, bytes quoteId);\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability\n /// to provide temporary exclusivity fill rights for the quote relayer.\n /// @param params The parameters required to bridge\n /// @param paramsV2 The parameters for exclusivity fill rights (optional, can be left empty)\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function relay(bytes memory request, address relayer) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param transactionId The transaction id associated with the encoded bridge transaction to prove\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital.\n /// @notice Can only send funds to the relayer address on the proof.\n /// @param request The encoded bridge transaction to claim on origin chain\n function claim(bytes memory request) external;\n /// @notice Checks if a transaction has been relayed\n /// @param transactionId The ID of the transaction to check\n /// @return True if the transaction has been relayed, false otherwise\n function bridgeRelays(bytes32 transactionId) external view returns (bool);\n\n /// @notice Returns the status of a bridge transaction\n /// @param transactionId The ID of the bridge transaction\n /// @return BridgeStatus Status of the bridge transaction\n function bridgeStatuses(bytes32 transactionId) external view returns (BridgeStatus);\n\n /// @notice Returns the timestamp and relayer of a bridge proof\n /// @param transactionId The ID of the bridge transaction\n /// @return timestamp The timestamp of the bridge proof\n /// @return relayer The relayer address of the bridge proof\n function bridgeProofs(bytes32 transactionId) external view returns (uint96 timestamp, address relayer);\n\n /// @notice Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\n /// @param request The bridge request to decode\n function getBridgeTransactionV2(bytes memory request) external view returns (BridgeTransactionV2 memory);\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// contracts/libs/UniversalToken.sol\n\nlibrary UniversalTokenLib {\n using SafeERC20 for IERC20;\n\n address internal constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Transfers tokens to the given account. Reverts if transfer is not successful.\n /// @dev This might trigger fallback, if ETH is transferred to the contract.\n /// Make sure this can not lead to reentrancy attacks.\n function universalTransfer(address token, address to, uint256 value) internal {\n // Don't do anything, if need to send tokens to this address\n if (to == address(this)) return;\n // Don't do anything, if trying to send zero value\n if (value == 0) return;\n if (token == ETH_ADDRESS) {\n /// @dev Note: this can potentially lead to executing code in `to`.\n // solhint-disable-next-line avoid-low-level-calls\n (bool success,) = to.call{value: value}(\"\");\n require(success, \"ETH transfer failed\");\n } else {\n IERC20(token).safeTransfer(to, value);\n }\n }\n\n /// @notice Issues an infinite allowance to the spender, if the current allowance is insufficient\n /// to spend the given amount.\n function universalApproveInfinity(address token, address spender, uint256 amountToSpend) internal {\n // ETH Chad doesn't require your approval\n if (token == ETH_ADDRESS) return;\n // No-op if allowance is already sufficient\n uint256 allowance = IERC20(token).allowance(address(this), spender);\n if (allowance \u003e= amountToSpend) return;\n // Otherwise, reset approval to 0 and set to max allowance\n if (allowance \u003e 0) IERC20(token).safeDecreaseAllowance(spender, allowance);\n IERC20(token).safeIncreaseAllowance(spender, type(uint256).max);\n }\n\n /// @notice Returns the balance of the given token (or native ETH) for the given account.\n function universalBalanceOf(address token, address account) internal view returns (uint256) {\n if (token == ETH_ADDRESS) {\n return account.balance;\n } else {\n return IERC20(token).balanceOf(account);\n }\n }\n\n /// @dev Checks that token is a contract and not ETH_ADDRESS.\n function assertIsContract(address token) internal view {\n // Check that ETH_ADDRESS was not used (in case this is a predeploy on any of the chains)\n if (token == UniversalTokenLib.ETH_ADDRESS) revert TokenNotContract();\n // Check that token is not an EOA\n if (token.code.length == 0) revert TokenNotContract();\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/Admin.sol\n\ncontract Admin is IAdmin, AccessControlEnumerable {\n using UniversalTokenLib for address;\n\n bytes32 public constant RELAYER_ROLE = keccak256(\"RELAYER_ROLE\");\n bytes32 public constant REFUNDER_ROLE = keccak256(\"REFUNDER_ROLE\");\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n uint256 public constant FEE_BPS = 1e6;\n uint256 public constant FEE_RATE_MAX = 0.01e6; // max 1% on origin amount\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Chain gas amount to forward as rebate if requested\n uint256 public chainGasAmount;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n }\n\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n require(newFeeRate \u003c= FEE_RATE_MAX, \"newFeeRate \u003e max\");\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n token.universalTransfer(recipient, feeAmount);\n emit FeesSwept(token, recipient, feeAmount);\n }\n\n function setChainGasAmount(uint256 newChainGasAmount) external onlyRole(GOVERNOR_ROLE) {\n uint256 oldChainGasAmount = chainGasAmount;\n chainGasAmount = newChainGasAmount;\n emit ChainGasAmountUpdated(oldChainGasAmount, newChainGasAmount);\n }\n}\n\n// contracts/FastBridgeV2.sol\n\n/// @notice FastBridgeV2 is a contract for bridging tokens across chains.\ncontract FastBridgeV2 is Admin, IFastBridgeV2, IFastBridgeV2Errors {\n using SafeERC20 for IERC20;\n using UniversalTokenLib for address;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Delay for a transaction after which it could be permisionlessly refunded\n uint256 public constant REFUND_DELAY = 7 days;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n /// @notice Maximum length of accepted callParams\n uint256 public constant MAX_CALL_PARAMS_LENGTH = 2 ** 16 - 1;\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeTxDetails) public bridgeTxDetails;\n /// @notice Relay details on destination chain\n mapping(bytes32 =\u003e BridgeRelay) public bridgeRelayDetails;\n /// @notice Unique bridge nonces tracked per originSender\n mapping(address =\u003e uint256) public senderNonces;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Replaced by senderNonces\n uint256 public immutable nonce = 0;\n /// @notice the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n bridge({\n params: params,\n paramsV2: BridgeParamsV2({\n quoteRelayer: address(0),\n quoteExclusivitySeconds: 0,\n quoteId: bytes(\"\"),\n callValue: 0,\n callParams: bytes(\"\")\n })\n });\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes memory request) external payable {\n relay({request: request, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes memory request, bytes32 destTxHash) external {\n prove({transactionId: keccak256(request), destTxHash: destTxHash, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridgeV2\n function claim(bytes memory request) external {\n claim({request: request, to: address(0)});\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003e DISPUTE_PERIOD) {\n revert DisputePeriodPassed();\n }\n\n // @dev relayer gets slashed effectively if dest relay has gone thru\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n bridgeTxDetails[transactionId].proofRelayer = address(0);\n bridgeTxDetails[transactionId].proofBlockTimestamp = 0;\n bridgeTxDetails[transactionId].proofBlockNumber = 0;\n\n emit BridgeProofDisputed(transactionId, msg.sender);\n }\n\n /// @inheritdoc IFastBridge\n function refund(bytes memory request) external {\n bytes32 transactionId = keccak256(request);\n\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n\n if (bridgeTxDetails[transactionId].status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n\n if (hasRole(REFUNDER_ROLE, msg.sender)) {\n // Refunder can refund if deadline has passed\n if (block.timestamp \u003c= transaction.deadline) revert DeadlineNotExceeded();\n } else {\n // Permissionless refund is allowed after REFUND_DELAY\n if (block.timestamp \u003c= transaction.deadline + REFUND_DELAY) revert DeadlineNotExceeded();\n }\n\n // if all checks passed, set to REFUNDED status\n bridgeTxDetails[transactionId].status = BridgeStatus.REFUNDED;\n\n // transfer origin collateral back to original sender\n address to = transaction.originSender;\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount + transaction.originFeeAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (bridgeTxDetails[transactionId].proofRelayer != relayer) revert SenderIncorrect();\n return _timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n /// @dev This method is added to achieve backwards compatibility with decoding requests into V1 structs:\n /// - `callValue` is partially reported as a zero/non-zero flag\n /// - `callParams` is ignored\n /// In order to process all kinds of requests use getBridgeTransactionV2 instead.\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory) {\n // Try decoding into V2 struct first. This will revert if V1 struct is passed\n try this.getBridgeTransactionV2(request) returns (BridgeTransactionV2 memory txV2) {\n // Note: we entirely ignore the callParams field, as it was not present in V1\n return BridgeTransaction({\n originChainId: txV2.originChainId,\n destChainId: txV2.destChainId,\n originSender: txV2.originSender,\n destRecipient: txV2.destRecipient,\n originToken: txV2.originToken,\n destToken: txV2.destToken,\n originAmount: txV2.originAmount,\n destAmount: txV2.destAmount,\n originFeeAmount: txV2.originFeeAmount,\n sendChainGas: txV2.callValue != 0,\n deadline: txV2.deadline,\n nonce: txV2.nonce\n });\n } catch {\n // Fallback to V1 struct\n return abi.decode(request, (BridgeTransaction));\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) public payable {\n int256 exclusivityEndTime = int256(block.timestamp) + paramsV2.quoteExclusivitySeconds;\n _validateBridgeParams(params, paramsV2, exclusivityEndTime);\n\n // transfer tokens to bridge contract\n /// @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _takeBridgedUserAsset(params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n\n // set status to requested\n bytes memory request = abi.encode(\n BridgeTransactionV2({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n callValue: paramsV2.callValue,\n deadline: params.deadline,\n nonce: senderNonces[params.sender]++, // increment nonce on every bridge\n exclusivityRelayer: paramsV2.quoteRelayer,\n // We checked exclusivityEndTime to be in range (0 .. params.deadline] above, so can safely cast\n exclusivityEndTime: uint256(exclusivityEndTime),\n callParams: paramsV2.callParams\n })\n );\n bytes32 transactionId = keccak256(request);\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n\n emit BridgeRequested({\n transactionId: transactionId,\n sender: params.sender,\n request: request,\n destChainId: params.dstChainId,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n sendChainGas: paramsV2.callValue != 0\n });\n emit BridgeQuoteDetails(transactionId, paramsV2.quoteId);\n }\n\n /// @inheritdoc IFastBridgeV2\n function relay(bytes memory request, address relayer) public payable {\n bytes32 transactionId = keccak256(request);\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n _validateRelayParams(transaction, transactionId, relayer);\n // mark bridge transaction as relayed\n bridgeRelayDetails[transactionId] =\n BridgeRelay({blockNumber: uint48(block.number), blockTimestamp: uint48(block.timestamp), relayer: relayer});\n\n // transfer tokens to recipient on destination chain and do an arbitrary call if requested\n address to = transaction.destRecipient;\n address token = transaction.destToken;\n uint256 amount = transaction.destAmount;\n uint256 callValue = transaction.callValue;\n\n // Emit the event before any external calls\n emit BridgeRelayed({\n transactionId: transactionId,\n relayer: relayer,\n to: to,\n originChainId: transaction.originChainId,\n originToken: transaction.originToken,\n destToken: token,\n originAmount: transaction.originAmount,\n destAmount: amount,\n chainGasAmount: callValue\n });\n\n // All state changes have been done at this point, can proceed to the external calls.\n // This follows the checks-effects-interactions pattern to mitigate potential reentrancy attacks.\n if (token == UniversalTokenLib.ETH_ADDRESS) {\n // For ETH non-zero callValue is not allowed\n if (callValue != 0) revert NativeTokenCallValueNotSupported();\n // Check that the correct msg.value was sent\n if (msg.value != amount) revert MsgValueIncorrect();\n } else {\n // For ERC20s, we check that the correct msg.value was sent\n if (msg.value != callValue) revert MsgValueIncorrect();\n // We need to transfer the tokens from the Relayer to the recipient first before performing an\n // optional post-transfer arbitrary call.\n IERC20(token).safeTransferFrom(msg.sender, to, amount);\n }\n\n if (transaction.callParams.length != 0) {\n // Arbitrary call requested, perform it while supplying full msg.value to the recipient\n // Note: if token has a fee on transfers, the recipient will have received less than `amount`.\n // This is a very niche edge case and should be handled by the recipient contract.\n _checkedCallRecipient({recipient: to, token: token, amount: amount, callParams: transaction.callParams});\n } else if (msg.value != 0) {\n // No arbitrary call requested, but msg.value was sent. This is either a relay with ETH,\n // or a non-zero callValue request with an ERC20. In both cases, transfer the ETH to the recipient.\n Address.sendValue(payable(to), msg.value);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) public onlyRole(RELAYER_ROLE) {\n // update bridge tx status given proof provided\n if (bridgeTxDetails[transactionId].status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n bridgeTxDetails[transactionId].status = BridgeStatus.RELAYER_PROVED;\n bridgeTxDetails[transactionId].proofBlockTimestamp = uint40(block.timestamp);\n bridgeTxDetails[transactionId].proofBlockNumber = uint48(block.number);\n bridgeTxDetails[transactionId].proofRelayer = relayer;\n\n emit BridgeProofProvided(transactionId, relayer, destTxHash);\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes memory request, address to) public {\n bytes32 transactionId = keccak256(request);\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n\n // update bridge tx status if able to claim origin collateral\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n\n // if \"to\" is zero addr, permissionlessly send funds to proven relayer\n if (to == address(0)) {\n to = bridgeTxDetails[transactionId].proofRelayer;\n } else if (bridgeTxDetails[transactionId].proofRelayer != msg.sender) {\n revert SenderIncorrect();\n }\n\n if (_timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003c= DISPUTE_PERIOD) {\n revert DisputePeriodNotPassed();\n }\n\n bridgeTxDetails[transactionId].status = BridgeStatus.RELAYER_CLAIMED;\n\n // update protocol fees if origin fee amount exists\n if (transaction.originFeeAmount \u003e 0) protocolFees[transaction.originToken] += transaction.originFeeAmount;\n\n // transfer origin collateral less fee to specified address\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositClaimed(transactionId, bridgeTxDetails[transactionId].proofRelayer, to, token, amount);\n }\n\n function bridgeStatuses(bytes32 transactionId) public view returns (BridgeStatus status) {\n return bridgeTxDetails[transactionId].status;\n }\n\n function bridgeProofs(bytes32 transactionId) public view returns (uint96 timestamp, address relayer) {\n timestamp = bridgeTxDetails[transactionId].proofBlockTimestamp;\n relayer = bridgeTxDetails[transactionId].proofRelayer;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeRelays(bytes32 transactionId) public view returns (bool) {\n // has this transactionId been relayed?\n return bridgeRelayDetails[transactionId].relayer != address(0);\n }\n\n /// @inheritdoc IFastBridgeV2\n function getBridgeTransactionV2(bytes memory request) public pure returns (BridgeTransactionV2 memory) {\n return abi.decode(request, (BridgeTransactionV2));\n }\n\n /// @notice Takes the bridged asset from the user into FastBridgeV2 custody. It will be later\n /// claimed by the relayer who completed the relay on destination chain, or refunded back to the user,\n /// should no one complete the relay.\n function _takeBridgedUserAsset(address token, uint256 amount) internal returns (uint256 amountTaken) {\n if (token == UniversalTokenLib.ETH_ADDRESS) {\n // For ETH we just need to check that the supplied msg.value is correct.\n // Supplied `msg.value` is already in FastBridgeV2 custody.\n if (amount != msg.value) revert MsgValueIncorrect();\n amountTaken = msg.value;\n } else {\n // For ERC20s, token is explicitly transferred from the user to FastBridgeV2.\n // We don't allow non-zero `msg.value` to avoid extra funds from being stuck in FastBridgeV2.\n token.assertIsContract();\n if (msg.value != 0) revert MsgValueIncorrect();\n amountTaken = IERC20(token).balanceOf(address(this));\n IERC20(token).safeTransferFrom(msg.sender, address(this), amount);\n // Use the balance difference as the amount taken in case of fee on transfer tokens.\n amountTaken = IERC20(token).balanceOf(address(this)) - amountTaken;\n }\n }\n\n /// @notice Calls the Recipient's hook function with the specified callParams and performs\n /// all the necessary checks for the returned value.\n function _checkedCallRecipient(\n address recipient,\n address token,\n uint256 amount,\n bytes memory callParams\n )\n internal\n {\n bytes memory hookData =\n abi.encodeCall(IFastBridgeRecipient.fastBridgeTransferReceived, (token, amount, callParams));\n // This will bubble any revert messages from the hook function\n bytes memory returnData = Address.functionCallWithValue({target: recipient, data: hookData, value: msg.value});\n // Explicit revert if no return data at all\n if (returnData.length == 0) revert RecipientNoReturnValue();\n // Check that exactly a single return value was returned\n if (returnData.length != 32) revert RecipientIncorrectReturnValue();\n // Return value should be abi-encoded hook function selector\n if (bytes32(returnData) != bytes32(IFastBridgeRecipient.fastBridgeTransferReceived.selector)) {\n revert RecipientIncorrectReturnValue();\n }\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint40(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint40).max but\n /// proof.timestamp \u003c type(uint40).max via unchecked statement\n /// @param proofBlockTimestamp The bridge proof block timestamp\n /// @return delta Time delta since proof submitted\n function _timeSince(uint40 proofBlockTimestamp) internal view returns (uint256 delta) {\n unchecked {\n delta = uint40(block.timestamp) - proofBlockTimestamp;\n }\n }\n\n /// @notice Performs all the necessary checks for a bridge to happen.\n /// @dev There's no good way to refactor this function to reduce cyclomatic complexity due to\n /// the number of checks that need to be performed, so we skip the code-complexity rule here.\n // solhint-disable-next-line code-complexity\n function _validateBridgeParams(\n BridgeParams memory params,\n BridgeParamsV2 memory paramsV2,\n int256 exclusivityEndTime\n )\n internal\n view\n {\n // Check V1 (legacy) params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.sender == address(0) || params.to == address(0)) revert ZeroAddress();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n // Check V2 params\n if (paramsV2.callParams.length \u003e MAX_CALL_PARAMS_LENGTH) revert CallParamsLengthAboveMax();\n if (paramsV2.callValue != 0 \u0026\u0026 params.destToken == UniversalTokenLib.ETH_ADDRESS) {\n revert NativeTokenCallValueNotSupported();\n }\n // exclusivityEndTime must be in range (0 .. params.deadline]\n if (exclusivityEndTime \u003c= 0 || exclusivityEndTime \u003e int256(params.deadline)) {\n revert ExclusivityParamsIncorrect();\n }\n }\n\n /// @notice Performs all the necessary checks for a relay to happen.\n function _validateRelayParams(\n BridgeTransactionV2 memory transaction,\n bytes32 transactionId,\n address relayer\n )\n internal\n view\n {\n if (relayer == address(0)) revert ZeroAddress();\n // Check if the transaction has already been relayed\n if (bridgeRelays(transactionId)) revert TransactionRelayed();\n if (transaction.destChainId != block.chainid) revert ChainIncorrect();\n // Check the deadline for relay to happen\n if (block.timestamp \u003e transaction.deadline) revert DeadlineExceeded();\n // Check the exclusivity period, if it is still ongoing\n // forgefmt: disable-next-item\n if (\n transaction.exclusivityRelayer != address(0) \u0026\u0026\n transaction.exclusivityRelayer != relayer \u0026\u0026\n block.timestamp \u003c= transaction.exclusivityEndTime\n ) {\n revert ExclusivityPeriodNotPassed();\n }\n }\n}\n","language":"Solidity","languageVersion":"0.8.24","compilerVersion":"0.8.24","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"64760:20167:0:-:0;;;65906:1;65873:34;;66011:85;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;66045:6;63675:38;52847:4;66045:6;63675:10;:38::i;:::-;-1:-1:-1;;66077:12:0::1;66063:26;::::0;-1:-1:-1;64760:20167:0;;62160:257;62246:4;;62277:31;62294:4;62300:7;62277:16;:31::i;:::-;62262:46;;62322:7;62318:69;;;62345:18;;;;:12;:18;;;;;:31;;62368:7;62345:22;:31::i;:::-;;62318:69;62403:7;-1:-1:-1;62160:257:0;;;;;:::o;56794:316::-;56871:4;53569:12;;;;;;;;;;;-1:-1:-1;;;;;53569:29:0;;;;;;;;;;;;56887:217;;56930:6;:12;;;;;;;;;;;-1:-1:-1;;;;;56930:29:0;;;;;;;;;:36;;-1:-1:-1;;56930:36:0;56962:4;56930:36;;;57012:12;23368:10;;23289:96;57012:12;-1:-1:-1;;;;;56985:40:0;57003:7;-1:-1:-1;;;;;56985:40:0;56997:4;56985:40;;;;;;;;;;-1:-1:-1;57046:4:0;57039:11;;56887:217;-1:-1:-1;57088:5:0;57081:12;;32813:150;32883:4;32906:50;32911:3;-1:-1:-1;;;;;32931:23:0;;26801:4;28857:21;;;:14;;;:21;;;;;;26817:321;;-1:-1:-1;26859:23:0;;;;;;;;:11;:23;;;;;;;;;;;;;27041:18;;27017:21;;;:14;;;:21;;;;;;:42;;;;27073:11;;14:290:1;84:6;137:2;125:9;116:7;112:23;108:32;105:52;;;153:1;150;143:12;105:52;179:16;;-1:-1:-1;;;;;224:31:1;;214:42;;204:70;;270:1;267;260:12;14:290;64760:20167:0;;;;;;;;;;;;;;;;;;","srcMapRuntime":"64760:20167:0:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;60820:212;;;;;;;;;;-1:-1:-1;60820:212:0;;;;;:::i;:::-;;:::i;:::-;;;612:14:1;;605:22;587:41;;575:2;560:18;60820:212:0;;;;;;;;63050:60;;;;;;;;;;;;63087:23;63050:60;;;;;785:25:1;;;773:2;758:18;63050:60:0;639:177:1;78427:150:0;;;;;;;;;;-1:-1:-1;78427:150:0;;;;;:::i;:::-;78495:19;78533:30;;;:15;:30;;;;;:37;;;;78427:150;;;;;;;;:::i;64022:359::-;;;;;;;;;;-1:-1:-1;64022:359:0;;;;;:::i;:::-;;:::i;:::-;;63232:45;;;;;;;;;;;;63271:6;63232:45;;76321:648;;;;;;;;;;-1:-1:-1;76321:648:0;;;;;:::i;:::-;;:::i;65110:45::-;;;;;;;;;;;;65149:6;65110:45;;54425:120;;;;;;;;;;-1:-1:-1;54425:120:0;;;;;:::i;:::-;54490:7;54516:12;;;;;;;;;;:22;;;;54425:120;65722:47;;;;;;;;;;-1:-1:-1;65722:47:0;;;;;:::i;:::-;;;;;;;;;;;;;;54841:136;;;;;;;;;;-1:-1:-1;54841:136:0;;;;;:::i;:::-;;:::i;55943:245::-;;;;;;;;;;-1:-1:-1;55943:245:0;;;;;:::i;:::-;;:::i;77007:1414::-;;;;;;;;;;-1:-1:-1;77007:1414:0;;;;;:::i;:::-;;:::i;66134:369::-;;;;;;:::i;:::-;;:::i;63394:30::-;;;;;;;;;;;;;;;;62978:66;;;;;;;;;;;;63018:26;62978:66;;79105:169;;;;;;;;;;-1:-1:-1;79105:169:0;;;;;:::i;:::-;;:::i;:::-;;;;;;;:::i;67821:1169::-;;;;;;;;;;-1:-1:-1;67821:1169:0;;;;;:::i;:::-;;:::i;65482:58::-;;;;;;;;;;-1:-1:-1;65482:58:0;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;65482:58:0;;;;;;;;;;;;;:::i;65242:56::-;;;;;;;;;;;;65288:10;65242:56;;78866:199;;;;;;;;;;-1:-1:-1;78866:199:0;;;;;:::i;:::-;78932:4;79003:33;;;:18;:33;;;;;:41;;;;-1:-1:-1;;;;;79003:41:0;:55;;;78866:199;66696:170;;;;;;;;;;-1:-1:-1;66696:170:0;;;;;:::i;:::-;;:::i;66541:117::-;;;;;;:::i;:::-;;:::i;61617:142::-;;;;;;;;;;-1:-1:-1;61617:142:0;;;;;:::i;:::-;;:::i;:::-;;;-1:-1:-1;;;;;12205:55:1;;;12187:74;;12175:2;12160:18;61617:142:0;12041:226:1;78583:243:0;;;;;;;;;;-1:-1:-1;78583:243:0;;;;;:::i;:::-;78649:16;78706:30;;;:15;:30;;;;;:50;;;;;;;78776:43;;;;-1:-1:-1;;;;;78776:43:0;;78583:243;;;;;12474:26:1;12462:39;;;12444:58;;-1:-1:-1;;;;;12538:55:1;;;12533:2;12518:18;;12511:83;12417:18;78583:243:0;12272:328:1;53469:136:0;;;;;;;;;;-1:-1:-1;53469:136:0;;;;;:::i;:::-;53546:4;53569:12;;;;;;;;;;;-1:-1:-1;;;;;53569:29:0;;;;;;;;;;;;;;;53469:136;62908:64;;;;;;;;;;;;62947:25;62908:64;;73365:2916;;;;;;:::i;:::-;;:::i;52802:49::-;;;;;;;;;;-1:-1:-1;52802:49:0;52847:4;52802:49;;65968:36;;;;;;;;;;;;;;;69028:392;;;;;;;;;;-1:-1:-1;69028:392:0;;;;;:::i;:::-;;:::i;69755:1121::-;;;;;;;;;;-1:-1:-1;69755:1121:0;;;;;:::i;:::-;;:::i;:::-;;;;;;;:::i;67048:735::-;;;;;;;;;;-1:-1:-1;67048:735:0;;;;;:::i;:::-;;:::i;65873:34::-;;;;;;;;;;;;;;;63726:290;;;;;;;;;;-1:-1:-1;63726:290:0;;;;;:::i;:::-;;:::i;64387:264::-;;;;;;;;;;-1:-1:-1;64387:264:0;;;;;:::i;:::-;;:::i;63189:37::-;;;;;;;;;;;;63223:3;63189:37;;70916:2409;;;;;;:::i;:::-;;:::i;66906:104::-;;;;;;;;;;-1:-1:-1;66906:104:0;;;;;:::i;:::-;;:::i;65597:57::-;;;;;;;;;;-1:-1:-1;65597:57:0;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;65597:57:0;;;;;;;15543:14:1;15584:15;;;15566:34;;15636:15;;;;15631:2;15616:18;;15609:43;-1:-1:-1;;;;;15688:55:1;15668:18;;;15661:83;15521:2;15506:18;65597:57:0;15335:415:1;61927:131:0;;;;;;;;;;-1:-1:-1;61927:131:0;;;;;:::i;:::-;;:::i;63116:66::-;;;;;;;;;;;;63156:26;63116:66;;55257:138;;;;;;;;;;-1:-1:-1;55257:138:0;;;;;:::i;:::-;;:::i;63480:47::-;;;;;;;;;;-1:-1:-1;63480:47:0;;;;;:::i;:::-;;;;;;;;;;;;;;65359:60;;;;;;;;;;;;65408:11;65359:60;;63601:29;;;;;;;;;;;;;;;;60820:212;60905:4;60928:57;;;60943:42;60928:57;;:97;;;60989:36;61013:11;60989:23;:36::i;:::-;60921:104;60820:212;-1:-1:-1;;60820:212:0:o;64022:359::-;63156:26;53079:16;53090:4;53079:10;:16::i;:::-;-1:-1:-1;;;;;64146:19:0;::::1;64126:17;64146:19:::0;;;:12:::1;:19;::::0;;;;;;64179:14;;;64175:27:::1;;64195:7;64022:359:::0;;;:::o;64175:27::-:1;-1:-1:-1::0;;;;;64243:19:0;::::1;64265:1;64243:19:::0;;;:12:::1;:19;::::0;;;;:23;64276:45:::1;::::0;64300:9;64311;64276:23:::1;:45::i;:::-;64336:38;::::0;;-1:-1:-1;;;;;16036:15:1;;;16018:34;;16088:15;;16083:2;16068:18;;16061:43;16120:18;;;16113:34;;;64336:38:0::1;::::0;15945:2:1;15930:18;64336:38:0::1;;;;;;;64116:265;53105:1;64022:359:::0;;;:::o;76321:648::-;62947:25;53079:16;53090:4;53079:10;:16::i;:::-;76537:22:::1;76496:30;::::0;;;:15:::1;:30;::::0;;;;:37;::::1;;:63;::::0;::::1;;;;;;:::i;:::-;;76492:93;;76568:17;;;;;;;;;;;;;;76492:93;76595:30;::::0;;;:15:::1;:30;::::0;;;;;;;;:67;;76635:27:::1;76758:70:::0;;;;76672:76:::1;76732:15;76672:76;;;76758:70:::0;;;;76815:12:::1;76758:70;;;::::0;;76838:53;::::1;::::0;-1:-1:-1;;;;;76838:53:0;::::1;::::0;;::::1;::::0;;;::::1;::::0;;;76907:55;;785:25:1;;;76907:55:0;;76838:53;;76595:30;;76907:55:::1;::::0;;;;;;;::::1;76321:648:::0;;;;:::o;54841:136::-;54490:7;54516:12;;;;;;;;;;:22;;;53079:16;53090:4;53079:10;:16::i;:::-;54945:25:::1;54956:4;54962:7;54945:10;:25::i;:::-;;54841:136:::0;;;:::o;55943:245::-;-1:-1:-1;;;;;56036:34:0;;23368:10;56036:34;56032:102;;56093:30;;;;;;;;;;;;;;56032:102;56144:37;56156:4;56162:18;56144:11;:37::i;77007:1414::-;77097:18;;;;;;77073:21;77166:31;77107:7;77166:22;:31::i;:::-;77125:72;-1:-1:-1;77323:27:0;77282:30;;;;:15;:30;;;;;:37;;;:68;;;;;;;;:::i;:::-;;77278:98;;77359:17;;;;;;;;;;;;;;77278:98;-1:-1:-1;;;;;77470:16:0;;77466:213;;77507:30;;;;:15;:30;;;;;:43;;;;-1:-1:-1;;;;;77507:43:0;;-1:-1:-1;77466:213:0;;;77571:30;;;;:15;:30;;;;;:43;;;;-1:-1:-1;;;;;77571:43:0;77618:10;77571:57;77567:112;;77651:17;;;;;;;;;;;;;;77567:112;77704:30;;;;:15;:30;;;;;:50;65004:10;;77704:50;;;;;;;82347:15;82340:45;82332:53;77693:80;77689:142;;77796:24;;;;;;;;;;;;;;77689:142;77841:30;;;;:15;:30;;;;;:68;;;;77881:28;77841:68;;;77984:27;;;;:31;77980:105;;78058:27;;;;78030:23;;;;-1:-1:-1;;;;;78017:37:0;;;;;:12;:37;;;;;:68;;:37;;;:68;;78058:27;;78017:68;:::i;:::-;;;;-1:-1:-1;;77980:105:0;78180:23;;;;78230:24;;;;78264:35;-1:-1:-1;;;;;78264:23:0;;78288:2;78230:24;78264:23;:35::i;:::-;78351:30;;;;:15;:30;;;;;;;;;:43;78315:99;;-1:-1:-1;;;;;16669:55:1;;;16651:74;;16741:18;;;16734:34;;;78315:99:0;;;;78351:43;;;;;;;;:30;;78315:99;;16624:18:1;78315:99:0;;;;;;;77063:1358;;;;77007:1414;;:::o;66134:369::-;66205:291;66234:6;66264:221;;;;;;;;66319:1;-1:-1:-1;;;;;66264:221:0;;;;;66364:1;66264:221;;;;66392:9;;;;;;;;;;;;66264:221;;;;66430:1;66264:221;;;;66461:9;;;;;;;;;;;;66264:221;;;66205:6;:291::i;:::-;66134:369;:::o;79105:169::-;79180:26;-1:-1:-1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;79180:26:0;79236:7;79225:42;;;;;;;;;;;;:::i;67821:1169::-;67902:18;;;;;;67878:21;67972:31;67912:7;67972:22;:31::i;:::-;67931:72;-1:-1:-1;68059:22:0;68018:30;;;;:15;:30;;;;;:37;;;:63;;;;;;;;:::i;:::-;;68014:93;;68090:17;;;;;;;;;;;;;;68014:93;68145:10;53546:4;53569:29;;;:12;;:29;:12;:29;;;;;68118:382;;;68253:11;:20;;;68234:15;:39;68230:73;;68282:21;;;;;;;;;;;;;;68230:73;68118:382;;;65149:6;68424:11;:20;;;:35;;;;:::i;:::-;68405:15;:54;68401:88;;68468:21;;;;;;;;;;;;;;68401:88;68566:30;;;;:15;:30;;;;;;:61;;;;68606:21;68566:61;;;68713:24;;;68763:23;;;;68840:27;;;;68813:24;;;;68713;;68763:23;;68813:54;;68840:27;68813:54;:::i;:::-;68796:71;-1:-1:-1;68877:35:0;-1:-1:-1;;;;;68877:23:0;;68901:2;68796:71;68877:23;:35::i;:::-;68928:55;;;-1:-1:-1;;;;;16669:55:1;;;16651:74;;16756:2;16741:18;;16734:34;;;68928:55:0;;;68950:13;;68928:55;;16624:18:1;68928:55:0;;;;;;;67868:1122;;;;;67821:1169;:::o;66696:170::-;66772:87;66804:7;66794:18;;;;;;66826:10;66847;66772:5;:87::i;:::-;66696:170;;:::o;66541:117::-;66605:46;66621:7;66639:10;66605:5;:46::i;61617:142::-;61698:7;61724:18;;;:12;:18;;;;;:28;;61746:5;61724:21;:28::i;:::-;61717:35;61617:142;-1:-1:-1;;;61617:142:0:o;73365:2916::-;73468:18;;;;;;73444:21;73537:31;73478:7;73537:22;:31::i;:::-;73496:72;;73578:57;73599:11;73612:13;73627:7;73578:20;:57::i;:::-;73739:107;;;;;;;;;;73772:12;73739:107;;;;73810:15;73739:107;;;;;;;;;-1:-1:-1;;;;;73739:107:0;;;;;;;;;-1:-1:-1;73691:33:0;;;:18;:33;;;;;:155;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;73969:25;;;;74020:21;;;;;74068:22;;;;74120:21;;;;74344:25;;74396:23;;;;;74477:24;;;;;74209:374;;19501:10:1;19489:23;;;19471:42;;19610:15;;;19590:18;;;19583:43;;;;19662:15;;;19642:18;;;19635:43;;;;19694:18;;;19687:34;;;;19737:19;;;19730:35;;;19781:19;;;19774:35;;;73969:25:0;;74020:21;;74068:22;;74120:21;74209:374;;;73739:107;73691:33;;74209:374;;19443:19:1;74209:374:0;;;;;;;74798:38;-1:-1:-1;;;;;74798:38:0;;;74794:695;;74913:14;;74909:61;;74936:34;;;;;;;;;;;;;;74909:61;75058:6;75045:9;:19;75041:51;;75073:19;;;;;;;;;;;;;;75041:51;74794:695;;;75212:9;75199;:22;75195:54;;75230:19;;;;;;;;;;;;;;75195:54;75424;-1:-1:-1;;;;;75424:30:0;;75455:10;75467:2;75471:6;75424:30;:54::i;:::-;75503:22;;;;:29;:34;75499:776;;75855:104;75889:2;75900:5;75915:6;75935:11;:22;;;75855:21;:104::i;:::-;75499:776;;;75980:9;:14;75976:299;;76223:41;76249:2;76254:9;76223:17;:41::i;:::-;73434:2847;;;;;;73365:2916;;:::o;69028:392::-;69109:4;69170:27;69129:30;;;;:15;:30;;;;;:37;;;:68;;;;;;;;:::i;:::-;;69125:98;;69206:17;;;;;;;;;;;;;;69125:98;69237:30;;;;:15;:30;;;;;:43;-1:-1:-1;;;;;69237:54:0;;;:43;;;;;:54;69233:84;;69300:17;;;;;;;;;;;;;;69233:84;-1:-1:-1;;69345:30:0;;;;:15;:30;;;;;:50;65004:10;69345:50;;;;;;;;82347:15;82340:45;82332:53;69334:79;;69028:392::o;69755:1121::-;-1:-1:-1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;69956:36:0;;;;;:4;;:27;;:36;;69984:7;;69956:36;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;69956:36:0;;;;;;;;;;;;:::i;:::-;;;69952:918;;70830:7;70819:40;;;;;;;;;;;;:::i;69952:918::-;70146:597;;;;;;;;70197:4;:18;;;70146:597;;;;;;70246:4;:16;;;70146:597;;;;;;70294:4;:17;;;-1:-1:-1;;;;;70146:597:0;;;;;70344:4;:18;;;-1:-1:-1;;;;;70146:597:0;;;;;70393:4;:16;;;-1:-1:-1;;;;;70146:597:0;;;;;70438:4;:14;;;-1:-1:-1;;;;;70146:597:0;;;;;70484:4;:17;;;70146:597;;;;70531:4;:15;;;70146:597;;;;70581:4;:20;;;70146:597;;;;70633:4;:14;;;70651:1;70633:19;;70146:597;;;;;;70680:4;:13;;;70146:597;;;;70718:4;:10;;;70146:597;;;70139:604;;;69755:1121;;;:::o;69952:918::-;69755:1121;;;:::o;67048:735::-;63087:23;53079:16;53090:4;53079:10;:16::i;:::-;67173:27:::1;67132:30;::::0;;;:15:::1;:30;::::0;;;;:37;::::1;;:68;::::0;::::1;;;;;;:::i;:::-;;67128:98;;67209:17;;;;;;;;;;;;;;67128:98;67251:30;::::0;;;:15:::1;:30;::::0;;;;:50;65004:10:::1;::::0;67251:50:::1;::::0;::::1;;::::0;;::::1;82347:15:::0;82340:45;82332:53;67240:79:::1;67236:138;;;67342:21;;;;;;;;;;;;;;67236:138;67461:30;::::0;;;:15:::1;:30;::::0;;;;;67501:22:::1;67663:51:::0;;67730:46;67765:10:::1;::::0;67461:30;;67730:46:::1;::::0;67461:30;67730:46:::1;67048:735:::0;;:::o;63726:290::-;63156:26;53079:16;53090:4;53079:10;:16::i;:::-;63271:6:::1;63825:10;:26;;63817:55;;;::::0;::::1;::::0;;21574:2:1;63817:55:0::1;::::0;::::1;21556:21:1::0;21613:2;21593:18;;;21586:30;21652:18;21632;;;21625:46;21688:18;;63817:55:0::1;;;;;;;;;63903:15;::::0;;63928:28;;;;63971:38:::1;::::0;;21891:25:1;;;21947:2;21932:18;;21925:34;;;63971:38:0::1;::::0;21864:18:1;63971:38:0::1;;;;;;;;63807:209;63726:290:::0;;:::o;64387:264::-;63156:26;53079:16;53090:4;53079:10;:16::i;:::-;64512:14:::1;::::0;;64536:34;;;;64585:59:::1;::::0;;21891:25:1;;;21947:2;21932:18;;21925:34;;;64585:59:0::1;::::0;21864:18:1;64585:59:0::1;21717:248:1::0;70916:2409:0;71017:25;71071:8;:32;;;71052:15;71045:58;;;;:::i;:::-;71017:86;;71113:59;71135:6;71143:8;71153:18;71113:21;:59::i;:::-;71308:20;71331:62;71353:6;:18;;;71373:6;:19;;;71331:21;:62::i;:::-;71308:85;;71461:23;71516:1;71498:15;;:19;71494:85;;;63223:3;71553:15;;71538:12;:30;;;;:::i;:::-;71537:42;;;;:::i;:::-;71519:60;;71494:85;71589:31;71605:15;71589:31;;:::i;:::-;;;71733:20;71780:924;;;;;;;;71840:13;71780:924;;;;;;71885:6;:17;;;71780:924;;;;;;71934:6;:13;;;-1:-1:-1;;;;;71780:924:0;;;;;71980:6;:9;;;-1:-1:-1;;;;;71780:924:0;;;;;72020:6;:18;;;-1:-1:-1;;;;;71780:924:0;;;;;72067:6;:16;;;-1:-1:-1;;;;;71780:924:0;;;;;72115:12;71780:924;;;;72157:6;:17;;;71780:924;;;;72209:15;71780:924;;;;72253:8;:18;;;71780:924;;;;72299:6;:15;;;71780:924;;;;72339:12;:27;72352:6;:13;;;-1:-1:-1;;;;;72339:27:0;-1:-1:-1;;;;;72339:27:0;;;;;;;;;;;;;:29;;;;;;;;;:::i;:::-;;;;;71780:924;;;;72441:8;:21;;;-1:-1:-1;;;;;71780:924:0;;;;;72621:18;71780:924;;;;72670:8;:19;;;71780:924;;;71756:958;;;;;;;;:::i;:::-;;;;;;;-1:-1:-1;;71756:958:0;;;;;;72748:18;;71756:958;72748:18;;;;;;;72724:21;72776:30;;;:15;:30;;;;;;:62;;;;72816:22;72776:62;;;72934:13;;;73004:17;;73048:18;;;;;73091:16;;;;73173:17;;;;73218:18;;;;71756:958;;-1:-1:-1;72748:18:0;;-1:-1:-1;;;;;72854:398:0;;;;72748:18;;72854:398;;;;71756:958;;73004:17;;73048:18;73091:16;73135:12;;73218:23;;;;72854:398;:::i;:::-;;;;;;;;73286:13;73267:51;73301:8;:16;;;73267:51;;;;;;:::i;:::-;;;;;;;;71007:2318;;;;;70916:2409;;:::o;66906:104::-;66962:41;66978:7;66999:1;66962:5;:41::i;61927:131::-;61998:7;62024:18;;;:12;:18;;;;;:27;;:25;:27::i;55257:138::-;54490:7;54516:12;;;;;;;;;;:22;;;53079:16;53090:4;53079:10;:16::i;:::-;55362:26:::1;55374:4;55380:7;55362:11;:26::i;53180:202::-:0;53265:4;53288:47;;;53303:32;53288:47;;:87;;-1:-1:-1;45095:25:0;45080:40;;;;53339:36;44981:146;53814:103;53880:30;53891:4;23368:10;53880;:30::i;58092:653::-;58267:4;-1:-1:-1;;;;;58253:19:0;;;58249:32;;58092:653;;;:::o;58249:32::-;58353:5;58362:1;58353:10;58349:23;;58092:653;;;:::o;58349:23::-;58385:20;-1:-1:-1;;;;;58385:20:0;;;58381:358;;58565:12;58582:2;-1:-1:-1;;;;;58582:7:0;58597:5;58582:25;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;58564:43;;;58629:7;58621:39;;;;;;;24145:2:1;58621:39:0;;;24127:21:1;24184:2;24164:18;;;24157:30;24223:21;24203:18;;;24196:49;24262:18;;58621:39:0;23943:343:1;58381:358:0;58691:37;-1:-1:-1;;;;;58691:26:0;;58718:2;58722:5;58691:26;:37::i;62160:257::-;62246:4;62262:12;62277:31;62294:4;62300:7;62277:16;:31::i;:::-;62262:46;;62322:7;62318:69;;;62345:18;;;;:12;:18;;;;;:31;;62368:7;62345:22;:31::i;:::-;;62403:7;62160:257;-1:-1:-1;;;62160:257:0:o;62520:262::-;62607:4;62623:12;62638:32;62656:4;62662:7;62638:17;:32::i;:::-;62623:47;;62684:7;62680:72;;;62707:18;;;;:12;:18;;;;;:34;;62733:7;62707:25;:34::i;34071:156::-;34145:7;34195:22;34199:3;34211:5;34195:3;:22::i;83982:943::-;-1:-1:-1;;;;;84170:21:0;;84166:47;;84200:13;;;;;;;;;;;;;;84166:47;78932:4;79003:33;;;:18;:33;;;;;:41;;;;-1:-1:-1;;;;;79003:41:0;:55;84284:60;;84324:20;;;;;;;;;;;;;;84284:60;84385:13;84358:11;:23;;;:40;;;84354:69;;84407:16;;;;;;;;;;;;;;84354:69;84505:11;:20;;;84487:15;:38;84483:69;;;84534:18;;;;;;;;;;;;;;84483:69;84682:30;;;;-1:-1:-1;;;;;84682:44:0;;;;;:101;;;84776:7;-1:-1:-1;;;;;84742:41:0;:11;:30;;;-1:-1:-1;;;;;84742:41:0;;;84682:101;:166;;;;;84818:11;:30;;;84799:15;:49;;84682:166;84665:254;;;84880:28;;;;;;;;;;;;;;46696:188;46823:53;;-1:-1:-1;;;;;16036:15:1;;;46823:53:0;;;16018:34:1;16088:15;;;16068:18;;;16061:43;16120:18;;;16113:34;;;46796:81:0;;46816:5;;46838:18;;;;;15930::1;;46823:53:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;46796:19;:81::i;80749:999::-;80924:21;81025:5;81032:6;81040:10;80960:92;;;;;;;;;;:::i;:::-;;;;-1:-1:-1;;80960:92:0;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;81159:84:0;81198:9;80960:92;81232:9;81159:29;:84::i;:::-;81133:110;;81309:10;:17;81330:1;81309:22;81305:59;;81340:24;;;;;;;;;;;;;;81305:59;81443:10;:17;81464:2;81443:23;81439:67;;81475:31;;;;;;;;;;;;;;81439:67;81620:56;81589:19;81597:10;81589:19;:::i;:::-;:88;81585:157;;81700:31;;;;;;;;;;;;;;81585:157;80914:834;;80749:999;;;;:::o;17900:331::-;18009:6;17985:21;:30;17981:109;;;18038:41;;;;;18073:4;18038:41;;;12187:74:1;12160:18;;18038:41:0;12041:226:1;17981:109:0;18101:12;18119:9;-1:-1:-1;;;;;18119:14:0;18141:6;18119:33;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;18100:52;;;18167:7;18162:63;;18197:17;;;;;;;;;;;;;;82727:1176;82980:13;82959:6;:17;;;:34;;;82955:63;;83002:16;;;;;;;;;;;;;;82955:63;83032:19;;;;:24;;:50;;-1:-1:-1;83060:17:0;;;;:22;83032:50;83028:80;;;83091:17;;;;;;;;;;;;;;83028:80;83122:13;;;;-1:-1:-1;;;;;83122:27:0;;;:54;;-1:-1:-1;83153:9:0;;;;-1:-1:-1;;;;;83153:23:0;;83122:54;83118:80;;;83185:13;;;;;;;;;;;;;;83118:80;83212:18;;;;-1:-1:-1;;;;;83212:32:0;;;:66;;-1:-1:-1;83248:16:0;;;;-1:-1:-1;;;;;83248:30:0;;83212:66;83208:92;;;83287:13;;;;;;;;;;;;;;83208:92;83332:37;65288:10;83332:15;:37;:::i;:::-;83314:6;:15;;;:55;83310:86;;;83378:18;;;;;;;;;;;;;;83310:86;65408:11;83437:8;:19;;;:26;:51;83433:90;;;83497:26;;;;;;;;;;;;;;83433:90;83537:18;;;;:23;;;;:76;;-1:-1:-1;83564:16:0;;;;-1:-1:-1;;;;;83564:49:0;57809:42;83564:49;83537:76;83533:148;;;83636:34;;;;;;;;;;;;;;83533:148;83786:1;83764:18;:23;;:71;;;;83819:6;:15;;;83791:18;:44;83764:71;83760:137;;;83858:28;;;;;;;;;;;;;;79527:1064;79607:19;79642:38;-1:-1:-1;;;;;79642:38:0;;;79638:947;;79867:9;79857:6;:19;79853:51;;79885:19;;;;;;;;;;;;;;79853:51;-1:-1:-1;79932:9:0;79638:947;;;80168:24;:5;-1:-1:-1;;;;;80168:22:0;;:24::i;:::-;80210:9;:14;80206:46;;80233:19;;;;;;;;;;;;;;80206:46;80280:38;;;;;80312:4;80280:38;;;12187:74:1;-1:-1:-1;;;;;80280:23:0;;;;;12160:18:1;;80280:38:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;80266:52;-1:-1:-1;80332:65:0;-1:-1:-1;;;;;80332:30:0;;80363:10;80383:4;80390:6;80332:30;:65::i;:::-;80522:38;;;;;80554:4;80522:38;;;12187:74:1;80563:11:0;;-1:-1:-1;;;;;80522:23:0;;;;;12160:18:1;;80522:38:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;:52;;;;:::i;33614:115::-;33677:7;33703:19;33711:3;29053:18;;28971:107;54047:197;53546:4;53569:12;;;;;;;;;;;-1:-1:-1;;;;;53569:29:0;;;;;;;;;;;;54130:108;;54180:47;;;;;-1:-1:-1;;;;;16669:55:1;;54180:47:0;;;16651:74:1;16741:18;;;16734:34;;;16624:18;;54180:47:0;16477:297:1;46297:160:0;46406:43;;-1:-1:-1;;;;;16669:55:1;;;46406:43:0;;;16651:74:1;16741:18;;;16734:34;;;46379:71:0;;46399:5;;46421:14;;;;;16624:18:1;;46406:43:0;16477:297:1;56794:316:0;56871:4;53569:12;;;;;;;;;;;-1:-1:-1;;;;;53569:29:0;;;;;;;;;;;;56887:217;;56930:6;:12;;;;;;;;;;;-1:-1:-1;;;;;56930:29:0;;;;;;;;;:36;;;;56962:4;56930:36;;;57012:12;23368:10;;23289:96;57012:12;-1:-1:-1;;;;;56985:40:0;57003:7;-1:-1:-1;;;;;56985:40:0;56997:4;56985:40;;;;;;;;;;-1:-1:-1;57046:4:0;57039:11;;56887:217;-1:-1:-1;57088:5:0;57081:12;;32813:150;32883:4;32906:50;32911:3;-1:-1:-1;;;;;32931:23:0;;32906:4;:50::i;57345:317::-;57423:4;53569:12;;;;;;;;;;;-1:-1:-1;;;;;53569:29:0;;;;;;;;;;;;57439:217;;;57513:5;57481:12;;;;;;;;;;;-1:-1:-1;;;;;57481:29:0;;;;;;;;;;:37;;;;;;57537:40;23368:10;;57481:12;;57537:40;;57513:5;57537:40;-1:-1:-1;57598:4:0;57591:11;;33131:156;33204:4;33227:53;33235:3;-1:-1:-1;;;;;33255:23:0;;33227:7;:53::i;29420:118::-;29487:7;29513:3;:11;;29525:5;29513:18;;;;;;;;:::i;:::-;;;;;;;;;29506:25;;29420:118;;;;:::o;49053:629::-;49472:23;49498:33;-1:-1:-1;;;;;49498:27:0;;49526:4;49498:27;:33::i;:::-;49472:59;;49545:10;:17;49566:1;49545:22;;:57;;;;;49583:10;49572:30;;;;;;;;;;;;:::i;:::-;49571:31;49545:57;49541:135;;;49625:40;;;;;-1:-1:-1;;;;;12205:55:1;;49625:40:0;;;12187:74:1;12160:18;;49625:40:0;12041:226:1;19549:392:0;19648:12;19700:5;19676:21;:29;19672:108;;;19728:41;;;;;19763:4;19728:41;;;12187:74:1;12160:18;;19728:41:0;12041:226:1;19672:108:0;19790:12;19804:23;19831:6;-1:-1:-1;;;;;19831:11:0;19850:5;19857:4;19831:31;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;19789:73;;;;19879:55;19906:6;19914:7;19923:10;19879:26;:55::i;:::-;19872:62;19549:392;-1:-1:-1;;;;;;19549:392:0:o;59909:344::-;60076:38;-1:-1:-1;;;;;60076:38:0;;;60072:69;;60123:18;;;;;;;;;;;;;;60072:69;60197:5;-1:-1:-1;;;;;60197:17:0;;60218:1;60197:22;60193:53;;60228:18;;;;;;;;;;;;;;26738:406;26801:4;28857:21;;;:14;;;:21;;;;;;26817:321;;-1:-1:-1;26859:23:0;;;;;;;;:11;:23;;;;;;;;;;;;;27041:18;;27017:21;;;:14;;;:21;;;;;;:42;;;;27073:11;;27312:1368;27378:4;27507:21;;;:14;;;:21;;;;;;27543:13;;27539:1135;;27910:18;27931:12;27942:1;27931:8;:12;:::i;:::-;27977:18;;27910:33;;-1:-1:-1;27957:17:0;;27977:22;;27998:1;;27977:22;:::i;:::-;27957:42;;28032:9;28018:10;:23;28014:378;;28061:17;28081:3;:11;;28093:9;28081:22;;;;;;;;:::i;:::-;;;;;;;;;28061:42;;28228:9;28202:3;:11;;28214:10;28202:23;;;;;;;;:::i;:::-;;;;;;;;;;;;:35;;;;28341:25;;;:14;;;:25;;;;;:36;;;28014:378;28470:17;;:3;;:17;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;28573:3;:14;;:21;28588:5;28573:21;;;;;;;;;;;28566:28;;;28616:4;28609:11;;;;;;;27539:1135;28658:5;28651:12;;;;;19074:151;19149:12;19180:38;19202:6;19210:4;19216:1;19180:21;:38::i;20994:582::-;21138:12;21167:7;21162:408;;21190:19;21198:10;21190:7;:19::i;:::-;21162:408;;;21414:17;;:22;:49;;;;-1:-1:-1;;;;;;21440:18:0;;;:23;21414:49;21410:119;;;21490:24;;;;;-1:-1:-1;;;;;12205:55:1;;21490:24:0;;;12187:74:1;12160:18;;21490:24:0;12041:226:1;21410:119:0;-1:-1:-1;21549:10:0;21542:17;;22112:516;22243:17;;:21;22239:383;;22471:10;22465:17;22527:15;22514:10;22510:2;22506:19;22499:44;22239:383;22594:17;;;;;;;;;;;;;;14:332:1;72:6;125:2;113:9;104:7;100:23;96:32;93:52;;;141:1;138;131:12;93:52;180:9;167:23;230:66;223:5;219:78;212:5;209:89;199:117;;312:1;309;302:12;821:180;880:6;933:2;921:9;912:7;908:23;904:32;901:52;;;949:1;946;939:12;901:52;-1:-1:-1;972:23:1;;821:180;-1:-1:-1;821:180:1:o;1006:184::-;1058:77;1055:1;1048:88;1155:4;1152:1;1145:15;1179:4;1176:1;1169:15;1195:297;1279:1;1272:5;1269:12;1259:200;;1315:77;1312:1;1305:88;1416:4;1413:1;1406:15;1444:4;1441:1;1434:15;1259:200;1468:18;;1195:297::o;1497:214::-;1646:2;1631:18;;1658:47;1635:9;1687:6;1658:47;:::i;1716:154::-;-1:-1:-1;;;;;1795:5:1;1791:54;1784:5;1781:65;1771:93;;1860:1;1857;1850:12;1875:134;1943:20;;1972:31;1943:20;1972:31;:::i;2014:388::-;2082:6;2090;2143:2;2131:9;2122:7;2118:23;2114:32;2111:52;;;2159:1;2156;2149:12;2111:52;2198:9;2185:23;2217:31;2242:5;2217:31;:::i;:::-;2267:5;-1:-1:-1;2324:2:1;2309:18;;2296:32;2337:33;2296:32;2337:33;:::i;:::-;2389:7;2379:17;;;2014:388;;;;;:::o;2589:383::-;2666:6;2674;2682;2735:2;2723:9;2714:7;2710:23;2706:32;2703:52;;;2751:1;2748;2741:12;2703:52;2787:9;2774:23;2764:33;;2844:2;2833:9;2829:18;2816:32;2806:42;;2898:2;2887:9;2883:18;2870:32;2911:31;2936:5;2911:31;:::i;:::-;2961:5;2951:15;;;2589:383;;;;;:::o;2977:247::-;3036:6;3089:2;3077:9;3068:7;3064:23;3060:32;3057:52;;;3105:1;3102;3095:12;3057:52;3144:9;3131:23;3163:31;3188:5;3163:31;:::i;3229:315::-;3297:6;3305;3358:2;3346:9;3337:7;3333:23;3329:32;3326:52;;;3374:1;3371;3364:12;3326:52;3410:9;3397:23;3387:33;;3470:2;3459:9;3455:18;3442:32;3483:31;3508:5;3483:31;:::i;3549:184::-;3601:77;3598:1;3591:88;3698:4;3695:1;3688:15;3722:4;3719:1;3712:15;3738:255;3810:2;3804:9;3852:6;3840:19;;3889:18;3874:34;;3910:22;;;3871:62;3868:88;;;3936:18;;:::i;:::-;3972:2;3965:22;3738:255;:::o;3998:253::-;4070:2;4064:9;4112:4;4100:17;;4147:18;4132:34;;4168:22;;;4129:62;4126:88;;;4194:18;;:::i;4256:255::-;4328:2;4322:9;4370:6;4358:19;;4407:18;4392:34;;4428:22;;;4389:62;4386:88;;;4454:18;;:::i;4516:252::-;4588:2;4582:9;4630:3;4618:16;;4664:18;4649:34;;4685:22;;;4646:62;4643:88;;;4711:18;;:::i;4773:334::-;4844:2;4838:9;4900:2;4890:13;;-1:-1:-1;;4886:86:1;4874:99;;5003:18;4988:34;;5024:22;;;4985:62;4982:88;;;5050:18;;:::i;:::-;5086:2;5079:22;4773:334;;-1:-1:-1;4773:334:1:o;5112:245::-;5160:4;5193:18;5185:6;5182:30;5179:56;;;5215:18;;:::i;:::-;-1:-1:-1;5272:2:1;5260:15;-1:-1:-1;;5256:88:1;5346:4;5252:99;;5112:245::o;5362:462::-;5404:5;5457:3;5450:4;5442:6;5438:17;5434:27;5424:55;;5475:1;5472;5465:12;5424:55;5511:6;5498:20;5542:48;5558:31;5586:2;5558:31;:::i;:::-;5542:48;:::i;:::-;5615:2;5606:7;5599:19;5661:3;5654:4;5649:2;5641:6;5637:15;5633:26;5630:35;5627:55;;;5678:1;5675;5668:12;5627:55;5743:2;5736:4;5728:6;5724:17;5717:4;5708:7;5704:18;5691:55;5791:1;5766:16;;;5784:4;5762:27;5755:38;;;;5770:7;5362:462;-1:-1:-1;;;5362:462:1:o;5829:455::-;5906:6;5914;5967:2;5955:9;5946:7;5942:23;5938:32;5935:52;;;5983:1;5980;5973:12;5935:52;6023:9;6010:23;6056:18;6048:6;6045:30;6042:50;;;6088:1;6085;6078:12;6042:50;6111:49;6152:7;6143:6;6132:9;6128:22;6111:49;:::i;:::-;6101:59;;;6210:2;6199:9;6195:18;6182:32;6223:31;6248:5;6223:31;:::i;6289:121::-;6374:10;6367:5;6363:22;6356:5;6353:33;6343:61;;6400:1;6397;6390:12;6415:132;6482:20;;6511:30;6482:20;6511:30;:::i;6552:118::-;6638:5;6631:13;6624:21;6617:5;6614:32;6604:60;;6660:1;6657;6650:12;6675:128;6740:20;;6769:28;6740:20;6769:28;:::i;6808:806::-;6867:5;6915:6;6903:9;6898:3;6894:19;6890:32;6887:52;;;6935:1;6932;6925:12;6887:52;6957:22;;:::i;:::-;6948:31;;7002:28;7020:9;7002:28;:::i;:::-;6995:5;6988:43;7063:38;7097:2;7086:9;7082:18;7063:38;:::i;:::-;7058:2;7051:5;7047:14;7040:62;7134:38;7168:2;7157:9;7153:18;7134:38;:::i;:::-;7129:2;7122:5;7118:14;7111:62;7205:38;7239:2;7228:9;7224:18;7205:38;:::i;:::-;7200:2;7193:5;7189:14;7182:62;7277:39;7311:3;7300:9;7296:19;7277:39;:::i;:::-;7271:3;7264:5;7260:15;7253:64;7378:3;7367:9;7363:19;7350:33;7344:3;7337:5;7333:15;7326:58;7445:3;7434:9;7430:19;7417:33;7411:3;7404:5;7400:15;7393:58;7484:36;7515:3;7504:9;7500:19;7484:36;:::i;:::-;7478:3;7471:5;7467:15;7460:61;7540:3;7603:2;7592:9;7588:18;7575:32;7570:2;7563:5;7559:14;7552:56;;6808:806;;;;:::o;7619:237::-;7707:6;7760:3;7748:9;7739:7;7735:23;7731:33;7728:53;;;7777:1;7774;7767:12;7728:53;7800:50;7842:7;7831:9;7800:50;:::i;7861:320::-;7929:6;7982:2;7970:9;7961:7;7957:23;7953:32;7950:52;;;7998:1;7995;7988:12;7950:52;8038:9;8025:23;8071:18;8063:6;8060:30;8057:50;;;8103:1;8100;8093:12;8057:50;8126:49;8167:7;8158:6;8147:9;8143:22;8126:49;:::i;:::-;8116:59;7861:320;-1:-1:-1;;;;7861:320:1:o;8417:250::-;8502:1;8512:113;8526:6;8523:1;8520:13;8512:113;;;8602:11;;;8596:18;8583:11;;;8576:39;8548:2;8541:10;8512:113;;;-1:-1:-1;;8659:1:1;8641:16;;8634:27;8417:250::o;8672:329::-;8713:3;8751:5;8745:12;8778:6;8773:3;8766:19;8794:76;8863:6;8856:4;8851:3;8847:14;8840:4;8833:5;8829:16;8794:76;:::i;:::-;8915:2;8903:15;-1:-1:-1;;8899:88:1;8890:98;;;;8990:4;8886:109;;8672:329;-1:-1:-1;;8672:329:1:o;9006:1866::-;9209:2;9198:9;9191:21;9221:52;9269:2;9258:9;9254:18;9245:6;9239:13;8262:10;8251:22;8239:35;;8186:94;9221:52;9172:4;9320:2;9312:6;9308:15;9302:22;9333:51;9380:2;9369:9;9365:18;9351:12;8262:10;8251:22;8239:35;;8186:94;9333:51;-1:-1:-1;9433:2:1;9421:15;;9415:22;-1:-1:-1;;;;;8351:54:1;;9496:2;9481:18;;8339:67;-1:-1:-1;9549:2:1;9537:15;;9531:22;-1:-1:-1;;;;;8351:54:1;;9612:3;9597:19;;8339:67;-1:-1:-1;9666:3:1;9654:16;;9648:23;-1:-1:-1;;;;;8351:54:1;;9730:3;9715:19;;8339:67;-1:-1:-1;9784:3:1;9772:16;;9766:23;-1:-1:-1;;;;;8351:54:1;;9848:3;9833:19;;8339:67;-1:-1:-1;9908:3:1;9896:16;;9890:23;9884:3;9869:19;;;9862:52;;;;9939:16;;9933:23;9975:3;9994:18;;;9987:30;;;;10042:15;;10036:22;10077:3;10096:18;;;10089:30;;;;10144:15;;10138:22;10179:3;10198:18;;;10191:30;;;;10246:15;;10240:22;10281:3;10300:18;;;10293:30;;;;10348:15;;10342:22;10384:3;10403:19;;;10396:31;;;;10464:16;;10458:23;10501:3;10513:55;10548:19;;;10458:23;-1:-1:-1;;;;;8351:54:1;8339:67;;8285:127;10513:55;10594:16;;10588:23;10631:3;10650:19;;;10643:32;;;;10712:16;;10706:23;10749:6;10771:19;;;10764:32;10706:23;-1:-1:-1;10813:53:1;10861:3;10846:19;;10706:23;10813:53;:::i;10877:513::-;11106:3;11091:19;;11119:47;11095:9;11148:6;11119:47;:::i;:::-;11214:12;11206:6;11202:25;11197:2;11186:9;11182:18;11175:53;11276:14;11268:6;11264:27;11259:2;11248:9;11244:18;11237:55;-1:-1:-1;;;;;11332:6:1;11328:55;11323:2;11312:9;11308:18;11301:83;10877:513;;;;;;;:::o;11395:388::-;11472:6;11480;11533:2;11521:9;11512:7;11508:23;11504:32;11501:52;;;11549:1;11546;11539:12;11501:52;11589:9;11576:23;11622:18;11614:6;11611:30;11608:50;;;11654:1;11651;11644:12;11608:50;11677:49;11718:7;11709:6;11698:9;11694:22;11677:49;:::i;:::-;11667:59;11773:2;11758:18;;;;11745:32;;-1:-1:-1;;;;11395:388:1:o;11788:248::-;11856:6;11864;11917:2;11905:9;11896:7;11892:23;11888:32;11885:52;;;11933:1;11930;11923:12;11885:52;-1:-1:-1;;11956:23:1;;;12026:2;12011:18;;;11998:32;;-1:-1:-1;11788:248:1:o;12605:1373::-;12836:13;;8262:10;8251:22;8239:35;;12805:3;12790:19;;12908:4;12900:6;12896:17;12890:24;12923:53;12970:4;12959:9;12955:20;12941:12;8262:10;8251:22;8239:35;;8186:94;12923:53;;13025:4;13017:6;13013:17;13007:24;13040:56;13090:4;13079:9;13075:20;13059:14;-1:-1:-1;;;;;8351:54:1;8339:67;;8285:127;13040:56;;13145:4;13137:6;13133:17;13127:24;13160:56;13210:4;13199:9;13195:20;13179:14;-1:-1:-1;;;;;8351:54:1;8339:67;;8285:127;13160:56;;13265:4;13257:6;13253:17;13247:24;13280:56;13330:4;13319:9;13315:20;13299:14;-1:-1:-1;;;;;8351:54:1;8339:67;;8285:127;13280:56;;13385:4;13377:6;13373:17;13367:24;13400:56;13450:4;13439:9;13435:20;13419:14;-1:-1:-1;;;;;8351:54:1;8339:67;;8285:127;13400:56;;13512:4;13504:6;13500:17;13494:24;13487:4;13476:9;13472:20;13465:54;13575:4;13567:6;13563:17;13557:24;13550:4;13539:9;13535:20;13528:54;13601:6;13661:2;13653:6;13649:15;13643:22;13638:2;13627:9;13623:18;13616:50;;13685:6;13740:2;13732:6;13728:15;13722:22;13753:51;13800:2;13789:9;13785:18;13769:14;421:13;414:21;402:34;;351:91;13753:51;-1:-1:-1;;13823:6:1;13871:15;;;13865:22;13845:18;;;13838:50;13907:6;13955:15;;;13949:22;13929:18;;;;13922:50;;;;12605:1373;:::o;14168:1162::-;14297:6;14305;14358:3;14346:9;14337:7;14333:23;14329:33;14326:53;;;14375:1;14372;14365:12;14326:53;14398:50;14440:7;14429:9;14398:50;:::i;:::-;14388:60;;14499:3;14488:9;14484:19;14471:33;14523:18;14564:2;14556:6;14553:14;14550:34;;;14580:1;14577;14570:12;14550:34;14603:22;;;;14659:4;14641:16;;;14637:27;14634:47;;;14677:1;14674;14667:12;14634:47;14703:22;;:::i;:::-;14762:2;14749:16;14774:33;14799:7;14774:33;:::i;:::-;14816:22;;14891:2;14883:11;;;14870:25;14854:14;;;14847:49;14942:2;14934:11;;14921:25;14958:16;;;14955:36;;;14987:1;14984;14977:12;14955:36;15023:44;15059:7;15048:8;15044:2;15040:17;15023:44;:::i;:::-;15018:2;15011:5;15007:14;15000:68;;15121:2;15117;15113:11;15100:25;15095:2;15088:5;15084:14;15077:49;15172:3;15168:2;15164:12;15151:26;15202:2;15192:8;15189:16;15186:36;;;15218:1;15215;15208:12;15186:36;15255:44;15291:7;15280:8;15276:2;15272:17;15255:44;:::i;:::-;15249:3;15242:5;15238:15;15231:69;;15319:5;15309:15;;;;;14168:1162;;;;;:::o;16158:184::-;16210:77;16207:1;16200:88;16307:4;16304:1;16297:15;16331:4;16328:1;16321:15;16347:125;16412:9;;;16433:10;;;16430:36;;;16446:18;;:::i;16779:136::-;16857:13;;16879:30;16857:13;16879:30;:::i;16920:138::-;16999:13;;17021:31;16999:13;17021:31;:::i;17063:441::-;17116:5;17169:3;17162:4;17154:6;17150:17;17146:27;17136:55;;17187:1;17184;17177:12;17136:55;17216:6;17210:13;17247:48;17263:31;17291:2;17263:31;:::i;17247:48::-;17320:2;17311:7;17304:19;17366:3;17359:4;17354:2;17346:6;17342:15;17338:26;17335:35;17332:55;;;17383:1;17380;17373:12;17332:55;17396:77;17470:2;17463:4;17454:7;17450:18;17443:4;17435:6;17431:17;17396:77;:::i;17509:1672::-;17616:6;17669:2;17657:9;17648:7;17644:23;17640:32;17637:52;;;17685:1;17682;17675:12;17637:52;17718:9;17712:16;17747:18;17788:2;17780:6;17777:14;17774:34;;;17804:1;17801;17794:12;17774:34;17827:22;;;;17883:6;17865:16;;;17861:29;17858:49;;;17903:1;17900;17893:12;17858:49;17929:22;;:::i;:::-;17974:32;18003:2;17974:32;:::i;:::-;17967:5;17960:47;18039:41;18076:2;18072;18068:11;18039:41;:::i;:::-;18034:2;18027:5;18023:14;18016:65;18113:42;18151:2;18147;18143:11;18113:42;:::i;:::-;18108:2;18101:5;18097:14;18090:66;18188:42;18226:2;18222;18218:11;18188:42;:::i;:::-;18183:2;18176:5;18172:14;18165:66;18264:43;18302:3;18298:2;18294:12;18264:43;:::i;:::-;18258:3;18251:5;18247:15;18240:68;18341:43;18379:3;18375:2;18371:12;18341:43;:::i;:::-;18335:3;18324:15;;18317:68;18432:3;18424:12;;;18418:19;18401:15;;;18394:44;18485:3;18477:12;;;18471:19;18454:15;;;18447:44;18510:3;18551:11;;;18545:18;18529:14;;;18522:42;18583:3;18624:11;;;18618:18;18602:14;;;18595:42;18656:3;18697:11;;;18691:18;18675:14;;;18668:42;18729:3;18770:11;;;18764:18;18748:14;;;18741:42;18802:3;18837:42;18867:11;;;18837:42;:::i;:::-;18821:14;;;18814:66;18899:3;18940:11;;;18934:18;18918:14;;;18911:42;18972:3;19006:11;;;19000:18;19030:16;;;19027:36;;;19059:1;19056;19049:12;19027:36;19095:55;19142:7;19131:8;19127:2;19123:17;19095:55;:::i;:::-;19079:14;;;19072:79;;;;-1:-1:-1;19083:5:1;17509:1672;-1:-1:-1;;;;;17509:1672:1:o;19820:217::-;19967:2;19956:9;19949:21;19930:4;19987:44;20027:2;20016:9;20012:18;20004:6;19987:44;:::i;20042:132::-;20118:13;;20140:28;20118:13;20140:28;:::i;20179:1188::-;20282:6;20335:3;20323:9;20314:7;20310:23;20306:33;20303:53;;;20352:1;20349;20342:12;20303:53;20378:22;;:::i;:::-;20423:39;20452:9;20423:39;:::i;:::-;20416:5;20409:54;20495:48;20539:2;20528:9;20524:18;20495:48;:::i;:::-;20490:2;20483:5;20479:14;20472:72;20576:49;20621:2;20610:9;20606:18;20576:49;:::i;:::-;20571:2;20564:5;20560:14;20553:73;20658:49;20703:2;20692:9;20688:18;20658:49;:::i;:::-;20653:2;20646:5;20642:14;20635:73;20741:50;20786:3;20775:9;20771:19;20741:50;:::i;:::-;20735:3;20728:5;20724:15;20717:75;20825:50;20870:3;20859:9;20855:19;20825:50;:::i;:::-;20819:3;20812:5;20808:15;20801:75;20930:3;20919:9;20915:19;20909:26;20903:3;20896:5;20892:15;20885:51;20990:3;20979:9;20975:19;20969:26;20963:3;20956:5;20952:15;20945:51;21015:3;21071:2;21060:9;21056:18;21050:25;21045:2;21038:5;21034:14;21027:49;;21095:3;21130:46;21172:2;21161:9;21157:18;21130:46;:::i;:::-;21114:14;;;21107:70;21196:3;21237:18;;;21231:25;21215:14;;;21208:49;21276:3;21317:18;;;21311:25;21295:14;;;21288:49;;;;-1:-1:-1;21118:5:1;20179:1188;-1:-1:-1;20179:1188:1:o;21970:216::-;22034:9;;;22062:11;;;22009:3;22092:9;;22120:10;;22116:19;;22145:10;;22137:19;;22113:44;22110:70;;;22160:18;;:::i;:::-;22110:70;;21970:216;;;;:::o;22191:168::-;22264:9;;;22295;;22312:15;;;22306:22;;22292:37;22282:71;;22333:18;;:::i;22364:274::-;22404:1;22430;22420:189;;22465:77;22462:1;22455:88;22566:4;22563:1;22556:15;22594:4;22591:1;22584:15;22420:189;-1:-1:-1;22623:9:1;;22364:274::o;22643:128::-;22710:9;;;22731:11;;;22728:37;;;22745:18;;:::i;22776:195::-;22815:3;22846:66;22839:5;22836:77;22833:103;;22916:18;;:::i;:::-;-1:-1:-1;22963:1:1;22952:13;;22776:195::o;22976:752::-;23283:3;23272:9;23265:22;23246:4;23304:45;23344:3;23333:9;23329:19;23321:6;23304:45;:::i;:::-;23397:10;23385:23;;;;23380:2;23365:18;;23358:51;-1:-1:-1;;;;;;23506:15:1;;;23501:2;23486:18;;23479:43;23558:15;;;;23553:2;23538:18;;23531:43;23605:3;23590:19;;23583:35;;;;23649:3;23634:19;;23627:35;23706:14;;23699:22;23693:3;23678:19;;;23671:51;23296:53;22976:752;-1:-1:-1;22976:752:1:o;24291:408::-;-1:-1:-1;;;;;24498:6:1;24494:55;24483:9;24476:74;24586:6;24581:2;24570:9;24566:18;24559:34;24629:2;24624;24613:9;24609:18;24602:30;24457:4;24649:44;24689:2;24678:9;24674:18;24666:6;24649:44;:::i;:::-;24641:52;24291:408;-1:-1:-1;;;;;24291:408:1:o;24704:357::-;24822:12;;24869:4;24858:16;;;24852:23;;24822:12;24887:16;;24884:171;;;24977:66;24967:6;24961:4;24957:17;24954:1;24950:25;24946:98;24939:5;24935:110;24926:119;;24884:171;;24704:357;;;:::o;25066:184::-;25136:6;25189:2;25177:9;25168:7;25164:23;25160:32;25157:52;;;25205:1;25202;25195:12;25157:52;-1:-1:-1;25228:16:1;;25066:184;-1:-1:-1;25066:184:1:o;25557:::-;25609:77;25606:1;25599:88;25706:4;25703:1;25696:15;25730:4;25727:1;25720:15;25746:245;25813:6;25866:2;25854:9;25845:7;25841:23;25837:32;25834:52;;;25882:1;25879;25872:12;25834:52;25914:9;25908:16;25933:28;25955:5;25933:28;:::i;25996:287::-;26125:3;26163:6;26157:13;26179:66;26238:6;26233:3;26226:4;26218:6;26214:17;26179:66;:::i;:::-;26261:16;;;;;25996:287;-1:-1:-1;;25996:287:1:o;26288:184::-;26340:77;26337:1;26330:88;26437:4;26434:1;26427:15;26461:4;26458:1;26451:15","abiDefinition":[{"inputs":[{"internalType":"address","name":"_owner","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AccessControlBadConfirmation","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"bytes32","name":"neededRole","type":"bytes32"}],"name":"AccessControlUnauthorizedAccount","type":"error"},{"inputs":[{"internalType":"address","name":"target","type":"address"}],"name":"AddressEmptyCode","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"AddressInsufficientBalance","type":"error"},{"inputs":[],"name":"AmountIncorrect","type":"error"},{"inputs":[],"name":"CallParamsLengthAboveMax","type":"error"},{"inputs":[],"name":"ChainIncorrect","type":"error"},{"inputs":[],"name":"DeadlineExceeded","type":"error"},{"inputs":[],"name":"DeadlineNotExceeded","type":"error"},{"inputs":[],"name":"DeadlineTooShort","type":"error"},{"inputs":[],"name":"DisputePeriodNotPassed","type":"error"},{"inputs":[],"name":"DisputePeriodPassed","type":"error"},{"inputs":[],"name":"ExclusivityParamsIncorrect","type":"error"},{"inputs":[],"name":"ExclusivityPeriodNotPassed","type":"error"},{"inputs":[],"name":"FailedInnerCall","type":"error"},{"inputs":[],"name":"MsgValueIncorrect","type":"error"},{"inputs":[],"name":"NativeTokenCallValueNotSupported","type":"error"},{"inputs":[],"name":"RecipientIncorrectReturnValue","type":"error"},{"inputs":[],"name":"RecipientNoReturnValue","type":"error"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"SafeERC20FailedOperation","type":"error"},{"inputs":[],"name":"SenderIncorrect","type":"error"},{"inputs":[],"name":"StatusIncorrect","type":"error"},{"inputs":[],"name":"TokenNotContract","type":"error"},{"inputs":[],"name":"TransactionRelayed","type":"error"},{"inputs":[],"name":"ZeroAddress","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"relayer","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"BridgeDepositClaimed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"BridgeDepositRefunded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"relayer","type":"address"}],"name":"BridgeProofDisputed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"relayer","type":"address"},{"indexed":false,"internalType":"bytes32","name":"transactionHash","type":"bytes32"}],"name":"BridgeProofProvided","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":false,"internalType":"bytes","name":"quoteId","type":"bytes"}],"name":"BridgeQuoteDetails","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"relayer","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint32","name":"originChainId","type":"uint32"},{"indexed":false,"internalType":"address","name":"originToken","type":"address"},{"indexed":false,"internalType":"address","name":"destToken","type":"address"},{"indexed":false,"internalType":"uint256","name":"originAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"destAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"chainGasAmount","type":"uint256"}],"name":"BridgeRelayed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"bytes","name":"request","type":"bytes"},{"indexed":false,"internalType":"uint32","name":"destChainId","type":"uint32"},{"indexed":false,"internalType":"address","name":"originToken","type":"address"},{"indexed":false,"internalType":"address","name":"destToken","type":"address"},{"indexed":false,"internalType":"uint256","name":"originAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"destAmount","type":"uint256"},{"indexed":false,"internalType":"bool","name":"sendChainGas","type":"bool"}],"name":"BridgeRequested","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldChainGasAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newChainGasAmount","type":"uint256"}],"name":"ChainGasAmountUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldFeeRate","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newFeeRate","type":"uint256"}],"name":"FeeRateUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"address","name":"recipient","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"FeesSwept","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"previousAdminRole","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"newAdminRole","type":"bytes32"}],"name":"RoleAdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleRevoked","type":"event"},{"inputs":[],"name":"DEFAULT_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"DISPUTE_PERIOD","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"FEE_BPS","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"FEE_RATE_MAX","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"GOVERNOR_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"GUARD_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_CALL_PARAMS_LENGTH","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MIN_DEADLINE_PERIOD","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"REFUNDER_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"REFUND_DELAY","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"RELAYER_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"uint32","name":"dstChainId","type":"uint32"},{"internalType":"address","name":"sender","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"address","name":"originToken","type":"address"},{"internalType":"address","name":"destToken","type":"address"},{"internalType":"uint256","name":"originAmount","type":"uint256"},{"internalType":"uint256","name":"destAmount","type":"uint256"},{"internalType":"bool","name":"sendChainGas","type":"bool"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"internalType":"struct IFastBridge.BridgeParams","name":"params","type":"tuple"}],"name":"bridge","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"uint32","name":"dstChainId","type":"uint32"},{"internalType":"address","name":"sender","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"address","name":"originToken","type":"address"},{"internalType":"address","name":"destToken","type":"address"},{"internalType":"uint256","name":"originAmount","type":"uint256"},{"internalType":"uint256","name":"destAmount","type":"uint256"},{"internalType":"bool","name":"sendChainGas","type":"bool"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"internalType":"struct IFastBridge.BridgeParams","name":"params","type":"tuple"},{"components":[{"internalType":"address","name":"quoteRelayer","type":"address"},{"internalType":"int256","name":"quoteExclusivitySeconds","type":"int256"},{"internalType":"bytes","name":"quoteId","type":"bytes"},{"internalType":"uint256","name":"callValue","type":"uint256"},{"internalType":"bytes","name":"callParams","type":"bytes"}],"internalType":"struct IFastBridgeV2.BridgeParamsV2","name":"paramsV2","type":"tuple"}],"name":"bridge","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"transactionId","type":"bytes32"}],"name":"bridgeProofs","outputs":[{"internalType":"uint96","name":"timestamp","type":"uint96"},{"internalType":"address","name":"relayer","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"bridgeRelayDetails","outputs":[{"internalType":"uint48","name":"blockNumber","type":"uint48"},{"internalType":"uint48","name":"blockTimestamp","type":"uint48"},{"internalType":"address","name":"relayer","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"transactionId","type":"bytes32"}],"name":"bridgeRelays","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"transactionId","type":"bytes32"}],"name":"bridgeStatuses","outputs":[{"internalType":"enum IFastBridgeV2.BridgeStatus","name":"status","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"bridgeTxDetails","outputs":[{"internalType":"enum IFastBridgeV2.BridgeStatus","name":"status","type":"uint8"},{"internalType":"uint40","name":"proofBlockTimestamp","type":"uint40"},{"internalType":"uint48","name":"proofBlockNumber","type":"uint48"},{"internalType":"address","name":"proofRelayer","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"internalType":"address","name":"relayer","type":"address"}],"name":"canClaim","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"chainGasAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"},{"internalType":"address","name":"to","type":"address"}],"name":"claim","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"}],"name":"claim","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"deployBlock","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"transactionId","type":"bytes32"}],"name":"dispute","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"}],"name":"getBridgeTransaction","outputs":[{"components":[{"internalType":"uint32","name":"originChainId","type":"uint32"},{"internalType":"uint32","name":"destChainId","type":"uint32"},{"internalType":"address","name":"originSender","type":"address"},{"internalType":"address","name":"destRecipient","type":"address"},{"internalType":"address","name":"originToken","type":"address"},{"internalType":"address","name":"destToken","type":"address"},{"internalType":"uint256","name":"originAmount","type":"uint256"},{"internalType":"uint256","name":"destAmount","type":"uint256"},{"internalType":"uint256","name":"originFeeAmount","type":"uint256"},{"internalType":"bool","name":"sendChainGas","type":"bool"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint256","name":"nonce","type":"uint256"}],"internalType":"struct IFastBridge.BridgeTransaction","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"}],"name":"getBridgeTransactionV2","outputs":[{"components":[{"internalType":"uint32","name":"originChainId","type":"uint32"},{"internalType":"uint32","name":"destChainId","type":"uint32"},{"internalType":"address","name":"originSender","type":"address"},{"internalType":"address","name":"destRecipient","type":"address"},{"internalType":"address","name":"originToken","type":"address"},{"internalType":"address","name":"destToken","type":"address"},{"internalType":"uint256","name":"originAmount","type":"uint256"},{"internalType":"uint256","name":"destAmount","type":"uint256"},{"internalType":"uint256","name":"originFeeAmount","type":"uint256"},{"internalType":"uint256","name":"callValue","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"address","name":"exclusivityRelayer","type":"address"},{"internalType":"uint256","name":"exclusivityEndTime","type":"uint256"},{"internalType":"bytes","name":"callParams","type":"bytes"}],"internalType":"struct IFastBridgeV2.BridgeTransactionV2","name":"","type":"tuple"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleAdmin","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"uint256","name":"index","type":"uint256"}],"name":"getRoleMember","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleMemberCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"grantRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"hasRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"nonce","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"protocolFeeRate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"protocolFees","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"internalType":"bytes32","name":"destTxHash","type":"bytes32"},{"internalType":"address","name":"relayer","type":"address"}],"name":"prove","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"},{"internalType":"bytes32","name":"destTxHash","type":"bytes32"}],"name":"prove","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"}],"name":"refund","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"}],"name":"relay","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"},{"internalType":"address","name":"relayer","type":"address"}],"name":"relay","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"callerConfirmation","type":"address"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"revokeRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"senderNonces","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"newChainGasAmount","type":"uint256"}],"name":"setChainGasAmount","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"newFeeRate","type":"uint256"}],"name":"setProtocolFeeRate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"address","name":"recipient","type":"address"}],"name":"sweepProtocolFees","outputs":[],"stateMutability":"nonpayable","type":"function"}],"userDoc":{"kind":"user","methods":{"DISPUTE_PERIOD()":{"notice":"Dispute period for relayed transactions"},"MAX_CALL_PARAMS_LENGTH()":{"notice":"Maximum length of accepted callParams"},"MIN_DEADLINE_PERIOD()":{"notice":"Minimum deadline period to relay a requested bridge transaction"},"REFUND_DELAY()":{"notice":"Delay for a transaction after which it could be permisionlessly refunded"},"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256))":{"notice":"Initiates bridge on origin chain to be relayed by off-chain relayer"},"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256),(address,int256,bytes,uint256,bytes))":{"notice":"Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability to provide temporary exclusivity fill rights for the quote relayer."},"bridgeProofs(bytes32)":{"notice":"Returns the timestamp and relayer of a bridge proof"},"bridgeRelayDetails(bytes32)":{"notice":"Relay details on destination chain"},"bridgeRelays(bytes32)":{"notice":"Checks if a transaction has been relayed"},"bridgeStatuses(bytes32)":{"notice":"Returns the status of a bridge transaction"},"bridgeTxDetails(bytes32)":{"notice":"Status of the bridge tx on origin chain"},"canClaim(bytes32,address)":{"notice":"Checks if the dispute period has passed so bridge deposit can be claimed"},"chainGasAmount()":{"notice":"Chain gas amount to forward as rebate if requested"},"claim(bytes)":{"notice":"Completes bridge transaction on origin chain by claiming originally deposited capital.Can only send funds to the relayer address on the proof."},"claim(bytes,address)":{"notice":"Completes bridge transaction on origin chain by claiming originally deposited capital"},"deployBlock()":{"notice":"the block the contract was deployed at"},"dispute(bytes32)":{"notice":"Disputes an outstanding proof in case relayer provided dest chain tx is invalid"},"getBridgeTransaction(bytes)":{"notice":"Decodes bridge request into a bridge transaction"},"getBridgeTransactionV2(bytes)":{"notice":"Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2"},"nonce()":{"notice":"This is deprecated and should not be used."},"protocolFeeRate()":{"notice":"Protocol fee rate taken on origin amount deposited in origin chain"},"protocolFees(address)":{"notice":"Protocol fee amounts accumulated"},"prove(bytes,bytes32)":{"notice":"Provides proof on origin side that relayer provided funds on destination side of bridge transaction"},"prove(bytes32,bytes32,address)":{"notice":"Provides proof on origin side that relayer provided funds on destination side of bridge transaction"},"refund(bytes)":{"notice":"Refunds an outstanding bridge transaction in case optimistic bridging failed"},"relay(bytes)":{"notice":"Relays destination side of bridge transaction by off-chain relayer"},"relay(bytes,address)":{"notice":"Relays destination side of bridge transaction by off-chain relayer"},"senderNonces(address)":{"notice":"Unique bridge nonces tracked per originSender"}},"notice":"FastBridgeV2 is a contract for bridging tokens across chains.","version":1},"developerDoc":{"errors":{"AccessControlBadConfirmation()":[{"details":"The caller of a function is not the expected one. NOTE: Don't confuse with {AccessControlUnauthorizedAccount}."}],"AccessControlUnauthorizedAccount(address,bytes32)":[{"details":"The `account` is missing a role."}],"AddressEmptyCode(address)":[{"details":"There's no code at `target` (it is not a contract)."}],"AddressInsufficientBalance(address)":[{"details":"The ETH balance of the account is not enough to perform the operation."}],"FailedInnerCall()":[{"details":"A call to an address target failed. The target may have reverted."}],"SafeERC20FailedOperation(address)":[{"details":"An operation with an ERC20 token failed."}]},"events":{"RoleAdminChanged(bytes32,bytes32,bytes32)":{"details":"Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole` `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite {RoleAdminChanged} not being emitted signaling this."},"RoleGranted(bytes32,address,address)":{"details":"Emitted when `account` is granted `role`. `sender` is the account that originated the contract call, an admin role bearer except when using {AccessControl-_setupRole}."},"RoleRevoked(bytes32,address,address)":{"details":"Emitted when `account` is revoked `role`. `sender` is the account that originated the contract call: - if using `revokeRole`, it is the admin role bearer - if using `renounceRole`, it is the role bearer (i.e. `account`)"}},"kind":"dev","methods":{"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256))":{"params":{"params":"The parameters required to bridge"}},"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256),(address,int256,bytes,uint256,bytes))":{"params":{"params":"The parameters required to bridge","paramsV2":"The parameters for exclusivity fill rights (optional, can be left empty)"}},"bridgeProofs(bytes32)":{"params":{"transactionId":"The ID of the bridge transaction"},"returns":{"relayer":"The relayer address of the bridge proof","timestamp":"The timestamp of the bridge proof"}},"bridgeRelays(bytes32)":{"params":{"transactionId":"The ID of the transaction to check"},"returns":{"_0":"True if the transaction has been relayed, false otherwise"}},"bridgeStatuses(bytes32)":{"params":{"transactionId":"The ID of the bridge transaction"},"returns":{"status":"BridgeStatus Status of the bridge transaction"}},"canClaim(bytes32,address)":{"params":{"relayer":"The address of the relayer attempting to claim","transactionId":"The transaction id associated with the encoded bridge transaction to check"}},"claim(bytes)":{"params":{"request":"The encoded bridge transaction to claim on origin chain"}},"claim(bytes,address)":{"params":{"request":"The encoded bridge transaction to claim on origin chain","to":"The recipient address of the funds"}},"dispute(bytes32)":{"params":{"transactionId":"The transaction id associated with the encoded bridge transaction to dispute"}},"getBridgeTransaction(bytes)":{"details":"This method is added to achieve backwards compatibility with decoding requests into V1 structs: - `callValue` is partially reported as a zero/non-zero flag - `callParams` is ignored In order to process all kinds of requests use getBridgeTransactionV2 instead.","params":{"request":"The bridge request to decode"}},"getBridgeTransactionV2(bytes)":{"params":{"request":"The bridge request to decode"}},"getRoleAdmin(bytes32)":{"details":"Returns the admin role that controls `role`. See {grantRole} and {revokeRole}. To change a role's admin, use {_setRoleAdmin}."},"getRoleMember(bytes32,uint256)":{"details":"Returns one of the accounts that have `role`. `index` must be a value between 0 and {getRoleMemberCount}, non-inclusive. Role bearers are not sorted in any particular way, and their ordering may change at any point. WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure you perform all queries on the same block. See the following https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post] for more information."},"getRoleMemberCount(bytes32)":{"details":"Returns the number of accounts that have `role`. Can be used together with {getRoleMember} to enumerate all bearers of a role."},"grantRole(bytes32,address)":{"details":"Grants `role` to `account`. If `account` had not been already granted `role`, emits a {RoleGranted} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleGranted} event."},"hasRole(bytes32,address)":{"details":"Returns `true` if `account` has been granted `role`."},"prove(bytes,bytes32)":{"params":{"destTxHash":"The destination tx hash proving bridge transaction was relayed","request":"The encoded bridge transaction to prove on origin chain"}},"prove(bytes32,bytes32,address)":{"params":{"destTxHash":"The destination tx hash proving bridge transaction was relayed","relayer":"The address of the relaying entity which should have control of the origin funds when claimed","transactionId":"The transaction id associated with the encoded bridge transaction to prove"}},"refund(bytes)":{"params":{"request":"The encoded bridge transaction to refund"}},"relay(bytes)":{"params":{"request":"The encoded bridge transaction to relay on destination chain"}},"relay(bytes,address)":{"params":{"relayer":"The address of the relaying entity which should have control of the origin funds when claimed","request":"The encoded bridge transaction to relay on destination chain"}},"renounceRole(bytes32,address)":{"details":"Revokes `role` from the calling account. Roles are often managed via {grantRole} and {revokeRole}: this function's purpose is to provide a mechanism for accounts to lose their privileges if they are compromised (such as when a trusted device is misplaced). If the calling account had been revoked `role`, emits a {RoleRevoked} event. Requirements: - the caller must be `callerConfirmation`. May emit a {RoleRevoked} event."},"revokeRole(bytes32,address)":{"details":"Revokes `role` from `account`. If `account` had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleRevoked} event."},"supportsInterface(bytes4)":{"details":"See {IERC165-supportsInterface}."}},"stateVariables":{"nonce":{"details":"Replaced by senderNonces"}},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_owner\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"AccessControlBadConfirmation\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"neededRole\",\"type\":\"bytes32\"}],\"name\":\"AccessControlUnauthorizedAccount\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"}],\"name\":\"AddressEmptyCode\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"AddressInsufficientBalance\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"AmountIncorrect\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"CallParamsLengthAboveMax\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ChainIncorrect\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DeadlineExceeded\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DeadlineNotExceeded\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DeadlineTooShort\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DisputePeriodNotPassed\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DisputePeriodPassed\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ExclusivityParamsIncorrect\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ExclusivityPeriodNotPassed\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"FailedInnerCall\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"MsgValueIncorrect\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"NativeTokenCallValueNotSupported\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"RecipientIncorrectReturnValue\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"RecipientNoReturnValue\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"}],\"name\":\"SafeERC20FailedOperation\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"SenderIncorrect\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"StatusIncorrect\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"TokenNotContract\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"TransactionRelayed\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ZeroAddress\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"BridgeDepositClaimed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"BridgeDepositRefunded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"name\":\"BridgeProofDisputed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"transactionHash\",\"type\":\"bytes32\"}],\"name\":\"BridgeProofProvided\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"quoteId\",\"type\":\"bytes\"}],\"name\":\"BridgeQuoteDetails\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"originChainId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"chainGasAmount\",\"type\":\"uint256\"}],\"name\":\"BridgeRelayed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"destChainId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"sendChainGas\",\"type\":\"bool\"}],\"name\":\"BridgeRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"oldChainGasAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newChainGasAmount\",\"type\":\"uint256\"}],\"name\":\"ChainGasAmountUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"oldFeeRate\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newFeeRate\",\"type\":\"uint256\"}],\"name\":\"FeeRateUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"FeesSwept\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"previousAdminRole\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"newAdminRole\",\"type\":\"bytes32\"}],\"name\":\"RoleAdminChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleGranted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleRevoked\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"DEFAULT_ADMIN_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"DISPUTE_PERIOD\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"FEE_BPS\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"FEE_RATE_MAX\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"GOVERNOR_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"GUARD_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"MAX_CALL_PARAMS_LENGTH\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"MIN_DEADLINE_PERIOD\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"REFUNDER_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"REFUND_DELAY\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"RELAYER_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"dstChainId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"sendChainGas\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"}],\"internalType\":\"struct IFastBridge.BridgeParams\",\"name\":\"params\",\"type\":\"tuple\"}],\"name\":\"bridge\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"dstChainId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"sendChainGas\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"}],\"internalType\":\"struct IFastBridge.BridgeParams\",\"name\":\"params\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"quoteRelayer\",\"type\":\"address\"},{\"internalType\":\"int256\",\"name\":\"quoteExclusivitySeconds\",\"type\":\"int256\"},{\"internalType\":\"bytes\",\"name\":\"quoteId\",\"type\":\"bytes\"},{\"internalType\":\"uint256\",\"name\":\"callValue\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"callParams\",\"type\":\"bytes\"}],\"internalType\":\"struct IFastBridgeV2.BridgeParamsV2\",\"name\":\"paramsV2\",\"type\":\"tuple\"}],\"name\":\"bridge\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"}],\"name\":\"bridgeProofs\",\"outputs\":[{\"internalType\":\"uint96\",\"name\":\"timestamp\",\"type\":\"uint96\"},{\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"bridgeRelayDetails\",\"outputs\":[{\"internalType\":\"uint48\",\"name\":\"blockNumber\",\"type\":\"uint48\"},{\"internalType\":\"uint48\",\"name\":\"blockTimestamp\",\"type\":\"uint48\"},{\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"}],\"name\":\"bridgeRelays\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"}],\"name\":\"bridgeStatuses\",\"outputs\":[{\"internalType\":\"enum IFastBridgeV2.BridgeStatus\",\"name\":\"status\",\"type\":\"uint8\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"bridgeTxDetails\",\"outputs\":[{\"internalType\":\"enum IFastBridgeV2.BridgeStatus\",\"name\":\"status\",\"type\":\"uint8\"},{\"internalType\":\"uint40\",\"name\":\"proofBlockTimestamp\",\"type\":\"uint40\"},{\"internalType\":\"uint48\",\"name\":\"proofBlockNumber\",\"type\":\"uint48\"},{\"internalType\":\"address\",\"name\":\"proofRelayer\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"name\":\"canClaim\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"chainGasAmount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"claim\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"claim\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"deployBlock\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"}],\"name\":\"dispute\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"getBridgeTransaction\",\"outputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"originChainId\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"destChainId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"originSender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destRecipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"originFeeAmount\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"sendChainGas\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"}],\"internalType\":\"struct IFastBridge.BridgeTransaction\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"getBridgeTransactionV2\",\"outputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"originChainId\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"destChainId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"originSender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destRecipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"originFeeAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"callValue\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"exclusivityRelayer\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"exclusivityEndTime\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"callParams\",\"type\":\"bytes\"}],\"internalType\":\"struct IFastBridgeV2.BridgeTransactionV2\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"}],\"name\":\"getRoleAdmin\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"index\",\"type\":\"uint256\"}],\"name\":\"getRoleMember\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"}],\"name\":\"getRoleMemberCount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"grantRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"hasRole\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"nonce\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"protocolFeeRate\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"protocolFees\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"destTxHash\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"name\":\"prove\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"},{\"internalType\":\"bytes32\",\"name\":\"destTxHash\",\"type\":\"bytes32\"}],\"name\":\"prove\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"refund\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"relay\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"},{\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"name\":\"relay\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"callerConfirmation\",\"type\":\"address\"}],\"name\":\"renounceRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"revokeRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"senderNonces\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"newChainGasAmount\",\"type\":\"uint256\"}],\"name\":\"setChainGasAmount\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"newFeeRate\",\"type\":\"uint256\"}],\"name\":\"setProtocolFeeRate\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes4\",\"name\":\"interfaceId\",\"type\":\"bytes4\"}],\"name\":\"supportsInterface\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"}],\"name\":\"sweepProtocolFees\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"errors\":{\"AccessControlBadConfirmation()\":[{\"details\":\"The caller of a function is not the expected one. NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\"}],\"AccessControlUnauthorizedAccount(address,bytes32)\":[{\"details\":\"The `account` is missing a role.\"}],\"AddressEmptyCode(address)\":[{\"details\":\"There's no code at `target` (it is not a contract).\"}],\"AddressInsufficientBalance(address)\":[{\"details\":\"The ETH balance of the account is not enough to perform the operation.\"}],\"FailedInnerCall()\":[{\"details\":\"A call to an address target failed. The target may have reverted.\"}],\"SafeERC20FailedOperation(address)\":[{\"details\":\"An operation with an ERC20 token failed.\"}]},\"events\":{\"RoleAdminChanged(bytes32,bytes32,bytes32)\":{\"details\":\"Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole` `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite {RoleAdminChanged} not being emitted signaling this.\"},\"RoleGranted(bytes32,address,address)\":{\"details\":\"Emitted when `account` is granted `role`. `sender` is the account that originated the contract call, an admin role bearer except when using {AccessControl-_setupRole}.\"},\"RoleRevoked(bytes32,address,address)\":{\"details\":\"Emitted when `account` is revoked `role`. `sender` is the account that originated the contract call: - if using `revokeRole`, it is the admin role bearer - if using `renounceRole`, it is the role bearer (i.e. `account`)\"}},\"kind\":\"dev\",\"methods\":{\"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256))\":{\"params\":{\"params\":\"The parameters required to bridge\"}},\"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256),(address,int256,bytes,uint256,bytes))\":{\"params\":{\"params\":\"The parameters required to bridge\",\"paramsV2\":\"The parameters for exclusivity fill rights (optional, can be left empty)\"}},\"bridgeProofs(bytes32)\":{\"params\":{\"transactionId\":\"The ID of the bridge transaction\"},\"returns\":{\"relayer\":\"The relayer address of the bridge proof\",\"timestamp\":\"The timestamp of the bridge proof\"}},\"bridgeRelays(bytes32)\":{\"params\":{\"transactionId\":\"The ID of the transaction to check\"},\"returns\":{\"_0\":\"True if the transaction has been relayed, false otherwise\"}},\"bridgeStatuses(bytes32)\":{\"params\":{\"transactionId\":\"The ID of the bridge transaction\"},\"returns\":{\"status\":\"BridgeStatus Status of the bridge transaction\"}},\"canClaim(bytes32,address)\":{\"params\":{\"relayer\":\"The address of the relayer attempting to claim\",\"transactionId\":\"The transaction id associated with the encoded bridge transaction to check\"}},\"claim(bytes)\":{\"params\":{\"request\":\"The encoded bridge transaction to claim on origin chain\"}},\"claim(bytes,address)\":{\"params\":{\"request\":\"The encoded bridge transaction to claim on origin chain\",\"to\":\"The recipient address of the funds\"}},\"dispute(bytes32)\":{\"params\":{\"transactionId\":\"The transaction id associated with the encoded bridge transaction to dispute\"}},\"getBridgeTransaction(bytes)\":{\"details\":\"This method is added to achieve backwards compatibility with decoding requests into V1 structs: - `callValue` is partially reported as a zero/non-zero flag - `callParams` is ignored In order to process all kinds of requests use getBridgeTransactionV2 instead.\",\"params\":{\"request\":\"The bridge request to decode\"}},\"getBridgeTransactionV2(bytes)\":{\"params\":{\"request\":\"The bridge request to decode\"}},\"getRoleAdmin(bytes32)\":{\"details\":\"Returns the admin role that controls `role`. See {grantRole} and {revokeRole}. To change a role's admin, use {_setRoleAdmin}.\"},\"getRoleMember(bytes32,uint256)\":{\"details\":\"Returns one of the accounts that have `role`. `index` must be a value between 0 and {getRoleMemberCount}, non-inclusive. Role bearers are not sorted in any particular way, and their ordering may change at any point. WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure you perform all queries on the same block. See the following https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post] for more information.\"},\"getRoleMemberCount(bytes32)\":{\"details\":\"Returns the number of accounts that have `role`. Can be used together with {getRoleMember} to enumerate all bearers of a role.\"},\"grantRole(bytes32,address)\":{\"details\":\"Grants `role` to `account`. If `account` had not been already granted `role`, emits a {RoleGranted} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleGranted} event.\"},\"hasRole(bytes32,address)\":{\"details\":\"Returns `true` if `account` has been granted `role`.\"},\"prove(bytes,bytes32)\":{\"params\":{\"destTxHash\":\"The destination tx hash proving bridge transaction was relayed\",\"request\":\"The encoded bridge transaction to prove on origin chain\"}},\"prove(bytes32,bytes32,address)\":{\"params\":{\"destTxHash\":\"The destination tx hash proving bridge transaction was relayed\",\"relayer\":\"The address of the relaying entity which should have control of the origin funds when claimed\",\"transactionId\":\"The transaction id associated with the encoded bridge transaction to prove\"}},\"refund(bytes)\":{\"params\":{\"request\":\"The encoded bridge transaction to refund\"}},\"relay(bytes)\":{\"params\":{\"request\":\"The encoded bridge transaction to relay on destination chain\"}},\"relay(bytes,address)\":{\"params\":{\"relayer\":\"The address of the relaying entity which should have control of the origin funds when claimed\",\"request\":\"The encoded bridge transaction to relay on destination chain\"}},\"renounceRole(bytes32,address)\":{\"details\":\"Revokes `role` from the calling account. Roles are often managed via {grantRole} and {revokeRole}: this function's purpose is to provide a mechanism for accounts to lose their privileges if they are compromised (such as when a trusted device is misplaced). If the calling account had been revoked `role`, emits a {RoleRevoked} event. Requirements: - the caller must be `callerConfirmation`. May emit a {RoleRevoked} event.\"},\"revokeRole(bytes32,address)\":{\"details\":\"Revokes `role` from `account`. If `account` had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleRevoked} event.\"},\"supportsInterface(bytes4)\":{\"details\":\"See {IERC165-supportsInterface}.\"}},\"stateVariables\":{\"nonce\":{\"details\":\"Replaced by senderNonces\"}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"DISPUTE_PERIOD()\":{\"notice\":\"Dispute period for relayed transactions\"},\"MAX_CALL_PARAMS_LENGTH()\":{\"notice\":\"Maximum length of accepted callParams\"},\"MIN_DEADLINE_PERIOD()\":{\"notice\":\"Minimum deadline period to relay a requested bridge transaction\"},\"REFUND_DELAY()\":{\"notice\":\"Delay for a transaction after which it could be permisionlessly refunded\"},\"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256))\":{\"notice\":\"Initiates bridge on origin chain to be relayed by off-chain relayer\"},\"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256),(address,int256,bytes,uint256,bytes))\":{\"notice\":\"Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability to provide temporary exclusivity fill rights for the quote relayer.\"},\"bridgeProofs(bytes32)\":{\"notice\":\"Returns the timestamp and relayer of a bridge proof\"},\"bridgeRelayDetails(bytes32)\":{\"notice\":\"Relay details on destination chain\"},\"bridgeRelays(bytes32)\":{\"notice\":\"Checks if a transaction has been relayed\"},\"bridgeStatuses(bytes32)\":{\"notice\":\"Returns the status of a bridge transaction\"},\"bridgeTxDetails(bytes32)\":{\"notice\":\"Status of the bridge tx on origin chain\"},\"canClaim(bytes32,address)\":{\"notice\":\"Checks if the dispute period has passed so bridge deposit can be claimed\"},\"chainGasAmount()\":{\"notice\":\"Chain gas amount to forward as rebate if requested\"},\"claim(bytes)\":{\"notice\":\"Completes bridge transaction on origin chain by claiming originally deposited capital.Can only send funds to the relayer address on the proof.\"},\"claim(bytes,address)\":{\"notice\":\"Completes bridge transaction on origin chain by claiming originally deposited capital\"},\"deployBlock()\":{\"notice\":\"the block the contract was deployed at\"},\"dispute(bytes32)\":{\"notice\":\"Disputes an outstanding proof in case relayer provided dest chain tx is invalid\"},\"getBridgeTransaction(bytes)\":{\"notice\":\"Decodes bridge request into a bridge transaction\"},\"getBridgeTransactionV2(bytes)\":{\"notice\":\"Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\"},\"nonce()\":{\"notice\":\"This is deprecated and should not be used.\"},\"protocolFeeRate()\":{\"notice\":\"Protocol fee rate taken on origin amount deposited in origin chain\"},\"protocolFees(address)\":{\"notice\":\"Protocol fee amounts accumulated\"},\"prove(bytes,bytes32)\":{\"notice\":\"Provides proof on origin side that relayer provided funds on destination side of bridge transaction\"},\"prove(bytes32,bytes32,address)\":{\"notice\":\"Provides proof on origin side that relayer provided funds on destination side of bridge transaction\"},\"refund(bytes)\":{\"notice\":\"Refunds an outstanding bridge transaction in case optimistic bridging failed\"},\"relay(bytes)\":{\"notice\":\"Relays destination side of bridge transaction by off-chain relayer\"},\"relay(bytes,address)\":{\"notice\":\"Relays destination side of bridge transaction by off-chain relayer\"},\"senderNonces(address)\":{\"notice\":\"Unique bridge nonces tracked per originSender\"}},\"notice\":\"FastBridgeV2 is a contract for bridging tokens across chains.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeV2.sol\":\"FastBridgeV2\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeV2.sol\":{\"keccak256\":\"0xfd916c030b1ffca5a136817827b8018c8ba42ca089905747f3de6148b73eb35e\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://18e6438c4096deb8ae453fb3365ba2b07d52944e93c08288fc5d012b71bf6bb3\",\"dweb:/ipfs/QmfEMqpT1zz6RRm7UuHLRowe1tds2cTGLrVonfm9XSCACj\"]}},\"version\":1}"},"hashes":{"DEFAULT_ADMIN_ROLE()":"a217fddf","DISPUTE_PERIOD()":"a5bbe22b","FEE_BPS()":"bf333f2c","FEE_RATE_MAX()":"0f5f6ed7","GOVERNOR_ROLE()":"ccc57490","GUARD_ROLE()":"03ed0ee5","MAX_CALL_PARAMS_LENGTH()":"df36bb13","MIN_DEADLINE_PERIOD()":"820688d5","REFUNDER_ROLE()":"5960ccf2","REFUND_DELAY()":"190da595","RELAYER_ROLE()":"926d7d7f","bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256))":"45851694","bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256),(address,int256,bytes,uint256,bytes))":"bfc7c607","bridgeProofs(bytes32)":"91ad5039","bridgeRelayDetails(bytes32)":"c79371b1","bridgeRelays(bytes32)":"8379a24f","bridgeStatuses(bytes32)":"051287bc","bridgeTxDetails(bytes32)":"63787e52","canClaim(bytes32,address)":"aa9641ab","chainGasAmount()":"e00a83e0","claim(bytes)":"c63ff8dd","claim(bytes,address)":"41fcb612","deployBlock()":"a3ec191a","dispute(bytes32)":"add98c70","getBridgeTransaction(bytes)":"ac11fb1a","getBridgeTransactionV2(bytes)":"5aa6ccba","getRoleAdmin(bytes32)":"248a9ca3","getRoleMember(bytes32,uint256)":"9010d07c","getRoleMemberCount(bytes32)":"ca15c873","grantRole(bytes32,address)":"2f2ff15d","hasRole(bytes32,address)":"91d14854","nonce()":"affed0e0","protocolFeeRate()":"58f85880","protocolFees(address)":"dcf844a7","prove(bytes,bytes32)":"886d36ff","prove(bytes32,bytes32,address)":"18e4357d","refund(bytes)":"5eb7d946","relay(bytes)":"8f0d6f17","relay(bytes,address)":"9c9545f0","renounceRole(bytes32,address)":"36568abe","revokeRole(bytes32,address)":"d547741f","senderNonces(address)":"295710ff","setChainGasAmount(uint256)":"b250fe6b","setProtocolFeeRate(uint256)":"b13aa2d6","supportsInterface(bytes4)":"01ffc9a7","sweepProtocolFees(address,address)":"06f333f2"}},"solidity/FastBridgeV2.sol:IAccessControl":{"code":"0x","runtime-code":"0x","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.24 ^0.8.0 ^0.8.20;\n\n// contracts/interfaces/IAdmin.sol\n\ninterface IAdmin {\n // ============ Events ============\n\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n event ChainGasAmountUpdated(uint256 oldChainGasAmount, uint256 newChainGasAmount);\n\n // ============ Methods ============\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n\n function setChainGasAmount(uint256 newChainGasAmount) external;\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IFastBridgeRecipient.sol\n\ninterface IFastBridgeRecipient {\n function fastBridgeTransferReceived(\n address token,\n uint256 amount,\n bytes memory callParams\n )\n external\n payable\n returns (bytes4);\n}\n\n// contracts/interfaces/IFastBridgeV2Errors.sol\n\ninterface IFastBridgeV2Errors {\n error AmountIncorrect();\n error CallParamsLengthAboveMax();\n error ChainIncorrect();\n error ExclusivityParamsIncorrect();\n error MsgValueIncorrect();\n error NativeTokenCallValueNotSupported();\n error SenderIncorrect();\n error StatusIncorrect();\n error ZeroAddress();\n\n error RecipientIncorrectReturnValue();\n error RecipientNoReturnValue();\n\n error DeadlineExceeded();\n error DeadlineNotExceeded();\n error DeadlineTooShort();\n error DisputePeriodNotPassed();\n error DisputePeriodPassed();\n error ExclusivityPeriodNotPassed();\n\n error TransactionRelayed();\n}\n\n// contracts/libs/Errors.sol\n\nerror DeadlineExceeded();\nerror DeadlineNotExceeded();\nerror DeadlineTooShort();\nerror InsufficientOutputAmount();\n\nerror MsgValueIncorrect();\nerror PoolNotFound();\nerror TokenAddressMismatch();\nerror TokenNotContract();\nerror TokenNotETH();\nerror TokensIdentical();\n\nerror ChainIncorrect();\nerror AmountIncorrect();\nerror ZeroAddress();\n\nerror DisputePeriodNotPassed();\nerror DisputePeriodPassed();\nerror SenderIncorrect();\nerror StatusIncorrect();\nerror TransactionIdIncorrect();\nerror TransactionRelayed();\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// contracts/interfaces/IFastBridgeV2.sol\n\ninterface IFastBridgeV2 is IFastBridge {\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n struct BridgeTxDetails {\n BridgeStatus status;\n uint40 proofBlockTimestamp;\n uint48 proofBlockNumber;\n address proofRelayer;\n }\n\n struct BridgeRelay {\n uint48 blockNumber;\n uint48 blockTimestamp;\n address relayer;\n }\n\n /// @notice New params introduced in the FastBridgeV2.\n /// We are passing fields from the older BridgeParams struct outside of this struct\n /// for backwards compatibility.\n /// Note: quoteRelayer and quoteExclusivitySeconds are either both zero (indicating no exclusivity)\n /// or both non-zero (indicating exclusivity for the given period).\n /// Note: callValue \u003e 0 can NOT be used with destToken = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE (ETH_ADDRESS)\n /// @param quoteRelayer Relayer that provided the quote for the transaction\n /// @param quoteExclusivitySeconds Period of time the quote relayer is guaranteed exclusivity after user's deposit\n /// @param quoteId Unique quote identifier used for tracking the quote\n /// @param callValue ETH value to send to the recipient (if any)\n /// @param callParams Parameters for the arbitrary call to the destination recipient (if any)\n struct BridgeParamsV2 {\n address quoteRelayer;\n int256 quoteExclusivitySeconds;\n bytes quoteId;\n uint256 callValue;\n bytes callParams;\n }\n\n /// @notice Updated bridge transaction struct to include parameters introduced in FastBridgeV2.\n /// Note: only `exclusivityRelayer` can fill such a transaction until `exclusivityEndTime`.\n /// TODO: consider changing the encoding scheme to prevent spending extra gas on decoding.\n struct BridgeTransactionV2 {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n uint256 callValue; // ETH value to send to the recipient (if any) - replaces V1's sendChainGas flag\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n address exclusivityRelayer;\n uint256 exclusivityEndTime;\n bytes callParams;\n }\n\n event BridgeQuoteDetails(bytes32 indexed transactionId, bytes quoteId);\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability\n /// to provide temporary exclusivity fill rights for the quote relayer.\n /// @param params The parameters required to bridge\n /// @param paramsV2 The parameters for exclusivity fill rights (optional, can be left empty)\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function relay(bytes memory request, address relayer) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param transactionId The transaction id associated with the encoded bridge transaction to prove\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital.\n /// @notice Can only send funds to the relayer address on the proof.\n /// @param request The encoded bridge transaction to claim on origin chain\n function claim(bytes memory request) external;\n /// @notice Checks if a transaction has been relayed\n /// @param transactionId The ID of the transaction to check\n /// @return True if the transaction has been relayed, false otherwise\n function bridgeRelays(bytes32 transactionId) external view returns (bool);\n\n /// @notice Returns the status of a bridge transaction\n /// @param transactionId The ID of the bridge transaction\n /// @return BridgeStatus Status of the bridge transaction\n function bridgeStatuses(bytes32 transactionId) external view returns (BridgeStatus);\n\n /// @notice Returns the timestamp and relayer of a bridge proof\n /// @param transactionId The ID of the bridge transaction\n /// @return timestamp The timestamp of the bridge proof\n /// @return relayer The relayer address of the bridge proof\n function bridgeProofs(bytes32 transactionId) external view returns (uint96 timestamp, address relayer);\n\n /// @notice Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\n /// @param request The bridge request to decode\n function getBridgeTransactionV2(bytes memory request) external view returns (BridgeTransactionV2 memory);\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// contracts/libs/UniversalToken.sol\n\nlibrary UniversalTokenLib {\n using SafeERC20 for IERC20;\n\n address internal constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Transfers tokens to the given account. Reverts if transfer is not successful.\n /// @dev This might trigger fallback, if ETH is transferred to the contract.\n /// Make sure this can not lead to reentrancy attacks.\n function universalTransfer(address token, address to, uint256 value) internal {\n // Don't do anything, if need to send tokens to this address\n if (to == address(this)) return;\n // Don't do anything, if trying to send zero value\n if (value == 0) return;\n if (token == ETH_ADDRESS) {\n /// @dev Note: this can potentially lead to executing code in `to`.\n // solhint-disable-next-line avoid-low-level-calls\n (bool success,) = to.call{value: value}(\"\");\n require(success, \"ETH transfer failed\");\n } else {\n IERC20(token).safeTransfer(to, value);\n }\n }\n\n /// @notice Issues an infinite allowance to the spender, if the current allowance is insufficient\n /// to spend the given amount.\n function universalApproveInfinity(address token, address spender, uint256 amountToSpend) internal {\n // ETH Chad doesn't require your approval\n if (token == ETH_ADDRESS) return;\n // No-op if allowance is already sufficient\n uint256 allowance = IERC20(token).allowance(address(this), spender);\n if (allowance \u003e= amountToSpend) return;\n // Otherwise, reset approval to 0 and set to max allowance\n if (allowance \u003e 0) IERC20(token).safeDecreaseAllowance(spender, allowance);\n IERC20(token).safeIncreaseAllowance(spender, type(uint256).max);\n }\n\n /// @notice Returns the balance of the given token (or native ETH) for the given account.\n function universalBalanceOf(address token, address account) internal view returns (uint256) {\n if (token == ETH_ADDRESS) {\n return account.balance;\n } else {\n return IERC20(token).balanceOf(account);\n }\n }\n\n /// @dev Checks that token is a contract and not ETH_ADDRESS.\n function assertIsContract(address token) internal view {\n // Check that ETH_ADDRESS was not used (in case this is a predeploy on any of the chains)\n if (token == UniversalTokenLib.ETH_ADDRESS) revert TokenNotContract();\n // Check that token is not an EOA\n if (token.code.length == 0) revert TokenNotContract();\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/Admin.sol\n\ncontract Admin is IAdmin, AccessControlEnumerable {\n using UniversalTokenLib for address;\n\n bytes32 public constant RELAYER_ROLE = keccak256(\"RELAYER_ROLE\");\n bytes32 public constant REFUNDER_ROLE = keccak256(\"REFUNDER_ROLE\");\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n uint256 public constant FEE_BPS = 1e6;\n uint256 public constant FEE_RATE_MAX = 0.01e6; // max 1% on origin amount\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Chain gas amount to forward as rebate if requested\n uint256 public chainGasAmount;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n }\n\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n require(newFeeRate \u003c= FEE_RATE_MAX, \"newFeeRate \u003e max\");\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n token.universalTransfer(recipient, feeAmount);\n emit FeesSwept(token, recipient, feeAmount);\n }\n\n function setChainGasAmount(uint256 newChainGasAmount) external onlyRole(GOVERNOR_ROLE) {\n uint256 oldChainGasAmount = chainGasAmount;\n chainGasAmount = newChainGasAmount;\n emit ChainGasAmountUpdated(oldChainGasAmount, newChainGasAmount);\n }\n}\n\n// contracts/FastBridgeV2.sol\n\n/// @notice FastBridgeV2 is a contract for bridging tokens across chains.\ncontract FastBridgeV2 is Admin, IFastBridgeV2, IFastBridgeV2Errors {\n using SafeERC20 for IERC20;\n using UniversalTokenLib for address;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Delay for a transaction after which it could be permisionlessly refunded\n uint256 public constant REFUND_DELAY = 7 days;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n /// @notice Maximum length of accepted callParams\n uint256 public constant MAX_CALL_PARAMS_LENGTH = 2 ** 16 - 1;\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeTxDetails) public bridgeTxDetails;\n /// @notice Relay details on destination chain\n mapping(bytes32 =\u003e BridgeRelay) public bridgeRelayDetails;\n /// @notice Unique bridge nonces tracked per originSender\n mapping(address =\u003e uint256) public senderNonces;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Replaced by senderNonces\n uint256 public immutable nonce = 0;\n /// @notice the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n bridge({\n params: params,\n paramsV2: BridgeParamsV2({\n quoteRelayer: address(0),\n quoteExclusivitySeconds: 0,\n quoteId: bytes(\"\"),\n callValue: 0,\n callParams: bytes(\"\")\n })\n });\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes memory request) external payable {\n relay({request: request, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes memory request, bytes32 destTxHash) external {\n prove({transactionId: keccak256(request), destTxHash: destTxHash, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridgeV2\n function claim(bytes memory request) external {\n claim({request: request, to: address(0)});\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003e DISPUTE_PERIOD) {\n revert DisputePeriodPassed();\n }\n\n // @dev relayer gets slashed effectively if dest relay has gone thru\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n bridgeTxDetails[transactionId].proofRelayer = address(0);\n bridgeTxDetails[transactionId].proofBlockTimestamp = 0;\n bridgeTxDetails[transactionId].proofBlockNumber = 0;\n\n emit BridgeProofDisputed(transactionId, msg.sender);\n }\n\n /// @inheritdoc IFastBridge\n function refund(bytes memory request) external {\n bytes32 transactionId = keccak256(request);\n\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n\n if (bridgeTxDetails[transactionId].status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n\n if (hasRole(REFUNDER_ROLE, msg.sender)) {\n // Refunder can refund if deadline has passed\n if (block.timestamp \u003c= transaction.deadline) revert DeadlineNotExceeded();\n } else {\n // Permissionless refund is allowed after REFUND_DELAY\n if (block.timestamp \u003c= transaction.deadline + REFUND_DELAY) revert DeadlineNotExceeded();\n }\n\n // if all checks passed, set to REFUNDED status\n bridgeTxDetails[transactionId].status = BridgeStatus.REFUNDED;\n\n // transfer origin collateral back to original sender\n address to = transaction.originSender;\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount + transaction.originFeeAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (bridgeTxDetails[transactionId].proofRelayer != relayer) revert SenderIncorrect();\n return _timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n /// @dev This method is added to achieve backwards compatibility with decoding requests into V1 structs:\n /// - `callValue` is partially reported as a zero/non-zero flag\n /// - `callParams` is ignored\n /// In order to process all kinds of requests use getBridgeTransactionV2 instead.\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory) {\n // Try decoding into V2 struct first. This will revert if V1 struct is passed\n try this.getBridgeTransactionV2(request) returns (BridgeTransactionV2 memory txV2) {\n // Note: we entirely ignore the callParams field, as it was not present in V1\n return BridgeTransaction({\n originChainId: txV2.originChainId,\n destChainId: txV2.destChainId,\n originSender: txV2.originSender,\n destRecipient: txV2.destRecipient,\n originToken: txV2.originToken,\n destToken: txV2.destToken,\n originAmount: txV2.originAmount,\n destAmount: txV2.destAmount,\n originFeeAmount: txV2.originFeeAmount,\n sendChainGas: txV2.callValue != 0,\n deadline: txV2.deadline,\n nonce: txV2.nonce\n });\n } catch {\n // Fallback to V1 struct\n return abi.decode(request, (BridgeTransaction));\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) public payable {\n int256 exclusivityEndTime = int256(block.timestamp) + paramsV2.quoteExclusivitySeconds;\n _validateBridgeParams(params, paramsV2, exclusivityEndTime);\n\n // transfer tokens to bridge contract\n /// @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _takeBridgedUserAsset(params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n\n // set status to requested\n bytes memory request = abi.encode(\n BridgeTransactionV2({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n callValue: paramsV2.callValue,\n deadline: params.deadline,\n nonce: senderNonces[params.sender]++, // increment nonce on every bridge\n exclusivityRelayer: paramsV2.quoteRelayer,\n // We checked exclusivityEndTime to be in range (0 .. params.deadline] above, so can safely cast\n exclusivityEndTime: uint256(exclusivityEndTime),\n callParams: paramsV2.callParams\n })\n );\n bytes32 transactionId = keccak256(request);\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n\n emit BridgeRequested({\n transactionId: transactionId,\n sender: params.sender,\n request: request,\n destChainId: params.dstChainId,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n sendChainGas: paramsV2.callValue != 0\n });\n emit BridgeQuoteDetails(transactionId, paramsV2.quoteId);\n }\n\n /// @inheritdoc IFastBridgeV2\n function relay(bytes memory request, address relayer) public payable {\n bytes32 transactionId = keccak256(request);\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n _validateRelayParams(transaction, transactionId, relayer);\n // mark bridge transaction as relayed\n bridgeRelayDetails[transactionId] =\n BridgeRelay({blockNumber: uint48(block.number), blockTimestamp: uint48(block.timestamp), relayer: relayer});\n\n // transfer tokens to recipient on destination chain and do an arbitrary call if requested\n address to = transaction.destRecipient;\n address token = transaction.destToken;\n uint256 amount = transaction.destAmount;\n uint256 callValue = transaction.callValue;\n\n // Emit the event before any external calls\n emit BridgeRelayed({\n transactionId: transactionId,\n relayer: relayer,\n to: to,\n originChainId: transaction.originChainId,\n originToken: transaction.originToken,\n destToken: token,\n originAmount: transaction.originAmount,\n destAmount: amount,\n chainGasAmount: callValue\n });\n\n // All state changes have been done at this point, can proceed to the external calls.\n // This follows the checks-effects-interactions pattern to mitigate potential reentrancy attacks.\n if (token == UniversalTokenLib.ETH_ADDRESS) {\n // For ETH non-zero callValue is not allowed\n if (callValue != 0) revert NativeTokenCallValueNotSupported();\n // Check that the correct msg.value was sent\n if (msg.value != amount) revert MsgValueIncorrect();\n } else {\n // For ERC20s, we check that the correct msg.value was sent\n if (msg.value != callValue) revert MsgValueIncorrect();\n // We need to transfer the tokens from the Relayer to the recipient first before performing an\n // optional post-transfer arbitrary call.\n IERC20(token).safeTransferFrom(msg.sender, to, amount);\n }\n\n if (transaction.callParams.length != 0) {\n // Arbitrary call requested, perform it while supplying full msg.value to the recipient\n // Note: if token has a fee on transfers, the recipient will have received less than `amount`.\n // This is a very niche edge case and should be handled by the recipient contract.\n _checkedCallRecipient({recipient: to, token: token, amount: amount, callParams: transaction.callParams});\n } else if (msg.value != 0) {\n // No arbitrary call requested, but msg.value was sent. This is either a relay with ETH,\n // or a non-zero callValue request with an ERC20. In both cases, transfer the ETH to the recipient.\n Address.sendValue(payable(to), msg.value);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) public onlyRole(RELAYER_ROLE) {\n // update bridge tx status given proof provided\n if (bridgeTxDetails[transactionId].status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n bridgeTxDetails[transactionId].status = BridgeStatus.RELAYER_PROVED;\n bridgeTxDetails[transactionId].proofBlockTimestamp = uint40(block.timestamp);\n bridgeTxDetails[transactionId].proofBlockNumber = uint48(block.number);\n bridgeTxDetails[transactionId].proofRelayer = relayer;\n\n emit BridgeProofProvided(transactionId, relayer, destTxHash);\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes memory request, address to) public {\n bytes32 transactionId = keccak256(request);\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n\n // update bridge tx status if able to claim origin collateral\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n\n // if \"to\" is zero addr, permissionlessly send funds to proven relayer\n if (to == address(0)) {\n to = bridgeTxDetails[transactionId].proofRelayer;\n } else if (bridgeTxDetails[transactionId].proofRelayer != msg.sender) {\n revert SenderIncorrect();\n }\n\n if (_timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003c= DISPUTE_PERIOD) {\n revert DisputePeriodNotPassed();\n }\n\n bridgeTxDetails[transactionId].status = BridgeStatus.RELAYER_CLAIMED;\n\n // update protocol fees if origin fee amount exists\n if (transaction.originFeeAmount \u003e 0) protocolFees[transaction.originToken] += transaction.originFeeAmount;\n\n // transfer origin collateral less fee to specified address\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositClaimed(transactionId, bridgeTxDetails[transactionId].proofRelayer, to, token, amount);\n }\n\n function bridgeStatuses(bytes32 transactionId) public view returns (BridgeStatus status) {\n return bridgeTxDetails[transactionId].status;\n }\n\n function bridgeProofs(bytes32 transactionId) public view returns (uint96 timestamp, address relayer) {\n timestamp = bridgeTxDetails[transactionId].proofBlockTimestamp;\n relayer = bridgeTxDetails[transactionId].proofRelayer;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeRelays(bytes32 transactionId) public view returns (bool) {\n // has this transactionId been relayed?\n return bridgeRelayDetails[transactionId].relayer != address(0);\n }\n\n /// @inheritdoc IFastBridgeV2\n function getBridgeTransactionV2(bytes memory request) public pure returns (BridgeTransactionV2 memory) {\n return abi.decode(request, (BridgeTransactionV2));\n }\n\n /// @notice Takes the bridged asset from the user into FastBridgeV2 custody. It will be later\n /// claimed by the relayer who completed the relay on destination chain, or refunded back to the user,\n /// should no one complete the relay.\n function _takeBridgedUserAsset(address token, uint256 amount) internal returns (uint256 amountTaken) {\n if (token == UniversalTokenLib.ETH_ADDRESS) {\n // For ETH we just need to check that the supplied msg.value is correct.\n // Supplied `msg.value` is already in FastBridgeV2 custody.\n if (amount != msg.value) revert MsgValueIncorrect();\n amountTaken = msg.value;\n } else {\n // For ERC20s, token is explicitly transferred from the user to FastBridgeV2.\n // We don't allow non-zero `msg.value` to avoid extra funds from being stuck in FastBridgeV2.\n token.assertIsContract();\n if (msg.value != 0) revert MsgValueIncorrect();\n amountTaken = IERC20(token).balanceOf(address(this));\n IERC20(token).safeTransferFrom(msg.sender, address(this), amount);\n // Use the balance difference as the amount taken in case of fee on transfer tokens.\n amountTaken = IERC20(token).balanceOf(address(this)) - amountTaken;\n }\n }\n\n /// @notice Calls the Recipient's hook function with the specified callParams and performs\n /// all the necessary checks for the returned value.\n function _checkedCallRecipient(\n address recipient,\n address token,\n uint256 amount,\n bytes memory callParams\n )\n internal\n {\n bytes memory hookData =\n abi.encodeCall(IFastBridgeRecipient.fastBridgeTransferReceived, (token, amount, callParams));\n // This will bubble any revert messages from the hook function\n bytes memory returnData = Address.functionCallWithValue({target: recipient, data: hookData, value: msg.value});\n // Explicit revert if no return data at all\n if (returnData.length == 0) revert RecipientNoReturnValue();\n // Check that exactly a single return value was returned\n if (returnData.length != 32) revert RecipientIncorrectReturnValue();\n // Return value should be abi-encoded hook function selector\n if (bytes32(returnData) != bytes32(IFastBridgeRecipient.fastBridgeTransferReceived.selector)) {\n revert RecipientIncorrectReturnValue();\n }\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint40(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint40).max but\n /// proof.timestamp \u003c type(uint40).max via unchecked statement\n /// @param proofBlockTimestamp The bridge proof block timestamp\n /// @return delta Time delta since proof submitted\n function _timeSince(uint40 proofBlockTimestamp) internal view returns (uint256 delta) {\n unchecked {\n delta = uint40(block.timestamp) - proofBlockTimestamp;\n }\n }\n\n /// @notice Performs all the necessary checks for a bridge to happen.\n /// @dev There's no good way to refactor this function to reduce cyclomatic complexity due to\n /// the number of checks that need to be performed, so we skip the code-complexity rule here.\n // solhint-disable-next-line code-complexity\n function _validateBridgeParams(\n BridgeParams memory params,\n BridgeParamsV2 memory paramsV2,\n int256 exclusivityEndTime\n )\n internal\n view\n {\n // Check V1 (legacy) params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.sender == address(0) || params.to == address(0)) revert ZeroAddress();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n // Check V2 params\n if (paramsV2.callParams.length \u003e MAX_CALL_PARAMS_LENGTH) revert CallParamsLengthAboveMax();\n if (paramsV2.callValue != 0 \u0026\u0026 params.destToken == UniversalTokenLib.ETH_ADDRESS) {\n revert NativeTokenCallValueNotSupported();\n }\n // exclusivityEndTime must be in range (0 .. params.deadline]\n if (exclusivityEndTime \u003c= 0 || exclusivityEndTime \u003e int256(params.deadline)) {\n revert ExclusivityParamsIncorrect();\n }\n }\n\n /// @notice Performs all the necessary checks for a relay to happen.\n function _validateRelayParams(\n BridgeTransactionV2 memory transaction,\n bytes32 transactionId,\n address relayer\n )\n internal\n view\n {\n if (relayer == address(0)) revert ZeroAddress();\n // Check if the transaction has already been relayed\n if (bridgeRelays(transactionId)) revert TransactionRelayed();\n if (transaction.destChainId != block.chainid) revert ChainIncorrect();\n // Check the deadline for relay to happen\n if (block.timestamp \u003e transaction.deadline) revert DeadlineExceeded();\n // Check the exclusivity period, if it is still ongoing\n // forgefmt: disable-next-item\n if (\n transaction.exclusivityRelayer != address(0) \u0026\u0026\n transaction.exclusivityRelayer != relayer \u0026\u0026\n block.timestamp \u003c= transaction.exclusivityEndTime\n ) {\n revert ExclusivityPeriodNotPassed();\n }\n }\n}\n","language":"Solidity","languageVersion":"0.8.24","compilerVersion":"0.8.24","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"","srcMapRuntime":"","abiDefinition":[{"inputs":[],"name":"AccessControlBadConfirmation","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"bytes32","name":"neededRole","type":"bytes32"}],"name":"AccessControlUnauthorizedAccount","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"previousAdminRole","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"newAdminRole","type":"bytes32"}],"name":"RoleAdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleRevoked","type":"event"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleAdmin","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"grantRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"hasRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"callerConfirmation","type":"address"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"revokeRole","outputs":[],"stateMutability":"nonpayable","type":"function"}],"userDoc":{"kind":"user","methods":{},"version":1},"developerDoc":{"details":"External interface of AccessControl declared to support ERC165 detection.","errors":{"AccessControlBadConfirmation()":[{"details":"The caller of a function is not the expected one. NOTE: Don't confuse with {AccessControlUnauthorizedAccount}."}],"AccessControlUnauthorizedAccount(address,bytes32)":[{"details":"The `account` is missing a role."}]},"events":{"RoleAdminChanged(bytes32,bytes32,bytes32)":{"details":"Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole` `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite {RoleAdminChanged} not being emitted signaling this."},"RoleGranted(bytes32,address,address)":{"details":"Emitted when `account` is granted `role`. `sender` is the account that originated the contract call, an admin role bearer except when using {AccessControl-_setupRole}."},"RoleRevoked(bytes32,address,address)":{"details":"Emitted when `account` is revoked `role`. `sender` is the account that originated the contract call: - if using `revokeRole`, it is the admin role bearer - if using `renounceRole`, it is the role bearer (i.e. `account`)"}},"kind":"dev","methods":{"getRoleAdmin(bytes32)":{"details":"Returns the admin role that controls `role`. See {grantRole} and {revokeRole}. To change a role's admin, use {AccessControl-_setRoleAdmin}."},"grantRole(bytes32,address)":{"details":"Grants `role` to `account`. If `account` had not been already granted `role`, emits a {RoleGranted} event. Requirements: - the caller must have ``role``'s admin role."},"hasRole(bytes32,address)":{"details":"Returns `true` if `account` has been granted `role`."},"renounceRole(bytes32,address)":{"details":"Revokes `role` from the calling account. Roles are often managed via {grantRole} and {revokeRole}: this function's purpose is to provide a mechanism for accounts to lose their privileges if they are compromised (such as when a trusted device is misplaced). If the calling account had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must be `callerConfirmation`."},"revokeRole(bytes32,address)":{"details":"Revokes `role` from `account`. If `account` had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must have ``role``'s admin role."}},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[],\"name\":\"AccessControlBadConfirmation\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"neededRole\",\"type\":\"bytes32\"}],\"name\":\"AccessControlUnauthorizedAccount\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"previousAdminRole\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"newAdminRole\",\"type\":\"bytes32\"}],\"name\":\"RoleAdminChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleGranted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleRevoked\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"}],\"name\":\"getRoleAdmin\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"grantRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"hasRole\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"callerConfirmation\",\"type\":\"address\"}],\"name\":\"renounceRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"revokeRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"details\":\"External interface of AccessControl declared to support ERC165 detection.\",\"errors\":{\"AccessControlBadConfirmation()\":[{\"details\":\"The caller of a function is not the expected one. NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\"}],\"AccessControlUnauthorizedAccount(address,bytes32)\":[{\"details\":\"The `account` is missing a role.\"}]},\"events\":{\"RoleAdminChanged(bytes32,bytes32,bytes32)\":{\"details\":\"Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole` `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite {RoleAdminChanged} not being emitted signaling this.\"},\"RoleGranted(bytes32,address,address)\":{\"details\":\"Emitted when `account` is granted `role`. `sender` is the account that originated the contract call, an admin role bearer except when using {AccessControl-_setupRole}.\"},\"RoleRevoked(bytes32,address,address)\":{\"details\":\"Emitted when `account` is revoked `role`. `sender` is the account that originated the contract call: - if using `revokeRole`, it is the admin role bearer - if using `renounceRole`, it is the role bearer (i.e. `account`)\"}},\"kind\":\"dev\",\"methods\":{\"getRoleAdmin(bytes32)\":{\"details\":\"Returns the admin role that controls `role`. See {grantRole} and {revokeRole}. To change a role's admin, use {AccessControl-_setRoleAdmin}.\"},\"grantRole(bytes32,address)\":{\"details\":\"Grants `role` to `account`. If `account` had not been already granted `role`, emits a {RoleGranted} event. Requirements: - the caller must have ``role``'s admin role.\"},\"hasRole(bytes32,address)\":{\"details\":\"Returns `true` if `account` has been granted `role`.\"},\"renounceRole(bytes32,address)\":{\"details\":\"Revokes `role` from the calling account. Roles are often managed via {grantRole} and {revokeRole}: this function's purpose is to provide a mechanism for accounts to lose their privileges if they are compromised (such as when a trusted device is misplaced). If the calling account had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must be `callerConfirmation`.\"},\"revokeRole(bytes32,address)\":{\"details\":\"Revokes `role` from `account`. If `account` had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must have ``role``'s admin role.\"}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeV2.sol\":\"IAccessControl\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeV2.sol\":{\"keccak256\":\"0xfd916c030b1ffca5a136817827b8018c8ba42ca089905747f3de6148b73eb35e\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://18e6438c4096deb8ae453fb3365ba2b07d52944e93c08288fc5d012b71bf6bb3\",\"dweb:/ipfs/QmfEMqpT1zz6RRm7UuHLRowe1tds2cTGLrVonfm9XSCACj\"]}},\"version\":1}"},"hashes":{"getRoleAdmin(bytes32)":"248a9ca3","grantRole(bytes32,address)":"2f2ff15d","hasRole(bytes32,address)":"91d14854","renounceRole(bytes32,address)":"36568abe","revokeRole(bytes32,address)":"d547741f"}},"solidity/FastBridgeV2.sol:IAccessControlEnumerable":{"code":"0x","runtime-code":"0x","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.24 ^0.8.0 ^0.8.20;\n\n// contracts/interfaces/IAdmin.sol\n\ninterface IAdmin {\n // ============ Events ============\n\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n event ChainGasAmountUpdated(uint256 oldChainGasAmount, uint256 newChainGasAmount);\n\n // ============ Methods ============\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n\n function setChainGasAmount(uint256 newChainGasAmount) external;\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IFastBridgeRecipient.sol\n\ninterface IFastBridgeRecipient {\n function fastBridgeTransferReceived(\n address token,\n uint256 amount,\n bytes memory callParams\n )\n external\n payable\n returns (bytes4);\n}\n\n// contracts/interfaces/IFastBridgeV2Errors.sol\n\ninterface IFastBridgeV2Errors {\n error AmountIncorrect();\n error CallParamsLengthAboveMax();\n error ChainIncorrect();\n error ExclusivityParamsIncorrect();\n error MsgValueIncorrect();\n error NativeTokenCallValueNotSupported();\n error SenderIncorrect();\n error StatusIncorrect();\n error ZeroAddress();\n\n error RecipientIncorrectReturnValue();\n error RecipientNoReturnValue();\n\n error DeadlineExceeded();\n error DeadlineNotExceeded();\n error DeadlineTooShort();\n error DisputePeriodNotPassed();\n error DisputePeriodPassed();\n error ExclusivityPeriodNotPassed();\n\n error TransactionRelayed();\n}\n\n// contracts/libs/Errors.sol\n\nerror DeadlineExceeded();\nerror DeadlineNotExceeded();\nerror DeadlineTooShort();\nerror InsufficientOutputAmount();\n\nerror MsgValueIncorrect();\nerror PoolNotFound();\nerror TokenAddressMismatch();\nerror TokenNotContract();\nerror TokenNotETH();\nerror TokensIdentical();\n\nerror ChainIncorrect();\nerror AmountIncorrect();\nerror ZeroAddress();\n\nerror DisputePeriodNotPassed();\nerror DisputePeriodPassed();\nerror SenderIncorrect();\nerror StatusIncorrect();\nerror TransactionIdIncorrect();\nerror TransactionRelayed();\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// contracts/interfaces/IFastBridgeV2.sol\n\ninterface IFastBridgeV2 is IFastBridge {\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n struct BridgeTxDetails {\n BridgeStatus status;\n uint40 proofBlockTimestamp;\n uint48 proofBlockNumber;\n address proofRelayer;\n }\n\n struct BridgeRelay {\n uint48 blockNumber;\n uint48 blockTimestamp;\n address relayer;\n }\n\n /// @notice New params introduced in the FastBridgeV2.\n /// We are passing fields from the older BridgeParams struct outside of this struct\n /// for backwards compatibility.\n /// Note: quoteRelayer and quoteExclusivitySeconds are either both zero (indicating no exclusivity)\n /// or both non-zero (indicating exclusivity for the given period).\n /// Note: callValue \u003e 0 can NOT be used with destToken = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE (ETH_ADDRESS)\n /// @param quoteRelayer Relayer that provided the quote for the transaction\n /// @param quoteExclusivitySeconds Period of time the quote relayer is guaranteed exclusivity after user's deposit\n /// @param quoteId Unique quote identifier used for tracking the quote\n /// @param callValue ETH value to send to the recipient (if any)\n /// @param callParams Parameters for the arbitrary call to the destination recipient (if any)\n struct BridgeParamsV2 {\n address quoteRelayer;\n int256 quoteExclusivitySeconds;\n bytes quoteId;\n uint256 callValue;\n bytes callParams;\n }\n\n /// @notice Updated bridge transaction struct to include parameters introduced in FastBridgeV2.\n /// Note: only `exclusivityRelayer` can fill such a transaction until `exclusivityEndTime`.\n /// TODO: consider changing the encoding scheme to prevent spending extra gas on decoding.\n struct BridgeTransactionV2 {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n uint256 callValue; // ETH value to send to the recipient (if any) - replaces V1's sendChainGas flag\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n address exclusivityRelayer;\n uint256 exclusivityEndTime;\n bytes callParams;\n }\n\n event BridgeQuoteDetails(bytes32 indexed transactionId, bytes quoteId);\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability\n /// to provide temporary exclusivity fill rights for the quote relayer.\n /// @param params The parameters required to bridge\n /// @param paramsV2 The parameters for exclusivity fill rights (optional, can be left empty)\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function relay(bytes memory request, address relayer) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param transactionId The transaction id associated with the encoded bridge transaction to prove\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital.\n /// @notice Can only send funds to the relayer address on the proof.\n /// @param request The encoded bridge transaction to claim on origin chain\n function claim(bytes memory request) external;\n /// @notice Checks if a transaction has been relayed\n /// @param transactionId The ID of the transaction to check\n /// @return True if the transaction has been relayed, false otherwise\n function bridgeRelays(bytes32 transactionId) external view returns (bool);\n\n /// @notice Returns the status of a bridge transaction\n /// @param transactionId The ID of the bridge transaction\n /// @return BridgeStatus Status of the bridge transaction\n function bridgeStatuses(bytes32 transactionId) external view returns (BridgeStatus);\n\n /// @notice Returns the timestamp and relayer of a bridge proof\n /// @param transactionId The ID of the bridge transaction\n /// @return timestamp The timestamp of the bridge proof\n /// @return relayer The relayer address of the bridge proof\n function bridgeProofs(bytes32 transactionId) external view returns (uint96 timestamp, address relayer);\n\n /// @notice Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\n /// @param request The bridge request to decode\n function getBridgeTransactionV2(bytes memory request) external view returns (BridgeTransactionV2 memory);\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// contracts/libs/UniversalToken.sol\n\nlibrary UniversalTokenLib {\n using SafeERC20 for IERC20;\n\n address internal constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Transfers tokens to the given account. Reverts if transfer is not successful.\n /// @dev This might trigger fallback, if ETH is transferred to the contract.\n /// Make sure this can not lead to reentrancy attacks.\n function universalTransfer(address token, address to, uint256 value) internal {\n // Don't do anything, if need to send tokens to this address\n if (to == address(this)) return;\n // Don't do anything, if trying to send zero value\n if (value == 0) return;\n if (token == ETH_ADDRESS) {\n /// @dev Note: this can potentially lead to executing code in `to`.\n // solhint-disable-next-line avoid-low-level-calls\n (bool success,) = to.call{value: value}(\"\");\n require(success, \"ETH transfer failed\");\n } else {\n IERC20(token).safeTransfer(to, value);\n }\n }\n\n /// @notice Issues an infinite allowance to the spender, if the current allowance is insufficient\n /// to spend the given amount.\n function universalApproveInfinity(address token, address spender, uint256 amountToSpend) internal {\n // ETH Chad doesn't require your approval\n if (token == ETH_ADDRESS) return;\n // No-op if allowance is already sufficient\n uint256 allowance = IERC20(token).allowance(address(this), spender);\n if (allowance \u003e= amountToSpend) return;\n // Otherwise, reset approval to 0 and set to max allowance\n if (allowance \u003e 0) IERC20(token).safeDecreaseAllowance(spender, allowance);\n IERC20(token).safeIncreaseAllowance(spender, type(uint256).max);\n }\n\n /// @notice Returns the balance of the given token (or native ETH) for the given account.\n function universalBalanceOf(address token, address account) internal view returns (uint256) {\n if (token == ETH_ADDRESS) {\n return account.balance;\n } else {\n return IERC20(token).balanceOf(account);\n }\n }\n\n /// @dev Checks that token is a contract and not ETH_ADDRESS.\n function assertIsContract(address token) internal view {\n // Check that ETH_ADDRESS was not used (in case this is a predeploy on any of the chains)\n if (token == UniversalTokenLib.ETH_ADDRESS) revert TokenNotContract();\n // Check that token is not an EOA\n if (token.code.length == 0) revert TokenNotContract();\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/Admin.sol\n\ncontract Admin is IAdmin, AccessControlEnumerable {\n using UniversalTokenLib for address;\n\n bytes32 public constant RELAYER_ROLE = keccak256(\"RELAYER_ROLE\");\n bytes32 public constant REFUNDER_ROLE = keccak256(\"REFUNDER_ROLE\");\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n uint256 public constant FEE_BPS = 1e6;\n uint256 public constant FEE_RATE_MAX = 0.01e6; // max 1% on origin amount\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Chain gas amount to forward as rebate if requested\n uint256 public chainGasAmount;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n }\n\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n require(newFeeRate \u003c= FEE_RATE_MAX, \"newFeeRate \u003e max\");\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n token.universalTransfer(recipient, feeAmount);\n emit FeesSwept(token, recipient, feeAmount);\n }\n\n function setChainGasAmount(uint256 newChainGasAmount) external onlyRole(GOVERNOR_ROLE) {\n uint256 oldChainGasAmount = chainGasAmount;\n chainGasAmount = newChainGasAmount;\n emit ChainGasAmountUpdated(oldChainGasAmount, newChainGasAmount);\n }\n}\n\n// contracts/FastBridgeV2.sol\n\n/// @notice FastBridgeV2 is a contract for bridging tokens across chains.\ncontract FastBridgeV2 is Admin, IFastBridgeV2, IFastBridgeV2Errors {\n using SafeERC20 for IERC20;\n using UniversalTokenLib for address;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Delay for a transaction after which it could be permisionlessly refunded\n uint256 public constant REFUND_DELAY = 7 days;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n /// @notice Maximum length of accepted callParams\n uint256 public constant MAX_CALL_PARAMS_LENGTH = 2 ** 16 - 1;\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeTxDetails) public bridgeTxDetails;\n /// @notice Relay details on destination chain\n mapping(bytes32 =\u003e BridgeRelay) public bridgeRelayDetails;\n /// @notice Unique bridge nonces tracked per originSender\n mapping(address =\u003e uint256) public senderNonces;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Replaced by senderNonces\n uint256 public immutable nonce = 0;\n /// @notice the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n bridge({\n params: params,\n paramsV2: BridgeParamsV2({\n quoteRelayer: address(0),\n quoteExclusivitySeconds: 0,\n quoteId: bytes(\"\"),\n callValue: 0,\n callParams: bytes(\"\")\n })\n });\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes memory request) external payable {\n relay({request: request, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes memory request, bytes32 destTxHash) external {\n prove({transactionId: keccak256(request), destTxHash: destTxHash, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridgeV2\n function claim(bytes memory request) external {\n claim({request: request, to: address(0)});\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003e DISPUTE_PERIOD) {\n revert DisputePeriodPassed();\n }\n\n // @dev relayer gets slashed effectively if dest relay has gone thru\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n bridgeTxDetails[transactionId].proofRelayer = address(0);\n bridgeTxDetails[transactionId].proofBlockTimestamp = 0;\n bridgeTxDetails[transactionId].proofBlockNumber = 0;\n\n emit BridgeProofDisputed(transactionId, msg.sender);\n }\n\n /// @inheritdoc IFastBridge\n function refund(bytes memory request) external {\n bytes32 transactionId = keccak256(request);\n\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n\n if (bridgeTxDetails[transactionId].status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n\n if (hasRole(REFUNDER_ROLE, msg.sender)) {\n // Refunder can refund if deadline has passed\n if (block.timestamp \u003c= transaction.deadline) revert DeadlineNotExceeded();\n } else {\n // Permissionless refund is allowed after REFUND_DELAY\n if (block.timestamp \u003c= transaction.deadline + REFUND_DELAY) revert DeadlineNotExceeded();\n }\n\n // if all checks passed, set to REFUNDED status\n bridgeTxDetails[transactionId].status = BridgeStatus.REFUNDED;\n\n // transfer origin collateral back to original sender\n address to = transaction.originSender;\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount + transaction.originFeeAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (bridgeTxDetails[transactionId].proofRelayer != relayer) revert SenderIncorrect();\n return _timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n /// @dev This method is added to achieve backwards compatibility with decoding requests into V1 structs:\n /// - `callValue` is partially reported as a zero/non-zero flag\n /// - `callParams` is ignored\n /// In order to process all kinds of requests use getBridgeTransactionV2 instead.\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory) {\n // Try decoding into V2 struct first. This will revert if V1 struct is passed\n try this.getBridgeTransactionV2(request) returns (BridgeTransactionV2 memory txV2) {\n // Note: we entirely ignore the callParams field, as it was not present in V1\n return BridgeTransaction({\n originChainId: txV2.originChainId,\n destChainId: txV2.destChainId,\n originSender: txV2.originSender,\n destRecipient: txV2.destRecipient,\n originToken: txV2.originToken,\n destToken: txV2.destToken,\n originAmount: txV2.originAmount,\n destAmount: txV2.destAmount,\n originFeeAmount: txV2.originFeeAmount,\n sendChainGas: txV2.callValue != 0,\n deadline: txV2.deadline,\n nonce: txV2.nonce\n });\n } catch {\n // Fallback to V1 struct\n return abi.decode(request, (BridgeTransaction));\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) public payable {\n int256 exclusivityEndTime = int256(block.timestamp) + paramsV2.quoteExclusivitySeconds;\n _validateBridgeParams(params, paramsV2, exclusivityEndTime);\n\n // transfer tokens to bridge contract\n /// @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _takeBridgedUserAsset(params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n\n // set status to requested\n bytes memory request = abi.encode(\n BridgeTransactionV2({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n callValue: paramsV2.callValue,\n deadline: params.deadline,\n nonce: senderNonces[params.sender]++, // increment nonce on every bridge\n exclusivityRelayer: paramsV2.quoteRelayer,\n // We checked exclusivityEndTime to be in range (0 .. params.deadline] above, so can safely cast\n exclusivityEndTime: uint256(exclusivityEndTime),\n callParams: paramsV2.callParams\n })\n );\n bytes32 transactionId = keccak256(request);\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n\n emit BridgeRequested({\n transactionId: transactionId,\n sender: params.sender,\n request: request,\n destChainId: params.dstChainId,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n sendChainGas: paramsV2.callValue != 0\n });\n emit BridgeQuoteDetails(transactionId, paramsV2.quoteId);\n }\n\n /// @inheritdoc IFastBridgeV2\n function relay(bytes memory request, address relayer) public payable {\n bytes32 transactionId = keccak256(request);\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n _validateRelayParams(transaction, transactionId, relayer);\n // mark bridge transaction as relayed\n bridgeRelayDetails[transactionId] =\n BridgeRelay({blockNumber: uint48(block.number), blockTimestamp: uint48(block.timestamp), relayer: relayer});\n\n // transfer tokens to recipient on destination chain and do an arbitrary call if requested\n address to = transaction.destRecipient;\n address token = transaction.destToken;\n uint256 amount = transaction.destAmount;\n uint256 callValue = transaction.callValue;\n\n // Emit the event before any external calls\n emit BridgeRelayed({\n transactionId: transactionId,\n relayer: relayer,\n to: to,\n originChainId: transaction.originChainId,\n originToken: transaction.originToken,\n destToken: token,\n originAmount: transaction.originAmount,\n destAmount: amount,\n chainGasAmount: callValue\n });\n\n // All state changes have been done at this point, can proceed to the external calls.\n // This follows the checks-effects-interactions pattern to mitigate potential reentrancy attacks.\n if (token == UniversalTokenLib.ETH_ADDRESS) {\n // For ETH non-zero callValue is not allowed\n if (callValue != 0) revert NativeTokenCallValueNotSupported();\n // Check that the correct msg.value was sent\n if (msg.value != amount) revert MsgValueIncorrect();\n } else {\n // For ERC20s, we check that the correct msg.value was sent\n if (msg.value != callValue) revert MsgValueIncorrect();\n // We need to transfer the tokens from the Relayer to the recipient first before performing an\n // optional post-transfer arbitrary call.\n IERC20(token).safeTransferFrom(msg.sender, to, amount);\n }\n\n if (transaction.callParams.length != 0) {\n // Arbitrary call requested, perform it while supplying full msg.value to the recipient\n // Note: if token has a fee on transfers, the recipient will have received less than `amount`.\n // This is a very niche edge case and should be handled by the recipient contract.\n _checkedCallRecipient({recipient: to, token: token, amount: amount, callParams: transaction.callParams});\n } else if (msg.value != 0) {\n // No arbitrary call requested, but msg.value was sent. This is either a relay with ETH,\n // or a non-zero callValue request with an ERC20. In both cases, transfer the ETH to the recipient.\n Address.sendValue(payable(to), msg.value);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) public onlyRole(RELAYER_ROLE) {\n // update bridge tx status given proof provided\n if (bridgeTxDetails[transactionId].status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n bridgeTxDetails[transactionId].status = BridgeStatus.RELAYER_PROVED;\n bridgeTxDetails[transactionId].proofBlockTimestamp = uint40(block.timestamp);\n bridgeTxDetails[transactionId].proofBlockNumber = uint48(block.number);\n bridgeTxDetails[transactionId].proofRelayer = relayer;\n\n emit BridgeProofProvided(transactionId, relayer, destTxHash);\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes memory request, address to) public {\n bytes32 transactionId = keccak256(request);\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n\n // update bridge tx status if able to claim origin collateral\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n\n // if \"to\" is zero addr, permissionlessly send funds to proven relayer\n if (to == address(0)) {\n to = bridgeTxDetails[transactionId].proofRelayer;\n } else if (bridgeTxDetails[transactionId].proofRelayer != msg.sender) {\n revert SenderIncorrect();\n }\n\n if (_timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003c= DISPUTE_PERIOD) {\n revert DisputePeriodNotPassed();\n }\n\n bridgeTxDetails[transactionId].status = BridgeStatus.RELAYER_CLAIMED;\n\n // update protocol fees if origin fee amount exists\n if (transaction.originFeeAmount \u003e 0) protocolFees[transaction.originToken] += transaction.originFeeAmount;\n\n // transfer origin collateral less fee to specified address\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositClaimed(transactionId, bridgeTxDetails[transactionId].proofRelayer, to, token, amount);\n }\n\n function bridgeStatuses(bytes32 transactionId) public view returns (BridgeStatus status) {\n return bridgeTxDetails[transactionId].status;\n }\n\n function bridgeProofs(bytes32 transactionId) public view returns (uint96 timestamp, address relayer) {\n timestamp = bridgeTxDetails[transactionId].proofBlockTimestamp;\n relayer = bridgeTxDetails[transactionId].proofRelayer;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeRelays(bytes32 transactionId) public view returns (bool) {\n // has this transactionId been relayed?\n return bridgeRelayDetails[transactionId].relayer != address(0);\n }\n\n /// @inheritdoc IFastBridgeV2\n function getBridgeTransactionV2(bytes memory request) public pure returns (BridgeTransactionV2 memory) {\n return abi.decode(request, (BridgeTransactionV2));\n }\n\n /// @notice Takes the bridged asset from the user into FastBridgeV2 custody. It will be later\n /// claimed by the relayer who completed the relay on destination chain, or refunded back to the user,\n /// should no one complete the relay.\n function _takeBridgedUserAsset(address token, uint256 amount) internal returns (uint256 amountTaken) {\n if (token == UniversalTokenLib.ETH_ADDRESS) {\n // For ETH we just need to check that the supplied msg.value is correct.\n // Supplied `msg.value` is already in FastBridgeV2 custody.\n if (amount != msg.value) revert MsgValueIncorrect();\n amountTaken = msg.value;\n } else {\n // For ERC20s, token is explicitly transferred from the user to FastBridgeV2.\n // We don't allow non-zero `msg.value` to avoid extra funds from being stuck in FastBridgeV2.\n token.assertIsContract();\n if (msg.value != 0) revert MsgValueIncorrect();\n amountTaken = IERC20(token).balanceOf(address(this));\n IERC20(token).safeTransferFrom(msg.sender, address(this), amount);\n // Use the balance difference as the amount taken in case of fee on transfer tokens.\n amountTaken = IERC20(token).balanceOf(address(this)) - amountTaken;\n }\n }\n\n /// @notice Calls the Recipient's hook function with the specified callParams and performs\n /// all the necessary checks for the returned value.\n function _checkedCallRecipient(\n address recipient,\n address token,\n uint256 amount,\n bytes memory callParams\n )\n internal\n {\n bytes memory hookData =\n abi.encodeCall(IFastBridgeRecipient.fastBridgeTransferReceived, (token, amount, callParams));\n // This will bubble any revert messages from the hook function\n bytes memory returnData = Address.functionCallWithValue({target: recipient, data: hookData, value: msg.value});\n // Explicit revert if no return data at all\n if (returnData.length == 0) revert RecipientNoReturnValue();\n // Check that exactly a single return value was returned\n if (returnData.length != 32) revert RecipientIncorrectReturnValue();\n // Return value should be abi-encoded hook function selector\n if (bytes32(returnData) != bytes32(IFastBridgeRecipient.fastBridgeTransferReceived.selector)) {\n revert RecipientIncorrectReturnValue();\n }\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint40(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint40).max but\n /// proof.timestamp \u003c type(uint40).max via unchecked statement\n /// @param proofBlockTimestamp The bridge proof block timestamp\n /// @return delta Time delta since proof submitted\n function _timeSince(uint40 proofBlockTimestamp) internal view returns (uint256 delta) {\n unchecked {\n delta = uint40(block.timestamp) - proofBlockTimestamp;\n }\n }\n\n /// @notice Performs all the necessary checks for a bridge to happen.\n /// @dev There's no good way to refactor this function to reduce cyclomatic complexity due to\n /// the number of checks that need to be performed, so we skip the code-complexity rule here.\n // solhint-disable-next-line code-complexity\n function _validateBridgeParams(\n BridgeParams memory params,\n BridgeParamsV2 memory paramsV2,\n int256 exclusivityEndTime\n )\n internal\n view\n {\n // Check V1 (legacy) params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.sender == address(0) || params.to == address(0)) revert ZeroAddress();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n // Check V2 params\n if (paramsV2.callParams.length \u003e MAX_CALL_PARAMS_LENGTH) revert CallParamsLengthAboveMax();\n if (paramsV2.callValue != 0 \u0026\u0026 params.destToken == UniversalTokenLib.ETH_ADDRESS) {\n revert NativeTokenCallValueNotSupported();\n }\n // exclusivityEndTime must be in range (0 .. params.deadline]\n if (exclusivityEndTime \u003c= 0 || exclusivityEndTime \u003e int256(params.deadline)) {\n revert ExclusivityParamsIncorrect();\n }\n }\n\n /// @notice Performs all the necessary checks for a relay to happen.\n function _validateRelayParams(\n BridgeTransactionV2 memory transaction,\n bytes32 transactionId,\n address relayer\n )\n internal\n view\n {\n if (relayer == address(0)) revert ZeroAddress();\n // Check if the transaction has already been relayed\n if (bridgeRelays(transactionId)) revert TransactionRelayed();\n if (transaction.destChainId != block.chainid) revert ChainIncorrect();\n // Check the deadline for relay to happen\n if (block.timestamp \u003e transaction.deadline) revert DeadlineExceeded();\n // Check the exclusivity period, if it is still ongoing\n // forgefmt: disable-next-item\n if (\n transaction.exclusivityRelayer != address(0) \u0026\u0026\n transaction.exclusivityRelayer != relayer \u0026\u0026\n block.timestamp \u003c= transaction.exclusivityEndTime\n ) {\n revert ExclusivityPeriodNotPassed();\n }\n }\n}\n","language":"Solidity","languageVersion":"0.8.24","compilerVersion":"0.8.24","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"","srcMapRuntime":"","abiDefinition":[{"inputs":[],"name":"AccessControlBadConfirmation","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"bytes32","name":"neededRole","type":"bytes32"}],"name":"AccessControlUnauthorizedAccount","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"previousAdminRole","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"newAdminRole","type":"bytes32"}],"name":"RoleAdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleRevoked","type":"event"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleAdmin","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"uint256","name":"index","type":"uint256"}],"name":"getRoleMember","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleMemberCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"grantRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"hasRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"callerConfirmation","type":"address"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"revokeRole","outputs":[],"stateMutability":"nonpayable","type":"function"}],"userDoc":{"kind":"user","methods":{},"version":1},"developerDoc":{"details":"External interface of AccessControlEnumerable declared to support ERC165 detection.","errors":{"AccessControlBadConfirmation()":[{"details":"The caller of a function is not the expected one. NOTE: Don't confuse with {AccessControlUnauthorizedAccount}."}],"AccessControlUnauthorizedAccount(address,bytes32)":[{"details":"The `account` is missing a role."}]},"events":{"RoleAdminChanged(bytes32,bytes32,bytes32)":{"details":"Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole` `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite {RoleAdminChanged} not being emitted signaling this."},"RoleGranted(bytes32,address,address)":{"details":"Emitted when `account` is granted `role`. `sender` is the account that originated the contract call, an admin role bearer except when using {AccessControl-_setupRole}."},"RoleRevoked(bytes32,address,address)":{"details":"Emitted when `account` is revoked `role`. `sender` is the account that originated the contract call: - if using `revokeRole`, it is the admin role bearer - if using `renounceRole`, it is the role bearer (i.e. `account`)"}},"kind":"dev","methods":{"getRoleAdmin(bytes32)":{"details":"Returns the admin role that controls `role`. See {grantRole} and {revokeRole}. To change a role's admin, use {AccessControl-_setRoleAdmin}."},"getRoleMember(bytes32,uint256)":{"details":"Returns one of the accounts that have `role`. `index` must be a value between 0 and {getRoleMemberCount}, non-inclusive. Role bearers are not sorted in any particular way, and their ordering may change at any point. WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure you perform all queries on the same block. See the following https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post] for more information."},"getRoleMemberCount(bytes32)":{"details":"Returns the number of accounts that have `role`. Can be used together with {getRoleMember} to enumerate all bearers of a role."},"grantRole(bytes32,address)":{"details":"Grants `role` to `account`. If `account` had not been already granted `role`, emits a {RoleGranted} event. Requirements: - the caller must have ``role``'s admin role."},"hasRole(bytes32,address)":{"details":"Returns `true` if `account` has been granted `role`."},"renounceRole(bytes32,address)":{"details":"Revokes `role` from the calling account. Roles are often managed via {grantRole} and {revokeRole}: this function's purpose is to provide a mechanism for accounts to lose their privileges if they are compromised (such as when a trusted device is misplaced). If the calling account had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must be `callerConfirmation`."},"revokeRole(bytes32,address)":{"details":"Revokes `role` from `account`. If `account` had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must have ``role``'s admin role."}},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[],\"name\":\"AccessControlBadConfirmation\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"neededRole\",\"type\":\"bytes32\"}],\"name\":\"AccessControlUnauthorizedAccount\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"previousAdminRole\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"newAdminRole\",\"type\":\"bytes32\"}],\"name\":\"RoleAdminChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleGranted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleRevoked\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"}],\"name\":\"getRoleAdmin\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"index\",\"type\":\"uint256\"}],\"name\":\"getRoleMember\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"}],\"name\":\"getRoleMemberCount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"grantRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"hasRole\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"callerConfirmation\",\"type\":\"address\"}],\"name\":\"renounceRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"revokeRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"details\":\"External interface of AccessControlEnumerable declared to support ERC165 detection.\",\"errors\":{\"AccessControlBadConfirmation()\":[{\"details\":\"The caller of a function is not the expected one. NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\"}],\"AccessControlUnauthorizedAccount(address,bytes32)\":[{\"details\":\"The `account` is missing a role.\"}]},\"events\":{\"RoleAdminChanged(bytes32,bytes32,bytes32)\":{\"details\":\"Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole` `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite {RoleAdminChanged} not being emitted signaling this.\"},\"RoleGranted(bytes32,address,address)\":{\"details\":\"Emitted when `account` is granted `role`. `sender` is the account that originated the contract call, an admin role bearer except when using {AccessControl-_setupRole}.\"},\"RoleRevoked(bytes32,address,address)\":{\"details\":\"Emitted when `account` is revoked `role`. `sender` is the account that originated the contract call: - if using `revokeRole`, it is the admin role bearer - if using `renounceRole`, it is the role bearer (i.e. `account`)\"}},\"kind\":\"dev\",\"methods\":{\"getRoleAdmin(bytes32)\":{\"details\":\"Returns the admin role that controls `role`. See {grantRole} and {revokeRole}. To change a role's admin, use {AccessControl-_setRoleAdmin}.\"},\"getRoleMember(bytes32,uint256)\":{\"details\":\"Returns one of the accounts that have `role`. `index` must be a value between 0 and {getRoleMemberCount}, non-inclusive. Role bearers are not sorted in any particular way, and their ordering may change at any point. WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure you perform all queries on the same block. See the following https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post] for more information.\"},\"getRoleMemberCount(bytes32)\":{\"details\":\"Returns the number of accounts that have `role`. Can be used together with {getRoleMember} to enumerate all bearers of a role.\"},\"grantRole(bytes32,address)\":{\"details\":\"Grants `role` to `account`. If `account` had not been already granted `role`, emits a {RoleGranted} event. Requirements: - the caller must have ``role``'s admin role.\"},\"hasRole(bytes32,address)\":{\"details\":\"Returns `true` if `account` has been granted `role`.\"},\"renounceRole(bytes32,address)\":{\"details\":\"Revokes `role` from the calling account. Roles are often managed via {grantRole} and {revokeRole}: this function's purpose is to provide a mechanism for accounts to lose their privileges if they are compromised (such as when a trusted device is misplaced). If the calling account had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must be `callerConfirmation`.\"},\"revokeRole(bytes32,address)\":{\"details\":\"Revokes `role` from `account`. If `account` had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must have ``role``'s admin role.\"}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeV2.sol\":\"IAccessControlEnumerable\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeV2.sol\":{\"keccak256\":\"0xfd916c030b1ffca5a136817827b8018c8ba42ca089905747f3de6148b73eb35e\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://18e6438c4096deb8ae453fb3365ba2b07d52944e93c08288fc5d012b71bf6bb3\",\"dweb:/ipfs/QmfEMqpT1zz6RRm7UuHLRowe1tds2cTGLrVonfm9XSCACj\"]}},\"version\":1}"},"hashes":{"getRoleAdmin(bytes32)":"248a9ca3","getRoleMember(bytes32,uint256)":"9010d07c","getRoleMemberCount(bytes32)":"ca15c873","grantRole(bytes32,address)":"2f2ff15d","hasRole(bytes32,address)":"91d14854","renounceRole(bytes32,address)":"36568abe","revokeRole(bytes32,address)":"d547741f"}},"solidity/FastBridgeV2.sol:IAdmin":{"code":"0x","runtime-code":"0x","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.24 ^0.8.0 ^0.8.20;\n\n// contracts/interfaces/IAdmin.sol\n\ninterface IAdmin {\n // ============ Events ============\n\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n event ChainGasAmountUpdated(uint256 oldChainGasAmount, uint256 newChainGasAmount);\n\n // ============ Methods ============\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n\n function setChainGasAmount(uint256 newChainGasAmount) external;\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IFastBridgeRecipient.sol\n\ninterface IFastBridgeRecipient {\n function fastBridgeTransferReceived(\n address token,\n uint256 amount,\n bytes memory callParams\n )\n external\n payable\n returns (bytes4);\n}\n\n// contracts/interfaces/IFastBridgeV2Errors.sol\n\ninterface IFastBridgeV2Errors {\n error AmountIncorrect();\n error CallParamsLengthAboveMax();\n error ChainIncorrect();\n error ExclusivityParamsIncorrect();\n error MsgValueIncorrect();\n error NativeTokenCallValueNotSupported();\n error SenderIncorrect();\n error StatusIncorrect();\n error ZeroAddress();\n\n error RecipientIncorrectReturnValue();\n error RecipientNoReturnValue();\n\n error DeadlineExceeded();\n error DeadlineNotExceeded();\n error DeadlineTooShort();\n error DisputePeriodNotPassed();\n error DisputePeriodPassed();\n error ExclusivityPeriodNotPassed();\n\n error TransactionRelayed();\n}\n\n// contracts/libs/Errors.sol\n\nerror DeadlineExceeded();\nerror DeadlineNotExceeded();\nerror DeadlineTooShort();\nerror InsufficientOutputAmount();\n\nerror MsgValueIncorrect();\nerror PoolNotFound();\nerror TokenAddressMismatch();\nerror TokenNotContract();\nerror TokenNotETH();\nerror TokensIdentical();\n\nerror ChainIncorrect();\nerror AmountIncorrect();\nerror ZeroAddress();\n\nerror DisputePeriodNotPassed();\nerror DisputePeriodPassed();\nerror SenderIncorrect();\nerror StatusIncorrect();\nerror TransactionIdIncorrect();\nerror TransactionRelayed();\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// contracts/interfaces/IFastBridgeV2.sol\n\ninterface IFastBridgeV2 is IFastBridge {\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n struct BridgeTxDetails {\n BridgeStatus status;\n uint40 proofBlockTimestamp;\n uint48 proofBlockNumber;\n address proofRelayer;\n }\n\n struct BridgeRelay {\n uint48 blockNumber;\n uint48 blockTimestamp;\n address relayer;\n }\n\n /// @notice New params introduced in the FastBridgeV2.\n /// We are passing fields from the older BridgeParams struct outside of this struct\n /// for backwards compatibility.\n /// Note: quoteRelayer and quoteExclusivitySeconds are either both zero (indicating no exclusivity)\n /// or both non-zero (indicating exclusivity for the given period).\n /// Note: callValue \u003e 0 can NOT be used with destToken = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE (ETH_ADDRESS)\n /// @param quoteRelayer Relayer that provided the quote for the transaction\n /// @param quoteExclusivitySeconds Period of time the quote relayer is guaranteed exclusivity after user's deposit\n /// @param quoteId Unique quote identifier used for tracking the quote\n /// @param callValue ETH value to send to the recipient (if any)\n /// @param callParams Parameters for the arbitrary call to the destination recipient (if any)\n struct BridgeParamsV2 {\n address quoteRelayer;\n int256 quoteExclusivitySeconds;\n bytes quoteId;\n uint256 callValue;\n bytes callParams;\n }\n\n /// @notice Updated bridge transaction struct to include parameters introduced in FastBridgeV2.\n /// Note: only `exclusivityRelayer` can fill such a transaction until `exclusivityEndTime`.\n /// TODO: consider changing the encoding scheme to prevent spending extra gas on decoding.\n struct BridgeTransactionV2 {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n uint256 callValue; // ETH value to send to the recipient (if any) - replaces V1's sendChainGas flag\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n address exclusivityRelayer;\n uint256 exclusivityEndTime;\n bytes callParams;\n }\n\n event BridgeQuoteDetails(bytes32 indexed transactionId, bytes quoteId);\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability\n /// to provide temporary exclusivity fill rights for the quote relayer.\n /// @param params The parameters required to bridge\n /// @param paramsV2 The parameters for exclusivity fill rights (optional, can be left empty)\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function relay(bytes memory request, address relayer) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param transactionId The transaction id associated with the encoded bridge transaction to prove\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital.\n /// @notice Can only send funds to the relayer address on the proof.\n /// @param request The encoded bridge transaction to claim on origin chain\n function claim(bytes memory request) external;\n /// @notice Checks if a transaction has been relayed\n /// @param transactionId The ID of the transaction to check\n /// @return True if the transaction has been relayed, false otherwise\n function bridgeRelays(bytes32 transactionId) external view returns (bool);\n\n /// @notice Returns the status of a bridge transaction\n /// @param transactionId The ID of the bridge transaction\n /// @return BridgeStatus Status of the bridge transaction\n function bridgeStatuses(bytes32 transactionId) external view returns (BridgeStatus);\n\n /// @notice Returns the timestamp and relayer of a bridge proof\n /// @param transactionId The ID of the bridge transaction\n /// @return timestamp The timestamp of the bridge proof\n /// @return relayer The relayer address of the bridge proof\n function bridgeProofs(bytes32 transactionId) external view returns (uint96 timestamp, address relayer);\n\n /// @notice Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\n /// @param request The bridge request to decode\n function getBridgeTransactionV2(bytes memory request) external view returns (BridgeTransactionV2 memory);\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// contracts/libs/UniversalToken.sol\n\nlibrary UniversalTokenLib {\n using SafeERC20 for IERC20;\n\n address internal constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Transfers tokens to the given account. Reverts if transfer is not successful.\n /// @dev This might trigger fallback, if ETH is transferred to the contract.\n /// Make sure this can not lead to reentrancy attacks.\n function universalTransfer(address token, address to, uint256 value) internal {\n // Don't do anything, if need to send tokens to this address\n if (to == address(this)) return;\n // Don't do anything, if trying to send zero value\n if (value == 0) return;\n if (token == ETH_ADDRESS) {\n /// @dev Note: this can potentially lead to executing code in `to`.\n // solhint-disable-next-line avoid-low-level-calls\n (bool success,) = to.call{value: value}(\"\");\n require(success, \"ETH transfer failed\");\n } else {\n IERC20(token).safeTransfer(to, value);\n }\n }\n\n /// @notice Issues an infinite allowance to the spender, if the current allowance is insufficient\n /// to spend the given amount.\n function universalApproveInfinity(address token, address spender, uint256 amountToSpend) internal {\n // ETH Chad doesn't require your approval\n if (token == ETH_ADDRESS) return;\n // No-op if allowance is already sufficient\n uint256 allowance = IERC20(token).allowance(address(this), spender);\n if (allowance \u003e= amountToSpend) return;\n // Otherwise, reset approval to 0 and set to max allowance\n if (allowance \u003e 0) IERC20(token).safeDecreaseAllowance(spender, allowance);\n IERC20(token).safeIncreaseAllowance(spender, type(uint256).max);\n }\n\n /// @notice Returns the balance of the given token (or native ETH) for the given account.\n function universalBalanceOf(address token, address account) internal view returns (uint256) {\n if (token == ETH_ADDRESS) {\n return account.balance;\n } else {\n return IERC20(token).balanceOf(account);\n }\n }\n\n /// @dev Checks that token is a contract and not ETH_ADDRESS.\n function assertIsContract(address token) internal view {\n // Check that ETH_ADDRESS was not used (in case this is a predeploy on any of the chains)\n if (token == UniversalTokenLib.ETH_ADDRESS) revert TokenNotContract();\n // Check that token is not an EOA\n if (token.code.length == 0) revert TokenNotContract();\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/Admin.sol\n\ncontract Admin is IAdmin, AccessControlEnumerable {\n using UniversalTokenLib for address;\n\n bytes32 public constant RELAYER_ROLE = keccak256(\"RELAYER_ROLE\");\n bytes32 public constant REFUNDER_ROLE = keccak256(\"REFUNDER_ROLE\");\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n uint256 public constant FEE_BPS = 1e6;\n uint256 public constant FEE_RATE_MAX = 0.01e6; // max 1% on origin amount\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Chain gas amount to forward as rebate if requested\n uint256 public chainGasAmount;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n }\n\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n require(newFeeRate \u003c= FEE_RATE_MAX, \"newFeeRate \u003e max\");\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n token.universalTransfer(recipient, feeAmount);\n emit FeesSwept(token, recipient, feeAmount);\n }\n\n function setChainGasAmount(uint256 newChainGasAmount) external onlyRole(GOVERNOR_ROLE) {\n uint256 oldChainGasAmount = chainGasAmount;\n chainGasAmount = newChainGasAmount;\n emit ChainGasAmountUpdated(oldChainGasAmount, newChainGasAmount);\n }\n}\n\n// contracts/FastBridgeV2.sol\n\n/// @notice FastBridgeV2 is a contract for bridging tokens across chains.\ncontract FastBridgeV2 is Admin, IFastBridgeV2, IFastBridgeV2Errors {\n using SafeERC20 for IERC20;\n using UniversalTokenLib for address;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Delay for a transaction after which it could be permisionlessly refunded\n uint256 public constant REFUND_DELAY = 7 days;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n /// @notice Maximum length of accepted callParams\n uint256 public constant MAX_CALL_PARAMS_LENGTH = 2 ** 16 - 1;\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeTxDetails) public bridgeTxDetails;\n /// @notice Relay details on destination chain\n mapping(bytes32 =\u003e BridgeRelay) public bridgeRelayDetails;\n /// @notice Unique bridge nonces tracked per originSender\n mapping(address =\u003e uint256) public senderNonces;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Replaced by senderNonces\n uint256 public immutable nonce = 0;\n /// @notice the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n bridge({\n params: params,\n paramsV2: BridgeParamsV2({\n quoteRelayer: address(0),\n quoteExclusivitySeconds: 0,\n quoteId: bytes(\"\"),\n callValue: 0,\n callParams: bytes(\"\")\n })\n });\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes memory request) external payable {\n relay({request: request, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes memory request, bytes32 destTxHash) external {\n prove({transactionId: keccak256(request), destTxHash: destTxHash, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridgeV2\n function claim(bytes memory request) external {\n claim({request: request, to: address(0)});\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003e DISPUTE_PERIOD) {\n revert DisputePeriodPassed();\n }\n\n // @dev relayer gets slashed effectively if dest relay has gone thru\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n bridgeTxDetails[transactionId].proofRelayer = address(0);\n bridgeTxDetails[transactionId].proofBlockTimestamp = 0;\n bridgeTxDetails[transactionId].proofBlockNumber = 0;\n\n emit BridgeProofDisputed(transactionId, msg.sender);\n }\n\n /// @inheritdoc IFastBridge\n function refund(bytes memory request) external {\n bytes32 transactionId = keccak256(request);\n\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n\n if (bridgeTxDetails[transactionId].status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n\n if (hasRole(REFUNDER_ROLE, msg.sender)) {\n // Refunder can refund if deadline has passed\n if (block.timestamp \u003c= transaction.deadline) revert DeadlineNotExceeded();\n } else {\n // Permissionless refund is allowed after REFUND_DELAY\n if (block.timestamp \u003c= transaction.deadline + REFUND_DELAY) revert DeadlineNotExceeded();\n }\n\n // if all checks passed, set to REFUNDED status\n bridgeTxDetails[transactionId].status = BridgeStatus.REFUNDED;\n\n // transfer origin collateral back to original sender\n address to = transaction.originSender;\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount + transaction.originFeeAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (bridgeTxDetails[transactionId].proofRelayer != relayer) revert SenderIncorrect();\n return _timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n /// @dev This method is added to achieve backwards compatibility with decoding requests into V1 structs:\n /// - `callValue` is partially reported as a zero/non-zero flag\n /// - `callParams` is ignored\n /// In order to process all kinds of requests use getBridgeTransactionV2 instead.\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory) {\n // Try decoding into V2 struct first. This will revert if V1 struct is passed\n try this.getBridgeTransactionV2(request) returns (BridgeTransactionV2 memory txV2) {\n // Note: we entirely ignore the callParams field, as it was not present in V1\n return BridgeTransaction({\n originChainId: txV2.originChainId,\n destChainId: txV2.destChainId,\n originSender: txV2.originSender,\n destRecipient: txV2.destRecipient,\n originToken: txV2.originToken,\n destToken: txV2.destToken,\n originAmount: txV2.originAmount,\n destAmount: txV2.destAmount,\n originFeeAmount: txV2.originFeeAmount,\n sendChainGas: txV2.callValue != 0,\n deadline: txV2.deadline,\n nonce: txV2.nonce\n });\n } catch {\n // Fallback to V1 struct\n return abi.decode(request, (BridgeTransaction));\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) public payable {\n int256 exclusivityEndTime = int256(block.timestamp) + paramsV2.quoteExclusivitySeconds;\n _validateBridgeParams(params, paramsV2, exclusivityEndTime);\n\n // transfer tokens to bridge contract\n /// @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _takeBridgedUserAsset(params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n\n // set status to requested\n bytes memory request = abi.encode(\n BridgeTransactionV2({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n callValue: paramsV2.callValue,\n deadline: params.deadline,\n nonce: senderNonces[params.sender]++, // increment nonce on every bridge\n exclusivityRelayer: paramsV2.quoteRelayer,\n // We checked exclusivityEndTime to be in range (0 .. params.deadline] above, so can safely cast\n exclusivityEndTime: uint256(exclusivityEndTime),\n callParams: paramsV2.callParams\n })\n );\n bytes32 transactionId = keccak256(request);\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n\n emit BridgeRequested({\n transactionId: transactionId,\n sender: params.sender,\n request: request,\n destChainId: params.dstChainId,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n sendChainGas: paramsV2.callValue != 0\n });\n emit BridgeQuoteDetails(transactionId, paramsV2.quoteId);\n }\n\n /// @inheritdoc IFastBridgeV2\n function relay(bytes memory request, address relayer) public payable {\n bytes32 transactionId = keccak256(request);\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n _validateRelayParams(transaction, transactionId, relayer);\n // mark bridge transaction as relayed\n bridgeRelayDetails[transactionId] =\n BridgeRelay({blockNumber: uint48(block.number), blockTimestamp: uint48(block.timestamp), relayer: relayer});\n\n // transfer tokens to recipient on destination chain and do an arbitrary call if requested\n address to = transaction.destRecipient;\n address token = transaction.destToken;\n uint256 amount = transaction.destAmount;\n uint256 callValue = transaction.callValue;\n\n // Emit the event before any external calls\n emit BridgeRelayed({\n transactionId: transactionId,\n relayer: relayer,\n to: to,\n originChainId: transaction.originChainId,\n originToken: transaction.originToken,\n destToken: token,\n originAmount: transaction.originAmount,\n destAmount: amount,\n chainGasAmount: callValue\n });\n\n // All state changes have been done at this point, can proceed to the external calls.\n // This follows the checks-effects-interactions pattern to mitigate potential reentrancy attacks.\n if (token == UniversalTokenLib.ETH_ADDRESS) {\n // For ETH non-zero callValue is not allowed\n if (callValue != 0) revert NativeTokenCallValueNotSupported();\n // Check that the correct msg.value was sent\n if (msg.value != amount) revert MsgValueIncorrect();\n } else {\n // For ERC20s, we check that the correct msg.value was sent\n if (msg.value != callValue) revert MsgValueIncorrect();\n // We need to transfer the tokens from the Relayer to the recipient first before performing an\n // optional post-transfer arbitrary call.\n IERC20(token).safeTransferFrom(msg.sender, to, amount);\n }\n\n if (transaction.callParams.length != 0) {\n // Arbitrary call requested, perform it while supplying full msg.value to the recipient\n // Note: if token has a fee on transfers, the recipient will have received less than `amount`.\n // This is a very niche edge case and should be handled by the recipient contract.\n _checkedCallRecipient({recipient: to, token: token, amount: amount, callParams: transaction.callParams});\n } else if (msg.value != 0) {\n // No arbitrary call requested, but msg.value was sent. This is either a relay with ETH,\n // or a non-zero callValue request with an ERC20. In both cases, transfer the ETH to the recipient.\n Address.sendValue(payable(to), msg.value);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) public onlyRole(RELAYER_ROLE) {\n // update bridge tx status given proof provided\n if (bridgeTxDetails[transactionId].status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n bridgeTxDetails[transactionId].status = BridgeStatus.RELAYER_PROVED;\n bridgeTxDetails[transactionId].proofBlockTimestamp = uint40(block.timestamp);\n bridgeTxDetails[transactionId].proofBlockNumber = uint48(block.number);\n bridgeTxDetails[transactionId].proofRelayer = relayer;\n\n emit BridgeProofProvided(transactionId, relayer, destTxHash);\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes memory request, address to) public {\n bytes32 transactionId = keccak256(request);\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n\n // update bridge tx status if able to claim origin collateral\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n\n // if \"to\" is zero addr, permissionlessly send funds to proven relayer\n if (to == address(0)) {\n to = bridgeTxDetails[transactionId].proofRelayer;\n } else if (bridgeTxDetails[transactionId].proofRelayer != msg.sender) {\n revert SenderIncorrect();\n }\n\n if (_timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003c= DISPUTE_PERIOD) {\n revert DisputePeriodNotPassed();\n }\n\n bridgeTxDetails[transactionId].status = BridgeStatus.RELAYER_CLAIMED;\n\n // update protocol fees if origin fee amount exists\n if (transaction.originFeeAmount \u003e 0) protocolFees[transaction.originToken] += transaction.originFeeAmount;\n\n // transfer origin collateral less fee to specified address\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositClaimed(transactionId, bridgeTxDetails[transactionId].proofRelayer, to, token, amount);\n }\n\n function bridgeStatuses(bytes32 transactionId) public view returns (BridgeStatus status) {\n return bridgeTxDetails[transactionId].status;\n }\n\n function bridgeProofs(bytes32 transactionId) public view returns (uint96 timestamp, address relayer) {\n timestamp = bridgeTxDetails[transactionId].proofBlockTimestamp;\n relayer = bridgeTxDetails[transactionId].proofRelayer;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeRelays(bytes32 transactionId) public view returns (bool) {\n // has this transactionId been relayed?\n return bridgeRelayDetails[transactionId].relayer != address(0);\n }\n\n /// @inheritdoc IFastBridgeV2\n function getBridgeTransactionV2(bytes memory request) public pure returns (BridgeTransactionV2 memory) {\n return abi.decode(request, (BridgeTransactionV2));\n }\n\n /// @notice Takes the bridged asset from the user into FastBridgeV2 custody. It will be later\n /// claimed by the relayer who completed the relay on destination chain, or refunded back to the user,\n /// should no one complete the relay.\n function _takeBridgedUserAsset(address token, uint256 amount) internal returns (uint256 amountTaken) {\n if (token == UniversalTokenLib.ETH_ADDRESS) {\n // For ETH we just need to check that the supplied msg.value is correct.\n // Supplied `msg.value` is already in FastBridgeV2 custody.\n if (amount != msg.value) revert MsgValueIncorrect();\n amountTaken = msg.value;\n } else {\n // For ERC20s, token is explicitly transferred from the user to FastBridgeV2.\n // We don't allow non-zero `msg.value` to avoid extra funds from being stuck in FastBridgeV2.\n token.assertIsContract();\n if (msg.value != 0) revert MsgValueIncorrect();\n amountTaken = IERC20(token).balanceOf(address(this));\n IERC20(token).safeTransferFrom(msg.sender, address(this), amount);\n // Use the balance difference as the amount taken in case of fee on transfer tokens.\n amountTaken = IERC20(token).balanceOf(address(this)) - amountTaken;\n }\n }\n\n /// @notice Calls the Recipient's hook function with the specified callParams and performs\n /// all the necessary checks for the returned value.\n function _checkedCallRecipient(\n address recipient,\n address token,\n uint256 amount,\n bytes memory callParams\n )\n internal\n {\n bytes memory hookData =\n abi.encodeCall(IFastBridgeRecipient.fastBridgeTransferReceived, (token, amount, callParams));\n // This will bubble any revert messages from the hook function\n bytes memory returnData = Address.functionCallWithValue({target: recipient, data: hookData, value: msg.value});\n // Explicit revert if no return data at all\n if (returnData.length == 0) revert RecipientNoReturnValue();\n // Check that exactly a single return value was returned\n if (returnData.length != 32) revert RecipientIncorrectReturnValue();\n // Return value should be abi-encoded hook function selector\n if (bytes32(returnData) != bytes32(IFastBridgeRecipient.fastBridgeTransferReceived.selector)) {\n revert RecipientIncorrectReturnValue();\n }\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint40(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint40).max but\n /// proof.timestamp \u003c type(uint40).max via unchecked statement\n /// @param proofBlockTimestamp The bridge proof block timestamp\n /// @return delta Time delta since proof submitted\n function _timeSince(uint40 proofBlockTimestamp) internal view returns (uint256 delta) {\n unchecked {\n delta = uint40(block.timestamp) - proofBlockTimestamp;\n }\n }\n\n /// @notice Performs all the necessary checks for a bridge to happen.\n /// @dev There's no good way to refactor this function to reduce cyclomatic complexity due to\n /// the number of checks that need to be performed, so we skip the code-complexity rule here.\n // solhint-disable-next-line code-complexity\n function _validateBridgeParams(\n BridgeParams memory params,\n BridgeParamsV2 memory paramsV2,\n int256 exclusivityEndTime\n )\n internal\n view\n {\n // Check V1 (legacy) params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.sender == address(0) || params.to == address(0)) revert ZeroAddress();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n // Check V2 params\n if (paramsV2.callParams.length \u003e MAX_CALL_PARAMS_LENGTH) revert CallParamsLengthAboveMax();\n if (paramsV2.callValue != 0 \u0026\u0026 params.destToken == UniversalTokenLib.ETH_ADDRESS) {\n revert NativeTokenCallValueNotSupported();\n }\n // exclusivityEndTime must be in range (0 .. params.deadline]\n if (exclusivityEndTime \u003c= 0 || exclusivityEndTime \u003e int256(params.deadline)) {\n revert ExclusivityParamsIncorrect();\n }\n }\n\n /// @notice Performs all the necessary checks for a relay to happen.\n function _validateRelayParams(\n BridgeTransactionV2 memory transaction,\n bytes32 transactionId,\n address relayer\n )\n internal\n view\n {\n if (relayer == address(0)) revert ZeroAddress();\n // Check if the transaction has already been relayed\n if (bridgeRelays(transactionId)) revert TransactionRelayed();\n if (transaction.destChainId != block.chainid) revert ChainIncorrect();\n // Check the deadline for relay to happen\n if (block.timestamp \u003e transaction.deadline) revert DeadlineExceeded();\n // Check the exclusivity period, if it is still ongoing\n // forgefmt: disable-next-item\n if (\n transaction.exclusivityRelayer != address(0) \u0026\u0026\n transaction.exclusivityRelayer != relayer \u0026\u0026\n block.timestamp \u003c= transaction.exclusivityEndTime\n ) {\n revert ExclusivityPeriodNotPassed();\n }\n }\n}\n","language":"Solidity","languageVersion":"0.8.24","compilerVersion":"0.8.24","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"","srcMapRuntime":"","abiDefinition":[{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldChainGasAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newChainGasAmount","type":"uint256"}],"name":"ChainGasAmountUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldFeeRate","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newFeeRate","type":"uint256"}],"name":"FeeRateUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"address","name":"recipient","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"FeesSwept","type":"event"},{"inputs":[{"internalType":"uint256","name":"newChainGasAmount","type":"uint256"}],"name":"setChainGasAmount","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"newFeeRate","type":"uint256"}],"name":"setProtocolFeeRate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"address","name":"recipient","type":"address"}],"name":"sweepProtocolFees","outputs":[],"stateMutability":"nonpayable","type":"function"}],"userDoc":{"kind":"user","methods":{},"version":1},"developerDoc":{"kind":"dev","methods":{},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"oldChainGasAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newChainGasAmount\",\"type\":\"uint256\"}],\"name\":\"ChainGasAmountUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"oldFeeRate\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newFeeRate\",\"type\":\"uint256\"}],\"name\":\"FeeRateUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"FeesSwept\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"newChainGasAmount\",\"type\":\"uint256\"}],\"name\":\"setChainGasAmount\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"newFeeRate\",\"type\":\"uint256\"}],\"name\":\"setProtocolFeeRate\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"}],\"name\":\"sweepProtocolFees\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeV2.sol\":\"IAdmin\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeV2.sol\":{\"keccak256\":\"0xfd916c030b1ffca5a136817827b8018c8ba42ca089905747f3de6148b73eb35e\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://18e6438c4096deb8ae453fb3365ba2b07d52944e93c08288fc5d012b71bf6bb3\",\"dweb:/ipfs/QmfEMqpT1zz6RRm7UuHLRowe1tds2cTGLrVonfm9XSCACj\"]}},\"version\":1}"},"hashes":{"setChainGasAmount(uint256)":"b250fe6b","setProtocolFeeRate(uint256)":"b13aa2d6","sweepProtocolFees(address,address)":"06f333f2"}},"solidity/FastBridgeV2.sol:IERC165":{"code":"0x","runtime-code":"0x","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.24 ^0.8.0 ^0.8.20;\n\n// contracts/interfaces/IAdmin.sol\n\ninterface IAdmin {\n // ============ Events ============\n\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n event ChainGasAmountUpdated(uint256 oldChainGasAmount, uint256 newChainGasAmount);\n\n // ============ Methods ============\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n\n function setChainGasAmount(uint256 newChainGasAmount) external;\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IFastBridgeRecipient.sol\n\ninterface IFastBridgeRecipient {\n function fastBridgeTransferReceived(\n address token,\n uint256 amount,\n bytes memory callParams\n )\n external\n payable\n returns (bytes4);\n}\n\n// contracts/interfaces/IFastBridgeV2Errors.sol\n\ninterface IFastBridgeV2Errors {\n error AmountIncorrect();\n error CallParamsLengthAboveMax();\n error ChainIncorrect();\n error ExclusivityParamsIncorrect();\n error MsgValueIncorrect();\n error NativeTokenCallValueNotSupported();\n error SenderIncorrect();\n error StatusIncorrect();\n error ZeroAddress();\n\n error RecipientIncorrectReturnValue();\n error RecipientNoReturnValue();\n\n error DeadlineExceeded();\n error DeadlineNotExceeded();\n error DeadlineTooShort();\n error DisputePeriodNotPassed();\n error DisputePeriodPassed();\n error ExclusivityPeriodNotPassed();\n\n error TransactionRelayed();\n}\n\n// contracts/libs/Errors.sol\n\nerror DeadlineExceeded();\nerror DeadlineNotExceeded();\nerror DeadlineTooShort();\nerror InsufficientOutputAmount();\n\nerror MsgValueIncorrect();\nerror PoolNotFound();\nerror TokenAddressMismatch();\nerror TokenNotContract();\nerror TokenNotETH();\nerror TokensIdentical();\n\nerror ChainIncorrect();\nerror AmountIncorrect();\nerror ZeroAddress();\n\nerror DisputePeriodNotPassed();\nerror DisputePeriodPassed();\nerror SenderIncorrect();\nerror StatusIncorrect();\nerror TransactionIdIncorrect();\nerror TransactionRelayed();\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// contracts/interfaces/IFastBridgeV2.sol\n\ninterface IFastBridgeV2 is IFastBridge {\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n struct BridgeTxDetails {\n BridgeStatus status;\n uint40 proofBlockTimestamp;\n uint48 proofBlockNumber;\n address proofRelayer;\n }\n\n struct BridgeRelay {\n uint48 blockNumber;\n uint48 blockTimestamp;\n address relayer;\n }\n\n /// @notice New params introduced in the FastBridgeV2.\n /// We are passing fields from the older BridgeParams struct outside of this struct\n /// for backwards compatibility.\n /// Note: quoteRelayer and quoteExclusivitySeconds are either both zero (indicating no exclusivity)\n /// or both non-zero (indicating exclusivity for the given period).\n /// Note: callValue \u003e 0 can NOT be used with destToken = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE (ETH_ADDRESS)\n /// @param quoteRelayer Relayer that provided the quote for the transaction\n /// @param quoteExclusivitySeconds Period of time the quote relayer is guaranteed exclusivity after user's deposit\n /// @param quoteId Unique quote identifier used for tracking the quote\n /// @param callValue ETH value to send to the recipient (if any)\n /// @param callParams Parameters for the arbitrary call to the destination recipient (if any)\n struct BridgeParamsV2 {\n address quoteRelayer;\n int256 quoteExclusivitySeconds;\n bytes quoteId;\n uint256 callValue;\n bytes callParams;\n }\n\n /// @notice Updated bridge transaction struct to include parameters introduced in FastBridgeV2.\n /// Note: only `exclusivityRelayer` can fill such a transaction until `exclusivityEndTime`.\n /// TODO: consider changing the encoding scheme to prevent spending extra gas on decoding.\n struct BridgeTransactionV2 {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n uint256 callValue; // ETH value to send to the recipient (if any) - replaces V1's sendChainGas flag\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n address exclusivityRelayer;\n uint256 exclusivityEndTime;\n bytes callParams;\n }\n\n event BridgeQuoteDetails(bytes32 indexed transactionId, bytes quoteId);\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability\n /// to provide temporary exclusivity fill rights for the quote relayer.\n /// @param params The parameters required to bridge\n /// @param paramsV2 The parameters for exclusivity fill rights (optional, can be left empty)\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function relay(bytes memory request, address relayer) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param transactionId The transaction id associated with the encoded bridge transaction to prove\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital.\n /// @notice Can only send funds to the relayer address on the proof.\n /// @param request The encoded bridge transaction to claim on origin chain\n function claim(bytes memory request) external;\n /// @notice Checks if a transaction has been relayed\n /// @param transactionId The ID of the transaction to check\n /// @return True if the transaction has been relayed, false otherwise\n function bridgeRelays(bytes32 transactionId) external view returns (bool);\n\n /// @notice Returns the status of a bridge transaction\n /// @param transactionId The ID of the bridge transaction\n /// @return BridgeStatus Status of the bridge transaction\n function bridgeStatuses(bytes32 transactionId) external view returns (BridgeStatus);\n\n /// @notice Returns the timestamp and relayer of a bridge proof\n /// @param transactionId The ID of the bridge transaction\n /// @return timestamp The timestamp of the bridge proof\n /// @return relayer The relayer address of the bridge proof\n function bridgeProofs(bytes32 transactionId) external view returns (uint96 timestamp, address relayer);\n\n /// @notice Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\n /// @param request The bridge request to decode\n function getBridgeTransactionV2(bytes memory request) external view returns (BridgeTransactionV2 memory);\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// contracts/libs/UniversalToken.sol\n\nlibrary UniversalTokenLib {\n using SafeERC20 for IERC20;\n\n address internal constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Transfers tokens to the given account. Reverts if transfer is not successful.\n /// @dev This might trigger fallback, if ETH is transferred to the contract.\n /// Make sure this can not lead to reentrancy attacks.\n function universalTransfer(address token, address to, uint256 value) internal {\n // Don't do anything, if need to send tokens to this address\n if (to == address(this)) return;\n // Don't do anything, if trying to send zero value\n if (value == 0) return;\n if (token == ETH_ADDRESS) {\n /// @dev Note: this can potentially lead to executing code in `to`.\n // solhint-disable-next-line avoid-low-level-calls\n (bool success,) = to.call{value: value}(\"\");\n require(success, \"ETH transfer failed\");\n } else {\n IERC20(token).safeTransfer(to, value);\n }\n }\n\n /// @notice Issues an infinite allowance to the spender, if the current allowance is insufficient\n /// to spend the given amount.\n function universalApproveInfinity(address token, address spender, uint256 amountToSpend) internal {\n // ETH Chad doesn't require your approval\n if (token == ETH_ADDRESS) return;\n // No-op if allowance is already sufficient\n uint256 allowance = IERC20(token).allowance(address(this), spender);\n if (allowance \u003e= amountToSpend) return;\n // Otherwise, reset approval to 0 and set to max allowance\n if (allowance \u003e 0) IERC20(token).safeDecreaseAllowance(spender, allowance);\n IERC20(token).safeIncreaseAllowance(spender, type(uint256).max);\n }\n\n /// @notice Returns the balance of the given token (or native ETH) for the given account.\n function universalBalanceOf(address token, address account) internal view returns (uint256) {\n if (token == ETH_ADDRESS) {\n return account.balance;\n } else {\n return IERC20(token).balanceOf(account);\n }\n }\n\n /// @dev Checks that token is a contract and not ETH_ADDRESS.\n function assertIsContract(address token) internal view {\n // Check that ETH_ADDRESS was not used (in case this is a predeploy on any of the chains)\n if (token == UniversalTokenLib.ETH_ADDRESS) revert TokenNotContract();\n // Check that token is not an EOA\n if (token.code.length == 0) revert TokenNotContract();\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/Admin.sol\n\ncontract Admin is IAdmin, AccessControlEnumerable {\n using UniversalTokenLib for address;\n\n bytes32 public constant RELAYER_ROLE = keccak256(\"RELAYER_ROLE\");\n bytes32 public constant REFUNDER_ROLE = keccak256(\"REFUNDER_ROLE\");\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n uint256 public constant FEE_BPS = 1e6;\n uint256 public constant FEE_RATE_MAX = 0.01e6; // max 1% on origin amount\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Chain gas amount to forward as rebate if requested\n uint256 public chainGasAmount;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n }\n\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n require(newFeeRate \u003c= FEE_RATE_MAX, \"newFeeRate \u003e max\");\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n token.universalTransfer(recipient, feeAmount);\n emit FeesSwept(token, recipient, feeAmount);\n }\n\n function setChainGasAmount(uint256 newChainGasAmount) external onlyRole(GOVERNOR_ROLE) {\n uint256 oldChainGasAmount = chainGasAmount;\n chainGasAmount = newChainGasAmount;\n emit ChainGasAmountUpdated(oldChainGasAmount, newChainGasAmount);\n }\n}\n\n// contracts/FastBridgeV2.sol\n\n/// @notice FastBridgeV2 is a contract for bridging tokens across chains.\ncontract FastBridgeV2 is Admin, IFastBridgeV2, IFastBridgeV2Errors {\n using SafeERC20 for IERC20;\n using UniversalTokenLib for address;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Delay for a transaction after which it could be permisionlessly refunded\n uint256 public constant REFUND_DELAY = 7 days;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n /// @notice Maximum length of accepted callParams\n uint256 public constant MAX_CALL_PARAMS_LENGTH = 2 ** 16 - 1;\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeTxDetails) public bridgeTxDetails;\n /// @notice Relay details on destination chain\n mapping(bytes32 =\u003e BridgeRelay) public bridgeRelayDetails;\n /// @notice Unique bridge nonces tracked per originSender\n mapping(address =\u003e uint256) public senderNonces;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Replaced by senderNonces\n uint256 public immutable nonce = 0;\n /// @notice the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n bridge({\n params: params,\n paramsV2: BridgeParamsV2({\n quoteRelayer: address(0),\n quoteExclusivitySeconds: 0,\n quoteId: bytes(\"\"),\n callValue: 0,\n callParams: bytes(\"\")\n })\n });\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes memory request) external payable {\n relay({request: request, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes memory request, bytes32 destTxHash) external {\n prove({transactionId: keccak256(request), destTxHash: destTxHash, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridgeV2\n function claim(bytes memory request) external {\n claim({request: request, to: address(0)});\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003e DISPUTE_PERIOD) {\n revert DisputePeriodPassed();\n }\n\n // @dev relayer gets slashed effectively if dest relay has gone thru\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n bridgeTxDetails[transactionId].proofRelayer = address(0);\n bridgeTxDetails[transactionId].proofBlockTimestamp = 0;\n bridgeTxDetails[transactionId].proofBlockNumber = 0;\n\n emit BridgeProofDisputed(transactionId, msg.sender);\n }\n\n /// @inheritdoc IFastBridge\n function refund(bytes memory request) external {\n bytes32 transactionId = keccak256(request);\n\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n\n if (bridgeTxDetails[transactionId].status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n\n if (hasRole(REFUNDER_ROLE, msg.sender)) {\n // Refunder can refund if deadline has passed\n if (block.timestamp \u003c= transaction.deadline) revert DeadlineNotExceeded();\n } else {\n // Permissionless refund is allowed after REFUND_DELAY\n if (block.timestamp \u003c= transaction.deadline + REFUND_DELAY) revert DeadlineNotExceeded();\n }\n\n // if all checks passed, set to REFUNDED status\n bridgeTxDetails[transactionId].status = BridgeStatus.REFUNDED;\n\n // transfer origin collateral back to original sender\n address to = transaction.originSender;\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount + transaction.originFeeAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (bridgeTxDetails[transactionId].proofRelayer != relayer) revert SenderIncorrect();\n return _timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n /// @dev This method is added to achieve backwards compatibility with decoding requests into V1 structs:\n /// - `callValue` is partially reported as a zero/non-zero flag\n /// - `callParams` is ignored\n /// In order to process all kinds of requests use getBridgeTransactionV2 instead.\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory) {\n // Try decoding into V2 struct first. This will revert if V1 struct is passed\n try this.getBridgeTransactionV2(request) returns (BridgeTransactionV2 memory txV2) {\n // Note: we entirely ignore the callParams field, as it was not present in V1\n return BridgeTransaction({\n originChainId: txV2.originChainId,\n destChainId: txV2.destChainId,\n originSender: txV2.originSender,\n destRecipient: txV2.destRecipient,\n originToken: txV2.originToken,\n destToken: txV2.destToken,\n originAmount: txV2.originAmount,\n destAmount: txV2.destAmount,\n originFeeAmount: txV2.originFeeAmount,\n sendChainGas: txV2.callValue != 0,\n deadline: txV2.deadline,\n nonce: txV2.nonce\n });\n } catch {\n // Fallback to V1 struct\n return abi.decode(request, (BridgeTransaction));\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) public payable {\n int256 exclusivityEndTime = int256(block.timestamp) + paramsV2.quoteExclusivitySeconds;\n _validateBridgeParams(params, paramsV2, exclusivityEndTime);\n\n // transfer tokens to bridge contract\n /// @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _takeBridgedUserAsset(params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n\n // set status to requested\n bytes memory request = abi.encode(\n BridgeTransactionV2({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n callValue: paramsV2.callValue,\n deadline: params.deadline,\n nonce: senderNonces[params.sender]++, // increment nonce on every bridge\n exclusivityRelayer: paramsV2.quoteRelayer,\n // We checked exclusivityEndTime to be in range (0 .. params.deadline] above, so can safely cast\n exclusivityEndTime: uint256(exclusivityEndTime),\n callParams: paramsV2.callParams\n })\n );\n bytes32 transactionId = keccak256(request);\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n\n emit BridgeRequested({\n transactionId: transactionId,\n sender: params.sender,\n request: request,\n destChainId: params.dstChainId,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n sendChainGas: paramsV2.callValue != 0\n });\n emit BridgeQuoteDetails(transactionId, paramsV2.quoteId);\n }\n\n /// @inheritdoc IFastBridgeV2\n function relay(bytes memory request, address relayer) public payable {\n bytes32 transactionId = keccak256(request);\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n _validateRelayParams(transaction, transactionId, relayer);\n // mark bridge transaction as relayed\n bridgeRelayDetails[transactionId] =\n BridgeRelay({blockNumber: uint48(block.number), blockTimestamp: uint48(block.timestamp), relayer: relayer});\n\n // transfer tokens to recipient on destination chain and do an arbitrary call if requested\n address to = transaction.destRecipient;\n address token = transaction.destToken;\n uint256 amount = transaction.destAmount;\n uint256 callValue = transaction.callValue;\n\n // Emit the event before any external calls\n emit BridgeRelayed({\n transactionId: transactionId,\n relayer: relayer,\n to: to,\n originChainId: transaction.originChainId,\n originToken: transaction.originToken,\n destToken: token,\n originAmount: transaction.originAmount,\n destAmount: amount,\n chainGasAmount: callValue\n });\n\n // All state changes have been done at this point, can proceed to the external calls.\n // This follows the checks-effects-interactions pattern to mitigate potential reentrancy attacks.\n if (token == UniversalTokenLib.ETH_ADDRESS) {\n // For ETH non-zero callValue is not allowed\n if (callValue != 0) revert NativeTokenCallValueNotSupported();\n // Check that the correct msg.value was sent\n if (msg.value != amount) revert MsgValueIncorrect();\n } else {\n // For ERC20s, we check that the correct msg.value was sent\n if (msg.value != callValue) revert MsgValueIncorrect();\n // We need to transfer the tokens from the Relayer to the recipient first before performing an\n // optional post-transfer arbitrary call.\n IERC20(token).safeTransferFrom(msg.sender, to, amount);\n }\n\n if (transaction.callParams.length != 0) {\n // Arbitrary call requested, perform it while supplying full msg.value to the recipient\n // Note: if token has a fee on transfers, the recipient will have received less than `amount`.\n // This is a very niche edge case and should be handled by the recipient contract.\n _checkedCallRecipient({recipient: to, token: token, amount: amount, callParams: transaction.callParams});\n } else if (msg.value != 0) {\n // No arbitrary call requested, but msg.value was sent. This is either a relay with ETH,\n // or a non-zero callValue request with an ERC20. In both cases, transfer the ETH to the recipient.\n Address.sendValue(payable(to), msg.value);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) public onlyRole(RELAYER_ROLE) {\n // update bridge tx status given proof provided\n if (bridgeTxDetails[transactionId].status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n bridgeTxDetails[transactionId].status = BridgeStatus.RELAYER_PROVED;\n bridgeTxDetails[transactionId].proofBlockTimestamp = uint40(block.timestamp);\n bridgeTxDetails[transactionId].proofBlockNumber = uint48(block.number);\n bridgeTxDetails[transactionId].proofRelayer = relayer;\n\n emit BridgeProofProvided(transactionId, relayer, destTxHash);\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes memory request, address to) public {\n bytes32 transactionId = keccak256(request);\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n\n // update bridge tx status if able to claim origin collateral\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n\n // if \"to\" is zero addr, permissionlessly send funds to proven relayer\n if (to == address(0)) {\n to = bridgeTxDetails[transactionId].proofRelayer;\n } else if (bridgeTxDetails[transactionId].proofRelayer != msg.sender) {\n revert SenderIncorrect();\n }\n\n if (_timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003c= DISPUTE_PERIOD) {\n revert DisputePeriodNotPassed();\n }\n\n bridgeTxDetails[transactionId].status = BridgeStatus.RELAYER_CLAIMED;\n\n // update protocol fees if origin fee amount exists\n if (transaction.originFeeAmount \u003e 0) protocolFees[transaction.originToken] += transaction.originFeeAmount;\n\n // transfer origin collateral less fee to specified address\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositClaimed(transactionId, bridgeTxDetails[transactionId].proofRelayer, to, token, amount);\n }\n\n function bridgeStatuses(bytes32 transactionId) public view returns (BridgeStatus status) {\n return bridgeTxDetails[transactionId].status;\n }\n\n function bridgeProofs(bytes32 transactionId) public view returns (uint96 timestamp, address relayer) {\n timestamp = bridgeTxDetails[transactionId].proofBlockTimestamp;\n relayer = bridgeTxDetails[transactionId].proofRelayer;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeRelays(bytes32 transactionId) public view returns (bool) {\n // has this transactionId been relayed?\n return bridgeRelayDetails[transactionId].relayer != address(0);\n }\n\n /// @inheritdoc IFastBridgeV2\n function getBridgeTransactionV2(bytes memory request) public pure returns (BridgeTransactionV2 memory) {\n return abi.decode(request, (BridgeTransactionV2));\n }\n\n /// @notice Takes the bridged asset from the user into FastBridgeV2 custody. It will be later\n /// claimed by the relayer who completed the relay on destination chain, or refunded back to the user,\n /// should no one complete the relay.\n function _takeBridgedUserAsset(address token, uint256 amount) internal returns (uint256 amountTaken) {\n if (token == UniversalTokenLib.ETH_ADDRESS) {\n // For ETH we just need to check that the supplied msg.value is correct.\n // Supplied `msg.value` is already in FastBridgeV2 custody.\n if (amount != msg.value) revert MsgValueIncorrect();\n amountTaken = msg.value;\n } else {\n // For ERC20s, token is explicitly transferred from the user to FastBridgeV2.\n // We don't allow non-zero `msg.value` to avoid extra funds from being stuck in FastBridgeV2.\n token.assertIsContract();\n if (msg.value != 0) revert MsgValueIncorrect();\n amountTaken = IERC20(token).balanceOf(address(this));\n IERC20(token).safeTransferFrom(msg.sender, address(this), amount);\n // Use the balance difference as the amount taken in case of fee on transfer tokens.\n amountTaken = IERC20(token).balanceOf(address(this)) - amountTaken;\n }\n }\n\n /// @notice Calls the Recipient's hook function with the specified callParams and performs\n /// all the necessary checks for the returned value.\n function _checkedCallRecipient(\n address recipient,\n address token,\n uint256 amount,\n bytes memory callParams\n )\n internal\n {\n bytes memory hookData =\n abi.encodeCall(IFastBridgeRecipient.fastBridgeTransferReceived, (token, amount, callParams));\n // This will bubble any revert messages from the hook function\n bytes memory returnData = Address.functionCallWithValue({target: recipient, data: hookData, value: msg.value});\n // Explicit revert if no return data at all\n if (returnData.length == 0) revert RecipientNoReturnValue();\n // Check that exactly a single return value was returned\n if (returnData.length != 32) revert RecipientIncorrectReturnValue();\n // Return value should be abi-encoded hook function selector\n if (bytes32(returnData) != bytes32(IFastBridgeRecipient.fastBridgeTransferReceived.selector)) {\n revert RecipientIncorrectReturnValue();\n }\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint40(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint40).max but\n /// proof.timestamp \u003c type(uint40).max via unchecked statement\n /// @param proofBlockTimestamp The bridge proof block timestamp\n /// @return delta Time delta since proof submitted\n function _timeSince(uint40 proofBlockTimestamp) internal view returns (uint256 delta) {\n unchecked {\n delta = uint40(block.timestamp) - proofBlockTimestamp;\n }\n }\n\n /// @notice Performs all the necessary checks for a bridge to happen.\n /// @dev There's no good way to refactor this function to reduce cyclomatic complexity due to\n /// the number of checks that need to be performed, so we skip the code-complexity rule here.\n // solhint-disable-next-line code-complexity\n function _validateBridgeParams(\n BridgeParams memory params,\n BridgeParamsV2 memory paramsV2,\n int256 exclusivityEndTime\n )\n internal\n view\n {\n // Check V1 (legacy) params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.sender == address(0) || params.to == address(0)) revert ZeroAddress();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n // Check V2 params\n if (paramsV2.callParams.length \u003e MAX_CALL_PARAMS_LENGTH) revert CallParamsLengthAboveMax();\n if (paramsV2.callValue != 0 \u0026\u0026 params.destToken == UniversalTokenLib.ETH_ADDRESS) {\n revert NativeTokenCallValueNotSupported();\n }\n // exclusivityEndTime must be in range (0 .. params.deadline]\n if (exclusivityEndTime \u003c= 0 || exclusivityEndTime \u003e int256(params.deadline)) {\n revert ExclusivityParamsIncorrect();\n }\n }\n\n /// @notice Performs all the necessary checks for a relay to happen.\n function _validateRelayParams(\n BridgeTransactionV2 memory transaction,\n bytes32 transactionId,\n address relayer\n )\n internal\n view\n {\n if (relayer == address(0)) revert ZeroAddress();\n // Check if the transaction has already been relayed\n if (bridgeRelays(transactionId)) revert TransactionRelayed();\n if (transaction.destChainId != block.chainid) revert ChainIncorrect();\n // Check the deadline for relay to happen\n if (block.timestamp \u003e transaction.deadline) revert DeadlineExceeded();\n // Check the exclusivity period, if it is still ongoing\n // forgefmt: disable-next-item\n if (\n transaction.exclusivityRelayer != address(0) \u0026\u0026\n transaction.exclusivityRelayer != relayer \u0026\u0026\n block.timestamp \u003c= transaction.exclusivityEndTime\n ) {\n revert ExclusivityPeriodNotPassed();\n }\n }\n}\n","language":"Solidity","languageVersion":"0.8.24","compilerVersion":"0.8.24","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"","srcMapRuntime":"","abiDefinition":[{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"}],"userDoc":{"kind":"user","methods":{},"version":1},"developerDoc":{"details":"Interface of the ERC165 standard, as defined in the https://eips.ethereum.org/EIPS/eip-165[EIP]. Implementers can declare support of contract interfaces, which can then be queried by others ({ERC165Checker}). For an implementation, see {ERC165}.","kind":"dev","methods":{"supportsInterface(bytes4)":{"details":"Returns true if this contract implements the interface defined by `interfaceId`. See the corresponding https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section] to learn more about how these ids are created. This function call must use less than 30 000 gas."}},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"bytes4\",\"name\":\"interfaceId\",\"type\":\"bytes4\"}],\"name\":\"supportsInterface\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"}],\"devdoc\":{\"details\":\"Interface of the ERC165 standard, as defined in the https://eips.ethereum.org/EIPS/eip-165[EIP]. Implementers can declare support of contract interfaces, which can then be queried by others ({ERC165Checker}). For an implementation, see {ERC165}.\",\"kind\":\"dev\",\"methods\":{\"supportsInterface(bytes4)\":{\"details\":\"Returns true if this contract implements the interface defined by `interfaceId`. See the corresponding https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section] to learn more about how these ids are created. This function call must use less than 30 000 gas.\"}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeV2.sol\":\"IERC165\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeV2.sol\":{\"keccak256\":\"0xfd916c030b1ffca5a136817827b8018c8ba42ca089905747f3de6148b73eb35e\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://18e6438c4096deb8ae453fb3365ba2b07d52944e93c08288fc5d012b71bf6bb3\",\"dweb:/ipfs/QmfEMqpT1zz6RRm7UuHLRowe1tds2cTGLrVonfm9XSCACj\"]}},\"version\":1}"},"hashes":{"supportsInterface(bytes4)":"01ffc9a7"}},"solidity/FastBridgeV2.sol:IERC20":{"code":"0x","runtime-code":"0x","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.24 ^0.8.0 ^0.8.20;\n\n// contracts/interfaces/IAdmin.sol\n\ninterface IAdmin {\n // ============ Events ============\n\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n event ChainGasAmountUpdated(uint256 oldChainGasAmount, uint256 newChainGasAmount);\n\n // ============ Methods ============\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n\n function setChainGasAmount(uint256 newChainGasAmount) external;\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IFastBridgeRecipient.sol\n\ninterface IFastBridgeRecipient {\n function fastBridgeTransferReceived(\n address token,\n uint256 amount,\n bytes memory callParams\n )\n external\n payable\n returns (bytes4);\n}\n\n// contracts/interfaces/IFastBridgeV2Errors.sol\n\ninterface IFastBridgeV2Errors {\n error AmountIncorrect();\n error CallParamsLengthAboveMax();\n error ChainIncorrect();\n error ExclusivityParamsIncorrect();\n error MsgValueIncorrect();\n error NativeTokenCallValueNotSupported();\n error SenderIncorrect();\n error StatusIncorrect();\n error ZeroAddress();\n\n error RecipientIncorrectReturnValue();\n error RecipientNoReturnValue();\n\n error DeadlineExceeded();\n error DeadlineNotExceeded();\n error DeadlineTooShort();\n error DisputePeriodNotPassed();\n error DisputePeriodPassed();\n error ExclusivityPeriodNotPassed();\n\n error TransactionRelayed();\n}\n\n// contracts/libs/Errors.sol\n\nerror DeadlineExceeded();\nerror DeadlineNotExceeded();\nerror DeadlineTooShort();\nerror InsufficientOutputAmount();\n\nerror MsgValueIncorrect();\nerror PoolNotFound();\nerror TokenAddressMismatch();\nerror TokenNotContract();\nerror TokenNotETH();\nerror TokensIdentical();\n\nerror ChainIncorrect();\nerror AmountIncorrect();\nerror ZeroAddress();\n\nerror DisputePeriodNotPassed();\nerror DisputePeriodPassed();\nerror SenderIncorrect();\nerror StatusIncorrect();\nerror TransactionIdIncorrect();\nerror TransactionRelayed();\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// contracts/interfaces/IFastBridgeV2.sol\n\ninterface IFastBridgeV2 is IFastBridge {\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n struct BridgeTxDetails {\n BridgeStatus status;\n uint40 proofBlockTimestamp;\n uint48 proofBlockNumber;\n address proofRelayer;\n }\n\n struct BridgeRelay {\n uint48 blockNumber;\n uint48 blockTimestamp;\n address relayer;\n }\n\n /// @notice New params introduced in the FastBridgeV2.\n /// We are passing fields from the older BridgeParams struct outside of this struct\n /// for backwards compatibility.\n /// Note: quoteRelayer and quoteExclusivitySeconds are either both zero (indicating no exclusivity)\n /// or both non-zero (indicating exclusivity for the given period).\n /// Note: callValue \u003e 0 can NOT be used with destToken = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE (ETH_ADDRESS)\n /// @param quoteRelayer Relayer that provided the quote for the transaction\n /// @param quoteExclusivitySeconds Period of time the quote relayer is guaranteed exclusivity after user's deposit\n /// @param quoteId Unique quote identifier used for tracking the quote\n /// @param callValue ETH value to send to the recipient (if any)\n /// @param callParams Parameters for the arbitrary call to the destination recipient (if any)\n struct BridgeParamsV2 {\n address quoteRelayer;\n int256 quoteExclusivitySeconds;\n bytes quoteId;\n uint256 callValue;\n bytes callParams;\n }\n\n /// @notice Updated bridge transaction struct to include parameters introduced in FastBridgeV2.\n /// Note: only `exclusivityRelayer` can fill such a transaction until `exclusivityEndTime`.\n /// TODO: consider changing the encoding scheme to prevent spending extra gas on decoding.\n struct BridgeTransactionV2 {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n uint256 callValue; // ETH value to send to the recipient (if any) - replaces V1's sendChainGas flag\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n address exclusivityRelayer;\n uint256 exclusivityEndTime;\n bytes callParams;\n }\n\n event BridgeQuoteDetails(bytes32 indexed transactionId, bytes quoteId);\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability\n /// to provide temporary exclusivity fill rights for the quote relayer.\n /// @param params The parameters required to bridge\n /// @param paramsV2 The parameters for exclusivity fill rights (optional, can be left empty)\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function relay(bytes memory request, address relayer) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param transactionId The transaction id associated with the encoded bridge transaction to prove\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital.\n /// @notice Can only send funds to the relayer address on the proof.\n /// @param request The encoded bridge transaction to claim on origin chain\n function claim(bytes memory request) external;\n /// @notice Checks if a transaction has been relayed\n /// @param transactionId The ID of the transaction to check\n /// @return True if the transaction has been relayed, false otherwise\n function bridgeRelays(bytes32 transactionId) external view returns (bool);\n\n /// @notice Returns the status of a bridge transaction\n /// @param transactionId The ID of the bridge transaction\n /// @return BridgeStatus Status of the bridge transaction\n function bridgeStatuses(bytes32 transactionId) external view returns (BridgeStatus);\n\n /// @notice Returns the timestamp and relayer of a bridge proof\n /// @param transactionId The ID of the bridge transaction\n /// @return timestamp The timestamp of the bridge proof\n /// @return relayer The relayer address of the bridge proof\n function bridgeProofs(bytes32 transactionId) external view returns (uint96 timestamp, address relayer);\n\n /// @notice Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\n /// @param request The bridge request to decode\n function getBridgeTransactionV2(bytes memory request) external view returns (BridgeTransactionV2 memory);\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// contracts/libs/UniversalToken.sol\n\nlibrary UniversalTokenLib {\n using SafeERC20 for IERC20;\n\n address internal constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Transfers tokens to the given account. Reverts if transfer is not successful.\n /// @dev This might trigger fallback, if ETH is transferred to the contract.\n /// Make sure this can not lead to reentrancy attacks.\n function universalTransfer(address token, address to, uint256 value) internal {\n // Don't do anything, if need to send tokens to this address\n if (to == address(this)) return;\n // Don't do anything, if trying to send zero value\n if (value == 0) return;\n if (token == ETH_ADDRESS) {\n /// @dev Note: this can potentially lead to executing code in `to`.\n // solhint-disable-next-line avoid-low-level-calls\n (bool success,) = to.call{value: value}(\"\");\n require(success, \"ETH transfer failed\");\n } else {\n IERC20(token).safeTransfer(to, value);\n }\n }\n\n /// @notice Issues an infinite allowance to the spender, if the current allowance is insufficient\n /// to spend the given amount.\n function universalApproveInfinity(address token, address spender, uint256 amountToSpend) internal {\n // ETH Chad doesn't require your approval\n if (token == ETH_ADDRESS) return;\n // No-op if allowance is already sufficient\n uint256 allowance = IERC20(token).allowance(address(this), spender);\n if (allowance \u003e= amountToSpend) return;\n // Otherwise, reset approval to 0 and set to max allowance\n if (allowance \u003e 0) IERC20(token).safeDecreaseAllowance(spender, allowance);\n IERC20(token).safeIncreaseAllowance(spender, type(uint256).max);\n }\n\n /// @notice Returns the balance of the given token (or native ETH) for the given account.\n function universalBalanceOf(address token, address account) internal view returns (uint256) {\n if (token == ETH_ADDRESS) {\n return account.balance;\n } else {\n return IERC20(token).balanceOf(account);\n }\n }\n\n /// @dev Checks that token is a contract and not ETH_ADDRESS.\n function assertIsContract(address token) internal view {\n // Check that ETH_ADDRESS was not used (in case this is a predeploy on any of the chains)\n if (token == UniversalTokenLib.ETH_ADDRESS) revert TokenNotContract();\n // Check that token is not an EOA\n if (token.code.length == 0) revert TokenNotContract();\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/Admin.sol\n\ncontract Admin is IAdmin, AccessControlEnumerable {\n using UniversalTokenLib for address;\n\n bytes32 public constant RELAYER_ROLE = keccak256(\"RELAYER_ROLE\");\n bytes32 public constant REFUNDER_ROLE = keccak256(\"REFUNDER_ROLE\");\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n uint256 public constant FEE_BPS = 1e6;\n uint256 public constant FEE_RATE_MAX = 0.01e6; // max 1% on origin amount\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Chain gas amount to forward as rebate if requested\n uint256 public chainGasAmount;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n }\n\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n require(newFeeRate \u003c= FEE_RATE_MAX, \"newFeeRate \u003e max\");\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n token.universalTransfer(recipient, feeAmount);\n emit FeesSwept(token, recipient, feeAmount);\n }\n\n function setChainGasAmount(uint256 newChainGasAmount) external onlyRole(GOVERNOR_ROLE) {\n uint256 oldChainGasAmount = chainGasAmount;\n chainGasAmount = newChainGasAmount;\n emit ChainGasAmountUpdated(oldChainGasAmount, newChainGasAmount);\n }\n}\n\n// contracts/FastBridgeV2.sol\n\n/// @notice FastBridgeV2 is a contract for bridging tokens across chains.\ncontract FastBridgeV2 is Admin, IFastBridgeV2, IFastBridgeV2Errors {\n using SafeERC20 for IERC20;\n using UniversalTokenLib for address;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Delay for a transaction after which it could be permisionlessly refunded\n uint256 public constant REFUND_DELAY = 7 days;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n /// @notice Maximum length of accepted callParams\n uint256 public constant MAX_CALL_PARAMS_LENGTH = 2 ** 16 - 1;\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeTxDetails) public bridgeTxDetails;\n /// @notice Relay details on destination chain\n mapping(bytes32 =\u003e BridgeRelay) public bridgeRelayDetails;\n /// @notice Unique bridge nonces tracked per originSender\n mapping(address =\u003e uint256) public senderNonces;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Replaced by senderNonces\n uint256 public immutable nonce = 0;\n /// @notice the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n bridge({\n params: params,\n paramsV2: BridgeParamsV2({\n quoteRelayer: address(0),\n quoteExclusivitySeconds: 0,\n quoteId: bytes(\"\"),\n callValue: 0,\n callParams: bytes(\"\")\n })\n });\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes memory request) external payable {\n relay({request: request, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes memory request, bytes32 destTxHash) external {\n prove({transactionId: keccak256(request), destTxHash: destTxHash, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridgeV2\n function claim(bytes memory request) external {\n claim({request: request, to: address(0)});\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003e DISPUTE_PERIOD) {\n revert DisputePeriodPassed();\n }\n\n // @dev relayer gets slashed effectively if dest relay has gone thru\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n bridgeTxDetails[transactionId].proofRelayer = address(0);\n bridgeTxDetails[transactionId].proofBlockTimestamp = 0;\n bridgeTxDetails[transactionId].proofBlockNumber = 0;\n\n emit BridgeProofDisputed(transactionId, msg.sender);\n }\n\n /// @inheritdoc IFastBridge\n function refund(bytes memory request) external {\n bytes32 transactionId = keccak256(request);\n\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n\n if (bridgeTxDetails[transactionId].status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n\n if (hasRole(REFUNDER_ROLE, msg.sender)) {\n // Refunder can refund if deadline has passed\n if (block.timestamp \u003c= transaction.deadline) revert DeadlineNotExceeded();\n } else {\n // Permissionless refund is allowed after REFUND_DELAY\n if (block.timestamp \u003c= transaction.deadline + REFUND_DELAY) revert DeadlineNotExceeded();\n }\n\n // if all checks passed, set to REFUNDED status\n bridgeTxDetails[transactionId].status = BridgeStatus.REFUNDED;\n\n // transfer origin collateral back to original sender\n address to = transaction.originSender;\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount + transaction.originFeeAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (bridgeTxDetails[transactionId].proofRelayer != relayer) revert SenderIncorrect();\n return _timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n /// @dev This method is added to achieve backwards compatibility with decoding requests into V1 structs:\n /// - `callValue` is partially reported as a zero/non-zero flag\n /// - `callParams` is ignored\n /// In order to process all kinds of requests use getBridgeTransactionV2 instead.\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory) {\n // Try decoding into V2 struct first. This will revert if V1 struct is passed\n try this.getBridgeTransactionV2(request) returns (BridgeTransactionV2 memory txV2) {\n // Note: we entirely ignore the callParams field, as it was not present in V1\n return BridgeTransaction({\n originChainId: txV2.originChainId,\n destChainId: txV2.destChainId,\n originSender: txV2.originSender,\n destRecipient: txV2.destRecipient,\n originToken: txV2.originToken,\n destToken: txV2.destToken,\n originAmount: txV2.originAmount,\n destAmount: txV2.destAmount,\n originFeeAmount: txV2.originFeeAmount,\n sendChainGas: txV2.callValue != 0,\n deadline: txV2.deadline,\n nonce: txV2.nonce\n });\n } catch {\n // Fallback to V1 struct\n return abi.decode(request, (BridgeTransaction));\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) public payable {\n int256 exclusivityEndTime = int256(block.timestamp) + paramsV2.quoteExclusivitySeconds;\n _validateBridgeParams(params, paramsV2, exclusivityEndTime);\n\n // transfer tokens to bridge contract\n /// @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _takeBridgedUserAsset(params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n\n // set status to requested\n bytes memory request = abi.encode(\n BridgeTransactionV2({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n callValue: paramsV2.callValue,\n deadline: params.deadline,\n nonce: senderNonces[params.sender]++, // increment nonce on every bridge\n exclusivityRelayer: paramsV2.quoteRelayer,\n // We checked exclusivityEndTime to be in range (0 .. params.deadline] above, so can safely cast\n exclusivityEndTime: uint256(exclusivityEndTime),\n callParams: paramsV2.callParams\n })\n );\n bytes32 transactionId = keccak256(request);\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n\n emit BridgeRequested({\n transactionId: transactionId,\n sender: params.sender,\n request: request,\n destChainId: params.dstChainId,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n sendChainGas: paramsV2.callValue != 0\n });\n emit BridgeQuoteDetails(transactionId, paramsV2.quoteId);\n }\n\n /// @inheritdoc IFastBridgeV2\n function relay(bytes memory request, address relayer) public payable {\n bytes32 transactionId = keccak256(request);\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n _validateRelayParams(transaction, transactionId, relayer);\n // mark bridge transaction as relayed\n bridgeRelayDetails[transactionId] =\n BridgeRelay({blockNumber: uint48(block.number), blockTimestamp: uint48(block.timestamp), relayer: relayer});\n\n // transfer tokens to recipient on destination chain and do an arbitrary call if requested\n address to = transaction.destRecipient;\n address token = transaction.destToken;\n uint256 amount = transaction.destAmount;\n uint256 callValue = transaction.callValue;\n\n // Emit the event before any external calls\n emit BridgeRelayed({\n transactionId: transactionId,\n relayer: relayer,\n to: to,\n originChainId: transaction.originChainId,\n originToken: transaction.originToken,\n destToken: token,\n originAmount: transaction.originAmount,\n destAmount: amount,\n chainGasAmount: callValue\n });\n\n // All state changes have been done at this point, can proceed to the external calls.\n // This follows the checks-effects-interactions pattern to mitigate potential reentrancy attacks.\n if (token == UniversalTokenLib.ETH_ADDRESS) {\n // For ETH non-zero callValue is not allowed\n if (callValue != 0) revert NativeTokenCallValueNotSupported();\n // Check that the correct msg.value was sent\n if (msg.value != amount) revert MsgValueIncorrect();\n } else {\n // For ERC20s, we check that the correct msg.value was sent\n if (msg.value != callValue) revert MsgValueIncorrect();\n // We need to transfer the tokens from the Relayer to the recipient first before performing an\n // optional post-transfer arbitrary call.\n IERC20(token).safeTransferFrom(msg.sender, to, amount);\n }\n\n if (transaction.callParams.length != 0) {\n // Arbitrary call requested, perform it while supplying full msg.value to the recipient\n // Note: if token has a fee on transfers, the recipient will have received less than `amount`.\n // This is a very niche edge case and should be handled by the recipient contract.\n _checkedCallRecipient({recipient: to, token: token, amount: amount, callParams: transaction.callParams});\n } else if (msg.value != 0) {\n // No arbitrary call requested, but msg.value was sent. This is either a relay with ETH,\n // or a non-zero callValue request with an ERC20. In both cases, transfer the ETH to the recipient.\n Address.sendValue(payable(to), msg.value);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) public onlyRole(RELAYER_ROLE) {\n // update bridge tx status given proof provided\n if (bridgeTxDetails[transactionId].status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n bridgeTxDetails[transactionId].status = BridgeStatus.RELAYER_PROVED;\n bridgeTxDetails[transactionId].proofBlockTimestamp = uint40(block.timestamp);\n bridgeTxDetails[transactionId].proofBlockNumber = uint48(block.number);\n bridgeTxDetails[transactionId].proofRelayer = relayer;\n\n emit BridgeProofProvided(transactionId, relayer, destTxHash);\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes memory request, address to) public {\n bytes32 transactionId = keccak256(request);\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n\n // update bridge tx status if able to claim origin collateral\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n\n // if \"to\" is zero addr, permissionlessly send funds to proven relayer\n if (to == address(0)) {\n to = bridgeTxDetails[transactionId].proofRelayer;\n } else if (bridgeTxDetails[transactionId].proofRelayer != msg.sender) {\n revert SenderIncorrect();\n }\n\n if (_timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003c= DISPUTE_PERIOD) {\n revert DisputePeriodNotPassed();\n }\n\n bridgeTxDetails[transactionId].status = BridgeStatus.RELAYER_CLAIMED;\n\n // update protocol fees if origin fee amount exists\n if (transaction.originFeeAmount \u003e 0) protocolFees[transaction.originToken] += transaction.originFeeAmount;\n\n // transfer origin collateral less fee to specified address\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositClaimed(transactionId, bridgeTxDetails[transactionId].proofRelayer, to, token, amount);\n }\n\n function bridgeStatuses(bytes32 transactionId) public view returns (BridgeStatus status) {\n return bridgeTxDetails[transactionId].status;\n }\n\n function bridgeProofs(bytes32 transactionId) public view returns (uint96 timestamp, address relayer) {\n timestamp = bridgeTxDetails[transactionId].proofBlockTimestamp;\n relayer = bridgeTxDetails[transactionId].proofRelayer;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeRelays(bytes32 transactionId) public view returns (bool) {\n // has this transactionId been relayed?\n return bridgeRelayDetails[transactionId].relayer != address(0);\n }\n\n /// @inheritdoc IFastBridgeV2\n function getBridgeTransactionV2(bytes memory request) public pure returns (BridgeTransactionV2 memory) {\n return abi.decode(request, (BridgeTransactionV2));\n }\n\n /// @notice Takes the bridged asset from the user into FastBridgeV2 custody. It will be later\n /// claimed by the relayer who completed the relay on destination chain, or refunded back to the user,\n /// should no one complete the relay.\n function _takeBridgedUserAsset(address token, uint256 amount) internal returns (uint256 amountTaken) {\n if (token == UniversalTokenLib.ETH_ADDRESS) {\n // For ETH we just need to check that the supplied msg.value is correct.\n // Supplied `msg.value` is already in FastBridgeV2 custody.\n if (amount != msg.value) revert MsgValueIncorrect();\n amountTaken = msg.value;\n } else {\n // For ERC20s, token is explicitly transferred from the user to FastBridgeV2.\n // We don't allow non-zero `msg.value` to avoid extra funds from being stuck in FastBridgeV2.\n token.assertIsContract();\n if (msg.value != 0) revert MsgValueIncorrect();\n amountTaken = IERC20(token).balanceOf(address(this));\n IERC20(token).safeTransferFrom(msg.sender, address(this), amount);\n // Use the balance difference as the amount taken in case of fee on transfer tokens.\n amountTaken = IERC20(token).balanceOf(address(this)) - amountTaken;\n }\n }\n\n /// @notice Calls the Recipient's hook function with the specified callParams and performs\n /// all the necessary checks for the returned value.\n function _checkedCallRecipient(\n address recipient,\n address token,\n uint256 amount,\n bytes memory callParams\n )\n internal\n {\n bytes memory hookData =\n abi.encodeCall(IFastBridgeRecipient.fastBridgeTransferReceived, (token, amount, callParams));\n // This will bubble any revert messages from the hook function\n bytes memory returnData = Address.functionCallWithValue({target: recipient, data: hookData, value: msg.value});\n // Explicit revert if no return data at all\n if (returnData.length == 0) revert RecipientNoReturnValue();\n // Check that exactly a single return value was returned\n if (returnData.length != 32) revert RecipientIncorrectReturnValue();\n // Return value should be abi-encoded hook function selector\n if (bytes32(returnData) != bytes32(IFastBridgeRecipient.fastBridgeTransferReceived.selector)) {\n revert RecipientIncorrectReturnValue();\n }\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint40(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint40).max but\n /// proof.timestamp \u003c type(uint40).max via unchecked statement\n /// @param proofBlockTimestamp The bridge proof block timestamp\n /// @return delta Time delta since proof submitted\n function _timeSince(uint40 proofBlockTimestamp) internal view returns (uint256 delta) {\n unchecked {\n delta = uint40(block.timestamp) - proofBlockTimestamp;\n }\n }\n\n /// @notice Performs all the necessary checks for a bridge to happen.\n /// @dev There's no good way to refactor this function to reduce cyclomatic complexity due to\n /// the number of checks that need to be performed, so we skip the code-complexity rule here.\n // solhint-disable-next-line code-complexity\n function _validateBridgeParams(\n BridgeParams memory params,\n BridgeParamsV2 memory paramsV2,\n int256 exclusivityEndTime\n )\n internal\n view\n {\n // Check V1 (legacy) params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.sender == address(0) || params.to == address(0)) revert ZeroAddress();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n // Check V2 params\n if (paramsV2.callParams.length \u003e MAX_CALL_PARAMS_LENGTH) revert CallParamsLengthAboveMax();\n if (paramsV2.callValue != 0 \u0026\u0026 params.destToken == UniversalTokenLib.ETH_ADDRESS) {\n revert NativeTokenCallValueNotSupported();\n }\n // exclusivityEndTime must be in range (0 .. params.deadline]\n if (exclusivityEndTime \u003c= 0 || exclusivityEndTime \u003e int256(params.deadline)) {\n revert ExclusivityParamsIncorrect();\n }\n }\n\n /// @notice Performs all the necessary checks for a relay to happen.\n function _validateRelayParams(\n BridgeTransactionV2 memory transaction,\n bytes32 transactionId,\n address relayer\n )\n internal\n view\n {\n if (relayer == address(0)) revert ZeroAddress();\n // Check if the transaction has already been relayed\n if (bridgeRelays(transactionId)) revert TransactionRelayed();\n if (transaction.destChainId != block.chainid) revert ChainIncorrect();\n // Check the deadline for relay to happen\n if (block.timestamp \u003e transaction.deadline) revert DeadlineExceeded();\n // Check the exclusivity period, if it is still ongoing\n // forgefmt: disable-next-item\n if (\n transaction.exclusivityRelayer != address(0) \u0026\u0026\n transaction.exclusivityRelayer != relayer \u0026\u0026\n block.timestamp \u003c= transaction.exclusivityEndTime\n ) {\n revert ExclusivityPeriodNotPassed();\n }\n }\n}\n","language":"Solidity","languageVersion":"0.8.24","compilerVersion":"0.8.24","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"","srcMapRuntime":"","abiDefinition":[{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Transfer","type":"event"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"}],"userDoc":{"kind":"user","methods":{},"version":1},"developerDoc":{"details":"Interface of the ERC20 standard as defined in the EIP.","events":{"Approval(address,address,uint256)":{"details":"Emitted when the allowance of a `spender` for an `owner` is set by a call to {approve}. `value` is the new allowance."},"Transfer(address,address,uint256)":{"details":"Emitted when `value` tokens are moved from one account (`from`) to another (`to`). Note that `value` may be zero."}},"kind":"dev","methods":{"allowance(address,address)":{"details":"Returns the remaining number of tokens that `spender` will be allowed to spend on behalf of `owner` through {transferFrom}. This is zero by default. This value changes when {approve} or {transferFrom} are called."},"approve(address,uint256)":{"details":"Sets a `value` amount of tokens as the allowance of `spender` over the caller's tokens. Returns a boolean value indicating whether the operation succeeded. IMPORTANT: Beware that changing an allowance with this method brings the risk that someone may use both the old and the new allowance by unfortunate transaction ordering. One possible solution to mitigate this race condition is to first reduce the spender's allowance to 0 and set the desired value afterwards: https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 Emits an {Approval} event."},"balanceOf(address)":{"details":"Returns the value of tokens owned by `account`."},"totalSupply()":{"details":"Returns the value of tokens in existence."},"transfer(address,uint256)":{"details":"Moves a `value` amount of tokens from the caller's account to `to`. Returns a boolean value indicating whether the operation succeeded. Emits a {Transfer} event."},"transferFrom(address,address,uint256)":{"details":"Moves a `value` amount of tokens from `from` to `to` using the allowance mechanism. `value` is then deducted from the caller's allowance. Returns a boolean value indicating whether the operation succeeded. Emits a {Transfer} event."}},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"Approval\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"Transfer\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"}],\"name\":\"allowance\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"approve\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"balanceOf\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"totalSupply\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"transfer\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"transferFrom\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"details\":\"Interface of the ERC20 standard as defined in the EIP.\",\"events\":{\"Approval(address,address,uint256)\":{\"details\":\"Emitted when the allowance of a `spender` for an `owner` is set by a call to {approve}. `value` is the new allowance.\"},\"Transfer(address,address,uint256)\":{\"details\":\"Emitted when `value` tokens are moved from one account (`from`) to another (`to`). Note that `value` may be zero.\"}},\"kind\":\"dev\",\"methods\":{\"allowance(address,address)\":{\"details\":\"Returns the remaining number of tokens that `spender` will be allowed to spend on behalf of `owner` through {transferFrom}. This is zero by default. This value changes when {approve} or {transferFrom} are called.\"},\"approve(address,uint256)\":{\"details\":\"Sets a `value` amount of tokens as the allowance of `spender` over the caller's tokens. Returns a boolean value indicating whether the operation succeeded. IMPORTANT: Beware that changing an allowance with this method brings the risk that someone may use both the old and the new allowance by unfortunate transaction ordering. One possible solution to mitigate this race condition is to first reduce the spender's allowance to 0 and set the desired value afterwards: https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 Emits an {Approval} event.\"},\"balanceOf(address)\":{\"details\":\"Returns the value of tokens owned by `account`.\"},\"totalSupply()\":{\"details\":\"Returns the value of tokens in existence.\"},\"transfer(address,uint256)\":{\"details\":\"Moves a `value` amount of tokens from the caller's account to `to`. Returns a boolean value indicating whether the operation succeeded. Emits a {Transfer} event.\"},\"transferFrom(address,address,uint256)\":{\"details\":\"Moves a `value` amount of tokens from `from` to `to` using the allowance mechanism. `value` is then deducted from the caller's allowance. Returns a boolean value indicating whether the operation succeeded. Emits a {Transfer} event.\"}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeV2.sol\":\"IERC20\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeV2.sol\":{\"keccak256\":\"0xfd916c030b1ffca5a136817827b8018c8ba42ca089905747f3de6148b73eb35e\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://18e6438c4096deb8ae453fb3365ba2b07d52944e93c08288fc5d012b71bf6bb3\",\"dweb:/ipfs/QmfEMqpT1zz6RRm7UuHLRowe1tds2cTGLrVonfm9XSCACj\"]}},\"version\":1}"},"hashes":{"allowance(address,address)":"dd62ed3e","approve(address,uint256)":"095ea7b3","balanceOf(address)":"70a08231","totalSupply()":"18160ddd","transfer(address,uint256)":"a9059cbb","transferFrom(address,address,uint256)":"23b872dd"}},"solidity/FastBridgeV2.sol:IERC20Permit":{"code":"0x","runtime-code":"0x","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.24 ^0.8.0 ^0.8.20;\n\n// contracts/interfaces/IAdmin.sol\n\ninterface IAdmin {\n // ============ Events ============\n\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n event ChainGasAmountUpdated(uint256 oldChainGasAmount, uint256 newChainGasAmount);\n\n // ============ Methods ============\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n\n function setChainGasAmount(uint256 newChainGasAmount) external;\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IFastBridgeRecipient.sol\n\ninterface IFastBridgeRecipient {\n function fastBridgeTransferReceived(\n address token,\n uint256 amount,\n bytes memory callParams\n )\n external\n payable\n returns (bytes4);\n}\n\n// contracts/interfaces/IFastBridgeV2Errors.sol\n\ninterface IFastBridgeV2Errors {\n error AmountIncorrect();\n error CallParamsLengthAboveMax();\n error ChainIncorrect();\n error ExclusivityParamsIncorrect();\n error MsgValueIncorrect();\n error NativeTokenCallValueNotSupported();\n error SenderIncorrect();\n error StatusIncorrect();\n error ZeroAddress();\n\n error RecipientIncorrectReturnValue();\n error RecipientNoReturnValue();\n\n error DeadlineExceeded();\n error DeadlineNotExceeded();\n error DeadlineTooShort();\n error DisputePeriodNotPassed();\n error DisputePeriodPassed();\n error ExclusivityPeriodNotPassed();\n\n error TransactionRelayed();\n}\n\n// contracts/libs/Errors.sol\n\nerror DeadlineExceeded();\nerror DeadlineNotExceeded();\nerror DeadlineTooShort();\nerror InsufficientOutputAmount();\n\nerror MsgValueIncorrect();\nerror PoolNotFound();\nerror TokenAddressMismatch();\nerror TokenNotContract();\nerror TokenNotETH();\nerror TokensIdentical();\n\nerror ChainIncorrect();\nerror AmountIncorrect();\nerror ZeroAddress();\n\nerror DisputePeriodNotPassed();\nerror DisputePeriodPassed();\nerror SenderIncorrect();\nerror StatusIncorrect();\nerror TransactionIdIncorrect();\nerror TransactionRelayed();\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// contracts/interfaces/IFastBridgeV2.sol\n\ninterface IFastBridgeV2 is IFastBridge {\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n struct BridgeTxDetails {\n BridgeStatus status;\n uint40 proofBlockTimestamp;\n uint48 proofBlockNumber;\n address proofRelayer;\n }\n\n struct BridgeRelay {\n uint48 blockNumber;\n uint48 blockTimestamp;\n address relayer;\n }\n\n /// @notice New params introduced in the FastBridgeV2.\n /// We are passing fields from the older BridgeParams struct outside of this struct\n /// for backwards compatibility.\n /// Note: quoteRelayer and quoteExclusivitySeconds are either both zero (indicating no exclusivity)\n /// or both non-zero (indicating exclusivity for the given period).\n /// Note: callValue \u003e 0 can NOT be used with destToken = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE (ETH_ADDRESS)\n /// @param quoteRelayer Relayer that provided the quote for the transaction\n /// @param quoteExclusivitySeconds Period of time the quote relayer is guaranteed exclusivity after user's deposit\n /// @param quoteId Unique quote identifier used for tracking the quote\n /// @param callValue ETH value to send to the recipient (if any)\n /// @param callParams Parameters for the arbitrary call to the destination recipient (if any)\n struct BridgeParamsV2 {\n address quoteRelayer;\n int256 quoteExclusivitySeconds;\n bytes quoteId;\n uint256 callValue;\n bytes callParams;\n }\n\n /// @notice Updated bridge transaction struct to include parameters introduced in FastBridgeV2.\n /// Note: only `exclusivityRelayer` can fill such a transaction until `exclusivityEndTime`.\n /// TODO: consider changing the encoding scheme to prevent spending extra gas on decoding.\n struct BridgeTransactionV2 {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n uint256 callValue; // ETH value to send to the recipient (if any) - replaces V1's sendChainGas flag\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n address exclusivityRelayer;\n uint256 exclusivityEndTime;\n bytes callParams;\n }\n\n event BridgeQuoteDetails(bytes32 indexed transactionId, bytes quoteId);\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability\n /// to provide temporary exclusivity fill rights for the quote relayer.\n /// @param params The parameters required to bridge\n /// @param paramsV2 The parameters for exclusivity fill rights (optional, can be left empty)\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function relay(bytes memory request, address relayer) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param transactionId The transaction id associated with the encoded bridge transaction to prove\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital.\n /// @notice Can only send funds to the relayer address on the proof.\n /// @param request The encoded bridge transaction to claim on origin chain\n function claim(bytes memory request) external;\n /// @notice Checks if a transaction has been relayed\n /// @param transactionId The ID of the transaction to check\n /// @return True if the transaction has been relayed, false otherwise\n function bridgeRelays(bytes32 transactionId) external view returns (bool);\n\n /// @notice Returns the status of a bridge transaction\n /// @param transactionId The ID of the bridge transaction\n /// @return BridgeStatus Status of the bridge transaction\n function bridgeStatuses(bytes32 transactionId) external view returns (BridgeStatus);\n\n /// @notice Returns the timestamp and relayer of a bridge proof\n /// @param transactionId The ID of the bridge transaction\n /// @return timestamp The timestamp of the bridge proof\n /// @return relayer The relayer address of the bridge proof\n function bridgeProofs(bytes32 transactionId) external view returns (uint96 timestamp, address relayer);\n\n /// @notice Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\n /// @param request The bridge request to decode\n function getBridgeTransactionV2(bytes memory request) external view returns (BridgeTransactionV2 memory);\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// contracts/libs/UniversalToken.sol\n\nlibrary UniversalTokenLib {\n using SafeERC20 for IERC20;\n\n address internal constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Transfers tokens to the given account. Reverts if transfer is not successful.\n /// @dev This might trigger fallback, if ETH is transferred to the contract.\n /// Make sure this can not lead to reentrancy attacks.\n function universalTransfer(address token, address to, uint256 value) internal {\n // Don't do anything, if need to send tokens to this address\n if (to == address(this)) return;\n // Don't do anything, if trying to send zero value\n if (value == 0) return;\n if (token == ETH_ADDRESS) {\n /// @dev Note: this can potentially lead to executing code in `to`.\n // solhint-disable-next-line avoid-low-level-calls\n (bool success,) = to.call{value: value}(\"\");\n require(success, \"ETH transfer failed\");\n } else {\n IERC20(token).safeTransfer(to, value);\n }\n }\n\n /// @notice Issues an infinite allowance to the spender, if the current allowance is insufficient\n /// to spend the given amount.\n function universalApproveInfinity(address token, address spender, uint256 amountToSpend) internal {\n // ETH Chad doesn't require your approval\n if (token == ETH_ADDRESS) return;\n // No-op if allowance is already sufficient\n uint256 allowance = IERC20(token).allowance(address(this), spender);\n if (allowance \u003e= amountToSpend) return;\n // Otherwise, reset approval to 0 and set to max allowance\n if (allowance \u003e 0) IERC20(token).safeDecreaseAllowance(spender, allowance);\n IERC20(token).safeIncreaseAllowance(spender, type(uint256).max);\n }\n\n /// @notice Returns the balance of the given token (or native ETH) for the given account.\n function universalBalanceOf(address token, address account) internal view returns (uint256) {\n if (token == ETH_ADDRESS) {\n return account.balance;\n } else {\n return IERC20(token).balanceOf(account);\n }\n }\n\n /// @dev Checks that token is a contract and not ETH_ADDRESS.\n function assertIsContract(address token) internal view {\n // Check that ETH_ADDRESS was not used (in case this is a predeploy on any of the chains)\n if (token == UniversalTokenLib.ETH_ADDRESS) revert TokenNotContract();\n // Check that token is not an EOA\n if (token.code.length == 0) revert TokenNotContract();\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/Admin.sol\n\ncontract Admin is IAdmin, AccessControlEnumerable {\n using UniversalTokenLib for address;\n\n bytes32 public constant RELAYER_ROLE = keccak256(\"RELAYER_ROLE\");\n bytes32 public constant REFUNDER_ROLE = keccak256(\"REFUNDER_ROLE\");\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n uint256 public constant FEE_BPS = 1e6;\n uint256 public constant FEE_RATE_MAX = 0.01e6; // max 1% on origin amount\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Chain gas amount to forward as rebate if requested\n uint256 public chainGasAmount;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n }\n\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n require(newFeeRate \u003c= FEE_RATE_MAX, \"newFeeRate \u003e max\");\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n token.universalTransfer(recipient, feeAmount);\n emit FeesSwept(token, recipient, feeAmount);\n }\n\n function setChainGasAmount(uint256 newChainGasAmount) external onlyRole(GOVERNOR_ROLE) {\n uint256 oldChainGasAmount = chainGasAmount;\n chainGasAmount = newChainGasAmount;\n emit ChainGasAmountUpdated(oldChainGasAmount, newChainGasAmount);\n }\n}\n\n// contracts/FastBridgeV2.sol\n\n/// @notice FastBridgeV2 is a contract for bridging tokens across chains.\ncontract FastBridgeV2 is Admin, IFastBridgeV2, IFastBridgeV2Errors {\n using SafeERC20 for IERC20;\n using UniversalTokenLib for address;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Delay for a transaction after which it could be permisionlessly refunded\n uint256 public constant REFUND_DELAY = 7 days;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n /// @notice Maximum length of accepted callParams\n uint256 public constant MAX_CALL_PARAMS_LENGTH = 2 ** 16 - 1;\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeTxDetails) public bridgeTxDetails;\n /// @notice Relay details on destination chain\n mapping(bytes32 =\u003e BridgeRelay) public bridgeRelayDetails;\n /// @notice Unique bridge nonces tracked per originSender\n mapping(address =\u003e uint256) public senderNonces;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Replaced by senderNonces\n uint256 public immutable nonce = 0;\n /// @notice the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n bridge({\n params: params,\n paramsV2: BridgeParamsV2({\n quoteRelayer: address(0),\n quoteExclusivitySeconds: 0,\n quoteId: bytes(\"\"),\n callValue: 0,\n callParams: bytes(\"\")\n })\n });\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes memory request) external payable {\n relay({request: request, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes memory request, bytes32 destTxHash) external {\n prove({transactionId: keccak256(request), destTxHash: destTxHash, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridgeV2\n function claim(bytes memory request) external {\n claim({request: request, to: address(0)});\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003e DISPUTE_PERIOD) {\n revert DisputePeriodPassed();\n }\n\n // @dev relayer gets slashed effectively if dest relay has gone thru\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n bridgeTxDetails[transactionId].proofRelayer = address(0);\n bridgeTxDetails[transactionId].proofBlockTimestamp = 0;\n bridgeTxDetails[transactionId].proofBlockNumber = 0;\n\n emit BridgeProofDisputed(transactionId, msg.sender);\n }\n\n /// @inheritdoc IFastBridge\n function refund(bytes memory request) external {\n bytes32 transactionId = keccak256(request);\n\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n\n if (bridgeTxDetails[transactionId].status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n\n if (hasRole(REFUNDER_ROLE, msg.sender)) {\n // Refunder can refund if deadline has passed\n if (block.timestamp \u003c= transaction.deadline) revert DeadlineNotExceeded();\n } else {\n // Permissionless refund is allowed after REFUND_DELAY\n if (block.timestamp \u003c= transaction.deadline + REFUND_DELAY) revert DeadlineNotExceeded();\n }\n\n // if all checks passed, set to REFUNDED status\n bridgeTxDetails[transactionId].status = BridgeStatus.REFUNDED;\n\n // transfer origin collateral back to original sender\n address to = transaction.originSender;\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount + transaction.originFeeAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (bridgeTxDetails[transactionId].proofRelayer != relayer) revert SenderIncorrect();\n return _timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n /// @dev This method is added to achieve backwards compatibility with decoding requests into V1 structs:\n /// - `callValue` is partially reported as a zero/non-zero flag\n /// - `callParams` is ignored\n /// In order to process all kinds of requests use getBridgeTransactionV2 instead.\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory) {\n // Try decoding into V2 struct first. This will revert if V1 struct is passed\n try this.getBridgeTransactionV2(request) returns (BridgeTransactionV2 memory txV2) {\n // Note: we entirely ignore the callParams field, as it was not present in V1\n return BridgeTransaction({\n originChainId: txV2.originChainId,\n destChainId: txV2.destChainId,\n originSender: txV2.originSender,\n destRecipient: txV2.destRecipient,\n originToken: txV2.originToken,\n destToken: txV2.destToken,\n originAmount: txV2.originAmount,\n destAmount: txV2.destAmount,\n originFeeAmount: txV2.originFeeAmount,\n sendChainGas: txV2.callValue != 0,\n deadline: txV2.deadline,\n nonce: txV2.nonce\n });\n } catch {\n // Fallback to V1 struct\n return abi.decode(request, (BridgeTransaction));\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) public payable {\n int256 exclusivityEndTime = int256(block.timestamp) + paramsV2.quoteExclusivitySeconds;\n _validateBridgeParams(params, paramsV2, exclusivityEndTime);\n\n // transfer tokens to bridge contract\n /// @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _takeBridgedUserAsset(params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n\n // set status to requested\n bytes memory request = abi.encode(\n BridgeTransactionV2({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n callValue: paramsV2.callValue,\n deadline: params.deadline,\n nonce: senderNonces[params.sender]++, // increment nonce on every bridge\n exclusivityRelayer: paramsV2.quoteRelayer,\n // We checked exclusivityEndTime to be in range (0 .. params.deadline] above, so can safely cast\n exclusivityEndTime: uint256(exclusivityEndTime),\n callParams: paramsV2.callParams\n })\n );\n bytes32 transactionId = keccak256(request);\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n\n emit BridgeRequested({\n transactionId: transactionId,\n sender: params.sender,\n request: request,\n destChainId: params.dstChainId,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n sendChainGas: paramsV2.callValue != 0\n });\n emit BridgeQuoteDetails(transactionId, paramsV2.quoteId);\n }\n\n /// @inheritdoc IFastBridgeV2\n function relay(bytes memory request, address relayer) public payable {\n bytes32 transactionId = keccak256(request);\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n _validateRelayParams(transaction, transactionId, relayer);\n // mark bridge transaction as relayed\n bridgeRelayDetails[transactionId] =\n BridgeRelay({blockNumber: uint48(block.number), blockTimestamp: uint48(block.timestamp), relayer: relayer});\n\n // transfer tokens to recipient on destination chain and do an arbitrary call if requested\n address to = transaction.destRecipient;\n address token = transaction.destToken;\n uint256 amount = transaction.destAmount;\n uint256 callValue = transaction.callValue;\n\n // Emit the event before any external calls\n emit BridgeRelayed({\n transactionId: transactionId,\n relayer: relayer,\n to: to,\n originChainId: transaction.originChainId,\n originToken: transaction.originToken,\n destToken: token,\n originAmount: transaction.originAmount,\n destAmount: amount,\n chainGasAmount: callValue\n });\n\n // All state changes have been done at this point, can proceed to the external calls.\n // This follows the checks-effects-interactions pattern to mitigate potential reentrancy attacks.\n if (token == UniversalTokenLib.ETH_ADDRESS) {\n // For ETH non-zero callValue is not allowed\n if (callValue != 0) revert NativeTokenCallValueNotSupported();\n // Check that the correct msg.value was sent\n if (msg.value != amount) revert MsgValueIncorrect();\n } else {\n // For ERC20s, we check that the correct msg.value was sent\n if (msg.value != callValue) revert MsgValueIncorrect();\n // We need to transfer the tokens from the Relayer to the recipient first before performing an\n // optional post-transfer arbitrary call.\n IERC20(token).safeTransferFrom(msg.sender, to, amount);\n }\n\n if (transaction.callParams.length != 0) {\n // Arbitrary call requested, perform it while supplying full msg.value to the recipient\n // Note: if token has a fee on transfers, the recipient will have received less than `amount`.\n // This is a very niche edge case and should be handled by the recipient contract.\n _checkedCallRecipient({recipient: to, token: token, amount: amount, callParams: transaction.callParams});\n } else if (msg.value != 0) {\n // No arbitrary call requested, but msg.value was sent. This is either a relay with ETH,\n // or a non-zero callValue request with an ERC20. In both cases, transfer the ETH to the recipient.\n Address.sendValue(payable(to), msg.value);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) public onlyRole(RELAYER_ROLE) {\n // update bridge tx status given proof provided\n if (bridgeTxDetails[transactionId].status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n bridgeTxDetails[transactionId].status = BridgeStatus.RELAYER_PROVED;\n bridgeTxDetails[transactionId].proofBlockTimestamp = uint40(block.timestamp);\n bridgeTxDetails[transactionId].proofBlockNumber = uint48(block.number);\n bridgeTxDetails[transactionId].proofRelayer = relayer;\n\n emit BridgeProofProvided(transactionId, relayer, destTxHash);\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes memory request, address to) public {\n bytes32 transactionId = keccak256(request);\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n\n // update bridge tx status if able to claim origin collateral\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n\n // if \"to\" is zero addr, permissionlessly send funds to proven relayer\n if (to == address(0)) {\n to = bridgeTxDetails[transactionId].proofRelayer;\n } else if (bridgeTxDetails[transactionId].proofRelayer != msg.sender) {\n revert SenderIncorrect();\n }\n\n if (_timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003c= DISPUTE_PERIOD) {\n revert DisputePeriodNotPassed();\n }\n\n bridgeTxDetails[transactionId].status = BridgeStatus.RELAYER_CLAIMED;\n\n // update protocol fees if origin fee amount exists\n if (transaction.originFeeAmount \u003e 0) protocolFees[transaction.originToken] += transaction.originFeeAmount;\n\n // transfer origin collateral less fee to specified address\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositClaimed(transactionId, bridgeTxDetails[transactionId].proofRelayer, to, token, amount);\n }\n\n function bridgeStatuses(bytes32 transactionId) public view returns (BridgeStatus status) {\n return bridgeTxDetails[transactionId].status;\n }\n\n function bridgeProofs(bytes32 transactionId) public view returns (uint96 timestamp, address relayer) {\n timestamp = bridgeTxDetails[transactionId].proofBlockTimestamp;\n relayer = bridgeTxDetails[transactionId].proofRelayer;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeRelays(bytes32 transactionId) public view returns (bool) {\n // has this transactionId been relayed?\n return bridgeRelayDetails[transactionId].relayer != address(0);\n }\n\n /// @inheritdoc IFastBridgeV2\n function getBridgeTransactionV2(bytes memory request) public pure returns (BridgeTransactionV2 memory) {\n return abi.decode(request, (BridgeTransactionV2));\n }\n\n /// @notice Takes the bridged asset from the user into FastBridgeV2 custody. It will be later\n /// claimed by the relayer who completed the relay on destination chain, or refunded back to the user,\n /// should no one complete the relay.\n function _takeBridgedUserAsset(address token, uint256 amount) internal returns (uint256 amountTaken) {\n if (token == UniversalTokenLib.ETH_ADDRESS) {\n // For ETH we just need to check that the supplied msg.value is correct.\n // Supplied `msg.value` is already in FastBridgeV2 custody.\n if (amount != msg.value) revert MsgValueIncorrect();\n amountTaken = msg.value;\n } else {\n // For ERC20s, token is explicitly transferred from the user to FastBridgeV2.\n // We don't allow non-zero `msg.value` to avoid extra funds from being stuck in FastBridgeV2.\n token.assertIsContract();\n if (msg.value != 0) revert MsgValueIncorrect();\n amountTaken = IERC20(token).balanceOf(address(this));\n IERC20(token).safeTransferFrom(msg.sender, address(this), amount);\n // Use the balance difference as the amount taken in case of fee on transfer tokens.\n amountTaken = IERC20(token).balanceOf(address(this)) - amountTaken;\n }\n }\n\n /// @notice Calls the Recipient's hook function with the specified callParams and performs\n /// all the necessary checks for the returned value.\n function _checkedCallRecipient(\n address recipient,\n address token,\n uint256 amount,\n bytes memory callParams\n )\n internal\n {\n bytes memory hookData =\n abi.encodeCall(IFastBridgeRecipient.fastBridgeTransferReceived, (token, amount, callParams));\n // This will bubble any revert messages from the hook function\n bytes memory returnData = Address.functionCallWithValue({target: recipient, data: hookData, value: msg.value});\n // Explicit revert if no return data at all\n if (returnData.length == 0) revert RecipientNoReturnValue();\n // Check that exactly a single return value was returned\n if (returnData.length != 32) revert RecipientIncorrectReturnValue();\n // Return value should be abi-encoded hook function selector\n if (bytes32(returnData) != bytes32(IFastBridgeRecipient.fastBridgeTransferReceived.selector)) {\n revert RecipientIncorrectReturnValue();\n }\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint40(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint40).max but\n /// proof.timestamp \u003c type(uint40).max via unchecked statement\n /// @param proofBlockTimestamp The bridge proof block timestamp\n /// @return delta Time delta since proof submitted\n function _timeSince(uint40 proofBlockTimestamp) internal view returns (uint256 delta) {\n unchecked {\n delta = uint40(block.timestamp) - proofBlockTimestamp;\n }\n }\n\n /// @notice Performs all the necessary checks for a bridge to happen.\n /// @dev There's no good way to refactor this function to reduce cyclomatic complexity due to\n /// the number of checks that need to be performed, so we skip the code-complexity rule here.\n // solhint-disable-next-line code-complexity\n function _validateBridgeParams(\n BridgeParams memory params,\n BridgeParamsV2 memory paramsV2,\n int256 exclusivityEndTime\n )\n internal\n view\n {\n // Check V1 (legacy) params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.sender == address(0) || params.to == address(0)) revert ZeroAddress();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n // Check V2 params\n if (paramsV2.callParams.length \u003e MAX_CALL_PARAMS_LENGTH) revert CallParamsLengthAboveMax();\n if (paramsV2.callValue != 0 \u0026\u0026 params.destToken == UniversalTokenLib.ETH_ADDRESS) {\n revert NativeTokenCallValueNotSupported();\n }\n // exclusivityEndTime must be in range (0 .. params.deadline]\n if (exclusivityEndTime \u003c= 0 || exclusivityEndTime \u003e int256(params.deadline)) {\n revert ExclusivityParamsIncorrect();\n }\n }\n\n /// @notice Performs all the necessary checks for a relay to happen.\n function _validateRelayParams(\n BridgeTransactionV2 memory transaction,\n bytes32 transactionId,\n address relayer\n )\n internal\n view\n {\n if (relayer == address(0)) revert ZeroAddress();\n // Check if the transaction has already been relayed\n if (bridgeRelays(transactionId)) revert TransactionRelayed();\n if (transaction.destChainId != block.chainid) revert ChainIncorrect();\n // Check the deadline for relay to happen\n if (block.timestamp \u003e transaction.deadline) revert DeadlineExceeded();\n // Check the exclusivity period, if it is still ongoing\n // forgefmt: disable-next-item\n if (\n transaction.exclusivityRelayer != address(0) \u0026\u0026\n transaction.exclusivityRelayer != relayer \u0026\u0026\n block.timestamp \u003c= transaction.exclusivityEndTime\n ) {\n revert ExclusivityPeriodNotPassed();\n }\n }\n}\n","language":"Solidity","languageVersion":"0.8.24","compilerVersion":"0.8.24","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"","srcMapRuntime":"","abiDefinition":[{"inputs":[],"name":"DOMAIN_SEPARATOR","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"nonces","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"permit","outputs":[],"stateMutability":"nonpayable","type":"function"}],"userDoc":{"kind":"user","methods":{},"version":1},"developerDoc":{"details":"Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in https://eips.ethereum.org/EIPS/eip-2612[EIP-2612]. Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't need to send a transaction, and thus is not required to hold Ether at all. ==== Security Considerations There are two important considerations concerning the use of `permit`. The first is that a valid permit signature expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be considered as an intention to spend the allowance in any specific way. The second is that because permits have built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be generally recommended is: ```solidity function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public { try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {} doThing(..., value); } function doThing(..., uint256 value) public { token.safeTransferFrom(msg.sender, address(this), value); ... } ``` Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also {SafeERC20-safeTransferFrom}). Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so contracts should have entry points that don't rely on permit.","kind":"dev","methods":{"DOMAIN_SEPARATOR()":{"details":"Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}."},"nonces(address)":{"details":"Returns the current nonce for `owner`. This value must be included whenever a signature is generated for {permit}. Every successful call to {permit} increases ``owner``'s nonce by one. This prevents a signature from being used multiple times."},"permit(address,address,uint256,uint256,uint8,bytes32,bytes32)":{"details":"Sets `value` as the allowance of `spender` over ``owner``'s tokens, given ``owner``'s signed approval. IMPORTANT: The same issues {IERC20-approve} has related to transaction ordering also apply here. Emits an {Approval} event. Requirements: - `spender` cannot be the zero address. - `deadline` must be a timestamp in the future. - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner` over the EIP712-formatted function arguments. - the signature must use ``owner``'s current nonce (see {nonces}). For more information on the signature format, see the https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP section]. CAUTION: See Security Considerations above."}},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[],\"name\":\"DOMAIN_SEPARATOR\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"}],\"name\":\"nonces\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"},{\"internalType\":\"uint8\",\"name\":\"v\",\"type\":\"uint8\"},{\"internalType\":\"bytes32\",\"name\":\"r\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"s\",\"type\":\"bytes32\"}],\"name\":\"permit\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"details\":\"Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in https://eips.ethereum.org/EIPS/eip-2612[EIP-2612]. Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't need to send a transaction, and thus is not required to hold Ether at all. ==== Security Considerations There are two important considerations concerning the use of `permit`. The first is that a valid permit signature expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be considered as an intention to spend the allowance in any specific way. The second is that because permits have built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be generally recommended is: ```solidity function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public { try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {} doThing(..., value); } function doThing(..., uint256 value) public { token.safeTransferFrom(msg.sender, address(this), value); ... } ``` Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also {SafeERC20-safeTransferFrom}). Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so contracts should have entry points that don't rely on permit.\",\"kind\":\"dev\",\"methods\":{\"DOMAIN_SEPARATOR()\":{\"details\":\"Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\"},\"nonces(address)\":{\"details\":\"Returns the current nonce for `owner`. This value must be included whenever a signature is generated for {permit}. Every successful call to {permit} increases ``owner``'s nonce by one. This prevents a signature from being used multiple times.\"},\"permit(address,address,uint256,uint256,uint8,bytes32,bytes32)\":{\"details\":\"Sets `value` as the allowance of `spender` over ``owner``'s tokens, given ``owner``'s signed approval. IMPORTANT: The same issues {IERC20-approve} has related to transaction ordering also apply here. Emits an {Approval} event. Requirements: - `spender` cannot be the zero address. - `deadline` must be a timestamp in the future. - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner` over the EIP712-formatted function arguments. - the signature must use ``owner``'s current nonce (see {nonces}). For more information on the signature format, see the https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP section]. CAUTION: See Security Considerations above.\"}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeV2.sol\":\"IERC20Permit\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeV2.sol\":{\"keccak256\":\"0xfd916c030b1ffca5a136817827b8018c8ba42ca089905747f3de6148b73eb35e\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://18e6438c4096deb8ae453fb3365ba2b07d52944e93c08288fc5d012b71bf6bb3\",\"dweb:/ipfs/QmfEMqpT1zz6RRm7UuHLRowe1tds2cTGLrVonfm9XSCACj\"]}},\"version\":1}"},"hashes":{"DOMAIN_SEPARATOR()":"3644e515","nonces(address)":"7ecebe00","permit(address,address,uint256,uint256,uint8,bytes32,bytes32)":"d505accf"}},"solidity/FastBridgeV2.sol:IFastBridge":{"code":"0x","runtime-code":"0x","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.24 ^0.8.0 ^0.8.20;\n\n// contracts/interfaces/IAdmin.sol\n\ninterface IAdmin {\n // ============ Events ============\n\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n event ChainGasAmountUpdated(uint256 oldChainGasAmount, uint256 newChainGasAmount);\n\n // ============ Methods ============\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n\n function setChainGasAmount(uint256 newChainGasAmount) external;\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IFastBridgeRecipient.sol\n\ninterface IFastBridgeRecipient {\n function fastBridgeTransferReceived(\n address token,\n uint256 amount,\n bytes memory callParams\n )\n external\n payable\n returns (bytes4);\n}\n\n// contracts/interfaces/IFastBridgeV2Errors.sol\n\ninterface IFastBridgeV2Errors {\n error AmountIncorrect();\n error CallParamsLengthAboveMax();\n error ChainIncorrect();\n error ExclusivityParamsIncorrect();\n error MsgValueIncorrect();\n error NativeTokenCallValueNotSupported();\n error SenderIncorrect();\n error StatusIncorrect();\n error ZeroAddress();\n\n error RecipientIncorrectReturnValue();\n error RecipientNoReturnValue();\n\n error DeadlineExceeded();\n error DeadlineNotExceeded();\n error DeadlineTooShort();\n error DisputePeriodNotPassed();\n error DisputePeriodPassed();\n error ExclusivityPeriodNotPassed();\n\n error TransactionRelayed();\n}\n\n// contracts/libs/Errors.sol\n\nerror DeadlineExceeded();\nerror DeadlineNotExceeded();\nerror DeadlineTooShort();\nerror InsufficientOutputAmount();\n\nerror MsgValueIncorrect();\nerror PoolNotFound();\nerror TokenAddressMismatch();\nerror TokenNotContract();\nerror TokenNotETH();\nerror TokensIdentical();\n\nerror ChainIncorrect();\nerror AmountIncorrect();\nerror ZeroAddress();\n\nerror DisputePeriodNotPassed();\nerror DisputePeriodPassed();\nerror SenderIncorrect();\nerror StatusIncorrect();\nerror TransactionIdIncorrect();\nerror TransactionRelayed();\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// contracts/interfaces/IFastBridgeV2.sol\n\ninterface IFastBridgeV2 is IFastBridge {\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n struct BridgeTxDetails {\n BridgeStatus status;\n uint40 proofBlockTimestamp;\n uint48 proofBlockNumber;\n address proofRelayer;\n }\n\n struct BridgeRelay {\n uint48 blockNumber;\n uint48 blockTimestamp;\n address relayer;\n }\n\n /// @notice New params introduced in the FastBridgeV2.\n /// We are passing fields from the older BridgeParams struct outside of this struct\n /// for backwards compatibility.\n /// Note: quoteRelayer and quoteExclusivitySeconds are either both zero (indicating no exclusivity)\n /// or both non-zero (indicating exclusivity for the given period).\n /// Note: callValue \u003e 0 can NOT be used with destToken = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE (ETH_ADDRESS)\n /// @param quoteRelayer Relayer that provided the quote for the transaction\n /// @param quoteExclusivitySeconds Period of time the quote relayer is guaranteed exclusivity after user's deposit\n /// @param quoteId Unique quote identifier used for tracking the quote\n /// @param callValue ETH value to send to the recipient (if any)\n /// @param callParams Parameters for the arbitrary call to the destination recipient (if any)\n struct BridgeParamsV2 {\n address quoteRelayer;\n int256 quoteExclusivitySeconds;\n bytes quoteId;\n uint256 callValue;\n bytes callParams;\n }\n\n /// @notice Updated bridge transaction struct to include parameters introduced in FastBridgeV2.\n /// Note: only `exclusivityRelayer` can fill such a transaction until `exclusivityEndTime`.\n /// TODO: consider changing the encoding scheme to prevent spending extra gas on decoding.\n struct BridgeTransactionV2 {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n uint256 callValue; // ETH value to send to the recipient (if any) - replaces V1's sendChainGas flag\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n address exclusivityRelayer;\n uint256 exclusivityEndTime;\n bytes callParams;\n }\n\n event BridgeQuoteDetails(bytes32 indexed transactionId, bytes quoteId);\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability\n /// to provide temporary exclusivity fill rights for the quote relayer.\n /// @param params The parameters required to bridge\n /// @param paramsV2 The parameters for exclusivity fill rights (optional, can be left empty)\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function relay(bytes memory request, address relayer) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param transactionId The transaction id associated with the encoded bridge transaction to prove\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital.\n /// @notice Can only send funds to the relayer address on the proof.\n /// @param request The encoded bridge transaction to claim on origin chain\n function claim(bytes memory request) external;\n /// @notice Checks if a transaction has been relayed\n /// @param transactionId The ID of the transaction to check\n /// @return True if the transaction has been relayed, false otherwise\n function bridgeRelays(bytes32 transactionId) external view returns (bool);\n\n /// @notice Returns the status of a bridge transaction\n /// @param transactionId The ID of the bridge transaction\n /// @return BridgeStatus Status of the bridge transaction\n function bridgeStatuses(bytes32 transactionId) external view returns (BridgeStatus);\n\n /// @notice Returns the timestamp and relayer of a bridge proof\n /// @param transactionId The ID of the bridge transaction\n /// @return timestamp The timestamp of the bridge proof\n /// @return relayer The relayer address of the bridge proof\n function bridgeProofs(bytes32 transactionId) external view returns (uint96 timestamp, address relayer);\n\n /// @notice Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\n /// @param request The bridge request to decode\n function getBridgeTransactionV2(bytes memory request) external view returns (BridgeTransactionV2 memory);\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// contracts/libs/UniversalToken.sol\n\nlibrary UniversalTokenLib {\n using SafeERC20 for IERC20;\n\n address internal constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Transfers tokens to the given account. Reverts if transfer is not successful.\n /// @dev This might trigger fallback, if ETH is transferred to the contract.\n /// Make sure this can not lead to reentrancy attacks.\n function universalTransfer(address token, address to, uint256 value) internal {\n // Don't do anything, if need to send tokens to this address\n if (to == address(this)) return;\n // Don't do anything, if trying to send zero value\n if (value == 0) return;\n if (token == ETH_ADDRESS) {\n /// @dev Note: this can potentially lead to executing code in `to`.\n // solhint-disable-next-line avoid-low-level-calls\n (bool success,) = to.call{value: value}(\"\");\n require(success, \"ETH transfer failed\");\n } else {\n IERC20(token).safeTransfer(to, value);\n }\n }\n\n /// @notice Issues an infinite allowance to the spender, if the current allowance is insufficient\n /// to spend the given amount.\n function universalApproveInfinity(address token, address spender, uint256 amountToSpend) internal {\n // ETH Chad doesn't require your approval\n if (token == ETH_ADDRESS) return;\n // No-op if allowance is already sufficient\n uint256 allowance = IERC20(token).allowance(address(this), spender);\n if (allowance \u003e= amountToSpend) return;\n // Otherwise, reset approval to 0 and set to max allowance\n if (allowance \u003e 0) IERC20(token).safeDecreaseAllowance(spender, allowance);\n IERC20(token).safeIncreaseAllowance(spender, type(uint256).max);\n }\n\n /// @notice Returns the balance of the given token (or native ETH) for the given account.\n function universalBalanceOf(address token, address account) internal view returns (uint256) {\n if (token == ETH_ADDRESS) {\n return account.balance;\n } else {\n return IERC20(token).balanceOf(account);\n }\n }\n\n /// @dev Checks that token is a contract and not ETH_ADDRESS.\n function assertIsContract(address token) internal view {\n // Check that ETH_ADDRESS was not used (in case this is a predeploy on any of the chains)\n if (token == UniversalTokenLib.ETH_ADDRESS) revert TokenNotContract();\n // Check that token is not an EOA\n if (token.code.length == 0) revert TokenNotContract();\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/Admin.sol\n\ncontract Admin is IAdmin, AccessControlEnumerable {\n using UniversalTokenLib for address;\n\n bytes32 public constant RELAYER_ROLE = keccak256(\"RELAYER_ROLE\");\n bytes32 public constant REFUNDER_ROLE = keccak256(\"REFUNDER_ROLE\");\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n uint256 public constant FEE_BPS = 1e6;\n uint256 public constant FEE_RATE_MAX = 0.01e6; // max 1% on origin amount\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Chain gas amount to forward as rebate if requested\n uint256 public chainGasAmount;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n }\n\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n require(newFeeRate \u003c= FEE_RATE_MAX, \"newFeeRate \u003e max\");\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n token.universalTransfer(recipient, feeAmount);\n emit FeesSwept(token, recipient, feeAmount);\n }\n\n function setChainGasAmount(uint256 newChainGasAmount) external onlyRole(GOVERNOR_ROLE) {\n uint256 oldChainGasAmount = chainGasAmount;\n chainGasAmount = newChainGasAmount;\n emit ChainGasAmountUpdated(oldChainGasAmount, newChainGasAmount);\n }\n}\n\n// contracts/FastBridgeV2.sol\n\n/// @notice FastBridgeV2 is a contract for bridging tokens across chains.\ncontract FastBridgeV2 is Admin, IFastBridgeV2, IFastBridgeV2Errors {\n using SafeERC20 for IERC20;\n using UniversalTokenLib for address;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Delay for a transaction after which it could be permisionlessly refunded\n uint256 public constant REFUND_DELAY = 7 days;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n /// @notice Maximum length of accepted callParams\n uint256 public constant MAX_CALL_PARAMS_LENGTH = 2 ** 16 - 1;\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeTxDetails) public bridgeTxDetails;\n /// @notice Relay details on destination chain\n mapping(bytes32 =\u003e BridgeRelay) public bridgeRelayDetails;\n /// @notice Unique bridge nonces tracked per originSender\n mapping(address =\u003e uint256) public senderNonces;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Replaced by senderNonces\n uint256 public immutable nonce = 0;\n /// @notice the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n bridge({\n params: params,\n paramsV2: BridgeParamsV2({\n quoteRelayer: address(0),\n quoteExclusivitySeconds: 0,\n quoteId: bytes(\"\"),\n callValue: 0,\n callParams: bytes(\"\")\n })\n });\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes memory request) external payable {\n relay({request: request, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes memory request, bytes32 destTxHash) external {\n prove({transactionId: keccak256(request), destTxHash: destTxHash, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridgeV2\n function claim(bytes memory request) external {\n claim({request: request, to: address(0)});\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003e DISPUTE_PERIOD) {\n revert DisputePeriodPassed();\n }\n\n // @dev relayer gets slashed effectively if dest relay has gone thru\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n bridgeTxDetails[transactionId].proofRelayer = address(0);\n bridgeTxDetails[transactionId].proofBlockTimestamp = 0;\n bridgeTxDetails[transactionId].proofBlockNumber = 0;\n\n emit BridgeProofDisputed(transactionId, msg.sender);\n }\n\n /// @inheritdoc IFastBridge\n function refund(bytes memory request) external {\n bytes32 transactionId = keccak256(request);\n\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n\n if (bridgeTxDetails[transactionId].status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n\n if (hasRole(REFUNDER_ROLE, msg.sender)) {\n // Refunder can refund if deadline has passed\n if (block.timestamp \u003c= transaction.deadline) revert DeadlineNotExceeded();\n } else {\n // Permissionless refund is allowed after REFUND_DELAY\n if (block.timestamp \u003c= transaction.deadline + REFUND_DELAY) revert DeadlineNotExceeded();\n }\n\n // if all checks passed, set to REFUNDED status\n bridgeTxDetails[transactionId].status = BridgeStatus.REFUNDED;\n\n // transfer origin collateral back to original sender\n address to = transaction.originSender;\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount + transaction.originFeeAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (bridgeTxDetails[transactionId].proofRelayer != relayer) revert SenderIncorrect();\n return _timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n /// @dev This method is added to achieve backwards compatibility with decoding requests into V1 structs:\n /// - `callValue` is partially reported as a zero/non-zero flag\n /// - `callParams` is ignored\n /// In order to process all kinds of requests use getBridgeTransactionV2 instead.\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory) {\n // Try decoding into V2 struct first. This will revert if V1 struct is passed\n try this.getBridgeTransactionV2(request) returns (BridgeTransactionV2 memory txV2) {\n // Note: we entirely ignore the callParams field, as it was not present in V1\n return BridgeTransaction({\n originChainId: txV2.originChainId,\n destChainId: txV2.destChainId,\n originSender: txV2.originSender,\n destRecipient: txV2.destRecipient,\n originToken: txV2.originToken,\n destToken: txV2.destToken,\n originAmount: txV2.originAmount,\n destAmount: txV2.destAmount,\n originFeeAmount: txV2.originFeeAmount,\n sendChainGas: txV2.callValue != 0,\n deadline: txV2.deadline,\n nonce: txV2.nonce\n });\n } catch {\n // Fallback to V1 struct\n return abi.decode(request, (BridgeTransaction));\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) public payable {\n int256 exclusivityEndTime = int256(block.timestamp) + paramsV2.quoteExclusivitySeconds;\n _validateBridgeParams(params, paramsV2, exclusivityEndTime);\n\n // transfer tokens to bridge contract\n /// @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _takeBridgedUserAsset(params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n\n // set status to requested\n bytes memory request = abi.encode(\n BridgeTransactionV2({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n callValue: paramsV2.callValue,\n deadline: params.deadline,\n nonce: senderNonces[params.sender]++, // increment nonce on every bridge\n exclusivityRelayer: paramsV2.quoteRelayer,\n // We checked exclusivityEndTime to be in range (0 .. params.deadline] above, so can safely cast\n exclusivityEndTime: uint256(exclusivityEndTime),\n callParams: paramsV2.callParams\n })\n );\n bytes32 transactionId = keccak256(request);\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n\n emit BridgeRequested({\n transactionId: transactionId,\n sender: params.sender,\n request: request,\n destChainId: params.dstChainId,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n sendChainGas: paramsV2.callValue != 0\n });\n emit BridgeQuoteDetails(transactionId, paramsV2.quoteId);\n }\n\n /// @inheritdoc IFastBridgeV2\n function relay(bytes memory request, address relayer) public payable {\n bytes32 transactionId = keccak256(request);\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n _validateRelayParams(transaction, transactionId, relayer);\n // mark bridge transaction as relayed\n bridgeRelayDetails[transactionId] =\n BridgeRelay({blockNumber: uint48(block.number), blockTimestamp: uint48(block.timestamp), relayer: relayer});\n\n // transfer tokens to recipient on destination chain and do an arbitrary call if requested\n address to = transaction.destRecipient;\n address token = transaction.destToken;\n uint256 amount = transaction.destAmount;\n uint256 callValue = transaction.callValue;\n\n // Emit the event before any external calls\n emit BridgeRelayed({\n transactionId: transactionId,\n relayer: relayer,\n to: to,\n originChainId: transaction.originChainId,\n originToken: transaction.originToken,\n destToken: token,\n originAmount: transaction.originAmount,\n destAmount: amount,\n chainGasAmount: callValue\n });\n\n // All state changes have been done at this point, can proceed to the external calls.\n // This follows the checks-effects-interactions pattern to mitigate potential reentrancy attacks.\n if (token == UniversalTokenLib.ETH_ADDRESS) {\n // For ETH non-zero callValue is not allowed\n if (callValue != 0) revert NativeTokenCallValueNotSupported();\n // Check that the correct msg.value was sent\n if (msg.value != amount) revert MsgValueIncorrect();\n } else {\n // For ERC20s, we check that the correct msg.value was sent\n if (msg.value != callValue) revert MsgValueIncorrect();\n // We need to transfer the tokens from the Relayer to the recipient first before performing an\n // optional post-transfer arbitrary call.\n IERC20(token).safeTransferFrom(msg.sender, to, amount);\n }\n\n if (transaction.callParams.length != 0) {\n // Arbitrary call requested, perform it while supplying full msg.value to the recipient\n // Note: if token has a fee on transfers, the recipient will have received less than `amount`.\n // This is a very niche edge case and should be handled by the recipient contract.\n _checkedCallRecipient({recipient: to, token: token, amount: amount, callParams: transaction.callParams});\n } else if (msg.value != 0) {\n // No arbitrary call requested, but msg.value was sent. This is either a relay with ETH,\n // or a non-zero callValue request with an ERC20. In both cases, transfer the ETH to the recipient.\n Address.sendValue(payable(to), msg.value);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) public onlyRole(RELAYER_ROLE) {\n // update bridge tx status given proof provided\n if (bridgeTxDetails[transactionId].status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n bridgeTxDetails[transactionId].status = BridgeStatus.RELAYER_PROVED;\n bridgeTxDetails[transactionId].proofBlockTimestamp = uint40(block.timestamp);\n bridgeTxDetails[transactionId].proofBlockNumber = uint48(block.number);\n bridgeTxDetails[transactionId].proofRelayer = relayer;\n\n emit BridgeProofProvided(transactionId, relayer, destTxHash);\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes memory request, address to) public {\n bytes32 transactionId = keccak256(request);\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n\n // update bridge tx status if able to claim origin collateral\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n\n // if \"to\" is zero addr, permissionlessly send funds to proven relayer\n if (to == address(0)) {\n to = bridgeTxDetails[transactionId].proofRelayer;\n } else if (bridgeTxDetails[transactionId].proofRelayer != msg.sender) {\n revert SenderIncorrect();\n }\n\n if (_timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003c= DISPUTE_PERIOD) {\n revert DisputePeriodNotPassed();\n }\n\n bridgeTxDetails[transactionId].status = BridgeStatus.RELAYER_CLAIMED;\n\n // update protocol fees if origin fee amount exists\n if (transaction.originFeeAmount \u003e 0) protocolFees[transaction.originToken] += transaction.originFeeAmount;\n\n // transfer origin collateral less fee to specified address\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositClaimed(transactionId, bridgeTxDetails[transactionId].proofRelayer, to, token, amount);\n }\n\n function bridgeStatuses(bytes32 transactionId) public view returns (BridgeStatus status) {\n return bridgeTxDetails[transactionId].status;\n }\n\n function bridgeProofs(bytes32 transactionId) public view returns (uint96 timestamp, address relayer) {\n timestamp = bridgeTxDetails[transactionId].proofBlockTimestamp;\n relayer = bridgeTxDetails[transactionId].proofRelayer;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeRelays(bytes32 transactionId) public view returns (bool) {\n // has this transactionId been relayed?\n return bridgeRelayDetails[transactionId].relayer != address(0);\n }\n\n /// @inheritdoc IFastBridgeV2\n function getBridgeTransactionV2(bytes memory request) public pure returns (BridgeTransactionV2 memory) {\n return abi.decode(request, (BridgeTransactionV2));\n }\n\n /// @notice Takes the bridged asset from the user into FastBridgeV2 custody. It will be later\n /// claimed by the relayer who completed the relay on destination chain, or refunded back to the user,\n /// should no one complete the relay.\n function _takeBridgedUserAsset(address token, uint256 amount) internal returns (uint256 amountTaken) {\n if (token == UniversalTokenLib.ETH_ADDRESS) {\n // For ETH we just need to check that the supplied msg.value is correct.\n // Supplied `msg.value` is already in FastBridgeV2 custody.\n if (amount != msg.value) revert MsgValueIncorrect();\n amountTaken = msg.value;\n } else {\n // For ERC20s, token is explicitly transferred from the user to FastBridgeV2.\n // We don't allow non-zero `msg.value` to avoid extra funds from being stuck in FastBridgeV2.\n token.assertIsContract();\n if (msg.value != 0) revert MsgValueIncorrect();\n amountTaken = IERC20(token).balanceOf(address(this));\n IERC20(token).safeTransferFrom(msg.sender, address(this), amount);\n // Use the balance difference as the amount taken in case of fee on transfer tokens.\n amountTaken = IERC20(token).balanceOf(address(this)) - amountTaken;\n }\n }\n\n /// @notice Calls the Recipient's hook function with the specified callParams and performs\n /// all the necessary checks for the returned value.\n function _checkedCallRecipient(\n address recipient,\n address token,\n uint256 amount,\n bytes memory callParams\n )\n internal\n {\n bytes memory hookData =\n abi.encodeCall(IFastBridgeRecipient.fastBridgeTransferReceived, (token, amount, callParams));\n // This will bubble any revert messages from the hook function\n bytes memory returnData = Address.functionCallWithValue({target: recipient, data: hookData, value: msg.value});\n // Explicit revert if no return data at all\n if (returnData.length == 0) revert RecipientNoReturnValue();\n // Check that exactly a single return value was returned\n if (returnData.length != 32) revert RecipientIncorrectReturnValue();\n // Return value should be abi-encoded hook function selector\n if (bytes32(returnData) != bytes32(IFastBridgeRecipient.fastBridgeTransferReceived.selector)) {\n revert RecipientIncorrectReturnValue();\n }\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint40(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint40).max but\n /// proof.timestamp \u003c type(uint40).max via unchecked statement\n /// @param proofBlockTimestamp The bridge proof block timestamp\n /// @return delta Time delta since proof submitted\n function _timeSince(uint40 proofBlockTimestamp) internal view returns (uint256 delta) {\n unchecked {\n delta = uint40(block.timestamp) - proofBlockTimestamp;\n }\n }\n\n /// @notice Performs all the necessary checks for a bridge to happen.\n /// @dev There's no good way to refactor this function to reduce cyclomatic complexity due to\n /// the number of checks that need to be performed, so we skip the code-complexity rule here.\n // solhint-disable-next-line code-complexity\n function _validateBridgeParams(\n BridgeParams memory params,\n BridgeParamsV2 memory paramsV2,\n int256 exclusivityEndTime\n )\n internal\n view\n {\n // Check V1 (legacy) params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.sender == address(0) || params.to == address(0)) revert ZeroAddress();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n // Check V2 params\n if (paramsV2.callParams.length \u003e MAX_CALL_PARAMS_LENGTH) revert CallParamsLengthAboveMax();\n if (paramsV2.callValue != 0 \u0026\u0026 params.destToken == UniversalTokenLib.ETH_ADDRESS) {\n revert NativeTokenCallValueNotSupported();\n }\n // exclusivityEndTime must be in range (0 .. params.deadline]\n if (exclusivityEndTime \u003c= 0 || exclusivityEndTime \u003e int256(params.deadline)) {\n revert ExclusivityParamsIncorrect();\n }\n }\n\n /// @notice Performs all the necessary checks for a relay to happen.\n function _validateRelayParams(\n BridgeTransactionV2 memory transaction,\n bytes32 transactionId,\n address relayer\n )\n internal\n view\n {\n if (relayer == address(0)) revert ZeroAddress();\n // Check if the transaction has already been relayed\n if (bridgeRelays(transactionId)) revert TransactionRelayed();\n if (transaction.destChainId != block.chainid) revert ChainIncorrect();\n // Check the deadline for relay to happen\n if (block.timestamp \u003e transaction.deadline) revert DeadlineExceeded();\n // Check the exclusivity period, if it is still ongoing\n // forgefmt: disable-next-item\n if (\n transaction.exclusivityRelayer != address(0) \u0026\u0026\n transaction.exclusivityRelayer != relayer \u0026\u0026\n block.timestamp \u003c= transaction.exclusivityEndTime\n ) {\n revert ExclusivityPeriodNotPassed();\n }\n }\n}\n","language":"Solidity","languageVersion":"0.8.24","compilerVersion":"0.8.24","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"","srcMapRuntime":"","abiDefinition":[{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"relayer","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"BridgeDepositClaimed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"BridgeDepositRefunded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"relayer","type":"address"}],"name":"BridgeProofDisputed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"relayer","type":"address"},{"indexed":false,"internalType":"bytes32","name":"transactionHash","type":"bytes32"}],"name":"BridgeProofProvided","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"relayer","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint32","name":"originChainId","type":"uint32"},{"indexed":false,"internalType":"address","name":"originToken","type":"address"},{"indexed":false,"internalType":"address","name":"destToken","type":"address"},{"indexed":false,"internalType":"uint256","name":"originAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"destAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"chainGasAmount","type":"uint256"}],"name":"BridgeRelayed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"bytes","name":"request","type":"bytes"},{"indexed":false,"internalType":"uint32","name":"destChainId","type":"uint32"},{"indexed":false,"internalType":"address","name":"originToken","type":"address"},{"indexed":false,"internalType":"address","name":"destToken","type":"address"},{"indexed":false,"internalType":"uint256","name":"originAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"destAmount","type":"uint256"},{"indexed":false,"internalType":"bool","name":"sendChainGas","type":"bool"}],"name":"BridgeRequested","type":"event"},{"inputs":[{"components":[{"internalType":"uint32","name":"dstChainId","type":"uint32"},{"internalType":"address","name":"sender","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"address","name":"originToken","type":"address"},{"internalType":"address","name":"destToken","type":"address"},{"internalType":"uint256","name":"originAmount","type":"uint256"},{"internalType":"uint256","name":"destAmount","type":"uint256"},{"internalType":"bool","name":"sendChainGas","type":"bool"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"internalType":"struct IFastBridge.BridgeParams","name":"params","type":"tuple"}],"name":"bridge","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"internalType":"address","name":"relayer","type":"address"}],"name":"canClaim","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"},{"internalType":"address","name":"to","type":"address"}],"name":"claim","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"transactionId","type":"bytes32"}],"name":"dispute","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"}],"name":"getBridgeTransaction","outputs":[{"components":[{"internalType":"uint32","name":"originChainId","type":"uint32"},{"internalType":"uint32","name":"destChainId","type":"uint32"},{"internalType":"address","name":"originSender","type":"address"},{"internalType":"address","name":"destRecipient","type":"address"},{"internalType":"address","name":"originToken","type":"address"},{"internalType":"address","name":"destToken","type":"address"},{"internalType":"uint256","name":"originAmount","type":"uint256"},{"internalType":"uint256","name":"destAmount","type":"uint256"},{"internalType":"uint256","name":"originFeeAmount","type":"uint256"},{"internalType":"bool","name":"sendChainGas","type":"bool"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint256","name":"nonce","type":"uint256"}],"internalType":"struct IFastBridge.BridgeTransaction","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"},{"internalType":"bytes32","name":"destTxHash","type":"bytes32"}],"name":"prove","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"}],"name":"refund","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"}],"name":"relay","outputs":[],"stateMutability":"payable","type":"function"}],"userDoc":{"kind":"user","methods":{"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256))":{"notice":"Initiates bridge on origin chain to be relayed by off-chain relayer"},"canClaim(bytes32,address)":{"notice":"Checks if the dispute period has passed so bridge deposit can be claimed"},"claim(bytes,address)":{"notice":"Completes bridge transaction on origin chain by claiming originally deposited capital"},"dispute(bytes32)":{"notice":"Disputes an outstanding proof in case relayer provided dest chain tx is invalid"},"getBridgeTransaction(bytes)":{"notice":"Decodes bridge request into a bridge transaction"},"prove(bytes,bytes32)":{"notice":"Provides proof on origin side that relayer provided funds on destination side of bridge transaction"},"refund(bytes)":{"notice":"Refunds an outstanding bridge transaction in case optimistic bridging failed"},"relay(bytes)":{"notice":"Relays destination side of bridge transaction by off-chain relayer"}},"version":1},"developerDoc":{"kind":"dev","methods":{"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256))":{"params":{"params":"The parameters required to bridge"}},"canClaim(bytes32,address)":{"params":{"relayer":"The address of the relayer attempting to claim","transactionId":"The transaction id associated with the encoded bridge transaction to check"}},"claim(bytes,address)":{"params":{"request":"The encoded bridge transaction to claim on origin chain","to":"The recipient address of the funds"}},"dispute(bytes32)":{"params":{"transactionId":"The transaction id associated with the encoded bridge transaction to dispute"}},"getBridgeTransaction(bytes)":{"params":{"request":"The bridge request to decode"}},"prove(bytes,bytes32)":{"params":{"destTxHash":"The destination tx hash proving bridge transaction was relayed","request":"The encoded bridge transaction to prove on origin chain"}},"refund(bytes)":{"params":{"request":"The encoded bridge transaction to refund"}},"relay(bytes)":{"params":{"request":"The encoded bridge transaction to relay on destination chain"}}},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"BridgeDepositClaimed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"BridgeDepositRefunded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"name\":\"BridgeProofDisputed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"transactionHash\",\"type\":\"bytes32\"}],\"name\":\"BridgeProofProvided\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"originChainId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"chainGasAmount\",\"type\":\"uint256\"}],\"name\":\"BridgeRelayed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"destChainId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"sendChainGas\",\"type\":\"bool\"}],\"name\":\"BridgeRequested\",\"type\":\"event\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"dstChainId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"sendChainGas\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"}],\"internalType\":\"struct IFastBridge.BridgeParams\",\"name\":\"params\",\"type\":\"tuple\"}],\"name\":\"bridge\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"name\":\"canClaim\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"claim\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"}],\"name\":\"dispute\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"getBridgeTransaction\",\"outputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"originChainId\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"destChainId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"originSender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destRecipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"originFeeAmount\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"sendChainGas\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"}],\"internalType\":\"struct IFastBridge.BridgeTransaction\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"},{\"internalType\":\"bytes32\",\"name\":\"destTxHash\",\"type\":\"bytes32\"}],\"name\":\"prove\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"refund\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"relay\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{\"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256))\":{\"params\":{\"params\":\"The parameters required to bridge\"}},\"canClaim(bytes32,address)\":{\"params\":{\"relayer\":\"The address of the relayer attempting to claim\",\"transactionId\":\"The transaction id associated with the encoded bridge transaction to check\"}},\"claim(bytes,address)\":{\"params\":{\"request\":\"The encoded bridge transaction to claim on origin chain\",\"to\":\"The recipient address of the funds\"}},\"dispute(bytes32)\":{\"params\":{\"transactionId\":\"The transaction id associated with the encoded bridge transaction to dispute\"}},\"getBridgeTransaction(bytes)\":{\"params\":{\"request\":\"The bridge request to decode\"}},\"prove(bytes,bytes32)\":{\"params\":{\"destTxHash\":\"The destination tx hash proving bridge transaction was relayed\",\"request\":\"The encoded bridge transaction to prove on origin chain\"}},\"refund(bytes)\":{\"params\":{\"request\":\"The encoded bridge transaction to refund\"}},\"relay(bytes)\":{\"params\":{\"request\":\"The encoded bridge transaction to relay on destination chain\"}}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256))\":{\"notice\":\"Initiates bridge on origin chain to be relayed by off-chain relayer\"},\"canClaim(bytes32,address)\":{\"notice\":\"Checks if the dispute period has passed so bridge deposit can be claimed\"},\"claim(bytes,address)\":{\"notice\":\"Completes bridge transaction on origin chain by claiming originally deposited capital\"},\"dispute(bytes32)\":{\"notice\":\"Disputes an outstanding proof in case relayer provided dest chain tx is invalid\"},\"getBridgeTransaction(bytes)\":{\"notice\":\"Decodes bridge request into a bridge transaction\"},\"prove(bytes,bytes32)\":{\"notice\":\"Provides proof on origin side that relayer provided funds on destination side of bridge transaction\"},\"refund(bytes)\":{\"notice\":\"Refunds an outstanding bridge transaction in case optimistic bridging failed\"},\"relay(bytes)\":{\"notice\":\"Relays destination side of bridge transaction by off-chain relayer\"}},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeV2.sol\":\"IFastBridge\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeV2.sol\":{\"keccak256\":\"0xfd916c030b1ffca5a136817827b8018c8ba42ca089905747f3de6148b73eb35e\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://18e6438c4096deb8ae453fb3365ba2b07d52944e93c08288fc5d012b71bf6bb3\",\"dweb:/ipfs/QmfEMqpT1zz6RRm7UuHLRowe1tds2cTGLrVonfm9XSCACj\"]}},\"version\":1}"},"hashes":{"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256))":"45851694","canClaim(bytes32,address)":"aa9641ab","claim(bytes,address)":"41fcb612","dispute(bytes32)":"add98c70","getBridgeTransaction(bytes)":"ac11fb1a","prove(bytes,bytes32)":"886d36ff","refund(bytes)":"5eb7d946","relay(bytes)":"8f0d6f17"}},"solidity/FastBridgeV2.sol:IFastBridgeRecipient":{"code":"0x","runtime-code":"0x","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.24 ^0.8.0 ^0.8.20;\n\n// contracts/interfaces/IAdmin.sol\n\ninterface IAdmin {\n // ============ Events ============\n\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n event ChainGasAmountUpdated(uint256 oldChainGasAmount, uint256 newChainGasAmount);\n\n // ============ Methods ============\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n\n function setChainGasAmount(uint256 newChainGasAmount) external;\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IFastBridgeRecipient.sol\n\ninterface IFastBridgeRecipient {\n function fastBridgeTransferReceived(\n address token,\n uint256 amount,\n bytes memory callParams\n )\n external\n payable\n returns (bytes4);\n}\n\n// contracts/interfaces/IFastBridgeV2Errors.sol\n\ninterface IFastBridgeV2Errors {\n error AmountIncorrect();\n error CallParamsLengthAboveMax();\n error ChainIncorrect();\n error ExclusivityParamsIncorrect();\n error MsgValueIncorrect();\n error NativeTokenCallValueNotSupported();\n error SenderIncorrect();\n error StatusIncorrect();\n error ZeroAddress();\n\n error RecipientIncorrectReturnValue();\n error RecipientNoReturnValue();\n\n error DeadlineExceeded();\n error DeadlineNotExceeded();\n error DeadlineTooShort();\n error DisputePeriodNotPassed();\n error DisputePeriodPassed();\n error ExclusivityPeriodNotPassed();\n\n error TransactionRelayed();\n}\n\n// contracts/libs/Errors.sol\n\nerror DeadlineExceeded();\nerror DeadlineNotExceeded();\nerror DeadlineTooShort();\nerror InsufficientOutputAmount();\n\nerror MsgValueIncorrect();\nerror PoolNotFound();\nerror TokenAddressMismatch();\nerror TokenNotContract();\nerror TokenNotETH();\nerror TokensIdentical();\n\nerror ChainIncorrect();\nerror AmountIncorrect();\nerror ZeroAddress();\n\nerror DisputePeriodNotPassed();\nerror DisputePeriodPassed();\nerror SenderIncorrect();\nerror StatusIncorrect();\nerror TransactionIdIncorrect();\nerror TransactionRelayed();\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// contracts/interfaces/IFastBridgeV2.sol\n\ninterface IFastBridgeV2 is IFastBridge {\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n struct BridgeTxDetails {\n BridgeStatus status;\n uint40 proofBlockTimestamp;\n uint48 proofBlockNumber;\n address proofRelayer;\n }\n\n struct BridgeRelay {\n uint48 blockNumber;\n uint48 blockTimestamp;\n address relayer;\n }\n\n /// @notice New params introduced in the FastBridgeV2.\n /// We are passing fields from the older BridgeParams struct outside of this struct\n /// for backwards compatibility.\n /// Note: quoteRelayer and quoteExclusivitySeconds are either both zero (indicating no exclusivity)\n /// or both non-zero (indicating exclusivity for the given period).\n /// Note: callValue \u003e 0 can NOT be used with destToken = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE (ETH_ADDRESS)\n /// @param quoteRelayer Relayer that provided the quote for the transaction\n /// @param quoteExclusivitySeconds Period of time the quote relayer is guaranteed exclusivity after user's deposit\n /// @param quoteId Unique quote identifier used for tracking the quote\n /// @param callValue ETH value to send to the recipient (if any)\n /// @param callParams Parameters for the arbitrary call to the destination recipient (if any)\n struct BridgeParamsV2 {\n address quoteRelayer;\n int256 quoteExclusivitySeconds;\n bytes quoteId;\n uint256 callValue;\n bytes callParams;\n }\n\n /// @notice Updated bridge transaction struct to include parameters introduced in FastBridgeV2.\n /// Note: only `exclusivityRelayer` can fill such a transaction until `exclusivityEndTime`.\n /// TODO: consider changing the encoding scheme to prevent spending extra gas on decoding.\n struct BridgeTransactionV2 {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n uint256 callValue; // ETH value to send to the recipient (if any) - replaces V1's sendChainGas flag\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n address exclusivityRelayer;\n uint256 exclusivityEndTime;\n bytes callParams;\n }\n\n event BridgeQuoteDetails(bytes32 indexed transactionId, bytes quoteId);\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability\n /// to provide temporary exclusivity fill rights for the quote relayer.\n /// @param params The parameters required to bridge\n /// @param paramsV2 The parameters for exclusivity fill rights (optional, can be left empty)\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function relay(bytes memory request, address relayer) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param transactionId The transaction id associated with the encoded bridge transaction to prove\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital.\n /// @notice Can only send funds to the relayer address on the proof.\n /// @param request The encoded bridge transaction to claim on origin chain\n function claim(bytes memory request) external;\n /// @notice Checks if a transaction has been relayed\n /// @param transactionId The ID of the transaction to check\n /// @return True if the transaction has been relayed, false otherwise\n function bridgeRelays(bytes32 transactionId) external view returns (bool);\n\n /// @notice Returns the status of a bridge transaction\n /// @param transactionId The ID of the bridge transaction\n /// @return BridgeStatus Status of the bridge transaction\n function bridgeStatuses(bytes32 transactionId) external view returns (BridgeStatus);\n\n /// @notice Returns the timestamp and relayer of a bridge proof\n /// @param transactionId The ID of the bridge transaction\n /// @return timestamp The timestamp of the bridge proof\n /// @return relayer The relayer address of the bridge proof\n function bridgeProofs(bytes32 transactionId) external view returns (uint96 timestamp, address relayer);\n\n /// @notice Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\n /// @param request The bridge request to decode\n function getBridgeTransactionV2(bytes memory request) external view returns (BridgeTransactionV2 memory);\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// contracts/libs/UniversalToken.sol\n\nlibrary UniversalTokenLib {\n using SafeERC20 for IERC20;\n\n address internal constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Transfers tokens to the given account. Reverts if transfer is not successful.\n /// @dev This might trigger fallback, if ETH is transferred to the contract.\n /// Make sure this can not lead to reentrancy attacks.\n function universalTransfer(address token, address to, uint256 value) internal {\n // Don't do anything, if need to send tokens to this address\n if (to == address(this)) return;\n // Don't do anything, if trying to send zero value\n if (value == 0) return;\n if (token == ETH_ADDRESS) {\n /// @dev Note: this can potentially lead to executing code in `to`.\n // solhint-disable-next-line avoid-low-level-calls\n (bool success,) = to.call{value: value}(\"\");\n require(success, \"ETH transfer failed\");\n } else {\n IERC20(token).safeTransfer(to, value);\n }\n }\n\n /// @notice Issues an infinite allowance to the spender, if the current allowance is insufficient\n /// to spend the given amount.\n function universalApproveInfinity(address token, address spender, uint256 amountToSpend) internal {\n // ETH Chad doesn't require your approval\n if (token == ETH_ADDRESS) return;\n // No-op if allowance is already sufficient\n uint256 allowance = IERC20(token).allowance(address(this), spender);\n if (allowance \u003e= amountToSpend) return;\n // Otherwise, reset approval to 0 and set to max allowance\n if (allowance \u003e 0) IERC20(token).safeDecreaseAllowance(spender, allowance);\n IERC20(token).safeIncreaseAllowance(spender, type(uint256).max);\n }\n\n /// @notice Returns the balance of the given token (or native ETH) for the given account.\n function universalBalanceOf(address token, address account) internal view returns (uint256) {\n if (token == ETH_ADDRESS) {\n return account.balance;\n } else {\n return IERC20(token).balanceOf(account);\n }\n }\n\n /// @dev Checks that token is a contract and not ETH_ADDRESS.\n function assertIsContract(address token) internal view {\n // Check that ETH_ADDRESS was not used (in case this is a predeploy on any of the chains)\n if (token == UniversalTokenLib.ETH_ADDRESS) revert TokenNotContract();\n // Check that token is not an EOA\n if (token.code.length == 0) revert TokenNotContract();\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/Admin.sol\n\ncontract Admin is IAdmin, AccessControlEnumerable {\n using UniversalTokenLib for address;\n\n bytes32 public constant RELAYER_ROLE = keccak256(\"RELAYER_ROLE\");\n bytes32 public constant REFUNDER_ROLE = keccak256(\"REFUNDER_ROLE\");\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n uint256 public constant FEE_BPS = 1e6;\n uint256 public constant FEE_RATE_MAX = 0.01e6; // max 1% on origin amount\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Chain gas amount to forward as rebate if requested\n uint256 public chainGasAmount;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n }\n\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n require(newFeeRate \u003c= FEE_RATE_MAX, \"newFeeRate \u003e max\");\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n token.universalTransfer(recipient, feeAmount);\n emit FeesSwept(token, recipient, feeAmount);\n }\n\n function setChainGasAmount(uint256 newChainGasAmount) external onlyRole(GOVERNOR_ROLE) {\n uint256 oldChainGasAmount = chainGasAmount;\n chainGasAmount = newChainGasAmount;\n emit ChainGasAmountUpdated(oldChainGasAmount, newChainGasAmount);\n }\n}\n\n// contracts/FastBridgeV2.sol\n\n/// @notice FastBridgeV2 is a contract for bridging tokens across chains.\ncontract FastBridgeV2 is Admin, IFastBridgeV2, IFastBridgeV2Errors {\n using SafeERC20 for IERC20;\n using UniversalTokenLib for address;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Delay for a transaction after which it could be permisionlessly refunded\n uint256 public constant REFUND_DELAY = 7 days;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n /// @notice Maximum length of accepted callParams\n uint256 public constant MAX_CALL_PARAMS_LENGTH = 2 ** 16 - 1;\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeTxDetails) public bridgeTxDetails;\n /// @notice Relay details on destination chain\n mapping(bytes32 =\u003e BridgeRelay) public bridgeRelayDetails;\n /// @notice Unique bridge nonces tracked per originSender\n mapping(address =\u003e uint256) public senderNonces;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Replaced by senderNonces\n uint256 public immutable nonce = 0;\n /// @notice the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n bridge({\n params: params,\n paramsV2: BridgeParamsV2({\n quoteRelayer: address(0),\n quoteExclusivitySeconds: 0,\n quoteId: bytes(\"\"),\n callValue: 0,\n callParams: bytes(\"\")\n })\n });\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes memory request) external payable {\n relay({request: request, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes memory request, bytes32 destTxHash) external {\n prove({transactionId: keccak256(request), destTxHash: destTxHash, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridgeV2\n function claim(bytes memory request) external {\n claim({request: request, to: address(0)});\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003e DISPUTE_PERIOD) {\n revert DisputePeriodPassed();\n }\n\n // @dev relayer gets slashed effectively if dest relay has gone thru\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n bridgeTxDetails[transactionId].proofRelayer = address(0);\n bridgeTxDetails[transactionId].proofBlockTimestamp = 0;\n bridgeTxDetails[transactionId].proofBlockNumber = 0;\n\n emit BridgeProofDisputed(transactionId, msg.sender);\n }\n\n /// @inheritdoc IFastBridge\n function refund(bytes memory request) external {\n bytes32 transactionId = keccak256(request);\n\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n\n if (bridgeTxDetails[transactionId].status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n\n if (hasRole(REFUNDER_ROLE, msg.sender)) {\n // Refunder can refund if deadline has passed\n if (block.timestamp \u003c= transaction.deadline) revert DeadlineNotExceeded();\n } else {\n // Permissionless refund is allowed after REFUND_DELAY\n if (block.timestamp \u003c= transaction.deadline + REFUND_DELAY) revert DeadlineNotExceeded();\n }\n\n // if all checks passed, set to REFUNDED status\n bridgeTxDetails[transactionId].status = BridgeStatus.REFUNDED;\n\n // transfer origin collateral back to original sender\n address to = transaction.originSender;\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount + transaction.originFeeAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (bridgeTxDetails[transactionId].proofRelayer != relayer) revert SenderIncorrect();\n return _timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n /// @dev This method is added to achieve backwards compatibility with decoding requests into V1 structs:\n /// - `callValue` is partially reported as a zero/non-zero flag\n /// - `callParams` is ignored\n /// In order to process all kinds of requests use getBridgeTransactionV2 instead.\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory) {\n // Try decoding into V2 struct first. This will revert if V1 struct is passed\n try this.getBridgeTransactionV2(request) returns (BridgeTransactionV2 memory txV2) {\n // Note: we entirely ignore the callParams field, as it was not present in V1\n return BridgeTransaction({\n originChainId: txV2.originChainId,\n destChainId: txV2.destChainId,\n originSender: txV2.originSender,\n destRecipient: txV2.destRecipient,\n originToken: txV2.originToken,\n destToken: txV2.destToken,\n originAmount: txV2.originAmount,\n destAmount: txV2.destAmount,\n originFeeAmount: txV2.originFeeAmount,\n sendChainGas: txV2.callValue != 0,\n deadline: txV2.deadline,\n nonce: txV2.nonce\n });\n } catch {\n // Fallback to V1 struct\n return abi.decode(request, (BridgeTransaction));\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) public payable {\n int256 exclusivityEndTime = int256(block.timestamp) + paramsV2.quoteExclusivitySeconds;\n _validateBridgeParams(params, paramsV2, exclusivityEndTime);\n\n // transfer tokens to bridge contract\n /// @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _takeBridgedUserAsset(params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n\n // set status to requested\n bytes memory request = abi.encode(\n BridgeTransactionV2({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n callValue: paramsV2.callValue,\n deadline: params.deadline,\n nonce: senderNonces[params.sender]++, // increment nonce on every bridge\n exclusivityRelayer: paramsV2.quoteRelayer,\n // We checked exclusivityEndTime to be in range (0 .. params.deadline] above, so can safely cast\n exclusivityEndTime: uint256(exclusivityEndTime),\n callParams: paramsV2.callParams\n })\n );\n bytes32 transactionId = keccak256(request);\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n\n emit BridgeRequested({\n transactionId: transactionId,\n sender: params.sender,\n request: request,\n destChainId: params.dstChainId,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n sendChainGas: paramsV2.callValue != 0\n });\n emit BridgeQuoteDetails(transactionId, paramsV2.quoteId);\n }\n\n /// @inheritdoc IFastBridgeV2\n function relay(bytes memory request, address relayer) public payable {\n bytes32 transactionId = keccak256(request);\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n _validateRelayParams(transaction, transactionId, relayer);\n // mark bridge transaction as relayed\n bridgeRelayDetails[transactionId] =\n BridgeRelay({blockNumber: uint48(block.number), blockTimestamp: uint48(block.timestamp), relayer: relayer});\n\n // transfer tokens to recipient on destination chain and do an arbitrary call if requested\n address to = transaction.destRecipient;\n address token = transaction.destToken;\n uint256 amount = transaction.destAmount;\n uint256 callValue = transaction.callValue;\n\n // Emit the event before any external calls\n emit BridgeRelayed({\n transactionId: transactionId,\n relayer: relayer,\n to: to,\n originChainId: transaction.originChainId,\n originToken: transaction.originToken,\n destToken: token,\n originAmount: transaction.originAmount,\n destAmount: amount,\n chainGasAmount: callValue\n });\n\n // All state changes have been done at this point, can proceed to the external calls.\n // This follows the checks-effects-interactions pattern to mitigate potential reentrancy attacks.\n if (token == UniversalTokenLib.ETH_ADDRESS) {\n // For ETH non-zero callValue is not allowed\n if (callValue != 0) revert NativeTokenCallValueNotSupported();\n // Check that the correct msg.value was sent\n if (msg.value != amount) revert MsgValueIncorrect();\n } else {\n // For ERC20s, we check that the correct msg.value was sent\n if (msg.value != callValue) revert MsgValueIncorrect();\n // We need to transfer the tokens from the Relayer to the recipient first before performing an\n // optional post-transfer arbitrary call.\n IERC20(token).safeTransferFrom(msg.sender, to, amount);\n }\n\n if (transaction.callParams.length != 0) {\n // Arbitrary call requested, perform it while supplying full msg.value to the recipient\n // Note: if token has a fee on transfers, the recipient will have received less than `amount`.\n // This is a very niche edge case and should be handled by the recipient contract.\n _checkedCallRecipient({recipient: to, token: token, amount: amount, callParams: transaction.callParams});\n } else if (msg.value != 0) {\n // No arbitrary call requested, but msg.value was sent. This is either a relay with ETH,\n // or a non-zero callValue request with an ERC20. In both cases, transfer the ETH to the recipient.\n Address.sendValue(payable(to), msg.value);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) public onlyRole(RELAYER_ROLE) {\n // update bridge tx status given proof provided\n if (bridgeTxDetails[transactionId].status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n bridgeTxDetails[transactionId].status = BridgeStatus.RELAYER_PROVED;\n bridgeTxDetails[transactionId].proofBlockTimestamp = uint40(block.timestamp);\n bridgeTxDetails[transactionId].proofBlockNumber = uint48(block.number);\n bridgeTxDetails[transactionId].proofRelayer = relayer;\n\n emit BridgeProofProvided(transactionId, relayer, destTxHash);\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes memory request, address to) public {\n bytes32 transactionId = keccak256(request);\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n\n // update bridge tx status if able to claim origin collateral\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n\n // if \"to\" is zero addr, permissionlessly send funds to proven relayer\n if (to == address(0)) {\n to = bridgeTxDetails[transactionId].proofRelayer;\n } else if (bridgeTxDetails[transactionId].proofRelayer != msg.sender) {\n revert SenderIncorrect();\n }\n\n if (_timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003c= DISPUTE_PERIOD) {\n revert DisputePeriodNotPassed();\n }\n\n bridgeTxDetails[transactionId].status = BridgeStatus.RELAYER_CLAIMED;\n\n // update protocol fees if origin fee amount exists\n if (transaction.originFeeAmount \u003e 0) protocolFees[transaction.originToken] += transaction.originFeeAmount;\n\n // transfer origin collateral less fee to specified address\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositClaimed(transactionId, bridgeTxDetails[transactionId].proofRelayer, to, token, amount);\n }\n\n function bridgeStatuses(bytes32 transactionId) public view returns (BridgeStatus status) {\n return bridgeTxDetails[transactionId].status;\n }\n\n function bridgeProofs(bytes32 transactionId) public view returns (uint96 timestamp, address relayer) {\n timestamp = bridgeTxDetails[transactionId].proofBlockTimestamp;\n relayer = bridgeTxDetails[transactionId].proofRelayer;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeRelays(bytes32 transactionId) public view returns (bool) {\n // has this transactionId been relayed?\n return bridgeRelayDetails[transactionId].relayer != address(0);\n }\n\n /// @inheritdoc IFastBridgeV2\n function getBridgeTransactionV2(bytes memory request) public pure returns (BridgeTransactionV2 memory) {\n return abi.decode(request, (BridgeTransactionV2));\n }\n\n /// @notice Takes the bridged asset from the user into FastBridgeV2 custody. It will be later\n /// claimed by the relayer who completed the relay on destination chain, or refunded back to the user,\n /// should no one complete the relay.\n function _takeBridgedUserAsset(address token, uint256 amount) internal returns (uint256 amountTaken) {\n if (token == UniversalTokenLib.ETH_ADDRESS) {\n // For ETH we just need to check that the supplied msg.value is correct.\n // Supplied `msg.value` is already in FastBridgeV2 custody.\n if (amount != msg.value) revert MsgValueIncorrect();\n amountTaken = msg.value;\n } else {\n // For ERC20s, token is explicitly transferred from the user to FastBridgeV2.\n // We don't allow non-zero `msg.value` to avoid extra funds from being stuck in FastBridgeV2.\n token.assertIsContract();\n if (msg.value != 0) revert MsgValueIncorrect();\n amountTaken = IERC20(token).balanceOf(address(this));\n IERC20(token).safeTransferFrom(msg.sender, address(this), amount);\n // Use the balance difference as the amount taken in case of fee on transfer tokens.\n amountTaken = IERC20(token).balanceOf(address(this)) - amountTaken;\n }\n }\n\n /// @notice Calls the Recipient's hook function with the specified callParams and performs\n /// all the necessary checks for the returned value.\n function _checkedCallRecipient(\n address recipient,\n address token,\n uint256 amount,\n bytes memory callParams\n )\n internal\n {\n bytes memory hookData =\n abi.encodeCall(IFastBridgeRecipient.fastBridgeTransferReceived, (token, amount, callParams));\n // This will bubble any revert messages from the hook function\n bytes memory returnData = Address.functionCallWithValue({target: recipient, data: hookData, value: msg.value});\n // Explicit revert if no return data at all\n if (returnData.length == 0) revert RecipientNoReturnValue();\n // Check that exactly a single return value was returned\n if (returnData.length != 32) revert RecipientIncorrectReturnValue();\n // Return value should be abi-encoded hook function selector\n if (bytes32(returnData) != bytes32(IFastBridgeRecipient.fastBridgeTransferReceived.selector)) {\n revert RecipientIncorrectReturnValue();\n }\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint40(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint40).max but\n /// proof.timestamp \u003c type(uint40).max via unchecked statement\n /// @param proofBlockTimestamp The bridge proof block timestamp\n /// @return delta Time delta since proof submitted\n function _timeSince(uint40 proofBlockTimestamp) internal view returns (uint256 delta) {\n unchecked {\n delta = uint40(block.timestamp) - proofBlockTimestamp;\n }\n }\n\n /// @notice Performs all the necessary checks for a bridge to happen.\n /// @dev There's no good way to refactor this function to reduce cyclomatic complexity due to\n /// the number of checks that need to be performed, so we skip the code-complexity rule here.\n // solhint-disable-next-line code-complexity\n function _validateBridgeParams(\n BridgeParams memory params,\n BridgeParamsV2 memory paramsV2,\n int256 exclusivityEndTime\n )\n internal\n view\n {\n // Check V1 (legacy) params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.sender == address(0) || params.to == address(0)) revert ZeroAddress();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n // Check V2 params\n if (paramsV2.callParams.length \u003e MAX_CALL_PARAMS_LENGTH) revert CallParamsLengthAboveMax();\n if (paramsV2.callValue != 0 \u0026\u0026 params.destToken == UniversalTokenLib.ETH_ADDRESS) {\n revert NativeTokenCallValueNotSupported();\n }\n // exclusivityEndTime must be in range (0 .. params.deadline]\n if (exclusivityEndTime \u003c= 0 || exclusivityEndTime \u003e int256(params.deadline)) {\n revert ExclusivityParamsIncorrect();\n }\n }\n\n /// @notice Performs all the necessary checks for a relay to happen.\n function _validateRelayParams(\n BridgeTransactionV2 memory transaction,\n bytes32 transactionId,\n address relayer\n )\n internal\n view\n {\n if (relayer == address(0)) revert ZeroAddress();\n // Check if the transaction has already been relayed\n if (bridgeRelays(transactionId)) revert TransactionRelayed();\n if (transaction.destChainId != block.chainid) revert ChainIncorrect();\n // Check the deadline for relay to happen\n if (block.timestamp \u003e transaction.deadline) revert DeadlineExceeded();\n // Check the exclusivity period, if it is still ongoing\n // forgefmt: disable-next-item\n if (\n transaction.exclusivityRelayer != address(0) \u0026\u0026\n transaction.exclusivityRelayer != relayer \u0026\u0026\n block.timestamp \u003c= transaction.exclusivityEndTime\n ) {\n revert ExclusivityPeriodNotPassed();\n }\n }\n}\n","language":"Solidity","languageVersion":"0.8.24","compilerVersion":"0.8.24","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"","srcMapRuntime":"","abiDefinition":[{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"bytes","name":"callParams","type":"bytes"}],"name":"fastBridgeTransferReceived","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"payable","type":"function"}],"userDoc":{"kind":"user","methods":{},"version":1},"developerDoc":{"kind":"dev","methods":{},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"callParams\",\"type\":\"bytes\"}],\"name\":\"fastBridgeTransferReceived\",\"outputs\":[{\"internalType\":\"bytes4\",\"name\":\"\",\"type\":\"bytes4\"}],\"stateMutability\":\"payable\",\"type\":\"function\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeV2.sol\":\"IFastBridgeRecipient\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeV2.sol\":{\"keccak256\":\"0xfd916c030b1ffca5a136817827b8018c8ba42ca089905747f3de6148b73eb35e\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://18e6438c4096deb8ae453fb3365ba2b07d52944e93c08288fc5d012b71bf6bb3\",\"dweb:/ipfs/QmfEMqpT1zz6RRm7UuHLRowe1tds2cTGLrVonfm9XSCACj\"]}},\"version\":1}"},"hashes":{"fastBridgeTransferReceived(address,uint256,bytes)":"461e0c21"}},"solidity/FastBridgeV2.sol:IFastBridgeV2":{"code":"0x","runtime-code":"0x","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.24 ^0.8.0 ^0.8.20;\n\n// contracts/interfaces/IAdmin.sol\n\ninterface IAdmin {\n // ============ Events ============\n\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n event ChainGasAmountUpdated(uint256 oldChainGasAmount, uint256 newChainGasAmount);\n\n // ============ Methods ============\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n\n function setChainGasAmount(uint256 newChainGasAmount) external;\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IFastBridgeRecipient.sol\n\ninterface IFastBridgeRecipient {\n function fastBridgeTransferReceived(\n address token,\n uint256 amount,\n bytes memory callParams\n )\n external\n payable\n returns (bytes4);\n}\n\n// contracts/interfaces/IFastBridgeV2Errors.sol\n\ninterface IFastBridgeV2Errors {\n error AmountIncorrect();\n error CallParamsLengthAboveMax();\n error ChainIncorrect();\n error ExclusivityParamsIncorrect();\n error MsgValueIncorrect();\n error NativeTokenCallValueNotSupported();\n error SenderIncorrect();\n error StatusIncorrect();\n error ZeroAddress();\n\n error RecipientIncorrectReturnValue();\n error RecipientNoReturnValue();\n\n error DeadlineExceeded();\n error DeadlineNotExceeded();\n error DeadlineTooShort();\n error DisputePeriodNotPassed();\n error DisputePeriodPassed();\n error ExclusivityPeriodNotPassed();\n\n error TransactionRelayed();\n}\n\n// contracts/libs/Errors.sol\n\nerror DeadlineExceeded();\nerror DeadlineNotExceeded();\nerror DeadlineTooShort();\nerror InsufficientOutputAmount();\n\nerror MsgValueIncorrect();\nerror PoolNotFound();\nerror TokenAddressMismatch();\nerror TokenNotContract();\nerror TokenNotETH();\nerror TokensIdentical();\n\nerror ChainIncorrect();\nerror AmountIncorrect();\nerror ZeroAddress();\n\nerror DisputePeriodNotPassed();\nerror DisputePeriodPassed();\nerror SenderIncorrect();\nerror StatusIncorrect();\nerror TransactionIdIncorrect();\nerror TransactionRelayed();\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// contracts/interfaces/IFastBridgeV2.sol\n\ninterface IFastBridgeV2 is IFastBridge {\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n struct BridgeTxDetails {\n BridgeStatus status;\n uint40 proofBlockTimestamp;\n uint48 proofBlockNumber;\n address proofRelayer;\n }\n\n struct BridgeRelay {\n uint48 blockNumber;\n uint48 blockTimestamp;\n address relayer;\n }\n\n /// @notice New params introduced in the FastBridgeV2.\n /// We are passing fields from the older BridgeParams struct outside of this struct\n /// for backwards compatibility.\n /// Note: quoteRelayer and quoteExclusivitySeconds are either both zero (indicating no exclusivity)\n /// or both non-zero (indicating exclusivity for the given period).\n /// Note: callValue \u003e 0 can NOT be used with destToken = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE (ETH_ADDRESS)\n /// @param quoteRelayer Relayer that provided the quote for the transaction\n /// @param quoteExclusivitySeconds Period of time the quote relayer is guaranteed exclusivity after user's deposit\n /// @param quoteId Unique quote identifier used for tracking the quote\n /// @param callValue ETH value to send to the recipient (if any)\n /// @param callParams Parameters for the arbitrary call to the destination recipient (if any)\n struct BridgeParamsV2 {\n address quoteRelayer;\n int256 quoteExclusivitySeconds;\n bytes quoteId;\n uint256 callValue;\n bytes callParams;\n }\n\n /// @notice Updated bridge transaction struct to include parameters introduced in FastBridgeV2.\n /// Note: only `exclusivityRelayer` can fill such a transaction until `exclusivityEndTime`.\n /// TODO: consider changing the encoding scheme to prevent spending extra gas on decoding.\n struct BridgeTransactionV2 {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n uint256 callValue; // ETH value to send to the recipient (if any) - replaces V1's sendChainGas flag\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n address exclusivityRelayer;\n uint256 exclusivityEndTime;\n bytes callParams;\n }\n\n event BridgeQuoteDetails(bytes32 indexed transactionId, bytes quoteId);\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability\n /// to provide temporary exclusivity fill rights for the quote relayer.\n /// @param params The parameters required to bridge\n /// @param paramsV2 The parameters for exclusivity fill rights (optional, can be left empty)\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function relay(bytes memory request, address relayer) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param transactionId The transaction id associated with the encoded bridge transaction to prove\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital.\n /// @notice Can only send funds to the relayer address on the proof.\n /// @param request The encoded bridge transaction to claim on origin chain\n function claim(bytes memory request) external;\n /// @notice Checks if a transaction has been relayed\n /// @param transactionId The ID of the transaction to check\n /// @return True if the transaction has been relayed, false otherwise\n function bridgeRelays(bytes32 transactionId) external view returns (bool);\n\n /// @notice Returns the status of a bridge transaction\n /// @param transactionId The ID of the bridge transaction\n /// @return BridgeStatus Status of the bridge transaction\n function bridgeStatuses(bytes32 transactionId) external view returns (BridgeStatus);\n\n /// @notice Returns the timestamp and relayer of a bridge proof\n /// @param transactionId The ID of the bridge transaction\n /// @return timestamp The timestamp of the bridge proof\n /// @return relayer The relayer address of the bridge proof\n function bridgeProofs(bytes32 transactionId) external view returns (uint96 timestamp, address relayer);\n\n /// @notice Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\n /// @param request The bridge request to decode\n function getBridgeTransactionV2(bytes memory request) external view returns (BridgeTransactionV2 memory);\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// contracts/libs/UniversalToken.sol\n\nlibrary UniversalTokenLib {\n using SafeERC20 for IERC20;\n\n address internal constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Transfers tokens to the given account. Reverts if transfer is not successful.\n /// @dev This might trigger fallback, if ETH is transferred to the contract.\n /// Make sure this can not lead to reentrancy attacks.\n function universalTransfer(address token, address to, uint256 value) internal {\n // Don't do anything, if need to send tokens to this address\n if (to == address(this)) return;\n // Don't do anything, if trying to send zero value\n if (value == 0) return;\n if (token == ETH_ADDRESS) {\n /// @dev Note: this can potentially lead to executing code in `to`.\n // solhint-disable-next-line avoid-low-level-calls\n (bool success,) = to.call{value: value}(\"\");\n require(success, \"ETH transfer failed\");\n } else {\n IERC20(token).safeTransfer(to, value);\n }\n }\n\n /// @notice Issues an infinite allowance to the spender, if the current allowance is insufficient\n /// to spend the given amount.\n function universalApproveInfinity(address token, address spender, uint256 amountToSpend) internal {\n // ETH Chad doesn't require your approval\n if (token == ETH_ADDRESS) return;\n // No-op if allowance is already sufficient\n uint256 allowance = IERC20(token).allowance(address(this), spender);\n if (allowance \u003e= amountToSpend) return;\n // Otherwise, reset approval to 0 and set to max allowance\n if (allowance \u003e 0) IERC20(token).safeDecreaseAllowance(spender, allowance);\n IERC20(token).safeIncreaseAllowance(spender, type(uint256).max);\n }\n\n /// @notice Returns the balance of the given token (or native ETH) for the given account.\n function universalBalanceOf(address token, address account) internal view returns (uint256) {\n if (token == ETH_ADDRESS) {\n return account.balance;\n } else {\n return IERC20(token).balanceOf(account);\n }\n }\n\n /// @dev Checks that token is a contract and not ETH_ADDRESS.\n function assertIsContract(address token) internal view {\n // Check that ETH_ADDRESS was not used (in case this is a predeploy on any of the chains)\n if (token == UniversalTokenLib.ETH_ADDRESS) revert TokenNotContract();\n // Check that token is not an EOA\n if (token.code.length == 0) revert TokenNotContract();\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/Admin.sol\n\ncontract Admin is IAdmin, AccessControlEnumerable {\n using UniversalTokenLib for address;\n\n bytes32 public constant RELAYER_ROLE = keccak256(\"RELAYER_ROLE\");\n bytes32 public constant REFUNDER_ROLE = keccak256(\"REFUNDER_ROLE\");\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n uint256 public constant FEE_BPS = 1e6;\n uint256 public constant FEE_RATE_MAX = 0.01e6; // max 1% on origin amount\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Chain gas amount to forward as rebate if requested\n uint256 public chainGasAmount;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n }\n\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n require(newFeeRate \u003c= FEE_RATE_MAX, \"newFeeRate \u003e max\");\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n token.universalTransfer(recipient, feeAmount);\n emit FeesSwept(token, recipient, feeAmount);\n }\n\n function setChainGasAmount(uint256 newChainGasAmount) external onlyRole(GOVERNOR_ROLE) {\n uint256 oldChainGasAmount = chainGasAmount;\n chainGasAmount = newChainGasAmount;\n emit ChainGasAmountUpdated(oldChainGasAmount, newChainGasAmount);\n }\n}\n\n// contracts/FastBridgeV2.sol\n\n/// @notice FastBridgeV2 is a contract for bridging tokens across chains.\ncontract FastBridgeV2 is Admin, IFastBridgeV2, IFastBridgeV2Errors {\n using SafeERC20 for IERC20;\n using UniversalTokenLib for address;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Delay for a transaction after which it could be permisionlessly refunded\n uint256 public constant REFUND_DELAY = 7 days;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n /// @notice Maximum length of accepted callParams\n uint256 public constant MAX_CALL_PARAMS_LENGTH = 2 ** 16 - 1;\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeTxDetails) public bridgeTxDetails;\n /// @notice Relay details on destination chain\n mapping(bytes32 =\u003e BridgeRelay) public bridgeRelayDetails;\n /// @notice Unique bridge nonces tracked per originSender\n mapping(address =\u003e uint256) public senderNonces;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Replaced by senderNonces\n uint256 public immutable nonce = 0;\n /// @notice the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n bridge({\n params: params,\n paramsV2: BridgeParamsV2({\n quoteRelayer: address(0),\n quoteExclusivitySeconds: 0,\n quoteId: bytes(\"\"),\n callValue: 0,\n callParams: bytes(\"\")\n })\n });\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes memory request) external payable {\n relay({request: request, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes memory request, bytes32 destTxHash) external {\n prove({transactionId: keccak256(request), destTxHash: destTxHash, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridgeV2\n function claim(bytes memory request) external {\n claim({request: request, to: address(0)});\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003e DISPUTE_PERIOD) {\n revert DisputePeriodPassed();\n }\n\n // @dev relayer gets slashed effectively if dest relay has gone thru\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n bridgeTxDetails[transactionId].proofRelayer = address(0);\n bridgeTxDetails[transactionId].proofBlockTimestamp = 0;\n bridgeTxDetails[transactionId].proofBlockNumber = 0;\n\n emit BridgeProofDisputed(transactionId, msg.sender);\n }\n\n /// @inheritdoc IFastBridge\n function refund(bytes memory request) external {\n bytes32 transactionId = keccak256(request);\n\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n\n if (bridgeTxDetails[transactionId].status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n\n if (hasRole(REFUNDER_ROLE, msg.sender)) {\n // Refunder can refund if deadline has passed\n if (block.timestamp \u003c= transaction.deadline) revert DeadlineNotExceeded();\n } else {\n // Permissionless refund is allowed after REFUND_DELAY\n if (block.timestamp \u003c= transaction.deadline + REFUND_DELAY) revert DeadlineNotExceeded();\n }\n\n // if all checks passed, set to REFUNDED status\n bridgeTxDetails[transactionId].status = BridgeStatus.REFUNDED;\n\n // transfer origin collateral back to original sender\n address to = transaction.originSender;\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount + transaction.originFeeAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (bridgeTxDetails[transactionId].proofRelayer != relayer) revert SenderIncorrect();\n return _timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n /// @dev This method is added to achieve backwards compatibility with decoding requests into V1 structs:\n /// - `callValue` is partially reported as a zero/non-zero flag\n /// - `callParams` is ignored\n /// In order to process all kinds of requests use getBridgeTransactionV2 instead.\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory) {\n // Try decoding into V2 struct first. This will revert if V1 struct is passed\n try this.getBridgeTransactionV2(request) returns (BridgeTransactionV2 memory txV2) {\n // Note: we entirely ignore the callParams field, as it was not present in V1\n return BridgeTransaction({\n originChainId: txV2.originChainId,\n destChainId: txV2.destChainId,\n originSender: txV2.originSender,\n destRecipient: txV2.destRecipient,\n originToken: txV2.originToken,\n destToken: txV2.destToken,\n originAmount: txV2.originAmount,\n destAmount: txV2.destAmount,\n originFeeAmount: txV2.originFeeAmount,\n sendChainGas: txV2.callValue != 0,\n deadline: txV2.deadline,\n nonce: txV2.nonce\n });\n } catch {\n // Fallback to V1 struct\n return abi.decode(request, (BridgeTransaction));\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) public payable {\n int256 exclusivityEndTime = int256(block.timestamp) + paramsV2.quoteExclusivitySeconds;\n _validateBridgeParams(params, paramsV2, exclusivityEndTime);\n\n // transfer tokens to bridge contract\n /// @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _takeBridgedUserAsset(params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n\n // set status to requested\n bytes memory request = abi.encode(\n BridgeTransactionV2({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n callValue: paramsV2.callValue,\n deadline: params.deadline,\n nonce: senderNonces[params.sender]++, // increment nonce on every bridge\n exclusivityRelayer: paramsV2.quoteRelayer,\n // We checked exclusivityEndTime to be in range (0 .. params.deadline] above, so can safely cast\n exclusivityEndTime: uint256(exclusivityEndTime),\n callParams: paramsV2.callParams\n })\n );\n bytes32 transactionId = keccak256(request);\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n\n emit BridgeRequested({\n transactionId: transactionId,\n sender: params.sender,\n request: request,\n destChainId: params.dstChainId,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n sendChainGas: paramsV2.callValue != 0\n });\n emit BridgeQuoteDetails(transactionId, paramsV2.quoteId);\n }\n\n /// @inheritdoc IFastBridgeV2\n function relay(bytes memory request, address relayer) public payable {\n bytes32 transactionId = keccak256(request);\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n _validateRelayParams(transaction, transactionId, relayer);\n // mark bridge transaction as relayed\n bridgeRelayDetails[transactionId] =\n BridgeRelay({blockNumber: uint48(block.number), blockTimestamp: uint48(block.timestamp), relayer: relayer});\n\n // transfer tokens to recipient on destination chain and do an arbitrary call if requested\n address to = transaction.destRecipient;\n address token = transaction.destToken;\n uint256 amount = transaction.destAmount;\n uint256 callValue = transaction.callValue;\n\n // Emit the event before any external calls\n emit BridgeRelayed({\n transactionId: transactionId,\n relayer: relayer,\n to: to,\n originChainId: transaction.originChainId,\n originToken: transaction.originToken,\n destToken: token,\n originAmount: transaction.originAmount,\n destAmount: amount,\n chainGasAmount: callValue\n });\n\n // All state changes have been done at this point, can proceed to the external calls.\n // This follows the checks-effects-interactions pattern to mitigate potential reentrancy attacks.\n if (token == UniversalTokenLib.ETH_ADDRESS) {\n // For ETH non-zero callValue is not allowed\n if (callValue != 0) revert NativeTokenCallValueNotSupported();\n // Check that the correct msg.value was sent\n if (msg.value != amount) revert MsgValueIncorrect();\n } else {\n // For ERC20s, we check that the correct msg.value was sent\n if (msg.value != callValue) revert MsgValueIncorrect();\n // We need to transfer the tokens from the Relayer to the recipient first before performing an\n // optional post-transfer arbitrary call.\n IERC20(token).safeTransferFrom(msg.sender, to, amount);\n }\n\n if (transaction.callParams.length != 0) {\n // Arbitrary call requested, perform it while supplying full msg.value to the recipient\n // Note: if token has a fee on transfers, the recipient will have received less than `amount`.\n // This is a very niche edge case and should be handled by the recipient contract.\n _checkedCallRecipient({recipient: to, token: token, amount: amount, callParams: transaction.callParams});\n } else if (msg.value != 0) {\n // No arbitrary call requested, but msg.value was sent. This is either a relay with ETH,\n // or a non-zero callValue request with an ERC20. In both cases, transfer the ETH to the recipient.\n Address.sendValue(payable(to), msg.value);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) public onlyRole(RELAYER_ROLE) {\n // update bridge tx status given proof provided\n if (bridgeTxDetails[transactionId].status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n bridgeTxDetails[transactionId].status = BridgeStatus.RELAYER_PROVED;\n bridgeTxDetails[transactionId].proofBlockTimestamp = uint40(block.timestamp);\n bridgeTxDetails[transactionId].proofBlockNumber = uint48(block.number);\n bridgeTxDetails[transactionId].proofRelayer = relayer;\n\n emit BridgeProofProvided(transactionId, relayer, destTxHash);\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes memory request, address to) public {\n bytes32 transactionId = keccak256(request);\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n\n // update bridge tx status if able to claim origin collateral\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n\n // if \"to\" is zero addr, permissionlessly send funds to proven relayer\n if (to == address(0)) {\n to = bridgeTxDetails[transactionId].proofRelayer;\n } else if (bridgeTxDetails[transactionId].proofRelayer != msg.sender) {\n revert SenderIncorrect();\n }\n\n if (_timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003c= DISPUTE_PERIOD) {\n revert DisputePeriodNotPassed();\n }\n\n bridgeTxDetails[transactionId].status = BridgeStatus.RELAYER_CLAIMED;\n\n // update protocol fees if origin fee amount exists\n if (transaction.originFeeAmount \u003e 0) protocolFees[transaction.originToken] += transaction.originFeeAmount;\n\n // transfer origin collateral less fee to specified address\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositClaimed(transactionId, bridgeTxDetails[transactionId].proofRelayer, to, token, amount);\n }\n\n function bridgeStatuses(bytes32 transactionId) public view returns (BridgeStatus status) {\n return bridgeTxDetails[transactionId].status;\n }\n\n function bridgeProofs(bytes32 transactionId) public view returns (uint96 timestamp, address relayer) {\n timestamp = bridgeTxDetails[transactionId].proofBlockTimestamp;\n relayer = bridgeTxDetails[transactionId].proofRelayer;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeRelays(bytes32 transactionId) public view returns (bool) {\n // has this transactionId been relayed?\n return bridgeRelayDetails[transactionId].relayer != address(0);\n }\n\n /// @inheritdoc IFastBridgeV2\n function getBridgeTransactionV2(bytes memory request) public pure returns (BridgeTransactionV2 memory) {\n return abi.decode(request, (BridgeTransactionV2));\n }\n\n /// @notice Takes the bridged asset from the user into FastBridgeV2 custody. It will be later\n /// claimed by the relayer who completed the relay on destination chain, or refunded back to the user,\n /// should no one complete the relay.\n function _takeBridgedUserAsset(address token, uint256 amount) internal returns (uint256 amountTaken) {\n if (token == UniversalTokenLib.ETH_ADDRESS) {\n // For ETH we just need to check that the supplied msg.value is correct.\n // Supplied `msg.value` is already in FastBridgeV2 custody.\n if (amount != msg.value) revert MsgValueIncorrect();\n amountTaken = msg.value;\n } else {\n // For ERC20s, token is explicitly transferred from the user to FastBridgeV2.\n // We don't allow non-zero `msg.value` to avoid extra funds from being stuck in FastBridgeV2.\n token.assertIsContract();\n if (msg.value != 0) revert MsgValueIncorrect();\n amountTaken = IERC20(token).balanceOf(address(this));\n IERC20(token).safeTransferFrom(msg.sender, address(this), amount);\n // Use the balance difference as the amount taken in case of fee on transfer tokens.\n amountTaken = IERC20(token).balanceOf(address(this)) - amountTaken;\n }\n }\n\n /// @notice Calls the Recipient's hook function with the specified callParams and performs\n /// all the necessary checks for the returned value.\n function _checkedCallRecipient(\n address recipient,\n address token,\n uint256 amount,\n bytes memory callParams\n )\n internal\n {\n bytes memory hookData =\n abi.encodeCall(IFastBridgeRecipient.fastBridgeTransferReceived, (token, amount, callParams));\n // This will bubble any revert messages from the hook function\n bytes memory returnData = Address.functionCallWithValue({target: recipient, data: hookData, value: msg.value});\n // Explicit revert if no return data at all\n if (returnData.length == 0) revert RecipientNoReturnValue();\n // Check that exactly a single return value was returned\n if (returnData.length != 32) revert RecipientIncorrectReturnValue();\n // Return value should be abi-encoded hook function selector\n if (bytes32(returnData) != bytes32(IFastBridgeRecipient.fastBridgeTransferReceived.selector)) {\n revert RecipientIncorrectReturnValue();\n }\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint40(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint40).max but\n /// proof.timestamp \u003c type(uint40).max via unchecked statement\n /// @param proofBlockTimestamp The bridge proof block timestamp\n /// @return delta Time delta since proof submitted\n function _timeSince(uint40 proofBlockTimestamp) internal view returns (uint256 delta) {\n unchecked {\n delta = uint40(block.timestamp) - proofBlockTimestamp;\n }\n }\n\n /// @notice Performs all the necessary checks for a bridge to happen.\n /// @dev There's no good way to refactor this function to reduce cyclomatic complexity due to\n /// the number of checks that need to be performed, so we skip the code-complexity rule here.\n // solhint-disable-next-line code-complexity\n function _validateBridgeParams(\n BridgeParams memory params,\n BridgeParamsV2 memory paramsV2,\n int256 exclusivityEndTime\n )\n internal\n view\n {\n // Check V1 (legacy) params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.sender == address(0) || params.to == address(0)) revert ZeroAddress();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n // Check V2 params\n if (paramsV2.callParams.length \u003e MAX_CALL_PARAMS_LENGTH) revert CallParamsLengthAboveMax();\n if (paramsV2.callValue != 0 \u0026\u0026 params.destToken == UniversalTokenLib.ETH_ADDRESS) {\n revert NativeTokenCallValueNotSupported();\n }\n // exclusivityEndTime must be in range (0 .. params.deadline]\n if (exclusivityEndTime \u003c= 0 || exclusivityEndTime \u003e int256(params.deadline)) {\n revert ExclusivityParamsIncorrect();\n }\n }\n\n /// @notice Performs all the necessary checks for a relay to happen.\n function _validateRelayParams(\n BridgeTransactionV2 memory transaction,\n bytes32 transactionId,\n address relayer\n )\n internal\n view\n {\n if (relayer == address(0)) revert ZeroAddress();\n // Check if the transaction has already been relayed\n if (bridgeRelays(transactionId)) revert TransactionRelayed();\n if (transaction.destChainId != block.chainid) revert ChainIncorrect();\n // Check the deadline for relay to happen\n if (block.timestamp \u003e transaction.deadline) revert DeadlineExceeded();\n // Check the exclusivity period, if it is still ongoing\n // forgefmt: disable-next-item\n if (\n transaction.exclusivityRelayer != address(0) \u0026\u0026\n transaction.exclusivityRelayer != relayer \u0026\u0026\n block.timestamp \u003c= transaction.exclusivityEndTime\n ) {\n revert ExclusivityPeriodNotPassed();\n }\n }\n}\n","language":"Solidity","languageVersion":"0.8.24","compilerVersion":"0.8.24","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"","srcMapRuntime":"","abiDefinition":[{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"relayer","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"BridgeDepositClaimed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"BridgeDepositRefunded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"relayer","type":"address"}],"name":"BridgeProofDisputed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"relayer","type":"address"},{"indexed":false,"internalType":"bytes32","name":"transactionHash","type":"bytes32"}],"name":"BridgeProofProvided","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":false,"internalType":"bytes","name":"quoteId","type":"bytes"}],"name":"BridgeQuoteDetails","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"relayer","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint32","name":"originChainId","type":"uint32"},{"indexed":false,"internalType":"address","name":"originToken","type":"address"},{"indexed":false,"internalType":"address","name":"destToken","type":"address"},{"indexed":false,"internalType":"uint256","name":"originAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"destAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"chainGasAmount","type":"uint256"}],"name":"BridgeRelayed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"bytes","name":"request","type":"bytes"},{"indexed":false,"internalType":"uint32","name":"destChainId","type":"uint32"},{"indexed":false,"internalType":"address","name":"originToken","type":"address"},{"indexed":false,"internalType":"address","name":"destToken","type":"address"},{"indexed":false,"internalType":"uint256","name":"originAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"destAmount","type":"uint256"},{"indexed":false,"internalType":"bool","name":"sendChainGas","type":"bool"}],"name":"BridgeRequested","type":"event"},{"inputs":[{"components":[{"internalType":"uint32","name":"dstChainId","type":"uint32"},{"internalType":"address","name":"sender","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"address","name":"originToken","type":"address"},{"internalType":"address","name":"destToken","type":"address"},{"internalType":"uint256","name":"originAmount","type":"uint256"},{"internalType":"uint256","name":"destAmount","type":"uint256"},{"internalType":"bool","name":"sendChainGas","type":"bool"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"internalType":"struct IFastBridge.BridgeParams","name":"params","type":"tuple"}],"name":"bridge","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"uint32","name":"dstChainId","type":"uint32"},{"internalType":"address","name":"sender","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"address","name":"originToken","type":"address"},{"internalType":"address","name":"destToken","type":"address"},{"internalType":"uint256","name":"originAmount","type":"uint256"},{"internalType":"uint256","name":"destAmount","type":"uint256"},{"internalType":"bool","name":"sendChainGas","type":"bool"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"internalType":"struct IFastBridge.BridgeParams","name":"params","type":"tuple"},{"components":[{"internalType":"address","name":"quoteRelayer","type":"address"},{"internalType":"int256","name":"quoteExclusivitySeconds","type":"int256"},{"internalType":"bytes","name":"quoteId","type":"bytes"},{"internalType":"uint256","name":"callValue","type":"uint256"},{"internalType":"bytes","name":"callParams","type":"bytes"}],"internalType":"struct IFastBridgeV2.BridgeParamsV2","name":"paramsV2","type":"tuple"}],"name":"bridge","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"transactionId","type":"bytes32"}],"name":"bridgeProofs","outputs":[{"internalType":"uint96","name":"timestamp","type":"uint96"},{"internalType":"address","name":"relayer","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"transactionId","type":"bytes32"}],"name":"bridgeRelays","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"transactionId","type":"bytes32"}],"name":"bridgeStatuses","outputs":[{"internalType":"enum IFastBridgeV2.BridgeStatus","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"internalType":"address","name":"relayer","type":"address"}],"name":"canClaim","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"},{"internalType":"address","name":"to","type":"address"}],"name":"claim","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"}],"name":"claim","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"transactionId","type":"bytes32"}],"name":"dispute","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"}],"name":"getBridgeTransaction","outputs":[{"components":[{"internalType":"uint32","name":"originChainId","type":"uint32"},{"internalType":"uint32","name":"destChainId","type":"uint32"},{"internalType":"address","name":"originSender","type":"address"},{"internalType":"address","name":"destRecipient","type":"address"},{"internalType":"address","name":"originToken","type":"address"},{"internalType":"address","name":"destToken","type":"address"},{"internalType":"uint256","name":"originAmount","type":"uint256"},{"internalType":"uint256","name":"destAmount","type":"uint256"},{"internalType":"uint256","name":"originFeeAmount","type":"uint256"},{"internalType":"bool","name":"sendChainGas","type":"bool"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint256","name":"nonce","type":"uint256"}],"internalType":"struct IFastBridge.BridgeTransaction","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"}],"name":"getBridgeTransactionV2","outputs":[{"components":[{"internalType":"uint32","name":"originChainId","type":"uint32"},{"internalType":"uint32","name":"destChainId","type":"uint32"},{"internalType":"address","name":"originSender","type":"address"},{"internalType":"address","name":"destRecipient","type":"address"},{"internalType":"address","name":"originToken","type":"address"},{"internalType":"address","name":"destToken","type":"address"},{"internalType":"uint256","name":"originAmount","type":"uint256"},{"internalType":"uint256","name":"destAmount","type":"uint256"},{"internalType":"uint256","name":"originFeeAmount","type":"uint256"},{"internalType":"uint256","name":"callValue","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"address","name":"exclusivityRelayer","type":"address"},{"internalType":"uint256","name":"exclusivityEndTime","type":"uint256"},{"internalType":"bytes","name":"callParams","type":"bytes"}],"internalType":"struct IFastBridgeV2.BridgeTransactionV2","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"internalType":"bytes32","name":"destTxHash","type":"bytes32"},{"internalType":"address","name":"relayer","type":"address"}],"name":"prove","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"},{"internalType":"bytes32","name":"destTxHash","type":"bytes32"}],"name":"prove","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"}],"name":"refund","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"}],"name":"relay","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"},{"internalType":"address","name":"relayer","type":"address"}],"name":"relay","outputs":[],"stateMutability":"payable","type":"function"}],"userDoc":{"kind":"user","methods":{"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256))":{"notice":"Initiates bridge on origin chain to be relayed by off-chain relayer"},"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256),(address,int256,bytes,uint256,bytes))":{"notice":"Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability to provide temporary exclusivity fill rights for the quote relayer."},"bridgeProofs(bytes32)":{"notice":"Returns the timestamp and relayer of a bridge proof"},"bridgeRelays(bytes32)":{"notice":"Checks if a transaction has been relayed"},"bridgeStatuses(bytes32)":{"notice":"Returns the status of a bridge transaction"},"canClaim(bytes32,address)":{"notice":"Checks if the dispute period has passed so bridge deposit can be claimed"},"claim(bytes)":{"notice":"Completes bridge transaction on origin chain by claiming originally deposited capital.Can only send funds to the relayer address on the proof."},"claim(bytes,address)":{"notice":"Completes bridge transaction on origin chain by claiming originally deposited capital"},"dispute(bytes32)":{"notice":"Disputes an outstanding proof in case relayer provided dest chain tx is invalid"},"getBridgeTransaction(bytes)":{"notice":"Decodes bridge request into a bridge transaction"},"getBridgeTransactionV2(bytes)":{"notice":"Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2"},"prove(bytes,bytes32)":{"notice":"Provides proof on origin side that relayer provided funds on destination side of bridge transaction"},"prove(bytes32,bytes32,address)":{"notice":"Provides proof on origin side that relayer provided funds on destination side of bridge transaction"},"refund(bytes)":{"notice":"Refunds an outstanding bridge transaction in case optimistic bridging failed"},"relay(bytes)":{"notice":"Relays destination side of bridge transaction by off-chain relayer"},"relay(bytes,address)":{"notice":"Relays destination side of bridge transaction by off-chain relayer"}},"version":1},"developerDoc":{"kind":"dev","methods":{"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256))":{"params":{"params":"The parameters required to bridge"}},"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256),(address,int256,bytes,uint256,bytes))":{"params":{"params":"The parameters required to bridge","paramsV2":"The parameters for exclusivity fill rights (optional, can be left empty)"}},"bridgeProofs(bytes32)":{"params":{"transactionId":"The ID of the bridge transaction"},"returns":{"relayer":"The relayer address of the bridge proof","timestamp":"The timestamp of the bridge proof"}},"bridgeRelays(bytes32)":{"params":{"transactionId":"The ID of the transaction to check"},"returns":{"_0":"True if the transaction has been relayed, false otherwise"}},"bridgeStatuses(bytes32)":{"params":{"transactionId":"The ID of the bridge transaction"},"returns":{"_0":"BridgeStatus Status of the bridge transaction"}},"canClaim(bytes32,address)":{"params":{"relayer":"The address of the relayer attempting to claim","transactionId":"The transaction id associated with the encoded bridge transaction to check"}},"claim(bytes)":{"params":{"request":"The encoded bridge transaction to claim on origin chain"}},"claim(bytes,address)":{"params":{"request":"The encoded bridge transaction to claim on origin chain","to":"The recipient address of the funds"}},"dispute(bytes32)":{"params":{"transactionId":"The transaction id associated with the encoded bridge transaction to dispute"}},"getBridgeTransaction(bytes)":{"params":{"request":"The bridge request to decode"}},"getBridgeTransactionV2(bytes)":{"params":{"request":"The bridge request to decode"}},"prove(bytes,bytes32)":{"params":{"destTxHash":"The destination tx hash proving bridge transaction was relayed","request":"The encoded bridge transaction to prove on origin chain"}},"prove(bytes32,bytes32,address)":{"params":{"destTxHash":"The destination tx hash proving bridge transaction was relayed","relayer":"The address of the relaying entity which should have control of the origin funds when claimed","transactionId":"The transaction id associated with the encoded bridge transaction to prove"}},"refund(bytes)":{"params":{"request":"The encoded bridge transaction to refund"}},"relay(bytes)":{"params":{"request":"The encoded bridge transaction to relay on destination chain"}},"relay(bytes,address)":{"params":{"relayer":"The address of the relaying entity which should have control of the origin funds when claimed","request":"The encoded bridge transaction to relay on destination chain"}}},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"BridgeDepositClaimed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"BridgeDepositRefunded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"name\":\"BridgeProofDisputed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"transactionHash\",\"type\":\"bytes32\"}],\"name\":\"BridgeProofProvided\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"quoteId\",\"type\":\"bytes\"}],\"name\":\"BridgeQuoteDetails\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"originChainId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"chainGasAmount\",\"type\":\"uint256\"}],\"name\":\"BridgeRelayed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"destChainId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"sendChainGas\",\"type\":\"bool\"}],\"name\":\"BridgeRequested\",\"type\":\"event\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"dstChainId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"sendChainGas\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"}],\"internalType\":\"struct IFastBridge.BridgeParams\",\"name\":\"params\",\"type\":\"tuple\"}],\"name\":\"bridge\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"dstChainId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"sendChainGas\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"}],\"internalType\":\"struct IFastBridge.BridgeParams\",\"name\":\"params\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"quoteRelayer\",\"type\":\"address\"},{\"internalType\":\"int256\",\"name\":\"quoteExclusivitySeconds\",\"type\":\"int256\"},{\"internalType\":\"bytes\",\"name\":\"quoteId\",\"type\":\"bytes\"},{\"internalType\":\"uint256\",\"name\":\"callValue\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"callParams\",\"type\":\"bytes\"}],\"internalType\":\"struct IFastBridgeV2.BridgeParamsV2\",\"name\":\"paramsV2\",\"type\":\"tuple\"}],\"name\":\"bridge\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"}],\"name\":\"bridgeProofs\",\"outputs\":[{\"internalType\":\"uint96\",\"name\":\"timestamp\",\"type\":\"uint96\"},{\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"}],\"name\":\"bridgeRelays\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"}],\"name\":\"bridgeStatuses\",\"outputs\":[{\"internalType\":\"enum IFastBridgeV2.BridgeStatus\",\"name\":\"\",\"type\":\"uint8\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"name\":\"canClaim\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"claim\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"claim\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"}],\"name\":\"dispute\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"getBridgeTransaction\",\"outputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"originChainId\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"destChainId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"originSender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destRecipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"originFeeAmount\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"sendChainGas\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"}],\"internalType\":\"struct IFastBridge.BridgeTransaction\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"getBridgeTransactionV2\",\"outputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"originChainId\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"destChainId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"originSender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destRecipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"originFeeAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"callValue\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"exclusivityRelayer\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"exclusivityEndTime\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"callParams\",\"type\":\"bytes\"}],\"internalType\":\"struct IFastBridgeV2.BridgeTransactionV2\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"destTxHash\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"name\":\"prove\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"},{\"internalType\":\"bytes32\",\"name\":\"destTxHash\",\"type\":\"bytes32\"}],\"name\":\"prove\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"refund\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"relay\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"},{\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"name\":\"relay\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{\"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256))\":{\"params\":{\"params\":\"The parameters required to bridge\"}},\"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256),(address,int256,bytes,uint256,bytes))\":{\"params\":{\"params\":\"The parameters required to bridge\",\"paramsV2\":\"The parameters for exclusivity fill rights (optional, can be left empty)\"}},\"bridgeProofs(bytes32)\":{\"params\":{\"transactionId\":\"The ID of the bridge transaction\"},\"returns\":{\"relayer\":\"The relayer address of the bridge proof\",\"timestamp\":\"The timestamp of the bridge proof\"}},\"bridgeRelays(bytes32)\":{\"params\":{\"transactionId\":\"The ID of the transaction to check\"},\"returns\":{\"_0\":\"True if the transaction has been relayed, false otherwise\"}},\"bridgeStatuses(bytes32)\":{\"params\":{\"transactionId\":\"The ID of the bridge transaction\"},\"returns\":{\"_0\":\"BridgeStatus Status of the bridge transaction\"}},\"canClaim(bytes32,address)\":{\"params\":{\"relayer\":\"The address of the relayer attempting to claim\",\"transactionId\":\"The transaction id associated with the encoded bridge transaction to check\"}},\"claim(bytes)\":{\"params\":{\"request\":\"The encoded bridge transaction to claim on origin chain\"}},\"claim(bytes,address)\":{\"params\":{\"request\":\"The encoded bridge transaction to claim on origin chain\",\"to\":\"The recipient address of the funds\"}},\"dispute(bytes32)\":{\"params\":{\"transactionId\":\"The transaction id associated with the encoded bridge transaction to dispute\"}},\"getBridgeTransaction(bytes)\":{\"params\":{\"request\":\"The bridge request to decode\"}},\"getBridgeTransactionV2(bytes)\":{\"params\":{\"request\":\"The bridge request to decode\"}},\"prove(bytes,bytes32)\":{\"params\":{\"destTxHash\":\"The destination tx hash proving bridge transaction was relayed\",\"request\":\"The encoded bridge transaction to prove on origin chain\"}},\"prove(bytes32,bytes32,address)\":{\"params\":{\"destTxHash\":\"The destination tx hash proving bridge transaction was relayed\",\"relayer\":\"The address of the relaying entity which should have control of the origin funds when claimed\",\"transactionId\":\"The transaction id associated with the encoded bridge transaction to prove\"}},\"refund(bytes)\":{\"params\":{\"request\":\"The encoded bridge transaction to refund\"}},\"relay(bytes)\":{\"params\":{\"request\":\"The encoded bridge transaction to relay on destination chain\"}},\"relay(bytes,address)\":{\"params\":{\"relayer\":\"The address of the relaying entity which should have control of the origin funds when claimed\",\"request\":\"The encoded bridge transaction to relay on destination chain\"}}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256))\":{\"notice\":\"Initiates bridge on origin chain to be relayed by off-chain relayer\"},\"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256),(address,int256,bytes,uint256,bytes))\":{\"notice\":\"Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability to provide temporary exclusivity fill rights for the quote relayer.\"},\"bridgeProofs(bytes32)\":{\"notice\":\"Returns the timestamp and relayer of a bridge proof\"},\"bridgeRelays(bytes32)\":{\"notice\":\"Checks if a transaction has been relayed\"},\"bridgeStatuses(bytes32)\":{\"notice\":\"Returns the status of a bridge transaction\"},\"canClaim(bytes32,address)\":{\"notice\":\"Checks if the dispute period has passed so bridge deposit can be claimed\"},\"claim(bytes)\":{\"notice\":\"Completes bridge transaction on origin chain by claiming originally deposited capital.Can only send funds to the relayer address on the proof.\"},\"claim(bytes,address)\":{\"notice\":\"Completes bridge transaction on origin chain by claiming originally deposited capital\"},\"dispute(bytes32)\":{\"notice\":\"Disputes an outstanding proof in case relayer provided dest chain tx is invalid\"},\"getBridgeTransaction(bytes)\":{\"notice\":\"Decodes bridge request into a bridge transaction\"},\"getBridgeTransactionV2(bytes)\":{\"notice\":\"Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\"},\"prove(bytes,bytes32)\":{\"notice\":\"Provides proof on origin side that relayer provided funds on destination side of bridge transaction\"},\"prove(bytes32,bytes32,address)\":{\"notice\":\"Provides proof on origin side that relayer provided funds on destination side of bridge transaction\"},\"refund(bytes)\":{\"notice\":\"Refunds an outstanding bridge transaction in case optimistic bridging failed\"},\"relay(bytes)\":{\"notice\":\"Relays destination side of bridge transaction by off-chain relayer\"},\"relay(bytes,address)\":{\"notice\":\"Relays destination side of bridge transaction by off-chain relayer\"}},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeV2.sol\":\"IFastBridgeV2\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeV2.sol\":{\"keccak256\":\"0xfd916c030b1ffca5a136817827b8018c8ba42ca089905747f3de6148b73eb35e\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://18e6438c4096deb8ae453fb3365ba2b07d52944e93c08288fc5d012b71bf6bb3\",\"dweb:/ipfs/QmfEMqpT1zz6RRm7UuHLRowe1tds2cTGLrVonfm9XSCACj\"]}},\"version\":1}"},"hashes":{"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256))":"45851694","bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256),(address,int256,bytes,uint256,bytes))":"bfc7c607","bridgeProofs(bytes32)":"91ad5039","bridgeRelays(bytes32)":"8379a24f","bridgeStatuses(bytes32)":"051287bc","canClaim(bytes32,address)":"aa9641ab","claim(bytes)":"c63ff8dd","claim(bytes,address)":"41fcb612","dispute(bytes32)":"add98c70","getBridgeTransaction(bytes)":"ac11fb1a","getBridgeTransactionV2(bytes)":"5aa6ccba","prove(bytes,bytes32)":"886d36ff","prove(bytes32,bytes32,address)":"18e4357d","refund(bytes)":"5eb7d946","relay(bytes)":"8f0d6f17","relay(bytes,address)":"9c9545f0"}},"solidity/FastBridgeV2.sol:IFastBridgeV2Errors":{"code":"0x","runtime-code":"0x","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.24 ^0.8.0 ^0.8.20;\n\n// contracts/interfaces/IAdmin.sol\n\ninterface IAdmin {\n // ============ Events ============\n\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n event ChainGasAmountUpdated(uint256 oldChainGasAmount, uint256 newChainGasAmount);\n\n // ============ Methods ============\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n\n function setChainGasAmount(uint256 newChainGasAmount) external;\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IFastBridgeRecipient.sol\n\ninterface IFastBridgeRecipient {\n function fastBridgeTransferReceived(\n address token,\n uint256 amount,\n bytes memory callParams\n )\n external\n payable\n returns (bytes4);\n}\n\n// contracts/interfaces/IFastBridgeV2Errors.sol\n\ninterface IFastBridgeV2Errors {\n error AmountIncorrect();\n error CallParamsLengthAboveMax();\n error ChainIncorrect();\n error ExclusivityParamsIncorrect();\n error MsgValueIncorrect();\n error NativeTokenCallValueNotSupported();\n error SenderIncorrect();\n error StatusIncorrect();\n error ZeroAddress();\n\n error RecipientIncorrectReturnValue();\n error RecipientNoReturnValue();\n\n error DeadlineExceeded();\n error DeadlineNotExceeded();\n error DeadlineTooShort();\n error DisputePeriodNotPassed();\n error DisputePeriodPassed();\n error ExclusivityPeriodNotPassed();\n\n error TransactionRelayed();\n}\n\n// contracts/libs/Errors.sol\n\nerror DeadlineExceeded();\nerror DeadlineNotExceeded();\nerror DeadlineTooShort();\nerror InsufficientOutputAmount();\n\nerror MsgValueIncorrect();\nerror PoolNotFound();\nerror TokenAddressMismatch();\nerror TokenNotContract();\nerror TokenNotETH();\nerror TokensIdentical();\n\nerror ChainIncorrect();\nerror AmountIncorrect();\nerror ZeroAddress();\n\nerror DisputePeriodNotPassed();\nerror DisputePeriodPassed();\nerror SenderIncorrect();\nerror StatusIncorrect();\nerror TransactionIdIncorrect();\nerror TransactionRelayed();\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// contracts/interfaces/IFastBridgeV2.sol\n\ninterface IFastBridgeV2 is IFastBridge {\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n struct BridgeTxDetails {\n BridgeStatus status;\n uint40 proofBlockTimestamp;\n uint48 proofBlockNumber;\n address proofRelayer;\n }\n\n struct BridgeRelay {\n uint48 blockNumber;\n uint48 blockTimestamp;\n address relayer;\n }\n\n /// @notice New params introduced in the FastBridgeV2.\n /// We are passing fields from the older BridgeParams struct outside of this struct\n /// for backwards compatibility.\n /// Note: quoteRelayer and quoteExclusivitySeconds are either both zero (indicating no exclusivity)\n /// or both non-zero (indicating exclusivity for the given period).\n /// Note: callValue \u003e 0 can NOT be used with destToken = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE (ETH_ADDRESS)\n /// @param quoteRelayer Relayer that provided the quote for the transaction\n /// @param quoteExclusivitySeconds Period of time the quote relayer is guaranteed exclusivity after user's deposit\n /// @param quoteId Unique quote identifier used for tracking the quote\n /// @param callValue ETH value to send to the recipient (if any)\n /// @param callParams Parameters for the arbitrary call to the destination recipient (if any)\n struct BridgeParamsV2 {\n address quoteRelayer;\n int256 quoteExclusivitySeconds;\n bytes quoteId;\n uint256 callValue;\n bytes callParams;\n }\n\n /// @notice Updated bridge transaction struct to include parameters introduced in FastBridgeV2.\n /// Note: only `exclusivityRelayer` can fill such a transaction until `exclusivityEndTime`.\n /// TODO: consider changing the encoding scheme to prevent spending extra gas on decoding.\n struct BridgeTransactionV2 {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n uint256 callValue; // ETH value to send to the recipient (if any) - replaces V1's sendChainGas flag\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n address exclusivityRelayer;\n uint256 exclusivityEndTime;\n bytes callParams;\n }\n\n event BridgeQuoteDetails(bytes32 indexed transactionId, bytes quoteId);\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability\n /// to provide temporary exclusivity fill rights for the quote relayer.\n /// @param params The parameters required to bridge\n /// @param paramsV2 The parameters for exclusivity fill rights (optional, can be left empty)\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function relay(bytes memory request, address relayer) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param transactionId The transaction id associated with the encoded bridge transaction to prove\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital.\n /// @notice Can only send funds to the relayer address on the proof.\n /// @param request The encoded bridge transaction to claim on origin chain\n function claim(bytes memory request) external;\n /// @notice Checks if a transaction has been relayed\n /// @param transactionId The ID of the transaction to check\n /// @return True if the transaction has been relayed, false otherwise\n function bridgeRelays(bytes32 transactionId) external view returns (bool);\n\n /// @notice Returns the status of a bridge transaction\n /// @param transactionId The ID of the bridge transaction\n /// @return BridgeStatus Status of the bridge transaction\n function bridgeStatuses(bytes32 transactionId) external view returns (BridgeStatus);\n\n /// @notice Returns the timestamp and relayer of a bridge proof\n /// @param transactionId The ID of the bridge transaction\n /// @return timestamp The timestamp of the bridge proof\n /// @return relayer The relayer address of the bridge proof\n function bridgeProofs(bytes32 transactionId) external view returns (uint96 timestamp, address relayer);\n\n /// @notice Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\n /// @param request The bridge request to decode\n function getBridgeTransactionV2(bytes memory request) external view returns (BridgeTransactionV2 memory);\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// contracts/libs/UniversalToken.sol\n\nlibrary UniversalTokenLib {\n using SafeERC20 for IERC20;\n\n address internal constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Transfers tokens to the given account. Reverts if transfer is not successful.\n /// @dev This might trigger fallback, if ETH is transferred to the contract.\n /// Make sure this can not lead to reentrancy attacks.\n function universalTransfer(address token, address to, uint256 value) internal {\n // Don't do anything, if need to send tokens to this address\n if (to == address(this)) return;\n // Don't do anything, if trying to send zero value\n if (value == 0) return;\n if (token == ETH_ADDRESS) {\n /// @dev Note: this can potentially lead to executing code in `to`.\n // solhint-disable-next-line avoid-low-level-calls\n (bool success,) = to.call{value: value}(\"\");\n require(success, \"ETH transfer failed\");\n } else {\n IERC20(token).safeTransfer(to, value);\n }\n }\n\n /// @notice Issues an infinite allowance to the spender, if the current allowance is insufficient\n /// to spend the given amount.\n function universalApproveInfinity(address token, address spender, uint256 amountToSpend) internal {\n // ETH Chad doesn't require your approval\n if (token == ETH_ADDRESS) return;\n // No-op if allowance is already sufficient\n uint256 allowance = IERC20(token).allowance(address(this), spender);\n if (allowance \u003e= amountToSpend) return;\n // Otherwise, reset approval to 0 and set to max allowance\n if (allowance \u003e 0) IERC20(token).safeDecreaseAllowance(spender, allowance);\n IERC20(token).safeIncreaseAllowance(spender, type(uint256).max);\n }\n\n /// @notice Returns the balance of the given token (or native ETH) for the given account.\n function universalBalanceOf(address token, address account) internal view returns (uint256) {\n if (token == ETH_ADDRESS) {\n return account.balance;\n } else {\n return IERC20(token).balanceOf(account);\n }\n }\n\n /// @dev Checks that token is a contract and not ETH_ADDRESS.\n function assertIsContract(address token) internal view {\n // Check that ETH_ADDRESS was not used (in case this is a predeploy on any of the chains)\n if (token == UniversalTokenLib.ETH_ADDRESS) revert TokenNotContract();\n // Check that token is not an EOA\n if (token.code.length == 0) revert TokenNotContract();\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/Admin.sol\n\ncontract Admin is IAdmin, AccessControlEnumerable {\n using UniversalTokenLib for address;\n\n bytes32 public constant RELAYER_ROLE = keccak256(\"RELAYER_ROLE\");\n bytes32 public constant REFUNDER_ROLE = keccak256(\"REFUNDER_ROLE\");\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n uint256 public constant FEE_BPS = 1e6;\n uint256 public constant FEE_RATE_MAX = 0.01e6; // max 1% on origin amount\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Chain gas amount to forward as rebate if requested\n uint256 public chainGasAmount;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n }\n\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n require(newFeeRate \u003c= FEE_RATE_MAX, \"newFeeRate \u003e max\");\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n token.universalTransfer(recipient, feeAmount);\n emit FeesSwept(token, recipient, feeAmount);\n }\n\n function setChainGasAmount(uint256 newChainGasAmount) external onlyRole(GOVERNOR_ROLE) {\n uint256 oldChainGasAmount = chainGasAmount;\n chainGasAmount = newChainGasAmount;\n emit ChainGasAmountUpdated(oldChainGasAmount, newChainGasAmount);\n }\n}\n\n// contracts/FastBridgeV2.sol\n\n/// @notice FastBridgeV2 is a contract for bridging tokens across chains.\ncontract FastBridgeV2 is Admin, IFastBridgeV2, IFastBridgeV2Errors {\n using SafeERC20 for IERC20;\n using UniversalTokenLib for address;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Delay for a transaction after which it could be permisionlessly refunded\n uint256 public constant REFUND_DELAY = 7 days;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n /// @notice Maximum length of accepted callParams\n uint256 public constant MAX_CALL_PARAMS_LENGTH = 2 ** 16 - 1;\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeTxDetails) public bridgeTxDetails;\n /// @notice Relay details on destination chain\n mapping(bytes32 =\u003e BridgeRelay) public bridgeRelayDetails;\n /// @notice Unique bridge nonces tracked per originSender\n mapping(address =\u003e uint256) public senderNonces;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Replaced by senderNonces\n uint256 public immutable nonce = 0;\n /// @notice the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n bridge({\n params: params,\n paramsV2: BridgeParamsV2({\n quoteRelayer: address(0),\n quoteExclusivitySeconds: 0,\n quoteId: bytes(\"\"),\n callValue: 0,\n callParams: bytes(\"\")\n })\n });\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes memory request) external payable {\n relay({request: request, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes memory request, bytes32 destTxHash) external {\n prove({transactionId: keccak256(request), destTxHash: destTxHash, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridgeV2\n function claim(bytes memory request) external {\n claim({request: request, to: address(0)});\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003e DISPUTE_PERIOD) {\n revert DisputePeriodPassed();\n }\n\n // @dev relayer gets slashed effectively if dest relay has gone thru\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n bridgeTxDetails[transactionId].proofRelayer = address(0);\n bridgeTxDetails[transactionId].proofBlockTimestamp = 0;\n bridgeTxDetails[transactionId].proofBlockNumber = 0;\n\n emit BridgeProofDisputed(transactionId, msg.sender);\n }\n\n /// @inheritdoc IFastBridge\n function refund(bytes memory request) external {\n bytes32 transactionId = keccak256(request);\n\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n\n if (bridgeTxDetails[transactionId].status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n\n if (hasRole(REFUNDER_ROLE, msg.sender)) {\n // Refunder can refund if deadline has passed\n if (block.timestamp \u003c= transaction.deadline) revert DeadlineNotExceeded();\n } else {\n // Permissionless refund is allowed after REFUND_DELAY\n if (block.timestamp \u003c= transaction.deadline + REFUND_DELAY) revert DeadlineNotExceeded();\n }\n\n // if all checks passed, set to REFUNDED status\n bridgeTxDetails[transactionId].status = BridgeStatus.REFUNDED;\n\n // transfer origin collateral back to original sender\n address to = transaction.originSender;\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount + transaction.originFeeAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (bridgeTxDetails[transactionId].proofRelayer != relayer) revert SenderIncorrect();\n return _timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n /// @dev This method is added to achieve backwards compatibility with decoding requests into V1 structs:\n /// - `callValue` is partially reported as a zero/non-zero flag\n /// - `callParams` is ignored\n /// In order to process all kinds of requests use getBridgeTransactionV2 instead.\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory) {\n // Try decoding into V2 struct first. This will revert if V1 struct is passed\n try this.getBridgeTransactionV2(request) returns (BridgeTransactionV2 memory txV2) {\n // Note: we entirely ignore the callParams field, as it was not present in V1\n return BridgeTransaction({\n originChainId: txV2.originChainId,\n destChainId: txV2.destChainId,\n originSender: txV2.originSender,\n destRecipient: txV2.destRecipient,\n originToken: txV2.originToken,\n destToken: txV2.destToken,\n originAmount: txV2.originAmount,\n destAmount: txV2.destAmount,\n originFeeAmount: txV2.originFeeAmount,\n sendChainGas: txV2.callValue != 0,\n deadline: txV2.deadline,\n nonce: txV2.nonce\n });\n } catch {\n // Fallback to V1 struct\n return abi.decode(request, (BridgeTransaction));\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) public payable {\n int256 exclusivityEndTime = int256(block.timestamp) + paramsV2.quoteExclusivitySeconds;\n _validateBridgeParams(params, paramsV2, exclusivityEndTime);\n\n // transfer tokens to bridge contract\n /// @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _takeBridgedUserAsset(params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n\n // set status to requested\n bytes memory request = abi.encode(\n BridgeTransactionV2({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n callValue: paramsV2.callValue,\n deadline: params.deadline,\n nonce: senderNonces[params.sender]++, // increment nonce on every bridge\n exclusivityRelayer: paramsV2.quoteRelayer,\n // We checked exclusivityEndTime to be in range (0 .. params.deadline] above, so can safely cast\n exclusivityEndTime: uint256(exclusivityEndTime),\n callParams: paramsV2.callParams\n })\n );\n bytes32 transactionId = keccak256(request);\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n\n emit BridgeRequested({\n transactionId: transactionId,\n sender: params.sender,\n request: request,\n destChainId: params.dstChainId,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n sendChainGas: paramsV2.callValue != 0\n });\n emit BridgeQuoteDetails(transactionId, paramsV2.quoteId);\n }\n\n /// @inheritdoc IFastBridgeV2\n function relay(bytes memory request, address relayer) public payable {\n bytes32 transactionId = keccak256(request);\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n _validateRelayParams(transaction, transactionId, relayer);\n // mark bridge transaction as relayed\n bridgeRelayDetails[transactionId] =\n BridgeRelay({blockNumber: uint48(block.number), blockTimestamp: uint48(block.timestamp), relayer: relayer});\n\n // transfer tokens to recipient on destination chain and do an arbitrary call if requested\n address to = transaction.destRecipient;\n address token = transaction.destToken;\n uint256 amount = transaction.destAmount;\n uint256 callValue = transaction.callValue;\n\n // Emit the event before any external calls\n emit BridgeRelayed({\n transactionId: transactionId,\n relayer: relayer,\n to: to,\n originChainId: transaction.originChainId,\n originToken: transaction.originToken,\n destToken: token,\n originAmount: transaction.originAmount,\n destAmount: amount,\n chainGasAmount: callValue\n });\n\n // All state changes have been done at this point, can proceed to the external calls.\n // This follows the checks-effects-interactions pattern to mitigate potential reentrancy attacks.\n if (token == UniversalTokenLib.ETH_ADDRESS) {\n // For ETH non-zero callValue is not allowed\n if (callValue != 0) revert NativeTokenCallValueNotSupported();\n // Check that the correct msg.value was sent\n if (msg.value != amount) revert MsgValueIncorrect();\n } else {\n // For ERC20s, we check that the correct msg.value was sent\n if (msg.value != callValue) revert MsgValueIncorrect();\n // We need to transfer the tokens from the Relayer to the recipient first before performing an\n // optional post-transfer arbitrary call.\n IERC20(token).safeTransferFrom(msg.sender, to, amount);\n }\n\n if (transaction.callParams.length != 0) {\n // Arbitrary call requested, perform it while supplying full msg.value to the recipient\n // Note: if token has a fee on transfers, the recipient will have received less than `amount`.\n // This is a very niche edge case and should be handled by the recipient contract.\n _checkedCallRecipient({recipient: to, token: token, amount: amount, callParams: transaction.callParams});\n } else if (msg.value != 0) {\n // No arbitrary call requested, but msg.value was sent. This is either a relay with ETH,\n // or a non-zero callValue request with an ERC20. In both cases, transfer the ETH to the recipient.\n Address.sendValue(payable(to), msg.value);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) public onlyRole(RELAYER_ROLE) {\n // update bridge tx status given proof provided\n if (bridgeTxDetails[transactionId].status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n bridgeTxDetails[transactionId].status = BridgeStatus.RELAYER_PROVED;\n bridgeTxDetails[transactionId].proofBlockTimestamp = uint40(block.timestamp);\n bridgeTxDetails[transactionId].proofBlockNumber = uint48(block.number);\n bridgeTxDetails[transactionId].proofRelayer = relayer;\n\n emit BridgeProofProvided(transactionId, relayer, destTxHash);\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes memory request, address to) public {\n bytes32 transactionId = keccak256(request);\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n\n // update bridge tx status if able to claim origin collateral\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n\n // if \"to\" is zero addr, permissionlessly send funds to proven relayer\n if (to == address(0)) {\n to = bridgeTxDetails[transactionId].proofRelayer;\n } else if (bridgeTxDetails[transactionId].proofRelayer != msg.sender) {\n revert SenderIncorrect();\n }\n\n if (_timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003c= DISPUTE_PERIOD) {\n revert DisputePeriodNotPassed();\n }\n\n bridgeTxDetails[transactionId].status = BridgeStatus.RELAYER_CLAIMED;\n\n // update protocol fees if origin fee amount exists\n if (transaction.originFeeAmount \u003e 0) protocolFees[transaction.originToken] += transaction.originFeeAmount;\n\n // transfer origin collateral less fee to specified address\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositClaimed(transactionId, bridgeTxDetails[transactionId].proofRelayer, to, token, amount);\n }\n\n function bridgeStatuses(bytes32 transactionId) public view returns (BridgeStatus status) {\n return bridgeTxDetails[transactionId].status;\n }\n\n function bridgeProofs(bytes32 transactionId) public view returns (uint96 timestamp, address relayer) {\n timestamp = bridgeTxDetails[transactionId].proofBlockTimestamp;\n relayer = bridgeTxDetails[transactionId].proofRelayer;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeRelays(bytes32 transactionId) public view returns (bool) {\n // has this transactionId been relayed?\n return bridgeRelayDetails[transactionId].relayer != address(0);\n }\n\n /// @inheritdoc IFastBridgeV2\n function getBridgeTransactionV2(bytes memory request) public pure returns (BridgeTransactionV2 memory) {\n return abi.decode(request, (BridgeTransactionV2));\n }\n\n /// @notice Takes the bridged asset from the user into FastBridgeV2 custody. It will be later\n /// claimed by the relayer who completed the relay on destination chain, or refunded back to the user,\n /// should no one complete the relay.\n function _takeBridgedUserAsset(address token, uint256 amount) internal returns (uint256 amountTaken) {\n if (token == UniversalTokenLib.ETH_ADDRESS) {\n // For ETH we just need to check that the supplied msg.value is correct.\n // Supplied `msg.value` is already in FastBridgeV2 custody.\n if (amount != msg.value) revert MsgValueIncorrect();\n amountTaken = msg.value;\n } else {\n // For ERC20s, token is explicitly transferred from the user to FastBridgeV2.\n // We don't allow non-zero `msg.value` to avoid extra funds from being stuck in FastBridgeV2.\n token.assertIsContract();\n if (msg.value != 0) revert MsgValueIncorrect();\n amountTaken = IERC20(token).balanceOf(address(this));\n IERC20(token).safeTransferFrom(msg.sender, address(this), amount);\n // Use the balance difference as the amount taken in case of fee on transfer tokens.\n amountTaken = IERC20(token).balanceOf(address(this)) - amountTaken;\n }\n }\n\n /// @notice Calls the Recipient's hook function with the specified callParams and performs\n /// all the necessary checks for the returned value.\n function _checkedCallRecipient(\n address recipient,\n address token,\n uint256 amount,\n bytes memory callParams\n )\n internal\n {\n bytes memory hookData =\n abi.encodeCall(IFastBridgeRecipient.fastBridgeTransferReceived, (token, amount, callParams));\n // This will bubble any revert messages from the hook function\n bytes memory returnData = Address.functionCallWithValue({target: recipient, data: hookData, value: msg.value});\n // Explicit revert if no return data at all\n if (returnData.length == 0) revert RecipientNoReturnValue();\n // Check that exactly a single return value was returned\n if (returnData.length != 32) revert RecipientIncorrectReturnValue();\n // Return value should be abi-encoded hook function selector\n if (bytes32(returnData) != bytes32(IFastBridgeRecipient.fastBridgeTransferReceived.selector)) {\n revert RecipientIncorrectReturnValue();\n }\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint40(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint40).max but\n /// proof.timestamp \u003c type(uint40).max via unchecked statement\n /// @param proofBlockTimestamp The bridge proof block timestamp\n /// @return delta Time delta since proof submitted\n function _timeSince(uint40 proofBlockTimestamp) internal view returns (uint256 delta) {\n unchecked {\n delta = uint40(block.timestamp) - proofBlockTimestamp;\n }\n }\n\n /// @notice Performs all the necessary checks for a bridge to happen.\n /// @dev There's no good way to refactor this function to reduce cyclomatic complexity due to\n /// the number of checks that need to be performed, so we skip the code-complexity rule here.\n // solhint-disable-next-line code-complexity\n function _validateBridgeParams(\n BridgeParams memory params,\n BridgeParamsV2 memory paramsV2,\n int256 exclusivityEndTime\n )\n internal\n view\n {\n // Check V1 (legacy) params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.sender == address(0) || params.to == address(0)) revert ZeroAddress();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n // Check V2 params\n if (paramsV2.callParams.length \u003e MAX_CALL_PARAMS_LENGTH) revert CallParamsLengthAboveMax();\n if (paramsV2.callValue != 0 \u0026\u0026 params.destToken == UniversalTokenLib.ETH_ADDRESS) {\n revert NativeTokenCallValueNotSupported();\n }\n // exclusivityEndTime must be in range (0 .. params.deadline]\n if (exclusivityEndTime \u003c= 0 || exclusivityEndTime \u003e int256(params.deadline)) {\n revert ExclusivityParamsIncorrect();\n }\n }\n\n /// @notice Performs all the necessary checks for a relay to happen.\n function _validateRelayParams(\n BridgeTransactionV2 memory transaction,\n bytes32 transactionId,\n address relayer\n )\n internal\n view\n {\n if (relayer == address(0)) revert ZeroAddress();\n // Check if the transaction has already been relayed\n if (bridgeRelays(transactionId)) revert TransactionRelayed();\n if (transaction.destChainId != block.chainid) revert ChainIncorrect();\n // Check the deadline for relay to happen\n if (block.timestamp \u003e transaction.deadline) revert DeadlineExceeded();\n // Check the exclusivity period, if it is still ongoing\n // forgefmt: disable-next-item\n if (\n transaction.exclusivityRelayer != address(0) \u0026\u0026\n transaction.exclusivityRelayer != relayer \u0026\u0026\n block.timestamp \u003c= transaction.exclusivityEndTime\n ) {\n revert ExclusivityPeriodNotPassed();\n }\n }\n}\n","language":"Solidity","languageVersion":"0.8.24","compilerVersion":"0.8.24","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"","srcMapRuntime":"","abiDefinition":[{"inputs":[],"name":"AmountIncorrect","type":"error"},{"inputs":[],"name":"CallParamsLengthAboveMax","type":"error"},{"inputs":[],"name":"ChainIncorrect","type":"error"},{"inputs":[],"name":"DeadlineExceeded","type":"error"},{"inputs":[],"name":"DeadlineNotExceeded","type":"error"},{"inputs":[],"name":"DeadlineTooShort","type":"error"},{"inputs":[],"name":"DisputePeriodNotPassed","type":"error"},{"inputs":[],"name":"DisputePeriodPassed","type":"error"},{"inputs":[],"name":"ExclusivityParamsIncorrect","type":"error"},{"inputs":[],"name":"ExclusivityPeriodNotPassed","type":"error"},{"inputs":[],"name":"MsgValueIncorrect","type":"error"},{"inputs":[],"name":"NativeTokenCallValueNotSupported","type":"error"},{"inputs":[],"name":"RecipientIncorrectReturnValue","type":"error"},{"inputs":[],"name":"RecipientNoReturnValue","type":"error"},{"inputs":[],"name":"SenderIncorrect","type":"error"},{"inputs":[],"name":"StatusIncorrect","type":"error"},{"inputs":[],"name":"TransactionRelayed","type":"error"},{"inputs":[],"name":"ZeroAddress","type":"error"}],"userDoc":{"kind":"user","methods":{},"version":1},"developerDoc":{"kind":"dev","methods":{},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[],\"name\":\"AmountIncorrect\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"CallParamsLengthAboveMax\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ChainIncorrect\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DeadlineExceeded\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DeadlineNotExceeded\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DeadlineTooShort\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DisputePeriodNotPassed\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DisputePeriodPassed\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ExclusivityParamsIncorrect\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ExclusivityPeriodNotPassed\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"MsgValueIncorrect\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"NativeTokenCallValueNotSupported\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"RecipientIncorrectReturnValue\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"RecipientNoReturnValue\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"SenderIncorrect\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"StatusIncorrect\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"TransactionRelayed\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ZeroAddress\",\"type\":\"error\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeV2.sol\":\"IFastBridgeV2Errors\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeV2.sol\":{\"keccak256\":\"0xfd916c030b1ffca5a136817827b8018c8ba42ca089905747f3de6148b73eb35e\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://18e6438c4096deb8ae453fb3365ba2b07d52944e93c08288fc5d012b71bf6bb3\",\"dweb:/ipfs/QmfEMqpT1zz6RRm7UuHLRowe1tds2cTGLrVonfm9XSCACj\"]}},\"version\":1}"},"hashes":{}},"solidity/FastBridgeV2.sol:SafeERC20":{"code":"0x60566037600b82828239805160001a607314602a57634e487b7160e01b600052600060045260246000fd5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600080fdfea2646970667358221220bf9b4d830342bc19a7972f35e2bc28e74742724839e41d049e96167e6d81d6ea64736f6c63430008180033","runtime-code":"0x73000000000000000000000000000000000000000030146080604052600080fdfea2646970667358221220bf9b4d830342bc19a7972f35e2bc28e74742724839e41d049e96167e6d81d6ea64736f6c63430008180033","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.24 ^0.8.0 ^0.8.20;\n\n// contracts/interfaces/IAdmin.sol\n\ninterface IAdmin {\n // ============ Events ============\n\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n event ChainGasAmountUpdated(uint256 oldChainGasAmount, uint256 newChainGasAmount);\n\n // ============ Methods ============\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n\n function setChainGasAmount(uint256 newChainGasAmount) external;\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IFastBridgeRecipient.sol\n\ninterface IFastBridgeRecipient {\n function fastBridgeTransferReceived(\n address token,\n uint256 amount,\n bytes memory callParams\n )\n external\n payable\n returns (bytes4);\n}\n\n// contracts/interfaces/IFastBridgeV2Errors.sol\n\ninterface IFastBridgeV2Errors {\n error AmountIncorrect();\n error CallParamsLengthAboveMax();\n error ChainIncorrect();\n error ExclusivityParamsIncorrect();\n error MsgValueIncorrect();\n error NativeTokenCallValueNotSupported();\n error SenderIncorrect();\n error StatusIncorrect();\n error ZeroAddress();\n\n error RecipientIncorrectReturnValue();\n error RecipientNoReturnValue();\n\n error DeadlineExceeded();\n error DeadlineNotExceeded();\n error DeadlineTooShort();\n error DisputePeriodNotPassed();\n error DisputePeriodPassed();\n error ExclusivityPeriodNotPassed();\n\n error TransactionRelayed();\n}\n\n// contracts/libs/Errors.sol\n\nerror DeadlineExceeded();\nerror DeadlineNotExceeded();\nerror DeadlineTooShort();\nerror InsufficientOutputAmount();\n\nerror MsgValueIncorrect();\nerror PoolNotFound();\nerror TokenAddressMismatch();\nerror TokenNotContract();\nerror TokenNotETH();\nerror TokensIdentical();\n\nerror ChainIncorrect();\nerror AmountIncorrect();\nerror ZeroAddress();\n\nerror DisputePeriodNotPassed();\nerror DisputePeriodPassed();\nerror SenderIncorrect();\nerror StatusIncorrect();\nerror TransactionIdIncorrect();\nerror TransactionRelayed();\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// contracts/interfaces/IFastBridgeV2.sol\n\ninterface IFastBridgeV2 is IFastBridge {\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n struct BridgeTxDetails {\n BridgeStatus status;\n uint40 proofBlockTimestamp;\n uint48 proofBlockNumber;\n address proofRelayer;\n }\n\n struct BridgeRelay {\n uint48 blockNumber;\n uint48 blockTimestamp;\n address relayer;\n }\n\n /// @notice New params introduced in the FastBridgeV2.\n /// We are passing fields from the older BridgeParams struct outside of this struct\n /// for backwards compatibility.\n /// Note: quoteRelayer and quoteExclusivitySeconds are either both zero (indicating no exclusivity)\n /// or both non-zero (indicating exclusivity for the given period).\n /// Note: callValue \u003e 0 can NOT be used with destToken = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE (ETH_ADDRESS)\n /// @param quoteRelayer Relayer that provided the quote for the transaction\n /// @param quoteExclusivitySeconds Period of time the quote relayer is guaranteed exclusivity after user's deposit\n /// @param quoteId Unique quote identifier used for tracking the quote\n /// @param callValue ETH value to send to the recipient (if any)\n /// @param callParams Parameters for the arbitrary call to the destination recipient (if any)\n struct BridgeParamsV2 {\n address quoteRelayer;\n int256 quoteExclusivitySeconds;\n bytes quoteId;\n uint256 callValue;\n bytes callParams;\n }\n\n /// @notice Updated bridge transaction struct to include parameters introduced in FastBridgeV2.\n /// Note: only `exclusivityRelayer` can fill such a transaction until `exclusivityEndTime`.\n /// TODO: consider changing the encoding scheme to prevent spending extra gas on decoding.\n struct BridgeTransactionV2 {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n uint256 callValue; // ETH value to send to the recipient (if any) - replaces V1's sendChainGas flag\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n address exclusivityRelayer;\n uint256 exclusivityEndTime;\n bytes callParams;\n }\n\n event BridgeQuoteDetails(bytes32 indexed transactionId, bytes quoteId);\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability\n /// to provide temporary exclusivity fill rights for the quote relayer.\n /// @param params The parameters required to bridge\n /// @param paramsV2 The parameters for exclusivity fill rights (optional, can be left empty)\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function relay(bytes memory request, address relayer) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param transactionId The transaction id associated with the encoded bridge transaction to prove\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital.\n /// @notice Can only send funds to the relayer address on the proof.\n /// @param request The encoded bridge transaction to claim on origin chain\n function claim(bytes memory request) external;\n /// @notice Checks if a transaction has been relayed\n /// @param transactionId The ID of the transaction to check\n /// @return True if the transaction has been relayed, false otherwise\n function bridgeRelays(bytes32 transactionId) external view returns (bool);\n\n /// @notice Returns the status of a bridge transaction\n /// @param transactionId The ID of the bridge transaction\n /// @return BridgeStatus Status of the bridge transaction\n function bridgeStatuses(bytes32 transactionId) external view returns (BridgeStatus);\n\n /// @notice Returns the timestamp and relayer of a bridge proof\n /// @param transactionId The ID of the bridge transaction\n /// @return timestamp The timestamp of the bridge proof\n /// @return relayer The relayer address of the bridge proof\n function bridgeProofs(bytes32 transactionId) external view returns (uint96 timestamp, address relayer);\n\n /// @notice Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\n /// @param request The bridge request to decode\n function getBridgeTransactionV2(bytes memory request) external view returns (BridgeTransactionV2 memory);\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// contracts/libs/UniversalToken.sol\n\nlibrary UniversalTokenLib {\n using SafeERC20 for IERC20;\n\n address internal constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Transfers tokens to the given account. Reverts if transfer is not successful.\n /// @dev This might trigger fallback, if ETH is transferred to the contract.\n /// Make sure this can not lead to reentrancy attacks.\n function universalTransfer(address token, address to, uint256 value) internal {\n // Don't do anything, if need to send tokens to this address\n if (to == address(this)) return;\n // Don't do anything, if trying to send zero value\n if (value == 0) return;\n if (token == ETH_ADDRESS) {\n /// @dev Note: this can potentially lead to executing code in `to`.\n // solhint-disable-next-line avoid-low-level-calls\n (bool success,) = to.call{value: value}(\"\");\n require(success, \"ETH transfer failed\");\n } else {\n IERC20(token).safeTransfer(to, value);\n }\n }\n\n /// @notice Issues an infinite allowance to the spender, if the current allowance is insufficient\n /// to spend the given amount.\n function universalApproveInfinity(address token, address spender, uint256 amountToSpend) internal {\n // ETH Chad doesn't require your approval\n if (token == ETH_ADDRESS) return;\n // No-op if allowance is already sufficient\n uint256 allowance = IERC20(token).allowance(address(this), spender);\n if (allowance \u003e= amountToSpend) return;\n // Otherwise, reset approval to 0 and set to max allowance\n if (allowance \u003e 0) IERC20(token).safeDecreaseAllowance(spender, allowance);\n IERC20(token).safeIncreaseAllowance(spender, type(uint256).max);\n }\n\n /// @notice Returns the balance of the given token (or native ETH) for the given account.\n function universalBalanceOf(address token, address account) internal view returns (uint256) {\n if (token == ETH_ADDRESS) {\n return account.balance;\n } else {\n return IERC20(token).balanceOf(account);\n }\n }\n\n /// @dev Checks that token is a contract and not ETH_ADDRESS.\n function assertIsContract(address token) internal view {\n // Check that ETH_ADDRESS was not used (in case this is a predeploy on any of the chains)\n if (token == UniversalTokenLib.ETH_ADDRESS) revert TokenNotContract();\n // Check that token is not an EOA\n if (token.code.length == 0) revert TokenNotContract();\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/Admin.sol\n\ncontract Admin is IAdmin, AccessControlEnumerable {\n using UniversalTokenLib for address;\n\n bytes32 public constant RELAYER_ROLE = keccak256(\"RELAYER_ROLE\");\n bytes32 public constant REFUNDER_ROLE = keccak256(\"REFUNDER_ROLE\");\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n uint256 public constant FEE_BPS = 1e6;\n uint256 public constant FEE_RATE_MAX = 0.01e6; // max 1% on origin amount\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Chain gas amount to forward as rebate if requested\n uint256 public chainGasAmount;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n }\n\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n require(newFeeRate \u003c= FEE_RATE_MAX, \"newFeeRate \u003e max\");\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n token.universalTransfer(recipient, feeAmount);\n emit FeesSwept(token, recipient, feeAmount);\n }\n\n function setChainGasAmount(uint256 newChainGasAmount) external onlyRole(GOVERNOR_ROLE) {\n uint256 oldChainGasAmount = chainGasAmount;\n chainGasAmount = newChainGasAmount;\n emit ChainGasAmountUpdated(oldChainGasAmount, newChainGasAmount);\n }\n}\n\n// contracts/FastBridgeV2.sol\n\n/// @notice FastBridgeV2 is a contract for bridging tokens across chains.\ncontract FastBridgeV2 is Admin, IFastBridgeV2, IFastBridgeV2Errors {\n using SafeERC20 for IERC20;\n using UniversalTokenLib for address;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Delay for a transaction after which it could be permisionlessly refunded\n uint256 public constant REFUND_DELAY = 7 days;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n /// @notice Maximum length of accepted callParams\n uint256 public constant MAX_CALL_PARAMS_LENGTH = 2 ** 16 - 1;\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeTxDetails) public bridgeTxDetails;\n /// @notice Relay details on destination chain\n mapping(bytes32 =\u003e BridgeRelay) public bridgeRelayDetails;\n /// @notice Unique bridge nonces tracked per originSender\n mapping(address =\u003e uint256) public senderNonces;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Replaced by senderNonces\n uint256 public immutable nonce = 0;\n /// @notice the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n bridge({\n params: params,\n paramsV2: BridgeParamsV2({\n quoteRelayer: address(0),\n quoteExclusivitySeconds: 0,\n quoteId: bytes(\"\"),\n callValue: 0,\n callParams: bytes(\"\")\n })\n });\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes memory request) external payable {\n relay({request: request, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes memory request, bytes32 destTxHash) external {\n prove({transactionId: keccak256(request), destTxHash: destTxHash, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridgeV2\n function claim(bytes memory request) external {\n claim({request: request, to: address(0)});\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003e DISPUTE_PERIOD) {\n revert DisputePeriodPassed();\n }\n\n // @dev relayer gets slashed effectively if dest relay has gone thru\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n bridgeTxDetails[transactionId].proofRelayer = address(0);\n bridgeTxDetails[transactionId].proofBlockTimestamp = 0;\n bridgeTxDetails[transactionId].proofBlockNumber = 0;\n\n emit BridgeProofDisputed(transactionId, msg.sender);\n }\n\n /// @inheritdoc IFastBridge\n function refund(bytes memory request) external {\n bytes32 transactionId = keccak256(request);\n\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n\n if (bridgeTxDetails[transactionId].status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n\n if (hasRole(REFUNDER_ROLE, msg.sender)) {\n // Refunder can refund if deadline has passed\n if (block.timestamp \u003c= transaction.deadline) revert DeadlineNotExceeded();\n } else {\n // Permissionless refund is allowed after REFUND_DELAY\n if (block.timestamp \u003c= transaction.deadline + REFUND_DELAY) revert DeadlineNotExceeded();\n }\n\n // if all checks passed, set to REFUNDED status\n bridgeTxDetails[transactionId].status = BridgeStatus.REFUNDED;\n\n // transfer origin collateral back to original sender\n address to = transaction.originSender;\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount + transaction.originFeeAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (bridgeTxDetails[transactionId].proofRelayer != relayer) revert SenderIncorrect();\n return _timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n /// @dev This method is added to achieve backwards compatibility with decoding requests into V1 structs:\n /// - `callValue` is partially reported as a zero/non-zero flag\n /// - `callParams` is ignored\n /// In order to process all kinds of requests use getBridgeTransactionV2 instead.\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory) {\n // Try decoding into V2 struct first. This will revert if V1 struct is passed\n try this.getBridgeTransactionV2(request) returns (BridgeTransactionV2 memory txV2) {\n // Note: we entirely ignore the callParams field, as it was not present in V1\n return BridgeTransaction({\n originChainId: txV2.originChainId,\n destChainId: txV2.destChainId,\n originSender: txV2.originSender,\n destRecipient: txV2.destRecipient,\n originToken: txV2.originToken,\n destToken: txV2.destToken,\n originAmount: txV2.originAmount,\n destAmount: txV2.destAmount,\n originFeeAmount: txV2.originFeeAmount,\n sendChainGas: txV2.callValue != 0,\n deadline: txV2.deadline,\n nonce: txV2.nonce\n });\n } catch {\n // Fallback to V1 struct\n return abi.decode(request, (BridgeTransaction));\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) public payable {\n int256 exclusivityEndTime = int256(block.timestamp) + paramsV2.quoteExclusivitySeconds;\n _validateBridgeParams(params, paramsV2, exclusivityEndTime);\n\n // transfer tokens to bridge contract\n /// @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _takeBridgedUserAsset(params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n\n // set status to requested\n bytes memory request = abi.encode(\n BridgeTransactionV2({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n callValue: paramsV2.callValue,\n deadline: params.deadline,\n nonce: senderNonces[params.sender]++, // increment nonce on every bridge\n exclusivityRelayer: paramsV2.quoteRelayer,\n // We checked exclusivityEndTime to be in range (0 .. params.deadline] above, so can safely cast\n exclusivityEndTime: uint256(exclusivityEndTime),\n callParams: paramsV2.callParams\n })\n );\n bytes32 transactionId = keccak256(request);\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n\n emit BridgeRequested({\n transactionId: transactionId,\n sender: params.sender,\n request: request,\n destChainId: params.dstChainId,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n sendChainGas: paramsV2.callValue != 0\n });\n emit BridgeQuoteDetails(transactionId, paramsV2.quoteId);\n }\n\n /// @inheritdoc IFastBridgeV2\n function relay(bytes memory request, address relayer) public payable {\n bytes32 transactionId = keccak256(request);\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n _validateRelayParams(transaction, transactionId, relayer);\n // mark bridge transaction as relayed\n bridgeRelayDetails[transactionId] =\n BridgeRelay({blockNumber: uint48(block.number), blockTimestamp: uint48(block.timestamp), relayer: relayer});\n\n // transfer tokens to recipient on destination chain and do an arbitrary call if requested\n address to = transaction.destRecipient;\n address token = transaction.destToken;\n uint256 amount = transaction.destAmount;\n uint256 callValue = transaction.callValue;\n\n // Emit the event before any external calls\n emit BridgeRelayed({\n transactionId: transactionId,\n relayer: relayer,\n to: to,\n originChainId: transaction.originChainId,\n originToken: transaction.originToken,\n destToken: token,\n originAmount: transaction.originAmount,\n destAmount: amount,\n chainGasAmount: callValue\n });\n\n // All state changes have been done at this point, can proceed to the external calls.\n // This follows the checks-effects-interactions pattern to mitigate potential reentrancy attacks.\n if (token == UniversalTokenLib.ETH_ADDRESS) {\n // For ETH non-zero callValue is not allowed\n if (callValue != 0) revert NativeTokenCallValueNotSupported();\n // Check that the correct msg.value was sent\n if (msg.value != amount) revert MsgValueIncorrect();\n } else {\n // For ERC20s, we check that the correct msg.value was sent\n if (msg.value != callValue) revert MsgValueIncorrect();\n // We need to transfer the tokens from the Relayer to the recipient first before performing an\n // optional post-transfer arbitrary call.\n IERC20(token).safeTransferFrom(msg.sender, to, amount);\n }\n\n if (transaction.callParams.length != 0) {\n // Arbitrary call requested, perform it while supplying full msg.value to the recipient\n // Note: if token has a fee on transfers, the recipient will have received less than `amount`.\n // This is a very niche edge case and should be handled by the recipient contract.\n _checkedCallRecipient({recipient: to, token: token, amount: amount, callParams: transaction.callParams});\n } else if (msg.value != 0) {\n // No arbitrary call requested, but msg.value was sent. This is either a relay with ETH,\n // or a non-zero callValue request with an ERC20. In both cases, transfer the ETH to the recipient.\n Address.sendValue(payable(to), msg.value);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) public onlyRole(RELAYER_ROLE) {\n // update bridge tx status given proof provided\n if (bridgeTxDetails[transactionId].status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n bridgeTxDetails[transactionId].status = BridgeStatus.RELAYER_PROVED;\n bridgeTxDetails[transactionId].proofBlockTimestamp = uint40(block.timestamp);\n bridgeTxDetails[transactionId].proofBlockNumber = uint48(block.number);\n bridgeTxDetails[transactionId].proofRelayer = relayer;\n\n emit BridgeProofProvided(transactionId, relayer, destTxHash);\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes memory request, address to) public {\n bytes32 transactionId = keccak256(request);\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n\n // update bridge tx status if able to claim origin collateral\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n\n // if \"to\" is zero addr, permissionlessly send funds to proven relayer\n if (to == address(0)) {\n to = bridgeTxDetails[transactionId].proofRelayer;\n } else if (bridgeTxDetails[transactionId].proofRelayer != msg.sender) {\n revert SenderIncorrect();\n }\n\n if (_timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003c= DISPUTE_PERIOD) {\n revert DisputePeriodNotPassed();\n }\n\n bridgeTxDetails[transactionId].status = BridgeStatus.RELAYER_CLAIMED;\n\n // update protocol fees if origin fee amount exists\n if (transaction.originFeeAmount \u003e 0) protocolFees[transaction.originToken] += transaction.originFeeAmount;\n\n // transfer origin collateral less fee to specified address\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositClaimed(transactionId, bridgeTxDetails[transactionId].proofRelayer, to, token, amount);\n }\n\n function bridgeStatuses(bytes32 transactionId) public view returns (BridgeStatus status) {\n return bridgeTxDetails[transactionId].status;\n }\n\n function bridgeProofs(bytes32 transactionId) public view returns (uint96 timestamp, address relayer) {\n timestamp = bridgeTxDetails[transactionId].proofBlockTimestamp;\n relayer = bridgeTxDetails[transactionId].proofRelayer;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeRelays(bytes32 transactionId) public view returns (bool) {\n // has this transactionId been relayed?\n return bridgeRelayDetails[transactionId].relayer != address(0);\n }\n\n /// @inheritdoc IFastBridgeV2\n function getBridgeTransactionV2(bytes memory request) public pure returns (BridgeTransactionV2 memory) {\n return abi.decode(request, (BridgeTransactionV2));\n }\n\n /// @notice Takes the bridged asset from the user into FastBridgeV2 custody. It will be later\n /// claimed by the relayer who completed the relay on destination chain, or refunded back to the user,\n /// should no one complete the relay.\n function _takeBridgedUserAsset(address token, uint256 amount) internal returns (uint256 amountTaken) {\n if (token == UniversalTokenLib.ETH_ADDRESS) {\n // For ETH we just need to check that the supplied msg.value is correct.\n // Supplied `msg.value` is already in FastBridgeV2 custody.\n if (amount != msg.value) revert MsgValueIncorrect();\n amountTaken = msg.value;\n } else {\n // For ERC20s, token is explicitly transferred from the user to FastBridgeV2.\n // We don't allow non-zero `msg.value` to avoid extra funds from being stuck in FastBridgeV2.\n token.assertIsContract();\n if (msg.value != 0) revert MsgValueIncorrect();\n amountTaken = IERC20(token).balanceOf(address(this));\n IERC20(token).safeTransferFrom(msg.sender, address(this), amount);\n // Use the balance difference as the amount taken in case of fee on transfer tokens.\n amountTaken = IERC20(token).balanceOf(address(this)) - amountTaken;\n }\n }\n\n /// @notice Calls the Recipient's hook function with the specified callParams and performs\n /// all the necessary checks for the returned value.\n function _checkedCallRecipient(\n address recipient,\n address token,\n uint256 amount,\n bytes memory callParams\n )\n internal\n {\n bytes memory hookData =\n abi.encodeCall(IFastBridgeRecipient.fastBridgeTransferReceived, (token, amount, callParams));\n // This will bubble any revert messages from the hook function\n bytes memory returnData = Address.functionCallWithValue({target: recipient, data: hookData, value: msg.value});\n // Explicit revert if no return data at all\n if (returnData.length == 0) revert RecipientNoReturnValue();\n // Check that exactly a single return value was returned\n if (returnData.length != 32) revert RecipientIncorrectReturnValue();\n // Return value should be abi-encoded hook function selector\n if (bytes32(returnData) != bytes32(IFastBridgeRecipient.fastBridgeTransferReceived.selector)) {\n revert RecipientIncorrectReturnValue();\n }\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint40(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint40).max but\n /// proof.timestamp \u003c type(uint40).max via unchecked statement\n /// @param proofBlockTimestamp The bridge proof block timestamp\n /// @return delta Time delta since proof submitted\n function _timeSince(uint40 proofBlockTimestamp) internal view returns (uint256 delta) {\n unchecked {\n delta = uint40(block.timestamp) - proofBlockTimestamp;\n }\n }\n\n /// @notice Performs all the necessary checks for a bridge to happen.\n /// @dev There's no good way to refactor this function to reduce cyclomatic complexity due to\n /// the number of checks that need to be performed, so we skip the code-complexity rule here.\n // solhint-disable-next-line code-complexity\n function _validateBridgeParams(\n BridgeParams memory params,\n BridgeParamsV2 memory paramsV2,\n int256 exclusivityEndTime\n )\n internal\n view\n {\n // Check V1 (legacy) params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.sender == address(0) || params.to == address(0)) revert ZeroAddress();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n // Check V2 params\n if (paramsV2.callParams.length \u003e MAX_CALL_PARAMS_LENGTH) revert CallParamsLengthAboveMax();\n if (paramsV2.callValue != 0 \u0026\u0026 params.destToken == UniversalTokenLib.ETH_ADDRESS) {\n revert NativeTokenCallValueNotSupported();\n }\n // exclusivityEndTime must be in range (0 .. params.deadline]\n if (exclusivityEndTime \u003c= 0 || exclusivityEndTime \u003e int256(params.deadline)) {\n revert ExclusivityParamsIncorrect();\n }\n }\n\n /// @notice Performs all the necessary checks for a relay to happen.\n function _validateRelayParams(\n BridgeTransactionV2 memory transaction,\n bytes32 transactionId,\n address relayer\n )\n internal\n view\n {\n if (relayer == address(0)) revert ZeroAddress();\n // Check if the transaction has already been relayed\n if (bridgeRelays(transactionId)) revert TransactionRelayed();\n if (transaction.destChainId != block.chainid) revert ChainIncorrect();\n // Check the deadline for relay to happen\n if (block.timestamp \u003e transaction.deadline) revert DeadlineExceeded();\n // Check the exclusivity period, if it is still ongoing\n // forgefmt: disable-next-item\n if (\n transaction.exclusivityRelayer != address(0) \u0026\u0026\n transaction.exclusivityRelayer != relayer \u0026\u0026\n block.timestamp \u003c= transaction.exclusivityEndTime\n ) {\n revert ExclusivityPeriodNotPassed();\n }\n }\n}\n","language":"Solidity","languageVersion":"0.8.24","compilerVersion":"0.8.24","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"45745:5018:0:-:0;;;;;;;;;;;;;;;-1:-1:-1;;;45745:5018:0;;;;;;;;;;;;;;;;;","srcMapRuntime":"45745:5018:0:-:0;;;;;;;;","abiDefinition":[{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"currentAllowance","type":"uint256"},{"internalType":"uint256","name":"requestedDecrease","type":"uint256"}],"name":"SafeERC20FailedDecreaseAllowance","type":"error"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"SafeERC20FailedOperation","type":"error"}],"userDoc":{"kind":"user","methods":{},"version":1},"developerDoc":{"details":"Wrappers around ERC20 operations that throw on failure (when the token contract returns false). Tokens that return no value (and instead revert or throw on failure) are also supported, non-reverting calls are assumed to be successful. To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract, which allows you to call the safe operations as `token.safeTransfer(...)`, etc.","errors":{"SafeERC20FailedDecreaseAllowance(address,uint256,uint256)":[{"details":"Indicates a failed `decreaseAllowance` request."}],"SafeERC20FailedOperation(address)":[{"details":"An operation with an ERC20 token failed."}]},"kind":"dev","methods":{},"title":"SafeERC20","version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"currentAllowance\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"requestedDecrease\",\"type\":\"uint256\"}],\"name\":\"SafeERC20FailedDecreaseAllowance\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"}],\"name\":\"SafeERC20FailedOperation\",\"type\":\"error\"}],\"devdoc\":{\"details\":\"Wrappers around ERC20 operations that throw on failure (when the token contract returns false). Tokens that return no value (and instead revert or throw on failure) are also supported, non-reverting calls are assumed to be successful. To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract, which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\",\"errors\":{\"SafeERC20FailedDecreaseAllowance(address,uint256,uint256)\":[{\"details\":\"Indicates a failed `decreaseAllowance` request.\"}],\"SafeERC20FailedOperation(address)\":[{\"details\":\"An operation with an ERC20 token failed.\"}]},\"kind\":\"dev\",\"methods\":{},\"title\":\"SafeERC20\",\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeV2.sol\":\"SafeERC20\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeV2.sol\":{\"keccak256\":\"0xfd916c030b1ffca5a136817827b8018c8ba42ca089905747f3de6148b73eb35e\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://18e6438c4096deb8ae453fb3365ba2b07d52944e93c08288fc5d012b71bf6bb3\",\"dweb:/ipfs/QmfEMqpT1zz6RRm7UuHLRowe1tds2cTGLrVonfm9XSCACj\"]}},\"version\":1}"},"hashes":{}},"solidity/FastBridgeV2.sol:UniversalTokenLib":{"code":"0x60566037600b82828239805160001a607314602a57634e487b7160e01b600052600060045260246000fd5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600080fdfea264697066735822122030abe7c99e33645ff08fba6fd46ebf752f2157cc4f5e930a35e81633f8aacbb864736f6c63430008180033","runtime-code":"0x73000000000000000000000000000000000000000030146080604052600080fdfea264697066735822122030abe7c99e33645ff08fba6fd46ebf752f2157cc4f5e930a35e81633f8aacbb864736f6c63430008180033","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.24 ^0.8.0 ^0.8.20;\n\n// contracts/interfaces/IAdmin.sol\n\ninterface IAdmin {\n // ============ Events ============\n\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n event ChainGasAmountUpdated(uint256 oldChainGasAmount, uint256 newChainGasAmount);\n\n // ============ Methods ============\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n\n function setChainGasAmount(uint256 newChainGasAmount) external;\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IFastBridgeRecipient.sol\n\ninterface IFastBridgeRecipient {\n function fastBridgeTransferReceived(\n address token,\n uint256 amount,\n bytes memory callParams\n )\n external\n payable\n returns (bytes4);\n}\n\n// contracts/interfaces/IFastBridgeV2Errors.sol\n\ninterface IFastBridgeV2Errors {\n error AmountIncorrect();\n error CallParamsLengthAboveMax();\n error ChainIncorrect();\n error ExclusivityParamsIncorrect();\n error MsgValueIncorrect();\n error NativeTokenCallValueNotSupported();\n error SenderIncorrect();\n error StatusIncorrect();\n error ZeroAddress();\n\n error RecipientIncorrectReturnValue();\n error RecipientNoReturnValue();\n\n error DeadlineExceeded();\n error DeadlineNotExceeded();\n error DeadlineTooShort();\n error DisputePeriodNotPassed();\n error DisputePeriodPassed();\n error ExclusivityPeriodNotPassed();\n\n error TransactionRelayed();\n}\n\n// contracts/libs/Errors.sol\n\nerror DeadlineExceeded();\nerror DeadlineNotExceeded();\nerror DeadlineTooShort();\nerror InsufficientOutputAmount();\n\nerror MsgValueIncorrect();\nerror PoolNotFound();\nerror TokenAddressMismatch();\nerror TokenNotContract();\nerror TokenNotETH();\nerror TokensIdentical();\n\nerror ChainIncorrect();\nerror AmountIncorrect();\nerror ZeroAddress();\n\nerror DisputePeriodNotPassed();\nerror DisputePeriodPassed();\nerror SenderIncorrect();\nerror StatusIncorrect();\nerror TransactionIdIncorrect();\nerror TransactionRelayed();\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// contracts/interfaces/IFastBridgeV2.sol\n\ninterface IFastBridgeV2 is IFastBridge {\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n struct BridgeTxDetails {\n BridgeStatus status;\n uint40 proofBlockTimestamp;\n uint48 proofBlockNumber;\n address proofRelayer;\n }\n\n struct BridgeRelay {\n uint48 blockNumber;\n uint48 blockTimestamp;\n address relayer;\n }\n\n /// @notice New params introduced in the FastBridgeV2.\n /// We are passing fields from the older BridgeParams struct outside of this struct\n /// for backwards compatibility.\n /// Note: quoteRelayer and quoteExclusivitySeconds are either both zero (indicating no exclusivity)\n /// or both non-zero (indicating exclusivity for the given period).\n /// Note: callValue \u003e 0 can NOT be used with destToken = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE (ETH_ADDRESS)\n /// @param quoteRelayer Relayer that provided the quote for the transaction\n /// @param quoteExclusivitySeconds Period of time the quote relayer is guaranteed exclusivity after user's deposit\n /// @param quoteId Unique quote identifier used for tracking the quote\n /// @param callValue ETH value to send to the recipient (if any)\n /// @param callParams Parameters for the arbitrary call to the destination recipient (if any)\n struct BridgeParamsV2 {\n address quoteRelayer;\n int256 quoteExclusivitySeconds;\n bytes quoteId;\n uint256 callValue;\n bytes callParams;\n }\n\n /// @notice Updated bridge transaction struct to include parameters introduced in FastBridgeV2.\n /// Note: only `exclusivityRelayer` can fill such a transaction until `exclusivityEndTime`.\n /// TODO: consider changing the encoding scheme to prevent spending extra gas on decoding.\n struct BridgeTransactionV2 {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n uint256 callValue; // ETH value to send to the recipient (if any) - replaces V1's sendChainGas flag\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n address exclusivityRelayer;\n uint256 exclusivityEndTime;\n bytes callParams;\n }\n\n event BridgeQuoteDetails(bytes32 indexed transactionId, bytes quoteId);\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability\n /// to provide temporary exclusivity fill rights for the quote relayer.\n /// @param params The parameters required to bridge\n /// @param paramsV2 The parameters for exclusivity fill rights (optional, can be left empty)\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function relay(bytes memory request, address relayer) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param transactionId The transaction id associated with the encoded bridge transaction to prove\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital.\n /// @notice Can only send funds to the relayer address on the proof.\n /// @param request The encoded bridge transaction to claim on origin chain\n function claim(bytes memory request) external;\n /// @notice Checks if a transaction has been relayed\n /// @param transactionId The ID of the transaction to check\n /// @return True if the transaction has been relayed, false otherwise\n function bridgeRelays(bytes32 transactionId) external view returns (bool);\n\n /// @notice Returns the status of a bridge transaction\n /// @param transactionId The ID of the bridge transaction\n /// @return BridgeStatus Status of the bridge transaction\n function bridgeStatuses(bytes32 transactionId) external view returns (BridgeStatus);\n\n /// @notice Returns the timestamp and relayer of a bridge proof\n /// @param transactionId The ID of the bridge transaction\n /// @return timestamp The timestamp of the bridge proof\n /// @return relayer The relayer address of the bridge proof\n function bridgeProofs(bytes32 transactionId) external view returns (uint96 timestamp, address relayer);\n\n /// @notice Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\n /// @param request The bridge request to decode\n function getBridgeTransactionV2(bytes memory request) external view returns (BridgeTransactionV2 memory);\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// contracts/libs/UniversalToken.sol\n\nlibrary UniversalTokenLib {\n using SafeERC20 for IERC20;\n\n address internal constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Transfers tokens to the given account. Reverts if transfer is not successful.\n /// @dev This might trigger fallback, if ETH is transferred to the contract.\n /// Make sure this can not lead to reentrancy attacks.\n function universalTransfer(address token, address to, uint256 value) internal {\n // Don't do anything, if need to send tokens to this address\n if (to == address(this)) return;\n // Don't do anything, if trying to send zero value\n if (value == 0) return;\n if (token == ETH_ADDRESS) {\n /// @dev Note: this can potentially lead to executing code in `to`.\n // solhint-disable-next-line avoid-low-level-calls\n (bool success,) = to.call{value: value}(\"\");\n require(success, \"ETH transfer failed\");\n } else {\n IERC20(token).safeTransfer(to, value);\n }\n }\n\n /// @notice Issues an infinite allowance to the spender, if the current allowance is insufficient\n /// to spend the given amount.\n function universalApproveInfinity(address token, address spender, uint256 amountToSpend) internal {\n // ETH Chad doesn't require your approval\n if (token == ETH_ADDRESS) return;\n // No-op if allowance is already sufficient\n uint256 allowance = IERC20(token).allowance(address(this), spender);\n if (allowance \u003e= amountToSpend) return;\n // Otherwise, reset approval to 0 and set to max allowance\n if (allowance \u003e 0) IERC20(token).safeDecreaseAllowance(spender, allowance);\n IERC20(token).safeIncreaseAllowance(spender, type(uint256).max);\n }\n\n /// @notice Returns the balance of the given token (or native ETH) for the given account.\n function universalBalanceOf(address token, address account) internal view returns (uint256) {\n if (token == ETH_ADDRESS) {\n return account.balance;\n } else {\n return IERC20(token).balanceOf(account);\n }\n }\n\n /// @dev Checks that token is a contract and not ETH_ADDRESS.\n function assertIsContract(address token) internal view {\n // Check that ETH_ADDRESS was not used (in case this is a predeploy on any of the chains)\n if (token == UniversalTokenLib.ETH_ADDRESS) revert TokenNotContract();\n // Check that token is not an EOA\n if (token.code.length == 0) revert TokenNotContract();\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/Admin.sol\n\ncontract Admin is IAdmin, AccessControlEnumerable {\n using UniversalTokenLib for address;\n\n bytes32 public constant RELAYER_ROLE = keccak256(\"RELAYER_ROLE\");\n bytes32 public constant REFUNDER_ROLE = keccak256(\"REFUNDER_ROLE\");\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n uint256 public constant FEE_BPS = 1e6;\n uint256 public constant FEE_RATE_MAX = 0.01e6; // max 1% on origin amount\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Chain gas amount to forward as rebate if requested\n uint256 public chainGasAmount;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n }\n\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n require(newFeeRate \u003c= FEE_RATE_MAX, \"newFeeRate \u003e max\");\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n token.universalTransfer(recipient, feeAmount);\n emit FeesSwept(token, recipient, feeAmount);\n }\n\n function setChainGasAmount(uint256 newChainGasAmount) external onlyRole(GOVERNOR_ROLE) {\n uint256 oldChainGasAmount = chainGasAmount;\n chainGasAmount = newChainGasAmount;\n emit ChainGasAmountUpdated(oldChainGasAmount, newChainGasAmount);\n }\n}\n\n// contracts/FastBridgeV2.sol\n\n/// @notice FastBridgeV2 is a contract for bridging tokens across chains.\ncontract FastBridgeV2 is Admin, IFastBridgeV2, IFastBridgeV2Errors {\n using SafeERC20 for IERC20;\n using UniversalTokenLib for address;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Delay for a transaction after which it could be permisionlessly refunded\n uint256 public constant REFUND_DELAY = 7 days;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n /// @notice Maximum length of accepted callParams\n uint256 public constant MAX_CALL_PARAMS_LENGTH = 2 ** 16 - 1;\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeTxDetails) public bridgeTxDetails;\n /// @notice Relay details on destination chain\n mapping(bytes32 =\u003e BridgeRelay) public bridgeRelayDetails;\n /// @notice Unique bridge nonces tracked per originSender\n mapping(address =\u003e uint256) public senderNonces;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Replaced by senderNonces\n uint256 public immutable nonce = 0;\n /// @notice the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n bridge({\n params: params,\n paramsV2: BridgeParamsV2({\n quoteRelayer: address(0),\n quoteExclusivitySeconds: 0,\n quoteId: bytes(\"\"),\n callValue: 0,\n callParams: bytes(\"\")\n })\n });\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes memory request) external payable {\n relay({request: request, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes memory request, bytes32 destTxHash) external {\n prove({transactionId: keccak256(request), destTxHash: destTxHash, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridgeV2\n function claim(bytes memory request) external {\n claim({request: request, to: address(0)});\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003e DISPUTE_PERIOD) {\n revert DisputePeriodPassed();\n }\n\n // @dev relayer gets slashed effectively if dest relay has gone thru\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n bridgeTxDetails[transactionId].proofRelayer = address(0);\n bridgeTxDetails[transactionId].proofBlockTimestamp = 0;\n bridgeTxDetails[transactionId].proofBlockNumber = 0;\n\n emit BridgeProofDisputed(transactionId, msg.sender);\n }\n\n /// @inheritdoc IFastBridge\n function refund(bytes memory request) external {\n bytes32 transactionId = keccak256(request);\n\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n\n if (bridgeTxDetails[transactionId].status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n\n if (hasRole(REFUNDER_ROLE, msg.sender)) {\n // Refunder can refund if deadline has passed\n if (block.timestamp \u003c= transaction.deadline) revert DeadlineNotExceeded();\n } else {\n // Permissionless refund is allowed after REFUND_DELAY\n if (block.timestamp \u003c= transaction.deadline + REFUND_DELAY) revert DeadlineNotExceeded();\n }\n\n // if all checks passed, set to REFUNDED status\n bridgeTxDetails[transactionId].status = BridgeStatus.REFUNDED;\n\n // transfer origin collateral back to original sender\n address to = transaction.originSender;\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount + transaction.originFeeAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (bridgeTxDetails[transactionId].proofRelayer != relayer) revert SenderIncorrect();\n return _timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n /// @dev This method is added to achieve backwards compatibility with decoding requests into V1 structs:\n /// - `callValue` is partially reported as a zero/non-zero flag\n /// - `callParams` is ignored\n /// In order to process all kinds of requests use getBridgeTransactionV2 instead.\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory) {\n // Try decoding into V2 struct first. This will revert if V1 struct is passed\n try this.getBridgeTransactionV2(request) returns (BridgeTransactionV2 memory txV2) {\n // Note: we entirely ignore the callParams field, as it was not present in V1\n return BridgeTransaction({\n originChainId: txV2.originChainId,\n destChainId: txV2.destChainId,\n originSender: txV2.originSender,\n destRecipient: txV2.destRecipient,\n originToken: txV2.originToken,\n destToken: txV2.destToken,\n originAmount: txV2.originAmount,\n destAmount: txV2.destAmount,\n originFeeAmount: txV2.originFeeAmount,\n sendChainGas: txV2.callValue != 0,\n deadline: txV2.deadline,\n nonce: txV2.nonce\n });\n } catch {\n // Fallback to V1 struct\n return abi.decode(request, (BridgeTransaction));\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) public payable {\n int256 exclusivityEndTime = int256(block.timestamp) + paramsV2.quoteExclusivitySeconds;\n _validateBridgeParams(params, paramsV2, exclusivityEndTime);\n\n // transfer tokens to bridge contract\n /// @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _takeBridgedUserAsset(params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n\n // set status to requested\n bytes memory request = abi.encode(\n BridgeTransactionV2({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n callValue: paramsV2.callValue,\n deadline: params.deadline,\n nonce: senderNonces[params.sender]++, // increment nonce on every bridge\n exclusivityRelayer: paramsV2.quoteRelayer,\n // We checked exclusivityEndTime to be in range (0 .. params.deadline] above, so can safely cast\n exclusivityEndTime: uint256(exclusivityEndTime),\n callParams: paramsV2.callParams\n })\n );\n bytes32 transactionId = keccak256(request);\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n\n emit BridgeRequested({\n transactionId: transactionId,\n sender: params.sender,\n request: request,\n destChainId: params.dstChainId,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n sendChainGas: paramsV2.callValue != 0\n });\n emit BridgeQuoteDetails(transactionId, paramsV2.quoteId);\n }\n\n /// @inheritdoc IFastBridgeV2\n function relay(bytes memory request, address relayer) public payable {\n bytes32 transactionId = keccak256(request);\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n _validateRelayParams(transaction, transactionId, relayer);\n // mark bridge transaction as relayed\n bridgeRelayDetails[transactionId] =\n BridgeRelay({blockNumber: uint48(block.number), blockTimestamp: uint48(block.timestamp), relayer: relayer});\n\n // transfer tokens to recipient on destination chain and do an arbitrary call if requested\n address to = transaction.destRecipient;\n address token = transaction.destToken;\n uint256 amount = transaction.destAmount;\n uint256 callValue = transaction.callValue;\n\n // Emit the event before any external calls\n emit BridgeRelayed({\n transactionId: transactionId,\n relayer: relayer,\n to: to,\n originChainId: transaction.originChainId,\n originToken: transaction.originToken,\n destToken: token,\n originAmount: transaction.originAmount,\n destAmount: amount,\n chainGasAmount: callValue\n });\n\n // All state changes have been done at this point, can proceed to the external calls.\n // This follows the checks-effects-interactions pattern to mitigate potential reentrancy attacks.\n if (token == UniversalTokenLib.ETH_ADDRESS) {\n // For ETH non-zero callValue is not allowed\n if (callValue != 0) revert NativeTokenCallValueNotSupported();\n // Check that the correct msg.value was sent\n if (msg.value != amount) revert MsgValueIncorrect();\n } else {\n // For ERC20s, we check that the correct msg.value was sent\n if (msg.value != callValue) revert MsgValueIncorrect();\n // We need to transfer the tokens from the Relayer to the recipient first before performing an\n // optional post-transfer arbitrary call.\n IERC20(token).safeTransferFrom(msg.sender, to, amount);\n }\n\n if (transaction.callParams.length != 0) {\n // Arbitrary call requested, perform it while supplying full msg.value to the recipient\n // Note: if token has a fee on transfers, the recipient will have received less than `amount`.\n // This is a very niche edge case and should be handled by the recipient contract.\n _checkedCallRecipient({recipient: to, token: token, amount: amount, callParams: transaction.callParams});\n } else if (msg.value != 0) {\n // No arbitrary call requested, but msg.value was sent. This is either a relay with ETH,\n // or a non-zero callValue request with an ERC20. In both cases, transfer the ETH to the recipient.\n Address.sendValue(payable(to), msg.value);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) public onlyRole(RELAYER_ROLE) {\n // update bridge tx status given proof provided\n if (bridgeTxDetails[transactionId].status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n bridgeTxDetails[transactionId].status = BridgeStatus.RELAYER_PROVED;\n bridgeTxDetails[transactionId].proofBlockTimestamp = uint40(block.timestamp);\n bridgeTxDetails[transactionId].proofBlockNumber = uint48(block.number);\n bridgeTxDetails[transactionId].proofRelayer = relayer;\n\n emit BridgeProofProvided(transactionId, relayer, destTxHash);\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes memory request, address to) public {\n bytes32 transactionId = keccak256(request);\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n\n // update bridge tx status if able to claim origin collateral\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n\n // if \"to\" is zero addr, permissionlessly send funds to proven relayer\n if (to == address(0)) {\n to = bridgeTxDetails[transactionId].proofRelayer;\n } else if (bridgeTxDetails[transactionId].proofRelayer != msg.sender) {\n revert SenderIncorrect();\n }\n\n if (_timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003c= DISPUTE_PERIOD) {\n revert DisputePeriodNotPassed();\n }\n\n bridgeTxDetails[transactionId].status = BridgeStatus.RELAYER_CLAIMED;\n\n // update protocol fees if origin fee amount exists\n if (transaction.originFeeAmount \u003e 0) protocolFees[transaction.originToken] += transaction.originFeeAmount;\n\n // transfer origin collateral less fee to specified address\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositClaimed(transactionId, bridgeTxDetails[transactionId].proofRelayer, to, token, amount);\n }\n\n function bridgeStatuses(bytes32 transactionId) public view returns (BridgeStatus status) {\n return bridgeTxDetails[transactionId].status;\n }\n\n function bridgeProofs(bytes32 transactionId) public view returns (uint96 timestamp, address relayer) {\n timestamp = bridgeTxDetails[transactionId].proofBlockTimestamp;\n relayer = bridgeTxDetails[transactionId].proofRelayer;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeRelays(bytes32 transactionId) public view returns (bool) {\n // has this transactionId been relayed?\n return bridgeRelayDetails[transactionId].relayer != address(0);\n }\n\n /// @inheritdoc IFastBridgeV2\n function getBridgeTransactionV2(bytes memory request) public pure returns (BridgeTransactionV2 memory) {\n return abi.decode(request, (BridgeTransactionV2));\n }\n\n /// @notice Takes the bridged asset from the user into FastBridgeV2 custody. It will be later\n /// claimed by the relayer who completed the relay on destination chain, or refunded back to the user,\n /// should no one complete the relay.\n function _takeBridgedUserAsset(address token, uint256 amount) internal returns (uint256 amountTaken) {\n if (token == UniversalTokenLib.ETH_ADDRESS) {\n // For ETH we just need to check that the supplied msg.value is correct.\n // Supplied `msg.value` is already in FastBridgeV2 custody.\n if (amount != msg.value) revert MsgValueIncorrect();\n amountTaken = msg.value;\n } else {\n // For ERC20s, token is explicitly transferred from the user to FastBridgeV2.\n // We don't allow non-zero `msg.value` to avoid extra funds from being stuck in FastBridgeV2.\n token.assertIsContract();\n if (msg.value != 0) revert MsgValueIncorrect();\n amountTaken = IERC20(token).balanceOf(address(this));\n IERC20(token).safeTransferFrom(msg.sender, address(this), amount);\n // Use the balance difference as the amount taken in case of fee on transfer tokens.\n amountTaken = IERC20(token).balanceOf(address(this)) - amountTaken;\n }\n }\n\n /// @notice Calls the Recipient's hook function with the specified callParams and performs\n /// all the necessary checks for the returned value.\n function _checkedCallRecipient(\n address recipient,\n address token,\n uint256 amount,\n bytes memory callParams\n )\n internal\n {\n bytes memory hookData =\n abi.encodeCall(IFastBridgeRecipient.fastBridgeTransferReceived, (token, amount, callParams));\n // This will bubble any revert messages from the hook function\n bytes memory returnData = Address.functionCallWithValue({target: recipient, data: hookData, value: msg.value});\n // Explicit revert if no return data at all\n if (returnData.length == 0) revert RecipientNoReturnValue();\n // Check that exactly a single return value was returned\n if (returnData.length != 32) revert RecipientIncorrectReturnValue();\n // Return value should be abi-encoded hook function selector\n if (bytes32(returnData) != bytes32(IFastBridgeRecipient.fastBridgeTransferReceived.selector)) {\n revert RecipientIncorrectReturnValue();\n }\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint40(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint40).max but\n /// proof.timestamp \u003c type(uint40).max via unchecked statement\n /// @param proofBlockTimestamp The bridge proof block timestamp\n /// @return delta Time delta since proof submitted\n function _timeSince(uint40 proofBlockTimestamp) internal view returns (uint256 delta) {\n unchecked {\n delta = uint40(block.timestamp) - proofBlockTimestamp;\n }\n }\n\n /// @notice Performs all the necessary checks for a bridge to happen.\n /// @dev There's no good way to refactor this function to reduce cyclomatic complexity due to\n /// the number of checks that need to be performed, so we skip the code-complexity rule here.\n // solhint-disable-next-line code-complexity\n function _validateBridgeParams(\n BridgeParams memory params,\n BridgeParamsV2 memory paramsV2,\n int256 exclusivityEndTime\n )\n internal\n view\n {\n // Check V1 (legacy) params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.sender == address(0) || params.to == address(0)) revert ZeroAddress();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n // Check V2 params\n if (paramsV2.callParams.length \u003e MAX_CALL_PARAMS_LENGTH) revert CallParamsLengthAboveMax();\n if (paramsV2.callValue != 0 \u0026\u0026 params.destToken == UniversalTokenLib.ETH_ADDRESS) {\n revert NativeTokenCallValueNotSupported();\n }\n // exclusivityEndTime must be in range (0 .. params.deadline]\n if (exclusivityEndTime \u003c= 0 || exclusivityEndTime \u003e int256(params.deadline)) {\n revert ExclusivityParamsIncorrect();\n }\n }\n\n /// @notice Performs all the necessary checks for a relay to happen.\n function _validateRelayParams(\n BridgeTransactionV2 memory transaction,\n bytes32 transactionId,\n address relayer\n )\n internal\n view\n {\n if (relayer == address(0)) revert ZeroAddress();\n // Check if the transaction has already been relayed\n if (bridgeRelays(transactionId)) revert TransactionRelayed();\n if (transaction.destChainId != block.chainid) revert ChainIncorrect();\n // Check the deadline for relay to happen\n if (block.timestamp \u003e transaction.deadline) revert DeadlineExceeded();\n // Check the exclusivity period, if it is still ongoing\n // forgefmt: disable-next-item\n if (\n transaction.exclusivityRelayer != address(0) \u0026\u0026\n transaction.exclusivityRelayer != relayer \u0026\u0026\n block.timestamp \u003c= transaction.exclusivityEndTime\n ) {\n revert ExclusivityPeriodNotPassed();\n }\n }\n}\n","language":"Solidity","languageVersion":"0.8.24","compilerVersion":"0.8.24","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"57704:2551:0:-:0;;;;;;;;;;;;;;;-1:-1:-1;;;57704:2551:0;;;;;;;;;;;;;;;;;","srcMapRuntime":"57704:2551:0:-:0;;;;;;;;","abiDefinition":[],"userDoc":{"kind":"user","methods":{},"version":1},"developerDoc":{"kind":"dev","methods":{},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[],\"devdoc\":{\"kind\":\"dev\",\"methods\":{},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeV2.sol\":\"UniversalTokenLib\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeV2.sol\":{\"keccak256\":\"0xfd916c030b1ffca5a136817827b8018c8ba42ca089905747f3de6148b73eb35e\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://18e6438c4096deb8ae453fb3365ba2b07d52944e93c08288fc5d012b71bf6bb3\",\"dweb:/ipfs/QmfEMqpT1zz6RRm7UuHLRowe1tds2cTGLrVonfm9XSCACj\"]}},\"version\":1}"},"hashes":{}}} \ No newline at end of file From f44c7ae8cb07edf872b195905055f3c77fc9a477 Mon Sep 17 00:00:00 2001 From: Daniel Wasserman Date: Wed, 16 Oct 2024 12:13:04 -0500 Subject: [PATCH 44/85] Fix: use native token decimals for CallValue --- services/rfq/relayer/reldb/base/model.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/services/rfq/relayer/reldb/base/model.go b/services/rfq/relayer/reldb/base/model.go index 52e95bab08..3c4bd7d322 100644 --- a/services/rfq/relayer/reldb/base/model.go +++ b/services/rfq/relayer/reldb/base/model.go @@ -146,9 +146,9 @@ func FromQuoteRequest(request reldb.QuoteRequest) RequestForQuote { OriginAmountOriginal: request.Transaction.OriginAmount.String(), OriginAmount: decimal.NewFromBigInt(request.Transaction.OriginAmount, int32(request.OriginTokenDecimals)), DestAmountOriginal: request.Transaction.DestAmount.String(), - DestAmount: decimal.NewFromBigInt(request.Transaction.DestAmount, int32(nativeTokenDecimals)), + DestAmount: decimal.NewFromBigInt(request.Transaction.DestAmount, int32(request.DestTokenDecimals)), OriginFeeAmount: decimal.NewFromBigInt(request.Transaction.OriginFeeAmount, int32(request.OriginTokenDecimals)), - CallValue: decimal.NewFromBigInt(request.Transaction.CallValue, int32(request.OriginTokenDecimals)), + CallValue: decimal.NewFromBigInt(request.Transaction.CallValue, int32(nativeTokenDecimals)), CallParams: request.Transaction.CallParams, Deadline: time.Unix(int64(request.Transaction.Deadline.Uint64()), 0), OriginNonce: int(request.Transaction.Nonce.Uint64()), From 978313d0838f58ac92dde48563e0cf0bf761e478 Mon Sep 17 00:00:00 2001 From: Daniel Wasserman Date: Thu, 24 Oct 2024 17:00:13 -0700 Subject: [PATCH 45/85] Feat: relayer uses v2 for relay() / prove() --- services/rfq/relayer/chain/chain.go | 8 ++++---- services/rfq/relayer/service/handlers.go | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/services/rfq/relayer/chain/chain.go b/services/rfq/relayer/chain/chain.go index 99e72ec180..f11e43a314 100644 --- a/services/rfq/relayer/chain/chain.go +++ b/services/rfq/relayer/chain/chain.go @@ -12,7 +12,7 @@ import ( "github.com/synapsecns/sanguine/ethergo/client" "github.com/synapsecns/sanguine/ethergo/listener" "github.com/synapsecns/sanguine/ethergo/submitter" - "github.com/synapsecns/sanguine/services/rfq/contracts/fastbridge" + "github.com/synapsecns/sanguine/services/rfq/contracts/fastbridgev2" "github.com/synapsecns/sanguine/services/rfq/relayer/relconfig" "github.com/synapsecns/sanguine/services/rfq/relayer/reldb" "github.com/synapsecns/sanguine/services/rfq/util" @@ -23,7 +23,7 @@ import ( // the plan is to move this out of relayer which is when this distinction will matter. type Chain struct { ChainID uint32 - Bridge *fastbridge.FastBridgeRef + Bridge *fastbridgev2.FastBridgeV2Ref Client client.EVM Confirmations uint64 listener listener.ContractListener @@ -40,7 +40,7 @@ func NewChain(ctx context.Context, cfg relconfig.Config, chainClient client.EVM, if err != nil { return nil, fmt.Errorf("could not get rfq address: %w", err) } - bridge, err := fastbridge.NewFastBridgeRef(addr, chainClient) + bridge, err := fastbridgev2.NewFastBridgeV2Ref(addr, chainClient) if err != nil { return nil, fmt.Errorf("could not create bridge contract: %w", err) } @@ -89,7 +89,7 @@ func (c Chain) SubmitRelay(ctx context.Context, request reldb.QuoteRequest) (uin nonce, err := c.SubmitTransaction(ctx, func(transactor *bind.TransactOpts) (tx *types.Transaction, err error) { transactor.Value = core.CopyBigInt(gasAmount) - tx, err = c.Bridge.Relay(transactor, request.RawRequest) + tx, err = c.Bridge.Relay0(transactor, request.RawRequest, c.submitter.Address()) if err != nil { return nil, fmt.Errorf("could not relay: %w", err) } diff --git a/services/rfq/relayer/service/handlers.go b/services/rfq/relayer/service/handlers.go index 48493229ce..582194245f 100644 --- a/services/rfq/relayer/service/handlers.go +++ b/services/rfq/relayer/service/handlers.go @@ -472,7 +472,7 @@ func (q *QuoteRequestHandler) handleRelayCompleted(ctx context.Context, span tra // relay has been finalized, it's time to go back to the origin chain and try to prove _, err = q.Origin.SubmitTransaction(ctx, func(transactor *bind.TransactOpts) (tx *types.Transaction, err error) { - tx, err = q.Origin.Bridge.Prove(transactor, request.RawRequest, request.DestTxHash) + tx, err = q.Origin.Bridge.Prove0(transactor, request.RawRequest, request.DestTxHash) if err != nil { return nil, fmt.Errorf("could not relay: %w", err) } From 23d4a7aa2706e8280a32a17faab645fbec55df15 Mon Sep 17 00:00:00 2001 From: dwasse Date: Thu, 14 Nov 2024 13:14:41 -0600 Subject: [PATCH 46/85] feat(rfq-relayer): regenerate with updated fastbridgev2 and zap terminology [SLT-442] (#3394) * Feat: regen fastbridgev2 * WIP: changes for new fastbridgev2 bindings * Feat: regenerate test contracts * Cleanup: remove logs * Fix: build --- .../fastbridgev2/fastbridgev2.abigen.go | 1097 +++++++++++++---- .../fastbridgev2.contractinfo.json | 2 +- .../fastbridgemockv2.abigen.go | 746 +++++++++-- .../fastbridgemockv2.contractinfo.json | 2 +- .../recipientmock/recipientmock.abigen.go | 224 ++-- .../recipientmock.contractinfo.json | 2 +- services/rfq/e2e/rfq_test.go | 6 +- services/rfq/relayer/chain/chain.go | 4 +- services/rfq/relayer/relapi/server_test.go | 4 +- services/rfq/relayer/reldb/base/model.go | 16 +- services/rfq/relayer/reldb/base/model_test.go | 4 +- 11 files changed, 1646 insertions(+), 461 deletions(-) diff --git a/services/rfq/contracts/fastbridgev2/fastbridgev2.abigen.go b/services/rfq/contracts/fastbridgev2/fastbridgev2.abigen.go index a6518eff27..10b4a12eb5 100644 --- a/services/rfq/contracts/fastbridgev2/fastbridgev2.abigen.go +++ b/services/rfq/contracts/fastbridgev2/fastbridgev2.abigen.go @@ -63,8 +63,8 @@ type IFastBridgeV2BridgeParamsV2 struct { QuoteRelayer common.Address QuoteExclusivitySeconds *big.Int QuoteId []byte - CallValue *big.Int - CallParams []byte + ZapNative *big.Int + ZapData []byte } // IFastBridgeV2BridgeTransactionV2 is an auto generated low-level Go binding around an user-defined struct. @@ -78,12 +78,18 @@ type IFastBridgeV2BridgeTransactionV2 struct { OriginAmount *big.Int DestAmount *big.Int OriginFeeAmount *big.Int - CallValue *big.Int Deadline *big.Int Nonce *big.Int ExclusivityRelayer common.Address ExclusivityEndTime *big.Int - CallParams []byte + ZapNative *big.Int + ZapData []byte +} + +// IMulticallTargetResult is an auto generated low-level Go binding around an user-defined struct. +type IMulticallTargetResult struct { + Success bool + ReturnData []byte } // AccessControlMetaData contains all meta data concerning the AccessControl contract. @@ -1827,7 +1833,7 @@ func (_AccessControlEnumerable *AccessControlEnumerableFilterer) ParseRoleRevoke // AddressMetaData contains all meta data concerning the Address contract. var AddressMetaData = &bind.MetaData{ ABI: "[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"}],\"name\":\"AddressEmptyCode\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"AddressInsufficientBalance\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"FailedInnerCall\",\"type\":\"error\"}]", - Bin: "0x60566037600b82828239805160001a607314602a57634e487b7160e01b600052600060045260246000fd5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600080fdfea2646970667358221220ac16750f49f1b9ced08b049feacc7b593708109660ad4859d5e0cc87a7718b8d64736f6c63430008180033", + Bin: "0x60566037600b82828239805160001a607314602a57634e487b7160e01b600052600060045260246000fd5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600080fdfea2646970667358221220bf1b9d7d74d58f093eea1b088fdbcad7f67374661fae1ab5815d7a31130f2fb864736f6c63430008180033", } // AddressABI is the input ABI used to generate the binding from. @@ -2023,7 +2029,7 @@ var AdminMetaData = &bind.MetaData{ "01ffc9a7": "supportsInterface(bytes4)", "06f333f2": "sweepProtocolFees(address,address)", }, - Bin: "0x60806040523480156200001157600080fd5b50604051620014123803806200141283398101604081905262000034916200018e565b6200004160008262000049565b5050620001b9565b60008062000058848462000086565b905080156200007d5760008481526001602052604090206200007b908462000134565b505b90505b92915050565b6000828152602081815260408083206001600160a01b038516845290915281205460ff166200012b576000838152602081815260408083206001600160a01b03861684529091529020805460ff19166001179055620000e23390565b6001600160a01b0316826001600160a01b0316847f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a450600162000080565b50600062000080565b60006200007d836001600160a01b03841660008181526001830160205260408120546200012b5750815460018181018455600084815260208082209093018490558454848252828601909352604090209190915562000080565b600060208284031215620001a157600080fd5b81516001600160a01b03811681146200007d57600080fd5b61124980620001c96000396000f3fe608060405234801561001057600080fd5b50600436106101775760003560e01c806391d14854116100d8578063bf333f2c1161008c578063d547741f11610066578063d547741f14610385578063dcf844a714610398578063e00a83e0146103b857600080fd5b8063bf333f2c14610341578063ca15c8731461034b578063ccc574901461035e57600080fd5b8063a217fddf116100bd578063a217fddf14610313578063b13aa2d61461031b578063b250fe6b1461032e57600080fd5b806391d14854146102a8578063926d7d7f146102ec57600080fd5b80632f2ff15d1161012f57806358f858801161011457806358f85880146102405780635960ccf2146102495780639010d07c1461027057600080fd5b80632f2ff15d1461021a57806336568abe1461022d57600080fd5b806306f333f21161016057806306f333f2146101d95780630f5f6ed7146101ee578063248a9ca3146101f757600080fd5b806301ffc9a71461017c57806303ed0ee5146101a4575b600080fd5b61018f61018a366004611013565b6103c1565b60405190151581526020015b60405180910390f35b6101cb7f043c983c49d46f0e102151eaf8085d4a2e6571d5df2d47b013f39bddfd4a639d81565b60405190815260200161019b565b6101ec6101e736600461107e565b61041d565b005b6101cb61271081565b6101cb6102053660046110b1565b60009081526020819052604090206001015490565b6101ec6102283660046110ca565b61050b565b6101ec61023b3660046110ca565b610536565b6101cb60025481565b6101cb7fdb9556138406326f00296e13ea2ad7db24ba82381212d816b1a40c23b466b32781565b61028361027e3660046110ed565b61058f565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200161019b565b61018f6102b63660046110ca565b60009182526020828152604080842073ffffffffffffffffffffffffffffffffffffffff93909316845291905290205460ff1690565b6101cb7fe2b7fb3b832174769106daebcfd6d1970523240dda11281102db9363b83b0dc481565b6101cb600081565b6101ec6103293660046110b1565b6105ae565b6101ec61033c3660046110b1565b610690565b6101cb620f424081565b6101cb6103593660046110b1565b6106f8565b6101cb7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f5581565b6101ec6103933660046110ca565b61070f565b6101cb6103a636600461110f565b60036020526000908152604090205481565b6101cb60045481565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f5a05180f000000000000000000000000000000000000000000000000000000001480610417575061041782610734565b92915050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f55610447816107cb565b73ffffffffffffffffffffffffffffffffffffffff83166000908152600360205260408120549081900361047b5750505050565b73ffffffffffffffffffffffffffffffffffffffff84166000818152600360205260408120556104ac9084836107d8565b6040805173ffffffffffffffffffffffffffffffffffffffff8087168252851660208201529081018290527f244e51bc38c1452fa8aaf487bcb4bca36c2baa3a5fbdb776b1eabd8dc6d277cd9060600160405180910390a1505b505050565b600082815260208190526040902060010154610526816107cb565b610530838361092f565b50505050565b73ffffffffffffffffffffffffffffffffffffffff81163314610585576040517f6697b23200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6105068282610964565b60008281526001602052604081206105a79083610991565b9392505050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f556105d8816107cb565b612710821115610649576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f6e657746656552617465203e206d61780000000000000000000000000000000060448201526064015b60405180910390fd5b600280549083905560408051828152602081018590527f14914da2bf76024616fbe1859783fcd4dbddcb179b1f3a854949fbf920dcb95791015b60405180910390a1505050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f556106ba816107cb565b600480549083905560408051828152602081018590527f5cf09b12f3f56b4c564d51b25b40360af6d795198adb61ae0806a36c294323fa9101610683565b60008181526001602052604081206104179061099d565b60008281526020819052604090206001015461072a816107cb565b6105308383610964565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f7965db0b00000000000000000000000000000000000000000000000000000000148061041757507f01ffc9a7000000000000000000000000000000000000000000000000000000007fffffffff00000000000000000000000000000000000000000000000000000000831614610417565b6107d581336109a7565b50565b3073ffffffffffffffffffffffffffffffffffffffff8316036107fa57505050565b8060000361080757505050565b7fffffffffffffffffffffffff111111111111111111111111111111111111111273ffffffffffffffffffffffffffffffffffffffff84160161090e5760008273ffffffffffffffffffffffffffffffffffffffff168260405160006040518083038185875af1925050503d806000811461089e576040519150601f19603f3d011682016040523d82523d6000602084013e6108a3565b606091505b5050905080610530576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f455448207472616e73666572206661696c6564000000000000000000000000006044820152606401610640565b61050673ffffffffffffffffffffffffffffffffffffffff84168383610a31565b60008061093c8484610abe565b905080156105a757600084815260016020526040902061095c9084610bba565b509392505050565b6000806109718484610bdc565b905080156105a757600084815260016020526040902061095c9084610c97565b60006105a78383610cb9565b6000610417825490565b60008281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915290205460ff16610a2d576040517fe2517d3f00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8216600482015260248101839052604401610640565b5050565b6040805173ffffffffffffffffffffffffffffffffffffffff8416602482015260448082018490528251808303909101815260649091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fa9059cbb00000000000000000000000000000000000000000000000000000000179052610506908490610ce3565b60008281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915281205460ff16610bb25760008381526020818152604080832073ffffffffffffffffffffffffffffffffffffffff86168452909152902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055610b503390565b73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16847f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a4506001610417565b506000610417565b60006105a78373ffffffffffffffffffffffffffffffffffffffff8416610d79565b60008281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915281205460ff1615610bb25760008381526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8616808552925280832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016905551339286917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a4506001610417565b60006105a78373ffffffffffffffffffffffffffffffffffffffff8416610dc0565b6000826000018281548110610cd057610cd061112a565b9060005260206000200154905092915050565b6000610d0573ffffffffffffffffffffffffffffffffffffffff841683610eb3565b90508051600014158015610d2a575080806020019051810190610d289190611159565b155b15610506576040517f5274afe700000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff84166004820152602401610640565b6000818152600183016020526040812054610bb257508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155610417565b60008181526001830160205260408120548015610ea9576000610de460018361117b565b8554909150600090610df89060019061117b565b9050808214610e5d576000866000018281548110610e1857610e1861112a565b9060005260206000200154905080876000018481548110610e3b57610e3b61112a565b6000918252602080832090910192909255918252600188019052604090208390555b8554869080610e6e57610e6e6111b5565b600190038181906000526020600020016000905590558560010160008681526020019081526020016000206000905560019350505050610417565b6000915050610417565b60606105a783836000846000808573ffffffffffffffffffffffffffffffffffffffff168486604051610ee691906111e4565b60006040518083038185875af1925050503d8060008114610f23576040519150601f19603f3d011682016040523d82523d6000602084013e610f28565b606091505b5091509150610f38868383610f42565b9695505050505050565b606082610f5757610f5282610fd1565b6105a7565b8151158015610f7b575073ffffffffffffffffffffffffffffffffffffffff84163b155b15610fca576040517f9996b31500000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff85166004820152602401610640565b50806105a7565b805115610fe15780518082602001fd5b6040517f1425ea4200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006020828403121561102557600080fd5b81357fffffffff00000000000000000000000000000000000000000000000000000000811681146105a757600080fd5b803573ffffffffffffffffffffffffffffffffffffffff8116811461107957600080fd5b919050565b6000806040838503121561109157600080fd5b61109a83611055565b91506110a860208401611055565b90509250929050565b6000602082840312156110c357600080fd5b5035919050565b600080604083850312156110dd57600080fd5b823591506110a860208401611055565b6000806040838503121561110057600080fd5b50508035926020909101359150565b60006020828403121561112157600080fd5b6105a782611055565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60006020828403121561116b57600080fd5b815180151581146105a757600080fd5b81810381811115610417577f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fd5b6000825160005b8181101561120557602081860181015185830152016111eb565b50600092019182525091905056fea2646970667358221220b13443229221519c0fdb3ac2db22c34ccdfff8fd9f142c9a058dcefb00a5a9d864736f6c63430008180033", + Bin: "0x60806040523480156200001157600080fd5b50604051620014123803806200141283398101604081905262000034916200018e565b6200004160008262000049565b5050620001b9565b60008062000058848462000086565b905080156200007d5760008481526001602052604090206200007b908462000134565b505b90505b92915050565b6000828152602081815260408083206001600160a01b038516845290915281205460ff166200012b576000838152602081815260408083206001600160a01b03861684529091529020805460ff19166001179055620000e23390565b6001600160a01b0316826001600160a01b0316847f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a450600162000080565b50600062000080565b60006200007d836001600160a01b03841660008181526001830160205260408120546200012b5750815460018181018455600084815260208082209093018490558454848252828601909352604090209190915562000080565b600060208284031215620001a157600080fd5b81516001600160a01b03811681146200007d57600080fd5b61124980620001c96000396000f3fe608060405234801561001057600080fd5b50600436106101775760003560e01c806391d14854116100d8578063bf333f2c1161008c578063d547741f11610066578063d547741f14610385578063dcf844a714610398578063e00a83e0146103b857600080fd5b8063bf333f2c14610341578063ca15c8731461034b578063ccc574901461035e57600080fd5b8063a217fddf116100bd578063a217fddf14610313578063b13aa2d61461031b578063b250fe6b1461032e57600080fd5b806391d14854146102a8578063926d7d7f146102ec57600080fd5b80632f2ff15d1161012f57806358f858801161011457806358f85880146102405780635960ccf2146102495780639010d07c1461027057600080fd5b80632f2ff15d1461021a57806336568abe1461022d57600080fd5b806306f333f21161016057806306f333f2146101d95780630f5f6ed7146101ee578063248a9ca3146101f757600080fd5b806301ffc9a71461017c57806303ed0ee5146101a4575b600080fd5b61018f61018a366004611013565b6103c1565b60405190151581526020015b60405180910390f35b6101cb7f043c983c49d46f0e102151eaf8085d4a2e6571d5df2d47b013f39bddfd4a639d81565b60405190815260200161019b565b6101ec6101e736600461107e565b61041d565b005b6101cb61271081565b6101cb6102053660046110b1565b60009081526020819052604090206001015490565b6101ec6102283660046110ca565b61050b565b6101ec61023b3660046110ca565b610536565b6101cb60025481565b6101cb7fdb9556138406326f00296e13ea2ad7db24ba82381212d816b1a40c23b466b32781565b61028361027e3660046110ed565b61058f565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200161019b565b61018f6102b63660046110ca565b60009182526020828152604080842073ffffffffffffffffffffffffffffffffffffffff93909316845291905290205460ff1690565b6101cb7fe2b7fb3b832174769106daebcfd6d1970523240dda11281102db9363b83b0dc481565b6101cb600081565b6101ec6103293660046110b1565b6105ae565b6101ec61033c3660046110b1565b610690565b6101cb620f424081565b6101cb6103593660046110b1565b6106f8565b6101cb7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f5581565b6101ec6103933660046110ca565b61070f565b6101cb6103a636600461110f565b60036020526000908152604090205481565b6101cb60045481565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f5a05180f000000000000000000000000000000000000000000000000000000001480610417575061041782610734565b92915050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f55610447816107cb565b73ffffffffffffffffffffffffffffffffffffffff83166000908152600360205260408120549081900361047b5750505050565b73ffffffffffffffffffffffffffffffffffffffff84166000818152600360205260408120556104ac9084836107d8565b6040805173ffffffffffffffffffffffffffffffffffffffff8087168252851660208201529081018290527f244e51bc38c1452fa8aaf487bcb4bca36c2baa3a5fbdb776b1eabd8dc6d277cd9060600160405180910390a1505b505050565b600082815260208190526040902060010154610526816107cb565b610530838361092f565b50505050565b73ffffffffffffffffffffffffffffffffffffffff81163314610585576040517f6697b23200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6105068282610964565b60008281526001602052604081206105a79083610991565b9392505050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f556105d8816107cb565b612710821115610649576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f6e657746656552617465203e206d61780000000000000000000000000000000060448201526064015b60405180910390fd5b600280549083905560408051828152602081018590527f14914da2bf76024616fbe1859783fcd4dbddcb179b1f3a854949fbf920dcb95791015b60405180910390a1505050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f556106ba816107cb565b600480549083905560408051828152602081018590527f5cf09b12f3f56b4c564d51b25b40360af6d795198adb61ae0806a36c294323fa9101610683565b60008181526001602052604081206104179061099d565b60008281526020819052604090206001015461072a816107cb565b6105308383610964565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f7965db0b00000000000000000000000000000000000000000000000000000000148061041757507f01ffc9a7000000000000000000000000000000000000000000000000000000007fffffffff00000000000000000000000000000000000000000000000000000000831614610417565b6107d581336109a7565b50565b3073ffffffffffffffffffffffffffffffffffffffff8316036107fa57505050565b8060000361080757505050565b7fffffffffffffffffffffffff111111111111111111111111111111111111111273ffffffffffffffffffffffffffffffffffffffff84160161090e5760008273ffffffffffffffffffffffffffffffffffffffff168260405160006040518083038185875af1925050503d806000811461089e576040519150601f19603f3d011682016040523d82523d6000602084013e6108a3565b606091505b5050905080610530576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f455448207472616e73666572206661696c6564000000000000000000000000006044820152606401610640565b61050673ffffffffffffffffffffffffffffffffffffffff84168383610a31565b60008061093c8484610abe565b905080156105a757600084815260016020526040902061095c9084610bba565b509392505050565b6000806109718484610bdc565b905080156105a757600084815260016020526040902061095c9084610c97565b60006105a78383610cb9565b6000610417825490565b60008281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915290205460ff16610a2d576040517fe2517d3f00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8216600482015260248101839052604401610640565b5050565b6040805173ffffffffffffffffffffffffffffffffffffffff8416602482015260448082018490528251808303909101815260649091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fa9059cbb00000000000000000000000000000000000000000000000000000000179052610506908490610ce3565b60008281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915281205460ff16610bb25760008381526020818152604080832073ffffffffffffffffffffffffffffffffffffffff86168452909152902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055610b503390565b73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16847f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a4506001610417565b506000610417565b60006105a78373ffffffffffffffffffffffffffffffffffffffff8416610d79565b60008281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915281205460ff1615610bb25760008381526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8616808552925280832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016905551339286917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a4506001610417565b60006105a78373ffffffffffffffffffffffffffffffffffffffff8416610dc0565b6000826000018281548110610cd057610cd061112a565b9060005260206000200154905092915050565b6000610d0573ffffffffffffffffffffffffffffffffffffffff841683610eb3565b90508051600014158015610d2a575080806020019051810190610d289190611159565b155b15610506576040517f5274afe700000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff84166004820152602401610640565b6000818152600183016020526040812054610bb257508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155610417565b60008181526001830160205260408120548015610ea9576000610de460018361117b565b8554909150600090610df89060019061117b565b9050808214610e5d576000866000018281548110610e1857610e1861112a565b9060005260206000200154905080876000018481548110610e3b57610e3b61112a565b6000918252602080832090910192909255918252600188019052604090208390555b8554869080610e6e57610e6e6111b5565b600190038181906000526020600020016000905590558560010160008681526020019081526020016000206000905560019350505050610417565b6000915050610417565b60606105a783836000846000808573ffffffffffffffffffffffffffffffffffffffff168486604051610ee691906111e4565b60006040518083038185875af1925050503d8060008114610f23576040519150601f19603f3d011682016040523d82523d6000602084013e610f28565b606091505b5091509150610f38868383610f42565b9695505050505050565b606082610f5757610f5282610fd1565b6105a7565b8151158015610f7b575073ffffffffffffffffffffffffffffffffffffffff84163b155b15610fca576040517f9996b31500000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff85166004820152602401610640565b50806105a7565b805115610fe15780518082602001fd5b6040517f1425ea4200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006020828403121561102557600080fd5b81357fffffffff00000000000000000000000000000000000000000000000000000000811681146105a757600080fd5b803573ffffffffffffffffffffffffffffffffffffffff8116811461107957600080fd5b919050565b6000806040838503121561109157600080fd5b61109a83611055565b91506110a860208401611055565b90509250929050565b6000602082840312156110c357600080fd5b5035919050565b600080604083850312156110dd57600080fd5b823591506110a860208401611055565b6000806040838503121561110057600080fd5b50508035926020909101359150565b60006020828403121561112157600080fd5b6105a782611055565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60006020828403121561116b57600080fd5b815180151581146105a757600080fd5b81810381811115610417577f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fd5b6000825160005b8181101561120557602081860181015185830152016111eb565b50600092019182525091905056fea2646970667358221220cf33c3d4da69e4a6aeddfcb46cd394bfc44899f75312d31fd8c8e38dff96ab9764736f6c63430008180033", } // AdminABI is the input ABI used to generate the binding from. @@ -3680,6 +3686,179 @@ func (_Admin *AdminFilterer) ParseRoleRevoked(log types.Log) (*AdminRoleRevoked, return event, nil } +// BridgeTransactionV2LibMetaData contains all meta data concerning the BridgeTransactionV2Lib contract. +var BridgeTransactionV2LibMetaData = &bind.MetaData{ + ABI: "[{\"inputs\":[],\"name\":\"BridgeTransactionV2__InvalidEncodedTx\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint16\",\"name\":\"version\",\"type\":\"uint16\"}],\"name\":\"BridgeTransactionV2__UnsupportedVersion\",\"type\":\"error\"}]", + Bin: "0x60566037600b82828239805160001a607314602a57634e487b7160e01b600052600060045260246000fd5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600080fdfea2646970667358221220c0d1e2256fb16b1e19ad4848dc80aafe3c3f70b204e139f256b5d6095b52dd5564736f6c63430008180033", +} + +// BridgeTransactionV2LibABI is the input ABI used to generate the binding from. +// Deprecated: Use BridgeTransactionV2LibMetaData.ABI instead. +var BridgeTransactionV2LibABI = BridgeTransactionV2LibMetaData.ABI + +// BridgeTransactionV2LibBin is the compiled bytecode used for deploying new contracts. +// Deprecated: Use BridgeTransactionV2LibMetaData.Bin instead. +var BridgeTransactionV2LibBin = BridgeTransactionV2LibMetaData.Bin + +// DeployBridgeTransactionV2Lib deploys a new Ethereum contract, binding an instance of BridgeTransactionV2Lib to it. +func DeployBridgeTransactionV2Lib(auth *bind.TransactOpts, backend bind.ContractBackend) (common.Address, *types.Transaction, *BridgeTransactionV2Lib, error) { + parsed, err := BridgeTransactionV2LibMetaData.GetAbi() + if err != nil { + return common.Address{}, nil, nil, err + } + if parsed == nil { + return common.Address{}, nil, nil, errors.New("GetABI returned nil") + } + + address, tx, contract, err := bind.DeployContract(auth, *parsed, common.FromHex(BridgeTransactionV2LibBin), backend) + if err != nil { + return common.Address{}, nil, nil, err + } + return address, tx, &BridgeTransactionV2Lib{BridgeTransactionV2LibCaller: BridgeTransactionV2LibCaller{contract: contract}, BridgeTransactionV2LibTransactor: BridgeTransactionV2LibTransactor{contract: contract}, BridgeTransactionV2LibFilterer: BridgeTransactionV2LibFilterer{contract: contract}}, nil +} + +// BridgeTransactionV2Lib is an auto generated Go binding around an Ethereum contract. +type BridgeTransactionV2Lib struct { + BridgeTransactionV2LibCaller // Read-only binding to the contract + BridgeTransactionV2LibTransactor // Write-only binding to the contract + BridgeTransactionV2LibFilterer // Log filterer for contract events +} + +// BridgeTransactionV2LibCaller is an auto generated read-only Go binding around an Ethereum contract. +type BridgeTransactionV2LibCaller struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// BridgeTransactionV2LibTransactor is an auto generated write-only Go binding around an Ethereum contract. +type BridgeTransactionV2LibTransactor struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// BridgeTransactionV2LibFilterer is an auto generated log filtering Go binding around an Ethereum contract events. +type BridgeTransactionV2LibFilterer struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// BridgeTransactionV2LibSession is an auto generated Go binding around an Ethereum contract, +// with pre-set call and transact options. +type BridgeTransactionV2LibSession struct { + Contract *BridgeTransactionV2Lib // Generic contract binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// BridgeTransactionV2LibCallerSession is an auto generated read-only Go binding around an Ethereum contract, +// with pre-set call options. +type BridgeTransactionV2LibCallerSession struct { + Contract *BridgeTransactionV2LibCaller // Generic contract caller binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session +} + +// BridgeTransactionV2LibTransactorSession is an auto generated write-only Go binding around an Ethereum contract, +// with pre-set transact options. +type BridgeTransactionV2LibTransactorSession struct { + Contract *BridgeTransactionV2LibTransactor // Generic contract transactor binding to set the session for + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// BridgeTransactionV2LibRaw is an auto generated low-level Go binding around an Ethereum contract. +type BridgeTransactionV2LibRaw struct { + Contract *BridgeTransactionV2Lib // Generic contract binding to access the raw methods on +} + +// BridgeTransactionV2LibCallerRaw is an auto generated low-level read-only Go binding around an Ethereum contract. +type BridgeTransactionV2LibCallerRaw struct { + Contract *BridgeTransactionV2LibCaller // Generic read-only contract binding to access the raw methods on +} + +// BridgeTransactionV2LibTransactorRaw is an auto generated low-level write-only Go binding around an Ethereum contract. +type BridgeTransactionV2LibTransactorRaw struct { + Contract *BridgeTransactionV2LibTransactor // Generic write-only contract binding to access the raw methods on +} + +// NewBridgeTransactionV2Lib creates a new instance of BridgeTransactionV2Lib, bound to a specific deployed contract. +func NewBridgeTransactionV2Lib(address common.Address, backend bind.ContractBackend) (*BridgeTransactionV2Lib, error) { + contract, err := bindBridgeTransactionV2Lib(address, backend, backend, backend) + if err != nil { + return nil, err + } + return &BridgeTransactionV2Lib{BridgeTransactionV2LibCaller: BridgeTransactionV2LibCaller{contract: contract}, BridgeTransactionV2LibTransactor: BridgeTransactionV2LibTransactor{contract: contract}, BridgeTransactionV2LibFilterer: BridgeTransactionV2LibFilterer{contract: contract}}, nil +} + +// NewBridgeTransactionV2LibCaller creates a new read-only instance of BridgeTransactionV2Lib, bound to a specific deployed contract. +func NewBridgeTransactionV2LibCaller(address common.Address, caller bind.ContractCaller) (*BridgeTransactionV2LibCaller, error) { + contract, err := bindBridgeTransactionV2Lib(address, caller, nil, nil) + if err != nil { + return nil, err + } + return &BridgeTransactionV2LibCaller{contract: contract}, nil +} + +// NewBridgeTransactionV2LibTransactor creates a new write-only instance of BridgeTransactionV2Lib, bound to a specific deployed contract. +func NewBridgeTransactionV2LibTransactor(address common.Address, transactor bind.ContractTransactor) (*BridgeTransactionV2LibTransactor, error) { + contract, err := bindBridgeTransactionV2Lib(address, nil, transactor, nil) + if err != nil { + return nil, err + } + return &BridgeTransactionV2LibTransactor{contract: contract}, nil +} + +// NewBridgeTransactionV2LibFilterer creates a new log filterer instance of BridgeTransactionV2Lib, bound to a specific deployed contract. +func NewBridgeTransactionV2LibFilterer(address common.Address, filterer bind.ContractFilterer) (*BridgeTransactionV2LibFilterer, error) { + contract, err := bindBridgeTransactionV2Lib(address, nil, nil, filterer) + if err != nil { + return nil, err + } + return &BridgeTransactionV2LibFilterer{contract: contract}, nil +} + +// bindBridgeTransactionV2Lib binds a generic wrapper to an already deployed contract. +func bindBridgeTransactionV2Lib(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) { + parsed, err := BridgeTransactionV2LibMetaData.GetAbi() + if err != nil { + return nil, err + } + return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil +} + +// Call invokes the (constant) contract method with params as input values and +// sets the output to result. The result type might be a single field for simple +// returns, a slice of interfaces for anonymous returns and a struct for named +// returns. +func (_BridgeTransactionV2Lib *BridgeTransactionV2LibRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _BridgeTransactionV2Lib.Contract.BridgeTransactionV2LibCaller.contract.Call(opts, result, method, params...) +} + +// Transfer initiates a plain transaction to move funds to the contract, calling +// its default method if one is available. +func (_BridgeTransactionV2Lib *BridgeTransactionV2LibRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _BridgeTransactionV2Lib.Contract.BridgeTransactionV2LibTransactor.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_BridgeTransactionV2Lib *BridgeTransactionV2LibRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _BridgeTransactionV2Lib.Contract.BridgeTransactionV2LibTransactor.contract.Transact(opts, method, params...) +} + +// Call invokes the (constant) contract method with params as input values and +// sets the output to result. The result type might be a single field for simple +// returns, a slice of interfaces for anonymous returns and a struct for named +// returns. +func (_BridgeTransactionV2Lib *BridgeTransactionV2LibCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _BridgeTransactionV2Lib.Contract.contract.Call(opts, result, method, params...) +} + +// Transfer initiates a plain transaction to move funds to the contract, calling +// its default method if one is available. +func (_BridgeTransactionV2Lib *BridgeTransactionV2LibTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _BridgeTransactionV2Lib.Contract.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_BridgeTransactionV2Lib *BridgeTransactionV2LibTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _BridgeTransactionV2Lib.Contract.contract.Transact(opts, method, params...) +} + // ContextMetaData contains all meta data concerning the Context contract. var ContextMetaData = &bind.MetaData{ ABI: "[]", @@ -4023,7 +4202,7 @@ func (_ERC165 *ERC165CallerSession) SupportsInterface(interfaceId [4]byte) (bool // EnumerableSetMetaData contains all meta data concerning the EnumerableSet contract. var EnumerableSetMetaData = &bind.MetaData{ ABI: "[]", - Bin: "0x60566037600b82828239805160001a607314602a57634e487b7160e01b600052600060045260246000fd5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600080fdfea264697066735822122096938e347a6ad7c9db19e62e3fe085fcb6b4b02d667bfa2b5db09e30538dd3cd64736f6c63430008180033", + Bin: "0x60566037600b82828239805160001a607314602a57634e487b7160e01b600052600060045260246000fd5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600080fdfea26469706673582212202a0689afaebf6ffa0f4d0a6fe04b9b6e642f8ef83c8db74e665e9fc77d71999964736f6c63430008180033", } // EnumerableSetABI is the input ABI used to generate the binding from. @@ -4195,7 +4374,7 @@ func (_EnumerableSet *EnumerableSetTransactorRaw) Transact(opts *bind.TransactOp // FastBridgeV2MetaData contains all meta data concerning the FastBridgeV2 contract. var FastBridgeV2MetaData = &bind.MetaData{ - ABI: "[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_owner\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"AccessControlBadConfirmation\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"neededRole\",\"type\":\"bytes32\"}],\"name\":\"AccessControlUnauthorizedAccount\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"}],\"name\":\"AddressEmptyCode\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"AddressInsufficientBalance\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"AmountIncorrect\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"CallParamsLengthAboveMax\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ChainIncorrect\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DeadlineExceeded\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DeadlineNotExceeded\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DeadlineTooShort\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DisputePeriodNotPassed\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DisputePeriodPassed\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ExclusivityParamsIncorrect\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ExclusivityPeriodNotPassed\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"FailedInnerCall\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"MsgValueIncorrect\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"NativeTokenCallValueNotSupported\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"RecipientIncorrectReturnValue\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"RecipientNoReturnValue\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"}],\"name\":\"SafeERC20FailedOperation\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"SenderIncorrect\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"StatusIncorrect\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"TokenNotContract\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"TransactionRelayed\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ZeroAddress\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"BridgeDepositClaimed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"BridgeDepositRefunded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"name\":\"BridgeProofDisputed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"transactionHash\",\"type\":\"bytes32\"}],\"name\":\"BridgeProofProvided\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"quoteId\",\"type\":\"bytes\"}],\"name\":\"BridgeQuoteDetails\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"originChainId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"chainGasAmount\",\"type\":\"uint256\"}],\"name\":\"BridgeRelayed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"destChainId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"sendChainGas\",\"type\":\"bool\"}],\"name\":\"BridgeRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"oldChainGasAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newChainGasAmount\",\"type\":\"uint256\"}],\"name\":\"ChainGasAmountUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"oldFeeRate\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newFeeRate\",\"type\":\"uint256\"}],\"name\":\"FeeRateUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"FeesSwept\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"previousAdminRole\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"newAdminRole\",\"type\":\"bytes32\"}],\"name\":\"RoleAdminChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleGranted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleRevoked\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"DEFAULT_ADMIN_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"DISPUTE_PERIOD\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"FEE_BPS\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"FEE_RATE_MAX\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"GOVERNOR_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"GUARD_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"MAX_CALL_PARAMS_LENGTH\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"MIN_DEADLINE_PERIOD\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"REFUNDER_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"REFUND_DELAY\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"RELAYER_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"dstChainId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"sendChainGas\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"}],\"internalType\":\"structIFastBridge.BridgeParams\",\"name\":\"params\",\"type\":\"tuple\"}],\"name\":\"bridge\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"dstChainId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"sendChainGas\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"}],\"internalType\":\"structIFastBridge.BridgeParams\",\"name\":\"params\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"quoteRelayer\",\"type\":\"address\"},{\"internalType\":\"int256\",\"name\":\"quoteExclusivitySeconds\",\"type\":\"int256\"},{\"internalType\":\"bytes\",\"name\":\"quoteId\",\"type\":\"bytes\"},{\"internalType\":\"uint256\",\"name\":\"callValue\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"callParams\",\"type\":\"bytes\"}],\"internalType\":\"structIFastBridgeV2.BridgeParamsV2\",\"name\":\"paramsV2\",\"type\":\"tuple\"}],\"name\":\"bridge\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"}],\"name\":\"bridgeProofs\",\"outputs\":[{\"internalType\":\"uint96\",\"name\":\"timestamp\",\"type\":\"uint96\"},{\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"bridgeRelayDetails\",\"outputs\":[{\"internalType\":\"uint48\",\"name\":\"blockNumber\",\"type\":\"uint48\"},{\"internalType\":\"uint48\",\"name\":\"blockTimestamp\",\"type\":\"uint48\"},{\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"}],\"name\":\"bridgeRelays\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"}],\"name\":\"bridgeStatuses\",\"outputs\":[{\"internalType\":\"enumIFastBridgeV2.BridgeStatus\",\"name\":\"status\",\"type\":\"uint8\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"bridgeTxDetails\",\"outputs\":[{\"internalType\":\"enumIFastBridgeV2.BridgeStatus\",\"name\":\"status\",\"type\":\"uint8\"},{\"internalType\":\"uint40\",\"name\":\"proofBlockTimestamp\",\"type\":\"uint40\"},{\"internalType\":\"uint48\",\"name\":\"proofBlockNumber\",\"type\":\"uint48\"},{\"internalType\":\"address\",\"name\":\"proofRelayer\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"name\":\"canClaim\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"chainGasAmount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"claim\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"claim\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"deployBlock\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"}],\"name\":\"dispute\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"getBridgeTransaction\",\"outputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"originChainId\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"destChainId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"originSender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destRecipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"originFeeAmount\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"sendChainGas\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"}],\"internalType\":\"structIFastBridge.BridgeTransaction\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"getBridgeTransactionV2\",\"outputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"originChainId\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"destChainId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"originSender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destRecipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"originFeeAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"callValue\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"exclusivityRelayer\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"exclusivityEndTime\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"callParams\",\"type\":\"bytes\"}],\"internalType\":\"structIFastBridgeV2.BridgeTransactionV2\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"}],\"name\":\"getRoleAdmin\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"index\",\"type\":\"uint256\"}],\"name\":\"getRoleMember\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"}],\"name\":\"getRoleMemberCount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"grantRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"hasRole\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"nonce\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"protocolFeeRate\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"protocolFees\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"destTxHash\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"name\":\"prove\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"},{\"internalType\":\"bytes32\",\"name\":\"destTxHash\",\"type\":\"bytes32\"}],\"name\":\"prove\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"refund\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"relay\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"},{\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"name\":\"relay\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"callerConfirmation\",\"type\":\"address\"}],\"name\":\"renounceRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"revokeRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"senderNonces\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"newChainGasAmount\",\"type\":\"uint256\"}],\"name\":\"setChainGasAmount\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"newFeeRate\",\"type\":\"uint256\"}],\"name\":\"setProtocolFeeRate\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes4\",\"name\":\"interfaceId\",\"type\":\"bytes4\"}],\"name\":\"supportsInterface\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"}],\"name\":\"sweepProtocolFees\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", + ABI: "[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_owner\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"AccessControlBadConfirmation\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"neededRole\",\"type\":\"bytes32\"}],\"name\":\"AccessControlUnauthorizedAccount\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"}],\"name\":\"AddressEmptyCode\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"AddressInsufficientBalance\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"AmountIncorrect\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"BridgeTransactionV2__InvalidEncodedTx\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint16\",\"name\":\"version\",\"type\":\"uint16\"}],\"name\":\"BridgeTransactionV2__UnsupportedVersion\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ChainIncorrect\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DeadlineExceeded\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DeadlineNotExceeded\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DeadlineTooShort\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DisputePeriodNotPassed\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DisputePeriodPassed\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ExclusivityParamsIncorrect\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ExclusivityPeriodNotPassed\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"FailedInnerCall\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"MsgValueIncorrect\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"MulticallTarget__UndeterminedRevert\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"RecipientIncorrectReturnValue\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"RecipientNoReturnValue\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"}],\"name\":\"SafeERC20FailedOperation\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"SenderIncorrect\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"StatusIncorrect\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"TokenNotContract\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"TransactionRelayed\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ZapDataLengthAboveMax\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ZapNativeNotSupported\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ZeroAddress\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"BridgeDepositClaimed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"BridgeDepositRefunded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"name\":\"BridgeProofDisputed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"transactionHash\",\"type\":\"bytes32\"}],\"name\":\"BridgeProofProvided\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"quoteId\",\"type\":\"bytes\"}],\"name\":\"BridgeQuoteDetails\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"originChainId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"chainGasAmount\",\"type\":\"uint256\"}],\"name\":\"BridgeRelayed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"destChainId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"sendChainGas\",\"type\":\"bool\"}],\"name\":\"BridgeRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"oldChainGasAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newChainGasAmount\",\"type\":\"uint256\"}],\"name\":\"ChainGasAmountUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"oldFeeRate\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newFeeRate\",\"type\":\"uint256\"}],\"name\":\"FeeRateUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"FeesSwept\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"previousAdminRole\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"newAdminRole\",\"type\":\"bytes32\"}],\"name\":\"RoleAdminChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleGranted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleRevoked\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"DEFAULT_ADMIN_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"DISPUTE_PERIOD\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"FEE_BPS\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"FEE_RATE_MAX\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"GOVERNOR_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"GUARD_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"MAX_ZAP_DATA_LENGTH\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"MIN_DEADLINE_PERIOD\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"NATIVE_GAS_TOKEN\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"REFUNDER_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"REFUND_DELAY\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"RELAYER_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"dstChainId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"sendChainGas\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"}],\"internalType\":\"structIFastBridge.BridgeParams\",\"name\":\"params\",\"type\":\"tuple\"}],\"name\":\"bridge\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"dstChainId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"sendChainGas\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"}],\"internalType\":\"structIFastBridge.BridgeParams\",\"name\":\"params\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"quoteRelayer\",\"type\":\"address\"},{\"internalType\":\"int256\",\"name\":\"quoteExclusivitySeconds\",\"type\":\"int256\"},{\"internalType\":\"bytes\",\"name\":\"quoteId\",\"type\":\"bytes\"},{\"internalType\":\"uint256\",\"name\":\"zapNative\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"zapData\",\"type\":\"bytes\"}],\"internalType\":\"structIFastBridgeV2.BridgeParamsV2\",\"name\":\"paramsV2\",\"type\":\"tuple\"}],\"name\":\"bridge\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"}],\"name\":\"bridgeProofs\",\"outputs\":[{\"internalType\":\"uint96\",\"name\":\"timestamp\",\"type\":\"uint96\"},{\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"bridgeRelayDetails\",\"outputs\":[{\"internalType\":\"uint48\",\"name\":\"blockNumber\",\"type\":\"uint48\"},{\"internalType\":\"uint48\",\"name\":\"blockTimestamp\",\"type\":\"uint48\"},{\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"}],\"name\":\"bridgeRelays\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"}],\"name\":\"bridgeStatuses\",\"outputs\":[{\"internalType\":\"enumIFastBridgeV2.BridgeStatus\",\"name\":\"status\",\"type\":\"uint8\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"bridgeTxDetails\",\"outputs\":[{\"internalType\":\"enumIFastBridgeV2.BridgeStatus\",\"name\":\"status\",\"type\":\"uint8\"},{\"internalType\":\"uint32\",\"name\":\"destChainId\",\"type\":\"uint32\"},{\"internalType\":\"uint56\",\"name\":\"proofBlockTimestamp\",\"type\":\"uint56\"},{\"internalType\":\"address\",\"name\":\"proofRelayer\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"name\":\"canClaim\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"chainGasAmount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"claim\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"claim\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"deployBlock\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"}],\"name\":\"dispute\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"getBridgeTransaction\",\"outputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"originChainId\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"destChainId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"originSender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destRecipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"originFeeAmount\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"sendChainGas\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"}],\"internalType\":\"structIFastBridge.BridgeTransaction\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"getBridgeTransactionV2\",\"outputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"originChainId\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"destChainId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"originSender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destRecipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"originFeeAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"exclusivityRelayer\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"exclusivityEndTime\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"zapNative\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"zapData\",\"type\":\"bytes\"}],\"internalType\":\"structIFastBridgeV2.BridgeTransactionV2\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"}],\"name\":\"getRoleAdmin\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"index\",\"type\":\"uint256\"}],\"name\":\"getRoleMember\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"}],\"name\":\"getRoleMemberCount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"grantRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"hasRole\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes[]\",\"name\":\"data\",\"type\":\"bytes[]\"},{\"internalType\":\"bool\",\"name\":\"ignoreReverts\",\"type\":\"bool\"}],\"name\":\"multicallNoResults\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes[]\",\"name\":\"data\",\"type\":\"bytes[]\"},{\"internalType\":\"bool\",\"name\":\"ignoreReverts\",\"type\":\"bool\"}],\"name\":\"multicallWithResults\",\"outputs\":[{\"components\":[{\"internalType\":\"bool\",\"name\":\"success\",\"type\":\"bool\"},{\"internalType\":\"bytes\",\"name\":\"returnData\",\"type\":\"bytes\"}],\"internalType\":\"structIMulticallTarget.Result[]\",\"name\":\"results\",\"type\":\"tuple[]\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"nonce\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"protocolFeeRate\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"protocolFees\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"destTxHash\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"name\":\"prove\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"},{\"internalType\":\"bytes32\",\"name\":\"destTxHash\",\"type\":\"bytes32\"}],\"name\":\"prove\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"refund\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"relay\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"},{\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"name\":\"relay\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"callerConfirmation\",\"type\":\"address\"}],\"name\":\"renounceRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"revokeRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"senderNonces\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"newChainGasAmount\",\"type\":\"uint256\"}],\"name\":\"setChainGasAmount\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"newFeeRate\",\"type\":\"uint256\"}],\"name\":\"setProtocolFeeRate\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes4\",\"name\":\"interfaceId\",\"type\":\"bytes4\"}],\"name\":\"supportsInterface\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"}],\"name\":\"sweepProtocolFees\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", Sigs: map[string]string{ "a217fddf": "DEFAULT_ADMIN_ROLE()", "a5bbe22b": "DISPUTE_PERIOD()", @@ -4203,8 +4382,9 @@ var FastBridgeV2MetaData = &bind.MetaData{ "0f5f6ed7": "FEE_RATE_MAX()", "ccc57490": "GOVERNOR_ROLE()", "03ed0ee5": "GUARD_ROLE()", - "df36bb13": "MAX_CALL_PARAMS_LENGTH()", + "54eff068": "MAX_ZAP_DATA_LENGTH()", "820688d5": "MIN_DEADLINE_PERIOD()", + "0f862f1e": "NATIVE_GAS_TOKEN()", "5960ccf2": "REFUNDER_ROLE()", "190da595": "REFUND_DELAY()", "926d7d7f": "RELAYER_ROLE()", @@ -4228,6 +4408,8 @@ var FastBridgeV2MetaData = &bind.MetaData{ "ca15c873": "getRoleMemberCount(bytes32)", "2f2ff15d": "grantRole(bytes32,address)", "91d14854": "hasRole(bytes32,address)", + "3f61331d": "multicallNoResults(bytes[],bool)", + "385c1d2f": "multicallWithResults(bytes[],bool)", "affed0e0": "nonce()", "58f85880": "protocolFeeRate()", "dcf844a7": "protocolFees(address)", @@ -4244,7 +4426,7 @@ var FastBridgeV2MetaData = &bind.MetaData{ "01ffc9a7": "supportsInterface(bytes4)", "06f333f2": "sweepProtocolFees(address,address)", }, - Bin: "0x60c060405260006080523480156200001657600080fd5b5060405162003e6138038062003e61833981016040819052620000399162000199565b806200004760008262000054565b50504360a05250620001c4565b60008062000063848462000091565b90508015620000885760008481526001602052604090206200008690846200013f565b505b90505b92915050565b6000828152602081815260408083206001600160a01b038516845290915281205460ff1662000136576000838152602081815260408083206001600160a01b03861684529091529020805460ff19166001179055620000ed3390565b6001600160a01b0316826001600160a01b0316847f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45060016200008b565b5060006200008b565b600062000088836001600160a01b038416600081815260018301602052604081205462000136575081546001818101845560008481526020808220909301849055845484825282860190935260409020919091556200008b565b600060208284031215620001ac57600080fd5b81516001600160a01b03811681146200008857600080fd5b60805160a051613c77620001ea6000396000610802015260006108a30152613c776000f3fe6080604052600436106102fd5760003560e01c806391ad50391161018f578063b13aa2d6116100e1578063ca15c8731161008a578063dcf844a711610064578063dcf844a714610a50578063df36bb1314610a7d578063e00a83e014610a9357600080fd5b8063ca15c873146109dc578063ccc57490146109fc578063d547741f14610a3057600080fd5b8063bfc7c607116100bb578063bfc7c6071461091c578063c63ff8dd1461092f578063c79371b11461094f57600080fd5b8063b13aa2d6146108c5578063b250fe6b146108e5578063bf333f2c1461090557600080fd5b8063a3ec191a11610143578063ac11fb1a1161011d578063ac11fb1a14610844578063add98c7014610871578063affed0e01461089157600080fd5b8063a3ec191a146107f0578063a5bbe22b14610607578063aa9641ab1461082457600080fd5b8063926d7d7f11610174578063926d7d7f146107945780639c9545f0146107c8578063a217fddf146107db57600080fd5b806391ad5039146106d057806391d148541461075057600080fd5b806341fcb6121161025357806363787e52116101fc578063886d36ff116101d6578063886d36ff146106655780638f0d6f17146106855780639010d07c1461069857600080fd5b806363787e521461058c578063820688d5146106075780638379a24f1461061d57600080fd5b80635960ccf21161022d5780635960ccf21461050b5780635aa6ccba1461053f5780635eb7d9461461056c57600080fd5b806341fcb612146104c257806345851694146104e257806358f85880146104f557600080fd5b806318e4357d116102b5578063295710ff1161028f578063295710ff146104555780632f2ff15d1461048257806336568abe146104a257600080fd5b806318e4357d146103ee578063190da5951461040e578063248a9ca31461042557600080fd5b8063051287bc116102e6578063051287bc1461037957806306f333f2146103b65780630f5f6ed7146103d857600080fd5b806301ffc9a71461030257806303ed0ee514610337575b600080fd5b34801561030e57600080fd5b5061032261031d366004612eef565b610aa9565b60405190151581526020015b60405180910390f35b34801561034357600080fd5b5061036b7f043c983c49d46f0e102151eaf8085d4a2e6571d5df2d47b013f39bddfd4a639d81565b60405190815260200161032e565b34801561038557600080fd5b506103a9610394366004612f31565b60009081526005602052604090205460ff1690565b60405161032e9190612fb4565b3480156103c257600080fd5b506103d66103d1366004612fe2565b610b05565b005b3480156103e457600080fd5b5061036b61271081565b3480156103fa57600080fd5b506103d661040936600461301b565b610bcc565b34801561041a57600080fd5b5061036b62093a8081565b34801561043157600080fd5b5061036b610440366004612f31565b60009081526020819052604090206001015490565b34801561046157600080fd5b5061036b610470366004613054565b60076020526000908152604090205481565b34801561048e57600080fd5b506103d661049d366004613071565b610d39565b3480156104ae57600080fd5b506103d66104bd366004613071565b610d64565b3480156104ce57600080fd5b506103d66104dd366004613209565b610db0565b6103d66104f0366004613329565b611026565b34801561050157600080fd5b5061036b60025481565b34801561051757600080fd5b5061036b7fdb9556138406326f00296e13ea2ad7db24ba82381212d816b1a40c23b466b32781565b34801561054b57600080fd5b5061055f61055a366004613346565b611083565b60405161032e91906133d3565b34801561057857600080fd5b506103d6610587366004613346565b611149565b34801561059857600080fd5b506105f76105a7366004612f31565b60056020526000908152604090205460ff811690610100810464ffffffffff16906601000000000000810465ffffffffffff16906c0100000000000000000000000090046001600160a01b031684565b60405161032e94939291906134e8565b34801561061357600080fd5b5061036b61070881565b34801561062957600080fd5b50610322610638366004612f31565b6000908152600660205260409020546c0100000000000000000000000090046001600160a01b0316151590565b34801561067157600080fd5b506103d6610680366004613529565b61133e565b6103d6610693366004613346565b611354565b3480156106a457600080fd5b506106b86106b336600461356e565b61135e565b6040516001600160a01b03909116815260200161032e565b3480156106dc57600080fd5b506107246106eb366004612f31565b600090815260056020526040902054610100810464ffffffffff16916c010000000000000000000000009091046001600160a01b031690565b604080516bffffffffffffffffffffffff90931683526001600160a01b0390911660208301520161032e565b34801561075c57600080fd5b5061032261076b366004613071565b6000918252602082815260408084206001600160a01b0393909316845291905290205460ff1690565b3480156107a057600080fd5b5061036b7fe2b7fb3b832174769106daebcfd6d1970523240dda11281102db9363b83b0dc481565b6103d66107d6366004613209565b61137d565b3480156107e757600080fd5b5061036b600081565b3480156107fc57600080fd5b5061036b7f000000000000000000000000000000000000000000000000000000000000000081565b34801561083057600080fd5b5061032261083f366004613071565b611603565b34801561085057600080fd5b5061086461085f366004613346565b6116ee565b60405161032e9190613590565b34801561087d57600080fd5b506103d661088c366004612f31565b6118a6565b34801561089d57600080fd5b5061036b7f000000000000000000000000000000000000000000000000000000000000000081565b3480156108d157600080fd5b506103d66108e0366004612f31565b6119c8565b3480156108f157600080fd5b506103d6610900366004612f31565b611aaa565b34801561091157600080fd5b5061036b620f424081565b6103d661092a366004613676565b611b12565b34801561093b57600080fd5b506103d661094a366004613346565b611d94565b34801561095b57600080fd5b506109ae61096a366004612f31565b60066020526000908152604090205465ffffffffffff8082169166010000000000008104909116906c0100000000000000000000000090046001600160a01b031683565b6040805165ffffffffffff94851681529390921660208401526001600160a01b03169082015260600161032e565b3480156109e857600080fd5b5061036b6109f7366004612f31565b611d9f565b348015610a0857600080fd5b5061036b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f5581565b348015610a3c57600080fd5b506103d6610a4b366004613071565b611db6565b348015610a5c57600080fd5b5061036b610a6b366004613054565b60036020526000908152604090205481565b348015610a8957600080fd5b5061036b61ffff81565b348015610a9f57600080fd5b5061036b60045481565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f5a05180f000000000000000000000000000000000000000000000000000000001480610aff5750610aff82611ddb565b92915050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f55610b2f81611e72565b6001600160a01b03831660009081526003602052604081205490819003610b565750505050565b6001600160a01b038416600081815260036020526040812055610b7a908483611e7c565b604080516001600160a01b038087168252851660208201529081018290527f244e51bc38c1452fa8aaf487bcb4bca36c2baa3a5fbdb776b1eabd8dc6d277cd9060600160405180910390a1505b505050565b7fe2b7fb3b832174769106daebcfd6d1970523240dda11281102db9363b83b0dc4610bf681611e72565b600160008581526005602052604090205460ff166004811115610c1b57610c1b612f4a565b14610c52576040517f4145817200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600084815260056020908152604091829020805460027fffffffffffffffffffffffffffffffffffffffff0000000000000000000000009091166101004264ffffffffff16027fffffffffffffffffffffffffffffffffffffffff000000000000ffffffffffff161766010000000000004365ffffffffffff160217176bffffffffffffffffffffffff166c010000000000000000000000006001600160a01b0387169081029190911790915582518681529251909287927f4ac8af8a2cd87193d64dfc7a3b8d9923b714ec528b18725d080aa1299be0c5e492918290030190a350505050565b600082815260208190526040902060010154610d5481611e72565b610d5e8383611f9f565b50505050565b6001600160a01b0381163314610da6576040517f6697b23200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610bc78282611fd4565b815160208301206000610dc284611083565b9050600260008381526005602052604090205460ff166004811115610de957610de9612f4a565b14610e20576040517f4145817200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600160a01b038316610e5d576000828152600560205260409020546c0100000000000000000000000090046001600160a01b03169250610ebd565b6000828152600560205260409020546c0100000000000000000000000090046001600160a01b03163314610ebd576040517f4af43a9000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008281526005602052604090205461070890610100900464ffffffffff90811642031611610f18576040517f1992d0bd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600082815260056020526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016600317905561010081015115610f925761010081015160808201516001600160a01b031660009081526003602052604081208054909190610f8c908490613773565b90915550505b608081015160c0820151610fb06001600160a01b0383168683611e7c565b6000848152600560209081526040918290205482516001600160a01b038681168252928101859052888316936c010000000000000000000000009092049092169187917f582211c35a2139ac3bbaac74663c6a1f56c6cbb658b41fe11fd45a82074ac678910160405180910390a4505050505050565b611080816040518060a0016040528060006001600160a01b03168152602001600081526020016040518060200160405280600081525081526020016000815260200160405180602001604052806000815250815250611b12565b50565b611135604051806101e00160405280600063ffffffff168152602001600063ffffffff16815260200160006001600160a01b0316815260200160006001600160a01b0316815260200160006001600160a01b0316815260200160006001600160a01b0316815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160006001600160a01b0316815260200160008152602001606081525090565b81806020019051810190610aff91906137e1565b80516020820120600061115b83611083565b9050600160008381526005602052604090205460ff16600481111561118257611182612f4a565b146111b9576040517f4145817200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b3360009081527fd2043bf65931af3dbecf60d0db8f40e4160406d7beb00522f4200cf4944a1eb8602052604090205460ff161561123357806101400151421161122e576040517fe15ff9ea00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61127f565b62093a808161014001516112479190613773565b421161127f576040517fe15ff9ea00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008281526005602052604080822080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166004179055820151608083015161010084015160c0850151929391926112d89190613773565b90506112ee6001600160a01b0383168483611e7c565b604080516001600160a01b0384811682526020820184905285169187917fb4c55c0c9bc613519b920e88748090150b890a875d307f21bea7d4fb2e8bc958910160405180910390a3505050505050565b61135082805190602001208233610bcc565b5050565b611080813361137d565b60008281526001602052604081206113769083612001565b9392505050565b81516020830120600061138f84611083565b905061139c81838561200d565b604080516060808201835265ffffffffffff438116835242811660208085019182526001600160a01b0389811686880181815260008b815260068552899020975188549551915184166c01000000000000000000000000026bffffffffffffffffffffffff9288166601000000000000027fffffffffffffffffffffffffffffffffffffffff00000000000000000000000090971691909716179490941793909316939093179094558583015160a08088015160e08901516101208a01518a516080808d015160c0808f01518e5163ffffffff9095168552918b169c84019c909c52858a169c83019c909c529881019a909a52968901819052918801869052919691959094938716929189917ff8ae392d784b1ea5e8881bfa586d81abf07ef4f1e2fc75f7fe51c90f05199a5c910160405180910390a47fffffffffffffffffffffffff11111111111111111111111111111111111111126001600160a01b0384160161157957801561153b576040517f2598ad2e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b813414611574576040517f81de0bf300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6115c7565b8034146115b2576040517f81de0bf300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6115c76001600160a01b0384163386856121aa565b6101c085015151156115e9576115e4848484886101c00151612226565b6115f9565b34156115f9576115f98434612385565b5050505050505050565b6000600260008481526005602052604090205460ff16600481111561162a5761162a612f4a565b14611661576040517f4145817200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000838152600560205260409020546001600160a01b038381166c0100000000000000000000000090920416146116c4576040517f4af43a9000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b505060009081526005602052604090205461070861010090910464ffffffffff9081164203161190565b6040805161018081018252600080825260208201819052818301819052606082018190526080820181905260a0820181905260c0820181905260e0820181905261010082018190526101208201819052610140820181905261016082015290517f5aa6ccba0000000000000000000000000000000000000000000000000000000081523090635aa6ccba90611787908590600401613916565b600060405180830381865afa9250505080156117c557506040513d6000823e601f3d908101601f191682016040526117c291908101906137e1565b60015b6117dd5781806020019051810190610aff9190613934565b604051806101800160405280826000015163ffffffff168152602001826020015163ffffffff16815260200182604001516001600160a01b0316815260200182606001516001600160a01b0316815260200182608001516001600160a01b031681526020018260a001516001600160a01b031681526020018260c0015181526020018260e001518152602001826101000151815260200182610120015160001415151581526020018261014001518152602001826101600151815250915050919050565b919050565b7f043c983c49d46f0e102151eaf8085d4a2e6571d5df2d47b013f39bddfd4a639d6118d081611e72565b600260008381526005602052604090205460ff1660048111156118f5576118f5612f4a565b1461192c576040517f4145817200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008281526005602052604090205461070890610100900464ffffffffff9081164203161115611988576040517f3e908aac00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000828152600560205260408082206001905551339184917f0695cf1d39b3055dcd0fe02d8b47eaf0d5a13e1996de925de59d0ef9b7f7fad49190a35050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f556119f281611e72565b612710821115611a63576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f6e657746656552617465203e206d61780000000000000000000000000000000060448201526064015b60405180910390fd5b600280549083905560408051828152602081018590527f14914da2bf76024616fbe1859783fcd4dbddcb179b1f3a854949fbf920dcb95791015b60405180910390a1505050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f55611ad481611e72565b600480549083905560408051828152602081018590527f5cf09b12f3f56b4c564d51b25b40360af6d795198adb61ae0806a36c294323fa9101611a9d565b6000816020015142611b249190613a00565b9050611b3183838361244e565b6000611b4584606001518560a001516126d3565b90506000806002541115611b7257620f424060025483611b659190613a28565b611b6f9190613a3f565b90505b611b7c8183613a7a565b91506000604051806101e001604052804663ffffffff168152602001876000015163ffffffff16815260200187602001516001600160a01b0316815260200187604001516001600160a01b0316815260200187606001516001600160a01b0316815260200187608001516001600160a01b031681526020018481526020018760c0015181526020018381526020018660600151815260200187610100015181526020016007600089602001516001600160a01b03166001600160a01b031681526020019081526020016000206000815480929190611c5990613a8d565b91905055815260200186600001516001600160a01b031681526020018581526020018660800151815250604051602001611c9391906133d3565b60408051808303601f1901815282825280516020808301919091206000818152600583529390932080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016600117905589015189516060808c015160808d015160c08e0151928d015195985095966001600160a01b039094169587957f120ea0364f36cdac7983bcfdd55270ca09d7f9b314a2ebc425a3b01ab1d6403a95611d47958b95909493928e9290151590613ac5565b60405180910390a3807f3120e2bb59c86aca6890191a589a96af3662838efa374fbdcdf4c95bfe4a6c0e8760400151604051611d839190613916565b60405180910390a250505050505050565b611080816000610db0565b6000818152600160205260408120610aff906128b4565b600082815260208190526040902060010154611dd181611e72565b610d5e8383611fd4565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f7965db0b000000000000000000000000000000000000000000000000000000001480610aff57507f01ffc9a7000000000000000000000000000000000000000000000000000000007fffffffff00000000000000000000000000000000000000000000000000000000831614610aff565b61108081336128be565b306001600160a01b03831603611e9157505050565b80600003611e9e57505050565b7fffffffffffffffffffffffff11111111111111111111111111111111111111126001600160a01b03841601611f8b576000826001600160a01b03168260405160006040518083038185875af1925050503d8060008114611f1b576040519150601f19603f3d011682016040523d82523d6000602084013e611f20565b606091505b5050905080610d5e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f455448207472616e73666572206661696c6564000000000000000000000000006044820152606401611a5a565b610bc76001600160a01b038416838361292a565b600080611fac848461295b565b90508015611376576000848152600160205260409020611fcc9084612a23565b509392505050565b600080611fe18484612a38565b90508015611376576000848152600160205260409020611fcc9084612ad9565b60006113768383612aee565b6001600160a01b03811661204d576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000828152600660205260409020546c0100000000000000000000000090046001600160a01b0316156120ac576040517fbef7bb7d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b46836020015163ffffffff16146120ef576040517f7029fdf900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b82610140015142111561212e576040517f559895a300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6101808301516001600160a01b0316158015906121625750806001600160a01b03168361018001516001600160a01b031614155b80156121735750826101a001514211155b15610bc7576040517f14be123200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040516001600160a01b038481166024830152838116604483015260648201839052610d5e9186918216906323b872dd906084015b604051602081830303815290604052915060e01b6020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8381831617835250505050612b18565b600083838360405160240161223d93929190613b1b565b60408051601f198184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f461e0c2100000000000000000000000000000000000000000000000000000000179052905060006122a4868334612b94565b905080516000036122e1576040517f1a95ad2600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b805160201461231c576040517ff3725cca00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f461e0c210000000000000000000000000000000000000000000000000000000061234682613b4c565b1461237d576040517ff3725cca00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b505050505050565b804710156123c1576040517fcd786059000000000000000000000000000000000000000000000000000000008152306004820152602401611a5a565b6000826001600160a01b03168260405160006040518083038185875af1925050503d806000811461240e576040519150601f19603f3d011682016040523d82523d6000602084013e612413565b606091505b5050905080610bc7576040517f1425ea4200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b46836000015163ffffffff1603612491576040517f7029fdf900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60a083015115806124a4575060c0830151155b156124db576040517fe38820c800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60208301516001600160a01b03161580612500575060408301516001600160a01b0316155b15612537576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60608301516001600160a01b0316158061255c575060808301516001600160a01b0316155b15612593576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61259f61070842613773565b83610100015110156125dd576040517f04b7fcc800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61ffff826080015151111561261e576040517ffbe24d4900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b606082015115801590612651575060808301516001600160a01b031673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee145b15612688576040517f2598ad2e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008113158061269c575082610100015181135b15610bc7576040517f352807b900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60007fffffffffffffffffffffffff11111111111111111111111111111111111111126001600160a01b038416016127455734821461273e576040517f81de0bf300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5034610aff565b612757836001600160a01b0316612c4a565b341561278f576040517f81de0bf300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201526001600160a01b038416906370a0823190602401602060405180830381865afa1580156127ec573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128109190613b91565b90506128276001600160a01b0384163330856121aa565b6040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015281906001600160a01b038516906370a0823190602401602060405180830381865afa158015612886573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128aa9190613b91565b6113769190613a7a565b6000610aff825490565b6000828152602081815260408083206001600160a01b038516845290915290205460ff16611350576040517fe2517d3f0000000000000000000000000000000000000000000000000000000081526001600160a01b038216600482015260248101839052604401611a5a565b6040516001600160a01b03838116602483015260448201839052610bc791859182169063a9059cbb906064016121df565b6000828152602081815260408083206001600160a01b038516845290915281205460ff16612a1b576000838152602081815260408083206001600160a01b0386168452909152902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790556129d33390565b6001600160a01b0316826001600160a01b0316847f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a4506001610aff565b506000610aff565b6000611376836001600160a01b038416612cf0565b6000828152602081815260408083206001600160a01b038516845290915281205460ff1615612a1b576000838152602081815260408083206001600160a01b038616808552925280832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016905551339286917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a4506001610aff565b6000611376836001600160a01b038416612d37565b6000826000018281548110612b0557612b05613baa565b9060005260206000200154905092915050565b6000612b2d6001600160a01b03841683612e2a565b90508051600014158015612b52575080806020019051810190612b509190613bd9565b155b15610bc7576040517f5274afe70000000000000000000000000000000000000000000000000000000081526001600160a01b0384166004820152602401611a5a565b606081471015612bd2576040517fcd786059000000000000000000000000000000000000000000000000000000008152306004820152602401611a5a565b600080856001600160a01b03168486604051612bee9190613bf6565b60006040518083038185875af1925050503d8060008114612c2b576040519150601f19603f3d011682016040523d82523d6000602084013e612c30565b606091505b5091509150612c40868383612e38565b9695505050505050565b7fffffffffffffffffffffffff11111111111111111111111111111111111111126001600160a01b03821601612cac576040517f7f523fe800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b806001600160a01b03163b600003611080576040517f7f523fe800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000818152600183016020526040812054612a1b57508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155610aff565b60008181526001830160205260408120548015612e20576000612d5b600183613a7a565b8554909150600090612d6f90600190613a7a565b9050808214612dd4576000866000018281548110612d8f57612d8f613baa565b9060005260206000200154905080876000018481548110612db257612db2613baa565b6000918252602080832090910192909255918252600188019052604090208390555b8554869080612de557612de5613c12565b600190038181906000526020600020016000905590558560010160008681526020019081526020016000206000905560019350505050610aff565b6000915050610aff565b606061137683836000612b94565b606082612e4d57612e4882612ead565b611376565b8151158015612e6457506001600160a01b0384163b155b15612ea6576040517f9996b3150000000000000000000000000000000000000000000000000000000081526001600160a01b0385166004820152602401611a5a565b5080611376565b805115612ebd5780518082602001fd5b6040517f1425ea4200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600060208284031215612f0157600080fd5b81357fffffffff000000000000000000000000000000000000000000000000000000008116811461137657600080fd5b600060208284031215612f4357600080fd5b5035919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b60058110612fb0577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b9052565b60208101610aff8284612f79565b6001600160a01b038116811461108057600080fd5b80356118a181612fc2565b60008060408385031215612ff557600080fd5b823561300081612fc2565b9150602083013561301081612fc2565b809150509250929050565b60008060006060848603121561303057600080fd5b8335925060208401359150604084013561304981612fc2565b809150509250925092565b60006020828403121561306657600080fd5b813561137681612fc2565b6000806040838503121561308457600080fd5b82359150602083013561301081612fc2565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051610120810167ffffffffffffffff811182821017156130e9576130e9613096565b60405290565b60405160a0810167ffffffffffffffff811182821017156130e9576130e9613096565b6040516101e0810167ffffffffffffffff811182821017156130e9576130e9613096565b604051610180810167ffffffffffffffff811182821017156130e9576130e9613096565b604051601f8201601f1916810167ffffffffffffffff8111828210171561318357613183613096565b604052919050565b600067ffffffffffffffff8211156131a5576131a5613096565b50601f01601f191660200190565b600082601f8301126131c457600080fd5b81356131d76131d28261318b565b61315a565b8181528460208386010111156131ec57600080fd5b816020850160208301376000918101602001919091529392505050565b6000806040838503121561321c57600080fd5b823567ffffffffffffffff81111561323357600080fd5b61323f858286016131b3565b925050602083013561301081612fc2565b63ffffffff8116811461108057600080fd5b80356118a181613250565b801515811461108057600080fd5b80356118a18161326d565b6000610120828403121561329957600080fd5b6132a16130c5565b90506132ac82613262565b81526132ba60208301612fd7565b60208201526132cb60408301612fd7565b60408201526132dc60608301612fd7565b60608201526132ed60808301612fd7565b608082015260a082013560a082015260c082013560c082015261331260e0830161327b565b60e082015261010080830135818301525092915050565b6000610120828403121561333c57600080fd5b6113768383613286565b60006020828403121561335857600080fd5b813567ffffffffffffffff81111561336f57600080fd5b61337b848285016131b3565b949350505050565b60005b8381101561339e578181015183820152602001613386565b50506000910152565b600081518084526133bf816020860160208601613383565b601f01601f19169290920160200192915050565b602081526133ea60208201835163ffffffff169052565b60006020830151613403604084018263ffffffff169052565b5060408301516001600160a01b03811660608401525060608301516001600160a01b03811660808401525060808301516001600160a01b03811660a08401525060a08301516001600160a01b03811660c08401525060c083015160e08381019190915283015161010080840191909152830151610120808401919091528301516101408084019190915283015161016080840191909152830151610180808401919091528301516101a06134c1818501836001600160a01b03169052565b8401516101c0848101919091528401516101e080850152905061337b6102008401826133a7565b608081016134f68287612f79565b64ffffffffff8516602083015265ffffffffffff841660408301526001600160a01b038316606083015295945050505050565b6000806040838503121561353c57600080fd5b823567ffffffffffffffff81111561355357600080fd5b61355f858286016131b3565b95602094909401359450505050565b6000806040838503121561358157600080fd5b50508035926020909101359150565b815163ffffffff168152610180810160208301516135b6602084018263ffffffff169052565b5060408301516135d160408401826001600160a01b03169052565b5060608301516135ec60608401826001600160a01b03169052565b50608083015161360760808401826001600160a01b03169052565b5060a083015161362260a08401826001600160a01b03169052565b5060c083015160c083015260e083015160e0830152610100808401518184015250610120808401516136578285018215159052565b5050610140838101519083015261016092830151929091019190915290565b600080610140838503121561368a57600080fd5b6136948484613286565b915061012083013567ffffffffffffffff808211156136b257600080fd5b9084019060a082870312156136c657600080fd5b6136ce6130ef565b82356136d981612fc2565b8152602083810135908201526040830135828111156136f757600080fd5b613703888286016131b3565b6040830152506060830135606082015260808301358281111561372557600080fd5b613731888286016131b3565b6080830152508093505050509250929050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b80820180821115610aff57610aff613744565b80516118a181613250565b80516118a181612fc2565b600082601f8301126137ad57600080fd5b81516137bb6131d28261318b565b8181528460208386010111156137d057600080fd5b61337b826020830160208701613383565b6000602082840312156137f357600080fd5b815167ffffffffffffffff8082111561380b57600080fd5b908301906101e0828603121561382057600080fd5b613828613112565b61383183613786565b815261383f60208401613786565b602082015261385060408401613791565b604082015261386160608401613791565b606082015261387260808401613791565b608082015261388360a08401613791565b60a082015260c0838101519082015260e0808401519082015261010080840151908201526101208084015190820152610140808401519082015261016080840151908201526101806138d6818501613791565b908201526101a083810151908201526101c080840151838111156138f957600080fd5b6139058882870161379c565b918301919091525095945050505050565b60208152600061137660208301846133a7565b80516118a18161326d565b6000610180828403121561394757600080fd5b61394f613136565b61395883613786565b815261396660208401613786565b602082015261397760408401613791565b604082015261398860608401613791565b606082015261399960808401613791565b60808201526139aa60a08401613791565b60a082015260c083015160c082015260e083015160e08201526101008084015181830152506101206139dd818501613929565b908201526101408381015190820152610160928301519281019290925250919050565b8082018281126000831280158216821582161715613a2057613a20613744565b505092915050565b8082028115828204841417610aff57610aff613744565b600082613a75577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b81810381811115610aff57610aff613744565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203613abe57613abe613744565b5060010190565b60e081526000613ad860e083018a6133a7565b63ffffffff989098166020830152506001600160a01b039586166040820152939094166060840152608083019190915260a082015290151560c090910152919050565b6001600160a01b0384168152826020820152606060408201526000613b4360608301846133a7565b95945050505050565b80516020808301519190811015613b8b577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8160200360031b1b821691505b50919050565b600060208284031215613ba357600080fd5b5051919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b600060208284031215613beb57600080fd5b81516113768161326d565b60008251613c08818460208701613383565b9190910192915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fdfea2646970667358221220fef42b85b97e95ca087836390d97d99307ec60b38cd20d26ea0f113c18a0660d64736f6c63430008180033", + Bin: "0x60c060405260006080523480156200001657600080fd5b506040516200475c3803806200475c833981016040819052620000399162000199565b806200004760008262000054565b50504360a05250620001c4565b60008062000063848462000091565b90508015620000885760008481526001602052604090206200008690846200013f565b505b90505b92915050565b6000828152602081815260408083206001600160a01b038516845290915281205460ff1662000136576000838152602081815260408083206001600160a01b03861684529091529020805460ff19166001179055620000ed3390565b6001600160a01b0316826001600160a01b0316847f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45060016200008b565b5060006200008b565b600062000088836001600160a01b038416600081815260018301602052604081205462000136575081546001818101845560008481526020808220909301849055845484825282860190935260409020919091556200008b565b600060208284031215620001ac57600080fd5b81516001600160a01b03811681146200008857600080fd5b60805160a051614572620001ea60003960006108b30152600061095401526145726000f3fe60806040526004361061031e5760003560e01c8063886d36ff116101a5578063add98c70116100ec578063c63ff8dd11610095578063ccc574901161006f578063ccc5749014610aad578063d547741f14610ae1578063dcf844a714610b01578063e00a83e014610b2e57600080fd5b8063c63ff8dd146109e0578063c79371b114610a00578063ca15c87314610a8d57600080fd5b8063b250fe6b116100c6578063b250fe6b14610996578063bf333f2c146109b6578063bfc7c607146109cd57600080fd5b8063add98c7014610922578063affed0e014610942578063b13aa2d61461097657600080fd5b80639c9545f01161014e578063a5bbe22b11610128578063a5bbe22b146106ca578063aa9641ab146108d5578063ac11fb1a146108f557600080fd5b80639c9545f014610879578063a217fddf1461088c578063a3ec191a146108a157600080fd5b806391ad50391161017f57806391ad50391461077b57806391d1485414610801578063926d7d7f1461084557600080fd5b8063886d36ff146107285780638f0d6f17146107485780639010d07c1461075b57600080fd5b8063385c1d2f116102695780635960ccf21161021257806363787e52116101ec57806363787e5214610650578063820688d5146106ca5780638379a24f146106e057600080fd5b80635960ccf2146105cf5780635aa6ccba146106035780635eb7d9461461063057600080fd5b80634585169411610243578063458516941461059057806354eff068146105a357806358f85880146105b957600080fd5b8063385c1d2f146105235780633f61331d1461055057806341fcb6121461057057600080fd5b806318e4357d116102cb578063295710ff116102a5578063295710ff146104b65780632f2ff15d146104e357806336568abe1461050357600080fd5b806318e4357d1461044f578063190da5951461046f578063248a9ca31461048657600080fd5b806306f333f2116102fc57806306f333f2146103d75780630f5f6ed7146103f95780630f862f1e1461040f57600080fd5b806301ffc9a71461032357806303ed0ee514610358578063051287bc1461039a575b600080fd5b34801561032f57600080fd5b5061034361033e36600461351e565b610b44565b60405190151581526020015b60405180910390f35b34801561036457600080fd5b5061038c7f043c983c49d46f0e102151eaf8085d4a2e6571d5df2d47b013f39bddfd4a639d81565b60405190815260200161034f565b3480156103a657600080fd5b506103ca6103b5366004613560565b60009081526005602052604090205460ff1690565b60405161034f91906135e3565b3480156103e357600080fd5b506103f76103f2366004613616565b610ba0565b005b34801561040557600080fd5b5061038c61271081565b34801561041b57600080fd5b5061043773eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee81565b6040516001600160a01b03909116815260200161034f565b34801561045b57600080fd5b506103f761046a36600461364f565b610c67565b34801561047b57600080fd5b5061038c62093a8081565b34801561049257600080fd5b5061038c6104a1366004613560565b60009081526020819052604090206001015490565b3480156104c257600080fd5b5061038c6104d1366004613688565b60076020526000908152604090205481565b3480156104ef57600080fd5b506103f76104fe3660046136a5565b610d7c565b34801561050f57600080fd5b506103f761051e3660046136a5565b610da7565b34801561052f57600080fd5b5061054361053e3660046136e3565b610df3565b60405161034f91906137ae565b34801561055c57600080fd5b506103f761056b3660046136e3565b610f81565b34801561057c57600080fd5b506103f761058b36600461388d565b61102b565b6103f761059e366004613a8e565b61129d565b3480156105af57600080fd5b5061038c61ffff81565b3480156105c557600080fd5b5061038c60025481565b3480156105db57600080fd5b5061038c7fdb9556138406326f00296e13ea2ad7db24ba82381212d816b1a40c23b466b32781565b34801561060f57600080fd5b5061062361061e366004613aab565b6112fa565b60405161034f9190613aed565b34801561063c57600080fd5b506103f761064b366004613aab565b6113c7565b34801561065c57600080fd5b506106ba61066b366004613560565b60056020526000908152604090205460ff811690610100810463ffffffff169065010000000000810466ffffffffffffff16906c0100000000000000000000000090046001600160a01b031684565b60405161034f9493929190613c0a565b3480156106d657600080fd5b5061038c61070881565b3480156106ec57600080fd5b506103436106fb366004613560565b6000908152600660205260409020546c0100000000000000000000000090046001600160a01b0316151590565b34801561073457600080fd5b506103f7610743366004613c4b565b6115c9565b6103f7610756366004613aab565b6115f5565b34801561076757600080fd5b50610437610776366004613c97565b611604565b34801561078757600080fd5b506107d5610796366004613560565b60009081526005602052604090205465010000000000810466ffffffffffffff16916c010000000000000000000000009091046001600160a01b031690565b604080516bffffffffffffffffffffffff90931683526001600160a01b0390911660208301520161034f565b34801561080d57600080fd5b5061034361081c3660046136a5565b6000918252602082815260408084206001600160a01b0393909316845291905290205460ff1690565b34801561085157600080fd5b5061038c7fe2b7fb3b832174769106daebcfd6d1970523240dda11281102db9363b83b0dc481565b6103f761088736600461388d565b61161c565b34801561089857600080fd5b5061038c600081565b3480156108ad57600080fd5b5061038c7f000000000000000000000000000000000000000000000000000000000000000081565b3480156108e157600080fd5b506103436108f03660046136a5565b6118d6565b34801561090157600080fd5b50610915610910366004613aab565b6119ad565b60405161034f9190613cb9565b34801561092e57600080fd5b506103f761093d366004613560565b611b61565b34801561094e57600080fd5b5061038c7f000000000000000000000000000000000000000000000000000000000000000081565b34801561098257600080fd5b506103f7610991366004613560565b611cab565b3480156109a257600080fd5b506103f76109b1366004613560565b611d8d565b3480156109c257600080fd5b5061038c620f424081565b6103f76109db366004613e1d565b611df5565b3480156109ec57600080fd5b506103f76109fb366004613aab565b612084565b348015610a0c57600080fd5b50610a5f610a1b366004613560565b60066020526000908152604090205465ffffffffffff8082169166010000000000008104909116906c0100000000000000000000000090046001600160a01b031683565b6040805165ffffffffffff94851681529390921660208401526001600160a01b03169082015260600161034f565b348015610a9957600080fd5b5061038c610aa8366004613560565b612090565b348015610ab957600080fd5b5061038c7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f5581565b348015610aed57600080fd5b506103f7610afc3660046136a5565b6120a7565b348015610b0d57600080fd5b5061038c610b1c366004613688565b60036020526000908152604090205481565b348015610b3a57600080fd5b5061038c60045481565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f5a05180f000000000000000000000000000000000000000000000000000000001480610b9a5750610b9a826120cc565b92915050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f55610bca81612163565b6001600160a01b03831660009081526003602052604081205490819003610bf15750505050565b6001600160a01b038416600081815260036020526040812055610c1590848361216d565b604080516001600160a01b038087168252851660208201529081018290527f244e51bc38c1452fa8aaf487bcb4bca36c2baa3a5fbdb776b1eabd8dc6d277cd9060600160405180910390a1505b505050565b7fe2b7fb3b832174769106daebcfd6d1970523240dda11281102db9363b83b0dc4610c9181612163565b60008481526005602052604090206001815460ff166004811115610cb757610cb7613579565b14610cee576040517f4145817200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80546001600160a01b0384166c0100000000000000000000000081026bffffffffffffffffffffffff66ffffffffffffff421665010000000000021664ffffffff009093169290921791909117600217825560405185815286907f4ac8af8a2cd87193d64dfc7a3b8d9923b714ec528b18725d080aa1299be0c5e49060200160405180910390a35050505050565b600082815260208190526040902060010154610d9781612163565b610da18383612290565b50505050565b6001600160a01b0381163314610de9576040517f6697b23200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610c6282826122bd565b60608267ffffffffffffffff811115610e0e57610e0e6138d9565b604051908082528060200260200182016040528015610e5457816020015b604080518082019091526000815260606020820152815260200190600190039081610e2c5790505b50905060005b83811015610f795730858583818110610e7557610e75613eeb565b9050602002810190610e879190613f1a565b604051610e95929190613f7f565b600060405180830381855af49150503d8060008114610ed0576040519150601f19603f3d011682016040523d82523d6000602084013e610ed5565b606091505b50838381518110610ee857610ee8613eeb565b6020026020010151600001848481518110610f0557610f05613eeb565b602002602001015160200182905282151515158152505050818181518110610f2f57610f2f613eeb565b602002602001015160000151158015610f46575082155b15610f7157610f71828281518110610f6057610f60613eeb565b6020026020010151602001516122ea565b600101610e5a565b509392505050565b60005b82811015610da15760008030868685818110610fa257610fa2613eeb565b9050602002810190610fb49190613f1a565b604051610fc2929190613f7f565b600060405180830381855af49150503d8060008114610ffd576040519150601f19603f3d011682016040523d82523d6000602084013e611002565b606091505b509150915081158015611013575083155b1561102157611021816122ea565b5050600101610f84565b611035838361232c565b60008383604051611047929190613f7f565b604080519182900390912060008181526005602052919091208054919250906c0100000000000000000000000081046001600160a01b03169060ff81169065010000000000900466ffffffffffffff1660028260048111156110ab576110ab613579565b146110e2576040517f4145817200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6107084282900366ffffffffffffff1611611129576040517f1992d0bd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600160a01b03861661113f57829550611181565b6001600160a01b0383163314611181576040517f4af43a9000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b83547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166003178455603288013560601c605a890135609a8a013580156111f0576001600160a01b038316600090815260036020526040812080548392906111ea908490613fbe565b90915550505b604080516001600160a01b03858116825260208201859052808c1692908916918b917f582211c35a2139ac3bbaac74663c6a1f56c6cbb658b41fe11fd45a82074ac678910160405180910390a47fffffffffffffffffffffffff11111111111111111111111111111111111111126001600160a01b0384160161127c5761127789836123ad565b611290565b6112906001600160a01b0384168a84612476565b5050505050505050505050565b6112f7816040518060a0016040528060006001600160a01b03168152602001600081526020016040518060200160405280600081525081526020016000815260200160405180602001604052806000815250815250611df5565b50565b6113ac604051806101e00160405280600063ffffffff168152602001600063ffffffff16815260200160006001600160a01b0316815260200160006001600160a01b0316815260200160006001600160a01b0316815260200160006001600160a01b03168152602001600081526020016000815260200160008152602001600081526020016000815260200160006001600160a01b031681526020016000815260200160008152602001606081525090565b6113b6838361232c565b6113c083836124ea565b9392505050565b6113d1828261232c565b600082826040516113e3929190613f7f565b604080519182900390912060008181526005602052919091209091506001815460ff16600481111561141757611417613579565b1461144e576040517f4145817200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b3360009081527fd2043bf65931af3dbecf60d0db8f40e4160406d7beb00522f4200cf4944a1eb8602052604090205460ba8501359060ff1661149a5761149762093a8082613fbe565b90505b8042116114d3576040517fe15ff9ea00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b81547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166004178255600a850135606090811c906032870135901c6000611522609a890135605a8a0135613fbe565b604080516001600160a01b03858116825260208201849052825193945086169289927fb4c55c0c9bc613519b920e88748090150b890a875d307f21bea7d4fb2e8bc958928290030190a37fffffffffffffffffffffffff11111111111111111111111111111111111111126001600160a01b038316016115ab576115a683826123ad565b6115bf565b6115bf6001600160a01b0383168483612476565b5050505050505050565b6115d3838361232c565b610c6283836040516115e6929190613f7f565b60405180910390208233610c67565b61160082823361161c565b5050565b60008281526001602052604081206113c0908361268c565b611626838361232c565b60008383604051611638929190613f7f565b6040518091039020905061164e84848385612698565b6040805160608101825265ffffffffffff438116825242811660208084019182526001600160a01b038088168587019081526000888152600690935295822094518554935196519091166c01000000000000000000000000026bffffffffffffffffffffffff9685166601000000000000027fffffffffffffffffffffffffffffffffffffffff0000000000000000000000009094169190941617919091179390931617905561170285601e013560601c90565b9050604685013560601c607a86013561012e8701356001600160a01b03808516908716867ff8ae392d784b1ea5e8881bfa586d81abf07ef4f1e2fc75f7fe51c90f05199a5c60028c013560e01c6040805163ffffffff92909216825260328e0135606090811c60208401526001600160a01b038a1683830152605a8f0135908301526080820188905260a08201879052519081900360c00190a47fffffffffffffffffffffffff11111111111111111111111111111111111111126001600160a01b03841601611842578015611804576040517f846dedc000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b81341461183d576040517f81de0bf300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611890565b80341461187b576040517f81de0bf300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6118906001600160a01b03841633868561282d565b36600061189d8a8a612866565b909250905080156118ba576118b58686868585612882565b6118ca565b34156118ca576118ca86346123ad565b50505050505050505050565b60008281526005602052604081206002815460ff1660048111156118fc576118fc613579565b14611933576040517f4145817200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80546001600160a01b038481166c010000000000000000000000009092041614611989576040517f4af43a9000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b546107086501000000000090910466ffffffffffffff908116420316119392505050565b6040805161018081018252600080825260208201819052818301819052606082018190526080820181905260a0820181905260c0820181905260e0820181905261010082018190526101208201819052610140820181905261016082015290517f5aa6ccba0000000000000000000000000000000000000000000000000000000081523090635aa6ccba90611a489086908690600401613ffc565b600060405180830381865afa925050508015611a8657506040513d6000823e601f3d908101601f19168201604052611a83919081019061406b565b60015b611a9d57611a96828401846141a0565b9050610b9a565b604051806101800160405280826000015163ffffffff168152602001826020015163ffffffff16815260200182604001516001600160a01b0316815260200182606001516001600160a01b0316815260200182608001516001600160a01b031681526020018260a001516001600160a01b031681526020018260c0015181526020018260e0015181526020018261010001518152602001826101a0015160001415151581526020018261012001518152602001826101400151815250915050610b9a565b7f043c983c49d46f0e102151eaf8085d4a2e6571d5df2d47b013f39bddfd4a639d611b8b81612163565b600082815260056020526040902080546c0100000000000000000000000081046001600160a01b03169060ff81169065010000000000900466ffffffffffffff166002826004811115611be057611be0613579565b14611c17576040517f4145817200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6107084282900366ffffffffffffff161115611c5f576040517f3e908aac00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b835464ffffffff001660011784556040516001600160a01b0384169087907f0695cf1d39b3055dcd0fe02d8b47eaf0d5a13e1996de925de59d0ef9b7f7fad490600090a3505050505050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f55611cd581612163565b612710821115611d46576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f6e657746656552617465203e206d61780000000000000000000000000000000060448201526064015b60405180910390fd5b600280549083905560408051828152602081018590527f14914da2bf76024616fbe1859783fcd4dbddcb179b1f3a854949fbf920dcb95791015b60405180910390a1505050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f55611db781612163565b600480549083905560408051828152602081018590527f5cf09b12f3f56b4c564d51b25b40360af6d795198adb61ae0806a36c294323fa9101611d80565b80516000906001600160a01b031615611e1a576020820151611e17904261426c565b90505b611e258383836129de565b6000611e3984606001518560a00151612c62565b90506000806002541115611e7257620f424060025483611e599190614294565b611e6391906142ab565b9050611e6f81836142e6565b91505b6000611f7b604051806101e001604052804663ffffffff168152602001886000015163ffffffff16815260200188602001516001600160a01b0316815260200188604001516001600160a01b0316815260200188606001516001600160a01b0316815260200188608001516001600160a01b031681526020018581526020018860c0015181526020018481526020018861010001518152602001600760008a602001516001600160a01b03166001600160a01b031681526020019081526020016000206000815480929190611f46906142f9565b90915550815287516001600160a01b031660208201526040810187905260608089015190820152608080890151910152612e75565b805160208083019190912060008181526005835260409081902080548b5163ffffffff8116610100027fffffffffffffffffffffffffffffffffffffffffffffffffffffff000000000090921691909117600117909155928a01516060808c015160808d015160c08e0151928d0151945197985094966001600160a01b039093169587957f120ea0364f36cdac7983bcfdd55270ca09d7f9b314a2ebc425a3b01ab1d6403a95612037958b959394938e92909190151590614331565b60405180910390a3807f3120e2bb59c86aca6890191a589a96af3662838efa374fbdcdf4c95bfe4a6c0e87604001516040516120739190614387565b60405180910390a250505050505050565b6116008282600061102b565b6000818152600160205260408120610b9a90612fba565b6000828152602081905260409020600101546120c281612163565b610da183836122bd565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f7965db0b000000000000000000000000000000000000000000000000000000001480610b9a57507f01ffc9a7000000000000000000000000000000000000000000000000000000007fffffffff00000000000000000000000000000000000000000000000000000000831614610b9a565b6112f78133612fc4565b306001600160a01b0383160361218257505050565b8060000361218f57505050565b7fffffffffffffffffffffffff11111111111111111111111111111111111111126001600160a01b0384160161227c576000826001600160a01b03168260405160006040518083038185875af1925050503d806000811461220c576040519150601f19603f3d011682016040523d82523d6000602084013e612211565b606091505b5050905080610da1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f455448207472616e73666572206661696c6564000000000000000000000000006044820152606401611d3d565b610c626001600160a01b0384168383612476565b60008061229d8484613030565b905080156113c0576000848152600160205260409020610f7990846130f8565b6000806122ca848461310d565b905080156113c0576000848152600160205260409020610f7990846131ae565b8051156122fa5780518082602001fd5b6040517f5ead5a9d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61014e811015612368576040517f6ee0e17100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b813560f01c60028114610c62576040517f8bd977e700000000000000000000000000000000000000000000000000000000815261ffff82166004820152602401611d3d565b804710156123e9576040517fcd786059000000000000000000000000000000000000000000000000000000008152306004820152602401611d3d565b6000826001600160a01b03168260405160006040518083038185875af1925050503d8060008114612436576040519150601f19603f3d011682016040523d82523d6000602084013e61243b565b606091505b5050905080610c62576040517f1425ea4200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040516001600160a01b03838116602483015260448201839052610c6291859182169063a9059cbb906064015b604051602081830303815290604052915060e01b6020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff83818316178352505050506131c3565b61259c604051806101e00160405280600063ffffffff168152602001600063ffffffff16815260200160006001600160a01b0316815260200160006001600160a01b0316815260200160006001600160a01b0316815260200160006001600160a01b03168152602001600081526020016000815260200160008152602001600081526020016000815260200160006001600160a01b031681526020016000815260200160008152602001606081525090565b600283013560e090811c82526006840135811c6020830152600a840135606090811c6040840152601e850135811c818401526032850135811c60808401526046850135811c60a0840152605a85013560c0840152607a85013591830191909152609a84013561010083015260ba84013561012083015260da84013561014083015260fa840135901c61016082015261010e83013561018082015261012e8301356101a082015261264c8383612866565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152505050506101c082015292915050565b60006113c0838361323f565b6001600160a01b0381166126d8576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000828152600660205260409020546c0100000000000000000000000090046001600160a01b031615612737576040517fbef7bb7d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600684013560e01c4614612777576040517f7029fdf900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60ba8401354211156127b5576040517f559895a300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60fa84013560601c80158015906127de5750816001600160a01b0316816001600160a01b031614155b80156127ef575061010e8501354211155b15612826576040517f14be123200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5050505050565b6040516001600160a01b038481166024830152838116604483015260648201839052610da19186918216906323b872dd906084016124a3565b3660006128778361014e818761439a565b915091509250929050565b60006128fd868686868660405160240161289f94939291906143c4565b60408051601f198184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fe85e13dd0000000000000000000000000000000000000000000000000000000017905234613269565b9050805160000361293a576040517f1a95ad2600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8051602014612975576040517ff3725cca00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7fe85e13dd0000000000000000000000000000000000000000000000000000000061299f826143ed565b146129d6576040517ff3725cca00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b505050505050565b46836000015163ffffffff1603612a21576040517f7029fdf900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60a08301511580612a34575060c0830151155b15612a6b576040517fe38820c800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60208301516001600160a01b03161580612a90575060408301516001600160a01b0316155b15612ac7576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60608301516001600160a01b03161580612aec575060808301516001600160a01b0316155b15612b23576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b612b2f61070842613fbe565b8361010001511015612b6d576040517f04b7fcc800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61ffff8260800151511115612bae576040517f177a70e100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b606082015115801590612be1575060808301516001600160a01b031673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee145b15612c18576040517f846dedc000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000811280612c2b575082610100015181135b15610c62576040517f352807b900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60007fffffffffffffffffffffffff11111111111111111111111111111111111111126001600160a01b03841601612cd457348214612ccd576040517f81de0bf300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5034610b9a565b3415612d0c576040517f81de0bf300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b826001600160a01b03163b600003612d50576040517f7f523fe800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201526001600160a01b038416906370a0823190602401602060405180830381865afa158015612dad573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612dd19190614432565b9050612de86001600160a01b03841633308561282d565b6040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015281906001600160a01b038516906370a0823190602401602060405180830381865afa158015612e47573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612e6b9190614432565b6113c091906142e6565b8051602080830151604080850151606086810151608088015160a089015160c08a015195517e02000000000000000000000000000000000000000000000000000000000000988101989098527fffffffff0000000000000000000000000000000000000000000000000000000060e0998a1b811660228a01529690981b90951660268701527fffffffffffffffffffffffffffffffffffffffff00000000000000000000000092821b8316602a870152811b8216603e86015292831b8116605285015293821b9093166066830152607a820192909252600090609a0160408051601f198184030181529082905260e08501516101008601516101208701516101408801516101608901516101808a01516101a08b01516101c08c0151979950612fa3988a989060200161444b565b604051602081830303815290604052915050919050565b6000610b9a825490565b6000828152602081815260408083206001600160a01b038516845290915290205460ff16611600576040517fe2517d3f0000000000000000000000000000000000000000000000000000000081526001600160a01b038216600482015260248101839052604401611d3d565b6000828152602081815260408083206001600160a01b038516845290915281205460ff166130f0576000838152602081815260408083206001600160a01b0386168452909152902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790556130a83390565b6001600160a01b0316826001600160a01b0316847f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a4506001610b9a565b506000610b9a565b60006113c0836001600160a01b03841661331f565b6000828152602081815260408083206001600160a01b038516845290915281205460ff16156130f0576000838152602081815260408083206001600160a01b038616808552925280832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016905551339286917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a4506001610b9a565b60006113c0836001600160a01b038416613366565b60006131d86001600160a01b03841683613459565b905080516000141580156131fd5750808060200190518101906131fb91906144d4565b155b15610c62576040517f5274afe70000000000000000000000000000000000000000000000000000000081526001600160a01b0384166004820152602401611d3d565b600082600001828154811061325657613256613eeb565b9060005260206000200154905092915050565b6060814710156132a7576040517fcd786059000000000000000000000000000000000000000000000000000000008152306004820152602401611d3d565b600080856001600160a01b031684866040516132c391906144f1565b60006040518083038185875af1925050503d8060008114613300576040519150601f19603f3d011682016040523d82523d6000602084013e613305565b606091505b5091509150613315868383613467565b9695505050505050565b60008181526001830160205260408120546130f057508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155610b9a565b6000818152600183016020526040812054801561344f57600061338a6001836142e6565b855490915060009061339e906001906142e6565b90508082146134035760008660000182815481106133be576133be613eeb565b90600052602060002001549050808760000184815481106133e1576133e1613eeb565b6000918252602080832090910192909255918252600188019052604090208390555b85548690806134145761341461450d565b600190038181906000526020600020016000905590558560010160008681526020019081526020016000206000905560019350505050610b9a565b6000915050610b9a565b60606113c083836000613269565b60608261347c57613477826134dc565b6113c0565b815115801561349357506001600160a01b0384163b155b156134d5576040517f9996b3150000000000000000000000000000000000000000000000000000000081526001600160a01b0385166004820152602401611d3d565b50806113c0565b8051156134ec5780518082602001fd5b6040517f1425ea4200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006020828403121561353057600080fd5b81357fffffffff00000000000000000000000000000000000000000000000000000000811681146113c057600080fd5b60006020828403121561357257600080fd5b5035919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b600581106135df577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b9052565b60208101610b9a82846135a8565b6001600160a01b03811681146112f757600080fd5b8035613611816135f1565b919050565b6000806040838503121561362957600080fd5b8235613634816135f1565b91506020830135613644816135f1565b809150509250929050565b60008060006060848603121561366457600080fd5b8335925060208401359150604084013561367d816135f1565b809150509250925092565b60006020828403121561369a57600080fd5b81356113c0816135f1565b600080604083850312156136b857600080fd5b823591506020830135613644816135f1565b80151581146112f757600080fd5b8035613611816136ca565b6000806000604084860312156136f857600080fd5b833567ffffffffffffffff8082111561371057600080fd5b818601915086601f83011261372457600080fd5b81358181111561373357600080fd5b8760208260051b850101111561374857600080fd5b6020928301955093505084013561367d816136ca565b60005b83811015613779578181015183820152602001613761565b50506000910152565b6000815180845261379a81602086016020860161375e565b601f01601f19169290920160200192915050565b600060208083018184528085518083526040925060408601915060408160051b87010184880160005b83811015613836578883037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc0018552815180511515845287015187840187905261382387850182613782565b95880195935050908601906001016137d7565b509098975050505050505050565b60008083601f84011261385657600080fd5b50813567ffffffffffffffff81111561386e57600080fd5b60208301915083602082850101111561388657600080fd5b9250929050565b6000806000604084860312156138a257600080fd5b833567ffffffffffffffff8111156138b957600080fd5b6138c586828701613844565b909450925050602084013561367d816135f1565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051610120810167ffffffffffffffff8111828210171561392c5761392c6138d9565b60405290565b60405160a0810167ffffffffffffffff8111828210171561392c5761392c6138d9565b6040516101e0810167ffffffffffffffff8111828210171561392c5761392c6138d9565b604051610180810167ffffffffffffffff8111828210171561392c5761392c6138d9565b604051601f8201601f1916810167ffffffffffffffff811182821017156139c6576139c66138d9565b604052919050565b63ffffffff811681146112f757600080fd5b8035613611816139ce565b600061012082840312156139fe57600080fd5b613a06613908565b9050613a11826139e0565b8152613a1f60208301613606565b6020820152613a3060408301613606565b6040820152613a4160608301613606565b6060820152613a5260808301613606565b608082015260a082013560a082015260c082013560c0820152613a7760e083016136d8565b60e082015261010080830135818301525092915050565b60006101208284031215613aa157600080fd5b6113c083836139eb565b60008060208385031215613abe57600080fd5b823567ffffffffffffffff811115613ad557600080fd5b613ae185828601613844565b90969095509350505050565b60208152613b0460208201835163ffffffff169052565b60006020830151613b1d604084018263ffffffff169052565b5060408301516001600160a01b03811660608401525060608301516001600160a01b03811660808401525060808301516001600160a01b03811660a08401525060a08301516001600160a01b03811660c08401525060c083015160e08381019190915283015161010080840191909152830151610120808401919091528301516101408084019190915283015161016080840191909152830151610180613bce818501836001600160a01b03169052565b8401516101a0848101919091528401516101c0808501919091528401516101e0808501529050613c02610200840182613782565b949350505050565b60808101613c1882876135a8565b63ffffffff8516602083015266ffffffffffffff841660408301526001600160a01b038316606083015295945050505050565b600080600060408486031215613c6057600080fd5b833567ffffffffffffffff811115613c7757600080fd5b613c8386828701613844565b909790965060209590950135949350505050565b60008060408385031215613caa57600080fd5b50508035926020909101359150565b815163ffffffff16815261018081016020830151613cdf602084018263ffffffff169052565b506040830151613cfa60408401826001600160a01b03169052565b506060830151613d1560608401826001600160a01b03169052565b506080830151613d3060808401826001600160a01b03169052565b5060a0830151613d4b60a08401826001600160a01b03169052565b5060c083015160c083015260e083015160e083015261010080840151818401525061012080840151613d808285018215159052565b5050610140838101519083015261016092830151929091019190915290565b600067ffffffffffffffff821115613db957613db96138d9565b50601f01601f191660200190565b600082601f830112613dd857600080fd5b8135613deb613de682613d9f565b61399d565b818152846020838601011115613e0057600080fd5b816020850160208301376000918101602001919091529392505050565b6000806101408385031215613e3157600080fd5b613e3b84846139eb565b915061012083013567ffffffffffffffff80821115613e5957600080fd5b9084019060a08287031215613e6d57600080fd5b613e75613932565b8235613e80816135f1565b815260208381013590820152604083013582811115613e9e57600080fd5b613eaa88828601613dc7565b60408301525060608301356060820152608083013582811115613ecc57600080fd5b613ed888828601613dc7565b6080830152508093505050509250929050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112613f4f57600080fd5b83018035915067ffffffffffffffff821115613f6a57600080fd5b60200191503681900382131561388657600080fd5b8183823760009101908152919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b80820180821115610b9a57610b9a613f8f565b818352818160208501375060006020828401015260006020601f19601f840116840101905092915050565b602081526000613c02602083018486613fd1565b8051613611816139ce565b8051613611816135f1565b600082601f83011261403757600080fd5b8151614045613de682613d9f565b81815284602083860101111561405a57600080fd5b613c0282602083016020870161375e565b60006020828403121561407d57600080fd5b815167ffffffffffffffff8082111561409557600080fd5b908301906101e082860312156140aa57600080fd5b6140b2613955565b6140bb83614010565b81526140c960208401614010565b60208201526140da6040840161401b565b60408201526140eb6060840161401b565b60608201526140fc6080840161401b565b608082015261410d60a0840161401b565b60a082015260c0838101519082015260e0808401519082015261010080840151908201526101208084015190820152610140808401519082015261016061415581850161401b565b9082015261018083810151908201526101a080840151908201526101c0808401518381111561418357600080fd5b61418f88828701614026565b918301919091525095945050505050565b600061018082840312156141b357600080fd5b6141bb613979565b6141c4836139e0565b81526141d2602084016139e0565b60208201526141e360408401613606565b60408201526141f460608401613606565b606082015261420560808401613606565b608082015261421660a08401613606565b60a082015260c083013560c082015260e083013560e08201526101008084013581830152506101206142498185016136d8565b908201526101408381013590820152610160928301359281019290925250919050565b808201828112600083128015821682158216171561428c5761428c613f8f565b505092915050565b8082028115828204841417610b9a57610b9a613f8f565b6000826142e1577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b81810381811115610b9a57610b9a613f8f565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820361432a5761432a613f8f565b5060010190565b60e08152600061434460e083018a613782565b63ffffffff989098166020830152506001600160a01b039586166040820152939094166060840152608083019190915260a082015290151560c090910152919050565b6020815260006113c06020830184613782565b600080858511156143aa57600080fd5b838611156143b757600080fd5b5050820193919092039150565b6001600160a01b0385168152836020820152606060408201526000613315606083018486613fd1565b8051602080830151919081101561442c577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8160200360031b1b821691505b50919050565b60006020828403121561444457600080fd5b5051919050565b60008a5161445d818460208f0161375e565b80830190508a81528960208201528860408201528760608201527fffffffffffffffffffffffffffffffffffffffff0000000000000000000000008760601b1660808201528560948201528460b482015283516144c18160d484016020880161375e565b0160d4019b9a5050505050505050505050565b6000602082840312156144e657600080fd5b81516113c0816136ca565b6000825161450381846020870161375e565b9190910192915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fdfea26469706673582212209a48ddc6013fa0ddcb3b8a930e8c7e75c40dab4d351f72ddd07978c3a1539f2764736f6c63430008180033", } // FastBridgeV2ABI is the input ABI used to generate the binding from. @@ -4604,12 +4786,12 @@ func (_FastBridgeV2 *FastBridgeV2CallerSession) GUARDROLE() ([32]byte, error) { return _FastBridgeV2.Contract.GUARDROLE(&_FastBridgeV2.CallOpts) } -// MAXCALLPARAMSLENGTH is a free data retrieval call binding the contract method 0xdf36bb13. +// MAXZAPDATALENGTH is a free data retrieval call binding the contract method 0x54eff068. // -// Solidity: function MAX_CALL_PARAMS_LENGTH() view returns(uint256) -func (_FastBridgeV2 *FastBridgeV2Caller) MAXCALLPARAMSLENGTH(opts *bind.CallOpts) (*big.Int, error) { +// Solidity: function MAX_ZAP_DATA_LENGTH() view returns(uint256) +func (_FastBridgeV2 *FastBridgeV2Caller) MAXZAPDATALENGTH(opts *bind.CallOpts) (*big.Int, error) { var out []interface{} - err := _FastBridgeV2.contract.Call(opts, &out, "MAX_CALL_PARAMS_LENGTH") + err := _FastBridgeV2.contract.Call(opts, &out, "MAX_ZAP_DATA_LENGTH") if err != nil { return *new(*big.Int), err @@ -4621,18 +4803,18 @@ func (_FastBridgeV2 *FastBridgeV2Caller) MAXCALLPARAMSLENGTH(opts *bind.CallOpts } -// MAXCALLPARAMSLENGTH is a free data retrieval call binding the contract method 0xdf36bb13. +// MAXZAPDATALENGTH is a free data retrieval call binding the contract method 0x54eff068. // -// Solidity: function MAX_CALL_PARAMS_LENGTH() view returns(uint256) -func (_FastBridgeV2 *FastBridgeV2Session) MAXCALLPARAMSLENGTH() (*big.Int, error) { - return _FastBridgeV2.Contract.MAXCALLPARAMSLENGTH(&_FastBridgeV2.CallOpts) +// Solidity: function MAX_ZAP_DATA_LENGTH() view returns(uint256) +func (_FastBridgeV2 *FastBridgeV2Session) MAXZAPDATALENGTH() (*big.Int, error) { + return _FastBridgeV2.Contract.MAXZAPDATALENGTH(&_FastBridgeV2.CallOpts) } -// MAXCALLPARAMSLENGTH is a free data retrieval call binding the contract method 0xdf36bb13. +// MAXZAPDATALENGTH is a free data retrieval call binding the contract method 0x54eff068. // -// Solidity: function MAX_CALL_PARAMS_LENGTH() view returns(uint256) -func (_FastBridgeV2 *FastBridgeV2CallerSession) MAXCALLPARAMSLENGTH() (*big.Int, error) { - return _FastBridgeV2.Contract.MAXCALLPARAMSLENGTH(&_FastBridgeV2.CallOpts) +// Solidity: function MAX_ZAP_DATA_LENGTH() view returns(uint256) +func (_FastBridgeV2 *FastBridgeV2CallerSession) MAXZAPDATALENGTH() (*big.Int, error) { + return _FastBridgeV2.Contract.MAXZAPDATALENGTH(&_FastBridgeV2.CallOpts) } // MINDEADLINEPERIOD is a free data retrieval call binding the contract method 0x820688d5. @@ -4666,6 +4848,37 @@ func (_FastBridgeV2 *FastBridgeV2CallerSession) MINDEADLINEPERIOD() (*big.Int, e return _FastBridgeV2.Contract.MINDEADLINEPERIOD(&_FastBridgeV2.CallOpts) } +// NATIVEGASTOKEN is a free data retrieval call binding the contract method 0x0f862f1e. +// +// Solidity: function NATIVE_GAS_TOKEN() view returns(address) +func (_FastBridgeV2 *FastBridgeV2Caller) NATIVEGASTOKEN(opts *bind.CallOpts) (common.Address, error) { + var out []interface{} + err := _FastBridgeV2.contract.Call(opts, &out, "NATIVE_GAS_TOKEN") + + if err != nil { + return *new(common.Address), err + } + + out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) + + return out0, err + +} + +// NATIVEGASTOKEN is a free data retrieval call binding the contract method 0x0f862f1e. +// +// Solidity: function NATIVE_GAS_TOKEN() view returns(address) +func (_FastBridgeV2 *FastBridgeV2Session) NATIVEGASTOKEN() (common.Address, error) { + return _FastBridgeV2.Contract.NATIVEGASTOKEN(&_FastBridgeV2.CallOpts) +} + +// NATIVEGASTOKEN is a free data retrieval call binding the contract method 0x0f862f1e. +// +// Solidity: function NATIVE_GAS_TOKEN() view returns(address) +func (_FastBridgeV2 *FastBridgeV2CallerSession) NATIVEGASTOKEN() (common.Address, error) { + return _FastBridgeV2.Contract.NATIVEGASTOKEN(&_FastBridgeV2.CallOpts) +} + // REFUNDERROLE is a free data retrieval call binding the contract method 0x5960ccf2. // // Solidity: function REFUNDER_ROLE() view returns(bytes32) @@ -4918,11 +5131,11 @@ func (_FastBridgeV2 *FastBridgeV2CallerSession) BridgeStatuses(transactionId [32 // BridgeTxDetails is a free data retrieval call binding the contract method 0x63787e52. // -// Solidity: function bridgeTxDetails(bytes32 ) view returns(uint8 status, uint40 proofBlockTimestamp, uint48 proofBlockNumber, address proofRelayer) +// Solidity: function bridgeTxDetails(bytes32 ) view returns(uint8 status, uint32 destChainId, uint56 proofBlockTimestamp, address proofRelayer) func (_FastBridgeV2 *FastBridgeV2Caller) BridgeTxDetails(opts *bind.CallOpts, arg0 [32]byte) (struct { Status uint8 + DestChainId uint32 ProofBlockTimestamp *big.Int - ProofBlockNumber *big.Int ProofRelayer common.Address }, error) { var out []interface{} @@ -4930,8 +5143,8 @@ func (_FastBridgeV2 *FastBridgeV2Caller) BridgeTxDetails(opts *bind.CallOpts, ar outstruct := new(struct { Status uint8 + DestChainId uint32 ProofBlockTimestamp *big.Int - ProofBlockNumber *big.Int ProofRelayer common.Address }) if err != nil { @@ -4939,8 +5152,8 @@ func (_FastBridgeV2 *FastBridgeV2Caller) BridgeTxDetails(opts *bind.CallOpts, ar } outstruct.Status = *abi.ConvertType(out[0], new(uint8)).(*uint8) - outstruct.ProofBlockTimestamp = *abi.ConvertType(out[1], new(*big.Int)).(**big.Int) - outstruct.ProofBlockNumber = *abi.ConvertType(out[2], new(*big.Int)).(**big.Int) + outstruct.DestChainId = *abi.ConvertType(out[1], new(uint32)).(*uint32) + outstruct.ProofBlockTimestamp = *abi.ConvertType(out[2], new(*big.Int)).(**big.Int) outstruct.ProofRelayer = *abi.ConvertType(out[3], new(common.Address)).(*common.Address) return *outstruct, err @@ -4949,11 +5162,11 @@ func (_FastBridgeV2 *FastBridgeV2Caller) BridgeTxDetails(opts *bind.CallOpts, ar // BridgeTxDetails is a free data retrieval call binding the contract method 0x63787e52. // -// Solidity: function bridgeTxDetails(bytes32 ) view returns(uint8 status, uint40 proofBlockTimestamp, uint48 proofBlockNumber, address proofRelayer) +// Solidity: function bridgeTxDetails(bytes32 ) view returns(uint8 status, uint32 destChainId, uint56 proofBlockTimestamp, address proofRelayer) func (_FastBridgeV2 *FastBridgeV2Session) BridgeTxDetails(arg0 [32]byte) (struct { Status uint8 + DestChainId uint32 ProofBlockTimestamp *big.Int - ProofBlockNumber *big.Int ProofRelayer common.Address }, error) { return _FastBridgeV2.Contract.BridgeTxDetails(&_FastBridgeV2.CallOpts, arg0) @@ -4961,11 +5174,11 @@ func (_FastBridgeV2 *FastBridgeV2Session) BridgeTxDetails(arg0 [32]byte) (struct // BridgeTxDetails is a free data retrieval call binding the contract method 0x63787e52. // -// Solidity: function bridgeTxDetails(bytes32 ) view returns(uint8 status, uint40 proofBlockTimestamp, uint48 proofBlockNumber, address proofRelayer) +// Solidity: function bridgeTxDetails(bytes32 ) view returns(uint8 status, uint32 destChainId, uint56 proofBlockTimestamp, address proofRelayer) func (_FastBridgeV2 *FastBridgeV2CallerSession) BridgeTxDetails(arg0 [32]byte) (struct { Status uint8 + DestChainId uint32 ProofBlockTimestamp *big.Int - ProofBlockNumber *big.Int ProofRelayer common.Address }, error) { return _FastBridgeV2.Contract.BridgeTxDetails(&_FastBridgeV2.CallOpts, arg0) @@ -5097,7 +5310,7 @@ func (_FastBridgeV2 *FastBridgeV2CallerSession) GetBridgeTransaction(request []b // GetBridgeTransactionV2 is a free data retrieval call binding the contract method 0x5aa6ccba. // -// Solidity: function getBridgeTransactionV2(bytes request) pure returns((uint32,uint32,address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,address,uint256,bytes)) +// Solidity: function getBridgeTransactionV2(bytes request) pure returns((uint32,uint32,address,address,address,address,uint256,uint256,uint256,uint256,uint256,address,uint256,uint256,bytes)) func (_FastBridgeV2 *FastBridgeV2Caller) GetBridgeTransactionV2(opts *bind.CallOpts, request []byte) (IFastBridgeV2BridgeTransactionV2, error) { var out []interface{} err := _FastBridgeV2.contract.Call(opts, &out, "getBridgeTransactionV2", request) @@ -5114,14 +5327,14 @@ func (_FastBridgeV2 *FastBridgeV2Caller) GetBridgeTransactionV2(opts *bind.CallO // GetBridgeTransactionV2 is a free data retrieval call binding the contract method 0x5aa6ccba. // -// Solidity: function getBridgeTransactionV2(bytes request) pure returns((uint32,uint32,address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,address,uint256,bytes)) +// Solidity: function getBridgeTransactionV2(bytes request) pure returns((uint32,uint32,address,address,address,address,uint256,uint256,uint256,uint256,uint256,address,uint256,uint256,bytes)) func (_FastBridgeV2 *FastBridgeV2Session) GetBridgeTransactionV2(request []byte) (IFastBridgeV2BridgeTransactionV2, error) { return _FastBridgeV2.Contract.GetBridgeTransactionV2(&_FastBridgeV2.CallOpts, request) } // GetBridgeTransactionV2 is a free data retrieval call binding the contract method 0x5aa6ccba. // -// Solidity: function getBridgeTransactionV2(bytes request) pure returns((uint32,uint32,address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,address,uint256,bytes)) +// Solidity: function getBridgeTransactionV2(bytes request) pure returns((uint32,uint32,address,address,address,address,uint256,uint256,uint256,uint256,uint256,address,uint256,uint256,bytes)) func (_FastBridgeV2 *FastBridgeV2CallerSession) GetBridgeTransactionV2(request []byte) (IFastBridgeV2BridgeTransactionV2, error) { return _FastBridgeV2.Contract.GetBridgeTransactionV2(&_FastBridgeV2.CallOpts, request) } @@ -5531,6 +5744,48 @@ func (_FastBridgeV2 *FastBridgeV2TransactorSession) GrantRole(role [32]byte, acc return _FastBridgeV2.Contract.GrantRole(&_FastBridgeV2.TransactOpts, role, account) } +// MulticallNoResults is a paid mutator transaction binding the contract method 0x3f61331d. +// +// Solidity: function multicallNoResults(bytes[] data, bool ignoreReverts) returns() +func (_FastBridgeV2 *FastBridgeV2Transactor) MulticallNoResults(opts *bind.TransactOpts, data [][]byte, ignoreReverts bool) (*types.Transaction, error) { + return _FastBridgeV2.contract.Transact(opts, "multicallNoResults", data, ignoreReverts) +} + +// MulticallNoResults is a paid mutator transaction binding the contract method 0x3f61331d. +// +// Solidity: function multicallNoResults(bytes[] data, bool ignoreReverts) returns() +func (_FastBridgeV2 *FastBridgeV2Session) MulticallNoResults(data [][]byte, ignoreReverts bool) (*types.Transaction, error) { + return _FastBridgeV2.Contract.MulticallNoResults(&_FastBridgeV2.TransactOpts, data, ignoreReverts) +} + +// MulticallNoResults is a paid mutator transaction binding the contract method 0x3f61331d. +// +// Solidity: function multicallNoResults(bytes[] data, bool ignoreReverts) returns() +func (_FastBridgeV2 *FastBridgeV2TransactorSession) MulticallNoResults(data [][]byte, ignoreReverts bool) (*types.Transaction, error) { + return _FastBridgeV2.Contract.MulticallNoResults(&_FastBridgeV2.TransactOpts, data, ignoreReverts) +} + +// MulticallWithResults is a paid mutator transaction binding the contract method 0x385c1d2f. +// +// Solidity: function multicallWithResults(bytes[] data, bool ignoreReverts) returns((bool,bytes)[] results) +func (_FastBridgeV2 *FastBridgeV2Transactor) MulticallWithResults(opts *bind.TransactOpts, data [][]byte, ignoreReverts bool) (*types.Transaction, error) { + return _FastBridgeV2.contract.Transact(opts, "multicallWithResults", data, ignoreReverts) +} + +// MulticallWithResults is a paid mutator transaction binding the contract method 0x385c1d2f. +// +// Solidity: function multicallWithResults(bytes[] data, bool ignoreReverts) returns((bool,bytes)[] results) +func (_FastBridgeV2 *FastBridgeV2Session) MulticallWithResults(data [][]byte, ignoreReverts bool) (*types.Transaction, error) { + return _FastBridgeV2.Contract.MulticallWithResults(&_FastBridgeV2.TransactOpts, data, ignoreReverts) +} + +// MulticallWithResults is a paid mutator transaction binding the contract method 0x385c1d2f. +// +// Solidity: function multicallWithResults(bytes[] data, bool ignoreReverts) returns((bool,bytes)[] results) +func (_FastBridgeV2 *FastBridgeV2TransactorSession) MulticallWithResults(data [][]byte, ignoreReverts bool) (*types.Transaction, error) { + return _FastBridgeV2.Contract.MulticallWithResults(&_FastBridgeV2.TransactOpts, data, ignoreReverts) +} + // Prove is a paid mutator transaction binding the contract method 0x18e4357d. // // Solidity: function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) returns() @@ -12337,188 +12592,9 @@ func (_IFastBridge *IFastBridgeFilterer) ParseBridgeRequested(log types.Log) (*I return event, nil } -// IFastBridgeRecipientMetaData contains all meta data concerning the IFastBridgeRecipient contract. -var IFastBridgeRecipientMetaData = &bind.MetaData{ - ABI: "[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"callParams\",\"type\":\"bytes\"}],\"name\":\"fastBridgeTransferReceived\",\"outputs\":[{\"internalType\":\"bytes4\",\"name\":\"\",\"type\":\"bytes4\"}],\"stateMutability\":\"payable\",\"type\":\"function\"}]", - Sigs: map[string]string{ - "461e0c21": "fastBridgeTransferReceived(address,uint256,bytes)", - }, -} - -// IFastBridgeRecipientABI is the input ABI used to generate the binding from. -// Deprecated: Use IFastBridgeRecipientMetaData.ABI instead. -var IFastBridgeRecipientABI = IFastBridgeRecipientMetaData.ABI - -// Deprecated: Use IFastBridgeRecipientMetaData.Sigs instead. -// IFastBridgeRecipientFuncSigs maps the 4-byte function signature to its string representation. -var IFastBridgeRecipientFuncSigs = IFastBridgeRecipientMetaData.Sigs - -// IFastBridgeRecipient is an auto generated Go binding around an Ethereum contract. -type IFastBridgeRecipient struct { - IFastBridgeRecipientCaller // Read-only binding to the contract - IFastBridgeRecipientTransactor // Write-only binding to the contract - IFastBridgeRecipientFilterer // Log filterer for contract events -} - -// IFastBridgeRecipientCaller is an auto generated read-only Go binding around an Ethereum contract. -type IFastBridgeRecipientCaller struct { - contract *bind.BoundContract // Generic contract wrapper for the low level calls -} - -// IFastBridgeRecipientTransactor is an auto generated write-only Go binding around an Ethereum contract. -type IFastBridgeRecipientTransactor struct { - contract *bind.BoundContract // Generic contract wrapper for the low level calls -} - -// IFastBridgeRecipientFilterer is an auto generated log filtering Go binding around an Ethereum contract events. -type IFastBridgeRecipientFilterer struct { - contract *bind.BoundContract // Generic contract wrapper for the low level calls -} - -// IFastBridgeRecipientSession is an auto generated Go binding around an Ethereum contract, -// with pre-set call and transact options. -type IFastBridgeRecipientSession struct { - Contract *IFastBridgeRecipient // Generic contract binding to set the session for - CallOpts bind.CallOpts // Call options to use throughout this session - TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session -} - -// IFastBridgeRecipientCallerSession is an auto generated read-only Go binding around an Ethereum contract, -// with pre-set call options. -type IFastBridgeRecipientCallerSession struct { - Contract *IFastBridgeRecipientCaller // Generic contract caller binding to set the session for - CallOpts bind.CallOpts // Call options to use throughout this session -} - -// IFastBridgeRecipientTransactorSession is an auto generated write-only Go binding around an Ethereum contract, -// with pre-set transact options. -type IFastBridgeRecipientTransactorSession struct { - Contract *IFastBridgeRecipientTransactor // Generic contract transactor binding to set the session for - TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session -} - -// IFastBridgeRecipientRaw is an auto generated low-level Go binding around an Ethereum contract. -type IFastBridgeRecipientRaw struct { - Contract *IFastBridgeRecipient // Generic contract binding to access the raw methods on -} - -// IFastBridgeRecipientCallerRaw is an auto generated low-level read-only Go binding around an Ethereum contract. -type IFastBridgeRecipientCallerRaw struct { - Contract *IFastBridgeRecipientCaller // Generic read-only contract binding to access the raw methods on -} - -// IFastBridgeRecipientTransactorRaw is an auto generated low-level write-only Go binding around an Ethereum contract. -type IFastBridgeRecipientTransactorRaw struct { - Contract *IFastBridgeRecipientTransactor // Generic write-only contract binding to access the raw methods on -} - -// NewIFastBridgeRecipient creates a new instance of IFastBridgeRecipient, bound to a specific deployed contract. -func NewIFastBridgeRecipient(address common.Address, backend bind.ContractBackend) (*IFastBridgeRecipient, error) { - contract, err := bindIFastBridgeRecipient(address, backend, backend, backend) - if err != nil { - return nil, err - } - return &IFastBridgeRecipient{IFastBridgeRecipientCaller: IFastBridgeRecipientCaller{contract: contract}, IFastBridgeRecipientTransactor: IFastBridgeRecipientTransactor{contract: contract}, IFastBridgeRecipientFilterer: IFastBridgeRecipientFilterer{contract: contract}}, nil -} - -// NewIFastBridgeRecipientCaller creates a new read-only instance of IFastBridgeRecipient, bound to a specific deployed contract. -func NewIFastBridgeRecipientCaller(address common.Address, caller bind.ContractCaller) (*IFastBridgeRecipientCaller, error) { - contract, err := bindIFastBridgeRecipient(address, caller, nil, nil) - if err != nil { - return nil, err - } - return &IFastBridgeRecipientCaller{contract: contract}, nil -} - -// NewIFastBridgeRecipientTransactor creates a new write-only instance of IFastBridgeRecipient, bound to a specific deployed contract. -func NewIFastBridgeRecipientTransactor(address common.Address, transactor bind.ContractTransactor) (*IFastBridgeRecipientTransactor, error) { - contract, err := bindIFastBridgeRecipient(address, nil, transactor, nil) - if err != nil { - return nil, err - } - return &IFastBridgeRecipientTransactor{contract: contract}, nil -} - -// NewIFastBridgeRecipientFilterer creates a new log filterer instance of IFastBridgeRecipient, bound to a specific deployed contract. -func NewIFastBridgeRecipientFilterer(address common.Address, filterer bind.ContractFilterer) (*IFastBridgeRecipientFilterer, error) { - contract, err := bindIFastBridgeRecipient(address, nil, nil, filterer) - if err != nil { - return nil, err - } - return &IFastBridgeRecipientFilterer{contract: contract}, nil -} - -// bindIFastBridgeRecipient binds a generic wrapper to an already deployed contract. -func bindIFastBridgeRecipient(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) { - parsed, err := IFastBridgeRecipientMetaData.GetAbi() - if err != nil { - return nil, err - } - return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil -} - -// Call invokes the (constant) contract method with params as input values and -// sets the output to result. The result type might be a single field for simple -// returns, a slice of interfaces for anonymous returns and a struct for named -// returns. -func (_IFastBridgeRecipient *IFastBridgeRecipientRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { - return _IFastBridgeRecipient.Contract.IFastBridgeRecipientCaller.contract.Call(opts, result, method, params...) -} - -// Transfer initiates a plain transaction to move funds to the contract, calling -// its default method if one is available. -func (_IFastBridgeRecipient *IFastBridgeRecipientRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { - return _IFastBridgeRecipient.Contract.IFastBridgeRecipientTransactor.contract.Transfer(opts) -} - -// Transact invokes the (paid) contract method with params as input values. -func (_IFastBridgeRecipient *IFastBridgeRecipientRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { - return _IFastBridgeRecipient.Contract.IFastBridgeRecipientTransactor.contract.Transact(opts, method, params...) -} - -// Call invokes the (constant) contract method with params as input values and -// sets the output to result. The result type might be a single field for simple -// returns, a slice of interfaces for anonymous returns and a struct for named -// returns. -func (_IFastBridgeRecipient *IFastBridgeRecipientCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { - return _IFastBridgeRecipient.Contract.contract.Call(opts, result, method, params...) -} - -// Transfer initiates a plain transaction to move funds to the contract, calling -// its default method if one is available. -func (_IFastBridgeRecipient *IFastBridgeRecipientTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { - return _IFastBridgeRecipient.Contract.contract.Transfer(opts) -} - -// Transact invokes the (paid) contract method with params as input values. -func (_IFastBridgeRecipient *IFastBridgeRecipientTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { - return _IFastBridgeRecipient.Contract.contract.Transact(opts, method, params...) -} - -// FastBridgeTransferReceived is a paid mutator transaction binding the contract method 0x461e0c21. -// -// Solidity: function fastBridgeTransferReceived(address token, uint256 amount, bytes callParams) payable returns(bytes4) -func (_IFastBridgeRecipient *IFastBridgeRecipientTransactor) FastBridgeTransferReceived(opts *bind.TransactOpts, token common.Address, amount *big.Int, callParams []byte) (*types.Transaction, error) { - return _IFastBridgeRecipient.contract.Transact(opts, "fastBridgeTransferReceived", token, amount, callParams) -} - -// FastBridgeTransferReceived is a paid mutator transaction binding the contract method 0x461e0c21. -// -// Solidity: function fastBridgeTransferReceived(address token, uint256 amount, bytes callParams) payable returns(bytes4) -func (_IFastBridgeRecipient *IFastBridgeRecipientSession) FastBridgeTransferReceived(token common.Address, amount *big.Int, callParams []byte) (*types.Transaction, error) { - return _IFastBridgeRecipient.Contract.FastBridgeTransferReceived(&_IFastBridgeRecipient.TransactOpts, token, amount, callParams) -} - -// FastBridgeTransferReceived is a paid mutator transaction binding the contract method 0x461e0c21. -// -// Solidity: function fastBridgeTransferReceived(address token, uint256 amount, bytes callParams) payable returns(bytes4) -func (_IFastBridgeRecipient *IFastBridgeRecipientTransactorSession) FastBridgeTransferReceived(token common.Address, amount *big.Int, callParams []byte) (*types.Transaction, error) { - return _IFastBridgeRecipient.Contract.FastBridgeTransferReceived(&_IFastBridgeRecipient.TransactOpts, token, amount, callParams) -} - // IFastBridgeV2MetaData contains all meta data concerning the IFastBridgeV2 contract. var IFastBridgeV2MetaData = &bind.MetaData{ - ABI: "[{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"BridgeDepositClaimed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"BridgeDepositRefunded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"name\":\"BridgeProofDisputed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"transactionHash\",\"type\":\"bytes32\"}],\"name\":\"BridgeProofProvided\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"quoteId\",\"type\":\"bytes\"}],\"name\":\"BridgeQuoteDetails\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"originChainId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"chainGasAmount\",\"type\":\"uint256\"}],\"name\":\"BridgeRelayed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"destChainId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"sendChainGas\",\"type\":\"bool\"}],\"name\":\"BridgeRequested\",\"type\":\"event\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"dstChainId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"sendChainGas\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"}],\"internalType\":\"structIFastBridge.BridgeParams\",\"name\":\"params\",\"type\":\"tuple\"}],\"name\":\"bridge\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"dstChainId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"sendChainGas\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"}],\"internalType\":\"structIFastBridge.BridgeParams\",\"name\":\"params\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"quoteRelayer\",\"type\":\"address\"},{\"internalType\":\"int256\",\"name\":\"quoteExclusivitySeconds\",\"type\":\"int256\"},{\"internalType\":\"bytes\",\"name\":\"quoteId\",\"type\":\"bytes\"},{\"internalType\":\"uint256\",\"name\":\"callValue\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"callParams\",\"type\":\"bytes\"}],\"internalType\":\"structIFastBridgeV2.BridgeParamsV2\",\"name\":\"paramsV2\",\"type\":\"tuple\"}],\"name\":\"bridge\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"}],\"name\":\"bridgeProofs\",\"outputs\":[{\"internalType\":\"uint96\",\"name\":\"timestamp\",\"type\":\"uint96\"},{\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"}],\"name\":\"bridgeRelays\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"}],\"name\":\"bridgeStatuses\",\"outputs\":[{\"internalType\":\"enumIFastBridgeV2.BridgeStatus\",\"name\":\"\",\"type\":\"uint8\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"name\":\"canClaim\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"claim\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"claim\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"}],\"name\":\"dispute\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"getBridgeTransaction\",\"outputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"originChainId\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"destChainId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"originSender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destRecipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"originFeeAmount\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"sendChainGas\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"}],\"internalType\":\"structIFastBridge.BridgeTransaction\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"getBridgeTransactionV2\",\"outputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"originChainId\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"destChainId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"originSender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destRecipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"originFeeAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"callValue\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"exclusivityRelayer\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"exclusivityEndTime\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"callParams\",\"type\":\"bytes\"}],\"internalType\":\"structIFastBridgeV2.BridgeTransactionV2\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"destTxHash\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"name\":\"prove\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"},{\"internalType\":\"bytes32\",\"name\":\"destTxHash\",\"type\":\"bytes32\"}],\"name\":\"prove\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"refund\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"relay\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"},{\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"name\":\"relay\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"}]", + ABI: "[{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"BridgeDepositClaimed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"BridgeDepositRefunded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"name\":\"BridgeProofDisputed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"transactionHash\",\"type\":\"bytes32\"}],\"name\":\"BridgeProofProvided\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"quoteId\",\"type\":\"bytes\"}],\"name\":\"BridgeQuoteDetails\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"originChainId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"chainGasAmount\",\"type\":\"uint256\"}],\"name\":\"BridgeRelayed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"destChainId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"sendChainGas\",\"type\":\"bool\"}],\"name\":\"BridgeRequested\",\"type\":\"event\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"dstChainId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"sendChainGas\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"}],\"internalType\":\"structIFastBridge.BridgeParams\",\"name\":\"params\",\"type\":\"tuple\"}],\"name\":\"bridge\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"dstChainId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"sendChainGas\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"}],\"internalType\":\"structIFastBridge.BridgeParams\",\"name\":\"params\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"quoteRelayer\",\"type\":\"address\"},{\"internalType\":\"int256\",\"name\":\"quoteExclusivitySeconds\",\"type\":\"int256\"},{\"internalType\":\"bytes\",\"name\":\"quoteId\",\"type\":\"bytes\"},{\"internalType\":\"uint256\",\"name\":\"zapNative\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"zapData\",\"type\":\"bytes\"}],\"internalType\":\"structIFastBridgeV2.BridgeParamsV2\",\"name\":\"paramsV2\",\"type\":\"tuple\"}],\"name\":\"bridge\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"}],\"name\":\"bridgeProofs\",\"outputs\":[{\"internalType\":\"uint96\",\"name\":\"timestamp\",\"type\":\"uint96\"},{\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"}],\"name\":\"bridgeRelays\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"}],\"name\":\"bridgeStatuses\",\"outputs\":[{\"internalType\":\"enumIFastBridgeV2.BridgeStatus\",\"name\":\"\",\"type\":\"uint8\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"name\":\"canClaim\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"claim\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"claim\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"}],\"name\":\"dispute\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"getBridgeTransaction\",\"outputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"originChainId\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"destChainId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"originSender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destRecipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"originFeeAmount\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"sendChainGas\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"}],\"internalType\":\"structIFastBridge.BridgeTransaction\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"getBridgeTransactionV2\",\"outputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"originChainId\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"destChainId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"originSender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destRecipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"originFeeAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"exclusivityRelayer\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"exclusivityEndTime\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"zapNative\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"zapData\",\"type\":\"bytes\"}],\"internalType\":\"structIFastBridgeV2.BridgeTransactionV2\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"destTxHash\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"name\":\"prove\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"},{\"internalType\":\"bytes32\",\"name\":\"destTxHash\",\"type\":\"bytes32\"}],\"name\":\"prove\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"refund\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"relay\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"},{\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"name\":\"relay\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"}]", Sigs: map[string]string{ "45851694": "bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256))", "bfc7c607": "bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256),(address,int256,bytes,uint256,bytes))", @@ -12860,7 +12936,7 @@ func (_IFastBridgeV2 *IFastBridgeV2CallerSession) GetBridgeTransaction(request [ // GetBridgeTransactionV2 is a free data retrieval call binding the contract method 0x5aa6ccba. // -// Solidity: function getBridgeTransactionV2(bytes request) view returns((uint32,uint32,address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,address,uint256,bytes)) +// Solidity: function getBridgeTransactionV2(bytes request) view returns((uint32,uint32,address,address,address,address,uint256,uint256,uint256,uint256,uint256,address,uint256,uint256,bytes)) func (_IFastBridgeV2 *IFastBridgeV2Caller) GetBridgeTransactionV2(opts *bind.CallOpts, request []byte) (IFastBridgeV2BridgeTransactionV2, error) { var out []interface{} err := _IFastBridgeV2.contract.Call(opts, &out, "getBridgeTransactionV2", request) @@ -12877,14 +12953,14 @@ func (_IFastBridgeV2 *IFastBridgeV2Caller) GetBridgeTransactionV2(opts *bind.Cal // GetBridgeTransactionV2 is a free data retrieval call binding the contract method 0x5aa6ccba. // -// Solidity: function getBridgeTransactionV2(bytes request) view returns((uint32,uint32,address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,address,uint256,bytes)) +// Solidity: function getBridgeTransactionV2(bytes request) view returns((uint32,uint32,address,address,address,address,uint256,uint256,uint256,uint256,uint256,address,uint256,uint256,bytes)) func (_IFastBridgeV2 *IFastBridgeV2Session) GetBridgeTransactionV2(request []byte) (IFastBridgeV2BridgeTransactionV2, error) { return _IFastBridgeV2.Contract.GetBridgeTransactionV2(&_IFastBridgeV2.CallOpts, request) } // GetBridgeTransactionV2 is a free data retrieval call binding the contract method 0x5aa6ccba. // -// Solidity: function getBridgeTransactionV2(bytes request) view returns((uint32,uint32,address,address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,address,uint256,bytes)) +// Solidity: function getBridgeTransactionV2(bytes request) view returns((uint32,uint32,address,address,address,address,uint256,uint256,uint256,uint256,uint256,address,uint256,uint256,bytes)) func (_IFastBridgeV2 *IFastBridgeV2CallerSession) GetBridgeTransactionV2(request []byte) (IFastBridgeV2BridgeTransactionV2, error) { return _IFastBridgeV2.Contract.GetBridgeTransactionV2(&_IFastBridgeV2.CallOpts, request) } @@ -14200,7 +14276,7 @@ func (_IFastBridgeV2 *IFastBridgeV2Filterer) ParseBridgeRequested(log types.Log) // IFastBridgeV2ErrorsMetaData contains all meta data concerning the IFastBridgeV2Errors contract. var IFastBridgeV2ErrorsMetaData = &bind.MetaData{ - ABI: "[{\"inputs\":[],\"name\":\"AmountIncorrect\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"CallParamsLengthAboveMax\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ChainIncorrect\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DeadlineExceeded\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DeadlineNotExceeded\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DeadlineTooShort\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DisputePeriodNotPassed\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DisputePeriodPassed\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ExclusivityParamsIncorrect\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ExclusivityPeriodNotPassed\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"MsgValueIncorrect\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"NativeTokenCallValueNotSupported\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"RecipientIncorrectReturnValue\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"RecipientNoReturnValue\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"SenderIncorrect\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"StatusIncorrect\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"TransactionRelayed\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ZeroAddress\",\"type\":\"error\"}]", + ABI: "[{\"inputs\":[],\"name\":\"AmountIncorrect\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ChainIncorrect\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DeadlineExceeded\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DeadlineNotExceeded\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DeadlineTooShort\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DisputePeriodNotPassed\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DisputePeriodPassed\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ExclusivityParamsIncorrect\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ExclusivityPeriodNotPassed\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"MsgValueIncorrect\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"RecipientIncorrectReturnValue\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"RecipientNoReturnValue\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"SenderIncorrect\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"StatusIncorrect\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"TokenNotContract\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"TransactionRelayed\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ZapDataLengthAboveMax\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ZapNativeNotSupported\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ZeroAddress\",\"type\":\"error\"}]", } // IFastBridgeV2ErrorsABI is the input ABI used to generate the binding from. @@ -14349,10 +14425,591 @@ func (_IFastBridgeV2Errors *IFastBridgeV2ErrorsTransactorRaw) Transact(opts *bin return _IFastBridgeV2Errors.Contract.contract.Transact(opts, method, params...) } +// IMulticallTargetMetaData contains all meta data concerning the IMulticallTarget contract. +var IMulticallTargetMetaData = &bind.MetaData{ + ABI: "[{\"inputs\":[{\"internalType\":\"bytes[]\",\"name\":\"data\",\"type\":\"bytes[]\"},{\"internalType\":\"bool\",\"name\":\"ignoreReverts\",\"type\":\"bool\"}],\"name\":\"multicallNoResults\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes[]\",\"name\":\"data\",\"type\":\"bytes[]\"},{\"internalType\":\"bool\",\"name\":\"ignoreReverts\",\"type\":\"bool\"}],\"name\":\"multicallWithResults\",\"outputs\":[{\"components\":[{\"internalType\":\"bool\",\"name\":\"success\",\"type\":\"bool\"},{\"internalType\":\"bytes\",\"name\":\"returnData\",\"type\":\"bytes\"}],\"internalType\":\"structIMulticallTarget.Result[]\",\"name\":\"results\",\"type\":\"tuple[]\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", + Sigs: map[string]string{ + "3f61331d": "multicallNoResults(bytes[],bool)", + "385c1d2f": "multicallWithResults(bytes[],bool)", + }, +} + +// IMulticallTargetABI is the input ABI used to generate the binding from. +// Deprecated: Use IMulticallTargetMetaData.ABI instead. +var IMulticallTargetABI = IMulticallTargetMetaData.ABI + +// Deprecated: Use IMulticallTargetMetaData.Sigs instead. +// IMulticallTargetFuncSigs maps the 4-byte function signature to its string representation. +var IMulticallTargetFuncSigs = IMulticallTargetMetaData.Sigs + +// IMulticallTarget is an auto generated Go binding around an Ethereum contract. +type IMulticallTarget struct { + IMulticallTargetCaller // Read-only binding to the contract + IMulticallTargetTransactor // Write-only binding to the contract + IMulticallTargetFilterer // Log filterer for contract events +} + +// IMulticallTargetCaller is an auto generated read-only Go binding around an Ethereum contract. +type IMulticallTargetCaller struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// IMulticallTargetTransactor is an auto generated write-only Go binding around an Ethereum contract. +type IMulticallTargetTransactor struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// IMulticallTargetFilterer is an auto generated log filtering Go binding around an Ethereum contract events. +type IMulticallTargetFilterer struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// IMulticallTargetSession is an auto generated Go binding around an Ethereum contract, +// with pre-set call and transact options. +type IMulticallTargetSession struct { + Contract *IMulticallTarget // Generic contract binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// IMulticallTargetCallerSession is an auto generated read-only Go binding around an Ethereum contract, +// with pre-set call options. +type IMulticallTargetCallerSession struct { + Contract *IMulticallTargetCaller // Generic contract caller binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session +} + +// IMulticallTargetTransactorSession is an auto generated write-only Go binding around an Ethereum contract, +// with pre-set transact options. +type IMulticallTargetTransactorSession struct { + Contract *IMulticallTargetTransactor // Generic contract transactor binding to set the session for + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// IMulticallTargetRaw is an auto generated low-level Go binding around an Ethereum contract. +type IMulticallTargetRaw struct { + Contract *IMulticallTarget // Generic contract binding to access the raw methods on +} + +// IMulticallTargetCallerRaw is an auto generated low-level read-only Go binding around an Ethereum contract. +type IMulticallTargetCallerRaw struct { + Contract *IMulticallTargetCaller // Generic read-only contract binding to access the raw methods on +} + +// IMulticallTargetTransactorRaw is an auto generated low-level write-only Go binding around an Ethereum contract. +type IMulticallTargetTransactorRaw struct { + Contract *IMulticallTargetTransactor // Generic write-only contract binding to access the raw methods on +} + +// NewIMulticallTarget creates a new instance of IMulticallTarget, bound to a specific deployed contract. +func NewIMulticallTarget(address common.Address, backend bind.ContractBackend) (*IMulticallTarget, error) { + contract, err := bindIMulticallTarget(address, backend, backend, backend) + if err != nil { + return nil, err + } + return &IMulticallTarget{IMulticallTargetCaller: IMulticallTargetCaller{contract: contract}, IMulticallTargetTransactor: IMulticallTargetTransactor{contract: contract}, IMulticallTargetFilterer: IMulticallTargetFilterer{contract: contract}}, nil +} + +// NewIMulticallTargetCaller creates a new read-only instance of IMulticallTarget, bound to a specific deployed contract. +func NewIMulticallTargetCaller(address common.Address, caller bind.ContractCaller) (*IMulticallTargetCaller, error) { + contract, err := bindIMulticallTarget(address, caller, nil, nil) + if err != nil { + return nil, err + } + return &IMulticallTargetCaller{contract: contract}, nil +} + +// NewIMulticallTargetTransactor creates a new write-only instance of IMulticallTarget, bound to a specific deployed contract. +func NewIMulticallTargetTransactor(address common.Address, transactor bind.ContractTransactor) (*IMulticallTargetTransactor, error) { + contract, err := bindIMulticallTarget(address, nil, transactor, nil) + if err != nil { + return nil, err + } + return &IMulticallTargetTransactor{contract: contract}, nil +} + +// NewIMulticallTargetFilterer creates a new log filterer instance of IMulticallTarget, bound to a specific deployed contract. +func NewIMulticallTargetFilterer(address common.Address, filterer bind.ContractFilterer) (*IMulticallTargetFilterer, error) { + contract, err := bindIMulticallTarget(address, nil, nil, filterer) + if err != nil { + return nil, err + } + return &IMulticallTargetFilterer{contract: contract}, nil +} + +// bindIMulticallTarget binds a generic wrapper to an already deployed contract. +func bindIMulticallTarget(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) { + parsed, err := IMulticallTargetMetaData.GetAbi() + if err != nil { + return nil, err + } + return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil +} + +// Call invokes the (constant) contract method with params as input values and +// sets the output to result. The result type might be a single field for simple +// returns, a slice of interfaces for anonymous returns and a struct for named +// returns. +func (_IMulticallTarget *IMulticallTargetRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _IMulticallTarget.Contract.IMulticallTargetCaller.contract.Call(opts, result, method, params...) +} + +// Transfer initiates a plain transaction to move funds to the contract, calling +// its default method if one is available. +func (_IMulticallTarget *IMulticallTargetRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _IMulticallTarget.Contract.IMulticallTargetTransactor.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_IMulticallTarget *IMulticallTargetRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _IMulticallTarget.Contract.IMulticallTargetTransactor.contract.Transact(opts, method, params...) +} + +// Call invokes the (constant) contract method with params as input values and +// sets the output to result. The result type might be a single field for simple +// returns, a slice of interfaces for anonymous returns and a struct for named +// returns. +func (_IMulticallTarget *IMulticallTargetCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _IMulticallTarget.Contract.contract.Call(opts, result, method, params...) +} + +// Transfer initiates a plain transaction to move funds to the contract, calling +// its default method if one is available. +func (_IMulticallTarget *IMulticallTargetTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _IMulticallTarget.Contract.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_IMulticallTarget *IMulticallTargetTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _IMulticallTarget.Contract.contract.Transact(opts, method, params...) +} + +// MulticallNoResults is a paid mutator transaction binding the contract method 0x3f61331d. +// +// Solidity: function multicallNoResults(bytes[] data, bool ignoreReverts) returns() +func (_IMulticallTarget *IMulticallTargetTransactor) MulticallNoResults(opts *bind.TransactOpts, data [][]byte, ignoreReverts bool) (*types.Transaction, error) { + return _IMulticallTarget.contract.Transact(opts, "multicallNoResults", data, ignoreReverts) +} + +// MulticallNoResults is a paid mutator transaction binding the contract method 0x3f61331d. +// +// Solidity: function multicallNoResults(bytes[] data, bool ignoreReverts) returns() +func (_IMulticallTarget *IMulticallTargetSession) MulticallNoResults(data [][]byte, ignoreReverts bool) (*types.Transaction, error) { + return _IMulticallTarget.Contract.MulticallNoResults(&_IMulticallTarget.TransactOpts, data, ignoreReverts) +} + +// MulticallNoResults is a paid mutator transaction binding the contract method 0x3f61331d. +// +// Solidity: function multicallNoResults(bytes[] data, bool ignoreReverts) returns() +func (_IMulticallTarget *IMulticallTargetTransactorSession) MulticallNoResults(data [][]byte, ignoreReverts bool) (*types.Transaction, error) { + return _IMulticallTarget.Contract.MulticallNoResults(&_IMulticallTarget.TransactOpts, data, ignoreReverts) +} + +// MulticallWithResults is a paid mutator transaction binding the contract method 0x385c1d2f. +// +// Solidity: function multicallWithResults(bytes[] data, bool ignoreReverts) returns((bool,bytes)[] results) +func (_IMulticallTarget *IMulticallTargetTransactor) MulticallWithResults(opts *bind.TransactOpts, data [][]byte, ignoreReverts bool) (*types.Transaction, error) { + return _IMulticallTarget.contract.Transact(opts, "multicallWithResults", data, ignoreReverts) +} + +// MulticallWithResults is a paid mutator transaction binding the contract method 0x385c1d2f. +// +// Solidity: function multicallWithResults(bytes[] data, bool ignoreReverts) returns((bool,bytes)[] results) +func (_IMulticallTarget *IMulticallTargetSession) MulticallWithResults(data [][]byte, ignoreReverts bool) (*types.Transaction, error) { + return _IMulticallTarget.Contract.MulticallWithResults(&_IMulticallTarget.TransactOpts, data, ignoreReverts) +} + +// MulticallWithResults is a paid mutator transaction binding the contract method 0x385c1d2f. +// +// Solidity: function multicallWithResults(bytes[] data, bool ignoreReverts) returns((bool,bytes)[] results) +func (_IMulticallTarget *IMulticallTargetTransactorSession) MulticallWithResults(data [][]byte, ignoreReverts bool) (*types.Transaction, error) { + return _IMulticallTarget.Contract.MulticallWithResults(&_IMulticallTarget.TransactOpts, data, ignoreReverts) +} + +// IZapRecipientMetaData contains all meta data concerning the IZapRecipient contract. +var IZapRecipientMetaData = &bind.MetaData{ + ABI: "[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"zapData\",\"type\":\"bytes\"}],\"name\":\"zap\",\"outputs\":[{\"internalType\":\"bytes4\",\"name\":\"\",\"type\":\"bytes4\"}],\"stateMutability\":\"payable\",\"type\":\"function\"}]", + Sigs: map[string]string{ + "e85e13dd": "zap(address,uint256,bytes)", + }, +} + +// IZapRecipientABI is the input ABI used to generate the binding from. +// Deprecated: Use IZapRecipientMetaData.ABI instead. +var IZapRecipientABI = IZapRecipientMetaData.ABI + +// Deprecated: Use IZapRecipientMetaData.Sigs instead. +// IZapRecipientFuncSigs maps the 4-byte function signature to its string representation. +var IZapRecipientFuncSigs = IZapRecipientMetaData.Sigs + +// IZapRecipient is an auto generated Go binding around an Ethereum contract. +type IZapRecipient struct { + IZapRecipientCaller // Read-only binding to the contract + IZapRecipientTransactor // Write-only binding to the contract + IZapRecipientFilterer // Log filterer for contract events +} + +// IZapRecipientCaller is an auto generated read-only Go binding around an Ethereum contract. +type IZapRecipientCaller struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// IZapRecipientTransactor is an auto generated write-only Go binding around an Ethereum contract. +type IZapRecipientTransactor struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// IZapRecipientFilterer is an auto generated log filtering Go binding around an Ethereum contract events. +type IZapRecipientFilterer struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// IZapRecipientSession is an auto generated Go binding around an Ethereum contract, +// with pre-set call and transact options. +type IZapRecipientSession struct { + Contract *IZapRecipient // Generic contract binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// IZapRecipientCallerSession is an auto generated read-only Go binding around an Ethereum contract, +// with pre-set call options. +type IZapRecipientCallerSession struct { + Contract *IZapRecipientCaller // Generic contract caller binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session +} + +// IZapRecipientTransactorSession is an auto generated write-only Go binding around an Ethereum contract, +// with pre-set transact options. +type IZapRecipientTransactorSession struct { + Contract *IZapRecipientTransactor // Generic contract transactor binding to set the session for + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// IZapRecipientRaw is an auto generated low-level Go binding around an Ethereum contract. +type IZapRecipientRaw struct { + Contract *IZapRecipient // Generic contract binding to access the raw methods on +} + +// IZapRecipientCallerRaw is an auto generated low-level read-only Go binding around an Ethereum contract. +type IZapRecipientCallerRaw struct { + Contract *IZapRecipientCaller // Generic read-only contract binding to access the raw methods on +} + +// IZapRecipientTransactorRaw is an auto generated low-level write-only Go binding around an Ethereum contract. +type IZapRecipientTransactorRaw struct { + Contract *IZapRecipientTransactor // Generic write-only contract binding to access the raw methods on +} + +// NewIZapRecipient creates a new instance of IZapRecipient, bound to a specific deployed contract. +func NewIZapRecipient(address common.Address, backend bind.ContractBackend) (*IZapRecipient, error) { + contract, err := bindIZapRecipient(address, backend, backend, backend) + if err != nil { + return nil, err + } + return &IZapRecipient{IZapRecipientCaller: IZapRecipientCaller{contract: contract}, IZapRecipientTransactor: IZapRecipientTransactor{contract: contract}, IZapRecipientFilterer: IZapRecipientFilterer{contract: contract}}, nil +} + +// NewIZapRecipientCaller creates a new read-only instance of IZapRecipient, bound to a specific deployed contract. +func NewIZapRecipientCaller(address common.Address, caller bind.ContractCaller) (*IZapRecipientCaller, error) { + contract, err := bindIZapRecipient(address, caller, nil, nil) + if err != nil { + return nil, err + } + return &IZapRecipientCaller{contract: contract}, nil +} + +// NewIZapRecipientTransactor creates a new write-only instance of IZapRecipient, bound to a specific deployed contract. +func NewIZapRecipientTransactor(address common.Address, transactor bind.ContractTransactor) (*IZapRecipientTransactor, error) { + contract, err := bindIZapRecipient(address, nil, transactor, nil) + if err != nil { + return nil, err + } + return &IZapRecipientTransactor{contract: contract}, nil +} + +// NewIZapRecipientFilterer creates a new log filterer instance of IZapRecipient, bound to a specific deployed contract. +func NewIZapRecipientFilterer(address common.Address, filterer bind.ContractFilterer) (*IZapRecipientFilterer, error) { + contract, err := bindIZapRecipient(address, nil, nil, filterer) + if err != nil { + return nil, err + } + return &IZapRecipientFilterer{contract: contract}, nil +} + +// bindIZapRecipient binds a generic wrapper to an already deployed contract. +func bindIZapRecipient(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) { + parsed, err := IZapRecipientMetaData.GetAbi() + if err != nil { + return nil, err + } + return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil +} + +// Call invokes the (constant) contract method with params as input values and +// sets the output to result. The result type might be a single field for simple +// returns, a slice of interfaces for anonymous returns and a struct for named +// returns. +func (_IZapRecipient *IZapRecipientRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _IZapRecipient.Contract.IZapRecipientCaller.contract.Call(opts, result, method, params...) +} + +// Transfer initiates a plain transaction to move funds to the contract, calling +// its default method if one is available. +func (_IZapRecipient *IZapRecipientRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _IZapRecipient.Contract.IZapRecipientTransactor.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_IZapRecipient *IZapRecipientRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _IZapRecipient.Contract.IZapRecipientTransactor.contract.Transact(opts, method, params...) +} + +// Call invokes the (constant) contract method with params as input values and +// sets the output to result. The result type might be a single field for simple +// returns, a slice of interfaces for anonymous returns and a struct for named +// returns. +func (_IZapRecipient *IZapRecipientCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _IZapRecipient.Contract.contract.Call(opts, result, method, params...) +} + +// Transfer initiates a plain transaction to move funds to the contract, calling +// its default method if one is available. +func (_IZapRecipient *IZapRecipientTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _IZapRecipient.Contract.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_IZapRecipient *IZapRecipientTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _IZapRecipient.Contract.contract.Transact(opts, method, params...) +} + +// Zap is a paid mutator transaction binding the contract method 0xe85e13dd. +// +// Solidity: function zap(address token, uint256 amount, bytes zapData) payable returns(bytes4) +func (_IZapRecipient *IZapRecipientTransactor) Zap(opts *bind.TransactOpts, token common.Address, amount *big.Int, zapData []byte) (*types.Transaction, error) { + return _IZapRecipient.contract.Transact(opts, "zap", token, amount, zapData) +} + +// Zap is a paid mutator transaction binding the contract method 0xe85e13dd. +// +// Solidity: function zap(address token, uint256 amount, bytes zapData) payable returns(bytes4) +func (_IZapRecipient *IZapRecipientSession) Zap(token common.Address, amount *big.Int, zapData []byte) (*types.Transaction, error) { + return _IZapRecipient.Contract.Zap(&_IZapRecipient.TransactOpts, token, amount, zapData) +} + +// Zap is a paid mutator transaction binding the contract method 0xe85e13dd. +// +// Solidity: function zap(address token, uint256 amount, bytes zapData) payable returns(bytes4) +func (_IZapRecipient *IZapRecipientTransactorSession) Zap(token common.Address, amount *big.Int, zapData []byte) (*types.Transaction, error) { + return _IZapRecipient.Contract.Zap(&_IZapRecipient.TransactOpts, token, amount, zapData) +} + +// MulticallTargetMetaData contains all meta data concerning the MulticallTarget contract. +var MulticallTargetMetaData = &bind.MetaData{ + ABI: "[{\"inputs\":[],\"name\":\"MulticallTarget__UndeterminedRevert\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"bytes[]\",\"name\":\"data\",\"type\":\"bytes[]\"},{\"internalType\":\"bool\",\"name\":\"ignoreReverts\",\"type\":\"bool\"}],\"name\":\"multicallNoResults\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes[]\",\"name\":\"data\",\"type\":\"bytes[]\"},{\"internalType\":\"bool\",\"name\":\"ignoreReverts\",\"type\":\"bool\"}],\"name\":\"multicallWithResults\",\"outputs\":[{\"components\":[{\"internalType\":\"bool\",\"name\":\"success\",\"type\":\"bool\"},{\"internalType\":\"bytes\",\"name\":\"returnData\",\"type\":\"bytes\"}],\"internalType\":\"structIMulticallTarget.Result[]\",\"name\":\"results\",\"type\":\"tuple[]\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", + Sigs: map[string]string{ + "3f61331d": "multicallNoResults(bytes[],bool)", + "385c1d2f": "multicallWithResults(bytes[],bool)", + }, +} + +// MulticallTargetABI is the input ABI used to generate the binding from. +// Deprecated: Use MulticallTargetMetaData.ABI instead. +var MulticallTargetABI = MulticallTargetMetaData.ABI + +// Deprecated: Use MulticallTargetMetaData.Sigs instead. +// MulticallTargetFuncSigs maps the 4-byte function signature to its string representation. +var MulticallTargetFuncSigs = MulticallTargetMetaData.Sigs + +// MulticallTarget is an auto generated Go binding around an Ethereum contract. +type MulticallTarget struct { + MulticallTargetCaller // Read-only binding to the contract + MulticallTargetTransactor // Write-only binding to the contract + MulticallTargetFilterer // Log filterer for contract events +} + +// MulticallTargetCaller is an auto generated read-only Go binding around an Ethereum contract. +type MulticallTargetCaller struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// MulticallTargetTransactor is an auto generated write-only Go binding around an Ethereum contract. +type MulticallTargetTransactor struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// MulticallTargetFilterer is an auto generated log filtering Go binding around an Ethereum contract events. +type MulticallTargetFilterer struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// MulticallTargetSession is an auto generated Go binding around an Ethereum contract, +// with pre-set call and transact options. +type MulticallTargetSession struct { + Contract *MulticallTarget // Generic contract binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// MulticallTargetCallerSession is an auto generated read-only Go binding around an Ethereum contract, +// with pre-set call options. +type MulticallTargetCallerSession struct { + Contract *MulticallTargetCaller // Generic contract caller binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session +} + +// MulticallTargetTransactorSession is an auto generated write-only Go binding around an Ethereum contract, +// with pre-set transact options. +type MulticallTargetTransactorSession struct { + Contract *MulticallTargetTransactor // Generic contract transactor binding to set the session for + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// MulticallTargetRaw is an auto generated low-level Go binding around an Ethereum contract. +type MulticallTargetRaw struct { + Contract *MulticallTarget // Generic contract binding to access the raw methods on +} + +// MulticallTargetCallerRaw is an auto generated low-level read-only Go binding around an Ethereum contract. +type MulticallTargetCallerRaw struct { + Contract *MulticallTargetCaller // Generic read-only contract binding to access the raw methods on +} + +// MulticallTargetTransactorRaw is an auto generated low-level write-only Go binding around an Ethereum contract. +type MulticallTargetTransactorRaw struct { + Contract *MulticallTargetTransactor // Generic write-only contract binding to access the raw methods on +} + +// NewMulticallTarget creates a new instance of MulticallTarget, bound to a specific deployed contract. +func NewMulticallTarget(address common.Address, backend bind.ContractBackend) (*MulticallTarget, error) { + contract, err := bindMulticallTarget(address, backend, backend, backend) + if err != nil { + return nil, err + } + return &MulticallTarget{MulticallTargetCaller: MulticallTargetCaller{contract: contract}, MulticallTargetTransactor: MulticallTargetTransactor{contract: contract}, MulticallTargetFilterer: MulticallTargetFilterer{contract: contract}}, nil +} + +// NewMulticallTargetCaller creates a new read-only instance of MulticallTarget, bound to a specific deployed contract. +func NewMulticallTargetCaller(address common.Address, caller bind.ContractCaller) (*MulticallTargetCaller, error) { + contract, err := bindMulticallTarget(address, caller, nil, nil) + if err != nil { + return nil, err + } + return &MulticallTargetCaller{contract: contract}, nil +} + +// NewMulticallTargetTransactor creates a new write-only instance of MulticallTarget, bound to a specific deployed contract. +func NewMulticallTargetTransactor(address common.Address, transactor bind.ContractTransactor) (*MulticallTargetTransactor, error) { + contract, err := bindMulticallTarget(address, nil, transactor, nil) + if err != nil { + return nil, err + } + return &MulticallTargetTransactor{contract: contract}, nil +} + +// NewMulticallTargetFilterer creates a new log filterer instance of MulticallTarget, bound to a specific deployed contract. +func NewMulticallTargetFilterer(address common.Address, filterer bind.ContractFilterer) (*MulticallTargetFilterer, error) { + contract, err := bindMulticallTarget(address, nil, nil, filterer) + if err != nil { + return nil, err + } + return &MulticallTargetFilterer{contract: contract}, nil +} + +// bindMulticallTarget binds a generic wrapper to an already deployed contract. +func bindMulticallTarget(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) { + parsed, err := MulticallTargetMetaData.GetAbi() + if err != nil { + return nil, err + } + return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil +} + +// Call invokes the (constant) contract method with params as input values and +// sets the output to result. The result type might be a single field for simple +// returns, a slice of interfaces for anonymous returns and a struct for named +// returns. +func (_MulticallTarget *MulticallTargetRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _MulticallTarget.Contract.MulticallTargetCaller.contract.Call(opts, result, method, params...) +} + +// Transfer initiates a plain transaction to move funds to the contract, calling +// its default method if one is available. +func (_MulticallTarget *MulticallTargetRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _MulticallTarget.Contract.MulticallTargetTransactor.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_MulticallTarget *MulticallTargetRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _MulticallTarget.Contract.MulticallTargetTransactor.contract.Transact(opts, method, params...) +} + +// Call invokes the (constant) contract method with params as input values and +// sets the output to result. The result type might be a single field for simple +// returns, a slice of interfaces for anonymous returns and a struct for named +// returns. +func (_MulticallTarget *MulticallTargetCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _MulticallTarget.Contract.contract.Call(opts, result, method, params...) +} + +// Transfer initiates a plain transaction to move funds to the contract, calling +// its default method if one is available. +func (_MulticallTarget *MulticallTargetTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _MulticallTarget.Contract.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_MulticallTarget *MulticallTargetTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _MulticallTarget.Contract.contract.Transact(opts, method, params...) +} + +// MulticallNoResults is a paid mutator transaction binding the contract method 0x3f61331d. +// +// Solidity: function multicallNoResults(bytes[] data, bool ignoreReverts) returns() +func (_MulticallTarget *MulticallTargetTransactor) MulticallNoResults(opts *bind.TransactOpts, data [][]byte, ignoreReverts bool) (*types.Transaction, error) { + return _MulticallTarget.contract.Transact(opts, "multicallNoResults", data, ignoreReverts) +} + +// MulticallNoResults is a paid mutator transaction binding the contract method 0x3f61331d. +// +// Solidity: function multicallNoResults(bytes[] data, bool ignoreReverts) returns() +func (_MulticallTarget *MulticallTargetSession) MulticallNoResults(data [][]byte, ignoreReverts bool) (*types.Transaction, error) { + return _MulticallTarget.Contract.MulticallNoResults(&_MulticallTarget.TransactOpts, data, ignoreReverts) +} + +// MulticallNoResults is a paid mutator transaction binding the contract method 0x3f61331d. +// +// Solidity: function multicallNoResults(bytes[] data, bool ignoreReverts) returns() +func (_MulticallTarget *MulticallTargetTransactorSession) MulticallNoResults(data [][]byte, ignoreReverts bool) (*types.Transaction, error) { + return _MulticallTarget.Contract.MulticallNoResults(&_MulticallTarget.TransactOpts, data, ignoreReverts) +} + +// MulticallWithResults is a paid mutator transaction binding the contract method 0x385c1d2f. +// +// Solidity: function multicallWithResults(bytes[] data, bool ignoreReverts) returns((bool,bytes)[] results) +func (_MulticallTarget *MulticallTargetTransactor) MulticallWithResults(opts *bind.TransactOpts, data [][]byte, ignoreReverts bool) (*types.Transaction, error) { + return _MulticallTarget.contract.Transact(opts, "multicallWithResults", data, ignoreReverts) +} + +// MulticallWithResults is a paid mutator transaction binding the contract method 0x385c1d2f. +// +// Solidity: function multicallWithResults(bytes[] data, bool ignoreReverts) returns((bool,bytes)[] results) +func (_MulticallTarget *MulticallTargetSession) MulticallWithResults(data [][]byte, ignoreReverts bool) (*types.Transaction, error) { + return _MulticallTarget.Contract.MulticallWithResults(&_MulticallTarget.TransactOpts, data, ignoreReverts) +} + +// MulticallWithResults is a paid mutator transaction binding the contract method 0x385c1d2f. +// +// Solidity: function multicallWithResults(bytes[] data, bool ignoreReverts) returns((bool,bytes)[] results) +func (_MulticallTarget *MulticallTargetTransactorSession) MulticallWithResults(data [][]byte, ignoreReverts bool) (*types.Transaction, error) { + return _MulticallTarget.Contract.MulticallWithResults(&_MulticallTarget.TransactOpts, data, ignoreReverts) +} + // SafeERC20MetaData contains all meta data concerning the SafeERC20 contract. var SafeERC20MetaData = &bind.MetaData{ ABI: "[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"currentAllowance\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"requestedDecrease\",\"type\":\"uint256\"}],\"name\":\"SafeERC20FailedDecreaseAllowance\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"}],\"name\":\"SafeERC20FailedOperation\",\"type\":\"error\"}]", - Bin: "0x60566037600b82828239805160001a607314602a57634e487b7160e01b600052600060045260246000fd5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600080fdfea2646970667358221220bf9b4d830342bc19a7972f35e2bc28e74742724839e41d049e96167e6d81d6ea64736f6c63430008180033", + Bin: "0x60566037600b82828239805160001a607314602a57634e487b7160e01b600052600060045260246000fd5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600080fdfea26469706673582212209fa7c4bd491bc75459d04b74ec3df4cf5631b4ff0438eacdbdda406ccb78986b64736f6c63430008180033", } // SafeERC20ABI is the input ABI used to generate the binding from. @@ -14525,7 +15182,7 @@ func (_SafeERC20 *SafeERC20TransactorRaw) Transact(opts *bind.TransactOpts, meth // UniversalTokenLibMetaData contains all meta data concerning the UniversalTokenLib contract. var UniversalTokenLibMetaData = &bind.MetaData{ ABI: "[]", - Bin: "0x60566037600b82828239805160001a607314602a57634e487b7160e01b600052600060045260246000fd5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600080fdfea264697066735822122030abe7c99e33645ff08fba6fd46ebf752f2157cc4f5e930a35e81633f8aacbb864736f6c63430008180033", + Bin: "0x60566037600b82828239805160001a607314602a57634e487b7160e01b600052600060045260246000fd5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600080fdfea26469706673582212208ee6f45538d68dae1182af6006877f66fc2bb57b5fe35283c7b3ccf352c1148364736f6c63430008180033", } // UniversalTokenLibABI is the input ABI used to generate the binding from. diff --git a/services/rfq/contracts/fastbridgev2/fastbridgev2.contractinfo.json b/services/rfq/contracts/fastbridgev2/fastbridgev2.contractinfo.json index 1ead51fc19..0b0fe18444 100644 --- a/services/rfq/contracts/fastbridgev2/fastbridgev2.contractinfo.json +++ b/services/rfq/contracts/fastbridgev2/fastbridgev2.contractinfo.json @@ -1 +1 @@ -{"solidity/FastBridgeV2.sol:AccessControl":{"code":"0x","runtime-code":"0x","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.24 ^0.8.0 ^0.8.20;\n\n// contracts/interfaces/IAdmin.sol\n\ninterface IAdmin {\n // ============ Events ============\n\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n event ChainGasAmountUpdated(uint256 oldChainGasAmount, uint256 newChainGasAmount);\n\n // ============ Methods ============\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n\n function setChainGasAmount(uint256 newChainGasAmount) external;\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IFastBridgeRecipient.sol\n\ninterface IFastBridgeRecipient {\n function fastBridgeTransferReceived(\n address token,\n uint256 amount,\n bytes memory callParams\n )\n external\n payable\n returns (bytes4);\n}\n\n// contracts/interfaces/IFastBridgeV2Errors.sol\n\ninterface IFastBridgeV2Errors {\n error AmountIncorrect();\n error CallParamsLengthAboveMax();\n error ChainIncorrect();\n error ExclusivityParamsIncorrect();\n error MsgValueIncorrect();\n error NativeTokenCallValueNotSupported();\n error SenderIncorrect();\n error StatusIncorrect();\n error ZeroAddress();\n\n error RecipientIncorrectReturnValue();\n error RecipientNoReturnValue();\n\n error DeadlineExceeded();\n error DeadlineNotExceeded();\n error DeadlineTooShort();\n error DisputePeriodNotPassed();\n error DisputePeriodPassed();\n error ExclusivityPeriodNotPassed();\n\n error TransactionRelayed();\n}\n\n// contracts/libs/Errors.sol\n\nerror DeadlineExceeded();\nerror DeadlineNotExceeded();\nerror DeadlineTooShort();\nerror InsufficientOutputAmount();\n\nerror MsgValueIncorrect();\nerror PoolNotFound();\nerror TokenAddressMismatch();\nerror TokenNotContract();\nerror TokenNotETH();\nerror TokensIdentical();\n\nerror ChainIncorrect();\nerror AmountIncorrect();\nerror ZeroAddress();\n\nerror DisputePeriodNotPassed();\nerror DisputePeriodPassed();\nerror SenderIncorrect();\nerror StatusIncorrect();\nerror TransactionIdIncorrect();\nerror TransactionRelayed();\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// contracts/interfaces/IFastBridgeV2.sol\n\ninterface IFastBridgeV2 is IFastBridge {\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n struct BridgeTxDetails {\n BridgeStatus status;\n uint40 proofBlockTimestamp;\n uint48 proofBlockNumber;\n address proofRelayer;\n }\n\n struct BridgeRelay {\n uint48 blockNumber;\n uint48 blockTimestamp;\n address relayer;\n }\n\n /// @notice New params introduced in the FastBridgeV2.\n /// We are passing fields from the older BridgeParams struct outside of this struct\n /// for backwards compatibility.\n /// Note: quoteRelayer and quoteExclusivitySeconds are either both zero (indicating no exclusivity)\n /// or both non-zero (indicating exclusivity for the given period).\n /// Note: callValue \u003e 0 can NOT be used with destToken = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE (ETH_ADDRESS)\n /// @param quoteRelayer Relayer that provided the quote for the transaction\n /// @param quoteExclusivitySeconds Period of time the quote relayer is guaranteed exclusivity after user's deposit\n /// @param quoteId Unique quote identifier used for tracking the quote\n /// @param callValue ETH value to send to the recipient (if any)\n /// @param callParams Parameters for the arbitrary call to the destination recipient (if any)\n struct BridgeParamsV2 {\n address quoteRelayer;\n int256 quoteExclusivitySeconds;\n bytes quoteId;\n uint256 callValue;\n bytes callParams;\n }\n\n /// @notice Updated bridge transaction struct to include parameters introduced in FastBridgeV2.\n /// Note: only `exclusivityRelayer` can fill such a transaction until `exclusivityEndTime`.\n /// TODO: consider changing the encoding scheme to prevent spending extra gas on decoding.\n struct BridgeTransactionV2 {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n uint256 callValue; // ETH value to send to the recipient (if any) - replaces V1's sendChainGas flag\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n address exclusivityRelayer;\n uint256 exclusivityEndTime;\n bytes callParams;\n }\n\n event BridgeQuoteDetails(bytes32 indexed transactionId, bytes quoteId);\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability\n /// to provide temporary exclusivity fill rights for the quote relayer.\n /// @param params The parameters required to bridge\n /// @param paramsV2 The parameters for exclusivity fill rights (optional, can be left empty)\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function relay(bytes memory request, address relayer) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param transactionId The transaction id associated with the encoded bridge transaction to prove\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital.\n /// @notice Can only send funds to the relayer address on the proof.\n /// @param request The encoded bridge transaction to claim on origin chain\n function claim(bytes memory request) external;\n /// @notice Checks if a transaction has been relayed\n /// @param transactionId The ID of the transaction to check\n /// @return True if the transaction has been relayed, false otherwise\n function bridgeRelays(bytes32 transactionId) external view returns (bool);\n\n /// @notice Returns the status of a bridge transaction\n /// @param transactionId The ID of the bridge transaction\n /// @return BridgeStatus Status of the bridge transaction\n function bridgeStatuses(bytes32 transactionId) external view returns (BridgeStatus);\n\n /// @notice Returns the timestamp and relayer of a bridge proof\n /// @param transactionId The ID of the bridge transaction\n /// @return timestamp The timestamp of the bridge proof\n /// @return relayer The relayer address of the bridge proof\n function bridgeProofs(bytes32 transactionId) external view returns (uint96 timestamp, address relayer);\n\n /// @notice Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\n /// @param request The bridge request to decode\n function getBridgeTransactionV2(bytes memory request) external view returns (BridgeTransactionV2 memory);\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// contracts/libs/UniversalToken.sol\n\nlibrary UniversalTokenLib {\n using SafeERC20 for IERC20;\n\n address internal constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Transfers tokens to the given account. Reverts if transfer is not successful.\n /// @dev This might trigger fallback, if ETH is transferred to the contract.\n /// Make sure this can not lead to reentrancy attacks.\n function universalTransfer(address token, address to, uint256 value) internal {\n // Don't do anything, if need to send tokens to this address\n if (to == address(this)) return;\n // Don't do anything, if trying to send zero value\n if (value == 0) return;\n if (token == ETH_ADDRESS) {\n /// @dev Note: this can potentially lead to executing code in `to`.\n // solhint-disable-next-line avoid-low-level-calls\n (bool success,) = to.call{value: value}(\"\");\n require(success, \"ETH transfer failed\");\n } else {\n IERC20(token).safeTransfer(to, value);\n }\n }\n\n /// @notice Issues an infinite allowance to the spender, if the current allowance is insufficient\n /// to spend the given amount.\n function universalApproveInfinity(address token, address spender, uint256 amountToSpend) internal {\n // ETH Chad doesn't require your approval\n if (token == ETH_ADDRESS) return;\n // No-op if allowance is already sufficient\n uint256 allowance = IERC20(token).allowance(address(this), spender);\n if (allowance \u003e= amountToSpend) return;\n // Otherwise, reset approval to 0 and set to max allowance\n if (allowance \u003e 0) IERC20(token).safeDecreaseAllowance(spender, allowance);\n IERC20(token).safeIncreaseAllowance(spender, type(uint256).max);\n }\n\n /// @notice Returns the balance of the given token (or native ETH) for the given account.\n function universalBalanceOf(address token, address account) internal view returns (uint256) {\n if (token == ETH_ADDRESS) {\n return account.balance;\n } else {\n return IERC20(token).balanceOf(account);\n }\n }\n\n /// @dev Checks that token is a contract and not ETH_ADDRESS.\n function assertIsContract(address token) internal view {\n // Check that ETH_ADDRESS was not used (in case this is a predeploy on any of the chains)\n if (token == UniversalTokenLib.ETH_ADDRESS) revert TokenNotContract();\n // Check that token is not an EOA\n if (token.code.length == 0) revert TokenNotContract();\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/Admin.sol\n\ncontract Admin is IAdmin, AccessControlEnumerable {\n using UniversalTokenLib for address;\n\n bytes32 public constant RELAYER_ROLE = keccak256(\"RELAYER_ROLE\");\n bytes32 public constant REFUNDER_ROLE = keccak256(\"REFUNDER_ROLE\");\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n uint256 public constant FEE_BPS = 1e6;\n uint256 public constant FEE_RATE_MAX = 0.01e6; // max 1% on origin amount\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Chain gas amount to forward as rebate if requested\n uint256 public chainGasAmount;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n }\n\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n require(newFeeRate \u003c= FEE_RATE_MAX, \"newFeeRate \u003e max\");\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n token.universalTransfer(recipient, feeAmount);\n emit FeesSwept(token, recipient, feeAmount);\n }\n\n function setChainGasAmount(uint256 newChainGasAmount) external onlyRole(GOVERNOR_ROLE) {\n uint256 oldChainGasAmount = chainGasAmount;\n chainGasAmount = newChainGasAmount;\n emit ChainGasAmountUpdated(oldChainGasAmount, newChainGasAmount);\n }\n}\n\n// contracts/FastBridgeV2.sol\n\n/// @notice FastBridgeV2 is a contract for bridging tokens across chains.\ncontract FastBridgeV2 is Admin, IFastBridgeV2, IFastBridgeV2Errors {\n using SafeERC20 for IERC20;\n using UniversalTokenLib for address;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Delay for a transaction after which it could be permisionlessly refunded\n uint256 public constant REFUND_DELAY = 7 days;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n /// @notice Maximum length of accepted callParams\n uint256 public constant MAX_CALL_PARAMS_LENGTH = 2 ** 16 - 1;\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeTxDetails) public bridgeTxDetails;\n /// @notice Relay details on destination chain\n mapping(bytes32 =\u003e BridgeRelay) public bridgeRelayDetails;\n /// @notice Unique bridge nonces tracked per originSender\n mapping(address =\u003e uint256) public senderNonces;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Replaced by senderNonces\n uint256 public immutable nonce = 0;\n /// @notice the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n bridge({\n params: params,\n paramsV2: BridgeParamsV2({\n quoteRelayer: address(0),\n quoteExclusivitySeconds: 0,\n quoteId: bytes(\"\"),\n callValue: 0,\n callParams: bytes(\"\")\n })\n });\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes memory request) external payable {\n relay({request: request, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes memory request, bytes32 destTxHash) external {\n prove({transactionId: keccak256(request), destTxHash: destTxHash, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridgeV2\n function claim(bytes memory request) external {\n claim({request: request, to: address(0)});\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003e DISPUTE_PERIOD) {\n revert DisputePeriodPassed();\n }\n\n // @dev relayer gets slashed effectively if dest relay has gone thru\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n bridgeTxDetails[transactionId].proofRelayer = address(0);\n bridgeTxDetails[transactionId].proofBlockTimestamp = 0;\n bridgeTxDetails[transactionId].proofBlockNumber = 0;\n\n emit BridgeProofDisputed(transactionId, msg.sender);\n }\n\n /// @inheritdoc IFastBridge\n function refund(bytes memory request) external {\n bytes32 transactionId = keccak256(request);\n\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n\n if (bridgeTxDetails[transactionId].status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n\n if (hasRole(REFUNDER_ROLE, msg.sender)) {\n // Refunder can refund if deadline has passed\n if (block.timestamp \u003c= transaction.deadline) revert DeadlineNotExceeded();\n } else {\n // Permissionless refund is allowed after REFUND_DELAY\n if (block.timestamp \u003c= transaction.deadline + REFUND_DELAY) revert DeadlineNotExceeded();\n }\n\n // if all checks passed, set to REFUNDED status\n bridgeTxDetails[transactionId].status = BridgeStatus.REFUNDED;\n\n // transfer origin collateral back to original sender\n address to = transaction.originSender;\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount + transaction.originFeeAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (bridgeTxDetails[transactionId].proofRelayer != relayer) revert SenderIncorrect();\n return _timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n /// @dev This method is added to achieve backwards compatibility with decoding requests into V1 structs:\n /// - `callValue` is partially reported as a zero/non-zero flag\n /// - `callParams` is ignored\n /// In order to process all kinds of requests use getBridgeTransactionV2 instead.\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory) {\n // Try decoding into V2 struct first. This will revert if V1 struct is passed\n try this.getBridgeTransactionV2(request) returns (BridgeTransactionV2 memory txV2) {\n // Note: we entirely ignore the callParams field, as it was not present in V1\n return BridgeTransaction({\n originChainId: txV2.originChainId,\n destChainId: txV2.destChainId,\n originSender: txV2.originSender,\n destRecipient: txV2.destRecipient,\n originToken: txV2.originToken,\n destToken: txV2.destToken,\n originAmount: txV2.originAmount,\n destAmount: txV2.destAmount,\n originFeeAmount: txV2.originFeeAmount,\n sendChainGas: txV2.callValue != 0,\n deadline: txV2.deadline,\n nonce: txV2.nonce\n });\n } catch {\n // Fallback to V1 struct\n return abi.decode(request, (BridgeTransaction));\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) public payable {\n int256 exclusivityEndTime = int256(block.timestamp) + paramsV2.quoteExclusivitySeconds;\n _validateBridgeParams(params, paramsV2, exclusivityEndTime);\n\n // transfer tokens to bridge contract\n /// @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _takeBridgedUserAsset(params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n\n // set status to requested\n bytes memory request = abi.encode(\n BridgeTransactionV2({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n callValue: paramsV2.callValue,\n deadline: params.deadline,\n nonce: senderNonces[params.sender]++, // increment nonce on every bridge\n exclusivityRelayer: paramsV2.quoteRelayer,\n // We checked exclusivityEndTime to be in range (0 .. params.deadline] above, so can safely cast\n exclusivityEndTime: uint256(exclusivityEndTime),\n callParams: paramsV2.callParams\n })\n );\n bytes32 transactionId = keccak256(request);\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n\n emit BridgeRequested({\n transactionId: transactionId,\n sender: params.sender,\n request: request,\n destChainId: params.dstChainId,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n sendChainGas: paramsV2.callValue != 0\n });\n emit BridgeQuoteDetails(transactionId, paramsV2.quoteId);\n }\n\n /// @inheritdoc IFastBridgeV2\n function relay(bytes memory request, address relayer) public payable {\n bytes32 transactionId = keccak256(request);\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n _validateRelayParams(transaction, transactionId, relayer);\n // mark bridge transaction as relayed\n bridgeRelayDetails[transactionId] =\n BridgeRelay({blockNumber: uint48(block.number), blockTimestamp: uint48(block.timestamp), relayer: relayer});\n\n // transfer tokens to recipient on destination chain and do an arbitrary call if requested\n address to = transaction.destRecipient;\n address token = transaction.destToken;\n uint256 amount = transaction.destAmount;\n uint256 callValue = transaction.callValue;\n\n // Emit the event before any external calls\n emit BridgeRelayed({\n transactionId: transactionId,\n relayer: relayer,\n to: to,\n originChainId: transaction.originChainId,\n originToken: transaction.originToken,\n destToken: token,\n originAmount: transaction.originAmount,\n destAmount: amount,\n chainGasAmount: callValue\n });\n\n // All state changes have been done at this point, can proceed to the external calls.\n // This follows the checks-effects-interactions pattern to mitigate potential reentrancy attacks.\n if (token == UniversalTokenLib.ETH_ADDRESS) {\n // For ETH non-zero callValue is not allowed\n if (callValue != 0) revert NativeTokenCallValueNotSupported();\n // Check that the correct msg.value was sent\n if (msg.value != amount) revert MsgValueIncorrect();\n } else {\n // For ERC20s, we check that the correct msg.value was sent\n if (msg.value != callValue) revert MsgValueIncorrect();\n // We need to transfer the tokens from the Relayer to the recipient first before performing an\n // optional post-transfer arbitrary call.\n IERC20(token).safeTransferFrom(msg.sender, to, amount);\n }\n\n if (transaction.callParams.length != 0) {\n // Arbitrary call requested, perform it while supplying full msg.value to the recipient\n // Note: if token has a fee on transfers, the recipient will have received less than `amount`.\n // This is a very niche edge case and should be handled by the recipient contract.\n _checkedCallRecipient({recipient: to, token: token, amount: amount, callParams: transaction.callParams});\n } else if (msg.value != 0) {\n // No arbitrary call requested, but msg.value was sent. This is either a relay with ETH,\n // or a non-zero callValue request with an ERC20. In both cases, transfer the ETH to the recipient.\n Address.sendValue(payable(to), msg.value);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) public onlyRole(RELAYER_ROLE) {\n // update bridge tx status given proof provided\n if (bridgeTxDetails[transactionId].status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n bridgeTxDetails[transactionId].status = BridgeStatus.RELAYER_PROVED;\n bridgeTxDetails[transactionId].proofBlockTimestamp = uint40(block.timestamp);\n bridgeTxDetails[transactionId].proofBlockNumber = uint48(block.number);\n bridgeTxDetails[transactionId].proofRelayer = relayer;\n\n emit BridgeProofProvided(transactionId, relayer, destTxHash);\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes memory request, address to) public {\n bytes32 transactionId = keccak256(request);\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n\n // update bridge tx status if able to claim origin collateral\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n\n // if \"to\" is zero addr, permissionlessly send funds to proven relayer\n if (to == address(0)) {\n to = bridgeTxDetails[transactionId].proofRelayer;\n } else if (bridgeTxDetails[transactionId].proofRelayer != msg.sender) {\n revert SenderIncorrect();\n }\n\n if (_timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003c= DISPUTE_PERIOD) {\n revert DisputePeriodNotPassed();\n }\n\n bridgeTxDetails[transactionId].status = BridgeStatus.RELAYER_CLAIMED;\n\n // update protocol fees if origin fee amount exists\n if (transaction.originFeeAmount \u003e 0) protocolFees[transaction.originToken] += transaction.originFeeAmount;\n\n // transfer origin collateral less fee to specified address\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositClaimed(transactionId, bridgeTxDetails[transactionId].proofRelayer, to, token, amount);\n }\n\n function bridgeStatuses(bytes32 transactionId) public view returns (BridgeStatus status) {\n return bridgeTxDetails[transactionId].status;\n }\n\n function bridgeProofs(bytes32 transactionId) public view returns (uint96 timestamp, address relayer) {\n timestamp = bridgeTxDetails[transactionId].proofBlockTimestamp;\n relayer = bridgeTxDetails[transactionId].proofRelayer;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeRelays(bytes32 transactionId) public view returns (bool) {\n // has this transactionId been relayed?\n return bridgeRelayDetails[transactionId].relayer != address(0);\n }\n\n /// @inheritdoc IFastBridgeV2\n function getBridgeTransactionV2(bytes memory request) public pure returns (BridgeTransactionV2 memory) {\n return abi.decode(request, (BridgeTransactionV2));\n }\n\n /// @notice Takes the bridged asset from the user into FastBridgeV2 custody. It will be later\n /// claimed by the relayer who completed the relay on destination chain, or refunded back to the user,\n /// should no one complete the relay.\n function _takeBridgedUserAsset(address token, uint256 amount) internal returns (uint256 amountTaken) {\n if (token == UniversalTokenLib.ETH_ADDRESS) {\n // For ETH we just need to check that the supplied msg.value is correct.\n // Supplied `msg.value` is already in FastBridgeV2 custody.\n if (amount != msg.value) revert MsgValueIncorrect();\n amountTaken = msg.value;\n } else {\n // For ERC20s, token is explicitly transferred from the user to FastBridgeV2.\n // We don't allow non-zero `msg.value` to avoid extra funds from being stuck in FastBridgeV2.\n token.assertIsContract();\n if (msg.value != 0) revert MsgValueIncorrect();\n amountTaken = IERC20(token).balanceOf(address(this));\n IERC20(token).safeTransferFrom(msg.sender, address(this), amount);\n // Use the balance difference as the amount taken in case of fee on transfer tokens.\n amountTaken = IERC20(token).balanceOf(address(this)) - amountTaken;\n }\n }\n\n /// @notice Calls the Recipient's hook function with the specified callParams and performs\n /// all the necessary checks for the returned value.\n function _checkedCallRecipient(\n address recipient,\n address token,\n uint256 amount,\n bytes memory callParams\n )\n internal\n {\n bytes memory hookData =\n abi.encodeCall(IFastBridgeRecipient.fastBridgeTransferReceived, (token, amount, callParams));\n // This will bubble any revert messages from the hook function\n bytes memory returnData = Address.functionCallWithValue({target: recipient, data: hookData, value: msg.value});\n // Explicit revert if no return data at all\n if (returnData.length == 0) revert RecipientNoReturnValue();\n // Check that exactly a single return value was returned\n if (returnData.length != 32) revert RecipientIncorrectReturnValue();\n // Return value should be abi-encoded hook function selector\n if (bytes32(returnData) != bytes32(IFastBridgeRecipient.fastBridgeTransferReceived.selector)) {\n revert RecipientIncorrectReturnValue();\n }\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint40(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint40).max but\n /// proof.timestamp \u003c type(uint40).max via unchecked statement\n /// @param proofBlockTimestamp The bridge proof block timestamp\n /// @return delta Time delta since proof submitted\n function _timeSince(uint40 proofBlockTimestamp) internal view returns (uint256 delta) {\n unchecked {\n delta = uint40(block.timestamp) - proofBlockTimestamp;\n }\n }\n\n /// @notice Performs all the necessary checks for a bridge to happen.\n /// @dev There's no good way to refactor this function to reduce cyclomatic complexity due to\n /// the number of checks that need to be performed, so we skip the code-complexity rule here.\n // solhint-disable-next-line code-complexity\n function _validateBridgeParams(\n BridgeParams memory params,\n BridgeParamsV2 memory paramsV2,\n int256 exclusivityEndTime\n )\n internal\n view\n {\n // Check V1 (legacy) params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.sender == address(0) || params.to == address(0)) revert ZeroAddress();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n // Check V2 params\n if (paramsV2.callParams.length \u003e MAX_CALL_PARAMS_LENGTH) revert CallParamsLengthAboveMax();\n if (paramsV2.callValue != 0 \u0026\u0026 params.destToken == UniversalTokenLib.ETH_ADDRESS) {\n revert NativeTokenCallValueNotSupported();\n }\n // exclusivityEndTime must be in range (0 .. params.deadline]\n if (exclusivityEndTime \u003c= 0 || exclusivityEndTime \u003e int256(params.deadline)) {\n revert ExclusivityParamsIncorrect();\n }\n }\n\n /// @notice Performs all the necessary checks for a relay to happen.\n function _validateRelayParams(\n BridgeTransactionV2 memory transaction,\n bytes32 transactionId,\n address relayer\n )\n internal\n view\n {\n if (relayer == address(0)) revert ZeroAddress();\n // Check if the transaction has already been relayed\n if (bridgeRelays(transactionId)) revert TransactionRelayed();\n if (transaction.destChainId != block.chainid) revert ChainIncorrect();\n // Check the deadline for relay to happen\n if (block.timestamp \u003e transaction.deadline) revert DeadlineExceeded();\n // Check the exclusivity period, if it is still ongoing\n // forgefmt: disable-next-item\n if (\n transaction.exclusivityRelayer != address(0) \u0026\u0026\n transaction.exclusivityRelayer != relayer \u0026\u0026\n block.timestamp \u003c= transaction.exclusivityEndTime\n ) {\n revert ExclusivityPeriodNotPassed();\n }\n }\n}\n","language":"Solidity","languageVersion":"0.8.24","compilerVersion":"0.8.24","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"","srcMapRuntime":"","abiDefinition":[{"inputs":[],"name":"AccessControlBadConfirmation","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"bytes32","name":"neededRole","type":"bytes32"}],"name":"AccessControlUnauthorizedAccount","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"previousAdminRole","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"newAdminRole","type":"bytes32"}],"name":"RoleAdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleRevoked","type":"event"},{"inputs":[],"name":"DEFAULT_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleAdmin","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"grantRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"hasRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"callerConfirmation","type":"address"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"revokeRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"}],"userDoc":{"kind":"user","methods":{},"version":1},"developerDoc":{"details":"Contract module that allows children to implement role-based access control mechanisms. This is a lightweight version that doesn't allow enumerating role members except through off-chain means by accessing the contract event logs. Some applications may benefit from on-chain enumerability, for those cases see {AccessControlEnumerable}. Roles are referred to by their `bytes32` identifier. These should be exposed in the external API and be unique. The best way to achieve this is by using `public constant` hash digests: ```solidity bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\"); ``` Roles can be used to represent a set of permissions. To restrict access to a function call, use {hasRole}: ```solidity function foo() public { require(hasRole(MY_ROLE, msg.sender)); ... } ``` Roles can be granted and revoked dynamically via the {grantRole} and {revokeRole} functions. Each role has an associated admin role, and only accounts that have a role's admin role can call {grantRole} and {revokeRole}. By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means that only accounts with this role will be able to grant or revoke other roles. More complex role relationships can be created by using {_setRoleAdmin}. WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to grant and revoke this role. Extra precautions should be taken to secure accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules} to enforce additional security measures for this role.","errors":{"AccessControlBadConfirmation()":[{"details":"The caller of a function is not the expected one. NOTE: Don't confuse with {AccessControlUnauthorizedAccount}."}],"AccessControlUnauthorizedAccount(address,bytes32)":[{"details":"The `account` is missing a role."}]},"events":{"RoleAdminChanged(bytes32,bytes32,bytes32)":{"details":"Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole` `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite {RoleAdminChanged} not being emitted signaling this."},"RoleGranted(bytes32,address,address)":{"details":"Emitted when `account` is granted `role`. `sender` is the account that originated the contract call, an admin role bearer except when using {AccessControl-_setupRole}."},"RoleRevoked(bytes32,address,address)":{"details":"Emitted when `account` is revoked `role`. `sender` is the account that originated the contract call: - if using `revokeRole`, it is the admin role bearer - if using `renounceRole`, it is the role bearer (i.e. `account`)"}},"kind":"dev","methods":{"getRoleAdmin(bytes32)":{"details":"Returns the admin role that controls `role`. See {grantRole} and {revokeRole}. To change a role's admin, use {_setRoleAdmin}."},"grantRole(bytes32,address)":{"details":"Grants `role` to `account`. If `account` had not been already granted `role`, emits a {RoleGranted} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleGranted} event."},"hasRole(bytes32,address)":{"details":"Returns `true` if `account` has been granted `role`."},"renounceRole(bytes32,address)":{"details":"Revokes `role` from the calling account. Roles are often managed via {grantRole} and {revokeRole}: this function's purpose is to provide a mechanism for accounts to lose their privileges if they are compromised (such as when a trusted device is misplaced). If the calling account had been revoked `role`, emits a {RoleRevoked} event. Requirements: - the caller must be `callerConfirmation`. May emit a {RoleRevoked} event."},"revokeRole(bytes32,address)":{"details":"Revokes `role` from `account`. If `account` had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleRevoked} event."},"supportsInterface(bytes4)":{"details":"See {IERC165-supportsInterface}."}},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[],\"name\":\"AccessControlBadConfirmation\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"neededRole\",\"type\":\"bytes32\"}],\"name\":\"AccessControlUnauthorizedAccount\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"previousAdminRole\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"newAdminRole\",\"type\":\"bytes32\"}],\"name\":\"RoleAdminChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleGranted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleRevoked\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"DEFAULT_ADMIN_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"}],\"name\":\"getRoleAdmin\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"grantRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"hasRole\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"callerConfirmation\",\"type\":\"address\"}],\"name\":\"renounceRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"revokeRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes4\",\"name\":\"interfaceId\",\"type\":\"bytes4\"}],\"name\":\"supportsInterface\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"}],\"devdoc\":{\"details\":\"Contract module that allows children to implement role-based access control mechanisms. This is a lightweight version that doesn't allow enumerating role members except through off-chain means by accessing the contract event logs. Some applications may benefit from on-chain enumerability, for those cases see {AccessControlEnumerable}. Roles are referred to by their `bytes32` identifier. These should be exposed in the external API and be unique. The best way to achieve this is by using `public constant` hash digests: ```solidity bytes32 public constant MY_ROLE = keccak256(\\\"MY_ROLE\\\"); ``` Roles can be used to represent a set of permissions. To restrict access to a function call, use {hasRole}: ```solidity function foo() public { require(hasRole(MY_ROLE, msg.sender)); ... } ``` Roles can be granted and revoked dynamically via the {grantRole} and {revokeRole} functions. Each role has an associated admin role, and only accounts that have a role's admin role can call {grantRole} and {revokeRole}. By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means that only accounts with this role will be able to grant or revoke other roles. More complex role relationships can be created by using {_setRoleAdmin}. WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to grant and revoke this role. Extra precautions should be taken to secure accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules} to enforce additional security measures for this role.\",\"errors\":{\"AccessControlBadConfirmation()\":[{\"details\":\"The caller of a function is not the expected one. NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\"}],\"AccessControlUnauthorizedAccount(address,bytes32)\":[{\"details\":\"The `account` is missing a role.\"}]},\"events\":{\"RoleAdminChanged(bytes32,bytes32,bytes32)\":{\"details\":\"Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole` `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite {RoleAdminChanged} not being emitted signaling this.\"},\"RoleGranted(bytes32,address,address)\":{\"details\":\"Emitted when `account` is granted `role`. `sender` is the account that originated the contract call, an admin role bearer except when using {AccessControl-_setupRole}.\"},\"RoleRevoked(bytes32,address,address)\":{\"details\":\"Emitted when `account` is revoked `role`. `sender` is the account that originated the contract call: - if using `revokeRole`, it is the admin role bearer - if using `renounceRole`, it is the role bearer (i.e. `account`)\"}},\"kind\":\"dev\",\"methods\":{\"getRoleAdmin(bytes32)\":{\"details\":\"Returns the admin role that controls `role`. See {grantRole} and {revokeRole}. To change a role's admin, use {_setRoleAdmin}.\"},\"grantRole(bytes32,address)\":{\"details\":\"Grants `role` to `account`. If `account` had not been already granted `role`, emits a {RoleGranted} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleGranted} event.\"},\"hasRole(bytes32,address)\":{\"details\":\"Returns `true` if `account` has been granted `role`.\"},\"renounceRole(bytes32,address)\":{\"details\":\"Revokes `role` from the calling account. Roles are often managed via {grantRole} and {revokeRole}: this function's purpose is to provide a mechanism for accounts to lose their privileges if they are compromised (such as when a trusted device is misplaced). If the calling account had been revoked `role`, emits a {RoleRevoked} event. Requirements: - the caller must be `callerConfirmation`. May emit a {RoleRevoked} event.\"},\"revokeRole(bytes32,address)\":{\"details\":\"Revokes `role` from `account`. If `account` had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleRevoked} event.\"},\"supportsInterface(bytes4)\":{\"details\":\"See {IERC165-supportsInterface}.\"}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeV2.sol\":\"AccessControl\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeV2.sol\":{\"keccak256\":\"0xfd916c030b1ffca5a136817827b8018c8ba42ca089905747f3de6148b73eb35e\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://18e6438c4096deb8ae453fb3365ba2b07d52944e93c08288fc5d012b71bf6bb3\",\"dweb:/ipfs/QmfEMqpT1zz6RRm7UuHLRowe1tds2cTGLrVonfm9XSCACj\"]}},\"version\":1}"},"hashes":{"DEFAULT_ADMIN_ROLE()":"a217fddf","getRoleAdmin(bytes32)":"248a9ca3","grantRole(bytes32,address)":"2f2ff15d","hasRole(bytes32,address)":"91d14854","renounceRole(bytes32,address)":"36568abe","revokeRole(bytes32,address)":"d547741f","supportsInterface(bytes4)":"01ffc9a7"}},"solidity/FastBridgeV2.sol:AccessControlEnumerable":{"code":"0x","runtime-code":"0x","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.24 ^0.8.0 ^0.8.20;\n\n// contracts/interfaces/IAdmin.sol\n\ninterface IAdmin {\n // ============ Events ============\n\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n event ChainGasAmountUpdated(uint256 oldChainGasAmount, uint256 newChainGasAmount);\n\n // ============ Methods ============\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n\n function setChainGasAmount(uint256 newChainGasAmount) external;\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IFastBridgeRecipient.sol\n\ninterface IFastBridgeRecipient {\n function fastBridgeTransferReceived(\n address token,\n uint256 amount,\n bytes memory callParams\n )\n external\n payable\n returns (bytes4);\n}\n\n// contracts/interfaces/IFastBridgeV2Errors.sol\n\ninterface IFastBridgeV2Errors {\n error AmountIncorrect();\n error CallParamsLengthAboveMax();\n error ChainIncorrect();\n error ExclusivityParamsIncorrect();\n error MsgValueIncorrect();\n error NativeTokenCallValueNotSupported();\n error SenderIncorrect();\n error StatusIncorrect();\n error ZeroAddress();\n\n error RecipientIncorrectReturnValue();\n error RecipientNoReturnValue();\n\n error DeadlineExceeded();\n error DeadlineNotExceeded();\n error DeadlineTooShort();\n error DisputePeriodNotPassed();\n error DisputePeriodPassed();\n error ExclusivityPeriodNotPassed();\n\n error TransactionRelayed();\n}\n\n// contracts/libs/Errors.sol\n\nerror DeadlineExceeded();\nerror DeadlineNotExceeded();\nerror DeadlineTooShort();\nerror InsufficientOutputAmount();\n\nerror MsgValueIncorrect();\nerror PoolNotFound();\nerror TokenAddressMismatch();\nerror TokenNotContract();\nerror TokenNotETH();\nerror TokensIdentical();\n\nerror ChainIncorrect();\nerror AmountIncorrect();\nerror ZeroAddress();\n\nerror DisputePeriodNotPassed();\nerror DisputePeriodPassed();\nerror SenderIncorrect();\nerror StatusIncorrect();\nerror TransactionIdIncorrect();\nerror TransactionRelayed();\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// contracts/interfaces/IFastBridgeV2.sol\n\ninterface IFastBridgeV2 is IFastBridge {\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n struct BridgeTxDetails {\n BridgeStatus status;\n uint40 proofBlockTimestamp;\n uint48 proofBlockNumber;\n address proofRelayer;\n }\n\n struct BridgeRelay {\n uint48 blockNumber;\n uint48 blockTimestamp;\n address relayer;\n }\n\n /// @notice New params introduced in the FastBridgeV2.\n /// We are passing fields from the older BridgeParams struct outside of this struct\n /// for backwards compatibility.\n /// Note: quoteRelayer and quoteExclusivitySeconds are either both zero (indicating no exclusivity)\n /// or both non-zero (indicating exclusivity for the given period).\n /// Note: callValue \u003e 0 can NOT be used with destToken = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE (ETH_ADDRESS)\n /// @param quoteRelayer Relayer that provided the quote for the transaction\n /// @param quoteExclusivitySeconds Period of time the quote relayer is guaranteed exclusivity after user's deposit\n /// @param quoteId Unique quote identifier used for tracking the quote\n /// @param callValue ETH value to send to the recipient (if any)\n /// @param callParams Parameters for the arbitrary call to the destination recipient (if any)\n struct BridgeParamsV2 {\n address quoteRelayer;\n int256 quoteExclusivitySeconds;\n bytes quoteId;\n uint256 callValue;\n bytes callParams;\n }\n\n /// @notice Updated bridge transaction struct to include parameters introduced in FastBridgeV2.\n /// Note: only `exclusivityRelayer` can fill such a transaction until `exclusivityEndTime`.\n /// TODO: consider changing the encoding scheme to prevent spending extra gas on decoding.\n struct BridgeTransactionV2 {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n uint256 callValue; // ETH value to send to the recipient (if any) - replaces V1's sendChainGas flag\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n address exclusivityRelayer;\n uint256 exclusivityEndTime;\n bytes callParams;\n }\n\n event BridgeQuoteDetails(bytes32 indexed transactionId, bytes quoteId);\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability\n /// to provide temporary exclusivity fill rights for the quote relayer.\n /// @param params The parameters required to bridge\n /// @param paramsV2 The parameters for exclusivity fill rights (optional, can be left empty)\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function relay(bytes memory request, address relayer) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param transactionId The transaction id associated with the encoded bridge transaction to prove\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital.\n /// @notice Can only send funds to the relayer address on the proof.\n /// @param request The encoded bridge transaction to claim on origin chain\n function claim(bytes memory request) external;\n /// @notice Checks if a transaction has been relayed\n /// @param transactionId The ID of the transaction to check\n /// @return True if the transaction has been relayed, false otherwise\n function bridgeRelays(bytes32 transactionId) external view returns (bool);\n\n /// @notice Returns the status of a bridge transaction\n /// @param transactionId The ID of the bridge transaction\n /// @return BridgeStatus Status of the bridge transaction\n function bridgeStatuses(bytes32 transactionId) external view returns (BridgeStatus);\n\n /// @notice Returns the timestamp and relayer of a bridge proof\n /// @param transactionId The ID of the bridge transaction\n /// @return timestamp The timestamp of the bridge proof\n /// @return relayer The relayer address of the bridge proof\n function bridgeProofs(bytes32 transactionId) external view returns (uint96 timestamp, address relayer);\n\n /// @notice Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\n /// @param request The bridge request to decode\n function getBridgeTransactionV2(bytes memory request) external view returns (BridgeTransactionV2 memory);\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// contracts/libs/UniversalToken.sol\n\nlibrary UniversalTokenLib {\n using SafeERC20 for IERC20;\n\n address internal constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Transfers tokens to the given account. Reverts if transfer is not successful.\n /// @dev This might trigger fallback, if ETH is transferred to the contract.\n /// Make sure this can not lead to reentrancy attacks.\n function universalTransfer(address token, address to, uint256 value) internal {\n // Don't do anything, if need to send tokens to this address\n if (to == address(this)) return;\n // Don't do anything, if trying to send zero value\n if (value == 0) return;\n if (token == ETH_ADDRESS) {\n /// @dev Note: this can potentially lead to executing code in `to`.\n // solhint-disable-next-line avoid-low-level-calls\n (bool success,) = to.call{value: value}(\"\");\n require(success, \"ETH transfer failed\");\n } else {\n IERC20(token).safeTransfer(to, value);\n }\n }\n\n /// @notice Issues an infinite allowance to the spender, if the current allowance is insufficient\n /// to spend the given amount.\n function universalApproveInfinity(address token, address spender, uint256 amountToSpend) internal {\n // ETH Chad doesn't require your approval\n if (token == ETH_ADDRESS) return;\n // No-op if allowance is already sufficient\n uint256 allowance = IERC20(token).allowance(address(this), spender);\n if (allowance \u003e= amountToSpend) return;\n // Otherwise, reset approval to 0 and set to max allowance\n if (allowance \u003e 0) IERC20(token).safeDecreaseAllowance(spender, allowance);\n IERC20(token).safeIncreaseAllowance(spender, type(uint256).max);\n }\n\n /// @notice Returns the balance of the given token (or native ETH) for the given account.\n function universalBalanceOf(address token, address account) internal view returns (uint256) {\n if (token == ETH_ADDRESS) {\n return account.balance;\n } else {\n return IERC20(token).balanceOf(account);\n }\n }\n\n /// @dev Checks that token is a contract and not ETH_ADDRESS.\n function assertIsContract(address token) internal view {\n // Check that ETH_ADDRESS was not used (in case this is a predeploy on any of the chains)\n if (token == UniversalTokenLib.ETH_ADDRESS) revert TokenNotContract();\n // Check that token is not an EOA\n if (token.code.length == 0) revert TokenNotContract();\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/Admin.sol\n\ncontract Admin is IAdmin, AccessControlEnumerable {\n using UniversalTokenLib for address;\n\n bytes32 public constant RELAYER_ROLE = keccak256(\"RELAYER_ROLE\");\n bytes32 public constant REFUNDER_ROLE = keccak256(\"REFUNDER_ROLE\");\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n uint256 public constant FEE_BPS = 1e6;\n uint256 public constant FEE_RATE_MAX = 0.01e6; // max 1% on origin amount\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Chain gas amount to forward as rebate if requested\n uint256 public chainGasAmount;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n }\n\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n require(newFeeRate \u003c= FEE_RATE_MAX, \"newFeeRate \u003e max\");\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n token.universalTransfer(recipient, feeAmount);\n emit FeesSwept(token, recipient, feeAmount);\n }\n\n function setChainGasAmount(uint256 newChainGasAmount) external onlyRole(GOVERNOR_ROLE) {\n uint256 oldChainGasAmount = chainGasAmount;\n chainGasAmount = newChainGasAmount;\n emit ChainGasAmountUpdated(oldChainGasAmount, newChainGasAmount);\n }\n}\n\n// contracts/FastBridgeV2.sol\n\n/// @notice FastBridgeV2 is a contract for bridging tokens across chains.\ncontract FastBridgeV2 is Admin, IFastBridgeV2, IFastBridgeV2Errors {\n using SafeERC20 for IERC20;\n using UniversalTokenLib for address;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Delay for a transaction after which it could be permisionlessly refunded\n uint256 public constant REFUND_DELAY = 7 days;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n /// @notice Maximum length of accepted callParams\n uint256 public constant MAX_CALL_PARAMS_LENGTH = 2 ** 16 - 1;\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeTxDetails) public bridgeTxDetails;\n /// @notice Relay details on destination chain\n mapping(bytes32 =\u003e BridgeRelay) public bridgeRelayDetails;\n /// @notice Unique bridge nonces tracked per originSender\n mapping(address =\u003e uint256) public senderNonces;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Replaced by senderNonces\n uint256 public immutable nonce = 0;\n /// @notice the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n bridge({\n params: params,\n paramsV2: BridgeParamsV2({\n quoteRelayer: address(0),\n quoteExclusivitySeconds: 0,\n quoteId: bytes(\"\"),\n callValue: 0,\n callParams: bytes(\"\")\n })\n });\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes memory request) external payable {\n relay({request: request, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes memory request, bytes32 destTxHash) external {\n prove({transactionId: keccak256(request), destTxHash: destTxHash, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridgeV2\n function claim(bytes memory request) external {\n claim({request: request, to: address(0)});\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003e DISPUTE_PERIOD) {\n revert DisputePeriodPassed();\n }\n\n // @dev relayer gets slashed effectively if dest relay has gone thru\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n bridgeTxDetails[transactionId].proofRelayer = address(0);\n bridgeTxDetails[transactionId].proofBlockTimestamp = 0;\n bridgeTxDetails[transactionId].proofBlockNumber = 0;\n\n emit BridgeProofDisputed(transactionId, msg.sender);\n }\n\n /// @inheritdoc IFastBridge\n function refund(bytes memory request) external {\n bytes32 transactionId = keccak256(request);\n\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n\n if (bridgeTxDetails[transactionId].status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n\n if (hasRole(REFUNDER_ROLE, msg.sender)) {\n // Refunder can refund if deadline has passed\n if (block.timestamp \u003c= transaction.deadline) revert DeadlineNotExceeded();\n } else {\n // Permissionless refund is allowed after REFUND_DELAY\n if (block.timestamp \u003c= transaction.deadline + REFUND_DELAY) revert DeadlineNotExceeded();\n }\n\n // if all checks passed, set to REFUNDED status\n bridgeTxDetails[transactionId].status = BridgeStatus.REFUNDED;\n\n // transfer origin collateral back to original sender\n address to = transaction.originSender;\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount + transaction.originFeeAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (bridgeTxDetails[transactionId].proofRelayer != relayer) revert SenderIncorrect();\n return _timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n /// @dev This method is added to achieve backwards compatibility with decoding requests into V1 structs:\n /// - `callValue` is partially reported as a zero/non-zero flag\n /// - `callParams` is ignored\n /// In order to process all kinds of requests use getBridgeTransactionV2 instead.\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory) {\n // Try decoding into V2 struct first. This will revert if V1 struct is passed\n try this.getBridgeTransactionV2(request) returns (BridgeTransactionV2 memory txV2) {\n // Note: we entirely ignore the callParams field, as it was not present in V1\n return BridgeTransaction({\n originChainId: txV2.originChainId,\n destChainId: txV2.destChainId,\n originSender: txV2.originSender,\n destRecipient: txV2.destRecipient,\n originToken: txV2.originToken,\n destToken: txV2.destToken,\n originAmount: txV2.originAmount,\n destAmount: txV2.destAmount,\n originFeeAmount: txV2.originFeeAmount,\n sendChainGas: txV2.callValue != 0,\n deadline: txV2.deadline,\n nonce: txV2.nonce\n });\n } catch {\n // Fallback to V1 struct\n return abi.decode(request, (BridgeTransaction));\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) public payable {\n int256 exclusivityEndTime = int256(block.timestamp) + paramsV2.quoteExclusivitySeconds;\n _validateBridgeParams(params, paramsV2, exclusivityEndTime);\n\n // transfer tokens to bridge contract\n /// @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _takeBridgedUserAsset(params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n\n // set status to requested\n bytes memory request = abi.encode(\n BridgeTransactionV2({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n callValue: paramsV2.callValue,\n deadline: params.deadline,\n nonce: senderNonces[params.sender]++, // increment nonce on every bridge\n exclusivityRelayer: paramsV2.quoteRelayer,\n // We checked exclusivityEndTime to be in range (0 .. params.deadline] above, so can safely cast\n exclusivityEndTime: uint256(exclusivityEndTime),\n callParams: paramsV2.callParams\n })\n );\n bytes32 transactionId = keccak256(request);\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n\n emit BridgeRequested({\n transactionId: transactionId,\n sender: params.sender,\n request: request,\n destChainId: params.dstChainId,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n sendChainGas: paramsV2.callValue != 0\n });\n emit BridgeQuoteDetails(transactionId, paramsV2.quoteId);\n }\n\n /// @inheritdoc IFastBridgeV2\n function relay(bytes memory request, address relayer) public payable {\n bytes32 transactionId = keccak256(request);\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n _validateRelayParams(transaction, transactionId, relayer);\n // mark bridge transaction as relayed\n bridgeRelayDetails[transactionId] =\n BridgeRelay({blockNumber: uint48(block.number), blockTimestamp: uint48(block.timestamp), relayer: relayer});\n\n // transfer tokens to recipient on destination chain and do an arbitrary call if requested\n address to = transaction.destRecipient;\n address token = transaction.destToken;\n uint256 amount = transaction.destAmount;\n uint256 callValue = transaction.callValue;\n\n // Emit the event before any external calls\n emit BridgeRelayed({\n transactionId: transactionId,\n relayer: relayer,\n to: to,\n originChainId: transaction.originChainId,\n originToken: transaction.originToken,\n destToken: token,\n originAmount: transaction.originAmount,\n destAmount: amount,\n chainGasAmount: callValue\n });\n\n // All state changes have been done at this point, can proceed to the external calls.\n // This follows the checks-effects-interactions pattern to mitigate potential reentrancy attacks.\n if (token == UniversalTokenLib.ETH_ADDRESS) {\n // For ETH non-zero callValue is not allowed\n if (callValue != 0) revert NativeTokenCallValueNotSupported();\n // Check that the correct msg.value was sent\n if (msg.value != amount) revert MsgValueIncorrect();\n } else {\n // For ERC20s, we check that the correct msg.value was sent\n if (msg.value != callValue) revert MsgValueIncorrect();\n // We need to transfer the tokens from the Relayer to the recipient first before performing an\n // optional post-transfer arbitrary call.\n IERC20(token).safeTransferFrom(msg.sender, to, amount);\n }\n\n if (transaction.callParams.length != 0) {\n // Arbitrary call requested, perform it while supplying full msg.value to the recipient\n // Note: if token has a fee on transfers, the recipient will have received less than `amount`.\n // This is a very niche edge case and should be handled by the recipient contract.\n _checkedCallRecipient({recipient: to, token: token, amount: amount, callParams: transaction.callParams});\n } else if (msg.value != 0) {\n // No arbitrary call requested, but msg.value was sent. This is either a relay with ETH,\n // or a non-zero callValue request with an ERC20. In both cases, transfer the ETH to the recipient.\n Address.sendValue(payable(to), msg.value);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) public onlyRole(RELAYER_ROLE) {\n // update bridge tx status given proof provided\n if (bridgeTxDetails[transactionId].status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n bridgeTxDetails[transactionId].status = BridgeStatus.RELAYER_PROVED;\n bridgeTxDetails[transactionId].proofBlockTimestamp = uint40(block.timestamp);\n bridgeTxDetails[transactionId].proofBlockNumber = uint48(block.number);\n bridgeTxDetails[transactionId].proofRelayer = relayer;\n\n emit BridgeProofProvided(transactionId, relayer, destTxHash);\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes memory request, address to) public {\n bytes32 transactionId = keccak256(request);\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n\n // update bridge tx status if able to claim origin collateral\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n\n // if \"to\" is zero addr, permissionlessly send funds to proven relayer\n if (to == address(0)) {\n to = bridgeTxDetails[transactionId].proofRelayer;\n } else if (bridgeTxDetails[transactionId].proofRelayer != msg.sender) {\n revert SenderIncorrect();\n }\n\n if (_timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003c= DISPUTE_PERIOD) {\n revert DisputePeriodNotPassed();\n }\n\n bridgeTxDetails[transactionId].status = BridgeStatus.RELAYER_CLAIMED;\n\n // update protocol fees if origin fee amount exists\n if (transaction.originFeeAmount \u003e 0) protocolFees[transaction.originToken] += transaction.originFeeAmount;\n\n // transfer origin collateral less fee to specified address\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositClaimed(transactionId, bridgeTxDetails[transactionId].proofRelayer, to, token, amount);\n }\n\n function bridgeStatuses(bytes32 transactionId) public view returns (BridgeStatus status) {\n return bridgeTxDetails[transactionId].status;\n }\n\n function bridgeProofs(bytes32 transactionId) public view returns (uint96 timestamp, address relayer) {\n timestamp = bridgeTxDetails[transactionId].proofBlockTimestamp;\n relayer = bridgeTxDetails[transactionId].proofRelayer;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeRelays(bytes32 transactionId) public view returns (bool) {\n // has this transactionId been relayed?\n return bridgeRelayDetails[transactionId].relayer != address(0);\n }\n\n /// @inheritdoc IFastBridgeV2\n function getBridgeTransactionV2(bytes memory request) public pure returns (BridgeTransactionV2 memory) {\n return abi.decode(request, (BridgeTransactionV2));\n }\n\n /// @notice Takes the bridged asset from the user into FastBridgeV2 custody. It will be later\n /// claimed by the relayer who completed the relay on destination chain, or refunded back to the user,\n /// should no one complete the relay.\n function _takeBridgedUserAsset(address token, uint256 amount) internal returns (uint256 amountTaken) {\n if (token == UniversalTokenLib.ETH_ADDRESS) {\n // For ETH we just need to check that the supplied msg.value is correct.\n // Supplied `msg.value` is already in FastBridgeV2 custody.\n if (amount != msg.value) revert MsgValueIncorrect();\n amountTaken = msg.value;\n } else {\n // For ERC20s, token is explicitly transferred from the user to FastBridgeV2.\n // We don't allow non-zero `msg.value` to avoid extra funds from being stuck in FastBridgeV2.\n token.assertIsContract();\n if (msg.value != 0) revert MsgValueIncorrect();\n amountTaken = IERC20(token).balanceOf(address(this));\n IERC20(token).safeTransferFrom(msg.sender, address(this), amount);\n // Use the balance difference as the amount taken in case of fee on transfer tokens.\n amountTaken = IERC20(token).balanceOf(address(this)) - amountTaken;\n }\n }\n\n /// @notice Calls the Recipient's hook function with the specified callParams and performs\n /// all the necessary checks for the returned value.\n function _checkedCallRecipient(\n address recipient,\n address token,\n uint256 amount,\n bytes memory callParams\n )\n internal\n {\n bytes memory hookData =\n abi.encodeCall(IFastBridgeRecipient.fastBridgeTransferReceived, (token, amount, callParams));\n // This will bubble any revert messages from the hook function\n bytes memory returnData = Address.functionCallWithValue({target: recipient, data: hookData, value: msg.value});\n // Explicit revert if no return data at all\n if (returnData.length == 0) revert RecipientNoReturnValue();\n // Check that exactly a single return value was returned\n if (returnData.length != 32) revert RecipientIncorrectReturnValue();\n // Return value should be abi-encoded hook function selector\n if (bytes32(returnData) != bytes32(IFastBridgeRecipient.fastBridgeTransferReceived.selector)) {\n revert RecipientIncorrectReturnValue();\n }\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint40(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint40).max but\n /// proof.timestamp \u003c type(uint40).max via unchecked statement\n /// @param proofBlockTimestamp The bridge proof block timestamp\n /// @return delta Time delta since proof submitted\n function _timeSince(uint40 proofBlockTimestamp) internal view returns (uint256 delta) {\n unchecked {\n delta = uint40(block.timestamp) - proofBlockTimestamp;\n }\n }\n\n /// @notice Performs all the necessary checks for a bridge to happen.\n /// @dev There's no good way to refactor this function to reduce cyclomatic complexity due to\n /// the number of checks that need to be performed, so we skip the code-complexity rule here.\n // solhint-disable-next-line code-complexity\n function _validateBridgeParams(\n BridgeParams memory params,\n BridgeParamsV2 memory paramsV2,\n int256 exclusivityEndTime\n )\n internal\n view\n {\n // Check V1 (legacy) params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.sender == address(0) || params.to == address(0)) revert ZeroAddress();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n // Check V2 params\n if (paramsV2.callParams.length \u003e MAX_CALL_PARAMS_LENGTH) revert CallParamsLengthAboveMax();\n if (paramsV2.callValue != 0 \u0026\u0026 params.destToken == UniversalTokenLib.ETH_ADDRESS) {\n revert NativeTokenCallValueNotSupported();\n }\n // exclusivityEndTime must be in range (0 .. params.deadline]\n if (exclusivityEndTime \u003c= 0 || exclusivityEndTime \u003e int256(params.deadline)) {\n revert ExclusivityParamsIncorrect();\n }\n }\n\n /// @notice Performs all the necessary checks for a relay to happen.\n function _validateRelayParams(\n BridgeTransactionV2 memory transaction,\n bytes32 transactionId,\n address relayer\n )\n internal\n view\n {\n if (relayer == address(0)) revert ZeroAddress();\n // Check if the transaction has already been relayed\n if (bridgeRelays(transactionId)) revert TransactionRelayed();\n if (transaction.destChainId != block.chainid) revert ChainIncorrect();\n // Check the deadline for relay to happen\n if (block.timestamp \u003e transaction.deadline) revert DeadlineExceeded();\n // Check the exclusivity period, if it is still ongoing\n // forgefmt: disable-next-item\n if (\n transaction.exclusivityRelayer != address(0) \u0026\u0026\n transaction.exclusivityRelayer != relayer \u0026\u0026\n block.timestamp \u003c= transaction.exclusivityEndTime\n ) {\n revert ExclusivityPeriodNotPassed();\n }\n }\n}\n","language":"Solidity","languageVersion":"0.8.24","compilerVersion":"0.8.24","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"","srcMapRuntime":"","abiDefinition":[{"inputs":[],"name":"AccessControlBadConfirmation","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"bytes32","name":"neededRole","type":"bytes32"}],"name":"AccessControlUnauthorizedAccount","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"previousAdminRole","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"newAdminRole","type":"bytes32"}],"name":"RoleAdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleRevoked","type":"event"},{"inputs":[],"name":"DEFAULT_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleAdmin","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"uint256","name":"index","type":"uint256"}],"name":"getRoleMember","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleMemberCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"grantRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"hasRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"callerConfirmation","type":"address"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"revokeRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"}],"userDoc":{"kind":"user","methods":{},"version":1},"developerDoc":{"details":"Extension of {AccessControl} that allows enumerating the members of each role.","errors":{"AccessControlBadConfirmation()":[{"details":"The caller of a function is not the expected one. NOTE: Don't confuse with {AccessControlUnauthorizedAccount}."}],"AccessControlUnauthorizedAccount(address,bytes32)":[{"details":"The `account` is missing a role."}]},"events":{"RoleAdminChanged(bytes32,bytes32,bytes32)":{"details":"Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole` `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite {RoleAdminChanged} not being emitted signaling this."},"RoleGranted(bytes32,address,address)":{"details":"Emitted when `account` is granted `role`. `sender` is the account that originated the contract call, an admin role bearer except when using {AccessControl-_setupRole}."},"RoleRevoked(bytes32,address,address)":{"details":"Emitted when `account` is revoked `role`. `sender` is the account that originated the contract call: - if using `revokeRole`, it is the admin role bearer - if using `renounceRole`, it is the role bearer (i.e. `account`)"}},"kind":"dev","methods":{"getRoleAdmin(bytes32)":{"details":"Returns the admin role that controls `role`. See {grantRole} and {revokeRole}. To change a role's admin, use {_setRoleAdmin}."},"getRoleMember(bytes32,uint256)":{"details":"Returns one of the accounts that have `role`. `index` must be a value between 0 and {getRoleMemberCount}, non-inclusive. Role bearers are not sorted in any particular way, and their ordering may change at any point. WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure you perform all queries on the same block. See the following https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post] for more information."},"getRoleMemberCount(bytes32)":{"details":"Returns the number of accounts that have `role`. Can be used together with {getRoleMember} to enumerate all bearers of a role."},"grantRole(bytes32,address)":{"details":"Grants `role` to `account`. If `account` had not been already granted `role`, emits a {RoleGranted} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleGranted} event."},"hasRole(bytes32,address)":{"details":"Returns `true` if `account` has been granted `role`."},"renounceRole(bytes32,address)":{"details":"Revokes `role` from the calling account. Roles are often managed via {grantRole} and {revokeRole}: this function's purpose is to provide a mechanism for accounts to lose their privileges if they are compromised (such as when a trusted device is misplaced). If the calling account had been revoked `role`, emits a {RoleRevoked} event. Requirements: - the caller must be `callerConfirmation`. May emit a {RoleRevoked} event."},"revokeRole(bytes32,address)":{"details":"Revokes `role` from `account`. If `account` had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleRevoked} event."},"supportsInterface(bytes4)":{"details":"See {IERC165-supportsInterface}."}},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[],\"name\":\"AccessControlBadConfirmation\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"neededRole\",\"type\":\"bytes32\"}],\"name\":\"AccessControlUnauthorizedAccount\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"previousAdminRole\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"newAdminRole\",\"type\":\"bytes32\"}],\"name\":\"RoleAdminChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleGranted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleRevoked\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"DEFAULT_ADMIN_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"}],\"name\":\"getRoleAdmin\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"index\",\"type\":\"uint256\"}],\"name\":\"getRoleMember\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"}],\"name\":\"getRoleMemberCount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"grantRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"hasRole\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"callerConfirmation\",\"type\":\"address\"}],\"name\":\"renounceRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"revokeRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes4\",\"name\":\"interfaceId\",\"type\":\"bytes4\"}],\"name\":\"supportsInterface\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"}],\"devdoc\":{\"details\":\"Extension of {AccessControl} that allows enumerating the members of each role.\",\"errors\":{\"AccessControlBadConfirmation()\":[{\"details\":\"The caller of a function is not the expected one. NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\"}],\"AccessControlUnauthorizedAccount(address,bytes32)\":[{\"details\":\"The `account` is missing a role.\"}]},\"events\":{\"RoleAdminChanged(bytes32,bytes32,bytes32)\":{\"details\":\"Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole` `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite {RoleAdminChanged} not being emitted signaling this.\"},\"RoleGranted(bytes32,address,address)\":{\"details\":\"Emitted when `account` is granted `role`. `sender` is the account that originated the contract call, an admin role bearer except when using {AccessControl-_setupRole}.\"},\"RoleRevoked(bytes32,address,address)\":{\"details\":\"Emitted when `account` is revoked `role`. `sender` is the account that originated the contract call: - if using `revokeRole`, it is the admin role bearer - if using `renounceRole`, it is the role bearer (i.e. `account`)\"}},\"kind\":\"dev\",\"methods\":{\"getRoleAdmin(bytes32)\":{\"details\":\"Returns the admin role that controls `role`. See {grantRole} and {revokeRole}. To change a role's admin, use {_setRoleAdmin}.\"},\"getRoleMember(bytes32,uint256)\":{\"details\":\"Returns one of the accounts that have `role`. `index` must be a value between 0 and {getRoleMemberCount}, non-inclusive. Role bearers are not sorted in any particular way, and their ordering may change at any point. WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure you perform all queries on the same block. See the following https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post] for more information.\"},\"getRoleMemberCount(bytes32)\":{\"details\":\"Returns the number of accounts that have `role`. Can be used together with {getRoleMember} to enumerate all bearers of a role.\"},\"grantRole(bytes32,address)\":{\"details\":\"Grants `role` to `account`. If `account` had not been already granted `role`, emits a {RoleGranted} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleGranted} event.\"},\"hasRole(bytes32,address)\":{\"details\":\"Returns `true` if `account` has been granted `role`.\"},\"renounceRole(bytes32,address)\":{\"details\":\"Revokes `role` from the calling account. Roles are often managed via {grantRole} and {revokeRole}: this function's purpose is to provide a mechanism for accounts to lose their privileges if they are compromised (such as when a trusted device is misplaced). If the calling account had been revoked `role`, emits a {RoleRevoked} event. Requirements: - the caller must be `callerConfirmation`. May emit a {RoleRevoked} event.\"},\"revokeRole(bytes32,address)\":{\"details\":\"Revokes `role` from `account`. If `account` had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleRevoked} event.\"},\"supportsInterface(bytes4)\":{\"details\":\"See {IERC165-supportsInterface}.\"}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeV2.sol\":\"AccessControlEnumerable\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeV2.sol\":{\"keccak256\":\"0xfd916c030b1ffca5a136817827b8018c8ba42ca089905747f3de6148b73eb35e\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://18e6438c4096deb8ae453fb3365ba2b07d52944e93c08288fc5d012b71bf6bb3\",\"dweb:/ipfs/QmfEMqpT1zz6RRm7UuHLRowe1tds2cTGLrVonfm9XSCACj\"]}},\"version\":1}"},"hashes":{"DEFAULT_ADMIN_ROLE()":"a217fddf","getRoleAdmin(bytes32)":"248a9ca3","getRoleMember(bytes32,uint256)":"9010d07c","getRoleMemberCount(bytes32)":"ca15c873","grantRole(bytes32,address)":"2f2ff15d","hasRole(bytes32,address)":"91d14854","renounceRole(bytes32,address)":"36568abe","revokeRole(bytes32,address)":"d547741f","supportsInterface(bytes4)":"01ffc9a7"}},"solidity/FastBridgeV2.sol:Address":{"code":"0x60566037600b82828239805160001a607314602a57634e487b7160e01b600052600060045260246000fd5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600080fdfea2646970667358221220ac16750f49f1b9ced08b049feacc7b593708109660ad4859d5e0cc87a7718b8d64736f6c63430008180033","runtime-code":"0x73000000000000000000000000000000000000000030146080604052600080fdfea2646970667358221220ac16750f49f1b9ced08b049feacc7b593708109660ad4859d5e0cc87a7718b8d64736f6c63430008180033","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.24 ^0.8.0 ^0.8.20;\n\n// contracts/interfaces/IAdmin.sol\n\ninterface IAdmin {\n // ============ Events ============\n\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n event ChainGasAmountUpdated(uint256 oldChainGasAmount, uint256 newChainGasAmount);\n\n // ============ Methods ============\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n\n function setChainGasAmount(uint256 newChainGasAmount) external;\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IFastBridgeRecipient.sol\n\ninterface IFastBridgeRecipient {\n function fastBridgeTransferReceived(\n address token,\n uint256 amount,\n bytes memory callParams\n )\n external\n payable\n returns (bytes4);\n}\n\n// contracts/interfaces/IFastBridgeV2Errors.sol\n\ninterface IFastBridgeV2Errors {\n error AmountIncorrect();\n error CallParamsLengthAboveMax();\n error ChainIncorrect();\n error ExclusivityParamsIncorrect();\n error MsgValueIncorrect();\n error NativeTokenCallValueNotSupported();\n error SenderIncorrect();\n error StatusIncorrect();\n error ZeroAddress();\n\n error RecipientIncorrectReturnValue();\n error RecipientNoReturnValue();\n\n error DeadlineExceeded();\n error DeadlineNotExceeded();\n error DeadlineTooShort();\n error DisputePeriodNotPassed();\n error DisputePeriodPassed();\n error ExclusivityPeriodNotPassed();\n\n error TransactionRelayed();\n}\n\n// contracts/libs/Errors.sol\n\nerror DeadlineExceeded();\nerror DeadlineNotExceeded();\nerror DeadlineTooShort();\nerror InsufficientOutputAmount();\n\nerror MsgValueIncorrect();\nerror PoolNotFound();\nerror TokenAddressMismatch();\nerror TokenNotContract();\nerror TokenNotETH();\nerror TokensIdentical();\n\nerror ChainIncorrect();\nerror AmountIncorrect();\nerror ZeroAddress();\n\nerror DisputePeriodNotPassed();\nerror DisputePeriodPassed();\nerror SenderIncorrect();\nerror StatusIncorrect();\nerror TransactionIdIncorrect();\nerror TransactionRelayed();\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// contracts/interfaces/IFastBridgeV2.sol\n\ninterface IFastBridgeV2 is IFastBridge {\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n struct BridgeTxDetails {\n BridgeStatus status;\n uint40 proofBlockTimestamp;\n uint48 proofBlockNumber;\n address proofRelayer;\n }\n\n struct BridgeRelay {\n uint48 blockNumber;\n uint48 blockTimestamp;\n address relayer;\n }\n\n /// @notice New params introduced in the FastBridgeV2.\n /// We are passing fields from the older BridgeParams struct outside of this struct\n /// for backwards compatibility.\n /// Note: quoteRelayer and quoteExclusivitySeconds are either both zero (indicating no exclusivity)\n /// or both non-zero (indicating exclusivity for the given period).\n /// Note: callValue \u003e 0 can NOT be used with destToken = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE (ETH_ADDRESS)\n /// @param quoteRelayer Relayer that provided the quote for the transaction\n /// @param quoteExclusivitySeconds Period of time the quote relayer is guaranteed exclusivity after user's deposit\n /// @param quoteId Unique quote identifier used for tracking the quote\n /// @param callValue ETH value to send to the recipient (if any)\n /// @param callParams Parameters for the arbitrary call to the destination recipient (if any)\n struct BridgeParamsV2 {\n address quoteRelayer;\n int256 quoteExclusivitySeconds;\n bytes quoteId;\n uint256 callValue;\n bytes callParams;\n }\n\n /// @notice Updated bridge transaction struct to include parameters introduced in FastBridgeV2.\n /// Note: only `exclusivityRelayer` can fill such a transaction until `exclusivityEndTime`.\n /// TODO: consider changing the encoding scheme to prevent spending extra gas on decoding.\n struct BridgeTransactionV2 {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n uint256 callValue; // ETH value to send to the recipient (if any) - replaces V1's sendChainGas flag\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n address exclusivityRelayer;\n uint256 exclusivityEndTime;\n bytes callParams;\n }\n\n event BridgeQuoteDetails(bytes32 indexed transactionId, bytes quoteId);\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability\n /// to provide temporary exclusivity fill rights for the quote relayer.\n /// @param params The parameters required to bridge\n /// @param paramsV2 The parameters for exclusivity fill rights (optional, can be left empty)\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function relay(bytes memory request, address relayer) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param transactionId The transaction id associated with the encoded bridge transaction to prove\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital.\n /// @notice Can only send funds to the relayer address on the proof.\n /// @param request The encoded bridge transaction to claim on origin chain\n function claim(bytes memory request) external;\n /// @notice Checks if a transaction has been relayed\n /// @param transactionId The ID of the transaction to check\n /// @return True if the transaction has been relayed, false otherwise\n function bridgeRelays(bytes32 transactionId) external view returns (bool);\n\n /// @notice Returns the status of a bridge transaction\n /// @param transactionId The ID of the bridge transaction\n /// @return BridgeStatus Status of the bridge transaction\n function bridgeStatuses(bytes32 transactionId) external view returns (BridgeStatus);\n\n /// @notice Returns the timestamp and relayer of a bridge proof\n /// @param transactionId The ID of the bridge transaction\n /// @return timestamp The timestamp of the bridge proof\n /// @return relayer The relayer address of the bridge proof\n function bridgeProofs(bytes32 transactionId) external view returns (uint96 timestamp, address relayer);\n\n /// @notice Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\n /// @param request The bridge request to decode\n function getBridgeTransactionV2(bytes memory request) external view returns (BridgeTransactionV2 memory);\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// contracts/libs/UniversalToken.sol\n\nlibrary UniversalTokenLib {\n using SafeERC20 for IERC20;\n\n address internal constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Transfers tokens to the given account. Reverts if transfer is not successful.\n /// @dev This might trigger fallback, if ETH is transferred to the contract.\n /// Make sure this can not lead to reentrancy attacks.\n function universalTransfer(address token, address to, uint256 value) internal {\n // Don't do anything, if need to send tokens to this address\n if (to == address(this)) return;\n // Don't do anything, if trying to send zero value\n if (value == 0) return;\n if (token == ETH_ADDRESS) {\n /// @dev Note: this can potentially lead to executing code in `to`.\n // solhint-disable-next-line avoid-low-level-calls\n (bool success,) = to.call{value: value}(\"\");\n require(success, \"ETH transfer failed\");\n } else {\n IERC20(token).safeTransfer(to, value);\n }\n }\n\n /// @notice Issues an infinite allowance to the spender, if the current allowance is insufficient\n /// to spend the given amount.\n function universalApproveInfinity(address token, address spender, uint256 amountToSpend) internal {\n // ETH Chad doesn't require your approval\n if (token == ETH_ADDRESS) return;\n // No-op if allowance is already sufficient\n uint256 allowance = IERC20(token).allowance(address(this), spender);\n if (allowance \u003e= amountToSpend) return;\n // Otherwise, reset approval to 0 and set to max allowance\n if (allowance \u003e 0) IERC20(token).safeDecreaseAllowance(spender, allowance);\n IERC20(token).safeIncreaseAllowance(spender, type(uint256).max);\n }\n\n /// @notice Returns the balance of the given token (or native ETH) for the given account.\n function universalBalanceOf(address token, address account) internal view returns (uint256) {\n if (token == ETH_ADDRESS) {\n return account.balance;\n } else {\n return IERC20(token).balanceOf(account);\n }\n }\n\n /// @dev Checks that token is a contract and not ETH_ADDRESS.\n function assertIsContract(address token) internal view {\n // Check that ETH_ADDRESS was not used (in case this is a predeploy on any of the chains)\n if (token == UniversalTokenLib.ETH_ADDRESS) revert TokenNotContract();\n // Check that token is not an EOA\n if (token.code.length == 0) revert TokenNotContract();\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/Admin.sol\n\ncontract Admin is IAdmin, AccessControlEnumerable {\n using UniversalTokenLib for address;\n\n bytes32 public constant RELAYER_ROLE = keccak256(\"RELAYER_ROLE\");\n bytes32 public constant REFUNDER_ROLE = keccak256(\"REFUNDER_ROLE\");\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n uint256 public constant FEE_BPS = 1e6;\n uint256 public constant FEE_RATE_MAX = 0.01e6; // max 1% on origin amount\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Chain gas amount to forward as rebate if requested\n uint256 public chainGasAmount;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n }\n\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n require(newFeeRate \u003c= FEE_RATE_MAX, \"newFeeRate \u003e max\");\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n token.universalTransfer(recipient, feeAmount);\n emit FeesSwept(token, recipient, feeAmount);\n }\n\n function setChainGasAmount(uint256 newChainGasAmount) external onlyRole(GOVERNOR_ROLE) {\n uint256 oldChainGasAmount = chainGasAmount;\n chainGasAmount = newChainGasAmount;\n emit ChainGasAmountUpdated(oldChainGasAmount, newChainGasAmount);\n }\n}\n\n// contracts/FastBridgeV2.sol\n\n/// @notice FastBridgeV2 is a contract for bridging tokens across chains.\ncontract FastBridgeV2 is Admin, IFastBridgeV2, IFastBridgeV2Errors {\n using SafeERC20 for IERC20;\n using UniversalTokenLib for address;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Delay for a transaction after which it could be permisionlessly refunded\n uint256 public constant REFUND_DELAY = 7 days;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n /// @notice Maximum length of accepted callParams\n uint256 public constant MAX_CALL_PARAMS_LENGTH = 2 ** 16 - 1;\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeTxDetails) public bridgeTxDetails;\n /// @notice Relay details on destination chain\n mapping(bytes32 =\u003e BridgeRelay) public bridgeRelayDetails;\n /// @notice Unique bridge nonces tracked per originSender\n mapping(address =\u003e uint256) public senderNonces;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Replaced by senderNonces\n uint256 public immutable nonce = 0;\n /// @notice the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n bridge({\n params: params,\n paramsV2: BridgeParamsV2({\n quoteRelayer: address(0),\n quoteExclusivitySeconds: 0,\n quoteId: bytes(\"\"),\n callValue: 0,\n callParams: bytes(\"\")\n })\n });\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes memory request) external payable {\n relay({request: request, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes memory request, bytes32 destTxHash) external {\n prove({transactionId: keccak256(request), destTxHash: destTxHash, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridgeV2\n function claim(bytes memory request) external {\n claim({request: request, to: address(0)});\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003e DISPUTE_PERIOD) {\n revert DisputePeriodPassed();\n }\n\n // @dev relayer gets slashed effectively if dest relay has gone thru\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n bridgeTxDetails[transactionId].proofRelayer = address(0);\n bridgeTxDetails[transactionId].proofBlockTimestamp = 0;\n bridgeTxDetails[transactionId].proofBlockNumber = 0;\n\n emit BridgeProofDisputed(transactionId, msg.sender);\n }\n\n /// @inheritdoc IFastBridge\n function refund(bytes memory request) external {\n bytes32 transactionId = keccak256(request);\n\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n\n if (bridgeTxDetails[transactionId].status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n\n if (hasRole(REFUNDER_ROLE, msg.sender)) {\n // Refunder can refund if deadline has passed\n if (block.timestamp \u003c= transaction.deadline) revert DeadlineNotExceeded();\n } else {\n // Permissionless refund is allowed after REFUND_DELAY\n if (block.timestamp \u003c= transaction.deadline + REFUND_DELAY) revert DeadlineNotExceeded();\n }\n\n // if all checks passed, set to REFUNDED status\n bridgeTxDetails[transactionId].status = BridgeStatus.REFUNDED;\n\n // transfer origin collateral back to original sender\n address to = transaction.originSender;\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount + transaction.originFeeAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (bridgeTxDetails[transactionId].proofRelayer != relayer) revert SenderIncorrect();\n return _timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n /// @dev This method is added to achieve backwards compatibility with decoding requests into V1 structs:\n /// - `callValue` is partially reported as a zero/non-zero flag\n /// - `callParams` is ignored\n /// In order to process all kinds of requests use getBridgeTransactionV2 instead.\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory) {\n // Try decoding into V2 struct first. This will revert if V1 struct is passed\n try this.getBridgeTransactionV2(request) returns (BridgeTransactionV2 memory txV2) {\n // Note: we entirely ignore the callParams field, as it was not present in V1\n return BridgeTransaction({\n originChainId: txV2.originChainId,\n destChainId: txV2.destChainId,\n originSender: txV2.originSender,\n destRecipient: txV2.destRecipient,\n originToken: txV2.originToken,\n destToken: txV2.destToken,\n originAmount: txV2.originAmount,\n destAmount: txV2.destAmount,\n originFeeAmount: txV2.originFeeAmount,\n sendChainGas: txV2.callValue != 0,\n deadline: txV2.deadline,\n nonce: txV2.nonce\n });\n } catch {\n // Fallback to V1 struct\n return abi.decode(request, (BridgeTransaction));\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) public payable {\n int256 exclusivityEndTime = int256(block.timestamp) + paramsV2.quoteExclusivitySeconds;\n _validateBridgeParams(params, paramsV2, exclusivityEndTime);\n\n // transfer tokens to bridge contract\n /// @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _takeBridgedUserAsset(params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n\n // set status to requested\n bytes memory request = abi.encode(\n BridgeTransactionV2({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n callValue: paramsV2.callValue,\n deadline: params.deadline,\n nonce: senderNonces[params.sender]++, // increment nonce on every bridge\n exclusivityRelayer: paramsV2.quoteRelayer,\n // We checked exclusivityEndTime to be in range (0 .. params.deadline] above, so can safely cast\n exclusivityEndTime: uint256(exclusivityEndTime),\n callParams: paramsV2.callParams\n })\n );\n bytes32 transactionId = keccak256(request);\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n\n emit BridgeRequested({\n transactionId: transactionId,\n sender: params.sender,\n request: request,\n destChainId: params.dstChainId,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n sendChainGas: paramsV2.callValue != 0\n });\n emit BridgeQuoteDetails(transactionId, paramsV2.quoteId);\n }\n\n /// @inheritdoc IFastBridgeV2\n function relay(bytes memory request, address relayer) public payable {\n bytes32 transactionId = keccak256(request);\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n _validateRelayParams(transaction, transactionId, relayer);\n // mark bridge transaction as relayed\n bridgeRelayDetails[transactionId] =\n BridgeRelay({blockNumber: uint48(block.number), blockTimestamp: uint48(block.timestamp), relayer: relayer});\n\n // transfer tokens to recipient on destination chain and do an arbitrary call if requested\n address to = transaction.destRecipient;\n address token = transaction.destToken;\n uint256 amount = transaction.destAmount;\n uint256 callValue = transaction.callValue;\n\n // Emit the event before any external calls\n emit BridgeRelayed({\n transactionId: transactionId,\n relayer: relayer,\n to: to,\n originChainId: transaction.originChainId,\n originToken: transaction.originToken,\n destToken: token,\n originAmount: transaction.originAmount,\n destAmount: amount,\n chainGasAmount: callValue\n });\n\n // All state changes have been done at this point, can proceed to the external calls.\n // This follows the checks-effects-interactions pattern to mitigate potential reentrancy attacks.\n if (token == UniversalTokenLib.ETH_ADDRESS) {\n // For ETH non-zero callValue is not allowed\n if (callValue != 0) revert NativeTokenCallValueNotSupported();\n // Check that the correct msg.value was sent\n if (msg.value != amount) revert MsgValueIncorrect();\n } else {\n // For ERC20s, we check that the correct msg.value was sent\n if (msg.value != callValue) revert MsgValueIncorrect();\n // We need to transfer the tokens from the Relayer to the recipient first before performing an\n // optional post-transfer arbitrary call.\n IERC20(token).safeTransferFrom(msg.sender, to, amount);\n }\n\n if (transaction.callParams.length != 0) {\n // Arbitrary call requested, perform it while supplying full msg.value to the recipient\n // Note: if token has a fee on transfers, the recipient will have received less than `amount`.\n // This is a very niche edge case and should be handled by the recipient contract.\n _checkedCallRecipient({recipient: to, token: token, amount: amount, callParams: transaction.callParams});\n } else if (msg.value != 0) {\n // No arbitrary call requested, but msg.value was sent. This is either a relay with ETH,\n // or a non-zero callValue request with an ERC20. In both cases, transfer the ETH to the recipient.\n Address.sendValue(payable(to), msg.value);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) public onlyRole(RELAYER_ROLE) {\n // update bridge tx status given proof provided\n if (bridgeTxDetails[transactionId].status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n bridgeTxDetails[transactionId].status = BridgeStatus.RELAYER_PROVED;\n bridgeTxDetails[transactionId].proofBlockTimestamp = uint40(block.timestamp);\n bridgeTxDetails[transactionId].proofBlockNumber = uint48(block.number);\n bridgeTxDetails[transactionId].proofRelayer = relayer;\n\n emit BridgeProofProvided(transactionId, relayer, destTxHash);\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes memory request, address to) public {\n bytes32 transactionId = keccak256(request);\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n\n // update bridge tx status if able to claim origin collateral\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n\n // if \"to\" is zero addr, permissionlessly send funds to proven relayer\n if (to == address(0)) {\n to = bridgeTxDetails[transactionId].proofRelayer;\n } else if (bridgeTxDetails[transactionId].proofRelayer != msg.sender) {\n revert SenderIncorrect();\n }\n\n if (_timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003c= DISPUTE_PERIOD) {\n revert DisputePeriodNotPassed();\n }\n\n bridgeTxDetails[transactionId].status = BridgeStatus.RELAYER_CLAIMED;\n\n // update protocol fees if origin fee amount exists\n if (transaction.originFeeAmount \u003e 0) protocolFees[transaction.originToken] += transaction.originFeeAmount;\n\n // transfer origin collateral less fee to specified address\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositClaimed(transactionId, bridgeTxDetails[transactionId].proofRelayer, to, token, amount);\n }\n\n function bridgeStatuses(bytes32 transactionId) public view returns (BridgeStatus status) {\n return bridgeTxDetails[transactionId].status;\n }\n\n function bridgeProofs(bytes32 transactionId) public view returns (uint96 timestamp, address relayer) {\n timestamp = bridgeTxDetails[transactionId].proofBlockTimestamp;\n relayer = bridgeTxDetails[transactionId].proofRelayer;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeRelays(bytes32 transactionId) public view returns (bool) {\n // has this transactionId been relayed?\n return bridgeRelayDetails[transactionId].relayer != address(0);\n }\n\n /// @inheritdoc IFastBridgeV2\n function getBridgeTransactionV2(bytes memory request) public pure returns (BridgeTransactionV2 memory) {\n return abi.decode(request, (BridgeTransactionV2));\n }\n\n /// @notice Takes the bridged asset from the user into FastBridgeV2 custody. It will be later\n /// claimed by the relayer who completed the relay on destination chain, or refunded back to the user,\n /// should no one complete the relay.\n function _takeBridgedUserAsset(address token, uint256 amount) internal returns (uint256 amountTaken) {\n if (token == UniversalTokenLib.ETH_ADDRESS) {\n // For ETH we just need to check that the supplied msg.value is correct.\n // Supplied `msg.value` is already in FastBridgeV2 custody.\n if (amount != msg.value) revert MsgValueIncorrect();\n amountTaken = msg.value;\n } else {\n // For ERC20s, token is explicitly transferred from the user to FastBridgeV2.\n // We don't allow non-zero `msg.value` to avoid extra funds from being stuck in FastBridgeV2.\n token.assertIsContract();\n if (msg.value != 0) revert MsgValueIncorrect();\n amountTaken = IERC20(token).balanceOf(address(this));\n IERC20(token).safeTransferFrom(msg.sender, address(this), amount);\n // Use the balance difference as the amount taken in case of fee on transfer tokens.\n amountTaken = IERC20(token).balanceOf(address(this)) - amountTaken;\n }\n }\n\n /// @notice Calls the Recipient's hook function with the specified callParams and performs\n /// all the necessary checks for the returned value.\n function _checkedCallRecipient(\n address recipient,\n address token,\n uint256 amount,\n bytes memory callParams\n )\n internal\n {\n bytes memory hookData =\n abi.encodeCall(IFastBridgeRecipient.fastBridgeTransferReceived, (token, amount, callParams));\n // This will bubble any revert messages from the hook function\n bytes memory returnData = Address.functionCallWithValue({target: recipient, data: hookData, value: msg.value});\n // Explicit revert if no return data at all\n if (returnData.length == 0) revert RecipientNoReturnValue();\n // Check that exactly a single return value was returned\n if (returnData.length != 32) revert RecipientIncorrectReturnValue();\n // Return value should be abi-encoded hook function selector\n if (bytes32(returnData) != bytes32(IFastBridgeRecipient.fastBridgeTransferReceived.selector)) {\n revert RecipientIncorrectReturnValue();\n }\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint40(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint40).max but\n /// proof.timestamp \u003c type(uint40).max via unchecked statement\n /// @param proofBlockTimestamp The bridge proof block timestamp\n /// @return delta Time delta since proof submitted\n function _timeSince(uint40 proofBlockTimestamp) internal view returns (uint256 delta) {\n unchecked {\n delta = uint40(block.timestamp) - proofBlockTimestamp;\n }\n }\n\n /// @notice Performs all the necessary checks for a bridge to happen.\n /// @dev There's no good way to refactor this function to reduce cyclomatic complexity due to\n /// the number of checks that need to be performed, so we skip the code-complexity rule here.\n // solhint-disable-next-line code-complexity\n function _validateBridgeParams(\n BridgeParams memory params,\n BridgeParamsV2 memory paramsV2,\n int256 exclusivityEndTime\n )\n internal\n view\n {\n // Check V1 (legacy) params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.sender == address(0) || params.to == address(0)) revert ZeroAddress();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n // Check V2 params\n if (paramsV2.callParams.length \u003e MAX_CALL_PARAMS_LENGTH) revert CallParamsLengthAboveMax();\n if (paramsV2.callValue != 0 \u0026\u0026 params.destToken == UniversalTokenLib.ETH_ADDRESS) {\n revert NativeTokenCallValueNotSupported();\n }\n // exclusivityEndTime must be in range (0 .. params.deadline]\n if (exclusivityEndTime \u003c= 0 || exclusivityEndTime \u003e int256(params.deadline)) {\n revert ExclusivityParamsIncorrect();\n }\n }\n\n /// @notice Performs all the necessary checks for a relay to happen.\n function _validateRelayParams(\n BridgeTransactionV2 memory transaction,\n bytes32 transactionId,\n address relayer\n )\n internal\n view\n {\n if (relayer == address(0)) revert ZeroAddress();\n // Check if the transaction has already been relayed\n if (bridgeRelays(transactionId)) revert TransactionRelayed();\n if (transaction.destChainId != block.chainid) revert ChainIncorrect();\n // Check the deadline for relay to happen\n if (block.timestamp \u003e transaction.deadline) revert DeadlineExceeded();\n // Check the exclusivity period, if it is still ongoing\n // forgefmt: disable-next-item\n if (\n transaction.exclusivityRelayer != address(0) \u0026\u0026\n transaction.exclusivityRelayer != relayer \u0026\u0026\n block.timestamp \u003c= transaction.exclusivityEndTime\n ) {\n revert ExclusivityPeriodNotPassed();\n }\n }\n}\n","language":"Solidity","languageVersion":"0.8.24","compilerVersion":"0.8.24","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"16564:6066:0:-:0;;;;;;;;;;;;;;;-1:-1:-1;;;16564:6066:0;;;;;;;;;;;;;;;;;","srcMapRuntime":"16564:6066:0:-:0;;;;;;;;","abiDefinition":[{"inputs":[{"internalType":"address","name":"target","type":"address"}],"name":"AddressEmptyCode","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"AddressInsufficientBalance","type":"error"},{"inputs":[],"name":"FailedInnerCall","type":"error"}],"userDoc":{"kind":"user","methods":{},"version":1},"developerDoc":{"details":"Collection of functions related to the address type","errors":{"AddressEmptyCode(address)":[{"details":"There's no code at `target` (it is not a contract)."}],"AddressInsufficientBalance(address)":[{"details":"The ETH balance of the account is not enough to perform the operation."}],"FailedInnerCall()":[{"details":"A call to an address target failed. The target may have reverted."}]},"kind":"dev","methods":{},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"}],\"name\":\"AddressEmptyCode\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"AddressInsufficientBalance\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"FailedInnerCall\",\"type\":\"error\"}],\"devdoc\":{\"details\":\"Collection of functions related to the address type\",\"errors\":{\"AddressEmptyCode(address)\":[{\"details\":\"There's no code at `target` (it is not a contract).\"}],\"AddressInsufficientBalance(address)\":[{\"details\":\"The ETH balance of the account is not enough to perform the operation.\"}],\"FailedInnerCall()\":[{\"details\":\"A call to an address target failed. The target may have reverted.\"}]},\"kind\":\"dev\",\"methods\":{},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeV2.sol\":\"Address\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeV2.sol\":{\"keccak256\":\"0xfd916c030b1ffca5a136817827b8018c8ba42ca089905747f3de6148b73eb35e\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://18e6438c4096deb8ae453fb3365ba2b07d52944e93c08288fc5d012b71bf6bb3\",\"dweb:/ipfs/QmfEMqpT1zz6RRm7UuHLRowe1tds2cTGLrVonfm9XSCACj\"]}},\"version\":1}"},"hashes":{}},"solidity/FastBridgeV2.sol:Admin":{"code":"0x60806040523480156200001157600080fd5b50604051620014123803806200141283398101604081905262000034916200018e565b6200004160008262000049565b5050620001b9565b60008062000058848462000086565b905080156200007d5760008481526001602052604090206200007b908462000134565b505b90505b92915050565b6000828152602081815260408083206001600160a01b038516845290915281205460ff166200012b576000838152602081815260408083206001600160a01b03861684529091529020805460ff19166001179055620000e23390565b6001600160a01b0316826001600160a01b0316847f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a450600162000080565b50600062000080565b60006200007d836001600160a01b03841660008181526001830160205260408120546200012b5750815460018181018455600084815260208082209093018490558454848252828601909352604090209190915562000080565b600060208284031215620001a157600080fd5b81516001600160a01b03811681146200007d57600080fd5b61124980620001c96000396000f3fe608060405234801561001057600080fd5b50600436106101775760003560e01c806391d14854116100d8578063bf333f2c1161008c578063d547741f11610066578063d547741f14610385578063dcf844a714610398578063e00a83e0146103b857600080fd5b8063bf333f2c14610341578063ca15c8731461034b578063ccc574901461035e57600080fd5b8063a217fddf116100bd578063a217fddf14610313578063b13aa2d61461031b578063b250fe6b1461032e57600080fd5b806391d14854146102a8578063926d7d7f146102ec57600080fd5b80632f2ff15d1161012f57806358f858801161011457806358f85880146102405780635960ccf2146102495780639010d07c1461027057600080fd5b80632f2ff15d1461021a57806336568abe1461022d57600080fd5b806306f333f21161016057806306f333f2146101d95780630f5f6ed7146101ee578063248a9ca3146101f757600080fd5b806301ffc9a71461017c57806303ed0ee5146101a4575b600080fd5b61018f61018a366004611013565b6103c1565b60405190151581526020015b60405180910390f35b6101cb7f043c983c49d46f0e102151eaf8085d4a2e6571d5df2d47b013f39bddfd4a639d81565b60405190815260200161019b565b6101ec6101e736600461107e565b61041d565b005b6101cb61271081565b6101cb6102053660046110b1565b60009081526020819052604090206001015490565b6101ec6102283660046110ca565b61050b565b6101ec61023b3660046110ca565b610536565b6101cb60025481565b6101cb7fdb9556138406326f00296e13ea2ad7db24ba82381212d816b1a40c23b466b32781565b61028361027e3660046110ed565b61058f565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200161019b565b61018f6102b63660046110ca565b60009182526020828152604080842073ffffffffffffffffffffffffffffffffffffffff93909316845291905290205460ff1690565b6101cb7fe2b7fb3b832174769106daebcfd6d1970523240dda11281102db9363b83b0dc481565b6101cb600081565b6101ec6103293660046110b1565b6105ae565b6101ec61033c3660046110b1565b610690565b6101cb620f424081565b6101cb6103593660046110b1565b6106f8565b6101cb7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f5581565b6101ec6103933660046110ca565b61070f565b6101cb6103a636600461110f565b60036020526000908152604090205481565b6101cb60045481565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f5a05180f000000000000000000000000000000000000000000000000000000001480610417575061041782610734565b92915050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f55610447816107cb565b73ffffffffffffffffffffffffffffffffffffffff83166000908152600360205260408120549081900361047b5750505050565b73ffffffffffffffffffffffffffffffffffffffff84166000818152600360205260408120556104ac9084836107d8565b6040805173ffffffffffffffffffffffffffffffffffffffff8087168252851660208201529081018290527f244e51bc38c1452fa8aaf487bcb4bca36c2baa3a5fbdb776b1eabd8dc6d277cd9060600160405180910390a1505b505050565b600082815260208190526040902060010154610526816107cb565b610530838361092f565b50505050565b73ffffffffffffffffffffffffffffffffffffffff81163314610585576040517f6697b23200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6105068282610964565b60008281526001602052604081206105a79083610991565b9392505050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f556105d8816107cb565b612710821115610649576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f6e657746656552617465203e206d61780000000000000000000000000000000060448201526064015b60405180910390fd5b600280549083905560408051828152602081018590527f14914da2bf76024616fbe1859783fcd4dbddcb179b1f3a854949fbf920dcb95791015b60405180910390a1505050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f556106ba816107cb565b600480549083905560408051828152602081018590527f5cf09b12f3f56b4c564d51b25b40360af6d795198adb61ae0806a36c294323fa9101610683565b60008181526001602052604081206104179061099d565b60008281526020819052604090206001015461072a816107cb565b6105308383610964565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f7965db0b00000000000000000000000000000000000000000000000000000000148061041757507f01ffc9a7000000000000000000000000000000000000000000000000000000007fffffffff00000000000000000000000000000000000000000000000000000000831614610417565b6107d581336109a7565b50565b3073ffffffffffffffffffffffffffffffffffffffff8316036107fa57505050565b8060000361080757505050565b7fffffffffffffffffffffffff111111111111111111111111111111111111111273ffffffffffffffffffffffffffffffffffffffff84160161090e5760008273ffffffffffffffffffffffffffffffffffffffff168260405160006040518083038185875af1925050503d806000811461089e576040519150601f19603f3d011682016040523d82523d6000602084013e6108a3565b606091505b5050905080610530576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f455448207472616e73666572206661696c6564000000000000000000000000006044820152606401610640565b61050673ffffffffffffffffffffffffffffffffffffffff84168383610a31565b60008061093c8484610abe565b905080156105a757600084815260016020526040902061095c9084610bba565b509392505050565b6000806109718484610bdc565b905080156105a757600084815260016020526040902061095c9084610c97565b60006105a78383610cb9565b6000610417825490565b60008281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915290205460ff16610a2d576040517fe2517d3f00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8216600482015260248101839052604401610640565b5050565b6040805173ffffffffffffffffffffffffffffffffffffffff8416602482015260448082018490528251808303909101815260649091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fa9059cbb00000000000000000000000000000000000000000000000000000000179052610506908490610ce3565b60008281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915281205460ff16610bb25760008381526020818152604080832073ffffffffffffffffffffffffffffffffffffffff86168452909152902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055610b503390565b73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16847f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a4506001610417565b506000610417565b60006105a78373ffffffffffffffffffffffffffffffffffffffff8416610d79565b60008281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915281205460ff1615610bb25760008381526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8616808552925280832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016905551339286917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a4506001610417565b60006105a78373ffffffffffffffffffffffffffffffffffffffff8416610dc0565b6000826000018281548110610cd057610cd061112a565b9060005260206000200154905092915050565b6000610d0573ffffffffffffffffffffffffffffffffffffffff841683610eb3565b90508051600014158015610d2a575080806020019051810190610d289190611159565b155b15610506576040517f5274afe700000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff84166004820152602401610640565b6000818152600183016020526040812054610bb257508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155610417565b60008181526001830160205260408120548015610ea9576000610de460018361117b565b8554909150600090610df89060019061117b565b9050808214610e5d576000866000018281548110610e1857610e1861112a565b9060005260206000200154905080876000018481548110610e3b57610e3b61112a565b6000918252602080832090910192909255918252600188019052604090208390555b8554869080610e6e57610e6e6111b5565b600190038181906000526020600020016000905590558560010160008681526020019081526020016000206000905560019350505050610417565b6000915050610417565b60606105a783836000846000808573ffffffffffffffffffffffffffffffffffffffff168486604051610ee691906111e4565b60006040518083038185875af1925050503d8060008114610f23576040519150601f19603f3d011682016040523d82523d6000602084013e610f28565b606091505b5091509150610f38868383610f42565b9695505050505050565b606082610f5757610f5282610fd1565b6105a7565b8151158015610f7b575073ffffffffffffffffffffffffffffffffffffffff84163b155b15610fca576040517f9996b31500000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff85166004820152602401610640565b50806105a7565b805115610fe15780518082602001fd5b6040517f1425ea4200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006020828403121561102557600080fd5b81357fffffffff00000000000000000000000000000000000000000000000000000000811681146105a757600080fd5b803573ffffffffffffffffffffffffffffffffffffffff8116811461107957600080fd5b919050565b6000806040838503121561109157600080fd5b61109a83611055565b91506110a860208401611055565b90509250929050565b6000602082840312156110c357600080fd5b5035919050565b600080604083850312156110dd57600080fd5b823591506110a860208401611055565b6000806040838503121561110057600080fd5b50508035926020909101359150565b60006020828403121561112157600080fd5b6105a782611055565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60006020828403121561116b57600080fd5b815180151581146105a757600080fd5b81810381811115610417577f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fd5b6000825160005b8181101561120557602081860181015185830152016111eb565b50600092019182525091905056fea2646970667358221220b13443229221519c0fdb3ac2db22c34ccdfff8fd9f142c9a058dcefb00a5a9d864736f6c63430008180033","runtime-code":"0x608060405234801561001057600080fd5b50600436106101775760003560e01c806391d14854116100d8578063bf333f2c1161008c578063d547741f11610066578063d547741f14610385578063dcf844a714610398578063e00a83e0146103b857600080fd5b8063bf333f2c14610341578063ca15c8731461034b578063ccc574901461035e57600080fd5b8063a217fddf116100bd578063a217fddf14610313578063b13aa2d61461031b578063b250fe6b1461032e57600080fd5b806391d14854146102a8578063926d7d7f146102ec57600080fd5b80632f2ff15d1161012f57806358f858801161011457806358f85880146102405780635960ccf2146102495780639010d07c1461027057600080fd5b80632f2ff15d1461021a57806336568abe1461022d57600080fd5b806306f333f21161016057806306f333f2146101d95780630f5f6ed7146101ee578063248a9ca3146101f757600080fd5b806301ffc9a71461017c57806303ed0ee5146101a4575b600080fd5b61018f61018a366004611013565b6103c1565b60405190151581526020015b60405180910390f35b6101cb7f043c983c49d46f0e102151eaf8085d4a2e6571d5df2d47b013f39bddfd4a639d81565b60405190815260200161019b565b6101ec6101e736600461107e565b61041d565b005b6101cb61271081565b6101cb6102053660046110b1565b60009081526020819052604090206001015490565b6101ec6102283660046110ca565b61050b565b6101ec61023b3660046110ca565b610536565b6101cb60025481565b6101cb7fdb9556138406326f00296e13ea2ad7db24ba82381212d816b1a40c23b466b32781565b61028361027e3660046110ed565b61058f565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200161019b565b61018f6102b63660046110ca565b60009182526020828152604080842073ffffffffffffffffffffffffffffffffffffffff93909316845291905290205460ff1690565b6101cb7fe2b7fb3b832174769106daebcfd6d1970523240dda11281102db9363b83b0dc481565b6101cb600081565b6101ec6103293660046110b1565b6105ae565b6101ec61033c3660046110b1565b610690565b6101cb620f424081565b6101cb6103593660046110b1565b6106f8565b6101cb7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f5581565b6101ec6103933660046110ca565b61070f565b6101cb6103a636600461110f565b60036020526000908152604090205481565b6101cb60045481565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f5a05180f000000000000000000000000000000000000000000000000000000001480610417575061041782610734565b92915050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f55610447816107cb565b73ffffffffffffffffffffffffffffffffffffffff83166000908152600360205260408120549081900361047b5750505050565b73ffffffffffffffffffffffffffffffffffffffff84166000818152600360205260408120556104ac9084836107d8565b6040805173ffffffffffffffffffffffffffffffffffffffff8087168252851660208201529081018290527f244e51bc38c1452fa8aaf487bcb4bca36c2baa3a5fbdb776b1eabd8dc6d277cd9060600160405180910390a1505b505050565b600082815260208190526040902060010154610526816107cb565b610530838361092f565b50505050565b73ffffffffffffffffffffffffffffffffffffffff81163314610585576040517f6697b23200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6105068282610964565b60008281526001602052604081206105a79083610991565b9392505050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f556105d8816107cb565b612710821115610649576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f6e657746656552617465203e206d61780000000000000000000000000000000060448201526064015b60405180910390fd5b600280549083905560408051828152602081018590527f14914da2bf76024616fbe1859783fcd4dbddcb179b1f3a854949fbf920dcb95791015b60405180910390a1505050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f556106ba816107cb565b600480549083905560408051828152602081018590527f5cf09b12f3f56b4c564d51b25b40360af6d795198adb61ae0806a36c294323fa9101610683565b60008181526001602052604081206104179061099d565b60008281526020819052604090206001015461072a816107cb565b6105308383610964565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f7965db0b00000000000000000000000000000000000000000000000000000000148061041757507f01ffc9a7000000000000000000000000000000000000000000000000000000007fffffffff00000000000000000000000000000000000000000000000000000000831614610417565b6107d581336109a7565b50565b3073ffffffffffffffffffffffffffffffffffffffff8316036107fa57505050565b8060000361080757505050565b7fffffffffffffffffffffffff111111111111111111111111111111111111111273ffffffffffffffffffffffffffffffffffffffff84160161090e5760008273ffffffffffffffffffffffffffffffffffffffff168260405160006040518083038185875af1925050503d806000811461089e576040519150601f19603f3d011682016040523d82523d6000602084013e6108a3565b606091505b5050905080610530576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f455448207472616e73666572206661696c6564000000000000000000000000006044820152606401610640565b61050673ffffffffffffffffffffffffffffffffffffffff84168383610a31565b60008061093c8484610abe565b905080156105a757600084815260016020526040902061095c9084610bba565b509392505050565b6000806109718484610bdc565b905080156105a757600084815260016020526040902061095c9084610c97565b60006105a78383610cb9565b6000610417825490565b60008281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915290205460ff16610a2d576040517fe2517d3f00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8216600482015260248101839052604401610640565b5050565b6040805173ffffffffffffffffffffffffffffffffffffffff8416602482015260448082018490528251808303909101815260649091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fa9059cbb00000000000000000000000000000000000000000000000000000000179052610506908490610ce3565b60008281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915281205460ff16610bb25760008381526020818152604080832073ffffffffffffffffffffffffffffffffffffffff86168452909152902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055610b503390565b73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16847f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a4506001610417565b506000610417565b60006105a78373ffffffffffffffffffffffffffffffffffffffff8416610d79565b60008281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915281205460ff1615610bb25760008381526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8616808552925280832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016905551339286917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a4506001610417565b60006105a78373ffffffffffffffffffffffffffffffffffffffff8416610dc0565b6000826000018281548110610cd057610cd061112a565b9060005260206000200154905092915050565b6000610d0573ffffffffffffffffffffffffffffffffffffffff841683610eb3565b90508051600014158015610d2a575080806020019051810190610d289190611159565b155b15610506576040517f5274afe700000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff84166004820152602401610640565b6000818152600183016020526040812054610bb257508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155610417565b60008181526001830160205260408120548015610ea9576000610de460018361117b565b8554909150600090610df89060019061117b565b9050808214610e5d576000866000018281548110610e1857610e1861112a565b9060005260206000200154905080876000018481548110610e3b57610e3b61112a565b6000918252602080832090910192909255918252600188019052604090208390555b8554869080610e6e57610e6e6111b5565b600190038181906000526020600020016000905590558560010160008681526020019081526020016000206000905560019350505050610417565b6000915050610417565b60606105a783836000846000808573ffffffffffffffffffffffffffffffffffffffff168486604051610ee691906111e4565b60006040518083038185875af1925050503d8060008114610f23576040519150601f19603f3d011682016040523d82523d6000602084013e610f28565b606091505b5091509150610f38868383610f42565b9695505050505050565b606082610f5757610f5282610fd1565b6105a7565b8151158015610f7b575073ffffffffffffffffffffffffffffffffffffffff84163b155b15610fca576040517f9996b31500000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff85166004820152602401610640565b50806105a7565b805115610fe15780518082602001fd5b6040517f1425ea4200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006020828403121561102557600080fd5b81357fffffffff00000000000000000000000000000000000000000000000000000000811681146105a757600080fd5b803573ffffffffffffffffffffffffffffffffffffffff8116811461107957600080fd5b919050565b6000806040838503121561109157600080fd5b61109a83611055565b91506110a860208401611055565b90509250929050565b6000602082840312156110c357600080fd5b5035919050565b600080604083850312156110dd57600080fd5b823591506110a860208401611055565b6000806040838503121561110057600080fd5b50508035926020909101359150565b60006020828403121561112157600080fd5b6105a782611055565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60006020828403121561116b57600080fd5b815180151581146105a757600080fd5b81810381811115610417577f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fd5b6000825160005b8181101561120557602081860181015185830152016111eb565b50600092019182525091905056fea2646970667358221220b13443229221519c0fdb3ac2db22c34ccdfff8fd9f142c9a058dcefb00a5a9d864736f6c63430008180033","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.24 ^0.8.0 ^0.8.20;\n\n// contracts/interfaces/IAdmin.sol\n\ninterface IAdmin {\n // ============ Events ============\n\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n event ChainGasAmountUpdated(uint256 oldChainGasAmount, uint256 newChainGasAmount);\n\n // ============ Methods ============\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n\n function setChainGasAmount(uint256 newChainGasAmount) external;\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IFastBridgeRecipient.sol\n\ninterface IFastBridgeRecipient {\n function fastBridgeTransferReceived(\n address token,\n uint256 amount,\n bytes memory callParams\n )\n external\n payable\n returns (bytes4);\n}\n\n// contracts/interfaces/IFastBridgeV2Errors.sol\n\ninterface IFastBridgeV2Errors {\n error AmountIncorrect();\n error CallParamsLengthAboveMax();\n error ChainIncorrect();\n error ExclusivityParamsIncorrect();\n error MsgValueIncorrect();\n error NativeTokenCallValueNotSupported();\n error SenderIncorrect();\n error StatusIncorrect();\n error ZeroAddress();\n\n error RecipientIncorrectReturnValue();\n error RecipientNoReturnValue();\n\n error DeadlineExceeded();\n error DeadlineNotExceeded();\n error DeadlineTooShort();\n error DisputePeriodNotPassed();\n error DisputePeriodPassed();\n error ExclusivityPeriodNotPassed();\n\n error TransactionRelayed();\n}\n\n// contracts/libs/Errors.sol\n\nerror DeadlineExceeded();\nerror DeadlineNotExceeded();\nerror DeadlineTooShort();\nerror InsufficientOutputAmount();\n\nerror MsgValueIncorrect();\nerror PoolNotFound();\nerror TokenAddressMismatch();\nerror TokenNotContract();\nerror TokenNotETH();\nerror TokensIdentical();\n\nerror ChainIncorrect();\nerror AmountIncorrect();\nerror ZeroAddress();\n\nerror DisputePeriodNotPassed();\nerror DisputePeriodPassed();\nerror SenderIncorrect();\nerror StatusIncorrect();\nerror TransactionIdIncorrect();\nerror TransactionRelayed();\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// contracts/interfaces/IFastBridgeV2.sol\n\ninterface IFastBridgeV2 is IFastBridge {\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n struct BridgeTxDetails {\n BridgeStatus status;\n uint40 proofBlockTimestamp;\n uint48 proofBlockNumber;\n address proofRelayer;\n }\n\n struct BridgeRelay {\n uint48 blockNumber;\n uint48 blockTimestamp;\n address relayer;\n }\n\n /// @notice New params introduced in the FastBridgeV2.\n /// We are passing fields from the older BridgeParams struct outside of this struct\n /// for backwards compatibility.\n /// Note: quoteRelayer and quoteExclusivitySeconds are either both zero (indicating no exclusivity)\n /// or both non-zero (indicating exclusivity for the given period).\n /// Note: callValue \u003e 0 can NOT be used with destToken = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE (ETH_ADDRESS)\n /// @param quoteRelayer Relayer that provided the quote for the transaction\n /// @param quoteExclusivitySeconds Period of time the quote relayer is guaranteed exclusivity after user's deposit\n /// @param quoteId Unique quote identifier used for tracking the quote\n /// @param callValue ETH value to send to the recipient (if any)\n /// @param callParams Parameters for the arbitrary call to the destination recipient (if any)\n struct BridgeParamsV2 {\n address quoteRelayer;\n int256 quoteExclusivitySeconds;\n bytes quoteId;\n uint256 callValue;\n bytes callParams;\n }\n\n /// @notice Updated bridge transaction struct to include parameters introduced in FastBridgeV2.\n /// Note: only `exclusivityRelayer` can fill such a transaction until `exclusivityEndTime`.\n /// TODO: consider changing the encoding scheme to prevent spending extra gas on decoding.\n struct BridgeTransactionV2 {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n uint256 callValue; // ETH value to send to the recipient (if any) - replaces V1's sendChainGas flag\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n address exclusivityRelayer;\n uint256 exclusivityEndTime;\n bytes callParams;\n }\n\n event BridgeQuoteDetails(bytes32 indexed transactionId, bytes quoteId);\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability\n /// to provide temporary exclusivity fill rights for the quote relayer.\n /// @param params The parameters required to bridge\n /// @param paramsV2 The parameters for exclusivity fill rights (optional, can be left empty)\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function relay(bytes memory request, address relayer) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param transactionId The transaction id associated with the encoded bridge transaction to prove\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital.\n /// @notice Can only send funds to the relayer address on the proof.\n /// @param request The encoded bridge transaction to claim on origin chain\n function claim(bytes memory request) external;\n /// @notice Checks if a transaction has been relayed\n /// @param transactionId The ID of the transaction to check\n /// @return True if the transaction has been relayed, false otherwise\n function bridgeRelays(bytes32 transactionId) external view returns (bool);\n\n /// @notice Returns the status of a bridge transaction\n /// @param transactionId The ID of the bridge transaction\n /// @return BridgeStatus Status of the bridge transaction\n function bridgeStatuses(bytes32 transactionId) external view returns (BridgeStatus);\n\n /// @notice Returns the timestamp and relayer of a bridge proof\n /// @param transactionId The ID of the bridge transaction\n /// @return timestamp The timestamp of the bridge proof\n /// @return relayer The relayer address of the bridge proof\n function bridgeProofs(bytes32 transactionId) external view returns (uint96 timestamp, address relayer);\n\n /// @notice Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\n /// @param request The bridge request to decode\n function getBridgeTransactionV2(bytes memory request) external view returns (BridgeTransactionV2 memory);\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// contracts/libs/UniversalToken.sol\n\nlibrary UniversalTokenLib {\n using SafeERC20 for IERC20;\n\n address internal constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Transfers tokens to the given account. Reverts if transfer is not successful.\n /// @dev This might trigger fallback, if ETH is transferred to the contract.\n /// Make sure this can not lead to reentrancy attacks.\n function universalTransfer(address token, address to, uint256 value) internal {\n // Don't do anything, if need to send tokens to this address\n if (to == address(this)) return;\n // Don't do anything, if trying to send zero value\n if (value == 0) return;\n if (token == ETH_ADDRESS) {\n /// @dev Note: this can potentially lead to executing code in `to`.\n // solhint-disable-next-line avoid-low-level-calls\n (bool success,) = to.call{value: value}(\"\");\n require(success, \"ETH transfer failed\");\n } else {\n IERC20(token).safeTransfer(to, value);\n }\n }\n\n /// @notice Issues an infinite allowance to the spender, if the current allowance is insufficient\n /// to spend the given amount.\n function universalApproveInfinity(address token, address spender, uint256 amountToSpend) internal {\n // ETH Chad doesn't require your approval\n if (token == ETH_ADDRESS) return;\n // No-op if allowance is already sufficient\n uint256 allowance = IERC20(token).allowance(address(this), spender);\n if (allowance \u003e= amountToSpend) return;\n // Otherwise, reset approval to 0 and set to max allowance\n if (allowance \u003e 0) IERC20(token).safeDecreaseAllowance(spender, allowance);\n IERC20(token).safeIncreaseAllowance(spender, type(uint256).max);\n }\n\n /// @notice Returns the balance of the given token (or native ETH) for the given account.\n function universalBalanceOf(address token, address account) internal view returns (uint256) {\n if (token == ETH_ADDRESS) {\n return account.balance;\n } else {\n return IERC20(token).balanceOf(account);\n }\n }\n\n /// @dev Checks that token is a contract and not ETH_ADDRESS.\n function assertIsContract(address token) internal view {\n // Check that ETH_ADDRESS was not used (in case this is a predeploy on any of the chains)\n if (token == UniversalTokenLib.ETH_ADDRESS) revert TokenNotContract();\n // Check that token is not an EOA\n if (token.code.length == 0) revert TokenNotContract();\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/Admin.sol\n\ncontract Admin is IAdmin, AccessControlEnumerable {\n using UniversalTokenLib for address;\n\n bytes32 public constant RELAYER_ROLE = keccak256(\"RELAYER_ROLE\");\n bytes32 public constant REFUNDER_ROLE = keccak256(\"REFUNDER_ROLE\");\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n uint256 public constant FEE_BPS = 1e6;\n uint256 public constant FEE_RATE_MAX = 0.01e6; // max 1% on origin amount\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Chain gas amount to forward as rebate if requested\n uint256 public chainGasAmount;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n }\n\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n require(newFeeRate \u003c= FEE_RATE_MAX, \"newFeeRate \u003e max\");\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n token.universalTransfer(recipient, feeAmount);\n emit FeesSwept(token, recipient, feeAmount);\n }\n\n function setChainGasAmount(uint256 newChainGasAmount) external onlyRole(GOVERNOR_ROLE) {\n uint256 oldChainGasAmount = chainGasAmount;\n chainGasAmount = newChainGasAmount;\n emit ChainGasAmountUpdated(oldChainGasAmount, newChainGasAmount);\n }\n}\n\n// contracts/FastBridgeV2.sol\n\n/// @notice FastBridgeV2 is a contract for bridging tokens across chains.\ncontract FastBridgeV2 is Admin, IFastBridgeV2, IFastBridgeV2Errors {\n using SafeERC20 for IERC20;\n using UniversalTokenLib for address;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Delay for a transaction after which it could be permisionlessly refunded\n uint256 public constant REFUND_DELAY = 7 days;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n /// @notice Maximum length of accepted callParams\n uint256 public constant MAX_CALL_PARAMS_LENGTH = 2 ** 16 - 1;\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeTxDetails) public bridgeTxDetails;\n /// @notice Relay details on destination chain\n mapping(bytes32 =\u003e BridgeRelay) public bridgeRelayDetails;\n /// @notice Unique bridge nonces tracked per originSender\n mapping(address =\u003e uint256) public senderNonces;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Replaced by senderNonces\n uint256 public immutable nonce = 0;\n /// @notice the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n bridge({\n params: params,\n paramsV2: BridgeParamsV2({\n quoteRelayer: address(0),\n quoteExclusivitySeconds: 0,\n quoteId: bytes(\"\"),\n callValue: 0,\n callParams: bytes(\"\")\n })\n });\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes memory request) external payable {\n relay({request: request, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes memory request, bytes32 destTxHash) external {\n prove({transactionId: keccak256(request), destTxHash: destTxHash, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridgeV2\n function claim(bytes memory request) external {\n claim({request: request, to: address(0)});\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003e DISPUTE_PERIOD) {\n revert DisputePeriodPassed();\n }\n\n // @dev relayer gets slashed effectively if dest relay has gone thru\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n bridgeTxDetails[transactionId].proofRelayer = address(0);\n bridgeTxDetails[transactionId].proofBlockTimestamp = 0;\n bridgeTxDetails[transactionId].proofBlockNumber = 0;\n\n emit BridgeProofDisputed(transactionId, msg.sender);\n }\n\n /// @inheritdoc IFastBridge\n function refund(bytes memory request) external {\n bytes32 transactionId = keccak256(request);\n\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n\n if (bridgeTxDetails[transactionId].status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n\n if (hasRole(REFUNDER_ROLE, msg.sender)) {\n // Refunder can refund if deadline has passed\n if (block.timestamp \u003c= transaction.deadline) revert DeadlineNotExceeded();\n } else {\n // Permissionless refund is allowed after REFUND_DELAY\n if (block.timestamp \u003c= transaction.deadline + REFUND_DELAY) revert DeadlineNotExceeded();\n }\n\n // if all checks passed, set to REFUNDED status\n bridgeTxDetails[transactionId].status = BridgeStatus.REFUNDED;\n\n // transfer origin collateral back to original sender\n address to = transaction.originSender;\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount + transaction.originFeeAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (bridgeTxDetails[transactionId].proofRelayer != relayer) revert SenderIncorrect();\n return _timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n /// @dev This method is added to achieve backwards compatibility with decoding requests into V1 structs:\n /// - `callValue` is partially reported as a zero/non-zero flag\n /// - `callParams` is ignored\n /// In order to process all kinds of requests use getBridgeTransactionV2 instead.\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory) {\n // Try decoding into V2 struct first. This will revert if V1 struct is passed\n try this.getBridgeTransactionV2(request) returns (BridgeTransactionV2 memory txV2) {\n // Note: we entirely ignore the callParams field, as it was not present in V1\n return BridgeTransaction({\n originChainId: txV2.originChainId,\n destChainId: txV2.destChainId,\n originSender: txV2.originSender,\n destRecipient: txV2.destRecipient,\n originToken: txV2.originToken,\n destToken: txV2.destToken,\n originAmount: txV2.originAmount,\n destAmount: txV2.destAmount,\n originFeeAmount: txV2.originFeeAmount,\n sendChainGas: txV2.callValue != 0,\n deadline: txV2.deadline,\n nonce: txV2.nonce\n });\n } catch {\n // Fallback to V1 struct\n return abi.decode(request, (BridgeTransaction));\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) public payable {\n int256 exclusivityEndTime = int256(block.timestamp) + paramsV2.quoteExclusivitySeconds;\n _validateBridgeParams(params, paramsV2, exclusivityEndTime);\n\n // transfer tokens to bridge contract\n /// @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _takeBridgedUserAsset(params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n\n // set status to requested\n bytes memory request = abi.encode(\n BridgeTransactionV2({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n callValue: paramsV2.callValue,\n deadline: params.deadline,\n nonce: senderNonces[params.sender]++, // increment nonce on every bridge\n exclusivityRelayer: paramsV2.quoteRelayer,\n // We checked exclusivityEndTime to be in range (0 .. params.deadline] above, so can safely cast\n exclusivityEndTime: uint256(exclusivityEndTime),\n callParams: paramsV2.callParams\n })\n );\n bytes32 transactionId = keccak256(request);\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n\n emit BridgeRequested({\n transactionId: transactionId,\n sender: params.sender,\n request: request,\n destChainId: params.dstChainId,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n sendChainGas: paramsV2.callValue != 0\n });\n emit BridgeQuoteDetails(transactionId, paramsV2.quoteId);\n }\n\n /// @inheritdoc IFastBridgeV2\n function relay(bytes memory request, address relayer) public payable {\n bytes32 transactionId = keccak256(request);\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n _validateRelayParams(transaction, transactionId, relayer);\n // mark bridge transaction as relayed\n bridgeRelayDetails[transactionId] =\n BridgeRelay({blockNumber: uint48(block.number), blockTimestamp: uint48(block.timestamp), relayer: relayer});\n\n // transfer tokens to recipient on destination chain and do an arbitrary call if requested\n address to = transaction.destRecipient;\n address token = transaction.destToken;\n uint256 amount = transaction.destAmount;\n uint256 callValue = transaction.callValue;\n\n // Emit the event before any external calls\n emit BridgeRelayed({\n transactionId: transactionId,\n relayer: relayer,\n to: to,\n originChainId: transaction.originChainId,\n originToken: transaction.originToken,\n destToken: token,\n originAmount: transaction.originAmount,\n destAmount: amount,\n chainGasAmount: callValue\n });\n\n // All state changes have been done at this point, can proceed to the external calls.\n // This follows the checks-effects-interactions pattern to mitigate potential reentrancy attacks.\n if (token == UniversalTokenLib.ETH_ADDRESS) {\n // For ETH non-zero callValue is not allowed\n if (callValue != 0) revert NativeTokenCallValueNotSupported();\n // Check that the correct msg.value was sent\n if (msg.value != amount) revert MsgValueIncorrect();\n } else {\n // For ERC20s, we check that the correct msg.value was sent\n if (msg.value != callValue) revert MsgValueIncorrect();\n // We need to transfer the tokens from the Relayer to the recipient first before performing an\n // optional post-transfer arbitrary call.\n IERC20(token).safeTransferFrom(msg.sender, to, amount);\n }\n\n if (transaction.callParams.length != 0) {\n // Arbitrary call requested, perform it while supplying full msg.value to the recipient\n // Note: if token has a fee on transfers, the recipient will have received less than `amount`.\n // This is a very niche edge case and should be handled by the recipient contract.\n _checkedCallRecipient({recipient: to, token: token, amount: amount, callParams: transaction.callParams});\n } else if (msg.value != 0) {\n // No arbitrary call requested, but msg.value was sent. This is either a relay with ETH,\n // or a non-zero callValue request with an ERC20. In both cases, transfer the ETH to the recipient.\n Address.sendValue(payable(to), msg.value);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) public onlyRole(RELAYER_ROLE) {\n // update bridge tx status given proof provided\n if (bridgeTxDetails[transactionId].status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n bridgeTxDetails[transactionId].status = BridgeStatus.RELAYER_PROVED;\n bridgeTxDetails[transactionId].proofBlockTimestamp = uint40(block.timestamp);\n bridgeTxDetails[transactionId].proofBlockNumber = uint48(block.number);\n bridgeTxDetails[transactionId].proofRelayer = relayer;\n\n emit BridgeProofProvided(transactionId, relayer, destTxHash);\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes memory request, address to) public {\n bytes32 transactionId = keccak256(request);\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n\n // update bridge tx status if able to claim origin collateral\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n\n // if \"to\" is zero addr, permissionlessly send funds to proven relayer\n if (to == address(0)) {\n to = bridgeTxDetails[transactionId].proofRelayer;\n } else if (bridgeTxDetails[transactionId].proofRelayer != msg.sender) {\n revert SenderIncorrect();\n }\n\n if (_timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003c= DISPUTE_PERIOD) {\n revert DisputePeriodNotPassed();\n }\n\n bridgeTxDetails[transactionId].status = BridgeStatus.RELAYER_CLAIMED;\n\n // update protocol fees if origin fee amount exists\n if (transaction.originFeeAmount \u003e 0) protocolFees[transaction.originToken] += transaction.originFeeAmount;\n\n // transfer origin collateral less fee to specified address\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositClaimed(transactionId, bridgeTxDetails[transactionId].proofRelayer, to, token, amount);\n }\n\n function bridgeStatuses(bytes32 transactionId) public view returns (BridgeStatus status) {\n return bridgeTxDetails[transactionId].status;\n }\n\n function bridgeProofs(bytes32 transactionId) public view returns (uint96 timestamp, address relayer) {\n timestamp = bridgeTxDetails[transactionId].proofBlockTimestamp;\n relayer = bridgeTxDetails[transactionId].proofRelayer;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeRelays(bytes32 transactionId) public view returns (bool) {\n // has this transactionId been relayed?\n return bridgeRelayDetails[transactionId].relayer != address(0);\n }\n\n /// @inheritdoc IFastBridgeV2\n function getBridgeTransactionV2(bytes memory request) public pure returns (BridgeTransactionV2 memory) {\n return abi.decode(request, (BridgeTransactionV2));\n }\n\n /// @notice Takes the bridged asset from the user into FastBridgeV2 custody. It will be later\n /// claimed by the relayer who completed the relay on destination chain, or refunded back to the user,\n /// should no one complete the relay.\n function _takeBridgedUserAsset(address token, uint256 amount) internal returns (uint256 amountTaken) {\n if (token == UniversalTokenLib.ETH_ADDRESS) {\n // For ETH we just need to check that the supplied msg.value is correct.\n // Supplied `msg.value` is already in FastBridgeV2 custody.\n if (amount != msg.value) revert MsgValueIncorrect();\n amountTaken = msg.value;\n } else {\n // For ERC20s, token is explicitly transferred from the user to FastBridgeV2.\n // We don't allow non-zero `msg.value` to avoid extra funds from being stuck in FastBridgeV2.\n token.assertIsContract();\n if (msg.value != 0) revert MsgValueIncorrect();\n amountTaken = IERC20(token).balanceOf(address(this));\n IERC20(token).safeTransferFrom(msg.sender, address(this), amount);\n // Use the balance difference as the amount taken in case of fee on transfer tokens.\n amountTaken = IERC20(token).balanceOf(address(this)) - amountTaken;\n }\n }\n\n /// @notice Calls the Recipient's hook function with the specified callParams and performs\n /// all the necessary checks for the returned value.\n function _checkedCallRecipient(\n address recipient,\n address token,\n uint256 amount,\n bytes memory callParams\n )\n internal\n {\n bytes memory hookData =\n abi.encodeCall(IFastBridgeRecipient.fastBridgeTransferReceived, (token, amount, callParams));\n // This will bubble any revert messages from the hook function\n bytes memory returnData = Address.functionCallWithValue({target: recipient, data: hookData, value: msg.value});\n // Explicit revert if no return data at all\n if (returnData.length == 0) revert RecipientNoReturnValue();\n // Check that exactly a single return value was returned\n if (returnData.length != 32) revert RecipientIncorrectReturnValue();\n // Return value should be abi-encoded hook function selector\n if (bytes32(returnData) != bytes32(IFastBridgeRecipient.fastBridgeTransferReceived.selector)) {\n revert RecipientIncorrectReturnValue();\n }\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint40(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint40).max but\n /// proof.timestamp \u003c type(uint40).max via unchecked statement\n /// @param proofBlockTimestamp The bridge proof block timestamp\n /// @return delta Time delta since proof submitted\n function _timeSince(uint40 proofBlockTimestamp) internal view returns (uint256 delta) {\n unchecked {\n delta = uint40(block.timestamp) - proofBlockTimestamp;\n }\n }\n\n /// @notice Performs all the necessary checks for a bridge to happen.\n /// @dev There's no good way to refactor this function to reduce cyclomatic complexity due to\n /// the number of checks that need to be performed, so we skip the code-complexity rule here.\n // solhint-disable-next-line code-complexity\n function _validateBridgeParams(\n BridgeParams memory params,\n BridgeParamsV2 memory paramsV2,\n int256 exclusivityEndTime\n )\n internal\n view\n {\n // Check V1 (legacy) params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.sender == address(0) || params.to == address(0)) revert ZeroAddress();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n // Check V2 params\n if (paramsV2.callParams.length \u003e MAX_CALL_PARAMS_LENGTH) revert CallParamsLengthAboveMax();\n if (paramsV2.callValue != 0 \u0026\u0026 params.destToken == UniversalTokenLib.ETH_ADDRESS) {\n revert NativeTokenCallValueNotSupported();\n }\n // exclusivityEndTime must be in range (0 .. params.deadline]\n if (exclusivityEndTime \u003c= 0 || exclusivityEndTime \u003e int256(params.deadline)) {\n revert ExclusivityParamsIncorrect();\n }\n }\n\n /// @notice Performs all the necessary checks for a relay to happen.\n function _validateRelayParams(\n BridgeTransactionV2 memory transaction,\n bytes32 transactionId,\n address relayer\n )\n internal\n view\n {\n if (relayer == address(0)) revert ZeroAddress();\n // Check if the transaction has already been relayed\n if (bridgeRelays(transactionId)) revert TransactionRelayed();\n if (transaction.destChainId != block.chainid) revert ChainIncorrect();\n // Check the deadline for relay to happen\n if (block.timestamp \u003e transaction.deadline) revert DeadlineExceeded();\n // Check the exclusivity period, if it is still ongoing\n // forgefmt: disable-next-item\n if (\n transaction.exclusivityRelayer != address(0) \u0026\u0026\n transaction.exclusivityRelayer != relayer \u0026\u0026\n block.timestamp \u003c= transaction.exclusivityEndTime\n ) {\n revert ExclusivityPeriodNotPassed();\n }\n }\n}\n","language":"Solidity","languageVersion":"0.8.24","compilerVersion":"0.8.24","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"62810:1843:0:-:0;;;63637:83;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;63675:38;52847:4;63706:6;63675:10;:38::i;:::-;;63637:83;62810:1843;;62160:257;62246:4;;62277:31;62294:4;62300:7;62277:16;:31::i;:::-;62262:46;;62322:7;62318:69;;;62345:18;;;;:12;:18;;;;;:31;;62368:7;62345:22;:31::i;:::-;;62318:69;62403:7;-1:-1:-1;62160:257:0;;;;;:::o;56794:316::-;56871:4;53569:12;;;;;;;;;;;-1:-1:-1;;;;;53569:29:0;;;;;;;;;;;;56887:217;;56930:6;:12;;;;;;;;;;;-1:-1:-1;;;;;56930:29:0;;;;;;;;;:36;;-1:-1:-1;;56930:36:0;56962:4;56930:36;;;57012:12;23368:10;;23289:96;57012:12;-1:-1:-1;;;;;56985:40:0;57003:7;-1:-1:-1;;;;;56985:40:0;56997:4;56985:40;;;;;;;;;;-1:-1:-1;57046:4:0;57039:11;;56887:217;-1:-1:-1;57088:5:0;57081:12;;32813:150;32883:4;32906:50;32911:3;-1:-1:-1;;;;;32931:23:0;;26801:4;28857:21;;;:14;;;:21;;;;;;26817:321;;-1:-1:-1;26859:23:0;;;;;;;;:11;:23;;;;;;;;;;;;;27041:18;;27017:21;;;:14;;;:21;;;;;;:42;;;;27073:11;;14:290:1;84:6;137:2;125:9;116:7;112:23;108:32;105:52;;;153:1;150;143:12;105:52;179:16;;-1:-1:-1;;;;;224:31:1;;214:42;;204:70;;270:1;267;260:12;14:290;62810:1843:0;;;;;;","srcMapRuntime":"62810:1843:0:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;60820:212;;;;;;:::i;:::-;;:::i;:::-;;;516:14:1;;509:22;491:41;;479:2;464:18;60820:212:0;;;;;;;;63050:60;;63087:23;63050:60;;;;;689:25:1;;;677:2;662:18;63050:60:0;543:177:1;64022:359:0;;;;;;:::i;:::-;;:::i;:::-;;63232:45;;63271:6;63232:45;;54425:120;;;;;;:::i;:::-;54490:7;54516:12;;;;;;;;;;:22;;;;54425:120;54841:136;;;;;;:::i;:::-;;:::i;55943:245::-;;;;;;:::i;:::-;;:::i;63394:30::-;;;;;;62978:66;;63018:26;62978:66;;61617:142;;;;;;:::i;:::-;;:::i;:::-;;;2246:42:1;2234:55;;;2216:74;;2204:2;2189:18;61617:142:0;2070:226:1;53469:136:0;;;;;;:::i;:::-;53546:4;53569:12;;;;;;;;;;;:29;;;;;;;;;;;;;;;;53469:136;62908:64;;62947:25;62908:64;;52802:49;;52847:4;52802:49;;63726:290;;;;;;:::i;:::-;;:::i;64387:264::-;;;;;;:::i;:::-;;:::i;63189:37::-;;63223:3;63189:37;;61927:131;;;;;;:::i;:::-;;:::i;63116:66::-;;63156:26;63116:66;;55257:138;;;;;;:::i;:::-;;:::i;63480:47::-;;;;;;:::i;:::-;;;;;;;;;;;;;;63601:29;;;;;;60820:212;60905:4;60928:57;;;60943:42;60928:57;;:97;;;60989:36;61013:11;60989:23;:36::i;:::-;60921:104;60820:212;-1:-1:-1;;60820:212:0:o;64022:359::-;63156:26;53079:16;53090:4;53079:10;:16::i;:::-;64146:19:::1;::::0;::::1;64126:17;64146:19:::0;;;:12:::1;:19;::::0;;;;;;64179:14;;;64175:27:::1;;64195:7;64022:359:::0;;;:::o;64175:27::-:1;64243:19;::::0;::::1;64265:1;64243:19:::0;;;:12:::1;:19;::::0;;;;:23;64276:45:::1;::::0;64300:9;64311;64276:23:::1;:45::i;:::-;64336:38;::::0;;2889:42:1;2958:15;;;2940:34;;3010:15;;3005:2;2990:18;;2983:43;3042:18;;;3035:34;;;64336:38:0::1;::::0;2867:2:1;2852:18;64336:38:0::1;;;;;;;64116:265;53105:1;64022:359:::0;;;:::o;54841:136::-;54490:7;54516:12;;;;;;;;;;:22;;;53079:16;53090:4;53079:10;:16::i;:::-;54945:25:::1;54956:4;54962:7;54945:10;:25::i;:::-;;54841:136:::0;;;:::o;55943:245::-;56036:34;;;23368:10;56036:34;56032:102;;56093:30;;;;;;;;;;;;;;56032:102;56144:37;56156:4;56162:18;56144:11;:37::i;61617:142::-;61698:7;61724:18;;;:12;:18;;;;;:28;;61746:5;61724:21;:28::i;:::-;61717:35;61617:142;-1:-1:-1;;;61617:142:0:o;63726:290::-;63156:26;53079:16;53090:4;53079:10;:16::i;:::-;63271:6:::1;63825:10;:26;;63817:55;;;::::0;::::1;::::0;;3282:2:1;63817:55:0::1;::::0;::::1;3264:21:1::0;3321:2;3301:18;;;3294:30;3360:18;3340;;;3333:46;3396:18;;63817:55:0::1;;;;;;;;;63903:15;::::0;;63928:28;;;;63971:38:::1;::::0;;3599:25:1;;;3655:2;3640:18;;3633:34;;;63971:38:0::1;::::0;3572:18:1;63971:38:0::1;;;;;;;;63807:209;63726:290:::0;;:::o;64387:264::-;63156:26;53079:16;53090:4;53079:10;:16::i;:::-;64512:14:::1;::::0;;64536:34;;;;64585:59:::1;::::0;;3599:25:1;;;3655:2;3640:18;;3633:34;;;64585:59:0::1;::::0;3572:18:1;64585:59:0::1;3425:248:1::0;61927:131:0;61998:7;62024:18;;;:12;:18;;;;;:27;;:25;:27::i;55257:138::-;54490:7;54516:12;;;;;;;;;;:22;;;53079:16;53090:4;53079:10;:16::i;:::-;55362:26:::1;55374:4;55380:7;55362:11;:26::i;53180:202::-:0;53265:4;53288:47;;;53303:32;53288:47;;:87;;-1:-1:-1;45095:25:0;45080:40;;;;53339:36;44981:146;53814:103;53880:30;53891:4;23368:10;53880;:30::i;:::-;53814:103;:::o;58092:653::-;58267:4;58253:19;;;;58249:32;;58092:653;;;:::o;58249:32::-;58353:5;58362:1;58353:10;58349:23;;58092:653;;;:::o;58349:23::-;58385:20;;;;;58381:358;;58565:12;58582:2;:7;;58597:5;58582:25;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;58564:43;;;58629:7;58621:39;;;;;;;4090:2:1;58621:39:0;;;4072:21:1;4129:2;4109:18;;;4102:30;4168:21;4148:18;;;4141:49;4207:18;;58621:39:0;3888:343:1;58381:358:0;58691:37;:26;;;58718:2;58722:5;58691:26;:37::i;62160:257::-;62246:4;62262:12;62277:31;62294:4;62300:7;62277:16;:31::i;:::-;62262:46;;62322:7;62318:69;;;62345:18;;;;:12;:18;;;;;:31;;62368:7;62345:22;:31::i;:::-;;62403:7;62160:257;-1:-1:-1;;;62160:257:0:o;62520:262::-;62607:4;62623:12;62638:32;62656:4;62662:7;62638:17;:32::i;:::-;62623:47;;62684:7;62680:72;;;62707:18;;;;:12;:18;;;;;:34;;62733:7;62707:25;:34::i;34071:156::-;34145:7;34195:22;34199:3;34211:5;34195:3;:22::i;33614:115::-;33677:7;33703:19;33711:3;29053:18;;28971:107;54047:197;53546:4;53569:12;;;;;;;;;;;:29;;;;;;;;;;;;;54130:108;;54180:47;;;;;4440:42:1;4428:55;;54180:47:0;;;4410:74:1;4500:18;;;4493:34;;;4383:18;;54180:47:0;4236:297:1;54130:108:0;54047:197;;:::o;46297:160::-;46406:43;;;46421:14;4428:55:1;;46406:43:0;;;4410:74:1;4500:18;;;;4493:34;;;46406:43:0;;;;;;;;;;4383:18:1;;;;46406:43:0;;;;;;;;;;;;;;46379:71;;46399:5;;46379:19;:71::i;56794:316::-;56871:4;53569:12;;;;;;;;;;;:29;;;;;;;;;;;;;56887:217;;56930:6;:12;;;;;;;;;;;:29;;;;;;;;;;:36;;;;56962:4;56930:36;;;57012:12;23368:10;;23289:96;57012:12;56985:40;;57003:7;56985:40;;56997:4;56985:40;;;;;;;;;;-1:-1:-1;57046:4:0;57039:11;;56887:217;-1:-1:-1;57088:5:0;57081:12;;32813:150;32883:4;32906:50;32911:3;32931:23;;;32906:4;:50::i;57345:317::-;57423:4;53569:12;;;;;;;;;;;:29;;;;;;;;;;;;;57439:217;;;57513:5;57481:12;;;;;;;;;;;:29;;;;;;;;;;;:37;;;;;;57537:40;23368:10;;57481:12;;57537:40;;57513:5;57537:40;-1:-1:-1;57598:4:0;57591:11;;33131:156;33204:4;33227:53;33235:3;33255:23;;;33227:7;:53::i;29420:118::-;29487:7;29513:3;:11;;29525:5;29513:18;;;;;;;;:::i;:::-;;;;;;;;;29506:25;;29420:118;;;;:::o;49053:629::-;49472:23;49498:33;:27;;;49526:4;49498:27;:33::i;:::-;49472:59;;49545:10;:17;49566:1;49545:22;;:57;;;;;49583:10;49572:30;;;;;;;;;;;;:::i;:::-;49571:31;49545:57;49541:135;;;49625:40;;;;;2246:42:1;2234:55;;49625:40:0;;;2216:74:1;2189:18;;49625:40:0;2070:226:1;26738:406:0;26801:4;28857:21;;;:14;;;:21;;;;;;26817:321;;-1:-1:-1;26859:23:0;;;;;;;;:11;:23;;;;;;;;;;;;;27041:18;;27017:21;;;:14;;;:21;;;;;;:42;;;;27073:11;;27312:1368;27378:4;27507:21;;;:14;;;:21;;;;;;27543:13;;27539:1135;;27910:18;27931:12;27942:1;27931:8;:12;:::i;:::-;27977:18;;27910:33;;-1:-1:-1;27957:17:0;;27977:22;;27998:1;;27977:22;:::i;:::-;27957:42;;28032:9;28018:10;:23;28014:378;;28061:17;28081:3;:11;;28093:9;28081:22;;;;;;;;:::i;:::-;;;;;;;;;28061:42;;28228:9;28202:3;:11;;28214:10;28202:23;;;;;;;;:::i;:::-;;;;;;;;;;;;:35;;;;28341:25;;;:14;;;:25;;;;;:36;;;28014:378;28470:17;;:3;;:17;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;28573:3;:14;;:21;28588:5;28573:21;;;;;;;;;;;28566:28;;;28616:4;28609:11;;;;;;;27539:1135;28658:5;28651:12;;;;;19074:151;19149:12;19180:38;19202:6;19210:4;19216:1;19149:12;19790;19804:23;19831:6;:11;;19850:5;19857:4;19831:31;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;19789:73;;;;19879:55;19906:6;19914:7;19923:10;19879:26;:55::i;:::-;19872:62;19549:392;-1:-1:-1;;;;;;19549:392:0:o;20994:582::-;21138:12;21167:7;21162:408;;21190:19;21198:10;21190:7;:19::i;:::-;21162:408;;;21414:17;;:22;:49;;;;-1:-1:-1;21440:18:0;;;;:23;21414:49;21410:119;;;21490:24;;;;;2246:42:1;2234:55;;21490:24:0;;;2216:74:1;2189:18;;21490:24:0;2070:226:1;21410:119:0;-1:-1:-1;21549:10:0;21542:17;;22112:516;22243:17;;:21;22239:383;;22471:10;22465:17;22527:15;22514:10;22510:2;22506:19;22499:44;22239:383;22594:17;;;;;;;;;;;;;;14:332:1;72:6;125:2;113:9;104:7;100:23;96:32;93:52;;;141:1;138;131:12;93:52;180:9;167:23;230:66;223:5;219:78;212:5;209:89;199:117;;312:1;309;302:12;725:196;793:20;;853:42;842:54;;832:65;;822:93;;911:1;908;901:12;822:93;725:196;;;:::o;926:260::-;994:6;1002;1055:2;1043:9;1034:7;1030:23;1026:32;1023:52;;;1071:1;1068;1061:12;1023:52;1094:29;1113:9;1094:29;:::i;:::-;1084:39;;1142:38;1176:2;1165:9;1161:18;1142:38;:::i;:::-;1132:48;;926:260;;;;;:::o;1373:180::-;1432:6;1485:2;1473:9;1464:7;1460:23;1456:32;1453:52;;;1501:1;1498;1491:12;1453:52;-1:-1:-1;1524:23:1;;1373:180;-1:-1:-1;1373:180:1:o;1558:254::-;1626:6;1634;1687:2;1675:9;1666:7;1662:23;1658:32;1655:52;;;1703:1;1700;1693:12;1655:52;1739:9;1726:23;1716:33;;1768:38;1802:2;1791:9;1787:18;1768:38;:::i;1817:248::-;1885:6;1893;1946:2;1934:9;1925:7;1921:23;1917:32;1914:52;;;1962:1;1959;1952:12;1914:52;-1:-1:-1;;1985:23:1;;;2055:2;2040:18;;;2027:32;;-1:-1:-1;1817:248:1:o;2486:186::-;2545:6;2598:2;2586:9;2577:7;2573:23;2569:32;2566:52;;;2614:1;2611;2604:12;2566:52;2637:29;2656:9;2637:29;:::i;4840:184::-;4892:77;4889:1;4882:88;4989:4;4986:1;4979:15;5013:4;5010:1;5003:15;5029:277;5096:6;5149:2;5137:9;5128:7;5124:23;5120:32;5117:52;;;5165:1;5162;5155:12;5117:52;5197:9;5191:16;5250:5;5243:13;5236:21;5229:5;5226:32;5216:60;;5272:1;5269;5262:12;5311:282;5378:9;;;5399:11;;;5396:191;;;5443:77;5440:1;5433:88;5544:4;5541:1;5534:15;5572:4;5569:1;5562:15;5598:184;5650:77;5647:1;5640:88;5747:4;5744:1;5737:15;5771:4;5768:1;5761:15;5787:412;5916:3;5954:6;5948:13;5979:1;5989:129;6003:6;6000:1;5997:13;5989:129;;;6101:4;6085:14;;;6081:25;;6075:32;6062:11;;;6055:53;6018:12;5989:129;;;-1:-1:-1;6173:1:1;6137:16;;6162:13;;;-1:-1:-1;6137:16:1;5787:412;-1:-1:-1;5787:412:1:o","abiDefinition":[{"inputs":[{"internalType":"address","name":"_owner","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AccessControlBadConfirmation","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"bytes32","name":"neededRole","type":"bytes32"}],"name":"AccessControlUnauthorizedAccount","type":"error"},{"inputs":[{"internalType":"address","name":"target","type":"address"}],"name":"AddressEmptyCode","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"AddressInsufficientBalance","type":"error"},{"inputs":[],"name":"FailedInnerCall","type":"error"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"SafeERC20FailedOperation","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldChainGasAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newChainGasAmount","type":"uint256"}],"name":"ChainGasAmountUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldFeeRate","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newFeeRate","type":"uint256"}],"name":"FeeRateUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"address","name":"recipient","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"FeesSwept","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"previousAdminRole","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"newAdminRole","type":"bytes32"}],"name":"RoleAdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleRevoked","type":"event"},{"inputs":[],"name":"DEFAULT_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"FEE_BPS","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"FEE_RATE_MAX","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"GOVERNOR_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"GUARD_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"REFUNDER_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"RELAYER_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"chainGasAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleAdmin","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"uint256","name":"index","type":"uint256"}],"name":"getRoleMember","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleMemberCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"grantRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"hasRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"protocolFeeRate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"protocolFees","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"callerConfirmation","type":"address"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"revokeRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"newChainGasAmount","type":"uint256"}],"name":"setChainGasAmount","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"newFeeRate","type":"uint256"}],"name":"setProtocolFeeRate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"address","name":"recipient","type":"address"}],"name":"sweepProtocolFees","outputs":[],"stateMutability":"nonpayable","type":"function"}],"userDoc":{"kind":"user","methods":{"chainGasAmount()":{"notice":"Chain gas amount to forward as rebate if requested"},"protocolFeeRate()":{"notice":"Protocol fee rate taken on origin amount deposited in origin chain"},"protocolFees(address)":{"notice":"Protocol fee amounts accumulated"}},"version":1},"developerDoc":{"errors":{"AccessControlBadConfirmation()":[{"details":"The caller of a function is not the expected one. NOTE: Don't confuse with {AccessControlUnauthorizedAccount}."}],"AccessControlUnauthorizedAccount(address,bytes32)":[{"details":"The `account` is missing a role."}],"AddressEmptyCode(address)":[{"details":"There's no code at `target` (it is not a contract)."}],"AddressInsufficientBalance(address)":[{"details":"The ETH balance of the account is not enough to perform the operation."}],"FailedInnerCall()":[{"details":"A call to an address target failed. The target may have reverted."}],"SafeERC20FailedOperation(address)":[{"details":"An operation with an ERC20 token failed."}]},"events":{"RoleAdminChanged(bytes32,bytes32,bytes32)":{"details":"Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole` `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite {RoleAdminChanged} not being emitted signaling this."},"RoleGranted(bytes32,address,address)":{"details":"Emitted when `account` is granted `role`. `sender` is the account that originated the contract call, an admin role bearer except when using {AccessControl-_setupRole}."},"RoleRevoked(bytes32,address,address)":{"details":"Emitted when `account` is revoked `role`. `sender` is the account that originated the contract call: - if using `revokeRole`, it is the admin role bearer - if using `renounceRole`, it is the role bearer (i.e. `account`)"}},"kind":"dev","methods":{"getRoleAdmin(bytes32)":{"details":"Returns the admin role that controls `role`. See {grantRole} and {revokeRole}. To change a role's admin, use {_setRoleAdmin}."},"getRoleMember(bytes32,uint256)":{"details":"Returns one of the accounts that have `role`. `index` must be a value between 0 and {getRoleMemberCount}, non-inclusive. Role bearers are not sorted in any particular way, and their ordering may change at any point. WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure you perform all queries on the same block. See the following https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post] for more information."},"getRoleMemberCount(bytes32)":{"details":"Returns the number of accounts that have `role`. Can be used together with {getRoleMember} to enumerate all bearers of a role."},"grantRole(bytes32,address)":{"details":"Grants `role` to `account`. If `account` had not been already granted `role`, emits a {RoleGranted} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleGranted} event."},"hasRole(bytes32,address)":{"details":"Returns `true` if `account` has been granted `role`."},"renounceRole(bytes32,address)":{"details":"Revokes `role` from the calling account. Roles are often managed via {grantRole} and {revokeRole}: this function's purpose is to provide a mechanism for accounts to lose their privileges if they are compromised (such as when a trusted device is misplaced). If the calling account had been revoked `role`, emits a {RoleRevoked} event. Requirements: - the caller must be `callerConfirmation`. May emit a {RoleRevoked} event."},"revokeRole(bytes32,address)":{"details":"Revokes `role` from `account`. If `account` had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleRevoked} event."},"supportsInterface(bytes4)":{"details":"See {IERC165-supportsInterface}."}},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_owner\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"AccessControlBadConfirmation\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"neededRole\",\"type\":\"bytes32\"}],\"name\":\"AccessControlUnauthorizedAccount\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"}],\"name\":\"AddressEmptyCode\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"AddressInsufficientBalance\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"FailedInnerCall\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"}],\"name\":\"SafeERC20FailedOperation\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"oldChainGasAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newChainGasAmount\",\"type\":\"uint256\"}],\"name\":\"ChainGasAmountUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"oldFeeRate\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newFeeRate\",\"type\":\"uint256\"}],\"name\":\"FeeRateUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"FeesSwept\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"previousAdminRole\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"newAdminRole\",\"type\":\"bytes32\"}],\"name\":\"RoleAdminChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleGranted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleRevoked\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"DEFAULT_ADMIN_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"FEE_BPS\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"FEE_RATE_MAX\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"GOVERNOR_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"GUARD_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"REFUNDER_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"RELAYER_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"chainGasAmount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"}],\"name\":\"getRoleAdmin\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"index\",\"type\":\"uint256\"}],\"name\":\"getRoleMember\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"}],\"name\":\"getRoleMemberCount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"grantRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"hasRole\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"protocolFeeRate\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"protocolFees\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"callerConfirmation\",\"type\":\"address\"}],\"name\":\"renounceRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"revokeRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"newChainGasAmount\",\"type\":\"uint256\"}],\"name\":\"setChainGasAmount\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"newFeeRate\",\"type\":\"uint256\"}],\"name\":\"setProtocolFeeRate\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes4\",\"name\":\"interfaceId\",\"type\":\"bytes4\"}],\"name\":\"supportsInterface\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"}],\"name\":\"sweepProtocolFees\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"errors\":{\"AccessControlBadConfirmation()\":[{\"details\":\"The caller of a function is not the expected one. NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\"}],\"AccessControlUnauthorizedAccount(address,bytes32)\":[{\"details\":\"The `account` is missing a role.\"}],\"AddressEmptyCode(address)\":[{\"details\":\"There's no code at `target` (it is not a contract).\"}],\"AddressInsufficientBalance(address)\":[{\"details\":\"The ETH balance of the account is not enough to perform the operation.\"}],\"FailedInnerCall()\":[{\"details\":\"A call to an address target failed. The target may have reverted.\"}],\"SafeERC20FailedOperation(address)\":[{\"details\":\"An operation with an ERC20 token failed.\"}]},\"events\":{\"RoleAdminChanged(bytes32,bytes32,bytes32)\":{\"details\":\"Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole` `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite {RoleAdminChanged} not being emitted signaling this.\"},\"RoleGranted(bytes32,address,address)\":{\"details\":\"Emitted when `account` is granted `role`. `sender` is the account that originated the contract call, an admin role bearer except when using {AccessControl-_setupRole}.\"},\"RoleRevoked(bytes32,address,address)\":{\"details\":\"Emitted when `account` is revoked `role`. `sender` is the account that originated the contract call: - if using `revokeRole`, it is the admin role bearer - if using `renounceRole`, it is the role bearer (i.e. `account`)\"}},\"kind\":\"dev\",\"methods\":{\"getRoleAdmin(bytes32)\":{\"details\":\"Returns the admin role that controls `role`. See {grantRole} and {revokeRole}. To change a role's admin, use {_setRoleAdmin}.\"},\"getRoleMember(bytes32,uint256)\":{\"details\":\"Returns one of the accounts that have `role`. `index` must be a value between 0 and {getRoleMemberCount}, non-inclusive. Role bearers are not sorted in any particular way, and their ordering may change at any point. WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure you perform all queries on the same block. See the following https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post] for more information.\"},\"getRoleMemberCount(bytes32)\":{\"details\":\"Returns the number of accounts that have `role`. Can be used together with {getRoleMember} to enumerate all bearers of a role.\"},\"grantRole(bytes32,address)\":{\"details\":\"Grants `role` to `account`. If `account` had not been already granted `role`, emits a {RoleGranted} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleGranted} event.\"},\"hasRole(bytes32,address)\":{\"details\":\"Returns `true` if `account` has been granted `role`.\"},\"renounceRole(bytes32,address)\":{\"details\":\"Revokes `role` from the calling account. Roles are often managed via {grantRole} and {revokeRole}: this function's purpose is to provide a mechanism for accounts to lose their privileges if they are compromised (such as when a trusted device is misplaced). If the calling account had been revoked `role`, emits a {RoleRevoked} event. Requirements: - the caller must be `callerConfirmation`. May emit a {RoleRevoked} event.\"},\"revokeRole(bytes32,address)\":{\"details\":\"Revokes `role` from `account`. If `account` had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleRevoked} event.\"},\"supportsInterface(bytes4)\":{\"details\":\"See {IERC165-supportsInterface}.\"}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"chainGasAmount()\":{\"notice\":\"Chain gas amount to forward as rebate if requested\"},\"protocolFeeRate()\":{\"notice\":\"Protocol fee rate taken on origin amount deposited in origin chain\"},\"protocolFees(address)\":{\"notice\":\"Protocol fee amounts accumulated\"}},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeV2.sol\":\"Admin\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeV2.sol\":{\"keccak256\":\"0xfd916c030b1ffca5a136817827b8018c8ba42ca089905747f3de6148b73eb35e\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://18e6438c4096deb8ae453fb3365ba2b07d52944e93c08288fc5d012b71bf6bb3\",\"dweb:/ipfs/QmfEMqpT1zz6RRm7UuHLRowe1tds2cTGLrVonfm9XSCACj\"]}},\"version\":1}"},"hashes":{"DEFAULT_ADMIN_ROLE()":"a217fddf","FEE_BPS()":"bf333f2c","FEE_RATE_MAX()":"0f5f6ed7","GOVERNOR_ROLE()":"ccc57490","GUARD_ROLE()":"03ed0ee5","REFUNDER_ROLE()":"5960ccf2","RELAYER_ROLE()":"926d7d7f","chainGasAmount()":"e00a83e0","getRoleAdmin(bytes32)":"248a9ca3","getRoleMember(bytes32,uint256)":"9010d07c","getRoleMemberCount(bytes32)":"ca15c873","grantRole(bytes32,address)":"2f2ff15d","hasRole(bytes32,address)":"91d14854","protocolFeeRate()":"58f85880","protocolFees(address)":"dcf844a7","renounceRole(bytes32,address)":"36568abe","revokeRole(bytes32,address)":"d547741f","setChainGasAmount(uint256)":"b250fe6b","setProtocolFeeRate(uint256)":"b13aa2d6","supportsInterface(bytes4)":"01ffc9a7","sweepProtocolFees(address,address)":"06f333f2"}},"solidity/FastBridgeV2.sol:Context":{"code":"0x","runtime-code":"0x","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.24 ^0.8.0 ^0.8.20;\n\n// contracts/interfaces/IAdmin.sol\n\ninterface IAdmin {\n // ============ Events ============\n\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n event ChainGasAmountUpdated(uint256 oldChainGasAmount, uint256 newChainGasAmount);\n\n // ============ Methods ============\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n\n function setChainGasAmount(uint256 newChainGasAmount) external;\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IFastBridgeRecipient.sol\n\ninterface IFastBridgeRecipient {\n function fastBridgeTransferReceived(\n address token,\n uint256 amount,\n bytes memory callParams\n )\n external\n payable\n returns (bytes4);\n}\n\n// contracts/interfaces/IFastBridgeV2Errors.sol\n\ninterface IFastBridgeV2Errors {\n error AmountIncorrect();\n error CallParamsLengthAboveMax();\n error ChainIncorrect();\n error ExclusivityParamsIncorrect();\n error MsgValueIncorrect();\n error NativeTokenCallValueNotSupported();\n error SenderIncorrect();\n error StatusIncorrect();\n error ZeroAddress();\n\n error RecipientIncorrectReturnValue();\n error RecipientNoReturnValue();\n\n error DeadlineExceeded();\n error DeadlineNotExceeded();\n error DeadlineTooShort();\n error DisputePeriodNotPassed();\n error DisputePeriodPassed();\n error ExclusivityPeriodNotPassed();\n\n error TransactionRelayed();\n}\n\n// contracts/libs/Errors.sol\n\nerror DeadlineExceeded();\nerror DeadlineNotExceeded();\nerror DeadlineTooShort();\nerror InsufficientOutputAmount();\n\nerror MsgValueIncorrect();\nerror PoolNotFound();\nerror TokenAddressMismatch();\nerror TokenNotContract();\nerror TokenNotETH();\nerror TokensIdentical();\n\nerror ChainIncorrect();\nerror AmountIncorrect();\nerror ZeroAddress();\n\nerror DisputePeriodNotPassed();\nerror DisputePeriodPassed();\nerror SenderIncorrect();\nerror StatusIncorrect();\nerror TransactionIdIncorrect();\nerror TransactionRelayed();\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// contracts/interfaces/IFastBridgeV2.sol\n\ninterface IFastBridgeV2 is IFastBridge {\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n struct BridgeTxDetails {\n BridgeStatus status;\n uint40 proofBlockTimestamp;\n uint48 proofBlockNumber;\n address proofRelayer;\n }\n\n struct BridgeRelay {\n uint48 blockNumber;\n uint48 blockTimestamp;\n address relayer;\n }\n\n /// @notice New params introduced in the FastBridgeV2.\n /// We are passing fields from the older BridgeParams struct outside of this struct\n /// for backwards compatibility.\n /// Note: quoteRelayer and quoteExclusivitySeconds are either both zero (indicating no exclusivity)\n /// or both non-zero (indicating exclusivity for the given period).\n /// Note: callValue \u003e 0 can NOT be used with destToken = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE (ETH_ADDRESS)\n /// @param quoteRelayer Relayer that provided the quote for the transaction\n /// @param quoteExclusivitySeconds Period of time the quote relayer is guaranteed exclusivity after user's deposit\n /// @param quoteId Unique quote identifier used for tracking the quote\n /// @param callValue ETH value to send to the recipient (if any)\n /// @param callParams Parameters for the arbitrary call to the destination recipient (if any)\n struct BridgeParamsV2 {\n address quoteRelayer;\n int256 quoteExclusivitySeconds;\n bytes quoteId;\n uint256 callValue;\n bytes callParams;\n }\n\n /// @notice Updated bridge transaction struct to include parameters introduced in FastBridgeV2.\n /// Note: only `exclusivityRelayer` can fill such a transaction until `exclusivityEndTime`.\n /// TODO: consider changing the encoding scheme to prevent spending extra gas on decoding.\n struct BridgeTransactionV2 {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n uint256 callValue; // ETH value to send to the recipient (if any) - replaces V1's sendChainGas flag\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n address exclusivityRelayer;\n uint256 exclusivityEndTime;\n bytes callParams;\n }\n\n event BridgeQuoteDetails(bytes32 indexed transactionId, bytes quoteId);\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability\n /// to provide temporary exclusivity fill rights for the quote relayer.\n /// @param params The parameters required to bridge\n /// @param paramsV2 The parameters for exclusivity fill rights (optional, can be left empty)\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function relay(bytes memory request, address relayer) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param transactionId The transaction id associated with the encoded bridge transaction to prove\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital.\n /// @notice Can only send funds to the relayer address on the proof.\n /// @param request The encoded bridge transaction to claim on origin chain\n function claim(bytes memory request) external;\n /// @notice Checks if a transaction has been relayed\n /// @param transactionId The ID of the transaction to check\n /// @return True if the transaction has been relayed, false otherwise\n function bridgeRelays(bytes32 transactionId) external view returns (bool);\n\n /// @notice Returns the status of a bridge transaction\n /// @param transactionId The ID of the bridge transaction\n /// @return BridgeStatus Status of the bridge transaction\n function bridgeStatuses(bytes32 transactionId) external view returns (BridgeStatus);\n\n /// @notice Returns the timestamp and relayer of a bridge proof\n /// @param transactionId The ID of the bridge transaction\n /// @return timestamp The timestamp of the bridge proof\n /// @return relayer The relayer address of the bridge proof\n function bridgeProofs(bytes32 transactionId) external view returns (uint96 timestamp, address relayer);\n\n /// @notice Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\n /// @param request The bridge request to decode\n function getBridgeTransactionV2(bytes memory request) external view returns (BridgeTransactionV2 memory);\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// contracts/libs/UniversalToken.sol\n\nlibrary UniversalTokenLib {\n using SafeERC20 for IERC20;\n\n address internal constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Transfers tokens to the given account. Reverts if transfer is not successful.\n /// @dev This might trigger fallback, if ETH is transferred to the contract.\n /// Make sure this can not lead to reentrancy attacks.\n function universalTransfer(address token, address to, uint256 value) internal {\n // Don't do anything, if need to send tokens to this address\n if (to == address(this)) return;\n // Don't do anything, if trying to send zero value\n if (value == 0) return;\n if (token == ETH_ADDRESS) {\n /// @dev Note: this can potentially lead to executing code in `to`.\n // solhint-disable-next-line avoid-low-level-calls\n (bool success,) = to.call{value: value}(\"\");\n require(success, \"ETH transfer failed\");\n } else {\n IERC20(token).safeTransfer(to, value);\n }\n }\n\n /// @notice Issues an infinite allowance to the spender, if the current allowance is insufficient\n /// to spend the given amount.\n function universalApproveInfinity(address token, address spender, uint256 amountToSpend) internal {\n // ETH Chad doesn't require your approval\n if (token == ETH_ADDRESS) return;\n // No-op if allowance is already sufficient\n uint256 allowance = IERC20(token).allowance(address(this), spender);\n if (allowance \u003e= amountToSpend) return;\n // Otherwise, reset approval to 0 and set to max allowance\n if (allowance \u003e 0) IERC20(token).safeDecreaseAllowance(spender, allowance);\n IERC20(token).safeIncreaseAllowance(spender, type(uint256).max);\n }\n\n /// @notice Returns the balance of the given token (or native ETH) for the given account.\n function universalBalanceOf(address token, address account) internal view returns (uint256) {\n if (token == ETH_ADDRESS) {\n return account.balance;\n } else {\n return IERC20(token).balanceOf(account);\n }\n }\n\n /// @dev Checks that token is a contract and not ETH_ADDRESS.\n function assertIsContract(address token) internal view {\n // Check that ETH_ADDRESS was not used (in case this is a predeploy on any of the chains)\n if (token == UniversalTokenLib.ETH_ADDRESS) revert TokenNotContract();\n // Check that token is not an EOA\n if (token.code.length == 0) revert TokenNotContract();\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/Admin.sol\n\ncontract Admin is IAdmin, AccessControlEnumerable {\n using UniversalTokenLib for address;\n\n bytes32 public constant RELAYER_ROLE = keccak256(\"RELAYER_ROLE\");\n bytes32 public constant REFUNDER_ROLE = keccak256(\"REFUNDER_ROLE\");\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n uint256 public constant FEE_BPS = 1e6;\n uint256 public constant FEE_RATE_MAX = 0.01e6; // max 1% on origin amount\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Chain gas amount to forward as rebate if requested\n uint256 public chainGasAmount;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n }\n\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n require(newFeeRate \u003c= FEE_RATE_MAX, \"newFeeRate \u003e max\");\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n token.universalTransfer(recipient, feeAmount);\n emit FeesSwept(token, recipient, feeAmount);\n }\n\n function setChainGasAmount(uint256 newChainGasAmount) external onlyRole(GOVERNOR_ROLE) {\n uint256 oldChainGasAmount = chainGasAmount;\n chainGasAmount = newChainGasAmount;\n emit ChainGasAmountUpdated(oldChainGasAmount, newChainGasAmount);\n }\n}\n\n// contracts/FastBridgeV2.sol\n\n/// @notice FastBridgeV2 is a contract for bridging tokens across chains.\ncontract FastBridgeV2 is Admin, IFastBridgeV2, IFastBridgeV2Errors {\n using SafeERC20 for IERC20;\n using UniversalTokenLib for address;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Delay for a transaction after which it could be permisionlessly refunded\n uint256 public constant REFUND_DELAY = 7 days;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n /// @notice Maximum length of accepted callParams\n uint256 public constant MAX_CALL_PARAMS_LENGTH = 2 ** 16 - 1;\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeTxDetails) public bridgeTxDetails;\n /// @notice Relay details on destination chain\n mapping(bytes32 =\u003e BridgeRelay) public bridgeRelayDetails;\n /// @notice Unique bridge nonces tracked per originSender\n mapping(address =\u003e uint256) public senderNonces;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Replaced by senderNonces\n uint256 public immutable nonce = 0;\n /// @notice the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n bridge({\n params: params,\n paramsV2: BridgeParamsV2({\n quoteRelayer: address(0),\n quoteExclusivitySeconds: 0,\n quoteId: bytes(\"\"),\n callValue: 0,\n callParams: bytes(\"\")\n })\n });\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes memory request) external payable {\n relay({request: request, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes memory request, bytes32 destTxHash) external {\n prove({transactionId: keccak256(request), destTxHash: destTxHash, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridgeV2\n function claim(bytes memory request) external {\n claim({request: request, to: address(0)});\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003e DISPUTE_PERIOD) {\n revert DisputePeriodPassed();\n }\n\n // @dev relayer gets slashed effectively if dest relay has gone thru\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n bridgeTxDetails[transactionId].proofRelayer = address(0);\n bridgeTxDetails[transactionId].proofBlockTimestamp = 0;\n bridgeTxDetails[transactionId].proofBlockNumber = 0;\n\n emit BridgeProofDisputed(transactionId, msg.sender);\n }\n\n /// @inheritdoc IFastBridge\n function refund(bytes memory request) external {\n bytes32 transactionId = keccak256(request);\n\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n\n if (bridgeTxDetails[transactionId].status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n\n if (hasRole(REFUNDER_ROLE, msg.sender)) {\n // Refunder can refund if deadline has passed\n if (block.timestamp \u003c= transaction.deadline) revert DeadlineNotExceeded();\n } else {\n // Permissionless refund is allowed after REFUND_DELAY\n if (block.timestamp \u003c= transaction.deadline + REFUND_DELAY) revert DeadlineNotExceeded();\n }\n\n // if all checks passed, set to REFUNDED status\n bridgeTxDetails[transactionId].status = BridgeStatus.REFUNDED;\n\n // transfer origin collateral back to original sender\n address to = transaction.originSender;\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount + transaction.originFeeAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (bridgeTxDetails[transactionId].proofRelayer != relayer) revert SenderIncorrect();\n return _timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n /// @dev This method is added to achieve backwards compatibility with decoding requests into V1 structs:\n /// - `callValue` is partially reported as a zero/non-zero flag\n /// - `callParams` is ignored\n /// In order to process all kinds of requests use getBridgeTransactionV2 instead.\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory) {\n // Try decoding into V2 struct first. This will revert if V1 struct is passed\n try this.getBridgeTransactionV2(request) returns (BridgeTransactionV2 memory txV2) {\n // Note: we entirely ignore the callParams field, as it was not present in V1\n return BridgeTransaction({\n originChainId: txV2.originChainId,\n destChainId: txV2.destChainId,\n originSender: txV2.originSender,\n destRecipient: txV2.destRecipient,\n originToken: txV2.originToken,\n destToken: txV2.destToken,\n originAmount: txV2.originAmount,\n destAmount: txV2.destAmount,\n originFeeAmount: txV2.originFeeAmount,\n sendChainGas: txV2.callValue != 0,\n deadline: txV2.deadline,\n nonce: txV2.nonce\n });\n } catch {\n // Fallback to V1 struct\n return abi.decode(request, (BridgeTransaction));\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) public payable {\n int256 exclusivityEndTime = int256(block.timestamp) + paramsV2.quoteExclusivitySeconds;\n _validateBridgeParams(params, paramsV2, exclusivityEndTime);\n\n // transfer tokens to bridge contract\n /// @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _takeBridgedUserAsset(params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n\n // set status to requested\n bytes memory request = abi.encode(\n BridgeTransactionV2({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n callValue: paramsV2.callValue,\n deadline: params.deadline,\n nonce: senderNonces[params.sender]++, // increment nonce on every bridge\n exclusivityRelayer: paramsV2.quoteRelayer,\n // We checked exclusivityEndTime to be in range (0 .. params.deadline] above, so can safely cast\n exclusivityEndTime: uint256(exclusivityEndTime),\n callParams: paramsV2.callParams\n })\n );\n bytes32 transactionId = keccak256(request);\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n\n emit BridgeRequested({\n transactionId: transactionId,\n sender: params.sender,\n request: request,\n destChainId: params.dstChainId,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n sendChainGas: paramsV2.callValue != 0\n });\n emit BridgeQuoteDetails(transactionId, paramsV2.quoteId);\n }\n\n /// @inheritdoc IFastBridgeV2\n function relay(bytes memory request, address relayer) public payable {\n bytes32 transactionId = keccak256(request);\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n _validateRelayParams(transaction, transactionId, relayer);\n // mark bridge transaction as relayed\n bridgeRelayDetails[transactionId] =\n BridgeRelay({blockNumber: uint48(block.number), blockTimestamp: uint48(block.timestamp), relayer: relayer});\n\n // transfer tokens to recipient on destination chain and do an arbitrary call if requested\n address to = transaction.destRecipient;\n address token = transaction.destToken;\n uint256 amount = transaction.destAmount;\n uint256 callValue = transaction.callValue;\n\n // Emit the event before any external calls\n emit BridgeRelayed({\n transactionId: transactionId,\n relayer: relayer,\n to: to,\n originChainId: transaction.originChainId,\n originToken: transaction.originToken,\n destToken: token,\n originAmount: transaction.originAmount,\n destAmount: amount,\n chainGasAmount: callValue\n });\n\n // All state changes have been done at this point, can proceed to the external calls.\n // This follows the checks-effects-interactions pattern to mitigate potential reentrancy attacks.\n if (token == UniversalTokenLib.ETH_ADDRESS) {\n // For ETH non-zero callValue is not allowed\n if (callValue != 0) revert NativeTokenCallValueNotSupported();\n // Check that the correct msg.value was sent\n if (msg.value != amount) revert MsgValueIncorrect();\n } else {\n // For ERC20s, we check that the correct msg.value was sent\n if (msg.value != callValue) revert MsgValueIncorrect();\n // We need to transfer the tokens from the Relayer to the recipient first before performing an\n // optional post-transfer arbitrary call.\n IERC20(token).safeTransferFrom(msg.sender, to, amount);\n }\n\n if (transaction.callParams.length != 0) {\n // Arbitrary call requested, perform it while supplying full msg.value to the recipient\n // Note: if token has a fee on transfers, the recipient will have received less than `amount`.\n // This is a very niche edge case and should be handled by the recipient contract.\n _checkedCallRecipient({recipient: to, token: token, amount: amount, callParams: transaction.callParams});\n } else if (msg.value != 0) {\n // No arbitrary call requested, but msg.value was sent. This is either a relay with ETH,\n // or a non-zero callValue request with an ERC20. In both cases, transfer the ETH to the recipient.\n Address.sendValue(payable(to), msg.value);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) public onlyRole(RELAYER_ROLE) {\n // update bridge tx status given proof provided\n if (bridgeTxDetails[transactionId].status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n bridgeTxDetails[transactionId].status = BridgeStatus.RELAYER_PROVED;\n bridgeTxDetails[transactionId].proofBlockTimestamp = uint40(block.timestamp);\n bridgeTxDetails[transactionId].proofBlockNumber = uint48(block.number);\n bridgeTxDetails[transactionId].proofRelayer = relayer;\n\n emit BridgeProofProvided(transactionId, relayer, destTxHash);\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes memory request, address to) public {\n bytes32 transactionId = keccak256(request);\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n\n // update bridge tx status if able to claim origin collateral\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n\n // if \"to\" is zero addr, permissionlessly send funds to proven relayer\n if (to == address(0)) {\n to = bridgeTxDetails[transactionId].proofRelayer;\n } else if (bridgeTxDetails[transactionId].proofRelayer != msg.sender) {\n revert SenderIncorrect();\n }\n\n if (_timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003c= DISPUTE_PERIOD) {\n revert DisputePeriodNotPassed();\n }\n\n bridgeTxDetails[transactionId].status = BridgeStatus.RELAYER_CLAIMED;\n\n // update protocol fees if origin fee amount exists\n if (transaction.originFeeAmount \u003e 0) protocolFees[transaction.originToken] += transaction.originFeeAmount;\n\n // transfer origin collateral less fee to specified address\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositClaimed(transactionId, bridgeTxDetails[transactionId].proofRelayer, to, token, amount);\n }\n\n function bridgeStatuses(bytes32 transactionId) public view returns (BridgeStatus status) {\n return bridgeTxDetails[transactionId].status;\n }\n\n function bridgeProofs(bytes32 transactionId) public view returns (uint96 timestamp, address relayer) {\n timestamp = bridgeTxDetails[transactionId].proofBlockTimestamp;\n relayer = bridgeTxDetails[transactionId].proofRelayer;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeRelays(bytes32 transactionId) public view returns (bool) {\n // has this transactionId been relayed?\n return bridgeRelayDetails[transactionId].relayer != address(0);\n }\n\n /// @inheritdoc IFastBridgeV2\n function getBridgeTransactionV2(bytes memory request) public pure returns (BridgeTransactionV2 memory) {\n return abi.decode(request, (BridgeTransactionV2));\n }\n\n /// @notice Takes the bridged asset from the user into FastBridgeV2 custody. It will be later\n /// claimed by the relayer who completed the relay on destination chain, or refunded back to the user,\n /// should no one complete the relay.\n function _takeBridgedUserAsset(address token, uint256 amount) internal returns (uint256 amountTaken) {\n if (token == UniversalTokenLib.ETH_ADDRESS) {\n // For ETH we just need to check that the supplied msg.value is correct.\n // Supplied `msg.value` is already in FastBridgeV2 custody.\n if (amount != msg.value) revert MsgValueIncorrect();\n amountTaken = msg.value;\n } else {\n // For ERC20s, token is explicitly transferred from the user to FastBridgeV2.\n // We don't allow non-zero `msg.value` to avoid extra funds from being stuck in FastBridgeV2.\n token.assertIsContract();\n if (msg.value != 0) revert MsgValueIncorrect();\n amountTaken = IERC20(token).balanceOf(address(this));\n IERC20(token).safeTransferFrom(msg.sender, address(this), amount);\n // Use the balance difference as the amount taken in case of fee on transfer tokens.\n amountTaken = IERC20(token).balanceOf(address(this)) - amountTaken;\n }\n }\n\n /// @notice Calls the Recipient's hook function with the specified callParams and performs\n /// all the necessary checks for the returned value.\n function _checkedCallRecipient(\n address recipient,\n address token,\n uint256 amount,\n bytes memory callParams\n )\n internal\n {\n bytes memory hookData =\n abi.encodeCall(IFastBridgeRecipient.fastBridgeTransferReceived, (token, amount, callParams));\n // This will bubble any revert messages from the hook function\n bytes memory returnData = Address.functionCallWithValue({target: recipient, data: hookData, value: msg.value});\n // Explicit revert if no return data at all\n if (returnData.length == 0) revert RecipientNoReturnValue();\n // Check that exactly a single return value was returned\n if (returnData.length != 32) revert RecipientIncorrectReturnValue();\n // Return value should be abi-encoded hook function selector\n if (bytes32(returnData) != bytes32(IFastBridgeRecipient.fastBridgeTransferReceived.selector)) {\n revert RecipientIncorrectReturnValue();\n }\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint40(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint40).max but\n /// proof.timestamp \u003c type(uint40).max via unchecked statement\n /// @param proofBlockTimestamp The bridge proof block timestamp\n /// @return delta Time delta since proof submitted\n function _timeSince(uint40 proofBlockTimestamp) internal view returns (uint256 delta) {\n unchecked {\n delta = uint40(block.timestamp) - proofBlockTimestamp;\n }\n }\n\n /// @notice Performs all the necessary checks for a bridge to happen.\n /// @dev There's no good way to refactor this function to reduce cyclomatic complexity due to\n /// the number of checks that need to be performed, so we skip the code-complexity rule here.\n // solhint-disable-next-line code-complexity\n function _validateBridgeParams(\n BridgeParams memory params,\n BridgeParamsV2 memory paramsV2,\n int256 exclusivityEndTime\n )\n internal\n view\n {\n // Check V1 (legacy) params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.sender == address(0) || params.to == address(0)) revert ZeroAddress();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n // Check V2 params\n if (paramsV2.callParams.length \u003e MAX_CALL_PARAMS_LENGTH) revert CallParamsLengthAboveMax();\n if (paramsV2.callValue != 0 \u0026\u0026 params.destToken == UniversalTokenLib.ETH_ADDRESS) {\n revert NativeTokenCallValueNotSupported();\n }\n // exclusivityEndTime must be in range (0 .. params.deadline]\n if (exclusivityEndTime \u003c= 0 || exclusivityEndTime \u003e int256(params.deadline)) {\n revert ExclusivityParamsIncorrect();\n }\n }\n\n /// @notice Performs all the necessary checks for a relay to happen.\n function _validateRelayParams(\n BridgeTransactionV2 memory transaction,\n bytes32 transactionId,\n address relayer\n )\n internal\n view\n {\n if (relayer == address(0)) revert ZeroAddress();\n // Check if the transaction has already been relayed\n if (bridgeRelays(transactionId)) revert TransactionRelayed();\n if (transaction.destChainId != block.chainid) revert ChainIncorrect();\n // Check the deadline for relay to happen\n if (block.timestamp \u003e transaction.deadline) revert DeadlineExceeded();\n // Check the exclusivity period, if it is still ongoing\n // forgefmt: disable-next-item\n if (\n transaction.exclusivityRelayer != address(0) \u0026\u0026\n transaction.exclusivityRelayer != relayer \u0026\u0026\n block.timestamp \u003c= transaction.exclusivityEndTime\n ) {\n revert ExclusivityPeriodNotPassed();\n }\n }\n}\n","language":"Solidity","languageVersion":"0.8.24","compilerVersion":"0.8.24","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"","srcMapRuntime":"","abiDefinition":[],"userDoc":{"kind":"user","methods":{},"version":1},"developerDoc":{"details":"Provides information about the current execution context, including the sender of the transaction and its data. While these are generally available via msg.sender and msg.data, they should not be accessed in such a direct manner, since when dealing with meta-transactions the account sending and paying for execution may not be the actual sender (as far as an application is concerned). This contract is only required for intermediate, library-like contracts.","kind":"dev","methods":{},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[],\"devdoc\":{\"details\":\"Provides information about the current execution context, including the sender of the transaction and its data. While these are generally available via msg.sender and msg.data, they should not be accessed in such a direct manner, since when dealing with meta-transactions the account sending and paying for execution may not be the actual sender (as far as an application is concerned). This contract is only required for intermediate, library-like contracts.\",\"kind\":\"dev\",\"methods\":{},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeV2.sol\":\"Context\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeV2.sol\":{\"keccak256\":\"0xfd916c030b1ffca5a136817827b8018c8ba42ca089905747f3de6148b73eb35e\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://18e6438c4096deb8ae453fb3365ba2b07d52944e93c08288fc5d012b71bf6bb3\",\"dweb:/ipfs/QmfEMqpT1zz6RRm7UuHLRowe1tds2cTGLrVonfm9XSCACj\"]}},\"version\":1}"},"hashes":{}},"solidity/FastBridgeV2.sol:ERC165":{"code":"0x","runtime-code":"0x","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.24 ^0.8.0 ^0.8.20;\n\n// contracts/interfaces/IAdmin.sol\n\ninterface IAdmin {\n // ============ Events ============\n\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n event ChainGasAmountUpdated(uint256 oldChainGasAmount, uint256 newChainGasAmount);\n\n // ============ Methods ============\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n\n function setChainGasAmount(uint256 newChainGasAmount) external;\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IFastBridgeRecipient.sol\n\ninterface IFastBridgeRecipient {\n function fastBridgeTransferReceived(\n address token,\n uint256 amount,\n bytes memory callParams\n )\n external\n payable\n returns (bytes4);\n}\n\n// contracts/interfaces/IFastBridgeV2Errors.sol\n\ninterface IFastBridgeV2Errors {\n error AmountIncorrect();\n error CallParamsLengthAboveMax();\n error ChainIncorrect();\n error ExclusivityParamsIncorrect();\n error MsgValueIncorrect();\n error NativeTokenCallValueNotSupported();\n error SenderIncorrect();\n error StatusIncorrect();\n error ZeroAddress();\n\n error RecipientIncorrectReturnValue();\n error RecipientNoReturnValue();\n\n error DeadlineExceeded();\n error DeadlineNotExceeded();\n error DeadlineTooShort();\n error DisputePeriodNotPassed();\n error DisputePeriodPassed();\n error ExclusivityPeriodNotPassed();\n\n error TransactionRelayed();\n}\n\n// contracts/libs/Errors.sol\n\nerror DeadlineExceeded();\nerror DeadlineNotExceeded();\nerror DeadlineTooShort();\nerror InsufficientOutputAmount();\n\nerror MsgValueIncorrect();\nerror PoolNotFound();\nerror TokenAddressMismatch();\nerror TokenNotContract();\nerror TokenNotETH();\nerror TokensIdentical();\n\nerror ChainIncorrect();\nerror AmountIncorrect();\nerror ZeroAddress();\n\nerror DisputePeriodNotPassed();\nerror DisputePeriodPassed();\nerror SenderIncorrect();\nerror StatusIncorrect();\nerror TransactionIdIncorrect();\nerror TransactionRelayed();\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// contracts/interfaces/IFastBridgeV2.sol\n\ninterface IFastBridgeV2 is IFastBridge {\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n struct BridgeTxDetails {\n BridgeStatus status;\n uint40 proofBlockTimestamp;\n uint48 proofBlockNumber;\n address proofRelayer;\n }\n\n struct BridgeRelay {\n uint48 blockNumber;\n uint48 blockTimestamp;\n address relayer;\n }\n\n /// @notice New params introduced in the FastBridgeV2.\n /// We are passing fields from the older BridgeParams struct outside of this struct\n /// for backwards compatibility.\n /// Note: quoteRelayer and quoteExclusivitySeconds are either both zero (indicating no exclusivity)\n /// or both non-zero (indicating exclusivity for the given period).\n /// Note: callValue \u003e 0 can NOT be used with destToken = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE (ETH_ADDRESS)\n /// @param quoteRelayer Relayer that provided the quote for the transaction\n /// @param quoteExclusivitySeconds Period of time the quote relayer is guaranteed exclusivity after user's deposit\n /// @param quoteId Unique quote identifier used for tracking the quote\n /// @param callValue ETH value to send to the recipient (if any)\n /// @param callParams Parameters for the arbitrary call to the destination recipient (if any)\n struct BridgeParamsV2 {\n address quoteRelayer;\n int256 quoteExclusivitySeconds;\n bytes quoteId;\n uint256 callValue;\n bytes callParams;\n }\n\n /// @notice Updated bridge transaction struct to include parameters introduced in FastBridgeV2.\n /// Note: only `exclusivityRelayer` can fill such a transaction until `exclusivityEndTime`.\n /// TODO: consider changing the encoding scheme to prevent spending extra gas on decoding.\n struct BridgeTransactionV2 {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n uint256 callValue; // ETH value to send to the recipient (if any) - replaces V1's sendChainGas flag\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n address exclusivityRelayer;\n uint256 exclusivityEndTime;\n bytes callParams;\n }\n\n event BridgeQuoteDetails(bytes32 indexed transactionId, bytes quoteId);\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability\n /// to provide temporary exclusivity fill rights for the quote relayer.\n /// @param params The parameters required to bridge\n /// @param paramsV2 The parameters for exclusivity fill rights (optional, can be left empty)\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function relay(bytes memory request, address relayer) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param transactionId The transaction id associated with the encoded bridge transaction to prove\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital.\n /// @notice Can only send funds to the relayer address on the proof.\n /// @param request The encoded bridge transaction to claim on origin chain\n function claim(bytes memory request) external;\n /// @notice Checks if a transaction has been relayed\n /// @param transactionId The ID of the transaction to check\n /// @return True if the transaction has been relayed, false otherwise\n function bridgeRelays(bytes32 transactionId) external view returns (bool);\n\n /// @notice Returns the status of a bridge transaction\n /// @param transactionId The ID of the bridge transaction\n /// @return BridgeStatus Status of the bridge transaction\n function bridgeStatuses(bytes32 transactionId) external view returns (BridgeStatus);\n\n /// @notice Returns the timestamp and relayer of a bridge proof\n /// @param transactionId The ID of the bridge transaction\n /// @return timestamp The timestamp of the bridge proof\n /// @return relayer The relayer address of the bridge proof\n function bridgeProofs(bytes32 transactionId) external view returns (uint96 timestamp, address relayer);\n\n /// @notice Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\n /// @param request The bridge request to decode\n function getBridgeTransactionV2(bytes memory request) external view returns (BridgeTransactionV2 memory);\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// contracts/libs/UniversalToken.sol\n\nlibrary UniversalTokenLib {\n using SafeERC20 for IERC20;\n\n address internal constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Transfers tokens to the given account. Reverts if transfer is not successful.\n /// @dev This might trigger fallback, if ETH is transferred to the contract.\n /// Make sure this can not lead to reentrancy attacks.\n function universalTransfer(address token, address to, uint256 value) internal {\n // Don't do anything, if need to send tokens to this address\n if (to == address(this)) return;\n // Don't do anything, if trying to send zero value\n if (value == 0) return;\n if (token == ETH_ADDRESS) {\n /// @dev Note: this can potentially lead to executing code in `to`.\n // solhint-disable-next-line avoid-low-level-calls\n (bool success,) = to.call{value: value}(\"\");\n require(success, \"ETH transfer failed\");\n } else {\n IERC20(token).safeTransfer(to, value);\n }\n }\n\n /// @notice Issues an infinite allowance to the spender, if the current allowance is insufficient\n /// to spend the given amount.\n function universalApproveInfinity(address token, address spender, uint256 amountToSpend) internal {\n // ETH Chad doesn't require your approval\n if (token == ETH_ADDRESS) return;\n // No-op if allowance is already sufficient\n uint256 allowance = IERC20(token).allowance(address(this), spender);\n if (allowance \u003e= amountToSpend) return;\n // Otherwise, reset approval to 0 and set to max allowance\n if (allowance \u003e 0) IERC20(token).safeDecreaseAllowance(spender, allowance);\n IERC20(token).safeIncreaseAllowance(spender, type(uint256).max);\n }\n\n /// @notice Returns the balance of the given token (or native ETH) for the given account.\n function universalBalanceOf(address token, address account) internal view returns (uint256) {\n if (token == ETH_ADDRESS) {\n return account.balance;\n } else {\n return IERC20(token).balanceOf(account);\n }\n }\n\n /// @dev Checks that token is a contract and not ETH_ADDRESS.\n function assertIsContract(address token) internal view {\n // Check that ETH_ADDRESS was not used (in case this is a predeploy on any of the chains)\n if (token == UniversalTokenLib.ETH_ADDRESS) revert TokenNotContract();\n // Check that token is not an EOA\n if (token.code.length == 0) revert TokenNotContract();\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/Admin.sol\n\ncontract Admin is IAdmin, AccessControlEnumerable {\n using UniversalTokenLib for address;\n\n bytes32 public constant RELAYER_ROLE = keccak256(\"RELAYER_ROLE\");\n bytes32 public constant REFUNDER_ROLE = keccak256(\"REFUNDER_ROLE\");\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n uint256 public constant FEE_BPS = 1e6;\n uint256 public constant FEE_RATE_MAX = 0.01e6; // max 1% on origin amount\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Chain gas amount to forward as rebate if requested\n uint256 public chainGasAmount;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n }\n\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n require(newFeeRate \u003c= FEE_RATE_MAX, \"newFeeRate \u003e max\");\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n token.universalTransfer(recipient, feeAmount);\n emit FeesSwept(token, recipient, feeAmount);\n }\n\n function setChainGasAmount(uint256 newChainGasAmount) external onlyRole(GOVERNOR_ROLE) {\n uint256 oldChainGasAmount = chainGasAmount;\n chainGasAmount = newChainGasAmount;\n emit ChainGasAmountUpdated(oldChainGasAmount, newChainGasAmount);\n }\n}\n\n// contracts/FastBridgeV2.sol\n\n/// @notice FastBridgeV2 is a contract for bridging tokens across chains.\ncontract FastBridgeV2 is Admin, IFastBridgeV2, IFastBridgeV2Errors {\n using SafeERC20 for IERC20;\n using UniversalTokenLib for address;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Delay for a transaction after which it could be permisionlessly refunded\n uint256 public constant REFUND_DELAY = 7 days;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n /// @notice Maximum length of accepted callParams\n uint256 public constant MAX_CALL_PARAMS_LENGTH = 2 ** 16 - 1;\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeTxDetails) public bridgeTxDetails;\n /// @notice Relay details on destination chain\n mapping(bytes32 =\u003e BridgeRelay) public bridgeRelayDetails;\n /// @notice Unique bridge nonces tracked per originSender\n mapping(address =\u003e uint256) public senderNonces;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Replaced by senderNonces\n uint256 public immutable nonce = 0;\n /// @notice the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n bridge({\n params: params,\n paramsV2: BridgeParamsV2({\n quoteRelayer: address(0),\n quoteExclusivitySeconds: 0,\n quoteId: bytes(\"\"),\n callValue: 0,\n callParams: bytes(\"\")\n })\n });\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes memory request) external payable {\n relay({request: request, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes memory request, bytes32 destTxHash) external {\n prove({transactionId: keccak256(request), destTxHash: destTxHash, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridgeV2\n function claim(bytes memory request) external {\n claim({request: request, to: address(0)});\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003e DISPUTE_PERIOD) {\n revert DisputePeriodPassed();\n }\n\n // @dev relayer gets slashed effectively if dest relay has gone thru\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n bridgeTxDetails[transactionId].proofRelayer = address(0);\n bridgeTxDetails[transactionId].proofBlockTimestamp = 0;\n bridgeTxDetails[transactionId].proofBlockNumber = 0;\n\n emit BridgeProofDisputed(transactionId, msg.sender);\n }\n\n /// @inheritdoc IFastBridge\n function refund(bytes memory request) external {\n bytes32 transactionId = keccak256(request);\n\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n\n if (bridgeTxDetails[transactionId].status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n\n if (hasRole(REFUNDER_ROLE, msg.sender)) {\n // Refunder can refund if deadline has passed\n if (block.timestamp \u003c= transaction.deadline) revert DeadlineNotExceeded();\n } else {\n // Permissionless refund is allowed after REFUND_DELAY\n if (block.timestamp \u003c= transaction.deadline + REFUND_DELAY) revert DeadlineNotExceeded();\n }\n\n // if all checks passed, set to REFUNDED status\n bridgeTxDetails[transactionId].status = BridgeStatus.REFUNDED;\n\n // transfer origin collateral back to original sender\n address to = transaction.originSender;\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount + transaction.originFeeAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (bridgeTxDetails[transactionId].proofRelayer != relayer) revert SenderIncorrect();\n return _timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n /// @dev This method is added to achieve backwards compatibility with decoding requests into V1 structs:\n /// - `callValue` is partially reported as a zero/non-zero flag\n /// - `callParams` is ignored\n /// In order to process all kinds of requests use getBridgeTransactionV2 instead.\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory) {\n // Try decoding into V2 struct first. This will revert if V1 struct is passed\n try this.getBridgeTransactionV2(request) returns (BridgeTransactionV2 memory txV2) {\n // Note: we entirely ignore the callParams field, as it was not present in V1\n return BridgeTransaction({\n originChainId: txV2.originChainId,\n destChainId: txV2.destChainId,\n originSender: txV2.originSender,\n destRecipient: txV2.destRecipient,\n originToken: txV2.originToken,\n destToken: txV2.destToken,\n originAmount: txV2.originAmount,\n destAmount: txV2.destAmount,\n originFeeAmount: txV2.originFeeAmount,\n sendChainGas: txV2.callValue != 0,\n deadline: txV2.deadline,\n nonce: txV2.nonce\n });\n } catch {\n // Fallback to V1 struct\n return abi.decode(request, (BridgeTransaction));\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) public payable {\n int256 exclusivityEndTime = int256(block.timestamp) + paramsV2.quoteExclusivitySeconds;\n _validateBridgeParams(params, paramsV2, exclusivityEndTime);\n\n // transfer tokens to bridge contract\n /// @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _takeBridgedUserAsset(params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n\n // set status to requested\n bytes memory request = abi.encode(\n BridgeTransactionV2({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n callValue: paramsV2.callValue,\n deadline: params.deadline,\n nonce: senderNonces[params.sender]++, // increment nonce on every bridge\n exclusivityRelayer: paramsV2.quoteRelayer,\n // We checked exclusivityEndTime to be in range (0 .. params.deadline] above, so can safely cast\n exclusivityEndTime: uint256(exclusivityEndTime),\n callParams: paramsV2.callParams\n })\n );\n bytes32 transactionId = keccak256(request);\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n\n emit BridgeRequested({\n transactionId: transactionId,\n sender: params.sender,\n request: request,\n destChainId: params.dstChainId,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n sendChainGas: paramsV2.callValue != 0\n });\n emit BridgeQuoteDetails(transactionId, paramsV2.quoteId);\n }\n\n /// @inheritdoc IFastBridgeV2\n function relay(bytes memory request, address relayer) public payable {\n bytes32 transactionId = keccak256(request);\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n _validateRelayParams(transaction, transactionId, relayer);\n // mark bridge transaction as relayed\n bridgeRelayDetails[transactionId] =\n BridgeRelay({blockNumber: uint48(block.number), blockTimestamp: uint48(block.timestamp), relayer: relayer});\n\n // transfer tokens to recipient on destination chain and do an arbitrary call if requested\n address to = transaction.destRecipient;\n address token = transaction.destToken;\n uint256 amount = transaction.destAmount;\n uint256 callValue = transaction.callValue;\n\n // Emit the event before any external calls\n emit BridgeRelayed({\n transactionId: transactionId,\n relayer: relayer,\n to: to,\n originChainId: transaction.originChainId,\n originToken: transaction.originToken,\n destToken: token,\n originAmount: transaction.originAmount,\n destAmount: amount,\n chainGasAmount: callValue\n });\n\n // All state changes have been done at this point, can proceed to the external calls.\n // This follows the checks-effects-interactions pattern to mitigate potential reentrancy attacks.\n if (token == UniversalTokenLib.ETH_ADDRESS) {\n // For ETH non-zero callValue is not allowed\n if (callValue != 0) revert NativeTokenCallValueNotSupported();\n // Check that the correct msg.value was sent\n if (msg.value != amount) revert MsgValueIncorrect();\n } else {\n // For ERC20s, we check that the correct msg.value was sent\n if (msg.value != callValue) revert MsgValueIncorrect();\n // We need to transfer the tokens from the Relayer to the recipient first before performing an\n // optional post-transfer arbitrary call.\n IERC20(token).safeTransferFrom(msg.sender, to, amount);\n }\n\n if (transaction.callParams.length != 0) {\n // Arbitrary call requested, perform it while supplying full msg.value to the recipient\n // Note: if token has a fee on transfers, the recipient will have received less than `amount`.\n // This is a very niche edge case and should be handled by the recipient contract.\n _checkedCallRecipient({recipient: to, token: token, amount: amount, callParams: transaction.callParams});\n } else if (msg.value != 0) {\n // No arbitrary call requested, but msg.value was sent. This is either a relay with ETH,\n // or a non-zero callValue request with an ERC20. In both cases, transfer the ETH to the recipient.\n Address.sendValue(payable(to), msg.value);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) public onlyRole(RELAYER_ROLE) {\n // update bridge tx status given proof provided\n if (bridgeTxDetails[transactionId].status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n bridgeTxDetails[transactionId].status = BridgeStatus.RELAYER_PROVED;\n bridgeTxDetails[transactionId].proofBlockTimestamp = uint40(block.timestamp);\n bridgeTxDetails[transactionId].proofBlockNumber = uint48(block.number);\n bridgeTxDetails[transactionId].proofRelayer = relayer;\n\n emit BridgeProofProvided(transactionId, relayer, destTxHash);\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes memory request, address to) public {\n bytes32 transactionId = keccak256(request);\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n\n // update bridge tx status if able to claim origin collateral\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n\n // if \"to\" is zero addr, permissionlessly send funds to proven relayer\n if (to == address(0)) {\n to = bridgeTxDetails[transactionId].proofRelayer;\n } else if (bridgeTxDetails[transactionId].proofRelayer != msg.sender) {\n revert SenderIncorrect();\n }\n\n if (_timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003c= DISPUTE_PERIOD) {\n revert DisputePeriodNotPassed();\n }\n\n bridgeTxDetails[transactionId].status = BridgeStatus.RELAYER_CLAIMED;\n\n // update protocol fees if origin fee amount exists\n if (transaction.originFeeAmount \u003e 0) protocolFees[transaction.originToken] += transaction.originFeeAmount;\n\n // transfer origin collateral less fee to specified address\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositClaimed(transactionId, bridgeTxDetails[transactionId].proofRelayer, to, token, amount);\n }\n\n function bridgeStatuses(bytes32 transactionId) public view returns (BridgeStatus status) {\n return bridgeTxDetails[transactionId].status;\n }\n\n function bridgeProofs(bytes32 transactionId) public view returns (uint96 timestamp, address relayer) {\n timestamp = bridgeTxDetails[transactionId].proofBlockTimestamp;\n relayer = bridgeTxDetails[transactionId].proofRelayer;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeRelays(bytes32 transactionId) public view returns (bool) {\n // has this transactionId been relayed?\n return bridgeRelayDetails[transactionId].relayer != address(0);\n }\n\n /// @inheritdoc IFastBridgeV2\n function getBridgeTransactionV2(bytes memory request) public pure returns (BridgeTransactionV2 memory) {\n return abi.decode(request, (BridgeTransactionV2));\n }\n\n /// @notice Takes the bridged asset from the user into FastBridgeV2 custody. It will be later\n /// claimed by the relayer who completed the relay on destination chain, or refunded back to the user,\n /// should no one complete the relay.\n function _takeBridgedUserAsset(address token, uint256 amount) internal returns (uint256 amountTaken) {\n if (token == UniversalTokenLib.ETH_ADDRESS) {\n // For ETH we just need to check that the supplied msg.value is correct.\n // Supplied `msg.value` is already in FastBridgeV2 custody.\n if (amount != msg.value) revert MsgValueIncorrect();\n amountTaken = msg.value;\n } else {\n // For ERC20s, token is explicitly transferred from the user to FastBridgeV2.\n // We don't allow non-zero `msg.value` to avoid extra funds from being stuck in FastBridgeV2.\n token.assertIsContract();\n if (msg.value != 0) revert MsgValueIncorrect();\n amountTaken = IERC20(token).balanceOf(address(this));\n IERC20(token).safeTransferFrom(msg.sender, address(this), amount);\n // Use the balance difference as the amount taken in case of fee on transfer tokens.\n amountTaken = IERC20(token).balanceOf(address(this)) - amountTaken;\n }\n }\n\n /// @notice Calls the Recipient's hook function with the specified callParams and performs\n /// all the necessary checks for the returned value.\n function _checkedCallRecipient(\n address recipient,\n address token,\n uint256 amount,\n bytes memory callParams\n )\n internal\n {\n bytes memory hookData =\n abi.encodeCall(IFastBridgeRecipient.fastBridgeTransferReceived, (token, amount, callParams));\n // This will bubble any revert messages from the hook function\n bytes memory returnData = Address.functionCallWithValue({target: recipient, data: hookData, value: msg.value});\n // Explicit revert if no return data at all\n if (returnData.length == 0) revert RecipientNoReturnValue();\n // Check that exactly a single return value was returned\n if (returnData.length != 32) revert RecipientIncorrectReturnValue();\n // Return value should be abi-encoded hook function selector\n if (bytes32(returnData) != bytes32(IFastBridgeRecipient.fastBridgeTransferReceived.selector)) {\n revert RecipientIncorrectReturnValue();\n }\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint40(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint40).max but\n /// proof.timestamp \u003c type(uint40).max via unchecked statement\n /// @param proofBlockTimestamp The bridge proof block timestamp\n /// @return delta Time delta since proof submitted\n function _timeSince(uint40 proofBlockTimestamp) internal view returns (uint256 delta) {\n unchecked {\n delta = uint40(block.timestamp) - proofBlockTimestamp;\n }\n }\n\n /// @notice Performs all the necessary checks for a bridge to happen.\n /// @dev There's no good way to refactor this function to reduce cyclomatic complexity due to\n /// the number of checks that need to be performed, so we skip the code-complexity rule here.\n // solhint-disable-next-line code-complexity\n function _validateBridgeParams(\n BridgeParams memory params,\n BridgeParamsV2 memory paramsV2,\n int256 exclusivityEndTime\n )\n internal\n view\n {\n // Check V1 (legacy) params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.sender == address(0) || params.to == address(0)) revert ZeroAddress();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n // Check V2 params\n if (paramsV2.callParams.length \u003e MAX_CALL_PARAMS_LENGTH) revert CallParamsLengthAboveMax();\n if (paramsV2.callValue != 0 \u0026\u0026 params.destToken == UniversalTokenLib.ETH_ADDRESS) {\n revert NativeTokenCallValueNotSupported();\n }\n // exclusivityEndTime must be in range (0 .. params.deadline]\n if (exclusivityEndTime \u003c= 0 || exclusivityEndTime \u003e int256(params.deadline)) {\n revert ExclusivityParamsIncorrect();\n }\n }\n\n /// @notice Performs all the necessary checks for a relay to happen.\n function _validateRelayParams(\n BridgeTransactionV2 memory transaction,\n bytes32 transactionId,\n address relayer\n )\n internal\n view\n {\n if (relayer == address(0)) revert ZeroAddress();\n // Check if the transaction has already been relayed\n if (bridgeRelays(transactionId)) revert TransactionRelayed();\n if (transaction.destChainId != block.chainid) revert ChainIncorrect();\n // Check the deadline for relay to happen\n if (block.timestamp \u003e transaction.deadline) revert DeadlineExceeded();\n // Check the exclusivity period, if it is still ongoing\n // forgefmt: disable-next-item\n if (\n transaction.exclusivityRelayer != address(0) \u0026\u0026\n transaction.exclusivityRelayer != relayer \u0026\u0026\n block.timestamp \u003c= transaction.exclusivityEndTime\n ) {\n revert ExclusivityPeriodNotPassed();\n }\n }\n}\n","language":"Solidity","languageVersion":"0.8.24","compilerVersion":"0.8.24","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"","srcMapRuntime":"","abiDefinition":[{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"}],"userDoc":{"kind":"user","methods":{},"version":1},"developerDoc":{"details":"Implementation of the {IERC165} interface. Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check for the additional interface id that will be supported. For example: ```solidity function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId); } ```","kind":"dev","methods":{"supportsInterface(bytes4)":{"details":"See {IERC165-supportsInterface}."}},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"bytes4\",\"name\":\"interfaceId\",\"type\":\"bytes4\"}],\"name\":\"supportsInterface\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"}],\"devdoc\":{\"details\":\"Implementation of the {IERC165} interface. Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check for the additional interface id that will be supported. For example: ```solidity function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId); } ```\",\"kind\":\"dev\",\"methods\":{\"supportsInterface(bytes4)\":{\"details\":\"See {IERC165-supportsInterface}.\"}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeV2.sol\":\"ERC165\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeV2.sol\":{\"keccak256\":\"0xfd916c030b1ffca5a136817827b8018c8ba42ca089905747f3de6148b73eb35e\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://18e6438c4096deb8ae453fb3365ba2b07d52944e93c08288fc5d012b71bf6bb3\",\"dweb:/ipfs/QmfEMqpT1zz6RRm7UuHLRowe1tds2cTGLrVonfm9XSCACj\"]}},\"version\":1}"},"hashes":{"supportsInterface(bytes4)":"01ffc9a7"}},"solidity/FastBridgeV2.sol:EnumerableSet":{"code":"0x60566037600b82828239805160001a607314602a57634e487b7160e01b600052600060045260246000fd5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600080fdfea264697066735822122096938e347a6ad7c9db19e62e3fe085fcb6b4b02d667bfa2b5db09e30538dd3cd64736f6c63430008180033","runtime-code":"0x73000000000000000000000000000000000000000030146080604052600080fdfea264697066735822122096938e347a6ad7c9db19e62e3fe085fcb6b4b02d667bfa2b5db09e30538dd3cd64736f6c63430008180033","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.24 ^0.8.0 ^0.8.20;\n\n// contracts/interfaces/IAdmin.sol\n\ninterface IAdmin {\n // ============ Events ============\n\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n event ChainGasAmountUpdated(uint256 oldChainGasAmount, uint256 newChainGasAmount);\n\n // ============ Methods ============\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n\n function setChainGasAmount(uint256 newChainGasAmount) external;\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IFastBridgeRecipient.sol\n\ninterface IFastBridgeRecipient {\n function fastBridgeTransferReceived(\n address token,\n uint256 amount,\n bytes memory callParams\n )\n external\n payable\n returns (bytes4);\n}\n\n// contracts/interfaces/IFastBridgeV2Errors.sol\n\ninterface IFastBridgeV2Errors {\n error AmountIncorrect();\n error CallParamsLengthAboveMax();\n error ChainIncorrect();\n error ExclusivityParamsIncorrect();\n error MsgValueIncorrect();\n error NativeTokenCallValueNotSupported();\n error SenderIncorrect();\n error StatusIncorrect();\n error ZeroAddress();\n\n error RecipientIncorrectReturnValue();\n error RecipientNoReturnValue();\n\n error DeadlineExceeded();\n error DeadlineNotExceeded();\n error DeadlineTooShort();\n error DisputePeriodNotPassed();\n error DisputePeriodPassed();\n error ExclusivityPeriodNotPassed();\n\n error TransactionRelayed();\n}\n\n// contracts/libs/Errors.sol\n\nerror DeadlineExceeded();\nerror DeadlineNotExceeded();\nerror DeadlineTooShort();\nerror InsufficientOutputAmount();\n\nerror MsgValueIncorrect();\nerror PoolNotFound();\nerror TokenAddressMismatch();\nerror TokenNotContract();\nerror TokenNotETH();\nerror TokensIdentical();\n\nerror ChainIncorrect();\nerror AmountIncorrect();\nerror ZeroAddress();\n\nerror DisputePeriodNotPassed();\nerror DisputePeriodPassed();\nerror SenderIncorrect();\nerror StatusIncorrect();\nerror TransactionIdIncorrect();\nerror TransactionRelayed();\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// contracts/interfaces/IFastBridgeV2.sol\n\ninterface IFastBridgeV2 is IFastBridge {\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n struct BridgeTxDetails {\n BridgeStatus status;\n uint40 proofBlockTimestamp;\n uint48 proofBlockNumber;\n address proofRelayer;\n }\n\n struct BridgeRelay {\n uint48 blockNumber;\n uint48 blockTimestamp;\n address relayer;\n }\n\n /// @notice New params introduced in the FastBridgeV2.\n /// We are passing fields from the older BridgeParams struct outside of this struct\n /// for backwards compatibility.\n /// Note: quoteRelayer and quoteExclusivitySeconds are either both zero (indicating no exclusivity)\n /// or both non-zero (indicating exclusivity for the given period).\n /// Note: callValue \u003e 0 can NOT be used with destToken = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE (ETH_ADDRESS)\n /// @param quoteRelayer Relayer that provided the quote for the transaction\n /// @param quoteExclusivitySeconds Period of time the quote relayer is guaranteed exclusivity after user's deposit\n /// @param quoteId Unique quote identifier used for tracking the quote\n /// @param callValue ETH value to send to the recipient (if any)\n /// @param callParams Parameters for the arbitrary call to the destination recipient (if any)\n struct BridgeParamsV2 {\n address quoteRelayer;\n int256 quoteExclusivitySeconds;\n bytes quoteId;\n uint256 callValue;\n bytes callParams;\n }\n\n /// @notice Updated bridge transaction struct to include parameters introduced in FastBridgeV2.\n /// Note: only `exclusivityRelayer` can fill such a transaction until `exclusivityEndTime`.\n /// TODO: consider changing the encoding scheme to prevent spending extra gas on decoding.\n struct BridgeTransactionV2 {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n uint256 callValue; // ETH value to send to the recipient (if any) - replaces V1's sendChainGas flag\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n address exclusivityRelayer;\n uint256 exclusivityEndTime;\n bytes callParams;\n }\n\n event BridgeQuoteDetails(bytes32 indexed transactionId, bytes quoteId);\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability\n /// to provide temporary exclusivity fill rights for the quote relayer.\n /// @param params The parameters required to bridge\n /// @param paramsV2 The parameters for exclusivity fill rights (optional, can be left empty)\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function relay(bytes memory request, address relayer) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param transactionId The transaction id associated with the encoded bridge transaction to prove\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital.\n /// @notice Can only send funds to the relayer address on the proof.\n /// @param request The encoded bridge transaction to claim on origin chain\n function claim(bytes memory request) external;\n /// @notice Checks if a transaction has been relayed\n /// @param transactionId The ID of the transaction to check\n /// @return True if the transaction has been relayed, false otherwise\n function bridgeRelays(bytes32 transactionId) external view returns (bool);\n\n /// @notice Returns the status of a bridge transaction\n /// @param transactionId The ID of the bridge transaction\n /// @return BridgeStatus Status of the bridge transaction\n function bridgeStatuses(bytes32 transactionId) external view returns (BridgeStatus);\n\n /// @notice Returns the timestamp and relayer of a bridge proof\n /// @param transactionId The ID of the bridge transaction\n /// @return timestamp The timestamp of the bridge proof\n /// @return relayer The relayer address of the bridge proof\n function bridgeProofs(bytes32 transactionId) external view returns (uint96 timestamp, address relayer);\n\n /// @notice Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\n /// @param request The bridge request to decode\n function getBridgeTransactionV2(bytes memory request) external view returns (BridgeTransactionV2 memory);\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// contracts/libs/UniversalToken.sol\n\nlibrary UniversalTokenLib {\n using SafeERC20 for IERC20;\n\n address internal constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Transfers tokens to the given account. Reverts if transfer is not successful.\n /// @dev This might trigger fallback, if ETH is transferred to the contract.\n /// Make sure this can not lead to reentrancy attacks.\n function universalTransfer(address token, address to, uint256 value) internal {\n // Don't do anything, if need to send tokens to this address\n if (to == address(this)) return;\n // Don't do anything, if trying to send zero value\n if (value == 0) return;\n if (token == ETH_ADDRESS) {\n /// @dev Note: this can potentially lead to executing code in `to`.\n // solhint-disable-next-line avoid-low-level-calls\n (bool success,) = to.call{value: value}(\"\");\n require(success, \"ETH transfer failed\");\n } else {\n IERC20(token).safeTransfer(to, value);\n }\n }\n\n /// @notice Issues an infinite allowance to the spender, if the current allowance is insufficient\n /// to spend the given amount.\n function universalApproveInfinity(address token, address spender, uint256 amountToSpend) internal {\n // ETH Chad doesn't require your approval\n if (token == ETH_ADDRESS) return;\n // No-op if allowance is already sufficient\n uint256 allowance = IERC20(token).allowance(address(this), spender);\n if (allowance \u003e= amountToSpend) return;\n // Otherwise, reset approval to 0 and set to max allowance\n if (allowance \u003e 0) IERC20(token).safeDecreaseAllowance(spender, allowance);\n IERC20(token).safeIncreaseAllowance(spender, type(uint256).max);\n }\n\n /// @notice Returns the balance of the given token (or native ETH) for the given account.\n function universalBalanceOf(address token, address account) internal view returns (uint256) {\n if (token == ETH_ADDRESS) {\n return account.balance;\n } else {\n return IERC20(token).balanceOf(account);\n }\n }\n\n /// @dev Checks that token is a contract and not ETH_ADDRESS.\n function assertIsContract(address token) internal view {\n // Check that ETH_ADDRESS was not used (in case this is a predeploy on any of the chains)\n if (token == UniversalTokenLib.ETH_ADDRESS) revert TokenNotContract();\n // Check that token is not an EOA\n if (token.code.length == 0) revert TokenNotContract();\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/Admin.sol\n\ncontract Admin is IAdmin, AccessControlEnumerable {\n using UniversalTokenLib for address;\n\n bytes32 public constant RELAYER_ROLE = keccak256(\"RELAYER_ROLE\");\n bytes32 public constant REFUNDER_ROLE = keccak256(\"REFUNDER_ROLE\");\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n uint256 public constant FEE_BPS = 1e6;\n uint256 public constant FEE_RATE_MAX = 0.01e6; // max 1% on origin amount\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Chain gas amount to forward as rebate if requested\n uint256 public chainGasAmount;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n }\n\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n require(newFeeRate \u003c= FEE_RATE_MAX, \"newFeeRate \u003e max\");\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n token.universalTransfer(recipient, feeAmount);\n emit FeesSwept(token, recipient, feeAmount);\n }\n\n function setChainGasAmount(uint256 newChainGasAmount) external onlyRole(GOVERNOR_ROLE) {\n uint256 oldChainGasAmount = chainGasAmount;\n chainGasAmount = newChainGasAmount;\n emit ChainGasAmountUpdated(oldChainGasAmount, newChainGasAmount);\n }\n}\n\n// contracts/FastBridgeV2.sol\n\n/// @notice FastBridgeV2 is a contract for bridging tokens across chains.\ncontract FastBridgeV2 is Admin, IFastBridgeV2, IFastBridgeV2Errors {\n using SafeERC20 for IERC20;\n using UniversalTokenLib for address;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Delay for a transaction after which it could be permisionlessly refunded\n uint256 public constant REFUND_DELAY = 7 days;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n /// @notice Maximum length of accepted callParams\n uint256 public constant MAX_CALL_PARAMS_LENGTH = 2 ** 16 - 1;\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeTxDetails) public bridgeTxDetails;\n /// @notice Relay details on destination chain\n mapping(bytes32 =\u003e BridgeRelay) public bridgeRelayDetails;\n /// @notice Unique bridge nonces tracked per originSender\n mapping(address =\u003e uint256) public senderNonces;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Replaced by senderNonces\n uint256 public immutable nonce = 0;\n /// @notice the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n bridge({\n params: params,\n paramsV2: BridgeParamsV2({\n quoteRelayer: address(0),\n quoteExclusivitySeconds: 0,\n quoteId: bytes(\"\"),\n callValue: 0,\n callParams: bytes(\"\")\n })\n });\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes memory request) external payable {\n relay({request: request, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes memory request, bytes32 destTxHash) external {\n prove({transactionId: keccak256(request), destTxHash: destTxHash, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridgeV2\n function claim(bytes memory request) external {\n claim({request: request, to: address(0)});\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003e DISPUTE_PERIOD) {\n revert DisputePeriodPassed();\n }\n\n // @dev relayer gets slashed effectively if dest relay has gone thru\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n bridgeTxDetails[transactionId].proofRelayer = address(0);\n bridgeTxDetails[transactionId].proofBlockTimestamp = 0;\n bridgeTxDetails[transactionId].proofBlockNumber = 0;\n\n emit BridgeProofDisputed(transactionId, msg.sender);\n }\n\n /// @inheritdoc IFastBridge\n function refund(bytes memory request) external {\n bytes32 transactionId = keccak256(request);\n\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n\n if (bridgeTxDetails[transactionId].status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n\n if (hasRole(REFUNDER_ROLE, msg.sender)) {\n // Refunder can refund if deadline has passed\n if (block.timestamp \u003c= transaction.deadline) revert DeadlineNotExceeded();\n } else {\n // Permissionless refund is allowed after REFUND_DELAY\n if (block.timestamp \u003c= transaction.deadline + REFUND_DELAY) revert DeadlineNotExceeded();\n }\n\n // if all checks passed, set to REFUNDED status\n bridgeTxDetails[transactionId].status = BridgeStatus.REFUNDED;\n\n // transfer origin collateral back to original sender\n address to = transaction.originSender;\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount + transaction.originFeeAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (bridgeTxDetails[transactionId].proofRelayer != relayer) revert SenderIncorrect();\n return _timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n /// @dev This method is added to achieve backwards compatibility with decoding requests into V1 structs:\n /// - `callValue` is partially reported as a zero/non-zero flag\n /// - `callParams` is ignored\n /// In order to process all kinds of requests use getBridgeTransactionV2 instead.\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory) {\n // Try decoding into V2 struct first. This will revert if V1 struct is passed\n try this.getBridgeTransactionV2(request) returns (BridgeTransactionV2 memory txV2) {\n // Note: we entirely ignore the callParams field, as it was not present in V1\n return BridgeTransaction({\n originChainId: txV2.originChainId,\n destChainId: txV2.destChainId,\n originSender: txV2.originSender,\n destRecipient: txV2.destRecipient,\n originToken: txV2.originToken,\n destToken: txV2.destToken,\n originAmount: txV2.originAmount,\n destAmount: txV2.destAmount,\n originFeeAmount: txV2.originFeeAmount,\n sendChainGas: txV2.callValue != 0,\n deadline: txV2.deadline,\n nonce: txV2.nonce\n });\n } catch {\n // Fallback to V1 struct\n return abi.decode(request, (BridgeTransaction));\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) public payable {\n int256 exclusivityEndTime = int256(block.timestamp) + paramsV2.quoteExclusivitySeconds;\n _validateBridgeParams(params, paramsV2, exclusivityEndTime);\n\n // transfer tokens to bridge contract\n /// @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _takeBridgedUserAsset(params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n\n // set status to requested\n bytes memory request = abi.encode(\n BridgeTransactionV2({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n callValue: paramsV2.callValue,\n deadline: params.deadline,\n nonce: senderNonces[params.sender]++, // increment nonce on every bridge\n exclusivityRelayer: paramsV2.quoteRelayer,\n // We checked exclusivityEndTime to be in range (0 .. params.deadline] above, so can safely cast\n exclusivityEndTime: uint256(exclusivityEndTime),\n callParams: paramsV2.callParams\n })\n );\n bytes32 transactionId = keccak256(request);\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n\n emit BridgeRequested({\n transactionId: transactionId,\n sender: params.sender,\n request: request,\n destChainId: params.dstChainId,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n sendChainGas: paramsV2.callValue != 0\n });\n emit BridgeQuoteDetails(transactionId, paramsV2.quoteId);\n }\n\n /// @inheritdoc IFastBridgeV2\n function relay(bytes memory request, address relayer) public payable {\n bytes32 transactionId = keccak256(request);\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n _validateRelayParams(transaction, transactionId, relayer);\n // mark bridge transaction as relayed\n bridgeRelayDetails[transactionId] =\n BridgeRelay({blockNumber: uint48(block.number), blockTimestamp: uint48(block.timestamp), relayer: relayer});\n\n // transfer tokens to recipient on destination chain and do an arbitrary call if requested\n address to = transaction.destRecipient;\n address token = transaction.destToken;\n uint256 amount = transaction.destAmount;\n uint256 callValue = transaction.callValue;\n\n // Emit the event before any external calls\n emit BridgeRelayed({\n transactionId: transactionId,\n relayer: relayer,\n to: to,\n originChainId: transaction.originChainId,\n originToken: transaction.originToken,\n destToken: token,\n originAmount: transaction.originAmount,\n destAmount: amount,\n chainGasAmount: callValue\n });\n\n // All state changes have been done at this point, can proceed to the external calls.\n // This follows the checks-effects-interactions pattern to mitigate potential reentrancy attacks.\n if (token == UniversalTokenLib.ETH_ADDRESS) {\n // For ETH non-zero callValue is not allowed\n if (callValue != 0) revert NativeTokenCallValueNotSupported();\n // Check that the correct msg.value was sent\n if (msg.value != amount) revert MsgValueIncorrect();\n } else {\n // For ERC20s, we check that the correct msg.value was sent\n if (msg.value != callValue) revert MsgValueIncorrect();\n // We need to transfer the tokens from the Relayer to the recipient first before performing an\n // optional post-transfer arbitrary call.\n IERC20(token).safeTransferFrom(msg.sender, to, amount);\n }\n\n if (transaction.callParams.length != 0) {\n // Arbitrary call requested, perform it while supplying full msg.value to the recipient\n // Note: if token has a fee on transfers, the recipient will have received less than `amount`.\n // This is a very niche edge case and should be handled by the recipient contract.\n _checkedCallRecipient({recipient: to, token: token, amount: amount, callParams: transaction.callParams});\n } else if (msg.value != 0) {\n // No arbitrary call requested, but msg.value was sent. This is either a relay with ETH,\n // or a non-zero callValue request with an ERC20. In both cases, transfer the ETH to the recipient.\n Address.sendValue(payable(to), msg.value);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) public onlyRole(RELAYER_ROLE) {\n // update bridge tx status given proof provided\n if (bridgeTxDetails[transactionId].status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n bridgeTxDetails[transactionId].status = BridgeStatus.RELAYER_PROVED;\n bridgeTxDetails[transactionId].proofBlockTimestamp = uint40(block.timestamp);\n bridgeTxDetails[transactionId].proofBlockNumber = uint48(block.number);\n bridgeTxDetails[transactionId].proofRelayer = relayer;\n\n emit BridgeProofProvided(transactionId, relayer, destTxHash);\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes memory request, address to) public {\n bytes32 transactionId = keccak256(request);\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n\n // update bridge tx status if able to claim origin collateral\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n\n // if \"to\" is zero addr, permissionlessly send funds to proven relayer\n if (to == address(0)) {\n to = bridgeTxDetails[transactionId].proofRelayer;\n } else if (bridgeTxDetails[transactionId].proofRelayer != msg.sender) {\n revert SenderIncorrect();\n }\n\n if (_timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003c= DISPUTE_PERIOD) {\n revert DisputePeriodNotPassed();\n }\n\n bridgeTxDetails[transactionId].status = BridgeStatus.RELAYER_CLAIMED;\n\n // update protocol fees if origin fee amount exists\n if (transaction.originFeeAmount \u003e 0) protocolFees[transaction.originToken] += transaction.originFeeAmount;\n\n // transfer origin collateral less fee to specified address\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositClaimed(transactionId, bridgeTxDetails[transactionId].proofRelayer, to, token, amount);\n }\n\n function bridgeStatuses(bytes32 transactionId) public view returns (BridgeStatus status) {\n return bridgeTxDetails[transactionId].status;\n }\n\n function bridgeProofs(bytes32 transactionId) public view returns (uint96 timestamp, address relayer) {\n timestamp = bridgeTxDetails[transactionId].proofBlockTimestamp;\n relayer = bridgeTxDetails[transactionId].proofRelayer;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeRelays(bytes32 transactionId) public view returns (bool) {\n // has this transactionId been relayed?\n return bridgeRelayDetails[transactionId].relayer != address(0);\n }\n\n /// @inheritdoc IFastBridgeV2\n function getBridgeTransactionV2(bytes memory request) public pure returns (BridgeTransactionV2 memory) {\n return abi.decode(request, (BridgeTransactionV2));\n }\n\n /// @notice Takes the bridged asset from the user into FastBridgeV2 custody. It will be later\n /// claimed by the relayer who completed the relay on destination chain, or refunded back to the user,\n /// should no one complete the relay.\n function _takeBridgedUserAsset(address token, uint256 amount) internal returns (uint256 amountTaken) {\n if (token == UniversalTokenLib.ETH_ADDRESS) {\n // For ETH we just need to check that the supplied msg.value is correct.\n // Supplied `msg.value` is already in FastBridgeV2 custody.\n if (amount != msg.value) revert MsgValueIncorrect();\n amountTaken = msg.value;\n } else {\n // For ERC20s, token is explicitly transferred from the user to FastBridgeV2.\n // We don't allow non-zero `msg.value` to avoid extra funds from being stuck in FastBridgeV2.\n token.assertIsContract();\n if (msg.value != 0) revert MsgValueIncorrect();\n amountTaken = IERC20(token).balanceOf(address(this));\n IERC20(token).safeTransferFrom(msg.sender, address(this), amount);\n // Use the balance difference as the amount taken in case of fee on transfer tokens.\n amountTaken = IERC20(token).balanceOf(address(this)) - amountTaken;\n }\n }\n\n /// @notice Calls the Recipient's hook function with the specified callParams and performs\n /// all the necessary checks for the returned value.\n function _checkedCallRecipient(\n address recipient,\n address token,\n uint256 amount,\n bytes memory callParams\n )\n internal\n {\n bytes memory hookData =\n abi.encodeCall(IFastBridgeRecipient.fastBridgeTransferReceived, (token, amount, callParams));\n // This will bubble any revert messages from the hook function\n bytes memory returnData = Address.functionCallWithValue({target: recipient, data: hookData, value: msg.value});\n // Explicit revert if no return data at all\n if (returnData.length == 0) revert RecipientNoReturnValue();\n // Check that exactly a single return value was returned\n if (returnData.length != 32) revert RecipientIncorrectReturnValue();\n // Return value should be abi-encoded hook function selector\n if (bytes32(returnData) != bytes32(IFastBridgeRecipient.fastBridgeTransferReceived.selector)) {\n revert RecipientIncorrectReturnValue();\n }\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint40(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint40).max but\n /// proof.timestamp \u003c type(uint40).max via unchecked statement\n /// @param proofBlockTimestamp The bridge proof block timestamp\n /// @return delta Time delta since proof submitted\n function _timeSince(uint40 proofBlockTimestamp) internal view returns (uint256 delta) {\n unchecked {\n delta = uint40(block.timestamp) - proofBlockTimestamp;\n }\n }\n\n /// @notice Performs all the necessary checks for a bridge to happen.\n /// @dev There's no good way to refactor this function to reduce cyclomatic complexity due to\n /// the number of checks that need to be performed, so we skip the code-complexity rule here.\n // solhint-disable-next-line code-complexity\n function _validateBridgeParams(\n BridgeParams memory params,\n BridgeParamsV2 memory paramsV2,\n int256 exclusivityEndTime\n )\n internal\n view\n {\n // Check V1 (legacy) params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.sender == address(0) || params.to == address(0)) revert ZeroAddress();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n // Check V2 params\n if (paramsV2.callParams.length \u003e MAX_CALL_PARAMS_LENGTH) revert CallParamsLengthAboveMax();\n if (paramsV2.callValue != 0 \u0026\u0026 params.destToken == UniversalTokenLib.ETH_ADDRESS) {\n revert NativeTokenCallValueNotSupported();\n }\n // exclusivityEndTime must be in range (0 .. params.deadline]\n if (exclusivityEndTime \u003c= 0 || exclusivityEndTime \u003e int256(params.deadline)) {\n revert ExclusivityParamsIncorrect();\n }\n }\n\n /// @notice Performs all the necessary checks for a relay to happen.\n function _validateRelayParams(\n BridgeTransactionV2 memory transaction,\n bytes32 transactionId,\n address relayer\n )\n internal\n view\n {\n if (relayer == address(0)) revert ZeroAddress();\n // Check if the transaction has already been relayed\n if (bridgeRelays(transactionId)) revert TransactionRelayed();\n if (transaction.destChainId != block.chainid) revert ChainIncorrect();\n // Check the deadline for relay to happen\n if (block.timestamp \u003e transaction.deadline) revert DeadlineExceeded();\n // Check the exclusivity period, if it is still ongoing\n // forgefmt: disable-next-item\n if (\n transaction.exclusivityRelayer != address(0) \u0026\u0026\n transaction.exclusivityRelayer != relayer \u0026\u0026\n block.timestamp \u003c= transaction.exclusivityEndTime\n ) {\n revert ExclusivityPeriodNotPassed();\n }\n }\n}\n","language":"Solidity","languageVersion":"0.8.24","compilerVersion":"0.8.24","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"25827:11640:0:-:0;;;;;;;;;;;;;;;-1:-1:-1;;;25827:11640:0;;;;;;;;;;;;;;;;;","srcMapRuntime":"25827:11640:0:-:0;;;;;;;;","abiDefinition":[],"userDoc":{"kind":"user","methods":{},"version":1},"developerDoc":{"details":"Library for managing https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive types. Sets have the following properties: - Elements are added, removed, and checked for existence in constant time (O(1)). - Elements are enumerated in O(n). No guarantees are made on the ordering. ```solidity contract Example { // Add the library methods using EnumerableSet for EnumerableSet.AddressSet; // Declare a set state variable EnumerableSet.AddressSet private mySet; } ``` As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`) and `uint256` (`UintSet`) are supported. [WARNING] ==== Trying to delete such a structure from storage will likely result in data corruption, rendering the structure unusable. See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info. In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an array of EnumerableSet. ====","kind":"dev","methods":{},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[],\"devdoc\":{\"details\":\"Library for managing https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive types. Sets have the following properties: - Elements are added, removed, and checked for existence in constant time (O(1)). - Elements are enumerated in O(n). No guarantees are made on the ordering. ```solidity contract Example { // Add the library methods using EnumerableSet for EnumerableSet.AddressSet; // Declare a set state variable EnumerableSet.AddressSet private mySet; } ``` As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`) and `uint256` (`UintSet`) are supported. [WARNING] ==== Trying to delete such a structure from storage will likely result in data corruption, rendering the structure unusable. See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info. In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an array of EnumerableSet. ====\",\"kind\":\"dev\",\"methods\":{},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeV2.sol\":\"EnumerableSet\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeV2.sol\":{\"keccak256\":\"0xfd916c030b1ffca5a136817827b8018c8ba42ca089905747f3de6148b73eb35e\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://18e6438c4096deb8ae453fb3365ba2b07d52944e93c08288fc5d012b71bf6bb3\",\"dweb:/ipfs/QmfEMqpT1zz6RRm7UuHLRowe1tds2cTGLrVonfm9XSCACj\"]}},\"version\":1}"},"hashes":{}},"solidity/FastBridgeV2.sol:FastBridgeV2":{"code":"0x60c060405260006080523480156200001657600080fd5b5060405162003e6138038062003e61833981016040819052620000399162000199565b806200004760008262000054565b50504360a05250620001c4565b60008062000063848462000091565b90508015620000885760008481526001602052604090206200008690846200013f565b505b90505b92915050565b6000828152602081815260408083206001600160a01b038516845290915281205460ff1662000136576000838152602081815260408083206001600160a01b03861684529091529020805460ff19166001179055620000ed3390565b6001600160a01b0316826001600160a01b0316847f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45060016200008b565b5060006200008b565b600062000088836001600160a01b038416600081815260018301602052604081205462000136575081546001818101845560008481526020808220909301849055845484825282860190935260409020919091556200008b565b600060208284031215620001ac57600080fd5b81516001600160a01b03811681146200008857600080fd5b60805160a051613c77620001ea6000396000610802015260006108a30152613c776000f3fe6080604052600436106102fd5760003560e01c806391ad50391161018f578063b13aa2d6116100e1578063ca15c8731161008a578063dcf844a711610064578063dcf844a714610a50578063df36bb1314610a7d578063e00a83e014610a9357600080fd5b8063ca15c873146109dc578063ccc57490146109fc578063d547741f14610a3057600080fd5b8063bfc7c607116100bb578063bfc7c6071461091c578063c63ff8dd1461092f578063c79371b11461094f57600080fd5b8063b13aa2d6146108c5578063b250fe6b146108e5578063bf333f2c1461090557600080fd5b8063a3ec191a11610143578063ac11fb1a1161011d578063ac11fb1a14610844578063add98c7014610871578063affed0e01461089157600080fd5b8063a3ec191a146107f0578063a5bbe22b14610607578063aa9641ab1461082457600080fd5b8063926d7d7f11610174578063926d7d7f146107945780639c9545f0146107c8578063a217fddf146107db57600080fd5b806391ad5039146106d057806391d148541461075057600080fd5b806341fcb6121161025357806363787e52116101fc578063886d36ff116101d6578063886d36ff146106655780638f0d6f17146106855780639010d07c1461069857600080fd5b806363787e521461058c578063820688d5146106075780638379a24f1461061d57600080fd5b80635960ccf21161022d5780635960ccf21461050b5780635aa6ccba1461053f5780635eb7d9461461056c57600080fd5b806341fcb612146104c257806345851694146104e257806358f85880146104f557600080fd5b806318e4357d116102b5578063295710ff1161028f578063295710ff146104555780632f2ff15d1461048257806336568abe146104a257600080fd5b806318e4357d146103ee578063190da5951461040e578063248a9ca31461042557600080fd5b8063051287bc116102e6578063051287bc1461037957806306f333f2146103b65780630f5f6ed7146103d857600080fd5b806301ffc9a71461030257806303ed0ee514610337575b600080fd5b34801561030e57600080fd5b5061032261031d366004612eef565b610aa9565b60405190151581526020015b60405180910390f35b34801561034357600080fd5b5061036b7f043c983c49d46f0e102151eaf8085d4a2e6571d5df2d47b013f39bddfd4a639d81565b60405190815260200161032e565b34801561038557600080fd5b506103a9610394366004612f31565b60009081526005602052604090205460ff1690565b60405161032e9190612fb4565b3480156103c257600080fd5b506103d66103d1366004612fe2565b610b05565b005b3480156103e457600080fd5b5061036b61271081565b3480156103fa57600080fd5b506103d661040936600461301b565b610bcc565b34801561041a57600080fd5b5061036b62093a8081565b34801561043157600080fd5b5061036b610440366004612f31565b60009081526020819052604090206001015490565b34801561046157600080fd5b5061036b610470366004613054565b60076020526000908152604090205481565b34801561048e57600080fd5b506103d661049d366004613071565b610d39565b3480156104ae57600080fd5b506103d66104bd366004613071565b610d64565b3480156104ce57600080fd5b506103d66104dd366004613209565b610db0565b6103d66104f0366004613329565b611026565b34801561050157600080fd5b5061036b60025481565b34801561051757600080fd5b5061036b7fdb9556138406326f00296e13ea2ad7db24ba82381212d816b1a40c23b466b32781565b34801561054b57600080fd5b5061055f61055a366004613346565b611083565b60405161032e91906133d3565b34801561057857600080fd5b506103d6610587366004613346565b611149565b34801561059857600080fd5b506105f76105a7366004612f31565b60056020526000908152604090205460ff811690610100810464ffffffffff16906601000000000000810465ffffffffffff16906c0100000000000000000000000090046001600160a01b031684565b60405161032e94939291906134e8565b34801561061357600080fd5b5061036b61070881565b34801561062957600080fd5b50610322610638366004612f31565b6000908152600660205260409020546c0100000000000000000000000090046001600160a01b0316151590565b34801561067157600080fd5b506103d6610680366004613529565b61133e565b6103d6610693366004613346565b611354565b3480156106a457600080fd5b506106b86106b336600461356e565b61135e565b6040516001600160a01b03909116815260200161032e565b3480156106dc57600080fd5b506107246106eb366004612f31565b600090815260056020526040902054610100810464ffffffffff16916c010000000000000000000000009091046001600160a01b031690565b604080516bffffffffffffffffffffffff90931683526001600160a01b0390911660208301520161032e565b34801561075c57600080fd5b5061032261076b366004613071565b6000918252602082815260408084206001600160a01b0393909316845291905290205460ff1690565b3480156107a057600080fd5b5061036b7fe2b7fb3b832174769106daebcfd6d1970523240dda11281102db9363b83b0dc481565b6103d66107d6366004613209565b61137d565b3480156107e757600080fd5b5061036b600081565b3480156107fc57600080fd5b5061036b7f000000000000000000000000000000000000000000000000000000000000000081565b34801561083057600080fd5b5061032261083f366004613071565b611603565b34801561085057600080fd5b5061086461085f366004613346565b6116ee565b60405161032e9190613590565b34801561087d57600080fd5b506103d661088c366004612f31565b6118a6565b34801561089d57600080fd5b5061036b7f000000000000000000000000000000000000000000000000000000000000000081565b3480156108d157600080fd5b506103d66108e0366004612f31565b6119c8565b3480156108f157600080fd5b506103d6610900366004612f31565b611aaa565b34801561091157600080fd5b5061036b620f424081565b6103d661092a366004613676565b611b12565b34801561093b57600080fd5b506103d661094a366004613346565b611d94565b34801561095b57600080fd5b506109ae61096a366004612f31565b60066020526000908152604090205465ffffffffffff8082169166010000000000008104909116906c0100000000000000000000000090046001600160a01b031683565b6040805165ffffffffffff94851681529390921660208401526001600160a01b03169082015260600161032e565b3480156109e857600080fd5b5061036b6109f7366004612f31565b611d9f565b348015610a0857600080fd5b5061036b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f5581565b348015610a3c57600080fd5b506103d6610a4b366004613071565b611db6565b348015610a5c57600080fd5b5061036b610a6b366004613054565b60036020526000908152604090205481565b348015610a8957600080fd5b5061036b61ffff81565b348015610a9f57600080fd5b5061036b60045481565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f5a05180f000000000000000000000000000000000000000000000000000000001480610aff5750610aff82611ddb565b92915050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f55610b2f81611e72565b6001600160a01b03831660009081526003602052604081205490819003610b565750505050565b6001600160a01b038416600081815260036020526040812055610b7a908483611e7c565b604080516001600160a01b038087168252851660208201529081018290527f244e51bc38c1452fa8aaf487bcb4bca36c2baa3a5fbdb776b1eabd8dc6d277cd9060600160405180910390a1505b505050565b7fe2b7fb3b832174769106daebcfd6d1970523240dda11281102db9363b83b0dc4610bf681611e72565b600160008581526005602052604090205460ff166004811115610c1b57610c1b612f4a565b14610c52576040517f4145817200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600084815260056020908152604091829020805460027fffffffffffffffffffffffffffffffffffffffff0000000000000000000000009091166101004264ffffffffff16027fffffffffffffffffffffffffffffffffffffffff000000000000ffffffffffff161766010000000000004365ffffffffffff160217176bffffffffffffffffffffffff166c010000000000000000000000006001600160a01b0387169081029190911790915582518681529251909287927f4ac8af8a2cd87193d64dfc7a3b8d9923b714ec528b18725d080aa1299be0c5e492918290030190a350505050565b600082815260208190526040902060010154610d5481611e72565b610d5e8383611f9f565b50505050565b6001600160a01b0381163314610da6576040517f6697b23200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610bc78282611fd4565b815160208301206000610dc284611083565b9050600260008381526005602052604090205460ff166004811115610de957610de9612f4a565b14610e20576040517f4145817200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600160a01b038316610e5d576000828152600560205260409020546c0100000000000000000000000090046001600160a01b03169250610ebd565b6000828152600560205260409020546c0100000000000000000000000090046001600160a01b03163314610ebd576040517f4af43a9000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008281526005602052604090205461070890610100900464ffffffffff90811642031611610f18576040517f1992d0bd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600082815260056020526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016600317905561010081015115610f925761010081015160808201516001600160a01b031660009081526003602052604081208054909190610f8c908490613773565b90915550505b608081015160c0820151610fb06001600160a01b0383168683611e7c565b6000848152600560209081526040918290205482516001600160a01b038681168252928101859052888316936c010000000000000000000000009092049092169187917f582211c35a2139ac3bbaac74663c6a1f56c6cbb658b41fe11fd45a82074ac678910160405180910390a4505050505050565b611080816040518060a0016040528060006001600160a01b03168152602001600081526020016040518060200160405280600081525081526020016000815260200160405180602001604052806000815250815250611b12565b50565b611135604051806101e00160405280600063ffffffff168152602001600063ffffffff16815260200160006001600160a01b0316815260200160006001600160a01b0316815260200160006001600160a01b0316815260200160006001600160a01b0316815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160006001600160a01b0316815260200160008152602001606081525090565b81806020019051810190610aff91906137e1565b80516020820120600061115b83611083565b9050600160008381526005602052604090205460ff16600481111561118257611182612f4a565b146111b9576040517f4145817200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b3360009081527fd2043bf65931af3dbecf60d0db8f40e4160406d7beb00522f4200cf4944a1eb8602052604090205460ff161561123357806101400151421161122e576040517fe15ff9ea00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61127f565b62093a808161014001516112479190613773565b421161127f576040517fe15ff9ea00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008281526005602052604080822080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166004179055820151608083015161010084015160c0850151929391926112d89190613773565b90506112ee6001600160a01b0383168483611e7c565b604080516001600160a01b0384811682526020820184905285169187917fb4c55c0c9bc613519b920e88748090150b890a875d307f21bea7d4fb2e8bc958910160405180910390a3505050505050565b61135082805190602001208233610bcc565b5050565b611080813361137d565b60008281526001602052604081206113769083612001565b9392505050565b81516020830120600061138f84611083565b905061139c81838561200d565b604080516060808201835265ffffffffffff438116835242811660208085019182526001600160a01b0389811686880181815260008b815260068552899020975188549551915184166c01000000000000000000000000026bffffffffffffffffffffffff9288166601000000000000027fffffffffffffffffffffffffffffffffffffffff00000000000000000000000090971691909716179490941793909316939093179094558583015160a08088015160e08901516101208a01518a516080808d015160c0808f01518e5163ffffffff9095168552918b169c84019c909c52858a169c83019c909c529881019a909a52968901819052918801869052919691959094938716929189917ff8ae392d784b1ea5e8881bfa586d81abf07ef4f1e2fc75f7fe51c90f05199a5c910160405180910390a47fffffffffffffffffffffffff11111111111111111111111111111111111111126001600160a01b0384160161157957801561153b576040517f2598ad2e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b813414611574576040517f81de0bf300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6115c7565b8034146115b2576040517f81de0bf300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6115c76001600160a01b0384163386856121aa565b6101c085015151156115e9576115e4848484886101c00151612226565b6115f9565b34156115f9576115f98434612385565b5050505050505050565b6000600260008481526005602052604090205460ff16600481111561162a5761162a612f4a565b14611661576040517f4145817200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000838152600560205260409020546001600160a01b038381166c0100000000000000000000000090920416146116c4576040517f4af43a9000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b505060009081526005602052604090205461070861010090910464ffffffffff9081164203161190565b6040805161018081018252600080825260208201819052818301819052606082018190526080820181905260a0820181905260c0820181905260e0820181905261010082018190526101208201819052610140820181905261016082015290517f5aa6ccba0000000000000000000000000000000000000000000000000000000081523090635aa6ccba90611787908590600401613916565b600060405180830381865afa9250505080156117c557506040513d6000823e601f3d908101601f191682016040526117c291908101906137e1565b60015b6117dd5781806020019051810190610aff9190613934565b604051806101800160405280826000015163ffffffff168152602001826020015163ffffffff16815260200182604001516001600160a01b0316815260200182606001516001600160a01b0316815260200182608001516001600160a01b031681526020018260a001516001600160a01b031681526020018260c0015181526020018260e001518152602001826101000151815260200182610120015160001415151581526020018261014001518152602001826101600151815250915050919050565b919050565b7f043c983c49d46f0e102151eaf8085d4a2e6571d5df2d47b013f39bddfd4a639d6118d081611e72565b600260008381526005602052604090205460ff1660048111156118f5576118f5612f4a565b1461192c576040517f4145817200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008281526005602052604090205461070890610100900464ffffffffff9081164203161115611988576040517f3e908aac00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000828152600560205260408082206001905551339184917f0695cf1d39b3055dcd0fe02d8b47eaf0d5a13e1996de925de59d0ef9b7f7fad49190a35050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f556119f281611e72565b612710821115611a63576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f6e657746656552617465203e206d61780000000000000000000000000000000060448201526064015b60405180910390fd5b600280549083905560408051828152602081018590527f14914da2bf76024616fbe1859783fcd4dbddcb179b1f3a854949fbf920dcb95791015b60405180910390a1505050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f55611ad481611e72565b600480549083905560408051828152602081018590527f5cf09b12f3f56b4c564d51b25b40360af6d795198adb61ae0806a36c294323fa9101611a9d565b6000816020015142611b249190613a00565b9050611b3183838361244e565b6000611b4584606001518560a001516126d3565b90506000806002541115611b7257620f424060025483611b659190613a28565b611b6f9190613a3f565b90505b611b7c8183613a7a565b91506000604051806101e001604052804663ffffffff168152602001876000015163ffffffff16815260200187602001516001600160a01b0316815260200187604001516001600160a01b0316815260200187606001516001600160a01b0316815260200187608001516001600160a01b031681526020018481526020018760c0015181526020018381526020018660600151815260200187610100015181526020016007600089602001516001600160a01b03166001600160a01b031681526020019081526020016000206000815480929190611c5990613a8d565b91905055815260200186600001516001600160a01b031681526020018581526020018660800151815250604051602001611c9391906133d3565b60408051808303601f1901815282825280516020808301919091206000818152600583529390932080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016600117905589015189516060808c015160808d015160c08e0151928d015195985095966001600160a01b039094169587957f120ea0364f36cdac7983bcfdd55270ca09d7f9b314a2ebc425a3b01ab1d6403a95611d47958b95909493928e9290151590613ac5565b60405180910390a3807f3120e2bb59c86aca6890191a589a96af3662838efa374fbdcdf4c95bfe4a6c0e8760400151604051611d839190613916565b60405180910390a250505050505050565b611080816000610db0565b6000818152600160205260408120610aff906128b4565b600082815260208190526040902060010154611dd181611e72565b610d5e8383611fd4565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f7965db0b000000000000000000000000000000000000000000000000000000001480610aff57507f01ffc9a7000000000000000000000000000000000000000000000000000000007fffffffff00000000000000000000000000000000000000000000000000000000831614610aff565b61108081336128be565b306001600160a01b03831603611e9157505050565b80600003611e9e57505050565b7fffffffffffffffffffffffff11111111111111111111111111111111111111126001600160a01b03841601611f8b576000826001600160a01b03168260405160006040518083038185875af1925050503d8060008114611f1b576040519150601f19603f3d011682016040523d82523d6000602084013e611f20565b606091505b5050905080610d5e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f455448207472616e73666572206661696c6564000000000000000000000000006044820152606401611a5a565b610bc76001600160a01b038416838361292a565b600080611fac848461295b565b90508015611376576000848152600160205260409020611fcc9084612a23565b509392505050565b600080611fe18484612a38565b90508015611376576000848152600160205260409020611fcc9084612ad9565b60006113768383612aee565b6001600160a01b03811661204d576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000828152600660205260409020546c0100000000000000000000000090046001600160a01b0316156120ac576040517fbef7bb7d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b46836020015163ffffffff16146120ef576040517f7029fdf900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b82610140015142111561212e576040517f559895a300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6101808301516001600160a01b0316158015906121625750806001600160a01b03168361018001516001600160a01b031614155b80156121735750826101a001514211155b15610bc7576040517f14be123200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040516001600160a01b038481166024830152838116604483015260648201839052610d5e9186918216906323b872dd906084015b604051602081830303815290604052915060e01b6020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8381831617835250505050612b18565b600083838360405160240161223d93929190613b1b565b60408051601f198184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f461e0c2100000000000000000000000000000000000000000000000000000000179052905060006122a4868334612b94565b905080516000036122e1576040517f1a95ad2600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b805160201461231c576040517ff3725cca00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f461e0c210000000000000000000000000000000000000000000000000000000061234682613b4c565b1461237d576040517ff3725cca00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b505050505050565b804710156123c1576040517fcd786059000000000000000000000000000000000000000000000000000000008152306004820152602401611a5a565b6000826001600160a01b03168260405160006040518083038185875af1925050503d806000811461240e576040519150601f19603f3d011682016040523d82523d6000602084013e612413565b606091505b5050905080610bc7576040517f1425ea4200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b46836000015163ffffffff1603612491576040517f7029fdf900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60a083015115806124a4575060c0830151155b156124db576040517fe38820c800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60208301516001600160a01b03161580612500575060408301516001600160a01b0316155b15612537576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60608301516001600160a01b0316158061255c575060808301516001600160a01b0316155b15612593576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61259f61070842613773565b83610100015110156125dd576040517f04b7fcc800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61ffff826080015151111561261e576040517ffbe24d4900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b606082015115801590612651575060808301516001600160a01b031673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee145b15612688576040517f2598ad2e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008113158061269c575082610100015181135b15610bc7576040517f352807b900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60007fffffffffffffffffffffffff11111111111111111111111111111111111111126001600160a01b038416016127455734821461273e576040517f81de0bf300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5034610aff565b612757836001600160a01b0316612c4a565b341561278f576040517f81de0bf300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201526001600160a01b038416906370a0823190602401602060405180830381865afa1580156127ec573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128109190613b91565b90506128276001600160a01b0384163330856121aa565b6040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015281906001600160a01b038516906370a0823190602401602060405180830381865afa158015612886573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128aa9190613b91565b6113769190613a7a565b6000610aff825490565b6000828152602081815260408083206001600160a01b038516845290915290205460ff16611350576040517fe2517d3f0000000000000000000000000000000000000000000000000000000081526001600160a01b038216600482015260248101839052604401611a5a565b6040516001600160a01b03838116602483015260448201839052610bc791859182169063a9059cbb906064016121df565b6000828152602081815260408083206001600160a01b038516845290915281205460ff16612a1b576000838152602081815260408083206001600160a01b0386168452909152902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790556129d33390565b6001600160a01b0316826001600160a01b0316847f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a4506001610aff565b506000610aff565b6000611376836001600160a01b038416612cf0565b6000828152602081815260408083206001600160a01b038516845290915281205460ff1615612a1b576000838152602081815260408083206001600160a01b038616808552925280832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016905551339286917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a4506001610aff565b6000611376836001600160a01b038416612d37565b6000826000018281548110612b0557612b05613baa565b9060005260206000200154905092915050565b6000612b2d6001600160a01b03841683612e2a565b90508051600014158015612b52575080806020019051810190612b509190613bd9565b155b15610bc7576040517f5274afe70000000000000000000000000000000000000000000000000000000081526001600160a01b0384166004820152602401611a5a565b606081471015612bd2576040517fcd786059000000000000000000000000000000000000000000000000000000008152306004820152602401611a5a565b600080856001600160a01b03168486604051612bee9190613bf6565b60006040518083038185875af1925050503d8060008114612c2b576040519150601f19603f3d011682016040523d82523d6000602084013e612c30565b606091505b5091509150612c40868383612e38565b9695505050505050565b7fffffffffffffffffffffffff11111111111111111111111111111111111111126001600160a01b03821601612cac576040517f7f523fe800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b806001600160a01b03163b600003611080576040517f7f523fe800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000818152600183016020526040812054612a1b57508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155610aff565b60008181526001830160205260408120548015612e20576000612d5b600183613a7a565b8554909150600090612d6f90600190613a7a565b9050808214612dd4576000866000018281548110612d8f57612d8f613baa565b9060005260206000200154905080876000018481548110612db257612db2613baa565b6000918252602080832090910192909255918252600188019052604090208390555b8554869080612de557612de5613c12565b600190038181906000526020600020016000905590558560010160008681526020019081526020016000206000905560019350505050610aff565b6000915050610aff565b606061137683836000612b94565b606082612e4d57612e4882612ead565b611376565b8151158015612e6457506001600160a01b0384163b155b15612ea6576040517f9996b3150000000000000000000000000000000000000000000000000000000081526001600160a01b0385166004820152602401611a5a565b5080611376565b805115612ebd5780518082602001fd5b6040517f1425ea4200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600060208284031215612f0157600080fd5b81357fffffffff000000000000000000000000000000000000000000000000000000008116811461137657600080fd5b600060208284031215612f4357600080fd5b5035919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b60058110612fb0577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b9052565b60208101610aff8284612f79565b6001600160a01b038116811461108057600080fd5b80356118a181612fc2565b60008060408385031215612ff557600080fd5b823561300081612fc2565b9150602083013561301081612fc2565b809150509250929050565b60008060006060848603121561303057600080fd5b8335925060208401359150604084013561304981612fc2565b809150509250925092565b60006020828403121561306657600080fd5b813561137681612fc2565b6000806040838503121561308457600080fd5b82359150602083013561301081612fc2565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051610120810167ffffffffffffffff811182821017156130e9576130e9613096565b60405290565b60405160a0810167ffffffffffffffff811182821017156130e9576130e9613096565b6040516101e0810167ffffffffffffffff811182821017156130e9576130e9613096565b604051610180810167ffffffffffffffff811182821017156130e9576130e9613096565b604051601f8201601f1916810167ffffffffffffffff8111828210171561318357613183613096565b604052919050565b600067ffffffffffffffff8211156131a5576131a5613096565b50601f01601f191660200190565b600082601f8301126131c457600080fd5b81356131d76131d28261318b565b61315a565b8181528460208386010111156131ec57600080fd5b816020850160208301376000918101602001919091529392505050565b6000806040838503121561321c57600080fd5b823567ffffffffffffffff81111561323357600080fd5b61323f858286016131b3565b925050602083013561301081612fc2565b63ffffffff8116811461108057600080fd5b80356118a181613250565b801515811461108057600080fd5b80356118a18161326d565b6000610120828403121561329957600080fd5b6132a16130c5565b90506132ac82613262565b81526132ba60208301612fd7565b60208201526132cb60408301612fd7565b60408201526132dc60608301612fd7565b60608201526132ed60808301612fd7565b608082015260a082013560a082015260c082013560c082015261331260e0830161327b565b60e082015261010080830135818301525092915050565b6000610120828403121561333c57600080fd5b6113768383613286565b60006020828403121561335857600080fd5b813567ffffffffffffffff81111561336f57600080fd5b61337b848285016131b3565b949350505050565b60005b8381101561339e578181015183820152602001613386565b50506000910152565b600081518084526133bf816020860160208601613383565b601f01601f19169290920160200192915050565b602081526133ea60208201835163ffffffff169052565b60006020830151613403604084018263ffffffff169052565b5060408301516001600160a01b03811660608401525060608301516001600160a01b03811660808401525060808301516001600160a01b03811660a08401525060a08301516001600160a01b03811660c08401525060c083015160e08381019190915283015161010080840191909152830151610120808401919091528301516101408084019190915283015161016080840191909152830151610180808401919091528301516101a06134c1818501836001600160a01b03169052565b8401516101c0848101919091528401516101e080850152905061337b6102008401826133a7565b608081016134f68287612f79565b64ffffffffff8516602083015265ffffffffffff841660408301526001600160a01b038316606083015295945050505050565b6000806040838503121561353c57600080fd5b823567ffffffffffffffff81111561355357600080fd5b61355f858286016131b3565b95602094909401359450505050565b6000806040838503121561358157600080fd5b50508035926020909101359150565b815163ffffffff168152610180810160208301516135b6602084018263ffffffff169052565b5060408301516135d160408401826001600160a01b03169052565b5060608301516135ec60608401826001600160a01b03169052565b50608083015161360760808401826001600160a01b03169052565b5060a083015161362260a08401826001600160a01b03169052565b5060c083015160c083015260e083015160e0830152610100808401518184015250610120808401516136578285018215159052565b5050610140838101519083015261016092830151929091019190915290565b600080610140838503121561368a57600080fd5b6136948484613286565b915061012083013567ffffffffffffffff808211156136b257600080fd5b9084019060a082870312156136c657600080fd5b6136ce6130ef565b82356136d981612fc2565b8152602083810135908201526040830135828111156136f757600080fd5b613703888286016131b3565b6040830152506060830135606082015260808301358281111561372557600080fd5b613731888286016131b3565b6080830152508093505050509250929050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b80820180821115610aff57610aff613744565b80516118a181613250565b80516118a181612fc2565b600082601f8301126137ad57600080fd5b81516137bb6131d28261318b565b8181528460208386010111156137d057600080fd5b61337b826020830160208701613383565b6000602082840312156137f357600080fd5b815167ffffffffffffffff8082111561380b57600080fd5b908301906101e0828603121561382057600080fd5b613828613112565b61383183613786565b815261383f60208401613786565b602082015261385060408401613791565b604082015261386160608401613791565b606082015261387260808401613791565b608082015261388360a08401613791565b60a082015260c0838101519082015260e0808401519082015261010080840151908201526101208084015190820152610140808401519082015261016080840151908201526101806138d6818501613791565b908201526101a083810151908201526101c080840151838111156138f957600080fd5b6139058882870161379c565b918301919091525095945050505050565b60208152600061137660208301846133a7565b80516118a18161326d565b6000610180828403121561394757600080fd5b61394f613136565b61395883613786565b815261396660208401613786565b602082015261397760408401613791565b604082015261398860608401613791565b606082015261399960808401613791565b60808201526139aa60a08401613791565b60a082015260c083015160c082015260e083015160e08201526101008084015181830152506101206139dd818501613929565b908201526101408381015190820152610160928301519281019290925250919050565b8082018281126000831280158216821582161715613a2057613a20613744565b505092915050565b8082028115828204841417610aff57610aff613744565b600082613a75577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b81810381811115610aff57610aff613744565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203613abe57613abe613744565b5060010190565b60e081526000613ad860e083018a6133a7565b63ffffffff989098166020830152506001600160a01b039586166040820152939094166060840152608083019190915260a082015290151560c090910152919050565b6001600160a01b0384168152826020820152606060408201526000613b4360608301846133a7565b95945050505050565b80516020808301519190811015613b8b577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8160200360031b1b821691505b50919050565b600060208284031215613ba357600080fd5b5051919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b600060208284031215613beb57600080fd5b81516113768161326d565b60008251613c08818460208701613383565b9190910192915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fdfea2646970667358221220fef42b85b97e95ca087836390d97d99307ec60b38cd20d26ea0f113c18a0660d64736f6c63430008180033","runtime-code":"0x6080604052600436106102fd5760003560e01c806391ad50391161018f578063b13aa2d6116100e1578063ca15c8731161008a578063dcf844a711610064578063dcf844a714610a50578063df36bb1314610a7d578063e00a83e014610a9357600080fd5b8063ca15c873146109dc578063ccc57490146109fc578063d547741f14610a3057600080fd5b8063bfc7c607116100bb578063bfc7c6071461091c578063c63ff8dd1461092f578063c79371b11461094f57600080fd5b8063b13aa2d6146108c5578063b250fe6b146108e5578063bf333f2c1461090557600080fd5b8063a3ec191a11610143578063ac11fb1a1161011d578063ac11fb1a14610844578063add98c7014610871578063affed0e01461089157600080fd5b8063a3ec191a146107f0578063a5bbe22b14610607578063aa9641ab1461082457600080fd5b8063926d7d7f11610174578063926d7d7f146107945780639c9545f0146107c8578063a217fddf146107db57600080fd5b806391ad5039146106d057806391d148541461075057600080fd5b806341fcb6121161025357806363787e52116101fc578063886d36ff116101d6578063886d36ff146106655780638f0d6f17146106855780639010d07c1461069857600080fd5b806363787e521461058c578063820688d5146106075780638379a24f1461061d57600080fd5b80635960ccf21161022d5780635960ccf21461050b5780635aa6ccba1461053f5780635eb7d9461461056c57600080fd5b806341fcb612146104c257806345851694146104e257806358f85880146104f557600080fd5b806318e4357d116102b5578063295710ff1161028f578063295710ff146104555780632f2ff15d1461048257806336568abe146104a257600080fd5b806318e4357d146103ee578063190da5951461040e578063248a9ca31461042557600080fd5b8063051287bc116102e6578063051287bc1461037957806306f333f2146103b65780630f5f6ed7146103d857600080fd5b806301ffc9a71461030257806303ed0ee514610337575b600080fd5b34801561030e57600080fd5b5061032261031d366004612eef565b610aa9565b60405190151581526020015b60405180910390f35b34801561034357600080fd5b5061036b7f043c983c49d46f0e102151eaf8085d4a2e6571d5df2d47b013f39bddfd4a639d81565b60405190815260200161032e565b34801561038557600080fd5b506103a9610394366004612f31565b60009081526005602052604090205460ff1690565b60405161032e9190612fb4565b3480156103c257600080fd5b506103d66103d1366004612fe2565b610b05565b005b3480156103e457600080fd5b5061036b61271081565b3480156103fa57600080fd5b506103d661040936600461301b565b610bcc565b34801561041a57600080fd5b5061036b62093a8081565b34801561043157600080fd5b5061036b610440366004612f31565b60009081526020819052604090206001015490565b34801561046157600080fd5b5061036b610470366004613054565b60076020526000908152604090205481565b34801561048e57600080fd5b506103d661049d366004613071565b610d39565b3480156104ae57600080fd5b506103d66104bd366004613071565b610d64565b3480156104ce57600080fd5b506103d66104dd366004613209565b610db0565b6103d66104f0366004613329565b611026565b34801561050157600080fd5b5061036b60025481565b34801561051757600080fd5b5061036b7fdb9556138406326f00296e13ea2ad7db24ba82381212d816b1a40c23b466b32781565b34801561054b57600080fd5b5061055f61055a366004613346565b611083565b60405161032e91906133d3565b34801561057857600080fd5b506103d6610587366004613346565b611149565b34801561059857600080fd5b506105f76105a7366004612f31565b60056020526000908152604090205460ff811690610100810464ffffffffff16906601000000000000810465ffffffffffff16906c0100000000000000000000000090046001600160a01b031684565b60405161032e94939291906134e8565b34801561061357600080fd5b5061036b61070881565b34801561062957600080fd5b50610322610638366004612f31565b6000908152600660205260409020546c0100000000000000000000000090046001600160a01b0316151590565b34801561067157600080fd5b506103d6610680366004613529565b61133e565b6103d6610693366004613346565b611354565b3480156106a457600080fd5b506106b86106b336600461356e565b61135e565b6040516001600160a01b03909116815260200161032e565b3480156106dc57600080fd5b506107246106eb366004612f31565b600090815260056020526040902054610100810464ffffffffff16916c010000000000000000000000009091046001600160a01b031690565b604080516bffffffffffffffffffffffff90931683526001600160a01b0390911660208301520161032e565b34801561075c57600080fd5b5061032261076b366004613071565b6000918252602082815260408084206001600160a01b0393909316845291905290205460ff1690565b3480156107a057600080fd5b5061036b7fe2b7fb3b832174769106daebcfd6d1970523240dda11281102db9363b83b0dc481565b6103d66107d6366004613209565b61137d565b3480156107e757600080fd5b5061036b600081565b3480156107fc57600080fd5b5061036b7f000000000000000000000000000000000000000000000000000000000000000081565b34801561083057600080fd5b5061032261083f366004613071565b611603565b34801561085057600080fd5b5061086461085f366004613346565b6116ee565b60405161032e9190613590565b34801561087d57600080fd5b506103d661088c366004612f31565b6118a6565b34801561089d57600080fd5b5061036b7f000000000000000000000000000000000000000000000000000000000000000081565b3480156108d157600080fd5b506103d66108e0366004612f31565b6119c8565b3480156108f157600080fd5b506103d6610900366004612f31565b611aaa565b34801561091157600080fd5b5061036b620f424081565b6103d661092a366004613676565b611b12565b34801561093b57600080fd5b506103d661094a366004613346565b611d94565b34801561095b57600080fd5b506109ae61096a366004612f31565b60066020526000908152604090205465ffffffffffff8082169166010000000000008104909116906c0100000000000000000000000090046001600160a01b031683565b6040805165ffffffffffff94851681529390921660208401526001600160a01b03169082015260600161032e565b3480156109e857600080fd5b5061036b6109f7366004612f31565b611d9f565b348015610a0857600080fd5b5061036b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f5581565b348015610a3c57600080fd5b506103d6610a4b366004613071565b611db6565b348015610a5c57600080fd5b5061036b610a6b366004613054565b60036020526000908152604090205481565b348015610a8957600080fd5b5061036b61ffff81565b348015610a9f57600080fd5b5061036b60045481565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f5a05180f000000000000000000000000000000000000000000000000000000001480610aff5750610aff82611ddb565b92915050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f55610b2f81611e72565b6001600160a01b03831660009081526003602052604081205490819003610b565750505050565b6001600160a01b038416600081815260036020526040812055610b7a908483611e7c565b604080516001600160a01b038087168252851660208201529081018290527f244e51bc38c1452fa8aaf487bcb4bca36c2baa3a5fbdb776b1eabd8dc6d277cd9060600160405180910390a1505b505050565b7fe2b7fb3b832174769106daebcfd6d1970523240dda11281102db9363b83b0dc4610bf681611e72565b600160008581526005602052604090205460ff166004811115610c1b57610c1b612f4a565b14610c52576040517f4145817200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600084815260056020908152604091829020805460027fffffffffffffffffffffffffffffffffffffffff0000000000000000000000009091166101004264ffffffffff16027fffffffffffffffffffffffffffffffffffffffff000000000000ffffffffffff161766010000000000004365ffffffffffff160217176bffffffffffffffffffffffff166c010000000000000000000000006001600160a01b0387169081029190911790915582518681529251909287927f4ac8af8a2cd87193d64dfc7a3b8d9923b714ec528b18725d080aa1299be0c5e492918290030190a350505050565b600082815260208190526040902060010154610d5481611e72565b610d5e8383611f9f565b50505050565b6001600160a01b0381163314610da6576040517f6697b23200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610bc78282611fd4565b815160208301206000610dc284611083565b9050600260008381526005602052604090205460ff166004811115610de957610de9612f4a565b14610e20576040517f4145817200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600160a01b038316610e5d576000828152600560205260409020546c0100000000000000000000000090046001600160a01b03169250610ebd565b6000828152600560205260409020546c0100000000000000000000000090046001600160a01b03163314610ebd576040517f4af43a9000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008281526005602052604090205461070890610100900464ffffffffff90811642031611610f18576040517f1992d0bd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600082815260056020526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016600317905561010081015115610f925761010081015160808201516001600160a01b031660009081526003602052604081208054909190610f8c908490613773565b90915550505b608081015160c0820151610fb06001600160a01b0383168683611e7c565b6000848152600560209081526040918290205482516001600160a01b038681168252928101859052888316936c010000000000000000000000009092049092169187917f582211c35a2139ac3bbaac74663c6a1f56c6cbb658b41fe11fd45a82074ac678910160405180910390a4505050505050565b611080816040518060a0016040528060006001600160a01b03168152602001600081526020016040518060200160405280600081525081526020016000815260200160405180602001604052806000815250815250611b12565b50565b611135604051806101e00160405280600063ffffffff168152602001600063ffffffff16815260200160006001600160a01b0316815260200160006001600160a01b0316815260200160006001600160a01b0316815260200160006001600160a01b0316815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160006001600160a01b0316815260200160008152602001606081525090565b81806020019051810190610aff91906137e1565b80516020820120600061115b83611083565b9050600160008381526005602052604090205460ff16600481111561118257611182612f4a565b146111b9576040517f4145817200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b3360009081527fd2043bf65931af3dbecf60d0db8f40e4160406d7beb00522f4200cf4944a1eb8602052604090205460ff161561123357806101400151421161122e576040517fe15ff9ea00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61127f565b62093a808161014001516112479190613773565b421161127f576040517fe15ff9ea00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008281526005602052604080822080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166004179055820151608083015161010084015160c0850151929391926112d89190613773565b90506112ee6001600160a01b0383168483611e7c565b604080516001600160a01b0384811682526020820184905285169187917fb4c55c0c9bc613519b920e88748090150b890a875d307f21bea7d4fb2e8bc958910160405180910390a3505050505050565b61135082805190602001208233610bcc565b5050565b611080813361137d565b60008281526001602052604081206113769083612001565b9392505050565b81516020830120600061138f84611083565b905061139c81838561200d565b604080516060808201835265ffffffffffff438116835242811660208085019182526001600160a01b0389811686880181815260008b815260068552899020975188549551915184166c01000000000000000000000000026bffffffffffffffffffffffff9288166601000000000000027fffffffffffffffffffffffffffffffffffffffff00000000000000000000000090971691909716179490941793909316939093179094558583015160a08088015160e08901516101208a01518a516080808d015160c0808f01518e5163ffffffff9095168552918b169c84019c909c52858a169c83019c909c529881019a909a52968901819052918801869052919691959094938716929189917ff8ae392d784b1ea5e8881bfa586d81abf07ef4f1e2fc75f7fe51c90f05199a5c910160405180910390a47fffffffffffffffffffffffff11111111111111111111111111111111111111126001600160a01b0384160161157957801561153b576040517f2598ad2e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b813414611574576040517f81de0bf300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6115c7565b8034146115b2576040517f81de0bf300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6115c76001600160a01b0384163386856121aa565b6101c085015151156115e9576115e4848484886101c00151612226565b6115f9565b34156115f9576115f98434612385565b5050505050505050565b6000600260008481526005602052604090205460ff16600481111561162a5761162a612f4a565b14611661576040517f4145817200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000838152600560205260409020546001600160a01b038381166c0100000000000000000000000090920416146116c4576040517f4af43a9000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b505060009081526005602052604090205461070861010090910464ffffffffff9081164203161190565b6040805161018081018252600080825260208201819052818301819052606082018190526080820181905260a0820181905260c0820181905260e0820181905261010082018190526101208201819052610140820181905261016082015290517f5aa6ccba0000000000000000000000000000000000000000000000000000000081523090635aa6ccba90611787908590600401613916565b600060405180830381865afa9250505080156117c557506040513d6000823e601f3d908101601f191682016040526117c291908101906137e1565b60015b6117dd5781806020019051810190610aff9190613934565b604051806101800160405280826000015163ffffffff168152602001826020015163ffffffff16815260200182604001516001600160a01b0316815260200182606001516001600160a01b0316815260200182608001516001600160a01b031681526020018260a001516001600160a01b031681526020018260c0015181526020018260e001518152602001826101000151815260200182610120015160001415151581526020018261014001518152602001826101600151815250915050919050565b919050565b7f043c983c49d46f0e102151eaf8085d4a2e6571d5df2d47b013f39bddfd4a639d6118d081611e72565b600260008381526005602052604090205460ff1660048111156118f5576118f5612f4a565b1461192c576040517f4145817200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008281526005602052604090205461070890610100900464ffffffffff9081164203161115611988576040517f3e908aac00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000828152600560205260408082206001905551339184917f0695cf1d39b3055dcd0fe02d8b47eaf0d5a13e1996de925de59d0ef9b7f7fad49190a35050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f556119f281611e72565b612710821115611a63576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f6e657746656552617465203e206d61780000000000000000000000000000000060448201526064015b60405180910390fd5b600280549083905560408051828152602081018590527f14914da2bf76024616fbe1859783fcd4dbddcb179b1f3a854949fbf920dcb95791015b60405180910390a1505050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f55611ad481611e72565b600480549083905560408051828152602081018590527f5cf09b12f3f56b4c564d51b25b40360af6d795198adb61ae0806a36c294323fa9101611a9d565b6000816020015142611b249190613a00565b9050611b3183838361244e565b6000611b4584606001518560a001516126d3565b90506000806002541115611b7257620f424060025483611b659190613a28565b611b6f9190613a3f565b90505b611b7c8183613a7a565b91506000604051806101e001604052804663ffffffff168152602001876000015163ffffffff16815260200187602001516001600160a01b0316815260200187604001516001600160a01b0316815260200187606001516001600160a01b0316815260200187608001516001600160a01b031681526020018481526020018760c0015181526020018381526020018660600151815260200187610100015181526020016007600089602001516001600160a01b03166001600160a01b031681526020019081526020016000206000815480929190611c5990613a8d565b91905055815260200186600001516001600160a01b031681526020018581526020018660800151815250604051602001611c9391906133d3565b60408051808303601f1901815282825280516020808301919091206000818152600583529390932080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016600117905589015189516060808c015160808d015160c08e0151928d015195985095966001600160a01b039094169587957f120ea0364f36cdac7983bcfdd55270ca09d7f9b314a2ebc425a3b01ab1d6403a95611d47958b95909493928e9290151590613ac5565b60405180910390a3807f3120e2bb59c86aca6890191a589a96af3662838efa374fbdcdf4c95bfe4a6c0e8760400151604051611d839190613916565b60405180910390a250505050505050565b611080816000610db0565b6000818152600160205260408120610aff906128b4565b600082815260208190526040902060010154611dd181611e72565b610d5e8383611fd4565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f7965db0b000000000000000000000000000000000000000000000000000000001480610aff57507f01ffc9a7000000000000000000000000000000000000000000000000000000007fffffffff00000000000000000000000000000000000000000000000000000000831614610aff565b61108081336128be565b306001600160a01b03831603611e9157505050565b80600003611e9e57505050565b7fffffffffffffffffffffffff11111111111111111111111111111111111111126001600160a01b03841601611f8b576000826001600160a01b03168260405160006040518083038185875af1925050503d8060008114611f1b576040519150601f19603f3d011682016040523d82523d6000602084013e611f20565b606091505b5050905080610d5e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f455448207472616e73666572206661696c6564000000000000000000000000006044820152606401611a5a565b610bc76001600160a01b038416838361292a565b600080611fac848461295b565b90508015611376576000848152600160205260409020611fcc9084612a23565b509392505050565b600080611fe18484612a38565b90508015611376576000848152600160205260409020611fcc9084612ad9565b60006113768383612aee565b6001600160a01b03811661204d576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000828152600660205260409020546c0100000000000000000000000090046001600160a01b0316156120ac576040517fbef7bb7d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b46836020015163ffffffff16146120ef576040517f7029fdf900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b82610140015142111561212e576040517f559895a300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6101808301516001600160a01b0316158015906121625750806001600160a01b03168361018001516001600160a01b031614155b80156121735750826101a001514211155b15610bc7576040517f14be123200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040516001600160a01b038481166024830152838116604483015260648201839052610d5e9186918216906323b872dd906084015b604051602081830303815290604052915060e01b6020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8381831617835250505050612b18565b600083838360405160240161223d93929190613b1b565b60408051601f198184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f461e0c2100000000000000000000000000000000000000000000000000000000179052905060006122a4868334612b94565b905080516000036122e1576040517f1a95ad2600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b805160201461231c576040517ff3725cca00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f461e0c210000000000000000000000000000000000000000000000000000000061234682613b4c565b1461237d576040517ff3725cca00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b505050505050565b804710156123c1576040517fcd786059000000000000000000000000000000000000000000000000000000008152306004820152602401611a5a565b6000826001600160a01b03168260405160006040518083038185875af1925050503d806000811461240e576040519150601f19603f3d011682016040523d82523d6000602084013e612413565b606091505b5050905080610bc7576040517f1425ea4200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b46836000015163ffffffff1603612491576040517f7029fdf900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60a083015115806124a4575060c0830151155b156124db576040517fe38820c800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60208301516001600160a01b03161580612500575060408301516001600160a01b0316155b15612537576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60608301516001600160a01b0316158061255c575060808301516001600160a01b0316155b15612593576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61259f61070842613773565b83610100015110156125dd576040517f04b7fcc800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61ffff826080015151111561261e576040517ffbe24d4900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b606082015115801590612651575060808301516001600160a01b031673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee145b15612688576040517f2598ad2e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008113158061269c575082610100015181135b15610bc7576040517f352807b900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60007fffffffffffffffffffffffff11111111111111111111111111111111111111126001600160a01b038416016127455734821461273e576040517f81de0bf300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5034610aff565b612757836001600160a01b0316612c4a565b341561278f576040517f81de0bf300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201526001600160a01b038416906370a0823190602401602060405180830381865afa1580156127ec573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128109190613b91565b90506128276001600160a01b0384163330856121aa565b6040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015281906001600160a01b038516906370a0823190602401602060405180830381865afa158015612886573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128aa9190613b91565b6113769190613a7a565b6000610aff825490565b6000828152602081815260408083206001600160a01b038516845290915290205460ff16611350576040517fe2517d3f0000000000000000000000000000000000000000000000000000000081526001600160a01b038216600482015260248101839052604401611a5a565b6040516001600160a01b03838116602483015260448201839052610bc791859182169063a9059cbb906064016121df565b6000828152602081815260408083206001600160a01b038516845290915281205460ff16612a1b576000838152602081815260408083206001600160a01b0386168452909152902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790556129d33390565b6001600160a01b0316826001600160a01b0316847f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a4506001610aff565b506000610aff565b6000611376836001600160a01b038416612cf0565b6000828152602081815260408083206001600160a01b038516845290915281205460ff1615612a1b576000838152602081815260408083206001600160a01b038616808552925280832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016905551339286917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a4506001610aff565b6000611376836001600160a01b038416612d37565b6000826000018281548110612b0557612b05613baa565b9060005260206000200154905092915050565b6000612b2d6001600160a01b03841683612e2a565b90508051600014158015612b52575080806020019051810190612b509190613bd9565b155b15610bc7576040517f5274afe70000000000000000000000000000000000000000000000000000000081526001600160a01b0384166004820152602401611a5a565b606081471015612bd2576040517fcd786059000000000000000000000000000000000000000000000000000000008152306004820152602401611a5a565b600080856001600160a01b03168486604051612bee9190613bf6565b60006040518083038185875af1925050503d8060008114612c2b576040519150601f19603f3d011682016040523d82523d6000602084013e612c30565b606091505b5091509150612c40868383612e38565b9695505050505050565b7fffffffffffffffffffffffff11111111111111111111111111111111111111126001600160a01b03821601612cac576040517f7f523fe800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b806001600160a01b03163b600003611080576040517f7f523fe800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000818152600183016020526040812054612a1b57508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155610aff565b60008181526001830160205260408120548015612e20576000612d5b600183613a7a565b8554909150600090612d6f90600190613a7a565b9050808214612dd4576000866000018281548110612d8f57612d8f613baa565b9060005260206000200154905080876000018481548110612db257612db2613baa565b6000918252602080832090910192909255918252600188019052604090208390555b8554869080612de557612de5613c12565b600190038181906000526020600020016000905590558560010160008681526020019081526020016000206000905560019350505050610aff565b6000915050610aff565b606061137683836000612b94565b606082612e4d57612e4882612ead565b611376565b8151158015612e6457506001600160a01b0384163b155b15612ea6576040517f9996b3150000000000000000000000000000000000000000000000000000000081526001600160a01b0385166004820152602401611a5a565b5080611376565b805115612ebd5780518082602001fd5b6040517f1425ea4200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600060208284031215612f0157600080fd5b81357fffffffff000000000000000000000000000000000000000000000000000000008116811461137657600080fd5b600060208284031215612f4357600080fd5b5035919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b60058110612fb0577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b9052565b60208101610aff8284612f79565b6001600160a01b038116811461108057600080fd5b80356118a181612fc2565b60008060408385031215612ff557600080fd5b823561300081612fc2565b9150602083013561301081612fc2565b809150509250929050565b60008060006060848603121561303057600080fd5b8335925060208401359150604084013561304981612fc2565b809150509250925092565b60006020828403121561306657600080fd5b813561137681612fc2565b6000806040838503121561308457600080fd5b82359150602083013561301081612fc2565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051610120810167ffffffffffffffff811182821017156130e9576130e9613096565b60405290565b60405160a0810167ffffffffffffffff811182821017156130e9576130e9613096565b6040516101e0810167ffffffffffffffff811182821017156130e9576130e9613096565b604051610180810167ffffffffffffffff811182821017156130e9576130e9613096565b604051601f8201601f1916810167ffffffffffffffff8111828210171561318357613183613096565b604052919050565b600067ffffffffffffffff8211156131a5576131a5613096565b50601f01601f191660200190565b600082601f8301126131c457600080fd5b81356131d76131d28261318b565b61315a565b8181528460208386010111156131ec57600080fd5b816020850160208301376000918101602001919091529392505050565b6000806040838503121561321c57600080fd5b823567ffffffffffffffff81111561323357600080fd5b61323f858286016131b3565b925050602083013561301081612fc2565b63ffffffff8116811461108057600080fd5b80356118a181613250565b801515811461108057600080fd5b80356118a18161326d565b6000610120828403121561329957600080fd5b6132a16130c5565b90506132ac82613262565b81526132ba60208301612fd7565b60208201526132cb60408301612fd7565b60408201526132dc60608301612fd7565b60608201526132ed60808301612fd7565b608082015260a082013560a082015260c082013560c082015261331260e0830161327b565b60e082015261010080830135818301525092915050565b6000610120828403121561333c57600080fd5b6113768383613286565b60006020828403121561335857600080fd5b813567ffffffffffffffff81111561336f57600080fd5b61337b848285016131b3565b949350505050565b60005b8381101561339e578181015183820152602001613386565b50506000910152565b600081518084526133bf816020860160208601613383565b601f01601f19169290920160200192915050565b602081526133ea60208201835163ffffffff169052565b60006020830151613403604084018263ffffffff169052565b5060408301516001600160a01b03811660608401525060608301516001600160a01b03811660808401525060808301516001600160a01b03811660a08401525060a08301516001600160a01b03811660c08401525060c083015160e08381019190915283015161010080840191909152830151610120808401919091528301516101408084019190915283015161016080840191909152830151610180808401919091528301516101a06134c1818501836001600160a01b03169052565b8401516101c0848101919091528401516101e080850152905061337b6102008401826133a7565b608081016134f68287612f79565b64ffffffffff8516602083015265ffffffffffff841660408301526001600160a01b038316606083015295945050505050565b6000806040838503121561353c57600080fd5b823567ffffffffffffffff81111561355357600080fd5b61355f858286016131b3565b95602094909401359450505050565b6000806040838503121561358157600080fd5b50508035926020909101359150565b815163ffffffff168152610180810160208301516135b6602084018263ffffffff169052565b5060408301516135d160408401826001600160a01b03169052565b5060608301516135ec60608401826001600160a01b03169052565b50608083015161360760808401826001600160a01b03169052565b5060a083015161362260a08401826001600160a01b03169052565b5060c083015160c083015260e083015160e0830152610100808401518184015250610120808401516136578285018215159052565b5050610140838101519083015261016092830151929091019190915290565b600080610140838503121561368a57600080fd5b6136948484613286565b915061012083013567ffffffffffffffff808211156136b257600080fd5b9084019060a082870312156136c657600080fd5b6136ce6130ef565b82356136d981612fc2565b8152602083810135908201526040830135828111156136f757600080fd5b613703888286016131b3565b6040830152506060830135606082015260808301358281111561372557600080fd5b613731888286016131b3565b6080830152508093505050509250929050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b80820180821115610aff57610aff613744565b80516118a181613250565b80516118a181612fc2565b600082601f8301126137ad57600080fd5b81516137bb6131d28261318b565b8181528460208386010111156137d057600080fd5b61337b826020830160208701613383565b6000602082840312156137f357600080fd5b815167ffffffffffffffff8082111561380b57600080fd5b908301906101e0828603121561382057600080fd5b613828613112565b61383183613786565b815261383f60208401613786565b602082015261385060408401613791565b604082015261386160608401613791565b606082015261387260808401613791565b608082015261388360a08401613791565b60a082015260c0838101519082015260e0808401519082015261010080840151908201526101208084015190820152610140808401519082015261016080840151908201526101806138d6818501613791565b908201526101a083810151908201526101c080840151838111156138f957600080fd5b6139058882870161379c565b918301919091525095945050505050565b60208152600061137660208301846133a7565b80516118a18161326d565b6000610180828403121561394757600080fd5b61394f613136565b61395883613786565b815261396660208401613786565b602082015261397760408401613791565b604082015261398860608401613791565b606082015261399960808401613791565b60808201526139aa60a08401613791565b60a082015260c083015160c082015260e083015160e08201526101008084015181830152506101206139dd818501613929565b908201526101408381015190820152610160928301519281019290925250919050565b8082018281126000831280158216821582161715613a2057613a20613744565b505092915050565b8082028115828204841417610aff57610aff613744565b600082613a75577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b81810381811115610aff57610aff613744565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203613abe57613abe613744565b5060010190565b60e081526000613ad860e083018a6133a7565b63ffffffff989098166020830152506001600160a01b039586166040820152939094166060840152608083019190915260a082015290151560c090910152919050565b6001600160a01b0384168152826020820152606060408201526000613b4360608301846133a7565b95945050505050565b80516020808301519190811015613b8b577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8160200360031b1b821691505b50919050565b600060208284031215613ba357600080fd5b5051919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b600060208284031215613beb57600080fd5b81516113768161326d565b60008251613c08818460208701613383565b9190910192915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fdfea2646970667358221220fef42b85b97e95ca087836390d97d99307ec60b38cd20d26ea0f113c18a0660d64736f6c63430008180033","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.24 ^0.8.0 ^0.8.20;\n\n// contracts/interfaces/IAdmin.sol\n\ninterface IAdmin {\n // ============ Events ============\n\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n event ChainGasAmountUpdated(uint256 oldChainGasAmount, uint256 newChainGasAmount);\n\n // ============ Methods ============\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n\n function setChainGasAmount(uint256 newChainGasAmount) external;\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IFastBridgeRecipient.sol\n\ninterface IFastBridgeRecipient {\n function fastBridgeTransferReceived(\n address token,\n uint256 amount,\n bytes memory callParams\n )\n external\n payable\n returns (bytes4);\n}\n\n// contracts/interfaces/IFastBridgeV2Errors.sol\n\ninterface IFastBridgeV2Errors {\n error AmountIncorrect();\n error CallParamsLengthAboveMax();\n error ChainIncorrect();\n error ExclusivityParamsIncorrect();\n error MsgValueIncorrect();\n error NativeTokenCallValueNotSupported();\n error SenderIncorrect();\n error StatusIncorrect();\n error ZeroAddress();\n\n error RecipientIncorrectReturnValue();\n error RecipientNoReturnValue();\n\n error DeadlineExceeded();\n error DeadlineNotExceeded();\n error DeadlineTooShort();\n error DisputePeriodNotPassed();\n error DisputePeriodPassed();\n error ExclusivityPeriodNotPassed();\n\n error TransactionRelayed();\n}\n\n// contracts/libs/Errors.sol\n\nerror DeadlineExceeded();\nerror DeadlineNotExceeded();\nerror DeadlineTooShort();\nerror InsufficientOutputAmount();\n\nerror MsgValueIncorrect();\nerror PoolNotFound();\nerror TokenAddressMismatch();\nerror TokenNotContract();\nerror TokenNotETH();\nerror TokensIdentical();\n\nerror ChainIncorrect();\nerror AmountIncorrect();\nerror ZeroAddress();\n\nerror DisputePeriodNotPassed();\nerror DisputePeriodPassed();\nerror SenderIncorrect();\nerror StatusIncorrect();\nerror TransactionIdIncorrect();\nerror TransactionRelayed();\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// contracts/interfaces/IFastBridgeV2.sol\n\ninterface IFastBridgeV2 is IFastBridge {\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n struct BridgeTxDetails {\n BridgeStatus status;\n uint40 proofBlockTimestamp;\n uint48 proofBlockNumber;\n address proofRelayer;\n }\n\n struct BridgeRelay {\n uint48 blockNumber;\n uint48 blockTimestamp;\n address relayer;\n }\n\n /// @notice New params introduced in the FastBridgeV2.\n /// We are passing fields from the older BridgeParams struct outside of this struct\n /// for backwards compatibility.\n /// Note: quoteRelayer and quoteExclusivitySeconds are either both zero (indicating no exclusivity)\n /// or both non-zero (indicating exclusivity for the given period).\n /// Note: callValue \u003e 0 can NOT be used with destToken = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE (ETH_ADDRESS)\n /// @param quoteRelayer Relayer that provided the quote for the transaction\n /// @param quoteExclusivitySeconds Period of time the quote relayer is guaranteed exclusivity after user's deposit\n /// @param quoteId Unique quote identifier used for tracking the quote\n /// @param callValue ETH value to send to the recipient (if any)\n /// @param callParams Parameters for the arbitrary call to the destination recipient (if any)\n struct BridgeParamsV2 {\n address quoteRelayer;\n int256 quoteExclusivitySeconds;\n bytes quoteId;\n uint256 callValue;\n bytes callParams;\n }\n\n /// @notice Updated bridge transaction struct to include parameters introduced in FastBridgeV2.\n /// Note: only `exclusivityRelayer` can fill such a transaction until `exclusivityEndTime`.\n /// TODO: consider changing the encoding scheme to prevent spending extra gas on decoding.\n struct BridgeTransactionV2 {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n uint256 callValue; // ETH value to send to the recipient (if any) - replaces V1's sendChainGas flag\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n address exclusivityRelayer;\n uint256 exclusivityEndTime;\n bytes callParams;\n }\n\n event BridgeQuoteDetails(bytes32 indexed transactionId, bytes quoteId);\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability\n /// to provide temporary exclusivity fill rights for the quote relayer.\n /// @param params The parameters required to bridge\n /// @param paramsV2 The parameters for exclusivity fill rights (optional, can be left empty)\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function relay(bytes memory request, address relayer) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param transactionId The transaction id associated with the encoded bridge transaction to prove\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital.\n /// @notice Can only send funds to the relayer address on the proof.\n /// @param request The encoded bridge transaction to claim on origin chain\n function claim(bytes memory request) external;\n /// @notice Checks if a transaction has been relayed\n /// @param transactionId The ID of the transaction to check\n /// @return True if the transaction has been relayed, false otherwise\n function bridgeRelays(bytes32 transactionId) external view returns (bool);\n\n /// @notice Returns the status of a bridge transaction\n /// @param transactionId The ID of the bridge transaction\n /// @return BridgeStatus Status of the bridge transaction\n function bridgeStatuses(bytes32 transactionId) external view returns (BridgeStatus);\n\n /// @notice Returns the timestamp and relayer of a bridge proof\n /// @param transactionId The ID of the bridge transaction\n /// @return timestamp The timestamp of the bridge proof\n /// @return relayer The relayer address of the bridge proof\n function bridgeProofs(bytes32 transactionId) external view returns (uint96 timestamp, address relayer);\n\n /// @notice Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\n /// @param request The bridge request to decode\n function getBridgeTransactionV2(bytes memory request) external view returns (BridgeTransactionV2 memory);\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// contracts/libs/UniversalToken.sol\n\nlibrary UniversalTokenLib {\n using SafeERC20 for IERC20;\n\n address internal constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Transfers tokens to the given account. Reverts if transfer is not successful.\n /// @dev This might trigger fallback, if ETH is transferred to the contract.\n /// Make sure this can not lead to reentrancy attacks.\n function universalTransfer(address token, address to, uint256 value) internal {\n // Don't do anything, if need to send tokens to this address\n if (to == address(this)) return;\n // Don't do anything, if trying to send zero value\n if (value == 0) return;\n if (token == ETH_ADDRESS) {\n /// @dev Note: this can potentially lead to executing code in `to`.\n // solhint-disable-next-line avoid-low-level-calls\n (bool success,) = to.call{value: value}(\"\");\n require(success, \"ETH transfer failed\");\n } else {\n IERC20(token).safeTransfer(to, value);\n }\n }\n\n /// @notice Issues an infinite allowance to the spender, if the current allowance is insufficient\n /// to spend the given amount.\n function universalApproveInfinity(address token, address spender, uint256 amountToSpend) internal {\n // ETH Chad doesn't require your approval\n if (token == ETH_ADDRESS) return;\n // No-op if allowance is already sufficient\n uint256 allowance = IERC20(token).allowance(address(this), spender);\n if (allowance \u003e= amountToSpend) return;\n // Otherwise, reset approval to 0 and set to max allowance\n if (allowance \u003e 0) IERC20(token).safeDecreaseAllowance(spender, allowance);\n IERC20(token).safeIncreaseAllowance(spender, type(uint256).max);\n }\n\n /// @notice Returns the balance of the given token (or native ETH) for the given account.\n function universalBalanceOf(address token, address account) internal view returns (uint256) {\n if (token == ETH_ADDRESS) {\n return account.balance;\n } else {\n return IERC20(token).balanceOf(account);\n }\n }\n\n /// @dev Checks that token is a contract and not ETH_ADDRESS.\n function assertIsContract(address token) internal view {\n // Check that ETH_ADDRESS was not used (in case this is a predeploy on any of the chains)\n if (token == UniversalTokenLib.ETH_ADDRESS) revert TokenNotContract();\n // Check that token is not an EOA\n if (token.code.length == 0) revert TokenNotContract();\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/Admin.sol\n\ncontract Admin is IAdmin, AccessControlEnumerable {\n using UniversalTokenLib for address;\n\n bytes32 public constant RELAYER_ROLE = keccak256(\"RELAYER_ROLE\");\n bytes32 public constant REFUNDER_ROLE = keccak256(\"REFUNDER_ROLE\");\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n uint256 public constant FEE_BPS = 1e6;\n uint256 public constant FEE_RATE_MAX = 0.01e6; // max 1% on origin amount\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Chain gas amount to forward as rebate if requested\n uint256 public chainGasAmount;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n }\n\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n require(newFeeRate \u003c= FEE_RATE_MAX, \"newFeeRate \u003e max\");\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n token.universalTransfer(recipient, feeAmount);\n emit FeesSwept(token, recipient, feeAmount);\n }\n\n function setChainGasAmount(uint256 newChainGasAmount) external onlyRole(GOVERNOR_ROLE) {\n uint256 oldChainGasAmount = chainGasAmount;\n chainGasAmount = newChainGasAmount;\n emit ChainGasAmountUpdated(oldChainGasAmount, newChainGasAmount);\n }\n}\n\n// contracts/FastBridgeV2.sol\n\n/// @notice FastBridgeV2 is a contract for bridging tokens across chains.\ncontract FastBridgeV2 is Admin, IFastBridgeV2, IFastBridgeV2Errors {\n using SafeERC20 for IERC20;\n using UniversalTokenLib for address;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Delay for a transaction after which it could be permisionlessly refunded\n uint256 public constant REFUND_DELAY = 7 days;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n /// @notice Maximum length of accepted callParams\n uint256 public constant MAX_CALL_PARAMS_LENGTH = 2 ** 16 - 1;\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeTxDetails) public bridgeTxDetails;\n /// @notice Relay details on destination chain\n mapping(bytes32 =\u003e BridgeRelay) public bridgeRelayDetails;\n /// @notice Unique bridge nonces tracked per originSender\n mapping(address =\u003e uint256) public senderNonces;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Replaced by senderNonces\n uint256 public immutable nonce = 0;\n /// @notice the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n bridge({\n params: params,\n paramsV2: BridgeParamsV2({\n quoteRelayer: address(0),\n quoteExclusivitySeconds: 0,\n quoteId: bytes(\"\"),\n callValue: 0,\n callParams: bytes(\"\")\n })\n });\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes memory request) external payable {\n relay({request: request, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes memory request, bytes32 destTxHash) external {\n prove({transactionId: keccak256(request), destTxHash: destTxHash, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridgeV2\n function claim(bytes memory request) external {\n claim({request: request, to: address(0)});\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003e DISPUTE_PERIOD) {\n revert DisputePeriodPassed();\n }\n\n // @dev relayer gets slashed effectively if dest relay has gone thru\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n bridgeTxDetails[transactionId].proofRelayer = address(0);\n bridgeTxDetails[transactionId].proofBlockTimestamp = 0;\n bridgeTxDetails[transactionId].proofBlockNumber = 0;\n\n emit BridgeProofDisputed(transactionId, msg.sender);\n }\n\n /// @inheritdoc IFastBridge\n function refund(bytes memory request) external {\n bytes32 transactionId = keccak256(request);\n\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n\n if (bridgeTxDetails[transactionId].status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n\n if (hasRole(REFUNDER_ROLE, msg.sender)) {\n // Refunder can refund if deadline has passed\n if (block.timestamp \u003c= transaction.deadline) revert DeadlineNotExceeded();\n } else {\n // Permissionless refund is allowed after REFUND_DELAY\n if (block.timestamp \u003c= transaction.deadline + REFUND_DELAY) revert DeadlineNotExceeded();\n }\n\n // if all checks passed, set to REFUNDED status\n bridgeTxDetails[transactionId].status = BridgeStatus.REFUNDED;\n\n // transfer origin collateral back to original sender\n address to = transaction.originSender;\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount + transaction.originFeeAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (bridgeTxDetails[transactionId].proofRelayer != relayer) revert SenderIncorrect();\n return _timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n /// @dev This method is added to achieve backwards compatibility with decoding requests into V1 structs:\n /// - `callValue` is partially reported as a zero/non-zero flag\n /// - `callParams` is ignored\n /// In order to process all kinds of requests use getBridgeTransactionV2 instead.\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory) {\n // Try decoding into V2 struct first. This will revert if V1 struct is passed\n try this.getBridgeTransactionV2(request) returns (BridgeTransactionV2 memory txV2) {\n // Note: we entirely ignore the callParams field, as it was not present in V1\n return BridgeTransaction({\n originChainId: txV2.originChainId,\n destChainId: txV2.destChainId,\n originSender: txV2.originSender,\n destRecipient: txV2.destRecipient,\n originToken: txV2.originToken,\n destToken: txV2.destToken,\n originAmount: txV2.originAmount,\n destAmount: txV2.destAmount,\n originFeeAmount: txV2.originFeeAmount,\n sendChainGas: txV2.callValue != 0,\n deadline: txV2.deadline,\n nonce: txV2.nonce\n });\n } catch {\n // Fallback to V1 struct\n return abi.decode(request, (BridgeTransaction));\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) public payable {\n int256 exclusivityEndTime = int256(block.timestamp) + paramsV2.quoteExclusivitySeconds;\n _validateBridgeParams(params, paramsV2, exclusivityEndTime);\n\n // transfer tokens to bridge contract\n /// @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _takeBridgedUserAsset(params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n\n // set status to requested\n bytes memory request = abi.encode(\n BridgeTransactionV2({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n callValue: paramsV2.callValue,\n deadline: params.deadline,\n nonce: senderNonces[params.sender]++, // increment nonce on every bridge\n exclusivityRelayer: paramsV2.quoteRelayer,\n // We checked exclusivityEndTime to be in range (0 .. params.deadline] above, so can safely cast\n exclusivityEndTime: uint256(exclusivityEndTime),\n callParams: paramsV2.callParams\n })\n );\n bytes32 transactionId = keccak256(request);\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n\n emit BridgeRequested({\n transactionId: transactionId,\n sender: params.sender,\n request: request,\n destChainId: params.dstChainId,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n sendChainGas: paramsV2.callValue != 0\n });\n emit BridgeQuoteDetails(transactionId, paramsV2.quoteId);\n }\n\n /// @inheritdoc IFastBridgeV2\n function relay(bytes memory request, address relayer) public payable {\n bytes32 transactionId = keccak256(request);\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n _validateRelayParams(transaction, transactionId, relayer);\n // mark bridge transaction as relayed\n bridgeRelayDetails[transactionId] =\n BridgeRelay({blockNumber: uint48(block.number), blockTimestamp: uint48(block.timestamp), relayer: relayer});\n\n // transfer tokens to recipient on destination chain and do an arbitrary call if requested\n address to = transaction.destRecipient;\n address token = transaction.destToken;\n uint256 amount = transaction.destAmount;\n uint256 callValue = transaction.callValue;\n\n // Emit the event before any external calls\n emit BridgeRelayed({\n transactionId: transactionId,\n relayer: relayer,\n to: to,\n originChainId: transaction.originChainId,\n originToken: transaction.originToken,\n destToken: token,\n originAmount: transaction.originAmount,\n destAmount: amount,\n chainGasAmount: callValue\n });\n\n // All state changes have been done at this point, can proceed to the external calls.\n // This follows the checks-effects-interactions pattern to mitigate potential reentrancy attacks.\n if (token == UniversalTokenLib.ETH_ADDRESS) {\n // For ETH non-zero callValue is not allowed\n if (callValue != 0) revert NativeTokenCallValueNotSupported();\n // Check that the correct msg.value was sent\n if (msg.value != amount) revert MsgValueIncorrect();\n } else {\n // For ERC20s, we check that the correct msg.value was sent\n if (msg.value != callValue) revert MsgValueIncorrect();\n // We need to transfer the tokens from the Relayer to the recipient first before performing an\n // optional post-transfer arbitrary call.\n IERC20(token).safeTransferFrom(msg.sender, to, amount);\n }\n\n if (transaction.callParams.length != 0) {\n // Arbitrary call requested, perform it while supplying full msg.value to the recipient\n // Note: if token has a fee on transfers, the recipient will have received less than `amount`.\n // This is a very niche edge case and should be handled by the recipient contract.\n _checkedCallRecipient({recipient: to, token: token, amount: amount, callParams: transaction.callParams});\n } else if (msg.value != 0) {\n // No arbitrary call requested, but msg.value was sent. This is either a relay with ETH,\n // or a non-zero callValue request with an ERC20. In both cases, transfer the ETH to the recipient.\n Address.sendValue(payable(to), msg.value);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) public onlyRole(RELAYER_ROLE) {\n // update bridge tx status given proof provided\n if (bridgeTxDetails[transactionId].status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n bridgeTxDetails[transactionId].status = BridgeStatus.RELAYER_PROVED;\n bridgeTxDetails[transactionId].proofBlockTimestamp = uint40(block.timestamp);\n bridgeTxDetails[transactionId].proofBlockNumber = uint48(block.number);\n bridgeTxDetails[transactionId].proofRelayer = relayer;\n\n emit BridgeProofProvided(transactionId, relayer, destTxHash);\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes memory request, address to) public {\n bytes32 transactionId = keccak256(request);\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n\n // update bridge tx status if able to claim origin collateral\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n\n // if \"to\" is zero addr, permissionlessly send funds to proven relayer\n if (to == address(0)) {\n to = bridgeTxDetails[transactionId].proofRelayer;\n } else if (bridgeTxDetails[transactionId].proofRelayer != msg.sender) {\n revert SenderIncorrect();\n }\n\n if (_timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003c= DISPUTE_PERIOD) {\n revert DisputePeriodNotPassed();\n }\n\n bridgeTxDetails[transactionId].status = BridgeStatus.RELAYER_CLAIMED;\n\n // update protocol fees if origin fee amount exists\n if (transaction.originFeeAmount \u003e 0) protocolFees[transaction.originToken] += transaction.originFeeAmount;\n\n // transfer origin collateral less fee to specified address\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositClaimed(transactionId, bridgeTxDetails[transactionId].proofRelayer, to, token, amount);\n }\n\n function bridgeStatuses(bytes32 transactionId) public view returns (BridgeStatus status) {\n return bridgeTxDetails[transactionId].status;\n }\n\n function bridgeProofs(bytes32 transactionId) public view returns (uint96 timestamp, address relayer) {\n timestamp = bridgeTxDetails[transactionId].proofBlockTimestamp;\n relayer = bridgeTxDetails[transactionId].proofRelayer;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeRelays(bytes32 transactionId) public view returns (bool) {\n // has this transactionId been relayed?\n return bridgeRelayDetails[transactionId].relayer != address(0);\n }\n\n /// @inheritdoc IFastBridgeV2\n function getBridgeTransactionV2(bytes memory request) public pure returns (BridgeTransactionV2 memory) {\n return abi.decode(request, (BridgeTransactionV2));\n }\n\n /// @notice Takes the bridged asset from the user into FastBridgeV2 custody. It will be later\n /// claimed by the relayer who completed the relay on destination chain, or refunded back to the user,\n /// should no one complete the relay.\n function _takeBridgedUserAsset(address token, uint256 amount) internal returns (uint256 amountTaken) {\n if (token == UniversalTokenLib.ETH_ADDRESS) {\n // For ETH we just need to check that the supplied msg.value is correct.\n // Supplied `msg.value` is already in FastBridgeV2 custody.\n if (amount != msg.value) revert MsgValueIncorrect();\n amountTaken = msg.value;\n } else {\n // For ERC20s, token is explicitly transferred from the user to FastBridgeV2.\n // We don't allow non-zero `msg.value` to avoid extra funds from being stuck in FastBridgeV2.\n token.assertIsContract();\n if (msg.value != 0) revert MsgValueIncorrect();\n amountTaken = IERC20(token).balanceOf(address(this));\n IERC20(token).safeTransferFrom(msg.sender, address(this), amount);\n // Use the balance difference as the amount taken in case of fee on transfer tokens.\n amountTaken = IERC20(token).balanceOf(address(this)) - amountTaken;\n }\n }\n\n /// @notice Calls the Recipient's hook function with the specified callParams and performs\n /// all the necessary checks for the returned value.\n function _checkedCallRecipient(\n address recipient,\n address token,\n uint256 amount,\n bytes memory callParams\n )\n internal\n {\n bytes memory hookData =\n abi.encodeCall(IFastBridgeRecipient.fastBridgeTransferReceived, (token, amount, callParams));\n // This will bubble any revert messages from the hook function\n bytes memory returnData = Address.functionCallWithValue({target: recipient, data: hookData, value: msg.value});\n // Explicit revert if no return data at all\n if (returnData.length == 0) revert RecipientNoReturnValue();\n // Check that exactly a single return value was returned\n if (returnData.length != 32) revert RecipientIncorrectReturnValue();\n // Return value should be abi-encoded hook function selector\n if (bytes32(returnData) != bytes32(IFastBridgeRecipient.fastBridgeTransferReceived.selector)) {\n revert RecipientIncorrectReturnValue();\n }\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint40(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint40).max but\n /// proof.timestamp \u003c type(uint40).max via unchecked statement\n /// @param proofBlockTimestamp The bridge proof block timestamp\n /// @return delta Time delta since proof submitted\n function _timeSince(uint40 proofBlockTimestamp) internal view returns (uint256 delta) {\n unchecked {\n delta = uint40(block.timestamp) - proofBlockTimestamp;\n }\n }\n\n /// @notice Performs all the necessary checks for a bridge to happen.\n /// @dev There's no good way to refactor this function to reduce cyclomatic complexity due to\n /// the number of checks that need to be performed, so we skip the code-complexity rule here.\n // solhint-disable-next-line code-complexity\n function _validateBridgeParams(\n BridgeParams memory params,\n BridgeParamsV2 memory paramsV2,\n int256 exclusivityEndTime\n )\n internal\n view\n {\n // Check V1 (legacy) params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.sender == address(0) || params.to == address(0)) revert ZeroAddress();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n // Check V2 params\n if (paramsV2.callParams.length \u003e MAX_CALL_PARAMS_LENGTH) revert CallParamsLengthAboveMax();\n if (paramsV2.callValue != 0 \u0026\u0026 params.destToken == UniversalTokenLib.ETH_ADDRESS) {\n revert NativeTokenCallValueNotSupported();\n }\n // exclusivityEndTime must be in range (0 .. params.deadline]\n if (exclusivityEndTime \u003c= 0 || exclusivityEndTime \u003e int256(params.deadline)) {\n revert ExclusivityParamsIncorrect();\n }\n }\n\n /// @notice Performs all the necessary checks for a relay to happen.\n function _validateRelayParams(\n BridgeTransactionV2 memory transaction,\n bytes32 transactionId,\n address relayer\n )\n internal\n view\n {\n if (relayer == address(0)) revert ZeroAddress();\n // Check if the transaction has already been relayed\n if (bridgeRelays(transactionId)) revert TransactionRelayed();\n if (transaction.destChainId != block.chainid) revert ChainIncorrect();\n // Check the deadline for relay to happen\n if (block.timestamp \u003e transaction.deadline) revert DeadlineExceeded();\n // Check the exclusivity period, if it is still ongoing\n // forgefmt: disable-next-item\n if (\n transaction.exclusivityRelayer != address(0) \u0026\u0026\n transaction.exclusivityRelayer != relayer \u0026\u0026\n block.timestamp \u003c= transaction.exclusivityEndTime\n ) {\n revert ExclusivityPeriodNotPassed();\n }\n }\n}\n","language":"Solidity","languageVersion":"0.8.24","compilerVersion":"0.8.24","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"64760:20167:0:-:0;;;65906:1;65873:34;;66011:85;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;66045:6;63675:38;52847:4;66045:6;63675:10;:38::i;:::-;-1:-1:-1;;66077:12:0::1;66063:26;::::0;-1:-1:-1;64760:20167:0;;62160:257;62246:4;;62277:31;62294:4;62300:7;62277:16;:31::i;:::-;62262:46;;62322:7;62318:69;;;62345:18;;;;:12;:18;;;;;:31;;62368:7;62345:22;:31::i;:::-;;62318:69;62403:7;-1:-1:-1;62160:257:0;;;;;:::o;56794:316::-;56871:4;53569:12;;;;;;;;;;;-1:-1:-1;;;;;53569:29:0;;;;;;;;;;;;56887:217;;56930:6;:12;;;;;;;;;;;-1:-1:-1;;;;;56930:29:0;;;;;;;;;:36;;-1:-1:-1;;56930:36:0;56962:4;56930:36;;;57012:12;23368:10;;23289:96;57012:12;-1:-1:-1;;;;;56985:40:0;57003:7;-1:-1:-1;;;;;56985:40:0;56997:4;56985:40;;;;;;;;;;-1:-1:-1;57046:4:0;57039:11;;56887:217;-1:-1:-1;57088:5:0;57081:12;;32813:150;32883:4;32906:50;32911:3;-1:-1:-1;;;;;32931:23:0;;26801:4;28857:21;;;:14;;;:21;;;;;;26817:321;;-1:-1:-1;26859:23:0;;;;;;;;:11;:23;;;;;;;;;;;;;27041:18;;27017:21;;;:14;;;:21;;;;;;:42;;;;27073:11;;14:290:1;84:6;137:2;125:9;116:7;112:23;108:32;105:52;;;153:1;150;143:12;105:52;179:16;;-1:-1:-1;;;;;224:31:1;;214:42;;204:70;;270:1;267;260:12;14:290;64760:20167:0;;;;;;;;;;;;;;;;;;","srcMapRuntime":"64760:20167:0:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;60820:212;;;;;;;;;;-1:-1:-1;60820:212:0;;;;;:::i;:::-;;:::i;:::-;;;612:14:1;;605:22;587:41;;575:2;560:18;60820:212:0;;;;;;;;63050:60;;;;;;;;;;;;63087:23;63050:60;;;;;785:25:1;;;773:2;758:18;63050:60:0;639:177:1;78427:150:0;;;;;;;;;;-1:-1:-1;78427:150:0;;;;;:::i;:::-;78495:19;78533:30;;;:15;:30;;;;;:37;;;;78427:150;;;;;;;;:::i;64022:359::-;;;;;;;;;;-1:-1:-1;64022:359:0;;;;;:::i;:::-;;:::i;:::-;;63232:45;;;;;;;;;;;;63271:6;63232:45;;76321:648;;;;;;;;;;-1:-1:-1;76321:648:0;;;;;:::i;:::-;;:::i;65110:45::-;;;;;;;;;;;;65149:6;65110:45;;54425:120;;;;;;;;;;-1:-1:-1;54425:120:0;;;;;:::i;:::-;54490:7;54516:12;;;;;;;;;;:22;;;;54425:120;65722:47;;;;;;;;;;-1:-1:-1;65722:47:0;;;;;:::i;:::-;;;;;;;;;;;;;;54841:136;;;;;;;;;;-1:-1:-1;54841:136:0;;;;;:::i;:::-;;:::i;55943:245::-;;;;;;;;;;-1:-1:-1;55943:245:0;;;;;:::i;:::-;;:::i;77007:1414::-;;;;;;;;;;-1:-1:-1;77007:1414:0;;;;;:::i;:::-;;:::i;66134:369::-;;;;;;:::i;:::-;;:::i;63394:30::-;;;;;;;;;;;;;;;;62978:66;;;;;;;;;;;;63018:26;62978:66;;79105:169;;;;;;;;;;-1:-1:-1;79105:169:0;;;;;:::i;:::-;;:::i;:::-;;;;;;;:::i;67821:1169::-;;;;;;;;;;-1:-1:-1;67821:1169:0;;;;;:::i;:::-;;:::i;65482:58::-;;;;;;;;;;-1:-1:-1;65482:58:0;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;65482:58:0;;;;;;;;;;;;;:::i;65242:56::-;;;;;;;;;;;;65288:10;65242:56;;78866:199;;;;;;;;;;-1:-1:-1;78866:199:0;;;;;:::i;:::-;78932:4;79003:33;;;:18;:33;;;;;:41;;;;-1:-1:-1;;;;;79003:41:0;:55;;;78866:199;66696:170;;;;;;;;;;-1:-1:-1;66696:170:0;;;;;:::i;:::-;;:::i;66541:117::-;;;;;;:::i;:::-;;:::i;61617:142::-;;;;;;;;;;-1:-1:-1;61617:142:0;;;;;:::i;:::-;;:::i;:::-;;;-1:-1:-1;;;;;12205:55:1;;;12187:74;;12175:2;12160:18;61617:142:0;12041:226:1;78583:243:0;;;;;;;;;;-1:-1:-1;78583:243:0;;;;;:::i;:::-;78649:16;78706:30;;;:15;:30;;;;;:50;;;;;;;78776:43;;;;-1:-1:-1;;;;;78776:43:0;;78583:243;;;;;12474:26:1;12462:39;;;12444:58;;-1:-1:-1;;;;;12538:55:1;;;12533:2;12518:18;;12511:83;12417:18;78583:243:0;12272:328:1;53469:136:0;;;;;;;;;;-1:-1:-1;53469:136:0;;;;;:::i;:::-;53546:4;53569:12;;;;;;;;;;;-1:-1:-1;;;;;53569:29:0;;;;;;;;;;;;;;;53469:136;62908:64;;;;;;;;;;;;62947:25;62908:64;;73365:2916;;;;;;:::i;:::-;;:::i;52802:49::-;;;;;;;;;;-1:-1:-1;52802:49:0;52847:4;52802:49;;65968:36;;;;;;;;;;;;;;;69028:392;;;;;;;;;;-1:-1:-1;69028:392:0;;;;;:::i;:::-;;:::i;69755:1121::-;;;;;;;;;;-1:-1:-1;69755:1121:0;;;;;:::i;:::-;;:::i;:::-;;;;;;;:::i;67048:735::-;;;;;;;;;;-1:-1:-1;67048:735:0;;;;;:::i;:::-;;:::i;65873:34::-;;;;;;;;;;;;;;;63726:290;;;;;;;;;;-1:-1:-1;63726:290:0;;;;;:::i;:::-;;:::i;64387:264::-;;;;;;;;;;-1:-1:-1;64387:264:0;;;;;:::i;:::-;;:::i;63189:37::-;;;;;;;;;;;;63223:3;63189:37;;70916:2409;;;;;;:::i;:::-;;:::i;66906:104::-;;;;;;;;;;-1:-1:-1;66906:104:0;;;;;:::i;:::-;;:::i;65597:57::-;;;;;;;;;;-1:-1:-1;65597:57:0;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;65597:57:0;;;;;;;15543:14:1;15584:15;;;15566:34;;15636:15;;;;15631:2;15616:18;;15609:43;-1:-1:-1;;;;;15688:55:1;15668:18;;;15661:83;15521:2;15506:18;65597:57:0;15335:415:1;61927:131:0;;;;;;;;;;-1:-1:-1;61927:131:0;;;;;:::i;:::-;;:::i;63116:66::-;;;;;;;;;;;;63156:26;63116:66;;55257:138;;;;;;;;;;-1:-1:-1;55257:138:0;;;;;:::i;:::-;;:::i;63480:47::-;;;;;;;;;;-1:-1:-1;63480:47:0;;;;;:::i;:::-;;;;;;;;;;;;;;65359:60;;;;;;;;;;;;65408:11;65359:60;;63601:29;;;;;;;;;;;;;;;;60820:212;60905:4;60928:57;;;60943:42;60928:57;;:97;;;60989:36;61013:11;60989:23;:36::i;:::-;60921:104;60820:212;-1:-1:-1;;60820:212:0:o;64022:359::-;63156:26;53079:16;53090:4;53079:10;:16::i;:::-;-1:-1:-1;;;;;64146:19:0;::::1;64126:17;64146:19:::0;;;:12:::1;:19;::::0;;;;;;64179:14;;;64175:27:::1;;64195:7;64022:359:::0;;;:::o;64175:27::-:1;-1:-1:-1::0;;;;;64243:19:0;::::1;64265:1;64243:19:::0;;;:12:::1;:19;::::0;;;;:23;64276:45:::1;::::0;64300:9;64311;64276:23:::1;:45::i;:::-;64336:38;::::0;;-1:-1:-1;;;;;16036:15:1;;;16018:34;;16088:15;;16083:2;16068:18;;16061:43;16120:18;;;16113:34;;;64336:38:0::1;::::0;15945:2:1;15930:18;64336:38:0::1;;;;;;;64116:265;53105:1;64022:359:::0;;;:::o;76321:648::-;62947:25;53079:16;53090:4;53079:10;:16::i;:::-;76537:22:::1;76496:30;::::0;;;:15:::1;:30;::::0;;;;:37;::::1;;:63;::::0;::::1;;;;;;:::i;:::-;;76492:93;;76568:17;;;;;;;;;;;;;;76492:93;76595:30;::::0;;;:15:::1;:30;::::0;;;;;;;;:67;;76635:27:::1;76758:70:::0;;;;76672:76:::1;76732:15;76672:76;;;76758:70:::0;;;;76815:12:::1;76758:70;;;::::0;;76838:53;::::1;::::0;-1:-1:-1;;;;;76838:53:0;::::1;::::0;;::::1;::::0;;;::::1;::::0;;;76907:55;;785:25:1;;;76907:55:0;;76838:53;;76595:30;;76907:55:::1;::::0;;;;;;;::::1;76321:648:::0;;;;:::o;54841:136::-;54490:7;54516:12;;;;;;;;;;:22;;;53079:16;53090:4;53079:10;:16::i;:::-;54945:25:::1;54956:4;54962:7;54945:10;:25::i;:::-;;54841:136:::0;;;:::o;55943:245::-;-1:-1:-1;;;;;56036:34:0;;23368:10;56036:34;56032:102;;56093:30;;;;;;;;;;;;;;56032:102;56144:37;56156:4;56162:18;56144:11;:37::i;77007:1414::-;77097:18;;;;;;77073:21;77166:31;77107:7;77166:22;:31::i;:::-;77125:72;-1:-1:-1;77323:27:0;77282:30;;;;:15;:30;;;;;:37;;;:68;;;;;;;;:::i;:::-;;77278:98;;77359:17;;;;;;;;;;;;;;77278:98;-1:-1:-1;;;;;77470:16:0;;77466:213;;77507:30;;;;:15;:30;;;;;:43;;;;-1:-1:-1;;;;;77507:43:0;;-1:-1:-1;77466:213:0;;;77571:30;;;;:15;:30;;;;;:43;;;;-1:-1:-1;;;;;77571:43:0;77618:10;77571:57;77567:112;;77651:17;;;;;;;;;;;;;;77567:112;77704:30;;;;:15;:30;;;;;:50;65004:10;;77704:50;;;;;;;82347:15;82340:45;82332:53;77693:80;77689:142;;77796:24;;;;;;;;;;;;;;77689:142;77841:30;;;;:15;:30;;;;;:68;;;;77881:28;77841:68;;;77984:27;;;;:31;77980:105;;78058:27;;;;78030:23;;;;-1:-1:-1;;;;;78017:37:0;;;;;:12;:37;;;;;:68;;:37;;;:68;;78058:27;;78017:68;:::i;:::-;;;;-1:-1:-1;;77980:105:0;78180:23;;;;78230:24;;;;78264:35;-1:-1:-1;;;;;78264:23:0;;78288:2;78230:24;78264:23;:35::i;:::-;78351:30;;;;:15;:30;;;;;;;;;:43;78315:99;;-1:-1:-1;;;;;16669:55:1;;;16651:74;;16741:18;;;16734:34;;;78315:99:0;;;;78351:43;;;;;;;;:30;;78315:99;;16624:18:1;78315:99:0;;;;;;;77063:1358;;;;77007:1414;;:::o;66134:369::-;66205:291;66234:6;66264:221;;;;;;;;66319:1;-1:-1:-1;;;;;66264:221:0;;;;;66364:1;66264:221;;;;66392:9;;;;;;;;;;;;66264:221;;;;66430:1;66264:221;;;;66461:9;;;;;;;;;;;;66264:221;;;66205:6;:291::i;:::-;66134:369;:::o;79105:169::-;79180:26;-1:-1:-1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;79180:26:0;79236:7;79225:42;;;;;;;;;;;;:::i;67821:1169::-;67902:18;;;;;;67878:21;67972:31;67912:7;67972:22;:31::i;:::-;67931:72;-1:-1:-1;68059:22:0;68018:30;;;;:15;:30;;;;;:37;;;:63;;;;;;;;:::i;:::-;;68014:93;;68090:17;;;;;;;;;;;;;;68014:93;68145:10;53546:4;53569:29;;;:12;;:29;:12;:29;;;;;68118:382;;;68253:11;:20;;;68234:15;:39;68230:73;;68282:21;;;;;;;;;;;;;;68230:73;68118:382;;;65149:6;68424:11;:20;;;:35;;;;:::i;:::-;68405:15;:54;68401:88;;68468:21;;;;;;;;;;;;;;68401:88;68566:30;;;;:15;:30;;;;;;:61;;;;68606:21;68566:61;;;68713:24;;;68763:23;;;;68840:27;;;;68813:24;;;;68713;;68763:23;;68813:54;;68840:27;68813:54;:::i;:::-;68796:71;-1:-1:-1;68877:35:0;-1:-1:-1;;;;;68877:23:0;;68901:2;68796:71;68877:23;:35::i;:::-;68928:55;;;-1:-1:-1;;;;;16669:55:1;;;16651:74;;16756:2;16741:18;;16734:34;;;68928:55:0;;;68950:13;;68928:55;;16624:18:1;68928:55:0;;;;;;;67868:1122;;;;;67821:1169;:::o;66696:170::-;66772:87;66804:7;66794:18;;;;;;66826:10;66847;66772:5;:87::i;:::-;66696:170;;:::o;66541:117::-;66605:46;66621:7;66639:10;66605:5;:46::i;61617:142::-;61698:7;61724:18;;;:12;:18;;;;;:28;;61746:5;61724:21;:28::i;:::-;61717:35;61617:142;-1:-1:-1;;;61617:142:0:o;73365:2916::-;73468:18;;;;;;73444:21;73537:31;73478:7;73537:22;:31::i;:::-;73496:72;;73578:57;73599:11;73612:13;73627:7;73578:20;:57::i;:::-;73739:107;;;;;;;;;;73772:12;73739:107;;;;73810:15;73739:107;;;;;;;;;-1:-1:-1;;;;;73739:107:0;;;;;;;;;-1:-1:-1;73691:33:0;;;:18;:33;;;;;:155;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;73969:25;;;;74020:21;;;;;74068:22;;;;74120:21;;;;74344:25;;74396:23;;;;;74477:24;;;;;74209:374;;19501:10:1;19489:23;;;19471:42;;19610:15;;;19590:18;;;19583:43;;;;19662:15;;;19642:18;;;19635:43;;;;19694:18;;;19687:34;;;;19737:19;;;19730:35;;;19781:19;;;19774:35;;;73969:25:0;;74020:21;;74068:22;;74120:21;74209:374;;;73739:107;73691:33;;74209:374;;19443:19:1;74209:374:0;;;;;;;74798:38;-1:-1:-1;;;;;74798:38:0;;;74794:695;;74913:14;;74909:61;;74936:34;;;;;;;;;;;;;;74909:61;75058:6;75045:9;:19;75041:51;;75073:19;;;;;;;;;;;;;;75041:51;74794:695;;;75212:9;75199;:22;75195:54;;75230:19;;;;;;;;;;;;;;75195:54;75424;-1:-1:-1;;;;;75424:30:0;;75455:10;75467:2;75471:6;75424:30;:54::i;:::-;75503:22;;;;:29;:34;75499:776;;75855:104;75889:2;75900:5;75915:6;75935:11;:22;;;75855:21;:104::i;:::-;75499:776;;;75980:9;:14;75976:299;;76223:41;76249:2;76254:9;76223:17;:41::i;:::-;73434:2847;;;;;;73365:2916;;:::o;69028:392::-;69109:4;69170:27;69129:30;;;;:15;:30;;;;;:37;;;:68;;;;;;;;:::i;:::-;;69125:98;;69206:17;;;;;;;;;;;;;;69125:98;69237:30;;;;:15;:30;;;;;:43;-1:-1:-1;;;;;69237:54:0;;;:43;;;;;:54;69233:84;;69300:17;;;;;;;;;;;;;;69233:84;-1:-1:-1;;69345:30:0;;;;:15;:30;;;;;:50;65004:10;69345:50;;;;;;;;82347:15;82340:45;82332:53;69334:79;;69028:392::o;69755:1121::-;-1:-1:-1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;69956:36:0;;;;;:4;;:27;;:36;;69984:7;;69956:36;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;69956:36:0;;;;;;;;;;;;:::i;:::-;;;69952:918;;70830:7;70819:40;;;;;;;;;;;;:::i;69952:918::-;70146:597;;;;;;;;70197:4;:18;;;70146:597;;;;;;70246:4;:16;;;70146:597;;;;;;70294:4;:17;;;-1:-1:-1;;;;;70146:597:0;;;;;70344:4;:18;;;-1:-1:-1;;;;;70146:597:0;;;;;70393:4;:16;;;-1:-1:-1;;;;;70146:597:0;;;;;70438:4;:14;;;-1:-1:-1;;;;;70146:597:0;;;;;70484:4;:17;;;70146:597;;;;70531:4;:15;;;70146:597;;;;70581:4;:20;;;70146:597;;;;70633:4;:14;;;70651:1;70633:19;;70146:597;;;;;;70680:4;:13;;;70146:597;;;;70718:4;:10;;;70146:597;;;70139:604;;;69755:1121;;;:::o;69952:918::-;69755:1121;;;:::o;67048:735::-;63087:23;53079:16;53090:4;53079:10;:16::i;:::-;67173:27:::1;67132:30;::::0;;;:15:::1;:30;::::0;;;;:37;::::1;;:68;::::0;::::1;;;;;;:::i;:::-;;67128:98;;67209:17;;;;;;;;;;;;;;67128:98;67251:30;::::0;;;:15:::1;:30;::::0;;;;:50;65004:10:::1;::::0;67251:50:::1;::::0;::::1;;::::0;;::::1;82347:15:::0;82340:45;82332:53;67240:79:::1;67236:138;;;67342:21;;;;;;;;;;;;;;67236:138;67461:30;::::0;;;:15:::1;:30;::::0;;;;;67501:22:::1;67663:51:::0;;67730:46;67765:10:::1;::::0;67461:30;;67730:46:::1;::::0;67461:30;67730:46:::1;67048:735:::0;;:::o;63726:290::-;63156:26;53079:16;53090:4;53079:10;:16::i;:::-;63271:6:::1;63825:10;:26;;63817:55;;;::::0;::::1;::::0;;21574:2:1;63817:55:0::1;::::0;::::1;21556:21:1::0;21613:2;21593:18;;;21586:30;21652:18;21632;;;21625:46;21688:18;;63817:55:0::1;;;;;;;;;63903:15;::::0;;63928:28;;;;63971:38:::1;::::0;;21891:25:1;;;21947:2;21932:18;;21925:34;;;63971:38:0::1;::::0;21864:18:1;63971:38:0::1;;;;;;;;63807:209;63726:290:::0;;:::o;64387:264::-;63156:26;53079:16;53090:4;53079:10;:16::i;:::-;64512:14:::1;::::0;;64536:34;;;;64585:59:::1;::::0;;21891:25:1;;;21947:2;21932:18;;21925:34;;;64585:59:0::1;::::0;21864:18:1;64585:59:0::1;21717:248:1::0;70916:2409:0;71017:25;71071:8;:32;;;71052:15;71045:58;;;;:::i;:::-;71017:86;;71113:59;71135:6;71143:8;71153:18;71113:21;:59::i;:::-;71308:20;71331:62;71353:6;:18;;;71373:6;:19;;;71331:21;:62::i;:::-;71308:85;;71461:23;71516:1;71498:15;;:19;71494:85;;;63223:3;71553:15;;71538:12;:30;;;;:::i;:::-;71537:42;;;;:::i;:::-;71519:60;;71494:85;71589:31;71605:15;71589:31;;:::i;:::-;;;71733:20;71780:924;;;;;;;;71840:13;71780:924;;;;;;71885:6;:17;;;71780:924;;;;;;71934:6;:13;;;-1:-1:-1;;;;;71780:924:0;;;;;71980:6;:9;;;-1:-1:-1;;;;;71780:924:0;;;;;72020:6;:18;;;-1:-1:-1;;;;;71780:924:0;;;;;72067:6;:16;;;-1:-1:-1;;;;;71780:924:0;;;;;72115:12;71780:924;;;;72157:6;:17;;;71780:924;;;;72209:15;71780:924;;;;72253:8;:18;;;71780:924;;;;72299:6;:15;;;71780:924;;;;72339:12;:27;72352:6;:13;;;-1:-1:-1;;;;;72339:27:0;-1:-1:-1;;;;;72339:27:0;;;;;;;;;;;;;:29;;;;;;;;;:::i;:::-;;;;;71780:924;;;;72441:8;:21;;;-1:-1:-1;;;;;71780:924:0;;;;;72621:18;71780:924;;;;72670:8;:19;;;71780:924;;;71756:958;;;;;;;;:::i;:::-;;;;;;;-1:-1:-1;;71756:958:0;;;;;;72748:18;;71756:958;72748:18;;;;;;;72724:21;72776:30;;;:15;:30;;;;;;:62;;;;72816:22;72776:62;;;72934:13;;;73004:17;;73048:18;;;;;73091:16;;;;73173:17;;;;73218:18;;;;71756:958;;-1:-1:-1;72748:18:0;;-1:-1:-1;;;;;72854:398:0;;;;72748:18;;72854:398;;;;71756:958;;73004:17;;73048:18;73091:16;73135:12;;73218:23;;;;72854:398;:::i;:::-;;;;;;;;73286:13;73267:51;73301:8;:16;;;73267:51;;;;;;:::i;:::-;;;;;;;;71007:2318;;;;;70916:2409;;:::o;66906:104::-;66962:41;66978:7;66999:1;66962:5;:41::i;61927:131::-;61998:7;62024:18;;;:12;:18;;;;;:27;;:25;:27::i;55257:138::-;54490:7;54516:12;;;;;;;;;;:22;;;53079:16;53090:4;53079:10;:16::i;:::-;55362:26:::1;55374:4;55380:7;55362:11;:26::i;53180:202::-:0;53265:4;53288:47;;;53303:32;53288:47;;:87;;-1:-1:-1;45095:25:0;45080:40;;;;53339:36;44981:146;53814:103;53880:30;53891:4;23368:10;53880;:30::i;58092:653::-;58267:4;-1:-1:-1;;;;;58253:19:0;;;58249:32;;58092:653;;;:::o;58249:32::-;58353:5;58362:1;58353:10;58349:23;;58092:653;;;:::o;58349:23::-;58385:20;-1:-1:-1;;;;;58385:20:0;;;58381:358;;58565:12;58582:2;-1:-1:-1;;;;;58582:7:0;58597:5;58582:25;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;58564:43;;;58629:7;58621:39;;;;;;;24145:2:1;58621:39:0;;;24127:21:1;24184:2;24164:18;;;24157:30;24223:21;24203:18;;;24196:49;24262:18;;58621:39:0;23943:343:1;58381:358:0;58691:37;-1:-1:-1;;;;;58691:26:0;;58718:2;58722:5;58691:26;:37::i;62160:257::-;62246:4;62262:12;62277:31;62294:4;62300:7;62277:16;:31::i;:::-;62262:46;;62322:7;62318:69;;;62345:18;;;;:12;:18;;;;;:31;;62368:7;62345:22;:31::i;:::-;;62403:7;62160:257;-1:-1:-1;;;62160:257:0:o;62520:262::-;62607:4;62623:12;62638:32;62656:4;62662:7;62638:17;:32::i;:::-;62623:47;;62684:7;62680:72;;;62707:18;;;;:12;:18;;;;;:34;;62733:7;62707:25;:34::i;34071:156::-;34145:7;34195:22;34199:3;34211:5;34195:3;:22::i;83982:943::-;-1:-1:-1;;;;;84170:21:0;;84166:47;;84200:13;;;;;;;;;;;;;;84166:47;78932:4;79003:33;;;:18;:33;;;;;:41;;;;-1:-1:-1;;;;;79003:41:0;:55;84284:60;;84324:20;;;;;;;;;;;;;;84284:60;84385:13;84358:11;:23;;;:40;;;84354:69;;84407:16;;;;;;;;;;;;;;84354:69;84505:11;:20;;;84487:15;:38;84483:69;;;84534:18;;;;;;;;;;;;;;84483:69;84682:30;;;;-1:-1:-1;;;;;84682:44:0;;;;;:101;;;84776:7;-1:-1:-1;;;;;84742:41:0;:11;:30;;;-1:-1:-1;;;;;84742:41:0;;;84682:101;:166;;;;;84818:11;:30;;;84799:15;:49;;84682:166;84665:254;;;84880:28;;;;;;;;;;;;;;46696:188;46823:53;;-1:-1:-1;;;;;16036:15:1;;;46823:53:0;;;16018:34:1;16088:15;;;16068:18;;;16061:43;16120:18;;;16113:34;;;46796:81:0;;46816:5;;46838:18;;;;;15930::1;;46823:53:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;46796:19;:81::i;80749:999::-;80924:21;81025:5;81032:6;81040:10;80960:92;;;;;;;;;;:::i;:::-;;;;-1:-1:-1;;80960:92:0;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;81159:84:0;81198:9;80960:92;81232:9;81159:29;:84::i;:::-;81133:110;;81309:10;:17;81330:1;81309:22;81305:59;;81340:24;;;;;;;;;;;;;;81305:59;81443:10;:17;81464:2;81443:23;81439:67;;81475:31;;;;;;;;;;;;;;81439:67;81620:56;81589:19;81597:10;81589:19;:::i;:::-;:88;81585:157;;81700:31;;;;;;;;;;;;;;81585:157;80914:834;;80749:999;;;;:::o;17900:331::-;18009:6;17985:21;:30;17981:109;;;18038:41;;;;;18073:4;18038:41;;;12187:74:1;12160:18;;18038:41:0;12041:226:1;17981:109:0;18101:12;18119:9;-1:-1:-1;;;;;18119:14:0;18141:6;18119:33;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;18100:52;;;18167:7;18162:63;;18197:17;;;;;;;;;;;;;;82727:1176;82980:13;82959:6;:17;;;:34;;;82955:63;;83002:16;;;;;;;;;;;;;;82955:63;83032:19;;;;:24;;:50;;-1:-1:-1;83060:17:0;;;;:22;83032:50;83028:80;;;83091:17;;;;;;;;;;;;;;83028:80;83122:13;;;;-1:-1:-1;;;;;83122:27:0;;;:54;;-1:-1:-1;83153:9:0;;;;-1:-1:-1;;;;;83153:23:0;;83122:54;83118:80;;;83185:13;;;;;;;;;;;;;;83118:80;83212:18;;;;-1:-1:-1;;;;;83212:32:0;;;:66;;-1:-1:-1;83248:16:0;;;;-1:-1:-1;;;;;83248:30:0;;83212:66;83208:92;;;83287:13;;;;;;;;;;;;;;83208:92;83332:37;65288:10;83332:15;:37;:::i;:::-;83314:6;:15;;;:55;83310:86;;;83378:18;;;;;;;;;;;;;;83310:86;65408:11;83437:8;:19;;;:26;:51;83433:90;;;83497:26;;;;;;;;;;;;;;83433:90;83537:18;;;;:23;;;;:76;;-1:-1:-1;83564:16:0;;;;-1:-1:-1;;;;;83564:49:0;57809:42;83564:49;83537:76;83533:148;;;83636:34;;;;;;;;;;;;;;83533:148;83786:1;83764:18;:23;;:71;;;;83819:6;:15;;;83791:18;:44;83764:71;83760:137;;;83858:28;;;;;;;;;;;;;;79527:1064;79607:19;79642:38;-1:-1:-1;;;;;79642:38:0;;;79638:947;;79867:9;79857:6;:19;79853:51;;79885:19;;;;;;;;;;;;;;79853:51;-1:-1:-1;79932:9:0;79638:947;;;80168:24;:5;-1:-1:-1;;;;;80168:22:0;;:24::i;:::-;80210:9;:14;80206:46;;80233:19;;;;;;;;;;;;;;80206:46;80280:38;;;;;80312:4;80280:38;;;12187:74:1;-1:-1:-1;;;;;80280:23:0;;;;;12160:18:1;;80280:38:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;80266:52;-1:-1:-1;80332:65:0;-1:-1:-1;;;;;80332:30:0;;80363:10;80383:4;80390:6;80332:30;:65::i;:::-;80522:38;;;;;80554:4;80522:38;;;12187:74:1;80563:11:0;;-1:-1:-1;;;;;80522:23:0;;;;;12160:18:1;;80522:38:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;:52;;;;:::i;33614:115::-;33677:7;33703:19;33711:3;29053:18;;28971:107;54047:197;53546:4;53569:12;;;;;;;;;;;-1:-1:-1;;;;;53569:29:0;;;;;;;;;;;;54130:108;;54180:47;;;;;-1:-1:-1;;;;;16669:55:1;;54180:47:0;;;16651:74:1;16741:18;;;16734:34;;;16624:18;;54180:47:0;16477:297:1;46297:160:0;46406:43;;-1:-1:-1;;;;;16669:55:1;;;46406:43:0;;;16651:74:1;16741:18;;;16734:34;;;46379:71:0;;46399:5;;46421:14;;;;;16624:18:1;;46406:43:0;16477:297:1;56794:316:0;56871:4;53569:12;;;;;;;;;;;-1:-1:-1;;;;;53569:29:0;;;;;;;;;;;;56887:217;;56930:6;:12;;;;;;;;;;;-1:-1:-1;;;;;56930:29:0;;;;;;;;;:36;;;;56962:4;56930:36;;;57012:12;23368:10;;23289:96;57012:12;-1:-1:-1;;;;;56985:40:0;57003:7;-1:-1:-1;;;;;56985:40:0;56997:4;56985:40;;;;;;;;;;-1:-1:-1;57046:4:0;57039:11;;56887:217;-1:-1:-1;57088:5:0;57081:12;;32813:150;32883:4;32906:50;32911:3;-1:-1:-1;;;;;32931:23:0;;32906:4;:50::i;57345:317::-;57423:4;53569:12;;;;;;;;;;;-1:-1:-1;;;;;53569:29:0;;;;;;;;;;;;57439:217;;;57513:5;57481:12;;;;;;;;;;;-1:-1:-1;;;;;57481:29:0;;;;;;;;;;:37;;;;;;57537:40;23368:10;;57481:12;;57537:40;;57513:5;57537:40;-1:-1:-1;57598:4:0;57591:11;;33131:156;33204:4;33227:53;33235:3;-1:-1:-1;;;;;33255:23:0;;33227:7;:53::i;29420:118::-;29487:7;29513:3;:11;;29525:5;29513:18;;;;;;;;:::i;:::-;;;;;;;;;29506:25;;29420:118;;;;:::o;49053:629::-;49472:23;49498:33;-1:-1:-1;;;;;49498:27:0;;49526:4;49498:27;:33::i;:::-;49472:59;;49545:10;:17;49566:1;49545:22;;:57;;;;;49583:10;49572:30;;;;;;;;;;;;:::i;:::-;49571:31;49545:57;49541:135;;;49625:40;;;;;-1:-1:-1;;;;;12205:55:1;;49625:40:0;;;12187:74:1;12160:18;;49625:40:0;12041:226:1;19549:392:0;19648:12;19700:5;19676:21;:29;19672:108;;;19728:41;;;;;19763:4;19728:41;;;12187:74:1;12160:18;;19728:41:0;12041:226:1;19672:108:0;19790:12;19804:23;19831:6;-1:-1:-1;;;;;19831:11:0;19850:5;19857:4;19831:31;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;19789:73;;;;19879:55;19906:6;19914:7;19923:10;19879:26;:55::i;:::-;19872:62;19549:392;-1:-1:-1;;;;;;19549:392:0:o;59909:344::-;60076:38;-1:-1:-1;;;;;60076:38:0;;;60072:69;;60123:18;;;;;;;;;;;;;;60072:69;60197:5;-1:-1:-1;;;;;60197:17:0;;60218:1;60197:22;60193:53;;60228:18;;;;;;;;;;;;;;26738:406;26801:4;28857:21;;;:14;;;:21;;;;;;26817:321;;-1:-1:-1;26859:23:0;;;;;;;;:11;:23;;;;;;;;;;;;;27041:18;;27017:21;;;:14;;;:21;;;;;;:42;;;;27073:11;;27312:1368;27378:4;27507:21;;;:14;;;:21;;;;;;27543:13;;27539:1135;;27910:18;27931:12;27942:1;27931:8;:12;:::i;:::-;27977:18;;27910:33;;-1:-1:-1;27957:17:0;;27977:22;;27998:1;;27977:22;:::i;:::-;27957:42;;28032:9;28018:10;:23;28014:378;;28061:17;28081:3;:11;;28093:9;28081:22;;;;;;;;:::i;:::-;;;;;;;;;28061:42;;28228:9;28202:3;:11;;28214:10;28202:23;;;;;;;;:::i;:::-;;;;;;;;;;;;:35;;;;28341:25;;;:14;;;:25;;;;;:36;;;28014:378;28470:17;;:3;;:17;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;28573:3;:14;;:21;28588:5;28573:21;;;;;;;;;;;28566:28;;;28616:4;28609:11;;;;;;;27539:1135;28658:5;28651:12;;;;;19074:151;19149:12;19180:38;19202:6;19210:4;19216:1;19180:21;:38::i;20994:582::-;21138:12;21167:7;21162:408;;21190:19;21198:10;21190:7;:19::i;:::-;21162:408;;;21414:17;;:22;:49;;;;-1:-1:-1;;;;;;21440:18:0;;;:23;21414:49;21410:119;;;21490:24;;;;;-1:-1:-1;;;;;12205:55:1;;21490:24:0;;;12187:74:1;12160:18;;21490:24:0;12041:226:1;21410:119:0;-1:-1:-1;21549:10:0;21542:17;;22112:516;22243:17;;:21;22239:383;;22471:10;22465:17;22527:15;22514:10;22510:2;22506:19;22499:44;22239:383;22594:17;;;;;;;;;;;;;;14:332:1;72:6;125:2;113:9;104:7;100:23;96:32;93:52;;;141:1;138;131:12;93:52;180:9;167:23;230:66;223:5;219:78;212:5;209:89;199:117;;312:1;309;302:12;821:180;880:6;933:2;921:9;912:7;908:23;904:32;901:52;;;949:1;946;939:12;901:52;-1:-1:-1;972:23:1;;821:180;-1:-1:-1;821:180:1:o;1006:184::-;1058:77;1055:1;1048:88;1155:4;1152:1;1145:15;1179:4;1176:1;1169:15;1195:297;1279:1;1272:5;1269:12;1259:200;;1315:77;1312:1;1305:88;1416:4;1413:1;1406:15;1444:4;1441:1;1434:15;1259:200;1468:18;;1195:297::o;1497:214::-;1646:2;1631:18;;1658:47;1635:9;1687:6;1658:47;:::i;1716:154::-;-1:-1:-1;;;;;1795:5:1;1791:54;1784:5;1781:65;1771:93;;1860:1;1857;1850:12;1875:134;1943:20;;1972:31;1943:20;1972:31;:::i;2014:388::-;2082:6;2090;2143:2;2131:9;2122:7;2118:23;2114:32;2111:52;;;2159:1;2156;2149:12;2111:52;2198:9;2185:23;2217:31;2242:5;2217:31;:::i;:::-;2267:5;-1:-1:-1;2324:2:1;2309:18;;2296:32;2337:33;2296:32;2337:33;:::i;:::-;2389:7;2379:17;;;2014:388;;;;;:::o;2589:383::-;2666:6;2674;2682;2735:2;2723:9;2714:7;2710:23;2706:32;2703:52;;;2751:1;2748;2741:12;2703:52;2787:9;2774:23;2764:33;;2844:2;2833:9;2829:18;2816:32;2806:42;;2898:2;2887:9;2883:18;2870:32;2911:31;2936:5;2911:31;:::i;:::-;2961:5;2951:15;;;2589:383;;;;;:::o;2977:247::-;3036:6;3089:2;3077:9;3068:7;3064:23;3060:32;3057:52;;;3105:1;3102;3095:12;3057:52;3144:9;3131:23;3163:31;3188:5;3163:31;:::i;3229:315::-;3297:6;3305;3358:2;3346:9;3337:7;3333:23;3329:32;3326:52;;;3374:1;3371;3364:12;3326:52;3410:9;3397:23;3387:33;;3470:2;3459:9;3455:18;3442:32;3483:31;3508:5;3483:31;:::i;3549:184::-;3601:77;3598:1;3591:88;3698:4;3695:1;3688:15;3722:4;3719:1;3712:15;3738:255;3810:2;3804:9;3852:6;3840:19;;3889:18;3874:34;;3910:22;;;3871:62;3868:88;;;3936:18;;:::i;:::-;3972:2;3965:22;3738:255;:::o;3998:253::-;4070:2;4064:9;4112:4;4100:17;;4147:18;4132:34;;4168:22;;;4129:62;4126:88;;;4194:18;;:::i;4256:255::-;4328:2;4322:9;4370:6;4358:19;;4407:18;4392:34;;4428:22;;;4389:62;4386:88;;;4454:18;;:::i;4516:252::-;4588:2;4582:9;4630:3;4618:16;;4664:18;4649:34;;4685:22;;;4646:62;4643:88;;;4711:18;;:::i;4773:334::-;4844:2;4838:9;4900:2;4890:13;;-1:-1:-1;;4886:86:1;4874:99;;5003:18;4988:34;;5024:22;;;4985:62;4982:88;;;5050:18;;:::i;:::-;5086:2;5079:22;4773:334;;-1:-1:-1;4773:334:1:o;5112:245::-;5160:4;5193:18;5185:6;5182:30;5179:56;;;5215:18;;:::i;:::-;-1:-1:-1;5272:2:1;5260:15;-1:-1:-1;;5256:88:1;5346:4;5252:99;;5112:245::o;5362:462::-;5404:5;5457:3;5450:4;5442:6;5438:17;5434:27;5424:55;;5475:1;5472;5465:12;5424:55;5511:6;5498:20;5542:48;5558:31;5586:2;5558:31;:::i;:::-;5542:48;:::i;:::-;5615:2;5606:7;5599:19;5661:3;5654:4;5649:2;5641:6;5637:15;5633:26;5630:35;5627:55;;;5678:1;5675;5668:12;5627:55;5743:2;5736:4;5728:6;5724:17;5717:4;5708:7;5704:18;5691:55;5791:1;5766:16;;;5784:4;5762:27;5755:38;;;;5770:7;5362:462;-1:-1:-1;;;5362:462:1:o;5829:455::-;5906:6;5914;5967:2;5955:9;5946:7;5942:23;5938:32;5935:52;;;5983:1;5980;5973:12;5935:52;6023:9;6010:23;6056:18;6048:6;6045:30;6042:50;;;6088:1;6085;6078:12;6042:50;6111:49;6152:7;6143:6;6132:9;6128:22;6111:49;:::i;:::-;6101:59;;;6210:2;6199:9;6195:18;6182:32;6223:31;6248:5;6223:31;:::i;6289:121::-;6374:10;6367:5;6363:22;6356:5;6353:33;6343:61;;6400:1;6397;6390:12;6415:132;6482:20;;6511:30;6482:20;6511:30;:::i;6552:118::-;6638:5;6631:13;6624:21;6617:5;6614:32;6604:60;;6660:1;6657;6650:12;6675:128;6740:20;;6769:28;6740:20;6769:28;:::i;6808:806::-;6867:5;6915:6;6903:9;6898:3;6894:19;6890:32;6887:52;;;6935:1;6932;6925:12;6887:52;6957:22;;:::i;:::-;6948:31;;7002:28;7020:9;7002:28;:::i;:::-;6995:5;6988:43;7063:38;7097:2;7086:9;7082:18;7063:38;:::i;:::-;7058:2;7051:5;7047:14;7040:62;7134:38;7168:2;7157:9;7153:18;7134:38;:::i;:::-;7129:2;7122:5;7118:14;7111:62;7205:38;7239:2;7228:9;7224:18;7205:38;:::i;:::-;7200:2;7193:5;7189:14;7182:62;7277:39;7311:3;7300:9;7296:19;7277:39;:::i;:::-;7271:3;7264:5;7260:15;7253:64;7378:3;7367:9;7363:19;7350:33;7344:3;7337:5;7333:15;7326:58;7445:3;7434:9;7430:19;7417:33;7411:3;7404:5;7400:15;7393:58;7484:36;7515:3;7504:9;7500:19;7484:36;:::i;:::-;7478:3;7471:5;7467:15;7460:61;7540:3;7603:2;7592:9;7588:18;7575:32;7570:2;7563:5;7559:14;7552:56;;6808:806;;;;:::o;7619:237::-;7707:6;7760:3;7748:9;7739:7;7735:23;7731:33;7728:53;;;7777:1;7774;7767:12;7728:53;7800:50;7842:7;7831:9;7800:50;:::i;7861:320::-;7929:6;7982:2;7970:9;7961:7;7957:23;7953:32;7950:52;;;7998:1;7995;7988:12;7950:52;8038:9;8025:23;8071:18;8063:6;8060:30;8057:50;;;8103:1;8100;8093:12;8057:50;8126:49;8167:7;8158:6;8147:9;8143:22;8126:49;:::i;:::-;8116:59;7861:320;-1:-1:-1;;;;7861:320:1:o;8417:250::-;8502:1;8512:113;8526:6;8523:1;8520:13;8512:113;;;8602:11;;;8596:18;8583:11;;;8576:39;8548:2;8541:10;8512:113;;;-1:-1:-1;;8659:1:1;8641:16;;8634:27;8417:250::o;8672:329::-;8713:3;8751:5;8745:12;8778:6;8773:3;8766:19;8794:76;8863:6;8856:4;8851:3;8847:14;8840:4;8833:5;8829:16;8794:76;:::i;:::-;8915:2;8903:15;-1:-1:-1;;8899:88:1;8890:98;;;;8990:4;8886:109;;8672:329;-1:-1:-1;;8672:329:1:o;9006:1866::-;9209:2;9198:9;9191:21;9221:52;9269:2;9258:9;9254:18;9245:6;9239:13;8262:10;8251:22;8239:35;;8186:94;9221:52;9172:4;9320:2;9312:6;9308:15;9302:22;9333:51;9380:2;9369:9;9365:18;9351:12;8262:10;8251:22;8239:35;;8186:94;9333:51;-1:-1:-1;9433:2:1;9421:15;;9415:22;-1:-1:-1;;;;;8351:54:1;;9496:2;9481:18;;8339:67;-1:-1:-1;9549:2:1;9537:15;;9531:22;-1:-1:-1;;;;;8351:54:1;;9612:3;9597:19;;8339:67;-1:-1:-1;9666:3:1;9654:16;;9648:23;-1:-1:-1;;;;;8351:54:1;;9730:3;9715:19;;8339:67;-1:-1:-1;9784:3:1;9772:16;;9766:23;-1:-1:-1;;;;;8351:54:1;;9848:3;9833:19;;8339:67;-1:-1:-1;9908:3:1;9896:16;;9890:23;9884:3;9869:19;;;9862:52;;;;9939:16;;9933:23;9975:3;9994:18;;;9987:30;;;;10042:15;;10036:22;10077:3;10096:18;;;10089:30;;;;10144:15;;10138:22;10179:3;10198:18;;;10191:30;;;;10246:15;;10240:22;10281:3;10300:18;;;10293:30;;;;10348:15;;10342:22;10384:3;10403:19;;;10396:31;;;;10464:16;;10458:23;10501:3;10513:55;10548:19;;;10458:23;-1:-1:-1;;;;;8351:54:1;8339:67;;8285:127;10513:55;10594:16;;10588:23;10631:3;10650:19;;;10643:32;;;;10712:16;;10706:23;10749:6;10771:19;;;10764:32;10706:23;-1:-1:-1;10813:53:1;10861:3;10846:19;;10706:23;10813:53;:::i;10877:513::-;11106:3;11091:19;;11119:47;11095:9;11148:6;11119:47;:::i;:::-;11214:12;11206:6;11202:25;11197:2;11186:9;11182:18;11175:53;11276:14;11268:6;11264:27;11259:2;11248:9;11244:18;11237:55;-1:-1:-1;;;;;11332:6:1;11328:55;11323:2;11312:9;11308:18;11301:83;10877:513;;;;;;;:::o;11395:388::-;11472:6;11480;11533:2;11521:9;11512:7;11508:23;11504:32;11501:52;;;11549:1;11546;11539:12;11501:52;11589:9;11576:23;11622:18;11614:6;11611:30;11608:50;;;11654:1;11651;11644:12;11608:50;11677:49;11718:7;11709:6;11698:9;11694:22;11677:49;:::i;:::-;11667:59;11773:2;11758:18;;;;11745:32;;-1:-1:-1;;;;11395:388:1:o;11788:248::-;11856:6;11864;11917:2;11905:9;11896:7;11892:23;11888:32;11885:52;;;11933:1;11930;11923:12;11885:52;-1:-1:-1;;11956:23:1;;;12026:2;12011:18;;;11998:32;;-1:-1:-1;11788:248:1:o;12605:1373::-;12836:13;;8262:10;8251:22;8239:35;;12805:3;12790:19;;12908:4;12900:6;12896:17;12890:24;12923:53;12970:4;12959:9;12955:20;12941:12;8262:10;8251:22;8239:35;;8186:94;12923:53;;13025:4;13017:6;13013:17;13007:24;13040:56;13090:4;13079:9;13075:20;13059:14;-1:-1:-1;;;;;8351:54:1;8339:67;;8285:127;13040:56;;13145:4;13137:6;13133:17;13127:24;13160:56;13210:4;13199:9;13195:20;13179:14;-1:-1:-1;;;;;8351:54:1;8339:67;;8285:127;13160:56;;13265:4;13257:6;13253:17;13247:24;13280:56;13330:4;13319:9;13315:20;13299:14;-1:-1:-1;;;;;8351:54:1;8339:67;;8285:127;13280:56;;13385:4;13377:6;13373:17;13367:24;13400:56;13450:4;13439:9;13435:20;13419:14;-1:-1:-1;;;;;8351:54:1;8339:67;;8285:127;13400:56;;13512:4;13504:6;13500:17;13494:24;13487:4;13476:9;13472:20;13465:54;13575:4;13567:6;13563:17;13557:24;13550:4;13539:9;13535:20;13528:54;13601:6;13661:2;13653:6;13649:15;13643:22;13638:2;13627:9;13623:18;13616:50;;13685:6;13740:2;13732:6;13728:15;13722:22;13753:51;13800:2;13789:9;13785:18;13769:14;421:13;414:21;402:34;;351:91;13753:51;-1:-1:-1;;13823:6:1;13871:15;;;13865:22;13845:18;;;13838:50;13907:6;13955:15;;;13949:22;13929:18;;;;13922:50;;;;12605:1373;:::o;14168:1162::-;14297:6;14305;14358:3;14346:9;14337:7;14333:23;14329:33;14326:53;;;14375:1;14372;14365:12;14326:53;14398:50;14440:7;14429:9;14398:50;:::i;:::-;14388:60;;14499:3;14488:9;14484:19;14471:33;14523:18;14564:2;14556:6;14553:14;14550:34;;;14580:1;14577;14570:12;14550:34;14603:22;;;;14659:4;14641:16;;;14637:27;14634:47;;;14677:1;14674;14667:12;14634:47;14703:22;;:::i;:::-;14762:2;14749:16;14774:33;14799:7;14774:33;:::i;:::-;14816:22;;14891:2;14883:11;;;14870:25;14854:14;;;14847:49;14942:2;14934:11;;14921:25;14958:16;;;14955:36;;;14987:1;14984;14977:12;14955:36;15023:44;15059:7;15048:8;15044:2;15040:17;15023:44;:::i;:::-;15018:2;15011:5;15007:14;15000:68;;15121:2;15117;15113:11;15100:25;15095:2;15088:5;15084:14;15077:49;15172:3;15168:2;15164:12;15151:26;15202:2;15192:8;15189:16;15186:36;;;15218:1;15215;15208:12;15186:36;15255:44;15291:7;15280:8;15276:2;15272:17;15255:44;:::i;:::-;15249:3;15242:5;15238:15;15231:69;;15319:5;15309:15;;;;;14168:1162;;;;;:::o;16158:184::-;16210:77;16207:1;16200:88;16307:4;16304:1;16297:15;16331:4;16328:1;16321:15;16347:125;16412:9;;;16433:10;;;16430:36;;;16446:18;;:::i;16779:136::-;16857:13;;16879:30;16857:13;16879:30;:::i;16920:138::-;16999:13;;17021:31;16999:13;17021:31;:::i;17063:441::-;17116:5;17169:3;17162:4;17154:6;17150:17;17146:27;17136:55;;17187:1;17184;17177:12;17136:55;17216:6;17210:13;17247:48;17263:31;17291:2;17263:31;:::i;17247:48::-;17320:2;17311:7;17304:19;17366:3;17359:4;17354:2;17346:6;17342:15;17338:26;17335:35;17332:55;;;17383:1;17380;17373:12;17332:55;17396:77;17470:2;17463:4;17454:7;17450:18;17443:4;17435:6;17431:17;17396:77;:::i;17509:1672::-;17616:6;17669:2;17657:9;17648:7;17644:23;17640:32;17637:52;;;17685:1;17682;17675:12;17637:52;17718:9;17712:16;17747:18;17788:2;17780:6;17777:14;17774:34;;;17804:1;17801;17794:12;17774:34;17827:22;;;;17883:6;17865:16;;;17861:29;17858:49;;;17903:1;17900;17893:12;17858:49;17929:22;;:::i;:::-;17974:32;18003:2;17974:32;:::i;:::-;17967:5;17960:47;18039:41;18076:2;18072;18068:11;18039:41;:::i;:::-;18034:2;18027:5;18023:14;18016:65;18113:42;18151:2;18147;18143:11;18113:42;:::i;:::-;18108:2;18101:5;18097:14;18090:66;18188:42;18226:2;18222;18218:11;18188:42;:::i;:::-;18183:2;18176:5;18172:14;18165:66;18264:43;18302:3;18298:2;18294:12;18264:43;:::i;:::-;18258:3;18251:5;18247:15;18240:68;18341:43;18379:3;18375:2;18371:12;18341:43;:::i;:::-;18335:3;18324:15;;18317:68;18432:3;18424:12;;;18418:19;18401:15;;;18394:44;18485:3;18477:12;;;18471:19;18454:15;;;18447:44;18510:3;18551:11;;;18545:18;18529:14;;;18522:42;18583:3;18624:11;;;18618:18;18602:14;;;18595:42;18656:3;18697:11;;;18691:18;18675:14;;;18668:42;18729:3;18770:11;;;18764:18;18748:14;;;18741:42;18802:3;18837:42;18867:11;;;18837:42;:::i;:::-;18821:14;;;18814:66;18899:3;18940:11;;;18934:18;18918:14;;;18911:42;18972:3;19006:11;;;19000:18;19030:16;;;19027:36;;;19059:1;19056;19049:12;19027:36;19095:55;19142:7;19131:8;19127:2;19123:17;19095:55;:::i;:::-;19079:14;;;19072:79;;;;-1:-1:-1;19083:5:1;17509:1672;-1:-1:-1;;;;;17509:1672:1:o;19820:217::-;19967:2;19956:9;19949:21;19930:4;19987:44;20027:2;20016:9;20012:18;20004:6;19987:44;:::i;20042:132::-;20118:13;;20140:28;20118:13;20140:28;:::i;20179:1188::-;20282:6;20335:3;20323:9;20314:7;20310:23;20306:33;20303:53;;;20352:1;20349;20342:12;20303:53;20378:22;;:::i;:::-;20423:39;20452:9;20423:39;:::i;:::-;20416:5;20409:54;20495:48;20539:2;20528:9;20524:18;20495:48;:::i;:::-;20490:2;20483:5;20479:14;20472:72;20576:49;20621:2;20610:9;20606:18;20576:49;:::i;:::-;20571:2;20564:5;20560:14;20553:73;20658:49;20703:2;20692:9;20688:18;20658:49;:::i;:::-;20653:2;20646:5;20642:14;20635:73;20741:50;20786:3;20775:9;20771:19;20741:50;:::i;:::-;20735:3;20728:5;20724:15;20717:75;20825:50;20870:3;20859:9;20855:19;20825:50;:::i;:::-;20819:3;20812:5;20808:15;20801:75;20930:3;20919:9;20915:19;20909:26;20903:3;20896:5;20892:15;20885:51;20990:3;20979:9;20975:19;20969:26;20963:3;20956:5;20952:15;20945:51;21015:3;21071:2;21060:9;21056:18;21050:25;21045:2;21038:5;21034:14;21027:49;;21095:3;21130:46;21172:2;21161:9;21157:18;21130:46;:::i;:::-;21114:14;;;21107:70;21196:3;21237:18;;;21231:25;21215:14;;;21208:49;21276:3;21317:18;;;21311:25;21295:14;;;21288:49;;;;-1:-1:-1;21118:5:1;20179:1188;-1:-1:-1;20179:1188:1:o;21970:216::-;22034:9;;;22062:11;;;22009:3;22092:9;;22120:10;;22116:19;;22145:10;;22137:19;;22113:44;22110:70;;;22160:18;;:::i;:::-;22110:70;;21970:216;;;;:::o;22191:168::-;22264:9;;;22295;;22312:15;;;22306:22;;22292:37;22282:71;;22333:18;;:::i;22364:274::-;22404:1;22430;22420:189;;22465:77;22462:1;22455:88;22566:4;22563:1;22556:15;22594:4;22591:1;22584:15;22420:189;-1:-1:-1;22623:9:1;;22364:274::o;22643:128::-;22710:9;;;22731:11;;;22728:37;;;22745:18;;:::i;22776:195::-;22815:3;22846:66;22839:5;22836:77;22833:103;;22916:18;;:::i;:::-;-1:-1:-1;22963:1:1;22952:13;;22776:195::o;22976:752::-;23283:3;23272:9;23265:22;23246:4;23304:45;23344:3;23333:9;23329:19;23321:6;23304:45;:::i;:::-;23397:10;23385:23;;;;23380:2;23365:18;;23358:51;-1:-1:-1;;;;;;23506:15:1;;;23501:2;23486:18;;23479:43;23558:15;;;;23553:2;23538:18;;23531:43;23605:3;23590:19;;23583:35;;;;23649:3;23634:19;;23627:35;23706:14;;23699:22;23693:3;23678:19;;;23671:51;23296:53;22976:752;-1:-1:-1;22976:752:1:o;24291:408::-;-1:-1:-1;;;;;24498:6:1;24494:55;24483:9;24476:74;24586:6;24581:2;24570:9;24566:18;24559:34;24629:2;24624;24613:9;24609:18;24602:30;24457:4;24649:44;24689:2;24678:9;24674:18;24666:6;24649:44;:::i;:::-;24641:52;24291:408;-1:-1:-1;;;;;24291:408:1:o;24704:357::-;24822:12;;24869:4;24858:16;;;24852:23;;24822:12;24887:16;;24884:171;;;24977:66;24967:6;24961:4;24957:17;24954:1;24950:25;24946:98;24939:5;24935:110;24926:119;;24884:171;;24704:357;;;:::o;25066:184::-;25136:6;25189:2;25177:9;25168:7;25164:23;25160:32;25157:52;;;25205:1;25202;25195:12;25157:52;-1:-1:-1;25228:16:1;;25066:184;-1:-1:-1;25066:184:1:o;25557:::-;25609:77;25606:1;25599:88;25706:4;25703:1;25696:15;25730:4;25727:1;25720:15;25746:245;25813:6;25866:2;25854:9;25845:7;25841:23;25837:32;25834:52;;;25882:1;25879;25872:12;25834:52;25914:9;25908:16;25933:28;25955:5;25933:28;:::i;25996:287::-;26125:3;26163:6;26157:13;26179:66;26238:6;26233:3;26226:4;26218:6;26214:17;26179:66;:::i;:::-;26261:16;;;;;25996:287;-1:-1:-1;;25996:287:1:o;26288:184::-;26340:77;26337:1;26330:88;26437:4;26434:1;26427:15;26461:4;26458:1;26451:15","abiDefinition":[{"inputs":[{"internalType":"address","name":"_owner","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AccessControlBadConfirmation","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"bytes32","name":"neededRole","type":"bytes32"}],"name":"AccessControlUnauthorizedAccount","type":"error"},{"inputs":[{"internalType":"address","name":"target","type":"address"}],"name":"AddressEmptyCode","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"AddressInsufficientBalance","type":"error"},{"inputs":[],"name":"AmountIncorrect","type":"error"},{"inputs":[],"name":"CallParamsLengthAboveMax","type":"error"},{"inputs":[],"name":"ChainIncorrect","type":"error"},{"inputs":[],"name":"DeadlineExceeded","type":"error"},{"inputs":[],"name":"DeadlineNotExceeded","type":"error"},{"inputs":[],"name":"DeadlineTooShort","type":"error"},{"inputs":[],"name":"DisputePeriodNotPassed","type":"error"},{"inputs":[],"name":"DisputePeriodPassed","type":"error"},{"inputs":[],"name":"ExclusivityParamsIncorrect","type":"error"},{"inputs":[],"name":"ExclusivityPeriodNotPassed","type":"error"},{"inputs":[],"name":"FailedInnerCall","type":"error"},{"inputs":[],"name":"MsgValueIncorrect","type":"error"},{"inputs":[],"name":"NativeTokenCallValueNotSupported","type":"error"},{"inputs":[],"name":"RecipientIncorrectReturnValue","type":"error"},{"inputs":[],"name":"RecipientNoReturnValue","type":"error"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"SafeERC20FailedOperation","type":"error"},{"inputs":[],"name":"SenderIncorrect","type":"error"},{"inputs":[],"name":"StatusIncorrect","type":"error"},{"inputs":[],"name":"TokenNotContract","type":"error"},{"inputs":[],"name":"TransactionRelayed","type":"error"},{"inputs":[],"name":"ZeroAddress","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"relayer","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"BridgeDepositClaimed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"BridgeDepositRefunded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"relayer","type":"address"}],"name":"BridgeProofDisputed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"relayer","type":"address"},{"indexed":false,"internalType":"bytes32","name":"transactionHash","type":"bytes32"}],"name":"BridgeProofProvided","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":false,"internalType":"bytes","name":"quoteId","type":"bytes"}],"name":"BridgeQuoteDetails","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"relayer","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint32","name":"originChainId","type":"uint32"},{"indexed":false,"internalType":"address","name":"originToken","type":"address"},{"indexed":false,"internalType":"address","name":"destToken","type":"address"},{"indexed":false,"internalType":"uint256","name":"originAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"destAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"chainGasAmount","type":"uint256"}],"name":"BridgeRelayed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"bytes","name":"request","type":"bytes"},{"indexed":false,"internalType":"uint32","name":"destChainId","type":"uint32"},{"indexed":false,"internalType":"address","name":"originToken","type":"address"},{"indexed":false,"internalType":"address","name":"destToken","type":"address"},{"indexed":false,"internalType":"uint256","name":"originAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"destAmount","type":"uint256"},{"indexed":false,"internalType":"bool","name":"sendChainGas","type":"bool"}],"name":"BridgeRequested","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldChainGasAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newChainGasAmount","type":"uint256"}],"name":"ChainGasAmountUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldFeeRate","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newFeeRate","type":"uint256"}],"name":"FeeRateUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"address","name":"recipient","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"FeesSwept","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"previousAdminRole","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"newAdminRole","type":"bytes32"}],"name":"RoleAdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleRevoked","type":"event"},{"inputs":[],"name":"DEFAULT_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"DISPUTE_PERIOD","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"FEE_BPS","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"FEE_RATE_MAX","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"GOVERNOR_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"GUARD_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_CALL_PARAMS_LENGTH","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MIN_DEADLINE_PERIOD","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"REFUNDER_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"REFUND_DELAY","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"RELAYER_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"uint32","name":"dstChainId","type":"uint32"},{"internalType":"address","name":"sender","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"address","name":"originToken","type":"address"},{"internalType":"address","name":"destToken","type":"address"},{"internalType":"uint256","name":"originAmount","type":"uint256"},{"internalType":"uint256","name":"destAmount","type":"uint256"},{"internalType":"bool","name":"sendChainGas","type":"bool"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"internalType":"struct IFastBridge.BridgeParams","name":"params","type":"tuple"}],"name":"bridge","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"uint32","name":"dstChainId","type":"uint32"},{"internalType":"address","name":"sender","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"address","name":"originToken","type":"address"},{"internalType":"address","name":"destToken","type":"address"},{"internalType":"uint256","name":"originAmount","type":"uint256"},{"internalType":"uint256","name":"destAmount","type":"uint256"},{"internalType":"bool","name":"sendChainGas","type":"bool"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"internalType":"struct IFastBridge.BridgeParams","name":"params","type":"tuple"},{"components":[{"internalType":"address","name":"quoteRelayer","type":"address"},{"internalType":"int256","name":"quoteExclusivitySeconds","type":"int256"},{"internalType":"bytes","name":"quoteId","type":"bytes"},{"internalType":"uint256","name":"callValue","type":"uint256"},{"internalType":"bytes","name":"callParams","type":"bytes"}],"internalType":"struct IFastBridgeV2.BridgeParamsV2","name":"paramsV2","type":"tuple"}],"name":"bridge","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"transactionId","type":"bytes32"}],"name":"bridgeProofs","outputs":[{"internalType":"uint96","name":"timestamp","type":"uint96"},{"internalType":"address","name":"relayer","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"bridgeRelayDetails","outputs":[{"internalType":"uint48","name":"blockNumber","type":"uint48"},{"internalType":"uint48","name":"blockTimestamp","type":"uint48"},{"internalType":"address","name":"relayer","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"transactionId","type":"bytes32"}],"name":"bridgeRelays","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"transactionId","type":"bytes32"}],"name":"bridgeStatuses","outputs":[{"internalType":"enum IFastBridgeV2.BridgeStatus","name":"status","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"bridgeTxDetails","outputs":[{"internalType":"enum IFastBridgeV2.BridgeStatus","name":"status","type":"uint8"},{"internalType":"uint40","name":"proofBlockTimestamp","type":"uint40"},{"internalType":"uint48","name":"proofBlockNumber","type":"uint48"},{"internalType":"address","name":"proofRelayer","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"internalType":"address","name":"relayer","type":"address"}],"name":"canClaim","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"chainGasAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"},{"internalType":"address","name":"to","type":"address"}],"name":"claim","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"}],"name":"claim","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"deployBlock","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"transactionId","type":"bytes32"}],"name":"dispute","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"}],"name":"getBridgeTransaction","outputs":[{"components":[{"internalType":"uint32","name":"originChainId","type":"uint32"},{"internalType":"uint32","name":"destChainId","type":"uint32"},{"internalType":"address","name":"originSender","type":"address"},{"internalType":"address","name":"destRecipient","type":"address"},{"internalType":"address","name":"originToken","type":"address"},{"internalType":"address","name":"destToken","type":"address"},{"internalType":"uint256","name":"originAmount","type":"uint256"},{"internalType":"uint256","name":"destAmount","type":"uint256"},{"internalType":"uint256","name":"originFeeAmount","type":"uint256"},{"internalType":"bool","name":"sendChainGas","type":"bool"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint256","name":"nonce","type":"uint256"}],"internalType":"struct IFastBridge.BridgeTransaction","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"}],"name":"getBridgeTransactionV2","outputs":[{"components":[{"internalType":"uint32","name":"originChainId","type":"uint32"},{"internalType":"uint32","name":"destChainId","type":"uint32"},{"internalType":"address","name":"originSender","type":"address"},{"internalType":"address","name":"destRecipient","type":"address"},{"internalType":"address","name":"originToken","type":"address"},{"internalType":"address","name":"destToken","type":"address"},{"internalType":"uint256","name":"originAmount","type":"uint256"},{"internalType":"uint256","name":"destAmount","type":"uint256"},{"internalType":"uint256","name":"originFeeAmount","type":"uint256"},{"internalType":"uint256","name":"callValue","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"address","name":"exclusivityRelayer","type":"address"},{"internalType":"uint256","name":"exclusivityEndTime","type":"uint256"},{"internalType":"bytes","name":"callParams","type":"bytes"}],"internalType":"struct IFastBridgeV2.BridgeTransactionV2","name":"","type":"tuple"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleAdmin","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"uint256","name":"index","type":"uint256"}],"name":"getRoleMember","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleMemberCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"grantRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"hasRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"nonce","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"protocolFeeRate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"protocolFees","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"internalType":"bytes32","name":"destTxHash","type":"bytes32"},{"internalType":"address","name":"relayer","type":"address"}],"name":"prove","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"},{"internalType":"bytes32","name":"destTxHash","type":"bytes32"}],"name":"prove","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"}],"name":"refund","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"}],"name":"relay","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"},{"internalType":"address","name":"relayer","type":"address"}],"name":"relay","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"callerConfirmation","type":"address"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"revokeRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"senderNonces","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"newChainGasAmount","type":"uint256"}],"name":"setChainGasAmount","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"newFeeRate","type":"uint256"}],"name":"setProtocolFeeRate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"address","name":"recipient","type":"address"}],"name":"sweepProtocolFees","outputs":[],"stateMutability":"nonpayable","type":"function"}],"userDoc":{"kind":"user","methods":{"DISPUTE_PERIOD()":{"notice":"Dispute period for relayed transactions"},"MAX_CALL_PARAMS_LENGTH()":{"notice":"Maximum length of accepted callParams"},"MIN_DEADLINE_PERIOD()":{"notice":"Minimum deadline period to relay a requested bridge transaction"},"REFUND_DELAY()":{"notice":"Delay for a transaction after which it could be permisionlessly refunded"},"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256))":{"notice":"Initiates bridge on origin chain to be relayed by off-chain relayer"},"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256),(address,int256,bytes,uint256,bytes))":{"notice":"Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability to provide temporary exclusivity fill rights for the quote relayer."},"bridgeProofs(bytes32)":{"notice":"Returns the timestamp and relayer of a bridge proof"},"bridgeRelayDetails(bytes32)":{"notice":"Relay details on destination chain"},"bridgeRelays(bytes32)":{"notice":"Checks if a transaction has been relayed"},"bridgeStatuses(bytes32)":{"notice":"Returns the status of a bridge transaction"},"bridgeTxDetails(bytes32)":{"notice":"Status of the bridge tx on origin chain"},"canClaim(bytes32,address)":{"notice":"Checks if the dispute period has passed so bridge deposit can be claimed"},"chainGasAmount()":{"notice":"Chain gas amount to forward as rebate if requested"},"claim(bytes)":{"notice":"Completes bridge transaction on origin chain by claiming originally deposited capital.Can only send funds to the relayer address on the proof."},"claim(bytes,address)":{"notice":"Completes bridge transaction on origin chain by claiming originally deposited capital"},"deployBlock()":{"notice":"the block the contract was deployed at"},"dispute(bytes32)":{"notice":"Disputes an outstanding proof in case relayer provided dest chain tx is invalid"},"getBridgeTransaction(bytes)":{"notice":"Decodes bridge request into a bridge transaction"},"getBridgeTransactionV2(bytes)":{"notice":"Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2"},"nonce()":{"notice":"This is deprecated and should not be used."},"protocolFeeRate()":{"notice":"Protocol fee rate taken on origin amount deposited in origin chain"},"protocolFees(address)":{"notice":"Protocol fee amounts accumulated"},"prove(bytes,bytes32)":{"notice":"Provides proof on origin side that relayer provided funds on destination side of bridge transaction"},"prove(bytes32,bytes32,address)":{"notice":"Provides proof on origin side that relayer provided funds on destination side of bridge transaction"},"refund(bytes)":{"notice":"Refunds an outstanding bridge transaction in case optimistic bridging failed"},"relay(bytes)":{"notice":"Relays destination side of bridge transaction by off-chain relayer"},"relay(bytes,address)":{"notice":"Relays destination side of bridge transaction by off-chain relayer"},"senderNonces(address)":{"notice":"Unique bridge nonces tracked per originSender"}},"notice":"FastBridgeV2 is a contract for bridging tokens across chains.","version":1},"developerDoc":{"errors":{"AccessControlBadConfirmation()":[{"details":"The caller of a function is not the expected one. NOTE: Don't confuse with {AccessControlUnauthorizedAccount}."}],"AccessControlUnauthorizedAccount(address,bytes32)":[{"details":"The `account` is missing a role."}],"AddressEmptyCode(address)":[{"details":"There's no code at `target` (it is not a contract)."}],"AddressInsufficientBalance(address)":[{"details":"The ETH balance of the account is not enough to perform the operation."}],"FailedInnerCall()":[{"details":"A call to an address target failed. The target may have reverted."}],"SafeERC20FailedOperation(address)":[{"details":"An operation with an ERC20 token failed."}]},"events":{"RoleAdminChanged(bytes32,bytes32,bytes32)":{"details":"Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole` `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite {RoleAdminChanged} not being emitted signaling this."},"RoleGranted(bytes32,address,address)":{"details":"Emitted when `account` is granted `role`. `sender` is the account that originated the contract call, an admin role bearer except when using {AccessControl-_setupRole}."},"RoleRevoked(bytes32,address,address)":{"details":"Emitted when `account` is revoked `role`. `sender` is the account that originated the contract call: - if using `revokeRole`, it is the admin role bearer - if using `renounceRole`, it is the role bearer (i.e. `account`)"}},"kind":"dev","methods":{"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256))":{"params":{"params":"The parameters required to bridge"}},"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256),(address,int256,bytes,uint256,bytes))":{"params":{"params":"The parameters required to bridge","paramsV2":"The parameters for exclusivity fill rights (optional, can be left empty)"}},"bridgeProofs(bytes32)":{"params":{"transactionId":"The ID of the bridge transaction"},"returns":{"relayer":"The relayer address of the bridge proof","timestamp":"The timestamp of the bridge proof"}},"bridgeRelays(bytes32)":{"params":{"transactionId":"The ID of the transaction to check"},"returns":{"_0":"True if the transaction has been relayed, false otherwise"}},"bridgeStatuses(bytes32)":{"params":{"transactionId":"The ID of the bridge transaction"},"returns":{"status":"BridgeStatus Status of the bridge transaction"}},"canClaim(bytes32,address)":{"params":{"relayer":"The address of the relayer attempting to claim","transactionId":"The transaction id associated with the encoded bridge transaction to check"}},"claim(bytes)":{"params":{"request":"The encoded bridge transaction to claim on origin chain"}},"claim(bytes,address)":{"params":{"request":"The encoded bridge transaction to claim on origin chain","to":"The recipient address of the funds"}},"dispute(bytes32)":{"params":{"transactionId":"The transaction id associated with the encoded bridge transaction to dispute"}},"getBridgeTransaction(bytes)":{"details":"This method is added to achieve backwards compatibility with decoding requests into V1 structs: - `callValue` is partially reported as a zero/non-zero flag - `callParams` is ignored In order to process all kinds of requests use getBridgeTransactionV2 instead.","params":{"request":"The bridge request to decode"}},"getBridgeTransactionV2(bytes)":{"params":{"request":"The bridge request to decode"}},"getRoleAdmin(bytes32)":{"details":"Returns the admin role that controls `role`. See {grantRole} and {revokeRole}. To change a role's admin, use {_setRoleAdmin}."},"getRoleMember(bytes32,uint256)":{"details":"Returns one of the accounts that have `role`. `index` must be a value between 0 and {getRoleMemberCount}, non-inclusive. Role bearers are not sorted in any particular way, and their ordering may change at any point. WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure you perform all queries on the same block. See the following https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post] for more information."},"getRoleMemberCount(bytes32)":{"details":"Returns the number of accounts that have `role`. Can be used together with {getRoleMember} to enumerate all bearers of a role."},"grantRole(bytes32,address)":{"details":"Grants `role` to `account`. If `account` had not been already granted `role`, emits a {RoleGranted} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleGranted} event."},"hasRole(bytes32,address)":{"details":"Returns `true` if `account` has been granted `role`."},"prove(bytes,bytes32)":{"params":{"destTxHash":"The destination tx hash proving bridge transaction was relayed","request":"The encoded bridge transaction to prove on origin chain"}},"prove(bytes32,bytes32,address)":{"params":{"destTxHash":"The destination tx hash proving bridge transaction was relayed","relayer":"The address of the relaying entity which should have control of the origin funds when claimed","transactionId":"The transaction id associated with the encoded bridge transaction to prove"}},"refund(bytes)":{"params":{"request":"The encoded bridge transaction to refund"}},"relay(bytes)":{"params":{"request":"The encoded bridge transaction to relay on destination chain"}},"relay(bytes,address)":{"params":{"relayer":"The address of the relaying entity which should have control of the origin funds when claimed","request":"The encoded bridge transaction to relay on destination chain"}},"renounceRole(bytes32,address)":{"details":"Revokes `role` from the calling account. Roles are often managed via {grantRole} and {revokeRole}: this function's purpose is to provide a mechanism for accounts to lose their privileges if they are compromised (such as when a trusted device is misplaced). If the calling account had been revoked `role`, emits a {RoleRevoked} event. Requirements: - the caller must be `callerConfirmation`. May emit a {RoleRevoked} event."},"revokeRole(bytes32,address)":{"details":"Revokes `role` from `account`. If `account` had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleRevoked} event."},"supportsInterface(bytes4)":{"details":"See {IERC165-supportsInterface}."}},"stateVariables":{"nonce":{"details":"Replaced by senderNonces"}},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_owner\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"AccessControlBadConfirmation\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"neededRole\",\"type\":\"bytes32\"}],\"name\":\"AccessControlUnauthorizedAccount\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"}],\"name\":\"AddressEmptyCode\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"AddressInsufficientBalance\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"AmountIncorrect\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"CallParamsLengthAboveMax\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ChainIncorrect\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DeadlineExceeded\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DeadlineNotExceeded\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DeadlineTooShort\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DisputePeriodNotPassed\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DisputePeriodPassed\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ExclusivityParamsIncorrect\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ExclusivityPeriodNotPassed\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"FailedInnerCall\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"MsgValueIncorrect\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"NativeTokenCallValueNotSupported\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"RecipientIncorrectReturnValue\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"RecipientNoReturnValue\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"}],\"name\":\"SafeERC20FailedOperation\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"SenderIncorrect\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"StatusIncorrect\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"TokenNotContract\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"TransactionRelayed\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ZeroAddress\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"BridgeDepositClaimed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"BridgeDepositRefunded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"name\":\"BridgeProofDisputed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"transactionHash\",\"type\":\"bytes32\"}],\"name\":\"BridgeProofProvided\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"quoteId\",\"type\":\"bytes\"}],\"name\":\"BridgeQuoteDetails\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"originChainId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"chainGasAmount\",\"type\":\"uint256\"}],\"name\":\"BridgeRelayed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"destChainId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"sendChainGas\",\"type\":\"bool\"}],\"name\":\"BridgeRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"oldChainGasAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newChainGasAmount\",\"type\":\"uint256\"}],\"name\":\"ChainGasAmountUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"oldFeeRate\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newFeeRate\",\"type\":\"uint256\"}],\"name\":\"FeeRateUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"FeesSwept\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"previousAdminRole\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"newAdminRole\",\"type\":\"bytes32\"}],\"name\":\"RoleAdminChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleGranted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleRevoked\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"DEFAULT_ADMIN_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"DISPUTE_PERIOD\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"FEE_BPS\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"FEE_RATE_MAX\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"GOVERNOR_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"GUARD_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"MAX_CALL_PARAMS_LENGTH\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"MIN_DEADLINE_PERIOD\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"REFUNDER_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"REFUND_DELAY\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"RELAYER_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"dstChainId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"sendChainGas\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"}],\"internalType\":\"struct IFastBridge.BridgeParams\",\"name\":\"params\",\"type\":\"tuple\"}],\"name\":\"bridge\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"dstChainId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"sendChainGas\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"}],\"internalType\":\"struct IFastBridge.BridgeParams\",\"name\":\"params\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"quoteRelayer\",\"type\":\"address\"},{\"internalType\":\"int256\",\"name\":\"quoteExclusivitySeconds\",\"type\":\"int256\"},{\"internalType\":\"bytes\",\"name\":\"quoteId\",\"type\":\"bytes\"},{\"internalType\":\"uint256\",\"name\":\"callValue\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"callParams\",\"type\":\"bytes\"}],\"internalType\":\"struct IFastBridgeV2.BridgeParamsV2\",\"name\":\"paramsV2\",\"type\":\"tuple\"}],\"name\":\"bridge\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"}],\"name\":\"bridgeProofs\",\"outputs\":[{\"internalType\":\"uint96\",\"name\":\"timestamp\",\"type\":\"uint96\"},{\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"bridgeRelayDetails\",\"outputs\":[{\"internalType\":\"uint48\",\"name\":\"blockNumber\",\"type\":\"uint48\"},{\"internalType\":\"uint48\",\"name\":\"blockTimestamp\",\"type\":\"uint48\"},{\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"}],\"name\":\"bridgeRelays\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"}],\"name\":\"bridgeStatuses\",\"outputs\":[{\"internalType\":\"enum IFastBridgeV2.BridgeStatus\",\"name\":\"status\",\"type\":\"uint8\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"bridgeTxDetails\",\"outputs\":[{\"internalType\":\"enum IFastBridgeV2.BridgeStatus\",\"name\":\"status\",\"type\":\"uint8\"},{\"internalType\":\"uint40\",\"name\":\"proofBlockTimestamp\",\"type\":\"uint40\"},{\"internalType\":\"uint48\",\"name\":\"proofBlockNumber\",\"type\":\"uint48\"},{\"internalType\":\"address\",\"name\":\"proofRelayer\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"name\":\"canClaim\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"chainGasAmount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"claim\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"claim\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"deployBlock\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"}],\"name\":\"dispute\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"getBridgeTransaction\",\"outputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"originChainId\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"destChainId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"originSender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destRecipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"originFeeAmount\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"sendChainGas\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"}],\"internalType\":\"struct IFastBridge.BridgeTransaction\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"getBridgeTransactionV2\",\"outputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"originChainId\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"destChainId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"originSender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destRecipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"originFeeAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"callValue\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"exclusivityRelayer\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"exclusivityEndTime\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"callParams\",\"type\":\"bytes\"}],\"internalType\":\"struct IFastBridgeV2.BridgeTransactionV2\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"}],\"name\":\"getRoleAdmin\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"index\",\"type\":\"uint256\"}],\"name\":\"getRoleMember\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"}],\"name\":\"getRoleMemberCount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"grantRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"hasRole\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"nonce\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"protocolFeeRate\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"protocolFees\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"destTxHash\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"name\":\"prove\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"},{\"internalType\":\"bytes32\",\"name\":\"destTxHash\",\"type\":\"bytes32\"}],\"name\":\"prove\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"refund\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"relay\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"},{\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"name\":\"relay\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"callerConfirmation\",\"type\":\"address\"}],\"name\":\"renounceRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"revokeRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"senderNonces\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"newChainGasAmount\",\"type\":\"uint256\"}],\"name\":\"setChainGasAmount\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"newFeeRate\",\"type\":\"uint256\"}],\"name\":\"setProtocolFeeRate\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes4\",\"name\":\"interfaceId\",\"type\":\"bytes4\"}],\"name\":\"supportsInterface\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"}],\"name\":\"sweepProtocolFees\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"errors\":{\"AccessControlBadConfirmation()\":[{\"details\":\"The caller of a function is not the expected one. NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\"}],\"AccessControlUnauthorizedAccount(address,bytes32)\":[{\"details\":\"The `account` is missing a role.\"}],\"AddressEmptyCode(address)\":[{\"details\":\"There's no code at `target` (it is not a contract).\"}],\"AddressInsufficientBalance(address)\":[{\"details\":\"The ETH balance of the account is not enough to perform the operation.\"}],\"FailedInnerCall()\":[{\"details\":\"A call to an address target failed. The target may have reverted.\"}],\"SafeERC20FailedOperation(address)\":[{\"details\":\"An operation with an ERC20 token failed.\"}]},\"events\":{\"RoleAdminChanged(bytes32,bytes32,bytes32)\":{\"details\":\"Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole` `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite {RoleAdminChanged} not being emitted signaling this.\"},\"RoleGranted(bytes32,address,address)\":{\"details\":\"Emitted when `account` is granted `role`. `sender` is the account that originated the contract call, an admin role bearer except when using {AccessControl-_setupRole}.\"},\"RoleRevoked(bytes32,address,address)\":{\"details\":\"Emitted when `account` is revoked `role`. `sender` is the account that originated the contract call: - if using `revokeRole`, it is the admin role bearer - if using `renounceRole`, it is the role bearer (i.e. `account`)\"}},\"kind\":\"dev\",\"methods\":{\"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256))\":{\"params\":{\"params\":\"The parameters required to bridge\"}},\"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256),(address,int256,bytes,uint256,bytes))\":{\"params\":{\"params\":\"The parameters required to bridge\",\"paramsV2\":\"The parameters for exclusivity fill rights (optional, can be left empty)\"}},\"bridgeProofs(bytes32)\":{\"params\":{\"transactionId\":\"The ID of the bridge transaction\"},\"returns\":{\"relayer\":\"The relayer address of the bridge proof\",\"timestamp\":\"The timestamp of the bridge proof\"}},\"bridgeRelays(bytes32)\":{\"params\":{\"transactionId\":\"The ID of the transaction to check\"},\"returns\":{\"_0\":\"True if the transaction has been relayed, false otherwise\"}},\"bridgeStatuses(bytes32)\":{\"params\":{\"transactionId\":\"The ID of the bridge transaction\"},\"returns\":{\"status\":\"BridgeStatus Status of the bridge transaction\"}},\"canClaim(bytes32,address)\":{\"params\":{\"relayer\":\"The address of the relayer attempting to claim\",\"transactionId\":\"The transaction id associated with the encoded bridge transaction to check\"}},\"claim(bytes)\":{\"params\":{\"request\":\"The encoded bridge transaction to claim on origin chain\"}},\"claim(bytes,address)\":{\"params\":{\"request\":\"The encoded bridge transaction to claim on origin chain\",\"to\":\"The recipient address of the funds\"}},\"dispute(bytes32)\":{\"params\":{\"transactionId\":\"The transaction id associated with the encoded bridge transaction to dispute\"}},\"getBridgeTransaction(bytes)\":{\"details\":\"This method is added to achieve backwards compatibility with decoding requests into V1 structs: - `callValue` is partially reported as a zero/non-zero flag - `callParams` is ignored In order to process all kinds of requests use getBridgeTransactionV2 instead.\",\"params\":{\"request\":\"The bridge request to decode\"}},\"getBridgeTransactionV2(bytes)\":{\"params\":{\"request\":\"The bridge request to decode\"}},\"getRoleAdmin(bytes32)\":{\"details\":\"Returns the admin role that controls `role`. See {grantRole} and {revokeRole}. To change a role's admin, use {_setRoleAdmin}.\"},\"getRoleMember(bytes32,uint256)\":{\"details\":\"Returns one of the accounts that have `role`. `index` must be a value between 0 and {getRoleMemberCount}, non-inclusive. Role bearers are not sorted in any particular way, and their ordering may change at any point. WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure you perform all queries on the same block. See the following https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post] for more information.\"},\"getRoleMemberCount(bytes32)\":{\"details\":\"Returns the number of accounts that have `role`. Can be used together with {getRoleMember} to enumerate all bearers of a role.\"},\"grantRole(bytes32,address)\":{\"details\":\"Grants `role` to `account`. If `account` had not been already granted `role`, emits a {RoleGranted} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleGranted} event.\"},\"hasRole(bytes32,address)\":{\"details\":\"Returns `true` if `account` has been granted `role`.\"},\"prove(bytes,bytes32)\":{\"params\":{\"destTxHash\":\"The destination tx hash proving bridge transaction was relayed\",\"request\":\"The encoded bridge transaction to prove on origin chain\"}},\"prove(bytes32,bytes32,address)\":{\"params\":{\"destTxHash\":\"The destination tx hash proving bridge transaction was relayed\",\"relayer\":\"The address of the relaying entity which should have control of the origin funds when claimed\",\"transactionId\":\"The transaction id associated with the encoded bridge transaction to prove\"}},\"refund(bytes)\":{\"params\":{\"request\":\"The encoded bridge transaction to refund\"}},\"relay(bytes)\":{\"params\":{\"request\":\"The encoded bridge transaction to relay on destination chain\"}},\"relay(bytes,address)\":{\"params\":{\"relayer\":\"The address of the relaying entity which should have control of the origin funds when claimed\",\"request\":\"The encoded bridge transaction to relay on destination chain\"}},\"renounceRole(bytes32,address)\":{\"details\":\"Revokes `role` from the calling account. Roles are often managed via {grantRole} and {revokeRole}: this function's purpose is to provide a mechanism for accounts to lose their privileges if they are compromised (such as when a trusted device is misplaced). If the calling account had been revoked `role`, emits a {RoleRevoked} event. Requirements: - the caller must be `callerConfirmation`. May emit a {RoleRevoked} event.\"},\"revokeRole(bytes32,address)\":{\"details\":\"Revokes `role` from `account`. If `account` had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleRevoked} event.\"},\"supportsInterface(bytes4)\":{\"details\":\"See {IERC165-supportsInterface}.\"}},\"stateVariables\":{\"nonce\":{\"details\":\"Replaced by senderNonces\"}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"DISPUTE_PERIOD()\":{\"notice\":\"Dispute period for relayed transactions\"},\"MAX_CALL_PARAMS_LENGTH()\":{\"notice\":\"Maximum length of accepted callParams\"},\"MIN_DEADLINE_PERIOD()\":{\"notice\":\"Minimum deadline period to relay a requested bridge transaction\"},\"REFUND_DELAY()\":{\"notice\":\"Delay for a transaction after which it could be permisionlessly refunded\"},\"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256))\":{\"notice\":\"Initiates bridge on origin chain to be relayed by off-chain relayer\"},\"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256),(address,int256,bytes,uint256,bytes))\":{\"notice\":\"Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability to provide temporary exclusivity fill rights for the quote relayer.\"},\"bridgeProofs(bytes32)\":{\"notice\":\"Returns the timestamp and relayer of a bridge proof\"},\"bridgeRelayDetails(bytes32)\":{\"notice\":\"Relay details on destination chain\"},\"bridgeRelays(bytes32)\":{\"notice\":\"Checks if a transaction has been relayed\"},\"bridgeStatuses(bytes32)\":{\"notice\":\"Returns the status of a bridge transaction\"},\"bridgeTxDetails(bytes32)\":{\"notice\":\"Status of the bridge tx on origin chain\"},\"canClaim(bytes32,address)\":{\"notice\":\"Checks if the dispute period has passed so bridge deposit can be claimed\"},\"chainGasAmount()\":{\"notice\":\"Chain gas amount to forward as rebate if requested\"},\"claim(bytes)\":{\"notice\":\"Completes bridge transaction on origin chain by claiming originally deposited capital.Can only send funds to the relayer address on the proof.\"},\"claim(bytes,address)\":{\"notice\":\"Completes bridge transaction on origin chain by claiming originally deposited capital\"},\"deployBlock()\":{\"notice\":\"the block the contract was deployed at\"},\"dispute(bytes32)\":{\"notice\":\"Disputes an outstanding proof in case relayer provided dest chain tx is invalid\"},\"getBridgeTransaction(bytes)\":{\"notice\":\"Decodes bridge request into a bridge transaction\"},\"getBridgeTransactionV2(bytes)\":{\"notice\":\"Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\"},\"nonce()\":{\"notice\":\"This is deprecated and should not be used.\"},\"protocolFeeRate()\":{\"notice\":\"Protocol fee rate taken on origin amount deposited in origin chain\"},\"protocolFees(address)\":{\"notice\":\"Protocol fee amounts accumulated\"},\"prove(bytes,bytes32)\":{\"notice\":\"Provides proof on origin side that relayer provided funds on destination side of bridge transaction\"},\"prove(bytes32,bytes32,address)\":{\"notice\":\"Provides proof on origin side that relayer provided funds on destination side of bridge transaction\"},\"refund(bytes)\":{\"notice\":\"Refunds an outstanding bridge transaction in case optimistic bridging failed\"},\"relay(bytes)\":{\"notice\":\"Relays destination side of bridge transaction by off-chain relayer\"},\"relay(bytes,address)\":{\"notice\":\"Relays destination side of bridge transaction by off-chain relayer\"},\"senderNonces(address)\":{\"notice\":\"Unique bridge nonces tracked per originSender\"}},\"notice\":\"FastBridgeV2 is a contract for bridging tokens across chains.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeV2.sol\":\"FastBridgeV2\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeV2.sol\":{\"keccak256\":\"0xfd916c030b1ffca5a136817827b8018c8ba42ca089905747f3de6148b73eb35e\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://18e6438c4096deb8ae453fb3365ba2b07d52944e93c08288fc5d012b71bf6bb3\",\"dweb:/ipfs/QmfEMqpT1zz6RRm7UuHLRowe1tds2cTGLrVonfm9XSCACj\"]}},\"version\":1}"},"hashes":{"DEFAULT_ADMIN_ROLE()":"a217fddf","DISPUTE_PERIOD()":"a5bbe22b","FEE_BPS()":"bf333f2c","FEE_RATE_MAX()":"0f5f6ed7","GOVERNOR_ROLE()":"ccc57490","GUARD_ROLE()":"03ed0ee5","MAX_CALL_PARAMS_LENGTH()":"df36bb13","MIN_DEADLINE_PERIOD()":"820688d5","REFUNDER_ROLE()":"5960ccf2","REFUND_DELAY()":"190da595","RELAYER_ROLE()":"926d7d7f","bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256))":"45851694","bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256),(address,int256,bytes,uint256,bytes))":"bfc7c607","bridgeProofs(bytes32)":"91ad5039","bridgeRelayDetails(bytes32)":"c79371b1","bridgeRelays(bytes32)":"8379a24f","bridgeStatuses(bytes32)":"051287bc","bridgeTxDetails(bytes32)":"63787e52","canClaim(bytes32,address)":"aa9641ab","chainGasAmount()":"e00a83e0","claim(bytes)":"c63ff8dd","claim(bytes,address)":"41fcb612","deployBlock()":"a3ec191a","dispute(bytes32)":"add98c70","getBridgeTransaction(bytes)":"ac11fb1a","getBridgeTransactionV2(bytes)":"5aa6ccba","getRoleAdmin(bytes32)":"248a9ca3","getRoleMember(bytes32,uint256)":"9010d07c","getRoleMemberCount(bytes32)":"ca15c873","grantRole(bytes32,address)":"2f2ff15d","hasRole(bytes32,address)":"91d14854","nonce()":"affed0e0","protocolFeeRate()":"58f85880","protocolFees(address)":"dcf844a7","prove(bytes,bytes32)":"886d36ff","prove(bytes32,bytes32,address)":"18e4357d","refund(bytes)":"5eb7d946","relay(bytes)":"8f0d6f17","relay(bytes,address)":"9c9545f0","renounceRole(bytes32,address)":"36568abe","revokeRole(bytes32,address)":"d547741f","senderNonces(address)":"295710ff","setChainGasAmount(uint256)":"b250fe6b","setProtocolFeeRate(uint256)":"b13aa2d6","supportsInterface(bytes4)":"01ffc9a7","sweepProtocolFees(address,address)":"06f333f2"}},"solidity/FastBridgeV2.sol:IAccessControl":{"code":"0x","runtime-code":"0x","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.24 ^0.8.0 ^0.8.20;\n\n// contracts/interfaces/IAdmin.sol\n\ninterface IAdmin {\n // ============ Events ============\n\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n event ChainGasAmountUpdated(uint256 oldChainGasAmount, uint256 newChainGasAmount);\n\n // ============ Methods ============\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n\n function setChainGasAmount(uint256 newChainGasAmount) external;\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IFastBridgeRecipient.sol\n\ninterface IFastBridgeRecipient {\n function fastBridgeTransferReceived(\n address token,\n uint256 amount,\n bytes memory callParams\n )\n external\n payable\n returns (bytes4);\n}\n\n// contracts/interfaces/IFastBridgeV2Errors.sol\n\ninterface IFastBridgeV2Errors {\n error AmountIncorrect();\n error CallParamsLengthAboveMax();\n error ChainIncorrect();\n error ExclusivityParamsIncorrect();\n error MsgValueIncorrect();\n error NativeTokenCallValueNotSupported();\n error SenderIncorrect();\n error StatusIncorrect();\n error ZeroAddress();\n\n error RecipientIncorrectReturnValue();\n error RecipientNoReturnValue();\n\n error DeadlineExceeded();\n error DeadlineNotExceeded();\n error DeadlineTooShort();\n error DisputePeriodNotPassed();\n error DisputePeriodPassed();\n error ExclusivityPeriodNotPassed();\n\n error TransactionRelayed();\n}\n\n// contracts/libs/Errors.sol\n\nerror DeadlineExceeded();\nerror DeadlineNotExceeded();\nerror DeadlineTooShort();\nerror InsufficientOutputAmount();\n\nerror MsgValueIncorrect();\nerror PoolNotFound();\nerror TokenAddressMismatch();\nerror TokenNotContract();\nerror TokenNotETH();\nerror TokensIdentical();\n\nerror ChainIncorrect();\nerror AmountIncorrect();\nerror ZeroAddress();\n\nerror DisputePeriodNotPassed();\nerror DisputePeriodPassed();\nerror SenderIncorrect();\nerror StatusIncorrect();\nerror TransactionIdIncorrect();\nerror TransactionRelayed();\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// contracts/interfaces/IFastBridgeV2.sol\n\ninterface IFastBridgeV2 is IFastBridge {\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n struct BridgeTxDetails {\n BridgeStatus status;\n uint40 proofBlockTimestamp;\n uint48 proofBlockNumber;\n address proofRelayer;\n }\n\n struct BridgeRelay {\n uint48 blockNumber;\n uint48 blockTimestamp;\n address relayer;\n }\n\n /// @notice New params introduced in the FastBridgeV2.\n /// We are passing fields from the older BridgeParams struct outside of this struct\n /// for backwards compatibility.\n /// Note: quoteRelayer and quoteExclusivitySeconds are either both zero (indicating no exclusivity)\n /// or both non-zero (indicating exclusivity for the given period).\n /// Note: callValue \u003e 0 can NOT be used with destToken = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE (ETH_ADDRESS)\n /// @param quoteRelayer Relayer that provided the quote for the transaction\n /// @param quoteExclusivitySeconds Period of time the quote relayer is guaranteed exclusivity after user's deposit\n /// @param quoteId Unique quote identifier used for tracking the quote\n /// @param callValue ETH value to send to the recipient (if any)\n /// @param callParams Parameters for the arbitrary call to the destination recipient (if any)\n struct BridgeParamsV2 {\n address quoteRelayer;\n int256 quoteExclusivitySeconds;\n bytes quoteId;\n uint256 callValue;\n bytes callParams;\n }\n\n /// @notice Updated bridge transaction struct to include parameters introduced in FastBridgeV2.\n /// Note: only `exclusivityRelayer` can fill such a transaction until `exclusivityEndTime`.\n /// TODO: consider changing the encoding scheme to prevent spending extra gas on decoding.\n struct BridgeTransactionV2 {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n uint256 callValue; // ETH value to send to the recipient (if any) - replaces V1's sendChainGas flag\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n address exclusivityRelayer;\n uint256 exclusivityEndTime;\n bytes callParams;\n }\n\n event BridgeQuoteDetails(bytes32 indexed transactionId, bytes quoteId);\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability\n /// to provide temporary exclusivity fill rights for the quote relayer.\n /// @param params The parameters required to bridge\n /// @param paramsV2 The parameters for exclusivity fill rights (optional, can be left empty)\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function relay(bytes memory request, address relayer) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param transactionId The transaction id associated with the encoded bridge transaction to prove\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital.\n /// @notice Can only send funds to the relayer address on the proof.\n /// @param request The encoded bridge transaction to claim on origin chain\n function claim(bytes memory request) external;\n /// @notice Checks if a transaction has been relayed\n /// @param transactionId The ID of the transaction to check\n /// @return True if the transaction has been relayed, false otherwise\n function bridgeRelays(bytes32 transactionId) external view returns (bool);\n\n /// @notice Returns the status of a bridge transaction\n /// @param transactionId The ID of the bridge transaction\n /// @return BridgeStatus Status of the bridge transaction\n function bridgeStatuses(bytes32 transactionId) external view returns (BridgeStatus);\n\n /// @notice Returns the timestamp and relayer of a bridge proof\n /// @param transactionId The ID of the bridge transaction\n /// @return timestamp The timestamp of the bridge proof\n /// @return relayer The relayer address of the bridge proof\n function bridgeProofs(bytes32 transactionId) external view returns (uint96 timestamp, address relayer);\n\n /// @notice Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\n /// @param request The bridge request to decode\n function getBridgeTransactionV2(bytes memory request) external view returns (BridgeTransactionV2 memory);\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// contracts/libs/UniversalToken.sol\n\nlibrary UniversalTokenLib {\n using SafeERC20 for IERC20;\n\n address internal constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Transfers tokens to the given account. Reverts if transfer is not successful.\n /// @dev This might trigger fallback, if ETH is transferred to the contract.\n /// Make sure this can not lead to reentrancy attacks.\n function universalTransfer(address token, address to, uint256 value) internal {\n // Don't do anything, if need to send tokens to this address\n if (to == address(this)) return;\n // Don't do anything, if trying to send zero value\n if (value == 0) return;\n if (token == ETH_ADDRESS) {\n /// @dev Note: this can potentially lead to executing code in `to`.\n // solhint-disable-next-line avoid-low-level-calls\n (bool success,) = to.call{value: value}(\"\");\n require(success, \"ETH transfer failed\");\n } else {\n IERC20(token).safeTransfer(to, value);\n }\n }\n\n /// @notice Issues an infinite allowance to the spender, if the current allowance is insufficient\n /// to spend the given amount.\n function universalApproveInfinity(address token, address spender, uint256 amountToSpend) internal {\n // ETH Chad doesn't require your approval\n if (token == ETH_ADDRESS) return;\n // No-op if allowance is already sufficient\n uint256 allowance = IERC20(token).allowance(address(this), spender);\n if (allowance \u003e= amountToSpend) return;\n // Otherwise, reset approval to 0 and set to max allowance\n if (allowance \u003e 0) IERC20(token).safeDecreaseAllowance(spender, allowance);\n IERC20(token).safeIncreaseAllowance(spender, type(uint256).max);\n }\n\n /// @notice Returns the balance of the given token (or native ETH) for the given account.\n function universalBalanceOf(address token, address account) internal view returns (uint256) {\n if (token == ETH_ADDRESS) {\n return account.balance;\n } else {\n return IERC20(token).balanceOf(account);\n }\n }\n\n /// @dev Checks that token is a contract and not ETH_ADDRESS.\n function assertIsContract(address token) internal view {\n // Check that ETH_ADDRESS was not used (in case this is a predeploy on any of the chains)\n if (token == UniversalTokenLib.ETH_ADDRESS) revert TokenNotContract();\n // Check that token is not an EOA\n if (token.code.length == 0) revert TokenNotContract();\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/Admin.sol\n\ncontract Admin is IAdmin, AccessControlEnumerable {\n using UniversalTokenLib for address;\n\n bytes32 public constant RELAYER_ROLE = keccak256(\"RELAYER_ROLE\");\n bytes32 public constant REFUNDER_ROLE = keccak256(\"REFUNDER_ROLE\");\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n uint256 public constant FEE_BPS = 1e6;\n uint256 public constant FEE_RATE_MAX = 0.01e6; // max 1% on origin amount\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Chain gas amount to forward as rebate if requested\n uint256 public chainGasAmount;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n }\n\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n require(newFeeRate \u003c= FEE_RATE_MAX, \"newFeeRate \u003e max\");\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n token.universalTransfer(recipient, feeAmount);\n emit FeesSwept(token, recipient, feeAmount);\n }\n\n function setChainGasAmount(uint256 newChainGasAmount) external onlyRole(GOVERNOR_ROLE) {\n uint256 oldChainGasAmount = chainGasAmount;\n chainGasAmount = newChainGasAmount;\n emit ChainGasAmountUpdated(oldChainGasAmount, newChainGasAmount);\n }\n}\n\n// contracts/FastBridgeV2.sol\n\n/// @notice FastBridgeV2 is a contract for bridging tokens across chains.\ncontract FastBridgeV2 is Admin, IFastBridgeV2, IFastBridgeV2Errors {\n using SafeERC20 for IERC20;\n using UniversalTokenLib for address;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Delay for a transaction after which it could be permisionlessly refunded\n uint256 public constant REFUND_DELAY = 7 days;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n /// @notice Maximum length of accepted callParams\n uint256 public constant MAX_CALL_PARAMS_LENGTH = 2 ** 16 - 1;\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeTxDetails) public bridgeTxDetails;\n /// @notice Relay details on destination chain\n mapping(bytes32 =\u003e BridgeRelay) public bridgeRelayDetails;\n /// @notice Unique bridge nonces tracked per originSender\n mapping(address =\u003e uint256) public senderNonces;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Replaced by senderNonces\n uint256 public immutable nonce = 0;\n /// @notice the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n bridge({\n params: params,\n paramsV2: BridgeParamsV2({\n quoteRelayer: address(0),\n quoteExclusivitySeconds: 0,\n quoteId: bytes(\"\"),\n callValue: 0,\n callParams: bytes(\"\")\n })\n });\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes memory request) external payable {\n relay({request: request, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes memory request, bytes32 destTxHash) external {\n prove({transactionId: keccak256(request), destTxHash: destTxHash, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridgeV2\n function claim(bytes memory request) external {\n claim({request: request, to: address(0)});\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003e DISPUTE_PERIOD) {\n revert DisputePeriodPassed();\n }\n\n // @dev relayer gets slashed effectively if dest relay has gone thru\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n bridgeTxDetails[transactionId].proofRelayer = address(0);\n bridgeTxDetails[transactionId].proofBlockTimestamp = 0;\n bridgeTxDetails[transactionId].proofBlockNumber = 0;\n\n emit BridgeProofDisputed(transactionId, msg.sender);\n }\n\n /// @inheritdoc IFastBridge\n function refund(bytes memory request) external {\n bytes32 transactionId = keccak256(request);\n\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n\n if (bridgeTxDetails[transactionId].status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n\n if (hasRole(REFUNDER_ROLE, msg.sender)) {\n // Refunder can refund if deadline has passed\n if (block.timestamp \u003c= transaction.deadline) revert DeadlineNotExceeded();\n } else {\n // Permissionless refund is allowed after REFUND_DELAY\n if (block.timestamp \u003c= transaction.deadline + REFUND_DELAY) revert DeadlineNotExceeded();\n }\n\n // if all checks passed, set to REFUNDED status\n bridgeTxDetails[transactionId].status = BridgeStatus.REFUNDED;\n\n // transfer origin collateral back to original sender\n address to = transaction.originSender;\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount + transaction.originFeeAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (bridgeTxDetails[transactionId].proofRelayer != relayer) revert SenderIncorrect();\n return _timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n /// @dev This method is added to achieve backwards compatibility with decoding requests into V1 structs:\n /// - `callValue` is partially reported as a zero/non-zero flag\n /// - `callParams` is ignored\n /// In order to process all kinds of requests use getBridgeTransactionV2 instead.\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory) {\n // Try decoding into V2 struct first. This will revert if V1 struct is passed\n try this.getBridgeTransactionV2(request) returns (BridgeTransactionV2 memory txV2) {\n // Note: we entirely ignore the callParams field, as it was not present in V1\n return BridgeTransaction({\n originChainId: txV2.originChainId,\n destChainId: txV2.destChainId,\n originSender: txV2.originSender,\n destRecipient: txV2.destRecipient,\n originToken: txV2.originToken,\n destToken: txV2.destToken,\n originAmount: txV2.originAmount,\n destAmount: txV2.destAmount,\n originFeeAmount: txV2.originFeeAmount,\n sendChainGas: txV2.callValue != 0,\n deadline: txV2.deadline,\n nonce: txV2.nonce\n });\n } catch {\n // Fallback to V1 struct\n return abi.decode(request, (BridgeTransaction));\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) public payable {\n int256 exclusivityEndTime = int256(block.timestamp) + paramsV2.quoteExclusivitySeconds;\n _validateBridgeParams(params, paramsV2, exclusivityEndTime);\n\n // transfer tokens to bridge contract\n /// @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _takeBridgedUserAsset(params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n\n // set status to requested\n bytes memory request = abi.encode(\n BridgeTransactionV2({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n callValue: paramsV2.callValue,\n deadline: params.deadline,\n nonce: senderNonces[params.sender]++, // increment nonce on every bridge\n exclusivityRelayer: paramsV2.quoteRelayer,\n // We checked exclusivityEndTime to be in range (0 .. params.deadline] above, so can safely cast\n exclusivityEndTime: uint256(exclusivityEndTime),\n callParams: paramsV2.callParams\n })\n );\n bytes32 transactionId = keccak256(request);\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n\n emit BridgeRequested({\n transactionId: transactionId,\n sender: params.sender,\n request: request,\n destChainId: params.dstChainId,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n sendChainGas: paramsV2.callValue != 0\n });\n emit BridgeQuoteDetails(transactionId, paramsV2.quoteId);\n }\n\n /// @inheritdoc IFastBridgeV2\n function relay(bytes memory request, address relayer) public payable {\n bytes32 transactionId = keccak256(request);\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n _validateRelayParams(transaction, transactionId, relayer);\n // mark bridge transaction as relayed\n bridgeRelayDetails[transactionId] =\n BridgeRelay({blockNumber: uint48(block.number), blockTimestamp: uint48(block.timestamp), relayer: relayer});\n\n // transfer tokens to recipient on destination chain and do an arbitrary call if requested\n address to = transaction.destRecipient;\n address token = transaction.destToken;\n uint256 amount = transaction.destAmount;\n uint256 callValue = transaction.callValue;\n\n // Emit the event before any external calls\n emit BridgeRelayed({\n transactionId: transactionId,\n relayer: relayer,\n to: to,\n originChainId: transaction.originChainId,\n originToken: transaction.originToken,\n destToken: token,\n originAmount: transaction.originAmount,\n destAmount: amount,\n chainGasAmount: callValue\n });\n\n // All state changes have been done at this point, can proceed to the external calls.\n // This follows the checks-effects-interactions pattern to mitigate potential reentrancy attacks.\n if (token == UniversalTokenLib.ETH_ADDRESS) {\n // For ETH non-zero callValue is not allowed\n if (callValue != 0) revert NativeTokenCallValueNotSupported();\n // Check that the correct msg.value was sent\n if (msg.value != amount) revert MsgValueIncorrect();\n } else {\n // For ERC20s, we check that the correct msg.value was sent\n if (msg.value != callValue) revert MsgValueIncorrect();\n // We need to transfer the tokens from the Relayer to the recipient first before performing an\n // optional post-transfer arbitrary call.\n IERC20(token).safeTransferFrom(msg.sender, to, amount);\n }\n\n if (transaction.callParams.length != 0) {\n // Arbitrary call requested, perform it while supplying full msg.value to the recipient\n // Note: if token has a fee on transfers, the recipient will have received less than `amount`.\n // This is a very niche edge case and should be handled by the recipient contract.\n _checkedCallRecipient({recipient: to, token: token, amount: amount, callParams: transaction.callParams});\n } else if (msg.value != 0) {\n // No arbitrary call requested, but msg.value was sent. This is either a relay with ETH,\n // or a non-zero callValue request with an ERC20. In both cases, transfer the ETH to the recipient.\n Address.sendValue(payable(to), msg.value);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) public onlyRole(RELAYER_ROLE) {\n // update bridge tx status given proof provided\n if (bridgeTxDetails[transactionId].status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n bridgeTxDetails[transactionId].status = BridgeStatus.RELAYER_PROVED;\n bridgeTxDetails[transactionId].proofBlockTimestamp = uint40(block.timestamp);\n bridgeTxDetails[transactionId].proofBlockNumber = uint48(block.number);\n bridgeTxDetails[transactionId].proofRelayer = relayer;\n\n emit BridgeProofProvided(transactionId, relayer, destTxHash);\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes memory request, address to) public {\n bytes32 transactionId = keccak256(request);\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n\n // update bridge tx status if able to claim origin collateral\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n\n // if \"to\" is zero addr, permissionlessly send funds to proven relayer\n if (to == address(0)) {\n to = bridgeTxDetails[transactionId].proofRelayer;\n } else if (bridgeTxDetails[transactionId].proofRelayer != msg.sender) {\n revert SenderIncorrect();\n }\n\n if (_timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003c= DISPUTE_PERIOD) {\n revert DisputePeriodNotPassed();\n }\n\n bridgeTxDetails[transactionId].status = BridgeStatus.RELAYER_CLAIMED;\n\n // update protocol fees if origin fee amount exists\n if (transaction.originFeeAmount \u003e 0) protocolFees[transaction.originToken] += transaction.originFeeAmount;\n\n // transfer origin collateral less fee to specified address\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositClaimed(transactionId, bridgeTxDetails[transactionId].proofRelayer, to, token, amount);\n }\n\n function bridgeStatuses(bytes32 transactionId) public view returns (BridgeStatus status) {\n return bridgeTxDetails[transactionId].status;\n }\n\n function bridgeProofs(bytes32 transactionId) public view returns (uint96 timestamp, address relayer) {\n timestamp = bridgeTxDetails[transactionId].proofBlockTimestamp;\n relayer = bridgeTxDetails[transactionId].proofRelayer;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeRelays(bytes32 transactionId) public view returns (bool) {\n // has this transactionId been relayed?\n return bridgeRelayDetails[transactionId].relayer != address(0);\n }\n\n /// @inheritdoc IFastBridgeV2\n function getBridgeTransactionV2(bytes memory request) public pure returns (BridgeTransactionV2 memory) {\n return abi.decode(request, (BridgeTransactionV2));\n }\n\n /// @notice Takes the bridged asset from the user into FastBridgeV2 custody. It will be later\n /// claimed by the relayer who completed the relay on destination chain, or refunded back to the user,\n /// should no one complete the relay.\n function _takeBridgedUserAsset(address token, uint256 amount) internal returns (uint256 amountTaken) {\n if (token == UniversalTokenLib.ETH_ADDRESS) {\n // For ETH we just need to check that the supplied msg.value is correct.\n // Supplied `msg.value` is already in FastBridgeV2 custody.\n if (amount != msg.value) revert MsgValueIncorrect();\n amountTaken = msg.value;\n } else {\n // For ERC20s, token is explicitly transferred from the user to FastBridgeV2.\n // We don't allow non-zero `msg.value` to avoid extra funds from being stuck in FastBridgeV2.\n token.assertIsContract();\n if (msg.value != 0) revert MsgValueIncorrect();\n amountTaken = IERC20(token).balanceOf(address(this));\n IERC20(token).safeTransferFrom(msg.sender, address(this), amount);\n // Use the balance difference as the amount taken in case of fee on transfer tokens.\n amountTaken = IERC20(token).balanceOf(address(this)) - amountTaken;\n }\n }\n\n /// @notice Calls the Recipient's hook function with the specified callParams and performs\n /// all the necessary checks for the returned value.\n function _checkedCallRecipient(\n address recipient,\n address token,\n uint256 amount,\n bytes memory callParams\n )\n internal\n {\n bytes memory hookData =\n abi.encodeCall(IFastBridgeRecipient.fastBridgeTransferReceived, (token, amount, callParams));\n // This will bubble any revert messages from the hook function\n bytes memory returnData = Address.functionCallWithValue({target: recipient, data: hookData, value: msg.value});\n // Explicit revert if no return data at all\n if (returnData.length == 0) revert RecipientNoReturnValue();\n // Check that exactly a single return value was returned\n if (returnData.length != 32) revert RecipientIncorrectReturnValue();\n // Return value should be abi-encoded hook function selector\n if (bytes32(returnData) != bytes32(IFastBridgeRecipient.fastBridgeTransferReceived.selector)) {\n revert RecipientIncorrectReturnValue();\n }\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint40(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint40).max but\n /// proof.timestamp \u003c type(uint40).max via unchecked statement\n /// @param proofBlockTimestamp The bridge proof block timestamp\n /// @return delta Time delta since proof submitted\n function _timeSince(uint40 proofBlockTimestamp) internal view returns (uint256 delta) {\n unchecked {\n delta = uint40(block.timestamp) - proofBlockTimestamp;\n }\n }\n\n /// @notice Performs all the necessary checks for a bridge to happen.\n /// @dev There's no good way to refactor this function to reduce cyclomatic complexity due to\n /// the number of checks that need to be performed, so we skip the code-complexity rule here.\n // solhint-disable-next-line code-complexity\n function _validateBridgeParams(\n BridgeParams memory params,\n BridgeParamsV2 memory paramsV2,\n int256 exclusivityEndTime\n )\n internal\n view\n {\n // Check V1 (legacy) params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.sender == address(0) || params.to == address(0)) revert ZeroAddress();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n // Check V2 params\n if (paramsV2.callParams.length \u003e MAX_CALL_PARAMS_LENGTH) revert CallParamsLengthAboveMax();\n if (paramsV2.callValue != 0 \u0026\u0026 params.destToken == UniversalTokenLib.ETH_ADDRESS) {\n revert NativeTokenCallValueNotSupported();\n }\n // exclusivityEndTime must be in range (0 .. params.deadline]\n if (exclusivityEndTime \u003c= 0 || exclusivityEndTime \u003e int256(params.deadline)) {\n revert ExclusivityParamsIncorrect();\n }\n }\n\n /// @notice Performs all the necessary checks for a relay to happen.\n function _validateRelayParams(\n BridgeTransactionV2 memory transaction,\n bytes32 transactionId,\n address relayer\n )\n internal\n view\n {\n if (relayer == address(0)) revert ZeroAddress();\n // Check if the transaction has already been relayed\n if (bridgeRelays(transactionId)) revert TransactionRelayed();\n if (transaction.destChainId != block.chainid) revert ChainIncorrect();\n // Check the deadline for relay to happen\n if (block.timestamp \u003e transaction.deadline) revert DeadlineExceeded();\n // Check the exclusivity period, if it is still ongoing\n // forgefmt: disable-next-item\n if (\n transaction.exclusivityRelayer != address(0) \u0026\u0026\n transaction.exclusivityRelayer != relayer \u0026\u0026\n block.timestamp \u003c= transaction.exclusivityEndTime\n ) {\n revert ExclusivityPeriodNotPassed();\n }\n }\n}\n","language":"Solidity","languageVersion":"0.8.24","compilerVersion":"0.8.24","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"","srcMapRuntime":"","abiDefinition":[{"inputs":[],"name":"AccessControlBadConfirmation","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"bytes32","name":"neededRole","type":"bytes32"}],"name":"AccessControlUnauthorizedAccount","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"previousAdminRole","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"newAdminRole","type":"bytes32"}],"name":"RoleAdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleRevoked","type":"event"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleAdmin","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"grantRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"hasRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"callerConfirmation","type":"address"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"revokeRole","outputs":[],"stateMutability":"nonpayable","type":"function"}],"userDoc":{"kind":"user","methods":{},"version":1},"developerDoc":{"details":"External interface of AccessControl declared to support ERC165 detection.","errors":{"AccessControlBadConfirmation()":[{"details":"The caller of a function is not the expected one. NOTE: Don't confuse with {AccessControlUnauthorizedAccount}."}],"AccessControlUnauthorizedAccount(address,bytes32)":[{"details":"The `account` is missing a role."}]},"events":{"RoleAdminChanged(bytes32,bytes32,bytes32)":{"details":"Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole` `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite {RoleAdminChanged} not being emitted signaling this."},"RoleGranted(bytes32,address,address)":{"details":"Emitted when `account` is granted `role`. `sender` is the account that originated the contract call, an admin role bearer except when using {AccessControl-_setupRole}."},"RoleRevoked(bytes32,address,address)":{"details":"Emitted when `account` is revoked `role`. `sender` is the account that originated the contract call: - if using `revokeRole`, it is the admin role bearer - if using `renounceRole`, it is the role bearer (i.e. `account`)"}},"kind":"dev","methods":{"getRoleAdmin(bytes32)":{"details":"Returns the admin role that controls `role`. See {grantRole} and {revokeRole}. To change a role's admin, use {AccessControl-_setRoleAdmin}."},"grantRole(bytes32,address)":{"details":"Grants `role` to `account`. If `account` had not been already granted `role`, emits a {RoleGranted} event. Requirements: - the caller must have ``role``'s admin role."},"hasRole(bytes32,address)":{"details":"Returns `true` if `account` has been granted `role`."},"renounceRole(bytes32,address)":{"details":"Revokes `role` from the calling account. Roles are often managed via {grantRole} and {revokeRole}: this function's purpose is to provide a mechanism for accounts to lose their privileges if they are compromised (such as when a trusted device is misplaced). If the calling account had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must be `callerConfirmation`."},"revokeRole(bytes32,address)":{"details":"Revokes `role` from `account`. If `account` had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must have ``role``'s admin role."}},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[],\"name\":\"AccessControlBadConfirmation\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"neededRole\",\"type\":\"bytes32\"}],\"name\":\"AccessControlUnauthorizedAccount\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"previousAdminRole\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"newAdminRole\",\"type\":\"bytes32\"}],\"name\":\"RoleAdminChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleGranted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleRevoked\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"}],\"name\":\"getRoleAdmin\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"grantRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"hasRole\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"callerConfirmation\",\"type\":\"address\"}],\"name\":\"renounceRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"revokeRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"details\":\"External interface of AccessControl declared to support ERC165 detection.\",\"errors\":{\"AccessControlBadConfirmation()\":[{\"details\":\"The caller of a function is not the expected one. NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\"}],\"AccessControlUnauthorizedAccount(address,bytes32)\":[{\"details\":\"The `account` is missing a role.\"}]},\"events\":{\"RoleAdminChanged(bytes32,bytes32,bytes32)\":{\"details\":\"Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole` `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite {RoleAdminChanged} not being emitted signaling this.\"},\"RoleGranted(bytes32,address,address)\":{\"details\":\"Emitted when `account` is granted `role`. `sender` is the account that originated the contract call, an admin role bearer except when using {AccessControl-_setupRole}.\"},\"RoleRevoked(bytes32,address,address)\":{\"details\":\"Emitted when `account` is revoked `role`. `sender` is the account that originated the contract call: - if using `revokeRole`, it is the admin role bearer - if using `renounceRole`, it is the role bearer (i.e. `account`)\"}},\"kind\":\"dev\",\"methods\":{\"getRoleAdmin(bytes32)\":{\"details\":\"Returns the admin role that controls `role`. See {grantRole} and {revokeRole}. To change a role's admin, use {AccessControl-_setRoleAdmin}.\"},\"grantRole(bytes32,address)\":{\"details\":\"Grants `role` to `account`. If `account` had not been already granted `role`, emits a {RoleGranted} event. Requirements: - the caller must have ``role``'s admin role.\"},\"hasRole(bytes32,address)\":{\"details\":\"Returns `true` if `account` has been granted `role`.\"},\"renounceRole(bytes32,address)\":{\"details\":\"Revokes `role` from the calling account. Roles are often managed via {grantRole} and {revokeRole}: this function's purpose is to provide a mechanism for accounts to lose their privileges if they are compromised (such as when a trusted device is misplaced). If the calling account had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must be `callerConfirmation`.\"},\"revokeRole(bytes32,address)\":{\"details\":\"Revokes `role` from `account`. If `account` had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must have ``role``'s admin role.\"}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeV2.sol\":\"IAccessControl\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeV2.sol\":{\"keccak256\":\"0xfd916c030b1ffca5a136817827b8018c8ba42ca089905747f3de6148b73eb35e\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://18e6438c4096deb8ae453fb3365ba2b07d52944e93c08288fc5d012b71bf6bb3\",\"dweb:/ipfs/QmfEMqpT1zz6RRm7UuHLRowe1tds2cTGLrVonfm9XSCACj\"]}},\"version\":1}"},"hashes":{"getRoleAdmin(bytes32)":"248a9ca3","grantRole(bytes32,address)":"2f2ff15d","hasRole(bytes32,address)":"91d14854","renounceRole(bytes32,address)":"36568abe","revokeRole(bytes32,address)":"d547741f"}},"solidity/FastBridgeV2.sol:IAccessControlEnumerable":{"code":"0x","runtime-code":"0x","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.24 ^0.8.0 ^0.8.20;\n\n// contracts/interfaces/IAdmin.sol\n\ninterface IAdmin {\n // ============ Events ============\n\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n event ChainGasAmountUpdated(uint256 oldChainGasAmount, uint256 newChainGasAmount);\n\n // ============ Methods ============\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n\n function setChainGasAmount(uint256 newChainGasAmount) external;\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IFastBridgeRecipient.sol\n\ninterface IFastBridgeRecipient {\n function fastBridgeTransferReceived(\n address token,\n uint256 amount,\n bytes memory callParams\n )\n external\n payable\n returns (bytes4);\n}\n\n// contracts/interfaces/IFastBridgeV2Errors.sol\n\ninterface IFastBridgeV2Errors {\n error AmountIncorrect();\n error CallParamsLengthAboveMax();\n error ChainIncorrect();\n error ExclusivityParamsIncorrect();\n error MsgValueIncorrect();\n error NativeTokenCallValueNotSupported();\n error SenderIncorrect();\n error StatusIncorrect();\n error ZeroAddress();\n\n error RecipientIncorrectReturnValue();\n error RecipientNoReturnValue();\n\n error DeadlineExceeded();\n error DeadlineNotExceeded();\n error DeadlineTooShort();\n error DisputePeriodNotPassed();\n error DisputePeriodPassed();\n error ExclusivityPeriodNotPassed();\n\n error TransactionRelayed();\n}\n\n// contracts/libs/Errors.sol\n\nerror DeadlineExceeded();\nerror DeadlineNotExceeded();\nerror DeadlineTooShort();\nerror InsufficientOutputAmount();\n\nerror MsgValueIncorrect();\nerror PoolNotFound();\nerror TokenAddressMismatch();\nerror TokenNotContract();\nerror TokenNotETH();\nerror TokensIdentical();\n\nerror ChainIncorrect();\nerror AmountIncorrect();\nerror ZeroAddress();\n\nerror DisputePeriodNotPassed();\nerror DisputePeriodPassed();\nerror SenderIncorrect();\nerror StatusIncorrect();\nerror TransactionIdIncorrect();\nerror TransactionRelayed();\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// contracts/interfaces/IFastBridgeV2.sol\n\ninterface IFastBridgeV2 is IFastBridge {\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n struct BridgeTxDetails {\n BridgeStatus status;\n uint40 proofBlockTimestamp;\n uint48 proofBlockNumber;\n address proofRelayer;\n }\n\n struct BridgeRelay {\n uint48 blockNumber;\n uint48 blockTimestamp;\n address relayer;\n }\n\n /// @notice New params introduced in the FastBridgeV2.\n /// We are passing fields from the older BridgeParams struct outside of this struct\n /// for backwards compatibility.\n /// Note: quoteRelayer and quoteExclusivitySeconds are either both zero (indicating no exclusivity)\n /// or both non-zero (indicating exclusivity for the given period).\n /// Note: callValue \u003e 0 can NOT be used with destToken = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE (ETH_ADDRESS)\n /// @param quoteRelayer Relayer that provided the quote for the transaction\n /// @param quoteExclusivitySeconds Period of time the quote relayer is guaranteed exclusivity after user's deposit\n /// @param quoteId Unique quote identifier used for tracking the quote\n /// @param callValue ETH value to send to the recipient (if any)\n /// @param callParams Parameters for the arbitrary call to the destination recipient (if any)\n struct BridgeParamsV2 {\n address quoteRelayer;\n int256 quoteExclusivitySeconds;\n bytes quoteId;\n uint256 callValue;\n bytes callParams;\n }\n\n /// @notice Updated bridge transaction struct to include parameters introduced in FastBridgeV2.\n /// Note: only `exclusivityRelayer` can fill such a transaction until `exclusivityEndTime`.\n /// TODO: consider changing the encoding scheme to prevent spending extra gas on decoding.\n struct BridgeTransactionV2 {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n uint256 callValue; // ETH value to send to the recipient (if any) - replaces V1's sendChainGas flag\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n address exclusivityRelayer;\n uint256 exclusivityEndTime;\n bytes callParams;\n }\n\n event BridgeQuoteDetails(bytes32 indexed transactionId, bytes quoteId);\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability\n /// to provide temporary exclusivity fill rights for the quote relayer.\n /// @param params The parameters required to bridge\n /// @param paramsV2 The parameters for exclusivity fill rights (optional, can be left empty)\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function relay(bytes memory request, address relayer) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param transactionId The transaction id associated with the encoded bridge transaction to prove\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital.\n /// @notice Can only send funds to the relayer address on the proof.\n /// @param request The encoded bridge transaction to claim on origin chain\n function claim(bytes memory request) external;\n /// @notice Checks if a transaction has been relayed\n /// @param transactionId The ID of the transaction to check\n /// @return True if the transaction has been relayed, false otherwise\n function bridgeRelays(bytes32 transactionId) external view returns (bool);\n\n /// @notice Returns the status of a bridge transaction\n /// @param transactionId The ID of the bridge transaction\n /// @return BridgeStatus Status of the bridge transaction\n function bridgeStatuses(bytes32 transactionId) external view returns (BridgeStatus);\n\n /// @notice Returns the timestamp and relayer of a bridge proof\n /// @param transactionId The ID of the bridge transaction\n /// @return timestamp The timestamp of the bridge proof\n /// @return relayer The relayer address of the bridge proof\n function bridgeProofs(bytes32 transactionId) external view returns (uint96 timestamp, address relayer);\n\n /// @notice Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\n /// @param request The bridge request to decode\n function getBridgeTransactionV2(bytes memory request) external view returns (BridgeTransactionV2 memory);\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// contracts/libs/UniversalToken.sol\n\nlibrary UniversalTokenLib {\n using SafeERC20 for IERC20;\n\n address internal constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Transfers tokens to the given account. Reverts if transfer is not successful.\n /// @dev This might trigger fallback, if ETH is transferred to the contract.\n /// Make sure this can not lead to reentrancy attacks.\n function universalTransfer(address token, address to, uint256 value) internal {\n // Don't do anything, if need to send tokens to this address\n if (to == address(this)) return;\n // Don't do anything, if trying to send zero value\n if (value == 0) return;\n if (token == ETH_ADDRESS) {\n /// @dev Note: this can potentially lead to executing code in `to`.\n // solhint-disable-next-line avoid-low-level-calls\n (bool success,) = to.call{value: value}(\"\");\n require(success, \"ETH transfer failed\");\n } else {\n IERC20(token).safeTransfer(to, value);\n }\n }\n\n /// @notice Issues an infinite allowance to the spender, if the current allowance is insufficient\n /// to spend the given amount.\n function universalApproveInfinity(address token, address spender, uint256 amountToSpend) internal {\n // ETH Chad doesn't require your approval\n if (token == ETH_ADDRESS) return;\n // No-op if allowance is already sufficient\n uint256 allowance = IERC20(token).allowance(address(this), spender);\n if (allowance \u003e= amountToSpend) return;\n // Otherwise, reset approval to 0 and set to max allowance\n if (allowance \u003e 0) IERC20(token).safeDecreaseAllowance(spender, allowance);\n IERC20(token).safeIncreaseAllowance(spender, type(uint256).max);\n }\n\n /// @notice Returns the balance of the given token (or native ETH) for the given account.\n function universalBalanceOf(address token, address account) internal view returns (uint256) {\n if (token == ETH_ADDRESS) {\n return account.balance;\n } else {\n return IERC20(token).balanceOf(account);\n }\n }\n\n /// @dev Checks that token is a contract and not ETH_ADDRESS.\n function assertIsContract(address token) internal view {\n // Check that ETH_ADDRESS was not used (in case this is a predeploy on any of the chains)\n if (token == UniversalTokenLib.ETH_ADDRESS) revert TokenNotContract();\n // Check that token is not an EOA\n if (token.code.length == 0) revert TokenNotContract();\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/Admin.sol\n\ncontract Admin is IAdmin, AccessControlEnumerable {\n using UniversalTokenLib for address;\n\n bytes32 public constant RELAYER_ROLE = keccak256(\"RELAYER_ROLE\");\n bytes32 public constant REFUNDER_ROLE = keccak256(\"REFUNDER_ROLE\");\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n uint256 public constant FEE_BPS = 1e6;\n uint256 public constant FEE_RATE_MAX = 0.01e6; // max 1% on origin amount\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Chain gas amount to forward as rebate if requested\n uint256 public chainGasAmount;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n }\n\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n require(newFeeRate \u003c= FEE_RATE_MAX, \"newFeeRate \u003e max\");\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n token.universalTransfer(recipient, feeAmount);\n emit FeesSwept(token, recipient, feeAmount);\n }\n\n function setChainGasAmount(uint256 newChainGasAmount) external onlyRole(GOVERNOR_ROLE) {\n uint256 oldChainGasAmount = chainGasAmount;\n chainGasAmount = newChainGasAmount;\n emit ChainGasAmountUpdated(oldChainGasAmount, newChainGasAmount);\n }\n}\n\n// contracts/FastBridgeV2.sol\n\n/// @notice FastBridgeV2 is a contract for bridging tokens across chains.\ncontract FastBridgeV2 is Admin, IFastBridgeV2, IFastBridgeV2Errors {\n using SafeERC20 for IERC20;\n using UniversalTokenLib for address;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Delay for a transaction after which it could be permisionlessly refunded\n uint256 public constant REFUND_DELAY = 7 days;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n /// @notice Maximum length of accepted callParams\n uint256 public constant MAX_CALL_PARAMS_LENGTH = 2 ** 16 - 1;\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeTxDetails) public bridgeTxDetails;\n /// @notice Relay details on destination chain\n mapping(bytes32 =\u003e BridgeRelay) public bridgeRelayDetails;\n /// @notice Unique bridge nonces tracked per originSender\n mapping(address =\u003e uint256) public senderNonces;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Replaced by senderNonces\n uint256 public immutable nonce = 0;\n /// @notice the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n bridge({\n params: params,\n paramsV2: BridgeParamsV2({\n quoteRelayer: address(0),\n quoteExclusivitySeconds: 0,\n quoteId: bytes(\"\"),\n callValue: 0,\n callParams: bytes(\"\")\n })\n });\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes memory request) external payable {\n relay({request: request, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes memory request, bytes32 destTxHash) external {\n prove({transactionId: keccak256(request), destTxHash: destTxHash, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridgeV2\n function claim(bytes memory request) external {\n claim({request: request, to: address(0)});\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003e DISPUTE_PERIOD) {\n revert DisputePeriodPassed();\n }\n\n // @dev relayer gets slashed effectively if dest relay has gone thru\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n bridgeTxDetails[transactionId].proofRelayer = address(0);\n bridgeTxDetails[transactionId].proofBlockTimestamp = 0;\n bridgeTxDetails[transactionId].proofBlockNumber = 0;\n\n emit BridgeProofDisputed(transactionId, msg.sender);\n }\n\n /// @inheritdoc IFastBridge\n function refund(bytes memory request) external {\n bytes32 transactionId = keccak256(request);\n\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n\n if (bridgeTxDetails[transactionId].status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n\n if (hasRole(REFUNDER_ROLE, msg.sender)) {\n // Refunder can refund if deadline has passed\n if (block.timestamp \u003c= transaction.deadline) revert DeadlineNotExceeded();\n } else {\n // Permissionless refund is allowed after REFUND_DELAY\n if (block.timestamp \u003c= transaction.deadline + REFUND_DELAY) revert DeadlineNotExceeded();\n }\n\n // if all checks passed, set to REFUNDED status\n bridgeTxDetails[transactionId].status = BridgeStatus.REFUNDED;\n\n // transfer origin collateral back to original sender\n address to = transaction.originSender;\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount + transaction.originFeeAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (bridgeTxDetails[transactionId].proofRelayer != relayer) revert SenderIncorrect();\n return _timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n /// @dev This method is added to achieve backwards compatibility with decoding requests into V1 structs:\n /// - `callValue` is partially reported as a zero/non-zero flag\n /// - `callParams` is ignored\n /// In order to process all kinds of requests use getBridgeTransactionV2 instead.\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory) {\n // Try decoding into V2 struct first. This will revert if V1 struct is passed\n try this.getBridgeTransactionV2(request) returns (BridgeTransactionV2 memory txV2) {\n // Note: we entirely ignore the callParams field, as it was not present in V1\n return BridgeTransaction({\n originChainId: txV2.originChainId,\n destChainId: txV2.destChainId,\n originSender: txV2.originSender,\n destRecipient: txV2.destRecipient,\n originToken: txV2.originToken,\n destToken: txV2.destToken,\n originAmount: txV2.originAmount,\n destAmount: txV2.destAmount,\n originFeeAmount: txV2.originFeeAmount,\n sendChainGas: txV2.callValue != 0,\n deadline: txV2.deadline,\n nonce: txV2.nonce\n });\n } catch {\n // Fallback to V1 struct\n return abi.decode(request, (BridgeTransaction));\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) public payable {\n int256 exclusivityEndTime = int256(block.timestamp) + paramsV2.quoteExclusivitySeconds;\n _validateBridgeParams(params, paramsV2, exclusivityEndTime);\n\n // transfer tokens to bridge contract\n /// @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _takeBridgedUserAsset(params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n\n // set status to requested\n bytes memory request = abi.encode(\n BridgeTransactionV2({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n callValue: paramsV2.callValue,\n deadline: params.deadline,\n nonce: senderNonces[params.sender]++, // increment nonce on every bridge\n exclusivityRelayer: paramsV2.quoteRelayer,\n // We checked exclusivityEndTime to be in range (0 .. params.deadline] above, so can safely cast\n exclusivityEndTime: uint256(exclusivityEndTime),\n callParams: paramsV2.callParams\n })\n );\n bytes32 transactionId = keccak256(request);\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n\n emit BridgeRequested({\n transactionId: transactionId,\n sender: params.sender,\n request: request,\n destChainId: params.dstChainId,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n sendChainGas: paramsV2.callValue != 0\n });\n emit BridgeQuoteDetails(transactionId, paramsV2.quoteId);\n }\n\n /// @inheritdoc IFastBridgeV2\n function relay(bytes memory request, address relayer) public payable {\n bytes32 transactionId = keccak256(request);\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n _validateRelayParams(transaction, transactionId, relayer);\n // mark bridge transaction as relayed\n bridgeRelayDetails[transactionId] =\n BridgeRelay({blockNumber: uint48(block.number), blockTimestamp: uint48(block.timestamp), relayer: relayer});\n\n // transfer tokens to recipient on destination chain and do an arbitrary call if requested\n address to = transaction.destRecipient;\n address token = transaction.destToken;\n uint256 amount = transaction.destAmount;\n uint256 callValue = transaction.callValue;\n\n // Emit the event before any external calls\n emit BridgeRelayed({\n transactionId: transactionId,\n relayer: relayer,\n to: to,\n originChainId: transaction.originChainId,\n originToken: transaction.originToken,\n destToken: token,\n originAmount: transaction.originAmount,\n destAmount: amount,\n chainGasAmount: callValue\n });\n\n // All state changes have been done at this point, can proceed to the external calls.\n // This follows the checks-effects-interactions pattern to mitigate potential reentrancy attacks.\n if (token == UniversalTokenLib.ETH_ADDRESS) {\n // For ETH non-zero callValue is not allowed\n if (callValue != 0) revert NativeTokenCallValueNotSupported();\n // Check that the correct msg.value was sent\n if (msg.value != amount) revert MsgValueIncorrect();\n } else {\n // For ERC20s, we check that the correct msg.value was sent\n if (msg.value != callValue) revert MsgValueIncorrect();\n // We need to transfer the tokens from the Relayer to the recipient first before performing an\n // optional post-transfer arbitrary call.\n IERC20(token).safeTransferFrom(msg.sender, to, amount);\n }\n\n if (transaction.callParams.length != 0) {\n // Arbitrary call requested, perform it while supplying full msg.value to the recipient\n // Note: if token has a fee on transfers, the recipient will have received less than `amount`.\n // This is a very niche edge case and should be handled by the recipient contract.\n _checkedCallRecipient({recipient: to, token: token, amount: amount, callParams: transaction.callParams});\n } else if (msg.value != 0) {\n // No arbitrary call requested, but msg.value was sent. This is either a relay with ETH,\n // or a non-zero callValue request with an ERC20. In both cases, transfer the ETH to the recipient.\n Address.sendValue(payable(to), msg.value);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) public onlyRole(RELAYER_ROLE) {\n // update bridge tx status given proof provided\n if (bridgeTxDetails[transactionId].status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n bridgeTxDetails[transactionId].status = BridgeStatus.RELAYER_PROVED;\n bridgeTxDetails[transactionId].proofBlockTimestamp = uint40(block.timestamp);\n bridgeTxDetails[transactionId].proofBlockNumber = uint48(block.number);\n bridgeTxDetails[transactionId].proofRelayer = relayer;\n\n emit BridgeProofProvided(transactionId, relayer, destTxHash);\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes memory request, address to) public {\n bytes32 transactionId = keccak256(request);\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n\n // update bridge tx status if able to claim origin collateral\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n\n // if \"to\" is zero addr, permissionlessly send funds to proven relayer\n if (to == address(0)) {\n to = bridgeTxDetails[transactionId].proofRelayer;\n } else if (bridgeTxDetails[transactionId].proofRelayer != msg.sender) {\n revert SenderIncorrect();\n }\n\n if (_timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003c= DISPUTE_PERIOD) {\n revert DisputePeriodNotPassed();\n }\n\n bridgeTxDetails[transactionId].status = BridgeStatus.RELAYER_CLAIMED;\n\n // update protocol fees if origin fee amount exists\n if (transaction.originFeeAmount \u003e 0) protocolFees[transaction.originToken] += transaction.originFeeAmount;\n\n // transfer origin collateral less fee to specified address\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositClaimed(transactionId, bridgeTxDetails[transactionId].proofRelayer, to, token, amount);\n }\n\n function bridgeStatuses(bytes32 transactionId) public view returns (BridgeStatus status) {\n return bridgeTxDetails[transactionId].status;\n }\n\n function bridgeProofs(bytes32 transactionId) public view returns (uint96 timestamp, address relayer) {\n timestamp = bridgeTxDetails[transactionId].proofBlockTimestamp;\n relayer = bridgeTxDetails[transactionId].proofRelayer;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeRelays(bytes32 transactionId) public view returns (bool) {\n // has this transactionId been relayed?\n return bridgeRelayDetails[transactionId].relayer != address(0);\n }\n\n /// @inheritdoc IFastBridgeV2\n function getBridgeTransactionV2(bytes memory request) public pure returns (BridgeTransactionV2 memory) {\n return abi.decode(request, (BridgeTransactionV2));\n }\n\n /// @notice Takes the bridged asset from the user into FastBridgeV2 custody. It will be later\n /// claimed by the relayer who completed the relay on destination chain, or refunded back to the user,\n /// should no one complete the relay.\n function _takeBridgedUserAsset(address token, uint256 amount) internal returns (uint256 amountTaken) {\n if (token == UniversalTokenLib.ETH_ADDRESS) {\n // For ETH we just need to check that the supplied msg.value is correct.\n // Supplied `msg.value` is already in FastBridgeV2 custody.\n if (amount != msg.value) revert MsgValueIncorrect();\n amountTaken = msg.value;\n } else {\n // For ERC20s, token is explicitly transferred from the user to FastBridgeV2.\n // We don't allow non-zero `msg.value` to avoid extra funds from being stuck in FastBridgeV2.\n token.assertIsContract();\n if (msg.value != 0) revert MsgValueIncorrect();\n amountTaken = IERC20(token).balanceOf(address(this));\n IERC20(token).safeTransferFrom(msg.sender, address(this), amount);\n // Use the balance difference as the amount taken in case of fee on transfer tokens.\n amountTaken = IERC20(token).balanceOf(address(this)) - amountTaken;\n }\n }\n\n /// @notice Calls the Recipient's hook function with the specified callParams and performs\n /// all the necessary checks for the returned value.\n function _checkedCallRecipient(\n address recipient,\n address token,\n uint256 amount,\n bytes memory callParams\n )\n internal\n {\n bytes memory hookData =\n abi.encodeCall(IFastBridgeRecipient.fastBridgeTransferReceived, (token, amount, callParams));\n // This will bubble any revert messages from the hook function\n bytes memory returnData = Address.functionCallWithValue({target: recipient, data: hookData, value: msg.value});\n // Explicit revert if no return data at all\n if (returnData.length == 0) revert RecipientNoReturnValue();\n // Check that exactly a single return value was returned\n if (returnData.length != 32) revert RecipientIncorrectReturnValue();\n // Return value should be abi-encoded hook function selector\n if (bytes32(returnData) != bytes32(IFastBridgeRecipient.fastBridgeTransferReceived.selector)) {\n revert RecipientIncorrectReturnValue();\n }\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint40(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint40).max but\n /// proof.timestamp \u003c type(uint40).max via unchecked statement\n /// @param proofBlockTimestamp The bridge proof block timestamp\n /// @return delta Time delta since proof submitted\n function _timeSince(uint40 proofBlockTimestamp) internal view returns (uint256 delta) {\n unchecked {\n delta = uint40(block.timestamp) - proofBlockTimestamp;\n }\n }\n\n /// @notice Performs all the necessary checks for a bridge to happen.\n /// @dev There's no good way to refactor this function to reduce cyclomatic complexity due to\n /// the number of checks that need to be performed, so we skip the code-complexity rule here.\n // solhint-disable-next-line code-complexity\n function _validateBridgeParams(\n BridgeParams memory params,\n BridgeParamsV2 memory paramsV2,\n int256 exclusivityEndTime\n )\n internal\n view\n {\n // Check V1 (legacy) params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.sender == address(0) || params.to == address(0)) revert ZeroAddress();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n // Check V2 params\n if (paramsV2.callParams.length \u003e MAX_CALL_PARAMS_LENGTH) revert CallParamsLengthAboveMax();\n if (paramsV2.callValue != 0 \u0026\u0026 params.destToken == UniversalTokenLib.ETH_ADDRESS) {\n revert NativeTokenCallValueNotSupported();\n }\n // exclusivityEndTime must be in range (0 .. params.deadline]\n if (exclusivityEndTime \u003c= 0 || exclusivityEndTime \u003e int256(params.deadline)) {\n revert ExclusivityParamsIncorrect();\n }\n }\n\n /// @notice Performs all the necessary checks for a relay to happen.\n function _validateRelayParams(\n BridgeTransactionV2 memory transaction,\n bytes32 transactionId,\n address relayer\n )\n internal\n view\n {\n if (relayer == address(0)) revert ZeroAddress();\n // Check if the transaction has already been relayed\n if (bridgeRelays(transactionId)) revert TransactionRelayed();\n if (transaction.destChainId != block.chainid) revert ChainIncorrect();\n // Check the deadline for relay to happen\n if (block.timestamp \u003e transaction.deadline) revert DeadlineExceeded();\n // Check the exclusivity period, if it is still ongoing\n // forgefmt: disable-next-item\n if (\n transaction.exclusivityRelayer != address(0) \u0026\u0026\n transaction.exclusivityRelayer != relayer \u0026\u0026\n block.timestamp \u003c= transaction.exclusivityEndTime\n ) {\n revert ExclusivityPeriodNotPassed();\n }\n }\n}\n","language":"Solidity","languageVersion":"0.8.24","compilerVersion":"0.8.24","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"","srcMapRuntime":"","abiDefinition":[{"inputs":[],"name":"AccessControlBadConfirmation","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"bytes32","name":"neededRole","type":"bytes32"}],"name":"AccessControlUnauthorizedAccount","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"previousAdminRole","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"newAdminRole","type":"bytes32"}],"name":"RoleAdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleRevoked","type":"event"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleAdmin","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"uint256","name":"index","type":"uint256"}],"name":"getRoleMember","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleMemberCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"grantRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"hasRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"callerConfirmation","type":"address"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"revokeRole","outputs":[],"stateMutability":"nonpayable","type":"function"}],"userDoc":{"kind":"user","methods":{},"version":1},"developerDoc":{"details":"External interface of AccessControlEnumerable declared to support ERC165 detection.","errors":{"AccessControlBadConfirmation()":[{"details":"The caller of a function is not the expected one. NOTE: Don't confuse with {AccessControlUnauthorizedAccount}."}],"AccessControlUnauthorizedAccount(address,bytes32)":[{"details":"The `account` is missing a role."}]},"events":{"RoleAdminChanged(bytes32,bytes32,bytes32)":{"details":"Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole` `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite {RoleAdminChanged} not being emitted signaling this."},"RoleGranted(bytes32,address,address)":{"details":"Emitted when `account` is granted `role`. `sender` is the account that originated the contract call, an admin role bearer except when using {AccessControl-_setupRole}."},"RoleRevoked(bytes32,address,address)":{"details":"Emitted when `account` is revoked `role`. `sender` is the account that originated the contract call: - if using `revokeRole`, it is the admin role bearer - if using `renounceRole`, it is the role bearer (i.e. `account`)"}},"kind":"dev","methods":{"getRoleAdmin(bytes32)":{"details":"Returns the admin role that controls `role`. See {grantRole} and {revokeRole}. To change a role's admin, use {AccessControl-_setRoleAdmin}."},"getRoleMember(bytes32,uint256)":{"details":"Returns one of the accounts that have `role`. `index` must be a value between 0 and {getRoleMemberCount}, non-inclusive. Role bearers are not sorted in any particular way, and their ordering may change at any point. WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure you perform all queries on the same block. See the following https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post] for more information."},"getRoleMemberCount(bytes32)":{"details":"Returns the number of accounts that have `role`. Can be used together with {getRoleMember} to enumerate all bearers of a role."},"grantRole(bytes32,address)":{"details":"Grants `role` to `account`. If `account` had not been already granted `role`, emits a {RoleGranted} event. Requirements: - the caller must have ``role``'s admin role."},"hasRole(bytes32,address)":{"details":"Returns `true` if `account` has been granted `role`."},"renounceRole(bytes32,address)":{"details":"Revokes `role` from the calling account. Roles are often managed via {grantRole} and {revokeRole}: this function's purpose is to provide a mechanism for accounts to lose their privileges if they are compromised (such as when a trusted device is misplaced). If the calling account had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must be `callerConfirmation`."},"revokeRole(bytes32,address)":{"details":"Revokes `role` from `account`. If `account` had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must have ``role``'s admin role."}},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[],\"name\":\"AccessControlBadConfirmation\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"neededRole\",\"type\":\"bytes32\"}],\"name\":\"AccessControlUnauthorizedAccount\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"previousAdminRole\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"newAdminRole\",\"type\":\"bytes32\"}],\"name\":\"RoleAdminChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleGranted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleRevoked\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"}],\"name\":\"getRoleAdmin\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"index\",\"type\":\"uint256\"}],\"name\":\"getRoleMember\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"}],\"name\":\"getRoleMemberCount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"grantRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"hasRole\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"callerConfirmation\",\"type\":\"address\"}],\"name\":\"renounceRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"revokeRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"details\":\"External interface of AccessControlEnumerable declared to support ERC165 detection.\",\"errors\":{\"AccessControlBadConfirmation()\":[{\"details\":\"The caller of a function is not the expected one. NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\"}],\"AccessControlUnauthorizedAccount(address,bytes32)\":[{\"details\":\"The `account` is missing a role.\"}]},\"events\":{\"RoleAdminChanged(bytes32,bytes32,bytes32)\":{\"details\":\"Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole` `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite {RoleAdminChanged} not being emitted signaling this.\"},\"RoleGranted(bytes32,address,address)\":{\"details\":\"Emitted when `account` is granted `role`. `sender` is the account that originated the contract call, an admin role bearer except when using {AccessControl-_setupRole}.\"},\"RoleRevoked(bytes32,address,address)\":{\"details\":\"Emitted when `account` is revoked `role`. `sender` is the account that originated the contract call: - if using `revokeRole`, it is the admin role bearer - if using `renounceRole`, it is the role bearer (i.e. `account`)\"}},\"kind\":\"dev\",\"methods\":{\"getRoleAdmin(bytes32)\":{\"details\":\"Returns the admin role that controls `role`. See {grantRole} and {revokeRole}. To change a role's admin, use {AccessControl-_setRoleAdmin}.\"},\"getRoleMember(bytes32,uint256)\":{\"details\":\"Returns one of the accounts that have `role`. `index` must be a value between 0 and {getRoleMemberCount}, non-inclusive. Role bearers are not sorted in any particular way, and their ordering may change at any point. WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure you perform all queries on the same block. See the following https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post] for more information.\"},\"getRoleMemberCount(bytes32)\":{\"details\":\"Returns the number of accounts that have `role`. Can be used together with {getRoleMember} to enumerate all bearers of a role.\"},\"grantRole(bytes32,address)\":{\"details\":\"Grants `role` to `account`. If `account` had not been already granted `role`, emits a {RoleGranted} event. Requirements: - the caller must have ``role``'s admin role.\"},\"hasRole(bytes32,address)\":{\"details\":\"Returns `true` if `account` has been granted `role`.\"},\"renounceRole(bytes32,address)\":{\"details\":\"Revokes `role` from the calling account. Roles are often managed via {grantRole} and {revokeRole}: this function's purpose is to provide a mechanism for accounts to lose their privileges if they are compromised (such as when a trusted device is misplaced). If the calling account had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must be `callerConfirmation`.\"},\"revokeRole(bytes32,address)\":{\"details\":\"Revokes `role` from `account`. If `account` had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must have ``role``'s admin role.\"}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeV2.sol\":\"IAccessControlEnumerable\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeV2.sol\":{\"keccak256\":\"0xfd916c030b1ffca5a136817827b8018c8ba42ca089905747f3de6148b73eb35e\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://18e6438c4096deb8ae453fb3365ba2b07d52944e93c08288fc5d012b71bf6bb3\",\"dweb:/ipfs/QmfEMqpT1zz6RRm7UuHLRowe1tds2cTGLrVonfm9XSCACj\"]}},\"version\":1}"},"hashes":{"getRoleAdmin(bytes32)":"248a9ca3","getRoleMember(bytes32,uint256)":"9010d07c","getRoleMemberCount(bytes32)":"ca15c873","grantRole(bytes32,address)":"2f2ff15d","hasRole(bytes32,address)":"91d14854","renounceRole(bytes32,address)":"36568abe","revokeRole(bytes32,address)":"d547741f"}},"solidity/FastBridgeV2.sol:IAdmin":{"code":"0x","runtime-code":"0x","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.24 ^0.8.0 ^0.8.20;\n\n// contracts/interfaces/IAdmin.sol\n\ninterface IAdmin {\n // ============ Events ============\n\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n event ChainGasAmountUpdated(uint256 oldChainGasAmount, uint256 newChainGasAmount);\n\n // ============ Methods ============\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n\n function setChainGasAmount(uint256 newChainGasAmount) external;\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IFastBridgeRecipient.sol\n\ninterface IFastBridgeRecipient {\n function fastBridgeTransferReceived(\n address token,\n uint256 amount,\n bytes memory callParams\n )\n external\n payable\n returns (bytes4);\n}\n\n// contracts/interfaces/IFastBridgeV2Errors.sol\n\ninterface IFastBridgeV2Errors {\n error AmountIncorrect();\n error CallParamsLengthAboveMax();\n error ChainIncorrect();\n error ExclusivityParamsIncorrect();\n error MsgValueIncorrect();\n error NativeTokenCallValueNotSupported();\n error SenderIncorrect();\n error StatusIncorrect();\n error ZeroAddress();\n\n error RecipientIncorrectReturnValue();\n error RecipientNoReturnValue();\n\n error DeadlineExceeded();\n error DeadlineNotExceeded();\n error DeadlineTooShort();\n error DisputePeriodNotPassed();\n error DisputePeriodPassed();\n error ExclusivityPeriodNotPassed();\n\n error TransactionRelayed();\n}\n\n// contracts/libs/Errors.sol\n\nerror DeadlineExceeded();\nerror DeadlineNotExceeded();\nerror DeadlineTooShort();\nerror InsufficientOutputAmount();\n\nerror MsgValueIncorrect();\nerror PoolNotFound();\nerror TokenAddressMismatch();\nerror TokenNotContract();\nerror TokenNotETH();\nerror TokensIdentical();\n\nerror ChainIncorrect();\nerror AmountIncorrect();\nerror ZeroAddress();\n\nerror DisputePeriodNotPassed();\nerror DisputePeriodPassed();\nerror SenderIncorrect();\nerror StatusIncorrect();\nerror TransactionIdIncorrect();\nerror TransactionRelayed();\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// contracts/interfaces/IFastBridgeV2.sol\n\ninterface IFastBridgeV2 is IFastBridge {\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n struct BridgeTxDetails {\n BridgeStatus status;\n uint40 proofBlockTimestamp;\n uint48 proofBlockNumber;\n address proofRelayer;\n }\n\n struct BridgeRelay {\n uint48 blockNumber;\n uint48 blockTimestamp;\n address relayer;\n }\n\n /// @notice New params introduced in the FastBridgeV2.\n /// We are passing fields from the older BridgeParams struct outside of this struct\n /// for backwards compatibility.\n /// Note: quoteRelayer and quoteExclusivitySeconds are either both zero (indicating no exclusivity)\n /// or both non-zero (indicating exclusivity for the given period).\n /// Note: callValue \u003e 0 can NOT be used with destToken = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE (ETH_ADDRESS)\n /// @param quoteRelayer Relayer that provided the quote for the transaction\n /// @param quoteExclusivitySeconds Period of time the quote relayer is guaranteed exclusivity after user's deposit\n /// @param quoteId Unique quote identifier used for tracking the quote\n /// @param callValue ETH value to send to the recipient (if any)\n /// @param callParams Parameters for the arbitrary call to the destination recipient (if any)\n struct BridgeParamsV2 {\n address quoteRelayer;\n int256 quoteExclusivitySeconds;\n bytes quoteId;\n uint256 callValue;\n bytes callParams;\n }\n\n /// @notice Updated bridge transaction struct to include parameters introduced in FastBridgeV2.\n /// Note: only `exclusivityRelayer` can fill such a transaction until `exclusivityEndTime`.\n /// TODO: consider changing the encoding scheme to prevent spending extra gas on decoding.\n struct BridgeTransactionV2 {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n uint256 callValue; // ETH value to send to the recipient (if any) - replaces V1's sendChainGas flag\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n address exclusivityRelayer;\n uint256 exclusivityEndTime;\n bytes callParams;\n }\n\n event BridgeQuoteDetails(bytes32 indexed transactionId, bytes quoteId);\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability\n /// to provide temporary exclusivity fill rights for the quote relayer.\n /// @param params The parameters required to bridge\n /// @param paramsV2 The parameters for exclusivity fill rights (optional, can be left empty)\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function relay(bytes memory request, address relayer) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param transactionId The transaction id associated with the encoded bridge transaction to prove\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital.\n /// @notice Can only send funds to the relayer address on the proof.\n /// @param request The encoded bridge transaction to claim on origin chain\n function claim(bytes memory request) external;\n /// @notice Checks if a transaction has been relayed\n /// @param transactionId The ID of the transaction to check\n /// @return True if the transaction has been relayed, false otherwise\n function bridgeRelays(bytes32 transactionId) external view returns (bool);\n\n /// @notice Returns the status of a bridge transaction\n /// @param transactionId The ID of the bridge transaction\n /// @return BridgeStatus Status of the bridge transaction\n function bridgeStatuses(bytes32 transactionId) external view returns (BridgeStatus);\n\n /// @notice Returns the timestamp and relayer of a bridge proof\n /// @param transactionId The ID of the bridge transaction\n /// @return timestamp The timestamp of the bridge proof\n /// @return relayer The relayer address of the bridge proof\n function bridgeProofs(bytes32 transactionId) external view returns (uint96 timestamp, address relayer);\n\n /// @notice Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\n /// @param request The bridge request to decode\n function getBridgeTransactionV2(bytes memory request) external view returns (BridgeTransactionV2 memory);\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// contracts/libs/UniversalToken.sol\n\nlibrary UniversalTokenLib {\n using SafeERC20 for IERC20;\n\n address internal constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Transfers tokens to the given account. Reverts if transfer is not successful.\n /// @dev This might trigger fallback, if ETH is transferred to the contract.\n /// Make sure this can not lead to reentrancy attacks.\n function universalTransfer(address token, address to, uint256 value) internal {\n // Don't do anything, if need to send tokens to this address\n if (to == address(this)) return;\n // Don't do anything, if trying to send zero value\n if (value == 0) return;\n if (token == ETH_ADDRESS) {\n /// @dev Note: this can potentially lead to executing code in `to`.\n // solhint-disable-next-line avoid-low-level-calls\n (bool success,) = to.call{value: value}(\"\");\n require(success, \"ETH transfer failed\");\n } else {\n IERC20(token).safeTransfer(to, value);\n }\n }\n\n /// @notice Issues an infinite allowance to the spender, if the current allowance is insufficient\n /// to spend the given amount.\n function universalApproveInfinity(address token, address spender, uint256 amountToSpend) internal {\n // ETH Chad doesn't require your approval\n if (token == ETH_ADDRESS) return;\n // No-op if allowance is already sufficient\n uint256 allowance = IERC20(token).allowance(address(this), spender);\n if (allowance \u003e= amountToSpend) return;\n // Otherwise, reset approval to 0 and set to max allowance\n if (allowance \u003e 0) IERC20(token).safeDecreaseAllowance(spender, allowance);\n IERC20(token).safeIncreaseAllowance(spender, type(uint256).max);\n }\n\n /// @notice Returns the balance of the given token (or native ETH) for the given account.\n function universalBalanceOf(address token, address account) internal view returns (uint256) {\n if (token == ETH_ADDRESS) {\n return account.balance;\n } else {\n return IERC20(token).balanceOf(account);\n }\n }\n\n /// @dev Checks that token is a contract and not ETH_ADDRESS.\n function assertIsContract(address token) internal view {\n // Check that ETH_ADDRESS was not used (in case this is a predeploy on any of the chains)\n if (token == UniversalTokenLib.ETH_ADDRESS) revert TokenNotContract();\n // Check that token is not an EOA\n if (token.code.length == 0) revert TokenNotContract();\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/Admin.sol\n\ncontract Admin is IAdmin, AccessControlEnumerable {\n using UniversalTokenLib for address;\n\n bytes32 public constant RELAYER_ROLE = keccak256(\"RELAYER_ROLE\");\n bytes32 public constant REFUNDER_ROLE = keccak256(\"REFUNDER_ROLE\");\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n uint256 public constant FEE_BPS = 1e6;\n uint256 public constant FEE_RATE_MAX = 0.01e6; // max 1% on origin amount\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Chain gas amount to forward as rebate if requested\n uint256 public chainGasAmount;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n }\n\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n require(newFeeRate \u003c= FEE_RATE_MAX, \"newFeeRate \u003e max\");\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n token.universalTransfer(recipient, feeAmount);\n emit FeesSwept(token, recipient, feeAmount);\n }\n\n function setChainGasAmount(uint256 newChainGasAmount) external onlyRole(GOVERNOR_ROLE) {\n uint256 oldChainGasAmount = chainGasAmount;\n chainGasAmount = newChainGasAmount;\n emit ChainGasAmountUpdated(oldChainGasAmount, newChainGasAmount);\n }\n}\n\n// contracts/FastBridgeV2.sol\n\n/// @notice FastBridgeV2 is a contract for bridging tokens across chains.\ncontract FastBridgeV2 is Admin, IFastBridgeV2, IFastBridgeV2Errors {\n using SafeERC20 for IERC20;\n using UniversalTokenLib for address;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Delay for a transaction after which it could be permisionlessly refunded\n uint256 public constant REFUND_DELAY = 7 days;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n /// @notice Maximum length of accepted callParams\n uint256 public constant MAX_CALL_PARAMS_LENGTH = 2 ** 16 - 1;\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeTxDetails) public bridgeTxDetails;\n /// @notice Relay details on destination chain\n mapping(bytes32 =\u003e BridgeRelay) public bridgeRelayDetails;\n /// @notice Unique bridge nonces tracked per originSender\n mapping(address =\u003e uint256) public senderNonces;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Replaced by senderNonces\n uint256 public immutable nonce = 0;\n /// @notice the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n bridge({\n params: params,\n paramsV2: BridgeParamsV2({\n quoteRelayer: address(0),\n quoteExclusivitySeconds: 0,\n quoteId: bytes(\"\"),\n callValue: 0,\n callParams: bytes(\"\")\n })\n });\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes memory request) external payable {\n relay({request: request, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes memory request, bytes32 destTxHash) external {\n prove({transactionId: keccak256(request), destTxHash: destTxHash, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridgeV2\n function claim(bytes memory request) external {\n claim({request: request, to: address(0)});\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003e DISPUTE_PERIOD) {\n revert DisputePeriodPassed();\n }\n\n // @dev relayer gets slashed effectively if dest relay has gone thru\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n bridgeTxDetails[transactionId].proofRelayer = address(0);\n bridgeTxDetails[transactionId].proofBlockTimestamp = 0;\n bridgeTxDetails[transactionId].proofBlockNumber = 0;\n\n emit BridgeProofDisputed(transactionId, msg.sender);\n }\n\n /// @inheritdoc IFastBridge\n function refund(bytes memory request) external {\n bytes32 transactionId = keccak256(request);\n\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n\n if (bridgeTxDetails[transactionId].status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n\n if (hasRole(REFUNDER_ROLE, msg.sender)) {\n // Refunder can refund if deadline has passed\n if (block.timestamp \u003c= transaction.deadline) revert DeadlineNotExceeded();\n } else {\n // Permissionless refund is allowed after REFUND_DELAY\n if (block.timestamp \u003c= transaction.deadline + REFUND_DELAY) revert DeadlineNotExceeded();\n }\n\n // if all checks passed, set to REFUNDED status\n bridgeTxDetails[transactionId].status = BridgeStatus.REFUNDED;\n\n // transfer origin collateral back to original sender\n address to = transaction.originSender;\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount + transaction.originFeeAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (bridgeTxDetails[transactionId].proofRelayer != relayer) revert SenderIncorrect();\n return _timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n /// @dev This method is added to achieve backwards compatibility with decoding requests into V1 structs:\n /// - `callValue` is partially reported as a zero/non-zero flag\n /// - `callParams` is ignored\n /// In order to process all kinds of requests use getBridgeTransactionV2 instead.\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory) {\n // Try decoding into V2 struct first. This will revert if V1 struct is passed\n try this.getBridgeTransactionV2(request) returns (BridgeTransactionV2 memory txV2) {\n // Note: we entirely ignore the callParams field, as it was not present in V1\n return BridgeTransaction({\n originChainId: txV2.originChainId,\n destChainId: txV2.destChainId,\n originSender: txV2.originSender,\n destRecipient: txV2.destRecipient,\n originToken: txV2.originToken,\n destToken: txV2.destToken,\n originAmount: txV2.originAmount,\n destAmount: txV2.destAmount,\n originFeeAmount: txV2.originFeeAmount,\n sendChainGas: txV2.callValue != 0,\n deadline: txV2.deadline,\n nonce: txV2.nonce\n });\n } catch {\n // Fallback to V1 struct\n return abi.decode(request, (BridgeTransaction));\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) public payable {\n int256 exclusivityEndTime = int256(block.timestamp) + paramsV2.quoteExclusivitySeconds;\n _validateBridgeParams(params, paramsV2, exclusivityEndTime);\n\n // transfer tokens to bridge contract\n /// @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _takeBridgedUserAsset(params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n\n // set status to requested\n bytes memory request = abi.encode(\n BridgeTransactionV2({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n callValue: paramsV2.callValue,\n deadline: params.deadline,\n nonce: senderNonces[params.sender]++, // increment nonce on every bridge\n exclusivityRelayer: paramsV2.quoteRelayer,\n // We checked exclusivityEndTime to be in range (0 .. params.deadline] above, so can safely cast\n exclusivityEndTime: uint256(exclusivityEndTime),\n callParams: paramsV2.callParams\n })\n );\n bytes32 transactionId = keccak256(request);\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n\n emit BridgeRequested({\n transactionId: transactionId,\n sender: params.sender,\n request: request,\n destChainId: params.dstChainId,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n sendChainGas: paramsV2.callValue != 0\n });\n emit BridgeQuoteDetails(transactionId, paramsV2.quoteId);\n }\n\n /// @inheritdoc IFastBridgeV2\n function relay(bytes memory request, address relayer) public payable {\n bytes32 transactionId = keccak256(request);\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n _validateRelayParams(transaction, transactionId, relayer);\n // mark bridge transaction as relayed\n bridgeRelayDetails[transactionId] =\n BridgeRelay({blockNumber: uint48(block.number), blockTimestamp: uint48(block.timestamp), relayer: relayer});\n\n // transfer tokens to recipient on destination chain and do an arbitrary call if requested\n address to = transaction.destRecipient;\n address token = transaction.destToken;\n uint256 amount = transaction.destAmount;\n uint256 callValue = transaction.callValue;\n\n // Emit the event before any external calls\n emit BridgeRelayed({\n transactionId: transactionId,\n relayer: relayer,\n to: to,\n originChainId: transaction.originChainId,\n originToken: transaction.originToken,\n destToken: token,\n originAmount: transaction.originAmount,\n destAmount: amount,\n chainGasAmount: callValue\n });\n\n // All state changes have been done at this point, can proceed to the external calls.\n // This follows the checks-effects-interactions pattern to mitigate potential reentrancy attacks.\n if (token == UniversalTokenLib.ETH_ADDRESS) {\n // For ETH non-zero callValue is not allowed\n if (callValue != 0) revert NativeTokenCallValueNotSupported();\n // Check that the correct msg.value was sent\n if (msg.value != amount) revert MsgValueIncorrect();\n } else {\n // For ERC20s, we check that the correct msg.value was sent\n if (msg.value != callValue) revert MsgValueIncorrect();\n // We need to transfer the tokens from the Relayer to the recipient first before performing an\n // optional post-transfer arbitrary call.\n IERC20(token).safeTransferFrom(msg.sender, to, amount);\n }\n\n if (transaction.callParams.length != 0) {\n // Arbitrary call requested, perform it while supplying full msg.value to the recipient\n // Note: if token has a fee on transfers, the recipient will have received less than `amount`.\n // This is a very niche edge case and should be handled by the recipient contract.\n _checkedCallRecipient({recipient: to, token: token, amount: amount, callParams: transaction.callParams});\n } else if (msg.value != 0) {\n // No arbitrary call requested, but msg.value was sent. This is either a relay with ETH,\n // or a non-zero callValue request with an ERC20. In both cases, transfer the ETH to the recipient.\n Address.sendValue(payable(to), msg.value);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) public onlyRole(RELAYER_ROLE) {\n // update bridge tx status given proof provided\n if (bridgeTxDetails[transactionId].status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n bridgeTxDetails[transactionId].status = BridgeStatus.RELAYER_PROVED;\n bridgeTxDetails[transactionId].proofBlockTimestamp = uint40(block.timestamp);\n bridgeTxDetails[transactionId].proofBlockNumber = uint48(block.number);\n bridgeTxDetails[transactionId].proofRelayer = relayer;\n\n emit BridgeProofProvided(transactionId, relayer, destTxHash);\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes memory request, address to) public {\n bytes32 transactionId = keccak256(request);\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n\n // update bridge tx status if able to claim origin collateral\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n\n // if \"to\" is zero addr, permissionlessly send funds to proven relayer\n if (to == address(0)) {\n to = bridgeTxDetails[transactionId].proofRelayer;\n } else if (bridgeTxDetails[transactionId].proofRelayer != msg.sender) {\n revert SenderIncorrect();\n }\n\n if (_timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003c= DISPUTE_PERIOD) {\n revert DisputePeriodNotPassed();\n }\n\n bridgeTxDetails[transactionId].status = BridgeStatus.RELAYER_CLAIMED;\n\n // update protocol fees if origin fee amount exists\n if (transaction.originFeeAmount \u003e 0) protocolFees[transaction.originToken] += transaction.originFeeAmount;\n\n // transfer origin collateral less fee to specified address\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositClaimed(transactionId, bridgeTxDetails[transactionId].proofRelayer, to, token, amount);\n }\n\n function bridgeStatuses(bytes32 transactionId) public view returns (BridgeStatus status) {\n return bridgeTxDetails[transactionId].status;\n }\n\n function bridgeProofs(bytes32 transactionId) public view returns (uint96 timestamp, address relayer) {\n timestamp = bridgeTxDetails[transactionId].proofBlockTimestamp;\n relayer = bridgeTxDetails[transactionId].proofRelayer;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeRelays(bytes32 transactionId) public view returns (bool) {\n // has this transactionId been relayed?\n return bridgeRelayDetails[transactionId].relayer != address(0);\n }\n\n /// @inheritdoc IFastBridgeV2\n function getBridgeTransactionV2(bytes memory request) public pure returns (BridgeTransactionV2 memory) {\n return abi.decode(request, (BridgeTransactionV2));\n }\n\n /// @notice Takes the bridged asset from the user into FastBridgeV2 custody. It will be later\n /// claimed by the relayer who completed the relay on destination chain, or refunded back to the user,\n /// should no one complete the relay.\n function _takeBridgedUserAsset(address token, uint256 amount) internal returns (uint256 amountTaken) {\n if (token == UniversalTokenLib.ETH_ADDRESS) {\n // For ETH we just need to check that the supplied msg.value is correct.\n // Supplied `msg.value` is already in FastBridgeV2 custody.\n if (amount != msg.value) revert MsgValueIncorrect();\n amountTaken = msg.value;\n } else {\n // For ERC20s, token is explicitly transferred from the user to FastBridgeV2.\n // We don't allow non-zero `msg.value` to avoid extra funds from being stuck in FastBridgeV2.\n token.assertIsContract();\n if (msg.value != 0) revert MsgValueIncorrect();\n amountTaken = IERC20(token).balanceOf(address(this));\n IERC20(token).safeTransferFrom(msg.sender, address(this), amount);\n // Use the balance difference as the amount taken in case of fee on transfer tokens.\n amountTaken = IERC20(token).balanceOf(address(this)) - amountTaken;\n }\n }\n\n /// @notice Calls the Recipient's hook function with the specified callParams and performs\n /// all the necessary checks for the returned value.\n function _checkedCallRecipient(\n address recipient,\n address token,\n uint256 amount,\n bytes memory callParams\n )\n internal\n {\n bytes memory hookData =\n abi.encodeCall(IFastBridgeRecipient.fastBridgeTransferReceived, (token, amount, callParams));\n // This will bubble any revert messages from the hook function\n bytes memory returnData = Address.functionCallWithValue({target: recipient, data: hookData, value: msg.value});\n // Explicit revert if no return data at all\n if (returnData.length == 0) revert RecipientNoReturnValue();\n // Check that exactly a single return value was returned\n if (returnData.length != 32) revert RecipientIncorrectReturnValue();\n // Return value should be abi-encoded hook function selector\n if (bytes32(returnData) != bytes32(IFastBridgeRecipient.fastBridgeTransferReceived.selector)) {\n revert RecipientIncorrectReturnValue();\n }\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint40(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint40).max but\n /// proof.timestamp \u003c type(uint40).max via unchecked statement\n /// @param proofBlockTimestamp The bridge proof block timestamp\n /// @return delta Time delta since proof submitted\n function _timeSince(uint40 proofBlockTimestamp) internal view returns (uint256 delta) {\n unchecked {\n delta = uint40(block.timestamp) - proofBlockTimestamp;\n }\n }\n\n /// @notice Performs all the necessary checks for a bridge to happen.\n /// @dev There's no good way to refactor this function to reduce cyclomatic complexity due to\n /// the number of checks that need to be performed, so we skip the code-complexity rule here.\n // solhint-disable-next-line code-complexity\n function _validateBridgeParams(\n BridgeParams memory params,\n BridgeParamsV2 memory paramsV2,\n int256 exclusivityEndTime\n )\n internal\n view\n {\n // Check V1 (legacy) params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.sender == address(0) || params.to == address(0)) revert ZeroAddress();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n // Check V2 params\n if (paramsV2.callParams.length \u003e MAX_CALL_PARAMS_LENGTH) revert CallParamsLengthAboveMax();\n if (paramsV2.callValue != 0 \u0026\u0026 params.destToken == UniversalTokenLib.ETH_ADDRESS) {\n revert NativeTokenCallValueNotSupported();\n }\n // exclusivityEndTime must be in range (0 .. params.deadline]\n if (exclusivityEndTime \u003c= 0 || exclusivityEndTime \u003e int256(params.deadline)) {\n revert ExclusivityParamsIncorrect();\n }\n }\n\n /// @notice Performs all the necessary checks for a relay to happen.\n function _validateRelayParams(\n BridgeTransactionV2 memory transaction,\n bytes32 transactionId,\n address relayer\n )\n internal\n view\n {\n if (relayer == address(0)) revert ZeroAddress();\n // Check if the transaction has already been relayed\n if (bridgeRelays(transactionId)) revert TransactionRelayed();\n if (transaction.destChainId != block.chainid) revert ChainIncorrect();\n // Check the deadline for relay to happen\n if (block.timestamp \u003e transaction.deadline) revert DeadlineExceeded();\n // Check the exclusivity period, if it is still ongoing\n // forgefmt: disable-next-item\n if (\n transaction.exclusivityRelayer != address(0) \u0026\u0026\n transaction.exclusivityRelayer != relayer \u0026\u0026\n block.timestamp \u003c= transaction.exclusivityEndTime\n ) {\n revert ExclusivityPeriodNotPassed();\n }\n }\n}\n","language":"Solidity","languageVersion":"0.8.24","compilerVersion":"0.8.24","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"","srcMapRuntime":"","abiDefinition":[{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldChainGasAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newChainGasAmount","type":"uint256"}],"name":"ChainGasAmountUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldFeeRate","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newFeeRate","type":"uint256"}],"name":"FeeRateUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"address","name":"recipient","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"FeesSwept","type":"event"},{"inputs":[{"internalType":"uint256","name":"newChainGasAmount","type":"uint256"}],"name":"setChainGasAmount","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"newFeeRate","type":"uint256"}],"name":"setProtocolFeeRate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"address","name":"recipient","type":"address"}],"name":"sweepProtocolFees","outputs":[],"stateMutability":"nonpayable","type":"function"}],"userDoc":{"kind":"user","methods":{},"version":1},"developerDoc":{"kind":"dev","methods":{},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"oldChainGasAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newChainGasAmount\",\"type\":\"uint256\"}],\"name\":\"ChainGasAmountUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"oldFeeRate\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newFeeRate\",\"type\":\"uint256\"}],\"name\":\"FeeRateUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"FeesSwept\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"newChainGasAmount\",\"type\":\"uint256\"}],\"name\":\"setChainGasAmount\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"newFeeRate\",\"type\":\"uint256\"}],\"name\":\"setProtocolFeeRate\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"}],\"name\":\"sweepProtocolFees\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeV2.sol\":\"IAdmin\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeV2.sol\":{\"keccak256\":\"0xfd916c030b1ffca5a136817827b8018c8ba42ca089905747f3de6148b73eb35e\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://18e6438c4096deb8ae453fb3365ba2b07d52944e93c08288fc5d012b71bf6bb3\",\"dweb:/ipfs/QmfEMqpT1zz6RRm7UuHLRowe1tds2cTGLrVonfm9XSCACj\"]}},\"version\":1}"},"hashes":{"setChainGasAmount(uint256)":"b250fe6b","setProtocolFeeRate(uint256)":"b13aa2d6","sweepProtocolFees(address,address)":"06f333f2"}},"solidity/FastBridgeV2.sol:IERC165":{"code":"0x","runtime-code":"0x","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.24 ^0.8.0 ^0.8.20;\n\n// contracts/interfaces/IAdmin.sol\n\ninterface IAdmin {\n // ============ Events ============\n\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n event ChainGasAmountUpdated(uint256 oldChainGasAmount, uint256 newChainGasAmount);\n\n // ============ Methods ============\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n\n function setChainGasAmount(uint256 newChainGasAmount) external;\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IFastBridgeRecipient.sol\n\ninterface IFastBridgeRecipient {\n function fastBridgeTransferReceived(\n address token,\n uint256 amount,\n bytes memory callParams\n )\n external\n payable\n returns (bytes4);\n}\n\n// contracts/interfaces/IFastBridgeV2Errors.sol\n\ninterface IFastBridgeV2Errors {\n error AmountIncorrect();\n error CallParamsLengthAboveMax();\n error ChainIncorrect();\n error ExclusivityParamsIncorrect();\n error MsgValueIncorrect();\n error NativeTokenCallValueNotSupported();\n error SenderIncorrect();\n error StatusIncorrect();\n error ZeroAddress();\n\n error RecipientIncorrectReturnValue();\n error RecipientNoReturnValue();\n\n error DeadlineExceeded();\n error DeadlineNotExceeded();\n error DeadlineTooShort();\n error DisputePeriodNotPassed();\n error DisputePeriodPassed();\n error ExclusivityPeriodNotPassed();\n\n error TransactionRelayed();\n}\n\n// contracts/libs/Errors.sol\n\nerror DeadlineExceeded();\nerror DeadlineNotExceeded();\nerror DeadlineTooShort();\nerror InsufficientOutputAmount();\n\nerror MsgValueIncorrect();\nerror PoolNotFound();\nerror TokenAddressMismatch();\nerror TokenNotContract();\nerror TokenNotETH();\nerror TokensIdentical();\n\nerror ChainIncorrect();\nerror AmountIncorrect();\nerror ZeroAddress();\n\nerror DisputePeriodNotPassed();\nerror DisputePeriodPassed();\nerror SenderIncorrect();\nerror StatusIncorrect();\nerror TransactionIdIncorrect();\nerror TransactionRelayed();\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// contracts/interfaces/IFastBridgeV2.sol\n\ninterface IFastBridgeV2 is IFastBridge {\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n struct BridgeTxDetails {\n BridgeStatus status;\n uint40 proofBlockTimestamp;\n uint48 proofBlockNumber;\n address proofRelayer;\n }\n\n struct BridgeRelay {\n uint48 blockNumber;\n uint48 blockTimestamp;\n address relayer;\n }\n\n /// @notice New params introduced in the FastBridgeV2.\n /// We are passing fields from the older BridgeParams struct outside of this struct\n /// for backwards compatibility.\n /// Note: quoteRelayer and quoteExclusivitySeconds are either both zero (indicating no exclusivity)\n /// or both non-zero (indicating exclusivity for the given period).\n /// Note: callValue \u003e 0 can NOT be used with destToken = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE (ETH_ADDRESS)\n /// @param quoteRelayer Relayer that provided the quote for the transaction\n /// @param quoteExclusivitySeconds Period of time the quote relayer is guaranteed exclusivity after user's deposit\n /// @param quoteId Unique quote identifier used for tracking the quote\n /// @param callValue ETH value to send to the recipient (if any)\n /// @param callParams Parameters for the arbitrary call to the destination recipient (if any)\n struct BridgeParamsV2 {\n address quoteRelayer;\n int256 quoteExclusivitySeconds;\n bytes quoteId;\n uint256 callValue;\n bytes callParams;\n }\n\n /// @notice Updated bridge transaction struct to include parameters introduced in FastBridgeV2.\n /// Note: only `exclusivityRelayer` can fill such a transaction until `exclusivityEndTime`.\n /// TODO: consider changing the encoding scheme to prevent spending extra gas on decoding.\n struct BridgeTransactionV2 {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n uint256 callValue; // ETH value to send to the recipient (if any) - replaces V1's sendChainGas flag\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n address exclusivityRelayer;\n uint256 exclusivityEndTime;\n bytes callParams;\n }\n\n event BridgeQuoteDetails(bytes32 indexed transactionId, bytes quoteId);\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability\n /// to provide temporary exclusivity fill rights for the quote relayer.\n /// @param params The parameters required to bridge\n /// @param paramsV2 The parameters for exclusivity fill rights (optional, can be left empty)\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function relay(bytes memory request, address relayer) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param transactionId The transaction id associated with the encoded bridge transaction to prove\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital.\n /// @notice Can only send funds to the relayer address on the proof.\n /// @param request The encoded bridge transaction to claim on origin chain\n function claim(bytes memory request) external;\n /// @notice Checks if a transaction has been relayed\n /// @param transactionId The ID of the transaction to check\n /// @return True if the transaction has been relayed, false otherwise\n function bridgeRelays(bytes32 transactionId) external view returns (bool);\n\n /// @notice Returns the status of a bridge transaction\n /// @param transactionId The ID of the bridge transaction\n /// @return BridgeStatus Status of the bridge transaction\n function bridgeStatuses(bytes32 transactionId) external view returns (BridgeStatus);\n\n /// @notice Returns the timestamp and relayer of a bridge proof\n /// @param transactionId The ID of the bridge transaction\n /// @return timestamp The timestamp of the bridge proof\n /// @return relayer The relayer address of the bridge proof\n function bridgeProofs(bytes32 transactionId) external view returns (uint96 timestamp, address relayer);\n\n /// @notice Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\n /// @param request The bridge request to decode\n function getBridgeTransactionV2(bytes memory request) external view returns (BridgeTransactionV2 memory);\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// contracts/libs/UniversalToken.sol\n\nlibrary UniversalTokenLib {\n using SafeERC20 for IERC20;\n\n address internal constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Transfers tokens to the given account. Reverts if transfer is not successful.\n /// @dev This might trigger fallback, if ETH is transferred to the contract.\n /// Make sure this can not lead to reentrancy attacks.\n function universalTransfer(address token, address to, uint256 value) internal {\n // Don't do anything, if need to send tokens to this address\n if (to == address(this)) return;\n // Don't do anything, if trying to send zero value\n if (value == 0) return;\n if (token == ETH_ADDRESS) {\n /// @dev Note: this can potentially lead to executing code in `to`.\n // solhint-disable-next-line avoid-low-level-calls\n (bool success,) = to.call{value: value}(\"\");\n require(success, \"ETH transfer failed\");\n } else {\n IERC20(token).safeTransfer(to, value);\n }\n }\n\n /// @notice Issues an infinite allowance to the spender, if the current allowance is insufficient\n /// to spend the given amount.\n function universalApproveInfinity(address token, address spender, uint256 amountToSpend) internal {\n // ETH Chad doesn't require your approval\n if (token == ETH_ADDRESS) return;\n // No-op if allowance is already sufficient\n uint256 allowance = IERC20(token).allowance(address(this), spender);\n if (allowance \u003e= amountToSpend) return;\n // Otherwise, reset approval to 0 and set to max allowance\n if (allowance \u003e 0) IERC20(token).safeDecreaseAllowance(spender, allowance);\n IERC20(token).safeIncreaseAllowance(spender, type(uint256).max);\n }\n\n /// @notice Returns the balance of the given token (or native ETH) for the given account.\n function universalBalanceOf(address token, address account) internal view returns (uint256) {\n if (token == ETH_ADDRESS) {\n return account.balance;\n } else {\n return IERC20(token).balanceOf(account);\n }\n }\n\n /// @dev Checks that token is a contract and not ETH_ADDRESS.\n function assertIsContract(address token) internal view {\n // Check that ETH_ADDRESS was not used (in case this is a predeploy on any of the chains)\n if (token == UniversalTokenLib.ETH_ADDRESS) revert TokenNotContract();\n // Check that token is not an EOA\n if (token.code.length == 0) revert TokenNotContract();\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/Admin.sol\n\ncontract Admin is IAdmin, AccessControlEnumerable {\n using UniversalTokenLib for address;\n\n bytes32 public constant RELAYER_ROLE = keccak256(\"RELAYER_ROLE\");\n bytes32 public constant REFUNDER_ROLE = keccak256(\"REFUNDER_ROLE\");\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n uint256 public constant FEE_BPS = 1e6;\n uint256 public constant FEE_RATE_MAX = 0.01e6; // max 1% on origin amount\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Chain gas amount to forward as rebate if requested\n uint256 public chainGasAmount;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n }\n\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n require(newFeeRate \u003c= FEE_RATE_MAX, \"newFeeRate \u003e max\");\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n token.universalTransfer(recipient, feeAmount);\n emit FeesSwept(token, recipient, feeAmount);\n }\n\n function setChainGasAmount(uint256 newChainGasAmount) external onlyRole(GOVERNOR_ROLE) {\n uint256 oldChainGasAmount = chainGasAmount;\n chainGasAmount = newChainGasAmount;\n emit ChainGasAmountUpdated(oldChainGasAmount, newChainGasAmount);\n }\n}\n\n// contracts/FastBridgeV2.sol\n\n/// @notice FastBridgeV2 is a contract for bridging tokens across chains.\ncontract FastBridgeV2 is Admin, IFastBridgeV2, IFastBridgeV2Errors {\n using SafeERC20 for IERC20;\n using UniversalTokenLib for address;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Delay for a transaction after which it could be permisionlessly refunded\n uint256 public constant REFUND_DELAY = 7 days;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n /// @notice Maximum length of accepted callParams\n uint256 public constant MAX_CALL_PARAMS_LENGTH = 2 ** 16 - 1;\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeTxDetails) public bridgeTxDetails;\n /// @notice Relay details on destination chain\n mapping(bytes32 =\u003e BridgeRelay) public bridgeRelayDetails;\n /// @notice Unique bridge nonces tracked per originSender\n mapping(address =\u003e uint256) public senderNonces;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Replaced by senderNonces\n uint256 public immutable nonce = 0;\n /// @notice the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n bridge({\n params: params,\n paramsV2: BridgeParamsV2({\n quoteRelayer: address(0),\n quoteExclusivitySeconds: 0,\n quoteId: bytes(\"\"),\n callValue: 0,\n callParams: bytes(\"\")\n })\n });\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes memory request) external payable {\n relay({request: request, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes memory request, bytes32 destTxHash) external {\n prove({transactionId: keccak256(request), destTxHash: destTxHash, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridgeV2\n function claim(bytes memory request) external {\n claim({request: request, to: address(0)});\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003e DISPUTE_PERIOD) {\n revert DisputePeriodPassed();\n }\n\n // @dev relayer gets slashed effectively if dest relay has gone thru\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n bridgeTxDetails[transactionId].proofRelayer = address(0);\n bridgeTxDetails[transactionId].proofBlockTimestamp = 0;\n bridgeTxDetails[transactionId].proofBlockNumber = 0;\n\n emit BridgeProofDisputed(transactionId, msg.sender);\n }\n\n /// @inheritdoc IFastBridge\n function refund(bytes memory request) external {\n bytes32 transactionId = keccak256(request);\n\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n\n if (bridgeTxDetails[transactionId].status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n\n if (hasRole(REFUNDER_ROLE, msg.sender)) {\n // Refunder can refund if deadline has passed\n if (block.timestamp \u003c= transaction.deadline) revert DeadlineNotExceeded();\n } else {\n // Permissionless refund is allowed after REFUND_DELAY\n if (block.timestamp \u003c= transaction.deadline + REFUND_DELAY) revert DeadlineNotExceeded();\n }\n\n // if all checks passed, set to REFUNDED status\n bridgeTxDetails[transactionId].status = BridgeStatus.REFUNDED;\n\n // transfer origin collateral back to original sender\n address to = transaction.originSender;\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount + transaction.originFeeAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (bridgeTxDetails[transactionId].proofRelayer != relayer) revert SenderIncorrect();\n return _timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n /// @dev This method is added to achieve backwards compatibility with decoding requests into V1 structs:\n /// - `callValue` is partially reported as a zero/non-zero flag\n /// - `callParams` is ignored\n /// In order to process all kinds of requests use getBridgeTransactionV2 instead.\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory) {\n // Try decoding into V2 struct first. This will revert if V1 struct is passed\n try this.getBridgeTransactionV2(request) returns (BridgeTransactionV2 memory txV2) {\n // Note: we entirely ignore the callParams field, as it was not present in V1\n return BridgeTransaction({\n originChainId: txV2.originChainId,\n destChainId: txV2.destChainId,\n originSender: txV2.originSender,\n destRecipient: txV2.destRecipient,\n originToken: txV2.originToken,\n destToken: txV2.destToken,\n originAmount: txV2.originAmount,\n destAmount: txV2.destAmount,\n originFeeAmount: txV2.originFeeAmount,\n sendChainGas: txV2.callValue != 0,\n deadline: txV2.deadline,\n nonce: txV2.nonce\n });\n } catch {\n // Fallback to V1 struct\n return abi.decode(request, (BridgeTransaction));\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) public payable {\n int256 exclusivityEndTime = int256(block.timestamp) + paramsV2.quoteExclusivitySeconds;\n _validateBridgeParams(params, paramsV2, exclusivityEndTime);\n\n // transfer tokens to bridge contract\n /// @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _takeBridgedUserAsset(params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n\n // set status to requested\n bytes memory request = abi.encode(\n BridgeTransactionV2({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n callValue: paramsV2.callValue,\n deadline: params.deadline,\n nonce: senderNonces[params.sender]++, // increment nonce on every bridge\n exclusivityRelayer: paramsV2.quoteRelayer,\n // We checked exclusivityEndTime to be in range (0 .. params.deadline] above, so can safely cast\n exclusivityEndTime: uint256(exclusivityEndTime),\n callParams: paramsV2.callParams\n })\n );\n bytes32 transactionId = keccak256(request);\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n\n emit BridgeRequested({\n transactionId: transactionId,\n sender: params.sender,\n request: request,\n destChainId: params.dstChainId,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n sendChainGas: paramsV2.callValue != 0\n });\n emit BridgeQuoteDetails(transactionId, paramsV2.quoteId);\n }\n\n /// @inheritdoc IFastBridgeV2\n function relay(bytes memory request, address relayer) public payable {\n bytes32 transactionId = keccak256(request);\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n _validateRelayParams(transaction, transactionId, relayer);\n // mark bridge transaction as relayed\n bridgeRelayDetails[transactionId] =\n BridgeRelay({blockNumber: uint48(block.number), blockTimestamp: uint48(block.timestamp), relayer: relayer});\n\n // transfer tokens to recipient on destination chain and do an arbitrary call if requested\n address to = transaction.destRecipient;\n address token = transaction.destToken;\n uint256 amount = transaction.destAmount;\n uint256 callValue = transaction.callValue;\n\n // Emit the event before any external calls\n emit BridgeRelayed({\n transactionId: transactionId,\n relayer: relayer,\n to: to,\n originChainId: transaction.originChainId,\n originToken: transaction.originToken,\n destToken: token,\n originAmount: transaction.originAmount,\n destAmount: amount,\n chainGasAmount: callValue\n });\n\n // All state changes have been done at this point, can proceed to the external calls.\n // This follows the checks-effects-interactions pattern to mitigate potential reentrancy attacks.\n if (token == UniversalTokenLib.ETH_ADDRESS) {\n // For ETH non-zero callValue is not allowed\n if (callValue != 0) revert NativeTokenCallValueNotSupported();\n // Check that the correct msg.value was sent\n if (msg.value != amount) revert MsgValueIncorrect();\n } else {\n // For ERC20s, we check that the correct msg.value was sent\n if (msg.value != callValue) revert MsgValueIncorrect();\n // We need to transfer the tokens from the Relayer to the recipient first before performing an\n // optional post-transfer arbitrary call.\n IERC20(token).safeTransferFrom(msg.sender, to, amount);\n }\n\n if (transaction.callParams.length != 0) {\n // Arbitrary call requested, perform it while supplying full msg.value to the recipient\n // Note: if token has a fee on transfers, the recipient will have received less than `amount`.\n // This is a very niche edge case and should be handled by the recipient contract.\n _checkedCallRecipient({recipient: to, token: token, amount: amount, callParams: transaction.callParams});\n } else if (msg.value != 0) {\n // No arbitrary call requested, but msg.value was sent. This is either a relay with ETH,\n // or a non-zero callValue request with an ERC20. In both cases, transfer the ETH to the recipient.\n Address.sendValue(payable(to), msg.value);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) public onlyRole(RELAYER_ROLE) {\n // update bridge tx status given proof provided\n if (bridgeTxDetails[transactionId].status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n bridgeTxDetails[transactionId].status = BridgeStatus.RELAYER_PROVED;\n bridgeTxDetails[transactionId].proofBlockTimestamp = uint40(block.timestamp);\n bridgeTxDetails[transactionId].proofBlockNumber = uint48(block.number);\n bridgeTxDetails[transactionId].proofRelayer = relayer;\n\n emit BridgeProofProvided(transactionId, relayer, destTxHash);\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes memory request, address to) public {\n bytes32 transactionId = keccak256(request);\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n\n // update bridge tx status if able to claim origin collateral\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n\n // if \"to\" is zero addr, permissionlessly send funds to proven relayer\n if (to == address(0)) {\n to = bridgeTxDetails[transactionId].proofRelayer;\n } else if (bridgeTxDetails[transactionId].proofRelayer != msg.sender) {\n revert SenderIncorrect();\n }\n\n if (_timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003c= DISPUTE_PERIOD) {\n revert DisputePeriodNotPassed();\n }\n\n bridgeTxDetails[transactionId].status = BridgeStatus.RELAYER_CLAIMED;\n\n // update protocol fees if origin fee amount exists\n if (transaction.originFeeAmount \u003e 0) protocolFees[transaction.originToken] += transaction.originFeeAmount;\n\n // transfer origin collateral less fee to specified address\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositClaimed(transactionId, bridgeTxDetails[transactionId].proofRelayer, to, token, amount);\n }\n\n function bridgeStatuses(bytes32 transactionId) public view returns (BridgeStatus status) {\n return bridgeTxDetails[transactionId].status;\n }\n\n function bridgeProofs(bytes32 transactionId) public view returns (uint96 timestamp, address relayer) {\n timestamp = bridgeTxDetails[transactionId].proofBlockTimestamp;\n relayer = bridgeTxDetails[transactionId].proofRelayer;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeRelays(bytes32 transactionId) public view returns (bool) {\n // has this transactionId been relayed?\n return bridgeRelayDetails[transactionId].relayer != address(0);\n }\n\n /// @inheritdoc IFastBridgeV2\n function getBridgeTransactionV2(bytes memory request) public pure returns (BridgeTransactionV2 memory) {\n return abi.decode(request, (BridgeTransactionV2));\n }\n\n /// @notice Takes the bridged asset from the user into FastBridgeV2 custody. It will be later\n /// claimed by the relayer who completed the relay on destination chain, or refunded back to the user,\n /// should no one complete the relay.\n function _takeBridgedUserAsset(address token, uint256 amount) internal returns (uint256 amountTaken) {\n if (token == UniversalTokenLib.ETH_ADDRESS) {\n // For ETH we just need to check that the supplied msg.value is correct.\n // Supplied `msg.value` is already in FastBridgeV2 custody.\n if (amount != msg.value) revert MsgValueIncorrect();\n amountTaken = msg.value;\n } else {\n // For ERC20s, token is explicitly transferred from the user to FastBridgeV2.\n // We don't allow non-zero `msg.value` to avoid extra funds from being stuck in FastBridgeV2.\n token.assertIsContract();\n if (msg.value != 0) revert MsgValueIncorrect();\n amountTaken = IERC20(token).balanceOf(address(this));\n IERC20(token).safeTransferFrom(msg.sender, address(this), amount);\n // Use the balance difference as the amount taken in case of fee on transfer tokens.\n amountTaken = IERC20(token).balanceOf(address(this)) - amountTaken;\n }\n }\n\n /// @notice Calls the Recipient's hook function with the specified callParams and performs\n /// all the necessary checks for the returned value.\n function _checkedCallRecipient(\n address recipient,\n address token,\n uint256 amount,\n bytes memory callParams\n )\n internal\n {\n bytes memory hookData =\n abi.encodeCall(IFastBridgeRecipient.fastBridgeTransferReceived, (token, amount, callParams));\n // This will bubble any revert messages from the hook function\n bytes memory returnData = Address.functionCallWithValue({target: recipient, data: hookData, value: msg.value});\n // Explicit revert if no return data at all\n if (returnData.length == 0) revert RecipientNoReturnValue();\n // Check that exactly a single return value was returned\n if (returnData.length != 32) revert RecipientIncorrectReturnValue();\n // Return value should be abi-encoded hook function selector\n if (bytes32(returnData) != bytes32(IFastBridgeRecipient.fastBridgeTransferReceived.selector)) {\n revert RecipientIncorrectReturnValue();\n }\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint40(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint40).max but\n /// proof.timestamp \u003c type(uint40).max via unchecked statement\n /// @param proofBlockTimestamp The bridge proof block timestamp\n /// @return delta Time delta since proof submitted\n function _timeSince(uint40 proofBlockTimestamp) internal view returns (uint256 delta) {\n unchecked {\n delta = uint40(block.timestamp) - proofBlockTimestamp;\n }\n }\n\n /// @notice Performs all the necessary checks for a bridge to happen.\n /// @dev There's no good way to refactor this function to reduce cyclomatic complexity due to\n /// the number of checks that need to be performed, so we skip the code-complexity rule here.\n // solhint-disable-next-line code-complexity\n function _validateBridgeParams(\n BridgeParams memory params,\n BridgeParamsV2 memory paramsV2,\n int256 exclusivityEndTime\n )\n internal\n view\n {\n // Check V1 (legacy) params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.sender == address(0) || params.to == address(0)) revert ZeroAddress();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n // Check V2 params\n if (paramsV2.callParams.length \u003e MAX_CALL_PARAMS_LENGTH) revert CallParamsLengthAboveMax();\n if (paramsV2.callValue != 0 \u0026\u0026 params.destToken == UniversalTokenLib.ETH_ADDRESS) {\n revert NativeTokenCallValueNotSupported();\n }\n // exclusivityEndTime must be in range (0 .. params.deadline]\n if (exclusivityEndTime \u003c= 0 || exclusivityEndTime \u003e int256(params.deadline)) {\n revert ExclusivityParamsIncorrect();\n }\n }\n\n /// @notice Performs all the necessary checks for a relay to happen.\n function _validateRelayParams(\n BridgeTransactionV2 memory transaction,\n bytes32 transactionId,\n address relayer\n )\n internal\n view\n {\n if (relayer == address(0)) revert ZeroAddress();\n // Check if the transaction has already been relayed\n if (bridgeRelays(transactionId)) revert TransactionRelayed();\n if (transaction.destChainId != block.chainid) revert ChainIncorrect();\n // Check the deadline for relay to happen\n if (block.timestamp \u003e transaction.deadline) revert DeadlineExceeded();\n // Check the exclusivity period, if it is still ongoing\n // forgefmt: disable-next-item\n if (\n transaction.exclusivityRelayer != address(0) \u0026\u0026\n transaction.exclusivityRelayer != relayer \u0026\u0026\n block.timestamp \u003c= transaction.exclusivityEndTime\n ) {\n revert ExclusivityPeriodNotPassed();\n }\n }\n}\n","language":"Solidity","languageVersion":"0.8.24","compilerVersion":"0.8.24","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"","srcMapRuntime":"","abiDefinition":[{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"}],"userDoc":{"kind":"user","methods":{},"version":1},"developerDoc":{"details":"Interface of the ERC165 standard, as defined in the https://eips.ethereum.org/EIPS/eip-165[EIP]. Implementers can declare support of contract interfaces, which can then be queried by others ({ERC165Checker}). For an implementation, see {ERC165}.","kind":"dev","methods":{"supportsInterface(bytes4)":{"details":"Returns true if this contract implements the interface defined by `interfaceId`. See the corresponding https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section] to learn more about how these ids are created. This function call must use less than 30 000 gas."}},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"bytes4\",\"name\":\"interfaceId\",\"type\":\"bytes4\"}],\"name\":\"supportsInterface\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"}],\"devdoc\":{\"details\":\"Interface of the ERC165 standard, as defined in the https://eips.ethereum.org/EIPS/eip-165[EIP]. Implementers can declare support of contract interfaces, which can then be queried by others ({ERC165Checker}). For an implementation, see {ERC165}.\",\"kind\":\"dev\",\"methods\":{\"supportsInterface(bytes4)\":{\"details\":\"Returns true if this contract implements the interface defined by `interfaceId`. See the corresponding https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section] to learn more about how these ids are created. This function call must use less than 30 000 gas.\"}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeV2.sol\":\"IERC165\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeV2.sol\":{\"keccak256\":\"0xfd916c030b1ffca5a136817827b8018c8ba42ca089905747f3de6148b73eb35e\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://18e6438c4096deb8ae453fb3365ba2b07d52944e93c08288fc5d012b71bf6bb3\",\"dweb:/ipfs/QmfEMqpT1zz6RRm7UuHLRowe1tds2cTGLrVonfm9XSCACj\"]}},\"version\":1}"},"hashes":{"supportsInterface(bytes4)":"01ffc9a7"}},"solidity/FastBridgeV2.sol:IERC20":{"code":"0x","runtime-code":"0x","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.24 ^0.8.0 ^0.8.20;\n\n// contracts/interfaces/IAdmin.sol\n\ninterface IAdmin {\n // ============ Events ============\n\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n event ChainGasAmountUpdated(uint256 oldChainGasAmount, uint256 newChainGasAmount);\n\n // ============ Methods ============\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n\n function setChainGasAmount(uint256 newChainGasAmount) external;\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IFastBridgeRecipient.sol\n\ninterface IFastBridgeRecipient {\n function fastBridgeTransferReceived(\n address token,\n uint256 amount,\n bytes memory callParams\n )\n external\n payable\n returns (bytes4);\n}\n\n// contracts/interfaces/IFastBridgeV2Errors.sol\n\ninterface IFastBridgeV2Errors {\n error AmountIncorrect();\n error CallParamsLengthAboveMax();\n error ChainIncorrect();\n error ExclusivityParamsIncorrect();\n error MsgValueIncorrect();\n error NativeTokenCallValueNotSupported();\n error SenderIncorrect();\n error StatusIncorrect();\n error ZeroAddress();\n\n error RecipientIncorrectReturnValue();\n error RecipientNoReturnValue();\n\n error DeadlineExceeded();\n error DeadlineNotExceeded();\n error DeadlineTooShort();\n error DisputePeriodNotPassed();\n error DisputePeriodPassed();\n error ExclusivityPeriodNotPassed();\n\n error TransactionRelayed();\n}\n\n// contracts/libs/Errors.sol\n\nerror DeadlineExceeded();\nerror DeadlineNotExceeded();\nerror DeadlineTooShort();\nerror InsufficientOutputAmount();\n\nerror MsgValueIncorrect();\nerror PoolNotFound();\nerror TokenAddressMismatch();\nerror TokenNotContract();\nerror TokenNotETH();\nerror TokensIdentical();\n\nerror ChainIncorrect();\nerror AmountIncorrect();\nerror ZeroAddress();\n\nerror DisputePeriodNotPassed();\nerror DisputePeriodPassed();\nerror SenderIncorrect();\nerror StatusIncorrect();\nerror TransactionIdIncorrect();\nerror TransactionRelayed();\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// contracts/interfaces/IFastBridgeV2.sol\n\ninterface IFastBridgeV2 is IFastBridge {\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n struct BridgeTxDetails {\n BridgeStatus status;\n uint40 proofBlockTimestamp;\n uint48 proofBlockNumber;\n address proofRelayer;\n }\n\n struct BridgeRelay {\n uint48 blockNumber;\n uint48 blockTimestamp;\n address relayer;\n }\n\n /// @notice New params introduced in the FastBridgeV2.\n /// We are passing fields from the older BridgeParams struct outside of this struct\n /// for backwards compatibility.\n /// Note: quoteRelayer and quoteExclusivitySeconds are either both zero (indicating no exclusivity)\n /// or both non-zero (indicating exclusivity for the given period).\n /// Note: callValue \u003e 0 can NOT be used with destToken = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE (ETH_ADDRESS)\n /// @param quoteRelayer Relayer that provided the quote for the transaction\n /// @param quoteExclusivitySeconds Period of time the quote relayer is guaranteed exclusivity after user's deposit\n /// @param quoteId Unique quote identifier used for tracking the quote\n /// @param callValue ETH value to send to the recipient (if any)\n /// @param callParams Parameters for the arbitrary call to the destination recipient (if any)\n struct BridgeParamsV2 {\n address quoteRelayer;\n int256 quoteExclusivitySeconds;\n bytes quoteId;\n uint256 callValue;\n bytes callParams;\n }\n\n /// @notice Updated bridge transaction struct to include parameters introduced in FastBridgeV2.\n /// Note: only `exclusivityRelayer` can fill such a transaction until `exclusivityEndTime`.\n /// TODO: consider changing the encoding scheme to prevent spending extra gas on decoding.\n struct BridgeTransactionV2 {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n uint256 callValue; // ETH value to send to the recipient (if any) - replaces V1's sendChainGas flag\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n address exclusivityRelayer;\n uint256 exclusivityEndTime;\n bytes callParams;\n }\n\n event BridgeQuoteDetails(bytes32 indexed transactionId, bytes quoteId);\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability\n /// to provide temporary exclusivity fill rights for the quote relayer.\n /// @param params The parameters required to bridge\n /// @param paramsV2 The parameters for exclusivity fill rights (optional, can be left empty)\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function relay(bytes memory request, address relayer) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param transactionId The transaction id associated with the encoded bridge transaction to prove\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital.\n /// @notice Can only send funds to the relayer address on the proof.\n /// @param request The encoded bridge transaction to claim on origin chain\n function claim(bytes memory request) external;\n /// @notice Checks if a transaction has been relayed\n /// @param transactionId The ID of the transaction to check\n /// @return True if the transaction has been relayed, false otherwise\n function bridgeRelays(bytes32 transactionId) external view returns (bool);\n\n /// @notice Returns the status of a bridge transaction\n /// @param transactionId The ID of the bridge transaction\n /// @return BridgeStatus Status of the bridge transaction\n function bridgeStatuses(bytes32 transactionId) external view returns (BridgeStatus);\n\n /// @notice Returns the timestamp and relayer of a bridge proof\n /// @param transactionId The ID of the bridge transaction\n /// @return timestamp The timestamp of the bridge proof\n /// @return relayer The relayer address of the bridge proof\n function bridgeProofs(bytes32 transactionId) external view returns (uint96 timestamp, address relayer);\n\n /// @notice Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\n /// @param request The bridge request to decode\n function getBridgeTransactionV2(bytes memory request) external view returns (BridgeTransactionV2 memory);\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// contracts/libs/UniversalToken.sol\n\nlibrary UniversalTokenLib {\n using SafeERC20 for IERC20;\n\n address internal constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Transfers tokens to the given account. Reverts if transfer is not successful.\n /// @dev This might trigger fallback, if ETH is transferred to the contract.\n /// Make sure this can not lead to reentrancy attacks.\n function universalTransfer(address token, address to, uint256 value) internal {\n // Don't do anything, if need to send tokens to this address\n if (to == address(this)) return;\n // Don't do anything, if trying to send zero value\n if (value == 0) return;\n if (token == ETH_ADDRESS) {\n /// @dev Note: this can potentially lead to executing code in `to`.\n // solhint-disable-next-line avoid-low-level-calls\n (bool success,) = to.call{value: value}(\"\");\n require(success, \"ETH transfer failed\");\n } else {\n IERC20(token).safeTransfer(to, value);\n }\n }\n\n /// @notice Issues an infinite allowance to the spender, if the current allowance is insufficient\n /// to spend the given amount.\n function universalApproveInfinity(address token, address spender, uint256 amountToSpend) internal {\n // ETH Chad doesn't require your approval\n if (token == ETH_ADDRESS) return;\n // No-op if allowance is already sufficient\n uint256 allowance = IERC20(token).allowance(address(this), spender);\n if (allowance \u003e= amountToSpend) return;\n // Otherwise, reset approval to 0 and set to max allowance\n if (allowance \u003e 0) IERC20(token).safeDecreaseAllowance(spender, allowance);\n IERC20(token).safeIncreaseAllowance(spender, type(uint256).max);\n }\n\n /// @notice Returns the balance of the given token (or native ETH) for the given account.\n function universalBalanceOf(address token, address account) internal view returns (uint256) {\n if (token == ETH_ADDRESS) {\n return account.balance;\n } else {\n return IERC20(token).balanceOf(account);\n }\n }\n\n /// @dev Checks that token is a contract and not ETH_ADDRESS.\n function assertIsContract(address token) internal view {\n // Check that ETH_ADDRESS was not used (in case this is a predeploy on any of the chains)\n if (token == UniversalTokenLib.ETH_ADDRESS) revert TokenNotContract();\n // Check that token is not an EOA\n if (token.code.length == 0) revert TokenNotContract();\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/Admin.sol\n\ncontract Admin is IAdmin, AccessControlEnumerable {\n using UniversalTokenLib for address;\n\n bytes32 public constant RELAYER_ROLE = keccak256(\"RELAYER_ROLE\");\n bytes32 public constant REFUNDER_ROLE = keccak256(\"REFUNDER_ROLE\");\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n uint256 public constant FEE_BPS = 1e6;\n uint256 public constant FEE_RATE_MAX = 0.01e6; // max 1% on origin amount\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Chain gas amount to forward as rebate if requested\n uint256 public chainGasAmount;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n }\n\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n require(newFeeRate \u003c= FEE_RATE_MAX, \"newFeeRate \u003e max\");\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n token.universalTransfer(recipient, feeAmount);\n emit FeesSwept(token, recipient, feeAmount);\n }\n\n function setChainGasAmount(uint256 newChainGasAmount) external onlyRole(GOVERNOR_ROLE) {\n uint256 oldChainGasAmount = chainGasAmount;\n chainGasAmount = newChainGasAmount;\n emit ChainGasAmountUpdated(oldChainGasAmount, newChainGasAmount);\n }\n}\n\n// contracts/FastBridgeV2.sol\n\n/// @notice FastBridgeV2 is a contract for bridging tokens across chains.\ncontract FastBridgeV2 is Admin, IFastBridgeV2, IFastBridgeV2Errors {\n using SafeERC20 for IERC20;\n using UniversalTokenLib for address;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Delay for a transaction after which it could be permisionlessly refunded\n uint256 public constant REFUND_DELAY = 7 days;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n /// @notice Maximum length of accepted callParams\n uint256 public constant MAX_CALL_PARAMS_LENGTH = 2 ** 16 - 1;\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeTxDetails) public bridgeTxDetails;\n /// @notice Relay details on destination chain\n mapping(bytes32 =\u003e BridgeRelay) public bridgeRelayDetails;\n /// @notice Unique bridge nonces tracked per originSender\n mapping(address =\u003e uint256) public senderNonces;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Replaced by senderNonces\n uint256 public immutable nonce = 0;\n /// @notice the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n bridge({\n params: params,\n paramsV2: BridgeParamsV2({\n quoteRelayer: address(0),\n quoteExclusivitySeconds: 0,\n quoteId: bytes(\"\"),\n callValue: 0,\n callParams: bytes(\"\")\n })\n });\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes memory request) external payable {\n relay({request: request, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes memory request, bytes32 destTxHash) external {\n prove({transactionId: keccak256(request), destTxHash: destTxHash, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridgeV2\n function claim(bytes memory request) external {\n claim({request: request, to: address(0)});\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003e DISPUTE_PERIOD) {\n revert DisputePeriodPassed();\n }\n\n // @dev relayer gets slashed effectively if dest relay has gone thru\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n bridgeTxDetails[transactionId].proofRelayer = address(0);\n bridgeTxDetails[transactionId].proofBlockTimestamp = 0;\n bridgeTxDetails[transactionId].proofBlockNumber = 0;\n\n emit BridgeProofDisputed(transactionId, msg.sender);\n }\n\n /// @inheritdoc IFastBridge\n function refund(bytes memory request) external {\n bytes32 transactionId = keccak256(request);\n\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n\n if (bridgeTxDetails[transactionId].status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n\n if (hasRole(REFUNDER_ROLE, msg.sender)) {\n // Refunder can refund if deadline has passed\n if (block.timestamp \u003c= transaction.deadline) revert DeadlineNotExceeded();\n } else {\n // Permissionless refund is allowed after REFUND_DELAY\n if (block.timestamp \u003c= transaction.deadline + REFUND_DELAY) revert DeadlineNotExceeded();\n }\n\n // if all checks passed, set to REFUNDED status\n bridgeTxDetails[transactionId].status = BridgeStatus.REFUNDED;\n\n // transfer origin collateral back to original sender\n address to = transaction.originSender;\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount + transaction.originFeeAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (bridgeTxDetails[transactionId].proofRelayer != relayer) revert SenderIncorrect();\n return _timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n /// @dev This method is added to achieve backwards compatibility with decoding requests into V1 structs:\n /// - `callValue` is partially reported as a zero/non-zero flag\n /// - `callParams` is ignored\n /// In order to process all kinds of requests use getBridgeTransactionV2 instead.\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory) {\n // Try decoding into V2 struct first. This will revert if V1 struct is passed\n try this.getBridgeTransactionV2(request) returns (BridgeTransactionV2 memory txV2) {\n // Note: we entirely ignore the callParams field, as it was not present in V1\n return BridgeTransaction({\n originChainId: txV2.originChainId,\n destChainId: txV2.destChainId,\n originSender: txV2.originSender,\n destRecipient: txV2.destRecipient,\n originToken: txV2.originToken,\n destToken: txV2.destToken,\n originAmount: txV2.originAmount,\n destAmount: txV2.destAmount,\n originFeeAmount: txV2.originFeeAmount,\n sendChainGas: txV2.callValue != 0,\n deadline: txV2.deadline,\n nonce: txV2.nonce\n });\n } catch {\n // Fallback to V1 struct\n return abi.decode(request, (BridgeTransaction));\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) public payable {\n int256 exclusivityEndTime = int256(block.timestamp) + paramsV2.quoteExclusivitySeconds;\n _validateBridgeParams(params, paramsV2, exclusivityEndTime);\n\n // transfer tokens to bridge contract\n /// @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _takeBridgedUserAsset(params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n\n // set status to requested\n bytes memory request = abi.encode(\n BridgeTransactionV2({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n callValue: paramsV2.callValue,\n deadline: params.deadline,\n nonce: senderNonces[params.sender]++, // increment nonce on every bridge\n exclusivityRelayer: paramsV2.quoteRelayer,\n // We checked exclusivityEndTime to be in range (0 .. params.deadline] above, so can safely cast\n exclusivityEndTime: uint256(exclusivityEndTime),\n callParams: paramsV2.callParams\n })\n );\n bytes32 transactionId = keccak256(request);\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n\n emit BridgeRequested({\n transactionId: transactionId,\n sender: params.sender,\n request: request,\n destChainId: params.dstChainId,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n sendChainGas: paramsV2.callValue != 0\n });\n emit BridgeQuoteDetails(transactionId, paramsV2.quoteId);\n }\n\n /// @inheritdoc IFastBridgeV2\n function relay(bytes memory request, address relayer) public payable {\n bytes32 transactionId = keccak256(request);\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n _validateRelayParams(transaction, transactionId, relayer);\n // mark bridge transaction as relayed\n bridgeRelayDetails[transactionId] =\n BridgeRelay({blockNumber: uint48(block.number), blockTimestamp: uint48(block.timestamp), relayer: relayer});\n\n // transfer tokens to recipient on destination chain and do an arbitrary call if requested\n address to = transaction.destRecipient;\n address token = transaction.destToken;\n uint256 amount = transaction.destAmount;\n uint256 callValue = transaction.callValue;\n\n // Emit the event before any external calls\n emit BridgeRelayed({\n transactionId: transactionId,\n relayer: relayer,\n to: to,\n originChainId: transaction.originChainId,\n originToken: transaction.originToken,\n destToken: token,\n originAmount: transaction.originAmount,\n destAmount: amount,\n chainGasAmount: callValue\n });\n\n // All state changes have been done at this point, can proceed to the external calls.\n // This follows the checks-effects-interactions pattern to mitigate potential reentrancy attacks.\n if (token == UniversalTokenLib.ETH_ADDRESS) {\n // For ETH non-zero callValue is not allowed\n if (callValue != 0) revert NativeTokenCallValueNotSupported();\n // Check that the correct msg.value was sent\n if (msg.value != amount) revert MsgValueIncorrect();\n } else {\n // For ERC20s, we check that the correct msg.value was sent\n if (msg.value != callValue) revert MsgValueIncorrect();\n // We need to transfer the tokens from the Relayer to the recipient first before performing an\n // optional post-transfer arbitrary call.\n IERC20(token).safeTransferFrom(msg.sender, to, amount);\n }\n\n if (transaction.callParams.length != 0) {\n // Arbitrary call requested, perform it while supplying full msg.value to the recipient\n // Note: if token has a fee on transfers, the recipient will have received less than `amount`.\n // This is a very niche edge case and should be handled by the recipient contract.\n _checkedCallRecipient({recipient: to, token: token, amount: amount, callParams: transaction.callParams});\n } else if (msg.value != 0) {\n // No arbitrary call requested, but msg.value was sent. This is either a relay with ETH,\n // or a non-zero callValue request with an ERC20. In both cases, transfer the ETH to the recipient.\n Address.sendValue(payable(to), msg.value);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) public onlyRole(RELAYER_ROLE) {\n // update bridge tx status given proof provided\n if (bridgeTxDetails[transactionId].status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n bridgeTxDetails[transactionId].status = BridgeStatus.RELAYER_PROVED;\n bridgeTxDetails[transactionId].proofBlockTimestamp = uint40(block.timestamp);\n bridgeTxDetails[transactionId].proofBlockNumber = uint48(block.number);\n bridgeTxDetails[transactionId].proofRelayer = relayer;\n\n emit BridgeProofProvided(transactionId, relayer, destTxHash);\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes memory request, address to) public {\n bytes32 transactionId = keccak256(request);\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n\n // update bridge tx status if able to claim origin collateral\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n\n // if \"to\" is zero addr, permissionlessly send funds to proven relayer\n if (to == address(0)) {\n to = bridgeTxDetails[transactionId].proofRelayer;\n } else if (bridgeTxDetails[transactionId].proofRelayer != msg.sender) {\n revert SenderIncorrect();\n }\n\n if (_timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003c= DISPUTE_PERIOD) {\n revert DisputePeriodNotPassed();\n }\n\n bridgeTxDetails[transactionId].status = BridgeStatus.RELAYER_CLAIMED;\n\n // update protocol fees if origin fee amount exists\n if (transaction.originFeeAmount \u003e 0) protocolFees[transaction.originToken] += transaction.originFeeAmount;\n\n // transfer origin collateral less fee to specified address\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositClaimed(transactionId, bridgeTxDetails[transactionId].proofRelayer, to, token, amount);\n }\n\n function bridgeStatuses(bytes32 transactionId) public view returns (BridgeStatus status) {\n return bridgeTxDetails[transactionId].status;\n }\n\n function bridgeProofs(bytes32 transactionId) public view returns (uint96 timestamp, address relayer) {\n timestamp = bridgeTxDetails[transactionId].proofBlockTimestamp;\n relayer = bridgeTxDetails[transactionId].proofRelayer;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeRelays(bytes32 transactionId) public view returns (bool) {\n // has this transactionId been relayed?\n return bridgeRelayDetails[transactionId].relayer != address(0);\n }\n\n /// @inheritdoc IFastBridgeV2\n function getBridgeTransactionV2(bytes memory request) public pure returns (BridgeTransactionV2 memory) {\n return abi.decode(request, (BridgeTransactionV2));\n }\n\n /// @notice Takes the bridged asset from the user into FastBridgeV2 custody. It will be later\n /// claimed by the relayer who completed the relay on destination chain, or refunded back to the user,\n /// should no one complete the relay.\n function _takeBridgedUserAsset(address token, uint256 amount) internal returns (uint256 amountTaken) {\n if (token == UniversalTokenLib.ETH_ADDRESS) {\n // For ETH we just need to check that the supplied msg.value is correct.\n // Supplied `msg.value` is already in FastBridgeV2 custody.\n if (amount != msg.value) revert MsgValueIncorrect();\n amountTaken = msg.value;\n } else {\n // For ERC20s, token is explicitly transferred from the user to FastBridgeV2.\n // We don't allow non-zero `msg.value` to avoid extra funds from being stuck in FastBridgeV2.\n token.assertIsContract();\n if (msg.value != 0) revert MsgValueIncorrect();\n amountTaken = IERC20(token).balanceOf(address(this));\n IERC20(token).safeTransferFrom(msg.sender, address(this), amount);\n // Use the balance difference as the amount taken in case of fee on transfer tokens.\n amountTaken = IERC20(token).balanceOf(address(this)) - amountTaken;\n }\n }\n\n /// @notice Calls the Recipient's hook function with the specified callParams and performs\n /// all the necessary checks for the returned value.\n function _checkedCallRecipient(\n address recipient,\n address token,\n uint256 amount,\n bytes memory callParams\n )\n internal\n {\n bytes memory hookData =\n abi.encodeCall(IFastBridgeRecipient.fastBridgeTransferReceived, (token, amount, callParams));\n // This will bubble any revert messages from the hook function\n bytes memory returnData = Address.functionCallWithValue({target: recipient, data: hookData, value: msg.value});\n // Explicit revert if no return data at all\n if (returnData.length == 0) revert RecipientNoReturnValue();\n // Check that exactly a single return value was returned\n if (returnData.length != 32) revert RecipientIncorrectReturnValue();\n // Return value should be abi-encoded hook function selector\n if (bytes32(returnData) != bytes32(IFastBridgeRecipient.fastBridgeTransferReceived.selector)) {\n revert RecipientIncorrectReturnValue();\n }\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint40(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint40).max but\n /// proof.timestamp \u003c type(uint40).max via unchecked statement\n /// @param proofBlockTimestamp The bridge proof block timestamp\n /// @return delta Time delta since proof submitted\n function _timeSince(uint40 proofBlockTimestamp) internal view returns (uint256 delta) {\n unchecked {\n delta = uint40(block.timestamp) - proofBlockTimestamp;\n }\n }\n\n /// @notice Performs all the necessary checks for a bridge to happen.\n /// @dev There's no good way to refactor this function to reduce cyclomatic complexity due to\n /// the number of checks that need to be performed, so we skip the code-complexity rule here.\n // solhint-disable-next-line code-complexity\n function _validateBridgeParams(\n BridgeParams memory params,\n BridgeParamsV2 memory paramsV2,\n int256 exclusivityEndTime\n )\n internal\n view\n {\n // Check V1 (legacy) params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.sender == address(0) || params.to == address(0)) revert ZeroAddress();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n // Check V2 params\n if (paramsV2.callParams.length \u003e MAX_CALL_PARAMS_LENGTH) revert CallParamsLengthAboveMax();\n if (paramsV2.callValue != 0 \u0026\u0026 params.destToken == UniversalTokenLib.ETH_ADDRESS) {\n revert NativeTokenCallValueNotSupported();\n }\n // exclusivityEndTime must be in range (0 .. params.deadline]\n if (exclusivityEndTime \u003c= 0 || exclusivityEndTime \u003e int256(params.deadline)) {\n revert ExclusivityParamsIncorrect();\n }\n }\n\n /// @notice Performs all the necessary checks for a relay to happen.\n function _validateRelayParams(\n BridgeTransactionV2 memory transaction,\n bytes32 transactionId,\n address relayer\n )\n internal\n view\n {\n if (relayer == address(0)) revert ZeroAddress();\n // Check if the transaction has already been relayed\n if (bridgeRelays(transactionId)) revert TransactionRelayed();\n if (transaction.destChainId != block.chainid) revert ChainIncorrect();\n // Check the deadline for relay to happen\n if (block.timestamp \u003e transaction.deadline) revert DeadlineExceeded();\n // Check the exclusivity period, if it is still ongoing\n // forgefmt: disable-next-item\n if (\n transaction.exclusivityRelayer != address(0) \u0026\u0026\n transaction.exclusivityRelayer != relayer \u0026\u0026\n block.timestamp \u003c= transaction.exclusivityEndTime\n ) {\n revert ExclusivityPeriodNotPassed();\n }\n }\n}\n","language":"Solidity","languageVersion":"0.8.24","compilerVersion":"0.8.24","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"","srcMapRuntime":"","abiDefinition":[{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Transfer","type":"event"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"}],"userDoc":{"kind":"user","methods":{},"version":1},"developerDoc":{"details":"Interface of the ERC20 standard as defined in the EIP.","events":{"Approval(address,address,uint256)":{"details":"Emitted when the allowance of a `spender` for an `owner` is set by a call to {approve}. `value` is the new allowance."},"Transfer(address,address,uint256)":{"details":"Emitted when `value` tokens are moved from one account (`from`) to another (`to`). Note that `value` may be zero."}},"kind":"dev","methods":{"allowance(address,address)":{"details":"Returns the remaining number of tokens that `spender` will be allowed to spend on behalf of `owner` through {transferFrom}. This is zero by default. This value changes when {approve} or {transferFrom} are called."},"approve(address,uint256)":{"details":"Sets a `value` amount of tokens as the allowance of `spender` over the caller's tokens. Returns a boolean value indicating whether the operation succeeded. IMPORTANT: Beware that changing an allowance with this method brings the risk that someone may use both the old and the new allowance by unfortunate transaction ordering. One possible solution to mitigate this race condition is to first reduce the spender's allowance to 0 and set the desired value afterwards: https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 Emits an {Approval} event."},"balanceOf(address)":{"details":"Returns the value of tokens owned by `account`."},"totalSupply()":{"details":"Returns the value of tokens in existence."},"transfer(address,uint256)":{"details":"Moves a `value` amount of tokens from the caller's account to `to`. Returns a boolean value indicating whether the operation succeeded. Emits a {Transfer} event."},"transferFrom(address,address,uint256)":{"details":"Moves a `value` amount of tokens from `from` to `to` using the allowance mechanism. `value` is then deducted from the caller's allowance. Returns a boolean value indicating whether the operation succeeded. Emits a {Transfer} event."}},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"Approval\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"Transfer\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"}],\"name\":\"allowance\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"approve\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"balanceOf\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"totalSupply\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"transfer\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"transferFrom\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"details\":\"Interface of the ERC20 standard as defined in the EIP.\",\"events\":{\"Approval(address,address,uint256)\":{\"details\":\"Emitted when the allowance of a `spender` for an `owner` is set by a call to {approve}. `value` is the new allowance.\"},\"Transfer(address,address,uint256)\":{\"details\":\"Emitted when `value` tokens are moved from one account (`from`) to another (`to`). Note that `value` may be zero.\"}},\"kind\":\"dev\",\"methods\":{\"allowance(address,address)\":{\"details\":\"Returns the remaining number of tokens that `spender` will be allowed to spend on behalf of `owner` through {transferFrom}. This is zero by default. This value changes when {approve} or {transferFrom} are called.\"},\"approve(address,uint256)\":{\"details\":\"Sets a `value` amount of tokens as the allowance of `spender` over the caller's tokens. Returns a boolean value indicating whether the operation succeeded. IMPORTANT: Beware that changing an allowance with this method brings the risk that someone may use both the old and the new allowance by unfortunate transaction ordering. One possible solution to mitigate this race condition is to first reduce the spender's allowance to 0 and set the desired value afterwards: https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 Emits an {Approval} event.\"},\"balanceOf(address)\":{\"details\":\"Returns the value of tokens owned by `account`.\"},\"totalSupply()\":{\"details\":\"Returns the value of tokens in existence.\"},\"transfer(address,uint256)\":{\"details\":\"Moves a `value` amount of tokens from the caller's account to `to`. Returns a boolean value indicating whether the operation succeeded. Emits a {Transfer} event.\"},\"transferFrom(address,address,uint256)\":{\"details\":\"Moves a `value` amount of tokens from `from` to `to` using the allowance mechanism. `value` is then deducted from the caller's allowance. Returns a boolean value indicating whether the operation succeeded. Emits a {Transfer} event.\"}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeV2.sol\":\"IERC20\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeV2.sol\":{\"keccak256\":\"0xfd916c030b1ffca5a136817827b8018c8ba42ca089905747f3de6148b73eb35e\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://18e6438c4096deb8ae453fb3365ba2b07d52944e93c08288fc5d012b71bf6bb3\",\"dweb:/ipfs/QmfEMqpT1zz6RRm7UuHLRowe1tds2cTGLrVonfm9XSCACj\"]}},\"version\":1}"},"hashes":{"allowance(address,address)":"dd62ed3e","approve(address,uint256)":"095ea7b3","balanceOf(address)":"70a08231","totalSupply()":"18160ddd","transfer(address,uint256)":"a9059cbb","transferFrom(address,address,uint256)":"23b872dd"}},"solidity/FastBridgeV2.sol:IERC20Permit":{"code":"0x","runtime-code":"0x","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.24 ^0.8.0 ^0.8.20;\n\n// contracts/interfaces/IAdmin.sol\n\ninterface IAdmin {\n // ============ Events ============\n\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n event ChainGasAmountUpdated(uint256 oldChainGasAmount, uint256 newChainGasAmount);\n\n // ============ Methods ============\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n\n function setChainGasAmount(uint256 newChainGasAmount) external;\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IFastBridgeRecipient.sol\n\ninterface IFastBridgeRecipient {\n function fastBridgeTransferReceived(\n address token,\n uint256 amount,\n bytes memory callParams\n )\n external\n payable\n returns (bytes4);\n}\n\n// contracts/interfaces/IFastBridgeV2Errors.sol\n\ninterface IFastBridgeV2Errors {\n error AmountIncorrect();\n error CallParamsLengthAboveMax();\n error ChainIncorrect();\n error ExclusivityParamsIncorrect();\n error MsgValueIncorrect();\n error NativeTokenCallValueNotSupported();\n error SenderIncorrect();\n error StatusIncorrect();\n error ZeroAddress();\n\n error RecipientIncorrectReturnValue();\n error RecipientNoReturnValue();\n\n error DeadlineExceeded();\n error DeadlineNotExceeded();\n error DeadlineTooShort();\n error DisputePeriodNotPassed();\n error DisputePeriodPassed();\n error ExclusivityPeriodNotPassed();\n\n error TransactionRelayed();\n}\n\n// contracts/libs/Errors.sol\n\nerror DeadlineExceeded();\nerror DeadlineNotExceeded();\nerror DeadlineTooShort();\nerror InsufficientOutputAmount();\n\nerror MsgValueIncorrect();\nerror PoolNotFound();\nerror TokenAddressMismatch();\nerror TokenNotContract();\nerror TokenNotETH();\nerror TokensIdentical();\n\nerror ChainIncorrect();\nerror AmountIncorrect();\nerror ZeroAddress();\n\nerror DisputePeriodNotPassed();\nerror DisputePeriodPassed();\nerror SenderIncorrect();\nerror StatusIncorrect();\nerror TransactionIdIncorrect();\nerror TransactionRelayed();\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// contracts/interfaces/IFastBridgeV2.sol\n\ninterface IFastBridgeV2 is IFastBridge {\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n struct BridgeTxDetails {\n BridgeStatus status;\n uint40 proofBlockTimestamp;\n uint48 proofBlockNumber;\n address proofRelayer;\n }\n\n struct BridgeRelay {\n uint48 blockNumber;\n uint48 blockTimestamp;\n address relayer;\n }\n\n /// @notice New params introduced in the FastBridgeV2.\n /// We are passing fields from the older BridgeParams struct outside of this struct\n /// for backwards compatibility.\n /// Note: quoteRelayer and quoteExclusivitySeconds are either both zero (indicating no exclusivity)\n /// or both non-zero (indicating exclusivity for the given period).\n /// Note: callValue \u003e 0 can NOT be used with destToken = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE (ETH_ADDRESS)\n /// @param quoteRelayer Relayer that provided the quote for the transaction\n /// @param quoteExclusivitySeconds Period of time the quote relayer is guaranteed exclusivity after user's deposit\n /// @param quoteId Unique quote identifier used for tracking the quote\n /// @param callValue ETH value to send to the recipient (if any)\n /// @param callParams Parameters for the arbitrary call to the destination recipient (if any)\n struct BridgeParamsV2 {\n address quoteRelayer;\n int256 quoteExclusivitySeconds;\n bytes quoteId;\n uint256 callValue;\n bytes callParams;\n }\n\n /// @notice Updated bridge transaction struct to include parameters introduced in FastBridgeV2.\n /// Note: only `exclusivityRelayer` can fill such a transaction until `exclusivityEndTime`.\n /// TODO: consider changing the encoding scheme to prevent spending extra gas on decoding.\n struct BridgeTransactionV2 {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n uint256 callValue; // ETH value to send to the recipient (if any) - replaces V1's sendChainGas flag\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n address exclusivityRelayer;\n uint256 exclusivityEndTime;\n bytes callParams;\n }\n\n event BridgeQuoteDetails(bytes32 indexed transactionId, bytes quoteId);\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability\n /// to provide temporary exclusivity fill rights for the quote relayer.\n /// @param params The parameters required to bridge\n /// @param paramsV2 The parameters for exclusivity fill rights (optional, can be left empty)\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function relay(bytes memory request, address relayer) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param transactionId The transaction id associated with the encoded bridge transaction to prove\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital.\n /// @notice Can only send funds to the relayer address on the proof.\n /// @param request The encoded bridge transaction to claim on origin chain\n function claim(bytes memory request) external;\n /// @notice Checks if a transaction has been relayed\n /// @param transactionId The ID of the transaction to check\n /// @return True if the transaction has been relayed, false otherwise\n function bridgeRelays(bytes32 transactionId) external view returns (bool);\n\n /// @notice Returns the status of a bridge transaction\n /// @param transactionId The ID of the bridge transaction\n /// @return BridgeStatus Status of the bridge transaction\n function bridgeStatuses(bytes32 transactionId) external view returns (BridgeStatus);\n\n /// @notice Returns the timestamp and relayer of a bridge proof\n /// @param transactionId The ID of the bridge transaction\n /// @return timestamp The timestamp of the bridge proof\n /// @return relayer The relayer address of the bridge proof\n function bridgeProofs(bytes32 transactionId) external view returns (uint96 timestamp, address relayer);\n\n /// @notice Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\n /// @param request The bridge request to decode\n function getBridgeTransactionV2(bytes memory request) external view returns (BridgeTransactionV2 memory);\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// contracts/libs/UniversalToken.sol\n\nlibrary UniversalTokenLib {\n using SafeERC20 for IERC20;\n\n address internal constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Transfers tokens to the given account. Reverts if transfer is not successful.\n /// @dev This might trigger fallback, if ETH is transferred to the contract.\n /// Make sure this can not lead to reentrancy attacks.\n function universalTransfer(address token, address to, uint256 value) internal {\n // Don't do anything, if need to send tokens to this address\n if (to == address(this)) return;\n // Don't do anything, if trying to send zero value\n if (value == 0) return;\n if (token == ETH_ADDRESS) {\n /// @dev Note: this can potentially lead to executing code in `to`.\n // solhint-disable-next-line avoid-low-level-calls\n (bool success,) = to.call{value: value}(\"\");\n require(success, \"ETH transfer failed\");\n } else {\n IERC20(token).safeTransfer(to, value);\n }\n }\n\n /// @notice Issues an infinite allowance to the spender, if the current allowance is insufficient\n /// to spend the given amount.\n function universalApproveInfinity(address token, address spender, uint256 amountToSpend) internal {\n // ETH Chad doesn't require your approval\n if (token == ETH_ADDRESS) return;\n // No-op if allowance is already sufficient\n uint256 allowance = IERC20(token).allowance(address(this), spender);\n if (allowance \u003e= amountToSpend) return;\n // Otherwise, reset approval to 0 and set to max allowance\n if (allowance \u003e 0) IERC20(token).safeDecreaseAllowance(spender, allowance);\n IERC20(token).safeIncreaseAllowance(spender, type(uint256).max);\n }\n\n /// @notice Returns the balance of the given token (or native ETH) for the given account.\n function universalBalanceOf(address token, address account) internal view returns (uint256) {\n if (token == ETH_ADDRESS) {\n return account.balance;\n } else {\n return IERC20(token).balanceOf(account);\n }\n }\n\n /// @dev Checks that token is a contract and not ETH_ADDRESS.\n function assertIsContract(address token) internal view {\n // Check that ETH_ADDRESS was not used (in case this is a predeploy on any of the chains)\n if (token == UniversalTokenLib.ETH_ADDRESS) revert TokenNotContract();\n // Check that token is not an EOA\n if (token.code.length == 0) revert TokenNotContract();\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/Admin.sol\n\ncontract Admin is IAdmin, AccessControlEnumerable {\n using UniversalTokenLib for address;\n\n bytes32 public constant RELAYER_ROLE = keccak256(\"RELAYER_ROLE\");\n bytes32 public constant REFUNDER_ROLE = keccak256(\"REFUNDER_ROLE\");\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n uint256 public constant FEE_BPS = 1e6;\n uint256 public constant FEE_RATE_MAX = 0.01e6; // max 1% on origin amount\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Chain gas amount to forward as rebate if requested\n uint256 public chainGasAmount;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n }\n\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n require(newFeeRate \u003c= FEE_RATE_MAX, \"newFeeRate \u003e max\");\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n token.universalTransfer(recipient, feeAmount);\n emit FeesSwept(token, recipient, feeAmount);\n }\n\n function setChainGasAmount(uint256 newChainGasAmount) external onlyRole(GOVERNOR_ROLE) {\n uint256 oldChainGasAmount = chainGasAmount;\n chainGasAmount = newChainGasAmount;\n emit ChainGasAmountUpdated(oldChainGasAmount, newChainGasAmount);\n }\n}\n\n// contracts/FastBridgeV2.sol\n\n/// @notice FastBridgeV2 is a contract for bridging tokens across chains.\ncontract FastBridgeV2 is Admin, IFastBridgeV2, IFastBridgeV2Errors {\n using SafeERC20 for IERC20;\n using UniversalTokenLib for address;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Delay for a transaction after which it could be permisionlessly refunded\n uint256 public constant REFUND_DELAY = 7 days;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n /// @notice Maximum length of accepted callParams\n uint256 public constant MAX_CALL_PARAMS_LENGTH = 2 ** 16 - 1;\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeTxDetails) public bridgeTxDetails;\n /// @notice Relay details on destination chain\n mapping(bytes32 =\u003e BridgeRelay) public bridgeRelayDetails;\n /// @notice Unique bridge nonces tracked per originSender\n mapping(address =\u003e uint256) public senderNonces;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Replaced by senderNonces\n uint256 public immutable nonce = 0;\n /// @notice the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n bridge({\n params: params,\n paramsV2: BridgeParamsV2({\n quoteRelayer: address(0),\n quoteExclusivitySeconds: 0,\n quoteId: bytes(\"\"),\n callValue: 0,\n callParams: bytes(\"\")\n })\n });\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes memory request) external payable {\n relay({request: request, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes memory request, bytes32 destTxHash) external {\n prove({transactionId: keccak256(request), destTxHash: destTxHash, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridgeV2\n function claim(bytes memory request) external {\n claim({request: request, to: address(0)});\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003e DISPUTE_PERIOD) {\n revert DisputePeriodPassed();\n }\n\n // @dev relayer gets slashed effectively if dest relay has gone thru\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n bridgeTxDetails[transactionId].proofRelayer = address(0);\n bridgeTxDetails[transactionId].proofBlockTimestamp = 0;\n bridgeTxDetails[transactionId].proofBlockNumber = 0;\n\n emit BridgeProofDisputed(transactionId, msg.sender);\n }\n\n /// @inheritdoc IFastBridge\n function refund(bytes memory request) external {\n bytes32 transactionId = keccak256(request);\n\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n\n if (bridgeTxDetails[transactionId].status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n\n if (hasRole(REFUNDER_ROLE, msg.sender)) {\n // Refunder can refund if deadline has passed\n if (block.timestamp \u003c= transaction.deadline) revert DeadlineNotExceeded();\n } else {\n // Permissionless refund is allowed after REFUND_DELAY\n if (block.timestamp \u003c= transaction.deadline + REFUND_DELAY) revert DeadlineNotExceeded();\n }\n\n // if all checks passed, set to REFUNDED status\n bridgeTxDetails[transactionId].status = BridgeStatus.REFUNDED;\n\n // transfer origin collateral back to original sender\n address to = transaction.originSender;\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount + transaction.originFeeAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (bridgeTxDetails[transactionId].proofRelayer != relayer) revert SenderIncorrect();\n return _timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n /// @dev This method is added to achieve backwards compatibility with decoding requests into V1 structs:\n /// - `callValue` is partially reported as a zero/non-zero flag\n /// - `callParams` is ignored\n /// In order to process all kinds of requests use getBridgeTransactionV2 instead.\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory) {\n // Try decoding into V2 struct first. This will revert if V1 struct is passed\n try this.getBridgeTransactionV2(request) returns (BridgeTransactionV2 memory txV2) {\n // Note: we entirely ignore the callParams field, as it was not present in V1\n return BridgeTransaction({\n originChainId: txV2.originChainId,\n destChainId: txV2.destChainId,\n originSender: txV2.originSender,\n destRecipient: txV2.destRecipient,\n originToken: txV2.originToken,\n destToken: txV2.destToken,\n originAmount: txV2.originAmount,\n destAmount: txV2.destAmount,\n originFeeAmount: txV2.originFeeAmount,\n sendChainGas: txV2.callValue != 0,\n deadline: txV2.deadline,\n nonce: txV2.nonce\n });\n } catch {\n // Fallback to V1 struct\n return abi.decode(request, (BridgeTransaction));\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) public payable {\n int256 exclusivityEndTime = int256(block.timestamp) + paramsV2.quoteExclusivitySeconds;\n _validateBridgeParams(params, paramsV2, exclusivityEndTime);\n\n // transfer tokens to bridge contract\n /// @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _takeBridgedUserAsset(params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n\n // set status to requested\n bytes memory request = abi.encode(\n BridgeTransactionV2({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n callValue: paramsV2.callValue,\n deadline: params.deadline,\n nonce: senderNonces[params.sender]++, // increment nonce on every bridge\n exclusivityRelayer: paramsV2.quoteRelayer,\n // We checked exclusivityEndTime to be in range (0 .. params.deadline] above, so can safely cast\n exclusivityEndTime: uint256(exclusivityEndTime),\n callParams: paramsV2.callParams\n })\n );\n bytes32 transactionId = keccak256(request);\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n\n emit BridgeRequested({\n transactionId: transactionId,\n sender: params.sender,\n request: request,\n destChainId: params.dstChainId,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n sendChainGas: paramsV2.callValue != 0\n });\n emit BridgeQuoteDetails(transactionId, paramsV2.quoteId);\n }\n\n /// @inheritdoc IFastBridgeV2\n function relay(bytes memory request, address relayer) public payable {\n bytes32 transactionId = keccak256(request);\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n _validateRelayParams(transaction, transactionId, relayer);\n // mark bridge transaction as relayed\n bridgeRelayDetails[transactionId] =\n BridgeRelay({blockNumber: uint48(block.number), blockTimestamp: uint48(block.timestamp), relayer: relayer});\n\n // transfer tokens to recipient on destination chain and do an arbitrary call if requested\n address to = transaction.destRecipient;\n address token = transaction.destToken;\n uint256 amount = transaction.destAmount;\n uint256 callValue = transaction.callValue;\n\n // Emit the event before any external calls\n emit BridgeRelayed({\n transactionId: transactionId,\n relayer: relayer,\n to: to,\n originChainId: transaction.originChainId,\n originToken: transaction.originToken,\n destToken: token,\n originAmount: transaction.originAmount,\n destAmount: amount,\n chainGasAmount: callValue\n });\n\n // All state changes have been done at this point, can proceed to the external calls.\n // This follows the checks-effects-interactions pattern to mitigate potential reentrancy attacks.\n if (token == UniversalTokenLib.ETH_ADDRESS) {\n // For ETH non-zero callValue is not allowed\n if (callValue != 0) revert NativeTokenCallValueNotSupported();\n // Check that the correct msg.value was sent\n if (msg.value != amount) revert MsgValueIncorrect();\n } else {\n // For ERC20s, we check that the correct msg.value was sent\n if (msg.value != callValue) revert MsgValueIncorrect();\n // We need to transfer the tokens from the Relayer to the recipient first before performing an\n // optional post-transfer arbitrary call.\n IERC20(token).safeTransferFrom(msg.sender, to, amount);\n }\n\n if (transaction.callParams.length != 0) {\n // Arbitrary call requested, perform it while supplying full msg.value to the recipient\n // Note: if token has a fee on transfers, the recipient will have received less than `amount`.\n // This is a very niche edge case and should be handled by the recipient contract.\n _checkedCallRecipient({recipient: to, token: token, amount: amount, callParams: transaction.callParams});\n } else if (msg.value != 0) {\n // No arbitrary call requested, but msg.value was sent. This is either a relay with ETH,\n // or a non-zero callValue request with an ERC20. In both cases, transfer the ETH to the recipient.\n Address.sendValue(payable(to), msg.value);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) public onlyRole(RELAYER_ROLE) {\n // update bridge tx status given proof provided\n if (bridgeTxDetails[transactionId].status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n bridgeTxDetails[transactionId].status = BridgeStatus.RELAYER_PROVED;\n bridgeTxDetails[transactionId].proofBlockTimestamp = uint40(block.timestamp);\n bridgeTxDetails[transactionId].proofBlockNumber = uint48(block.number);\n bridgeTxDetails[transactionId].proofRelayer = relayer;\n\n emit BridgeProofProvided(transactionId, relayer, destTxHash);\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes memory request, address to) public {\n bytes32 transactionId = keccak256(request);\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n\n // update bridge tx status if able to claim origin collateral\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n\n // if \"to\" is zero addr, permissionlessly send funds to proven relayer\n if (to == address(0)) {\n to = bridgeTxDetails[transactionId].proofRelayer;\n } else if (bridgeTxDetails[transactionId].proofRelayer != msg.sender) {\n revert SenderIncorrect();\n }\n\n if (_timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003c= DISPUTE_PERIOD) {\n revert DisputePeriodNotPassed();\n }\n\n bridgeTxDetails[transactionId].status = BridgeStatus.RELAYER_CLAIMED;\n\n // update protocol fees if origin fee amount exists\n if (transaction.originFeeAmount \u003e 0) protocolFees[transaction.originToken] += transaction.originFeeAmount;\n\n // transfer origin collateral less fee to specified address\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositClaimed(transactionId, bridgeTxDetails[transactionId].proofRelayer, to, token, amount);\n }\n\n function bridgeStatuses(bytes32 transactionId) public view returns (BridgeStatus status) {\n return bridgeTxDetails[transactionId].status;\n }\n\n function bridgeProofs(bytes32 transactionId) public view returns (uint96 timestamp, address relayer) {\n timestamp = bridgeTxDetails[transactionId].proofBlockTimestamp;\n relayer = bridgeTxDetails[transactionId].proofRelayer;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeRelays(bytes32 transactionId) public view returns (bool) {\n // has this transactionId been relayed?\n return bridgeRelayDetails[transactionId].relayer != address(0);\n }\n\n /// @inheritdoc IFastBridgeV2\n function getBridgeTransactionV2(bytes memory request) public pure returns (BridgeTransactionV2 memory) {\n return abi.decode(request, (BridgeTransactionV2));\n }\n\n /// @notice Takes the bridged asset from the user into FastBridgeV2 custody. It will be later\n /// claimed by the relayer who completed the relay on destination chain, or refunded back to the user,\n /// should no one complete the relay.\n function _takeBridgedUserAsset(address token, uint256 amount) internal returns (uint256 amountTaken) {\n if (token == UniversalTokenLib.ETH_ADDRESS) {\n // For ETH we just need to check that the supplied msg.value is correct.\n // Supplied `msg.value` is already in FastBridgeV2 custody.\n if (amount != msg.value) revert MsgValueIncorrect();\n amountTaken = msg.value;\n } else {\n // For ERC20s, token is explicitly transferred from the user to FastBridgeV2.\n // We don't allow non-zero `msg.value` to avoid extra funds from being stuck in FastBridgeV2.\n token.assertIsContract();\n if (msg.value != 0) revert MsgValueIncorrect();\n amountTaken = IERC20(token).balanceOf(address(this));\n IERC20(token).safeTransferFrom(msg.sender, address(this), amount);\n // Use the balance difference as the amount taken in case of fee on transfer tokens.\n amountTaken = IERC20(token).balanceOf(address(this)) - amountTaken;\n }\n }\n\n /// @notice Calls the Recipient's hook function with the specified callParams and performs\n /// all the necessary checks for the returned value.\n function _checkedCallRecipient(\n address recipient,\n address token,\n uint256 amount,\n bytes memory callParams\n )\n internal\n {\n bytes memory hookData =\n abi.encodeCall(IFastBridgeRecipient.fastBridgeTransferReceived, (token, amount, callParams));\n // This will bubble any revert messages from the hook function\n bytes memory returnData = Address.functionCallWithValue({target: recipient, data: hookData, value: msg.value});\n // Explicit revert if no return data at all\n if (returnData.length == 0) revert RecipientNoReturnValue();\n // Check that exactly a single return value was returned\n if (returnData.length != 32) revert RecipientIncorrectReturnValue();\n // Return value should be abi-encoded hook function selector\n if (bytes32(returnData) != bytes32(IFastBridgeRecipient.fastBridgeTransferReceived.selector)) {\n revert RecipientIncorrectReturnValue();\n }\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint40(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint40).max but\n /// proof.timestamp \u003c type(uint40).max via unchecked statement\n /// @param proofBlockTimestamp The bridge proof block timestamp\n /// @return delta Time delta since proof submitted\n function _timeSince(uint40 proofBlockTimestamp) internal view returns (uint256 delta) {\n unchecked {\n delta = uint40(block.timestamp) - proofBlockTimestamp;\n }\n }\n\n /// @notice Performs all the necessary checks for a bridge to happen.\n /// @dev There's no good way to refactor this function to reduce cyclomatic complexity due to\n /// the number of checks that need to be performed, so we skip the code-complexity rule here.\n // solhint-disable-next-line code-complexity\n function _validateBridgeParams(\n BridgeParams memory params,\n BridgeParamsV2 memory paramsV2,\n int256 exclusivityEndTime\n )\n internal\n view\n {\n // Check V1 (legacy) params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.sender == address(0) || params.to == address(0)) revert ZeroAddress();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n // Check V2 params\n if (paramsV2.callParams.length \u003e MAX_CALL_PARAMS_LENGTH) revert CallParamsLengthAboveMax();\n if (paramsV2.callValue != 0 \u0026\u0026 params.destToken == UniversalTokenLib.ETH_ADDRESS) {\n revert NativeTokenCallValueNotSupported();\n }\n // exclusivityEndTime must be in range (0 .. params.deadline]\n if (exclusivityEndTime \u003c= 0 || exclusivityEndTime \u003e int256(params.deadline)) {\n revert ExclusivityParamsIncorrect();\n }\n }\n\n /// @notice Performs all the necessary checks for a relay to happen.\n function _validateRelayParams(\n BridgeTransactionV2 memory transaction,\n bytes32 transactionId,\n address relayer\n )\n internal\n view\n {\n if (relayer == address(0)) revert ZeroAddress();\n // Check if the transaction has already been relayed\n if (bridgeRelays(transactionId)) revert TransactionRelayed();\n if (transaction.destChainId != block.chainid) revert ChainIncorrect();\n // Check the deadline for relay to happen\n if (block.timestamp \u003e transaction.deadline) revert DeadlineExceeded();\n // Check the exclusivity period, if it is still ongoing\n // forgefmt: disable-next-item\n if (\n transaction.exclusivityRelayer != address(0) \u0026\u0026\n transaction.exclusivityRelayer != relayer \u0026\u0026\n block.timestamp \u003c= transaction.exclusivityEndTime\n ) {\n revert ExclusivityPeriodNotPassed();\n }\n }\n}\n","language":"Solidity","languageVersion":"0.8.24","compilerVersion":"0.8.24","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"","srcMapRuntime":"","abiDefinition":[{"inputs":[],"name":"DOMAIN_SEPARATOR","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"nonces","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"permit","outputs":[],"stateMutability":"nonpayable","type":"function"}],"userDoc":{"kind":"user","methods":{},"version":1},"developerDoc":{"details":"Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in https://eips.ethereum.org/EIPS/eip-2612[EIP-2612]. Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't need to send a transaction, and thus is not required to hold Ether at all. ==== Security Considerations There are two important considerations concerning the use of `permit`. The first is that a valid permit signature expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be considered as an intention to spend the allowance in any specific way. The second is that because permits have built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be generally recommended is: ```solidity function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public { try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {} doThing(..., value); } function doThing(..., uint256 value) public { token.safeTransferFrom(msg.sender, address(this), value); ... } ``` Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also {SafeERC20-safeTransferFrom}). Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so contracts should have entry points that don't rely on permit.","kind":"dev","methods":{"DOMAIN_SEPARATOR()":{"details":"Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}."},"nonces(address)":{"details":"Returns the current nonce for `owner`. This value must be included whenever a signature is generated for {permit}. Every successful call to {permit} increases ``owner``'s nonce by one. This prevents a signature from being used multiple times."},"permit(address,address,uint256,uint256,uint8,bytes32,bytes32)":{"details":"Sets `value` as the allowance of `spender` over ``owner``'s tokens, given ``owner``'s signed approval. IMPORTANT: The same issues {IERC20-approve} has related to transaction ordering also apply here. Emits an {Approval} event. Requirements: - `spender` cannot be the zero address. - `deadline` must be a timestamp in the future. - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner` over the EIP712-formatted function arguments. - the signature must use ``owner``'s current nonce (see {nonces}). For more information on the signature format, see the https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP section]. CAUTION: See Security Considerations above."}},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[],\"name\":\"DOMAIN_SEPARATOR\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"}],\"name\":\"nonces\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"},{\"internalType\":\"uint8\",\"name\":\"v\",\"type\":\"uint8\"},{\"internalType\":\"bytes32\",\"name\":\"r\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"s\",\"type\":\"bytes32\"}],\"name\":\"permit\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"details\":\"Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in https://eips.ethereum.org/EIPS/eip-2612[EIP-2612]. Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't need to send a transaction, and thus is not required to hold Ether at all. ==== Security Considerations There are two important considerations concerning the use of `permit`. The first is that a valid permit signature expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be considered as an intention to spend the allowance in any specific way. The second is that because permits have built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be generally recommended is: ```solidity function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public { try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {} doThing(..., value); } function doThing(..., uint256 value) public { token.safeTransferFrom(msg.sender, address(this), value); ... } ``` Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also {SafeERC20-safeTransferFrom}). Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so contracts should have entry points that don't rely on permit.\",\"kind\":\"dev\",\"methods\":{\"DOMAIN_SEPARATOR()\":{\"details\":\"Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\"},\"nonces(address)\":{\"details\":\"Returns the current nonce for `owner`. This value must be included whenever a signature is generated for {permit}. Every successful call to {permit} increases ``owner``'s nonce by one. This prevents a signature from being used multiple times.\"},\"permit(address,address,uint256,uint256,uint8,bytes32,bytes32)\":{\"details\":\"Sets `value` as the allowance of `spender` over ``owner``'s tokens, given ``owner``'s signed approval. IMPORTANT: The same issues {IERC20-approve} has related to transaction ordering also apply here. Emits an {Approval} event. Requirements: - `spender` cannot be the zero address. - `deadline` must be a timestamp in the future. - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner` over the EIP712-formatted function arguments. - the signature must use ``owner``'s current nonce (see {nonces}). For more information on the signature format, see the https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP section]. CAUTION: See Security Considerations above.\"}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeV2.sol\":\"IERC20Permit\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeV2.sol\":{\"keccak256\":\"0xfd916c030b1ffca5a136817827b8018c8ba42ca089905747f3de6148b73eb35e\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://18e6438c4096deb8ae453fb3365ba2b07d52944e93c08288fc5d012b71bf6bb3\",\"dweb:/ipfs/QmfEMqpT1zz6RRm7UuHLRowe1tds2cTGLrVonfm9XSCACj\"]}},\"version\":1}"},"hashes":{"DOMAIN_SEPARATOR()":"3644e515","nonces(address)":"7ecebe00","permit(address,address,uint256,uint256,uint8,bytes32,bytes32)":"d505accf"}},"solidity/FastBridgeV2.sol:IFastBridge":{"code":"0x","runtime-code":"0x","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.24 ^0.8.0 ^0.8.20;\n\n// contracts/interfaces/IAdmin.sol\n\ninterface IAdmin {\n // ============ Events ============\n\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n event ChainGasAmountUpdated(uint256 oldChainGasAmount, uint256 newChainGasAmount);\n\n // ============ Methods ============\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n\n function setChainGasAmount(uint256 newChainGasAmount) external;\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IFastBridgeRecipient.sol\n\ninterface IFastBridgeRecipient {\n function fastBridgeTransferReceived(\n address token,\n uint256 amount,\n bytes memory callParams\n )\n external\n payable\n returns (bytes4);\n}\n\n// contracts/interfaces/IFastBridgeV2Errors.sol\n\ninterface IFastBridgeV2Errors {\n error AmountIncorrect();\n error CallParamsLengthAboveMax();\n error ChainIncorrect();\n error ExclusivityParamsIncorrect();\n error MsgValueIncorrect();\n error NativeTokenCallValueNotSupported();\n error SenderIncorrect();\n error StatusIncorrect();\n error ZeroAddress();\n\n error RecipientIncorrectReturnValue();\n error RecipientNoReturnValue();\n\n error DeadlineExceeded();\n error DeadlineNotExceeded();\n error DeadlineTooShort();\n error DisputePeriodNotPassed();\n error DisputePeriodPassed();\n error ExclusivityPeriodNotPassed();\n\n error TransactionRelayed();\n}\n\n// contracts/libs/Errors.sol\n\nerror DeadlineExceeded();\nerror DeadlineNotExceeded();\nerror DeadlineTooShort();\nerror InsufficientOutputAmount();\n\nerror MsgValueIncorrect();\nerror PoolNotFound();\nerror TokenAddressMismatch();\nerror TokenNotContract();\nerror TokenNotETH();\nerror TokensIdentical();\n\nerror ChainIncorrect();\nerror AmountIncorrect();\nerror ZeroAddress();\n\nerror DisputePeriodNotPassed();\nerror DisputePeriodPassed();\nerror SenderIncorrect();\nerror StatusIncorrect();\nerror TransactionIdIncorrect();\nerror TransactionRelayed();\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// contracts/interfaces/IFastBridgeV2.sol\n\ninterface IFastBridgeV2 is IFastBridge {\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n struct BridgeTxDetails {\n BridgeStatus status;\n uint40 proofBlockTimestamp;\n uint48 proofBlockNumber;\n address proofRelayer;\n }\n\n struct BridgeRelay {\n uint48 blockNumber;\n uint48 blockTimestamp;\n address relayer;\n }\n\n /// @notice New params introduced in the FastBridgeV2.\n /// We are passing fields from the older BridgeParams struct outside of this struct\n /// for backwards compatibility.\n /// Note: quoteRelayer and quoteExclusivitySeconds are either both zero (indicating no exclusivity)\n /// or both non-zero (indicating exclusivity for the given period).\n /// Note: callValue \u003e 0 can NOT be used with destToken = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE (ETH_ADDRESS)\n /// @param quoteRelayer Relayer that provided the quote for the transaction\n /// @param quoteExclusivitySeconds Period of time the quote relayer is guaranteed exclusivity after user's deposit\n /// @param quoteId Unique quote identifier used for tracking the quote\n /// @param callValue ETH value to send to the recipient (if any)\n /// @param callParams Parameters for the arbitrary call to the destination recipient (if any)\n struct BridgeParamsV2 {\n address quoteRelayer;\n int256 quoteExclusivitySeconds;\n bytes quoteId;\n uint256 callValue;\n bytes callParams;\n }\n\n /// @notice Updated bridge transaction struct to include parameters introduced in FastBridgeV2.\n /// Note: only `exclusivityRelayer` can fill such a transaction until `exclusivityEndTime`.\n /// TODO: consider changing the encoding scheme to prevent spending extra gas on decoding.\n struct BridgeTransactionV2 {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n uint256 callValue; // ETH value to send to the recipient (if any) - replaces V1's sendChainGas flag\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n address exclusivityRelayer;\n uint256 exclusivityEndTime;\n bytes callParams;\n }\n\n event BridgeQuoteDetails(bytes32 indexed transactionId, bytes quoteId);\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability\n /// to provide temporary exclusivity fill rights for the quote relayer.\n /// @param params The parameters required to bridge\n /// @param paramsV2 The parameters for exclusivity fill rights (optional, can be left empty)\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function relay(bytes memory request, address relayer) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param transactionId The transaction id associated with the encoded bridge transaction to prove\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital.\n /// @notice Can only send funds to the relayer address on the proof.\n /// @param request The encoded bridge transaction to claim on origin chain\n function claim(bytes memory request) external;\n /// @notice Checks if a transaction has been relayed\n /// @param transactionId The ID of the transaction to check\n /// @return True if the transaction has been relayed, false otherwise\n function bridgeRelays(bytes32 transactionId) external view returns (bool);\n\n /// @notice Returns the status of a bridge transaction\n /// @param transactionId The ID of the bridge transaction\n /// @return BridgeStatus Status of the bridge transaction\n function bridgeStatuses(bytes32 transactionId) external view returns (BridgeStatus);\n\n /// @notice Returns the timestamp and relayer of a bridge proof\n /// @param transactionId The ID of the bridge transaction\n /// @return timestamp The timestamp of the bridge proof\n /// @return relayer The relayer address of the bridge proof\n function bridgeProofs(bytes32 transactionId) external view returns (uint96 timestamp, address relayer);\n\n /// @notice Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\n /// @param request The bridge request to decode\n function getBridgeTransactionV2(bytes memory request) external view returns (BridgeTransactionV2 memory);\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// contracts/libs/UniversalToken.sol\n\nlibrary UniversalTokenLib {\n using SafeERC20 for IERC20;\n\n address internal constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Transfers tokens to the given account. Reverts if transfer is not successful.\n /// @dev This might trigger fallback, if ETH is transferred to the contract.\n /// Make sure this can not lead to reentrancy attacks.\n function universalTransfer(address token, address to, uint256 value) internal {\n // Don't do anything, if need to send tokens to this address\n if (to == address(this)) return;\n // Don't do anything, if trying to send zero value\n if (value == 0) return;\n if (token == ETH_ADDRESS) {\n /// @dev Note: this can potentially lead to executing code in `to`.\n // solhint-disable-next-line avoid-low-level-calls\n (bool success,) = to.call{value: value}(\"\");\n require(success, \"ETH transfer failed\");\n } else {\n IERC20(token).safeTransfer(to, value);\n }\n }\n\n /// @notice Issues an infinite allowance to the spender, if the current allowance is insufficient\n /// to spend the given amount.\n function universalApproveInfinity(address token, address spender, uint256 amountToSpend) internal {\n // ETH Chad doesn't require your approval\n if (token == ETH_ADDRESS) return;\n // No-op if allowance is already sufficient\n uint256 allowance = IERC20(token).allowance(address(this), spender);\n if (allowance \u003e= amountToSpend) return;\n // Otherwise, reset approval to 0 and set to max allowance\n if (allowance \u003e 0) IERC20(token).safeDecreaseAllowance(spender, allowance);\n IERC20(token).safeIncreaseAllowance(spender, type(uint256).max);\n }\n\n /// @notice Returns the balance of the given token (or native ETH) for the given account.\n function universalBalanceOf(address token, address account) internal view returns (uint256) {\n if (token == ETH_ADDRESS) {\n return account.balance;\n } else {\n return IERC20(token).balanceOf(account);\n }\n }\n\n /// @dev Checks that token is a contract and not ETH_ADDRESS.\n function assertIsContract(address token) internal view {\n // Check that ETH_ADDRESS was not used (in case this is a predeploy on any of the chains)\n if (token == UniversalTokenLib.ETH_ADDRESS) revert TokenNotContract();\n // Check that token is not an EOA\n if (token.code.length == 0) revert TokenNotContract();\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/Admin.sol\n\ncontract Admin is IAdmin, AccessControlEnumerable {\n using UniversalTokenLib for address;\n\n bytes32 public constant RELAYER_ROLE = keccak256(\"RELAYER_ROLE\");\n bytes32 public constant REFUNDER_ROLE = keccak256(\"REFUNDER_ROLE\");\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n uint256 public constant FEE_BPS = 1e6;\n uint256 public constant FEE_RATE_MAX = 0.01e6; // max 1% on origin amount\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Chain gas amount to forward as rebate if requested\n uint256 public chainGasAmount;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n }\n\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n require(newFeeRate \u003c= FEE_RATE_MAX, \"newFeeRate \u003e max\");\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n token.universalTransfer(recipient, feeAmount);\n emit FeesSwept(token, recipient, feeAmount);\n }\n\n function setChainGasAmount(uint256 newChainGasAmount) external onlyRole(GOVERNOR_ROLE) {\n uint256 oldChainGasAmount = chainGasAmount;\n chainGasAmount = newChainGasAmount;\n emit ChainGasAmountUpdated(oldChainGasAmount, newChainGasAmount);\n }\n}\n\n// contracts/FastBridgeV2.sol\n\n/// @notice FastBridgeV2 is a contract for bridging tokens across chains.\ncontract FastBridgeV2 is Admin, IFastBridgeV2, IFastBridgeV2Errors {\n using SafeERC20 for IERC20;\n using UniversalTokenLib for address;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Delay for a transaction after which it could be permisionlessly refunded\n uint256 public constant REFUND_DELAY = 7 days;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n /// @notice Maximum length of accepted callParams\n uint256 public constant MAX_CALL_PARAMS_LENGTH = 2 ** 16 - 1;\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeTxDetails) public bridgeTxDetails;\n /// @notice Relay details on destination chain\n mapping(bytes32 =\u003e BridgeRelay) public bridgeRelayDetails;\n /// @notice Unique bridge nonces tracked per originSender\n mapping(address =\u003e uint256) public senderNonces;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Replaced by senderNonces\n uint256 public immutable nonce = 0;\n /// @notice the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n bridge({\n params: params,\n paramsV2: BridgeParamsV2({\n quoteRelayer: address(0),\n quoteExclusivitySeconds: 0,\n quoteId: bytes(\"\"),\n callValue: 0,\n callParams: bytes(\"\")\n })\n });\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes memory request) external payable {\n relay({request: request, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes memory request, bytes32 destTxHash) external {\n prove({transactionId: keccak256(request), destTxHash: destTxHash, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridgeV2\n function claim(bytes memory request) external {\n claim({request: request, to: address(0)});\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003e DISPUTE_PERIOD) {\n revert DisputePeriodPassed();\n }\n\n // @dev relayer gets slashed effectively if dest relay has gone thru\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n bridgeTxDetails[transactionId].proofRelayer = address(0);\n bridgeTxDetails[transactionId].proofBlockTimestamp = 0;\n bridgeTxDetails[transactionId].proofBlockNumber = 0;\n\n emit BridgeProofDisputed(transactionId, msg.sender);\n }\n\n /// @inheritdoc IFastBridge\n function refund(bytes memory request) external {\n bytes32 transactionId = keccak256(request);\n\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n\n if (bridgeTxDetails[transactionId].status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n\n if (hasRole(REFUNDER_ROLE, msg.sender)) {\n // Refunder can refund if deadline has passed\n if (block.timestamp \u003c= transaction.deadline) revert DeadlineNotExceeded();\n } else {\n // Permissionless refund is allowed after REFUND_DELAY\n if (block.timestamp \u003c= transaction.deadline + REFUND_DELAY) revert DeadlineNotExceeded();\n }\n\n // if all checks passed, set to REFUNDED status\n bridgeTxDetails[transactionId].status = BridgeStatus.REFUNDED;\n\n // transfer origin collateral back to original sender\n address to = transaction.originSender;\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount + transaction.originFeeAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (bridgeTxDetails[transactionId].proofRelayer != relayer) revert SenderIncorrect();\n return _timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n /// @dev This method is added to achieve backwards compatibility with decoding requests into V1 structs:\n /// - `callValue` is partially reported as a zero/non-zero flag\n /// - `callParams` is ignored\n /// In order to process all kinds of requests use getBridgeTransactionV2 instead.\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory) {\n // Try decoding into V2 struct first. This will revert if V1 struct is passed\n try this.getBridgeTransactionV2(request) returns (BridgeTransactionV2 memory txV2) {\n // Note: we entirely ignore the callParams field, as it was not present in V1\n return BridgeTransaction({\n originChainId: txV2.originChainId,\n destChainId: txV2.destChainId,\n originSender: txV2.originSender,\n destRecipient: txV2.destRecipient,\n originToken: txV2.originToken,\n destToken: txV2.destToken,\n originAmount: txV2.originAmount,\n destAmount: txV2.destAmount,\n originFeeAmount: txV2.originFeeAmount,\n sendChainGas: txV2.callValue != 0,\n deadline: txV2.deadline,\n nonce: txV2.nonce\n });\n } catch {\n // Fallback to V1 struct\n return abi.decode(request, (BridgeTransaction));\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) public payable {\n int256 exclusivityEndTime = int256(block.timestamp) + paramsV2.quoteExclusivitySeconds;\n _validateBridgeParams(params, paramsV2, exclusivityEndTime);\n\n // transfer tokens to bridge contract\n /// @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _takeBridgedUserAsset(params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n\n // set status to requested\n bytes memory request = abi.encode(\n BridgeTransactionV2({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n callValue: paramsV2.callValue,\n deadline: params.deadline,\n nonce: senderNonces[params.sender]++, // increment nonce on every bridge\n exclusivityRelayer: paramsV2.quoteRelayer,\n // We checked exclusivityEndTime to be in range (0 .. params.deadline] above, so can safely cast\n exclusivityEndTime: uint256(exclusivityEndTime),\n callParams: paramsV2.callParams\n })\n );\n bytes32 transactionId = keccak256(request);\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n\n emit BridgeRequested({\n transactionId: transactionId,\n sender: params.sender,\n request: request,\n destChainId: params.dstChainId,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n sendChainGas: paramsV2.callValue != 0\n });\n emit BridgeQuoteDetails(transactionId, paramsV2.quoteId);\n }\n\n /// @inheritdoc IFastBridgeV2\n function relay(bytes memory request, address relayer) public payable {\n bytes32 transactionId = keccak256(request);\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n _validateRelayParams(transaction, transactionId, relayer);\n // mark bridge transaction as relayed\n bridgeRelayDetails[transactionId] =\n BridgeRelay({blockNumber: uint48(block.number), blockTimestamp: uint48(block.timestamp), relayer: relayer});\n\n // transfer tokens to recipient on destination chain and do an arbitrary call if requested\n address to = transaction.destRecipient;\n address token = transaction.destToken;\n uint256 amount = transaction.destAmount;\n uint256 callValue = transaction.callValue;\n\n // Emit the event before any external calls\n emit BridgeRelayed({\n transactionId: transactionId,\n relayer: relayer,\n to: to,\n originChainId: transaction.originChainId,\n originToken: transaction.originToken,\n destToken: token,\n originAmount: transaction.originAmount,\n destAmount: amount,\n chainGasAmount: callValue\n });\n\n // All state changes have been done at this point, can proceed to the external calls.\n // This follows the checks-effects-interactions pattern to mitigate potential reentrancy attacks.\n if (token == UniversalTokenLib.ETH_ADDRESS) {\n // For ETH non-zero callValue is not allowed\n if (callValue != 0) revert NativeTokenCallValueNotSupported();\n // Check that the correct msg.value was sent\n if (msg.value != amount) revert MsgValueIncorrect();\n } else {\n // For ERC20s, we check that the correct msg.value was sent\n if (msg.value != callValue) revert MsgValueIncorrect();\n // We need to transfer the tokens from the Relayer to the recipient first before performing an\n // optional post-transfer arbitrary call.\n IERC20(token).safeTransferFrom(msg.sender, to, amount);\n }\n\n if (transaction.callParams.length != 0) {\n // Arbitrary call requested, perform it while supplying full msg.value to the recipient\n // Note: if token has a fee on transfers, the recipient will have received less than `amount`.\n // This is a very niche edge case and should be handled by the recipient contract.\n _checkedCallRecipient({recipient: to, token: token, amount: amount, callParams: transaction.callParams});\n } else if (msg.value != 0) {\n // No arbitrary call requested, but msg.value was sent. This is either a relay with ETH,\n // or a non-zero callValue request with an ERC20. In both cases, transfer the ETH to the recipient.\n Address.sendValue(payable(to), msg.value);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) public onlyRole(RELAYER_ROLE) {\n // update bridge tx status given proof provided\n if (bridgeTxDetails[transactionId].status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n bridgeTxDetails[transactionId].status = BridgeStatus.RELAYER_PROVED;\n bridgeTxDetails[transactionId].proofBlockTimestamp = uint40(block.timestamp);\n bridgeTxDetails[transactionId].proofBlockNumber = uint48(block.number);\n bridgeTxDetails[transactionId].proofRelayer = relayer;\n\n emit BridgeProofProvided(transactionId, relayer, destTxHash);\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes memory request, address to) public {\n bytes32 transactionId = keccak256(request);\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n\n // update bridge tx status if able to claim origin collateral\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n\n // if \"to\" is zero addr, permissionlessly send funds to proven relayer\n if (to == address(0)) {\n to = bridgeTxDetails[transactionId].proofRelayer;\n } else if (bridgeTxDetails[transactionId].proofRelayer != msg.sender) {\n revert SenderIncorrect();\n }\n\n if (_timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003c= DISPUTE_PERIOD) {\n revert DisputePeriodNotPassed();\n }\n\n bridgeTxDetails[transactionId].status = BridgeStatus.RELAYER_CLAIMED;\n\n // update protocol fees if origin fee amount exists\n if (transaction.originFeeAmount \u003e 0) protocolFees[transaction.originToken] += transaction.originFeeAmount;\n\n // transfer origin collateral less fee to specified address\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositClaimed(transactionId, bridgeTxDetails[transactionId].proofRelayer, to, token, amount);\n }\n\n function bridgeStatuses(bytes32 transactionId) public view returns (BridgeStatus status) {\n return bridgeTxDetails[transactionId].status;\n }\n\n function bridgeProofs(bytes32 transactionId) public view returns (uint96 timestamp, address relayer) {\n timestamp = bridgeTxDetails[transactionId].proofBlockTimestamp;\n relayer = bridgeTxDetails[transactionId].proofRelayer;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeRelays(bytes32 transactionId) public view returns (bool) {\n // has this transactionId been relayed?\n return bridgeRelayDetails[transactionId].relayer != address(0);\n }\n\n /// @inheritdoc IFastBridgeV2\n function getBridgeTransactionV2(bytes memory request) public pure returns (BridgeTransactionV2 memory) {\n return abi.decode(request, (BridgeTransactionV2));\n }\n\n /// @notice Takes the bridged asset from the user into FastBridgeV2 custody. It will be later\n /// claimed by the relayer who completed the relay on destination chain, or refunded back to the user,\n /// should no one complete the relay.\n function _takeBridgedUserAsset(address token, uint256 amount) internal returns (uint256 amountTaken) {\n if (token == UniversalTokenLib.ETH_ADDRESS) {\n // For ETH we just need to check that the supplied msg.value is correct.\n // Supplied `msg.value` is already in FastBridgeV2 custody.\n if (amount != msg.value) revert MsgValueIncorrect();\n amountTaken = msg.value;\n } else {\n // For ERC20s, token is explicitly transferred from the user to FastBridgeV2.\n // We don't allow non-zero `msg.value` to avoid extra funds from being stuck in FastBridgeV2.\n token.assertIsContract();\n if (msg.value != 0) revert MsgValueIncorrect();\n amountTaken = IERC20(token).balanceOf(address(this));\n IERC20(token).safeTransferFrom(msg.sender, address(this), amount);\n // Use the balance difference as the amount taken in case of fee on transfer tokens.\n amountTaken = IERC20(token).balanceOf(address(this)) - amountTaken;\n }\n }\n\n /// @notice Calls the Recipient's hook function with the specified callParams and performs\n /// all the necessary checks for the returned value.\n function _checkedCallRecipient(\n address recipient,\n address token,\n uint256 amount,\n bytes memory callParams\n )\n internal\n {\n bytes memory hookData =\n abi.encodeCall(IFastBridgeRecipient.fastBridgeTransferReceived, (token, amount, callParams));\n // This will bubble any revert messages from the hook function\n bytes memory returnData = Address.functionCallWithValue({target: recipient, data: hookData, value: msg.value});\n // Explicit revert if no return data at all\n if (returnData.length == 0) revert RecipientNoReturnValue();\n // Check that exactly a single return value was returned\n if (returnData.length != 32) revert RecipientIncorrectReturnValue();\n // Return value should be abi-encoded hook function selector\n if (bytes32(returnData) != bytes32(IFastBridgeRecipient.fastBridgeTransferReceived.selector)) {\n revert RecipientIncorrectReturnValue();\n }\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint40(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint40).max but\n /// proof.timestamp \u003c type(uint40).max via unchecked statement\n /// @param proofBlockTimestamp The bridge proof block timestamp\n /// @return delta Time delta since proof submitted\n function _timeSince(uint40 proofBlockTimestamp) internal view returns (uint256 delta) {\n unchecked {\n delta = uint40(block.timestamp) - proofBlockTimestamp;\n }\n }\n\n /// @notice Performs all the necessary checks for a bridge to happen.\n /// @dev There's no good way to refactor this function to reduce cyclomatic complexity due to\n /// the number of checks that need to be performed, so we skip the code-complexity rule here.\n // solhint-disable-next-line code-complexity\n function _validateBridgeParams(\n BridgeParams memory params,\n BridgeParamsV2 memory paramsV2,\n int256 exclusivityEndTime\n )\n internal\n view\n {\n // Check V1 (legacy) params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.sender == address(0) || params.to == address(0)) revert ZeroAddress();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n // Check V2 params\n if (paramsV2.callParams.length \u003e MAX_CALL_PARAMS_LENGTH) revert CallParamsLengthAboveMax();\n if (paramsV2.callValue != 0 \u0026\u0026 params.destToken == UniversalTokenLib.ETH_ADDRESS) {\n revert NativeTokenCallValueNotSupported();\n }\n // exclusivityEndTime must be in range (0 .. params.deadline]\n if (exclusivityEndTime \u003c= 0 || exclusivityEndTime \u003e int256(params.deadline)) {\n revert ExclusivityParamsIncorrect();\n }\n }\n\n /// @notice Performs all the necessary checks for a relay to happen.\n function _validateRelayParams(\n BridgeTransactionV2 memory transaction,\n bytes32 transactionId,\n address relayer\n )\n internal\n view\n {\n if (relayer == address(0)) revert ZeroAddress();\n // Check if the transaction has already been relayed\n if (bridgeRelays(transactionId)) revert TransactionRelayed();\n if (transaction.destChainId != block.chainid) revert ChainIncorrect();\n // Check the deadline for relay to happen\n if (block.timestamp \u003e transaction.deadline) revert DeadlineExceeded();\n // Check the exclusivity period, if it is still ongoing\n // forgefmt: disable-next-item\n if (\n transaction.exclusivityRelayer != address(0) \u0026\u0026\n transaction.exclusivityRelayer != relayer \u0026\u0026\n block.timestamp \u003c= transaction.exclusivityEndTime\n ) {\n revert ExclusivityPeriodNotPassed();\n }\n }\n}\n","language":"Solidity","languageVersion":"0.8.24","compilerVersion":"0.8.24","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"","srcMapRuntime":"","abiDefinition":[{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"relayer","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"BridgeDepositClaimed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"BridgeDepositRefunded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"relayer","type":"address"}],"name":"BridgeProofDisputed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"relayer","type":"address"},{"indexed":false,"internalType":"bytes32","name":"transactionHash","type":"bytes32"}],"name":"BridgeProofProvided","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"relayer","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint32","name":"originChainId","type":"uint32"},{"indexed":false,"internalType":"address","name":"originToken","type":"address"},{"indexed":false,"internalType":"address","name":"destToken","type":"address"},{"indexed":false,"internalType":"uint256","name":"originAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"destAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"chainGasAmount","type":"uint256"}],"name":"BridgeRelayed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"bytes","name":"request","type":"bytes"},{"indexed":false,"internalType":"uint32","name":"destChainId","type":"uint32"},{"indexed":false,"internalType":"address","name":"originToken","type":"address"},{"indexed":false,"internalType":"address","name":"destToken","type":"address"},{"indexed":false,"internalType":"uint256","name":"originAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"destAmount","type":"uint256"},{"indexed":false,"internalType":"bool","name":"sendChainGas","type":"bool"}],"name":"BridgeRequested","type":"event"},{"inputs":[{"components":[{"internalType":"uint32","name":"dstChainId","type":"uint32"},{"internalType":"address","name":"sender","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"address","name":"originToken","type":"address"},{"internalType":"address","name":"destToken","type":"address"},{"internalType":"uint256","name":"originAmount","type":"uint256"},{"internalType":"uint256","name":"destAmount","type":"uint256"},{"internalType":"bool","name":"sendChainGas","type":"bool"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"internalType":"struct IFastBridge.BridgeParams","name":"params","type":"tuple"}],"name":"bridge","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"internalType":"address","name":"relayer","type":"address"}],"name":"canClaim","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"},{"internalType":"address","name":"to","type":"address"}],"name":"claim","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"transactionId","type":"bytes32"}],"name":"dispute","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"}],"name":"getBridgeTransaction","outputs":[{"components":[{"internalType":"uint32","name":"originChainId","type":"uint32"},{"internalType":"uint32","name":"destChainId","type":"uint32"},{"internalType":"address","name":"originSender","type":"address"},{"internalType":"address","name":"destRecipient","type":"address"},{"internalType":"address","name":"originToken","type":"address"},{"internalType":"address","name":"destToken","type":"address"},{"internalType":"uint256","name":"originAmount","type":"uint256"},{"internalType":"uint256","name":"destAmount","type":"uint256"},{"internalType":"uint256","name":"originFeeAmount","type":"uint256"},{"internalType":"bool","name":"sendChainGas","type":"bool"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint256","name":"nonce","type":"uint256"}],"internalType":"struct IFastBridge.BridgeTransaction","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"},{"internalType":"bytes32","name":"destTxHash","type":"bytes32"}],"name":"prove","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"}],"name":"refund","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"}],"name":"relay","outputs":[],"stateMutability":"payable","type":"function"}],"userDoc":{"kind":"user","methods":{"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256))":{"notice":"Initiates bridge on origin chain to be relayed by off-chain relayer"},"canClaim(bytes32,address)":{"notice":"Checks if the dispute period has passed so bridge deposit can be claimed"},"claim(bytes,address)":{"notice":"Completes bridge transaction on origin chain by claiming originally deposited capital"},"dispute(bytes32)":{"notice":"Disputes an outstanding proof in case relayer provided dest chain tx is invalid"},"getBridgeTransaction(bytes)":{"notice":"Decodes bridge request into a bridge transaction"},"prove(bytes,bytes32)":{"notice":"Provides proof on origin side that relayer provided funds on destination side of bridge transaction"},"refund(bytes)":{"notice":"Refunds an outstanding bridge transaction in case optimistic bridging failed"},"relay(bytes)":{"notice":"Relays destination side of bridge transaction by off-chain relayer"}},"version":1},"developerDoc":{"kind":"dev","methods":{"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256))":{"params":{"params":"The parameters required to bridge"}},"canClaim(bytes32,address)":{"params":{"relayer":"The address of the relayer attempting to claim","transactionId":"The transaction id associated with the encoded bridge transaction to check"}},"claim(bytes,address)":{"params":{"request":"The encoded bridge transaction to claim on origin chain","to":"The recipient address of the funds"}},"dispute(bytes32)":{"params":{"transactionId":"The transaction id associated with the encoded bridge transaction to dispute"}},"getBridgeTransaction(bytes)":{"params":{"request":"The bridge request to decode"}},"prove(bytes,bytes32)":{"params":{"destTxHash":"The destination tx hash proving bridge transaction was relayed","request":"The encoded bridge transaction to prove on origin chain"}},"refund(bytes)":{"params":{"request":"The encoded bridge transaction to refund"}},"relay(bytes)":{"params":{"request":"The encoded bridge transaction to relay on destination chain"}}},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"BridgeDepositClaimed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"BridgeDepositRefunded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"name\":\"BridgeProofDisputed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"transactionHash\",\"type\":\"bytes32\"}],\"name\":\"BridgeProofProvided\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"originChainId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"chainGasAmount\",\"type\":\"uint256\"}],\"name\":\"BridgeRelayed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"destChainId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"sendChainGas\",\"type\":\"bool\"}],\"name\":\"BridgeRequested\",\"type\":\"event\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"dstChainId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"sendChainGas\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"}],\"internalType\":\"struct IFastBridge.BridgeParams\",\"name\":\"params\",\"type\":\"tuple\"}],\"name\":\"bridge\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"name\":\"canClaim\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"claim\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"}],\"name\":\"dispute\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"getBridgeTransaction\",\"outputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"originChainId\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"destChainId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"originSender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destRecipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"originFeeAmount\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"sendChainGas\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"}],\"internalType\":\"struct IFastBridge.BridgeTransaction\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"},{\"internalType\":\"bytes32\",\"name\":\"destTxHash\",\"type\":\"bytes32\"}],\"name\":\"prove\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"refund\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"relay\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{\"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256))\":{\"params\":{\"params\":\"The parameters required to bridge\"}},\"canClaim(bytes32,address)\":{\"params\":{\"relayer\":\"The address of the relayer attempting to claim\",\"transactionId\":\"The transaction id associated with the encoded bridge transaction to check\"}},\"claim(bytes,address)\":{\"params\":{\"request\":\"The encoded bridge transaction to claim on origin chain\",\"to\":\"The recipient address of the funds\"}},\"dispute(bytes32)\":{\"params\":{\"transactionId\":\"The transaction id associated with the encoded bridge transaction to dispute\"}},\"getBridgeTransaction(bytes)\":{\"params\":{\"request\":\"The bridge request to decode\"}},\"prove(bytes,bytes32)\":{\"params\":{\"destTxHash\":\"The destination tx hash proving bridge transaction was relayed\",\"request\":\"The encoded bridge transaction to prove on origin chain\"}},\"refund(bytes)\":{\"params\":{\"request\":\"The encoded bridge transaction to refund\"}},\"relay(bytes)\":{\"params\":{\"request\":\"The encoded bridge transaction to relay on destination chain\"}}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256))\":{\"notice\":\"Initiates bridge on origin chain to be relayed by off-chain relayer\"},\"canClaim(bytes32,address)\":{\"notice\":\"Checks if the dispute period has passed so bridge deposit can be claimed\"},\"claim(bytes,address)\":{\"notice\":\"Completes bridge transaction on origin chain by claiming originally deposited capital\"},\"dispute(bytes32)\":{\"notice\":\"Disputes an outstanding proof in case relayer provided dest chain tx is invalid\"},\"getBridgeTransaction(bytes)\":{\"notice\":\"Decodes bridge request into a bridge transaction\"},\"prove(bytes,bytes32)\":{\"notice\":\"Provides proof on origin side that relayer provided funds on destination side of bridge transaction\"},\"refund(bytes)\":{\"notice\":\"Refunds an outstanding bridge transaction in case optimistic bridging failed\"},\"relay(bytes)\":{\"notice\":\"Relays destination side of bridge transaction by off-chain relayer\"}},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeV2.sol\":\"IFastBridge\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeV2.sol\":{\"keccak256\":\"0xfd916c030b1ffca5a136817827b8018c8ba42ca089905747f3de6148b73eb35e\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://18e6438c4096deb8ae453fb3365ba2b07d52944e93c08288fc5d012b71bf6bb3\",\"dweb:/ipfs/QmfEMqpT1zz6RRm7UuHLRowe1tds2cTGLrVonfm9XSCACj\"]}},\"version\":1}"},"hashes":{"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256))":"45851694","canClaim(bytes32,address)":"aa9641ab","claim(bytes,address)":"41fcb612","dispute(bytes32)":"add98c70","getBridgeTransaction(bytes)":"ac11fb1a","prove(bytes,bytes32)":"886d36ff","refund(bytes)":"5eb7d946","relay(bytes)":"8f0d6f17"}},"solidity/FastBridgeV2.sol:IFastBridgeRecipient":{"code":"0x","runtime-code":"0x","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.24 ^0.8.0 ^0.8.20;\n\n// contracts/interfaces/IAdmin.sol\n\ninterface IAdmin {\n // ============ Events ============\n\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n event ChainGasAmountUpdated(uint256 oldChainGasAmount, uint256 newChainGasAmount);\n\n // ============ Methods ============\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n\n function setChainGasAmount(uint256 newChainGasAmount) external;\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IFastBridgeRecipient.sol\n\ninterface IFastBridgeRecipient {\n function fastBridgeTransferReceived(\n address token,\n uint256 amount,\n bytes memory callParams\n )\n external\n payable\n returns (bytes4);\n}\n\n// contracts/interfaces/IFastBridgeV2Errors.sol\n\ninterface IFastBridgeV2Errors {\n error AmountIncorrect();\n error CallParamsLengthAboveMax();\n error ChainIncorrect();\n error ExclusivityParamsIncorrect();\n error MsgValueIncorrect();\n error NativeTokenCallValueNotSupported();\n error SenderIncorrect();\n error StatusIncorrect();\n error ZeroAddress();\n\n error RecipientIncorrectReturnValue();\n error RecipientNoReturnValue();\n\n error DeadlineExceeded();\n error DeadlineNotExceeded();\n error DeadlineTooShort();\n error DisputePeriodNotPassed();\n error DisputePeriodPassed();\n error ExclusivityPeriodNotPassed();\n\n error TransactionRelayed();\n}\n\n// contracts/libs/Errors.sol\n\nerror DeadlineExceeded();\nerror DeadlineNotExceeded();\nerror DeadlineTooShort();\nerror InsufficientOutputAmount();\n\nerror MsgValueIncorrect();\nerror PoolNotFound();\nerror TokenAddressMismatch();\nerror TokenNotContract();\nerror TokenNotETH();\nerror TokensIdentical();\n\nerror ChainIncorrect();\nerror AmountIncorrect();\nerror ZeroAddress();\n\nerror DisputePeriodNotPassed();\nerror DisputePeriodPassed();\nerror SenderIncorrect();\nerror StatusIncorrect();\nerror TransactionIdIncorrect();\nerror TransactionRelayed();\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// contracts/interfaces/IFastBridgeV2.sol\n\ninterface IFastBridgeV2 is IFastBridge {\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n struct BridgeTxDetails {\n BridgeStatus status;\n uint40 proofBlockTimestamp;\n uint48 proofBlockNumber;\n address proofRelayer;\n }\n\n struct BridgeRelay {\n uint48 blockNumber;\n uint48 blockTimestamp;\n address relayer;\n }\n\n /// @notice New params introduced in the FastBridgeV2.\n /// We are passing fields from the older BridgeParams struct outside of this struct\n /// for backwards compatibility.\n /// Note: quoteRelayer and quoteExclusivitySeconds are either both zero (indicating no exclusivity)\n /// or both non-zero (indicating exclusivity for the given period).\n /// Note: callValue \u003e 0 can NOT be used with destToken = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE (ETH_ADDRESS)\n /// @param quoteRelayer Relayer that provided the quote for the transaction\n /// @param quoteExclusivitySeconds Period of time the quote relayer is guaranteed exclusivity after user's deposit\n /// @param quoteId Unique quote identifier used for tracking the quote\n /// @param callValue ETH value to send to the recipient (if any)\n /// @param callParams Parameters for the arbitrary call to the destination recipient (if any)\n struct BridgeParamsV2 {\n address quoteRelayer;\n int256 quoteExclusivitySeconds;\n bytes quoteId;\n uint256 callValue;\n bytes callParams;\n }\n\n /// @notice Updated bridge transaction struct to include parameters introduced in FastBridgeV2.\n /// Note: only `exclusivityRelayer` can fill such a transaction until `exclusivityEndTime`.\n /// TODO: consider changing the encoding scheme to prevent spending extra gas on decoding.\n struct BridgeTransactionV2 {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n uint256 callValue; // ETH value to send to the recipient (if any) - replaces V1's sendChainGas flag\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n address exclusivityRelayer;\n uint256 exclusivityEndTime;\n bytes callParams;\n }\n\n event BridgeQuoteDetails(bytes32 indexed transactionId, bytes quoteId);\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability\n /// to provide temporary exclusivity fill rights for the quote relayer.\n /// @param params The parameters required to bridge\n /// @param paramsV2 The parameters for exclusivity fill rights (optional, can be left empty)\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function relay(bytes memory request, address relayer) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param transactionId The transaction id associated with the encoded bridge transaction to prove\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital.\n /// @notice Can only send funds to the relayer address on the proof.\n /// @param request The encoded bridge transaction to claim on origin chain\n function claim(bytes memory request) external;\n /// @notice Checks if a transaction has been relayed\n /// @param transactionId The ID of the transaction to check\n /// @return True if the transaction has been relayed, false otherwise\n function bridgeRelays(bytes32 transactionId) external view returns (bool);\n\n /// @notice Returns the status of a bridge transaction\n /// @param transactionId The ID of the bridge transaction\n /// @return BridgeStatus Status of the bridge transaction\n function bridgeStatuses(bytes32 transactionId) external view returns (BridgeStatus);\n\n /// @notice Returns the timestamp and relayer of a bridge proof\n /// @param transactionId The ID of the bridge transaction\n /// @return timestamp The timestamp of the bridge proof\n /// @return relayer The relayer address of the bridge proof\n function bridgeProofs(bytes32 transactionId) external view returns (uint96 timestamp, address relayer);\n\n /// @notice Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\n /// @param request The bridge request to decode\n function getBridgeTransactionV2(bytes memory request) external view returns (BridgeTransactionV2 memory);\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// contracts/libs/UniversalToken.sol\n\nlibrary UniversalTokenLib {\n using SafeERC20 for IERC20;\n\n address internal constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Transfers tokens to the given account. Reverts if transfer is not successful.\n /// @dev This might trigger fallback, if ETH is transferred to the contract.\n /// Make sure this can not lead to reentrancy attacks.\n function universalTransfer(address token, address to, uint256 value) internal {\n // Don't do anything, if need to send tokens to this address\n if (to == address(this)) return;\n // Don't do anything, if trying to send zero value\n if (value == 0) return;\n if (token == ETH_ADDRESS) {\n /// @dev Note: this can potentially lead to executing code in `to`.\n // solhint-disable-next-line avoid-low-level-calls\n (bool success,) = to.call{value: value}(\"\");\n require(success, \"ETH transfer failed\");\n } else {\n IERC20(token).safeTransfer(to, value);\n }\n }\n\n /// @notice Issues an infinite allowance to the spender, if the current allowance is insufficient\n /// to spend the given amount.\n function universalApproveInfinity(address token, address spender, uint256 amountToSpend) internal {\n // ETH Chad doesn't require your approval\n if (token == ETH_ADDRESS) return;\n // No-op if allowance is already sufficient\n uint256 allowance = IERC20(token).allowance(address(this), spender);\n if (allowance \u003e= amountToSpend) return;\n // Otherwise, reset approval to 0 and set to max allowance\n if (allowance \u003e 0) IERC20(token).safeDecreaseAllowance(spender, allowance);\n IERC20(token).safeIncreaseAllowance(spender, type(uint256).max);\n }\n\n /// @notice Returns the balance of the given token (or native ETH) for the given account.\n function universalBalanceOf(address token, address account) internal view returns (uint256) {\n if (token == ETH_ADDRESS) {\n return account.balance;\n } else {\n return IERC20(token).balanceOf(account);\n }\n }\n\n /// @dev Checks that token is a contract and not ETH_ADDRESS.\n function assertIsContract(address token) internal view {\n // Check that ETH_ADDRESS was not used (in case this is a predeploy on any of the chains)\n if (token == UniversalTokenLib.ETH_ADDRESS) revert TokenNotContract();\n // Check that token is not an EOA\n if (token.code.length == 0) revert TokenNotContract();\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/Admin.sol\n\ncontract Admin is IAdmin, AccessControlEnumerable {\n using UniversalTokenLib for address;\n\n bytes32 public constant RELAYER_ROLE = keccak256(\"RELAYER_ROLE\");\n bytes32 public constant REFUNDER_ROLE = keccak256(\"REFUNDER_ROLE\");\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n uint256 public constant FEE_BPS = 1e6;\n uint256 public constant FEE_RATE_MAX = 0.01e6; // max 1% on origin amount\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Chain gas amount to forward as rebate if requested\n uint256 public chainGasAmount;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n }\n\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n require(newFeeRate \u003c= FEE_RATE_MAX, \"newFeeRate \u003e max\");\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n token.universalTransfer(recipient, feeAmount);\n emit FeesSwept(token, recipient, feeAmount);\n }\n\n function setChainGasAmount(uint256 newChainGasAmount) external onlyRole(GOVERNOR_ROLE) {\n uint256 oldChainGasAmount = chainGasAmount;\n chainGasAmount = newChainGasAmount;\n emit ChainGasAmountUpdated(oldChainGasAmount, newChainGasAmount);\n }\n}\n\n// contracts/FastBridgeV2.sol\n\n/// @notice FastBridgeV2 is a contract for bridging tokens across chains.\ncontract FastBridgeV2 is Admin, IFastBridgeV2, IFastBridgeV2Errors {\n using SafeERC20 for IERC20;\n using UniversalTokenLib for address;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Delay for a transaction after which it could be permisionlessly refunded\n uint256 public constant REFUND_DELAY = 7 days;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n /// @notice Maximum length of accepted callParams\n uint256 public constant MAX_CALL_PARAMS_LENGTH = 2 ** 16 - 1;\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeTxDetails) public bridgeTxDetails;\n /// @notice Relay details on destination chain\n mapping(bytes32 =\u003e BridgeRelay) public bridgeRelayDetails;\n /// @notice Unique bridge nonces tracked per originSender\n mapping(address =\u003e uint256) public senderNonces;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Replaced by senderNonces\n uint256 public immutable nonce = 0;\n /// @notice the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n bridge({\n params: params,\n paramsV2: BridgeParamsV2({\n quoteRelayer: address(0),\n quoteExclusivitySeconds: 0,\n quoteId: bytes(\"\"),\n callValue: 0,\n callParams: bytes(\"\")\n })\n });\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes memory request) external payable {\n relay({request: request, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes memory request, bytes32 destTxHash) external {\n prove({transactionId: keccak256(request), destTxHash: destTxHash, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridgeV2\n function claim(bytes memory request) external {\n claim({request: request, to: address(0)});\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003e DISPUTE_PERIOD) {\n revert DisputePeriodPassed();\n }\n\n // @dev relayer gets slashed effectively if dest relay has gone thru\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n bridgeTxDetails[transactionId].proofRelayer = address(0);\n bridgeTxDetails[transactionId].proofBlockTimestamp = 0;\n bridgeTxDetails[transactionId].proofBlockNumber = 0;\n\n emit BridgeProofDisputed(transactionId, msg.sender);\n }\n\n /// @inheritdoc IFastBridge\n function refund(bytes memory request) external {\n bytes32 transactionId = keccak256(request);\n\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n\n if (bridgeTxDetails[transactionId].status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n\n if (hasRole(REFUNDER_ROLE, msg.sender)) {\n // Refunder can refund if deadline has passed\n if (block.timestamp \u003c= transaction.deadline) revert DeadlineNotExceeded();\n } else {\n // Permissionless refund is allowed after REFUND_DELAY\n if (block.timestamp \u003c= transaction.deadline + REFUND_DELAY) revert DeadlineNotExceeded();\n }\n\n // if all checks passed, set to REFUNDED status\n bridgeTxDetails[transactionId].status = BridgeStatus.REFUNDED;\n\n // transfer origin collateral back to original sender\n address to = transaction.originSender;\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount + transaction.originFeeAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (bridgeTxDetails[transactionId].proofRelayer != relayer) revert SenderIncorrect();\n return _timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n /// @dev This method is added to achieve backwards compatibility with decoding requests into V1 structs:\n /// - `callValue` is partially reported as a zero/non-zero flag\n /// - `callParams` is ignored\n /// In order to process all kinds of requests use getBridgeTransactionV2 instead.\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory) {\n // Try decoding into V2 struct first. This will revert if V1 struct is passed\n try this.getBridgeTransactionV2(request) returns (BridgeTransactionV2 memory txV2) {\n // Note: we entirely ignore the callParams field, as it was not present in V1\n return BridgeTransaction({\n originChainId: txV2.originChainId,\n destChainId: txV2.destChainId,\n originSender: txV2.originSender,\n destRecipient: txV2.destRecipient,\n originToken: txV2.originToken,\n destToken: txV2.destToken,\n originAmount: txV2.originAmount,\n destAmount: txV2.destAmount,\n originFeeAmount: txV2.originFeeAmount,\n sendChainGas: txV2.callValue != 0,\n deadline: txV2.deadline,\n nonce: txV2.nonce\n });\n } catch {\n // Fallback to V1 struct\n return abi.decode(request, (BridgeTransaction));\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) public payable {\n int256 exclusivityEndTime = int256(block.timestamp) + paramsV2.quoteExclusivitySeconds;\n _validateBridgeParams(params, paramsV2, exclusivityEndTime);\n\n // transfer tokens to bridge contract\n /// @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _takeBridgedUserAsset(params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n\n // set status to requested\n bytes memory request = abi.encode(\n BridgeTransactionV2({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n callValue: paramsV2.callValue,\n deadline: params.deadline,\n nonce: senderNonces[params.sender]++, // increment nonce on every bridge\n exclusivityRelayer: paramsV2.quoteRelayer,\n // We checked exclusivityEndTime to be in range (0 .. params.deadline] above, so can safely cast\n exclusivityEndTime: uint256(exclusivityEndTime),\n callParams: paramsV2.callParams\n })\n );\n bytes32 transactionId = keccak256(request);\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n\n emit BridgeRequested({\n transactionId: transactionId,\n sender: params.sender,\n request: request,\n destChainId: params.dstChainId,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n sendChainGas: paramsV2.callValue != 0\n });\n emit BridgeQuoteDetails(transactionId, paramsV2.quoteId);\n }\n\n /// @inheritdoc IFastBridgeV2\n function relay(bytes memory request, address relayer) public payable {\n bytes32 transactionId = keccak256(request);\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n _validateRelayParams(transaction, transactionId, relayer);\n // mark bridge transaction as relayed\n bridgeRelayDetails[transactionId] =\n BridgeRelay({blockNumber: uint48(block.number), blockTimestamp: uint48(block.timestamp), relayer: relayer});\n\n // transfer tokens to recipient on destination chain and do an arbitrary call if requested\n address to = transaction.destRecipient;\n address token = transaction.destToken;\n uint256 amount = transaction.destAmount;\n uint256 callValue = transaction.callValue;\n\n // Emit the event before any external calls\n emit BridgeRelayed({\n transactionId: transactionId,\n relayer: relayer,\n to: to,\n originChainId: transaction.originChainId,\n originToken: transaction.originToken,\n destToken: token,\n originAmount: transaction.originAmount,\n destAmount: amount,\n chainGasAmount: callValue\n });\n\n // All state changes have been done at this point, can proceed to the external calls.\n // This follows the checks-effects-interactions pattern to mitigate potential reentrancy attacks.\n if (token == UniversalTokenLib.ETH_ADDRESS) {\n // For ETH non-zero callValue is not allowed\n if (callValue != 0) revert NativeTokenCallValueNotSupported();\n // Check that the correct msg.value was sent\n if (msg.value != amount) revert MsgValueIncorrect();\n } else {\n // For ERC20s, we check that the correct msg.value was sent\n if (msg.value != callValue) revert MsgValueIncorrect();\n // We need to transfer the tokens from the Relayer to the recipient first before performing an\n // optional post-transfer arbitrary call.\n IERC20(token).safeTransferFrom(msg.sender, to, amount);\n }\n\n if (transaction.callParams.length != 0) {\n // Arbitrary call requested, perform it while supplying full msg.value to the recipient\n // Note: if token has a fee on transfers, the recipient will have received less than `amount`.\n // This is a very niche edge case and should be handled by the recipient contract.\n _checkedCallRecipient({recipient: to, token: token, amount: amount, callParams: transaction.callParams});\n } else if (msg.value != 0) {\n // No arbitrary call requested, but msg.value was sent. This is either a relay with ETH,\n // or a non-zero callValue request with an ERC20. In both cases, transfer the ETH to the recipient.\n Address.sendValue(payable(to), msg.value);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) public onlyRole(RELAYER_ROLE) {\n // update bridge tx status given proof provided\n if (bridgeTxDetails[transactionId].status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n bridgeTxDetails[transactionId].status = BridgeStatus.RELAYER_PROVED;\n bridgeTxDetails[transactionId].proofBlockTimestamp = uint40(block.timestamp);\n bridgeTxDetails[transactionId].proofBlockNumber = uint48(block.number);\n bridgeTxDetails[transactionId].proofRelayer = relayer;\n\n emit BridgeProofProvided(transactionId, relayer, destTxHash);\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes memory request, address to) public {\n bytes32 transactionId = keccak256(request);\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n\n // update bridge tx status if able to claim origin collateral\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n\n // if \"to\" is zero addr, permissionlessly send funds to proven relayer\n if (to == address(0)) {\n to = bridgeTxDetails[transactionId].proofRelayer;\n } else if (bridgeTxDetails[transactionId].proofRelayer != msg.sender) {\n revert SenderIncorrect();\n }\n\n if (_timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003c= DISPUTE_PERIOD) {\n revert DisputePeriodNotPassed();\n }\n\n bridgeTxDetails[transactionId].status = BridgeStatus.RELAYER_CLAIMED;\n\n // update protocol fees if origin fee amount exists\n if (transaction.originFeeAmount \u003e 0) protocolFees[transaction.originToken] += transaction.originFeeAmount;\n\n // transfer origin collateral less fee to specified address\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositClaimed(transactionId, bridgeTxDetails[transactionId].proofRelayer, to, token, amount);\n }\n\n function bridgeStatuses(bytes32 transactionId) public view returns (BridgeStatus status) {\n return bridgeTxDetails[transactionId].status;\n }\n\n function bridgeProofs(bytes32 transactionId) public view returns (uint96 timestamp, address relayer) {\n timestamp = bridgeTxDetails[transactionId].proofBlockTimestamp;\n relayer = bridgeTxDetails[transactionId].proofRelayer;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeRelays(bytes32 transactionId) public view returns (bool) {\n // has this transactionId been relayed?\n return bridgeRelayDetails[transactionId].relayer != address(0);\n }\n\n /// @inheritdoc IFastBridgeV2\n function getBridgeTransactionV2(bytes memory request) public pure returns (BridgeTransactionV2 memory) {\n return abi.decode(request, (BridgeTransactionV2));\n }\n\n /// @notice Takes the bridged asset from the user into FastBridgeV2 custody. It will be later\n /// claimed by the relayer who completed the relay on destination chain, or refunded back to the user,\n /// should no one complete the relay.\n function _takeBridgedUserAsset(address token, uint256 amount) internal returns (uint256 amountTaken) {\n if (token == UniversalTokenLib.ETH_ADDRESS) {\n // For ETH we just need to check that the supplied msg.value is correct.\n // Supplied `msg.value` is already in FastBridgeV2 custody.\n if (amount != msg.value) revert MsgValueIncorrect();\n amountTaken = msg.value;\n } else {\n // For ERC20s, token is explicitly transferred from the user to FastBridgeV2.\n // We don't allow non-zero `msg.value` to avoid extra funds from being stuck in FastBridgeV2.\n token.assertIsContract();\n if (msg.value != 0) revert MsgValueIncorrect();\n amountTaken = IERC20(token).balanceOf(address(this));\n IERC20(token).safeTransferFrom(msg.sender, address(this), amount);\n // Use the balance difference as the amount taken in case of fee on transfer tokens.\n amountTaken = IERC20(token).balanceOf(address(this)) - amountTaken;\n }\n }\n\n /// @notice Calls the Recipient's hook function with the specified callParams and performs\n /// all the necessary checks for the returned value.\n function _checkedCallRecipient(\n address recipient,\n address token,\n uint256 amount,\n bytes memory callParams\n )\n internal\n {\n bytes memory hookData =\n abi.encodeCall(IFastBridgeRecipient.fastBridgeTransferReceived, (token, amount, callParams));\n // This will bubble any revert messages from the hook function\n bytes memory returnData = Address.functionCallWithValue({target: recipient, data: hookData, value: msg.value});\n // Explicit revert if no return data at all\n if (returnData.length == 0) revert RecipientNoReturnValue();\n // Check that exactly a single return value was returned\n if (returnData.length != 32) revert RecipientIncorrectReturnValue();\n // Return value should be abi-encoded hook function selector\n if (bytes32(returnData) != bytes32(IFastBridgeRecipient.fastBridgeTransferReceived.selector)) {\n revert RecipientIncorrectReturnValue();\n }\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint40(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint40).max but\n /// proof.timestamp \u003c type(uint40).max via unchecked statement\n /// @param proofBlockTimestamp The bridge proof block timestamp\n /// @return delta Time delta since proof submitted\n function _timeSince(uint40 proofBlockTimestamp) internal view returns (uint256 delta) {\n unchecked {\n delta = uint40(block.timestamp) - proofBlockTimestamp;\n }\n }\n\n /// @notice Performs all the necessary checks for a bridge to happen.\n /// @dev There's no good way to refactor this function to reduce cyclomatic complexity due to\n /// the number of checks that need to be performed, so we skip the code-complexity rule here.\n // solhint-disable-next-line code-complexity\n function _validateBridgeParams(\n BridgeParams memory params,\n BridgeParamsV2 memory paramsV2,\n int256 exclusivityEndTime\n )\n internal\n view\n {\n // Check V1 (legacy) params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.sender == address(0) || params.to == address(0)) revert ZeroAddress();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n // Check V2 params\n if (paramsV2.callParams.length \u003e MAX_CALL_PARAMS_LENGTH) revert CallParamsLengthAboveMax();\n if (paramsV2.callValue != 0 \u0026\u0026 params.destToken == UniversalTokenLib.ETH_ADDRESS) {\n revert NativeTokenCallValueNotSupported();\n }\n // exclusivityEndTime must be in range (0 .. params.deadline]\n if (exclusivityEndTime \u003c= 0 || exclusivityEndTime \u003e int256(params.deadline)) {\n revert ExclusivityParamsIncorrect();\n }\n }\n\n /// @notice Performs all the necessary checks for a relay to happen.\n function _validateRelayParams(\n BridgeTransactionV2 memory transaction,\n bytes32 transactionId,\n address relayer\n )\n internal\n view\n {\n if (relayer == address(0)) revert ZeroAddress();\n // Check if the transaction has already been relayed\n if (bridgeRelays(transactionId)) revert TransactionRelayed();\n if (transaction.destChainId != block.chainid) revert ChainIncorrect();\n // Check the deadline for relay to happen\n if (block.timestamp \u003e transaction.deadline) revert DeadlineExceeded();\n // Check the exclusivity period, if it is still ongoing\n // forgefmt: disable-next-item\n if (\n transaction.exclusivityRelayer != address(0) \u0026\u0026\n transaction.exclusivityRelayer != relayer \u0026\u0026\n block.timestamp \u003c= transaction.exclusivityEndTime\n ) {\n revert ExclusivityPeriodNotPassed();\n }\n }\n}\n","language":"Solidity","languageVersion":"0.8.24","compilerVersion":"0.8.24","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"","srcMapRuntime":"","abiDefinition":[{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"bytes","name":"callParams","type":"bytes"}],"name":"fastBridgeTransferReceived","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"payable","type":"function"}],"userDoc":{"kind":"user","methods":{},"version":1},"developerDoc":{"kind":"dev","methods":{},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"callParams\",\"type\":\"bytes\"}],\"name\":\"fastBridgeTransferReceived\",\"outputs\":[{\"internalType\":\"bytes4\",\"name\":\"\",\"type\":\"bytes4\"}],\"stateMutability\":\"payable\",\"type\":\"function\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeV2.sol\":\"IFastBridgeRecipient\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeV2.sol\":{\"keccak256\":\"0xfd916c030b1ffca5a136817827b8018c8ba42ca089905747f3de6148b73eb35e\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://18e6438c4096deb8ae453fb3365ba2b07d52944e93c08288fc5d012b71bf6bb3\",\"dweb:/ipfs/QmfEMqpT1zz6RRm7UuHLRowe1tds2cTGLrVonfm9XSCACj\"]}},\"version\":1}"},"hashes":{"fastBridgeTransferReceived(address,uint256,bytes)":"461e0c21"}},"solidity/FastBridgeV2.sol:IFastBridgeV2":{"code":"0x","runtime-code":"0x","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.24 ^0.8.0 ^0.8.20;\n\n// contracts/interfaces/IAdmin.sol\n\ninterface IAdmin {\n // ============ Events ============\n\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n event ChainGasAmountUpdated(uint256 oldChainGasAmount, uint256 newChainGasAmount);\n\n // ============ Methods ============\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n\n function setChainGasAmount(uint256 newChainGasAmount) external;\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IFastBridgeRecipient.sol\n\ninterface IFastBridgeRecipient {\n function fastBridgeTransferReceived(\n address token,\n uint256 amount,\n bytes memory callParams\n )\n external\n payable\n returns (bytes4);\n}\n\n// contracts/interfaces/IFastBridgeV2Errors.sol\n\ninterface IFastBridgeV2Errors {\n error AmountIncorrect();\n error CallParamsLengthAboveMax();\n error ChainIncorrect();\n error ExclusivityParamsIncorrect();\n error MsgValueIncorrect();\n error NativeTokenCallValueNotSupported();\n error SenderIncorrect();\n error StatusIncorrect();\n error ZeroAddress();\n\n error RecipientIncorrectReturnValue();\n error RecipientNoReturnValue();\n\n error DeadlineExceeded();\n error DeadlineNotExceeded();\n error DeadlineTooShort();\n error DisputePeriodNotPassed();\n error DisputePeriodPassed();\n error ExclusivityPeriodNotPassed();\n\n error TransactionRelayed();\n}\n\n// contracts/libs/Errors.sol\n\nerror DeadlineExceeded();\nerror DeadlineNotExceeded();\nerror DeadlineTooShort();\nerror InsufficientOutputAmount();\n\nerror MsgValueIncorrect();\nerror PoolNotFound();\nerror TokenAddressMismatch();\nerror TokenNotContract();\nerror TokenNotETH();\nerror TokensIdentical();\n\nerror ChainIncorrect();\nerror AmountIncorrect();\nerror ZeroAddress();\n\nerror DisputePeriodNotPassed();\nerror DisputePeriodPassed();\nerror SenderIncorrect();\nerror StatusIncorrect();\nerror TransactionIdIncorrect();\nerror TransactionRelayed();\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// contracts/interfaces/IFastBridgeV2.sol\n\ninterface IFastBridgeV2 is IFastBridge {\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n struct BridgeTxDetails {\n BridgeStatus status;\n uint40 proofBlockTimestamp;\n uint48 proofBlockNumber;\n address proofRelayer;\n }\n\n struct BridgeRelay {\n uint48 blockNumber;\n uint48 blockTimestamp;\n address relayer;\n }\n\n /// @notice New params introduced in the FastBridgeV2.\n /// We are passing fields from the older BridgeParams struct outside of this struct\n /// for backwards compatibility.\n /// Note: quoteRelayer and quoteExclusivitySeconds are either both zero (indicating no exclusivity)\n /// or both non-zero (indicating exclusivity for the given period).\n /// Note: callValue \u003e 0 can NOT be used with destToken = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE (ETH_ADDRESS)\n /// @param quoteRelayer Relayer that provided the quote for the transaction\n /// @param quoteExclusivitySeconds Period of time the quote relayer is guaranteed exclusivity after user's deposit\n /// @param quoteId Unique quote identifier used for tracking the quote\n /// @param callValue ETH value to send to the recipient (if any)\n /// @param callParams Parameters for the arbitrary call to the destination recipient (if any)\n struct BridgeParamsV2 {\n address quoteRelayer;\n int256 quoteExclusivitySeconds;\n bytes quoteId;\n uint256 callValue;\n bytes callParams;\n }\n\n /// @notice Updated bridge transaction struct to include parameters introduced in FastBridgeV2.\n /// Note: only `exclusivityRelayer` can fill such a transaction until `exclusivityEndTime`.\n /// TODO: consider changing the encoding scheme to prevent spending extra gas on decoding.\n struct BridgeTransactionV2 {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n uint256 callValue; // ETH value to send to the recipient (if any) - replaces V1's sendChainGas flag\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n address exclusivityRelayer;\n uint256 exclusivityEndTime;\n bytes callParams;\n }\n\n event BridgeQuoteDetails(bytes32 indexed transactionId, bytes quoteId);\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability\n /// to provide temporary exclusivity fill rights for the quote relayer.\n /// @param params The parameters required to bridge\n /// @param paramsV2 The parameters for exclusivity fill rights (optional, can be left empty)\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function relay(bytes memory request, address relayer) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param transactionId The transaction id associated with the encoded bridge transaction to prove\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital.\n /// @notice Can only send funds to the relayer address on the proof.\n /// @param request The encoded bridge transaction to claim on origin chain\n function claim(bytes memory request) external;\n /// @notice Checks if a transaction has been relayed\n /// @param transactionId The ID of the transaction to check\n /// @return True if the transaction has been relayed, false otherwise\n function bridgeRelays(bytes32 transactionId) external view returns (bool);\n\n /// @notice Returns the status of a bridge transaction\n /// @param transactionId The ID of the bridge transaction\n /// @return BridgeStatus Status of the bridge transaction\n function bridgeStatuses(bytes32 transactionId) external view returns (BridgeStatus);\n\n /// @notice Returns the timestamp and relayer of a bridge proof\n /// @param transactionId The ID of the bridge transaction\n /// @return timestamp The timestamp of the bridge proof\n /// @return relayer The relayer address of the bridge proof\n function bridgeProofs(bytes32 transactionId) external view returns (uint96 timestamp, address relayer);\n\n /// @notice Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\n /// @param request The bridge request to decode\n function getBridgeTransactionV2(bytes memory request) external view returns (BridgeTransactionV2 memory);\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// contracts/libs/UniversalToken.sol\n\nlibrary UniversalTokenLib {\n using SafeERC20 for IERC20;\n\n address internal constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Transfers tokens to the given account. Reverts if transfer is not successful.\n /// @dev This might trigger fallback, if ETH is transferred to the contract.\n /// Make sure this can not lead to reentrancy attacks.\n function universalTransfer(address token, address to, uint256 value) internal {\n // Don't do anything, if need to send tokens to this address\n if (to == address(this)) return;\n // Don't do anything, if trying to send zero value\n if (value == 0) return;\n if (token == ETH_ADDRESS) {\n /// @dev Note: this can potentially lead to executing code in `to`.\n // solhint-disable-next-line avoid-low-level-calls\n (bool success,) = to.call{value: value}(\"\");\n require(success, \"ETH transfer failed\");\n } else {\n IERC20(token).safeTransfer(to, value);\n }\n }\n\n /// @notice Issues an infinite allowance to the spender, if the current allowance is insufficient\n /// to spend the given amount.\n function universalApproveInfinity(address token, address spender, uint256 amountToSpend) internal {\n // ETH Chad doesn't require your approval\n if (token == ETH_ADDRESS) return;\n // No-op if allowance is already sufficient\n uint256 allowance = IERC20(token).allowance(address(this), spender);\n if (allowance \u003e= amountToSpend) return;\n // Otherwise, reset approval to 0 and set to max allowance\n if (allowance \u003e 0) IERC20(token).safeDecreaseAllowance(spender, allowance);\n IERC20(token).safeIncreaseAllowance(spender, type(uint256).max);\n }\n\n /// @notice Returns the balance of the given token (or native ETH) for the given account.\n function universalBalanceOf(address token, address account) internal view returns (uint256) {\n if (token == ETH_ADDRESS) {\n return account.balance;\n } else {\n return IERC20(token).balanceOf(account);\n }\n }\n\n /// @dev Checks that token is a contract and not ETH_ADDRESS.\n function assertIsContract(address token) internal view {\n // Check that ETH_ADDRESS was not used (in case this is a predeploy on any of the chains)\n if (token == UniversalTokenLib.ETH_ADDRESS) revert TokenNotContract();\n // Check that token is not an EOA\n if (token.code.length == 0) revert TokenNotContract();\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/Admin.sol\n\ncontract Admin is IAdmin, AccessControlEnumerable {\n using UniversalTokenLib for address;\n\n bytes32 public constant RELAYER_ROLE = keccak256(\"RELAYER_ROLE\");\n bytes32 public constant REFUNDER_ROLE = keccak256(\"REFUNDER_ROLE\");\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n uint256 public constant FEE_BPS = 1e6;\n uint256 public constant FEE_RATE_MAX = 0.01e6; // max 1% on origin amount\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Chain gas amount to forward as rebate if requested\n uint256 public chainGasAmount;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n }\n\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n require(newFeeRate \u003c= FEE_RATE_MAX, \"newFeeRate \u003e max\");\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n token.universalTransfer(recipient, feeAmount);\n emit FeesSwept(token, recipient, feeAmount);\n }\n\n function setChainGasAmount(uint256 newChainGasAmount) external onlyRole(GOVERNOR_ROLE) {\n uint256 oldChainGasAmount = chainGasAmount;\n chainGasAmount = newChainGasAmount;\n emit ChainGasAmountUpdated(oldChainGasAmount, newChainGasAmount);\n }\n}\n\n// contracts/FastBridgeV2.sol\n\n/// @notice FastBridgeV2 is a contract for bridging tokens across chains.\ncontract FastBridgeV2 is Admin, IFastBridgeV2, IFastBridgeV2Errors {\n using SafeERC20 for IERC20;\n using UniversalTokenLib for address;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Delay for a transaction after which it could be permisionlessly refunded\n uint256 public constant REFUND_DELAY = 7 days;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n /// @notice Maximum length of accepted callParams\n uint256 public constant MAX_CALL_PARAMS_LENGTH = 2 ** 16 - 1;\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeTxDetails) public bridgeTxDetails;\n /// @notice Relay details on destination chain\n mapping(bytes32 =\u003e BridgeRelay) public bridgeRelayDetails;\n /// @notice Unique bridge nonces tracked per originSender\n mapping(address =\u003e uint256) public senderNonces;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Replaced by senderNonces\n uint256 public immutable nonce = 0;\n /// @notice the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n bridge({\n params: params,\n paramsV2: BridgeParamsV2({\n quoteRelayer: address(0),\n quoteExclusivitySeconds: 0,\n quoteId: bytes(\"\"),\n callValue: 0,\n callParams: bytes(\"\")\n })\n });\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes memory request) external payable {\n relay({request: request, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes memory request, bytes32 destTxHash) external {\n prove({transactionId: keccak256(request), destTxHash: destTxHash, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridgeV2\n function claim(bytes memory request) external {\n claim({request: request, to: address(0)});\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003e DISPUTE_PERIOD) {\n revert DisputePeriodPassed();\n }\n\n // @dev relayer gets slashed effectively if dest relay has gone thru\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n bridgeTxDetails[transactionId].proofRelayer = address(0);\n bridgeTxDetails[transactionId].proofBlockTimestamp = 0;\n bridgeTxDetails[transactionId].proofBlockNumber = 0;\n\n emit BridgeProofDisputed(transactionId, msg.sender);\n }\n\n /// @inheritdoc IFastBridge\n function refund(bytes memory request) external {\n bytes32 transactionId = keccak256(request);\n\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n\n if (bridgeTxDetails[transactionId].status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n\n if (hasRole(REFUNDER_ROLE, msg.sender)) {\n // Refunder can refund if deadline has passed\n if (block.timestamp \u003c= transaction.deadline) revert DeadlineNotExceeded();\n } else {\n // Permissionless refund is allowed after REFUND_DELAY\n if (block.timestamp \u003c= transaction.deadline + REFUND_DELAY) revert DeadlineNotExceeded();\n }\n\n // if all checks passed, set to REFUNDED status\n bridgeTxDetails[transactionId].status = BridgeStatus.REFUNDED;\n\n // transfer origin collateral back to original sender\n address to = transaction.originSender;\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount + transaction.originFeeAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (bridgeTxDetails[transactionId].proofRelayer != relayer) revert SenderIncorrect();\n return _timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n /// @dev This method is added to achieve backwards compatibility with decoding requests into V1 structs:\n /// - `callValue` is partially reported as a zero/non-zero flag\n /// - `callParams` is ignored\n /// In order to process all kinds of requests use getBridgeTransactionV2 instead.\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory) {\n // Try decoding into V2 struct first. This will revert if V1 struct is passed\n try this.getBridgeTransactionV2(request) returns (BridgeTransactionV2 memory txV2) {\n // Note: we entirely ignore the callParams field, as it was not present in V1\n return BridgeTransaction({\n originChainId: txV2.originChainId,\n destChainId: txV2.destChainId,\n originSender: txV2.originSender,\n destRecipient: txV2.destRecipient,\n originToken: txV2.originToken,\n destToken: txV2.destToken,\n originAmount: txV2.originAmount,\n destAmount: txV2.destAmount,\n originFeeAmount: txV2.originFeeAmount,\n sendChainGas: txV2.callValue != 0,\n deadline: txV2.deadline,\n nonce: txV2.nonce\n });\n } catch {\n // Fallback to V1 struct\n return abi.decode(request, (BridgeTransaction));\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) public payable {\n int256 exclusivityEndTime = int256(block.timestamp) + paramsV2.quoteExclusivitySeconds;\n _validateBridgeParams(params, paramsV2, exclusivityEndTime);\n\n // transfer tokens to bridge contract\n /// @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _takeBridgedUserAsset(params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n\n // set status to requested\n bytes memory request = abi.encode(\n BridgeTransactionV2({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n callValue: paramsV2.callValue,\n deadline: params.deadline,\n nonce: senderNonces[params.sender]++, // increment nonce on every bridge\n exclusivityRelayer: paramsV2.quoteRelayer,\n // We checked exclusivityEndTime to be in range (0 .. params.deadline] above, so can safely cast\n exclusivityEndTime: uint256(exclusivityEndTime),\n callParams: paramsV2.callParams\n })\n );\n bytes32 transactionId = keccak256(request);\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n\n emit BridgeRequested({\n transactionId: transactionId,\n sender: params.sender,\n request: request,\n destChainId: params.dstChainId,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n sendChainGas: paramsV2.callValue != 0\n });\n emit BridgeQuoteDetails(transactionId, paramsV2.quoteId);\n }\n\n /// @inheritdoc IFastBridgeV2\n function relay(bytes memory request, address relayer) public payable {\n bytes32 transactionId = keccak256(request);\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n _validateRelayParams(transaction, transactionId, relayer);\n // mark bridge transaction as relayed\n bridgeRelayDetails[transactionId] =\n BridgeRelay({blockNumber: uint48(block.number), blockTimestamp: uint48(block.timestamp), relayer: relayer});\n\n // transfer tokens to recipient on destination chain and do an arbitrary call if requested\n address to = transaction.destRecipient;\n address token = transaction.destToken;\n uint256 amount = transaction.destAmount;\n uint256 callValue = transaction.callValue;\n\n // Emit the event before any external calls\n emit BridgeRelayed({\n transactionId: transactionId,\n relayer: relayer,\n to: to,\n originChainId: transaction.originChainId,\n originToken: transaction.originToken,\n destToken: token,\n originAmount: transaction.originAmount,\n destAmount: amount,\n chainGasAmount: callValue\n });\n\n // All state changes have been done at this point, can proceed to the external calls.\n // This follows the checks-effects-interactions pattern to mitigate potential reentrancy attacks.\n if (token == UniversalTokenLib.ETH_ADDRESS) {\n // For ETH non-zero callValue is not allowed\n if (callValue != 0) revert NativeTokenCallValueNotSupported();\n // Check that the correct msg.value was sent\n if (msg.value != amount) revert MsgValueIncorrect();\n } else {\n // For ERC20s, we check that the correct msg.value was sent\n if (msg.value != callValue) revert MsgValueIncorrect();\n // We need to transfer the tokens from the Relayer to the recipient first before performing an\n // optional post-transfer arbitrary call.\n IERC20(token).safeTransferFrom(msg.sender, to, amount);\n }\n\n if (transaction.callParams.length != 0) {\n // Arbitrary call requested, perform it while supplying full msg.value to the recipient\n // Note: if token has a fee on transfers, the recipient will have received less than `amount`.\n // This is a very niche edge case and should be handled by the recipient contract.\n _checkedCallRecipient({recipient: to, token: token, amount: amount, callParams: transaction.callParams});\n } else if (msg.value != 0) {\n // No arbitrary call requested, but msg.value was sent. This is either a relay with ETH,\n // or a non-zero callValue request with an ERC20. In both cases, transfer the ETH to the recipient.\n Address.sendValue(payable(to), msg.value);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) public onlyRole(RELAYER_ROLE) {\n // update bridge tx status given proof provided\n if (bridgeTxDetails[transactionId].status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n bridgeTxDetails[transactionId].status = BridgeStatus.RELAYER_PROVED;\n bridgeTxDetails[transactionId].proofBlockTimestamp = uint40(block.timestamp);\n bridgeTxDetails[transactionId].proofBlockNumber = uint48(block.number);\n bridgeTxDetails[transactionId].proofRelayer = relayer;\n\n emit BridgeProofProvided(transactionId, relayer, destTxHash);\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes memory request, address to) public {\n bytes32 transactionId = keccak256(request);\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n\n // update bridge tx status if able to claim origin collateral\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n\n // if \"to\" is zero addr, permissionlessly send funds to proven relayer\n if (to == address(0)) {\n to = bridgeTxDetails[transactionId].proofRelayer;\n } else if (bridgeTxDetails[transactionId].proofRelayer != msg.sender) {\n revert SenderIncorrect();\n }\n\n if (_timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003c= DISPUTE_PERIOD) {\n revert DisputePeriodNotPassed();\n }\n\n bridgeTxDetails[transactionId].status = BridgeStatus.RELAYER_CLAIMED;\n\n // update protocol fees if origin fee amount exists\n if (transaction.originFeeAmount \u003e 0) protocolFees[transaction.originToken] += transaction.originFeeAmount;\n\n // transfer origin collateral less fee to specified address\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositClaimed(transactionId, bridgeTxDetails[transactionId].proofRelayer, to, token, amount);\n }\n\n function bridgeStatuses(bytes32 transactionId) public view returns (BridgeStatus status) {\n return bridgeTxDetails[transactionId].status;\n }\n\n function bridgeProofs(bytes32 transactionId) public view returns (uint96 timestamp, address relayer) {\n timestamp = bridgeTxDetails[transactionId].proofBlockTimestamp;\n relayer = bridgeTxDetails[transactionId].proofRelayer;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeRelays(bytes32 transactionId) public view returns (bool) {\n // has this transactionId been relayed?\n return bridgeRelayDetails[transactionId].relayer != address(0);\n }\n\n /// @inheritdoc IFastBridgeV2\n function getBridgeTransactionV2(bytes memory request) public pure returns (BridgeTransactionV2 memory) {\n return abi.decode(request, (BridgeTransactionV2));\n }\n\n /// @notice Takes the bridged asset from the user into FastBridgeV2 custody. It will be later\n /// claimed by the relayer who completed the relay on destination chain, or refunded back to the user,\n /// should no one complete the relay.\n function _takeBridgedUserAsset(address token, uint256 amount) internal returns (uint256 amountTaken) {\n if (token == UniversalTokenLib.ETH_ADDRESS) {\n // For ETH we just need to check that the supplied msg.value is correct.\n // Supplied `msg.value` is already in FastBridgeV2 custody.\n if (amount != msg.value) revert MsgValueIncorrect();\n amountTaken = msg.value;\n } else {\n // For ERC20s, token is explicitly transferred from the user to FastBridgeV2.\n // We don't allow non-zero `msg.value` to avoid extra funds from being stuck in FastBridgeV2.\n token.assertIsContract();\n if (msg.value != 0) revert MsgValueIncorrect();\n amountTaken = IERC20(token).balanceOf(address(this));\n IERC20(token).safeTransferFrom(msg.sender, address(this), amount);\n // Use the balance difference as the amount taken in case of fee on transfer tokens.\n amountTaken = IERC20(token).balanceOf(address(this)) - amountTaken;\n }\n }\n\n /// @notice Calls the Recipient's hook function with the specified callParams and performs\n /// all the necessary checks for the returned value.\n function _checkedCallRecipient(\n address recipient,\n address token,\n uint256 amount,\n bytes memory callParams\n )\n internal\n {\n bytes memory hookData =\n abi.encodeCall(IFastBridgeRecipient.fastBridgeTransferReceived, (token, amount, callParams));\n // This will bubble any revert messages from the hook function\n bytes memory returnData = Address.functionCallWithValue({target: recipient, data: hookData, value: msg.value});\n // Explicit revert if no return data at all\n if (returnData.length == 0) revert RecipientNoReturnValue();\n // Check that exactly a single return value was returned\n if (returnData.length != 32) revert RecipientIncorrectReturnValue();\n // Return value should be abi-encoded hook function selector\n if (bytes32(returnData) != bytes32(IFastBridgeRecipient.fastBridgeTransferReceived.selector)) {\n revert RecipientIncorrectReturnValue();\n }\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint40(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint40).max but\n /// proof.timestamp \u003c type(uint40).max via unchecked statement\n /// @param proofBlockTimestamp The bridge proof block timestamp\n /// @return delta Time delta since proof submitted\n function _timeSince(uint40 proofBlockTimestamp) internal view returns (uint256 delta) {\n unchecked {\n delta = uint40(block.timestamp) - proofBlockTimestamp;\n }\n }\n\n /// @notice Performs all the necessary checks for a bridge to happen.\n /// @dev There's no good way to refactor this function to reduce cyclomatic complexity due to\n /// the number of checks that need to be performed, so we skip the code-complexity rule here.\n // solhint-disable-next-line code-complexity\n function _validateBridgeParams(\n BridgeParams memory params,\n BridgeParamsV2 memory paramsV2,\n int256 exclusivityEndTime\n )\n internal\n view\n {\n // Check V1 (legacy) params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.sender == address(0) || params.to == address(0)) revert ZeroAddress();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n // Check V2 params\n if (paramsV2.callParams.length \u003e MAX_CALL_PARAMS_LENGTH) revert CallParamsLengthAboveMax();\n if (paramsV2.callValue != 0 \u0026\u0026 params.destToken == UniversalTokenLib.ETH_ADDRESS) {\n revert NativeTokenCallValueNotSupported();\n }\n // exclusivityEndTime must be in range (0 .. params.deadline]\n if (exclusivityEndTime \u003c= 0 || exclusivityEndTime \u003e int256(params.deadline)) {\n revert ExclusivityParamsIncorrect();\n }\n }\n\n /// @notice Performs all the necessary checks for a relay to happen.\n function _validateRelayParams(\n BridgeTransactionV2 memory transaction,\n bytes32 transactionId,\n address relayer\n )\n internal\n view\n {\n if (relayer == address(0)) revert ZeroAddress();\n // Check if the transaction has already been relayed\n if (bridgeRelays(transactionId)) revert TransactionRelayed();\n if (transaction.destChainId != block.chainid) revert ChainIncorrect();\n // Check the deadline for relay to happen\n if (block.timestamp \u003e transaction.deadline) revert DeadlineExceeded();\n // Check the exclusivity period, if it is still ongoing\n // forgefmt: disable-next-item\n if (\n transaction.exclusivityRelayer != address(0) \u0026\u0026\n transaction.exclusivityRelayer != relayer \u0026\u0026\n block.timestamp \u003c= transaction.exclusivityEndTime\n ) {\n revert ExclusivityPeriodNotPassed();\n }\n }\n}\n","language":"Solidity","languageVersion":"0.8.24","compilerVersion":"0.8.24","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"","srcMapRuntime":"","abiDefinition":[{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"relayer","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"BridgeDepositClaimed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"BridgeDepositRefunded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"relayer","type":"address"}],"name":"BridgeProofDisputed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"relayer","type":"address"},{"indexed":false,"internalType":"bytes32","name":"transactionHash","type":"bytes32"}],"name":"BridgeProofProvided","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":false,"internalType":"bytes","name":"quoteId","type":"bytes"}],"name":"BridgeQuoteDetails","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"relayer","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint32","name":"originChainId","type":"uint32"},{"indexed":false,"internalType":"address","name":"originToken","type":"address"},{"indexed":false,"internalType":"address","name":"destToken","type":"address"},{"indexed":false,"internalType":"uint256","name":"originAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"destAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"chainGasAmount","type":"uint256"}],"name":"BridgeRelayed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"bytes","name":"request","type":"bytes"},{"indexed":false,"internalType":"uint32","name":"destChainId","type":"uint32"},{"indexed":false,"internalType":"address","name":"originToken","type":"address"},{"indexed":false,"internalType":"address","name":"destToken","type":"address"},{"indexed":false,"internalType":"uint256","name":"originAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"destAmount","type":"uint256"},{"indexed":false,"internalType":"bool","name":"sendChainGas","type":"bool"}],"name":"BridgeRequested","type":"event"},{"inputs":[{"components":[{"internalType":"uint32","name":"dstChainId","type":"uint32"},{"internalType":"address","name":"sender","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"address","name":"originToken","type":"address"},{"internalType":"address","name":"destToken","type":"address"},{"internalType":"uint256","name":"originAmount","type":"uint256"},{"internalType":"uint256","name":"destAmount","type":"uint256"},{"internalType":"bool","name":"sendChainGas","type":"bool"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"internalType":"struct IFastBridge.BridgeParams","name":"params","type":"tuple"}],"name":"bridge","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"uint32","name":"dstChainId","type":"uint32"},{"internalType":"address","name":"sender","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"address","name":"originToken","type":"address"},{"internalType":"address","name":"destToken","type":"address"},{"internalType":"uint256","name":"originAmount","type":"uint256"},{"internalType":"uint256","name":"destAmount","type":"uint256"},{"internalType":"bool","name":"sendChainGas","type":"bool"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"internalType":"struct IFastBridge.BridgeParams","name":"params","type":"tuple"},{"components":[{"internalType":"address","name":"quoteRelayer","type":"address"},{"internalType":"int256","name":"quoteExclusivitySeconds","type":"int256"},{"internalType":"bytes","name":"quoteId","type":"bytes"},{"internalType":"uint256","name":"callValue","type":"uint256"},{"internalType":"bytes","name":"callParams","type":"bytes"}],"internalType":"struct IFastBridgeV2.BridgeParamsV2","name":"paramsV2","type":"tuple"}],"name":"bridge","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"transactionId","type":"bytes32"}],"name":"bridgeProofs","outputs":[{"internalType":"uint96","name":"timestamp","type":"uint96"},{"internalType":"address","name":"relayer","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"transactionId","type":"bytes32"}],"name":"bridgeRelays","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"transactionId","type":"bytes32"}],"name":"bridgeStatuses","outputs":[{"internalType":"enum IFastBridgeV2.BridgeStatus","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"internalType":"address","name":"relayer","type":"address"}],"name":"canClaim","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"},{"internalType":"address","name":"to","type":"address"}],"name":"claim","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"}],"name":"claim","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"transactionId","type":"bytes32"}],"name":"dispute","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"}],"name":"getBridgeTransaction","outputs":[{"components":[{"internalType":"uint32","name":"originChainId","type":"uint32"},{"internalType":"uint32","name":"destChainId","type":"uint32"},{"internalType":"address","name":"originSender","type":"address"},{"internalType":"address","name":"destRecipient","type":"address"},{"internalType":"address","name":"originToken","type":"address"},{"internalType":"address","name":"destToken","type":"address"},{"internalType":"uint256","name":"originAmount","type":"uint256"},{"internalType":"uint256","name":"destAmount","type":"uint256"},{"internalType":"uint256","name":"originFeeAmount","type":"uint256"},{"internalType":"bool","name":"sendChainGas","type":"bool"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint256","name":"nonce","type":"uint256"}],"internalType":"struct IFastBridge.BridgeTransaction","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"}],"name":"getBridgeTransactionV2","outputs":[{"components":[{"internalType":"uint32","name":"originChainId","type":"uint32"},{"internalType":"uint32","name":"destChainId","type":"uint32"},{"internalType":"address","name":"originSender","type":"address"},{"internalType":"address","name":"destRecipient","type":"address"},{"internalType":"address","name":"originToken","type":"address"},{"internalType":"address","name":"destToken","type":"address"},{"internalType":"uint256","name":"originAmount","type":"uint256"},{"internalType":"uint256","name":"destAmount","type":"uint256"},{"internalType":"uint256","name":"originFeeAmount","type":"uint256"},{"internalType":"uint256","name":"callValue","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"address","name":"exclusivityRelayer","type":"address"},{"internalType":"uint256","name":"exclusivityEndTime","type":"uint256"},{"internalType":"bytes","name":"callParams","type":"bytes"}],"internalType":"struct IFastBridgeV2.BridgeTransactionV2","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"internalType":"bytes32","name":"destTxHash","type":"bytes32"},{"internalType":"address","name":"relayer","type":"address"}],"name":"prove","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"},{"internalType":"bytes32","name":"destTxHash","type":"bytes32"}],"name":"prove","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"}],"name":"refund","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"}],"name":"relay","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"},{"internalType":"address","name":"relayer","type":"address"}],"name":"relay","outputs":[],"stateMutability":"payable","type":"function"}],"userDoc":{"kind":"user","methods":{"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256))":{"notice":"Initiates bridge on origin chain to be relayed by off-chain relayer"},"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256),(address,int256,bytes,uint256,bytes))":{"notice":"Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability to provide temporary exclusivity fill rights for the quote relayer."},"bridgeProofs(bytes32)":{"notice":"Returns the timestamp and relayer of a bridge proof"},"bridgeRelays(bytes32)":{"notice":"Checks if a transaction has been relayed"},"bridgeStatuses(bytes32)":{"notice":"Returns the status of a bridge transaction"},"canClaim(bytes32,address)":{"notice":"Checks if the dispute period has passed so bridge deposit can be claimed"},"claim(bytes)":{"notice":"Completes bridge transaction on origin chain by claiming originally deposited capital.Can only send funds to the relayer address on the proof."},"claim(bytes,address)":{"notice":"Completes bridge transaction on origin chain by claiming originally deposited capital"},"dispute(bytes32)":{"notice":"Disputes an outstanding proof in case relayer provided dest chain tx is invalid"},"getBridgeTransaction(bytes)":{"notice":"Decodes bridge request into a bridge transaction"},"getBridgeTransactionV2(bytes)":{"notice":"Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2"},"prove(bytes,bytes32)":{"notice":"Provides proof on origin side that relayer provided funds on destination side of bridge transaction"},"prove(bytes32,bytes32,address)":{"notice":"Provides proof on origin side that relayer provided funds on destination side of bridge transaction"},"refund(bytes)":{"notice":"Refunds an outstanding bridge transaction in case optimistic bridging failed"},"relay(bytes)":{"notice":"Relays destination side of bridge transaction by off-chain relayer"},"relay(bytes,address)":{"notice":"Relays destination side of bridge transaction by off-chain relayer"}},"version":1},"developerDoc":{"kind":"dev","methods":{"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256))":{"params":{"params":"The parameters required to bridge"}},"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256),(address,int256,bytes,uint256,bytes))":{"params":{"params":"The parameters required to bridge","paramsV2":"The parameters for exclusivity fill rights (optional, can be left empty)"}},"bridgeProofs(bytes32)":{"params":{"transactionId":"The ID of the bridge transaction"},"returns":{"relayer":"The relayer address of the bridge proof","timestamp":"The timestamp of the bridge proof"}},"bridgeRelays(bytes32)":{"params":{"transactionId":"The ID of the transaction to check"},"returns":{"_0":"True if the transaction has been relayed, false otherwise"}},"bridgeStatuses(bytes32)":{"params":{"transactionId":"The ID of the bridge transaction"},"returns":{"_0":"BridgeStatus Status of the bridge transaction"}},"canClaim(bytes32,address)":{"params":{"relayer":"The address of the relayer attempting to claim","transactionId":"The transaction id associated with the encoded bridge transaction to check"}},"claim(bytes)":{"params":{"request":"The encoded bridge transaction to claim on origin chain"}},"claim(bytes,address)":{"params":{"request":"The encoded bridge transaction to claim on origin chain","to":"The recipient address of the funds"}},"dispute(bytes32)":{"params":{"transactionId":"The transaction id associated with the encoded bridge transaction to dispute"}},"getBridgeTransaction(bytes)":{"params":{"request":"The bridge request to decode"}},"getBridgeTransactionV2(bytes)":{"params":{"request":"The bridge request to decode"}},"prove(bytes,bytes32)":{"params":{"destTxHash":"The destination tx hash proving bridge transaction was relayed","request":"The encoded bridge transaction to prove on origin chain"}},"prove(bytes32,bytes32,address)":{"params":{"destTxHash":"The destination tx hash proving bridge transaction was relayed","relayer":"The address of the relaying entity which should have control of the origin funds when claimed","transactionId":"The transaction id associated with the encoded bridge transaction to prove"}},"refund(bytes)":{"params":{"request":"The encoded bridge transaction to refund"}},"relay(bytes)":{"params":{"request":"The encoded bridge transaction to relay on destination chain"}},"relay(bytes,address)":{"params":{"relayer":"The address of the relaying entity which should have control of the origin funds when claimed","request":"The encoded bridge transaction to relay on destination chain"}}},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"BridgeDepositClaimed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"BridgeDepositRefunded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"name\":\"BridgeProofDisputed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"transactionHash\",\"type\":\"bytes32\"}],\"name\":\"BridgeProofProvided\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"quoteId\",\"type\":\"bytes\"}],\"name\":\"BridgeQuoteDetails\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"originChainId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"chainGasAmount\",\"type\":\"uint256\"}],\"name\":\"BridgeRelayed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"destChainId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"sendChainGas\",\"type\":\"bool\"}],\"name\":\"BridgeRequested\",\"type\":\"event\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"dstChainId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"sendChainGas\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"}],\"internalType\":\"struct IFastBridge.BridgeParams\",\"name\":\"params\",\"type\":\"tuple\"}],\"name\":\"bridge\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"dstChainId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"sendChainGas\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"}],\"internalType\":\"struct IFastBridge.BridgeParams\",\"name\":\"params\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"quoteRelayer\",\"type\":\"address\"},{\"internalType\":\"int256\",\"name\":\"quoteExclusivitySeconds\",\"type\":\"int256\"},{\"internalType\":\"bytes\",\"name\":\"quoteId\",\"type\":\"bytes\"},{\"internalType\":\"uint256\",\"name\":\"callValue\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"callParams\",\"type\":\"bytes\"}],\"internalType\":\"struct IFastBridgeV2.BridgeParamsV2\",\"name\":\"paramsV2\",\"type\":\"tuple\"}],\"name\":\"bridge\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"}],\"name\":\"bridgeProofs\",\"outputs\":[{\"internalType\":\"uint96\",\"name\":\"timestamp\",\"type\":\"uint96\"},{\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"}],\"name\":\"bridgeRelays\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"}],\"name\":\"bridgeStatuses\",\"outputs\":[{\"internalType\":\"enum IFastBridgeV2.BridgeStatus\",\"name\":\"\",\"type\":\"uint8\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"name\":\"canClaim\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"claim\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"claim\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"}],\"name\":\"dispute\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"getBridgeTransaction\",\"outputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"originChainId\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"destChainId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"originSender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destRecipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"originFeeAmount\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"sendChainGas\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"}],\"internalType\":\"struct IFastBridge.BridgeTransaction\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"getBridgeTransactionV2\",\"outputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"originChainId\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"destChainId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"originSender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destRecipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"originFeeAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"callValue\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"exclusivityRelayer\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"exclusivityEndTime\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"callParams\",\"type\":\"bytes\"}],\"internalType\":\"struct IFastBridgeV2.BridgeTransactionV2\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"destTxHash\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"name\":\"prove\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"},{\"internalType\":\"bytes32\",\"name\":\"destTxHash\",\"type\":\"bytes32\"}],\"name\":\"prove\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"refund\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"relay\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"},{\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"name\":\"relay\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{\"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256))\":{\"params\":{\"params\":\"The parameters required to bridge\"}},\"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256),(address,int256,bytes,uint256,bytes))\":{\"params\":{\"params\":\"The parameters required to bridge\",\"paramsV2\":\"The parameters for exclusivity fill rights (optional, can be left empty)\"}},\"bridgeProofs(bytes32)\":{\"params\":{\"transactionId\":\"The ID of the bridge transaction\"},\"returns\":{\"relayer\":\"The relayer address of the bridge proof\",\"timestamp\":\"The timestamp of the bridge proof\"}},\"bridgeRelays(bytes32)\":{\"params\":{\"transactionId\":\"The ID of the transaction to check\"},\"returns\":{\"_0\":\"True if the transaction has been relayed, false otherwise\"}},\"bridgeStatuses(bytes32)\":{\"params\":{\"transactionId\":\"The ID of the bridge transaction\"},\"returns\":{\"_0\":\"BridgeStatus Status of the bridge transaction\"}},\"canClaim(bytes32,address)\":{\"params\":{\"relayer\":\"The address of the relayer attempting to claim\",\"transactionId\":\"The transaction id associated with the encoded bridge transaction to check\"}},\"claim(bytes)\":{\"params\":{\"request\":\"The encoded bridge transaction to claim on origin chain\"}},\"claim(bytes,address)\":{\"params\":{\"request\":\"The encoded bridge transaction to claim on origin chain\",\"to\":\"The recipient address of the funds\"}},\"dispute(bytes32)\":{\"params\":{\"transactionId\":\"The transaction id associated with the encoded bridge transaction to dispute\"}},\"getBridgeTransaction(bytes)\":{\"params\":{\"request\":\"The bridge request to decode\"}},\"getBridgeTransactionV2(bytes)\":{\"params\":{\"request\":\"The bridge request to decode\"}},\"prove(bytes,bytes32)\":{\"params\":{\"destTxHash\":\"The destination tx hash proving bridge transaction was relayed\",\"request\":\"The encoded bridge transaction to prove on origin chain\"}},\"prove(bytes32,bytes32,address)\":{\"params\":{\"destTxHash\":\"The destination tx hash proving bridge transaction was relayed\",\"relayer\":\"The address of the relaying entity which should have control of the origin funds when claimed\",\"transactionId\":\"The transaction id associated with the encoded bridge transaction to prove\"}},\"refund(bytes)\":{\"params\":{\"request\":\"The encoded bridge transaction to refund\"}},\"relay(bytes)\":{\"params\":{\"request\":\"The encoded bridge transaction to relay on destination chain\"}},\"relay(bytes,address)\":{\"params\":{\"relayer\":\"The address of the relaying entity which should have control of the origin funds when claimed\",\"request\":\"The encoded bridge transaction to relay on destination chain\"}}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256))\":{\"notice\":\"Initiates bridge on origin chain to be relayed by off-chain relayer\"},\"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256),(address,int256,bytes,uint256,bytes))\":{\"notice\":\"Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability to provide temporary exclusivity fill rights for the quote relayer.\"},\"bridgeProofs(bytes32)\":{\"notice\":\"Returns the timestamp and relayer of a bridge proof\"},\"bridgeRelays(bytes32)\":{\"notice\":\"Checks if a transaction has been relayed\"},\"bridgeStatuses(bytes32)\":{\"notice\":\"Returns the status of a bridge transaction\"},\"canClaim(bytes32,address)\":{\"notice\":\"Checks if the dispute period has passed so bridge deposit can be claimed\"},\"claim(bytes)\":{\"notice\":\"Completes bridge transaction on origin chain by claiming originally deposited capital.Can only send funds to the relayer address on the proof.\"},\"claim(bytes,address)\":{\"notice\":\"Completes bridge transaction on origin chain by claiming originally deposited capital\"},\"dispute(bytes32)\":{\"notice\":\"Disputes an outstanding proof in case relayer provided dest chain tx is invalid\"},\"getBridgeTransaction(bytes)\":{\"notice\":\"Decodes bridge request into a bridge transaction\"},\"getBridgeTransactionV2(bytes)\":{\"notice\":\"Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\"},\"prove(bytes,bytes32)\":{\"notice\":\"Provides proof on origin side that relayer provided funds on destination side of bridge transaction\"},\"prove(bytes32,bytes32,address)\":{\"notice\":\"Provides proof on origin side that relayer provided funds on destination side of bridge transaction\"},\"refund(bytes)\":{\"notice\":\"Refunds an outstanding bridge transaction in case optimistic bridging failed\"},\"relay(bytes)\":{\"notice\":\"Relays destination side of bridge transaction by off-chain relayer\"},\"relay(bytes,address)\":{\"notice\":\"Relays destination side of bridge transaction by off-chain relayer\"}},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeV2.sol\":\"IFastBridgeV2\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeV2.sol\":{\"keccak256\":\"0xfd916c030b1ffca5a136817827b8018c8ba42ca089905747f3de6148b73eb35e\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://18e6438c4096deb8ae453fb3365ba2b07d52944e93c08288fc5d012b71bf6bb3\",\"dweb:/ipfs/QmfEMqpT1zz6RRm7UuHLRowe1tds2cTGLrVonfm9XSCACj\"]}},\"version\":1}"},"hashes":{"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256))":"45851694","bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256),(address,int256,bytes,uint256,bytes))":"bfc7c607","bridgeProofs(bytes32)":"91ad5039","bridgeRelays(bytes32)":"8379a24f","bridgeStatuses(bytes32)":"051287bc","canClaim(bytes32,address)":"aa9641ab","claim(bytes)":"c63ff8dd","claim(bytes,address)":"41fcb612","dispute(bytes32)":"add98c70","getBridgeTransaction(bytes)":"ac11fb1a","getBridgeTransactionV2(bytes)":"5aa6ccba","prove(bytes,bytes32)":"886d36ff","prove(bytes32,bytes32,address)":"18e4357d","refund(bytes)":"5eb7d946","relay(bytes)":"8f0d6f17","relay(bytes,address)":"9c9545f0"}},"solidity/FastBridgeV2.sol:IFastBridgeV2Errors":{"code":"0x","runtime-code":"0x","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.24 ^0.8.0 ^0.8.20;\n\n// contracts/interfaces/IAdmin.sol\n\ninterface IAdmin {\n // ============ Events ============\n\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n event ChainGasAmountUpdated(uint256 oldChainGasAmount, uint256 newChainGasAmount);\n\n // ============ Methods ============\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n\n function setChainGasAmount(uint256 newChainGasAmount) external;\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IFastBridgeRecipient.sol\n\ninterface IFastBridgeRecipient {\n function fastBridgeTransferReceived(\n address token,\n uint256 amount,\n bytes memory callParams\n )\n external\n payable\n returns (bytes4);\n}\n\n// contracts/interfaces/IFastBridgeV2Errors.sol\n\ninterface IFastBridgeV2Errors {\n error AmountIncorrect();\n error CallParamsLengthAboveMax();\n error ChainIncorrect();\n error ExclusivityParamsIncorrect();\n error MsgValueIncorrect();\n error NativeTokenCallValueNotSupported();\n error SenderIncorrect();\n error StatusIncorrect();\n error ZeroAddress();\n\n error RecipientIncorrectReturnValue();\n error RecipientNoReturnValue();\n\n error DeadlineExceeded();\n error DeadlineNotExceeded();\n error DeadlineTooShort();\n error DisputePeriodNotPassed();\n error DisputePeriodPassed();\n error ExclusivityPeriodNotPassed();\n\n error TransactionRelayed();\n}\n\n// contracts/libs/Errors.sol\n\nerror DeadlineExceeded();\nerror DeadlineNotExceeded();\nerror DeadlineTooShort();\nerror InsufficientOutputAmount();\n\nerror MsgValueIncorrect();\nerror PoolNotFound();\nerror TokenAddressMismatch();\nerror TokenNotContract();\nerror TokenNotETH();\nerror TokensIdentical();\n\nerror ChainIncorrect();\nerror AmountIncorrect();\nerror ZeroAddress();\n\nerror DisputePeriodNotPassed();\nerror DisputePeriodPassed();\nerror SenderIncorrect();\nerror StatusIncorrect();\nerror TransactionIdIncorrect();\nerror TransactionRelayed();\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// contracts/interfaces/IFastBridgeV2.sol\n\ninterface IFastBridgeV2 is IFastBridge {\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n struct BridgeTxDetails {\n BridgeStatus status;\n uint40 proofBlockTimestamp;\n uint48 proofBlockNumber;\n address proofRelayer;\n }\n\n struct BridgeRelay {\n uint48 blockNumber;\n uint48 blockTimestamp;\n address relayer;\n }\n\n /// @notice New params introduced in the FastBridgeV2.\n /// We are passing fields from the older BridgeParams struct outside of this struct\n /// for backwards compatibility.\n /// Note: quoteRelayer and quoteExclusivitySeconds are either both zero (indicating no exclusivity)\n /// or both non-zero (indicating exclusivity for the given period).\n /// Note: callValue \u003e 0 can NOT be used with destToken = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE (ETH_ADDRESS)\n /// @param quoteRelayer Relayer that provided the quote for the transaction\n /// @param quoteExclusivitySeconds Period of time the quote relayer is guaranteed exclusivity after user's deposit\n /// @param quoteId Unique quote identifier used for tracking the quote\n /// @param callValue ETH value to send to the recipient (if any)\n /// @param callParams Parameters for the arbitrary call to the destination recipient (if any)\n struct BridgeParamsV2 {\n address quoteRelayer;\n int256 quoteExclusivitySeconds;\n bytes quoteId;\n uint256 callValue;\n bytes callParams;\n }\n\n /// @notice Updated bridge transaction struct to include parameters introduced in FastBridgeV2.\n /// Note: only `exclusivityRelayer` can fill such a transaction until `exclusivityEndTime`.\n /// TODO: consider changing the encoding scheme to prevent spending extra gas on decoding.\n struct BridgeTransactionV2 {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n uint256 callValue; // ETH value to send to the recipient (if any) - replaces V1's sendChainGas flag\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n address exclusivityRelayer;\n uint256 exclusivityEndTime;\n bytes callParams;\n }\n\n event BridgeQuoteDetails(bytes32 indexed transactionId, bytes quoteId);\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability\n /// to provide temporary exclusivity fill rights for the quote relayer.\n /// @param params The parameters required to bridge\n /// @param paramsV2 The parameters for exclusivity fill rights (optional, can be left empty)\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function relay(bytes memory request, address relayer) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param transactionId The transaction id associated with the encoded bridge transaction to prove\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital.\n /// @notice Can only send funds to the relayer address on the proof.\n /// @param request The encoded bridge transaction to claim on origin chain\n function claim(bytes memory request) external;\n /// @notice Checks if a transaction has been relayed\n /// @param transactionId The ID of the transaction to check\n /// @return True if the transaction has been relayed, false otherwise\n function bridgeRelays(bytes32 transactionId) external view returns (bool);\n\n /// @notice Returns the status of a bridge transaction\n /// @param transactionId The ID of the bridge transaction\n /// @return BridgeStatus Status of the bridge transaction\n function bridgeStatuses(bytes32 transactionId) external view returns (BridgeStatus);\n\n /// @notice Returns the timestamp and relayer of a bridge proof\n /// @param transactionId The ID of the bridge transaction\n /// @return timestamp The timestamp of the bridge proof\n /// @return relayer The relayer address of the bridge proof\n function bridgeProofs(bytes32 transactionId) external view returns (uint96 timestamp, address relayer);\n\n /// @notice Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\n /// @param request The bridge request to decode\n function getBridgeTransactionV2(bytes memory request) external view returns (BridgeTransactionV2 memory);\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// contracts/libs/UniversalToken.sol\n\nlibrary UniversalTokenLib {\n using SafeERC20 for IERC20;\n\n address internal constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Transfers tokens to the given account. Reverts if transfer is not successful.\n /// @dev This might trigger fallback, if ETH is transferred to the contract.\n /// Make sure this can not lead to reentrancy attacks.\n function universalTransfer(address token, address to, uint256 value) internal {\n // Don't do anything, if need to send tokens to this address\n if (to == address(this)) return;\n // Don't do anything, if trying to send zero value\n if (value == 0) return;\n if (token == ETH_ADDRESS) {\n /// @dev Note: this can potentially lead to executing code in `to`.\n // solhint-disable-next-line avoid-low-level-calls\n (bool success,) = to.call{value: value}(\"\");\n require(success, \"ETH transfer failed\");\n } else {\n IERC20(token).safeTransfer(to, value);\n }\n }\n\n /// @notice Issues an infinite allowance to the spender, if the current allowance is insufficient\n /// to spend the given amount.\n function universalApproveInfinity(address token, address spender, uint256 amountToSpend) internal {\n // ETH Chad doesn't require your approval\n if (token == ETH_ADDRESS) return;\n // No-op if allowance is already sufficient\n uint256 allowance = IERC20(token).allowance(address(this), spender);\n if (allowance \u003e= amountToSpend) return;\n // Otherwise, reset approval to 0 and set to max allowance\n if (allowance \u003e 0) IERC20(token).safeDecreaseAllowance(spender, allowance);\n IERC20(token).safeIncreaseAllowance(spender, type(uint256).max);\n }\n\n /// @notice Returns the balance of the given token (or native ETH) for the given account.\n function universalBalanceOf(address token, address account) internal view returns (uint256) {\n if (token == ETH_ADDRESS) {\n return account.balance;\n } else {\n return IERC20(token).balanceOf(account);\n }\n }\n\n /// @dev Checks that token is a contract and not ETH_ADDRESS.\n function assertIsContract(address token) internal view {\n // Check that ETH_ADDRESS was not used (in case this is a predeploy on any of the chains)\n if (token == UniversalTokenLib.ETH_ADDRESS) revert TokenNotContract();\n // Check that token is not an EOA\n if (token.code.length == 0) revert TokenNotContract();\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/Admin.sol\n\ncontract Admin is IAdmin, AccessControlEnumerable {\n using UniversalTokenLib for address;\n\n bytes32 public constant RELAYER_ROLE = keccak256(\"RELAYER_ROLE\");\n bytes32 public constant REFUNDER_ROLE = keccak256(\"REFUNDER_ROLE\");\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n uint256 public constant FEE_BPS = 1e6;\n uint256 public constant FEE_RATE_MAX = 0.01e6; // max 1% on origin amount\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Chain gas amount to forward as rebate if requested\n uint256 public chainGasAmount;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n }\n\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n require(newFeeRate \u003c= FEE_RATE_MAX, \"newFeeRate \u003e max\");\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n token.universalTransfer(recipient, feeAmount);\n emit FeesSwept(token, recipient, feeAmount);\n }\n\n function setChainGasAmount(uint256 newChainGasAmount) external onlyRole(GOVERNOR_ROLE) {\n uint256 oldChainGasAmount = chainGasAmount;\n chainGasAmount = newChainGasAmount;\n emit ChainGasAmountUpdated(oldChainGasAmount, newChainGasAmount);\n }\n}\n\n// contracts/FastBridgeV2.sol\n\n/// @notice FastBridgeV2 is a contract for bridging tokens across chains.\ncontract FastBridgeV2 is Admin, IFastBridgeV2, IFastBridgeV2Errors {\n using SafeERC20 for IERC20;\n using UniversalTokenLib for address;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Delay for a transaction after which it could be permisionlessly refunded\n uint256 public constant REFUND_DELAY = 7 days;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n /// @notice Maximum length of accepted callParams\n uint256 public constant MAX_CALL_PARAMS_LENGTH = 2 ** 16 - 1;\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeTxDetails) public bridgeTxDetails;\n /// @notice Relay details on destination chain\n mapping(bytes32 =\u003e BridgeRelay) public bridgeRelayDetails;\n /// @notice Unique bridge nonces tracked per originSender\n mapping(address =\u003e uint256) public senderNonces;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Replaced by senderNonces\n uint256 public immutable nonce = 0;\n /// @notice the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n bridge({\n params: params,\n paramsV2: BridgeParamsV2({\n quoteRelayer: address(0),\n quoteExclusivitySeconds: 0,\n quoteId: bytes(\"\"),\n callValue: 0,\n callParams: bytes(\"\")\n })\n });\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes memory request) external payable {\n relay({request: request, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes memory request, bytes32 destTxHash) external {\n prove({transactionId: keccak256(request), destTxHash: destTxHash, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridgeV2\n function claim(bytes memory request) external {\n claim({request: request, to: address(0)});\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003e DISPUTE_PERIOD) {\n revert DisputePeriodPassed();\n }\n\n // @dev relayer gets slashed effectively if dest relay has gone thru\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n bridgeTxDetails[transactionId].proofRelayer = address(0);\n bridgeTxDetails[transactionId].proofBlockTimestamp = 0;\n bridgeTxDetails[transactionId].proofBlockNumber = 0;\n\n emit BridgeProofDisputed(transactionId, msg.sender);\n }\n\n /// @inheritdoc IFastBridge\n function refund(bytes memory request) external {\n bytes32 transactionId = keccak256(request);\n\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n\n if (bridgeTxDetails[transactionId].status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n\n if (hasRole(REFUNDER_ROLE, msg.sender)) {\n // Refunder can refund if deadline has passed\n if (block.timestamp \u003c= transaction.deadline) revert DeadlineNotExceeded();\n } else {\n // Permissionless refund is allowed after REFUND_DELAY\n if (block.timestamp \u003c= transaction.deadline + REFUND_DELAY) revert DeadlineNotExceeded();\n }\n\n // if all checks passed, set to REFUNDED status\n bridgeTxDetails[transactionId].status = BridgeStatus.REFUNDED;\n\n // transfer origin collateral back to original sender\n address to = transaction.originSender;\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount + transaction.originFeeAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (bridgeTxDetails[transactionId].proofRelayer != relayer) revert SenderIncorrect();\n return _timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n /// @dev This method is added to achieve backwards compatibility with decoding requests into V1 structs:\n /// - `callValue` is partially reported as a zero/non-zero flag\n /// - `callParams` is ignored\n /// In order to process all kinds of requests use getBridgeTransactionV2 instead.\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory) {\n // Try decoding into V2 struct first. This will revert if V1 struct is passed\n try this.getBridgeTransactionV2(request) returns (BridgeTransactionV2 memory txV2) {\n // Note: we entirely ignore the callParams field, as it was not present in V1\n return BridgeTransaction({\n originChainId: txV2.originChainId,\n destChainId: txV2.destChainId,\n originSender: txV2.originSender,\n destRecipient: txV2.destRecipient,\n originToken: txV2.originToken,\n destToken: txV2.destToken,\n originAmount: txV2.originAmount,\n destAmount: txV2.destAmount,\n originFeeAmount: txV2.originFeeAmount,\n sendChainGas: txV2.callValue != 0,\n deadline: txV2.deadline,\n nonce: txV2.nonce\n });\n } catch {\n // Fallback to V1 struct\n return abi.decode(request, (BridgeTransaction));\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) public payable {\n int256 exclusivityEndTime = int256(block.timestamp) + paramsV2.quoteExclusivitySeconds;\n _validateBridgeParams(params, paramsV2, exclusivityEndTime);\n\n // transfer tokens to bridge contract\n /// @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _takeBridgedUserAsset(params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n\n // set status to requested\n bytes memory request = abi.encode(\n BridgeTransactionV2({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n callValue: paramsV2.callValue,\n deadline: params.deadline,\n nonce: senderNonces[params.sender]++, // increment nonce on every bridge\n exclusivityRelayer: paramsV2.quoteRelayer,\n // We checked exclusivityEndTime to be in range (0 .. params.deadline] above, so can safely cast\n exclusivityEndTime: uint256(exclusivityEndTime),\n callParams: paramsV2.callParams\n })\n );\n bytes32 transactionId = keccak256(request);\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n\n emit BridgeRequested({\n transactionId: transactionId,\n sender: params.sender,\n request: request,\n destChainId: params.dstChainId,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n sendChainGas: paramsV2.callValue != 0\n });\n emit BridgeQuoteDetails(transactionId, paramsV2.quoteId);\n }\n\n /// @inheritdoc IFastBridgeV2\n function relay(bytes memory request, address relayer) public payable {\n bytes32 transactionId = keccak256(request);\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n _validateRelayParams(transaction, transactionId, relayer);\n // mark bridge transaction as relayed\n bridgeRelayDetails[transactionId] =\n BridgeRelay({blockNumber: uint48(block.number), blockTimestamp: uint48(block.timestamp), relayer: relayer});\n\n // transfer tokens to recipient on destination chain and do an arbitrary call if requested\n address to = transaction.destRecipient;\n address token = transaction.destToken;\n uint256 amount = transaction.destAmount;\n uint256 callValue = transaction.callValue;\n\n // Emit the event before any external calls\n emit BridgeRelayed({\n transactionId: transactionId,\n relayer: relayer,\n to: to,\n originChainId: transaction.originChainId,\n originToken: transaction.originToken,\n destToken: token,\n originAmount: transaction.originAmount,\n destAmount: amount,\n chainGasAmount: callValue\n });\n\n // All state changes have been done at this point, can proceed to the external calls.\n // This follows the checks-effects-interactions pattern to mitigate potential reentrancy attacks.\n if (token == UniversalTokenLib.ETH_ADDRESS) {\n // For ETH non-zero callValue is not allowed\n if (callValue != 0) revert NativeTokenCallValueNotSupported();\n // Check that the correct msg.value was sent\n if (msg.value != amount) revert MsgValueIncorrect();\n } else {\n // For ERC20s, we check that the correct msg.value was sent\n if (msg.value != callValue) revert MsgValueIncorrect();\n // We need to transfer the tokens from the Relayer to the recipient first before performing an\n // optional post-transfer arbitrary call.\n IERC20(token).safeTransferFrom(msg.sender, to, amount);\n }\n\n if (transaction.callParams.length != 0) {\n // Arbitrary call requested, perform it while supplying full msg.value to the recipient\n // Note: if token has a fee on transfers, the recipient will have received less than `amount`.\n // This is a very niche edge case and should be handled by the recipient contract.\n _checkedCallRecipient({recipient: to, token: token, amount: amount, callParams: transaction.callParams});\n } else if (msg.value != 0) {\n // No arbitrary call requested, but msg.value was sent. This is either a relay with ETH,\n // or a non-zero callValue request with an ERC20. In both cases, transfer the ETH to the recipient.\n Address.sendValue(payable(to), msg.value);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) public onlyRole(RELAYER_ROLE) {\n // update bridge tx status given proof provided\n if (bridgeTxDetails[transactionId].status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n bridgeTxDetails[transactionId].status = BridgeStatus.RELAYER_PROVED;\n bridgeTxDetails[transactionId].proofBlockTimestamp = uint40(block.timestamp);\n bridgeTxDetails[transactionId].proofBlockNumber = uint48(block.number);\n bridgeTxDetails[transactionId].proofRelayer = relayer;\n\n emit BridgeProofProvided(transactionId, relayer, destTxHash);\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes memory request, address to) public {\n bytes32 transactionId = keccak256(request);\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n\n // update bridge tx status if able to claim origin collateral\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n\n // if \"to\" is zero addr, permissionlessly send funds to proven relayer\n if (to == address(0)) {\n to = bridgeTxDetails[transactionId].proofRelayer;\n } else if (bridgeTxDetails[transactionId].proofRelayer != msg.sender) {\n revert SenderIncorrect();\n }\n\n if (_timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003c= DISPUTE_PERIOD) {\n revert DisputePeriodNotPassed();\n }\n\n bridgeTxDetails[transactionId].status = BridgeStatus.RELAYER_CLAIMED;\n\n // update protocol fees if origin fee amount exists\n if (transaction.originFeeAmount \u003e 0) protocolFees[transaction.originToken] += transaction.originFeeAmount;\n\n // transfer origin collateral less fee to specified address\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositClaimed(transactionId, bridgeTxDetails[transactionId].proofRelayer, to, token, amount);\n }\n\n function bridgeStatuses(bytes32 transactionId) public view returns (BridgeStatus status) {\n return bridgeTxDetails[transactionId].status;\n }\n\n function bridgeProofs(bytes32 transactionId) public view returns (uint96 timestamp, address relayer) {\n timestamp = bridgeTxDetails[transactionId].proofBlockTimestamp;\n relayer = bridgeTxDetails[transactionId].proofRelayer;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeRelays(bytes32 transactionId) public view returns (bool) {\n // has this transactionId been relayed?\n return bridgeRelayDetails[transactionId].relayer != address(0);\n }\n\n /// @inheritdoc IFastBridgeV2\n function getBridgeTransactionV2(bytes memory request) public pure returns (BridgeTransactionV2 memory) {\n return abi.decode(request, (BridgeTransactionV2));\n }\n\n /// @notice Takes the bridged asset from the user into FastBridgeV2 custody. It will be later\n /// claimed by the relayer who completed the relay on destination chain, or refunded back to the user,\n /// should no one complete the relay.\n function _takeBridgedUserAsset(address token, uint256 amount) internal returns (uint256 amountTaken) {\n if (token == UniversalTokenLib.ETH_ADDRESS) {\n // For ETH we just need to check that the supplied msg.value is correct.\n // Supplied `msg.value` is already in FastBridgeV2 custody.\n if (amount != msg.value) revert MsgValueIncorrect();\n amountTaken = msg.value;\n } else {\n // For ERC20s, token is explicitly transferred from the user to FastBridgeV2.\n // We don't allow non-zero `msg.value` to avoid extra funds from being stuck in FastBridgeV2.\n token.assertIsContract();\n if (msg.value != 0) revert MsgValueIncorrect();\n amountTaken = IERC20(token).balanceOf(address(this));\n IERC20(token).safeTransferFrom(msg.sender, address(this), amount);\n // Use the balance difference as the amount taken in case of fee on transfer tokens.\n amountTaken = IERC20(token).balanceOf(address(this)) - amountTaken;\n }\n }\n\n /// @notice Calls the Recipient's hook function with the specified callParams and performs\n /// all the necessary checks for the returned value.\n function _checkedCallRecipient(\n address recipient,\n address token,\n uint256 amount,\n bytes memory callParams\n )\n internal\n {\n bytes memory hookData =\n abi.encodeCall(IFastBridgeRecipient.fastBridgeTransferReceived, (token, amount, callParams));\n // This will bubble any revert messages from the hook function\n bytes memory returnData = Address.functionCallWithValue({target: recipient, data: hookData, value: msg.value});\n // Explicit revert if no return data at all\n if (returnData.length == 0) revert RecipientNoReturnValue();\n // Check that exactly a single return value was returned\n if (returnData.length != 32) revert RecipientIncorrectReturnValue();\n // Return value should be abi-encoded hook function selector\n if (bytes32(returnData) != bytes32(IFastBridgeRecipient.fastBridgeTransferReceived.selector)) {\n revert RecipientIncorrectReturnValue();\n }\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint40(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint40).max but\n /// proof.timestamp \u003c type(uint40).max via unchecked statement\n /// @param proofBlockTimestamp The bridge proof block timestamp\n /// @return delta Time delta since proof submitted\n function _timeSince(uint40 proofBlockTimestamp) internal view returns (uint256 delta) {\n unchecked {\n delta = uint40(block.timestamp) - proofBlockTimestamp;\n }\n }\n\n /// @notice Performs all the necessary checks for a bridge to happen.\n /// @dev There's no good way to refactor this function to reduce cyclomatic complexity due to\n /// the number of checks that need to be performed, so we skip the code-complexity rule here.\n // solhint-disable-next-line code-complexity\n function _validateBridgeParams(\n BridgeParams memory params,\n BridgeParamsV2 memory paramsV2,\n int256 exclusivityEndTime\n )\n internal\n view\n {\n // Check V1 (legacy) params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.sender == address(0) || params.to == address(0)) revert ZeroAddress();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n // Check V2 params\n if (paramsV2.callParams.length \u003e MAX_CALL_PARAMS_LENGTH) revert CallParamsLengthAboveMax();\n if (paramsV2.callValue != 0 \u0026\u0026 params.destToken == UniversalTokenLib.ETH_ADDRESS) {\n revert NativeTokenCallValueNotSupported();\n }\n // exclusivityEndTime must be in range (0 .. params.deadline]\n if (exclusivityEndTime \u003c= 0 || exclusivityEndTime \u003e int256(params.deadline)) {\n revert ExclusivityParamsIncorrect();\n }\n }\n\n /// @notice Performs all the necessary checks for a relay to happen.\n function _validateRelayParams(\n BridgeTransactionV2 memory transaction,\n bytes32 transactionId,\n address relayer\n )\n internal\n view\n {\n if (relayer == address(0)) revert ZeroAddress();\n // Check if the transaction has already been relayed\n if (bridgeRelays(transactionId)) revert TransactionRelayed();\n if (transaction.destChainId != block.chainid) revert ChainIncorrect();\n // Check the deadline for relay to happen\n if (block.timestamp \u003e transaction.deadline) revert DeadlineExceeded();\n // Check the exclusivity period, if it is still ongoing\n // forgefmt: disable-next-item\n if (\n transaction.exclusivityRelayer != address(0) \u0026\u0026\n transaction.exclusivityRelayer != relayer \u0026\u0026\n block.timestamp \u003c= transaction.exclusivityEndTime\n ) {\n revert ExclusivityPeriodNotPassed();\n }\n }\n}\n","language":"Solidity","languageVersion":"0.8.24","compilerVersion":"0.8.24","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"","srcMapRuntime":"","abiDefinition":[{"inputs":[],"name":"AmountIncorrect","type":"error"},{"inputs":[],"name":"CallParamsLengthAboveMax","type":"error"},{"inputs":[],"name":"ChainIncorrect","type":"error"},{"inputs":[],"name":"DeadlineExceeded","type":"error"},{"inputs":[],"name":"DeadlineNotExceeded","type":"error"},{"inputs":[],"name":"DeadlineTooShort","type":"error"},{"inputs":[],"name":"DisputePeriodNotPassed","type":"error"},{"inputs":[],"name":"DisputePeriodPassed","type":"error"},{"inputs":[],"name":"ExclusivityParamsIncorrect","type":"error"},{"inputs":[],"name":"ExclusivityPeriodNotPassed","type":"error"},{"inputs":[],"name":"MsgValueIncorrect","type":"error"},{"inputs":[],"name":"NativeTokenCallValueNotSupported","type":"error"},{"inputs":[],"name":"RecipientIncorrectReturnValue","type":"error"},{"inputs":[],"name":"RecipientNoReturnValue","type":"error"},{"inputs":[],"name":"SenderIncorrect","type":"error"},{"inputs":[],"name":"StatusIncorrect","type":"error"},{"inputs":[],"name":"TransactionRelayed","type":"error"},{"inputs":[],"name":"ZeroAddress","type":"error"}],"userDoc":{"kind":"user","methods":{},"version":1},"developerDoc":{"kind":"dev","methods":{},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[],\"name\":\"AmountIncorrect\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"CallParamsLengthAboveMax\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ChainIncorrect\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DeadlineExceeded\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DeadlineNotExceeded\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DeadlineTooShort\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DisputePeriodNotPassed\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DisputePeriodPassed\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ExclusivityParamsIncorrect\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ExclusivityPeriodNotPassed\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"MsgValueIncorrect\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"NativeTokenCallValueNotSupported\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"RecipientIncorrectReturnValue\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"RecipientNoReturnValue\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"SenderIncorrect\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"StatusIncorrect\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"TransactionRelayed\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ZeroAddress\",\"type\":\"error\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeV2.sol\":\"IFastBridgeV2Errors\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeV2.sol\":{\"keccak256\":\"0xfd916c030b1ffca5a136817827b8018c8ba42ca089905747f3de6148b73eb35e\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://18e6438c4096deb8ae453fb3365ba2b07d52944e93c08288fc5d012b71bf6bb3\",\"dweb:/ipfs/QmfEMqpT1zz6RRm7UuHLRowe1tds2cTGLrVonfm9XSCACj\"]}},\"version\":1}"},"hashes":{}},"solidity/FastBridgeV2.sol:SafeERC20":{"code":"0x60566037600b82828239805160001a607314602a57634e487b7160e01b600052600060045260246000fd5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600080fdfea2646970667358221220bf9b4d830342bc19a7972f35e2bc28e74742724839e41d049e96167e6d81d6ea64736f6c63430008180033","runtime-code":"0x73000000000000000000000000000000000000000030146080604052600080fdfea2646970667358221220bf9b4d830342bc19a7972f35e2bc28e74742724839e41d049e96167e6d81d6ea64736f6c63430008180033","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.24 ^0.8.0 ^0.8.20;\n\n// contracts/interfaces/IAdmin.sol\n\ninterface IAdmin {\n // ============ Events ============\n\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n event ChainGasAmountUpdated(uint256 oldChainGasAmount, uint256 newChainGasAmount);\n\n // ============ Methods ============\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n\n function setChainGasAmount(uint256 newChainGasAmount) external;\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IFastBridgeRecipient.sol\n\ninterface IFastBridgeRecipient {\n function fastBridgeTransferReceived(\n address token,\n uint256 amount,\n bytes memory callParams\n )\n external\n payable\n returns (bytes4);\n}\n\n// contracts/interfaces/IFastBridgeV2Errors.sol\n\ninterface IFastBridgeV2Errors {\n error AmountIncorrect();\n error CallParamsLengthAboveMax();\n error ChainIncorrect();\n error ExclusivityParamsIncorrect();\n error MsgValueIncorrect();\n error NativeTokenCallValueNotSupported();\n error SenderIncorrect();\n error StatusIncorrect();\n error ZeroAddress();\n\n error RecipientIncorrectReturnValue();\n error RecipientNoReturnValue();\n\n error DeadlineExceeded();\n error DeadlineNotExceeded();\n error DeadlineTooShort();\n error DisputePeriodNotPassed();\n error DisputePeriodPassed();\n error ExclusivityPeriodNotPassed();\n\n error TransactionRelayed();\n}\n\n// contracts/libs/Errors.sol\n\nerror DeadlineExceeded();\nerror DeadlineNotExceeded();\nerror DeadlineTooShort();\nerror InsufficientOutputAmount();\n\nerror MsgValueIncorrect();\nerror PoolNotFound();\nerror TokenAddressMismatch();\nerror TokenNotContract();\nerror TokenNotETH();\nerror TokensIdentical();\n\nerror ChainIncorrect();\nerror AmountIncorrect();\nerror ZeroAddress();\n\nerror DisputePeriodNotPassed();\nerror DisputePeriodPassed();\nerror SenderIncorrect();\nerror StatusIncorrect();\nerror TransactionIdIncorrect();\nerror TransactionRelayed();\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// contracts/interfaces/IFastBridgeV2.sol\n\ninterface IFastBridgeV2 is IFastBridge {\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n struct BridgeTxDetails {\n BridgeStatus status;\n uint40 proofBlockTimestamp;\n uint48 proofBlockNumber;\n address proofRelayer;\n }\n\n struct BridgeRelay {\n uint48 blockNumber;\n uint48 blockTimestamp;\n address relayer;\n }\n\n /// @notice New params introduced in the FastBridgeV2.\n /// We are passing fields from the older BridgeParams struct outside of this struct\n /// for backwards compatibility.\n /// Note: quoteRelayer and quoteExclusivitySeconds are either both zero (indicating no exclusivity)\n /// or both non-zero (indicating exclusivity for the given period).\n /// Note: callValue \u003e 0 can NOT be used with destToken = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE (ETH_ADDRESS)\n /// @param quoteRelayer Relayer that provided the quote for the transaction\n /// @param quoteExclusivitySeconds Period of time the quote relayer is guaranteed exclusivity after user's deposit\n /// @param quoteId Unique quote identifier used for tracking the quote\n /// @param callValue ETH value to send to the recipient (if any)\n /// @param callParams Parameters for the arbitrary call to the destination recipient (if any)\n struct BridgeParamsV2 {\n address quoteRelayer;\n int256 quoteExclusivitySeconds;\n bytes quoteId;\n uint256 callValue;\n bytes callParams;\n }\n\n /// @notice Updated bridge transaction struct to include parameters introduced in FastBridgeV2.\n /// Note: only `exclusivityRelayer` can fill such a transaction until `exclusivityEndTime`.\n /// TODO: consider changing the encoding scheme to prevent spending extra gas on decoding.\n struct BridgeTransactionV2 {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n uint256 callValue; // ETH value to send to the recipient (if any) - replaces V1's sendChainGas flag\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n address exclusivityRelayer;\n uint256 exclusivityEndTime;\n bytes callParams;\n }\n\n event BridgeQuoteDetails(bytes32 indexed transactionId, bytes quoteId);\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability\n /// to provide temporary exclusivity fill rights for the quote relayer.\n /// @param params The parameters required to bridge\n /// @param paramsV2 The parameters for exclusivity fill rights (optional, can be left empty)\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function relay(bytes memory request, address relayer) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param transactionId The transaction id associated with the encoded bridge transaction to prove\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital.\n /// @notice Can only send funds to the relayer address on the proof.\n /// @param request The encoded bridge transaction to claim on origin chain\n function claim(bytes memory request) external;\n /// @notice Checks if a transaction has been relayed\n /// @param transactionId The ID of the transaction to check\n /// @return True if the transaction has been relayed, false otherwise\n function bridgeRelays(bytes32 transactionId) external view returns (bool);\n\n /// @notice Returns the status of a bridge transaction\n /// @param transactionId The ID of the bridge transaction\n /// @return BridgeStatus Status of the bridge transaction\n function bridgeStatuses(bytes32 transactionId) external view returns (BridgeStatus);\n\n /// @notice Returns the timestamp and relayer of a bridge proof\n /// @param transactionId The ID of the bridge transaction\n /// @return timestamp The timestamp of the bridge proof\n /// @return relayer The relayer address of the bridge proof\n function bridgeProofs(bytes32 transactionId) external view returns (uint96 timestamp, address relayer);\n\n /// @notice Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\n /// @param request The bridge request to decode\n function getBridgeTransactionV2(bytes memory request) external view returns (BridgeTransactionV2 memory);\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// contracts/libs/UniversalToken.sol\n\nlibrary UniversalTokenLib {\n using SafeERC20 for IERC20;\n\n address internal constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Transfers tokens to the given account. Reverts if transfer is not successful.\n /// @dev This might trigger fallback, if ETH is transferred to the contract.\n /// Make sure this can not lead to reentrancy attacks.\n function universalTransfer(address token, address to, uint256 value) internal {\n // Don't do anything, if need to send tokens to this address\n if (to == address(this)) return;\n // Don't do anything, if trying to send zero value\n if (value == 0) return;\n if (token == ETH_ADDRESS) {\n /// @dev Note: this can potentially lead to executing code in `to`.\n // solhint-disable-next-line avoid-low-level-calls\n (bool success,) = to.call{value: value}(\"\");\n require(success, \"ETH transfer failed\");\n } else {\n IERC20(token).safeTransfer(to, value);\n }\n }\n\n /// @notice Issues an infinite allowance to the spender, if the current allowance is insufficient\n /// to spend the given amount.\n function universalApproveInfinity(address token, address spender, uint256 amountToSpend) internal {\n // ETH Chad doesn't require your approval\n if (token == ETH_ADDRESS) return;\n // No-op if allowance is already sufficient\n uint256 allowance = IERC20(token).allowance(address(this), spender);\n if (allowance \u003e= amountToSpend) return;\n // Otherwise, reset approval to 0 and set to max allowance\n if (allowance \u003e 0) IERC20(token).safeDecreaseAllowance(spender, allowance);\n IERC20(token).safeIncreaseAllowance(spender, type(uint256).max);\n }\n\n /// @notice Returns the balance of the given token (or native ETH) for the given account.\n function universalBalanceOf(address token, address account) internal view returns (uint256) {\n if (token == ETH_ADDRESS) {\n return account.balance;\n } else {\n return IERC20(token).balanceOf(account);\n }\n }\n\n /// @dev Checks that token is a contract and not ETH_ADDRESS.\n function assertIsContract(address token) internal view {\n // Check that ETH_ADDRESS was not used (in case this is a predeploy on any of the chains)\n if (token == UniversalTokenLib.ETH_ADDRESS) revert TokenNotContract();\n // Check that token is not an EOA\n if (token.code.length == 0) revert TokenNotContract();\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/Admin.sol\n\ncontract Admin is IAdmin, AccessControlEnumerable {\n using UniversalTokenLib for address;\n\n bytes32 public constant RELAYER_ROLE = keccak256(\"RELAYER_ROLE\");\n bytes32 public constant REFUNDER_ROLE = keccak256(\"REFUNDER_ROLE\");\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n uint256 public constant FEE_BPS = 1e6;\n uint256 public constant FEE_RATE_MAX = 0.01e6; // max 1% on origin amount\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Chain gas amount to forward as rebate if requested\n uint256 public chainGasAmount;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n }\n\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n require(newFeeRate \u003c= FEE_RATE_MAX, \"newFeeRate \u003e max\");\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n token.universalTransfer(recipient, feeAmount);\n emit FeesSwept(token, recipient, feeAmount);\n }\n\n function setChainGasAmount(uint256 newChainGasAmount) external onlyRole(GOVERNOR_ROLE) {\n uint256 oldChainGasAmount = chainGasAmount;\n chainGasAmount = newChainGasAmount;\n emit ChainGasAmountUpdated(oldChainGasAmount, newChainGasAmount);\n }\n}\n\n// contracts/FastBridgeV2.sol\n\n/// @notice FastBridgeV2 is a contract for bridging tokens across chains.\ncontract FastBridgeV2 is Admin, IFastBridgeV2, IFastBridgeV2Errors {\n using SafeERC20 for IERC20;\n using UniversalTokenLib for address;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Delay for a transaction after which it could be permisionlessly refunded\n uint256 public constant REFUND_DELAY = 7 days;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n /// @notice Maximum length of accepted callParams\n uint256 public constant MAX_CALL_PARAMS_LENGTH = 2 ** 16 - 1;\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeTxDetails) public bridgeTxDetails;\n /// @notice Relay details on destination chain\n mapping(bytes32 =\u003e BridgeRelay) public bridgeRelayDetails;\n /// @notice Unique bridge nonces tracked per originSender\n mapping(address =\u003e uint256) public senderNonces;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Replaced by senderNonces\n uint256 public immutable nonce = 0;\n /// @notice the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n bridge({\n params: params,\n paramsV2: BridgeParamsV2({\n quoteRelayer: address(0),\n quoteExclusivitySeconds: 0,\n quoteId: bytes(\"\"),\n callValue: 0,\n callParams: bytes(\"\")\n })\n });\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes memory request) external payable {\n relay({request: request, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes memory request, bytes32 destTxHash) external {\n prove({transactionId: keccak256(request), destTxHash: destTxHash, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridgeV2\n function claim(bytes memory request) external {\n claim({request: request, to: address(0)});\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003e DISPUTE_PERIOD) {\n revert DisputePeriodPassed();\n }\n\n // @dev relayer gets slashed effectively if dest relay has gone thru\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n bridgeTxDetails[transactionId].proofRelayer = address(0);\n bridgeTxDetails[transactionId].proofBlockTimestamp = 0;\n bridgeTxDetails[transactionId].proofBlockNumber = 0;\n\n emit BridgeProofDisputed(transactionId, msg.sender);\n }\n\n /// @inheritdoc IFastBridge\n function refund(bytes memory request) external {\n bytes32 transactionId = keccak256(request);\n\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n\n if (bridgeTxDetails[transactionId].status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n\n if (hasRole(REFUNDER_ROLE, msg.sender)) {\n // Refunder can refund if deadline has passed\n if (block.timestamp \u003c= transaction.deadline) revert DeadlineNotExceeded();\n } else {\n // Permissionless refund is allowed after REFUND_DELAY\n if (block.timestamp \u003c= transaction.deadline + REFUND_DELAY) revert DeadlineNotExceeded();\n }\n\n // if all checks passed, set to REFUNDED status\n bridgeTxDetails[transactionId].status = BridgeStatus.REFUNDED;\n\n // transfer origin collateral back to original sender\n address to = transaction.originSender;\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount + transaction.originFeeAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (bridgeTxDetails[transactionId].proofRelayer != relayer) revert SenderIncorrect();\n return _timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n /// @dev This method is added to achieve backwards compatibility with decoding requests into V1 structs:\n /// - `callValue` is partially reported as a zero/non-zero flag\n /// - `callParams` is ignored\n /// In order to process all kinds of requests use getBridgeTransactionV2 instead.\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory) {\n // Try decoding into V2 struct first. This will revert if V1 struct is passed\n try this.getBridgeTransactionV2(request) returns (BridgeTransactionV2 memory txV2) {\n // Note: we entirely ignore the callParams field, as it was not present in V1\n return BridgeTransaction({\n originChainId: txV2.originChainId,\n destChainId: txV2.destChainId,\n originSender: txV2.originSender,\n destRecipient: txV2.destRecipient,\n originToken: txV2.originToken,\n destToken: txV2.destToken,\n originAmount: txV2.originAmount,\n destAmount: txV2.destAmount,\n originFeeAmount: txV2.originFeeAmount,\n sendChainGas: txV2.callValue != 0,\n deadline: txV2.deadline,\n nonce: txV2.nonce\n });\n } catch {\n // Fallback to V1 struct\n return abi.decode(request, (BridgeTransaction));\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) public payable {\n int256 exclusivityEndTime = int256(block.timestamp) + paramsV2.quoteExclusivitySeconds;\n _validateBridgeParams(params, paramsV2, exclusivityEndTime);\n\n // transfer tokens to bridge contract\n /// @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _takeBridgedUserAsset(params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n\n // set status to requested\n bytes memory request = abi.encode(\n BridgeTransactionV2({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n callValue: paramsV2.callValue,\n deadline: params.deadline,\n nonce: senderNonces[params.sender]++, // increment nonce on every bridge\n exclusivityRelayer: paramsV2.quoteRelayer,\n // We checked exclusivityEndTime to be in range (0 .. params.deadline] above, so can safely cast\n exclusivityEndTime: uint256(exclusivityEndTime),\n callParams: paramsV2.callParams\n })\n );\n bytes32 transactionId = keccak256(request);\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n\n emit BridgeRequested({\n transactionId: transactionId,\n sender: params.sender,\n request: request,\n destChainId: params.dstChainId,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n sendChainGas: paramsV2.callValue != 0\n });\n emit BridgeQuoteDetails(transactionId, paramsV2.quoteId);\n }\n\n /// @inheritdoc IFastBridgeV2\n function relay(bytes memory request, address relayer) public payable {\n bytes32 transactionId = keccak256(request);\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n _validateRelayParams(transaction, transactionId, relayer);\n // mark bridge transaction as relayed\n bridgeRelayDetails[transactionId] =\n BridgeRelay({blockNumber: uint48(block.number), blockTimestamp: uint48(block.timestamp), relayer: relayer});\n\n // transfer tokens to recipient on destination chain and do an arbitrary call if requested\n address to = transaction.destRecipient;\n address token = transaction.destToken;\n uint256 amount = transaction.destAmount;\n uint256 callValue = transaction.callValue;\n\n // Emit the event before any external calls\n emit BridgeRelayed({\n transactionId: transactionId,\n relayer: relayer,\n to: to,\n originChainId: transaction.originChainId,\n originToken: transaction.originToken,\n destToken: token,\n originAmount: transaction.originAmount,\n destAmount: amount,\n chainGasAmount: callValue\n });\n\n // All state changes have been done at this point, can proceed to the external calls.\n // This follows the checks-effects-interactions pattern to mitigate potential reentrancy attacks.\n if (token == UniversalTokenLib.ETH_ADDRESS) {\n // For ETH non-zero callValue is not allowed\n if (callValue != 0) revert NativeTokenCallValueNotSupported();\n // Check that the correct msg.value was sent\n if (msg.value != amount) revert MsgValueIncorrect();\n } else {\n // For ERC20s, we check that the correct msg.value was sent\n if (msg.value != callValue) revert MsgValueIncorrect();\n // We need to transfer the tokens from the Relayer to the recipient first before performing an\n // optional post-transfer arbitrary call.\n IERC20(token).safeTransferFrom(msg.sender, to, amount);\n }\n\n if (transaction.callParams.length != 0) {\n // Arbitrary call requested, perform it while supplying full msg.value to the recipient\n // Note: if token has a fee on transfers, the recipient will have received less than `amount`.\n // This is a very niche edge case and should be handled by the recipient contract.\n _checkedCallRecipient({recipient: to, token: token, amount: amount, callParams: transaction.callParams});\n } else if (msg.value != 0) {\n // No arbitrary call requested, but msg.value was sent. This is either a relay with ETH,\n // or a non-zero callValue request with an ERC20. In both cases, transfer the ETH to the recipient.\n Address.sendValue(payable(to), msg.value);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) public onlyRole(RELAYER_ROLE) {\n // update bridge tx status given proof provided\n if (bridgeTxDetails[transactionId].status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n bridgeTxDetails[transactionId].status = BridgeStatus.RELAYER_PROVED;\n bridgeTxDetails[transactionId].proofBlockTimestamp = uint40(block.timestamp);\n bridgeTxDetails[transactionId].proofBlockNumber = uint48(block.number);\n bridgeTxDetails[transactionId].proofRelayer = relayer;\n\n emit BridgeProofProvided(transactionId, relayer, destTxHash);\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes memory request, address to) public {\n bytes32 transactionId = keccak256(request);\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n\n // update bridge tx status if able to claim origin collateral\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n\n // if \"to\" is zero addr, permissionlessly send funds to proven relayer\n if (to == address(0)) {\n to = bridgeTxDetails[transactionId].proofRelayer;\n } else if (bridgeTxDetails[transactionId].proofRelayer != msg.sender) {\n revert SenderIncorrect();\n }\n\n if (_timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003c= DISPUTE_PERIOD) {\n revert DisputePeriodNotPassed();\n }\n\n bridgeTxDetails[transactionId].status = BridgeStatus.RELAYER_CLAIMED;\n\n // update protocol fees if origin fee amount exists\n if (transaction.originFeeAmount \u003e 0) protocolFees[transaction.originToken] += transaction.originFeeAmount;\n\n // transfer origin collateral less fee to specified address\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositClaimed(transactionId, bridgeTxDetails[transactionId].proofRelayer, to, token, amount);\n }\n\n function bridgeStatuses(bytes32 transactionId) public view returns (BridgeStatus status) {\n return bridgeTxDetails[transactionId].status;\n }\n\n function bridgeProofs(bytes32 transactionId) public view returns (uint96 timestamp, address relayer) {\n timestamp = bridgeTxDetails[transactionId].proofBlockTimestamp;\n relayer = bridgeTxDetails[transactionId].proofRelayer;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeRelays(bytes32 transactionId) public view returns (bool) {\n // has this transactionId been relayed?\n return bridgeRelayDetails[transactionId].relayer != address(0);\n }\n\n /// @inheritdoc IFastBridgeV2\n function getBridgeTransactionV2(bytes memory request) public pure returns (BridgeTransactionV2 memory) {\n return abi.decode(request, (BridgeTransactionV2));\n }\n\n /// @notice Takes the bridged asset from the user into FastBridgeV2 custody. It will be later\n /// claimed by the relayer who completed the relay on destination chain, or refunded back to the user,\n /// should no one complete the relay.\n function _takeBridgedUserAsset(address token, uint256 amount) internal returns (uint256 amountTaken) {\n if (token == UniversalTokenLib.ETH_ADDRESS) {\n // For ETH we just need to check that the supplied msg.value is correct.\n // Supplied `msg.value` is already in FastBridgeV2 custody.\n if (amount != msg.value) revert MsgValueIncorrect();\n amountTaken = msg.value;\n } else {\n // For ERC20s, token is explicitly transferred from the user to FastBridgeV2.\n // We don't allow non-zero `msg.value` to avoid extra funds from being stuck in FastBridgeV2.\n token.assertIsContract();\n if (msg.value != 0) revert MsgValueIncorrect();\n amountTaken = IERC20(token).balanceOf(address(this));\n IERC20(token).safeTransferFrom(msg.sender, address(this), amount);\n // Use the balance difference as the amount taken in case of fee on transfer tokens.\n amountTaken = IERC20(token).balanceOf(address(this)) - amountTaken;\n }\n }\n\n /// @notice Calls the Recipient's hook function with the specified callParams and performs\n /// all the necessary checks for the returned value.\n function _checkedCallRecipient(\n address recipient,\n address token,\n uint256 amount,\n bytes memory callParams\n )\n internal\n {\n bytes memory hookData =\n abi.encodeCall(IFastBridgeRecipient.fastBridgeTransferReceived, (token, amount, callParams));\n // This will bubble any revert messages from the hook function\n bytes memory returnData = Address.functionCallWithValue({target: recipient, data: hookData, value: msg.value});\n // Explicit revert if no return data at all\n if (returnData.length == 0) revert RecipientNoReturnValue();\n // Check that exactly a single return value was returned\n if (returnData.length != 32) revert RecipientIncorrectReturnValue();\n // Return value should be abi-encoded hook function selector\n if (bytes32(returnData) != bytes32(IFastBridgeRecipient.fastBridgeTransferReceived.selector)) {\n revert RecipientIncorrectReturnValue();\n }\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint40(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint40).max but\n /// proof.timestamp \u003c type(uint40).max via unchecked statement\n /// @param proofBlockTimestamp The bridge proof block timestamp\n /// @return delta Time delta since proof submitted\n function _timeSince(uint40 proofBlockTimestamp) internal view returns (uint256 delta) {\n unchecked {\n delta = uint40(block.timestamp) - proofBlockTimestamp;\n }\n }\n\n /// @notice Performs all the necessary checks for a bridge to happen.\n /// @dev There's no good way to refactor this function to reduce cyclomatic complexity due to\n /// the number of checks that need to be performed, so we skip the code-complexity rule here.\n // solhint-disable-next-line code-complexity\n function _validateBridgeParams(\n BridgeParams memory params,\n BridgeParamsV2 memory paramsV2,\n int256 exclusivityEndTime\n )\n internal\n view\n {\n // Check V1 (legacy) params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.sender == address(0) || params.to == address(0)) revert ZeroAddress();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n // Check V2 params\n if (paramsV2.callParams.length \u003e MAX_CALL_PARAMS_LENGTH) revert CallParamsLengthAboveMax();\n if (paramsV2.callValue != 0 \u0026\u0026 params.destToken == UniversalTokenLib.ETH_ADDRESS) {\n revert NativeTokenCallValueNotSupported();\n }\n // exclusivityEndTime must be in range (0 .. params.deadline]\n if (exclusivityEndTime \u003c= 0 || exclusivityEndTime \u003e int256(params.deadline)) {\n revert ExclusivityParamsIncorrect();\n }\n }\n\n /// @notice Performs all the necessary checks for a relay to happen.\n function _validateRelayParams(\n BridgeTransactionV2 memory transaction,\n bytes32 transactionId,\n address relayer\n )\n internal\n view\n {\n if (relayer == address(0)) revert ZeroAddress();\n // Check if the transaction has already been relayed\n if (bridgeRelays(transactionId)) revert TransactionRelayed();\n if (transaction.destChainId != block.chainid) revert ChainIncorrect();\n // Check the deadline for relay to happen\n if (block.timestamp \u003e transaction.deadline) revert DeadlineExceeded();\n // Check the exclusivity period, if it is still ongoing\n // forgefmt: disable-next-item\n if (\n transaction.exclusivityRelayer != address(0) \u0026\u0026\n transaction.exclusivityRelayer != relayer \u0026\u0026\n block.timestamp \u003c= transaction.exclusivityEndTime\n ) {\n revert ExclusivityPeriodNotPassed();\n }\n }\n}\n","language":"Solidity","languageVersion":"0.8.24","compilerVersion":"0.8.24","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"45745:5018:0:-:0;;;;;;;;;;;;;;;-1:-1:-1;;;45745:5018:0;;;;;;;;;;;;;;;;;","srcMapRuntime":"45745:5018:0:-:0;;;;;;;;","abiDefinition":[{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"currentAllowance","type":"uint256"},{"internalType":"uint256","name":"requestedDecrease","type":"uint256"}],"name":"SafeERC20FailedDecreaseAllowance","type":"error"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"SafeERC20FailedOperation","type":"error"}],"userDoc":{"kind":"user","methods":{},"version":1},"developerDoc":{"details":"Wrappers around ERC20 operations that throw on failure (when the token contract returns false). Tokens that return no value (and instead revert or throw on failure) are also supported, non-reverting calls are assumed to be successful. To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract, which allows you to call the safe operations as `token.safeTransfer(...)`, etc.","errors":{"SafeERC20FailedDecreaseAllowance(address,uint256,uint256)":[{"details":"Indicates a failed `decreaseAllowance` request."}],"SafeERC20FailedOperation(address)":[{"details":"An operation with an ERC20 token failed."}]},"kind":"dev","methods":{},"title":"SafeERC20","version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"currentAllowance\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"requestedDecrease\",\"type\":\"uint256\"}],\"name\":\"SafeERC20FailedDecreaseAllowance\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"}],\"name\":\"SafeERC20FailedOperation\",\"type\":\"error\"}],\"devdoc\":{\"details\":\"Wrappers around ERC20 operations that throw on failure (when the token contract returns false). Tokens that return no value (and instead revert or throw on failure) are also supported, non-reverting calls are assumed to be successful. To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract, which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\",\"errors\":{\"SafeERC20FailedDecreaseAllowance(address,uint256,uint256)\":[{\"details\":\"Indicates a failed `decreaseAllowance` request.\"}],\"SafeERC20FailedOperation(address)\":[{\"details\":\"An operation with an ERC20 token failed.\"}]},\"kind\":\"dev\",\"methods\":{},\"title\":\"SafeERC20\",\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeV2.sol\":\"SafeERC20\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeV2.sol\":{\"keccak256\":\"0xfd916c030b1ffca5a136817827b8018c8ba42ca089905747f3de6148b73eb35e\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://18e6438c4096deb8ae453fb3365ba2b07d52944e93c08288fc5d012b71bf6bb3\",\"dweb:/ipfs/QmfEMqpT1zz6RRm7UuHLRowe1tds2cTGLrVonfm9XSCACj\"]}},\"version\":1}"},"hashes":{}},"solidity/FastBridgeV2.sol:UniversalTokenLib":{"code":"0x60566037600b82828239805160001a607314602a57634e487b7160e01b600052600060045260246000fd5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600080fdfea264697066735822122030abe7c99e33645ff08fba6fd46ebf752f2157cc4f5e930a35e81633f8aacbb864736f6c63430008180033","runtime-code":"0x73000000000000000000000000000000000000000030146080604052600080fdfea264697066735822122030abe7c99e33645ff08fba6fd46ebf752f2157cc4f5e930a35e81633f8aacbb864736f6c63430008180033","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.24 ^0.8.0 ^0.8.20;\n\n// contracts/interfaces/IAdmin.sol\n\ninterface IAdmin {\n // ============ Events ============\n\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n event ChainGasAmountUpdated(uint256 oldChainGasAmount, uint256 newChainGasAmount);\n\n // ============ Methods ============\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n\n function setChainGasAmount(uint256 newChainGasAmount) external;\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IFastBridgeRecipient.sol\n\ninterface IFastBridgeRecipient {\n function fastBridgeTransferReceived(\n address token,\n uint256 amount,\n bytes memory callParams\n )\n external\n payable\n returns (bytes4);\n}\n\n// contracts/interfaces/IFastBridgeV2Errors.sol\n\ninterface IFastBridgeV2Errors {\n error AmountIncorrect();\n error CallParamsLengthAboveMax();\n error ChainIncorrect();\n error ExclusivityParamsIncorrect();\n error MsgValueIncorrect();\n error NativeTokenCallValueNotSupported();\n error SenderIncorrect();\n error StatusIncorrect();\n error ZeroAddress();\n\n error RecipientIncorrectReturnValue();\n error RecipientNoReturnValue();\n\n error DeadlineExceeded();\n error DeadlineNotExceeded();\n error DeadlineTooShort();\n error DisputePeriodNotPassed();\n error DisputePeriodPassed();\n error ExclusivityPeriodNotPassed();\n\n error TransactionRelayed();\n}\n\n// contracts/libs/Errors.sol\n\nerror DeadlineExceeded();\nerror DeadlineNotExceeded();\nerror DeadlineTooShort();\nerror InsufficientOutputAmount();\n\nerror MsgValueIncorrect();\nerror PoolNotFound();\nerror TokenAddressMismatch();\nerror TokenNotContract();\nerror TokenNotETH();\nerror TokensIdentical();\n\nerror ChainIncorrect();\nerror AmountIncorrect();\nerror ZeroAddress();\n\nerror DisputePeriodNotPassed();\nerror DisputePeriodPassed();\nerror SenderIncorrect();\nerror StatusIncorrect();\nerror TransactionIdIncorrect();\nerror TransactionRelayed();\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// contracts/interfaces/IFastBridgeV2.sol\n\ninterface IFastBridgeV2 is IFastBridge {\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n struct BridgeTxDetails {\n BridgeStatus status;\n uint40 proofBlockTimestamp;\n uint48 proofBlockNumber;\n address proofRelayer;\n }\n\n struct BridgeRelay {\n uint48 blockNumber;\n uint48 blockTimestamp;\n address relayer;\n }\n\n /// @notice New params introduced in the FastBridgeV2.\n /// We are passing fields from the older BridgeParams struct outside of this struct\n /// for backwards compatibility.\n /// Note: quoteRelayer and quoteExclusivitySeconds are either both zero (indicating no exclusivity)\n /// or both non-zero (indicating exclusivity for the given period).\n /// Note: callValue \u003e 0 can NOT be used with destToken = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE (ETH_ADDRESS)\n /// @param quoteRelayer Relayer that provided the quote for the transaction\n /// @param quoteExclusivitySeconds Period of time the quote relayer is guaranteed exclusivity after user's deposit\n /// @param quoteId Unique quote identifier used for tracking the quote\n /// @param callValue ETH value to send to the recipient (if any)\n /// @param callParams Parameters for the arbitrary call to the destination recipient (if any)\n struct BridgeParamsV2 {\n address quoteRelayer;\n int256 quoteExclusivitySeconds;\n bytes quoteId;\n uint256 callValue;\n bytes callParams;\n }\n\n /// @notice Updated bridge transaction struct to include parameters introduced in FastBridgeV2.\n /// Note: only `exclusivityRelayer` can fill such a transaction until `exclusivityEndTime`.\n /// TODO: consider changing the encoding scheme to prevent spending extra gas on decoding.\n struct BridgeTransactionV2 {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n uint256 callValue; // ETH value to send to the recipient (if any) - replaces V1's sendChainGas flag\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n address exclusivityRelayer;\n uint256 exclusivityEndTime;\n bytes callParams;\n }\n\n event BridgeQuoteDetails(bytes32 indexed transactionId, bytes quoteId);\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability\n /// to provide temporary exclusivity fill rights for the quote relayer.\n /// @param params The parameters required to bridge\n /// @param paramsV2 The parameters for exclusivity fill rights (optional, can be left empty)\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function relay(bytes memory request, address relayer) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param transactionId The transaction id associated with the encoded bridge transaction to prove\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital.\n /// @notice Can only send funds to the relayer address on the proof.\n /// @param request The encoded bridge transaction to claim on origin chain\n function claim(bytes memory request) external;\n /// @notice Checks if a transaction has been relayed\n /// @param transactionId The ID of the transaction to check\n /// @return True if the transaction has been relayed, false otherwise\n function bridgeRelays(bytes32 transactionId) external view returns (bool);\n\n /// @notice Returns the status of a bridge transaction\n /// @param transactionId The ID of the bridge transaction\n /// @return BridgeStatus Status of the bridge transaction\n function bridgeStatuses(bytes32 transactionId) external view returns (BridgeStatus);\n\n /// @notice Returns the timestamp and relayer of a bridge proof\n /// @param transactionId The ID of the bridge transaction\n /// @return timestamp The timestamp of the bridge proof\n /// @return relayer The relayer address of the bridge proof\n function bridgeProofs(bytes32 transactionId) external view returns (uint96 timestamp, address relayer);\n\n /// @notice Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\n /// @param request The bridge request to decode\n function getBridgeTransactionV2(bytes memory request) external view returns (BridgeTransactionV2 memory);\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// contracts/libs/UniversalToken.sol\n\nlibrary UniversalTokenLib {\n using SafeERC20 for IERC20;\n\n address internal constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Transfers tokens to the given account. Reverts if transfer is not successful.\n /// @dev This might trigger fallback, if ETH is transferred to the contract.\n /// Make sure this can not lead to reentrancy attacks.\n function universalTransfer(address token, address to, uint256 value) internal {\n // Don't do anything, if need to send tokens to this address\n if (to == address(this)) return;\n // Don't do anything, if trying to send zero value\n if (value == 0) return;\n if (token == ETH_ADDRESS) {\n /// @dev Note: this can potentially lead to executing code in `to`.\n // solhint-disable-next-line avoid-low-level-calls\n (bool success,) = to.call{value: value}(\"\");\n require(success, \"ETH transfer failed\");\n } else {\n IERC20(token).safeTransfer(to, value);\n }\n }\n\n /// @notice Issues an infinite allowance to the spender, if the current allowance is insufficient\n /// to spend the given amount.\n function universalApproveInfinity(address token, address spender, uint256 amountToSpend) internal {\n // ETH Chad doesn't require your approval\n if (token == ETH_ADDRESS) return;\n // No-op if allowance is already sufficient\n uint256 allowance = IERC20(token).allowance(address(this), spender);\n if (allowance \u003e= amountToSpend) return;\n // Otherwise, reset approval to 0 and set to max allowance\n if (allowance \u003e 0) IERC20(token).safeDecreaseAllowance(spender, allowance);\n IERC20(token).safeIncreaseAllowance(spender, type(uint256).max);\n }\n\n /// @notice Returns the balance of the given token (or native ETH) for the given account.\n function universalBalanceOf(address token, address account) internal view returns (uint256) {\n if (token == ETH_ADDRESS) {\n return account.balance;\n } else {\n return IERC20(token).balanceOf(account);\n }\n }\n\n /// @dev Checks that token is a contract and not ETH_ADDRESS.\n function assertIsContract(address token) internal view {\n // Check that ETH_ADDRESS was not used (in case this is a predeploy on any of the chains)\n if (token == UniversalTokenLib.ETH_ADDRESS) revert TokenNotContract();\n // Check that token is not an EOA\n if (token.code.length == 0) revert TokenNotContract();\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/Admin.sol\n\ncontract Admin is IAdmin, AccessControlEnumerable {\n using UniversalTokenLib for address;\n\n bytes32 public constant RELAYER_ROLE = keccak256(\"RELAYER_ROLE\");\n bytes32 public constant REFUNDER_ROLE = keccak256(\"REFUNDER_ROLE\");\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n uint256 public constant FEE_BPS = 1e6;\n uint256 public constant FEE_RATE_MAX = 0.01e6; // max 1% on origin amount\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Chain gas amount to forward as rebate if requested\n uint256 public chainGasAmount;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n }\n\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n require(newFeeRate \u003c= FEE_RATE_MAX, \"newFeeRate \u003e max\");\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n token.universalTransfer(recipient, feeAmount);\n emit FeesSwept(token, recipient, feeAmount);\n }\n\n function setChainGasAmount(uint256 newChainGasAmount) external onlyRole(GOVERNOR_ROLE) {\n uint256 oldChainGasAmount = chainGasAmount;\n chainGasAmount = newChainGasAmount;\n emit ChainGasAmountUpdated(oldChainGasAmount, newChainGasAmount);\n }\n}\n\n// contracts/FastBridgeV2.sol\n\n/// @notice FastBridgeV2 is a contract for bridging tokens across chains.\ncontract FastBridgeV2 is Admin, IFastBridgeV2, IFastBridgeV2Errors {\n using SafeERC20 for IERC20;\n using UniversalTokenLib for address;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Delay for a transaction after which it could be permisionlessly refunded\n uint256 public constant REFUND_DELAY = 7 days;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n /// @notice Maximum length of accepted callParams\n uint256 public constant MAX_CALL_PARAMS_LENGTH = 2 ** 16 - 1;\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeTxDetails) public bridgeTxDetails;\n /// @notice Relay details on destination chain\n mapping(bytes32 =\u003e BridgeRelay) public bridgeRelayDetails;\n /// @notice Unique bridge nonces tracked per originSender\n mapping(address =\u003e uint256) public senderNonces;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Replaced by senderNonces\n uint256 public immutable nonce = 0;\n /// @notice the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n bridge({\n params: params,\n paramsV2: BridgeParamsV2({\n quoteRelayer: address(0),\n quoteExclusivitySeconds: 0,\n quoteId: bytes(\"\"),\n callValue: 0,\n callParams: bytes(\"\")\n })\n });\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes memory request) external payable {\n relay({request: request, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes memory request, bytes32 destTxHash) external {\n prove({transactionId: keccak256(request), destTxHash: destTxHash, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridgeV2\n function claim(bytes memory request) external {\n claim({request: request, to: address(0)});\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003e DISPUTE_PERIOD) {\n revert DisputePeriodPassed();\n }\n\n // @dev relayer gets slashed effectively if dest relay has gone thru\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n bridgeTxDetails[transactionId].proofRelayer = address(0);\n bridgeTxDetails[transactionId].proofBlockTimestamp = 0;\n bridgeTxDetails[transactionId].proofBlockNumber = 0;\n\n emit BridgeProofDisputed(transactionId, msg.sender);\n }\n\n /// @inheritdoc IFastBridge\n function refund(bytes memory request) external {\n bytes32 transactionId = keccak256(request);\n\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n\n if (bridgeTxDetails[transactionId].status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n\n if (hasRole(REFUNDER_ROLE, msg.sender)) {\n // Refunder can refund if deadline has passed\n if (block.timestamp \u003c= transaction.deadline) revert DeadlineNotExceeded();\n } else {\n // Permissionless refund is allowed after REFUND_DELAY\n if (block.timestamp \u003c= transaction.deadline + REFUND_DELAY) revert DeadlineNotExceeded();\n }\n\n // if all checks passed, set to REFUNDED status\n bridgeTxDetails[transactionId].status = BridgeStatus.REFUNDED;\n\n // transfer origin collateral back to original sender\n address to = transaction.originSender;\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount + transaction.originFeeAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (bridgeTxDetails[transactionId].proofRelayer != relayer) revert SenderIncorrect();\n return _timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n /// @dev This method is added to achieve backwards compatibility with decoding requests into V1 structs:\n /// - `callValue` is partially reported as a zero/non-zero flag\n /// - `callParams` is ignored\n /// In order to process all kinds of requests use getBridgeTransactionV2 instead.\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory) {\n // Try decoding into V2 struct first. This will revert if V1 struct is passed\n try this.getBridgeTransactionV2(request) returns (BridgeTransactionV2 memory txV2) {\n // Note: we entirely ignore the callParams field, as it was not present in V1\n return BridgeTransaction({\n originChainId: txV2.originChainId,\n destChainId: txV2.destChainId,\n originSender: txV2.originSender,\n destRecipient: txV2.destRecipient,\n originToken: txV2.originToken,\n destToken: txV2.destToken,\n originAmount: txV2.originAmount,\n destAmount: txV2.destAmount,\n originFeeAmount: txV2.originFeeAmount,\n sendChainGas: txV2.callValue != 0,\n deadline: txV2.deadline,\n nonce: txV2.nonce\n });\n } catch {\n // Fallback to V1 struct\n return abi.decode(request, (BridgeTransaction));\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) public payable {\n int256 exclusivityEndTime = int256(block.timestamp) + paramsV2.quoteExclusivitySeconds;\n _validateBridgeParams(params, paramsV2, exclusivityEndTime);\n\n // transfer tokens to bridge contract\n /// @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _takeBridgedUserAsset(params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n\n // set status to requested\n bytes memory request = abi.encode(\n BridgeTransactionV2({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n callValue: paramsV2.callValue,\n deadline: params.deadline,\n nonce: senderNonces[params.sender]++, // increment nonce on every bridge\n exclusivityRelayer: paramsV2.quoteRelayer,\n // We checked exclusivityEndTime to be in range (0 .. params.deadline] above, so can safely cast\n exclusivityEndTime: uint256(exclusivityEndTime),\n callParams: paramsV2.callParams\n })\n );\n bytes32 transactionId = keccak256(request);\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n\n emit BridgeRequested({\n transactionId: transactionId,\n sender: params.sender,\n request: request,\n destChainId: params.dstChainId,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n sendChainGas: paramsV2.callValue != 0\n });\n emit BridgeQuoteDetails(transactionId, paramsV2.quoteId);\n }\n\n /// @inheritdoc IFastBridgeV2\n function relay(bytes memory request, address relayer) public payable {\n bytes32 transactionId = keccak256(request);\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n _validateRelayParams(transaction, transactionId, relayer);\n // mark bridge transaction as relayed\n bridgeRelayDetails[transactionId] =\n BridgeRelay({blockNumber: uint48(block.number), blockTimestamp: uint48(block.timestamp), relayer: relayer});\n\n // transfer tokens to recipient on destination chain and do an arbitrary call if requested\n address to = transaction.destRecipient;\n address token = transaction.destToken;\n uint256 amount = transaction.destAmount;\n uint256 callValue = transaction.callValue;\n\n // Emit the event before any external calls\n emit BridgeRelayed({\n transactionId: transactionId,\n relayer: relayer,\n to: to,\n originChainId: transaction.originChainId,\n originToken: transaction.originToken,\n destToken: token,\n originAmount: transaction.originAmount,\n destAmount: amount,\n chainGasAmount: callValue\n });\n\n // All state changes have been done at this point, can proceed to the external calls.\n // This follows the checks-effects-interactions pattern to mitigate potential reentrancy attacks.\n if (token == UniversalTokenLib.ETH_ADDRESS) {\n // For ETH non-zero callValue is not allowed\n if (callValue != 0) revert NativeTokenCallValueNotSupported();\n // Check that the correct msg.value was sent\n if (msg.value != amount) revert MsgValueIncorrect();\n } else {\n // For ERC20s, we check that the correct msg.value was sent\n if (msg.value != callValue) revert MsgValueIncorrect();\n // We need to transfer the tokens from the Relayer to the recipient first before performing an\n // optional post-transfer arbitrary call.\n IERC20(token).safeTransferFrom(msg.sender, to, amount);\n }\n\n if (transaction.callParams.length != 0) {\n // Arbitrary call requested, perform it while supplying full msg.value to the recipient\n // Note: if token has a fee on transfers, the recipient will have received less than `amount`.\n // This is a very niche edge case and should be handled by the recipient contract.\n _checkedCallRecipient({recipient: to, token: token, amount: amount, callParams: transaction.callParams});\n } else if (msg.value != 0) {\n // No arbitrary call requested, but msg.value was sent. This is either a relay with ETH,\n // or a non-zero callValue request with an ERC20. In both cases, transfer the ETH to the recipient.\n Address.sendValue(payable(to), msg.value);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) public onlyRole(RELAYER_ROLE) {\n // update bridge tx status given proof provided\n if (bridgeTxDetails[transactionId].status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n bridgeTxDetails[transactionId].status = BridgeStatus.RELAYER_PROVED;\n bridgeTxDetails[transactionId].proofBlockTimestamp = uint40(block.timestamp);\n bridgeTxDetails[transactionId].proofBlockNumber = uint48(block.number);\n bridgeTxDetails[transactionId].proofRelayer = relayer;\n\n emit BridgeProofProvided(transactionId, relayer, destTxHash);\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes memory request, address to) public {\n bytes32 transactionId = keccak256(request);\n BridgeTransactionV2 memory transaction = getBridgeTransactionV2(request);\n\n // update bridge tx status if able to claim origin collateral\n if (bridgeTxDetails[transactionId].status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n\n // if \"to\" is zero addr, permissionlessly send funds to proven relayer\n if (to == address(0)) {\n to = bridgeTxDetails[transactionId].proofRelayer;\n } else if (bridgeTxDetails[transactionId].proofRelayer != msg.sender) {\n revert SenderIncorrect();\n }\n\n if (_timeSince(bridgeTxDetails[transactionId].proofBlockTimestamp) \u003c= DISPUTE_PERIOD) {\n revert DisputePeriodNotPassed();\n }\n\n bridgeTxDetails[transactionId].status = BridgeStatus.RELAYER_CLAIMED;\n\n // update protocol fees if origin fee amount exists\n if (transaction.originFeeAmount \u003e 0) protocolFees[transaction.originToken] += transaction.originFeeAmount;\n\n // transfer origin collateral less fee to specified address\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositClaimed(transactionId, bridgeTxDetails[transactionId].proofRelayer, to, token, amount);\n }\n\n function bridgeStatuses(bytes32 transactionId) public view returns (BridgeStatus status) {\n return bridgeTxDetails[transactionId].status;\n }\n\n function bridgeProofs(bytes32 transactionId) public view returns (uint96 timestamp, address relayer) {\n timestamp = bridgeTxDetails[transactionId].proofBlockTimestamp;\n relayer = bridgeTxDetails[transactionId].proofRelayer;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeRelays(bytes32 transactionId) public view returns (bool) {\n // has this transactionId been relayed?\n return bridgeRelayDetails[transactionId].relayer != address(0);\n }\n\n /// @inheritdoc IFastBridgeV2\n function getBridgeTransactionV2(bytes memory request) public pure returns (BridgeTransactionV2 memory) {\n return abi.decode(request, (BridgeTransactionV2));\n }\n\n /// @notice Takes the bridged asset from the user into FastBridgeV2 custody. It will be later\n /// claimed by the relayer who completed the relay on destination chain, or refunded back to the user,\n /// should no one complete the relay.\n function _takeBridgedUserAsset(address token, uint256 amount) internal returns (uint256 amountTaken) {\n if (token == UniversalTokenLib.ETH_ADDRESS) {\n // For ETH we just need to check that the supplied msg.value is correct.\n // Supplied `msg.value` is already in FastBridgeV2 custody.\n if (amount != msg.value) revert MsgValueIncorrect();\n amountTaken = msg.value;\n } else {\n // For ERC20s, token is explicitly transferred from the user to FastBridgeV2.\n // We don't allow non-zero `msg.value` to avoid extra funds from being stuck in FastBridgeV2.\n token.assertIsContract();\n if (msg.value != 0) revert MsgValueIncorrect();\n amountTaken = IERC20(token).balanceOf(address(this));\n IERC20(token).safeTransferFrom(msg.sender, address(this), amount);\n // Use the balance difference as the amount taken in case of fee on transfer tokens.\n amountTaken = IERC20(token).balanceOf(address(this)) - amountTaken;\n }\n }\n\n /// @notice Calls the Recipient's hook function with the specified callParams and performs\n /// all the necessary checks for the returned value.\n function _checkedCallRecipient(\n address recipient,\n address token,\n uint256 amount,\n bytes memory callParams\n )\n internal\n {\n bytes memory hookData =\n abi.encodeCall(IFastBridgeRecipient.fastBridgeTransferReceived, (token, amount, callParams));\n // This will bubble any revert messages from the hook function\n bytes memory returnData = Address.functionCallWithValue({target: recipient, data: hookData, value: msg.value});\n // Explicit revert if no return data at all\n if (returnData.length == 0) revert RecipientNoReturnValue();\n // Check that exactly a single return value was returned\n if (returnData.length != 32) revert RecipientIncorrectReturnValue();\n // Return value should be abi-encoded hook function selector\n if (bytes32(returnData) != bytes32(IFastBridgeRecipient.fastBridgeTransferReceived.selector)) {\n revert RecipientIncorrectReturnValue();\n }\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint40(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint40).max but\n /// proof.timestamp \u003c type(uint40).max via unchecked statement\n /// @param proofBlockTimestamp The bridge proof block timestamp\n /// @return delta Time delta since proof submitted\n function _timeSince(uint40 proofBlockTimestamp) internal view returns (uint256 delta) {\n unchecked {\n delta = uint40(block.timestamp) - proofBlockTimestamp;\n }\n }\n\n /// @notice Performs all the necessary checks for a bridge to happen.\n /// @dev There's no good way to refactor this function to reduce cyclomatic complexity due to\n /// the number of checks that need to be performed, so we skip the code-complexity rule here.\n // solhint-disable-next-line code-complexity\n function _validateBridgeParams(\n BridgeParams memory params,\n BridgeParamsV2 memory paramsV2,\n int256 exclusivityEndTime\n )\n internal\n view\n {\n // Check V1 (legacy) params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.sender == address(0) || params.to == address(0)) revert ZeroAddress();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n // Check V2 params\n if (paramsV2.callParams.length \u003e MAX_CALL_PARAMS_LENGTH) revert CallParamsLengthAboveMax();\n if (paramsV2.callValue != 0 \u0026\u0026 params.destToken == UniversalTokenLib.ETH_ADDRESS) {\n revert NativeTokenCallValueNotSupported();\n }\n // exclusivityEndTime must be in range (0 .. params.deadline]\n if (exclusivityEndTime \u003c= 0 || exclusivityEndTime \u003e int256(params.deadline)) {\n revert ExclusivityParamsIncorrect();\n }\n }\n\n /// @notice Performs all the necessary checks for a relay to happen.\n function _validateRelayParams(\n BridgeTransactionV2 memory transaction,\n bytes32 transactionId,\n address relayer\n )\n internal\n view\n {\n if (relayer == address(0)) revert ZeroAddress();\n // Check if the transaction has already been relayed\n if (bridgeRelays(transactionId)) revert TransactionRelayed();\n if (transaction.destChainId != block.chainid) revert ChainIncorrect();\n // Check the deadline for relay to happen\n if (block.timestamp \u003e transaction.deadline) revert DeadlineExceeded();\n // Check the exclusivity period, if it is still ongoing\n // forgefmt: disable-next-item\n if (\n transaction.exclusivityRelayer != address(0) \u0026\u0026\n transaction.exclusivityRelayer != relayer \u0026\u0026\n block.timestamp \u003c= transaction.exclusivityEndTime\n ) {\n revert ExclusivityPeriodNotPassed();\n }\n }\n}\n","language":"Solidity","languageVersion":"0.8.24","compilerVersion":"0.8.24","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"57704:2551:0:-:0;;;;;;;;;;;;;;;-1:-1:-1;;;57704:2551:0;;;;;;;;;;;;;;;;;","srcMapRuntime":"57704:2551:0:-:0;;;;;;;;","abiDefinition":[],"userDoc":{"kind":"user","methods":{},"version":1},"developerDoc":{"kind":"dev","methods":{},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[],\"devdoc\":{\"kind\":\"dev\",\"methods\":{},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeV2.sol\":\"UniversalTokenLib\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeV2.sol\":{\"keccak256\":\"0xfd916c030b1ffca5a136817827b8018c8ba42ca089905747f3de6148b73eb35e\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://18e6438c4096deb8ae453fb3365ba2b07d52944e93c08288fc5d012b71bf6bb3\",\"dweb:/ipfs/QmfEMqpT1zz6RRm7UuHLRowe1tds2cTGLrVonfm9XSCACj\"]}},\"version\":1}"},"hashes":{}}} \ No newline at end of file +{"solidity/FastBridgeV2.sol:AccessControl":{"code":"0x","runtime-code":"0x","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.24 ^0.8.20 ^0.8.4;\n\n// contracts/interfaces/IAdmin.sol\n\ninterface IAdmin {\n // ============ Events ============\n\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n event ChainGasAmountUpdated(uint256 oldChainGasAmount, uint256 newChainGasAmount);\n\n // ============ Methods ============\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n\n function setChainGasAmount(uint256 newChainGasAmount) external;\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IFastBridgeV2Errors.sol\n\ninterface IFastBridgeV2Errors {\n error AmountIncorrect();\n error ChainIncorrect();\n error ExclusivityParamsIncorrect();\n error MsgValueIncorrect();\n error SenderIncorrect();\n error StatusIncorrect();\n error TokenNotContract();\n error ZapDataLengthAboveMax();\n error ZapNativeNotSupported();\n error ZeroAddress();\n\n error RecipientIncorrectReturnValue();\n error RecipientNoReturnValue();\n\n error DeadlineExceeded();\n error DeadlineNotExceeded();\n error DeadlineTooShort();\n error DisputePeriodNotPassed();\n error DisputePeriodPassed();\n error ExclusivityPeriodNotPassed();\n\n error TransactionRelayed();\n}\n\n// contracts/interfaces/IMulticallTarget.sol\n\n/// @notice Interface for a contract that can be called multiple times by the same caller. Inspired by MulticallV3:\n/// https://github.com/mds1/multicall/blob/master/src/Multicall3.sol\ninterface IMulticallTarget {\n struct Result {\n bool success;\n bytes returnData;\n }\n\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external;\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results);\n}\n\n// contracts/interfaces/IZapRecipient.sol\n\ninterface IZapRecipient {\n function zap(address token, uint256 amount, bytes memory zapData) external payable returns (bytes4);\n}\n\n// contracts/libs/Errors.sol\n\nerror DeadlineExceeded();\nerror DeadlineNotExceeded();\nerror DeadlineTooShort();\nerror InsufficientOutputAmount();\n\nerror MsgValueIncorrect();\nerror PoolNotFound();\nerror TokenAddressMismatch();\nerror TokenNotContract();\nerror TokenNotETH();\nerror TokensIdentical();\n\nerror ChainIncorrect();\nerror AmountIncorrect();\nerror ZeroAddress();\n\nerror DisputePeriodNotPassed();\nerror DisputePeriodPassed();\nerror SenderIncorrect();\nerror StatusIncorrect();\nerror TransactionIdIncorrect();\nerror TransactionRelayed();\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// contracts/interfaces/IFastBridgeV2.sol\n\ninterface IFastBridgeV2 is IFastBridge {\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n struct BridgeTxDetails {\n BridgeStatus status;\n uint32 destChainId;\n uint56 proofBlockTimestamp;\n address proofRelayer;\n }\n\n struct BridgeRelay {\n uint48 blockNumber;\n uint48 blockTimestamp;\n address relayer;\n }\n\n /// @notice New params introduced in the FastBridgeV2.\n /// We are passing fields from the older BridgeParams struct outside of this struct\n /// for backwards compatibility.\n /// Note: quoteRelayer and quoteExclusivitySeconds are either both zero (indicating no exclusivity)\n /// or both non-zero (indicating exclusivity for the given period).\n /// Note: zapNative \u003e 0 can NOT be used with destToken = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE (native token)\n /// @param quoteRelayer Relayer that provided the quote for the transaction\n /// @param quoteExclusivitySeconds Period of time the quote relayer is guaranteed exclusivity after user's deposit\n /// @param quoteId Unique quote identifier used for tracking the quote\n /// @param zapNative ETH value to send to the recipient (if any)\n /// @param zapData Parameters for the Zap to the destination recipient (if any)\n struct BridgeParamsV2 {\n address quoteRelayer;\n int256 quoteExclusivitySeconds;\n bytes quoteId;\n uint256 zapNative;\n bytes zapData;\n }\n\n /// @notice Updated bridge transaction struct to include parameters introduced in FastBridgeV2.\n /// Note: only `exclusivityRelayer` can fill such a transaction until `exclusivityEndTime`.\n struct BridgeTransactionV2 {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n // Note: sendChainGas flag from V1 is deprecated\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n address exclusivityRelayer;\n uint256 exclusivityEndTime;\n uint256 zapNative; // ETH value to send to the recipient (if any)\n bytes zapData; // data to pass for the Zap action (if any)\n }\n\n event BridgeQuoteDetails(bytes32 indexed transactionId, bytes quoteId);\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability\n /// to provide temporary exclusivity fill rights for the quote relayer.\n /// @param params The parameters required to bridge\n /// @param paramsV2 The parameters for exclusivity fill rights (optional, can be left empty)\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function relay(bytes memory request, address relayer) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param transactionId The transaction id associated with the encoded bridge transaction to prove\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital.\n /// @notice Can only send funds to the relayer address on the proof.\n /// @param request The encoded bridge transaction to claim on origin chain\n function claim(bytes memory request) external;\n /// @notice Checks if a transaction has been relayed\n /// @param transactionId The ID of the transaction to check\n /// @return True if the transaction has been relayed, false otherwise\n function bridgeRelays(bytes32 transactionId) external view returns (bool);\n\n /// @notice Returns the status of a bridge transaction\n /// @param transactionId The ID of the bridge transaction\n /// @return BridgeStatus Status of the bridge transaction\n function bridgeStatuses(bytes32 transactionId) external view returns (BridgeStatus);\n\n /// @notice Returns the timestamp and relayer of a bridge proof\n /// @param transactionId The ID of the bridge transaction\n /// @return timestamp The timestamp of the bridge proof\n /// @return relayer The relayer address of the bridge proof\n function bridgeProofs(bytes32 transactionId) external view returns (uint96 timestamp, address relayer);\n\n /// @notice Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\n /// @param request The bridge request to decode\n function getBridgeTransactionV2(bytes memory request) external view returns (BridgeTransactionV2 memory);\n}\n\n// contracts/utils/MulticallTarget.sol\n\n// solhint-disable avoid-low-level-calls\n/// @notice Template for a contract that supports batched calls (preserving the msg.sender).\n/// Only calls with zero msg.value could be batched.\nabstract contract MulticallTarget is IMulticallTarget {\n error MulticallTarget__UndeterminedRevert();\n\n /// @notice Perform a batched call to this contract, preserving the msg.sender.\n /// The return data from each call is discarded.\n /// @dev The method is non-payable, so only calls with `msg.value == 0` could be batched.\n /// It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag.\n /// Otherwise, the whole batch call will be reverted with the original revert reason.\n /// @param data List of abi-encoded calldata for the calls to perform.\n /// @param ignoreReverts Whether to ignore the revert errors from the calls.\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external {\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\n if (!success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(result);\n }\n }\n }\n\n /// @notice Perform a batched call to this contract, preserving the msg.sender.\n /// The return data from each call is preserved.\n /// @dev The method is non-payable, so only calls with `msg.value == 0` could be batched.\n /// It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag.\n /// Otherwise, the whole batch call will be reverted with the original revert reason.\n /// @param data List of abi-encoded calldata for the calls to perform.\n /// @param ignoreReverts Whether to ignore the revert errors from the calls.\n /// @return results List of results from the calls: `(success, returnData)`.\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results)\n {\n results = new Result[](data.length);\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (results[i].success, results[i].returnData) = address(this).delegatecall(data[i]);\n if (!results[i].success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(results[i].returnData);\n }\n }\n }\n\n /// @dev Bubbles the revert message from the underlying call.\n /// Note: preserves the same custom error or revert string, if one was used.\n /// Source: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v5.0.2/contracts/utils/Address.sol#L143-L158\n function _bubbleRevert(bytes memory returnData) internal pure {\n // Look for revert reason and bubble it up if present\n if (returnData.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n // solhint-disable-next-line no-inline-assembly\n assembly {\n let returndata_size := mload(returnData)\n revert(add(32, returnData), returndata_size)\n }\n } else {\n revert MulticallTarget__UndeterminedRevert();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// contracts/libs/BridgeTransactionV2.sol\n\n// solhint-disable no-inline-assembly\nlibrary BridgeTransactionV2Lib {\n uint16 internal constant VERSION = 2;\n\n // Offsets of the fields in the packed BridgeTransactionV2 struct\n // uint16 version [000 .. 002)\n // uint32 originChainId [002 .. 006)\n // uint32 destChainId [006 .. 010)\n // address originSender [010 .. 030)\n // address destRecipient [030 .. 050)\n // address originToken [050 .. 070)\n // address destToken [070 .. 090)\n // uint256 originAmount [090 .. 122)\n // uint256 destAmount [122 .. 154)\n // uint256 originFeeAmount [154 .. 186)\n // uint256 deadline [186 .. 218)\n // uint256 nonce [218 .. 250)\n // address exclusivityRelayer [250 .. 270)\n // uint256 exclusivityEndTime [270 .. 302)\n // uint256 zapNative [302 .. 334)\n // bytes zapData [334 .. ***)\n\n // forgefmt: disable-start\n uint256 private constant OFFSET_ORIGIN_CHAIN_ID = 2;\n uint256 private constant OFFSET_DEST_CHAIN_ID = 6;\n uint256 private constant OFFSET_ORIGIN_SENDER = 10;\n uint256 private constant OFFSET_DEST_RECIPIENT = 30;\n uint256 private constant OFFSET_ORIGIN_TOKEN = 50;\n uint256 private constant OFFSET_DEST_TOKEN = 70;\n uint256 private constant OFFSET_ORIGIN_AMOUNT = 90;\n uint256 private constant OFFSET_DEST_AMOUNT = 122;\n uint256 private constant OFFSET_ORIGIN_FEE_AMOUNT = 154;\n uint256 private constant OFFSET_DEADLINE = 186;\n uint256 private constant OFFSET_NONCE = 218;\n uint256 private constant OFFSET_EXCLUSIVITY_RELAYER = 250;\n uint256 private constant OFFSET_EXCLUSIVITY_END_TIME = 270;\n uint256 private constant OFFSET_ZAP_NATIVE = 302;\n uint256 private constant OFFSET_ZAP_DATA = 334;\n // forgefmt: disable-end\n\n error BridgeTransactionV2__InvalidEncodedTx();\n error BridgeTransactionV2__UnsupportedVersion(uint16 version);\n\n /// @notice Validates the encoded transaction to be a tightly packed encoded payload for BridgeTransactionV2.\n /// @dev Checks the minimum length and the version, use this function before decoding any of the fields.\n function validateV2(bytes calldata encodedTx) internal pure {\n // Check the minimum length: must at least include all static fields.\n if (encodedTx.length \u003c OFFSET_ZAP_DATA) revert BridgeTransactionV2__InvalidEncodedTx();\n // Once we validated the length, we can be sure that the version field is present.\n uint16 version_ = version(encodedTx);\n if (version_ != VERSION) revert BridgeTransactionV2__UnsupportedVersion(version_);\n }\n\n /// @notice Encodes the BridgeTransactionV2 struct by tightly packing the fields.\n /// @dev `abi.decode` will not work as a result of the tightly packed fields. Use `decodeV2` to decode instead.\n function encodeV2(IFastBridgeV2.BridgeTransactionV2 memory bridgeTx) internal pure returns (bytes memory) {\n // We split the encoding into two parts to avoid stack-too-deep error\n bytes memory firstPart = abi.encodePacked(\n VERSION,\n bridgeTx.originChainId,\n bridgeTx.destChainId,\n bridgeTx.originSender,\n bridgeTx.destRecipient,\n bridgeTx.originToken,\n bridgeTx.destToken,\n bridgeTx.originAmount\n );\n return abi.encodePacked(\n firstPart,\n bridgeTx.destAmount,\n bridgeTx.originFeeAmount,\n // Note: we skip the deprecated `sendChainGas` flag, which was present in BridgeTransaction V1\n bridgeTx.deadline,\n bridgeTx.nonce,\n // New V2 fields: exclusivity\n bridgeTx.exclusivityRelayer,\n bridgeTx.exclusivityEndTime,\n // New V2 fields: Zap\n bridgeTx.zapNative,\n bridgeTx.zapData\n );\n }\n\n /// @notice Decodes the BridgeTransactionV2 struct from the encoded transaction.\n /// @dev Encoded BridgeTransactionV2 struct must be tightly packed.\n /// Use `validateV2` before decoding to ensure the encoded transaction is valid.\n function decodeV2(bytes calldata encodedTx)\n internal\n pure\n returns (IFastBridgeV2.BridgeTransactionV2 memory bridgeTx)\n {\n bridgeTx.originChainId = originChainId(encodedTx);\n bridgeTx.destChainId = destChainId(encodedTx);\n bridgeTx.originSender = originSender(encodedTx);\n bridgeTx.destRecipient = destRecipient(encodedTx);\n bridgeTx.originToken = originToken(encodedTx);\n bridgeTx.destToken = destToken(encodedTx);\n bridgeTx.originAmount = originAmount(encodedTx);\n bridgeTx.destAmount = destAmount(encodedTx);\n bridgeTx.originFeeAmount = originFeeAmount(encodedTx);\n bridgeTx.deadline = deadline(encodedTx);\n bridgeTx.nonce = nonce(encodedTx);\n bridgeTx.exclusivityRelayer = exclusivityRelayer(encodedTx);\n bridgeTx.exclusivityEndTime = exclusivityEndTime(encodedTx);\n bridgeTx.zapNative = zapNative(encodedTx);\n bridgeTx.zapData = zapData(encodedTx);\n }\n\n /// @notice Extracts the version from the encoded transaction.\n function version(bytes calldata encodedTx) internal pure returns (uint16 version_) {\n // Load 32 bytes from the start and shift it 240 bits to the right to get the highest 16 bits.\n assembly {\n version_ := shr(240, calldataload(encodedTx.offset))\n }\n }\n\n /// @notice Extracts the origin chain ID from the encoded transaction.\n function originChainId(bytes calldata encodedTx) internal pure returns (uint32 originChainId_) {\n // Load 32 bytes from the offset and shift it 224 bits to the right to get the highest 32 bits.\n assembly {\n originChainId_ := shr(224, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_CHAIN_ID)))\n }\n }\n\n /// @notice Extracts the destination chain ID from the encoded transaction.\n function destChainId(bytes calldata encodedTx) internal pure returns (uint32 destChainId_) {\n // Load 32 bytes from the offset and shift it 224 bits to the right to get the highest 32 bits.\n assembly {\n destChainId_ := shr(224, calldataload(add(encodedTx.offset, OFFSET_DEST_CHAIN_ID)))\n }\n }\n\n /// @notice Extracts the origin sender from the encoded transaction.\n function originSender(bytes calldata encodedTx) internal pure returns (address originSender_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n originSender_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_SENDER)))\n }\n }\n\n /// @notice Extracts the destination recipient from the encoded transaction.\n function destRecipient(bytes calldata encodedTx) internal pure returns (address destRecipient_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n destRecipient_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_DEST_RECIPIENT)))\n }\n }\n\n /// @notice Extracts the origin token from the encoded transaction.\n function originToken(bytes calldata encodedTx) internal pure returns (address originToken_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n originToken_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_TOKEN)))\n }\n }\n\n /// @notice Extracts the destination token from the encoded transaction.\n function destToken(bytes calldata encodedTx) internal pure returns (address destToken_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n destToken_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_DEST_TOKEN)))\n }\n }\n\n /// @notice Extracts the origin amount from the encoded transaction.\n function originAmount(bytes calldata encodedTx) internal pure returns (uint256 originAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n originAmount_ := calldataload(add(encodedTx.offset, OFFSET_ORIGIN_AMOUNT))\n }\n }\n\n /// @notice Extracts the destination amount from the encoded transaction.\n function destAmount(bytes calldata encodedTx) internal pure returns (uint256 destAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n destAmount_ := calldataload(add(encodedTx.offset, OFFSET_DEST_AMOUNT))\n }\n }\n\n /// @notice Extracts the origin fee amount from the encoded transaction.\n function originFeeAmount(bytes calldata encodedTx) internal pure returns (uint256 originFeeAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n originFeeAmount_ := calldataload(add(encodedTx.offset, OFFSET_ORIGIN_FEE_AMOUNT))\n }\n }\n\n /// @notice Extracts the deadline from the encoded transaction.\n function deadline(bytes calldata encodedTx) internal pure returns (uint256 deadline_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n deadline_ := calldataload(add(encodedTx.offset, OFFSET_DEADLINE))\n }\n }\n\n /// @notice Extracts the nonce from the encoded transaction.\n function nonce(bytes calldata encodedTx) internal pure returns (uint256 nonce_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n nonce_ := calldataload(add(encodedTx.offset, OFFSET_NONCE))\n }\n }\n\n /// @notice Extracts the exclusivity relayer from the encoded transaction.\n function exclusivityRelayer(bytes calldata encodedTx) internal pure returns (address exclusivityRelayer_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n exclusivityRelayer_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_EXCLUSIVITY_RELAYER)))\n }\n }\n\n /// @notice Extracts the exclusivity end time from the encoded transaction.\n function exclusivityEndTime(bytes calldata encodedTx) internal pure returns (uint256 exclusivityEndTime_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n exclusivityEndTime_ := calldataload(add(encodedTx.offset, OFFSET_EXCLUSIVITY_END_TIME))\n }\n }\n\n /// @notice Extracts the Zap's native value from the encoded transaction.\n function zapNative(bytes calldata encodedTx) internal pure returns (uint256 zapNative_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n zapNative_ := calldataload(add(encodedTx.offset, OFFSET_ZAP_NATIVE))\n }\n }\n\n /// @notice Extracts the Zap's data from the encoded transaction.\n function zapData(bytes calldata encodedTx) internal pure returns (bytes calldata zapData_) {\n zapData_ = encodedTx[OFFSET_ZAP_DATA:];\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// contracts/libs/UniversalToken.sol\n\nlibrary UniversalTokenLib {\n using SafeERC20 for IERC20;\n\n address internal constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Transfers tokens to the given account. Reverts if transfer is not successful.\n /// @dev This might trigger fallback, if ETH is transferred to the contract.\n /// Make sure this can not lead to reentrancy attacks.\n function universalTransfer(address token, address to, uint256 value) internal {\n // Don't do anything, if need to send tokens to this address\n if (to == address(this)) return;\n // Don't do anything, if trying to send zero value\n if (value == 0) return;\n if (token == ETH_ADDRESS) {\n /// @dev Note: this can potentially lead to executing code in `to`.\n // solhint-disable-next-line avoid-low-level-calls\n (bool success,) = to.call{value: value}(\"\");\n require(success, \"ETH transfer failed\");\n } else {\n IERC20(token).safeTransfer(to, value);\n }\n }\n\n /// @notice Issues an infinite allowance to the spender, if the current allowance is insufficient\n /// to spend the given amount.\n function universalApproveInfinity(address token, address spender, uint256 amountToSpend) internal {\n // ETH Chad doesn't require your approval\n if (token == ETH_ADDRESS) return;\n // No-op if allowance is already sufficient\n uint256 allowance = IERC20(token).allowance(address(this), spender);\n if (allowance \u003e= amountToSpend) return;\n // Otherwise, reset approval to 0 and set to max allowance\n if (allowance \u003e 0) IERC20(token).safeDecreaseAllowance(spender, allowance);\n IERC20(token).safeIncreaseAllowance(spender, type(uint256).max);\n }\n\n /// @notice Returns the balance of the given token (or native ETH) for the given account.\n function universalBalanceOf(address token, address account) internal view returns (uint256) {\n if (token == ETH_ADDRESS) {\n return account.balance;\n } else {\n return IERC20(token).balanceOf(account);\n }\n }\n\n /// @dev Checks that token is a contract and not ETH_ADDRESS.\n function assertIsContract(address token) internal view {\n // Check that ETH_ADDRESS was not used (in case this is a predeploy on any of the chains)\n if (token == UniversalTokenLib.ETH_ADDRESS) revert TokenNotContract();\n // Check that token is not an EOA\n if (token.code.length == 0) revert TokenNotContract();\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/Admin.sol\n\ncontract Admin is IAdmin, AccessControlEnumerable {\n using UniversalTokenLib for address;\n\n bytes32 public constant RELAYER_ROLE = keccak256(\"RELAYER_ROLE\");\n bytes32 public constant REFUNDER_ROLE = keccak256(\"REFUNDER_ROLE\");\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n uint256 public constant FEE_BPS = 1e6;\n uint256 public constant FEE_RATE_MAX = 0.01e6; // max 1% on origin amount\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Chain gas amount to forward as rebate if requested\n uint256 public chainGasAmount;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n }\n\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n require(newFeeRate \u003c= FEE_RATE_MAX, \"newFeeRate \u003e max\");\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n token.universalTransfer(recipient, feeAmount);\n emit FeesSwept(token, recipient, feeAmount);\n }\n\n function setChainGasAmount(uint256 newChainGasAmount) external onlyRole(GOVERNOR_ROLE) {\n uint256 oldChainGasAmount = chainGasAmount;\n chainGasAmount = newChainGasAmount;\n emit ChainGasAmountUpdated(oldChainGasAmount, newChainGasAmount);\n }\n}\n\n// contracts/FastBridgeV2.sol\n\n/// @notice FastBridgeV2 is a contract for bridging tokens across chains.\ncontract FastBridgeV2 is Admin, MulticallTarget, IFastBridgeV2, IFastBridgeV2Errors {\n using BridgeTransactionV2Lib for bytes;\n using SafeERC20 for IERC20;\n\n /// @notice Address reserved for native gas token (ETH on Ethereum and most L2s, AVAX on Avalanche, etc)\n address public constant NATIVE_GAS_TOKEN = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Delay for a transaction after which it could be permisionlessly refunded\n uint256 public constant REFUND_DELAY = 7 days;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n /// @notice Maximum length of accepted zapData\n uint256 public constant MAX_ZAP_DATA_LENGTH = 2 ** 16 - 1;\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeTxDetails) public bridgeTxDetails;\n /// @notice Relay details on destination chain\n mapping(bytes32 =\u003e BridgeRelay) public bridgeRelayDetails;\n /// @notice Unique bridge nonces tracked per originSender\n mapping(address =\u003e uint256) public senderNonces;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Replaced by senderNonces\n uint256 public immutable nonce = 0;\n /// @notice the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n bridge({\n params: params,\n paramsV2: BridgeParamsV2({\n quoteRelayer: address(0),\n quoteExclusivitySeconds: 0,\n quoteId: bytes(\"\"),\n zapNative: 0,\n zapData: bytes(\"\")\n })\n });\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes calldata request) external payable {\n // relay override will validate the request\n relay({request: request, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes calldata request, bytes32 destTxHash) external {\n request.validateV2();\n prove({transactionId: keccak256(request), destTxHash: destTxHash, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridgeV2\n function claim(bytes calldata request) external {\n // claim override will validate the request\n claim({request: request, to: address(0)});\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Aggregate the read operations from the same storage slot\n address disputedRelayer = $.proofRelayer;\n BridgeStatus status = $.status;\n uint56 proofBlockTimestamp = $.proofBlockTimestamp;\n // Can only dispute a RELAYER_PROVED transaction within the dispute period\n if (status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(proofBlockTimestamp) \u003e DISPUTE_PERIOD) {\n revert DisputePeriodPassed();\n }\n // Update status to REQUESTED and delete the disputed proof details\n // Note: these are storage writes\n $.status = BridgeStatus.REQUESTED;\n $.proofRelayer = address(0);\n $.proofBlockTimestamp = 0;\n\n emit BridgeProofDisputed(transactionId, disputedRelayer);\n }\n\n /// @inheritdoc IFastBridge\n function refund(bytes calldata request) external {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Can only refund a REQUESTED transaction after its deadline expires\n if ($.status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n uint256 deadline = request.deadline();\n // Permissionless refund is only allowed after REFUND_DELAY on top of the deadline\n if (!hasRole(REFUNDER_ROLE, msg.sender)) deadline += REFUND_DELAY;\n if (block.timestamp \u003c= deadline) revert DeadlineNotExceeded();\n // Update status to REFUNDED and return the full amount (collateral + protocol fees) to the original sender.\n // The protocol fees are only updated when the transaction is claimed, so we don't need to update them here.\n // Note: this is a storage write\n $.status = BridgeStatus.REFUNDED;\n\n address to = request.originSender();\n address token = request.originToken();\n uint256 amount = request.originAmount() + request.originFeeAmount();\n // Emit the event before any external calls\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n // Complete the user refund as the last transaction action\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(to), amount);\n } else {\n IERC20(token).safeTransfer(to, amount);\n }\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // The correct relayer can only claim a RELAYER_PROVED transaction after the dispute period\n if ($.status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if ($.proofRelayer != relayer) revert SenderIncorrect();\n return _timeSince($.proofBlockTimestamp) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n /// @dev This method is added to achieve backwards compatibility with decoding requests into V1 structs:\n /// - `zapNative` is partially reported as a zero/non-zero flag\n /// - `zapData` is ignored\n /// In order to process all kinds of requests use getBridgeTransactionV2 instead.\n function getBridgeTransaction(bytes calldata request) external view returns (BridgeTransaction memory) {\n // Try decoding into V2 struct first. This will revert if V1 struct is passed\n try this.getBridgeTransactionV2(request) returns (BridgeTransactionV2 memory txV2) {\n // Note: we entirely ignore the zapData field, as it was not present in V1\n return BridgeTransaction({\n originChainId: txV2.originChainId,\n destChainId: txV2.destChainId,\n originSender: txV2.originSender,\n destRecipient: txV2.destRecipient,\n originToken: txV2.originToken,\n destToken: txV2.destToken,\n originAmount: txV2.originAmount,\n destAmount: txV2.destAmount,\n originFeeAmount: txV2.originFeeAmount,\n sendChainGas: txV2.zapNative != 0,\n deadline: txV2.deadline,\n nonce: txV2.nonce\n });\n } catch {\n // Fallback to V1 struct\n return abi.decode(request, (BridgeTransaction));\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function getBridgeTransactionV2(bytes calldata request) external pure returns (BridgeTransactionV2 memory) {\n request.validateV2();\n return BridgeTransactionV2Lib.decodeV2(request);\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) public payable {\n int256 exclusivityEndTime = 0;\n // if relayer exclusivity is not intended for this bridge, set exclusivityEndTime to static zero\n // otherwise, set exclusivity to expire at the current block ts offset by quoteExclusivitySeconds\n if (paramsV2.quoteRelayer != address(0)) {\n exclusivityEndTime = int256(block.timestamp) + paramsV2.quoteExclusivitySeconds;\n }\n _validateBridgeParams(params, paramsV2, exclusivityEndTime);\n\n // transfer tokens to bridge contract\n /// @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _takeBridgedUserAsset(params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) {\n originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n }\n\n // set status to requested\n bytes memory request = BridgeTransactionV2Lib.encodeV2(\n BridgeTransactionV2({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n deadline: params.deadline,\n nonce: senderNonces[params.sender]++, // increment nonce on every bridge\n exclusivityRelayer: paramsV2.quoteRelayer,\n // We checked exclusivityEndTime to be in range [0 .. params.deadline] above, so can safely cast\n exclusivityEndTime: uint256(exclusivityEndTime),\n zapNative: paramsV2.zapNative,\n zapData: paramsV2.zapData\n })\n );\n bytes32 transactionId = keccak256(request);\n // Note: the tx status will be updated throughout the tx lifecycle, while destChainId is set once here\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n bridgeTxDetails[transactionId].destChainId = params.dstChainId;\n\n emit BridgeRequested({\n transactionId: transactionId,\n sender: params.sender,\n request: request,\n destChainId: params.dstChainId,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n sendChainGas: paramsV2.zapNative != 0\n });\n emit BridgeQuoteDetails(transactionId, paramsV2.quoteId);\n }\n\n /// @inheritdoc IFastBridgeV2\n function relay(bytes calldata request, address relayer) public payable {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n _validateRelayParams(request, transactionId, relayer);\n // mark bridge transaction as relayed\n bridgeRelayDetails[transactionId] =\n BridgeRelay({blockNumber: uint48(block.number), blockTimestamp: uint48(block.timestamp), relayer: relayer});\n\n // transfer tokens to recipient on destination chain and trigger Zap if requested\n address to = request.destRecipient();\n address token = request.destToken();\n uint256 amount = request.destAmount();\n uint256 zapNative = request.zapNative();\n\n // Emit the event before any external calls\n emit BridgeRelayed({\n transactionId: transactionId,\n relayer: relayer,\n to: to,\n originChainId: request.originChainId(),\n originToken: request.originToken(),\n destToken: token,\n originAmount: request.originAmount(),\n destAmount: amount,\n chainGasAmount: zapNative\n });\n\n // All state changes have been done at this point, can proceed to the external calls.\n // This follows the checks-effects-interactions pattern to mitigate potential reentrancy attacks.\n if (token == NATIVE_GAS_TOKEN) {\n // For the native gas token, additional zapNative is not allowed\n if (zapNative != 0) revert ZapNativeNotSupported();\n // Check that the correct msg.value was sent\n if (msg.value != amount) revert MsgValueIncorrect();\n // Don't do a native transfer yet: we will handle it alongside the Zap below\n } else {\n // For ERC20s, we check that the correct msg.value was sent\n if (msg.value != zapNative) revert MsgValueIncorrect();\n // We need to transfer the tokens from the Relayer to the recipient first before performing an\n // optional post-transfer Zap.\n IERC20(token).safeTransferFrom(msg.sender, to, amount);\n }\n // At this point we have done:\n // - Transferred the requested amount of ERC20 tokens to the recipient.\n // At this point we have confirmed:\n // - For ERC20s: msg.value matches the requested zapNative amount.\n // - For the native gas token: msg.value matches the requested destAmount.\n // Remaining optional things to do:\n // - Forward the full msg.value to the recipient (if non-zero).\n // - Trigger a Zap (if zapData is present).\n bytes calldata zapData = request.zapData();\n if (zapData.length != 0) {\n // Zap Data is present: Zap has been requested by the recipient. Trigger it forwarding the full msg.value.\n\n // Note: if token has a fee on transfers, the recipient will have received less than `amount`.\n // This is a very niche edge case and should be handled by the recipient contract.\n _triggerZapWithChecks({recipient: to, token: token, amount: amount, zapData: zapData});\n } else if (msg.value != 0) {\n // Zap Data is missing, but msg.value was sent. This could happen in two different cases:\n // - Relay with the native gas token is happening.\n // - Relay with ERC20 is happening, with a `zapNative \u003e 0` request.\n // In both cases, we need to transfer the full msg.value to the recipient.\n Address.sendValue(payable(to), msg.value);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) public onlyRole(RELAYER_ROLE) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n\n // Can only prove a REQUESTED transaction\n if ($.status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n // Update status to RELAYER_PROVED and store the proof details\n // Note: these are storage writes\n $.status = BridgeStatus.RELAYER_PROVED;\n $.proofBlockTimestamp = uint56(block.timestamp);\n $.proofRelayer = relayer;\n\n emit BridgeProofProvided(transactionId, relayer, destTxHash);\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes calldata request, address to) public {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Aggregate the read operations from the same storage slot\n address proofRelayer = $.proofRelayer;\n BridgeStatus status = $.status;\n uint56 proofBlockTimestamp = $.proofBlockTimestamp;\n\n // Can only claim a RELAYER_PROVED transaction after the dispute period\n if (status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(proofBlockTimestamp) \u003c= DISPUTE_PERIOD) {\n revert DisputePeriodNotPassed();\n }\n\n if (to == address(0)) {\n // Anyone could claim the funds to the proven relayer on their behalf\n to = proofRelayer;\n } else if (proofRelayer != msg.sender) {\n // Only the proven relayer could specify an address to claim the funds to\n revert SenderIncorrect();\n }\n\n // Update status to RELAYER_CLAIMED and transfer the origin collateral to the specified claim address\n // Note: this is a storage write\n $.status = BridgeStatus.RELAYER_CLAIMED;\n\n address token = request.originToken();\n uint256 amount = request.originAmount();\n // Update protocol fees if origin fee amount exists\n uint256 originFeeAmount = request.originFeeAmount();\n if (originFeeAmount \u003e 0) protocolFees[token] += originFeeAmount;\n // Emit the event before any external calls\n emit BridgeDepositClaimed(transactionId, proofRelayer, to, token, amount);\n // Complete the relayer claim as the last transaction action\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(to), amount);\n } else {\n IERC20(token).safeTransfer(to, amount);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeStatuses(bytes32 transactionId) public view returns (BridgeStatus status) {\n return bridgeTxDetails[transactionId].status;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeProofs(bytes32 transactionId) public view returns (uint96 timestamp, address relayer) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n\n timestamp = $.proofBlockTimestamp;\n relayer = $.proofRelayer;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeRelays(bytes32 transactionId) public view returns (bool) {\n // has this transactionId been relayed?\n return bridgeRelayDetails[transactionId].relayer != address(0);\n }\n\n /// @notice Takes the bridged asset from the user into FastBridgeV2 custody. It will be later\n /// claimed by the relayer who completed the relay on destination chain, or refunded back to the user,\n /// should no one complete the relay.\n function _takeBridgedUserAsset(address token, uint256 amount) internal returns (uint256 amountTaken) {\n if (token == NATIVE_GAS_TOKEN) {\n // For the native gas token, we just need to check that the supplied msg.value is correct.\n // Supplied `msg.value` is already in FastBridgeV2 custody.\n if (amount != msg.value) revert MsgValueIncorrect();\n amountTaken = msg.value;\n } else {\n // For ERC20s, token is explicitly transferred from the user to FastBridgeV2.\n // We don't allow non-zero `msg.value` to avoid extra funds from being stuck in FastBridgeV2.\n if (msg.value != 0) revert MsgValueIncorrect();\n // Throw an explicit error if the provided token address is not a contract\n if (token.code.length == 0) revert TokenNotContract();\n amountTaken = IERC20(token).balanceOf(address(this));\n IERC20(token).safeTransferFrom(msg.sender, address(this), amount);\n // Use the balance difference as the amount taken in case of fee on transfer tokens.\n amountTaken = IERC20(token).balanceOf(address(this)) - amountTaken;\n }\n }\n\n /// @notice Calls the Recipient's hook function with the specified zapData and performs\n /// all the necessary checks for the returned value.\n function _triggerZapWithChecks(address recipient, address token, uint256 amount, bytes calldata zapData) internal {\n // This will bubble any revert messages from the hook function\n bytes memory returnData = Address.functionCallWithValue({\n target: recipient,\n data: abi.encodeCall(IZapRecipient.zap, (token, amount, zapData)),\n // Note: see `relay()` for reasoning behind passing msg.value\n value: msg.value\n });\n // Explicit revert if no return data at all\n if (returnData.length == 0) revert RecipientNoReturnValue();\n // Check that exactly a single return value was returned\n if (returnData.length != 32) revert RecipientIncorrectReturnValue();\n // Return value should be abi-encoded hook function selector\n if (bytes32(returnData) != bytes32(IZapRecipient.zap.selector)) {\n revert RecipientIncorrectReturnValue();\n }\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint56(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint56).max but\n /// proof.timestamp \u003c type(uint56).max via unchecked statement\n /// @param proofBlockTimestamp The bridge proof block timestamp\n /// @return delta Time delta since proof submitted\n function _timeSince(uint56 proofBlockTimestamp) internal view returns (uint256 delta) {\n unchecked {\n delta = uint56(block.timestamp) - proofBlockTimestamp;\n }\n }\n\n /// @notice Performs all the necessary checks for a bridge to happen.\n /// @dev There's no good way to refactor this function to reduce cyclomatic complexity due to\n /// the number of checks that need to be performed, so we skip the code-complexity rule here.\n // solhint-disable-next-line code-complexity\n function _validateBridgeParams(\n BridgeParams memory params,\n BridgeParamsV2 memory paramsV2,\n int256 exclusivityEndTime\n )\n internal\n view\n {\n // Check V1 (legacy) params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.sender == address(0) || params.to == address(0)) revert ZeroAddress();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n // Check V2 params\n if (paramsV2.zapData.length \u003e MAX_ZAP_DATA_LENGTH) revert ZapDataLengthAboveMax();\n if (paramsV2.zapNative != 0 \u0026\u0026 params.destToken == NATIVE_GAS_TOKEN) {\n revert ZapNativeNotSupported();\n }\n // exclusivityEndTime must be in range [0 .. params.deadline]\n if (exclusivityEndTime \u003c 0 || exclusivityEndTime \u003e int256(params.deadline)) {\n revert ExclusivityParamsIncorrect();\n }\n }\n\n /// @notice Performs all the necessary checks for a relay to happen.\n function _validateRelayParams(bytes calldata request, bytes32 transactionId, address relayer) internal view {\n if (relayer == address(0)) revert ZeroAddress();\n // Check if the transaction has already been relayed\n if (bridgeRelays(transactionId)) revert TransactionRelayed();\n if (request.destChainId() != block.chainid) revert ChainIncorrect();\n // Check the deadline for relay to happen\n if (block.timestamp \u003e request.deadline()) revert DeadlineExceeded();\n // Check the exclusivity period, if it is still ongoing\n address exclRelayer = request.exclusivityRelayer();\n if (exclRelayer != address(0) \u0026\u0026 exclRelayer != relayer \u0026\u0026 block.timestamp \u003c= request.exclusivityEndTime()) {\n revert ExclusivityPeriodNotPassed();\n }\n }\n}\n","language":"Solidity","languageVersion":"0.8.24","compilerVersion":"0.8.24","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"","srcMapRuntime":"","abiDefinition":[{"inputs":[],"name":"AccessControlBadConfirmation","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"bytes32","name":"neededRole","type":"bytes32"}],"name":"AccessControlUnauthorizedAccount","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"previousAdminRole","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"newAdminRole","type":"bytes32"}],"name":"RoleAdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleRevoked","type":"event"},{"inputs":[],"name":"DEFAULT_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleAdmin","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"grantRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"hasRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"callerConfirmation","type":"address"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"revokeRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"}],"userDoc":{"kind":"user","methods":{},"version":1},"developerDoc":{"details":"Contract module that allows children to implement role-based access control mechanisms. This is a lightweight version that doesn't allow enumerating role members except through off-chain means by accessing the contract event logs. Some applications may benefit from on-chain enumerability, for those cases see {AccessControlEnumerable}. Roles are referred to by their `bytes32` identifier. These should be exposed in the external API and be unique. The best way to achieve this is by using `public constant` hash digests: ```solidity bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\"); ``` Roles can be used to represent a set of permissions. To restrict access to a function call, use {hasRole}: ```solidity function foo() public { require(hasRole(MY_ROLE, msg.sender)); ... } ``` Roles can be granted and revoked dynamically via the {grantRole} and {revokeRole} functions. Each role has an associated admin role, and only accounts that have a role's admin role can call {grantRole} and {revokeRole}. By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means that only accounts with this role will be able to grant or revoke other roles. More complex role relationships can be created by using {_setRoleAdmin}. WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to grant and revoke this role. Extra precautions should be taken to secure accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules} to enforce additional security measures for this role.","errors":{"AccessControlBadConfirmation()":[{"details":"The caller of a function is not the expected one. NOTE: Don't confuse with {AccessControlUnauthorizedAccount}."}],"AccessControlUnauthorizedAccount(address,bytes32)":[{"details":"The `account` is missing a role."}]},"events":{"RoleAdminChanged(bytes32,bytes32,bytes32)":{"details":"Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole` `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite {RoleAdminChanged} not being emitted signaling this."},"RoleGranted(bytes32,address,address)":{"details":"Emitted when `account` is granted `role`. `sender` is the account that originated the contract call, an admin role bearer except when using {AccessControl-_setupRole}."},"RoleRevoked(bytes32,address,address)":{"details":"Emitted when `account` is revoked `role`. `sender` is the account that originated the contract call: - if using `revokeRole`, it is the admin role bearer - if using `renounceRole`, it is the role bearer (i.e. `account`)"}},"kind":"dev","methods":{"getRoleAdmin(bytes32)":{"details":"Returns the admin role that controls `role`. See {grantRole} and {revokeRole}. To change a role's admin, use {_setRoleAdmin}."},"grantRole(bytes32,address)":{"details":"Grants `role` to `account`. If `account` had not been already granted `role`, emits a {RoleGranted} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleGranted} event."},"hasRole(bytes32,address)":{"details":"Returns `true` if `account` has been granted `role`."},"renounceRole(bytes32,address)":{"details":"Revokes `role` from the calling account. Roles are often managed via {grantRole} and {revokeRole}: this function's purpose is to provide a mechanism for accounts to lose their privileges if they are compromised (such as when a trusted device is misplaced). If the calling account had been revoked `role`, emits a {RoleRevoked} event. Requirements: - the caller must be `callerConfirmation`. May emit a {RoleRevoked} event."},"revokeRole(bytes32,address)":{"details":"Revokes `role` from `account`. If `account` had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleRevoked} event."},"supportsInterface(bytes4)":{"details":"See {IERC165-supportsInterface}."}},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[],\"name\":\"AccessControlBadConfirmation\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"neededRole\",\"type\":\"bytes32\"}],\"name\":\"AccessControlUnauthorizedAccount\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"previousAdminRole\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"newAdminRole\",\"type\":\"bytes32\"}],\"name\":\"RoleAdminChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleGranted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleRevoked\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"DEFAULT_ADMIN_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"}],\"name\":\"getRoleAdmin\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"grantRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"hasRole\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"callerConfirmation\",\"type\":\"address\"}],\"name\":\"renounceRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"revokeRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes4\",\"name\":\"interfaceId\",\"type\":\"bytes4\"}],\"name\":\"supportsInterface\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"}],\"devdoc\":{\"details\":\"Contract module that allows children to implement role-based access control mechanisms. This is a lightweight version that doesn't allow enumerating role members except through off-chain means by accessing the contract event logs. Some applications may benefit from on-chain enumerability, for those cases see {AccessControlEnumerable}. Roles are referred to by their `bytes32` identifier. These should be exposed in the external API and be unique. The best way to achieve this is by using `public constant` hash digests: ```solidity bytes32 public constant MY_ROLE = keccak256(\\\"MY_ROLE\\\"); ``` Roles can be used to represent a set of permissions. To restrict access to a function call, use {hasRole}: ```solidity function foo() public { require(hasRole(MY_ROLE, msg.sender)); ... } ``` Roles can be granted and revoked dynamically via the {grantRole} and {revokeRole} functions. Each role has an associated admin role, and only accounts that have a role's admin role can call {grantRole} and {revokeRole}. By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means that only accounts with this role will be able to grant or revoke other roles. More complex role relationships can be created by using {_setRoleAdmin}. WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to grant and revoke this role. Extra precautions should be taken to secure accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules} to enforce additional security measures for this role.\",\"errors\":{\"AccessControlBadConfirmation()\":[{\"details\":\"The caller of a function is not the expected one. NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\"}],\"AccessControlUnauthorizedAccount(address,bytes32)\":[{\"details\":\"The `account` is missing a role.\"}]},\"events\":{\"RoleAdminChanged(bytes32,bytes32,bytes32)\":{\"details\":\"Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole` `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite {RoleAdminChanged} not being emitted signaling this.\"},\"RoleGranted(bytes32,address,address)\":{\"details\":\"Emitted when `account` is granted `role`. `sender` is the account that originated the contract call, an admin role bearer except when using {AccessControl-_setupRole}.\"},\"RoleRevoked(bytes32,address,address)\":{\"details\":\"Emitted when `account` is revoked `role`. `sender` is the account that originated the contract call: - if using `revokeRole`, it is the admin role bearer - if using `renounceRole`, it is the role bearer (i.e. `account`)\"}},\"kind\":\"dev\",\"methods\":{\"getRoleAdmin(bytes32)\":{\"details\":\"Returns the admin role that controls `role`. See {grantRole} and {revokeRole}. To change a role's admin, use {_setRoleAdmin}.\"},\"grantRole(bytes32,address)\":{\"details\":\"Grants `role` to `account`. If `account` had not been already granted `role`, emits a {RoleGranted} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleGranted} event.\"},\"hasRole(bytes32,address)\":{\"details\":\"Returns `true` if `account` has been granted `role`.\"},\"renounceRole(bytes32,address)\":{\"details\":\"Revokes `role` from the calling account. Roles are often managed via {grantRole} and {revokeRole}: this function's purpose is to provide a mechanism for accounts to lose their privileges if they are compromised (such as when a trusted device is misplaced). If the calling account had been revoked `role`, emits a {RoleRevoked} event. Requirements: - the caller must be `callerConfirmation`. May emit a {RoleRevoked} event.\"},\"revokeRole(bytes32,address)\":{\"details\":\"Revokes `role` from `account`. If `account` had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleRevoked} event.\"},\"supportsInterface(bytes4)\":{\"details\":\"See {IERC165-supportsInterface}.\"}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeV2.sol\":\"AccessControl\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeV2.sol\":{\"keccak256\":\"0x5069b55ca07f21bfe30b2a43c18a18318c8af9c181b2dcb07c290825efd70f34\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://273dc020a49d08e50126bbea0d7f783f79d08c702f2fdbc560618d24af308acc\",\"dweb:/ipfs/QmXJ2UVzFc8EPB74RT4CXQPC4xw66jt4T13poyfyd3UERh\"]}},\"version\":1}"},"hashes":{"DEFAULT_ADMIN_ROLE()":"a217fddf","getRoleAdmin(bytes32)":"248a9ca3","grantRole(bytes32,address)":"2f2ff15d","hasRole(bytes32,address)":"91d14854","renounceRole(bytes32,address)":"36568abe","revokeRole(bytes32,address)":"d547741f","supportsInterface(bytes4)":"01ffc9a7"}},"solidity/FastBridgeV2.sol:AccessControlEnumerable":{"code":"0x","runtime-code":"0x","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.24 ^0.8.20 ^0.8.4;\n\n// contracts/interfaces/IAdmin.sol\n\ninterface IAdmin {\n // ============ Events ============\n\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n event ChainGasAmountUpdated(uint256 oldChainGasAmount, uint256 newChainGasAmount);\n\n // ============ Methods ============\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n\n function setChainGasAmount(uint256 newChainGasAmount) external;\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IFastBridgeV2Errors.sol\n\ninterface IFastBridgeV2Errors {\n error AmountIncorrect();\n error ChainIncorrect();\n error ExclusivityParamsIncorrect();\n error MsgValueIncorrect();\n error SenderIncorrect();\n error StatusIncorrect();\n error TokenNotContract();\n error ZapDataLengthAboveMax();\n error ZapNativeNotSupported();\n error ZeroAddress();\n\n error RecipientIncorrectReturnValue();\n error RecipientNoReturnValue();\n\n error DeadlineExceeded();\n error DeadlineNotExceeded();\n error DeadlineTooShort();\n error DisputePeriodNotPassed();\n error DisputePeriodPassed();\n error ExclusivityPeriodNotPassed();\n\n error TransactionRelayed();\n}\n\n// contracts/interfaces/IMulticallTarget.sol\n\n/// @notice Interface for a contract that can be called multiple times by the same caller. Inspired by MulticallV3:\n/// https://github.com/mds1/multicall/blob/master/src/Multicall3.sol\ninterface IMulticallTarget {\n struct Result {\n bool success;\n bytes returnData;\n }\n\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external;\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results);\n}\n\n// contracts/interfaces/IZapRecipient.sol\n\ninterface IZapRecipient {\n function zap(address token, uint256 amount, bytes memory zapData) external payable returns (bytes4);\n}\n\n// contracts/libs/Errors.sol\n\nerror DeadlineExceeded();\nerror DeadlineNotExceeded();\nerror DeadlineTooShort();\nerror InsufficientOutputAmount();\n\nerror MsgValueIncorrect();\nerror PoolNotFound();\nerror TokenAddressMismatch();\nerror TokenNotContract();\nerror TokenNotETH();\nerror TokensIdentical();\n\nerror ChainIncorrect();\nerror AmountIncorrect();\nerror ZeroAddress();\n\nerror DisputePeriodNotPassed();\nerror DisputePeriodPassed();\nerror SenderIncorrect();\nerror StatusIncorrect();\nerror TransactionIdIncorrect();\nerror TransactionRelayed();\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// contracts/interfaces/IFastBridgeV2.sol\n\ninterface IFastBridgeV2 is IFastBridge {\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n struct BridgeTxDetails {\n BridgeStatus status;\n uint32 destChainId;\n uint56 proofBlockTimestamp;\n address proofRelayer;\n }\n\n struct BridgeRelay {\n uint48 blockNumber;\n uint48 blockTimestamp;\n address relayer;\n }\n\n /// @notice New params introduced in the FastBridgeV2.\n /// We are passing fields from the older BridgeParams struct outside of this struct\n /// for backwards compatibility.\n /// Note: quoteRelayer and quoteExclusivitySeconds are either both zero (indicating no exclusivity)\n /// or both non-zero (indicating exclusivity for the given period).\n /// Note: zapNative \u003e 0 can NOT be used with destToken = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE (native token)\n /// @param quoteRelayer Relayer that provided the quote for the transaction\n /// @param quoteExclusivitySeconds Period of time the quote relayer is guaranteed exclusivity after user's deposit\n /// @param quoteId Unique quote identifier used for tracking the quote\n /// @param zapNative ETH value to send to the recipient (if any)\n /// @param zapData Parameters for the Zap to the destination recipient (if any)\n struct BridgeParamsV2 {\n address quoteRelayer;\n int256 quoteExclusivitySeconds;\n bytes quoteId;\n uint256 zapNative;\n bytes zapData;\n }\n\n /// @notice Updated bridge transaction struct to include parameters introduced in FastBridgeV2.\n /// Note: only `exclusivityRelayer` can fill such a transaction until `exclusivityEndTime`.\n struct BridgeTransactionV2 {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n // Note: sendChainGas flag from V1 is deprecated\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n address exclusivityRelayer;\n uint256 exclusivityEndTime;\n uint256 zapNative; // ETH value to send to the recipient (if any)\n bytes zapData; // data to pass for the Zap action (if any)\n }\n\n event BridgeQuoteDetails(bytes32 indexed transactionId, bytes quoteId);\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability\n /// to provide temporary exclusivity fill rights for the quote relayer.\n /// @param params The parameters required to bridge\n /// @param paramsV2 The parameters for exclusivity fill rights (optional, can be left empty)\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function relay(bytes memory request, address relayer) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param transactionId The transaction id associated with the encoded bridge transaction to prove\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital.\n /// @notice Can only send funds to the relayer address on the proof.\n /// @param request The encoded bridge transaction to claim on origin chain\n function claim(bytes memory request) external;\n /// @notice Checks if a transaction has been relayed\n /// @param transactionId The ID of the transaction to check\n /// @return True if the transaction has been relayed, false otherwise\n function bridgeRelays(bytes32 transactionId) external view returns (bool);\n\n /// @notice Returns the status of a bridge transaction\n /// @param transactionId The ID of the bridge transaction\n /// @return BridgeStatus Status of the bridge transaction\n function bridgeStatuses(bytes32 transactionId) external view returns (BridgeStatus);\n\n /// @notice Returns the timestamp and relayer of a bridge proof\n /// @param transactionId The ID of the bridge transaction\n /// @return timestamp The timestamp of the bridge proof\n /// @return relayer The relayer address of the bridge proof\n function bridgeProofs(bytes32 transactionId) external view returns (uint96 timestamp, address relayer);\n\n /// @notice Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\n /// @param request The bridge request to decode\n function getBridgeTransactionV2(bytes memory request) external view returns (BridgeTransactionV2 memory);\n}\n\n// contracts/utils/MulticallTarget.sol\n\n// solhint-disable avoid-low-level-calls\n/// @notice Template for a contract that supports batched calls (preserving the msg.sender).\n/// Only calls with zero msg.value could be batched.\nabstract contract MulticallTarget is IMulticallTarget {\n error MulticallTarget__UndeterminedRevert();\n\n /// @notice Perform a batched call to this contract, preserving the msg.sender.\n /// The return data from each call is discarded.\n /// @dev The method is non-payable, so only calls with `msg.value == 0` could be batched.\n /// It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag.\n /// Otherwise, the whole batch call will be reverted with the original revert reason.\n /// @param data List of abi-encoded calldata for the calls to perform.\n /// @param ignoreReverts Whether to ignore the revert errors from the calls.\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external {\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\n if (!success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(result);\n }\n }\n }\n\n /// @notice Perform a batched call to this contract, preserving the msg.sender.\n /// The return data from each call is preserved.\n /// @dev The method is non-payable, so only calls with `msg.value == 0` could be batched.\n /// It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag.\n /// Otherwise, the whole batch call will be reverted with the original revert reason.\n /// @param data List of abi-encoded calldata for the calls to perform.\n /// @param ignoreReverts Whether to ignore the revert errors from the calls.\n /// @return results List of results from the calls: `(success, returnData)`.\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results)\n {\n results = new Result[](data.length);\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (results[i].success, results[i].returnData) = address(this).delegatecall(data[i]);\n if (!results[i].success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(results[i].returnData);\n }\n }\n }\n\n /// @dev Bubbles the revert message from the underlying call.\n /// Note: preserves the same custom error or revert string, if one was used.\n /// Source: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v5.0.2/contracts/utils/Address.sol#L143-L158\n function _bubbleRevert(bytes memory returnData) internal pure {\n // Look for revert reason and bubble it up if present\n if (returnData.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n // solhint-disable-next-line no-inline-assembly\n assembly {\n let returndata_size := mload(returnData)\n revert(add(32, returnData), returndata_size)\n }\n } else {\n revert MulticallTarget__UndeterminedRevert();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// contracts/libs/BridgeTransactionV2.sol\n\n// solhint-disable no-inline-assembly\nlibrary BridgeTransactionV2Lib {\n uint16 internal constant VERSION = 2;\n\n // Offsets of the fields in the packed BridgeTransactionV2 struct\n // uint16 version [000 .. 002)\n // uint32 originChainId [002 .. 006)\n // uint32 destChainId [006 .. 010)\n // address originSender [010 .. 030)\n // address destRecipient [030 .. 050)\n // address originToken [050 .. 070)\n // address destToken [070 .. 090)\n // uint256 originAmount [090 .. 122)\n // uint256 destAmount [122 .. 154)\n // uint256 originFeeAmount [154 .. 186)\n // uint256 deadline [186 .. 218)\n // uint256 nonce [218 .. 250)\n // address exclusivityRelayer [250 .. 270)\n // uint256 exclusivityEndTime [270 .. 302)\n // uint256 zapNative [302 .. 334)\n // bytes zapData [334 .. ***)\n\n // forgefmt: disable-start\n uint256 private constant OFFSET_ORIGIN_CHAIN_ID = 2;\n uint256 private constant OFFSET_DEST_CHAIN_ID = 6;\n uint256 private constant OFFSET_ORIGIN_SENDER = 10;\n uint256 private constant OFFSET_DEST_RECIPIENT = 30;\n uint256 private constant OFFSET_ORIGIN_TOKEN = 50;\n uint256 private constant OFFSET_DEST_TOKEN = 70;\n uint256 private constant OFFSET_ORIGIN_AMOUNT = 90;\n uint256 private constant OFFSET_DEST_AMOUNT = 122;\n uint256 private constant OFFSET_ORIGIN_FEE_AMOUNT = 154;\n uint256 private constant OFFSET_DEADLINE = 186;\n uint256 private constant OFFSET_NONCE = 218;\n uint256 private constant OFFSET_EXCLUSIVITY_RELAYER = 250;\n uint256 private constant OFFSET_EXCLUSIVITY_END_TIME = 270;\n uint256 private constant OFFSET_ZAP_NATIVE = 302;\n uint256 private constant OFFSET_ZAP_DATA = 334;\n // forgefmt: disable-end\n\n error BridgeTransactionV2__InvalidEncodedTx();\n error BridgeTransactionV2__UnsupportedVersion(uint16 version);\n\n /// @notice Validates the encoded transaction to be a tightly packed encoded payload for BridgeTransactionV2.\n /// @dev Checks the minimum length and the version, use this function before decoding any of the fields.\n function validateV2(bytes calldata encodedTx) internal pure {\n // Check the minimum length: must at least include all static fields.\n if (encodedTx.length \u003c OFFSET_ZAP_DATA) revert BridgeTransactionV2__InvalidEncodedTx();\n // Once we validated the length, we can be sure that the version field is present.\n uint16 version_ = version(encodedTx);\n if (version_ != VERSION) revert BridgeTransactionV2__UnsupportedVersion(version_);\n }\n\n /// @notice Encodes the BridgeTransactionV2 struct by tightly packing the fields.\n /// @dev `abi.decode` will not work as a result of the tightly packed fields. Use `decodeV2` to decode instead.\n function encodeV2(IFastBridgeV2.BridgeTransactionV2 memory bridgeTx) internal pure returns (bytes memory) {\n // We split the encoding into two parts to avoid stack-too-deep error\n bytes memory firstPart = abi.encodePacked(\n VERSION,\n bridgeTx.originChainId,\n bridgeTx.destChainId,\n bridgeTx.originSender,\n bridgeTx.destRecipient,\n bridgeTx.originToken,\n bridgeTx.destToken,\n bridgeTx.originAmount\n );\n return abi.encodePacked(\n firstPart,\n bridgeTx.destAmount,\n bridgeTx.originFeeAmount,\n // Note: we skip the deprecated `sendChainGas` flag, which was present in BridgeTransaction V1\n bridgeTx.deadline,\n bridgeTx.nonce,\n // New V2 fields: exclusivity\n bridgeTx.exclusivityRelayer,\n bridgeTx.exclusivityEndTime,\n // New V2 fields: Zap\n bridgeTx.zapNative,\n bridgeTx.zapData\n );\n }\n\n /// @notice Decodes the BridgeTransactionV2 struct from the encoded transaction.\n /// @dev Encoded BridgeTransactionV2 struct must be tightly packed.\n /// Use `validateV2` before decoding to ensure the encoded transaction is valid.\n function decodeV2(bytes calldata encodedTx)\n internal\n pure\n returns (IFastBridgeV2.BridgeTransactionV2 memory bridgeTx)\n {\n bridgeTx.originChainId = originChainId(encodedTx);\n bridgeTx.destChainId = destChainId(encodedTx);\n bridgeTx.originSender = originSender(encodedTx);\n bridgeTx.destRecipient = destRecipient(encodedTx);\n bridgeTx.originToken = originToken(encodedTx);\n bridgeTx.destToken = destToken(encodedTx);\n bridgeTx.originAmount = originAmount(encodedTx);\n bridgeTx.destAmount = destAmount(encodedTx);\n bridgeTx.originFeeAmount = originFeeAmount(encodedTx);\n bridgeTx.deadline = deadline(encodedTx);\n bridgeTx.nonce = nonce(encodedTx);\n bridgeTx.exclusivityRelayer = exclusivityRelayer(encodedTx);\n bridgeTx.exclusivityEndTime = exclusivityEndTime(encodedTx);\n bridgeTx.zapNative = zapNative(encodedTx);\n bridgeTx.zapData = zapData(encodedTx);\n }\n\n /// @notice Extracts the version from the encoded transaction.\n function version(bytes calldata encodedTx) internal pure returns (uint16 version_) {\n // Load 32 bytes from the start and shift it 240 bits to the right to get the highest 16 bits.\n assembly {\n version_ := shr(240, calldataload(encodedTx.offset))\n }\n }\n\n /// @notice Extracts the origin chain ID from the encoded transaction.\n function originChainId(bytes calldata encodedTx) internal pure returns (uint32 originChainId_) {\n // Load 32 bytes from the offset and shift it 224 bits to the right to get the highest 32 bits.\n assembly {\n originChainId_ := shr(224, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_CHAIN_ID)))\n }\n }\n\n /// @notice Extracts the destination chain ID from the encoded transaction.\n function destChainId(bytes calldata encodedTx) internal pure returns (uint32 destChainId_) {\n // Load 32 bytes from the offset and shift it 224 bits to the right to get the highest 32 bits.\n assembly {\n destChainId_ := shr(224, calldataload(add(encodedTx.offset, OFFSET_DEST_CHAIN_ID)))\n }\n }\n\n /// @notice Extracts the origin sender from the encoded transaction.\n function originSender(bytes calldata encodedTx) internal pure returns (address originSender_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n originSender_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_SENDER)))\n }\n }\n\n /// @notice Extracts the destination recipient from the encoded transaction.\n function destRecipient(bytes calldata encodedTx) internal pure returns (address destRecipient_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n destRecipient_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_DEST_RECIPIENT)))\n }\n }\n\n /// @notice Extracts the origin token from the encoded transaction.\n function originToken(bytes calldata encodedTx) internal pure returns (address originToken_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n originToken_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_TOKEN)))\n }\n }\n\n /// @notice Extracts the destination token from the encoded transaction.\n function destToken(bytes calldata encodedTx) internal pure returns (address destToken_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n destToken_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_DEST_TOKEN)))\n }\n }\n\n /// @notice Extracts the origin amount from the encoded transaction.\n function originAmount(bytes calldata encodedTx) internal pure returns (uint256 originAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n originAmount_ := calldataload(add(encodedTx.offset, OFFSET_ORIGIN_AMOUNT))\n }\n }\n\n /// @notice Extracts the destination amount from the encoded transaction.\n function destAmount(bytes calldata encodedTx) internal pure returns (uint256 destAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n destAmount_ := calldataload(add(encodedTx.offset, OFFSET_DEST_AMOUNT))\n }\n }\n\n /// @notice Extracts the origin fee amount from the encoded transaction.\n function originFeeAmount(bytes calldata encodedTx) internal pure returns (uint256 originFeeAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n originFeeAmount_ := calldataload(add(encodedTx.offset, OFFSET_ORIGIN_FEE_AMOUNT))\n }\n }\n\n /// @notice Extracts the deadline from the encoded transaction.\n function deadline(bytes calldata encodedTx) internal pure returns (uint256 deadline_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n deadline_ := calldataload(add(encodedTx.offset, OFFSET_DEADLINE))\n }\n }\n\n /// @notice Extracts the nonce from the encoded transaction.\n function nonce(bytes calldata encodedTx) internal pure returns (uint256 nonce_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n nonce_ := calldataload(add(encodedTx.offset, OFFSET_NONCE))\n }\n }\n\n /// @notice Extracts the exclusivity relayer from the encoded transaction.\n function exclusivityRelayer(bytes calldata encodedTx) internal pure returns (address exclusivityRelayer_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n exclusivityRelayer_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_EXCLUSIVITY_RELAYER)))\n }\n }\n\n /// @notice Extracts the exclusivity end time from the encoded transaction.\n function exclusivityEndTime(bytes calldata encodedTx) internal pure returns (uint256 exclusivityEndTime_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n exclusivityEndTime_ := calldataload(add(encodedTx.offset, OFFSET_EXCLUSIVITY_END_TIME))\n }\n }\n\n /// @notice Extracts the Zap's native value from the encoded transaction.\n function zapNative(bytes calldata encodedTx) internal pure returns (uint256 zapNative_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n zapNative_ := calldataload(add(encodedTx.offset, OFFSET_ZAP_NATIVE))\n }\n }\n\n /// @notice Extracts the Zap's data from the encoded transaction.\n function zapData(bytes calldata encodedTx) internal pure returns (bytes calldata zapData_) {\n zapData_ = encodedTx[OFFSET_ZAP_DATA:];\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// contracts/libs/UniversalToken.sol\n\nlibrary UniversalTokenLib {\n using SafeERC20 for IERC20;\n\n address internal constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Transfers tokens to the given account. Reverts if transfer is not successful.\n /// @dev This might trigger fallback, if ETH is transferred to the contract.\n /// Make sure this can not lead to reentrancy attacks.\n function universalTransfer(address token, address to, uint256 value) internal {\n // Don't do anything, if need to send tokens to this address\n if (to == address(this)) return;\n // Don't do anything, if trying to send zero value\n if (value == 0) return;\n if (token == ETH_ADDRESS) {\n /// @dev Note: this can potentially lead to executing code in `to`.\n // solhint-disable-next-line avoid-low-level-calls\n (bool success,) = to.call{value: value}(\"\");\n require(success, \"ETH transfer failed\");\n } else {\n IERC20(token).safeTransfer(to, value);\n }\n }\n\n /// @notice Issues an infinite allowance to the spender, if the current allowance is insufficient\n /// to spend the given amount.\n function universalApproveInfinity(address token, address spender, uint256 amountToSpend) internal {\n // ETH Chad doesn't require your approval\n if (token == ETH_ADDRESS) return;\n // No-op if allowance is already sufficient\n uint256 allowance = IERC20(token).allowance(address(this), spender);\n if (allowance \u003e= amountToSpend) return;\n // Otherwise, reset approval to 0 and set to max allowance\n if (allowance \u003e 0) IERC20(token).safeDecreaseAllowance(spender, allowance);\n IERC20(token).safeIncreaseAllowance(spender, type(uint256).max);\n }\n\n /// @notice Returns the balance of the given token (or native ETH) for the given account.\n function universalBalanceOf(address token, address account) internal view returns (uint256) {\n if (token == ETH_ADDRESS) {\n return account.balance;\n } else {\n return IERC20(token).balanceOf(account);\n }\n }\n\n /// @dev Checks that token is a contract and not ETH_ADDRESS.\n function assertIsContract(address token) internal view {\n // Check that ETH_ADDRESS was not used (in case this is a predeploy on any of the chains)\n if (token == UniversalTokenLib.ETH_ADDRESS) revert TokenNotContract();\n // Check that token is not an EOA\n if (token.code.length == 0) revert TokenNotContract();\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/Admin.sol\n\ncontract Admin is IAdmin, AccessControlEnumerable {\n using UniversalTokenLib for address;\n\n bytes32 public constant RELAYER_ROLE = keccak256(\"RELAYER_ROLE\");\n bytes32 public constant REFUNDER_ROLE = keccak256(\"REFUNDER_ROLE\");\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n uint256 public constant FEE_BPS = 1e6;\n uint256 public constant FEE_RATE_MAX = 0.01e6; // max 1% on origin amount\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Chain gas amount to forward as rebate if requested\n uint256 public chainGasAmount;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n }\n\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n require(newFeeRate \u003c= FEE_RATE_MAX, \"newFeeRate \u003e max\");\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n token.universalTransfer(recipient, feeAmount);\n emit FeesSwept(token, recipient, feeAmount);\n }\n\n function setChainGasAmount(uint256 newChainGasAmount) external onlyRole(GOVERNOR_ROLE) {\n uint256 oldChainGasAmount = chainGasAmount;\n chainGasAmount = newChainGasAmount;\n emit ChainGasAmountUpdated(oldChainGasAmount, newChainGasAmount);\n }\n}\n\n// contracts/FastBridgeV2.sol\n\n/// @notice FastBridgeV2 is a contract for bridging tokens across chains.\ncontract FastBridgeV2 is Admin, MulticallTarget, IFastBridgeV2, IFastBridgeV2Errors {\n using BridgeTransactionV2Lib for bytes;\n using SafeERC20 for IERC20;\n\n /// @notice Address reserved for native gas token (ETH on Ethereum and most L2s, AVAX on Avalanche, etc)\n address public constant NATIVE_GAS_TOKEN = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Delay for a transaction after which it could be permisionlessly refunded\n uint256 public constant REFUND_DELAY = 7 days;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n /// @notice Maximum length of accepted zapData\n uint256 public constant MAX_ZAP_DATA_LENGTH = 2 ** 16 - 1;\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeTxDetails) public bridgeTxDetails;\n /// @notice Relay details on destination chain\n mapping(bytes32 =\u003e BridgeRelay) public bridgeRelayDetails;\n /// @notice Unique bridge nonces tracked per originSender\n mapping(address =\u003e uint256) public senderNonces;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Replaced by senderNonces\n uint256 public immutable nonce = 0;\n /// @notice the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n bridge({\n params: params,\n paramsV2: BridgeParamsV2({\n quoteRelayer: address(0),\n quoteExclusivitySeconds: 0,\n quoteId: bytes(\"\"),\n zapNative: 0,\n zapData: bytes(\"\")\n })\n });\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes calldata request) external payable {\n // relay override will validate the request\n relay({request: request, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes calldata request, bytes32 destTxHash) external {\n request.validateV2();\n prove({transactionId: keccak256(request), destTxHash: destTxHash, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridgeV2\n function claim(bytes calldata request) external {\n // claim override will validate the request\n claim({request: request, to: address(0)});\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Aggregate the read operations from the same storage slot\n address disputedRelayer = $.proofRelayer;\n BridgeStatus status = $.status;\n uint56 proofBlockTimestamp = $.proofBlockTimestamp;\n // Can only dispute a RELAYER_PROVED transaction within the dispute period\n if (status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(proofBlockTimestamp) \u003e DISPUTE_PERIOD) {\n revert DisputePeriodPassed();\n }\n // Update status to REQUESTED and delete the disputed proof details\n // Note: these are storage writes\n $.status = BridgeStatus.REQUESTED;\n $.proofRelayer = address(0);\n $.proofBlockTimestamp = 0;\n\n emit BridgeProofDisputed(transactionId, disputedRelayer);\n }\n\n /// @inheritdoc IFastBridge\n function refund(bytes calldata request) external {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Can only refund a REQUESTED transaction after its deadline expires\n if ($.status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n uint256 deadline = request.deadline();\n // Permissionless refund is only allowed after REFUND_DELAY on top of the deadline\n if (!hasRole(REFUNDER_ROLE, msg.sender)) deadline += REFUND_DELAY;\n if (block.timestamp \u003c= deadline) revert DeadlineNotExceeded();\n // Update status to REFUNDED and return the full amount (collateral + protocol fees) to the original sender.\n // The protocol fees are only updated when the transaction is claimed, so we don't need to update them here.\n // Note: this is a storage write\n $.status = BridgeStatus.REFUNDED;\n\n address to = request.originSender();\n address token = request.originToken();\n uint256 amount = request.originAmount() + request.originFeeAmount();\n // Emit the event before any external calls\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n // Complete the user refund as the last transaction action\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(to), amount);\n } else {\n IERC20(token).safeTransfer(to, amount);\n }\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // The correct relayer can only claim a RELAYER_PROVED transaction after the dispute period\n if ($.status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if ($.proofRelayer != relayer) revert SenderIncorrect();\n return _timeSince($.proofBlockTimestamp) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n /// @dev This method is added to achieve backwards compatibility with decoding requests into V1 structs:\n /// - `zapNative` is partially reported as a zero/non-zero flag\n /// - `zapData` is ignored\n /// In order to process all kinds of requests use getBridgeTransactionV2 instead.\n function getBridgeTransaction(bytes calldata request) external view returns (BridgeTransaction memory) {\n // Try decoding into V2 struct first. This will revert if V1 struct is passed\n try this.getBridgeTransactionV2(request) returns (BridgeTransactionV2 memory txV2) {\n // Note: we entirely ignore the zapData field, as it was not present in V1\n return BridgeTransaction({\n originChainId: txV2.originChainId,\n destChainId: txV2.destChainId,\n originSender: txV2.originSender,\n destRecipient: txV2.destRecipient,\n originToken: txV2.originToken,\n destToken: txV2.destToken,\n originAmount: txV2.originAmount,\n destAmount: txV2.destAmount,\n originFeeAmount: txV2.originFeeAmount,\n sendChainGas: txV2.zapNative != 0,\n deadline: txV2.deadline,\n nonce: txV2.nonce\n });\n } catch {\n // Fallback to V1 struct\n return abi.decode(request, (BridgeTransaction));\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function getBridgeTransactionV2(bytes calldata request) external pure returns (BridgeTransactionV2 memory) {\n request.validateV2();\n return BridgeTransactionV2Lib.decodeV2(request);\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) public payable {\n int256 exclusivityEndTime = 0;\n // if relayer exclusivity is not intended for this bridge, set exclusivityEndTime to static zero\n // otherwise, set exclusivity to expire at the current block ts offset by quoteExclusivitySeconds\n if (paramsV2.quoteRelayer != address(0)) {\n exclusivityEndTime = int256(block.timestamp) + paramsV2.quoteExclusivitySeconds;\n }\n _validateBridgeParams(params, paramsV2, exclusivityEndTime);\n\n // transfer tokens to bridge contract\n /// @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _takeBridgedUserAsset(params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) {\n originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n }\n\n // set status to requested\n bytes memory request = BridgeTransactionV2Lib.encodeV2(\n BridgeTransactionV2({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n deadline: params.deadline,\n nonce: senderNonces[params.sender]++, // increment nonce on every bridge\n exclusivityRelayer: paramsV2.quoteRelayer,\n // We checked exclusivityEndTime to be in range [0 .. params.deadline] above, so can safely cast\n exclusivityEndTime: uint256(exclusivityEndTime),\n zapNative: paramsV2.zapNative,\n zapData: paramsV2.zapData\n })\n );\n bytes32 transactionId = keccak256(request);\n // Note: the tx status will be updated throughout the tx lifecycle, while destChainId is set once here\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n bridgeTxDetails[transactionId].destChainId = params.dstChainId;\n\n emit BridgeRequested({\n transactionId: transactionId,\n sender: params.sender,\n request: request,\n destChainId: params.dstChainId,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n sendChainGas: paramsV2.zapNative != 0\n });\n emit BridgeQuoteDetails(transactionId, paramsV2.quoteId);\n }\n\n /// @inheritdoc IFastBridgeV2\n function relay(bytes calldata request, address relayer) public payable {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n _validateRelayParams(request, transactionId, relayer);\n // mark bridge transaction as relayed\n bridgeRelayDetails[transactionId] =\n BridgeRelay({blockNumber: uint48(block.number), blockTimestamp: uint48(block.timestamp), relayer: relayer});\n\n // transfer tokens to recipient on destination chain and trigger Zap if requested\n address to = request.destRecipient();\n address token = request.destToken();\n uint256 amount = request.destAmount();\n uint256 zapNative = request.zapNative();\n\n // Emit the event before any external calls\n emit BridgeRelayed({\n transactionId: transactionId,\n relayer: relayer,\n to: to,\n originChainId: request.originChainId(),\n originToken: request.originToken(),\n destToken: token,\n originAmount: request.originAmount(),\n destAmount: amount,\n chainGasAmount: zapNative\n });\n\n // All state changes have been done at this point, can proceed to the external calls.\n // This follows the checks-effects-interactions pattern to mitigate potential reentrancy attacks.\n if (token == NATIVE_GAS_TOKEN) {\n // For the native gas token, additional zapNative is not allowed\n if (zapNative != 0) revert ZapNativeNotSupported();\n // Check that the correct msg.value was sent\n if (msg.value != amount) revert MsgValueIncorrect();\n // Don't do a native transfer yet: we will handle it alongside the Zap below\n } else {\n // For ERC20s, we check that the correct msg.value was sent\n if (msg.value != zapNative) revert MsgValueIncorrect();\n // We need to transfer the tokens from the Relayer to the recipient first before performing an\n // optional post-transfer Zap.\n IERC20(token).safeTransferFrom(msg.sender, to, amount);\n }\n // At this point we have done:\n // - Transferred the requested amount of ERC20 tokens to the recipient.\n // At this point we have confirmed:\n // - For ERC20s: msg.value matches the requested zapNative amount.\n // - For the native gas token: msg.value matches the requested destAmount.\n // Remaining optional things to do:\n // - Forward the full msg.value to the recipient (if non-zero).\n // - Trigger a Zap (if zapData is present).\n bytes calldata zapData = request.zapData();\n if (zapData.length != 0) {\n // Zap Data is present: Zap has been requested by the recipient. Trigger it forwarding the full msg.value.\n\n // Note: if token has a fee on transfers, the recipient will have received less than `amount`.\n // This is a very niche edge case and should be handled by the recipient contract.\n _triggerZapWithChecks({recipient: to, token: token, amount: amount, zapData: zapData});\n } else if (msg.value != 0) {\n // Zap Data is missing, but msg.value was sent. This could happen in two different cases:\n // - Relay with the native gas token is happening.\n // - Relay with ERC20 is happening, with a `zapNative \u003e 0` request.\n // In both cases, we need to transfer the full msg.value to the recipient.\n Address.sendValue(payable(to), msg.value);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) public onlyRole(RELAYER_ROLE) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n\n // Can only prove a REQUESTED transaction\n if ($.status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n // Update status to RELAYER_PROVED and store the proof details\n // Note: these are storage writes\n $.status = BridgeStatus.RELAYER_PROVED;\n $.proofBlockTimestamp = uint56(block.timestamp);\n $.proofRelayer = relayer;\n\n emit BridgeProofProvided(transactionId, relayer, destTxHash);\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes calldata request, address to) public {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Aggregate the read operations from the same storage slot\n address proofRelayer = $.proofRelayer;\n BridgeStatus status = $.status;\n uint56 proofBlockTimestamp = $.proofBlockTimestamp;\n\n // Can only claim a RELAYER_PROVED transaction after the dispute period\n if (status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(proofBlockTimestamp) \u003c= DISPUTE_PERIOD) {\n revert DisputePeriodNotPassed();\n }\n\n if (to == address(0)) {\n // Anyone could claim the funds to the proven relayer on their behalf\n to = proofRelayer;\n } else if (proofRelayer != msg.sender) {\n // Only the proven relayer could specify an address to claim the funds to\n revert SenderIncorrect();\n }\n\n // Update status to RELAYER_CLAIMED and transfer the origin collateral to the specified claim address\n // Note: this is a storage write\n $.status = BridgeStatus.RELAYER_CLAIMED;\n\n address token = request.originToken();\n uint256 amount = request.originAmount();\n // Update protocol fees if origin fee amount exists\n uint256 originFeeAmount = request.originFeeAmount();\n if (originFeeAmount \u003e 0) protocolFees[token] += originFeeAmount;\n // Emit the event before any external calls\n emit BridgeDepositClaimed(transactionId, proofRelayer, to, token, amount);\n // Complete the relayer claim as the last transaction action\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(to), amount);\n } else {\n IERC20(token).safeTransfer(to, amount);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeStatuses(bytes32 transactionId) public view returns (BridgeStatus status) {\n return bridgeTxDetails[transactionId].status;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeProofs(bytes32 transactionId) public view returns (uint96 timestamp, address relayer) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n\n timestamp = $.proofBlockTimestamp;\n relayer = $.proofRelayer;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeRelays(bytes32 transactionId) public view returns (bool) {\n // has this transactionId been relayed?\n return bridgeRelayDetails[transactionId].relayer != address(0);\n }\n\n /// @notice Takes the bridged asset from the user into FastBridgeV2 custody. It will be later\n /// claimed by the relayer who completed the relay on destination chain, or refunded back to the user,\n /// should no one complete the relay.\n function _takeBridgedUserAsset(address token, uint256 amount) internal returns (uint256 amountTaken) {\n if (token == NATIVE_GAS_TOKEN) {\n // For the native gas token, we just need to check that the supplied msg.value is correct.\n // Supplied `msg.value` is already in FastBridgeV2 custody.\n if (amount != msg.value) revert MsgValueIncorrect();\n amountTaken = msg.value;\n } else {\n // For ERC20s, token is explicitly transferred from the user to FastBridgeV2.\n // We don't allow non-zero `msg.value` to avoid extra funds from being stuck in FastBridgeV2.\n if (msg.value != 0) revert MsgValueIncorrect();\n // Throw an explicit error if the provided token address is not a contract\n if (token.code.length == 0) revert TokenNotContract();\n amountTaken = IERC20(token).balanceOf(address(this));\n IERC20(token).safeTransferFrom(msg.sender, address(this), amount);\n // Use the balance difference as the amount taken in case of fee on transfer tokens.\n amountTaken = IERC20(token).balanceOf(address(this)) - amountTaken;\n }\n }\n\n /// @notice Calls the Recipient's hook function with the specified zapData and performs\n /// all the necessary checks for the returned value.\n function _triggerZapWithChecks(address recipient, address token, uint256 amount, bytes calldata zapData) internal {\n // This will bubble any revert messages from the hook function\n bytes memory returnData = Address.functionCallWithValue({\n target: recipient,\n data: abi.encodeCall(IZapRecipient.zap, (token, amount, zapData)),\n // Note: see `relay()` for reasoning behind passing msg.value\n value: msg.value\n });\n // Explicit revert if no return data at all\n if (returnData.length == 0) revert RecipientNoReturnValue();\n // Check that exactly a single return value was returned\n if (returnData.length != 32) revert RecipientIncorrectReturnValue();\n // Return value should be abi-encoded hook function selector\n if (bytes32(returnData) != bytes32(IZapRecipient.zap.selector)) {\n revert RecipientIncorrectReturnValue();\n }\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint56(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint56).max but\n /// proof.timestamp \u003c type(uint56).max via unchecked statement\n /// @param proofBlockTimestamp The bridge proof block timestamp\n /// @return delta Time delta since proof submitted\n function _timeSince(uint56 proofBlockTimestamp) internal view returns (uint256 delta) {\n unchecked {\n delta = uint56(block.timestamp) - proofBlockTimestamp;\n }\n }\n\n /// @notice Performs all the necessary checks for a bridge to happen.\n /// @dev There's no good way to refactor this function to reduce cyclomatic complexity due to\n /// the number of checks that need to be performed, so we skip the code-complexity rule here.\n // solhint-disable-next-line code-complexity\n function _validateBridgeParams(\n BridgeParams memory params,\n BridgeParamsV2 memory paramsV2,\n int256 exclusivityEndTime\n )\n internal\n view\n {\n // Check V1 (legacy) params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.sender == address(0) || params.to == address(0)) revert ZeroAddress();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n // Check V2 params\n if (paramsV2.zapData.length \u003e MAX_ZAP_DATA_LENGTH) revert ZapDataLengthAboveMax();\n if (paramsV2.zapNative != 0 \u0026\u0026 params.destToken == NATIVE_GAS_TOKEN) {\n revert ZapNativeNotSupported();\n }\n // exclusivityEndTime must be in range [0 .. params.deadline]\n if (exclusivityEndTime \u003c 0 || exclusivityEndTime \u003e int256(params.deadline)) {\n revert ExclusivityParamsIncorrect();\n }\n }\n\n /// @notice Performs all the necessary checks for a relay to happen.\n function _validateRelayParams(bytes calldata request, bytes32 transactionId, address relayer) internal view {\n if (relayer == address(0)) revert ZeroAddress();\n // Check if the transaction has already been relayed\n if (bridgeRelays(transactionId)) revert TransactionRelayed();\n if (request.destChainId() != block.chainid) revert ChainIncorrect();\n // Check the deadline for relay to happen\n if (block.timestamp \u003e request.deadline()) revert DeadlineExceeded();\n // Check the exclusivity period, if it is still ongoing\n address exclRelayer = request.exclusivityRelayer();\n if (exclRelayer != address(0) \u0026\u0026 exclRelayer != relayer \u0026\u0026 block.timestamp \u003c= request.exclusivityEndTime()) {\n revert ExclusivityPeriodNotPassed();\n }\n }\n}\n","language":"Solidity","languageVersion":"0.8.24","compilerVersion":"0.8.24","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"","srcMapRuntime":"","abiDefinition":[{"inputs":[],"name":"AccessControlBadConfirmation","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"bytes32","name":"neededRole","type":"bytes32"}],"name":"AccessControlUnauthorizedAccount","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"previousAdminRole","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"newAdminRole","type":"bytes32"}],"name":"RoleAdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleRevoked","type":"event"},{"inputs":[],"name":"DEFAULT_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleAdmin","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"uint256","name":"index","type":"uint256"}],"name":"getRoleMember","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleMemberCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"grantRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"hasRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"callerConfirmation","type":"address"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"revokeRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"}],"userDoc":{"kind":"user","methods":{},"version":1},"developerDoc":{"details":"Extension of {AccessControl} that allows enumerating the members of each role.","errors":{"AccessControlBadConfirmation()":[{"details":"The caller of a function is not the expected one. NOTE: Don't confuse with {AccessControlUnauthorizedAccount}."}],"AccessControlUnauthorizedAccount(address,bytes32)":[{"details":"The `account` is missing a role."}]},"events":{"RoleAdminChanged(bytes32,bytes32,bytes32)":{"details":"Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole` `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite {RoleAdminChanged} not being emitted signaling this."},"RoleGranted(bytes32,address,address)":{"details":"Emitted when `account` is granted `role`. `sender` is the account that originated the contract call, an admin role bearer except when using {AccessControl-_setupRole}."},"RoleRevoked(bytes32,address,address)":{"details":"Emitted when `account` is revoked `role`. `sender` is the account that originated the contract call: - if using `revokeRole`, it is the admin role bearer - if using `renounceRole`, it is the role bearer (i.e. `account`)"}},"kind":"dev","methods":{"getRoleAdmin(bytes32)":{"details":"Returns the admin role that controls `role`. See {grantRole} and {revokeRole}. To change a role's admin, use {_setRoleAdmin}."},"getRoleMember(bytes32,uint256)":{"details":"Returns one of the accounts that have `role`. `index` must be a value between 0 and {getRoleMemberCount}, non-inclusive. Role bearers are not sorted in any particular way, and their ordering may change at any point. WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure you perform all queries on the same block. See the following https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post] for more information."},"getRoleMemberCount(bytes32)":{"details":"Returns the number of accounts that have `role`. Can be used together with {getRoleMember} to enumerate all bearers of a role."},"grantRole(bytes32,address)":{"details":"Grants `role` to `account`. If `account` had not been already granted `role`, emits a {RoleGranted} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleGranted} event."},"hasRole(bytes32,address)":{"details":"Returns `true` if `account` has been granted `role`."},"renounceRole(bytes32,address)":{"details":"Revokes `role` from the calling account. Roles are often managed via {grantRole} and {revokeRole}: this function's purpose is to provide a mechanism for accounts to lose their privileges if they are compromised (such as when a trusted device is misplaced). If the calling account had been revoked `role`, emits a {RoleRevoked} event. Requirements: - the caller must be `callerConfirmation`. May emit a {RoleRevoked} event."},"revokeRole(bytes32,address)":{"details":"Revokes `role` from `account`. If `account` had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleRevoked} event."},"supportsInterface(bytes4)":{"details":"See {IERC165-supportsInterface}."}},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[],\"name\":\"AccessControlBadConfirmation\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"neededRole\",\"type\":\"bytes32\"}],\"name\":\"AccessControlUnauthorizedAccount\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"previousAdminRole\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"newAdminRole\",\"type\":\"bytes32\"}],\"name\":\"RoleAdminChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleGranted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleRevoked\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"DEFAULT_ADMIN_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"}],\"name\":\"getRoleAdmin\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"index\",\"type\":\"uint256\"}],\"name\":\"getRoleMember\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"}],\"name\":\"getRoleMemberCount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"grantRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"hasRole\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"callerConfirmation\",\"type\":\"address\"}],\"name\":\"renounceRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"revokeRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes4\",\"name\":\"interfaceId\",\"type\":\"bytes4\"}],\"name\":\"supportsInterface\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"}],\"devdoc\":{\"details\":\"Extension of {AccessControl} that allows enumerating the members of each role.\",\"errors\":{\"AccessControlBadConfirmation()\":[{\"details\":\"The caller of a function is not the expected one. NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\"}],\"AccessControlUnauthorizedAccount(address,bytes32)\":[{\"details\":\"The `account` is missing a role.\"}]},\"events\":{\"RoleAdminChanged(bytes32,bytes32,bytes32)\":{\"details\":\"Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole` `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite {RoleAdminChanged} not being emitted signaling this.\"},\"RoleGranted(bytes32,address,address)\":{\"details\":\"Emitted when `account` is granted `role`. `sender` is the account that originated the contract call, an admin role bearer except when using {AccessControl-_setupRole}.\"},\"RoleRevoked(bytes32,address,address)\":{\"details\":\"Emitted when `account` is revoked `role`. `sender` is the account that originated the contract call: - if using `revokeRole`, it is the admin role bearer - if using `renounceRole`, it is the role bearer (i.e. `account`)\"}},\"kind\":\"dev\",\"methods\":{\"getRoleAdmin(bytes32)\":{\"details\":\"Returns the admin role that controls `role`. See {grantRole} and {revokeRole}. To change a role's admin, use {_setRoleAdmin}.\"},\"getRoleMember(bytes32,uint256)\":{\"details\":\"Returns one of the accounts that have `role`. `index` must be a value between 0 and {getRoleMemberCount}, non-inclusive. Role bearers are not sorted in any particular way, and their ordering may change at any point. WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure you perform all queries on the same block. See the following https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post] for more information.\"},\"getRoleMemberCount(bytes32)\":{\"details\":\"Returns the number of accounts that have `role`. Can be used together with {getRoleMember} to enumerate all bearers of a role.\"},\"grantRole(bytes32,address)\":{\"details\":\"Grants `role` to `account`. If `account` had not been already granted `role`, emits a {RoleGranted} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleGranted} event.\"},\"hasRole(bytes32,address)\":{\"details\":\"Returns `true` if `account` has been granted `role`.\"},\"renounceRole(bytes32,address)\":{\"details\":\"Revokes `role` from the calling account. Roles are often managed via {grantRole} and {revokeRole}: this function's purpose is to provide a mechanism for accounts to lose their privileges if they are compromised (such as when a trusted device is misplaced). If the calling account had been revoked `role`, emits a {RoleRevoked} event. Requirements: - the caller must be `callerConfirmation`. May emit a {RoleRevoked} event.\"},\"revokeRole(bytes32,address)\":{\"details\":\"Revokes `role` from `account`. If `account` had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleRevoked} event.\"},\"supportsInterface(bytes4)\":{\"details\":\"See {IERC165-supportsInterface}.\"}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeV2.sol\":\"AccessControlEnumerable\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeV2.sol\":{\"keccak256\":\"0x5069b55ca07f21bfe30b2a43c18a18318c8af9c181b2dcb07c290825efd70f34\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://273dc020a49d08e50126bbea0d7f783f79d08c702f2fdbc560618d24af308acc\",\"dweb:/ipfs/QmXJ2UVzFc8EPB74RT4CXQPC4xw66jt4T13poyfyd3UERh\"]}},\"version\":1}"},"hashes":{"DEFAULT_ADMIN_ROLE()":"a217fddf","getRoleAdmin(bytes32)":"248a9ca3","getRoleMember(bytes32,uint256)":"9010d07c","getRoleMemberCount(bytes32)":"ca15c873","grantRole(bytes32,address)":"2f2ff15d","hasRole(bytes32,address)":"91d14854","renounceRole(bytes32,address)":"36568abe","revokeRole(bytes32,address)":"d547741f","supportsInterface(bytes4)":"01ffc9a7"}},"solidity/FastBridgeV2.sol:Address":{"code":"0x60566037600b82828239805160001a607314602a57634e487b7160e01b600052600060045260246000fd5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600080fdfea2646970667358221220bf1b9d7d74d58f093eea1b088fdbcad7f67374661fae1ab5815d7a31130f2fb864736f6c63430008180033","runtime-code":"0x73000000000000000000000000000000000000000030146080604052600080fdfea2646970667358221220bf1b9d7d74d58f093eea1b088fdbcad7f67374661fae1ab5815d7a31130f2fb864736f6c63430008180033","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.24 ^0.8.20 ^0.8.4;\n\n// contracts/interfaces/IAdmin.sol\n\ninterface IAdmin {\n // ============ Events ============\n\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n event ChainGasAmountUpdated(uint256 oldChainGasAmount, uint256 newChainGasAmount);\n\n // ============ Methods ============\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n\n function setChainGasAmount(uint256 newChainGasAmount) external;\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IFastBridgeV2Errors.sol\n\ninterface IFastBridgeV2Errors {\n error AmountIncorrect();\n error ChainIncorrect();\n error ExclusivityParamsIncorrect();\n error MsgValueIncorrect();\n error SenderIncorrect();\n error StatusIncorrect();\n error TokenNotContract();\n error ZapDataLengthAboveMax();\n error ZapNativeNotSupported();\n error ZeroAddress();\n\n error RecipientIncorrectReturnValue();\n error RecipientNoReturnValue();\n\n error DeadlineExceeded();\n error DeadlineNotExceeded();\n error DeadlineTooShort();\n error DisputePeriodNotPassed();\n error DisputePeriodPassed();\n error ExclusivityPeriodNotPassed();\n\n error TransactionRelayed();\n}\n\n// contracts/interfaces/IMulticallTarget.sol\n\n/// @notice Interface for a contract that can be called multiple times by the same caller. Inspired by MulticallV3:\n/// https://github.com/mds1/multicall/blob/master/src/Multicall3.sol\ninterface IMulticallTarget {\n struct Result {\n bool success;\n bytes returnData;\n }\n\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external;\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results);\n}\n\n// contracts/interfaces/IZapRecipient.sol\n\ninterface IZapRecipient {\n function zap(address token, uint256 amount, bytes memory zapData) external payable returns (bytes4);\n}\n\n// contracts/libs/Errors.sol\n\nerror DeadlineExceeded();\nerror DeadlineNotExceeded();\nerror DeadlineTooShort();\nerror InsufficientOutputAmount();\n\nerror MsgValueIncorrect();\nerror PoolNotFound();\nerror TokenAddressMismatch();\nerror TokenNotContract();\nerror TokenNotETH();\nerror TokensIdentical();\n\nerror ChainIncorrect();\nerror AmountIncorrect();\nerror ZeroAddress();\n\nerror DisputePeriodNotPassed();\nerror DisputePeriodPassed();\nerror SenderIncorrect();\nerror StatusIncorrect();\nerror TransactionIdIncorrect();\nerror TransactionRelayed();\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// contracts/interfaces/IFastBridgeV2.sol\n\ninterface IFastBridgeV2 is IFastBridge {\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n struct BridgeTxDetails {\n BridgeStatus status;\n uint32 destChainId;\n uint56 proofBlockTimestamp;\n address proofRelayer;\n }\n\n struct BridgeRelay {\n uint48 blockNumber;\n uint48 blockTimestamp;\n address relayer;\n }\n\n /// @notice New params introduced in the FastBridgeV2.\n /// We are passing fields from the older BridgeParams struct outside of this struct\n /// for backwards compatibility.\n /// Note: quoteRelayer and quoteExclusivitySeconds are either both zero (indicating no exclusivity)\n /// or both non-zero (indicating exclusivity for the given period).\n /// Note: zapNative \u003e 0 can NOT be used with destToken = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE (native token)\n /// @param quoteRelayer Relayer that provided the quote for the transaction\n /// @param quoteExclusivitySeconds Period of time the quote relayer is guaranteed exclusivity after user's deposit\n /// @param quoteId Unique quote identifier used for tracking the quote\n /// @param zapNative ETH value to send to the recipient (if any)\n /// @param zapData Parameters for the Zap to the destination recipient (if any)\n struct BridgeParamsV2 {\n address quoteRelayer;\n int256 quoteExclusivitySeconds;\n bytes quoteId;\n uint256 zapNative;\n bytes zapData;\n }\n\n /// @notice Updated bridge transaction struct to include parameters introduced in FastBridgeV2.\n /// Note: only `exclusivityRelayer` can fill such a transaction until `exclusivityEndTime`.\n struct BridgeTransactionV2 {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n // Note: sendChainGas flag from V1 is deprecated\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n address exclusivityRelayer;\n uint256 exclusivityEndTime;\n uint256 zapNative; // ETH value to send to the recipient (if any)\n bytes zapData; // data to pass for the Zap action (if any)\n }\n\n event BridgeQuoteDetails(bytes32 indexed transactionId, bytes quoteId);\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability\n /// to provide temporary exclusivity fill rights for the quote relayer.\n /// @param params The parameters required to bridge\n /// @param paramsV2 The parameters for exclusivity fill rights (optional, can be left empty)\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function relay(bytes memory request, address relayer) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param transactionId The transaction id associated with the encoded bridge transaction to prove\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital.\n /// @notice Can only send funds to the relayer address on the proof.\n /// @param request The encoded bridge transaction to claim on origin chain\n function claim(bytes memory request) external;\n /// @notice Checks if a transaction has been relayed\n /// @param transactionId The ID of the transaction to check\n /// @return True if the transaction has been relayed, false otherwise\n function bridgeRelays(bytes32 transactionId) external view returns (bool);\n\n /// @notice Returns the status of a bridge transaction\n /// @param transactionId The ID of the bridge transaction\n /// @return BridgeStatus Status of the bridge transaction\n function bridgeStatuses(bytes32 transactionId) external view returns (BridgeStatus);\n\n /// @notice Returns the timestamp and relayer of a bridge proof\n /// @param transactionId The ID of the bridge transaction\n /// @return timestamp The timestamp of the bridge proof\n /// @return relayer The relayer address of the bridge proof\n function bridgeProofs(bytes32 transactionId) external view returns (uint96 timestamp, address relayer);\n\n /// @notice Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\n /// @param request The bridge request to decode\n function getBridgeTransactionV2(bytes memory request) external view returns (BridgeTransactionV2 memory);\n}\n\n// contracts/utils/MulticallTarget.sol\n\n// solhint-disable avoid-low-level-calls\n/// @notice Template for a contract that supports batched calls (preserving the msg.sender).\n/// Only calls with zero msg.value could be batched.\nabstract contract MulticallTarget is IMulticallTarget {\n error MulticallTarget__UndeterminedRevert();\n\n /// @notice Perform a batched call to this contract, preserving the msg.sender.\n /// The return data from each call is discarded.\n /// @dev The method is non-payable, so only calls with `msg.value == 0` could be batched.\n /// It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag.\n /// Otherwise, the whole batch call will be reverted with the original revert reason.\n /// @param data List of abi-encoded calldata for the calls to perform.\n /// @param ignoreReverts Whether to ignore the revert errors from the calls.\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external {\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\n if (!success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(result);\n }\n }\n }\n\n /// @notice Perform a batched call to this contract, preserving the msg.sender.\n /// The return data from each call is preserved.\n /// @dev The method is non-payable, so only calls with `msg.value == 0` could be batched.\n /// It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag.\n /// Otherwise, the whole batch call will be reverted with the original revert reason.\n /// @param data List of abi-encoded calldata for the calls to perform.\n /// @param ignoreReverts Whether to ignore the revert errors from the calls.\n /// @return results List of results from the calls: `(success, returnData)`.\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results)\n {\n results = new Result[](data.length);\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (results[i].success, results[i].returnData) = address(this).delegatecall(data[i]);\n if (!results[i].success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(results[i].returnData);\n }\n }\n }\n\n /// @dev Bubbles the revert message from the underlying call.\n /// Note: preserves the same custom error or revert string, if one was used.\n /// Source: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v5.0.2/contracts/utils/Address.sol#L143-L158\n function _bubbleRevert(bytes memory returnData) internal pure {\n // Look for revert reason and bubble it up if present\n if (returnData.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n // solhint-disable-next-line no-inline-assembly\n assembly {\n let returndata_size := mload(returnData)\n revert(add(32, returnData), returndata_size)\n }\n } else {\n revert MulticallTarget__UndeterminedRevert();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// contracts/libs/BridgeTransactionV2.sol\n\n// solhint-disable no-inline-assembly\nlibrary BridgeTransactionV2Lib {\n uint16 internal constant VERSION = 2;\n\n // Offsets of the fields in the packed BridgeTransactionV2 struct\n // uint16 version [000 .. 002)\n // uint32 originChainId [002 .. 006)\n // uint32 destChainId [006 .. 010)\n // address originSender [010 .. 030)\n // address destRecipient [030 .. 050)\n // address originToken [050 .. 070)\n // address destToken [070 .. 090)\n // uint256 originAmount [090 .. 122)\n // uint256 destAmount [122 .. 154)\n // uint256 originFeeAmount [154 .. 186)\n // uint256 deadline [186 .. 218)\n // uint256 nonce [218 .. 250)\n // address exclusivityRelayer [250 .. 270)\n // uint256 exclusivityEndTime [270 .. 302)\n // uint256 zapNative [302 .. 334)\n // bytes zapData [334 .. ***)\n\n // forgefmt: disable-start\n uint256 private constant OFFSET_ORIGIN_CHAIN_ID = 2;\n uint256 private constant OFFSET_DEST_CHAIN_ID = 6;\n uint256 private constant OFFSET_ORIGIN_SENDER = 10;\n uint256 private constant OFFSET_DEST_RECIPIENT = 30;\n uint256 private constant OFFSET_ORIGIN_TOKEN = 50;\n uint256 private constant OFFSET_DEST_TOKEN = 70;\n uint256 private constant OFFSET_ORIGIN_AMOUNT = 90;\n uint256 private constant OFFSET_DEST_AMOUNT = 122;\n uint256 private constant OFFSET_ORIGIN_FEE_AMOUNT = 154;\n uint256 private constant OFFSET_DEADLINE = 186;\n uint256 private constant OFFSET_NONCE = 218;\n uint256 private constant OFFSET_EXCLUSIVITY_RELAYER = 250;\n uint256 private constant OFFSET_EXCLUSIVITY_END_TIME = 270;\n uint256 private constant OFFSET_ZAP_NATIVE = 302;\n uint256 private constant OFFSET_ZAP_DATA = 334;\n // forgefmt: disable-end\n\n error BridgeTransactionV2__InvalidEncodedTx();\n error BridgeTransactionV2__UnsupportedVersion(uint16 version);\n\n /// @notice Validates the encoded transaction to be a tightly packed encoded payload for BridgeTransactionV2.\n /// @dev Checks the minimum length and the version, use this function before decoding any of the fields.\n function validateV2(bytes calldata encodedTx) internal pure {\n // Check the minimum length: must at least include all static fields.\n if (encodedTx.length \u003c OFFSET_ZAP_DATA) revert BridgeTransactionV2__InvalidEncodedTx();\n // Once we validated the length, we can be sure that the version field is present.\n uint16 version_ = version(encodedTx);\n if (version_ != VERSION) revert BridgeTransactionV2__UnsupportedVersion(version_);\n }\n\n /// @notice Encodes the BridgeTransactionV2 struct by tightly packing the fields.\n /// @dev `abi.decode` will not work as a result of the tightly packed fields. Use `decodeV2` to decode instead.\n function encodeV2(IFastBridgeV2.BridgeTransactionV2 memory bridgeTx) internal pure returns (bytes memory) {\n // We split the encoding into two parts to avoid stack-too-deep error\n bytes memory firstPart = abi.encodePacked(\n VERSION,\n bridgeTx.originChainId,\n bridgeTx.destChainId,\n bridgeTx.originSender,\n bridgeTx.destRecipient,\n bridgeTx.originToken,\n bridgeTx.destToken,\n bridgeTx.originAmount\n );\n return abi.encodePacked(\n firstPart,\n bridgeTx.destAmount,\n bridgeTx.originFeeAmount,\n // Note: we skip the deprecated `sendChainGas` flag, which was present in BridgeTransaction V1\n bridgeTx.deadline,\n bridgeTx.nonce,\n // New V2 fields: exclusivity\n bridgeTx.exclusivityRelayer,\n bridgeTx.exclusivityEndTime,\n // New V2 fields: Zap\n bridgeTx.zapNative,\n bridgeTx.zapData\n );\n }\n\n /// @notice Decodes the BridgeTransactionV2 struct from the encoded transaction.\n /// @dev Encoded BridgeTransactionV2 struct must be tightly packed.\n /// Use `validateV2` before decoding to ensure the encoded transaction is valid.\n function decodeV2(bytes calldata encodedTx)\n internal\n pure\n returns (IFastBridgeV2.BridgeTransactionV2 memory bridgeTx)\n {\n bridgeTx.originChainId = originChainId(encodedTx);\n bridgeTx.destChainId = destChainId(encodedTx);\n bridgeTx.originSender = originSender(encodedTx);\n bridgeTx.destRecipient = destRecipient(encodedTx);\n bridgeTx.originToken = originToken(encodedTx);\n bridgeTx.destToken = destToken(encodedTx);\n bridgeTx.originAmount = originAmount(encodedTx);\n bridgeTx.destAmount = destAmount(encodedTx);\n bridgeTx.originFeeAmount = originFeeAmount(encodedTx);\n bridgeTx.deadline = deadline(encodedTx);\n bridgeTx.nonce = nonce(encodedTx);\n bridgeTx.exclusivityRelayer = exclusivityRelayer(encodedTx);\n bridgeTx.exclusivityEndTime = exclusivityEndTime(encodedTx);\n bridgeTx.zapNative = zapNative(encodedTx);\n bridgeTx.zapData = zapData(encodedTx);\n }\n\n /// @notice Extracts the version from the encoded transaction.\n function version(bytes calldata encodedTx) internal pure returns (uint16 version_) {\n // Load 32 bytes from the start and shift it 240 bits to the right to get the highest 16 bits.\n assembly {\n version_ := shr(240, calldataload(encodedTx.offset))\n }\n }\n\n /// @notice Extracts the origin chain ID from the encoded transaction.\n function originChainId(bytes calldata encodedTx) internal pure returns (uint32 originChainId_) {\n // Load 32 bytes from the offset and shift it 224 bits to the right to get the highest 32 bits.\n assembly {\n originChainId_ := shr(224, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_CHAIN_ID)))\n }\n }\n\n /// @notice Extracts the destination chain ID from the encoded transaction.\n function destChainId(bytes calldata encodedTx) internal pure returns (uint32 destChainId_) {\n // Load 32 bytes from the offset and shift it 224 bits to the right to get the highest 32 bits.\n assembly {\n destChainId_ := shr(224, calldataload(add(encodedTx.offset, OFFSET_DEST_CHAIN_ID)))\n }\n }\n\n /// @notice Extracts the origin sender from the encoded transaction.\n function originSender(bytes calldata encodedTx) internal pure returns (address originSender_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n originSender_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_SENDER)))\n }\n }\n\n /// @notice Extracts the destination recipient from the encoded transaction.\n function destRecipient(bytes calldata encodedTx) internal pure returns (address destRecipient_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n destRecipient_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_DEST_RECIPIENT)))\n }\n }\n\n /// @notice Extracts the origin token from the encoded transaction.\n function originToken(bytes calldata encodedTx) internal pure returns (address originToken_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n originToken_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_TOKEN)))\n }\n }\n\n /// @notice Extracts the destination token from the encoded transaction.\n function destToken(bytes calldata encodedTx) internal pure returns (address destToken_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n destToken_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_DEST_TOKEN)))\n }\n }\n\n /// @notice Extracts the origin amount from the encoded transaction.\n function originAmount(bytes calldata encodedTx) internal pure returns (uint256 originAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n originAmount_ := calldataload(add(encodedTx.offset, OFFSET_ORIGIN_AMOUNT))\n }\n }\n\n /// @notice Extracts the destination amount from the encoded transaction.\n function destAmount(bytes calldata encodedTx) internal pure returns (uint256 destAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n destAmount_ := calldataload(add(encodedTx.offset, OFFSET_DEST_AMOUNT))\n }\n }\n\n /// @notice Extracts the origin fee amount from the encoded transaction.\n function originFeeAmount(bytes calldata encodedTx) internal pure returns (uint256 originFeeAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n originFeeAmount_ := calldataload(add(encodedTx.offset, OFFSET_ORIGIN_FEE_AMOUNT))\n }\n }\n\n /// @notice Extracts the deadline from the encoded transaction.\n function deadline(bytes calldata encodedTx) internal pure returns (uint256 deadline_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n deadline_ := calldataload(add(encodedTx.offset, OFFSET_DEADLINE))\n }\n }\n\n /// @notice Extracts the nonce from the encoded transaction.\n function nonce(bytes calldata encodedTx) internal pure returns (uint256 nonce_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n nonce_ := calldataload(add(encodedTx.offset, OFFSET_NONCE))\n }\n }\n\n /// @notice Extracts the exclusivity relayer from the encoded transaction.\n function exclusivityRelayer(bytes calldata encodedTx) internal pure returns (address exclusivityRelayer_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n exclusivityRelayer_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_EXCLUSIVITY_RELAYER)))\n }\n }\n\n /// @notice Extracts the exclusivity end time from the encoded transaction.\n function exclusivityEndTime(bytes calldata encodedTx) internal pure returns (uint256 exclusivityEndTime_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n exclusivityEndTime_ := calldataload(add(encodedTx.offset, OFFSET_EXCLUSIVITY_END_TIME))\n }\n }\n\n /// @notice Extracts the Zap's native value from the encoded transaction.\n function zapNative(bytes calldata encodedTx) internal pure returns (uint256 zapNative_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n zapNative_ := calldataload(add(encodedTx.offset, OFFSET_ZAP_NATIVE))\n }\n }\n\n /// @notice Extracts the Zap's data from the encoded transaction.\n function zapData(bytes calldata encodedTx) internal pure returns (bytes calldata zapData_) {\n zapData_ = encodedTx[OFFSET_ZAP_DATA:];\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// contracts/libs/UniversalToken.sol\n\nlibrary UniversalTokenLib {\n using SafeERC20 for IERC20;\n\n address internal constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Transfers tokens to the given account. Reverts if transfer is not successful.\n /// @dev This might trigger fallback, if ETH is transferred to the contract.\n /// Make sure this can not lead to reentrancy attacks.\n function universalTransfer(address token, address to, uint256 value) internal {\n // Don't do anything, if need to send tokens to this address\n if (to == address(this)) return;\n // Don't do anything, if trying to send zero value\n if (value == 0) return;\n if (token == ETH_ADDRESS) {\n /// @dev Note: this can potentially lead to executing code in `to`.\n // solhint-disable-next-line avoid-low-level-calls\n (bool success,) = to.call{value: value}(\"\");\n require(success, \"ETH transfer failed\");\n } else {\n IERC20(token).safeTransfer(to, value);\n }\n }\n\n /// @notice Issues an infinite allowance to the spender, if the current allowance is insufficient\n /// to spend the given amount.\n function universalApproveInfinity(address token, address spender, uint256 amountToSpend) internal {\n // ETH Chad doesn't require your approval\n if (token == ETH_ADDRESS) return;\n // No-op if allowance is already sufficient\n uint256 allowance = IERC20(token).allowance(address(this), spender);\n if (allowance \u003e= amountToSpend) return;\n // Otherwise, reset approval to 0 and set to max allowance\n if (allowance \u003e 0) IERC20(token).safeDecreaseAllowance(spender, allowance);\n IERC20(token).safeIncreaseAllowance(spender, type(uint256).max);\n }\n\n /// @notice Returns the balance of the given token (or native ETH) for the given account.\n function universalBalanceOf(address token, address account) internal view returns (uint256) {\n if (token == ETH_ADDRESS) {\n return account.balance;\n } else {\n return IERC20(token).balanceOf(account);\n }\n }\n\n /// @dev Checks that token is a contract and not ETH_ADDRESS.\n function assertIsContract(address token) internal view {\n // Check that ETH_ADDRESS was not used (in case this is a predeploy on any of the chains)\n if (token == UniversalTokenLib.ETH_ADDRESS) revert TokenNotContract();\n // Check that token is not an EOA\n if (token.code.length == 0) revert TokenNotContract();\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/Admin.sol\n\ncontract Admin is IAdmin, AccessControlEnumerable {\n using UniversalTokenLib for address;\n\n bytes32 public constant RELAYER_ROLE = keccak256(\"RELAYER_ROLE\");\n bytes32 public constant REFUNDER_ROLE = keccak256(\"REFUNDER_ROLE\");\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n uint256 public constant FEE_BPS = 1e6;\n uint256 public constant FEE_RATE_MAX = 0.01e6; // max 1% on origin amount\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Chain gas amount to forward as rebate if requested\n uint256 public chainGasAmount;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n }\n\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n require(newFeeRate \u003c= FEE_RATE_MAX, \"newFeeRate \u003e max\");\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n token.universalTransfer(recipient, feeAmount);\n emit FeesSwept(token, recipient, feeAmount);\n }\n\n function setChainGasAmount(uint256 newChainGasAmount) external onlyRole(GOVERNOR_ROLE) {\n uint256 oldChainGasAmount = chainGasAmount;\n chainGasAmount = newChainGasAmount;\n emit ChainGasAmountUpdated(oldChainGasAmount, newChainGasAmount);\n }\n}\n\n// contracts/FastBridgeV2.sol\n\n/// @notice FastBridgeV2 is a contract for bridging tokens across chains.\ncontract FastBridgeV2 is Admin, MulticallTarget, IFastBridgeV2, IFastBridgeV2Errors {\n using BridgeTransactionV2Lib for bytes;\n using SafeERC20 for IERC20;\n\n /// @notice Address reserved for native gas token (ETH on Ethereum and most L2s, AVAX on Avalanche, etc)\n address public constant NATIVE_GAS_TOKEN = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Delay for a transaction after which it could be permisionlessly refunded\n uint256 public constant REFUND_DELAY = 7 days;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n /// @notice Maximum length of accepted zapData\n uint256 public constant MAX_ZAP_DATA_LENGTH = 2 ** 16 - 1;\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeTxDetails) public bridgeTxDetails;\n /// @notice Relay details on destination chain\n mapping(bytes32 =\u003e BridgeRelay) public bridgeRelayDetails;\n /// @notice Unique bridge nonces tracked per originSender\n mapping(address =\u003e uint256) public senderNonces;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Replaced by senderNonces\n uint256 public immutable nonce = 0;\n /// @notice the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n bridge({\n params: params,\n paramsV2: BridgeParamsV2({\n quoteRelayer: address(0),\n quoteExclusivitySeconds: 0,\n quoteId: bytes(\"\"),\n zapNative: 0,\n zapData: bytes(\"\")\n })\n });\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes calldata request) external payable {\n // relay override will validate the request\n relay({request: request, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes calldata request, bytes32 destTxHash) external {\n request.validateV2();\n prove({transactionId: keccak256(request), destTxHash: destTxHash, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridgeV2\n function claim(bytes calldata request) external {\n // claim override will validate the request\n claim({request: request, to: address(0)});\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Aggregate the read operations from the same storage slot\n address disputedRelayer = $.proofRelayer;\n BridgeStatus status = $.status;\n uint56 proofBlockTimestamp = $.proofBlockTimestamp;\n // Can only dispute a RELAYER_PROVED transaction within the dispute period\n if (status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(proofBlockTimestamp) \u003e DISPUTE_PERIOD) {\n revert DisputePeriodPassed();\n }\n // Update status to REQUESTED and delete the disputed proof details\n // Note: these are storage writes\n $.status = BridgeStatus.REQUESTED;\n $.proofRelayer = address(0);\n $.proofBlockTimestamp = 0;\n\n emit BridgeProofDisputed(transactionId, disputedRelayer);\n }\n\n /// @inheritdoc IFastBridge\n function refund(bytes calldata request) external {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Can only refund a REQUESTED transaction after its deadline expires\n if ($.status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n uint256 deadline = request.deadline();\n // Permissionless refund is only allowed after REFUND_DELAY on top of the deadline\n if (!hasRole(REFUNDER_ROLE, msg.sender)) deadline += REFUND_DELAY;\n if (block.timestamp \u003c= deadline) revert DeadlineNotExceeded();\n // Update status to REFUNDED and return the full amount (collateral + protocol fees) to the original sender.\n // The protocol fees are only updated when the transaction is claimed, so we don't need to update them here.\n // Note: this is a storage write\n $.status = BridgeStatus.REFUNDED;\n\n address to = request.originSender();\n address token = request.originToken();\n uint256 amount = request.originAmount() + request.originFeeAmount();\n // Emit the event before any external calls\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n // Complete the user refund as the last transaction action\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(to), amount);\n } else {\n IERC20(token).safeTransfer(to, amount);\n }\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // The correct relayer can only claim a RELAYER_PROVED transaction after the dispute period\n if ($.status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if ($.proofRelayer != relayer) revert SenderIncorrect();\n return _timeSince($.proofBlockTimestamp) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n /// @dev This method is added to achieve backwards compatibility with decoding requests into V1 structs:\n /// - `zapNative` is partially reported as a zero/non-zero flag\n /// - `zapData` is ignored\n /// In order to process all kinds of requests use getBridgeTransactionV2 instead.\n function getBridgeTransaction(bytes calldata request) external view returns (BridgeTransaction memory) {\n // Try decoding into V2 struct first. This will revert if V1 struct is passed\n try this.getBridgeTransactionV2(request) returns (BridgeTransactionV2 memory txV2) {\n // Note: we entirely ignore the zapData field, as it was not present in V1\n return BridgeTransaction({\n originChainId: txV2.originChainId,\n destChainId: txV2.destChainId,\n originSender: txV2.originSender,\n destRecipient: txV2.destRecipient,\n originToken: txV2.originToken,\n destToken: txV2.destToken,\n originAmount: txV2.originAmount,\n destAmount: txV2.destAmount,\n originFeeAmount: txV2.originFeeAmount,\n sendChainGas: txV2.zapNative != 0,\n deadline: txV2.deadline,\n nonce: txV2.nonce\n });\n } catch {\n // Fallback to V1 struct\n return abi.decode(request, (BridgeTransaction));\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function getBridgeTransactionV2(bytes calldata request) external pure returns (BridgeTransactionV2 memory) {\n request.validateV2();\n return BridgeTransactionV2Lib.decodeV2(request);\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) public payable {\n int256 exclusivityEndTime = 0;\n // if relayer exclusivity is not intended for this bridge, set exclusivityEndTime to static zero\n // otherwise, set exclusivity to expire at the current block ts offset by quoteExclusivitySeconds\n if (paramsV2.quoteRelayer != address(0)) {\n exclusivityEndTime = int256(block.timestamp) + paramsV2.quoteExclusivitySeconds;\n }\n _validateBridgeParams(params, paramsV2, exclusivityEndTime);\n\n // transfer tokens to bridge contract\n /// @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _takeBridgedUserAsset(params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) {\n originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n }\n\n // set status to requested\n bytes memory request = BridgeTransactionV2Lib.encodeV2(\n BridgeTransactionV2({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n deadline: params.deadline,\n nonce: senderNonces[params.sender]++, // increment nonce on every bridge\n exclusivityRelayer: paramsV2.quoteRelayer,\n // We checked exclusivityEndTime to be in range [0 .. params.deadline] above, so can safely cast\n exclusivityEndTime: uint256(exclusivityEndTime),\n zapNative: paramsV2.zapNative,\n zapData: paramsV2.zapData\n })\n );\n bytes32 transactionId = keccak256(request);\n // Note: the tx status will be updated throughout the tx lifecycle, while destChainId is set once here\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n bridgeTxDetails[transactionId].destChainId = params.dstChainId;\n\n emit BridgeRequested({\n transactionId: transactionId,\n sender: params.sender,\n request: request,\n destChainId: params.dstChainId,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n sendChainGas: paramsV2.zapNative != 0\n });\n emit BridgeQuoteDetails(transactionId, paramsV2.quoteId);\n }\n\n /// @inheritdoc IFastBridgeV2\n function relay(bytes calldata request, address relayer) public payable {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n _validateRelayParams(request, transactionId, relayer);\n // mark bridge transaction as relayed\n bridgeRelayDetails[transactionId] =\n BridgeRelay({blockNumber: uint48(block.number), blockTimestamp: uint48(block.timestamp), relayer: relayer});\n\n // transfer tokens to recipient on destination chain and trigger Zap if requested\n address to = request.destRecipient();\n address token = request.destToken();\n uint256 amount = request.destAmount();\n uint256 zapNative = request.zapNative();\n\n // Emit the event before any external calls\n emit BridgeRelayed({\n transactionId: transactionId,\n relayer: relayer,\n to: to,\n originChainId: request.originChainId(),\n originToken: request.originToken(),\n destToken: token,\n originAmount: request.originAmount(),\n destAmount: amount,\n chainGasAmount: zapNative\n });\n\n // All state changes have been done at this point, can proceed to the external calls.\n // This follows the checks-effects-interactions pattern to mitigate potential reentrancy attacks.\n if (token == NATIVE_GAS_TOKEN) {\n // For the native gas token, additional zapNative is not allowed\n if (zapNative != 0) revert ZapNativeNotSupported();\n // Check that the correct msg.value was sent\n if (msg.value != amount) revert MsgValueIncorrect();\n // Don't do a native transfer yet: we will handle it alongside the Zap below\n } else {\n // For ERC20s, we check that the correct msg.value was sent\n if (msg.value != zapNative) revert MsgValueIncorrect();\n // We need to transfer the tokens from the Relayer to the recipient first before performing an\n // optional post-transfer Zap.\n IERC20(token).safeTransferFrom(msg.sender, to, amount);\n }\n // At this point we have done:\n // - Transferred the requested amount of ERC20 tokens to the recipient.\n // At this point we have confirmed:\n // - For ERC20s: msg.value matches the requested zapNative amount.\n // - For the native gas token: msg.value matches the requested destAmount.\n // Remaining optional things to do:\n // - Forward the full msg.value to the recipient (if non-zero).\n // - Trigger a Zap (if zapData is present).\n bytes calldata zapData = request.zapData();\n if (zapData.length != 0) {\n // Zap Data is present: Zap has been requested by the recipient. Trigger it forwarding the full msg.value.\n\n // Note: if token has a fee on transfers, the recipient will have received less than `amount`.\n // This is a very niche edge case and should be handled by the recipient contract.\n _triggerZapWithChecks({recipient: to, token: token, amount: amount, zapData: zapData});\n } else if (msg.value != 0) {\n // Zap Data is missing, but msg.value was sent. This could happen in two different cases:\n // - Relay with the native gas token is happening.\n // - Relay with ERC20 is happening, with a `zapNative \u003e 0` request.\n // In both cases, we need to transfer the full msg.value to the recipient.\n Address.sendValue(payable(to), msg.value);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) public onlyRole(RELAYER_ROLE) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n\n // Can only prove a REQUESTED transaction\n if ($.status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n // Update status to RELAYER_PROVED and store the proof details\n // Note: these are storage writes\n $.status = BridgeStatus.RELAYER_PROVED;\n $.proofBlockTimestamp = uint56(block.timestamp);\n $.proofRelayer = relayer;\n\n emit BridgeProofProvided(transactionId, relayer, destTxHash);\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes calldata request, address to) public {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Aggregate the read operations from the same storage slot\n address proofRelayer = $.proofRelayer;\n BridgeStatus status = $.status;\n uint56 proofBlockTimestamp = $.proofBlockTimestamp;\n\n // Can only claim a RELAYER_PROVED transaction after the dispute period\n if (status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(proofBlockTimestamp) \u003c= DISPUTE_PERIOD) {\n revert DisputePeriodNotPassed();\n }\n\n if (to == address(0)) {\n // Anyone could claim the funds to the proven relayer on their behalf\n to = proofRelayer;\n } else if (proofRelayer != msg.sender) {\n // Only the proven relayer could specify an address to claim the funds to\n revert SenderIncorrect();\n }\n\n // Update status to RELAYER_CLAIMED and transfer the origin collateral to the specified claim address\n // Note: this is a storage write\n $.status = BridgeStatus.RELAYER_CLAIMED;\n\n address token = request.originToken();\n uint256 amount = request.originAmount();\n // Update protocol fees if origin fee amount exists\n uint256 originFeeAmount = request.originFeeAmount();\n if (originFeeAmount \u003e 0) protocolFees[token] += originFeeAmount;\n // Emit the event before any external calls\n emit BridgeDepositClaimed(transactionId, proofRelayer, to, token, amount);\n // Complete the relayer claim as the last transaction action\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(to), amount);\n } else {\n IERC20(token).safeTransfer(to, amount);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeStatuses(bytes32 transactionId) public view returns (BridgeStatus status) {\n return bridgeTxDetails[transactionId].status;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeProofs(bytes32 transactionId) public view returns (uint96 timestamp, address relayer) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n\n timestamp = $.proofBlockTimestamp;\n relayer = $.proofRelayer;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeRelays(bytes32 transactionId) public view returns (bool) {\n // has this transactionId been relayed?\n return bridgeRelayDetails[transactionId].relayer != address(0);\n }\n\n /// @notice Takes the bridged asset from the user into FastBridgeV2 custody. It will be later\n /// claimed by the relayer who completed the relay on destination chain, or refunded back to the user,\n /// should no one complete the relay.\n function _takeBridgedUserAsset(address token, uint256 amount) internal returns (uint256 amountTaken) {\n if (token == NATIVE_GAS_TOKEN) {\n // For the native gas token, we just need to check that the supplied msg.value is correct.\n // Supplied `msg.value` is already in FastBridgeV2 custody.\n if (amount != msg.value) revert MsgValueIncorrect();\n amountTaken = msg.value;\n } else {\n // For ERC20s, token is explicitly transferred from the user to FastBridgeV2.\n // We don't allow non-zero `msg.value` to avoid extra funds from being stuck in FastBridgeV2.\n if (msg.value != 0) revert MsgValueIncorrect();\n // Throw an explicit error if the provided token address is not a contract\n if (token.code.length == 0) revert TokenNotContract();\n amountTaken = IERC20(token).balanceOf(address(this));\n IERC20(token).safeTransferFrom(msg.sender, address(this), amount);\n // Use the balance difference as the amount taken in case of fee on transfer tokens.\n amountTaken = IERC20(token).balanceOf(address(this)) - amountTaken;\n }\n }\n\n /// @notice Calls the Recipient's hook function with the specified zapData and performs\n /// all the necessary checks for the returned value.\n function _triggerZapWithChecks(address recipient, address token, uint256 amount, bytes calldata zapData) internal {\n // This will bubble any revert messages from the hook function\n bytes memory returnData = Address.functionCallWithValue({\n target: recipient,\n data: abi.encodeCall(IZapRecipient.zap, (token, amount, zapData)),\n // Note: see `relay()` for reasoning behind passing msg.value\n value: msg.value\n });\n // Explicit revert if no return data at all\n if (returnData.length == 0) revert RecipientNoReturnValue();\n // Check that exactly a single return value was returned\n if (returnData.length != 32) revert RecipientIncorrectReturnValue();\n // Return value should be abi-encoded hook function selector\n if (bytes32(returnData) != bytes32(IZapRecipient.zap.selector)) {\n revert RecipientIncorrectReturnValue();\n }\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint56(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint56).max but\n /// proof.timestamp \u003c type(uint56).max via unchecked statement\n /// @param proofBlockTimestamp The bridge proof block timestamp\n /// @return delta Time delta since proof submitted\n function _timeSince(uint56 proofBlockTimestamp) internal view returns (uint256 delta) {\n unchecked {\n delta = uint56(block.timestamp) - proofBlockTimestamp;\n }\n }\n\n /// @notice Performs all the necessary checks for a bridge to happen.\n /// @dev There's no good way to refactor this function to reduce cyclomatic complexity due to\n /// the number of checks that need to be performed, so we skip the code-complexity rule here.\n // solhint-disable-next-line code-complexity\n function _validateBridgeParams(\n BridgeParams memory params,\n BridgeParamsV2 memory paramsV2,\n int256 exclusivityEndTime\n )\n internal\n view\n {\n // Check V1 (legacy) params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.sender == address(0) || params.to == address(0)) revert ZeroAddress();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n // Check V2 params\n if (paramsV2.zapData.length \u003e MAX_ZAP_DATA_LENGTH) revert ZapDataLengthAboveMax();\n if (paramsV2.zapNative != 0 \u0026\u0026 params.destToken == NATIVE_GAS_TOKEN) {\n revert ZapNativeNotSupported();\n }\n // exclusivityEndTime must be in range [0 .. params.deadline]\n if (exclusivityEndTime \u003c 0 || exclusivityEndTime \u003e int256(params.deadline)) {\n revert ExclusivityParamsIncorrect();\n }\n }\n\n /// @notice Performs all the necessary checks for a relay to happen.\n function _validateRelayParams(bytes calldata request, bytes32 transactionId, address relayer) internal view {\n if (relayer == address(0)) revert ZeroAddress();\n // Check if the transaction has already been relayed\n if (bridgeRelays(transactionId)) revert TransactionRelayed();\n if (request.destChainId() != block.chainid) revert ChainIncorrect();\n // Check the deadline for relay to happen\n if (block.timestamp \u003e request.deadline()) revert DeadlineExceeded();\n // Check the exclusivity period, if it is still ongoing\n address exclRelayer = request.exclusivityRelayer();\n if (exclRelayer != address(0) \u0026\u0026 exclRelayer != relayer \u0026\u0026 block.timestamp \u003c= request.exclusivityEndTime()) {\n revert ExclusivityPeriodNotPassed();\n }\n }\n}\n","language":"Solidity","languageVersion":"0.8.24","compilerVersion":"0.8.24","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"17068:6066:0:-:0;;;;;;;;;;;;;;;-1:-1:-1;;;17068:6066:0;;;;;;;;;;;;;;;;;","srcMapRuntime":"17068:6066:0:-:0;;;;;;;;","abiDefinition":[{"inputs":[{"internalType":"address","name":"target","type":"address"}],"name":"AddressEmptyCode","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"AddressInsufficientBalance","type":"error"},{"inputs":[],"name":"FailedInnerCall","type":"error"}],"userDoc":{"kind":"user","methods":{},"version":1},"developerDoc":{"details":"Collection of functions related to the address type","errors":{"AddressEmptyCode(address)":[{"details":"There's no code at `target` (it is not a contract)."}],"AddressInsufficientBalance(address)":[{"details":"The ETH balance of the account is not enough to perform the operation."}],"FailedInnerCall()":[{"details":"A call to an address target failed. The target may have reverted."}]},"kind":"dev","methods":{},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"}],\"name\":\"AddressEmptyCode\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"AddressInsufficientBalance\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"FailedInnerCall\",\"type\":\"error\"}],\"devdoc\":{\"details\":\"Collection of functions related to the address type\",\"errors\":{\"AddressEmptyCode(address)\":[{\"details\":\"There's no code at `target` (it is not a contract).\"}],\"AddressInsufficientBalance(address)\":[{\"details\":\"The ETH balance of the account is not enough to perform the operation.\"}],\"FailedInnerCall()\":[{\"details\":\"A call to an address target failed. The target may have reverted.\"}]},\"kind\":\"dev\",\"methods\":{},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeV2.sol\":\"Address\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeV2.sol\":{\"keccak256\":\"0x5069b55ca07f21bfe30b2a43c18a18318c8af9c181b2dcb07c290825efd70f34\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://273dc020a49d08e50126bbea0d7f783f79d08c702f2fdbc560618d24af308acc\",\"dweb:/ipfs/QmXJ2UVzFc8EPB74RT4CXQPC4xw66jt4T13poyfyd3UERh\"]}},\"version\":1}"},"hashes":{}},"solidity/FastBridgeV2.sol:Admin":{"code":"0x60806040523480156200001157600080fd5b50604051620014123803806200141283398101604081905262000034916200018e565b6200004160008262000049565b5050620001b9565b60008062000058848462000086565b905080156200007d5760008481526001602052604090206200007b908462000134565b505b90505b92915050565b6000828152602081815260408083206001600160a01b038516845290915281205460ff166200012b576000838152602081815260408083206001600160a01b03861684529091529020805460ff19166001179055620000e23390565b6001600160a01b0316826001600160a01b0316847f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a450600162000080565b50600062000080565b60006200007d836001600160a01b03841660008181526001830160205260408120546200012b5750815460018181018455600084815260208082209093018490558454848252828601909352604090209190915562000080565b600060208284031215620001a157600080fd5b81516001600160a01b03811681146200007d57600080fd5b61124980620001c96000396000f3fe608060405234801561001057600080fd5b50600436106101775760003560e01c806391d14854116100d8578063bf333f2c1161008c578063d547741f11610066578063d547741f14610385578063dcf844a714610398578063e00a83e0146103b857600080fd5b8063bf333f2c14610341578063ca15c8731461034b578063ccc574901461035e57600080fd5b8063a217fddf116100bd578063a217fddf14610313578063b13aa2d61461031b578063b250fe6b1461032e57600080fd5b806391d14854146102a8578063926d7d7f146102ec57600080fd5b80632f2ff15d1161012f57806358f858801161011457806358f85880146102405780635960ccf2146102495780639010d07c1461027057600080fd5b80632f2ff15d1461021a57806336568abe1461022d57600080fd5b806306f333f21161016057806306f333f2146101d95780630f5f6ed7146101ee578063248a9ca3146101f757600080fd5b806301ffc9a71461017c57806303ed0ee5146101a4575b600080fd5b61018f61018a366004611013565b6103c1565b60405190151581526020015b60405180910390f35b6101cb7f043c983c49d46f0e102151eaf8085d4a2e6571d5df2d47b013f39bddfd4a639d81565b60405190815260200161019b565b6101ec6101e736600461107e565b61041d565b005b6101cb61271081565b6101cb6102053660046110b1565b60009081526020819052604090206001015490565b6101ec6102283660046110ca565b61050b565b6101ec61023b3660046110ca565b610536565b6101cb60025481565b6101cb7fdb9556138406326f00296e13ea2ad7db24ba82381212d816b1a40c23b466b32781565b61028361027e3660046110ed565b61058f565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200161019b565b61018f6102b63660046110ca565b60009182526020828152604080842073ffffffffffffffffffffffffffffffffffffffff93909316845291905290205460ff1690565b6101cb7fe2b7fb3b832174769106daebcfd6d1970523240dda11281102db9363b83b0dc481565b6101cb600081565b6101ec6103293660046110b1565b6105ae565b6101ec61033c3660046110b1565b610690565b6101cb620f424081565b6101cb6103593660046110b1565b6106f8565b6101cb7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f5581565b6101ec6103933660046110ca565b61070f565b6101cb6103a636600461110f565b60036020526000908152604090205481565b6101cb60045481565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f5a05180f000000000000000000000000000000000000000000000000000000001480610417575061041782610734565b92915050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f55610447816107cb565b73ffffffffffffffffffffffffffffffffffffffff83166000908152600360205260408120549081900361047b5750505050565b73ffffffffffffffffffffffffffffffffffffffff84166000818152600360205260408120556104ac9084836107d8565b6040805173ffffffffffffffffffffffffffffffffffffffff8087168252851660208201529081018290527f244e51bc38c1452fa8aaf487bcb4bca36c2baa3a5fbdb776b1eabd8dc6d277cd9060600160405180910390a1505b505050565b600082815260208190526040902060010154610526816107cb565b610530838361092f565b50505050565b73ffffffffffffffffffffffffffffffffffffffff81163314610585576040517f6697b23200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6105068282610964565b60008281526001602052604081206105a79083610991565b9392505050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f556105d8816107cb565b612710821115610649576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f6e657746656552617465203e206d61780000000000000000000000000000000060448201526064015b60405180910390fd5b600280549083905560408051828152602081018590527f14914da2bf76024616fbe1859783fcd4dbddcb179b1f3a854949fbf920dcb95791015b60405180910390a1505050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f556106ba816107cb565b600480549083905560408051828152602081018590527f5cf09b12f3f56b4c564d51b25b40360af6d795198adb61ae0806a36c294323fa9101610683565b60008181526001602052604081206104179061099d565b60008281526020819052604090206001015461072a816107cb565b6105308383610964565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f7965db0b00000000000000000000000000000000000000000000000000000000148061041757507f01ffc9a7000000000000000000000000000000000000000000000000000000007fffffffff00000000000000000000000000000000000000000000000000000000831614610417565b6107d581336109a7565b50565b3073ffffffffffffffffffffffffffffffffffffffff8316036107fa57505050565b8060000361080757505050565b7fffffffffffffffffffffffff111111111111111111111111111111111111111273ffffffffffffffffffffffffffffffffffffffff84160161090e5760008273ffffffffffffffffffffffffffffffffffffffff168260405160006040518083038185875af1925050503d806000811461089e576040519150601f19603f3d011682016040523d82523d6000602084013e6108a3565b606091505b5050905080610530576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f455448207472616e73666572206661696c6564000000000000000000000000006044820152606401610640565b61050673ffffffffffffffffffffffffffffffffffffffff84168383610a31565b60008061093c8484610abe565b905080156105a757600084815260016020526040902061095c9084610bba565b509392505050565b6000806109718484610bdc565b905080156105a757600084815260016020526040902061095c9084610c97565b60006105a78383610cb9565b6000610417825490565b60008281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915290205460ff16610a2d576040517fe2517d3f00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8216600482015260248101839052604401610640565b5050565b6040805173ffffffffffffffffffffffffffffffffffffffff8416602482015260448082018490528251808303909101815260649091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fa9059cbb00000000000000000000000000000000000000000000000000000000179052610506908490610ce3565b60008281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915281205460ff16610bb25760008381526020818152604080832073ffffffffffffffffffffffffffffffffffffffff86168452909152902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055610b503390565b73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16847f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a4506001610417565b506000610417565b60006105a78373ffffffffffffffffffffffffffffffffffffffff8416610d79565b60008281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915281205460ff1615610bb25760008381526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8616808552925280832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016905551339286917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a4506001610417565b60006105a78373ffffffffffffffffffffffffffffffffffffffff8416610dc0565b6000826000018281548110610cd057610cd061112a565b9060005260206000200154905092915050565b6000610d0573ffffffffffffffffffffffffffffffffffffffff841683610eb3565b90508051600014158015610d2a575080806020019051810190610d289190611159565b155b15610506576040517f5274afe700000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff84166004820152602401610640565b6000818152600183016020526040812054610bb257508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155610417565b60008181526001830160205260408120548015610ea9576000610de460018361117b565b8554909150600090610df89060019061117b565b9050808214610e5d576000866000018281548110610e1857610e1861112a565b9060005260206000200154905080876000018481548110610e3b57610e3b61112a565b6000918252602080832090910192909255918252600188019052604090208390555b8554869080610e6e57610e6e6111b5565b600190038181906000526020600020016000905590558560010160008681526020019081526020016000206000905560019350505050610417565b6000915050610417565b60606105a783836000846000808573ffffffffffffffffffffffffffffffffffffffff168486604051610ee691906111e4565b60006040518083038185875af1925050503d8060008114610f23576040519150601f19603f3d011682016040523d82523d6000602084013e610f28565b606091505b5091509150610f38868383610f42565b9695505050505050565b606082610f5757610f5282610fd1565b6105a7565b8151158015610f7b575073ffffffffffffffffffffffffffffffffffffffff84163b155b15610fca576040517f9996b31500000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff85166004820152602401610640565b50806105a7565b805115610fe15780518082602001fd5b6040517f1425ea4200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006020828403121561102557600080fd5b81357fffffffff00000000000000000000000000000000000000000000000000000000811681146105a757600080fd5b803573ffffffffffffffffffffffffffffffffffffffff8116811461107957600080fd5b919050565b6000806040838503121561109157600080fd5b61109a83611055565b91506110a860208401611055565b90509250929050565b6000602082840312156110c357600080fd5b5035919050565b600080604083850312156110dd57600080fd5b823591506110a860208401611055565b6000806040838503121561110057600080fd5b50508035926020909101359150565b60006020828403121561112157600080fd5b6105a782611055565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60006020828403121561116b57600080fd5b815180151581146105a757600080fd5b81810381811115610417577f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fd5b6000825160005b8181101561120557602081860181015185830152016111eb565b50600092019182525091905056fea2646970667358221220cf33c3d4da69e4a6aeddfcb46cd394bfc44899f75312d31fd8c8e38dff96ab9764736f6c63430008180033","runtime-code":"0x608060405234801561001057600080fd5b50600436106101775760003560e01c806391d14854116100d8578063bf333f2c1161008c578063d547741f11610066578063d547741f14610385578063dcf844a714610398578063e00a83e0146103b857600080fd5b8063bf333f2c14610341578063ca15c8731461034b578063ccc574901461035e57600080fd5b8063a217fddf116100bd578063a217fddf14610313578063b13aa2d61461031b578063b250fe6b1461032e57600080fd5b806391d14854146102a8578063926d7d7f146102ec57600080fd5b80632f2ff15d1161012f57806358f858801161011457806358f85880146102405780635960ccf2146102495780639010d07c1461027057600080fd5b80632f2ff15d1461021a57806336568abe1461022d57600080fd5b806306f333f21161016057806306f333f2146101d95780630f5f6ed7146101ee578063248a9ca3146101f757600080fd5b806301ffc9a71461017c57806303ed0ee5146101a4575b600080fd5b61018f61018a366004611013565b6103c1565b60405190151581526020015b60405180910390f35b6101cb7f043c983c49d46f0e102151eaf8085d4a2e6571d5df2d47b013f39bddfd4a639d81565b60405190815260200161019b565b6101ec6101e736600461107e565b61041d565b005b6101cb61271081565b6101cb6102053660046110b1565b60009081526020819052604090206001015490565b6101ec6102283660046110ca565b61050b565b6101ec61023b3660046110ca565b610536565b6101cb60025481565b6101cb7fdb9556138406326f00296e13ea2ad7db24ba82381212d816b1a40c23b466b32781565b61028361027e3660046110ed565b61058f565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200161019b565b61018f6102b63660046110ca565b60009182526020828152604080842073ffffffffffffffffffffffffffffffffffffffff93909316845291905290205460ff1690565b6101cb7fe2b7fb3b832174769106daebcfd6d1970523240dda11281102db9363b83b0dc481565b6101cb600081565b6101ec6103293660046110b1565b6105ae565b6101ec61033c3660046110b1565b610690565b6101cb620f424081565b6101cb6103593660046110b1565b6106f8565b6101cb7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f5581565b6101ec6103933660046110ca565b61070f565b6101cb6103a636600461110f565b60036020526000908152604090205481565b6101cb60045481565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f5a05180f000000000000000000000000000000000000000000000000000000001480610417575061041782610734565b92915050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f55610447816107cb565b73ffffffffffffffffffffffffffffffffffffffff83166000908152600360205260408120549081900361047b5750505050565b73ffffffffffffffffffffffffffffffffffffffff84166000818152600360205260408120556104ac9084836107d8565b6040805173ffffffffffffffffffffffffffffffffffffffff8087168252851660208201529081018290527f244e51bc38c1452fa8aaf487bcb4bca36c2baa3a5fbdb776b1eabd8dc6d277cd9060600160405180910390a1505b505050565b600082815260208190526040902060010154610526816107cb565b610530838361092f565b50505050565b73ffffffffffffffffffffffffffffffffffffffff81163314610585576040517f6697b23200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6105068282610964565b60008281526001602052604081206105a79083610991565b9392505050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f556105d8816107cb565b612710821115610649576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f6e657746656552617465203e206d61780000000000000000000000000000000060448201526064015b60405180910390fd5b600280549083905560408051828152602081018590527f14914da2bf76024616fbe1859783fcd4dbddcb179b1f3a854949fbf920dcb95791015b60405180910390a1505050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f556106ba816107cb565b600480549083905560408051828152602081018590527f5cf09b12f3f56b4c564d51b25b40360af6d795198adb61ae0806a36c294323fa9101610683565b60008181526001602052604081206104179061099d565b60008281526020819052604090206001015461072a816107cb565b6105308383610964565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f7965db0b00000000000000000000000000000000000000000000000000000000148061041757507f01ffc9a7000000000000000000000000000000000000000000000000000000007fffffffff00000000000000000000000000000000000000000000000000000000831614610417565b6107d581336109a7565b50565b3073ffffffffffffffffffffffffffffffffffffffff8316036107fa57505050565b8060000361080757505050565b7fffffffffffffffffffffffff111111111111111111111111111111111111111273ffffffffffffffffffffffffffffffffffffffff84160161090e5760008273ffffffffffffffffffffffffffffffffffffffff168260405160006040518083038185875af1925050503d806000811461089e576040519150601f19603f3d011682016040523d82523d6000602084013e6108a3565b606091505b5050905080610530576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f455448207472616e73666572206661696c6564000000000000000000000000006044820152606401610640565b61050673ffffffffffffffffffffffffffffffffffffffff84168383610a31565b60008061093c8484610abe565b905080156105a757600084815260016020526040902061095c9084610bba565b509392505050565b6000806109718484610bdc565b905080156105a757600084815260016020526040902061095c9084610c97565b60006105a78383610cb9565b6000610417825490565b60008281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915290205460ff16610a2d576040517fe2517d3f00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8216600482015260248101839052604401610640565b5050565b6040805173ffffffffffffffffffffffffffffffffffffffff8416602482015260448082018490528251808303909101815260649091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fa9059cbb00000000000000000000000000000000000000000000000000000000179052610506908490610ce3565b60008281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915281205460ff16610bb25760008381526020818152604080832073ffffffffffffffffffffffffffffffffffffffff86168452909152902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055610b503390565b73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16847f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a4506001610417565b506000610417565b60006105a78373ffffffffffffffffffffffffffffffffffffffff8416610d79565b60008281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915281205460ff1615610bb25760008381526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8616808552925280832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016905551339286917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a4506001610417565b60006105a78373ffffffffffffffffffffffffffffffffffffffff8416610dc0565b6000826000018281548110610cd057610cd061112a565b9060005260206000200154905092915050565b6000610d0573ffffffffffffffffffffffffffffffffffffffff841683610eb3565b90508051600014158015610d2a575080806020019051810190610d289190611159565b155b15610506576040517f5274afe700000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff84166004820152602401610640565b6000818152600183016020526040812054610bb257508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155610417565b60008181526001830160205260408120548015610ea9576000610de460018361117b565b8554909150600090610df89060019061117b565b9050808214610e5d576000866000018281548110610e1857610e1861112a565b9060005260206000200154905080876000018481548110610e3b57610e3b61112a565b6000918252602080832090910192909255918252600188019052604090208390555b8554869080610e6e57610e6e6111b5565b600190038181906000526020600020016000905590558560010160008681526020019081526020016000206000905560019350505050610417565b6000915050610417565b60606105a783836000846000808573ffffffffffffffffffffffffffffffffffffffff168486604051610ee691906111e4565b60006040518083038185875af1925050503d8060008114610f23576040519150601f19603f3d011682016040523d82523d6000602084013e610f28565b606091505b5091509150610f38868383610f42565b9695505050505050565b606082610f5757610f5282610fd1565b6105a7565b8151158015610f7b575073ffffffffffffffffffffffffffffffffffffffff84163b155b15610fca576040517f9996b31500000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff85166004820152602401610640565b50806105a7565b805115610fe15780518082602001fd5b6040517f1425ea4200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006020828403121561102557600080fd5b81357fffffffff00000000000000000000000000000000000000000000000000000000811681146105a757600080fd5b803573ffffffffffffffffffffffffffffffffffffffff8116811461107957600080fd5b919050565b6000806040838503121561109157600080fd5b61109a83611055565b91506110a860208401611055565b90509250929050565b6000602082840312156110c357600080fd5b5035919050565b600080604083850312156110dd57600080fd5b823591506110a860208401611055565b6000806040838503121561110057600080fd5b50508035926020909101359150565b60006020828403121561112157600080fd5b6105a782611055565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60006020828403121561116b57600080fd5b815180151581146105a757600080fd5b81810381811115610417577f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fd5b6000825160005b8181101561120557602081860181015185830152016111eb565b50600092019182525091905056fea2646970667358221220cf33c3d4da69e4a6aeddfcb46cd394bfc44899f75312d31fd8c8e38dff96ab9764736f6c63430008180033","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.24 ^0.8.20 ^0.8.4;\n\n// contracts/interfaces/IAdmin.sol\n\ninterface IAdmin {\n // ============ Events ============\n\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n event ChainGasAmountUpdated(uint256 oldChainGasAmount, uint256 newChainGasAmount);\n\n // ============ Methods ============\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n\n function setChainGasAmount(uint256 newChainGasAmount) external;\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IFastBridgeV2Errors.sol\n\ninterface IFastBridgeV2Errors {\n error AmountIncorrect();\n error ChainIncorrect();\n error ExclusivityParamsIncorrect();\n error MsgValueIncorrect();\n error SenderIncorrect();\n error StatusIncorrect();\n error TokenNotContract();\n error ZapDataLengthAboveMax();\n error ZapNativeNotSupported();\n error ZeroAddress();\n\n error RecipientIncorrectReturnValue();\n error RecipientNoReturnValue();\n\n error DeadlineExceeded();\n error DeadlineNotExceeded();\n error DeadlineTooShort();\n error DisputePeriodNotPassed();\n error DisputePeriodPassed();\n error ExclusivityPeriodNotPassed();\n\n error TransactionRelayed();\n}\n\n// contracts/interfaces/IMulticallTarget.sol\n\n/// @notice Interface for a contract that can be called multiple times by the same caller. Inspired by MulticallV3:\n/// https://github.com/mds1/multicall/blob/master/src/Multicall3.sol\ninterface IMulticallTarget {\n struct Result {\n bool success;\n bytes returnData;\n }\n\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external;\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results);\n}\n\n// contracts/interfaces/IZapRecipient.sol\n\ninterface IZapRecipient {\n function zap(address token, uint256 amount, bytes memory zapData) external payable returns (bytes4);\n}\n\n// contracts/libs/Errors.sol\n\nerror DeadlineExceeded();\nerror DeadlineNotExceeded();\nerror DeadlineTooShort();\nerror InsufficientOutputAmount();\n\nerror MsgValueIncorrect();\nerror PoolNotFound();\nerror TokenAddressMismatch();\nerror TokenNotContract();\nerror TokenNotETH();\nerror TokensIdentical();\n\nerror ChainIncorrect();\nerror AmountIncorrect();\nerror ZeroAddress();\n\nerror DisputePeriodNotPassed();\nerror DisputePeriodPassed();\nerror SenderIncorrect();\nerror StatusIncorrect();\nerror TransactionIdIncorrect();\nerror TransactionRelayed();\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// contracts/interfaces/IFastBridgeV2.sol\n\ninterface IFastBridgeV2 is IFastBridge {\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n struct BridgeTxDetails {\n BridgeStatus status;\n uint32 destChainId;\n uint56 proofBlockTimestamp;\n address proofRelayer;\n }\n\n struct BridgeRelay {\n uint48 blockNumber;\n uint48 blockTimestamp;\n address relayer;\n }\n\n /// @notice New params introduced in the FastBridgeV2.\n /// We are passing fields from the older BridgeParams struct outside of this struct\n /// for backwards compatibility.\n /// Note: quoteRelayer and quoteExclusivitySeconds are either both zero (indicating no exclusivity)\n /// or both non-zero (indicating exclusivity for the given period).\n /// Note: zapNative \u003e 0 can NOT be used with destToken = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE (native token)\n /// @param quoteRelayer Relayer that provided the quote for the transaction\n /// @param quoteExclusivitySeconds Period of time the quote relayer is guaranteed exclusivity after user's deposit\n /// @param quoteId Unique quote identifier used for tracking the quote\n /// @param zapNative ETH value to send to the recipient (if any)\n /// @param zapData Parameters for the Zap to the destination recipient (if any)\n struct BridgeParamsV2 {\n address quoteRelayer;\n int256 quoteExclusivitySeconds;\n bytes quoteId;\n uint256 zapNative;\n bytes zapData;\n }\n\n /// @notice Updated bridge transaction struct to include parameters introduced in FastBridgeV2.\n /// Note: only `exclusivityRelayer` can fill such a transaction until `exclusivityEndTime`.\n struct BridgeTransactionV2 {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n // Note: sendChainGas flag from V1 is deprecated\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n address exclusivityRelayer;\n uint256 exclusivityEndTime;\n uint256 zapNative; // ETH value to send to the recipient (if any)\n bytes zapData; // data to pass for the Zap action (if any)\n }\n\n event BridgeQuoteDetails(bytes32 indexed transactionId, bytes quoteId);\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability\n /// to provide temporary exclusivity fill rights for the quote relayer.\n /// @param params The parameters required to bridge\n /// @param paramsV2 The parameters for exclusivity fill rights (optional, can be left empty)\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function relay(bytes memory request, address relayer) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param transactionId The transaction id associated with the encoded bridge transaction to prove\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital.\n /// @notice Can only send funds to the relayer address on the proof.\n /// @param request The encoded bridge transaction to claim on origin chain\n function claim(bytes memory request) external;\n /// @notice Checks if a transaction has been relayed\n /// @param transactionId The ID of the transaction to check\n /// @return True if the transaction has been relayed, false otherwise\n function bridgeRelays(bytes32 transactionId) external view returns (bool);\n\n /// @notice Returns the status of a bridge transaction\n /// @param transactionId The ID of the bridge transaction\n /// @return BridgeStatus Status of the bridge transaction\n function bridgeStatuses(bytes32 transactionId) external view returns (BridgeStatus);\n\n /// @notice Returns the timestamp and relayer of a bridge proof\n /// @param transactionId The ID of the bridge transaction\n /// @return timestamp The timestamp of the bridge proof\n /// @return relayer The relayer address of the bridge proof\n function bridgeProofs(bytes32 transactionId) external view returns (uint96 timestamp, address relayer);\n\n /// @notice Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\n /// @param request The bridge request to decode\n function getBridgeTransactionV2(bytes memory request) external view returns (BridgeTransactionV2 memory);\n}\n\n// contracts/utils/MulticallTarget.sol\n\n// solhint-disable avoid-low-level-calls\n/// @notice Template for a contract that supports batched calls (preserving the msg.sender).\n/// Only calls with zero msg.value could be batched.\nabstract contract MulticallTarget is IMulticallTarget {\n error MulticallTarget__UndeterminedRevert();\n\n /// @notice Perform a batched call to this contract, preserving the msg.sender.\n /// The return data from each call is discarded.\n /// @dev The method is non-payable, so only calls with `msg.value == 0` could be batched.\n /// It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag.\n /// Otherwise, the whole batch call will be reverted with the original revert reason.\n /// @param data List of abi-encoded calldata for the calls to perform.\n /// @param ignoreReverts Whether to ignore the revert errors from the calls.\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external {\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\n if (!success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(result);\n }\n }\n }\n\n /// @notice Perform a batched call to this contract, preserving the msg.sender.\n /// The return data from each call is preserved.\n /// @dev The method is non-payable, so only calls with `msg.value == 0` could be batched.\n /// It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag.\n /// Otherwise, the whole batch call will be reverted with the original revert reason.\n /// @param data List of abi-encoded calldata for the calls to perform.\n /// @param ignoreReverts Whether to ignore the revert errors from the calls.\n /// @return results List of results from the calls: `(success, returnData)`.\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results)\n {\n results = new Result[](data.length);\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (results[i].success, results[i].returnData) = address(this).delegatecall(data[i]);\n if (!results[i].success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(results[i].returnData);\n }\n }\n }\n\n /// @dev Bubbles the revert message from the underlying call.\n /// Note: preserves the same custom error or revert string, if one was used.\n /// Source: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v5.0.2/contracts/utils/Address.sol#L143-L158\n function _bubbleRevert(bytes memory returnData) internal pure {\n // Look for revert reason and bubble it up if present\n if (returnData.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n // solhint-disable-next-line no-inline-assembly\n assembly {\n let returndata_size := mload(returnData)\n revert(add(32, returnData), returndata_size)\n }\n } else {\n revert MulticallTarget__UndeterminedRevert();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// contracts/libs/BridgeTransactionV2.sol\n\n// solhint-disable no-inline-assembly\nlibrary BridgeTransactionV2Lib {\n uint16 internal constant VERSION = 2;\n\n // Offsets of the fields in the packed BridgeTransactionV2 struct\n // uint16 version [000 .. 002)\n // uint32 originChainId [002 .. 006)\n // uint32 destChainId [006 .. 010)\n // address originSender [010 .. 030)\n // address destRecipient [030 .. 050)\n // address originToken [050 .. 070)\n // address destToken [070 .. 090)\n // uint256 originAmount [090 .. 122)\n // uint256 destAmount [122 .. 154)\n // uint256 originFeeAmount [154 .. 186)\n // uint256 deadline [186 .. 218)\n // uint256 nonce [218 .. 250)\n // address exclusivityRelayer [250 .. 270)\n // uint256 exclusivityEndTime [270 .. 302)\n // uint256 zapNative [302 .. 334)\n // bytes zapData [334 .. ***)\n\n // forgefmt: disable-start\n uint256 private constant OFFSET_ORIGIN_CHAIN_ID = 2;\n uint256 private constant OFFSET_DEST_CHAIN_ID = 6;\n uint256 private constant OFFSET_ORIGIN_SENDER = 10;\n uint256 private constant OFFSET_DEST_RECIPIENT = 30;\n uint256 private constant OFFSET_ORIGIN_TOKEN = 50;\n uint256 private constant OFFSET_DEST_TOKEN = 70;\n uint256 private constant OFFSET_ORIGIN_AMOUNT = 90;\n uint256 private constant OFFSET_DEST_AMOUNT = 122;\n uint256 private constant OFFSET_ORIGIN_FEE_AMOUNT = 154;\n uint256 private constant OFFSET_DEADLINE = 186;\n uint256 private constant OFFSET_NONCE = 218;\n uint256 private constant OFFSET_EXCLUSIVITY_RELAYER = 250;\n uint256 private constant OFFSET_EXCLUSIVITY_END_TIME = 270;\n uint256 private constant OFFSET_ZAP_NATIVE = 302;\n uint256 private constant OFFSET_ZAP_DATA = 334;\n // forgefmt: disable-end\n\n error BridgeTransactionV2__InvalidEncodedTx();\n error BridgeTransactionV2__UnsupportedVersion(uint16 version);\n\n /// @notice Validates the encoded transaction to be a tightly packed encoded payload for BridgeTransactionV2.\n /// @dev Checks the minimum length and the version, use this function before decoding any of the fields.\n function validateV2(bytes calldata encodedTx) internal pure {\n // Check the minimum length: must at least include all static fields.\n if (encodedTx.length \u003c OFFSET_ZAP_DATA) revert BridgeTransactionV2__InvalidEncodedTx();\n // Once we validated the length, we can be sure that the version field is present.\n uint16 version_ = version(encodedTx);\n if (version_ != VERSION) revert BridgeTransactionV2__UnsupportedVersion(version_);\n }\n\n /// @notice Encodes the BridgeTransactionV2 struct by tightly packing the fields.\n /// @dev `abi.decode` will not work as a result of the tightly packed fields. Use `decodeV2` to decode instead.\n function encodeV2(IFastBridgeV2.BridgeTransactionV2 memory bridgeTx) internal pure returns (bytes memory) {\n // We split the encoding into two parts to avoid stack-too-deep error\n bytes memory firstPart = abi.encodePacked(\n VERSION,\n bridgeTx.originChainId,\n bridgeTx.destChainId,\n bridgeTx.originSender,\n bridgeTx.destRecipient,\n bridgeTx.originToken,\n bridgeTx.destToken,\n bridgeTx.originAmount\n );\n return abi.encodePacked(\n firstPart,\n bridgeTx.destAmount,\n bridgeTx.originFeeAmount,\n // Note: we skip the deprecated `sendChainGas` flag, which was present in BridgeTransaction V1\n bridgeTx.deadline,\n bridgeTx.nonce,\n // New V2 fields: exclusivity\n bridgeTx.exclusivityRelayer,\n bridgeTx.exclusivityEndTime,\n // New V2 fields: Zap\n bridgeTx.zapNative,\n bridgeTx.zapData\n );\n }\n\n /// @notice Decodes the BridgeTransactionV2 struct from the encoded transaction.\n /// @dev Encoded BridgeTransactionV2 struct must be tightly packed.\n /// Use `validateV2` before decoding to ensure the encoded transaction is valid.\n function decodeV2(bytes calldata encodedTx)\n internal\n pure\n returns (IFastBridgeV2.BridgeTransactionV2 memory bridgeTx)\n {\n bridgeTx.originChainId = originChainId(encodedTx);\n bridgeTx.destChainId = destChainId(encodedTx);\n bridgeTx.originSender = originSender(encodedTx);\n bridgeTx.destRecipient = destRecipient(encodedTx);\n bridgeTx.originToken = originToken(encodedTx);\n bridgeTx.destToken = destToken(encodedTx);\n bridgeTx.originAmount = originAmount(encodedTx);\n bridgeTx.destAmount = destAmount(encodedTx);\n bridgeTx.originFeeAmount = originFeeAmount(encodedTx);\n bridgeTx.deadline = deadline(encodedTx);\n bridgeTx.nonce = nonce(encodedTx);\n bridgeTx.exclusivityRelayer = exclusivityRelayer(encodedTx);\n bridgeTx.exclusivityEndTime = exclusivityEndTime(encodedTx);\n bridgeTx.zapNative = zapNative(encodedTx);\n bridgeTx.zapData = zapData(encodedTx);\n }\n\n /// @notice Extracts the version from the encoded transaction.\n function version(bytes calldata encodedTx) internal pure returns (uint16 version_) {\n // Load 32 bytes from the start and shift it 240 bits to the right to get the highest 16 bits.\n assembly {\n version_ := shr(240, calldataload(encodedTx.offset))\n }\n }\n\n /// @notice Extracts the origin chain ID from the encoded transaction.\n function originChainId(bytes calldata encodedTx) internal pure returns (uint32 originChainId_) {\n // Load 32 bytes from the offset and shift it 224 bits to the right to get the highest 32 bits.\n assembly {\n originChainId_ := shr(224, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_CHAIN_ID)))\n }\n }\n\n /// @notice Extracts the destination chain ID from the encoded transaction.\n function destChainId(bytes calldata encodedTx) internal pure returns (uint32 destChainId_) {\n // Load 32 bytes from the offset and shift it 224 bits to the right to get the highest 32 bits.\n assembly {\n destChainId_ := shr(224, calldataload(add(encodedTx.offset, OFFSET_DEST_CHAIN_ID)))\n }\n }\n\n /// @notice Extracts the origin sender from the encoded transaction.\n function originSender(bytes calldata encodedTx) internal pure returns (address originSender_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n originSender_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_SENDER)))\n }\n }\n\n /// @notice Extracts the destination recipient from the encoded transaction.\n function destRecipient(bytes calldata encodedTx) internal pure returns (address destRecipient_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n destRecipient_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_DEST_RECIPIENT)))\n }\n }\n\n /// @notice Extracts the origin token from the encoded transaction.\n function originToken(bytes calldata encodedTx) internal pure returns (address originToken_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n originToken_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_TOKEN)))\n }\n }\n\n /// @notice Extracts the destination token from the encoded transaction.\n function destToken(bytes calldata encodedTx) internal pure returns (address destToken_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n destToken_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_DEST_TOKEN)))\n }\n }\n\n /// @notice Extracts the origin amount from the encoded transaction.\n function originAmount(bytes calldata encodedTx) internal pure returns (uint256 originAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n originAmount_ := calldataload(add(encodedTx.offset, OFFSET_ORIGIN_AMOUNT))\n }\n }\n\n /// @notice Extracts the destination amount from the encoded transaction.\n function destAmount(bytes calldata encodedTx) internal pure returns (uint256 destAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n destAmount_ := calldataload(add(encodedTx.offset, OFFSET_DEST_AMOUNT))\n }\n }\n\n /// @notice Extracts the origin fee amount from the encoded transaction.\n function originFeeAmount(bytes calldata encodedTx) internal pure returns (uint256 originFeeAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n originFeeAmount_ := calldataload(add(encodedTx.offset, OFFSET_ORIGIN_FEE_AMOUNT))\n }\n }\n\n /// @notice Extracts the deadline from the encoded transaction.\n function deadline(bytes calldata encodedTx) internal pure returns (uint256 deadline_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n deadline_ := calldataload(add(encodedTx.offset, OFFSET_DEADLINE))\n }\n }\n\n /// @notice Extracts the nonce from the encoded transaction.\n function nonce(bytes calldata encodedTx) internal pure returns (uint256 nonce_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n nonce_ := calldataload(add(encodedTx.offset, OFFSET_NONCE))\n }\n }\n\n /// @notice Extracts the exclusivity relayer from the encoded transaction.\n function exclusivityRelayer(bytes calldata encodedTx) internal pure returns (address exclusivityRelayer_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n exclusivityRelayer_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_EXCLUSIVITY_RELAYER)))\n }\n }\n\n /// @notice Extracts the exclusivity end time from the encoded transaction.\n function exclusivityEndTime(bytes calldata encodedTx) internal pure returns (uint256 exclusivityEndTime_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n exclusivityEndTime_ := calldataload(add(encodedTx.offset, OFFSET_EXCLUSIVITY_END_TIME))\n }\n }\n\n /// @notice Extracts the Zap's native value from the encoded transaction.\n function zapNative(bytes calldata encodedTx) internal pure returns (uint256 zapNative_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n zapNative_ := calldataload(add(encodedTx.offset, OFFSET_ZAP_NATIVE))\n }\n }\n\n /// @notice Extracts the Zap's data from the encoded transaction.\n function zapData(bytes calldata encodedTx) internal pure returns (bytes calldata zapData_) {\n zapData_ = encodedTx[OFFSET_ZAP_DATA:];\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// contracts/libs/UniversalToken.sol\n\nlibrary UniversalTokenLib {\n using SafeERC20 for IERC20;\n\n address internal constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Transfers tokens to the given account. Reverts if transfer is not successful.\n /// @dev This might trigger fallback, if ETH is transferred to the contract.\n /// Make sure this can not lead to reentrancy attacks.\n function universalTransfer(address token, address to, uint256 value) internal {\n // Don't do anything, if need to send tokens to this address\n if (to == address(this)) return;\n // Don't do anything, if trying to send zero value\n if (value == 0) return;\n if (token == ETH_ADDRESS) {\n /// @dev Note: this can potentially lead to executing code in `to`.\n // solhint-disable-next-line avoid-low-level-calls\n (bool success,) = to.call{value: value}(\"\");\n require(success, \"ETH transfer failed\");\n } else {\n IERC20(token).safeTransfer(to, value);\n }\n }\n\n /// @notice Issues an infinite allowance to the spender, if the current allowance is insufficient\n /// to spend the given amount.\n function universalApproveInfinity(address token, address spender, uint256 amountToSpend) internal {\n // ETH Chad doesn't require your approval\n if (token == ETH_ADDRESS) return;\n // No-op if allowance is already sufficient\n uint256 allowance = IERC20(token).allowance(address(this), spender);\n if (allowance \u003e= amountToSpend) return;\n // Otherwise, reset approval to 0 and set to max allowance\n if (allowance \u003e 0) IERC20(token).safeDecreaseAllowance(spender, allowance);\n IERC20(token).safeIncreaseAllowance(spender, type(uint256).max);\n }\n\n /// @notice Returns the balance of the given token (or native ETH) for the given account.\n function universalBalanceOf(address token, address account) internal view returns (uint256) {\n if (token == ETH_ADDRESS) {\n return account.balance;\n } else {\n return IERC20(token).balanceOf(account);\n }\n }\n\n /// @dev Checks that token is a contract and not ETH_ADDRESS.\n function assertIsContract(address token) internal view {\n // Check that ETH_ADDRESS was not used (in case this is a predeploy on any of the chains)\n if (token == UniversalTokenLib.ETH_ADDRESS) revert TokenNotContract();\n // Check that token is not an EOA\n if (token.code.length == 0) revert TokenNotContract();\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/Admin.sol\n\ncontract Admin is IAdmin, AccessControlEnumerable {\n using UniversalTokenLib for address;\n\n bytes32 public constant RELAYER_ROLE = keccak256(\"RELAYER_ROLE\");\n bytes32 public constant REFUNDER_ROLE = keccak256(\"REFUNDER_ROLE\");\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n uint256 public constant FEE_BPS = 1e6;\n uint256 public constant FEE_RATE_MAX = 0.01e6; // max 1% on origin amount\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Chain gas amount to forward as rebate if requested\n uint256 public chainGasAmount;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n }\n\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n require(newFeeRate \u003c= FEE_RATE_MAX, \"newFeeRate \u003e max\");\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n token.universalTransfer(recipient, feeAmount);\n emit FeesSwept(token, recipient, feeAmount);\n }\n\n function setChainGasAmount(uint256 newChainGasAmount) external onlyRole(GOVERNOR_ROLE) {\n uint256 oldChainGasAmount = chainGasAmount;\n chainGasAmount = newChainGasAmount;\n emit ChainGasAmountUpdated(oldChainGasAmount, newChainGasAmount);\n }\n}\n\n// contracts/FastBridgeV2.sol\n\n/// @notice FastBridgeV2 is a contract for bridging tokens across chains.\ncontract FastBridgeV2 is Admin, MulticallTarget, IFastBridgeV2, IFastBridgeV2Errors {\n using BridgeTransactionV2Lib for bytes;\n using SafeERC20 for IERC20;\n\n /// @notice Address reserved for native gas token (ETH on Ethereum and most L2s, AVAX on Avalanche, etc)\n address public constant NATIVE_GAS_TOKEN = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Delay for a transaction after which it could be permisionlessly refunded\n uint256 public constant REFUND_DELAY = 7 days;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n /// @notice Maximum length of accepted zapData\n uint256 public constant MAX_ZAP_DATA_LENGTH = 2 ** 16 - 1;\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeTxDetails) public bridgeTxDetails;\n /// @notice Relay details on destination chain\n mapping(bytes32 =\u003e BridgeRelay) public bridgeRelayDetails;\n /// @notice Unique bridge nonces tracked per originSender\n mapping(address =\u003e uint256) public senderNonces;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Replaced by senderNonces\n uint256 public immutable nonce = 0;\n /// @notice the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n bridge({\n params: params,\n paramsV2: BridgeParamsV2({\n quoteRelayer: address(0),\n quoteExclusivitySeconds: 0,\n quoteId: bytes(\"\"),\n zapNative: 0,\n zapData: bytes(\"\")\n })\n });\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes calldata request) external payable {\n // relay override will validate the request\n relay({request: request, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes calldata request, bytes32 destTxHash) external {\n request.validateV2();\n prove({transactionId: keccak256(request), destTxHash: destTxHash, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridgeV2\n function claim(bytes calldata request) external {\n // claim override will validate the request\n claim({request: request, to: address(0)});\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Aggregate the read operations from the same storage slot\n address disputedRelayer = $.proofRelayer;\n BridgeStatus status = $.status;\n uint56 proofBlockTimestamp = $.proofBlockTimestamp;\n // Can only dispute a RELAYER_PROVED transaction within the dispute period\n if (status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(proofBlockTimestamp) \u003e DISPUTE_PERIOD) {\n revert DisputePeriodPassed();\n }\n // Update status to REQUESTED and delete the disputed proof details\n // Note: these are storage writes\n $.status = BridgeStatus.REQUESTED;\n $.proofRelayer = address(0);\n $.proofBlockTimestamp = 0;\n\n emit BridgeProofDisputed(transactionId, disputedRelayer);\n }\n\n /// @inheritdoc IFastBridge\n function refund(bytes calldata request) external {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Can only refund a REQUESTED transaction after its deadline expires\n if ($.status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n uint256 deadline = request.deadline();\n // Permissionless refund is only allowed after REFUND_DELAY on top of the deadline\n if (!hasRole(REFUNDER_ROLE, msg.sender)) deadline += REFUND_DELAY;\n if (block.timestamp \u003c= deadline) revert DeadlineNotExceeded();\n // Update status to REFUNDED and return the full amount (collateral + protocol fees) to the original sender.\n // The protocol fees are only updated when the transaction is claimed, so we don't need to update them here.\n // Note: this is a storage write\n $.status = BridgeStatus.REFUNDED;\n\n address to = request.originSender();\n address token = request.originToken();\n uint256 amount = request.originAmount() + request.originFeeAmount();\n // Emit the event before any external calls\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n // Complete the user refund as the last transaction action\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(to), amount);\n } else {\n IERC20(token).safeTransfer(to, amount);\n }\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // The correct relayer can only claim a RELAYER_PROVED transaction after the dispute period\n if ($.status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if ($.proofRelayer != relayer) revert SenderIncorrect();\n return _timeSince($.proofBlockTimestamp) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n /// @dev This method is added to achieve backwards compatibility with decoding requests into V1 structs:\n /// - `zapNative` is partially reported as a zero/non-zero flag\n /// - `zapData` is ignored\n /// In order to process all kinds of requests use getBridgeTransactionV2 instead.\n function getBridgeTransaction(bytes calldata request) external view returns (BridgeTransaction memory) {\n // Try decoding into V2 struct first. This will revert if V1 struct is passed\n try this.getBridgeTransactionV2(request) returns (BridgeTransactionV2 memory txV2) {\n // Note: we entirely ignore the zapData field, as it was not present in V1\n return BridgeTransaction({\n originChainId: txV2.originChainId,\n destChainId: txV2.destChainId,\n originSender: txV2.originSender,\n destRecipient: txV2.destRecipient,\n originToken: txV2.originToken,\n destToken: txV2.destToken,\n originAmount: txV2.originAmount,\n destAmount: txV2.destAmount,\n originFeeAmount: txV2.originFeeAmount,\n sendChainGas: txV2.zapNative != 0,\n deadline: txV2.deadline,\n nonce: txV2.nonce\n });\n } catch {\n // Fallback to V1 struct\n return abi.decode(request, (BridgeTransaction));\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function getBridgeTransactionV2(bytes calldata request) external pure returns (BridgeTransactionV2 memory) {\n request.validateV2();\n return BridgeTransactionV2Lib.decodeV2(request);\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) public payable {\n int256 exclusivityEndTime = 0;\n // if relayer exclusivity is not intended for this bridge, set exclusivityEndTime to static zero\n // otherwise, set exclusivity to expire at the current block ts offset by quoteExclusivitySeconds\n if (paramsV2.quoteRelayer != address(0)) {\n exclusivityEndTime = int256(block.timestamp) + paramsV2.quoteExclusivitySeconds;\n }\n _validateBridgeParams(params, paramsV2, exclusivityEndTime);\n\n // transfer tokens to bridge contract\n /// @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _takeBridgedUserAsset(params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) {\n originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n }\n\n // set status to requested\n bytes memory request = BridgeTransactionV2Lib.encodeV2(\n BridgeTransactionV2({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n deadline: params.deadline,\n nonce: senderNonces[params.sender]++, // increment nonce on every bridge\n exclusivityRelayer: paramsV2.quoteRelayer,\n // We checked exclusivityEndTime to be in range [0 .. params.deadline] above, so can safely cast\n exclusivityEndTime: uint256(exclusivityEndTime),\n zapNative: paramsV2.zapNative,\n zapData: paramsV2.zapData\n })\n );\n bytes32 transactionId = keccak256(request);\n // Note: the tx status will be updated throughout the tx lifecycle, while destChainId is set once here\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n bridgeTxDetails[transactionId].destChainId = params.dstChainId;\n\n emit BridgeRequested({\n transactionId: transactionId,\n sender: params.sender,\n request: request,\n destChainId: params.dstChainId,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n sendChainGas: paramsV2.zapNative != 0\n });\n emit BridgeQuoteDetails(transactionId, paramsV2.quoteId);\n }\n\n /// @inheritdoc IFastBridgeV2\n function relay(bytes calldata request, address relayer) public payable {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n _validateRelayParams(request, transactionId, relayer);\n // mark bridge transaction as relayed\n bridgeRelayDetails[transactionId] =\n BridgeRelay({blockNumber: uint48(block.number), blockTimestamp: uint48(block.timestamp), relayer: relayer});\n\n // transfer tokens to recipient on destination chain and trigger Zap if requested\n address to = request.destRecipient();\n address token = request.destToken();\n uint256 amount = request.destAmount();\n uint256 zapNative = request.zapNative();\n\n // Emit the event before any external calls\n emit BridgeRelayed({\n transactionId: transactionId,\n relayer: relayer,\n to: to,\n originChainId: request.originChainId(),\n originToken: request.originToken(),\n destToken: token,\n originAmount: request.originAmount(),\n destAmount: amount,\n chainGasAmount: zapNative\n });\n\n // All state changes have been done at this point, can proceed to the external calls.\n // This follows the checks-effects-interactions pattern to mitigate potential reentrancy attacks.\n if (token == NATIVE_GAS_TOKEN) {\n // For the native gas token, additional zapNative is not allowed\n if (zapNative != 0) revert ZapNativeNotSupported();\n // Check that the correct msg.value was sent\n if (msg.value != amount) revert MsgValueIncorrect();\n // Don't do a native transfer yet: we will handle it alongside the Zap below\n } else {\n // For ERC20s, we check that the correct msg.value was sent\n if (msg.value != zapNative) revert MsgValueIncorrect();\n // We need to transfer the tokens from the Relayer to the recipient first before performing an\n // optional post-transfer Zap.\n IERC20(token).safeTransferFrom(msg.sender, to, amount);\n }\n // At this point we have done:\n // - Transferred the requested amount of ERC20 tokens to the recipient.\n // At this point we have confirmed:\n // - For ERC20s: msg.value matches the requested zapNative amount.\n // - For the native gas token: msg.value matches the requested destAmount.\n // Remaining optional things to do:\n // - Forward the full msg.value to the recipient (if non-zero).\n // - Trigger a Zap (if zapData is present).\n bytes calldata zapData = request.zapData();\n if (zapData.length != 0) {\n // Zap Data is present: Zap has been requested by the recipient. Trigger it forwarding the full msg.value.\n\n // Note: if token has a fee on transfers, the recipient will have received less than `amount`.\n // This is a very niche edge case and should be handled by the recipient contract.\n _triggerZapWithChecks({recipient: to, token: token, amount: amount, zapData: zapData});\n } else if (msg.value != 0) {\n // Zap Data is missing, but msg.value was sent. This could happen in two different cases:\n // - Relay with the native gas token is happening.\n // - Relay with ERC20 is happening, with a `zapNative \u003e 0` request.\n // In both cases, we need to transfer the full msg.value to the recipient.\n Address.sendValue(payable(to), msg.value);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) public onlyRole(RELAYER_ROLE) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n\n // Can only prove a REQUESTED transaction\n if ($.status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n // Update status to RELAYER_PROVED and store the proof details\n // Note: these are storage writes\n $.status = BridgeStatus.RELAYER_PROVED;\n $.proofBlockTimestamp = uint56(block.timestamp);\n $.proofRelayer = relayer;\n\n emit BridgeProofProvided(transactionId, relayer, destTxHash);\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes calldata request, address to) public {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Aggregate the read operations from the same storage slot\n address proofRelayer = $.proofRelayer;\n BridgeStatus status = $.status;\n uint56 proofBlockTimestamp = $.proofBlockTimestamp;\n\n // Can only claim a RELAYER_PROVED transaction after the dispute period\n if (status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(proofBlockTimestamp) \u003c= DISPUTE_PERIOD) {\n revert DisputePeriodNotPassed();\n }\n\n if (to == address(0)) {\n // Anyone could claim the funds to the proven relayer on their behalf\n to = proofRelayer;\n } else if (proofRelayer != msg.sender) {\n // Only the proven relayer could specify an address to claim the funds to\n revert SenderIncorrect();\n }\n\n // Update status to RELAYER_CLAIMED and transfer the origin collateral to the specified claim address\n // Note: this is a storage write\n $.status = BridgeStatus.RELAYER_CLAIMED;\n\n address token = request.originToken();\n uint256 amount = request.originAmount();\n // Update protocol fees if origin fee amount exists\n uint256 originFeeAmount = request.originFeeAmount();\n if (originFeeAmount \u003e 0) protocolFees[token] += originFeeAmount;\n // Emit the event before any external calls\n emit BridgeDepositClaimed(transactionId, proofRelayer, to, token, amount);\n // Complete the relayer claim as the last transaction action\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(to), amount);\n } else {\n IERC20(token).safeTransfer(to, amount);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeStatuses(bytes32 transactionId) public view returns (BridgeStatus status) {\n return bridgeTxDetails[transactionId].status;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeProofs(bytes32 transactionId) public view returns (uint96 timestamp, address relayer) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n\n timestamp = $.proofBlockTimestamp;\n relayer = $.proofRelayer;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeRelays(bytes32 transactionId) public view returns (bool) {\n // has this transactionId been relayed?\n return bridgeRelayDetails[transactionId].relayer != address(0);\n }\n\n /// @notice Takes the bridged asset from the user into FastBridgeV2 custody. It will be later\n /// claimed by the relayer who completed the relay on destination chain, or refunded back to the user,\n /// should no one complete the relay.\n function _takeBridgedUserAsset(address token, uint256 amount) internal returns (uint256 amountTaken) {\n if (token == NATIVE_GAS_TOKEN) {\n // For the native gas token, we just need to check that the supplied msg.value is correct.\n // Supplied `msg.value` is already in FastBridgeV2 custody.\n if (amount != msg.value) revert MsgValueIncorrect();\n amountTaken = msg.value;\n } else {\n // For ERC20s, token is explicitly transferred from the user to FastBridgeV2.\n // We don't allow non-zero `msg.value` to avoid extra funds from being stuck in FastBridgeV2.\n if (msg.value != 0) revert MsgValueIncorrect();\n // Throw an explicit error if the provided token address is not a contract\n if (token.code.length == 0) revert TokenNotContract();\n amountTaken = IERC20(token).balanceOf(address(this));\n IERC20(token).safeTransferFrom(msg.sender, address(this), amount);\n // Use the balance difference as the amount taken in case of fee on transfer tokens.\n amountTaken = IERC20(token).balanceOf(address(this)) - amountTaken;\n }\n }\n\n /// @notice Calls the Recipient's hook function with the specified zapData and performs\n /// all the necessary checks for the returned value.\n function _triggerZapWithChecks(address recipient, address token, uint256 amount, bytes calldata zapData) internal {\n // This will bubble any revert messages from the hook function\n bytes memory returnData = Address.functionCallWithValue({\n target: recipient,\n data: abi.encodeCall(IZapRecipient.zap, (token, amount, zapData)),\n // Note: see `relay()` for reasoning behind passing msg.value\n value: msg.value\n });\n // Explicit revert if no return data at all\n if (returnData.length == 0) revert RecipientNoReturnValue();\n // Check that exactly a single return value was returned\n if (returnData.length != 32) revert RecipientIncorrectReturnValue();\n // Return value should be abi-encoded hook function selector\n if (bytes32(returnData) != bytes32(IZapRecipient.zap.selector)) {\n revert RecipientIncorrectReturnValue();\n }\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint56(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint56).max but\n /// proof.timestamp \u003c type(uint56).max via unchecked statement\n /// @param proofBlockTimestamp The bridge proof block timestamp\n /// @return delta Time delta since proof submitted\n function _timeSince(uint56 proofBlockTimestamp) internal view returns (uint256 delta) {\n unchecked {\n delta = uint56(block.timestamp) - proofBlockTimestamp;\n }\n }\n\n /// @notice Performs all the necessary checks for a bridge to happen.\n /// @dev There's no good way to refactor this function to reduce cyclomatic complexity due to\n /// the number of checks that need to be performed, so we skip the code-complexity rule here.\n // solhint-disable-next-line code-complexity\n function _validateBridgeParams(\n BridgeParams memory params,\n BridgeParamsV2 memory paramsV2,\n int256 exclusivityEndTime\n )\n internal\n view\n {\n // Check V1 (legacy) params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.sender == address(0) || params.to == address(0)) revert ZeroAddress();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n // Check V2 params\n if (paramsV2.zapData.length \u003e MAX_ZAP_DATA_LENGTH) revert ZapDataLengthAboveMax();\n if (paramsV2.zapNative != 0 \u0026\u0026 params.destToken == NATIVE_GAS_TOKEN) {\n revert ZapNativeNotSupported();\n }\n // exclusivityEndTime must be in range [0 .. params.deadline]\n if (exclusivityEndTime \u003c 0 || exclusivityEndTime \u003e int256(params.deadline)) {\n revert ExclusivityParamsIncorrect();\n }\n }\n\n /// @notice Performs all the necessary checks for a relay to happen.\n function _validateRelayParams(bytes calldata request, bytes32 transactionId, address relayer) internal view {\n if (relayer == address(0)) revert ZeroAddress();\n // Check if the transaction has already been relayed\n if (bridgeRelays(transactionId)) revert TransactionRelayed();\n if (request.destChainId() != block.chainid) revert ChainIncorrect();\n // Check the deadline for relay to happen\n if (block.timestamp \u003e request.deadline()) revert DeadlineExceeded();\n // Check the exclusivity period, if it is still ongoing\n address exclRelayer = request.exclusivityRelayer();\n if (exclRelayer != address(0) \u0026\u0026 exclRelayer != relayer \u0026\u0026 block.timestamp \u003c= request.exclusivityEndTime()) {\n revert ExclusivityPeriodNotPassed();\n }\n }\n}\n","language":"Solidity","languageVersion":"0.8.24","compilerVersion":"0.8.24","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"78879:1843:0:-:0;;;79706:83;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;79744:38;68916:4;79775:6;79744:10;:38::i;:::-;;79706:83;78879:1843;;78229:257;78315:4;;78346:31;78363:4;78369:7;78346:16;:31::i;:::-;78331:46;;78391:7;78387:69;;;78414:18;;;;:12;:18;;;;;:31;;78437:7;78414:22;:31::i;:::-;;78387:69;78472:7;-1:-1:-1;78229:257:0;;;;;:::o;72863:316::-;72940:4;69638:12;;;;;;;;;;;-1:-1:-1;;;;;69638:29:0;;;;;;;;;;;;72956:217;;72999:6;:12;;;;;;;;;;;-1:-1:-1;;;;;72999:29:0;;;;;;;;;:36;;-1:-1:-1;;72999:36:0;73031:4;72999:36;;;73081:12;23872:10;;23793:96;73081:12;-1:-1:-1;;;;;73054:40:0;73072:7;-1:-1:-1;;;;;73054:40:0;73066:4;73054:40;;;;;;;;;;-1:-1:-1;73115:4:0;73108:11;;72956:217;-1:-1:-1;73157:5:0;73150:12;;33317:150;33387:4;33410:50;33415:3;-1:-1:-1;;;;;33435:23:0;;27305:4;29361:21;;;:14;;;:21;;;;;;27321:321;;-1:-1:-1;27363:23:0;;;;;;;;:11;:23;;;;;;;;;;;;;27545:18;;27521:21;;;:14;;;:21;;;;;;:42;;;;27577:11;;14:290:1;84:6;137:2;125:9;116:7;112:23;108:32;105:52;;;153:1;150;143:12;105:52;179:16;;-1:-1:-1;;;;;224:31:1;;214:42;;204:70;;270:1;267;260:12;14:290;78879:1843:0;;;;;;","srcMapRuntime":"78879:1843:0:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;76889:212;;;;;;:::i;:::-;;:::i;:::-;;;516:14:1;;509:22;491:41;;479:2;464:18;76889:212:0;;;;;;;;79119:60;;79156:23;79119:60;;;;;689:25:1;;;677:2;662:18;79119:60:0;543:177:1;80091:359:0;;;;;;:::i;:::-;;:::i;:::-;;79301:45;;79340:6;79301:45;;70494:120;;;;;;:::i;:::-;70559:7;70585:12;;;;;;;;;;:22;;;;70494:120;70910:136;;;;;;:::i;:::-;;:::i;72012:245::-;;;;;;:::i;:::-;;:::i;79463:30::-;;;;;;79047:66;;79087:26;79047:66;;77686:142;;;;;;:::i;:::-;;:::i;:::-;;;2246:42:1;2234:55;;;2216:74;;2204:2;2189:18;77686:142:0;2070:226:1;69538:136:0;;;;;;:::i;:::-;69615:4;69638:12;;;;;;;;;;;:29;;;;;;;;;;;;;;;;69538:136;78977:64;;79016:25;78977:64;;68871:49;;68916:4;68871:49;;79795:290;;;;;;:::i;:::-;;:::i;80456:264::-;;;;;;:::i;:::-;;:::i;79258:37::-;;79292:3;79258:37;;77996:131;;;;;;:::i;:::-;;:::i;79185:66::-;;79225:26;79185:66;;71326:138;;;;;;:::i;:::-;;:::i;79549:47::-;;;;;;:::i;:::-;;;;;;;;;;;;;;79670:29;;;;;;76889:212;76974:4;76997:57;;;77012:42;76997:57;;:97;;;77058:36;77082:11;77058:23;:36::i;:::-;76990:104;76889:212;-1:-1:-1;;76889:212:0:o;80091:359::-;79225:26;69148:16;69159:4;69148:10;:16::i;:::-;80215:19:::1;::::0;::::1;80195:17;80215:19:::0;;;:12:::1;:19;::::0;;;;;;80248:14;;;80244:27:::1;;80264:7;80091:359:::0;;;:::o;80244:27::-:1;80312:19;::::0;::::1;80334:1;80312:19:::0;;;:12:::1;:19;::::0;;;;:23;80345:45:::1;::::0;80369:9;80380;80345:23:::1;:45::i;:::-;80405:38;::::0;;2889:42:1;2958:15;;;2940:34;;3010:15;;3005:2;2990:18;;2983:43;3042:18;;;3035:34;;;80405:38:0::1;::::0;2867:2:1;2852:18;80405:38:0::1;;;;;;;80185:265;69174:1;80091:359:::0;;;:::o;70910:136::-;70559:7;70585:12;;;;;;;;;;:22;;;69148:16;69159:4;69148:10;:16::i;:::-;71014:25:::1;71025:4;71031:7;71014:10;:25::i;:::-;;70910:136:::0;;;:::o;72012:245::-;72105:34;;;23872:10;72105:34;72101:102;;72162:30;;;;;;;;;;;;;;72101:102;72213:37;72225:4;72231:18;72213:11;:37::i;77686:142::-;77767:7;77793:18;;;:12;:18;;;;;:28;;77815:5;77793:21;:28::i;:::-;77786:35;77686:142;-1:-1:-1;;;77686:142:0:o;79795:290::-;79225:26;69148:16;69159:4;69148:10;:16::i;:::-;79340:6:::1;79894:10;:26;;79886:55;;;::::0;::::1;::::0;;3282:2:1;79886:55:0::1;::::0;::::1;3264:21:1::0;3321:2;3301:18;;;3294:30;3360:18;3340;;;3333:46;3396:18;;79886:55:0::1;;;;;;;;;79972:15;::::0;;79997:28;;;;80040:38:::1;::::0;;3599:25:1;;;3655:2;3640:18;;3633:34;;;80040:38:0::1;::::0;3572:18:1;80040:38:0::1;;;;;;;;79876:209;79795:290:::0;;:::o;80456:264::-;79225:26;69148:16;69159:4;69148:10;:16::i;:::-;80581:14:::1;::::0;;80605:34;;;;80654:59:::1;::::0;;3599:25:1;;;3655:2;3640:18;;3633:34;;;80654:59:0::1;::::0;3572:18:1;80654:59:0::1;3425:248:1::0;77996:131:0;78067:7;78093:18;;;:12;:18;;;;;:27;;:25;:27::i;71326:138::-;70559:7;70585:12;;;;;;;;;;:22;;;69148:16;69159:4;69148:10;:16::i;:::-;71431:26:::1;71443:4;71449:7;71431:11;:26::i;69249:202::-:0;69334:4;69357:47;;;69372:32;69357:47;;:87;;-1:-1:-1;49585:25:0;49570:40;;;;69408:36;49471:146;69883:103;69949:30;69960:4;23872:10;69949;:30::i;:::-;69883:103;:::o;74161:653::-;74336:4;74322:19;;;;74318:32;;74161:653;;;:::o;74318:32::-;74422:5;74431:1;74422:10;74418:23;;74161:653;;;:::o;74418:23::-;74454:20;;;;;74450:358;;74634:12;74651:2;:7;;74666:5;74651:25;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;74633:43;;;74698:7;74690:39;;;;;;;4090:2:1;74690:39:0;;;4072:21:1;4129:2;4109:18;;;4102:30;4168:21;4148:18;;;4141:49;4207:18;;74690:39:0;3888:343:1;74450:358:0;74760:37;:26;;;74787:2;74791:5;74760:26;:37::i;78229:257::-;78315:4;78331:12;78346:31;78363:4;78369:7;78346:16;:31::i;:::-;78331:46;;78391:7;78387:69;;;78414:18;;;;:12;:18;;;;;:31;;78437:7;78414:22;:31::i;:::-;;78472:7;78229:257;-1:-1:-1;;;78229:257:0:o;78589:262::-;78676:4;78692:12;78707:32;78725:4;78731:7;78707:17;:32::i;:::-;78692:47;;78753:7;78749:72;;;78776:18;;;;:12;:18;;;;;:34;;78802:7;78776:25;:34::i;34575:156::-;34649:7;34699:22;34703:3;34715:5;34699:3;:22::i;34118:115::-;34181:7;34207:19;34215:3;29557:18;;29475:107;70116:197;69615:4;69638:12;;;;;;;;;;;:29;;;;;;;;;;;;;70199:108;;70249:47;;;;;4440:42:1;4428:55;;70249:47:0;;;4410:74:1;4500:18;;;4493:34;;;4383:18;;70249:47:0;4236:297:1;70199:108:0;70116:197;;:::o;62366:160::-;62475:43;;;62490:14;4428:55:1;;62475:43:0;;;4410:74:1;4500:18;;;;4493:34;;;62475:43:0;;;;;;;;;;4383:18:1;;;;62475:43:0;;;;;;;;;;;;;;62448:71;;62468:5;;62448:19;:71::i;72863:316::-;72940:4;69638:12;;;;;;;;;;;:29;;;;;;;;;;;;;72956:217;;72999:6;:12;;;;;;;;;;;:29;;;;;;;;;;:36;;;;73031:4;72999:36;;;73081:12;23872:10;;23793:96;73081:12;73054:40;;73072:7;73054:40;;73066:4;73054:40;;;;;;;;;;-1:-1:-1;73115:4:0;73108:11;;72956:217;-1:-1:-1;73157:5:0;73150:12;;33317:150;33387:4;33410:50;33415:3;33435:23;;;33410:4;:50::i;73414:317::-;73492:4;69638:12;;;;;;;;;;;:29;;;;;;;;;;;;;73508:217;;;73582:5;73550:12;;;;;;;;;;;:29;;;;;;;;;;;:37;;;;;;73606:40;23872:10;;73550:12;;73606:40;;73582:5;73606:40;-1:-1:-1;73667:4:0;73660:11;;33635:156;33708:4;33731:53;33739:3;33759:23;;;33731:7;:53::i;29924:118::-;29991:7;30017:3;:11;;30029:5;30017:18;;;;;;;;:::i;:::-;;;;;;;;;30010:25;;29924:118;;;;:::o;65122:629::-;65541:23;65567:33;:27;;;65595:4;65567:27;:33::i;:::-;65541:59;;65614:10;:17;65635:1;65614:22;;:57;;;;;65652:10;65641:30;;;;;;;;;;;;:::i;:::-;65640:31;65614:57;65610:135;;;65694:40;;;;;2246:42:1;2234:55;;65694:40:0;;;2216:74:1;2189:18;;65694:40:0;2070:226:1;27242:406:0;27305:4;29361:21;;;:14;;;:21;;;;;;27321:321;;-1:-1:-1;27363:23:0;;;;;;;;:11;:23;;;;;;;;;;;;;27545:18;;27521:21;;;:14;;;:21;;;;;;:42;;;;27577:11;;27816:1368;27882:4;28011:21;;;:14;;;:21;;;;;;28047:13;;28043:1135;;28414:18;28435:12;28446:1;28435:8;:12;:::i;:::-;28481:18;;28414:33;;-1:-1:-1;28461:17:0;;28481:22;;28502:1;;28481:22;:::i;:::-;28461:42;;28536:9;28522:10;:23;28518:378;;28565:17;28585:3;:11;;28597:9;28585:22;;;;;;;;:::i;:::-;;;;;;;;;28565:42;;28732:9;28706:3;:11;;28718:10;28706:23;;;;;;;;:::i;:::-;;;;;;;;;;;;:35;;;;28845:25;;;:14;;;:25;;;;;:36;;;28518:378;28974:17;;:3;;:17;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;29077:3;:14;;:21;29092:5;29077:21;;;;;;;;;;;29070:28;;;29120:4;29113:11;;;;;;;28043:1135;29162:5;29155:12;;;;;19578:151;19653:12;19684:38;19706:6;19714:4;19720:1;19653:12;20294;20308:23;20335:6;:11;;20354:5;20361:4;20335:31;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;20293:73;;;;20383:55;20410:6;20418:7;20427:10;20383:26;:55::i;:::-;20376:62;20053:392;-1:-1:-1;;;;;;20053:392:0:o;21498:582::-;21642:12;21671:7;21666:408;;21694:19;21702:10;21694:7;:19::i;:::-;21666:408;;;21918:17;;:22;:49;;;;-1:-1:-1;21944:18:0;;;;:23;21918:49;21914:119;;;21994:24;;;;;2246:42:1;2234:55;;21994:24:0;;;2216:74:1;2189:18;;21994:24:0;2070:226:1;21914:119:0;-1:-1:-1;22053:10:0;22046:17;;22616:516;22747:17;;:21;22743:383;;22975:10;22969:17;23031:15;23018:10;23014:2;23010:19;23003:44;22743:383;23098:17;;;;;;;;;;;;;;14:332:1;72:6;125:2;113:9;104:7;100:23;96:32;93:52;;;141:1;138;131:12;93:52;180:9;167:23;230:66;223:5;219:78;212:5;209:89;199:117;;312:1;309;302:12;725:196;793:20;;853:42;842:54;;832:65;;822:93;;911:1;908;901:12;822:93;725:196;;;:::o;926:260::-;994:6;1002;1055:2;1043:9;1034:7;1030:23;1026:32;1023:52;;;1071:1;1068;1061:12;1023:52;1094:29;1113:9;1094:29;:::i;:::-;1084:39;;1142:38;1176:2;1165:9;1161:18;1142:38;:::i;:::-;1132:48;;926:260;;;;;:::o;1373:180::-;1432:6;1485:2;1473:9;1464:7;1460:23;1456:32;1453:52;;;1501:1;1498;1491:12;1453:52;-1:-1:-1;1524:23:1;;1373:180;-1:-1:-1;1373:180:1:o;1558:254::-;1626:6;1634;1687:2;1675:9;1666:7;1662:23;1658:32;1655:52;;;1703:1;1700;1693:12;1655:52;1739:9;1726:23;1716:33;;1768:38;1802:2;1791:9;1787:18;1768:38;:::i;1817:248::-;1885:6;1893;1946:2;1934:9;1925:7;1921:23;1917:32;1914:52;;;1962:1;1959;1952:12;1914:52;-1:-1:-1;;1985:23:1;;;2055:2;2040:18;;;2027:32;;-1:-1:-1;1817:248:1:o;2486:186::-;2545:6;2598:2;2586:9;2577:7;2573:23;2569:32;2566:52;;;2614:1;2611;2604:12;2566:52;2637:29;2656:9;2637:29;:::i;4840:184::-;4892:77;4889:1;4882:88;4989:4;4986:1;4979:15;5013:4;5010:1;5003:15;5029:277;5096:6;5149:2;5137:9;5128:7;5124:23;5120:32;5117:52;;;5165:1;5162;5155:12;5117:52;5197:9;5191:16;5250:5;5243:13;5236:21;5229:5;5226:32;5216:60;;5272:1;5269;5262:12;5311:282;5378:9;;;5399:11;;;5396:191;;;5443:77;5440:1;5433:88;5544:4;5541:1;5534:15;5572:4;5569:1;5562:15;5598:184;5650:77;5647:1;5640:88;5747:4;5744:1;5737:15;5771:4;5768:1;5761:15;5787:412;5916:3;5954:6;5948:13;5979:1;5989:129;6003:6;6000:1;5997:13;5989:129;;;6101:4;6085:14;;;6081:25;;6075:32;6062:11;;;6055:53;6018:12;5989:129;;;-1:-1:-1;6173:1:1;6137:16;;6162:13;;;-1:-1:-1;6137:16:1;5787:412;-1:-1:-1;5787:412:1:o","abiDefinition":[{"inputs":[{"internalType":"address","name":"_owner","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AccessControlBadConfirmation","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"bytes32","name":"neededRole","type":"bytes32"}],"name":"AccessControlUnauthorizedAccount","type":"error"},{"inputs":[{"internalType":"address","name":"target","type":"address"}],"name":"AddressEmptyCode","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"AddressInsufficientBalance","type":"error"},{"inputs":[],"name":"FailedInnerCall","type":"error"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"SafeERC20FailedOperation","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldChainGasAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newChainGasAmount","type":"uint256"}],"name":"ChainGasAmountUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldFeeRate","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newFeeRate","type":"uint256"}],"name":"FeeRateUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"address","name":"recipient","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"FeesSwept","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"previousAdminRole","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"newAdminRole","type":"bytes32"}],"name":"RoleAdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleRevoked","type":"event"},{"inputs":[],"name":"DEFAULT_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"FEE_BPS","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"FEE_RATE_MAX","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"GOVERNOR_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"GUARD_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"REFUNDER_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"RELAYER_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"chainGasAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleAdmin","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"uint256","name":"index","type":"uint256"}],"name":"getRoleMember","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleMemberCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"grantRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"hasRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"protocolFeeRate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"protocolFees","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"callerConfirmation","type":"address"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"revokeRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"newChainGasAmount","type":"uint256"}],"name":"setChainGasAmount","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"newFeeRate","type":"uint256"}],"name":"setProtocolFeeRate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"address","name":"recipient","type":"address"}],"name":"sweepProtocolFees","outputs":[],"stateMutability":"nonpayable","type":"function"}],"userDoc":{"kind":"user","methods":{"chainGasAmount()":{"notice":"Chain gas amount to forward as rebate if requested"},"protocolFeeRate()":{"notice":"Protocol fee rate taken on origin amount deposited in origin chain"},"protocolFees(address)":{"notice":"Protocol fee amounts accumulated"}},"version":1},"developerDoc":{"errors":{"AccessControlBadConfirmation()":[{"details":"The caller of a function is not the expected one. NOTE: Don't confuse with {AccessControlUnauthorizedAccount}."}],"AccessControlUnauthorizedAccount(address,bytes32)":[{"details":"The `account` is missing a role."}],"AddressEmptyCode(address)":[{"details":"There's no code at `target` (it is not a contract)."}],"AddressInsufficientBalance(address)":[{"details":"The ETH balance of the account is not enough to perform the operation."}],"FailedInnerCall()":[{"details":"A call to an address target failed. The target may have reverted."}],"SafeERC20FailedOperation(address)":[{"details":"An operation with an ERC20 token failed."}]},"events":{"RoleAdminChanged(bytes32,bytes32,bytes32)":{"details":"Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole` `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite {RoleAdminChanged} not being emitted signaling this."},"RoleGranted(bytes32,address,address)":{"details":"Emitted when `account` is granted `role`. `sender` is the account that originated the contract call, an admin role bearer except when using {AccessControl-_setupRole}."},"RoleRevoked(bytes32,address,address)":{"details":"Emitted when `account` is revoked `role`. `sender` is the account that originated the contract call: - if using `revokeRole`, it is the admin role bearer - if using `renounceRole`, it is the role bearer (i.e. `account`)"}},"kind":"dev","methods":{"getRoleAdmin(bytes32)":{"details":"Returns the admin role that controls `role`. See {grantRole} and {revokeRole}. To change a role's admin, use {_setRoleAdmin}."},"getRoleMember(bytes32,uint256)":{"details":"Returns one of the accounts that have `role`. `index` must be a value between 0 and {getRoleMemberCount}, non-inclusive. Role bearers are not sorted in any particular way, and their ordering may change at any point. WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure you perform all queries on the same block. See the following https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post] for more information."},"getRoleMemberCount(bytes32)":{"details":"Returns the number of accounts that have `role`. Can be used together with {getRoleMember} to enumerate all bearers of a role."},"grantRole(bytes32,address)":{"details":"Grants `role` to `account`. If `account` had not been already granted `role`, emits a {RoleGranted} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleGranted} event."},"hasRole(bytes32,address)":{"details":"Returns `true` if `account` has been granted `role`."},"renounceRole(bytes32,address)":{"details":"Revokes `role` from the calling account. Roles are often managed via {grantRole} and {revokeRole}: this function's purpose is to provide a mechanism for accounts to lose their privileges if they are compromised (such as when a trusted device is misplaced). If the calling account had been revoked `role`, emits a {RoleRevoked} event. Requirements: - the caller must be `callerConfirmation`. May emit a {RoleRevoked} event."},"revokeRole(bytes32,address)":{"details":"Revokes `role` from `account`. If `account` had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleRevoked} event."},"supportsInterface(bytes4)":{"details":"See {IERC165-supportsInterface}."}},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_owner\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"AccessControlBadConfirmation\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"neededRole\",\"type\":\"bytes32\"}],\"name\":\"AccessControlUnauthorizedAccount\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"}],\"name\":\"AddressEmptyCode\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"AddressInsufficientBalance\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"FailedInnerCall\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"}],\"name\":\"SafeERC20FailedOperation\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"oldChainGasAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newChainGasAmount\",\"type\":\"uint256\"}],\"name\":\"ChainGasAmountUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"oldFeeRate\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newFeeRate\",\"type\":\"uint256\"}],\"name\":\"FeeRateUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"FeesSwept\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"previousAdminRole\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"newAdminRole\",\"type\":\"bytes32\"}],\"name\":\"RoleAdminChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleGranted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleRevoked\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"DEFAULT_ADMIN_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"FEE_BPS\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"FEE_RATE_MAX\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"GOVERNOR_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"GUARD_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"REFUNDER_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"RELAYER_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"chainGasAmount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"}],\"name\":\"getRoleAdmin\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"index\",\"type\":\"uint256\"}],\"name\":\"getRoleMember\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"}],\"name\":\"getRoleMemberCount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"grantRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"hasRole\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"protocolFeeRate\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"protocolFees\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"callerConfirmation\",\"type\":\"address\"}],\"name\":\"renounceRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"revokeRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"newChainGasAmount\",\"type\":\"uint256\"}],\"name\":\"setChainGasAmount\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"newFeeRate\",\"type\":\"uint256\"}],\"name\":\"setProtocolFeeRate\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes4\",\"name\":\"interfaceId\",\"type\":\"bytes4\"}],\"name\":\"supportsInterface\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"}],\"name\":\"sweepProtocolFees\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"errors\":{\"AccessControlBadConfirmation()\":[{\"details\":\"The caller of a function is not the expected one. NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\"}],\"AccessControlUnauthorizedAccount(address,bytes32)\":[{\"details\":\"The `account` is missing a role.\"}],\"AddressEmptyCode(address)\":[{\"details\":\"There's no code at `target` (it is not a contract).\"}],\"AddressInsufficientBalance(address)\":[{\"details\":\"The ETH balance of the account is not enough to perform the operation.\"}],\"FailedInnerCall()\":[{\"details\":\"A call to an address target failed. The target may have reverted.\"}],\"SafeERC20FailedOperation(address)\":[{\"details\":\"An operation with an ERC20 token failed.\"}]},\"events\":{\"RoleAdminChanged(bytes32,bytes32,bytes32)\":{\"details\":\"Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole` `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite {RoleAdminChanged} not being emitted signaling this.\"},\"RoleGranted(bytes32,address,address)\":{\"details\":\"Emitted when `account` is granted `role`. `sender` is the account that originated the contract call, an admin role bearer except when using {AccessControl-_setupRole}.\"},\"RoleRevoked(bytes32,address,address)\":{\"details\":\"Emitted when `account` is revoked `role`. `sender` is the account that originated the contract call: - if using `revokeRole`, it is the admin role bearer - if using `renounceRole`, it is the role bearer (i.e. `account`)\"}},\"kind\":\"dev\",\"methods\":{\"getRoleAdmin(bytes32)\":{\"details\":\"Returns the admin role that controls `role`. See {grantRole} and {revokeRole}. To change a role's admin, use {_setRoleAdmin}.\"},\"getRoleMember(bytes32,uint256)\":{\"details\":\"Returns one of the accounts that have `role`. `index` must be a value between 0 and {getRoleMemberCount}, non-inclusive. Role bearers are not sorted in any particular way, and their ordering may change at any point. WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure you perform all queries on the same block. See the following https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post] for more information.\"},\"getRoleMemberCount(bytes32)\":{\"details\":\"Returns the number of accounts that have `role`. Can be used together with {getRoleMember} to enumerate all bearers of a role.\"},\"grantRole(bytes32,address)\":{\"details\":\"Grants `role` to `account`. If `account` had not been already granted `role`, emits a {RoleGranted} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleGranted} event.\"},\"hasRole(bytes32,address)\":{\"details\":\"Returns `true` if `account` has been granted `role`.\"},\"renounceRole(bytes32,address)\":{\"details\":\"Revokes `role` from the calling account. Roles are often managed via {grantRole} and {revokeRole}: this function's purpose is to provide a mechanism for accounts to lose their privileges if they are compromised (such as when a trusted device is misplaced). If the calling account had been revoked `role`, emits a {RoleRevoked} event. Requirements: - the caller must be `callerConfirmation`. May emit a {RoleRevoked} event.\"},\"revokeRole(bytes32,address)\":{\"details\":\"Revokes `role` from `account`. If `account` had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleRevoked} event.\"},\"supportsInterface(bytes4)\":{\"details\":\"See {IERC165-supportsInterface}.\"}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"chainGasAmount()\":{\"notice\":\"Chain gas amount to forward as rebate if requested\"},\"protocolFeeRate()\":{\"notice\":\"Protocol fee rate taken on origin amount deposited in origin chain\"},\"protocolFees(address)\":{\"notice\":\"Protocol fee amounts accumulated\"}},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeV2.sol\":\"Admin\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeV2.sol\":{\"keccak256\":\"0x5069b55ca07f21bfe30b2a43c18a18318c8af9c181b2dcb07c290825efd70f34\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://273dc020a49d08e50126bbea0d7f783f79d08c702f2fdbc560618d24af308acc\",\"dweb:/ipfs/QmXJ2UVzFc8EPB74RT4CXQPC4xw66jt4T13poyfyd3UERh\"]}},\"version\":1}"},"hashes":{"DEFAULT_ADMIN_ROLE()":"a217fddf","FEE_BPS()":"bf333f2c","FEE_RATE_MAX()":"0f5f6ed7","GOVERNOR_ROLE()":"ccc57490","GUARD_ROLE()":"03ed0ee5","REFUNDER_ROLE()":"5960ccf2","RELAYER_ROLE()":"926d7d7f","chainGasAmount()":"e00a83e0","getRoleAdmin(bytes32)":"248a9ca3","getRoleMember(bytes32,uint256)":"9010d07c","getRoleMemberCount(bytes32)":"ca15c873","grantRole(bytes32,address)":"2f2ff15d","hasRole(bytes32,address)":"91d14854","protocolFeeRate()":"58f85880","protocolFees(address)":"dcf844a7","renounceRole(bytes32,address)":"36568abe","revokeRole(bytes32,address)":"d547741f","setChainGasAmount(uint256)":"b250fe6b","setProtocolFeeRate(uint256)":"b13aa2d6","supportsInterface(bytes4)":"01ffc9a7","sweepProtocolFees(address,address)":"06f333f2"}},"solidity/FastBridgeV2.sol:BridgeTransactionV2Lib":{"code":"0x60566037600b82828239805160001a607314602a57634e487b7160e01b600052600060045260246000fd5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600080fdfea2646970667358221220c0d1e2256fb16b1e19ad4848dc80aafe3c3f70b204e139f256b5d6095b52dd5564736f6c63430008180033","runtime-code":"0x73000000000000000000000000000000000000000030146080604052600080fdfea2646970667358221220c0d1e2256fb16b1e19ad4848dc80aafe3c3f70b204e139f256b5d6095b52dd5564736f6c63430008180033","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.24 ^0.8.20 ^0.8.4;\n\n// contracts/interfaces/IAdmin.sol\n\ninterface IAdmin {\n // ============ Events ============\n\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n event ChainGasAmountUpdated(uint256 oldChainGasAmount, uint256 newChainGasAmount);\n\n // ============ Methods ============\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n\n function setChainGasAmount(uint256 newChainGasAmount) external;\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IFastBridgeV2Errors.sol\n\ninterface IFastBridgeV2Errors {\n error AmountIncorrect();\n error ChainIncorrect();\n error ExclusivityParamsIncorrect();\n error MsgValueIncorrect();\n error SenderIncorrect();\n error StatusIncorrect();\n error TokenNotContract();\n error ZapDataLengthAboveMax();\n error ZapNativeNotSupported();\n error ZeroAddress();\n\n error RecipientIncorrectReturnValue();\n error RecipientNoReturnValue();\n\n error DeadlineExceeded();\n error DeadlineNotExceeded();\n error DeadlineTooShort();\n error DisputePeriodNotPassed();\n error DisputePeriodPassed();\n error ExclusivityPeriodNotPassed();\n\n error TransactionRelayed();\n}\n\n// contracts/interfaces/IMulticallTarget.sol\n\n/// @notice Interface for a contract that can be called multiple times by the same caller. Inspired by MulticallV3:\n/// https://github.com/mds1/multicall/blob/master/src/Multicall3.sol\ninterface IMulticallTarget {\n struct Result {\n bool success;\n bytes returnData;\n }\n\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external;\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results);\n}\n\n// contracts/interfaces/IZapRecipient.sol\n\ninterface IZapRecipient {\n function zap(address token, uint256 amount, bytes memory zapData) external payable returns (bytes4);\n}\n\n// contracts/libs/Errors.sol\n\nerror DeadlineExceeded();\nerror DeadlineNotExceeded();\nerror DeadlineTooShort();\nerror InsufficientOutputAmount();\n\nerror MsgValueIncorrect();\nerror PoolNotFound();\nerror TokenAddressMismatch();\nerror TokenNotContract();\nerror TokenNotETH();\nerror TokensIdentical();\n\nerror ChainIncorrect();\nerror AmountIncorrect();\nerror ZeroAddress();\n\nerror DisputePeriodNotPassed();\nerror DisputePeriodPassed();\nerror SenderIncorrect();\nerror StatusIncorrect();\nerror TransactionIdIncorrect();\nerror TransactionRelayed();\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// contracts/interfaces/IFastBridgeV2.sol\n\ninterface IFastBridgeV2 is IFastBridge {\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n struct BridgeTxDetails {\n BridgeStatus status;\n uint32 destChainId;\n uint56 proofBlockTimestamp;\n address proofRelayer;\n }\n\n struct BridgeRelay {\n uint48 blockNumber;\n uint48 blockTimestamp;\n address relayer;\n }\n\n /// @notice New params introduced in the FastBridgeV2.\n /// We are passing fields from the older BridgeParams struct outside of this struct\n /// for backwards compatibility.\n /// Note: quoteRelayer and quoteExclusivitySeconds are either both zero (indicating no exclusivity)\n /// or both non-zero (indicating exclusivity for the given period).\n /// Note: zapNative \u003e 0 can NOT be used with destToken = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE (native token)\n /// @param quoteRelayer Relayer that provided the quote for the transaction\n /// @param quoteExclusivitySeconds Period of time the quote relayer is guaranteed exclusivity after user's deposit\n /// @param quoteId Unique quote identifier used for tracking the quote\n /// @param zapNative ETH value to send to the recipient (if any)\n /// @param zapData Parameters for the Zap to the destination recipient (if any)\n struct BridgeParamsV2 {\n address quoteRelayer;\n int256 quoteExclusivitySeconds;\n bytes quoteId;\n uint256 zapNative;\n bytes zapData;\n }\n\n /// @notice Updated bridge transaction struct to include parameters introduced in FastBridgeV2.\n /// Note: only `exclusivityRelayer` can fill such a transaction until `exclusivityEndTime`.\n struct BridgeTransactionV2 {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n // Note: sendChainGas flag from V1 is deprecated\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n address exclusivityRelayer;\n uint256 exclusivityEndTime;\n uint256 zapNative; // ETH value to send to the recipient (if any)\n bytes zapData; // data to pass for the Zap action (if any)\n }\n\n event BridgeQuoteDetails(bytes32 indexed transactionId, bytes quoteId);\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability\n /// to provide temporary exclusivity fill rights for the quote relayer.\n /// @param params The parameters required to bridge\n /// @param paramsV2 The parameters for exclusivity fill rights (optional, can be left empty)\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function relay(bytes memory request, address relayer) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param transactionId The transaction id associated with the encoded bridge transaction to prove\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital.\n /// @notice Can only send funds to the relayer address on the proof.\n /// @param request The encoded bridge transaction to claim on origin chain\n function claim(bytes memory request) external;\n /// @notice Checks if a transaction has been relayed\n /// @param transactionId The ID of the transaction to check\n /// @return True if the transaction has been relayed, false otherwise\n function bridgeRelays(bytes32 transactionId) external view returns (bool);\n\n /// @notice Returns the status of a bridge transaction\n /// @param transactionId The ID of the bridge transaction\n /// @return BridgeStatus Status of the bridge transaction\n function bridgeStatuses(bytes32 transactionId) external view returns (BridgeStatus);\n\n /// @notice Returns the timestamp and relayer of a bridge proof\n /// @param transactionId The ID of the bridge transaction\n /// @return timestamp The timestamp of the bridge proof\n /// @return relayer The relayer address of the bridge proof\n function bridgeProofs(bytes32 transactionId) external view returns (uint96 timestamp, address relayer);\n\n /// @notice Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\n /// @param request The bridge request to decode\n function getBridgeTransactionV2(bytes memory request) external view returns (BridgeTransactionV2 memory);\n}\n\n// contracts/utils/MulticallTarget.sol\n\n// solhint-disable avoid-low-level-calls\n/// @notice Template for a contract that supports batched calls (preserving the msg.sender).\n/// Only calls with zero msg.value could be batched.\nabstract contract MulticallTarget is IMulticallTarget {\n error MulticallTarget__UndeterminedRevert();\n\n /// @notice Perform a batched call to this contract, preserving the msg.sender.\n /// The return data from each call is discarded.\n /// @dev The method is non-payable, so only calls with `msg.value == 0` could be batched.\n /// It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag.\n /// Otherwise, the whole batch call will be reverted with the original revert reason.\n /// @param data List of abi-encoded calldata for the calls to perform.\n /// @param ignoreReverts Whether to ignore the revert errors from the calls.\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external {\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\n if (!success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(result);\n }\n }\n }\n\n /// @notice Perform a batched call to this contract, preserving the msg.sender.\n /// The return data from each call is preserved.\n /// @dev The method is non-payable, so only calls with `msg.value == 0` could be batched.\n /// It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag.\n /// Otherwise, the whole batch call will be reverted with the original revert reason.\n /// @param data List of abi-encoded calldata for the calls to perform.\n /// @param ignoreReverts Whether to ignore the revert errors from the calls.\n /// @return results List of results from the calls: `(success, returnData)`.\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results)\n {\n results = new Result[](data.length);\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (results[i].success, results[i].returnData) = address(this).delegatecall(data[i]);\n if (!results[i].success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(results[i].returnData);\n }\n }\n }\n\n /// @dev Bubbles the revert message from the underlying call.\n /// Note: preserves the same custom error or revert string, if one was used.\n /// Source: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v5.0.2/contracts/utils/Address.sol#L143-L158\n function _bubbleRevert(bytes memory returnData) internal pure {\n // Look for revert reason and bubble it up if present\n if (returnData.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n // solhint-disable-next-line no-inline-assembly\n assembly {\n let returndata_size := mload(returnData)\n revert(add(32, returnData), returndata_size)\n }\n } else {\n revert MulticallTarget__UndeterminedRevert();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// contracts/libs/BridgeTransactionV2.sol\n\n// solhint-disable no-inline-assembly\nlibrary BridgeTransactionV2Lib {\n uint16 internal constant VERSION = 2;\n\n // Offsets of the fields in the packed BridgeTransactionV2 struct\n // uint16 version [000 .. 002)\n // uint32 originChainId [002 .. 006)\n // uint32 destChainId [006 .. 010)\n // address originSender [010 .. 030)\n // address destRecipient [030 .. 050)\n // address originToken [050 .. 070)\n // address destToken [070 .. 090)\n // uint256 originAmount [090 .. 122)\n // uint256 destAmount [122 .. 154)\n // uint256 originFeeAmount [154 .. 186)\n // uint256 deadline [186 .. 218)\n // uint256 nonce [218 .. 250)\n // address exclusivityRelayer [250 .. 270)\n // uint256 exclusivityEndTime [270 .. 302)\n // uint256 zapNative [302 .. 334)\n // bytes zapData [334 .. ***)\n\n // forgefmt: disable-start\n uint256 private constant OFFSET_ORIGIN_CHAIN_ID = 2;\n uint256 private constant OFFSET_DEST_CHAIN_ID = 6;\n uint256 private constant OFFSET_ORIGIN_SENDER = 10;\n uint256 private constant OFFSET_DEST_RECIPIENT = 30;\n uint256 private constant OFFSET_ORIGIN_TOKEN = 50;\n uint256 private constant OFFSET_DEST_TOKEN = 70;\n uint256 private constant OFFSET_ORIGIN_AMOUNT = 90;\n uint256 private constant OFFSET_DEST_AMOUNT = 122;\n uint256 private constant OFFSET_ORIGIN_FEE_AMOUNT = 154;\n uint256 private constant OFFSET_DEADLINE = 186;\n uint256 private constant OFFSET_NONCE = 218;\n uint256 private constant OFFSET_EXCLUSIVITY_RELAYER = 250;\n uint256 private constant OFFSET_EXCLUSIVITY_END_TIME = 270;\n uint256 private constant OFFSET_ZAP_NATIVE = 302;\n uint256 private constant OFFSET_ZAP_DATA = 334;\n // forgefmt: disable-end\n\n error BridgeTransactionV2__InvalidEncodedTx();\n error BridgeTransactionV2__UnsupportedVersion(uint16 version);\n\n /// @notice Validates the encoded transaction to be a tightly packed encoded payload for BridgeTransactionV2.\n /// @dev Checks the minimum length and the version, use this function before decoding any of the fields.\n function validateV2(bytes calldata encodedTx) internal pure {\n // Check the minimum length: must at least include all static fields.\n if (encodedTx.length \u003c OFFSET_ZAP_DATA) revert BridgeTransactionV2__InvalidEncodedTx();\n // Once we validated the length, we can be sure that the version field is present.\n uint16 version_ = version(encodedTx);\n if (version_ != VERSION) revert BridgeTransactionV2__UnsupportedVersion(version_);\n }\n\n /// @notice Encodes the BridgeTransactionV2 struct by tightly packing the fields.\n /// @dev `abi.decode` will not work as a result of the tightly packed fields. Use `decodeV2` to decode instead.\n function encodeV2(IFastBridgeV2.BridgeTransactionV2 memory bridgeTx) internal pure returns (bytes memory) {\n // We split the encoding into two parts to avoid stack-too-deep error\n bytes memory firstPart = abi.encodePacked(\n VERSION,\n bridgeTx.originChainId,\n bridgeTx.destChainId,\n bridgeTx.originSender,\n bridgeTx.destRecipient,\n bridgeTx.originToken,\n bridgeTx.destToken,\n bridgeTx.originAmount\n );\n return abi.encodePacked(\n firstPart,\n bridgeTx.destAmount,\n bridgeTx.originFeeAmount,\n // Note: we skip the deprecated `sendChainGas` flag, which was present in BridgeTransaction V1\n bridgeTx.deadline,\n bridgeTx.nonce,\n // New V2 fields: exclusivity\n bridgeTx.exclusivityRelayer,\n bridgeTx.exclusivityEndTime,\n // New V2 fields: Zap\n bridgeTx.zapNative,\n bridgeTx.zapData\n );\n }\n\n /// @notice Decodes the BridgeTransactionV2 struct from the encoded transaction.\n /// @dev Encoded BridgeTransactionV2 struct must be tightly packed.\n /// Use `validateV2` before decoding to ensure the encoded transaction is valid.\n function decodeV2(bytes calldata encodedTx)\n internal\n pure\n returns (IFastBridgeV2.BridgeTransactionV2 memory bridgeTx)\n {\n bridgeTx.originChainId = originChainId(encodedTx);\n bridgeTx.destChainId = destChainId(encodedTx);\n bridgeTx.originSender = originSender(encodedTx);\n bridgeTx.destRecipient = destRecipient(encodedTx);\n bridgeTx.originToken = originToken(encodedTx);\n bridgeTx.destToken = destToken(encodedTx);\n bridgeTx.originAmount = originAmount(encodedTx);\n bridgeTx.destAmount = destAmount(encodedTx);\n bridgeTx.originFeeAmount = originFeeAmount(encodedTx);\n bridgeTx.deadline = deadline(encodedTx);\n bridgeTx.nonce = nonce(encodedTx);\n bridgeTx.exclusivityRelayer = exclusivityRelayer(encodedTx);\n bridgeTx.exclusivityEndTime = exclusivityEndTime(encodedTx);\n bridgeTx.zapNative = zapNative(encodedTx);\n bridgeTx.zapData = zapData(encodedTx);\n }\n\n /// @notice Extracts the version from the encoded transaction.\n function version(bytes calldata encodedTx) internal pure returns (uint16 version_) {\n // Load 32 bytes from the start and shift it 240 bits to the right to get the highest 16 bits.\n assembly {\n version_ := shr(240, calldataload(encodedTx.offset))\n }\n }\n\n /// @notice Extracts the origin chain ID from the encoded transaction.\n function originChainId(bytes calldata encodedTx) internal pure returns (uint32 originChainId_) {\n // Load 32 bytes from the offset and shift it 224 bits to the right to get the highest 32 bits.\n assembly {\n originChainId_ := shr(224, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_CHAIN_ID)))\n }\n }\n\n /// @notice Extracts the destination chain ID from the encoded transaction.\n function destChainId(bytes calldata encodedTx) internal pure returns (uint32 destChainId_) {\n // Load 32 bytes from the offset and shift it 224 bits to the right to get the highest 32 bits.\n assembly {\n destChainId_ := shr(224, calldataload(add(encodedTx.offset, OFFSET_DEST_CHAIN_ID)))\n }\n }\n\n /// @notice Extracts the origin sender from the encoded transaction.\n function originSender(bytes calldata encodedTx) internal pure returns (address originSender_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n originSender_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_SENDER)))\n }\n }\n\n /// @notice Extracts the destination recipient from the encoded transaction.\n function destRecipient(bytes calldata encodedTx) internal pure returns (address destRecipient_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n destRecipient_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_DEST_RECIPIENT)))\n }\n }\n\n /// @notice Extracts the origin token from the encoded transaction.\n function originToken(bytes calldata encodedTx) internal pure returns (address originToken_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n originToken_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_TOKEN)))\n }\n }\n\n /// @notice Extracts the destination token from the encoded transaction.\n function destToken(bytes calldata encodedTx) internal pure returns (address destToken_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n destToken_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_DEST_TOKEN)))\n }\n }\n\n /// @notice Extracts the origin amount from the encoded transaction.\n function originAmount(bytes calldata encodedTx) internal pure returns (uint256 originAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n originAmount_ := calldataload(add(encodedTx.offset, OFFSET_ORIGIN_AMOUNT))\n }\n }\n\n /// @notice Extracts the destination amount from the encoded transaction.\n function destAmount(bytes calldata encodedTx) internal pure returns (uint256 destAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n destAmount_ := calldataload(add(encodedTx.offset, OFFSET_DEST_AMOUNT))\n }\n }\n\n /// @notice Extracts the origin fee amount from the encoded transaction.\n function originFeeAmount(bytes calldata encodedTx) internal pure returns (uint256 originFeeAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n originFeeAmount_ := calldataload(add(encodedTx.offset, OFFSET_ORIGIN_FEE_AMOUNT))\n }\n }\n\n /// @notice Extracts the deadline from the encoded transaction.\n function deadline(bytes calldata encodedTx) internal pure returns (uint256 deadline_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n deadline_ := calldataload(add(encodedTx.offset, OFFSET_DEADLINE))\n }\n }\n\n /// @notice Extracts the nonce from the encoded transaction.\n function nonce(bytes calldata encodedTx) internal pure returns (uint256 nonce_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n nonce_ := calldataload(add(encodedTx.offset, OFFSET_NONCE))\n }\n }\n\n /// @notice Extracts the exclusivity relayer from the encoded transaction.\n function exclusivityRelayer(bytes calldata encodedTx) internal pure returns (address exclusivityRelayer_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n exclusivityRelayer_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_EXCLUSIVITY_RELAYER)))\n }\n }\n\n /// @notice Extracts the exclusivity end time from the encoded transaction.\n function exclusivityEndTime(bytes calldata encodedTx) internal pure returns (uint256 exclusivityEndTime_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n exclusivityEndTime_ := calldataload(add(encodedTx.offset, OFFSET_EXCLUSIVITY_END_TIME))\n }\n }\n\n /// @notice Extracts the Zap's native value from the encoded transaction.\n function zapNative(bytes calldata encodedTx) internal pure returns (uint256 zapNative_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n zapNative_ := calldataload(add(encodedTx.offset, OFFSET_ZAP_NATIVE))\n }\n }\n\n /// @notice Extracts the Zap's data from the encoded transaction.\n function zapData(bytes calldata encodedTx) internal pure returns (bytes calldata zapData_) {\n zapData_ = encodedTx[OFFSET_ZAP_DATA:];\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// contracts/libs/UniversalToken.sol\n\nlibrary UniversalTokenLib {\n using SafeERC20 for IERC20;\n\n address internal constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Transfers tokens to the given account. Reverts if transfer is not successful.\n /// @dev This might trigger fallback, if ETH is transferred to the contract.\n /// Make sure this can not lead to reentrancy attacks.\n function universalTransfer(address token, address to, uint256 value) internal {\n // Don't do anything, if need to send tokens to this address\n if (to == address(this)) return;\n // Don't do anything, if trying to send zero value\n if (value == 0) return;\n if (token == ETH_ADDRESS) {\n /// @dev Note: this can potentially lead to executing code in `to`.\n // solhint-disable-next-line avoid-low-level-calls\n (bool success,) = to.call{value: value}(\"\");\n require(success, \"ETH transfer failed\");\n } else {\n IERC20(token).safeTransfer(to, value);\n }\n }\n\n /// @notice Issues an infinite allowance to the spender, if the current allowance is insufficient\n /// to spend the given amount.\n function universalApproveInfinity(address token, address spender, uint256 amountToSpend) internal {\n // ETH Chad doesn't require your approval\n if (token == ETH_ADDRESS) return;\n // No-op if allowance is already sufficient\n uint256 allowance = IERC20(token).allowance(address(this), spender);\n if (allowance \u003e= amountToSpend) return;\n // Otherwise, reset approval to 0 and set to max allowance\n if (allowance \u003e 0) IERC20(token).safeDecreaseAllowance(spender, allowance);\n IERC20(token).safeIncreaseAllowance(spender, type(uint256).max);\n }\n\n /// @notice Returns the balance of the given token (or native ETH) for the given account.\n function universalBalanceOf(address token, address account) internal view returns (uint256) {\n if (token == ETH_ADDRESS) {\n return account.balance;\n } else {\n return IERC20(token).balanceOf(account);\n }\n }\n\n /// @dev Checks that token is a contract and not ETH_ADDRESS.\n function assertIsContract(address token) internal view {\n // Check that ETH_ADDRESS was not used (in case this is a predeploy on any of the chains)\n if (token == UniversalTokenLib.ETH_ADDRESS) revert TokenNotContract();\n // Check that token is not an EOA\n if (token.code.length == 0) revert TokenNotContract();\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/Admin.sol\n\ncontract Admin is IAdmin, AccessControlEnumerable {\n using UniversalTokenLib for address;\n\n bytes32 public constant RELAYER_ROLE = keccak256(\"RELAYER_ROLE\");\n bytes32 public constant REFUNDER_ROLE = keccak256(\"REFUNDER_ROLE\");\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n uint256 public constant FEE_BPS = 1e6;\n uint256 public constant FEE_RATE_MAX = 0.01e6; // max 1% on origin amount\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Chain gas amount to forward as rebate if requested\n uint256 public chainGasAmount;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n }\n\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n require(newFeeRate \u003c= FEE_RATE_MAX, \"newFeeRate \u003e max\");\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n token.universalTransfer(recipient, feeAmount);\n emit FeesSwept(token, recipient, feeAmount);\n }\n\n function setChainGasAmount(uint256 newChainGasAmount) external onlyRole(GOVERNOR_ROLE) {\n uint256 oldChainGasAmount = chainGasAmount;\n chainGasAmount = newChainGasAmount;\n emit ChainGasAmountUpdated(oldChainGasAmount, newChainGasAmount);\n }\n}\n\n// contracts/FastBridgeV2.sol\n\n/// @notice FastBridgeV2 is a contract for bridging tokens across chains.\ncontract FastBridgeV2 is Admin, MulticallTarget, IFastBridgeV2, IFastBridgeV2Errors {\n using BridgeTransactionV2Lib for bytes;\n using SafeERC20 for IERC20;\n\n /// @notice Address reserved for native gas token (ETH on Ethereum and most L2s, AVAX on Avalanche, etc)\n address public constant NATIVE_GAS_TOKEN = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Delay for a transaction after which it could be permisionlessly refunded\n uint256 public constant REFUND_DELAY = 7 days;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n /// @notice Maximum length of accepted zapData\n uint256 public constant MAX_ZAP_DATA_LENGTH = 2 ** 16 - 1;\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeTxDetails) public bridgeTxDetails;\n /// @notice Relay details on destination chain\n mapping(bytes32 =\u003e BridgeRelay) public bridgeRelayDetails;\n /// @notice Unique bridge nonces tracked per originSender\n mapping(address =\u003e uint256) public senderNonces;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Replaced by senderNonces\n uint256 public immutable nonce = 0;\n /// @notice the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n bridge({\n params: params,\n paramsV2: BridgeParamsV2({\n quoteRelayer: address(0),\n quoteExclusivitySeconds: 0,\n quoteId: bytes(\"\"),\n zapNative: 0,\n zapData: bytes(\"\")\n })\n });\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes calldata request) external payable {\n // relay override will validate the request\n relay({request: request, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes calldata request, bytes32 destTxHash) external {\n request.validateV2();\n prove({transactionId: keccak256(request), destTxHash: destTxHash, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridgeV2\n function claim(bytes calldata request) external {\n // claim override will validate the request\n claim({request: request, to: address(0)});\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Aggregate the read operations from the same storage slot\n address disputedRelayer = $.proofRelayer;\n BridgeStatus status = $.status;\n uint56 proofBlockTimestamp = $.proofBlockTimestamp;\n // Can only dispute a RELAYER_PROVED transaction within the dispute period\n if (status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(proofBlockTimestamp) \u003e DISPUTE_PERIOD) {\n revert DisputePeriodPassed();\n }\n // Update status to REQUESTED and delete the disputed proof details\n // Note: these are storage writes\n $.status = BridgeStatus.REQUESTED;\n $.proofRelayer = address(0);\n $.proofBlockTimestamp = 0;\n\n emit BridgeProofDisputed(transactionId, disputedRelayer);\n }\n\n /// @inheritdoc IFastBridge\n function refund(bytes calldata request) external {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Can only refund a REQUESTED transaction after its deadline expires\n if ($.status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n uint256 deadline = request.deadline();\n // Permissionless refund is only allowed after REFUND_DELAY on top of the deadline\n if (!hasRole(REFUNDER_ROLE, msg.sender)) deadline += REFUND_DELAY;\n if (block.timestamp \u003c= deadline) revert DeadlineNotExceeded();\n // Update status to REFUNDED and return the full amount (collateral + protocol fees) to the original sender.\n // The protocol fees are only updated when the transaction is claimed, so we don't need to update them here.\n // Note: this is a storage write\n $.status = BridgeStatus.REFUNDED;\n\n address to = request.originSender();\n address token = request.originToken();\n uint256 amount = request.originAmount() + request.originFeeAmount();\n // Emit the event before any external calls\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n // Complete the user refund as the last transaction action\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(to), amount);\n } else {\n IERC20(token).safeTransfer(to, amount);\n }\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // The correct relayer can only claim a RELAYER_PROVED transaction after the dispute period\n if ($.status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if ($.proofRelayer != relayer) revert SenderIncorrect();\n return _timeSince($.proofBlockTimestamp) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n /// @dev This method is added to achieve backwards compatibility with decoding requests into V1 structs:\n /// - `zapNative` is partially reported as a zero/non-zero flag\n /// - `zapData` is ignored\n /// In order to process all kinds of requests use getBridgeTransactionV2 instead.\n function getBridgeTransaction(bytes calldata request) external view returns (BridgeTransaction memory) {\n // Try decoding into V2 struct first. This will revert if V1 struct is passed\n try this.getBridgeTransactionV2(request) returns (BridgeTransactionV2 memory txV2) {\n // Note: we entirely ignore the zapData field, as it was not present in V1\n return BridgeTransaction({\n originChainId: txV2.originChainId,\n destChainId: txV2.destChainId,\n originSender: txV2.originSender,\n destRecipient: txV2.destRecipient,\n originToken: txV2.originToken,\n destToken: txV2.destToken,\n originAmount: txV2.originAmount,\n destAmount: txV2.destAmount,\n originFeeAmount: txV2.originFeeAmount,\n sendChainGas: txV2.zapNative != 0,\n deadline: txV2.deadline,\n nonce: txV2.nonce\n });\n } catch {\n // Fallback to V1 struct\n return abi.decode(request, (BridgeTransaction));\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function getBridgeTransactionV2(bytes calldata request) external pure returns (BridgeTransactionV2 memory) {\n request.validateV2();\n return BridgeTransactionV2Lib.decodeV2(request);\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) public payable {\n int256 exclusivityEndTime = 0;\n // if relayer exclusivity is not intended for this bridge, set exclusivityEndTime to static zero\n // otherwise, set exclusivity to expire at the current block ts offset by quoteExclusivitySeconds\n if (paramsV2.quoteRelayer != address(0)) {\n exclusivityEndTime = int256(block.timestamp) + paramsV2.quoteExclusivitySeconds;\n }\n _validateBridgeParams(params, paramsV2, exclusivityEndTime);\n\n // transfer tokens to bridge contract\n /// @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _takeBridgedUserAsset(params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) {\n originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n }\n\n // set status to requested\n bytes memory request = BridgeTransactionV2Lib.encodeV2(\n BridgeTransactionV2({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n deadline: params.deadline,\n nonce: senderNonces[params.sender]++, // increment nonce on every bridge\n exclusivityRelayer: paramsV2.quoteRelayer,\n // We checked exclusivityEndTime to be in range [0 .. params.deadline] above, so can safely cast\n exclusivityEndTime: uint256(exclusivityEndTime),\n zapNative: paramsV2.zapNative,\n zapData: paramsV2.zapData\n })\n );\n bytes32 transactionId = keccak256(request);\n // Note: the tx status will be updated throughout the tx lifecycle, while destChainId is set once here\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n bridgeTxDetails[transactionId].destChainId = params.dstChainId;\n\n emit BridgeRequested({\n transactionId: transactionId,\n sender: params.sender,\n request: request,\n destChainId: params.dstChainId,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n sendChainGas: paramsV2.zapNative != 0\n });\n emit BridgeQuoteDetails(transactionId, paramsV2.quoteId);\n }\n\n /// @inheritdoc IFastBridgeV2\n function relay(bytes calldata request, address relayer) public payable {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n _validateRelayParams(request, transactionId, relayer);\n // mark bridge transaction as relayed\n bridgeRelayDetails[transactionId] =\n BridgeRelay({blockNumber: uint48(block.number), blockTimestamp: uint48(block.timestamp), relayer: relayer});\n\n // transfer tokens to recipient on destination chain and trigger Zap if requested\n address to = request.destRecipient();\n address token = request.destToken();\n uint256 amount = request.destAmount();\n uint256 zapNative = request.zapNative();\n\n // Emit the event before any external calls\n emit BridgeRelayed({\n transactionId: transactionId,\n relayer: relayer,\n to: to,\n originChainId: request.originChainId(),\n originToken: request.originToken(),\n destToken: token,\n originAmount: request.originAmount(),\n destAmount: amount,\n chainGasAmount: zapNative\n });\n\n // All state changes have been done at this point, can proceed to the external calls.\n // This follows the checks-effects-interactions pattern to mitigate potential reentrancy attacks.\n if (token == NATIVE_GAS_TOKEN) {\n // For the native gas token, additional zapNative is not allowed\n if (zapNative != 0) revert ZapNativeNotSupported();\n // Check that the correct msg.value was sent\n if (msg.value != amount) revert MsgValueIncorrect();\n // Don't do a native transfer yet: we will handle it alongside the Zap below\n } else {\n // For ERC20s, we check that the correct msg.value was sent\n if (msg.value != zapNative) revert MsgValueIncorrect();\n // We need to transfer the tokens from the Relayer to the recipient first before performing an\n // optional post-transfer Zap.\n IERC20(token).safeTransferFrom(msg.sender, to, amount);\n }\n // At this point we have done:\n // - Transferred the requested amount of ERC20 tokens to the recipient.\n // At this point we have confirmed:\n // - For ERC20s: msg.value matches the requested zapNative amount.\n // - For the native gas token: msg.value matches the requested destAmount.\n // Remaining optional things to do:\n // - Forward the full msg.value to the recipient (if non-zero).\n // - Trigger a Zap (if zapData is present).\n bytes calldata zapData = request.zapData();\n if (zapData.length != 0) {\n // Zap Data is present: Zap has been requested by the recipient. Trigger it forwarding the full msg.value.\n\n // Note: if token has a fee on transfers, the recipient will have received less than `amount`.\n // This is a very niche edge case and should be handled by the recipient contract.\n _triggerZapWithChecks({recipient: to, token: token, amount: amount, zapData: zapData});\n } else if (msg.value != 0) {\n // Zap Data is missing, but msg.value was sent. This could happen in two different cases:\n // - Relay with the native gas token is happening.\n // - Relay with ERC20 is happening, with a `zapNative \u003e 0` request.\n // In both cases, we need to transfer the full msg.value to the recipient.\n Address.sendValue(payable(to), msg.value);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) public onlyRole(RELAYER_ROLE) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n\n // Can only prove a REQUESTED transaction\n if ($.status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n // Update status to RELAYER_PROVED and store the proof details\n // Note: these are storage writes\n $.status = BridgeStatus.RELAYER_PROVED;\n $.proofBlockTimestamp = uint56(block.timestamp);\n $.proofRelayer = relayer;\n\n emit BridgeProofProvided(transactionId, relayer, destTxHash);\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes calldata request, address to) public {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Aggregate the read operations from the same storage slot\n address proofRelayer = $.proofRelayer;\n BridgeStatus status = $.status;\n uint56 proofBlockTimestamp = $.proofBlockTimestamp;\n\n // Can only claim a RELAYER_PROVED transaction after the dispute period\n if (status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(proofBlockTimestamp) \u003c= DISPUTE_PERIOD) {\n revert DisputePeriodNotPassed();\n }\n\n if (to == address(0)) {\n // Anyone could claim the funds to the proven relayer on their behalf\n to = proofRelayer;\n } else if (proofRelayer != msg.sender) {\n // Only the proven relayer could specify an address to claim the funds to\n revert SenderIncorrect();\n }\n\n // Update status to RELAYER_CLAIMED and transfer the origin collateral to the specified claim address\n // Note: this is a storage write\n $.status = BridgeStatus.RELAYER_CLAIMED;\n\n address token = request.originToken();\n uint256 amount = request.originAmount();\n // Update protocol fees if origin fee amount exists\n uint256 originFeeAmount = request.originFeeAmount();\n if (originFeeAmount \u003e 0) protocolFees[token] += originFeeAmount;\n // Emit the event before any external calls\n emit BridgeDepositClaimed(transactionId, proofRelayer, to, token, amount);\n // Complete the relayer claim as the last transaction action\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(to), amount);\n } else {\n IERC20(token).safeTransfer(to, amount);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeStatuses(bytes32 transactionId) public view returns (BridgeStatus status) {\n return bridgeTxDetails[transactionId].status;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeProofs(bytes32 transactionId) public view returns (uint96 timestamp, address relayer) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n\n timestamp = $.proofBlockTimestamp;\n relayer = $.proofRelayer;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeRelays(bytes32 transactionId) public view returns (bool) {\n // has this transactionId been relayed?\n return bridgeRelayDetails[transactionId].relayer != address(0);\n }\n\n /// @notice Takes the bridged asset from the user into FastBridgeV2 custody. It will be later\n /// claimed by the relayer who completed the relay on destination chain, or refunded back to the user,\n /// should no one complete the relay.\n function _takeBridgedUserAsset(address token, uint256 amount) internal returns (uint256 amountTaken) {\n if (token == NATIVE_GAS_TOKEN) {\n // For the native gas token, we just need to check that the supplied msg.value is correct.\n // Supplied `msg.value` is already in FastBridgeV2 custody.\n if (amount != msg.value) revert MsgValueIncorrect();\n amountTaken = msg.value;\n } else {\n // For ERC20s, token is explicitly transferred from the user to FastBridgeV2.\n // We don't allow non-zero `msg.value` to avoid extra funds from being stuck in FastBridgeV2.\n if (msg.value != 0) revert MsgValueIncorrect();\n // Throw an explicit error if the provided token address is not a contract\n if (token.code.length == 0) revert TokenNotContract();\n amountTaken = IERC20(token).balanceOf(address(this));\n IERC20(token).safeTransferFrom(msg.sender, address(this), amount);\n // Use the balance difference as the amount taken in case of fee on transfer tokens.\n amountTaken = IERC20(token).balanceOf(address(this)) - amountTaken;\n }\n }\n\n /// @notice Calls the Recipient's hook function with the specified zapData and performs\n /// all the necessary checks for the returned value.\n function _triggerZapWithChecks(address recipient, address token, uint256 amount, bytes calldata zapData) internal {\n // This will bubble any revert messages from the hook function\n bytes memory returnData = Address.functionCallWithValue({\n target: recipient,\n data: abi.encodeCall(IZapRecipient.zap, (token, amount, zapData)),\n // Note: see `relay()` for reasoning behind passing msg.value\n value: msg.value\n });\n // Explicit revert if no return data at all\n if (returnData.length == 0) revert RecipientNoReturnValue();\n // Check that exactly a single return value was returned\n if (returnData.length != 32) revert RecipientIncorrectReturnValue();\n // Return value should be abi-encoded hook function selector\n if (bytes32(returnData) != bytes32(IZapRecipient.zap.selector)) {\n revert RecipientIncorrectReturnValue();\n }\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint56(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint56).max but\n /// proof.timestamp \u003c type(uint56).max via unchecked statement\n /// @param proofBlockTimestamp The bridge proof block timestamp\n /// @return delta Time delta since proof submitted\n function _timeSince(uint56 proofBlockTimestamp) internal view returns (uint256 delta) {\n unchecked {\n delta = uint56(block.timestamp) - proofBlockTimestamp;\n }\n }\n\n /// @notice Performs all the necessary checks for a bridge to happen.\n /// @dev There's no good way to refactor this function to reduce cyclomatic complexity due to\n /// the number of checks that need to be performed, so we skip the code-complexity rule here.\n // solhint-disable-next-line code-complexity\n function _validateBridgeParams(\n BridgeParams memory params,\n BridgeParamsV2 memory paramsV2,\n int256 exclusivityEndTime\n )\n internal\n view\n {\n // Check V1 (legacy) params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.sender == address(0) || params.to == address(0)) revert ZeroAddress();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n // Check V2 params\n if (paramsV2.zapData.length \u003e MAX_ZAP_DATA_LENGTH) revert ZapDataLengthAboveMax();\n if (paramsV2.zapNative != 0 \u0026\u0026 params.destToken == NATIVE_GAS_TOKEN) {\n revert ZapNativeNotSupported();\n }\n // exclusivityEndTime must be in range [0 .. params.deadline]\n if (exclusivityEndTime \u003c 0 || exclusivityEndTime \u003e int256(params.deadline)) {\n revert ExclusivityParamsIncorrect();\n }\n }\n\n /// @notice Performs all the necessary checks for a relay to happen.\n function _validateRelayParams(bytes calldata request, bytes32 transactionId, address relayer) internal view {\n if (relayer == address(0)) revert ZeroAddress();\n // Check if the transaction has already been relayed\n if (bridgeRelays(transactionId)) revert TransactionRelayed();\n if (request.destChainId() != block.chainid) revert ChainIncorrect();\n // Check the deadline for relay to happen\n if (block.timestamp \u003e request.deadline()) revert DeadlineExceeded();\n // Check the exclusivity period, if it is still ongoing\n address exclRelayer = request.exclusivityRelayer();\n if (exclRelayer != address(0) \u0026\u0026 exclRelayer != relayer \u0026\u0026 block.timestamp \u003c= request.exclusivityEndTime()) {\n revert ExclusivityPeriodNotPassed();\n }\n }\n}\n","language":"Solidity","languageVersion":"0.8.24","compilerVersion":"0.8.24","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"49702:11496:0:-:0;;;;;;;;;;;;;;;-1:-1:-1;;;49702:11496:0;;;;;;;;;;;;;;;;;","srcMapRuntime":"49702:11496:0:-:0;;;;;;;;","abiDefinition":[{"inputs":[],"name":"BridgeTransactionV2__InvalidEncodedTx","type":"error"},{"inputs":[{"internalType":"uint16","name":"version","type":"uint16"}],"name":"BridgeTransactionV2__UnsupportedVersion","type":"error"}],"userDoc":{"kind":"user","methods":{},"version":1},"developerDoc":{"kind":"dev","methods":{},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[],\"name\":\"BridgeTransactionV2__InvalidEncodedTx\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint16\",\"name\":\"version\",\"type\":\"uint16\"}],\"name\":\"BridgeTransactionV2__UnsupportedVersion\",\"type\":\"error\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeV2.sol\":\"BridgeTransactionV2Lib\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeV2.sol\":{\"keccak256\":\"0x5069b55ca07f21bfe30b2a43c18a18318c8af9c181b2dcb07c290825efd70f34\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://273dc020a49d08e50126bbea0d7f783f79d08c702f2fdbc560618d24af308acc\",\"dweb:/ipfs/QmXJ2UVzFc8EPB74RT4CXQPC4xw66jt4T13poyfyd3UERh\"]}},\"version\":1}"},"hashes":{}},"solidity/FastBridgeV2.sol:Context":{"code":"0x","runtime-code":"0x","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.24 ^0.8.20 ^0.8.4;\n\n// contracts/interfaces/IAdmin.sol\n\ninterface IAdmin {\n // ============ Events ============\n\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n event ChainGasAmountUpdated(uint256 oldChainGasAmount, uint256 newChainGasAmount);\n\n // ============ Methods ============\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n\n function setChainGasAmount(uint256 newChainGasAmount) external;\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IFastBridgeV2Errors.sol\n\ninterface IFastBridgeV2Errors {\n error AmountIncorrect();\n error ChainIncorrect();\n error ExclusivityParamsIncorrect();\n error MsgValueIncorrect();\n error SenderIncorrect();\n error StatusIncorrect();\n error TokenNotContract();\n error ZapDataLengthAboveMax();\n error ZapNativeNotSupported();\n error ZeroAddress();\n\n error RecipientIncorrectReturnValue();\n error RecipientNoReturnValue();\n\n error DeadlineExceeded();\n error DeadlineNotExceeded();\n error DeadlineTooShort();\n error DisputePeriodNotPassed();\n error DisputePeriodPassed();\n error ExclusivityPeriodNotPassed();\n\n error TransactionRelayed();\n}\n\n// contracts/interfaces/IMulticallTarget.sol\n\n/// @notice Interface for a contract that can be called multiple times by the same caller. Inspired by MulticallV3:\n/// https://github.com/mds1/multicall/blob/master/src/Multicall3.sol\ninterface IMulticallTarget {\n struct Result {\n bool success;\n bytes returnData;\n }\n\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external;\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results);\n}\n\n// contracts/interfaces/IZapRecipient.sol\n\ninterface IZapRecipient {\n function zap(address token, uint256 amount, bytes memory zapData) external payable returns (bytes4);\n}\n\n// contracts/libs/Errors.sol\n\nerror DeadlineExceeded();\nerror DeadlineNotExceeded();\nerror DeadlineTooShort();\nerror InsufficientOutputAmount();\n\nerror MsgValueIncorrect();\nerror PoolNotFound();\nerror TokenAddressMismatch();\nerror TokenNotContract();\nerror TokenNotETH();\nerror TokensIdentical();\n\nerror ChainIncorrect();\nerror AmountIncorrect();\nerror ZeroAddress();\n\nerror DisputePeriodNotPassed();\nerror DisputePeriodPassed();\nerror SenderIncorrect();\nerror StatusIncorrect();\nerror TransactionIdIncorrect();\nerror TransactionRelayed();\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// contracts/interfaces/IFastBridgeV2.sol\n\ninterface IFastBridgeV2 is IFastBridge {\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n struct BridgeTxDetails {\n BridgeStatus status;\n uint32 destChainId;\n uint56 proofBlockTimestamp;\n address proofRelayer;\n }\n\n struct BridgeRelay {\n uint48 blockNumber;\n uint48 blockTimestamp;\n address relayer;\n }\n\n /// @notice New params introduced in the FastBridgeV2.\n /// We are passing fields from the older BridgeParams struct outside of this struct\n /// for backwards compatibility.\n /// Note: quoteRelayer and quoteExclusivitySeconds are either both zero (indicating no exclusivity)\n /// or both non-zero (indicating exclusivity for the given period).\n /// Note: zapNative \u003e 0 can NOT be used with destToken = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE (native token)\n /// @param quoteRelayer Relayer that provided the quote for the transaction\n /// @param quoteExclusivitySeconds Period of time the quote relayer is guaranteed exclusivity after user's deposit\n /// @param quoteId Unique quote identifier used for tracking the quote\n /// @param zapNative ETH value to send to the recipient (if any)\n /// @param zapData Parameters for the Zap to the destination recipient (if any)\n struct BridgeParamsV2 {\n address quoteRelayer;\n int256 quoteExclusivitySeconds;\n bytes quoteId;\n uint256 zapNative;\n bytes zapData;\n }\n\n /// @notice Updated bridge transaction struct to include parameters introduced in FastBridgeV2.\n /// Note: only `exclusivityRelayer` can fill such a transaction until `exclusivityEndTime`.\n struct BridgeTransactionV2 {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n // Note: sendChainGas flag from V1 is deprecated\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n address exclusivityRelayer;\n uint256 exclusivityEndTime;\n uint256 zapNative; // ETH value to send to the recipient (if any)\n bytes zapData; // data to pass for the Zap action (if any)\n }\n\n event BridgeQuoteDetails(bytes32 indexed transactionId, bytes quoteId);\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability\n /// to provide temporary exclusivity fill rights for the quote relayer.\n /// @param params The parameters required to bridge\n /// @param paramsV2 The parameters for exclusivity fill rights (optional, can be left empty)\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function relay(bytes memory request, address relayer) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param transactionId The transaction id associated with the encoded bridge transaction to prove\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital.\n /// @notice Can only send funds to the relayer address on the proof.\n /// @param request The encoded bridge transaction to claim on origin chain\n function claim(bytes memory request) external;\n /// @notice Checks if a transaction has been relayed\n /// @param transactionId The ID of the transaction to check\n /// @return True if the transaction has been relayed, false otherwise\n function bridgeRelays(bytes32 transactionId) external view returns (bool);\n\n /// @notice Returns the status of a bridge transaction\n /// @param transactionId The ID of the bridge transaction\n /// @return BridgeStatus Status of the bridge transaction\n function bridgeStatuses(bytes32 transactionId) external view returns (BridgeStatus);\n\n /// @notice Returns the timestamp and relayer of a bridge proof\n /// @param transactionId The ID of the bridge transaction\n /// @return timestamp The timestamp of the bridge proof\n /// @return relayer The relayer address of the bridge proof\n function bridgeProofs(bytes32 transactionId) external view returns (uint96 timestamp, address relayer);\n\n /// @notice Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\n /// @param request The bridge request to decode\n function getBridgeTransactionV2(bytes memory request) external view returns (BridgeTransactionV2 memory);\n}\n\n// contracts/utils/MulticallTarget.sol\n\n// solhint-disable avoid-low-level-calls\n/// @notice Template for a contract that supports batched calls (preserving the msg.sender).\n/// Only calls with zero msg.value could be batched.\nabstract contract MulticallTarget is IMulticallTarget {\n error MulticallTarget__UndeterminedRevert();\n\n /// @notice Perform a batched call to this contract, preserving the msg.sender.\n /// The return data from each call is discarded.\n /// @dev The method is non-payable, so only calls with `msg.value == 0` could be batched.\n /// It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag.\n /// Otherwise, the whole batch call will be reverted with the original revert reason.\n /// @param data List of abi-encoded calldata for the calls to perform.\n /// @param ignoreReverts Whether to ignore the revert errors from the calls.\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external {\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\n if (!success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(result);\n }\n }\n }\n\n /// @notice Perform a batched call to this contract, preserving the msg.sender.\n /// The return data from each call is preserved.\n /// @dev The method is non-payable, so only calls with `msg.value == 0` could be batched.\n /// It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag.\n /// Otherwise, the whole batch call will be reverted with the original revert reason.\n /// @param data List of abi-encoded calldata for the calls to perform.\n /// @param ignoreReverts Whether to ignore the revert errors from the calls.\n /// @return results List of results from the calls: `(success, returnData)`.\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results)\n {\n results = new Result[](data.length);\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (results[i].success, results[i].returnData) = address(this).delegatecall(data[i]);\n if (!results[i].success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(results[i].returnData);\n }\n }\n }\n\n /// @dev Bubbles the revert message from the underlying call.\n /// Note: preserves the same custom error or revert string, if one was used.\n /// Source: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v5.0.2/contracts/utils/Address.sol#L143-L158\n function _bubbleRevert(bytes memory returnData) internal pure {\n // Look for revert reason and bubble it up if present\n if (returnData.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n // solhint-disable-next-line no-inline-assembly\n assembly {\n let returndata_size := mload(returnData)\n revert(add(32, returnData), returndata_size)\n }\n } else {\n revert MulticallTarget__UndeterminedRevert();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// contracts/libs/BridgeTransactionV2.sol\n\n// solhint-disable no-inline-assembly\nlibrary BridgeTransactionV2Lib {\n uint16 internal constant VERSION = 2;\n\n // Offsets of the fields in the packed BridgeTransactionV2 struct\n // uint16 version [000 .. 002)\n // uint32 originChainId [002 .. 006)\n // uint32 destChainId [006 .. 010)\n // address originSender [010 .. 030)\n // address destRecipient [030 .. 050)\n // address originToken [050 .. 070)\n // address destToken [070 .. 090)\n // uint256 originAmount [090 .. 122)\n // uint256 destAmount [122 .. 154)\n // uint256 originFeeAmount [154 .. 186)\n // uint256 deadline [186 .. 218)\n // uint256 nonce [218 .. 250)\n // address exclusivityRelayer [250 .. 270)\n // uint256 exclusivityEndTime [270 .. 302)\n // uint256 zapNative [302 .. 334)\n // bytes zapData [334 .. ***)\n\n // forgefmt: disable-start\n uint256 private constant OFFSET_ORIGIN_CHAIN_ID = 2;\n uint256 private constant OFFSET_DEST_CHAIN_ID = 6;\n uint256 private constant OFFSET_ORIGIN_SENDER = 10;\n uint256 private constant OFFSET_DEST_RECIPIENT = 30;\n uint256 private constant OFFSET_ORIGIN_TOKEN = 50;\n uint256 private constant OFFSET_DEST_TOKEN = 70;\n uint256 private constant OFFSET_ORIGIN_AMOUNT = 90;\n uint256 private constant OFFSET_DEST_AMOUNT = 122;\n uint256 private constant OFFSET_ORIGIN_FEE_AMOUNT = 154;\n uint256 private constant OFFSET_DEADLINE = 186;\n uint256 private constant OFFSET_NONCE = 218;\n uint256 private constant OFFSET_EXCLUSIVITY_RELAYER = 250;\n uint256 private constant OFFSET_EXCLUSIVITY_END_TIME = 270;\n uint256 private constant OFFSET_ZAP_NATIVE = 302;\n uint256 private constant OFFSET_ZAP_DATA = 334;\n // forgefmt: disable-end\n\n error BridgeTransactionV2__InvalidEncodedTx();\n error BridgeTransactionV2__UnsupportedVersion(uint16 version);\n\n /// @notice Validates the encoded transaction to be a tightly packed encoded payload for BridgeTransactionV2.\n /// @dev Checks the minimum length and the version, use this function before decoding any of the fields.\n function validateV2(bytes calldata encodedTx) internal pure {\n // Check the minimum length: must at least include all static fields.\n if (encodedTx.length \u003c OFFSET_ZAP_DATA) revert BridgeTransactionV2__InvalidEncodedTx();\n // Once we validated the length, we can be sure that the version field is present.\n uint16 version_ = version(encodedTx);\n if (version_ != VERSION) revert BridgeTransactionV2__UnsupportedVersion(version_);\n }\n\n /// @notice Encodes the BridgeTransactionV2 struct by tightly packing the fields.\n /// @dev `abi.decode` will not work as a result of the tightly packed fields. Use `decodeV2` to decode instead.\n function encodeV2(IFastBridgeV2.BridgeTransactionV2 memory bridgeTx) internal pure returns (bytes memory) {\n // We split the encoding into two parts to avoid stack-too-deep error\n bytes memory firstPart = abi.encodePacked(\n VERSION,\n bridgeTx.originChainId,\n bridgeTx.destChainId,\n bridgeTx.originSender,\n bridgeTx.destRecipient,\n bridgeTx.originToken,\n bridgeTx.destToken,\n bridgeTx.originAmount\n );\n return abi.encodePacked(\n firstPart,\n bridgeTx.destAmount,\n bridgeTx.originFeeAmount,\n // Note: we skip the deprecated `sendChainGas` flag, which was present in BridgeTransaction V1\n bridgeTx.deadline,\n bridgeTx.nonce,\n // New V2 fields: exclusivity\n bridgeTx.exclusivityRelayer,\n bridgeTx.exclusivityEndTime,\n // New V2 fields: Zap\n bridgeTx.zapNative,\n bridgeTx.zapData\n );\n }\n\n /// @notice Decodes the BridgeTransactionV2 struct from the encoded transaction.\n /// @dev Encoded BridgeTransactionV2 struct must be tightly packed.\n /// Use `validateV2` before decoding to ensure the encoded transaction is valid.\n function decodeV2(bytes calldata encodedTx)\n internal\n pure\n returns (IFastBridgeV2.BridgeTransactionV2 memory bridgeTx)\n {\n bridgeTx.originChainId = originChainId(encodedTx);\n bridgeTx.destChainId = destChainId(encodedTx);\n bridgeTx.originSender = originSender(encodedTx);\n bridgeTx.destRecipient = destRecipient(encodedTx);\n bridgeTx.originToken = originToken(encodedTx);\n bridgeTx.destToken = destToken(encodedTx);\n bridgeTx.originAmount = originAmount(encodedTx);\n bridgeTx.destAmount = destAmount(encodedTx);\n bridgeTx.originFeeAmount = originFeeAmount(encodedTx);\n bridgeTx.deadline = deadline(encodedTx);\n bridgeTx.nonce = nonce(encodedTx);\n bridgeTx.exclusivityRelayer = exclusivityRelayer(encodedTx);\n bridgeTx.exclusivityEndTime = exclusivityEndTime(encodedTx);\n bridgeTx.zapNative = zapNative(encodedTx);\n bridgeTx.zapData = zapData(encodedTx);\n }\n\n /// @notice Extracts the version from the encoded transaction.\n function version(bytes calldata encodedTx) internal pure returns (uint16 version_) {\n // Load 32 bytes from the start and shift it 240 bits to the right to get the highest 16 bits.\n assembly {\n version_ := shr(240, calldataload(encodedTx.offset))\n }\n }\n\n /// @notice Extracts the origin chain ID from the encoded transaction.\n function originChainId(bytes calldata encodedTx) internal pure returns (uint32 originChainId_) {\n // Load 32 bytes from the offset and shift it 224 bits to the right to get the highest 32 bits.\n assembly {\n originChainId_ := shr(224, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_CHAIN_ID)))\n }\n }\n\n /// @notice Extracts the destination chain ID from the encoded transaction.\n function destChainId(bytes calldata encodedTx) internal pure returns (uint32 destChainId_) {\n // Load 32 bytes from the offset and shift it 224 bits to the right to get the highest 32 bits.\n assembly {\n destChainId_ := shr(224, calldataload(add(encodedTx.offset, OFFSET_DEST_CHAIN_ID)))\n }\n }\n\n /// @notice Extracts the origin sender from the encoded transaction.\n function originSender(bytes calldata encodedTx) internal pure returns (address originSender_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n originSender_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_SENDER)))\n }\n }\n\n /// @notice Extracts the destination recipient from the encoded transaction.\n function destRecipient(bytes calldata encodedTx) internal pure returns (address destRecipient_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n destRecipient_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_DEST_RECIPIENT)))\n }\n }\n\n /// @notice Extracts the origin token from the encoded transaction.\n function originToken(bytes calldata encodedTx) internal pure returns (address originToken_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n originToken_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_TOKEN)))\n }\n }\n\n /// @notice Extracts the destination token from the encoded transaction.\n function destToken(bytes calldata encodedTx) internal pure returns (address destToken_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n destToken_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_DEST_TOKEN)))\n }\n }\n\n /// @notice Extracts the origin amount from the encoded transaction.\n function originAmount(bytes calldata encodedTx) internal pure returns (uint256 originAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n originAmount_ := calldataload(add(encodedTx.offset, OFFSET_ORIGIN_AMOUNT))\n }\n }\n\n /// @notice Extracts the destination amount from the encoded transaction.\n function destAmount(bytes calldata encodedTx) internal pure returns (uint256 destAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n destAmount_ := calldataload(add(encodedTx.offset, OFFSET_DEST_AMOUNT))\n }\n }\n\n /// @notice Extracts the origin fee amount from the encoded transaction.\n function originFeeAmount(bytes calldata encodedTx) internal pure returns (uint256 originFeeAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n originFeeAmount_ := calldataload(add(encodedTx.offset, OFFSET_ORIGIN_FEE_AMOUNT))\n }\n }\n\n /// @notice Extracts the deadline from the encoded transaction.\n function deadline(bytes calldata encodedTx) internal pure returns (uint256 deadline_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n deadline_ := calldataload(add(encodedTx.offset, OFFSET_DEADLINE))\n }\n }\n\n /// @notice Extracts the nonce from the encoded transaction.\n function nonce(bytes calldata encodedTx) internal pure returns (uint256 nonce_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n nonce_ := calldataload(add(encodedTx.offset, OFFSET_NONCE))\n }\n }\n\n /// @notice Extracts the exclusivity relayer from the encoded transaction.\n function exclusivityRelayer(bytes calldata encodedTx) internal pure returns (address exclusivityRelayer_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n exclusivityRelayer_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_EXCLUSIVITY_RELAYER)))\n }\n }\n\n /// @notice Extracts the exclusivity end time from the encoded transaction.\n function exclusivityEndTime(bytes calldata encodedTx) internal pure returns (uint256 exclusivityEndTime_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n exclusivityEndTime_ := calldataload(add(encodedTx.offset, OFFSET_EXCLUSIVITY_END_TIME))\n }\n }\n\n /// @notice Extracts the Zap's native value from the encoded transaction.\n function zapNative(bytes calldata encodedTx) internal pure returns (uint256 zapNative_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n zapNative_ := calldataload(add(encodedTx.offset, OFFSET_ZAP_NATIVE))\n }\n }\n\n /// @notice Extracts the Zap's data from the encoded transaction.\n function zapData(bytes calldata encodedTx) internal pure returns (bytes calldata zapData_) {\n zapData_ = encodedTx[OFFSET_ZAP_DATA:];\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// contracts/libs/UniversalToken.sol\n\nlibrary UniversalTokenLib {\n using SafeERC20 for IERC20;\n\n address internal constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Transfers tokens to the given account. Reverts if transfer is not successful.\n /// @dev This might trigger fallback, if ETH is transferred to the contract.\n /// Make sure this can not lead to reentrancy attacks.\n function universalTransfer(address token, address to, uint256 value) internal {\n // Don't do anything, if need to send tokens to this address\n if (to == address(this)) return;\n // Don't do anything, if trying to send zero value\n if (value == 0) return;\n if (token == ETH_ADDRESS) {\n /// @dev Note: this can potentially lead to executing code in `to`.\n // solhint-disable-next-line avoid-low-level-calls\n (bool success,) = to.call{value: value}(\"\");\n require(success, \"ETH transfer failed\");\n } else {\n IERC20(token).safeTransfer(to, value);\n }\n }\n\n /// @notice Issues an infinite allowance to the spender, if the current allowance is insufficient\n /// to spend the given amount.\n function universalApproveInfinity(address token, address spender, uint256 amountToSpend) internal {\n // ETH Chad doesn't require your approval\n if (token == ETH_ADDRESS) return;\n // No-op if allowance is already sufficient\n uint256 allowance = IERC20(token).allowance(address(this), spender);\n if (allowance \u003e= amountToSpend) return;\n // Otherwise, reset approval to 0 and set to max allowance\n if (allowance \u003e 0) IERC20(token).safeDecreaseAllowance(spender, allowance);\n IERC20(token).safeIncreaseAllowance(spender, type(uint256).max);\n }\n\n /// @notice Returns the balance of the given token (or native ETH) for the given account.\n function universalBalanceOf(address token, address account) internal view returns (uint256) {\n if (token == ETH_ADDRESS) {\n return account.balance;\n } else {\n return IERC20(token).balanceOf(account);\n }\n }\n\n /// @dev Checks that token is a contract and not ETH_ADDRESS.\n function assertIsContract(address token) internal view {\n // Check that ETH_ADDRESS was not used (in case this is a predeploy on any of the chains)\n if (token == UniversalTokenLib.ETH_ADDRESS) revert TokenNotContract();\n // Check that token is not an EOA\n if (token.code.length == 0) revert TokenNotContract();\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/Admin.sol\n\ncontract Admin is IAdmin, AccessControlEnumerable {\n using UniversalTokenLib for address;\n\n bytes32 public constant RELAYER_ROLE = keccak256(\"RELAYER_ROLE\");\n bytes32 public constant REFUNDER_ROLE = keccak256(\"REFUNDER_ROLE\");\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n uint256 public constant FEE_BPS = 1e6;\n uint256 public constant FEE_RATE_MAX = 0.01e6; // max 1% on origin amount\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Chain gas amount to forward as rebate if requested\n uint256 public chainGasAmount;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n }\n\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n require(newFeeRate \u003c= FEE_RATE_MAX, \"newFeeRate \u003e max\");\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n token.universalTransfer(recipient, feeAmount);\n emit FeesSwept(token, recipient, feeAmount);\n }\n\n function setChainGasAmount(uint256 newChainGasAmount) external onlyRole(GOVERNOR_ROLE) {\n uint256 oldChainGasAmount = chainGasAmount;\n chainGasAmount = newChainGasAmount;\n emit ChainGasAmountUpdated(oldChainGasAmount, newChainGasAmount);\n }\n}\n\n// contracts/FastBridgeV2.sol\n\n/// @notice FastBridgeV2 is a contract for bridging tokens across chains.\ncontract FastBridgeV2 is Admin, MulticallTarget, IFastBridgeV2, IFastBridgeV2Errors {\n using BridgeTransactionV2Lib for bytes;\n using SafeERC20 for IERC20;\n\n /// @notice Address reserved for native gas token (ETH on Ethereum and most L2s, AVAX on Avalanche, etc)\n address public constant NATIVE_GAS_TOKEN = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Delay for a transaction after which it could be permisionlessly refunded\n uint256 public constant REFUND_DELAY = 7 days;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n /// @notice Maximum length of accepted zapData\n uint256 public constant MAX_ZAP_DATA_LENGTH = 2 ** 16 - 1;\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeTxDetails) public bridgeTxDetails;\n /// @notice Relay details on destination chain\n mapping(bytes32 =\u003e BridgeRelay) public bridgeRelayDetails;\n /// @notice Unique bridge nonces tracked per originSender\n mapping(address =\u003e uint256) public senderNonces;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Replaced by senderNonces\n uint256 public immutable nonce = 0;\n /// @notice the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n bridge({\n params: params,\n paramsV2: BridgeParamsV2({\n quoteRelayer: address(0),\n quoteExclusivitySeconds: 0,\n quoteId: bytes(\"\"),\n zapNative: 0,\n zapData: bytes(\"\")\n })\n });\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes calldata request) external payable {\n // relay override will validate the request\n relay({request: request, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes calldata request, bytes32 destTxHash) external {\n request.validateV2();\n prove({transactionId: keccak256(request), destTxHash: destTxHash, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridgeV2\n function claim(bytes calldata request) external {\n // claim override will validate the request\n claim({request: request, to: address(0)});\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Aggregate the read operations from the same storage slot\n address disputedRelayer = $.proofRelayer;\n BridgeStatus status = $.status;\n uint56 proofBlockTimestamp = $.proofBlockTimestamp;\n // Can only dispute a RELAYER_PROVED transaction within the dispute period\n if (status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(proofBlockTimestamp) \u003e DISPUTE_PERIOD) {\n revert DisputePeriodPassed();\n }\n // Update status to REQUESTED and delete the disputed proof details\n // Note: these are storage writes\n $.status = BridgeStatus.REQUESTED;\n $.proofRelayer = address(0);\n $.proofBlockTimestamp = 0;\n\n emit BridgeProofDisputed(transactionId, disputedRelayer);\n }\n\n /// @inheritdoc IFastBridge\n function refund(bytes calldata request) external {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Can only refund a REQUESTED transaction after its deadline expires\n if ($.status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n uint256 deadline = request.deadline();\n // Permissionless refund is only allowed after REFUND_DELAY on top of the deadline\n if (!hasRole(REFUNDER_ROLE, msg.sender)) deadline += REFUND_DELAY;\n if (block.timestamp \u003c= deadline) revert DeadlineNotExceeded();\n // Update status to REFUNDED and return the full amount (collateral + protocol fees) to the original sender.\n // The protocol fees are only updated when the transaction is claimed, so we don't need to update them here.\n // Note: this is a storage write\n $.status = BridgeStatus.REFUNDED;\n\n address to = request.originSender();\n address token = request.originToken();\n uint256 amount = request.originAmount() + request.originFeeAmount();\n // Emit the event before any external calls\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n // Complete the user refund as the last transaction action\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(to), amount);\n } else {\n IERC20(token).safeTransfer(to, amount);\n }\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // The correct relayer can only claim a RELAYER_PROVED transaction after the dispute period\n if ($.status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if ($.proofRelayer != relayer) revert SenderIncorrect();\n return _timeSince($.proofBlockTimestamp) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n /// @dev This method is added to achieve backwards compatibility with decoding requests into V1 structs:\n /// - `zapNative` is partially reported as a zero/non-zero flag\n /// - `zapData` is ignored\n /// In order to process all kinds of requests use getBridgeTransactionV2 instead.\n function getBridgeTransaction(bytes calldata request) external view returns (BridgeTransaction memory) {\n // Try decoding into V2 struct first. This will revert if V1 struct is passed\n try this.getBridgeTransactionV2(request) returns (BridgeTransactionV2 memory txV2) {\n // Note: we entirely ignore the zapData field, as it was not present in V1\n return BridgeTransaction({\n originChainId: txV2.originChainId,\n destChainId: txV2.destChainId,\n originSender: txV2.originSender,\n destRecipient: txV2.destRecipient,\n originToken: txV2.originToken,\n destToken: txV2.destToken,\n originAmount: txV2.originAmount,\n destAmount: txV2.destAmount,\n originFeeAmount: txV2.originFeeAmount,\n sendChainGas: txV2.zapNative != 0,\n deadline: txV2.deadline,\n nonce: txV2.nonce\n });\n } catch {\n // Fallback to V1 struct\n return abi.decode(request, (BridgeTransaction));\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function getBridgeTransactionV2(bytes calldata request) external pure returns (BridgeTransactionV2 memory) {\n request.validateV2();\n return BridgeTransactionV2Lib.decodeV2(request);\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) public payable {\n int256 exclusivityEndTime = 0;\n // if relayer exclusivity is not intended for this bridge, set exclusivityEndTime to static zero\n // otherwise, set exclusivity to expire at the current block ts offset by quoteExclusivitySeconds\n if (paramsV2.quoteRelayer != address(0)) {\n exclusivityEndTime = int256(block.timestamp) + paramsV2.quoteExclusivitySeconds;\n }\n _validateBridgeParams(params, paramsV2, exclusivityEndTime);\n\n // transfer tokens to bridge contract\n /// @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _takeBridgedUserAsset(params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) {\n originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n }\n\n // set status to requested\n bytes memory request = BridgeTransactionV2Lib.encodeV2(\n BridgeTransactionV2({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n deadline: params.deadline,\n nonce: senderNonces[params.sender]++, // increment nonce on every bridge\n exclusivityRelayer: paramsV2.quoteRelayer,\n // We checked exclusivityEndTime to be in range [0 .. params.deadline] above, so can safely cast\n exclusivityEndTime: uint256(exclusivityEndTime),\n zapNative: paramsV2.zapNative,\n zapData: paramsV2.zapData\n })\n );\n bytes32 transactionId = keccak256(request);\n // Note: the tx status will be updated throughout the tx lifecycle, while destChainId is set once here\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n bridgeTxDetails[transactionId].destChainId = params.dstChainId;\n\n emit BridgeRequested({\n transactionId: transactionId,\n sender: params.sender,\n request: request,\n destChainId: params.dstChainId,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n sendChainGas: paramsV2.zapNative != 0\n });\n emit BridgeQuoteDetails(transactionId, paramsV2.quoteId);\n }\n\n /// @inheritdoc IFastBridgeV2\n function relay(bytes calldata request, address relayer) public payable {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n _validateRelayParams(request, transactionId, relayer);\n // mark bridge transaction as relayed\n bridgeRelayDetails[transactionId] =\n BridgeRelay({blockNumber: uint48(block.number), blockTimestamp: uint48(block.timestamp), relayer: relayer});\n\n // transfer tokens to recipient on destination chain and trigger Zap if requested\n address to = request.destRecipient();\n address token = request.destToken();\n uint256 amount = request.destAmount();\n uint256 zapNative = request.zapNative();\n\n // Emit the event before any external calls\n emit BridgeRelayed({\n transactionId: transactionId,\n relayer: relayer,\n to: to,\n originChainId: request.originChainId(),\n originToken: request.originToken(),\n destToken: token,\n originAmount: request.originAmount(),\n destAmount: amount,\n chainGasAmount: zapNative\n });\n\n // All state changes have been done at this point, can proceed to the external calls.\n // This follows the checks-effects-interactions pattern to mitigate potential reentrancy attacks.\n if (token == NATIVE_GAS_TOKEN) {\n // For the native gas token, additional zapNative is not allowed\n if (zapNative != 0) revert ZapNativeNotSupported();\n // Check that the correct msg.value was sent\n if (msg.value != amount) revert MsgValueIncorrect();\n // Don't do a native transfer yet: we will handle it alongside the Zap below\n } else {\n // For ERC20s, we check that the correct msg.value was sent\n if (msg.value != zapNative) revert MsgValueIncorrect();\n // We need to transfer the tokens from the Relayer to the recipient first before performing an\n // optional post-transfer Zap.\n IERC20(token).safeTransferFrom(msg.sender, to, amount);\n }\n // At this point we have done:\n // - Transferred the requested amount of ERC20 tokens to the recipient.\n // At this point we have confirmed:\n // - For ERC20s: msg.value matches the requested zapNative amount.\n // - For the native gas token: msg.value matches the requested destAmount.\n // Remaining optional things to do:\n // - Forward the full msg.value to the recipient (if non-zero).\n // - Trigger a Zap (if zapData is present).\n bytes calldata zapData = request.zapData();\n if (zapData.length != 0) {\n // Zap Data is present: Zap has been requested by the recipient. Trigger it forwarding the full msg.value.\n\n // Note: if token has a fee on transfers, the recipient will have received less than `amount`.\n // This is a very niche edge case and should be handled by the recipient contract.\n _triggerZapWithChecks({recipient: to, token: token, amount: amount, zapData: zapData});\n } else if (msg.value != 0) {\n // Zap Data is missing, but msg.value was sent. This could happen in two different cases:\n // - Relay with the native gas token is happening.\n // - Relay with ERC20 is happening, with a `zapNative \u003e 0` request.\n // In both cases, we need to transfer the full msg.value to the recipient.\n Address.sendValue(payable(to), msg.value);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) public onlyRole(RELAYER_ROLE) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n\n // Can only prove a REQUESTED transaction\n if ($.status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n // Update status to RELAYER_PROVED and store the proof details\n // Note: these are storage writes\n $.status = BridgeStatus.RELAYER_PROVED;\n $.proofBlockTimestamp = uint56(block.timestamp);\n $.proofRelayer = relayer;\n\n emit BridgeProofProvided(transactionId, relayer, destTxHash);\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes calldata request, address to) public {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Aggregate the read operations from the same storage slot\n address proofRelayer = $.proofRelayer;\n BridgeStatus status = $.status;\n uint56 proofBlockTimestamp = $.proofBlockTimestamp;\n\n // Can only claim a RELAYER_PROVED transaction after the dispute period\n if (status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(proofBlockTimestamp) \u003c= DISPUTE_PERIOD) {\n revert DisputePeriodNotPassed();\n }\n\n if (to == address(0)) {\n // Anyone could claim the funds to the proven relayer on their behalf\n to = proofRelayer;\n } else if (proofRelayer != msg.sender) {\n // Only the proven relayer could specify an address to claim the funds to\n revert SenderIncorrect();\n }\n\n // Update status to RELAYER_CLAIMED and transfer the origin collateral to the specified claim address\n // Note: this is a storage write\n $.status = BridgeStatus.RELAYER_CLAIMED;\n\n address token = request.originToken();\n uint256 amount = request.originAmount();\n // Update protocol fees if origin fee amount exists\n uint256 originFeeAmount = request.originFeeAmount();\n if (originFeeAmount \u003e 0) protocolFees[token] += originFeeAmount;\n // Emit the event before any external calls\n emit BridgeDepositClaimed(transactionId, proofRelayer, to, token, amount);\n // Complete the relayer claim as the last transaction action\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(to), amount);\n } else {\n IERC20(token).safeTransfer(to, amount);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeStatuses(bytes32 transactionId) public view returns (BridgeStatus status) {\n return bridgeTxDetails[transactionId].status;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeProofs(bytes32 transactionId) public view returns (uint96 timestamp, address relayer) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n\n timestamp = $.proofBlockTimestamp;\n relayer = $.proofRelayer;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeRelays(bytes32 transactionId) public view returns (bool) {\n // has this transactionId been relayed?\n return bridgeRelayDetails[transactionId].relayer != address(0);\n }\n\n /// @notice Takes the bridged asset from the user into FastBridgeV2 custody. It will be later\n /// claimed by the relayer who completed the relay on destination chain, or refunded back to the user,\n /// should no one complete the relay.\n function _takeBridgedUserAsset(address token, uint256 amount) internal returns (uint256 amountTaken) {\n if (token == NATIVE_GAS_TOKEN) {\n // For the native gas token, we just need to check that the supplied msg.value is correct.\n // Supplied `msg.value` is already in FastBridgeV2 custody.\n if (amount != msg.value) revert MsgValueIncorrect();\n amountTaken = msg.value;\n } else {\n // For ERC20s, token is explicitly transferred from the user to FastBridgeV2.\n // We don't allow non-zero `msg.value` to avoid extra funds from being stuck in FastBridgeV2.\n if (msg.value != 0) revert MsgValueIncorrect();\n // Throw an explicit error if the provided token address is not a contract\n if (token.code.length == 0) revert TokenNotContract();\n amountTaken = IERC20(token).balanceOf(address(this));\n IERC20(token).safeTransferFrom(msg.sender, address(this), amount);\n // Use the balance difference as the amount taken in case of fee on transfer tokens.\n amountTaken = IERC20(token).balanceOf(address(this)) - amountTaken;\n }\n }\n\n /// @notice Calls the Recipient's hook function with the specified zapData and performs\n /// all the necessary checks for the returned value.\n function _triggerZapWithChecks(address recipient, address token, uint256 amount, bytes calldata zapData) internal {\n // This will bubble any revert messages from the hook function\n bytes memory returnData = Address.functionCallWithValue({\n target: recipient,\n data: abi.encodeCall(IZapRecipient.zap, (token, amount, zapData)),\n // Note: see `relay()` for reasoning behind passing msg.value\n value: msg.value\n });\n // Explicit revert if no return data at all\n if (returnData.length == 0) revert RecipientNoReturnValue();\n // Check that exactly a single return value was returned\n if (returnData.length != 32) revert RecipientIncorrectReturnValue();\n // Return value should be abi-encoded hook function selector\n if (bytes32(returnData) != bytes32(IZapRecipient.zap.selector)) {\n revert RecipientIncorrectReturnValue();\n }\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint56(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint56).max but\n /// proof.timestamp \u003c type(uint56).max via unchecked statement\n /// @param proofBlockTimestamp The bridge proof block timestamp\n /// @return delta Time delta since proof submitted\n function _timeSince(uint56 proofBlockTimestamp) internal view returns (uint256 delta) {\n unchecked {\n delta = uint56(block.timestamp) - proofBlockTimestamp;\n }\n }\n\n /// @notice Performs all the necessary checks for a bridge to happen.\n /// @dev There's no good way to refactor this function to reduce cyclomatic complexity due to\n /// the number of checks that need to be performed, so we skip the code-complexity rule here.\n // solhint-disable-next-line code-complexity\n function _validateBridgeParams(\n BridgeParams memory params,\n BridgeParamsV2 memory paramsV2,\n int256 exclusivityEndTime\n )\n internal\n view\n {\n // Check V1 (legacy) params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.sender == address(0) || params.to == address(0)) revert ZeroAddress();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n // Check V2 params\n if (paramsV2.zapData.length \u003e MAX_ZAP_DATA_LENGTH) revert ZapDataLengthAboveMax();\n if (paramsV2.zapNative != 0 \u0026\u0026 params.destToken == NATIVE_GAS_TOKEN) {\n revert ZapNativeNotSupported();\n }\n // exclusivityEndTime must be in range [0 .. params.deadline]\n if (exclusivityEndTime \u003c 0 || exclusivityEndTime \u003e int256(params.deadline)) {\n revert ExclusivityParamsIncorrect();\n }\n }\n\n /// @notice Performs all the necessary checks for a relay to happen.\n function _validateRelayParams(bytes calldata request, bytes32 transactionId, address relayer) internal view {\n if (relayer == address(0)) revert ZeroAddress();\n // Check if the transaction has already been relayed\n if (bridgeRelays(transactionId)) revert TransactionRelayed();\n if (request.destChainId() != block.chainid) revert ChainIncorrect();\n // Check the deadline for relay to happen\n if (block.timestamp \u003e request.deadline()) revert DeadlineExceeded();\n // Check the exclusivity period, if it is still ongoing\n address exclRelayer = request.exclusivityRelayer();\n if (exclRelayer != address(0) \u0026\u0026 exclRelayer != relayer \u0026\u0026 block.timestamp \u003c= request.exclusivityEndTime()) {\n revert ExclusivityPeriodNotPassed();\n }\n }\n}\n","language":"Solidity","languageVersion":"0.8.24","compilerVersion":"0.8.24","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"","srcMapRuntime":"","abiDefinition":[],"userDoc":{"kind":"user","methods":{},"version":1},"developerDoc":{"details":"Provides information about the current execution context, including the sender of the transaction and its data. While these are generally available via msg.sender and msg.data, they should not be accessed in such a direct manner, since when dealing with meta-transactions the account sending and paying for execution may not be the actual sender (as far as an application is concerned). This contract is only required for intermediate, library-like contracts.","kind":"dev","methods":{},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[],\"devdoc\":{\"details\":\"Provides information about the current execution context, including the sender of the transaction and its data. While these are generally available via msg.sender and msg.data, they should not be accessed in such a direct manner, since when dealing with meta-transactions the account sending and paying for execution may not be the actual sender (as far as an application is concerned). This contract is only required for intermediate, library-like contracts.\",\"kind\":\"dev\",\"methods\":{},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeV2.sol\":\"Context\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeV2.sol\":{\"keccak256\":\"0x5069b55ca07f21bfe30b2a43c18a18318c8af9c181b2dcb07c290825efd70f34\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://273dc020a49d08e50126bbea0d7f783f79d08c702f2fdbc560618d24af308acc\",\"dweb:/ipfs/QmXJ2UVzFc8EPB74RT4CXQPC4xw66jt4T13poyfyd3UERh\"]}},\"version\":1}"},"hashes":{}},"solidity/FastBridgeV2.sol:ERC165":{"code":"0x","runtime-code":"0x","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.24 ^0.8.20 ^0.8.4;\n\n// contracts/interfaces/IAdmin.sol\n\ninterface IAdmin {\n // ============ Events ============\n\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n event ChainGasAmountUpdated(uint256 oldChainGasAmount, uint256 newChainGasAmount);\n\n // ============ Methods ============\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n\n function setChainGasAmount(uint256 newChainGasAmount) external;\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IFastBridgeV2Errors.sol\n\ninterface IFastBridgeV2Errors {\n error AmountIncorrect();\n error ChainIncorrect();\n error ExclusivityParamsIncorrect();\n error MsgValueIncorrect();\n error SenderIncorrect();\n error StatusIncorrect();\n error TokenNotContract();\n error ZapDataLengthAboveMax();\n error ZapNativeNotSupported();\n error ZeroAddress();\n\n error RecipientIncorrectReturnValue();\n error RecipientNoReturnValue();\n\n error DeadlineExceeded();\n error DeadlineNotExceeded();\n error DeadlineTooShort();\n error DisputePeriodNotPassed();\n error DisputePeriodPassed();\n error ExclusivityPeriodNotPassed();\n\n error TransactionRelayed();\n}\n\n// contracts/interfaces/IMulticallTarget.sol\n\n/// @notice Interface for a contract that can be called multiple times by the same caller. Inspired by MulticallV3:\n/// https://github.com/mds1/multicall/blob/master/src/Multicall3.sol\ninterface IMulticallTarget {\n struct Result {\n bool success;\n bytes returnData;\n }\n\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external;\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results);\n}\n\n// contracts/interfaces/IZapRecipient.sol\n\ninterface IZapRecipient {\n function zap(address token, uint256 amount, bytes memory zapData) external payable returns (bytes4);\n}\n\n// contracts/libs/Errors.sol\n\nerror DeadlineExceeded();\nerror DeadlineNotExceeded();\nerror DeadlineTooShort();\nerror InsufficientOutputAmount();\n\nerror MsgValueIncorrect();\nerror PoolNotFound();\nerror TokenAddressMismatch();\nerror TokenNotContract();\nerror TokenNotETH();\nerror TokensIdentical();\n\nerror ChainIncorrect();\nerror AmountIncorrect();\nerror ZeroAddress();\n\nerror DisputePeriodNotPassed();\nerror DisputePeriodPassed();\nerror SenderIncorrect();\nerror StatusIncorrect();\nerror TransactionIdIncorrect();\nerror TransactionRelayed();\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// contracts/interfaces/IFastBridgeV2.sol\n\ninterface IFastBridgeV2 is IFastBridge {\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n struct BridgeTxDetails {\n BridgeStatus status;\n uint32 destChainId;\n uint56 proofBlockTimestamp;\n address proofRelayer;\n }\n\n struct BridgeRelay {\n uint48 blockNumber;\n uint48 blockTimestamp;\n address relayer;\n }\n\n /// @notice New params introduced in the FastBridgeV2.\n /// We are passing fields from the older BridgeParams struct outside of this struct\n /// for backwards compatibility.\n /// Note: quoteRelayer and quoteExclusivitySeconds are either both zero (indicating no exclusivity)\n /// or both non-zero (indicating exclusivity for the given period).\n /// Note: zapNative \u003e 0 can NOT be used with destToken = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE (native token)\n /// @param quoteRelayer Relayer that provided the quote for the transaction\n /// @param quoteExclusivitySeconds Period of time the quote relayer is guaranteed exclusivity after user's deposit\n /// @param quoteId Unique quote identifier used for tracking the quote\n /// @param zapNative ETH value to send to the recipient (if any)\n /// @param zapData Parameters for the Zap to the destination recipient (if any)\n struct BridgeParamsV2 {\n address quoteRelayer;\n int256 quoteExclusivitySeconds;\n bytes quoteId;\n uint256 zapNative;\n bytes zapData;\n }\n\n /// @notice Updated bridge transaction struct to include parameters introduced in FastBridgeV2.\n /// Note: only `exclusivityRelayer` can fill such a transaction until `exclusivityEndTime`.\n struct BridgeTransactionV2 {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n // Note: sendChainGas flag from V1 is deprecated\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n address exclusivityRelayer;\n uint256 exclusivityEndTime;\n uint256 zapNative; // ETH value to send to the recipient (if any)\n bytes zapData; // data to pass for the Zap action (if any)\n }\n\n event BridgeQuoteDetails(bytes32 indexed transactionId, bytes quoteId);\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability\n /// to provide temporary exclusivity fill rights for the quote relayer.\n /// @param params The parameters required to bridge\n /// @param paramsV2 The parameters for exclusivity fill rights (optional, can be left empty)\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function relay(bytes memory request, address relayer) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param transactionId The transaction id associated with the encoded bridge transaction to prove\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital.\n /// @notice Can only send funds to the relayer address on the proof.\n /// @param request The encoded bridge transaction to claim on origin chain\n function claim(bytes memory request) external;\n /// @notice Checks if a transaction has been relayed\n /// @param transactionId The ID of the transaction to check\n /// @return True if the transaction has been relayed, false otherwise\n function bridgeRelays(bytes32 transactionId) external view returns (bool);\n\n /// @notice Returns the status of a bridge transaction\n /// @param transactionId The ID of the bridge transaction\n /// @return BridgeStatus Status of the bridge transaction\n function bridgeStatuses(bytes32 transactionId) external view returns (BridgeStatus);\n\n /// @notice Returns the timestamp and relayer of a bridge proof\n /// @param transactionId The ID of the bridge transaction\n /// @return timestamp The timestamp of the bridge proof\n /// @return relayer The relayer address of the bridge proof\n function bridgeProofs(bytes32 transactionId) external view returns (uint96 timestamp, address relayer);\n\n /// @notice Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\n /// @param request The bridge request to decode\n function getBridgeTransactionV2(bytes memory request) external view returns (BridgeTransactionV2 memory);\n}\n\n// contracts/utils/MulticallTarget.sol\n\n// solhint-disable avoid-low-level-calls\n/// @notice Template for a contract that supports batched calls (preserving the msg.sender).\n/// Only calls with zero msg.value could be batched.\nabstract contract MulticallTarget is IMulticallTarget {\n error MulticallTarget__UndeterminedRevert();\n\n /// @notice Perform a batched call to this contract, preserving the msg.sender.\n /// The return data from each call is discarded.\n /// @dev The method is non-payable, so only calls with `msg.value == 0` could be batched.\n /// It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag.\n /// Otherwise, the whole batch call will be reverted with the original revert reason.\n /// @param data List of abi-encoded calldata for the calls to perform.\n /// @param ignoreReverts Whether to ignore the revert errors from the calls.\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external {\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\n if (!success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(result);\n }\n }\n }\n\n /// @notice Perform a batched call to this contract, preserving the msg.sender.\n /// The return data from each call is preserved.\n /// @dev The method is non-payable, so only calls with `msg.value == 0` could be batched.\n /// It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag.\n /// Otherwise, the whole batch call will be reverted with the original revert reason.\n /// @param data List of abi-encoded calldata for the calls to perform.\n /// @param ignoreReverts Whether to ignore the revert errors from the calls.\n /// @return results List of results from the calls: `(success, returnData)`.\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results)\n {\n results = new Result[](data.length);\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (results[i].success, results[i].returnData) = address(this).delegatecall(data[i]);\n if (!results[i].success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(results[i].returnData);\n }\n }\n }\n\n /// @dev Bubbles the revert message from the underlying call.\n /// Note: preserves the same custom error or revert string, if one was used.\n /// Source: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v5.0.2/contracts/utils/Address.sol#L143-L158\n function _bubbleRevert(bytes memory returnData) internal pure {\n // Look for revert reason and bubble it up if present\n if (returnData.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n // solhint-disable-next-line no-inline-assembly\n assembly {\n let returndata_size := mload(returnData)\n revert(add(32, returnData), returndata_size)\n }\n } else {\n revert MulticallTarget__UndeterminedRevert();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// contracts/libs/BridgeTransactionV2.sol\n\n// solhint-disable no-inline-assembly\nlibrary BridgeTransactionV2Lib {\n uint16 internal constant VERSION = 2;\n\n // Offsets of the fields in the packed BridgeTransactionV2 struct\n // uint16 version [000 .. 002)\n // uint32 originChainId [002 .. 006)\n // uint32 destChainId [006 .. 010)\n // address originSender [010 .. 030)\n // address destRecipient [030 .. 050)\n // address originToken [050 .. 070)\n // address destToken [070 .. 090)\n // uint256 originAmount [090 .. 122)\n // uint256 destAmount [122 .. 154)\n // uint256 originFeeAmount [154 .. 186)\n // uint256 deadline [186 .. 218)\n // uint256 nonce [218 .. 250)\n // address exclusivityRelayer [250 .. 270)\n // uint256 exclusivityEndTime [270 .. 302)\n // uint256 zapNative [302 .. 334)\n // bytes zapData [334 .. ***)\n\n // forgefmt: disable-start\n uint256 private constant OFFSET_ORIGIN_CHAIN_ID = 2;\n uint256 private constant OFFSET_DEST_CHAIN_ID = 6;\n uint256 private constant OFFSET_ORIGIN_SENDER = 10;\n uint256 private constant OFFSET_DEST_RECIPIENT = 30;\n uint256 private constant OFFSET_ORIGIN_TOKEN = 50;\n uint256 private constant OFFSET_DEST_TOKEN = 70;\n uint256 private constant OFFSET_ORIGIN_AMOUNT = 90;\n uint256 private constant OFFSET_DEST_AMOUNT = 122;\n uint256 private constant OFFSET_ORIGIN_FEE_AMOUNT = 154;\n uint256 private constant OFFSET_DEADLINE = 186;\n uint256 private constant OFFSET_NONCE = 218;\n uint256 private constant OFFSET_EXCLUSIVITY_RELAYER = 250;\n uint256 private constant OFFSET_EXCLUSIVITY_END_TIME = 270;\n uint256 private constant OFFSET_ZAP_NATIVE = 302;\n uint256 private constant OFFSET_ZAP_DATA = 334;\n // forgefmt: disable-end\n\n error BridgeTransactionV2__InvalidEncodedTx();\n error BridgeTransactionV2__UnsupportedVersion(uint16 version);\n\n /// @notice Validates the encoded transaction to be a tightly packed encoded payload for BridgeTransactionV2.\n /// @dev Checks the minimum length and the version, use this function before decoding any of the fields.\n function validateV2(bytes calldata encodedTx) internal pure {\n // Check the minimum length: must at least include all static fields.\n if (encodedTx.length \u003c OFFSET_ZAP_DATA) revert BridgeTransactionV2__InvalidEncodedTx();\n // Once we validated the length, we can be sure that the version field is present.\n uint16 version_ = version(encodedTx);\n if (version_ != VERSION) revert BridgeTransactionV2__UnsupportedVersion(version_);\n }\n\n /// @notice Encodes the BridgeTransactionV2 struct by tightly packing the fields.\n /// @dev `abi.decode` will not work as a result of the tightly packed fields. Use `decodeV2` to decode instead.\n function encodeV2(IFastBridgeV2.BridgeTransactionV2 memory bridgeTx) internal pure returns (bytes memory) {\n // We split the encoding into two parts to avoid stack-too-deep error\n bytes memory firstPart = abi.encodePacked(\n VERSION,\n bridgeTx.originChainId,\n bridgeTx.destChainId,\n bridgeTx.originSender,\n bridgeTx.destRecipient,\n bridgeTx.originToken,\n bridgeTx.destToken,\n bridgeTx.originAmount\n );\n return abi.encodePacked(\n firstPart,\n bridgeTx.destAmount,\n bridgeTx.originFeeAmount,\n // Note: we skip the deprecated `sendChainGas` flag, which was present in BridgeTransaction V1\n bridgeTx.deadline,\n bridgeTx.nonce,\n // New V2 fields: exclusivity\n bridgeTx.exclusivityRelayer,\n bridgeTx.exclusivityEndTime,\n // New V2 fields: Zap\n bridgeTx.zapNative,\n bridgeTx.zapData\n );\n }\n\n /// @notice Decodes the BridgeTransactionV2 struct from the encoded transaction.\n /// @dev Encoded BridgeTransactionV2 struct must be tightly packed.\n /// Use `validateV2` before decoding to ensure the encoded transaction is valid.\n function decodeV2(bytes calldata encodedTx)\n internal\n pure\n returns (IFastBridgeV2.BridgeTransactionV2 memory bridgeTx)\n {\n bridgeTx.originChainId = originChainId(encodedTx);\n bridgeTx.destChainId = destChainId(encodedTx);\n bridgeTx.originSender = originSender(encodedTx);\n bridgeTx.destRecipient = destRecipient(encodedTx);\n bridgeTx.originToken = originToken(encodedTx);\n bridgeTx.destToken = destToken(encodedTx);\n bridgeTx.originAmount = originAmount(encodedTx);\n bridgeTx.destAmount = destAmount(encodedTx);\n bridgeTx.originFeeAmount = originFeeAmount(encodedTx);\n bridgeTx.deadline = deadline(encodedTx);\n bridgeTx.nonce = nonce(encodedTx);\n bridgeTx.exclusivityRelayer = exclusivityRelayer(encodedTx);\n bridgeTx.exclusivityEndTime = exclusivityEndTime(encodedTx);\n bridgeTx.zapNative = zapNative(encodedTx);\n bridgeTx.zapData = zapData(encodedTx);\n }\n\n /// @notice Extracts the version from the encoded transaction.\n function version(bytes calldata encodedTx) internal pure returns (uint16 version_) {\n // Load 32 bytes from the start and shift it 240 bits to the right to get the highest 16 bits.\n assembly {\n version_ := shr(240, calldataload(encodedTx.offset))\n }\n }\n\n /// @notice Extracts the origin chain ID from the encoded transaction.\n function originChainId(bytes calldata encodedTx) internal pure returns (uint32 originChainId_) {\n // Load 32 bytes from the offset and shift it 224 bits to the right to get the highest 32 bits.\n assembly {\n originChainId_ := shr(224, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_CHAIN_ID)))\n }\n }\n\n /// @notice Extracts the destination chain ID from the encoded transaction.\n function destChainId(bytes calldata encodedTx) internal pure returns (uint32 destChainId_) {\n // Load 32 bytes from the offset and shift it 224 bits to the right to get the highest 32 bits.\n assembly {\n destChainId_ := shr(224, calldataload(add(encodedTx.offset, OFFSET_DEST_CHAIN_ID)))\n }\n }\n\n /// @notice Extracts the origin sender from the encoded transaction.\n function originSender(bytes calldata encodedTx) internal pure returns (address originSender_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n originSender_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_SENDER)))\n }\n }\n\n /// @notice Extracts the destination recipient from the encoded transaction.\n function destRecipient(bytes calldata encodedTx) internal pure returns (address destRecipient_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n destRecipient_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_DEST_RECIPIENT)))\n }\n }\n\n /// @notice Extracts the origin token from the encoded transaction.\n function originToken(bytes calldata encodedTx) internal pure returns (address originToken_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n originToken_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_TOKEN)))\n }\n }\n\n /// @notice Extracts the destination token from the encoded transaction.\n function destToken(bytes calldata encodedTx) internal pure returns (address destToken_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n destToken_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_DEST_TOKEN)))\n }\n }\n\n /// @notice Extracts the origin amount from the encoded transaction.\n function originAmount(bytes calldata encodedTx) internal pure returns (uint256 originAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n originAmount_ := calldataload(add(encodedTx.offset, OFFSET_ORIGIN_AMOUNT))\n }\n }\n\n /// @notice Extracts the destination amount from the encoded transaction.\n function destAmount(bytes calldata encodedTx) internal pure returns (uint256 destAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n destAmount_ := calldataload(add(encodedTx.offset, OFFSET_DEST_AMOUNT))\n }\n }\n\n /// @notice Extracts the origin fee amount from the encoded transaction.\n function originFeeAmount(bytes calldata encodedTx) internal pure returns (uint256 originFeeAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n originFeeAmount_ := calldataload(add(encodedTx.offset, OFFSET_ORIGIN_FEE_AMOUNT))\n }\n }\n\n /// @notice Extracts the deadline from the encoded transaction.\n function deadline(bytes calldata encodedTx) internal pure returns (uint256 deadline_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n deadline_ := calldataload(add(encodedTx.offset, OFFSET_DEADLINE))\n }\n }\n\n /// @notice Extracts the nonce from the encoded transaction.\n function nonce(bytes calldata encodedTx) internal pure returns (uint256 nonce_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n nonce_ := calldataload(add(encodedTx.offset, OFFSET_NONCE))\n }\n }\n\n /// @notice Extracts the exclusivity relayer from the encoded transaction.\n function exclusivityRelayer(bytes calldata encodedTx) internal pure returns (address exclusivityRelayer_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n exclusivityRelayer_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_EXCLUSIVITY_RELAYER)))\n }\n }\n\n /// @notice Extracts the exclusivity end time from the encoded transaction.\n function exclusivityEndTime(bytes calldata encodedTx) internal pure returns (uint256 exclusivityEndTime_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n exclusivityEndTime_ := calldataload(add(encodedTx.offset, OFFSET_EXCLUSIVITY_END_TIME))\n }\n }\n\n /// @notice Extracts the Zap's native value from the encoded transaction.\n function zapNative(bytes calldata encodedTx) internal pure returns (uint256 zapNative_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n zapNative_ := calldataload(add(encodedTx.offset, OFFSET_ZAP_NATIVE))\n }\n }\n\n /// @notice Extracts the Zap's data from the encoded transaction.\n function zapData(bytes calldata encodedTx) internal pure returns (bytes calldata zapData_) {\n zapData_ = encodedTx[OFFSET_ZAP_DATA:];\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// contracts/libs/UniversalToken.sol\n\nlibrary UniversalTokenLib {\n using SafeERC20 for IERC20;\n\n address internal constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Transfers tokens to the given account. Reverts if transfer is not successful.\n /// @dev This might trigger fallback, if ETH is transferred to the contract.\n /// Make sure this can not lead to reentrancy attacks.\n function universalTransfer(address token, address to, uint256 value) internal {\n // Don't do anything, if need to send tokens to this address\n if (to == address(this)) return;\n // Don't do anything, if trying to send zero value\n if (value == 0) return;\n if (token == ETH_ADDRESS) {\n /// @dev Note: this can potentially lead to executing code in `to`.\n // solhint-disable-next-line avoid-low-level-calls\n (bool success,) = to.call{value: value}(\"\");\n require(success, \"ETH transfer failed\");\n } else {\n IERC20(token).safeTransfer(to, value);\n }\n }\n\n /// @notice Issues an infinite allowance to the spender, if the current allowance is insufficient\n /// to spend the given amount.\n function universalApproveInfinity(address token, address spender, uint256 amountToSpend) internal {\n // ETH Chad doesn't require your approval\n if (token == ETH_ADDRESS) return;\n // No-op if allowance is already sufficient\n uint256 allowance = IERC20(token).allowance(address(this), spender);\n if (allowance \u003e= amountToSpend) return;\n // Otherwise, reset approval to 0 and set to max allowance\n if (allowance \u003e 0) IERC20(token).safeDecreaseAllowance(spender, allowance);\n IERC20(token).safeIncreaseAllowance(spender, type(uint256).max);\n }\n\n /// @notice Returns the balance of the given token (or native ETH) for the given account.\n function universalBalanceOf(address token, address account) internal view returns (uint256) {\n if (token == ETH_ADDRESS) {\n return account.balance;\n } else {\n return IERC20(token).balanceOf(account);\n }\n }\n\n /// @dev Checks that token is a contract and not ETH_ADDRESS.\n function assertIsContract(address token) internal view {\n // Check that ETH_ADDRESS was not used (in case this is a predeploy on any of the chains)\n if (token == UniversalTokenLib.ETH_ADDRESS) revert TokenNotContract();\n // Check that token is not an EOA\n if (token.code.length == 0) revert TokenNotContract();\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/Admin.sol\n\ncontract Admin is IAdmin, AccessControlEnumerable {\n using UniversalTokenLib for address;\n\n bytes32 public constant RELAYER_ROLE = keccak256(\"RELAYER_ROLE\");\n bytes32 public constant REFUNDER_ROLE = keccak256(\"REFUNDER_ROLE\");\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n uint256 public constant FEE_BPS = 1e6;\n uint256 public constant FEE_RATE_MAX = 0.01e6; // max 1% on origin amount\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Chain gas amount to forward as rebate if requested\n uint256 public chainGasAmount;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n }\n\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n require(newFeeRate \u003c= FEE_RATE_MAX, \"newFeeRate \u003e max\");\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n token.universalTransfer(recipient, feeAmount);\n emit FeesSwept(token, recipient, feeAmount);\n }\n\n function setChainGasAmount(uint256 newChainGasAmount) external onlyRole(GOVERNOR_ROLE) {\n uint256 oldChainGasAmount = chainGasAmount;\n chainGasAmount = newChainGasAmount;\n emit ChainGasAmountUpdated(oldChainGasAmount, newChainGasAmount);\n }\n}\n\n// contracts/FastBridgeV2.sol\n\n/// @notice FastBridgeV2 is a contract for bridging tokens across chains.\ncontract FastBridgeV2 is Admin, MulticallTarget, IFastBridgeV2, IFastBridgeV2Errors {\n using BridgeTransactionV2Lib for bytes;\n using SafeERC20 for IERC20;\n\n /// @notice Address reserved for native gas token (ETH on Ethereum and most L2s, AVAX on Avalanche, etc)\n address public constant NATIVE_GAS_TOKEN = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Delay for a transaction after which it could be permisionlessly refunded\n uint256 public constant REFUND_DELAY = 7 days;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n /// @notice Maximum length of accepted zapData\n uint256 public constant MAX_ZAP_DATA_LENGTH = 2 ** 16 - 1;\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeTxDetails) public bridgeTxDetails;\n /// @notice Relay details on destination chain\n mapping(bytes32 =\u003e BridgeRelay) public bridgeRelayDetails;\n /// @notice Unique bridge nonces tracked per originSender\n mapping(address =\u003e uint256) public senderNonces;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Replaced by senderNonces\n uint256 public immutable nonce = 0;\n /// @notice the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n bridge({\n params: params,\n paramsV2: BridgeParamsV2({\n quoteRelayer: address(0),\n quoteExclusivitySeconds: 0,\n quoteId: bytes(\"\"),\n zapNative: 0,\n zapData: bytes(\"\")\n })\n });\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes calldata request) external payable {\n // relay override will validate the request\n relay({request: request, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes calldata request, bytes32 destTxHash) external {\n request.validateV2();\n prove({transactionId: keccak256(request), destTxHash: destTxHash, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridgeV2\n function claim(bytes calldata request) external {\n // claim override will validate the request\n claim({request: request, to: address(0)});\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Aggregate the read operations from the same storage slot\n address disputedRelayer = $.proofRelayer;\n BridgeStatus status = $.status;\n uint56 proofBlockTimestamp = $.proofBlockTimestamp;\n // Can only dispute a RELAYER_PROVED transaction within the dispute period\n if (status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(proofBlockTimestamp) \u003e DISPUTE_PERIOD) {\n revert DisputePeriodPassed();\n }\n // Update status to REQUESTED and delete the disputed proof details\n // Note: these are storage writes\n $.status = BridgeStatus.REQUESTED;\n $.proofRelayer = address(0);\n $.proofBlockTimestamp = 0;\n\n emit BridgeProofDisputed(transactionId, disputedRelayer);\n }\n\n /// @inheritdoc IFastBridge\n function refund(bytes calldata request) external {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Can only refund a REQUESTED transaction after its deadline expires\n if ($.status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n uint256 deadline = request.deadline();\n // Permissionless refund is only allowed after REFUND_DELAY on top of the deadline\n if (!hasRole(REFUNDER_ROLE, msg.sender)) deadline += REFUND_DELAY;\n if (block.timestamp \u003c= deadline) revert DeadlineNotExceeded();\n // Update status to REFUNDED and return the full amount (collateral + protocol fees) to the original sender.\n // The protocol fees are only updated when the transaction is claimed, so we don't need to update them here.\n // Note: this is a storage write\n $.status = BridgeStatus.REFUNDED;\n\n address to = request.originSender();\n address token = request.originToken();\n uint256 amount = request.originAmount() + request.originFeeAmount();\n // Emit the event before any external calls\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n // Complete the user refund as the last transaction action\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(to), amount);\n } else {\n IERC20(token).safeTransfer(to, amount);\n }\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // The correct relayer can only claim a RELAYER_PROVED transaction after the dispute period\n if ($.status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if ($.proofRelayer != relayer) revert SenderIncorrect();\n return _timeSince($.proofBlockTimestamp) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n /// @dev This method is added to achieve backwards compatibility with decoding requests into V1 structs:\n /// - `zapNative` is partially reported as a zero/non-zero flag\n /// - `zapData` is ignored\n /// In order to process all kinds of requests use getBridgeTransactionV2 instead.\n function getBridgeTransaction(bytes calldata request) external view returns (BridgeTransaction memory) {\n // Try decoding into V2 struct first. This will revert if V1 struct is passed\n try this.getBridgeTransactionV2(request) returns (BridgeTransactionV2 memory txV2) {\n // Note: we entirely ignore the zapData field, as it was not present in V1\n return BridgeTransaction({\n originChainId: txV2.originChainId,\n destChainId: txV2.destChainId,\n originSender: txV2.originSender,\n destRecipient: txV2.destRecipient,\n originToken: txV2.originToken,\n destToken: txV2.destToken,\n originAmount: txV2.originAmount,\n destAmount: txV2.destAmount,\n originFeeAmount: txV2.originFeeAmount,\n sendChainGas: txV2.zapNative != 0,\n deadline: txV2.deadline,\n nonce: txV2.nonce\n });\n } catch {\n // Fallback to V1 struct\n return abi.decode(request, (BridgeTransaction));\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function getBridgeTransactionV2(bytes calldata request) external pure returns (BridgeTransactionV2 memory) {\n request.validateV2();\n return BridgeTransactionV2Lib.decodeV2(request);\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) public payable {\n int256 exclusivityEndTime = 0;\n // if relayer exclusivity is not intended for this bridge, set exclusivityEndTime to static zero\n // otherwise, set exclusivity to expire at the current block ts offset by quoteExclusivitySeconds\n if (paramsV2.quoteRelayer != address(0)) {\n exclusivityEndTime = int256(block.timestamp) + paramsV2.quoteExclusivitySeconds;\n }\n _validateBridgeParams(params, paramsV2, exclusivityEndTime);\n\n // transfer tokens to bridge contract\n /// @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _takeBridgedUserAsset(params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) {\n originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n }\n\n // set status to requested\n bytes memory request = BridgeTransactionV2Lib.encodeV2(\n BridgeTransactionV2({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n deadline: params.deadline,\n nonce: senderNonces[params.sender]++, // increment nonce on every bridge\n exclusivityRelayer: paramsV2.quoteRelayer,\n // We checked exclusivityEndTime to be in range [0 .. params.deadline] above, so can safely cast\n exclusivityEndTime: uint256(exclusivityEndTime),\n zapNative: paramsV2.zapNative,\n zapData: paramsV2.zapData\n })\n );\n bytes32 transactionId = keccak256(request);\n // Note: the tx status will be updated throughout the tx lifecycle, while destChainId is set once here\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n bridgeTxDetails[transactionId].destChainId = params.dstChainId;\n\n emit BridgeRequested({\n transactionId: transactionId,\n sender: params.sender,\n request: request,\n destChainId: params.dstChainId,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n sendChainGas: paramsV2.zapNative != 0\n });\n emit BridgeQuoteDetails(transactionId, paramsV2.quoteId);\n }\n\n /// @inheritdoc IFastBridgeV2\n function relay(bytes calldata request, address relayer) public payable {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n _validateRelayParams(request, transactionId, relayer);\n // mark bridge transaction as relayed\n bridgeRelayDetails[transactionId] =\n BridgeRelay({blockNumber: uint48(block.number), blockTimestamp: uint48(block.timestamp), relayer: relayer});\n\n // transfer tokens to recipient on destination chain and trigger Zap if requested\n address to = request.destRecipient();\n address token = request.destToken();\n uint256 amount = request.destAmount();\n uint256 zapNative = request.zapNative();\n\n // Emit the event before any external calls\n emit BridgeRelayed({\n transactionId: transactionId,\n relayer: relayer,\n to: to,\n originChainId: request.originChainId(),\n originToken: request.originToken(),\n destToken: token,\n originAmount: request.originAmount(),\n destAmount: amount,\n chainGasAmount: zapNative\n });\n\n // All state changes have been done at this point, can proceed to the external calls.\n // This follows the checks-effects-interactions pattern to mitigate potential reentrancy attacks.\n if (token == NATIVE_GAS_TOKEN) {\n // For the native gas token, additional zapNative is not allowed\n if (zapNative != 0) revert ZapNativeNotSupported();\n // Check that the correct msg.value was sent\n if (msg.value != amount) revert MsgValueIncorrect();\n // Don't do a native transfer yet: we will handle it alongside the Zap below\n } else {\n // For ERC20s, we check that the correct msg.value was sent\n if (msg.value != zapNative) revert MsgValueIncorrect();\n // We need to transfer the tokens from the Relayer to the recipient first before performing an\n // optional post-transfer Zap.\n IERC20(token).safeTransferFrom(msg.sender, to, amount);\n }\n // At this point we have done:\n // - Transferred the requested amount of ERC20 tokens to the recipient.\n // At this point we have confirmed:\n // - For ERC20s: msg.value matches the requested zapNative amount.\n // - For the native gas token: msg.value matches the requested destAmount.\n // Remaining optional things to do:\n // - Forward the full msg.value to the recipient (if non-zero).\n // - Trigger a Zap (if zapData is present).\n bytes calldata zapData = request.zapData();\n if (zapData.length != 0) {\n // Zap Data is present: Zap has been requested by the recipient. Trigger it forwarding the full msg.value.\n\n // Note: if token has a fee on transfers, the recipient will have received less than `amount`.\n // This is a very niche edge case and should be handled by the recipient contract.\n _triggerZapWithChecks({recipient: to, token: token, amount: amount, zapData: zapData});\n } else if (msg.value != 0) {\n // Zap Data is missing, but msg.value was sent. This could happen in two different cases:\n // - Relay with the native gas token is happening.\n // - Relay with ERC20 is happening, with a `zapNative \u003e 0` request.\n // In both cases, we need to transfer the full msg.value to the recipient.\n Address.sendValue(payable(to), msg.value);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) public onlyRole(RELAYER_ROLE) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n\n // Can only prove a REQUESTED transaction\n if ($.status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n // Update status to RELAYER_PROVED and store the proof details\n // Note: these are storage writes\n $.status = BridgeStatus.RELAYER_PROVED;\n $.proofBlockTimestamp = uint56(block.timestamp);\n $.proofRelayer = relayer;\n\n emit BridgeProofProvided(transactionId, relayer, destTxHash);\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes calldata request, address to) public {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Aggregate the read operations from the same storage slot\n address proofRelayer = $.proofRelayer;\n BridgeStatus status = $.status;\n uint56 proofBlockTimestamp = $.proofBlockTimestamp;\n\n // Can only claim a RELAYER_PROVED transaction after the dispute period\n if (status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(proofBlockTimestamp) \u003c= DISPUTE_PERIOD) {\n revert DisputePeriodNotPassed();\n }\n\n if (to == address(0)) {\n // Anyone could claim the funds to the proven relayer on their behalf\n to = proofRelayer;\n } else if (proofRelayer != msg.sender) {\n // Only the proven relayer could specify an address to claim the funds to\n revert SenderIncorrect();\n }\n\n // Update status to RELAYER_CLAIMED and transfer the origin collateral to the specified claim address\n // Note: this is a storage write\n $.status = BridgeStatus.RELAYER_CLAIMED;\n\n address token = request.originToken();\n uint256 amount = request.originAmount();\n // Update protocol fees if origin fee amount exists\n uint256 originFeeAmount = request.originFeeAmount();\n if (originFeeAmount \u003e 0) protocolFees[token] += originFeeAmount;\n // Emit the event before any external calls\n emit BridgeDepositClaimed(transactionId, proofRelayer, to, token, amount);\n // Complete the relayer claim as the last transaction action\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(to), amount);\n } else {\n IERC20(token).safeTransfer(to, amount);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeStatuses(bytes32 transactionId) public view returns (BridgeStatus status) {\n return bridgeTxDetails[transactionId].status;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeProofs(bytes32 transactionId) public view returns (uint96 timestamp, address relayer) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n\n timestamp = $.proofBlockTimestamp;\n relayer = $.proofRelayer;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeRelays(bytes32 transactionId) public view returns (bool) {\n // has this transactionId been relayed?\n return bridgeRelayDetails[transactionId].relayer != address(0);\n }\n\n /// @notice Takes the bridged asset from the user into FastBridgeV2 custody. It will be later\n /// claimed by the relayer who completed the relay on destination chain, or refunded back to the user,\n /// should no one complete the relay.\n function _takeBridgedUserAsset(address token, uint256 amount) internal returns (uint256 amountTaken) {\n if (token == NATIVE_GAS_TOKEN) {\n // For the native gas token, we just need to check that the supplied msg.value is correct.\n // Supplied `msg.value` is already in FastBridgeV2 custody.\n if (amount != msg.value) revert MsgValueIncorrect();\n amountTaken = msg.value;\n } else {\n // For ERC20s, token is explicitly transferred from the user to FastBridgeV2.\n // We don't allow non-zero `msg.value` to avoid extra funds from being stuck in FastBridgeV2.\n if (msg.value != 0) revert MsgValueIncorrect();\n // Throw an explicit error if the provided token address is not a contract\n if (token.code.length == 0) revert TokenNotContract();\n amountTaken = IERC20(token).balanceOf(address(this));\n IERC20(token).safeTransferFrom(msg.sender, address(this), amount);\n // Use the balance difference as the amount taken in case of fee on transfer tokens.\n amountTaken = IERC20(token).balanceOf(address(this)) - amountTaken;\n }\n }\n\n /// @notice Calls the Recipient's hook function with the specified zapData and performs\n /// all the necessary checks for the returned value.\n function _triggerZapWithChecks(address recipient, address token, uint256 amount, bytes calldata zapData) internal {\n // This will bubble any revert messages from the hook function\n bytes memory returnData = Address.functionCallWithValue({\n target: recipient,\n data: abi.encodeCall(IZapRecipient.zap, (token, amount, zapData)),\n // Note: see `relay()` for reasoning behind passing msg.value\n value: msg.value\n });\n // Explicit revert if no return data at all\n if (returnData.length == 0) revert RecipientNoReturnValue();\n // Check that exactly a single return value was returned\n if (returnData.length != 32) revert RecipientIncorrectReturnValue();\n // Return value should be abi-encoded hook function selector\n if (bytes32(returnData) != bytes32(IZapRecipient.zap.selector)) {\n revert RecipientIncorrectReturnValue();\n }\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint56(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint56).max but\n /// proof.timestamp \u003c type(uint56).max via unchecked statement\n /// @param proofBlockTimestamp The bridge proof block timestamp\n /// @return delta Time delta since proof submitted\n function _timeSince(uint56 proofBlockTimestamp) internal view returns (uint256 delta) {\n unchecked {\n delta = uint56(block.timestamp) - proofBlockTimestamp;\n }\n }\n\n /// @notice Performs all the necessary checks for a bridge to happen.\n /// @dev There's no good way to refactor this function to reduce cyclomatic complexity due to\n /// the number of checks that need to be performed, so we skip the code-complexity rule here.\n // solhint-disable-next-line code-complexity\n function _validateBridgeParams(\n BridgeParams memory params,\n BridgeParamsV2 memory paramsV2,\n int256 exclusivityEndTime\n )\n internal\n view\n {\n // Check V1 (legacy) params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.sender == address(0) || params.to == address(0)) revert ZeroAddress();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n // Check V2 params\n if (paramsV2.zapData.length \u003e MAX_ZAP_DATA_LENGTH) revert ZapDataLengthAboveMax();\n if (paramsV2.zapNative != 0 \u0026\u0026 params.destToken == NATIVE_GAS_TOKEN) {\n revert ZapNativeNotSupported();\n }\n // exclusivityEndTime must be in range [0 .. params.deadline]\n if (exclusivityEndTime \u003c 0 || exclusivityEndTime \u003e int256(params.deadline)) {\n revert ExclusivityParamsIncorrect();\n }\n }\n\n /// @notice Performs all the necessary checks for a relay to happen.\n function _validateRelayParams(bytes calldata request, bytes32 transactionId, address relayer) internal view {\n if (relayer == address(0)) revert ZeroAddress();\n // Check if the transaction has already been relayed\n if (bridgeRelays(transactionId)) revert TransactionRelayed();\n if (request.destChainId() != block.chainid) revert ChainIncorrect();\n // Check the deadline for relay to happen\n if (block.timestamp \u003e request.deadline()) revert DeadlineExceeded();\n // Check the exclusivity period, if it is still ongoing\n address exclRelayer = request.exclusivityRelayer();\n if (exclRelayer != address(0) \u0026\u0026 exclRelayer != relayer \u0026\u0026 block.timestamp \u003c= request.exclusivityEndTime()) {\n revert ExclusivityPeriodNotPassed();\n }\n }\n}\n","language":"Solidity","languageVersion":"0.8.24","compilerVersion":"0.8.24","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"","srcMapRuntime":"","abiDefinition":[{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"}],"userDoc":{"kind":"user","methods":{},"version":1},"developerDoc":{"details":"Implementation of the {IERC165} interface. Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check for the additional interface id that will be supported. For example: ```solidity function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId); } ```","kind":"dev","methods":{"supportsInterface(bytes4)":{"details":"See {IERC165-supportsInterface}."}},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"bytes4\",\"name\":\"interfaceId\",\"type\":\"bytes4\"}],\"name\":\"supportsInterface\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"}],\"devdoc\":{\"details\":\"Implementation of the {IERC165} interface. Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check for the additional interface id that will be supported. For example: ```solidity function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId); } ```\",\"kind\":\"dev\",\"methods\":{\"supportsInterface(bytes4)\":{\"details\":\"See {IERC165-supportsInterface}.\"}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeV2.sol\":\"ERC165\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeV2.sol\":{\"keccak256\":\"0x5069b55ca07f21bfe30b2a43c18a18318c8af9c181b2dcb07c290825efd70f34\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://273dc020a49d08e50126bbea0d7f783f79d08c702f2fdbc560618d24af308acc\",\"dweb:/ipfs/QmXJ2UVzFc8EPB74RT4CXQPC4xw66jt4T13poyfyd3UERh\"]}},\"version\":1}"},"hashes":{"supportsInterface(bytes4)":"01ffc9a7"}},"solidity/FastBridgeV2.sol:EnumerableSet":{"code":"0x60566037600b82828239805160001a607314602a57634e487b7160e01b600052600060045260246000fd5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600080fdfea26469706673582212202a0689afaebf6ffa0f4d0a6fe04b9b6e642f8ef83c8db74e665e9fc77d71999964736f6c63430008180033","runtime-code":"0x73000000000000000000000000000000000000000030146080604052600080fdfea26469706673582212202a0689afaebf6ffa0f4d0a6fe04b9b6e642f8ef83c8db74e665e9fc77d71999964736f6c63430008180033","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.24 ^0.8.20 ^0.8.4;\n\n// contracts/interfaces/IAdmin.sol\n\ninterface IAdmin {\n // ============ Events ============\n\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n event ChainGasAmountUpdated(uint256 oldChainGasAmount, uint256 newChainGasAmount);\n\n // ============ Methods ============\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n\n function setChainGasAmount(uint256 newChainGasAmount) external;\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IFastBridgeV2Errors.sol\n\ninterface IFastBridgeV2Errors {\n error AmountIncorrect();\n error ChainIncorrect();\n error ExclusivityParamsIncorrect();\n error MsgValueIncorrect();\n error SenderIncorrect();\n error StatusIncorrect();\n error TokenNotContract();\n error ZapDataLengthAboveMax();\n error ZapNativeNotSupported();\n error ZeroAddress();\n\n error RecipientIncorrectReturnValue();\n error RecipientNoReturnValue();\n\n error DeadlineExceeded();\n error DeadlineNotExceeded();\n error DeadlineTooShort();\n error DisputePeriodNotPassed();\n error DisputePeriodPassed();\n error ExclusivityPeriodNotPassed();\n\n error TransactionRelayed();\n}\n\n// contracts/interfaces/IMulticallTarget.sol\n\n/// @notice Interface for a contract that can be called multiple times by the same caller. Inspired by MulticallV3:\n/// https://github.com/mds1/multicall/blob/master/src/Multicall3.sol\ninterface IMulticallTarget {\n struct Result {\n bool success;\n bytes returnData;\n }\n\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external;\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results);\n}\n\n// contracts/interfaces/IZapRecipient.sol\n\ninterface IZapRecipient {\n function zap(address token, uint256 amount, bytes memory zapData) external payable returns (bytes4);\n}\n\n// contracts/libs/Errors.sol\n\nerror DeadlineExceeded();\nerror DeadlineNotExceeded();\nerror DeadlineTooShort();\nerror InsufficientOutputAmount();\n\nerror MsgValueIncorrect();\nerror PoolNotFound();\nerror TokenAddressMismatch();\nerror TokenNotContract();\nerror TokenNotETH();\nerror TokensIdentical();\n\nerror ChainIncorrect();\nerror AmountIncorrect();\nerror ZeroAddress();\n\nerror DisputePeriodNotPassed();\nerror DisputePeriodPassed();\nerror SenderIncorrect();\nerror StatusIncorrect();\nerror TransactionIdIncorrect();\nerror TransactionRelayed();\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// contracts/interfaces/IFastBridgeV2.sol\n\ninterface IFastBridgeV2 is IFastBridge {\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n struct BridgeTxDetails {\n BridgeStatus status;\n uint32 destChainId;\n uint56 proofBlockTimestamp;\n address proofRelayer;\n }\n\n struct BridgeRelay {\n uint48 blockNumber;\n uint48 blockTimestamp;\n address relayer;\n }\n\n /// @notice New params introduced in the FastBridgeV2.\n /// We are passing fields from the older BridgeParams struct outside of this struct\n /// for backwards compatibility.\n /// Note: quoteRelayer and quoteExclusivitySeconds are either both zero (indicating no exclusivity)\n /// or both non-zero (indicating exclusivity for the given period).\n /// Note: zapNative \u003e 0 can NOT be used with destToken = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE (native token)\n /// @param quoteRelayer Relayer that provided the quote for the transaction\n /// @param quoteExclusivitySeconds Period of time the quote relayer is guaranteed exclusivity after user's deposit\n /// @param quoteId Unique quote identifier used for tracking the quote\n /// @param zapNative ETH value to send to the recipient (if any)\n /// @param zapData Parameters for the Zap to the destination recipient (if any)\n struct BridgeParamsV2 {\n address quoteRelayer;\n int256 quoteExclusivitySeconds;\n bytes quoteId;\n uint256 zapNative;\n bytes zapData;\n }\n\n /// @notice Updated bridge transaction struct to include parameters introduced in FastBridgeV2.\n /// Note: only `exclusivityRelayer` can fill such a transaction until `exclusivityEndTime`.\n struct BridgeTransactionV2 {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n // Note: sendChainGas flag from V1 is deprecated\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n address exclusivityRelayer;\n uint256 exclusivityEndTime;\n uint256 zapNative; // ETH value to send to the recipient (if any)\n bytes zapData; // data to pass for the Zap action (if any)\n }\n\n event BridgeQuoteDetails(bytes32 indexed transactionId, bytes quoteId);\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability\n /// to provide temporary exclusivity fill rights for the quote relayer.\n /// @param params The parameters required to bridge\n /// @param paramsV2 The parameters for exclusivity fill rights (optional, can be left empty)\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function relay(bytes memory request, address relayer) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param transactionId The transaction id associated with the encoded bridge transaction to prove\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital.\n /// @notice Can only send funds to the relayer address on the proof.\n /// @param request The encoded bridge transaction to claim on origin chain\n function claim(bytes memory request) external;\n /// @notice Checks if a transaction has been relayed\n /// @param transactionId The ID of the transaction to check\n /// @return True if the transaction has been relayed, false otherwise\n function bridgeRelays(bytes32 transactionId) external view returns (bool);\n\n /// @notice Returns the status of a bridge transaction\n /// @param transactionId The ID of the bridge transaction\n /// @return BridgeStatus Status of the bridge transaction\n function bridgeStatuses(bytes32 transactionId) external view returns (BridgeStatus);\n\n /// @notice Returns the timestamp and relayer of a bridge proof\n /// @param transactionId The ID of the bridge transaction\n /// @return timestamp The timestamp of the bridge proof\n /// @return relayer The relayer address of the bridge proof\n function bridgeProofs(bytes32 transactionId) external view returns (uint96 timestamp, address relayer);\n\n /// @notice Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\n /// @param request The bridge request to decode\n function getBridgeTransactionV2(bytes memory request) external view returns (BridgeTransactionV2 memory);\n}\n\n// contracts/utils/MulticallTarget.sol\n\n// solhint-disable avoid-low-level-calls\n/// @notice Template for a contract that supports batched calls (preserving the msg.sender).\n/// Only calls with zero msg.value could be batched.\nabstract contract MulticallTarget is IMulticallTarget {\n error MulticallTarget__UndeterminedRevert();\n\n /// @notice Perform a batched call to this contract, preserving the msg.sender.\n /// The return data from each call is discarded.\n /// @dev The method is non-payable, so only calls with `msg.value == 0` could be batched.\n /// It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag.\n /// Otherwise, the whole batch call will be reverted with the original revert reason.\n /// @param data List of abi-encoded calldata for the calls to perform.\n /// @param ignoreReverts Whether to ignore the revert errors from the calls.\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external {\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\n if (!success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(result);\n }\n }\n }\n\n /// @notice Perform a batched call to this contract, preserving the msg.sender.\n /// The return data from each call is preserved.\n /// @dev The method is non-payable, so only calls with `msg.value == 0` could be batched.\n /// It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag.\n /// Otherwise, the whole batch call will be reverted with the original revert reason.\n /// @param data List of abi-encoded calldata for the calls to perform.\n /// @param ignoreReverts Whether to ignore the revert errors from the calls.\n /// @return results List of results from the calls: `(success, returnData)`.\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results)\n {\n results = new Result[](data.length);\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (results[i].success, results[i].returnData) = address(this).delegatecall(data[i]);\n if (!results[i].success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(results[i].returnData);\n }\n }\n }\n\n /// @dev Bubbles the revert message from the underlying call.\n /// Note: preserves the same custom error or revert string, if one was used.\n /// Source: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v5.0.2/contracts/utils/Address.sol#L143-L158\n function _bubbleRevert(bytes memory returnData) internal pure {\n // Look for revert reason and bubble it up if present\n if (returnData.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n // solhint-disable-next-line no-inline-assembly\n assembly {\n let returndata_size := mload(returnData)\n revert(add(32, returnData), returndata_size)\n }\n } else {\n revert MulticallTarget__UndeterminedRevert();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// contracts/libs/BridgeTransactionV2.sol\n\n// solhint-disable no-inline-assembly\nlibrary BridgeTransactionV2Lib {\n uint16 internal constant VERSION = 2;\n\n // Offsets of the fields in the packed BridgeTransactionV2 struct\n // uint16 version [000 .. 002)\n // uint32 originChainId [002 .. 006)\n // uint32 destChainId [006 .. 010)\n // address originSender [010 .. 030)\n // address destRecipient [030 .. 050)\n // address originToken [050 .. 070)\n // address destToken [070 .. 090)\n // uint256 originAmount [090 .. 122)\n // uint256 destAmount [122 .. 154)\n // uint256 originFeeAmount [154 .. 186)\n // uint256 deadline [186 .. 218)\n // uint256 nonce [218 .. 250)\n // address exclusivityRelayer [250 .. 270)\n // uint256 exclusivityEndTime [270 .. 302)\n // uint256 zapNative [302 .. 334)\n // bytes zapData [334 .. ***)\n\n // forgefmt: disable-start\n uint256 private constant OFFSET_ORIGIN_CHAIN_ID = 2;\n uint256 private constant OFFSET_DEST_CHAIN_ID = 6;\n uint256 private constant OFFSET_ORIGIN_SENDER = 10;\n uint256 private constant OFFSET_DEST_RECIPIENT = 30;\n uint256 private constant OFFSET_ORIGIN_TOKEN = 50;\n uint256 private constant OFFSET_DEST_TOKEN = 70;\n uint256 private constant OFFSET_ORIGIN_AMOUNT = 90;\n uint256 private constant OFFSET_DEST_AMOUNT = 122;\n uint256 private constant OFFSET_ORIGIN_FEE_AMOUNT = 154;\n uint256 private constant OFFSET_DEADLINE = 186;\n uint256 private constant OFFSET_NONCE = 218;\n uint256 private constant OFFSET_EXCLUSIVITY_RELAYER = 250;\n uint256 private constant OFFSET_EXCLUSIVITY_END_TIME = 270;\n uint256 private constant OFFSET_ZAP_NATIVE = 302;\n uint256 private constant OFFSET_ZAP_DATA = 334;\n // forgefmt: disable-end\n\n error BridgeTransactionV2__InvalidEncodedTx();\n error BridgeTransactionV2__UnsupportedVersion(uint16 version);\n\n /// @notice Validates the encoded transaction to be a tightly packed encoded payload for BridgeTransactionV2.\n /// @dev Checks the minimum length and the version, use this function before decoding any of the fields.\n function validateV2(bytes calldata encodedTx) internal pure {\n // Check the minimum length: must at least include all static fields.\n if (encodedTx.length \u003c OFFSET_ZAP_DATA) revert BridgeTransactionV2__InvalidEncodedTx();\n // Once we validated the length, we can be sure that the version field is present.\n uint16 version_ = version(encodedTx);\n if (version_ != VERSION) revert BridgeTransactionV2__UnsupportedVersion(version_);\n }\n\n /// @notice Encodes the BridgeTransactionV2 struct by tightly packing the fields.\n /// @dev `abi.decode` will not work as a result of the tightly packed fields. Use `decodeV2` to decode instead.\n function encodeV2(IFastBridgeV2.BridgeTransactionV2 memory bridgeTx) internal pure returns (bytes memory) {\n // We split the encoding into two parts to avoid stack-too-deep error\n bytes memory firstPart = abi.encodePacked(\n VERSION,\n bridgeTx.originChainId,\n bridgeTx.destChainId,\n bridgeTx.originSender,\n bridgeTx.destRecipient,\n bridgeTx.originToken,\n bridgeTx.destToken,\n bridgeTx.originAmount\n );\n return abi.encodePacked(\n firstPart,\n bridgeTx.destAmount,\n bridgeTx.originFeeAmount,\n // Note: we skip the deprecated `sendChainGas` flag, which was present in BridgeTransaction V1\n bridgeTx.deadline,\n bridgeTx.nonce,\n // New V2 fields: exclusivity\n bridgeTx.exclusivityRelayer,\n bridgeTx.exclusivityEndTime,\n // New V2 fields: Zap\n bridgeTx.zapNative,\n bridgeTx.zapData\n );\n }\n\n /// @notice Decodes the BridgeTransactionV2 struct from the encoded transaction.\n /// @dev Encoded BridgeTransactionV2 struct must be tightly packed.\n /// Use `validateV2` before decoding to ensure the encoded transaction is valid.\n function decodeV2(bytes calldata encodedTx)\n internal\n pure\n returns (IFastBridgeV2.BridgeTransactionV2 memory bridgeTx)\n {\n bridgeTx.originChainId = originChainId(encodedTx);\n bridgeTx.destChainId = destChainId(encodedTx);\n bridgeTx.originSender = originSender(encodedTx);\n bridgeTx.destRecipient = destRecipient(encodedTx);\n bridgeTx.originToken = originToken(encodedTx);\n bridgeTx.destToken = destToken(encodedTx);\n bridgeTx.originAmount = originAmount(encodedTx);\n bridgeTx.destAmount = destAmount(encodedTx);\n bridgeTx.originFeeAmount = originFeeAmount(encodedTx);\n bridgeTx.deadline = deadline(encodedTx);\n bridgeTx.nonce = nonce(encodedTx);\n bridgeTx.exclusivityRelayer = exclusivityRelayer(encodedTx);\n bridgeTx.exclusivityEndTime = exclusivityEndTime(encodedTx);\n bridgeTx.zapNative = zapNative(encodedTx);\n bridgeTx.zapData = zapData(encodedTx);\n }\n\n /// @notice Extracts the version from the encoded transaction.\n function version(bytes calldata encodedTx) internal pure returns (uint16 version_) {\n // Load 32 bytes from the start and shift it 240 bits to the right to get the highest 16 bits.\n assembly {\n version_ := shr(240, calldataload(encodedTx.offset))\n }\n }\n\n /// @notice Extracts the origin chain ID from the encoded transaction.\n function originChainId(bytes calldata encodedTx) internal pure returns (uint32 originChainId_) {\n // Load 32 bytes from the offset and shift it 224 bits to the right to get the highest 32 bits.\n assembly {\n originChainId_ := shr(224, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_CHAIN_ID)))\n }\n }\n\n /// @notice Extracts the destination chain ID from the encoded transaction.\n function destChainId(bytes calldata encodedTx) internal pure returns (uint32 destChainId_) {\n // Load 32 bytes from the offset and shift it 224 bits to the right to get the highest 32 bits.\n assembly {\n destChainId_ := shr(224, calldataload(add(encodedTx.offset, OFFSET_DEST_CHAIN_ID)))\n }\n }\n\n /// @notice Extracts the origin sender from the encoded transaction.\n function originSender(bytes calldata encodedTx) internal pure returns (address originSender_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n originSender_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_SENDER)))\n }\n }\n\n /// @notice Extracts the destination recipient from the encoded transaction.\n function destRecipient(bytes calldata encodedTx) internal pure returns (address destRecipient_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n destRecipient_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_DEST_RECIPIENT)))\n }\n }\n\n /// @notice Extracts the origin token from the encoded transaction.\n function originToken(bytes calldata encodedTx) internal pure returns (address originToken_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n originToken_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_TOKEN)))\n }\n }\n\n /// @notice Extracts the destination token from the encoded transaction.\n function destToken(bytes calldata encodedTx) internal pure returns (address destToken_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n destToken_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_DEST_TOKEN)))\n }\n }\n\n /// @notice Extracts the origin amount from the encoded transaction.\n function originAmount(bytes calldata encodedTx) internal pure returns (uint256 originAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n originAmount_ := calldataload(add(encodedTx.offset, OFFSET_ORIGIN_AMOUNT))\n }\n }\n\n /// @notice Extracts the destination amount from the encoded transaction.\n function destAmount(bytes calldata encodedTx) internal pure returns (uint256 destAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n destAmount_ := calldataload(add(encodedTx.offset, OFFSET_DEST_AMOUNT))\n }\n }\n\n /// @notice Extracts the origin fee amount from the encoded transaction.\n function originFeeAmount(bytes calldata encodedTx) internal pure returns (uint256 originFeeAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n originFeeAmount_ := calldataload(add(encodedTx.offset, OFFSET_ORIGIN_FEE_AMOUNT))\n }\n }\n\n /// @notice Extracts the deadline from the encoded transaction.\n function deadline(bytes calldata encodedTx) internal pure returns (uint256 deadline_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n deadline_ := calldataload(add(encodedTx.offset, OFFSET_DEADLINE))\n }\n }\n\n /// @notice Extracts the nonce from the encoded transaction.\n function nonce(bytes calldata encodedTx) internal pure returns (uint256 nonce_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n nonce_ := calldataload(add(encodedTx.offset, OFFSET_NONCE))\n }\n }\n\n /// @notice Extracts the exclusivity relayer from the encoded transaction.\n function exclusivityRelayer(bytes calldata encodedTx) internal pure returns (address exclusivityRelayer_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n exclusivityRelayer_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_EXCLUSIVITY_RELAYER)))\n }\n }\n\n /// @notice Extracts the exclusivity end time from the encoded transaction.\n function exclusivityEndTime(bytes calldata encodedTx) internal pure returns (uint256 exclusivityEndTime_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n exclusivityEndTime_ := calldataload(add(encodedTx.offset, OFFSET_EXCLUSIVITY_END_TIME))\n }\n }\n\n /// @notice Extracts the Zap's native value from the encoded transaction.\n function zapNative(bytes calldata encodedTx) internal pure returns (uint256 zapNative_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n zapNative_ := calldataload(add(encodedTx.offset, OFFSET_ZAP_NATIVE))\n }\n }\n\n /// @notice Extracts the Zap's data from the encoded transaction.\n function zapData(bytes calldata encodedTx) internal pure returns (bytes calldata zapData_) {\n zapData_ = encodedTx[OFFSET_ZAP_DATA:];\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// contracts/libs/UniversalToken.sol\n\nlibrary UniversalTokenLib {\n using SafeERC20 for IERC20;\n\n address internal constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Transfers tokens to the given account. Reverts if transfer is not successful.\n /// @dev This might trigger fallback, if ETH is transferred to the contract.\n /// Make sure this can not lead to reentrancy attacks.\n function universalTransfer(address token, address to, uint256 value) internal {\n // Don't do anything, if need to send tokens to this address\n if (to == address(this)) return;\n // Don't do anything, if trying to send zero value\n if (value == 0) return;\n if (token == ETH_ADDRESS) {\n /// @dev Note: this can potentially lead to executing code in `to`.\n // solhint-disable-next-line avoid-low-level-calls\n (bool success,) = to.call{value: value}(\"\");\n require(success, \"ETH transfer failed\");\n } else {\n IERC20(token).safeTransfer(to, value);\n }\n }\n\n /// @notice Issues an infinite allowance to the spender, if the current allowance is insufficient\n /// to spend the given amount.\n function universalApproveInfinity(address token, address spender, uint256 amountToSpend) internal {\n // ETH Chad doesn't require your approval\n if (token == ETH_ADDRESS) return;\n // No-op if allowance is already sufficient\n uint256 allowance = IERC20(token).allowance(address(this), spender);\n if (allowance \u003e= amountToSpend) return;\n // Otherwise, reset approval to 0 and set to max allowance\n if (allowance \u003e 0) IERC20(token).safeDecreaseAllowance(spender, allowance);\n IERC20(token).safeIncreaseAllowance(spender, type(uint256).max);\n }\n\n /// @notice Returns the balance of the given token (or native ETH) for the given account.\n function universalBalanceOf(address token, address account) internal view returns (uint256) {\n if (token == ETH_ADDRESS) {\n return account.balance;\n } else {\n return IERC20(token).balanceOf(account);\n }\n }\n\n /// @dev Checks that token is a contract and not ETH_ADDRESS.\n function assertIsContract(address token) internal view {\n // Check that ETH_ADDRESS was not used (in case this is a predeploy on any of the chains)\n if (token == UniversalTokenLib.ETH_ADDRESS) revert TokenNotContract();\n // Check that token is not an EOA\n if (token.code.length == 0) revert TokenNotContract();\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/Admin.sol\n\ncontract Admin is IAdmin, AccessControlEnumerable {\n using UniversalTokenLib for address;\n\n bytes32 public constant RELAYER_ROLE = keccak256(\"RELAYER_ROLE\");\n bytes32 public constant REFUNDER_ROLE = keccak256(\"REFUNDER_ROLE\");\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n uint256 public constant FEE_BPS = 1e6;\n uint256 public constant FEE_RATE_MAX = 0.01e6; // max 1% on origin amount\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Chain gas amount to forward as rebate if requested\n uint256 public chainGasAmount;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n }\n\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n require(newFeeRate \u003c= FEE_RATE_MAX, \"newFeeRate \u003e max\");\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n token.universalTransfer(recipient, feeAmount);\n emit FeesSwept(token, recipient, feeAmount);\n }\n\n function setChainGasAmount(uint256 newChainGasAmount) external onlyRole(GOVERNOR_ROLE) {\n uint256 oldChainGasAmount = chainGasAmount;\n chainGasAmount = newChainGasAmount;\n emit ChainGasAmountUpdated(oldChainGasAmount, newChainGasAmount);\n }\n}\n\n// contracts/FastBridgeV2.sol\n\n/// @notice FastBridgeV2 is a contract for bridging tokens across chains.\ncontract FastBridgeV2 is Admin, MulticallTarget, IFastBridgeV2, IFastBridgeV2Errors {\n using BridgeTransactionV2Lib for bytes;\n using SafeERC20 for IERC20;\n\n /// @notice Address reserved for native gas token (ETH on Ethereum and most L2s, AVAX on Avalanche, etc)\n address public constant NATIVE_GAS_TOKEN = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Delay for a transaction after which it could be permisionlessly refunded\n uint256 public constant REFUND_DELAY = 7 days;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n /// @notice Maximum length of accepted zapData\n uint256 public constant MAX_ZAP_DATA_LENGTH = 2 ** 16 - 1;\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeTxDetails) public bridgeTxDetails;\n /// @notice Relay details on destination chain\n mapping(bytes32 =\u003e BridgeRelay) public bridgeRelayDetails;\n /// @notice Unique bridge nonces tracked per originSender\n mapping(address =\u003e uint256) public senderNonces;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Replaced by senderNonces\n uint256 public immutable nonce = 0;\n /// @notice the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n bridge({\n params: params,\n paramsV2: BridgeParamsV2({\n quoteRelayer: address(0),\n quoteExclusivitySeconds: 0,\n quoteId: bytes(\"\"),\n zapNative: 0,\n zapData: bytes(\"\")\n })\n });\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes calldata request) external payable {\n // relay override will validate the request\n relay({request: request, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes calldata request, bytes32 destTxHash) external {\n request.validateV2();\n prove({transactionId: keccak256(request), destTxHash: destTxHash, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridgeV2\n function claim(bytes calldata request) external {\n // claim override will validate the request\n claim({request: request, to: address(0)});\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Aggregate the read operations from the same storage slot\n address disputedRelayer = $.proofRelayer;\n BridgeStatus status = $.status;\n uint56 proofBlockTimestamp = $.proofBlockTimestamp;\n // Can only dispute a RELAYER_PROVED transaction within the dispute period\n if (status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(proofBlockTimestamp) \u003e DISPUTE_PERIOD) {\n revert DisputePeriodPassed();\n }\n // Update status to REQUESTED and delete the disputed proof details\n // Note: these are storage writes\n $.status = BridgeStatus.REQUESTED;\n $.proofRelayer = address(0);\n $.proofBlockTimestamp = 0;\n\n emit BridgeProofDisputed(transactionId, disputedRelayer);\n }\n\n /// @inheritdoc IFastBridge\n function refund(bytes calldata request) external {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Can only refund a REQUESTED transaction after its deadline expires\n if ($.status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n uint256 deadline = request.deadline();\n // Permissionless refund is only allowed after REFUND_DELAY on top of the deadline\n if (!hasRole(REFUNDER_ROLE, msg.sender)) deadline += REFUND_DELAY;\n if (block.timestamp \u003c= deadline) revert DeadlineNotExceeded();\n // Update status to REFUNDED and return the full amount (collateral + protocol fees) to the original sender.\n // The protocol fees are only updated when the transaction is claimed, so we don't need to update them here.\n // Note: this is a storage write\n $.status = BridgeStatus.REFUNDED;\n\n address to = request.originSender();\n address token = request.originToken();\n uint256 amount = request.originAmount() + request.originFeeAmount();\n // Emit the event before any external calls\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n // Complete the user refund as the last transaction action\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(to), amount);\n } else {\n IERC20(token).safeTransfer(to, amount);\n }\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // The correct relayer can only claim a RELAYER_PROVED transaction after the dispute period\n if ($.status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if ($.proofRelayer != relayer) revert SenderIncorrect();\n return _timeSince($.proofBlockTimestamp) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n /// @dev This method is added to achieve backwards compatibility with decoding requests into V1 structs:\n /// - `zapNative` is partially reported as a zero/non-zero flag\n /// - `zapData` is ignored\n /// In order to process all kinds of requests use getBridgeTransactionV2 instead.\n function getBridgeTransaction(bytes calldata request) external view returns (BridgeTransaction memory) {\n // Try decoding into V2 struct first. This will revert if V1 struct is passed\n try this.getBridgeTransactionV2(request) returns (BridgeTransactionV2 memory txV2) {\n // Note: we entirely ignore the zapData field, as it was not present in V1\n return BridgeTransaction({\n originChainId: txV2.originChainId,\n destChainId: txV2.destChainId,\n originSender: txV2.originSender,\n destRecipient: txV2.destRecipient,\n originToken: txV2.originToken,\n destToken: txV2.destToken,\n originAmount: txV2.originAmount,\n destAmount: txV2.destAmount,\n originFeeAmount: txV2.originFeeAmount,\n sendChainGas: txV2.zapNative != 0,\n deadline: txV2.deadline,\n nonce: txV2.nonce\n });\n } catch {\n // Fallback to V1 struct\n return abi.decode(request, (BridgeTransaction));\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function getBridgeTransactionV2(bytes calldata request) external pure returns (BridgeTransactionV2 memory) {\n request.validateV2();\n return BridgeTransactionV2Lib.decodeV2(request);\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) public payable {\n int256 exclusivityEndTime = 0;\n // if relayer exclusivity is not intended for this bridge, set exclusivityEndTime to static zero\n // otherwise, set exclusivity to expire at the current block ts offset by quoteExclusivitySeconds\n if (paramsV2.quoteRelayer != address(0)) {\n exclusivityEndTime = int256(block.timestamp) + paramsV2.quoteExclusivitySeconds;\n }\n _validateBridgeParams(params, paramsV2, exclusivityEndTime);\n\n // transfer tokens to bridge contract\n /// @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _takeBridgedUserAsset(params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) {\n originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n }\n\n // set status to requested\n bytes memory request = BridgeTransactionV2Lib.encodeV2(\n BridgeTransactionV2({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n deadline: params.deadline,\n nonce: senderNonces[params.sender]++, // increment nonce on every bridge\n exclusivityRelayer: paramsV2.quoteRelayer,\n // We checked exclusivityEndTime to be in range [0 .. params.deadline] above, so can safely cast\n exclusivityEndTime: uint256(exclusivityEndTime),\n zapNative: paramsV2.zapNative,\n zapData: paramsV2.zapData\n })\n );\n bytes32 transactionId = keccak256(request);\n // Note: the tx status will be updated throughout the tx lifecycle, while destChainId is set once here\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n bridgeTxDetails[transactionId].destChainId = params.dstChainId;\n\n emit BridgeRequested({\n transactionId: transactionId,\n sender: params.sender,\n request: request,\n destChainId: params.dstChainId,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n sendChainGas: paramsV2.zapNative != 0\n });\n emit BridgeQuoteDetails(transactionId, paramsV2.quoteId);\n }\n\n /// @inheritdoc IFastBridgeV2\n function relay(bytes calldata request, address relayer) public payable {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n _validateRelayParams(request, transactionId, relayer);\n // mark bridge transaction as relayed\n bridgeRelayDetails[transactionId] =\n BridgeRelay({blockNumber: uint48(block.number), blockTimestamp: uint48(block.timestamp), relayer: relayer});\n\n // transfer tokens to recipient on destination chain and trigger Zap if requested\n address to = request.destRecipient();\n address token = request.destToken();\n uint256 amount = request.destAmount();\n uint256 zapNative = request.zapNative();\n\n // Emit the event before any external calls\n emit BridgeRelayed({\n transactionId: transactionId,\n relayer: relayer,\n to: to,\n originChainId: request.originChainId(),\n originToken: request.originToken(),\n destToken: token,\n originAmount: request.originAmount(),\n destAmount: amount,\n chainGasAmount: zapNative\n });\n\n // All state changes have been done at this point, can proceed to the external calls.\n // This follows the checks-effects-interactions pattern to mitigate potential reentrancy attacks.\n if (token == NATIVE_GAS_TOKEN) {\n // For the native gas token, additional zapNative is not allowed\n if (zapNative != 0) revert ZapNativeNotSupported();\n // Check that the correct msg.value was sent\n if (msg.value != amount) revert MsgValueIncorrect();\n // Don't do a native transfer yet: we will handle it alongside the Zap below\n } else {\n // For ERC20s, we check that the correct msg.value was sent\n if (msg.value != zapNative) revert MsgValueIncorrect();\n // We need to transfer the tokens from the Relayer to the recipient first before performing an\n // optional post-transfer Zap.\n IERC20(token).safeTransferFrom(msg.sender, to, amount);\n }\n // At this point we have done:\n // - Transferred the requested amount of ERC20 tokens to the recipient.\n // At this point we have confirmed:\n // - For ERC20s: msg.value matches the requested zapNative amount.\n // - For the native gas token: msg.value matches the requested destAmount.\n // Remaining optional things to do:\n // - Forward the full msg.value to the recipient (if non-zero).\n // - Trigger a Zap (if zapData is present).\n bytes calldata zapData = request.zapData();\n if (zapData.length != 0) {\n // Zap Data is present: Zap has been requested by the recipient. Trigger it forwarding the full msg.value.\n\n // Note: if token has a fee on transfers, the recipient will have received less than `amount`.\n // This is a very niche edge case and should be handled by the recipient contract.\n _triggerZapWithChecks({recipient: to, token: token, amount: amount, zapData: zapData});\n } else if (msg.value != 0) {\n // Zap Data is missing, but msg.value was sent. This could happen in two different cases:\n // - Relay with the native gas token is happening.\n // - Relay with ERC20 is happening, with a `zapNative \u003e 0` request.\n // In both cases, we need to transfer the full msg.value to the recipient.\n Address.sendValue(payable(to), msg.value);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) public onlyRole(RELAYER_ROLE) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n\n // Can only prove a REQUESTED transaction\n if ($.status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n // Update status to RELAYER_PROVED and store the proof details\n // Note: these are storage writes\n $.status = BridgeStatus.RELAYER_PROVED;\n $.proofBlockTimestamp = uint56(block.timestamp);\n $.proofRelayer = relayer;\n\n emit BridgeProofProvided(transactionId, relayer, destTxHash);\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes calldata request, address to) public {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Aggregate the read operations from the same storage slot\n address proofRelayer = $.proofRelayer;\n BridgeStatus status = $.status;\n uint56 proofBlockTimestamp = $.proofBlockTimestamp;\n\n // Can only claim a RELAYER_PROVED transaction after the dispute period\n if (status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(proofBlockTimestamp) \u003c= DISPUTE_PERIOD) {\n revert DisputePeriodNotPassed();\n }\n\n if (to == address(0)) {\n // Anyone could claim the funds to the proven relayer on their behalf\n to = proofRelayer;\n } else if (proofRelayer != msg.sender) {\n // Only the proven relayer could specify an address to claim the funds to\n revert SenderIncorrect();\n }\n\n // Update status to RELAYER_CLAIMED and transfer the origin collateral to the specified claim address\n // Note: this is a storage write\n $.status = BridgeStatus.RELAYER_CLAIMED;\n\n address token = request.originToken();\n uint256 amount = request.originAmount();\n // Update protocol fees if origin fee amount exists\n uint256 originFeeAmount = request.originFeeAmount();\n if (originFeeAmount \u003e 0) protocolFees[token] += originFeeAmount;\n // Emit the event before any external calls\n emit BridgeDepositClaimed(transactionId, proofRelayer, to, token, amount);\n // Complete the relayer claim as the last transaction action\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(to), amount);\n } else {\n IERC20(token).safeTransfer(to, amount);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeStatuses(bytes32 transactionId) public view returns (BridgeStatus status) {\n return bridgeTxDetails[transactionId].status;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeProofs(bytes32 transactionId) public view returns (uint96 timestamp, address relayer) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n\n timestamp = $.proofBlockTimestamp;\n relayer = $.proofRelayer;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeRelays(bytes32 transactionId) public view returns (bool) {\n // has this transactionId been relayed?\n return bridgeRelayDetails[transactionId].relayer != address(0);\n }\n\n /// @notice Takes the bridged asset from the user into FastBridgeV2 custody. It will be later\n /// claimed by the relayer who completed the relay on destination chain, or refunded back to the user,\n /// should no one complete the relay.\n function _takeBridgedUserAsset(address token, uint256 amount) internal returns (uint256 amountTaken) {\n if (token == NATIVE_GAS_TOKEN) {\n // For the native gas token, we just need to check that the supplied msg.value is correct.\n // Supplied `msg.value` is already in FastBridgeV2 custody.\n if (amount != msg.value) revert MsgValueIncorrect();\n amountTaken = msg.value;\n } else {\n // For ERC20s, token is explicitly transferred from the user to FastBridgeV2.\n // We don't allow non-zero `msg.value` to avoid extra funds from being stuck in FastBridgeV2.\n if (msg.value != 0) revert MsgValueIncorrect();\n // Throw an explicit error if the provided token address is not a contract\n if (token.code.length == 0) revert TokenNotContract();\n amountTaken = IERC20(token).balanceOf(address(this));\n IERC20(token).safeTransferFrom(msg.sender, address(this), amount);\n // Use the balance difference as the amount taken in case of fee on transfer tokens.\n amountTaken = IERC20(token).balanceOf(address(this)) - amountTaken;\n }\n }\n\n /// @notice Calls the Recipient's hook function with the specified zapData and performs\n /// all the necessary checks for the returned value.\n function _triggerZapWithChecks(address recipient, address token, uint256 amount, bytes calldata zapData) internal {\n // This will bubble any revert messages from the hook function\n bytes memory returnData = Address.functionCallWithValue({\n target: recipient,\n data: abi.encodeCall(IZapRecipient.zap, (token, amount, zapData)),\n // Note: see `relay()` for reasoning behind passing msg.value\n value: msg.value\n });\n // Explicit revert if no return data at all\n if (returnData.length == 0) revert RecipientNoReturnValue();\n // Check that exactly a single return value was returned\n if (returnData.length != 32) revert RecipientIncorrectReturnValue();\n // Return value should be abi-encoded hook function selector\n if (bytes32(returnData) != bytes32(IZapRecipient.zap.selector)) {\n revert RecipientIncorrectReturnValue();\n }\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint56(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint56).max but\n /// proof.timestamp \u003c type(uint56).max via unchecked statement\n /// @param proofBlockTimestamp The bridge proof block timestamp\n /// @return delta Time delta since proof submitted\n function _timeSince(uint56 proofBlockTimestamp) internal view returns (uint256 delta) {\n unchecked {\n delta = uint56(block.timestamp) - proofBlockTimestamp;\n }\n }\n\n /// @notice Performs all the necessary checks for a bridge to happen.\n /// @dev There's no good way to refactor this function to reduce cyclomatic complexity due to\n /// the number of checks that need to be performed, so we skip the code-complexity rule here.\n // solhint-disable-next-line code-complexity\n function _validateBridgeParams(\n BridgeParams memory params,\n BridgeParamsV2 memory paramsV2,\n int256 exclusivityEndTime\n )\n internal\n view\n {\n // Check V1 (legacy) params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.sender == address(0) || params.to == address(0)) revert ZeroAddress();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n // Check V2 params\n if (paramsV2.zapData.length \u003e MAX_ZAP_DATA_LENGTH) revert ZapDataLengthAboveMax();\n if (paramsV2.zapNative != 0 \u0026\u0026 params.destToken == NATIVE_GAS_TOKEN) {\n revert ZapNativeNotSupported();\n }\n // exclusivityEndTime must be in range [0 .. params.deadline]\n if (exclusivityEndTime \u003c 0 || exclusivityEndTime \u003e int256(params.deadline)) {\n revert ExclusivityParamsIncorrect();\n }\n }\n\n /// @notice Performs all the necessary checks for a relay to happen.\n function _validateRelayParams(bytes calldata request, bytes32 transactionId, address relayer) internal view {\n if (relayer == address(0)) revert ZeroAddress();\n // Check if the transaction has already been relayed\n if (bridgeRelays(transactionId)) revert TransactionRelayed();\n if (request.destChainId() != block.chainid) revert ChainIncorrect();\n // Check the deadline for relay to happen\n if (block.timestamp \u003e request.deadline()) revert DeadlineExceeded();\n // Check the exclusivity period, if it is still ongoing\n address exclRelayer = request.exclusivityRelayer();\n if (exclRelayer != address(0) \u0026\u0026 exclRelayer != relayer \u0026\u0026 block.timestamp \u003c= request.exclusivityEndTime()) {\n revert ExclusivityPeriodNotPassed();\n }\n }\n}\n","language":"Solidity","languageVersion":"0.8.24","compilerVersion":"0.8.24","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"26331:11640:0:-:0;;;;;;;;;;;;;;;-1:-1:-1;;;26331:11640:0;;;;;;;;;;;;;;;;;","srcMapRuntime":"26331:11640:0:-:0;;;;;;;;","abiDefinition":[],"userDoc":{"kind":"user","methods":{},"version":1},"developerDoc":{"details":"Library for managing https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive types. Sets have the following properties: - Elements are added, removed, and checked for existence in constant time (O(1)). - Elements are enumerated in O(n). No guarantees are made on the ordering. ```solidity contract Example { // Add the library methods using EnumerableSet for EnumerableSet.AddressSet; // Declare a set state variable EnumerableSet.AddressSet private mySet; } ``` As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`) and `uint256` (`UintSet`) are supported. [WARNING] ==== Trying to delete such a structure from storage will likely result in data corruption, rendering the structure unusable. See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info. In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an array of EnumerableSet. ====","kind":"dev","methods":{},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[],\"devdoc\":{\"details\":\"Library for managing https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive types. Sets have the following properties: - Elements are added, removed, and checked for existence in constant time (O(1)). - Elements are enumerated in O(n). No guarantees are made on the ordering. ```solidity contract Example { // Add the library methods using EnumerableSet for EnumerableSet.AddressSet; // Declare a set state variable EnumerableSet.AddressSet private mySet; } ``` As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`) and `uint256` (`UintSet`) are supported. [WARNING] ==== Trying to delete such a structure from storage will likely result in data corruption, rendering the structure unusable. See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info. In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an array of EnumerableSet. ====\",\"kind\":\"dev\",\"methods\":{},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeV2.sol\":\"EnumerableSet\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeV2.sol\":{\"keccak256\":\"0x5069b55ca07f21bfe30b2a43c18a18318c8af9c181b2dcb07c290825efd70f34\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://273dc020a49d08e50126bbea0d7f783f79d08c702f2fdbc560618d24af308acc\",\"dweb:/ipfs/QmXJ2UVzFc8EPB74RT4CXQPC4xw66jt4T13poyfyd3UERh\"]}},\"version\":1}"},"hashes":{}},"solidity/FastBridgeV2.sol:FastBridgeV2":{"code":"0x60c060405260006080523480156200001657600080fd5b506040516200475c3803806200475c833981016040819052620000399162000199565b806200004760008262000054565b50504360a05250620001c4565b60008062000063848462000091565b90508015620000885760008481526001602052604090206200008690846200013f565b505b90505b92915050565b6000828152602081815260408083206001600160a01b038516845290915281205460ff1662000136576000838152602081815260408083206001600160a01b03861684529091529020805460ff19166001179055620000ed3390565b6001600160a01b0316826001600160a01b0316847f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45060016200008b565b5060006200008b565b600062000088836001600160a01b038416600081815260018301602052604081205462000136575081546001818101845560008481526020808220909301849055845484825282860190935260409020919091556200008b565b600060208284031215620001ac57600080fd5b81516001600160a01b03811681146200008857600080fd5b60805160a051614572620001ea60003960006108b30152600061095401526145726000f3fe60806040526004361061031e5760003560e01c8063886d36ff116101a5578063add98c70116100ec578063c63ff8dd11610095578063ccc574901161006f578063ccc5749014610aad578063d547741f14610ae1578063dcf844a714610b01578063e00a83e014610b2e57600080fd5b8063c63ff8dd146109e0578063c79371b114610a00578063ca15c87314610a8d57600080fd5b8063b250fe6b116100c6578063b250fe6b14610996578063bf333f2c146109b6578063bfc7c607146109cd57600080fd5b8063add98c7014610922578063affed0e014610942578063b13aa2d61461097657600080fd5b80639c9545f01161014e578063a5bbe22b11610128578063a5bbe22b146106ca578063aa9641ab146108d5578063ac11fb1a146108f557600080fd5b80639c9545f014610879578063a217fddf1461088c578063a3ec191a146108a157600080fd5b806391ad50391161017f57806391ad50391461077b57806391d1485414610801578063926d7d7f1461084557600080fd5b8063886d36ff146107285780638f0d6f17146107485780639010d07c1461075b57600080fd5b8063385c1d2f116102695780635960ccf21161021257806363787e52116101ec57806363787e5214610650578063820688d5146106ca5780638379a24f146106e057600080fd5b80635960ccf2146105cf5780635aa6ccba146106035780635eb7d9461461063057600080fd5b80634585169411610243578063458516941461059057806354eff068146105a357806358f85880146105b957600080fd5b8063385c1d2f146105235780633f61331d1461055057806341fcb6121461057057600080fd5b806318e4357d116102cb578063295710ff116102a5578063295710ff146104b65780632f2ff15d146104e357806336568abe1461050357600080fd5b806318e4357d1461044f578063190da5951461046f578063248a9ca31461048657600080fd5b806306f333f2116102fc57806306f333f2146103d75780630f5f6ed7146103f95780630f862f1e1461040f57600080fd5b806301ffc9a71461032357806303ed0ee514610358578063051287bc1461039a575b600080fd5b34801561032f57600080fd5b5061034361033e36600461351e565b610b44565b60405190151581526020015b60405180910390f35b34801561036457600080fd5b5061038c7f043c983c49d46f0e102151eaf8085d4a2e6571d5df2d47b013f39bddfd4a639d81565b60405190815260200161034f565b3480156103a657600080fd5b506103ca6103b5366004613560565b60009081526005602052604090205460ff1690565b60405161034f91906135e3565b3480156103e357600080fd5b506103f76103f2366004613616565b610ba0565b005b34801561040557600080fd5b5061038c61271081565b34801561041b57600080fd5b5061043773eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee81565b6040516001600160a01b03909116815260200161034f565b34801561045b57600080fd5b506103f761046a36600461364f565b610c67565b34801561047b57600080fd5b5061038c62093a8081565b34801561049257600080fd5b5061038c6104a1366004613560565b60009081526020819052604090206001015490565b3480156104c257600080fd5b5061038c6104d1366004613688565b60076020526000908152604090205481565b3480156104ef57600080fd5b506103f76104fe3660046136a5565b610d7c565b34801561050f57600080fd5b506103f761051e3660046136a5565b610da7565b34801561052f57600080fd5b5061054361053e3660046136e3565b610df3565b60405161034f91906137ae565b34801561055c57600080fd5b506103f761056b3660046136e3565b610f81565b34801561057c57600080fd5b506103f761058b36600461388d565b61102b565b6103f761059e366004613a8e565b61129d565b3480156105af57600080fd5b5061038c61ffff81565b3480156105c557600080fd5b5061038c60025481565b3480156105db57600080fd5b5061038c7fdb9556138406326f00296e13ea2ad7db24ba82381212d816b1a40c23b466b32781565b34801561060f57600080fd5b5061062361061e366004613aab565b6112fa565b60405161034f9190613aed565b34801561063c57600080fd5b506103f761064b366004613aab565b6113c7565b34801561065c57600080fd5b506106ba61066b366004613560565b60056020526000908152604090205460ff811690610100810463ffffffff169065010000000000810466ffffffffffffff16906c0100000000000000000000000090046001600160a01b031684565b60405161034f9493929190613c0a565b3480156106d657600080fd5b5061038c61070881565b3480156106ec57600080fd5b506103436106fb366004613560565b6000908152600660205260409020546c0100000000000000000000000090046001600160a01b0316151590565b34801561073457600080fd5b506103f7610743366004613c4b565b6115c9565b6103f7610756366004613aab565b6115f5565b34801561076757600080fd5b50610437610776366004613c97565b611604565b34801561078757600080fd5b506107d5610796366004613560565b60009081526005602052604090205465010000000000810466ffffffffffffff16916c010000000000000000000000009091046001600160a01b031690565b604080516bffffffffffffffffffffffff90931683526001600160a01b0390911660208301520161034f565b34801561080d57600080fd5b5061034361081c3660046136a5565b6000918252602082815260408084206001600160a01b0393909316845291905290205460ff1690565b34801561085157600080fd5b5061038c7fe2b7fb3b832174769106daebcfd6d1970523240dda11281102db9363b83b0dc481565b6103f761088736600461388d565b61161c565b34801561089857600080fd5b5061038c600081565b3480156108ad57600080fd5b5061038c7f000000000000000000000000000000000000000000000000000000000000000081565b3480156108e157600080fd5b506103436108f03660046136a5565b6118d6565b34801561090157600080fd5b50610915610910366004613aab565b6119ad565b60405161034f9190613cb9565b34801561092e57600080fd5b506103f761093d366004613560565b611b61565b34801561094e57600080fd5b5061038c7f000000000000000000000000000000000000000000000000000000000000000081565b34801561098257600080fd5b506103f7610991366004613560565b611cab565b3480156109a257600080fd5b506103f76109b1366004613560565b611d8d565b3480156109c257600080fd5b5061038c620f424081565b6103f76109db366004613e1d565b611df5565b3480156109ec57600080fd5b506103f76109fb366004613aab565b612084565b348015610a0c57600080fd5b50610a5f610a1b366004613560565b60066020526000908152604090205465ffffffffffff8082169166010000000000008104909116906c0100000000000000000000000090046001600160a01b031683565b6040805165ffffffffffff94851681529390921660208401526001600160a01b03169082015260600161034f565b348015610a9957600080fd5b5061038c610aa8366004613560565b612090565b348015610ab957600080fd5b5061038c7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f5581565b348015610aed57600080fd5b506103f7610afc3660046136a5565b6120a7565b348015610b0d57600080fd5b5061038c610b1c366004613688565b60036020526000908152604090205481565b348015610b3a57600080fd5b5061038c60045481565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f5a05180f000000000000000000000000000000000000000000000000000000001480610b9a5750610b9a826120cc565b92915050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f55610bca81612163565b6001600160a01b03831660009081526003602052604081205490819003610bf15750505050565b6001600160a01b038416600081815260036020526040812055610c1590848361216d565b604080516001600160a01b038087168252851660208201529081018290527f244e51bc38c1452fa8aaf487bcb4bca36c2baa3a5fbdb776b1eabd8dc6d277cd9060600160405180910390a1505b505050565b7fe2b7fb3b832174769106daebcfd6d1970523240dda11281102db9363b83b0dc4610c9181612163565b60008481526005602052604090206001815460ff166004811115610cb757610cb7613579565b14610cee576040517f4145817200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80546001600160a01b0384166c0100000000000000000000000081026bffffffffffffffffffffffff66ffffffffffffff421665010000000000021664ffffffff009093169290921791909117600217825560405185815286907f4ac8af8a2cd87193d64dfc7a3b8d9923b714ec528b18725d080aa1299be0c5e49060200160405180910390a35050505050565b600082815260208190526040902060010154610d9781612163565b610da18383612290565b50505050565b6001600160a01b0381163314610de9576040517f6697b23200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610c6282826122bd565b60608267ffffffffffffffff811115610e0e57610e0e6138d9565b604051908082528060200260200182016040528015610e5457816020015b604080518082019091526000815260606020820152815260200190600190039081610e2c5790505b50905060005b83811015610f795730858583818110610e7557610e75613eeb565b9050602002810190610e879190613f1a565b604051610e95929190613f7f565b600060405180830381855af49150503d8060008114610ed0576040519150601f19603f3d011682016040523d82523d6000602084013e610ed5565b606091505b50838381518110610ee857610ee8613eeb565b6020026020010151600001848481518110610f0557610f05613eeb565b602002602001015160200182905282151515158152505050818181518110610f2f57610f2f613eeb565b602002602001015160000151158015610f46575082155b15610f7157610f71828281518110610f6057610f60613eeb565b6020026020010151602001516122ea565b600101610e5a565b509392505050565b60005b82811015610da15760008030868685818110610fa257610fa2613eeb565b9050602002810190610fb49190613f1a565b604051610fc2929190613f7f565b600060405180830381855af49150503d8060008114610ffd576040519150601f19603f3d011682016040523d82523d6000602084013e611002565b606091505b509150915081158015611013575083155b1561102157611021816122ea565b5050600101610f84565b611035838361232c565b60008383604051611047929190613f7f565b604080519182900390912060008181526005602052919091208054919250906c0100000000000000000000000081046001600160a01b03169060ff81169065010000000000900466ffffffffffffff1660028260048111156110ab576110ab613579565b146110e2576040517f4145817200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6107084282900366ffffffffffffff1611611129576040517f1992d0bd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600160a01b03861661113f57829550611181565b6001600160a01b0383163314611181576040517f4af43a9000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b83547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166003178455603288013560601c605a890135609a8a013580156111f0576001600160a01b038316600090815260036020526040812080548392906111ea908490613fbe565b90915550505b604080516001600160a01b03858116825260208201859052808c1692908916918b917f582211c35a2139ac3bbaac74663c6a1f56c6cbb658b41fe11fd45a82074ac678910160405180910390a47fffffffffffffffffffffffff11111111111111111111111111111111111111126001600160a01b0384160161127c5761127789836123ad565b611290565b6112906001600160a01b0384168a84612476565b5050505050505050505050565b6112f7816040518060a0016040528060006001600160a01b03168152602001600081526020016040518060200160405280600081525081526020016000815260200160405180602001604052806000815250815250611df5565b50565b6113ac604051806101e00160405280600063ffffffff168152602001600063ffffffff16815260200160006001600160a01b0316815260200160006001600160a01b0316815260200160006001600160a01b0316815260200160006001600160a01b03168152602001600081526020016000815260200160008152602001600081526020016000815260200160006001600160a01b031681526020016000815260200160008152602001606081525090565b6113b6838361232c565b6113c083836124ea565b9392505050565b6113d1828261232c565b600082826040516113e3929190613f7f565b604080519182900390912060008181526005602052919091209091506001815460ff16600481111561141757611417613579565b1461144e576040517f4145817200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b3360009081527fd2043bf65931af3dbecf60d0db8f40e4160406d7beb00522f4200cf4944a1eb8602052604090205460ba8501359060ff1661149a5761149762093a8082613fbe565b90505b8042116114d3576040517fe15ff9ea00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b81547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166004178255600a850135606090811c906032870135901c6000611522609a890135605a8a0135613fbe565b604080516001600160a01b03858116825260208201849052825193945086169289927fb4c55c0c9bc613519b920e88748090150b890a875d307f21bea7d4fb2e8bc958928290030190a37fffffffffffffffffffffffff11111111111111111111111111111111111111126001600160a01b038316016115ab576115a683826123ad565b6115bf565b6115bf6001600160a01b0383168483612476565b5050505050505050565b6115d3838361232c565b610c6283836040516115e6929190613f7f565b60405180910390208233610c67565b61160082823361161c565b5050565b60008281526001602052604081206113c0908361268c565b611626838361232c565b60008383604051611638929190613f7f565b6040518091039020905061164e84848385612698565b6040805160608101825265ffffffffffff438116825242811660208084019182526001600160a01b038088168587019081526000888152600690935295822094518554935196519091166c01000000000000000000000000026bffffffffffffffffffffffff9685166601000000000000027fffffffffffffffffffffffffffffffffffffffff0000000000000000000000009094169190941617919091179390931617905561170285601e013560601c90565b9050604685013560601c607a86013561012e8701356001600160a01b03808516908716867ff8ae392d784b1ea5e8881bfa586d81abf07ef4f1e2fc75f7fe51c90f05199a5c60028c013560e01c6040805163ffffffff92909216825260328e0135606090811c60208401526001600160a01b038a1683830152605a8f0135908301526080820188905260a08201879052519081900360c00190a47fffffffffffffffffffffffff11111111111111111111111111111111111111126001600160a01b03841601611842578015611804576040517f846dedc000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b81341461183d576040517f81de0bf300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611890565b80341461187b576040517f81de0bf300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6118906001600160a01b03841633868561282d565b36600061189d8a8a612866565b909250905080156118ba576118b58686868585612882565b6118ca565b34156118ca576118ca86346123ad565b50505050505050505050565b60008281526005602052604081206002815460ff1660048111156118fc576118fc613579565b14611933576040517f4145817200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80546001600160a01b038481166c010000000000000000000000009092041614611989576040517f4af43a9000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b546107086501000000000090910466ffffffffffffff908116420316119392505050565b6040805161018081018252600080825260208201819052818301819052606082018190526080820181905260a0820181905260c0820181905260e0820181905261010082018190526101208201819052610140820181905261016082015290517f5aa6ccba0000000000000000000000000000000000000000000000000000000081523090635aa6ccba90611a489086908690600401613ffc565b600060405180830381865afa925050508015611a8657506040513d6000823e601f3d908101601f19168201604052611a83919081019061406b565b60015b611a9d57611a96828401846141a0565b9050610b9a565b604051806101800160405280826000015163ffffffff168152602001826020015163ffffffff16815260200182604001516001600160a01b0316815260200182606001516001600160a01b0316815260200182608001516001600160a01b031681526020018260a001516001600160a01b031681526020018260c0015181526020018260e0015181526020018261010001518152602001826101a0015160001415151581526020018261012001518152602001826101400151815250915050610b9a565b7f043c983c49d46f0e102151eaf8085d4a2e6571d5df2d47b013f39bddfd4a639d611b8b81612163565b600082815260056020526040902080546c0100000000000000000000000081046001600160a01b03169060ff81169065010000000000900466ffffffffffffff166002826004811115611be057611be0613579565b14611c17576040517f4145817200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6107084282900366ffffffffffffff161115611c5f576040517f3e908aac00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b835464ffffffff001660011784556040516001600160a01b0384169087907f0695cf1d39b3055dcd0fe02d8b47eaf0d5a13e1996de925de59d0ef9b7f7fad490600090a3505050505050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f55611cd581612163565b612710821115611d46576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f6e657746656552617465203e206d61780000000000000000000000000000000060448201526064015b60405180910390fd5b600280549083905560408051828152602081018590527f14914da2bf76024616fbe1859783fcd4dbddcb179b1f3a854949fbf920dcb95791015b60405180910390a1505050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f55611db781612163565b600480549083905560408051828152602081018590527f5cf09b12f3f56b4c564d51b25b40360af6d795198adb61ae0806a36c294323fa9101611d80565b80516000906001600160a01b031615611e1a576020820151611e17904261426c565b90505b611e258383836129de565b6000611e3984606001518560a00151612c62565b90506000806002541115611e7257620f424060025483611e599190614294565b611e6391906142ab565b9050611e6f81836142e6565b91505b6000611f7b604051806101e001604052804663ffffffff168152602001886000015163ffffffff16815260200188602001516001600160a01b0316815260200188604001516001600160a01b0316815260200188606001516001600160a01b0316815260200188608001516001600160a01b031681526020018581526020018860c0015181526020018481526020018861010001518152602001600760008a602001516001600160a01b03166001600160a01b031681526020019081526020016000206000815480929190611f46906142f9565b90915550815287516001600160a01b031660208201526040810187905260608089015190820152608080890151910152612e75565b805160208083019190912060008181526005835260409081902080548b5163ffffffff8116610100027fffffffffffffffffffffffffffffffffffffffffffffffffffffff000000000090921691909117600117909155928a01516060808c015160808d015160c08e0151928d0151945197985094966001600160a01b039093169587957f120ea0364f36cdac7983bcfdd55270ca09d7f9b314a2ebc425a3b01ab1d6403a95612037958b959394938e92909190151590614331565b60405180910390a3807f3120e2bb59c86aca6890191a589a96af3662838efa374fbdcdf4c95bfe4a6c0e87604001516040516120739190614387565b60405180910390a250505050505050565b6116008282600061102b565b6000818152600160205260408120610b9a90612fba565b6000828152602081905260409020600101546120c281612163565b610da183836122bd565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f7965db0b000000000000000000000000000000000000000000000000000000001480610b9a57507f01ffc9a7000000000000000000000000000000000000000000000000000000007fffffffff00000000000000000000000000000000000000000000000000000000831614610b9a565b6112f78133612fc4565b306001600160a01b0383160361218257505050565b8060000361218f57505050565b7fffffffffffffffffffffffff11111111111111111111111111111111111111126001600160a01b0384160161227c576000826001600160a01b03168260405160006040518083038185875af1925050503d806000811461220c576040519150601f19603f3d011682016040523d82523d6000602084013e612211565b606091505b5050905080610da1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f455448207472616e73666572206661696c6564000000000000000000000000006044820152606401611d3d565b610c626001600160a01b0384168383612476565b60008061229d8484613030565b905080156113c0576000848152600160205260409020610f7990846130f8565b6000806122ca848461310d565b905080156113c0576000848152600160205260409020610f7990846131ae565b8051156122fa5780518082602001fd5b6040517f5ead5a9d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61014e811015612368576040517f6ee0e17100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b813560f01c60028114610c62576040517f8bd977e700000000000000000000000000000000000000000000000000000000815261ffff82166004820152602401611d3d565b804710156123e9576040517fcd786059000000000000000000000000000000000000000000000000000000008152306004820152602401611d3d565b6000826001600160a01b03168260405160006040518083038185875af1925050503d8060008114612436576040519150601f19603f3d011682016040523d82523d6000602084013e61243b565b606091505b5050905080610c62576040517f1425ea4200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040516001600160a01b03838116602483015260448201839052610c6291859182169063a9059cbb906064015b604051602081830303815290604052915060e01b6020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff83818316178352505050506131c3565b61259c604051806101e00160405280600063ffffffff168152602001600063ffffffff16815260200160006001600160a01b0316815260200160006001600160a01b0316815260200160006001600160a01b0316815260200160006001600160a01b03168152602001600081526020016000815260200160008152602001600081526020016000815260200160006001600160a01b031681526020016000815260200160008152602001606081525090565b600283013560e090811c82526006840135811c6020830152600a840135606090811c6040840152601e850135811c818401526032850135811c60808401526046850135811c60a0840152605a85013560c0840152607a85013591830191909152609a84013561010083015260ba84013561012083015260da84013561014083015260fa840135901c61016082015261010e83013561018082015261012e8301356101a082015261264c8383612866565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152505050506101c082015292915050565b60006113c0838361323f565b6001600160a01b0381166126d8576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000828152600660205260409020546c0100000000000000000000000090046001600160a01b031615612737576040517fbef7bb7d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600684013560e01c4614612777576040517f7029fdf900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60ba8401354211156127b5576040517f559895a300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60fa84013560601c80158015906127de5750816001600160a01b0316816001600160a01b031614155b80156127ef575061010e8501354211155b15612826576040517f14be123200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5050505050565b6040516001600160a01b038481166024830152838116604483015260648201839052610da19186918216906323b872dd906084016124a3565b3660006128778361014e818761439a565b915091509250929050565b60006128fd868686868660405160240161289f94939291906143c4565b60408051601f198184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fe85e13dd0000000000000000000000000000000000000000000000000000000017905234613269565b9050805160000361293a576040517f1a95ad2600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8051602014612975576040517ff3725cca00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7fe85e13dd0000000000000000000000000000000000000000000000000000000061299f826143ed565b146129d6576040517ff3725cca00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b505050505050565b46836000015163ffffffff1603612a21576040517f7029fdf900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60a08301511580612a34575060c0830151155b15612a6b576040517fe38820c800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60208301516001600160a01b03161580612a90575060408301516001600160a01b0316155b15612ac7576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60608301516001600160a01b03161580612aec575060808301516001600160a01b0316155b15612b23576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b612b2f61070842613fbe565b8361010001511015612b6d576040517f04b7fcc800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61ffff8260800151511115612bae576040517f177a70e100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b606082015115801590612be1575060808301516001600160a01b031673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee145b15612c18576040517f846dedc000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000811280612c2b575082610100015181135b15610c62576040517f352807b900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60007fffffffffffffffffffffffff11111111111111111111111111111111111111126001600160a01b03841601612cd457348214612ccd576040517f81de0bf300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5034610b9a565b3415612d0c576040517f81de0bf300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b826001600160a01b03163b600003612d50576040517f7f523fe800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201526001600160a01b038416906370a0823190602401602060405180830381865afa158015612dad573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612dd19190614432565b9050612de86001600160a01b03841633308561282d565b6040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015281906001600160a01b038516906370a0823190602401602060405180830381865afa158015612e47573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612e6b9190614432565b6113c091906142e6565b8051602080830151604080850151606086810151608088015160a089015160c08a015195517e02000000000000000000000000000000000000000000000000000000000000988101989098527fffffffff0000000000000000000000000000000000000000000000000000000060e0998a1b811660228a01529690981b90951660268701527fffffffffffffffffffffffffffffffffffffffff00000000000000000000000092821b8316602a870152811b8216603e86015292831b8116605285015293821b9093166066830152607a820192909252600090609a0160408051601f198184030181529082905260e08501516101008601516101208701516101408801516101608901516101808a01516101a08b01516101c08c0151979950612fa3988a989060200161444b565b604051602081830303815290604052915050919050565b6000610b9a825490565b6000828152602081815260408083206001600160a01b038516845290915290205460ff16611600576040517fe2517d3f0000000000000000000000000000000000000000000000000000000081526001600160a01b038216600482015260248101839052604401611d3d565b6000828152602081815260408083206001600160a01b038516845290915281205460ff166130f0576000838152602081815260408083206001600160a01b0386168452909152902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790556130a83390565b6001600160a01b0316826001600160a01b0316847f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a4506001610b9a565b506000610b9a565b60006113c0836001600160a01b03841661331f565b6000828152602081815260408083206001600160a01b038516845290915281205460ff16156130f0576000838152602081815260408083206001600160a01b038616808552925280832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016905551339286917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a4506001610b9a565b60006113c0836001600160a01b038416613366565b60006131d86001600160a01b03841683613459565b905080516000141580156131fd5750808060200190518101906131fb91906144d4565b155b15610c62576040517f5274afe70000000000000000000000000000000000000000000000000000000081526001600160a01b0384166004820152602401611d3d565b600082600001828154811061325657613256613eeb565b9060005260206000200154905092915050565b6060814710156132a7576040517fcd786059000000000000000000000000000000000000000000000000000000008152306004820152602401611d3d565b600080856001600160a01b031684866040516132c391906144f1565b60006040518083038185875af1925050503d8060008114613300576040519150601f19603f3d011682016040523d82523d6000602084013e613305565b606091505b5091509150613315868383613467565b9695505050505050565b60008181526001830160205260408120546130f057508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155610b9a565b6000818152600183016020526040812054801561344f57600061338a6001836142e6565b855490915060009061339e906001906142e6565b90508082146134035760008660000182815481106133be576133be613eeb565b90600052602060002001549050808760000184815481106133e1576133e1613eeb565b6000918252602080832090910192909255918252600188019052604090208390555b85548690806134145761341461450d565b600190038181906000526020600020016000905590558560010160008681526020019081526020016000206000905560019350505050610b9a565b6000915050610b9a565b60606113c083836000613269565b60608261347c57613477826134dc565b6113c0565b815115801561349357506001600160a01b0384163b155b156134d5576040517f9996b3150000000000000000000000000000000000000000000000000000000081526001600160a01b0385166004820152602401611d3d565b50806113c0565b8051156134ec5780518082602001fd5b6040517f1425ea4200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006020828403121561353057600080fd5b81357fffffffff00000000000000000000000000000000000000000000000000000000811681146113c057600080fd5b60006020828403121561357257600080fd5b5035919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b600581106135df577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b9052565b60208101610b9a82846135a8565b6001600160a01b03811681146112f757600080fd5b8035613611816135f1565b919050565b6000806040838503121561362957600080fd5b8235613634816135f1565b91506020830135613644816135f1565b809150509250929050565b60008060006060848603121561366457600080fd5b8335925060208401359150604084013561367d816135f1565b809150509250925092565b60006020828403121561369a57600080fd5b81356113c0816135f1565b600080604083850312156136b857600080fd5b823591506020830135613644816135f1565b80151581146112f757600080fd5b8035613611816136ca565b6000806000604084860312156136f857600080fd5b833567ffffffffffffffff8082111561371057600080fd5b818601915086601f83011261372457600080fd5b81358181111561373357600080fd5b8760208260051b850101111561374857600080fd5b6020928301955093505084013561367d816136ca565b60005b83811015613779578181015183820152602001613761565b50506000910152565b6000815180845261379a81602086016020860161375e565b601f01601f19169290920160200192915050565b600060208083018184528085518083526040925060408601915060408160051b87010184880160005b83811015613836578883037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc0018552815180511515845287015187840187905261382387850182613782565b95880195935050908601906001016137d7565b509098975050505050505050565b60008083601f84011261385657600080fd5b50813567ffffffffffffffff81111561386e57600080fd5b60208301915083602082850101111561388657600080fd5b9250929050565b6000806000604084860312156138a257600080fd5b833567ffffffffffffffff8111156138b957600080fd5b6138c586828701613844565b909450925050602084013561367d816135f1565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051610120810167ffffffffffffffff8111828210171561392c5761392c6138d9565b60405290565b60405160a0810167ffffffffffffffff8111828210171561392c5761392c6138d9565b6040516101e0810167ffffffffffffffff8111828210171561392c5761392c6138d9565b604051610180810167ffffffffffffffff8111828210171561392c5761392c6138d9565b604051601f8201601f1916810167ffffffffffffffff811182821017156139c6576139c66138d9565b604052919050565b63ffffffff811681146112f757600080fd5b8035613611816139ce565b600061012082840312156139fe57600080fd5b613a06613908565b9050613a11826139e0565b8152613a1f60208301613606565b6020820152613a3060408301613606565b6040820152613a4160608301613606565b6060820152613a5260808301613606565b608082015260a082013560a082015260c082013560c0820152613a7760e083016136d8565b60e082015261010080830135818301525092915050565b60006101208284031215613aa157600080fd5b6113c083836139eb565b60008060208385031215613abe57600080fd5b823567ffffffffffffffff811115613ad557600080fd5b613ae185828601613844565b90969095509350505050565b60208152613b0460208201835163ffffffff169052565b60006020830151613b1d604084018263ffffffff169052565b5060408301516001600160a01b03811660608401525060608301516001600160a01b03811660808401525060808301516001600160a01b03811660a08401525060a08301516001600160a01b03811660c08401525060c083015160e08381019190915283015161010080840191909152830151610120808401919091528301516101408084019190915283015161016080840191909152830151610180613bce818501836001600160a01b03169052565b8401516101a0848101919091528401516101c0808501919091528401516101e0808501529050613c02610200840182613782565b949350505050565b60808101613c1882876135a8565b63ffffffff8516602083015266ffffffffffffff841660408301526001600160a01b038316606083015295945050505050565b600080600060408486031215613c6057600080fd5b833567ffffffffffffffff811115613c7757600080fd5b613c8386828701613844565b909790965060209590950135949350505050565b60008060408385031215613caa57600080fd5b50508035926020909101359150565b815163ffffffff16815261018081016020830151613cdf602084018263ffffffff169052565b506040830151613cfa60408401826001600160a01b03169052565b506060830151613d1560608401826001600160a01b03169052565b506080830151613d3060808401826001600160a01b03169052565b5060a0830151613d4b60a08401826001600160a01b03169052565b5060c083015160c083015260e083015160e083015261010080840151818401525061012080840151613d808285018215159052565b5050610140838101519083015261016092830151929091019190915290565b600067ffffffffffffffff821115613db957613db96138d9565b50601f01601f191660200190565b600082601f830112613dd857600080fd5b8135613deb613de682613d9f565b61399d565b818152846020838601011115613e0057600080fd5b816020850160208301376000918101602001919091529392505050565b6000806101408385031215613e3157600080fd5b613e3b84846139eb565b915061012083013567ffffffffffffffff80821115613e5957600080fd5b9084019060a08287031215613e6d57600080fd5b613e75613932565b8235613e80816135f1565b815260208381013590820152604083013582811115613e9e57600080fd5b613eaa88828601613dc7565b60408301525060608301356060820152608083013582811115613ecc57600080fd5b613ed888828601613dc7565b6080830152508093505050509250929050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112613f4f57600080fd5b83018035915067ffffffffffffffff821115613f6a57600080fd5b60200191503681900382131561388657600080fd5b8183823760009101908152919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b80820180821115610b9a57610b9a613f8f565b818352818160208501375060006020828401015260006020601f19601f840116840101905092915050565b602081526000613c02602083018486613fd1565b8051613611816139ce565b8051613611816135f1565b600082601f83011261403757600080fd5b8151614045613de682613d9f565b81815284602083860101111561405a57600080fd5b613c0282602083016020870161375e565b60006020828403121561407d57600080fd5b815167ffffffffffffffff8082111561409557600080fd5b908301906101e082860312156140aa57600080fd5b6140b2613955565b6140bb83614010565b81526140c960208401614010565b60208201526140da6040840161401b565b60408201526140eb6060840161401b565b60608201526140fc6080840161401b565b608082015261410d60a0840161401b565b60a082015260c0838101519082015260e0808401519082015261010080840151908201526101208084015190820152610140808401519082015261016061415581850161401b565b9082015261018083810151908201526101a080840151908201526101c0808401518381111561418357600080fd5b61418f88828701614026565b918301919091525095945050505050565b600061018082840312156141b357600080fd5b6141bb613979565b6141c4836139e0565b81526141d2602084016139e0565b60208201526141e360408401613606565b60408201526141f460608401613606565b606082015261420560808401613606565b608082015261421660a08401613606565b60a082015260c083013560c082015260e083013560e08201526101008084013581830152506101206142498185016136d8565b908201526101408381013590820152610160928301359281019290925250919050565b808201828112600083128015821682158216171561428c5761428c613f8f565b505092915050565b8082028115828204841417610b9a57610b9a613f8f565b6000826142e1577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b81810381811115610b9a57610b9a613f8f565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820361432a5761432a613f8f565b5060010190565b60e08152600061434460e083018a613782565b63ffffffff989098166020830152506001600160a01b039586166040820152939094166060840152608083019190915260a082015290151560c090910152919050565b6020815260006113c06020830184613782565b600080858511156143aa57600080fd5b838611156143b757600080fd5b5050820193919092039150565b6001600160a01b0385168152836020820152606060408201526000613315606083018486613fd1565b8051602080830151919081101561442c577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8160200360031b1b821691505b50919050565b60006020828403121561444457600080fd5b5051919050565b60008a5161445d818460208f0161375e565b80830190508a81528960208201528860408201528760608201527fffffffffffffffffffffffffffffffffffffffff0000000000000000000000008760601b1660808201528560948201528460b482015283516144c18160d484016020880161375e565b0160d4019b9a5050505050505050505050565b6000602082840312156144e657600080fd5b81516113c0816136ca565b6000825161450381846020870161375e565b9190910192915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fdfea26469706673582212209a48ddc6013fa0ddcb3b8a930e8c7e75c40dab4d351f72ddd07978c3a1539f2764736f6c63430008180033","runtime-code":"0x60806040526004361061031e5760003560e01c8063886d36ff116101a5578063add98c70116100ec578063c63ff8dd11610095578063ccc574901161006f578063ccc5749014610aad578063d547741f14610ae1578063dcf844a714610b01578063e00a83e014610b2e57600080fd5b8063c63ff8dd146109e0578063c79371b114610a00578063ca15c87314610a8d57600080fd5b8063b250fe6b116100c6578063b250fe6b14610996578063bf333f2c146109b6578063bfc7c607146109cd57600080fd5b8063add98c7014610922578063affed0e014610942578063b13aa2d61461097657600080fd5b80639c9545f01161014e578063a5bbe22b11610128578063a5bbe22b146106ca578063aa9641ab146108d5578063ac11fb1a146108f557600080fd5b80639c9545f014610879578063a217fddf1461088c578063a3ec191a146108a157600080fd5b806391ad50391161017f57806391ad50391461077b57806391d1485414610801578063926d7d7f1461084557600080fd5b8063886d36ff146107285780638f0d6f17146107485780639010d07c1461075b57600080fd5b8063385c1d2f116102695780635960ccf21161021257806363787e52116101ec57806363787e5214610650578063820688d5146106ca5780638379a24f146106e057600080fd5b80635960ccf2146105cf5780635aa6ccba146106035780635eb7d9461461063057600080fd5b80634585169411610243578063458516941461059057806354eff068146105a357806358f85880146105b957600080fd5b8063385c1d2f146105235780633f61331d1461055057806341fcb6121461057057600080fd5b806318e4357d116102cb578063295710ff116102a5578063295710ff146104b65780632f2ff15d146104e357806336568abe1461050357600080fd5b806318e4357d1461044f578063190da5951461046f578063248a9ca31461048657600080fd5b806306f333f2116102fc57806306f333f2146103d75780630f5f6ed7146103f95780630f862f1e1461040f57600080fd5b806301ffc9a71461032357806303ed0ee514610358578063051287bc1461039a575b600080fd5b34801561032f57600080fd5b5061034361033e36600461351e565b610b44565b60405190151581526020015b60405180910390f35b34801561036457600080fd5b5061038c7f043c983c49d46f0e102151eaf8085d4a2e6571d5df2d47b013f39bddfd4a639d81565b60405190815260200161034f565b3480156103a657600080fd5b506103ca6103b5366004613560565b60009081526005602052604090205460ff1690565b60405161034f91906135e3565b3480156103e357600080fd5b506103f76103f2366004613616565b610ba0565b005b34801561040557600080fd5b5061038c61271081565b34801561041b57600080fd5b5061043773eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee81565b6040516001600160a01b03909116815260200161034f565b34801561045b57600080fd5b506103f761046a36600461364f565b610c67565b34801561047b57600080fd5b5061038c62093a8081565b34801561049257600080fd5b5061038c6104a1366004613560565b60009081526020819052604090206001015490565b3480156104c257600080fd5b5061038c6104d1366004613688565b60076020526000908152604090205481565b3480156104ef57600080fd5b506103f76104fe3660046136a5565b610d7c565b34801561050f57600080fd5b506103f761051e3660046136a5565b610da7565b34801561052f57600080fd5b5061054361053e3660046136e3565b610df3565b60405161034f91906137ae565b34801561055c57600080fd5b506103f761056b3660046136e3565b610f81565b34801561057c57600080fd5b506103f761058b36600461388d565b61102b565b6103f761059e366004613a8e565b61129d565b3480156105af57600080fd5b5061038c61ffff81565b3480156105c557600080fd5b5061038c60025481565b3480156105db57600080fd5b5061038c7fdb9556138406326f00296e13ea2ad7db24ba82381212d816b1a40c23b466b32781565b34801561060f57600080fd5b5061062361061e366004613aab565b6112fa565b60405161034f9190613aed565b34801561063c57600080fd5b506103f761064b366004613aab565b6113c7565b34801561065c57600080fd5b506106ba61066b366004613560565b60056020526000908152604090205460ff811690610100810463ffffffff169065010000000000810466ffffffffffffff16906c0100000000000000000000000090046001600160a01b031684565b60405161034f9493929190613c0a565b3480156106d657600080fd5b5061038c61070881565b3480156106ec57600080fd5b506103436106fb366004613560565b6000908152600660205260409020546c0100000000000000000000000090046001600160a01b0316151590565b34801561073457600080fd5b506103f7610743366004613c4b565b6115c9565b6103f7610756366004613aab565b6115f5565b34801561076757600080fd5b50610437610776366004613c97565b611604565b34801561078757600080fd5b506107d5610796366004613560565b60009081526005602052604090205465010000000000810466ffffffffffffff16916c010000000000000000000000009091046001600160a01b031690565b604080516bffffffffffffffffffffffff90931683526001600160a01b0390911660208301520161034f565b34801561080d57600080fd5b5061034361081c3660046136a5565b6000918252602082815260408084206001600160a01b0393909316845291905290205460ff1690565b34801561085157600080fd5b5061038c7fe2b7fb3b832174769106daebcfd6d1970523240dda11281102db9363b83b0dc481565b6103f761088736600461388d565b61161c565b34801561089857600080fd5b5061038c600081565b3480156108ad57600080fd5b5061038c7f000000000000000000000000000000000000000000000000000000000000000081565b3480156108e157600080fd5b506103436108f03660046136a5565b6118d6565b34801561090157600080fd5b50610915610910366004613aab565b6119ad565b60405161034f9190613cb9565b34801561092e57600080fd5b506103f761093d366004613560565b611b61565b34801561094e57600080fd5b5061038c7f000000000000000000000000000000000000000000000000000000000000000081565b34801561098257600080fd5b506103f7610991366004613560565b611cab565b3480156109a257600080fd5b506103f76109b1366004613560565b611d8d565b3480156109c257600080fd5b5061038c620f424081565b6103f76109db366004613e1d565b611df5565b3480156109ec57600080fd5b506103f76109fb366004613aab565b612084565b348015610a0c57600080fd5b50610a5f610a1b366004613560565b60066020526000908152604090205465ffffffffffff8082169166010000000000008104909116906c0100000000000000000000000090046001600160a01b031683565b6040805165ffffffffffff94851681529390921660208401526001600160a01b03169082015260600161034f565b348015610a9957600080fd5b5061038c610aa8366004613560565b612090565b348015610ab957600080fd5b5061038c7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f5581565b348015610aed57600080fd5b506103f7610afc3660046136a5565b6120a7565b348015610b0d57600080fd5b5061038c610b1c366004613688565b60036020526000908152604090205481565b348015610b3a57600080fd5b5061038c60045481565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f5a05180f000000000000000000000000000000000000000000000000000000001480610b9a5750610b9a826120cc565b92915050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f55610bca81612163565b6001600160a01b03831660009081526003602052604081205490819003610bf15750505050565b6001600160a01b038416600081815260036020526040812055610c1590848361216d565b604080516001600160a01b038087168252851660208201529081018290527f244e51bc38c1452fa8aaf487bcb4bca36c2baa3a5fbdb776b1eabd8dc6d277cd9060600160405180910390a1505b505050565b7fe2b7fb3b832174769106daebcfd6d1970523240dda11281102db9363b83b0dc4610c9181612163565b60008481526005602052604090206001815460ff166004811115610cb757610cb7613579565b14610cee576040517f4145817200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80546001600160a01b0384166c0100000000000000000000000081026bffffffffffffffffffffffff66ffffffffffffff421665010000000000021664ffffffff009093169290921791909117600217825560405185815286907f4ac8af8a2cd87193d64dfc7a3b8d9923b714ec528b18725d080aa1299be0c5e49060200160405180910390a35050505050565b600082815260208190526040902060010154610d9781612163565b610da18383612290565b50505050565b6001600160a01b0381163314610de9576040517f6697b23200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610c6282826122bd565b60608267ffffffffffffffff811115610e0e57610e0e6138d9565b604051908082528060200260200182016040528015610e5457816020015b604080518082019091526000815260606020820152815260200190600190039081610e2c5790505b50905060005b83811015610f795730858583818110610e7557610e75613eeb565b9050602002810190610e879190613f1a565b604051610e95929190613f7f565b600060405180830381855af49150503d8060008114610ed0576040519150601f19603f3d011682016040523d82523d6000602084013e610ed5565b606091505b50838381518110610ee857610ee8613eeb565b6020026020010151600001848481518110610f0557610f05613eeb565b602002602001015160200182905282151515158152505050818181518110610f2f57610f2f613eeb565b602002602001015160000151158015610f46575082155b15610f7157610f71828281518110610f6057610f60613eeb565b6020026020010151602001516122ea565b600101610e5a565b509392505050565b60005b82811015610da15760008030868685818110610fa257610fa2613eeb565b9050602002810190610fb49190613f1a565b604051610fc2929190613f7f565b600060405180830381855af49150503d8060008114610ffd576040519150601f19603f3d011682016040523d82523d6000602084013e611002565b606091505b509150915081158015611013575083155b1561102157611021816122ea565b5050600101610f84565b611035838361232c565b60008383604051611047929190613f7f565b604080519182900390912060008181526005602052919091208054919250906c0100000000000000000000000081046001600160a01b03169060ff81169065010000000000900466ffffffffffffff1660028260048111156110ab576110ab613579565b146110e2576040517f4145817200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6107084282900366ffffffffffffff1611611129576040517f1992d0bd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600160a01b03861661113f57829550611181565b6001600160a01b0383163314611181576040517f4af43a9000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b83547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166003178455603288013560601c605a890135609a8a013580156111f0576001600160a01b038316600090815260036020526040812080548392906111ea908490613fbe565b90915550505b604080516001600160a01b03858116825260208201859052808c1692908916918b917f582211c35a2139ac3bbaac74663c6a1f56c6cbb658b41fe11fd45a82074ac678910160405180910390a47fffffffffffffffffffffffff11111111111111111111111111111111111111126001600160a01b0384160161127c5761127789836123ad565b611290565b6112906001600160a01b0384168a84612476565b5050505050505050505050565b6112f7816040518060a0016040528060006001600160a01b03168152602001600081526020016040518060200160405280600081525081526020016000815260200160405180602001604052806000815250815250611df5565b50565b6113ac604051806101e00160405280600063ffffffff168152602001600063ffffffff16815260200160006001600160a01b0316815260200160006001600160a01b0316815260200160006001600160a01b0316815260200160006001600160a01b03168152602001600081526020016000815260200160008152602001600081526020016000815260200160006001600160a01b031681526020016000815260200160008152602001606081525090565b6113b6838361232c565b6113c083836124ea565b9392505050565b6113d1828261232c565b600082826040516113e3929190613f7f565b604080519182900390912060008181526005602052919091209091506001815460ff16600481111561141757611417613579565b1461144e576040517f4145817200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b3360009081527fd2043bf65931af3dbecf60d0db8f40e4160406d7beb00522f4200cf4944a1eb8602052604090205460ba8501359060ff1661149a5761149762093a8082613fbe565b90505b8042116114d3576040517fe15ff9ea00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b81547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166004178255600a850135606090811c906032870135901c6000611522609a890135605a8a0135613fbe565b604080516001600160a01b03858116825260208201849052825193945086169289927fb4c55c0c9bc613519b920e88748090150b890a875d307f21bea7d4fb2e8bc958928290030190a37fffffffffffffffffffffffff11111111111111111111111111111111111111126001600160a01b038316016115ab576115a683826123ad565b6115bf565b6115bf6001600160a01b0383168483612476565b5050505050505050565b6115d3838361232c565b610c6283836040516115e6929190613f7f565b60405180910390208233610c67565b61160082823361161c565b5050565b60008281526001602052604081206113c0908361268c565b611626838361232c565b60008383604051611638929190613f7f565b6040518091039020905061164e84848385612698565b6040805160608101825265ffffffffffff438116825242811660208084019182526001600160a01b038088168587019081526000888152600690935295822094518554935196519091166c01000000000000000000000000026bffffffffffffffffffffffff9685166601000000000000027fffffffffffffffffffffffffffffffffffffffff0000000000000000000000009094169190941617919091179390931617905561170285601e013560601c90565b9050604685013560601c607a86013561012e8701356001600160a01b03808516908716867ff8ae392d784b1ea5e8881bfa586d81abf07ef4f1e2fc75f7fe51c90f05199a5c60028c013560e01c6040805163ffffffff92909216825260328e0135606090811c60208401526001600160a01b038a1683830152605a8f0135908301526080820188905260a08201879052519081900360c00190a47fffffffffffffffffffffffff11111111111111111111111111111111111111126001600160a01b03841601611842578015611804576040517f846dedc000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b81341461183d576040517f81de0bf300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611890565b80341461187b576040517f81de0bf300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6118906001600160a01b03841633868561282d565b36600061189d8a8a612866565b909250905080156118ba576118b58686868585612882565b6118ca565b34156118ca576118ca86346123ad565b50505050505050505050565b60008281526005602052604081206002815460ff1660048111156118fc576118fc613579565b14611933576040517f4145817200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80546001600160a01b038481166c010000000000000000000000009092041614611989576040517f4af43a9000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b546107086501000000000090910466ffffffffffffff908116420316119392505050565b6040805161018081018252600080825260208201819052818301819052606082018190526080820181905260a0820181905260c0820181905260e0820181905261010082018190526101208201819052610140820181905261016082015290517f5aa6ccba0000000000000000000000000000000000000000000000000000000081523090635aa6ccba90611a489086908690600401613ffc565b600060405180830381865afa925050508015611a8657506040513d6000823e601f3d908101601f19168201604052611a83919081019061406b565b60015b611a9d57611a96828401846141a0565b9050610b9a565b604051806101800160405280826000015163ffffffff168152602001826020015163ffffffff16815260200182604001516001600160a01b0316815260200182606001516001600160a01b0316815260200182608001516001600160a01b031681526020018260a001516001600160a01b031681526020018260c0015181526020018260e0015181526020018261010001518152602001826101a0015160001415151581526020018261012001518152602001826101400151815250915050610b9a565b7f043c983c49d46f0e102151eaf8085d4a2e6571d5df2d47b013f39bddfd4a639d611b8b81612163565b600082815260056020526040902080546c0100000000000000000000000081046001600160a01b03169060ff81169065010000000000900466ffffffffffffff166002826004811115611be057611be0613579565b14611c17576040517f4145817200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6107084282900366ffffffffffffff161115611c5f576040517f3e908aac00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b835464ffffffff001660011784556040516001600160a01b0384169087907f0695cf1d39b3055dcd0fe02d8b47eaf0d5a13e1996de925de59d0ef9b7f7fad490600090a3505050505050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f55611cd581612163565b612710821115611d46576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f6e657746656552617465203e206d61780000000000000000000000000000000060448201526064015b60405180910390fd5b600280549083905560408051828152602081018590527f14914da2bf76024616fbe1859783fcd4dbddcb179b1f3a854949fbf920dcb95791015b60405180910390a1505050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f55611db781612163565b600480549083905560408051828152602081018590527f5cf09b12f3f56b4c564d51b25b40360af6d795198adb61ae0806a36c294323fa9101611d80565b80516000906001600160a01b031615611e1a576020820151611e17904261426c565b90505b611e258383836129de565b6000611e3984606001518560a00151612c62565b90506000806002541115611e7257620f424060025483611e599190614294565b611e6391906142ab565b9050611e6f81836142e6565b91505b6000611f7b604051806101e001604052804663ffffffff168152602001886000015163ffffffff16815260200188602001516001600160a01b0316815260200188604001516001600160a01b0316815260200188606001516001600160a01b0316815260200188608001516001600160a01b031681526020018581526020018860c0015181526020018481526020018861010001518152602001600760008a602001516001600160a01b03166001600160a01b031681526020019081526020016000206000815480929190611f46906142f9565b90915550815287516001600160a01b031660208201526040810187905260608089015190820152608080890151910152612e75565b805160208083019190912060008181526005835260409081902080548b5163ffffffff8116610100027fffffffffffffffffffffffffffffffffffffffffffffffffffffff000000000090921691909117600117909155928a01516060808c015160808d015160c08e0151928d0151945197985094966001600160a01b039093169587957f120ea0364f36cdac7983bcfdd55270ca09d7f9b314a2ebc425a3b01ab1d6403a95612037958b959394938e92909190151590614331565b60405180910390a3807f3120e2bb59c86aca6890191a589a96af3662838efa374fbdcdf4c95bfe4a6c0e87604001516040516120739190614387565b60405180910390a250505050505050565b6116008282600061102b565b6000818152600160205260408120610b9a90612fba565b6000828152602081905260409020600101546120c281612163565b610da183836122bd565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f7965db0b000000000000000000000000000000000000000000000000000000001480610b9a57507f01ffc9a7000000000000000000000000000000000000000000000000000000007fffffffff00000000000000000000000000000000000000000000000000000000831614610b9a565b6112f78133612fc4565b306001600160a01b0383160361218257505050565b8060000361218f57505050565b7fffffffffffffffffffffffff11111111111111111111111111111111111111126001600160a01b0384160161227c576000826001600160a01b03168260405160006040518083038185875af1925050503d806000811461220c576040519150601f19603f3d011682016040523d82523d6000602084013e612211565b606091505b5050905080610da1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f455448207472616e73666572206661696c6564000000000000000000000000006044820152606401611d3d565b610c626001600160a01b0384168383612476565b60008061229d8484613030565b905080156113c0576000848152600160205260409020610f7990846130f8565b6000806122ca848461310d565b905080156113c0576000848152600160205260409020610f7990846131ae565b8051156122fa5780518082602001fd5b6040517f5ead5a9d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61014e811015612368576040517f6ee0e17100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b813560f01c60028114610c62576040517f8bd977e700000000000000000000000000000000000000000000000000000000815261ffff82166004820152602401611d3d565b804710156123e9576040517fcd786059000000000000000000000000000000000000000000000000000000008152306004820152602401611d3d565b6000826001600160a01b03168260405160006040518083038185875af1925050503d8060008114612436576040519150601f19603f3d011682016040523d82523d6000602084013e61243b565b606091505b5050905080610c62576040517f1425ea4200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040516001600160a01b03838116602483015260448201839052610c6291859182169063a9059cbb906064015b604051602081830303815290604052915060e01b6020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff83818316178352505050506131c3565b61259c604051806101e00160405280600063ffffffff168152602001600063ffffffff16815260200160006001600160a01b0316815260200160006001600160a01b0316815260200160006001600160a01b0316815260200160006001600160a01b03168152602001600081526020016000815260200160008152602001600081526020016000815260200160006001600160a01b031681526020016000815260200160008152602001606081525090565b600283013560e090811c82526006840135811c6020830152600a840135606090811c6040840152601e850135811c818401526032850135811c60808401526046850135811c60a0840152605a85013560c0840152607a85013591830191909152609a84013561010083015260ba84013561012083015260da84013561014083015260fa840135901c61016082015261010e83013561018082015261012e8301356101a082015261264c8383612866565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152505050506101c082015292915050565b60006113c0838361323f565b6001600160a01b0381166126d8576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000828152600660205260409020546c0100000000000000000000000090046001600160a01b031615612737576040517fbef7bb7d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600684013560e01c4614612777576040517f7029fdf900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60ba8401354211156127b5576040517f559895a300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60fa84013560601c80158015906127de5750816001600160a01b0316816001600160a01b031614155b80156127ef575061010e8501354211155b15612826576040517f14be123200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5050505050565b6040516001600160a01b038481166024830152838116604483015260648201839052610da19186918216906323b872dd906084016124a3565b3660006128778361014e818761439a565b915091509250929050565b60006128fd868686868660405160240161289f94939291906143c4565b60408051601f198184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fe85e13dd0000000000000000000000000000000000000000000000000000000017905234613269565b9050805160000361293a576040517f1a95ad2600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8051602014612975576040517ff3725cca00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7fe85e13dd0000000000000000000000000000000000000000000000000000000061299f826143ed565b146129d6576040517ff3725cca00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b505050505050565b46836000015163ffffffff1603612a21576040517f7029fdf900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60a08301511580612a34575060c0830151155b15612a6b576040517fe38820c800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60208301516001600160a01b03161580612a90575060408301516001600160a01b0316155b15612ac7576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60608301516001600160a01b03161580612aec575060808301516001600160a01b0316155b15612b23576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b612b2f61070842613fbe565b8361010001511015612b6d576040517f04b7fcc800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61ffff8260800151511115612bae576040517f177a70e100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b606082015115801590612be1575060808301516001600160a01b031673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee145b15612c18576040517f846dedc000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000811280612c2b575082610100015181135b15610c62576040517f352807b900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60007fffffffffffffffffffffffff11111111111111111111111111111111111111126001600160a01b03841601612cd457348214612ccd576040517f81de0bf300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5034610b9a565b3415612d0c576040517f81de0bf300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b826001600160a01b03163b600003612d50576040517f7f523fe800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201526001600160a01b038416906370a0823190602401602060405180830381865afa158015612dad573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612dd19190614432565b9050612de86001600160a01b03841633308561282d565b6040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015281906001600160a01b038516906370a0823190602401602060405180830381865afa158015612e47573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612e6b9190614432565b6113c091906142e6565b8051602080830151604080850151606086810151608088015160a089015160c08a015195517e02000000000000000000000000000000000000000000000000000000000000988101989098527fffffffff0000000000000000000000000000000000000000000000000000000060e0998a1b811660228a01529690981b90951660268701527fffffffffffffffffffffffffffffffffffffffff00000000000000000000000092821b8316602a870152811b8216603e86015292831b8116605285015293821b9093166066830152607a820192909252600090609a0160408051601f198184030181529082905260e08501516101008601516101208701516101408801516101608901516101808a01516101a08b01516101c08c0151979950612fa3988a989060200161444b565b604051602081830303815290604052915050919050565b6000610b9a825490565b6000828152602081815260408083206001600160a01b038516845290915290205460ff16611600576040517fe2517d3f0000000000000000000000000000000000000000000000000000000081526001600160a01b038216600482015260248101839052604401611d3d565b6000828152602081815260408083206001600160a01b038516845290915281205460ff166130f0576000838152602081815260408083206001600160a01b0386168452909152902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790556130a83390565b6001600160a01b0316826001600160a01b0316847f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a4506001610b9a565b506000610b9a565b60006113c0836001600160a01b03841661331f565b6000828152602081815260408083206001600160a01b038516845290915281205460ff16156130f0576000838152602081815260408083206001600160a01b038616808552925280832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016905551339286917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a4506001610b9a565b60006113c0836001600160a01b038416613366565b60006131d86001600160a01b03841683613459565b905080516000141580156131fd5750808060200190518101906131fb91906144d4565b155b15610c62576040517f5274afe70000000000000000000000000000000000000000000000000000000081526001600160a01b0384166004820152602401611d3d565b600082600001828154811061325657613256613eeb565b9060005260206000200154905092915050565b6060814710156132a7576040517fcd786059000000000000000000000000000000000000000000000000000000008152306004820152602401611d3d565b600080856001600160a01b031684866040516132c391906144f1565b60006040518083038185875af1925050503d8060008114613300576040519150601f19603f3d011682016040523d82523d6000602084013e613305565b606091505b5091509150613315868383613467565b9695505050505050565b60008181526001830160205260408120546130f057508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155610b9a565b6000818152600183016020526040812054801561344f57600061338a6001836142e6565b855490915060009061339e906001906142e6565b90508082146134035760008660000182815481106133be576133be613eeb565b90600052602060002001549050808760000184815481106133e1576133e1613eeb565b6000918252602080832090910192909255918252600188019052604090208390555b85548690806134145761341461450d565b600190038181906000526020600020016000905590558560010160008681526020019081526020016000206000905560019350505050610b9a565b6000915050610b9a565b60606113c083836000613269565b60608261347c57613477826134dc565b6113c0565b815115801561349357506001600160a01b0384163b155b156134d5576040517f9996b3150000000000000000000000000000000000000000000000000000000081526001600160a01b0385166004820152602401611d3d565b50806113c0565b8051156134ec5780518082602001fd5b6040517f1425ea4200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006020828403121561353057600080fd5b81357fffffffff00000000000000000000000000000000000000000000000000000000811681146113c057600080fd5b60006020828403121561357257600080fd5b5035919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b600581106135df577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b9052565b60208101610b9a82846135a8565b6001600160a01b03811681146112f757600080fd5b8035613611816135f1565b919050565b6000806040838503121561362957600080fd5b8235613634816135f1565b91506020830135613644816135f1565b809150509250929050565b60008060006060848603121561366457600080fd5b8335925060208401359150604084013561367d816135f1565b809150509250925092565b60006020828403121561369a57600080fd5b81356113c0816135f1565b600080604083850312156136b857600080fd5b823591506020830135613644816135f1565b80151581146112f757600080fd5b8035613611816136ca565b6000806000604084860312156136f857600080fd5b833567ffffffffffffffff8082111561371057600080fd5b818601915086601f83011261372457600080fd5b81358181111561373357600080fd5b8760208260051b850101111561374857600080fd5b6020928301955093505084013561367d816136ca565b60005b83811015613779578181015183820152602001613761565b50506000910152565b6000815180845261379a81602086016020860161375e565b601f01601f19169290920160200192915050565b600060208083018184528085518083526040925060408601915060408160051b87010184880160005b83811015613836578883037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc0018552815180511515845287015187840187905261382387850182613782565b95880195935050908601906001016137d7565b509098975050505050505050565b60008083601f84011261385657600080fd5b50813567ffffffffffffffff81111561386e57600080fd5b60208301915083602082850101111561388657600080fd5b9250929050565b6000806000604084860312156138a257600080fd5b833567ffffffffffffffff8111156138b957600080fd5b6138c586828701613844565b909450925050602084013561367d816135f1565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051610120810167ffffffffffffffff8111828210171561392c5761392c6138d9565b60405290565b60405160a0810167ffffffffffffffff8111828210171561392c5761392c6138d9565b6040516101e0810167ffffffffffffffff8111828210171561392c5761392c6138d9565b604051610180810167ffffffffffffffff8111828210171561392c5761392c6138d9565b604051601f8201601f1916810167ffffffffffffffff811182821017156139c6576139c66138d9565b604052919050565b63ffffffff811681146112f757600080fd5b8035613611816139ce565b600061012082840312156139fe57600080fd5b613a06613908565b9050613a11826139e0565b8152613a1f60208301613606565b6020820152613a3060408301613606565b6040820152613a4160608301613606565b6060820152613a5260808301613606565b608082015260a082013560a082015260c082013560c0820152613a7760e083016136d8565b60e082015261010080830135818301525092915050565b60006101208284031215613aa157600080fd5b6113c083836139eb565b60008060208385031215613abe57600080fd5b823567ffffffffffffffff811115613ad557600080fd5b613ae185828601613844565b90969095509350505050565b60208152613b0460208201835163ffffffff169052565b60006020830151613b1d604084018263ffffffff169052565b5060408301516001600160a01b03811660608401525060608301516001600160a01b03811660808401525060808301516001600160a01b03811660a08401525060a08301516001600160a01b03811660c08401525060c083015160e08381019190915283015161010080840191909152830151610120808401919091528301516101408084019190915283015161016080840191909152830151610180613bce818501836001600160a01b03169052565b8401516101a0848101919091528401516101c0808501919091528401516101e0808501529050613c02610200840182613782565b949350505050565b60808101613c1882876135a8565b63ffffffff8516602083015266ffffffffffffff841660408301526001600160a01b038316606083015295945050505050565b600080600060408486031215613c6057600080fd5b833567ffffffffffffffff811115613c7757600080fd5b613c8386828701613844565b909790965060209590950135949350505050565b60008060408385031215613caa57600080fd5b50508035926020909101359150565b815163ffffffff16815261018081016020830151613cdf602084018263ffffffff169052565b506040830151613cfa60408401826001600160a01b03169052565b506060830151613d1560608401826001600160a01b03169052565b506080830151613d3060808401826001600160a01b03169052565b5060a0830151613d4b60a08401826001600160a01b03169052565b5060c083015160c083015260e083015160e083015261010080840151818401525061012080840151613d808285018215159052565b5050610140838101519083015261016092830151929091019190915290565b600067ffffffffffffffff821115613db957613db96138d9565b50601f01601f191660200190565b600082601f830112613dd857600080fd5b8135613deb613de682613d9f565b61399d565b818152846020838601011115613e0057600080fd5b816020850160208301376000918101602001919091529392505050565b6000806101408385031215613e3157600080fd5b613e3b84846139eb565b915061012083013567ffffffffffffffff80821115613e5957600080fd5b9084019060a08287031215613e6d57600080fd5b613e75613932565b8235613e80816135f1565b815260208381013590820152604083013582811115613e9e57600080fd5b613eaa88828601613dc7565b60408301525060608301356060820152608083013582811115613ecc57600080fd5b613ed888828601613dc7565b6080830152508093505050509250929050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112613f4f57600080fd5b83018035915067ffffffffffffffff821115613f6a57600080fd5b60200191503681900382131561388657600080fd5b8183823760009101908152919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b80820180821115610b9a57610b9a613f8f565b818352818160208501375060006020828401015260006020601f19601f840116840101905092915050565b602081526000613c02602083018486613fd1565b8051613611816139ce565b8051613611816135f1565b600082601f83011261403757600080fd5b8151614045613de682613d9f565b81815284602083860101111561405a57600080fd5b613c0282602083016020870161375e565b60006020828403121561407d57600080fd5b815167ffffffffffffffff8082111561409557600080fd5b908301906101e082860312156140aa57600080fd5b6140b2613955565b6140bb83614010565b81526140c960208401614010565b60208201526140da6040840161401b565b60408201526140eb6060840161401b565b60608201526140fc6080840161401b565b608082015261410d60a0840161401b565b60a082015260c0838101519082015260e0808401519082015261010080840151908201526101208084015190820152610140808401519082015261016061415581850161401b565b9082015261018083810151908201526101a080840151908201526101c0808401518381111561418357600080fd5b61418f88828701614026565b918301919091525095945050505050565b600061018082840312156141b357600080fd5b6141bb613979565b6141c4836139e0565b81526141d2602084016139e0565b60208201526141e360408401613606565b60408201526141f460608401613606565b606082015261420560808401613606565b608082015261421660a08401613606565b60a082015260c083013560c082015260e083013560e08201526101008084013581830152506101206142498185016136d8565b908201526101408381013590820152610160928301359281019290925250919050565b808201828112600083128015821682158216171561428c5761428c613f8f565b505092915050565b8082028115828204841417610b9a57610b9a613f8f565b6000826142e1577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b81810381811115610b9a57610b9a613f8f565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820361432a5761432a613f8f565b5060010190565b60e08152600061434460e083018a613782565b63ffffffff989098166020830152506001600160a01b039586166040820152939094166060840152608083019190915260a082015290151560c090910152919050565b6020815260006113c06020830184613782565b600080858511156143aa57600080fd5b838611156143b757600080fd5b5050820193919092039150565b6001600160a01b0385168152836020820152606060408201526000613315606083018486613fd1565b8051602080830151919081101561442c577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8160200360031b1b821691505b50919050565b60006020828403121561444457600080fd5b5051919050565b60008a5161445d818460208f0161375e565b80830190508a81528960208201528860408201528760608201527fffffffffffffffffffffffffffffffffffffffff0000000000000000000000008760601b1660808201528560948201528460b482015283516144c18160d484016020880161375e565b0160d4019b9a5050505050505050505050565b6000602082840312156144e657600080fd5b81516113c0816136ca565b6000825161450381846020870161375e565b9190910192915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fdfea26469706673582212209a48ddc6013fa0ddcb3b8a930e8c7e75c40dab4d351f72ddd07978c3a1539f2764736f6c63430008180033","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.24 ^0.8.20 ^0.8.4;\n\n// contracts/interfaces/IAdmin.sol\n\ninterface IAdmin {\n // ============ Events ============\n\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n event ChainGasAmountUpdated(uint256 oldChainGasAmount, uint256 newChainGasAmount);\n\n // ============ Methods ============\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n\n function setChainGasAmount(uint256 newChainGasAmount) external;\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IFastBridgeV2Errors.sol\n\ninterface IFastBridgeV2Errors {\n error AmountIncorrect();\n error ChainIncorrect();\n error ExclusivityParamsIncorrect();\n error MsgValueIncorrect();\n error SenderIncorrect();\n error StatusIncorrect();\n error TokenNotContract();\n error ZapDataLengthAboveMax();\n error ZapNativeNotSupported();\n error ZeroAddress();\n\n error RecipientIncorrectReturnValue();\n error RecipientNoReturnValue();\n\n error DeadlineExceeded();\n error DeadlineNotExceeded();\n error DeadlineTooShort();\n error DisputePeriodNotPassed();\n error DisputePeriodPassed();\n error ExclusivityPeriodNotPassed();\n\n error TransactionRelayed();\n}\n\n// contracts/interfaces/IMulticallTarget.sol\n\n/// @notice Interface for a contract that can be called multiple times by the same caller. Inspired by MulticallV3:\n/// https://github.com/mds1/multicall/blob/master/src/Multicall3.sol\ninterface IMulticallTarget {\n struct Result {\n bool success;\n bytes returnData;\n }\n\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external;\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results);\n}\n\n// contracts/interfaces/IZapRecipient.sol\n\ninterface IZapRecipient {\n function zap(address token, uint256 amount, bytes memory zapData) external payable returns (bytes4);\n}\n\n// contracts/libs/Errors.sol\n\nerror DeadlineExceeded();\nerror DeadlineNotExceeded();\nerror DeadlineTooShort();\nerror InsufficientOutputAmount();\n\nerror MsgValueIncorrect();\nerror PoolNotFound();\nerror TokenAddressMismatch();\nerror TokenNotContract();\nerror TokenNotETH();\nerror TokensIdentical();\n\nerror ChainIncorrect();\nerror AmountIncorrect();\nerror ZeroAddress();\n\nerror DisputePeriodNotPassed();\nerror DisputePeriodPassed();\nerror SenderIncorrect();\nerror StatusIncorrect();\nerror TransactionIdIncorrect();\nerror TransactionRelayed();\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// contracts/interfaces/IFastBridgeV2.sol\n\ninterface IFastBridgeV2 is IFastBridge {\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n struct BridgeTxDetails {\n BridgeStatus status;\n uint32 destChainId;\n uint56 proofBlockTimestamp;\n address proofRelayer;\n }\n\n struct BridgeRelay {\n uint48 blockNumber;\n uint48 blockTimestamp;\n address relayer;\n }\n\n /// @notice New params introduced in the FastBridgeV2.\n /// We are passing fields from the older BridgeParams struct outside of this struct\n /// for backwards compatibility.\n /// Note: quoteRelayer and quoteExclusivitySeconds are either both zero (indicating no exclusivity)\n /// or both non-zero (indicating exclusivity for the given period).\n /// Note: zapNative \u003e 0 can NOT be used with destToken = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE (native token)\n /// @param quoteRelayer Relayer that provided the quote for the transaction\n /// @param quoteExclusivitySeconds Period of time the quote relayer is guaranteed exclusivity after user's deposit\n /// @param quoteId Unique quote identifier used for tracking the quote\n /// @param zapNative ETH value to send to the recipient (if any)\n /// @param zapData Parameters for the Zap to the destination recipient (if any)\n struct BridgeParamsV2 {\n address quoteRelayer;\n int256 quoteExclusivitySeconds;\n bytes quoteId;\n uint256 zapNative;\n bytes zapData;\n }\n\n /// @notice Updated bridge transaction struct to include parameters introduced in FastBridgeV2.\n /// Note: only `exclusivityRelayer` can fill such a transaction until `exclusivityEndTime`.\n struct BridgeTransactionV2 {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n // Note: sendChainGas flag from V1 is deprecated\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n address exclusivityRelayer;\n uint256 exclusivityEndTime;\n uint256 zapNative; // ETH value to send to the recipient (if any)\n bytes zapData; // data to pass for the Zap action (if any)\n }\n\n event BridgeQuoteDetails(bytes32 indexed transactionId, bytes quoteId);\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability\n /// to provide temporary exclusivity fill rights for the quote relayer.\n /// @param params The parameters required to bridge\n /// @param paramsV2 The parameters for exclusivity fill rights (optional, can be left empty)\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function relay(bytes memory request, address relayer) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param transactionId The transaction id associated with the encoded bridge transaction to prove\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital.\n /// @notice Can only send funds to the relayer address on the proof.\n /// @param request The encoded bridge transaction to claim on origin chain\n function claim(bytes memory request) external;\n /// @notice Checks if a transaction has been relayed\n /// @param transactionId The ID of the transaction to check\n /// @return True if the transaction has been relayed, false otherwise\n function bridgeRelays(bytes32 transactionId) external view returns (bool);\n\n /// @notice Returns the status of a bridge transaction\n /// @param transactionId The ID of the bridge transaction\n /// @return BridgeStatus Status of the bridge transaction\n function bridgeStatuses(bytes32 transactionId) external view returns (BridgeStatus);\n\n /// @notice Returns the timestamp and relayer of a bridge proof\n /// @param transactionId The ID of the bridge transaction\n /// @return timestamp The timestamp of the bridge proof\n /// @return relayer The relayer address of the bridge proof\n function bridgeProofs(bytes32 transactionId) external view returns (uint96 timestamp, address relayer);\n\n /// @notice Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\n /// @param request The bridge request to decode\n function getBridgeTransactionV2(bytes memory request) external view returns (BridgeTransactionV2 memory);\n}\n\n// contracts/utils/MulticallTarget.sol\n\n// solhint-disable avoid-low-level-calls\n/// @notice Template for a contract that supports batched calls (preserving the msg.sender).\n/// Only calls with zero msg.value could be batched.\nabstract contract MulticallTarget is IMulticallTarget {\n error MulticallTarget__UndeterminedRevert();\n\n /// @notice Perform a batched call to this contract, preserving the msg.sender.\n /// The return data from each call is discarded.\n /// @dev The method is non-payable, so only calls with `msg.value == 0` could be batched.\n /// It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag.\n /// Otherwise, the whole batch call will be reverted with the original revert reason.\n /// @param data List of abi-encoded calldata for the calls to perform.\n /// @param ignoreReverts Whether to ignore the revert errors from the calls.\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external {\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\n if (!success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(result);\n }\n }\n }\n\n /// @notice Perform a batched call to this contract, preserving the msg.sender.\n /// The return data from each call is preserved.\n /// @dev The method is non-payable, so only calls with `msg.value == 0` could be batched.\n /// It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag.\n /// Otherwise, the whole batch call will be reverted with the original revert reason.\n /// @param data List of abi-encoded calldata for the calls to perform.\n /// @param ignoreReverts Whether to ignore the revert errors from the calls.\n /// @return results List of results from the calls: `(success, returnData)`.\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results)\n {\n results = new Result[](data.length);\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (results[i].success, results[i].returnData) = address(this).delegatecall(data[i]);\n if (!results[i].success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(results[i].returnData);\n }\n }\n }\n\n /// @dev Bubbles the revert message from the underlying call.\n /// Note: preserves the same custom error or revert string, if one was used.\n /// Source: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v5.0.2/contracts/utils/Address.sol#L143-L158\n function _bubbleRevert(bytes memory returnData) internal pure {\n // Look for revert reason and bubble it up if present\n if (returnData.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n // solhint-disable-next-line no-inline-assembly\n assembly {\n let returndata_size := mload(returnData)\n revert(add(32, returnData), returndata_size)\n }\n } else {\n revert MulticallTarget__UndeterminedRevert();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// contracts/libs/BridgeTransactionV2.sol\n\n// solhint-disable no-inline-assembly\nlibrary BridgeTransactionV2Lib {\n uint16 internal constant VERSION = 2;\n\n // Offsets of the fields in the packed BridgeTransactionV2 struct\n // uint16 version [000 .. 002)\n // uint32 originChainId [002 .. 006)\n // uint32 destChainId [006 .. 010)\n // address originSender [010 .. 030)\n // address destRecipient [030 .. 050)\n // address originToken [050 .. 070)\n // address destToken [070 .. 090)\n // uint256 originAmount [090 .. 122)\n // uint256 destAmount [122 .. 154)\n // uint256 originFeeAmount [154 .. 186)\n // uint256 deadline [186 .. 218)\n // uint256 nonce [218 .. 250)\n // address exclusivityRelayer [250 .. 270)\n // uint256 exclusivityEndTime [270 .. 302)\n // uint256 zapNative [302 .. 334)\n // bytes zapData [334 .. ***)\n\n // forgefmt: disable-start\n uint256 private constant OFFSET_ORIGIN_CHAIN_ID = 2;\n uint256 private constant OFFSET_DEST_CHAIN_ID = 6;\n uint256 private constant OFFSET_ORIGIN_SENDER = 10;\n uint256 private constant OFFSET_DEST_RECIPIENT = 30;\n uint256 private constant OFFSET_ORIGIN_TOKEN = 50;\n uint256 private constant OFFSET_DEST_TOKEN = 70;\n uint256 private constant OFFSET_ORIGIN_AMOUNT = 90;\n uint256 private constant OFFSET_DEST_AMOUNT = 122;\n uint256 private constant OFFSET_ORIGIN_FEE_AMOUNT = 154;\n uint256 private constant OFFSET_DEADLINE = 186;\n uint256 private constant OFFSET_NONCE = 218;\n uint256 private constant OFFSET_EXCLUSIVITY_RELAYER = 250;\n uint256 private constant OFFSET_EXCLUSIVITY_END_TIME = 270;\n uint256 private constant OFFSET_ZAP_NATIVE = 302;\n uint256 private constant OFFSET_ZAP_DATA = 334;\n // forgefmt: disable-end\n\n error BridgeTransactionV2__InvalidEncodedTx();\n error BridgeTransactionV2__UnsupportedVersion(uint16 version);\n\n /// @notice Validates the encoded transaction to be a tightly packed encoded payload for BridgeTransactionV2.\n /// @dev Checks the minimum length and the version, use this function before decoding any of the fields.\n function validateV2(bytes calldata encodedTx) internal pure {\n // Check the minimum length: must at least include all static fields.\n if (encodedTx.length \u003c OFFSET_ZAP_DATA) revert BridgeTransactionV2__InvalidEncodedTx();\n // Once we validated the length, we can be sure that the version field is present.\n uint16 version_ = version(encodedTx);\n if (version_ != VERSION) revert BridgeTransactionV2__UnsupportedVersion(version_);\n }\n\n /// @notice Encodes the BridgeTransactionV2 struct by tightly packing the fields.\n /// @dev `abi.decode` will not work as a result of the tightly packed fields. Use `decodeV2` to decode instead.\n function encodeV2(IFastBridgeV2.BridgeTransactionV2 memory bridgeTx) internal pure returns (bytes memory) {\n // We split the encoding into two parts to avoid stack-too-deep error\n bytes memory firstPart = abi.encodePacked(\n VERSION,\n bridgeTx.originChainId,\n bridgeTx.destChainId,\n bridgeTx.originSender,\n bridgeTx.destRecipient,\n bridgeTx.originToken,\n bridgeTx.destToken,\n bridgeTx.originAmount\n );\n return abi.encodePacked(\n firstPart,\n bridgeTx.destAmount,\n bridgeTx.originFeeAmount,\n // Note: we skip the deprecated `sendChainGas` flag, which was present in BridgeTransaction V1\n bridgeTx.deadline,\n bridgeTx.nonce,\n // New V2 fields: exclusivity\n bridgeTx.exclusivityRelayer,\n bridgeTx.exclusivityEndTime,\n // New V2 fields: Zap\n bridgeTx.zapNative,\n bridgeTx.zapData\n );\n }\n\n /// @notice Decodes the BridgeTransactionV2 struct from the encoded transaction.\n /// @dev Encoded BridgeTransactionV2 struct must be tightly packed.\n /// Use `validateV2` before decoding to ensure the encoded transaction is valid.\n function decodeV2(bytes calldata encodedTx)\n internal\n pure\n returns (IFastBridgeV2.BridgeTransactionV2 memory bridgeTx)\n {\n bridgeTx.originChainId = originChainId(encodedTx);\n bridgeTx.destChainId = destChainId(encodedTx);\n bridgeTx.originSender = originSender(encodedTx);\n bridgeTx.destRecipient = destRecipient(encodedTx);\n bridgeTx.originToken = originToken(encodedTx);\n bridgeTx.destToken = destToken(encodedTx);\n bridgeTx.originAmount = originAmount(encodedTx);\n bridgeTx.destAmount = destAmount(encodedTx);\n bridgeTx.originFeeAmount = originFeeAmount(encodedTx);\n bridgeTx.deadline = deadline(encodedTx);\n bridgeTx.nonce = nonce(encodedTx);\n bridgeTx.exclusivityRelayer = exclusivityRelayer(encodedTx);\n bridgeTx.exclusivityEndTime = exclusivityEndTime(encodedTx);\n bridgeTx.zapNative = zapNative(encodedTx);\n bridgeTx.zapData = zapData(encodedTx);\n }\n\n /// @notice Extracts the version from the encoded transaction.\n function version(bytes calldata encodedTx) internal pure returns (uint16 version_) {\n // Load 32 bytes from the start and shift it 240 bits to the right to get the highest 16 bits.\n assembly {\n version_ := shr(240, calldataload(encodedTx.offset))\n }\n }\n\n /// @notice Extracts the origin chain ID from the encoded transaction.\n function originChainId(bytes calldata encodedTx) internal pure returns (uint32 originChainId_) {\n // Load 32 bytes from the offset and shift it 224 bits to the right to get the highest 32 bits.\n assembly {\n originChainId_ := shr(224, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_CHAIN_ID)))\n }\n }\n\n /// @notice Extracts the destination chain ID from the encoded transaction.\n function destChainId(bytes calldata encodedTx) internal pure returns (uint32 destChainId_) {\n // Load 32 bytes from the offset and shift it 224 bits to the right to get the highest 32 bits.\n assembly {\n destChainId_ := shr(224, calldataload(add(encodedTx.offset, OFFSET_DEST_CHAIN_ID)))\n }\n }\n\n /// @notice Extracts the origin sender from the encoded transaction.\n function originSender(bytes calldata encodedTx) internal pure returns (address originSender_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n originSender_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_SENDER)))\n }\n }\n\n /// @notice Extracts the destination recipient from the encoded transaction.\n function destRecipient(bytes calldata encodedTx) internal pure returns (address destRecipient_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n destRecipient_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_DEST_RECIPIENT)))\n }\n }\n\n /// @notice Extracts the origin token from the encoded transaction.\n function originToken(bytes calldata encodedTx) internal pure returns (address originToken_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n originToken_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_TOKEN)))\n }\n }\n\n /// @notice Extracts the destination token from the encoded transaction.\n function destToken(bytes calldata encodedTx) internal pure returns (address destToken_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n destToken_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_DEST_TOKEN)))\n }\n }\n\n /// @notice Extracts the origin amount from the encoded transaction.\n function originAmount(bytes calldata encodedTx) internal pure returns (uint256 originAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n originAmount_ := calldataload(add(encodedTx.offset, OFFSET_ORIGIN_AMOUNT))\n }\n }\n\n /// @notice Extracts the destination amount from the encoded transaction.\n function destAmount(bytes calldata encodedTx) internal pure returns (uint256 destAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n destAmount_ := calldataload(add(encodedTx.offset, OFFSET_DEST_AMOUNT))\n }\n }\n\n /// @notice Extracts the origin fee amount from the encoded transaction.\n function originFeeAmount(bytes calldata encodedTx) internal pure returns (uint256 originFeeAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n originFeeAmount_ := calldataload(add(encodedTx.offset, OFFSET_ORIGIN_FEE_AMOUNT))\n }\n }\n\n /// @notice Extracts the deadline from the encoded transaction.\n function deadline(bytes calldata encodedTx) internal pure returns (uint256 deadline_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n deadline_ := calldataload(add(encodedTx.offset, OFFSET_DEADLINE))\n }\n }\n\n /// @notice Extracts the nonce from the encoded transaction.\n function nonce(bytes calldata encodedTx) internal pure returns (uint256 nonce_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n nonce_ := calldataload(add(encodedTx.offset, OFFSET_NONCE))\n }\n }\n\n /// @notice Extracts the exclusivity relayer from the encoded transaction.\n function exclusivityRelayer(bytes calldata encodedTx) internal pure returns (address exclusivityRelayer_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n exclusivityRelayer_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_EXCLUSIVITY_RELAYER)))\n }\n }\n\n /// @notice Extracts the exclusivity end time from the encoded transaction.\n function exclusivityEndTime(bytes calldata encodedTx) internal pure returns (uint256 exclusivityEndTime_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n exclusivityEndTime_ := calldataload(add(encodedTx.offset, OFFSET_EXCLUSIVITY_END_TIME))\n }\n }\n\n /// @notice Extracts the Zap's native value from the encoded transaction.\n function zapNative(bytes calldata encodedTx) internal pure returns (uint256 zapNative_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n zapNative_ := calldataload(add(encodedTx.offset, OFFSET_ZAP_NATIVE))\n }\n }\n\n /// @notice Extracts the Zap's data from the encoded transaction.\n function zapData(bytes calldata encodedTx) internal pure returns (bytes calldata zapData_) {\n zapData_ = encodedTx[OFFSET_ZAP_DATA:];\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// contracts/libs/UniversalToken.sol\n\nlibrary UniversalTokenLib {\n using SafeERC20 for IERC20;\n\n address internal constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Transfers tokens to the given account. Reverts if transfer is not successful.\n /// @dev This might trigger fallback, if ETH is transferred to the contract.\n /// Make sure this can not lead to reentrancy attacks.\n function universalTransfer(address token, address to, uint256 value) internal {\n // Don't do anything, if need to send tokens to this address\n if (to == address(this)) return;\n // Don't do anything, if trying to send zero value\n if (value == 0) return;\n if (token == ETH_ADDRESS) {\n /// @dev Note: this can potentially lead to executing code in `to`.\n // solhint-disable-next-line avoid-low-level-calls\n (bool success,) = to.call{value: value}(\"\");\n require(success, \"ETH transfer failed\");\n } else {\n IERC20(token).safeTransfer(to, value);\n }\n }\n\n /// @notice Issues an infinite allowance to the spender, if the current allowance is insufficient\n /// to spend the given amount.\n function universalApproveInfinity(address token, address spender, uint256 amountToSpend) internal {\n // ETH Chad doesn't require your approval\n if (token == ETH_ADDRESS) return;\n // No-op if allowance is already sufficient\n uint256 allowance = IERC20(token).allowance(address(this), spender);\n if (allowance \u003e= amountToSpend) return;\n // Otherwise, reset approval to 0 and set to max allowance\n if (allowance \u003e 0) IERC20(token).safeDecreaseAllowance(spender, allowance);\n IERC20(token).safeIncreaseAllowance(spender, type(uint256).max);\n }\n\n /// @notice Returns the balance of the given token (or native ETH) for the given account.\n function universalBalanceOf(address token, address account) internal view returns (uint256) {\n if (token == ETH_ADDRESS) {\n return account.balance;\n } else {\n return IERC20(token).balanceOf(account);\n }\n }\n\n /// @dev Checks that token is a contract and not ETH_ADDRESS.\n function assertIsContract(address token) internal view {\n // Check that ETH_ADDRESS was not used (in case this is a predeploy on any of the chains)\n if (token == UniversalTokenLib.ETH_ADDRESS) revert TokenNotContract();\n // Check that token is not an EOA\n if (token.code.length == 0) revert TokenNotContract();\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/Admin.sol\n\ncontract Admin is IAdmin, AccessControlEnumerable {\n using UniversalTokenLib for address;\n\n bytes32 public constant RELAYER_ROLE = keccak256(\"RELAYER_ROLE\");\n bytes32 public constant REFUNDER_ROLE = keccak256(\"REFUNDER_ROLE\");\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n uint256 public constant FEE_BPS = 1e6;\n uint256 public constant FEE_RATE_MAX = 0.01e6; // max 1% on origin amount\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Chain gas amount to forward as rebate if requested\n uint256 public chainGasAmount;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n }\n\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n require(newFeeRate \u003c= FEE_RATE_MAX, \"newFeeRate \u003e max\");\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n token.universalTransfer(recipient, feeAmount);\n emit FeesSwept(token, recipient, feeAmount);\n }\n\n function setChainGasAmount(uint256 newChainGasAmount) external onlyRole(GOVERNOR_ROLE) {\n uint256 oldChainGasAmount = chainGasAmount;\n chainGasAmount = newChainGasAmount;\n emit ChainGasAmountUpdated(oldChainGasAmount, newChainGasAmount);\n }\n}\n\n// contracts/FastBridgeV2.sol\n\n/// @notice FastBridgeV2 is a contract for bridging tokens across chains.\ncontract FastBridgeV2 is Admin, MulticallTarget, IFastBridgeV2, IFastBridgeV2Errors {\n using BridgeTransactionV2Lib for bytes;\n using SafeERC20 for IERC20;\n\n /// @notice Address reserved for native gas token (ETH on Ethereum and most L2s, AVAX on Avalanche, etc)\n address public constant NATIVE_GAS_TOKEN = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Delay for a transaction after which it could be permisionlessly refunded\n uint256 public constant REFUND_DELAY = 7 days;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n /// @notice Maximum length of accepted zapData\n uint256 public constant MAX_ZAP_DATA_LENGTH = 2 ** 16 - 1;\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeTxDetails) public bridgeTxDetails;\n /// @notice Relay details on destination chain\n mapping(bytes32 =\u003e BridgeRelay) public bridgeRelayDetails;\n /// @notice Unique bridge nonces tracked per originSender\n mapping(address =\u003e uint256) public senderNonces;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Replaced by senderNonces\n uint256 public immutable nonce = 0;\n /// @notice the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n bridge({\n params: params,\n paramsV2: BridgeParamsV2({\n quoteRelayer: address(0),\n quoteExclusivitySeconds: 0,\n quoteId: bytes(\"\"),\n zapNative: 0,\n zapData: bytes(\"\")\n })\n });\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes calldata request) external payable {\n // relay override will validate the request\n relay({request: request, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes calldata request, bytes32 destTxHash) external {\n request.validateV2();\n prove({transactionId: keccak256(request), destTxHash: destTxHash, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridgeV2\n function claim(bytes calldata request) external {\n // claim override will validate the request\n claim({request: request, to: address(0)});\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Aggregate the read operations from the same storage slot\n address disputedRelayer = $.proofRelayer;\n BridgeStatus status = $.status;\n uint56 proofBlockTimestamp = $.proofBlockTimestamp;\n // Can only dispute a RELAYER_PROVED transaction within the dispute period\n if (status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(proofBlockTimestamp) \u003e DISPUTE_PERIOD) {\n revert DisputePeriodPassed();\n }\n // Update status to REQUESTED and delete the disputed proof details\n // Note: these are storage writes\n $.status = BridgeStatus.REQUESTED;\n $.proofRelayer = address(0);\n $.proofBlockTimestamp = 0;\n\n emit BridgeProofDisputed(transactionId, disputedRelayer);\n }\n\n /// @inheritdoc IFastBridge\n function refund(bytes calldata request) external {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Can only refund a REQUESTED transaction after its deadline expires\n if ($.status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n uint256 deadline = request.deadline();\n // Permissionless refund is only allowed after REFUND_DELAY on top of the deadline\n if (!hasRole(REFUNDER_ROLE, msg.sender)) deadline += REFUND_DELAY;\n if (block.timestamp \u003c= deadline) revert DeadlineNotExceeded();\n // Update status to REFUNDED and return the full amount (collateral + protocol fees) to the original sender.\n // The protocol fees are only updated when the transaction is claimed, so we don't need to update them here.\n // Note: this is a storage write\n $.status = BridgeStatus.REFUNDED;\n\n address to = request.originSender();\n address token = request.originToken();\n uint256 amount = request.originAmount() + request.originFeeAmount();\n // Emit the event before any external calls\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n // Complete the user refund as the last transaction action\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(to), amount);\n } else {\n IERC20(token).safeTransfer(to, amount);\n }\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // The correct relayer can only claim a RELAYER_PROVED transaction after the dispute period\n if ($.status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if ($.proofRelayer != relayer) revert SenderIncorrect();\n return _timeSince($.proofBlockTimestamp) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n /// @dev This method is added to achieve backwards compatibility with decoding requests into V1 structs:\n /// - `zapNative` is partially reported as a zero/non-zero flag\n /// - `zapData` is ignored\n /// In order to process all kinds of requests use getBridgeTransactionV2 instead.\n function getBridgeTransaction(bytes calldata request) external view returns (BridgeTransaction memory) {\n // Try decoding into V2 struct first. This will revert if V1 struct is passed\n try this.getBridgeTransactionV2(request) returns (BridgeTransactionV2 memory txV2) {\n // Note: we entirely ignore the zapData field, as it was not present in V1\n return BridgeTransaction({\n originChainId: txV2.originChainId,\n destChainId: txV2.destChainId,\n originSender: txV2.originSender,\n destRecipient: txV2.destRecipient,\n originToken: txV2.originToken,\n destToken: txV2.destToken,\n originAmount: txV2.originAmount,\n destAmount: txV2.destAmount,\n originFeeAmount: txV2.originFeeAmount,\n sendChainGas: txV2.zapNative != 0,\n deadline: txV2.deadline,\n nonce: txV2.nonce\n });\n } catch {\n // Fallback to V1 struct\n return abi.decode(request, (BridgeTransaction));\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function getBridgeTransactionV2(bytes calldata request) external pure returns (BridgeTransactionV2 memory) {\n request.validateV2();\n return BridgeTransactionV2Lib.decodeV2(request);\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) public payable {\n int256 exclusivityEndTime = 0;\n // if relayer exclusivity is not intended for this bridge, set exclusivityEndTime to static zero\n // otherwise, set exclusivity to expire at the current block ts offset by quoteExclusivitySeconds\n if (paramsV2.quoteRelayer != address(0)) {\n exclusivityEndTime = int256(block.timestamp) + paramsV2.quoteExclusivitySeconds;\n }\n _validateBridgeParams(params, paramsV2, exclusivityEndTime);\n\n // transfer tokens to bridge contract\n /// @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _takeBridgedUserAsset(params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) {\n originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n }\n\n // set status to requested\n bytes memory request = BridgeTransactionV2Lib.encodeV2(\n BridgeTransactionV2({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n deadline: params.deadline,\n nonce: senderNonces[params.sender]++, // increment nonce on every bridge\n exclusivityRelayer: paramsV2.quoteRelayer,\n // We checked exclusivityEndTime to be in range [0 .. params.deadline] above, so can safely cast\n exclusivityEndTime: uint256(exclusivityEndTime),\n zapNative: paramsV2.zapNative,\n zapData: paramsV2.zapData\n })\n );\n bytes32 transactionId = keccak256(request);\n // Note: the tx status will be updated throughout the tx lifecycle, while destChainId is set once here\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n bridgeTxDetails[transactionId].destChainId = params.dstChainId;\n\n emit BridgeRequested({\n transactionId: transactionId,\n sender: params.sender,\n request: request,\n destChainId: params.dstChainId,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n sendChainGas: paramsV2.zapNative != 0\n });\n emit BridgeQuoteDetails(transactionId, paramsV2.quoteId);\n }\n\n /// @inheritdoc IFastBridgeV2\n function relay(bytes calldata request, address relayer) public payable {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n _validateRelayParams(request, transactionId, relayer);\n // mark bridge transaction as relayed\n bridgeRelayDetails[transactionId] =\n BridgeRelay({blockNumber: uint48(block.number), blockTimestamp: uint48(block.timestamp), relayer: relayer});\n\n // transfer tokens to recipient on destination chain and trigger Zap if requested\n address to = request.destRecipient();\n address token = request.destToken();\n uint256 amount = request.destAmount();\n uint256 zapNative = request.zapNative();\n\n // Emit the event before any external calls\n emit BridgeRelayed({\n transactionId: transactionId,\n relayer: relayer,\n to: to,\n originChainId: request.originChainId(),\n originToken: request.originToken(),\n destToken: token,\n originAmount: request.originAmount(),\n destAmount: amount,\n chainGasAmount: zapNative\n });\n\n // All state changes have been done at this point, can proceed to the external calls.\n // This follows the checks-effects-interactions pattern to mitigate potential reentrancy attacks.\n if (token == NATIVE_GAS_TOKEN) {\n // For the native gas token, additional zapNative is not allowed\n if (zapNative != 0) revert ZapNativeNotSupported();\n // Check that the correct msg.value was sent\n if (msg.value != amount) revert MsgValueIncorrect();\n // Don't do a native transfer yet: we will handle it alongside the Zap below\n } else {\n // For ERC20s, we check that the correct msg.value was sent\n if (msg.value != zapNative) revert MsgValueIncorrect();\n // We need to transfer the tokens from the Relayer to the recipient first before performing an\n // optional post-transfer Zap.\n IERC20(token).safeTransferFrom(msg.sender, to, amount);\n }\n // At this point we have done:\n // - Transferred the requested amount of ERC20 tokens to the recipient.\n // At this point we have confirmed:\n // - For ERC20s: msg.value matches the requested zapNative amount.\n // - For the native gas token: msg.value matches the requested destAmount.\n // Remaining optional things to do:\n // - Forward the full msg.value to the recipient (if non-zero).\n // - Trigger a Zap (if zapData is present).\n bytes calldata zapData = request.zapData();\n if (zapData.length != 0) {\n // Zap Data is present: Zap has been requested by the recipient. Trigger it forwarding the full msg.value.\n\n // Note: if token has a fee on transfers, the recipient will have received less than `amount`.\n // This is a very niche edge case and should be handled by the recipient contract.\n _triggerZapWithChecks({recipient: to, token: token, amount: amount, zapData: zapData});\n } else if (msg.value != 0) {\n // Zap Data is missing, but msg.value was sent. This could happen in two different cases:\n // - Relay with the native gas token is happening.\n // - Relay with ERC20 is happening, with a `zapNative \u003e 0` request.\n // In both cases, we need to transfer the full msg.value to the recipient.\n Address.sendValue(payable(to), msg.value);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) public onlyRole(RELAYER_ROLE) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n\n // Can only prove a REQUESTED transaction\n if ($.status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n // Update status to RELAYER_PROVED and store the proof details\n // Note: these are storage writes\n $.status = BridgeStatus.RELAYER_PROVED;\n $.proofBlockTimestamp = uint56(block.timestamp);\n $.proofRelayer = relayer;\n\n emit BridgeProofProvided(transactionId, relayer, destTxHash);\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes calldata request, address to) public {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Aggregate the read operations from the same storage slot\n address proofRelayer = $.proofRelayer;\n BridgeStatus status = $.status;\n uint56 proofBlockTimestamp = $.proofBlockTimestamp;\n\n // Can only claim a RELAYER_PROVED transaction after the dispute period\n if (status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(proofBlockTimestamp) \u003c= DISPUTE_PERIOD) {\n revert DisputePeriodNotPassed();\n }\n\n if (to == address(0)) {\n // Anyone could claim the funds to the proven relayer on their behalf\n to = proofRelayer;\n } else if (proofRelayer != msg.sender) {\n // Only the proven relayer could specify an address to claim the funds to\n revert SenderIncorrect();\n }\n\n // Update status to RELAYER_CLAIMED and transfer the origin collateral to the specified claim address\n // Note: this is a storage write\n $.status = BridgeStatus.RELAYER_CLAIMED;\n\n address token = request.originToken();\n uint256 amount = request.originAmount();\n // Update protocol fees if origin fee amount exists\n uint256 originFeeAmount = request.originFeeAmount();\n if (originFeeAmount \u003e 0) protocolFees[token] += originFeeAmount;\n // Emit the event before any external calls\n emit BridgeDepositClaimed(transactionId, proofRelayer, to, token, amount);\n // Complete the relayer claim as the last transaction action\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(to), amount);\n } else {\n IERC20(token).safeTransfer(to, amount);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeStatuses(bytes32 transactionId) public view returns (BridgeStatus status) {\n return bridgeTxDetails[transactionId].status;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeProofs(bytes32 transactionId) public view returns (uint96 timestamp, address relayer) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n\n timestamp = $.proofBlockTimestamp;\n relayer = $.proofRelayer;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeRelays(bytes32 transactionId) public view returns (bool) {\n // has this transactionId been relayed?\n return bridgeRelayDetails[transactionId].relayer != address(0);\n }\n\n /// @notice Takes the bridged asset from the user into FastBridgeV2 custody. It will be later\n /// claimed by the relayer who completed the relay on destination chain, or refunded back to the user,\n /// should no one complete the relay.\n function _takeBridgedUserAsset(address token, uint256 amount) internal returns (uint256 amountTaken) {\n if (token == NATIVE_GAS_TOKEN) {\n // For the native gas token, we just need to check that the supplied msg.value is correct.\n // Supplied `msg.value` is already in FastBridgeV2 custody.\n if (amount != msg.value) revert MsgValueIncorrect();\n amountTaken = msg.value;\n } else {\n // For ERC20s, token is explicitly transferred from the user to FastBridgeV2.\n // We don't allow non-zero `msg.value` to avoid extra funds from being stuck in FastBridgeV2.\n if (msg.value != 0) revert MsgValueIncorrect();\n // Throw an explicit error if the provided token address is not a contract\n if (token.code.length == 0) revert TokenNotContract();\n amountTaken = IERC20(token).balanceOf(address(this));\n IERC20(token).safeTransferFrom(msg.sender, address(this), amount);\n // Use the balance difference as the amount taken in case of fee on transfer tokens.\n amountTaken = IERC20(token).balanceOf(address(this)) - amountTaken;\n }\n }\n\n /// @notice Calls the Recipient's hook function with the specified zapData and performs\n /// all the necessary checks for the returned value.\n function _triggerZapWithChecks(address recipient, address token, uint256 amount, bytes calldata zapData) internal {\n // This will bubble any revert messages from the hook function\n bytes memory returnData = Address.functionCallWithValue({\n target: recipient,\n data: abi.encodeCall(IZapRecipient.zap, (token, amount, zapData)),\n // Note: see `relay()` for reasoning behind passing msg.value\n value: msg.value\n });\n // Explicit revert if no return data at all\n if (returnData.length == 0) revert RecipientNoReturnValue();\n // Check that exactly a single return value was returned\n if (returnData.length != 32) revert RecipientIncorrectReturnValue();\n // Return value should be abi-encoded hook function selector\n if (bytes32(returnData) != bytes32(IZapRecipient.zap.selector)) {\n revert RecipientIncorrectReturnValue();\n }\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint56(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint56).max but\n /// proof.timestamp \u003c type(uint56).max via unchecked statement\n /// @param proofBlockTimestamp The bridge proof block timestamp\n /// @return delta Time delta since proof submitted\n function _timeSince(uint56 proofBlockTimestamp) internal view returns (uint256 delta) {\n unchecked {\n delta = uint56(block.timestamp) - proofBlockTimestamp;\n }\n }\n\n /// @notice Performs all the necessary checks for a bridge to happen.\n /// @dev There's no good way to refactor this function to reduce cyclomatic complexity due to\n /// the number of checks that need to be performed, so we skip the code-complexity rule here.\n // solhint-disable-next-line code-complexity\n function _validateBridgeParams(\n BridgeParams memory params,\n BridgeParamsV2 memory paramsV2,\n int256 exclusivityEndTime\n )\n internal\n view\n {\n // Check V1 (legacy) params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.sender == address(0) || params.to == address(0)) revert ZeroAddress();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n // Check V2 params\n if (paramsV2.zapData.length \u003e MAX_ZAP_DATA_LENGTH) revert ZapDataLengthAboveMax();\n if (paramsV2.zapNative != 0 \u0026\u0026 params.destToken == NATIVE_GAS_TOKEN) {\n revert ZapNativeNotSupported();\n }\n // exclusivityEndTime must be in range [0 .. params.deadline]\n if (exclusivityEndTime \u003c 0 || exclusivityEndTime \u003e int256(params.deadline)) {\n revert ExclusivityParamsIncorrect();\n }\n }\n\n /// @notice Performs all the necessary checks for a relay to happen.\n function _validateRelayParams(bytes calldata request, bytes32 transactionId, address relayer) internal view {\n if (relayer == address(0)) revert ZeroAddress();\n // Check if the transaction has already been relayed\n if (bridgeRelays(transactionId)) revert TransactionRelayed();\n if (request.destChainId() != block.chainid) revert ChainIncorrect();\n // Check the deadline for relay to happen\n if (block.timestamp \u003e request.deadline()) revert DeadlineExceeded();\n // Check the exclusivity period, if it is still ongoing\n address exclRelayer = request.exclusivityRelayer();\n if (exclRelayer != address(0) \u0026\u0026 exclRelayer != relayer \u0026\u0026 block.timestamp \u003c= request.exclusivityEndTime()) {\n revert ExclusivityPeriodNotPassed();\n }\n }\n}\n","language":"Solidity","languageVersion":"0.8.24","compilerVersion":"0.8.24","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"80829:22781:0:-:0;;;82190:1;82157:34;;82295:85;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;82329:6;79744:38;68916:4;82329:6;79744:10;:38::i;:::-;-1:-1:-1;;82361:12:0::1;82347:26;::::0;-1:-1:-1;80829:22781:0;;78229:257;78315:4;;78346:31;78363:4;78369:7;78346:16;:31::i;:::-;78331:46;;78391:7;78387:69;;;78414:18;;;;:12;:18;;;;;:31;;78437:7;78414:22;:31::i;:::-;;78387:69;78472:7;-1:-1:-1;78229:257:0;;;;;:::o;72863:316::-;72940:4;69638:12;;;;;;;;;;;-1:-1:-1;;;;;69638:29:0;;;;;;;;;;;;72956:217;;72999:6;:12;;;;;;;;;;;-1:-1:-1;;;;;72999:29:0;;;;;;;;;:36;;-1:-1:-1;;72999:36:0;73031:4;72999:36;;;73081:12;23872:10;;23793:96;73081:12;-1:-1:-1;;;;;73054:40:0;73072:7;-1:-1:-1;;;;;73054:40:0;73066:4;73054:40;;;;;;;;;;-1:-1:-1;73115:4:0;73108:11;;72956:217;-1:-1:-1;73157:5:0;73150:12;;33317:150;33387:4;33410:50;33415:3;-1:-1:-1;;;;;33435:23:0;;27305:4;29361:21;;;:14;;;:21;;;;;;27321:321;;-1:-1:-1;27363:23:0;;;;;;;;:11;:23;;;;;;;;;;;;;27545:18;;27521:21;;;:14;;;:21;;;;;;:42;;;;27577:11;;14:290:1;84:6;137:2;125:9;116:7;112:23;108:32;105:52;;;153:1;150;143:12;105:52;179:16;;-1:-1:-1;;;;;224:31:1;;214:42;;204:70;;270:1;267;260:12;14:290;80829:22781:0;;;;;;;;;;;;;;;;;;","srcMapRuntime":"80829:22781:0:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;76889:212;;;;;;;;;;-1:-1:-1;76889:212:0;;;;;:::i;:::-;;:::i;:::-;;;612:14:1;;605:22;587:41;;575:2;560:18;76889:212:0;;;;;;;;79119:60;;;;;;;;;;;;79156:23;79119:60;;;;;785:25:1;;;773:2;758:18;79119:60:0;639:177:1;97373:150:0;;;;;;;;;;-1:-1:-1;97373:150:0;;;;;:::i;:::-;97441:19;97479:30;;;:15;:30;;;;;:37;;;;97373:150;;;;;;;;:::i;80091:359::-;;;;;;;;;;-1:-1:-1;80091:359:0;;;;;:::i;:::-;;:::i;:::-;;79301:45;;;;;;;;;;;;79340:6;79301:45;;81105:85;;;;;;;;;;;;81148:42;81105:85;;;;;-1:-1:-1;;;;;2885:55:1;;;2867:74;;2855:2;2840:18;81105:85:0;2721:226:1;94762:628:0;;;;;;;;;;-1:-1:-1;94762:628:0;;;;;:::i;:::-;;:::i;81400:45::-;;;;;;;;;;;;81439:6;81400:45;;70494:120;;;;;;;;;;-1:-1:-1;70494:120:0;;;;;:::i;:::-;70559:7;70585:12;;;;;;;;;;:22;;;;70494:120;82006:47;;;;;;;;;;-1:-1:-1;82006:47:0;;;;;:::i;:::-;;;;;;;;;;;;;;70910:136;;;;;;;;;;-1:-1:-1;70910:136:0;;;;;:::i;:::-;;:::i;72012:245::-;;;;;;;;;;-1:-1:-1;72012:245:0;;;;;:::i;:::-;;:::i;45772:875::-;;;;;;;;;;-1:-1:-1;45772:875:0;;;;;:::i;:::-;;:::i;:::-;;;;;;;:::i;44371:718::-;;;;;;;;;;-1:-1:-1;44371:718:0;;;;;:::i;:::-;;:::i;95428:1905::-;;;;;;;;;;-1:-1:-1;95428:1905:0;;;;;:::i;:::-;;:::i;82418:366::-;;;;;;:::i;:::-;;:::i;81646:57::-;;;;;;;;;;;;81692:11;81646:57;;79463:30;;;;;;;;;;;;;;;;79047:66;;;;;;;;;;;;79087:26;79047:66;;87939:201;;;;;;;;;;-1:-1:-1;87939:201:0;;;;;:::i;:::-;;:::i;:::-;;;;;;;:::i;84446:1490::-;;;;;;;;;;-1:-1:-1;84446:1490:0;;;;;:::i;:::-;;:::i;81766:58::-;;;;;;;;;;-1:-1:-1;81766:58:0;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;81766:58:0;;;;;;;;;;;;;:::i;81532:56::-;;;;;;;;;;;;81578:10;81532:56;;97857:199;;;;;;;;;;-1:-1:-1;97857:199:0;;;;;:::i;:::-;97923:4;97994:33;;;:18;:33;;;;;:41;;;;-1:-1:-1;;;;;97994:41:0;:55;;;97857:199;83031:202;;;;;;;;;;-1:-1:-1;83031:202:0;;;;;:::i;:::-;;:::i;82822:171::-;;;;;;:::i;:::-;;:::i;77686:142::-;;;;;;;;;;-1:-1:-1;77686:142:0;;;;;:::i;:::-;;:::i;97563:254::-;;;;;;;;;;-1:-1:-1;97563:254:0;;;;;:::i;:::-;97629:16;97702:30;;;:15;:30;;;;;97755:21;;;;;;;97796:14;;;;-1:-1:-1;;;;;97796:14:0;;97563:254;;;;;14243:26:1;14231:39;;;14213:58;;-1:-1:-1;;;;;14307:55:1;;;14302:2;14287:18;;14280:83;14186:18;97563:254:0;14041:328:1;69538:136:0;;;;;;;;;;-1:-1:-1;69538:136:0;;;;;:::i;:::-;69615:4;69638:12;;;;;;;;;;;-1:-1:-1;;;;;69638:29:0;;;;;;;;;;;;;;;69538:136;78977:64;;;;;;;;;;;;79016:25;78977:64;;91163:3559;;;;;;:::i;:::-;;:::i;68871:49::-;;;;;;;;;;-1:-1:-1;68871:49:0;68916:4;68871:49;;82252:36;;;;;;;;;;;;;;;85974:473;;;;;;;;;;-1:-1:-1;85974:473:0;;;;;:::i;:::-;;:::i;86779:1120::-;;;;;;;;;;-1:-1:-1;86779:1120:0;;;;;:::i;:::-;;:::i;:::-;;;;;;;:::i;83469:939::-;;;;;;;;;;-1:-1:-1;83469:939:0;;;;;:::i;:::-;;:::i;82157:34::-;;;;;;;;;;;;;;;79795:290;;;;;;;;;;-1:-1:-1;79795:290:0;;;;;:::i;:::-;;:::i;80456:264::-;;;;;;;;;;-1:-1:-1;80456:264:0;;;;;:::i;:::-;;:::i;79258:37::-;;;;;;;;;;;;79292:3;79258:37;;88180:2943;;;;;;:::i;:::-;;:::i;83273:158::-;;;;;;;;;;-1:-1:-1;83273:158:0;;;;;:::i;:::-;;:::i;81881:57::-;;;;;;;;;;-1:-1:-1;81881:57:0;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;81881:57:0;;;;;;;18029:14:1;18070:15;;;18052:34;;18122:15;;;;18117:2;18102:18;;18095:43;-1:-1:-1;;;;;18174:55:1;18154:18;;;18147:83;18007:2;17992:18;81881:57:0;17821:415:1;77996:131:0;;;;;;;;;;-1:-1:-1;77996:131:0;;;;;:::i;:::-;;:::i;79185:66::-;;;;;;;;;;;;79225:26;79185:66;;71326:138;;;;;;;;;;-1:-1:-1;71326:138:0;;;;;:::i;:::-;;:::i;79549:47::-;;;;;;;;;;-1:-1:-1;79549:47:0;;;;;:::i;:::-;;;;;;;;;;;;;;79670:29;;;;;;;;;;;;;;;;76889:212;76974:4;76997:57;;;77012:42;76997:57;;:97;;;77058:36;77082:11;77058:23;:36::i;:::-;76990:104;76889:212;-1:-1:-1;;76889:212:0:o;80091:359::-;79225:26;69148:16;69159:4;69148:10;:16::i;:::-;-1:-1:-1;;;;;80215:19:0;::::1;80195:17;80215:19:::0;;;:12:::1;:19;::::0;;;;;;80248:14;;;80244:27:::1;;80264:7;80091:359:::0;;;:::o;80244:27::-:1;-1:-1:-1::0;;;;;80312:19:0;::::1;80334:1;80312:19:::0;;;:12:::1;:19;::::0;;;;:23;80345:45:::1;::::0;80369:9;80380;80345:23:::1;:45::i;:::-;80405:38;::::0;;-1:-1:-1;;;;;18522:15:1;;;18504:34;;18574:15;;18569:2;18554:18;;18547:43;18606:18;;;18599:34;;;80405:38:0::1;::::0;18431:2:1;18416:18;80405:38:0::1;;;;;;;80185:265;69174:1;80091:359:::0;;;:::o;94762:628::-;79016:25;69148:16;69159:4;69148:10;:16::i;:::-;94877:25:::1;94905:30:::0;;;:15:::1;:30;::::0;;;;95012:22:::1;95000:8:::0;;::::1;;:34;::::0;::::1;;;;;;:::i;:::-;;94996:64;;95043:17;;;;;;;;;;;;;;94996:64;95183:38:::0;;-1:-1:-1;;;;;95288:24:0;::::1;::::0;;::::1;::::0;95231:47:::1;95262:15;95231:47;::::0;::::1;95288:24:::0;;;;;;;;;;;;;95194:27:::1;95288:24:::0;;;95328:55:::1;::::0;785:25:1;;;95348:13:0;;95328:55:::1;::::0;773:2:1;758:18;95328:55:0::1;;;;;;;94867:523;94762:628:::0;;;;:::o;70910:136::-;70559:7;70585:12;;;;;;;;;;:22;;;69148:16;69159:4;69148:10;:16::i;:::-;71014:25:::1;71025:4;71031:7;71014:10;:25::i;:::-;;70910:136:::0;;;:::o;72012:245::-;-1:-1:-1;;;;;72105:34:0;;23872:10;72105:34;72101:102;;72162:30;;;;;;;;;;;;;;72101:102;72213:37;72225:4;72231:18;72213:11;:37::i;45772:875::-;45901:23;45963:4;45950:25;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;;;;;;;;;;;;;45950:25:0;;;;;;;;;;;;;;;;45940:35;;45990:9;45985:656;46005:15;;;45985:656;;;46478:4;46497;;46502:1;46497:7;;;;;;;:::i;:::-;;;;;;;;;;;;:::i;:::-;46470:35;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;46425:7;46433:1;46425:10;;;;;;;;:::i;:::-;;;;;;;:18;;46445:7;46453:1;46445:10;;;;;;;;:::i;:::-;;;;;;;:21;;46424:81;;;;;;;;;;;;;46524:7;46532:1;46524:10;;;;;;;;:::i;:::-;;;;;;;:18;;;46523:19;:37;;;;;46547:13;46546:14;46523:37;46519:112;;;46580:36;46594:7;46602:1;46594:10;;;;;;;;:::i;:::-;;;;;;;:21;;;46580:13;:36::i;:::-;46022:3;;45985:656;;;;45772:875;;;;;:::o;44371:718::-;44466:9;44461:622;44481:15;;;44461:622;;;44901:12;;44946:4;44965;;44970:1;44965:7;;;;;;;:::i;:::-;;;;;;;;;;;;:::i;:::-;44938:35;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;44900:73;;;;44992:7;44991:8;:26;;;;;45004:13;45003:14;44991:26;44987:86;;;45037:21;45051:6;45037:13;:21::i;:::-;-1:-1:-1;;44498:3:0;;44461:622;;95428:1905;95496:20;:7;;:18;:20::i;:::-;95526:21;95560:7;;95550:18;;;;;;;:::i;:::-;;;;;;;;;;;95578:25;95606:30;;;:15;:30;;;;;;95737:14;;95550:18;;-1:-1:-1;95606:30:0;95737:14;;;-1:-1:-1;;;;;95737:14:0;;95783:8;;;;95830:21;;;;;95956:27;95946:6;:37;;;;;;;;:::i;:::-;;95942:67;;95992:17;;;;;;;;;;;;;;95942:67;81294:10;101199:15;101192:45;;;101184:53;;96023:49;96019:111;;96095:24;;;;;;;;;;;;;;96019:111;-1:-1:-1;;;;;96144:16:0;;96140:319;;96263:12;96258:17;;96140:319;;;-1:-1:-1;;;;;96296:26:0;;96312:10;96296:26;96292:167;;96431:17;;;;;;;;;;;;;;96292:167;96620:39;;;;96631:28;96620:39;;;57393:19;57371:42;;57358:56;57354:2;57350:65;58183:20;58161:43;;58148:57;58971:24;58949:47;;58936:61;96891:19;;96887:63;;-1:-1:-1;;;;;96912:19:0;;;;;;:12;:19;;;;;:38;;96935:15;;96912:19;:38;;96935:15;;96912:38;:::i;:::-;;;;-1:-1:-1;;96887:63:0;97017:68;;;-1:-1:-1;;;;;20205:55:1;;;20187:74;;20292:2;20277:18;;20270:34;;;97017:68:0;;;;;;;;97038:13;;97017:68;;20160:18:1;97017:68:0;;;;;;;97168:25;-1:-1:-1;;;;;97168:25:0;;;97164:163;;97209:38;97235:2;97240:6;97209:17;:38::i;:::-;97164:163;;;97278:38;-1:-1:-1;;;;;97278:26:0;;97305:2;97309:6;97278:26;:38::i;:::-;95486:1847;;;;;;;;95428:1905;;;:::o;82418:366::-;82489:288;82518:6;82548:218;;;;;;;;82603:1;-1:-1:-1;;;;;82548:218:0;;;;;82648:1;82548:218;;;;82676:9;;;;;;;;;;;;82548:218;;;;82714:1;82548:218;;;;82742:9;;;;;;;;;;;;82548:218;;;82489:6;:288::i;:::-;82418:366;:::o;87939:201::-;88018:26;-1:-1:-1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;88018:26:0;88056:20;:7;;:18;:20::i;:::-;88093:40;88125:7;;88093:31;:40::i;:::-;88086:47;87939:201;-1:-1:-1;;;87939:201:0:o;84446:1490::-;84505:20;:7;;:18;:20::i;:::-;84535:21;84569:7;;84559:18;;;;;;;:::i;:::-;;;;;;;;;;;84587:25;84615:30;;;:15;:30;;;;;;84559:18;;-1:-1:-1;84749:22:0;84737:8;;;;:34;;;;;;;;:::i;:::-;;84733:64;;84780:17;;;;;;;;;;;;;;84733:64;84973:10;84807:16;69638:29;;;:12;;:29;:12;:29;;;59347:15;59325:38;;59312:52;;69638:29;;84945:65;;84986:24;81439:6;84986:24;;:::i;:::-;;;84945:65;85043:8;85024:15;:27;85020:61;;85060:21;;;;;;;;;;;;;;85020:61;85366:32;;;;85377:21;85366:32;;;56567:20;56545:43;;56532:57;56528:2;56524:66;;;;57393:19;57371:42;;57358:56;57350:65;;-1:-1:-1;85518:50:0;58971:24;58949:47;;58936:61;58183:20;58161:43;;58148:57;85518:50;:::i;:::-;85635:55;;;-1:-1:-1;;;;;20205:55:1;;;20187:74;;20292:2;20277:18;;20270:34;;;85635:55:0;;20270:34:1;;-1:-1:-1;85635:55:0;;;85657:13;;85635:55;;;;;;;;85771:25;-1:-1:-1;;;;;85771:25:0;;;85767:163;;85812:38;85838:2;85843:6;85812:17;:38::i;:::-;85767:163;;;85881:38;-1:-1:-1;;;;;85881:26:0;;85908:2;85912:6;85881:26;:38::i;:::-;84495:1441;;;;;;84446:1490;;:::o;83031:202::-;83109:20;:7;;:18;:20::i;:::-;83139:87;83171:7;;83161:18;;;;;;;:::i;:::-;;;;;;;;83193:10;83214;83139:5;:87::i;82822:171::-;82940:46;82956:7;;82974:10;82940:5;:46::i;:::-;82822:171;;:::o;77686:142::-;77767:7;77793:18;;;:12;:18;;;;;:28;;77815:5;77793:21;:28::i;91163:3559::-;91244:20;:7;;:18;:20::i;:::-;91274:21;91308:7;;91298:18;;;;;;;:::i;:::-;;;;;;;;91274:42;;91326:53;91347:7;;91356:13;91371:7;91326:20;:53::i;:::-;91483:107;;;;;;;;;91516:12;91483:107;;;;91554:15;91483:107;;;;;;;;;-1:-1:-1;;;;;91483:107:0;;;;;;;;;-1:-1:-1;91435:33:0;;;:18;:33;;;;;;:155;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;91704:23;:7;56987:21;56965:44;56952:58;56948:2;56944:67;;56693:334;91704:23;91691:36;-1:-1:-1;57796:17:0;57774:40;;57761:54;57757:2;57753:63;58571:18;58549:41;;58536:55;60939:17;60917:40;;60904:54;-1:-1:-1;;;;;91936:368:0;;;;;;91979:13;91936:368;55743:22;55721:45;;55708:59;55703:3;55699:69;91936:368;;;20630:10:1;20618:23;;;;20600:42;;57393:19:0;57371:42;;57358:56;57354:2;57350:65;;;20734:2:1;20719:18;;20712:43;-1:-1:-1;;;;;20791:15:1;;20771:18;;;20764:43;58183:20:0;58161:43;;58148:57;20823:18:1;;;20816:34;20881:3;20866:19;;20859:35;;;20925:3;20910:19;;20903:35;;;91936:368:0;;;;;20587:3:1;91936:368:0;;;92519:25;-1:-1:-1;;;;;92519:25:0;;;92515:769;;92641:14;;92637:50;;92664:23;;;;;;;;;;;;;;92637:50;92775:6;92762:9;:19;92758:51;;92790:19;;;;;;;;;;;;;;92758:51;92515:769;;;93018:9;93005;:22;93001:54;;93036:19;;;;;;;;;;;;;;93001:54;93219;-1:-1:-1;;;;;93219:30:0;;93250:10;93262:2;93266:6;93219:30;:54::i;:::-;93782:22;;93807:17;:7;;:15;:17::i;:::-;93782:42;;-1:-1:-1;93782:42:0;-1:-1:-1;93838:19:0;;93834:882;;94195:86;94229:2;94240:5;94255:6;94272:7;;94195:21;:86::i;:::-;93834:882;;;94302:9;:14;94298:418;;94664:41;94690:2;94695:9;94664:17;:41::i;:::-;91234:3488;;;;;;;91163:3559;;;:::o;85974:473::-;86055:4;86099:30;;;:15;:30;;;;;86255:27;86243:8;;;;:39;;;;;;;;:::i;:::-;;86239:69;;86291:17;;;;;;;;;;;;;;86239:69;86322:14;;-1:-1:-1;;;;;86322:25:0;;;:14;;;;;:25;86318:55;;86356:17;;;;;;;;;;;;;;86318:55;86401:21;81294:10;86401:21;;;;;;;;101199:15;101192:45;101184:53;86390:50;;;-1:-1:-1;;;85974:473:0:o;86779:1120::-;-1:-1:-1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;86982:36:0;;;;;:4;;:27;;:36;;87010:7;;;;86982:36;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;86982:36:0;;;;;;;;;;;;:::i;:::-;;;86978:915;;87842:40;;;;87853:7;87842:40;:::i;:::-;87835:47;;;;86978:915;87169:597;;;;;;;;87220:4;:18;;;87169:597;;;;;;87269:4;:16;;;87169:597;;;;;;87317:4;:17;;;-1:-1:-1;;;;;87169:597:0;;;;;87367:4;:18;;;-1:-1:-1;;;;;87169:597:0;;;;;87416:4;:16;;;-1:-1:-1;;;;;87169:597:0;;;;;87461:4;:14;;;-1:-1:-1;;;;;87169:597:0;;;;;87507:4;:17;;;87169:597;;;;87554:4;:15;;;87169:597;;;;87604:4;:20;;;87169:597;;;;87656:4;:14;;;87674:1;87656:19;;87169:597;;;;;;87703:4;:13;;;87169:597;;;;87741:4;:10;;;87169:597;;;87162:604;;;;;83469:939;79156:23;69148:16;69159:4;69148:10;:16::i;:::-;83549:25:::1;83577:30:::0;;;:15:::1;:30;::::0;;;;83711:14;;;;::::1;-1:-1:-1::0;;;;;83711:14:0::1;::::0;83757:8:::1;::::0;::::1;::::0;83804:21;;::::1;;;83932:27;83922:6;:37;;;;;;;;:::i;:::-;;83918:67;;83968:17;;;;;;;;;;;;;;83918:67;81294:10;101199:15:::0;101192:45;;;101184:53;;83999:48:::1;83995:107;;;84070:21;;;;;;;;;;;;;;83995:107;84229:33:::0;;84309:25;;84240:22:::1;84309:25:::0;;;84350:51:::1;::::0;-1:-1:-1;;;;;84350:51:0;::::1;::::0;84370:13;;84350:51:::1;::::0;-1:-1:-1;;84350:51:0::1;83539:869;;;;83469:939:::0;;:::o;79795:290::-;79225:26;69148:16;69159:4;69148:10;:16::i;:::-;79340:6:::1;79894:10;:26;;79886:55;;;::::0;::::1;::::0;;25277:2:1;79886:55:0::1;::::0;::::1;25259:21:1::0;25316:2;25296:18;;;25289:30;25355:18;25335;;;25328:46;25391:18;;79886:55:0::1;;;;;;;;;79972:15;::::0;;79997:28;;;;80040:38:::1;::::0;;25594:25:1;;;25650:2;25635:18;;25628:34;;;80040:38:0::1;::::0;25567:18:1;80040:38:0::1;;;;;;;;79876:209;79795:290:::0;;:::o;80456:264::-;79225:26;69148:16;69159:4;69148:10;:16::i;:::-;80581:14:::1;::::0;;80605:34;;;;80654:59:::1;::::0;;25594:25:1;;;25650:2;25635:18;;25628:34;;;80654:59:0::1;::::0;25567:18:1;80654:59:0::1;25420:248:1::0;88180:2943:0;88535:21;;88281:25;;-1:-1:-1;;;;;88535:35:0;;88531:145;;88633:32;;;;88607:58;;88614:15;88607:58;:::i;:::-;88586:79;;88531:145;88685:59;88707:6;88715:8;88725:18;88685:21;:59::i;:::-;88880:20;88903:62;88925:6;:18;;;88945:6;:19;;;88903:21;:62::i;:::-;88880:85;;89033:23;89088:1;89070:15;;:19;89066:222;;;79292:3;89139:15;;89124:12;:30;;;;:::i;:::-;89123:42;;;;:::i;:::-;89105:60;-1:-1:-1;89179:31:0;89105:60;89179:31;;:::i;:::-;;;89066:222;89333:20;89356:973;89401:918;;;;;;;;89461:13;89401:918;;;;;;89506:6;:17;;;89401:918;;;;;;89555:6;:13;;;-1:-1:-1;;;;;89401:918:0;;;;;89601:6;:9;;;-1:-1:-1;;;;;89401:918:0;;;;;89641:6;:18;;;-1:-1:-1;;;;;89401:918:0;;;;;89688:6;:16;;;-1:-1:-1;;;;;89401:918:0;;;;;89736:12;89401:918;;;;89778:6;:17;;;89401:918;;;;89830:15;89401:918;;;;89873:6;:15;;;89401:918;;;;89913:12;:27;89926:6;:13;;;-1:-1:-1;;;;;89913:27:0;-1:-1:-1;;;;;89913:27:0;;;;;;;;;;;;;:29;;;;;;;;;:::i;:::-;;;;-1:-1:-1;89401:918:0;;90015:21;;-1:-1:-1;;;;;89401:918:0;;;;;;;;;;;;90243:18;;;;89401:918;;;;;90288:16;;;;89401:918;;;89356:31;:973::i;:::-;90363:18;;;;;;;;;;90339:21;90502:30;;;:15;:30;;;;;;;:62;;90619:17;;90574:62;;;;;;;;;;;;;90542:22;90574:62;;;;90732:13;;;;90846:18;;;;;90889:16;;;;90971:17;;;;91016:18;;;;90652:398;;90363:18;;-1:-1:-1;90363:18:0;;-1:-1:-1;;;;;90652:398:0;;;;90363:18;;90652:398;;;;90363:18;;90619:17;;90846:18;90933:12;;90971:17;;91016:23;;;;90652:398;:::i;:::-;;;;;;;;91084:13;91065:51;91099:8;:16;;;91065:51;;;;;;:::i;:::-;;;;;;;;88271:2852;;;;;88180:2943;;:::o;83273:158::-;83383:41;83399:7;;83420:1;83383:5;:41::i;77996:131::-;78067:7;78093:18;;;:12;:18;;;;;:27;;:25;:27::i;71326:138::-;70559:7;70585:12;;;;;;;;;;:22;;;69148:16;69159:4;69148:10;:16::i;:::-;71431:26:::1;71443:4;71449:7;71431:11;:26::i;69249:202::-:0;69334:4;69357:47;;;69372:32;69357:47;;:87;;-1:-1:-1;49585:25:0;49570:40;;;;69408:36;49471:146;69883:103;69949:30;69960:4;23872:10;69949;:30::i;74161:653::-;74336:4;-1:-1:-1;;;;;74322:19:0;;;74318:32;;74161:653;;;:::o;74318:32::-;74422:5;74431:1;74422:10;74418:23;;74161:653;;;:::o;74418:23::-;74454:20;-1:-1:-1;;;;;74454:20:0;;;74450:358;;74634:12;74651:2;-1:-1:-1;;;;;74651:7:0;74666:5;74651:25;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;74633:43;;;74698:7;74690:39;;;;;;;28070:2:1;74690:39:0;;;28052:21:1;28109:2;28089:18;;;28082:30;28148:21;28128:18;;;28121:49;28187:18;;74690:39:0;27868:343:1;74450:358:0;74760:37;-1:-1:-1;;;;;74760:26:0;;74787:2;74791:5;74760:26;:37::i;78229:257::-;78315:4;78331:12;78346:31;78363:4;78369:7;78346:16;:31::i;:::-;78331:46;;78391:7;78387:69;;;78414:18;;;;:12;:18;;;;;:31;;78437:7;78414:22;:31::i;78589:262::-;78676:4;78692:12;78707:32;78725:4;78731:7;78707:17;:32::i;:::-;78692:47;;78753:7;78749:72;;;78776:18;;;;:12;:18;;;;;:34;;78802:7;78776:25;:34::i;46921:556::-;47059:17;;:21;47055:416;;47300:10;47294:17;47356:15;47343:10;47339:2;47335:19;47328:44;47055:416;47423:37;;;;;;;;;;;;;;52055:469;51674:3;52207:34;;52203:86;;;52250:39;;;;;;;;;;;;;;52203:86;55321:30;;55316:3;55312:40;49774:1;52440:19;;52436:81;;52468:49;;;;;28390:6:1;28378:19;;52468:49:0;;;28360:38:1;28333:18;;52468:49:0;28216:188:1;18404:331:0;18513:6;18489:21;:30;18485:109;;;18542:41;;;;;18577:4;18542:41;;;2867:74:1;2840:18;;18542:41:0;2721:226:1;18485:109:0;18605:12;18623:9;-1:-1:-1;;;;;18623:14:0;18645:6;18623:33;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;18604:52;;;18671:7;18666:63;;18701:17;;;;;;;;;;;;;;62366:160;62475:43;;-1:-1:-1;;;;;20205:55:1;;;62475:43:0;;;20187:74:1;20277:18;;;20270:34;;;62448:71:0;;62468:5;;62490:14;;;;;20160:18:1;;62475:43:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;62448:19;:71::i;54018:990::-;54109:49;-1:-1:-1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;54109:49:0;55743:22;55721:45;;55708:59;55703:3;55699:69;;;54174:49;;56158:20;56136:43;;56123:57;56114:67;;54233:20;;;:45;56567:20;56545:43;;56532:57;56528:2;56524:66;;;54288:21;;;:47;56987:21;56965:44;;56952:58;56944:67;;54345:22;;;:49;57393:19;57371:42;;57358:56;57350:65;;54404:20;;;:45;57796:17;57774:40;;57761:54;57753:63;;54459:18;;;:41;58183:20;58161:43;;58148:57;54510:21;;;:47;58571:18;58549:41;;58536:55;54567:19;;;:43;;;;58971:24;58949:47;;58936:61;54620:24;;;:53;59347:15;59325:38;;59312:52;54683:17;;;:39;59702:12;59680:35;;59667:49;54732:14;;;:33;60126:26;60104:49;;60091:63;60083:72;;54775:27;;;:59;60547:27;60525:50;;60512:64;54844:27;;;:59;60939:17;60917:40;;60904:54;54913:18;;;:41;54983:18;55721:45;54991:9;54983:7;:18::i;:::-;54964:37;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;54964:16:0;;;:37;:8;54018:990;-1:-1:-1;;54018:990:0:o;34575:156::-;34649:7;34699:22;34703:3;34715:5;34699:3;:22::i;102800:808::-;-1:-1:-1;;;;;102922:21:0;;102918:47;;102952:13;;;;;;;;;;;;;;102918:47;97923:4;97994:33;;;:18;:33;;;;;:41;;;;-1:-1:-1;;;;;97994:41:0;:55;103036:60;;103076:20;;;;;;;;;;;;;;103036:60;56158:20;56136:43;;56123:57;56118:3;56114:67;103135:13;103110:38;103106:67;;103157:16;;;;;;;;;;;;;;103106:67;59347:15;59325:38;;59312:52;103237:15;:36;103233:67;;;103282:18;;;;;;;;;;;;;;103233:67;60126:26;60104:49;;60091:63;60087:2;60083:72;103438:25;;;;;:51;;;103482:7;-1:-1:-1;;;;;103467:22:0;:11;-1:-1:-1;;;;;103467:22:0;;;103438:51;:102;;;;-1:-1:-1;60547:27:0;60525:50;;60512:64;103493:15;:47;;103438:102;103434:168;;;103563:28;;;;;;;;;;;;;;103434:168;102908:700;102800:808;;;;:::o;62765:188::-;62892:53;;-1:-1:-1;;;;;18522:15:1;;;62892:53:0;;;18504:34:1;18574:15;;;18554:18;;;18547:43;18606:18;;;18599:34;;;62865:81:0;;62885:5;;62907:18;;;;;18416::1;;62892:53:0;18241:398:1;61050:146:0;61116:23;;61162:27;:9;51674:3;61162:9;;:27;:::i;:::-;61151:38;;;;61050:146;;;;;:::o;99649:951::-;99844:23;99870:255;99922:9;99986:5;99993:6;100001:7;;99951:59;;;;;;;;;;;:::i;:::-;;;;-1:-1:-1;;99951:59:0;;;;;;;;;;;;;;;;;;;;100105:9;99870:29;:255::i;:::-;99844:281;;100191:10;:17;100212:1;100191:22;100187:59;;100222:24;;;;;;;;;;;;;;100187:59;100325:10;:17;100346:2;100325:23;100321:67;;100357:31;;;;;;;;;;;;;;100321:67;100502:26;100471:19;100479:10;100471:19;:::i;:::-;:58;100467:127;;100552:31;;;;;;;;;;;;;;100467:127;99763:837;99649:951;;;;;:::o;101579:1142::-;101832:13;101811:6;:17;;;:34;;;101807:63;;101854:16;;;;;;;;;;;;;;101807:63;101884:19;;;;:24;;:50;;-1:-1:-1;101912:17:0;;;;:22;101884:50;101880:80;;;101943:17;;;;;;;;;;;;;;101880:80;101974:13;;;;-1:-1:-1;;;;;101974:27:0;;;:54;;-1:-1:-1;102005:9:0;;;;-1:-1:-1;;;;;102005:23:0;;101974:54;101970:80;;;102037:13;;;;;;;;;;;;;;101970:80;102064:18;;;;-1:-1:-1;;;;;102064:32:0;;;:66;;-1:-1:-1;102100:16:0;;;;-1:-1:-1;;;;;102100:30:0;;102064:66;102060:92;;;102139:13;;;;;;;;;;;;;;102060:92;102184:37;81578:10;102184:15;:37;:::i;:::-;102166:6;:15;;;:55;102162:86;;;102230:18;;;;;;;;;;;;;;102162:86;81692:11;102289:8;:16;;;:23;:45;102285:81;;;102343:23;;;;;;;;;;;;;;102285:81;102380:18;;;;:23;;;;:63;;-1:-1:-1;102407:16:0;;;;-1:-1:-1;;;;;102407:36:0;81148:42;102407:36;102380:63;102376:124;;;102466:23;;;;;;;;;;;;;;102376:124;102604:1;102583:18;:22;:70;;;;102637:6;:15;;;102609:18;:44;102583:70;102579:136;;;102676:28;;;;;;;;;;;;;;98309:1185;98389:19;98424:25;-1:-1:-1;;;;;98424:25:0;;;98420:1068;;98654:9;98644:6;:19;98640:51;;98672:19;;;;;;;;;;;;;;98640:51;-1:-1:-1;98719:9:0;98420:1068;;;98959:9;:14;98955:46;;98982:19;;;;;;;;;;;;;;98955:46;99106:5;-1:-1:-1;;;;;99106:17:0;;99127:1;99106:22;99102:53;;99137:18;;;;;;;;;;;;;;99102:53;99183:38;;;;;99215:4;99183:38;;;2867:74:1;-1:-1:-1;;;;;99183:23:0;;;;;2840:18:1;;99183:38:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;99169:52;-1:-1:-1;99235:65:0;-1:-1:-1;;;;;99235:30:0;;99266:10;99286:4;99293:6;99235:30;:65::i;:::-;99425:38;;;;;99457:4;99425:38;;;2867:74:1;99466:11:0;;-1:-1:-1;;;;;99425:23:0;;;;;2840:18:1;;99425:38:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;:52;;;;:::i;52732:1038::-;53002:22;;53038:20;;;;;53072:21;;;;;52824:12;53107:22;;;;53143:20;;;;53177:18;;;;53209:21;;;;52951:289;;30071:16:1;52951:289:0;;;30055:102:1;;;;30176:66;30279:3;30275:16;;;30271:25;;30258:11;;;30251:46;30330:16;;;;30326:25;;;30313:11;;;30306:46;30371:66;30471:15;;;30467:24;;30453:12;;;30446:46;30526:15;;30522:24;;30508:12;;;30501:46;30581:15;;;30577:24;;30563:12;;;30556:46;30636:15;;;30632:24;;;30618:12;;;30611:46;30673:12;;;30666:28;;;;52926:22:0;;30710:13:1;;52951:289:0;;;-1:-1:-1;;52951:289:0;;;;;;;;;;53310:19;;;;53343:24;;;;53488:17;;;;53519:14;;;;53589:27;;;;53630;;;;53705:18;;;;53737:16;;;;52951:289;;-1:-1:-1;53257:506:0;;52951:289;;53737:16;52951:289;53257:506;;:::i;:::-;;;;;;;;;;;;;53250:513;;;52732:1038;;;:::o;34118:115::-;34181:7;34207:19;34215:3;29557:18;;29475:107;70116:197;69615:4;69638:12;;;;;;;;;;;-1:-1:-1;;;;;69638:29:0;;;;;;;;;;;;70199:108;;70249:47;;;;;-1:-1:-1;;;;;20205:55:1;;70249:47:0;;;20187:74:1;20277:18;;;20270:34;;;20160:18;;70249:47:0;20013:297:1;72863:316:0;72940:4;69638:12;;;;;;;;;;;-1:-1:-1;;;;;69638:29:0;;;;;;;;;;;;72956:217;;72999:6;:12;;;;;;;;;;;-1:-1:-1;;;;;72999:29:0;;;;;;;;;:36;;;;73031:4;72999:36;;;73081:12;23872:10;;23793:96;73081:12;-1:-1:-1;;;;;73054:40:0;73072:7;-1:-1:-1;;;;;73054:40:0;73066:4;73054:40;;;;;;;;;;-1:-1:-1;73115:4:0;73108:11;;72956:217;-1:-1:-1;73157:5:0;73150:12;;33317:150;33387:4;33410:50;33415:3;-1:-1:-1;;;;;33435:23:0;;33410:4;:50::i;73414:317::-;73492:4;69638:12;;;;;;;;;;;-1:-1:-1;;;;;69638:29:0;;;;;;;;;;;;73508:217;;;73582:5;73550:12;;;;;;;;;;;-1:-1:-1;;;;;73550:29:0;;;;;;;;;;:37;;;;;;73606:40;23872:10;;73550:12;;73606:40;;73582:5;73606:40;-1:-1:-1;73667:4:0;73660:11;;33635:156;33708:4;33731:53;33739:3;-1:-1:-1;;;;;33759:23:0;;33731:7;:53::i;65122:629::-;65541:23;65567:33;-1:-1:-1;;;;;65567:27:0;;65595:4;65567:27;:33::i;:::-;65541:59;;65614:10;:17;65635:1;65614:22;;:57;;;;;65652:10;65641:30;;;;;;;;;;;;:::i;:::-;65640:31;65614:57;65610:135;;;65694:40;;;;;-1:-1:-1;;;;;2885:55:1;;65694:40:0;;;2867:74:1;2840:18;;65694:40:0;2721:226:1;29924:118:0;29991:7;30017:3;:11;;30029:5;30017:18;;;;;;;;:::i;:::-;;;;;;;;;30010:25;;29924:118;;;;:::o;20053:392::-;20152:12;20204:5;20180:21;:29;20176:108;;;20232:41;;;;;20267:4;20232:41;;;2867:74:1;2840:18;;20232:41:0;2721:226:1;20176:108:0;20294:12;20308:23;20335:6;-1:-1:-1;;;;;20335:11:0;20354:5;20361:4;20335:31;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;20293:73;;;;20383:55;20410:6;20418:7;20427:10;20383:26;:55::i;:::-;20376:62;20053:392;-1:-1:-1;;;;;;20053:392:0:o;27242:406::-;27305:4;29361:21;;;:14;;;:21;;;;;;27321:321;;-1:-1:-1;27363:23:0;;;;;;;;:11;:23;;;;;;;;;;;;;27545:18;;27521:21;;;:14;;;:21;;;;;;:42;;;;27577:11;;27816:1368;27882:4;28011:21;;;:14;;;:21;;;;;;28047:13;;28043:1135;;28414:18;28435:12;28446:1;28435:8;:12;:::i;:::-;28481:18;;28414:33;;-1:-1:-1;28461:17:0;;28481:22;;28502:1;;28481:22;:::i;:::-;28461:42;;28536:9;28522:10;:23;28518:378;;28565:17;28585:3;:11;;28597:9;28585:22;;;;;;;;:::i;:::-;;;;;;;;;28565:42;;28732:9;28706:3;:11;;28718:10;28706:23;;;;;;;;:::i;:::-;;;;;;;;;;;;:35;;;;28845:25;;;:14;;;:25;;;;;:36;;;28518:378;28974:17;;:3;;:17;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;29077:3;:14;;:21;29092:5;29077:21;;;;;;;;;;;29070:28;;;29120:4;29113:11;;;;;;;28043:1135;29162:5;29155:12;;;;;19578:151;19653:12;19684:38;19706:6;19714:4;19720:1;19684:21;:38::i;21498:582::-;21642:12;21671:7;21666:408;;21694:19;21702:10;21694:7;:19::i;:::-;21666:408;;;21918:17;;:22;:49;;;;-1:-1:-1;;;;;;21944:18:0;;;:23;21918:49;21914:119;;;21994:24;;;;;-1:-1:-1;;;;;2885:55:1;;21994:24:0;;;2867:74:1;2840:18;;21994:24:0;2721:226:1;21914:119:0;-1:-1:-1;22053:10:0;22046:17;;22616:516;22747:17;;:21;22743:383;;22975:10;22969:17;23031:15;23018:10;23014:2;23010:19;23003:44;22743:383;23098:17;;;;;;;;;;;;;;14:332:1;72:6;125:2;113:9;104:7;100:23;96:32;93:52;;;141:1;138;131:12;93:52;180:9;167:23;230:66;223:5;219:78;212:5;209:89;199:117;;312:1;309;302:12;821:180;880:6;933:2;921:9;912:7;908:23;904:32;901:52;;;949:1;946;939:12;901:52;-1:-1:-1;972:23:1;;821:180;-1:-1:-1;821:180:1:o;1006:184::-;1058:77;1055:1;1048:88;1155:4;1152:1;1145:15;1179:4;1176:1;1169:15;1195:297;1279:1;1272:5;1269:12;1259:200;;1315:77;1312:1;1305:88;1416:4;1413:1;1406:15;1444:4;1441:1;1434:15;1259:200;1468:18;;1195:297::o;1497:214::-;1646:2;1631:18;;1658:47;1635:9;1687:6;1658:47;:::i;1716:154::-;-1:-1:-1;;;;;1795:5:1;1791:54;1784:5;1781:65;1771:93;;1860:1;1857;1850:12;1875:134;1943:20;;1972:31;1943:20;1972:31;:::i;:::-;1875:134;;;:::o;2014:388::-;2082:6;2090;2143:2;2131:9;2122:7;2118:23;2114:32;2111:52;;;2159:1;2156;2149:12;2111:52;2198:9;2185:23;2217:31;2242:5;2217:31;:::i;:::-;2267:5;-1:-1:-1;2324:2:1;2309:18;;2296:32;2337:33;2296:32;2337:33;:::i;:::-;2389:7;2379:17;;;2014:388;;;;;:::o;2952:383::-;3029:6;3037;3045;3098:2;3086:9;3077:7;3073:23;3069:32;3066:52;;;3114:1;3111;3104:12;3066:52;3150:9;3137:23;3127:33;;3207:2;3196:9;3192:18;3179:32;3169:42;;3261:2;3250:9;3246:18;3233:32;3274:31;3299:5;3274:31;:::i;:::-;3324:5;3314:15;;;2952:383;;;;;:::o;3340:247::-;3399:6;3452:2;3440:9;3431:7;3427:23;3423:32;3420:52;;;3468:1;3465;3458:12;3420:52;3507:9;3494:23;3526:31;3551:5;3526:31;:::i;3592:315::-;3660:6;3668;3721:2;3709:9;3700:7;3696:23;3692:32;3689:52;;;3737:1;3734;3727:12;3689:52;3773:9;3760:23;3750:33;;3833:2;3822:9;3818:18;3805:32;3846:31;3871:5;3846:31;:::i;3912:118::-;3998:5;3991:13;3984:21;3977:5;3974:32;3964:60;;4020:1;4017;4010:12;4035:128;4100:20;;4129:28;4100:20;4129:28;:::i;4168:761::-;4271:6;4279;4287;4340:2;4328:9;4319:7;4315:23;4311:32;4308:52;;;4356:1;4353;4346:12;4308:52;4396:9;4383:23;4425:18;4466:2;4458:6;4455:14;4452:34;;;4482:1;4479;4472:12;4452:34;4520:6;4509:9;4505:22;4495:32;;4565:7;4558:4;4554:2;4550:13;4546:27;4536:55;;4587:1;4584;4577:12;4536:55;4627:2;4614:16;4653:2;4645:6;4642:14;4639:34;;;4669:1;4666;4659:12;4639:34;4724:7;4717:4;4707:6;4704:1;4700:14;4696:2;4692:23;4688:34;4685:47;4682:67;;;4745:1;4742;4735:12;4682:67;4776:4;4768:13;;;;-1:-1:-1;4800:6:1;-1:-1:-1;;4841:20:1;;4828:34;4871:28;4828:34;4871:28;:::i;4934:250::-;5019:1;5029:113;5043:6;5040:1;5037:13;5029:113;;;5119:11;;;5113:18;5100:11;;;5093:39;5065:2;5058:10;5029:113;;;-1:-1:-1;;5176:1:1;5158:16;;5151:27;4934:250::o;5189:329::-;5230:3;5268:5;5262:12;5295:6;5290:3;5283:19;5311:76;5380:6;5373:4;5368:3;5364:14;5357:4;5350:5;5346:16;5311:76;:::i;:::-;5432:2;5420:15;-1:-1:-1;;5416:88:1;5407:98;;;;5507:4;5403:109;;5189:329;-1:-1:-1;;5189:329:1:o;5523:1097::-;5711:4;5740:2;5780;5769:9;5765:18;5810:2;5799:9;5792:21;5833:6;5868;5862:13;5899:6;5891;5884:22;5925:2;5915:12;;5958:2;5947:9;5943:18;5936:25;;6020:2;6010:6;6007:1;6003:14;5992:9;5988:30;5984:39;6058:2;6050:6;6046:15;6079:1;6089:502;6103:6;6100:1;6097:13;6089:502;;;6168:22;;;6192:66;6164:95;6152:108;;6283:13;;6338:9;;6331:17;6324:25;6309:41;;6389:11;;6383:18;6421:15;;;6414:27;;;6464:47;6495:15;;;6383:18;6464:47;:::i;:::-;6569:12;;;;6454:57;-1:-1:-1;;6534:15:1;;;;6125:1;6118:9;6089:502;;;-1:-1:-1;6608:6:1;;5523:1097;-1:-1:-1;;;;;;;;5523:1097:1:o;6625:347::-;6676:8;6686:6;6740:3;6733:4;6725:6;6721:17;6717:27;6707:55;;6758:1;6755;6748:12;6707:55;-1:-1:-1;6781:20:1;;6824:18;6813:30;;6810:50;;;6856:1;6853;6846:12;6810:50;6893:4;6885:6;6881:17;6869:29;;6945:3;6938:4;6929:6;6921;6917:19;6913:30;6910:39;6907:59;;;6962:1;6959;6952:12;6907:59;6625:347;;;;;:::o;6977:544::-;7056:6;7064;7072;7125:2;7113:9;7104:7;7100:23;7096:32;7093:52;;;7141:1;7138;7131:12;7093:52;7181:9;7168:23;7214:18;7206:6;7203:30;7200:50;;;7246:1;7243;7236:12;7200:50;7285:58;7335:7;7326:6;7315:9;7311:22;7285:58;:::i;:::-;7362:8;;-1:-1:-1;7259:84:1;-1:-1:-1;;7447:2:1;7432:18;;7419:32;7460:31;7419:32;7460:31;:::i;7526:184::-;7578:77;7575:1;7568:88;7675:4;7672:1;7665:15;7699:4;7696:1;7689:15;7715:255;7787:2;7781:9;7829:6;7817:19;;7866:18;7851:34;;7887:22;;;7848:62;7845:88;;;7913:18;;:::i;:::-;7949:2;7942:22;7715:255;:::o;7975:253::-;8047:2;8041:9;8089:4;8077:17;;8124:18;8109:34;;8145:22;;;8106:62;8103:88;;;8171:18;;:::i;8233:255::-;8305:2;8299:9;8347:6;8335:19;;8384:18;8369:34;;8405:22;;;8366:62;8363:88;;;8431:18;;:::i;8493:252::-;8565:2;8559:9;8607:3;8595:16;;8641:18;8626:34;;8662:22;;;8623:62;8620:88;;;8688:18;;:::i;8750:334::-;8821:2;8815:9;8877:2;8867:13;;-1:-1:-1;;8863:86:1;8851:99;;8980:18;8965:34;;9001:22;;;8962:62;8959:88;;;9027:18;;:::i;:::-;9063:2;9056:22;8750:334;;-1:-1:-1;8750:334:1:o;9089:121::-;9174:10;9167:5;9163:22;9156:5;9153:33;9143:61;;9200:1;9197;9190:12;9215:132;9282:20;;9311:30;9282:20;9311:30;:::i;9352:806::-;9411:5;9459:6;9447:9;9442:3;9438:19;9434:32;9431:52;;;9479:1;9476;9469:12;9431:52;9501:22;;:::i;:::-;9492:31;;9546:28;9564:9;9546:28;:::i;:::-;9539:5;9532:43;9607:38;9641:2;9630:9;9626:18;9607:38;:::i;:::-;9602:2;9595:5;9591:14;9584:62;9678:38;9712:2;9701:9;9697:18;9678:38;:::i;:::-;9673:2;9666:5;9662:14;9655:62;9749:38;9783:2;9772:9;9768:18;9749:38;:::i;:::-;9744:2;9737:5;9733:14;9726:62;9821:39;9855:3;9844:9;9840:19;9821:39;:::i;:::-;9815:3;9808:5;9804:15;9797:64;9922:3;9911:9;9907:19;9894:33;9888:3;9881:5;9877:15;9870:58;9989:3;9978:9;9974:19;9961:33;9955:3;9948:5;9944:15;9937:58;10028:36;10059:3;10048:9;10044:19;10028:36;:::i;:::-;10022:3;10015:5;10011:15;10004:61;10084:3;10147:2;10136:9;10132:18;10119:32;10114:2;10107:5;10103:14;10096:56;;9352:806;;;;:::o;10163:237::-;10251:6;10304:3;10292:9;10283:7;10279:23;10275:33;10272:53;;;10321:1;10318;10311:12;10272:53;10344:50;10386:7;10375:9;10344:50;:::i;10405:409::-;10475:6;10483;10536:2;10524:9;10515:7;10511:23;10507:32;10504:52;;;10552:1;10549;10542:12;10504:52;10592:9;10579:23;10625:18;10617:6;10614:30;10611:50;;;10657:1;10654;10647:12;10611:50;10696:58;10746:7;10737:6;10726:9;10722:22;10696:58;:::i;:::-;10773:8;;10670:84;;-1:-1:-1;10405:409:1;-1:-1:-1;;;;10405:409:1:o;10918:1865::-;11121:2;11110:9;11103:21;11133:52;11181:2;11170:9;11166:18;11157:6;11151:13;10895:10;10884:22;10872:35;;10819:94;11133:52;11084:4;11232:2;11224:6;11220:15;11214:22;11245:51;11292:2;11281:9;11277:18;11263:12;10895:10;10884:22;10872:35;;10819:94;11245:51;-1:-1:-1;11345:2:1;11333:15;;11327:22;-1:-1:-1;;;;;2655:54:1;;11408:2;11393:18;;2643:67;-1:-1:-1;11461:2:1;11449:15;;11443:22;-1:-1:-1;;;;;2655:54:1;;11524:3;11509:19;;2643:67;-1:-1:-1;11578:3:1;11566:16;;11560:23;-1:-1:-1;;;;;2655:54:1;;11642:3;11627:19;;2643:67;-1:-1:-1;11696:3:1;11684:16;;11678:23;-1:-1:-1;;;;;2655:54:1;;11760:3;11745:19;;2643:67;-1:-1:-1;11820:3:1;11808:16;;11802:23;11796:3;11781:19;;;11774:52;;;;11851:16;;11845:23;11887:3;11906:18;;;11899:30;;;;11954:15;;11948:22;11989:3;12008:18;;;12001:30;;;;12056:15;;12050:22;12091:3;12110:18;;;12103:30;;;;12158:15;;12152:22;12193:3;12212:18;;;12205:30;;;;12272:15;;12266:22;12307:3;12319:54;12354:18;;;12266:22;-1:-1:-1;;;;;2655:54:1;2643:67;;2589:127;12319:54;12399:15;;12393:22;12435:3;12454:19;;;12447:32;;;;12505:16;;12499:23;12542:3;12561:19;;;12554:32;;;;12623:16;;12617:23;12660:6;12682:19;;;12675:32;12617:23;-1:-1:-1;12724:53:1;12772:3;12757:19;;12617:23;12724:53;:::i;:::-;12716:61;10918:1865;-1:-1:-1;;;;10918:1865:1:o;12788:513::-;13017:3;13002:19;;13030:47;13006:9;13059:6;13030:47;:::i;:::-;13125:10;13117:6;13113:23;13108:2;13097:9;13093:18;13086:51;13185:16;13177:6;13173:29;13168:2;13157:9;13153:18;13146:57;-1:-1:-1;;;;;13243:6:1;13239:55;13234:2;13223:9;13219:18;13212:83;12788:513;;;;;;;:::o;13306:477::-;13385:6;13393;13401;13454:2;13442:9;13433:7;13429:23;13425:32;13422:52;;;13470:1;13467;13460:12;13422:52;13510:9;13497:23;13543:18;13535:6;13532:30;13529:50;;;13575:1;13572;13565:12;13529:50;13614:58;13664:7;13655:6;13644:9;13640:22;13614:58;:::i;:::-;13691:8;;13588:84;;-1:-1:-1;13773:2:1;13758:18;;;;13745:32;;13306:477;-1:-1:-1;;;;13306:477:1:o;13788:248::-;13856:6;13864;13917:2;13905:9;13896:7;13892:23;13888:32;13885:52;;;13933:1;13930;13923:12;13885:52;-1:-1:-1;;13956:23:1;;;14026:2;14011:18;;;13998:32;;-1:-1:-1;13788:248:1:o;14374:1373::-;14605:13;;10895:10;10884:22;10872:35;;14574:3;14559:19;;14677:4;14669:6;14665:17;14659:24;14692:53;14739:4;14728:9;14724:20;14710:12;10895:10;10884:22;10872:35;;10819:94;14692:53;;14794:4;14786:6;14782:17;14776:24;14809:56;14859:4;14848:9;14844:20;14828:14;-1:-1:-1;;;;;2655:54:1;2643:67;;2589:127;14809:56;;14914:4;14906:6;14902:17;14896:24;14929:56;14979:4;14968:9;14964:20;14948:14;-1:-1:-1;;;;;2655:54:1;2643:67;;2589:127;14929:56;;15034:4;15026:6;15022:17;15016:24;15049:56;15099:4;15088:9;15084:20;15068:14;-1:-1:-1;;;;;2655:54:1;2643:67;;2589:127;15049:56;;15154:4;15146:6;15142:17;15136:24;15169:56;15219:4;15208:9;15204:20;15188:14;-1:-1:-1;;;;;2655:54:1;2643:67;;2589:127;15169:56;;15281:4;15273:6;15269:17;15263:24;15256:4;15245:9;15241:20;15234:54;15344:4;15336:6;15332:17;15326:24;15319:4;15308:9;15304:20;15297:54;15370:6;15430:2;15422:6;15418:15;15412:22;15407:2;15396:9;15392:18;15385:50;;15454:6;15509:2;15501:6;15497:15;15491:22;15522:51;15569:2;15558:9;15554:18;15538:14;421:13;414:21;402:34;;351:91;15522:51;-1:-1:-1;;15592:6:1;15640:15;;;15634:22;15614:18;;;15607:50;15676:6;15724:15;;;15718:22;15698:18;;;;15691:50;;;;14374:1373;:::o;15937:245::-;15985:4;16018:18;16010:6;16007:30;16004:56;;;16040:18;;:::i;:::-;-1:-1:-1;16097:2:1;16085:15;-1:-1:-1;;16081:88:1;16171:4;16077:99;;15937:245::o;16187:462::-;16229:5;16282:3;16275:4;16267:6;16263:17;16259:27;16249:55;;16300:1;16297;16290:12;16249:55;16336:6;16323:20;16367:48;16383:31;16411:2;16383:31;:::i;:::-;16367:48;:::i;:::-;16440:2;16431:7;16424:19;16486:3;16479:4;16474:2;16466:6;16462:15;16458:26;16455:35;16452:55;;;16503:1;16500;16493:12;16452:55;16568:2;16561:4;16553:6;16549:17;16542:4;16533:7;16529:18;16516:55;16616:1;16591:16;;;16609:4;16587:27;16580:38;;;;16595:7;16187:462;-1:-1:-1;;;16187:462:1:o;16654:1162::-;16783:6;16791;16844:3;16832:9;16823:7;16819:23;16815:33;16812:53;;;16861:1;16858;16851:12;16812:53;16884:50;16926:7;16915:9;16884:50;:::i;:::-;16874:60;;16985:3;16974:9;16970:19;16957:33;17009:18;17050:2;17042:6;17039:14;17036:34;;;17066:1;17063;17056:12;17036:34;17089:22;;;;17145:4;17127:16;;;17123:27;17120:47;;;17163:1;17160;17153:12;17120:47;17189:22;;:::i;:::-;17248:2;17235:16;17260:33;17285:7;17260:33;:::i;:::-;17302:22;;17377:2;17369:11;;;17356:25;17340:14;;;17333:49;17428:2;17420:11;;17407:25;17444:16;;;17441:36;;;17473:1;17470;17463:12;17441:36;17509:44;17545:7;17534:8;17530:2;17526:17;17509:44;:::i;:::-;17504:2;17497:5;17493:14;17486:68;;17607:2;17603;17599:11;17586:25;17581:2;17574:5;17570:14;17563:49;17658:3;17654:2;17650:12;17637:26;17688:2;17678:8;17675:16;17672:36;;;17704:1;17701;17694:12;17672:36;17741:44;17777:7;17766:8;17762:2;17758:17;17741:44;:::i;:::-;17735:3;17728:5;17724:15;17717:69;;17805:5;17795:15;;;;;16654:1162;;;;;:::o;18644:184::-;18696:77;18693:1;18686:88;18793:4;18790:1;18783:15;18817:4;18814:1;18807:15;18833:580;18910:4;18916:6;18976:11;18963:25;19066:66;19055:8;19039:14;19035:29;19031:102;19011:18;19007:127;18997:155;;19148:1;19145;19138:12;18997:155;19175:33;;19227:20;;;-1:-1:-1;19270:18:1;19259:30;;19256:50;;;19302:1;19299;19292:12;19256:50;19335:4;19323:17;;-1:-1:-1;19366:14:1;19362:27;;;19352:38;;19349:58;;;19403:1;19400;19393:12;19418:271;19601:6;19593;19588:3;19575:33;19557:3;19627:16;;19652:13;;;19627:16;19418:271;-1:-1:-1;19418:271:1:o;19694:184::-;19746:77;19743:1;19736:88;19843:4;19840:1;19833:15;19867:4;19864:1;19857:15;19883:125;19948:9;;;19969:10;;;19966:36;;;19982:18;;:::i;20949:325::-;21037:6;21032:3;21025:19;21089:6;21082:5;21075:4;21070:3;21066:14;21053:43;;21141:1;21134:4;21125:6;21120:3;21116:16;21112:27;21105:38;21007:3;21263:4;-1:-1:-1;;21188:2:1;21180:6;21176:15;21172:88;21167:3;21163:98;21159:109;21152:116;;20949:325;;;;:::o;21279:244::-;21436:2;21425:9;21418:21;21399:4;21456:61;21513:2;21502:9;21498:18;21490:6;21482;21456:61;:::i;21528:136::-;21606:13;;21628:30;21606:13;21628:30;:::i;21669:138::-;21748:13;;21770:31;21748:13;21770:31;:::i;21812:441::-;21865:5;21918:3;21911:4;21903:6;21899:17;21895:27;21885:55;;21936:1;21933;21926:12;21885:55;21965:6;21959:13;21996:48;22012:31;22040:2;22012:31;:::i;21996:48::-;22069:2;22060:7;22053:19;22115:3;22108:4;22103:2;22095:6;22091:15;22087:26;22084:35;22081:55;;;22132:1;22129;22122:12;22081:55;22145:77;22219:2;22212:4;22203:7;22199:18;22192:4;22184:6;22180:17;22145:77;:::i;22258:1672::-;22365:6;22418:2;22406:9;22397:7;22393:23;22389:32;22386:52;;;22434:1;22431;22424:12;22386:52;22467:9;22461:16;22496:18;22537:2;22529:6;22526:14;22523:34;;;22553:1;22550;22543:12;22523:34;22576:22;;;;22632:6;22614:16;;;22610:29;22607:49;;;22652:1;22649;22642:12;22607:49;22678:22;;:::i;:::-;22723:32;22752:2;22723:32;:::i;:::-;22716:5;22709:47;22788:41;22825:2;22821;22817:11;22788:41;:::i;:::-;22783:2;22776:5;22772:14;22765:65;22862:42;22900:2;22896;22892:11;22862:42;:::i;:::-;22857:2;22850:5;22846:14;22839:66;22937:42;22975:2;22971;22967:11;22937:42;:::i;:::-;22932:2;22925:5;22921:14;22914:66;23013:43;23051:3;23047:2;23043:12;23013:43;:::i;:::-;23007:3;23000:5;22996:15;22989:68;23090:43;23128:3;23124:2;23120:12;23090:43;:::i;:::-;23084:3;23073:15;;23066:68;23181:3;23173:12;;;23167:19;23150:15;;;23143:44;23234:3;23226:12;;;23220:19;23203:15;;;23196:44;23259:3;23300:11;;;23294:18;23278:14;;;23271:42;23332:3;23373:11;;;23367:18;23351:14;;;23344:42;23405:3;23446:11;;;23440:18;23424:14;;;23417:42;23478:3;23513:42;23543:11;;;23513:42;:::i;:::-;23497:14;;;23490:66;23575:3;23616:11;;;23610:18;23594:14;;;23587:42;23648:3;23689:11;;;23683:18;23667:14;;;23660:42;23721:3;23755:11;;;23749:18;23779:16;;;23776:36;;;23808:1;23805;23798:12;23776:36;23844:55;23891:7;23880:8;23876:2;23872:17;23844:55;:::i;:::-;23828:14;;;23821:79;;;;-1:-1:-1;23832:5:1;22258:1672;-1:-1:-1;;;;;22258:1672:1:o;23935:1135::-;24027:6;24080:3;24068:9;24059:7;24055:23;24051:33;24048:53;;;24097:1;24094;24087:12;24048:53;24123:22;;:::i;:::-;24168:28;24186:9;24168:28;:::i;:::-;24161:5;24154:43;24229:37;24262:2;24251:9;24247:18;24229:37;:::i;:::-;24224:2;24217:5;24213:14;24206:61;24299:38;24333:2;24322:9;24318:18;24299:38;:::i;:::-;24294:2;24287:5;24283:14;24276:62;24370:38;24404:2;24393:9;24389:18;24370:38;:::i;:::-;24365:2;24358:5;24354:14;24347:62;24442:39;24476:3;24465:9;24461:19;24442:39;:::i;:::-;24436:3;24429:5;24425:15;24418:64;24515:39;24549:3;24538:9;24534:19;24515:39;:::i;:::-;24509:3;24502:5;24498:15;24491:64;24616:3;24605:9;24601:19;24588:33;24582:3;24575:5;24571:15;24564:58;24683:3;24672:9;24668:19;24655:33;24649:3;24642:5;24638:15;24631:58;24708:3;24771:2;24760:9;24756:18;24743:32;24738:2;24731:5;24727:14;24720:56;;24795:3;24830:35;24861:2;24850:9;24846:18;24830:35;:::i;:::-;24814:14;;;24807:59;24885:3;24933:18;;;24920:32;24904:14;;;24897:56;24972:3;25020:18;;;25007:32;24991:14;;;24984:56;;;;-1:-1:-1;24818:5:1;23935:1135;-1:-1:-1;23935:1135:1:o;25673:216::-;25737:9;;;25765:11;;;25712:3;25795:9;;25823:10;;25819:19;;25848:10;;25840:19;;25816:44;25813:70;;;25863:18;;:::i;:::-;25813:70;;25673:216;;;;:::o;25894:168::-;25967:9;;;25998;;26015:15;;;26009:22;;25995:37;25985:71;;26036:18;;:::i;26067:274::-;26107:1;26133;26123:189;;26168:77;26165:1;26158:88;26269:4;26266:1;26259:15;26297:4;26294:1;26287:15;26123:189;-1:-1:-1;26326:9:1;;26067:274::o;26346:128::-;26413:9;;;26434:11;;;26431:37;;;26448:18;;:::i;26479:195::-;26518:3;26549:66;26542:5;26539:77;26536:103;;26619:18;;:::i;:::-;-1:-1:-1;26666:1:1;26655:13;;26479:195::o;26679:752::-;26986:3;26975:9;26968:22;26949:4;27007:45;27047:3;27036:9;27032:19;27024:6;27007:45;:::i;:::-;27100:10;27088:23;;;;27083:2;27068:18;;27061:51;-1:-1:-1;;;;;;27209:15:1;;;27204:2;27189:18;;27182:43;27261:15;;;;27256:2;27241:18;;27234:43;27308:3;27293:19;;27286:35;;;;27352:3;27337:19;;27330:35;27409:14;;27402:22;27396:3;27381:19;;;27374:51;26999:53;26679:752;-1:-1:-1;26679:752:1:o;27436:217::-;27583:2;27572:9;27565:21;27546:4;27603:44;27643:2;27632:9;27628:18;27620:6;27603:44;:::i;28409:331::-;28514:9;28525;28567:8;28555:10;28552:24;28549:44;;;28589:1;28586;28579:12;28549:44;28618:6;28608:8;28605:20;28602:40;;;28638:1;28635;28628:12;28602:40;-1:-1:-1;;28664:23:1;;;28709:25;;;;;-1:-1:-1;28409:331:1:o;28745:435::-;-1:-1:-1;;;;;28962:6:1;28958:55;28947:9;28940:74;29050:6;29045:2;29034:9;29030:18;29023:34;29093:2;29088;29077:9;29073:18;29066:30;28921:4;29113:61;29170:2;29159:9;29155:18;29147:6;29139;29113:61;:::i;29185:357::-;29303:12;;29350:4;29339:16;;;29333:23;;29303:12;29368:16;;29365:171;;;29458:66;29448:6;29442:4;29438:17;29435:1;29431:25;29427:98;29420:5;29416:110;29407:119;;29365:171;;29185:357;;;:::o;29547:184::-;29617:6;29670:2;29658:9;29649:7;29645:23;29641:32;29638:52;;;29686:1;29683;29676:12;29638:52;-1:-1:-1;29709:16:1;;29547:184;-1:-1:-1;29547:184:1:o;30734:1059::-;31105:3;31143:6;31137:13;31159:66;31218:6;31213:3;31206:4;31198:6;31194:17;31159:66;:::i;:::-;31256:6;31251:3;31247:16;31234:29;;31286:6;31279:5;31272:21;31327:6;31320:4;31313:5;31309:16;31302:32;31366:6;31361:2;31354:5;31350:14;31343:30;31405:6;31400:2;31393:5;31389:14;31382:30;31466:66;31457:6;31453:2;31449:15;31445:88;31439:3;31432:5;31428:15;31421:113;31567:6;31561:3;31554:5;31550:15;31543:31;31607:6;31601:3;31594:5;31590:15;31583:31;31645:6;31639:13;31661:80;31732:8;31726:3;31719:5;31715:15;31708:4;31700:6;31696:17;31661:80;:::i;:::-;31761:20;31783:3;31757:30;;30734:1059;-1:-1:-1;;;;;;;;;;;30734:1059:1:o;32100:245::-;32167:6;32220:2;32208:9;32199:7;32195:23;32191:32;32188:52;;;32236:1;32233;32226:12;32188:52;32268:9;32262:16;32287:28;32309:5;32287:28;:::i;32350:287::-;32479:3;32517:6;32511:13;32533:66;32592:6;32587:3;32580:4;32572:6;32568:17;32533:66;:::i;:::-;32615:16;;;;;32350:287;-1:-1:-1;;32350:287:1:o;32642:184::-;32694:77;32691:1;32684:88;32791:4;32788:1;32781:15;32815:4;32812:1;32805:15","abiDefinition":[{"inputs":[{"internalType":"address","name":"_owner","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AccessControlBadConfirmation","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"bytes32","name":"neededRole","type":"bytes32"}],"name":"AccessControlUnauthorizedAccount","type":"error"},{"inputs":[{"internalType":"address","name":"target","type":"address"}],"name":"AddressEmptyCode","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"AddressInsufficientBalance","type":"error"},{"inputs":[],"name":"AmountIncorrect","type":"error"},{"inputs":[],"name":"BridgeTransactionV2__InvalidEncodedTx","type":"error"},{"inputs":[{"internalType":"uint16","name":"version","type":"uint16"}],"name":"BridgeTransactionV2__UnsupportedVersion","type":"error"},{"inputs":[],"name":"ChainIncorrect","type":"error"},{"inputs":[],"name":"DeadlineExceeded","type":"error"},{"inputs":[],"name":"DeadlineNotExceeded","type":"error"},{"inputs":[],"name":"DeadlineTooShort","type":"error"},{"inputs":[],"name":"DisputePeriodNotPassed","type":"error"},{"inputs":[],"name":"DisputePeriodPassed","type":"error"},{"inputs":[],"name":"ExclusivityParamsIncorrect","type":"error"},{"inputs":[],"name":"ExclusivityPeriodNotPassed","type":"error"},{"inputs":[],"name":"FailedInnerCall","type":"error"},{"inputs":[],"name":"MsgValueIncorrect","type":"error"},{"inputs":[],"name":"MulticallTarget__UndeterminedRevert","type":"error"},{"inputs":[],"name":"RecipientIncorrectReturnValue","type":"error"},{"inputs":[],"name":"RecipientNoReturnValue","type":"error"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"SafeERC20FailedOperation","type":"error"},{"inputs":[],"name":"SenderIncorrect","type":"error"},{"inputs":[],"name":"StatusIncorrect","type":"error"},{"inputs":[],"name":"TokenNotContract","type":"error"},{"inputs":[],"name":"TransactionRelayed","type":"error"},{"inputs":[],"name":"ZapDataLengthAboveMax","type":"error"},{"inputs":[],"name":"ZapNativeNotSupported","type":"error"},{"inputs":[],"name":"ZeroAddress","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"relayer","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"BridgeDepositClaimed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"BridgeDepositRefunded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"relayer","type":"address"}],"name":"BridgeProofDisputed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"relayer","type":"address"},{"indexed":false,"internalType":"bytes32","name":"transactionHash","type":"bytes32"}],"name":"BridgeProofProvided","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":false,"internalType":"bytes","name":"quoteId","type":"bytes"}],"name":"BridgeQuoteDetails","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"relayer","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint32","name":"originChainId","type":"uint32"},{"indexed":false,"internalType":"address","name":"originToken","type":"address"},{"indexed":false,"internalType":"address","name":"destToken","type":"address"},{"indexed":false,"internalType":"uint256","name":"originAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"destAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"chainGasAmount","type":"uint256"}],"name":"BridgeRelayed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"bytes","name":"request","type":"bytes"},{"indexed":false,"internalType":"uint32","name":"destChainId","type":"uint32"},{"indexed":false,"internalType":"address","name":"originToken","type":"address"},{"indexed":false,"internalType":"address","name":"destToken","type":"address"},{"indexed":false,"internalType":"uint256","name":"originAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"destAmount","type":"uint256"},{"indexed":false,"internalType":"bool","name":"sendChainGas","type":"bool"}],"name":"BridgeRequested","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldChainGasAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newChainGasAmount","type":"uint256"}],"name":"ChainGasAmountUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldFeeRate","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newFeeRate","type":"uint256"}],"name":"FeeRateUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"address","name":"recipient","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"FeesSwept","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"previousAdminRole","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"newAdminRole","type":"bytes32"}],"name":"RoleAdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleRevoked","type":"event"},{"inputs":[],"name":"DEFAULT_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"DISPUTE_PERIOD","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"FEE_BPS","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"FEE_RATE_MAX","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"GOVERNOR_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"GUARD_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_ZAP_DATA_LENGTH","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MIN_DEADLINE_PERIOD","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"NATIVE_GAS_TOKEN","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"REFUNDER_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"REFUND_DELAY","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"RELAYER_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"uint32","name":"dstChainId","type":"uint32"},{"internalType":"address","name":"sender","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"address","name":"originToken","type":"address"},{"internalType":"address","name":"destToken","type":"address"},{"internalType":"uint256","name":"originAmount","type":"uint256"},{"internalType":"uint256","name":"destAmount","type":"uint256"},{"internalType":"bool","name":"sendChainGas","type":"bool"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"internalType":"struct IFastBridge.BridgeParams","name":"params","type":"tuple"}],"name":"bridge","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"uint32","name":"dstChainId","type":"uint32"},{"internalType":"address","name":"sender","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"address","name":"originToken","type":"address"},{"internalType":"address","name":"destToken","type":"address"},{"internalType":"uint256","name":"originAmount","type":"uint256"},{"internalType":"uint256","name":"destAmount","type":"uint256"},{"internalType":"bool","name":"sendChainGas","type":"bool"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"internalType":"struct IFastBridge.BridgeParams","name":"params","type":"tuple"},{"components":[{"internalType":"address","name":"quoteRelayer","type":"address"},{"internalType":"int256","name":"quoteExclusivitySeconds","type":"int256"},{"internalType":"bytes","name":"quoteId","type":"bytes"},{"internalType":"uint256","name":"zapNative","type":"uint256"},{"internalType":"bytes","name":"zapData","type":"bytes"}],"internalType":"struct IFastBridgeV2.BridgeParamsV2","name":"paramsV2","type":"tuple"}],"name":"bridge","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"transactionId","type":"bytes32"}],"name":"bridgeProofs","outputs":[{"internalType":"uint96","name":"timestamp","type":"uint96"},{"internalType":"address","name":"relayer","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"bridgeRelayDetails","outputs":[{"internalType":"uint48","name":"blockNumber","type":"uint48"},{"internalType":"uint48","name":"blockTimestamp","type":"uint48"},{"internalType":"address","name":"relayer","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"transactionId","type":"bytes32"}],"name":"bridgeRelays","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"transactionId","type":"bytes32"}],"name":"bridgeStatuses","outputs":[{"internalType":"enum IFastBridgeV2.BridgeStatus","name":"status","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"bridgeTxDetails","outputs":[{"internalType":"enum IFastBridgeV2.BridgeStatus","name":"status","type":"uint8"},{"internalType":"uint32","name":"destChainId","type":"uint32"},{"internalType":"uint56","name":"proofBlockTimestamp","type":"uint56"},{"internalType":"address","name":"proofRelayer","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"internalType":"address","name":"relayer","type":"address"}],"name":"canClaim","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"chainGasAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"},{"internalType":"address","name":"to","type":"address"}],"name":"claim","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"}],"name":"claim","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"deployBlock","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"transactionId","type":"bytes32"}],"name":"dispute","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"}],"name":"getBridgeTransaction","outputs":[{"components":[{"internalType":"uint32","name":"originChainId","type":"uint32"},{"internalType":"uint32","name":"destChainId","type":"uint32"},{"internalType":"address","name":"originSender","type":"address"},{"internalType":"address","name":"destRecipient","type":"address"},{"internalType":"address","name":"originToken","type":"address"},{"internalType":"address","name":"destToken","type":"address"},{"internalType":"uint256","name":"originAmount","type":"uint256"},{"internalType":"uint256","name":"destAmount","type":"uint256"},{"internalType":"uint256","name":"originFeeAmount","type":"uint256"},{"internalType":"bool","name":"sendChainGas","type":"bool"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint256","name":"nonce","type":"uint256"}],"internalType":"struct IFastBridge.BridgeTransaction","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"}],"name":"getBridgeTransactionV2","outputs":[{"components":[{"internalType":"uint32","name":"originChainId","type":"uint32"},{"internalType":"uint32","name":"destChainId","type":"uint32"},{"internalType":"address","name":"originSender","type":"address"},{"internalType":"address","name":"destRecipient","type":"address"},{"internalType":"address","name":"originToken","type":"address"},{"internalType":"address","name":"destToken","type":"address"},{"internalType":"uint256","name":"originAmount","type":"uint256"},{"internalType":"uint256","name":"destAmount","type":"uint256"},{"internalType":"uint256","name":"originFeeAmount","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"address","name":"exclusivityRelayer","type":"address"},{"internalType":"uint256","name":"exclusivityEndTime","type":"uint256"},{"internalType":"uint256","name":"zapNative","type":"uint256"},{"internalType":"bytes","name":"zapData","type":"bytes"}],"internalType":"struct IFastBridgeV2.BridgeTransactionV2","name":"","type":"tuple"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleAdmin","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"uint256","name":"index","type":"uint256"}],"name":"getRoleMember","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleMemberCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"grantRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"hasRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes[]","name":"data","type":"bytes[]"},{"internalType":"bool","name":"ignoreReverts","type":"bool"}],"name":"multicallNoResults","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes[]","name":"data","type":"bytes[]"},{"internalType":"bool","name":"ignoreReverts","type":"bool"}],"name":"multicallWithResults","outputs":[{"components":[{"internalType":"bool","name":"success","type":"bool"},{"internalType":"bytes","name":"returnData","type":"bytes"}],"internalType":"struct IMulticallTarget.Result[]","name":"results","type":"tuple[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"nonce","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"protocolFeeRate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"protocolFees","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"internalType":"bytes32","name":"destTxHash","type":"bytes32"},{"internalType":"address","name":"relayer","type":"address"}],"name":"prove","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"},{"internalType":"bytes32","name":"destTxHash","type":"bytes32"}],"name":"prove","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"}],"name":"refund","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"}],"name":"relay","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"},{"internalType":"address","name":"relayer","type":"address"}],"name":"relay","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"callerConfirmation","type":"address"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"revokeRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"senderNonces","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"newChainGasAmount","type":"uint256"}],"name":"setChainGasAmount","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"newFeeRate","type":"uint256"}],"name":"setProtocolFeeRate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"address","name":"recipient","type":"address"}],"name":"sweepProtocolFees","outputs":[],"stateMutability":"nonpayable","type":"function"}],"userDoc":{"kind":"user","methods":{"DISPUTE_PERIOD()":{"notice":"Dispute period for relayed transactions"},"MAX_ZAP_DATA_LENGTH()":{"notice":"Maximum length of accepted zapData"},"MIN_DEADLINE_PERIOD()":{"notice":"Minimum deadline period to relay a requested bridge transaction"},"NATIVE_GAS_TOKEN()":{"notice":"Address reserved for native gas token (ETH on Ethereum and most L2s, AVAX on Avalanche, etc)"},"REFUND_DELAY()":{"notice":"Delay for a transaction after which it could be permisionlessly refunded"},"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256))":{"notice":"Initiates bridge on origin chain to be relayed by off-chain relayer"},"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256),(address,int256,bytes,uint256,bytes))":{"notice":"Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability to provide temporary exclusivity fill rights for the quote relayer."},"bridgeProofs(bytes32)":{"notice":"Returns the timestamp and relayer of a bridge proof"},"bridgeRelayDetails(bytes32)":{"notice":"Relay details on destination chain"},"bridgeRelays(bytes32)":{"notice":"Checks if a transaction has been relayed"},"bridgeStatuses(bytes32)":{"notice":"Returns the status of a bridge transaction"},"bridgeTxDetails(bytes32)":{"notice":"Status of the bridge tx on origin chain"},"canClaim(bytes32,address)":{"notice":"Checks if the dispute period has passed so bridge deposit can be claimed"},"chainGasAmount()":{"notice":"Chain gas amount to forward as rebate if requested"},"claim(bytes)":{"notice":"Completes bridge transaction on origin chain by claiming originally deposited capital.Can only send funds to the relayer address on the proof."},"claim(bytes,address)":{"notice":"Completes bridge transaction on origin chain by claiming originally deposited capital"},"deployBlock()":{"notice":"the block the contract was deployed at"},"dispute(bytes32)":{"notice":"Disputes an outstanding proof in case relayer provided dest chain tx is invalid"},"getBridgeTransaction(bytes)":{"notice":"Decodes bridge request into a bridge transaction"},"getBridgeTransactionV2(bytes)":{"notice":"Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2"},"multicallNoResults(bytes[],bool)":{"notice":"Perform a batched call to this contract, preserving the msg.sender. The return data from each call is discarded."},"multicallWithResults(bytes[],bool)":{"notice":"Perform a batched call to this contract, preserving the msg.sender. The return data from each call is preserved."},"nonce()":{"notice":"This is deprecated and should not be used."},"protocolFeeRate()":{"notice":"Protocol fee rate taken on origin amount deposited in origin chain"},"protocolFees(address)":{"notice":"Protocol fee amounts accumulated"},"prove(bytes,bytes32)":{"notice":"Provides proof on origin side that relayer provided funds on destination side of bridge transaction"},"prove(bytes32,bytes32,address)":{"notice":"Provides proof on origin side that relayer provided funds on destination side of bridge transaction"},"refund(bytes)":{"notice":"Refunds an outstanding bridge transaction in case optimistic bridging failed"},"relay(bytes)":{"notice":"Relays destination side of bridge transaction by off-chain relayer"},"relay(bytes,address)":{"notice":"Relays destination side of bridge transaction by off-chain relayer"},"senderNonces(address)":{"notice":"Unique bridge nonces tracked per originSender"}},"notice":"FastBridgeV2 is a contract for bridging tokens across chains.","version":1},"developerDoc":{"errors":{"AccessControlBadConfirmation()":[{"details":"The caller of a function is not the expected one. NOTE: Don't confuse with {AccessControlUnauthorizedAccount}."}],"AccessControlUnauthorizedAccount(address,bytes32)":[{"details":"The `account` is missing a role."}],"AddressEmptyCode(address)":[{"details":"There's no code at `target` (it is not a contract)."}],"AddressInsufficientBalance(address)":[{"details":"The ETH balance of the account is not enough to perform the operation."}],"FailedInnerCall()":[{"details":"A call to an address target failed. The target may have reverted."}],"SafeERC20FailedOperation(address)":[{"details":"An operation with an ERC20 token failed."}]},"events":{"RoleAdminChanged(bytes32,bytes32,bytes32)":{"details":"Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole` `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite {RoleAdminChanged} not being emitted signaling this."},"RoleGranted(bytes32,address,address)":{"details":"Emitted when `account` is granted `role`. `sender` is the account that originated the contract call, an admin role bearer except when using {AccessControl-_setupRole}."},"RoleRevoked(bytes32,address,address)":{"details":"Emitted when `account` is revoked `role`. `sender` is the account that originated the contract call: - if using `revokeRole`, it is the admin role bearer - if using `renounceRole`, it is the role bearer (i.e. `account`)"}},"kind":"dev","methods":{"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256))":{"params":{"params":"The parameters required to bridge"}},"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256),(address,int256,bytes,uint256,bytes))":{"params":{"params":"The parameters required to bridge","paramsV2":"The parameters for exclusivity fill rights (optional, can be left empty)"}},"bridgeProofs(bytes32)":{"params":{"transactionId":"The ID of the bridge transaction"},"returns":{"relayer":"The relayer address of the bridge proof","timestamp":"The timestamp of the bridge proof"}},"bridgeRelays(bytes32)":{"params":{"transactionId":"The ID of the transaction to check"},"returns":{"_0":"True if the transaction has been relayed, false otherwise"}},"bridgeStatuses(bytes32)":{"params":{"transactionId":"The ID of the bridge transaction"},"returns":{"status":"BridgeStatus Status of the bridge transaction"}},"canClaim(bytes32,address)":{"params":{"relayer":"The address of the relayer attempting to claim","transactionId":"The transaction id associated with the encoded bridge transaction to check"}},"claim(bytes)":{"params":{"request":"The encoded bridge transaction to claim on origin chain"}},"claim(bytes,address)":{"params":{"request":"The encoded bridge transaction to claim on origin chain","to":"The recipient address of the funds"}},"dispute(bytes32)":{"params":{"transactionId":"The transaction id associated with the encoded bridge transaction to dispute"}},"getBridgeTransaction(bytes)":{"details":"This method is added to achieve backwards compatibility with decoding requests into V1 structs: - `zapNative` is partially reported as a zero/non-zero flag - `zapData` is ignored In order to process all kinds of requests use getBridgeTransactionV2 instead.","params":{"request":"The bridge request to decode"}},"getBridgeTransactionV2(bytes)":{"params":{"request":"The bridge request to decode"}},"getRoleAdmin(bytes32)":{"details":"Returns the admin role that controls `role`. See {grantRole} and {revokeRole}. To change a role's admin, use {_setRoleAdmin}."},"getRoleMember(bytes32,uint256)":{"details":"Returns one of the accounts that have `role`. `index` must be a value between 0 and {getRoleMemberCount}, non-inclusive. Role bearers are not sorted in any particular way, and their ordering may change at any point. WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure you perform all queries on the same block. See the following https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post] for more information."},"getRoleMemberCount(bytes32)":{"details":"Returns the number of accounts that have `role`. Can be used together with {getRoleMember} to enumerate all bearers of a role."},"grantRole(bytes32,address)":{"details":"Grants `role` to `account`. If `account` had not been already granted `role`, emits a {RoleGranted} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleGranted} event."},"hasRole(bytes32,address)":{"details":"Returns `true` if `account` has been granted `role`."},"multicallNoResults(bytes[],bool)":{"details":"The method is non-payable, so only calls with `msg.value == 0` could be batched. It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag. Otherwise, the whole batch call will be reverted with the original revert reason.","params":{"data":"List of abi-encoded calldata for the calls to perform.","ignoreReverts":"Whether to ignore the revert errors from the calls."}},"multicallWithResults(bytes[],bool)":{"details":"The method is non-payable, so only calls with `msg.value == 0` could be batched. It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag. Otherwise, the whole batch call will be reverted with the original revert reason.","params":{"data":"List of abi-encoded calldata for the calls to perform.","ignoreReverts":"Whether to ignore the revert errors from the calls."},"returns":{"results":" List of results from the calls: `(success, returnData)`."}},"prove(bytes,bytes32)":{"params":{"destTxHash":"The destination tx hash proving bridge transaction was relayed","request":"The encoded bridge transaction to prove on origin chain"}},"prove(bytes32,bytes32,address)":{"params":{"destTxHash":"The destination tx hash proving bridge transaction was relayed","relayer":"The address of the relaying entity which should have control of the origin funds when claimed","transactionId":"The transaction id associated with the encoded bridge transaction to prove"}},"refund(bytes)":{"params":{"request":"The encoded bridge transaction to refund"}},"relay(bytes)":{"params":{"request":"The encoded bridge transaction to relay on destination chain"}},"relay(bytes,address)":{"params":{"relayer":"The address of the relaying entity which should have control of the origin funds when claimed","request":"The encoded bridge transaction to relay on destination chain"}},"renounceRole(bytes32,address)":{"details":"Revokes `role` from the calling account. Roles are often managed via {grantRole} and {revokeRole}: this function's purpose is to provide a mechanism for accounts to lose their privileges if they are compromised (such as when a trusted device is misplaced). If the calling account had been revoked `role`, emits a {RoleRevoked} event. Requirements: - the caller must be `callerConfirmation`. May emit a {RoleRevoked} event."},"revokeRole(bytes32,address)":{"details":"Revokes `role` from `account`. If `account` had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleRevoked} event."},"supportsInterface(bytes4)":{"details":"See {IERC165-supportsInterface}."}},"stateVariables":{"nonce":{"details":"Replaced by senderNonces"}},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_owner\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"AccessControlBadConfirmation\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"neededRole\",\"type\":\"bytes32\"}],\"name\":\"AccessControlUnauthorizedAccount\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"}],\"name\":\"AddressEmptyCode\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"AddressInsufficientBalance\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"AmountIncorrect\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"BridgeTransactionV2__InvalidEncodedTx\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint16\",\"name\":\"version\",\"type\":\"uint16\"}],\"name\":\"BridgeTransactionV2__UnsupportedVersion\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ChainIncorrect\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DeadlineExceeded\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DeadlineNotExceeded\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DeadlineTooShort\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DisputePeriodNotPassed\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DisputePeriodPassed\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ExclusivityParamsIncorrect\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ExclusivityPeriodNotPassed\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"FailedInnerCall\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"MsgValueIncorrect\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"MulticallTarget__UndeterminedRevert\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"RecipientIncorrectReturnValue\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"RecipientNoReturnValue\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"}],\"name\":\"SafeERC20FailedOperation\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"SenderIncorrect\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"StatusIncorrect\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"TokenNotContract\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"TransactionRelayed\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ZapDataLengthAboveMax\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ZapNativeNotSupported\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ZeroAddress\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"BridgeDepositClaimed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"BridgeDepositRefunded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"name\":\"BridgeProofDisputed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"transactionHash\",\"type\":\"bytes32\"}],\"name\":\"BridgeProofProvided\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"quoteId\",\"type\":\"bytes\"}],\"name\":\"BridgeQuoteDetails\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"originChainId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"chainGasAmount\",\"type\":\"uint256\"}],\"name\":\"BridgeRelayed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"destChainId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"sendChainGas\",\"type\":\"bool\"}],\"name\":\"BridgeRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"oldChainGasAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newChainGasAmount\",\"type\":\"uint256\"}],\"name\":\"ChainGasAmountUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"oldFeeRate\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newFeeRate\",\"type\":\"uint256\"}],\"name\":\"FeeRateUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"FeesSwept\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"previousAdminRole\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"newAdminRole\",\"type\":\"bytes32\"}],\"name\":\"RoleAdminChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleGranted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleRevoked\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"DEFAULT_ADMIN_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"DISPUTE_PERIOD\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"FEE_BPS\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"FEE_RATE_MAX\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"GOVERNOR_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"GUARD_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"MAX_ZAP_DATA_LENGTH\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"MIN_DEADLINE_PERIOD\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"NATIVE_GAS_TOKEN\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"REFUNDER_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"REFUND_DELAY\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"RELAYER_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"dstChainId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"sendChainGas\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"}],\"internalType\":\"struct IFastBridge.BridgeParams\",\"name\":\"params\",\"type\":\"tuple\"}],\"name\":\"bridge\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"dstChainId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"sendChainGas\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"}],\"internalType\":\"struct IFastBridge.BridgeParams\",\"name\":\"params\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"quoteRelayer\",\"type\":\"address\"},{\"internalType\":\"int256\",\"name\":\"quoteExclusivitySeconds\",\"type\":\"int256\"},{\"internalType\":\"bytes\",\"name\":\"quoteId\",\"type\":\"bytes\"},{\"internalType\":\"uint256\",\"name\":\"zapNative\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"zapData\",\"type\":\"bytes\"}],\"internalType\":\"struct IFastBridgeV2.BridgeParamsV2\",\"name\":\"paramsV2\",\"type\":\"tuple\"}],\"name\":\"bridge\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"}],\"name\":\"bridgeProofs\",\"outputs\":[{\"internalType\":\"uint96\",\"name\":\"timestamp\",\"type\":\"uint96\"},{\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"bridgeRelayDetails\",\"outputs\":[{\"internalType\":\"uint48\",\"name\":\"blockNumber\",\"type\":\"uint48\"},{\"internalType\":\"uint48\",\"name\":\"blockTimestamp\",\"type\":\"uint48\"},{\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"}],\"name\":\"bridgeRelays\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"}],\"name\":\"bridgeStatuses\",\"outputs\":[{\"internalType\":\"enum IFastBridgeV2.BridgeStatus\",\"name\":\"status\",\"type\":\"uint8\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"bridgeTxDetails\",\"outputs\":[{\"internalType\":\"enum IFastBridgeV2.BridgeStatus\",\"name\":\"status\",\"type\":\"uint8\"},{\"internalType\":\"uint32\",\"name\":\"destChainId\",\"type\":\"uint32\"},{\"internalType\":\"uint56\",\"name\":\"proofBlockTimestamp\",\"type\":\"uint56\"},{\"internalType\":\"address\",\"name\":\"proofRelayer\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"name\":\"canClaim\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"chainGasAmount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"claim\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"claim\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"deployBlock\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"}],\"name\":\"dispute\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"getBridgeTransaction\",\"outputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"originChainId\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"destChainId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"originSender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destRecipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"originFeeAmount\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"sendChainGas\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"}],\"internalType\":\"struct IFastBridge.BridgeTransaction\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"getBridgeTransactionV2\",\"outputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"originChainId\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"destChainId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"originSender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destRecipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"originFeeAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"exclusivityRelayer\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"exclusivityEndTime\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"zapNative\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"zapData\",\"type\":\"bytes\"}],\"internalType\":\"struct IFastBridgeV2.BridgeTransactionV2\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"}],\"name\":\"getRoleAdmin\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"index\",\"type\":\"uint256\"}],\"name\":\"getRoleMember\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"}],\"name\":\"getRoleMemberCount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"grantRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"hasRole\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes[]\",\"name\":\"data\",\"type\":\"bytes[]\"},{\"internalType\":\"bool\",\"name\":\"ignoreReverts\",\"type\":\"bool\"}],\"name\":\"multicallNoResults\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes[]\",\"name\":\"data\",\"type\":\"bytes[]\"},{\"internalType\":\"bool\",\"name\":\"ignoreReverts\",\"type\":\"bool\"}],\"name\":\"multicallWithResults\",\"outputs\":[{\"components\":[{\"internalType\":\"bool\",\"name\":\"success\",\"type\":\"bool\"},{\"internalType\":\"bytes\",\"name\":\"returnData\",\"type\":\"bytes\"}],\"internalType\":\"struct IMulticallTarget.Result[]\",\"name\":\"results\",\"type\":\"tuple[]\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"nonce\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"protocolFeeRate\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"protocolFees\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"destTxHash\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"name\":\"prove\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"},{\"internalType\":\"bytes32\",\"name\":\"destTxHash\",\"type\":\"bytes32\"}],\"name\":\"prove\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"refund\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"relay\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"},{\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"name\":\"relay\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"callerConfirmation\",\"type\":\"address\"}],\"name\":\"renounceRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"revokeRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"senderNonces\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"newChainGasAmount\",\"type\":\"uint256\"}],\"name\":\"setChainGasAmount\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"newFeeRate\",\"type\":\"uint256\"}],\"name\":\"setProtocolFeeRate\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes4\",\"name\":\"interfaceId\",\"type\":\"bytes4\"}],\"name\":\"supportsInterface\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"}],\"name\":\"sweepProtocolFees\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"errors\":{\"AccessControlBadConfirmation()\":[{\"details\":\"The caller of a function is not the expected one. NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\"}],\"AccessControlUnauthorizedAccount(address,bytes32)\":[{\"details\":\"The `account` is missing a role.\"}],\"AddressEmptyCode(address)\":[{\"details\":\"There's no code at `target` (it is not a contract).\"}],\"AddressInsufficientBalance(address)\":[{\"details\":\"The ETH balance of the account is not enough to perform the operation.\"}],\"FailedInnerCall()\":[{\"details\":\"A call to an address target failed. The target may have reverted.\"}],\"SafeERC20FailedOperation(address)\":[{\"details\":\"An operation with an ERC20 token failed.\"}]},\"events\":{\"RoleAdminChanged(bytes32,bytes32,bytes32)\":{\"details\":\"Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole` `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite {RoleAdminChanged} not being emitted signaling this.\"},\"RoleGranted(bytes32,address,address)\":{\"details\":\"Emitted when `account` is granted `role`. `sender` is the account that originated the contract call, an admin role bearer except when using {AccessControl-_setupRole}.\"},\"RoleRevoked(bytes32,address,address)\":{\"details\":\"Emitted when `account` is revoked `role`. `sender` is the account that originated the contract call: - if using `revokeRole`, it is the admin role bearer - if using `renounceRole`, it is the role bearer (i.e. `account`)\"}},\"kind\":\"dev\",\"methods\":{\"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256))\":{\"params\":{\"params\":\"The parameters required to bridge\"}},\"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256),(address,int256,bytes,uint256,bytes))\":{\"params\":{\"params\":\"The parameters required to bridge\",\"paramsV2\":\"The parameters for exclusivity fill rights (optional, can be left empty)\"}},\"bridgeProofs(bytes32)\":{\"params\":{\"transactionId\":\"The ID of the bridge transaction\"},\"returns\":{\"relayer\":\"The relayer address of the bridge proof\",\"timestamp\":\"The timestamp of the bridge proof\"}},\"bridgeRelays(bytes32)\":{\"params\":{\"transactionId\":\"The ID of the transaction to check\"},\"returns\":{\"_0\":\"True if the transaction has been relayed, false otherwise\"}},\"bridgeStatuses(bytes32)\":{\"params\":{\"transactionId\":\"The ID of the bridge transaction\"},\"returns\":{\"status\":\"BridgeStatus Status of the bridge transaction\"}},\"canClaim(bytes32,address)\":{\"params\":{\"relayer\":\"The address of the relayer attempting to claim\",\"transactionId\":\"The transaction id associated with the encoded bridge transaction to check\"}},\"claim(bytes)\":{\"params\":{\"request\":\"The encoded bridge transaction to claim on origin chain\"}},\"claim(bytes,address)\":{\"params\":{\"request\":\"The encoded bridge transaction to claim on origin chain\",\"to\":\"The recipient address of the funds\"}},\"dispute(bytes32)\":{\"params\":{\"transactionId\":\"The transaction id associated with the encoded bridge transaction to dispute\"}},\"getBridgeTransaction(bytes)\":{\"details\":\"This method is added to achieve backwards compatibility with decoding requests into V1 structs: - `zapNative` is partially reported as a zero/non-zero flag - `zapData` is ignored In order to process all kinds of requests use getBridgeTransactionV2 instead.\",\"params\":{\"request\":\"The bridge request to decode\"}},\"getBridgeTransactionV2(bytes)\":{\"params\":{\"request\":\"The bridge request to decode\"}},\"getRoleAdmin(bytes32)\":{\"details\":\"Returns the admin role that controls `role`. See {grantRole} and {revokeRole}. To change a role's admin, use {_setRoleAdmin}.\"},\"getRoleMember(bytes32,uint256)\":{\"details\":\"Returns one of the accounts that have `role`. `index` must be a value between 0 and {getRoleMemberCount}, non-inclusive. Role bearers are not sorted in any particular way, and their ordering may change at any point. WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure you perform all queries on the same block. See the following https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post] for more information.\"},\"getRoleMemberCount(bytes32)\":{\"details\":\"Returns the number of accounts that have `role`. Can be used together with {getRoleMember} to enumerate all bearers of a role.\"},\"grantRole(bytes32,address)\":{\"details\":\"Grants `role` to `account`. If `account` had not been already granted `role`, emits a {RoleGranted} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleGranted} event.\"},\"hasRole(bytes32,address)\":{\"details\":\"Returns `true` if `account` has been granted `role`.\"},\"multicallNoResults(bytes[],bool)\":{\"details\":\"The method is non-payable, so only calls with `msg.value == 0` could be batched. It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag. Otherwise, the whole batch call will be reverted with the original revert reason.\",\"params\":{\"data\":\"List of abi-encoded calldata for the calls to perform.\",\"ignoreReverts\":\"Whether to ignore the revert errors from the calls.\"}},\"multicallWithResults(bytes[],bool)\":{\"details\":\"The method is non-payable, so only calls with `msg.value == 0` could be batched. It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag. Otherwise, the whole batch call will be reverted with the original revert reason.\",\"params\":{\"data\":\"List of abi-encoded calldata for the calls to perform.\",\"ignoreReverts\":\"Whether to ignore the revert errors from the calls.\"},\"returns\":{\"results\":\" List of results from the calls: `(success, returnData)`.\"}},\"prove(bytes,bytes32)\":{\"params\":{\"destTxHash\":\"The destination tx hash proving bridge transaction was relayed\",\"request\":\"The encoded bridge transaction to prove on origin chain\"}},\"prove(bytes32,bytes32,address)\":{\"params\":{\"destTxHash\":\"The destination tx hash proving bridge transaction was relayed\",\"relayer\":\"The address of the relaying entity which should have control of the origin funds when claimed\",\"transactionId\":\"The transaction id associated with the encoded bridge transaction to prove\"}},\"refund(bytes)\":{\"params\":{\"request\":\"The encoded bridge transaction to refund\"}},\"relay(bytes)\":{\"params\":{\"request\":\"The encoded bridge transaction to relay on destination chain\"}},\"relay(bytes,address)\":{\"params\":{\"relayer\":\"The address of the relaying entity which should have control of the origin funds when claimed\",\"request\":\"The encoded bridge transaction to relay on destination chain\"}},\"renounceRole(bytes32,address)\":{\"details\":\"Revokes `role` from the calling account. Roles are often managed via {grantRole} and {revokeRole}: this function's purpose is to provide a mechanism for accounts to lose their privileges if they are compromised (such as when a trusted device is misplaced). If the calling account had been revoked `role`, emits a {RoleRevoked} event. Requirements: - the caller must be `callerConfirmation`. May emit a {RoleRevoked} event.\"},\"revokeRole(bytes32,address)\":{\"details\":\"Revokes `role` from `account`. If `account` had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleRevoked} event.\"},\"supportsInterface(bytes4)\":{\"details\":\"See {IERC165-supportsInterface}.\"}},\"stateVariables\":{\"nonce\":{\"details\":\"Replaced by senderNonces\"}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"DISPUTE_PERIOD()\":{\"notice\":\"Dispute period for relayed transactions\"},\"MAX_ZAP_DATA_LENGTH()\":{\"notice\":\"Maximum length of accepted zapData\"},\"MIN_DEADLINE_PERIOD()\":{\"notice\":\"Minimum deadline period to relay a requested bridge transaction\"},\"NATIVE_GAS_TOKEN()\":{\"notice\":\"Address reserved for native gas token (ETH on Ethereum and most L2s, AVAX on Avalanche, etc)\"},\"REFUND_DELAY()\":{\"notice\":\"Delay for a transaction after which it could be permisionlessly refunded\"},\"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256))\":{\"notice\":\"Initiates bridge on origin chain to be relayed by off-chain relayer\"},\"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256),(address,int256,bytes,uint256,bytes))\":{\"notice\":\"Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability to provide temporary exclusivity fill rights for the quote relayer.\"},\"bridgeProofs(bytes32)\":{\"notice\":\"Returns the timestamp and relayer of a bridge proof\"},\"bridgeRelayDetails(bytes32)\":{\"notice\":\"Relay details on destination chain\"},\"bridgeRelays(bytes32)\":{\"notice\":\"Checks if a transaction has been relayed\"},\"bridgeStatuses(bytes32)\":{\"notice\":\"Returns the status of a bridge transaction\"},\"bridgeTxDetails(bytes32)\":{\"notice\":\"Status of the bridge tx on origin chain\"},\"canClaim(bytes32,address)\":{\"notice\":\"Checks if the dispute period has passed so bridge deposit can be claimed\"},\"chainGasAmount()\":{\"notice\":\"Chain gas amount to forward as rebate if requested\"},\"claim(bytes)\":{\"notice\":\"Completes bridge transaction on origin chain by claiming originally deposited capital.Can only send funds to the relayer address on the proof.\"},\"claim(bytes,address)\":{\"notice\":\"Completes bridge transaction on origin chain by claiming originally deposited capital\"},\"deployBlock()\":{\"notice\":\"the block the contract was deployed at\"},\"dispute(bytes32)\":{\"notice\":\"Disputes an outstanding proof in case relayer provided dest chain tx is invalid\"},\"getBridgeTransaction(bytes)\":{\"notice\":\"Decodes bridge request into a bridge transaction\"},\"getBridgeTransactionV2(bytes)\":{\"notice\":\"Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\"},\"multicallNoResults(bytes[],bool)\":{\"notice\":\"Perform a batched call to this contract, preserving the msg.sender. The return data from each call is discarded.\"},\"multicallWithResults(bytes[],bool)\":{\"notice\":\"Perform a batched call to this contract, preserving the msg.sender. The return data from each call is preserved.\"},\"nonce()\":{\"notice\":\"This is deprecated and should not be used.\"},\"protocolFeeRate()\":{\"notice\":\"Protocol fee rate taken on origin amount deposited in origin chain\"},\"protocolFees(address)\":{\"notice\":\"Protocol fee amounts accumulated\"},\"prove(bytes,bytes32)\":{\"notice\":\"Provides proof on origin side that relayer provided funds on destination side of bridge transaction\"},\"prove(bytes32,bytes32,address)\":{\"notice\":\"Provides proof on origin side that relayer provided funds on destination side of bridge transaction\"},\"refund(bytes)\":{\"notice\":\"Refunds an outstanding bridge transaction in case optimistic bridging failed\"},\"relay(bytes)\":{\"notice\":\"Relays destination side of bridge transaction by off-chain relayer\"},\"relay(bytes,address)\":{\"notice\":\"Relays destination side of bridge transaction by off-chain relayer\"},\"senderNonces(address)\":{\"notice\":\"Unique bridge nonces tracked per originSender\"}},\"notice\":\"FastBridgeV2 is a contract for bridging tokens across chains.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeV2.sol\":\"FastBridgeV2\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeV2.sol\":{\"keccak256\":\"0x5069b55ca07f21bfe30b2a43c18a18318c8af9c181b2dcb07c290825efd70f34\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://273dc020a49d08e50126bbea0d7f783f79d08c702f2fdbc560618d24af308acc\",\"dweb:/ipfs/QmXJ2UVzFc8EPB74RT4CXQPC4xw66jt4T13poyfyd3UERh\"]}},\"version\":1}"},"hashes":{"DEFAULT_ADMIN_ROLE()":"a217fddf","DISPUTE_PERIOD()":"a5bbe22b","FEE_BPS()":"bf333f2c","FEE_RATE_MAX()":"0f5f6ed7","GOVERNOR_ROLE()":"ccc57490","GUARD_ROLE()":"03ed0ee5","MAX_ZAP_DATA_LENGTH()":"54eff068","MIN_DEADLINE_PERIOD()":"820688d5","NATIVE_GAS_TOKEN()":"0f862f1e","REFUNDER_ROLE()":"5960ccf2","REFUND_DELAY()":"190da595","RELAYER_ROLE()":"926d7d7f","bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256))":"45851694","bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256),(address,int256,bytes,uint256,bytes))":"bfc7c607","bridgeProofs(bytes32)":"91ad5039","bridgeRelayDetails(bytes32)":"c79371b1","bridgeRelays(bytes32)":"8379a24f","bridgeStatuses(bytes32)":"051287bc","bridgeTxDetails(bytes32)":"63787e52","canClaim(bytes32,address)":"aa9641ab","chainGasAmount()":"e00a83e0","claim(bytes)":"c63ff8dd","claim(bytes,address)":"41fcb612","deployBlock()":"a3ec191a","dispute(bytes32)":"add98c70","getBridgeTransaction(bytes)":"ac11fb1a","getBridgeTransactionV2(bytes)":"5aa6ccba","getRoleAdmin(bytes32)":"248a9ca3","getRoleMember(bytes32,uint256)":"9010d07c","getRoleMemberCount(bytes32)":"ca15c873","grantRole(bytes32,address)":"2f2ff15d","hasRole(bytes32,address)":"91d14854","multicallNoResults(bytes[],bool)":"3f61331d","multicallWithResults(bytes[],bool)":"385c1d2f","nonce()":"affed0e0","protocolFeeRate()":"58f85880","protocolFees(address)":"dcf844a7","prove(bytes,bytes32)":"886d36ff","prove(bytes32,bytes32,address)":"18e4357d","refund(bytes)":"5eb7d946","relay(bytes)":"8f0d6f17","relay(bytes,address)":"9c9545f0","renounceRole(bytes32,address)":"36568abe","revokeRole(bytes32,address)":"d547741f","senderNonces(address)":"295710ff","setChainGasAmount(uint256)":"b250fe6b","setProtocolFeeRate(uint256)":"b13aa2d6","supportsInterface(bytes4)":"01ffc9a7","sweepProtocolFees(address,address)":"06f333f2"}},"solidity/FastBridgeV2.sol:IAccessControl":{"code":"0x","runtime-code":"0x","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.24 ^0.8.20 ^0.8.4;\n\n// contracts/interfaces/IAdmin.sol\n\ninterface IAdmin {\n // ============ Events ============\n\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n event ChainGasAmountUpdated(uint256 oldChainGasAmount, uint256 newChainGasAmount);\n\n // ============ Methods ============\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n\n function setChainGasAmount(uint256 newChainGasAmount) external;\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IFastBridgeV2Errors.sol\n\ninterface IFastBridgeV2Errors {\n error AmountIncorrect();\n error ChainIncorrect();\n error ExclusivityParamsIncorrect();\n error MsgValueIncorrect();\n error SenderIncorrect();\n error StatusIncorrect();\n error TokenNotContract();\n error ZapDataLengthAboveMax();\n error ZapNativeNotSupported();\n error ZeroAddress();\n\n error RecipientIncorrectReturnValue();\n error RecipientNoReturnValue();\n\n error DeadlineExceeded();\n error DeadlineNotExceeded();\n error DeadlineTooShort();\n error DisputePeriodNotPassed();\n error DisputePeriodPassed();\n error ExclusivityPeriodNotPassed();\n\n error TransactionRelayed();\n}\n\n// contracts/interfaces/IMulticallTarget.sol\n\n/// @notice Interface for a contract that can be called multiple times by the same caller. Inspired by MulticallV3:\n/// https://github.com/mds1/multicall/blob/master/src/Multicall3.sol\ninterface IMulticallTarget {\n struct Result {\n bool success;\n bytes returnData;\n }\n\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external;\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results);\n}\n\n// contracts/interfaces/IZapRecipient.sol\n\ninterface IZapRecipient {\n function zap(address token, uint256 amount, bytes memory zapData) external payable returns (bytes4);\n}\n\n// contracts/libs/Errors.sol\n\nerror DeadlineExceeded();\nerror DeadlineNotExceeded();\nerror DeadlineTooShort();\nerror InsufficientOutputAmount();\n\nerror MsgValueIncorrect();\nerror PoolNotFound();\nerror TokenAddressMismatch();\nerror TokenNotContract();\nerror TokenNotETH();\nerror TokensIdentical();\n\nerror ChainIncorrect();\nerror AmountIncorrect();\nerror ZeroAddress();\n\nerror DisputePeriodNotPassed();\nerror DisputePeriodPassed();\nerror SenderIncorrect();\nerror StatusIncorrect();\nerror TransactionIdIncorrect();\nerror TransactionRelayed();\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// contracts/interfaces/IFastBridgeV2.sol\n\ninterface IFastBridgeV2 is IFastBridge {\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n struct BridgeTxDetails {\n BridgeStatus status;\n uint32 destChainId;\n uint56 proofBlockTimestamp;\n address proofRelayer;\n }\n\n struct BridgeRelay {\n uint48 blockNumber;\n uint48 blockTimestamp;\n address relayer;\n }\n\n /// @notice New params introduced in the FastBridgeV2.\n /// We are passing fields from the older BridgeParams struct outside of this struct\n /// for backwards compatibility.\n /// Note: quoteRelayer and quoteExclusivitySeconds are either both zero (indicating no exclusivity)\n /// or both non-zero (indicating exclusivity for the given period).\n /// Note: zapNative \u003e 0 can NOT be used with destToken = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE (native token)\n /// @param quoteRelayer Relayer that provided the quote for the transaction\n /// @param quoteExclusivitySeconds Period of time the quote relayer is guaranteed exclusivity after user's deposit\n /// @param quoteId Unique quote identifier used for tracking the quote\n /// @param zapNative ETH value to send to the recipient (if any)\n /// @param zapData Parameters for the Zap to the destination recipient (if any)\n struct BridgeParamsV2 {\n address quoteRelayer;\n int256 quoteExclusivitySeconds;\n bytes quoteId;\n uint256 zapNative;\n bytes zapData;\n }\n\n /// @notice Updated bridge transaction struct to include parameters introduced in FastBridgeV2.\n /// Note: only `exclusivityRelayer` can fill such a transaction until `exclusivityEndTime`.\n struct BridgeTransactionV2 {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n // Note: sendChainGas flag from V1 is deprecated\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n address exclusivityRelayer;\n uint256 exclusivityEndTime;\n uint256 zapNative; // ETH value to send to the recipient (if any)\n bytes zapData; // data to pass for the Zap action (if any)\n }\n\n event BridgeQuoteDetails(bytes32 indexed transactionId, bytes quoteId);\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability\n /// to provide temporary exclusivity fill rights for the quote relayer.\n /// @param params The parameters required to bridge\n /// @param paramsV2 The parameters for exclusivity fill rights (optional, can be left empty)\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function relay(bytes memory request, address relayer) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param transactionId The transaction id associated with the encoded bridge transaction to prove\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital.\n /// @notice Can only send funds to the relayer address on the proof.\n /// @param request The encoded bridge transaction to claim on origin chain\n function claim(bytes memory request) external;\n /// @notice Checks if a transaction has been relayed\n /// @param transactionId The ID of the transaction to check\n /// @return True if the transaction has been relayed, false otherwise\n function bridgeRelays(bytes32 transactionId) external view returns (bool);\n\n /// @notice Returns the status of a bridge transaction\n /// @param transactionId The ID of the bridge transaction\n /// @return BridgeStatus Status of the bridge transaction\n function bridgeStatuses(bytes32 transactionId) external view returns (BridgeStatus);\n\n /// @notice Returns the timestamp and relayer of a bridge proof\n /// @param transactionId The ID of the bridge transaction\n /// @return timestamp The timestamp of the bridge proof\n /// @return relayer The relayer address of the bridge proof\n function bridgeProofs(bytes32 transactionId) external view returns (uint96 timestamp, address relayer);\n\n /// @notice Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\n /// @param request The bridge request to decode\n function getBridgeTransactionV2(bytes memory request) external view returns (BridgeTransactionV2 memory);\n}\n\n// contracts/utils/MulticallTarget.sol\n\n// solhint-disable avoid-low-level-calls\n/// @notice Template for a contract that supports batched calls (preserving the msg.sender).\n/// Only calls with zero msg.value could be batched.\nabstract contract MulticallTarget is IMulticallTarget {\n error MulticallTarget__UndeterminedRevert();\n\n /// @notice Perform a batched call to this contract, preserving the msg.sender.\n /// The return data from each call is discarded.\n /// @dev The method is non-payable, so only calls with `msg.value == 0` could be batched.\n /// It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag.\n /// Otherwise, the whole batch call will be reverted with the original revert reason.\n /// @param data List of abi-encoded calldata for the calls to perform.\n /// @param ignoreReverts Whether to ignore the revert errors from the calls.\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external {\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\n if (!success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(result);\n }\n }\n }\n\n /// @notice Perform a batched call to this contract, preserving the msg.sender.\n /// The return data from each call is preserved.\n /// @dev The method is non-payable, so only calls with `msg.value == 0` could be batched.\n /// It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag.\n /// Otherwise, the whole batch call will be reverted with the original revert reason.\n /// @param data List of abi-encoded calldata for the calls to perform.\n /// @param ignoreReverts Whether to ignore the revert errors from the calls.\n /// @return results List of results from the calls: `(success, returnData)`.\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results)\n {\n results = new Result[](data.length);\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (results[i].success, results[i].returnData) = address(this).delegatecall(data[i]);\n if (!results[i].success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(results[i].returnData);\n }\n }\n }\n\n /// @dev Bubbles the revert message from the underlying call.\n /// Note: preserves the same custom error or revert string, if one was used.\n /// Source: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v5.0.2/contracts/utils/Address.sol#L143-L158\n function _bubbleRevert(bytes memory returnData) internal pure {\n // Look for revert reason and bubble it up if present\n if (returnData.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n // solhint-disable-next-line no-inline-assembly\n assembly {\n let returndata_size := mload(returnData)\n revert(add(32, returnData), returndata_size)\n }\n } else {\n revert MulticallTarget__UndeterminedRevert();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// contracts/libs/BridgeTransactionV2.sol\n\n// solhint-disable no-inline-assembly\nlibrary BridgeTransactionV2Lib {\n uint16 internal constant VERSION = 2;\n\n // Offsets of the fields in the packed BridgeTransactionV2 struct\n // uint16 version [000 .. 002)\n // uint32 originChainId [002 .. 006)\n // uint32 destChainId [006 .. 010)\n // address originSender [010 .. 030)\n // address destRecipient [030 .. 050)\n // address originToken [050 .. 070)\n // address destToken [070 .. 090)\n // uint256 originAmount [090 .. 122)\n // uint256 destAmount [122 .. 154)\n // uint256 originFeeAmount [154 .. 186)\n // uint256 deadline [186 .. 218)\n // uint256 nonce [218 .. 250)\n // address exclusivityRelayer [250 .. 270)\n // uint256 exclusivityEndTime [270 .. 302)\n // uint256 zapNative [302 .. 334)\n // bytes zapData [334 .. ***)\n\n // forgefmt: disable-start\n uint256 private constant OFFSET_ORIGIN_CHAIN_ID = 2;\n uint256 private constant OFFSET_DEST_CHAIN_ID = 6;\n uint256 private constant OFFSET_ORIGIN_SENDER = 10;\n uint256 private constant OFFSET_DEST_RECIPIENT = 30;\n uint256 private constant OFFSET_ORIGIN_TOKEN = 50;\n uint256 private constant OFFSET_DEST_TOKEN = 70;\n uint256 private constant OFFSET_ORIGIN_AMOUNT = 90;\n uint256 private constant OFFSET_DEST_AMOUNT = 122;\n uint256 private constant OFFSET_ORIGIN_FEE_AMOUNT = 154;\n uint256 private constant OFFSET_DEADLINE = 186;\n uint256 private constant OFFSET_NONCE = 218;\n uint256 private constant OFFSET_EXCLUSIVITY_RELAYER = 250;\n uint256 private constant OFFSET_EXCLUSIVITY_END_TIME = 270;\n uint256 private constant OFFSET_ZAP_NATIVE = 302;\n uint256 private constant OFFSET_ZAP_DATA = 334;\n // forgefmt: disable-end\n\n error BridgeTransactionV2__InvalidEncodedTx();\n error BridgeTransactionV2__UnsupportedVersion(uint16 version);\n\n /// @notice Validates the encoded transaction to be a tightly packed encoded payload for BridgeTransactionV2.\n /// @dev Checks the minimum length and the version, use this function before decoding any of the fields.\n function validateV2(bytes calldata encodedTx) internal pure {\n // Check the minimum length: must at least include all static fields.\n if (encodedTx.length \u003c OFFSET_ZAP_DATA) revert BridgeTransactionV2__InvalidEncodedTx();\n // Once we validated the length, we can be sure that the version field is present.\n uint16 version_ = version(encodedTx);\n if (version_ != VERSION) revert BridgeTransactionV2__UnsupportedVersion(version_);\n }\n\n /// @notice Encodes the BridgeTransactionV2 struct by tightly packing the fields.\n /// @dev `abi.decode` will not work as a result of the tightly packed fields. Use `decodeV2` to decode instead.\n function encodeV2(IFastBridgeV2.BridgeTransactionV2 memory bridgeTx) internal pure returns (bytes memory) {\n // We split the encoding into two parts to avoid stack-too-deep error\n bytes memory firstPart = abi.encodePacked(\n VERSION,\n bridgeTx.originChainId,\n bridgeTx.destChainId,\n bridgeTx.originSender,\n bridgeTx.destRecipient,\n bridgeTx.originToken,\n bridgeTx.destToken,\n bridgeTx.originAmount\n );\n return abi.encodePacked(\n firstPart,\n bridgeTx.destAmount,\n bridgeTx.originFeeAmount,\n // Note: we skip the deprecated `sendChainGas` flag, which was present in BridgeTransaction V1\n bridgeTx.deadline,\n bridgeTx.nonce,\n // New V2 fields: exclusivity\n bridgeTx.exclusivityRelayer,\n bridgeTx.exclusivityEndTime,\n // New V2 fields: Zap\n bridgeTx.zapNative,\n bridgeTx.zapData\n );\n }\n\n /// @notice Decodes the BridgeTransactionV2 struct from the encoded transaction.\n /// @dev Encoded BridgeTransactionV2 struct must be tightly packed.\n /// Use `validateV2` before decoding to ensure the encoded transaction is valid.\n function decodeV2(bytes calldata encodedTx)\n internal\n pure\n returns (IFastBridgeV2.BridgeTransactionV2 memory bridgeTx)\n {\n bridgeTx.originChainId = originChainId(encodedTx);\n bridgeTx.destChainId = destChainId(encodedTx);\n bridgeTx.originSender = originSender(encodedTx);\n bridgeTx.destRecipient = destRecipient(encodedTx);\n bridgeTx.originToken = originToken(encodedTx);\n bridgeTx.destToken = destToken(encodedTx);\n bridgeTx.originAmount = originAmount(encodedTx);\n bridgeTx.destAmount = destAmount(encodedTx);\n bridgeTx.originFeeAmount = originFeeAmount(encodedTx);\n bridgeTx.deadline = deadline(encodedTx);\n bridgeTx.nonce = nonce(encodedTx);\n bridgeTx.exclusivityRelayer = exclusivityRelayer(encodedTx);\n bridgeTx.exclusivityEndTime = exclusivityEndTime(encodedTx);\n bridgeTx.zapNative = zapNative(encodedTx);\n bridgeTx.zapData = zapData(encodedTx);\n }\n\n /// @notice Extracts the version from the encoded transaction.\n function version(bytes calldata encodedTx) internal pure returns (uint16 version_) {\n // Load 32 bytes from the start and shift it 240 bits to the right to get the highest 16 bits.\n assembly {\n version_ := shr(240, calldataload(encodedTx.offset))\n }\n }\n\n /// @notice Extracts the origin chain ID from the encoded transaction.\n function originChainId(bytes calldata encodedTx) internal pure returns (uint32 originChainId_) {\n // Load 32 bytes from the offset and shift it 224 bits to the right to get the highest 32 bits.\n assembly {\n originChainId_ := shr(224, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_CHAIN_ID)))\n }\n }\n\n /// @notice Extracts the destination chain ID from the encoded transaction.\n function destChainId(bytes calldata encodedTx) internal pure returns (uint32 destChainId_) {\n // Load 32 bytes from the offset and shift it 224 bits to the right to get the highest 32 bits.\n assembly {\n destChainId_ := shr(224, calldataload(add(encodedTx.offset, OFFSET_DEST_CHAIN_ID)))\n }\n }\n\n /// @notice Extracts the origin sender from the encoded transaction.\n function originSender(bytes calldata encodedTx) internal pure returns (address originSender_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n originSender_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_SENDER)))\n }\n }\n\n /// @notice Extracts the destination recipient from the encoded transaction.\n function destRecipient(bytes calldata encodedTx) internal pure returns (address destRecipient_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n destRecipient_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_DEST_RECIPIENT)))\n }\n }\n\n /// @notice Extracts the origin token from the encoded transaction.\n function originToken(bytes calldata encodedTx) internal pure returns (address originToken_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n originToken_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_TOKEN)))\n }\n }\n\n /// @notice Extracts the destination token from the encoded transaction.\n function destToken(bytes calldata encodedTx) internal pure returns (address destToken_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n destToken_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_DEST_TOKEN)))\n }\n }\n\n /// @notice Extracts the origin amount from the encoded transaction.\n function originAmount(bytes calldata encodedTx) internal pure returns (uint256 originAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n originAmount_ := calldataload(add(encodedTx.offset, OFFSET_ORIGIN_AMOUNT))\n }\n }\n\n /// @notice Extracts the destination amount from the encoded transaction.\n function destAmount(bytes calldata encodedTx) internal pure returns (uint256 destAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n destAmount_ := calldataload(add(encodedTx.offset, OFFSET_DEST_AMOUNT))\n }\n }\n\n /// @notice Extracts the origin fee amount from the encoded transaction.\n function originFeeAmount(bytes calldata encodedTx) internal pure returns (uint256 originFeeAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n originFeeAmount_ := calldataload(add(encodedTx.offset, OFFSET_ORIGIN_FEE_AMOUNT))\n }\n }\n\n /// @notice Extracts the deadline from the encoded transaction.\n function deadline(bytes calldata encodedTx) internal pure returns (uint256 deadline_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n deadline_ := calldataload(add(encodedTx.offset, OFFSET_DEADLINE))\n }\n }\n\n /// @notice Extracts the nonce from the encoded transaction.\n function nonce(bytes calldata encodedTx) internal pure returns (uint256 nonce_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n nonce_ := calldataload(add(encodedTx.offset, OFFSET_NONCE))\n }\n }\n\n /// @notice Extracts the exclusivity relayer from the encoded transaction.\n function exclusivityRelayer(bytes calldata encodedTx) internal pure returns (address exclusivityRelayer_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n exclusivityRelayer_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_EXCLUSIVITY_RELAYER)))\n }\n }\n\n /// @notice Extracts the exclusivity end time from the encoded transaction.\n function exclusivityEndTime(bytes calldata encodedTx) internal pure returns (uint256 exclusivityEndTime_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n exclusivityEndTime_ := calldataload(add(encodedTx.offset, OFFSET_EXCLUSIVITY_END_TIME))\n }\n }\n\n /// @notice Extracts the Zap's native value from the encoded transaction.\n function zapNative(bytes calldata encodedTx) internal pure returns (uint256 zapNative_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n zapNative_ := calldataload(add(encodedTx.offset, OFFSET_ZAP_NATIVE))\n }\n }\n\n /// @notice Extracts the Zap's data from the encoded transaction.\n function zapData(bytes calldata encodedTx) internal pure returns (bytes calldata zapData_) {\n zapData_ = encodedTx[OFFSET_ZAP_DATA:];\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// contracts/libs/UniversalToken.sol\n\nlibrary UniversalTokenLib {\n using SafeERC20 for IERC20;\n\n address internal constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Transfers tokens to the given account. Reverts if transfer is not successful.\n /// @dev This might trigger fallback, if ETH is transferred to the contract.\n /// Make sure this can not lead to reentrancy attacks.\n function universalTransfer(address token, address to, uint256 value) internal {\n // Don't do anything, if need to send tokens to this address\n if (to == address(this)) return;\n // Don't do anything, if trying to send zero value\n if (value == 0) return;\n if (token == ETH_ADDRESS) {\n /// @dev Note: this can potentially lead to executing code in `to`.\n // solhint-disable-next-line avoid-low-level-calls\n (bool success,) = to.call{value: value}(\"\");\n require(success, \"ETH transfer failed\");\n } else {\n IERC20(token).safeTransfer(to, value);\n }\n }\n\n /// @notice Issues an infinite allowance to the spender, if the current allowance is insufficient\n /// to spend the given amount.\n function universalApproveInfinity(address token, address spender, uint256 amountToSpend) internal {\n // ETH Chad doesn't require your approval\n if (token == ETH_ADDRESS) return;\n // No-op if allowance is already sufficient\n uint256 allowance = IERC20(token).allowance(address(this), spender);\n if (allowance \u003e= amountToSpend) return;\n // Otherwise, reset approval to 0 and set to max allowance\n if (allowance \u003e 0) IERC20(token).safeDecreaseAllowance(spender, allowance);\n IERC20(token).safeIncreaseAllowance(spender, type(uint256).max);\n }\n\n /// @notice Returns the balance of the given token (or native ETH) for the given account.\n function universalBalanceOf(address token, address account) internal view returns (uint256) {\n if (token == ETH_ADDRESS) {\n return account.balance;\n } else {\n return IERC20(token).balanceOf(account);\n }\n }\n\n /// @dev Checks that token is a contract and not ETH_ADDRESS.\n function assertIsContract(address token) internal view {\n // Check that ETH_ADDRESS was not used (in case this is a predeploy on any of the chains)\n if (token == UniversalTokenLib.ETH_ADDRESS) revert TokenNotContract();\n // Check that token is not an EOA\n if (token.code.length == 0) revert TokenNotContract();\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/Admin.sol\n\ncontract Admin is IAdmin, AccessControlEnumerable {\n using UniversalTokenLib for address;\n\n bytes32 public constant RELAYER_ROLE = keccak256(\"RELAYER_ROLE\");\n bytes32 public constant REFUNDER_ROLE = keccak256(\"REFUNDER_ROLE\");\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n uint256 public constant FEE_BPS = 1e6;\n uint256 public constant FEE_RATE_MAX = 0.01e6; // max 1% on origin amount\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Chain gas amount to forward as rebate if requested\n uint256 public chainGasAmount;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n }\n\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n require(newFeeRate \u003c= FEE_RATE_MAX, \"newFeeRate \u003e max\");\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n token.universalTransfer(recipient, feeAmount);\n emit FeesSwept(token, recipient, feeAmount);\n }\n\n function setChainGasAmount(uint256 newChainGasAmount) external onlyRole(GOVERNOR_ROLE) {\n uint256 oldChainGasAmount = chainGasAmount;\n chainGasAmount = newChainGasAmount;\n emit ChainGasAmountUpdated(oldChainGasAmount, newChainGasAmount);\n }\n}\n\n// contracts/FastBridgeV2.sol\n\n/// @notice FastBridgeV2 is a contract for bridging tokens across chains.\ncontract FastBridgeV2 is Admin, MulticallTarget, IFastBridgeV2, IFastBridgeV2Errors {\n using BridgeTransactionV2Lib for bytes;\n using SafeERC20 for IERC20;\n\n /// @notice Address reserved for native gas token (ETH on Ethereum and most L2s, AVAX on Avalanche, etc)\n address public constant NATIVE_GAS_TOKEN = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Delay for a transaction after which it could be permisionlessly refunded\n uint256 public constant REFUND_DELAY = 7 days;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n /// @notice Maximum length of accepted zapData\n uint256 public constant MAX_ZAP_DATA_LENGTH = 2 ** 16 - 1;\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeTxDetails) public bridgeTxDetails;\n /// @notice Relay details on destination chain\n mapping(bytes32 =\u003e BridgeRelay) public bridgeRelayDetails;\n /// @notice Unique bridge nonces tracked per originSender\n mapping(address =\u003e uint256) public senderNonces;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Replaced by senderNonces\n uint256 public immutable nonce = 0;\n /// @notice the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n bridge({\n params: params,\n paramsV2: BridgeParamsV2({\n quoteRelayer: address(0),\n quoteExclusivitySeconds: 0,\n quoteId: bytes(\"\"),\n zapNative: 0,\n zapData: bytes(\"\")\n })\n });\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes calldata request) external payable {\n // relay override will validate the request\n relay({request: request, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes calldata request, bytes32 destTxHash) external {\n request.validateV2();\n prove({transactionId: keccak256(request), destTxHash: destTxHash, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridgeV2\n function claim(bytes calldata request) external {\n // claim override will validate the request\n claim({request: request, to: address(0)});\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Aggregate the read operations from the same storage slot\n address disputedRelayer = $.proofRelayer;\n BridgeStatus status = $.status;\n uint56 proofBlockTimestamp = $.proofBlockTimestamp;\n // Can only dispute a RELAYER_PROVED transaction within the dispute period\n if (status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(proofBlockTimestamp) \u003e DISPUTE_PERIOD) {\n revert DisputePeriodPassed();\n }\n // Update status to REQUESTED and delete the disputed proof details\n // Note: these are storage writes\n $.status = BridgeStatus.REQUESTED;\n $.proofRelayer = address(0);\n $.proofBlockTimestamp = 0;\n\n emit BridgeProofDisputed(transactionId, disputedRelayer);\n }\n\n /// @inheritdoc IFastBridge\n function refund(bytes calldata request) external {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Can only refund a REQUESTED transaction after its deadline expires\n if ($.status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n uint256 deadline = request.deadline();\n // Permissionless refund is only allowed after REFUND_DELAY on top of the deadline\n if (!hasRole(REFUNDER_ROLE, msg.sender)) deadline += REFUND_DELAY;\n if (block.timestamp \u003c= deadline) revert DeadlineNotExceeded();\n // Update status to REFUNDED and return the full amount (collateral + protocol fees) to the original sender.\n // The protocol fees are only updated when the transaction is claimed, so we don't need to update them here.\n // Note: this is a storage write\n $.status = BridgeStatus.REFUNDED;\n\n address to = request.originSender();\n address token = request.originToken();\n uint256 amount = request.originAmount() + request.originFeeAmount();\n // Emit the event before any external calls\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n // Complete the user refund as the last transaction action\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(to), amount);\n } else {\n IERC20(token).safeTransfer(to, amount);\n }\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // The correct relayer can only claim a RELAYER_PROVED transaction after the dispute period\n if ($.status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if ($.proofRelayer != relayer) revert SenderIncorrect();\n return _timeSince($.proofBlockTimestamp) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n /// @dev This method is added to achieve backwards compatibility with decoding requests into V1 structs:\n /// - `zapNative` is partially reported as a zero/non-zero flag\n /// - `zapData` is ignored\n /// In order to process all kinds of requests use getBridgeTransactionV2 instead.\n function getBridgeTransaction(bytes calldata request) external view returns (BridgeTransaction memory) {\n // Try decoding into V2 struct first. This will revert if V1 struct is passed\n try this.getBridgeTransactionV2(request) returns (BridgeTransactionV2 memory txV2) {\n // Note: we entirely ignore the zapData field, as it was not present in V1\n return BridgeTransaction({\n originChainId: txV2.originChainId,\n destChainId: txV2.destChainId,\n originSender: txV2.originSender,\n destRecipient: txV2.destRecipient,\n originToken: txV2.originToken,\n destToken: txV2.destToken,\n originAmount: txV2.originAmount,\n destAmount: txV2.destAmount,\n originFeeAmount: txV2.originFeeAmount,\n sendChainGas: txV2.zapNative != 0,\n deadline: txV2.deadline,\n nonce: txV2.nonce\n });\n } catch {\n // Fallback to V1 struct\n return abi.decode(request, (BridgeTransaction));\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function getBridgeTransactionV2(bytes calldata request) external pure returns (BridgeTransactionV2 memory) {\n request.validateV2();\n return BridgeTransactionV2Lib.decodeV2(request);\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) public payable {\n int256 exclusivityEndTime = 0;\n // if relayer exclusivity is not intended for this bridge, set exclusivityEndTime to static zero\n // otherwise, set exclusivity to expire at the current block ts offset by quoteExclusivitySeconds\n if (paramsV2.quoteRelayer != address(0)) {\n exclusivityEndTime = int256(block.timestamp) + paramsV2.quoteExclusivitySeconds;\n }\n _validateBridgeParams(params, paramsV2, exclusivityEndTime);\n\n // transfer tokens to bridge contract\n /// @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _takeBridgedUserAsset(params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) {\n originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n }\n\n // set status to requested\n bytes memory request = BridgeTransactionV2Lib.encodeV2(\n BridgeTransactionV2({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n deadline: params.deadline,\n nonce: senderNonces[params.sender]++, // increment nonce on every bridge\n exclusivityRelayer: paramsV2.quoteRelayer,\n // We checked exclusivityEndTime to be in range [0 .. params.deadline] above, so can safely cast\n exclusivityEndTime: uint256(exclusivityEndTime),\n zapNative: paramsV2.zapNative,\n zapData: paramsV2.zapData\n })\n );\n bytes32 transactionId = keccak256(request);\n // Note: the tx status will be updated throughout the tx lifecycle, while destChainId is set once here\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n bridgeTxDetails[transactionId].destChainId = params.dstChainId;\n\n emit BridgeRequested({\n transactionId: transactionId,\n sender: params.sender,\n request: request,\n destChainId: params.dstChainId,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n sendChainGas: paramsV2.zapNative != 0\n });\n emit BridgeQuoteDetails(transactionId, paramsV2.quoteId);\n }\n\n /// @inheritdoc IFastBridgeV2\n function relay(bytes calldata request, address relayer) public payable {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n _validateRelayParams(request, transactionId, relayer);\n // mark bridge transaction as relayed\n bridgeRelayDetails[transactionId] =\n BridgeRelay({blockNumber: uint48(block.number), blockTimestamp: uint48(block.timestamp), relayer: relayer});\n\n // transfer tokens to recipient on destination chain and trigger Zap if requested\n address to = request.destRecipient();\n address token = request.destToken();\n uint256 amount = request.destAmount();\n uint256 zapNative = request.zapNative();\n\n // Emit the event before any external calls\n emit BridgeRelayed({\n transactionId: transactionId,\n relayer: relayer,\n to: to,\n originChainId: request.originChainId(),\n originToken: request.originToken(),\n destToken: token,\n originAmount: request.originAmount(),\n destAmount: amount,\n chainGasAmount: zapNative\n });\n\n // All state changes have been done at this point, can proceed to the external calls.\n // This follows the checks-effects-interactions pattern to mitigate potential reentrancy attacks.\n if (token == NATIVE_GAS_TOKEN) {\n // For the native gas token, additional zapNative is not allowed\n if (zapNative != 0) revert ZapNativeNotSupported();\n // Check that the correct msg.value was sent\n if (msg.value != amount) revert MsgValueIncorrect();\n // Don't do a native transfer yet: we will handle it alongside the Zap below\n } else {\n // For ERC20s, we check that the correct msg.value was sent\n if (msg.value != zapNative) revert MsgValueIncorrect();\n // We need to transfer the tokens from the Relayer to the recipient first before performing an\n // optional post-transfer Zap.\n IERC20(token).safeTransferFrom(msg.sender, to, amount);\n }\n // At this point we have done:\n // - Transferred the requested amount of ERC20 tokens to the recipient.\n // At this point we have confirmed:\n // - For ERC20s: msg.value matches the requested zapNative amount.\n // - For the native gas token: msg.value matches the requested destAmount.\n // Remaining optional things to do:\n // - Forward the full msg.value to the recipient (if non-zero).\n // - Trigger a Zap (if zapData is present).\n bytes calldata zapData = request.zapData();\n if (zapData.length != 0) {\n // Zap Data is present: Zap has been requested by the recipient. Trigger it forwarding the full msg.value.\n\n // Note: if token has a fee on transfers, the recipient will have received less than `amount`.\n // This is a very niche edge case and should be handled by the recipient contract.\n _triggerZapWithChecks({recipient: to, token: token, amount: amount, zapData: zapData});\n } else if (msg.value != 0) {\n // Zap Data is missing, but msg.value was sent. This could happen in two different cases:\n // - Relay with the native gas token is happening.\n // - Relay with ERC20 is happening, with a `zapNative \u003e 0` request.\n // In both cases, we need to transfer the full msg.value to the recipient.\n Address.sendValue(payable(to), msg.value);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) public onlyRole(RELAYER_ROLE) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n\n // Can only prove a REQUESTED transaction\n if ($.status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n // Update status to RELAYER_PROVED and store the proof details\n // Note: these are storage writes\n $.status = BridgeStatus.RELAYER_PROVED;\n $.proofBlockTimestamp = uint56(block.timestamp);\n $.proofRelayer = relayer;\n\n emit BridgeProofProvided(transactionId, relayer, destTxHash);\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes calldata request, address to) public {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Aggregate the read operations from the same storage slot\n address proofRelayer = $.proofRelayer;\n BridgeStatus status = $.status;\n uint56 proofBlockTimestamp = $.proofBlockTimestamp;\n\n // Can only claim a RELAYER_PROVED transaction after the dispute period\n if (status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(proofBlockTimestamp) \u003c= DISPUTE_PERIOD) {\n revert DisputePeriodNotPassed();\n }\n\n if (to == address(0)) {\n // Anyone could claim the funds to the proven relayer on their behalf\n to = proofRelayer;\n } else if (proofRelayer != msg.sender) {\n // Only the proven relayer could specify an address to claim the funds to\n revert SenderIncorrect();\n }\n\n // Update status to RELAYER_CLAIMED and transfer the origin collateral to the specified claim address\n // Note: this is a storage write\n $.status = BridgeStatus.RELAYER_CLAIMED;\n\n address token = request.originToken();\n uint256 amount = request.originAmount();\n // Update protocol fees if origin fee amount exists\n uint256 originFeeAmount = request.originFeeAmount();\n if (originFeeAmount \u003e 0) protocolFees[token] += originFeeAmount;\n // Emit the event before any external calls\n emit BridgeDepositClaimed(transactionId, proofRelayer, to, token, amount);\n // Complete the relayer claim as the last transaction action\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(to), amount);\n } else {\n IERC20(token).safeTransfer(to, amount);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeStatuses(bytes32 transactionId) public view returns (BridgeStatus status) {\n return bridgeTxDetails[transactionId].status;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeProofs(bytes32 transactionId) public view returns (uint96 timestamp, address relayer) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n\n timestamp = $.proofBlockTimestamp;\n relayer = $.proofRelayer;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeRelays(bytes32 transactionId) public view returns (bool) {\n // has this transactionId been relayed?\n return bridgeRelayDetails[transactionId].relayer != address(0);\n }\n\n /// @notice Takes the bridged asset from the user into FastBridgeV2 custody. It will be later\n /// claimed by the relayer who completed the relay on destination chain, or refunded back to the user,\n /// should no one complete the relay.\n function _takeBridgedUserAsset(address token, uint256 amount) internal returns (uint256 amountTaken) {\n if (token == NATIVE_GAS_TOKEN) {\n // For the native gas token, we just need to check that the supplied msg.value is correct.\n // Supplied `msg.value` is already in FastBridgeV2 custody.\n if (amount != msg.value) revert MsgValueIncorrect();\n amountTaken = msg.value;\n } else {\n // For ERC20s, token is explicitly transferred from the user to FastBridgeV2.\n // We don't allow non-zero `msg.value` to avoid extra funds from being stuck in FastBridgeV2.\n if (msg.value != 0) revert MsgValueIncorrect();\n // Throw an explicit error if the provided token address is not a contract\n if (token.code.length == 0) revert TokenNotContract();\n amountTaken = IERC20(token).balanceOf(address(this));\n IERC20(token).safeTransferFrom(msg.sender, address(this), amount);\n // Use the balance difference as the amount taken in case of fee on transfer tokens.\n amountTaken = IERC20(token).balanceOf(address(this)) - amountTaken;\n }\n }\n\n /// @notice Calls the Recipient's hook function with the specified zapData and performs\n /// all the necessary checks for the returned value.\n function _triggerZapWithChecks(address recipient, address token, uint256 amount, bytes calldata zapData) internal {\n // This will bubble any revert messages from the hook function\n bytes memory returnData = Address.functionCallWithValue({\n target: recipient,\n data: abi.encodeCall(IZapRecipient.zap, (token, amount, zapData)),\n // Note: see `relay()` for reasoning behind passing msg.value\n value: msg.value\n });\n // Explicit revert if no return data at all\n if (returnData.length == 0) revert RecipientNoReturnValue();\n // Check that exactly a single return value was returned\n if (returnData.length != 32) revert RecipientIncorrectReturnValue();\n // Return value should be abi-encoded hook function selector\n if (bytes32(returnData) != bytes32(IZapRecipient.zap.selector)) {\n revert RecipientIncorrectReturnValue();\n }\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint56(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint56).max but\n /// proof.timestamp \u003c type(uint56).max via unchecked statement\n /// @param proofBlockTimestamp The bridge proof block timestamp\n /// @return delta Time delta since proof submitted\n function _timeSince(uint56 proofBlockTimestamp) internal view returns (uint256 delta) {\n unchecked {\n delta = uint56(block.timestamp) - proofBlockTimestamp;\n }\n }\n\n /// @notice Performs all the necessary checks for a bridge to happen.\n /// @dev There's no good way to refactor this function to reduce cyclomatic complexity due to\n /// the number of checks that need to be performed, so we skip the code-complexity rule here.\n // solhint-disable-next-line code-complexity\n function _validateBridgeParams(\n BridgeParams memory params,\n BridgeParamsV2 memory paramsV2,\n int256 exclusivityEndTime\n )\n internal\n view\n {\n // Check V1 (legacy) params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.sender == address(0) || params.to == address(0)) revert ZeroAddress();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n // Check V2 params\n if (paramsV2.zapData.length \u003e MAX_ZAP_DATA_LENGTH) revert ZapDataLengthAboveMax();\n if (paramsV2.zapNative != 0 \u0026\u0026 params.destToken == NATIVE_GAS_TOKEN) {\n revert ZapNativeNotSupported();\n }\n // exclusivityEndTime must be in range [0 .. params.deadline]\n if (exclusivityEndTime \u003c 0 || exclusivityEndTime \u003e int256(params.deadline)) {\n revert ExclusivityParamsIncorrect();\n }\n }\n\n /// @notice Performs all the necessary checks for a relay to happen.\n function _validateRelayParams(bytes calldata request, bytes32 transactionId, address relayer) internal view {\n if (relayer == address(0)) revert ZeroAddress();\n // Check if the transaction has already been relayed\n if (bridgeRelays(transactionId)) revert TransactionRelayed();\n if (request.destChainId() != block.chainid) revert ChainIncorrect();\n // Check the deadline for relay to happen\n if (block.timestamp \u003e request.deadline()) revert DeadlineExceeded();\n // Check the exclusivity period, if it is still ongoing\n address exclRelayer = request.exclusivityRelayer();\n if (exclRelayer != address(0) \u0026\u0026 exclRelayer != relayer \u0026\u0026 block.timestamp \u003c= request.exclusivityEndTime()) {\n revert ExclusivityPeriodNotPassed();\n }\n }\n}\n","language":"Solidity","languageVersion":"0.8.24","compilerVersion":"0.8.24","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"","srcMapRuntime":"","abiDefinition":[{"inputs":[],"name":"AccessControlBadConfirmation","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"bytes32","name":"neededRole","type":"bytes32"}],"name":"AccessControlUnauthorizedAccount","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"previousAdminRole","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"newAdminRole","type":"bytes32"}],"name":"RoleAdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleRevoked","type":"event"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleAdmin","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"grantRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"hasRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"callerConfirmation","type":"address"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"revokeRole","outputs":[],"stateMutability":"nonpayable","type":"function"}],"userDoc":{"kind":"user","methods":{},"version":1},"developerDoc":{"details":"External interface of AccessControl declared to support ERC165 detection.","errors":{"AccessControlBadConfirmation()":[{"details":"The caller of a function is not the expected one. NOTE: Don't confuse with {AccessControlUnauthorizedAccount}."}],"AccessControlUnauthorizedAccount(address,bytes32)":[{"details":"The `account` is missing a role."}]},"events":{"RoleAdminChanged(bytes32,bytes32,bytes32)":{"details":"Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole` `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite {RoleAdminChanged} not being emitted signaling this."},"RoleGranted(bytes32,address,address)":{"details":"Emitted when `account` is granted `role`. `sender` is the account that originated the contract call, an admin role bearer except when using {AccessControl-_setupRole}."},"RoleRevoked(bytes32,address,address)":{"details":"Emitted when `account` is revoked `role`. `sender` is the account that originated the contract call: - if using `revokeRole`, it is the admin role bearer - if using `renounceRole`, it is the role bearer (i.e. `account`)"}},"kind":"dev","methods":{"getRoleAdmin(bytes32)":{"details":"Returns the admin role that controls `role`. See {grantRole} and {revokeRole}. To change a role's admin, use {AccessControl-_setRoleAdmin}."},"grantRole(bytes32,address)":{"details":"Grants `role` to `account`. If `account` had not been already granted `role`, emits a {RoleGranted} event. Requirements: - the caller must have ``role``'s admin role."},"hasRole(bytes32,address)":{"details":"Returns `true` if `account` has been granted `role`."},"renounceRole(bytes32,address)":{"details":"Revokes `role` from the calling account. Roles are often managed via {grantRole} and {revokeRole}: this function's purpose is to provide a mechanism for accounts to lose their privileges if they are compromised (such as when a trusted device is misplaced). If the calling account had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must be `callerConfirmation`."},"revokeRole(bytes32,address)":{"details":"Revokes `role` from `account`. If `account` had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must have ``role``'s admin role."}},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[],\"name\":\"AccessControlBadConfirmation\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"neededRole\",\"type\":\"bytes32\"}],\"name\":\"AccessControlUnauthorizedAccount\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"previousAdminRole\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"newAdminRole\",\"type\":\"bytes32\"}],\"name\":\"RoleAdminChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleGranted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleRevoked\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"}],\"name\":\"getRoleAdmin\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"grantRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"hasRole\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"callerConfirmation\",\"type\":\"address\"}],\"name\":\"renounceRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"revokeRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"details\":\"External interface of AccessControl declared to support ERC165 detection.\",\"errors\":{\"AccessControlBadConfirmation()\":[{\"details\":\"The caller of a function is not the expected one. NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\"}],\"AccessControlUnauthorizedAccount(address,bytes32)\":[{\"details\":\"The `account` is missing a role.\"}]},\"events\":{\"RoleAdminChanged(bytes32,bytes32,bytes32)\":{\"details\":\"Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole` `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite {RoleAdminChanged} not being emitted signaling this.\"},\"RoleGranted(bytes32,address,address)\":{\"details\":\"Emitted when `account` is granted `role`. `sender` is the account that originated the contract call, an admin role bearer except when using {AccessControl-_setupRole}.\"},\"RoleRevoked(bytes32,address,address)\":{\"details\":\"Emitted when `account` is revoked `role`. `sender` is the account that originated the contract call: - if using `revokeRole`, it is the admin role bearer - if using `renounceRole`, it is the role bearer (i.e. `account`)\"}},\"kind\":\"dev\",\"methods\":{\"getRoleAdmin(bytes32)\":{\"details\":\"Returns the admin role that controls `role`. See {grantRole} and {revokeRole}. To change a role's admin, use {AccessControl-_setRoleAdmin}.\"},\"grantRole(bytes32,address)\":{\"details\":\"Grants `role` to `account`. If `account` had not been already granted `role`, emits a {RoleGranted} event. Requirements: - the caller must have ``role``'s admin role.\"},\"hasRole(bytes32,address)\":{\"details\":\"Returns `true` if `account` has been granted `role`.\"},\"renounceRole(bytes32,address)\":{\"details\":\"Revokes `role` from the calling account. Roles are often managed via {grantRole} and {revokeRole}: this function's purpose is to provide a mechanism for accounts to lose their privileges if they are compromised (such as when a trusted device is misplaced). If the calling account had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must be `callerConfirmation`.\"},\"revokeRole(bytes32,address)\":{\"details\":\"Revokes `role` from `account`. If `account` had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must have ``role``'s admin role.\"}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeV2.sol\":\"IAccessControl\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeV2.sol\":{\"keccak256\":\"0x5069b55ca07f21bfe30b2a43c18a18318c8af9c181b2dcb07c290825efd70f34\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://273dc020a49d08e50126bbea0d7f783f79d08c702f2fdbc560618d24af308acc\",\"dweb:/ipfs/QmXJ2UVzFc8EPB74RT4CXQPC4xw66jt4T13poyfyd3UERh\"]}},\"version\":1}"},"hashes":{"getRoleAdmin(bytes32)":"248a9ca3","grantRole(bytes32,address)":"2f2ff15d","hasRole(bytes32,address)":"91d14854","renounceRole(bytes32,address)":"36568abe","revokeRole(bytes32,address)":"d547741f"}},"solidity/FastBridgeV2.sol:IAccessControlEnumerable":{"code":"0x","runtime-code":"0x","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.24 ^0.8.20 ^0.8.4;\n\n// contracts/interfaces/IAdmin.sol\n\ninterface IAdmin {\n // ============ Events ============\n\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n event ChainGasAmountUpdated(uint256 oldChainGasAmount, uint256 newChainGasAmount);\n\n // ============ Methods ============\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n\n function setChainGasAmount(uint256 newChainGasAmount) external;\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IFastBridgeV2Errors.sol\n\ninterface IFastBridgeV2Errors {\n error AmountIncorrect();\n error ChainIncorrect();\n error ExclusivityParamsIncorrect();\n error MsgValueIncorrect();\n error SenderIncorrect();\n error StatusIncorrect();\n error TokenNotContract();\n error ZapDataLengthAboveMax();\n error ZapNativeNotSupported();\n error ZeroAddress();\n\n error RecipientIncorrectReturnValue();\n error RecipientNoReturnValue();\n\n error DeadlineExceeded();\n error DeadlineNotExceeded();\n error DeadlineTooShort();\n error DisputePeriodNotPassed();\n error DisputePeriodPassed();\n error ExclusivityPeriodNotPassed();\n\n error TransactionRelayed();\n}\n\n// contracts/interfaces/IMulticallTarget.sol\n\n/// @notice Interface for a contract that can be called multiple times by the same caller. Inspired by MulticallV3:\n/// https://github.com/mds1/multicall/blob/master/src/Multicall3.sol\ninterface IMulticallTarget {\n struct Result {\n bool success;\n bytes returnData;\n }\n\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external;\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results);\n}\n\n// contracts/interfaces/IZapRecipient.sol\n\ninterface IZapRecipient {\n function zap(address token, uint256 amount, bytes memory zapData) external payable returns (bytes4);\n}\n\n// contracts/libs/Errors.sol\n\nerror DeadlineExceeded();\nerror DeadlineNotExceeded();\nerror DeadlineTooShort();\nerror InsufficientOutputAmount();\n\nerror MsgValueIncorrect();\nerror PoolNotFound();\nerror TokenAddressMismatch();\nerror TokenNotContract();\nerror TokenNotETH();\nerror TokensIdentical();\n\nerror ChainIncorrect();\nerror AmountIncorrect();\nerror ZeroAddress();\n\nerror DisputePeriodNotPassed();\nerror DisputePeriodPassed();\nerror SenderIncorrect();\nerror StatusIncorrect();\nerror TransactionIdIncorrect();\nerror TransactionRelayed();\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// contracts/interfaces/IFastBridgeV2.sol\n\ninterface IFastBridgeV2 is IFastBridge {\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n struct BridgeTxDetails {\n BridgeStatus status;\n uint32 destChainId;\n uint56 proofBlockTimestamp;\n address proofRelayer;\n }\n\n struct BridgeRelay {\n uint48 blockNumber;\n uint48 blockTimestamp;\n address relayer;\n }\n\n /// @notice New params introduced in the FastBridgeV2.\n /// We are passing fields from the older BridgeParams struct outside of this struct\n /// for backwards compatibility.\n /// Note: quoteRelayer and quoteExclusivitySeconds are either both zero (indicating no exclusivity)\n /// or both non-zero (indicating exclusivity for the given period).\n /// Note: zapNative \u003e 0 can NOT be used with destToken = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE (native token)\n /// @param quoteRelayer Relayer that provided the quote for the transaction\n /// @param quoteExclusivitySeconds Period of time the quote relayer is guaranteed exclusivity after user's deposit\n /// @param quoteId Unique quote identifier used for tracking the quote\n /// @param zapNative ETH value to send to the recipient (if any)\n /// @param zapData Parameters for the Zap to the destination recipient (if any)\n struct BridgeParamsV2 {\n address quoteRelayer;\n int256 quoteExclusivitySeconds;\n bytes quoteId;\n uint256 zapNative;\n bytes zapData;\n }\n\n /// @notice Updated bridge transaction struct to include parameters introduced in FastBridgeV2.\n /// Note: only `exclusivityRelayer` can fill such a transaction until `exclusivityEndTime`.\n struct BridgeTransactionV2 {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n // Note: sendChainGas flag from V1 is deprecated\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n address exclusivityRelayer;\n uint256 exclusivityEndTime;\n uint256 zapNative; // ETH value to send to the recipient (if any)\n bytes zapData; // data to pass for the Zap action (if any)\n }\n\n event BridgeQuoteDetails(bytes32 indexed transactionId, bytes quoteId);\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability\n /// to provide temporary exclusivity fill rights for the quote relayer.\n /// @param params The parameters required to bridge\n /// @param paramsV2 The parameters for exclusivity fill rights (optional, can be left empty)\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function relay(bytes memory request, address relayer) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param transactionId The transaction id associated with the encoded bridge transaction to prove\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital.\n /// @notice Can only send funds to the relayer address on the proof.\n /// @param request The encoded bridge transaction to claim on origin chain\n function claim(bytes memory request) external;\n /// @notice Checks if a transaction has been relayed\n /// @param transactionId The ID of the transaction to check\n /// @return True if the transaction has been relayed, false otherwise\n function bridgeRelays(bytes32 transactionId) external view returns (bool);\n\n /// @notice Returns the status of a bridge transaction\n /// @param transactionId The ID of the bridge transaction\n /// @return BridgeStatus Status of the bridge transaction\n function bridgeStatuses(bytes32 transactionId) external view returns (BridgeStatus);\n\n /// @notice Returns the timestamp and relayer of a bridge proof\n /// @param transactionId The ID of the bridge transaction\n /// @return timestamp The timestamp of the bridge proof\n /// @return relayer The relayer address of the bridge proof\n function bridgeProofs(bytes32 transactionId) external view returns (uint96 timestamp, address relayer);\n\n /// @notice Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\n /// @param request The bridge request to decode\n function getBridgeTransactionV2(bytes memory request) external view returns (BridgeTransactionV2 memory);\n}\n\n// contracts/utils/MulticallTarget.sol\n\n// solhint-disable avoid-low-level-calls\n/// @notice Template for a contract that supports batched calls (preserving the msg.sender).\n/// Only calls with zero msg.value could be batched.\nabstract contract MulticallTarget is IMulticallTarget {\n error MulticallTarget__UndeterminedRevert();\n\n /// @notice Perform a batched call to this contract, preserving the msg.sender.\n /// The return data from each call is discarded.\n /// @dev The method is non-payable, so only calls with `msg.value == 0` could be batched.\n /// It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag.\n /// Otherwise, the whole batch call will be reverted with the original revert reason.\n /// @param data List of abi-encoded calldata for the calls to perform.\n /// @param ignoreReverts Whether to ignore the revert errors from the calls.\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external {\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\n if (!success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(result);\n }\n }\n }\n\n /// @notice Perform a batched call to this contract, preserving the msg.sender.\n /// The return data from each call is preserved.\n /// @dev The method is non-payable, so only calls with `msg.value == 0` could be batched.\n /// It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag.\n /// Otherwise, the whole batch call will be reverted with the original revert reason.\n /// @param data List of abi-encoded calldata for the calls to perform.\n /// @param ignoreReverts Whether to ignore the revert errors from the calls.\n /// @return results List of results from the calls: `(success, returnData)`.\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results)\n {\n results = new Result[](data.length);\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (results[i].success, results[i].returnData) = address(this).delegatecall(data[i]);\n if (!results[i].success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(results[i].returnData);\n }\n }\n }\n\n /// @dev Bubbles the revert message from the underlying call.\n /// Note: preserves the same custom error or revert string, if one was used.\n /// Source: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v5.0.2/contracts/utils/Address.sol#L143-L158\n function _bubbleRevert(bytes memory returnData) internal pure {\n // Look for revert reason and bubble it up if present\n if (returnData.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n // solhint-disable-next-line no-inline-assembly\n assembly {\n let returndata_size := mload(returnData)\n revert(add(32, returnData), returndata_size)\n }\n } else {\n revert MulticallTarget__UndeterminedRevert();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// contracts/libs/BridgeTransactionV2.sol\n\n// solhint-disable no-inline-assembly\nlibrary BridgeTransactionV2Lib {\n uint16 internal constant VERSION = 2;\n\n // Offsets of the fields in the packed BridgeTransactionV2 struct\n // uint16 version [000 .. 002)\n // uint32 originChainId [002 .. 006)\n // uint32 destChainId [006 .. 010)\n // address originSender [010 .. 030)\n // address destRecipient [030 .. 050)\n // address originToken [050 .. 070)\n // address destToken [070 .. 090)\n // uint256 originAmount [090 .. 122)\n // uint256 destAmount [122 .. 154)\n // uint256 originFeeAmount [154 .. 186)\n // uint256 deadline [186 .. 218)\n // uint256 nonce [218 .. 250)\n // address exclusivityRelayer [250 .. 270)\n // uint256 exclusivityEndTime [270 .. 302)\n // uint256 zapNative [302 .. 334)\n // bytes zapData [334 .. ***)\n\n // forgefmt: disable-start\n uint256 private constant OFFSET_ORIGIN_CHAIN_ID = 2;\n uint256 private constant OFFSET_DEST_CHAIN_ID = 6;\n uint256 private constant OFFSET_ORIGIN_SENDER = 10;\n uint256 private constant OFFSET_DEST_RECIPIENT = 30;\n uint256 private constant OFFSET_ORIGIN_TOKEN = 50;\n uint256 private constant OFFSET_DEST_TOKEN = 70;\n uint256 private constant OFFSET_ORIGIN_AMOUNT = 90;\n uint256 private constant OFFSET_DEST_AMOUNT = 122;\n uint256 private constant OFFSET_ORIGIN_FEE_AMOUNT = 154;\n uint256 private constant OFFSET_DEADLINE = 186;\n uint256 private constant OFFSET_NONCE = 218;\n uint256 private constant OFFSET_EXCLUSIVITY_RELAYER = 250;\n uint256 private constant OFFSET_EXCLUSIVITY_END_TIME = 270;\n uint256 private constant OFFSET_ZAP_NATIVE = 302;\n uint256 private constant OFFSET_ZAP_DATA = 334;\n // forgefmt: disable-end\n\n error BridgeTransactionV2__InvalidEncodedTx();\n error BridgeTransactionV2__UnsupportedVersion(uint16 version);\n\n /// @notice Validates the encoded transaction to be a tightly packed encoded payload for BridgeTransactionV2.\n /// @dev Checks the minimum length and the version, use this function before decoding any of the fields.\n function validateV2(bytes calldata encodedTx) internal pure {\n // Check the minimum length: must at least include all static fields.\n if (encodedTx.length \u003c OFFSET_ZAP_DATA) revert BridgeTransactionV2__InvalidEncodedTx();\n // Once we validated the length, we can be sure that the version field is present.\n uint16 version_ = version(encodedTx);\n if (version_ != VERSION) revert BridgeTransactionV2__UnsupportedVersion(version_);\n }\n\n /// @notice Encodes the BridgeTransactionV2 struct by tightly packing the fields.\n /// @dev `abi.decode` will not work as a result of the tightly packed fields. Use `decodeV2` to decode instead.\n function encodeV2(IFastBridgeV2.BridgeTransactionV2 memory bridgeTx) internal pure returns (bytes memory) {\n // We split the encoding into two parts to avoid stack-too-deep error\n bytes memory firstPart = abi.encodePacked(\n VERSION,\n bridgeTx.originChainId,\n bridgeTx.destChainId,\n bridgeTx.originSender,\n bridgeTx.destRecipient,\n bridgeTx.originToken,\n bridgeTx.destToken,\n bridgeTx.originAmount\n );\n return abi.encodePacked(\n firstPart,\n bridgeTx.destAmount,\n bridgeTx.originFeeAmount,\n // Note: we skip the deprecated `sendChainGas` flag, which was present in BridgeTransaction V1\n bridgeTx.deadline,\n bridgeTx.nonce,\n // New V2 fields: exclusivity\n bridgeTx.exclusivityRelayer,\n bridgeTx.exclusivityEndTime,\n // New V2 fields: Zap\n bridgeTx.zapNative,\n bridgeTx.zapData\n );\n }\n\n /// @notice Decodes the BridgeTransactionV2 struct from the encoded transaction.\n /// @dev Encoded BridgeTransactionV2 struct must be tightly packed.\n /// Use `validateV2` before decoding to ensure the encoded transaction is valid.\n function decodeV2(bytes calldata encodedTx)\n internal\n pure\n returns (IFastBridgeV2.BridgeTransactionV2 memory bridgeTx)\n {\n bridgeTx.originChainId = originChainId(encodedTx);\n bridgeTx.destChainId = destChainId(encodedTx);\n bridgeTx.originSender = originSender(encodedTx);\n bridgeTx.destRecipient = destRecipient(encodedTx);\n bridgeTx.originToken = originToken(encodedTx);\n bridgeTx.destToken = destToken(encodedTx);\n bridgeTx.originAmount = originAmount(encodedTx);\n bridgeTx.destAmount = destAmount(encodedTx);\n bridgeTx.originFeeAmount = originFeeAmount(encodedTx);\n bridgeTx.deadline = deadline(encodedTx);\n bridgeTx.nonce = nonce(encodedTx);\n bridgeTx.exclusivityRelayer = exclusivityRelayer(encodedTx);\n bridgeTx.exclusivityEndTime = exclusivityEndTime(encodedTx);\n bridgeTx.zapNative = zapNative(encodedTx);\n bridgeTx.zapData = zapData(encodedTx);\n }\n\n /// @notice Extracts the version from the encoded transaction.\n function version(bytes calldata encodedTx) internal pure returns (uint16 version_) {\n // Load 32 bytes from the start and shift it 240 bits to the right to get the highest 16 bits.\n assembly {\n version_ := shr(240, calldataload(encodedTx.offset))\n }\n }\n\n /// @notice Extracts the origin chain ID from the encoded transaction.\n function originChainId(bytes calldata encodedTx) internal pure returns (uint32 originChainId_) {\n // Load 32 bytes from the offset and shift it 224 bits to the right to get the highest 32 bits.\n assembly {\n originChainId_ := shr(224, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_CHAIN_ID)))\n }\n }\n\n /// @notice Extracts the destination chain ID from the encoded transaction.\n function destChainId(bytes calldata encodedTx) internal pure returns (uint32 destChainId_) {\n // Load 32 bytes from the offset and shift it 224 bits to the right to get the highest 32 bits.\n assembly {\n destChainId_ := shr(224, calldataload(add(encodedTx.offset, OFFSET_DEST_CHAIN_ID)))\n }\n }\n\n /// @notice Extracts the origin sender from the encoded transaction.\n function originSender(bytes calldata encodedTx) internal pure returns (address originSender_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n originSender_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_SENDER)))\n }\n }\n\n /// @notice Extracts the destination recipient from the encoded transaction.\n function destRecipient(bytes calldata encodedTx) internal pure returns (address destRecipient_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n destRecipient_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_DEST_RECIPIENT)))\n }\n }\n\n /// @notice Extracts the origin token from the encoded transaction.\n function originToken(bytes calldata encodedTx) internal pure returns (address originToken_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n originToken_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_TOKEN)))\n }\n }\n\n /// @notice Extracts the destination token from the encoded transaction.\n function destToken(bytes calldata encodedTx) internal pure returns (address destToken_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n destToken_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_DEST_TOKEN)))\n }\n }\n\n /// @notice Extracts the origin amount from the encoded transaction.\n function originAmount(bytes calldata encodedTx) internal pure returns (uint256 originAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n originAmount_ := calldataload(add(encodedTx.offset, OFFSET_ORIGIN_AMOUNT))\n }\n }\n\n /// @notice Extracts the destination amount from the encoded transaction.\n function destAmount(bytes calldata encodedTx) internal pure returns (uint256 destAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n destAmount_ := calldataload(add(encodedTx.offset, OFFSET_DEST_AMOUNT))\n }\n }\n\n /// @notice Extracts the origin fee amount from the encoded transaction.\n function originFeeAmount(bytes calldata encodedTx) internal pure returns (uint256 originFeeAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n originFeeAmount_ := calldataload(add(encodedTx.offset, OFFSET_ORIGIN_FEE_AMOUNT))\n }\n }\n\n /// @notice Extracts the deadline from the encoded transaction.\n function deadline(bytes calldata encodedTx) internal pure returns (uint256 deadline_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n deadline_ := calldataload(add(encodedTx.offset, OFFSET_DEADLINE))\n }\n }\n\n /// @notice Extracts the nonce from the encoded transaction.\n function nonce(bytes calldata encodedTx) internal pure returns (uint256 nonce_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n nonce_ := calldataload(add(encodedTx.offset, OFFSET_NONCE))\n }\n }\n\n /// @notice Extracts the exclusivity relayer from the encoded transaction.\n function exclusivityRelayer(bytes calldata encodedTx) internal pure returns (address exclusivityRelayer_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n exclusivityRelayer_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_EXCLUSIVITY_RELAYER)))\n }\n }\n\n /// @notice Extracts the exclusivity end time from the encoded transaction.\n function exclusivityEndTime(bytes calldata encodedTx) internal pure returns (uint256 exclusivityEndTime_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n exclusivityEndTime_ := calldataload(add(encodedTx.offset, OFFSET_EXCLUSIVITY_END_TIME))\n }\n }\n\n /// @notice Extracts the Zap's native value from the encoded transaction.\n function zapNative(bytes calldata encodedTx) internal pure returns (uint256 zapNative_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n zapNative_ := calldataload(add(encodedTx.offset, OFFSET_ZAP_NATIVE))\n }\n }\n\n /// @notice Extracts the Zap's data from the encoded transaction.\n function zapData(bytes calldata encodedTx) internal pure returns (bytes calldata zapData_) {\n zapData_ = encodedTx[OFFSET_ZAP_DATA:];\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// contracts/libs/UniversalToken.sol\n\nlibrary UniversalTokenLib {\n using SafeERC20 for IERC20;\n\n address internal constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Transfers tokens to the given account. Reverts if transfer is not successful.\n /// @dev This might trigger fallback, if ETH is transferred to the contract.\n /// Make sure this can not lead to reentrancy attacks.\n function universalTransfer(address token, address to, uint256 value) internal {\n // Don't do anything, if need to send tokens to this address\n if (to == address(this)) return;\n // Don't do anything, if trying to send zero value\n if (value == 0) return;\n if (token == ETH_ADDRESS) {\n /// @dev Note: this can potentially lead to executing code in `to`.\n // solhint-disable-next-line avoid-low-level-calls\n (bool success,) = to.call{value: value}(\"\");\n require(success, \"ETH transfer failed\");\n } else {\n IERC20(token).safeTransfer(to, value);\n }\n }\n\n /// @notice Issues an infinite allowance to the spender, if the current allowance is insufficient\n /// to spend the given amount.\n function universalApproveInfinity(address token, address spender, uint256 amountToSpend) internal {\n // ETH Chad doesn't require your approval\n if (token == ETH_ADDRESS) return;\n // No-op if allowance is already sufficient\n uint256 allowance = IERC20(token).allowance(address(this), spender);\n if (allowance \u003e= amountToSpend) return;\n // Otherwise, reset approval to 0 and set to max allowance\n if (allowance \u003e 0) IERC20(token).safeDecreaseAllowance(spender, allowance);\n IERC20(token).safeIncreaseAllowance(spender, type(uint256).max);\n }\n\n /// @notice Returns the balance of the given token (or native ETH) for the given account.\n function universalBalanceOf(address token, address account) internal view returns (uint256) {\n if (token == ETH_ADDRESS) {\n return account.balance;\n } else {\n return IERC20(token).balanceOf(account);\n }\n }\n\n /// @dev Checks that token is a contract and not ETH_ADDRESS.\n function assertIsContract(address token) internal view {\n // Check that ETH_ADDRESS was not used (in case this is a predeploy on any of the chains)\n if (token == UniversalTokenLib.ETH_ADDRESS) revert TokenNotContract();\n // Check that token is not an EOA\n if (token.code.length == 0) revert TokenNotContract();\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/Admin.sol\n\ncontract Admin is IAdmin, AccessControlEnumerable {\n using UniversalTokenLib for address;\n\n bytes32 public constant RELAYER_ROLE = keccak256(\"RELAYER_ROLE\");\n bytes32 public constant REFUNDER_ROLE = keccak256(\"REFUNDER_ROLE\");\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n uint256 public constant FEE_BPS = 1e6;\n uint256 public constant FEE_RATE_MAX = 0.01e6; // max 1% on origin amount\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Chain gas amount to forward as rebate if requested\n uint256 public chainGasAmount;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n }\n\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n require(newFeeRate \u003c= FEE_RATE_MAX, \"newFeeRate \u003e max\");\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n token.universalTransfer(recipient, feeAmount);\n emit FeesSwept(token, recipient, feeAmount);\n }\n\n function setChainGasAmount(uint256 newChainGasAmount) external onlyRole(GOVERNOR_ROLE) {\n uint256 oldChainGasAmount = chainGasAmount;\n chainGasAmount = newChainGasAmount;\n emit ChainGasAmountUpdated(oldChainGasAmount, newChainGasAmount);\n }\n}\n\n// contracts/FastBridgeV2.sol\n\n/// @notice FastBridgeV2 is a contract for bridging tokens across chains.\ncontract FastBridgeV2 is Admin, MulticallTarget, IFastBridgeV2, IFastBridgeV2Errors {\n using BridgeTransactionV2Lib for bytes;\n using SafeERC20 for IERC20;\n\n /// @notice Address reserved for native gas token (ETH on Ethereum and most L2s, AVAX on Avalanche, etc)\n address public constant NATIVE_GAS_TOKEN = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Delay for a transaction after which it could be permisionlessly refunded\n uint256 public constant REFUND_DELAY = 7 days;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n /// @notice Maximum length of accepted zapData\n uint256 public constant MAX_ZAP_DATA_LENGTH = 2 ** 16 - 1;\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeTxDetails) public bridgeTxDetails;\n /// @notice Relay details on destination chain\n mapping(bytes32 =\u003e BridgeRelay) public bridgeRelayDetails;\n /// @notice Unique bridge nonces tracked per originSender\n mapping(address =\u003e uint256) public senderNonces;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Replaced by senderNonces\n uint256 public immutable nonce = 0;\n /// @notice the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n bridge({\n params: params,\n paramsV2: BridgeParamsV2({\n quoteRelayer: address(0),\n quoteExclusivitySeconds: 0,\n quoteId: bytes(\"\"),\n zapNative: 0,\n zapData: bytes(\"\")\n })\n });\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes calldata request) external payable {\n // relay override will validate the request\n relay({request: request, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes calldata request, bytes32 destTxHash) external {\n request.validateV2();\n prove({transactionId: keccak256(request), destTxHash: destTxHash, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridgeV2\n function claim(bytes calldata request) external {\n // claim override will validate the request\n claim({request: request, to: address(0)});\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Aggregate the read operations from the same storage slot\n address disputedRelayer = $.proofRelayer;\n BridgeStatus status = $.status;\n uint56 proofBlockTimestamp = $.proofBlockTimestamp;\n // Can only dispute a RELAYER_PROVED transaction within the dispute period\n if (status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(proofBlockTimestamp) \u003e DISPUTE_PERIOD) {\n revert DisputePeriodPassed();\n }\n // Update status to REQUESTED and delete the disputed proof details\n // Note: these are storage writes\n $.status = BridgeStatus.REQUESTED;\n $.proofRelayer = address(0);\n $.proofBlockTimestamp = 0;\n\n emit BridgeProofDisputed(transactionId, disputedRelayer);\n }\n\n /// @inheritdoc IFastBridge\n function refund(bytes calldata request) external {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Can only refund a REQUESTED transaction after its deadline expires\n if ($.status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n uint256 deadline = request.deadline();\n // Permissionless refund is only allowed after REFUND_DELAY on top of the deadline\n if (!hasRole(REFUNDER_ROLE, msg.sender)) deadline += REFUND_DELAY;\n if (block.timestamp \u003c= deadline) revert DeadlineNotExceeded();\n // Update status to REFUNDED and return the full amount (collateral + protocol fees) to the original sender.\n // The protocol fees are only updated when the transaction is claimed, so we don't need to update them here.\n // Note: this is a storage write\n $.status = BridgeStatus.REFUNDED;\n\n address to = request.originSender();\n address token = request.originToken();\n uint256 amount = request.originAmount() + request.originFeeAmount();\n // Emit the event before any external calls\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n // Complete the user refund as the last transaction action\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(to), amount);\n } else {\n IERC20(token).safeTransfer(to, amount);\n }\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // The correct relayer can only claim a RELAYER_PROVED transaction after the dispute period\n if ($.status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if ($.proofRelayer != relayer) revert SenderIncorrect();\n return _timeSince($.proofBlockTimestamp) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n /// @dev This method is added to achieve backwards compatibility with decoding requests into V1 structs:\n /// - `zapNative` is partially reported as a zero/non-zero flag\n /// - `zapData` is ignored\n /// In order to process all kinds of requests use getBridgeTransactionV2 instead.\n function getBridgeTransaction(bytes calldata request) external view returns (BridgeTransaction memory) {\n // Try decoding into V2 struct first. This will revert if V1 struct is passed\n try this.getBridgeTransactionV2(request) returns (BridgeTransactionV2 memory txV2) {\n // Note: we entirely ignore the zapData field, as it was not present in V1\n return BridgeTransaction({\n originChainId: txV2.originChainId,\n destChainId: txV2.destChainId,\n originSender: txV2.originSender,\n destRecipient: txV2.destRecipient,\n originToken: txV2.originToken,\n destToken: txV2.destToken,\n originAmount: txV2.originAmount,\n destAmount: txV2.destAmount,\n originFeeAmount: txV2.originFeeAmount,\n sendChainGas: txV2.zapNative != 0,\n deadline: txV2.deadline,\n nonce: txV2.nonce\n });\n } catch {\n // Fallback to V1 struct\n return abi.decode(request, (BridgeTransaction));\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function getBridgeTransactionV2(bytes calldata request) external pure returns (BridgeTransactionV2 memory) {\n request.validateV2();\n return BridgeTransactionV2Lib.decodeV2(request);\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) public payable {\n int256 exclusivityEndTime = 0;\n // if relayer exclusivity is not intended for this bridge, set exclusivityEndTime to static zero\n // otherwise, set exclusivity to expire at the current block ts offset by quoteExclusivitySeconds\n if (paramsV2.quoteRelayer != address(0)) {\n exclusivityEndTime = int256(block.timestamp) + paramsV2.quoteExclusivitySeconds;\n }\n _validateBridgeParams(params, paramsV2, exclusivityEndTime);\n\n // transfer tokens to bridge contract\n /// @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _takeBridgedUserAsset(params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) {\n originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n }\n\n // set status to requested\n bytes memory request = BridgeTransactionV2Lib.encodeV2(\n BridgeTransactionV2({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n deadline: params.deadline,\n nonce: senderNonces[params.sender]++, // increment nonce on every bridge\n exclusivityRelayer: paramsV2.quoteRelayer,\n // We checked exclusivityEndTime to be in range [0 .. params.deadline] above, so can safely cast\n exclusivityEndTime: uint256(exclusivityEndTime),\n zapNative: paramsV2.zapNative,\n zapData: paramsV2.zapData\n })\n );\n bytes32 transactionId = keccak256(request);\n // Note: the tx status will be updated throughout the tx lifecycle, while destChainId is set once here\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n bridgeTxDetails[transactionId].destChainId = params.dstChainId;\n\n emit BridgeRequested({\n transactionId: transactionId,\n sender: params.sender,\n request: request,\n destChainId: params.dstChainId,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n sendChainGas: paramsV2.zapNative != 0\n });\n emit BridgeQuoteDetails(transactionId, paramsV2.quoteId);\n }\n\n /// @inheritdoc IFastBridgeV2\n function relay(bytes calldata request, address relayer) public payable {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n _validateRelayParams(request, transactionId, relayer);\n // mark bridge transaction as relayed\n bridgeRelayDetails[transactionId] =\n BridgeRelay({blockNumber: uint48(block.number), blockTimestamp: uint48(block.timestamp), relayer: relayer});\n\n // transfer tokens to recipient on destination chain and trigger Zap if requested\n address to = request.destRecipient();\n address token = request.destToken();\n uint256 amount = request.destAmount();\n uint256 zapNative = request.zapNative();\n\n // Emit the event before any external calls\n emit BridgeRelayed({\n transactionId: transactionId,\n relayer: relayer,\n to: to,\n originChainId: request.originChainId(),\n originToken: request.originToken(),\n destToken: token,\n originAmount: request.originAmount(),\n destAmount: amount,\n chainGasAmount: zapNative\n });\n\n // All state changes have been done at this point, can proceed to the external calls.\n // This follows the checks-effects-interactions pattern to mitigate potential reentrancy attacks.\n if (token == NATIVE_GAS_TOKEN) {\n // For the native gas token, additional zapNative is not allowed\n if (zapNative != 0) revert ZapNativeNotSupported();\n // Check that the correct msg.value was sent\n if (msg.value != amount) revert MsgValueIncorrect();\n // Don't do a native transfer yet: we will handle it alongside the Zap below\n } else {\n // For ERC20s, we check that the correct msg.value was sent\n if (msg.value != zapNative) revert MsgValueIncorrect();\n // We need to transfer the tokens from the Relayer to the recipient first before performing an\n // optional post-transfer Zap.\n IERC20(token).safeTransferFrom(msg.sender, to, amount);\n }\n // At this point we have done:\n // - Transferred the requested amount of ERC20 tokens to the recipient.\n // At this point we have confirmed:\n // - For ERC20s: msg.value matches the requested zapNative amount.\n // - For the native gas token: msg.value matches the requested destAmount.\n // Remaining optional things to do:\n // - Forward the full msg.value to the recipient (if non-zero).\n // - Trigger a Zap (if zapData is present).\n bytes calldata zapData = request.zapData();\n if (zapData.length != 0) {\n // Zap Data is present: Zap has been requested by the recipient. Trigger it forwarding the full msg.value.\n\n // Note: if token has a fee on transfers, the recipient will have received less than `amount`.\n // This is a very niche edge case and should be handled by the recipient contract.\n _triggerZapWithChecks({recipient: to, token: token, amount: amount, zapData: zapData});\n } else if (msg.value != 0) {\n // Zap Data is missing, but msg.value was sent. This could happen in two different cases:\n // - Relay with the native gas token is happening.\n // - Relay with ERC20 is happening, with a `zapNative \u003e 0` request.\n // In both cases, we need to transfer the full msg.value to the recipient.\n Address.sendValue(payable(to), msg.value);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) public onlyRole(RELAYER_ROLE) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n\n // Can only prove a REQUESTED transaction\n if ($.status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n // Update status to RELAYER_PROVED and store the proof details\n // Note: these are storage writes\n $.status = BridgeStatus.RELAYER_PROVED;\n $.proofBlockTimestamp = uint56(block.timestamp);\n $.proofRelayer = relayer;\n\n emit BridgeProofProvided(transactionId, relayer, destTxHash);\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes calldata request, address to) public {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Aggregate the read operations from the same storage slot\n address proofRelayer = $.proofRelayer;\n BridgeStatus status = $.status;\n uint56 proofBlockTimestamp = $.proofBlockTimestamp;\n\n // Can only claim a RELAYER_PROVED transaction after the dispute period\n if (status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(proofBlockTimestamp) \u003c= DISPUTE_PERIOD) {\n revert DisputePeriodNotPassed();\n }\n\n if (to == address(0)) {\n // Anyone could claim the funds to the proven relayer on their behalf\n to = proofRelayer;\n } else if (proofRelayer != msg.sender) {\n // Only the proven relayer could specify an address to claim the funds to\n revert SenderIncorrect();\n }\n\n // Update status to RELAYER_CLAIMED and transfer the origin collateral to the specified claim address\n // Note: this is a storage write\n $.status = BridgeStatus.RELAYER_CLAIMED;\n\n address token = request.originToken();\n uint256 amount = request.originAmount();\n // Update protocol fees if origin fee amount exists\n uint256 originFeeAmount = request.originFeeAmount();\n if (originFeeAmount \u003e 0) protocolFees[token] += originFeeAmount;\n // Emit the event before any external calls\n emit BridgeDepositClaimed(transactionId, proofRelayer, to, token, amount);\n // Complete the relayer claim as the last transaction action\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(to), amount);\n } else {\n IERC20(token).safeTransfer(to, amount);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeStatuses(bytes32 transactionId) public view returns (BridgeStatus status) {\n return bridgeTxDetails[transactionId].status;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeProofs(bytes32 transactionId) public view returns (uint96 timestamp, address relayer) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n\n timestamp = $.proofBlockTimestamp;\n relayer = $.proofRelayer;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeRelays(bytes32 transactionId) public view returns (bool) {\n // has this transactionId been relayed?\n return bridgeRelayDetails[transactionId].relayer != address(0);\n }\n\n /// @notice Takes the bridged asset from the user into FastBridgeV2 custody. It will be later\n /// claimed by the relayer who completed the relay on destination chain, or refunded back to the user,\n /// should no one complete the relay.\n function _takeBridgedUserAsset(address token, uint256 amount) internal returns (uint256 amountTaken) {\n if (token == NATIVE_GAS_TOKEN) {\n // For the native gas token, we just need to check that the supplied msg.value is correct.\n // Supplied `msg.value` is already in FastBridgeV2 custody.\n if (amount != msg.value) revert MsgValueIncorrect();\n amountTaken = msg.value;\n } else {\n // For ERC20s, token is explicitly transferred from the user to FastBridgeV2.\n // We don't allow non-zero `msg.value` to avoid extra funds from being stuck in FastBridgeV2.\n if (msg.value != 0) revert MsgValueIncorrect();\n // Throw an explicit error if the provided token address is not a contract\n if (token.code.length == 0) revert TokenNotContract();\n amountTaken = IERC20(token).balanceOf(address(this));\n IERC20(token).safeTransferFrom(msg.sender, address(this), amount);\n // Use the balance difference as the amount taken in case of fee on transfer tokens.\n amountTaken = IERC20(token).balanceOf(address(this)) - amountTaken;\n }\n }\n\n /// @notice Calls the Recipient's hook function with the specified zapData and performs\n /// all the necessary checks for the returned value.\n function _triggerZapWithChecks(address recipient, address token, uint256 amount, bytes calldata zapData) internal {\n // This will bubble any revert messages from the hook function\n bytes memory returnData = Address.functionCallWithValue({\n target: recipient,\n data: abi.encodeCall(IZapRecipient.zap, (token, amount, zapData)),\n // Note: see `relay()` for reasoning behind passing msg.value\n value: msg.value\n });\n // Explicit revert if no return data at all\n if (returnData.length == 0) revert RecipientNoReturnValue();\n // Check that exactly a single return value was returned\n if (returnData.length != 32) revert RecipientIncorrectReturnValue();\n // Return value should be abi-encoded hook function selector\n if (bytes32(returnData) != bytes32(IZapRecipient.zap.selector)) {\n revert RecipientIncorrectReturnValue();\n }\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint56(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint56).max but\n /// proof.timestamp \u003c type(uint56).max via unchecked statement\n /// @param proofBlockTimestamp The bridge proof block timestamp\n /// @return delta Time delta since proof submitted\n function _timeSince(uint56 proofBlockTimestamp) internal view returns (uint256 delta) {\n unchecked {\n delta = uint56(block.timestamp) - proofBlockTimestamp;\n }\n }\n\n /// @notice Performs all the necessary checks for a bridge to happen.\n /// @dev There's no good way to refactor this function to reduce cyclomatic complexity due to\n /// the number of checks that need to be performed, so we skip the code-complexity rule here.\n // solhint-disable-next-line code-complexity\n function _validateBridgeParams(\n BridgeParams memory params,\n BridgeParamsV2 memory paramsV2,\n int256 exclusivityEndTime\n )\n internal\n view\n {\n // Check V1 (legacy) params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.sender == address(0) || params.to == address(0)) revert ZeroAddress();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n // Check V2 params\n if (paramsV2.zapData.length \u003e MAX_ZAP_DATA_LENGTH) revert ZapDataLengthAboveMax();\n if (paramsV2.zapNative != 0 \u0026\u0026 params.destToken == NATIVE_GAS_TOKEN) {\n revert ZapNativeNotSupported();\n }\n // exclusivityEndTime must be in range [0 .. params.deadline]\n if (exclusivityEndTime \u003c 0 || exclusivityEndTime \u003e int256(params.deadline)) {\n revert ExclusivityParamsIncorrect();\n }\n }\n\n /// @notice Performs all the necessary checks for a relay to happen.\n function _validateRelayParams(bytes calldata request, bytes32 transactionId, address relayer) internal view {\n if (relayer == address(0)) revert ZeroAddress();\n // Check if the transaction has already been relayed\n if (bridgeRelays(transactionId)) revert TransactionRelayed();\n if (request.destChainId() != block.chainid) revert ChainIncorrect();\n // Check the deadline for relay to happen\n if (block.timestamp \u003e request.deadline()) revert DeadlineExceeded();\n // Check the exclusivity period, if it is still ongoing\n address exclRelayer = request.exclusivityRelayer();\n if (exclRelayer != address(0) \u0026\u0026 exclRelayer != relayer \u0026\u0026 block.timestamp \u003c= request.exclusivityEndTime()) {\n revert ExclusivityPeriodNotPassed();\n }\n }\n}\n","language":"Solidity","languageVersion":"0.8.24","compilerVersion":"0.8.24","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"","srcMapRuntime":"","abiDefinition":[{"inputs":[],"name":"AccessControlBadConfirmation","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"bytes32","name":"neededRole","type":"bytes32"}],"name":"AccessControlUnauthorizedAccount","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"previousAdminRole","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"newAdminRole","type":"bytes32"}],"name":"RoleAdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleRevoked","type":"event"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleAdmin","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"uint256","name":"index","type":"uint256"}],"name":"getRoleMember","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleMemberCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"grantRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"hasRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"callerConfirmation","type":"address"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"revokeRole","outputs":[],"stateMutability":"nonpayable","type":"function"}],"userDoc":{"kind":"user","methods":{},"version":1},"developerDoc":{"details":"External interface of AccessControlEnumerable declared to support ERC165 detection.","errors":{"AccessControlBadConfirmation()":[{"details":"The caller of a function is not the expected one. NOTE: Don't confuse with {AccessControlUnauthorizedAccount}."}],"AccessControlUnauthorizedAccount(address,bytes32)":[{"details":"The `account` is missing a role."}]},"events":{"RoleAdminChanged(bytes32,bytes32,bytes32)":{"details":"Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole` `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite {RoleAdminChanged} not being emitted signaling this."},"RoleGranted(bytes32,address,address)":{"details":"Emitted when `account` is granted `role`. `sender` is the account that originated the contract call, an admin role bearer except when using {AccessControl-_setupRole}."},"RoleRevoked(bytes32,address,address)":{"details":"Emitted when `account` is revoked `role`. `sender` is the account that originated the contract call: - if using `revokeRole`, it is the admin role bearer - if using `renounceRole`, it is the role bearer (i.e. `account`)"}},"kind":"dev","methods":{"getRoleAdmin(bytes32)":{"details":"Returns the admin role that controls `role`. See {grantRole} and {revokeRole}. To change a role's admin, use {AccessControl-_setRoleAdmin}."},"getRoleMember(bytes32,uint256)":{"details":"Returns one of the accounts that have `role`. `index` must be a value between 0 and {getRoleMemberCount}, non-inclusive. Role bearers are not sorted in any particular way, and their ordering may change at any point. WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure you perform all queries on the same block. See the following https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post] for more information."},"getRoleMemberCount(bytes32)":{"details":"Returns the number of accounts that have `role`. Can be used together with {getRoleMember} to enumerate all bearers of a role."},"grantRole(bytes32,address)":{"details":"Grants `role` to `account`. If `account` had not been already granted `role`, emits a {RoleGranted} event. Requirements: - the caller must have ``role``'s admin role."},"hasRole(bytes32,address)":{"details":"Returns `true` if `account` has been granted `role`."},"renounceRole(bytes32,address)":{"details":"Revokes `role` from the calling account. Roles are often managed via {grantRole} and {revokeRole}: this function's purpose is to provide a mechanism for accounts to lose their privileges if they are compromised (such as when a trusted device is misplaced). If the calling account had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must be `callerConfirmation`."},"revokeRole(bytes32,address)":{"details":"Revokes `role` from `account`. If `account` had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must have ``role``'s admin role."}},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[],\"name\":\"AccessControlBadConfirmation\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"neededRole\",\"type\":\"bytes32\"}],\"name\":\"AccessControlUnauthorizedAccount\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"previousAdminRole\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"newAdminRole\",\"type\":\"bytes32\"}],\"name\":\"RoleAdminChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleGranted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleRevoked\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"}],\"name\":\"getRoleAdmin\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"index\",\"type\":\"uint256\"}],\"name\":\"getRoleMember\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"}],\"name\":\"getRoleMemberCount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"grantRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"hasRole\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"callerConfirmation\",\"type\":\"address\"}],\"name\":\"renounceRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"revokeRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"details\":\"External interface of AccessControlEnumerable declared to support ERC165 detection.\",\"errors\":{\"AccessControlBadConfirmation()\":[{\"details\":\"The caller of a function is not the expected one. NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\"}],\"AccessControlUnauthorizedAccount(address,bytes32)\":[{\"details\":\"The `account` is missing a role.\"}]},\"events\":{\"RoleAdminChanged(bytes32,bytes32,bytes32)\":{\"details\":\"Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole` `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite {RoleAdminChanged} not being emitted signaling this.\"},\"RoleGranted(bytes32,address,address)\":{\"details\":\"Emitted when `account` is granted `role`. `sender` is the account that originated the contract call, an admin role bearer except when using {AccessControl-_setupRole}.\"},\"RoleRevoked(bytes32,address,address)\":{\"details\":\"Emitted when `account` is revoked `role`. `sender` is the account that originated the contract call: - if using `revokeRole`, it is the admin role bearer - if using `renounceRole`, it is the role bearer (i.e. `account`)\"}},\"kind\":\"dev\",\"methods\":{\"getRoleAdmin(bytes32)\":{\"details\":\"Returns the admin role that controls `role`. See {grantRole} and {revokeRole}. To change a role's admin, use {AccessControl-_setRoleAdmin}.\"},\"getRoleMember(bytes32,uint256)\":{\"details\":\"Returns one of the accounts that have `role`. `index` must be a value between 0 and {getRoleMemberCount}, non-inclusive. Role bearers are not sorted in any particular way, and their ordering may change at any point. WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure you perform all queries on the same block. See the following https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post] for more information.\"},\"getRoleMemberCount(bytes32)\":{\"details\":\"Returns the number of accounts that have `role`. Can be used together with {getRoleMember} to enumerate all bearers of a role.\"},\"grantRole(bytes32,address)\":{\"details\":\"Grants `role` to `account`. If `account` had not been already granted `role`, emits a {RoleGranted} event. Requirements: - the caller must have ``role``'s admin role.\"},\"hasRole(bytes32,address)\":{\"details\":\"Returns `true` if `account` has been granted `role`.\"},\"renounceRole(bytes32,address)\":{\"details\":\"Revokes `role` from the calling account. Roles are often managed via {grantRole} and {revokeRole}: this function's purpose is to provide a mechanism for accounts to lose their privileges if they are compromised (such as when a trusted device is misplaced). If the calling account had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must be `callerConfirmation`.\"},\"revokeRole(bytes32,address)\":{\"details\":\"Revokes `role` from `account`. If `account` had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must have ``role``'s admin role.\"}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeV2.sol\":\"IAccessControlEnumerable\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeV2.sol\":{\"keccak256\":\"0x5069b55ca07f21bfe30b2a43c18a18318c8af9c181b2dcb07c290825efd70f34\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://273dc020a49d08e50126bbea0d7f783f79d08c702f2fdbc560618d24af308acc\",\"dweb:/ipfs/QmXJ2UVzFc8EPB74RT4CXQPC4xw66jt4T13poyfyd3UERh\"]}},\"version\":1}"},"hashes":{"getRoleAdmin(bytes32)":"248a9ca3","getRoleMember(bytes32,uint256)":"9010d07c","getRoleMemberCount(bytes32)":"ca15c873","grantRole(bytes32,address)":"2f2ff15d","hasRole(bytes32,address)":"91d14854","renounceRole(bytes32,address)":"36568abe","revokeRole(bytes32,address)":"d547741f"}},"solidity/FastBridgeV2.sol:IAdmin":{"code":"0x","runtime-code":"0x","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.24 ^0.8.20 ^0.8.4;\n\n// contracts/interfaces/IAdmin.sol\n\ninterface IAdmin {\n // ============ Events ============\n\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n event ChainGasAmountUpdated(uint256 oldChainGasAmount, uint256 newChainGasAmount);\n\n // ============ Methods ============\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n\n function setChainGasAmount(uint256 newChainGasAmount) external;\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IFastBridgeV2Errors.sol\n\ninterface IFastBridgeV2Errors {\n error AmountIncorrect();\n error ChainIncorrect();\n error ExclusivityParamsIncorrect();\n error MsgValueIncorrect();\n error SenderIncorrect();\n error StatusIncorrect();\n error TokenNotContract();\n error ZapDataLengthAboveMax();\n error ZapNativeNotSupported();\n error ZeroAddress();\n\n error RecipientIncorrectReturnValue();\n error RecipientNoReturnValue();\n\n error DeadlineExceeded();\n error DeadlineNotExceeded();\n error DeadlineTooShort();\n error DisputePeriodNotPassed();\n error DisputePeriodPassed();\n error ExclusivityPeriodNotPassed();\n\n error TransactionRelayed();\n}\n\n// contracts/interfaces/IMulticallTarget.sol\n\n/// @notice Interface for a contract that can be called multiple times by the same caller. Inspired by MulticallV3:\n/// https://github.com/mds1/multicall/blob/master/src/Multicall3.sol\ninterface IMulticallTarget {\n struct Result {\n bool success;\n bytes returnData;\n }\n\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external;\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results);\n}\n\n// contracts/interfaces/IZapRecipient.sol\n\ninterface IZapRecipient {\n function zap(address token, uint256 amount, bytes memory zapData) external payable returns (bytes4);\n}\n\n// contracts/libs/Errors.sol\n\nerror DeadlineExceeded();\nerror DeadlineNotExceeded();\nerror DeadlineTooShort();\nerror InsufficientOutputAmount();\n\nerror MsgValueIncorrect();\nerror PoolNotFound();\nerror TokenAddressMismatch();\nerror TokenNotContract();\nerror TokenNotETH();\nerror TokensIdentical();\n\nerror ChainIncorrect();\nerror AmountIncorrect();\nerror ZeroAddress();\n\nerror DisputePeriodNotPassed();\nerror DisputePeriodPassed();\nerror SenderIncorrect();\nerror StatusIncorrect();\nerror TransactionIdIncorrect();\nerror TransactionRelayed();\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// contracts/interfaces/IFastBridgeV2.sol\n\ninterface IFastBridgeV2 is IFastBridge {\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n struct BridgeTxDetails {\n BridgeStatus status;\n uint32 destChainId;\n uint56 proofBlockTimestamp;\n address proofRelayer;\n }\n\n struct BridgeRelay {\n uint48 blockNumber;\n uint48 blockTimestamp;\n address relayer;\n }\n\n /// @notice New params introduced in the FastBridgeV2.\n /// We are passing fields from the older BridgeParams struct outside of this struct\n /// for backwards compatibility.\n /// Note: quoteRelayer and quoteExclusivitySeconds are either both zero (indicating no exclusivity)\n /// or both non-zero (indicating exclusivity for the given period).\n /// Note: zapNative \u003e 0 can NOT be used with destToken = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE (native token)\n /// @param quoteRelayer Relayer that provided the quote for the transaction\n /// @param quoteExclusivitySeconds Period of time the quote relayer is guaranteed exclusivity after user's deposit\n /// @param quoteId Unique quote identifier used for tracking the quote\n /// @param zapNative ETH value to send to the recipient (if any)\n /// @param zapData Parameters for the Zap to the destination recipient (if any)\n struct BridgeParamsV2 {\n address quoteRelayer;\n int256 quoteExclusivitySeconds;\n bytes quoteId;\n uint256 zapNative;\n bytes zapData;\n }\n\n /// @notice Updated bridge transaction struct to include parameters introduced in FastBridgeV2.\n /// Note: only `exclusivityRelayer` can fill such a transaction until `exclusivityEndTime`.\n struct BridgeTransactionV2 {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n // Note: sendChainGas flag from V1 is deprecated\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n address exclusivityRelayer;\n uint256 exclusivityEndTime;\n uint256 zapNative; // ETH value to send to the recipient (if any)\n bytes zapData; // data to pass for the Zap action (if any)\n }\n\n event BridgeQuoteDetails(bytes32 indexed transactionId, bytes quoteId);\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability\n /// to provide temporary exclusivity fill rights for the quote relayer.\n /// @param params The parameters required to bridge\n /// @param paramsV2 The parameters for exclusivity fill rights (optional, can be left empty)\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function relay(bytes memory request, address relayer) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param transactionId The transaction id associated with the encoded bridge transaction to prove\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital.\n /// @notice Can only send funds to the relayer address on the proof.\n /// @param request The encoded bridge transaction to claim on origin chain\n function claim(bytes memory request) external;\n /// @notice Checks if a transaction has been relayed\n /// @param transactionId The ID of the transaction to check\n /// @return True if the transaction has been relayed, false otherwise\n function bridgeRelays(bytes32 transactionId) external view returns (bool);\n\n /// @notice Returns the status of a bridge transaction\n /// @param transactionId The ID of the bridge transaction\n /// @return BridgeStatus Status of the bridge transaction\n function bridgeStatuses(bytes32 transactionId) external view returns (BridgeStatus);\n\n /// @notice Returns the timestamp and relayer of a bridge proof\n /// @param transactionId The ID of the bridge transaction\n /// @return timestamp The timestamp of the bridge proof\n /// @return relayer The relayer address of the bridge proof\n function bridgeProofs(bytes32 transactionId) external view returns (uint96 timestamp, address relayer);\n\n /// @notice Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\n /// @param request The bridge request to decode\n function getBridgeTransactionV2(bytes memory request) external view returns (BridgeTransactionV2 memory);\n}\n\n// contracts/utils/MulticallTarget.sol\n\n// solhint-disable avoid-low-level-calls\n/// @notice Template for a contract that supports batched calls (preserving the msg.sender).\n/// Only calls with zero msg.value could be batched.\nabstract contract MulticallTarget is IMulticallTarget {\n error MulticallTarget__UndeterminedRevert();\n\n /// @notice Perform a batched call to this contract, preserving the msg.sender.\n /// The return data from each call is discarded.\n /// @dev The method is non-payable, so only calls with `msg.value == 0` could be batched.\n /// It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag.\n /// Otherwise, the whole batch call will be reverted with the original revert reason.\n /// @param data List of abi-encoded calldata for the calls to perform.\n /// @param ignoreReverts Whether to ignore the revert errors from the calls.\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external {\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\n if (!success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(result);\n }\n }\n }\n\n /// @notice Perform a batched call to this contract, preserving the msg.sender.\n /// The return data from each call is preserved.\n /// @dev The method is non-payable, so only calls with `msg.value == 0` could be batched.\n /// It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag.\n /// Otherwise, the whole batch call will be reverted with the original revert reason.\n /// @param data List of abi-encoded calldata for the calls to perform.\n /// @param ignoreReverts Whether to ignore the revert errors from the calls.\n /// @return results List of results from the calls: `(success, returnData)`.\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results)\n {\n results = new Result[](data.length);\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (results[i].success, results[i].returnData) = address(this).delegatecall(data[i]);\n if (!results[i].success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(results[i].returnData);\n }\n }\n }\n\n /// @dev Bubbles the revert message from the underlying call.\n /// Note: preserves the same custom error or revert string, if one was used.\n /// Source: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v5.0.2/contracts/utils/Address.sol#L143-L158\n function _bubbleRevert(bytes memory returnData) internal pure {\n // Look for revert reason and bubble it up if present\n if (returnData.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n // solhint-disable-next-line no-inline-assembly\n assembly {\n let returndata_size := mload(returnData)\n revert(add(32, returnData), returndata_size)\n }\n } else {\n revert MulticallTarget__UndeterminedRevert();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// contracts/libs/BridgeTransactionV2.sol\n\n// solhint-disable no-inline-assembly\nlibrary BridgeTransactionV2Lib {\n uint16 internal constant VERSION = 2;\n\n // Offsets of the fields in the packed BridgeTransactionV2 struct\n // uint16 version [000 .. 002)\n // uint32 originChainId [002 .. 006)\n // uint32 destChainId [006 .. 010)\n // address originSender [010 .. 030)\n // address destRecipient [030 .. 050)\n // address originToken [050 .. 070)\n // address destToken [070 .. 090)\n // uint256 originAmount [090 .. 122)\n // uint256 destAmount [122 .. 154)\n // uint256 originFeeAmount [154 .. 186)\n // uint256 deadline [186 .. 218)\n // uint256 nonce [218 .. 250)\n // address exclusivityRelayer [250 .. 270)\n // uint256 exclusivityEndTime [270 .. 302)\n // uint256 zapNative [302 .. 334)\n // bytes zapData [334 .. ***)\n\n // forgefmt: disable-start\n uint256 private constant OFFSET_ORIGIN_CHAIN_ID = 2;\n uint256 private constant OFFSET_DEST_CHAIN_ID = 6;\n uint256 private constant OFFSET_ORIGIN_SENDER = 10;\n uint256 private constant OFFSET_DEST_RECIPIENT = 30;\n uint256 private constant OFFSET_ORIGIN_TOKEN = 50;\n uint256 private constant OFFSET_DEST_TOKEN = 70;\n uint256 private constant OFFSET_ORIGIN_AMOUNT = 90;\n uint256 private constant OFFSET_DEST_AMOUNT = 122;\n uint256 private constant OFFSET_ORIGIN_FEE_AMOUNT = 154;\n uint256 private constant OFFSET_DEADLINE = 186;\n uint256 private constant OFFSET_NONCE = 218;\n uint256 private constant OFFSET_EXCLUSIVITY_RELAYER = 250;\n uint256 private constant OFFSET_EXCLUSIVITY_END_TIME = 270;\n uint256 private constant OFFSET_ZAP_NATIVE = 302;\n uint256 private constant OFFSET_ZAP_DATA = 334;\n // forgefmt: disable-end\n\n error BridgeTransactionV2__InvalidEncodedTx();\n error BridgeTransactionV2__UnsupportedVersion(uint16 version);\n\n /// @notice Validates the encoded transaction to be a tightly packed encoded payload for BridgeTransactionV2.\n /// @dev Checks the minimum length and the version, use this function before decoding any of the fields.\n function validateV2(bytes calldata encodedTx) internal pure {\n // Check the minimum length: must at least include all static fields.\n if (encodedTx.length \u003c OFFSET_ZAP_DATA) revert BridgeTransactionV2__InvalidEncodedTx();\n // Once we validated the length, we can be sure that the version field is present.\n uint16 version_ = version(encodedTx);\n if (version_ != VERSION) revert BridgeTransactionV2__UnsupportedVersion(version_);\n }\n\n /// @notice Encodes the BridgeTransactionV2 struct by tightly packing the fields.\n /// @dev `abi.decode` will not work as a result of the tightly packed fields. Use `decodeV2` to decode instead.\n function encodeV2(IFastBridgeV2.BridgeTransactionV2 memory bridgeTx) internal pure returns (bytes memory) {\n // We split the encoding into two parts to avoid stack-too-deep error\n bytes memory firstPart = abi.encodePacked(\n VERSION,\n bridgeTx.originChainId,\n bridgeTx.destChainId,\n bridgeTx.originSender,\n bridgeTx.destRecipient,\n bridgeTx.originToken,\n bridgeTx.destToken,\n bridgeTx.originAmount\n );\n return abi.encodePacked(\n firstPart,\n bridgeTx.destAmount,\n bridgeTx.originFeeAmount,\n // Note: we skip the deprecated `sendChainGas` flag, which was present in BridgeTransaction V1\n bridgeTx.deadline,\n bridgeTx.nonce,\n // New V2 fields: exclusivity\n bridgeTx.exclusivityRelayer,\n bridgeTx.exclusivityEndTime,\n // New V2 fields: Zap\n bridgeTx.zapNative,\n bridgeTx.zapData\n );\n }\n\n /// @notice Decodes the BridgeTransactionV2 struct from the encoded transaction.\n /// @dev Encoded BridgeTransactionV2 struct must be tightly packed.\n /// Use `validateV2` before decoding to ensure the encoded transaction is valid.\n function decodeV2(bytes calldata encodedTx)\n internal\n pure\n returns (IFastBridgeV2.BridgeTransactionV2 memory bridgeTx)\n {\n bridgeTx.originChainId = originChainId(encodedTx);\n bridgeTx.destChainId = destChainId(encodedTx);\n bridgeTx.originSender = originSender(encodedTx);\n bridgeTx.destRecipient = destRecipient(encodedTx);\n bridgeTx.originToken = originToken(encodedTx);\n bridgeTx.destToken = destToken(encodedTx);\n bridgeTx.originAmount = originAmount(encodedTx);\n bridgeTx.destAmount = destAmount(encodedTx);\n bridgeTx.originFeeAmount = originFeeAmount(encodedTx);\n bridgeTx.deadline = deadline(encodedTx);\n bridgeTx.nonce = nonce(encodedTx);\n bridgeTx.exclusivityRelayer = exclusivityRelayer(encodedTx);\n bridgeTx.exclusivityEndTime = exclusivityEndTime(encodedTx);\n bridgeTx.zapNative = zapNative(encodedTx);\n bridgeTx.zapData = zapData(encodedTx);\n }\n\n /// @notice Extracts the version from the encoded transaction.\n function version(bytes calldata encodedTx) internal pure returns (uint16 version_) {\n // Load 32 bytes from the start and shift it 240 bits to the right to get the highest 16 bits.\n assembly {\n version_ := shr(240, calldataload(encodedTx.offset))\n }\n }\n\n /// @notice Extracts the origin chain ID from the encoded transaction.\n function originChainId(bytes calldata encodedTx) internal pure returns (uint32 originChainId_) {\n // Load 32 bytes from the offset and shift it 224 bits to the right to get the highest 32 bits.\n assembly {\n originChainId_ := shr(224, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_CHAIN_ID)))\n }\n }\n\n /// @notice Extracts the destination chain ID from the encoded transaction.\n function destChainId(bytes calldata encodedTx) internal pure returns (uint32 destChainId_) {\n // Load 32 bytes from the offset and shift it 224 bits to the right to get the highest 32 bits.\n assembly {\n destChainId_ := shr(224, calldataload(add(encodedTx.offset, OFFSET_DEST_CHAIN_ID)))\n }\n }\n\n /// @notice Extracts the origin sender from the encoded transaction.\n function originSender(bytes calldata encodedTx) internal pure returns (address originSender_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n originSender_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_SENDER)))\n }\n }\n\n /// @notice Extracts the destination recipient from the encoded transaction.\n function destRecipient(bytes calldata encodedTx) internal pure returns (address destRecipient_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n destRecipient_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_DEST_RECIPIENT)))\n }\n }\n\n /// @notice Extracts the origin token from the encoded transaction.\n function originToken(bytes calldata encodedTx) internal pure returns (address originToken_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n originToken_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_TOKEN)))\n }\n }\n\n /// @notice Extracts the destination token from the encoded transaction.\n function destToken(bytes calldata encodedTx) internal pure returns (address destToken_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n destToken_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_DEST_TOKEN)))\n }\n }\n\n /// @notice Extracts the origin amount from the encoded transaction.\n function originAmount(bytes calldata encodedTx) internal pure returns (uint256 originAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n originAmount_ := calldataload(add(encodedTx.offset, OFFSET_ORIGIN_AMOUNT))\n }\n }\n\n /// @notice Extracts the destination amount from the encoded transaction.\n function destAmount(bytes calldata encodedTx) internal pure returns (uint256 destAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n destAmount_ := calldataload(add(encodedTx.offset, OFFSET_DEST_AMOUNT))\n }\n }\n\n /// @notice Extracts the origin fee amount from the encoded transaction.\n function originFeeAmount(bytes calldata encodedTx) internal pure returns (uint256 originFeeAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n originFeeAmount_ := calldataload(add(encodedTx.offset, OFFSET_ORIGIN_FEE_AMOUNT))\n }\n }\n\n /// @notice Extracts the deadline from the encoded transaction.\n function deadline(bytes calldata encodedTx) internal pure returns (uint256 deadline_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n deadline_ := calldataload(add(encodedTx.offset, OFFSET_DEADLINE))\n }\n }\n\n /// @notice Extracts the nonce from the encoded transaction.\n function nonce(bytes calldata encodedTx) internal pure returns (uint256 nonce_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n nonce_ := calldataload(add(encodedTx.offset, OFFSET_NONCE))\n }\n }\n\n /// @notice Extracts the exclusivity relayer from the encoded transaction.\n function exclusivityRelayer(bytes calldata encodedTx) internal pure returns (address exclusivityRelayer_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n exclusivityRelayer_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_EXCLUSIVITY_RELAYER)))\n }\n }\n\n /// @notice Extracts the exclusivity end time from the encoded transaction.\n function exclusivityEndTime(bytes calldata encodedTx) internal pure returns (uint256 exclusivityEndTime_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n exclusivityEndTime_ := calldataload(add(encodedTx.offset, OFFSET_EXCLUSIVITY_END_TIME))\n }\n }\n\n /// @notice Extracts the Zap's native value from the encoded transaction.\n function zapNative(bytes calldata encodedTx) internal pure returns (uint256 zapNative_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n zapNative_ := calldataload(add(encodedTx.offset, OFFSET_ZAP_NATIVE))\n }\n }\n\n /// @notice Extracts the Zap's data from the encoded transaction.\n function zapData(bytes calldata encodedTx) internal pure returns (bytes calldata zapData_) {\n zapData_ = encodedTx[OFFSET_ZAP_DATA:];\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// contracts/libs/UniversalToken.sol\n\nlibrary UniversalTokenLib {\n using SafeERC20 for IERC20;\n\n address internal constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Transfers tokens to the given account. Reverts if transfer is not successful.\n /// @dev This might trigger fallback, if ETH is transferred to the contract.\n /// Make sure this can not lead to reentrancy attacks.\n function universalTransfer(address token, address to, uint256 value) internal {\n // Don't do anything, if need to send tokens to this address\n if (to == address(this)) return;\n // Don't do anything, if trying to send zero value\n if (value == 0) return;\n if (token == ETH_ADDRESS) {\n /// @dev Note: this can potentially lead to executing code in `to`.\n // solhint-disable-next-line avoid-low-level-calls\n (bool success,) = to.call{value: value}(\"\");\n require(success, \"ETH transfer failed\");\n } else {\n IERC20(token).safeTransfer(to, value);\n }\n }\n\n /// @notice Issues an infinite allowance to the spender, if the current allowance is insufficient\n /// to spend the given amount.\n function universalApproveInfinity(address token, address spender, uint256 amountToSpend) internal {\n // ETH Chad doesn't require your approval\n if (token == ETH_ADDRESS) return;\n // No-op if allowance is already sufficient\n uint256 allowance = IERC20(token).allowance(address(this), spender);\n if (allowance \u003e= amountToSpend) return;\n // Otherwise, reset approval to 0 and set to max allowance\n if (allowance \u003e 0) IERC20(token).safeDecreaseAllowance(spender, allowance);\n IERC20(token).safeIncreaseAllowance(spender, type(uint256).max);\n }\n\n /// @notice Returns the balance of the given token (or native ETH) for the given account.\n function universalBalanceOf(address token, address account) internal view returns (uint256) {\n if (token == ETH_ADDRESS) {\n return account.balance;\n } else {\n return IERC20(token).balanceOf(account);\n }\n }\n\n /// @dev Checks that token is a contract and not ETH_ADDRESS.\n function assertIsContract(address token) internal view {\n // Check that ETH_ADDRESS was not used (in case this is a predeploy on any of the chains)\n if (token == UniversalTokenLib.ETH_ADDRESS) revert TokenNotContract();\n // Check that token is not an EOA\n if (token.code.length == 0) revert TokenNotContract();\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/Admin.sol\n\ncontract Admin is IAdmin, AccessControlEnumerable {\n using UniversalTokenLib for address;\n\n bytes32 public constant RELAYER_ROLE = keccak256(\"RELAYER_ROLE\");\n bytes32 public constant REFUNDER_ROLE = keccak256(\"REFUNDER_ROLE\");\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n uint256 public constant FEE_BPS = 1e6;\n uint256 public constant FEE_RATE_MAX = 0.01e6; // max 1% on origin amount\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Chain gas amount to forward as rebate if requested\n uint256 public chainGasAmount;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n }\n\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n require(newFeeRate \u003c= FEE_RATE_MAX, \"newFeeRate \u003e max\");\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n token.universalTransfer(recipient, feeAmount);\n emit FeesSwept(token, recipient, feeAmount);\n }\n\n function setChainGasAmount(uint256 newChainGasAmount) external onlyRole(GOVERNOR_ROLE) {\n uint256 oldChainGasAmount = chainGasAmount;\n chainGasAmount = newChainGasAmount;\n emit ChainGasAmountUpdated(oldChainGasAmount, newChainGasAmount);\n }\n}\n\n// contracts/FastBridgeV2.sol\n\n/// @notice FastBridgeV2 is a contract for bridging tokens across chains.\ncontract FastBridgeV2 is Admin, MulticallTarget, IFastBridgeV2, IFastBridgeV2Errors {\n using BridgeTransactionV2Lib for bytes;\n using SafeERC20 for IERC20;\n\n /// @notice Address reserved for native gas token (ETH on Ethereum and most L2s, AVAX on Avalanche, etc)\n address public constant NATIVE_GAS_TOKEN = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Delay for a transaction after which it could be permisionlessly refunded\n uint256 public constant REFUND_DELAY = 7 days;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n /// @notice Maximum length of accepted zapData\n uint256 public constant MAX_ZAP_DATA_LENGTH = 2 ** 16 - 1;\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeTxDetails) public bridgeTxDetails;\n /// @notice Relay details on destination chain\n mapping(bytes32 =\u003e BridgeRelay) public bridgeRelayDetails;\n /// @notice Unique bridge nonces tracked per originSender\n mapping(address =\u003e uint256) public senderNonces;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Replaced by senderNonces\n uint256 public immutable nonce = 0;\n /// @notice the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n bridge({\n params: params,\n paramsV2: BridgeParamsV2({\n quoteRelayer: address(0),\n quoteExclusivitySeconds: 0,\n quoteId: bytes(\"\"),\n zapNative: 0,\n zapData: bytes(\"\")\n })\n });\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes calldata request) external payable {\n // relay override will validate the request\n relay({request: request, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes calldata request, bytes32 destTxHash) external {\n request.validateV2();\n prove({transactionId: keccak256(request), destTxHash: destTxHash, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridgeV2\n function claim(bytes calldata request) external {\n // claim override will validate the request\n claim({request: request, to: address(0)});\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Aggregate the read operations from the same storage slot\n address disputedRelayer = $.proofRelayer;\n BridgeStatus status = $.status;\n uint56 proofBlockTimestamp = $.proofBlockTimestamp;\n // Can only dispute a RELAYER_PROVED transaction within the dispute period\n if (status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(proofBlockTimestamp) \u003e DISPUTE_PERIOD) {\n revert DisputePeriodPassed();\n }\n // Update status to REQUESTED and delete the disputed proof details\n // Note: these are storage writes\n $.status = BridgeStatus.REQUESTED;\n $.proofRelayer = address(0);\n $.proofBlockTimestamp = 0;\n\n emit BridgeProofDisputed(transactionId, disputedRelayer);\n }\n\n /// @inheritdoc IFastBridge\n function refund(bytes calldata request) external {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Can only refund a REQUESTED transaction after its deadline expires\n if ($.status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n uint256 deadline = request.deadline();\n // Permissionless refund is only allowed after REFUND_DELAY on top of the deadline\n if (!hasRole(REFUNDER_ROLE, msg.sender)) deadline += REFUND_DELAY;\n if (block.timestamp \u003c= deadline) revert DeadlineNotExceeded();\n // Update status to REFUNDED and return the full amount (collateral + protocol fees) to the original sender.\n // The protocol fees are only updated when the transaction is claimed, so we don't need to update them here.\n // Note: this is a storage write\n $.status = BridgeStatus.REFUNDED;\n\n address to = request.originSender();\n address token = request.originToken();\n uint256 amount = request.originAmount() + request.originFeeAmount();\n // Emit the event before any external calls\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n // Complete the user refund as the last transaction action\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(to), amount);\n } else {\n IERC20(token).safeTransfer(to, amount);\n }\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // The correct relayer can only claim a RELAYER_PROVED transaction after the dispute period\n if ($.status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if ($.proofRelayer != relayer) revert SenderIncorrect();\n return _timeSince($.proofBlockTimestamp) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n /// @dev This method is added to achieve backwards compatibility with decoding requests into V1 structs:\n /// - `zapNative` is partially reported as a zero/non-zero flag\n /// - `zapData` is ignored\n /// In order to process all kinds of requests use getBridgeTransactionV2 instead.\n function getBridgeTransaction(bytes calldata request) external view returns (BridgeTransaction memory) {\n // Try decoding into V2 struct first. This will revert if V1 struct is passed\n try this.getBridgeTransactionV2(request) returns (BridgeTransactionV2 memory txV2) {\n // Note: we entirely ignore the zapData field, as it was not present in V1\n return BridgeTransaction({\n originChainId: txV2.originChainId,\n destChainId: txV2.destChainId,\n originSender: txV2.originSender,\n destRecipient: txV2.destRecipient,\n originToken: txV2.originToken,\n destToken: txV2.destToken,\n originAmount: txV2.originAmount,\n destAmount: txV2.destAmount,\n originFeeAmount: txV2.originFeeAmount,\n sendChainGas: txV2.zapNative != 0,\n deadline: txV2.deadline,\n nonce: txV2.nonce\n });\n } catch {\n // Fallback to V1 struct\n return abi.decode(request, (BridgeTransaction));\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function getBridgeTransactionV2(bytes calldata request) external pure returns (BridgeTransactionV2 memory) {\n request.validateV2();\n return BridgeTransactionV2Lib.decodeV2(request);\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) public payable {\n int256 exclusivityEndTime = 0;\n // if relayer exclusivity is not intended for this bridge, set exclusivityEndTime to static zero\n // otherwise, set exclusivity to expire at the current block ts offset by quoteExclusivitySeconds\n if (paramsV2.quoteRelayer != address(0)) {\n exclusivityEndTime = int256(block.timestamp) + paramsV2.quoteExclusivitySeconds;\n }\n _validateBridgeParams(params, paramsV2, exclusivityEndTime);\n\n // transfer tokens to bridge contract\n /// @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _takeBridgedUserAsset(params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) {\n originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n }\n\n // set status to requested\n bytes memory request = BridgeTransactionV2Lib.encodeV2(\n BridgeTransactionV2({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n deadline: params.deadline,\n nonce: senderNonces[params.sender]++, // increment nonce on every bridge\n exclusivityRelayer: paramsV2.quoteRelayer,\n // We checked exclusivityEndTime to be in range [0 .. params.deadline] above, so can safely cast\n exclusivityEndTime: uint256(exclusivityEndTime),\n zapNative: paramsV2.zapNative,\n zapData: paramsV2.zapData\n })\n );\n bytes32 transactionId = keccak256(request);\n // Note: the tx status will be updated throughout the tx lifecycle, while destChainId is set once here\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n bridgeTxDetails[transactionId].destChainId = params.dstChainId;\n\n emit BridgeRequested({\n transactionId: transactionId,\n sender: params.sender,\n request: request,\n destChainId: params.dstChainId,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n sendChainGas: paramsV2.zapNative != 0\n });\n emit BridgeQuoteDetails(transactionId, paramsV2.quoteId);\n }\n\n /// @inheritdoc IFastBridgeV2\n function relay(bytes calldata request, address relayer) public payable {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n _validateRelayParams(request, transactionId, relayer);\n // mark bridge transaction as relayed\n bridgeRelayDetails[transactionId] =\n BridgeRelay({blockNumber: uint48(block.number), blockTimestamp: uint48(block.timestamp), relayer: relayer});\n\n // transfer tokens to recipient on destination chain and trigger Zap if requested\n address to = request.destRecipient();\n address token = request.destToken();\n uint256 amount = request.destAmount();\n uint256 zapNative = request.zapNative();\n\n // Emit the event before any external calls\n emit BridgeRelayed({\n transactionId: transactionId,\n relayer: relayer,\n to: to,\n originChainId: request.originChainId(),\n originToken: request.originToken(),\n destToken: token,\n originAmount: request.originAmount(),\n destAmount: amount,\n chainGasAmount: zapNative\n });\n\n // All state changes have been done at this point, can proceed to the external calls.\n // This follows the checks-effects-interactions pattern to mitigate potential reentrancy attacks.\n if (token == NATIVE_GAS_TOKEN) {\n // For the native gas token, additional zapNative is not allowed\n if (zapNative != 0) revert ZapNativeNotSupported();\n // Check that the correct msg.value was sent\n if (msg.value != amount) revert MsgValueIncorrect();\n // Don't do a native transfer yet: we will handle it alongside the Zap below\n } else {\n // For ERC20s, we check that the correct msg.value was sent\n if (msg.value != zapNative) revert MsgValueIncorrect();\n // We need to transfer the tokens from the Relayer to the recipient first before performing an\n // optional post-transfer Zap.\n IERC20(token).safeTransferFrom(msg.sender, to, amount);\n }\n // At this point we have done:\n // - Transferred the requested amount of ERC20 tokens to the recipient.\n // At this point we have confirmed:\n // - For ERC20s: msg.value matches the requested zapNative amount.\n // - For the native gas token: msg.value matches the requested destAmount.\n // Remaining optional things to do:\n // - Forward the full msg.value to the recipient (if non-zero).\n // - Trigger a Zap (if zapData is present).\n bytes calldata zapData = request.zapData();\n if (zapData.length != 0) {\n // Zap Data is present: Zap has been requested by the recipient. Trigger it forwarding the full msg.value.\n\n // Note: if token has a fee on transfers, the recipient will have received less than `amount`.\n // This is a very niche edge case and should be handled by the recipient contract.\n _triggerZapWithChecks({recipient: to, token: token, amount: amount, zapData: zapData});\n } else if (msg.value != 0) {\n // Zap Data is missing, but msg.value was sent. This could happen in two different cases:\n // - Relay with the native gas token is happening.\n // - Relay with ERC20 is happening, with a `zapNative \u003e 0` request.\n // In both cases, we need to transfer the full msg.value to the recipient.\n Address.sendValue(payable(to), msg.value);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) public onlyRole(RELAYER_ROLE) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n\n // Can only prove a REQUESTED transaction\n if ($.status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n // Update status to RELAYER_PROVED and store the proof details\n // Note: these are storage writes\n $.status = BridgeStatus.RELAYER_PROVED;\n $.proofBlockTimestamp = uint56(block.timestamp);\n $.proofRelayer = relayer;\n\n emit BridgeProofProvided(transactionId, relayer, destTxHash);\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes calldata request, address to) public {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Aggregate the read operations from the same storage slot\n address proofRelayer = $.proofRelayer;\n BridgeStatus status = $.status;\n uint56 proofBlockTimestamp = $.proofBlockTimestamp;\n\n // Can only claim a RELAYER_PROVED transaction after the dispute period\n if (status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(proofBlockTimestamp) \u003c= DISPUTE_PERIOD) {\n revert DisputePeriodNotPassed();\n }\n\n if (to == address(0)) {\n // Anyone could claim the funds to the proven relayer on their behalf\n to = proofRelayer;\n } else if (proofRelayer != msg.sender) {\n // Only the proven relayer could specify an address to claim the funds to\n revert SenderIncorrect();\n }\n\n // Update status to RELAYER_CLAIMED and transfer the origin collateral to the specified claim address\n // Note: this is a storage write\n $.status = BridgeStatus.RELAYER_CLAIMED;\n\n address token = request.originToken();\n uint256 amount = request.originAmount();\n // Update protocol fees if origin fee amount exists\n uint256 originFeeAmount = request.originFeeAmount();\n if (originFeeAmount \u003e 0) protocolFees[token] += originFeeAmount;\n // Emit the event before any external calls\n emit BridgeDepositClaimed(transactionId, proofRelayer, to, token, amount);\n // Complete the relayer claim as the last transaction action\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(to), amount);\n } else {\n IERC20(token).safeTransfer(to, amount);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeStatuses(bytes32 transactionId) public view returns (BridgeStatus status) {\n return bridgeTxDetails[transactionId].status;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeProofs(bytes32 transactionId) public view returns (uint96 timestamp, address relayer) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n\n timestamp = $.proofBlockTimestamp;\n relayer = $.proofRelayer;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeRelays(bytes32 transactionId) public view returns (bool) {\n // has this transactionId been relayed?\n return bridgeRelayDetails[transactionId].relayer != address(0);\n }\n\n /// @notice Takes the bridged asset from the user into FastBridgeV2 custody. It will be later\n /// claimed by the relayer who completed the relay on destination chain, or refunded back to the user,\n /// should no one complete the relay.\n function _takeBridgedUserAsset(address token, uint256 amount) internal returns (uint256 amountTaken) {\n if (token == NATIVE_GAS_TOKEN) {\n // For the native gas token, we just need to check that the supplied msg.value is correct.\n // Supplied `msg.value` is already in FastBridgeV2 custody.\n if (amount != msg.value) revert MsgValueIncorrect();\n amountTaken = msg.value;\n } else {\n // For ERC20s, token is explicitly transferred from the user to FastBridgeV2.\n // We don't allow non-zero `msg.value` to avoid extra funds from being stuck in FastBridgeV2.\n if (msg.value != 0) revert MsgValueIncorrect();\n // Throw an explicit error if the provided token address is not a contract\n if (token.code.length == 0) revert TokenNotContract();\n amountTaken = IERC20(token).balanceOf(address(this));\n IERC20(token).safeTransferFrom(msg.sender, address(this), amount);\n // Use the balance difference as the amount taken in case of fee on transfer tokens.\n amountTaken = IERC20(token).balanceOf(address(this)) - amountTaken;\n }\n }\n\n /// @notice Calls the Recipient's hook function with the specified zapData and performs\n /// all the necessary checks for the returned value.\n function _triggerZapWithChecks(address recipient, address token, uint256 amount, bytes calldata zapData) internal {\n // This will bubble any revert messages from the hook function\n bytes memory returnData = Address.functionCallWithValue({\n target: recipient,\n data: abi.encodeCall(IZapRecipient.zap, (token, amount, zapData)),\n // Note: see `relay()` for reasoning behind passing msg.value\n value: msg.value\n });\n // Explicit revert if no return data at all\n if (returnData.length == 0) revert RecipientNoReturnValue();\n // Check that exactly a single return value was returned\n if (returnData.length != 32) revert RecipientIncorrectReturnValue();\n // Return value should be abi-encoded hook function selector\n if (bytes32(returnData) != bytes32(IZapRecipient.zap.selector)) {\n revert RecipientIncorrectReturnValue();\n }\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint56(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint56).max but\n /// proof.timestamp \u003c type(uint56).max via unchecked statement\n /// @param proofBlockTimestamp The bridge proof block timestamp\n /// @return delta Time delta since proof submitted\n function _timeSince(uint56 proofBlockTimestamp) internal view returns (uint256 delta) {\n unchecked {\n delta = uint56(block.timestamp) - proofBlockTimestamp;\n }\n }\n\n /// @notice Performs all the necessary checks for a bridge to happen.\n /// @dev There's no good way to refactor this function to reduce cyclomatic complexity due to\n /// the number of checks that need to be performed, so we skip the code-complexity rule here.\n // solhint-disable-next-line code-complexity\n function _validateBridgeParams(\n BridgeParams memory params,\n BridgeParamsV2 memory paramsV2,\n int256 exclusivityEndTime\n )\n internal\n view\n {\n // Check V1 (legacy) params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.sender == address(0) || params.to == address(0)) revert ZeroAddress();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n // Check V2 params\n if (paramsV2.zapData.length \u003e MAX_ZAP_DATA_LENGTH) revert ZapDataLengthAboveMax();\n if (paramsV2.zapNative != 0 \u0026\u0026 params.destToken == NATIVE_GAS_TOKEN) {\n revert ZapNativeNotSupported();\n }\n // exclusivityEndTime must be in range [0 .. params.deadline]\n if (exclusivityEndTime \u003c 0 || exclusivityEndTime \u003e int256(params.deadline)) {\n revert ExclusivityParamsIncorrect();\n }\n }\n\n /// @notice Performs all the necessary checks for a relay to happen.\n function _validateRelayParams(bytes calldata request, bytes32 transactionId, address relayer) internal view {\n if (relayer == address(0)) revert ZeroAddress();\n // Check if the transaction has already been relayed\n if (bridgeRelays(transactionId)) revert TransactionRelayed();\n if (request.destChainId() != block.chainid) revert ChainIncorrect();\n // Check the deadline for relay to happen\n if (block.timestamp \u003e request.deadline()) revert DeadlineExceeded();\n // Check the exclusivity period, if it is still ongoing\n address exclRelayer = request.exclusivityRelayer();\n if (exclRelayer != address(0) \u0026\u0026 exclRelayer != relayer \u0026\u0026 block.timestamp \u003c= request.exclusivityEndTime()) {\n revert ExclusivityPeriodNotPassed();\n }\n }\n}\n","language":"Solidity","languageVersion":"0.8.24","compilerVersion":"0.8.24","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"","srcMapRuntime":"","abiDefinition":[{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldChainGasAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newChainGasAmount","type":"uint256"}],"name":"ChainGasAmountUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldFeeRate","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newFeeRate","type":"uint256"}],"name":"FeeRateUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"address","name":"recipient","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"FeesSwept","type":"event"},{"inputs":[{"internalType":"uint256","name":"newChainGasAmount","type":"uint256"}],"name":"setChainGasAmount","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"newFeeRate","type":"uint256"}],"name":"setProtocolFeeRate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"address","name":"recipient","type":"address"}],"name":"sweepProtocolFees","outputs":[],"stateMutability":"nonpayable","type":"function"}],"userDoc":{"kind":"user","methods":{},"version":1},"developerDoc":{"kind":"dev","methods":{},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"oldChainGasAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newChainGasAmount\",\"type\":\"uint256\"}],\"name\":\"ChainGasAmountUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"oldFeeRate\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newFeeRate\",\"type\":\"uint256\"}],\"name\":\"FeeRateUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"FeesSwept\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"newChainGasAmount\",\"type\":\"uint256\"}],\"name\":\"setChainGasAmount\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"newFeeRate\",\"type\":\"uint256\"}],\"name\":\"setProtocolFeeRate\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"}],\"name\":\"sweepProtocolFees\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeV2.sol\":\"IAdmin\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeV2.sol\":{\"keccak256\":\"0x5069b55ca07f21bfe30b2a43c18a18318c8af9c181b2dcb07c290825efd70f34\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://273dc020a49d08e50126bbea0d7f783f79d08c702f2fdbc560618d24af308acc\",\"dweb:/ipfs/QmXJ2UVzFc8EPB74RT4CXQPC4xw66jt4T13poyfyd3UERh\"]}},\"version\":1}"},"hashes":{"setChainGasAmount(uint256)":"b250fe6b","setProtocolFeeRate(uint256)":"b13aa2d6","sweepProtocolFees(address,address)":"06f333f2"}},"solidity/FastBridgeV2.sol:IERC165":{"code":"0x","runtime-code":"0x","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.24 ^0.8.20 ^0.8.4;\n\n// contracts/interfaces/IAdmin.sol\n\ninterface IAdmin {\n // ============ Events ============\n\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n event ChainGasAmountUpdated(uint256 oldChainGasAmount, uint256 newChainGasAmount);\n\n // ============ Methods ============\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n\n function setChainGasAmount(uint256 newChainGasAmount) external;\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IFastBridgeV2Errors.sol\n\ninterface IFastBridgeV2Errors {\n error AmountIncorrect();\n error ChainIncorrect();\n error ExclusivityParamsIncorrect();\n error MsgValueIncorrect();\n error SenderIncorrect();\n error StatusIncorrect();\n error TokenNotContract();\n error ZapDataLengthAboveMax();\n error ZapNativeNotSupported();\n error ZeroAddress();\n\n error RecipientIncorrectReturnValue();\n error RecipientNoReturnValue();\n\n error DeadlineExceeded();\n error DeadlineNotExceeded();\n error DeadlineTooShort();\n error DisputePeriodNotPassed();\n error DisputePeriodPassed();\n error ExclusivityPeriodNotPassed();\n\n error TransactionRelayed();\n}\n\n// contracts/interfaces/IMulticallTarget.sol\n\n/// @notice Interface for a contract that can be called multiple times by the same caller. Inspired by MulticallV3:\n/// https://github.com/mds1/multicall/blob/master/src/Multicall3.sol\ninterface IMulticallTarget {\n struct Result {\n bool success;\n bytes returnData;\n }\n\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external;\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results);\n}\n\n// contracts/interfaces/IZapRecipient.sol\n\ninterface IZapRecipient {\n function zap(address token, uint256 amount, bytes memory zapData) external payable returns (bytes4);\n}\n\n// contracts/libs/Errors.sol\n\nerror DeadlineExceeded();\nerror DeadlineNotExceeded();\nerror DeadlineTooShort();\nerror InsufficientOutputAmount();\n\nerror MsgValueIncorrect();\nerror PoolNotFound();\nerror TokenAddressMismatch();\nerror TokenNotContract();\nerror TokenNotETH();\nerror TokensIdentical();\n\nerror ChainIncorrect();\nerror AmountIncorrect();\nerror ZeroAddress();\n\nerror DisputePeriodNotPassed();\nerror DisputePeriodPassed();\nerror SenderIncorrect();\nerror StatusIncorrect();\nerror TransactionIdIncorrect();\nerror TransactionRelayed();\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// contracts/interfaces/IFastBridgeV2.sol\n\ninterface IFastBridgeV2 is IFastBridge {\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n struct BridgeTxDetails {\n BridgeStatus status;\n uint32 destChainId;\n uint56 proofBlockTimestamp;\n address proofRelayer;\n }\n\n struct BridgeRelay {\n uint48 blockNumber;\n uint48 blockTimestamp;\n address relayer;\n }\n\n /// @notice New params introduced in the FastBridgeV2.\n /// We are passing fields from the older BridgeParams struct outside of this struct\n /// for backwards compatibility.\n /// Note: quoteRelayer and quoteExclusivitySeconds are either both zero (indicating no exclusivity)\n /// or both non-zero (indicating exclusivity for the given period).\n /// Note: zapNative \u003e 0 can NOT be used with destToken = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE (native token)\n /// @param quoteRelayer Relayer that provided the quote for the transaction\n /// @param quoteExclusivitySeconds Period of time the quote relayer is guaranteed exclusivity after user's deposit\n /// @param quoteId Unique quote identifier used for tracking the quote\n /// @param zapNative ETH value to send to the recipient (if any)\n /// @param zapData Parameters for the Zap to the destination recipient (if any)\n struct BridgeParamsV2 {\n address quoteRelayer;\n int256 quoteExclusivitySeconds;\n bytes quoteId;\n uint256 zapNative;\n bytes zapData;\n }\n\n /// @notice Updated bridge transaction struct to include parameters introduced in FastBridgeV2.\n /// Note: only `exclusivityRelayer` can fill such a transaction until `exclusivityEndTime`.\n struct BridgeTransactionV2 {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n // Note: sendChainGas flag from V1 is deprecated\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n address exclusivityRelayer;\n uint256 exclusivityEndTime;\n uint256 zapNative; // ETH value to send to the recipient (if any)\n bytes zapData; // data to pass for the Zap action (if any)\n }\n\n event BridgeQuoteDetails(bytes32 indexed transactionId, bytes quoteId);\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability\n /// to provide temporary exclusivity fill rights for the quote relayer.\n /// @param params The parameters required to bridge\n /// @param paramsV2 The parameters for exclusivity fill rights (optional, can be left empty)\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function relay(bytes memory request, address relayer) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param transactionId The transaction id associated with the encoded bridge transaction to prove\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital.\n /// @notice Can only send funds to the relayer address on the proof.\n /// @param request The encoded bridge transaction to claim on origin chain\n function claim(bytes memory request) external;\n /// @notice Checks if a transaction has been relayed\n /// @param transactionId The ID of the transaction to check\n /// @return True if the transaction has been relayed, false otherwise\n function bridgeRelays(bytes32 transactionId) external view returns (bool);\n\n /// @notice Returns the status of a bridge transaction\n /// @param transactionId The ID of the bridge transaction\n /// @return BridgeStatus Status of the bridge transaction\n function bridgeStatuses(bytes32 transactionId) external view returns (BridgeStatus);\n\n /// @notice Returns the timestamp and relayer of a bridge proof\n /// @param transactionId The ID of the bridge transaction\n /// @return timestamp The timestamp of the bridge proof\n /// @return relayer The relayer address of the bridge proof\n function bridgeProofs(bytes32 transactionId) external view returns (uint96 timestamp, address relayer);\n\n /// @notice Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\n /// @param request The bridge request to decode\n function getBridgeTransactionV2(bytes memory request) external view returns (BridgeTransactionV2 memory);\n}\n\n// contracts/utils/MulticallTarget.sol\n\n// solhint-disable avoid-low-level-calls\n/// @notice Template for a contract that supports batched calls (preserving the msg.sender).\n/// Only calls with zero msg.value could be batched.\nabstract contract MulticallTarget is IMulticallTarget {\n error MulticallTarget__UndeterminedRevert();\n\n /// @notice Perform a batched call to this contract, preserving the msg.sender.\n /// The return data from each call is discarded.\n /// @dev The method is non-payable, so only calls with `msg.value == 0` could be batched.\n /// It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag.\n /// Otherwise, the whole batch call will be reverted with the original revert reason.\n /// @param data List of abi-encoded calldata for the calls to perform.\n /// @param ignoreReverts Whether to ignore the revert errors from the calls.\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external {\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\n if (!success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(result);\n }\n }\n }\n\n /// @notice Perform a batched call to this contract, preserving the msg.sender.\n /// The return data from each call is preserved.\n /// @dev The method is non-payable, so only calls with `msg.value == 0` could be batched.\n /// It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag.\n /// Otherwise, the whole batch call will be reverted with the original revert reason.\n /// @param data List of abi-encoded calldata for the calls to perform.\n /// @param ignoreReverts Whether to ignore the revert errors from the calls.\n /// @return results List of results from the calls: `(success, returnData)`.\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results)\n {\n results = new Result[](data.length);\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (results[i].success, results[i].returnData) = address(this).delegatecall(data[i]);\n if (!results[i].success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(results[i].returnData);\n }\n }\n }\n\n /// @dev Bubbles the revert message from the underlying call.\n /// Note: preserves the same custom error or revert string, if one was used.\n /// Source: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v5.0.2/contracts/utils/Address.sol#L143-L158\n function _bubbleRevert(bytes memory returnData) internal pure {\n // Look for revert reason and bubble it up if present\n if (returnData.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n // solhint-disable-next-line no-inline-assembly\n assembly {\n let returndata_size := mload(returnData)\n revert(add(32, returnData), returndata_size)\n }\n } else {\n revert MulticallTarget__UndeterminedRevert();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// contracts/libs/BridgeTransactionV2.sol\n\n// solhint-disable no-inline-assembly\nlibrary BridgeTransactionV2Lib {\n uint16 internal constant VERSION = 2;\n\n // Offsets of the fields in the packed BridgeTransactionV2 struct\n // uint16 version [000 .. 002)\n // uint32 originChainId [002 .. 006)\n // uint32 destChainId [006 .. 010)\n // address originSender [010 .. 030)\n // address destRecipient [030 .. 050)\n // address originToken [050 .. 070)\n // address destToken [070 .. 090)\n // uint256 originAmount [090 .. 122)\n // uint256 destAmount [122 .. 154)\n // uint256 originFeeAmount [154 .. 186)\n // uint256 deadline [186 .. 218)\n // uint256 nonce [218 .. 250)\n // address exclusivityRelayer [250 .. 270)\n // uint256 exclusivityEndTime [270 .. 302)\n // uint256 zapNative [302 .. 334)\n // bytes zapData [334 .. ***)\n\n // forgefmt: disable-start\n uint256 private constant OFFSET_ORIGIN_CHAIN_ID = 2;\n uint256 private constant OFFSET_DEST_CHAIN_ID = 6;\n uint256 private constant OFFSET_ORIGIN_SENDER = 10;\n uint256 private constant OFFSET_DEST_RECIPIENT = 30;\n uint256 private constant OFFSET_ORIGIN_TOKEN = 50;\n uint256 private constant OFFSET_DEST_TOKEN = 70;\n uint256 private constant OFFSET_ORIGIN_AMOUNT = 90;\n uint256 private constant OFFSET_DEST_AMOUNT = 122;\n uint256 private constant OFFSET_ORIGIN_FEE_AMOUNT = 154;\n uint256 private constant OFFSET_DEADLINE = 186;\n uint256 private constant OFFSET_NONCE = 218;\n uint256 private constant OFFSET_EXCLUSIVITY_RELAYER = 250;\n uint256 private constant OFFSET_EXCLUSIVITY_END_TIME = 270;\n uint256 private constant OFFSET_ZAP_NATIVE = 302;\n uint256 private constant OFFSET_ZAP_DATA = 334;\n // forgefmt: disable-end\n\n error BridgeTransactionV2__InvalidEncodedTx();\n error BridgeTransactionV2__UnsupportedVersion(uint16 version);\n\n /// @notice Validates the encoded transaction to be a tightly packed encoded payload for BridgeTransactionV2.\n /// @dev Checks the minimum length and the version, use this function before decoding any of the fields.\n function validateV2(bytes calldata encodedTx) internal pure {\n // Check the minimum length: must at least include all static fields.\n if (encodedTx.length \u003c OFFSET_ZAP_DATA) revert BridgeTransactionV2__InvalidEncodedTx();\n // Once we validated the length, we can be sure that the version field is present.\n uint16 version_ = version(encodedTx);\n if (version_ != VERSION) revert BridgeTransactionV2__UnsupportedVersion(version_);\n }\n\n /// @notice Encodes the BridgeTransactionV2 struct by tightly packing the fields.\n /// @dev `abi.decode` will not work as a result of the tightly packed fields. Use `decodeV2` to decode instead.\n function encodeV2(IFastBridgeV2.BridgeTransactionV2 memory bridgeTx) internal pure returns (bytes memory) {\n // We split the encoding into two parts to avoid stack-too-deep error\n bytes memory firstPart = abi.encodePacked(\n VERSION,\n bridgeTx.originChainId,\n bridgeTx.destChainId,\n bridgeTx.originSender,\n bridgeTx.destRecipient,\n bridgeTx.originToken,\n bridgeTx.destToken,\n bridgeTx.originAmount\n );\n return abi.encodePacked(\n firstPart,\n bridgeTx.destAmount,\n bridgeTx.originFeeAmount,\n // Note: we skip the deprecated `sendChainGas` flag, which was present in BridgeTransaction V1\n bridgeTx.deadline,\n bridgeTx.nonce,\n // New V2 fields: exclusivity\n bridgeTx.exclusivityRelayer,\n bridgeTx.exclusivityEndTime,\n // New V2 fields: Zap\n bridgeTx.zapNative,\n bridgeTx.zapData\n );\n }\n\n /// @notice Decodes the BridgeTransactionV2 struct from the encoded transaction.\n /// @dev Encoded BridgeTransactionV2 struct must be tightly packed.\n /// Use `validateV2` before decoding to ensure the encoded transaction is valid.\n function decodeV2(bytes calldata encodedTx)\n internal\n pure\n returns (IFastBridgeV2.BridgeTransactionV2 memory bridgeTx)\n {\n bridgeTx.originChainId = originChainId(encodedTx);\n bridgeTx.destChainId = destChainId(encodedTx);\n bridgeTx.originSender = originSender(encodedTx);\n bridgeTx.destRecipient = destRecipient(encodedTx);\n bridgeTx.originToken = originToken(encodedTx);\n bridgeTx.destToken = destToken(encodedTx);\n bridgeTx.originAmount = originAmount(encodedTx);\n bridgeTx.destAmount = destAmount(encodedTx);\n bridgeTx.originFeeAmount = originFeeAmount(encodedTx);\n bridgeTx.deadline = deadline(encodedTx);\n bridgeTx.nonce = nonce(encodedTx);\n bridgeTx.exclusivityRelayer = exclusivityRelayer(encodedTx);\n bridgeTx.exclusivityEndTime = exclusivityEndTime(encodedTx);\n bridgeTx.zapNative = zapNative(encodedTx);\n bridgeTx.zapData = zapData(encodedTx);\n }\n\n /// @notice Extracts the version from the encoded transaction.\n function version(bytes calldata encodedTx) internal pure returns (uint16 version_) {\n // Load 32 bytes from the start and shift it 240 bits to the right to get the highest 16 bits.\n assembly {\n version_ := shr(240, calldataload(encodedTx.offset))\n }\n }\n\n /// @notice Extracts the origin chain ID from the encoded transaction.\n function originChainId(bytes calldata encodedTx) internal pure returns (uint32 originChainId_) {\n // Load 32 bytes from the offset and shift it 224 bits to the right to get the highest 32 bits.\n assembly {\n originChainId_ := shr(224, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_CHAIN_ID)))\n }\n }\n\n /// @notice Extracts the destination chain ID from the encoded transaction.\n function destChainId(bytes calldata encodedTx) internal pure returns (uint32 destChainId_) {\n // Load 32 bytes from the offset and shift it 224 bits to the right to get the highest 32 bits.\n assembly {\n destChainId_ := shr(224, calldataload(add(encodedTx.offset, OFFSET_DEST_CHAIN_ID)))\n }\n }\n\n /// @notice Extracts the origin sender from the encoded transaction.\n function originSender(bytes calldata encodedTx) internal pure returns (address originSender_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n originSender_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_SENDER)))\n }\n }\n\n /// @notice Extracts the destination recipient from the encoded transaction.\n function destRecipient(bytes calldata encodedTx) internal pure returns (address destRecipient_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n destRecipient_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_DEST_RECIPIENT)))\n }\n }\n\n /// @notice Extracts the origin token from the encoded transaction.\n function originToken(bytes calldata encodedTx) internal pure returns (address originToken_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n originToken_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_TOKEN)))\n }\n }\n\n /// @notice Extracts the destination token from the encoded transaction.\n function destToken(bytes calldata encodedTx) internal pure returns (address destToken_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n destToken_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_DEST_TOKEN)))\n }\n }\n\n /// @notice Extracts the origin amount from the encoded transaction.\n function originAmount(bytes calldata encodedTx) internal pure returns (uint256 originAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n originAmount_ := calldataload(add(encodedTx.offset, OFFSET_ORIGIN_AMOUNT))\n }\n }\n\n /// @notice Extracts the destination amount from the encoded transaction.\n function destAmount(bytes calldata encodedTx) internal pure returns (uint256 destAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n destAmount_ := calldataload(add(encodedTx.offset, OFFSET_DEST_AMOUNT))\n }\n }\n\n /// @notice Extracts the origin fee amount from the encoded transaction.\n function originFeeAmount(bytes calldata encodedTx) internal pure returns (uint256 originFeeAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n originFeeAmount_ := calldataload(add(encodedTx.offset, OFFSET_ORIGIN_FEE_AMOUNT))\n }\n }\n\n /// @notice Extracts the deadline from the encoded transaction.\n function deadline(bytes calldata encodedTx) internal pure returns (uint256 deadline_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n deadline_ := calldataload(add(encodedTx.offset, OFFSET_DEADLINE))\n }\n }\n\n /// @notice Extracts the nonce from the encoded transaction.\n function nonce(bytes calldata encodedTx) internal pure returns (uint256 nonce_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n nonce_ := calldataload(add(encodedTx.offset, OFFSET_NONCE))\n }\n }\n\n /// @notice Extracts the exclusivity relayer from the encoded transaction.\n function exclusivityRelayer(bytes calldata encodedTx) internal pure returns (address exclusivityRelayer_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n exclusivityRelayer_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_EXCLUSIVITY_RELAYER)))\n }\n }\n\n /// @notice Extracts the exclusivity end time from the encoded transaction.\n function exclusivityEndTime(bytes calldata encodedTx) internal pure returns (uint256 exclusivityEndTime_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n exclusivityEndTime_ := calldataload(add(encodedTx.offset, OFFSET_EXCLUSIVITY_END_TIME))\n }\n }\n\n /// @notice Extracts the Zap's native value from the encoded transaction.\n function zapNative(bytes calldata encodedTx) internal pure returns (uint256 zapNative_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n zapNative_ := calldataload(add(encodedTx.offset, OFFSET_ZAP_NATIVE))\n }\n }\n\n /// @notice Extracts the Zap's data from the encoded transaction.\n function zapData(bytes calldata encodedTx) internal pure returns (bytes calldata zapData_) {\n zapData_ = encodedTx[OFFSET_ZAP_DATA:];\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// contracts/libs/UniversalToken.sol\n\nlibrary UniversalTokenLib {\n using SafeERC20 for IERC20;\n\n address internal constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Transfers tokens to the given account. Reverts if transfer is not successful.\n /// @dev This might trigger fallback, if ETH is transferred to the contract.\n /// Make sure this can not lead to reentrancy attacks.\n function universalTransfer(address token, address to, uint256 value) internal {\n // Don't do anything, if need to send tokens to this address\n if (to == address(this)) return;\n // Don't do anything, if trying to send zero value\n if (value == 0) return;\n if (token == ETH_ADDRESS) {\n /// @dev Note: this can potentially lead to executing code in `to`.\n // solhint-disable-next-line avoid-low-level-calls\n (bool success,) = to.call{value: value}(\"\");\n require(success, \"ETH transfer failed\");\n } else {\n IERC20(token).safeTransfer(to, value);\n }\n }\n\n /// @notice Issues an infinite allowance to the spender, if the current allowance is insufficient\n /// to spend the given amount.\n function universalApproveInfinity(address token, address spender, uint256 amountToSpend) internal {\n // ETH Chad doesn't require your approval\n if (token == ETH_ADDRESS) return;\n // No-op if allowance is already sufficient\n uint256 allowance = IERC20(token).allowance(address(this), spender);\n if (allowance \u003e= amountToSpend) return;\n // Otherwise, reset approval to 0 and set to max allowance\n if (allowance \u003e 0) IERC20(token).safeDecreaseAllowance(spender, allowance);\n IERC20(token).safeIncreaseAllowance(spender, type(uint256).max);\n }\n\n /// @notice Returns the balance of the given token (or native ETH) for the given account.\n function universalBalanceOf(address token, address account) internal view returns (uint256) {\n if (token == ETH_ADDRESS) {\n return account.balance;\n } else {\n return IERC20(token).balanceOf(account);\n }\n }\n\n /// @dev Checks that token is a contract and not ETH_ADDRESS.\n function assertIsContract(address token) internal view {\n // Check that ETH_ADDRESS was not used (in case this is a predeploy on any of the chains)\n if (token == UniversalTokenLib.ETH_ADDRESS) revert TokenNotContract();\n // Check that token is not an EOA\n if (token.code.length == 0) revert TokenNotContract();\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/Admin.sol\n\ncontract Admin is IAdmin, AccessControlEnumerable {\n using UniversalTokenLib for address;\n\n bytes32 public constant RELAYER_ROLE = keccak256(\"RELAYER_ROLE\");\n bytes32 public constant REFUNDER_ROLE = keccak256(\"REFUNDER_ROLE\");\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n uint256 public constant FEE_BPS = 1e6;\n uint256 public constant FEE_RATE_MAX = 0.01e6; // max 1% on origin amount\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Chain gas amount to forward as rebate if requested\n uint256 public chainGasAmount;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n }\n\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n require(newFeeRate \u003c= FEE_RATE_MAX, \"newFeeRate \u003e max\");\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n token.universalTransfer(recipient, feeAmount);\n emit FeesSwept(token, recipient, feeAmount);\n }\n\n function setChainGasAmount(uint256 newChainGasAmount) external onlyRole(GOVERNOR_ROLE) {\n uint256 oldChainGasAmount = chainGasAmount;\n chainGasAmount = newChainGasAmount;\n emit ChainGasAmountUpdated(oldChainGasAmount, newChainGasAmount);\n }\n}\n\n// contracts/FastBridgeV2.sol\n\n/// @notice FastBridgeV2 is a contract for bridging tokens across chains.\ncontract FastBridgeV2 is Admin, MulticallTarget, IFastBridgeV2, IFastBridgeV2Errors {\n using BridgeTransactionV2Lib for bytes;\n using SafeERC20 for IERC20;\n\n /// @notice Address reserved for native gas token (ETH on Ethereum and most L2s, AVAX on Avalanche, etc)\n address public constant NATIVE_GAS_TOKEN = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Delay for a transaction after which it could be permisionlessly refunded\n uint256 public constant REFUND_DELAY = 7 days;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n /// @notice Maximum length of accepted zapData\n uint256 public constant MAX_ZAP_DATA_LENGTH = 2 ** 16 - 1;\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeTxDetails) public bridgeTxDetails;\n /// @notice Relay details on destination chain\n mapping(bytes32 =\u003e BridgeRelay) public bridgeRelayDetails;\n /// @notice Unique bridge nonces tracked per originSender\n mapping(address =\u003e uint256) public senderNonces;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Replaced by senderNonces\n uint256 public immutable nonce = 0;\n /// @notice the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n bridge({\n params: params,\n paramsV2: BridgeParamsV2({\n quoteRelayer: address(0),\n quoteExclusivitySeconds: 0,\n quoteId: bytes(\"\"),\n zapNative: 0,\n zapData: bytes(\"\")\n })\n });\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes calldata request) external payable {\n // relay override will validate the request\n relay({request: request, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes calldata request, bytes32 destTxHash) external {\n request.validateV2();\n prove({transactionId: keccak256(request), destTxHash: destTxHash, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridgeV2\n function claim(bytes calldata request) external {\n // claim override will validate the request\n claim({request: request, to: address(0)});\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Aggregate the read operations from the same storage slot\n address disputedRelayer = $.proofRelayer;\n BridgeStatus status = $.status;\n uint56 proofBlockTimestamp = $.proofBlockTimestamp;\n // Can only dispute a RELAYER_PROVED transaction within the dispute period\n if (status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(proofBlockTimestamp) \u003e DISPUTE_PERIOD) {\n revert DisputePeriodPassed();\n }\n // Update status to REQUESTED and delete the disputed proof details\n // Note: these are storage writes\n $.status = BridgeStatus.REQUESTED;\n $.proofRelayer = address(0);\n $.proofBlockTimestamp = 0;\n\n emit BridgeProofDisputed(transactionId, disputedRelayer);\n }\n\n /// @inheritdoc IFastBridge\n function refund(bytes calldata request) external {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Can only refund a REQUESTED transaction after its deadline expires\n if ($.status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n uint256 deadline = request.deadline();\n // Permissionless refund is only allowed after REFUND_DELAY on top of the deadline\n if (!hasRole(REFUNDER_ROLE, msg.sender)) deadline += REFUND_DELAY;\n if (block.timestamp \u003c= deadline) revert DeadlineNotExceeded();\n // Update status to REFUNDED and return the full amount (collateral + protocol fees) to the original sender.\n // The protocol fees are only updated when the transaction is claimed, so we don't need to update them here.\n // Note: this is a storage write\n $.status = BridgeStatus.REFUNDED;\n\n address to = request.originSender();\n address token = request.originToken();\n uint256 amount = request.originAmount() + request.originFeeAmount();\n // Emit the event before any external calls\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n // Complete the user refund as the last transaction action\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(to), amount);\n } else {\n IERC20(token).safeTransfer(to, amount);\n }\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // The correct relayer can only claim a RELAYER_PROVED transaction after the dispute period\n if ($.status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if ($.proofRelayer != relayer) revert SenderIncorrect();\n return _timeSince($.proofBlockTimestamp) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n /// @dev This method is added to achieve backwards compatibility with decoding requests into V1 structs:\n /// - `zapNative` is partially reported as a zero/non-zero flag\n /// - `zapData` is ignored\n /// In order to process all kinds of requests use getBridgeTransactionV2 instead.\n function getBridgeTransaction(bytes calldata request) external view returns (BridgeTransaction memory) {\n // Try decoding into V2 struct first. This will revert if V1 struct is passed\n try this.getBridgeTransactionV2(request) returns (BridgeTransactionV2 memory txV2) {\n // Note: we entirely ignore the zapData field, as it was not present in V1\n return BridgeTransaction({\n originChainId: txV2.originChainId,\n destChainId: txV2.destChainId,\n originSender: txV2.originSender,\n destRecipient: txV2.destRecipient,\n originToken: txV2.originToken,\n destToken: txV2.destToken,\n originAmount: txV2.originAmount,\n destAmount: txV2.destAmount,\n originFeeAmount: txV2.originFeeAmount,\n sendChainGas: txV2.zapNative != 0,\n deadline: txV2.deadline,\n nonce: txV2.nonce\n });\n } catch {\n // Fallback to V1 struct\n return abi.decode(request, (BridgeTransaction));\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function getBridgeTransactionV2(bytes calldata request) external pure returns (BridgeTransactionV2 memory) {\n request.validateV2();\n return BridgeTransactionV2Lib.decodeV2(request);\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) public payable {\n int256 exclusivityEndTime = 0;\n // if relayer exclusivity is not intended for this bridge, set exclusivityEndTime to static zero\n // otherwise, set exclusivity to expire at the current block ts offset by quoteExclusivitySeconds\n if (paramsV2.quoteRelayer != address(0)) {\n exclusivityEndTime = int256(block.timestamp) + paramsV2.quoteExclusivitySeconds;\n }\n _validateBridgeParams(params, paramsV2, exclusivityEndTime);\n\n // transfer tokens to bridge contract\n /// @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _takeBridgedUserAsset(params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) {\n originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n }\n\n // set status to requested\n bytes memory request = BridgeTransactionV2Lib.encodeV2(\n BridgeTransactionV2({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n deadline: params.deadline,\n nonce: senderNonces[params.sender]++, // increment nonce on every bridge\n exclusivityRelayer: paramsV2.quoteRelayer,\n // We checked exclusivityEndTime to be in range [0 .. params.deadline] above, so can safely cast\n exclusivityEndTime: uint256(exclusivityEndTime),\n zapNative: paramsV2.zapNative,\n zapData: paramsV2.zapData\n })\n );\n bytes32 transactionId = keccak256(request);\n // Note: the tx status will be updated throughout the tx lifecycle, while destChainId is set once here\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n bridgeTxDetails[transactionId].destChainId = params.dstChainId;\n\n emit BridgeRequested({\n transactionId: transactionId,\n sender: params.sender,\n request: request,\n destChainId: params.dstChainId,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n sendChainGas: paramsV2.zapNative != 0\n });\n emit BridgeQuoteDetails(transactionId, paramsV2.quoteId);\n }\n\n /// @inheritdoc IFastBridgeV2\n function relay(bytes calldata request, address relayer) public payable {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n _validateRelayParams(request, transactionId, relayer);\n // mark bridge transaction as relayed\n bridgeRelayDetails[transactionId] =\n BridgeRelay({blockNumber: uint48(block.number), blockTimestamp: uint48(block.timestamp), relayer: relayer});\n\n // transfer tokens to recipient on destination chain and trigger Zap if requested\n address to = request.destRecipient();\n address token = request.destToken();\n uint256 amount = request.destAmount();\n uint256 zapNative = request.zapNative();\n\n // Emit the event before any external calls\n emit BridgeRelayed({\n transactionId: transactionId,\n relayer: relayer,\n to: to,\n originChainId: request.originChainId(),\n originToken: request.originToken(),\n destToken: token,\n originAmount: request.originAmount(),\n destAmount: amount,\n chainGasAmount: zapNative\n });\n\n // All state changes have been done at this point, can proceed to the external calls.\n // This follows the checks-effects-interactions pattern to mitigate potential reentrancy attacks.\n if (token == NATIVE_GAS_TOKEN) {\n // For the native gas token, additional zapNative is not allowed\n if (zapNative != 0) revert ZapNativeNotSupported();\n // Check that the correct msg.value was sent\n if (msg.value != amount) revert MsgValueIncorrect();\n // Don't do a native transfer yet: we will handle it alongside the Zap below\n } else {\n // For ERC20s, we check that the correct msg.value was sent\n if (msg.value != zapNative) revert MsgValueIncorrect();\n // We need to transfer the tokens from the Relayer to the recipient first before performing an\n // optional post-transfer Zap.\n IERC20(token).safeTransferFrom(msg.sender, to, amount);\n }\n // At this point we have done:\n // - Transferred the requested amount of ERC20 tokens to the recipient.\n // At this point we have confirmed:\n // - For ERC20s: msg.value matches the requested zapNative amount.\n // - For the native gas token: msg.value matches the requested destAmount.\n // Remaining optional things to do:\n // - Forward the full msg.value to the recipient (if non-zero).\n // - Trigger a Zap (if zapData is present).\n bytes calldata zapData = request.zapData();\n if (zapData.length != 0) {\n // Zap Data is present: Zap has been requested by the recipient. Trigger it forwarding the full msg.value.\n\n // Note: if token has a fee on transfers, the recipient will have received less than `amount`.\n // This is a very niche edge case and should be handled by the recipient contract.\n _triggerZapWithChecks({recipient: to, token: token, amount: amount, zapData: zapData});\n } else if (msg.value != 0) {\n // Zap Data is missing, but msg.value was sent. This could happen in two different cases:\n // - Relay with the native gas token is happening.\n // - Relay with ERC20 is happening, with a `zapNative \u003e 0` request.\n // In both cases, we need to transfer the full msg.value to the recipient.\n Address.sendValue(payable(to), msg.value);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) public onlyRole(RELAYER_ROLE) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n\n // Can only prove a REQUESTED transaction\n if ($.status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n // Update status to RELAYER_PROVED and store the proof details\n // Note: these are storage writes\n $.status = BridgeStatus.RELAYER_PROVED;\n $.proofBlockTimestamp = uint56(block.timestamp);\n $.proofRelayer = relayer;\n\n emit BridgeProofProvided(transactionId, relayer, destTxHash);\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes calldata request, address to) public {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Aggregate the read operations from the same storage slot\n address proofRelayer = $.proofRelayer;\n BridgeStatus status = $.status;\n uint56 proofBlockTimestamp = $.proofBlockTimestamp;\n\n // Can only claim a RELAYER_PROVED transaction after the dispute period\n if (status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(proofBlockTimestamp) \u003c= DISPUTE_PERIOD) {\n revert DisputePeriodNotPassed();\n }\n\n if (to == address(0)) {\n // Anyone could claim the funds to the proven relayer on their behalf\n to = proofRelayer;\n } else if (proofRelayer != msg.sender) {\n // Only the proven relayer could specify an address to claim the funds to\n revert SenderIncorrect();\n }\n\n // Update status to RELAYER_CLAIMED and transfer the origin collateral to the specified claim address\n // Note: this is a storage write\n $.status = BridgeStatus.RELAYER_CLAIMED;\n\n address token = request.originToken();\n uint256 amount = request.originAmount();\n // Update protocol fees if origin fee amount exists\n uint256 originFeeAmount = request.originFeeAmount();\n if (originFeeAmount \u003e 0) protocolFees[token] += originFeeAmount;\n // Emit the event before any external calls\n emit BridgeDepositClaimed(transactionId, proofRelayer, to, token, amount);\n // Complete the relayer claim as the last transaction action\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(to), amount);\n } else {\n IERC20(token).safeTransfer(to, amount);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeStatuses(bytes32 transactionId) public view returns (BridgeStatus status) {\n return bridgeTxDetails[transactionId].status;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeProofs(bytes32 transactionId) public view returns (uint96 timestamp, address relayer) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n\n timestamp = $.proofBlockTimestamp;\n relayer = $.proofRelayer;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeRelays(bytes32 transactionId) public view returns (bool) {\n // has this transactionId been relayed?\n return bridgeRelayDetails[transactionId].relayer != address(0);\n }\n\n /// @notice Takes the bridged asset from the user into FastBridgeV2 custody. It will be later\n /// claimed by the relayer who completed the relay on destination chain, or refunded back to the user,\n /// should no one complete the relay.\n function _takeBridgedUserAsset(address token, uint256 amount) internal returns (uint256 amountTaken) {\n if (token == NATIVE_GAS_TOKEN) {\n // For the native gas token, we just need to check that the supplied msg.value is correct.\n // Supplied `msg.value` is already in FastBridgeV2 custody.\n if (amount != msg.value) revert MsgValueIncorrect();\n amountTaken = msg.value;\n } else {\n // For ERC20s, token is explicitly transferred from the user to FastBridgeV2.\n // We don't allow non-zero `msg.value` to avoid extra funds from being stuck in FastBridgeV2.\n if (msg.value != 0) revert MsgValueIncorrect();\n // Throw an explicit error if the provided token address is not a contract\n if (token.code.length == 0) revert TokenNotContract();\n amountTaken = IERC20(token).balanceOf(address(this));\n IERC20(token).safeTransferFrom(msg.sender, address(this), amount);\n // Use the balance difference as the amount taken in case of fee on transfer tokens.\n amountTaken = IERC20(token).balanceOf(address(this)) - amountTaken;\n }\n }\n\n /// @notice Calls the Recipient's hook function with the specified zapData and performs\n /// all the necessary checks for the returned value.\n function _triggerZapWithChecks(address recipient, address token, uint256 amount, bytes calldata zapData) internal {\n // This will bubble any revert messages from the hook function\n bytes memory returnData = Address.functionCallWithValue({\n target: recipient,\n data: abi.encodeCall(IZapRecipient.zap, (token, amount, zapData)),\n // Note: see `relay()` for reasoning behind passing msg.value\n value: msg.value\n });\n // Explicit revert if no return data at all\n if (returnData.length == 0) revert RecipientNoReturnValue();\n // Check that exactly a single return value was returned\n if (returnData.length != 32) revert RecipientIncorrectReturnValue();\n // Return value should be abi-encoded hook function selector\n if (bytes32(returnData) != bytes32(IZapRecipient.zap.selector)) {\n revert RecipientIncorrectReturnValue();\n }\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint56(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint56).max but\n /// proof.timestamp \u003c type(uint56).max via unchecked statement\n /// @param proofBlockTimestamp The bridge proof block timestamp\n /// @return delta Time delta since proof submitted\n function _timeSince(uint56 proofBlockTimestamp) internal view returns (uint256 delta) {\n unchecked {\n delta = uint56(block.timestamp) - proofBlockTimestamp;\n }\n }\n\n /// @notice Performs all the necessary checks for a bridge to happen.\n /// @dev There's no good way to refactor this function to reduce cyclomatic complexity due to\n /// the number of checks that need to be performed, so we skip the code-complexity rule here.\n // solhint-disable-next-line code-complexity\n function _validateBridgeParams(\n BridgeParams memory params,\n BridgeParamsV2 memory paramsV2,\n int256 exclusivityEndTime\n )\n internal\n view\n {\n // Check V1 (legacy) params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.sender == address(0) || params.to == address(0)) revert ZeroAddress();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n // Check V2 params\n if (paramsV2.zapData.length \u003e MAX_ZAP_DATA_LENGTH) revert ZapDataLengthAboveMax();\n if (paramsV2.zapNative != 0 \u0026\u0026 params.destToken == NATIVE_GAS_TOKEN) {\n revert ZapNativeNotSupported();\n }\n // exclusivityEndTime must be in range [0 .. params.deadline]\n if (exclusivityEndTime \u003c 0 || exclusivityEndTime \u003e int256(params.deadline)) {\n revert ExclusivityParamsIncorrect();\n }\n }\n\n /// @notice Performs all the necessary checks for a relay to happen.\n function _validateRelayParams(bytes calldata request, bytes32 transactionId, address relayer) internal view {\n if (relayer == address(0)) revert ZeroAddress();\n // Check if the transaction has already been relayed\n if (bridgeRelays(transactionId)) revert TransactionRelayed();\n if (request.destChainId() != block.chainid) revert ChainIncorrect();\n // Check the deadline for relay to happen\n if (block.timestamp \u003e request.deadline()) revert DeadlineExceeded();\n // Check the exclusivity period, if it is still ongoing\n address exclRelayer = request.exclusivityRelayer();\n if (exclRelayer != address(0) \u0026\u0026 exclRelayer != relayer \u0026\u0026 block.timestamp \u003c= request.exclusivityEndTime()) {\n revert ExclusivityPeriodNotPassed();\n }\n }\n}\n","language":"Solidity","languageVersion":"0.8.24","compilerVersion":"0.8.24","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"","srcMapRuntime":"","abiDefinition":[{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"}],"userDoc":{"kind":"user","methods":{},"version":1},"developerDoc":{"details":"Interface of the ERC165 standard, as defined in the https://eips.ethereum.org/EIPS/eip-165[EIP]. Implementers can declare support of contract interfaces, which can then be queried by others ({ERC165Checker}). For an implementation, see {ERC165}.","kind":"dev","methods":{"supportsInterface(bytes4)":{"details":"Returns true if this contract implements the interface defined by `interfaceId`. See the corresponding https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section] to learn more about how these ids are created. This function call must use less than 30 000 gas."}},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"bytes4\",\"name\":\"interfaceId\",\"type\":\"bytes4\"}],\"name\":\"supportsInterface\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"}],\"devdoc\":{\"details\":\"Interface of the ERC165 standard, as defined in the https://eips.ethereum.org/EIPS/eip-165[EIP]. Implementers can declare support of contract interfaces, which can then be queried by others ({ERC165Checker}). For an implementation, see {ERC165}.\",\"kind\":\"dev\",\"methods\":{\"supportsInterface(bytes4)\":{\"details\":\"Returns true if this contract implements the interface defined by `interfaceId`. See the corresponding https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section] to learn more about how these ids are created. This function call must use less than 30 000 gas.\"}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeV2.sol\":\"IERC165\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeV2.sol\":{\"keccak256\":\"0x5069b55ca07f21bfe30b2a43c18a18318c8af9c181b2dcb07c290825efd70f34\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://273dc020a49d08e50126bbea0d7f783f79d08c702f2fdbc560618d24af308acc\",\"dweb:/ipfs/QmXJ2UVzFc8EPB74RT4CXQPC4xw66jt4T13poyfyd3UERh\"]}},\"version\":1}"},"hashes":{"supportsInterface(bytes4)":"01ffc9a7"}},"solidity/FastBridgeV2.sol:IERC20":{"code":"0x","runtime-code":"0x","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.24 ^0.8.20 ^0.8.4;\n\n// contracts/interfaces/IAdmin.sol\n\ninterface IAdmin {\n // ============ Events ============\n\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n event ChainGasAmountUpdated(uint256 oldChainGasAmount, uint256 newChainGasAmount);\n\n // ============ Methods ============\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n\n function setChainGasAmount(uint256 newChainGasAmount) external;\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IFastBridgeV2Errors.sol\n\ninterface IFastBridgeV2Errors {\n error AmountIncorrect();\n error ChainIncorrect();\n error ExclusivityParamsIncorrect();\n error MsgValueIncorrect();\n error SenderIncorrect();\n error StatusIncorrect();\n error TokenNotContract();\n error ZapDataLengthAboveMax();\n error ZapNativeNotSupported();\n error ZeroAddress();\n\n error RecipientIncorrectReturnValue();\n error RecipientNoReturnValue();\n\n error DeadlineExceeded();\n error DeadlineNotExceeded();\n error DeadlineTooShort();\n error DisputePeriodNotPassed();\n error DisputePeriodPassed();\n error ExclusivityPeriodNotPassed();\n\n error TransactionRelayed();\n}\n\n// contracts/interfaces/IMulticallTarget.sol\n\n/// @notice Interface for a contract that can be called multiple times by the same caller. Inspired by MulticallV3:\n/// https://github.com/mds1/multicall/blob/master/src/Multicall3.sol\ninterface IMulticallTarget {\n struct Result {\n bool success;\n bytes returnData;\n }\n\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external;\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results);\n}\n\n// contracts/interfaces/IZapRecipient.sol\n\ninterface IZapRecipient {\n function zap(address token, uint256 amount, bytes memory zapData) external payable returns (bytes4);\n}\n\n// contracts/libs/Errors.sol\n\nerror DeadlineExceeded();\nerror DeadlineNotExceeded();\nerror DeadlineTooShort();\nerror InsufficientOutputAmount();\n\nerror MsgValueIncorrect();\nerror PoolNotFound();\nerror TokenAddressMismatch();\nerror TokenNotContract();\nerror TokenNotETH();\nerror TokensIdentical();\n\nerror ChainIncorrect();\nerror AmountIncorrect();\nerror ZeroAddress();\n\nerror DisputePeriodNotPassed();\nerror DisputePeriodPassed();\nerror SenderIncorrect();\nerror StatusIncorrect();\nerror TransactionIdIncorrect();\nerror TransactionRelayed();\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// contracts/interfaces/IFastBridgeV2.sol\n\ninterface IFastBridgeV2 is IFastBridge {\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n struct BridgeTxDetails {\n BridgeStatus status;\n uint32 destChainId;\n uint56 proofBlockTimestamp;\n address proofRelayer;\n }\n\n struct BridgeRelay {\n uint48 blockNumber;\n uint48 blockTimestamp;\n address relayer;\n }\n\n /// @notice New params introduced in the FastBridgeV2.\n /// We are passing fields from the older BridgeParams struct outside of this struct\n /// for backwards compatibility.\n /// Note: quoteRelayer and quoteExclusivitySeconds are either both zero (indicating no exclusivity)\n /// or both non-zero (indicating exclusivity for the given period).\n /// Note: zapNative \u003e 0 can NOT be used with destToken = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE (native token)\n /// @param quoteRelayer Relayer that provided the quote for the transaction\n /// @param quoteExclusivitySeconds Period of time the quote relayer is guaranteed exclusivity after user's deposit\n /// @param quoteId Unique quote identifier used for tracking the quote\n /// @param zapNative ETH value to send to the recipient (if any)\n /// @param zapData Parameters for the Zap to the destination recipient (if any)\n struct BridgeParamsV2 {\n address quoteRelayer;\n int256 quoteExclusivitySeconds;\n bytes quoteId;\n uint256 zapNative;\n bytes zapData;\n }\n\n /// @notice Updated bridge transaction struct to include parameters introduced in FastBridgeV2.\n /// Note: only `exclusivityRelayer` can fill such a transaction until `exclusivityEndTime`.\n struct BridgeTransactionV2 {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n // Note: sendChainGas flag from V1 is deprecated\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n address exclusivityRelayer;\n uint256 exclusivityEndTime;\n uint256 zapNative; // ETH value to send to the recipient (if any)\n bytes zapData; // data to pass for the Zap action (if any)\n }\n\n event BridgeQuoteDetails(bytes32 indexed transactionId, bytes quoteId);\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability\n /// to provide temporary exclusivity fill rights for the quote relayer.\n /// @param params The parameters required to bridge\n /// @param paramsV2 The parameters for exclusivity fill rights (optional, can be left empty)\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function relay(bytes memory request, address relayer) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param transactionId The transaction id associated with the encoded bridge transaction to prove\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital.\n /// @notice Can only send funds to the relayer address on the proof.\n /// @param request The encoded bridge transaction to claim on origin chain\n function claim(bytes memory request) external;\n /// @notice Checks if a transaction has been relayed\n /// @param transactionId The ID of the transaction to check\n /// @return True if the transaction has been relayed, false otherwise\n function bridgeRelays(bytes32 transactionId) external view returns (bool);\n\n /// @notice Returns the status of a bridge transaction\n /// @param transactionId The ID of the bridge transaction\n /// @return BridgeStatus Status of the bridge transaction\n function bridgeStatuses(bytes32 transactionId) external view returns (BridgeStatus);\n\n /// @notice Returns the timestamp and relayer of a bridge proof\n /// @param transactionId The ID of the bridge transaction\n /// @return timestamp The timestamp of the bridge proof\n /// @return relayer The relayer address of the bridge proof\n function bridgeProofs(bytes32 transactionId) external view returns (uint96 timestamp, address relayer);\n\n /// @notice Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\n /// @param request The bridge request to decode\n function getBridgeTransactionV2(bytes memory request) external view returns (BridgeTransactionV2 memory);\n}\n\n// contracts/utils/MulticallTarget.sol\n\n// solhint-disable avoid-low-level-calls\n/// @notice Template for a contract that supports batched calls (preserving the msg.sender).\n/// Only calls with zero msg.value could be batched.\nabstract contract MulticallTarget is IMulticallTarget {\n error MulticallTarget__UndeterminedRevert();\n\n /// @notice Perform a batched call to this contract, preserving the msg.sender.\n /// The return data from each call is discarded.\n /// @dev The method is non-payable, so only calls with `msg.value == 0` could be batched.\n /// It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag.\n /// Otherwise, the whole batch call will be reverted with the original revert reason.\n /// @param data List of abi-encoded calldata for the calls to perform.\n /// @param ignoreReverts Whether to ignore the revert errors from the calls.\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external {\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\n if (!success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(result);\n }\n }\n }\n\n /// @notice Perform a batched call to this contract, preserving the msg.sender.\n /// The return data from each call is preserved.\n /// @dev The method is non-payable, so only calls with `msg.value == 0` could be batched.\n /// It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag.\n /// Otherwise, the whole batch call will be reverted with the original revert reason.\n /// @param data List of abi-encoded calldata for the calls to perform.\n /// @param ignoreReverts Whether to ignore the revert errors from the calls.\n /// @return results List of results from the calls: `(success, returnData)`.\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results)\n {\n results = new Result[](data.length);\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (results[i].success, results[i].returnData) = address(this).delegatecall(data[i]);\n if (!results[i].success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(results[i].returnData);\n }\n }\n }\n\n /// @dev Bubbles the revert message from the underlying call.\n /// Note: preserves the same custom error or revert string, if one was used.\n /// Source: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v5.0.2/contracts/utils/Address.sol#L143-L158\n function _bubbleRevert(bytes memory returnData) internal pure {\n // Look for revert reason and bubble it up if present\n if (returnData.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n // solhint-disable-next-line no-inline-assembly\n assembly {\n let returndata_size := mload(returnData)\n revert(add(32, returnData), returndata_size)\n }\n } else {\n revert MulticallTarget__UndeterminedRevert();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// contracts/libs/BridgeTransactionV2.sol\n\n// solhint-disable no-inline-assembly\nlibrary BridgeTransactionV2Lib {\n uint16 internal constant VERSION = 2;\n\n // Offsets of the fields in the packed BridgeTransactionV2 struct\n // uint16 version [000 .. 002)\n // uint32 originChainId [002 .. 006)\n // uint32 destChainId [006 .. 010)\n // address originSender [010 .. 030)\n // address destRecipient [030 .. 050)\n // address originToken [050 .. 070)\n // address destToken [070 .. 090)\n // uint256 originAmount [090 .. 122)\n // uint256 destAmount [122 .. 154)\n // uint256 originFeeAmount [154 .. 186)\n // uint256 deadline [186 .. 218)\n // uint256 nonce [218 .. 250)\n // address exclusivityRelayer [250 .. 270)\n // uint256 exclusivityEndTime [270 .. 302)\n // uint256 zapNative [302 .. 334)\n // bytes zapData [334 .. ***)\n\n // forgefmt: disable-start\n uint256 private constant OFFSET_ORIGIN_CHAIN_ID = 2;\n uint256 private constant OFFSET_DEST_CHAIN_ID = 6;\n uint256 private constant OFFSET_ORIGIN_SENDER = 10;\n uint256 private constant OFFSET_DEST_RECIPIENT = 30;\n uint256 private constant OFFSET_ORIGIN_TOKEN = 50;\n uint256 private constant OFFSET_DEST_TOKEN = 70;\n uint256 private constant OFFSET_ORIGIN_AMOUNT = 90;\n uint256 private constant OFFSET_DEST_AMOUNT = 122;\n uint256 private constant OFFSET_ORIGIN_FEE_AMOUNT = 154;\n uint256 private constant OFFSET_DEADLINE = 186;\n uint256 private constant OFFSET_NONCE = 218;\n uint256 private constant OFFSET_EXCLUSIVITY_RELAYER = 250;\n uint256 private constant OFFSET_EXCLUSIVITY_END_TIME = 270;\n uint256 private constant OFFSET_ZAP_NATIVE = 302;\n uint256 private constant OFFSET_ZAP_DATA = 334;\n // forgefmt: disable-end\n\n error BridgeTransactionV2__InvalidEncodedTx();\n error BridgeTransactionV2__UnsupportedVersion(uint16 version);\n\n /// @notice Validates the encoded transaction to be a tightly packed encoded payload for BridgeTransactionV2.\n /// @dev Checks the minimum length and the version, use this function before decoding any of the fields.\n function validateV2(bytes calldata encodedTx) internal pure {\n // Check the minimum length: must at least include all static fields.\n if (encodedTx.length \u003c OFFSET_ZAP_DATA) revert BridgeTransactionV2__InvalidEncodedTx();\n // Once we validated the length, we can be sure that the version field is present.\n uint16 version_ = version(encodedTx);\n if (version_ != VERSION) revert BridgeTransactionV2__UnsupportedVersion(version_);\n }\n\n /// @notice Encodes the BridgeTransactionV2 struct by tightly packing the fields.\n /// @dev `abi.decode` will not work as a result of the tightly packed fields. Use `decodeV2` to decode instead.\n function encodeV2(IFastBridgeV2.BridgeTransactionV2 memory bridgeTx) internal pure returns (bytes memory) {\n // We split the encoding into two parts to avoid stack-too-deep error\n bytes memory firstPart = abi.encodePacked(\n VERSION,\n bridgeTx.originChainId,\n bridgeTx.destChainId,\n bridgeTx.originSender,\n bridgeTx.destRecipient,\n bridgeTx.originToken,\n bridgeTx.destToken,\n bridgeTx.originAmount\n );\n return abi.encodePacked(\n firstPart,\n bridgeTx.destAmount,\n bridgeTx.originFeeAmount,\n // Note: we skip the deprecated `sendChainGas` flag, which was present in BridgeTransaction V1\n bridgeTx.deadline,\n bridgeTx.nonce,\n // New V2 fields: exclusivity\n bridgeTx.exclusivityRelayer,\n bridgeTx.exclusivityEndTime,\n // New V2 fields: Zap\n bridgeTx.zapNative,\n bridgeTx.zapData\n );\n }\n\n /// @notice Decodes the BridgeTransactionV2 struct from the encoded transaction.\n /// @dev Encoded BridgeTransactionV2 struct must be tightly packed.\n /// Use `validateV2` before decoding to ensure the encoded transaction is valid.\n function decodeV2(bytes calldata encodedTx)\n internal\n pure\n returns (IFastBridgeV2.BridgeTransactionV2 memory bridgeTx)\n {\n bridgeTx.originChainId = originChainId(encodedTx);\n bridgeTx.destChainId = destChainId(encodedTx);\n bridgeTx.originSender = originSender(encodedTx);\n bridgeTx.destRecipient = destRecipient(encodedTx);\n bridgeTx.originToken = originToken(encodedTx);\n bridgeTx.destToken = destToken(encodedTx);\n bridgeTx.originAmount = originAmount(encodedTx);\n bridgeTx.destAmount = destAmount(encodedTx);\n bridgeTx.originFeeAmount = originFeeAmount(encodedTx);\n bridgeTx.deadline = deadline(encodedTx);\n bridgeTx.nonce = nonce(encodedTx);\n bridgeTx.exclusivityRelayer = exclusivityRelayer(encodedTx);\n bridgeTx.exclusivityEndTime = exclusivityEndTime(encodedTx);\n bridgeTx.zapNative = zapNative(encodedTx);\n bridgeTx.zapData = zapData(encodedTx);\n }\n\n /// @notice Extracts the version from the encoded transaction.\n function version(bytes calldata encodedTx) internal pure returns (uint16 version_) {\n // Load 32 bytes from the start and shift it 240 bits to the right to get the highest 16 bits.\n assembly {\n version_ := shr(240, calldataload(encodedTx.offset))\n }\n }\n\n /// @notice Extracts the origin chain ID from the encoded transaction.\n function originChainId(bytes calldata encodedTx) internal pure returns (uint32 originChainId_) {\n // Load 32 bytes from the offset and shift it 224 bits to the right to get the highest 32 bits.\n assembly {\n originChainId_ := shr(224, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_CHAIN_ID)))\n }\n }\n\n /// @notice Extracts the destination chain ID from the encoded transaction.\n function destChainId(bytes calldata encodedTx) internal pure returns (uint32 destChainId_) {\n // Load 32 bytes from the offset and shift it 224 bits to the right to get the highest 32 bits.\n assembly {\n destChainId_ := shr(224, calldataload(add(encodedTx.offset, OFFSET_DEST_CHAIN_ID)))\n }\n }\n\n /// @notice Extracts the origin sender from the encoded transaction.\n function originSender(bytes calldata encodedTx) internal pure returns (address originSender_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n originSender_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_SENDER)))\n }\n }\n\n /// @notice Extracts the destination recipient from the encoded transaction.\n function destRecipient(bytes calldata encodedTx) internal pure returns (address destRecipient_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n destRecipient_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_DEST_RECIPIENT)))\n }\n }\n\n /// @notice Extracts the origin token from the encoded transaction.\n function originToken(bytes calldata encodedTx) internal pure returns (address originToken_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n originToken_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_TOKEN)))\n }\n }\n\n /// @notice Extracts the destination token from the encoded transaction.\n function destToken(bytes calldata encodedTx) internal pure returns (address destToken_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n destToken_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_DEST_TOKEN)))\n }\n }\n\n /// @notice Extracts the origin amount from the encoded transaction.\n function originAmount(bytes calldata encodedTx) internal pure returns (uint256 originAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n originAmount_ := calldataload(add(encodedTx.offset, OFFSET_ORIGIN_AMOUNT))\n }\n }\n\n /// @notice Extracts the destination amount from the encoded transaction.\n function destAmount(bytes calldata encodedTx) internal pure returns (uint256 destAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n destAmount_ := calldataload(add(encodedTx.offset, OFFSET_DEST_AMOUNT))\n }\n }\n\n /// @notice Extracts the origin fee amount from the encoded transaction.\n function originFeeAmount(bytes calldata encodedTx) internal pure returns (uint256 originFeeAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n originFeeAmount_ := calldataload(add(encodedTx.offset, OFFSET_ORIGIN_FEE_AMOUNT))\n }\n }\n\n /// @notice Extracts the deadline from the encoded transaction.\n function deadline(bytes calldata encodedTx) internal pure returns (uint256 deadline_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n deadline_ := calldataload(add(encodedTx.offset, OFFSET_DEADLINE))\n }\n }\n\n /// @notice Extracts the nonce from the encoded transaction.\n function nonce(bytes calldata encodedTx) internal pure returns (uint256 nonce_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n nonce_ := calldataload(add(encodedTx.offset, OFFSET_NONCE))\n }\n }\n\n /// @notice Extracts the exclusivity relayer from the encoded transaction.\n function exclusivityRelayer(bytes calldata encodedTx) internal pure returns (address exclusivityRelayer_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n exclusivityRelayer_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_EXCLUSIVITY_RELAYER)))\n }\n }\n\n /// @notice Extracts the exclusivity end time from the encoded transaction.\n function exclusivityEndTime(bytes calldata encodedTx) internal pure returns (uint256 exclusivityEndTime_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n exclusivityEndTime_ := calldataload(add(encodedTx.offset, OFFSET_EXCLUSIVITY_END_TIME))\n }\n }\n\n /// @notice Extracts the Zap's native value from the encoded transaction.\n function zapNative(bytes calldata encodedTx) internal pure returns (uint256 zapNative_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n zapNative_ := calldataload(add(encodedTx.offset, OFFSET_ZAP_NATIVE))\n }\n }\n\n /// @notice Extracts the Zap's data from the encoded transaction.\n function zapData(bytes calldata encodedTx) internal pure returns (bytes calldata zapData_) {\n zapData_ = encodedTx[OFFSET_ZAP_DATA:];\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// contracts/libs/UniversalToken.sol\n\nlibrary UniversalTokenLib {\n using SafeERC20 for IERC20;\n\n address internal constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Transfers tokens to the given account. Reverts if transfer is not successful.\n /// @dev This might trigger fallback, if ETH is transferred to the contract.\n /// Make sure this can not lead to reentrancy attacks.\n function universalTransfer(address token, address to, uint256 value) internal {\n // Don't do anything, if need to send tokens to this address\n if (to == address(this)) return;\n // Don't do anything, if trying to send zero value\n if (value == 0) return;\n if (token == ETH_ADDRESS) {\n /// @dev Note: this can potentially lead to executing code in `to`.\n // solhint-disable-next-line avoid-low-level-calls\n (bool success,) = to.call{value: value}(\"\");\n require(success, \"ETH transfer failed\");\n } else {\n IERC20(token).safeTransfer(to, value);\n }\n }\n\n /// @notice Issues an infinite allowance to the spender, if the current allowance is insufficient\n /// to spend the given amount.\n function universalApproveInfinity(address token, address spender, uint256 amountToSpend) internal {\n // ETH Chad doesn't require your approval\n if (token == ETH_ADDRESS) return;\n // No-op if allowance is already sufficient\n uint256 allowance = IERC20(token).allowance(address(this), spender);\n if (allowance \u003e= amountToSpend) return;\n // Otherwise, reset approval to 0 and set to max allowance\n if (allowance \u003e 0) IERC20(token).safeDecreaseAllowance(spender, allowance);\n IERC20(token).safeIncreaseAllowance(spender, type(uint256).max);\n }\n\n /// @notice Returns the balance of the given token (or native ETH) for the given account.\n function universalBalanceOf(address token, address account) internal view returns (uint256) {\n if (token == ETH_ADDRESS) {\n return account.balance;\n } else {\n return IERC20(token).balanceOf(account);\n }\n }\n\n /// @dev Checks that token is a contract and not ETH_ADDRESS.\n function assertIsContract(address token) internal view {\n // Check that ETH_ADDRESS was not used (in case this is a predeploy on any of the chains)\n if (token == UniversalTokenLib.ETH_ADDRESS) revert TokenNotContract();\n // Check that token is not an EOA\n if (token.code.length == 0) revert TokenNotContract();\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/Admin.sol\n\ncontract Admin is IAdmin, AccessControlEnumerable {\n using UniversalTokenLib for address;\n\n bytes32 public constant RELAYER_ROLE = keccak256(\"RELAYER_ROLE\");\n bytes32 public constant REFUNDER_ROLE = keccak256(\"REFUNDER_ROLE\");\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n uint256 public constant FEE_BPS = 1e6;\n uint256 public constant FEE_RATE_MAX = 0.01e6; // max 1% on origin amount\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Chain gas amount to forward as rebate if requested\n uint256 public chainGasAmount;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n }\n\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n require(newFeeRate \u003c= FEE_RATE_MAX, \"newFeeRate \u003e max\");\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n token.universalTransfer(recipient, feeAmount);\n emit FeesSwept(token, recipient, feeAmount);\n }\n\n function setChainGasAmount(uint256 newChainGasAmount) external onlyRole(GOVERNOR_ROLE) {\n uint256 oldChainGasAmount = chainGasAmount;\n chainGasAmount = newChainGasAmount;\n emit ChainGasAmountUpdated(oldChainGasAmount, newChainGasAmount);\n }\n}\n\n// contracts/FastBridgeV2.sol\n\n/// @notice FastBridgeV2 is a contract for bridging tokens across chains.\ncontract FastBridgeV2 is Admin, MulticallTarget, IFastBridgeV2, IFastBridgeV2Errors {\n using BridgeTransactionV2Lib for bytes;\n using SafeERC20 for IERC20;\n\n /// @notice Address reserved for native gas token (ETH on Ethereum and most L2s, AVAX on Avalanche, etc)\n address public constant NATIVE_GAS_TOKEN = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Delay for a transaction after which it could be permisionlessly refunded\n uint256 public constant REFUND_DELAY = 7 days;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n /// @notice Maximum length of accepted zapData\n uint256 public constant MAX_ZAP_DATA_LENGTH = 2 ** 16 - 1;\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeTxDetails) public bridgeTxDetails;\n /// @notice Relay details on destination chain\n mapping(bytes32 =\u003e BridgeRelay) public bridgeRelayDetails;\n /// @notice Unique bridge nonces tracked per originSender\n mapping(address =\u003e uint256) public senderNonces;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Replaced by senderNonces\n uint256 public immutable nonce = 0;\n /// @notice the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n bridge({\n params: params,\n paramsV2: BridgeParamsV2({\n quoteRelayer: address(0),\n quoteExclusivitySeconds: 0,\n quoteId: bytes(\"\"),\n zapNative: 0,\n zapData: bytes(\"\")\n })\n });\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes calldata request) external payable {\n // relay override will validate the request\n relay({request: request, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes calldata request, bytes32 destTxHash) external {\n request.validateV2();\n prove({transactionId: keccak256(request), destTxHash: destTxHash, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridgeV2\n function claim(bytes calldata request) external {\n // claim override will validate the request\n claim({request: request, to: address(0)});\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Aggregate the read operations from the same storage slot\n address disputedRelayer = $.proofRelayer;\n BridgeStatus status = $.status;\n uint56 proofBlockTimestamp = $.proofBlockTimestamp;\n // Can only dispute a RELAYER_PROVED transaction within the dispute period\n if (status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(proofBlockTimestamp) \u003e DISPUTE_PERIOD) {\n revert DisputePeriodPassed();\n }\n // Update status to REQUESTED and delete the disputed proof details\n // Note: these are storage writes\n $.status = BridgeStatus.REQUESTED;\n $.proofRelayer = address(0);\n $.proofBlockTimestamp = 0;\n\n emit BridgeProofDisputed(transactionId, disputedRelayer);\n }\n\n /// @inheritdoc IFastBridge\n function refund(bytes calldata request) external {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Can only refund a REQUESTED transaction after its deadline expires\n if ($.status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n uint256 deadline = request.deadline();\n // Permissionless refund is only allowed after REFUND_DELAY on top of the deadline\n if (!hasRole(REFUNDER_ROLE, msg.sender)) deadline += REFUND_DELAY;\n if (block.timestamp \u003c= deadline) revert DeadlineNotExceeded();\n // Update status to REFUNDED and return the full amount (collateral + protocol fees) to the original sender.\n // The protocol fees are only updated when the transaction is claimed, so we don't need to update them here.\n // Note: this is a storage write\n $.status = BridgeStatus.REFUNDED;\n\n address to = request.originSender();\n address token = request.originToken();\n uint256 amount = request.originAmount() + request.originFeeAmount();\n // Emit the event before any external calls\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n // Complete the user refund as the last transaction action\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(to), amount);\n } else {\n IERC20(token).safeTransfer(to, amount);\n }\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // The correct relayer can only claim a RELAYER_PROVED transaction after the dispute period\n if ($.status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if ($.proofRelayer != relayer) revert SenderIncorrect();\n return _timeSince($.proofBlockTimestamp) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n /// @dev This method is added to achieve backwards compatibility with decoding requests into V1 structs:\n /// - `zapNative` is partially reported as a zero/non-zero flag\n /// - `zapData` is ignored\n /// In order to process all kinds of requests use getBridgeTransactionV2 instead.\n function getBridgeTransaction(bytes calldata request) external view returns (BridgeTransaction memory) {\n // Try decoding into V2 struct first. This will revert if V1 struct is passed\n try this.getBridgeTransactionV2(request) returns (BridgeTransactionV2 memory txV2) {\n // Note: we entirely ignore the zapData field, as it was not present in V1\n return BridgeTransaction({\n originChainId: txV2.originChainId,\n destChainId: txV2.destChainId,\n originSender: txV2.originSender,\n destRecipient: txV2.destRecipient,\n originToken: txV2.originToken,\n destToken: txV2.destToken,\n originAmount: txV2.originAmount,\n destAmount: txV2.destAmount,\n originFeeAmount: txV2.originFeeAmount,\n sendChainGas: txV2.zapNative != 0,\n deadline: txV2.deadline,\n nonce: txV2.nonce\n });\n } catch {\n // Fallback to V1 struct\n return abi.decode(request, (BridgeTransaction));\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function getBridgeTransactionV2(bytes calldata request) external pure returns (BridgeTransactionV2 memory) {\n request.validateV2();\n return BridgeTransactionV2Lib.decodeV2(request);\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) public payable {\n int256 exclusivityEndTime = 0;\n // if relayer exclusivity is not intended for this bridge, set exclusivityEndTime to static zero\n // otherwise, set exclusivity to expire at the current block ts offset by quoteExclusivitySeconds\n if (paramsV2.quoteRelayer != address(0)) {\n exclusivityEndTime = int256(block.timestamp) + paramsV2.quoteExclusivitySeconds;\n }\n _validateBridgeParams(params, paramsV2, exclusivityEndTime);\n\n // transfer tokens to bridge contract\n /// @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _takeBridgedUserAsset(params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) {\n originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n }\n\n // set status to requested\n bytes memory request = BridgeTransactionV2Lib.encodeV2(\n BridgeTransactionV2({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n deadline: params.deadline,\n nonce: senderNonces[params.sender]++, // increment nonce on every bridge\n exclusivityRelayer: paramsV2.quoteRelayer,\n // We checked exclusivityEndTime to be in range [0 .. params.deadline] above, so can safely cast\n exclusivityEndTime: uint256(exclusivityEndTime),\n zapNative: paramsV2.zapNative,\n zapData: paramsV2.zapData\n })\n );\n bytes32 transactionId = keccak256(request);\n // Note: the tx status will be updated throughout the tx lifecycle, while destChainId is set once here\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n bridgeTxDetails[transactionId].destChainId = params.dstChainId;\n\n emit BridgeRequested({\n transactionId: transactionId,\n sender: params.sender,\n request: request,\n destChainId: params.dstChainId,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n sendChainGas: paramsV2.zapNative != 0\n });\n emit BridgeQuoteDetails(transactionId, paramsV2.quoteId);\n }\n\n /// @inheritdoc IFastBridgeV2\n function relay(bytes calldata request, address relayer) public payable {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n _validateRelayParams(request, transactionId, relayer);\n // mark bridge transaction as relayed\n bridgeRelayDetails[transactionId] =\n BridgeRelay({blockNumber: uint48(block.number), blockTimestamp: uint48(block.timestamp), relayer: relayer});\n\n // transfer tokens to recipient on destination chain and trigger Zap if requested\n address to = request.destRecipient();\n address token = request.destToken();\n uint256 amount = request.destAmount();\n uint256 zapNative = request.zapNative();\n\n // Emit the event before any external calls\n emit BridgeRelayed({\n transactionId: transactionId,\n relayer: relayer,\n to: to,\n originChainId: request.originChainId(),\n originToken: request.originToken(),\n destToken: token,\n originAmount: request.originAmount(),\n destAmount: amount,\n chainGasAmount: zapNative\n });\n\n // All state changes have been done at this point, can proceed to the external calls.\n // This follows the checks-effects-interactions pattern to mitigate potential reentrancy attacks.\n if (token == NATIVE_GAS_TOKEN) {\n // For the native gas token, additional zapNative is not allowed\n if (zapNative != 0) revert ZapNativeNotSupported();\n // Check that the correct msg.value was sent\n if (msg.value != amount) revert MsgValueIncorrect();\n // Don't do a native transfer yet: we will handle it alongside the Zap below\n } else {\n // For ERC20s, we check that the correct msg.value was sent\n if (msg.value != zapNative) revert MsgValueIncorrect();\n // We need to transfer the tokens from the Relayer to the recipient first before performing an\n // optional post-transfer Zap.\n IERC20(token).safeTransferFrom(msg.sender, to, amount);\n }\n // At this point we have done:\n // - Transferred the requested amount of ERC20 tokens to the recipient.\n // At this point we have confirmed:\n // - For ERC20s: msg.value matches the requested zapNative amount.\n // - For the native gas token: msg.value matches the requested destAmount.\n // Remaining optional things to do:\n // - Forward the full msg.value to the recipient (if non-zero).\n // - Trigger a Zap (if zapData is present).\n bytes calldata zapData = request.zapData();\n if (zapData.length != 0) {\n // Zap Data is present: Zap has been requested by the recipient. Trigger it forwarding the full msg.value.\n\n // Note: if token has a fee on transfers, the recipient will have received less than `amount`.\n // This is a very niche edge case and should be handled by the recipient contract.\n _triggerZapWithChecks({recipient: to, token: token, amount: amount, zapData: zapData});\n } else if (msg.value != 0) {\n // Zap Data is missing, but msg.value was sent. This could happen in two different cases:\n // - Relay with the native gas token is happening.\n // - Relay with ERC20 is happening, with a `zapNative \u003e 0` request.\n // In both cases, we need to transfer the full msg.value to the recipient.\n Address.sendValue(payable(to), msg.value);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) public onlyRole(RELAYER_ROLE) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n\n // Can only prove a REQUESTED transaction\n if ($.status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n // Update status to RELAYER_PROVED and store the proof details\n // Note: these are storage writes\n $.status = BridgeStatus.RELAYER_PROVED;\n $.proofBlockTimestamp = uint56(block.timestamp);\n $.proofRelayer = relayer;\n\n emit BridgeProofProvided(transactionId, relayer, destTxHash);\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes calldata request, address to) public {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Aggregate the read operations from the same storage slot\n address proofRelayer = $.proofRelayer;\n BridgeStatus status = $.status;\n uint56 proofBlockTimestamp = $.proofBlockTimestamp;\n\n // Can only claim a RELAYER_PROVED transaction after the dispute period\n if (status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(proofBlockTimestamp) \u003c= DISPUTE_PERIOD) {\n revert DisputePeriodNotPassed();\n }\n\n if (to == address(0)) {\n // Anyone could claim the funds to the proven relayer on their behalf\n to = proofRelayer;\n } else if (proofRelayer != msg.sender) {\n // Only the proven relayer could specify an address to claim the funds to\n revert SenderIncorrect();\n }\n\n // Update status to RELAYER_CLAIMED and transfer the origin collateral to the specified claim address\n // Note: this is a storage write\n $.status = BridgeStatus.RELAYER_CLAIMED;\n\n address token = request.originToken();\n uint256 amount = request.originAmount();\n // Update protocol fees if origin fee amount exists\n uint256 originFeeAmount = request.originFeeAmount();\n if (originFeeAmount \u003e 0) protocolFees[token] += originFeeAmount;\n // Emit the event before any external calls\n emit BridgeDepositClaimed(transactionId, proofRelayer, to, token, amount);\n // Complete the relayer claim as the last transaction action\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(to), amount);\n } else {\n IERC20(token).safeTransfer(to, amount);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeStatuses(bytes32 transactionId) public view returns (BridgeStatus status) {\n return bridgeTxDetails[transactionId].status;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeProofs(bytes32 transactionId) public view returns (uint96 timestamp, address relayer) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n\n timestamp = $.proofBlockTimestamp;\n relayer = $.proofRelayer;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeRelays(bytes32 transactionId) public view returns (bool) {\n // has this transactionId been relayed?\n return bridgeRelayDetails[transactionId].relayer != address(0);\n }\n\n /// @notice Takes the bridged asset from the user into FastBridgeV2 custody. It will be later\n /// claimed by the relayer who completed the relay on destination chain, or refunded back to the user,\n /// should no one complete the relay.\n function _takeBridgedUserAsset(address token, uint256 amount) internal returns (uint256 amountTaken) {\n if (token == NATIVE_GAS_TOKEN) {\n // For the native gas token, we just need to check that the supplied msg.value is correct.\n // Supplied `msg.value` is already in FastBridgeV2 custody.\n if (amount != msg.value) revert MsgValueIncorrect();\n amountTaken = msg.value;\n } else {\n // For ERC20s, token is explicitly transferred from the user to FastBridgeV2.\n // We don't allow non-zero `msg.value` to avoid extra funds from being stuck in FastBridgeV2.\n if (msg.value != 0) revert MsgValueIncorrect();\n // Throw an explicit error if the provided token address is not a contract\n if (token.code.length == 0) revert TokenNotContract();\n amountTaken = IERC20(token).balanceOf(address(this));\n IERC20(token).safeTransferFrom(msg.sender, address(this), amount);\n // Use the balance difference as the amount taken in case of fee on transfer tokens.\n amountTaken = IERC20(token).balanceOf(address(this)) - amountTaken;\n }\n }\n\n /// @notice Calls the Recipient's hook function with the specified zapData and performs\n /// all the necessary checks for the returned value.\n function _triggerZapWithChecks(address recipient, address token, uint256 amount, bytes calldata zapData) internal {\n // This will bubble any revert messages from the hook function\n bytes memory returnData = Address.functionCallWithValue({\n target: recipient,\n data: abi.encodeCall(IZapRecipient.zap, (token, amount, zapData)),\n // Note: see `relay()` for reasoning behind passing msg.value\n value: msg.value\n });\n // Explicit revert if no return data at all\n if (returnData.length == 0) revert RecipientNoReturnValue();\n // Check that exactly a single return value was returned\n if (returnData.length != 32) revert RecipientIncorrectReturnValue();\n // Return value should be abi-encoded hook function selector\n if (bytes32(returnData) != bytes32(IZapRecipient.zap.selector)) {\n revert RecipientIncorrectReturnValue();\n }\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint56(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint56).max but\n /// proof.timestamp \u003c type(uint56).max via unchecked statement\n /// @param proofBlockTimestamp The bridge proof block timestamp\n /// @return delta Time delta since proof submitted\n function _timeSince(uint56 proofBlockTimestamp) internal view returns (uint256 delta) {\n unchecked {\n delta = uint56(block.timestamp) - proofBlockTimestamp;\n }\n }\n\n /// @notice Performs all the necessary checks for a bridge to happen.\n /// @dev There's no good way to refactor this function to reduce cyclomatic complexity due to\n /// the number of checks that need to be performed, so we skip the code-complexity rule here.\n // solhint-disable-next-line code-complexity\n function _validateBridgeParams(\n BridgeParams memory params,\n BridgeParamsV2 memory paramsV2,\n int256 exclusivityEndTime\n )\n internal\n view\n {\n // Check V1 (legacy) params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.sender == address(0) || params.to == address(0)) revert ZeroAddress();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n // Check V2 params\n if (paramsV2.zapData.length \u003e MAX_ZAP_DATA_LENGTH) revert ZapDataLengthAboveMax();\n if (paramsV2.zapNative != 0 \u0026\u0026 params.destToken == NATIVE_GAS_TOKEN) {\n revert ZapNativeNotSupported();\n }\n // exclusivityEndTime must be in range [0 .. params.deadline]\n if (exclusivityEndTime \u003c 0 || exclusivityEndTime \u003e int256(params.deadline)) {\n revert ExclusivityParamsIncorrect();\n }\n }\n\n /// @notice Performs all the necessary checks for a relay to happen.\n function _validateRelayParams(bytes calldata request, bytes32 transactionId, address relayer) internal view {\n if (relayer == address(0)) revert ZeroAddress();\n // Check if the transaction has already been relayed\n if (bridgeRelays(transactionId)) revert TransactionRelayed();\n if (request.destChainId() != block.chainid) revert ChainIncorrect();\n // Check the deadline for relay to happen\n if (block.timestamp \u003e request.deadline()) revert DeadlineExceeded();\n // Check the exclusivity period, if it is still ongoing\n address exclRelayer = request.exclusivityRelayer();\n if (exclRelayer != address(0) \u0026\u0026 exclRelayer != relayer \u0026\u0026 block.timestamp \u003c= request.exclusivityEndTime()) {\n revert ExclusivityPeriodNotPassed();\n }\n }\n}\n","language":"Solidity","languageVersion":"0.8.24","compilerVersion":"0.8.24","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"","srcMapRuntime":"","abiDefinition":[{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Transfer","type":"event"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"}],"userDoc":{"kind":"user","methods":{},"version":1},"developerDoc":{"details":"Interface of the ERC20 standard as defined in the EIP.","events":{"Approval(address,address,uint256)":{"details":"Emitted when the allowance of a `spender` for an `owner` is set by a call to {approve}. `value` is the new allowance."},"Transfer(address,address,uint256)":{"details":"Emitted when `value` tokens are moved from one account (`from`) to another (`to`). Note that `value` may be zero."}},"kind":"dev","methods":{"allowance(address,address)":{"details":"Returns the remaining number of tokens that `spender` will be allowed to spend on behalf of `owner` through {transferFrom}. This is zero by default. This value changes when {approve} or {transferFrom} are called."},"approve(address,uint256)":{"details":"Sets a `value` amount of tokens as the allowance of `spender` over the caller's tokens. Returns a boolean value indicating whether the operation succeeded. IMPORTANT: Beware that changing an allowance with this method brings the risk that someone may use both the old and the new allowance by unfortunate transaction ordering. One possible solution to mitigate this race condition is to first reduce the spender's allowance to 0 and set the desired value afterwards: https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 Emits an {Approval} event."},"balanceOf(address)":{"details":"Returns the value of tokens owned by `account`."},"totalSupply()":{"details":"Returns the value of tokens in existence."},"transfer(address,uint256)":{"details":"Moves a `value` amount of tokens from the caller's account to `to`. Returns a boolean value indicating whether the operation succeeded. Emits a {Transfer} event."},"transferFrom(address,address,uint256)":{"details":"Moves a `value` amount of tokens from `from` to `to` using the allowance mechanism. `value` is then deducted from the caller's allowance. Returns a boolean value indicating whether the operation succeeded. Emits a {Transfer} event."}},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"Approval\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"Transfer\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"}],\"name\":\"allowance\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"approve\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"balanceOf\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"totalSupply\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"transfer\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"transferFrom\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"details\":\"Interface of the ERC20 standard as defined in the EIP.\",\"events\":{\"Approval(address,address,uint256)\":{\"details\":\"Emitted when the allowance of a `spender` for an `owner` is set by a call to {approve}. `value` is the new allowance.\"},\"Transfer(address,address,uint256)\":{\"details\":\"Emitted when `value` tokens are moved from one account (`from`) to another (`to`). Note that `value` may be zero.\"}},\"kind\":\"dev\",\"methods\":{\"allowance(address,address)\":{\"details\":\"Returns the remaining number of tokens that `spender` will be allowed to spend on behalf of `owner` through {transferFrom}. This is zero by default. This value changes when {approve} or {transferFrom} are called.\"},\"approve(address,uint256)\":{\"details\":\"Sets a `value` amount of tokens as the allowance of `spender` over the caller's tokens. Returns a boolean value indicating whether the operation succeeded. IMPORTANT: Beware that changing an allowance with this method brings the risk that someone may use both the old and the new allowance by unfortunate transaction ordering. One possible solution to mitigate this race condition is to first reduce the spender's allowance to 0 and set the desired value afterwards: https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 Emits an {Approval} event.\"},\"balanceOf(address)\":{\"details\":\"Returns the value of tokens owned by `account`.\"},\"totalSupply()\":{\"details\":\"Returns the value of tokens in existence.\"},\"transfer(address,uint256)\":{\"details\":\"Moves a `value` amount of tokens from the caller's account to `to`. Returns a boolean value indicating whether the operation succeeded. Emits a {Transfer} event.\"},\"transferFrom(address,address,uint256)\":{\"details\":\"Moves a `value` amount of tokens from `from` to `to` using the allowance mechanism. `value` is then deducted from the caller's allowance. Returns a boolean value indicating whether the operation succeeded. Emits a {Transfer} event.\"}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeV2.sol\":\"IERC20\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeV2.sol\":{\"keccak256\":\"0x5069b55ca07f21bfe30b2a43c18a18318c8af9c181b2dcb07c290825efd70f34\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://273dc020a49d08e50126bbea0d7f783f79d08c702f2fdbc560618d24af308acc\",\"dweb:/ipfs/QmXJ2UVzFc8EPB74RT4CXQPC4xw66jt4T13poyfyd3UERh\"]}},\"version\":1}"},"hashes":{"allowance(address,address)":"dd62ed3e","approve(address,uint256)":"095ea7b3","balanceOf(address)":"70a08231","totalSupply()":"18160ddd","transfer(address,uint256)":"a9059cbb","transferFrom(address,address,uint256)":"23b872dd"}},"solidity/FastBridgeV2.sol:IERC20Permit":{"code":"0x","runtime-code":"0x","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.24 ^0.8.20 ^0.8.4;\n\n// contracts/interfaces/IAdmin.sol\n\ninterface IAdmin {\n // ============ Events ============\n\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n event ChainGasAmountUpdated(uint256 oldChainGasAmount, uint256 newChainGasAmount);\n\n // ============ Methods ============\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n\n function setChainGasAmount(uint256 newChainGasAmount) external;\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IFastBridgeV2Errors.sol\n\ninterface IFastBridgeV2Errors {\n error AmountIncorrect();\n error ChainIncorrect();\n error ExclusivityParamsIncorrect();\n error MsgValueIncorrect();\n error SenderIncorrect();\n error StatusIncorrect();\n error TokenNotContract();\n error ZapDataLengthAboveMax();\n error ZapNativeNotSupported();\n error ZeroAddress();\n\n error RecipientIncorrectReturnValue();\n error RecipientNoReturnValue();\n\n error DeadlineExceeded();\n error DeadlineNotExceeded();\n error DeadlineTooShort();\n error DisputePeriodNotPassed();\n error DisputePeriodPassed();\n error ExclusivityPeriodNotPassed();\n\n error TransactionRelayed();\n}\n\n// contracts/interfaces/IMulticallTarget.sol\n\n/// @notice Interface for a contract that can be called multiple times by the same caller. Inspired by MulticallV3:\n/// https://github.com/mds1/multicall/blob/master/src/Multicall3.sol\ninterface IMulticallTarget {\n struct Result {\n bool success;\n bytes returnData;\n }\n\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external;\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results);\n}\n\n// contracts/interfaces/IZapRecipient.sol\n\ninterface IZapRecipient {\n function zap(address token, uint256 amount, bytes memory zapData) external payable returns (bytes4);\n}\n\n// contracts/libs/Errors.sol\n\nerror DeadlineExceeded();\nerror DeadlineNotExceeded();\nerror DeadlineTooShort();\nerror InsufficientOutputAmount();\n\nerror MsgValueIncorrect();\nerror PoolNotFound();\nerror TokenAddressMismatch();\nerror TokenNotContract();\nerror TokenNotETH();\nerror TokensIdentical();\n\nerror ChainIncorrect();\nerror AmountIncorrect();\nerror ZeroAddress();\n\nerror DisputePeriodNotPassed();\nerror DisputePeriodPassed();\nerror SenderIncorrect();\nerror StatusIncorrect();\nerror TransactionIdIncorrect();\nerror TransactionRelayed();\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// contracts/interfaces/IFastBridgeV2.sol\n\ninterface IFastBridgeV2 is IFastBridge {\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n struct BridgeTxDetails {\n BridgeStatus status;\n uint32 destChainId;\n uint56 proofBlockTimestamp;\n address proofRelayer;\n }\n\n struct BridgeRelay {\n uint48 blockNumber;\n uint48 blockTimestamp;\n address relayer;\n }\n\n /// @notice New params introduced in the FastBridgeV2.\n /// We are passing fields from the older BridgeParams struct outside of this struct\n /// for backwards compatibility.\n /// Note: quoteRelayer and quoteExclusivitySeconds are either both zero (indicating no exclusivity)\n /// or both non-zero (indicating exclusivity for the given period).\n /// Note: zapNative \u003e 0 can NOT be used with destToken = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE (native token)\n /// @param quoteRelayer Relayer that provided the quote for the transaction\n /// @param quoteExclusivitySeconds Period of time the quote relayer is guaranteed exclusivity after user's deposit\n /// @param quoteId Unique quote identifier used for tracking the quote\n /// @param zapNative ETH value to send to the recipient (if any)\n /// @param zapData Parameters for the Zap to the destination recipient (if any)\n struct BridgeParamsV2 {\n address quoteRelayer;\n int256 quoteExclusivitySeconds;\n bytes quoteId;\n uint256 zapNative;\n bytes zapData;\n }\n\n /// @notice Updated bridge transaction struct to include parameters introduced in FastBridgeV2.\n /// Note: only `exclusivityRelayer` can fill such a transaction until `exclusivityEndTime`.\n struct BridgeTransactionV2 {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n // Note: sendChainGas flag from V1 is deprecated\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n address exclusivityRelayer;\n uint256 exclusivityEndTime;\n uint256 zapNative; // ETH value to send to the recipient (if any)\n bytes zapData; // data to pass for the Zap action (if any)\n }\n\n event BridgeQuoteDetails(bytes32 indexed transactionId, bytes quoteId);\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability\n /// to provide temporary exclusivity fill rights for the quote relayer.\n /// @param params The parameters required to bridge\n /// @param paramsV2 The parameters for exclusivity fill rights (optional, can be left empty)\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function relay(bytes memory request, address relayer) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param transactionId The transaction id associated with the encoded bridge transaction to prove\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital.\n /// @notice Can only send funds to the relayer address on the proof.\n /// @param request The encoded bridge transaction to claim on origin chain\n function claim(bytes memory request) external;\n /// @notice Checks if a transaction has been relayed\n /// @param transactionId The ID of the transaction to check\n /// @return True if the transaction has been relayed, false otherwise\n function bridgeRelays(bytes32 transactionId) external view returns (bool);\n\n /// @notice Returns the status of a bridge transaction\n /// @param transactionId The ID of the bridge transaction\n /// @return BridgeStatus Status of the bridge transaction\n function bridgeStatuses(bytes32 transactionId) external view returns (BridgeStatus);\n\n /// @notice Returns the timestamp and relayer of a bridge proof\n /// @param transactionId The ID of the bridge transaction\n /// @return timestamp The timestamp of the bridge proof\n /// @return relayer The relayer address of the bridge proof\n function bridgeProofs(bytes32 transactionId) external view returns (uint96 timestamp, address relayer);\n\n /// @notice Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\n /// @param request The bridge request to decode\n function getBridgeTransactionV2(bytes memory request) external view returns (BridgeTransactionV2 memory);\n}\n\n// contracts/utils/MulticallTarget.sol\n\n// solhint-disable avoid-low-level-calls\n/// @notice Template for a contract that supports batched calls (preserving the msg.sender).\n/// Only calls with zero msg.value could be batched.\nabstract contract MulticallTarget is IMulticallTarget {\n error MulticallTarget__UndeterminedRevert();\n\n /// @notice Perform a batched call to this contract, preserving the msg.sender.\n /// The return data from each call is discarded.\n /// @dev The method is non-payable, so only calls with `msg.value == 0` could be batched.\n /// It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag.\n /// Otherwise, the whole batch call will be reverted with the original revert reason.\n /// @param data List of abi-encoded calldata for the calls to perform.\n /// @param ignoreReverts Whether to ignore the revert errors from the calls.\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external {\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\n if (!success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(result);\n }\n }\n }\n\n /// @notice Perform a batched call to this contract, preserving the msg.sender.\n /// The return data from each call is preserved.\n /// @dev The method is non-payable, so only calls with `msg.value == 0` could be batched.\n /// It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag.\n /// Otherwise, the whole batch call will be reverted with the original revert reason.\n /// @param data List of abi-encoded calldata for the calls to perform.\n /// @param ignoreReverts Whether to ignore the revert errors from the calls.\n /// @return results List of results from the calls: `(success, returnData)`.\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results)\n {\n results = new Result[](data.length);\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (results[i].success, results[i].returnData) = address(this).delegatecall(data[i]);\n if (!results[i].success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(results[i].returnData);\n }\n }\n }\n\n /// @dev Bubbles the revert message from the underlying call.\n /// Note: preserves the same custom error or revert string, if one was used.\n /// Source: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v5.0.2/contracts/utils/Address.sol#L143-L158\n function _bubbleRevert(bytes memory returnData) internal pure {\n // Look for revert reason and bubble it up if present\n if (returnData.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n // solhint-disable-next-line no-inline-assembly\n assembly {\n let returndata_size := mload(returnData)\n revert(add(32, returnData), returndata_size)\n }\n } else {\n revert MulticallTarget__UndeterminedRevert();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// contracts/libs/BridgeTransactionV2.sol\n\n// solhint-disable no-inline-assembly\nlibrary BridgeTransactionV2Lib {\n uint16 internal constant VERSION = 2;\n\n // Offsets of the fields in the packed BridgeTransactionV2 struct\n // uint16 version [000 .. 002)\n // uint32 originChainId [002 .. 006)\n // uint32 destChainId [006 .. 010)\n // address originSender [010 .. 030)\n // address destRecipient [030 .. 050)\n // address originToken [050 .. 070)\n // address destToken [070 .. 090)\n // uint256 originAmount [090 .. 122)\n // uint256 destAmount [122 .. 154)\n // uint256 originFeeAmount [154 .. 186)\n // uint256 deadline [186 .. 218)\n // uint256 nonce [218 .. 250)\n // address exclusivityRelayer [250 .. 270)\n // uint256 exclusivityEndTime [270 .. 302)\n // uint256 zapNative [302 .. 334)\n // bytes zapData [334 .. ***)\n\n // forgefmt: disable-start\n uint256 private constant OFFSET_ORIGIN_CHAIN_ID = 2;\n uint256 private constant OFFSET_DEST_CHAIN_ID = 6;\n uint256 private constant OFFSET_ORIGIN_SENDER = 10;\n uint256 private constant OFFSET_DEST_RECIPIENT = 30;\n uint256 private constant OFFSET_ORIGIN_TOKEN = 50;\n uint256 private constant OFFSET_DEST_TOKEN = 70;\n uint256 private constant OFFSET_ORIGIN_AMOUNT = 90;\n uint256 private constant OFFSET_DEST_AMOUNT = 122;\n uint256 private constant OFFSET_ORIGIN_FEE_AMOUNT = 154;\n uint256 private constant OFFSET_DEADLINE = 186;\n uint256 private constant OFFSET_NONCE = 218;\n uint256 private constant OFFSET_EXCLUSIVITY_RELAYER = 250;\n uint256 private constant OFFSET_EXCLUSIVITY_END_TIME = 270;\n uint256 private constant OFFSET_ZAP_NATIVE = 302;\n uint256 private constant OFFSET_ZAP_DATA = 334;\n // forgefmt: disable-end\n\n error BridgeTransactionV2__InvalidEncodedTx();\n error BridgeTransactionV2__UnsupportedVersion(uint16 version);\n\n /// @notice Validates the encoded transaction to be a tightly packed encoded payload for BridgeTransactionV2.\n /// @dev Checks the minimum length and the version, use this function before decoding any of the fields.\n function validateV2(bytes calldata encodedTx) internal pure {\n // Check the minimum length: must at least include all static fields.\n if (encodedTx.length \u003c OFFSET_ZAP_DATA) revert BridgeTransactionV2__InvalidEncodedTx();\n // Once we validated the length, we can be sure that the version field is present.\n uint16 version_ = version(encodedTx);\n if (version_ != VERSION) revert BridgeTransactionV2__UnsupportedVersion(version_);\n }\n\n /// @notice Encodes the BridgeTransactionV2 struct by tightly packing the fields.\n /// @dev `abi.decode` will not work as a result of the tightly packed fields. Use `decodeV2` to decode instead.\n function encodeV2(IFastBridgeV2.BridgeTransactionV2 memory bridgeTx) internal pure returns (bytes memory) {\n // We split the encoding into two parts to avoid stack-too-deep error\n bytes memory firstPart = abi.encodePacked(\n VERSION,\n bridgeTx.originChainId,\n bridgeTx.destChainId,\n bridgeTx.originSender,\n bridgeTx.destRecipient,\n bridgeTx.originToken,\n bridgeTx.destToken,\n bridgeTx.originAmount\n );\n return abi.encodePacked(\n firstPart,\n bridgeTx.destAmount,\n bridgeTx.originFeeAmount,\n // Note: we skip the deprecated `sendChainGas` flag, which was present in BridgeTransaction V1\n bridgeTx.deadline,\n bridgeTx.nonce,\n // New V2 fields: exclusivity\n bridgeTx.exclusivityRelayer,\n bridgeTx.exclusivityEndTime,\n // New V2 fields: Zap\n bridgeTx.zapNative,\n bridgeTx.zapData\n );\n }\n\n /// @notice Decodes the BridgeTransactionV2 struct from the encoded transaction.\n /// @dev Encoded BridgeTransactionV2 struct must be tightly packed.\n /// Use `validateV2` before decoding to ensure the encoded transaction is valid.\n function decodeV2(bytes calldata encodedTx)\n internal\n pure\n returns (IFastBridgeV2.BridgeTransactionV2 memory bridgeTx)\n {\n bridgeTx.originChainId = originChainId(encodedTx);\n bridgeTx.destChainId = destChainId(encodedTx);\n bridgeTx.originSender = originSender(encodedTx);\n bridgeTx.destRecipient = destRecipient(encodedTx);\n bridgeTx.originToken = originToken(encodedTx);\n bridgeTx.destToken = destToken(encodedTx);\n bridgeTx.originAmount = originAmount(encodedTx);\n bridgeTx.destAmount = destAmount(encodedTx);\n bridgeTx.originFeeAmount = originFeeAmount(encodedTx);\n bridgeTx.deadline = deadline(encodedTx);\n bridgeTx.nonce = nonce(encodedTx);\n bridgeTx.exclusivityRelayer = exclusivityRelayer(encodedTx);\n bridgeTx.exclusivityEndTime = exclusivityEndTime(encodedTx);\n bridgeTx.zapNative = zapNative(encodedTx);\n bridgeTx.zapData = zapData(encodedTx);\n }\n\n /// @notice Extracts the version from the encoded transaction.\n function version(bytes calldata encodedTx) internal pure returns (uint16 version_) {\n // Load 32 bytes from the start and shift it 240 bits to the right to get the highest 16 bits.\n assembly {\n version_ := shr(240, calldataload(encodedTx.offset))\n }\n }\n\n /// @notice Extracts the origin chain ID from the encoded transaction.\n function originChainId(bytes calldata encodedTx) internal pure returns (uint32 originChainId_) {\n // Load 32 bytes from the offset and shift it 224 bits to the right to get the highest 32 bits.\n assembly {\n originChainId_ := shr(224, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_CHAIN_ID)))\n }\n }\n\n /// @notice Extracts the destination chain ID from the encoded transaction.\n function destChainId(bytes calldata encodedTx) internal pure returns (uint32 destChainId_) {\n // Load 32 bytes from the offset and shift it 224 bits to the right to get the highest 32 bits.\n assembly {\n destChainId_ := shr(224, calldataload(add(encodedTx.offset, OFFSET_DEST_CHAIN_ID)))\n }\n }\n\n /// @notice Extracts the origin sender from the encoded transaction.\n function originSender(bytes calldata encodedTx) internal pure returns (address originSender_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n originSender_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_SENDER)))\n }\n }\n\n /// @notice Extracts the destination recipient from the encoded transaction.\n function destRecipient(bytes calldata encodedTx) internal pure returns (address destRecipient_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n destRecipient_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_DEST_RECIPIENT)))\n }\n }\n\n /// @notice Extracts the origin token from the encoded transaction.\n function originToken(bytes calldata encodedTx) internal pure returns (address originToken_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n originToken_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_TOKEN)))\n }\n }\n\n /// @notice Extracts the destination token from the encoded transaction.\n function destToken(bytes calldata encodedTx) internal pure returns (address destToken_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n destToken_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_DEST_TOKEN)))\n }\n }\n\n /// @notice Extracts the origin amount from the encoded transaction.\n function originAmount(bytes calldata encodedTx) internal pure returns (uint256 originAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n originAmount_ := calldataload(add(encodedTx.offset, OFFSET_ORIGIN_AMOUNT))\n }\n }\n\n /// @notice Extracts the destination amount from the encoded transaction.\n function destAmount(bytes calldata encodedTx) internal pure returns (uint256 destAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n destAmount_ := calldataload(add(encodedTx.offset, OFFSET_DEST_AMOUNT))\n }\n }\n\n /// @notice Extracts the origin fee amount from the encoded transaction.\n function originFeeAmount(bytes calldata encodedTx) internal pure returns (uint256 originFeeAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n originFeeAmount_ := calldataload(add(encodedTx.offset, OFFSET_ORIGIN_FEE_AMOUNT))\n }\n }\n\n /// @notice Extracts the deadline from the encoded transaction.\n function deadline(bytes calldata encodedTx) internal pure returns (uint256 deadline_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n deadline_ := calldataload(add(encodedTx.offset, OFFSET_DEADLINE))\n }\n }\n\n /// @notice Extracts the nonce from the encoded transaction.\n function nonce(bytes calldata encodedTx) internal pure returns (uint256 nonce_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n nonce_ := calldataload(add(encodedTx.offset, OFFSET_NONCE))\n }\n }\n\n /// @notice Extracts the exclusivity relayer from the encoded transaction.\n function exclusivityRelayer(bytes calldata encodedTx) internal pure returns (address exclusivityRelayer_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n exclusivityRelayer_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_EXCLUSIVITY_RELAYER)))\n }\n }\n\n /// @notice Extracts the exclusivity end time from the encoded transaction.\n function exclusivityEndTime(bytes calldata encodedTx) internal pure returns (uint256 exclusivityEndTime_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n exclusivityEndTime_ := calldataload(add(encodedTx.offset, OFFSET_EXCLUSIVITY_END_TIME))\n }\n }\n\n /// @notice Extracts the Zap's native value from the encoded transaction.\n function zapNative(bytes calldata encodedTx) internal pure returns (uint256 zapNative_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n zapNative_ := calldataload(add(encodedTx.offset, OFFSET_ZAP_NATIVE))\n }\n }\n\n /// @notice Extracts the Zap's data from the encoded transaction.\n function zapData(bytes calldata encodedTx) internal pure returns (bytes calldata zapData_) {\n zapData_ = encodedTx[OFFSET_ZAP_DATA:];\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// contracts/libs/UniversalToken.sol\n\nlibrary UniversalTokenLib {\n using SafeERC20 for IERC20;\n\n address internal constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Transfers tokens to the given account. Reverts if transfer is not successful.\n /// @dev This might trigger fallback, if ETH is transferred to the contract.\n /// Make sure this can not lead to reentrancy attacks.\n function universalTransfer(address token, address to, uint256 value) internal {\n // Don't do anything, if need to send tokens to this address\n if (to == address(this)) return;\n // Don't do anything, if trying to send zero value\n if (value == 0) return;\n if (token == ETH_ADDRESS) {\n /// @dev Note: this can potentially lead to executing code in `to`.\n // solhint-disable-next-line avoid-low-level-calls\n (bool success,) = to.call{value: value}(\"\");\n require(success, \"ETH transfer failed\");\n } else {\n IERC20(token).safeTransfer(to, value);\n }\n }\n\n /// @notice Issues an infinite allowance to the spender, if the current allowance is insufficient\n /// to spend the given amount.\n function universalApproveInfinity(address token, address spender, uint256 amountToSpend) internal {\n // ETH Chad doesn't require your approval\n if (token == ETH_ADDRESS) return;\n // No-op if allowance is already sufficient\n uint256 allowance = IERC20(token).allowance(address(this), spender);\n if (allowance \u003e= amountToSpend) return;\n // Otherwise, reset approval to 0 and set to max allowance\n if (allowance \u003e 0) IERC20(token).safeDecreaseAllowance(spender, allowance);\n IERC20(token).safeIncreaseAllowance(spender, type(uint256).max);\n }\n\n /// @notice Returns the balance of the given token (or native ETH) for the given account.\n function universalBalanceOf(address token, address account) internal view returns (uint256) {\n if (token == ETH_ADDRESS) {\n return account.balance;\n } else {\n return IERC20(token).balanceOf(account);\n }\n }\n\n /// @dev Checks that token is a contract and not ETH_ADDRESS.\n function assertIsContract(address token) internal view {\n // Check that ETH_ADDRESS was not used (in case this is a predeploy on any of the chains)\n if (token == UniversalTokenLib.ETH_ADDRESS) revert TokenNotContract();\n // Check that token is not an EOA\n if (token.code.length == 0) revert TokenNotContract();\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/Admin.sol\n\ncontract Admin is IAdmin, AccessControlEnumerable {\n using UniversalTokenLib for address;\n\n bytes32 public constant RELAYER_ROLE = keccak256(\"RELAYER_ROLE\");\n bytes32 public constant REFUNDER_ROLE = keccak256(\"REFUNDER_ROLE\");\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n uint256 public constant FEE_BPS = 1e6;\n uint256 public constant FEE_RATE_MAX = 0.01e6; // max 1% on origin amount\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Chain gas amount to forward as rebate if requested\n uint256 public chainGasAmount;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n }\n\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n require(newFeeRate \u003c= FEE_RATE_MAX, \"newFeeRate \u003e max\");\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n token.universalTransfer(recipient, feeAmount);\n emit FeesSwept(token, recipient, feeAmount);\n }\n\n function setChainGasAmount(uint256 newChainGasAmount) external onlyRole(GOVERNOR_ROLE) {\n uint256 oldChainGasAmount = chainGasAmount;\n chainGasAmount = newChainGasAmount;\n emit ChainGasAmountUpdated(oldChainGasAmount, newChainGasAmount);\n }\n}\n\n// contracts/FastBridgeV2.sol\n\n/// @notice FastBridgeV2 is a contract for bridging tokens across chains.\ncontract FastBridgeV2 is Admin, MulticallTarget, IFastBridgeV2, IFastBridgeV2Errors {\n using BridgeTransactionV2Lib for bytes;\n using SafeERC20 for IERC20;\n\n /// @notice Address reserved for native gas token (ETH on Ethereum and most L2s, AVAX on Avalanche, etc)\n address public constant NATIVE_GAS_TOKEN = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Delay for a transaction after which it could be permisionlessly refunded\n uint256 public constant REFUND_DELAY = 7 days;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n /// @notice Maximum length of accepted zapData\n uint256 public constant MAX_ZAP_DATA_LENGTH = 2 ** 16 - 1;\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeTxDetails) public bridgeTxDetails;\n /// @notice Relay details on destination chain\n mapping(bytes32 =\u003e BridgeRelay) public bridgeRelayDetails;\n /// @notice Unique bridge nonces tracked per originSender\n mapping(address =\u003e uint256) public senderNonces;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Replaced by senderNonces\n uint256 public immutable nonce = 0;\n /// @notice the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n bridge({\n params: params,\n paramsV2: BridgeParamsV2({\n quoteRelayer: address(0),\n quoteExclusivitySeconds: 0,\n quoteId: bytes(\"\"),\n zapNative: 0,\n zapData: bytes(\"\")\n })\n });\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes calldata request) external payable {\n // relay override will validate the request\n relay({request: request, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes calldata request, bytes32 destTxHash) external {\n request.validateV2();\n prove({transactionId: keccak256(request), destTxHash: destTxHash, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridgeV2\n function claim(bytes calldata request) external {\n // claim override will validate the request\n claim({request: request, to: address(0)});\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Aggregate the read operations from the same storage slot\n address disputedRelayer = $.proofRelayer;\n BridgeStatus status = $.status;\n uint56 proofBlockTimestamp = $.proofBlockTimestamp;\n // Can only dispute a RELAYER_PROVED transaction within the dispute period\n if (status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(proofBlockTimestamp) \u003e DISPUTE_PERIOD) {\n revert DisputePeriodPassed();\n }\n // Update status to REQUESTED and delete the disputed proof details\n // Note: these are storage writes\n $.status = BridgeStatus.REQUESTED;\n $.proofRelayer = address(0);\n $.proofBlockTimestamp = 0;\n\n emit BridgeProofDisputed(transactionId, disputedRelayer);\n }\n\n /// @inheritdoc IFastBridge\n function refund(bytes calldata request) external {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Can only refund a REQUESTED transaction after its deadline expires\n if ($.status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n uint256 deadline = request.deadline();\n // Permissionless refund is only allowed after REFUND_DELAY on top of the deadline\n if (!hasRole(REFUNDER_ROLE, msg.sender)) deadline += REFUND_DELAY;\n if (block.timestamp \u003c= deadline) revert DeadlineNotExceeded();\n // Update status to REFUNDED and return the full amount (collateral + protocol fees) to the original sender.\n // The protocol fees are only updated when the transaction is claimed, so we don't need to update them here.\n // Note: this is a storage write\n $.status = BridgeStatus.REFUNDED;\n\n address to = request.originSender();\n address token = request.originToken();\n uint256 amount = request.originAmount() + request.originFeeAmount();\n // Emit the event before any external calls\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n // Complete the user refund as the last transaction action\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(to), amount);\n } else {\n IERC20(token).safeTransfer(to, amount);\n }\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // The correct relayer can only claim a RELAYER_PROVED transaction after the dispute period\n if ($.status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if ($.proofRelayer != relayer) revert SenderIncorrect();\n return _timeSince($.proofBlockTimestamp) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n /// @dev This method is added to achieve backwards compatibility with decoding requests into V1 structs:\n /// - `zapNative` is partially reported as a zero/non-zero flag\n /// - `zapData` is ignored\n /// In order to process all kinds of requests use getBridgeTransactionV2 instead.\n function getBridgeTransaction(bytes calldata request) external view returns (BridgeTransaction memory) {\n // Try decoding into V2 struct first. This will revert if V1 struct is passed\n try this.getBridgeTransactionV2(request) returns (BridgeTransactionV2 memory txV2) {\n // Note: we entirely ignore the zapData field, as it was not present in V1\n return BridgeTransaction({\n originChainId: txV2.originChainId,\n destChainId: txV2.destChainId,\n originSender: txV2.originSender,\n destRecipient: txV2.destRecipient,\n originToken: txV2.originToken,\n destToken: txV2.destToken,\n originAmount: txV2.originAmount,\n destAmount: txV2.destAmount,\n originFeeAmount: txV2.originFeeAmount,\n sendChainGas: txV2.zapNative != 0,\n deadline: txV2.deadline,\n nonce: txV2.nonce\n });\n } catch {\n // Fallback to V1 struct\n return abi.decode(request, (BridgeTransaction));\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function getBridgeTransactionV2(bytes calldata request) external pure returns (BridgeTransactionV2 memory) {\n request.validateV2();\n return BridgeTransactionV2Lib.decodeV2(request);\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) public payable {\n int256 exclusivityEndTime = 0;\n // if relayer exclusivity is not intended for this bridge, set exclusivityEndTime to static zero\n // otherwise, set exclusivity to expire at the current block ts offset by quoteExclusivitySeconds\n if (paramsV2.quoteRelayer != address(0)) {\n exclusivityEndTime = int256(block.timestamp) + paramsV2.quoteExclusivitySeconds;\n }\n _validateBridgeParams(params, paramsV2, exclusivityEndTime);\n\n // transfer tokens to bridge contract\n /// @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _takeBridgedUserAsset(params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) {\n originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n }\n\n // set status to requested\n bytes memory request = BridgeTransactionV2Lib.encodeV2(\n BridgeTransactionV2({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n deadline: params.deadline,\n nonce: senderNonces[params.sender]++, // increment nonce on every bridge\n exclusivityRelayer: paramsV2.quoteRelayer,\n // We checked exclusivityEndTime to be in range [0 .. params.deadline] above, so can safely cast\n exclusivityEndTime: uint256(exclusivityEndTime),\n zapNative: paramsV2.zapNative,\n zapData: paramsV2.zapData\n })\n );\n bytes32 transactionId = keccak256(request);\n // Note: the tx status will be updated throughout the tx lifecycle, while destChainId is set once here\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n bridgeTxDetails[transactionId].destChainId = params.dstChainId;\n\n emit BridgeRequested({\n transactionId: transactionId,\n sender: params.sender,\n request: request,\n destChainId: params.dstChainId,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n sendChainGas: paramsV2.zapNative != 0\n });\n emit BridgeQuoteDetails(transactionId, paramsV2.quoteId);\n }\n\n /// @inheritdoc IFastBridgeV2\n function relay(bytes calldata request, address relayer) public payable {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n _validateRelayParams(request, transactionId, relayer);\n // mark bridge transaction as relayed\n bridgeRelayDetails[transactionId] =\n BridgeRelay({blockNumber: uint48(block.number), blockTimestamp: uint48(block.timestamp), relayer: relayer});\n\n // transfer tokens to recipient on destination chain and trigger Zap if requested\n address to = request.destRecipient();\n address token = request.destToken();\n uint256 amount = request.destAmount();\n uint256 zapNative = request.zapNative();\n\n // Emit the event before any external calls\n emit BridgeRelayed({\n transactionId: transactionId,\n relayer: relayer,\n to: to,\n originChainId: request.originChainId(),\n originToken: request.originToken(),\n destToken: token,\n originAmount: request.originAmount(),\n destAmount: amount,\n chainGasAmount: zapNative\n });\n\n // All state changes have been done at this point, can proceed to the external calls.\n // This follows the checks-effects-interactions pattern to mitigate potential reentrancy attacks.\n if (token == NATIVE_GAS_TOKEN) {\n // For the native gas token, additional zapNative is not allowed\n if (zapNative != 0) revert ZapNativeNotSupported();\n // Check that the correct msg.value was sent\n if (msg.value != amount) revert MsgValueIncorrect();\n // Don't do a native transfer yet: we will handle it alongside the Zap below\n } else {\n // For ERC20s, we check that the correct msg.value was sent\n if (msg.value != zapNative) revert MsgValueIncorrect();\n // We need to transfer the tokens from the Relayer to the recipient first before performing an\n // optional post-transfer Zap.\n IERC20(token).safeTransferFrom(msg.sender, to, amount);\n }\n // At this point we have done:\n // - Transferred the requested amount of ERC20 tokens to the recipient.\n // At this point we have confirmed:\n // - For ERC20s: msg.value matches the requested zapNative amount.\n // - For the native gas token: msg.value matches the requested destAmount.\n // Remaining optional things to do:\n // - Forward the full msg.value to the recipient (if non-zero).\n // - Trigger a Zap (if zapData is present).\n bytes calldata zapData = request.zapData();\n if (zapData.length != 0) {\n // Zap Data is present: Zap has been requested by the recipient. Trigger it forwarding the full msg.value.\n\n // Note: if token has a fee on transfers, the recipient will have received less than `amount`.\n // This is a very niche edge case and should be handled by the recipient contract.\n _triggerZapWithChecks({recipient: to, token: token, amount: amount, zapData: zapData});\n } else if (msg.value != 0) {\n // Zap Data is missing, but msg.value was sent. This could happen in two different cases:\n // - Relay with the native gas token is happening.\n // - Relay with ERC20 is happening, with a `zapNative \u003e 0` request.\n // In both cases, we need to transfer the full msg.value to the recipient.\n Address.sendValue(payable(to), msg.value);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) public onlyRole(RELAYER_ROLE) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n\n // Can only prove a REQUESTED transaction\n if ($.status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n // Update status to RELAYER_PROVED and store the proof details\n // Note: these are storage writes\n $.status = BridgeStatus.RELAYER_PROVED;\n $.proofBlockTimestamp = uint56(block.timestamp);\n $.proofRelayer = relayer;\n\n emit BridgeProofProvided(transactionId, relayer, destTxHash);\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes calldata request, address to) public {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Aggregate the read operations from the same storage slot\n address proofRelayer = $.proofRelayer;\n BridgeStatus status = $.status;\n uint56 proofBlockTimestamp = $.proofBlockTimestamp;\n\n // Can only claim a RELAYER_PROVED transaction after the dispute period\n if (status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(proofBlockTimestamp) \u003c= DISPUTE_PERIOD) {\n revert DisputePeriodNotPassed();\n }\n\n if (to == address(0)) {\n // Anyone could claim the funds to the proven relayer on their behalf\n to = proofRelayer;\n } else if (proofRelayer != msg.sender) {\n // Only the proven relayer could specify an address to claim the funds to\n revert SenderIncorrect();\n }\n\n // Update status to RELAYER_CLAIMED and transfer the origin collateral to the specified claim address\n // Note: this is a storage write\n $.status = BridgeStatus.RELAYER_CLAIMED;\n\n address token = request.originToken();\n uint256 amount = request.originAmount();\n // Update protocol fees if origin fee amount exists\n uint256 originFeeAmount = request.originFeeAmount();\n if (originFeeAmount \u003e 0) protocolFees[token] += originFeeAmount;\n // Emit the event before any external calls\n emit BridgeDepositClaimed(transactionId, proofRelayer, to, token, amount);\n // Complete the relayer claim as the last transaction action\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(to), amount);\n } else {\n IERC20(token).safeTransfer(to, amount);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeStatuses(bytes32 transactionId) public view returns (BridgeStatus status) {\n return bridgeTxDetails[transactionId].status;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeProofs(bytes32 transactionId) public view returns (uint96 timestamp, address relayer) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n\n timestamp = $.proofBlockTimestamp;\n relayer = $.proofRelayer;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeRelays(bytes32 transactionId) public view returns (bool) {\n // has this transactionId been relayed?\n return bridgeRelayDetails[transactionId].relayer != address(0);\n }\n\n /// @notice Takes the bridged asset from the user into FastBridgeV2 custody. It will be later\n /// claimed by the relayer who completed the relay on destination chain, or refunded back to the user,\n /// should no one complete the relay.\n function _takeBridgedUserAsset(address token, uint256 amount) internal returns (uint256 amountTaken) {\n if (token == NATIVE_GAS_TOKEN) {\n // For the native gas token, we just need to check that the supplied msg.value is correct.\n // Supplied `msg.value` is already in FastBridgeV2 custody.\n if (amount != msg.value) revert MsgValueIncorrect();\n amountTaken = msg.value;\n } else {\n // For ERC20s, token is explicitly transferred from the user to FastBridgeV2.\n // We don't allow non-zero `msg.value` to avoid extra funds from being stuck in FastBridgeV2.\n if (msg.value != 0) revert MsgValueIncorrect();\n // Throw an explicit error if the provided token address is not a contract\n if (token.code.length == 0) revert TokenNotContract();\n amountTaken = IERC20(token).balanceOf(address(this));\n IERC20(token).safeTransferFrom(msg.sender, address(this), amount);\n // Use the balance difference as the amount taken in case of fee on transfer tokens.\n amountTaken = IERC20(token).balanceOf(address(this)) - amountTaken;\n }\n }\n\n /// @notice Calls the Recipient's hook function with the specified zapData and performs\n /// all the necessary checks for the returned value.\n function _triggerZapWithChecks(address recipient, address token, uint256 amount, bytes calldata zapData) internal {\n // This will bubble any revert messages from the hook function\n bytes memory returnData = Address.functionCallWithValue({\n target: recipient,\n data: abi.encodeCall(IZapRecipient.zap, (token, amount, zapData)),\n // Note: see `relay()` for reasoning behind passing msg.value\n value: msg.value\n });\n // Explicit revert if no return data at all\n if (returnData.length == 0) revert RecipientNoReturnValue();\n // Check that exactly a single return value was returned\n if (returnData.length != 32) revert RecipientIncorrectReturnValue();\n // Return value should be abi-encoded hook function selector\n if (bytes32(returnData) != bytes32(IZapRecipient.zap.selector)) {\n revert RecipientIncorrectReturnValue();\n }\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint56(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint56).max but\n /// proof.timestamp \u003c type(uint56).max via unchecked statement\n /// @param proofBlockTimestamp The bridge proof block timestamp\n /// @return delta Time delta since proof submitted\n function _timeSince(uint56 proofBlockTimestamp) internal view returns (uint256 delta) {\n unchecked {\n delta = uint56(block.timestamp) - proofBlockTimestamp;\n }\n }\n\n /// @notice Performs all the necessary checks for a bridge to happen.\n /// @dev There's no good way to refactor this function to reduce cyclomatic complexity due to\n /// the number of checks that need to be performed, so we skip the code-complexity rule here.\n // solhint-disable-next-line code-complexity\n function _validateBridgeParams(\n BridgeParams memory params,\n BridgeParamsV2 memory paramsV2,\n int256 exclusivityEndTime\n )\n internal\n view\n {\n // Check V1 (legacy) params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.sender == address(0) || params.to == address(0)) revert ZeroAddress();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n // Check V2 params\n if (paramsV2.zapData.length \u003e MAX_ZAP_DATA_LENGTH) revert ZapDataLengthAboveMax();\n if (paramsV2.zapNative != 0 \u0026\u0026 params.destToken == NATIVE_GAS_TOKEN) {\n revert ZapNativeNotSupported();\n }\n // exclusivityEndTime must be in range [0 .. params.deadline]\n if (exclusivityEndTime \u003c 0 || exclusivityEndTime \u003e int256(params.deadline)) {\n revert ExclusivityParamsIncorrect();\n }\n }\n\n /// @notice Performs all the necessary checks for a relay to happen.\n function _validateRelayParams(bytes calldata request, bytes32 transactionId, address relayer) internal view {\n if (relayer == address(0)) revert ZeroAddress();\n // Check if the transaction has already been relayed\n if (bridgeRelays(transactionId)) revert TransactionRelayed();\n if (request.destChainId() != block.chainid) revert ChainIncorrect();\n // Check the deadline for relay to happen\n if (block.timestamp \u003e request.deadline()) revert DeadlineExceeded();\n // Check the exclusivity period, if it is still ongoing\n address exclRelayer = request.exclusivityRelayer();\n if (exclRelayer != address(0) \u0026\u0026 exclRelayer != relayer \u0026\u0026 block.timestamp \u003c= request.exclusivityEndTime()) {\n revert ExclusivityPeriodNotPassed();\n }\n }\n}\n","language":"Solidity","languageVersion":"0.8.24","compilerVersion":"0.8.24","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"","srcMapRuntime":"","abiDefinition":[{"inputs":[],"name":"DOMAIN_SEPARATOR","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"nonces","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"permit","outputs":[],"stateMutability":"nonpayable","type":"function"}],"userDoc":{"kind":"user","methods":{},"version":1},"developerDoc":{"details":"Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in https://eips.ethereum.org/EIPS/eip-2612[EIP-2612]. Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't need to send a transaction, and thus is not required to hold Ether at all. ==== Security Considerations There are two important considerations concerning the use of `permit`. The first is that a valid permit signature expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be considered as an intention to spend the allowance in any specific way. The second is that because permits have built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be generally recommended is: ```solidity function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public { try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {} doThing(..., value); } function doThing(..., uint256 value) public { token.safeTransferFrom(msg.sender, address(this), value); ... } ``` Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also {SafeERC20-safeTransferFrom}). Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so contracts should have entry points that don't rely on permit.","kind":"dev","methods":{"DOMAIN_SEPARATOR()":{"details":"Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}."},"nonces(address)":{"details":"Returns the current nonce for `owner`. This value must be included whenever a signature is generated for {permit}. Every successful call to {permit} increases ``owner``'s nonce by one. This prevents a signature from being used multiple times."},"permit(address,address,uint256,uint256,uint8,bytes32,bytes32)":{"details":"Sets `value` as the allowance of `spender` over ``owner``'s tokens, given ``owner``'s signed approval. IMPORTANT: The same issues {IERC20-approve} has related to transaction ordering also apply here. Emits an {Approval} event. Requirements: - `spender` cannot be the zero address. - `deadline` must be a timestamp in the future. - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner` over the EIP712-formatted function arguments. - the signature must use ``owner``'s current nonce (see {nonces}). For more information on the signature format, see the https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP section]. CAUTION: See Security Considerations above."}},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[],\"name\":\"DOMAIN_SEPARATOR\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"}],\"name\":\"nonces\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"},{\"internalType\":\"uint8\",\"name\":\"v\",\"type\":\"uint8\"},{\"internalType\":\"bytes32\",\"name\":\"r\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"s\",\"type\":\"bytes32\"}],\"name\":\"permit\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"details\":\"Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in https://eips.ethereum.org/EIPS/eip-2612[EIP-2612]. Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't need to send a transaction, and thus is not required to hold Ether at all. ==== Security Considerations There are two important considerations concerning the use of `permit`. The first is that a valid permit signature expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be considered as an intention to spend the allowance in any specific way. The second is that because permits have built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be generally recommended is: ```solidity function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public { try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {} doThing(..., value); } function doThing(..., uint256 value) public { token.safeTransferFrom(msg.sender, address(this), value); ... } ``` Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also {SafeERC20-safeTransferFrom}). Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so contracts should have entry points that don't rely on permit.\",\"kind\":\"dev\",\"methods\":{\"DOMAIN_SEPARATOR()\":{\"details\":\"Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\"},\"nonces(address)\":{\"details\":\"Returns the current nonce for `owner`. This value must be included whenever a signature is generated for {permit}. Every successful call to {permit} increases ``owner``'s nonce by one. This prevents a signature from being used multiple times.\"},\"permit(address,address,uint256,uint256,uint8,bytes32,bytes32)\":{\"details\":\"Sets `value` as the allowance of `spender` over ``owner``'s tokens, given ``owner``'s signed approval. IMPORTANT: The same issues {IERC20-approve} has related to transaction ordering also apply here. Emits an {Approval} event. Requirements: - `spender` cannot be the zero address. - `deadline` must be a timestamp in the future. - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner` over the EIP712-formatted function arguments. - the signature must use ``owner``'s current nonce (see {nonces}). For more information on the signature format, see the https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP section]. CAUTION: See Security Considerations above.\"}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeV2.sol\":\"IERC20Permit\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeV2.sol\":{\"keccak256\":\"0x5069b55ca07f21bfe30b2a43c18a18318c8af9c181b2dcb07c290825efd70f34\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://273dc020a49d08e50126bbea0d7f783f79d08c702f2fdbc560618d24af308acc\",\"dweb:/ipfs/QmXJ2UVzFc8EPB74RT4CXQPC4xw66jt4T13poyfyd3UERh\"]}},\"version\":1}"},"hashes":{"DOMAIN_SEPARATOR()":"3644e515","nonces(address)":"7ecebe00","permit(address,address,uint256,uint256,uint8,bytes32,bytes32)":"d505accf"}},"solidity/FastBridgeV2.sol:IFastBridge":{"code":"0x","runtime-code":"0x","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.24 ^0.8.20 ^0.8.4;\n\n// contracts/interfaces/IAdmin.sol\n\ninterface IAdmin {\n // ============ Events ============\n\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n event ChainGasAmountUpdated(uint256 oldChainGasAmount, uint256 newChainGasAmount);\n\n // ============ Methods ============\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n\n function setChainGasAmount(uint256 newChainGasAmount) external;\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IFastBridgeV2Errors.sol\n\ninterface IFastBridgeV2Errors {\n error AmountIncorrect();\n error ChainIncorrect();\n error ExclusivityParamsIncorrect();\n error MsgValueIncorrect();\n error SenderIncorrect();\n error StatusIncorrect();\n error TokenNotContract();\n error ZapDataLengthAboveMax();\n error ZapNativeNotSupported();\n error ZeroAddress();\n\n error RecipientIncorrectReturnValue();\n error RecipientNoReturnValue();\n\n error DeadlineExceeded();\n error DeadlineNotExceeded();\n error DeadlineTooShort();\n error DisputePeriodNotPassed();\n error DisputePeriodPassed();\n error ExclusivityPeriodNotPassed();\n\n error TransactionRelayed();\n}\n\n// contracts/interfaces/IMulticallTarget.sol\n\n/// @notice Interface for a contract that can be called multiple times by the same caller. Inspired by MulticallV3:\n/// https://github.com/mds1/multicall/blob/master/src/Multicall3.sol\ninterface IMulticallTarget {\n struct Result {\n bool success;\n bytes returnData;\n }\n\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external;\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results);\n}\n\n// contracts/interfaces/IZapRecipient.sol\n\ninterface IZapRecipient {\n function zap(address token, uint256 amount, bytes memory zapData) external payable returns (bytes4);\n}\n\n// contracts/libs/Errors.sol\n\nerror DeadlineExceeded();\nerror DeadlineNotExceeded();\nerror DeadlineTooShort();\nerror InsufficientOutputAmount();\n\nerror MsgValueIncorrect();\nerror PoolNotFound();\nerror TokenAddressMismatch();\nerror TokenNotContract();\nerror TokenNotETH();\nerror TokensIdentical();\n\nerror ChainIncorrect();\nerror AmountIncorrect();\nerror ZeroAddress();\n\nerror DisputePeriodNotPassed();\nerror DisputePeriodPassed();\nerror SenderIncorrect();\nerror StatusIncorrect();\nerror TransactionIdIncorrect();\nerror TransactionRelayed();\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// contracts/interfaces/IFastBridgeV2.sol\n\ninterface IFastBridgeV2 is IFastBridge {\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n struct BridgeTxDetails {\n BridgeStatus status;\n uint32 destChainId;\n uint56 proofBlockTimestamp;\n address proofRelayer;\n }\n\n struct BridgeRelay {\n uint48 blockNumber;\n uint48 blockTimestamp;\n address relayer;\n }\n\n /// @notice New params introduced in the FastBridgeV2.\n /// We are passing fields from the older BridgeParams struct outside of this struct\n /// for backwards compatibility.\n /// Note: quoteRelayer and quoteExclusivitySeconds are either both zero (indicating no exclusivity)\n /// or both non-zero (indicating exclusivity for the given period).\n /// Note: zapNative \u003e 0 can NOT be used with destToken = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE (native token)\n /// @param quoteRelayer Relayer that provided the quote for the transaction\n /// @param quoteExclusivitySeconds Period of time the quote relayer is guaranteed exclusivity after user's deposit\n /// @param quoteId Unique quote identifier used for tracking the quote\n /// @param zapNative ETH value to send to the recipient (if any)\n /// @param zapData Parameters for the Zap to the destination recipient (if any)\n struct BridgeParamsV2 {\n address quoteRelayer;\n int256 quoteExclusivitySeconds;\n bytes quoteId;\n uint256 zapNative;\n bytes zapData;\n }\n\n /// @notice Updated bridge transaction struct to include parameters introduced in FastBridgeV2.\n /// Note: only `exclusivityRelayer` can fill such a transaction until `exclusivityEndTime`.\n struct BridgeTransactionV2 {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n // Note: sendChainGas flag from V1 is deprecated\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n address exclusivityRelayer;\n uint256 exclusivityEndTime;\n uint256 zapNative; // ETH value to send to the recipient (if any)\n bytes zapData; // data to pass for the Zap action (if any)\n }\n\n event BridgeQuoteDetails(bytes32 indexed transactionId, bytes quoteId);\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability\n /// to provide temporary exclusivity fill rights for the quote relayer.\n /// @param params The parameters required to bridge\n /// @param paramsV2 The parameters for exclusivity fill rights (optional, can be left empty)\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function relay(bytes memory request, address relayer) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param transactionId The transaction id associated with the encoded bridge transaction to prove\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital.\n /// @notice Can only send funds to the relayer address on the proof.\n /// @param request The encoded bridge transaction to claim on origin chain\n function claim(bytes memory request) external;\n /// @notice Checks if a transaction has been relayed\n /// @param transactionId The ID of the transaction to check\n /// @return True if the transaction has been relayed, false otherwise\n function bridgeRelays(bytes32 transactionId) external view returns (bool);\n\n /// @notice Returns the status of a bridge transaction\n /// @param transactionId The ID of the bridge transaction\n /// @return BridgeStatus Status of the bridge transaction\n function bridgeStatuses(bytes32 transactionId) external view returns (BridgeStatus);\n\n /// @notice Returns the timestamp and relayer of a bridge proof\n /// @param transactionId The ID of the bridge transaction\n /// @return timestamp The timestamp of the bridge proof\n /// @return relayer The relayer address of the bridge proof\n function bridgeProofs(bytes32 transactionId) external view returns (uint96 timestamp, address relayer);\n\n /// @notice Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\n /// @param request The bridge request to decode\n function getBridgeTransactionV2(bytes memory request) external view returns (BridgeTransactionV2 memory);\n}\n\n// contracts/utils/MulticallTarget.sol\n\n// solhint-disable avoid-low-level-calls\n/// @notice Template for a contract that supports batched calls (preserving the msg.sender).\n/// Only calls with zero msg.value could be batched.\nabstract contract MulticallTarget is IMulticallTarget {\n error MulticallTarget__UndeterminedRevert();\n\n /// @notice Perform a batched call to this contract, preserving the msg.sender.\n /// The return data from each call is discarded.\n /// @dev The method is non-payable, so only calls with `msg.value == 0` could be batched.\n /// It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag.\n /// Otherwise, the whole batch call will be reverted with the original revert reason.\n /// @param data List of abi-encoded calldata for the calls to perform.\n /// @param ignoreReverts Whether to ignore the revert errors from the calls.\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external {\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\n if (!success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(result);\n }\n }\n }\n\n /// @notice Perform a batched call to this contract, preserving the msg.sender.\n /// The return data from each call is preserved.\n /// @dev The method is non-payable, so only calls with `msg.value == 0` could be batched.\n /// It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag.\n /// Otherwise, the whole batch call will be reverted with the original revert reason.\n /// @param data List of abi-encoded calldata for the calls to perform.\n /// @param ignoreReverts Whether to ignore the revert errors from the calls.\n /// @return results List of results from the calls: `(success, returnData)`.\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results)\n {\n results = new Result[](data.length);\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (results[i].success, results[i].returnData) = address(this).delegatecall(data[i]);\n if (!results[i].success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(results[i].returnData);\n }\n }\n }\n\n /// @dev Bubbles the revert message from the underlying call.\n /// Note: preserves the same custom error or revert string, if one was used.\n /// Source: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v5.0.2/contracts/utils/Address.sol#L143-L158\n function _bubbleRevert(bytes memory returnData) internal pure {\n // Look for revert reason and bubble it up if present\n if (returnData.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n // solhint-disable-next-line no-inline-assembly\n assembly {\n let returndata_size := mload(returnData)\n revert(add(32, returnData), returndata_size)\n }\n } else {\n revert MulticallTarget__UndeterminedRevert();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// contracts/libs/BridgeTransactionV2.sol\n\n// solhint-disable no-inline-assembly\nlibrary BridgeTransactionV2Lib {\n uint16 internal constant VERSION = 2;\n\n // Offsets of the fields in the packed BridgeTransactionV2 struct\n // uint16 version [000 .. 002)\n // uint32 originChainId [002 .. 006)\n // uint32 destChainId [006 .. 010)\n // address originSender [010 .. 030)\n // address destRecipient [030 .. 050)\n // address originToken [050 .. 070)\n // address destToken [070 .. 090)\n // uint256 originAmount [090 .. 122)\n // uint256 destAmount [122 .. 154)\n // uint256 originFeeAmount [154 .. 186)\n // uint256 deadline [186 .. 218)\n // uint256 nonce [218 .. 250)\n // address exclusivityRelayer [250 .. 270)\n // uint256 exclusivityEndTime [270 .. 302)\n // uint256 zapNative [302 .. 334)\n // bytes zapData [334 .. ***)\n\n // forgefmt: disable-start\n uint256 private constant OFFSET_ORIGIN_CHAIN_ID = 2;\n uint256 private constant OFFSET_DEST_CHAIN_ID = 6;\n uint256 private constant OFFSET_ORIGIN_SENDER = 10;\n uint256 private constant OFFSET_DEST_RECIPIENT = 30;\n uint256 private constant OFFSET_ORIGIN_TOKEN = 50;\n uint256 private constant OFFSET_DEST_TOKEN = 70;\n uint256 private constant OFFSET_ORIGIN_AMOUNT = 90;\n uint256 private constant OFFSET_DEST_AMOUNT = 122;\n uint256 private constant OFFSET_ORIGIN_FEE_AMOUNT = 154;\n uint256 private constant OFFSET_DEADLINE = 186;\n uint256 private constant OFFSET_NONCE = 218;\n uint256 private constant OFFSET_EXCLUSIVITY_RELAYER = 250;\n uint256 private constant OFFSET_EXCLUSIVITY_END_TIME = 270;\n uint256 private constant OFFSET_ZAP_NATIVE = 302;\n uint256 private constant OFFSET_ZAP_DATA = 334;\n // forgefmt: disable-end\n\n error BridgeTransactionV2__InvalidEncodedTx();\n error BridgeTransactionV2__UnsupportedVersion(uint16 version);\n\n /// @notice Validates the encoded transaction to be a tightly packed encoded payload for BridgeTransactionV2.\n /// @dev Checks the minimum length and the version, use this function before decoding any of the fields.\n function validateV2(bytes calldata encodedTx) internal pure {\n // Check the minimum length: must at least include all static fields.\n if (encodedTx.length \u003c OFFSET_ZAP_DATA) revert BridgeTransactionV2__InvalidEncodedTx();\n // Once we validated the length, we can be sure that the version field is present.\n uint16 version_ = version(encodedTx);\n if (version_ != VERSION) revert BridgeTransactionV2__UnsupportedVersion(version_);\n }\n\n /// @notice Encodes the BridgeTransactionV2 struct by tightly packing the fields.\n /// @dev `abi.decode` will not work as a result of the tightly packed fields. Use `decodeV2` to decode instead.\n function encodeV2(IFastBridgeV2.BridgeTransactionV2 memory bridgeTx) internal pure returns (bytes memory) {\n // We split the encoding into two parts to avoid stack-too-deep error\n bytes memory firstPart = abi.encodePacked(\n VERSION,\n bridgeTx.originChainId,\n bridgeTx.destChainId,\n bridgeTx.originSender,\n bridgeTx.destRecipient,\n bridgeTx.originToken,\n bridgeTx.destToken,\n bridgeTx.originAmount\n );\n return abi.encodePacked(\n firstPart,\n bridgeTx.destAmount,\n bridgeTx.originFeeAmount,\n // Note: we skip the deprecated `sendChainGas` flag, which was present in BridgeTransaction V1\n bridgeTx.deadline,\n bridgeTx.nonce,\n // New V2 fields: exclusivity\n bridgeTx.exclusivityRelayer,\n bridgeTx.exclusivityEndTime,\n // New V2 fields: Zap\n bridgeTx.zapNative,\n bridgeTx.zapData\n );\n }\n\n /// @notice Decodes the BridgeTransactionV2 struct from the encoded transaction.\n /// @dev Encoded BridgeTransactionV2 struct must be tightly packed.\n /// Use `validateV2` before decoding to ensure the encoded transaction is valid.\n function decodeV2(bytes calldata encodedTx)\n internal\n pure\n returns (IFastBridgeV2.BridgeTransactionV2 memory bridgeTx)\n {\n bridgeTx.originChainId = originChainId(encodedTx);\n bridgeTx.destChainId = destChainId(encodedTx);\n bridgeTx.originSender = originSender(encodedTx);\n bridgeTx.destRecipient = destRecipient(encodedTx);\n bridgeTx.originToken = originToken(encodedTx);\n bridgeTx.destToken = destToken(encodedTx);\n bridgeTx.originAmount = originAmount(encodedTx);\n bridgeTx.destAmount = destAmount(encodedTx);\n bridgeTx.originFeeAmount = originFeeAmount(encodedTx);\n bridgeTx.deadline = deadline(encodedTx);\n bridgeTx.nonce = nonce(encodedTx);\n bridgeTx.exclusivityRelayer = exclusivityRelayer(encodedTx);\n bridgeTx.exclusivityEndTime = exclusivityEndTime(encodedTx);\n bridgeTx.zapNative = zapNative(encodedTx);\n bridgeTx.zapData = zapData(encodedTx);\n }\n\n /// @notice Extracts the version from the encoded transaction.\n function version(bytes calldata encodedTx) internal pure returns (uint16 version_) {\n // Load 32 bytes from the start and shift it 240 bits to the right to get the highest 16 bits.\n assembly {\n version_ := shr(240, calldataload(encodedTx.offset))\n }\n }\n\n /// @notice Extracts the origin chain ID from the encoded transaction.\n function originChainId(bytes calldata encodedTx) internal pure returns (uint32 originChainId_) {\n // Load 32 bytes from the offset and shift it 224 bits to the right to get the highest 32 bits.\n assembly {\n originChainId_ := shr(224, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_CHAIN_ID)))\n }\n }\n\n /// @notice Extracts the destination chain ID from the encoded transaction.\n function destChainId(bytes calldata encodedTx) internal pure returns (uint32 destChainId_) {\n // Load 32 bytes from the offset and shift it 224 bits to the right to get the highest 32 bits.\n assembly {\n destChainId_ := shr(224, calldataload(add(encodedTx.offset, OFFSET_DEST_CHAIN_ID)))\n }\n }\n\n /// @notice Extracts the origin sender from the encoded transaction.\n function originSender(bytes calldata encodedTx) internal pure returns (address originSender_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n originSender_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_SENDER)))\n }\n }\n\n /// @notice Extracts the destination recipient from the encoded transaction.\n function destRecipient(bytes calldata encodedTx) internal pure returns (address destRecipient_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n destRecipient_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_DEST_RECIPIENT)))\n }\n }\n\n /// @notice Extracts the origin token from the encoded transaction.\n function originToken(bytes calldata encodedTx) internal pure returns (address originToken_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n originToken_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_TOKEN)))\n }\n }\n\n /// @notice Extracts the destination token from the encoded transaction.\n function destToken(bytes calldata encodedTx) internal pure returns (address destToken_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n destToken_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_DEST_TOKEN)))\n }\n }\n\n /// @notice Extracts the origin amount from the encoded transaction.\n function originAmount(bytes calldata encodedTx) internal pure returns (uint256 originAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n originAmount_ := calldataload(add(encodedTx.offset, OFFSET_ORIGIN_AMOUNT))\n }\n }\n\n /// @notice Extracts the destination amount from the encoded transaction.\n function destAmount(bytes calldata encodedTx) internal pure returns (uint256 destAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n destAmount_ := calldataload(add(encodedTx.offset, OFFSET_DEST_AMOUNT))\n }\n }\n\n /// @notice Extracts the origin fee amount from the encoded transaction.\n function originFeeAmount(bytes calldata encodedTx) internal pure returns (uint256 originFeeAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n originFeeAmount_ := calldataload(add(encodedTx.offset, OFFSET_ORIGIN_FEE_AMOUNT))\n }\n }\n\n /// @notice Extracts the deadline from the encoded transaction.\n function deadline(bytes calldata encodedTx) internal pure returns (uint256 deadline_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n deadline_ := calldataload(add(encodedTx.offset, OFFSET_DEADLINE))\n }\n }\n\n /// @notice Extracts the nonce from the encoded transaction.\n function nonce(bytes calldata encodedTx) internal pure returns (uint256 nonce_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n nonce_ := calldataload(add(encodedTx.offset, OFFSET_NONCE))\n }\n }\n\n /// @notice Extracts the exclusivity relayer from the encoded transaction.\n function exclusivityRelayer(bytes calldata encodedTx) internal pure returns (address exclusivityRelayer_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n exclusivityRelayer_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_EXCLUSIVITY_RELAYER)))\n }\n }\n\n /// @notice Extracts the exclusivity end time from the encoded transaction.\n function exclusivityEndTime(bytes calldata encodedTx) internal pure returns (uint256 exclusivityEndTime_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n exclusivityEndTime_ := calldataload(add(encodedTx.offset, OFFSET_EXCLUSIVITY_END_TIME))\n }\n }\n\n /// @notice Extracts the Zap's native value from the encoded transaction.\n function zapNative(bytes calldata encodedTx) internal pure returns (uint256 zapNative_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n zapNative_ := calldataload(add(encodedTx.offset, OFFSET_ZAP_NATIVE))\n }\n }\n\n /// @notice Extracts the Zap's data from the encoded transaction.\n function zapData(bytes calldata encodedTx) internal pure returns (bytes calldata zapData_) {\n zapData_ = encodedTx[OFFSET_ZAP_DATA:];\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// contracts/libs/UniversalToken.sol\n\nlibrary UniversalTokenLib {\n using SafeERC20 for IERC20;\n\n address internal constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Transfers tokens to the given account. Reverts if transfer is not successful.\n /// @dev This might trigger fallback, if ETH is transferred to the contract.\n /// Make sure this can not lead to reentrancy attacks.\n function universalTransfer(address token, address to, uint256 value) internal {\n // Don't do anything, if need to send tokens to this address\n if (to == address(this)) return;\n // Don't do anything, if trying to send zero value\n if (value == 0) return;\n if (token == ETH_ADDRESS) {\n /// @dev Note: this can potentially lead to executing code in `to`.\n // solhint-disable-next-line avoid-low-level-calls\n (bool success,) = to.call{value: value}(\"\");\n require(success, \"ETH transfer failed\");\n } else {\n IERC20(token).safeTransfer(to, value);\n }\n }\n\n /// @notice Issues an infinite allowance to the spender, if the current allowance is insufficient\n /// to spend the given amount.\n function universalApproveInfinity(address token, address spender, uint256 amountToSpend) internal {\n // ETH Chad doesn't require your approval\n if (token == ETH_ADDRESS) return;\n // No-op if allowance is already sufficient\n uint256 allowance = IERC20(token).allowance(address(this), spender);\n if (allowance \u003e= amountToSpend) return;\n // Otherwise, reset approval to 0 and set to max allowance\n if (allowance \u003e 0) IERC20(token).safeDecreaseAllowance(spender, allowance);\n IERC20(token).safeIncreaseAllowance(spender, type(uint256).max);\n }\n\n /// @notice Returns the balance of the given token (or native ETH) for the given account.\n function universalBalanceOf(address token, address account) internal view returns (uint256) {\n if (token == ETH_ADDRESS) {\n return account.balance;\n } else {\n return IERC20(token).balanceOf(account);\n }\n }\n\n /// @dev Checks that token is a contract and not ETH_ADDRESS.\n function assertIsContract(address token) internal view {\n // Check that ETH_ADDRESS was not used (in case this is a predeploy on any of the chains)\n if (token == UniversalTokenLib.ETH_ADDRESS) revert TokenNotContract();\n // Check that token is not an EOA\n if (token.code.length == 0) revert TokenNotContract();\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/Admin.sol\n\ncontract Admin is IAdmin, AccessControlEnumerable {\n using UniversalTokenLib for address;\n\n bytes32 public constant RELAYER_ROLE = keccak256(\"RELAYER_ROLE\");\n bytes32 public constant REFUNDER_ROLE = keccak256(\"REFUNDER_ROLE\");\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n uint256 public constant FEE_BPS = 1e6;\n uint256 public constant FEE_RATE_MAX = 0.01e6; // max 1% on origin amount\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Chain gas amount to forward as rebate if requested\n uint256 public chainGasAmount;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n }\n\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n require(newFeeRate \u003c= FEE_RATE_MAX, \"newFeeRate \u003e max\");\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n token.universalTransfer(recipient, feeAmount);\n emit FeesSwept(token, recipient, feeAmount);\n }\n\n function setChainGasAmount(uint256 newChainGasAmount) external onlyRole(GOVERNOR_ROLE) {\n uint256 oldChainGasAmount = chainGasAmount;\n chainGasAmount = newChainGasAmount;\n emit ChainGasAmountUpdated(oldChainGasAmount, newChainGasAmount);\n }\n}\n\n// contracts/FastBridgeV2.sol\n\n/// @notice FastBridgeV2 is a contract for bridging tokens across chains.\ncontract FastBridgeV2 is Admin, MulticallTarget, IFastBridgeV2, IFastBridgeV2Errors {\n using BridgeTransactionV2Lib for bytes;\n using SafeERC20 for IERC20;\n\n /// @notice Address reserved for native gas token (ETH on Ethereum and most L2s, AVAX on Avalanche, etc)\n address public constant NATIVE_GAS_TOKEN = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Delay for a transaction after which it could be permisionlessly refunded\n uint256 public constant REFUND_DELAY = 7 days;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n /// @notice Maximum length of accepted zapData\n uint256 public constant MAX_ZAP_DATA_LENGTH = 2 ** 16 - 1;\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeTxDetails) public bridgeTxDetails;\n /// @notice Relay details on destination chain\n mapping(bytes32 =\u003e BridgeRelay) public bridgeRelayDetails;\n /// @notice Unique bridge nonces tracked per originSender\n mapping(address =\u003e uint256) public senderNonces;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Replaced by senderNonces\n uint256 public immutable nonce = 0;\n /// @notice the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n bridge({\n params: params,\n paramsV2: BridgeParamsV2({\n quoteRelayer: address(0),\n quoteExclusivitySeconds: 0,\n quoteId: bytes(\"\"),\n zapNative: 0,\n zapData: bytes(\"\")\n })\n });\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes calldata request) external payable {\n // relay override will validate the request\n relay({request: request, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes calldata request, bytes32 destTxHash) external {\n request.validateV2();\n prove({transactionId: keccak256(request), destTxHash: destTxHash, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridgeV2\n function claim(bytes calldata request) external {\n // claim override will validate the request\n claim({request: request, to: address(0)});\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Aggregate the read operations from the same storage slot\n address disputedRelayer = $.proofRelayer;\n BridgeStatus status = $.status;\n uint56 proofBlockTimestamp = $.proofBlockTimestamp;\n // Can only dispute a RELAYER_PROVED transaction within the dispute period\n if (status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(proofBlockTimestamp) \u003e DISPUTE_PERIOD) {\n revert DisputePeriodPassed();\n }\n // Update status to REQUESTED and delete the disputed proof details\n // Note: these are storage writes\n $.status = BridgeStatus.REQUESTED;\n $.proofRelayer = address(0);\n $.proofBlockTimestamp = 0;\n\n emit BridgeProofDisputed(transactionId, disputedRelayer);\n }\n\n /// @inheritdoc IFastBridge\n function refund(bytes calldata request) external {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Can only refund a REQUESTED transaction after its deadline expires\n if ($.status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n uint256 deadline = request.deadline();\n // Permissionless refund is only allowed after REFUND_DELAY on top of the deadline\n if (!hasRole(REFUNDER_ROLE, msg.sender)) deadline += REFUND_DELAY;\n if (block.timestamp \u003c= deadline) revert DeadlineNotExceeded();\n // Update status to REFUNDED and return the full amount (collateral + protocol fees) to the original sender.\n // The protocol fees are only updated when the transaction is claimed, so we don't need to update them here.\n // Note: this is a storage write\n $.status = BridgeStatus.REFUNDED;\n\n address to = request.originSender();\n address token = request.originToken();\n uint256 amount = request.originAmount() + request.originFeeAmount();\n // Emit the event before any external calls\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n // Complete the user refund as the last transaction action\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(to), amount);\n } else {\n IERC20(token).safeTransfer(to, amount);\n }\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // The correct relayer can only claim a RELAYER_PROVED transaction after the dispute period\n if ($.status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if ($.proofRelayer != relayer) revert SenderIncorrect();\n return _timeSince($.proofBlockTimestamp) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n /// @dev This method is added to achieve backwards compatibility with decoding requests into V1 structs:\n /// - `zapNative` is partially reported as a zero/non-zero flag\n /// - `zapData` is ignored\n /// In order to process all kinds of requests use getBridgeTransactionV2 instead.\n function getBridgeTransaction(bytes calldata request) external view returns (BridgeTransaction memory) {\n // Try decoding into V2 struct first. This will revert if V1 struct is passed\n try this.getBridgeTransactionV2(request) returns (BridgeTransactionV2 memory txV2) {\n // Note: we entirely ignore the zapData field, as it was not present in V1\n return BridgeTransaction({\n originChainId: txV2.originChainId,\n destChainId: txV2.destChainId,\n originSender: txV2.originSender,\n destRecipient: txV2.destRecipient,\n originToken: txV2.originToken,\n destToken: txV2.destToken,\n originAmount: txV2.originAmount,\n destAmount: txV2.destAmount,\n originFeeAmount: txV2.originFeeAmount,\n sendChainGas: txV2.zapNative != 0,\n deadline: txV2.deadline,\n nonce: txV2.nonce\n });\n } catch {\n // Fallback to V1 struct\n return abi.decode(request, (BridgeTransaction));\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function getBridgeTransactionV2(bytes calldata request) external pure returns (BridgeTransactionV2 memory) {\n request.validateV2();\n return BridgeTransactionV2Lib.decodeV2(request);\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) public payable {\n int256 exclusivityEndTime = 0;\n // if relayer exclusivity is not intended for this bridge, set exclusivityEndTime to static zero\n // otherwise, set exclusivity to expire at the current block ts offset by quoteExclusivitySeconds\n if (paramsV2.quoteRelayer != address(0)) {\n exclusivityEndTime = int256(block.timestamp) + paramsV2.quoteExclusivitySeconds;\n }\n _validateBridgeParams(params, paramsV2, exclusivityEndTime);\n\n // transfer tokens to bridge contract\n /// @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _takeBridgedUserAsset(params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) {\n originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n }\n\n // set status to requested\n bytes memory request = BridgeTransactionV2Lib.encodeV2(\n BridgeTransactionV2({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n deadline: params.deadline,\n nonce: senderNonces[params.sender]++, // increment nonce on every bridge\n exclusivityRelayer: paramsV2.quoteRelayer,\n // We checked exclusivityEndTime to be in range [0 .. params.deadline] above, so can safely cast\n exclusivityEndTime: uint256(exclusivityEndTime),\n zapNative: paramsV2.zapNative,\n zapData: paramsV2.zapData\n })\n );\n bytes32 transactionId = keccak256(request);\n // Note: the tx status will be updated throughout the tx lifecycle, while destChainId is set once here\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n bridgeTxDetails[transactionId].destChainId = params.dstChainId;\n\n emit BridgeRequested({\n transactionId: transactionId,\n sender: params.sender,\n request: request,\n destChainId: params.dstChainId,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n sendChainGas: paramsV2.zapNative != 0\n });\n emit BridgeQuoteDetails(transactionId, paramsV2.quoteId);\n }\n\n /// @inheritdoc IFastBridgeV2\n function relay(bytes calldata request, address relayer) public payable {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n _validateRelayParams(request, transactionId, relayer);\n // mark bridge transaction as relayed\n bridgeRelayDetails[transactionId] =\n BridgeRelay({blockNumber: uint48(block.number), blockTimestamp: uint48(block.timestamp), relayer: relayer});\n\n // transfer tokens to recipient on destination chain and trigger Zap if requested\n address to = request.destRecipient();\n address token = request.destToken();\n uint256 amount = request.destAmount();\n uint256 zapNative = request.zapNative();\n\n // Emit the event before any external calls\n emit BridgeRelayed({\n transactionId: transactionId,\n relayer: relayer,\n to: to,\n originChainId: request.originChainId(),\n originToken: request.originToken(),\n destToken: token,\n originAmount: request.originAmount(),\n destAmount: amount,\n chainGasAmount: zapNative\n });\n\n // All state changes have been done at this point, can proceed to the external calls.\n // This follows the checks-effects-interactions pattern to mitigate potential reentrancy attacks.\n if (token == NATIVE_GAS_TOKEN) {\n // For the native gas token, additional zapNative is not allowed\n if (zapNative != 0) revert ZapNativeNotSupported();\n // Check that the correct msg.value was sent\n if (msg.value != amount) revert MsgValueIncorrect();\n // Don't do a native transfer yet: we will handle it alongside the Zap below\n } else {\n // For ERC20s, we check that the correct msg.value was sent\n if (msg.value != zapNative) revert MsgValueIncorrect();\n // We need to transfer the tokens from the Relayer to the recipient first before performing an\n // optional post-transfer Zap.\n IERC20(token).safeTransferFrom(msg.sender, to, amount);\n }\n // At this point we have done:\n // - Transferred the requested amount of ERC20 tokens to the recipient.\n // At this point we have confirmed:\n // - For ERC20s: msg.value matches the requested zapNative amount.\n // - For the native gas token: msg.value matches the requested destAmount.\n // Remaining optional things to do:\n // - Forward the full msg.value to the recipient (if non-zero).\n // - Trigger a Zap (if zapData is present).\n bytes calldata zapData = request.zapData();\n if (zapData.length != 0) {\n // Zap Data is present: Zap has been requested by the recipient. Trigger it forwarding the full msg.value.\n\n // Note: if token has a fee on transfers, the recipient will have received less than `amount`.\n // This is a very niche edge case and should be handled by the recipient contract.\n _triggerZapWithChecks({recipient: to, token: token, amount: amount, zapData: zapData});\n } else if (msg.value != 0) {\n // Zap Data is missing, but msg.value was sent. This could happen in two different cases:\n // - Relay with the native gas token is happening.\n // - Relay with ERC20 is happening, with a `zapNative \u003e 0` request.\n // In both cases, we need to transfer the full msg.value to the recipient.\n Address.sendValue(payable(to), msg.value);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) public onlyRole(RELAYER_ROLE) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n\n // Can only prove a REQUESTED transaction\n if ($.status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n // Update status to RELAYER_PROVED and store the proof details\n // Note: these are storage writes\n $.status = BridgeStatus.RELAYER_PROVED;\n $.proofBlockTimestamp = uint56(block.timestamp);\n $.proofRelayer = relayer;\n\n emit BridgeProofProvided(transactionId, relayer, destTxHash);\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes calldata request, address to) public {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Aggregate the read operations from the same storage slot\n address proofRelayer = $.proofRelayer;\n BridgeStatus status = $.status;\n uint56 proofBlockTimestamp = $.proofBlockTimestamp;\n\n // Can only claim a RELAYER_PROVED transaction after the dispute period\n if (status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(proofBlockTimestamp) \u003c= DISPUTE_PERIOD) {\n revert DisputePeriodNotPassed();\n }\n\n if (to == address(0)) {\n // Anyone could claim the funds to the proven relayer on their behalf\n to = proofRelayer;\n } else if (proofRelayer != msg.sender) {\n // Only the proven relayer could specify an address to claim the funds to\n revert SenderIncorrect();\n }\n\n // Update status to RELAYER_CLAIMED and transfer the origin collateral to the specified claim address\n // Note: this is a storage write\n $.status = BridgeStatus.RELAYER_CLAIMED;\n\n address token = request.originToken();\n uint256 amount = request.originAmount();\n // Update protocol fees if origin fee amount exists\n uint256 originFeeAmount = request.originFeeAmount();\n if (originFeeAmount \u003e 0) protocolFees[token] += originFeeAmount;\n // Emit the event before any external calls\n emit BridgeDepositClaimed(transactionId, proofRelayer, to, token, amount);\n // Complete the relayer claim as the last transaction action\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(to), amount);\n } else {\n IERC20(token).safeTransfer(to, amount);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeStatuses(bytes32 transactionId) public view returns (BridgeStatus status) {\n return bridgeTxDetails[transactionId].status;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeProofs(bytes32 transactionId) public view returns (uint96 timestamp, address relayer) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n\n timestamp = $.proofBlockTimestamp;\n relayer = $.proofRelayer;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeRelays(bytes32 transactionId) public view returns (bool) {\n // has this transactionId been relayed?\n return bridgeRelayDetails[transactionId].relayer != address(0);\n }\n\n /// @notice Takes the bridged asset from the user into FastBridgeV2 custody. It will be later\n /// claimed by the relayer who completed the relay on destination chain, or refunded back to the user,\n /// should no one complete the relay.\n function _takeBridgedUserAsset(address token, uint256 amount) internal returns (uint256 amountTaken) {\n if (token == NATIVE_GAS_TOKEN) {\n // For the native gas token, we just need to check that the supplied msg.value is correct.\n // Supplied `msg.value` is already in FastBridgeV2 custody.\n if (amount != msg.value) revert MsgValueIncorrect();\n amountTaken = msg.value;\n } else {\n // For ERC20s, token is explicitly transferred from the user to FastBridgeV2.\n // We don't allow non-zero `msg.value` to avoid extra funds from being stuck in FastBridgeV2.\n if (msg.value != 0) revert MsgValueIncorrect();\n // Throw an explicit error if the provided token address is not a contract\n if (token.code.length == 0) revert TokenNotContract();\n amountTaken = IERC20(token).balanceOf(address(this));\n IERC20(token).safeTransferFrom(msg.sender, address(this), amount);\n // Use the balance difference as the amount taken in case of fee on transfer tokens.\n amountTaken = IERC20(token).balanceOf(address(this)) - amountTaken;\n }\n }\n\n /// @notice Calls the Recipient's hook function with the specified zapData and performs\n /// all the necessary checks for the returned value.\n function _triggerZapWithChecks(address recipient, address token, uint256 amount, bytes calldata zapData) internal {\n // This will bubble any revert messages from the hook function\n bytes memory returnData = Address.functionCallWithValue({\n target: recipient,\n data: abi.encodeCall(IZapRecipient.zap, (token, amount, zapData)),\n // Note: see `relay()` for reasoning behind passing msg.value\n value: msg.value\n });\n // Explicit revert if no return data at all\n if (returnData.length == 0) revert RecipientNoReturnValue();\n // Check that exactly a single return value was returned\n if (returnData.length != 32) revert RecipientIncorrectReturnValue();\n // Return value should be abi-encoded hook function selector\n if (bytes32(returnData) != bytes32(IZapRecipient.zap.selector)) {\n revert RecipientIncorrectReturnValue();\n }\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint56(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint56).max but\n /// proof.timestamp \u003c type(uint56).max via unchecked statement\n /// @param proofBlockTimestamp The bridge proof block timestamp\n /// @return delta Time delta since proof submitted\n function _timeSince(uint56 proofBlockTimestamp) internal view returns (uint256 delta) {\n unchecked {\n delta = uint56(block.timestamp) - proofBlockTimestamp;\n }\n }\n\n /// @notice Performs all the necessary checks for a bridge to happen.\n /// @dev There's no good way to refactor this function to reduce cyclomatic complexity due to\n /// the number of checks that need to be performed, so we skip the code-complexity rule here.\n // solhint-disable-next-line code-complexity\n function _validateBridgeParams(\n BridgeParams memory params,\n BridgeParamsV2 memory paramsV2,\n int256 exclusivityEndTime\n )\n internal\n view\n {\n // Check V1 (legacy) params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.sender == address(0) || params.to == address(0)) revert ZeroAddress();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n // Check V2 params\n if (paramsV2.zapData.length \u003e MAX_ZAP_DATA_LENGTH) revert ZapDataLengthAboveMax();\n if (paramsV2.zapNative != 0 \u0026\u0026 params.destToken == NATIVE_GAS_TOKEN) {\n revert ZapNativeNotSupported();\n }\n // exclusivityEndTime must be in range [0 .. params.deadline]\n if (exclusivityEndTime \u003c 0 || exclusivityEndTime \u003e int256(params.deadline)) {\n revert ExclusivityParamsIncorrect();\n }\n }\n\n /// @notice Performs all the necessary checks for a relay to happen.\n function _validateRelayParams(bytes calldata request, bytes32 transactionId, address relayer) internal view {\n if (relayer == address(0)) revert ZeroAddress();\n // Check if the transaction has already been relayed\n if (bridgeRelays(transactionId)) revert TransactionRelayed();\n if (request.destChainId() != block.chainid) revert ChainIncorrect();\n // Check the deadline for relay to happen\n if (block.timestamp \u003e request.deadline()) revert DeadlineExceeded();\n // Check the exclusivity period, if it is still ongoing\n address exclRelayer = request.exclusivityRelayer();\n if (exclRelayer != address(0) \u0026\u0026 exclRelayer != relayer \u0026\u0026 block.timestamp \u003c= request.exclusivityEndTime()) {\n revert ExclusivityPeriodNotPassed();\n }\n }\n}\n","language":"Solidity","languageVersion":"0.8.24","compilerVersion":"0.8.24","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"","srcMapRuntime":"","abiDefinition":[{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"relayer","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"BridgeDepositClaimed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"BridgeDepositRefunded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"relayer","type":"address"}],"name":"BridgeProofDisputed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"relayer","type":"address"},{"indexed":false,"internalType":"bytes32","name":"transactionHash","type":"bytes32"}],"name":"BridgeProofProvided","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"relayer","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint32","name":"originChainId","type":"uint32"},{"indexed":false,"internalType":"address","name":"originToken","type":"address"},{"indexed":false,"internalType":"address","name":"destToken","type":"address"},{"indexed":false,"internalType":"uint256","name":"originAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"destAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"chainGasAmount","type":"uint256"}],"name":"BridgeRelayed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"bytes","name":"request","type":"bytes"},{"indexed":false,"internalType":"uint32","name":"destChainId","type":"uint32"},{"indexed":false,"internalType":"address","name":"originToken","type":"address"},{"indexed":false,"internalType":"address","name":"destToken","type":"address"},{"indexed":false,"internalType":"uint256","name":"originAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"destAmount","type":"uint256"},{"indexed":false,"internalType":"bool","name":"sendChainGas","type":"bool"}],"name":"BridgeRequested","type":"event"},{"inputs":[{"components":[{"internalType":"uint32","name":"dstChainId","type":"uint32"},{"internalType":"address","name":"sender","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"address","name":"originToken","type":"address"},{"internalType":"address","name":"destToken","type":"address"},{"internalType":"uint256","name":"originAmount","type":"uint256"},{"internalType":"uint256","name":"destAmount","type":"uint256"},{"internalType":"bool","name":"sendChainGas","type":"bool"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"internalType":"struct IFastBridge.BridgeParams","name":"params","type":"tuple"}],"name":"bridge","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"internalType":"address","name":"relayer","type":"address"}],"name":"canClaim","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"},{"internalType":"address","name":"to","type":"address"}],"name":"claim","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"transactionId","type":"bytes32"}],"name":"dispute","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"}],"name":"getBridgeTransaction","outputs":[{"components":[{"internalType":"uint32","name":"originChainId","type":"uint32"},{"internalType":"uint32","name":"destChainId","type":"uint32"},{"internalType":"address","name":"originSender","type":"address"},{"internalType":"address","name":"destRecipient","type":"address"},{"internalType":"address","name":"originToken","type":"address"},{"internalType":"address","name":"destToken","type":"address"},{"internalType":"uint256","name":"originAmount","type":"uint256"},{"internalType":"uint256","name":"destAmount","type":"uint256"},{"internalType":"uint256","name":"originFeeAmount","type":"uint256"},{"internalType":"bool","name":"sendChainGas","type":"bool"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint256","name":"nonce","type":"uint256"}],"internalType":"struct IFastBridge.BridgeTransaction","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"},{"internalType":"bytes32","name":"destTxHash","type":"bytes32"}],"name":"prove","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"}],"name":"refund","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"}],"name":"relay","outputs":[],"stateMutability":"payable","type":"function"}],"userDoc":{"kind":"user","methods":{"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256))":{"notice":"Initiates bridge on origin chain to be relayed by off-chain relayer"},"canClaim(bytes32,address)":{"notice":"Checks if the dispute period has passed so bridge deposit can be claimed"},"claim(bytes,address)":{"notice":"Completes bridge transaction on origin chain by claiming originally deposited capital"},"dispute(bytes32)":{"notice":"Disputes an outstanding proof in case relayer provided dest chain tx is invalid"},"getBridgeTransaction(bytes)":{"notice":"Decodes bridge request into a bridge transaction"},"prove(bytes,bytes32)":{"notice":"Provides proof on origin side that relayer provided funds on destination side of bridge transaction"},"refund(bytes)":{"notice":"Refunds an outstanding bridge transaction in case optimistic bridging failed"},"relay(bytes)":{"notice":"Relays destination side of bridge transaction by off-chain relayer"}},"version":1},"developerDoc":{"kind":"dev","methods":{"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256))":{"params":{"params":"The parameters required to bridge"}},"canClaim(bytes32,address)":{"params":{"relayer":"The address of the relayer attempting to claim","transactionId":"The transaction id associated with the encoded bridge transaction to check"}},"claim(bytes,address)":{"params":{"request":"The encoded bridge transaction to claim on origin chain","to":"The recipient address of the funds"}},"dispute(bytes32)":{"params":{"transactionId":"The transaction id associated with the encoded bridge transaction to dispute"}},"getBridgeTransaction(bytes)":{"params":{"request":"The bridge request to decode"}},"prove(bytes,bytes32)":{"params":{"destTxHash":"The destination tx hash proving bridge transaction was relayed","request":"The encoded bridge transaction to prove on origin chain"}},"refund(bytes)":{"params":{"request":"The encoded bridge transaction to refund"}},"relay(bytes)":{"params":{"request":"The encoded bridge transaction to relay on destination chain"}}},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"BridgeDepositClaimed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"BridgeDepositRefunded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"name\":\"BridgeProofDisputed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"transactionHash\",\"type\":\"bytes32\"}],\"name\":\"BridgeProofProvided\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"originChainId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"chainGasAmount\",\"type\":\"uint256\"}],\"name\":\"BridgeRelayed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"destChainId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"sendChainGas\",\"type\":\"bool\"}],\"name\":\"BridgeRequested\",\"type\":\"event\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"dstChainId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"sendChainGas\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"}],\"internalType\":\"struct IFastBridge.BridgeParams\",\"name\":\"params\",\"type\":\"tuple\"}],\"name\":\"bridge\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"name\":\"canClaim\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"claim\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"}],\"name\":\"dispute\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"getBridgeTransaction\",\"outputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"originChainId\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"destChainId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"originSender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destRecipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"originFeeAmount\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"sendChainGas\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"}],\"internalType\":\"struct IFastBridge.BridgeTransaction\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"},{\"internalType\":\"bytes32\",\"name\":\"destTxHash\",\"type\":\"bytes32\"}],\"name\":\"prove\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"refund\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"relay\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{\"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256))\":{\"params\":{\"params\":\"The parameters required to bridge\"}},\"canClaim(bytes32,address)\":{\"params\":{\"relayer\":\"The address of the relayer attempting to claim\",\"transactionId\":\"The transaction id associated with the encoded bridge transaction to check\"}},\"claim(bytes,address)\":{\"params\":{\"request\":\"The encoded bridge transaction to claim on origin chain\",\"to\":\"The recipient address of the funds\"}},\"dispute(bytes32)\":{\"params\":{\"transactionId\":\"The transaction id associated with the encoded bridge transaction to dispute\"}},\"getBridgeTransaction(bytes)\":{\"params\":{\"request\":\"The bridge request to decode\"}},\"prove(bytes,bytes32)\":{\"params\":{\"destTxHash\":\"The destination tx hash proving bridge transaction was relayed\",\"request\":\"The encoded bridge transaction to prove on origin chain\"}},\"refund(bytes)\":{\"params\":{\"request\":\"The encoded bridge transaction to refund\"}},\"relay(bytes)\":{\"params\":{\"request\":\"The encoded bridge transaction to relay on destination chain\"}}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256))\":{\"notice\":\"Initiates bridge on origin chain to be relayed by off-chain relayer\"},\"canClaim(bytes32,address)\":{\"notice\":\"Checks if the dispute period has passed so bridge deposit can be claimed\"},\"claim(bytes,address)\":{\"notice\":\"Completes bridge transaction on origin chain by claiming originally deposited capital\"},\"dispute(bytes32)\":{\"notice\":\"Disputes an outstanding proof in case relayer provided dest chain tx is invalid\"},\"getBridgeTransaction(bytes)\":{\"notice\":\"Decodes bridge request into a bridge transaction\"},\"prove(bytes,bytes32)\":{\"notice\":\"Provides proof on origin side that relayer provided funds on destination side of bridge transaction\"},\"refund(bytes)\":{\"notice\":\"Refunds an outstanding bridge transaction in case optimistic bridging failed\"},\"relay(bytes)\":{\"notice\":\"Relays destination side of bridge transaction by off-chain relayer\"}},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeV2.sol\":\"IFastBridge\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeV2.sol\":{\"keccak256\":\"0x5069b55ca07f21bfe30b2a43c18a18318c8af9c181b2dcb07c290825efd70f34\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://273dc020a49d08e50126bbea0d7f783f79d08c702f2fdbc560618d24af308acc\",\"dweb:/ipfs/QmXJ2UVzFc8EPB74RT4CXQPC4xw66jt4T13poyfyd3UERh\"]}},\"version\":1}"},"hashes":{"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256))":"45851694","canClaim(bytes32,address)":"aa9641ab","claim(bytes,address)":"41fcb612","dispute(bytes32)":"add98c70","getBridgeTransaction(bytes)":"ac11fb1a","prove(bytes,bytes32)":"886d36ff","refund(bytes)":"5eb7d946","relay(bytes)":"8f0d6f17"}},"solidity/FastBridgeV2.sol:IFastBridgeV2":{"code":"0x","runtime-code":"0x","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.24 ^0.8.20 ^0.8.4;\n\n// contracts/interfaces/IAdmin.sol\n\ninterface IAdmin {\n // ============ Events ============\n\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n event ChainGasAmountUpdated(uint256 oldChainGasAmount, uint256 newChainGasAmount);\n\n // ============ Methods ============\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n\n function setChainGasAmount(uint256 newChainGasAmount) external;\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IFastBridgeV2Errors.sol\n\ninterface IFastBridgeV2Errors {\n error AmountIncorrect();\n error ChainIncorrect();\n error ExclusivityParamsIncorrect();\n error MsgValueIncorrect();\n error SenderIncorrect();\n error StatusIncorrect();\n error TokenNotContract();\n error ZapDataLengthAboveMax();\n error ZapNativeNotSupported();\n error ZeroAddress();\n\n error RecipientIncorrectReturnValue();\n error RecipientNoReturnValue();\n\n error DeadlineExceeded();\n error DeadlineNotExceeded();\n error DeadlineTooShort();\n error DisputePeriodNotPassed();\n error DisputePeriodPassed();\n error ExclusivityPeriodNotPassed();\n\n error TransactionRelayed();\n}\n\n// contracts/interfaces/IMulticallTarget.sol\n\n/// @notice Interface for a contract that can be called multiple times by the same caller. Inspired by MulticallV3:\n/// https://github.com/mds1/multicall/blob/master/src/Multicall3.sol\ninterface IMulticallTarget {\n struct Result {\n bool success;\n bytes returnData;\n }\n\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external;\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results);\n}\n\n// contracts/interfaces/IZapRecipient.sol\n\ninterface IZapRecipient {\n function zap(address token, uint256 amount, bytes memory zapData) external payable returns (bytes4);\n}\n\n// contracts/libs/Errors.sol\n\nerror DeadlineExceeded();\nerror DeadlineNotExceeded();\nerror DeadlineTooShort();\nerror InsufficientOutputAmount();\n\nerror MsgValueIncorrect();\nerror PoolNotFound();\nerror TokenAddressMismatch();\nerror TokenNotContract();\nerror TokenNotETH();\nerror TokensIdentical();\n\nerror ChainIncorrect();\nerror AmountIncorrect();\nerror ZeroAddress();\n\nerror DisputePeriodNotPassed();\nerror DisputePeriodPassed();\nerror SenderIncorrect();\nerror StatusIncorrect();\nerror TransactionIdIncorrect();\nerror TransactionRelayed();\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// contracts/interfaces/IFastBridgeV2.sol\n\ninterface IFastBridgeV2 is IFastBridge {\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n struct BridgeTxDetails {\n BridgeStatus status;\n uint32 destChainId;\n uint56 proofBlockTimestamp;\n address proofRelayer;\n }\n\n struct BridgeRelay {\n uint48 blockNumber;\n uint48 blockTimestamp;\n address relayer;\n }\n\n /// @notice New params introduced in the FastBridgeV2.\n /// We are passing fields from the older BridgeParams struct outside of this struct\n /// for backwards compatibility.\n /// Note: quoteRelayer and quoteExclusivitySeconds are either both zero (indicating no exclusivity)\n /// or both non-zero (indicating exclusivity for the given period).\n /// Note: zapNative \u003e 0 can NOT be used with destToken = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE (native token)\n /// @param quoteRelayer Relayer that provided the quote for the transaction\n /// @param quoteExclusivitySeconds Period of time the quote relayer is guaranteed exclusivity after user's deposit\n /// @param quoteId Unique quote identifier used for tracking the quote\n /// @param zapNative ETH value to send to the recipient (if any)\n /// @param zapData Parameters for the Zap to the destination recipient (if any)\n struct BridgeParamsV2 {\n address quoteRelayer;\n int256 quoteExclusivitySeconds;\n bytes quoteId;\n uint256 zapNative;\n bytes zapData;\n }\n\n /// @notice Updated bridge transaction struct to include parameters introduced in FastBridgeV2.\n /// Note: only `exclusivityRelayer` can fill such a transaction until `exclusivityEndTime`.\n struct BridgeTransactionV2 {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n // Note: sendChainGas flag from V1 is deprecated\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n address exclusivityRelayer;\n uint256 exclusivityEndTime;\n uint256 zapNative; // ETH value to send to the recipient (if any)\n bytes zapData; // data to pass for the Zap action (if any)\n }\n\n event BridgeQuoteDetails(bytes32 indexed transactionId, bytes quoteId);\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability\n /// to provide temporary exclusivity fill rights for the quote relayer.\n /// @param params The parameters required to bridge\n /// @param paramsV2 The parameters for exclusivity fill rights (optional, can be left empty)\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function relay(bytes memory request, address relayer) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param transactionId The transaction id associated with the encoded bridge transaction to prove\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital.\n /// @notice Can only send funds to the relayer address on the proof.\n /// @param request The encoded bridge transaction to claim on origin chain\n function claim(bytes memory request) external;\n /// @notice Checks if a transaction has been relayed\n /// @param transactionId The ID of the transaction to check\n /// @return True if the transaction has been relayed, false otherwise\n function bridgeRelays(bytes32 transactionId) external view returns (bool);\n\n /// @notice Returns the status of a bridge transaction\n /// @param transactionId The ID of the bridge transaction\n /// @return BridgeStatus Status of the bridge transaction\n function bridgeStatuses(bytes32 transactionId) external view returns (BridgeStatus);\n\n /// @notice Returns the timestamp and relayer of a bridge proof\n /// @param transactionId The ID of the bridge transaction\n /// @return timestamp The timestamp of the bridge proof\n /// @return relayer The relayer address of the bridge proof\n function bridgeProofs(bytes32 transactionId) external view returns (uint96 timestamp, address relayer);\n\n /// @notice Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\n /// @param request The bridge request to decode\n function getBridgeTransactionV2(bytes memory request) external view returns (BridgeTransactionV2 memory);\n}\n\n// contracts/utils/MulticallTarget.sol\n\n// solhint-disable avoid-low-level-calls\n/// @notice Template for a contract that supports batched calls (preserving the msg.sender).\n/// Only calls with zero msg.value could be batched.\nabstract contract MulticallTarget is IMulticallTarget {\n error MulticallTarget__UndeterminedRevert();\n\n /// @notice Perform a batched call to this contract, preserving the msg.sender.\n /// The return data from each call is discarded.\n /// @dev The method is non-payable, so only calls with `msg.value == 0` could be batched.\n /// It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag.\n /// Otherwise, the whole batch call will be reverted with the original revert reason.\n /// @param data List of abi-encoded calldata for the calls to perform.\n /// @param ignoreReverts Whether to ignore the revert errors from the calls.\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external {\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\n if (!success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(result);\n }\n }\n }\n\n /// @notice Perform a batched call to this contract, preserving the msg.sender.\n /// The return data from each call is preserved.\n /// @dev The method is non-payable, so only calls with `msg.value == 0` could be batched.\n /// It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag.\n /// Otherwise, the whole batch call will be reverted with the original revert reason.\n /// @param data List of abi-encoded calldata for the calls to perform.\n /// @param ignoreReverts Whether to ignore the revert errors from the calls.\n /// @return results List of results from the calls: `(success, returnData)`.\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results)\n {\n results = new Result[](data.length);\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (results[i].success, results[i].returnData) = address(this).delegatecall(data[i]);\n if (!results[i].success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(results[i].returnData);\n }\n }\n }\n\n /// @dev Bubbles the revert message from the underlying call.\n /// Note: preserves the same custom error or revert string, if one was used.\n /// Source: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v5.0.2/contracts/utils/Address.sol#L143-L158\n function _bubbleRevert(bytes memory returnData) internal pure {\n // Look for revert reason and bubble it up if present\n if (returnData.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n // solhint-disable-next-line no-inline-assembly\n assembly {\n let returndata_size := mload(returnData)\n revert(add(32, returnData), returndata_size)\n }\n } else {\n revert MulticallTarget__UndeterminedRevert();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// contracts/libs/BridgeTransactionV2.sol\n\n// solhint-disable no-inline-assembly\nlibrary BridgeTransactionV2Lib {\n uint16 internal constant VERSION = 2;\n\n // Offsets of the fields in the packed BridgeTransactionV2 struct\n // uint16 version [000 .. 002)\n // uint32 originChainId [002 .. 006)\n // uint32 destChainId [006 .. 010)\n // address originSender [010 .. 030)\n // address destRecipient [030 .. 050)\n // address originToken [050 .. 070)\n // address destToken [070 .. 090)\n // uint256 originAmount [090 .. 122)\n // uint256 destAmount [122 .. 154)\n // uint256 originFeeAmount [154 .. 186)\n // uint256 deadline [186 .. 218)\n // uint256 nonce [218 .. 250)\n // address exclusivityRelayer [250 .. 270)\n // uint256 exclusivityEndTime [270 .. 302)\n // uint256 zapNative [302 .. 334)\n // bytes zapData [334 .. ***)\n\n // forgefmt: disable-start\n uint256 private constant OFFSET_ORIGIN_CHAIN_ID = 2;\n uint256 private constant OFFSET_DEST_CHAIN_ID = 6;\n uint256 private constant OFFSET_ORIGIN_SENDER = 10;\n uint256 private constant OFFSET_DEST_RECIPIENT = 30;\n uint256 private constant OFFSET_ORIGIN_TOKEN = 50;\n uint256 private constant OFFSET_DEST_TOKEN = 70;\n uint256 private constant OFFSET_ORIGIN_AMOUNT = 90;\n uint256 private constant OFFSET_DEST_AMOUNT = 122;\n uint256 private constant OFFSET_ORIGIN_FEE_AMOUNT = 154;\n uint256 private constant OFFSET_DEADLINE = 186;\n uint256 private constant OFFSET_NONCE = 218;\n uint256 private constant OFFSET_EXCLUSIVITY_RELAYER = 250;\n uint256 private constant OFFSET_EXCLUSIVITY_END_TIME = 270;\n uint256 private constant OFFSET_ZAP_NATIVE = 302;\n uint256 private constant OFFSET_ZAP_DATA = 334;\n // forgefmt: disable-end\n\n error BridgeTransactionV2__InvalidEncodedTx();\n error BridgeTransactionV2__UnsupportedVersion(uint16 version);\n\n /// @notice Validates the encoded transaction to be a tightly packed encoded payload for BridgeTransactionV2.\n /// @dev Checks the minimum length and the version, use this function before decoding any of the fields.\n function validateV2(bytes calldata encodedTx) internal pure {\n // Check the minimum length: must at least include all static fields.\n if (encodedTx.length \u003c OFFSET_ZAP_DATA) revert BridgeTransactionV2__InvalidEncodedTx();\n // Once we validated the length, we can be sure that the version field is present.\n uint16 version_ = version(encodedTx);\n if (version_ != VERSION) revert BridgeTransactionV2__UnsupportedVersion(version_);\n }\n\n /// @notice Encodes the BridgeTransactionV2 struct by tightly packing the fields.\n /// @dev `abi.decode` will not work as a result of the tightly packed fields. Use `decodeV2` to decode instead.\n function encodeV2(IFastBridgeV2.BridgeTransactionV2 memory bridgeTx) internal pure returns (bytes memory) {\n // We split the encoding into two parts to avoid stack-too-deep error\n bytes memory firstPart = abi.encodePacked(\n VERSION,\n bridgeTx.originChainId,\n bridgeTx.destChainId,\n bridgeTx.originSender,\n bridgeTx.destRecipient,\n bridgeTx.originToken,\n bridgeTx.destToken,\n bridgeTx.originAmount\n );\n return abi.encodePacked(\n firstPart,\n bridgeTx.destAmount,\n bridgeTx.originFeeAmount,\n // Note: we skip the deprecated `sendChainGas` flag, which was present in BridgeTransaction V1\n bridgeTx.deadline,\n bridgeTx.nonce,\n // New V2 fields: exclusivity\n bridgeTx.exclusivityRelayer,\n bridgeTx.exclusivityEndTime,\n // New V2 fields: Zap\n bridgeTx.zapNative,\n bridgeTx.zapData\n );\n }\n\n /// @notice Decodes the BridgeTransactionV2 struct from the encoded transaction.\n /// @dev Encoded BridgeTransactionV2 struct must be tightly packed.\n /// Use `validateV2` before decoding to ensure the encoded transaction is valid.\n function decodeV2(bytes calldata encodedTx)\n internal\n pure\n returns (IFastBridgeV2.BridgeTransactionV2 memory bridgeTx)\n {\n bridgeTx.originChainId = originChainId(encodedTx);\n bridgeTx.destChainId = destChainId(encodedTx);\n bridgeTx.originSender = originSender(encodedTx);\n bridgeTx.destRecipient = destRecipient(encodedTx);\n bridgeTx.originToken = originToken(encodedTx);\n bridgeTx.destToken = destToken(encodedTx);\n bridgeTx.originAmount = originAmount(encodedTx);\n bridgeTx.destAmount = destAmount(encodedTx);\n bridgeTx.originFeeAmount = originFeeAmount(encodedTx);\n bridgeTx.deadline = deadline(encodedTx);\n bridgeTx.nonce = nonce(encodedTx);\n bridgeTx.exclusivityRelayer = exclusivityRelayer(encodedTx);\n bridgeTx.exclusivityEndTime = exclusivityEndTime(encodedTx);\n bridgeTx.zapNative = zapNative(encodedTx);\n bridgeTx.zapData = zapData(encodedTx);\n }\n\n /// @notice Extracts the version from the encoded transaction.\n function version(bytes calldata encodedTx) internal pure returns (uint16 version_) {\n // Load 32 bytes from the start and shift it 240 bits to the right to get the highest 16 bits.\n assembly {\n version_ := shr(240, calldataload(encodedTx.offset))\n }\n }\n\n /// @notice Extracts the origin chain ID from the encoded transaction.\n function originChainId(bytes calldata encodedTx) internal pure returns (uint32 originChainId_) {\n // Load 32 bytes from the offset and shift it 224 bits to the right to get the highest 32 bits.\n assembly {\n originChainId_ := shr(224, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_CHAIN_ID)))\n }\n }\n\n /// @notice Extracts the destination chain ID from the encoded transaction.\n function destChainId(bytes calldata encodedTx) internal pure returns (uint32 destChainId_) {\n // Load 32 bytes from the offset and shift it 224 bits to the right to get the highest 32 bits.\n assembly {\n destChainId_ := shr(224, calldataload(add(encodedTx.offset, OFFSET_DEST_CHAIN_ID)))\n }\n }\n\n /// @notice Extracts the origin sender from the encoded transaction.\n function originSender(bytes calldata encodedTx) internal pure returns (address originSender_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n originSender_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_SENDER)))\n }\n }\n\n /// @notice Extracts the destination recipient from the encoded transaction.\n function destRecipient(bytes calldata encodedTx) internal pure returns (address destRecipient_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n destRecipient_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_DEST_RECIPIENT)))\n }\n }\n\n /// @notice Extracts the origin token from the encoded transaction.\n function originToken(bytes calldata encodedTx) internal pure returns (address originToken_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n originToken_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_TOKEN)))\n }\n }\n\n /// @notice Extracts the destination token from the encoded transaction.\n function destToken(bytes calldata encodedTx) internal pure returns (address destToken_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n destToken_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_DEST_TOKEN)))\n }\n }\n\n /// @notice Extracts the origin amount from the encoded transaction.\n function originAmount(bytes calldata encodedTx) internal pure returns (uint256 originAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n originAmount_ := calldataload(add(encodedTx.offset, OFFSET_ORIGIN_AMOUNT))\n }\n }\n\n /// @notice Extracts the destination amount from the encoded transaction.\n function destAmount(bytes calldata encodedTx) internal pure returns (uint256 destAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n destAmount_ := calldataload(add(encodedTx.offset, OFFSET_DEST_AMOUNT))\n }\n }\n\n /// @notice Extracts the origin fee amount from the encoded transaction.\n function originFeeAmount(bytes calldata encodedTx) internal pure returns (uint256 originFeeAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n originFeeAmount_ := calldataload(add(encodedTx.offset, OFFSET_ORIGIN_FEE_AMOUNT))\n }\n }\n\n /// @notice Extracts the deadline from the encoded transaction.\n function deadline(bytes calldata encodedTx) internal pure returns (uint256 deadline_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n deadline_ := calldataload(add(encodedTx.offset, OFFSET_DEADLINE))\n }\n }\n\n /// @notice Extracts the nonce from the encoded transaction.\n function nonce(bytes calldata encodedTx) internal pure returns (uint256 nonce_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n nonce_ := calldataload(add(encodedTx.offset, OFFSET_NONCE))\n }\n }\n\n /// @notice Extracts the exclusivity relayer from the encoded transaction.\n function exclusivityRelayer(bytes calldata encodedTx) internal pure returns (address exclusivityRelayer_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n exclusivityRelayer_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_EXCLUSIVITY_RELAYER)))\n }\n }\n\n /// @notice Extracts the exclusivity end time from the encoded transaction.\n function exclusivityEndTime(bytes calldata encodedTx) internal pure returns (uint256 exclusivityEndTime_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n exclusivityEndTime_ := calldataload(add(encodedTx.offset, OFFSET_EXCLUSIVITY_END_TIME))\n }\n }\n\n /// @notice Extracts the Zap's native value from the encoded transaction.\n function zapNative(bytes calldata encodedTx) internal pure returns (uint256 zapNative_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n zapNative_ := calldataload(add(encodedTx.offset, OFFSET_ZAP_NATIVE))\n }\n }\n\n /// @notice Extracts the Zap's data from the encoded transaction.\n function zapData(bytes calldata encodedTx) internal pure returns (bytes calldata zapData_) {\n zapData_ = encodedTx[OFFSET_ZAP_DATA:];\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// contracts/libs/UniversalToken.sol\n\nlibrary UniversalTokenLib {\n using SafeERC20 for IERC20;\n\n address internal constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Transfers tokens to the given account. Reverts if transfer is not successful.\n /// @dev This might trigger fallback, if ETH is transferred to the contract.\n /// Make sure this can not lead to reentrancy attacks.\n function universalTransfer(address token, address to, uint256 value) internal {\n // Don't do anything, if need to send tokens to this address\n if (to == address(this)) return;\n // Don't do anything, if trying to send zero value\n if (value == 0) return;\n if (token == ETH_ADDRESS) {\n /// @dev Note: this can potentially lead to executing code in `to`.\n // solhint-disable-next-line avoid-low-level-calls\n (bool success,) = to.call{value: value}(\"\");\n require(success, \"ETH transfer failed\");\n } else {\n IERC20(token).safeTransfer(to, value);\n }\n }\n\n /// @notice Issues an infinite allowance to the spender, if the current allowance is insufficient\n /// to spend the given amount.\n function universalApproveInfinity(address token, address spender, uint256 amountToSpend) internal {\n // ETH Chad doesn't require your approval\n if (token == ETH_ADDRESS) return;\n // No-op if allowance is already sufficient\n uint256 allowance = IERC20(token).allowance(address(this), spender);\n if (allowance \u003e= amountToSpend) return;\n // Otherwise, reset approval to 0 and set to max allowance\n if (allowance \u003e 0) IERC20(token).safeDecreaseAllowance(spender, allowance);\n IERC20(token).safeIncreaseAllowance(spender, type(uint256).max);\n }\n\n /// @notice Returns the balance of the given token (or native ETH) for the given account.\n function universalBalanceOf(address token, address account) internal view returns (uint256) {\n if (token == ETH_ADDRESS) {\n return account.balance;\n } else {\n return IERC20(token).balanceOf(account);\n }\n }\n\n /// @dev Checks that token is a contract and not ETH_ADDRESS.\n function assertIsContract(address token) internal view {\n // Check that ETH_ADDRESS was not used (in case this is a predeploy on any of the chains)\n if (token == UniversalTokenLib.ETH_ADDRESS) revert TokenNotContract();\n // Check that token is not an EOA\n if (token.code.length == 0) revert TokenNotContract();\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/Admin.sol\n\ncontract Admin is IAdmin, AccessControlEnumerable {\n using UniversalTokenLib for address;\n\n bytes32 public constant RELAYER_ROLE = keccak256(\"RELAYER_ROLE\");\n bytes32 public constant REFUNDER_ROLE = keccak256(\"REFUNDER_ROLE\");\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n uint256 public constant FEE_BPS = 1e6;\n uint256 public constant FEE_RATE_MAX = 0.01e6; // max 1% on origin amount\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Chain gas amount to forward as rebate if requested\n uint256 public chainGasAmount;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n }\n\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n require(newFeeRate \u003c= FEE_RATE_MAX, \"newFeeRate \u003e max\");\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n token.universalTransfer(recipient, feeAmount);\n emit FeesSwept(token, recipient, feeAmount);\n }\n\n function setChainGasAmount(uint256 newChainGasAmount) external onlyRole(GOVERNOR_ROLE) {\n uint256 oldChainGasAmount = chainGasAmount;\n chainGasAmount = newChainGasAmount;\n emit ChainGasAmountUpdated(oldChainGasAmount, newChainGasAmount);\n }\n}\n\n// contracts/FastBridgeV2.sol\n\n/// @notice FastBridgeV2 is a contract for bridging tokens across chains.\ncontract FastBridgeV2 is Admin, MulticallTarget, IFastBridgeV2, IFastBridgeV2Errors {\n using BridgeTransactionV2Lib for bytes;\n using SafeERC20 for IERC20;\n\n /// @notice Address reserved for native gas token (ETH on Ethereum and most L2s, AVAX on Avalanche, etc)\n address public constant NATIVE_GAS_TOKEN = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Delay for a transaction after which it could be permisionlessly refunded\n uint256 public constant REFUND_DELAY = 7 days;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n /// @notice Maximum length of accepted zapData\n uint256 public constant MAX_ZAP_DATA_LENGTH = 2 ** 16 - 1;\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeTxDetails) public bridgeTxDetails;\n /// @notice Relay details on destination chain\n mapping(bytes32 =\u003e BridgeRelay) public bridgeRelayDetails;\n /// @notice Unique bridge nonces tracked per originSender\n mapping(address =\u003e uint256) public senderNonces;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Replaced by senderNonces\n uint256 public immutable nonce = 0;\n /// @notice the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n bridge({\n params: params,\n paramsV2: BridgeParamsV2({\n quoteRelayer: address(0),\n quoteExclusivitySeconds: 0,\n quoteId: bytes(\"\"),\n zapNative: 0,\n zapData: bytes(\"\")\n })\n });\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes calldata request) external payable {\n // relay override will validate the request\n relay({request: request, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes calldata request, bytes32 destTxHash) external {\n request.validateV2();\n prove({transactionId: keccak256(request), destTxHash: destTxHash, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridgeV2\n function claim(bytes calldata request) external {\n // claim override will validate the request\n claim({request: request, to: address(0)});\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Aggregate the read operations from the same storage slot\n address disputedRelayer = $.proofRelayer;\n BridgeStatus status = $.status;\n uint56 proofBlockTimestamp = $.proofBlockTimestamp;\n // Can only dispute a RELAYER_PROVED transaction within the dispute period\n if (status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(proofBlockTimestamp) \u003e DISPUTE_PERIOD) {\n revert DisputePeriodPassed();\n }\n // Update status to REQUESTED and delete the disputed proof details\n // Note: these are storage writes\n $.status = BridgeStatus.REQUESTED;\n $.proofRelayer = address(0);\n $.proofBlockTimestamp = 0;\n\n emit BridgeProofDisputed(transactionId, disputedRelayer);\n }\n\n /// @inheritdoc IFastBridge\n function refund(bytes calldata request) external {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Can only refund a REQUESTED transaction after its deadline expires\n if ($.status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n uint256 deadline = request.deadline();\n // Permissionless refund is only allowed after REFUND_DELAY on top of the deadline\n if (!hasRole(REFUNDER_ROLE, msg.sender)) deadline += REFUND_DELAY;\n if (block.timestamp \u003c= deadline) revert DeadlineNotExceeded();\n // Update status to REFUNDED and return the full amount (collateral + protocol fees) to the original sender.\n // The protocol fees are only updated when the transaction is claimed, so we don't need to update them here.\n // Note: this is a storage write\n $.status = BridgeStatus.REFUNDED;\n\n address to = request.originSender();\n address token = request.originToken();\n uint256 amount = request.originAmount() + request.originFeeAmount();\n // Emit the event before any external calls\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n // Complete the user refund as the last transaction action\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(to), amount);\n } else {\n IERC20(token).safeTransfer(to, amount);\n }\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // The correct relayer can only claim a RELAYER_PROVED transaction after the dispute period\n if ($.status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if ($.proofRelayer != relayer) revert SenderIncorrect();\n return _timeSince($.proofBlockTimestamp) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n /// @dev This method is added to achieve backwards compatibility with decoding requests into V1 structs:\n /// - `zapNative` is partially reported as a zero/non-zero flag\n /// - `zapData` is ignored\n /// In order to process all kinds of requests use getBridgeTransactionV2 instead.\n function getBridgeTransaction(bytes calldata request) external view returns (BridgeTransaction memory) {\n // Try decoding into V2 struct first. This will revert if V1 struct is passed\n try this.getBridgeTransactionV2(request) returns (BridgeTransactionV2 memory txV2) {\n // Note: we entirely ignore the zapData field, as it was not present in V1\n return BridgeTransaction({\n originChainId: txV2.originChainId,\n destChainId: txV2.destChainId,\n originSender: txV2.originSender,\n destRecipient: txV2.destRecipient,\n originToken: txV2.originToken,\n destToken: txV2.destToken,\n originAmount: txV2.originAmount,\n destAmount: txV2.destAmount,\n originFeeAmount: txV2.originFeeAmount,\n sendChainGas: txV2.zapNative != 0,\n deadline: txV2.deadline,\n nonce: txV2.nonce\n });\n } catch {\n // Fallback to V1 struct\n return abi.decode(request, (BridgeTransaction));\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function getBridgeTransactionV2(bytes calldata request) external pure returns (BridgeTransactionV2 memory) {\n request.validateV2();\n return BridgeTransactionV2Lib.decodeV2(request);\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) public payable {\n int256 exclusivityEndTime = 0;\n // if relayer exclusivity is not intended for this bridge, set exclusivityEndTime to static zero\n // otherwise, set exclusivity to expire at the current block ts offset by quoteExclusivitySeconds\n if (paramsV2.quoteRelayer != address(0)) {\n exclusivityEndTime = int256(block.timestamp) + paramsV2.quoteExclusivitySeconds;\n }\n _validateBridgeParams(params, paramsV2, exclusivityEndTime);\n\n // transfer tokens to bridge contract\n /// @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _takeBridgedUserAsset(params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) {\n originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n }\n\n // set status to requested\n bytes memory request = BridgeTransactionV2Lib.encodeV2(\n BridgeTransactionV2({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n deadline: params.deadline,\n nonce: senderNonces[params.sender]++, // increment nonce on every bridge\n exclusivityRelayer: paramsV2.quoteRelayer,\n // We checked exclusivityEndTime to be in range [0 .. params.deadline] above, so can safely cast\n exclusivityEndTime: uint256(exclusivityEndTime),\n zapNative: paramsV2.zapNative,\n zapData: paramsV2.zapData\n })\n );\n bytes32 transactionId = keccak256(request);\n // Note: the tx status will be updated throughout the tx lifecycle, while destChainId is set once here\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n bridgeTxDetails[transactionId].destChainId = params.dstChainId;\n\n emit BridgeRequested({\n transactionId: transactionId,\n sender: params.sender,\n request: request,\n destChainId: params.dstChainId,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n sendChainGas: paramsV2.zapNative != 0\n });\n emit BridgeQuoteDetails(transactionId, paramsV2.quoteId);\n }\n\n /// @inheritdoc IFastBridgeV2\n function relay(bytes calldata request, address relayer) public payable {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n _validateRelayParams(request, transactionId, relayer);\n // mark bridge transaction as relayed\n bridgeRelayDetails[transactionId] =\n BridgeRelay({blockNumber: uint48(block.number), blockTimestamp: uint48(block.timestamp), relayer: relayer});\n\n // transfer tokens to recipient on destination chain and trigger Zap if requested\n address to = request.destRecipient();\n address token = request.destToken();\n uint256 amount = request.destAmount();\n uint256 zapNative = request.zapNative();\n\n // Emit the event before any external calls\n emit BridgeRelayed({\n transactionId: transactionId,\n relayer: relayer,\n to: to,\n originChainId: request.originChainId(),\n originToken: request.originToken(),\n destToken: token,\n originAmount: request.originAmount(),\n destAmount: amount,\n chainGasAmount: zapNative\n });\n\n // All state changes have been done at this point, can proceed to the external calls.\n // This follows the checks-effects-interactions pattern to mitigate potential reentrancy attacks.\n if (token == NATIVE_GAS_TOKEN) {\n // For the native gas token, additional zapNative is not allowed\n if (zapNative != 0) revert ZapNativeNotSupported();\n // Check that the correct msg.value was sent\n if (msg.value != amount) revert MsgValueIncorrect();\n // Don't do a native transfer yet: we will handle it alongside the Zap below\n } else {\n // For ERC20s, we check that the correct msg.value was sent\n if (msg.value != zapNative) revert MsgValueIncorrect();\n // We need to transfer the tokens from the Relayer to the recipient first before performing an\n // optional post-transfer Zap.\n IERC20(token).safeTransferFrom(msg.sender, to, amount);\n }\n // At this point we have done:\n // - Transferred the requested amount of ERC20 tokens to the recipient.\n // At this point we have confirmed:\n // - For ERC20s: msg.value matches the requested zapNative amount.\n // - For the native gas token: msg.value matches the requested destAmount.\n // Remaining optional things to do:\n // - Forward the full msg.value to the recipient (if non-zero).\n // - Trigger a Zap (if zapData is present).\n bytes calldata zapData = request.zapData();\n if (zapData.length != 0) {\n // Zap Data is present: Zap has been requested by the recipient. Trigger it forwarding the full msg.value.\n\n // Note: if token has a fee on transfers, the recipient will have received less than `amount`.\n // This is a very niche edge case and should be handled by the recipient contract.\n _triggerZapWithChecks({recipient: to, token: token, amount: amount, zapData: zapData});\n } else if (msg.value != 0) {\n // Zap Data is missing, but msg.value was sent. This could happen in two different cases:\n // - Relay with the native gas token is happening.\n // - Relay with ERC20 is happening, with a `zapNative \u003e 0` request.\n // In both cases, we need to transfer the full msg.value to the recipient.\n Address.sendValue(payable(to), msg.value);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) public onlyRole(RELAYER_ROLE) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n\n // Can only prove a REQUESTED transaction\n if ($.status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n // Update status to RELAYER_PROVED and store the proof details\n // Note: these are storage writes\n $.status = BridgeStatus.RELAYER_PROVED;\n $.proofBlockTimestamp = uint56(block.timestamp);\n $.proofRelayer = relayer;\n\n emit BridgeProofProvided(transactionId, relayer, destTxHash);\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes calldata request, address to) public {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Aggregate the read operations from the same storage slot\n address proofRelayer = $.proofRelayer;\n BridgeStatus status = $.status;\n uint56 proofBlockTimestamp = $.proofBlockTimestamp;\n\n // Can only claim a RELAYER_PROVED transaction after the dispute period\n if (status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(proofBlockTimestamp) \u003c= DISPUTE_PERIOD) {\n revert DisputePeriodNotPassed();\n }\n\n if (to == address(0)) {\n // Anyone could claim the funds to the proven relayer on their behalf\n to = proofRelayer;\n } else if (proofRelayer != msg.sender) {\n // Only the proven relayer could specify an address to claim the funds to\n revert SenderIncorrect();\n }\n\n // Update status to RELAYER_CLAIMED and transfer the origin collateral to the specified claim address\n // Note: this is a storage write\n $.status = BridgeStatus.RELAYER_CLAIMED;\n\n address token = request.originToken();\n uint256 amount = request.originAmount();\n // Update protocol fees if origin fee amount exists\n uint256 originFeeAmount = request.originFeeAmount();\n if (originFeeAmount \u003e 0) protocolFees[token] += originFeeAmount;\n // Emit the event before any external calls\n emit BridgeDepositClaimed(transactionId, proofRelayer, to, token, amount);\n // Complete the relayer claim as the last transaction action\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(to), amount);\n } else {\n IERC20(token).safeTransfer(to, amount);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeStatuses(bytes32 transactionId) public view returns (BridgeStatus status) {\n return bridgeTxDetails[transactionId].status;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeProofs(bytes32 transactionId) public view returns (uint96 timestamp, address relayer) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n\n timestamp = $.proofBlockTimestamp;\n relayer = $.proofRelayer;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeRelays(bytes32 transactionId) public view returns (bool) {\n // has this transactionId been relayed?\n return bridgeRelayDetails[transactionId].relayer != address(0);\n }\n\n /// @notice Takes the bridged asset from the user into FastBridgeV2 custody. It will be later\n /// claimed by the relayer who completed the relay on destination chain, or refunded back to the user,\n /// should no one complete the relay.\n function _takeBridgedUserAsset(address token, uint256 amount) internal returns (uint256 amountTaken) {\n if (token == NATIVE_GAS_TOKEN) {\n // For the native gas token, we just need to check that the supplied msg.value is correct.\n // Supplied `msg.value` is already in FastBridgeV2 custody.\n if (amount != msg.value) revert MsgValueIncorrect();\n amountTaken = msg.value;\n } else {\n // For ERC20s, token is explicitly transferred from the user to FastBridgeV2.\n // We don't allow non-zero `msg.value` to avoid extra funds from being stuck in FastBridgeV2.\n if (msg.value != 0) revert MsgValueIncorrect();\n // Throw an explicit error if the provided token address is not a contract\n if (token.code.length == 0) revert TokenNotContract();\n amountTaken = IERC20(token).balanceOf(address(this));\n IERC20(token).safeTransferFrom(msg.sender, address(this), amount);\n // Use the balance difference as the amount taken in case of fee on transfer tokens.\n amountTaken = IERC20(token).balanceOf(address(this)) - amountTaken;\n }\n }\n\n /// @notice Calls the Recipient's hook function with the specified zapData and performs\n /// all the necessary checks for the returned value.\n function _triggerZapWithChecks(address recipient, address token, uint256 amount, bytes calldata zapData) internal {\n // This will bubble any revert messages from the hook function\n bytes memory returnData = Address.functionCallWithValue({\n target: recipient,\n data: abi.encodeCall(IZapRecipient.zap, (token, amount, zapData)),\n // Note: see `relay()` for reasoning behind passing msg.value\n value: msg.value\n });\n // Explicit revert if no return data at all\n if (returnData.length == 0) revert RecipientNoReturnValue();\n // Check that exactly a single return value was returned\n if (returnData.length != 32) revert RecipientIncorrectReturnValue();\n // Return value should be abi-encoded hook function selector\n if (bytes32(returnData) != bytes32(IZapRecipient.zap.selector)) {\n revert RecipientIncorrectReturnValue();\n }\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint56(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint56).max but\n /// proof.timestamp \u003c type(uint56).max via unchecked statement\n /// @param proofBlockTimestamp The bridge proof block timestamp\n /// @return delta Time delta since proof submitted\n function _timeSince(uint56 proofBlockTimestamp) internal view returns (uint256 delta) {\n unchecked {\n delta = uint56(block.timestamp) - proofBlockTimestamp;\n }\n }\n\n /// @notice Performs all the necessary checks for a bridge to happen.\n /// @dev There's no good way to refactor this function to reduce cyclomatic complexity due to\n /// the number of checks that need to be performed, so we skip the code-complexity rule here.\n // solhint-disable-next-line code-complexity\n function _validateBridgeParams(\n BridgeParams memory params,\n BridgeParamsV2 memory paramsV2,\n int256 exclusivityEndTime\n )\n internal\n view\n {\n // Check V1 (legacy) params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.sender == address(0) || params.to == address(0)) revert ZeroAddress();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n // Check V2 params\n if (paramsV2.zapData.length \u003e MAX_ZAP_DATA_LENGTH) revert ZapDataLengthAboveMax();\n if (paramsV2.zapNative != 0 \u0026\u0026 params.destToken == NATIVE_GAS_TOKEN) {\n revert ZapNativeNotSupported();\n }\n // exclusivityEndTime must be in range [0 .. params.deadline]\n if (exclusivityEndTime \u003c 0 || exclusivityEndTime \u003e int256(params.deadline)) {\n revert ExclusivityParamsIncorrect();\n }\n }\n\n /// @notice Performs all the necessary checks for a relay to happen.\n function _validateRelayParams(bytes calldata request, bytes32 transactionId, address relayer) internal view {\n if (relayer == address(0)) revert ZeroAddress();\n // Check if the transaction has already been relayed\n if (bridgeRelays(transactionId)) revert TransactionRelayed();\n if (request.destChainId() != block.chainid) revert ChainIncorrect();\n // Check the deadline for relay to happen\n if (block.timestamp \u003e request.deadline()) revert DeadlineExceeded();\n // Check the exclusivity period, if it is still ongoing\n address exclRelayer = request.exclusivityRelayer();\n if (exclRelayer != address(0) \u0026\u0026 exclRelayer != relayer \u0026\u0026 block.timestamp \u003c= request.exclusivityEndTime()) {\n revert ExclusivityPeriodNotPassed();\n }\n }\n}\n","language":"Solidity","languageVersion":"0.8.24","compilerVersion":"0.8.24","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"","srcMapRuntime":"","abiDefinition":[{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"relayer","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"BridgeDepositClaimed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"BridgeDepositRefunded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"relayer","type":"address"}],"name":"BridgeProofDisputed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"relayer","type":"address"},{"indexed":false,"internalType":"bytes32","name":"transactionHash","type":"bytes32"}],"name":"BridgeProofProvided","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":false,"internalType":"bytes","name":"quoteId","type":"bytes"}],"name":"BridgeQuoteDetails","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"relayer","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint32","name":"originChainId","type":"uint32"},{"indexed":false,"internalType":"address","name":"originToken","type":"address"},{"indexed":false,"internalType":"address","name":"destToken","type":"address"},{"indexed":false,"internalType":"uint256","name":"originAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"destAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"chainGasAmount","type":"uint256"}],"name":"BridgeRelayed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"bytes","name":"request","type":"bytes"},{"indexed":false,"internalType":"uint32","name":"destChainId","type":"uint32"},{"indexed":false,"internalType":"address","name":"originToken","type":"address"},{"indexed":false,"internalType":"address","name":"destToken","type":"address"},{"indexed":false,"internalType":"uint256","name":"originAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"destAmount","type":"uint256"},{"indexed":false,"internalType":"bool","name":"sendChainGas","type":"bool"}],"name":"BridgeRequested","type":"event"},{"inputs":[{"components":[{"internalType":"uint32","name":"dstChainId","type":"uint32"},{"internalType":"address","name":"sender","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"address","name":"originToken","type":"address"},{"internalType":"address","name":"destToken","type":"address"},{"internalType":"uint256","name":"originAmount","type":"uint256"},{"internalType":"uint256","name":"destAmount","type":"uint256"},{"internalType":"bool","name":"sendChainGas","type":"bool"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"internalType":"struct IFastBridge.BridgeParams","name":"params","type":"tuple"}],"name":"bridge","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"uint32","name":"dstChainId","type":"uint32"},{"internalType":"address","name":"sender","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"address","name":"originToken","type":"address"},{"internalType":"address","name":"destToken","type":"address"},{"internalType":"uint256","name":"originAmount","type":"uint256"},{"internalType":"uint256","name":"destAmount","type":"uint256"},{"internalType":"bool","name":"sendChainGas","type":"bool"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"internalType":"struct IFastBridge.BridgeParams","name":"params","type":"tuple"},{"components":[{"internalType":"address","name":"quoteRelayer","type":"address"},{"internalType":"int256","name":"quoteExclusivitySeconds","type":"int256"},{"internalType":"bytes","name":"quoteId","type":"bytes"},{"internalType":"uint256","name":"zapNative","type":"uint256"},{"internalType":"bytes","name":"zapData","type":"bytes"}],"internalType":"struct IFastBridgeV2.BridgeParamsV2","name":"paramsV2","type":"tuple"}],"name":"bridge","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"transactionId","type":"bytes32"}],"name":"bridgeProofs","outputs":[{"internalType":"uint96","name":"timestamp","type":"uint96"},{"internalType":"address","name":"relayer","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"transactionId","type":"bytes32"}],"name":"bridgeRelays","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"transactionId","type":"bytes32"}],"name":"bridgeStatuses","outputs":[{"internalType":"enum IFastBridgeV2.BridgeStatus","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"internalType":"address","name":"relayer","type":"address"}],"name":"canClaim","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"},{"internalType":"address","name":"to","type":"address"}],"name":"claim","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"}],"name":"claim","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"transactionId","type":"bytes32"}],"name":"dispute","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"}],"name":"getBridgeTransaction","outputs":[{"components":[{"internalType":"uint32","name":"originChainId","type":"uint32"},{"internalType":"uint32","name":"destChainId","type":"uint32"},{"internalType":"address","name":"originSender","type":"address"},{"internalType":"address","name":"destRecipient","type":"address"},{"internalType":"address","name":"originToken","type":"address"},{"internalType":"address","name":"destToken","type":"address"},{"internalType":"uint256","name":"originAmount","type":"uint256"},{"internalType":"uint256","name":"destAmount","type":"uint256"},{"internalType":"uint256","name":"originFeeAmount","type":"uint256"},{"internalType":"bool","name":"sendChainGas","type":"bool"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint256","name":"nonce","type":"uint256"}],"internalType":"struct IFastBridge.BridgeTransaction","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"}],"name":"getBridgeTransactionV2","outputs":[{"components":[{"internalType":"uint32","name":"originChainId","type":"uint32"},{"internalType":"uint32","name":"destChainId","type":"uint32"},{"internalType":"address","name":"originSender","type":"address"},{"internalType":"address","name":"destRecipient","type":"address"},{"internalType":"address","name":"originToken","type":"address"},{"internalType":"address","name":"destToken","type":"address"},{"internalType":"uint256","name":"originAmount","type":"uint256"},{"internalType":"uint256","name":"destAmount","type":"uint256"},{"internalType":"uint256","name":"originFeeAmount","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"address","name":"exclusivityRelayer","type":"address"},{"internalType":"uint256","name":"exclusivityEndTime","type":"uint256"},{"internalType":"uint256","name":"zapNative","type":"uint256"},{"internalType":"bytes","name":"zapData","type":"bytes"}],"internalType":"struct IFastBridgeV2.BridgeTransactionV2","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"internalType":"bytes32","name":"destTxHash","type":"bytes32"},{"internalType":"address","name":"relayer","type":"address"}],"name":"prove","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"},{"internalType":"bytes32","name":"destTxHash","type":"bytes32"}],"name":"prove","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"}],"name":"refund","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"}],"name":"relay","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"},{"internalType":"address","name":"relayer","type":"address"}],"name":"relay","outputs":[],"stateMutability":"payable","type":"function"}],"userDoc":{"kind":"user","methods":{"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256))":{"notice":"Initiates bridge on origin chain to be relayed by off-chain relayer"},"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256),(address,int256,bytes,uint256,bytes))":{"notice":"Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability to provide temporary exclusivity fill rights for the quote relayer."},"bridgeProofs(bytes32)":{"notice":"Returns the timestamp and relayer of a bridge proof"},"bridgeRelays(bytes32)":{"notice":"Checks if a transaction has been relayed"},"bridgeStatuses(bytes32)":{"notice":"Returns the status of a bridge transaction"},"canClaim(bytes32,address)":{"notice":"Checks if the dispute period has passed so bridge deposit can be claimed"},"claim(bytes)":{"notice":"Completes bridge transaction on origin chain by claiming originally deposited capital.Can only send funds to the relayer address on the proof."},"claim(bytes,address)":{"notice":"Completes bridge transaction on origin chain by claiming originally deposited capital"},"dispute(bytes32)":{"notice":"Disputes an outstanding proof in case relayer provided dest chain tx is invalid"},"getBridgeTransaction(bytes)":{"notice":"Decodes bridge request into a bridge transaction"},"getBridgeTransactionV2(bytes)":{"notice":"Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2"},"prove(bytes,bytes32)":{"notice":"Provides proof on origin side that relayer provided funds on destination side of bridge transaction"},"prove(bytes32,bytes32,address)":{"notice":"Provides proof on origin side that relayer provided funds on destination side of bridge transaction"},"refund(bytes)":{"notice":"Refunds an outstanding bridge transaction in case optimistic bridging failed"},"relay(bytes)":{"notice":"Relays destination side of bridge transaction by off-chain relayer"},"relay(bytes,address)":{"notice":"Relays destination side of bridge transaction by off-chain relayer"}},"version":1},"developerDoc":{"kind":"dev","methods":{"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256))":{"params":{"params":"The parameters required to bridge"}},"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256),(address,int256,bytes,uint256,bytes))":{"params":{"params":"The parameters required to bridge","paramsV2":"The parameters for exclusivity fill rights (optional, can be left empty)"}},"bridgeProofs(bytes32)":{"params":{"transactionId":"The ID of the bridge transaction"},"returns":{"relayer":"The relayer address of the bridge proof","timestamp":"The timestamp of the bridge proof"}},"bridgeRelays(bytes32)":{"params":{"transactionId":"The ID of the transaction to check"},"returns":{"_0":"True if the transaction has been relayed, false otherwise"}},"bridgeStatuses(bytes32)":{"params":{"transactionId":"The ID of the bridge transaction"},"returns":{"_0":"BridgeStatus Status of the bridge transaction"}},"canClaim(bytes32,address)":{"params":{"relayer":"The address of the relayer attempting to claim","transactionId":"The transaction id associated with the encoded bridge transaction to check"}},"claim(bytes)":{"params":{"request":"The encoded bridge transaction to claim on origin chain"}},"claim(bytes,address)":{"params":{"request":"The encoded bridge transaction to claim on origin chain","to":"The recipient address of the funds"}},"dispute(bytes32)":{"params":{"transactionId":"The transaction id associated with the encoded bridge transaction to dispute"}},"getBridgeTransaction(bytes)":{"params":{"request":"The bridge request to decode"}},"getBridgeTransactionV2(bytes)":{"params":{"request":"The bridge request to decode"}},"prove(bytes,bytes32)":{"params":{"destTxHash":"The destination tx hash proving bridge transaction was relayed","request":"The encoded bridge transaction to prove on origin chain"}},"prove(bytes32,bytes32,address)":{"params":{"destTxHash":"The destination tx hash proving bridge transaction was relayed","relayer":"The address of the relaying entity which should have control of the origin funds when claimed","transactionId":"The transaction id associated with the encoded bridge transaction to prove"}},"refund(bytes)":{"params":{"request":"The encoded bridge transaction to refund"}},"relay(bytes)":{"params":{"request":"The encoded bridge transaction to relay on destination chain"}},"relay(bytes,address)":{"params":{"relayer":"The address of the relaying entity which should have control of the origin funds when claimed","request":"The encoded bridge transaction to relay on destination chain"}}},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"BridgeDepositClaimed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"BridgeDepositRefunded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"name\":\"BridgeProofDisputed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"transactionHash\",\"type\":\"bytes32\"}],\"name\":\"BridgeProofProvided\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"quoteId\",\"type\":\"bytes\"}],\"name\":\"BridgeQuoteDetails\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"originChainId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"chainGasAmount\",\"type\":\"uint256\"}],\"name\":\"BridgeRelayed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"destChainId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"sendChainGas\",\"type\":\"bool\"}],\"name\":\"BridgeRequested\",\"type\":\"event\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"dstChainId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"sendChainGas\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"}],\"internalType\":\"struct IFastBridge.BridgeParams\",\"name\":\"params\",\"type\":\"tuple\"}],\"name\":\"bridge\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"dstChainId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"sendChainGas\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"}],\"internalType\":\"struct IFastBridge.BridgeParams\",\"name\":\"params\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"quoteRelayer\",\"type\":\"address\"},{\"internalType\":\"int256\",\"name\":\"quoteExclusivitySeconds\",\"type\":\"int256\"},{\"internalType\":\"bytes\",\"name\":\"quoteId\",\"type\":\"bytes\"},{\"internalType\":\"uint256\",\"name\":\"zapNative\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"zapData\",\"type\":\"bytes\"}],\"internalType\":\"struct IFastBridgeV2.BridgeParamsV2\",\"name\":\"paramsV2\",\"type\":\"tuple\"}],\"name\":\"bridge\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"}],\"name\":\"bridgeProofs\",\"outputs\":[{\"internalType\":\"uint96\",\"name\":\"timestamp\",\"type\":\"uint96\"},{\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"}],\"name\":\"bridgeRelays\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"}],\"name\":\"bridgeStatuses\",\"outputs\":[{\"internalType\":\"enum IFastBridgeV2.BridgeStatus\",\"name\":\"\",\"type\":\"uint8\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"name\":\"canClaim\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"claim\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"claim\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"}],\"name\":\"dispute\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"getBridgeTransaction\",\"outputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"originChainId\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"destChainId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"originSender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destRecipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"originFeeAmount\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"sendChainGas\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"}],\"internalType\":\"struct IFastBridge.BridgeTransaction\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"getBridgeTransactionV2\",\"outputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"originChainId\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"destChainId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"originSender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destRecipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"originFeeAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"exclusivityRelayer\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"exclusivityEndTime\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"zapNative\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"zapData\",\"type\":\"bytes\"}],\"internalType\":\"struct IFastBridgeV2.BridgeTransactionV2\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"destTxHash\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"name\":\"prove\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"},{\"internalType\":\"bytes32\",\"name\":\"destTxHash\",\"type\":\"bytes32\"}],\"name\":\"prove\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"refund\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"relay\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"},{\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"name\":\"relay\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{\"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256))\":{\"params\":{\"params\":\"The parameters required to bridge\"}},\"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256),(address,int256,bytes,uint256,bytes))\":{\"params\":{\"params\":\"The parameters required to bridge\",\"paramsV2\":\"The parameters for exclusivity fill rights (optional, can be left empty)\"}},\"bridgeProofs(bytes32)\":{\"params\":{\"transactionId\":\"The ID of the bridge transaction\"},\"returns\":{\"relayer\":\"The relayer address of the bridge proof\",\"timestamp\":\"The timestamp of the bridge proof\"}},\"bridgeRelays(bytes32)\":{\"params\":{\"transactionId\":\"The ID of the transaction to check\"},\"returns\":{\"_0\":\"True if the transaction has been relayed, false otherwise\"}},\"bridgeStatuses(bytes32)\":{\"params\":{\"transactionId\":\"The ID of the bridge transaction\"},\"returns\":{\"_0\":\"BridgeStatus Status of the bridge transaction\"}},\"canClaim(bytes32,address)\":{\"params\":{\"relayer\":\"The address of the relayer attempting to claim\",\"transactionId\":\"The transaction id associated with the encoded bridge transaction to check\"}},\"claim(bytes)\":{\"params\":{\"request\":\"The encoded bridge transaction to claim on origin chain\"}},\"claim(bytes,address)\":{\"params\":{\"request\":\"The encoded bridge transaction to claim on origin chain\",\"to\":\"The recipient address of the funds\"}},\"dispute(bytes32)\":{\"params\":{\"transactionId\":\"The transaction id associated with the encoded bridge transaction to dispute\"}},\"getBridgeTransaction(bytes)\":{\"params\":{\"request\":\"The bridge request to decode\"}},\"getBridgeTransactionV2(bytes)\":{\"params\":{\"request\":\"The bridge request to decode\"}},\"prove(bytes,bytes32)\":{\"params\":{\"destTxHash\":\"The destination tx hash proving bridge transaction was relayed\",\"request\":\"The encoded bridge transaction to prove on origin chain\"}},\"prove(bytes32,bytes32,address)\":{\"params\":{\"destTxHash\":\"The destination tx hash proving bridge transaction was relayed\",\"relayer\":\"The address of the relaying entity which should have control of the origin funds when claimed\",\"transactionId\":\"The transaction id associated with the encoded bridge transaction to prove\"}},\"refund(bytes)\":{\"params\":{\"request\":\"The encoded bridge transaction to refund\"}},\"relay(bytes)\":{\"params\":{\"request\":\"The encoded bridge transaction to relay on destination chain\"}},\"relay(bytes,address)\":{\"params\":{\"relayer\":\"The address of the relaying entity which should have control of the origin funds when claimed\",\"request\":\"The encoded bridge transaction to relay on destination chain\"}}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256))\":{\"notice\":\"Initiates bridge on origin chain to be relayed by off-chain relayer\"},\"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256),(address,int256,bytes,uint256,bytes))\":{\"notice\":\"Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability to provide temporary exclusivity fill rights for the quote relayer.\"},\"bridgeProofs(bytes32)\":{\"notice\":\"Returns the timestamp and relayer of a bridge proof\"},\"bridgeRelays(bytes32)\":{\"notice\":\"Checks if a transaction has been relayed\"},\"bridgeStatuses(bytes32)\":{\"notice\":\"Returns the status of a bridge transaction\"},\"canClaim(bytes32,address)\":{\"notice\":\"Checks if the dispute period has passed so bridge deposit can be claimed\"},\"claim(bytes)\":{\"notice\":\"Completes bridge transaction on origin chain by claiming originally deposited capital.Can only send funds to the relayer address on the proof.\"},\"claim(bytes,address)\":{\"notice\":\"Completes bridge transaction on origin chain by claiming originally deposited capital\"},\"dispute(bytes32)\":{\"notice\":\"Disputes an outstanding proof in case relayer provided dest chain tx is invalid\"},\"getBridgeTransaction(bytes)\":{\"notice\":\"Decodes bridge request into a bridge transaction\"},\"getBridgeTransactionV2(bytes)\":{\"notice\":\"Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\"},\"prove(bytes,bytes32)\":{\"notice\":\"Provides proof on origin side that relayer provided funds on destination side of bridge transaction\"},\"prove(bytes32,bytes32,address)\":{\"notice\":\"Provides proof on origin side that relayer provided funds on destination side of bridge transaction\"},\"refund(bytes)\":{\"notice\":\"Refunds an outstanding bridge transaction in case optimistic bridging failed\"},\"relay(bytes)\":{\"notice\":\"Relays destination side of bridge transaction by off-chain relayer\"},\"relay(bytes,address)\":{\"notice\":\"Relays destination side of bridge transaction by off-chain relayer\"}},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeV2.sol\":\"IFastBridgeV2\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeV2.sol\":{\"keccak256\":\"0x5069b55ca07f21bfe30b2a43c18a18318c8af9c181b2dcb07c290825efd70f34\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://273dc020a49d08e50126bbea0d7f783f79d08c702f2fdbc560618d24af308acc\",\"dweb:/ipfs/QmXJ2UVzFc8EPB74RT4CXQPC4xw66jt4T13poyfyd3UERh\"]}},\"version\":1}"},"hashes":{"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256))":"45851694","bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256),(address,int256,bytes,uint256,bytes))":"bfc7c607","bridgeProofs(bytes32)":"91ad5039","bridgeRelays(bytes32)":"8379a24f","bridgeStatuses(bytes32)":"051287bc","canClaim(bytes32,address)":"aa9641ab","claim(bytes)":"c63ff8dd","claim(bytes,address)":"41fcb612","dispute(bytes32)":"add98c70","getBridgeTransaction(bytes)":"ac11fb1a","getBridgeTransactionV2(bytes)":"5aa6ccba","prove(bytes,bytes32)":"886d36ff","prove(bytes32,bytes32,address)":"18e4357d","refund(bytes)":"5eb7d946","relay(bytes)":"8f0d6f17","relay(bytes,address)":"9c9545f0"}},"solidity/FastBridgeV2.sol:IFastBridgeV2Errors":{"code":"0x","runtime-code":"0x","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.24 ^0.8.20 ^0.8.4;\n\n// contracts/interfaces/IAdmin.sol\n\ninterface IAdmin {\n // ============ Events ============\n\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n event ChainGasAmountUpdated(uint256 oldChainGasAmount, uint256 newChainGasAmount);\n\n // ============ Methods ============\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n\n function setChainGasAmount(uint256 newChainGasAmount) external;\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IFastBridgeV2Errors.sol\n\ninterface IFastBridgeV2Errors {\n error AmountIncorrect();\n error ChainIncorrect();\n error ExclusivityParamsIncorrect();\n error MsgValueIncorrect();\n error SenderIncorrect();\n error StatusIncorrect();\n error TokenNotContract();\n error ZapDataLengthAboveMax();\n error ZapNativeNotSupported();\n error ZeroAddress();\n\n error RecipientIncorrectReturnValue();\n error RecipientNoReturnValue();\n\n error DeadlineExceeded();\n error DeadlineNotExceeded();\n error DeadlineTooShort();\n error DisputePeriodNotPassed();\n error DisputePeriodPassed();\n error ExclusivityPeriodNotPassed();\n\n error TransactionRelayed();\n}\n\n// contracts/interfaces/IMulticallTarget.sol\n\n/// @notice Interface for a contract that can be called multiple times by the same caller. Inspired by MulticallV3:\n/// https://github.com/mds1/multicall/blob/master/src/Multicall3.sol\ninterface IMulticallTarget {\n struct Result {\n bool success;\n bytes returnData;\n }\n\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external;\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results);\n}\n\n// contracts/interfaces/IZapRecipient.sol\n\ninterface IZapRecipient {\n function zap(address token, uint256 amount, bytes memory zapData) external payable returns (bytes4);\n}\n\n// contracts/libs/Errors.sol\n\nerror DeadlineExceeded();\nerror DeadlineNotExceeded();\nerror DeadlineTooShort();\nerror InsufficientOutputAmount();\n\nerror MsgValueIncorrect();\nerror PoolNotFound();\nerror TokenAddressMismatch();\nerror TokenNotContract();\nerror TokenNotETH();\nerror TokensIdentical();\n\nerror ChainIncorrect();\nerror AmountIncorrect();\nerror ZeroAddress();\n\nerror DisputePeriodNotPassed();\nerror DisputePeriodPassed();\nerror SenderIncorrect();\nerror StatusIncorrect();\nerror TransactionIdIncorrect();\nerror TransactionRelayed();\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// contracts/interfaces/IFastBridgeV2.sol\n\ninterface IFastBridgeV2 is IFastBridge {\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n struct BridgeTxDetails {\n BridgeStatus status;\n uint32 destChainId;\n uint56 proofBlockTimestamp;\n address proofRelayer;\n }\n\n struct BridgeRelay {\n uint48 blockNumber;\n uint48 blockTimestamp;\n address relayer;\n }\n\n /// @notice New params introduced in the FastBridgeV2.\n /// We are passing fields from the older BridgeParams struct outside of this struct\n /// for backwards compatibility.\n /// Note: quoteRelayer and quoteExclusivitySeconds are either both zero (indicating no exclusivity)\n /// or both non-zero (indicating exclusivity for the given period).\n /// Note: zapNative \u003e 0 can NOT be used with destToken = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE (native token)\n /// @param quoteRelayer Relayer that provided the quote for the transaction\n /// @param quoteExclusivitySeconds Period of time the quote relayer is guaranteed exclusivity after user's deposit\n /// @param quoteId Unique quote identifier used for tracking the quote\n /// @param zapNative ETH value to send to the recipient (if any)\n /// @param zapData Parameters for the Zap to the destination recipient (if any)\n struct BridgeParamsV2 {\n address quoteRelayer;\n int256 quoteExclusivitySeconds;\n bytes quoteId;\n uint256 zapNative;\n bytes zapData;\n }\n\n /// @notice Updated bridge transaction struct to include parameters introduced in FastBridgeV2.\n /// Note: only `exclusivityRelayer` can fill such a transaction until `exclusivityEndTime`.\n struct BridgeTransactionV2 {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n // Note: sendChainGas flag from V1 is deprecated\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n address exclusivityRelayer;\n uint256 exclusivityEndTime;\n uint256 zapNative; // ETH value to send to the recipient (if any)\n bytes zapData; // data to pass for the Zap action (if any)\n }\n\n event BridgeQuoteDetails(bytes32 indexed transactionId, bytes quoteId);\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability\n /// to provide temporary exclusivity fill rights for the quote relayer.\n /// @param params The parameters required to bridge\n /// @param paramsV2 The parameters for exclusivity fill rights (optional, can be left empty)\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function relay(bytes memory request, address relayer) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param transactionId The transaction id associated with the encoded bridge transaction to prove\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital.\n /// @notice Can only send funds to the relayer address on the proof.\n /// @param request The encoded bridge transaction to claim on origin chain\n function claim(bytes memory request) external;\n /// @notice Checks if a transaction has been relayed\n /// @param transactionId The ID of the transaction to check\n /// @return True if the transaction has been relayed, false otherwise\n function bridgeRelays(bytes32 transactionId) external view returns (bool);\n\n /// @notice Returns the status of a bridge transaction\n /// @param transactionId The ID of the bridge transaction\n /// @return BridgeStatus Status of the bridge transaction\n function bridgeStatuses(bytes32 transactionId) external view returns (BridgeStatus);\n\n /// @notice Returns the timestamp and relayer of a bridge proof\n /// @param transactionId The ID of the bridge transaction\n /// @return timestamp The timestamp of the bridge proof\n /// @return relayer The relayer address of the bridge proof\n function bridgeProofs(bytes32 transactionId) external view returns (uint96 timestamp, address relayer);\n\n /// @notice Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\n /// @param request The bridge request to decode\n function getBridgeTransactionV2(bytes memory request) external view returns (BridgeTransactionV2 memory);\n}\n\n// contracts/utils/MulticallTarget.sol\n\n// solhint-disable avoid-low-level-calls\n/// @notice Template for a contract that supports batched calls (preserving the msg.sender).\n/// Only calls with zero msg.value could be batched.\nabstract contract MulticallTarget is IMulticallTarget {\n error MulticallTarget__UndeterminedRevert();\n\n /// @notice Perform a batched call to this contract, preserving the msg.sender.\n /// The return data from each call is discarded.\n /// @dev The method is non-payable, so only calls with `msg.value == 0` could be batched.\n /// It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag.\n /// Otherwise, the whole batch call will be reverted with the original revert reason.\n /// @param data List of abi-encoded calldata for the calls to perform.\n /// @param ignoreReverts Whether to ignore the revert errors from the calls.\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external {\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\n if (!success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(result);\n }\n }\n }\n\n /// @notice Perform a batched call to this contract, preserving the msg.sender.\n /// The return data from each call is preserved.\n /// @dev The method is non-payable, so only calls with `msg.value == 0` could be batched.\n /// It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag.\n /// Otherwise, the whole batch call will be reverted with the original revert reason.\n /// @param data List of abi-encoded calldata for the calls to perform.\n /// @param ignoreReverts Whether to ignore the revert errors from the calls.\n /// @return results List of results from the calls: `(success, returnData)`.\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results)\n {\n results = new Result[](data.length);\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (results[i].success, results[i].returnData) = address(this).delegatecall(data[i]);\n if (!results[i].success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(results[i].returnData);\n }\n }\n }\n\n /// @dev Bubbles the revert message from the underlying call.\n /// Note: preserves the same custom error or revert string, if one was used.\n /// Source: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v5.0.2/contracts/utils/Address.sol#L143-L158\n function _bubbleRevert(bytes memory returnData) internal pure {\n // Look for revert reason and bubble it up if present\n if (returnData.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n // solhint-disable-next-line no-inline-assembly\n assembly {\n let returndata_size := mload(returnData)\n revert(add(32, returnData), returndata_size)\n }\n } else {\n revert MulticallTarget__UndeterminedRevert();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// contracts/libs/BridgeTransactionV2.sol\n\n// solhint-disable no-inline-assembly\nlibrary BridgeTransactionV2Lib {\n uint16 internal constant VERSION = 2;\n\n // Offsets of the fields in the packed BridgeTransactionV2 struct\n // uint16 version [000 .. 002)\n // uint32 originChainId [002 .. 006)\n // uint32 destChainId [006 .. 010)\n // address originSender [010 .. 030)\n // address destRecipient [030 .. 050)\n // address originToken [050 .. 070)\n // address destToken [070 .. 090)\n // uint256 originAmount [090 .. 122)\n // uint256 destAmount [122 .. 154)\n // uint256 originFeeAmount [154 .. 186)\n // uint256 deadline [186 .. 218)\n // uint256 nonce [218 .. 250)\n // address exclusivityRelayer [250 .. 270)\n // uint256 exclusivityEndTime [270 .. 302)\n // uint256 zapNative [302 .. 334)\n // bytes zapData [334 .. ***)\n\n // forgefmt: disable-start\n uint256 private constant OFFSET_ORIGIN_CHAIN_ID = 2;\n uint256 private constant OFFSET_DEST_CHAIN_ID = 6;\n uint256 private constant OFFSET_ORIGIN_SENDER = 10;\n uint256 private constant OFFSET_DEST_RECIPIENT = 30;\n uint256 private constant OFFSET_ORIGIN_TOKEN = 50;\n uint256 private constant OFFSET_DEST_TOKEN = 70;\n uint256 private constant OFFSET_ORIGIN_AMOUNT = 90;\n uint256 private constant OFFSET_DEST_AMOUNT = 122;\n uint256 private constant OFFSET_ORIGIN_FEE_AMOUNT = 154;\n uint256 private constant OFFSET_DEADLINE = 186;\n uint256 private constant OFFSET_NONCE = 218;\n uint256 private constant OFFSET_EXCLUSIVITY_RELAYER = 250;\n uint256 private constant OFFSET_EXCLUSIVITY_END_TIME = 270;\n uint256 private constant OFFSET_ZAP_NATIVE = 302;\n uint256 private constant OFFSET_ZAP_DATA = 334;\n // forgefmt: disable-end\n\n error BridgeTransactionV2__InvalidEncodedTx();\n error BridgeTransactionV2__UnsupportedVersion(uint16 version);\n\n /// @notice Validates the encoded transaction to be a tightly packed encoded payload for BridgeTransactionV2.\n /// @dev Checks the minimum length and the version, use this function before decoding any of the fields.\n function validateV2(bytes calldata encodedTx) internal pure {\n // Check the minimum length: must at least include all static fields.\n if (encodedTx.length \u003c OFFSET_ZAP_DATA) revert BridgeTransactionV2__InvalidEncodedTx();\n // Once we validated the length, we can be sure that the version field is present.\n uint16 version_ = version(encodedTx);\n if (version_ != VERSION) revert BridgeTransactionV2__UnsupportedVersion(version_);\n }\n\n /// @notice Encodes the BridgeTransactionV2 struct by tightly packing the fields.\n /// @dev `abi.decode` will not work as a result of the tightly packed fields. Use `decodeV2` to decode instead.\n function encodeV2(IFastBridgeV2.BridgeTransactionV2 memory bridgeTx) internal pure returns (bytes memory) {\n // We split the encoding into two parts to avoid stack-too-deep error\n bytes memory firstPart = abi.encodePacked(\n VERSION,\n bridgeTx.originChainId,\n bridgeTx.destChainId,\n bridgeTx.originSender,\n bridgeTx.destRecipient,\n bridgeTx.originToken,\n bridgeTx.destToken,\n bridgeTx.originAmount\n );\n return abi.encodePacked(\n firstPart,\n bridgeTx.destAmount,\n bridgeTx.originFeeAmount,\n // Note: we skip the deprecated `sendChainGas` flag, which was present in BridgeTransaction V1\n bridgeTx.deadline,\n bridgeTx.nonce,\n // New V2 fields: exclusivity\n bridgeTx.exclusivityRelayer,\n bridgeTx.exclusivityEndTime,\n // New V2 fields: Zap\n bridgeTx.zapNative,\n bridgeTx.zapData\n );\n }\n\n /// @notice Decodes the BridgeTransactionV2 struct from the encoded transaction.\n /// @dev Encoded BridgeTransactionV2 struct must be tightly packed.\n /// Use `validateV2` before decoding to ensure the encoded transaction is valid.\n function decodeV2(bytes calldata encodedTx)\n internal\n pure\n returns (IFastBridgeV2.BridgeTransactionV2 memory bridgeTx)\n {\n bridgeTx.originChainId = originChainId(encodedTx);\n bridgeTx.destChainId = destChainId(encodedTx);\n bridgeTx.originSender = originSender(encodedTx);\n bridgeTx.destRecipient = destRecipient(encodedTx);\n bridgeTx.originToken = originToken(encodedTx);\n bridgeTx.destToken = destToken(encodedTx);\n bridgeTx.originAmount = originAmount(encodedTx);\n bridgeTx.destAmount = destAmount(encodedTx);\n bridgeTx.originFeeAmount = originFeeAmount(encodedTx);\n bridgeTx.deadline = deadline(encodedTx);\n bridgeTx.nonce = nonce(encodedTx);\n bridgeTx.exclusivityRelayer = exclusivityRelayer(encodedTx);\n bridgeTx.exclusivityEndTime = exclusivityEndTime(encodedTx);\n bridgeTx.zapNative = zapNative(encodedTx);\n bridgeTx.zapData = zapData(encodedTx);\n }\n\n /// @notice Extracts the version from the encoded transaction.\n function version(bytes calldata encodedTx) internal pure returns (uint16 version_) {\n // Load 32 bytes from the start and shift it 240 bits to the right to get the highest 16 bits.\n assembly {\n version_ := shr(240, calldataload(encodedTx.offset))\n }\n }\n\n /// @notice Extracts the origin chain ID from the encoded transaction.\n function originChainId(bytes calldata encodedTx) internal pure returns (uint32 originChainId_) {\n // Load 32 bytes from the offset and shift it 224 bits to the right to get the highest 32 bits.\n assembly {\n originChainId_ := shr(224, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_CHAIN_ID)))\n }\n }\n\n /// @notice Extracts the destination chain ID from the encoded transaction.\n function destChainId(bytes calldata encodedTx) internal pure returns (uint32 destChainId_) {\n // Load 32 bytes from the offset and shift it 224 bits to the right to get the highest 32 bits.\n assembly {\n destChainId_ := shr(224, calldataload(add(encodedTx.offset, OFFSET_DEST_CHAIN_ID)))\n }\n }\n\n /// @notice Extracts the origin sender from the encoded transaction.\n function originSender(bytes calldata encodedTx) internal pure returns (address originSender_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n originSender_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_SENDER)))\n }\n }\n\n /// @notice Extracts the destination recipient from the encoded transaction.\n function destRecipient(bytes calldata encodedTx) internal pure returns (address destRecipient_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n destRecipient_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_DEST_RECIPIENT)))\n }\n }\n\n /// @notice Extracts the origin token from the encoded transaction.\n function originToken(bytes calldata encodedTx) internal pure returns (address originToken_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n originToken_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_TOKEN)))\n }\n }\n\n /// @notice Extracts the destination token from the encoded transaction.\n function destToken(bytes calldata encodedTx) internal pure returns (address destToken_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n destToken_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_DEST_TOKEN)))\n }\n }\n\n /// @notice Extracts the origin amount from the encoded transaction.\n function originAmount(bytes calldata encodedTx) internal pure returns (uint256 originAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n originAmount_ := calldataload(add(encodedTx.offset, OFFSET_ORIGIN_AMOUNT))\n }\n }\n\n /// @notice Extracts the destination amount from the encoded transaction.\n function destAmount(bytes calldata encodedTx) internal pure returns (uint256 destAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n destAmount_ := calldataload(add(encodedTx.offset, OFFSET_DEST_AMOUNT))\n }\n }\n\n /// @notice Extracts the origin fee amount from the encoded transaction.\n function originFeeAmount(bytes calldata encodedTx) internal pure returns (uint256 originFeeAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n originFeeAmount_ := calldataload(add(encodedTx.offset, OFFSET_ORIGIN_FEE_AMOUNT))\n }\n }\n\n /// @notice Extracts the deadline from the encoded transaction.\n function deadline(bytes calldata encodedTx) internal pure returns (uint256 deadline_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n deadline_ := calldataload(add(encodedTx.offset, OFFSET_DEADLINE))\n }\n }\n\n /// @notice Extracts the nonce from the encoded transaction.\n function nonce(bytes calldata encodedTx) internal pure returns (uint256 nonce_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n nonce_ := calldataload(add(encodedTx.offset, OFFSET_NONCE))\n }\n }\n\n /// @notice Extracts the exclusivity relayer from the encoded transaction.\n function exclusivityRelayer(bytes calldata encodedTx) internal pure returns (address exclusivityRelayer_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n exclusivityRelayer_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_EXCLUSIVITY_RELAYER)))\n }\n }\n\n /// @notice Extracts the exclusivity end time from the encoded transaction.\n function exclusivityEndTime(bytes calldata encodedTx) internal pure returns (uint256 exclusivityEndTime_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n exclusivityEndTime_ := calldataload(add(encodedTx.offset, OFFSET_EXCLUSIVITY_END_TIME))\n }\n }\n\n /// @notice Extracts the Zap's native value from the encoded transaction.\n function zapNative(bytes calldata encodedTx) internal pure returns (uint256 zapNative_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n zapNative_ := calldataload(add(encodedTx.offset, OFFSET_ZAP_NATIVE))\n }\n }\n\n /// @notice Extracts the Zap's data from the encoded transaction.\n function zapData(bytes calldata encodedTx) internal pure returns (bytes calldata zapData_) {\n zapData_ = encodedTx[OFFSET_ZAP_DATA:];\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// contracts/libs/UniversalToken.sol\n\nlibrary UniversalTokenLib {\n using SafeERC20 for IERC20;\n\n address internal constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Transfers tokens to the given account. Reverts if transfer is not successful.\n /// @dev This might trigger fallback, if ETH is transferred to the contract.\n /// Make sure this can not lead to reentrancy attacks.\n function universalTransfer(address token, address to, uint256 value) internal {\n // Don't do anything, if need to send tokens to this address\n if (to == address(this)) return;\n // Don't do anything, if trying to send zero value\n if (value == 0) return;\n if (token == ETH_ADDRESS) {\n /// @dev Note: this can potentially lead to executing code in `to`.\n // solhint-disable-next-line avoid-low-level-calls\n (bool success,) = to.call{value: value}(\"\");\n require(success, \"ETH transfer failed\");\n } else {\n IERC20(token).safeTransfer(to, value);\n }\n }\n\n /// @notice Issues an infinite allowance to the spender, if the current allowance is insufficient\n /// to spend the given amount.\n function universalApproveInfinity(address token, address spender, uint256 amountToSpend) internal {\n // ETH Chad doesn't require your approval\n if (token == ETH_ADDRESS) return;\n // No-op if allowance is already sufficient\n uint256 allowance = IERC20(token).allowance(address(this), spender);\n if (allowance \u003e= amountToSpend) return;\n // Otherwise, reset approval to 0 and set to max allowance\n if (allowance \u003e 0) IERC20(token).safeDecreaseAllowance(spender, allowance);\n IERC20(token).safeIncreaseAllowance(spender, type(uint256).max);\n }\n\n /// @notice Returns the balance of the given token (or native ETH) for the given account.\n function universalBalanceOf(address token, address account) internal view returns (uint256) {\n if (token == ETH_ADDRESS) {\n return account.balance;\n } else {\n return IERC20(token).balanceOf(account);\n }\n }\n\n /// @dev Checks that token is a contract and not ETH_ADDRESS.\n function assertIsContract(address token) internal view {\n // Check that ETH_ADDRESS was not used (in case this is a predeploy on any of the chains)\n if (token == UniversalTokenLib.ETH_ADDRESS) revert TokenNotContract();\n // Check that token is not an EOA\n if (token.code.length == 0) revert TokenNotContract();\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/Admin.sol\n\ncontract Admin is IAdmin, AccessControlEnumerable {\n using UniversalTokenLib for address;\n\n bytes32 public constant RELAYER_ROLE = keccak256(\"RELAYER_ROLE\");\n bytes32 public constant REFUNDER_ROLE = keccak256(\"REFUNDER_ROLE\");\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n uint256 public constant FEE_BPS = 1e6;\n uint256 public constant FEE_RATE_MAX = 0.01e6; // max 1% on origin amount\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Chain gas amount to forward as rebate if requested\n uint256 public chainGasAmount;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n }\n\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n require(newFeeRate \u003c= FEE_RATE_MAX, \"newFeeRate \u003e max\");\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n token.universalTransfer(recipient, feeAmount);\n emit FeesSwept(token, recipient, feeAmount);\n }\n\n function setChainGasAmount(uint256 newChainGasAmount) external onlyRole(GOVERNOR_ROLE) {\n uint256 oldChainGasAmount = chainGasAmount;\n chainGasAmount = newChainGasAmount;\n emit ChainGasAmountUpdated(oldChainGasAmount, newChainGasAmount);\n }\n}\n\n// contracts/FastBridgeV2.sol\n\n/// @notice FastBridgeV2 is a contract for bridging tokens across chains.\ncontract FastBridgeV2 is Admin, MulticallTarget, IFastBridgeV2, IFastBridgeV2Errors {\n using BridgeTransactionV2Lib for bytes;\n using SafeERC20 for IERC20;\n\n /// @notice Address reserved for native gas token (ETH on Ethereum and most L2s, AVAX on Avalanche, etc)\n address public constant NATIVE_GAS_TOKEN = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Delay for a transaction after which it could be permisionlessly refunded\n uint256 public constant REFUND_DELAY = 7 days;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n /// @notice Maximum length of accepted zapData\n uint256 public constant MAX_ZAP_DATA_LENGTH = 2 ** 16 - 1;\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeTxDetails) public bridgeTxDetails;\n /// @notice Relay details on destination chain\n mapping(bytes32 =\u003e BridgeRelay) public bridgeRelayDetails;\n /// @notice Unique bridge nonces tracked per originSender\n mapping(address =\u003e uint256) public senderNonces;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Replaced by senderNonces\n uint256 public immutable nonce = 0;\n /// @notice the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n bridge({\n params: params,\n paramsV2: BridgeParamsV2({\n quoteRelayer: address(0),\n quoteExclusivitySeconds: 0,\n quoteId: bytes(\"\"),\n zapNative: 0,\n zapData: bytes(\"\")\n })\n });\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes calldata request) external payable {\n // relay override will validate the request\n relay({request: request, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes calldata request, bytes32 destTxHash) external {\n request.validateV2();\n prove({transactionId: keccak256(request), destTxHash: destTxHash, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridgeV2\n function claim(bytes calldata request) external {\n // claim override will validate the request\n claim({request: request, to: address(0)});\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Aggregate the read operations from the same storage slot\n address disputedRelayer = $.proofRelayer;\n BridgeStatus status = $.status;\n uint56 proofBlockTimestamp = $.proofBlockTimestamp;\n // Can only dispute a RELAYER_PROVED transaction within the dispute period\n if (status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(proofBlockTimestamp) \u003e DISPUTE_PERIOD) {\n revert DisputePeriodPassed();\n }\n // Update status to REQUESTED and delete the disputed proof details\n // Note: these are storage writes\n $.status = BridgeStatus.REQUESTED;\n $.proofRelayer = address(0);\n $.proofBlockTimestamp = 0;\n\n emit BridgeProofDisputed(transactionId, disputedRelayer);\n }\n\n /// @inheritdoc IFastBridge\n function refund(bytes calldata request) external {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Can only refund a REQUESTED transaction after its deadline expires\n if ($.status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n uint256 deadline = request.deadline();\n // Permissionless refund is only allowed after REFUND_DELAY on top of the deadline\n if (!hasRole(REFUNDER_ROLE, msg.sender)) deadline += REFUND_DELAY;\n if (block.timestamp \u003c= deadline) revert DeadlineNotExceeded();\n // Update status to REFUNDED and return the full amount (collateral + protocol fees) to the original sender.\n // The protocol fees are only updated when the transaction is claimed, so we don't need to update them here.\n // Note: this is a storage write\n $.status = BridgeStatus.REFUNDED;\n\n address to = request.originSender();\n address token = request.originToken();\n uint256 amount = request.originAmount() + request.originFeeAmount();\n // Emit the event before any external calls\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n // Complete the user refund as the last transaction action\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(to), amount);\n } else {\n IERC20(token).safeTransfer(to, amount);\n }\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // The correct relayer can only claim a RELAYER_PROVED transaction after the dispute period\n if ($.status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if ($.proofRelayer != relayer) revert SenderIncorrect();\n return _timeSince($.proofBlockTimestamp) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n /// @dev This method is added to achieve backwards compatibility with decoding requests into V1 structs:\n /// - `zapNative` is partially reported as a zero/non-zero flag\n /// - `zapData` is ignored\n /// In order to process all kinds of requests use getBridgeTransactionV2 instead.\n function getBridgeTransaction(bytes calldata request) external view returns (BridgeTransaction memory) {\n // Try decoding into V2 struct first. This will revert if V1 struct is passed\n try this.getBridgeTransactionV2(request) returns (BridgeTransactionV2 memory txV2) {\n // Note: we entirely ignore the zapData field, as it was not present in V1\n return BridgeTransaction({\n originChainId: txV2.originChainId,\n destChainId: txV2.destChainId,\n originSender: txV2.originSender,\n destRecipient: txV2.destRecipient,\n originToken: txV2.originToken,\n destToken: txV2.destToken,\n originAmount: txV2.originAmount,\n destAmount: txV2.destAmount,\n originFeeAmount: txV2.originFeeAmount,\n sendChainGas: txV2.zapNative != 0,\n deadline: txV2.deadline,\n nonce: txV2.nonce\n });\n } catch {\n // Fallback to V1 struct\n return abi.decode(request, (BridgeTransaction));\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function getBridgeTransactionV2(bytes calldata request) external pure returns (BridgeTransactionV2 memory) {\n request.validateV2();\n return BridgeTransactionV2Lib.decodeV2(request);\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) public payable {\n int256 exclusivityEndTime = 0;\n // if relayer exclusivity is not intended for this bridge, set exclusivityEndTime to static zero\n // otherwise, set exclusivity to expire at the current block ts offset by quoteExclusivitySeconds\n if (paramsV2.quoteRelayer != address(0)) {\n exclusivityEndTime = int256(block.timestamp) + paramsV2.quoteExclusivitySeconds;\n }\n _validateBridgeParams(params, paramsV2, exclusivityEndTime);\n\n // transfer tokens to bridge contract\n /// @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _takeBridgedUserAsset(params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) {\n originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n }\n\n // set status to requested\n bytes memory request = BridgeTransactionV2Lib.encodeV2(\n BridgeTransactionV2({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n deadline: params.deadline,\n nonce: senderNonces[params.sender]++, // increment nonce on every bridge\n exclusivityRelayer: paramsV2.quoteRelayer,\n // We checked exclusivityEndTime to be in range [0 .. params.deadline] above, so can safely cast\n exclusivityEndTime: uint256(exclusivityEndTime),\n zapNative: paramsV2.zapNative,\n zapData: paramsV2.zapData\n })\n );\n bytes32 transactionId = keccak256(request);\n // Note: the tx status will be updated throughout the tx lifecycle, while destChainId is set once here\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n bridgeTxDetails[transactionId].destChainId = params.dstChainId;\n\n emit BridgeRequested({\n transactionId: transactionId,\n sender: params.sender,\n request: request,\n destChainId: params.dstChainId,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n sendChainGas: paramsV2.zapNative != 0\n });\n emit BridgeQuoteDetails(transactionId, paramsV2.quoteId);\n }\n\n /// @inheritdoc IFastBridgeV2\n function relay(bytes calldata request, address relayer) public payable {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n _validateRelayParams(request, transactionId, relayer);\n // mark bridge transaction as relayed\n bridgeRelayDetails[transactionId] =\n BridgeRelay({blockNumber: uint48(block.number), blockTimestamp: uint48(block.timestamp), relayer: relayer});\n\n // transfer tokens to recipient on destination chain and trigger Zap if requested\n address to = request.destRecipient();\n address token = request.destToken();\n uint256 amount = request.destAmount();\n uint256 zapNative = request.zapNative();\n\n // Emit the event before any external calls\n emit BridgeRelayed({\n transactionId: transactionId,\n relayer: relayer,\n to: to,\n originChainId: request.originChainId(),\n originToken: request.originToken(),\n destToken: token,\n originAmount: request.originAmount(),\n destAmount: amount,\n chainGasAmount: zapNative\n });\n\n // All state changes have been done at this point, can proceed to the external calls.\n // This follows the checks-effects-interactions pattern to mitigate potential reentrancy attacks.\n if (token == NATIVE_GAS_TOKEN) {\n // For the native gas token, additional zapNative is not allowed\n if (zapNative != 0) revert ZapNativeNotSupported();\n // Check that the correct msg.value was sent\n if (msg.value != amount) revert MsgValueIncorrect();\n // Don't do a native transfer yet: we will handle it alongside the Zap below\n } else {\n // For ERC20s, we check that the correct msg.value was sent\n if (msg.value != zapNative) revert MsgValueIncorrect();\n // We need to transfer the tokens from the Relayer to the recipient first before performing an\n // optional post-transfer Zap.\n IERC20(token).safeTransferFrom(msg.sender, to, amount);\n }\n // At this point we have done:\n // - Transferred the requested amount of ERC20 tokens to the recipient.\n // At this point we have confirmed:\n // - For ERC20s: msg.value matches the requested zapNative amount.\n // - For the native gas token: msg.value matches the requested destAmount.\n // Remaining optional things to do:\n // - Forward the full msg.value to the recipient (if non-zero).\n // - Trigger a Zap (if zapData is present).\n bytes calldata zapData = request.zapData();\n if (zapData.length != 0) {\n // Zap Data is present: Zap has been requested by the recipient. Trigger it forwarding the full msg.value.\n\n // Note: if token has a fee on transfers, the recipient will have received less than `amount`.\n // This is a very niche edge case and should be handled by the recipient contract.\n _triggerZapWithChecks({recipient: to, token: token, amount: amount, zapData: zapData});\n } else if (msg.value != 0) {\n // Zap Data is missing, but msg.value was sent. This could happen in two different cases:\n // - Relay with the native gas token is happening.\n // - Relay with ERC20 is happening, with a `zapNative \u003e 0` request.\n // In both cases, we need to transfer the full msg.value to the recipient.\n Address.sendValue(payable(to), msg.value);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) public onlyRole(RELAYER_ROLE) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n\n // Can only prove a REQUESTED transaction\n if ($.status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n // Update status to RELAYER_PROVED and store the proof details\n // Note: these are storage writes\n $.status = BridgeStatus.RELAYER_PROVED;\n $.proofBlockTimestamp = uint56(block.timestamp);\n $.proofRelayer = relayer;\n\n emit BridgeProofProvided(transactionId, relayer, destTxHash);\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes calldata request, address to) public {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Aggregate the read operations from the same storage slot\n address proofRelayer = $.proofRelayer;\n BridgeStatus status = $.status;\n uint56 proofBlockTimestamp = $.proofBlockTimestamp;\n\n // Can only claim a RELAYER_PROVED transaction after the dispute period\n if (status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(proofBlockTimestamp) \u003c= DISPUTE_PERIOD) {\n revert DisputePeriodNotPassed();\n }\n\n if (to == address(0)) {\n // Anyone could claim the funds to the proven relayer on their behalf\n to = proofRelayer;\n } else if (proofRelayer != msg.sender) {\n // Only the proven relayer could specify an address to claim the funds to\n revert SenderIncorrect();\n }\n\n // Update status to RELAYER_CLAIMED and transfer the origin collateral to the specified claim address\n // Note: this is a storage write\n $.status = BridgeStatus.RELAYER_CLAIMED;\n\n address token = request.originToken();\n uint256 amount = request.originAmount();\n // Update protocol fees if origin fee amount exists\n uint256 originFeeAmount = request.originFeeAmount();\n if (originFeeAmount \u003e 0) protocolFees[token] += originFeeAmount;\n // Emit the event before any external calls\n emit BridgeDepositClaimed(transactionId, proofRelayer, to, token, amount);\n // Complete the relayer claim as the last transaction action\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(to), amount);\n } else {\n IERC20(token).safeTransfer(to, amount);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeStatuses(bytes32 transactionId) public view returns (BridgeStatus status) {\n return bridgeTxDetails[transactionId].status;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeProofs(bytes32 transactionId) public view returns (uint96 timestamp, address relayer) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n\n timestamp = $.proofBlockTimestamp;\n relayer = $.proofRelayer;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeRelays(bytes32 transactionId) public view returns (bool) {\n // has this transactionId been relayed?\n return bridgeRelayDetails[transactionId].relayer != address(0);\n }\n\n /// @notice Takes the bridged asset from the user into FastBridgeV2 custody. It will be later\n /// claimed by the relayer who completed the relay on destination chain, or refunded back to the user,\n /// should no one complete the relay.\n function _takeBridgedUserAsset(address token, uint256 amount) internal returns (uint256 amountTaken) {\n if (token == NATIVE_GAS_TOKEN) {\n // For the native gas token, we just need to check that the supplied msg.value is correct.\n // Supplied `msg.value` is already in FastBridgeV2 custody.\n if (amount != msg.value) revert MsgValueIncorrect();\n amountTaken = msg.value;\n } else {\n // For ERC20s, token is explicitly transferred from the user to FastBridgeV2.\n // We don't allow non-zero `msg.value` to avoid extra funds from being stuck in FastBridgeV2.\n if (msg.value != 0) revert MsgValueIncorrect();\n // Throw an explicit error if the provided token address is not a contract\n if (token.code.length == 0) revert TokenNotContract();\n amountTaken = IERC20(token).balanceOf(address(this));\n IERC20(token).safeTransferFrom(msg.sender, address(this), amount);\n // Use the balance difference as the amount taken in case of fee on transfer tokens.\n amountTaken = IERC20(token).balanceOf(address(this)) - amountTaken;\n }\n }\n\n /// @notice Calls the Recipient's hook function with the specified zapData and performs\n /// all the necessary checks for the returned value.\n function _triggerZapWithChecks(address recipient, address token, uint256 amount, bytes calldata zapData) internal {\n // This will bubble any revert messages from the hook function\n bytes memory returnData = Address.functionCallWithValue({\n target: recipient,\n data: abi.encodeCall(IZapRecipient.zap, (token, amount, zapData)),\n // Note: see `relay()` for reasoning behind passing msg.value\n value: msg.value\n });\n // Explicit revert if no return data at all\n if (returnData.length == 0) revert RecipientNoReturnValue();\n // Check that exactly a single return value was returned\n if (returnData.length != 32) revert RecipientIncorrectReturnValue();\n // Return value should be abi-encoded hook function selector\n if (bytes32(returnData) != bytes32(IZapRecipient.zap.selector)) {\n revert RecipientIncorrectReturnValue();\n }\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint56(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint56).max but\n /// proof.timestamp \u003c type(uint56).max via unchecked statement\n /// @param proofBlockTimestamp The bridge proof block timestamp\n /// @return delta Time delta since proof submitted\n function _timeSince(uint56 proofBlockTimestamp) internal view returns (uint256 delta) {\n unchecked {\n delta = uint56(block.timestamp) - proofBlockTimestamp;\n }\n }\n\n /// @notice Performs all the necessary checks for a bridge to happen.\n /// @dev There's no good way to refactor this function to reduce cyclomatic complexity due to\n /// the number of checks that need to be performed, so we skip the code-complexity rule here.\n // solhint-disable-next-line code-complexity\n function _validateBridgeParams(\n BridgeParams memory params,\n BridgeParamsV2 memory paramsV2,\n int256 exclusivityEndTime\n )\n internal\n view\n {\n // Check V1 (legacy) params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.sender == address(0) || params.to == address(0)) revert ZeroAddress();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n // Check V2 params\n if (paramsV2.zapData.length \u003e MAX_ZAP_DATA_LENGTH) revert ZapDataLengthAboveMax();\n if (paramsV2.zapNative != 0 \u0026\u0026 params.destToken == NATIVE_GAS_TOKEN) {\n revert ZapNativeNotSupported();\n }\n // exclusivityEndTime must be in range [0 .. params.deadline]\n if (exclusivityEndTime \u003c 0 || exclusivityEndTime \u003e int256(params.deadline)) {\n revert ExclusivityParamsIncorrect();\n }\n }\n\n /// @notice Performs all the necessary checks for a relay to happen.\n function _validateRelayParams(bytes calldata request, bytes32 transactionId, address relayer) internal view {\n if (relayer == address(0)) revert ZeroAddress();\n // Check if the transaction has already been relayed\n if (bridgeRelays(transactionId)) revert TransactionRelayed();\n if (request.destChainId() != block.chainid) revert ChainIncorrect();\n // Check the deadline for relay to happen\n if (block.timestamp \u003e request.deadline()) revert DeadlineExceeded();\n // Check the exclusivity period, if it is still ongoing\n address exclRelayer = request.exclusivityRelayer();\n if (exclRelayer != address(0) \u0026\u0026 exclRelayer != relayer \u0026\u0026 block.timestamp \u003c= request.exclusivityEndTime()) {\n revert ExclusivityPeriodNotPassed();\n }\n }\n}\n","language":"Solidity","languageVersion":"0.8.24","compilerVersion":"0.8.24","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"","srcMapRuntime":"","abiDefinition":[{"inputs":[],"name":"AmountIncorrect","type":"error"},{"inputs":[],"name":"ChainIncorrect","type":"error"},{"inputs":[],"name":"DeadlineExceeded","type":"error"},{"inputs":[],"name":"DeadlineNotExceeded","type":"error"},{"inputs":[],"name":"DeadlineTooShort","type":"error"},{"inputs":[],"name":"DisputePeriodNotPassed","type":"error"},{"inputs":[],"name":"DisputePeriodPassed","type":"error"},{"inputs":[],"name":"ExclusivityParamsIncorrect","type":"error"},{"inputs":[],"name":"ExclusivityPeriodNotPassed","type":"error"},{"inputs":[],"name":"MsgValueIncorrect","type":"error"},{"inputs":[],"name":"RecipientIncorrectReturnValue","type":"error"},{"inputs":[],"name":"RecipientNoReturnValue","type":"error"},{"inputs":[],"name":"SenderIncorrect","type":"error"},{"inputs":[],"name":"StatusIncorrect","type":"error"},{"inputs":[],"name":"TokenNotContract","type":"error"},{"inputs":[],"name":"TransactionRelayed","type":"error"},{"inputs":[],"name":"ZapDataLengthAboveMax","type":"error"},{"inputs":[],"name":"ZapNativeNotSupported","type":"error"},{"inputs":[],"name":"ZeroAddress","type":"error"}],"userDoc":{"kind":"user","methods":{},"version":1},"developerDoc":{"kind":"dev","methods":{},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[],\"name\":\"AmountIncorrect\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ChainIncorrect\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DeadlineExceeded\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DeadlineNotExceeded\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DeadlineTooShort\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DisputePeriodNotPassed\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DisputePeriodPassed\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ExclusivityParamsIncorrect\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ExclusivityPeriodNotPassed\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"MsgValueIncorrect\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"RecipientIncorrectReturnValue\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"RecipientNoReturnValue\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"SenderIncorrect\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"StatusIncorrect\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"TokenNotContract\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"TransactionRelayed\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ZapDataLengthAboveMax\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ZapNativeNotSupported\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ZeroAddress\",\"type\":\"error\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeV2.sol\":\"IFastBridgeV2Errors\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeV2.sol\":{\"keccak256\":\"0x5069b55ca07f21bfe30b2a43c18a18318c8af9c181b2dcb07c290825efd70f34\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://273dc020a49d08e50126bbea0d7f783f79d08c702f2fdbc560618d24af308acc\",\"dweb:/ipfs/QmXJ2UVzFc8EPB74RT4CXQPC4xw66jt4T13poyfyd3UERh\"]}},\"version\":1}"},"hashes":{}},"solidity/FastBridgeV2.sol:IMulticallTarget":{"code":"0x","runtime-code":"0x","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.24 ^0.8.20 ^0.8.4;\n\n// contracts/interfaces/IAdmin.sol\n\ninterface IAdmin {\n // ============ Events ============\n\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n event ChainGasAmountUpdated(uint256 oldChainGasAmount, uint256 newChainGasAmount);\n\n // ============ Methods ============\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n\n function setChainGasAmount(uint256 newChainGasAmount) external;\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IFastBridgeV2Errors.sol\n\ninterface IFastBridgeV2Errors {\n error AmountIncorrect();\n error ChainIncorrect();\n error ExclusivityParamsIncorrect();\n error MsgValueIncorrect();\n error SenderIncorrect();\n error StatusIncorrect();\n error TokenNotContract();\n error ZapDataLengthAboveMax();\n error ZapNativeNotSupported();\n error ZeroAddress();\n\n error RecipientIncorrectReturnValue();\n error RecipientNoReturnValue();\n\n error DeadlineExceeded();\n error DeadlineNotExceeded();\n error DeadlineTooShort();\n error DisputePeriodNotPassed();\n error DisputePeriodPassed();\n error ExclusivityPeriodNotPassed();\n\n error TransactionRelayed();\n}\n\n// contracts/interfaces/IMulticallTarget.sol\n\n/// @notice Interface for a contract that can be called multiple times by the same caller. Inspired by MulticallV3:\n/// https://github.com/mds1/multicall/blob/master/src/Multicall3.sol\ninterface IMulticallTarget {\n struct Result {\n bool success;\n bytes returnData;\n }\n\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external;\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results);\n}\n\n// contracts/interfaces/IZapRecipient.sol\n\ninterface IZapRecipient {\n function zap(address token, uint256 amount, bytes memory zapData) external payable returns (bytes4);\n}\n\n// contracts/libs/Errors.sol\n\nerror DeadlineExceeded();\nerror DeadlineNotExceeded();\nerror DeadlineTooShort();\nerror InsufficientOutputAmount();\n\nerror MsgValueIncorrect();\nerror PoolNotFound();\nerror TokenAddressMismatch();\nerror TokenNotContract();\nerror TokenNotETH();\nerror TokensIdentical();\n\nerror ChainIncorrect();\nerror AmountIncorrect();\nerror ZeroAddress();\n\nerror DisputePeriodNotPassed();\nerror DisputePeriodPassed();\nerror SenderIncorrect();\nerror StatusIncorrect();\nerror TransactionIdIncorrect();\nerror TransactionRelayed();\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// contracts/interfaces/IFastBridgeV2.sol\n\ninterface IFastBridgeV2 is IFastBridge {\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n struct BridgeTxDetails {\n BridgeStatus status;\n uint32 destChainId;\n uint56 proofBlockTimestamp;\n address proofRelayer;\n }\n\n struct BridgeRelay {\n uint48 blockNumber;\n uint48 blockTimestamp;\n address relayer;\n }\n\n /// @notice New params introduced in the FastBridgeV2.\n /// We are passing fields from the older BridgeParams struct outside of this struct\n /// for backwards compatibility.\n /// Note: quoteRelayer and quoteExclusivitySeconds are either both zero (indicating no exclusivity)\n /// or both non-zero (indicating exclusivity for the given period).\n /// Note: zapNative \u003e 0 can NOT be used with destToken = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE (native token)\n /// @param quoteRelayer Relayer that provided the quote for the transaction\n /// @param quoteExclusivitySeconds Period of time the quote relayer is guaranteed exclusivity after user's deposit\n /// @param quoteId Unique quote identifier used for tracking the quote\n /// @param zapNative ETH value to send to the recipient (if any)\n /// @param zapData Parameters for the Zap to the destination recipient (if any)\n struct BridgeParamsV2 {\n address quoteRelayer;\n int256 quoteExclusivitySeconds;\n bytes quoteId;\n uint256 zapNative;\n bytes zapData;\n }\n\n /// @notice Updated bridge transaction struct to include parameters introduced in FastBridgeV2.\n /// Note: only `exclusivityRelayer` can fill such a transaction until `exclusivityEndTime`.\n struct BridgeTransactionV2 {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n // Note: sendChainGas flag from V1 is deprecated\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n address exclusivityRelayer;\n uint256 exclusivityEndTime;\n uint256 zapNative; // ETH value to send to the recipient (if any)\n bytes zapData; // data to pass for the Zap action (if any)\n }\n\n event BridgeQuoteDetails(bytes32 indexed transactionId, bytes quoteId);\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability\n /// to provide temporary exclusivity fill rights for the quote relayer.\n /// @param params The parameters required to bridge\n /// @param paramsV2 The parameters for exclusivity fill rights (optional, can be left empty)\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function relay(bytes memory request, address relayer) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param transactionId The transaction id associated with the encoded bridge transaction to prove\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital.\n /// @notice Can only send funds to the relayer address on the proof.\n /// @param request The encoded bridge transaction to claim on origin chain\n function claim(bytes memory request) external;\n /// @notice Checks if a transaction has been relayed\n /// @param transactionId The ID of the transaction to check\n /// @return True if the transaction has been relayed, false otherwise\n function bridgeRelays(bytes32 transactionId) external view returns (bool);\n\n /// @notice Returns the status of a bridge transaction\n /// @param transactionId The ID of the bridge transaction\n /// @return BridgeStatus Status of the bridge transaction\n function bridgeStatuses(bytes32 transactionId) external view returns (BridgeStatus);\n\n /// @notice Returns the timestamp and relayer of a bridge proof\n /// @param transactionId The ID of the bridge transaction\n /// @return timestamp The timestamp of the bridge proof\n /// @return relayer The relayer address of the bridge proof\n function bridgeProofs(bytes32 transactionId) external view returns (uint96 timestamp, address relayer);\n\n /// @notice Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\n /// @param request The bridge request to decode\n function getBridgeTransactionV2(bytes memory request) external view returns (BridgeTransactionV2 memory);\n}\n\n// contracts/utils/MulticallTarget.sol\n\n// solhint-disable avoid-low-level-calls\n/// @notice Template for a contract that supports batched calls (preserving the msg.sender).\n/// Only calls with zero msg.value could be batched.\nabstract contract MulticallTarget is IMulticallTarget {\n error MulticallTarget__UndeterminedRevert();\n\n /// @notice Perform a batched call to this contract, preserving the msg.sender.\n /// The return data from each call is discarded.\n /// @dev The method is non-payable, so only calls with `msg.value == 0` could be batched.\n /// It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag.\n /// Otherwise, the whole batch call will be reverted with the original revert reason.\n /// @param data List of abi-encoded calldata for the calls to perform.\n /// @param ignoreReverts Whether to ignore the revert errors from the calls.\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external {\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\n if (!success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(result);\n }\n }\n }\n\n /// @notice Perform a batched call to this contract, preserving the msg.sender.\n /// The return data from each call is preserved.\n /// @dev The method is non-payable, so only calls with `msg.value == 0` could be batched.\n /// It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag.\n /// Otherwise, the whole batch call will be reverted with the original revert reason.\n /// @param data List of abi-encoded calldata for the calls to perform.\n /// @param ignoreReverts Whether to ignore the revert errors from the calls.\n /// @return results List of results from the calls: `(success, returnData)`.\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results)\n {\n results = new Result[](data.length);\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (results[i].success, results[i].returnData) = address(this).delegatecall(data[i]);\n if (!results[i].success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(results[i].returnData);\n }\n }\n }\n\n /// @dev Bubbles the revert message from the underlying call.\n /// Note: preserves the same custom error or revert string, if one was used.\n /// Source: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v5.0.2/contracts/utils/Address.sol#L143-L158\n function _bubbleRevert(bytes memory returnData) internal pure {\n // Look for revert reason and bubble it up if present\n if (returnData.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n // solhint-disable-next-line no-inline-assembly\n assembly {\n let returndata_size := mload(returnData)\n revert(add(32, returnData), returndata_size)\n }\n } else {\n revert MulticallTarget__UndeterminedRevert();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// contracts/libs/BridgeTransactionV2.sol\n\n// solhint-disable no-inline-assembly\nlibrary BridgeTransactionV2Lib {\n uint16 internal constant VERSION = 2;\n\n // Offsets of the fields in the packed BridgeTransactionV2 struct\n // uint16 version [000 .. 002)\n // uint32 originChainId [002 .. 006)\n // uint32 destChainId [006 .. 010)\n // address originSender [010 .. 030)\n // address destRecipient [030 .. 050)\n // address originToken [050 .. 070)\n // address destToken [070 .. 090)\n // uint256 originAmount [090 .. 122)\n // uint256 destAmount [122 .. 154)\n // uint256 originFeeAmount [154 .. 186)\n // uint256 deadline [186 .. 218)\n // uint256 nonce [218 .. 250)\n // address exclusivityRelayer [250 .. 270)\n // uint256 exclusivityEndTime [270 .. 302)\n // uint256 zapNative [302 .. 334)\n // bytes zapData [334 .. ***)\n\n // forgefmt: disable-start\n uint256 private constant OFFSET_ORIGIN_CHAIN_ID = 2;\n uint256 private constant OFFSET_DEST_CHAIN_ID = 6;\n uint256 private constant OFFSET_ORIGIN_SENDER = 10;\n uint256 private constant OFFSET_DEST_RECIPIENT = 30;\n uint256 private constant OFFSET_ORIGIN_TOKEN = 50;\n uint256 private constant OFFSET_DEST_TOKEN = 70;\n uint256 private constant OFFSET_ORIGIN_AMOUNT = 90;\n uint256 private constant OFFSET_DEST_AMOUNT = 122;\n uint256 private constant OFFSET_ORIGIN_FEE_AMOUNT = 154;\n uint256 private constant OFFSET_DEADLINE = 186;\n uint256 private constant OFFSET_NONCE = 218;\n uint256 private constant OFFSET_EXCLUSIVITY_RELAYER = 250;\n uint256 private constant OFFSET_EXCLUSIVITY_END_TIME = 270;\n uint256 private constant OFFSET_ZAP_NATIVE = 302;\n uint256 private constant OFFSET_ZAP_DATA = 334;\n // forgefmt: disable-end\n\n error BridgeTransactionV2__InvalidEncodedTx();\n error BridgeTransactionV2__UnsupportedVersion(uint16 version);\n\n /// @notice Validates the encoded transaction to be a tightly packed encoded payload for BridgeTransactionV2.\n /// @dev Checks the minimum length and the version, use this function before decoding any of the fields.\n function validateV2(bytes calldata encodedTx) internal pure {\n // Check the minimum length: must at least include all static fields.\n if (encodedTx.length \u003c OFFSET_ZAP_DATA) revert BridgeTransactionV2__InvalidEncodedTx();\n // Once we validated the length, we can be sure that the version field is present.\n uint16 version_ = version(encodedTx);\n if (version_ != VERSION) revert BridgeTransactionV2__UnsupportedVersion(version_);\n }\n\n /// @notice Encodes the BridgeTransactionV2 struct by tightly packing the fields.\n /// @dev `abi.decode` will not work as a result of the tightly packed fields. Use `decodeV2` to decode instead.\n function encodeV2(IFastBridgeV2.BridgeTransactionV2 memory bridgeTx) internal pure returns (bytes memory) {\n // We split the encoding into two parts to avoid stack-too-deep error\n bytes memory firstPart = abi.encodePacked(\n VERSION,\n bridgeTx.originChainId,\n bridgeTx.destChainId,\n bridgeTx.originSender,\n bridgeTx.destRecipient,\n bridgeTx.originToken,\n bridgeTx.destToken,\n bridgeTx.originAmount\n );\n return abi.encodePacked(\n firstPart,\n bridgeTx.destAmount,\n bridgeTx.originFeeAmount,\n // Note: we skip the deprecated `sendChainGas` flag, which was present in BridgeTransaction V1\n bridgeTx.deadline,\n bridgeTx.nonce,\n // New V2 fields: exclusivity\n bridgeTx.exclusivityRelayer,\n bridgeTx.exclusivityEndTime,\n // New V2 fields: Zap\n bridgeTx.zapNative,\n bridgeTx.zapData\n );\n }\n\n /// @notice Decodes the BridgeTransactionV2 struct from the encoded transaction.\n /// @dev Encoded BridgeTransactionV2 struct must be tightly packed.\n /// Use `validateV2` before decoding to ensure the encoded transaction is valid.\n function decodeV2(bytes calldata encodedTx)\n internal\n pure\n returns (IFastBridgeV2.BridgeTransactionV2 memory bridgeTx)\n {\n bridgeTx.originChainId = originChainId(encodedTx);\n bridgeTx.destChainId = destChainId(encodedTx);\n bridgeTx.originSender = originSender(encodedTx);\n bridgeTx.destRecipient = destRecipient(encodedTx);\n bridgeTx.originToken = originToken(encodedTx);\n bridgeTx.destToken = destToken(encodedTx);\n bridgeTx.originAmount = originAmount(encodedTx);\n bridgeTx.destAmount = destAmount(encodedTx);\n bridgeTx.originFeeAmount = originFeeAmount(encodedTx);\n bridgeTx.deadline = deadline(encodedTx);\n bridgeTx.nonce = nonce(encodedTx);\n bridgeTx.exclusivityRelayer = exclusivityRelayer(encodedTx);\n bridgeTx.exclusivityEndTime = exclusivityEndTime(encodedTx);\n bridgeTx.zapNative = zapNative(encodedTx);\n bridgeTx.zapData = zapData(encodedTx);\n }\n\n /// @notice Extracts the version from the encoded transaction.\n function version(bytes calldata encodedTx) internal pure returns (uint16 version_) {\n // Load 32 bytes from the start and shift it 240 bits to the right to get the highest 16 bits.\n assembly {\n version_ := shr(240, calldataload(encodedTx.offset))\n }\n }\n\n /// @notice Extracts the origin chain ID from the encoded transaction.\n function originChainId(bytes calldata encodedTx) internal pure returns (uint32 originChainId_) {\n // Load 32 bytes from the offset and shift it 224 bits to the right to get the highest 32 bits.\n assembly {\n originChainId_ := shr(224, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_CHAIN_ID)))\n }\n }\n\n /// @notice Extracts the destination chain ID from the encoded transaction.\n function destChainId(bytes calldata encodedTx) internal pure returns (uint32 destChainId_) {\n // Load 32 bytes from the offset and shift it 224 bits to the right to get the highest 32 bits.\n assembly {\n destChainId_ := shr(224, calldataload(add(encodedTx.offset, OFFSET_DEST_CHAIN_ID)))\n }\n }\n\n /// @notice Extracts the origin sender from the encoded transaction.\n function originSender(bytes calldata encodedTx) internal pure returns (address originSender_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n originSender_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_SENDER)))\n }\n }\n\n /// @notice Extracts the destination recipient from the encoded transaction.\n function destRecipient(bytes calldata encodedTx) internal pure returns (address destRecipient_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n destRecipient_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_DEST_RECIPIENT)))\n }\n }\n\n /// @notice Extracts the origin token from the encoded transaction.\n function originToken(bytes calldata encodedTx) internal pure returns (address originToken_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n originToken_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_TOKEN)))\n }\n }\n\n /// @notice Extracts the destination token from the encoded transaction.\n function destToken(bytes calldata encodedTx) internal pure returns (address destToken_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n destToken_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_DEST_TOKEN)))\n }\n }\n\n /// @notice Extracts the origin amount from the encoded transaction.\n function originAmount(bytes calldata encodedTx) internal pure returns (uint256 originAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n originAmount_ := calldataload(add(encodedTx.offset, OFFSET_ORIGIN_AMOUNT))\n }\n }\n\n /// @notice Extracts the destination amount from the encoded transaction.\n function destAmount(bytes calldata encodedTx) internal pure returns (uint256 destAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n destAmount_ := calldataload(add(encodedTx.offset, OFFSET_DEST_AMOUNT))\n }\n }\n\n /// @notice Extracts the origin fee amount from the encoded transaction.\n function originFeeAmount(bytes calldata encodedTx) internal pure returns (uint256 originFeeAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n originFeeAmount_ := calldataload(add(encodedTx.offset, OFFSET_ORIGIN_FEE_AMOUNT))\n }\n }\n\n /// @notice Extracts the deadline from the encoded transaction.\n function deadline(bytes calldata encodedTx) internal pure returns (uint256 deadline_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n deadline_ := calldataload(add(encodedTx.offset, OFFSET_DEADLINE))\n }\n }\n\n /// @notice Extracts the nonce from the encoded transaction.\n function nonce(bytes calldata encodedTx) internal pure returns (uint256 nonce_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n nonce_ := calldataload(add(encodedTx.offset, OFFSET_NONCE))\n }\n }\n\n /// @notice Extracts the exclusivity relayer from the encoded transaction.\n function exclusivityRelayer(bytes calldata encodedTx) internal pure returns (address exclusivityRelayer_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n exclusivityRelayer_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_EXCLUSIVITY_RELAYER)))\n }\n }\n\n /// @notice Extracts the exclusivity end time from the encoded transaction.\n function exclusivityEndTime(bytes calldata encodedTx) internal pure returns (uint256 exclusivityEndTime_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n exclusivityEndTime_ := calldataload(add(encodedTx.offset, OFFSET_EXCLUSIVITY_END_TIME))\n }\n }\n\n /// @notice Extracts the Zap's native value from the encoded transaction.\n function zapNative(bytes calldata encodedTx) internal pure returns (uint256 zapNative_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n zapNative_ := calldataload(add(encodedTx.offset, OFFSET_ZAP_NATIVE))\n }\n }\n\n /// @notice Extracts the Zap's data from the encoded transaction.\n function zapData(bytes calldata encodedTx) internal pure returns (bytes calldata zapData_) {\n zapData_ = encodedTx[OFFSET_ZAP_DATA:];\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// contracts/libs/UniversalToken.sol\n\nlibrary UniversalTokenLib {\n using SafeERC20 for IERC20;\n\n address internal constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Transfers tokens to the given account. Reverts if transfer is not successful.\n /// @dev This might trigger fallback, if ETH is transferred to the contract.\n /// Make sure this can not lead to reentrancy attacks.\n function universalTransfer(address token, address to, uint256 value) internal {\n // Don't do anything, if need to send tokens to this address\n if (to == address(this)) return;\n // Don't do anything, if trying to send zero value\n if (value == 0) return;\n if (token == ETH_ADDRESS) {\n /// @dev Note: this can potentially lead to executing code in `to`.\n // solhint-disable-next-line avoid-low-level-calls\n (bool success,) = to.call{value: value}(\"\");\n require(success, \"ETH transfer failed\");\n } else {\n IERC20(token).safeTransfer(to, value);\n }\n }\n\n /// @notice Issues an infinite allowance to the spender, if the current allowance is insufficient\n /// to spend the given amount.\n function universalApproveInfinity(address token, address spender, uint256 amountToSpend) internal {\n // ETH Chad doesn't require your approval\n if (token == ETH_ADDRESS) return;\n // No-op if allowance is already sufficient\n uint256 allowance = IERC20(token).allowance(address(this), spender);\n if (allowance \u003e= amountToSpend) return;\n // Otherwise, reset approval to 0 and set to max allowance\n if (allowance \u003e 0) IERC20(token).safeDecreaseAllowance(spender, allowance);\n IERC20(token).safeIncreaseAllowance(spender, type(uint256).max);\n }\n\n /// @notice Returns the balance of the given token (or native ETH) for the given account.\n function universalBalanceOf(address token, address account) internal view returns (uint256) {\n if (token == ETH_ADDRESS) {\n return account.balance;\n } else {\n return IERC20(token).balanceOf(account);\n }\n }\n\n /// @dev Checks that token is a contract and not ETH_ADDRESS.\n function assertIsContract(address token) internal view {\n // Check that ETH_ADDRESS was not used (in case this is a predeploy on any of the chains)\n if (token == UniversalTokenLib.ETH_ADDRESS) revert TokenNotContract();\n // Check that token is not an EOA\n if (token.code.length == 0) revert TokenNotContract();\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/Admin.sol\n\ncontract Admin is IAdmin, AccessControlEnumerable {\n using UniversalTokenLib for address;\n\n bytes32 public constant RELAYER_ROLE = keccak256(\"RELAYER_ROLE\");\n bytes32 public constant REFUNDER_ROLE = keccak256(\"REFUNDER_ROLE\");\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n uint256 public constant FEE_BPS = 1e6;\n uint256 public constant FEE_RATE_MAX = 0.01e6; // max 1% on origin amount\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Chain gas amount to forward as rebate if requested\n uint256 public chainGasAmount;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n }\n\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n require(newFeeRate \u003c= FEE_RATE_MAX, \"newFeeRate \u003e max\");\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n token.universalTransfer(recipient, feeAmount);\n emit FeesSwept(token, recipient, feeAmount);\n }\n\n function setChainGasAmount(uint256 newChainGasAmount) external onlyRole(GOVERNOR_ROLE) {\n uint256 oldChainGasAmount = chainGasAmount;\n chainGasAmount = newChainGasAmount;\n emit ChainGasAmountUpdated(oldChainGasAmount, newChainGasAmount);\n }\n}\n\n// contracts/FastBridgeV2.sol\n\n/// @notice FastBridgeV2 is a contract for bridging tokens across chains.\ncontract FastBridgeV2 is Admin, MulticallTarget, IFastBridgeV2, IFastBridgeV2Errors {\n using BridgeTransactionV2Lib for bytes;\n using SafeERC20 for IERC20;\n\n /// @notice Address reserved for native gas token (ETH on Ethereum and most L2s, AVAX on Avalanche, etc)\n address public constant NATIVE_GAS_TOKEN = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Delay for a transaction after which it could be permisionlessly refunded\n uint256 public constant REFUND_DELAY = 7 days;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n /// @notice Maximum length of accepted zapData\n uint256 public constant MAX_ZAP_DATA_LENGTH = 2 ** 16 - 1;\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeTxDetails) public bridgeTxDetails;\n /// @notice Relay details on destination chain\n mapping(bytes32 =\u003e BridgeRelay) public bridgeRelayDetails;\n /// @notice Unique bridge nonces tracked per originSender\n mapping(address =\u003e uint256) public senderNonces;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Replaced by senderNonces\n uint256 public immutable nonce = 0;\n /// @notice the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n bridge({\n params: params,\n paramsV2: BridgeParamsV2({\n quoteRelayer: address(0),\n quoteExclusivitySeconds: 0,\n quoteId: bytes(\"\"),\n zapNative: 0,\n zapData: bytes(\"\")\n })\n });\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes calldata request) external payable {\n // relay override will validate the request\n relay({request: request, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes calldata request, bytes32 destTxHash) external {\n request.validateV2();\n prove({transactionId: keccak256(request), destTxHash: destTxHash, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridgeV2\n function claim(bytes calldata request) external {\n // claim override will validate the request\n claim({request: request, to: address(0)});\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Aggregate the read operations from the same storage slot\n address disputedRelayer = $.proofRelayer;\n BridgeStatus status = $.status;\n uint56 proofBlockTimestamp = $.proofBlockTimestamp;\n // Can only dispute a RELAYER_PROVED transaction within the dispute period\n if (status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(proofBlockTimestamp) \u003e DISPUTE_PERIOD) {\n revert DisputePeriodPassed();\n }\n // Update status to REQUESTED and delete the disputed proof details\n // Note: these are storage writes\n $.status = BridgeStatus.REQUESTED;\n $.proofRelayer = address(0);\n $.proofBlockTimestamp = 0;\n\n emit BridgeProofDisputed(transactionId, disputedRelayer);\n }\n\n /// @inheritdoc IFastBridge\n function refund(bytes calldata request) external {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Can only refund a REQUESTED transaction after its deadline expires\n if ($.status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n uint256 deadline = request.deadline();\n // Permissionless refund is only allowed after REFUND_DELAY on top of the deadline\n if (!hasRole(REFUNDER_ROLE, msg.sender)) deadline += REFUND_DELAY;\n if (block.timestamp \u003c= deadline) revert DeadlineNotExceeded();\n // Update status to REFUNDED and return the full amount (collateral + protocol fees) to the original sender.\n // The protocol fees are only updated when the transaction is claimed, so we don't need to update them here.\n // Note: this is a storage write\n $.status = BridgeStatus.REFUNDED;\n\n address to = request.originSender();\n address token = request.originToken();\n uint256 amount = request.originAmount() + request.originFeeAmount();\n // Emit the event before any external calls\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n // Complete the user refund as the last transaction action\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(to), amount);\n } else {\n IERC20(token).safeTransfer(to, amount);\n }\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // The correct relayer can only claim a RELAYER_PROVED transaction after the dispute period\n if ($.status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if ($.proofRelayer != relayer) revert SenderIncorrect();\n return _timeSince($.proofBlockTimestamp) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n /// @dev This method is added to achieve backwards compatibility with decoding requests into V1 structs:\n /// - `zapNative` is partially reported as a zero/non-zero flag\n /// - `zapData` is ignored\n /// In order to process all kinds of requests use getBridgeTransactionV2 instead.\n function getBridgeTransaction(bytes calldata request) external view returns (BridgeTransaction memory) {\n // Try decoding into V2 struct first. This will revert if V1 struct is passed\n try this.getBridgeTransactionV2(request) returns (BridgeTransactionV2 memory txV2) {\n // Note: we entirely ignore the zapData field, as it was not present in V1\n return BridgeTransaction({\n originChainId: txV2.originChainId,\n destChainId: txV2.destChainId,\n originSender: txV2.originSender,\n destRecipient: txV2.destRecipient,\n originToken: txV2.originToken,\n destToken: txV2.destToken,\n originAmount: txV2.originAmount,\n destAmount: txV2.destAmount,\n originFeeAmount: txV2.originFeeAmount,\n sendChainGas: txV2.zapNative != 0,\n deadline: txV2.deadline,\n nonce: txV2.nonce\n });\n } catch {\n // Fallback to V1 struct\n return abi.decode(request, (BridgeTransaction));\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function getBridgeTransactionV2(bytes calldata request) external pure returns (BridgeTransactionV2 memory) {\n request.validateV2();\n return BridgeTransactionV2Lib.decodeV2(request);\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) public payable {\n int256 exclusivityEndTime = 0;\n // if relayer exclusivity is not intended for this bridge, set exclusivityEndTime to static zero\n // otherwise, set exclusivity to expire at the current block ts offset by quoteExclusivitySeconds\n if (paramsV2.quoteRelayer != address(0)) {\n exclusivityEndTime = int256(block.timestamp) + paramsV2.quoteExclusivitySeconds;\n }\n _validateBridgeParams(params, paramsV2, exclusivityEndTime);\n\n // transfer tokens to bridge contract\n /// @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _takeBridgedUserAsset(params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) {\n originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n }\n\n // set status to requested\n bytes memory request = BridgeTransactionV2Lib.encodeV2(\n BridgeTransactionV2({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n deadline: params.deadline,\n nonce: senderNonces[params.sender]++, // increment nonce on every bridge\n exclusivityRelayer: paramsV2.quoteRelayer,\n // We checked exclusivityEndTime to be in range [0 .. params.deadline] above, so can safely cast\n exclusivityEndTime: uint256(exclusivityEndTime),\n zapNative: paramsV2.zapNative,\n zapData: paramsV2.zapData\n })\n );\n bytes32 transactionId = keccak256(request);\n // Note: the tx status will be updated throughout the tx lifecycle, while destChainId is set once here\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n bridgeTxDetails[transactionId].destChainId = params.dstChainId;\n\n emit BridgeRequested({\n transactionId: transactionId,\n sender: params.sender,\n request: request,\n destChainId: params.dstChainId,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n sendChainGas: paramsV2.zapNative != 0\n });\n emit BridgeQuoteDetails(transactionId, paramsV2.quoteId);\n }\n\n /// @inheritdoc IFastBridgeV2\n function relay(bytes calldata request, address relayer) public payable {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n _validateRelayParams(request, transactionId, relayer);\n // mark bridge transaction as relayed\n bridgeRelayDetails[transactionId] =\n BridgeRelay({blockNumber: uint48(block.number), blockTimestamp: uint48(block.timestamp), relayer: relayer});\n\n // transfer tokens to recipient on destination chain and trigger Zap if requested\n address to = request.destRecipient();\n address token = request.destToken();\n uint256 amount = request.destAmount();\n uint256 zapNative = request.zapNative();\n\n // Emit the event before any external calls\n emit BridgeRelayed({\n transactionId: transactionId,\n relayer: relayer,\n to: to,\n originChainId: request.originChainId(),\n originToken: request.originToken(),\n destToken: token,\n originAmount: request.originAmount(),\n destAmount: amount,\n chainGasAmount: zapNative\n });\n\n // All state changes have been done at this point, can proceed to the external calls.\n // This follows the checks-effects-interactions pattern to mitigate potential reentrancy attacks.\n if (token == NATIVE_GAS_TOKEN) {\n // For the native gas token, additional zapNative is not allowed\n if (zapNative != 0) revert ZapNativeNotSupported();\n // Check that the correct msg.value was sent\n if (msg.value != amount) revert MsgValueIncorrect();\n // Don't do a native transfer yet: we will handle it alongside the Zap below\n } else {\n // For ERC20s, we check that the correct msg.value was sent\n if (msg.value != zapNative) revert MsgValueIncorrect();\n // We need to transfer the tokens from the Relayer to the recipient first before performing an\n // optional post-transfer Zap.\n IERC20(token).safeTransferFrom(msg.sender, to, amount);\n }\n // At this point we have done:\n // - Transferred the requested amount of ERC20 tokens to the recipient.\n // At this point we have confirmed:\n // - For ERC20s: msg.value matches the requested zapNative amount.\n // - For the native gas token: msg.value matches the requested destAmount.\n // Remaining optional things to do:\n // - Forward the full msg.value to the recipient (if non-zero).\n // - Trigger a Zap (if zapData is present).\n bytes calldata zapData = request.zapData();\n if (zapData.length != 0) {\n // Zap Data is present: Zap has been requested by the recipient. Trigger it forwarding the full msg.value.\n\n // Note: if token has a fee on transfers, the recipient will have received less than `amount`.\n // This is a very niche edge case and should be handled by the recipient contract.\n _triggerZapWithChecks({recipient: to, token: token, amount: amount, zapData: zapData});\n } else if (msg.value != 0) {\n // Zap Data is missing, but msg.value was sent. This could happen in two different cases:\n // - Relay with the native gas token is happening.\n // - Relay with ERC20 is happening, with a `zapNative \u003e 0` request.\n // In both cases, we need to transfer the full msg.value to the recipient.\n Address.sendValue(payable(to), msg.value);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) public onlyRole(RELAYER_ROLE) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n\n // Can only prove a REQUESTED transaction\n if ($.status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n // Update status to RELAYER_PROVED and store the proof details\n // Note: these are storage writes\n $.status = BridgeStatus.RELAYER_PROVED;\n $.proofBlockTimestamp = uint56(block.timestamp);\n $.proofRelayer = relayer;\n\n emit BridgeProofProvided(transactionId, relayer, destTxHash);\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes calldata request, address to) public {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Aggregate the read operations from the same storage slot\n address proofRelayer = $.proofRelayer;\n BridgeStatus status = $.status;\n uint56 proofBlockTimestamp = $.proofBlockTimestamp;\n\n // Can only claim a RELAYER_PROVED transaction after the dispute period\n if (status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(proofBlockTimestamp) \u003c= DISPUTE_PERIOD) {\n revert DisputePeriodNotPassed();\n }\n\n if (to == address(0)) {\n // Anyone could claim the funds to the proven relayer on their behalf\n to = proofRelayer;\n } else if (proofRelayer != msg.sender) {\n // Only the proven relayer could specify an address to claim the funds to\n revert SenderIncorrect();\n }\n\n // Update status to RELAYER_CLAIMED and transfer the origin collateral to the specified claim address\n // Note: this is a storage write\n $.status = BridgeStatus.RELAYER_CLAIMED;\n\n address token = request.originToken();\n uint256 amount = request.originAmount();\n // Update protocol fees if origin fee amount exists\n uint256 originFeeAmount = request.originFeeAmount();\n if (originFeeAmount \u003e 0) protocolFees[token] += originFeeAmount;\n // Emit the event before any external calls\n emit BridgeDepositClaimed(transactionId, proofRelayer, to, token, amount);\n // Complete the relayer claim as the last transaction action\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(to), amount);\n } else {\n IERC20(token).safeTransfer(to, amount);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeStatuses(bytes32 transactionId) public view returns (BridgeStatus status) {\n return bridgeTxDetails[transactionId].status;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeProofs(bytes32 transactionId) public view returns (uint96 timestamp, address relayer) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n\n timestamp = $.proofBlockTimestamp;\n relayer = $.proofRelayer;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeRelays(bytes32 transactionId) public view returns (bool) {\n // has this transactionId been relayed?\n return bridgeRelayDetails[transactionId].relayer != address(0);\n }\n\n /// @notice Takes the bridged asset from the user into FastBridgeV2 custody. It will be later\n /// claimed by the relayer who completed the relay on destination chain, or refunded back to the user,\n /// should no one complete the relay.\n function _takeBridgedUserAsset(address token, uint256 amount) internal returns (uint256 amountTaken) {\n if (token == NATIVE_GAS_TOKEN) {\n // For the native gas token, we just need to check that the supplied msg.value is correct.\n // Supplied `msg.value` is already in FastBridgeV2 custody.\n if (amount != msg.value) revert MsgValueIncorrect();\n amountTaken = msg.value;\n } else {\n // For ERC20s, token is explicitly transferred from the user to FastBridgeV2.\n // We don't allow non-zero `msg.value` to avoid extra funds from being stuck in FastBridgeV2.\n if (msg.value != 0) revert MsgValueIncorrect();\n // Throw an explicit error if the provided token address is not a contract\n if (token.code.length == 0) revert TokenNotContract();\n amountTaken = IERC20(token).balanceOf(address(this));\n IERC20(token).safeTransferFrom(msg.sender, address(this), amount);\n // Use the balance difference as the amount taken in case of fee on transfer tokens.\n amountTaken = IERC20(token).balanceOf(address(this)) - amountTaken;\n }\n }\n\n /// @notice Calls the Recipient's hook function with the specified zapData and performs\n /// all the necessary checks for the returned value.\n function _triggerZapWithChecks(address recipient, address token, uint256 amount, bytes calldata zapData) internal {\n // This will bubble any revert messages from the hook function\n bytes memory returnData = Address.functionCallWithValue({\n target: recipient,\n data: abi.encodeCall(IZapRecipient.zap, (token, amount, zapData)),\n // Note: see `relay()` for reasoning behind passing msg.value\n value: msg.value\n });\n // Explicit revert if no return data at all\n if (returnData.length == 0) revert RecipientNoReturnValue();\n // Check that exactly a single return value was returned\n if (returnData.length != 32) revert RecipientIncorrectReturnValue();\n // Return value should be abi-encoded hook function selector\n if (bytes32(returnData) != bytes32(IZapRecipient.zap.selector)) {\n revert RecipientIncorrectReturnValue();\n }\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint56(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint56).max but\n /// proof.timestamp \u003c type(uint56).max via unchecked statement\n /// @param proofBlockTimestamp The bridge proof block timestamp\n /// @return delta Time delta since proof submitted\n function _timeSince(uint56 proofBlockTimestamp) internal view returns (uint256 delta) {\n unchecked {\n delta = uint56(block.timestamp) - proofBlockTimestamp;\n }\n }\n\n /// @notice Performs all the necessary checks for a bridge to happen.\n /// @dev There's no good way to refactor this function to reduce cyclomatic complexity due to\n /// the number of checks that need to be performed, so we skip the code-complexity rule here.\n // solhint-disable-next-line code-complexity\n function _validateBridgeParams(\n BridgeParams memory params,\n BridgeParamsV2 memory paramsV2,\n int256 exclusivityEndTime\n )\n internal\n view\n {\n // Check V1 (legacy) params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.sender == address(0) || params.to == address(0)) revert ZeroAddress();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n // Check V2 params\n if (paramsV2.zapData.length \u003e MAX_ZAP_DATA_LENGTH) revert ZapDataLengthAboveMax();\n if (paramsV2.zapNative != 0 \u0026\u0026 params.destToken == NATIVE_GAS_TOKEN) {\n revert ZapNativeNotSupported();\n }\n // exclusivityEndTime must be in range [0 .. params.deadline]\n if (exclusivityEndTime \u003c 0 || exclusivityEndTime \u003e int256(params.deadline)) {\n revert ExclusivityParamsIncorrect();\n }\n }\n\n /// @notice Performs all the necessary checks for a relay to happen.\n function _validateRelayParams(bytes calldata request, bytes32 transactionId, address relayer) internal view {\n if (relayer == address(0)) revert ZeroAddress();\n // Check if the transaction has already been relayed\n if (bridgeRelays(transactionId)) revert TransactionRelayed();\n if (request.destChainId() != block.chainid) revert ChainIncorrect();\n // Check the deadline for relay to happen\n if (block.timestamp \u003e request.deadline()) revert DeadlineExceeded();\n // Check the exclusivity period, if it is still ongoing\n address exclRelayer = request.exclusivityRelayer();\n if (exclRelayer != address(0) \u0026\u0026 exclRelayer != relayer \u0026\u0026 block.timestamp \u003c= request.exclusivityEndTime()) {\n revert ExclusivityPeriodNotPassed();\n }\n }\n}\n","language":"Solidity","languageVersion":"0.8.24","compilerVersion":"0.8.24","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"","srcMapRuntime":"","abiDefinition":[{"inputs":[{"internalType":"bytes[]","name":"data","type":"bytes[]"},{"internalType":"bool","name":"ignoreReverts","type":"bool"}],"name":"multicallNoResults","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes[]","name":"data","type":"bytes[]"},{"internalType":"bool","name":"ignoreReverts","type":"bool"}],"name":"multicallWithResults","outputs":[{"components":[{"internalType":"bool","name":"success","type":"bool"},{"internalType":"bytes","name":"returnData","type":"bytes"}],"internalType":"struct IMulticallTarget.Result[]","name":"results","type":"tuple[]"}],"stateMutability":"nonpayable","type":"function"}],"userDoc":{"kind":"user","methods":{},"notice":"Interface for a contract that can be called multiple times by the same caller. Inspired by MulticallV3: https://github.com/mds1/multicall/blob/master/src/Multicall3.sol","version":1},"developerDoc":{"kind":"dev","methods":{},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"bytes[]\",\"name\":\"data\",\"type\":\"bytes[]\"},{\"internalType\":\"bool\",\"name\":\"ignoreReverts\",\"type\":\"bool\"}],\"name\":\"multicallNoResults\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes[]\",\"name\":\"data\",\"type\":\"bytes[]\"},{\"internalType\":\"bool\",\"name\":\"ignoreReverts\",\"type\":\"bool\"}],\"name\":\"multicallWithResults\",\"outputs\":[{\"components\":[{\"internalType\":\"bool\",\"name\":\"success\",\"type\":\"bool\"},{\"internalType\":\"bytes\",\"name\":\"returnData\",\"type\":\"bytes\"}],\"internalType\":\"struct IMulticallTarget.Result[]\",\"name\":\"results\",\"type\":\"tuple[]\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"notice\":\"Interface for a contract that can be called multiple times by the same caller. Inspired by MulticallV3: https://github.com/mds1/multicall/blob/master/src/Multicall3.sol\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeV2.sol\":\"IMulticallTarget\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeV2.sol\":{\"keccak256\":\"0x5069b55ca07f21bfe30b2a43c18a18318c8af9c181b2dcb07c290825efd70f34\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://273dc020a49d08e50126bbea0d7f783f79d08c702f2fdbc560618d24af308acc\",\"dweb:/ipfs/QmXJ2UVzFc8EPB74RT4CXQPC4xw66jt4T13poyfyd3UERh\"]}},\"version\":1}"},"hashes":{"multicallNoResults(bytes[],bool)":"3f61331d","multicallWithResults(bytes[],bool)":"385c1d2f"}},"solidity/FastBridgeV2.sol:IZapRecipient":{"code":"0x","runtime-code":"0x","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.24 ^0.8.20 ^0.8.4;\n\n// contracts/interfaces/IAdmin.sol\n\ninterface IAdmin {\n // ============ Events ============\n\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n event ChainGasAmountUpdated(uint256 oldChainGasAmount, uint256 newChainGasAmount);\n\n // ============ Methods ============\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n\n function setChainGasAmount(uint256 newChainGasAmount) external;\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IFastBridgeV2Errors.sol\n\ninterface IFastBridgeV2Errors {\n error AmountIncorrect();\n error ChainIncorrect();\n error ExclusivityParamsIncorrect();\n error MsgValueIncorrect();\n error SenderIncorrect();\n error StatusIncorrect();\n error TokenNotContract();\n error ZapDataLengthAboveMax();\n error ZapNativeNotSupported();\n error ZeroAddress();\n\n error RecipientIncorrectReturnValue();\n error RecipientNoReturnValue();\n\n error DeadlineExceeded();\n error DeadlineNotExceeded();\n error DeadlineTooShort();\n error DisputePeriodNotPassed();\n error DisputePeriodPassed();\n error ExclusivityPeriodNotPassed();\n\n error TransactionRelayed();\n}\n\n// contracts/interfaces/IMulticallTarget.sol\n\n/// @notice Interface for a contract that can be called multiple times by the same caller. Inspired by MulticallV3:\n/// https://github.com/mds1/multicall/blob/master/src/Multicall3.sol\ninterface IMulticallTarget {\n struct Result {\n bool success;\n bytes returnData;\n }\n\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external;\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results);\n}\n\n// contracts/interfaces/IZapRecipient.sol\n\ninterface IZapRecipient {\n function zap(address token, uint256 amount, bytes memory zapData) external payable returns (bytes4);\n}\n\n// contracts/libs/Errors.sol\n\nerror DeadlineExceeded();\nerror DeadlineNotExceeded();\nerror DeadlineTooShort();\nerror InsufficientOutputAmount();\n\nerror MsgValueIncorrect();\nerror PoolNotFound();\nerror TokenAddressMismatch();\nerror TokenNotContract();\nerror TokenNotETH();\nerror TokensIdentical();\n\nerror ChainIncorrect();\nerror AmountIncorrect();\nerror ZeroAddress();\n\nerror DisputePeriodNotPassed();\nerror DisputePeriodPassed();\nerror SenderIncorrect();\nerror StatusIncorrect();\nerror TransactionIdIncorrect();\nerror TransactionRelayed();\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// contracts/interfaces/IFastBridgeV2.sol\n\ninterface IFastBridgeV2 is IFastBridge {\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n struct BridgeTxDetails {\n BridgeStatus status;\n uint32 destChainId;\n uint56 proofBlockTimestamp;\n address proofRelayer;\n }\n\n struct BridgeRelay {\n uint48 blockNumber;\n uint48 blockTimestamp;\n address relayer;\n }\n\n /// @notice New params introduced in the FastBridgeV2.\n /// We are passing fields from the older BridgeParams struct outside of this struct\n /// for backwards compatibility.\n /// Note: quoteRelayer and quoteExclusivitySeconds are either both zero (indicating no exclusivity)\n /// or both non-zero (indicating exclusivity for the given period).\n /// Note: zapNative \u003e 0 can NOT be used with destToken = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE (native token)\n /// @param quoteRelayer Relayer that provided the quote for the transaction\n /// @param quoteExclusivitySeconds Period of time the quote relayer is guaranteed exclusivity after user's deposit\n /// @param quoteId Unique quote identifier used for tracking the quote\n /// @param zapNative ETH value to send to the recipient (if any)\n /// @param zapData Parameters for the Zap to the destination recipient (if any)\n struct BridgeParamsV2 {\n address quoteRelayer;\n int256 quoteExclusivitySeconds;\n bytes quoteId;\n uint256 zapNative;\n bytes zapData;\n }\n\n /// @notice Updated bridge transaction struct to include parameters introduced in FastBridgeV2.\n /// Note: only `exclusivityRelayer` can fill such a transaction until `exclusivityEndTime`.\n struct BridgeTransactionV2 {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n // Note: sendChainGas flag from V1 is deprecated\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n address exclusivityRelayer;\n uint256 exclusivityEndTime;\n uint256 zapNative; // ETH value to send to the recipient (if any)\n bytes zapData; // data to pass for the Zap action (if any)\n }\n\n event BridgeQuoteDetails(bytes32 indexed transactionId, bytes quoteId);\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability\n /// to provide temporary exclusivity fill rights for the quote relayer.\n /// @param params The parameters required to bridge\n /// @param paramsV2 The parameters for exclusivity fill rights (optional, can be left empty)\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function relay(bytes memory request, address relayer) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param transactionId The transaction id associated with the encoded bridge transaction to prove\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital.\n /// @notice Can only send funds to the relayer address on the proof.\n /// @param request The encoded bridge transaction to claim on origin chain\n function claim(bytes memory request) external;\n /// @notice Checks if a transaction has been relayed\n /// @param transactionId The ID of the transaction to check\n /// @return True if the transaction has been relayed, false otherwise\n function bridgeRelays(bytes32 transactionId) external view returns (bool);\n\n /// @notice Returns the status of a bridge transaction\n /// @param transactionId The ID of the bridge transaction\n /// @return BridgeStatus Status of the bridge transaction\n function bridgeStatuses(bytes32 transactionId) external view returns (BridgeStatus);\n\n /// @notice Returns the timestamp and relayer of a bridge proof\n /// @param transactionId The ID of the bridge transaction\n /// @return timestamp The timestamp of the bridge proof\n /// @return relayer The relayer address of the bridge proof\n function bridgeProofs(bytes32 transactionId) external view returns (uint96 timestamp, address relayer);\n\n /// @notice Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\n /// @param request The bridge request to decode\n function getBridgeTransactionV2(bytes memory request) external view returns (BridgeTransactionV2 memory);\n}\n\n// contracts/utils/MulticallTarget.sol\n\n// solhint-disable avoid-low-level-calls\n/// @notice Template for a contract that supports batched calls (preserving the msg.sender).\n/// Only calls with zero msg.value could be batched.\nabstract contract MulticallTarget is IMulticallTarget {\n error MulticallTarget__UndeterminedRevert();\n\n /// @notice Perform a batched call to this contract, preserving the msg.sender.\n /// The return data from each call is discarded.\n /// @dev The method is non-payable, so only calls with `msg.value == 0` could be batched.\n /// It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag.\n /// Otherwise, the whole batch call will be reverted with the original revert reason.\n /// @param data List of abi-encoded calldata for the calls to perform.\n /// @param ignoreReverts Whether to ignore the revert errors from the calls.\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external {\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\n if (!success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(result);\n }\n }\n }\n\n /// @notice Perform a batched call to this contract, preserving the msg.sender.\n /// The return data from each call is preserved.\n /// @dev The method is non-payable, so only calls with `msg.value == 0` could be batched.\n /// It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag.\n /// Otherwise, the whole batch call will be reverted with the original revert reason.\n /// @param data List of abi-encoded calldata for the calls to perform.\n /// @param ignoreReverts Whether to ignore the revert errors from the calls.\n /// @return results List of results from the calls: `(success, returnData)`.\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results)\n {\n results = new Result[](data.length);\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (results[i].success, results[i].returnData) = address(this).delegatecall(data[i]);\n if (!results[i].success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(results[i].returnData);\n }\n }\n }\n\n /// @dev Bubbles the revert message from the underlying call.\n /// Note: preserves the same custom error or revert string, if one was used.\n /// Source: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v5.0.2/contracts/utils/Address.sol#L143-L158\n function _bubbleRevert(bytes memory returnData) internal pure {\n // Look for revert reason and bubble it up if present\n if (returnData.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n // solhint-disable-next-line no-inline-assembly\n assembly {\n let returndata_size := mload(returnData)\n revert(add(32, returnData), returndata_size)\n }\n } else {\n revert MulticallTarget__UndeterminedRevert();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// contracts/libs/BridgeTransactionV2.sol\n\n// solhint-disable no-inline-assembly\nlibrary BridgeTransactionV2Lib {\n uint16 internal constant VERSION = 2;\n\n // Offsets of the fields in the packed BridgeTransactionV2 struct\n // uint16 version [000 .. 002)\n // uint32 originChainId [002 .. 006)\n // uint32 destChainId [006 .. 010)\n // address originSender [010 .. 030)\n // address destRecipient [030 .. 050)\n // address originToken [050 .. 070)\n // address destToken [070 .. 090)\n // uint256 originAmount [090 .. 122)\n // uint256 destAmount [122 .. 154)\n // uint256 originFeeAmount [154 .. 186)\n // uint256 deadline [186 .. 218)\n // uint256 nonce [218 .. 250)\n // address exclusivityRelayer [250 .. 270)\n // uint256 exclusivityEndTime [270 .. 302)\n // uint256 zapNative [302 .. 334)\n // bytes zapData [334 .. ***)\n\n // forgefmt: disable-start\n uint256 private constant OFFSET_ORIGIN_CHAIN_ID = 2;\n uint256 private constant OFFSET_DEST_CHAIN_ID = 6;\n uint256 private constant OFFSET_ORIGIN_SENDER = 10;\n uint256 private constant OFFSET_DEST_RECIPIENT = 30;\n uint256 private constant OFFSET_ORIGIN_TOKEN = 50;\n uint256 private constant OFFSET_DEST_TOKEN = 70;\n uint256 private constant OFFSET_ORIGIN_AMOUNT = 90;\n uint256 private constant OFFSET_DEST_AMOUNT = 122;\n uint256 private constant OFFSET_ORIGIN_FEE_AMOUNT = 154;\n uint256 private constant OFFSET_DEADLINE = 186;\n uint256 private constant OFFSET_NONCE = 218;\n uint256 private constant OFFSET_EXCLUSIVITY_RELAYER = 250;\n uint256 private constant OFFSET_EXCLUSIVITY_END_TIME = 270;\n uint256 private constant OFFSET_ZAP_NATIVE = 302;\n uint256 private constant OFFSET_ZAP_DATA = 334;\n // forgefmt: disable-end\n\n error BridgeTransactionV2__InvalidEncodedTx();\n error BridgeTransactionV2__UnsupportedVersion(uint16 version);\n\n /// @notice Validates the encoded transaction to be a tightly packed encoded payload for BridgeTransactionV2.\n /// @dev Checks the minimum length and the version, use this function before decoding any of the fields.\n function validateV2(bytes calldata encodedTx) internal pure {\n // Check the minimum length: must at least include all static fields.\n if (encodedTx.length \u003c OFFSET_ZAP_DATA) revert BridgeTransactionV2__InvalidEncodedTx();\n // Once we validated the length, we can be sure that the version field is present.\n uint16 version_ = version(encodedTx);\n if (version_ != VERSION) revert BridgeTransactionV2__UnsupportedVersion(version_);\n }\n\n /// @notice Encodes the BridgeTransactionV2 struct by tightly packing the fields.\n /// @dev `abi.decode` will not work as a result of the tightly packed fields. Use `decodeV2` to decode instead.\n function encodeV2(IFastBridgeV2.BridgeTransactionV2 memory bridgeTx) internal pure returns (bytes memory) {\n // We split the encoding into two parts to avoid stack-too-deep error\n bytes memory firstPart = abi.encodePacked(\n VERSION,\n bridgeTx.originChainId,\n bridgeTx.destChainId,\n bridgeTx.originSender,\n bridgeTx.destRecipient,\n bridgeTx.originToken,\n bridgeTx.destToken,\n bridgeTx.originAmount\n );\n return abi.encodePacked(\n firstPart,\n bridgeTx.destAmount,\n bridgeTx.originFeeAmount,\n // Note: we skip the deprecated `sendChainGas` flag, which was present in BridgeTransaction V1\n bridgeTx.deadline,\n bridgeTx.nonce,\n // New V2 fields: exclusivity\n bridgeTx.exclusivityRelayer,\n bridgeTx.exclusivityEndTime,\n // New V2 fields: Zap\n bridgeTx.zapNative,\n bridgeTx.zapData\n );\n }\n\n /// @notice Decodes the BridgeTransactionV2 struct from the encoded transaction.\n /// @dev Encoded BridgeTransactionV2 struct must be tightly packed.\n /// Use `validateV2` before decoding to ensure the encoded transaction is valid.\n function decodeV2(bytes calldata encodedTx)\n internal\n pure\n returns (IFastBridgeV2.BridgeTransactionV2 memory bridgeTx)\n {\n bridgeTx.originChainId = originChainId(encodedTx);\n bridgeTx.destChainId = destChainId(encodedTx);\n bridgeTx.originSender = originSender(encodedTx);\n bridgeTx.destRecipient = destRecipient(encodedTx);\n bridgeTx.originToken = originToken(encodedTx);\n bridgeTx.destToken = destToken(encodedTx);\n bridgeTx.originAmount = originAmount(encodedTx);\n bridgeTx.destAmount = destAmount(encodedTx);\n bridgeTx.originFeeAmount = originFeeAmount(encodedTx);\n bridgeTx.deadline = deadline(encodedTx);\n bridgeTx.nonce = nonce(encodedTx);\n bridgeTx.exclusivityRelayer = exclusivityRelayer(encodedTx);\n bridgeTx.exclusivityEndTime = exclusivityEndTime(encodedTx);\n bridgeTx.zapNative = zapNative(encodedTx);\n bridgeTx.zapData = zapData(encodedTx);\n }\n\n /// @notice Extracts the version from the encoded transaction.\n function version(bytes calldata encodedTx) internal pure returns (uint16 version_) {\n // Load 32 bytes from the start and shift it 240 bits to the right to get the highest 16 bits.\n assembly {\n version_ := shr(240, calldataload(encodedTx.offset))\n }\n }\n\n /// @notice Extracts the origin chain ID from the encoded transaction.\n function originChainId(bytes calldata encodedTx) internal pure returns (uint32 originChainId_) {\n // Load 32 bytes from the offset and shift it 224 bits to the right to get the highest 32 bits.\n assembly {\n originChainId_ := shr(224, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_CHAIN_ID)))\n }\n }\n\n /// @notice Extracts the destination chain ID from the encoded transaction.\n function destChainId(bytes calldata encodedTx) internal pure returns (uint32 destChainId_) {\n // Load 32 bytes from the offset and shift it 224 bits to the right to get the highest 32 bits.\n assembly {\n destChainId_ := shr(224, calldataload(add(encodedTx.offset, OFFSET_DEST_CHAIN_ID)))\n }\n }\n\n /// @notice Extracts the origin sender from the encoded transaction.\n function originSender(bytes calldata encodedTx) internal pure returns (address originSender_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n originSender_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_SENDER)))\n }\n }\n\n /// @notice Extracts the destination recipient from the encoded transaction.\n function destRecipient(bytes calldata encodedTx) internal pure returns (address destRecipient_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n destRecipient_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_DEST_RECIPIENT)))\n }\n }\n\n /// @notice Extracts the origin token from the encoded transaction.\n function originToken(bytes calldata encodedTx) internal pure returns (address originToken_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n originToken_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_TOKEN)))\n }\n }\n\n /// @notice Extracts the destination token from the encoded transaction.\n function destToken(bytes calldata encodedTx) internal pure returns (address destToken_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n destToken_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_DEST_TOKEN)))\n }\n }\n\n /// @notice Extracts the origin amount from the encoded transaction.\n function originAmount(bytes calldata encodedTx) internal pure returns (uint256 originAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n originAmount_ := calldataload(add(encodedTx.offset, OFFSET_ORIGIN_AMOUNT))\n }\n }\n\n /// @notice Extracts the destination amount from the encoded transaction.\n function destAmount(bytes calldata encodedTx) internal pure returns (uint256 destAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n destAmount_ := calldataload(add(encodedTx.offset, OFFSET_DEST_AMOUNT))\n }\n }\n\n /// @notice Extracts the origin fee amount from the encoded transaction.\n function originFeeAmount(bytes calldata encodedTx) internal pure returns (uint256 originFeeAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n originFeeAmount_ := calldataload(add(encodedTx.offset, OFFSET_ORIGIN_FEE_AMOUNT))\n }\n }\n\n /// @notice Extracts the deadline from the encoded transaction.\n function deadline(bytes calldata encodedTx) internal pure returns (uint256 deadline_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n deadline_ := calldataload(add(encodedTx.offset, OFFSET_DEADLINE))\n }\n }\n\n /// @notice Extracts the nonce from the encoded transaction.\n function nonce(bytes calldata encodedTx) internal pure returns (uint256 nonce_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n nonce_ := calldataload(add(encodedTx.offset, OFFSET_NONCE))\n }\n }\n\n /// @notice Extracts the exclusivity relayer from the encoded transaction.\n function exclusivityRelayer(bytes calldata encodedTx) internal pure returns (address exclusivityRelayer_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n exclusivityRelayer_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_EXCLUSIVITY_RELAYER)))\n }\n }\n\n /// @notice Extracts the exclusivity end time from the encoded transaction.\n function exclusivityEndTime(bytes calldata encodedTx) internal pure returns (uint256 exclusivityEndTime_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n exclusivityEndTime_ := calldataload(add(encodedTx.offset, OFFSET_EXCLUSIVITY_END_TIME))\n }\n }\n\n /// @notice Extracts the Zap's native value from the encoded transaction.\n function zapNative(bytes calldata encodedTx) internal pure returns (uint256 zapNative_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n zapNative_ := calldataload(add(encodedTx.offset, OFFSET_ZAP_NATIVE))\n }\n }\n\n /// @notice Extracts the Zap's data from the encoded transaction.\n function zapData(bytes calldata encodedTx) internal pure returns (bytes calldata zapData_) {\n zapData_ = encodedTx[OFFSET_ZAP_DATA:];\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// contracts/libs/UniversalToken.sol\n\nlibrary UniversalTokenLib {\n using SafeERC20 for IERC20;\n\n address internal constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Transfers tokens to the given account. Reverts if transfer is not successful.\n /// @dev This might trigger fallback, if ETH is transferred to the contract.\n /// Make sure this can not lead to reentrancy attacks.\n function universalTransfer(address token, address to, uint256 value) internal {\n // Don't do anything, if need to send tokens to this address\n if (to == address(this)) return;\n // Don't do anything, if trying to send zero value\n if (value == 0) return;\n if (token == ETH_ADDRESS) {\n /// @dev Note: this can potentially lead to executing code in `to`.\n // solhint-disable-next-line avoid-low-level-calls\n (bool success,) = to.call{value: value}(\"\");\n require(success, \"ETH transfer failed\");\n } else {\n IERC20(token).safeTransfer(to, value);\n }\n }\n\n /// @notice Issues an infinite allowance to the spender, if the current allowance is insufficient\n /// to spend the given amount.\n function universalApproveInfinity(address token, address spender, uint256 amountToSpend) internal {\n // ETH Chad doesn't require your approval\n if (token == ETH_ADDRESS) return;\n // No-op if allowance is already sufficient\n uint256 allowance = IERC20(token).allowance(address(this), spender);\n if (allowance \u003e= amountToSpend) return;\n // Otherwise, reset approval to 0 and set to max allowance\n if (allowance \u003e 0) IERC20(token).safeDecreaseAllowance(spender, allowance);\n IERC20(token).safeIncreaseAllowance(spender, type(uint256).max);\n }\n\n /// @notice Returns the balance of the given token (or native ETH) for the given account.\n function universalBalanceOf(address token, address account) internal view returns (uint256) {\n if (token == ETH_ADDRESS) {\n return account.balance;\n } else {\n return IERC20(token).balanceOf(account);\n }\n }\n\n /// @dev Checks that token is a contract and not ETH_ADDRESS.\n function assertIsContract(address token) internal view {\n // Check that ETH_ADDRESS was not used (in case this is a predeploy on any of the chains)\n if (token == UniversalTokenLib.ETH_ADDRESS) revert TokenNotContract();\n // Check that token is not an EOA\n if (token.code.length == 0) revert TokenNotContract();\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/Admin.sol\n\ncontract Admin is IAdmin, AccessControlEnumerable {\n using UniversalTokenLib for address;\n\n bytes32 public constant RELAYER_ROLE = keccak256(\"RELAYER_ROLE\");\n bytes32 public constant REFUNDER_ROLE = keccak256(\"REFUNDER_ROLE\");\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n uint256 public constant FEE_BPS = 1e6;\n uint256 public constant FEE_RATE_MAX = 0.01e6; // max 1% on origin amount\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Chain gas amount to forward as rebate if requested\n uint256 public chainGasAmount;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n }\n\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n require(newFeeRate \u003c= FEE_RATE_MAX, \"newFeeRate \u003e max\");\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n token.universalTransfer(recipient, feeAmount);\n emit FeesSwept(token, recipient, feeAmount);\n }\n\n function setChainGasAmount(uint256 newChainGasAmount) external onlyRole(GOVERNOR_ROLE) {\n uint256 oldChainGasAmount = chainGasAmount;\n chainGasAmount = newChainGasAmount;\n emit ChainGasAmountUpdated(oldChainGasAmount, newChainGasAmount);\n }\n}\n\n// contracts/FastBridgeV2.sol\n\n/// @notice FastBridgeV2 is a contract for bridging tokens across chains.\ncontract FastBridgeV2 is Admin, MulticallTarget, IFastBridgeV2, IFastBridgeV2Errors {\n using BridgeTransactionV2Lib for bytes;\n using SafeERC20 for IERC20;\n\n /// @notice Address reserved for native gas token (ETH on Ethereum and most L2s, AVAX on Avalanche, etc)\n address public constant NATIVE_GAS_TOKEN = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Delay for a transaction after which it could be permisionlessly refunded\n uint256 public constant REFUND_DELAY = 7 days;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n /// @notice Maximum length of accepted zapData\n uint256 public constant MAX_ZAP_DATA_LENGTH = 2 ** 16 - 1;\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeTxDetails) public bridgeTxDetails;\n /// @notice Relay details on destination chain\n mapping(bytes32 =\u003e BridgeRelay) public bridgeRelayDetails;\n /// @notice Unique bridge nonces tracked per originSender\n mapping(address =\u003e uint256) public senderNonces;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Replaced by senderNonces\n uint256 public immutable nonce = 0;\n /// @notice the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n bridge({\n params: params,\n paramsV2: BridgeParamsV2({\n quoteRelayer: address(0),\n quoteExclusivitySeconds: 0,\n quoteId: bytes(\"\"),\n zapNative: 0,\n zapData: bytes(\"\")\n })\n });\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes calldata request) external payable {\n // relay override will validate the request\n relay({request: request, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes calldata request, bytes32 destTxHash) external {\n request.validateV2();\n prove({transactionId: keccak256(request), destTxHash: destTxHash, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridgeV2\n function claim(bytes calldata request) external {\n // claim override will validate the request\n claim({request: request, to: address(0)});\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Aggregate the read operations from the same storage slot\n address disputedRelayer = $.proofRelayer;\n BridgeStatus status = $.status;\n uint56 proofBlockTimestamp = $.proofBlockTimestamp;\n // Can only dispute a RELAYER_PROVED transaction within the dispute period\n if (status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(proofBlockTimestamp) \u003e DISPUTE_PERIOD) {\n revert DisputePeriodPassed();\n }\n // Update status to REQUESTED and delete the disputed proof details\n // Note: these are storage writes\n $.status = BridgeStatus.REQUESTED;\n $.proofRelayer = address(0);\n $.proofBlockTimestamp = 0;\n\n emit BridgeProofDisputed(transactionId, disputedRelayer);\n }\n\n /// @inheritdoc IFastBridge\n function refund(bytes calldata request) external {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Can only refund a REQUESTED transaction after its deadline expires\n if ($.status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n uint256 deadline = request.deadline();\n // Permissionless refund is only allowed after REFUND_DELAY on top of the deadline\n if (!hasRole(REFUNDER_ROLE, msg.sender)) deadline += REFUND_DELAY;\n if (block.timestamp \u003c= deadline) revert DeadlineNotExceeded();\n // Update status to REFUNDED and return the full amount (collateral + protocol fees) to the original sender.\n // The protocol fees are only updated when the transaction is claimed, so we don't need to update them here.\n // Note: this is a storage write\n $.status = BridgeStatus.REFUNDED;\n\n address to = request.originSender();\n address token = request.originToken();\n uint256 amount = request.originAmount() + request.originFeeAmount();\n // Emit the event before any external calls\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n // Complete the user refund as the last transaction action\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(to), amount);\n } else {\n IERC20(token).safeTransfer(to, amount);\n }\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // The correct relayer can only claim a RELAYER_PROVED transaction after the dispute period\n if ($.status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if ($.proofRelayer != relayer) revert SenderIncorrect();\n return _timeSince($.proofBlockTimestamp) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n /// @dev This method is added to achieve backwards compatibility with decoding requests into V1 structs:\n /// - `zapNative` is partially reported as a zero/non-zero flag\n /// - `zapData` is ignored\n /// In order to process all kinds of requests use getBridgeTransactionV2 instead.\n function getBridgeTransaction(bytes calldata request) external view returns (BridgeTransaction memory) {\n // Try decoding into V2 struct first. This will revert if V1 struct is passed\n try this.getBridgeTransactionV2(request) returns (BridgeTransactionV2 memory txV2) {\n // Note: we entirely ignore the zapData field, as it was not present in V1\n return BridgeTransaction({\n originChainId: txV2.originChainId,\n destChainId: txV2.destChainId,\n originSender: txV2.originSender,\n destRecipient: txV2.destRecipient,\n originToken: txV2.originToken,\n destToken: txV2.destToken,\n originAmount: txV2.originAmount,\n destAmount: txV2.destAmount,\n originFeeAmount: txV2.originFeeAmount,\n sendChainGas: txV2.zapNative != 0,\n deadline: txV2.deadline,\n nonce: txV2.nonce\n });\n } catch {\n // Fallback to V1 struct\n return abi.decode(request, (BridgeTransaction));\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function getBridgeTransactionV2(bytes calldata request) external pure returns (BridgeTransactionV2 memory) {\n request.validateV2();\n return BridgeTransactionV2Lib.decodeV2(request);\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) public payable {\n int256 exclusivityEndTime = 0;\n // if relayer exclusivity is not intended for this bridge, set exclusivityEndTime to static zero\n // otherwise, set exclusivity to expire at the current block ts offset by quoteExclusivitySeconds\n if (paramsV2.quoteRelayer != address(0)) {\n exclusivityEndTime = int256(block.timestamp) + paramsV2.quoteExclusivitySeconds;\n }\n _validateBridgeParams(params, paramsV2, exclusivityEndTime);\n\n // transfer tokens to bridge contract\n /// @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _takeBridgedUserAsset(params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) {\n originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n }\n\n // set status to requested\n bytes memory request = BridgeTransactionV2Lib.encodeV2(\n BridgeTransactionV2({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n deadline: params.deadline,\n nonce: senderNonces[params.sender]++, // increment nonce on every bridge\n exclusivityRelayer: paramsV2.quoteRelayer,\n // We checked exclusivityEndTime to be in range [0 .. params.deadline] above, so can safely cast\n exclusivityEndTime: uint256(exclusivityEndTime),\n zapNative: paramsV2.zapNative,\n zapData: paramsV2.zapData\n })\n );\n bytes32 transactionId = keccak256(request);\n // Note: the tx status will be updated throughout the tx lifecycle, while destChainId is set once here\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n bridgeTxDetails[transactionId].destChainId = params.dstChainId;\n\n emit BridgeRequested({\n transactionId: transactionId,\n sender: params.sender,\n request: request,\n destChainId: params.dstChainId,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n sendChainGas: paramsV2.zapNative != 0\n });\n emit BridgeQuoteDetails(transactionId, paramsV2.quoteId);\n }\n\n /// @inheritdoc IFastBridgeV2\n function relay(bytes calldata request, address relayer) public payable {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n _validateRelayParams(request, transactionId, relayer);\n // mark bridge transaction as relayed\n bridgeRelayDetails[transactionId] =\n BridgeRelay({blockNumber: uint48(block.number), blockTimestamp: uint48(block.timestamp), relayer: relayer});\n\n // transfer tokens to recipient on destination chain and trigger Zap if requested\n address to = request.destRecipient();\n address token = request.destToken();\n uint256 amount = request.destAmount();\n uint256 zapNative = request.zapNative();\n\n // Emit the event before any external calls\n emit BridgeRelayed({\n transactionId: transactionId,\n relayer: relayer,\n to: to,\n originChainId: request.originChainId(),\n originToken: request.originToken(),\n destToken: token,\n originAmount: request.originAmount(),\n destAmount: amount,\n chainGasAmount: zapNative\n });\n\n // All state changes have been done at this point, can proceed to the external calls.\n // This follows the checks-effects-interactions pattern to mitigate potential reentrancy attacks.\n if (token == NATIVE_GAS_TOKEN) {\n // For the native gas token, additional zapNative is not allowed\n if (zapNative != 0) revert ZapNativeNotSupported();\n // Check that the correct msg.value was sent\n if (msg.value != amount) revert MsgValueIncorrect();\n // Don't do a native transfer yet: we will handle it alongside the Zap below\n } else {\n // For ERC20s, we check that the correct msg.value was sent\n if (msg.value != zapNative) revert MsgValueIncorrect();\n // We need to transfer the tokens from the Relayer to the recipient first before performing an\n // optional post-transfer Zap.\n IERC20(token).safeTransferFrom(msg.sender, to, amount);\n }\n // At this point we have done:\n // - Transferred the requested amount of ERC20 tokens to the recipient.\n // At this point we have confirmed:\n // - For ERC20s: msg.value matches the requested zapNative amount.\n // - For the native gas token: msg.value matches the requested destAmount.\n // Remaining optional things to do:\n // - Forward the full msg.value to the recipient (if non-zero).\n // - Trigger a Zap (if zapData is present).\n bytes calldata zapData = request.zapData();\n if (zapData.length != 0) {\n // Zap Data is present: Zap has been requested by the recipient. Trigger it forwarding the full msg.value.\n\n // Note: if token has a fee on transfers, the recipient will have received less than `amount`.\n // This is a very niche edge case and should be handled by the recipient contract.\n _triggerZapWithChecks({recipient: to, token: token, amount: amount, zapData: zapData});\n } else if (msg.value != 0) {\n // Zap Data is missing, but msg.value was sent. This could happen in two different cases:\n // - Relay with the native gas token is happening.\n // - Relay with ERC20 is happening, with a `zapNative \u003e 0` request.\n // In both cases, we need to transfer the full msg.value to the recipient.\n Address.sendValue(payable(to), msg.value);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) public onlyRole(RELAYER_ROLE) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n\n // Can only prove a REQUESTED transaction\n if ($.status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n // Update status to RELAYER_PROVED and store the proof details\n // Note: these are storage writes\n $.status = BridgeStatus.RELAYER_PROVED;\n $.proofBlockTimestamp = uint56(block.timestamp);\n $.proofRelayer = relayer;\n\n emit BridgeProofProvided(transactionId, relayer, destTxHash);\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes calldata request, address to) public {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Aggregate the read operations from the same storage slot\n address proofRelayer = $.proofRelayer;\n BridgeStatus status = $.status;\n uint56 proofBlockTimestamp = $.proofBlockTimestamp;\n\n // Can only claim a RELAYER_PROVED transaction after the dispute period\n if (status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(proofBlockTimestamp) \u003c= DISPUTE_PERIOD) {\n revert DisputePeriodNotPassed();\n }\n\n if (to == address(0)) {\n // Anyone could claim the funds to the proven relayer on their behalf\n to = proofRelayer;\n } else if (proofRelayer != msg.sender) {\n // Only the proven relayer could specify an address to claim the funds to\n revert SenderIncorrect();\n }\n\n // Update status to RELAYER_CLAIMED and transfer the origin collateral to the specified claim address\n // Note: this is a storage write\n $.status = BridgeStatus.RELAYER_CLAIMED;\n\n address token = request.originToken();\n uint256 amount = request.originAmount();\n // Update protocol fees if origin fee amount exists\n uint256 originFeeAmount = request.originFeeAmount();\n if (originFeeAmount \u003e 0) protocolFees[token] += originFeeAmount;\n // Emit the event before any external calls\n emit BridgeDepositClaimed(transactionId, proofRelayer, to, token, amount);\n // Complete the relayer claim as the last transaction action\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(to), amount);\n } else {\n IERC20(token).safeTransfer(to, amount);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeStatuses(bytes32 transactionId) public view returns (BridgeStatus status) {\n return bridgeTxDetails[transactionId].status;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeProofs(bytes32 transactionId) public view returns (uint96 timestamp, address relayer) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n\n timestamp = $.proofBlockTimestamp;\n relayer = $.proofRelayer;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeRelays(bytes32 transactionId) public view returns (bool) {\n // has this transactionId been relayed?\n return bridgeRelayDetails[transactionId].relayer != address(0);\n }\n\n /// @notice Takes the bridged asset from the user into FastBridgeV2 custody. It will be later\n /// claimed by the relayer who completed the relay on destination chain, or refunded back to the user,\n /// should no one complete the relay.\n function _takeBridgedUserAsset(address token, uint256 amount) internal returns (uint256 amountTaken) {\n if (token == NATIVE_GAS_TOKEN) {\n // For the native gas token, we just need to check that the supplied msg.value is correct.\n // Supplied `msg.value` is already in FastBridgeV2 custody.\n if (amount != msg.value) revert MsgValueIncorrect();\n amountTaken = msg.value;\n } else {\n // For ERC20s, token is explicitly transferred from the user to FastBridgeV2.\n // We don't allow non-zero `msg.value` to avoid extra funds from being stuck in FastBridgeV2.\n if (msg.value != 0) revert MsgValueIncorrect();\n // Throw an explicit error if the provided token address is not a contract\n if (token.code.length == 0) revert TokenNotContract();\n amountTaken = IERC20(token).balanceOf(address(this));\n IERC20(token).safeTransferFrom(msg.sender, address(this), amount);\n // Use the balance difference as the amount taken in case of fee on transfer tokens.\n amountTaken = IERC20(token).balanceOf(address(this)) - amountTaken;\n }\n }\n\n /// @notice Calls the Recipient's hook function with the specified zapData and performs\n /// all the necessary checks for the returned value.\n function _triggerZapWithChecks(address recipient, address token, uint256 amount, bytes calldata zapData) internal {\n // This will bubble any revert messages from the hook function\n bytes memory returnData = Address.functionCallWithValue({\n target: recipient,\n data: abi.encodeCall(IZapRecipient.zap, (token, amount, zapData)),\n // Note: see `relay()` for reasoning behind passing msg.value\n value: msg.value\n });\n // Explicit revert if no return data at all\n if (returnData.length == 0) revert RecipientNoReturnValue();\n // Check that exactly a single return value was returned\n if (returnData.length != 32) revert RecipientIncorrectReturnValue();\n // Return value should be abi-encoded hook function selector\n if (bytes32(returnData) != bytes32(IZapRecipient.zap.selector)) {\n revert RecipientIncorrectReturnValue();\n }\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint56(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint56).max but\n /// proof.timestamp \u003c type(uint56).max via unchecked statement\n /// @param proofBlockTimestamp The bridge proof block timestamp\n /// @return delta Time delta since proof submitted\n function _timeSince(uint56 proofBlockTimestamp) internal view returns (uint256 delta) {\n unchecked {\n delta = uint56(block.timestamp) - proofBlockTimestamp;\n }\n }\n\n /// @notice Performs all the necessary checks for a bridge to happen.\n /// @dev There's no good way to refactor this function to reduce cyclomatic complexity due to\n /// the number of checks that need to be performed, so we skip the code-complexity rule here.\n // solhint-disable-next-line code-complexity\n function _validateBridgeParams(\n BridgeParams memory params,\n BridgeParamsV2 memory paramsV2,\n int256 exclusivityEndTime\n )\n internal\n view\n {\n // Check V1 (legacy) params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.sender == address(0) || params.to == address(0)) revert ZeroAddress();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n // Check V2 params\n if (paramsV2.zapData.length \u003e MAX_ZAP_DATA_LENGTH) revert ZapDataLengthAboveMax();\n if (paramsV2.zapNative != 0 \u0026\u0026 params.destToken == NATIVE_GAS_TOKEN) {\n revert ZapNativeNotSupported();\n }\n // exclusivityEndTime must be in range [0 .. params.deadline]\n if (exclusivityEndTime \u003c 0 || exclusivityEndTime \u003e int256(params.deadline)) {\n revert ExclusivityParamsIncorrect();\n }\n }\n\n /// @notice Performs all the necessary checks for a relay to happen.\n function _validateRelayParams(bytes calldata request, bytes32 transactionId, address relayer) internal view {\n if (relayer == address(0)) revert ZeroAddress();\n // Check if the transaction has already been relayed\n if (bridgeRelays(transactionId)) revert TransactionRelayed();\n if (request.destChainId() != block.chainid) revert ChainIncorrect();\n // Check the deadline for relay to happen\n if (block.timestamp \u003e request.deadline()) revert DeadlineExceeded();\n // Check the exclusivity period, if it is still ongoing\n address exclRelayer = request.exclusivityRelayer();\n if (exclRelayer != address(0) \u0026\u0026 exclRelayer != relayer \u0026\u0026 block.timestamp \u003c= request.exclusivityEndTime()) {\n revert ExclusivityPeriodNotPassed();\n }\n }\n}\n","language":"Solidity","languageVersion":"0.8.24","compilerVersion":"0.8.24","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"","srcMapRuntime":"","abiDefinition":[{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"bytes","name":"zapData","type":"bytes"}],"name":"zap","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"payable","type":"function"}],"userDoc":{"kind":"user","methods":{},"version":1},"developerDoc":{"kind":"dev","methods":{},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"zapData\",\"type\":\"bytes\"}],\"name\":\"zap\",\"outputs\":[{\"internalType\":\"bytes4\",\"name\":\"\",\"type\":\"bytes4\"}],\"stateMutability\":\"payable\",\"type\":\"function\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeV2.sol\":\"IZapRecipient\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeV2.sol\":{\"keccak256\":\"0x5069b55ca07f21bfe30b2a43c18a18318c8af9c181b2dcb07c290825efd70f34\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://273dc020a49d08e50126bbea0d7f783f79d08c702f2fdbc560618d24af308acc\",\"dweb:/ipfs/QmXJ2UVzFc8EPB74RT4CXQPC4xw66jt4T13poyfyd3UERh\"]}},\"version\":1}"},"hashes":{"zap(address,uint256,bytes)":"e85e13dd"}},"solidity/FastBridgeV2.sol:MulticallTarget":{"code":"0x","runtime-code":"0x","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.24 ^0.8.20 ^0.8.4;\n\n// contracts/interfaces/IAdmin.sol\n\ninterface IAdmin {\n // ============ Events ============\n\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n event ChainGasAmountUpdated(uint256 oldChainGasAmount, uint256 newChainGasAmount);\n\n // ============ Methods ============\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n\n function setChainGasAmount(uint256 newChainGasAmount) external;\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IFastBridgeV2Errors.sol\n\ninterface IFastBridgeV2Errors {\n error AmountIncorrect();\n error ChainIncorrect();\n error ExclusivityParamsIncorrect();\n error MsgValueIncorrect();\n error SenderIncorrect();\n error StatusIncorrect();\n error TokenNotContract();\n error ZapDataLengthAboveMax();\n error ZapNativeNotSupported();\n error ZeroAddress();\n\n error RecipientIncorrectReturnValue();\n error RecipientNoReturnValue();\n\n error DeadlineExceeded();\n error DeadlineNotExceeded();\n error DeadlineTooShort();\n error DisputePeriodNotPassed();\n error DisputePeriodPassed();\n error ExclusivityPeriodNotPassed();\n\n error TransactionRelayed();\n}\n\n// contracts/interfaces/IMulticallTarget.sol\n\n/// @notice Interface for a contract that can be called multiple times by the same caller. Inspired by MulticallV3:\n/// https://github.com/mds1/multicall/blob/master/src/Multicall3.sol\ninterface IMulticallTarget {\n struct Result {\n bool success;\n bytes returnData;\n }\n\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external;\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results);\n}\n\n// contracts/interfaces/IZapRecipient.sol\n\ninterface IZapRecipient {\n function zap(address token, uint256 amount, bytes memory zapData) external payable returns (bytes4);\n}\n\n// contracts/libs/Errors.sol\n\nerror DeadlineExceeded();\nerror DeadlineNotExceeded();\nerror DeadlineTooShort();\nerror InsufficientOutputAmount();\n\nerror MsgValueIncorrect();\nerror PoolNotFound();\nerror TokenAddressMismatch();\nerror TokenNotContract();\nerror TokenNotETH();\nerror TokensIdentical();\n\nerror ChainIncorrect();\nerror AmountIncorrect();\nerror ZeroAddress();\n\nerror DisputePeriodNotPassed();\nerror DisputePeriodPassed();\nerror SenderIncorrect();\nerror StatusIncorrect();\nerror TransactionIdIncorrect();\nerror TransactionRelayed();\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// contracts/interfaces/IFastBridgeV2.sol\n\ninterface IFastBridgeV2 is IFastBridge {\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n struct BridgeTxDetails {\n BridgeStatus status;\n uint32 destChainId;\n uint56 proofBlockTimestamp;\n address proofRelayer;\n }\n\n struct BridgeRelay {\n uint48 blockNumber;\n uint48 blockTimestamp;\n address relayer;\n }\n\n /// @notice New params introduced in the FastBridgeV2.\n /// We are passing fields from the older BridgeParams struct outside of this struct\n /// for backwards compatibility.\n /// Note: quoteRelayer and quoteExclusivitySeconds are either both zero (indicating no exclusivity)\n /// or both non-zero (indicating exclusivity for the given period).\n /// Note: zapNative \u003e 0 can NOT be used with destToken = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE (native token)\n /// @param quoteRelayer Relayer that provided the quote for the transaction\n /// @param quoteExclusivitySeconds Period of time the quote relayer is guaranteed exclusivity after user's deposit\n /// @param quoteId Unique quote identifier used for tracking the quote\n /// @param zapNative ETH value to send to the recipient (if any)\n /// @param zapData Parameters for the Zap to the destination recipient (if any)\n struct BridgeParamsV2 {\n address quoteRelayer;\n int256 quoteExclusivitySeconds;\n bytes quoteId;\n uint256 zapNative;\n bytes zapData;\n }\n\n /// @notice Updated bridge transaction struct to include parameters introduced in FastBridgeV2.\n /// Note: only `exclusivityRelayer` can fill such a transaction until `exclusivityEndTime`.\n struct BridgeTransactionV2 {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n // Note: sendChainGas flag from V1 is deprecated\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n address exclusivityRelayer;\n uint256 exclusivityEndTime;\n uint256 zapNative; // ETH value to send to the recipient (if any)\n bytes zapData; // data to pass for the Zap action (if any)\n }\n\n event BridgeQuoteDetails(bytes32 indexed transactionId, bytes quoteId);\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability\n /// to provide temporary exclusivity fill rights for the quote relayer.\n /// @param params The parameters required to bridge\n /// @param paramsV2 The parameters for exclusivity fill rights (optional, can be left empty)\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function relay(bytes memory request, address relayer) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param transactionId The transaction id associated with the encoded bridge transaction to prove\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital.\n /// @notice Can only send funds to the relayer address on the proof.\n /// @param request The encoded bridge transaction to claim on origin chain\n function claim(bytes memory request) external;\n /// @notice Checks if a transaction has been relayed\n /// @param transactionId The ID of the transaction to check\n /// @return True if the transaction has been relayed, false otherwise\n function bridgeRelays(bytes32 transactionId) external view returns (bool);\n\n /// @notice Returns the status of a bridge transaction\n /// @param transactionId The ID of the bridge transaction\n /// @return BridgeStatus Status of the bridge transaction\n function bridgeStatuses(bytes32 transactionId) external view returns (BridgeStatus);\n\n /// @notice Returns the timestamp and relayer of a bridge proof\n /// @param transactionId The ID of the bridge transaction\n /// @return timestamp The timestamp of the bridge proof\n /// @return relayer The relayer address of the bridge proof\n function bridgeProofs(bytes32 transactionId) external view returns (uint96 timestamp, address relayer);\n\n /// @notice Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\n /// @param request The bridge request to decode\n function getBridgeTransactionV2(bytes memory request) external view returns (BridgeTransactionV2 memory);\n}\n\n// contracts/utils/MulticallTarget.sol\n\n// solhint-disable avoid-low-level-calls\n/// @notice Template for a contract that supports batched calls (preserving the msg.sender).\n/// Only calls with zero msg.value could be batched.\nabstract contract MulticallTarget is IMulticallTarget {\n error MulticallTarget__UndeterminedRevert();\n\n /// @notice Perform a batched call to this contract, preserving the msg.sender.\n /// The return data from each call is discarded.\n /// @dev The method is non-payable, so only calls with `msg.value == 0` could be batched.\n /// It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag.\n /// Otherwise, the whole batch call will be reverted with the original revert reason.\n /// @param data List of abi-encoded calldata for the calls to perform.\n /// @param ignoreReverts Whether to ignore the revert errors from the calls.\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external {\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\n if (!success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(result);\n }\n }\n }\n\n /// @notice Perform a batched call to this contract, preserving the msg.sender.\n /// The return data from each call is preserved.\n /// @dev The method is non-payable, so only calls with `msg.value == 0` could be batched.\n /// It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag.\n /// Otherwise, the whole batch call will be reverted with the original revert reason.\n /// @param data List of abi-encoded calldata for the calls to perform.\n /// @param ignoreReverts Whether to ignore the revert errors from the calls.\n /// @return results List of results from the calls: `(success, returnData)`.\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results)\n {\n results = new Result[](data.length);\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (results[i].success, results[i].returnData) = address(this).delegatecall(data[i]);\n if (!results[i].success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(results[i].returnData);\n }\n }\n }\n\n /// @dev Bubbles the revert message from the underlying call.\n /// Note: preserves the same custom error or revert string, if one was used.\n /// Source: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v5.0.2/contracts/utils/Address.sol#L143-L158\n function _bubbleRevert(bytes memory returnData) internal pure {\n // Look for revert reason and bubble it up if present\n if (returnData.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n // solhint-disable-next-line no-inline-assembly\n assembly {\n let returndata_size := mload(returnData)\n revert(add(32, returnData), returndata_size)\n }\n } else {\n revert MulticallTarget__UndeterminedRevert();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// contracts/libs/BridgeTransactionV2.sol\n\n// solhint-disable no-inline-assembly\nlibrary BridgeTransactionV2Lib {\n uint16 internal constant VERSION = 2;\n\n // Offsets of the fields in the packed BridgeTransactionV2 struct\n // uint16 version [000 .. 002)\n // uint32 originChainId [002 .. 006)\n // uint32 destChainId [006 .. 010)\n // address originSender [010 .. 030)\n // address destRecipient [030 .. 050)\n // address originToken [050 .. 070)\n // address destToken [070 .. 090)\n // uint256 originAmount [090 .. 122)\n // uint256 destAmount [122 .. 154)\n // uint256 originFeeAmount [154 .. 186)\n // uint256 deadline [186 .. 218)\n // uint256 nonce [218 .. 250)\n // address exclusivityRelayer [250 .. 270)\n // uint256 exclusivityEndTime [270 .. 302)\n // uint256 zapNative [302 .. 334)\n // bytes zapData [334 .. ***)\n\n // forgefmt: disable-start\n uint256 private constant OFFSET_ORIGIN_CHAIN_ID = 2;\n uint256 private constant OFFSET_DEST_CHAIN_ID = 6;\n uint256 private constant OFFSET_ORIGIN_SENDER = 10;\n uint256 private constant OFFSET_DEST_RECIPIENT = 30;\n uint256 private constant OFFSET_ORIGIN_TOKEN = 50;\n uint256 private constant OFFSET_DEST_TOKEN = 70;\n uint256 private constant OFFSET_ORIGIN_AMOUNT = 90;\n uint256 private constant OFFSET_DEST_AMOUNT = 122;\n uint256 private constant OFFSET_ORIGIN_FEE_AMOUNT = 154;\n uint256 private constant OFFSET_DEADLINE = 186;\n uint256 private constant OFFSET_NONCE = 218;\n uint256 private constant OFFSET_EXCLUSIVITY_RELAYER = 250;\n uint256 private constant OFFSET_EXCLUSIVITY_END_TIME = 270;\n uint256 private constant OFFSET_ZAP_NATIVE = 302;\n uint256 private constant OFFSET_ZAP_DATA = 334;\n // forgefmt: disable-end\n\n error BridgeTransactionV2__InvalidEncodedTx();\n error BridgeTransactionV2__UnsupportedVersion(uint16 version);\n\n /// @notice Validates the encoded transaction to be a tightly packed encoded payload for BridgeTransactionV2.\n /// @dev Checks the minimum length and the version, use this function before decoding any of the fields.\n function validateV2(bytes calldata encodedTx) internal pure {\n // Check the minimum length: must at least include all static fields.\n if (encodedTx.length \u003c OFFSET_ZAP_DATA) revert BridgeTransactionV2__InvalidEncodedTx();\n // Once we validated the length, we can be sure that the version field is present.\n uint16 version_ = version(encodedTx);\n if (version_ != VERSION) revert BridgeTransactionV2__UnsupportedVersion(version_);\n }\n\n /// @notice Encodes the BridgeTransactionV2 struct by tightly packing the fields.\n /// @dev `abi.decode` will not work as a result of the tightly packed fields. Use `decodeV2` to decode instead.\n function encodeV2(IFastBridgeV2.BridgeTransactionV2 memory bridgeTx) internal pure returns (bytes memory) {\n // We split the encoding into two parts to avoid stack-too-deep error\n bytes memory firstPart = abi.encodePacked(\n VERSION,\n bridgeTx.originChainId,\n bridgeTx.destChainId,\n bridgeTx.originSender,\n bridgeTx.destRecipient,\n bridgeTx.originToken,\n bridgeTx.destToken,\n bridgeTx.originAmount\n );\n return abi.encodePacked(\n firstPart,\n bridgeTx.destAmount,\n bridgeTx.originFeeAmount,\n // Note: we skip the deprecated `sendChainGas` flag, which was present in BridgeTransaction V1\n bridgeTx.deadline,\n bridgeTx.nonce,\n // New V2 fields: exclusivity\n bridgeTx.exclusivityRelayer,\n bridgeTx.exclusivityEndTime,\n // New V2 fields: Zap\n bridgeTx.zapNative,\n bridgeTx.zapData\n );\n }\n\n /// @notice Decodes the BridgeTransactionV2 struct from the encoded transaction.\n /// @dev Encoded BridgeTransactionV2 struct must be tightly packed.\n /// Use `validateV2` before decoding to ensure the encoded transaction is valid.\n function decodeV2(bytes calldata encodedTx)\n internal\n pure\n returns (IFastBridgeV2.BridgeTransactionV2 memory bridgeTx)\n {\n bridgeTx.originChainId = originChainId(encodedTx);\n bridgeTx.destChainId = destChainId(encodedTx);\n bridgeTx.originSender = originSender(encodedTx);\n bridgeTx.destRecipient = destRecipient(encodedTx);\n bridgeTx.originToken = originToken(encodedTx);\n bridgeTx.destToken = destToken(encodedTx);\n bridgeTx.originAmount = originAmount(encodedTx);\n bridgeTx.destAmount = destAmount(encodedTx);\n bridgeTx.originFeeAmount = originFeeAmount(encodedTx);\n bridgeTx.deadline = deadline(encodedTx);\n bridgeTx.nonce = nonce(encodedTx);\n bridgeTx.exclusivityRelayer = exclusivityRelayer(encodedTx);\n bridgeTx.exclusivityEndTime = exclusivityEndTime(encodedTx);\n bridgeTx.zapNative = zapNative(encodedTx);\n bridgeTx.zapData = zapData(encodedTx);\n }\n\n /// @notice Extracts the version from the encoded transaction.\n function version(bytes calldata encodedTx) internal pure returns (uint16 version_) {\n // Load 32 bytes from the start and shift it 240 bits to the right to get the highest 16 bits.\n assembly {\n version_ := shr(240, calldataload(encodedTx.offset))\n }\n }\n\n /// @notice Extracts the origin chain ID from the encoded transaction.\n function originChainId(bytes calldata encodedTx) internal pure returns (uint32 originChainId_) {\n // Load 32 bytes from the offset and shift it 224 bits to the right to get the highest 32 bits.\n assembly {\n originChainId_ := shr(224, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_CHAIN_ID)))\n }\n }\n\n /// @notice Extracts the destination chain ID from the encoded transaction.\n function destChainId(bytes calldata encodedTx) internal pure returns (uint32 destChainId_) {\n // Load 32 bytes from the offset and shift it 224 bits to the right to get the highest 32 bits.\n assembly {\n destChainId_ := shr(224, calldataload(add(encodedTx.offset, OFFSET_DEST_CHAIN_ID)))\n }\n }\n\n /// @notice Extracts the origin sender from the encoded transaction.\n function originSender(bytes calldata encodedTx) internal pure returns (address originSender_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n originSender_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_SENDER)))\n }\n }\n\n /// @notice Extracts the destination recipient from the encoded transaction.\n function destRecipient(bytes calldata encodedTx) internal pure returns (address destRecipient_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n destRecipient_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_DEST_RECIPIENT)))\n }\n }\n\n /// @notice Extracts the origin token from the encoded transaction.\n function originToken(bytes calldata encodedTx) internal pure returns (address originToken_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n originToken_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_TOKEN)))\n }\n }\n\n /// @notice Extracts the destination token from the encoded transaction.\n function destToken(bytes calldata encodedTx) internal pure returns (address destToken_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n destToken_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_DEST_TOKEN)))\n }\n }\n\n /// @notice Extracts the origin amount from the encoded transaction.\n function originAmount(bytes calldata encodedTx) internal pure returns (uint256 originAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n originAmount_ := calldataload(add(encodedTx.offset, OFFSET_ORIGIN_AMOUNT))\n }\n }\n\n /// @notice Extracts the destination amount from the encoded transaction.\n function destAmount(bytes calldata encodedTx) internal pure returns (uint256 destAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n destAmount_ := calldataload(add(encodedTx.offset, OFFSET_DEST_AMOUNT))\n }\n }\n\n /// @notice Extracts the origin fee amount from the encoded transaction.\n function originFeeAmount(bytes calldata encodedTx) internal pure returns (uint256 originFeeAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n originFeeAmount_ := calldataload(add(encodedTx.offset, OFFSET_ORIGIN_FEE_AMOUNT))\n }\n }\n\n /// @notice Extracts the deadline from the encoded transaction.\n function deadline(bytes calldata encodedTx) internal pure returns (uint256 deadline_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n deadline_ := calldataload(add(encodedTx.offset, OFFSET_DEADLINE))\n }\n }\n\n /// @notice Extracts the nonce from the encoded transaction.\n function nonce(bytes calldata encodedTx) internal pure returns (uint256 nonce_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n nonce_ := calldataload(add(encodedTx.offset, OFFSET_NONCE))\n }\n }\n\n /// @notice Extracts the exclusivity relayer from the encoded transaction.\n function exclusivityRelayer(bytes calldata encodedTx) internal pure returns (address exclusivityRelayer_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n exclusivityRelayer_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_EXCLUSIVITY_RELAYER)))\n }\n }\n\n /// @notice Extracts the exclusivity end time from the encoded transaction.\n function exclusivityEndTime(bytes calldata encodedTx) internal pure returns (uint256 exclusivityEndTime_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n exclusivityEndTime_ := calldataload(add(encodedTx.offset, OFFSET_EXCLUSIVITY_END_TIME))\n }\n }\n\n /// @notice Extracts the Zap's native value from the encoded transaction.\n function zapNative(bytes calldata encodedTx) internal pure returns (uint256 zapNative_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n zapNative_ := calldataload(add(encodedTx.offset, OFFSET_ZAP_NATIVE))\n }\n }\n\n /// @notice Extracts the Zap's data from the encoded transaction.\n function zapData(bytes calldata encodedTx) internal pure returns (bytes calldata zapData_) {\n zapData_ = encodedTx[OFFSET_ZAP_DATA:];\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// contracts/libs/UniversalToken.sol\n\nlibrary UniversalTokenLib {\n using SafeERC20 for IERC20;\n\n address internal constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Transfers tokens to the given account. Reverts if transfer is not successful.\n /// @dev This might trigger fallback, if ETH is transferred to the contract.\n /// Make sure this can not lead to reentrancy attacks.\n function universalTransfer(address token, address to, uint256 value) internal {\n // Don't do anything, if need to send tokens to this address\n if (to == address(this)) return;\n // Don't do anything, if trying to send zero value\n if (value == 0) return;\n if (token == ETH_ADDRESS) {\n /// @dev Note: this can potentially lead to executing code in `to`.\n // solhint-disable-next-line avoid-low-level-calls\n (bool success,) = to.call{value: value}(\"\");\n require(success, \"ETH transfer failed\");\n } else {\n IERC20(token).safeTransfer(to, value);\n }\n }\n\n /// @notice Issues an infinite allowance to the spender, if the current allowance is insufficient\n /// to spend the given amount.\n function universalApproveInfinity(address token, address spender, uint256 amountToSpend) internal {\n // ETH Chad doesn't require your approval\n if (token == ETH_ADDRESS) return;\n // No-op if allowance is already sufficient\n uint256 allowance = IERC20(token).allowance(address(this), spender);\n if (allowance \u003e= amountToSpend) return;\n // Otherwise, reset approval to 0 and set to max allowance\n if (allowance \u003e 0) IERC20(token).safeDecreaseAllowance(spender, allowance);\n IERC20(token).safeIncreaseAllowance(spender, type(uint256).max);\n }\n\n /// @notice Returns the balance of the given token (or native ETH) for the given account.\n function universalBalanceOf(address token, address account) internal view returns (uint256) {\n if (token == ETH_ADDRESS) {\n return account.balance;\n } else {\n return IERC20(token).balanceOf(account);\n }\n }\n\n /// @dev Checks that token is a contract and not ETH_ADDRESS.\n function assertIsContract(address token) internal view {\n // Check that ETH_ADDRESS was not used (in case this is a predeploy on any of the chains)\n if (token == UniversalTokenLib.ETH_ADDRESS) revert TokenNotContract();\n // Check that token is not an EOA\n if (token.code.length == 0) revert TokenNotContract();\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/Admin.sol\n\ncontract Admin is IAdmin, AccessControlEnumerable {\n using UniversalTokenLib for address;\n\n bytes32 public constant RELAYER_ROLE = keccak256(\"RELAYER_ROLE\");\n bytes32 public constant REFUNDER_ROLE = keccak256(\"REFUNDER_ROLE\");\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n uint256 public constant FEE_BPS = 1e6;\n uint256 public constant FEE_RATE_MAX = 0.01e6; // max 1% on origin amount\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Chain gas amount to forward as rebate if requested\n uint256 public chainGasAmount;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n }\n\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n require(newFeeRate \u003c= FEE_RATE_MAX, \"newFeeRate \u003e max\");\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n token.universalTransfer(recipient, feeAmount);\n emit FeesSwept(token, recipient, feeAmount);\n }\n\n function setChainGasAmount(uint256 newChainGasAmount) external onlyRole(GOVERNOR_ROLE) {\n uint256 oldChainGasAmount = chainGasAmount;\n chainGasAmount = newChainGasAmount;\n emit ChainGasAmountUpdated(oldChainGasAmount, newChainGasAmount);\n }\n}\n\n// contracts/FastBridgeV2.sol\n\n/// @notice FastBridgeV2 is a contract for bridging tokens across chains.\ncontract FastBridgeV2 is Admin, MulticallTarget, IFastBridgeV2, IFastBridgeV2Errors {\n using BridgeTransactionV2Lib for bytes;\n using SafeERC20 for IERC20;\n\n /// @notice Address reserved for native gas token (ETH on Ethereum and most L2s, AVAX on Avalanche, etc)\n address public constant NATIVE_GAS_TOKEN = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Delay for a transaction after which it could be permisionlessly refunded\n uint256 public constant REFUND_DELAY = 7 days;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n /// @notice Maximum length of accepted zapData\n uint256 public constant MAX_ZAP_DATA_LENGTH = 2 ** 16 - 1;\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeTxDetails) public bridgeTxDetails;\n /// @notice Relay details on destination chain\n mapping(bytes32 =\u003e BridgeRelay) public bridgeRelayDetails;\n /// @notice Unique bridge nonces tracked per originSender\n mapping(address =\u003e uint256) public senderNonces;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Replaced by senderNonces\n uint256 public immutable nonce = 0;\n /// @notice the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n bridge({\n params: params,\n paramsV2: BridgeParamsV2({\n quoteRelayer: address(0),\n quoteExclusivitySeconds: 0,\n quoteId: bytes(\"\"),\n zapNative: 0,\n zapData: bytes(\"\")\n })\n });\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes calldata request) external payable {\n // relay override will validate the request\n relay({request: request, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes calldata request, bytes32 destTxHash) external {\n request.validateV2();\n prove({transactionId: keccak256(request), destTxHash: destTxHash, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridgeV2\n function claim(bytes calldata request) external {\n // claim override will validate the request\n claim({request: request, to: address(0)});\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Aggregate the read operations from the same storage slot\n address disputedRelayer = $.proofRelayer;\n BridgeStatus status = $.status;\n uint56 proofBlockTimestamp = $.proofBlockTimestamp;\n // Can only dispute a RELAYER_PROVED transaction within the dispute period\n if (status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(proofBlockTimestamp) \u003e DISPUTE_PERIOD) {\n revert DisputePeriodPassed();\n }\n // Update status to REQUESTED and delete the disputed proof details\n // Note: these are storage writes\n $.status = BridgeStatus.REQUESTED;\n $.proofRelayer = address(0);\n $.proofBlockTimestamp = 0;\n\n emit BridgeProofDisputed(transactionId, disputedRelayer);\n }\n\n /// @inheritdoc IFastBridge\n function refund(bytes calldata request) external {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Can only refund a REQUESTED transaction after its deadline expires\n if ($.status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n uint256 deadline = request.deadline();\n // Permissionless refund is only allowed after REFUND_DELAY on top of the deadline\n if (!hasRole(REFUNDER_ROLE, msg.sender)) deadline += REFUND_DELAY;\n if (block.timestamp \u003c= deadline) revert DeadlineNotExceeded();\n // Update status to REFUNDED and return the full amount (collateral + protocol fees) to the original sender.\n // The protocol fees are only updated when the transaction is claimed, so we don't need to update them here.\n // Note: this is a storage write\n $.status = BridgeStatus.REFUNDED;\n\n address to = request.originSender();\n address token = request.originToken();\n uint256 amount = request.originAmount() + request.originFeeAmount();\n // Emit the event before any external calls\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n // Complete the user refund as the last transaction action\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(to), amount);\n } else {\n IERC20(token).safeTransfer(to, amount);\n }\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // The correct relayer can only claim a RELAYER_PROVED transaction after the dispute period\n if ($.status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if ($.proofRelayer != relayer) revert SenderIncorrect();\n return _timeSince($.proofBlockTimestamp) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n /// @dev This method is added to achieve backwards compatibility with decoding requests into V1 structs:\n /// - `zapNative` is partially reported as a zero/non-zero flag\n /// - `zapData` is ignored\n /// In order to process all kinds of requests use getBridgeTransactionV2 instead.\n function getBridgeTransaction(bytes calldata request) external view returns (BridgeTransaction memory) {\n // Try decoding into V2 struct first. This will revert if V1 struct is passed\n try this.getBridgeTransactionV2(request) returns (BridgeTransactionV2 memory txV2) {\n // Note: we entirely ignore the zapData field, as it was not present in V1\n return BridgeTransaction({\n originChainId: txV2.originChainId,\n destChainId: txV2.destChainId,\n originSender: txV2.originSender,\n destRecipient: txV2.destRecipient,\n originToken: txV2.originToken,\n destToken: txV2.destToken,\n originAmount: txV2.originAmount,\n destAmount: txV2.destAmount,\n originFeeAmount: txV2.originFeeAmount,\n sendChainGas: txV2.zapNative != 0,\n deadline: txV2.deadline,\n nonce: txV2.nonce\n });\n } catch {\n // Fallback to V1 struct\n return abi.decode(request, (BridgeTransaction));\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function getBridgeTransactionV2(bytes calldata request) external pure returns (BridgeTransactionV2 memory) {\n request.validateV2();\n return BridgeTransactionV2Lib.decodeV2(request);\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) public payable {\n int256 exclusivityEndTime = 0;\n // if relayer exclusivity is not intended for this bridge, set exclusivityEndTime to static zero\n // otherwise, set exclusivity to expire at the current block ts offset by quoteExclusivitySeconds\n if (paramsV2.quoteRelayer != address(0)) {\n exclusivityEndTime = int256(block.timestamp) + paramsV2.quoteExclusivitySeconds;\n }\n _validateBridgeParams(params, paramsV2, exclusivityEndTime);\n\n // transfer tokens to bridge contract\n /// @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _takeBridgedUserAsset(params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) {\n originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n }\n\n // set status to requested\n bytes memory request = BridgeTransactionV2Lib.encodeV2(\n BridgeTransactionV2({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n deadline: params.deadline,\n nonce: senderNonces[params.sender]++, // increment nonce on every bridge\n exclusivityRelayer: paramsV2.quoteRelayer,\n // We checked exclusivityEndTime to be in range [0 .. params.deadline] above, so can safely cast\n exclusivityEndTime: uint256(exclusivityEndTime),\n zapNative: paramsV2.zapNative,\n zapData: paramsV2.zapData\n })\n );\n bytes32 transactionId = keccak256(request);\n // Note: the tx status will be updated throughout the tx lifecycle, while destChainId is set once here\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n bridgeTxDetails[transactionId].destChainId = params.dstChainId;\n\n emit BridgeRequested({\n transactionId: transactionId,\n sender: params.sender,\n request: request,\n destChainId: params.dstChainId,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n sendChainGas: paramsV2.zapNative != 0\n });\n emit BridgeQuoteDetails(transactionId, paramsV2.quoteId);\n }\n\n /// @inheritdoc IFastBridgeV2\n function relay(bytes calldata request, address relayer) public payable {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n _validateRelayParams(request, transactionId, relayer);\n // mark bridge transaction as relayed\n bridgeRelayDetails[transactionId] =\n BridgeRelay({blockNumber: uint48(block.number), blockTimestamp: uint48(block.timestamp), relayer: relayer});\n\n // transfer tokens to recipient on destination chain and trigger Zap if requested\n address to = request.destRecipient();\n address token = request.destToken();\n uint256 amount = request.destAmount();\n uint256 zapNative = request.zapNative();\n\n // Emit the event before any external calls\n emit BridgeRelayed({\n transactionId: transactionId,\n relayer: relayer,\n to: to,\n originChainId: request.originChainId(),\n originToken: request.originToken(),\n destToken: token,\n originAmount: request.originAmount(),\n destAmount: amount,\n chainGasAmount: zapNative\n });\n\n // All state changes have been done at this point, can proceed to the external calls.\n // This follows the checks-effects-interactions pattern to mitigate potential reentrancy attacks.\n if (token == NATIVE_GAS_TOKEN) {\n // For the native gas token, additional zapNative is not allowed\n if (zapNative != 0) revert ZapNativeNotSupported();\n // Check that the correct msg.value was sent\n if (msg.value != amount) revert MsgValueIncorrect();\n // Don't do a native transfer yet: we will handle it alongside the Zap below\n } else {\n // For ERC20s, we check that the correct msg.value was sent\n if (msg.value != zapNative) revert MsgValueIncorrect();\n // We need to transfer the tokens from the Relayer to the recipient first before performing an\n // optional post-transfer Zap.\n IERC20(token).safeTransferFrom(msg.sender, to, amount);\n }\n // At this point we have done:\n // - Transferred the requested amount of ERC20 tokens to the recipient.\n // At this point we have confirmed:\n // - For ERC20s: msg.value matches the requested zapNative amount.\n // - For the native gas token: msg.value matches the requested destAmount.\n // Remaining optional things to do:\n // - Forward the full msg.value to the recipient (if non-zero).\n // - Trigger a Zap (if zapData is present).\n bytes calldata zapData = request.zapData();\n if (zapData.length != 0) {\n // Zap Data is present: Zap has been requested by the recipient. Trigger it forwarding the full msg.value.\n\n // Note: if token has a fee on transfers, the recipient will have received less than `amount`.\n // This is a very niche edge case and should be handled by the recipient contract.\n _triggerZapWithChecks({recipient: to, token: token, amount: amount, zapData: zapData});\n } else if (msg.value != 0) {\n // Zap Data is missing, but msg.value was sent. This could happen in two different cases:\n // - Relay with the native gas token is happening.\n // - Relay with ERC20 is happening, with a `zapNative \u003e 0` request.\n // In both cases, we need to transfer the full msg.value to the recipient.\n Address.sendValue(payable(to), msg.value);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) public onlyRole(RELAYER_ROLE) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n\n // Can only prove a REQUESTED transaction\n if ($.status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n // Update status to RELAYER_PROVED and store the proof details\n // Note: these are storage writes\n $.status = BridgeStatus.RELAYER_PROVED;\n $.proofBlockTimestamp = uint56(block.timestamp);\n $.proofRelayer = relayer;\n\n emit BridgeProofProvided(transactionId, relayer, destTxHash);\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes calldata request, address to) public {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Aggregate the read operations from the same storage slot\n address proofRelayer = $.proofRelayer;\n BridgeStatus status = $.status;\n uint56 proofBlockTimestamp = $.proofBlockTimestamp;\n\n // Can only claim a RELAYER_PROVED transaction after the dispute period\n if (status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(proofBlockTimestamp) \u003c= DISPUTE_PERIOD) {\n revert DisputePeriodNotPassed();\n }\n\n if (to == address(0)) {\n // Anyone could claim the funds to the proven relayer on their behalf\n to = proofRelayer;\n } else if (proofRelayer != msg.sender) {\n // Only the proven relayer could specify an address to claim the funds to\n revert SenderIncorrect();\n }\n\n // Update status to RELAYER_CLAIMED and transfer the origin collateral to the specified claim address\n // Note: this is a storage write\n $.status = BridgeStatus.RELAYER_CLAIMED;\n\n address token = request.originToken();\n uint256 amount = request.originAmount();\n // Update protocol fees if origin fee amount exists\n uint256 originFeeAmount = request.originFeeAmount();\n if (originFeeAmount \u003e 0) protocolFees[token] += originFeeAmount;\n // Emit the event before any external calls\n emit BridgeDepositClaimed(transactionId, proofRelayer, to, token, amount);\n // Complete the relayer claim as the last transaction action\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(to), amount);\n } else {\n IERC20(token).safeTransfer(to, amount);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeStatuses(bytes32 transactionId) public view returns (BridgeStatus status) {\n return bridgeTxDetails[transactionId].status;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeProofs(bytes32 transactionId) public view returns (uint96 timestamp, address relayer) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n\n timestamp = $.proofBlockTimestamp;\n relayer = $.proofRelayer;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeRelays(bytes32 transactionId) public view returns (bool) {\n // has this transactionId been relayed?\n return bridgeRelayDetails[transactionId].relayer != address(0);\n }\n\n /// @notice Takes the bridged asset from the user into FastBridgeV2 custody. It will be later\n /// claimed by the relayer who completed the relay on destination chain, or refunded back to the user,\n /// should no one complete the relay.\n function _takeBridgedUserAsset(address token, uint256 amount) internal returns (uint256 amountTaken) {\n if (token == NATIVE_GAS_TOKEN) {\n // For the native gas token, we just need to check that the supplied msg.value is correct.\n // Supplied `msg.value` is already in FastBridgeV2 custody.\n if (amount != msg.value) revert MsgValueIncorrect();\n amountTaken = msg.value;\n } else {\n // For ERC20s, token is explicitly transferred from the user to FastBridgeV2.\n // We don't allow non-zero `msg.value` to avoid extra funds from being stuck in FastBridgeV2.\n if (msg.value != 0) revert MsgValueIncorrect();\n // Throw an explicit error if the provided token address is not a contract\n if (token.code.length == 0) revert TokenNotContract();\n amountTaken = IERC20(token).balanceOf(address(this));\n IERC20(token).safeTransferFrom(msg.sender, address(this), amount);\n // Use the balance difference as the amount taken in case of fee on transfer tokens.\n amountTaken = IERC20(token).balanceOf(address(this)) - amountTaken;\n }\n }\n\n /// @notice Calls the Recipient's hook function with the specified zapData and performs\n /// all the necessary checks for the returned value.\n function _triggerZapWithChecks(address recipient, address token, uint256 amount, bytes calldata zapData) internal {\n // This will bubble any revert messages from the hook function\n bytes memory returnData = Address.functionCallWithValue({\n target: recipient,\n data: abi.encodeCall(IZapRecipient.zap, (token, amount, zapData)),\n // Note: see `relay()` for reasoning behind passing msg.value\n value: msg.value\n });\n // Explicit revert if no return data at all\n if (returnData.length == 0) revert RecipientNoReturnValue();\n // Check that exactly a single return value was returned\n if (returnData.length != 32) revert RecipientIncorrectReturnValue();\n // Return value should be abi-encoded hook function selector\n if (bytes32(returnData) != bytes32(IZapRecipient.zap.selector)) {\n revert RecipientIncorrectReturnValue();\n }\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint56(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint56).max but\n /// proof.timestamp \u003c type(uint56).max via unchecked statement\n /// @param proofBlockTimestamp The bridge proof block timestamp\n /// @return delta Time delta since proof submitted\n function _timeSince(uint56 proofBlockTimestamp) internal view returns (uint256 delta) {\n unchecked {\n delta = uint56(block.timestamp) - proofBlockTimestamp;\n }\n }\n\n /// @notice Performs all the necessary checks for a bridge to happen.\n /// @dev There's no good way to refactor this function to reduce cyclomatic complexity due to\n /// the number of checks that need to be performed, so we skip the code-complexity rule here.\n // solhint-disable-next-line code-complexity\n function _validateBridgeParams(\n BridgeParams memory params,\n BridgeParamsV2 memory paramsV2,\n int256 exclusivityEndTime\n )\n internal\n view\n {\n // Check V1 (legacy) params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.sender == address(0) || params.to == address(0)) revert ZeroAddress();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n // Check V2 params\n if (paramsV2.zapData.length \u003e MAX_ZAP_DATA_LENGTH) revert ZapDataLengthAboveMax();\n if (paramsV2.zapNative != 0 \u0026\u0026 params.destToken == NATIVE_GAS_TOKEN) {\n revert ZapNativeNotSupported();\n }\n // exclusivityEndTime must be in range [0 .. params.deadline]\n if (exclusivityEndTime \u003c 0 || exclusivityEndTime \u003e int256(params.deadline)) {\n revert ExclusivityParamsIncorrect();\n }\n }\n\n /// @notice Performs all the necessary checks for a relay to happen.\n function _validateRelayParams(bytes calldata request, bytes32 transactionId, address relayer) internal view {\n if (relayer == address(0)) revert ZeroAddress();\n // Check if the transaction has already been relayed\n if (bridgeRelays(transactionId)) revert TransactionRelayed();\n if (request.destChainId() != block.chainid) revert ChainIncorrect();\n // Check the deadline for relay to happen\n if (block.timestamp \u003e request.deadline()) revert DeadlineExceeded();\n // Check the exclusivity period, if it is still ongoing\n address exclRelayer = request.exclusivityRelayer();\n if (exclRelayer != address(0) \u0026\u0026 exclRelayer != relayer \u0026\u0026 block.timestamp \u003c= request.exclusivityEndTime()) {\n revert ExclusivityPeriodNotPassed();\n }\n }\n}\n","language":"Solidity","languageVersion":"0.8.24","compilerVersion":"0.8.24","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"","srcMapRuntime":"","abiDefinition":[{"inputs":[],"name":"MulticallTarget__UndeterminedRevert","type":"error"},{"inputs":[{"internalType":"bytes[]","name":"data","type":"bytes[]"},{"internalType":"bool","name":"ignoreReverts","type":"bool"}],"name":"multicallNoResults","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes[]","name":"data","type":"bytes[]"},{"internalType":"bool","name":"ignoreReverts","type":"bool"}],"name":"multicallWithResults","outputs":[{"components":[{"internalType":"bool","name":"success","type":"bool"},{"internalType":"bytes","name":"returnData","type":"bytes"}],"internalType":"struct IMulticallTarget.Result[]","name":"results","type":"tuple[]"}],"stateMutability":"nonpayable","type":"function"}],"userDoc":{"kind":"user","methods":{"multicallNoResults(bytes[],bool)":{"notice":"Perform a batched call to this contract, preserving the msg.sender. The return data from each call is discarded."},"multicallWithResults(bytes[],bool)":{"notice":"Perform a batched call to this contract, preserving the msg.sender. The return data from each call is preserved."}},"notice":"Template for a contract that supports batched calls (preserving the msg.sender). Only calls with zero msg.value could be batched.","version":1},"developerDoc":{"kind":"dev","methods":{"multicallNoResults(bytes[],bool)":{"details":"The method is non-payable, so only calls with `msg.value == 0` could be batched. It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag. Otherwise, the whole batch call will be reverted with the original revert reason.","params":{"data":"List of abi-encoded calldata for the calls to perform.","ignoreReverts":"Whether to ignore the revert errors from the calls."}},"multicallWithResults(bytes[],bool)":{"details":"The method is non-payable, so only calls with `msg.value == 0` could be batched. It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag. Otherwise, the whole batch call will be reverted with the original revert reason.","params":{"data":"List of abi-encoded calldata for the calls to perform.","ignoreReverts":"Whether to ignore the revert errors from the calls."},"returns":{"results":" List of results from the calls: `(success, returnData)`."}}},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[],\"name\":\"MulticallTarget__UndeterminedRevert\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"bytes[]\",\"name\":\"data\",\"type\":\"bytes[]\"},{\"internalType\":\"bool\",\"name\":\"ignoreReverts\",\"type\":\"bool\"}],\"name\":\"multicallNoResults\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes[]\",\"name\":\"data\",\"type\":\"bytes[]\"},{\"internalType\":\"bool\",\"name\":\"ignoreReverts\",\"type\":\"bool\"}],\"name\":\"multicallWithResults\",\"outputs\":[{\"components\":[{\"internalType\":\"bool\",\"name\":\"success\",\"type\":\"bool\"},{\"internalType\":\"bytes\",\"name\":\"returnData\",\"type\":\"bytes\"}],\"internalType\":\"struct IMulticallTarget.Result[]\",\"name\":\"results\",\"type\":\"tuple[]\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{\"multicallNoResults(bytes[],bool)\":{\"details\":\"The method is non-payable, so only calls with `msg.value == 0` could be batched. It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag. Otherwise, the whole batch call will be reverted with the original revert reason.\",\"params\":{\"data\":\"List of abi-encoded calldata for the calls to perform.\",\"ignoreReverts\":\"Whether to ignore the revert errors from the calls.\"}},\"multicallWithResults(bytes[],bool)\":{\"details\":\"The method is non-payable, so only calls with `msg.value == 0` could be batched. It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag. Otherwise, the whole batch call will be reverted with the original revert reason.\",\"params\":{\"data\":\"List of abi-encoded calldata for the calls to perform.\",\"ignoreReverts\":\"Whether to ignore the revert errors from the calls.\"},\"returns\":{\"results\":\" List of results from the calls: `(success, returnData)`.\"}}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"multicallNoResults(bytes[],bool)\":{\"notice\":\"Perform a batched call to this contract, preserving the msg.sender. The return data from each call is discarded.\"},\"multicallWithResults(bytes[],bool)\":{\"notice\":\"Perform a batched call to this contract, preserving the msg.sender. The return data from each call is preserved.\"}},\"notice\":\"Template for a contract that supports batched calls (preserving the msg.sender). Only calls with zero msg.value could be batched.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeV2.sol\":\"MulticallTarget\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeV2.sol\":{\"keccak256\":\"0x5069b55ca07f21bfe30b2a43c18a18318c8af9c181b2dcb07c290825efd70f34\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://273dc020a49d08e50126bbea0d7f783f79d08c702f2fdbc560618d24af308acc\",\"dweb:/ipfs/QmXJ2UVzFc8EPB74RT4CXQPC4xw66jt4T13poyfyd3UERh\"]}},\"version\":1}"},"hashes":{"multicallNoResults(bytes[],bool)":"3f61331d","multicallWithResults(bytes[],bool)":"385c1d2f"}},"solidity/FastBridgeV2.sol:SafeERC20":{"code":"0x60566037600b82828239805160001a607314602a57634e487b7160e01b600052600060045260246000fd5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600080fdfea26469706673582212209fa7c4bd491bc75459d04b74ec3df4cf5631b4ff0438eacdbdda406ccb78986b64736f6c63430008180033","runtime-code":"0x73000000000000000000000000000000000000000030146080604052600080fdfea26469706673582212209fa7c4bd491bc75459d04b74ec3df4cf5631b4ff0438eacdbdda406ccb78986b64736f6c63430008180033","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.24 ^0.8.20 ^0.8.4;\n\n// contracts/interfaces/IAdmin.sol\n\ninterface IAdmin {\n // ============ Events ============\n\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n event ChainGasAmountUpdated(uint256 oldChainGasAmount, uint256 newChainGasAmount);\n\n // ============ Methods ============\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n\n function setChainGasAmount(uint256 newChainGasAmount) external;\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IFastBridgeV2Errors.sol\n\ninterface IFastBridgeV2Errors {\n error AmountIncorrect();\n error ChainIncorrect();\n error ExclusivityParamsIncorrect();\n error MsgValueIncorrect();\n error SenderIncorrect();\n error StatusIncorrect();\n error TokenNotContract();\n error ZapDataLengthAboveMax();\n error ZapNativeNotSupported();\n error ZeroAddress();\n\n error RecipientIncorrectReturnValue();\n error RecipientNoReturnValue();\n\n error DeadlineExceeded();\n error DeadlineNotExceeded();\n error DeadlineTooShort();\n error DisputePeriodNotPassed();\n error DisputePeriodPassed();\n error ExclusivityPeriodNotPassed();\n\n error TransactionRelayed();\n}\n\n// contracts/interfaces/IMulticallTarget.sol\n\n/// @notice Interface for a contract that can be called multiple times by the same caller. Inspired by MulticallV3:\n/// https://github.com/mds1/multicall/blob/master/src/Multicall3.sol\ninterface IMulticallTarget {\n struct Result {\n bool success;\n bytes returnData;\n }\n\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external;\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results);\n}\n\n// contracts/interfaces/IZapRecipient.sol\n\ninterface IZapRecipient {\n function zap(address token, uint256 amount, bytes memory zapData) external payable returns (bytes4);\n}\n\n// contracts/libs/Errors.sol\n\nerror DeadlineExceeded();\nerror DeadlineNotExceeded();\nerror DeadlineTooShort();\nerror InsufficientOutputAmount();\n\nerror MsgValueIncorrect();\nerror PoolNotFound();\nerror TokenAddressMismatch();\nerror TokenNotContract();\nerror TokenNotETH();\nerror TokensIdentical();\n\nerror ChainIncorrect();\nerror AmountIncorrect();\nerror ZeroAddress();\n\nerror DisputePeriodNotPassed();\nerror DisputePeriodPassed();\nerror SenderIncorrect();\nerror StatusIncorrect();\nerror TransactionIdIncorrect();\nerror TransactionRelayed();\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// contracts/interfaces/IFastBridgeV2.sol\n\ninterface IFastBridgeV2 is IFastBridge {\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n struct BridgeTxDetails {\n BridgeStatus status;\n uint32 destChainId;\n uint56 proofBlockTimestamp;\n address proofRelayer;\n }\n\n struct BridgeRelay {\n uint48 blockNumber;\n uint48 blockTimestamp;\n address relayer;\n }\n\n /// @notice New params introduced in the FastBridgeV2.\n /// We are passing fields from the older BridgeParams struct outside of this struct\n /// for backwards compatibility.\n /// Note: quoteRelayer and quoteExclusivitySeconds are either both zero (indicating no exclusivity)\n /// or both non-zero (indicating exclusivity for the given period).\n /// Note: zapNative \u003e 0 can NOT be used with destToken = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE (native token)\n /// @param quoteRelayer Relayer that provided the quote for the transaction\n /// @param quoteExclusivitySeconds Period of time the quote relayer is guaranteed exclusivity after user's deposit\n /// @param quoteId Unique quote identifier used for tracking the quote\n /// @param zapNative ETH value to send to the recipient (if any)\n /// @param zapData Parameters for the Zap to the destination recipient (if any)\n struct BridgeParamsV2 {\n address quoteRelayer;\n int256 quoteExclusivitySeconds;\n bytes quoteId;\n uint256 zapNative;\n bytes zapData;\n }\n\n /// @notice Updated bridge transaction struct to include parameters introduced in FastBridgeV2.\n /// Note: only `exclusivityRelayer` can fill such a transaction until `exclusivityEndTime`.\n struct BridgeTransactionV2 {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n // Note: sendChainGas flag from V1 is deprecated\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n address exclusivityRelayer;\n uint256 exclusivityEndTime;\n uint256 zapNative; // ETH value to send to the recipient (if any)\n bytes zapData; // data to pass for the Zap action (if any)\n }\n\n event BridgeQuoteDetails(bytes32 indexed transactionId, bytes quoteId);\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability\n /// to provide temporary exclusivity fill rights for the quote relayer.\n /// @param params The parameters required to bridge\n /// @param paramsV2 The parameters for exclusivity fill rights (optional, can be left empty)\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function relay(bytes memory request, address relayer) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param transactionId The transaction id associated with the encoded bridge transaction to prove\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital.\n /// @notice Can only send funds to the relayer address on the proof.\n /// @param request The encoded bridge transaction to claim on origin chain\n function claim(bytes memory request) external;\n /// @notice Checks if a transaction has been relayed\n /// @param transactionId The ID of the transaction to check\n /// @return True if the transaction has been relayed, false otherwise\n function bridgeRelays(bytes32 transactionId) external view returns (bool);\n\n /// @notice Returns the status of a bridge transaction\n /// @param transactionId The ID of the bridge transaction\n /// @return BridgeStatus Status of the bridge transaction\n function bridgeStatuses(bytes32 transactionId) external view returns (BridgeStatus);\n\n /// @notice Returns the timestamp and relayer of a bridge proof\n /// @param transactionId The ID of the bridge transaction\n /// @return timestamp The timestamp of the bridge proof\n /// @return relayer The relayer address of the bridge proof\n function bridgeProofs(bytes32 transactionId) external view returns (uint96 timestamp, address relayer);\n\n /// @notice Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\n /// @param request The bridge request to decode\n function getBridgeTransactionV2(bytes memory request) external view returns (BridgeTransactionV2 memory);\n}\n\n// contracts/utils/MulticallTarget.sol\n\n// solhint-disable avoid-low-level-calls\n/// @notice Template for a contract that supports batched calls (preserving the msg.sender).\n/// Only calls with zero msg.value could be batched.\nabstract contract MulticallTarget is IMulticallTarget {\n error MulticallTarget__UndeterminedRevert();\n\n /// @notice Perform a batched call to this contract, preserving the msg.sender.\n /// The return data from each call is discarded.\n /// @dev The method is non-payable, so only calls with `msg.value == 0` could be batched.\n /// It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag.\n /// Otherwise, the whole batch call will be reverted with the original revert reason.\n /// @param data List of abi-encoded calldata for the calls to perform.\n /// @param ignoreReverts Whether to ignore the revert errors from the calls.\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external {\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\n if (!success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(result);\n }\n }\n }\n\n /// @notice Perform a batched call to this contract, preserving the msg.sender.\n /// The return data from each call is preserved.\n /// @dev The method is non-payable, so only calls with `msg.value == 0` could be batched.\n /// It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag.\n /// Otherwise, the whole batch call will be reverted with the original revert reason.\n /// @param data List of abi-encoded calldata for the calls to perform.\n /// @param ignoreReverts Whether to ignore the revert errors from the calls.\n /// @return results List of results from the calls: `(success, returnData)`.\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results)\n {\n results = new Result[](data.length);\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (results[i].success, results[i].returnData) = address(this).delegatecall(data[i]);\n if (!results[i].success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(results[i].returnData);\n }\n }\n }\n\n /// @dev Bubbles the revert message from the underlying call.\n /// Note: preserves the same custom error or revert string, if one was used.\n /// Source: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v5.0.2/contracts/utils/Address.sol#L143-L158\n function _bubbleRevert(bytes memory returnData) internal pure {\n // Look for revert reason and bubble it up if present\n if (returnData.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n // solhint-disable-next-line no-inline-assembly\n assembly {\n let returndata_size := mload(returnData)\n revert(add(32, returnData), returndata_size)\n }\n } else {\n revert MulticallTarget__UndeterminedRevert();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// contracts/libs/BridgeTransactionV2.sol\n\n// solhint-disable no-inline-assembly\nlibrary BridgeTransactionV2Lib {\n uint16 internal constant VERSION = 2;\n\n // Offsets of the fields in the packed BridgeTransactionV2 struct\n // uint16 version [000 .. 002)\n // uint32 originChainId [002 .. 006)\n // uint32 destChainId [006 .. 010)\n // address originSender [010 .. 030)\n // address destRecipient [030 .. 050)\n // address originToken [050 .. 070)\n // address destToken [070 .. 090)\n // uint256 originAmount [090 .. 122)\n // uint256 destAmount [122 .. 154)\n // uint256 originFeeAmount [154 .. 186)\n // uint256 deadline [186 .. 218)\n // uint256 nonce [218 .. 250)\n // address exclusivityRelayer [250 .. 270)\n // uint256 exclusivityEndTime [270 .. 302)\n // uint256 zapNative [302 .. 334)\n // bytes zapData [334 .. ***)\n\n // forgefmt: disable-start\n uint256 private constant OFFSET_ORIGIN_CHAIN_ID = 2;\n uint256 private constant OFFSET_DEST_CHAIN_ID = 6;\n uint256 private constant OFFSET_ORIGIN_SENDER = 10;\n uint256 private constant OFFSET_DEST_RECIPIENT = 30;\n uint256 private constant OFFSET_ORIGIN_TOKEN = 50;\n uint256 private constant OFFSET_DEST_TOKEN = 70;\n uint256 private constant OFFSET_ORIGIN_AMOUNT = 90;\n uint256 private constant OFFSET_DEST_AMOUNT = 122;\n uint256 private constant OFFSET_ORIGIN_FEE_AMOUNT = 154;\n uint256 private constant OFFSET_DEADLINE = 186;\n uint256 private constant OFFSET_NONCE = 218;\n uint256 private constant OFFSET_EXCLUSIVITY_RELAYER = 250;\n uint256 private constant OFFSET_EXCLUSIVITY_END_TIME = 270;\n uint256 private constant OFFSET_ZAP_NATIVE = 302;\n uint256 private constant OFFSET_ZAP_DATA = 334;\n // forgefmt: disable-end\n\n error BridgeTransactionV2__InvalidEncodedTx();\n error BridgeTransactionV2__UnsupportedVersion(uint16 version);\n\n /// @notice Validates the encoded transaction to be a tightly packed encoded payload for BridgeTransactionV2.\n /// @dev Checks the minimum length and the version, use this function before decoding any of the fields.\n function validateV2(bytes calldata encodedTx) internal pure {\n // Check the minimum length: must at least include all static fields.\n if (encodedTx.length \u003c OFFSET_ZAP_DATA) revert BridgeTransactionV2__InvalidEncodedTx();\n // Once we validated the length, we can be sure that the version field is present.\n uint16 version_ = version(encodedTx);\n if (version_ != VERSION) revert BridgeTransactionV2__UnsupportedVersion(version_);\n }\n\n /// @notice Encodes the BridgeTransactionV2 struct by tightly packing the fields.\n /// @dev `abi.decode` will not work as a result of the tightly packed fields. Use `decodeV2` to decode instead.\n function encodeV2(IFastBridgeV2.BridgeTransactionV2 memory bridgeTx) internal pure returns (bytes memory) {\n // We split the encoding into two parts to avoid stack-too-deep error\n bytes memory firstPart = abi.encodePacked(\n VERSION,\n bridgeTx.originChainId,\n bridgeTx.destChainId,\n bridgeTx.originSender,\n bridgeTx.destRecipient,\n bridgeTx.originToken,\n bridgeTx.destToken,\n bridgeTx.originAmount\n );\n return abi.encodePacked(\n firstPart,\n bridgeTx.destAmount,\n bridgeTx.originFeeAmount,\n // Note: we skip the deprecated `sendChainGas` flag, which was present in BridgeTransaction V1\n bridgeTx.deadline,\n bridgeTx.nonce,\n // New V2 fields: exclusivity\n bridgeTx.exclusivityRelayer,\n bridgeTx.exclusivityEndTime,\n // New V2 fields: Zap\n bridgeTx.zapNative,\n bridgeTx.zapData\n );\n }\n\n /// @notice Decodes the BridgeTransactionV2 struct from the encoded transaction.\n /// @dev Encoded BridgeTransactionV2 struct must be tightly packed.\n /// Use `validateV2` before decoding to ensure the encoded transaction is valid.\n function decodeV2(bytes calldata encodedTx)\n internal\n pure\n returns (IFastBridgeV2.BridgeTransactionV2 memory bridgeTx)\n {\n bridgeTx.originChainId = originChainId(encodedTx);\n bridgeTx.destChainId = destChainId(encodedTx);\n bridgeTx.originSender = originSender(encodedTx);\n bridgeTx.destRecipient = destRecipient(encodedTx);\n bridgeTx.originToken = originToken(encodedTx);\n bridgeTx.destToken = destToken(encodedTx);\n bridgeTx.originAmount = originAmount(encodedTx);\n bridgeTx.destAmount = destAmount(encodedTx);\n bridgeTx.originFeeAmount = originFeeAmount(encodedTx);\n bridgeTx.deadline = deadline(encodedTx);\n bridgeTx.nonce = nonce(encodedTx);\n bridgeTx.exclusivityRelayer = exclusivityRelayer(encodedTx);\n bridgeTx.exclusivityEndTime = exclusivityEndTime(encodedTx);\n bridgeTx.zapNative = zapNative(encodedTx);\n bridgeTx.zapData = zapData(encodedTx);\n }\n\n /// @notice Extracts the version from the encoded transaction.\n function version(bytes calldata encodedTx) internal pure returns (uint16 version_) {\n // Load 32 bytes from the start and shift it 240 bits to the right to get the highest 16 bits.\n assembly {\n version_ := shr(240, calldataload(encodedTx.offset))\n }\n }\n\n /// @notice Extracts the origin chain ID from the encoded transaction.\n function originChainId(bytes calldata encodedTx) internal pure returns (uint32 originChainId_) {\n // Load 32 bytes from the offset and shift it 224 bits to the right to get the highest 32 bits.\n assembly {\n originChainId_ := shr(224, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_CHAIN_ID)))\n }\n }\n\n /// @notice Extracts the destination chain ID from the encoded transaction.\n function destChainId(bytes calldata encodedTx) internal pure returns (uint32 destChainId_) {\n // Load 32 bytes from the offset and shift it 224 bits to the right to get the highest 32 bits.\n assembly {\n destChainId_ := shr(224, calldataload(add(encodedTx.offset, OFFSET_DEST_CHAIN_ID)))\n }\n }\n\n /// @notice Extracts the origin sender from the encoded transaction.\n function originSender(bytes calldata encodedTx) internal pure returns (address originSender_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n originSender_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_SENDER)))\n }\n }\n\n /// @notice Extracts the destination recipient from the encoded transaction.\n function destRecipient(bytes calldata encodedTx) internal pure returns (address destRecipient_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n destRecipient_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_DEST_RECIPIENT)))\n }\n }\n\n /// @notice Extracts the origin token from the encoded transaction.\n function originToken(bytes calldata encodedTx) internal pure returns (address originToken_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n originToken_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_TOKEN)))\n }\n }\n\n /// @notice Extracts the destination token from the encoded transaction.\n function destToken(bytes calldata encodedTx) internal pure returns (address destToken_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n destToken_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_DEST_TOKEN)))\n }\n }\n\n /// @notice Extracts the origin amount from the encoded transaction.\n function originAmount(bytes calldata encodedTx) internal pure returns (uint256 originAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n originAmount_ := calldataload(add(encodedTx.offset, OFFSET_ORIGIN_AMOUNT))\n }\n }\n\n /// @notice Extracts the destination amount from the encoded transaction.\n function destAmount(bytes calldata encodedTx) internal pure returns (uint256 destAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n destAmount_ := calldataload(add(encodedTx.offset, OFFSET_DEST_AMOUNT))\n }\n }\n\n /// @notice Extracts the origin fee amount from the encoded transaction.\n function originFeeAmount(bytes calldata encodedTx) internal pure returns (uint256 originFeeAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n originFeeAmount_ := calldataload(add(encodedTx.offset, OFFSET_ORIGIN_FEE_AMOUNT))\n }\n }\n\n /// @notice Extracts the deadline from the encoded transaction.\n function deadline(bytes calldata encodedTx) internal pure returns (uint256 deadline_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n deadline_ := calldataload(add(encodedTx.offset, OFFSET_DEADLINE))\n }\n }\n\n /// @notice Extracts the nonce from the encoded transaction.\n function nonce(bytes calldata encodedTx) internal pure returns (uint256 nonce_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n nonce_ := calldataload(add(encodedTx.offset, OFFSET_NONCE))\n }\n }\n\n /// @notice Extracts the exclusivity relayer from the encoded transaction.\n function exclusivityRelayer(bytes calldata encodedTx) internal pure returns (address exclusivityRelayer_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n exclusivityRelayer_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_EXCLUSIVITY_RELAYER)))\n }\n }\n\n /// @notice Extracts the exclusivity end time from the encoded transaction.\n function exclusivityEndTime(bytes calldata encodedTx) internal pure returns (uint256 exclusivityEndTime_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n exclusivityEndTime_ := calldataload(add(encodedTx.offset, OFFSET_EXCLUSIVITY_END_TIME))\n }\n }\n\n /// @notice Extracts the Zap's native value from the encoded transaction.\n function zapNative(bytes calldata encodedTx) internal pure returns (uint256 zapNative_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n zapNative_ := calldataload(add(encodedTx.offset, OFFSET_ZAP_NATIVE))\n }\n }\n\n /// @notice Extracts the Zap's data from the encoded transaction.\n function zapData(bytes calldata encodedTx) internal pure returns (bytes calldata zapData_) {\n zapData_ = encodedTx[OFFSET_ZAP_DATA:];\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// contracts/libs/UniversalToken.sol\n\nlibrary UniversalTokenLib {\n using SafeERC20 for IERC20;\n\n address internal constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Transfers tokens to the given account. Reverts if transfer is not successful.\n /// @dev This might trigger fallback, if ETH is transferred to the contract.\n /// Make sure this can not lead to reentrancy attacks.\n function universalTransfer(address token, address to, uint256 value) internal {\n // Don't do anything, if need to send tokens to this address\n if (to == address(this)) return;\n // Don't do anything, if trying to send zero value\n if (value == 0) return;\n if (token == ETH_ADDRESS) {\n /// @dev Note: this can potentially lead to executing code in `to`.\n // solhint-disable-next-line avoid-low-level-calls\n (bool success,) = to.call{value: value}(\"\");\n require(success, \"ETH transfer failed\");\n } else {\n IERC20(token).safeTransfer(to, value);\n }\n }\n\n /// @notice Issues an infinite allowance to the spender, if the current allowance is insufficient\n /// to spend the given amount.\n function universalApproveInfinity(address token, address spender, uint256 amountToSpend) internal {\n // ETH Chad doesn't require your approval\n if (token == ETH_ADDRESS) return;\n // No-op if allowance is already sufficient\n uint256 allowance = IERC20(token).allowance(address(this), spender);\n if (allowance \u003e= amountToSpend) return;\n // Otherwise, reset approval to 0 and set to max allowance\n if (allowance \u003e 0) IERC20(token).safeDecreaseAllowance(spender, allowance);\n IERC20(token).safeIncreaseAllowance(spender, type(uint256).max);\n }\n\n /// @notice Returns the balance of the given token (or native ETH) for the given account.\n function universalBalanceOf(address token, address account) internal view returns (uint256) {\n if (token == ETH_ADDRESS) {\n return account.balance;\n } else {\n return IERC20(token).balanceOf(account);\n }\n }\n\n /// @dev Checks that token is a contract and not ETH_ADDRESS.\n function assertIsContract(address token) internal view {\n // Check that ETH_ADDRESS was not used (in case this is a predeploy on any of the chains)\n if (token == UniversalTokenLib.ETH_ADDRESS) revert TokenNotContract();\n // Check that token is not an EOA\n if (token.code.length == 0) revert TokenNotContract();\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/Admin.sol\n\ncontract Admin is IAdmin, AccessControlEnumerable {\n using UniversalTokenLib for address;\n\n bytes32 public constant RELAYER_ROLE = keccak256(\"RELAYER_ROLE\");\n bytes32 public constant REFUNDER_ROLE = keccak256(\"REFUNDER_ROLE\");\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n uint256 public constant FEE_BPS = 1e6;\n uint256 public constant FEE_RATE_MAX = 0.01e6; // max 1% on origin amount\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Chain gas amount to forward as rebate if requested\n uint256 public chainGasAmount;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n }\n\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n require(newFeeRate \u003c= FEE_RATE_MAX, \"newFeeRate \u003e max\");\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n token.universalTransfer(recipient, feeAmount);\n emit FeesSwept(token, recipient, feeAmount);\n }\n\n function setChainGasAmount(uint256 newChainGasAmount) external onlyRole(GOVERNOR_ROLE) {\n uint256 oldChainGasAmount = chainGasAmount;\n chainGasAmount = newChainGasAmount;\n emit ChainGasAmountUpdated(oldChainGasAmount, newChainGasAmount);\n }\n}\n\n// contracts/FastBridgeV2.sol\n\n/// @notice FastBridgeV2 is a contract for bridging tokens across chains.\ncontract FastBridgeV2 is Admin, MulticallTarget, IFastBridgeV2, IFastBridgeV2Errors {\n using BridgeTransactionV2Lib for bytes;\n using SafeERC20 for IERC20;\n\n /// @notice Address reserved for native gas token (ETH on Ethereum and most L2s, AVAX on Avalanche, etc)\n address public constant NATIVE_GAS_TOKEN = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Delay for a transaction after which it could be permisionlessly refunded\n uint256 public constant REFUND_DELAY = 7 days;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n /// @notice Maximum length of accepted zapData\n uint256 public constant MAX_ZAP_DATA_LENGTH = 2 ** 16 - 1;\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeTxDetails) public bridgeTxDetails;\n /// @notice Relay details on destination chain\n mapping(bytes32 =\u003e BridgeRelay) public bridgeRelayDetails;\n /// @notice Unique bridge nonces tracked per originSender\n mapping(address =\u003e uint256) public senderNonces;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Replaced by senderNonces\n uint256 public immutable nonce = 0;\n /// @notice the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n bridge({\n params: params,\n paramsV2: BridgeParamsV2({\n quoteRelayer: address(0),\n quoteExclusivitySeconds: 0,\n quoteId: bytes(\"\"),\n zapNative: 0,\n zapData: bytes(\"\")\n })\n });\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes calldata request) external payable {\n // relay override will validate the request\n relay({request: request, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes calldata request, bytes32 destTxHash) external {\n request.validateV2();\n prove({transactionId: keccak256(request), destTxHash: destTxHash, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridgeV2\n function claim(bytes calldata request) external {\n // claim override will validate the request\n claim({request: request, to: address(0)});\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Aggregate the read operations from the same storage slot\n address disputedRelayer = $.proofRelayer;\n BridgeStatus status = $.status;\n uint56 proofBlockTimestamp = $.proofBlockTimestamp;\n // Can only dispute a RELAYER_PROVED transaction within the dispute period\n if (status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(proofBlockTimestamp) \u003e DISPUTE_PERIOD) {\n revert DisputePeriodPassed();\n }\n // Update status to REQUESTED and delete the disputed proof details\n // Note: these are storage writes\n $.status = BridgeStatus.REQUESTED;\n $.proofRelayer = address(0);\n $.proofBlockTimestamp = 0;\n\n emit BridgeProofDisputed(transactionId, disputedRelayer);\n }\n\n /// @inheritdoc IFastBridge\n function refund(bytes calldata request) external {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Can only refund a REQUESTED transaction after its deadline expires\n if ($.status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n uint256 deadline = request.deadline();\n // Permissionless refund is only allowed after REFUND_DELAY on top of the deadline\n if (!hasRole(REFUNDER_ROLE, msg.sender)) deadline += REFUND_DELAY;\n if (block.timestamp \u003c= deadline) revert DeadlineNotExceeded();\n // Update status to REFUNDED and return the full amount (collateral + protocol fees) to the original sender.\n // The protocol fees are only updated when the transaction is claimed, so we don't need to update them here.\n // Note: this is a storage write\n $.status = BridgeStatus.REFUNDED;\n\n address to = request.originSender();\n address token = request.originToken();\n uint256 amount = request.originAmount() + request.originFeeAmount();\n // Emit the event before any external calls\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n // Complete the user refund as the last transaction action\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(to), amount);\n } else {\n IERC20(token).safeTransfer(to, amount);\n }\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // The correct relayer can only claim a RELAYER_PROVED transaction after the dispute period\n if ($.status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if ($.proofRelayer != relayer) revert SenderIncorrect();\n return _timeSince($.proofBlockTimestamp) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n /// @dev This method is added to achieve backwards compatibility with decoding requests into V1 structs:\n /// - `zapNative` is partially reported as a zero/non-zero flag\n /// - `zapData` is ignored\n /// In order to process all kinds of requests use getBridgeTransactionV2 instead.\n function getBridgeTransaction(bytes calldata request) external view returns (BridgeTransaction memory) {\n // Try decoding into V2 struct first. This will revert if V1 struct is passed\n try this.getBridgeTransactionV2(request) returns (BridgeTransactionV2 memory txV2) {\n // Note: we entirely ignore the zapData field, as it was not present in V1\n return BridgeTransaction({\n originChainId: txV2.originChainId,\n destChainId: txV2.destChainId,\n originSender: txV2.originSender,\n destRecipient: txV2.destRecipient,\n originToken: txV2.originToken,\n destToken: txV2.destToken,\n originAmount: txV2.originAmount,\n destAmount: txV2.destAmount,\n originFeeAmount: txV2.originFeeAmount,\n sendChainGas: txV2.zapNative != 0,\n deadline: txV2.deadline,\n nonce: txV2.nonce\n });\n } catch {\n // Fallback to V1 struct\n return abi.decode(request, (BridgeTransaction));\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function getBridgeTransactionV2(bytes calldata request) external pure returns (BridgeTransactionV2 memory) {\n request.validateV2();\n return BridgeTransactionV2Lib.decodeV2(request);\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) public payable {\n int256 exclusivityEndTime = 0;\n // if relayer exclusivity is not intended for this bridge, set exclusivityEndTime to static zero\n // otherwise, set exclusivity to expire at the current block ts offset by quoteExclusivitySeconds\n if (paramsV2.quoteRelayer != address(0)) {\n exclusivityEndTime = int256(block.timestamp) + paramsV2.quoteExclusivitySeconds;\n }\n _validateBridgeParams(params, paramsV2, exclusivityEndTime);\n\n // transfer tokens to bridge contract\n /// @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _takeBridgedUserAsset(params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) {\n originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n }\n\n // set status to requested\n bytes memory request = BridgeTransactionV2Lib.encodeV2(\n BridgeTransactionV2({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n deadline: params.deadline,\n nonce: senderNonces[params.sender]++, // increment nonce on every bridge\n exclusivityRelayer: paramsV2.quoteRelayer,\n // We checked exclusivityEndTime to be in range [0 .. params.deadline] above, so can safely cast\n exclusivityEndTime: uint256(exclusivityEndTime),\n zapNative: paramsV2.zapNative,\n zapData: paramsV2.zapData\n })\n );\n bytes32 transactionId = keccak256(request);\n // Note: the tx status will be updated throughout the tx lifecycle, while destChainId is set once here\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n bridgeTxDetails[transactionId].destChainId = params.dstChainId;\n\n emit BridgeRequested({\n transactionId: transactionId,\n sender: params.sender,\n request: request,\n destChainId: params.dstChainId,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n sendChainGas: paramsV2.zapNative != 0\n });\n emit BridgeQuoteDetails(transactionId, paramsV2.quoteId);\n }\n\n /// @inheritdoc IFastBridgeV2\n function relay(bytes calldata request, address relayer) public payable {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n _validateRelayParams(request, transactionId, relayer);\n // mark bridge transaction as relayed\n bridgeRelayDetails[transactionId] =\n BridgeRelay({blockNumber: uint48(block.number), blockTimestamp: uint48(block.timestamp), relayer: relayer});\n\n // transfer tokens to recipient on destination chain and trigger Zap if requested\n address to = request.destRecipient();\n address token = request.destToken();\n uint256 amount = request.destAmount();\n uint256 zapNative = request.zapNative();\n\n // Emit the event before any external calls\n emit BridgeRelayed({\n transactionId: transactionId,\n relayer: relayer,\n to: to,\n originChainId: request.originChainId(),\n originToken: request.originToken(),\n destToken: token,\n originAmount: request.originAmount(),\n destAmount: amount,\n chainGasAmount: zapNative\n });\n\n // All state changes have been done at this point, can proceed to the external calls.\n // This follows the checks-effects-interactions pattern to mitigate potential reentrancy attacks.\n if (token == NATIVE_GAS_TOKEN) {\n // For the native gas token, additional zapNative is not allowed\n if (zapNative != 0) revert ZapNativeNotSupported();\n // Check that the correct msg.value was sent\n if (msg.value != amount) revert MsgValueIncorrect();\n // Don't do a native transfer yet: we will handle it alongside the Zap below\n } else {\n // For ERC20s, we check that the correct msg.value was sent\n if (msg.value != zapNative) revert MsgValueIncorrect();\n // We need to transfer the tokens from the Relayer to the recipient first before performing an\n // optional post-transfer Zap.\n IERC20(token).safeTransferFrom(msg.sender, to, amount);\n }\n // At this point we have done:\n // - Transferred the requested amount of ERC20 tokens to the recipient.\n // At this point we have confirmed:\n // - For ERC20s: msg.value matches the requested zapNative amount.\n // - For the native gas token: msg.value matches the requested destAmount.\n // Remaining optional things to do:\n // - Forward the full msg.value to the recipient (if non-zero).\n // - Trigger a Zap (if zapData is present).\n bytes calldata zapData = request.zapData();\n if (zapData.length != 0) {\n // Zap Data is present: Zap has been requested by the recipient. Trigger it forwarding the full msg.value.\n\n // Note: if token has a fee on transfers, the recipient will have received less than `amount`.\n // This is a very niche edge case and should be handled by the recipient contract.\n _triggerZapWithChecks({recipient: to, token: token, amount: amount, zapData: zapData});\n } else if (msg.value != 0) {\n // Zap Data is missing, but msg.value was sent. This could happen in two different cases:\n // - Relay with the native gas token is happening.\n // - Relay with ERC20 is happening, with a `zapNative \u003e 0` request.\n // In both cases, we need to transfer the full msg.value to the recipient.\n Address.sendValue(payable(to), msg.value);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) public onlyRole(RELAYER_ROLE) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n\n // Can only prove a REQUESTED transaction\n if ($.status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n // Update status to RELAYER_PROVED and store the proof details\n // Note: these are storage writes\n $.status = BridgeStatus.RELAYER_PROVED;\n $.proofBlockTimestamp = uint56(block.timestamp);\n $.proofRelayer = relayer;\n\n emit BridgeProofProvided(transactionId, relayer, destTxHash);\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes calldata request, address to) public {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Aggregate the read operations from the same storage slot\n address proofRelayer = $.proofRelayer;\n BridgeStatus status = $.status;\n uint56 proofBlockTimestamp = $.proofBlockTimestamp;\n\n // Can only claim a RELAYER_PROVED transaction after the dispute period\n if (status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(proofBlockTimestamp) \u003c= DISPUTE_PERIOD) {\n revert DisputePeriodNotPassed();\n }\n\n if (to == address(0)) {\n // Anyone could claim the funds to the proven relayer on their behalf\n to = proofRelayer;\n } else if (proofRelayer != msg.sender) {\n // Only the proven relayer could specify an address to claim the funds to\n revert SenderIncorrect();\n }\n\n // Update status to RELAYER_CLAIMED and transfer the origin collateral to the specified claim address\n // Note: this is a storage write\n $.status = BridgeStatus.RELAYER_CLAIMED;\n\n address token = request.originToken();\n uint256 amount = request.originAmount();\n // Update protocol fees if origin fee amount exists\n uint256 originFeeAmount = request.originFeeAmount();\n if (originFeeAmount \u003e 0) protocolFees[token] += originFeeAmount;\n // Emit the event before any external calls\n emit BridgeDepositClaimed(transactionId, proofRelayer, to, token, amount);\n // Complete the relayer claim as the last transaction action\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(to), amount);\n } else {\n IERC20(token).safeTransfer(to, amount);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeStatuses(bytes32 transactionId) public view returns (BridgeStatus status) {\n return bridgeTxDetails[transactionId].status;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeProofs(bytes32 transactionId) public view returns (uint96 timestamp, address relayer) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n\n timestamp = $.proofBlockTimestamp;\n relayer = $.proofRelayer;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeRelays(bytes32 transactionId) public view returns (bool) {\n // has this transactionId been relayed?\n return bridgeRelayDetails[transactionId].relayer != address(0);\n }\n\n /// @notice Takes the bridged asset from the user into FastBridgeV2 custody. It will be later\n /// claimed by the relayer who completed the relay on destination chain, or refunded back to the user,\n /// should no one complete the relay.\n function _takeBridgedUserAsset(address token, uint256 amount) internal returns (uint256 amountTaken) {\n if (token == NATIVE_GAS_TOKEN) {\n // For the native gas token, we just need to check that the supplied msg.value is correct.\n // Supplied `msg.value` is already in FastBridgeV2 custody.\n if (amount != msg.value) revert MsgValueIncorrect();\n amountTaken = msg.value;\n } else {\n // For ERC20s, token is explicitly transferred from the user to FastBridgeV2.\n // We don't allow non-zero `msg.value` to avoid extra funds from being stuck in FastBridgeV2.\n if (msg.value != 0) revert MsgValueIncorrect();\n // Throw an explicit error if the provided token address is not a contract\n if (token.code.length == 0) revert TokenNotContract();\n amountTaken = IERC20(token).balanceOf(address(this));\n IERC20(token).safeTransferFrom(msg.sender, address(this), amount);\n // Use the balance difference as the amount taken in case of fee on transfer tokens.\n amountTaken = IERC20(token).balanceOf(address(this)) - amountTaken;\n }\n }\n\n /// @notice Calls the Recipient's hook function with the specified zapData and performs\n /// all the necessary checks for the returned value.\n function _triggerZapWithChecks(address recipient, address token, uint256 amount, bytes calldata zapData) internal {\n // This will bubble any revert messages from the hook function\n bytes memory returnData = Address.functionCallWithValue({\n target: recipient,\n data: abi.encodeCall(IZapRecipient.zap, (token, amount, zapData)),\n // Note: see `relay()` for reasoning behind passing msg.value\n value: msg.value\n });\n // Explicit revert if no return data at all\n if (returnData.length == 0) revert RecipientNoReturnValue();\n // Check that exactly a single return value was returned\n if (returnData.length != 32) revert RecipientIncorrectReturnValue();\n // Return value should be abi-encoded hook function selector\n if (bytes32(returnData) != bytes32(IZapRecipient.zap.selector)) {\n revert RecipientIncorrectReturnValue();\n }\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint56(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint56).max but\n /// proof.timestamp \u003c type(uint56).max via unchecked statement\n /// @param proofBlockTimestamp The bridge proof block timestamp\n /// @return delta Time delta since proof submitted\n function _timeSince(uint56 proofBlockTimestamp) internal view returns (uint256 delta) {\n unchecked {\n delta = uint56(block.timestamp) - proofBlockTimestamp;\n }\n }\n\n /// @notice Performs all the necessary checks for a bridge to happen.\n /// @dev There's no good way to refactor this function to reduce cyclomatic complexity due to\n /// the number of checks that need to be performed, so we skip the code-complexity rule here.\n // solhint-disable-next-line code-complexity\n function _validateBridgeParams(\n BridgeParams memory params,\n BridgeParamsV2 memory paramsV2,\n int256 exclusivityEndTime\n )\n internal\n view\n {\n // Check V1 (legacy) params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.sender == address(0) || params.to == address(0)) revert ZeroAddress();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n // Check V2 params\n if (paramsV2.zapData.length \u003e MAX_ZAP_DATA_LENGTH) revert ZapDataLengthAboveMax();\n if (paramsV2.zapNative != 0 \u0026\u0026 params.destToken == NATIVE_GAS_TOKEN) {\n revert ZapNativeNotSupported();\n }\n // exclusivityEndTime must be in range [0 .. params.deadline]\n if (exclusivityEndTime \u003c 0 || exclusivityEndTime \u003e int256(params.deadline)) {\n revert ExclusivityParamsIncorrect();\n }\n }\n\n /// @notice Performs all the necessary checks for a relay to happen.\n function _validateRelayParams(bytes calldata request, bytes32 transactionId, address relayer) internal view {\n if (relayer == address(0)) revert ZeroAddress();\n // Check if the transaction has already been relayed\n if (bridgeRelays(transactionId)) revert TransactionRelayed();\n if (request.destChainId() != block.chainid) revert ChainIncorrect();\n // Check the deadline for relay to happen\n if (block.timestamp \u003e request.deadline()) revert DeadlineExceeded();\n // Check the exclusivity period, if it is still ongoing\n address exclRelayer = request.exclusivityRelayer();\n if (exclRelayer != address(0) \u0026\u0026 exclRelayer != relayer \u0026\u0026 block.timestamp \u003c= request.exclusivityEndTime()) {\n revert ExclusivityPeriodNotPassed();\n }\n }\n}\n","language":"Solidity","languageVersion":"0.8.24","compilerVersion":"0.8.24","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"61814:5018:0:-:0;;;;;;;;;;;;;;;-1:-1:-1;;;61814:5018:0;;;;;;;;;;;;;;;;;","srcMapRuntime":"61814:5018:0:-:0;;;;;;;;","abiDefinition":[{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"currentAllowance","type":"uint256"},{"internalType":"uint256","name":"requestedDecrease","type":"uint256"}],"name":"SafeERC20FailedDecreaseAllowance","type":"error"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"SafeERC20FailedOperation","type":"error"}],"userDoc":{"kind":"user","methods":{},"version":1},"developerDoc":{"details":"Wrappers around ERC20 operations that throw on failure (when the token contract returns false). Tokens that return no value (and instead revert or throw on failure) are also supported, non-reverting calls are assumed to be successful. To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract, which allows you to call the safe operations as `token.safeTransfer(...)`, etc.","errors":{"SafeERC20FailedDecreaseAllowance(address,uint256,uint256)":[{"details":"Indicates a failed `decreaseAllowance` request."}],"SafeERC20FailedOperation(address)":[{"details":"An operation with an ERC20 token failed."}]},"kind":"dev","methods":{},"title":"SafeERC20","version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"currentAllowance\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"requestedDecrease\",\"type\":\"uint256\"}],\"name\":\"SafeERC20FailedDecreaseAllowance\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"}],\"name\":\"SafeERC20FailedOperation\",\"type\":\"error\"}],\"devdoc\":{\"details\":\"Wrappers around ERC20 operations that throw on failure (when the token contract returns false). Tokens that return no value (and instead revert or throw on failure) are also supported, non-reverting calls are assumed to be successful. To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract, which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\",\"errors\":{\"SafeERC20FailedDecreaseAllowance(address,uint256,uint256)\":[{\"details\":\"Indicates a failed `decreaseAllowance` request.\"}],\"SafeERC20FailedOperation(address)\":[{\"details\":\"An operation with an ERC20 token failed.\"}]},\"kind\":\"dev\",\"methods\":{},\"title\":\"SafeERC20\",\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeV2.sol\":\"SafeERC20\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeV2.sol\":{\"keccak256\":\"0x5069b55ca07f21bfe30b2a43c18a18318c8af9c181b2dcb07c290825efd70f34\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://273dc020a49d08e50126bbea0d7f783f79d08c702f2fdbc560618d24af308acc\",\"dweb:/ipfs/QmXJ2UVzFc8EPB74RT4CXQPC4xw66jt4T13poyfyd3UERh\"]}},\"version\":1}"},"hashes":{}},"solidity/FastBridgeV2.sol:UniversalTokenLib":{"code":"0x60566037600b82828239805160001a607314602a57634e487b7160e01b600052600060045260246000fd5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600080fdfea26469706673582212208ee6f45538d68dae1182af6006877f66fc2bb57b5fe35283c7b3ccf352c1148364736f6c63430008180033","runtime-code":"0x73000000000000000000000000000000000000000030146080604052600080fdfea26469706673582212208ee6f45538d68dae1182af6006877f66fc2bb57b5fe35283c7b3ccf352c1148364736f6c63430008180033","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.24 ^0.8.20 ^0.8.4;\n\n// contracts/interfaces/IAdmin.sol\n\ninterface IAdmin {\n // ============ Events ============\n\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n event ChainGasAmountUpdated(uint256 oldChainGasAmount, uint256 newChainGasAmount);\n\n // ============ Methods ============\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n\n function setChainGasAmount(uint256 newChainGasAmount) external;\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IFastBridgeV2Errors.sol\n\ninterface IFastBridgeV2Errors {\n error AmountIncorrect();\n error ChainIncorrect();\n error ExclusivityParamsIncorrect();\n error MsgValueIncorrect();\n error SenderIncorrect();\n error StatusIncorrect();\n error TokenNotContract();\n error ZapDataLengthAboveMax();\n error ZapNativeNotSupported();\n error ZeroAddress();\n\n error RecipientIncorrectReturnValue();\n error RecipientNoReturnValue();\n\n error DeadlineExceeded();\n error DeadlineNotExceeded();\n error DeadlineTooShort();\n error DisputePeriodNotPassed();\n error DisputePeriodPassed();\n error ExclusivityPeriodNotPassed();\n\n error TransactionRelayed();\n}\n\n// contracts/interfaces/IMulticallTarget.sol\n\n/// @notice Interface for a contract that can be called multiple times by the same caller. Inspired by MulticallV3:\n/// https://github.com/mds1/multicall/blob/master/src/Multicall3.sol\ninterface IMulticallTarget {\n struct Result {\n bool success;\n bytes returnData;\n }\n\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external;\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results);\n}\n\n// contracts/interfaces/IZapRecipient.sol\n\ninterface IZapRecipient {\n function zap(address token, uint256 amount, bytes memory zapData) external payable returns (bytes4);\n}\n\n// contracts/libs/Errors.sol\n\nerror DeadlineExceeded();\nerror DeadlineNotExceeded();\nerror DeadlineTooShort();\nerror InsufficientOutputAmount();\n\nerror MsgValueIncorrect();\nerror PoolNotFound();\nerror TokenAddressMismatch();\nerror TokenNotContract();\nerror TokenNotETH();\nerror TokensIdentical();\n\nerror ChainIncorrect();\nerror AmountIncorrect();\nerror ZeroAddress();\n\nerror DisputePeriodNotPassed();\nerror DisputePeriodPassed();\nerror SenderIncorrect();\nerror StatusIncorrect();\nerror TransactionIdIncorrect();\nerror TransactionRelayed();\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// contracts/interfaces/IFastBridgeV2.sol\n\ninterface IFastBridgeV2 is IFastBridge {\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n struct BridgeTxDetails {\n BridgeStatus status;\n uint32 destChainId;\n uint56 proofBlockTimestamp;\n address proofRelayer;\n }\n\n struct BridgeRelay {\n uint48 blockNumber;\n uint48 blockTimestamp;\n address relayer;\n }\n\n /// @notice New params introduced in the FastBridgeV2.\n /// We are passing fields from the older BridgeParams struct outside of this struct\n /// for backwards compatibility.\n /// Note: quoteRelayer and quoteExclusivitySeconds are either both zero (indicating no exclusivity)\n /// or both non-zero (indicating exclusivity for the given period).\n /// Note: zapNative \u003e 0 can NOT be used with destToken = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE (native token)\n /// @param quoteRelayer Relayer that provided the quote for the transaction\n /// @param quoteExclusivitySeconds Period of time the quote relayer is guaranteed exclusivity after user's deposit\n /// @param quoteId Unique quote identifier used for tracking the quote\n /// @param zapNative ETH value to send to the recipient (if any)\n /// @param zapData Parameters for the Zap to the destination recipient (if any)\n struct BridgeParamsV2 {\n address quoteRelayer;\n int256 quoteExclusivitySeconds;\n bytes quoteId;\n uint256 zapNative;\n bytes zapData;\n }\n\n /// @notice Updated bridge transaction struct to include parameters introduced in FastBridgeV2.\n /// Note: only `exclusivityRelayer` can fill such a transaction until `exclusivityEndTime`.\n struct BridgeTransactionV2 {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n // Note: sendChainGas flag from V1 is deprecated\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n address exclusivityRelayer;\n uint256 exclusivityEndTime;\n uint256 zapNative; // ETH value to send to the recipient (if any)\n bytes zapData; // data to pass for the Zap action (if any)\n }\n\n event BridgeQuoteDetails(bytes32 indexed transactionId, bytes quoteId);\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability\n /// to provide temporary exclusivity fill rights for the quote relayer.\n /// @param params The parameters required to bridge\n /// @param paramsV2 The parameters for exclusivity fill rights (optional, can be left empty)\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function relay(bytes memory request, address relayer) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param transactionId The transaction id associated with the encoded bridge transaction to prove\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital.\n /// @notice Can only send funds to the relayer address on the proof.\n /// @param request The encoded bridge transaction to claim on origin chain\n function claim(bytes memory request) external;\n /// @notice Checks if a transaction has been relayed\n /// @param transactionId The ID of the transaction to check\n /// @return True if the transaction has been relayed, false otherwise\n function bridgeRelays(bytes32 transactionId) external view returns (bool);\n\n /// @notice Returns the status of a bridge transaction\n /// @param transactionId The ID of the bridge transaction\n /// @return BridgeStatus Status of the bridge transaction\n function bridgeStatuses(bytes32 transactionId) external view returns (BridgeStatus);\n\n /// @notice Returns the timestamp and relayer of a bridge proof\n /// @param transactionId The ID of the bridge transaction\n /// @return timestamp The timestamp of the bridge proof\n /// @return relayer The relayer address of the bridge proof\n function bridgeProofs(bytes32 transactionId) external view returns (uint96 timestamp, address relayer);\n\n /// @notice Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\n /// @param request The bridge request to decode\n function getBridgeTransactionV2(bytes memory request) external view returns (BridgeTransactionV2 memory);\n}\n\n// contracts/utils/MulticallTarget.sol\n\n// solhint-disable avoid-low-level-calls\n/// @notice Template for a contract that supports batched calls (preserving the msg.sender).\n/// Only calls with zero msg.value could be batched.\nabstract contract MulticallTarget is IMulticallTarget {\n error MulticallTarget__UndeterminedRevert();\n\n /// @notice Perform a batched call to this contract, preserving the msg.sender.\n /// The return data from each call is discarded.\n /// @dev The method is non-payable, so only calls with `msg.value == 0` could be batched.\n /// It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag.\n /// Otherwise, the whole batch call will be reverted with the original revert reason.\n /// @param data List of abi-encoded calldata for the calls to perform.\n /// @param ignoreReverts Whether to ignore the revert errors from the calls.\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external {\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\n if (!success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(result);\n }\n }\n }\n\n /// @notice Perform a batched call to this contract, preserving the msg.sender.\n /// The return data from each call is preserved.\n /// @dev The method is non-payable, so only calls with `msg.value == 0` could be batched.\n /// It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag.\n /// Otherwise, the whole batch call will be reverted with the original revert reason.\n /// @param data List of abi-encoded calldata for the calls to perform.\n /// @param ignoreReverts Whether to ignore the revert errors from the calls.\n /// @return results List of results from the calls: `(success, returnData)`.\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results)\n {\n results = new Result[](data.length);\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (results[i].success, results[i].returnData) = address(this).delegatecall(data[i]);\n if (!results[i].success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(results[i].returnData);\n }\n }\n }\n\n /// @dev Bubbles the revert message from the underlying call.\n /// Note: preserves the same custom error or revert string, if one was used.\n /// Source: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v5.0.2/contracts/utils/Address.sol#L143-L158\n function _bubbleRevert(bytes memory returnData) internal pure {\n // Look for revert reason and bubble it up if present\n if (returnData.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n // solhint-disable-next-line no-inline-assembly\n assembly {\n let returndata_size := mload(returnData)\n revert(add(32, returnData), returndata_size)\n }\n } else {\n revert MulticallTarget__UndeterminedRevert();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// contracts/libs/BridgeTransactionV2.sol\n\n// solhint-disable no-inline-assembly\nlibrary BridgeTransactionV2Lib {\n uint16 internal constant VERSION = 2;\n\n // Offsets of the fields in the packed BridgeTransactionV2 struct\n // uint16 version [000 .. 002)\n // uint32 originChainId [002 .. 006)\n // uint32 destChainId [006 .. 010)\n // address originSender [010 .. 030)\n // address destRecipient [030 .. 050)\n // address originToken [050 .. 070)\n // address destToken [070 .. 090)\n // uint256 originAmount [090 .. 122)\n // uint256 destAmount [122 .. 154)\n // uint256 originFeeAmount [154 .. 186)\n // uint256 deadline [186 .. 218)\n // uint256 nonce [218 .. 250)\n // address exclusivityRelayer [250 .. 270)\n // uint256 exclusivityEndTime [270 .. 302)\n // uint256 zapNative [302 .. 334)\n // bytes zapData [334 .. ***)\n\n // forgefmt: disable-start\n uint256 private constant OFFSET_ORIGIN_CHAIN_ID = 2;\n uint256 private constant OFFSET_DEST_CHAIN_ID = 6;\n uint256 private constant OFFSET_ORIGIN_SENDER = 10;\n uint256 private constant OFFSET_DEST_RECIPIENT = 30;\n uint256 private constant OFFSET_ORIGIN_TOKEN = 50;\n uint256 private constant OFFSET_DEST_TOKEN = 70;\n uint256 private constant OFFSET_ORIGIN_AMOUNT = 90;\n uint256 private constant OFFSET_DEST_AMOUNT = 122;\n uint256 private constant OFFSET_ORIGIN_FEE_AMOUNT = 154;\n uint256 private constant OFFSET_DEADLINE = 186;\n uint256 private constant OFFSET_NONCE = 218;\n uint256 private constant OFFSET_EXCLUSIVITY_RELAYER = 250;\n uint256 private constant OFFSET_EXCLUSIVITY_END_TIME = 270;\n uint256 private constant OFFSET_ZAP_NATIVE = 302;\n uint256 private constant OFFSET_ZAP_DATA = 334;\n // forgefmt: disable-end\n\n error BridgeTransactionV2__InvalidEncodedTx();\n error BridgeTransactionV2__UnsupportedVersion(uint16 version);\n\n /// @notice Validates the encoded transaction to be a tightly packed encoded payload for BridgeTransactionV2.\n /// @dev Checks the minimum length and the version, use this function before decoding any of the fields.\n function validateV2(bytes calldata encodedTx) internal pure {\n // Check the minimum length: must at least include all static fields.\n if (encodedTx.length \u003c OFFSET_ZAP_DATA) revert BridgeTransactionV2__InvalidEncodedTx();\n // Once we validated the length, we can be sure that the version field is present.\n uint16 version_ = version(encodedTx);\n if (version_ != VERSION) revert BridgeTransactionV2__UnsupportedVersion(version_);\n }\n\n /// @notice Encodes the BridgeTransactionV2 struct by tightly packing the fields.\n /// @dev `abi.decode` will not work as a result of the tightly packed fields. Use `decodeV2` to decode instead.\n function encodeV2(IFastBridgeV2.BridgeTransactionV2 memory bridgeTx) internal pure returns (bytes memory) {\n // We split the encoding into two parts to avoid stack-too-deep error\n bytes memory firstPart = abi.encodePacked(\n VERSION,\n bridgeTx.originChainId,\n bridgeTx.destChainId,\n bridgeTx.originSender,\n bridgeTx.destRecipient,\n bridgeTx.originToken,\n bridgeTx.destToken,\n bridgeTx.originAmount\n );\n return abi.encodePacked(\n firstPart,\n bridgeTx.destAmount,\n bridgeTx.originFeeAmount,\n // Note: we skip the deprecated `sendChainGas` flag, which was present in BridgeTransaction V1\n bridgeTx.deadline,\n bridgeTx.nonce,\n // New V2 fields: exclusivity\n bridgeTx.exclusivityRelayer,\n bridgeTx.exclusivityEndTime,\n // New V2 fields: Zap\n bridgeTx.zapNative,\n bridgeTx.zapData\n );\n }\n\n /// @notice Decodes the BridgeTransactionV2 struct from the encoded transaction.\n /// @dev Encoded BridgeTransactionV2 struct must be tightly packed.\n /// Use `validateV2` before decoding to ensure the encoded transaction is valid.\n function decodeV2(bytes calldata encodedTx)\n internal\n pure\n returns (IFastBridgeV2.BridgeTransactionV2 memory bridgeTx)\n {\n bridgeTx.originChainId = originChainId(encodedTx);\n bridgeTx.destChainId = destChainId(encodedTx);\n bridgeTx.originSender = originSender(encodedTx);\n bridgeTx.destRecipient = destRecipient(encodedTx);\n bridgeTx.originToken = originToken(encodedTx);\n bridgeTx.destToken = destToken(encodedTx);\n bridgeTx.originAmount = originAmount(encodedTx);\n bridgeTx.destAmount = destAmount(encodedTx);\n bridgeTx.originFeeAmount = originFeeAmount(encodedTx);\n bridgeTx.deadline = deadline(encodedTx);\n bridgeTx.nonce = nonce(encodedTx);\n bridgeTx.exclusivityRelayer = exclusivityRelayer(encodedTx);\n bridgeTx.exclusivityEndTime = exclusivityEndTime(encodedTx);\n bridgeTx.zapNative = zapNative(encodedTx);\n bridgeTx.zapData = zapData(encodedTx);\n }\n\n /// @notice Extracts the version from the encoded transaction.\n function version(bytes calldata encodedTx) internal pure returns (uint16 version_) {\n // Load 32 bytes from the start and shift it 240 bits to the right to get the highest 16 bits.\n assembly {\n version_ := shr(240, calldataload(encodedTx.offset))\n }\n }\n\n /// @notice Extracts the origin chain ID from the encoded transaction.\n function originChainId(bytes calldata encodedTx) internal pure returns (uint32 originChainId_) {\n // Load 32 bytes from the offset and shift it 224 bits to the right to get the highest 32 bits.\n assembly {\n originChainId_ := shr(224, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_CHAIN_ID)))\n }\n }\n\n /// @notice Extracts the destination chain ID from the encoded transaction.\n function destChainId(bytes calldata encodedTx) internal pure returns (uint32 destChainId_) {\n // Load 32 bytes from the offset and shift it 224 bits to the right to get the highest 32 bits.\n assembly {\n destChainId_ := shr(224, calldataload(add(encodedTx.offset, OFFSET_DEST_CHAIN_ID)))\n }\n }\n\n /// @notice Extracts the origin sender from the encoded transaction.\n function originSender(bytes calldata encodedTx) internal pure returns (address originSender_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n originSender_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_SENDER)))\n }\n }\n\n /// @notice Extracts the destination recipient from the encoded transaction.\n function destRecipient(bytes calldata encodedTx) internal pure returns (address destRecipient_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n destRecipient_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_DEST_RECIPIENT)))\n }\n }\n\n /// @notice Extracts the origin token from the encoded transaction.\n function originToken(bytes calldata encodedTx) internal pure returns (address originToken_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n originToken_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_TOKEN)))\n }\n }\n\n /// @notice Extracts the destination token from the encoded transaction.\n function destToken(bytes calldata encodedTx) internal pure returns (address destToken_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n destToken_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_DEST_TOKEN)))\n }\n }\n\n /// @notice Extracts the origin amount from the encoded transaction.\n function originAmount(bytes calldata encodedTx) internal pure returns (uint256 originAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n originAmount_ := calldataload(add(encodedTx.offset, OFFSET_ORIGIN_AMOUNT))\n }\n }\n\n /// @notice Extracts the destination amount from the encoded transaction.\n function destAmount(bytes calldata encodedTx) internal pure returns (uint256 destAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n destAmount_ := calldataload(add(encodedTx.offset, OFFSET_DEST_AMOUNT))\n }\n }\n\n /// @notice Extracts the origin fee amount from the encoded transaction.\n function originFeeAmount(bytes calldata encodedTx) internal pure returns (uint256 originFeeAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n originFeeAmount_ := calldataload(add(encodedTx.offset, OFFSET_ORIGIN_FEE_AMOUNT))\n }\n }\n\n /// @notice Extracts the deadline from the encoded transaction.\n function deadline(bytes calldata encodedTx) internal pure returns (uint256 deadline_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n deadline_ := calldataload(add(encodedTx.offset, OFFSET_DEADLINE))\n }\n }\n\n /// @notice Extracts the nonce from the encoded transaction.\n function nonce(bytes calldata encodedTx) internal pure returns (uint256 nonce_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n nonce_ := calldataload(add(encodedTx.offset, OFFSET_NONCE))\n }\n }\n\n /// @notice Extracts the exclusivity relayer from the encoded transaction.\n function exclusivityRelayer(bytes calldata encodedTx) internal pure returns (address exclusivityRelayer_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n exclusivityRelayer_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_EXCLUSIVITY_RELAYER)))\n }\n }\n\n /// @notice Extracts the exclusivity end time from the encoded transaction.\n function exclusivityEndTime(bytes calldata encodedTx) internal pure returns (uint256 exclusivityEndTime_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n exclusivityEndTime_ := calldataload(add(encodedTx.offset, OFFSET_EXCLUSIVITY_END_TIME))\n }\n }\n\n /// @notice Extracts the Zap's native value from the encoded transaction.\n function zapNative(bytes calldata encodedTx) internal pure returns (uint256 zapNative_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n zapNative_ := calldataload(add(encodedTx.offset, OFFSET_ZAP_NATIVE))\n }\n }\n\n /// @notice Extracts the Zap's data from the encoded transaction.\n function zapData(bytes calldata encodedTx) internal pure returns (bytes calldata zapData_) {\n zapData_ = encodedTx[OFFSET_ZAP_DATA:];\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// contracts/libs/UniversalToken.sol\n\nlibrary UniversalTokenLib {\n using SafeERC20 for IERC20;\n\n address internal constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Transfers tokens to the given account. Reverts if transfer is not successful.\n /// @dev This might trigger fallback, if ETH is transferred to the contract.\n /// Make sure this can not lead to reentrancy attacks.\n function universalTransfer(address token, address to, uint256 value) internal {\n // Don't do anything, if need to send tokens to this address\n if (to == address(this)) return;\n // Don't do anything, if trying to send zero value\n if (value == 0) return;\n if (token == ETH_ADDRESS) {\n /// @dev Note: this can potentially lead to executing code in `to`.\n // solhint-disable-next-line avoid-low-level-calls\n (bool success,) = to.call{value: value}(\"\");\n require(success, \"ETH transfer failed\");\n } else {\n IERC20(token).safeTransfer(to, value);\n }\n }\n\n /// @notice Issues an infinite allowance to the spender, if the current allowance is insufficient\n /// to spend the given amount.\n function universalApproveInfinity(address token, address spender, uint256 amountToSpend) internal {\n // ETH Chad doesn't require your approval\n if (token == ETH_ADDRESS) return;\n // No-op if allowance is already sufficient\n uint256 allowance = IERC20(token).allowance(address(this), spender);\n if (allowance \u003e= amountToSpend) return;\n // Otherwise, reset approval to 0 and set to max allowance\n if (allowance \u003e 0) IERC20(token).safeDecreaseAllowance(spender, allowance);\n IERC20(token).safeIncreaseAllowance(spender, type(uint256).max);\n }\n\n /// @notice Returns the balance of the given token (or native ETH) for the given account.\n function universalBalanceOf(address token, address account) internal view returns (uint256) {\n if (token == ETH_ADDRESS) {\n return account.balance;\n } else {\n return IERC20(token).balanceOf(account);\n }\n }\n\n /// @dev Checks that token is a contract and not ETH_ADDRESS.\n function assertIsContract(address token) internal view {\n // Check that ETH_ADDRESS was not used (in case this is a predeploy on any of the chains)\n if (token == UniversalTokenLib.ETH_ADDRESS) revert TokenNotContract();\n // Check that token is not an EOA\n if (token.code.length == 0) revert TokenNotContract();\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/Admin.sol\n\ncontract Admin is IAdmin, AccessControlEnumerable {\n using UniversalTokenLib for address;\n\n bytes32 public constant RELAYER_ROLE = keccak256(\"RELAYER_ROLE\");\n bytes32 public constant REFUNDER_ROLE = keccak256(\"REFUNDER_ROLE\");\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n uint256 public constant FEE_BPS = 1e6;\n uint256 public constant FEE_RATE_MAX = 0.01e6; // max 1% on origin amount\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Chain gas amount to forward as rebate if requested\n uint256 public chainGasAmount;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n }\n\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n require(newFeeRate \u003c= FEE_RATE_MAX, \"newFeeRate \u003e max\");\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n token.universalTransfer(recipient, feeAmount);\n emit FeesSwept(token, recipient, feeAmount);\n }\n\n function setChainGasAmount(uint256 newChainGasAmount) external onlyRole(GOVERNOR_ROLE) {\n uint256 oldChainGasAmount = chainGasAmount;\n chainGasAmount = newChainGasAmount;\n emit ChainGasAmountUpdated(oldChainGasAmount, newChainGasAmount);\n }\n}\n\n// contracts/FastBridgeV2.sol\n\n/// @notice FastBridgeV2 is a contract for bridging tokens across chains.\ncontract FastBridgeV2 is Admin, MulticallTarget, IFastBridgeV2, IFastBridgeV2Errors {\n using BridgeTransactionV2Lib for bytes;\n using SafeERC20 for IERC20;\n\n /// @notice Address reserved for native gas token (ETH on Ethereum and most L2s, AVAX on Avalanche, etc)\n address public constant NATIVE_GAS_TOKEN = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Delay for a transaction after which it could be permisionlessly refunded\n uint256 public constant REFUND_DELAY = 7 days;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n /// @notice Maximum length of accepted zapData\n uint256 public constant MAX_ZAP_DATA_LENGTH = 2 ** 16 - 1;\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeTxDetails) public bridgeTxDetails;\n /// @notice Relay details on destination chain\n mapping(bytes32 =\u003e BridgeRelay) public bridgeRelayDetails;\n /// @notice Unique bridge nonces tracked per originSender\n mapping(address =\u003e uint256) public senderNonces;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Replaced by senderNonces\n uint256 public immutable nonce = 0;\n /// @notice the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n bridge({\n params: params,\n paramsV2: BridgeParamsV2({\n quoteRelayer: address(0),\n quoteExclusivitySeconds: 0,\n quoteId: bytes(\"\"),\n zapNative: 0,\n zapData: bytes(\"\")\n })\n });\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes calldata request) external payable {\n // relay override will validate the request\n relay({request: request, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes calldata request, bytes32 destTxHash) external {\n request.validateV2();\n prove({transactionId: keccak256(request), destTxHash: destTxHash, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridgeV2\n function claim(bytes calldata request) external {\n // claim override will validate the request\n claim({request: request, to: address(0)});\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Aggregate the read operations from the same storage slot\n address disputedRelayer = $.proofRelayer;\n BridgeStatus status = $.status;\n uint56 proofBlockTimestamp = $.proofBlockTimestamp;\n // Can only dispute a RELAYER_PROVED transaction within the dispute period\n if (status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(proofBlockTimestamp) \u003e DISPUTE_PERIOD) {\n revert DisputePeriodPassed();\n }\n // Update status to REQUESTED and delete the disputed proof details\n // Note: these are storage writes\n $.status = BridgeStatus.REQUESTED;\n $.proofRelayer = address(0);\n $.proofBlockTimestamp = 0;\n\n emit BridgeProofDisputed(transactionId, disputedRelayer);\n }\n\n /// @inheritdoc IFastBridge\n function refund(bytes calldata request) external {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Can only refund a REQUESTED transaction after its deadline expires\n if ($.status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n uint256 deadline = request.deadline();\n // Permissionless refund is only allowed after REFUND_DELAY on top of the deadline\n if (!hasRole(REFUNDER_ROLE, msg.sender)) deadline += REFUND_DELAY;\n if (block.timestamp \u003c= deadline) revert DeadlineNotExceeded();\n // Update status to REFUNDED and return the full amount (collateral + protocol fees) to the original sender.\n // The protocol fees are only updated when the transaction is claimed, so we don't need to update them here.\n // Note: this is a storage write\n $.status = BridgeStatus.REFUNDED;\n\n address to = request.originSender();\n address token = request.originToken();\n uint256 amount = request.originAmount() + request.originFeeAmount();\n // Emit the event before any external calls\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n // Complete the user refund as the last transaction action\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(to), amount);\n } else {\n IERC20(token).safeTransfer(to, amount);\n }\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // The correct relayer can only claim a RELAYER_PROVED transaction after the dispute period\n if ($.status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if ($.proofRelayer != relayer) revert SenderIncorrect();\n return _timeSince($.proofBlockTimestamp) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n /// @dev This method is added to achieve backwards compatibility with decoding requests into V1 structs:\n /// - `zapNative` is partially reported as a zero/non-zero flag\n /// - `zapData` is ignored\n /// In order to process all kinds of requests use getBridgeTransactionV2 instead.\n function getBridgeTransaction(bytes calldata request) external view returns (BridgeTransaction memory) {\n // Try decoding into V2 struct first. This will revert if V1 struct is passed\n try this.getBridgeTransactionV2(request) returns (BridgeTransactionV2 memory txV2) {\n // Note: we entirely ignore the zapData field, as it was not present in V1\n return BridgeTransaction({\n originChainId: txV2.originChainId,\n destChainId: txV2.destChainId,\n originSender: txV2.originSender,\n destRecipient: txV2.destRecipient,\n originToken: txV2.originToken,\n destToken: txV2.destToken,\n originAmount: txV2.originAmount,\n destAmount: txV2.destAmount,\n originFeeAmount: txV2.originFeeAmount,\n sendChainGas: txV2.zapNative != 0,\n deadline: txV2.deadline,\n nonce: txV2.nonce\n });\n } catch {\n // Fallback to V1 struct\n return abi.decode(request, (BridgeTransaction));\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function getBridgeTransactionV2(bytes calldata request) external pure returns (BridgeTransactionV2 memory) {\n request.validateV2();\n return BridgeTransactionV2Lib.decodeV2(request);\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) public payable {\n int256 exclusivityEndTime = 0;\n // if relayer exclusivity is not intended for this bridge, set exclusivityEndTime to static zero\n // otherwise, set exclusivity to expire at the current block ts offset by quoteExclusivitySeconds\n if (paramsV2.quoteRelayer != address(0)) {\n exclusivityEndTime = int256(block.timestamp) + paramsV2.quoteExclusivitySeconds;\n }\n _validateBridgeParams(params, paramsV2, exclusivityEndTime);\n\n // transfer tokens to bridge contract\n /// @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _takeBridgedUserAsset(params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) {\n originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n }\n\n // set status to requested\n bytes memory request = BridgeTransactionV2Lib.encodeV2(\n BridgeTransactionV2({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n deadline: params.deadline,\n nonce: senderNonces[params.sender]++, // increment nonce on every bridge\n exclusivityRelayer: paramsV2.quoteRelayer,\n // We checked exclusivityEndTime to be in range [0 .. params.deadline] above, so can safely cast\n exclusivityEndTime: uint256(exclusivityEndTime),\n zapNative: paramsV2.zapNative,\n zapData: paramsV2.zapData\n })\n );\n bytes32 transactionId = keccak256(request);\n // Note: the tx status will be updated throughout the tx lifecycle, while destChainId is set once here\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n bridgeTxDetails[transactionId].destChainId = params.dstChainId;\n\n emit BridgeRequested({\n transactionId: transactionId,\n sender: params.sender,\n request: request,\n destChainId: params.dstChainId,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n sendChainGas: paramsV2.zapNative != 0\n });\n emit BridgeQuoteDetails(transactionId, paramsV2.quoteId);\n }\n\n /// @inheritdoc IFastBridgeV2\n function relay(bytes calldata request, address relayer) public payable {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n _validateRelayParams(request, transactionId, relayer);\n // mark bridge transaction as relayed\n bridgeRelayDetails[transactionId] =\n BridgeRelay({blockNumber: uint48(block.number), blockTimestamp: uint48(block.timestamp), relayer: relayer});\n\n // transfer tokens to recipient on destination chain and trigger Zap if requested\n address to = request.destRecipient();\n address token = request.destToken();\n uint256 amount = request.destAmount();\n uint256 zapNative = request.zapNative();\n\n // Emit the event before any external calls\n emit BridgeRelayed({\n transactionId: transactionId,\n relayer: relayer,\n to: to,\n originChainId: request.originChainId(),\n originToken: request.originToken(),\n destToken: token,\n originAmount: request.originAmount(),\n destAmount: amount,\n chainGasAmount: zapNative\n });\n\n // All state changes have been done at this point, can proceed to the external calls.\n // This follows the checks-effects-interactions pattern to mitigate potential reentrancy attacks.\n if (token == NATIVE_GAS_TOKEN) {\n // For the native gas token, additional zapNative is not allowed\n if (zapNative != 0) revert ZapNativeNotSupported();\n // Check that the correct msg.value was sent\n if (msg.value != amount) revert MsgValueIncorrect();\n // Don't do a native transfer yet: we will handle it alongside the Zap below\n } else {\n // For ERC20s, we check that the correct msg.value was sent\n if (msg.value != zapNative) revert MsgValueIncorrect();\n // We need to transfer the tokens from the Relayer to the recipient first before performing an\n // optional post-transfer Zap.\n IERC20(token).safeTransferFrom(msg.sender, to, amount);\n }\n // At this point we have done:\n // - Transferred the requested amount of ERC20 tokens to the recipient.\n // At this point we have confirmed:\n // - For ERC20s: msg.value matches the requested zapNative amount.\n // - For the native gas token: msg.value matches the requested destAmount.\n // Remaining optional things to do:\n // - Forward the full msg.value to the recipient (if non-zero).\n // - Trigger a Zap (if zapData is present).\n bytes calldata zapData = request.zapData();\n if (zapData.length != 0) {\n // Zap Data is present: Zap has been requested by the recipient. Trigger it forwarding the full msg.value.\n\n // Note: if token has a fee on transfers, the recipient will have received less than `amount`.\n // This is a very niche edge case and should be handled by the recipient contract.\n _triggerZapWithChecks({recipient: to, token: token, amount: amount, zapData: zapData});\n } else if (msg.value != 0) {\n // Zap Data is missing, but msg.value was sent. This could happen in two different cases:\n // - Relay with the native gas token is happening.\n // - Relay with ERC20 is happening, with a `zapNative \u003e 0` request.\n // In both cases, we need to transfer the full msg.value to the recipient.\n Address.sendValue(payable(to), msg.value);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) public onlyRole(RELAYER_ROLE) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n\n // Can only prove a REQUESTED transaction\n if ($.status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n // Update status to RELAYER_PROVED and store the proof details\n // Note: these are storage writes\n $.status = BridgeStatus.RELAYER_PROVED;\n $.proofBlockTimestamp = uint56(block.timestamp);\n $.proofRelayer = relayer;\n\n emit BridgeProofProvided(transactionId, relayer, destTxHash);\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes calldata request, address to) public {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Aggregate the read operations from the same storage slot\n address proofRelayer = $.proofRelayer;\n BridgeStatus status = $.status;\n uint56 proofBlockTimestamp = $.proofBlockTimestamp;\n\n // Can only claim a RELAYER_PROVED transaction after the dispute period\n if (status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(proofBlockTimestamp) \u003c= DISPUTE_PERIOD) {\n revert DisputePeriodNotPassed();\n }\n\n if (to == address(0)) {\n // Anyone could claim the funds to the proven relayer on their behalf\n to = proofRelayer;\n } else if (proofRelayer != msg.sender) {\n // Only the proven relayer could specify an address to claim the funds to\n revert SenderIncorrect();\n }\n\n // Update status to RELAYER_CLAIMED and transfer the origin collateral to the specified claim address\n // Note: this is a storage write\n $.status = BridgeStatus.RELAYER_CLAIMED;\n\n address token = request.originToken();\n uint256 amount = request.originAmount();\n // Update protocol fees if origin fee amount exists\n uint256 originFeeAmount = request.originFeeAmount();\n if (originFeeAmount \u003e 0) protocolFees[token] += originFeeAmount;\n // Emit the event before any external calls\n emit BridgeDepositClaimed(transactionId, proofRelayer, to, token, amount);\n // Complete the relayer claim as the last transaction action\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(to), amount);\n } else {\n IERC20(token).safeTransfer(to, amount);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeStatuses(bytes32 transactionId) public view returns (BridgeStatus status) {\n return bridgeTxDetails[transactionId].status;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeProofs(bytes32 transactionId) public view returns (uint96 timestamp, address relayer) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n\n timestamp = $.proofBlockTimestamp;\n relayer = $.proofRelayer;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeRelays(bytes32 transactionId) public view returns (bool) {\n // has this transactionId been relayed?\n return bridgeRelayDetails[transactionId].relayer != address(0);\n }\n\n /// @notice Takes the bridged asset from the user into FastBridgeV2 custody. It will be later\n /// claimed by the relayer who completed the relay on destination chain, or refunded back to the user,\n /// should no one complete the relay.\n function _takeBridgedUserAsset(address token, uint256 amount) internal returns (uint256 amountTaken) {\n if (token == NATIVE_GAS_TOKEN) {\n // For the native gas token, we just need to check that the supplied msg.value is correct.\n // Supplied `msg.value` is already in FastBridgeV2 custody.\n if (amount != msg.value) revert MsgValueIncorrect();\n amountTaken = msg.value;\n } else {\n // For ERC20s, token is explicitly transferred from the user to FastBridgeV2.\n // We don't allow non-zero `msg.value` to avoid extra funds from being stuck in FastBridgeV2.\n if (msg.value != 0) revert MsgValueIncorrect();\n // Throw an explicit error if the provided token address is not a contract\n if (token.code.length == 0) revert TokenNotContract();\n amountTaken = IERC20(token).balanceOf(address(this));\n IERC20(token).safeTransferFrom(msg.sender, address(this), amount);\n // Use the balance difference as the amount taken in case of fee on transfer tokens.\n amountTaken = IERC20(token).balanceOf(address(this)) - amountTaken;\n }\n }\n\n /// @notice Calls the Recipient's hook function with the specified zapData and performs\n /// all the necessary checks for the returned value.\n function _triggerZapWithChecks(address recipient, address token, uint256 amount, bytes calldata zapData) internal {\n // This will bubble any revert messages from the hook function\n bytes memory returnData = Address.functionCallWithValue({\n target: recipient,\n data: abi.encodeCall(IZapRecipient.zap, (token, amount, zapData)),\n // Note: see `relay()` for reasoning behind passing msg.value\n value: msg.value\n });\n // Explicit revert if no return data at all\n if (returnData.length == 0) revert RecipientNoReturnValue();\n // Check that exactly a single return value was returned\n if (returnData.length != 32) revert RecipientIncorrectReturnValue();\n // Return value should be abi-encoded hook function selector\n if (bytes32(returnData) != bytes32(IZapRecipient.zap.selector)) {\n revert RecipientIncorrectReturnValue();\n }\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint56(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint56).max but\n /// proof.timestamp \u003c type(uint56).max via unchecked statement\n /// @param proofBlockTimestamp The bridge proof block timestamp\n /// @return delta Time delta since proof submitted\n function _timeSince(uint56 proofBlockTimestamp) internal view returns (uint256 delta) {\n unchecked {\n delta = uint56(block.timestamp) - proofBlockTimestamp;\n }\n }\n\n /// @notice Performs all the necessary checks for a bridge to happen.\n /// @dev There's no good way to refactor this function to reduce cyclomatic complexity due to\n /// the number of checks that need to be performed, so we skip the code-complexity rule here.\n // solhint-disable-next-line code-complexity\n function _validateBridgeParams(\n BridgeParams memory params,\n BridgeParamsV2 memory paramsV2,\n int256 exclusivityEndTime\n )\n internal\n view\n {\n // Check V1 (legacy) params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.sender == address(0) || params.to == address(0)) revert ZeroAddress();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n // Check V2 params\n if (paramsV2.zapData.length \u003e MAX_ZAP_DATA_LENGTH) revert ZapDataLengthAboveMax();\n if (paramsV2.zapNative != 0 \u0026\u0026 params.destToken == NATIVE_GAS_TOKEN) {\n revert ZapNativeNotSupported();\n }\n // exclusivityEndTime must be in range [0 .. params.deadline]\n if (exclusivityEndTime \u003c 0 || exclusivityEndTime \u003e int256(params.deadline)) {\n revert ExclusivityParamsIncorrect();\n }\n }\n\n /// @notice Performs all the necessary checks for a relay to happen.\n function _validateRelayParams(bytes calldata request, bytes32 transactionId, address relayer) internal view {\n if (relayer == address(0)) revert ZeroAddress();\n // Check if the transaction has already been relayed\n if (bridgeRelays(transactionId)) revert TransactionRelayed();\n if (request.destChainId() != block.chainid) revert ChainIncorrect();\n // Check the deadline for relay to happen\n if (block.timestamp \u003e request.deadline()) revert DeadlineExceeded();\n // Check the exclusivity period, if it is still ongoing\n address exclRelayer = request.exclusivityRelayer();\n if (exclRelayer != address(0) \u0026\u0026 exclRelayer != relayer \u0026\u0026 block.timestamp \u003c= request.exclusivityEndTime()) {\n revert ExclusivityPeriodNotPassed();\n }\n }\n}\n","language":"Solidity","languageVersion":"0.8.24","compilerVersion":"0.8.24","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"73773:2551:0:-:0;;;;;;;;;;;;;;;-1:-1:-1;;;73773:2551:0;;;;;;;;;;;;;;;;;","srcMapRuntime":"73773:2551:0:-:0;;;;;;;;","abiDefinition":[],"userDoc":{"kind":"user","methods":{},"version":1},"developerDoc":{"kind":"dev","methods":{},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[],\"devdoc\":{\"kind\":\"dev\",\"methods\":{},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeV2.sol\":\"UniversalTokenLib\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeV2.sol\":{\"keccak256\":\"0x5069b55ca07f21bfe30b2a43c18a18318c8af9c181b2dcb07c290825efd70f34\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://273dc020a49d08e50126bbea0d7f783f79d08c702f2fdbc560618d24af308acc\",\"dweb:/ipfs/QmXJ2UVzFc8EPB74RT4CXQPC4xw66jt4T13poyfyd3UERh\"]}},\"version\":1}"},"hashes":{}}} \ No newline at end of file diff --git a/services/rfq/contracts/testcontracts/fastbridgemockv2/fastbridgemockv2.abigen.go b/services/rfq/contracts/testcontracts/fastbridgemockv2/fastbridgemockv2.abigen.go index 31056fdacd..4b73303022 100644 --- a/services/rfq/contracts/testcontracts/fastbridgemockv2/fastbridgemockv2.abigen.go +++ b/services/rfq/contracts/testcontracts/fastbridgemockv2/fastbridgemockv2.abigen.go @@ -58,6 +58,12 @@ type IFastBridgeBridgeTransaction struct { Nonce *big.Int } +// IMulticallTargetResult is an auto generated low-level Go binding around an user-defined struct. +type IMulticallTargetResult struct { + Success bool + ReturnData []byte +} + // AccessControlMetaData contains all meta data concerning the AccessControl contract. var AccessControlMetaData = &bind.MetaData{ ABI: "[{\"inputs\":[],\"name\":\"AccessControlBadConfirmation\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"neededRole\",\"type\":\"bytes32\"}],\"name\":\"AccessControlUnauthorizedAccount\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"previousAdminRole\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"newAdminRole\",\"type\":\"bytes32\"}],\"name\":\"RoleAdminChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleGranted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleRevoked\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"DEFAULT_ADMIN_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"}],\"name\":\"getRoleAdmin\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"grantRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"hasRole\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"callerConfirmation\",\"type\":\"address\"}],\"name\":\"renounceRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"revokeRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes4\",\"name\":\"interfaceId\",\"type\":\"bytes4\"}],\"name\":\"supportsInterface\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"}]", @@ -1799,7 +1805,7 @@ func (_AccessControlEnumerable *AccessControlEnumerableFilterer) ParseRoleRevoke // AddressMetaData contains all meta data concerning the Address contract. var AddressMetaData = &bind.MetaData{ ABI: "[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"}],\"name\":\"AddressEmptyCode\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"AddressInsufficientBalance\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"FailedInnerCall\",\"type\":\"error\"}]", - Bin: "0x60566037600b82828239805160001a607314602a57634e487b7160e01b600052600060045260246000fd5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600080fdfea264697066735822122083549ae8a6625896ee7f9ad3afb09c83f8f6b7f2c10b67bf18def7b2b300f36a64736f6c63430008140033", + Bin: "0x60566037600b82828239805160001a607314602a57634e487b7160e01b600052600060045260246000fd5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600080fdfea2646970667358221220d19ff64d6e75d44d1945372c19c9bd8fcbe60ec22dd02143e88fdd9d7a948d3564736f6c63430008140033", } // AddressABI is the input ABI used to generate the binding from. @@ -1995,7 +2001,7 @@ var AdminMetaData = &bind.MetaData{ "01ffc9a7": "supportsInterface(bytes4)", "06f333f2": "sweepProtocolFees(address,address)", }, - Bin: "0x60806040523480156200001157600080fd5b50604051620014123803806200141283398101604081905262000034916200018e565b6200004160008262000049565b5050620001b9565b60008062000058848462000086565b905080156200007d5760008481526001602052604090206200007b908462000134565b505b90505b92915050565b6000828152602081815260408083206001600160a01b038516845290915281205460ff166200012b576000838152602081815260408083206001600160a01b03861684529091529020805460ff19166001179055620000e23390565b6001600160a01b0316826001600160a01b0316847f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a450600162000080565b50600062000080565b60006200007d836001600160a01b03841660008181526001830160205260408120546200012b5750815460018181018455600084815260208082209093018490558454848252828601909352604090209190915562000080565b600060208284031215620001a157600080fd5b81516001600160a01b03811681146200007d57600080fd5b61124980620001c96000396000f3fe608060405234801561001057600080fd5b50600436106101775760003560e01c806391d14854116100d8578063bf333f2c1161008c578063d547741f11610066578063d547741f14610385578063dcf844a714610398578063e00a83e0146103b857600080fd5b8063bf333f2c14610341578063ca15c8731461034b578063ccc574901461035e57600080fd5b8063a217fddf116100bd578063a217fddf14610313578063b13aa2d61461031b578063b250fe6b1461032e57600080fd5b806391d14854146102a8578063926d7d7f146102ec57600080fd5b80632f2ff15d1161012f57806358f858801161011457806358f85880146102405780635960ccf2146102495780639010d07c1461027057600080fd5b80632f2ff15d1461021a57806336568abe1461022d57600080fd5b806306f333f21161016057806306f333f2146101d95780630f5f6ed7146101ee578063248a9ca3146101f757600080fd5b806301ffc9a71461017c57806303ed0ee5146101a4575b600080fd5b61018f61018a366004611013565b6103c1565b60405190151581526020015b60405180910390f35b6101cb7f043c983c49d46f0e102151eaf8085d4a2e6571d5df2d47b013f39bddfd4a639d81565b60405190815260200161019b565b6101ec6101e736600461107e565b61041d565b005b6101cb61271081565b6101cb6102053660046110b1565b60009081526020819052604090206001015490565b6101ec6102283660046110ca565b61050b565b6101ec61023b3660046110ca565b610536565b6101cb60025481565b6101cb7fdb9556138406326f00296e13ea2ad7db24ba82381212d816b1a40c23b466b32781565b61028361027e3660046110ed565b61058f565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200161019b565b61018f6102b63660046110ca565b60009182526020828152604080842073ffffffffffffffffffffffffffffffffffffffff93909316845291905290205460ff1690565b6101cb7fe2b7fb3b832174769106daebcfd6d1970523240dda11281102db9363b83b0dc481565b6101cb600081565b6101ec6103293660046110b1565b6105ae565b6101ec61033c3660046110b1565b610690565b6101cb620f424081565b6101cb6103593660046110b1565b6106f8565b6101cb7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f5581565b6101ec6103933660046110ca565b61070f565b6101cb6103a636600461110f565b60036020526000908152604090205481565b6101cb60045481565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f5a05180f000000000000000000000000000000000000000000000000000000001480610417575061041782610734565b92915050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f55610447816107cb565b73ffffffffffffffffffffffffffffffffffffffff83166000908152600360205260408120549081900361047b5750505050565b73ffffffffffffffffffffffffffffffffffffffff84166000818152600360205260408120556104ac9084836107d8565b6040805173ffffffffffffffffffffffffffffffffffffffff8087168252851660208201529081018290527f244e51bc38c1452fa8aaf487bcb4bca36c2baa3a5fbdb776b1eabd8dc6d277cd9060600160405180910390a1505b505050565b600082815260208190526040902060010154610526816107cb565b610530838361092f565b50505050565b73ffffffffffffffffffffffffffffffffffffffff81163314610585576040517f6697b23200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6105068282610964565b60008281526001602052604081206105a79083610991565b9392505050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f556105d8816107cb565b612710821115610649576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f6e657746656552617465203e206d61780000000000000000000000000000000060448201526064015b60405180910390fd5b600280549083905560408051828152602081018590527f14914da2bf76024616fbe1859783fcd4dbddcb179b1f3a854949fbf920dcb95791015b60405180910390a1505050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f556106ba816107cb565b600480549083905560408051828152602081018590527f5cf09b12f3f56b4c564d51b25b40360af6d795198adb61ae0806a36c294323fa9101610683565b60008181526001602052604081206104179061099d565b60008281526020819052604090206001015461072a816107cb565b6105308383610964565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f7965db0b00000000000000000000000000000000000000000000000000000000148061041757507f01ffc9a7000000000000000000000000000000000000000000000000000000007fffffffff00000000000000000000000000000000000000000000000000000000831614610417565b6107d581336109a7565b50565b3073ffffffffffffffffffffffffffffffffffffffff8316036107fa57505050565b8060000361080757505050565b7fffffffffffffffffffffffff111111111111111111111111111111111111111273ffffffffffffffffffffffffffffffffffffffff84160161090e5760008273ffffffffffffffffffffffffffffffffffffffff168260405160006040518083038185875af1925050503d806000811461089e576040519150601f19603f3d011682016040523d82523d6000602084013e6108a3565b606091505b5050905080610530576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f455448207472616e73666572206661696c6564000000000000000000000000006044820152606401610640565b61050673ffffffffffffffffffffffffffffffffffffffff84168383610a31565b60008061093c8484610abe565b905080156105a757600084815260016020526040902061095c9084610bba565b509392505050565b6000806109718484610bdc565b905080156105a757600084815260016020526040902061095c9084610c97565b60006105a78383610cb9565b6000610417825490565b60008281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915290205460ff16610a2d576040517fe2517d3f00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8216600482015260248101839052604401610640565b5050565b6040805173ffffffffffffffffffffffffffffffffffffffff8416602482015260448082018490528251808303909101815260649091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fa9059cbb00000000000000000000000000000000000000000000000000000000179052610506908490610ce3565b60008281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915281205460ff16610bb25760008381526020818152604080832073ffffffffffffffffffffffffffffffffffffffff86168452909152902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055610b503390565b73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16847f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a4506001610417565b506000610417565b60006105a78373ffffffffffffffffffffffffffffffffffffffff8416610d79565b60008281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915281205460ff1615610bb25760008381526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8616808552925280832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016905551339286917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a4506001610417565b60006105a78373ffffffffffffffffffffffffffffffffffffffff8416610dc0565b6000826000018281548110610cd057610cd061112a565b9060005260206000200154905092915050565b6000610d0573ffffffffffffffffffffffffffffffffffffffff841683610eb3565b90508051600014158015610d2a575080806020019051810190610d289190611159565b155b15610506576040517f5274afe700000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff84166004820152602401610640565b6000818152600183016020526040812054610bb257508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155610417565b60008181526001830160205260408120548015610ea9576000610de460018361117b565b8554909150600090610df89060019061117b565b9050808214610e5d576000866000018281548110610e1857610e1861112a565b9060005260206000200154905080876000018481548110610e3b57610e3b61112a565b6000918252602080832090910192909255918252600188019052604090208390555b8554869080610e6e57610e6e6111b5565b600190038181906000526020600020016000905590558560010160008681526020019081526020016000206000905560019350505050610417565b6000915050610417565b60606105a783836000846000808573ffffffffffffffffffffffffffffffffffffffff168486604051610ee691906111e4565b60006040518083038185875af1925050503d8060008114610f23576040519150601f19603f3d011682016040523d82523d6000602084013e610f28565b606091505b5091509150610f38868383610f42565b9695505050505050565b606082610f5757610f5282610fd1565b6105a7565b8151158015610f7b575073ffffffffffffffffffffffffffffffffffffffff84163b155b15610fca576040517f9996b31500000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff85166004820152602401610640565b50806105a7565b805115610fe15780518082602001fd5b6040517f1425ea4200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006020828403121561102557600080fd5b81357fffffffff00000000000000000000000000000000000000000000000000000000811681146105a757600080fd5b803573ffffffffffffffffffffffffffffffffffffffff8116811461107957600080fd5b919050565b6000806040838503121561109157600080fd5b61109a83611055565b91506110a860208401611055565b90509250929050565b6000602082840312156110c357600080fd5b5035919050565b600080604083850312156110dd57600080fd5b823591506110a860208401611055565b6000806040838503121561110057600080fd5b50508035926020909101359150565b60006020828403121561112157600080fd5b6105a782611055565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60006020828403121561116b57600080fd5b815180151581146105a757600080fd5b81810381811115610417577f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fd5b6000825160005b8181101561120557602081860181015185830152016111eb565b50600092019182525091905056fea264697066735822122079131b92a1423b929ce85a16df536bfcfda7bffbb7079337b796201173ad4a2264736f6c63430008140033", + Bin: "0x60806040523480156200001157600080fd5b50604051620014123803806200141283398101604081905262000034916200018e565b6200004160008262000049565b5050620001b9565b60008062000058848462000086565b905080156200007d5760008481526001602052604090206200007b908462000134565b505b90505b92915050565b6000828152602081815260408083206001600160a01b038516845290915281205460ff166200012b576000838152602081815260408083206001600160a01b03861684529091529020805460ff19166001179055620000e23390565b6001600160a01b0316826001600160a01b0316847f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a450600162000080565b50600062000080565b60006200007d836001600160a01b03841660008181526001830160205260408120546200012b5750815460018181018455600084815260208082209093018490558454848252828601909352604090209190915562000080565b600060208284031215620001a157600080fd5b81516001600160a01b03811681146200007d57600080fd5b61124980620001c96000396000f3fe608060405234801561001057600080fd5b50600436106101775760003560e01c806391d14854116100d8578063bf333f2c1161008c578063d547741f11610066578063d547741f14610385578063dcf844a714610398578063e00a83e0146103b857600080fd5b8063bf333f2c14610341578063ca15c8731461034b578063ccc574901461035e57600080fd5b8063a217fddf116100bd578063a217fddf14610313578063b13aa2d61461031b578063b250fe6b1461032e57600080fd5b806391d14854146102a8578063926d7d7f146102ec57600080fd5b80632f2ff15d1161012f57806358f858801161011457806358f85880146102405780635960ccf2146102495780639010d07c1461027057600080fd5b80632f2ff15d1461021a57806336568abe1461022d57600080fd5b806306f333f21161016057806306f333f2146101d95780630f5f6ed7146101ee578063248a9ca3146101f757600080fd5b806301ffc9a71461017c57806303ed0ee5146101a4575b600080fd5b61018f61018a366004611013565b6103c1565b60405190151581526020015b60405180910390f35b6101cb7f043c983c49d46f0e102151eaf8085d4a2e6571d5df2d47b013f39bddfd4a639d81565b60405190815260200161019b565b6101ec6101e736600461107e565b61041d565b005b6101cb61271081565b6101cb6102053660046110b1565b60009081526020819052604090206001015490565b6101ec6102283660046110ca565b61050b565b6101ec61023b3660046110ca565b610536565b6101cb60025481565b6101cb7fdb9556138406326f00296e13ea2ad7db24ba82381212d816b1a40c23b466b32781565b61028361027e3660046110ed565b61058f565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200161019b565b61018f6102b63660046110ca565b60009182526020828152604080842073ffffffffffffffffffffffffffffffffffffffff93909316845291905290205460ff1690565b6101cb7fe2b7fb3b832174769106daebcfd6d1970523240dda11281102db9363b83b0dc481565b6101cb600081565b6101ec6103293660046110b1565b6105ae565b6101ec61033c3660046110b1565b610690565b6101cb620f424081565b6101cb6103593660046110b1565b6106f8565b6101cb7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f5581565b6101ec6103933660046110ca565b61070f565b6101cb6103a636600461110f565b60036020526000908152604090205481565b6101cb60045481565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f5a05180f000000000000000000000000000000000000000000000000000000001480610417575061041782610734565b92915050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f55610447816107cb565b73ffffffffffffffffffffffffffffffffffffffff83166000908152600360205260408120549081900361047b5750505050565b73ffffffffffffffffffffffffffffffffffffffff84166000818152600360205260408120556104ac9084836107d8565b6040805173ffffffffffffffffffffffffffffffffffffffff8087168252851660208201529081018290527f244e51bc38c1452fa8aaf487bcb4bca36c2baa3a5fbdb776b1eabd8dc6d277cd9060600160405180910390a1505b505050565b600082815260208190526040902060010154610526816107cb565b610530838361092f565b50505050565b73ffffffffffffffffffffffffffffffffffffffff81163314610585576040517f6697b23200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6105068282610964565b60008281526001602052604081206105a79083610991565b9392505050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f556105d8816107cb565b612710821115610649576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f6e657746656552617465203e206d61780000000000000000000000000000000060448201526064015b60405180910390fd5b600280549083905560408051828152602081018590527f14914da2bf76024616fbe1859783fcd4dbddcb179b1f3a854949fbf920dcb95791015b60405180910390a1505050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f556106ba816107cb565b600480549083905560408051828152602081018590527f5cf09b12f3f56b4c564d51b25b40360af6d795198adb61ae0806a36c294323fa9101610683565b60008181526001602052604081206104179061099d565b60008281526020819052604090206001015461072a816107cb565b6105308383610964565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f7965db0b00000000000000000000000000000000000000000000000000000000148061041757507f01ffc9a7000000000000000000000000000000000000000000000000000000007fffffffff00000000000000000000000000000000000000000000000000000000831614610417565b6107d581336109a7565b50565b3073ffffffffffffffffffffffffffffffffffffffff8316036107fa57505050565b8060000361080757505050565b7fffffffffffffffffffffffff111111111111111111111111111111111111111273ffffffffffffffffffffffffffffffffffffffff84160161090e5760008273ffffffffffffffffffffffffffffffffffffffff168260405160006040518083038185875af1925050503d806000811461089e576040519150601f19603f3d011682016040523d82523d6000602084013e6108a3565b606091505b5050905080610530576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f455448207472616e73666572206661696c6564000000000000000000000000006044820152606401610640565b61050673ffffffffffffffffffffffffffffffffffffffff84168383610a31565b60008061093c8484610abe565b905080156105a757600084815260016020526040902061095c9084610bba565b509392505050565b6000806109718484610bdc565b905080156105a757600084815260016020526040902061095c9084610c97565b60006105a78383610cb9565b6000610417825490565b60008281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915290205460ff16610a2d576040517fe2517d3f00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8216600482015260248101839052604401610640565b5050565b6040805173ffffffffffffffffffffffffffffffffffffffff8416602482015260448082018490528251808303909101815260649091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fa9059cbb00000000000000000000000000000000000000000000000000000000179052610506908490610ce3565b60008281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915281205460ff16610bb25760008381526020818152604080832073ffffffffffffffffffffffffffffffffffffffff86168452909152902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055610b503390565b73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16847f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a4506001610417565b506000610417565b60006105a78373ffffffffffffffffffffffffffffffffffffffff8416610d79565b60008281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915281205460ff1615610bb25760008381526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8616808552925280832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016905551339286917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a4506001610417565b60006105a78373ffffffffffffffffffffffffffffffffffffffff8416610dc0565b6000826000018281548110610cd057610cd061112a565b9060005260206000200154905092915050565b6000610d0573ffffffffffffffffffffffffffffffffffffffff841683610eb3565b90508051600014158015610d2a575080806020019051810190610d289190611159565b155b15610506576040517f5274afe700000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff84166004820152602401610640565b6000818152600183016020526040812054610bb257508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155610417565b60008181526001830160205260408120548015610ea9576000610de460018361117b565b8554909150600090610df89060019061117b565b9050808214610e5d576000866000018281548110610e1857610e1861112a565b9060005260206000200154905080876000018481548110610e3b57610e3b61112a565b6000918252602080832090910192909255918252600188019052604090208390555b8554869080610e6e57610e6e6111b5565b600190038181906000526020600020016000905590558560010160008681526020019081526020016000206000905560019350505050610417565b6000915050610417565b60606105a783836000846000808573ffffffffffffffffffffffffffffffffffffffff168486604051610ee691906111e4565b60006040518083038185875af1925050503d8060008114610f23576040519150601f19603f3d011682016040523d82523d6000602084013e610f28565b606091505b5091509150610f38868383610f42565b9695505050505050565b606082610f5757610f5282610fd1565b6105a7565b8151158015610f7b575073ffffffffffffffffffffffffffffffffffffffff84163b155b15610fca576040517f9996b31500000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff85166004820152602401610640565b50806105a7565b805115610fe15780518082602001fd5b6040517f1425ea4200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006020828403121561102557600080fd5b81357fffffffff00000000000000000000000000000000000000000000000000000000811681146105a757600080fd5b803573ffffffffffffffffffffffffffffffffffffffff8116811461107957600080fd5b919050565b6000806040838503121561109157600080fd5b61109a83611055565b91506110a860208401611055565b90509250929050565b6000602082840312156110c357600080fd5b5035919050565b600080604083850312156110dd57600080fd5b823591506110a860208401611055565b6000806040838503121561110057600080fd5b50508035926020909101359150565b60006020828403121561112157600080fd5b6105a782611055565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60006020828403121561116b57600080fd5b815180151581146105a757600080fd5b81810381811115610417577f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fd5b6000825160005b8181101561120557602081860181015185830152016111eb565b50600092019182525091905056fea26469706673582212208b32889d103161da471a6c3bbc957a6d1f6866bfcc129ed80af1c666033956c464736f6c63430008140033", } // AdminABI is the input ABI used to generate the binding from. @@ -3995,7 +4001,7 @@ func (_ERC165 *ERC165CallerSession) SupportsInterface(interfaceId [4]byte) (bool // EnumerableSetMetaData contains all meta data concerning the EnumerableSet contract. var EnumerableSetMetaData = &bind.MetaData{ ABI: "[]", - Bin: "0x60566037600b82828239805160001a607314602a57634e487b7160e01b600052600060045260246000fd5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600080fdfea264697066735822122061192eb5b75fa46e55c42a092ec06111165ec29e2ac6d00c6d247f0df8ba17fd64736f6c63430008140033", + Bin: "0x60566037600b82828239805160001a607314602a57634e487b7160e01b600052600060045260246000fd5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600080fdfea26469706673582212200a382fa821943728900498ca83a11a0bb08c358f5c346e82519f2d9e93b2c4cb64736f6c63430008140033", } // EnumerableSetABI is the input ABI used to generate the binding from. @@ -4167,7 +4173,7 @@ func (_EnumerableSet *EnumerableSetTransactorRaw) Transact(opts *bind.TransactOp // FastBridgeMetaData contains all meta data concerning the FastBridge contract. var FastBridgeMetaData = &bind.MetaData{ - ABI: "[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_owner\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"AccessControlBadConfirmation\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"neededRole\",\"type\":\"bytes32\"}],\"name\":\"AccessControlUnauthorizedAccount\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"}],\"name\":\"AddressEmptyCode\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"AddressInsufficientBalance\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"AmountIncorrect\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ChainIncorrect\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DeadlineExceeded\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DeadlineNotExceeded\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DeadlineTooShort\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DisputePeriodNotPassed\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DisputePeriodPassed\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"FailedInnerCall\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"MsgValueIncorrect\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"}],\"name\":\"SafeERC20FailedOperation\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"SenderIncorrect\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"StatusIncorrect\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"TokenNotContract\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"TransactionRelayed\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ZeroAddress\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"BridgeDepositClaimed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"BridgeDepositRefunded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"name\":\"BridgeProofDisputed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"transactionHash\",\"type\":\"bytes32\"}],\"name\":\"BridgeProofProvided\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"originChainId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"chainGasAmount\",\"type\":\"uint256\"}],\"name\":\"BridgeRelayed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"destChainId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"sendChainGas\",\"type\":\"bool\"}],\"name\":\"BridgeRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"oldChainGasAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newChainGasAmount\",\"type\":\"uint256\"}],\"name\":\"ChainGasAmountUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"oldFeeRate\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newFeeRate\",\"type\":\"uint256\"}],\"name\":\"FeeRateUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"FeesSwept\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"previousAdminRole\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"newAdminRole\",\"type\":\"bytes32\"}],\"name\":\"RoleAdminChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleGranted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleRevoked\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"DEFAULT_ADMIN_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"DISPUTE_PERIOD\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"FEE_BPS\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"FEE_RATE_MAX\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"GOVERNOR_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"GUARD_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"MIN_DEADLINE_PERIOD\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"REFUNDER_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"REFUND_DELAY\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"RELAYER_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"dstChainId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"sendChainGas\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"}],\"internalType\":\"structIFastBridge.BridgeParams\",\"name\":\"params\",\"type\":\"tuple\"}],\"name\":\"bridge\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"bridgeProofs\",\"outputs\":[{\"internalType\":\"uint96\",\"name\":\"timestamp\",\"type\":\"uint96\"},{\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"bridgeRelays\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"bridgeStatuses\",\"outputs\":[{\"internalType\":\"enumFastBridge.BridgeStatus\",\"name\":\"\",\"type\":\"uint8\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"name\":\"canClaim\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"chainGasAmount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"claim\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"deployBlock\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"}],\"name\":\"dispute\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"getBridgeTransaction\",\"outputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"originChainId\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"destChainId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"originSender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destRecipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"originFeeAmount\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"sendChainGas\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"}],\"internalType\":\"structIFastBridge.BridgeTransaction\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"}],\"name\":\"getRoleAdmin\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"index\",\"type\":\"uint256\"}],\"name\":\"getRoleMember\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"}],\"name\":\"getRoleMemberCount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"grantRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"hasRole\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"nonce\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"protocolFeeRate\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"protocolFees\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"},{\"internalType\":\"bytes32\",\"name\":\"destTxHash\",\"type\":\"bytes32\"}],\"name\":\"prove\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"refund\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"relay\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"callerConfirmation\",\"type\":\"address\"}],\"name\":\"renounceRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"revokeRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"newChainGasAmount\",\"type\":\"uint256\"}],\"name\":\"setChainGasAmount\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"newFeeRate\",\"type\":\"uint256\"}],\"name\":\"setProtocolFeeRate\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes4\",\"name\":\"interfaceId\",\"type\":\"bytes4\"}],\"name\":\"supportsInterface\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"}],\"name\":\"sweepProtocolFees\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", + ABI: "[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_owner\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"AccessControlBadConfirmation\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"neededRole\",\"type\":\"bytes32\"}],\"name\":\"AccessControlUnauthorizedAccount\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"}],\"name\":\"AddressEmptyCode\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"AddressInsufficientBalance\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"AmountIncorrect\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ChainIncorrect\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DeadlineExceeded\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DeadlineNotExceeded\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DeadlineTooShort\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DisputePeriodNotPassed\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DisputePeriodPassed\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"FailedInnerCall\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"MsgValueIncorrect\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"MulticallTarget__UndeterminedRevert\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"}],\"name\":\"SafeERC20FailedOperation\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"SenderIncorrect\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"StatusIncorrect\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"TokenNotContract\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"TransactionRelayed\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ZeroAddress\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"BridgeDepositClaimed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"BridgeDepositRefunded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"name\":\"BridgeProofDisputed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"transactionHash\",\"type\":\"bytes32\"}],\"name\":\"BridgeProofProvided\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"originChainId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"chainGasAmount\",\"type\":\"uint256\"}],\"name\":\"BridgeRelayed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"destChainId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"sendChainGas\",\"type\":\"bool\"}],\"name\":\"BridgeRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"oldChainGasAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newChainGasAmount\",\"type\":\"uint256\"}],\"name\":\"ChainGasAmountUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"oldFeeRate\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newFeeRate\",\"type\":\"uint256\"}],\"name\":\"FeeRateUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"FeesSwept\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"previousAdminRole\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"newAdminRole\",\"type\":\"bytes32\"}],\"name\":\"RoleAdminChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleGranted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleRevoked\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"DEFAULT_ADMIN_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"DISPUTE_PERIOD\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"FEE_BPS\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"FEE_RATE_MAX\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"GOVERNOR_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"GUARD_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"MIN_DEADLINE_PERIOD\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"REFUNDER_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"REFUND_DELAY\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"RELAYER_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"dstChainId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"sendChainGas\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"}],\"internalType\":\"structIFastBridge.BridgeParams\",\"name\":\"params\",\"type\":\"tuple\"}],\"name\":\"bridge\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"bridgeProofs\",\"outputs\":[{\"internalType\":\"uint96\",\"name\":\"timestamp\",\"type\":\"uint96\"},{\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"bridgeRelays\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"bridgeStatuses\",\"outputs\":[{\"internalType\":\"enumFastBridge.BridgeStatus\",\"name\":\"\",\"type\":\"uint8\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"name\":\"canClaim\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"chainGasAmount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"claim\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"deployBlock\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"}],\"name\":\"dispute\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"getBridgeTransaction\",\"outputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"originChainId\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"destChainId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"originSender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destRecipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"originFeeAmount\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"sendChainGas\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"}],\"internalType\":\"structIFastBridge.BridgeTransaction\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"}],\"name\":\"getRoleAdmin\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"index\",\"type\":\"uint256\"}],\"name\":\"getRoleMember\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"}],\"name\":\"getRoleMemberCount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"grantRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"hasRole\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes[]\",\"name\":\"data\",\"type\":\"bytes[]\"},{\"internalType\":\"bool\",\"name\":\"ignoreReverts\",\"type\":\"bool\"}],\"name\":\"multicallNoResults\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes[]\",\"name\":\"data\",\"type\":\"bytes[]\"},{\"internalType\":\"bool\",\"name\":\"ignoreReverts\",\"type\":\"bool\"}],\"name\":\"multicallWithResults\",\"outputs\":[{\"components\":[{\"internalType\":\"bool\",\"name\":\"success\",\"type\":\"bool\"},{\"internalType\":\"bytes\",\"name\":\"returnData\",\"type\":\"bytes\"}],\"internalType\":\"structIMulticallTarget.Result[]\",\"name\":\"results\",\"type\":\"tuple[]\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"nonce\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"protocolFeeRate\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"protocolFees\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"},{\"internalType\":\"bytes32\",\"name\":\"destTxHash\",\"type\":\"bytes32\"}],\"name\":\"prove\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"refund\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"relay\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"callerConfirmation\",\"type\":\"address\"}],\"name\":\"renounceRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"revokeRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"newChainGasAmount\",\"type\":\"uint256\"}],\"name\":\"setChainGasAmount\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"newFeeRate\",\"type\":\"uint256\"}],\"name\":\"setProtocolFeeRate\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes4\",\"name\":\"interfaceId\",\"type\":\"bytes4\"}],\"name\":\"supportsInterface\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"}],\"name\":\"sweepProtocolFees\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", Sigs: map[string]string{ "a217fddf": "DEFAULT_ADMIN_ROLE()", "a5bbe22b": "DISPUTE_PERIOD()", @@ -4194,6 +4200,8 @@ var FastBridgeMetaData = &bind.MetaData{ "ca15c873": "getRoleMemberCount(bytes32)", "2f2ff15d": "grantRole(bytes32,address)", "91d14854": "hasRole(bytes32,address)", + "3f61331d": "multicallNoResults(bytes[],bool)", + "385c1d2f": "multicallWithResults(bytes[],bool)", "affed0e0": "nonce()", "58f85880": "protocolFeeRate()", "dcf844a7": "protocolFees(address)", @@ -4207,7 +4215,7 @@ var FastBridgeMetaData = &bind.MetaData{ "01ffc9a7": "supportsInterface(bytes4)", "06f333f2": "sweepProtocolFees(address,address)", }, - Bin: "0x60a06040523480156200001157600080fd5b5060405162002d7a38038062002d7a833981016040819052620000349162000194565b80620000426000826200004f565b50504360805250620001bf565b6000806200005e84846200008c565b90508015620000835760008481526001602052604090206200008190846200013a565b505b90505b92915050565b6000828152602081815260408083206001600160a01b038516845290915281205460ff1662000131576000838152602081815260408083206001600160a01b03861684529091529020805460ff19166001179055620000e83390565b6001600160a01b0316826001600160a01b0316847f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a450600162000086565b50600062000086565b600062000083836001600160a01b0384166000818152600183016020526040812054620001315750815460018181018455600084815260208082209093018490558454848252828601909352604090209190915562000086565b600060208284031215620001a757600080fd5b81516001600160a01b03811681146200008357600080fd5b608051612b9f620001db60003960006106510152612b9f6000f3fe60806040526004361061026a5760003560e01c80639010d07c11610153578063add98c70116100cb578063ca15c8731161007f578063d547741f11610064578063d547741f146107a1578063dcf844a7146107c1578063e00a83e0146107ee57600080fd5b8063ca15c8731461074d578063ccc574901461076d57600080fd5b8063b13aa2d6116100b0578063b13aa2d6146106f6578063b250fe6b14610716578063bf333f2c1461073657600080fd5b8063add98c70146106c0578063affed0e0146106e057600080fd5b8063a217fddf11610122578063a5bbe22b11610107578063a5bbe22b1461047f578063aa9641ab14610673578063ac11fb1a1461069357600080fd5b8063a217fddf1461062a578063a3ec191a1461063f57600080fd5b80639010d07c146104f857806391ad50391461053057806391d14854146105b2578063926d7d7f146105f657600080fd5b806341fcb612116101e65780635eb7d946116101b55780638379a24f1161019a5780638379a24f14610495578063886d36ff146104c55780638f0d6f17146104e557600080fd5b80635eb7d9461461045f578063820688d51461047f57600080fd5b806341fcb612146103e2578063458516941461040257806358f85880146104155780635960ccf21461042b57600080fd5b80630f5f6ed71161023d578063248a9ca311610222578063248a9ca3146103725780632f2ff15d146103a257806336568abe146103c257600080fd5b80630f5f6ed714610345578063190da5951461035b57600080fd5b806301ffc9a71461026f57806303ed0ee5146102a4578063051287bc146102e657806306f333f214610323575b600080fd5b34801561027b57600080fd5b5061028f61028a3660046122fc565b610804565b60405190151581526020015b60405180910390f35b3480156102b057600080fd5b506102d87f043c983c49d46f0e102151eaf8085d4a2e6571d5df2d47b013f39bddfd4a639d81565b60405190815260200161029b565b3480156102f257600080fd5b5061031661030136600461233e565b60056020526000908152604090205460ff1681565b60405161029b9190612386565b34801561032f57600080fd5b5061034361033e3660046123ec565b610860565b005b34801561035157600080fd5b506102d861271081565b34801561036757600080fd5b506102d862093a8081565b34801561037e57600080fd5b506102d861038d36600461233e565b60009081526020819052604090206001015490565b3480156103ae57600080fd5b506103436103bd366004612425565b610927565b3480156103ce57600080fd5b506103436103dd366004612425565b610952565b3480156103ee57600080fd5b506103436103fd366004612572565b61099e565b6103436104103660046125ef565b610bd7565b34801561042157600080fd5b506102d860025481565b34801561043757600080fd5b506102d87fdb9556138406326f00296e13ea2ad7db24ba82381212d816b1a40c23b466b32781565b34801561046b57600080fd5b5061034361047a366004612692565b610ee5565b34801561048b57600080fd5b506102d861070881565b3480156104a157600080fd5b5061028f6104b036600461233e565b60076020526000908152604090205460ff1681565b3480156104d157600080fd5b506103436104e03660046126cf565b6110bd565b6103436104f3366004612692565b6111f0565b34801561050457600080fd5b50610518610513366004612714565b611437565b6040516001600160a01b03909116815260200161029b565b34801561053c57600080fd5b5061058661054b36600461233e565b6006602052600090815260409020546bffffffffffffffffffffffff8116906c0100000000000000000000000090046001600160a01b031682565b604080516bffffffffffffffffffffffff90931683526001600160a01b0390911660208301520161029b565b3480156105be57600080fd5b5061028f6105cd366004612425565b6000918252602082815260408084206001600160a01b0393909316845291905290205460ff1690565b34801561060257600080fd5b506102d87fe2b7fb3b832174769106daebcfd6d1970523240dda11281102db9363b83b0dc481565b34801561063657600080fd5b506102d8600081565b34801561064b57600080fd5b506102d87f000000000000000000000000000000000000000000000000000000000000000081565b34801561067f57600080fd5b5061028f61068e366004612425565b611456565b34801561069f57600080fd5b506106b36106ae366004612692565b611559565b60405161029b9190612736565b3480156106cc57600080fd5b506103436106db36600461233e565b6115cc565b3480156106ec57600080fd5b506102d860085481565b34801561070257600080fd5b5061034361071136600461233e565b611735565b34801561072257600080fd5b5061034361073136600461233e565b611817565b34801561074257600080fd5b506102d8620f424081565b34801561075957600080fd5b506102d861076836600461233e565b61187f565b34801561077957600080fd5b506102d87f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f5581565b3480156107ad57600080fd5b506103436107bc366004612425565b611896565b3480156107cd57600080fd5b506102d86107dc36600461281c565b60036020526000908152604090205481565b3480156107fa57600080fd5b506102d860045481565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f5a05180f00000000000000000000000000000000000000000000000000000000148061085a575061085a826118bb565b92915050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f5561088a81611952565b6001600160a01b038316600090815260036020526040812054908190036108b15750505050565b6001600160a01b0384166000818152600360205260408120556108d590848361195f565b604080516001600160a01b038087168252851660208201529081018290527f244e51bc38c1452fa8aaf487bcb4bca36c2baa3a5fbdb776b1eabd8dc6d277cd9060600160405180910390a1505b505050565b60008281526020819052604090206001015461094281611952565b61094c8383611a82565b50505050565b6001600160a01b0381163314610994576040517f6697b23200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6109228282611ab7565b7fe2b7fb3b832174769106daebcfd6d1970523240dda11281102db9363b83b0dc46109c881611952565b8251602084012060006109da85611559565b9050600260008381526005602052604090205460ff166004811115610a0157610a01612357565b14610a38576040517f4145817200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000828152600660209081526040918290208251808401909352546bffffffffffffffffffffffff811683526c0100000000000000000000000090046001600160a01b03169082018190523314610abb576040517f4af43a9000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80516107089042036bffffffffffffffffffffffff1611610b08576040517f1992d0bd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000838152600560205260409020805460ff1916600317905561010082015115610b645761010082015160808301516001600160a01b031660009081526003602052604081208054909190610b5e908490612868565b90915550505b608082015160c0830151610b826001600160a01b038316888361195f565b604080516001600160a01b03848116825260208201849052891691339188917f582211c35a2139ac3bbaac74663c6a1f56c6cbb658b41fe11fd45a82074ac67891015b60405180910390a45050505050505050565b46816000015163ffffffff1603610c1a576040517f7029fdf900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60a08101511580610c2d575060c0810151155b15610c64576040517fe38820c800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60608101516001600160a01b03161580610c89575060808101516001600160a01b0316155b15610cc0576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610ccc61070842612868565b8161010001511015610d0a576040517f04b7fcc800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000610d1f3083606001518460a00151611ae4565b90506000806002541115610d4c57620f424060025483610d3f919061287b565b610d499190612892565b90505b610d5681836128cd565b915060006040518061018001604052804663ffffffff168152602001856000015163ffffffff16815260200185602001516001600160a01b0316815260200185604001516001600160a01b0316815260200185606001516001600160a01b0316815260200185608001516001600160a01b031681526020018481526020018560c0015181526020018381526020018560e0015115158152602001856101000151815260200160086000815480929190610e0e906128e0565b909155509052604051610e249190602001612736565b604080518083037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0018152828252805160208083019190912060008181526005835293909320805460ff191660011790558701518751606089015160808a015160c08b015160e08c015195985095966001600160a01b039094169587957f120ea0364f36cdac7983bcfdd55270ca09d7f9b314a2ebc425a3b01ab1d6403a95610ed6958b959094909390928e9261293c565b60405180910390a35050505050565b805160208201206000610ef783611559565b3360009081527fd2043bf65931af3dbecf60d0db8f40e4160406d7beb00522f4200cf4944a1eb8602052604090205490915060ff1615610f74578061014001514211610f6f576040517fe15ff9ea00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610fc0565b62093a80816101400151610f889190612868565b4211610fc0576040517fe15ff9ea00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600160008381526005602052604090205460ff166004811115610fe557610fe5612357565b1461101c576040517f4145817200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600082815260056020526040808220805460ff19166004179055820151608083015161010084015160c0850151929391926110579190612868565b905061106d6001600160a01b038316848361195f565b604080516001600160a01b0384811682526020820184905285169187917fb4c55c0c9bc613519b920e88748090150b890a875d307f21bea7d4fb2e8bc958910160405180910390a3505050505050565b7fe2b7fb3b832174769106daebcfd6d1970523240dda11281102db9363b83b0dc46110e781611952565b82516020840120600160008281526005602052604090205460ff16600481111561111357611113612357565b1461114a576040517f4145817200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008181526005602090815260408083208054600260ff19909116179055805180820182526bffffffffffffffffffffffff4281168252338285018181528787526006865295849020925195516001600160a01b03166c0100000000000000000000000002959091169490941790555185815283917f4ac8af8a2cd87193d64dfc7a3b8d9923b714ec528b18725d080aa1299be0c5e4910160405180910390a350505050565b7fe2b7fb3b832174769106daebcfd6d1970523240dda11281102db9363b83b0dc461121a81611952565b81516020830120600061122c84611559565b90504663ffffffff16816020015163ffffffff1614611277576040517f7029fdf900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8061014001514211156112b6576040517f559895a300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008281526007602052604090205460ff16156112ff576040517fbef7bb7d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000828152600760205260409020805460ff19166001179055606081015160a082015160e083015160045461012085015161134857506000611342848484611ae4565b506113b9565b7fffffffffffffffffffffffff11111111111111111111111111111111111111126001600160a01b0384160161138c5761134284846113878486612868565b611ae4565b611397848484611ae4565b506113b78473eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee83611ae4565b505b845160808087015160a08089015160c0808b015160e08c01516040805163ffffffff90991689526001600160a01b0396871660208a0152938616938801939093526060870152938501528301849052861691339189917ff8ae392d784b1ea5e8881bfa586d81abf07ef4f1e2fc75f7fe51c90f05199a5c9101610bc5565b600082815260016020526040812061144f9083611cb3565b9392505050565b6000600260008481526005602052604090205460ff16600481111561147d5761147d612357565b146114b4576040517f4145817200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000838152600660209081526040918290208251808401909352546bffffffffffffffffffffffff811683526001600160a01b036c01000000000000000000000000909104811691830182905284161461153a576040517f4af43a9000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80516107089042036bffffffffffffffffffffffff1611949350505050565b604080516101808101825260008082526020808301829052928201819052606082018190526080820181905260a0820181905260c0820181905260e082018190526101008201819052610120820181905261014082018190526101608201528251909161085a91840181019084016129ed565b7f043c983c49d46f0e102151eaf8085d4a2e6571d5df2d47b013f39bddfd4a639d6115f681611952565b600260008381526005602052604090205460ff16600481111561161b5761161b612357565b14611652576040517f4145817200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000828152600660209081526040918290208251808401909352546bffffffffffffffffffffffff8082168085526c010000000000000000000000009092046001600160a01b031693909201929092526107089142031611156116e1576040517f3e908aac00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000828152600560209081526040808320805460ff19166001179055600690915280822082905551339184917f0695cf1d39b3055dcd0fe02d8b47eaf0d5a13e1996de925de59d0ef9b7f7fad49190a35050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f5561175f81611952565b6127108211156117d0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f6e657746656552617465203e206d61780000000000000000000000000000000060448201526064015b60405180910390fd5b600280549083905560408051828152602081018590527f14914da2bf76024616fbe1859783fcd4dbddcb179b1f3a854949fbf920dcb95791015b60405180910390a1505050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f5561184181611952565b600480549083905560408051828152602081018590527f5cf09b12f3f56b4c564d51b25b40360af6d795198adb61ae0806a36c294323fa910161180a565b600081815260016020526040812061085a90611cbf565b6000828152602081905260409020600101546118b181611952565b61094c8383611ab7565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f7965db0b00000000000000000000000000000000000000000000000000000000148061085a57507f01ffc9a7000000000000000000000000000000000000000000000000000000007fffffffff0000000000000000000000000000000000000000000000000000000083161461085a565b61195c8133611cc9565b50565b306001600160a01b0383160361197457505050565b8060000361198157505050565b7fffffffffffffffffffffffff11111111111111111111111111111111111111126001600160a01b03841601611a6e576000826001600160a01b03168260405160006040518083038185875af1925050503d80600081146119fe576040519150601f19603f3d011682016040523d82523d6000602084013e611a03565b606091505b505090508061094c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f455448207472616e73666572206661696c65640000000000000000000000000060448201526064016117c7565b6109226001600160a01b0384168383611d39565b600080611a8f8484611dad565b9050801561144f576000848152600160205260409020611aaf9084611e57565b509392505050565b600080611ac48484611e6c565b9050801561144f576000848152600160205260409020611aaf9084611eef565b60006001600160a01b03831673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee14611c4d57611b1c836001600160a01b0316611f04565b6040517f70a082310000000000000000000000000000000000000000000000000000000081526001600160a01b0385811660048301528416906370a0823190602401602060405180830381865afa158015611b7b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b9f9190612ab9565b9050611bb66001600160a01b038416338685611faa565b6040517f70a082310000000000000000000000000000000000000000000000000000000081526001600160a01b0385811660048301528291908516906370a0823190602401602060405180830381865afa158015611c18573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c3c9190612ab9565b611c4691906128cd565b905061144f565b348214611c86576040517f81de0bf300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600160a01b0384163014611caa57611caa6001600160a01b038416858461195f565b50349392505050565b600061144f8383611fe3565b600061085a825490565b6000828152602081815260408083206001600160a01b038516845290915290205460ff16611d35576040517fe2517d3f0000000000000000000000000000000000000000000000000000000081526001600160a01b0382166004820152602481018390526044016117c7565b5050565b6040516001600160a01b0383811660248301526044820183905261092291859182169063a9059cbb906064015b604051602081830303815290604052915060e01b6020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff838183161783525050505061200d565b6000828152602081815260408083206001600160a01b038516845290915281205460ff16611e4f576000838152602081815260408083206001600160a01b03861684529091529020805460ff19166001179055611e073390565b6001600160a01b0316826001600160a01b0316847f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a450600161085a565b50600061085a565b600061144f836001600160a01b038416612089565b6000828152602081815260408083206001600160a01b038516845290915281205460ff1615611e4f576000838152602081815260408083206001600160a01b0386168085529252808320805460ff1916905551339286917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a450600161085a565b600061144f836001600160a01b0384166120d0565b7fffffffffffffffffffffffff11111111111111111111111111111111111111126001600160a01b03821601611f66576040517f7f523fe800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b806001600160a01b03163b60000361195c576040517f7f523fe800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040516001600160a01b03848116602483015283811660448301526064820183905261094c9186918216906323b872dd90608401611d66565b6000826000018281548110611ffa57611ffa612ad2565b9060005260206000200154905092915050565b60006120226001600160a01b038416836121c3565b905080516000141580156120475750808060200190518101906120459190612b01565b155b15610922576040517f5274afe70000000000000000000000000000000000000000000000000000000081526001600160a01b03841660048201526024016117c7565b6000818152600183016020526040812054611e4f5750815460018181018455600084815260208082209093018490558454848252828601909352604090209190915561085a565b600081815260018301602052604081205480156121b95760006120f46001836128cd565b8554909150600090612108906001906128cd565b905080821461216d57600086600001828154811061212857612128612ad2565b906000526020600020015490508087600001848154811061214b5761214b612ad2565b6000918252602080832090910192909255918252600188019052604090208390555b855486908061217e5761217e612b1e565b60019003818190600052602060002001600090559055856001016000868152602001908152602001600020600090556001935050505061085a565b600091505061085a565b606061144f8383600084600080856001600160a01b031684866040516121e99190612b4d565b60006040518083038185875af1925050503d8060008114612226576040519150601f19603f3d011682016040523d82523d6000602084013e61222b565b606091505b509150915061223b868383612245565b9695505050505050565b60608261225a57612255826122ba565b61144f565b815115801561227157506001600160a01b0384163b155b156122b3576040517f9996b3150000000000000000000000000000000000000000000000000000000081526001600160a01b03851660048201526024016117c7565b508061144f565b8051156122ca5780518082602001fd5b6040517f1425ea4200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006020828403121561230e57600080fd5b81357fffffffff000000000000000000000000000000000000000000000000000000008116811461144f57600080fd5b60006020828403121561235057600080fd5b5035919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b60208101600583106123c1577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b91905290565b6001600160a01b038116811461195c57600080fd5b80356123e7816123c7565b919050565b600080604083850312156123ff57600080fd5b823561240a816123c7565b9150602083013561241a816123c7565b809150509250929050565b6000806040838503121561243857600080fd5b82359150602083013561241a816123c7565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051610120810167ffffffffffffffff8111828210171561249d5761249d61244a565b60405290565b604051610180810167ffffffffffffffff8111828210171561249d5761249d61244a565b600082601f8301126124d857600080fd5b813567ffffffffffffffff808211156124f3576124f361244a565b604051601f83017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f011681019082821181831017156125395761253961244a565b8160405283815286602085880101111561255257600080fd5b836020870160208301376000602085830101528094505050505092915050565b6000806040838503121561258557600080fd5b823567ffffffffffffffff81111561259c57600080fd5b6125a8858286016124c7565b925050602083013561241a816123c7565b63ffffffff8116811461195c57600080fd5b80356123e7816125b9565b801515811461195c57600080fd5b80356123e7816125d6565b6000610120828403121561260257600080fd5b61260a612479565b612613836125cb565b8152612621602084016123dc565b6020820152612632604084016123dc565b6040820152612643606084016123dc565b6060820152612654608084016123dc565b608082015260a083013560a082015260c083013560c082015261267960e084016125e4565b60e0820152610100928301359281019290925250919050565b6000602082840312156126a457600080fd5b813567ffffffffffffffff8111156126bb57600080fd5b6126c7848285016124c7565b949350505050565b600080604083850312156126e257600080fd5b823567ffffffffffffffff8111156126f957600080fd5b612705858286016124c7565b95602094909401359450505050565b6000806040838503121561272757600080fd5b50508035926020909101359150565b815163ffffffff1681526101808101602083015161275c602084018263ffffffff169052565b50604083015161277760408401826001600160a01b03169052565b50606083015161279260608401826001600160a01b03169052565b5060808301516127ad60808401826001600160a01b03169052565b5060a08301516127c860a08401826001600160a01b03169052565b5060c083015160c083015260e083015160e0830152610100808401518184015250610120808401516127fd8285018215159052565b5050610140838101519083015261016092830151929091019190915290565b60006020828403121561282e57600080fd5b813561144f816123c7565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b8082018082111561085a5761085a612839565b808202811582820484141761085a5761085a612839565b6000826128c8577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b8181038181111561085a5761085a612839565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820361291157612911612839565b5060010190565b60005b8381101561293357818101518382015260200161291b565b50506000910152565b60e08152600088518060e084015261010061295d8282860160208e01612918565b63ffffffff9990991660208401526001600160a01b039788166040840152959096166060820152608081019390935260a0830191909152151560c0820152601f9091017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0160190910192915050565b80516123e7816125b9565b80516123e7816123c7565b80516123e7816125d6565b60006101808284031215612a0057600080fd5b612a086124a3565b612a11836129cc565b8152612a1f602084016129cc565b6020820152612a30604084016129d7565b6040820152612a41606084016129d7565b6060820152612a52608084016129d7565b6080820152612a6360a084016129d7565b60a082015260c083015160c082015260e083015160e0820152610100808401518183015250610120612a968185016129e2565b908201526101408381015190820152610160928301519281019290925250919050565b600060208284031215612acb57600080fd5b5051919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b600060208284031215612b1357600080fd5b815161144f816125d6565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fd5b60008251612b5f818460208701612918565b919091019291505056fea26469706673582212202ed7e54598f559f515fc7a3d92c2ad3ddbadbeb6d23e4975b013050318c9925564736f6c63430008140033", + Bin: "0x60a06040523480156200001157600080fd5b506040516200322638038062003226833981016040819052620000349162000194565b80620000426000826200004f565b50504360805250620001bf565b6000806200005e84846200008c565b90508015620000835760008481526001602052604090206200008190846200013a565b505b90505b92915050565b6000828152602081815260408083206001600160a01b038516845290915281205460ff1662000131576000838152602081815260408083206001600160a01b03861684529091529020805460ff19166001179055620000e83390565b6001600160a01b0316826001600160a01b0316847f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a450600162000086565b50600062000086565b600062000083836001600160a01b0384166000818152600183016020526040812054620001315750815460018181018455600084815260208082209093018490558454848252828601909352604090209190915562000086565b600060208284031215620001a757600080fd5b81516001600160a01b03811681146200008357600080fd5b60805161304b620001db60003960006106d4015261304b6000f3fe6080604052600436106102a05760003560e01c80638f0d6f171161016e578063add98c70116100cb578063ca15c8731161007f578063d547741f11610064578063d547741f14610824578063dcf844a714610844578063e00a83e01461087157600080fd5b8063ca15c873146107d0578063ccc57490146107f057600080fd5b8063b13aa2d6116100b0578063b13aa2d614610779578063b250fe6b14610799578063bf333f2c146107b957600080fd5b8063add98c7014610743578063affed0e01461076357600080fd5b8063a217fddf11610122578063a5bbe22b11610107578063a5bbe22b14610502578063aa9641ab146106f6578063ac11fb1a1461071657600080fd5b8063a217fddf146106ad578063a3ec191a146106c257600080fd5b806391ad50391161015357806391ad5039146105b357806391d1485414610635578063926d7d7f1461067957600080fd5b80638f0d6f17146105685780639010d07c1461057b57600080fd5b8063385c1d2f1161021c5780635960ccf2116101d0578063820688d5116101b5578063820688d5146105025780638379a24f14610518578063886d36ff1461054857600080fd5b80635960ccf2146104ae5780635eb7d946146104e257600080fd5b806341fcb6121161020157806341fcb61214610465578063458516941461048557806358f858801461049857600080fd5b8063385c1d2f146104185780633f61331d1461044557600080fd5b80630f5f6ed711610273578063248a9ca311610258578063248a9ca3146103a85780632f2ff15d146103d857806336568abe146103f857600080fd5b80630f5f6ed71461037b578063190da5951461039157600080fd5b806301ffc9a7146102a557806303ed0ee5146102da578063051287bc1461031c57806306f333f214610359575b600080fd5b3480156102b157600080fd5b506102c56102c0366004612602565b610887565b60405190151581526020015b60405180910390f35b3480156102e657600080fd5b5061030e7f043c983c49d46f0e102151eaf8085d4a2e6571d5df2d47b013f39bddfd4a639d81565b6040519081526020016102d1565b34801561032857600080fd5b5061034c610337366004612644565b60056020526000908152604090205460ff1681565b6040516102d1919061268c565b34801561036557600080fd5b506103796103743660046126f2565b6108e3565b005b34801561038757600080fd5b5061030e61271081565b34801561039d57600080fd5b5061030e62093a8081565b3480156103b457600080fd5b5061030e6103c3366004612644565b60009081526020819052604090206001015490565b3480156103e457600080fd5b506103796103f336600461272b565b6109aa565b34801561040457600080fd5b5061037961041336600461272b565b6109d5565b34801561042457600080fd5b50610438610433366004612769565b610a21565b6040516102d1919061285d565b34801561045157600080fd5b50610379610460366004612769565b610bb7565b34801561047157600080fd5b50610379610480366004612a19565b610c6a565b610379610493366004612a7d565b610ea3565b3480156104a457600080fd5b5061030e60025481565b3480156104ba57600080fd5b5061030e7fdb9556138406326f00296e13ea2ad7db24ba82381212d816b1a40c23b466b32781565b3480156104ee57600080fd5b506103796104fd366004612b20565b6111b1565b34801561050e57600080fd5b5061030e61070881565b34801561052457600080fd5b506102c5610533366004612644565b60076020526000908152604090205460ff1681565b34801561055457600080fd5b50610379610563366004612b5d565b611389565b610379610576366004612b20565b6114bc565b34801561058757600080fd5b5061059b610596366004612ba2565b611703565b6040516001600160a01b0390911681526020016102d1565b3480156105bf57600080fd5b506106096105ce366004612644565b6006602052600090815260409020546bffffffffffffffffffffffff8116906c0100000000000000000000000090046001600160a01b031682565b604080516bffffffffffffffffffffffff90931683526001600160a01b039091166020830152016102d1565b34801561064157600080fd5b506102c561065036600461272b565b6000918252602082815260408084206001600160a01b0393909316845291905290205460ff1690565b34801561068557600080fd5b5061030e7fe2b7fb3b832174769106daebcfd6d1970523240dda11281102db9363b83b0dc481565b3480156106b957600080fd5b5061030e600081565b3480156106ce57600080fd5b5061030e7f000000000000000000000000000000000000000000000000000000000000000081565b34801561070257600080fd5b506102c561071136600461272b565b611722565b34801561072257600080fd5b50610736610731366004612b20565b611825565b6040516102d19190612bc4565b34801561074f57600080fd5b5061037961075e366004612644565b611898565b34801561076f57600080fd5b5061030e60085481565b34801561078557600080fd5b50610379610794366004612644565b611a01565b3480156107a557600080fd5b506103796107b4366004612644565b611ae3565b3480156107c557600080fd5b5061030e620f424081565b3480156107dc57600080fd5b5061030e6107eb366004612644565b611b4b565b3480156107fc57600080fd5b5061030e7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f5581565b34801561083057600080fd5b5061037961083f36600461272b565b611b62565b34801561085057600080fd5b5061030e61085f366004612caa565b60036020526000908152604090205481565b34801561087d57600080fd5b5061030e60045481565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f5a05180f0000000000000000000000000000000000000000000000000000000014806108dd57506108dd82611b87565b92915050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f5561090d81611c1e565b6001600160a01b038316600090815260036020526040812054908190036109345750505050565b6001600160a01b038416600081815260036020526040812055610958908483611c2b565b604080516001600160a01b038087168252851660208201529081018290527f244e51bc38c1452fa8aaf487bcb4bca36c2baa3a5fbdb776b1eabd8dc6d277cd9060600160405180910390a1505b505050565b6000828152602081905260409020600101546109c581611c1e565b6109cf8383611d4e565b50505050565b6001600160a01b0381163314610a17576040517f6697b23200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6109a58282611d7b565b60608267ffffffffffffffff811115610a3c57610a3c6128f1565b604051908082528060200260200182016040528015610a8257816020015b604080518082019091526000815260606020820152815260200190600190039081610a5a5790505b50905060005b83811015610baf5730858583818110610aa357610aa3612cc7565b9050602002810190610ab59190612cf6565b604051610ac3929190612d62565b600060405180830381855af49150503d8060008114610afe576040519150601f19603f3d011682016040523d82523d6000602084013e610b03565b606091505b50838381518110610b1657610b16612cc7565b6020026020010151600001848481518110610b3357610b33612cc7565b602002602001015160200182905282151515158152505050818181518110610b5d57610b5d612cc7565b602002602001015160000151158015610b74575082155b15610b9f57610b9f828281518110610b8e57610b8e612cc7565b602002602001015160200151611da8565b610ba881612da1565b9050610a88565b509392505050565b60005b828110156109cf5760008030868685818110610bd857610bd8612cc7565b9050602002810190610bea9190612cf6565b604051610bf8929190612d62565b600060405180830381855af49150503d8060008114610c33576040519150601f19603f3d011682016040523d82523d6000602084013e610c38565b606091505b509150915081158015610c49575083155b15610c5757610c5781611da8565b505080610c6390612da1565b9050610bba565b7fe2b7fb3b832174769106daebcfd6d1970523240dda11281102db9363b83b0dc4610c9481611c1e565b825160208401206000610ca685611825565b9050600260008381526005602052604090205460ff166004811115610ccd57610ccd61265d565b14610d04576040517f4145817200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000828152600660209081526040918290208251808401909352546bffffffffffffffffffffffff811683526c0100000000000000000000000090046001600160a01b03169082018190523314610d87576040517f4af43a9000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80516107089042036bffffffffffffffffffffffff1611610dd4576040517f1992d0bd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000838152600560205260409020805460ff1916600317905561010082015115610e305761010082015160808301516001600160a01b031660009081526003602052604081208054909190610e2a908490612dd9565b90915550505b608082015160c0830151610e4e6001600160a01b0383168883611c2b565b604080516001600160a01b03848116825260208201849052891691339188917f582211c35a2139ac3bbaac74663c6a1f56c6cbb658b41fe11fd45a82074ac67891015b60405180910390a45050505050505050565b46816000015163ffffffff1603610ee6576040517f7029fdf900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60a08101511580610ef9575060c0810151155b15610f30576040517fe38820c800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60608101516001600160a01b03161580610f55575060808101516001600160a01b0316155b15610f8c576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610f9861070842612dd9565b8161010001511015610fd6576040517f04b7fcc800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000610feb3083606001518460a00151611dea565b9050600080600254111561101857620f42406002548361100b9190612dec565b6110159190612e03565b90505b6110228183612e3e565b915060006040518061018001604052804663ffffffff168152602001856000015163ffffffff16815260200185602001516001600160a01b0316815260200185604001516001600160a01b0316815260200185606001516001600160a01b0316815260200185608001516001600160a01b031681526020018481526020018560c0015181526020018381526020018560e00151151581526020018561010001518152602001600860008154809291906110da90612da1565b9091555090526040516110f09190602001612bc4565b604080518083037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0018152828252805160208083019190912060008181526005835293909320805460ff191660011790558701518751606089015160808a015160c08b015160e08c015195985095966001600160a01b039094169587957f120ea0364f36cdac7983bcfdd55270ca09d7f9b314a2ebc425a3b01ab1d6403a956111a2958b959094909390928e92612e51565b60405180910390a35050505050565b8051602082012060006111c383611825565b3360009081527fd2043bf65931af3dbecf60d0db8f40e4160406d7beb00522f4200cf4944a1eb8602052604090205490915060ff161561124057806101400151421161123b576040517fe15ff9ea00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61128c565b62093a808161014001516112549190612dd9565b421161128c576040517fe15ff9ea00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600160008381526005602052604090205460ff1660048111156112b1576112b161265d565b146112e8576040517f4145817200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600082815260056020526040808220805460ff19166004179055820151608083015161010084015160c0850151929391926113239190612dd9565b90506113396001600160a01b0383168483611c2b565b604080516001600160a01b0384811682526020820184905285169187917fb4c55c0c9bc613519b920e88748090150b890a875d307f21bea7d4fb2e8bc958910160405180910390a3505050505050565b7fe2b7fb3b832174769106daebcfd6d1970523240dda11281102db9363b83b0dc46113b381611c1e565b82516020840120600160008281526005602052604090205460ff1660048111156113df576113df61265d565b14611416576040517f4145817200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008181526005602090815260408083208054600260ff19909116179055805180820182526bffffffffffffffffffffffff4281168252338285018181528787526006865295849020925195516001600160a01b03166c0100000000000000000000000002959091169490941790555185815283917f4ac8af8a2cd87193d64dfc7a3b8d9923b714ec528b18725d080aa1299be0c5e4910160405180910390a350505050565b7fe2b7fb3b832174769106daebcfd6d1970523240dda11281102db9363b83b0dc46114e681611c1e565b8151602083012060006114f884611825565b90504663ffffffff16816020015163ffffffff1614611543576040517f7029fdf900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b806101400151421115611582576040517f559895a300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008281526007602052604090205460ff16156115cb576040517fbef7bb7d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000828152600760205260409020805460ff19166001179055606081015160a082015160e08301516004546101208501516116145750600061160e848484611dea565b50611685565b7fffffffffffffffffffffffff11111111111111111111111111111111111111126001600160a01b038416016116585761160e84846116538486612dd9565b611dea565b611663848484611dea565b506116838473eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee83611dea565b505b845160808087015160a08089015160c0808b015160e08c01516040805163ffffffff90991689526001600160a01b0396871660208a0152938616938801939093526060870152938501528301849052861691339189917ff8ae392d784b1ea5e8881bfa586d81abf07ef4f1e2fc75f7fe51c90f05199a5c9101610e91565b600082815260016020526040812061171b9083611fb9565b9392505050565b6000600260008481526005602052604090205460ff1660048111156117495761174961265d565b14611780576040517f4145817200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000838152600660209081526040918290208251808401909352546bffffffffffffffffffffffff811683526001600160a01b036c010000000000000000000000009091048116918301829052841614611806576040517f4af43a9000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80516107089042036bffffffffffffffffffffffff1611949350505050565b604080516101808101825260008082526020808301829052928201819052606082018190526080820181905260a0820181905260c0820181905260e08201819052610100820181905261012082018190526101408201819052610160820152825190916108dd9184018101908401612ec8565b7f043c983c49d46f0e102151eaf8085d4a2e6571d5df2d47b013f39bddfd4a639d6118c281611c1e565b600260008381526005602052604090205460ff1660048111156118e7576118e761265d565b1461191e576040517f4145817200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000828152600660209081526040918290208251808401909352546bffffffffffffffffffffffff8082168085526c010000000000000000000000009092046001600160a01b031693909201929092526107089142031611156119ad576040517f3e908aac00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000828152600560209081526040808320805460ff19166001179055600690915280822082905551339184917f0695cf1d39b3055dcd0fe02d8b47eaf0d5a13e1996de925de59d0ef9b7f7fad49190a35050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f55611a2b81611c1e565b612710821115611a9c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f6e657746656552617465203e206d61780000000000000000000000000000000060448201526064015b60405180910390fd5b600280549083905560408051828152602081018590527f14914da2bf76024616fbe1859783fcd4dbddcb179b1f3a854949fbf920dcb95791015b60405180910390a1505050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f55611b0d81611c1e565b600480549083905560408051828152602081018590527f5cf09b12f3f56b4c564d51b25b40360af6d795198adb61ae0806a36c294323fa9101611ad6565b60008181526001602052604081206108dd90611fc5565b600082815260208190526040902060010154611b7d81611c1e565b6109cf8383611d7b565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f7965db0b0000000000000000000000000000000000000000000000000000000014806108dd57507f01ffc9a7000000000000000000000000000000000000000000000000000000007fffffffff000000000000000000000000000000000000000000000000000000008316146108dd565b611c288133611fcf565b50565b306001600160a01b03831603611c4057505050565b80600003611c4d57505050565b7fffffffffffffffffffffffff11111111111111111111111111111111111111126001600160a01b03841601611d3a576000826001600160a01b03168260405160006040518083038185875af1925050503d8060008114611cca576040519150601f19603f3d011682016040523d82523d6000602084013e611ccf565b606091505b50509050806109cf576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f455448207472616e73666572206661696c6564000000000000000000000000006044820152606401611a93565b6109a56001600160a01b038416838361203f565b600080611d5b84846120b3565b9050801561171b576000848152600160205260409020610baf908461215d565b600080611d888484612172565b9050801561171b576000848152600160205260409020610baf90846121f5565b805115611db85780518082602001fd5b6040517f5ead5a9d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006001600160a01b03831673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee14611f5357611e22836001600160a01b031661220a565b6040517f70a082310000000000000000000000000000000000000000000000000000000081526001600160a01b0385811660048301528416906370a0823190602401602060405180830381865afa158015611e81573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ea59190612f94565b9050611ebc6001600160a01b0384163386856122b0565b6040517f70a082310000000000000000000000000000000000000000000000000000000081526001600160a01b0385811660048301528291908516906370a0823190602401602060405180830381865afa158015611f1e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f429190612f94565b611f4c9190612e3e565b905061171b565b348214611f8c576040517f81de0bf300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600160a01b0384163014611fb057611fb06001600160a01b0384168584611c2b565b50349392505050565b600061171b83836122e9565b60006108dd825490565b6000828152602081815260408083206001600160a01b038516845290915290205460ff1661203b576040517fe2517d3f0000000000000000000000000000000000000000000000000000000081526001600160a01b038216600482015260248101839052604401611a93565b5050565b6040516001600160a01b038381166024830152604482018390526109a591859182169063a9059cbb906064015b604051602081830303815290604052915060e01b6020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8381831617835250505050612313565b6000828152602081815260408083206001600160a01b038516845290915281205460ff16612155576000838152602081815260408083206001600160a01b03861684529091529020805460ff1916600117905561210d3390565b6001600160a01b0316826001600160a01b0316847f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45060016108dd565b5060006108dd565b600061171b836001600160a01b03841661238f565b6000828152602081815260408083206001600160a01b038516845290915281205460ff1615612155576000838152602081815260408083206001600160a01b0386168085529252808320805460ff1916905551339286917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a45060016108dd565b600061171b836001600160a01b0384166123d6565b7fffffffffffffffffffffffff11111111111111111111111111111111111111126001600160a01b0382160161226c576040517f7f523fe800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b806001600160a01b03163b600003611c28576040517f7f523fe800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040516001600160a01b0384811660248301528381166044830152606482018390526109cf9186918216906323b872dd9060840161206c565b600082600001828154811061230057612300612cc7565b9060005260206000200154905092915050565b60006123286001600160a01b038416836124c9565b9050805160001415801561234d57508080602001905181019061234b9190612fad565b155b156109a5576040517f5274afe70000000000000000000000000000000000000000000000000000000081526001600160a01b0384166004820152602401611a93565b6000818152600183016020526040812054612155575081546001818101845560008481526020808220909301849055845484825282860190935260409020919091556108dd565b600081815260018301602052604081205480156124bf5760006123fa600183612e3e565b855490915060009061240e90600190612e3e565b905080821461247357600086600001828154811061242e5761242e612cc7565b906000526020600020015490508087600001848154811061245157612451612cc7565b6000918252602080832090910192909255918252600188019052604090208390555b855486908061248457612484612fca565b6001900381819060005260206000200160009055905585600101600086815260200190815260200160002060009055600193505050506108dd565b60009150506108dd565b606061171b8383600084600080856001600160a01b031684866040516124ef9190612ff9565b60006040518083038185875af1925050503d806000811461252c576040519150601f19603f3d011682016040523d82523d6000602084013e612531565b606091505b509150915061254186838361254b565b9695505050505050565b6060826125605761255b826125c0565b61171b565b815115801561257757506001600160a01b0384163b155b156125b9576040517f9996b3150000000000000000000000000000000000000000000000000000000081526001600160a01b0385166004820152602401611a93565b508061171b565b8051156125d05780518082602001fd5b6040517f1425ea4200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006020828403121561261457600080fd5b81357fffffffff000000000000000000000000000000000000000000000000000000008116811461171b57600080fd5b60006020828403121561265657600080fd5b5035919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b60208101600583106126c7577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b91905290565b6001600160a01b0381168114611c2857600080fd5b80356126ed816126cd565b919050565b6000806040838503121561270557600080fd5b8235612710816126cd565b91506020830135612720816126cd565b809150509250929050565b6000806040838503121561273e57600080fd5b823591506020830135612720816126cd565b8015158114611c2857600080fd5b80356126ed81612750565b60008060006040848603121561277e57600080fd5b833567ffffffffffffffff8082111561279657600080fd5b818601915086601f8301126127aa57600080fd5b8135818111156127b957600080fd5b8760208260051b85010111156127ce57600080fd5b602092830195509350508401356127e481612750565b809150509250925092565b60005b8381101561280a5781810151838201526020016127f2565b50506000910152565b6000815180845261282b8160208601602086016127ef565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b60006020808301818452808551808352604092508286019150828160051b87010184880160005b838110156128e3578883037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc001855281518051151584528701518784018790526128d087850182612813565b9588019593505090860190600101612884565b509098975050505050505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051610120810167ffffffffffffffff81118282101715612944576129446128f1565b60405290565b604051610180810167ffffffffffffffff81118282101715612944576129446128f1565b600082601f83011261297f57600080fd5b813567ffffffffffffffff8082111561299a5761299a6128f1565b604051601f83017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f011681019082821181831017156129e0576129e06128f1565b816040528381528660208588010111156129f957600080fd5b836020870160208301376000602085830101528094505050505092915050565b60008060408385031215612a2c57600080fd5b823567ffffffffffffffff811115612a4357600080fd5b612a4f8582860161296e565b9250506020830135612720816126cd565b63ffffffff81168114611c2857600080fd5b80356126ed81612a60565b60006101208284031215612a9057600080fd5b612a98612920565b612aa183612a72565b8152612aaf602084016126e2565b6020820152612ac0604084016126e2565b6040820152612ad1606084016126e2565b6060820152612ae2608084016126e2565b608082015260a083013560a082015260c083013560c0820152612b0760e0840161275e565b60e0820152610100928301359281019290925250919050565b600060208284031215612b3257600080fd5b813567ffffffffffffffff811115612b4957600080fd5b612b558482850161296e565b949350505050565b60008060408385031215612b7057600080fd5b823567ffffffffffffffff811115612b8757600080fd5b612b938582860161296e565b95602094909401359450505050565b60008060408385031215612bb557600080fd5b50508035926020909101359150565b815163ffffffff16815261018081016020830151612bea602084018263ffffffff169052565b506040830151612c0560408401826001600160a01b03169052565b506060830151612c2060608401826001600160a01b03169052565b506080830151612c3b60808401826001600160a01b03169052565b5060a0830151612c5660a08401826001600160a01b03169052565b5060c083015160c083015260e083015160e083015261010080840151818401525061012080840151612c8b8285018215159052565b5050610140838101519083015261016092830151929091019190915290565b600060208284031215612cbc57600080fd5b813561171b816126cd565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112612d2b57600080fd5b83018035915067ffffffffffffffff821115612d4657600080fd5b602001915036819003821315612d5b57600080fd5b9250929050565b8183823760009101908152919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203612dd257612dd2612d72565b5060010190565b808201808211156108dd576108dd612d72565b80820281158282048414176108dd576108dd612d72565b600082612e39577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b818103818111156108dd576108dd612d72565b60e081526000612e6460e083018a612813565b63ffffffff989098166020830152506001600160a01b039586166040820152939094166060840152608083019190915260a082015290151560c090910152919050565b80516126ed81612a60565b80516126ed816126cd565b80516126ed81612750565b60006101808284031215612edb57600080fd5b612ee361294a565b612eec83612ea7565b8152612efa60208401612ea7565b6020820152612f0b60408401612eb2565b6040820152612f1c60608401612eb2565b6060820152612f2d60808401612eb2565b6080820152612f3e60a08401612eb2565b60a082015260c083015160c082015260e083015160e0820152610100808401518183015250610120612f71818501612ebd565b908201526101408381015190820152610160928301519281019290925250919050565b600060208284031215612fa657600080fd5b5051919050565b600060208284031215612fbf57600080fd5b815161171b81612750565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fd5b6000825161300b8184602087016127ef565b919091019291505056fea2646970667358221220a96fddf13970542174791dd58f2a7c0d8038c41139bc7a4cec0696cb1cda555864736f6c63430008140033", } // FastBridgeABI is the input ABI used to generate the binding from. @@ -5254,6 +5262,48 @@ func (_FastBridge *FastBridgeTransactorSession) GrantRole(role [32]byte, account return _FastBridge.Contract.GrantRole(&_FastBridge.TransactOpts, role, account) } +// MulticallNoResults is a paid mutator transaction binding the contract method 0x3f61331d. +// +// Solidity: function multicallNoResults(bytes[] data, bool ignoreReverts) returns() +func (_FastBridge *FastBridgeTransactor) MulticallNoResults(opts *bind.TransactOpts, data [][]byte, ignoreReverts bool) (*types.Transaction, error) { + return _FastBridge.contract.Transact(opts, "multicallNoResults", data, ignoreReverts) +} + +// MulticallNoResults is a paid mutator transaction binding the contract method 0x3f61331d. +// +// Solidity: function multicallNoResults(bytes[] data, bool ignoreReverts) returns() +func (_FastBridge *FastBridgeSession) MulticallNoResults(data [][]byte, ignoreReverts bool) (*types.Transaction, error) { + return _FastBridge.Contract.MulticallNoResults(&_FastBridge.TransactOpts, data, ignoreReverts) +} + +// MulticallNoResults is a paid mutator transaction binding the contract method 0x3f61331d. +// +// Solidity: function multicallNoResults(bytes[] data, bool ignoreReverts) returns() +func (_FastBridge *FastBridgeTransactorSession) MulticallNoResults(data [][]byte, ignoreReverts bool) (*types.Transaction, error) { + return _FastBridge.Contract.MulticallNoResults(&_FastBridge.TransactOpts, data, ignoreReverts) +} + +// MulticallWithResults is a paid mutator transaction binding the contract method 0x385c1d2f. +// +// Solidity: function multicallWithResults(bytes[] data, bool ignoreReverts) returns((bool,bytes)[] results) +func (_FastBridge *FastBridgeTransactor) MulticallWithResults(opts *bind.TransactOpts, data [][]byte, ignoreReverts bool) (*types.Transaction, error) { + return _FastBridge.contract.Transact(opts, "multicallWithResults", data, ignoreReverts) +} + +// MulticallWithResults is a paid mutator transaction binding the contract method 0x385c1d2f. +// +// Solidity: function multicallWithResults(bytes[] data, bool ignoreReverts) returns((bool,bytes)[] results) +func (_FastBridge *FastBridgeSession) MulticallWithResults(data [][]byte, ignoreReverts bool) (*types.Transaction, error) { + return _FastBridge.Contract.MulticallWithResults(&_FastBridge.TransactOpts, data, ignoreReverts) +} + +// MulticallWithResults is a paid mutator transaction binding the contract method 0x385c1d2f. +// +// Solidity: function multicallWithResults(bytes[] data, bool ignoreReverts) returns((bool,bytes)[] results) +func (_FastBridge *FastBridgeTransactorSession) MulticallWithResults(data [][]byte, ignoreReverts bool) (*types.Transaction, error) { + return _FastBridge.Contract.MulticallWithResults(&_FastBridge.TransactOpts, data, ignoreReverts) +} + // Prove is a paid mutator transaction binding the contract method 0x886d36ff. // // Solidity: function prove(bytes request, bytes32 destTxHash) returns() @@ -7270,7 +7320,7 @@ func (_FastBridge *FastBridgeFilterer) ParseRoleRevoked(log types.Log) (*FastBri // FastBridgeMockMetaData contains all meta data concerning the FastBridgeMock contract. var FastBridgeMockMetaData = &bind.MetaData{ - ABI: "[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_owner\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"AccessControlBadConfirmation\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"neededRole\",\"type\":\"bytes32\"}],\"name\":\"AccessControlUnauthorizedAccount\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"}],\"name\":\"AddressEmptyCode\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"AddressInsufficientBalance\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"FailedInnerCall\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"}],\"name\":\"SafeERC20FailedOperation\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"BridgeDepositClaimed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"BridgeDepositRefunded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"name\":\"BridgeProofDisputed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"transactionHash\",\"type\":\"bytes32\"}],\"name\":\"BridgeProofProvided\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"originChainId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"chainGasAmount\",\"type\":\"uint256\"}],\"name\":\"BridgeRelayed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"destChainId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"sendChainGas\",\"type\":\"bool\"}],\"name\":\"BridgeRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"oldChainGasAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newChainGasAmount\",\"type\":\"uint256\"}],\"name\":\"ChainGasAmountUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"oldFeeRate\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newFeeRate\",\"type\":\"uint256\"}],\"name\":\"FeeRateUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"FeesSwept\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"previousAdminRole\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"newAdminRole\",\"type\":\"bytes32\"}],\"name\":\"RoleAdminChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleGranted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleRevoked\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"DEFAULT_ADMIN_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"FEE_BPS\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"FEE_RATE_MAX\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"GOVERNOR_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"GUARD_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"REFUNDER_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"RELAYER_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"dstChainId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"sendChainGas\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"}],\"internalType\":\"structIFastBridge.BridgeParams\",\"name\":\"params\",\"type\":\"tuple\"}],\"name\":\"bridge\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionid\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"name\":\"canClaim\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"chainGasAmount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"claim\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"deployBlock\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"}],\"name\":\"dispute\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"getBridgeTransaction\",\"outputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"originChainId\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"destChainId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"originSender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destRecipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"originFeeAmount\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"sendChainGas\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"}],\"internalType\":\"structIFastBridge.BridgeTransaction\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"enumFastBridge.BridgeStatus\",\"name\":\"keyValue\",\"type\":\"uint8\"}],\"name\":\"getEnumKeyByValue\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"}],\"name\":\"getRoleAdmin\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"index\",\"type\":\"uint256\"}],\"name\":\"getRoleMember\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"}],\"name\":\"getRoleMemberCount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"grantRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"hasRole\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"uint32\",\"name\":\"originChainId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"chainGasAmount\",\"type\":\"uint256\"}],\"name\":\"mockBridgeRelayer\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"components\":[{\"internalType\":\"uint32\",\"name\":\"dstChainId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"sendChainGas\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"}],\"internalType\":\"structIFastBridge.BridgeParams\",\"name\":\"params\",\"type\":\"tuple\"}],\"name\":\"mockBridgeRequest\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"mockBridgeRequestRaw\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"nonce\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"protocolFeeRate\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"protocolFees\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"},{\"internalType\":\"bytes32\",\"name\":\"destTxHash\",\"type\":\"bytes32\"}],\"name\":\"prove\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"refund\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"relay\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"callerConfirmation\",\"type\":\"address\"}],\"name\":\"renounceRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"revokeRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"newChainGasAmount\",\"type\":\"uint256\"}],\"name\":\"setChainGasAmount\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"newFeeRate\",\"type\":\"uint256\"}],\"name\":\"setProtocolFeeRate\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes4\",\"name\":\"interfaceId\",\"type\":\"bytes4\"}],\"name\":\"supportsInterface\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"}],\"name\":\"sweepProtocolFees\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", + ABI: "[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_owner\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"AccessControlBadConfirmation\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"neededRole\",\"type\":\"bytes32\"}],\"name\":\"AccessControlUnauthorizedAccount\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"}],\"name\":\"AddressEmptyCode\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"AddressInsufficientBalance\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"FailedInnerCall\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"}],\"name\":\"SafeERC20FailedOperation\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"BridgeDepositClaimed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"BridgeDepositRefunded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"name\":\"BridgeProofDisputed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"transactionHash\",\"type\":\"bytes32\"}],\"name\":\"BridgeProofProvided\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"originChainId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"chainGasAmount\",\"type\":\"uint256\"}],\"name\":\"BridgeRelayed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"destChainId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"sendChainGas\",\"type\":\"bool\"}],\"name\":\"BridgeRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"oldChainGasAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newChainGasAmount\",\"type\":\"uint256\"}],\"name\":\"ChainGasAmountUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"oldFeeRate\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newFeeRate\",\"type\":\"uint256\"}],\"name\":\"FeeRateUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"FeesSwept\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"previousAdminRole\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"newAdminRole\",\"type\":\"bytes32\"}],\"name\":\"RoleAdminChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleGranted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleRevoked\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"DEFAULT_ADMIN_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"FEE_BPS\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"FEE_RATE_MAX\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"GOVERNOR_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"GUARD_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"REFUNDER_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"RELAYER_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"dstChainId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"sendChainGas\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"}],\"internalType\":\"structIFastBridge.BridgeParams\",\"name\":\"\",\"type\":\"tuple\"}],\"name\":\"bridge\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"canClaim\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"chainGasAmount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"claim\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"deployBlock\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"dispute\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"getBridgeTransaction\",\"outputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"originChainId\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"destChainId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"originSender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destRecipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"originFeeAmount\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"sendChainGas\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"}],\"internalType\":\"structIFastBridge.BridgeTransaction\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"enumFastBridge.BridgeStatus\",\"name\":\"keyValue\",\"type\":\"uint8\"}],\"name\":\"getEnumKeyByValue\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"}],\"name\":\"getRoleAdmin\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"index\",\"type\":\"uint256\"}],\"name\":\"getRoleMember\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"}],\"name\":\"getRoleMemberCount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"grantRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"hasRole\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"uint32\",\"name\":\"originChainId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"chainGasAmount\",\"type\":\"uint256\"}],\"name\":\"mockBridgeRelayer\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"components\":[{\"internalType\":\"uint32\",\"name\":\"dstChainId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"sendChainGas\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"}],\"internalType\":\"structIFastBridge.BridgeParams\",\"name\":\"params\",\"type\":\"tuple\"}],\"name\":\"mockBridgeRequest\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"mockBridgeRequestRaw\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"nonce\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"protocolFeeRate\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"protocolFees\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"},{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"prove\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"name\":\"refund\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"name\":\"relay\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"callerConfirmation\",\"type\":\"address\"}],\"name\":\"renounceRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"revokeRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"newChainGasAmount\",\"type\":\"uint256\"}],\"name\":\"setChainGasAmount\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"newFeeRate\",\"type\":\"uint256\"}],\"name\":\"setProtocolFeeRate\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes4\",\"name\":\"interfaceId\",\"type\":\"bytes4\"}],\"name\":\"supportsInterface\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"}],\"name\":\"sweepProtocolFees\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"testFastBridgeMock\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", Sigs: map[string]string{ "a217fddf": "DEFAULT_ADMIN_ROLE()", "bf333f2c": "FEE_BPS()", @@ -7307,8 +7357,9 @@ var FastBridgeMockMetaData = &bind.MetaData{ "b13aa2d6": "setProtocolFeeRate(uint256)", "01ffc9a7": "supportsInterface(bytes4)", "06f333f2": "sweepProtocolFees(address,address)", + "4774fa38": "testFastBridgeMock()", }, - Bin: "0x60a06040523480156200001157600080fd5b506040516200254e3803806200254e833981016040819052620000349162000194565b80620000426000826200004f565b50504360805250620001bf565b6000806200005e84846200008c565b90508015620000835760008481526001602052604090206200008190846200013a565b505b90505b92915050565b6000828152602081815260408083206001600160a01b038516845290915281205460ff1662000131576000838152602081815260408083206001600160a01b03861684529091529020805460ff19166001179055620000e83390565b6001600160a01b0316826001600160a01b0316847f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a450600162000086565b50600062000086565b600062000083836001600160a01b0384166000818152600183016020526040812054620001315750815460018181018455600084815260208082209093018490558454848252828601909352604090209190915562000086565b600060208284031215620001a757600080fd5b81516001600160a01b03811681146200008357600080fd5b608051612373620001db600039600061053201526123736000f3fe6080604052600436106102345760003560e01c8063926d7d7f11610138578063b13aa2d6116100b0578063ca15c8731161007f578063d547741f11610064578063d547741f146106dd578063dcf844a7146106fd578063e00a83e01461072a57600080fd5b8063ca15c87314610689578063ccc57490146106a957600080fd5b8063b13aa2d614610612578063b250fe6b14610632578063bf333f2c14610652578063c72870cc1461066957600080fd5b8063ac11fb1a11610107578063add98c70116100ec578063add98c70146105c1578063aedf009d146105dc578063affed0e0146105fc57600080fd5b8063ac11fb1a14610574578063acaebbf1146105a157600080fd5b8063926d7d7f146104d7578063a217fddf1461050b578063a3ec191a14610520578063aa9641ab1461055457600080fd5b806345851694116101cb57806385ad903d1161019a5780638f0d6f171161017f5780638f0d6f17146104335780639010d07c1461044157806391d148541461048657600080fd5b806385ad903d146103eb578063886d36ff1461041857600080fd5b8063458516941461037857806358f85880146103865780635960ccf21461039c5780635eb7d946146103d057600080fd5b8063248a9ca311610207578063248a9ca3146102e85780632f2ff15d1461031857806336568abe1461033857806341fcb6121461035857600080fd5b806301ffc9a71461023957806303ed0ee51461026e57806306f333f2146102b05780630f5f6ed7146102d2575b600080fd5b34801561024557600080fd5b5061025961025436600461195d565b610740565b60405190151581526020015b60405180910390f35b34801561027a57600080fd5b506102a27f043c983c49d46f0e102151eaf8085d4a2e6571d5df2d47b013f39bddfd4a639d81565b604051908152602001610265565b3480156102bc57600080fd5b506102d06102cb3660046119d1565b61079c565b005b3480156102de57600080fd5b506102a261271081565b3480156102f457600080fd5b506102a2610303366004611a0a565b60009081526020819052604090206001015490565b34801561032457600080fd5b506102d0610333366004611a23565b61088a565b34801561034457600080fd5b506102d0610353366004611a23565b6108b5565b34801561036457600080fd5b506102d0610373366004611b70565b61090e565b6102d0610373366004611c90565b34801561039257600080fd5b506102a260025481565b3480156103a857600080fd5b506102a27fdb9556138406326f00296e13ea2ad7db24ba82381212d816b1a40c23b466b32781565b3480156103dc57600080fd5b506102d0610373366004611cad565b3480156103f757600080fd5b5061040b610406366004611cea565b610975565b6040516102659190611d79565b34801561042457600080fd5b506102d0610373366004611d8c565b6102d0610373366004611cad565b34801561044d57600080fd5b5061046161045c366004611dd1565b610b25565b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610265565b34801561049257600080fd5b506102596104a1366004611a23565b60009182526020828152604080842073ffffffffffffffffffffffffffffffffffffffff93909316845291905290205460ff1690565b3480156104e357600080fd5b506102a27fe2b7fb3b832174769106daebcfd6d1970523240dda11281102db9363b83b0dc481565b34801561051757600080fd5b506102a2600081565b34801561052c57600080fd5b506102a27f000000000000000000000000000000000000000000000000000000000000000081565b34801561056057600080fd5b5061025961056f366004611a23565b610b44565b34801561058057600080fd5b5061059461058f366004611cad565b610ba9565b6040516102659190611df3565b3480156105ad57600080fd5b506102d06105bc366004611f0d565b610c1c565b3480156105cd57600080fd5b506102d0610373366004611a0a565b3480156105e857600080fd5b506102d06105f7366004611f4d565b610dec565b34801561060857600080fd5b506102a260055481565b34801561061e57600080fd5b506102d061062d366004611a0a565b610e77565b34801561063e57600080fd5b506102d061064d366004611a0a565b610f54565b34801561065e57600080fd5b506102a2620f424081565b34801561067557600080fd5b506102d0610684366004611fa6565b610fbc565b34801561069557600080fd5b506102a26106a4366004611a0a565b611042565b3480156106b557600080fd5b506102a27f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f5581565b3480156106e957600080fd5b506102d06106f8366004611a23565b611059565b34801561070957600080fd5b506102a261071836600461203e565b60036020526000908152604090205481565b34801561073657600080fd5b506102a260045481565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f5a05180f00000000000000000000000000000000000000000000000000000000148061079657506107968261107e565b92915050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f556107c681611115565b73ffffffffffffffffffffffffffffffffffffffff8316600090815260036020526040812054908190036107fa5750505050565b73ffffffffffffffffffffffffffffffffffffffff841660008181526003602052604081205561082b908483611122565b6040805173ffffffffffffffffffffffffffffffffffffffff8087168252851660208201529081018290527f244e51bc38c1452fa8aaf487bcb4bca36c2baa3a5fbdb776b1eabd8dc6d277cd9060600160405180910390a1505b505050565b6000828152602081905260409020600101546108a581611115565b6108af8383611279565b50505050565b73ffffffffffffffffffffffffffffffffffffffff81163314610904576040517f6697b23200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61088582826112ae565b6040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f6e6f7420696d706c656d656e746564000000000000000000000000000000000060448201526064015b60405180910390fd5b60608160048111156109895761098961205b565b6000036109c957505060408051808201909152600481527f4e554c4c00000000000000000000000000000000000000000000000000000000602082015290565b8160048111156109db576109db61205b565b600103610a1b57505060408051808201909152600981527f5245515545535445440000000000000000000000000000000000000000000000602082015290565b816004811115610a2d57610a2d61205b565b600203610a6d57505060408051808201909152600e81527f52454c415945525f50524f564544000000000000000000000000000000000000602082015290565b816004811115610a7f57610a7f61205b565b600303610abf57505060408051808201909152600f81527f52454c415945525f434c41494d45440000000000000000000000000000000000602082015290565b816004811115610ad157610ad161205b565b600403610b1157505060408051808201909152600881527f524546554e444544000000000000000000000000000000000000000000000000602082015290565b505060408051602081019091526000815290565b6000828152600160205260408120610b3d90836112db565b9392505050565b6040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f6e6f7420696d706c656d656e7465640000000000000000000000000000000000604482015260009060640161096c565b604080516101808101825260008082526020808301829052928201819052606082018190526080820181905260a0820181905260c0820181905260e082018190526101008201819052610120820181905261014082018190526101608201528251909161079691840181019084016120ab565b6000620f42406002548360a00151610c3491906121a6565b610c3e91906121bd565b9050808260a001818151610c5291906121f8565b9150818152505060006040518061018001604052804663ffffffff168152602001846000015163ffffffff168152602001846020015173ffffffffffffffffffffffffffffffffffffffff168152602001846040015173ffffffffffffffffffffffffffffffffffffffff168152602001846060015173ffffffffffffffffffffffffffffffffffffffff168152602001846080015173ffffffffffffffffffffffffffffffffffffffff1681526020018460a0015181526020018460c0015181526020018381526020018460e0015115158152602001846101000151815260200160056000815480929190610d479061220b565b909155509052604051610d5d9190602001611df3565b6040516020818303038152906040529050826020015173ffffffffffffffffffffffffffffffffffffffff16857f120ea0364f36cdac7983bcfdd55270ca09d7f9b314a2ebc425a3b01ab1d6403a838660000151876060015188608001518960a001518a60c001518b60e00151604051610ddd9796959493929190612243565b60405180910390a35050505050565b6000610df782610ba9565b9050806040015173ffffffffffffffffffffffffffffffffffffffff16847f120ea0364f36cdac7983bcfdd55270ca09d7f9b314a2ebc425a3b01ab1d6403a84846020015185608001518660a001518760c001518860e00151896101200151604051610e699796959493929190612243565b60405180910390a350505050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f55610ea181611115565b612710821115610f0d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f6e657746656552617465203e206d617800000000000000000000000000000000604482015260640161096c565b600280549083905560408051828152602081018590527f14914da2bf76024616fbe1859783fcd4dbddcb179b1f3a854949fbf920dcb95791015b60405180910390a1505050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f55610f7e81611115565b600480549083905560408051828152602081018590527f5cf09b12f3f56b4c564d51b25b40360af6d795198adb61ae0806a36c294323fa9101610f47565b6040805163ffffffff8816815273ffffffffffffffffffffffffffffffffffffffff878116602083015286811682840152606082018690526080820185905260a082018490529151898316928b16918c917ff8ae392d784b1ea5e8881bfa586d81abf07ef4f1e2fc75f7fe51c90f05199a5c9181900360c00190a4505050505050505050565b6000818152600160205260408120610796906112e7565b60008281526020819052604090206001015461107481611115565b6108af83836112ae565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f7965db0b00000000000000000000000000000000000000000000000000000000148061079657507f01ffc9a7000000000000000000000000000000000000000000000000000000007fffffffff00000000000000000000000000000000000000000000000000000000831614610796565b61111f81336112f1565b50565b3073ffffffffffffffffffffffffffffffffffffffff83160361114457505050565b8060000361115157505050565b7fffffffffffffffffffffffff111111111111111111111111111111111111111273ffffffffffffffffffffffffffffffffffffffff8416016112585760008273ffffffffffffffffffffffffffffffffffffffff168260405160006040518083038185875af1925050503d80600081146111e8576040519150601f19603f3d011682016040523d82523d6000602084013e6111ed565b606091505b50509050806108af576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f455448207472616e73666572206661696c656400000000000000000000000000604482015260640161096c565b61088573ffffffffffffffffffffffffffffffffffffffff8416838361137b565b6000806112868484611408565b90508015610b3d5760008481526001602052604090206112a69084611504565b509392505050565b6000806112bb8484611526565b90508015610b3d5760008481526001602052604090206112a690846115e1565b6000610b3d8383611603565b6000610796825490565b60008281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915290205460ff16611377576040517fe2517d3f00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff821660048201526024810183905260440161096c565b5050565b6040805173ffffffffffffffffffffffffffffffffffffffff8416602482015260448082018490528251808303909101815260649091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fa9059cbb0000000000000000000000000000000000000000000000000000000017905261088590849061162d565b60008281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915281205460ff166114fc5760008381526020818152604080832073ffffffffffffffffffffffffffffffffffffffff86168452909152902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016600117905561149a3390565b73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16847f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a4506001610796565b506000610796565b6000610b3d8373ffffffffffffffffffffffffffffffffffffffff84166116c3565b60008281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915281205460ff16156114fc5760008381526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8616808552925280832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016905551339286917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a4506001610796565b6000610b3d8373ffffffffffffffffffffffffffffffffffffffff841661170a565b600082600001828154811061161a5761161a6122a6565b9060005260206000200154905092915050565b600061164f73ffffffffffffffffffffffffffffffffffffffff8416836117fd565b9050805160001415801561167457508080602001905181019061167291906122d5565b155b15610885576040517f5274afe700000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8416600482015260240161096c565b60008181526001830160205260408120546114fc57508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155610796565b600081815260018301602052604081205480156117f357600061172e6001836121f8565b8554909150600090611742906001906121f8565b90508082146117a7576000866000018281548110611762576117626122a6565b9060005260206000200154905080876000018481548110611785576117856122a6565b6000918252602080832090910192909255918252600188019052604090208390555b85548690806117b8576117b86122f2565b600190038181906000526020600020016000905590558560010160008681526020019081526020016000206000905560019350505050610796565b6000915050610796565b6060610b3d83836000846000808573ffffffffffffffffffffffffffffffffffffffff1684866040516118309190612321565b60006040518083038185875af1925050503d806000811461186d576040519150601f19603f3d011682016040523d82523d6000602084013e611872565b606091505b509150915061188286838361188c565b9695505050505050565b6060826118a15761189c8261191b565b610b3d565b81511580156118c5575073ffffffffffffffffffffffffffffffffffffffff84163b155b15611914576040517f9996b31500000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8516600482015260240161096c565b5080610b3d565b80511561192b5780518082602001fd5b6040517f1425ea4200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006020828403121561196f57600080fd5b81357fffffffff0000000000000000000000000000000000000000000000000000000081168114610b3d57600080fd5b73ffffffffffffffffffffffffffffffffffffffff8116811461111f57600080fd5b80356119cc8161199f565b919050565b600080604083850312156119e457600080fd5b82356119ef8161199f565b915060208301356119ff8161199f565b809150509250929050565b600060208284031215611a1c57600080fd5b5035919050565b60008060408385031215611a3657600080fd5b8235915060208301356119ff8161199f565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051610120810167ffffffffffffffff81118282101715611a9b57611a9b611a48565b60405290565b604051610180810167ffffffffffffffff81118282101715611a9b57611a9b611a48565b600082601f830112611ad657600080fd5b813567ffffffffffffffff80821115611af157611af1611a48565b604051601f83017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f01168101908282118183101715611b3757611b37611a48565b81604052838152866020858801011115611b5057600080fd5b836020870160208301376000602085830101528094505050505092915050565b60008060408385031215611b8357600080fd5b823567ffffffffffffffff811115611b9a57600080fd5b611ba685828601611ac5565b92505060208301356119ff8161199f565b63ffffffff8116811461111f57600080fd5b80356119cc81611bb7565b801515811461111f57600080fd5b80356119cc81611bd4565b60006101208284031215611c0057600080fd5b611c08611a77565b9050611c1382611bc9565b8152611c21602083016119c1565b6020820152611c32604083016119c1565b6040820152611c43606083016119c1565b6060820152611c54608083016119c1565b608082015260a082013560a082015260c082013560c0820152611c7960e08301611be2565b60e082015261010080830135818301525092915050565b60006101208284031215611ca357600080fd5b610b3d8383611bed565b600060208284031215611cbf57600080fd5b813567ffffffffffffffff811115611cd657600080fd5b611ce284828501611ac5565b949350505050565b600060208284031215611cfc57600080fd5b813560058110610b3d57600080fd5b60005b83811015611d26578181015183820152602001611d0e565b50506000910152565b60008151808452611d47816020860160208601611d0b565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b602081526000610b3d6020830184611d2f565b60008060408385031215611d9f57600080fd5b823567ffffffffffffffff811115611db657600080fd5b611dc285828601611ac5565b95602094909401359450505050565b60008060408385031215611de457600080fd5b50508035926020909101359150565b815163ffffffff16815261018081016020830151611e19602084018263ffffffff169052565b506040830151611e41604084018273ffffffffffffffffffffffffffffffffffffffff169052565b506060830151611e69606084018273ffffffffffffffffffffffffffffffffffffffff169052565b506080830151611e91608084018273ffffffffffffffffffffffffffffffffffffffff169052565b5060a0830151611eb960a084018273ffffffffffffffffffffffffffffffffffffffff169052565b5060c083015160c083015260e083015160e083015261010080840151818401525061012080840151611eee8285018215159052565b5050610140838101519083015261016092830151929091019190915290565b60008060006101608486031215611f2357600080fd5b833592506020840135611f358161199f565b9150611f448560408601611bed565b90509250925092565b600080600060608486031215611f6257600080fd5b833592506020840135611f748161199f565b9150604084013567ffffffffffffffff811115611f9057600080fd5b611f9c86828701611ac5565b9150509250925092565b60008060008060008060008060006101208a8c031215611fc557600080fd5b8935985060208a0135611fd78161199f565b975060408a0135611fe78161199f565b965060608a0135611ff781611bb7565b955060808a01356120078161199f565b945060a08a01356120178161199f565b8094505060c08a0135925060e08a013591506101008a013590509295985092959850929598565b60006020828403121561205057600080fd5b8135610b3d8161199f565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b80516119cc81611bb7565b80516119cc8161199f565b80516119cc81611bd4565b600061018082840312156120be57600080fd5b6120c6611aa1565b6120cf8361208a565b81526120dd6020840161208a565b60208201526120ee60408401612095565b60408201526120ff60608401612095565b606082015261211060808401612095565b608082015261212160a08401612095565b60a082015260c083015160c082015260e083015160e08201526101008084015181830152506101206121548185016120a0565b908201526101408381015190820152610160928301519281019290925250919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b808202811582820484141761079657610796612177565b6000826121f3577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b8181038181111561079657610796612177565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820361223c5761223c612177565b5060010190565b60e08152600061225660e083018a611d2f565b63ffffffff9890981660208301525073ffffffffffffffffffffffffffffffffffffffff9586166040820152939094166060840152608083019190915260a082015290151560c090910152919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b6000602082840312156122e757600080fd5b8151610b3d81611bd4565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fd5b60008251612333818460208701611d0b565b919091019291505056fea2646970667358221220b683b83c62d39501bf0f8c7280114538e17cdaba91a577c85b1d7b2b6a51230c64736f6c63430008140033", + Bin: "0x60a06040523480156200001157600080fd5b506040516200257538038062002575833981016040819052620000349162000194565b80620000426000826200004f565b50504360805250620001bf565b6000806200005e84846200008c565b90508015620000835760008481526001602052604090206200008190846200013a565b505b90505b92915050565b6000828152602081815260408083206001600160a01b038516845290915281205460ff1662000131576000838152602081815260408083206001600160a01b03861684529091529020805460ff19166001179055620000e83390565b6001600160a01b0316826001600160a01b0316847f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a450600162000086565b50600062000086565b600062000083836001600160a01b0384166000818152600183016020526040812054620001315750815460018181018455600084815260208082209093018490558454848252828601909352604090209190915562000086565b600060208284031215620001a757600080fd5b81516001600160a01b03811681146200008357600080fd5b60805161239a620001db6000396000610559015261239a6000f3fe60806040526004361061024f5760003560e01c8063926d7d7f11610138578063b13aa2d6116100b0578063ca15c8731161007f578063d547741f11610064578063d547741f14610704578063dcf844a714610724578063e00a83e01461075157600080fd5b8063ca15c873146106b0578063ccc57490146106d057600080fd5b8063b13aa2d614610639578063b250fe6b14610659578063bf333f2c14610679578063c72870cc1461069057600080fd5b8063ac11fb1a11610107578063add98c70116100ec578063add98c70146105e8578063aedf009d14610603578063affed0e01461062357600080fd5b8063ac11fb1a1461059b578063acaebbf1146105c857600080fd5b8063926d7d7f146104fe578063a217fddf14610532578063a3ec191a14610547578063aa9641ab1461057b57600080fd5b80634774fa38116101cb57806385ad903d1161019a5780638f0d6f171161017f5780638f0d6f171461045a5780639010d07c1461046857806391d14854146104ad57600080fd5b806385ad903d14610412578063886d36ff1461043f57600080fd5b80634774fa38146103a157806358f85880146103ad5780635960ccf2146103c35780635eb7d946146103f757600080fd5b8063248a9ca31161022257806336568abe1161020757806336568abe1461035357806341fcb61214610373578063458516941461039357600080fd5b8063248a9ca3146103035780632f2ff15d1461033357600080fd5b806301ffc9a71461025457806303ed0ee51461028957806306f333f2146102cb5780630f5f6ed7146102ed575b600080fd5b34801561026057600080fd5b5061027461026f366004611984565b610767565b60405190151581526020015b60405180910390f35b34801561029557600080fd5b506102bd7f043c983c49d46f0e102151eaf8085d4a2e6571d5df2d47b013f39bddfd4a639d81565b604051908152602001610280565b3480156102d757600080fd5b506102eb6102e63660046119f8565b6107c3565b005b3480156102f957600080fd5b506102bd61271081565b34801561030f57600080fd5b506102bd61031e366004611a31565b60009081526020819052604090206001015490565b34801561033f57600080fd5b506102eb61034e366004611a4a565b6108b1565b34801561035f57600080fd5b506102eb61036e366004611a4a565b6108dc565b34801561037f57600080fd5b506102eb61038e366004611b97565b610935565b6102eb61038e366004611cb7565b3480156102eb57600080fd5b3480156103b957600080fd5b506102bd60025481565b3480156103cf57600080fd5b506102bd7fdb9556138406326f00296e13ea2ad7db24ba82381212d816b1a40c23b466b32781565b34801561040357600080fd5b506102eb61038e366004611cd4565b34801561041e57600080fd5b5061043261042d366004611d11565b61099c565b6040516102809190611da0565b34801561044b57600080fd5b506102eb61038e366004611db3565b6102eb61038e366004611cd4565b34801561047457600080fd5b50610488610483366004611df8565b610b4c565b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610280565b3480156104b957600080fd5b506102746104c8366004611a4a565b60009182526020828152604080842073ffffffffffffffffffffffffffffffffffffffff93909316845291905290205460ff1690565b34801561050a57600080fd5b506102bd7fe2b7fb3b832174769106daebcfd6d1970523240dda11281102db9363b83b0dc481565b34801561053e57600080fd5b506102bd600081565b34801561055357600080fd5b506102bd7f000000000000000000000000000000000000000000000000000000000000000081565b34801561058757600080fd5b50610274610596366004611a4a565b610b6b565b3480156105a757600080fd5b506105bb6105b6366004611cd4565b610bd0565b6040516102809190611e1a565b3480156105d457600080fd5b506102eb6105e3366004611f34565b610c43565b3480156105f457600080fd5b506102eb61038e366004611a31565b34801561060f57600080fd5b506102eb61061e366004611f74565b610e13565b34801561062f57600080fd5b506102bd60055481565b34801561064557600080fd5b506102eb610654366004611a31565b610e9e565b34801561066557600080fd5b506102eb610674366004611a31565b610f7b565b34801561068557600080fd5b506102bd620f424081565b34801561069c57600080fd5b506102eb6106ab366004611fcd565b610fe3565b3480156106bc57600080fd5b506102bd6106cb366004611a31565b611069565b3480156106dc57600080fd5b506102bd7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f5581565b34801561071057600080fd5b506102eb61071f366004611a4a565b611080565b34801561073057600080fd5b506102bd61073f366004612065565b60036020526000908152604090205481565b34801561075d57600080fd5b506102bd60045481565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f5a05180f0000000000000000000000000000000000000000000000000000000014806107bd57506107bd826110a5565b92915050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f556107ed8161113c565b73ffffffffffffffffffffffffffffffffffffffff8316600090815260036020526040812054908190036108215750505050565b73ffffffffffffffffffffffffffffffffffffffff8416600081815260036020526040812055610852908483611149565b6040805173ffffffffffffffffffffffffffffffffffffffff8087168252851660208201529081018290527f244e51bc38c1452fa8aaf487bcb4bca36c2baa3a5fbdb776b1eabd8dc6d277cd9060600160405180910390a1505b505050565b6000828152602081905260409020600101546108cc8161113c565b6108d683836112a0565b50505050565b73ffffffffffffffffffffffffffffffffffffffff8116331461092b576040517f6697b23200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6108ac82826112d5565b6040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f6e6f7420696d706c656d656e746564000000000000000000000000000000000060448201526064015b60405180910390fd5b60608160048111156109b0576109b0612082565b6000036109f057505060408051808201909152600481527f4e554c4c00000000000000000000000000000000000000000000000000000000602082015290565b816004811115610a0257610a02612082565b600103610a4257505060408051808201909152600981527f5245515545535445440000000000000000000000000000000000000000000000602082015290565b816004811115610a5457610a54612082565b600203610a9457505060408051808201909152600e81527f52454c415945525f50524f564544000000000000000000000000000000000000602082015290565b816004811115610aa657610aa6612082565b600303610ae657505060408051808201909152600f81527f52454c415945525f434c41494d45440000000000000000000000000000000000602082015290565b816004811115610af857610af8612082565b600403610b3857505060408051808201909152600881527f524546554e444544000000000000000000000000000000000000000000000000602082015290565b505060408051602081019091526000815290565b6000828152600160205260408120610b649083611302565b9392505050565b6040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f6e6f7420696d706c656d656e74656400000000000000000000000000000000006044820152600090606401610993565b604080516101808101825260008082526020808301829052928201819052606082018190526080820181905260a0820181905260c0820181905260e08201819052610100820181905261012082018190526101408201819052610160820152825190916107bd91840181019084016120d2565b6000620f42406002548360a00151610c5b91906121cd565b610c6591906121e4565b9050808260a001818151610c79919061221f565b9150818152505060006040518061018001604052804663ffffffff168152602001846000015163ffffffff168152602001846020015173ffffffffffffffffffffffffffffffffffffffff168152602001846040015173ffffffffffffffffffffffffffffffffffffffff168152602001846060015173ffffffffffffffffffffffffffffffffffffffff168152602001846080015173ffffffffffffffffffffffffffffffffffffffff1681526020018460a0015181526020018460c0015181526020018381526020018460e0015115158152602001846101000151815260200160056000815480929190610d6e90612232565b909155509052604051610d849190602001611e1a565b6040516020818303038152906040529050826020015173ffffffffffffffffffffffffffffffffffffffff16857f120ea0364f36cdac7983bcfdd55270ca09d7f9b314a2ebc425a3b01ab1d6403a838660000151876060015188608001518960a001518a60c001518b60e00151604051610e04979695949392919061226a565b60405180910390a35050505050565b6000610e1e82610bd0565b9050806040015173ffffffffffffffffffffffffffffffffffffffff16847f120ea0364f36cdac7983bcfdd55270ca09d7f9b314a2ebc425a3b01ab1d6403a84846020015185608001518660a001518760c001518860e00151896101200151604051610e90979695949392919061226a565b60405180910390a350505050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f55610ec88161113c565b612710821115610f34576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f6e657746656552617465203e206d6178000000000000000000000000000000006044820152606401610993565b600280549083905560408051828152602081018590527f14914da2bf76024616fbe1859783fcd4dbddcb179b1f3a854949fbf920dcb95791015b60405180910390a1505050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f55610fa58161113c565b600480549083905560408051828152602081018590527f5cf09b12f3f56b4c564d51b25b40360af6d795198adb61ae0806a36c294323fa9101610f6e565b6040805163ffffffff8816815273ffffffffffffffffffffffffffffffffffffffff878116602083015286811682840152606082018690526080820185905260a082018490529151898316928b16918c917ff8ae392d784b1ea5e8881bfa586d81abf07ef4f1e2fc75f7fe51c90f05199a5c9181900360c00190a4505050505050505050565b60008181526001602052604081206107bd9061130e565b60008281526020819052604090206001015461109b8161113c565b6108d683836112d5565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f7965db0b0000000000000000000000000000000000000000000000000000000014806107bd57507f01ffc9a7000000000000000000000000000000000000000000000000000000007fffffffff000000000000000000000000000000000000000000000000000000008316146107bd565b6111468133611318565b50565b3073ffffffffffffffffffffffffffffffffffffffff83160361116b57505050565b8060000361117857505050565b7fffffffffffffffffffffffff111111111111111111111111111111111111111273ffffffffffffffffffffffffffffffffffffffff84160161127f5760008273ffffffffffffffffffffffffffffffffffffffff168260405160006040518083038185875af1925050503d806000811461120f576040519150601f19603f3d011682016040523d82523d6000602084013e611214565b606091505b50509050806108d6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f455448207472616e73666572206661696c6564000000000000000000000000006044820152606401610993565b6108ac73ffffffffffffffffffffffffffffffffffffffff841683836113a2565b6000806112ad848461142f565b90508015610b645760008481526001602052604090206112cd908461152b565b509392505050565b6000806112e2848461154d565b90508015610b645760008481526001602052604090206112cd9084611608565b6000610b64838361162a565b60006107bd825490565b60008281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915290205460ff1661139e576040517fe2517d3f00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8216600482015260248101839052604401610993565b5050565b6040805173ffffffffffffffffffffffffffffffffffffffff8416602482015260448082018490528251808303909101815260649091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fa9059cbb000000000000000000000000000000000000000000000000000000001790526108ac908490611654565b60008281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915281205460ff166115235760008381526020818152604080832073ffffffffffffffffffffffffffffffffffffffff86168452909152902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790556114c13390565b73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16847f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45060016107bd565b5060006107bd565b6000610b648373ffffffffffffffffffffffffffffffffffffffff84166116ea565b60008281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915281205460ff16156115235760008381526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8616808552925280832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016905551339286917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a45060016107bd565b6000610b648373ffffffffffffffffffffffffffffffffffffffff8416611731565b6000826000018281548110611641576116416122cd565b9060005260206000200154905092915050565b600061167673ffffffffffffffffffffffffffffffffffffffff841683611824565b9050805160001415801561169b57508080602001905181019061169991906122fc565b155b156108ac576040517f5274afe700000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff84166004820152602401610993565b6000818152600183016020526040812054611523575081546001818101845560008481526020808220909301849055845484825282860190935260409020919091556107bd565b6000818152600183016020526040812054801561181a57600061175560018361221f565b85549091506000906117699060019061221f565b90508082146117ce576000866000018281548110611789576117896122cd565b90600052602060002001549050808760000184815481106117ac576117ac6122cd565b6000918252602080832090910192909255918252600188019052604090208390555b85548690806117df576117df612319565b6001900381819060005260206000200160009055905585600101600086815260200190815260200160002060009055600193505050506107bd565b60009150506107bd565b6060610b6483836000846000808573ffffffffffffffffffffffffffffffffffffffff1684866040516118579190612348565b60006040518083038185875af1925050503d8060008114611894576040519150601f19603f3d011682016040523d82523d6000602084013e611899565b606091505b50915091506118a98683836118b3565b9695505050505050565b6060826118c8576118c382611942565b610b64565b81511580156118ec575073ffffffffffffffffffffffffffffffffffffffff84163b155b1561193b576040517f9996b31500000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff85166004820152602401610993565b5080610b64565b8051156119525780518082602001fd5b6040517f1425ea4200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006020828403121561199657600080fd5b81357fffffffff0000000000000000000000000000000000000000000000000000000081168114610b6457600080fd5b73ffffffffffffffffffffffffffffffffffffffff8116811461114657600080fd5b80356119f3816119c6565b919050565b60008060408385031215611a0b57600080fd5b8235611a16816119c6565b91506020830135611a26816119c6565b809150509250929050565b600060208284031215611a4357600080fd5b5035919050565b60008060408385031215611a5d57600080fd5b823591506020830135611a26816119c6565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051610120810167ffffffffffffffff81118282101715611ac257611ac2611a6f565b60405290565b604051610180810167ffffffffffffffff81118282101715611ac257611ac2611a6f565b600082601f830112611afd57600080fd5b813567ffffffffffffffff80821115611b1857611b18611a6f565b604051601f83017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f01168101908282118183101715611b5e57611b5e611a6f565b81604052838152866020858801011115611b7757600080fd5b836020870160208301376000602085830101528094505050505092915050565b60008060408385031215611baa57600080fd5b823567ffffffffffffffff811115611bc157600080fd5b611bcd85828601611aec565b9250506020830135611a26816119c6565b63ffffffff8116811461114657600080fd5b80356119f381611bde565b801515811461114657600080fd5b80356119f381611bfb565b60006101208284031215611c2757600080fd5b611c2f611a9e565b9050611c3a82611bf0565b8152611c48602083016119e8565b6020820152611c59604083016119e8565b6040820152611c6a606083016119e8565b6060820152611c7b608083016119e8565b608082015260a082013560a082015260c082013560c0820152611ca060e08301611c09565b60e082015261010080830135818301525092915050565b60006101208284031215611cca57600080fd5b610b648383611c14565b600060208284031215611ce657600080fd5b813567ffffffffffffffff811115611cfd57600080fd5b611d0984828501611aec565b949350505050565b600060208284031215611d2357600080fd5b813560058110610b6457600080fd5b60005b83811015611d4d578181015183820152602001611d35565b50506000910152565b60008151808452611d6e816020860160208601611d32565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b602081526000610b646020830184611d56565b60008060408385031215611dc657600080fd5b823567ffffffffffffffff811115611ddd57600080fd5b611de985828601611aec565b95602094909401359450505050565b60008060408385031215611e0b57600080fd5b50508035926020909101359150565b815163ffffffff16815261018081016020830151611e40602084018263ffffffff169052565b506040830151611e68604084018273ffffffffffffffffffffffffffffffffffffffff169052565b506060830151611e90606084018273ffffffffffffffffffffffffffffffffffffffff169052565b506080830151611eb8608084018273ffffffffffffffffffffffffffffffffffffffff169052565b5060a0830151611ee060a084018273ffffffffffffffffffffffffffffffffffffffff169052565b5060c083015160c083015260e083015160e083015261010080840151818401525061012080840151611f158285018215159052565b5050610140838101519083015261016092830151929091019190915290565b60008060006101608486031215611f4a57600080fd5b833592506020840135611f5c816119c6565b9150611f6b8560408601611c14565b90509250925092565b600080600060608486031215611f8957600080fd5b833592506020840135611f9b816119c6565b9150604084013567ffffffffffffffff811115611fb757600080fd5b611fc386828701611aec565b9150509250925092565b60008060008060008060008060006101208a8c031215611fec57600080fd5b8935985060208a0135611ffe816119c6565b975060408a013561200e816119c6565b965060608a013561201e81611bde565b955060808a013561202e816119c6565b945060a08a013561203e816119c6565b8094505060c08a0135925060e08a013591506101008a013590509295985092959850929598565b60006020828403121561207757600080fd5b8135610b64816119c6565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b80516119f381611bde565b80516119f3816119c6565b80516119f381611bfb565b600061018082840312156120e557600080fd5b6120ed611ac8565b6120f6836120b1565b8152612104602084016120b1565b6020820152612115604084016120bc565b6040820152612126606084016120bc565b6060820152612137608084016120bc565b608082015261214860a084016120bc565b60a082015260c083015160c082015260e083015160e082015261010080840151818301525061012061217b8185016120c7565b908201526101408381015190820152610160928301519281019290925250919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b80820281158282048414176107bd576107bd61219e565b60008261221a577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b818103818111156107bd576107bd61219e565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82036122635761226361219e565b5060010190565b60e08152600061227d60e083018a611d56565b63ffffffff9890981660208301525073ffffffffffffffffffffffffffffffffffffffff9586166040820152939094166060840152608083019190915260a082015290151560c090910152919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60006020828403121561230e57600080fd5b8151610b6481611bfb565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fd5b6000825161235a818460208701611d32565b919091019291505056fea2646970667358221220aba3477f2b2fe8af51fb1d8c4ab96118b12f29e32da3cc98e0fddac12acfe47464736f6c63430008140033", } // FastBridgeMockABI is the input ABI used to generate the binding from. @@ -7701,10 +7752,10 @@ func (_FastBridgeMock *FastBridgeMockCallerSession) RELAYERROLE() ([32]byte, err // CanClaim is a free data retrieval call binding the contract method 0xaa9641ab. // -// Solidity: function canClaim(bytes32 transactionid, address relayer) view returns(bool) -func (_FastBridgeMock *FastBridgeMockCaller) CanClaim(opts *bind.CallOpts, transactionid [32]byte, relayer common.Address) (bool, error) { +// Solidity: function canClaim(bytes32 , address ) pure returns(bool) +func (_FastBridgeMock *FastBridgeMockCaller) CanClaim(opts *bind.CallOpts, arg0 [32]byte, arg1 common.Address) (bool, error) { var out []interface{} - err := _FastBridgeMock.contract.Call(opts, &out, "canClaim", transactionid, relayer) + err := _FastBridgeMock.contract.Call(opts, &out, "canClaim", arg0, arg1) if err != nil { return *new(bool), err @@ -7718,16 +7769,16 @@ func (_FastBridgeMock *FastBridgeMockCaller) CanClaim(opts *bind.CallOpts, trans // CanClaim is a free data retrieval call binding the contract method 0xaa9641ab. // -// Solidity: function canClaim(bytes32 transactionid, address relayer) view returns(bool) -func (_FastBridgeMock *FastBridgeMockSession) CanClaim(transactionid [32]byte, relayer common.Address) (bool, error) { - return _FastBridgeMock.Contract.CanClaim(&_FastBridgeMock.CallOpts, transactionid, relayer) +// Solidity: function canClaim(bytes32 , address ) pure returns(bool) +func (_FastBridgeMock *FastBridgeMockSession) CanClaim(arg0 [32]byte, arg1 common.Address) (bool, error) { + return _FastBridgeMock.Contract.CanClaim(&_FastBridgeMock.CallOpts, arg0, arg1) } // CanClaim is a free data retrieval call binding the contract method 0xaa9641ab. // -// Solidity: function canClaim(bytes32 transactionid, address relayer) view returns(bool) -func (_FastBridgeMock *FastBridgeMockCallerSession) CanClaim(transactionid [32]byte, relayer common.Address) (bool, error) { - return _FastBridgeMock.Contract.CanClaim(&_FastBridgeMock.CallOpts, transactionid, relayer) +// Solidity: function canClaim(bytes32 , address ) pure returns(bool) +func (_FastBridgeMock *FastBridgeMockCallerSession) CanClaim(arg0 [32]byte, arg1 common.Address) (bool, error) { + return _FastBridgeMock.Contract.CanClaim(&_FastBridgeMock.CallOpts, arg0, arg1) } // ChainGasAmount is a free data retrieval call binding the contract method 0xe00a83e0. @@ -7761,6 +7812,35 @@ func (_FastBridgeMock *FastBridgeMockCallerSession) ChainGasAmount() (*big.Int, return _FastBridgeMock.Contract.ChainGasAmount(&_FastBridgeMock.CallOpts) } +// Claim is a free data retrieval call binding the contract method 0x41fcb612. +// +// Solidity: function claim(bytes , address ) pure returns() +func (_FastBridgeMock *FastBridgeMockCaller) Claim(opts *bind.CallOpts, arg0 []byte, arg1 common.Address) error { + var out []interface{} + err := _FastBridgeMock.contract.Call(opts, &out, "claim", arg0, arg1) + + if err != nil { + return err + } + + return err + +} + +// Claim is a free data retrieval call binding the contract method 0x41fcb612. +// +// Solidity: function claim(bytes , address ) pure returns() +func (_FastBridgeMock *FastBridgeMockSession) Claim(arg0 []byte, arg1 common.Address) error { + return _FastBridgeMock.Contract.Claim(&_FastBridgeMock.CallOpts, arg0, arg1) +} + +// Claim is a free data retrieval call binding the contract method 0x41fcb612. +// +// Solidity: function claim(bytes , address ) pure returns() +func (_FastBridgeMock *FastBridgeMockCallerSession) Claim(arg0 []byte, arg1 common.Address) error { + return _FastBridgeMock.Contract.Claim(&_FastBridgeMock.CallOpts, arg0, arg1) +} + // DeployBlock is a free data retrieval call binding the contract method 0xa3ec191a. // // Solidity: function deployBlock() view returns(uint256) @@ -7792,6 +7872,35 @@ func (_FastBridgeMock *FastBridgeMockCallerSession) DeployBlock() (*big.Int, err return _FastBridgeMock.Contract.DeployBlock(&_FastBridgeMock.CallOpts) } +// Dispute is a free data retrieval call binding the contract method 0xadd98c70. +// +// Solidity: function dispute(bytes32 ) pure returns() +func (_FastBridgeMock *FastBridgeMockCaller) Dispute(opts *bind.CallOpts, arg0 [32]byte) error { + var out []interface{} + err := _FastBridgeMock.contract.Call(opts, &out, "dispute", arg0) + + if err != nil { + return err + } + + return err + +} + +// Dispute is a free data retrieval call binding the contract method 0xadd98c70. +// +// Solidity: function dispute(bytes32 ) pure returns() +func (_FastBridgeMock *FastBridgeMockSession) Dispute(arg0 [32]byte) error { + return _FastBridgeMock.Contract.Dispute(&_FastBridgeMock.CallOpts, arg0) +} + +// Dispute is a free data retrieval call binding the contract method 0xadd98c70. +// +// Solidity: function dispute(bytes32 ) pure returns() +func (_FastBridgeMock *FastBridgeMockCallerSession) Dispute(arg0 [32]byte) error { + return _FastBridgeMock.Contract.Dispute(&_FastBridgeMock.CallOpts, arg0) +} + // GetBridgeTransaction is a free data retrieval call binding the contract method 0xac11fb1a. // // Solidity: function getBridgeTransaction(bytes request) pure returns((uint32,uint32,address,address,address,address,uint256,uint256,uint256,bool,uint256,uint256)) @@ -8071,6 +8180,64 @@ func (_FastBridgeMock *FastBridgeMockCallerSession) ProtocolFees(arg0 common.Add return _FastBridgeMock.Contract.ProtocolFees(&_FastBridgeMock.CallOpts, arg0) } +// Prove is a free data retrieval call binding the contract method 0x886d36ff. +// +// Solidity: function prove(bytes , bytes32 ) pure returns() +func (_FastBridgeMock *FastBridgeMockCaller) Prove(opts *bind.CallOpts, arg0 []byte, arg1 [32]byte) error { + var out []interface{} + err := _FastBridgeMock.contract.Call(opts, &out, "prove", arg0, arg1) + + if err != nil { + return err + } + + return err + +} + +// Prove is a free data retrieval call binding the contract method 0x886d36ff. +// +// Solidity: function prove(bytes , bytes32 ) pure returns() +func (_FastBridgeMock *FastBridgeMockSession) Prove(arg0 []byte, arg1 [32]byte) error { + return _FastBridgeMock.Contract.Prove(&_FastBridgeMock.CallOpts, arg0, arg1) +} + +// Prove is a free data retrieval call binding the contract method 0x886d36ff. +// +// Solidity: function prove(bytes , bytes32 ) pure returns() +func (_FastBridgeMock *FastBridgeMockCallerSession) Prove(arg0 []byte, arg1 [32]byte) error { + return _FastBridgeMock.Contract.Prove(&_FastBridgeMock.CallOpts, arg0, arg1) +} + +// Refund is a free data retrieval call binding the contract method 0x5eb7d946. +// +// Solidity: function refund(bytes ) pure returns() +func (_FastBridgeMock *FastBridgeMockCaller) Refund(opts *bind.CallOpts, arg0 []byte) error { + var out []interface{} + err := _FastBridgeMock.contract.Call(opts, &out, "refund", arg0) + + if err != nil { + return err + } + + return err + +} + +// Refund is a free data retrieval call binding the contract method 0x5eb7d946. +// +// Solidity: function refund(bytes ) pure returns() +func (_FastBridgeMock *FastBridgeMockSession) Refund(arg0 []byte) error { + return _FastBridgeMock.Contract.Refund(&_FastBridgeMock.CallOpts, arg0) +} + +// Refund is a free data retrieval call binding the contract method 0x5eb7d946. +// +// Solidity: function refund(bytes ) pure returns() +func (_FastBridgeMock *FastBridgeMockCallerSession) Refund(arg0 []byte) error { + return _FastBridgeMock.Contract.Refund(&_FastBridgeMock.CallOpts, arg0) +} + // SupportsInterface is a free data retrieval call binding the contract method 0x01ffc9a7. // // Solidity: function supportsInterface(bytes4 interfaceId) view returns(bool) @@ -8104,65 +8271,23 @@ func (_FastBridgeMock *FastBridgeMockCallerSession) SupportsInterface(interfaceI // Bridge is a paid mutator transaction binding the contract method 0x45851694. // -// Solidity: function bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256) params) payable returns() -func (_FastBridgeMock *FastBridgeMockTransactor) Bridge(opts *bind.TransactOpts, params IFastBridgeBridgeParams) (*types.Transaction, error) { - return _FastBridgeMock.contract.Transact(opts, "bridge", params) +// Solidity: function bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256) ) payable returns() +func (_FastBridgeMock *FastBridgeMockTransactor) Bridge(opts *bind.TransactOpts, arg0 IFastBridgeBridgeParams) (*types.Transaction, error) { + return _FastBridgeMock.contract.Transact(opts, "bridge", arg0) } // Bridge is a paid mutator transaction binding the contract method 0x45851694. // -// Solidity: function bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256) params) payable returns() -func (_FastBridgeMock *FastBridgeMockSession) Bridge(params IFastBridgeBridgeParams) (*types.Transaction, error) { - return _FastBridgeMock.Contract.Bridge(&_FastBridgeMock.TransactOpts, params) +// Solidity: function bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256) ) payable returns() +func (_FastBridgeMock *FastBridgeMockSession) Bridge(arg0 IFastBridgeBridgeParams) (*types.Transaction, error) { + return _FastBridgeMock.Contract.Bridge(&_FastBridgeMock.TransactOpts, arg0) } // Bridge is a paid mutator transaction binding the contract method 0x45851694. // -// Solidity: function bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256) params) payable returns() -func (_FastBridgeMock *FastBridgeMockTransactorSession) Bridge(params IFastBridgeBridgeParams) (*types.Transaction, error) { - return _FastBridgeMock.Contract.Bridge(&_FastBridgeMock.TransactOpts, params) -} - -// Claim is a paid mutator transaction binding the contract method 0x41fcb612. -// -// Solidity: function claim(bytes request, address to) returns() -func (_FastBridgeMock *FastBridgeMockTransactor) Claim(opts *bind.TransactOpts, request []byte, to common.Address) (*types.Transaction, error) { - return _FastBridgeMock.contract.Transact(opts, "claim", request, to) -} - -// Claim is a paid mutator transaction binding the contract method 0x41fcb612. -// -// Solidity: function claim(bytes request, address to) returns() -func (_FastBridgeMock *FastBridgeMockSession) Claim(request []byte, to common.Address) (*types.Transaction, error) { - return _FastBridgeMock.Contract.Claim(&_FastBridgeMock.TransactOpts, request, to) -} - -// Claim is a paid mutator transaction binding the contract method 0x41fcb612. -// -// Solidity: function claim(bytes request, address to) returns() -func (_FastBridgeMock *FastBridgeMockTransactorSession) Claim(request []byte, to common.Address) (*types.Transaction, error) { - return _FastBridgeMock.Contract.Claim(&_FastBridgeMock.TransactOpts, request, to) -} - -// Dispute is a paid mutator transaction binding the contract method 0xadd98c70. -// -// Solidity: function dispute(bytes32 transactionId) returns() -func (_FastBridgeMock *FastBridgeMockTransactor) Dispute(opts *bind.TransactOpts, transactionId [32]byte) (*types.Transaction, error) { - return _FastBridgeMock.contract.Transact(opts, "dispute", transactionId) -} - -// Dispute is a paid mutator transaction binding the contract method 0xadd98c70. -// -// Solidity: function dispute(bytes32 transactionId) returns() -func (_FastBridgeMock *FastBridgeMockSession) Dispute(transactionId [32]byte) (*types.Transaction, error) { - return _FastBridgeMock.Contract.Dispute(&_FastBridgeMock.TransactOpts, transactionId) -} - -// Dispute is a paid mutator transaction binding the contract method 0xadd98c70. -// -// Solidity: function dispute(bytes32 transactionId) returns() -func (_FastBridgeMock *FastBridgeMockTransactorSession) Dispute(transactionId [32]byte) (*types.Transaction, error) { - return _FastBridgeMock.Contract.Dispute(&_FastBridgeMock.TransactOpts, transactionId) +// Solidity: function bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256) ) payable returns() +func (_FastBridgeMock *FastBridgeMockTransactorSession) Bridge(arg0 IFastBridgeBridgeParams) (*types.Transaction, error) { + return _FastBridgeMock.Contract.Bridge(&_FastBridgeMock.TransactOpts, arg0) } // GrantRole is a paid mutator transaction binding the contract method 0x2f2ff15d. @@ -8249,67 +8374,25 @@ func (_FastBridgeMock *FastBridgeMockTransactorSession) MockBridgeRequestRaw(tra return _FastBridgeMock.Contract.MockBridgeRequestRaw(&_FastBridgeMock.TransactOpts, transactionId, sender, request) } -// Prove is a paid mutator transaction binding the contract method 0x886d36ff. -// -// Solidity: function prove(bytes request, bytes32 destTxHash) returns() -func (_FastBridgeMock *FastBridgeMockTransactor) Prove(opts *bind.TransactOpts, request []byte, destTxHash [32]byte) (*types.Transaction, error) { - return _FastBridgeMock.contract.Transact(opts, "prove", request, destTxHash) -} - -// Prove is a paid mutator transaction binding the contract method 0x886d36ff. -// -// Solidity: function prove(bytes request, bytes32 destTxHash) returns() -func (_FastBridgeMock *FastBridgeMockSession) Prove(request []byte, destTxHash [32]byte) (*types.Transaction, error) { - return _FastBridgeMock.Contract.Prove(&_FastBridgeMock.TransactOpts, request, destTxHash) -} - -// Prove is a paid mutator transaction binding the contract method 0x886d36ff. -// -// Solidity: function prove(bytes request, bytes32 destTxHash) returns() -func (_FastBridgeMock *FastBridgeMockTransactorSession) Prove(request []byte, destTxHash [32]byte) (*types.Transaction, error) { - return _FastBridgeMock.Contract.Prove(&_FastBridgeMock.TransactOpts, request, destTxHash) -} - -// Refund is a paid mutator transaction binding the contract method 0x5eb7d946. -// -// Solidity: function refund(bytes request) returns() -func (_FastBridgeMock *FastBridgeMockTransactor) Refund(opts *bind.TransactOpts, request []byte) (*types.Transaction, error) { - return _FastBridgeMock.contract.Transact(opts, "refund", request) -} - -// Refund is a paid mutator transaction binding the contract method 0x5eb7d946. -// -// Solidity: function refund(bytes request) returns() -func (_FastBridgeMock *FastBridgeMockSession) Refund(request []byte) (*types.Transaction, error) { - return _FastBridgeMock.Contract.Refund(&_FastBridgeMock.TransactOpts, request) -} - -// Refund is a paid mutator transaction binding the contract method 0x5eb7d946. -// -// Solidity: function refund(bytes request) returns() -func (_FastBridgeMock *FastBridgeMockTransactorSession) Refund(request []byte) (*types.Transaction, error) { - return _FastBridgeMock.Contract.Refund(&_FastBridgeMock.TransactOpts, request) -} - // Relay is a paid mutator transaction binding the contract method 0x8f0d6f17. // -// Solidity: function relay(bytes request) payable returns() -func (_FastBridgeMock *FastBridgeMockTransactor) Relay(opts *bind.TransactOpts, request []byte) (*types.Transaction, error) { - return _FastBridgeMock.contract.Transact(opts, "relay", request) +// Solidity: function relay(bytes ) payable returns() +func (_FastBridgeMock *FastBridgeMockTransactor) Relay(opts *bind.TransactOpts, arg0 []byte) (*types.Transaction, error) { + return _FastBridgeMock.contract.Transact(opts, "relay", arg0) } // Relay is a paid mutator transaction binding the contract method 0x8f0d6f17. // -// Solidity: function relay(bytes request) payable returns() -func (_FastBridgeMock *FastBridgeMockSession) Relay(request []byte) (*types.Transaction, error) { - return _FastBridgeMock.Contract.Relay(&_FastBridgeMock.TransactOpts, request) +// Solidity: function relay(bytes ) payable returns() +func (_FastBridgeMock *FastBridgeMockSession) Relay(arg0 []byte) (*types.Transaction, error) { + return _FastBridgeMock.Contract.Relay(&_FastBridgeMock.TransactOpts, arg0) } // Relay is a paid mutator transaction binding the contract method 0x8f0d6f17. // -// Solidity: function relay(bytes request) payable returns() -func (_FastBridgeMock *FastBridgeMockTransactorSession) Relay(request []byte) (*types.Transaction, error) { - return _FastBridgeMock.Contract.Relay(&_FastBridgeMock.TransactOpts, request) +// Solidity: function relay(bytes ) payable returns() +func (_FastBridgeMock *FastBridgeMockTransactorSession) Relay(arg0 []byte) (*types.Transaction, error) { + return _FastBridgeMock.Contract.Relay(&_FastBridgeMock.TransactOpts, arg0) } // RenounceRole is a paid mutator transaction binding the contract method 0x36568abe. @@ -8417,6 +8500,27 @@ func (_FastBridgeMock *FastBridgeMockTransactorSession) SweepProtocolFees(token return _FastBridgeMock.Contract.SweepProtocolFees(&_FastBridgeMock.TransactOpts, token, recipient) } +// TestFastBridgeMock is a paid mutator transaction binding the contract method 0x4774fa38. +// +// Solidity: function testFastBridgeMock() returns() +func (_FastBridgeMock *FastBridgeMockTransactor) TestFastBridgeMock(opts *bind.TransactOpts) (*types.Transaction, error) { + return _FastBridgeMock.contract.Transact(opts, "testFastBridgeMock") +} + +// TestFastBridgeMock is a paid mutator transaction binding the contract method 0x4774fa38. +// +// Solidity: function testFastBridgeMock() returns() +func (_FastBridgeMock *FastBridgeMockSession) TestFastBridgeMock() (*types.Transaction, error) { + return _FastBridgeMock.Contract.TestFastBridgeMock(&_FastBridgeMock.TransactOpts) +} + +// TestFastBridgeMock is a paid mutator transaction binding the contract method 0x4774fa38. +// +// Solidity: function testFastBridgeMock() returns() +func (_FastBridgeMock *FastBridgeMockTransactorSession) TestFastBridgeMock() (*types.Transaction, error) { + return _FastBridgeMock.Contract.TestFastBridgeMock(&_FastBridgeMock.TransactOpts) +} + // FastBridgeMockBridgeDepositClaimedIterator is returned from FilterBridgeDepositClaimed and is used to iterate over the raw logs and unpacked data for BridgeDepositClaimed events raised by the FastBridgeMock contract. type FastBridgeMockBridgeDepositClaimedIterator struct { Event *FastBridgeMockBridgeDepositClaimed // Event containing the contract specifics and raw log @@ -14868,10 +14972,412 @@ func (_IFastBridge *IFastBridgeFilterer) ParseBridgeRequested(log types.Log) (*I return event, nil } +// IMulticallTargetMetaData contains all meta data concerning the IMulticallTarget contract. +var IMulticallTargetMetaData = &bind.MetaData{ + ABI: "[{\"inputs\":[{\"internalType\":\"bytes[]\",\"name\":\"data\",\"type\":\"bytes[]\"},{\"internalType\":\"bool\",\"name\":\"ignoreReverts\",\"type\":\"bool\"}],\"name\":\"multicallNoResults\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes[]\",\"name\":\"data\",\"type\":\"bytes[]\"},{\"internalType\":\"bool\",\"name\":\"ignoreReverts\",\"type\":\"bool\"}],\"name\":\"multicallWithResults\",\"outputs\":[{\"components\":[{\"internalType\":\"bool\",\"name\":\"success\",\"type\":\"bool\"},{\"internalType\":\"bytes\",\"name\":\"returnData\",\"type\":\"bytes\"}],\"internalType\":\"structIMulticallTarget.Result[]\",\"name\":\"results\",\"type\":\"tuple[]\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", + Sigs: map[string]string{ + "3f61331d": "multicallNoResults(bytes[],bool)", + "385c1d2f": "multicallWithResults(bytes[],bool)", + }, +} + +// IMulticallTargetABI is the input ABI used to generate the binding from. +// Deprecated: Use IMulticallTargetMetaData.ABI instead. +var IMulticallTargetABI = IMulticallTargetMetaData.ABI + +// Deprecated: Use IMulticallTargetMetaData.Sigs instead. +// IMulticallTargetFuncSigs maps the 4-byte function signature to its string representation. +var IMulticallTargetFuncSigs = IMulticallTargetMetaData.Sigs + +// IMulticallTarget is an auto generated Go binding around an Ethereum contract. +type IMulticallTarget struct { + IMulticallTargetCaller // Read-only binding to the contract + IMulticallTargetTransactor // Write-only binding to the contract + IMulticallTargetFilterer // Log filterer for contract events +} + +// IMulticallTargetCaller is an auto generated read-only Go binding around an Ethereum contract. +type IMulticallTargetCaller struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// IMulticallTargetTransactor is an auto generated write-only Go binding around an Ethereum contract. +type IMulticallTargetTransactor struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// IMulticallTargetFilterer is an auto generated log filtering Go binding around an Ethereum contract events. +type IMulticallTargetFilterer struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// IMulticallTargetSession is an auto generated Go binding around an Ethereum contract, +// with pre-set call and transact options. +type IMulticallTargetSession struct { + Contract *IMulticallTarget // Generic contract binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// IMulticallTargetCallerSession is an auto generated read-only Go binding around an Ethereum contract, +// with pre-set call options. +type IMulticallTargetCallerSession struct { + Contract *IMulticallTargetCaller // Generic contract caller binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session +} + +// IMulticallTargetTransactorSession is an auto generated write-only Go binding around an Ethereum contract, +// with pre-set transact options. +type IMulticallTargetTransactorSession struct { + Contract *IMulticallTargetTransactor // Generic contract transactor binding to set the session for + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// IMulticallTargetRaw is an auto generated low-level Go binding around an Ethereum contract. +type IMulticallTargetRaw struct { + Contract *IMulticallTarget // Generic contract binding to access the raw methods on +} + +// IMulticallTargetCallerRaw is an auto generated low-level read-only Go binding around an Ethereum contract. +type IMulticallTargetCallerRaw struct { + Contract *IMulticallTargetCaller // Generic read-only contract binding to access the raw methods on +} + +// IMulticallTargetTransactorRaw is an auto generated low-level write-only Go binding around an Ethereum contract. +type IMulticallTargetTransactorRaw struct { + Contract *IMulticallTargetTransactor // Generic write-only contract binding to access the raw methods on +} + +// NewIMulticallTarget creates a new instance of IMulticallTarget, bound to a specific deployed contract. +func NewIMulticallTarget(address common.Address, backend bind.ContractBackend) (*IMulticallTarget, error) { + contract, err := bindIMulticallTarget(address, backend, backend, backend) + if err != nil { + return nil, err + } + return &IMulticallTarget{IMulticallTargetCaller: IMulticallTargetCaller{contract: contract}, IMulticallTargetTransactor: IMulticallTargetTransactor{contract: contract}, IMulticallTargetFilterer: IMulticallTargetFilterer{contract: contract}}, nil +} + +// NewIMulticallTargetCaller creates a new read-only instance of IMulticallTarget, bound to a specific deployed contract. +func NewIMulticallTargetCaller(address common.Address, caller bind.ContractCaller) (*IMulticallTargetCaller, error) { + contract, err := bindIMulticallTarget(address, caller, nil, nil) + if err != nil { + return nil, err + } + return &IMulticallTargetCaller{contract: contract}, nil +} + +// NewIMulticallTargetTransactor creates a new write-only instance of IMulticallTarget, bound to a specific deployed contract. +func NewIMulticallTargetTransactor(address common.Address, transactor bind.ContractTransactor) (*IMulticallTargetTransactor, error) { + contract, err := bindIMulticallTarget(address, nil, transactor, nil) + if err != nil { + return nil, err + } + return &IMulticallTargetTransactor{contract: contract}, nil +} + +// NewIMulticallTargetFilterer creates a new log filterer instance of IMulticallTarget, bound to a specific deployed contract. +func NewIMulticallTargetFilterer(address common.Address, filterer bind.ContractFilterer) (*IMulticallTargetFilterer, error) { + contract, err := bindIMulticallTarget(address, nil, nil, filterer) + if err != nil { + return nil, err + } + return &IMulticallTargetFilterer{contract: contract}, nil +} + +// bindIMulticallTarget binds a generic wrapper to an already deployed contract. +func bindIMulticallTarget(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) { + parsed, err := IMulticallTargetMetaData.GetAbi() + if err != nil { + return nil, err + } + return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil +} + +// Call invokes the (constant) contract method with params as input values and +// sets the output to result. The result type might be a single field for simple +// returns, a slice of interfaces for anonymous returns and a struct for named +// returns. +func (_IMulticallTarget *IMulticallTargetRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _IMulticallTarget.Contract.IMulticallTargetCaller.contract.Call(opts, result, method, params...) +} + +// Transfer initiates a plain transaction to move funds to the contract, calling +// its default method if one is available. +func (_IMulticallTarget *IMulticallTargetRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _IMulticallTarget.Contract.IMulticallTargetTransactor.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_IMulticallTarget *IMulticallTargetRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _IMulticallTarget.Contract.IMulticallTargetTransactor.contract.Transact(opts, method, params...) +} + +// Call invokes the (constant) contract method with params as input values and +// sets the output to result. The result type might be a single field for simple +// returns, a slice of interfaces for anonymous returns and a struct for named +// returns. +func (_IMulticallTarget *IMulticallTargetCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _IMulticallTarget.Contract.contract.Call(opts, result, method, params...) +} + +// Transfer initiates a plain transaction to move funds to the contract, calling +// its default method if one is available. +func (_IMulticallTarget *IMulticallTargetTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _IMulticallTarget.Contract.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_IMulticallTarget *IMulticallTargetTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _IMulticallTarget.Contract.contract.Transact(opts, method, params...) +} + +// MulticallNoResults is a paid mutator transaction binding the contract method 0x3f61331d. +// +// Solidity: function multicallNoResults(bytes[] data, bool ignoreReverts) returns() +func (_IMulticallTarget *IMulticallTargetTransactor) MulticallNoResults(opts *bind.TransactOpts, data [][]byte, ignoreReverts bool) (*types.Transaction, error) { + return _IMulticallTarget.contract.Transact(opts, "multicallNoResults", data, ignoreReverts) +} + +// MulticallNoResults is a paid mutator transaction binding the contract method 0x3f61331d. +// +// Solidity: function multicallNoResults(bytes[] data, bool ignoreReverts) returns() +func (_IMulticallTarget *IMulticallTargetSession) MulticallNoResults(data [][]byte, ignoreReverts bool) (*types.Transaction, error) { + return _IMulticallTarget.Contract.MulticallNoResults(&_IMulticallTarget.TransactOpts, data, ignoreReverts) +} + +// MulticallNoResults is a paid mutator transaction binding the contract method 0x3f61331d. +// +// Solidity: function multicallNoResults(bytes[] data, bool ignoreReverts) returns() +func (_IMulticallTarget *IMulticallTargetTransactorSession) MulticallNoResults(data [][]byte, ignoreReverts bool) (*types.Transaction, error) { + return _IMulticallTarget.Contract.MulticallNoResults(&_IMulticallTarget.TransactOpts, data, ignoreReverts) +} + +// MulticallWithResults is a paid mutator transaction binding the contract method 0x385c1d2f. +// +// Solidity: function multicallWithResults(bytes[] data, bool ignoreReverts) returns((bool,bytes)[] results) +func (_IMulticallTarget *IMulticallTargetTransactor) MulticallWithResults(opts *bind.TransactOpts, data [][]byte, ignoreReverts bool) (*types.Transaction, error) { + return _IMulticallTarget.contract.Transact(opts, "multicallWithResults", data, ignoreReverts) +} + +// MulticallWithResults is a paid mutator transaction binding the contract method 0x385c1d2f. +// +// Solidity: function multicallWithResults(bytes[] data, bool ignoreReverts) returns((bool,bytes)[] results) +func (_IMulticallTarget *IMulticallTargetSession) MulticallWithResults(data [][]byte, ignoreReverts bool) (*types.Transaction, error) { + return _IMulticallTarget.Contract.MulticallWithResults(&_IMulticallTarget.TransactOpts, data, ignoreReverts) +} + +// MulticallWithResults is a paid mutator transaction binding the contract method 0x385c1d2f. +// +// Solidity: function multicallWithResults(bytes[] data, bool ignoreReverts) returns((bool,bytes)[] results) +func (_IMulticallTarget *IMulticallTargetTransactorSession) MulticallWithResults(data [][]byte, ignoreReverts bool) (*types.Transaction, error) { + return _IMulticallTarget.Contract.MulticallWithResults(&_IMulticallTarget.TransactOpts, data, ignoreReverts) +} + +// MulticallTargetMetaData contains all meta data concerning the MulticallTarget contract. +var MulticallTargetMetaData = &bind.MetaData{ + ABI: "[{\"inputs\":[],\"name\":\"MulticallTarget__UndeterminedRevert\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"bytes[]\",\"name\":\"data\",\"type\":\"bytes[]\"},{\"internalType\":\"bool\",\"name\":\"ignoreReverts\",\"type\":\"bool\"}],\"name\":\"multicallNoResults\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes[]\",\"name\":\"data\",\"type\":\"bytes[]\"},{\"internalType\":\"bool\",\"name\":\"ignoreReverts\",\"type\":\"bool\"}],\"name\":\"multicallWithResults\",\"outputs\":[{\"components\":[{\"internalType\":\"bool\",\"name\":\"success\",\"type\":\"bool\"},{\"internalType\":\"bytes\",\"name\":\"returnData\",\"type\":\"bytes\"}],\"internalType\":\"structIMulticallTarget.Result[]\",\"name\":\"results\",\"type\":\"tuple[]\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", + Sigs: map[string]string{ + "3f61331d": "multicallNoResults(bytes[],bool)", + "385c1d2f": "multicallWithResults(bytes[],bool)", + }, +} + +// MulticallTargetABI is the input ABI used to generate the binding from. +// Deprecated: Use MulticallTargetMetaData.ABI instead. +var MulticallTargetABI = MulticallTargetMetaData.ABI + +// Deprecated: Use MulticallTargetMetaData.Sigs instead. +// MulticallTargetFuncSigs maps the 4-byte function signature to its string representation. +var MulticallTargetFuncSigs = MulticallTargetMetaData.Sigs + +// MulticallTarget is an auto generated Go binding around an Ethereum contract. +type MulticallTarget struct { + MulticallTargetCaller // Read-only binding to the contract + MulticallTargetTransactor // Write-only binding to the contract + MulticallTargetFilterer // Log filterer for contract events +} + +// MulticallTargetCaller is an auto generated read-only Go binding around an Ethereum contract. +type MulticallTargetCaller struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// MulticallTargetTransactor is an auto generated write-only Go binding around an Ethereum contract. +type MulticallTargetTransactor struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// MulticallTargetFilterer is an auto generated log filtering Go binding around an Ethereum contract events. +type MulticallTargetFilterer struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// MulticallTargetSession is an auto generated Go binding around an Ethereum contract, +// with pre-set call and transact options. +type MulticallTargetSession struct { + Contract *MulticallTarget // Generic contract binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// MulticallTargetCallerSession is an auto generated read-only Go binding around an Ethereum contract, +// with pre-set call options. +type MulticallTargetCallerSession struct { + Contract *MulticallTargetCaller // Generic contract caller binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session +} + +// MulticallTargetTransactorSession is an auto generated write-only Go binding around an Ethereum contract, +// with pre-set transact options. +type MulticallTargetTransactorSession struct { + Contract *MulticallTargetTransactor // Generic contract transactor binding to set the session for + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// MulticallTargetRaw is an auto generated low-level Go binding around an Ethereum contract. +type MulticallTargetRaw struct { + Contract *MulticallTarget // Generic contract binding to access the raw methods on +} + +// MulticallTargetCallerRaw is an auto generated low-level read-only Go binding around an Ethereum contract. +type MulticallTargetCallerRaw struct { + Contract *MulticallTargetCaller // Generic read-only contract binding to access the raw methods on +} + +// MulticallTargetTransactorRaw is an auto generated low-level write-only Go binding around an Ethereum contract. +type MulticallTargetTransactorRaw struct { + Contract *MulticallTargetTransactor // Generic write-only contract binding to access the raw methods on +} + +// NewMulticallTarget creates a new instance of MulticallTarget, bound to a specific deployed contract. +func NewMulticallTarget(address common.Address, backend bind.ContractBackend) (*MulticallTarget, error) { + contract, err := bindMulticallTarget(address, backend, backend, backend) + if err != nil { + return nil, err + } + return &MulticallTarget{MulticallTargetCaller: MulticallTargetCaller{contract: contract}, MulticallTargetTransactor: MulticallTargetTransactor{contract: contract}, MulticallTargetFilterer: MulticallTargetFilterer{contract: contract}}, nil +} + +// NewMulticallTargetCaller creates a new read-only instance of MulticallTarget, bound to a specific deployed contract. +func NewMulticallTargetCaller(address common.Address, caller bind.ContractCaller) (*MulticallTargetCaller, error) { + contract, err := bindMulticallTarget(address, caller, nil, nil) + if err != nil { + return nil, err + } + return &MulticallTargetCaller{contract: contract}, nil +} + +// NewMulticallTargetTransactor creates a new write-only instance of MulticallTarget, bound to a specific deployed contract. +func NewMulticallTargetTransactor(address common.Address, transactor bind.ContractTransactor) (*MulticallTargetTransactor, error) { + contract, err := bindMulticallTarget(address, nil, transactor, nil) + if err != nil { + return nil, err + } + return &MulticallTargetTransactor{contract: contract}, nil +} + +// NewMulticallTargetFilterer creates a new log filterer instance of MulticallTarget, bound to a specific deployed contract. +func NewMulticallTargetFilterer(address common.Address, filterer bind.ContractFilterer) (*MulticallTargetFilterer, error) { + contract, err := bindMulticallTarget(address, nil, nil, filterer) + if err != nil { + return nil, err + } + return &MulticallTargetFilterer{contract: contract}, nil +} + +// bindMulticallTarget binds a generic wrapper to an already deployed contract. +func bindMulticallTarget(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) { + parsed, err := MulticallTargetMetaData.GetAbi() + if err != nil { + return nil, err + } + return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil +} + +// Call invokes the (constant) contract method with params as input values and +// sets the output to result. The result type might be a single field for simple +// returns, a slice of interfaces for anonymous returns and a struct for named +// returns. +func (_MulticallTarget *MulticallTargetRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _MulticallTarget.Contract.MulticallTargetCaller.contract.Call(opts, result, method, params...) +} + +// Transfer initiates a plain transaction to move funds to the contract, calling +// its default method if one is available. +func (_MulticallTarget *MulticallTargetRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _MulticallTarget.Contract.MulticallTargetTransactor.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_MulticallTarget *MulticallTargetRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _MulticallTarget.Contract.MulticallTargetTransactor.contract.Transact(opts, method, params...) +} + +// Call invokes the (constant) contract method with params as input values and +// sets the output to result. The result type might be a single field for simple +// returns, a slice of interfaces for anonymous returns and a struct for named +// returns. +func (_MulticallTarget *MulticallTargetCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _MulticallTarget.Contract.contract.Call(opts, result, method, params...) +} + +// Transfer initiates a plain transaction to move funds to the contract, calling +// its default method if one is available. +func (_MulticallTarget *MulticallTargetTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _MulticallTarget.Contract.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_MulticallTarget *MulticallTargetTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _MulticallTarget.Contract.contract.Transact(opts, method, params...) +} + +// MulticallNoResults is a paid mutator transaction binding the contract method 0x3f61331d. +// +// Solidity: function multicallNoResults(bytes[] data, bool ignoreReverts) returns() +func (_MulticallTarget *MulticallTargetTransactor) MulticallNoResults(opts *bind.TransactOpts, data [][]byte, ignoreReverts bool) (*types.Transaction, error) { + return _MulticallTarget.contract.Transact(opts, "multicallNoResults", data, ignoreReverts) +} + +// MulticallNoResults is a paid mutator transaction binding the contract method 0x3f61331d. +// +// Solidity: function multicallNoResults(bytes[] data, bool ignoreReverts) returns() +func (_MulticallTarget *MulticallTargetSession) MulticallNoResults(data [][]byte, ignoreReverts bool) (*types.Transaction, error) { + return _MulticallTarget.Contract.MulticallNoResults(&_MulticallTarget.TransactOpts, data, ignoreReverts) +} + +// MulticallNoResults is a paid mutator transaction binding the contract method 0x3f61331d. +// +// Solidity: function multicallNoResults(bytes[] data, bool ignoreReverts) returns() +func (_MulticallTarget *MulticallTargetTransactorSession) MulticallNoResults(data [][]byte, ignoreReverts bool) (*types.Transaction, error) { + return _MulticallTarget.Contract.MulticallNoResults(&_MulticallTarget.TransactOpts, data, ignoreReverts) +} + +// MulticallWithResults is a paid mutator transaction binding the contract method 0x385c1d2f. +// +// Solidity: function multicallWithResults(bytes[] data, bool ignoreReverts) returns((bool,bytes)[] results) +func (_MulticallTarget *MulticallTargetTransactor) MulticallWithResults(opts *bind.TransactOpts, data [][]byte, ignoreReverts bool) (*types.Transaction, error) { + return _MulticallTarget.contract.Transact(opts, "multicallWithResults", data, ignoreReverts) +} + +// MulticallWithResults is a paid mutator transaction binding the contract method 0x385c1d2f. +// +// Solidity: function multicallWithResults(bytes[] data, bool ignoreReverts) returns((bool,bytes)[] results) +func (_MulticallTarget *MulticallTargetSession) MulticallWithResults(data [][]byte, ignoreReverts bool) (*types.Transaction, error) { + return _MulticallTarget.Contract.MulticallWithResults(&_MulticallTarget.TransactOpts, data, ignoreReverts) +} + +// MulticallWithResults is a paid mutator transaction binding the contract method 0x385c1d2f. +// +// Solidity: function multicallWithResults(bytes[] data, bool ignoreReverts) returns((bool,bytes)[] results) +func (_MulticallTarget *MulticallTargetTransactorSession) MulticallWithResults(data [][]byte, ignoreReverts bool) (*types.Transaction, error) { + return _MulticallTarget.Contract.MulticallWithResults(&_MulticallTarget.TransactOpts, data, ignoreReverts) +} + // SafeERC20MetaData contains all meta data concerning the SafeERC20 contract. var SafeERC20MetaData = &bind.MetaData{ ABI: "[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"currentAllowance\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"requestedDecrease\",\"type\":\"uint256\"}],\"name\":\"SafeERC20FailedDecreaseAllowance\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"}],\"name\":\"SafeERC20FailedOperation\",\"type\":\"error\"}]", - Bin: "0x60566037600b82828239805160001a607314602a57634e487b7160e01b600052600060045260246000fd5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600080fdfea2646970667358221220c9ee2b1c91328c4f3496cd535cd06e2517aa82f2297fd1e3b5006b41112840f764736f6c63430008140033", + Bin: "0x60566037600b82828239805160001a607314602a57634e487b7160e01b600052600060045260246000fd5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600080fdfea264697066735822122095b019b39709f79687d9e5b44e40378a5a332da0a4d6c1fd704a420d3d83d79564736f6c63430008140033", } // SafeERC20ABI is the input ABI used to generate the binding from. @@ -15044,7 +15550,7 @@ func (_SafeERC20 *SafeERC20TransactorRaw) Transact(opts *bind.TransactOpts, meth // UniversalTokenLibMetaData contains all meta data concerning the UniversalTokenLib contract. var UniversalTokenLibMetaData = &bind.MetaData{ ABI: "[]", - Bin: "0x60566037600b82828239805160001a607314602a57634e487b7160e01b600052600060045260246000fd5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600080fdfea26469706673582212202023f39864841dc931462dc7b8bdf9ede1735f580a13a3476b5bff0f5f9ca81b64736f6c63430008140033", + Bin: "0x60566037600b82828239805160001a607314602a57634e487b7160e01b600052600060045260246000fd5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600080fdfea264697066735822122087b87767f0bafa66071dc27ec91229435afb6d496e62ef4ad0e258952a2f5c9064736f6c63430008140033", } // UniversalTokenLibABI is the input ABI used to generate the binding from. diff --git a/services/rfq/contracts/testcontracts/fastbridgemockv2/fastbridgemockv2.contractinfo.json b/services/rfq/contracts/testcontracts/fastbridgemockv2/fastbridgemockv2.contractinfo.json index 63ccf6945f..0c0bd6d5ab 100644 --- a/services/rfq/contracts/testcontracts/fastbridgemockv2/fastbridgemockv2.contractinfo.json +++ b/services/rfq/contracts/testcontracts/fastbridgemockv2/fastbridgemockv2.contractinfo.json @@ -1 +1 @@ -{"solidity/FastBridgeMock.sol:AccessControl":{"code":"0x","runtime-code":"0x","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.20 ^0.8.20;\n\n// contracts/interfaces/IAdmin.sol\n\ninterface IAdmin {\n // ============ Events ============\n\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n event ChainGasAmountUpdated(uint256 oldChainGasAmount, uint256 newChainGasAmount);\n\n // ============ Methods ============\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n\n function setChainGasAmount(uint256 newChainGasAmount) external;\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/libs/Errors.sol\n\nerror DeadlineExceeded();\nerror DeadlineNotExceeded();\nerror DeadlineTooShort();\nerror InsufficientOutputAmount();\n\nerror MsgValueIncorrect();\nerror PoolNotFound();\nerror TokenAddressMismatch();\nerror TokenNotContract();\nerror TokenNotETH();\nerror TokensIdentical();\n\nerror ChainIncorrect();\nerror AmountIncorrect();\nerror ZeroAddress();\n\nerror DisputePeriodNotPassed();\nerror DisputePeriodPassed();\nerror SenderIncorrect();\nerror StatusIncorrect();\nerror TransactionIdIncorrect();\nerror TransactionRelayed();\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// contracts/libs/UniversalToken.sol\n\nlibrary UniversalTokenLib {\n using SafeERC20 for IERC20;\n\n address internal constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Transfers tokens to the given account. Reverts if transfer is not successful.\n /// @dev This might trigger fallback, if ETH is transferred to the contract.\n /// Make sure this can not lead to reentrancy attacks.\n function universalTransfer(address token, address to, uint256 value) internal {\n // Don't do anything, if need to send tokens to this address\n if (to == address(this)) return;\n // Don't do anything, if trying to send zero value\n if (value == 0) return;\n if (token == ETH_ADDRESS) {\n /// @dev Note: this can potentially lead to executing code in `to`.\n // solhint-disable-next-line avoid-low-level-calls\n (bool success,) = to.call{value: value}(\"\");\n require(success, \"ETH transfer failed\");\n } else {\n IERC20(token).safeTransfer(to, value);\n }\n }\n\n /// @notice Issues an infinite allowance to the spender, if the current allowance is insufficient\n /// to spend the given amount.\n function universalApproveInfinity(address token, address spender, uint256 amountToSpend) internal {\n // ETH Chad doesn't require your approval\n if (token == ETH_ADDRESS) return;\n // No-op if allowance is already sufficient\n uint256 allowance = IERC20(token).allowance(address(this), spender);\n if (allowance \u003e= amountToSpend) return;\n // Otherwise, reset approval to 0 and set to max allowance\n if (allowance \u003e 0) IERC20(token).safeDecreaseAllowance(spender, allowance);\n IERC20(token).safeIncreaseAllowance(spender, type(uint256).max);\n }\n\n /// @notice Returns the balance of the given token (or native ETH) for the given account.\n function universalBalanceOf(address token, address account) internal view returns (uint256) {\n if (token == ETH_ADDRESS) {\n return account.balance;\n } else {\n return IERC20(token).balanceOf(account);\n }\n }\n\n /// @dev Checks that token is a contract and not ETH_ADDRESS.\n function assertIsContract(address token) internal view {\n // Check that ETH_ADDRESS was not used (in case this is a predeploy on any of the chains)\n if (token == UniversalTokenLib.ETH_ADDRESS) revert TokenNotContract();\n // Check that token is not an EOA\n if (token.code.length == 0) revert TokenNotContract();\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/Admin.sol\n\ncontract Admin is IAdmin, AccessControlEnumerable {\n using UniversalTokenLib for address;\n\n bytes32 public constant RELAYER_ROLE = keccak256(\"RELAYER_ROLE\");\n bytes32 public constant REFUNDER_ROLE = keccak256(\"REFUNDER_ROLE\");\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n uint256 public constant FEE_BPS = 1e6;\n uint256 public constant FEE_RATE_MAX = 0.01e6; // max 1% on origin amount\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Chain gas amount to forward as rebate if requested\n uint256 public chainGasAmount;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n }\n\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n require(newFeeRate \u003c= FEE_RATE_MAX, \"newFeeRate \u003e max\");\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n token.universalTransfer(recipient, feeAmount);\n emit FeesSwept(token, recipient, feeAmount);\n }\n\n function setChainGasAmount(uint256 newChainGasAmount) external onlyRole(GOVERNOR_ROLE) {\n uint256 oldChainGasAmount = chainGasAmount;\n chainGasAmount = newChainGasAmount;\n emit ChainGasAmountUpdated(oldChainGasAmount, newChainGasAmount);\n }\n}\n\n// contracts/FastBridge.sol\n\ncontract FastBridge is IFastBridge, Admin {\n using SafeERC20 for IERC20;\n using UniversalTokenLib for address;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Delay for a transaction after which it could be permisionlessly refunded\n uint256 public constant REFUND_DELAY = 7 days;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeStatus) public bridgeStatuses;\n /// @notice Proof of relayed bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeProof) public bridgeProofs;\n /// @notice Whether bridge has been relayed on destination chain\n mapping(bytes32 =\u003e bool) public bridgeRelays;\n\n /// @dev to prevent replays\n uint256 public nonce;\n // @dev the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @notice Pulls a requested token from the user to the requested recipient.\n /// @dev Be careful of re-entrancy issues when msg.value \u003e 0 and recipient != address(this)\n function _pullToken(address recipient, address token, uint256 amount) internal returns (uint256 amountPulled) {\n if (token != UniversalTokenLib.ETH_ADDRESS) {\n token.assertIsContract();\n // Record token balance before transfer\n amountPulled = IERC20(token).balanceOf(recipient);\n // Token needs to be pulled only if msg.value is zero\n // This way user can specify WETH as the origin asset\n IERC20(token).safeTransferFrom(msg.sender, recipient, amount);\n // Use the difference between the recorded balance and the current balance as the amountPulled\n amountPulled = IERC20(token).balanceOf(recipient) - amountPulled;\n } else {\n // Otherwise, we need to check that ETH amount matches msg.value\n if (amount != msg.value) revert MsgValueIncorrect();\n // Transfer value to recipient if not this address\n if (recipient != address(this)) token.universalTransfer(recipient, amount);\n // We will forward msg.value in the external call later, if recipient is not this contract\n amountPulled = msg.value;\n }\n }\n\n /// @inheritdoc IFastBridge\n function getBridgeTransaction(bytes memory request) public pure returns (BridgeTransaction memory) {\n return abi.decode(request, (BridgeTransaction));\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n // check bridge params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n\n // transfer tokens to bridge contract\n // @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _pullToken(address(this), params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n\n // set status to requested\n bytes memory request = abi.encode(\n BridgeTransaction({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n sendChainGas: params.sendChainGas,\n deadline: params.deadline,\n nonce: nonce++ // increment nonce on every bridge\n })\n );\n bytes32 transactionId = keccak256(request);\n bridgeStatuses[transactionId] = BridgeStatus.REQUESTED;\n\n emit BridgeRequested(\n transactionId,\n params.sender,\n request,\n params.dstChainId,\n params.originToken,\n params.destToken,\n originAmount,\n params.destAmount,\n params.sendChainGas\n );\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes memory request) external payable onlyRole(RELAYER_ROLE) {\n bytes32 transactionId = keccak256(request);\n BridgeTransaction memory transaction = getBridgeTransaction(request);\n if (transaction.destChainId != uint32(block.chainid)) revert ChainIncorrect();\n\n // check haven't exceeded deadline for relay to happen\n if (block.timestamp \u003e transaction.deadline) revert DeadlineExceeded();\n\n // mark bridge transaction as relayed\n if (bridgeRelays[transactionId]) revert TransactionRelayed();\n bridgeRelays[transactionId] = true;\n\n // transfer tokens to recipient on destination chain and gas rebate if requested\n address to = transaction.destRecipient;\n address token = transaction.destToken;\n uint256 amount = transaction.destAmount;\n\n uint256 rebate = chainGasAmount;\n if (!transaction.sendChainGas) {\n // forward erc20\n rebate = 0;\n _pullToken(to, token, amount);\n } else if (token == UniversalTokenLib.ETH_ADDRESS) {\n // lump in gas rebate into amount in native gas token\n _pullToken(to, token, amount + rebate);\n } else {\n // forward erc20 then forward gas rebate in native gas token\n _pullToken(to, token, amount);\n _pullToken(to, UniversalTokenLib.ETH_ADDRESS, rebate);\n }\n\n emit BridgeRelayed(\n transactionId,\n msg.sender,\n to,\n transaction.originChainId,\n transaction.originToken,\n transaction.destToken,\n transaction.originAmount,\n transaction.destAmount,\n rebate\n );\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes memory request, bytes32 destTxHash) external onlyRole(RELAYER_ROLE) {\n bytes32 transactionId = keccak256(request);\n // update bridge tx status given proof provided\n if (bridgeStatuses[transactionId] != BridgeStatus.REQUESTED) revert StatusIncorrect();\n bridgeStatuses[transactionId] = BridgeStatus.RELAYER_PROVED;\n bridgeProofs[transactionId] = BridgeProof({timestamp: uint96(block.timestamp), relayer: msg.sender}); // overflow ok\n\n emit BridgeProofProvided(transactionId, msg.sender, destTxHash);\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint96(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint96).max but\n /// proof.timestamp \u003c type(uint96).max via unchecked statement\n /// @param proof The bridge proof\n /// @return delta Time delta since proof submitted\n function _timeSince(BridgeProof memory proof) internal view returns (uint256 delta) {\n unchecked {\n delta = uint96(block.timestamp) - proof.timestamp;\n }\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n if (bridgeStatuses[transactionId] != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n BridgeProof memory proof = bridgeProofs[transactionId];\n if (proof.relayer != relayer) revert SenderIncorrect();\n return _timeSince(proof) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes memory request, address to) external onlyRole(RELAYER_ROLE) {\n bytes32 transactionId = keccak256(request);\n BridgeTransaction memory transaction = getBridgeTransaction(request);\n\n // update bridge tx status if able to claim origin collateral\n if (bridgeStatuses[transactionId] != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n\n BridgeProof memory proof = bridgeProofs[transactionId];\n if (proof.relayer != msg.sender) revert SenderIncorrect();\n if (_timeSince(proof) \u003c= DISPUTE_PERIOD) revert DisputePeriodNotPassed();\n\n bridgeStatuses[transactionId] = BridgeStatus.RELAYER_CLAIMED;\n\n // update protocol fees if origin fee amount exists\n if (transaction.originFeeAmount \u003e 0) protocolFees[transaction.originToken] += transaction.originFeeAmount;\n\n // transfer origin collateral less fee to specified address\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositClaimed(transactionId, msg.sender, to, token, amount);\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n if (bridgeStatuses[transactionId] != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(bridgeProofs[transactionId]) \u003e DISPUTE_PERIOD) revert DisputePeriodPassed();\n\n // @dev relayer gets slashed effectively if dest relay has gone thru\n bridgeStatuses[transactionId] = BridgeStatus.REQUESTED;\n delete bridgeProofs[transactionId];\n\n emit BridgeProofDisputed(transactionId, msg.sender);\n }\n\n /// @inheritdoc IFastBridge\n function refund(bytes memory request) external {\n bytes32 transactionId = keccak256(request);\n BridgeTransaction memory transaction = getBridgeTransaction(request);\n\n if (hasRole(REFUNDER_ROLE, msg.sender)) {\n // Refunder can refund if deadline has passed\n if (block.timestamp \u003c= transaction.deadline) revert DeadlineNotExceeded();\n } else {\n // Permissionless refund is allowed after REFUND_DELAY\n if (block.timestamp \u003c= transaction.deadline + REFUND_DELAY) revert DeadlineNotExceeded();\n }\n\n // set status to refunded if still in requested state\n if (bridgeStatuses[transactionId] != BridgeStatus.REQUESTED) revert StatusIncorrect();\n bridgeStatuses[transactionId] = BridgeStatus.REFUNDED;\n\n // transfer origin collateral back to original sender\n address to = transaction.originSender;\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount + transaction.originFeeAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n }\n}\n\n// test/FastBridgeMock.sol\n\ncontract FastBridgeMock is IFastBridge, Admin {\n // @dev the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @dev to prevent replays\n uint256 public nonce;\n\n function getBridgeTransaction(bytes memory request) public pure returns (BridgeTransaction memory) {\n return abi.decode(request, (BridgeTransaction));\n }\n\n // used for testing in go.\n // see: https://ethereum.stackexchange.com/questions/21155/how-to-expose-enum-in-solidity-contract\n // make sure to update fastbridge/status.go if this changes\n // or underliyng enum changes.\n //\n // TODO: a foundry test should be added to ensure this is always in sync.\n function getEnumKeyByValue(FastBridge.BridgeStatus keyValue) public pure returns (string memory) {\n if (FastBridge.BridgeStatus.NULL == keyValue) return \"NULL\";\n if (FastBridge.BridgeStatus.REQUESTED == keyValue) return \"REQUESTED\";\n if (FastBridge.BridgeStatus.RELAYER_PROVED == keyValue) return \"RELAYER_PROVED\";\n if (FastBridge.BridgeStatus.RELAYER_CLAIMED == keyValue) return \"RELAYER_CLAIMED\";\n if (FastBridge.BridgeStatus.REFUNDED == keyValue) return \"REFUNDED\";\n return \"\";\n }\n\n function mockBridgeRequest(bytes32 transactionId, address sender, BridgeParams memory params) external {\n uint256 originFeeAmount = (params.originAmount * protocolFeeRate) / FEE_BPS;\n params.originAmount -= originFeeAmount;\n\n bytes memory request = abi.encode(\n BridgeTransaction({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: params.originAmount, // includes relayer fee\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n sendChainGas: params.sendChainGas,\n deadline: params.deadline,\n nonce: nonce++ // increment nonce on every bridge\n })\n );\n\n emit BridgeRequested(\n transactionId,\n params.sender,\n request,\n params.dstChainId,\n params.originToken,\n params.destToken,\n params.originAmount,\n params.destAmount,\n params.sendChainGas\n );\n }\n\n function mockBridgeRequestRaw(bytes32 transactionId, address sender, bytes memory request) external {\n BridgeTransaction memory transaction = getBridgeTransaction(request);\n emit BridgeRequested(\n transactionId,\n transaction.originSender,\n request,\n transaction.destChainId,\n transaction.originToken,\n transaction.destToken,\n transaction.originAmount,\n transaction.destAmount,\n transaction.sendChainGas\n );\n }\n\n function mockBridgeRelayer(\n bytes32 transactionId,\n address relayer,\n address to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n )\n external\n {\n emit BridgeRelayed(\n transactionId, relayer, to, originChainId, originToken, destToken, originAmount, destAmount, chainGasAmount\n );\n }\n\n function bridge(BridgeParams memory params) external payable {\n revert(\"not implemented\");\n }\n\n function relay(bytes memory request) external payable {\n revert(\"not implemented\");\n }\n\n function prove(bytes memory request, bytes32 destTxHash) external {\n revert(\"not implemented\");\n }\n\n function canClaim(bytes32 transactionid, address relayer) external view returns (bool) {\n revert(\"not implemented\");\n }\n\n function claim(bytes memory request, address to) external {\n revert(\"not implemented\");\n }\n\n function dispute(bytes32 transactionId) external {\n revert(\"not implemented\");\n }\n\n function refund(bytes memory request) external {\n revert(\"not implemented\");\n }\n}\n","language":"Solidity","languageVersion":"0.8.20","compilerVersion":"0.8.20","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"","srcMapRuntime":"","abiDefinition":[{"inputs":[],"name":"AccessControlBadConfirmation","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"bytes32","name":"neededRole","type":"bytes32"}],"name":"AccessControlUnauthorizedAccount","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"previousAdminRole","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"newAdminRole","type":"bytes32"}],"name":"RoleAdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleRevoked","type":"event"},{"inputs":[],"name":"DEFAULT_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleAdmin","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"grantRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"hasRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"callerConfirmation","type":"address"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"revokeRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"}],"userDoc":{"kind":"user","methods":{},"version":1},"developerDoc":{"details":"Contract module that allows children to implement role-based access control mechanisms. This is a lightweight version that doesn't allow enumerating role members except through off-chain means by accessing the contract event logs. Some applications may benefit from on-chain enumerability, for those cases see {AccessControlEnumerable}. Roles are referred to by their `bytes32` identifier. These should be exposed in the external API and be unique. The best way to achieve this is by using `public constant` hash digests: ```solidity bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\"); ``` Roles can be used to represent a set of permissions. To restrict access to a function call, use {hasRole}: ```solidity function foo() public { require(hasRole(MY_ROLE, msg.sender)); ... } ``` Roles can be granted and revoked dynamically via the {grantRole} and {revokeRole} functions. Each role has an associated admin role, and only accounts that have a role's admin role can call {grantRole} and {revokeRole}. By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means that only accounts with this role will be able to grant or revoke other roles. More complex role relationships can be created by using {_setRoleAdmin}. WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to grant and revoke this role. Extra precautions should be taken to secure accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules} to enforce additional security measures for this role.","errors":{"AccessControlBadConfirmation()":[{"details":"The caller of a function is not the expected one. NOTE: Don't confuse with {AccessControlUnauthorizedAccount}."}],"AccessControlUnauthorizedAccount(address,bytes32)":[{"details":"The `account` is missing a role."}]},"events":{"RoleAdminChanged(bytes32,bytes32,bytes32)":{"details":"Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole` `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite {RoleAdminChanged} not being emitted signaling this."},"RoleGranted(bytes32,address,address)":{"details":"Emitted when `account` is granted `role`. `sender` is the account that originated the contract call, an admin role bearer except when using {AccessControl-_setupRole}."},"RoleRevoked(bytes32,address,address)":{"details":"Emitted when `account` is revoked `role`. `sender` is the account that originated the contract call: - if using `revokeRole`, it is the admin role bearer - if using `renounceRole`, it is the role bearer (i.e. `account`)"}},"kind":"dev","methods":{"getRoleAdmin(bytes32)":{"details":"Returns the admin role that controls `role`. See {grantRole} and {revokeRole}. To change a role's admin, use {_setRoleAdmin}."},"grantRole(bytes32,address)":{"details":"Grants `role` to `account`. If `account` had not been already granted `role`, emits a {RoleGranted} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleGranted} event."},"hasRole(bytes32,address)":{"details":"Returns `true` if `account` has been granted `role`."},"renounceRole(bytes32,address)":{"details":"Revokes `role` from the calling account. Roles are often managed via {grantRole} and {revokeRole}: this function's purpose is to provide a mechanism for accounts to lose their privileges if they are compromised (such as when a trusted device is misplaced). If the calling account had been revoked `role`, emits a {RoleRevoked} event. Requirements: - the caller must be `callerConfirmation`. May emit a {RoleRevoked} event."},"revokeRole(bytes32,address)":{"details":"Revokes `role` from `account`. If `account` had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleRevoked} event."},"supportsInterface(bytes4)":{"details":"See {IERC165-supportsInterface}."}},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.20+commit.a1b79de6\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[],\"name\":\"AccessControlBadConfirmation\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"neededRole\",\"type\":\"bytes32\"}],\"name\":\"AccessControlUnauthorizedAccount\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"previousAdminRole\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"newAdminRole\",\"type\":\"bytes32\"}],\"name\":\"RoleAdminChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleGranted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleRevoked\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"DEFAULT_ADMIN_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"}],\"name\":\"getRoleAdmin\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"grantRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"hasRole\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"callerConfirmation\",\"type\":\"address\"}],\"name\":\"renounceRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"revokeRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes4\",\"name\":\"interfaceId\",\"type\":\"bytes4\"}],\"name\":\"supportsInterface\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"}],\"devdoc\":{\"details\":\"Contract module that allows children to implement role-based access control mechanisms. This is a lightweight version that doesn't allow enumerating role members except through off-chain means by accessing the contract event logs. Some applications may benefit from on-chain enumerability, for those cases see {AccessControlEnumerable}. Roles are referred to by their `bytes32` identifier. These should be exposed in the external API and be unique. The best way to achieve this is by using `public constant` hash digests: ```solidity bytes32 public constant MY_ROLE = keccak256(\\\"MY_ROLE\\\"); ``` Roles can be used to represent a set of permissions. To restrict access to a function call, use {hasRole}: ```solidity function foo() public { require(hasRole(MY_ROLE, msg.sender)); ... } ``` Roles can be granted and revoked dynamically via the {grantRole} and {revokeRole} functions. Each role has an associated admin role, and only accounts that have a role's admin role can call {grantRole} and {revokeRole}. By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means that only accounts with this role will be able to grant or revoke other roles. More complex role relationships can be created by using {_setRoleAdmin}. WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to grant and revoke this role. Extra precautions should be taken to secure accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules} to enforce additional security measures for this role.\",\"errors\":{\"AccessControlBadConfirmation()\":[{\"details\":\"The caller of a function is not the expected one. NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\"}],\"AccessControlUnauthorizedAccount(address,bytes32)\":[{\"details\":\"The `account` is missing a role.\"}]},\"events\":{\"RoleAdminChanged(bytes32,bytes32,bytes32)\":{\"details\":\"Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole` `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite {RoleAdminChanged} not being emitted signaling this.\"},\"RoleGranted(bytes32,address,address)\":{\"details\":\"Emitted when `account` is granted `role`. `sender` is the account that originated the contract call, an admin role bearer except when using {AccessControl-_setupRole}.\"},\"RoleRevoked(bytes32,address,address)\":{\"details\":\"Emitted when `account` is revoked `role`. `sender` is the account that originated the contract call: - if using `revokeRole`, it is the admin role bearer - if using `renounceRole`, it is the role bearer (i.e. `account`)\"}},\"kind\":\"dev\",\"methods\":{\"getRoleAdmin(bytes32)\":{\"details\":\"Returns the admin role that controls `role`. See {grantRole} and {revokeRole}. To change a role's admin, use {_setRoleAdmin}.\"},\"grantRole(bytes32,address)\":{\"details\":\"Grants `role` to `account`. If `account` had not been already granted `role`, emits a {RoleGranted} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleGranted} event.\"},\"hasRole(bytes32,address)\":{\"details\":\"Returns `true` if `account` has been granted `role`.\"},\"renounceRole(bytes32,address)\":{\"details\":\"Revokes `role` from the calling account. Roles are often managed via {grantRole} and {revokeRole}: this function's purpose is to provide a mechanism for accounts to lose their privileges if they are compromised (such as when a trusted device is misplaced). If the calling account had been revoked `role`, emits a {RoleRevoked} event. Requirements: - the caller must be `callerConfirmation`. May emit a {RoleRevoked} event.\"},\"revokeRole(bytes32,address)\":{\"details\":\"Revokes `role` from `account`. If `account` had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleRevoked} event.\"},\"supportsInterface(bytes4)\":{\"details\":\"See {IERC165-supportsInterface}.\"}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeMock.sol\":\"AccessControl\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeMock.sol\":{\"keccak256\":\"0x620e81214ecd324ae8b971219291f176c454ce76fb1c01d656428096da8f1366\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://18e556772c12e13aa2d52a50cc7c48e676c8d5af22b90adaf7befb39cdd08e64\",\"dweb:/ipfs/QmPrQc98TxHCFMeuFNADyjr6Nqo52rHhHy1LBcsVdMRXjL\"]}},\"version\":1}"},"hashes":{"DEFAULT_ADMIN_ROLE()":"a217fddf","getRoleAdmin(bytes32)":"248a9ca3","grantRole(bytes32,address)":"2f2ff15d","hasRole(bytes32,address)":"91d14854","renounceRole(bytes32,address)":"36568abe","revokeRole(bytes32,address)":"d547741f","supportsInterface(bytes4)":"01ffc9a7"}},"solidity/FastBridgeMock.sol:AccessControlEnumerable":{"code":"0x","runtime-code":"0x","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.20 ^0.8.20;\n\n// contracts/interfaces/IAdmin.sol\n\ninterface IAdmin {\n // ============ Events ============\n\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n event ChainGasAmountUpdated(uint256 oldChainGasAmount, uint256 newChainGasAmount);\n\n // ============ Methods ============\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n\n function setChainGasAmount(uint256 newChainGasAmount) external;\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/libs/Errors.sol\n\nerror DeadlineExceeded();\nerror DeadlineNotExceeded();\nerror DeadlineTooShort();\nerror InsufficientOutputAmount();\n\nerror MsgValueIncorrect();\nerror PoolNotFound();\nerror TokenAddressMismatch();\nerror TokenNotContract();\nerror TokenNotETH();\nerror TokensIdentical();\n\nerror ChainIncorrect();\nerror AmountIncorrect();\nerror ZeroAddress();\n\nerror DisputePeriodNotPassed();\nerror DisputePeriodPassed();\nerror SenderIncorrect();\nerror StatusIncorrect();\nerror TransactionIdIncorrect();\nerror TransactionRelayed();\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// contracts/libs/UniversalToken.sol\n\nlibrary UniversalTokenLib {\n using SafeERC20 for IERC20;\n\n address internal constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Transfers tokens to the given account. Reverts if transfer is not successful.\n /// @dev This might trigger fallback, if ETH is transferred to the contract.\n /// Make sure this can not lead to reentrancy attacks.\n function universalTransfer(address token, address to, uint256 value) internal {\n // Don't do anything, if need to send tokens to this address\n if (to == address(this)) return;\n // Don't do anything, if trying to send zero value\n if (value == 0) return;\n if (token == ETH_ADDRESS) {\n /// @dev Note: this can potentially lead to executing code in `to`.\n // solhint-disable-next-line avoid-low-level-calls\n (bool success,) = to.call{value: value}(\"\");\n require(success, \"ETH transfer failed\");\n } else {\n IERC20(token).safeTransfer(to, value);\n }\n }\n\n /// @notice Issues an infinite allowance to the spender, if the current allowance is insufficient\n /// to spend the given amount.\n function universalApproveInfinity(address token, address spender, uint256 amountToSpend) internal {\n // ETH Chad doesn't require your approval\n if (token == ETH_ADDRESS) return;\n // No-op if allowance is already sufficient\n uint256 allowance = IERC20(token).allowance(address(this), spender);\n if (allowance \u003e= amountToSpend) return;\n // Otherwise, reset approval to 0 and set to max allowance\n if (allowance \u003e 0) IERC20(token).safeDecreaseAllowance(spender, allowance);\n IERC20(token).safeIncreaseAllowance(spender, type(uint256).max);\n }\n\n /// @notice Returns the balance of the given token (or native ETH) for the given account.\n function universalBalanceOf(address token, address account) internal view returns (uint256) {\n if (token == ETH_ADDRESS) {\n return account.balance;\n } else {\n return IERC20(token).balanceOf(account);\n }\n }\n\n /// @dev Checks that token is a contract and not ETH_ADDRESS.\n function assertIsContract(address token) internal view {\n // Check that ETH_ADDRESS was not used (in case this is a predeploy on any of the chains)\n if (token == UniversalTokenLib.ETH_ADDRESS) revert TokenNotContract();\n // Check that token is not an EOA\n if (token.code.length == 0) revert TokenNotContract();\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/Admin.sol\n\ncontract Admin is IAdmin, AccessControlEnumerable {\n using UniversalTokenLib for address;\n\n bytes32 public constant RELAYER_ROLE = keccak256(\"RELAYER_ROLE\");\n bytes32 public constant REFUNDER_ROLE = keccak256(\"REFUNDER_ROLE\");\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n uint256 public constant FEE_BPS = 1e6;\n uint256 public constant FEE_RATE_MAX = 0.01e6; // max 1% on origin amount\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Chain gas amount to forward as rebate if requested\n uint256 public chainGasAmount;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n }\n\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n require(newFeeRate \u003c= FEE_RATE_MAX, \"newFeeRate \u003e max\");\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n token.universalTransfer(recipient, feeAmount);\n emit FeesSwept(token, recipient, feeAmount);\n }\n\n function setChainGasAmount(uint256 newChainGasAmount) external onlyRole(GOVERNOR_ROLE) {\n uint256 oldChainGasAmount = chainGasAmount;\n chainGasAmount = newChainGasAmount;\n emit ChainGasAmountUpdated(oldChainGasAmount, newChainGasAmount);\n }\n}\n\n// contracts/FastBridge.sol\n\ncontract FastBridge is IFastBridge, Admin {\n using SafeERC20 for IERC20;\n using UniversalTokenLib for address;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Delay for a transaction after which it could be permisionlessly refunded\n uint256 public constant REFUND_DELAY = 7 days;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeStatus) public bridgeStatuses;\n /// @notice Proof of relayed bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeProof) public bridgeProofs;\n /// @notice Whether bridge has been relayed on destination chain\n mapping(bytes32 =\u003e bool) public bridgeRelays;\n\n /// @dev to prevent replays\n uint256 public nonce;\n // @dev the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @notice Pulls a requested token from the user to the requested recipient.\n /// @dev Be careful of re-entrancy issues when msg.value \u003e 0 and recipient != address(this)\n function _pullToken(address recipient, address token, uint256 amount) internal returns (uint256 amountPulled) {\n if (token != UniversalTokenLib.ETH_ADDRESS) {\n token.assertIsContract();\n // Record token balance before transfer\n amountPulled = IERC20(token).balanceOf(recipient);\n // Token needs to be pulled only if msg.value is zero\n // This way user can specify WETH as the origin asset\n IERC20(token).safeTransferFrom(msg.sender, recipient, amount);\n // Use the difference between the recorded balance and the current balance as the amountPulled\n amountPulled = IERC20(token).balanceOf(recipient) - amountPulled;\n } else {\n // Otherwise, we need to check that ETH amount matches msg.value\n if (amount != msg.value) revert MsgValueIncorrect();\n // Transfer value to recipient if not this address\n if (recipient != address(this)) token.universalTransfer(recipient, amount);\n // We will forward msg.value in the external call later, if recipient is not this contract\n amountPulled = msg.value;\n }\n }\n\n /// @inheritdoc IFastBridge\n function getBridgeTransaction(bytes memory request) public pure returns (BridgeTransaction memory) {\n return abi.decode(request, (BridgeTransaction));\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n // check bridge params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n\n // transfer tokens to bridge contract\n // @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _pullToken(address(this), params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n\n // set status to requested\n bytes memory request = abi.encode(\n BridgeTransaction({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n sendChainGas: params.sendChainGas,\n deadline: params.deadline,\n nonce: nonce++ // increment nonce on every bridge\n })\n );\n bytes32 transactionId = keccak256(request);\n bridgeStatuses[transactionId] = BridgeStatus.REQUESTED;\n\n emit BridgeRequested(\n transactionId,\n params.sender,\n request,\n params.dstChainId,\n params.originToken,\n params.destToken,\n originAmount,\n params.destAmount,\n params.sendChainGas\n );\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes memory request) external payable onlyRole(RELAYER_ROLE) {\n bytes32 transactionId = keccak256(request);\n BridgeTransaction memory transaction = getBridgeTransaction(request);\n if (transaction.destChainId != uint32(block.chainid)) revert ChainIncorrect();\n\n // check haven't exceeded deadline for relay to happen\n if (block.timestamp \u003e transaction.deadline) revert DeadlineExceeded();\n\n // mark bridge transaction as relayed\n if (bridgeRelays[transactionId]) revert TransactionRelayed();\n bridgeRelays[transactionId] = true;\n\n // transfer tokens to recipient on destination chain and gas rebate if requested\n address to = transaction.destRecipient;\n address token = transaction.destToken;\n uint256 amount = transaction.destAmount;\n\n uint256 rebate = chainGasAmount;\n if (!transaction.sendChainGas) {\n // forward erc20\n rebate = 0;\n _pullToken(to, token, amount);\n } else if (token == UniversalTokenLib.ETH_ADDRESS) {\n // lump in gas rebate into amount in native gas token\n _pullToken(to, token, amount + rebate);\n } else {\n // forward erc20 then forward gas rebate in native gas token\n _pullToken(to, token, amount);\n _pullToken(to, UniversalTokenLib.ETH_ADDRESS, rebate);\n }\n\n emit BridgeRelayed(\n transactionId,\n msg.sender,\n to,\n transaction.originChainId,\n transaction.originToken,\n transaction.destToken,\n transaction.originAmount,\n transaction.destAmount,\n rebate\n );\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes memory request, bytes32 destTxHash) external onlyRole(RELAYER_ROLE) {\n bytes32 transactionId = keccak256(request);\n // update bridge tx status given proof provided\n if (bridgeStatuses[transactionId] != BridgeStatus.REQUESTED) revert StatusIncorrect();\n bridgeStatuses[transactionId] = BridgeStatus.RELAYER_PROVED;\n bridgeProofs[transactionId] = BridgeProof({timestamp: uint96(block.timestamp), relayer: msg.sender}); // overflow ok\n\n emit BridgeProofProvided(transactionId, msg.sender, destTxHash);\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint96(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint96).max but\n /// proof.timestamp \u003c type(uint96).max via unchecked statement\n /// @param proof The bridge proof\n /// @return delta Time delta since proof submitted\n function _timeSince(BridgeProof memory proof) internal view returns (uint256 delta) {\n unchecked {\n delta = uint96(block.timestamp) - proof.timestamp;\n }\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n if (bridgeStatuses[transactionId] != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n BridgeProof memory proof = bridgeProofs[transactionId];\n if (proof.relayer != relayer) revert SenderIncorrect();\n return _timeSince(proof) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes memory request, address to) external onlyRole(RELAYER_ROLE) {\n bytes32 transactionId = keccak256(request);\n BridgeTransaction memory transaction = getBridgeTransaction(request);\n\n // update bridge tx status if able to claim origin collateral\n if (bridgeStatuses[transactionId] != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n\n BridgeProof memory proof = bridgeProofs[transactionId];\n if (proof.relayer != msg.sender) revert SenderIncorrect();\n if (_timeSince(proof) \u003c= DISPUTE_PERIOD) revert DisputePeriodNotPassed();\n\n bridgeStatuses[transactionId] = BridgeStatus.RELAYER_CLAIMED;\n\n // update protocol fees if origin fee amount exists\n if (transaction.originFeeAmount \u003e 0) protocolFees[transaction.originToken] += transaction.originFeeAmount;\n\n // transfer origin collateral less fee to specified address\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositClaimed(transactionId, msg.sender, to, token, amount);\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n if (bridgeStatuses[transactionId] != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(bridgeProofs[transactionId]) \u003e DISPUTE_PERIOD) revert DisputePeriodPassed();\n\n // @dev relayer gets slashed effectively if dest relay has gone thru\n bridgeStatuses[transactionId] = BridgeStatus.REQUESTED;\n delete bridgeProofs[transactionId];\n\n emit BridgeProofDisputed(transactionId, msg.sender);\n }\n\n /// @inheritdoc IFastBridge\n function refund(bytes memory request) external {\n bytes32 transactionId = keccak256(request);\n BridgeTransaction memory transaction = getBridgeTransaction(request);\n\n if (hasRole(REFUNDER_ROLE, msg.sender)) {\n // Refunder can refund if deadline has passed\n if (block.timestamp \u003c= transaction.deadline) revert DeadlineNotExceeded();\n } else {\n // Permissionless refund is allowed after REFUND_DELAY\n if (block.timestamp \u003c= transaction.deadline + REFUND_DELAY) revert DeadlineNotExceeded();\n }\n\n // set status to refunded if still in requested state\n if (bridgeStatuses[transactionId] != BridgeStatus.REQUESTED) revert StatusIncorrect();\n bridgeStatuses[transactionId] = BridgeStatus.REFUNDED;\n\n // transfer origin collateral back to original sender\n address to = transaction.originSender;\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount + transaction.originFeeAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n }\n}\n\n// test/FastBridgeMock.sol\n\ncontract FastBridgeMock is IFastBridge, Admin {\n // @dev the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @dev to prevent replays\n uint256 public nonce;\n\n function getBridgeTransaction(bytes memory request) public pure returns (BridgeTransaction memory) {\n return abi.decode(request, (BridgeTransaction));\n }\n\n // used for testing in go.\n // see: https://ethereum.stackexchange.com/questions/21155/how-to-expose-enum-in-solidity-contract\n // make sure to update fastbridge/status.go if this changes\n // or underliyng enum changes.\n //\n // TODO: a foundry test should be added to ensure this is always in sync.\n function getEnumKeyByValue(FastBridge.BridgeStatus keyValue) public pure returns (string memory) {\n if (FastBridge.BridgeStatus.NULL == keyValue) return \"NULL\";\n if (FastBridge.BridgeStatus.REQUESTED == keyValue) return \"REQUESTED\";\n if (FastBridge.BridgeStatus.RELAYER_PROVED == keyValue) return \"RELAYER_PROVED\";\n if (FastBridge.BridgeStatus.RELAYER_CLAIMED == keyValue) return \"RELAYER_CLAIMED\";\n if (FastBridge.BridgeStatus.REFUNDED == keyValue) return \"REFUNDED\";\n return \"\";\n }\n\n function mockBridgeRequest(bytes32 transactionId, address sender, BridgeParams memory params) external {\n uint256 originFeeAmount = (params.originAmount * protocolFeeRate) / FEE_BPS;\n params.originAmount -= originFeeAmount;\n\n bytes memory request = abi.encode(\n BridgeTransaction({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: params.originAmount, // includes relayer fee\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n sendChainGas: params.sendChainGas,\n deadline: params.deadline,\n nonce: nonce++ // increment nonce on every bridge\n })\n );\n\n emit BridgeRequested(\n transactionId,\n params.sender,\n request,\n params.dstChainId,\n params.originToken,\n params.destToken,\n params.originAmount,\n params.destAmount,\n params.sendChainGas\n );\n }\n\n function mockBridgeRequestRaw(bytes32 transactionId, address sender, bytes memory request) external {\n BridgeTransaction memory transaction = getBridgeTransaction(request);\n emit BridgeRequested(\n transactionId,\n transaction.originSender,\n request,\n transaction.destChainId,\n transaction.originToken,\n transaction.destToken,\n transaction.originAmount,\n transaction.destAmount,\n transaction.sendChainGas\n );\n }\n\n function mockBridgeRelayer(\n bytes32 transactionId,\n address relayer,\n address to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n )\n external\n {\n emit BridgeRelayed(\n transactionId, relayer, to, originChainId, originToken, destToken, originAmount, destAmount, chainGasAmount\n );\n }\n\n function bridge(BridgeParams memory params) external payable {\n revert(\"not implemented\");\n }\n\n function relay(bytes memory request) external payable {\n revert(\"not implemented\");\n }\n\n function prove(bytes memory request, bytes32 destTxHash) external {\n revert(\"not implemented\");\n }\n\n function canClaim(bytes32 transactionid, address relayer) external view returns (bool) {\n revert(\"not implemented\");\n }\n\n function claim(bytes memory request, address to) external {\n revert(\"not implemented\");\n }\n\n function dispute(bytes32 transactionId) external {\n revert(\"not implemented\");\n }\n\n function refund(bytes memory request) external {\n revert(\"not implemented\");\n }\n}\n","language":"Solidity","languageVersion":"0.8.20","compilerVersion":"0.8.20","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"","srcMapRuntime":"","abiDefinition":[{"inputs":[],"name":"AccessControlBadConfirmation","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"bytes32","name":"neededRole","type":"bytes32"}],"name":"AccessControlUnauthorizedAccount","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"previousAdminRole","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"newAdminRole","type":"bytes32"}],"name":"RoleAdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleRevoked","type":"event"},{"inputs":[],"name":"DEFAULT_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleAdmin","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"uint256","name":"index","type":"uint256"}],"name":"getRoleMember","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleMemberCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"grantRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"hasRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"callerConfirmation","type":"address"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"revokeRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"}],"userDoc":{"kind":"user","methods":{},"version":1},"developerDoc":{"details":"Extension of {AccessControl} that allows enumerating the members of each role.","errors":{"AccessControlBadConfirmation()":[{"details":"The caller of a function is not the expected one. NOTE: Don't confuse with {AccessControlUnauthorizedAccount}."}],"AccessControlUnauthorizedAccount(address,bytes32)":[{"details":"The `account` is missing a role."}]},"events":{"RoleAdminChanged(bytes32,bytes32,bytes32)":{"details":"Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole` `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite {RoleAdminChanged} not being emitted signaling this."},"RoleGranted(bytes32,address,address)":{"details":"Emitted when `account` is granted `role`. `sender` is the account that originated the contract call, an admin role bearer except when using {AccessControl-_setupRole}."},"RoleRevoked(bytes32,address,address)":{"details":"Emitted when `account` is revoked `role`. `sender` is the account that originated the contract call: - if using `revokeRole`, it is the admin role bearer - if using `renounceRole`, it is the role bearer (i.e. `account`)"}},"kind":"dev","methods":{"getRoleAdmin(bytes32)":{"details":"Returns the admin role that controls `role`. See {grantRole} and {revokeRole}. To change a role's admin, use {_setRoleAdmin}."},"getRoleMember(bytes32,uint256)":{"details":"Returns one of the accounts that have `role`. `index` must be a value between 0 and {getRoleMemberCount}, non-inclusive. Role bearers are not sorted in any particular way, and their ordering may change at any point. WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure you perform all queries on the same block. See the following https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post] for more information."},"getRoleMemberCount(bytes32)":{"details":"Returns the number of accounts that have `role`. Can be used together with {getRoleMember} to enumerate all bearers of a role."},"grantRole(bytes32,address)":{"details":"Grants `role` to `account`. If `account` had not been already granted `role`, emits a {RoleGranted} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleGranted} event."},"hasRole(bytes32,address)":{"details":"Returns `true` if `account` has been granted `role`."},"renounceRole(bytes32,address)":{"details":"Revokes `role` from the calling account. Roles are often managed via {grantRole} and {revokeRole}: this function's purpose is to provide a mechanism for accounts to lose their privileges if they are compromised (such as when a trusted device is misplaced). If the calling account had been revoked `role`, emits a {RoleRevoked} event. Requirements: - the caller must be `callerConfirmation`. May emit a {RoleRevoked} event."},"revokeRole(bytes32,address)":{"details":"Revokes `role` from `account`. If `account` had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleRevoked} event."},"supportsInterface(bytes4)":{"details":"See {IERC165-supportsInterface}."}},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.20+commit.a1b79de6\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[],\"name\":\"AccessControlBadConfirmation\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"neededRole\",\"type\":\"bytes32\"}],\"name\":\"AccessControlUnauthorizedAccount\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"previousAdminRole\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"newAdminRole\",\"type\":\"bytes32\"}],\"name\":\"RoleAdminChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleGranted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleRevoked\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"DEFAULT_ADMIN_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"}],\"name\":\"getRoleAdmin\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"index\",\"type\":\"uint256\"}],\"name\":\"getRoleMember\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"}],\"name\":\"getRoleMemberCount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"grantRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"hasRole\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"callerConfirmation\",\"type\":\"address\"}],\"name\":\"renounceRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"revokeRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes4\",\"name\":\"interfaceId\",\"type\":\"bytes4\"}],\"name\":\"supportsInterface\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"}],\"devdoc\":{\"details\":\"Extension of {AccessControl} that allows enumerating the members of each role.\",\"errors\":{\"AccessControlBadConfirmation()\":[{\"details\":\"The caller of a function is not the expected one. NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\"}],\"AccessControlUnauthorizedAccount(address,bytes32)\":[{\"details\":\"The `account` is missing a role.\"}]},\"events\":{\"RoleAdminChanged(bytes32,bytes32,bytes32)\":{\"details\":\"Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole` `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite {RoleAdminChanged} not being emitted signaling this.\"},\"RoleGranted(bytes32,address,address)\":{\"details\":\"Emitted when `account` is granted `role`. `sender` is the account that originated the contract call, an admin role bearer except when using {AccessControl-_setupRole}.\"},\"RoleRevoked(bytes32,address,address)\":{\"details\":\"Emitted when `account` is revoked `role`. `sender` is the account that originated the contract call: - if using `revokeRole`, it is the admin role bearer - if using `renounceRole`, it is the role bearer (i.e. `account`)\"}},\"kind\":\"dev\",\"methods\":{\"getRoleAdmin(bytes32)\":{\"details\":\"Returns the admin role that controls `role`. See {grantRole} and {revokeRole}. To change a role's admin, use {_setRoleAdmin}.\"},\"getRoleMember(bytes32,uint256)\":{\"details\":\"Returns one of the accounts that have `role`. `index` must be a value between 0 and {getRoleMemberCount}, non-inclusive. Role bearers are not sorted in any particular way, and their ordering may change at any point. WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure you perform all queries on the same block. See the following https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post] for more information.\"},\"getRoleMemberCount(bytes32)\":{\"details\":\"Returns the number of accounts that have `role`. Can be used together with {getRoleMember} to enumerate all bearers of a role.\"},\"grantRole(bytes32,address)\":{\"details\":\"Grants `role` to `account`. If `account` had not been already granted `role`, emits a {RoleGranted} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleGranted} event.\"},\"hasRole(bytes32,address)\":{\"details\":\"Returns `true` if `account` has been granted `role`.\"},\"renounceRole(bytes32,address)\":{\"details\":\"Revokes `role` from the calling account. Roles are often managed via {grantRole} and {revokeRole}: this function's purpose is to provide a mechanism for accounts to lose their privileges if they are compromised (such as when a trusted device is misplaced). If the calling account had been revoked `role`, emits a {RoleRevoked} event. Requirements: - the caller must be `callerConfirmation`. May emit a {RoleRevoked} event.\"},\"revokeRole(bytes32,address)\":{\"details\":\"Revokes `role` from `account`. If `account` had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleRevoked} event.\"},\"supportsInterface(bytes4)\":{\"details\":\"See {IERC165-supportsInterface}.\"}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeMock.sol\":\"AccessControlEnumerable\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeMock.sol\":{\"keccak256\":\"0x620e81214ecd324ae8b971219291f176c454ce76fb1c01d656428096da8f1366\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://18e556772c12e13aa2d52a50cc7c48e676c8d5af22b90adaf7befb39cdd08e64\",\"dweb:/ipfs/QmPrQc98TxHCFMeuFNADyjr6Nqo52rHhHy1LBcsVdMRXjL\"]}},\"version\":1}"},"hashes":{"DEFAULT_ADMIN_ROLE()":"a217fddf","getRoleAdmin(bytes32)":"248a9ca3","getRoleMember(bytes32,uint256)":"9010d07c","getRoleMemberCount(bytes32)":"ca15c873","grantRole(bytes32,address)":"2f2ff15d","hasRole(bytes32,address)":"91d14854","renounceRole(bytes32,address)":"36568abe","revokeRole(bytes32,address)":"d547741f","supportsInterface(bytes4)":"01ffc9a7"}},"solidity/FastBridgeMock.sol:Address":{"code":"0x60566037600b82828239805160001a607314602a57634e487b7160e01b600052600060045260246000fd5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600080fdfea264697066735822122083549ae8a6625896ee7f9ad3afb09c83f8f6b7f2c10b67bf18def7b2b300f36a64736f6c63430008140033","runtime-code":"0x73000000000000000000000000000000000000000030146080604052600080fdfea264697066735822122083549ae8a6625896ee7f9ad3afb09c83f8f6b7f2c10b67bf18def7b2b300f36a64736f6c63430008140033","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.20 ^0.8.20;\n\n// contracts/interfaces/IAdmin.sol\n\ninterface IAdmin {\n // ============ Events ============\n\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n event ChainGasAmountUpdated(uint256 oldChainGasAmount, uint256 newChainGasAmount);\n\n // ============ Methods ============\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n\n function setChainGasAmount(uint256 newChainGasAmount) external;\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/libs/Errors.sol\n\nerror DeadlineExceeded();\nerror DeadlineNotExceeded();\nerror DeadlineTooShort();\nerror InsufficientOutputAmount();\n\nerror MsgValueIncorrect();\nerror PoolNotFound();\nerror TokenAddressMismatch();\nerror TokenNotContract();\nerror TokenNotETH();\nerror TokensIdentical();\n\nerror ChainIncorrect();\nerror AmountIncorrect();\nerror ZeroAddress();\n\nerror DisputePeriodNotPassed();\nerror DisputePeriodPassed();\nerror SenderIncorrect();\nerror StatusIncorrect();\nerror TransactionIdIncorrect();\nerror TransactionRelayed();\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// contracts/libs/UniversalToken.sol\n\nlibrary UniversalTokenLib {\n using SafeERC20 for IERC20;\n\n address internal constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Transfers tokens to the given account. Reverts if transfer is not successful.\n /// @dev This might trigger fallback, if ETH is transferred to the contract.\n /// Make sure this can not lead to reentrancy attacks.\n function universalTransfer(address token, address to, uint256 value) internal {\n // Don't do anything, if need to send tokens to this address\n if (to == address(this)) return;\n // Don't do anything, if trying to send zero value\n if (value == 0) return;\n if (token == ETH_ADDRESS) {\n /// @dev Note: this can potentially lead to executing code in `to`.\n // solhint-disable-next-line avoid-low-level-calls\n (bool success,) = to.call{value: value}(\"\");\n require(success, \"ETH transfer failed\");\n } else {\n IERC20(token).safeTransfer(to, value);\n }\n }\n\n /// @notice Issues an infinite allowance to the spender, if the current allowance is insufficient\n /// to spend the given amount.\n function universalApproveInfinity(address token, address spender, uint256 amountToSpend) internal {\n // ETH Chad doesn't require your approval\n if (token == ETH_ADDRESS) return;\n // No-op if allowance is already sufficient\n uint256 allowance = IERC20(token).allowance(address(this), spender);\n if (allowance \u003e= amountToSpend) return;\n // Otherwise, reset approval to 0 and set to max allowance\n if (allowance \u003e 0) IERC20(token).safeDecreaseAllowance(spender, allowance);\n IERC20(token).safeIncreaseAllowance(spender, type(uint256).max);\n }\n\n /// @notice Returns the balance of the given token (or native ETH) for the given account.\n function universalBalanceOf(address token, address account) internal view returns (uint256) {\n if (token == ETH_ADDRESS) {\n return account.balance;\n } else {\n return IERC20(token).balanceOf(account);\n }\n }\n\n /// @dev Checks that token is a contract and not ETH_ADDRESS.\n function assertIsContract(address token) internal view {\n // Check that ETH_ADDRESS was not used (in case this is a predeploy on any of the chains)\n if (token == UniversalTokenLib.ETH_ADDRESS) revert TokenNotContract();\n // Check that token is not an EOA\n if (token.code.length == 0) revert TokenNotContract();\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/Admin.sol\n\ncontract Admin is IAdmin, AccessControlEnumerable {\n using UniversalTokenLib for address;\n\n bytes32 public constant RELAYER_ROLE = keccak256(\"RELAYER_ROLE\");\n bytes32 public constant REFUNDER_ROLE = keccak256(\"REFUNDER_ROLE\");\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n uint256 public constant FEE_BPS = 1e6;\n uint256 public constant FEE_RATE_MAX = 0.01e6; // max 1% on origin amount\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Chain gas amount to forward as rebate if requested\n uint256 public chainGasAmount;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n }\n\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n require(newFeeRate \u003c= FEE_RATE_MAX, \"newFeeRate \u003e max\");\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n token.universalTransfer(recipient, feeAmount);\n emit FeesSwept(token, recipient, feeAmount);\n }\n\n function setChainGasAmount(uint256 newChainGasAmount) external onlyRole(GOVERNOR_ROLE) {\n uint256 oldChainGasAmount = chainGasAmount;\n chainGasAmount = newChainGasAmount;\n emit ChainGasAmountUpdated(oldChainGasAmount, newChainGasAmount);\n }\n}\n\n// contracts/FastBridge.sol\n\ncontract FastBridge is IFastBridge, Admin {\n using SafeERC20 for IERC20;\n using UniversalTokenLib for address;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Delay for a transaction after which it could be permisionlessly refunded\n uint256 public constant REFUND_DELAY = 7 days;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeStatus) public bridgeStatuses;\n /// @notice Proof of relayed bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeProof) public bridgeProofs;\n /// @notice Whether bridge has been relayed on destination chain\n mapping(bytes32 =\u003e bool) public bridgeRelays;\n\n /// @dev to prevent replays\n uint256 public nonce;\n // @dev the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @notice Pulls a requested token from the user to the requested recipient.\n /// @dev Be careful of re-entrancy issues when msg.value \u003e 0 and recipient != address(this)\n function _pullToken(address recipient, address token, uint256 amount) internal returns (uint256 amountPulled) {\n if (token != UniversalTokenLib.ETH_ADDRESS) {\n token.assertIsContract();\n // Record token balance before transfer\n amountPulled = IERC20(token).balanceOf(recipient);\n // Token needs to be pulled only if msg.value is zero\n // This way user can specify WETH as the origin asset\n IERC20(token).safeTransferFrom(msg.sender, recipient, amount);\n // Use the difference between the recorded balance and the current balance as the amountPulled\n amountPulled = IERC20(token).balanceOf(recipient) - amountPulled;\n } else {\n // Otherwise, we need to check that ETH amount matches msg.value\n if (amount != msg.value) revert MsgValueIncorrect();\n // Transfer value to recipient if not this address\n if (recipient != address(this)) token.universalTransfer(recipient, amount);\n // We will forward msg.value in the external call later, if recipient is not this contract\n amountPulled = msg.value;\n }\n }\n\n /// @inheritdoc IFastBridge\n function getBridgeTransaction(bytes memory request) public pure returns (BridgeTransaction memory) {\n return abi.decode(request, (BridgeTransaction));\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n // check bridge params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n\n // transfer tokens to bridge contract\n // @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _pullToken(address(this), params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n\n // set status to requested\n bytes memory request = abi.encode(\n BridgeTransaction({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n sendChainGas: params.sendChainGas,\n deadline: params.deadline,\n nonce: nonce++ // increment nonce on every bridge\n })\n );\n bytes32 transactionId = keccak256(request);\n bridgeStatuses[transactionId] = BridgeStatus.REQUESTED;\n\n emit BridgeRequested(\n transactionId,\n params.sender,\n request,\n params.dstChainId,\n params.originToken,\n params.destToken,\n originAmount,\n params.destAmount,\n params.sendChainGas\n );\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes memory request) external payable onlyRole(RELAYER_ROLE) {\n bytes32 transactionId = keccak256(request);\n BridgeTransaction memory transaction = getBridgeTransaction(request);\n if (transaction.destChainId != uint32(block.chainid)) revert ChainIncorrect();\n\n // check haven't exceeded deadline for relay to happen\n if (block.timestamp \u003e transaction.deadline) revert DeadlineExceeded();\n\n // mark bridge transaction as relayed\n if (bridgeRelays[transactionId]) revert TransactionRelayed();\n bridgeRelays[transactionId] = true;\n\n // transfer tokens to recipient on destination chain and gas rebate if requested\n address to = transaction.destRecipient;\n address token = transaction.destToken;\n uint256 amount = transaction.destAmount;\n\n uint256 rebate = chainGasAmount;\n if (!transaction.sendChainGas) {\n // forward erc20\n rebate = 0;\n _pullToken(to, token, amount);\n } else if (token == UniversalTokenLib.ETH_ADDRESS) {\n // lump in gas rebate into amount in native gas token\n _pullToken(to, token, amount + rebate);\n } else {\n // forward erc20 then forward gas rebate in native gas token\n _pullToken(to, token, amount);\n _pullToken(to, UniversalTokenLib.ETH_ADDRESS, rebate);\n }\n\n emit BridgeRelayed(\n transactionId,\n msg.sender,\n to,\n transaction.originChainId,\n transaction.originToken,\n transaction.destToken,\n transaction.originAmount,\n transaction.destAmount,\n rebate\n );\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes memory request, bytes32 destTxHash) external onlyRole(RELAYER_ROLE) {\n bytes32 transactionId = keccak256(request);\n // update bridge tx status given proof provided\n if (bridgeStatuses[transactionId] != BridgeStatus.REQUESTED) revert StatusIncorrect();\n bridgeStatuses[transactionId] = BridgeStatus.RELAYER_PROVED;\n bridgeProofs[transactionId] = BridgeProof({timestamp: uint96(block.timestamp), relayer: msg.sender}); // overflow ok\n\n emit BridgeProofProvided(transactionId, msg.sender, destTxHash);\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint96(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint96).max but\n /// proof.timestamp \u003c type(uint96).max via unchecked statement\n /// @param proof The bridge proof\n /// @return delta Time delta since proof submitted\n function _timeSince(BridgeProof memory proof) internal view returns (uint256 delta) {\n unchecked {\n delta = uint96(block.timestamp) - proof.timestamp;\n }\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n if (bridgeStatuses[transactionId] != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n BridgeProof memory proof = bridgeProofs[transactionId];\n if (proof.relayer != relayer) revert SenderIncorrect();\n return _timeSince(proof) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes memory request, address to) external onlyRole(RELAYER_ROLE) {\n bytes32 transactionId = keccak256(request);\n BridgeTransaction memory transaction = getBridgeTransaction(request);\n\n // update bridge tx status if able to claim origin collateral\n if (bridgeStatuses[transactionId] != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n\n BridgeProof memory proof = bridgeProofs[transactionId];\n if (proof.relayer != msg.sender) revert SenderIncorrect();\n if (_timeSince(proof) \u003c= DISPUTE_PERIOD) revert DisputePeriodNotPassed();\n\n bridgeStatuses[transactionId] = BridgeStatus.RELAYER_CLAIMED;\n\n // update protocol fees if origin fee amount exists\n if (transaction.originFeeAmount \u003e 0) protocolFees[transaction.originToken] += transaction.originFeeAmount;\n\n // transfer origin collateral less fee to specified address\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositClaimed(transactionId, msg.sender, to, token, amount);\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n if (bridgeStatuses[transactionId] != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(bridgeProofs[transactionId]) \u003e DISPUTE_PERIOD) revert DisputePeriodPassed();\n\n // @dev relayer gets slashed effectively if dest relay has gone thru\n bridgeStatuses[transactionId] = BridgeStatus.REQUESTED;\n delete bridgeProofs[transactionId];\n\n emit BridgeProofDisputed(transactionId, msg.sender);\n }\n\n /// @inheritdoc IFastBridge\n function refund(bytes memory request) external {\n bytes32 transactionId = keccak256(request);\n BridgeTransaction memory transaction = getBridgeTransaction(request);\n\n if (hasRole(REFUNDER_ROLE, msg.sender)) {\n // Refunder can refund if deadline has passed\n if (block.timestamp \u003c= transaction.deadline) revert DeadlineNotExceeded();\n } else {\n // Permissionless refund is allowed after REFUND_DELAY\n if (block.timestamp \u003c= transaction.deadline + REFUND_DELAY) revert DeadlineNotExceeded();\n }\n\n // set status to refunded if still in requested state\n if (bridgeStatuses[transactionId] != BridgeStatus.REQUESTED) revert StatusIncorrect();\n bridgeStatuses[transactionId] = BridgeStatus.REFUNDED;\n\n // transfer origin collateral back to original sender\n address to = transaction.originSender;\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount + transaction.originFeeAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n }\n}\n\n// test/FastBridgeMock.sol\n\ncontract FastBridgeMock is IFastBridge, Admin {\n // @dev the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @dev to prevent replays\n uint256 public nonce;\n\n function getBridgeTransaction(bytes memory request) public pure returns (BridgeTransaction memory) {\n return abi.decode(request, (BridgeTransaction));\n }\n\n // used for testing in go.\n // see: https://ethereum.stackexchange.com/questions/21155/how-to-expose-enum-in-solidity-contract\n // make sure to update fastbridge/status.go if this changes\n // or underliyng enum changes.\n //\n // TODO: a foundry test should be added to ensure this is always in sync.\n function getEnumKeyByValue(FastBridge.BridgeStatus keyValue) public pure returns (string memory) {\n if (FastBridge.BridgeStatus.NULL == keyValue) return \"NULL\";\n if (FastBridge.BridgeStatus.REQUESTED == keyValue) return \"REQUESTED\";\n if (FastBridge.BridgeStatus.RELAYER_PROVED == keyValue) return \"RELAYER_PROVED\";\n if (FastBridge.BridgeStatus.RELAYER_CLAIMED == keyValue) return \"RELAYER_CLAIMED\";\n if (FastBridge.BridgeStatus.REFUNDED == keyValue) return \"REFUNDED\";\n return \"\";\n }\n\n function mockBridgeRequest(bytes32 transactionId, address sender, BridgeParams memory params) external {\n uint256 originFeeAmount = (params.originAmount * protocolFeeRate) / FEE_BPS;\n params.originAmount -= originFeeAmount;\n\n bytes memory request = abi.encode(\n BridgeTransaction({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: params.originAmount, // includes relayer fee\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n sendChainGas: params.sendChainGas,\n deadline: params.deadline,\n nonce: nonce++ // increment nonce on every bridge\n })\n );\n\n emit BridgeRequested(\n transactionId,\n params.sender,\n request,\n params.dstChainId,\n params.originToken,\n params.destToken,\n params.originAmount,\n params.destAmount,\n params.sendChainGas\n );\n }\n\n function mockBridgeRequestRaw(bytes32 transactionId, address sender, bytes memory request) external {\n BridgeTransaction memory transaction = getBridgeTransaction(request);\n emit BridgeRequested(\n transactionId,\n transaction.originSender,\n request,\n transaction.destChainId,\n transaction.originToken,\n transaction.destToken,\n transaction.originAmount,\n transaction.destAmount,\n transaction.sendChainGas\n );\n }\n\n function mockBridgeRelayer(\n bytes32 transactionId,\n address relayer,\n address to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n )\n external\n {\n emit BridgeRelayed(\n transactionId, relayer, to, originChainId, originToken, destToken, originAmount, destAmount, chainGasAmount\n );\n }\n\n function bridge(BridgeParams memory params) external payable {\n revert(\"not implemented\");\n }\n\n function relay(bytes memory request) external payable {\n revert(\"not implemented\");\n }\n\n function prove(bytes memory request, bytes32 destTxHash) external {\n revert(\"not implemented\");\n }\n\n function canClaim(bytes32 transactionid, address relayer) external view returns (bool) {\n revert(\"not implemented\");\n }\n\n function claim(bytes memory request, address to) external {\n revert(\"not implemented\");\n }\n\n function dispute(bytes32 transactionId) external {\n revert(\"not implemented\");\n }\n\n function refund(bytes memory request) external {\n revert(\"not implemented\");\n }\n}\n","language":"Solidity","languageVersion":"0.8.20","compilerVersion":"0.8.20","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"15591:6066:0:-:0;;;;;;;;;;;;;;;-1:-1:-1;;;15591:6066:0;;;;;;;;;;;;;;;;;","srcMapRuntime":"15591:6066:0:-:0;;;;;;;;","abiDefinition":[{"inputs":[{"internalType":"address","name":"target","type":"address"}],"name":"AddressEmptyCode","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"AddressInsufficientBalance","type":"error"},{"inputs":[],"name":"FailedInnerCall","type":"error"}],"userDoc":{"kind":"user","methods":{},"version":1},"developerDoc":{"details":"Collection of functions related to the address type","errors":{"AddressEmptyCode(address)":[{"details":"There's no code at `target` (it is not a contract)."}],"AddressInsufficientBalance(address)":[{"details":"The ETH balance of the account is not enough to perform the operation."}],"FailedInnerCall()":[{"details":"A call to an address target failed. The target may have reverted."}]},"kind":"dev","methods":{},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.20+commit.a1b79de6\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"}],\"name\":\"AddressEmptyCode\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"AddressInsufficientBalance\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"FailedInnerCall\",\"type\":\"error\"}],\"devdoc\":{\"details\":\"Collection of functions related to the address type\",\"errors\":{\"AddressEmptyCode(address)\":[{\"details\":\"There's no code at `target` (it is not a contract).\"}],\"AddressInsufficientBalance(address)\":[{\"details\":\"The ETH balance of the account is not enough to perform the operation.\"}],\"FailedInnerCall()\":[{\"details\":\"A call to an address target failed. The target may have reverted.\"}]},\"kind\":\"dev\",\"methods\":{},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeMock.sol\":\"Address\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeMock.sol\":{\"keccak256\":\"0x620e81214ecd324ae8b971219291f176c454ce76fb1c01d656428096da8f1366\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://18e556772c12e13aa2d52a50cc7c48e676c8d5af22b90adaf7befb39cdd08e64\",\"dweb:/ipfs/QmPrQc98TxHCFMeuFNADyjr6Nqo52rHhHy1LBcsVdMRXjL\"]}},\"version\":1}"},"hashes":{}},"solidity/FastBridgeMock.sol:Admin":{"code":"0x60806040523480156200001157600080fd5b50604051620014123803806200141283398101604081905262000034916200018e565b6200004160008262000049565b5050620001b9565b60008062000058848462000086565b905080156200007d5760008481526001602052604090206200007b908462000134565b505b90505b92915050565b6000828152602081815260408083206001600160a01b038516845290915281205460ff166200012b576000838152602081815260408083206001600160a01b03861684529091529020805460ff19166001179055620000e23390565b6001600160a01b0316826001600160a01b0316847f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a450600162000080565b50600062000080565b60006200007d836001600160a01b03841660008181526001830160205260408120546200012b5750815460018181018455600084815260208082209093018490558454848252828601909352604090209190915562000080565b600060208284031215620001a157600080fd5b81516001600160a01b03811681146200007d57600080fd5b61124980620001c96000396000f3fe608060405234801561001057600080fd5b50600436106101775760003560e01c806391d14854116100d8578063bf333f2c1161008c578063d547741f11610066578063d547741f14610385578063dcf844a714610398578063e00a83e0146103b857600080fd5b8063bf333f2c14610341578063ca15c8731461034b578063ccc574901461035e57600080fd5b8063a217fddf116100bd578063a217fddf14610313578063b13aa2d61461031b578063b250fe6b1461032e57600080fd5b806391d14854146102a8578063926d7d7f146102ec57600080fd5b80632f2ff15d1161012f57806358f858801161011457806358f85880146102405780635960ccf2146102495780639010d07c1461027057600080fd5b80632f2ff15d1461021a57806336568abe1461022d57600080fd5b806306f333f21161016057806306f333f2146101d95780630f5f6ed7146101ee578063248a9ca3146101f757600080fd5b806301ffc9a71461017c57806303ed0ee5146101a4575b600080fd5b61018f61018a366004611013565b6103c1565b60405190151581526020015b60405180910390f35b6101cb7f043c983c49d46f0e102151eaf8085d4a2e6571d5df2d47b013f39bddfd4a639d81565b60405190815260200161019b565b6101ec6101e736600461107e565b61041d565b005b6101cb61271081565b6101cb6102053660046110b1565b60009081526020819052604090206001015490565b6101ec6102283660046110ca565b61050b565b6101ec61023b3660046110ca565b610536565b6101cb60025481565b6101cb7fdb9556138406326f00296e13ea2ad7db24ba82381212d816b1a40c23b466b32781565b61028361027e3660046110ed565b61058f565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200161019b565b61018f6102b63660046110ca565b60009182526020828152604080842073ffffffffffffffffffffffffffffffffffffffff93909316845291905290205460ff1690565b6101cb7fe2b7fb3b832174769106daebcfd6d1970523240dda11281102db9363b83b0dc481565b6101cb600081565b6101ec6103293660046110b1565b6105ae565b6101ec61033c3660046110b1565b610690565b6101cb620f424081565b6101cb6103593660046110b1565b6106f8565b6101cb7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f5581565b6101ec6103933660046110ca565b61070f565b6101cb6103a636600461110f565b60036020526000908152604090205481565b6101cb60045481565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f5a05180f000000000000000000000000000000000000000000000000000000001480610417575061041782610734565b92915050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f55610447816107cb565b73ffffffffffffffffffffffffffffffffffffffff83166000908152600360205260408120549081900361047b5750505050565b73ffffffffffffffffffffffffffffffffffffffff84166000818152600360205260408120556104ac9084836107d8565b6040805173ffffffffffffffffffffffffffffffffffffffff8087168252851660208201529081018290527f244e51bc38c1452fa8aaf487bcb4bca36c2baa3a5fbdb776b1eabd8dc6d277cd9060600160405180910390a1505b505050565b600082815260208190526040902060010154610526816107cb565b610530838361092f565b50505050565b73ffffffffffffffffffffffffffffffffffffffff81163314610585576040517f6697b23200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6105068282610964565b60008281526001602052604081206105a79083610991565b9392505050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f556105d8816107cb565b612710821115610649576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f6e657746656552617465203e206d61780000000000000000000000000000000060448201526064015b60405180910390fd5b600280549083905560408051828152602081018590527f14914da2bf76024616fbe1859783fcd4dbddcb179b1f3a854949fbf920dcb95791015b60405180910390a1505050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f556106ba816107cb565b600480549083905560408051828152602081018590527f5cf09b12f3f56b4c564d51b25b40360af6d795198adb61ae0806a36c294323fa9101610683565b60008181526001602052604081206104179061099d565b60008281526020819052604090206001015461072a816107cb565b6105308383610964565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f7965db0b00000000000000000000000000000000000000000000000000000000148061041757507f01ffc9a7000000000000000000000000000000000000000000000000000000007fffffffff00000000000000000000000000000000000000000000000000000000831614610417565b6107d581336109a7565b50565b3073ffffffffffffffffffffffffffffffffffffffff8316036107fa57505050565b8060000361080757505050565b7fffffffffffffffffffffffff111111111111111111111111111111111111111273ffffffffffffffffffffffffffffffffffffffff84160161090e5760008273ffffffffffffffffffffffffffffffffffffffff168260405160006040518083038185875af1925050503d806000811461089e576040519150601f19603f3d011682016040523d82523d6000602084013e6108a3565b606091505b5050905080610530576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f455448207472616e73666572206661696c6564000000000000000000000000006044820152606401610640565b61050673ffffffffffffffffffffffffffffffffffffffff84168383610a31565b60008061093c8484610abe565b905080156105a757600084815260016020526040902061095c9084610bba565b509392505050565b6000806109718484610bdc565b905080156105a757600084815260016020526040902061095c9084610c97565b60006105a78383610cb9565b6000610417825490565b60008281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915290205460ff16610a2d576040517fe2517d3f00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8216600482015260248101839052604401610640565b5050565b6040805173ffffffffffffffffffffffffffffffffffffffff8416602482015260448082018490528251808303909101815260649091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fa9059cbb00000000000000000000000000000000000000000000000000000000179052610506908490610ce3565b60008281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915281205460ff16610bb25760008381526020818152604080832073ffffffffffffffffffffffffffffffffffffffff86168452909152902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055610b503390565b73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16847f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a4506001610417565b506000610417565b60006105a78373ffffffffffffffffffffffffffffffffffffffff8416610d79565b60008281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915281205460ff1615610bb25760008381526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8616808552925280832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016905551339286917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a4506001610417565b60006105a78373ffffffffffffffffffffffffffffffffffffffff8416610dc0565b6000826000018281548110610cd057610cd061112a565b9060005260206000200154905092915050565b6000610d0573ffffffffffffffffffffffffffffffffffffffff841683610eb3565b90508051600014158015610d2a575080806020019051810190610d289190611159565b155b15610506576040517f5274afe700000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff84166004820152602401610640565b6000818152600183016020526040812054610bb257508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155610417565b60008181526001830160205260408120548015610ea9576000610de460018361117b565b8554909150600090610df89060019061117b565b9050808214610e5d576000866000018281548110610e1857610e1861112a565b9060005260206000200154905080876000018481548110610e3b57610e3b61112a565b6000918252602080832090910192909255918252600188019052604090208390555b8554869080610e6e57610e6e6111b5565b600190038181906000526020600020016000905590558560010160008681526020019081526020016000206000905560019350505050610417565b6000915050610417565b60606105a783836000846000808573ffffffffffffffffffffffffffffffffffffffff168486604051610ee691906111e4565b60006040518083038185875af1925050503d8060008114610f23576040519150601f19603f3d011682016040523d82523d6000602084013e610f28565b606091505b5091509150610f38868383610f42565b9695505050505050565b606082610f5757610f5282610fd1565b6105a7565b8151158015610f7b575073ffffffffffffffffffffffffffffffffffffffff84163b155b15610fca576040517f9996b31500000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff85166004820152602401610640565b50806105a7565b805115610fe15780518082602001fd5b6040517f1425ea4200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006020828403121561102557600080fd5b81357fffffffff00000000000000000000000000000000000000000000000000000000811681146105a757600080fd5b803573ffffffffffffffffffffffffffffffffffffffff8116811461107957600080fd5b919050565b6000806040838503121561109157600080fd5b61109a83611055565b91506110a860208401611055565b90509250929050565b6000602082840312156110c357600080fd5b5035919050565b600080604083850312156110dd57600080fd5b823591506110a860208401611055565b6000806040838503121561110057600080fd5b50508035926020909101359150565b60006020828403121561112157600080fd5b6105a782611055565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60006020828403121561116b57600080fd5b815180151581146105a757600080fd5b81810381811115610417577f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fd5b6000825160005b8181101561120557602081860181015185830152016111eb565b50600092019182525091905056fea264697066735822122079131b92a1423b929ce85a16df536bfcfda7bffbb7079337b796201173ad4a2264736f6c63430008140033","runtime-code":"0x608060405234801561001057600080fd5b50600436106101775760003560e01c806391d14854116100d8578063bf333f2c1161008c578063d547741f11610066578063d547741f14610385578063dcf844a714610398578063e00a83e0146103b857600080fd5b8063bf333f2c14610341578063ca15c8731461034b578063ccc574901461035e57600080fd5b8063a217fddf116100bd578063a217fddf14610313578063b13aa2d61461031b578063b250fe6b1461032e57600080fd5b806391d14854146102a8578063926d7d7f146102ec57600080fd5b80632f2ff15d1161012f57806358f858801161011457806358f85880146102405780635960ccf2146102495780639010d07c1461027057600080fd5b80632f2ff15d1461021a57806336568abe1461022d57600080fd5b806306f333f21161016057806306f333f2146101d95780630f5f6ed7146101ee578063248a9ca3146101f757600080fd5b806301ffc9a71461017c57806303ed0ee5146101a4575b600080fd5b61018f61018a366004611013565b6103c1565b60405190151581526020015b60405180910390f35b6101cb7f043c983c49d46f0e102151eaf8085d4a2e6571d5df2d47b013f39bddfd4a639d81565b60405190815260200161019b565b6101ec6101e736600461107e565b61041d565b005b6101cb61271081565b6101cb6102053660046110b1565b60009081526020819052604090206001015490565b6101ec6102283660046110ca565b61050b565b6101ec61023b3660046110ca565b610536565b6101cb60025481565b6101cb7fdb9556138406326f00296e13ea2ad7db24ba82381212d816b1a40c23b466b32781565b61028361027e3660046110ed565b61058f565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200161019b565b61018f6102b63660046110ca565b60009182526020828152604080842073ffffffffffffffffffffffffffffffffffffffff93909316845291905290205460ff1690565b6101cb7fe2b7fb3b832174769106daebcfd6d1970523240dda11281102db9363b83b0dc481565b6101cb600081565b6101ec6103293660046110b1565b6105ae565b6101ec61033c3660046110b1565b610690565b6101cb620f424081565b6101cb6103593660046110b1565b6106f8565b6101cb7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f5581565b6101ec6103933660046110ca565b61070f565b6101cb6103a636600461110f565b60036020526000908152604090205481565b6101cb60045481565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f5a05180f000000000000000000000000000000000000000000000000000000001480610417575061041782610734565b92915050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f55610447816107cb565b73ffffffffffffffffffffffffffffffffffffffff83166000908152600360205260408120549081900361047b5750505050565b73ffffffffffffffffffffffffffffffffffffffff84166000818152600360205260408120556104ac9084836107d8565b6040805173ffffffffffffffffffffffffffffffffffffffff8087168252851660208201529081018290527f244e51bc38c1452fa8aaf487bcb4bca36c2baa3a5fbdb776b1eabd8dc6d277cd9060600160405180910390a1505b505050565b600082815260208190526040902060010154610526816107cb565b610530838361092f565b50505050565b73ffffffffffffffffffffffffffffffffffffffff81163314610585576040517f6697b23200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6105068282610964565b60008281526001602052604081206105a79083610991565b9392505050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f556105d8816107cb565b612710821115610649576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f6e657746656552617465203e206d61780000000000000000000000000000000060448201526064015b60405180910390fd5b600280549083905560408051828152602081018590527f14914da2bf76024616fbe1859783fcd4dbddcb179b1f3a854949fbf920dcb95791015b60405180910390a1505050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f556106ba816107cb565b600480549083905560408051828152602081018590527f5cf09b12f3f56b4c564d51b25b40360af6d795198adb61ae0806a36c294323fa9101610683565b60008181526001602052604081206104179061099d565b60008281526020819052604090206001015461072a816107cb565b6105308383610964565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f7965db0b00000000000000000000000000000000000000000000000000000000148061041757507f01ffc9a7000000000000000000000000000000000000000000000000000000007fffffffff00000000000000000000000000000000000000000000000000000000831614610417565b6107d581336109a7565b50565b3073ffffffffffffffffffffffffffffffffffffffff8316036107fa57505050565b8060000361080757505050565b7fffffffffffffffffffffffff111111111111111111111111111111111111111273ffffffffffffffffffffffffffffffffffffffff84160161090e5760008273ffffffffffffffffffffffffffffffffffffffff168260405160006040518083038185875af1925050503d806000811461089e576040519150601f19603f3d011682016040523d82523d6000602084013e6108a3565b606091505b5050905080610530576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f455448207472616e73666572206661696c6564000000000000000000000000006044820152606401610640565b61050673ffffffffffffffffffffffffffffffffffffffff84168383610a31565b60008061093c8484610abe565b905080156105a757600084815260016020526040902061095c9084610bba565b509392505050565b6000806109718484610bdc565b905080156105a757600084815260016020526040902061095c9084610c97565b60006105a78383610cb9565b6000610417825490565b60008281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915290205460ff16610a2d576040517fe2517d3f00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8216600482015260248101839052604401610640565b5050565b6040805173ffffffffffffffffffffffffffffffffffffffff8416602482015260448082018490528251808303909101815260649091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fa9059cbb00000000000000000000000000000000000000000000000000000000179052610506908490610ce3565b60008281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915281205460ff16610bb25760008381526020818152604080832073ffffffffffffffffffffffffffffffffffffffff86168452909152902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055610b503390565b73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16847f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a4506001610417565b506000610417565b60006105a78373ffffffffffffffffffffffffffffffffffffffff8416610d79565b60008281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915281205460ff1615610bb25760008381526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8616808552925280832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016905551339286917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a4506001610417565b60006105a78373ffffffffffffffffffffffffffffffffffffffff8416610dc0565b6000826000018281548110610cd057610cd061112a565b9060005260206000200154905092915050565b6000610d0573ffffffffffffffffffffffffffffffffffffffff841683610eb3565b90508051600014158015610d2a575080806020019051810190610d289190611159565b155b15610506576040517f5274afe700000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff84166004820152602401610640565b6000818152600183016020526040812054610bb257508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155610417565b60008181526001830160205260408120548015610ea9576000610de460018361117b565b8554909150600090610df89060019061117b565b9050808214610e5d576000866000018281548110610e1857610e1861112a565b9060005260206000200154905080876000018481548110610e3b57610e3b61112a565b6000918252602080832090910192909255918252600188019052604090208390555b8554869080610e6e57610e6e6111b5565b600190038181906000526020600020016000905590558560010160008681526020019081526020016000206000905560019350505050610417565b6000915050610417565b60606105a783836000846000808573ffffffffffffffffffffffffffffffffffffffff168486604051610ee691906111e4565b60006040518083038185875af1925050503d8060008114610f23576040519150601f19603f3d011682016040523d82523d6000602084013e610f28565b606091505b5091509150610f38868383610f42565b9695505050505050565b606082610f5757610f5282610fd1565b6105a7565b8151158015610f7b575073ffffffffffffffffffffffffffffffffffffffff84163b155b15610fca576040517f9996b31500000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff85166004820152602401610640565b50806105a7565b805115610fe15780518082602001fd5b6040517f1425ea4200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006020828403121561102557600080fd5b81357fffffffff00000000000000000000000000000000000000000000000000000000811681146105a757600080fd5b803573ffffffffffffffffffffffffffffffffffffffff8116811461107957600080fd5b919050565b6000806040838503121561109157600080fd5b61109a83611055565b91506110a860208401611055565b90509250929050565b6000602082840312156110c357600080fd5b5035919050565b600080604083850312156110dd57600080fd5b823591506110a860208401611055565b6000806040838503121561110057600080fd5b50508035926020909101359150565b60006020828403121561112157600080fd5b6105a782611055565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60006020828403121561116b57600080fd5b815180151581146105a757600080fd5b81810381811115610417577f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fd5b6000825160005b8181101561120557602081860181015185830152016111eb565b50600092019182525091905056fea264697066735822122079131b92a1423b929ce85a16df536bfcfda7bffbb7079337b796201173ad4a2264736f6c63430008140033","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.20 ^0.8.20;\n\n// contracts/interfaces/IAdmin.sol\n\ninterface IAdmin {\n // ============ Events ============\n\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n event ChainGasAmountUpdated(uint256 oldChainGasAmount, uint256 newChainGasAmount);\n\n // ============ Methods ============\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n\n function setChainGasAmount(uint256 newChainGasAmount) external;\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/libs/Errors.sol\n\nerror DeadlineExceeded();\nerror DeadlineNotExceeded();\nerror DeadlineTooShort();\nerror InsufficientOutputAmount();\n\nerror MsgValueIncorrect();\nerror PoolNotFound();\nerror TokenAddressMismatch();\nerror TokenNotContract();\nerror TokenNotETH();\nerror TokensIdentical();\n\nerror ChainIncorrect();\nerror AmountIncorrect();\nerror ZeroAddress();\n\nerror DisputePeriodNotPassed();\nerror DisputePeriodPassed();\nerror SenderIncorrect();\nerror StatusIncorrect();\nerror TransactionIdIncorrect();\nerror TransactionRelayed();\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// contracts/libs/UniversalToken.sol\n\nlibrary UniversalTokenLib {\n using SafeERC20 for IERC20;\n\n address internal constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Transfers tokens to the given account. Reverts if transfer is not successful.\n /// @dev This might trigger fallback, if ETH is transferred to the contract.\n /// Make sure this can not lead to reentrancy attacks.\n function universalTransfer(address token, address to, uint256 value) internal {\n // Don't do anything, if need to send tokens to this address\n if (to == address(this)) return;\n // Don't do anything, if trying to send zero value\n if (value == 0) return;\n if (token == ETH_ADDRESS) {\n /// @dev Note: this can potentially lead to executing code in `to`.\n // solhint-disable-next-line avoid-low-level-calls\n (bool success,) = to.call{value: value}(\"\");\n require(success, \"ETH transfer failed\");\n } else {\n IERC20(token).safeTransfer(to, value);\n }\n }\n\n /// @notice Issues an infinite allowance to the spender, if the current allowance is insufficient\n /// to spend the given amount.\n function universalApproveInfinity(address token, address spender, uint256 amountToSpend) internal {\n // ETH Chad doesn't require your approval\n if (token == ETH_ADDRESS) return;\n // No-op if allowance is already sufficient\n uint256 allowance = IERC20(token).allowance(address(this), spender);\n if (allowance \u003e= amountToSpend) return;\n // Otherwise, reset approval to 0 and set to max allowance\n if (allowance \u003e 0) IERC20(token).safeDecreaseAllowance(spender, allowance);\n IERC20(token).safeIncreaseAllowance(spender, type(uint256).max);\n }\n\n /// @notice Returns the balance of the given token (or native ETH) for the given account.\n function universalBalanceOf(address token, address account) internal view returns (uint256) {\n if (token == ETH_ADDRESS) {\n return account.balance;\n } else {\n return IERC20(token).balanceOf(account);\n }\n }\n\n /// @dev Checks that token is a contract and not ETH_ADDRESS.\n function assertIsContract(address token) internal view {\n // Check that ETH_ADDRESS was not used (in case this is a predeploy on any of the chains)\n if (token == UniversalTokenLib.ETH_ADDRESS) revert TokenNotContract();\n // Check that token is not an EOA\n if (token.code.length == 0) revert TokenNotContract();\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/Admin.sol\n\ncontract Admin is IAdmin, AccessControlEnumerable {\n using UniversalTokenLib for address;\n\n bytes32 public constant RELAYER_ROLE = keccak256(\"RELAYER_ROLE\");\n bytes32 public constant REFUNDER_ROLE = keccak256(\"REFUNDER_ROLE\");\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n uint256 public constant FEE_BPS = 1e6;\n uint256 public constant FEE_RATE_MAX = 0.01e6; // max 1% on origin amount\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Chain gas amount to forward as rebate if requested\n uint256 public chainGasAmount;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n }\n\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n require(newFeeRate \u003c= FEE_RATE_MAX, \"newFeeRate \u003e max\");\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n token.universalTransfer(recipient, feeAmount);\n emit FeesSwept(token, recipient, feeAmount);\n }\n\n function setChainGasAmount(uint256 newChainGasAmount) external onlyRole(GOVERNOR_ROLE) {\n uint256 oldChainGasAmount = chainGasAmount;\n chainGasAmount = newChainGasAmount;\n emit ChainGasAmountUpdated(oldChainGasAmount, newChainGasAmount);\n }\n}\n\n// contracts/FastBridge.sol\n\ncontract FastBridge is IFastBridge, Admin {\n using SafeERC20 for IERC20;\n using UniversalTokenLib for address;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Delay for a transaction after which it could be permisionlessly refunded\n uint256 public constant REFUND_DELAY = 7 days;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeStatus) public bridgeStatuses;\n /// @notice Proof of relayed bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeProof) public bridgeProofs;\n /// @notice Whether bridge has been relayed on destination chain\n mapping(bytes32 =\u003e bool) public bridgeRelays;\n\n /// @dev to prevent replays\n uint256 public nonce;\n // @dev the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @notice Pulls a requested token from the user to the requested recipient.\n /// @dev Be careful of re-entrancy issues when msg.value \u003e 0 and recipient != address(this)\n function _pullToken(address recipient, address token, uint256 amount) internal returns (uint256 amountPulled) {\n if (token != UniversalTokenLib.ETH_ADDRESS) {\n token.assertIsContract();\n // Record token balance before transfer\n amountPulled = IERC20(token).balanceOf(recipient);\n // Token needs to be pulled only if msg.value is zero\n // This way user can specify WETH as the origin asset\n IERC20(token).safeTransferFrom(msg.sender, recipient, amount);\n // Use the difference between the recorded balance and the current balance as the amountPulled\n amountPulled = IERC20(token).balanceOf(recipient) - amountPulled;\n } else {\n // Otherwise, we need to check that ETH amount matches msg.value\n if (amount != msg.value) revert MsgValueIncorrect();\n // Transfer value to recipient if not this address\n if (recipient != address(this)) token.universalTransfer(recipient, amount);\n // We will forward msg.value in the external call later, if recipient is not this contract\n amountPulled = msg.value;\n }\n }\n\n /// @inheritdoc IFastBridge\n function getBridgeTransaction(bytes memory request) public pure returns (BridgeTransaction memory) {\n return abi.decode(request, (BridgeTransaction));\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n // check bridge params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n\n // transfer tokens to bridge contract\n // @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _pullToken(address(this), params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n\n // set status to requested\n bytes memory request = abi.encode(\n BridgeTransaction({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n sendChainGas: params.sendChainGas,\n deadline: params.deadline,\n nonce: nonce++ // increment nonce on every bridge\n })\n );\n bytes32 transactionId = keccak256(request);\n bridgeStatuses[transactionId] = BridgeStatus.REQUESTED;\n\n emit BridgeRequested(\n transactionId,\n params.sender,\n request,\n params.dstChainId,\n params.originToken,\n params.destToken,\n originAmount,\n params.destAmount,\n params.sendChainGas\n );\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes memory request) external payable onlyRole(RELAYER_ROLE) {\n bytes32 transactionId = keccak256(request);\n BridgeTransaction memory transaction = getBridgeTransaction(request);\n if (transaction.destChainId != uint32(block.chainid)) revert ChainIncorrect();\n\n // check haven't exceeded deadline for relay to happen\n if (block.timestamp \u003e transaction.deadline) revert DeadlineExceeded();\n\n // mark bridge transaction as relayed\n if (bridgeRelays[transactionId]) revert TransactionRelayed();\n bridgeRelays[transactionId] = true;\n\n // transfer tokens to recipient on destination chain and gas rebate if requested\n address to = transaction.destRecipient;\n address token = transaction.destToken;\n uint256 amount = transaction.destAmount;\n\n uint256 rebate = chainGasAmount;\n if (!transaction.sendChainGas) {\n // forward erc20\n rebate = 0;\n _pullToken(to, token, amount);\n } else if (token == UniversalTokenLib.ETH_ADDRESS) {\n // lump in gas rebate into amount in native gas token\n _pullToken(to, token, amount + rebate);\n } else {\n // forward erc20 then forward gas rebate in native gas token\n _pullToken(to, token, amount);\n _pullToken(to, UniversalTokenLib.ETH_ADDRESS, rebate);\n }\n\n emit BridgeRelayed(\n transactionId,\n msg.sender,\n to,\n transaction.originChainId,\n transaction.originToken,\n transaction.destToken,\n transaction.originAmount,\n transaction.destAmount,\n rebate\n );\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes memory request, bytes32 destTxHash) external onlyRole(RELAYER_ROLE) {\n bytes32 transactionId = keccak256(request);\n // update bridge tx status given proof provided\n if (bridgeStatuses[transactionId] != BridgeStatus.REQUESTED) revert StatusIncorrect();\n bridgeStatuses[transactionId] = BridgeStatus.RELAYER_PROVED;\n bridgeProofs[transactionId] = BridgeProof({timestamp: uint96(block.timestamp), relayer: msg.sender}); // overflow ok\n\n emit BridgeProofProvided(transactionId, msg.sender, destTxHash);\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint96(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint96).max but\n /// proof.timestamp \u003c type(uint96).max via unchecked statement\n /// @param proof The bridge proof\n /// @return delta Time delta since proof submitted\n function _timeSince(BridgeProof memory proof) internal view returns (uint256 delta) {\n unchecked {\n delta = uint96(block.timestamp) - proof.timestamp;\n }\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n if (bridgeStatuses[transactionId] != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n BridgeProof memory proof = bridgeProofs[transactionId];\n if (proof.relayer != relayer) revert SenderIncorrect();\n return _timeSince(proof) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes memory request, address to) external onlyRole(RELAYER_ROLE) {\n bytes32 transactionId = keccak256(request);\n BridgeTransaction memory transaction = getBridgeTransaction(request);\n\n // update bridge tx status if able to claim origin collateral\n if (bridgeStatuses[transactionId] != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n\n BridgeProof memory proof = bridgeProofs[transactionId];\n if (proof.relayer != msg.sender) revert SenderIncorrect();\n if (_timeSince(proof) \u003c= DISPUTE_PERIOD) revert DisputePeriodNotPassed();\n\n bridgeStatuses[transactionId] = BridgeStatus.RELAYER_CLAIMED;\n\n // update protocol fees if origin fee amount exists\n if (transaction.originFeeAmount \u003e 0) protocolFees[transaction.originToken] += transaction.originFeeAmount;\n\n // transfer origin collateral less fee to specified address\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositClaimed(transactionId, msg.sender, to, token, amount);\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n if (bridgeStatuses[transactionId] != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(bridgeProofs[transactionId]) \u003e DISPUTE_PERIOD) revert DisputePeriodPassed();\n\n // @dev relayer gets slashed effectively if dest relay has gone thru\n bridgeStatuses[transactionId] = BridgeStatus.REQUESTED;\n delete bridgeProofs[transactionId];\n\n emit BridgeProofDisputed(transactionId, msg.sender);\n }\n\n /// @inheritdoc IFastBridge\n function refund(bytes memory request) external {\n bytes32 transactionId = keccak256(request);\n BridgeTransaction memory transaction = getBridgeTransaction(request);\n\n if (hasRole(REFUNDER_ROLE, msg.sender)) {\n // Refunder can refund if deadline has passed\n if (block.timestamp \u003c= transaction.deadline) revert DeadlineNotExceeded();\n } else {\n // Permissionless refund is allowed after REFUND_DELAY\n if (block.timestamp \u003c= transaction.deadline + REFUND_DELAY) revert DeadlineNotExceeded();\n }\n\n // set status to refunded if still in requested state\n if (bridgeStatuses[transactionId] != BridgeStatus.REQUESTED) revert StatusIncorrect();\n bridgeStatuses[transactionId] = BridgeStatus.REFUNDED;\n\n // transfer origin collateral back to original sender\n address to = transaction.originSender;\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount + transaction.originFeeAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n }\n}\n\n// test/FastBridgeMock.sol\n\ncontract FastBridgeMock is IFastBridge, Admin {\n // @dev the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @dev to prevent replays\n uint256 public nonce;\n\n function getBridgeTransaction(bytes memory request) public pure returns (BridgeTransaction memory) {\n return abi.decode(request, (BridgeTransaction));\n }\n\n // used for testing in go.\n // see: https://ethereum.stackexchange.com/questions/21155/how-to-expose-enum-in-solidity-contract\n // make sure to update fastbridge/status.go if this changes\n // or underliyng enum changes.\n //\n // TODO: a foundry test should be added to ensure this is always in sync.\n function getEnumKeyByValue(FastBridge.BridgeStatus keyValue) public pure returns (string memory) {\n if (FastBridge.BridgeStatus.NULL == keyValue) return \"NULL\";\n if (FastBridge.BridgeStatus.REQUESTED == keyValue) return \"REQUESTED\";\n if (FastBridge.BridgeStatus.RELAYER_PROVED == keyValue) return \"RELAYER_PROVED\";\n if (FastBridge.BridgeStatus.RELAYER_CLAIMED == keyValue) return \"RELAYER_CLAIMED\";\n if (FastBridge.BridgeStatus.REFUNDED == keyValue) return \"REFUNDED\";\n return \"\";\n }\n\n function mockBridgeRequest(bytes32 transactionId, address sender, BridgeParams memory params) external {\n uint256 originFeeAmount = (params.originAmount * protocolFeeRate) / FEE_BPS;\n params.originAmount -= originFeeAmount;\n\n bytes memory request = abi.encode(\n BridgeTransaction({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: params.originAmount, // includes relayer fee\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n sendChainGas: params.sendChainGas,\n deadline: params.deadline,\n nonce: nonce++ // increment nonce on every bridge\n })\n );\n\n emit BridgeRequested(\n transactionId,\n params.sender,\n request,\n params.dstChainId,\n params.originToken,\n params.destToken,\n params.originAmount,\n params.destAmount,\n params.sendChainGas\n );\n }\n\n function mockBridgeRequestRaw(bytes32 transactionId, address sender, bytes memory request) external {\n BridgeTransaction memory transaction = getBridgeTransaction(request);\n emit BridgeRequested(\n transactionId,\n transaction.originSender,\n request,\n transaction.destChainId,\n transaction.originToken,\n transaction.destToken,\n transaction.originAmount,\n transaction.destAmount,\n transaction.sendChainGas\n );\n }\n\n function mockBridgeRelayer(\n bytes32 transactionId,\n address relayer,\n address to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n )\n external\n {\n emit BridgeRelayed(\n transactionId, relayer, to, originChainId, originToken, destToken, originAmount, destAmount, chainGasAmount\n );\n }\n\n function bridge(BridgeParams memory params) external payable {\n revert(\"not implemented\");\n }\n\n function relay(bytes memory request) external payable {\n revert(\"not implemented\");\n }\n\n function prove(bytes memory request, bytes32 destTxHash) external {\n revert(\"not implemented\");\n }\n\n function canClaim(bytes32 transactionid, address relayer) external view returns (bool) {\n revert(\"not implemented\");\n }\n\n function claim(bytes memory request, address to) external {\n revert(\"not implemented\");\n }\n\n function dispute(bytes32 transactionId) external {\n revert(\"not implemented\");\n }\n\n function refund(bytes memory request) external {\n revert(\"not implemented\");\n }\n}\n","language":"Solidity","languageVersion":"0.8.20","compilerVersion":"0.8.20","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"56315:1843:0:-:0;;;57142:83;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;57180:38;46352:4;57211:6;57180:10;:38::i;:::-;;57142:83;56315:1843;;55665:257;55751:4;;55782:31;55799:4;55805:7;55782:16;:31::i;:::-;55767:46;;55827:7;55823:69;;;55850:18;;;;:12;:18;;;;;:31;;55873:7;55850:22;:31::i;:::-;;55823:69;55908:7;-1:-1:-1;55665:257:0;;;;;:::o;50299:316::-;50376:4;47074:12;;;;;;;;;;;-1:-1:-1;;;;;47074:29:0;;;;;;;;;;;;50392:217;;50435:6;:12;;;;;;;;;;;-1:-1:-1;;;;;50435:29:0;;;;;;;;;:36;;-1:-1:-1;;50435:36:0;50467:4;50435:36;;;50517:12;22395:10;;22316:96;50517:12;-1:-1:-1;;;;;50490:40:0;50508:7;-1:-1:-1;;;;;50490:40:0;50502:4;50490:40;;;;;;;;;;-1:-1:-1;50551:4:0;50544:11;;50392:217;-1:-1:-1;50593:5:0;50586:12;;31840:150;31910:4;31933:50;31938:3;-1:-1:-1;;;;;31958:23:0;;25828:4;27884:21;;;:14;;;:21;;;;;;25844:321;;-1:-1:-1;25886:23:0;;;;;;;;:11;:23;;;;;;;;;;;;;26068:18;;26044:21;;;:14;;;:21;;;;;;:42;;;;26100:11;;14:290:1;84:6;137:2;125:9;116:7;112:23;108:32;105:52;;;153:1;150;143:12;105:52;179:16;;-1:-1:-1;;;;;224:31:1;;214:42;;204:70;;270:1;267;260:12;14:290;56315:1843:0;;;;;;","srcMapRuntime":"56315:1843:0:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;54325:212;;;;;;:::i;:::-;;:::i;:::-;;;516:14:1;;509:22;491:41;;479:2;464:18;54325:212:0;;;;;;;;56555:60;;56592:23;56555:60;;;;;689:25:1;;;677:2;662:18;56555:60:0;543:177:1;57527:359:0;;;;;;:::i;:::-;;:::i;:::-;;56737:45;;56776:6;56737:45;;47930:120;;;;;;:::i;:::-;47995:7;48021:12;;;;;;;;;;:22;;;;47930:120;48346:136;;;;;;:::i;:::-;;:::i;49448:245::-;;;;;;:::i;:::-;;:::i;56899:30::-;;;;;;56483:66;;56523:26;56483:66;;55122:142;;;;;;:::i;:::-;;:::i;:::-;;;2246:42:1;2234:55;;;2216:74;;2204:2;2189:18;55122:142:0;2070:226:1;46974:136:0;;;;;;:::i;:::-;47051:4;47074:12;;;;;;;;;;;:29;;;;;;;;;;;;;;;;46974:136;56413:64;;56452:25;56413:64;;46307:49;;46352:4;46307:49;;57231:290;;;;;;:::i;:::-;;:::i;57892:264::-;;;;;;:::i;:::-;;:::i;56694:37::-;;56728:3;56694:37;;55432:131;;;;;;:::i;:::-;;:::i;56621:66::-;;56661:26;56621:66;;48762:138;;;;;;:::i;:::-;;:::i;56985:47::-;;;;;;:::i;:::-;;;;;;;;;;;;;;57106:29;;;;;;54325:212;54410:4;54433:57;;;54448:42;54433:57;;:97;;;54494:36;54518:11;54494:23;:36::i;:::-;54426:104;54325:212;-1:-1:-1;;54325:212:0:o;57527:359::-;56661:26;46584:16;46595:4;46584:10;:16::i;:::-;57651:19:::1;::::0;::::1;57631:17;57651:19:::0;;;:12:::1;:19;::::0;;;;;;57684:14;;;57680:27:::1;;57700:7;57527:359:::0;;;:::o;57680:27::-:1;57748:19;::::0;::::1;57770:1;57748:19:::0;;;:12:::1;:19;::::0;;;;:23;57781:45:::1;::::0;57805:9;57816;57781:23:::1;:45::i;:::-;57841:38;::::0;;2889:42:1;2958:15;;;2940:34;;3010:15;;3005:2;2990:18;;2983:43;3042:18;;;3035:34;;;57841:38:0::1;::::0;2867:2:1;2852:18;57841:38:0::1;;;;;;;57621:265;46610:1;57527:359:::0;;;:::o;48346:136::-;47995:7;48021:12;;;;;;;;;;:22;;;46584:16;46595:4;46584:10;:16::i;:::-;48450:25:::1;48461:4;48467:7;48450:10;:25::i;:::-;;48346:136:::0;;;:::o;49448:245::-;49541:34;;;22395:10;49541:34;49537:102;;49598:30;;;;;;;;;;;;;;49537:102;49649:37;49661:4;49667:18;49649:11;:37::i;55122:142::-;55203:7;55229:18;;;:12;:18;;;;;:28;;55251:5;55229:21;:28::i;:::-;55222:35;55122:142;-1:-1:-1;;;55122:142:0:o;57231:290::-;56661:26;46584:16;46595:4;46584:10;:16::i;:::-;56776:6:::1;57330:10;:26;;57322:55;;;::::0;::::1;::::0;;3282:2:1;57322:55:0::1;::::0;::::1;3264:21:1::0;3321:2;3301:18;;;3294:30;3360:18;3340;;;3333:46;3396:18;;57322:55:0::1;;;;;;;;;57408:15;::::0;;57433:28;;;;57476:38:::1;::::0;;3599:25:1;;;3655:2;3640:18;;3633:34;;;57476:38:0::1;::::0;3572:18:1;57476:38:0::1;;;;;;;;57312:209;57231:290:::0;;:::o;57892:264::-;56661:26;46584:16;46595:4;46584:10;:16::i;:::-;58017:14:::1;::::0;;58041:34;;;;58090:59:::1;::::0;;3599:25:1;;;3655:2;3640:18;;3633:34;;;58090:59:0::1;::::0;3572:18:1;58090:59:0::1;3425:248:1::0;55432:131:0;55503:7;55529:18;;;:12;:18;;;;;:27;;:25;:27::i;48762:138::-;47995:7;48021:12;;;;;;;;;;:22;;;46584:16;46595:4;46584:10;:16::i;:::-;48867:26:::1;48879:4;48885:7;48867:11;:26::i;46685:202::-:0;46770:4;46793:47;;;46808:32;46793:47;;:87;;-1:-1:-1;38600:25:0;38585:40;;;;46844:36;38486:146;47319:103;47385:30;47396:4;22395:10;47385;:30::i;:::-;47319:103;:::o;51597:653::-;51772:4;51758:19;;;;51754:32;;51597:653;;;:::o;51754:32::-;51858:5;51867:1;51858:10;51854:23;;51597:653;;;:::o;51854:23::-;51890:20;;;;;51886:358;;52070:12;52087:2;:7;;52102:5;52087:25;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;52069:43;;;52134:7;52126:39;;;;;;;4090:2:1;52126:39:0;;;4072:21:1;4129:2;4109:18;;;4102:30;4168:21;4148:18;;;4141:49;4207:18;;52126:39:0;3888:343:1;51886:358:0;52196:37;:26;;;52223:2;52227:5;52196:26;:37::i;55665:257::-;55751:4;55767:12;55782:31;55799:4;55805:7;55782:16;:31::i;:::-;55767:46;;55827:7;55823:69;;;55850:18;;;;:12;:18;;;;;:31;;55873:7;55850:22;:31::i;:::-;;55908:7;55665:257;-1:-1:-1;;;55665:257:0:o;56025:262::-;56112:4;56128:12;56143:32;56161:4;56167:7;56143:17;:32::i;:::-;56128:47;;56189:7;56185:72;;;56212:18;;;;:12;:18;;;;;:34;;56238:7;56212:25;:34::i;33098:156::-;33172:7;33222:22;33226:3;33238:5;33222:3;:22::i;32641:115::-;32704:7;32730:19;32738:3;28080:18;;27998:107;47552:197;47051:4;47074:12;;;;;;;;;;;:29;;;;;;;;;;;;;47635:108;;47685:47;;;;;4440:42:1;4428:55;;47685:47:0;;;4410:74:1;4500:18;;;4493:34;;;4383:18;;47685:47:0;4236:297:1;47635:108:0;47552:197;;:::o;39802:160::-;39911:43;;;39926:14;4428:55:1;;39911:43:0;;;4410:74:1;4500:18;;;;4493:34;;;39911:43:0;;;;;;;;;;4383:18:1;;;;39911:43:0;;;;;;;;;;;;;;39884:71;;39904:5;;39884:19;:71::i;50299:316::-;50376:4;47074:12;;;;;;;;;;;:29;;;;;;;;;;;;;50392:217;;50435:6;:12;;;;;;;;;;;:29;;;;;;;;;;:36;;;;50467:4;50435:36;;;50517:12;22395:10;;22316:96;50517:12;50490:40;;50508:7;50490:40;;50502:4;50490:40;;;;;;;;;;-1:-1:-1;50551:4:0;50544:11;;50392:217;-1:-1:-1;50593:5:0;50586:12;;31840:150;31910:4;31933:50;31938:3;31958:23;;;31933:4;:50::i;50850:317::-;50928:4;47074:12;;;;;;;;;;;:29;;;;;;;;;;;;;50944:217;;;51018:5;50986:12;;;;;;;;;;;:29;;;;;;;;;;;:37;;;;;;51042:40;22395:10;;50986:12;;51042:40;;51018:5;51042:40;-1:-1:-1;51103:4:0;51096:11;;32158:156;32231:4;32254:53;32262:3;32282:23;;;32254:7;:53::i;28447:118::-;28514:7;28540:3;:11;;28552:5;28540:18;;;;;;;;:::i;:::-;;;;;;;;;28533:25;;28447:118;;;;:::o;42558:629::-;42977:23;43003:33;:27;;;43031:4;43003:27;:33::i;:::-;42977:59;;43050:10;:17;43071:1;43050:22;;:57;;;;;43088:10;43077:30;;;;;;;;;;;;:::i;:::-;43076:31;43050:57;43046:135;;;43130:40;;;;;2246:42:1;2234:55;;43130:40:0;;;2216:74:1;2189:18;;43130:40:0;2070:226:1;25765:406:0;25828:4;27884:21;;;:14;;;:21;;;;;;25844:321;;-1:-1:-1;25886:23:0;;;;;;;;:11;:23;;;;;;;;;;;;;26068:18;;26044:21;;;:14;;;:21;;;;;;:42;;;;26100:11;;26339:1368;26405:4;26534:21;;;:14;;;:21;;;;;;26570:13;;26566:1135;;26937:18;26958:12;26969:1;26958:8;:12;:::i;:::-;27004:18;;26937:33;;-1:-1:-1;26984:17:0;;27004:22;;27025:1;;27004:22;:::i;:::-;26984:42;;27059:9;27045:10;:23;27041:378;;27088:17;27108:3;:11;;27120:9;27108:22;;;;;;;;:::i;:::-;;;;;;;;;27088:42;;27255:9;27229:3;:11;;27241:10;27229:23;;;;;;;;:::i;:::-;;;;;;;;;;;;:35;;;;27368:25;;;:14;;;:25;;;;;:36;;;27041:378;27497:17;;:3;;:17;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;27600:3;:14;;:21;27615:5;27600:21;;;;;;;;;;;27593:28;;;27643:4;27636:11;;;;;;;26566:1135;27685:5;27678:12;;;;;18101:151;18176:12;18207:38;18229:6;18237:4;18243:1;18176:12;18817;18831:23;18858:6;:11;;18877:5;18884:4;18858:31;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;18816:73;;;;18906:55;18933:6;18941:7;18950:10;18906:26;:55::i;:::-;18899:62;18576:392;-1:-1:-1;;;;;;18576:392:0:o;20021:582::-;20165:12;20194:7;20189:408;;20217:19;20225:10;20217:7;:19::i;:::-;20189:408;;;20441:17;;:22;:49;;;;-1:-1:-1;20467:18:0;;;;:23;20441:49;20437:119;;;20517:24;;;;;2246:42:1;2234:55;;20517:24:0;;;2216:74:1;2189:18;;20517:24:0;2070:226:1;20437:119:0;-1:-1:-1;20576:10:0;20569:17;;21139:516;21270:17;;:21;21266:383;;21498:10;21492:17;21554:15;21541:10;21537:2;21533:19;21526:44;21266:383;21621:17;;;;;;;;;;;;;;14:332:1;72:6;125:2;113:9;104:7;100:23;96:32;93:52;;;141:1;138;131:12;93:52;180:9;167:23;230:66;223:5;219:78;212:5;209:89;199:117;;312:1;309;302:12;725:196;793:20;;853:42;842:54;;832:65;;822:93;;911:1;908;901:12;822:93;725:196;;;:::o;926:260::-;994:6;1002;1055:2;1043:9;1034:7;1030:23;1026:32;1023:52;;;1071:1;1068;1061:12;1023:52;1094:29;1113:9;1094:29;:::i;:::-;1084:39;;1142:38;1176:2;1165:9;1161:18;1142:38;:::i;:::-;1132:48;;926:260;;;;;:::o;1373:180::-;1432:6;1485:2;1473:9;1464:7;1460:23;1456:32;1453:52;;;1501:1;1498;1491:12;1453:52;-1:-1:-1;1524:23:1;;1373:180;-1:-1:-1;1373:180:1:o;1558:254::-;1626:6;1634;1687:2;1675:9;1666:7;1662:23;1658:32;1655:52;;;1703:1;1700;1693:12;1655:52;1739:9;1726:23;1716:33;;1768:38;1802:2;1791:9;1787:18;1768:38;:::i;1817:248::-;1885:6;1893;1946:2;1934:9;1925:7;1921:23;1917:32;1914:52;;;1962:1;1959;1952:12;1914:52;-1:-1:-1;;1985:23:1;;;2055:2;2040:18;;;2027:32;;-1:-1:-1;1817:248:1:o;2486:186::-;2545:6;2598:2;2586:9;2577:7;2573:23;2569:32;2566:52;;;2614:1;2611;2604:12;2566:52;2637:29;2656:9;2637:29;:::i;4840:184::-;4892:77;4889:1;4882:88;4989:4;4986:1;4979:15;5013:4;5010:1;5003:15;5029:277;5096:6;5149:2;5137:9;5128:7;5124:23;5120:32;5117:52;;;5165:1;5162;5155:12;5117:52;5197:9;5191:16;5250:5;5243:13;5236:21;5229:5;5226:32;5216:60;;5272:1;5269;5262:12;5311:282;5378:9;;;5399:11;;;5396:191;;;5443:77;5440:1;5433:88;5544:4;5541:1;5534:15;5572:4;5569:1;5562:15;5598:184;5650:77;5647:1;5640:88;5747:4;5744:1;5737:15;5771:4;5768:1;5761:15;5787:412;5916:3;5954:6;5948:13;5979:1;5989:129;6003:6;6000:1;5997:13;5989:129;;;6101:4;6085:14;;;6081:25;;6075:32;6062:11;;;6055:53;6018:12;5989:129;;;-1:-1:-1;6173:1:1;6137:16;;6162:13;;;-1:-1:-1;6137:16:1;5787:412;-1:-1:-1;5787:412:1:o","abiDefinition":[{"inputs":[{"internalType":"address","name":"_owner","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AccessControlBadConfirmation","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"bytes32","name":"neededRole","type":"bytes32"}],"name":"AccessControlUnauthorizedAccount","type":"error"},{"inputs":[{"internalType":"address","name":"target","type":"address"}],"name":"AddressEmptyCode","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"AddressInsufficientBalance","type":"error"},{"inputs":[],"name":"FailedInnerCall","type":"error"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"SafeERC20FailedOperation","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldChainGasAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newChainGasAmount","type":"uint256"}],"name":"ChainGasAmountUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldFeeRate","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newFeeRate","type":"uint256"}],"name":"FeeRateUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"address","name":"recipient","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"FeesSwept","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"previousAdminRole","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"newAdminRole","type":"bytes32"}],"name":"RoleAdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleRevoked","type":"event"},{"inputs":[],"name":"DEFAULT_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"FEE_BPS","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"FEE_RATE_MAX","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"GOVERNOR_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"GUARD_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"REFUNDER_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"RELAYER_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"chainGasAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleAdmin","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"uint256","name":"index","type":"uint256"}],"name":"getRoleMember","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleMemberCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"grantRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"hasRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"protocolFeeRate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"protocolFees","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"callerConfirmation","type":"address"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"revokeRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"newChainGasAmount","type":"uint256"}],"name":"setChainGasAmount","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"newFeeRate","type":"uint256"}],"name":"setProtocolFeeRate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"address","name":"recipient","type":"address"}],"name":"sweepProtocolFees","outputs":[],"stateMutability":"nonpayable","type":"function"}],"userDoc":{"kind":"user","methods":{"chainGasAmount()":{"notice":"Chain gas amount to forward as rebate if requested"},"protocolFeeRate()":{"notice":"Protocol fee rate taken on origin amount deposited in origin chain"},"protocolFees(address)":{"notice":"Protocol fee amounts accumulated"}},"version":1},"developerDoc":{"errors":{"AccessControlBadConfirmation()":[{"details":"The caller of a function is not the expected one. NOTE: Don't confuse with {AccessControlUnauthorizedAccount}."}],"AccessControlUnauthorizedAccount(address,bytes32)":[{"details":"The `account` is missing a role."}],"AddressEmptyCode(address)":[{"details":"There's no code at `target` (it is not a contract)."}],"AddressInsufficientBalance(address)":[{"details":"The ETH balance of the account is not enough to perform the operation."}],"FailedInnerCall()":[{"details":"A call to an address target failed. The target may have reverted."}],"SafeERC20FailedOperation(address)":[{"details":"An operation with an ERC20 token failed."}]},"events":{"RoleAdminChanged(bytes32,bytes32,bytes32)":{"details":"Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole` `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite {RoleAdminChanged} not being emitted signaling this."},"RoleGranted(bytes32,address,address)":{"details":"Emitted when `account` is granted `role`. `sender` is the account that originated the contract call, an admin role bearer except when using {AccessControl-_setupRole}."},"RoleRevoked(bytes32,address,address)":{"details":"Emitted when `account` is revoked `role`. `sender` is the account that originated the contract call: - if using `revokeRole`, it is the admin role bearer - if using `renounceRole`, it is the role bearer (i.e. `account`)"}},"kind":"dev","methods":{"getRoleAdmin(bytes32)":{"details":"Returns the admin role that controls `role`. See {grantRole} and {revokeRole}. To change a role's admin, use {_setRoleAdmin}."},"getRoleMember(bytes32,uint256)":{"details":"Returns one of the accounts that have `role`. `index` must be a value between 0 and {getRoleMemberCount}, non-inclusive. Role bearers are not sorted in any particular way, and their ordering may change at any point. WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure you perform all queries on the same block. See the following https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post] for more information."},"getRoleMemberCount(bytes32)":{"details":"Returns the number of accounts that have `role`. Can be used together with {getRoleMember} to enumerate all bearers of a role."},"grantRole(bytes32,address)":{"details":"Grants `role` to `account`. If `account` had not been already granted `role`, emits a {RoleGranted} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleGranted} event."},"hasRole(bytes32,address)":{"details":"Returns `true` if `account` has been granted `role`."},"renounceRole(bytes32,address)":{"details":"Revokes `role` from the calling account. Roles are often managed via {grantRole} and {revokeRole}: this function's purpose is to provide a mechanism for accounts to lose their privileges if they are compromised (such as when a trusted device is misplaced). If the calling account had been revoked `role`, emits a {RoleRevoked} event. Requirements: - the caller must be `callerConfirmation`. May emit a {RoleRevoked} event."},"revokeRole(bytes32,address)":{"details":"Revokes `role` from `account`. If `account` had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleRevoked} event."},"supportsInterface(bytes4)":{"details":"See {IERC165-supportsInterface}."}},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.20+commit.a1b79de6\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_owner\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"AccessControlBadConfirmation\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"neededRole\",\"type\":\"bytes32\"}],\"name\":\"AccessControlUnauthorizedAccount\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"}],\"name\":\"AddressEmptyCode\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"AddressInsufficientBalance\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"FailedInnerCall\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"}],\"name\":\"SafeERC20FailedOperation\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"oldChainGasAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newChainGasAmount\",\"type\":\"uint256\"}],\"name\":\"ChainGasAmountUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"oldFeeRate\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newFeeRate\",\"type\":\"uint256\"}],\"name\":\"FeeRateUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"FeesSwept\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"previousAdminRole\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"newAdminRole\",\"type\":\"bytes32\"}],\"name\":\"RoleAdminChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleGranted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleRevoked\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"DEFAULT_ADMIN_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"FEE_BPS\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"FEE_RATE_MAX\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"GOVERNOR_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"GUARD_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"REFUNDER_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"RELAYER_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"chainGasAmount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"}],\"name\":\"getRoleAdmin\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"index\",\"type\":\"uint256\"}],\"name\":\"getRoleMember\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"}],\"name\":\"getRoleMemberCount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"grantRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"hasRole\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"protocolFeeRate\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"protocolFees\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"callerConfirmation\",\"type\":\"address\"}],\"name\":\"renounceRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"revokeRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"newChainGasAmount\",\"type\":\"uint256\"}],\"name\":\"setChainGasAmount\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"newFeeRate\",\"type\":\"uint256\"}],\"name\":\"setProtocolFeeRate\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes4\",\"name\":\"interfaceId\",\"type\":\"bytes4\"}],\"name\":\"supportsInterface\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"}],\"name\":\"sweepProtocolFees\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"errors\":{\"AccessControlBadConfirmation()\":[{\"details\":\"The caller of a function is not the expected one. NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\"}],\"AccessControlUnauthorizedAccount(address,bytes32)\":[{\"details\":\"The `account` is missing a role.\"}],\"AddressEmptyCode(address)\":[{\"details\":\"There's no code at `target` (it is not a contract).\"}],\"AddressInsufficientBalance(address)\":[{\"details\":\"The ETH balance of the account is not enough to perform the operation.\"}],\"FailedInnerCall()\":[{\"details\":\"A call to an address target failed. The target may have reverted.\"}],\"SafeERC20FailedOperation(address)\":[{\"details\":\"An operation with an ERC20 token failed.\"}]},\"events\":{\"RoleAdminChanged(bytes32,bytes32,bytes32)\":{\"details\":\"Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole` `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite {RoleAdminChanged} not being emitted signaling this.\"},\"RoleGranted(bytes32,address,address)\":{\"details\":\"Emitted when `account` is granted `role`. `sender` is the account that originated the contract call, an admin role bearer except when using {AccessControl-_setupRole}.\"},\"RoleRevoked(bytes32,address,address)\":{\"details\":\"Emitted when `account` is revoked `role`. `sender` is the account that originated the contract call: - if using `revokeRole`, it is the admin role bearer - if using `renounceRole`, it is the role bearer (i.e. `account`)\"}},\"kind\":\"dev\",\"methods\":{\"getRoleAdmin(bytes32)\":{\"details\":\"Returns the admin role that controls `role`. See {grantRole} and {revokeRole}. To change a role's admin, use {_setRoleAdmin}.\"},\"getRoleMember(bytes32,uint256)\":{\"details\":\"Returns one of the accounts that have `role`. `index` must be a value between 0 and {getRoleMemberCount}, non-inclusive. Role bearers are not sorted in any particular way, and their ordering may change at any point. WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure you perform all queries on the same block. See the following https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post] for more information.\"},\"getRoleMemberCount(bytes32)\":{\"details\":\"Returns the number of accounts that have `role`. Can be used together with {getRoleMember} to enumerate all bearers of a role.\"},\"grantRole(bytes32,address)\":{\"details\":\"Grants `role` to `account`. If `account` had not been already granted `role`, emits a {RoleGranted} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleGranted} event.\"},\"hasRole(bytes32,address)\":{\"details\":\"Returns `true` if `account` has been granted `role`.\"},\"renounceRole(bytes32,address)\":{\"details\":\"Revokes `role` from the calling account. Roles are often managed via {grantRole} and {revokeRole}: this function's purpose is to provide a mechanism for accounts to lose their privileges if they are compromised (such as when a trusted device is misplaced). If the calling account had been revoked `role`, emits a {RoleRevoked} event. Requirements: - the caller must be `callerConfirmation`. May emit a {RoleRevoked} event.\"},\"revokeRole(bytes32,address)\":{\"details\":\"Revokes `role` from `account`. If `account` had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleRevoked} event.\"},\"supportsInterface(bytes4)\":{\"details\":\"See {IERC165-supportsInterface}.\"}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"chainGasAmount()\":{\"notice\":\"Chain gas amount to forward as rebate if requested\"},\"protocolFeeRate()\":{\"notice\":\"Protocol fee rate taken on origin amount deposited in origin chain\"},\"protocolFees(address)\":{\"notice\":\"Protocol fee amounts accumulated\"}},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeMock.sol\":\"Admin\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeMock.sol\":{\"keccak256\":\"0x620e81214ecd324ae8b971219291f176c454ce76fb1c01d656428096da8f1366\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://18e556772c12e13aa2d52a50cc7c48e676c8d5af22b90adaf7befb39cdd08e64\",\"dweb:/ipfs/QmPrQc98TxHCFMeuFNADyjr6Nqo52rHhHy1LBcsVdMRXjL\"]}},\"version\":1}"},"hashes":{"DEFAULT_ADMIN_ROLE()":"a217fddf","FEE_BPS()":"bf333f2c","FEE_RATE_MAX()":"0f5f6ed7","GOVERNOR_ROLE()":"ccc57490","GUARD_ROLE()":"03ed0ee5","REFUNDER_ROLE()":"5960ccf2","RELAYER_ROLE()":"926d7d7f","chainGasAmount()":"e00a83e0","getRoleAdmin(bytes32)":"248a9ca3","getRoleMember(bytes32,uint256)":"9010d07c","getRoleMemberCount(bytes32)":"ca15c873","grantRole(bytes32,address)":"2f2ff15d","hasRole(bytes32,address)":"91d14854","protocolFeeRate()":"58f85880","protocolFees(address)":"dcf844a7","renounceRole(bytes32,address)":"36568abe","revokeRole(bytes32,address)":"d547741f","setChainGasAmount(uint256)":"b250fe6b","setProtocolFeeRate(uint256)":"b13aa2d6","supportsInterface(bytes4)":"01ffc9a7","sweepProtocolFees(address,address)":"06f333f2"}},"solidity/FastBridgeMock.sol:Context":{"code":"0x","runtime-code":"0x","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.20 ^0.8.20;\n\n// contracts/interfaces/IAdmin.sol\n\ninterface IAdmin {\n // ============ Events ============\n\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n event ChainGasAmountUpdated(uint256 oldChainGasAmount, uint256 newChainGasAmount);\n\n // ============ Methods ============\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n\n function setChainGasAmount(uint256 newChainGasAmount) external;\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/libs/Errors.sol\n\nerror DeadlineExceeded();\nerror DeadlineNotExceeded();\nerror DeadlineTooShort();\nerror InsufficientOutputAmount();\n\nerror MsgValueIncorrect();\nerror PoolNotFound();\nerror TokenAddressMismatch();\nerror TokenNotContract();\nerror TokenNotETH();\nerror TokensIdentical();\n\nerror ChainIncorrect();\nerror AmountIncorrect();\nerror ZeroAddress();\n\nerror DisputePeriodNotPassed();\nerror DisputePeriodPassed();\nerror SenderIncorrect();\nerror StatusIncorrect();\nerror TransactionIdIncorrect();\nerror TransactionRelayed();\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// contracts/libs/UniversalToken.sol\n\nlibrary UniversalTokenLib {\n using SafeERC20 for IERC20;\n\n address internal constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Transfers tokens to the given account. Reverts if transfer is not successful.\n /// @dev This might trigger fallback, if ETH is transferred to the contract.\n /// Make sure this can not lead to reentrancy attacks.\n function universalTransfer(address token, address to, uint256 value) internal {\n // Don't do anything, if need to send tokens to this address\n if (to == address(this)) return;\n // Don't do anything, if trying to send zero value\n if (value == 0) return;\n if (token == ETH_ADDRESS) {\n /// @dev Note: this can potentially lead to executing code in `to`.\n // solhint-disable-next-line avoid-low-level-calls\n (bool success,) = to.call{value: value}(\"\");\n require(success, \"ETH transfer failed\");\n } else {\n IERC20(token).safeTransfer(to, value);\n }\n }\n\n /// @notice Issues an infinite allowance to the spender, if the current allowance is insufficient\n /// to spend the given amount.\n function universalApproveInfinity(address token, address spender, uint256 amountToSpend) internal {\n // ETH Chad doesn't require your approval\n if (token == ETH_ADDRESS) return;\n // No-op if allowance is already sufficient\n uint256 allowance = IERC20(token).allowance(address(this), spender);\n if (allowance \u003e= amountToSpend) return;\n // Otherwise, reset approval to 0 and set to max allowance\n if (allowance \u003e 0) IERC20(token).safeDecreaseAllowance(spender, allowance);\n IERC20(token).safeIncreaseAllowance(spender, type(uint256).max);\n }\n\n /// @notice Returns the balance of the given token (or native ETH) for the given account.\n function universalBalanceOf(address token, address account) internal view returns (uint256) {\n if (token == ETH_ADDRESS) {\n return account.balance;\n } else {\n return IERC20(token).balanceOf(account);\n }\n }\n\n /// @dev Checks that token is a contract and not ETH_ADDRESS.\n function assertIsContract(address token) internal view {\n // Check that ETH_ADDRESS was not used (in case this is a predeploy on any of the chains)\n if (token == UniversalTokenLib.ETH_ADDRESS) revert TokenNotContract();\n // Check that token is not an EOA\n if (token.code.length == 0) revert TokenNotContract();\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/Admin.sol\n\ncontract Admin is IAdmin, AccessControlEnumerable {\n using UniversalTokenLib for address;\n\n bytes32 public constant RELAYER_ROLE = keccak256(\"RELAYER_ROLE\");\n bytes32 public constant REFUNDER_ROLE = keccak256(\"REFUNDER_ROLE\");\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n uint256 public constant FEE_BPS = 1e6;\n uint256 public constant FEE_RATE_MAX = 0.01e6; // max 1% on origin amount\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Chain gas amount to forward as rebate if requested\n uint256 public chainGasAmount;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n }\n\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n require(newFeeRate \u003c= FEE_RATE_MAX, \"newFeeRate \u003e max\");\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n token.universalTransfer(recipient, feeAmount);\n emit FeesSwept(token, recipient, feeAmount);\n }\n\n function setChainGasAmount(uint256 newChainGasAmount) external onlyRole(GOVERNOR_ROLE) {\n uint256 oldChainGasAmount = chainGasAmount;\n chainGasAmount = newChainGasAmount;\n emit ChainGasAmountUpdated(oldChainGasAmount, newChainGasAmount);\n }\n}\n\n// contracts/FastBridge.sol\n\ncontract FastBridge is IFastBridge, Admin {\n using SafeERC20 for IERC20;\n using UniversalTokenLib for address;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Delay for a transaction after which it could be permisionlessly refunded\n uint256 public constant REFUND_DELAY = 7 days;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeStatus) public bridgeStatuses;\n /// @notice Proof of relayed bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeProof) public bridgeProofs;\n /// @notice Whether bridge has been relayed on destination chain\n mapping(bytes32 =\u003e bool) public bridgeRelays;\n\n /// @dev to prevent replays\n uint256 public nonce;\n // @dev the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @notice Pulls a requested token from the user to the requested recipient.\n /// @dev Be careful of re-entrancy issues when msg.value \u003e 0 and recipient != address(this)\n function _pullToken(address recipient, address token, uint256 amount) internal returns (uint256 amountPulled) {\n if (token != UniversalTokenLib.ETH_ADDRESS) {\n token.assertIsContract();\n // Record token balance before transfer\n amountPulled = IERC20(token).balanceOf(recipient);\n // Token needs to be pulled only if msg.value is zero\n // This way user can specify WETH as the origin asset\n IERC20(token).safeTransferFrom(msg.sender, recipient, amount);\n // Use the difference between the recorded balance and the current balance as the amountPulled\n amountPulled = IERC20(token).balanceOf(recipient) - amountPulled;\n } else {\n // Otherwise, we need to check that ETH amount matches msg.value\n if (amount != msg.value) revert MsgValueIncorrect();\n // Transfer value to recipient if not this address\n if (recipient != address(this)) token.universalTransfer(recipient, amount);\n // We will forward msg.value in the external call later, if recipient is not this contract\n amountPulled = msg.value;\n }\n }\n\n /// @inheritdoc IFastBridge\n function getBridgeTransaction(bytes memory request) public pure returns (BridgeTransaction memory) {\n return abi.decode(request, (BridgeTransaction));\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n // check bridge params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n\n // transfer tokens to bridge contract\n // @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _pullToken(address(this), params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n\n // set status to requested\n bytes memory request = abi.encode(\n BridgeTransaction({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n sendChainGas: params.sendChainGas,\n deadline: params.deadline,\n nonce: nonce++ // increment nonce on every bridge\n })\n );\n bytes32 transactionId = keccak256(request);\n bridgeStatuses[transactionId] = BridgeStatus.REQUESTED;\n\n emit BridgeRequested(\n transactionId,\n params.sender,\n request,\n params.dstChainId,\n params.originToken,\n params.destToken,\n originAmount,\n params.destAmount,\n params.sendChainGas\n );\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes memory request) external payable onlyRole(RELAYER_ROLE) {\n bytes32 transactionId = keccak256(request);\n BridgeTransaction memory transaction = getBridgeTransaction(request);\n if (transaction.destChainId != uint32(block.chainid)) revert ChainIncorrect();\n\n // check haven't exceeded deadline for relay to happen\n if (block.timestamp \u003e transaction.deadline) revert DeadlineExceeded();\n\n // mark bridge transaction as relayed\n if (bridgeRelays[transactionId]) revert TransactionRelayed();\n bridgeRelays[transactionId] = true;\n\n // transfer tokens to recipient on destination chain and gas rebate if requested\n address to = transaction.destRecipient;\n address token = transaction.destToken;\n uint256 amount = transaction.destAmount;\n\n uint256 rebate = chainGasAmount;\n if (!transaction.sendChainGas) {\n // forward erc20\n rebate = 0;\n _pullToken(to, token, amount);\n } else if (token == UniversalTokenLib.ETH_ADDRESS) {\n // lump in gas rebate into amount in native gas token\n _pullToken(to, token, amount + rebate);\n } else {\n // forward erc20 then forward gas rebate in native gas token\n _pullToken(to, token, amount);\n _pullToken(to, UniversalTokenLib.ETH_ADDRESS, rebate);\n }\n\n emit BridgeRelayed(\n transactionId,\n msg.sender,\n to,\n transaction.originChainId,\n transaction.originToken,\n transaction.destToken,\n transaction.originAmount,\n transaction.destAmount,\n rebate\n );\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes memory request, bytes32 destTxHash) external onlyRole(RELAYER_ROLE) {\n bytes32 transactionId = keccak256(request);\n // update bridge tx status given proof provided\n if (bridgeStatuses[transactionId] != BridgeStatus.REQUESTED) revert StatusIncorrect();\n bridgeStatuses[transactionId] = BridgeStatus.RELAYER_PROVED;\n bridgeProofs[transactionId] = BridgeProof({timestamp: uint96(block.timestamp), relayer: msg.sender}); // overflow ok\n\n emit BridgeProofProvided(transactionId, msg.sender, destTxHash);\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint96(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint96).max but\n /// proof.timestamp \u003c type(uint96).max via unchecked statement\n /// @param proof The bridge proof\n /// @return delta Time delta since proof submitted\n function _timeSince(BridgeProof memory proof) internal view returns (uint256 delta) {\n unchecked {\n delta = uint96(block.timestamp) - proof.timestamp;\n }\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n if (bridgeStatuses[transactionId] != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n BridgeProof memory proof = bridgeProofs[transactionId];\n if (proof.relayer != relayer) revert SenderIncorrect();\n return _timeSince(proof) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes memory request, address to) external onlyRole(RELAYER_ROLE) {\n bytes32 transactionId = keccak256(request);\n BridgeTransaction memory transaction = getBridgeTransaction(request);\n\n // update bridge tx status if able to claim origin collateral\n if (bridgeStatuses[transactionId] != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n\n BridgeProof memory proof = bridgeProofs[transactionId];\n if (proof.relayer != msg.sender) revert SenderIncorrect();\n if (_timeSince(proof) \u003c= DISPUTE_PERIOD) revert DisputePeriodNotPassed();\n\n bridgeStatuses[transactionId] = BridgeStatus.RELAYER_CLAIMED;\n\n // update protocol fees if origin fee amount exists\n if (transaction.originFeeAmount \u003e 0) protocolFees[transaction.originToken] += transaction.originFeeAmount;\n\n // transfer origin collateral less fee to specified address\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositClaimed(transactionId, msg.sender, to, token, amount);\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n if (bridgeStatuses[transactionId] != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(bridgeProofs[transactionId]) \u003e DISPUTE_PERIOD) revert DisputePeriodPassed();\n\n // @dev relayer gets slashed effectively if dest relay has gone thru\n bridgeStatuses[transactionId] = BridgeStatus.REQUESTED;\n delete bridgeProofs[transactionId];\n\n emit BridgeProofDisputed(transactionId, msg.sender);\n }\n\n /// @inheritdoc IFastBridge\n function refund(bytes memory request) external {\n bytes32 transactionId = keccak256(request);\n BridgeTransaction memory transaction = getBridgeTransaction(request);\n\n if (hasRole(REFUNDER_ROLE, msg.sender)) {\n // Refunder can refund if deadline has passed\n if (block.timestamp \u003c= transaction.deadline) revert DeadlineNotExceeded();\n } else {\n // Permissionless refund is allowed after REFUND_DELAY\n if (block.timestamp \u003c= transaction.deadline + REFUND_DELAY) revert DeadlineNotExceeded();\n }\n\n // set status to refunded if still in requested state\n if (bridgeStatuses[transactionId] != BridgeStatus.REQUESTED) revert StatusIncorrect();\n bridgeStatuses[transactionId] = BridgeStatus.REFUNDED;\n\n // transfer origin collateral back to original sender\n address to = transaction.originSender;\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount + transaction.originFeeAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n }\n}\n\n// test/FastBridgeMock.sol\n\ncontract FastBridgeMock is IFastBridge, Admin {\n // @dev the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @dev to prevent replays\n uint256 public nonce;\n\n function getBridgeTransaction(bytes memory request) public pure returns (BridgeTransaction memory) {\n return abi.decode(request, (BridgeTransaction));\n }\n\n // used for testing in go.\n // see: https://ethereum.stackexchange.com/questions/21155/how-to-expose-enum-in-solidity-contract\n // make sure to update fastbridge/status.go if this changes\n // or underliyng enum changes.\n //\n // TODO: a foundry test should be added to ensure this is always in sync.\n function getEnumKeyByValue(FastBridge.BridgeStatus keyValue) public pure returns (string memory) {\n if (FastBridge.BridgeStatus.NULL == keyValue) return \"NULL\";\n if (FastBridge.BridgeStatus.REQUESTED == keyValue) return \"REQUESTED\";\n if (FastBridge.BridgeStatus.RELAYER_PROVED == keyValue) return \"RELAYER_PROVED\";\n if (FastBridge.BridgeStatus.RELAYER_CLAIMED == keyValue) return \"RELAYER_CLAIMED\";\n if (FastBridge.BridgeStatus.REFUNDED == keyValue) return \"REFUNDED\";\n return \"\";\n }\n\n function mockBridgeRequest(bytes32 transactionId, address sender, BridgeParams memory params) external {\n uint256 originFeeAmount = (params.originAmount * protocolFeeRate) / FEE_BPS;\n params.originAmount -= originFeeAmount;\n\n bytes memory request = abi.encode(\n BridgeTransaction({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: params.originAmount, // includes relayer fee\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n sendChainGas: params.sendChainGas,\n deadline: params.deadline,\n nonce: nonce++ // increment nonce on every bridge\n })\n );\n\n emit BridgeRequested(\n transactionId,\n params.sender,\n request,\n params.dstChainId,\n params.originToken,\n params.destToken,\n params.originAmount,\n params.destAmount,\n params.sendChainGas\n );\n }\n\n function mockBridgeRequestRaw(bytes32 transactionId, address sender, bytes memory request) external {\n BridgeTransaction memory transaction = getBridgeTransaction(request);\n emit BridgeRequested(\n transactionId,\n transaction.originSender,\n request,\n transaction.destChainId,\n transaction.originToken,\n transaction.destToken,\n transaction.originAmount,\n transaction.destAmount,\n transaction.sendChainGas\n );\n }\n\n function mockBridgeRelayer(\n bytes32 transactionId,\n address relayer,\n address to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n )\n external\n {\n emit BridgeRelayed(\n transactionId, relayer, to, originChainId, originToken, destToken, originAmount, destAmount, chainGasAmount\n );\n }\n\n function bridge(BridgeParams memory params) external payable {\n revert(\"not implemented\");\n }\n\n function relay(bytes memory request) external payable {\n revert(\"not implemented\");\n }\n\n function prove(bytes memory request, bytes32 destTxHash) external {\n revert(\"not implemented\");\n }\n\n function canClaim(bytes32 transactionid, address relayer) external view returns (bool) {\n revert(\"not implemented\");\n }\n\n function claim(bytes memory request, address to) external {\n revert(\"not implemented\");\n }\n\n function dispute(bytes32 transactionId) external {\n revert(\"not implemented\");\n }\n\n function refund(bytes memory request) external {\n revert(\"not implemented\");\n }\n}\n","language":"Solidity","languageVersion":"0.8.20","compilerVersion":"0.8.20","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"","srcMapRuntime":"","abiDefinition":[],"userDoc":{"kind":"user","methods":{},"version":1},"developerDoc":{"details":"Provides information about the current execution context, including the sender of the transaction and its data. While these are generally available via msg.sender and msg.data, they should not be accessed in such a direct manner, since when dealing with meta-transactions the account sending and paying for execution may not be the actual sender (as far as an application is concerned). This contract is only required for intermediate, library-like contracts.","kind":"dev","methods":{},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.20+commit.a1b79de6\"},\"language\":\"Solidity\",\"output\":{\"abi\":[],\"devdoc\":{\"details\":\"Provides information about the current execution context, including the sender of the transaction and its data. While these are generally available via msg.sender and msg.data, they should not be accessed in such a direct manner, since when dealing with meta-transactions the account sending and paying for execution may not be the actual sender (as far as an application is concerned). This contract is only required for intermediate, library-like contracts.\",\"kind\":\"dev\",\"methods\":{},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeMock.sol\":\"Context\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeMock.sol\":{\"keccak256\":\"0x620e81214ecd324ae8b971219291f176c454ce76fb1c01d656428096da8f1366\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://18e556772c12e13aa2d52a50cc7c48e676c8d5af22b90adaf7befb39cdd08e64\",\"dweb:/ipfs/QmPrQc98TxHCFMeuFNADyjr6Nqo52rHhHy1LBcsVdMRXjL\"]}},\"version\":1}"},"hashes":{}},"solidity/FastBridgeMock.sol:ERC165":{"code":"0x","runtime-code":"0x","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.20 ^0.8.20;\n\n// contracts/interfaces/IAdmin.sol\n\ninterface IAdmin {\n // ============ Events ============\n\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n event ChainGasAmountUpdated(uint256 oldChainGasAmount, uint256 newChainGasAmount);\n\n // ============ Methods ============\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n\n function setChainGasAmount(uint256 newChainGasAmount) external;\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/libs/Errors.sol\n\nerror DeadlineExceeded();\nerror DeadlineNotExceeded();\nerror DeadlineTooShort();\nerror InsufficientOutputAmount();\n\nerror MsgValueIncorrect();\nerror PoolNotFound();\nerror TokenAddressMismatch();\nerror TokenNotContract();\nerror TokenNotETH();\nerror TokensIdentical();\n\nerror ChainIncorrect();\nerror AmountIncorrect();\nerror ZeroAddress();\n\nerror DisputePeriodNotPassed();\nerror DisputePeriodPassed();\nerror SenderIncorrect();\nerror StatusIncorrect();\nerror TransactionIdIncorrect();\nerror TransactionRelayed();\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// contracts/libs/UniversalToken.sol\n\nlibrary UniversalTokenLib {\n using SafeERC20 for IERC20;\n\n address internal constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Transfers tokens to the given account. Reverts if transfer is not successful.\n /// @dev This might trigger fallback, if ETH is transferred to the contract.\n /// Make sure this can not lead to reentrancy attacks.\n function universalTransfer(address token, address to, uint256 value) internal {\n // Don't do anything, if need to send tokens to this address\n if (to == address(this)) return;\n // Don't do anything, if trying to send zero value\n if (value == 0) return;\n if (token == ETH_ADDRESS) {\n /// @dev Note: this can potentially lead to executing code in `to`.\n // solhint-disable-next-line avoid-low-level-calls\n (bool success,) = to.call{value: value}(\"\");\n require(success, \"ETH transfer failed\");\n } else {\n IERC20(token).safeTransfer(to, value);\n }\n }\n\n /// @notice Issues an infinite allowance to the spender, if the current allowance is insufficient\n /// to spend the given amount.\n function universalApproveInfinity(address token, address spender, uint256 amountToSpend) internal {\n // ETH Chad doesn't require your approval\n if (token == ETH_ADDRESS) return;\n // No-op if allowance is already sufficient\n uint256 allowance = IERC20(token).allowance(address(this), spender);\n if (allowance \u003e= amountToSpend) return;\n // Otherwise, reset approval to 0 and set to max allowance\n if (allowance \u003e 0) IERC20(token).safeDecreaseAllowance(spender, allowance);\n IERC20(token).safeIncreaseAllowance(spender, type(uint256).max);\n }\n\n /// @notice Returns the balance of the given token (or native ETH) for the given account.\n function universalBalanceOf(address token, address account) internal view returns (uint256) {\n if (token == ETH_ADDRESS) {\n return account.balance;\n } else {\n return IERC20(token).balanceOf(account);\n }\n }\n\n /// @dev Checks that token is a contract and not ETH_ADDRESS.\n function assertIsContract(address token) internal view {\n // Check that ETH_ADDRESS was not used (in case this is a predeploy on any of the chains)\n if (token == UniversalTokenLib.ETH_ADDRESS) revert TokenNotContract();\n // Check that token is not an EOA\n if (token.code.length == 0) revert TokenNotContract();\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/Admin.sol\n\ncontract Admin is IAdmin, AccessControlEnumerable {\n using UniversalTokenLib for address;\n\n bytes32 public constant RELAYER_ROLE = keccak256(\"RELAYER_ROLE\");\n bytes32 public constant REFUNDER_ROLE = keccak256(\"REFUNDER_ROLE\");\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n uint256 public constant FEE_BPS = 1e6;\n uint256 public constant FEE_RATE_MAX = 0.01e6; // max 1% on origin amount\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Chain gas amount to forward as rebate if requested\n uint256 public chainGasAmount;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n }\n\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n require(newFeeRate \u003c= FEE_RATE_MAX, \"newFeeRate \u003e max\");\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n token.universalTransfer(recipient, feeAmount);\n emit FeesSwept(token, recipient, feeAmount);\n }\n\n function setChainGasAmount(uint256 newChainGasAmount) external onlyRole(GOVERNOR_ROLE) {\n uint256 oldChainGasAmount = chainGasAmount;\n chainGasAmount = newChainGasAmount;\n emit ChainGasAmountUpdated(oldChainGasAmount, newChainGasAmount);\n }\n}\n\n// contracts/FastBridge.sol\n\ncontract FastBridge is IFastBridge, Admin {\n using SafeERC20 for IERC20;\n using UniversalTokenLib for address;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Delay for a transaction after which it could be permisionlessly refunded\n uint256 public constant REFUND_DELAY = 7 days;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeStatus) public bridgeStatuses;\n /// @notice Proof of relayed bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeProof) public bridgeProofs;\n /// @notice Whether bridge has been relayed on destination chain\n mapping(bytes32 =\u003e bool) public bridgeRelays;\n\n /// @dev to prevent replays\n uint256 public nonce;\n // @dev the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @notice Pulls a requested token from the user to the requested recipient.\n /// @dev Be careful of re-entrancy issues when msg.value \u003e 0 and recipient != address(this)\n function _pullToken(address recipient, address token, uint256 amount) internal returns (uint256 amountPulled) {\n if (token != UniversalTokenLib.ETH_ADDRESS) {\n token.assertIsContract();\n // Record token balance before transfer\n amountPulled = IERC20(token).balanceOf(recipient);\n // Token needs to be pulled only if msg.value is zero\n // This way user can specify WETH as the origin asset\n IERC20(token).safeTransferFrom(msg.sender, recipient, amount);\n // Use the difference between the recorded balance and the current balance as the amountPulled\n amountPulled = IERC20(token).balanceOf(recipient) - amountPulled;\n } else {\n // Otherwise, we need to check that ETH amount matches msg.value\n if (amount != msg.value) revert MsgValueIncorrect();\n // Transfer value to recipient if not this address\n if (recipient != address(this)) token.universalTransfer(recipient, amount);\n // We will forward msg.value in the external call later, if recipient is not this contract\n amountPulled = msg.value;\n }\n }\n\n /// @inheritdoc IFastBridge\n function getBridgeTransaction(bytes memory request) public pure returns (BridgeTransaction memory) {\n return abi.decode(request, (BridgeTransaction));\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n // check bridge params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n\n // transfer tokens to bridge contract\n // @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _pullToken(address(this), params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n\n // set status to requested\n bytes memory request = abi.encode(\n BridgeTransaction({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n sendChainGas: params.sendChainGas,\n deadline: params.deadline,\n nonce: nonce++ // increment nonce on every bridge\n })\n );\n bytes32 transactionId = keccak256(request);\n bridgeStatuses[transactionId] = BridgeStatus.REQUESTED;\n\n emit BridgeRequested(\n transactionId,\n params.sender,\n request,\n params.dstChainId,\n params.originToken,\n params.destToken,\n originAmount,\n params.destAmount,\n params.sendChainGas\n );\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes memory request) external payable onlyRole(RELAYER_ROLE) {\n bytes32 transactionId = keccak256(request);\n BridgeTransaction memory transaction = getBridgeTransaction(request);\n if (transaction.destChainId != uint32(block.chainid)) revert ChainIncorrect();\n\n // check haven't exceeded deadline for relay to happen\n if (block.timestamp \u003e transaction.deadline) revert DeadlineExceeded();\n\n // mark bridge transaction as relayed\n if (bridgeRelays[transactionId]) revert TransactionRelayed();\n bridgeRelays[transactionId] = true;\n\n // transfer tokens to recipient on destination chain and gas rebate if requested\n address to = transaction.destRecipient;\n address token = transaction.destToken;\n uint256 amount = transaction.destAmount;\n\n uint256 rebate = chainGasAmount;\n if (!transaction.sendChainGas) {\n // forward erc20\n rebate = 0;\n _pullToken(to, token, amount);\n } else if (token == UniversalTokenLib.ETH_ADDRESS) {\n // lump in gas rebate into amount in native gas token\n _pullToken(to, token, amount + rebate);\n } else {\n // forward erc20 then forward gas rebate in native gas token\n _pullToken(to, token, amount);\n _pullToken(to, UniversalTokenLib.ETH_ADDRESS, rebate);\n }\n\n emit BridgeRelayed(\n transactionId,\n msg.sender,\n to,\n transaction.originChainId,\n transaction.originToken,\n transaction.destToken,\n transaction.originAmount,\n transaction.destAmount,\n rebate\n );\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes memory request, bytes32 destTxHash) external onlyRole(RELAYER_ROLE) {\n bytes32 transactionId = keccak256(request);\n // update bridge tx status given proof provided\n if (bridgeStatuses[transactionId] != BridgeStatus.REQUESTED) revert StatusIncorrect();\n bridgeStatuses[transactionId] = BridgeStatus.RELAYER_PROVED;\n bridgeProofs[transactionId] = BridgeProof({timestamp: uint96(block.timestamp), relayer: msg.sender}); // overflow ok\n\n emit BridgeProofProvided(transactionId, msg.sender, destTxHash);\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint96(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint96).max but\n /// proof.timestamp \u003c type(uint96).max via unchecked statement\n /// @param proof The bridge proof\n /// @return delta Time delta since proof submitted\n function _timeSince(BridgeProof memory proof) internal view returns (uint256 delta) {\n unchecked {\n delta = uint96(block.timestamp) - proof.timestamp;\n }\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n if (bridgeStatuses[transactionId] != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n BridgeProof memory proof = bridgeProofs[transactionId];\n if (proof.relayer != relayer) revert SenderIncorrect();\n return _timeSince(proof) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes memory request, address to) external onlyRole(RELAYER_ROLE) {\n bytes32 transactionId = keccak256(request);\n BridgeTransaction memory transaction = getBridgeTransaction(request);\n\n // update bridge tx status if able to claim origin collateral\n if (bridgeStatuses[transactionId] != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n\n BridgeProof memory proof = bridgeProofs[transactionId];\n if (proof.relayer != msg.sender) revert SenderIncorrect();\n if (_timeSince(proof) \u003c= DISPUTE_PERIOD) revert DisputePeriodNotPassed();\n\n bridgeStatuses[transactionId] = BridgeStatus.RELAYER_CLAIMED;\n\n // update protocol fees if origin fee amount exists\n if (transaction.originFeeAmount \u003e 0) protocolFees[transaction.originToken] += transaction.originFeeAmount;\n\n // transfer origin collateral less fee to specified address\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositClaimed(transactionId, msg.sender, to, token, amount);\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n if (bridgeStatuses[transactionId] != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(bridgeProofs[transactionId]) \u003e DISPUTE_PERIOD) revert DisputePeriodPassed();\n\n // @dev relayer gets slashed effectively if dest relay has gone thru\n bridgeStatuses[transactionId] = BridgeStatus.REQUESTED;\n delete bridgeProofs[transactionId];\n\n emit BridgeProofDisputed(transactionId, msg.sender);\n }\n\n /// @inheritdoc IFastBridge\n function refund(bytes memory request) external {\n bytes32 transactionId = keccak256(request);\n BridgeTransaction memory transaction = getBridgeTransaction(request);\n\n if (hasRole(REFUNDER_ROLE, msg.sender)) {\n // Refunder can refund if deadline has passed\n if (block.timestamp \u003c= transaction.deadline) revert DeadlineNotExceeded();\n } else {\n // Permissionless refund is allowed after REFUND_DELAY\n if (block.timestamp \u003c= transaction.deadline + REFUND_DELAY) revert DeadlineNotExceeded();\n }\n\n // set status to refunded if still in requested state\n if (bridgeStatuses[transactionId] != BridgeStatus.REQUESTED) revert StatusIncorrect();\n bridgeStatuses[transactionId] = BridgeStatus.REFUNDED;\n\n // transfer origin collateral back to original sender\n address to = transaction.originSender;\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount + transaction.originFeeAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n }\n}\n\n// test/FastBridgeMock.sol\n\ncontract FastBridgeMock is IFastBridge, Admin {\n // @dev the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @dev to prevent replays\n uint256 public nonce;\n\n function getBridgeTransaction(bytes memory request) public pure returns (BridgeTransaction memory) {\n return abi.decode(request, (BridgeTransaction));\n }\n\n // used for testing in go.\n // see: https://ethereum.stackexchange.com/questions/21155/how-to-expose-enum-in-solidity-contract\n // make sure to update fastbridge/status.go if this changes\n // or underliyng enum changes.\n //\n // TODO: a foundry test should be added to ensure this is always in sync.\n function getEnumKeyByValue(FastBridge.BridgeStatus keyValue) public pure returns (string memory) {\n if (FastBridge.BridgeStatus.NULL == keyValue) return \"NULL\";\n if (FastBridge.BridgeStatus.REQUESTED == keyValue) return \"REQUESTED\";\n if (FastBridge.BridgeStatus.RELAYER_PROVED == keyValue) return \"RELAYER_PROVED\";\n if (FastBridge.BridgeStatus.RELAYER_CLAIMED == keyValue) return \"RELAYER_CLAIMED\";\n if (FastBridge.BridgeStatus.REFUNDED == keyValue) return \"REFUNDED\";\n return \"\";\n }\n\n function mockBridgeRequest(bytes32 transactionId, address sender, BridgeParams memory params) external {\n uint256 originFeeAmount = (params.originAmount * protocolFeeRate) / FEE_BPS;\n params.originAmount -= originFeeAmount;\n\n bytes memory request = abi.encode(\n BridgeTransaction({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: params.originAmount, // includes relayer fee\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n sendChainGas: params.sendChainGas,\n deadline: params.deadline,\n nonce: nonce++ // increment nonce on every bridge\n })\n );\n\n emit BridgeRequested(\n transactionId,\n params.sender,\n request,\n params.dstChainId,\n params.originToken,\n params.destToken,\n params.originAmount,\n params.destAmount,\n params.sendChainGas\n );\n }\n\n function mockBridgeRequestRaw(bytes32 transactionId, address sender, bytes memory request) external {\n BridgeTransaction memory transaction = getBridgeTransaction(request);\n emit BridgeRequested(\n transactionId,\n transaction.originSender,\n request,\n transaction.destChainId,\n transaction.originToken,\n transaction.destToken,\n transaction.originAmount,\n transaction.destAmount,\n transaction.sendChainGas\n );\n }\n\n function mockBridgeRelayer(\n bytes32 transactionId,\n address relayer,\n address to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n )\n external\n {\n emit BridgeRelayed(\n transactionId, relayer, to, originChainId, originToken, destToken, originAmount, destAmount, chainGasAmount\n );\n }\n\n function bridge(BridgeParams memory params) external payable {\n revert(\"not implemented\");\n }\n\n function relay(bytes memory request) external payable {\n revert(\"not implemented\");\n }\n\n function prove(bytes memory request, bytes32 destTxHash) external {\n revert(\"not implemented\");\n }\n\n function canClaim(bytes32 transactionid, address relayer) external view returns (bool) {\n revert(\"not implemented\");\n }\n\n function claim(bytes memory request, address to) external {\n revert(\"not implemented\");\n }\n\n function dispute(bytes32 transactionId) external {\n revert(\"not implemented\");\n }\n\n function refund(bytes memory request) external {\n revert(\"not implemented\");\n }\n}\n","language":"Solidity","languageVersion":"0.8.20","compilerVersion":"0.8.20","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"","srcMapRuntime":"","abiDefinition":[{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"}],"userDoc":{"kind":"user","methods":{},"version":1},"developerDoc":{"details":"Implementation of the {IERC165} interface. Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check for the additional interface id that will be supported. For example: ```solidity function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId); } ```","kind":"dev","methods":{"supportsInterface(bytes4)":{"details":"See {IERC165-supportsInterface}."}},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.20+commit.a1b79de6\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"bytes4\",\"name\":\"interfaceId\",\"type\":\"bytes4\"}],\"name\":\"supportsInterface\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"}],\"devdoc\":{\"details\":\"Implementation of the {IERC165} interface. Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check for the additional interface id that will be supported. For example: ```solidity function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId); } ```\",\"kind\":\"dev\",\"methods\":{\"supportsInterface(bytes4)\":{\"details\":\"See {IERC165-supportsInterface}.\"}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeMock.sol\":\"ERC165\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeMock.sol\":{\"keccak256\":\"0x620e81214ecd324ae8b971219291f176c454ce76fb1c01d656428096da8f1366\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://18e556772c12e13aa2d52a50cc7c48e676c8d5af22b90adaf7befb39cdd08e64\",\"dweb:/ipfs/QmPrQc98TxHCFMeuFNADyjr6Nqo52rHhHy1LBcsVdMRXjL\"]}},\"version\":1}"},"hashes":{"supportsInterface(bytes4)":"01ffc9a7"}},"solidity/FastBridgeMock.sol:EnumerableSet":{"code":"0x60566037600b82828239805160001a607314602a57634e487b7160e01b600052600060045260246000fd5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600080fdfea264697066735822122061192eb5b75fa46e55c42a092ec06111165ec29e2ac6d00c6d247f0df8ba17fd64736f6c63430008140033","runtime-code":"0x73000000000000000000000000000000000000000030146080604052600080fdfea264697066735822122061192eb5b75fa46e55c42a092ec06111165ec29e2ac6d00c6d247f0df8ba17fd64736f6c63430008140033","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.20 ^0.8.20;\n\n// contracts/interfaces/IAdmin.sol\n\ninterface IAdmin {\n // ============ Events ============\n\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n event ChainGasAmountUpdated(uint256 oldChainGasAmount, uint256 newChainGasAmount);\n\n // ============ Methods ============\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n\n function setChainGasAmount(uint256 newChainGasAmount) external;\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/libs/Errors.sol\n\nerror DeadlineExceeded();\nerror DeadlineNotExceeded();\nerror DeadlineTooShort();\nerror InsufficientOutputAmount();\n\nerror MsgValueIncorrect();\nerror PoolNotFound();\nerror TokenAddressMismatch();\nerror TokenNotContract();\nerror TokenNotETH();\nerror TokensIdentical();\n\nerror ChainIncorrect();\nerror AmountIncorrect();\nerror ZeroAddress();\n\nerror DisputePeriodNotPassed();\nerror DisputePeriodPassed();\nerror SenderIncorrect();\nerror StatusIncorrect();\nerror TransactionIdIncorrect();\nerror TransactionRelayed();\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// contracts/libs/UniversalToken.sol\n\nlibrary UniversalTokenLib {\n using SafeERC20 for IERC20;\n\n address internal constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Transfers tokens to the given account. Reverts if transfer is not successful.\n /// @dev This might trigger fallback, if ETH is transferred to the contract.\n /// Make sure this can not lead to reentrancy attacks.\n function universalTransfer(address token, address to, uint256 value) internal {\n // Don't do anything, if need to send tokens to this address\n if (to == address(this)) return;\n // Don't do anything, if trying to send zero value\n if (value == 0) return;\n if (token == ETH_ADDRESS) {\n /// @dev Note: this can potentially lead to executing code in `to`.\n // solhint-disable-next-line avoid-low-level-calls\n (bool success,) = to.call{value: value}(\"\");\n require(success, \"ETH transfer failed\");\n } else {\n IERC20(token).safeTransfer(to, value);\n }\n }\n\n /// @notice Issues an infinite allowance to the spender, if the current allowance is insufficient\n /// to spend the given amount.\n function universalApproveInfinity(address token, address spender, uint256 amountToSpend) internal {\n // ETH Chad doesn't require your approval\n if (token == ETH_ADDRESS) return;\n // No-op if allowance is already sufficient\n uint256 allowance = IERC20(token).allowance(address(this), spender);\n if (allowance \u003e= amountToSpend) return;\n // Otherwise, reset approval to 0 and set to max allowance\n if (allowance \u003e 0) IERC20(token).safeDecreaseAllowance(spender, allowance);\n IERC20(token).safeIncreaseAllowance(spender, type(uint256).max);\n }\n\n /// @notice Returns the balance of the given token (or native ETH) for the given account.\n function universalBalanceOf(address token, address account) internal view returns (uint256) {\n if (token == ETH_ADDRESS) {\n return account.balance;\n } else {\n return IERC20(token).balanceOf(account);\n }\n }\n\n /// @dev Checks that token is a contract and not ETH_ADDRESS.\n function assertIsContract(address token) internal view {\n // Check that ETH_ADDRESS was not used (in case this is a predeploy on any of the chains)\n if (token == UniversalTokenLib.ETH_ADDRESS) revert TokenNotContract();\n // Check that token is not an EOA\n if (token.code.length == 0) revert TokenNotContract();\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/Admin.sol\n\ncontract Admin is IAdmin, AccessControlEnumerable {\n using UniversalTokenLib for address;\n\n bytes32 public constant RELAYER_ROLE = keccak256(\"RELAYER_ROLE\");\n bytes32 public constant REFUNDER_ROLE = keccak256(\"REFUNDER_ROLE\");\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n uint256 public constant FEE_BPS = 1e6;\n uint256 public constant FEE_RATE_MAX = 0.01e6; // max 1% on origin amount\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Chain gas amount to forward as rebate if requested\n uint256 public chainGasAmount;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n }\n\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n require(newFeeRate \u003c= FEE_RATE_MAX, \"newFeeRate \u003e max\");\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n token.universalTransfer(recipient, feeAmount);\n emit FeesSwept(token, recipient, feeAmount);\n }\n\n function setChainGasAmount(uint256 newChainGasAmount) external onlyRole(GOVERNOR_ROLE) {\n uint256 oldChainGasAmount = chainGasAmount;\n chainGasAmount = newChainGasAmount;\n emit ChainGasAmountUpdated(oldChainGasAmount, newChainGasAmount);\n }\n}\n\n// contracts/FastBridge.sol\n\ncontract FastBridge is IFastBridge, Admin {\n using SafeERC20 for IERC20;\n using UniversalTokenLib for address;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Delay for a transaction after which it could be permisionlessly refunded\n uint256 public constant REFUND_DELAY = 7 days;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeStatus) public bridgeStatuses;\n /// @notice Proof of relayed bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeProof) public bridgeProofs;\n /// @notice Whether bridge has been relayed on destination chain\n mapping(bytes32 =\u003e bool) public bridgeRelays;\n\n /// @dev to prevent replays\n uint256 public nonce;\n // @dev the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @notice Pulls a requested token from the user to the requested recipient.\n /// @dev Be careful of re-entrancy issues when msg.value \u003e 0 and recipient != address(this)\n function _pullToken(address recipient, address token, uint256 amount) internal returns (uint256 amountPulled) {\n if (token != UniversalTokenLib.ETH_ADDRESS) {\n token.assertIsContract();\n // Record token balance before transfer\n amountPulled = IERC20(token).balanceOf(recipient);\n // Token needs to be pulled only if msg.value is zero\n // This way user can specify WETH as the origin asset\n IERC20(token).safeTransferFrom(msg.sender, recipient, amount);\n // Use the difference between the recorded balance and the current balance as the amountPulled\n amountPulled = IERC20(token).balanceOf(recipient) - amountPulled;\n } else {\n // Otherwise, we need to check that ETH amount matches msg.value\n if (amount != msg.value) revert MsgValueIncorrect();\n // Transfer value to recipient if not this address\n if (recipient != address(this)) token.universalTransfer(recipient, amount);\n // We will forward msg.value in the external call later, if recipient is not this contract\n amountPulled = msg.value;\n }\n }\n\n /// @inheritdoc IFastBridge\n function getBridgeTransaction(bytes memory request) public pure returns (BridgeTransaction memory) {\n return abi.decode(request, (BridgeTransaction));\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n // check bridge params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n\n // transfer tokens to bridge contract\n // @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _pullToken(address(this), params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n\n // set status to requested\n bytes memory request = abi.encode(\n BridgeTransaction({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n sendChainGas: params.sendChainGas,\n deadline: params.deadline,\n nonce: nonce++ // increment nonce on every bridge\n })\n );\n bytes32 transactionId = keccak256(request);\n bridgeStatuses[transactionId] = BridgeStatus.REQUESTED;\n\n emit BridgeRequested(\n transactionId,\n params.sender,\n request,\n params.dstChainId,\n params.originToken,\n params.destToken,\n originAmount,\n params.destAmount,\n params.sendChainGas\n );\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes memory request) external payable onlyRole(RELAYER_ROLE) {\n bytes32 transactionId = keccak256(request);\n BridgeTransaction memory transaction = getBridgeTransaction(request);\n if (transaction.destChainId != uint32(block.chainid)) revert ChainIncorrect();\n\n // check haven't exceeded deadline for relay to happen\n if (block.timestamp \u003e transaction.deadline) revert DeadlineExceeded();\n\n // mark bridge transaction as relayed\n if (bridgeRelays[transactionId]) revert TransactionRelayed();\n bridgeRelays[transactionId] = true;\n\n // transfer tokens to recipient on destination chain and gas rebate if requested\n address to = transaction.destRecipient;\n address token = transaction.destToken;\n uint256 amount = transaction.destAmount;\n\n uint256 rebate = chainGasAmount;\n if (!transaction.sendChainGas) {\n // forward erc20\n rebate = 0;\n _pullToken(to, token, amount);\n } else if (token == UniversalTokenLib.ETH_ADDRESS) {\n // lump in gas rebate into amount in native gas token\n _pullToken(to, token, amount + rebate);\n } else {\n // forward erc20 then forward gas rebate in native gas token\n _pullToken(to, token, amount);\n _pullToken(to, UniversalTokenLib.ETH_ADDRESS, rebate);\n }\n\n emit BridgeRelayed(\n transactionId,\n msg.sender,\n to,\n transaction.originChainId,\n transaction.originToken,\n transaction.destToken,\n transaction.originAmount,\n transaction.destAmount,\n rebate\n );\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes memory request, bytes32 destTxHash) external onlyRole(RELAYER_ROLE) {\n bytes32 transactionId = keccak256(request);\n // update bridge tx status given proof provided\n if (bridgeStatuses[transactionId] != BridgeStatus.REQUESTED) revert StatusIncorrect();\n bridgeStatuses[transactionId] = BridgeStatus.RELAYER_PROVED;\n bridgeProofs[transactionId] = BridgeProof({timestamp: uint96(block.timestamp), relayer: msg.sender}); // overflow ok\n\n emit BridgeProofProvided(transactionId, msg.sender, destTxHash);\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint96(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint96).max but\n /// proof.timestamp \u003c type(uint96).max via unchecked statement\n /// @param proof The bridge proof\n /// @return delta Time delta since proof submitted\n function _timeSince(BridgeProof memory proof) internal view returns (uint256 delta) {\n unchecked {\n delta = uint96(block.timestamp) - proof.timestamp;\n }\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n if (bridgeStatuses[transactionId] != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n BridgeProof memory proof = bridgeProofs[transactionId];\n if (proof.relayer != relayer) revert SenderIncorrect();\n return _timeSince(proof) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes memory request, address to) external onlyRole(RELAYER_ROLE) {\n bytes32 transactionId = keccak256(request);\n BridgeTransaction memory transaction = getBridgeTransaction(request);\n\n // update bridge tx status if able to claim origin collateral\n if (bridgeStatuses[transactionId] != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n\n BridgeProof memory proof = bridgeProofs[transactionId];\n if (proof.relayer != msg.sender) revert SenderIncorrect();\n if (_timeSince(proof) \u003c= DISPUTE_PERIOD) revert DisputePeriodNotPassed();\n\n bridgeStatuses[transactionId] = BridgeStatus.RELAYER_CLAIMED;\n\n // update protocol fees if origin fee amount exists\n if (transaction.originFeeAmount \u003e 0) protocolFees[transaction.originToken] += transaction.originFeeAmount;\n\n // transfer origin collateral less fee to specified address\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositClaimed(transactionId, msg.sender, to, token, amount);\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n if (bridgeStatuses[transactionId] != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(bridgeProofs[transactionId]) \u003e DISPUTE_PERIOD) revert DisputePeriodPassed();\n\n // @dev relayer gets slashed effectively if dest relay has gone thru\n bridgeStatuses[transactionId] = BridgeStatus.REQUESTED;\n delete bridgeProofs[transactionId];\n\n emit BridgeProofDisputed(transactionId, msg.sender);\n }\n\n /// @inheritdoc IFastBridge\n function refund(bytes memory request) external {\n bytes32 transactionId = keccak256(request);\n BridgeTransaction memory transaction = getBridgeTransaction(request);\n\n if (hasRole(REFUNDER_ROLE, msg.sender)) {\n // Refunder can refund if deadline has passed\n if (block.timestamp \u003c= transaction.deadline) revert DeadlineNotExceeded();\n } else {\n // Permissionless refund is allowed after REFUND_DELAY\n if (block.timestamp \u003c= transaction.deadline + REFUND_DELAY) revert DeadlineNotExceeded();\n }\n\n // set status to refunded if still in requested state\n if (bridgeStatuses[transactionId] != BridgeStatus.REQUESTED) revert StatusIncorrect();\n bridgeStatuses[transactionId] = BridgeStatus.REFUNDED;\n\n // transfer origin collateral back to original sender\n address to = transaction.originSender;\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount + transaction.originFeeAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n }\n}\n\n// test/FastBridgeMock.sol\n\ncontract FastBridgeMock is IFastBridge, Admin {\n // @dev the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @dev to prevent replays\n uint256 public nonce;\n\n function getBridgeTransaction(bytes memory request) public pure returns (BridgeTransaction memory) {\n return abi.decode(request, (BridgeTransaction));\n }\n\n // used for testing in go.\n // see: https://ethereum.stackexchange.com/questions/21155/how-to-expose-enum-in-solidity-contract\n // make sure to update fastbridge/status.go if this changes\n // or underliyng enum changes.\n //\n // TODO: a foundry test should be added to ensure this is always in sync.\n function getEnumKeyByValue(FastBridge.BridgeStatus keyValue) public pure returns (string memory) {\n if (FastBridge.BridgeStatus.NULL == keyValue) return \"NULL\";\n if (FastBridge.BridgeStatus.REQUESTED == keyValue) return \"REQUESTED\";\n if (FastBridge.BridgeStatus.RELAYER_PROVED == keyValue) return \"RELAYER_PROVED\";\n if (FastBridge.BridgeStatus.RELAYER_CLAIMED == keyValue) return \"RELAYER_CLAIMED\";\n if (FastBridge.BridgeStatus.REFUNDED == keyValue) return \"REFUNDED\";\n return \"\";\n }\n\n function mockBridgeRequest(bytes32 transactionId, address sender, BridgeParams memory params) external {\n uint256 originFeeAmount = (params.originAmount * protocolFeeRate) / FEE_BPS;\n params.originAmount -= originFeeAmount;\n\n bytes memory request = abi.encode(\n BridgeTransaction({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: params.originAmount, // includes relayer fee\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n sendChainGas: params.sendChainGas,\n deadline: params.deadline,\n nonce: nonce++ // increment nonce on every bridge\n })\n );\n\n emit BridgeRequested(\n transactionId,\n params.sender,\n request,\n params.dstChainId,\n params.originToken,\n params.destToken,\n params.originAmount,\n params.destAmount,\n params.sendChainGas\n );\n }\n\n function mockBridgeRequestRaw(bytes32 transactionId, address sender, bytes memory request) external {\n BridgeTransaction memory transaction = getBridgeTransaction(request);\n emit BridgeRequested(\n transactionId,\n transaction.originSender,\n request,\n transaction.destChainId,\n transaction.originToken,\n transaction.destToken,\n transaction.originAmount,\n transaction.destAmount,\n transaction.sendChainGas\n );\n }\n\n function mockBridgeRelayer(\n bytes32 transactionId,\n address relayer,\n address to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n )\n external\n {\n emit BridgeRelayed(\n transactionId, relayer, to, originChainId, originToken, destToken, originAmount, destAmount, chainGasAmount\n );\n }\n\n function bridge(BridgeParams memory params) external payable {\n revert(\"not implemented\");\n }\n\n function relay(bytes memory request) external payable {\n revert(\"not implemented\");\n }\n\n function prove(bytes memory request, bytes32 destTxHash) external {\n revert(\"not implemented\");\n }\n\n function canClaim(bytes32 transactionid, address relayer) external view returns (bool) {\n revert(\"not implemented\");\n }\n\n function claim(bytes memory request, address to) external {\n revert(\"not implemented\");\n }\n\n function dispute(bytes32 transactionId) external {\n revert(\"not implemented\");\n }\n\n function refund(bytes memory request) external {\n revert(\"not implemented\");\n }\n}\n","language":"Solidity","languageVersion":"0.8.20","compilerVersion":"0.8.20","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"24854:11640:0:-:0;;;;;;;;;;;;;;;-1:-1:-1;;;24854:11640:0;;;;;;;;;;;;;;;;;","srcMapRuntime":"24854:11640:0:-:0;;;;;;;;","abiDefinition":[],"userDoc":{"kind":"user","methods":{},"version":1},"developerDoc":{"details":"Library for managing https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive types. Sets have the following properties: - Elements are added, removed, and checked for existence in constant time (O(1)). - Elements are enumerated in O(n). No guarantees are made on the ordering. ```solidity contract Example { // Add the library methods using EnumerableSet for EnumerableSet.AddressSet; // Declare a set state variable EnumerableSet.AddressSet private mySet; } ``` As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`) and `uint256` (`UintSet`) are supported. [WARNING] ==== Trying to delete such a structure from storage will likely result in data corruption, rendering the structure unusable. See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info. In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an array of EnumerableSet. ====","kind":"dev","methods":{},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.20+commit.a1b79de6\"},\"language\":\"Solidity\",\"output\":{\"abi\":[],\"devdoc\":{\"details\":\"Library for managing https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive types. Sets have the following properties: - Elements are added, removed, and checked for existence in constant time (O(1)). - Elements are enumerated in O(n). No guarantees are made on the ordering. ```solidity contract Example { // Add the library methods using EnumerableSet for EnumerableSet.AddressSet; // Declare a set state variable EnumerableSet.AddressSet private mySet; } ``` As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`) and `uint256` (`UintSet`) are supported. [WARNING] ==== Trying to delete such a structure from storage will likely result in data corruption, rendering the structure unusable. See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info. In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an array of EnumerableSet. ====\",\"kind\":\"dev\",\"methods\":{},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeMock.sol\":\"EnumerableSet\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeMock.sol\":{\"keccak256\":\"0x620e81214ecd324ae8b971219291f176c454ce76fb1c01d656428096da8f1366\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://18e556772c12e13aa2d52a50cc7c48e676c8d5af22b90adaf7befb39cdd08e64\",\"dweb:/ipfs/QmPrQc98TxHCFMeuFNADyjr6Nqo52rHhHy1LBcsVdMRXjL\"]}},\"version\":1}"},"hashes":{}},"solidity/FastBridgeMock.sol:FastBridge":{"code":"0x60a06040523480156200001157600080fd5b5060405162002d7a38038062002d7a833981016040819052620000349162000194565b80620000426000826200004f565b50504360805250620001bf565b6000806200005e84846200008c565b90508015620000835760008481526001602052604090206200008190846200013a565b505b90505b92915050565b6000828152602081815260408083206001600160a01b038516845290915281205460ff1662000131576000838152602081815260408083206001600160a01b03861684529091529020805460ff19166001179055620000e83390565b6001600160a01b0316826001600160a01b0316847f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a450600162000086565b50600062000086565b600062000083836001600160a01b0384166000818152600183016020526040812054620001315750815460018181018455600084815260208082209093018490558454848252828601909352604090209190915562000086565b600060208284031215620001a757600080fd5b81516001600160a01b03811681146200008357600080fd5b608051612b9f620001db60003960006106510152612b9f6000f3fe60806040526004361061026a5760003560e01c80639010d07c11610153578063add98c70116100cb578063ca15c8731161007f578063d547741f11610064578063d547741f146107a1578063dcf844a7146107c1578063e00a83e0146107ee57600080fd5b8063ca15c8731461074d578063ccc574901461076d57600080fd5b8063b13aa2d6116100b0578063b13aa2d6146106f6578063b250fe6b14610716578063bf333f2c1461073657600080fd5b8063add98c70146106c0578063affed0e0146106e057600080fd5b8063a217fddf11610122578063a5bbe22b11610107578063a5bbe22b1461047f578063aa9641ab14610673578063ac11fb1a1461069357600080fd5b8063a217fddf1461062a578063a3ec191a1461063f57600080fd5b80639010d07c146104f857806391ad50391461053057806391d14854146105b2578063926d7d7f146105f657600080fd5b806341fcb612116101e65780635eb7d946116101b55780638379a24f1161019a5780638379a24f14610495578063886d36ff146104c55780638f0d6f17146104e557600080fd5b80635eb7d9461461045f578063820688d51461047f57600080fd5b806341fcb612146103e2578063458516941461040257806358f85880146104155780635960ccf21461042b57600080fd5b80630f5f6ed71161023d578063248a9ca311610222578063248a9ca3146103725780632f2ff15d146103a257806336568abe146103c257600080fd5b80630f5f6ed714610345578063190da5951461035b57600080fd5b806301ffc9a71461026f57806303ed0ee5146102a4578063051287bc146102e657806306f333f214610323575b600080fd5b34801561027b57600080fd5b5061028f61028a3660046122fc565b610804565b60405190151581526020015b60405180910390f35b3480156102b057600080fd5b506102d87f043c983c49d46f0e102151eaf8085d4a2e6571d5df2d47b013f39bddfd4a639d81565b60405190815260200161029b565b3480156102f257600080fd5b5061031661030136600461233e565b60056020526000908152604090205460ff1681565b60405161029b9190612386565b34801561032f57600080fd5b5061034361033e3660046123ec565b610860565b005b34801561035157600080fd5b506102d861271081565b34801561036757600080fd5b506102d862093a8081565b34801561037e57600080fd5b506102d861038d36600461233e565b60009081526020819052604090206001015490565b3480156103ae57600080fd5b506103436103bd366004612425565b610927565b3480156103ce57600080fd5b506103436103dd366004612425565b610952565b3480156103ee57600080fd5b506103436103fd366004612572565b61099e565b6103436104103660046125ef565b610bd7565b34801561042157600080fd5b506102d860025481565b34801561043757600080fd5b506102d87fdb9556138406326f00296e13ea2ad7db24ba82381212d816b1a40c23b466b32781565b34801561046b57600080fd5b5061034361047a366004612692565b610ee5565b34801561048b57600080fd5b506102d861070881565b3480156104a157600080fd5b5061028f6104b036600461233e565b60076020526000908152604090205460ff1681565b3480156104d157600080fd5b506103436104e03660046126cf565b6110bd565b6103436104f3366004612692565b6111f0565b34801561050457600080fd5b50610518610513366004612714565b611437565b6040516001600160a01b03909116815260200161029b565b34801561053c57600080fd5b5061058661054b36600461233e565b6006602052600090815260409020546bffffffffffffffffffffffff8116906c0100000000000000000000000090046001600160a01b031682565b604080516bffffffffffffffffffffffff90931683526001600160a01b0390911660208301520161029b565b3480156105be57600080fd5b5061028f6105cd366004612425565b6000918252602082815260408084206001600160a01b0393909316845291905290205460ff1690565b34801561060257600080fd5b506102d87fe2b7fb3b832174769106daebcfd6d1970523240dda11281102db9363b83b0dc481565b34801561063657600080fd5b506102d8600081565b34801561064b57600080fd5b506102d87f000000000000000000000000000000000000000000000000000000000000000081565b34801561067f57600080fd5b5061028f61068e366004612425565b611456565b34801561069f57600080fd5b506106b36106ae366004612692565b611559565b60405161029b9190612736565b3480156106cc57600080fd5b506103436106db36600461233e565b6115cc565b3480156106ec57600080fd5b506102d860085481565b34801561070257600080fd5b5061034361071136600461233e565b611735565b34801561072257600080fd5b5061034361073136600461233e565b611817565b34801561074257600080fd5b506102d8620f424081565b34801561075957600080fd5b506102d861076836600461233e565b61187f565b34801561077957600080fd5b506102d87f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f5581565b3480156107ad57600080fd5b506103436107bc366004612425565b611896565b3480156107cd57600080fd5b506102d86107dc36600461281c565b60036020526000908152604090205481565b3480156107fa57600080fd5b506102d860045481565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f5a05180f00000000000000000000000000000000000000000000000000000000148061085a575061085a826118bb565b92915050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f5561088a81611952565b6001600160a01b038316600090815260036020526040812054908190036108b15750505050565b6001600160a01b0384166000818152600360205260408120556108d590848361195f565b604080516001600160a01b038087168252851660208201529081018290527f244e51bc38c1452fa8aaf487bcb4bca36c2baa3a5fbdb776b1eabd8dc6d277cd9060600160405180910390a1505b505050565b60008281526020819052604090206001015461094281611952565b61094c8383611a82565b50505050565b6001600160a01b0381163314610994576040517f6697b23200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6109228282611ab7565b7fe2b7fb3b832174769106daebcfd6d1970523240dda11281102db9363b83b0dc46109c881611952565b8251602084012060006109da85611559565b9050600260008381526005602052604090205460ff166004811115610a0157610a01612357565b14610a38576040517f4145817200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000828152600660209081526040918290208251808401909352546bffffffffffffffffffffffff811683526c0100000000000000000000000090046001600160a01b03169082018190523314610abb576040517f4af43a9000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80516107089042036bffffffffffffffffffffffff1611610b08576040517f1992d0bd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000838152600560205260409020805460ff1916600317905561010082015115610b645761010082015160808301516001600160a01b031660009081526003602052604081208054909190610b5e908490612868565b90915550505b608082015160c0830151610b826001600160a01b038316888361195f565b604080516001600160a01b03848116825260208201849052891691339188917f582211c35a2139ac3bbaac74663c6a1f56c6cbb658b41fe11fd45a82074ac67891015b60405180910390a45050505050505050565b46816000015163ffffffff1603610c1a576040517f7029fdf900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60a08101511580610c2d575060c0810151155b15610c64576040517fe38820c800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60608101516001600160a01b03161580610c89575060808101516001600160a01b0316155b15610cc0576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610ccc61070842612868565b8161010001511015610d0a576040517f04b7fcc800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000610d1f3083606001518460a00151611ae4565b90506000806002541115610d4c57620f424060025483610d3f919061287b565b610d499190612892565b90505b610d5681836128cd565b915060006040518061018001604052804663ffffffff168152602001856000015163ffffffff16815260200185602001516001600160a01b0316815260200185604001516001600160a01b0316815260200185606001516001600160a01b0316815260200185608001516001600160a01b031681526020018481526020018560c0015181526020018381526020018560e0015115158152602001856101000151815260200160086000815480929190610e0e906128e0565b909155509052604051610e249190602001612736565b604080518083037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0018152828252805160208083019190912060008181526005835293909320805460ff191660011790558701518751606089015160808a015160c08b015160e08c015195985095966001600160a01b039094169587957f120ea0364f36cdac7983bcfdd55270ca09d7f9b314a2ebc425a3b01ab1d6403a95610ed6958b959094909390928e9261293c565b60405180910390a35050505050565b805160208201206000610ef783611559565b3360009081527fd2043bf65931af3dbecf60d0db8f40e4160406d7beb00522f4200cf4944a1eb8602052604090205490915060ff1615610f74578061014001514211610f6f576040517fe15ff9ea00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610fc0565b62093a80816101400151610f889190612868565b4211610fc0576040517fe15ff9ea00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600160008381526005602052604090205460ff166004811115610fe557610fe5612357565b1461101c576040517f4145817200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600082815260056020526040808220805460ff19166004179055820151608083015161010084015160c0850151929391926110579190612868565b905061106d6001600160a01b038316848361195f565b604080516001600160a01b0384811682526020820184905285169187917fb4c55c0c9bc613519b920e88748090150b890a875d307f21bea7d4fb2e8bc958910160405180910390a3505050505050565b7fe2b7fb3b832174769106daebcfd6d1970523240dda11281102db9363b83b0dc46110e781611952565b82516020840120600160008281526005602052604090205460ff16600481111561111357611113612357565b1461114a576040517f4145817200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008181526005602090815260408083208054600260ff19909116179055805180820182526bffffffffffffffffffffffff4281168252338285018181528787526006865295849020925195516001600160a01b03166c0100000000000000000000000002959091169490941790555185815283917f4ac8af8a2cd87193d64dfc7a3b8d9923b714ec528b18725d080aa1299be0c5e4910160405180910390a350505050565b7fe2b7fb3b832174769106daebcfd6d1970523240dda11281102db9363b83b0dc461121a81611952565b81516020830120600061122c84611559565b90504663ffffffff16816020015163ffffffff1614611277576040517f7029fdf900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8061014001514211156112b6576040517f559895a300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008281526007602052604090205460ff16156112ff576040517fbef7bb7d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000828152600760205260409020805460ff19166001179055606081015160a082015160e083015160045461012085015161134857506000611342848484611ae4565b506113b9565b7fffffffffffffffffffffffff11111111111111111111111111111111111111126001600160a01b0384160161138c5761134284846113878486612868565b611ae4565b611397848484611ae4565b506113b78473eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee83611ae4565b505b845160808087015160a08089015160c0808b015160e08c01516040805163ffffffff90991689526001600160a01b0396871660208a0152938616938801939093526060870152938501528301849052861691339189917ff8ae392d784b1ea5e8881bfa586d81abf07ef4f1e2fc75f7fe51c90f05199a5c9101610bc5565b600082815260016020526040812061144f9083611cb3565b9392505050565b6000600260008481526005602052604090205460ff16600481111561147d5761147d612357565b146114b4576040517f4145817200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000838152600660209081526040918290208251808401909352546bffffffffffffffffffffffff811683526001600160a01b036c01000000000000000000000000909104811691830182905284161461153a576040517f4af43a9000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80516107089042036bffffffffffffffffffffffff1611949350505050565b604080516101808101825260008082526020808301829052928201819052606082018190526080820181905260a0820181905260c0820181905260e082018190526101008201819052610120820181905261014082018190526101608201528251909161085a91840181019084016129ed565b7f043c983c49d46f0e102151eaf8085d4a2e6571d5df2d47b013f39bddfd4a639d6115f681611952565b600260008381526005602052604090205460ff16600481111561161b5761161b612357565b14611652576040517f4145817200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000828152600660209081526040918290208251808401909352546bffffffffffffffffffffffff8082168085526c010000000000000000000000009092046001600160a01b031693909201929092526107089142031611156116e1576040517f3e908aac00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000828152600560209081526040808320805460ff19166001179055600690915280822082905551339184917f0695cf1d39b3055dcd0fe02d8b47eaf0d5a13e1996de925de59d0ef9b7f7fad49190a35050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f5561175f81611952565b6127108211156117d0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f6e657746656552617465203e206d61780000000000000000000000000000000060448201526064015b60405180910390fd5b600280549083905560408051828152602081018590527f14914da2bf76024616fbe1859783fcd4dbddcb179b1f3a854949fbf920dcb95791015b60405180910390a1505050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f5561184181611952565b600480549083905560408051828152602081018590527f5cf09b12f3f56b4c564d51b25b40360af6d795198adb61ae0806a36c294323fa910161180a565b600081815260016020526040812061085a90611cbf565b6000828152602081905260409020600101546118b181611952565b61094c8383611ab7565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f7965db0b00000000000000000000000000000000000000000000000000000000148061085a57507f01ffc9a7000000000000000000000000000000000000000000000000000000007fffffffff0000000000000000000000000000000000000000000000000000000083161461085a565b61195c8133611cc9565b50565b306001600160a01b0383160361197457505050565b8060000361198157505050565b7fffffffffffffffffffffffff11111111111111111111111111111111111111126001600160a01b03841601611a6e576000826001600160a01b03168260405160006040518083038185875af1925050503d80600081146119fe576040519150601f19603f3d011682016040523d82523d6000602084013e611a03565b606091505b505090508061094c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f455448207472616e73666572206661696c65640000000000000000000000000060448201526064016117c7565b6109226001600160a01b0384168383611d39565b600080611a8f8484611dad565b9050801561144f576000848152600160205260409020611aaf9084611e57565b509392505050565b600080611ac48484611e6c565b9050801561144f576000848152600160205260409020611aaf9084611eef565b60006001600160a01b03831673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee14611c4d57611b1c836001600160a01b0316611f04565b6040517f70a082310000000000000000000000000000000000000000000000000000000081526001600160a01b0385811660048301528416906370a0823190602401602060405180830381865afa158015611b7b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b9f9190612ab9565b9050611bb66001600160a01b038416338685611faa565b6040517f70a082310000000000000000000000000000000000000000000000000000000081526001600160a01b0385811660048301528291908516906370a0823190602401602060405180830381865afa158015611c18573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c3c9190612ab9565b611c4691906128cd565b905061144f565b348214611c86576040517f81de0bf300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600160a01b0384163014611caa57611caa6001600160a01b038416858461195f565b50349392505050565b600061144f8383611fe3565b600061085a825490565b6000828152602081815260408083206001600160a01b038516845290915290205460ff16611d35576040517fe2517d3f0000000000000000000000000000000000000000000000000000000081526001600160a01b0382166004820152602481018390526044016117c7565b5050565b6040516001600160a01b0383811660248301526044820183905261092291859182169063a9059cbb906064015b604051602081830303815290604052915060e01b6020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff838183161783525050505061200d565b6000828152602081815260408083206001600160a01b038516845290915281205460ff16611e4f576000838152602081815260408083206001600160a01b03861684529091529020805460ff19166001179055611e073390565b6001600160a01b0316826001600160a01b0316847f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a450600161085a565b50600061085a565b600061144f836001600160a01b038416612089565b6000828152602081815260408083206001600160a01b038516845290915281205460ff1615611e4f576000838152602081815260408083206001600160a01b0386168085529252808320805460ff1916905551339286917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a450600161085a565b600061144f836001600160a01b0384166120d0565b7fffffffffffffffffffffffff11111111111111111111111111111111111111126001600160a01b03821601611f66576040517f7f523fe800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b806001600160a01b03163b60000361195c576040517f7f523fe800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040516001600160a01b03848116602483015283811660448301526064820183905261094c9186918216906323b872dd90608401611d66565b6000826000018281548110611ffa57611ffa612ad2565b9060005260206000200154905092915050565b60006120226001600160a01b038416836121c3565b905080516000141580156120475750808060200190518101906120459190612b01565b155b15610922576040517f5274afe70000000000000000000000000000000000000000000000000000000081526001600160a01b03841660048201526024016117c7565b6000818152600183016020526040812054611e4f5750815460018181018455600084815260208082209093018490558454848252828601909352604090209190915561085a565b600081815260018301602052604081205480156121b95760006120f46001836128cd565b8554909150600090612108906001906128cd565b905080821461216d57600086600001828154811061212857612128612ad2565b906000526020600020015490508087600001848154811061214b5761214b612ad2565b6000918252602080832090910192909255918252600188019052604090208390555b855486908061217e5761217e612b1e565b60019003818190600052602060002001600090559055856001016000868152602001908152602001600020600090556001935050505061085a565b600091505061085a565b606061144f8383600084600080856001600160a01b031684866040516121e99190612b4d565b60006040518083038185875af1925050503d8060008114612226576040519150601f19603f3d011682016040523d82523d6000602084013e61222b565b606091505b509150915061223b868383612245565b9695505050505050565b60608261225a57612255826122ba565b61144f565b815115801561227157506001600160a01b0384163b155b156122b3576040517f9996b3150000000000000000000000000000000000000000000000000000000081526001600160a01b03851660048201526024016117c7565b508061144f565b8051156122ca5780518082602001fd5b6040517f1425ea4200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006020828403121561230e57600080fd5b81357fffffffff000000000000000000000000000000000000000000000000000000008116811461144f57600080fd5b60006020828403121561235057600080fd5b5035919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b60208101600583106123c1577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b91905290565b6001600160a01b038116811461195c57600080fd5b80356123e7816123c7565b919050565b600080604083850312156123ff57600080fd5b823561240a816123c7565b9150602083013561241a816123c7565b809150509250929050565b6000806040838503121561243857600080fd5b82359150602083013561241a816123c7565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051610120810167ffffffffffffffff8111828210171561249d5761249d61244a565b60405290565b604051610180810167ffffffffffffffff8111828210171561249d5761249d61244a565b600082601f8301126124d857600080fd5b813567ffffffffffffffff808211156124f3576124f361244a565b604051601f83017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f011681019082821181831017156125395761253961244a565b8160405283815286602085880101111561255257600080fd5b836020870160208301376000602085830101528094505050505092915050565b6000806040838503121561258557600080fd5b823567ffffffffffffffff81111561259c57600080fd5b6125a8858286016124c7565b925050602083013561241a816123c7565b63ffffffff8116811461195c57600080fd5b80356123e7816125b9565b801515811461195c57600080fd5b80356123e7816125d6565b6000610120828403121561260257600080fd5b61260a612479565b612613836125cb565b8152612621602084016123dc565b6020820152612632604084016123dc565b6040820152612643606084016123dc565b6060820152612654608084016123dc565b608082015260a083013560a082015260c083013560c082015261267960e084016125e4565b60e0820152610100928301359281019290925250919050565b6000602082840312156126a457600080fd5b813567ffffffffffffffff8111156126bb57600080fd5b6126c7848285016124c7565b949350505050565b600080604083850312156126e257600080fd5b823567ffffffffffffffff8111156126f957600080fd5b612705858286016124c7565b95602094909401359450505050565b6000806040838503121561272757600080fd5b50508035926020909101359150565b815163ffffffff1681526101808101602083015161275c602084018263ffffffff169052565b50604083015161277760408401826001600160a01b03169052565b50606083015161279260608401826001600160a01b03169052565b5060808301516127ad60808401826001600160a01b03169052565b5060a08301516127c860a08401826001600160a01b03169052565b5060c083015160c083015260e083015160e0830152610100808401518184015250610120808401516127fd8285018215159052565b5050610140838101519083015261016092830151929091019190915290565b60006020828403121561282e57600080fd5b813561144f816123c7565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b8082018082111561085a5761085a612839565b808202811582820484141761085a5761085a612839565b6000826128c8577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b8181038181111561085a5761085a612839565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820361291157612911612839565b5060010190565b60005b8381101561293357818101518382015260200161291b565b50506000910152565b60e08152600088518060e084015261010061295d8282860160208e01612918565b63ffffffff9990991660208401526001600160a01b039788166040840152959096166060820152608081019390935260a0830191909152151560c0820152601f9091017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0160190910192915050565b80516123e7816125b9565b80516123e7816123c7565b80516123e7816125d6565b60006101808284031215612a0057600080fd5b612a086124a3565b612a11836129cc565b8152612a1f602084016129cc565b6020820152612a30604084016129d7565b6040820152612a41606084016129d7565b6060820152612a52608084016129d7565b6080820152612a6360a084016129d7565b60a082015260c083015160c082015260e083015160e0820152610100808401518183015250610120612a968185016129e2565b908201526101408381015190820152610160928301519281019290925250919050565b600060208284031215612acb57600080fd5b5051919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b600060208284031215612b1357600080fd5b815161144f816125d6565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fd5b60008251612b5f818460208701612918565b919091019291505056fea26469706673582212202ed7e54598f559f515fc7a3d92c2ad3ddbadbeb6d23e4975b013050318c9925564736f6c63430008140033","runtime-code":"0x60806040526004361061026a5760003560e01c80639010d07c11610153578063add98c70116100cb578063ca15c8731161007f578063d547741f11610064578063d547741f146107a1578063dcf844a7146107c1578063e00a83e0146107ee57600080fd5b8063ca15c8731461074d578063ccc574901461076d57600080fd5b8063b13aa2d6116100b0578063b13aa2d6146106f6578063b250fe6b14610716578063bf333f2c1461073657600080fd5b8063add98c70146106c0578063affed0e0146106e057600080fd5b8063a217fddf11610122578063a5bbe22b11610107578063a5bbe22b1461047f578063aa9641ab14610673578063ac11fb1a1461069357600080fd5b8063a217fddf1461062a578063a3ec191a1461063f57600080fd5b80639010d07c146104f857806391ad50391461053057806391d14854146105b2578063926d7d7f146105f657600080fd5b806341fcb612116101e65780635eb7d946116101b55780638379a24f1161019a5780638379a24f14610495578063886d36ff146104c55780638f0d6f17146104e557600080fd5b80635eb7d9461461045f578063820688d51461047f57600080fd5b806341fcb612146103e2578063458516941461040257806358f85880146104155780635960ccf21461042b57600080fd5b80630f5f6ed71161023d578063248a9ca311610222578063248a9ca3146103725780632f2ff15d146103a257806336568abe146103c257600080fd5b80630f5f6ed714610345578063190da5951461035b57600080fd5b806301ffc9a71461026f57806303ed0ee5146102a4578063051287bc146102e657806306f333f214610323575b600080fd5b34801561027b57600080fd5b5061028f61028a3660046122fc565b610804565b60405190151581526020015b60405180910390f35b3480156102b057600080fd5b506102d87f043c983c49d46f0e102151eaf8085d4a2e6571d5df2d47b013f39bddfd4a639d81565b60405190815260200161029b565b3480156102f257600080fd5b5061031661030136600461233e565b60056020526000908152604090205460ff1681565b60405161029b9190612386565b34801561032f57600080fd5b5061034361033e3660046123ec565b610860565b005b34801561035157600080fd5b506102d861271081565b34801561036757600080fd5b506102d862093a8081565b34801561037e57600080fd5b506102d861038d36600461233e565b60009081526020819052604090206001015490565b3480156103ae57600080fd5b506103436103bd366004612425565b610927565b3480156103ce57600080fd5b506103436103dd366004612425565b610952565b3480156103ee57600080fd5b506103436103fd366004612572565b61099e565b6103436104103660046125ef565b610bd7565b34801561042157600080fd5b506102d860025481565b34801561043757600080fd5b506102d87fdb9556138406326f00296e13ea2ad7db24ba82381212d816b1a40c23b466b32781565b34801561046b57600080fd5b5061034361047a366004612692565b610ee5565b34801561048b57600080fd5b506102d861070881565b3480156104a157600080fd5b5061028f6104b036600461233e565b60076020526000908152604090205460ff1681565b3480156104d157600080fd5b506103436104e03660046126cf565b6110bd565b6103436104f3366004612692565b6111f0565b34801561050457600080fd5b50610518610513366004612714565b611437565b6040516001600160a01b03909116815260200161029b565b34801561053c57600080fd5b5061058661054b36600461233e565b6006602052600090815260409020546bffffffffffffffffffffffff8116906c0100000000000000000000000090046001600160a01b031682565b604080516bffffffffffffffffffffffff90931683526001600160a01b0390911660208301520161029b565b3480156105be57600080fd5b5061028f6105cd366004612425565b6000918252602082815260408084206001600160a01b0393909316845291905290205460ff1690565b34801561060257600080fd5b506102d87fe2b7fb3b832174769106daebcfd6d1970523240dda11281102db9363b83b0dc481565b34801561063657600080fd5b506102d8600081565b34801561064b57600080fd5b506102d87f000000000000000000000000000000000000000000000000000000000000000081565b34801561067f57600080fd5b5061028f61068e366004612425565b611456565b34801561069f57600080fd5b506106b36106ae366004612692565b611559565b60405161029b9190612736565b3480156106cc57600080fd5b506103436106db36600461233e565b6115cc565b3480156106ec57600080fd5b506102d860085481565b34801561070257600080fd5b5061034361071136600461233e565b611735565b34801561072257600080fd5b5061034361073136600461233e565b611817565b34801561074257600080fd5b506102d8620f424081565b34801561075957600080fd5b506102d861076836600461233e565b61187f565b34801561077957600080fd5b506102d87f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f5581565b3480156107ad57600080fd5b506103436107bc366004612425565b611896565b3480156107cd57600080fd5b506102d86107dc36600461281c565b60036020526000908152604090205481565b3480156107fa57600080fd5b506102d860045481565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f5a05180f00000000000000000000000000000000000000000000000000000000148061085a575061085a826118bb565b92915050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f5561088a81611952565b6001600160a01b038316600090815260036020526040812054908190036108b15750505050565b6001600160a01b0384166000818152600360205260408120556108d590848361195f565b604080516001600160a01b038087168252851660208201529081018290527f244e51bc38c1452fa8aaf487bcb4bca36c2baa3a5fbdb776b1eabd8dc6d277cd9060600160405180910390a1505b505050565b60008281526020819052604090206001015461094281611952565b61094c8383611a82565b50505050565b6001600160a01b0381163314610994576040517f6697b23200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6109228282611ab7565b7fe2b7fb3b832174769106daebcfd6d1970523240dda11281102db9363b83b0dc46109c881611952565b8251602084012060006109da85611559565b9050600260008381526005602052604090205460ff166004811115610a0157610a01612357565b14610a38576040517f4145817200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000828152600660209081526040918290208251808401909352546bffffffffffffffffffffffff811683526c0100000000000000000000000090046001600160a01b03169082018190523314610abb576040517f4af43a9000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80516107089042036bffffffffffffffffffffffff1611610b08576040517f1992d0bd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000838152600560205260409020805460ff1916600317905561010082015115610b645761010082015160808301516001600160a01b031660009081526003602052604081208054909190610b5e908490612868565b90915550505b608082015160c0830151610b826001600160a01b038316888361195f565b604080516001600160a01b03848116825260208201849052891691339188917f582211c35a2139ac3bbaac74663c6a1f56c6cbb658b41fe11fd45a82074ac67891015b60405180910390a45050505050505050565b46816000015163ffffffff1603610c1a576040517f7029fdf900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60a08101511580610c2d575060c0810151155b15610c64576040517fe38820c800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60608101516001600160a01b03161580610c89575060808101516001600160a01b0316155b15610cc0576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610ccc61070842612868565b8161010001511015610d0a576040517f04b7fcc800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000610d1f3083606001518460a00151611ae4565b90506000806002541115610d4c57620f424060025483610d3f919061287b565b610d499190612892565b90505b610d5681836128cd565b915060006040518061018001604052804663ffffffff168152602001856000015163ffffffff16815260200185602001516001600160a01b0316815260200185604001516001600160a01b0316815260200185606001516001600160a01b0316815260200185608001516001600160a01b031681526020018481526020018560c0015181526020018381526020018560e0015115158152602001856101000151815260200160086000815480929190610e0e906128e0565b909155509052604051610e249190602001612736565b604080518083037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0018152828252805160208083019190912060008181526005835293909320805460ff191660011790558701518751606089015160808a015160c08b015160e08c015195985095966001600160a01b039094169587957f120ea0364f36cdac7983bcfdd55270ca09d7f9b314a2ebc425a3b01ab1d6403a95610ed6958b959094909390928e9261293c565b60405180910390a35050505050565b805160208201206000610ef783611559565b3360009081527fd2043bf65931af3dbecf60d0db8f40e4160406d7beb00522f4200cf4944a1eb8602052604090205490915060ff1615610f74578061014001514211610f6f576040517fe15ff9ea00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610fc0565b62093a80816101400151610f889190612868565b4211610fc0576040517fe15ff9ea00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600160008381526005602052604090205460ff166004811115610fe557610fe5612357565b1461101c576040517f4145817200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600082815260056020526040808220805460ff19166004179055820151608083015161010084015160c0850151929391926110579190612868565b905061106d6001600160a01b038316848361195f565b604080516001600160a01b0384811682526020820184905285169187917fb4c55c0c9bc613519b920e88748090150b890a875d307f21bea7d4fb2e8bc958910160405180910390a3505050505050565b7fe2b7fb3b832174769106daebcfd6d1970523240dda11281102db9363b83b0dc46110e781611952565b82516020840120600160008281526005602052604090205460ff16600481111561111357611113612357565b1461114a576040517f4145817200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008181526005602090815260408083208054600260ff19909116179055805180820182526bffffffffffffffffffffffff4281168252338285018181528787526006865295849020925195516001600160a01b03166c0100000000000000000000000002959091169490941790555185815283917f4ac8af8a2cd87193d64dfc7a3b8d9923b714ec528b18725d080aa1299be0c5e4910160405180910390a350505050565b7fe2b7fb3b832174769106daebcfd6d1970523240dda11281102db9363b83b0dc461121a81611952565b81516020830120600061122c84611559565b90504663ffffffff16816020015163ffffffff1614611277576040517f7029fdf900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8061014001514211156112b6576040517f559895a300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008281526007602052604090205460ff16156112ff576040517fbef7bb7d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000828152600760205260409020805460ff19166001179055606081015160a082015160e083015160045461012085015161134857506000611342848484611ae4565b506113b9565b7fffffffffffffffffffffffff11111111111111111111111111111111111111126001600160a01b0384160161138c5761134284846113878486612868565b611ae4565b611397848484611ae4565b506113b78473eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee83611ae4565b505b845160808087015160a08089015160c0808b015160e08c01516040805163ffffffff90991689526001600160a01b0396871660208a0152938616938801939093526060870152938501528301849052861691339189917ff8ae392d784b1ea5e8881bfa586d81abf07ef4f1e2fc75f7fe51c90f05199a5c9101610bc5565b600082815260016020526040812061144f9083611cb3565b9392505050565b6000600260008481526005602052604090205460ff16600481111561147d5761147d612357565b146114b4576040517f4145817200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000838152600660209081526040918290208251808401909352546bffffffffffffffffffffffff811683526001600160a01b036c01000000000000000000000000909104811691830182905284161461153a576040517f4af43a9000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80516107089042036bffffffffffffffffffffffff1611949350505050565b604080516101808101825260008082526020808301829052928201819052606082018190526080820181905260a0820181905260c0820181905260e082018190526101008201819052610120820181905261014082018190526101608201528251909161085a91840181019084016129ed565b7f043c983c49d46f0e102151eaf8085d4a2e6571d5df2d47b013f39bddfd4a639d6115f681611952565b600260008381526005602052604090205460ff16600481111561161b5761161b612357565b14611652576040517f4145817200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000828152600660209081526040918290208251808401909352546bffffffffffffffffffffffff8082168085526c010000000000000000000000009092046001600160a01b031693909201929092526107089142031611156116e1576040517f3e908aac00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000828152600560209081526040808320805460ff19166001179055600690915280822082905551339184917f0695cf1d39b3055dcd0fe02d8b47eaf0d5a13e1996de925de59d0ef9b7f7fad49190a35050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f5561175f81611952565b6127108211156117d0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f6e657746656552617465203e206d61780000000000000000000000000000000060448201526064015b60405180910390fd5b600280549083905560408051828152602081018590527f14914da2bf76024616fbe1859783fcd4dbddcb179b1f3a854949fbf920dcb95791015b60405180910390a1505050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f5561184181611952565b600480549083905560408051828152602081018590527f5cf09b12f3f56b4c564d51b25b40360af6d795198adb61ae0806a36c294323fa910161180a565b600081815260016020526040812061085a90611cbf565b6000828152602081905260409020600101546118b181611952565b61094c8383611ab7565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f7965db0b00000000000000000000000000000000000000000000000000000000148061085a57507f01ffc9a7000000000000000000000000000000000000000000000000000000007fffffffff0000000000000000000000000000000000000000000000000000000083161461085a565b61195c8133611cc9565b50565b306001600160a01b0383160361197457505050565b8060000361198157505050565b7fffffffffffffffffffffffff11111111111111111111111111111111111111126001600160a01b03841601611a6e576000826001600160a01b03168260405160006040518083038185875af1925050503d80600081146119fe576040519150601f19603f3d011682016040523d82523d6000602084013e611a03565b606091505b505090508061094c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f455448207472616e73666572206661696c65640000000000000000000000000060448201526064016117c7565b6109226001600160a01b0384168383611d39565b600080611a8f8484611dad565b9050801561144f576000848152600160205260409020611aaf9084611e57565b509392505050565b600080611ac48484611e6c565b9050801561144f576000848152600160205260409020611aaf9084611eef565b60006001600160a01b03831673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee14611c4d57611b1c836001600160a01b0316611f04565b6040517f70a082310000000000000000000000000000000000000000000000000000000081526001600160a01b0385811660048301528416906370a0823190602401602060405180830381865afa158015611b7b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b9f9190612ab9565b9050611bb66001600160a01b038416338685611faa565b6040517f70a082310000000000000000000000000000000000000000000000000000000081526001600160a01b0385811660048301528291908516906370a0823190602401602060405180830381865afa158015611c18573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c3c9190612ab9565b611c4691906128cd565b905061144f565b348214611c86576040517f81de0bf300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600160a01b0384163014611caa57611caa6001600160a01b038416858461195f565b50349392505050565b600061144f8383611fe3565b600061085a825490565b6000828152602081815260408083206001600160a01b038516845290915290205460ff16611d35576040517fe2517d3f0000000000000000000000000000000000000000000000000000000081526001600160a01b0382166004820152602481018390526044016117c7565b5050565b6040516001600160a01b0383811660248301526044820183905261092291859182169063a9059cbb906064015b604051602081830303815290604052915060e01b6020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff838183161783525050505061200d565b6000828152602081815260408083206001600160a01b038516845290915281205460ff16611e4f576000838152602081815260408083206001600160a01b03861684529091529020805460ff19166001179055611e073390565b6001600160a01b0316826001600160a01b0316847f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a450600161085a565b50600061085a565b600061144f836001600160a01b038416612089565b6000828152602081815260408083206001600160a01b038516845290915281205460ff1615611e4f576000838152602081815260408083206001600160a01b0386168085529252808320805460ff1916905551339286917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a450600161085a565b600061144f836001600160a01b0384166120d0565b7fffffffffffffffffffffffff11111111111111111111111111111111111111126001600160a01b03821601611f66576040517f7f523fe800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b806001600160a01b03163b60000361195c576040517f7f523fe800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040516001600160a01b03848116602483015283811660448301526064820183905261094c9186918216906323b872dd90608401611d66565b6000826000018281548110611ffa57611ffa612ad2565b9060005260206000200154905092915050565b60006120226001600160a01b038416836121c3565b905080516000141580156120475750808060200190518101906120459190612b01565b155b15610922576040517f5274afe70000000000000000000000000000000000000000000000000000000081526001600160a01b03841660048201526024016117c7565b6000818152600183016020526040812054611e4f5750815460018181018455600084815260208082209093018490558454848252828601909352604090209190915561085a565b600081815260018301602052604081205480156121b95760006120f46001836128cd565b8554909150600090612108906001906128cd565b905080821461216d57600086600001828154811061212857612128612ad2565b906000526020600020015490508087600001848154811061214b5761214b612ad2565b6000918252602080832090910192909255918252600188019052604090208390555b855486908061217e5761217e612b1e565b60019003818190600052602060002001600090559055856001016000868152602001908152602001600020600090556001935050505061085a565b600091505061085a565b606061144f8383600084600080856001600160a01b031684866040516121e99190612b4d565b60006040518083038185875af1925050503d8060008114612226576040519150601f19603f3d011682016040523d82523d6000602084013e61222b565b606091505b509150915061223b868383612245565b9695505050505050565b60608261225a57612255826122ba565b61144f565b815115801561227157506001600160a01b0384163b155b156122b3576040517f9996b3150000000000000000000000000000000000000000000000000000000081526001600160a01b03851660048201526024016117c7565b508061144f565b8051156122ca5780518082602001fd5b6040517f1425ea4200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006020828403121561230e57600080fd5b81357fffffffff000000000000000000000000000000000000000000000000000000008116811461144f57600080fd5b60006020828403121561235057600080fd5b5035919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b60208101600583106123c1577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b91905290565b6001600160a01b038116811461195c57600080fd5b80356123e7816123c7565b919050565b600080604083850312156123ff57600080fd5b823561240a816123c7565b9150602083013561241a816123c7565b809150509250929050565b6000806040838503121561243857600080fd5b82359150602083013561241a816123c7565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051610120810167ffffffffffffffff8111828210171561249d5761249d61244a565b60405290565b604051610180810167ffffffffffffffff8111828210171561249d5761249d61244a565b600082601f8301126124d857600080fd5b813567ffffffffffffffff808211156124f3576124f361244a565b604051601f83017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f011681019082821181831017156125395761253961244a565b8160405283815286602085880101111561255257600080fd5b836020870160208301376000602085830101528094505050505092915050565b6000806040838503121561258557600080fd5b823567ffffffffffffffff81111561259c57600080fd5b6125a8858286016124c7565b925050602083013561241a816123c7565b63ffffffff8116811461195c57600080fd5b80356123e7816125b9565b801515811461195c57600080fd5b80356123e7816125d6565b6000610120828403121561260257600080fd5b61260a612479565b612613836125cb565b8152612621602084016123dc565b6020820152612632604084016123dc565b6040820152612643606084016123dc565b6060820152612654608084016123dc565b608082015260a083013560a082015260c083013560c082015261267960e084016125e4565b60e0820152610100928301359281019290925250919050565b6000602082840312156126a457600080fd5b813567ffffffffffffffff8111156126bb57600080fd5b6126c7848285016124c7565b949350505050565b600080604083850312156126e257600080fd5b823567ffffffffffffffff8111156126f957600080fd5b612705858286016124c7565b95602094909401359450505050565b6000806040838503121561272757600080fd5b50508035926020909101359150565b815163ffffffff1681526101808101602083015161275c602084018263ffffffff169052565b50604083015161277760408401826001600160a01b03169052565b50606083015161279260608401826001600160a01b03169052565b5060808301516127ad60808401826001600160a01b03169052565b5060a08301516127c860a08401826001600160a01b03169052565b5060c083015160c083015260e083015160e0830152610100808401518184015250610120808401516127fd8285018215159052565b5050610140838101519083015261016092830151929091019190915290565b60006020828403121561282e57600080fd5b813561144f816123c7565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b8082018082111561085a5761085a612839565b808202811582820484141761085a5761085a612839565b6000826128c8577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b8181038181111561085a5761085a612839565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820361291157612911612839565b5060010190565b60005b8381101561293357818101518382015260200161291b565b50506000910152565b60e08152600088518060e084015261010061295d8282860160208e01612918565b63ffffffff9990991660208401526001600160a01b039788166040840152959096166060820152608081019390935260a0830191909152151560c0820152601f9091017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0160190910192915050565b80516123e7816125b9565b80516123e7816123c7565b80516123e7816125d6565b60006101808284031215612a0057600080fd5b612a086124a3565b612a11836129cc565b8152612a1f602084016129cc565b6020820152612a30604084016129d7565b6040820152612a41606084016129d7565b6060820152612a52608084016129d7565b6080820152612a6360a084016129d7565b60a082015260c083015160c082015260e083015160e0820152610100808401518183015250610120612a968185016129e2565b908201526101408381015190820152610160928301519281019290925250919050565b600060208284031215612acb57600080fd5b5051919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b600060208284031215612b1357600080fd5b815161144f816125d6565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fd5b60008251612b5f818460208701612918565b919091019291505056fea26469706673582212202ed7e54598f559f515fc7a3d92c2ad3ddbadbeb6d23e4975b013050318c9925564736f6c63430008140033","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.20 ^0.8.20;\n\n// contracts/interfaces/IAdmin.sol\n\ninterface IAdmin {\n // ============ Events ============\n\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n event ChainGasAmountUpdated(uint256 oldChainGasAmount, uint256 newChainGasAmount);\n\n // ============ Methods ============\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n\n function setChainGasAmount(uint256 newChainGasAmount) external;\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/libs/Errors.sol\n\nerror DeadlineExceeded();\nerror DeadlineNotExceeded();\nerror DeadlineTooShort();\nerror InsufficientOutputAmount();\n\nerror MsgValueIncorrect();\nerror PoolNotFound();\nerror TokenAddressMismatch();\nerror TokenNotContract();\nerror TokenNotETH();\nerror TokensIdentical();\n\nerror ChainIncorrect();\nerror AmountIncorrect();\nerror ZeroAddress();\n\nerror DisputePeriodNotPassed();\nerror DisputePeriodPassed();\nerror SenderIncorrect();\nerror StatusIncorrect();\nerror TransactionIdIncorrect();\nerror TransactionRelayed();\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// contracts/libs/UniversalToken.sol\n\nlibrary UniversalTokenLib {\n using SafeERC20 for IERC20;\n\n address internal constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Transfers tokens to the given account. Reverts if transfer is not successful.\n /// @dev This might trigger fallback, if ETH is transferred to the contract.\n /// Make sure this can not lead to reentrancy attacks.\n function universalTransfer(address token, address to, uint256 value) internal {\n // Don't do anything, if need to send tokens to this address\n if (to == address(this)) return;\n // Don't do anything, if trying to send zero value\n if (value == 0) return;\n if (token == ETH_ADDRESS) {\n /// @dev Note: this can potentially lead to executing code in `to`.\n // solhint-disable-next-line avoid-low-level-calls\n (bool success,) = to.call{value: value}(\"\");\n require(success, \"ETH transfer failed\");\n } else {\n IERC20(token).safeTransfer(to, value);\n }\n }\n\n /// @notice Issues an infinite allowance to the spender, if the current allowance is insufficient\n /// to spend the given amount.\n function universalApproveInfinity(address token, address spender, uint256 amountToSpend) internal {\n // ETH Chad doesn't require your approval\n if (token == ETH_ADDRESS) return;\n // No-op if allowance is already sufficient\n uint256 allowance = IERC20(token).allowance(address(this), spender);\n if (allowance \u003e= amountToSpend) return;\n // Otherwise, reset approval to 0 and set to max allowance\n if (allowance \u003e 0) IERC20(token).safeDecreaseAllowance(spender, allowance);\n IERC20(token).safeIncreaseAllowance(spender, type(uint256).max);\n }\n\n /// @notice Returns the balance of the given token (or native ETH) for the given account.\n function universalBalanceOf(address token, address account) internal view returns (uint256) {\n if (token == ETH_ADDRESS) {\n return account.balance;\n } else {\n return IERC20(token).balanceOf(account);\n }\n }\n\n /// @dev Checks that token is a contract and not ETH_ADDRESS.\n function assertIsContract(address token) internal view {\n // Check that ETH_ADDRESS was not used (in case this is a predeploy on any of the chains)\n if (token == UniversalTokenLib.ETH_ADDRESS) revert TokenNotContract();\n // Check that token is not an EOA\n if (token.code.length == 0) revert TokenNotContract();\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/Admin.sol\n\ncontract Admin is IAdmin, AccessControlEnumerable {\n using UniversalTokenLib for address;\n\n bytes32 public constant RELAYER_ROLE = keccak256(\"RELAYER_ROLE\");\n bytes32 public constant REFUNDER_ROLE = keccak256(\"REFUNDER_ROLE\");\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n uint256 public constant FEE_BPS = 1e6;\n uint256 public constant FEE_RATE_MAX = 0.01e6; // max 1% on origin amount\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Chain gas amount to forward as rebate if requested\n uint256 public chainGasAmount;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n }\n\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n require(newFeeRate \u003c= FEE_RATE_MAX, \"newFeeRate \u003e max\");\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n token.universalTransfer(recipient, feeAmount);\n emit FeesSwept(token, recipient, feeAmount);\n }\n\n function setChainGasAmount(uint256 newChainGasAmount) external onlyRole(GOVERNOR_ROLE) {\n uint256 oldChainGasAmount = chainGasAmount;\n chainGasAmount = newChainGasAmount;\n emit ChainGasAmountUpdated(oldChainGasAmount, newChainGasAmount);\n }\n}\n\n// contracts/FastBridge.sol\n\ncontract FastBridge is IFastBridge, Admin {\n using SafeERC20 for IERC20;\n using UniversalTokenLib for address;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Delay for a transaction after which it could be permisionlessly refunded\n uint256 public constant REFUND_DELAY = 7 days;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeStatus) public bridgeStatuses;\n /// @notice Proof of relayed bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeProof) public bridgeProofs;\n /// @notice Whether bridge has been relayed on destination chain\n mapping(bytes32 =\u003e bool) public bridgeRelays;\n\n /// @dev to prevent replays\n uint256 public nonce;\n // @dev the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @notice Pulls a requested token from the user to the requested recipient.\n /// @dev Be careful of re-entrancy issues when msg.value \u003e 0 and recipient != address(this)\n function _pullToken(address recipient, address token, uint256 amount) internal returns (uint256 amountPulled) {\n if (token != UniversalTokenLib.ETH_ADDRESS) {\n token.assertIsContract();\n // Record token balance before transfer\n amountPulled = IERC20(token).balanceOf(recipient);\n // Token needs to be pulled only if msg.value is zero\n // This way user can specify WETH as the origin asset\n IERC20(token).safeTransferFrom(msg.sender, recipient, amount);\n // Use the difference between the recorded balance and the current balance as the amountPulled\n amountPulled = IERC20(token).balanceOf(recipient) - amountPulled;\n } else {\n // Otherwise, we need to check that ETH amount matches msg.value\n if (amount != msg.value) revert MsgValueIncorrect();\n // Transfer value to recipient if not this address\n if (recipient != address(this)) token.universalTransfer(recipient, amount);\n // We will forward msg.value in the external call later, if recipient is not this contract\n amountPulled = msg.value;\n }\n }\n\n /// @inheritdoc IFastBridge\n function getBridgeTransaction(bytes memory request) public pure returns (BridgeTransaction memory) {\n return abi.decode(request, (BridgeTransaction));\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n // check bridge params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n\n // transfer tokens to bridge contract\n // @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _pullToken(address(this), params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n\n // set status to requested\n bytes memory request = abi.encode(\n BridgeTransaction({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n sendChainGas: params.sendChainGas,\n deadline: params.deadline,\n nonce: nonce++ // increment nonce on every bridge\n })\n );\n bytes32 transactionId = keccak256(request);\n bridgeStatuses[transactionId] = BridgeStatus.REQUESTED;\n\n emit BridgeRequested(\n transactionId,\n params.sender,\n request,\n params.dstChainId,\n params.originToken,\n params.destToken,\n originAmount,\n params.destAmount,\n params.sendChainGas\n );\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes memory request) external payable onlyRole(RELAYER_ROLE) {\n bytes32 transactionId = keccak256(request);\n BridgeTransaction memory transaction = getBridgeTransaction(request);\n if (transaction.destChainId != uint32(block.chainid)) revert ChainIncorrect();\n\n // check haven't exceeded deadline for relay to happen\n if (block.timestamp \u003e transaction.deadline) revert DeadlineExceeded();\n\n // mark bridge transaction as relayed\n if (bridgeRelays[transactionId]) revert TransactionRelayed();\n bridgeRelays[transactionId] = true;\n\n // transfer tokens to recipient on destination chain and gas rebate if requested\n address to = transaction.destRecipient;\n address token = transaction.destToken;\n uint256 amount = transaction.destAmount;\n\n uint256 rebate = chainGasAmount;\n if (!transaction.sendChainGas) {\n // forward erc20\n rebate = 0;\n _pullToken(to, token, amount);\n } else if (token == UniversalTokenLib.ETH_ADDRESS) {\n // lump in gas rebate into amount in native gas token\n _pullToken(to, token, amount + rebate);\n } else {\n // forward erc20 then forward gas rebate in native gas token\n _pullToken(to, token, amount);\n _pullToken(to, UniversalTokenLib.ETH_ADDRESS, rebate);\n }\n\n emit BridgeRelayed(\n transactionId,\n msg.sender,\n to,\n transaction.originChainId,\n transaction.originToken,\n transaction.destToken,\n transaction.originAmount,\n transaction.destAmount,\n rebate\n );\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes memory request, bytes32 destTxHash) external onlyRole(RELAYER_ROLE) {\n bytes32 transactionId = keccak256(request);\n // update bridge tx status given proof provided\n if (bridgeStatuses[transactionId] != BridgeStatus.REQUESTED) revert StatusIncorrect();\n bridgeStatuses[transactionId] = BridgeStatus.RELAYER_PROVED;\n bridgeProofs[transactionId] = BridgeProof({timestamp: uint96(block.timestamp), relayer: msg.sender}); // overflow ok\n\n emit BridgeProofProvided(transactionId, msg.sender, destTxHash);\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint96(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint96).max but\n /// proof.timestamp \u003c type(uint96).max via unchecked statement\n /// @param proof The bridge proof\n /// @return delta Time delta since proof submitted\n function _timeSince(BridgeProof memory proof) internal view returns (uint256 delta) {\n unchecked {\n delta = uint96(block.timestamp) - proof.timestamp;\n }\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n if (bridgeStatuses[transactionId] != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n BridgeProof memory proof = bridgeProofs[transactionId];\n if (proof.relayer != relayer) revert SenderIncorrect();\n return _timeSince(proof) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes memory request, address to) external onlyRole(RELAYER_ROLE) {\n bytes32 transactionId = keccak256(request);\n BridgeTransaction memory transaction = getBridgeTransaction(request);\n\n // update bridge tx status if able to claim origin collateral\n if (bridgeStatuses[transactionId] != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n\n BridgeProof memory proof = bridgeProofs[transactionId];\n if (proof.relayer != msg.sender) revert SenderIncorrect();\n if (_timeSince(proof) \u003c= DISPUTE_PERIOD) revert DisputePeriodNotPassed();\n\n bridgeStatuses[transactionId] = BridgeStatus.RELAYER_CLAIMED;\n\n // update protocol fees if origin fee amount exists\n if (transaction.originFeeAmount \u003e 0) protocolFees[transaction.originToken] += transaction.originFeeAmount;\n\n // transfer origin collateral less fee to specified address\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositClaimed(transactionId, msg.sender, to, token, amount);\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n if (bridgeStatuses[transactionId] != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(bridgeProofs[transactionId]) \u003e DISPUTE_PERIOD) revert DisputePeriodPassed();\n\n // @dev relayer gets slashed effectively if dest relay has gone thru\n bridgeStatuses[transactionId] = BridgeStatus.REQUESTED;\n delete bridgeProofs[transactionId];\n\n emit BridgeProofDisputed(transactionId, msg.sender);\n }\n\n /// @inheritdoc IFastBridge\n function refund(bytes memory request) external {\n bytes32 transactionId = keccak256(request);\n BridgeTransaction memory transaction = getBridgeTransaction(request);\n\n if (hasRole(REFUNDER_ROLE, msg.sender)) {\n // Refunder can refund if deadline has passed\n if (block.timestamp \u003c= transaction.deadline) revert DeadlineNotExceeded();\n } else {\n // Permissionless refund is allowed after REFUND_DELAY\n if (block.timestamp \u003c= transaction.deadline + REFUND_DELAY) revert DeadlineNotExceeded();\n }\n\n // set status to refunded if still in requested state\n if (bridgeStatuses[transactionId] != BridgeStatus.REQUESTED) revert StatusIncorrect();\n bridgeStatuses[transactionId] = BridgeStatus.REFUNDED;\n\n // transfer origin collateral back to original sender\n address to = transaction.originSender;\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount + transaction.originFeeAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n }\n}\n\n// test/FastBridgeMock.sol\n\ncontract FastBridgeMock is IFastBridge, Admin {\n // @dev the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @dev to prevent replays\n uint256 public nonce;\n\n function getBridgeTransaction(bytes memory request) public pure returns (BridgeTransaction memory) {\n return abi.decode(request, (BridgeTransaction));\n }\n\n // used for testing in go.\n // see: https://ethereum.stackexchange.com/questions/21155/how-to-expose-enum-in-solidity-contract\n // make sure to update fastbridge/status.go if this changes\n // or underliyng enum changes.\n //\n // TODO: a foundry test should be added to ensure this is always in sync.\n function getEnumKeyByValue(FastBridge.BridgeStatus keyValue) public pure returns (string memory) {\n if (FastBridge.BridgeStatus.NULL == keyValue) return \"NULL\";\n if (FastBridge.BridgeStatus.REQUESTED == keyValue) return \"REQUESTED\";\n if (FastBridge.BridgeStatus.RELAYER_PROVED == keyValue) return \"RELAYER_PROVED\";\n if (FastBridge.BridgeStatus.RELAYER_CLAIMED == keyValue) return \"RELAYER_CLAIMED\";\n if (FastBridge.BridgeStatus.REFUNDED == keyValue) return \"REFUNDED\";\n return \"\";\n }\n\n function mockBridgeRequest(bytes32 transactionId, address sender, BridgeParams memory params) external {\n uint256 originFeeAmount = (params.originAmount * protocolFeeRate) / FEE_BPS;\n params.originAmount -= originFeeAmount;\n\n bytes memory request = abi.encode(\n BridgeTransaction({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: params.originAmount, // includes relayer fee\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n sendChainGas: params.sendChainGas,\n deadline: params.deadline,\n nonce: nonce++ // increment nonce on every bridge\n })\n );\n\n emit BridgeRequested(\n transactionId,\n params.sender,\n request,\n params.dstChainId,\n params.originToken,\n params.destToken,\n params.originAmount,\n params.destAmount,\n params.sendChainGas\n );\n }\n\n function mockBridgeRequestRaw(bytes32 transactionId, address sender, bytes memory request) external {\n BridgeTransaction memory transaction = getBridgeTransaction(request);\n emit BridgeRequested(\n transactionId,\n transaction.originSender,\n request,\n transaction.destChainId,\n transaction.originToken,\n transaction.destToken,\n transaction.originAmount,\n transaction.destAmount,\n transaction.sendChainGas\n );\n }\n\n function mockBridgeRelayer(\n bytes32 transactionId,\n address relayer,\n address to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n )\n external\n {\n emit BridgeRelayed(\n transactionId, relayer, to, originChainId, originToken, destToken, originAmount, destAmount, chainGasAmount\n );\n }\n\n function bridge(BridgeParams memory params) external payable {\n revert(\"not implemented\");\n }\n\n function relay(bytes memory request) external payable {\n revert(\"not implemented\");\n }\n\n function prove(bytes memory request, bytes32 destTxHash) external {\n revert(\"not implemented\");\n }\n\n function canClaim(bytes32 transactionid, address relayer) external view returns (bool) {\n revert(\"not implemented\");\n }\n\n function claim(bytes memory request, address to) external {\n revert(\"not implemented\");\n }\n\n function dispute(bytes32 transactionId) external {\n revert(\"not implemented\");\n }\n\n function refund(bytes memory request) external {\n revert(\"not implemented\");\n }\n}\n","language":"Solidity","languageVersion":"0.8.20","compilerVersion":"0.8.20","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"58189:11304:0:-:0;;;59364:85;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;59398:6;57180:38;46352:4;59398:6;57180:10;:38::i;:::-;-1:-1:-1;;59430:12:0::1;59416:26;::::0;-1:-1:-1;58189:11304:0;;55665:257;55751:4;;55782:31;55799:4;55805:7;55782:16;:31::i;:::-;55767:46;;55827:7;55823:69;;;55850:18;;;;:12;:18;;;;;:31;;55873:7;55850:22;:31::i;:::-;;55823:69;55908:7;-1:-1:-1;55665:257:0;;;;;:::o;50299:316::-;50376:4;47074:12;;;;;;;;;;;-1:-1:-1;;;;;47074:29:0;;;;;;;;;;;;50392:217;;50435:6;:12;;;;;;;;;;;-1:-1:-1;;;;;50435:29:0;;;;;;;;;:36;;-1:-1:-1;;50435:36:0;50467:4;50435:36;;;50517:12;22395:10;;22316:96;50517:12;-1:-1:-1;;;;;50490:40:0;50508:7;-1:-1:-1;;;;;50490:40:0;50502:4;50490:40;;;;;;;;;;-1:-1:-1;50551:4:0;50544:11;;50392:217;-1:-1:-1;50593:5:0;50586:12;;31840:150;31910:4;31933:50;31938:3;-1:-1:-1;;;;;31958:23:0;;25828:4;27884:21;;;:14;;;:21;;;;;;25844:321;;-1:-1:-1;25886:23:0;;;;;;;;:11;:23;;;;;;;;;;;;;26068:18;;26044:21;;;:14;;;:21;;;;;;:42;;;;26100:11;;14:290:1;84:6;137:2;125:9;116:7;112:23;108:32;105:52;;;153:1;150;143:12;105:52;179:16;;-1:-1:-1;;;;;224:31:1;;214:42;;204:70;;270:1;267;260:12;14:290;58189:11304:0;;;;;;;;;;;;","srcMapRuntime":"58189:11304:0:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;54325:212;;;;;;;;;;-1:-1:-1;54325:212:0;;;;;:::i;:::-;;:::i;:::-;;;612:14:1;;605:22;587:41;;575:2;560:18;54325:212:0;;;;;;;;56555:60;;;;;;;;;;;;56592:23;56555:60;;;;;785:25:1;;;773:2;758:18;56555:60:0;639:177:1;58916:54:0;;;;;;;;;;-1:-1:-1;58916:54:0;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;:::i;57527:359::-;;;;;;;;;;-1:-1:-1;57527:359:0;;;;;:::i;:::-;;:::i;:::-;;56737:45;;;;;;;;;;;;56776:6;56737:45;;58514;;;;;;;;;;;;58553:6;58514:45;;47930:120;;;;;;;;;;-1:-1:-1;47930:120:0;;;;;:::i;:::-;47995:7;48021:12;;;;;;;;;;:22;;;;47930:120;48346:136;;;;;;;;;;-1:-1:-1;48346:136:0;;;;;:::i;:::-;;:::i;49448:245::-;;;;;;;;;;-1:-1:-1;49448:245:0;;;;;:::i;:::-;;:::i;66591:1146::-;;;;;;;;;;-1:-1:-1;66591:1146:0;;;;;:::i;:::-;;:::i;61049:2114::-;;;;;;:::i;:::-;;:::i;56899:30::-;;;;;;;;;;;;;;;;56483:66;;;;;;;;;;;;56523:26;56483:66;;68338:1153;;;;;;;;;;-1:-1:-1;68338:1153:0;;;;;:::i;:::-;;:::i;58646:56::-;;;;;;;;;;;;58692:10;58646:56;;59161:44;;;;;;;;;;-1:-1:-1;59161:44:0;;;;;:::i;:::-;;;;;;;;;;;;;;;;64957:567;;;;;;;;;;-1:-1:-1;64957:567:0;;;;;:::i;:::-;;:::i;63201:1718::-;;;;;;:::i;:::-;;:::i;55122:142::-;;;;;;;;;;-1:-1:-1;55122:142:0;;;;;:::i;:::-;;:::i;:::-;;;-1:-1:-1;;;;;7391:55:1;;;7373:74;;7361:2;7346:18;55122:142:0;7227:226:1;59035:51:0;;;;;;;;;;-1:-1:-1;59035:51:0;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;59035:51:0;;;;;;;7660:26:1;7648:39;;;7630:58;;-1:-1:-1;;;;;7724:55:1;;;7719:2;7704:18;;7697:83;7603:18;59035:51:0;7458:328:1;46974:136:0;;;;;;;;;;-1:-1:-1;46974:136:0;;;;;:::i;:::-;47051:4;47074:12;;;;;;;;;;;-1:-1:-1;;;;;47074:29:0;;;;;;;;;;;;;;;46974:136;56413:64;;;;;;;;;;;;56452:25;56413:64;;46307:49;;;;;;;;;;-1:-1:-1;46307:49:0;46352:4;46307:49;;59321:36;;;;;;;;;;;;;;;66180:373;;;;;;;;;;-1:-1:-1;66180:373:0;;;;;:::i;:::-;;:::i;60848:163::-;;;;;;;;;;-1:-1:-1;60848:163:0;;;;;:::i;:::-;;:::i;:::-;;;;;;;:::i;67775:525::-;;;;;;;;;;-1:-1:-1;67775:525:0;;;;;:::i;:::-;;:::i;59244:20::-;;;;;;;;;;;;;;;;57231:290;;;;;;;;;;-1:-1:-1;57231:290:0;;;;;:::i;:::-;;:::i;57892:264::-;;;;;;;;;;-1:-1:-1;57892:264:0;;;;;:::i;:::-;;:::i;56694:37::-;;;;;;;;;;;;56728:3;56694:37;;55432:131;;;;;;;;;;-1:-1:-1;55432:131:0;;;;;:::i;:::-;;:::i;56621:66::-;;;;;;;;;;;;56661:26;56621:66;;48762:138;;;;;;;;;;-1:-1:-1;48762:138:0;;;;;:::i;:::-;;:::i;56985:47::-;;;;;;;;;;-1:-1:-1;56985:47:0;;;;;:::i;:::-;;;;;;;;;;;;;;57106:29;;;;;;;;;;;;;;;;54325:212;54410:4;54433:57;;;54448:42;54433:57;;:97;;;54494:36;54518:11;54494:23;:36::i;:::-;54426:104;54325:212;-1:-1:-1;;54325:212:0:o;57527:359::-;56661:26;46584:16;46595:4;46584:10;:16::i;:::-;-1:-1:-1;;;;;57651:19:0;::::1;57631:17;57651:19:::0;;;:12:::1;:19;::::0;;;;;;57684:14;;;57680:27:::1;;57700:7;57527:359:::0;;;:::o;57680:27::-:1;-1:-1:-1::0;;;;;57748:19:0;::::1;57770:1;57748:19:::0;;;:12:::1;:19;::::0;;;;:23;57781:45:::1;::::0;57805:9;57816;57781:23:::1;:45::i;:::-;57841:38;::::0;;-1:-1:-1;;;;;9986:15:1;;;9968:34;;10038:15;;10033:2;10018:18;;10011:43;10070:18;;;10063:34;;;57841:38:0::1;::::0;9895:2:1;9880:18;57841:38:0::1;;;;;;;57621:265;46610:1;57527:359:::0;;;:::o;48346:136::-;47995:7;48021:12;;;;;;;;;;:22;;;46584:16;46595:4;46584:10;:16::i;:::-;48450:25:::1;48461:4;48467:7;48450:10;:25::i;:::-;;48346:136:::0;;;:::o;49448:245::-;-1:-1:-1;;;;;49541:34:0;;22395:10;49541:34;49537:102;;49598:30;;;;;;;;;;;;;;49537:102;49649:37;49661:4;49667:18;49649:11;:37::i;66591:1146::-;56452:25;46584:16;46595:4;46584:10;:16::i;:::-;66706:18;;::::1;::::0;::::1;::::0;66682:21:::1;66773:29;66716:7:::0;66773:20:::1;:29::i;:::-;66734:68:::0;-1:-1:-1;66920:27:0::1;66887:29;::::0;;;:14:::1;:29;::::0;;;;;::::1;;:60;::::0;::::1;;;;;;:::i;:::-;;66883:90;;66956:17;;;;;;;;;;;;;;66883:90;66984:24;67011:27:::0;;;:12:::1;:27;::::0;;;;;;;;66984:54;;;;::::1;::::0;;;;::::1;::::0;::::1;::::0;;;;::::1;-1:-1:-1::0;;;;;66984:54:0::1;::::0;;::::1;::::0;;;67069:10:::1;67052:27;67048:57;;67088:17;;;;;;;;;;;;;;67048:57;66110:15:::0;;58408:10:::1;::::0;66091:15;66084:41;66076:49;;67119:35:::1;67115:72;;67163:24;;;;;;;;;;;;;;67115:72;67198:29;::::0;;;:14:::1;:29;::::0;;;;:60;;-1:-1:-1;;67198:60:0::1;67230:28;67198:60;::::0;;67333:27:::1;::::0;::::1;::::0;:31;67329:105:::1;;67407:27;::::0;::::1;::::0;67379:23:::1;::::0;::::1;::::0;-1:-1:-1;;;;;67366:37:0::1;;::::0;;;:12:::1;:37;::::0;;;;:68;;:37;;;:68:::1;::::0;67407:27;;67366:68:::1;:::i;:::-;::::0;;;-1:-1:-1;;67329:105:0::1;67529:23;::::0;::::1;::::0;67579:24:::1;::::0;::::1;::::0;67613:35:::1;-1:-1:-1::0;;;;;67613:23:0;::::1;67637:2:::0;67579:24;67613:23:::1;:35::i;:::-;67664:66;::::0;;-1:-1:-1;;;;;10619:55:1;;;10601:74;;10706:2;10691:18;;10684:34;;;67664:66:0;::::1;::::0;67700:10:::1;::::0;67685:13;;67664:66:::1;::::0;10574:18:1;67664:66:0::1;;;;;;;;66672:1065;;;;;66591:1146:::0;;;:::o;61049:2114::-;61176:13;61155:6;:17;;;:34;;;61151:63;;61198:16;;;;;;;;;;;;;;61151:63;61228:19;;;;:24;;:50;;-1:-1:-1;61256:17:0;;;;:22;61228:50;61224:80;;;61287:17;;;;;;;;;;;;;;61224:80;61318:18;;;;-1:-1:-1;;;;;61318:32:0;;;:66;;-1:-1:-1;61354:16:0;;;;-1:-1:-1;;;;;61354:30:0;;61318:66;61314:92;;;61393:13;;;;;;;;;;;;;;61314:92;61438:37;58692:10;61438:15;:37;:::i;:::-;61420:6;:15;;;:55;61416:86;;;61484:18;;;;;;;;;;;;;;61416:86;61637:20;61660:66;61679:4;61686:6;:18;;;61706:6;:19;;;61660:10;:66::i;:::-;61637:89;;61794:23;61849:1;61831:15;;:19;61827:85;;;56728:3;61886:15;;61871:12;:30;;;;:::i;:::-;61870:42;;;;:::i;:::-;61852:60;;61827:85;61922:31;61938:15;61922:31;;:::i;:::-;;;62066:20;62113:618;;;;;;;;62171:13;62113:618;;;;;;62216:6;:17;;;62113:618;;;;;;62265:6;:13;;;-1:-1:-1;;;;;62113:618:0;;;;;62311:6;:9;;;-1:-1:-1;;;;;62113:618:0;;;;;62351:6;:18;;;-1:-1:-1;;;;;62113:618:0;;;;;62398:6;:16;;;-1:-1:-1;;;;;62113:618:0;;;;;62446:12;62113:618;;;;62488:6;:17;;;62113:618;;;;62540:15;62113:618;;;;62587:6;:19;;;62113:618;;;;;;62634:6;:15;;;62113:618;;;;62674:5;;:7;;;;;;;;;:::i;:::-;;;;-1:-1:-1;62113:618:0;;62089:652;;;;;;;;:::i;:::-;;;;;;;;;;;;;;62775:18;;62089:652;62775:18;;;;;;;62751:21;62803:29;;;:14;:29;;;;;;:54;;-1:-1:-1;;62803:54:0;62835:22;62803:54;;;62929:13;;;62977:17;;63008:18;;;;63040:16;;;;63096:17;;;;63127:19;;;;62089:652;;-1:-1:-1;62775:18:0;;-1:-1:-1;;;;;62873:283:0;;;;62775:18;;62873:283;;;;62089:652;;62977:17;;63008:18;;63040:16;;63070:12;;62873:283;:::i;:::-;;;;;;;;61110:2053;;;;61049:2114;:::o;68338:1153::-;68419:18;;;;;;68395:21;68486:29;68429:7;68486:20;:29::i;:::-;68553:10;47051:4;47074:29;;;:12;;:29;:12;:29;;;68447:68;;-1:-1:-1;47074:29:0;;68526:382;;;68661:11;:20;;;68642:15;:39;68638:73;;68690:21;;;;;;;;;;;;;;68638:73;68526:382;;;58553:6;68832:11;:20;;;:35;;;;:::i;:::-;68813:15;:54;68809:88;;68876:21;;;;;;;;;;;;;;68809:88;69017:22;68984:29;;;;:14;:29;;;;;;;;:55;;;;;;;;:::i;:::-;;68980:85;;69048:17;;;;;;;;;;;;;;68980:85;69075:29;;;;:14;:29;;;;;;:53;;-1:-1:-1;;69075:53:0;69107:21;69075:53;;;69214:24;;;69264:23;;;;69341:27;;;;69314:24;;;;69214;;69264:23;;69314:54;;69341:27;69314:54;:::i;:::-;69297:71;-1:-1:-1;69378:35:0;-1:-1:-1;;;;;69378:23:0;;69402:2;69297:71;69378:23;:35::i;:::-;69429:55;;;-1:-1:-1;;;;;10619:55:1;;;10601:74;;10706:2;10691:18;;10684:34;;;69429:55:0;;;69451:13;;69429:55;;10574:18:1;69429:55:0;;;;;;;68385:1106;;;;;68338:1153;:::o;64957:567::-;56452:25;46584:16;46595:4;46584:10;:16::i;:::-;65080:18;;::::1;::::0;::::1;::::0;65201:22:::1;65168:29;::::0;;;:14:::1;:29;::::0;;;;;::::1;;:55;::::0;::::1;;;;;;:::i;:::-;;65164:85;;65232:17;;;;;;;;;;;;;;65164:85;65259:29;::::0;;;:14:::1;:29;::::0;;;;;;;:59;;65291:27:::1;-1:-1:-1::0;;65259:59:0;;::::1;;::::0;;65358:70;;;;::::1;::::0;;::::1;65389:15;65358:70:::0;::::1;::::0;;65416:10:::1;65358:70:::0;;::::1;::::0;;;65328:27;;;:12:::1;:27:::0;;;;;;:100;;;;-1:-1:-1;;;;;65328:100:0::1;::::0;::::1;::::0;;;::::1;::::0;;;::::1;::::0;;65459:58;785:25:1;;;65259:29:0;;65459:58:::1;::::0;758:18:1;65459:58:0::1;;;;;;;65046:478;64957:567:::0;;;:::o;63201:1718::-;56452:25;46584:16;46595:4;46584:10;:16::i;:::-;63312:18;;::::1;::::0;::::1;::::0;63288:21:::1;63379:29;63322:7:::0;63379:20:::1;:29::i;:::-;63340:68;;63456:13;63422:48;;:11;:23;;;:48;;;63418:77;;63479:16;;;;;;;;;;;;;;63418:77;63591:11;:20;;;63573:15;:38;63569:69;;;63620:18;;;;;;;;;;;;;;63569:69;63699:27;::::0;;;:12:::1;:27;::::0;;;;;::::1;;63695:60;;;63735:20;;;;;;;;;;;;;;63695:60;63765:27;::::0;;;:12:::1;:27;::::0;;;;:34;;-1:-1:-1;;63765:34:0::1;63795:4;63765:34;::::0;;63912:25:::1;::::0;::::1;::::0;63963:21:::1;::::0;::::1;::::0;64011:22:::1;::::0;::::1;::::0;64061:14:::1;::::0;64090:24:::1;::::0;::::1;::::0;64085:517:::1;;-1:-1:-1::0;64168:1:0::1;64183:29;64194:2:::0;64198:5;64205:6;64183:10:::1;:29::i;:::-;;64085:517;;;64233:38:::0;-1:-1:-1;;;;;64233:38:0;::::1;::::0;64229:373:::1;;64353:38;64364:2:::0;64368:5;64375:15:::1;64384:6:::0;64375;:15:::1;:::i;:::-;64353:10;:38::i;64229:373::-;64495:29;64506:2;64510:5;64517:6;64495:10;:29::i;:::-;;64538:53;64549:2;51314:42;64584:6;64538:10;:53::i;:::-;;64229:373;64711:25:::0;;64750:23:::1;::::0;;::::1;::::0;64787:21:::1;::::0;;::::1;::::0;64822:24:::1;::::0;;::::1;::::0;64860:22:::1;::::0;::::1;::::0;64617:295:::1;::::0;;13103:10:1;13091:23;;;13073:42;;-1:-1:-1;;;;;13212:15:1;;;13207:2;13192:18;;13185:43;13264:15;;;13244:18;;;13237:43;;;;13311:2;13296:18;;13289:34;13339:19;;;13332:35;13383:19;;13376:35;;;64617:295:0;::::1;::::0;64671:10:::1;::::0;64644:13;;64617:295:::1;::::0;13045:19:1;64617:295:0::1;12788:629:1::0;55122:142:0;55203:7;55229:18;;;:12;:18;;;;;:28;;55251:5;55229:21;:28::i;:::-;55222:35;55122:142;-1:-1:-1;;;55122:142:0:o;66180:373::-;66261:4;66314:27;66281:29;;;;:14;:29;;;;;;;;:60;;;;;;;;:::i;:::-;;66277:90;;66350:17;;;;;;;;;;;;;;66277:90;66377:24;66404:27;;;:12;:27;;;;;;;;;66377:54;;;;;;;;;;;;;;-1:-1:-1;;;;;66377:54:0;;;;;;;;;;;;66445:24;;;66441:54;;66478:17;;;;;;;;;;;;;;66441:54;66110:15;;58408:10;;66091:15;66084:41;66076:49;;66512:34;;66180:373;-1:-1:-1;;;;66180:373:0:o;60848:163::-;-1:-1:-1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;60964:40:0;;-1:-1:-1;;60964:40:0;;;;;;;;;;:::i;67775:525::-;56592:23;46584:16;46595:4;46584:10;:16::i;:::-;67892:27:::1;67859:29;::::0;;;:14:::1;:29;::::0;;;;;::::1;;:60;::::0;::::1;;;;;;:::i;:::-;;67855:90;;67928:17;;;;;;;;;;;;;;67855:90;67970:27;::::0;;;:12:::1;:27;::::0;;;;;;;;67959:39;;;;::::1;::::0;;;;::::1;::::0;;::::1;::::0;;;;;;::::1;-1:-1:-1::0;;;;;67959:39:0::1;::::0;;;::::1;::::0;;;;58408:10:::1;::::0;66091:15;66084:41;66076:49;67959:56:::1;67955:90;;;68024:21;;;;;;;;;;;;;;67955:90;68133:29;::::0;;;:14:::1;:29;::::0;;;;;;;:54;;-1:-1:-1;;68133:54:0::1;68165:22;68133:54;::::0;;68204:12:::1;:27:::0;;;;;;68197:34;;;68247:46;68282:10:::1;::::0;68133:29;;68247:46:::1;::::0;68133:29;68247:46:::1;67775:525:::0;;:::o;57231:290::-;56661:26;46584:16;46595:4;46584:10;:16::i;:::-;56776:6:::1;57330:10;:26;;57322:55;;;::::0;::::1;::::0;;15233:2:1;57322:55:0::1;::::0;::::1;15215:21:1::0;15272:2;15252:18;;;15245:30;15311:18;15291;;;15284:46;15347:18;;57322:55:0::1;;;;;;;;;57408:15;::::0;;57433:28;;;;57476:38:::1;::::0;;15550:25:1;;;15606:2;15591:18;;15584:34;;;57476:38:0::1;::::0;15523:18:1;57476:38:0::1;;;;;;;;57312:209;57231:290:::0;;:::o;57892:264::-;56661:26;46584:16;46595:4;46584:10;:16::i;:::-;58017:14:::1;::::0;;58041:34;;;;58090:59:::1;::::0;;15550:25:1;;;15606:2;15591:18;;15584:34;;;58090:59:0::1;::::0;15523:18:1;58090:59:0::1;15376:248:1::0;55432:131:0;55503:7;55529:18;;;:12;:18;;;;;:27;;:25;:27::i;48762:138::-;47995:7;48021:12;;;;;;;;;;:22;;;46584:16;46595:4;46584:10;:16::i;:::-;48867:26:::1;48879:4;48885:7;48867:11;:26::i;46685:202::-:0;46770:4;46793:47;;;46808:32;46793:47;;:87;;-1:-1:-1;38600:25:0;38585:40;;;;46844:36;38486:146;47319:103;47385:30;47396:4;22395:10;47385;:30::i;:::-;47319:103;:::o;51597:653::-;51772:4;-1:-1:-1;;;;;51758:19:0;;;51754:32;;51597:653;;;:::o;51754:32::-;51858:5;51867:1;51858:10;51854:23;;51597:653;;;:::o;51854:23::-;51890:20;-1:-1:-1;;;;;51890:20:0;;;51886:358;;52070:12;52087:2;-1:-1:-1;;;;;52087:7:0;52102:5;52087:25;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;52069:43;;;52134:7;52126:39;;;;;;;16041:2:1;52126:39:0;;;16023:21:1;16080:2;16060:18;;;16053:30;16119:21;16099:18;;;16092:49;16158:18;;52126:39:0;15839:343:1;51886:358:0;52196:37;-1:-1:-1;;;;;52196:26:0;;52223:2;52227:5;52196:26;:37::i;55665:257::-;55751:4;55767:12;55782:31;55799:4;55805:7;55782:16;:31::i;:::-;55767:46;;55827:7;55823:69;;;55850:18;;;;:12;:18;;;;;:31;;55873:7;55850:22;:31::i;:::-;;55908:7;55665:257;-1:-1:-1;;;55665:257:0:o;56025:262::-;56112:4;56128:12;56143:32;56161:4;56167:7;56143:17;:32::i;:::-;56128:47;;56189:7;56185:72;;;56212:18;;;;:12;:18;;;;;:34;;56238:7;56212:25;:34::i;59633:1177::-;59721:20;-1:-1:-1;;;;;59757:38:0;;51314:42;59757:38;59753:1051;;59811:24;:5;-1:-1:-1;;;;;59811:22:0;;:24::i;:::-;59916:34;;;;;-1:-1:-1;;;;;7391:55:1;;;59916:34:0;;;7373:74:1;59916:23:0;;;;;7346:18:1;;59916:34:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;59901:49;-1:-1:-1;60096:61:0;-1:-1:-1;;;;;60096:30:0;;60127:10;60139:9;60150:6;60096:30;:61::i;:::-;60293:34;;;;;-1:-1:-1;;;;;7391:55:1;;;60293:34:0;;;7373:74:1;60330:12:0;;60293:23;;;;;;7346:18:1;;60293:34:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;:49;;;;:::i;:::-;60278:64;;59753:1051;;;60464:9;60454:6;:19;60450:51;;60482:19;;;;;;;;;;;;;;60450:51;-1:-1:-1;;;;;60582:26:0;;60603:4;60582:26;60578:74;;60610:42;-1:-1:-1;;;;;60610:23:0;;60634:9;60645:6;60610:23;:42::i;:::-;-1:-1:-1;60784:9:0;59633:1177;;;;;:::o;33098:156::-;33172:7;33222:22;33226:3;33238:5;33222:3;:22::i;32641:115::-;32704:7;32730:19;32738:3;28080:18;;27998:107;47552:197;47051:4;47074:12;;;;;;;;;;;-1:-1:-1;;;;;47074:29:0;;;;;;;;;;;;47635:108;;47685:47;;;;;-1:-1:-1;;;;;10619:55:1;;47685:47:0;;;10601:74:1;10691:18;;;10684:34;;;10574:18;;47685:47:0;10427:297:1;47635:108:0;47552:197;;:::o;39802:160::-;39911:43;;-1:-1:-1;;;;;10619:55:1;;;39911:43:0;;;10601:74:1;10691:18;;;10684:34;;;39884:71:0;;39904:5;;39926:14;;;;;10574:18:1;;39911:43:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;39884:19;:71::i;50299:316::-;50376:4;47074:12;;;;;;;;;;;-1:-1:-1;;;;;47074:29:0;;;;;;;;;;;;50392:217;;50435:6;:12;;;;;;;;;;;-1:-1:-1;;;;;50435:29:0;;;;;;;;;:36;;-1:-1:-1;;50435:36:0;50467:4;50435:36;;;50517:12;22395:10;;22316:96;50517:12;-1:-1:-1;;;;;50490:40:0;50508:7;-1:-1:-1;;;;;50490:40:0;50502:4;50490:40;;;;;;;;;;-1:-1:-1;50551:4:0;50544:11;;50392:217;-1:-1:-1;50593:5:0;50586:12;;31840:150;31910:4;31933:50;31938:3;-1:-1:-1;;;;;31958:23:0;;31933:4;:50::i;50850:317::-;50928:4;47074:12;;;;;;;;;;;-1:-1:-1;;;;;47074:29:0;;;;;;;;;;;;50944:217;;;51018:5;50986:12;;;;;;;;;;;-1:-1:-1;;;;;50986:29:0;;;;;;;;;;:37;;-1:-1:-1;;50986:37:0;;;51042:40;22395:10;;50986:12;;51042:40;;51018:5;51042:40;-1:-1:-1;51103:4:0;51096:11;;32158:156;32231:4;32254:53;32262:3;-1:-1:-1;;;;;32282:23:0;;32254:7;:53::i;53414:344::-;53581:38;-1:-1:-1;;;;;53581:38:0;;;53577:69;;53628:18;;;;;;;;;;;;;;53577:69;53702:5;-1:-1:-1;;;;;53702:17:0;;53723:1;53702:22;53698:53;;53733:18;;;;;;;;;;;;;;40201:188;40328:53;;-1:-1:-1;;;;;9986:15:1;;;40328:53:0;;;9968:34:1;10038:15;;;10018:18;;;10011:43;10070:18;;;10063:34;;;40301:81:0;;40321:5;;40343:18;;;;;9880::1;;40328:53:0;9705:398:1;28447:118:0;28514:7;28540:3;:11;;28552:5;28540:18;;;;;;;;:::i;:::-;;;;;;;;;28533:25;;28447:118;;;;:::o;42558:629::-;42977:23;43003:33;-1:-1:-1;;;;;43003:27:0;;43031:4;43003:27;:33::i;:::-;42977:59;;43050:10;:17;43071:1;43050:22;;:57;;;;;43088:10;43077:30;;;;;;;;;;;;:::i;:::-;43076:31;43050:57;43046:135;;;43130:40;;;;;-1:-1:-1;;;;;7391:55:1;;43130:40:0;;;7373:74:1;7346:18;;43130:40:0;7227:226:1;25765:406:0;25828:4;27884:21;;;:14;;;:21;;;;;;25844:321;;-1:-1:-1;25886:23:0;;;;;;;;:11;:23;;;;;;;;;;;;;26068:18;;26044:21;;;:14;;;:21;;;;;;:42;;;;26100:11;;26339:1368;26405:4;26534:21;;;:14;;;:21;;;;;;26570:13;;26566:1135;;26937:18;26958:12;26969:1;26958:8;:12;:::i;:::-;27004:18;;26937:33;;-1:-1:-1;26984:17:0;;27004:22;;27025:1;;27004:22;:::i;:::-;26984:42;;27059:9;27045:10;:23;27041:378;;27088:17;27108:3;:11;;27120:9;27108:22;;;;;;;;:::i;:::-;;;;;;;;;27088:42;;27255:9;27229:3;:11;;27241:10;27229:23;;;;;;;;:::i;:::-;;;;;;;;;;;;:35;;;;27368:25;;;:14;;;:25;;;;;:36;;;27041:378;27497:17;;:3;;:17;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;27600:3;:14;;:21;27615:5;27600:21;;;;;;;;;;;27593:28;;;27643:4;27636:11;;;;;;;26566:1135;27685:5;27678:12;;;;;18101:151;18176:12;18207:38;18229:6;18237:4;18243:1;18176:12;18817;18831:23;18858:6;-1:-1:-1;;;;;18858:11:0;18877:5;18884:4;18858:31;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;18816:73;;;;18906:55;18933:6;18941:7;18950:10;18906:26;:55::i;:::-;18899:62;18576:392;-1:-1:-1;;;;;;18576:392:0:o;20021:582::-;20165:12;20194:7;20189:408;;20217:19;20225:10;20217:7;:19::i;:::-;20189:408;;;20441:17;;:22;:49;;;;-1:-1:-1;;;;;;20467:18:0;;;:23;20441:49;20437:119;;;20517:24;;;;;-1:-1:-1;;;;;7391:55:1;;20517:24:0;;;7373:74:1;7346:18;;20517:24:0;7227:226:1;20437:119:0;-1:-1:-1;20576:10:0;20569:17;;21139:516;21270:17;;:21;21266:383;;21498:10;21492:17;21554:15;21541:10;21537:2;21533:19;21526:44;21266:383;21621:17;;;;;;;;;;;;;;14:332:1;72:6;125:2;113:9;104:7;100:23;96:32;93:52;;;141:1;138;131:12;93:52;180:9;167:23;230:66;223:5;219:78;212:5;209:89;199:117;;312:1;309;302:12;821:180;880:6;933:2;921:9;912:7;908:23;904:32;901:52;;;949:1;946;939:12;901:52;-1:-1:-1;972:23:1;;821:180;-1:-1:-1;821:180:1:o;1006:184::-;1058:77;1055:1;1048:88;1155:4;1152:1;1145:15;1179:4;1176:1;1169:15;1195:402;1344:2;1329:18;;1377:1;1366:13;;1356:201;;1413:77;1410:1;1403:88;1514:4;1511:1;1504:15;1542:4;1539:1;1532:15;1356:201;1566:25;;;1195:402;:::o;1602:154::-;-1:-1:-1;;;;;1681:5:1;1677:54;1670:5;1667:65;1657:93;;1746:1;1743;1736:12;1761:134;1829:20;;1858:31;1829:20;1858:31;:::i;:::-;1761:134;;;:::o;1900:388::-;1968:6;1976;2029:2;2017:9;2008:7;2004:23;2000:32;1997:52;;;2045:1;2042;2035:12;1997:52;2084:9;2071:23;2103:31;2128:5;2103:31;:::i;:::-;2153:5;-1:-1:-1;2210:2:1;2195:18;;2182:32;2223:33;2182:32;2223:33;:::i;:::-;2275:7;2265:17;;;1900:388;;;;;:::o;2475:315::-;2543:6;2551;2604:2;2592:9;2583:7;2579:23;2575:32;2572:52;;;2620:1;2617;2610:12;2572:52;2656:9;2643:23;2633:33;;2716:2;2705:9;2701:18;2688:32;2729:31;2754:5;2729:31;:::i;2795:184::-;2847:77;2844:1;2837:88;2944:4;2941:1;2934:15;2968:4;2965:1;2958:15;2984:252;3056:2;3050:9;3098:3;3086:16;;3132:18;3117:34;;3153:22;;;3114:62;3111:88;;;3179:18;;:::i;:::-;3215:2;3208:22;2984:252;:::o;3241:247::-;3308:2;3302:9;3350:3;3338:16;;3384:18;3369:34;;3405:22;;;3366:62;3363:88;;;3431:18;;:::i;3493:777::-;3535:5;3588:3;3581:4;3573:6;3569:17;3565:27;3555:55;;3606:1;3603;3596:12;3555:55;3642:6;3629:20;3668:18;3705:2;3701;3698:10;3695:36;;;3711:18;;:::i;:::-;3845:2;3839:9;3907:4;3899:13;;3750:66;3895:22;;;3919:2;3891:31;3887:40;3875:53;;;3943:18;;;3963:22;;;3940:46;3937:72;;;3989:18;;:::i;:::-;4029:10;4025:2;4018:22;4064:2;4056:6;4049:18;4110:3;4103:4;4098:2;4090:6;4086:15;4082:26;4079:35;4076:55;;;4127:1;4124;4117:12;4076:55;4191:2;4184:4;4176:6;4172:17;4165:4;4157:6;4153:17;4140:54;4238:1;4231:4;4226:2;4218:6;4214:15;4210:26;4203:37;4258:6;4249:15;;;;;;3493:777;;;;:::o;4275:455::-;4352:6;4360;4413:2;4401:9;4392:7;4388:23;4384:32;4381:52;;;4429:1;4426;4419:12;4381:52;4469:9;4456:23;4502:18;4494:6;4491:30;4488:50;;;4534:1;4531;4524:12;4488:50;4557:49;4598:7;4589:6;4578:9;4574:22;4557:49;:::i;:::-;4547:59;;;4656:2;4645:9;4641:18;4628:32;4669:31;4694:5;4669:31;:::i;4735:121::-;4820:10;4813:5;4809:22;4802:5;4799:33;4789:61;;4846:1;4843;4836:12;4861:132;4928:20;;4957:30;4928:20;4957:30;:::i;4998:118::-;5084:5;5077:13;5070:21;5063:5;5060:32;5050:60;;5106:1;5103;5096:12;5121:128;5186:20;;5215:28;5186:20;5215:28;:::i;5254:865::-;5342:6;5395:3;5383:9;5374:7;5370:23;5366:33;5363:53;;;5412:1;5409;5402:12;5363:53;5438:22;;:::i;:::-;5483:28;5501:9;5483:28;:::i;:::-;5476:5;5469:43;5544:38;5578:2;5567:9;5563:18;5544:38;:::i;:::-;5539:2;5532:5;5528:14;5521:62;5615:38;5649:2;5638:9;5634:18;5615:38;:::i;:::-;5610:2;5603:5;5599:14;5592:62;5686:38;5720:2;5709:9;5705:18;5686:38;:::i;:::-;5681:2;5674:5;5670:14;5663:62;5758:39;5792:3;5781:9;5777:19;5758:39;:::i;:::-;5752:3;5745:5;5741:15;5734:64;5859:3;5848:9;5844:19;5831:33;5825:3;5818:5;5814:15;5807:58;5926:3;5915:9;5911:19;5898:33;5892:3;5885:5;5881:15;5874:58;5965:36;5996:3;5985:9;5981:19;5965:36;:::i;:::-;5959:3;5948:15;;5941:61;6021:3;6069:18;;;6056:32;6040:14;;;6033:56;;;;-1:-1:-1;5952:5:1;5254:865;-1:-1:-1;5254:865:1:o;6124:320::-;6192:6;6245:2;6233:9;6224:7;6220:23;6216:32;6213:52;;;6261:1;6258;6251:12;6213:52;6301:9;6288:23;6334:18;6326:6;6323:30;6320:50;;;6366:1;6363;6356:12;6320:50;6389:49;6430:7;6421:6;6410:9;6406:22;6389:49;:::i;:::-;6379:59;6124:320;-1:-1:-1;;;;6124:320:1:o;6449:388::-;6526:6;6534;6587:2;6575:9;6566:7;6562:23;6558:32;6555:52;;;6603:1;6600;6593:12;6555:52;6643:9;6630:23;6676:18;6668:6;6665:30;6662:50;;;6708:1;6705;6698:12;6662:50;6731:49;6772:7;6763:6;6752:9;6748:22;6731:49;:::i;:::-;6721:59;6827:2;6812:18;;;;6799:32;;-1:-1:-1;;;;6449:388:1:o;6842:248::-;6910:6;6918;6971:2;6959:9;6950:7;6946:23;6942:32;6939:52;;;6987:1;6984;6977:12;6939:52;-1:-1:-1;;7010:23:1;;;7080:2;7065:18;;;7052:32;;-1:-1:-1;6842:248:1:o;7890:1373::-;8121:13;;7867:10;7856:22;7844:35;;8090:3;8075:19;;8193:4;8185:6;8181:17;8175:24;8208:53;8255:4;8244:9;8240:20;8226:12;7867:10;7856:22;7844:35;;7791:94;8208:53;;8310:4;8302:6;8298:17;8292:24;8325:56;8375:4;8364:9;8360:20;8344:14;-1:-1:-1;;;;;7161:54:1;7149:67;;7095:127;8325:56;;8430:4;8422:6;8418:17;8412:24;8445:56;8495:4;8484:9;8480:20;8464:14;-1:-1:-1;;;;;7161:54:1;7149:67;;7095:127;8445:56;;8550:4;8542:6;8538:17;8532:24;8565:56;8615:4;8604:9;8600:20;8584:14;-1:-1:-1;;;;;7161:54:1;7149:67;;7095:127;8565:56;;8670:4;8662:6;8658:17;8652:24;8685:56;8735:4;8724:9;8720:20;8704:14;-1:-1:-1;;;;;7161:54:1;7149:67;;7095:127;8685:56;;8797:4;8789:6;8785:17;8779:24;8772:4;8761:9;8757:20;8750:54;8860:4;8852:6;8848:17;8842:24;8835:4;8824:9;8820:20;8813:54;8886:6;8946:2;8938:6;8934:15;8928:22;8923:2;8912:9;8908:18;8901:50;;8970:6;9025:2;9017:6;9013:15;9007:22;9038:51;9085:2;9074:9;9070:18;9054:14;421:13;414:21;402:34;;351:91;9038:51;-1:-1:-1;;9108:6:1;9156:15;;;9150:22;9130:18;;;9123:50;9192:6;9240:15;;;9234:22;9214:18;;;;9207:50;;;;7890:1373;:::o;9453:247::-;9512:6;9565:2;9553:9;9544:7;9540:23;9536:32;9533:52;;;9581:1;9578;9571:12;9533:52;9620:9;9607:23;9639:31;9664:5;9639:31;:::i;10108:184::-;10160:77;10157:1;10150:88;10257:4;10254:1;10247:15;10281:4;10278:1;10271:15;10297:125;10362:9;;;10383:10;;;10380:36;;;10396:18;;:::i;10729:168::-;10802:9;;;10833;;10850:15;;;10844:22;;10830:37;10820:71;;10871:18;;:::i;10902:274::-;10942:1;10968;10958:189;;11003:77;11000:1;10993:88;11104:4;11101:1;11094:15;11132:4;11129:1;11122:15;10958:189;-1:-1:-1;11161:9:1;;10902:274::o;11181:128::-;11248:9;;;11269:11;;;11266:37;;;11283:18;;:::i;11314:195::-;11353:3;11384:66;11377:5;11374:77;11371:103;;11454:18;;:::i;:::-;-1:-1:-1;11501:1:1;11490:13;;11314:195::o;11514:250::-;11599:1;11609:113;11623:6;11620:1;11617:13;11609:113;;;11699:11;;;11693:18;11680:11;;;11673:39;11645:2;11638:10;11609:113;;;-1:-1:-1;;11756:1:1;11738:16;;11731:27;11514:250::o;11769:1014::-;12076:3;12065:9;12058:22;12039:4;12109:6;12103:13;12153:6;12147:3;12136:9;12132:19;12125:35;12179:3;12191:81;12265:6;12260:2;12249:9;12245:18;12238:4;12230:6;12226:17;12191:81;:::i;:::-;12452:10;12440:23;;;;12433:4;12418:20;;12411:53;-1:-1:-1;;;;;12561:15:1;;;12556:2;12541:18;;12534:43;12613:15;;;;12608:2;12593:18;;12586:43;12660:3;12645:19;;12638:35;;;;12704:3;12689:19;;12682:35;;;;12761:14;12754:22;12748:3;12733:19;;12726:51;12324:2;12312:15;;;-1:-1:-1;12308:88:1;12293:104;12289:113;;;;;-1:-1:-1;;11769:1014:1:o;13422:136::-;13500:13;;13522:30;13500:13;13522:30;:::i;13563:138::-;13642:13;;13664:31;13642:13;13664:31;:::i;13706:132::-;13782:13;;13804:28;13782:13;13804:28;:::i;13843:1183::-;13946:6;13999:3;13987:9;13978:7;13974:23;13970:33;13967:53;;;14016:1;14013;14006:12;13967:53;14042:17;;:::i;:::-;14082:39;14111:9;14082:39;:::i;:::-;14075:5;14068:54;14154:48;14198:2;14187:9;14183:18;14154:48;:::i;:::-;14149:2;14142:5;14138:14;14131:72;14235:49;14280:2;14269:9;14265:18;14235:49;:::i;:::-;14230:2;14223:5;14219:14;14212:73;14317:49;14362:2;14351:9;14347:18;14317:49;:::i;:::-;14312:2;14305:5;14301:14;14294:73;14400:50;14445:3;14434:9;14430:19;14400:50;:::i;:::-;14394:3;14387:5;14383:15;14376:75;14484:50;14529:3;14518:9;14514:19;14484:50;:::i;:::-;14478:3;14471:5;14467:15;14460:75;14589:3;14578:9;14574:19;14568:26;14562:3;14555:5;14551:15;14544:51;14649:3;14638:9;14634:19;14628:26;14622:3;14615:5;14611:15;14604:51;14674:3;14730:2;14719:9;14715:18;14709:25;14704:2;14697:5;14693:14;14686:49;;14754:3;14789:46;14831:2;14820:9;14816:18;14789:46;:::i;:::-;14773:14;;;14766:70;14855:3;14896:18;;;14890:25;14874:14;;;14867:49;14935:3;14976:18;;;14970:25;14954:14;;;14947:49;;;;-1:-1:-1;14777:5:1;13843:1183;-1:-1:-1;13843:1183:1:o;16187:184::-;16257:6;16310:2;16298:9;16289:7;16285:23;16281:32;16278:52;;;16326:1;16323;16316:12;16278:52;-1:-1:-1;16349:16:1;;16187:184;-1:-1:-1;16187:184:1:o;16678:::-;16730:77;16727:1;16720:88;16827:4;16824:1;16817:15;16851:4;16848:1;16841:15;16867:245;16934:6;16987:2;16975:9;16966:7;16962:23;16958:32;16955:52;;;17003:1;17000;16993:12;16955:52;17035:9;17029:16;17054:28;17076:5;17054:28;:::i;17117:184::-;17169:77;17166:1;17159:88;17266:4;17263:1;17256:15;17290:4;17287:1;17280:15;17306:287;17435:3;17473:6;17467:13;17489:66;17548:6;17543:3;17536:4;17528:6;17524:17;17489:66;:::i;:::-;17571:16;;;;;17306:287;-1:-1:-1;;17306:287:1:o","abiDefinition":[{"inputs":[{"internalType":"address","name":"_owner","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AccessControlBadConfirmation","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"bytes32","name":"neededRole","type":"bytes32"}],"name":"AccessControlUnauthorizedAccount","type":"error"},{"inputs":[{"internalType":"address","name":"target","type":"address"}],"name":"AddressEmptyCode","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"AddressInsufficientBalance","type":"error"},{"inputs":[],"name":"AmountIncorrect","type":"error"},{"inputs":[],"name":"ChainIncorrect","type":"error"},{"inputs":[],"name":"DeadlineExceeded","type":"error"},{"inputs":[],"name":"DeadlineNotExceeded","type":"error"},{"inputs":[],"name":"DeadlineTooShort","type":"error"},{"inputs":[],"name":"DisputePeriodNotPassed","type":"error"},{"inputs":[],"name":"DisputePeriodPassed","type":"error"},{"inputs":[],"name":"FailedInnerCall","type":"error"},{"inputs":[],"name":"MsgValueIncorrect","type":"error"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"SafeERC20FailedOperation","type":"error"},{"inputs":[],"name":"SenderIncorrect","type":"error"},{"inputs":[],"name":"StatusIncorrect","type":"error"},{"inputs":[],"name":"TokenNotContract","type":"error"},{"inputs":[],"name":"TransactionRelayed","type":"error"},{"inputs":[],"name":"ZeroAddress","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"relayer","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"BridgeDepositClaimed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"BridgeDepositRefunded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"relayer","type":"address"}],"name":"BridgeProofDisputed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"relayer","type":"address"},{"indexed":false,"internalType":"bytes32","name":"transactionHash","type":"bytes32"}],"name":"BridgeProofProvided","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"relayer","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint32","name":"originChainId","type":"uint32"},{"indexed":false,"internalType":"address","name":"originToken","type":"address"},{"indexed":false,"internalType":"address","name":"destToken","type":"address"},{"indexed":false,"internalType":"uint256","name":"originAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"destAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"chainGasAmount","type":"uint256"}],"name":"BridgeRelayed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"bytes","name":"request","type":"bytes"},{"indexed":false,"internalType":"uint32","name":"destChainId","type":"uint32"},{"indexed":false,"internalType":"address","name":"originToken","type":"address"},{"indexed":false,"internalType":"address","name":"destToken","type":"address"},{"indexed":false,"internalType":"uint256","name":"originAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"destAmount","type":"uint256"},{"indexed":false,"internalType":"bool","name":"sendChainGas","type":"bool"}],"name":"BridgeRequested","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldChainGasAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newChainGasAmount","type":"uint256"}],"name":"ChainGasAmountUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldFeeRate","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newFeeRate","type":"uint256"}],"name":"FeeRateUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"address","name":"recipient","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"FeesSwept","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"previousAdminRole","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"newAdminRole","type":"bytes32"}],"name":"RoleAdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleRevoked","type":"event"},{"inputs":[],"name":"DEFAULT_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"DISPUTE_PERIOD","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"FEE_BPS","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"FEE_RATE_MAX","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"GOVERNOR_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"GUARD_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MIN_DEADLINE_PERIOD","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"REFUNDER_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"REFUND_DELAY","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"RELAYER_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"uint32","name":"dstChainId","type":"uint32"},{"internalType":"address","name":"sender","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"address","name":"originToken","type":"address"},{"internalType":"address","name":"destToken","type":"address"},{"internalType":"uint256","name":"originAmount","type":"uint256"},{"internalType":"uint256","name":"destAmount","type":"uint256"},{"internalType":"bool","name":"sendChainGas","type":"bool"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"internalType":"struct IFastBridge.BridgeParams","name":"params","type":"tuple"}],"name":"bridge","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"bridgeProofs","outputs":[{"internalType":"uint96","name":"timestamp","type":"uint96"},{"internalType":"address","name":"relayer","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"bridgeRelays","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"bridgeStatuses","outputs":[{"internalType":"enum FastBridge.BridgeStatus","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"internalType":"address","name":"relayer","type":"address"}],"name":"canClaim","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"chainGasAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"},{"internalType":"address","name":"to","type":"address"}],"name":"claim","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"deployBlock","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"transactionId","type":"bytes32"}],"name":"dispute","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"}],"name":"getBridgeTransaction","outputs":[{"components":[{"internalType":"uint32","name":"originChainId","type":"uint32"},{"internalType":"uint32","name":"destChainId","type":"uint32"},{"internalType":"address","name":"originSender","type":"address"},{"internalType":"address","name":"destRecipient","type":"address"},{"internalType":"address","name":"originToken","type":"address"},{"internalType":"address","name":"destToken","type":"address"},{"internalType":"uint256","name":"originAmount","type":"uint256"},{"internalType":"uint256","name":"destAmount","type":"uint256"},{"internalType":"uint256","name":"originFeeAmount","type":"uint256"},{"internalType":"bool","name":"sendChainGas","type":"bool"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint256","name":"nonce","type":"uint256"}],"internalType":"struct IFastBridge.BridgeTransaction","name":"","type":"tuple"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleAdmin","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"uint256","name":"index","type":"uint256"}],"name":"getRoleMember","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleMemberCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"grantRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"hasRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"nonce","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"protocolFeeRate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"protocolFees","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"},{"internalType":"bytes32","name":"destTxHash","type":"bytes32"}],"name":"prove","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"}],"name":"refund","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"}],"name":"relay","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"callerConfirmation","type":"address"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"revokeRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"newChainGasAmount","type":"uint256"}],"name":"setChainGasAmount","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"newFeeRate","type":"uint256"}],"name":"setProtocolFeeRate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"address","name":"recipient","type":"address"}],"name":"sweepProtocolFees","outputs":[],"stateMutability":"nonpayable","type":"function"}],"userDoc":{"kind":"user","methods":{"DISPUTE_PERIOD()":{"notice":"Dispute period for relayed transactions"},"MIN_DEADLINE_PERIOD()":{"notice":"Minimum deadline period to relay a requested bridge transaction"},"REFUND_DELAY()":{"notice":"Delay for a transaction after which it could be permisionlessly refunded"},"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256))":{"notice":"Initiates bridge on origin chain to be relayed by off-chain relayer"},"bridgeProofs(bytes32)":{"notice":"Proof of relayed bridge tx on origin chain"},"bridgeRelays(bytes32)":{"notice":"Whether bridge has been relayed on destination chain"},"bridgeStatuses(bytes32)":{"notice":"Status of the bridge tx on origin chain"},"canClaim(bytes32,address)":{"notice":"Checks if the dispute period has passed so bridge deposit can be claimed"},"chainGasAmount()":{"notice":"Chain gas amount to forward as rebate if requested"},"claim(bytes,address)":{"notice":"Completes bridge transaction on origin chain by claiming originally deposited capital"},"dispute(bytes32)":{"notice":"Disputes an outstanding proof in case relayer provided dest chain tx is invalid"},"getBridgeTransaction(bytes)":{"notice":"Decodes bridge request into a bridge transaction"},"protocolFeeRate()":{"notice":"Protocol fee rate taken on origin amount deposited in origin chain"},"protocolFees(address)":{"notice":"Protocol fee amounts accumulated"},"prove(bytes,bytes32)":{"notice":"Provides proof on origin side that relayer provided funds on destination side of bridge transaction"},"refund(bytes)":{"notice":"Refunds an outstanding bridge transaction in case optimistic bridging failed"},"relay(bytes)":{"notice":"Relays destination side of bridge transaction by off-chain relayer"}},"version":1},"developerDoc":{"errors":{"AccessControlBadConfirmation()":[{"details":"The caller of a function is not the expected one. NOTE: Don't confuse with {AccessControlUnauthorizedAccount}."}],"AccessControlUnauthorizedAccount(address,bytes32)":[{"details":"The `account` is missing a role."}],"AddressEmptyCode(address)":[{"details":"There's no code at `target` (it is not a contract)."}],"AddressInsufficientBalance(address)":[{"details":"The ETH balance of the account is not enough to perform the operation."}],"FailedInnerCall()":[{"details":"A call to an address target failed. The target may have reverted."}],"SafeERC20FailedOperation(address)":[{"details":"An operation with an ERC20 token failed."}]},"events":{"RoleAdminChanged(bytes32,bytes32,bytes32)":{"details":"Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole` `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite {RoleAdminChanged} not being emitted signaling this."},"RoleGranted(bytes32,address,address)":{"details":"Emitted when `account` is granted `role`. `sender` is the account that originated the contract call, an admin role bearer except when using {AccessControl-_setupRole}."},"RoleRevoked(bytes32,address,address)":{"details":"Emitted when `account` is revoked `role`. `sender` is the account that originated the contract call: - if using `revokeRole`, it is the admin role bearer - if using `renounceRole`, it is the role bearer (i.e. `account`)"}},"kind":"dev","methods":{"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256))":{"params":{"params":"The parameters required to bridge"}},"canClaim(bytes32,address)":{"params":{"relayer":"The address of the relayer attempting to claim","transactionId":"The transaction id associated with the encoded bridge transaction to check"}},"claim(bytes,address)":{"params":{"request":"The encoded bridge transaction to claim on origin chain","to":"The recipient address of the funds"}},"dispute(bytes32)":{"params":{"transactionId":"The transaction id associated with the encoded bridge transaction to dispute"}},"getBridgeTransaction(bytes)":{"params":{"request":"The bridge request to decode"}},"getRoleAdmin(bytes32)":{"details":"Returns the admin role that controls `role`. See {grantRole} and {revokeRole}. To change a role's admin, use {_setRoleAdmin}."},"getRoleMember(bytes32,uint256)":{"details":"Returns one of the accounts that have `role`. `index` must be a value between 0 and {getRoleMemberCount}, non-inclusive. Role bearers are not sorted in any particular way, and their ordering may change at any point. WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure you perform all queries on the same block. See the following https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post] for more information."},"getRoleMemberCount(bytes32)":{"details":"Returns the number of accounts that have `role`. Can be used together with {getRoleMember} to enumerate all bearers of a role."},"grantRole(bytes32,address)":{"details":"Grants `role` to `account`. If `account` had not been already granted `role`, emits a {RoleGranted} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleGranted} event."},"hasRole(bytes32,address)":{"details":"Returns `true` if `account` has been granted `role`."},"prove(bytes,bytes32)":{"params":{"destTxHash":"The destination tx hash proving bridge transaction was relayed","request":"The encoded bridge transaction to prove on origin chain"}},"refund(bytes)":{"params":{"request":"The encoded bridge transaction to refund"}},"relay(bytes)":{"params":{"request":"The encoded bridge transaction to relay on destination chain"}},"renounceRole(bytes32,address)":{"details":"Revokes `role` from the calling account. Roles are often managed via {grantRole} and {revokeRole}: this function's purpose is to provide a mechanism for accounts to lose their privileges if they are compromised (such as when a trusted device is misplaced). If the calling account had been revoked `role`, emits a {RoleRevoked} event. Requirements: - the caller must be `callerConfirmation`. May emit a {RoleRevoked} event."},"revokeRole(bytes32,address)":{"details":"Revokes `role` from `account`. If `account` had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleRevoked} event."},"supportsInterface(bytes4)":{"details":"See {IERC165-supportsInterface}."}},"stateVariables":{"nonce":{"details":"to prevent replays"}},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.20+commit.a1b79de6\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_owner\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"AccessControlBadConfirmation\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"neededRole\",\"type\":\"bytes32\"}],\"name\":\"AccessControlUnauthorizedAccount\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"}],\"name\":\"AddressEmptyCode\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"AddressInsufficientBalance\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"AmountIncorrect\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ChainIncorrect\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DeadlineExceeded\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DeadlineNotExceeded\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DeadlineTooShort\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DisputePeriodNotPassed\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DisputePeriodPassed\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"FailedInnerCall\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"MsgValueIncorrect\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"}],\"name\":\"SafeERC20FailedOperation\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"SenderIncorrect\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"StatusIncorrect\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"TokenNotContract\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"TransactionRelayed\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ZeroAddress\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"BridgeDepositClaimed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"BridgeDepositRefunded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"name\":\"BridgeProofDisputed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"transactionHash\",\"type\":\"bytes32\"}],\"name\":\"BridgeProofProvided\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"originChainId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"chainGasAmount\",\"type\":\"uint256\"}],\"name\":\"BridgeRelayed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"destChainId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"sendChainGas\",\"type\":\"bool\"}],\"name\":\"BridgeRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"oldChainGasAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newChainGasAmount\",\"type\":\"uint256\"}],\"name\":\"ChainGasAmountUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"oldFeeRate\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newFeeRate\",\"type\":\"uint256\"}],\"name\":\"FeeRateUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"FeesSwept\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"previousAdminRole\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"newAdminRole\",\"type\":\"bytes32\"}],\"name\":\"RoleAdminChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleGranted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleRevoked\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"DEFAULT_ADMIN_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"DISPUTE_PERIOD\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"FEE_BPS\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"FEE_RATE_MAX\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"GOVERNOR_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"GUARD_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"MIN_DEADLINE_PERIOD\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"REFUNDER_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"REFUND_DELAY\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"RELAYER_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"dstChainId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"sendChainGas\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"}],\"internalType\":\"struct IFastBridge.BridgeParams\",\"name\":\"params\",\"type\":\"tuple\"}],\"name\":\"bridge\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"bridgeProofs\",\"outputs\":[{\"internalType\":\"uint96\",\"name\":\"timestamp\",\"type\":\"uint96\"},{\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"bridgeRelays\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"bridgeStatuses\",\"outputs\":[{\"internalType\":\"enum FastBridge.BridgeStatus\",\"name\":\"\",\"type\":\"uint8\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"name\":\"canClaim\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"chainGasAmount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"claim\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"deployBlock\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"}],\"name\":\"dispute\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"getBridgeTransaction\",\"outputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"originChainId\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"destChainId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"originSender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destRecipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"originFeeAmount\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"sendChainGas\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"}],\"internalType\":\"struct IFastBridge.BridgeTransaction\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"}],\"name\":\"getRoleAdmin\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"index\",\"type\":\"uint256\"}],\"name\":\"getRoleMember\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"}],\"name\":\"getRoleMemberCount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"grantRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"hasRole\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"nonce\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"protocolFeeRate\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"protocolFees\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"},{\"internalType\":\"bytes32\",\"name\":\"destTxHash\",\"type\":\"bytes32\"}],\"name\":\"prove\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"refund\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"relay\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"callerConfirmation\",\"type\":\"address\"}],\"name\":\"renounceRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"revokeRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"newChainGasAmount\",\"type\":\"uint256\"}],\"name\":\"setChainGasAmount\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"newFeeRate\",\"type\":\"uint256\"}],\"name\":\"setProtocolFeeRate\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes4\",\"name\":\"interfaceId\",\"type\":\"bytes4\"}],\"name\":\"supportsInterface\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"}],\"name\":\"sweepProtocolFees\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"errors\":{\"AccessControlBadConfirmation()\":[{\"details\":\"The caller of a function is not the expected one. NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\"}],\"AccessControlUnauthorizedAccount(address,bytes32)\":[{\"details\":\"The `account` is missing a role.\"}],\"AddressEmptyCode(address)\":[{\"details\":\"There's no code at `target` (it is not a contract).\"}],\"AddressInsufficientBalance(address)\":[{\"details\":\"The ETH balance of the account is not enough to perform the operation.\"}],\"FailedInnerCall()\":[{\"details\":\"A call to an address target failed. The target may have reverted.\"}],\"SafeERC20FailedOperation(address)\":[{\"details\":\"An operation with an ERC20 token failed.\"}]},\"events\":{\"RoleAdminChanged(bytes32,bytes32,bytes32)\":{\"details\":\"Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole` `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite {RoleAdminChanged} not being emitted signaling this.\"},\"RoleGranted(bytes32,address,address)\":{\"details\":\"Emitted when `account` is granted `role`. `sender` is the account that originated the contract call, an admin role bearer except when using {AccessControl-_setupRole}.\"},\"RoleRevoked(bytes32,address,address)\":{\"details\":\"Emitted when `account` is revoked `role`. `sender` is the account that originated the contract call: - if using `revokeRole`, it is the admin role bearer - if using `renounceRole`, it is the role bearer (i.e. `account`)\"}},\"kind\":\"dev\",\"methods\":{\"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256))\":{\"params\":{\"params\":\"The parameters required to bridge\"}},\"canClaim(bytes32,address)\":{\"params\":{\"relayer\":\"The address of the relayer attempting to claim\",\"transactionId\":\"The transaction id associated with the encoded bridge transaction to check\"}},\"claim(bytes,address)\":{\"params\":{\"request\":\"The encoded bridge transaction to claim on origin chain\",\"to\":\"The recipient address of the funds\"}},\"dispute(bytes32)\":{\"params\":{\"transactionId\":\"The transaction id associated with the encoded bridge transaction to dispute\"}},\"getBridgeTransaction(bytes)\":{\"params\":{\"request\":\"The bridge request to decode\"}},\"getRoleAdmin(bytes32)\":{\"details\":\"Returns the admin role that controls `role`. See {grantRole} and {revokeRole}. To change a role's admin, use {_setRoleAdmin}.\"},\"getRoleMember(bytes32,uint256)\":{\"details\":\"Returns one of the accounts that have `role`. `index` must be a value between 0 and {getRoleMemberCount}, non-inclusive. Role bearers are not sorted in any particular way, and their ordering may change at any point. WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure you perform all queries on the same block. See the following https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post] for more information.\"},\"getRoleMemberCount(bytes32)\":{\"details\":\"Returns the number of accounts that have `role`. Can be used together with {getRoleMember} to enumerate all bearers of a role.\"},\"grantRole(bytes32,address)\":{\"details\":\"Grants `role` to `account`. If `account` had not been already granted `role`, emits a {RoleGranted} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleGranted} event.\"},\"hasRole(bytes32,address)\":{\"details\":\"Returns `true` if `account` has been granted `role`.\"},\"prove(bytes,bytes32)\":{\"params\":{\"destTxHash\":\"The destination tx hash proving bridge transaction was relayed\",\"request\":\"The encoded bridge transaction to prove on origin chain\"}},\"refund(bytes)\":{\"params\":{\"request\":\"The encoded bridge transaction to refund\"}},\"relay(bytes)\":{\"params\":{\"request\":\"The encoded bridge transaction to relay on destination chain\"}},\"renounceRole(bytes32,address)\":{\"details\":\"Revokes `role` from the calling account. Roles are often managed via {grantRole} and {revokeRole}: this function's purpose is to provide a mechanism for accounts to lose their privileges if they are compromised (such as when a trusted device is misplaced). If the calling account had been revoked `role`, emits a {RoleRevoked} event. Requirements: - the caller must be `callerConfirmation`. May emit a {RoleRevoked} event.\"},\"revokeRole(bytes32,address)\":{\"details\":\"Revokes `role` from `account`. If `account` had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleRevoked} event.\"},\"supportsInterface(bytes4)\":{\"details\":\"See {IERC165-supportsInterface}.\"}},\"stateVariables\":{\"nonce\":{\"details\":\"to prevent replays\"}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"DISPUTE_PERIOD()\":{\"notice\":\"Dispute period for relayed transactions\"},\"MIN_DEADLINE_PERIOD()\":{\"notice\":\"Minimum deadline period to relay a requested bridge transaction\"},\"REFUND_DELAY()\":{\"notice\":\"Delay for a transaction after which it could be permisionlessly refunded\"},\"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256))\":{\"notice\":\"Initiates bridge on origin chain to be relayed by off-chain relayer\"},\"bridgeProofs(bytes32)\":{\"notice\":\"Proof of relayed bridge tx on origin chain\"},\"bridgeRelays(bytes32)\":{\"notice\":\"Whether bridge has been relayed on destination chain\"},\"bridgeStatuses(bytes32)\":{\"notice\":\"Status of the bridge tx on origin chain\"},\"canClaim(bytes32,address)\":{\"notice\":\"Checks if the dispute period has passed so bridge deposit can be claimed\"},\"chainGasAmount()\":{\"notice\":\"Chain gas amount to forward as rebate if requested\"},\"claim(bytes,address)\":{\"notice\":\"Completes bridge transaction on origin chain by claiming originally deposited capital\"},\"dispute(bytes32)\":{\"notice\":\"Disputes an outstanding proof in case relayer provided dest chain tx is invalid\"},\"getBridgeTransaction(bytes)\":{\"notice\":\"Decodes bridge request into a bridge transaction\"},\"protocolFeeRate()\":{\"notice\":\"Protocol fee rate taken on origin amount deposited in origin chain\"},\"protocolFees(address)\":{\"notice\":\"Protocol fee amounts accumulated\"},\"prove(bytes,bytes32)\":{\"notice\":\"Provides proof on origin side that relayer provided funds on destination side of bridge transaction\"},\"refund(bytes)\":{\"notice\":\"Refunds an outstanding bridge transaction in case optimistic bridging failed\"},\"relay(bytes)\":{\"notice\":\"Relays destination side of bridge transaction by off-chain relayer\"}},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeMock.sol\":\"FastBridge\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeMock.sol\":{\"keccak256\":\"0x620e81214ecd324ae8b971219291f176c454ce76fb1c01d656428096da8f1366\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://18e556772c12e13aa2d52a50cc7c48e676c8d5af22b90adaf7befb39cdd08e64\",\"dweb:/ipfs/QmPrQc98TxHCFMeuFNADyjr6Nqo52rHhHy1LBcsVdMRXjL\"]}},\"version\":1}"},"hashes":{"DEFAULT_ADMIN_ROLE()":"a217fddf","DISPUTE_PERIOD()":"a5bbe22b","FEE_BPS()":"bf333f2c","FEE_RATE_MAX()":"0f5f6ed7","GOVERNOR_ROLE()":"ccc57490","GUARD_ROLE()":"03ed0ee5","MIN_DEADLINE_PERIOD()":"820688d5","REFUNDER_ROLE()":"5960ccf2","REFUND_DELAY()":"190da595","RELAYER_ROLE()":"926d7d7f","bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256))":"45851694","bridgeProofs(bytes32)":"91ad5039","bridgeRelays(bytes32)":"8379a24f","bridgeStatuses(bytes32)":"051287bc","canClaim(bytes32,address)":"aa9641ab","chainGasAmount()":"e00a83e0","claim(bytes,address)":"41fcb612","deployBlock()":"a3ec191a","dispute(bytes32)":"add98c70","getBridgeTransaction(bytes)":"ac11fb1a","getRoleAdmin(bytes32)":"248a9ca3","getRoleMember(bytes32,uint256)":"9010d07c","getRoleMemberCount(bytes32)":"ca15c873","grantRole(bytes32,address)":"2f2ff15d","hasRole(bytes32,address)":"91d14854","nonce()":"affed0e0","protocolFeeRate()":"58f85880","protocolFees(address)":"dcf844a7","prove(bytes,bytes32)":"886d36ff","refund(bytes)":"5eb7d946","relay(bytes)":"8f0d6f17","renounceRole(bytes32,address)":"36568abe","revokeRole(bytes32,address)":"d547741f","setChainGasAmount(uint256)":"b250fe6b","setProtocolFeeRate(uint256)":"b13aa2d6","supportsInterface(bytes4)":"01ffc9a7","sweepProtocolFees(address,address)":"06f333f2"}},"solidity/FastBridgeMock.sol:FastBridgeMock":{"code":"0x60a06040523480156200001157600080fd5b506040516200254e3803806200254e833981016040819052620000349162000194565b80620000426000826200004f565b50504360805250620001bf565b6000806200005e84846200008c565b90508015620000835760008481526001602052604090206200008190846200013a565b505b90505b92915050565b6000828152602081815260408083206001600160a01b038516845290915281205460ff1662000131576000838152602081815260408083206001600160a01b03861684529091529020805460ff19166001179055620000e83390565b6001600160a01b0316826001600160a01b0316847f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a450600162000086565b50600062000086565b600062000083836001600160a01b0384166000818152600183016020526040812054620001315750815460018181018455600084815260208082209093018490558454848252828601909352604090209190915562000086565b600060208284031215620001a757600080fd5b81516001600160a01b03811681146200008357600080fd5b608051612373620001db600039600061053201526123736000f3fe6080604052600436106102345760003560e01c8063926d7d7f11610138578063b13aa2d6116100b0578063ca15c8731161007f578063d547741f11610064578063d547741f146106dd578063dcf844a7146106fd578063e00a83e01461072a57600080fd5b8063ca15c87314610689578063ccc57490146106a957600080fd5b8063b13aa2d614610612578063b250fe6b14610632578063bf333f2c14610652578063c72870cc1461066957600080fd5b8063ac11fb1a11610107578063add98c70116100ec578063add98c70146105c1578063aedf009d146105dc578063affed0e0146105fc57600080fd5b8063ac11fb1a14610574578063acaebbf1146105a157600080fd5b8063926d7d7f146104d7578063a217fddf1461050b578063a3ec191a14610520578063aa9641ab1461055457600080fd5b806345851694116101cb57806385ad903d1161019a5780638f0d6f171161017f5780638f0d6f17146104335780639010d07c1461044157806391d148541461048657600080fd5b806385ad903d146103eb578063886d36ff1461041857600080fd5b8063458516941461037857806358f85880146103865780635960ccf21461039c5780635eb7d946146103d057600080fd5b8063248a9ca311610207578063248a9ca3146102e85780632f2ff15d1461031857806336568abe1461033857806341fcb6121461035857600080fd5b806301ffc9a71461023957806303ed0ee51461026e57806306f333f2146102b05780630f5f6ed7146102d2575b600080fd5b34801561024557600080fd5b5061025961025436600461195d565b610740565b60405190151581526020015b60405180910390f35b34801561027a57600080fd5b506102a27f043c983c49d46f0e102151eaf8085d4a2e6571d5df2d47b013f39bddfd4a639d81565b604051908152602001610265565b3480156102bc57600080fd5b506102d06102cb3660046119d1565b61079c565b005b3480156102de57600080fd5b506102a261271081565b3480156102f457600080fd5b506102a2610303366004611a0a565b60009081526020819052604090206001015490565b34801561032457600080fd5b506102d0610333366004611a23565b61088a565b34801561034457600080fd5b506102d0610353366004611a23565b6108b5565b34801561036457600080fd5b506102d0610373366004611b70565b61090e565b6102d0610373366004611c90565b34801561039257600080fd5b506102a260025481565b3480156103a857600080fd5b506102a27fdb9556138406326f00296e13ea2ad7db24ba82381212d816b1a40c23b466b32781565b3480156103dc57600080fd5b506102d0610373366004611cad565b3480156103f757600080fd5b5061040b610406366004611cea565b610975565b6040516102659190611d79565b34801561042457600080fd5b506102d0610373366004611d8c565b6102d0610373366004611cad565b34801561044d57600080fd5b5061046161045c366004611dd1565b610b25565b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610265565b34801561049257600080fd5b506102596104a1366004611a23565b60009182526020828152604080842073ffffffffffffffffffffffffffffffffffffffff93909316845291905290205460ff1690565b3480156104e357600080fd5b506102a27fe2b7fb3b832174769106daebcfd6d1970523240dda11281102db9363b83b0dc481565b34801561051757600080fd5b506102a2600081565b34801561052c57600080fd5b506102a27f000000000000000000000000000000000000000000000000000000000000000081565b34801561056057600080fd5b5061025961056f366004611a23565b610b44565b34801561058057600080fd5b5061059461058f366004611cad565b610ba9565b6040516102659190611df3565b3480156105ad57600080fd5b506102d06105bc366004611f0d565b610c1c565b3480156105cd57600080fd5b506102d0610373366004611a0a565b3480156105e857600080fd5b506102d06105f7366004611f4d565b610dec565b34801561060857600080fd5b506102a260055481565b34801561061e57600080fd5b506102d061062d366004611a0a565b610e77565b34801561063e57600080fd5b506102d061064d366004611a0a565b610f54565b34801561065e57600080fd5b506102a2620f424081565b34801561067557600080fd5b506102d0610684366004611fa6565b610fbc565b34801561069557600080fd5b506102a26106a4366004611a0a565b611042565b3480156106b557600080fd5b506102a27f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f5581565b3480156106e957600080fd5b506102d06106f8366004611a23565b611059565b34801561070957600080fd5b506102a261071836600461203e565b60036020526000908152604090205481565b34801561073657600080fd5b506102a260045481565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f5a05180f00000000000000000000000000000000000000000000000000000000148061079657506107968261107e565b92915050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f556107c681611115565b73ffffffffffffffffffffffffffffffffffffffff8316600090815260036020526040812054908190036107fa5750505050565b73ffffffffffffffffffffffffffffffffffffffff841660008181526003602052604081205561082b908483611122565b6040805173ffffffffffffffffffffffffffffffffffffffff8087168252851660208201529081018290527f244e51bc38c1452fa8aaf487bcb4bca36c2baa3a5fbdb776b1eabd8dc6d277cd9060600160405180910390a1505b505050565b6000828152602081905260409020600101546108a581611115565b6108af8383611279565b50505050565b73ffffffffffffffffffffffffffffffffffffffff81163314610904576040517f6697b23200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61088582826112ae565b6040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f6e6f7420696d706c656d656e746564000000000000000000000000000000000060448201526064015b60405180910390fd5b60608160048111156109895761098961205b565b6000036109c957505060408051808201909152600481527f4e554c4c00000000000000000000000000000000000000000000000000000000602082015290565b8160048111156109db576109db61205b565b600103610a1b57505060408051808201909152600981527f5245515545535445440000000000000000000000000000000000000000000000602082015290565b816004811115610a2d57610a2d61205b565b600203610a6d57505060408051808201909152600e81527f52454c415945525f50524f564544000000000000000000000000000000000000602082015290565b816004811115610a7f57610a7f61205b565b600303610abf57505060408051808201909152600f81527f52454c415945525f434c41494d45440000000000000000000000000000000000602082015290565b816004811115610ad157610ad161205b565b600403610b1157505060408051808201909152600881527f524546554e444544000000000000000000000000000000000000000000000000602082015290565b505060408051602081019091526000815290565b6000828152600160205260408120610b3d90836112db565b9392505050565b6040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f6e6f7420696d706c656d656e7465640000000000000000000000000000000000604482015260009060640161096c565b604080516101808101825260008082526020808301829052928201819052606082018190526080820181905260a0820181905260c0820181905260e082018190526101008201819052610120820181905261014082018190526101608201528251909161079691840181019084016120ab565b6000620f42406002548360a00151610c3491906121a6565b610c3e91906121bd565b9050808260a001818151610c5291906121f8565b9150818152505060006040518061018001604052804663ffffffff168152602001846000015163ffffffff168152602001846020015173ffffffffffffffffffffffffffffffffffffffff168152602001846040015173ffffffffffffffffffffffffffffffffffffffff168152602001846060015173ffffffffffffffffffffffffffffffffffffffff168152602001846080015173ffffffffffffffffffffffffffffffffffffffff1681526020018460a0015181526020018460c0015181526020018381526020018460e0015115158152602001846101000151815260200160056000815480929190610d479061220b565b909155509052604051610d5d9190602001611df3565b6040516020818303038152906040529050826020015173ffffffffffffffffffffffffffffffffffffffff16857f120ea0364f36cdac7983bcfdd55270ca09d7f9b314a2ebc425a3b01ab1d6403a838660000151876060015188608001518960a001518a60c001518b60e00151604051610ddd9796959493929190612243565b60405180910390a35050505050565b6000610df782610ba9565b9050806040015173ffffffffffffffffffffffffffffffffffffffff16847f120ea0364f36cdac7983bcfdd55270ca09d7f9b314a2ebc425a3b01ab1d6403a84846020015185608001518660a001518760c001518860e00151896101200151604051610e699796959493929190612243565b60405180910390a350505050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f55610ea181611115565b612710821115610f0d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f6e657746656552617465203e206d617800000000000000000000000000000000604482015260640161096c565b600280549083905560408051828152602081018590527f14914da2bf76024616fbe1859783fcd4dbddcb179b1f3a854949fbf920dcb95791015b60405180910390a1505050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f55610f7e81611115565b600480549083905560408051828152602081018590527f5cf09b12f3f56b4c564d51b25b40360af6d795198adb61ae0806a36c294323fa9101610f47565b6040805163ffffffff8816815273ffffffffffffffffffffffffffffffffffffffff878116602083015286811682840152606082018690526080820185905260a082018490529151898316928b16918c917ff8ae392d784b1ea5e8881bfa586d81abf07ef4f1e2fc75f7fe51c90f05199a5c9181900360c00190a4505050505050505050565b6000818152600160205260408120610796906112e7565b60008281526020819052604090206001015461107481611115565b6108af83836112ae565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f7965db0b00000000000000000000000000000000000000000000000000000000148061079657507f01ffc9a7000000000000000000000000000000000000000000000000000000007fffffffff00000000000000000000000000000000000000000000000000000000831614610796565b61111f81336112f1565b50565b3073ffffffffffffffffffffffffffffffffffffffff83160361114457505050565b8060000361115157505050565b7fffffffffffffffffffffffff111111111111111111111111111111111111111273ffffffffffffffffffffffffffffffffffffffff8416016112585760008273ffffffffffffffffffffffffffffffffffffffff168260405160006040518083038185875af1925050503d80600081146111e8576040519150601f19603f3d011682016040523d82523d6000602084013e6111ed565b606091505b50509050806108af576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f455448207472616e73666572206661696c656400000000000000000000000000604482015260640161096c565b61088573ffffffffffffffffffffffffffffffffffffffff8416838361137b565b6000806112868484611408565b90508015610b3d5760008481526001602052604090206112a69084611504565b509392505050565b6000806112bb8484611526565b90508015610b3d5760008481526001602052604090206112a690846115e1565b6000610b3d8383611603565b6000610796825490565b60008281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915290205460ff16611377576040517fe2517d3f00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff821660048201526024810183905260440161096c565b5050565b6040805173ffffffffffffffffffffffffffffffffffffffff8416602482015260448082018490528251808303909101815260649091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fa9059cbb0000000000000000000000000000000000000000000000000000000017905261088590849061162d565b60008281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915281205460ff166114fc5760008381526020818152604080832073ffffffffffffffffffffffffffffffffffffffff86168452909152902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016600117905561149a3390565b73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16847f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a4506001610796565b506000610796565b6000610b3d8373ffffffffffffffffffffffffffffffffffffffff84166116c3565b60008281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915281205460ff16156114fc5760008381526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8616808552925280832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016905551339286917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a4506001610796565b6000610b3d8373ffffffffffffffffffffffffffffffffffffffff841661170a565b600082600001828154811061161a5761161a6122a6565b9060005260206000200154905092915050565b600061164f73ffffffffffffffffffffffffffffffffffffffff8416836117fd565b9050805160001415801561167457508080602001905181019061167291906122d5565b155b15610885576040517f5274afe700000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8416600482015260240161096c565b60008181526001830160205260408120546114fc57508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155610796565b600081815260018301602052604081205480156117f357600061172e6001836121f8565b8554909150600090611742906001906121f8565b90508082146117a7576000866000018281548110611762576117626122a6565b9060005260206000200154905080876000018481548110611785576117856122a6565b6000918252602080832090910192909255918252600188019052604090208390555b85548690806117b8576117b86122f2565b600190038181906000526020600020016000905590558560010160008681526020019081526020016000206000905560019350505050610796565b6000915050610796565b6060610b3d83836000846000808573ffffffffffffffffffffffffffffffffffffffff1684866040516118309190612321565b60006040518083038185875af1925050503d806000811461186d576040519150601f19603f3d011682016040523d82523d6000602084013e611872565b606091505b509150915061188286838361188c565b9695505050505050565b6060826118a15761189c8261191b565b610b3d565b81511580156118c5575073ffffffffffffffffffffffffffffffffffffffff84163b155b15611914576040517f9996b31500000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8516600482015260240161096c565b5080610b3d565b80511561192b5780518082602001fd5b6040517f1425ea4200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006020828403121561196f57600080fd5b81357fffffffff0000000000000000000000000000000000000000000000000000000081168114610b3d57600080fd5b73ffffffffffffffffffffffffffffffffffffffff8116811461111f57600080fd5b80356119cc8161199f565b919050565b600080604083850312156119e457600080fd5b82356119ef8161199f565b915060208301356119ff8161199f565b809150509250929050565b600060208284031215611a1c57600080fd5b5035919050565b60008060408385031215611a3657600080fd5b8235915060208301356119ff8161199f565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051610120810167ffffffffffffffff81118282101715611a9b57611a9b611a48565b60405290565b604051610180810167ffffffffffffffff81118282101715611a9b57611a9b611a48565b600082601f830112611ad657600080fd5b813567ffffffffffffffff80821115611af157611af1611a48565b604051601f83017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f01168101908282118183101715611b3757611b37611a48565b81604052838152866020858801011115611b5057600080fd5b836020870160208301376000602085830101528094505050505092915050565b60008060408385031215611b8357600080fd5b823567ffffffffffffffff811115611b9a57600080fd5b611ba685828601611ac5565b92505060208301356119ff8161199f565b63ffffffff8116811461111f57600080fd5b80356119cc81611bb7565b801515811461111f57600080fd5b80356119cc81611bd4565b60006101208284031215611c0057600080fd5b611c08611a77565b9050611c1382611bc9565b8152611c21602083016119c1565b6020820152611c32604083016119c1565b6040820152611c43606083016119c1565b6060820152611c54608083016119c1565b608082015260a082013560a082015260c082013560c0820152611c7960e08301611be2565b60e082015261010080830135818301525092915050565b60006101208284031215611ca357600080fd5b610b3d8383611bed565b600060208284031215611cbf57600080fd5b813567ffffffffffffffff811115611cd657600080fd5b611ce284828501611ac5565b949350505050565b600060208284031215611cfc57600080fd5b813560058110610b3d57600080fd5b60005b83811015611d26578181015183820152602001611d0e565b50506000910152565b60008151808452611d47816020860160208601611d0b565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b602081526000610b3d6020830184611d2f565b60008060408385031215611d9f57600080fd5b823567ffffffffffffffff811115611db657600080fd5b611dc285828601611ac5565b95602094909401359450505050565b60008060408385031215611de457600080fd5b50508035926020909101359150565b815163ffffffff16815261018081016020830151611e19602084018263ffffffff169052565b506040830151611e41604084018273ffffffffffffffffffffffffffffffffffffffff169052565b506060830151611e69606084018273ffffffffffffffffffffffffffffffffffffffff169052565b506080830151611e91608084018273ffffffffffffffffffffffffffffffffffffffff169052565b5060a0830151611eb960a084018273ffffffffffffffffffffffffffffffffffffffff169052565b5060c083015160c083015260e083015160e083015261010080840151818401525061012080840151611eee8285018215159052565b5050610140838101519083015261016092830151929091019190915290565b60008060006101608486031215611f2357600080fd5b833592506020840135611f358161199f565b9150611f448560408601611bed565b90509250925092565b600080600060608486031215611f6257600080fd5b833592506020840135611f748161199f565b9150604084013567ffffffffffffffff811115611f9057600080fd5b611f9c86828701611ac5565b9150509250925092565b60008060008060008060008060006101208a8c031215611fc557600080fd5b8935985060208a0135611fd78161199f565b975060408a0135611fe78161199f565b965060608a0135611ff781611bb7565b955060808a01356120078161199f565b945060a08a01356120178161199f565b8094505060c08a0135925060e08a013591506101008a013590509295985092959850929598565b60006020828403121561205057600080fd5b8135610b3d8161199f565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b80516119cc81611bb7565b80516119cc8161199f565b80516119cc81611bd4565b600061018082840312156120be57600080fd5b6120c6611aa1565b6120cf8361208a565b81526120dd6020840161208a565b60208201526120ee60408401612095565b60408201526120ff60608401612095565b606082015261211060808401612095565b608082015261212160a08401612095565b60a082015260c083015160c082015260e083015160e08201526101008084015181830152506101206121548185016120a0565b908201526101408381015190820152610160928301519281019290925250919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b808202811582820484141761079657610796612177565b6000826121f3577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b8181038181111561079657610796612177565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820361223c5761223c612177565b5060010190565b60e08152600061225660e083018a611d2f565b63ffffffff9890981660208301525073ffffffffffffffffffffffffffffffffffffffff9586166040820152939094166060840152608083019190915260a082015290151560c090910152919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b6000602082840312156122e757600080fd5b8151610b3d81611bd4565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fd5b60008251612333818460208701611d0b565b919091019291505056fea2646970667358221220b683b83c62d39501bf0f8c7280114538e17cdaba91a577c85b1d7b2b6a51230c64736f6c63430008140033","runtime-code":"0x6080604052600436106102345760003560e01c8063926d7d7f11610138578063b13aa2d6116100b0578063ca15c8731161007f578063d547741f11610064578063d547741f146106dd578063dcf844a7146106fd578063e00a83e01461072a57600080fd5b8063ca15c87314610689578063ccc57490146106a957600080fd5b8063b13aa2d614610612578063b250fe6b14610632578063bf333f2c14610652578063c72870cc1461066957600080fd5b8063ac11fb1a11610107578063add98c70116100ec578063add98c70146105c1578063aedf009d146105dc578063affed0e0146105fc57600080fd5b8063ac11fb1a14610574578063acaebbf1146105a157600080fd5b8063926d7d7f146104d7578063a217fddf1461050b578063a3ec191a14610520578063aa9641ab1461055457600080fd5b806345851694116101cb57806385ad903d1161019a5780638f0d6f171161017f5780638f0d6f17146104335780639010d07c1461044157806391d148541461048657600080fd5b806385ad903d146103eb578063886d36ff1461041857600080fd5b8063458516941461037857806358f85880146103865780635960ccf21461039c5780635eb7d946146103d057600080fd5b8063248a9ca311610207578063248a9ca3146102e85780632f2ff15d1461031857806336568abe1461033857806341fcb6121461035857600080fd5b806301ffc9a71461023957806303ed0ee51461026e57806306f333f2146102b05780630f5f6ed7146102d2575b600080fd5b34801561024557600080fd5b5061025961025436600461195d565b610740565b60405190151581526020015b60405180910390f35b34801561027a57600080fd5b506102a27f043c983c49d46f0e102151eaf8085d4a2e6571d5df2d47b013f39bddfd4a639d81565b604051908152602001610265565b3480156102bc57600080fd5b506102d06102cb3660046119d1565b61079c565b005b3480156102de57600080fd5b506102a261271081565b3480156102f457600080fd5b506102a2610303366004611a0a565b60009081526020819052604090206001015490565b34801561032457600080fd5b506102d0610333366004611a23565b61088a565b34801561034457600080fd5b506102d0610353366004611a23565b6108b5565b34801561036457600080fd5b506102d0610373366004611b70565b61090e565b6102d0610373366004611c90565b34801561039257600080fd5b506102a260025481565b3480156103a857600080fd5b506102a27fdb9556138406326f00296e13ea2ad7db24ba82381212d816b1a40c23b466b32781565b3480156103dc57600080fd5b506102d0610373366004611cad565b3480156103f757600080fd5b5061040b610406366004611cea565b610975565b6040516102659190611d79565b34801561042457600080fd5b506102d0610373366004611d8c565b6102d0610373366004611cad565b34801561044d57600080fd5b5061046161045c366004611dd1565b610b25565b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610265565b34801561049257600080fd5b506102596104a1366004611a23565b60009182526020828152604080842073ffffffffffffffffffffffffffffffffffffffff93909316845291905290205460ff1690565b3480156104e357600080fd5b506102a27fe2b7fb3b832174769106daebcfd6d1970523240dda11281102db9363b83b0dc481565b34801561051757600080fd5b506102a2600081565b34801561052c57600080fd5b506102a27f000000000000000000000000000000000000000000000000000000000000000081565b34801561056057600080fd5b5061025961056f366004611a23565b610b44565b34801561058057600080fd5b5061059461058f366004611cad565b610ba9565b6040516102659190611df3565b3480156105ad57600080fd5b506102d06105bc366004611f0d565b610c1c565b3480156105cd57600080fd5b506102d0610373366004611a0a565b3480156105e857600080fd5b506102d06105f7366004611f4d565b610dec565b34801561060857600080fd5b506102a260055481565b34801561061e57600080fd5b506102d061062d366004611a0a565b610e77565b34801561063e57600080fd5b506102d061064d366004611a0a565b610f54565b34801561065e57600080fd5b506102a2620f424081565b34801561067557600080fd5b506102d0610684366004611fa6565b610fbc565b34801561069557600080fd5b506102a26106a4366004611a0a565b611042565b3480156106b557600080fd5b506102a27f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f5581565b3480156106e957600080fd5b506102d06106f8366004611a23565b611059565b34801561070957600080fd5b506102a261071836600461203e565b60036020526000908152604090205481565b34801561073657600080fd5b506102a260045481565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f5a05180f00000000000000000000000000000000000000000000000000000000148061079657506107968261107e565b92915050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f556107c681611115565b73ffffffffffffffffffffffffffffffffffffffff8316600090815260036020526040812054908190036107fa5750505050565b73ffffffffffffffffffffffffffffffffffffffff841660008181526003602052604081205561082b908483611122565b6040805173ffffffffffffffffffffffffffffffffffffffff8087168252851660208201529081018290527f244e51bc38c1452fa8aaf487bcb4bca36c2baa3a5fbdb776b1eabd8dc6d277cd9060600160405180910390a1505b505050565b6000828152602081905260409020600101546108a581611115565b6108af8383611279565b50505050565b73ffffffffffffffffffffffffffffffffffffffff81163314610904576040517f6697b23200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61088582826112ae565b6040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f6e6f7420696d706c656d656e746564000000000000000000000000000000000060448201526064015b60405180910390fd5b60608160048111156109895761098961205b565b6000036109c957505060408051808201909152600481527f4e554c4c00000000000000000000000000000000000000000000000000000000602082015290565b8160048111156109db576109db61205b565b600103610a1b57505060408051808201909152600981527f5245515545535445440000000000000000000000000000000000000000000000602082015290565b816004811115610a2d57610a2d61205b565b600203610a6d57505060408051808201909152600e81527f52454c415945525f50524f564544000000000000000000000000000000000000602082015290565b816004811115610a7f57610a7f61205b565b600303610abf57505060408051808201909152600f81527f52454c415945525f434c41494d45440000000000000000000000000000000000602082015290565b816004811115610ad157610ad161205b565b600403610b1157505060408051808201909152600881527f524546554e444544000000000000000000000000000000000000000000000000602082015290565b505060408051602081019091526000815290565b6000828152600160205260408120610b3d90836112db565b9392505050565b6040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f6e6f7420696d706c656d656e7465640000000000000000000000000000000000604482015260009060640161096c565b604080516101808101825260008082526020808301829052928201819052606082018190526080820181905260a0820181905260c0820181905260e082018190526101008201819052610120820181905261014082018190526101608201528251909161079691840181019084016120ab565b6000620f42406002548360a00151610c3491906121a6565b610c3e91906121bd565b9050808260a001818151610c5291906121f8565b9150818152505060006040518061018001604052804663ffffffff168152602001846000015163ffffffff168152602001846020015173ffffffffffffffffffffffffffffffffffffffff168152602001846040015173ffffffffffffffffffffffffffffffffffffffff168152602001846060015173ffffffffffffffffffffffffffffffffffffffff168152602001846080015173ffffffffffffffffffffffffffffffffffffffff1681526020018460a0015181526020018460c0015181526020018381526020018460e0015115158152602001846101000151815260200160056000815480929190610d479061220b565b909155509052604051610d5d9190602001611df3565b6040516020818303038152906040529050826020015173ffffffffffffffffffffffffffffffffffffffff16857f120ea0364f36cdac7983bcfdd55270ca09d7f9b314a2ebc425a3b01ab1d6403a838660000151876060015188608001518960a001518a60c001518b60e00151604051610ddd9796959493929190612243565b60405180910390a35050505050565b6000610df782610ba9565b9050806040015173ffffffffffffffffffffffffffffffffffffffff16847f120ea0364f36cdac7983bcfdd55270ca09d7f9b314a2ebc425a3b01ab1d6403a84846020015185608001518660a001518760c001518860e00151896101200151604051610e699796959493929190612243565b60405180910390a350505050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f55610ea181611115565b612710821115610f0d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f6e657746656552617465203e206d617800000000000000000000000000000000604482015260640161096c565b600280549083905560408051828152602081018590527f14914da2bf76024616fbe1859783fcd4dbddcb179b1f3a854949fbf920dcb95791015b60405180910390a1505050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f55610f7e81611115565b600480549083905560408051828152602081018590527f5cf09b12f3f56b4c564d51b25b40360af6d795198adb61ae0806a36c294323fa9101610f47565b6040805163ffffffff8816815273ffffffffffffffffffffffffffffffffffffffff878116602083015286811682840152606082018690526080820185905260a082018490529151898316928b16918c917ff8ae392d784b1ea5e8881bfa586d81abf07ef4f1e2fc75f7fe51c90f05199a5c9181900360c00190a4505050505050505050565b6000818152600160205260408120610796906112e7565b60008281526020819052604090206001015461107481611115565b6108af83836112ae565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f7965db0b00000000000000000000000000000000000000000000000000000000148061079657507f01ffc9a7000000000000000000000000000000000000000000000000000000007fffffffff00000000000000000000000000000000000000000000000000000000831614610796565b61111f81336112f1565b50565b3073ffffffffffffffffffffffffffffffffffffffff83160361114457505050565b8060000361115157505050565b7fffffffffffffffffffffffff111111111111111111111111111111111111111273ffffffffffffffffffffffffffffffffffffffff8416016112585760008273ffffffffffffffffffffffffffffffffffffffff168260405160006040518083038185875af1925050503d80600081146111e8576040519150601f19603f3d011682016040523d82523d6000602084013e6111ed565b606091505b50509050806108af576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f455448207472616e73666572206661696c656400000000000000000000000000604482015260640161096c565b61088573ffffffffffffffffffffffffffffffffffffffff8416838361137b565b6000806112868484611408565b90508015610b3d5760008481526001602052604090206112a69084611504565b509392505050565b6000806112bb8484611526565b90508015610b3d5760008481526001602052604090206112a690846115e1565b6000610b3d8383611603565b6000610796825490565b60008281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915290205460ff16611377576040517fe2517d3f00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff821660048201526024810183905260440161096c565b5050565b6040805173ffffffffffffffffffffffffffffffffffffffff8416602482015260448082018490528251808303909101815260649091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fa9059cbb0000000000000000000000000000000000000000000000000000000017905261088590849061162d565b60008281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915281205460ff166114fc5760008381526020818152604080832073ffffffffffffffffffffffffffffffffffffffff86168452909152902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016600117905561149a3390565b73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16847f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a4506001610796565b506000610796565b6000610b3d8373ffffffffffffffffffffffffffffffffffffffff84166116c3565b60008281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915281205460ff16156114fc5760008381526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8616808552925280832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016905551339286917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a4506001610796565b6000610b3d8373ffffffffffffffffffffffffffffffffffffffff841661170a565b600082600001828154811061161a5761161a6122a6565b9060005260206000200154905092915050565b600061164f73ffffffffffffffffffffffffffffffffffffffff8416836117fd565b9050805160001415801561167457508080602001905181019061167291906122d5565b155b15610885576040517f5274afe700000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8416600482015260240161096c565b60008181526001830160205260408120546114fc57508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155610796565b600081815260018301602052604081205480156117f357600061172e6001836121f8565b8554909150600090611742906001906121f8565b90508082146117a7576000866000018281548110611762576117626122a6565b9060005260206000200154905080876000018481548110611785576117856122a6565b6000918252602080832090910192909255918252600188019052604090208390555b85548690806117b8576117b86122f2565b600190038181906000526020600020016000905590558560010160008681526020019081526020016000206000905560019350505050610796565b6000915050610796565b6060610b3d83836000846000808573ffffffffffffffffffffffffffffffffffffffff1684866040516118309190612321565b60006040518083038185875af1925050503d806000811461186d576040519150601f19603f3d011682016040523d82523d6000602084013e611872565b606091505b509150915061188286838361188c565b9695505050505050565b6060826118a15761189c8261191b565b610b3d565b81511580156118c5575073ffffffffffffffffffffffffffffffffffffffff84163b155b15611914576040517f9996b31500000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8516600482015260240161096c565b5080610b3d565b80511561192b5780518082602001fd5b6040517f1425ea4200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006020828403121561196f57600080fd5b81357fffffffff0000000000000000000000000000000000000000000000000000000081168114610b3d57600080fd5b73ffffffffffffffffffffffffffffffffffffffff8116811461111f57600080fd5b80356119cc8161199f565b919050565b600080604083850312156119e457600080fd5b82356119ef8161199f565b915060208301356119ff8161199f565b809150509250929050565b600060208284031215611a1c57600080fd5b5035919050565b60008060408385031215611a3657600080fd5b8235915060208301356119ff8161199f565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051610120810167ffffffffffffffff81118282101715611a9b57611a9b611a48565b60405290565b604051610180810167ffffffffffffffff81118282101715611a9b57611a9b611a48565b600082601f830112611ad657600080fd5b813567ffffffffffffffff80821115611af157611af1611a48565b604051601f83017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f01168101908282118183101715611b3757611b37611a48565b81604052838152866020858801011115611b5057600080fd5b836020870160208301376000602085830101528094505050505092915050565b60008060408385031215611b8357600080fd5b823567ffffffffffffffff811115611b9a57600080fd5b611ba685828601611ac5565b92505060208301356119ff8161199f565b63ffffffff8116811461111f57600080fd5b80356119cc81611bb7565b801515811461111f57600080fd5b80356119cc81611bd4565b60006101208284031215611c0057600080fd5b611c08611a77565b9050611c1382611bc9565b8152611c21602083016119c1565b6020820152611c32604083016119c1565b6040820152611c43606083016119c1565b6060820152611c54608083016119c1565b608082015260a082013560a082015260c082013560c0820152611c7960e08301611be2565b60e082015261010080830135818301525092915050565b60006101208284031215611ca357600080fd5b610b3d8383611bed565b600060208284031215611cbf57600080fd5b813567ffffffffffffffff811115611cd657600080fd5b611ce284828501611ac5565b949350505050565b600060208284031215611cfc57600080fd5b813560058110610b3d57600080fd5b60005b83811015611d26578181015183820152602001611d0e565b50506000910152565b60008151808452611d47816020860160208601611d0b565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b602081526000610b3d6020830184611d2f565b60008060408385031215611d9f57600080fd5b823567ffffffffffffffff811115611db657600080fd5b611dc285828601611ac5565b95602094909401359450505050565b60008060408385031215611de457600080fd5b50508035926020909101359150565b815163ffffffff16815261018081016020830151611e19602084018263ffffffff169052565b506040830151611e41604084018273ffffffffffffffffffffffffffffffffffffffff169052565b506060830151611e69606084018273ffffffffffffffffffffffffffffffffffffffff169052565b506080830151611e91608084018273ffffffffffffffffffffffffffffffffffffffff169052565b5060a0830151611eb960a084018273ffffffffffffffffffffffffffffffffffffffff169052565b5060c083015160c083015260e083015160e083015261010080840151818401525061012080840151611eee8285018215159052565b5050610140838101519083015261016092830151929091019190915290565b60008060006101608486031215611f2357600080fd5b833592506020840135611f358161199f565b9150611f448560408601611bed565b90509250925092565b600080600060608486031215611f6257600080fd5b833592506020840135611f748161199f565b9150604084013567ffffffffffffffff811115611f9057600080fd5b611f9c86828701611ac5565b9150509250925092565b60008060008060008060008060006101208a8c031215611fc557600080fd5b8935985060208a0135611fd78161199f565b975060408a0135611fe78161199f565b965060608a0135611ff781611bb7565b955060808a01356120078161199f565b945060a08a01356120178161199f565b8094505060c08a0135925060e08a013591506101008a013590509295985092959850929598565b60006020828403121561205057600080fd5b8135610b3d8161199f565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b80516119cc81611bb7565b80516119cc8161199f565b80516119cc81611bd4565b600061018082840312156120be57600080fd5b6120c6611aa1565b6120cf8361208a565b81526120dd6020840161208a565b60208201526120ee60408401612095565b60408201526120ff60608401612095565b606082015261211060808401612095565b608082015261212160a08401612095565b60a082015260c083015160c082015260e083015160e08201526101008084015181830152506101206121548185016120a0565b908201526101408381015190820152610160928301519281019290925250919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b808202811582820484141761079657610796612177565b6000826121f3577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b8181038181111561079657610796612177565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820361223c5761223c612177565b5060010190565b60e08152600061225660e083018a611d2f565b63ffffffff9890981660208301525073ffffffffffffffffffffffffffffffffffffffff9586166040820152939094166060840152608083019190915260a082015290151560c090910152919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b6000602082840312156122e757600080fd5b8151610b3d81611bd4565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fd5b60008251612333818460208701611d0b565b919091019291505056fea2646970667358221220b683b83c62d39501bf0f8c7280114538e17cdaba91a577c85b1d7b2b6a51230c64736f6c63430008140033","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.20 ^0.8.20;\n\n// contracts/interfaces/IAdmin.sol\n\ninterface IAdmin {\n // ============ Events ============\n\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n event ChainGasAmountUpdated(uint256 oldChainGasAmount, uint256 newChainGasAmount);\n\n // ============ Methods ============\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n\n function setChainGasAmount(uint256 newChainGasAmount) external;\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/libs/Errors.sol\n\nerror DeadlineExceeded();\nerror DeadlineNotExceeded();\nerror DeadlineTooShort();\nerror InsufficientOutputAmount();\n\nerror MsgValueIncorrect();\nerror PoolNotFound();\nerror TokenAddressMismatch();\nerror TokenNotContract();\nerror TokenNotETH();\nerror TokensIdentical();\n\nerror ChainIncorrect();\nerror AmountIncorrect();\nerror ZeroAddress();\n\nerror DisputePeriodNotPassed();\nerror DisputePeriodPassed();\nerror SenderIncorrect();\nerror StatusIncorrect();\nerror TransactionIdIncorrect();\nerror TransactionRelayed();\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// contracts/libs/UniversalToken.sol\n\nlibrary UniversalTokenLib {\n using SafeERC20 for IERC20;\n\n address internal constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Transfers tokens to the given account. Reverts if transfer is not successful.\n /// @dev This might trigger fallback, if ETH is transferred to the contract.\n /// Make sure this can not lead to reentrancy attacks.\n function universalTransfer(address token, address to, uint256 value) internal {\n // Don't do anything, if need to send tokens to this address\n if (to == address(this)) return;\n // Don't do anything, if trying to send zero value\n if (value == 0) return;\n if (token == ETH_ADDRESS) {\n /// @dev Note: this can potentially lead to executing code in `to`.\n // solhint-disable-next-line avoid-low-level-calls\n (bool success,) = to.call{value: value}(\"\");\n require(success, \"ETH transfer failed\");\n } else {\n IERC20(token).safeTransfer(to, value);\n }\n }\n\n /// @notice Issues an infinite allowance to the spender, if the current allowance is insufficient\n /// to spend the given amount.\n function universalApproveInfinity(address token, address spender, uint256 amountToSpend) internal {\n // ETH Chad doesn't require your approval\n if (token == ETH_ADDRESS) return;\n // No-op if allowance is already sufficient\n uint256 allowance = IERC20(token).allowance(address(this), spender);\n if (allowance \u003e= amountToSpend) return;\n // Otherwise, reset approval to 0 and set to max allowance\n if (allowance \u003e 0) IERC20(token).safeDecreaseAllowance(spender, allowance);\n IERC20(token).safeIncreaseAllowance(spender, type(uint256).max);\n }\n\n /// @notice Returns the balance of the given token (or native ETH) for the given account.\n function universalBalanceOf(address token, address account) internal view returns (uint256) {\n if (token == ETH_ADDRESS) {\n return account.balance;\n } else {\n return IERC20(token).balanceOf(account);\n }\n }\n\n /// @dev Checks that token is a contract and not ETH_ADDRESS.\n function assertIsContract(address token) internal view {\n // Check that ETH_ADDRESS was not used (in case this is a predeploy on any of the chains)\n if (token == UniversalTokenLib.ETH_ADDRESS) revert TokenNotContract();\n // Check that token is not an EOA\n if (token.code.length == 0) revert TokenNotContract();\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/Admin.sol\n\ncontract Admin is IAdmin, AccessControlEnumerable {\n using UniversalTokenLib for address;\n\n bytes32 public constant RELAYER_ROLE = keccak256(\"RELAYER_ROLE\");\n bytes32 public constant REFUNDER_ROLE = keccak256(\"REFUNDER_ROLE\");\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n uint256 public constant FEE_BPS = 1e6;\n uint256 public constant FEE_RATE_MAX = 0.01e6; // max 1% on origin amount\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Chain gas amount to forward as rebate if requested\n uint256 public chainGasAmount;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n }\n\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n require(newFeeRate \u003c= FEE_RATE_MAX, \"newFeeRate \u003e max\");\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n token.universalTransfer(recipient, feeAmount);\n emit FeesSwept(token, recipient, feeAmount);\n }\n\n function setChainGasAmount(uint256 newChainGasAmount) external onlyRole(GOVERNOR_ROLE) {\n uint256 oldChainGasAmount = chainGasAmount;\n chainGasAmount = newChainGasAmount;\n emit ChainGasAmountUpdated(oldChainGasAmount, newChainGasAmount);\n }\n}\n\n// contracts/FastBridge.sol\n\ncontract FastBridge is IFastBridge, Admin {\n using SafeERC20 for IERC20;\n using UniversalTokenLib for address;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Delay for a transaction after which it could be permisionlessly refunded\n uint256 public constant REFUND_DELAY = 7 days;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeStatus) public bridgeStatuses;\n /// @notice Proof of relayed bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeProof) public bridgeProofs;\n /// @notice Whether bridge has been relayed on destination chain\n mapping(bytes32 =\u003e bool) public bridgeRelays;\n\n /// @dev to prevent replays\n uint256 public nonce;\n // @dev the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @notice Pulls a requested token from the user to the requested recipient.\n /// @dev Be careful of re-entrancy issues when msg.value \u003e 0 and recipient != address(this)\n function _pullToken(address recipient, address token, uint256 amount) internal returns (uint256 amountPulled) {\n if (token != UniversalTokenLib.ETH_ADDRESS) {\n token.assertIsContract();\n // Record token balance before transfer\n amountPulled = IERC20(token).balanceOf(recipient);\n // Token needs to be pulled only if msg.value is zero\n // This way user can specify WETH as the origin asset\n IERC20(token).safeTransferFrom(msg.sender, recipient, amount);\n // Use the difference between the recorded balance and the current balance as the amountPulled\n amountPulled = IERC20(token).balanceOf(recipient) - amountPulled;\n } else {\n // Otherwise, we need to check that ETH amount matches msg.value\n if (amount != msg.value) revert MsgValueIncorrect();\n // Transfer value to recipient if not this address\n if (recipient != address(this)) token.universalTransfer(recipient, amount);\n // We will forward msg.value in the external call later, if recipient is not this contract\n amountPulled = msg.value;\n }\n }\n\n /// @inheritdoc IFastBridge\n function getBridgeTransaction(bytes memory request) public pure returns (BridgeTransaction memory) {\n return abi.decode(request, (BridgeTransaction));\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n // check bridge params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n\n // transfer tokens to bridge contract\n // @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _pullToken(address(this), params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n\n // set status to requested\n bytes memory request = abi.encode(\n BridgeTransaction({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n sendChainGas: params.sendChainGas,\n deadline: params.deadline,\n nonce: nonce++ // increment nonce on every bridge\n })\n );\n bytes32 transactionId = keccak256(request);\n bridgeStatuses[transactionId] = BridgeStatus.REQUESTED;\n\n emit BridgeRequested(\n transactionId,\n params.sender,\n request,\n params.dstChainId,\n params.originToken,\n params.destToken,\n originAmount,\n params.destAmount,\n params.sendChainGas\n );\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes memory request) external payable onlyRole(RELAYER_ROLE) {\n bytes32 transactionId = keccak256(request);\n BridgeTransaction memory transaction = getBridgeTransaction(request);\n if (transaction.destChainId != uint32(block.chainid)) revert ChainIncorrect();\n\n // check haven't exceeded deadline for relay to happen\n if (block.timestamp \u003e transaction.deadline) revert DeadlineExceeded();\n\n // mark bridge transaction as relayed\n if (bridgeRelays[transactionId]) revert TransactionRelayed();\n bridgeRelays[transactionId] = true;\n\n // transfer tokens to recipient on destination chain and gas rebate if requested\n address to = transaction.destRecipient;\n address token = transaction.destToken;\n uint256 amount = transaction.destAmount;\n\n uint256 rebate = chainGasAmount;\n if (!transaction.sendChainGas) {\n // forward erc20\n rebate = 0;\n _pullToken(to, token, amount);\n } else if (token == UniversalTokenLib.ETH_ADDRESS) {\n // lump in gas rebate into amount in native gas token\n _pullToken(to, token, amount + rebate);\n } else {\n // forward erc20 then forward gas rebate in native gas token\n _pullToken(to, token, amount);\n _pullToken(to, UniversalTokenLib.ETH_ADDRESS, rebate);\n }\n\n emit BridgeRelayed(\n transactionId,\n msg.sender,\n to,\n transaction.originChainId,\n transaction.originToken,\n transaction.destToken,\n transaction.originAmount,\n transaction.destAmount,\n rebate\n );\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes memory request, bytes32 destTxHash) external onlyRole(RELAYER_ROLE) {\n bytes32 transactionId = keccak256(request);\n // update bridge tx status given proof provided\n if (bridgeStatuses[transactionId] != BridgeStatus.REQUESTED) revert StatusIncorrect();\n bridgeStatuses[transactionId] = BridgeStatus.RELAYER_PROVED;\n bridgeProofs[transactionId] = BridgeProof({timestamp: uint96(block.timestamp), relayer: msg.sender}); // overflow ok\n\n emit BridgeProofProvided(transactionId, msg.sender, destTxHash);\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint96(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint96).max but\n /// proof.timestamp \u003c type(uint96).max via unchecked statement\n /// @param proof The bridge proof\n /// @return delta Time delta since proof submitted\n function _timeSince(BridgeProof memory proof) internal view returns (uint256 delta) {\n unchecked {\n delta = uint96(block.timestamp) - proof.timestamp;\n }\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n if (bridgeStatuses[transactionId] != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n BridgeProof memory proof = bridgeProofs[transactionId];\n if (proof.relayer != relayer) revert SenderIncorrect();\n return _timeSince(proof) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes memory request, address to) external onlyRole(RELAYER_ROLE) {\n bytes32 transactionId = keccak256(request);\n BridgeTransaction memory transaction = getBridgeTransaction(request);\n\n // update bridge tx status if able to claim origin collateral\n if (bridgeStatuses[transactionId] != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n\n BridgeProof memory proof = bridgeProofs[transactionId];\n if (proof.relayer != msg.sender) revert SenderIncorrect();\n if (_timeSince(proof) \u003c= DISPUTE_PERIOD) revert DisputePeriodNotPassed();\n\n bridgeStatuses[transactionId] = BridgeStatus.RELAYER_CLAIMED;\n\n // update protocol fees if origin fee amount exists\n if (transaction.originFeeAmount \u003e 0) protocolFees[transaction.originToken] += transaction.originFeeAmount;\n\n // transfer origin collateral less fee to specified address\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositClaimed(transactionId, msg.sender, to, token, amount);\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n if (bridgeStatuses[transactionId] != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(bridgeProofs[transactionId]) \u003e DISPUTE_PERIOD) revert DisputePeriodPassed();\n\n // @dev relayer gets slashed effectively if dest relay has gone thru\n bridgeStatuses[transactionId] = BridgeStatus.REQUESTED;\n delete bridgeProofs[transactionId];\n\n emit BridgeProofDisputed(transactionId, msg.sender);\n }\n\n /// @inheritdoc IFastBridge\n function refund(bytes memory request) external {\n bytes32 transactionId = keccak256(request);\n BridgeTransaction memory transaction = getBridgeTransaction(request);\n\n if (hasRole(REFUNDER_ROLE, msg.sender)) {\n // Refunder can refund if deadline has passed\n if (block.timestamp \u003c= transaction.deadline) revert DeadlineNotExceeded();\n } else {\n // Permissionless refund is allowed after REFUND_DELAY\n if (block.timestamp \u003c= transaction.deadline + REFUND_DELAY) revert DeadlineNotExceeded();\n }\n\n // set status to refunded if still in requested state\n if (bridgeStatuses[transactionId] != BridgeStatus.REQUESTED) revert StatusIncorrect();\n bridgeStatuses[transactionId] = BridgeStatus.REFUNDED;\n\n // transfer origin collateral back to original sender\n address to = transaction.originSender;\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount + transaction.originFeeAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n }\n}\n\n// test/FastBridgeMock.sol\n\ncontract FastBridgeMock is IFastBridge, Admin {\n // @dev the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @dev to prevent replays\n uint256 public nonce;\n\n function getBridgeTransaction(bytes memory request) public pure returns (BridgeTransaction memory) {\n return abi.decode(request, (BridgeTransaction));\n }\n\n // used for testing in go.\n // see: https://ethereum.stackexchange.com/questions/21155/how-to-expose-enum-in-solidity-contract\n // make sure to update fastbridge/status.go if this changes\n // or underliyng enum changes.\n //\n // TODO: a foundry test should be added to ensure this is always in sync.\n function getEnumKeyByValue(FastBridge.BridgeStatus keyValue) public pure returns (string memory) {\n if (FastBridge.BridgeStatus.NULL == keyValue) return \"NULL\";\n if (FastBridge.BridgeStatus.REQUESTED == keyValue) return \"REQUESTED\";\n if (FastBridge.BridgeStatus.RELAYER_PROVED == keyValue) return \"RELAYER_PROVED\";\n if (FastBridge.BridgeStatus.RELAYER_CLAIMED == keyValue) return \"RELAYER_CLAIMED\";\n if (FastBridge.BridgeStatus.REFUNDED == keyValue) return \"REFUNDED\";\n return \"\";\n }\n\n function mockBridgeRequest(bytes32 transactionId, address sender, BridgeParams memory params) external {\n uint256 originFeeAmount = (params.originAmount * protocolFeeRate) / FEE_BPS;\n params.originAmount -= originFeeAmount;\n\n bytes memory request = abi.encode(\n BridgeTransaction({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: params.originAmount, // includes relayer fee\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n sendChainGas: params.sendChainGas,\n deadline: params.deadline,\n nonce: nonce++ // increment nonce on every bridge\n })\n );\n\n emit BridgeRequested(\n transactionId,\n params.sender,\n request,\n params.dstChainId,\n params.originToken,\n params.destToken,\n params.originAmount,\n params.destAmount,\n params.sendChainGas\n );\n }\n\n function mockBridgeRequestRaw(bytes32 transactionId, address sender, bytes memory request) external {\n BridgeTransaction memory transaction = getBridgeTransaction(request);\n emit BridgeRequested(\n transactionId,\n transaction.originSender,\n request,\n transaction.destChainId,\n transaction.originToken,\n transaction.destToken,\n transaction.originAmount,\n transaction.destAmount,\n transaction.sendChainGas\n );\n }\n\n function mockBridgeRelayer(\n bytes32 transactionId,\n address relayer,\n address to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n )\n external\n {\n emit BridgeRelayed(\n transactionId, relayer, to, originChainId, originToken, destToken, originAmount, destAmount, chainGasAmount\n );\n }\n\n function bridge(BridgeParams memory params) external payable {\n revert(\"not implemented\");\n }\n\n function relay(bytes memory request) external payable {\n revert(\"not implemented\");\n }\n\n function prove(bytes memory request, bytes32 destTxHash) external {\n revert(\"not implemented\");\n }\n\n function canClaim(bytes32 transactionid, address relayer) external view returns (bool) {\n revert(\"not implemented\");\n }\n\n function claim(bytes memory request, address to) external {\n revert(\"not implemented\");\n }\n\n function dispute(bytes32 transactionId) external {\n revert(\"not implemented\");\n }\n\n function refund(bytes memory request) external {\n revert(\"not implemented\");\n }\n}\n","language":"Solidity","languageVersion":"0.8.20","compilerVersion":"0.8.20","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"69523:4359:0:-:0;;;69669:85;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;69703:6;57180:38;46352:4;69703:6;57180:10;:38::i;:::-;-1:-1:-1;;69735:12:0::1;69721:26;::::0;-1:-1:-1;69523:4359:0;;55665:257;55751:4;;55782:31;55799:4;55805:7;55782:16;:31::i;:::-;55767:46;;55827:7;55823:69;;;55850:18;;;;:12;:18;;;;;:31;;55873:7;55850:22;:31::i;:::-;;55823:69;55908:7;-1:-1:-1;55665:257:0;;;;;:::o;50299:316::-;50376:4;47074:12;;;;;;;;;;;-1:-1:-1;;;;;47074:29:0;;;;;;;;;;;;50392:217;;50435:6;:12;;;;;;;;;;;-1:-1:-1;;;;;50435:29:0;;;;;;;;;:36;;-1:-1:-1;;50435:36:0;50467:4;50435:36;;;50517:12;22395:10;;22316:96;50517:12;-1:-1:-1;;;;;50490:40:0;50508:7;-1:-1:-1;;;;;50490:40:0;50502:4;50490:40;;;;;;;;;;-1:-1:-1;50551:4:0;50544:11;;50392:217;-1:-1:-1;50593:5:0;50586:12;;31840:150;31910:4;31933:50;31938:3;-1:-1:-1;;;;;31958:23:0;;25828:4;27884:21;;;:14;;;:21;;;;;;25844:321;;-1:-1:-1;25886:23:0;;;;;;;;:11;:23;;;;;;;;;;;;;26068:18;;26044:21;;;:14;;;:21;;;;;;:42;;;;26100:11;;14:290:1;84:6;137:2;125:9;116:7;112:23;108:32;105:52;;;153:1;150;143:12;105:52;179:16;;-1:-1:-1;;;;;224:31:1;;214:42;;204:70;;270:1;267;260:12;14:290;69523:4359:0;;;;;;;;;;;;","srcMapRuntime":"69523:4359:0:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;54325:212;;;;;;;;;;-1:-1:-1;54325:212:0;;;;;:::i;:::-;;:::i;:::-;;;612:14:1;;605:22;587:41;;575:2;560:18;54325:212:0;;;;;;;;56555:60;;;;;;;;;;;;56592:23;56555:60;;;;;785:25:1;;;773:2;758:18;56555:60:0;639:177:1;57527:359:0;;;;;;;;;;-1:-1:-1;57527:359:0;;;;;:::i;:::-;;:::i;:::-;;56737:45;;;;;;;;;;;;56776:6;56737:45;;47930:120;;;;;;;;;;-1:-1:-1;47930:120:0;;;;;:::i;:::-;47995:7;48021:12;;;;;;;;;;:22;;;;47930:120;48346:136;;;;;;;;;;-1:-1:-1;48346:136:0;;;;;:::i;:::-;;:::i;49448:245::-;;;;;;;;;;-1:-1:-1;49448:245:0;;;;;:::i;:::-;;:::i;73588:100::-;;;;;;;;;;-1:-1:-1;73588:100:0;;;;;:::i;:::-;;:::i;73128:103::-;;;;;;:::i;56899:30::-;;;;;;;;;;;;;;;;56483:66;;;;;;;;;;;;56523:26;56483:66;;73791:89;;;;;;;;;;-1:-1:-1;73791:89:0;;;;;:::i;70306:528::-;;;;;;;;;;-1:-1:-1;70306:528:0;;;;;:::i;:::-;;:::i;:::-;;;;;;;:::i;73339:108::-;;;;;;;;;;-1:-1:-1;73339:108:0;;;;;:::i;73237:96::-;;;;;;:::i;55122:142::-;;;;;;;;;;-1:-1:-1;55122:142:0;;;;;:::i;:::-;;:::i;:::-;;;8086:42:1;8074:55;;;8056:74;;8044:2;8029:18;55122:142:0;7910:226:1;46974:136:0;;;;;;;;;;-1:-1:-1;46974:136:0;;;;;:::i;:::-;47051:4;47074:12;;;;;;;;;;;:29;;;;;;;;;;;;;;;;46974:136;56413:64;;;;;;;;;;;;56452:25;56413:64;;46307:49;;;;;;;;;;-1:-1:-1;46307:49:0;46352:4;46307:49;;69626:36;;;;;;;;;;;;;;;73453:129;;;;;;;;;;-1:-1:-1;73453:129:0;;;;;:::i;:::-;;:::i;69819:163::-;;;;;;;;;;-1:-1:-1;69819:163:0;;;;;:::i;:::-;;:::i;:::-;;;;;;;:::i;70840:1266::-;;;;;;;;;;-1:-1:-1;70840:1266:0;;;;;:::i;:::-;;:::i;73694:91::-;;;;;;;;;;-1:-1:-1;73694:91:0;;;;;:::i;72112:532::-;;;;;;;;;;-1:-1:-1;72112:532:0;;;;;:::i;:::-;;:::i;69792:20::-;;;;;;;;;;;;;;;;57231:290;;;;;;;;;;-1:-1:-1;57231:290:0;;;;;:::i;:::-;;:::i;57892:264::-;;;;;;;;;;-1:-1:-1;57892:264:0;;;;;:::i;:::-;;:::i;56694:37::-;;;;;;;;;;;;56728:3;56694:37;;72650:472;;;;;;;;;;-1:-1:-1;72650:472:0;;;;;:::i;:::-;;:::i;55432:131::-;;;;;;;;;;-1:-1:-1;55432:131:0;;;;;:::i;:::-;;:::i;56621:66::-;;;;;;;;;;;;56661:26;56621:66;;48762:138;;;;;;;;;;-1:-1:-1;48762:138:0;;;;;:::i;:::-;;:::i;56985:47::-;;;;;;;;;;-1:-1:-1;56985:47:0;;;;;:::i;:::-;;;;;;;;;;;;;;57106:29;;;;;;;;;;;;;;;;54325:212;54410:4;54433:57;;;54448:42;54433:57;;:97;;;54494:36;54518:11;54494:23;:36::i;:::-;54426:104;54325:212;-1:-1:-1;;54325:212:0:o;57527:359::-;56661:26;46584:16;46595:4;46584:10;:16::i;:::-;57651:19:::1;::::0;::::1;57631:17;57651:19:::0;;;:12:::1;:19;::::0;;;;;;57684:14;;;57680:27:::1;;57700:7;57527:359:::0;;;:::o;57680:27::-:1;57748:19;::::0;::::1;57770:1;57748:19:::0;;;:12:::1;:19;::::0;;;;:23;57781:45:::1;::::0;57805:9;57816;57781:23:::1;:45::i;:::-;57841:38;::::0;;12332:42:1;12401:15;;;12383:34;;12453:15;;12448:2;12433:18;;12426:43;12485:18;;;12478:34;;;57841:38:0::1;::::0;12310:2:1;12295:18;57841:38:0::1;;;;;;;57621:265;46610:1;57527:359:::0;;;:::o;48346:136::-;47995:7;48021:12;;;;;;;;;;:22;;;46584:16;46595:4;46584:10;:16::i;:::-;48450:25:::1;48461:4;48467:7;48450:10;:25::i;:::-;;48346:136:::0;;;:::o;49448:245::-;49541:34;;;22395:10;49541:34;49537:102;;49598:30;;;;;;;;;;;;;;49537:102;49649:37;49661:4;49667:18;49649:11;:37::i;73588:100::-;73656:25;;;;;12725:2:1;73656:25:0;;;12707:21:1;12764:2;12744:18;;;12737:30;12803:17;12783:18;;;12776:45;12838:18;;73656:25:0;;;;;;;;70306:528;70388:13;70449:8;70417:40;;;;;;;;:::i;:::-;:28;:40;70413:59;;-1:-1:-1;;70459:13:0;;;;;;;;;;;;;;;;;;70306:528::o;70413:59::-;70523:8;70486:45;;;;;;;;:::i;:::-;:33;:45;70482:69;;-1:-1:-1;;70533:18:0;;;;;;;;;;;;;;;;;;70306:528::o;70482:69::-;70607:8;70565:50;;;;;;;;:::i;:::-;:38;:50;70561:79;;-1:-1:-1;;70617:23:0;;;;;;;;;;;;;;;;;;70306:528::o;70561:79::-;70697:8;70654:51;;;;;;;;:::i;:::-;:39;:51;70650:81;;-1:-1:-1;;70707:24:0;;;;;;;;;;;;;;;;;;70306:528::o;70650:81::-;70781:8;70745:44;;;;;;;;:::i;:::-;:32;:44;70741:67;;-1:-1:-1;;70791:17:0;;;;;;;;;;;;;;;;;;70306:528::o;70741:67::-;-1:-1:-1;;70818:9:0;;;;;;;;;-1:-1:-1;70818:9:0;;;70306:528::o;55122:142::-;55203:7;55229:18;;;:12;:18;;;;;:28;;55251:5;55229:21;:28::i;:::-;55222:35;55122:142;-1:-1:-1;;;55122:142:0:o;73453:129::-;73550:25;;;;;12725:2:1;73550:25:0;;;12707:21:1;12764:2;12744:18;;;12737:30;12803:17;12783:18;;;12776:45;73534:4:0;;12838:18:1;;73550:25:0;12523:339:1;69819:163:0;-1:-1:-1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;69935:40:0;;-1:-1:-1;;69935:40:0;;;;;;;;;;:::i;70840:1266::-;70953:23;56728:3;71002:15;;70980:6;:19;;;:37;;;;:::i;:::-;70979:49;;;;:::i;:::-;70953:75;;71061:15;71038:6;:19;;:38;;;;;;;:::i;:::-;;;;;;;;71087:20;71134:649;;;;;;;;71192:13;71134:649;;;;;;71237:6;:17;;;71134:649;;;;;;71286:6;:13;;;71134:649;;;;;;71332:6;:9;;;71134:649;;;;;;71372:6;:18;;;71134:649;;;;;;71419:6;:16;;;71134:649;;;;;;71467:6;:19;;;71134:649;;;;71540:6;:17;;;71134:649;;;;71592:15;71134:649;;;;71639:6;:19;;;71134:649;;;;;;71686:6;:15;;;71134:649;;;;71726:5;;:7;;;;;;;;;:::i;:::-;;;;-1:-1:-1;71134:649:0;;71110:683;;;;;;;;:::i;:::-;;;;;;;;;;;;;71087:706;;71865:6;:13;;;71809:290;;71838:13;71809:290;71892:7;71913:6;:17;;;71944:6;:18;;;71976:6;:16;;;72006:6;:19;;;72039:6;:17;;;72070:6;:19;;;71809:290;;;;;;;;;;;;:::i;:::-;;;;;;;;70943:1163;;70840:1266;;;:::o;72112:532::-;72222:36;72261:29;72282:7;72261:20;:29::i;:::-;72222:68;;72361:11;:24;;;72305:332;;72334:13;72305:332;72399:7;72420:11;:23;;;72457:11;:23;;;72494:11;:21;;;72529:11;:24;;;72567:11;:22;;;72603:11;:24;;;72305:332;;;;;;;;;;;;:::i;:::-;;;;;;;;72212:432;72112:532;;;:::o;57231:290::-;56661:26;46584:16;46595:4;46584:10;:16::i;:::-;56776:6:::1;57330:10;:26;;57322:55;;;::::0;::::1;::::0;;16599:2:1;57322:55:0::1;::::0;::::1;16581:21:1::0;16638:2;16618:18;;;16611:30;16677:18;16657;;;16650:46;16713:18;;57322:55:0::1;16397:340:1::0;57322:55:0::1;57408:15;::::0;;57433:28;;;;57476:38:::1;::::0;;16916:25:1;;;16972:2;16957:18;;16950:34;;;57476:38:0::1;::::0;16889:18:1;57476:38:0::1;;;;;;;;57312:209;57231:290:::0;;:::o;57892:264::-;56661:26;46584:16;46595:4;46584:10;:16::i;:::-;58017:14:::1;::::0;;58041:34;;;;58090:59:::1;::::0;;16916:25:1;;;16972:2;16957:18;;16950:34;;;58090:59:0::1;::::0;16889:18:1;58090:59:0::1;16742:248:1::0;72650:472:0;72971:144;;;17310:10:1;17298:23;;17280:42;;72971:144:0;17419:15:1;;;17414:2;17399:18;;17392:43;17471:15;;;17451:18;;;17444:43;17518:2;17503:18;;17496:34;;;17561:3;17546:19;;17539:35;;;17605:3;17590:19;;17583:35;;;72971:144:0;;;;;;;;;72998:13;;72971:144;;;;;17267:3:1;72971:144:0;;;72650:472;;;;;;;;;:::o;55432:131::-;55503:7;55529:18;;;:12;:18;;;;;:27;;:25;:27::i;48762:138::-;47995:7;48021:12;;;;;;;;;;:22;;;46584:16;46595:4;46584:10;:16::i;:::-;48867:26:::1;48879:4;48885:7;48867:11;:26::i;46685:202::-:0;46770:4;46793:47;;;46808:32;46793:47;;:87;;-1:-1:-1;38600:25:0;38585:40;;;;46844:36;38486:146;47319:103;47385:30;47396:4;22395:10;47385;:30::i;:::-;47319:103;:::o;51597:653::-;51772:4;51758:19;;;;51754:32;;51597:653;;;:::o;51754:32::-;51858:5;51867:1;51858:10;51854:23;;51597:653;;;:::o;51854:23::-;51890:20;;;;;51886:358;;52070:12;52087:2;:7;;52102:5;52087:25;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;52069:43;;;52134:7;52126:39;;;;;;;18041:2:1;52126:39:0;;;18023:21:1;18080:2;18060:18;;;18053:30;18119:21;18099:18;;;18092:49;18158:18;;52126:39:0;17839:343:1;51886:358:0;52196:37;:26;;;52223:2;52227:5;52196:26;:37::i;55665:257::-;55751:4;55767:12;55782:31;55799:4;55805:7;55782:16;:31::i;:::-;55767:46;;55827:7;55823:69;;;55850:18;;;;:12;:18;;;;;:31;;55873:7;55850:22;:31::i;:::-;;55908:7;55665:257;-1:-1:-1;;;55665:257:0:o;56025:262::-;56112:4;56128:12;56143:32;56161:4;56167:7;56143:17;:32::i;:::-;56128:47;;56189:7;56185:72;;;56212:18;;;;:12;:18;;;;;:34;;56238:7;56212:25;:34::i;33098:156::-;33172:7;33222:22;33226:3;33238:5;33222:3;:22::i;32641:115::-;32704:7;32730:19;32738:3;28080:18;;27998:107;47552:197;47051:4;47074:12;;;;;;;;;;;:29;;;;;;;;;;;;;47635:108;;47685:47;;;;;18391:42:1;18379:55;;47685:47:0;;;18361:74:1;18451:18;;;18444:34;;;18334:18;;47685:47:0;18187:297:1;47635:108:0;47552:197;;:::o;39802:160::-;39911:43;;;39926:14;18379:55:1;;39911:43:0;;;18361:74:1;18451:18;;;;18444:34;;;39911:43:0;;;;;;;;;;18334:18:1;;;;39911:43:0;;;;;;;;;;;;;;39884:71;;39904:5;;39884:19;:71::i;50299:316::-;50376:4;47074:12;;;;;;;;;;;:29;;;;;;;;;;;;;50392:217;;50435:6;:12;;;;;;;;;;;:29;;;;;;;;;;:36;;;;50467:4;50435:36;;;50517:12;22395:10;;22316:96;50517:12;50490:40;;50508:7;50490:40;;50502:4;50490:40;;;;;;;;;;-1:-1:-1;50551:4:0;50544:11;;50392:217;-1:-1:-1;50593:5:0;50586:12;;31840:150;31910:4;31933:50;31938:3;31958:23;;;31933:4;:50::i;50850:317::-;50928:4;47074:12;;;;;;;;;;;:29;;;;;;;;;;;;;50944:217;;;51018:5;50986:12;;;;;;;;;;;:29;;;;;;;;;;;:37;;;;;;51042:40;22395:10;;50986:12;;51042:40;;51018:5;51042:40;-1:-1:-1;51103:4:0;51096:11;;32158:156;32231:4;32254:53;32262:3;32282:23;;;32254:7;:53::i;28447:118::-;28514:7;28540:3;:11;;28552:5;28540:18;;;;;;;;:::i;:::-;;;;;;;;;28533:25;;28447:118;;;;:::o;42558:629::-;42977:23;43003:33;:27;;;43031:4;43003:27;:33::i;:::-;42977:59;;43050:10;:17;43071:1;43050:22;;:57;;;;;43088:10;43077:30;;;;;;;;;;;;:::i;:::-;43076:31;43050:57;43046:135;;;43130:40;;;;;8086:42:1;8074:55;;43130:40:0;;;8056:74:1;8029:18;;43130:40:0;7910:226:1;25765:406:0;25828:4;27884:21;;;:14;;;:21;;;;;;25844:321;;-1:-1:-1;25886:23:0;;;;;;;;:11;:23;;;;;;;;;;;;;26068:18;;26044:21;;;:14;;;:21;;;;;;:42;;;;26100:11;;26339:1368;26405:4;26534:21;;;:14;;;:21;;;;;;26570:13;;26566:1135;;26937:18;26958:12;26969:1;26958:8;:12;:::i;:::-;27004:18;;26937:33;;-1:-1:-1;26984:17:0;;27004:22;;27025:1;;27004:22;:::i;:::-;26984:42;;27059:9;27045:10;:23;27041:378;;27088:17;27108:3;:11;;27120:9;27108:22;;;;;;;;:::i;:::-;;;;;;;;;27088:42;;27255:9;27229:3;:11;;27241:10;27229:23;;;;;;;;:::i;:::-;;;;;;;;;;;;:35;;;;27368:25;;;:14;;;:25;;;;;:36;;;27041:378;27497:17;;:3;;:17;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;27600:3;:14;;:21;27615:5;27600:21;;;;;;;;;;;27593:28;;;27643:4;27636:11;;;;;;;26566:1135;27685:5;27678:12;;;;;18101:151;18176:12;18207:38;18229:6;18237:4;18243:1;18176:12;18817;18831:23;18858:6;:11;;18877:5;18884:4;18858:31;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;18816:73;;;;18906:55;18933:6;18941:7;18950:10;18906:26;:55::i;:::-;18899:62;18576:392;-1:-1:-1;;;;;;18576:392:0:o;20021:582::-;20165:12;20194:7;20189:408;;20217:19;20225:10;20217:7;:19::i;:::-;20189:408;;;20441:17;;:22;:49;;;;-1:-1:-1;20467:18:0;;;;:23;20441:49;20437:119;;;20517:24;;;;;8086:42:1;8074:55;;20517:24:0;;;8056:74:1;8029:18;;20517:24:0;7910:226:1;20437:119:0;-1:-1:-1;20576:10:0;20569:17;;21139:516;21270:17;;:21;21266:383;;21498:10;21492:17;21554:15;21541:10;21537:2;21533:19;21526:44;21266:383;21621:17;;;;;;;;;;;;;;14:332:1;72:6;125:2;113:9;104:7;100:23;96:32;93:52;;;141:1;138;131:12;93:52;180:9;167:23;230:66;223:5;219:78;212:5;209:89;199:117;;312:1;309;302:12;821:154;907:42;900:5;896:54;889:5;886:65;876:93;;965:1;962;955:12;980:134;1048:20;;1077:31;1048:20;1077:31;:::i;:::-;980:134;;;:::o;1119:388::-;1187:6;1195;1248:2;1236:9;1227:7;1223:23;1219:32;1216:52;;;1264:1;1261;1254:12;1216:52;1303:9;1290:23;1322:31;1347:5;1322:31;:::i;:::-;1372:5;-1:-1:-1;1429:2:1;1414:18;;1401:32;1442:33;1401:32;1442:33;:::i;:::-;1494:7;1484:17;;;1119:388;;;;;:::o;1694:180::-;1753:6;1806:2;1794:9;1785:7;1781:23;1777:32;1774:52;;;1822:1;1819;1812:12;1774:52;-1:-1:-1;1845:23:1;;1694:180;-1:-1:-1;1694:180:1:o;1879:315::-;1947:6;1955;2008:2;1996:9;1987:7;1983:23;1979:32;1976:52;;;2024:1;2021;2014:12;1976:52;2060:9;2047:23;2037:33;;2120:2;2109:9;2105:18;2092:32;2133:31;2158:5;2133:31;:::i;2199:184::-;2251:77;2248:1;2241:88;2348:4;2345:1;2338:15;2372:4;2369:1;2362:15;2388:255;2460:2;2454:9;2502:6;2490:19;;2539:18;2524:34;;2560:22;;;2521:62;2518:88;;;2586:18;;:::i;:::-;2622:2;2615:22;2388:255;:::o;2648:247::-;2715:2;2709:9;2757:3;2745:16;;2791:18;2776:34;;2812:22;;;2773:62;2770:88;;;2838:18;;:::i;2900:777::-;2942:5;2995:3;2988:4;2980:6;2976:17;2972:27;2962:55;;3013:1;3010;3003:12;2962:55;3049:6;3036:20;3075:18;3112:2;3108;3105:10;3102:36;;;3118:18;;:::i;:::-;3252:2;3246:9;3314:4;3306:13;;3157:66;3302:22;;;3326:2;3298:31;3294:40;3282:53;;;3350:18;;;3370:22;;;3347:46;3344:72;;;3396:18;;:::i;:::-;3436:10;3432:2;3425:22;3471:2;3463:6;3456:18;3517:3;3510:4;3505:2;3497:6;3493:15;3489:26;3486:35;3483:55;;;3534:1;3531;3524:12;3483:55;3598:2;3591:4;3583:6;3579:17;3572:4;3564:6;3560:17;3547:54;3645:1;3638:4;3633:2;3625:6;3621:15;3617:26;3610:37;3665:6;3656:15;;;;;;2900:777;;;;:::o;3682:455::-;3759:6;3767;3820:2;3808:9;3799:7;3795:23;3791:32;3788:52;;;3836:1;3833;3826:12;3788:52;3876:9;3863:23;3909:18;3901:6;3898:30;3895:50;;;3941:1;3938;3931:12;3895:50;3964:49;4005:7;3996:6;3985:9;3981:22;3964:49;:::i;:::-;3954:59;;;4063:2;4052:9;4048:18;4035:32;4076:31;4101:5;4076:31;:::i;4142:121::-;4227:10;4220:5;4216:22;4209:5;4206:33;4196:61;;4253:1;4250;4243:12;4268:132;4335:20;;4364:30;4335:20;4364:30;:::i;4405:118::-;4491:5;4484:13;4477:21;4470:5;4467:32;4457:60;;4513:1;4510;4503:12;4528:128;4593:20;;4622:28;4593:20;4622:28;:::i;4661:806::-;4720:5;4768:6;4756:9;4751:3;4747:19;4743:32;4740:52;;;4788:1;4785;4778:12;4740:52;4810:22;;:::i;:::-;4801:31;;4855:28;4873:9;4855:28;:::i;:::-;4848:5;4841:43;4916:38;4950:2;4939:9;4935:18;4916:38;:::i;:::-;4911:2;4904:5;4900:14;4893:62;4987:38;5021:2;5010:9;5006:18;4987:38;:::i;:::-;4982:2;4975:5;4971:14;4964:62;5058:38;5092:2;5081:9;5077:18;5058:38;:::i;:::-;5053:2;5046:5;5042:14;5035:62;5130:39;5164:3;5153:9;5149:19;5130:39;:::i;:::-;5124:3;5117:5;5113:15;5106:64;5231:3;5220:9;5216:19;5203:33;5197:3;5190:5;5186:15;5179:58;5298:3;5287:9;5283:19;5270:33;5264:3;5257:5;5253:15;5246:58;5337:36;5368:3;5357:9;5353:19;5337:36;:::i;:::-;5331:3;5324:5;5320:15;5313:61;5393:3;5456:2;5445:9;5441:18;5428:32;5423:2;5416:5;5412:14;5405:56;;4661:806;;;;:::o;5472:237::-;5560:6;5613:3;5601:9;5592:7;5588:23;5584:33;5581:53;;;5630:1;5627;5620:12;5581:53;5653:50;5695:7;5684:9;5653:50;:::i;5714:320::-;5782:6;5835:2;5823:9;5814:7;5810:23;5806:32;5803:52;;;5851:1;5848;5841:12;5803:52;5891:9;5878:23;5924:18;5916:6;5913:30;5910:50;;;5956:1;5953;5946:12;5910:50;5979:49;6020:7;6011:6;6000:9;5996:22;5979:49;:::i;:::-;5969:59;5714:320;-1:-1:-1;;;;5714:320:1:o;6039:273::-;6115:6;6168:2;6156:9;6147:7;6143:23;6139:32;6136:52;;;6184:1;6181;6174:12;6136:52;6223:9;6210:23;6262:1;6255:5;6252:12;6242:40;;6278:1;6275;6268:12;6317:250;6402:1;6412:113;6426:6;6423:1;6420:13;6412:113;;;6502:11;;;6496:18;6483:11;;;6476:39;6448:2;6441:10;6412:113;;;-1:-1:-1;;6559:1:1;6541:16;;6534:27;6317:250::o;6572:330::-;6614:3;6652:5;6646:12;6679:6;6674:3;6667:19;6695:76;6764:6;6757:4;6752:3;6748:14;6741:4;6734:5;6730:16;6695:76;:::i;:::-;6816:2;6804:15;6821:66;6800:88;6791:98;;;;6891:4;6787:109;;6572:330;-1:-1:-1;;6572:330:1:o;6907:220::-;7056:2;7045:9;7038:21;7019:4;7076:45;7117:2;7106:9;7102:18;7094:6;7076:45;:::i;7132:388::-;7209:6;7217;7270:2;7258:9;7249:7;7245:23;7241:32;7238:52;;;7286:1;7283;7276:12;7238:52;7326:9;7313:23;7359:18;7351:6;7348:30;7345:50;;;7391:1;7388;7381:12;7345:50;7414:49;7455:7;7446:6;7435:9;7431:22;7414:49;:::i;:::-;7404:59;7510:2;7495:18;;;;7482:32;;-1:-1:-1;;;;7132:388:1:o;7525:248::-;7593:6;7601;7654:2;7642:9;7633:7;7629:23;7625:32;7622:52;;;7670:1;7667;7660:12;7622:52;-1:-1:-1;;7693:23:1;;;7763:2;7748:18;;;7735:32;;-1:-1:-1;7525:248:1:o;8240:1373::-;8471:13;;8217:10;8206:22;8194:35;;8440:3;8425:19;;8543:4;8535:6;8531:17;8525:24;8558:53;8605:4;8594:9;8590:20;8576:12;8217:10;8206:22;8194:35;;8141:94;8558:53;;8660:4;8652:6;8648:17;8642:24;8675:56;8725:4;8714:9;8710:20;8694:14;7855:42;7844:54;7832:67;;7778:127;8675:56;;8780:4;8772:6;8768:17;8762:24;8795:56;8845:4;8834:9;8830:20;8814:14;7855:42;7844:54;7832:67;;7778:127;8795:56;;8900:4;8892:6;8888:17;8882:24;8915:56;8965:4;8954:9;8950:20;8934:14;7855:42;7844:54;7832:67;;7778:127;8915:56;;9020:4;9012:6;9008:17;9002:24;9035:56;9085:4;9074:9;9070:20;9054:14;7855:42;7844:54;7832:67;;7778:127;9035:56;;9147:4;9139:6;9135:17;9129:24;9122:4;9111:9;9107:20;9100:54;9210:4;9202:6;9198:17;9192:24;9185:4;9174:9;9170:20;9163:54;9236:6;9296:2;9288:6;9284:15;9278:22;9273:2;9262:9;9258:18;9251:50;;9320:6;9375:2;9367:6;9363:15;9357:22;9388:51;9435:2;9424:9;9420:18;9404:14;421:13;414:21;402:34;;351:91;9388:51;-1:-1:-1;;9458:6:1;9506:15;;;9500:22;9480:18;;;9473:50;9542:6;9590:15;;;9584:22;9564:18;;;;9557:50;;;;8240:1373;:::o;9618:440::-;9724:6;9732;9740;9793:3;9781:9;9772:7;9768:23;9764:33;9761:53;;;9810:1;9807;9800:12;9761:53;9846:9;9833:23;9823:33;;9906:2;9895:9;9891:18;9878:32;9919:31;9944:5;9919:31;:::i;:::-;9969:5;-1:-1:-1;9993:59:1;10044:7;10039:2;10024:18;;9993:59;:::i;:::-;9983:69;;9618:440;;;;;:::o;10063:523::-;10149:6;10157;10165;10218:2;10206:9;10197:7;10193:23;10189:32;10186:52;;;10234:1;10231;10224:12;10186:52;10270:9;10257:23;10247:33;;10330:2;10319:9;10315:18;10302:32;10343:31;10368:5;10343:31;:::i;:::-;10393:5;-1:-1:-1;10449:2:1;10434:18;;10421:32;10476:18;10465:30;;10462:50;;;10508:1;10505;10498:12;10462:50;10531:49;10572:7;10563:6;10552:9;10548:22;10531:49;:::i;:::-;10521:59;;;10063:523;;;;;:::o;10776:1087::-;10906:6;10914;10922;10930;10938;10946;10954;10962;10970;11023:3;11011:9;11002:7;10998:23;10994:33;10991:53;;;11040:1;11037;11030:12;10991:53;11076:9;11063:23;11053:33;;11136:2;11125:9;11121:18;11108:32;11149:31;11174:5;11149:31;:::i;:::-;11199:5;-1:-1:-1;11256:2:1;11241:18;;11228:32;11269:33;11228:32;11269:33;:::i;:::-;11321:7;-1:-1:-1;11380:2:1;11365:18;;11352:32;11393;11352;11393;:::i;:::-;11444:7;-1:-1:-1;11503:3:1;11488:19;;11475:33;11517;11475;11517;:::i;:::-;11569:7;-1:-1:-1;11628:3:1;11613:19;;11600:33;11642;11600;11642;:::i;:::-;11694:7;11684:17;;;11748:3;11737:9;11733:19;11720:33;11710:43;;11800:3;11789:9;11785:19;11772:33;11762:43;;11852:3;11841:9;11837:19;11824:33;11814:43;;10776:1087;;;;;;;;;;;:::o;11868:247::-;11927:6;11980:2;11968:9;11959:7;11955:23;11951:32;11948:52;;;11996:1;11993;11986:12;11948:52;12035:9;12022:23;12054:31;12079:5;12054:31;:::i;12867:184::-;12919:77;12916:1;12909:88;13016:4;13013:1;13006:15;13040:4;13037:1;13030:15;13056:136;13134:13;;13156:30;13134:13;13156:30;:::i;13197:138::-;13276:13;;13298:31;13276:13;13298:31;:::i;13340:132::-;13416:13;;13438:28;13416:13;13438:28;:::i;13477:1183::-;13580:6;13633:3;13621:9;13612:7;13608:23;13604:33;13601:53;;;13650:1;13647;13640:12;13601:53;13676:17;;:::i;:::-;13716:39;13745:9;13716:39;:::i;:::-;13709:5;13702:54;13788:48;13832:2;13821:9;13817:18;13788:48;:::i;:::-;13783:2;13776:5;13772:14;13765:72;13869:49;13914:2;13903:9;13899:18;13869:49;:::i;:::-;13864:2;13857:5;13853:14;13846:73;13951:49;13996:2;13985:9;13981:18;13951:49;:::i;:::-;13946:2;13939:5;13935:14;13928:73;14034:50;14079:3;14068:9;14064:19;14034:50;:::i;:::-;14028:3;14021:5;14017:15;14010:75;14118:50;14163:3;14152:9;14148:19;14118:50;:::i;:::-;14112:3;14105:5;14101:15;14094:75;14223:3;14212:9;14208:19;14202:26;14196:3;14189:5;14185:15;14178:51;14283:3;14272:9;14268:19;14262:26;14256:3;14249:5;14245:15;14238:51;14308:3;14364:2;14353:9;14349:18;14343:25;14338:2;14331:5;14327:14;14320:49;;14388:3;14423:46;14465:2;14454:9;14450:18;14423:46;:::i;:::-;14407:14;;;14400:70;14489:3;14530:18;;;14524:25;14508:14;;;14501:49;14569:3;14610:18;;;14604:25;14588:14;;;14581:49;;;;-1:-1:-1;14411:5:1;13477:1183;-1:-1:-1;13477:1183:1:o;14665:184::-;14717:77;14714:1;14707:88;14814:4;14811:1;14804:15;14838:4;14835:1;14828:15;14854:168;14927:9;;;14958;;14975:15;;;14969:22;;14955:37;14945:71;;14996:18;;:::i;15027:274::-;15067:1;15093;15083:189;;15128:77;15125:1;15118:88;15229:4;15226:1;15219:15;15257:4;15254:1;15247:15;15083:189;-1:-1:-1;15286:9:1;;15027:274::o;15306:128::-;15373:9;;;15394:11;;;15391:37;;;15408:18;;:::i;15439:195::-;15478:3;15509:66;15502:5;15499:77;15496:103;;15579:18;;:::i;:::-;-1:-1:-1;15626:1:1;15615:13;;15439:195::o;15639:753::-;15946:3;15935:9;15928:22;15909:4;15967:46;16008:3;15997:9;15993:19;15985:6;15967:46;:::i;:::-;16061:10;16049:23;;;;16044:2;16029:18;;16022:51;-1:-1:-1;16092:42:1;16170:15;;;16165:2;16150:18;;16143:43;16222:15;;;;16217:2;16202:18;;16195:43;16269:3;16254:19;;16247:35;;;;16313:3;16298:19;;16291:35;16370:14;;16363:22;16357:3;16342:19;;;16335:51;15959:54;15639:753;-1:-1:-1;15639:753:1:o;18791:184::-;18843:77;18840:1;18833:88;18940:4;18937:1;18930:15;18964:4;18961:1;18954:15;18980:245;19047:6;19100:2;19088:9;19079:7;19075:23;19071:32;19068:52;;;19116:1;19113;19106:12;19068:52;19148:9;19142:16;19167:28;19189:5;19167:28;:::i;19230:184::-;19282:77;19279:1;19272:88;19379:4;19376:1;19369:15;19403:4;19400:1;19393:15;19419:287;19548:3;19586:6;19580:13;19602:66;19661:6;19656:3;19649:4;19641:6;19637:17;19602:66;:::i;:::-;19684:16;;;;;19419:287;-1:-1:-1;;19419:287:1:o","abiDefinition":[{"inputs":[{"internalType":"address","name":"_owner","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AccessControlBadConfirmation","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"bytes32","name":"neededRole","type":"bytes32"}],"name":"AccessControlUnauthorizedAccount","type":"error"},{"inputs":[{"internalType":"address","name":"target","type":"address"}],"name":"AddressEmptyCode","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"AddressInsufficientBalance","type":"error"},{"inputs":[],"name":"FailedInnerCall","type":"error"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"SafeERC20FailedOperation","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"relayer","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"BridgeDepositClaimed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"BridgeDepositRefunded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"relayer","type":"address"}],"name":"BridgeProofDisputed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"relayer","type":"address"},{"indexed":false,"internalType":"bytes32","name":"transactionHash","type":"bytes32"}],"name":"BridgeProofProvided","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"relayer","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint32","name":"originChainId","type":"uint32"},{"indexed":false,"internalType":"address","name":"originToken","type":"address"},{"indexed":false,"internalType":"address","name":"destToken","type":"address"},{"indexed":false,"internalType":"uint256","name":"originAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"destAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"chainGasAmount","type":"uint256"}],"name":"BridgeRelayed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"bytes","name":"request","type":"bytes"},{"indexed":false,"internalType":"uint32","name":"destChainId","type":"uint32"},{"indexed":false,"internalType":"address","name":"originToken","type":"address"},{"indexed":false,"internalType":"address","name":"destToken","type":"address"},{"indexed":false,"internalType":"uint256","name":"originAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"destAmount","type":"uint256"},{"indexed":false,"internalType":"bool","name":"sendChainGas","type":"bool"}],"name":"BridgeRequested","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldChainGasAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newChainGasAmount","type":"uint256"}],"name":"ChainGasAmountUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldFeeRate","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newFeeRate","type":"uint256"}],"name":"FeeRateUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"address","name":"recipient","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"FeesSwept","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"previousAdminRole","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"newAdminRole","type":"bytes32"}],"name":"RoleAdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleRevoked","type":"event"},{"inputs":[],"name":"DEFAULT_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"FEE_BPS","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"FEE_RATE_MAX","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"GOVERNOR_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"GUARD_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"REFUNDER_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"RELAYER_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"uint32","name":"dstChainId","type":"uint32"},{"internalType":"address","name":"sender","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"address","name":"originToken","type":"address"},{"internalType":"address","name":"destToken","type":"address"},{"internalType":"uint256","name":"originAmount","type":"uint256"},{"internalType":"uint256","name":"destAmount","type":"uint256"},{"internalType":"bool","name":"sendChainGas","type":"bool"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"internalType":"struct IFastBridge.BridgeParams","name":"params","type":"tuple"}],"name":"bridge","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"transactionid","type":"bytes32"},{"internalType":"address","name":"relayer","type":"address"}],"name":"canClaim","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"chainGasAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"},{"internalType":"address","name":"to","type":"address"}],"name":"claim","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"deployBlock","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"transactionId","type":"bytes32"}],"name":"dispute","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"}],"name":"getBridgeTransaction","outputs":[{"components":[{"internalType":"uint32","name":"originChainId","type":"uint32"},{"internalType":"uint32","name":"destChainId","type":"uint32"},{"internalType":"address","name":"originSender","type":"address"},{"internalType":"address","name":"destRecipient","type":"address"},{"internalType":"address","name":"originToken","type":"address"},{"internalType":"address","name":"destToken","type":"address"},{"internalType":"uint256","name":"originAmount","type":"uint256"},{"internalType":"uint256","name":"destAmount","type":"uint256"},{"internalType":"uint256","name":"originFeeAmount","type":"uint256"},{"internalType":"bool","name":"sendChainGas","type":"bool"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint256","name":"nonce","type":"uint256"}],"internalType":"struct IFastBridge.BridgeTransaction","name":"","type":"tuple"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"enum FastBridge.BridgeStatus","name":"keyValue","type":"uint8"}],"name":"getEnumKeyByValue","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleAdmin","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"uint256","name":"index","type":"uint256"}],"name":"getRoleMember","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleMemberCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"grantRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"hasRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"internalType":"address","name":"relayer","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint32","name":"originChainId","type":"uint32"},{"internalType":"address","name":"originToken","type":"address"},{"internalType":"address","name":"destToken","type":"address"},{"internalType":"uint256","name":"originAmount","type":"uint256"},{"internalType":"uint256","name":"destAmount","type":"uint256"},{"internalType":"uint256","name":"chainGasAmount","type":"uint256"}],"name":"mockBridgeRelayer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"internalType":"address","name":"sender","type":"address"},{"components":[{"internalType":"uint32","name":"dstChainId","type":"uint32"},{"internalType":"address","name":"sender","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"address","name":"originToken","type":"address"},{"internalType":"address","name":"destToken","type":"address"},{"internalType":"uint256","name":"originAmount","type":"uint256"},{"internalType":"uint256","name":"destAmount","type":"uint256"},{"internalType":"bool","name":"sendChainGas","type":"bool"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"internalType":"struct IFastBridge.BridgeParams","name":"params","type":"tuple"}],"name":"mockBridgeRequest","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"internalType":"address","name":"sender","type":"address"},{"internalType":"bytes","name":"request","type":"bytes"}],"name":"mockBridgeRequestRaw","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"nonce","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"protocolFeeRate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"protocolFees","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"},{"internalType":"bytes32","name":"destTxHash","type":"bytes32"}],"name":"prove","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"}],"name":"refund","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"}],"name":"relay","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"callerConfirmation","type":"address"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"revokeRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"newChainGasAmount","type":"uint256"}],"name":"setChainGasAmount","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"newFeeRate","type":"uint256"}],"name":"setProtocolFeeRate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"address","name":"recipient","type":"address"}],"name":"sweepProtocolFees","outputs":[],"stateMutability":"nonpayable","type":"function"}],"userDoc":{"kind":"user","methods":{"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256))":{"notice":"Initiates bridge on origin chain to be relayed by off-chain relayer"},"chainGasAmount()":{"notice":"Chain gas amount to forward as rebate if requested"},"claim(bytes,address)":{"notice":"Completes bridge transaction on origin chain by claiming originally deposited capital"},"dispute(bytes32)":{"notice":"Disputes an outstanding proof in case relayer provided dest chain tx is invalid"},"getBridgeTransaction(bytes)":{"notice":"Decodes bridge request into a bridge transaction"},"protocolFeeRate()":{"notice":"Protocol fee rate taken on origin amount deposited in origin chain"},"protocolFees(address)":{"notice":"Protocol fee amounts accumulated"},"prove(bytes,bytes32)":{"notice":"Provides proof on origin side that relayer provided funds on destination side of bridge transaction"},"refund(bytes)":{"notice":"Refunds an outstanding bridge transaction in case optimistic bridging failed"},"relay(bytes)":{"notice":"Relays destination side of bridge transaction by off-chain relayer"}},"version":1},"developerDoc":{"errors":{"AccessControlBadConfirmation()":[{"details":"The caller of a function is not the expected one. NOTE: Don't confuse with {AccessControlUnauthorizedAccount}."}],"AccessControlUnauthorizedAccount(address,bytes32)":[{"details":"The `account` is missing a role."}],"AddressEmptyCode(address)":[{"details":"There's no code at `target` (it is not a contract)."}],"AddressInsufficientBalance(address)":[{"details":"The ETH balance of the account is not enough to perform the operation."}],"FailedInnerCall()":[{"details":"A call to an address target failed. The target may have reverted."}],"SafeERC20FailedOperation(address)":[{"details":"An operation with an ERC20 token failed."}]},"events":{"RoleAdminChanged(bytes32,bytes32,bytes32)":{"details":"Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole` `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite {RoleAdminChanged} not being emitted signaling this."},"RoleGranted(bytes32,address,address)":{"details":"Emitted when `account` is granted `role`. `sender` is the account that originated the contract call, an admin role bearer except when using {AccessControl-_setupRole}."},"RoleRevoked(bytes32,address,address)":{"details":"Emitted when `account` is revoked `role`. `sender` is the account that originated the contract call: - if using `revokeRole`, it is the admin role bearer - if using `renounceRole`, it is the role bearer (i.e. `account`)"}},"kind":"dev","methods":{"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256))":{"params":{"params":"The parameters required to bridge"}},"claim(bytes,address)":{"params":{"request":"The encoded bridge transaction to claim on origin chain","to":"The recipient address of the funds"}},"dispute(bytes32)":{"params":{"transactionId":"The transaction id associated with the encoded bridge transaction to dispute"}},"getBridgeTransaction(bytes)":{"params":{"request":"The bridge request to decode"}},"getRoleAdmin(bytes32)":{"details":"Returns the admin role that controls `role`. See {grantRole} and {revokeRole}. To change a role's admin, use {_setRoleAdmin}."},"getRoleMember(bytes32,uint256)":{"details":"Returns one of the accounts that have `role`. `index` must be a value between 0 and {getRoleMemberCount}, non-inclusive. Role bearers are not sorted in any particular way, and their ordering may change at any point. WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure you perform all queries on the same block. See the following https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post] for more information."},"getRoleMemberCount(bytes32)":{"details":"Returns the number of accounts that have `role`. Can be used together with {getRoleMember} to enumerate all bearers of a role."},"grantRole(bytes32,address)":{"details":"Grants `role` to `account`. If `account` had not been already granted `role`, emits a {RoleGranted} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleGranted} event."},"hasRole(bytes32,address)":{"details":"Returns `true` if `account` has been granted `role`."},"prove(bytes,bytes32)":{"params":{"destTxHash":"The destination tx hash proving bridge transaction was relayed","request":"The encoded bridge transaction to prove on origin chain"}},"refund(bytes)":{"params":{"request":"The encoded bridge transaction to refund"}},"relay(bytes)":{"params":{"request":"The encoded bridge transaction to relay on destination chain"}},"renounceRole(bytes32,address)":{"details":"Revokes `role` from the calling account. Roles are often managed via {grantRole} and {revokeRole}: this function's purpose is to provide a mechanism for accounts to lose their privileges if they are compromised (such as when a trusted device is misplaced). If the calling account had been revoked `role`, emits a {RoleRevoked} event. Requirements: - the caller must be `callerConfirmation`. May emit a {RoleRevoked} event."},"revokeRole(bytes32,address)":{"details":"Revokes `role` from `account`. If `account` had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleRevoked} event."},"supportsInterface(bytes4)":{"details":"See {IERC165-supportsInterface}."}},"stateVariables":{"nonce":{"details":"to prevent replays"}},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.20+commit.a1b79de6\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_owner\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"AccessControlBadConfirmation\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"neededRole\",\"type\":\"bytes32\"}],\"name\":\"AccessControlUnauthorizedAccount\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"}],\"name\":\"AddressEmptyCode\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"AddressInsufficientBalance\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"FailedInnerCall\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"}],\"name\":\"SafeERC20FailedOperation\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"BridgeDepositClaimed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"BridgeDepositRefunded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"name\":\"BridgeProofDisputed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"transactionHash\",\"type\":\"bytes32\"}],\"name\":\"BridgeProofProvided\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"originChainId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"chainGasAmount\",\"type\":\"uint256\"}],\"name\":\"BridgeRelayed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"destChainId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"sendChainGas\",\"type\":\"bool\"}],\"name\":\"BridgeRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"oldChainGasAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newChainGasAmount\",\"type\":\"uint256\"}],\"name\":\"ChainGasAmountUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"oldFeeRate\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newFeeRate\",\"type\":\"uint256\"}],\"name\":\"FeeRateUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"FeesSwept\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"previousAdminRole\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"newAdminRole\",\"type\":\"bytes32\"}],\"name\":\"RoleAdminChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleGranted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleRevoked\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"DEFAULT_ADMIN_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"FEE_BPS\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"FEE_RATE_MAX\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"GOVERNOR_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"GUARD_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"REFUNDER_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"RELAYER_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"dstChainId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"sendChainGas\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"}],\"internalType\":\"struct IFastBridge.BridgeParams\",\"name\":\"params\",\"type\":\"tuple\"}],\"name\":\"bridge\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionid\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"name\":\"canClaim\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"chainGasAmount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"claim\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"deployBlock\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"}],\"name\":\"dispute\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"getBridgeTransaction\",\"outputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"originChainId\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"destChainId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"originSender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destRecipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"originFeeAmount\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"sendChainGas\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"}],\"internalType\":\"struct IFastBridge.BridgeTransaction\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"enum FastBridge.BridgeStatus\",\"name\":\"keyValue\",\"type\":\"uint8\"}],\"name\":\"getEnumKeyByValue\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"}],\"name\":\"getRoleAdmin\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"index\",\"type\":\"uint256\"}],\"name\":\"getRoleMember\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"}],\"name\":\"getRoleMemberCount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"grantRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"hasRole\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"uint32\",\"name\":\"originChainId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"chainGasAmount\",\"type\":\"uint256\"}],\"name\":\"mockBridgeRelayer\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"components\":[{\"internalType\":\"uint32\",\"name\":\"dstChainId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"sendChainGas\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"}],\"internalType\":\"struct IFastBridge.BridgeParams\",\"name\":\"params\",\"type\":\"tuple\"}],\"name\":\"mockBridgeRequest\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"mockBridgeRequestRaw\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"nonce\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"protocolFeeRate\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"protocolFees\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"},{\"internalType\":\"bytes32\",\"name\":\"destTxHash\",\"type\":\"bytes32\"}],\"name\":\"prove\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"refund\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"relay\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"callerConfirmation\",\"type\":\"address\"}],\"name\":\"renounceRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"revokeRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"newChainGasAmount\",\"type\":\"uint256\"}],\"name\":\"setChainGasAmount\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"newFeeRate\",\"type\":\"uint256\"}],\"name\":\"setProtocolFeeRate\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes4\",\"name\":\"interfaceId\",\"type\":\"bytes4\"}],\"name\":\"supportsInterface\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"}],\"name\":\"sweepProtocolFees\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"errors\":{\"AccessControlBadConfirmation()\":[{\"details\":\"The caller of a function is not the expected one. NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\"}],\"AccessControlUnauthorizedAccount(address,bytes32)\":[{\"details\":\"The `account` is missing a role.\"}],\"AddressEmptyCode(address)\":[{\"details\":\"There's no code at `target` (it is not a contract).\"}],\"AddressInsufficientBalance(address)\":[{\"details\":\"The ETH balance of the account is not enough to perform the operation.\"}],\"FailedInnerCall()\":[{\"details\":\"A call to an address target failed. The target may have reverted.\"}],\"SafeERC20FailedOperation(address)\":[{\"details\":\"An operation with an ERC20 token failed.\"}]},\"events\":{\"RoleAdminChanged(bytes32,bytes32,bytes32)\":{\"details\":\"Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole` `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite {RoleAdminChanged} not being emitted signaling this.\"},\"RoleGranted(bytes32,address,address)\":{\"details\":\"Emitted when `account` is granted `role`. `sender` is the account that originated the contract call, an admin role bearer except when using {AccessControl-_setupRole}.\"},\"RoleRevoked(bytes32,address,address)\":{\"details\":\"Emitted when `account` is revoked `role`. `sender` is the account that originated the contract call: - if using `revokeRole`, it is the admin role bearer - if using `renounceRole`, it is the role bearer (i.e. `account`)\"}},\"kind\":\"dev\",\"methods\":{\"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256))\":{\"params\":{\"params\":\"The parameters required to bridge\"}},\"claim(bytes,address)\":{\"params\":{\"request\":\"The encoded bridge transaction to claim on origin chain\",\"to\":\"The recipient address of the funds\"}},\"dispute(bytes32)\":{\"params\":{\"transactionId\":\"The transaction id associated with the encoded bridge transaction to dispute\"}},\"getBridgeTransaction(bytes)\":{\"params\":{\"request\":\"The bridge request to decode\"}},\"getRoleAdmin(bytes32)\":{\"details\":\"Returns the admin role that controls `role`. See {grantRole} and {revokeRole}. To change a role's admin, use {_setRoleAdmin}.\"},\"getRoleMember(bytes32,uint256)\":{\"details\":\"Returns one of the accounts that have `role`. `index` must be a value between 0 and {getRoleMemberCount}, non-inclusive. Role bearers are not sorted in any particular way, and their ordering may change at any point. WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure you perform all queries on the same block. See the following https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post] for more information.\"},\"getRoleMemberCount(bytes32)\":{\"details\":\"Returns the number of accounts that have `role`. Can be used together with {getRoleMember} to enumerate all bearers of a role.\"},\"grantRole(bytes32,address)\":{\"details\":\"Grants `role` to `account`. If `account` had not been already granted `role`, emits a {RoleGranted} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleGranted} event.\"},\"hasRole(bytes32,address)\":{\"details\":\"Returns `true` if `account` has been granted `role`.\"},\"prove(bytes,bytes32)\":{\"params\":{\"destTxHash\":\"The destination tx hash proving bridge transaction was relayed\",\"request\":\"The encoded bridge transaction to prove on origin chain\"}},\"refund(bytes)\":{\"params\":{\"request\":\"The encoded bridge transaction to refund\"}},\"relay(bytes)\":{\"params\":{\"request\":\"The encoded bridge transaction to relay on destination chain\"}},\"renounceRole(bytes32,address)\":{\"details\":\"Revokes `role` from the calling account. Roles are often managed via {grantRole} and {revokeRole}: this function's purpose is to provide a mechanism for accounts to lose their privileges if they are compromised (such as when a trusted device is misplaced). If the calling account had been revoked `role`, emits a {RoleRevoked} event. Requirements: - the caller must be `callerConfirmation`. May emit a {RoleRevoked} event.\"},\"revokeRole(bytes32,address)\":{\"details\":\"Revokes `role` from `account`. If `account` had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleRevoked} event.\"},\"supportsInterface(bytes4)\":{\"details\":\"See {IERC165-supportsInterface}.\"}},\"stateVariables\":{\"nonce\":{\"details\":\"to prevent replays\"}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256))\":{\"notice\":\"Initiates bridge on origin chain to be relayed by off-chain relayer\"},\"chainGasAmount()\":{\"notice\":\"Chain gas amount to forward as rebate if requested\"},\"claim(bytes,address)\":{\"notice\":\"Completes bridge transaction on origin chain by claiming originally deposited capital\"},\"dispute(bytes32)\":{\"notice\":\"Disputes an outstanding proof in case relayer provided dest chain tx is invalid\"},\"getBridgeTransaction(bytes)\":{\"notice\":\"Decodes bridge request into a bridge transaction\"},\"protocolFeeRate()\":{\"notice\":\"Protocol fee rate taken on origin amount deposited in origin chain\"},\"protocolFees(address)\":{\"notice\":\"Protocol fee amounts accumulated\"},\"prove(bytes,bytes32)\":{\"notice\":\"Provides proof on origin side that relayer provided funds on destination side of bridge transaction\"},\"refund(bytes)\":{\"notice\":\"Refunds an outstanding bridge transaction in case optimistic bridging failed\"},\"relay(bytes)\":{\"notice\":\"Relays destination side of bridge transaction by off-chain relayer\"}},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeMock.sol\":\"FastBridgeMock\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeMock.sol\":{\"keccak256\":\"0x620e81214ecd324ae8b971219291f176c454ce76fb1c01d656428096da8f1366\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://18e556772c12e13aa2d52a50cc7c48e676c8d5af22b90adaf7befb39cdd08e64\",\"dweb:/ipfs/QmPrQc98TxHCFMeuFNADyjr6Nqo52rHhHy1LBcsVdMRXjL\"]}},\"version\":1}"},"hashes":{"DEFAULT_ADMIN_ROLE()":"a217fddf","FEE_BPS()":"bf333f2c","FEE_RATE_MAX()":"0f5f6ed7","GOVERNOR_ROLE()":"ccc57490","GUARD_ROLE()":"03ed0ee5","REFUNDER_ROLE()":"5960ccf2","RELAYER_ROLE()":"926d7d7f","bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256))":"45851694","canClaim(bytes32,address)":"aa9641ab","chainGasAmount()":"e00a83e0","claim(bytes,address)":"41fcb612","deployBlock()":"a3ec191a","dispute(bytes32)":"add98c70","getBridgeTransaction(bytes)":"ac11fb1a","getEnumKeyByValue(uint8)":"85ad903d","getRoleAdmin(bytes32)":"248a9ca3","getRoleMember(bytes32,uint256)":"9010d07c","getRoleMemberCount(bytes32)":"ca15c873","grantRole(bytes32,address)":"2f2ff15d","hasRole(bytes32,address)":"91d14854","mockBridgeRelayer(bytes32,address,address,uint32,address,address,uint256,uint256,uint256)":"c72870cc","mockBridgeRequest(bytes32,address,(uint32,address,address,address,address,uint256,uint256,bool,uint256))":"acaebbf1","mockBridgeRequestRaw(bytes32,address,bytes)":"aedf009d","nonce()":"affed0e0","protocolFeeRate()":"58f85880","protocolFees(address)":"dcf844a7","prove(bytes,bytes32)":"886d36ff","refund(bytes)":"5eb7d946","relay(bytes)":"8f0d6f17","renounceRole(bytes32,address)":"36568abe","revokeRole(bytes32,address)":"d547741f","setChainGasAmount(uint256)":"b250fe6b","setProtocolFeeRate(uint256)":"b13aa2d6","supportsInterface(bytes4)":"01ffc9a7","sweepProtocolFees(address,address)":"06f333f2"}},"solidity/FastBridgeMock.sol:IAccessControl":{"code":"0x","runtime-code":"0x","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.20 ^0.8.20;\n\n// contracts/interfaces/IAdmin.sol\n\ninterface IAdmin {\n // ============ Events ============\n\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n event ChainGasAmountUpdated(uint256 oldChainGasAmount, uint256 newChainGasAmount);\n\n // ============ Methods ============\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n\n function setChainGasAmount(uint256 newChainGasAmount) external;\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/libs/Errors.sol\n\nerror DeadlineExceeded();\nerror DeadlineNotExceeded();\nerror DeadlineTooShort();\nerror InsufficientOutputAmount();\n\nerror MsgValueIncorrect();\nerror PoolNotFound();\nerror TokenAddressMismatch();\nerror TokenNotContract();\nerror TokenNotETH();\nerror TokensIdentical();\n\nerror ChainIncorrect();\nerror AmountIncorrect();\nerror ZeroAddress();\n\nerror DisputePeriodNotPassed();\nerror DisputePeriodPassed();\nerror SenderIncorrect();\nerror StatusIncorrect();\nerror TransactionIdIncorrect();\nerror TransactionRelayed();\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// contracts/libs/UniversalToken.sol\n\nlibrary UniversalTokenLib {\n using SafeERC20 for IERC20;\n\n address internal constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Transfers tokens to the given account. Reverts if transfer is not successful.\n /// @dev This might trigger fallback, if ETH is transferred to the contract.\n /// Make sure this can not lead to reentrancy attacks.\n function universalTransfer(address token, address to, uint256 value) internal {\n // Don't do anything, if need to send tokens to this address\n if (to == address(this)) return;\n // Don't do anything, if trying to send zero value\n if (value == 0) return;\n if (token == ETH_ADDRESS) {\n /// @dev Note: this can potentially lead to executing code in `to`.\n // solhint-disable-next-line avoid-low-level-calls\n (bool success,) = to.call{value: value}(\"\");\n require(success, \"ETH transfer failed\");\n } else {\n IERC20(token).safeTransfer(to, value);\n }\n }\n\n /// @notice Issues an infinite allowance to the spender, if the current allowance is insufficient\n /// to spend the given amount.\n function universalApproveInfinity(address token, address spender, uint256 amountToSpend) internal {\n // ETH Chad doesn't require your approval\n if (token == ETH_ADDRESS) return;\n // No-op if allowance is already sufficient\n uint256 allowance = IERC20(token).allowance(address(this), spender);\n if (allowance \u003e= amountToSpend) return;\n // Otherwise, reset approval to 0 and set to max allowance\n if (allowance \u003e 0) IERC20(token).safeDecreaseAllowance(spender, allowance);\n IERC20(token).safeIncreaseAllowance(spender, type(uint256).max);\n }\n\n /// @notice Returns the balance of the given token (or native ETH) for the given account.\n function universalBalanceOf(address token, address account) internal view returns (uint256) {\n if (token == ETH_ADDRESS) {\n return account.balance;\n } else {\n return IERC20(token).balanceOf(account);\n }\n }\n\n /// @dev Checks that token is a contract and not ETH_ADDRESS.\n function assertIsContract(address token) internal view {\n // Check that ETH_ADDRESS was not used (in case this is a predeploy on any of the chains)\n if (token == UniversalTokenLib.ETH_ADDRESS) revert TokenNotContract();\n // Check that token is not an EOA\n if (token.code.length == 0) revert TokenNotContract();\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/Admin.sol\n\ncontract Admin is IAdmin, AccessControlEnumerable {\n using UniversalTokenLib for address;\n\n bytes32 public constant RELAYER_ROLE = keccak256(\"RELAYER_ROLE\");\n bytes32 public constant REFUNDER_ROLE = keccak256(\"REFUNDER_ROLE\");\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n uint256 public constant FEE_BPS = 1e6;\n uint256 public constant FEE_RATE_MAX = 0.01e6; // max 1% on origin amount\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Chain gas amount to forward as rebate if requested\n uint256 public chainGasAmount;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n }\n\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n require(newFeeRate \u003c= FEE_RATE_MAX, \"newFeeRate \u003e max\");\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n token.universalTransfer(recipient, feeAmount);\n emit FeesSwept(token, recipient, feeAmount);\n }\n\n function setChainGasAmount(uint256 newChainGasAmount) external onlyRole(GOVERNOR_ROLE) {\n uint256 oldChainGasAmount = chainGasAmount;\n chainGasAmount = newChainGasAmount;\n emit ChainGasAmountUpdated(oldChainGasAmount, newChainGasAmount);\n }\n}\n\n// contracts/FastBridge.sol\n\ncontract FastBridge is IFastBridge, Admin {\n using SafeERC20 for IERC20;\n using UniversalTokenLib for address;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Delay for a transaction after which it could be permisionlessly refunded\n uint256 public constant REFUND_DELAY = 7 days;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeStatus) public bridgeStatuses;\n /// @notice Proof of relayed bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeProof) public bridgeProofs;\n /// @notice Whether bridge has been relayed on destination chain\n mapping(bytes32 =\u003e bool) public bridgeRelays;\n\n /// @dev to prevent replays\n uint256 public nonce;\n // @dev the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @notice Pulls a requested token from the user to the requested recipient.\n /// @dev Be careful of re-entrancy issues when msg.value \u003e 0 and recipient != address(this)\n function _pullToken(address recipient, address token, uint256 amount) internal returns (uint256 amountPulled) {\n if (token != UniversalTokenLib.ETH_ADDRESS) {\n token.assertIsContract();\n // Record token balance before transfer\n amountPulled = IERC20(token).balanceOf(recipient);\n // Token needs to be pulled only if msg.value is zero\n // This way user can specify WETH as the origin asset\n IERC20(token).safeTransferFrom(msg.sender, recipient, amount);\n // Use the difference between the recorded balance and the current balance as the amountPulled\n amountPulled = IERC20(token).balanceOf(recipient) - amountPulled;\n } else {\n // Otherwise, we need to check that ETH amount matches msg.value\n if (amount != msg.value) revert MsgValueIncorrect();\n // Transfer value to recipient if not this address\n if (recipient != address(this)) token.universalTransfer(recipient, amount);\n // We will forward msg.value in the external call later, if recipient is not this contract\n amountPulled = msg.value;\n }\n }\n\n /// @inheritdoc IFastBridge\n function getBridgeTransaction(bytes memory request) public pure returns (BridgeTransaction memory) {\n return abi.decode(request, (BridgeTransaction));\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n // check bridge params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n\n // transfer tokens to bridge contract\n // @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _pullToken(address(this), params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n\n // set status to requested\n bytes memory request = abi.encode(\n BridgeTransaction({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n sendChainGas: params.sendChainGas,\n deadline: params.deadline,\n nonce: nonce++ // increment nonce on every bridge\n })\n );\n bytes32 transactionId = keccak256(request);\n bridgeStatuses[transactionId] = BridgeStatus.REQUESTED;\n\n emit BridgeRequested(\n transactionId,\n params.sender,\n request,\n params.dstChainId,\n params.originToken,\n params.destToken,\n originAmount,\n params.destAmount,\n params.sendChainGas\n );\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes memory request) external payable onlyRole(RELAYER_ROLE) {\n bytes32 transactionId = keccak256(request);\n BridgeTransaction memory transaction = getBridgeTransaction(request);\n if (transaction.destChainId != uint32(block.chainid)) revert ChainIncorrect();\n\n // check haven't exceeded deadline for relay to happen\n if (block.timestamp \u003e transaction.deadline) revert DeadlineExceeded();\n\n // mark bridge transaction as relayed\n if (bridgeRelays[transactionId]) revert TransactionRelayed();\n bridgeRelays[transactionId] = true;\n\n // transfer tokens to recipient on destination chain and gas rebate if requested\n address to = transaction.destRecipient;\n address token = transaction.destToken;\n uint256 amount = transaction.destAmount;\n\n uint256 rebate = chainGasAmount;\n if (!transaction.sendChainGas) {\n // forward erc20\n rebate = 0;\n _pullToken(to, token, amount);\n } else if (token == UniversalTokenLib.ETH_ADDRESS) {\n // lump in gas rebate into amount in native gas token\n _pullToken(to, token, amount + rebate);\n } else {\n // forward erc20 then forward gas rebate in native gas token\n _pullToken(to, token, amount);\n _pullToken(to, UniversalTokenLib.ETH_ADDRESS, rebate);\n }\n\n emit BridgeRelayed(\n transactionId,\n msg.sender,\n to,\n transaction.originChainId,\n transaction.originToken,\n transaction.destToken,\n transaction.originAmount,\n transaction.destAmount,\n rebate\n );\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes memory request, bytes32 destTxHash) external onlyRole(RELAYER_ROLE) {\n bytes32 transactionId = keccak256(request);\n // update bridge tx status given proof provided\n if (bridgeStatuses[transactionId] != BridgeStatus.REQUESTED) revert StatusIncorrect();\n bridgeStatuses[transactionId] = BridgeStatus.RELAYER_PROVED;\n bridgeProofs[transactionId] = BridgeProof({timestamp: uint96(block.timestamp), relayer: msg.sender}); // overflow ok\n\n emit BridgeProofProvided(transactionId, msg.sender, destTxHash);\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint96(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint96).max but\n /// proof.timestamp \u003c type(uint96).max via unchecked statement\n /// @param proof The bridge proof\n /// @return delta Time delta since proof submitted\n function _timeSince(BridgeProof memory proof) internal view returns (uint256 delta) {\n unchecked {\n delta = uint96(block.timestamp) - proof.timestamp;\n }\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n if (bridgeStatuses[transactionId] != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n BridgeProof memory proof = bridgeProofs[transactionId];\n if (proof.relayer != relayer) revert SenderIncorrect();\n return _timeSince(proof) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes memory request, address to) external onlyRole(RELAYER_ROLE) {\n bytes32 transactionId = keccak256(request);\n BridgeTransaction memory transaction = getBridgeTransaction(request);\n\n // update bridge tx status if able to claim origin collateral\n if (bridgeStatuses[transactionId] != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n\n BridgeProof memory proof = bridgeProofs[transactionId];\n if (proof.relayer != msg.sender) revert SenderIncorrect();\n if (_timeSince(proof) \u003c= DISPUTE_PERIOD) revert DisputePeriodNotPassed();\n\n bridgeStatuses[transactionId] = BridgeStatus.RELAYER_CLAIMED;\n\n // update protocol fees if origin fee amount exists\n if (transaction.originFeeAmount \u003e 0) protocolFees[transaction.originToken] += transaction.originFeeAmount;\n\n // transfer origin collateral less fee to specified address\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositClaimed(transactionId, msg.sender, to, token, amount);\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n if (bridgeStatuses[transactionId] != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(bridgeProofs[transactionId]) \u003e DISPUTE_PERIOD) revert DisputePeriodPassed();\n\n // @dev relayer gets slashed effectively if dest relay has gone thru\n bridgeStatuses[transactionId] = BridgeStatus.REQUESTED;\n delete bridgeProofs[transactionId];\n\n emit BridgeProofDisputed(transactionId, msg.sender);\n }\n\n /// @inheritdoc IFastBridge\n function refund(bytes memory request) external {\n bytes32 transactionId = keccak256(request);\n BridgeTransaction memory transaction = getBridgeTransaction(request);\n\n if (hasRole(REFUNDER_ROLE, msg.sender)) {\n // Refunder can refund if deadline has passed\n if (block.timestamp \u003c= transaction.deadline) revert DeadlineNotExceeded();\n } else {\n // Permissionless refund is allowed after REFUND_DELAY\n if (block.timestamp \u003c= transaction.deadline + REFUND_DELAY) revert DeadlineNotExceeded();\n }\n\n // set status to refunded if still in requested state\n if (bridgeStatuses[transactionId] != BridgeStatus.REQUESTED) revert StatusIncorrect();\n bridgeStatuses[transactionId] = BridgeStatus.REFUNDED;\n\n // transfer origin collateral back to original sender\n address to = transaction.originSender;\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount + transaction.originFeeAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n }\n}\n\n// test/FastBridgeMock.sol\n\ncontract FastBridgeMock is IFastBridge, Admin {\n // @dev the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @dev to prevent replays\n uint256 public nonce;\n\n function getBridgeTransaction(bytes memory request) public pure returns (BridgeTransaction memory) {\n return abi.decode(request, (BridgeTransaction));\n }\n\n // used for testing in go.\n // see: https://ethereum.stackexchange.com/questions/21155/how-to-expose-enum-in-solidity-contract\n // make sure to update fastbridge/status.go if this changes\n // or underliyng enum changes.\n //\n // TODO: a foundry test should be added to ensure this is always in sync.\n function getEnumKeyByValue(FastBridge.BridgeStatus keyValue) public pure returns (string memory) {\n if (FastBridge.BridgeStatus.NULL == keyValue) return \"NULL\";\n if (FastBridge.BridgeStatus.REQUESTED == keyValue) return \"REQUESTED\";\n if (FastBridge.BridgeStatus.RELAYER_PROVED == keyValue) return \"RELAYER_PROVED\";\n if (FastBridge.BridgeStatus.RELAYER_CLAIMED == keyValue) return \"RELAYER_CLAIMED\";\n if (FastBridge.BridgeStatus.REFUNDED == keyValue) return \"REFUNDED\";\n return \"\";\n }\n\n function mockBridgeRequest(bytes32 transactionId, address sender, BridgeParams memory params) external {\n uint256 originFeeAmount = (params.originAmount * protocolFeeRate) / FEE_BPS;\n params.originAmount -= originFeeAmount;\n\n bytes memory request = abi.encode(\n BridgeTransaction({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: params.originAmount, // includes relayer fee\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n sendChainGas: params.sendChainGas,\n deadline: params.deadline,\n nonce: nonce++ // increment nonce on every bridge\n })\n );\n\n emit BridgeRequested(\n transactionId,\n params.sender,\n request,\n params.dstChainId,\n params.originToken,\n params.destToken,\n params.originAmount,\n params.destAmount,\n params.sendChainGas\n );\n }\n\n function mockBridgeRequestRaw(bytes32 transactionId, address sender, bytes memory request) external {\n BridgeTransaction memory transaction = getBridgeTransaction(request);\n emit BridgeRequested(\n transactionId,\n transaction.originSender,\n request,\n transaction.destChainId,\n transaction.originToken,\n transaction.destToken,\n transaction.originAmount,\n transaction.destAmount,\n transaction.sendChainGas\n );\n }\n\n function mockBridgeRelayer(\n bytes32 transactionId,\n address relayer,\n address to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n )\n external\n {\n emit BridgeRelayed(\n transactionId, relayer, to, originChainId, originToken, destToken, originAmount, destAmount, chainGasAmount\n );\n }\n\n function bridge(BridgeParams memory params) external payable {\n revert(\"not implemented\");\n }\n\n function relay(bytes memory request) external payable {\n revert(\"not implemented\");\n }\n\n function prove(bytes memory request, bytes32 destTxHash) external {\n revert(\"not implemented\");\n }\n\n function canClaim(bytes32 transactionid, address relayer) external view returns (bool) {\n revert(\"not implemented\");\n }\n\n function claim(bytes memory request, address to) external {\n revert(\"not implemented\");\n }\n\n function dispute(bytes32 transactionId) external {\n revert(\"not implemented\");\n }\n\n function refund(bytes memory request) external {\n revert(\"not implemented\");\n }\n}\n","language":"Solidity","languageVersion":"0.8.20","compilerVersion":"0.8.20","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"","srcMapRuntime":"","abiDefinition":[{"inputs":[],"name":"AccessControlBadConfirmation","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"bytes32","name":"neededRole","type":"bytes32"}],"name":"AccessControlUnauthorizedAccount","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"previousAdminRole","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"newAdminRole","type":"bytes32"}],"name":"RoleAdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleRevoked","type":"event"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleAdmin","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"grantRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"hasRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"callerConfirmation","type":"address"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"revokeRole","outputs":[],"stateMutability":"nonpayable","type":"function"}],"userDoc":{"kind":"user","methods":{},"version":1},"developerDoc":{"details":"External interface of AccessControl declared to support ERC165 detection.","errors":{"AccessControlBadConfirmation()":[{"details":"The caller of a function is not the expected one. NOTE: Don't confuse with {AccessControlUnauthorizedAccount}."}],"AccessControlUnauthorizedAccount(address,bytes32)":[{"details":"The `account` is missing a role."}]},"events":{"RoleAdminChanged(bytes32,bytes32,bytes32)":{"details":"Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole` `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite {RoleAdminChanged} not being emitted signaling this."},"RoleGranted(bytes32,address,address)":{"details":"Emitted when `account` is granted `role`. `sender` is the account that originated the contract call, an admin role bearer except when using {AccessControl-_setupRole}."},"RoleRevoked(bytes32,address,address)":{"details":"Emitted when `account` is revoked `role`. `sender` is the account that originated the contract call: - if using `revokeRole`, it is the admin role bearer - if using `renounceRole`, it is the role bearer (i.e. `account`)"}},"kind":"dev","methods":{"getRoleAdmin(bytes32)":{"details":"Returns the admin role that controls `role`. See {grantRole} and {revokeRole}. To change a role's admin, use {AccessControl-_setRoleAdmin}."},"grantRole(bytes32,address)":{"details":"Grants `role` to `account`. If `account` had not been already granted `role`, emits a {RoleGranted} event. Requirements: - the caller must have ``role``'s admin role."},"hasRole(bytes32,address)":{"details":"Returns `true` if `account` has been granted `role`."},"renounceRole(bytes32,address)":{"details":"Revokes `role` from the calling account. Roles are often managed via {grantRole} and {revokeRole}: this function's purpose is to provide a mechanism for accounts to lose their privileges if they are compromised (such as when a trusted device is misplaced). If the calling account had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must be `callerConfirmation`."},"revokeRole(bytes32,address)":{"details":"Revokes `role` from `account`. If `account` had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must have ``role``'s admin role."}},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.20+commit.a1b79de6\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[],\"name\":\"AccessControlBadConfirmation\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"neededRole\",\"type\":\"bytes32\"}],\"name\":\"AccessControlUnauthorizedAccount\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"previousAdminRole\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"newAdminRole\",\"type\":\"bytes32\"}],\"name\":\"RoleAdminChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleGranted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleRevoked\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"}],\"name\":\"getRoleAdmin\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"grantRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"hasRole\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"callerConfirmation\",\"type\":\"address\"}],\"name\":\"renounceRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"revokeRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"details\":\"External interface of AccessControl declared to support ERC165 detection.\",\"errors\":{\"AccessControlBadConfirmation()\":[{\"details\":\"The caller of a function is not the expected one. NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\"}],\"AccessControlUnauthorizedAccount(address,bytes32)\":[{\"details\":\"The `account` is missing a role.\"}]},\"events\":{\"RoleAdminChanged(bytes32,bytes32,bytes32)\":{\"details\":\"Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole` `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite {RoleAdminChanged} not being emitted signaling this.\"},\"RoleGranted(bytes32,address,address)\":{\"details\":\"Emitted when `account` is granted `role`. `sender` is the account that originated the contract call, an admin role bearer except when using {AccessControl-_setupRole}.\"},\"RoleRevoked(bytes32,address,address)\":{\"details\":\"Emitted when `account` is revoked `role`. `sender` is the account that originated the contract call: - if using `revokeRole`, it is the admin role bearer - if using `renounceRole`, it is the role bearer (i.e. `account`)\"}},\"kind\":\"dev\",\"methods\":{\"getRoleAdmin(bytes32)\":{\"details\":\"Returns the admin role that controls `role`. See {grantRole} and {revokeRole}. To change a role's admin, use {AccessControl-_setRoleAdmin}.\"},\"grantRole(bytes32,address)\":{\"details\":\"Grants `role` to `account`. If `account` had not been already granted `role`, emits a {RoleGranted} event. Requirements: - the caller must have ``role``'s admin role.\"},\"hasRole(bytes32,address)\":{\"details\":\"Returns `true` if `account` has been granted `role`.\"},\"renounceRole(bytes32,address)\":{\"details\":\"Revokes `role` from the calling account. Roles are often managed via {grantRole} and {revokeRole}: this function's purpose is to provide a mechanism for accounts to lose their privileges if they are compromised (such as when a trusted device is misplaced). If the calling account had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must be `callerConfirmation`.\"},\"revokeRole(bytes32,address)\":{\"details\":\"Revokes `role` from `account`. If `account` had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must have ``role``'s admin role.\"}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeMock.sol\":\"IAccessControl\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeMock.sol\":{\"keccak256\":\"0x620e81214ecd324ae8b971219291f176c454ce76fb1c01d656428096da8f1366\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://18e556772c12e13aa2d52a50cc7c48e676c8d5af22b90adaf7befb39cdd08e64\",\"dweb:/ipfs/QmPrQc98TxHCFMeuFNADyjr6Nqo52rHhHy1LBcsVdMRXjL\"]}},\"version\":1}"},"hashes":{"getRoleAdmin(bytes32)":"248a9ca3","grantRole(bytes32,address)":"2f2ff15d","hasRole(bytes32,address)":"91d14854","renounceRole(bytes32,address)":"36568abe","revokeRole(bytes32,address)":"d547741f"}},"solidity/FastBridgeMock.sol:IAccessControlEnumerable":{"code":"0x","runtime-code":"0x","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.20 ^0.8.20;\n\n// contracts/interfaces/IAdmin.sol\n\ninterface IAdmin {\n // ============ Events ============\n\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n event ChainGasAmountUpdated(uint256 oldChainGasAmount, uint256 newChainGasAmount);\n\n // ============ Methods ============\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n\n function setChainGasAmount(uint256 newChainGasAmount) external;\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/libs/Errors.sol\n\nerror DeadlineExceeded();\nerror DeadlineNotExceeded();\nerror DeadlineTooShort();\nerror InsufficientOutputAmount();\n\nerror MsgValueIncorrect();\nerror PoolNotFound();\nerror TokenAddressMismatch();\nerror TokenNotContract();\nerror TokenNotETH();\nerror TokensIdentical();\n\nerror ChainIncorrect();\nerror AmountIncorrect();\nerror ZeroAddress();\n\nerror DisputePeriodNotPassed();\nerror DisputePeriodPassed();\nerror SenderIncorrect();\nerror StatusIncorrect();\nerror TransactionIdIncorrect();\nerror TransactionRelayed();\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// contracts/libs/UniversalToken.sol\n\nlibrary UniversalTokenLib {\n using SafeERC20 for IERC20;\n\n address internal constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Transfers tokens to the given account. Reverts if transfer is not successful.\n /// @dev This might trigger fallback, if ETH is transferred to the contract.\n /// Make sure this can not lead to reentrancy attacks.\n function universalTransfer(address token, address to, uint256 value) internal {\n // Don't do anything, if need to send tokens to this address\n if (to == address(this)) return;\n // Don't do anything, if trying to send zero value\n if (value == 0) return;\n if (token == ETH_ADDRESS) {\n /// @dev Note: this can potentially lead to executing code in `to`.\n // solhint-disable-next-line avoid-low-level-calls\n (bool success,) = to.call{value: value}(\"\");\n require(success, \"ETH transfer failed\");\n } else {\n IERC20(token).safeTransfer(to, value);\n }\n }\n\n /// @notice Issues an infinite allowance to the spender, if the current allowance is insufficient\n /// to spend the given amount.\n function universalApproveInfinity(address token, address spender, uint256 amountToSpend) internal {\n // ETH Chad doesn't require your approval\n if (token == ETH_ADDRESS) return;\n // No-op if allowance is already sufficient\n uint256 allowance = IERC20(token).allowance(address(this), spender);\n if (allowance \u003e= amountToSpend) return;\n // Otherwise, reset approval to 0 and set to max allowance\n if (allowance \u003e 0) IERC20(token).safeDecreaseAllowance(spender, allowance);\n IERC20(token).safeIncreaseAllowance(spender, type(uint256).max);\n }\n\n /// @notice Returns the balance of the given token (or native ETH) for the given account.\n function universalBalanceOf(address token, address account) internal view returns (uint256) {\n if (token == ETH_ADDRESS) {\n return account.balance;\n } else {\n return IERC20(token).balanceOf(account);\n }\n }\n\n /// @dev Checks that token is a contract and not ETH_ADDRESS.\n function assertIsContract(address token) internal view {\n // Check that ETH_ADDRESS was not used (in case this is a predeploy on any of the chains)\n if (token == UniversalTokenLib.ETH_ADDRESS) revert TokenNotContract();\n // Check that token is not an EOA\n if (token.code.length == 0) revert TokenNotContract();\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/Admin.sol\n\ncontract Admin is IAdmin, AccessControlEnumerable {\n using UniversalTokenLib for address;\n\n bytes32 public constant RELAYER_ROLE = keccak256(\"RELAYER_ROLE\");\n bytes32 public constant REFUNDER_ROLE = keccak256(\"REFUNDER_ROLE\");\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n uint256 public constant FEE_BPS = 1e6;\n uint256 public constant FEE_RATE_MAX = 0.01e6; // max 1% on origin amount\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Chain gas amount to forward as rebate if requested\n uint256 public chainGasAmount;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n }\n\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n require(newFeeRate \u003c= FEE_RATE_MAX, \"newFeeRate \u003e max\");\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n token.universalTransfer(recipient, feeAmount);\n emit FeesSwept(token, recipient, feeAmount);\n }\n\n function setChainGasAmount(uint256 newChainGasAmount) external onlyRole(GOVERNOR_ROLE) {\n uint256 oldChainGasAmount = chainGasAmount;\n chainGasAmount = newChainGasAmount;\n emit ChainGasAmountUpdated(oldChainGasAmount, newChainGasAmount);\n }\n}\n\n// contracts/FastBridge.sol\n\ncontract FastBridge is IFastBridge, Admin {\n using SafeERC20 for IERC20;\n using UniversalTokenLib for address;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Delay for a transaction after which it could be permisionlessly refunded\n uint256 public constant REFUND_DELAY = 7 days;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeStatus) public bridgeStatuses;\n /// @notice Proof of relayed bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeProof) public bridgeProofs;\n /// @notice Whether bridge has been relayed on destination chain\n mapping(bytes32 =\u003e bool) public bridgeRelays;\n\n /// @dev to prevent replays\n uint256 public nonce;\n // @dev the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @notice Pulls a requested token from the user to the requested recipient.\n /// @dev Be careful of re-entrancy issues when msg.value \u003e 0 and recipient != address(this)\n function _pullToken(address recipient, address token, uint256 amount) internal returns (uint256 amountPulled) {\n if (token != UniversalTokenLib.ETH_ADDRESS) {\n token.assertIsContract();\n // Record token balance before transfer\n amountPulled = IERC20(token).balanceOf(recipient);\n // Token needs to be pulled only if msg.value is zero\n // This way user can specify WETH as the origin asset\n IERC20(token).safeTransferFrom(msg.sender, recipient, amount);\n // Use the difference between the recorded balance and the current balance as the amountPulled\n amountPulled = IERC20(token).balanceOf(recipient) - amountPulled;\n } else {\n // Otherwise, we need to check that ETH amount matches msg.value\n if (amount != msg.value) revert MsgValueIncorrect();\n // Transfer value to recipient if not this address\n if (recipient != address(this)) token.universalTransfer(recipient, amount);\n // We will forward msg.value in the external call later, if recipient is not this contract\n amountPulled = msg.value;\n }\n }\n\n /// @inheritdoc IFastBridge\n function getBridgeTransaction(bytes memory request) public pure returns (BridgeTransaction memory) {\n return abi.decode(request, (BridgeTransaction));\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n // check bridge params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n\n // transfer tokens to bridge contract\n // @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _pullToken(address(this), params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n\n // set status to requested\n bytes memory request = abi.encode(\n BridgeTransaction({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n sendChainGas: params.sendChainGas,\n deadline: params.deadline,\n nonce: nonce++ // increment nonce on every bridge\n })\n );\n bytes32 transactionId = keccak256(request);\n bridgeStatuses[transactionId] = BridgeStatus.REQUESTED;\n\n emit BridgeRequested(\n transactionId,\n params.sender,\n request,\n params.dstChainId,\n params.originToken,\n params.destToken,\n originAmount,\n params.destAmount,\n params.sendChainGas\n );\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes memory request) external payable onlyRole(RELAYER_ROLE) {\n bytes32 transactionId = keccak256(request);\n BridgeTransaction memory transaction = getBridgeTransaction(request);\n if (transaction.destChainId != uint32(block.chainid)) revert ChainIncorrect();\n\n // check haven't exceeded deadline for relay to happen\n if (block.timestamp \u003e transaction.deadline) revert DeadlineExceeded();\n\n // mark bridge transaction as relayed\n if (bridgeRelays[transactionId]) revert TransactionRelayed();\n bridgeRelays[transactionId] = true;\n\n // transfer tokens to recipient on destination chain and gas rebate if requested\n address to = transaction.destRecipient;\n address token = transaction.destToken;\n uint256 amount = transaction.destAmount;\n\n uint256 rebate = chainGasAmount;\n if (!transaction.sendChainGas) {\n // forward erc20\n rebate = 0;\n _pullToken(to, token, amount);\n } else if (token == UniversalTokenLib.ETH_ADDRESS) {\n // lump in gas rebate into amount in native gas token\n _pullToken(to, token, amount + rebate);\n } else {\n // forward erc20 then forward gas rebate in native gas token\n _pullToken(to, token, amount);\n _pullToken(to, UniversalTokenLib.ETH_ADDRESS, rebate);\n }\n\n emit BridgeRelayed(\n transactionId,\n msg.sender,\n to,\n transaction.originChainId,\n transaction.originToken,\n transaction.destToken,\n transaction.originAmount,\n transaction.destAmount,\n rebate\n );\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes memory request, bytes32 destTxHash) external onlyRole(RELAYER_ROLE) {\n bytes32 transactionId = keccak256(request);\n // update bridge tx status given proof provided\n if (bridgeStatuses[transactionId] != BridgeStatus.REQUESTED) revert StatusIncorrect();\n bridgeStatuses[transactionId] = BridgeStatus.RELAYER_PROVED;\n bridgeProofs[transactionId] = BridgeProof({timestamp: uint96(block.timestamp), relayer: msg.sender}); // overflow ok\n\n emit BridgeProofProvided(transactionId, msg.sender, destTxHash);\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint96(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint96).max but\n /// proof.timestamp \u003c type(uint96).max via unchecked statement\n /// @param proof The bridge proof\n /// @return delta Time delta since proof submitted\n function _timeSince(BridgeProof memory proof) internal view returns (uint256 delta) {\n unchecked {\n delta = uint96(block.timestamp) - proof.timestamp;\n }\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n if (bridgeStatuses[transactionId] != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n BridgeProof memory proof = bridgeProofs[transactionId];\n if (proof.relayer != relayer) revert SenderIncorrect();\n return _timeSince(proof) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes memory request, address to) external onlyRole(RELAYER_ROLE) {\n bytes32 transactionId = keccak256(request);\n BridgeTransaction memory transaction = getBridgeTransaction(request);\n\n // update bridge tx status if able to claim origin collateral\n if (bridgeStatuses[transactionId] != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n\n BridgeProof memory proof = bridgeProofs[transactionId];\n if (proof.relayer != msg.sender) revert SenderIncorrect();\n if (_timeSince(proof) \u003c= DISPUTE_PERIOD) revert DisputePeriodNotPassed();\n\n bridgeStatuses[transactionId] = BridgeStatus.RELAYER_CLAIMED;\n\n // update protocol fees if origin fee amount exists\n if (transaction.originFeeAmount \u003e 0) protocolFees[transaction.originToken] += transaction.originFeeAmount;\n\n // transfer origin collateral less fee to specified address\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositClaimed(transactionId, msg.sender, to, token, amount);\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n if (bridgeStatuses[transactionId] != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(bridgeProofs[transactionId]) \u003e DISPUTE_PERIOD) revert DisputePeriodPassed();\n\n // @dev relayer gets slashed effectively if dest relay has gone thru\n bridgeStatuses[transactionId] = BridgeStatus.REQUESTED;\n delete bridgeProofs[transactionId];\n\n emit BridgeProofDisputed(transactionId, msg.sender);\n }\n\n /// @inheritdoc IFastBridge\n function refund(bytes memory request) external {\n bytes32 transactionId = keccak256(request);\n BridgeTransaction memory transaction = getBridgeTransaction(request);\n\n if (hasRole(REFUNDER_ROLE, msg.sender)) {\n // Refunder can refund if deadline has passed\n if (block.timestamp \u003c= transaction.deadline) revert DeadlineNotExceeded();\n } else {\n // Permissionless refund is allowed after REFUND_DELAY\n if (block.timestamp \u003c= transaction.deadline + REFUND_DELAY) revert DeadlineNotExceeded();\n }\n\n // set status to refunded if still in requested state\n if (bridgeStatuses[transactionId] != BridgeStatus.REQUESTED) revert StatusIncorrect();\n bridgeStatuses[transactionId] = BridgeStatus.REFUNDED;\n\n // transfer origin collateral back to original sender\n address to = transaction.originSender;\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount + transaction.originFeeAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n }\n}\n\n// test/FastBridgeMock.sol\n\ncontract FastBridgeMock is IFastBridge, Admin {\n // @dev the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @dev to prevent replays\n uint256 public nonce;\n\n function getBridgeTransaction(bytes memory request) public pure returns (BridgeTransaction memory) {\n return abi.decode(request, (BridgeTransaction));\n }\n\n // used for testing in go.\n // see: https://ethereum.stackexchange.com/questions/21155/how-to-expose-enum-in-solidity-contract\n // make sure to update fastbridge/status.go if this changes\n // or underliyng enum changes.\n //\n // TODO: a foundry test should be added to ensure this is always in sync.\n function getEnumKeyByValue(FastBridge.BridgeStatus keyValue) public pure returns (string memory) {\n if (FastBridge.BridgeStatus.NULL == keyValue) return \"NULL\";\n if (FastBridge.BridgeStatus.REQUESTED == keyValue) return \"REQUESTED\";\n if (FastBridge.BridgeStatus.RELAYER_PROVED == keyValue) return \"RELAYER_PROVED\";\n if (FastBridge.BridgeStatus.RELAYER_CLAIMED == keyValue) return \"RELAYER_CLAIMED\";\n if (FastBridge.BridgeStatus.REFUNDED == keyValue) return \"REFUNDED\";\n return \"\";\n }\n\n function mockBridgeRequest(bytes32 transactionId, address sender, BridgeParams memory params) external {\n uint256 originFeeAmount = (params.originAmount * protocolFeeRate) / FEE_BPS;\n params.originAmount -= originFeeAmount;\n\n bytes memory request = abi.encode(\n BridgeTransaction({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: params.originAmount, // includes relayer fee\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n sendChainGas: params.sendChainGas,\n deadline: params.deadline,\n nonce: nonce++ // increment nonce on every bridge\n })\n );\n\n emit BridgeRequested(\n transactionId,\n params.sender,\n request,\n params.dstChainId,\n params.originToken,\n params.destToken,\n params.originAmount,\n params.destAmount,\n params.sendChainGas\n );\n }\n\n function mockBridgeRequestRaw(bytes32 transactionId, address sender, bytes memory request) external {\n BridgeTransaction memory transaction = getBridgeTransaction(request);\n emit BridgeRequested(\n transactionId,\n transaction.originSender,\n request,\n transaction.destChainId,\n transaction.originToken,\n transaction.destToken,\n transaction.originAmount,\n transaction.destAmount,\n transaction.sendChainGas\n );\n }\n\n function mockBridgeRelayer(\n bytes32 transactionId,\n address relayer,\n address to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n )\n external\n {\n emit BridgeRelayed(\n transactionId, relayer, to, originChainId, originToken, destToken, originAmount, destAmount, chainGasAmount\n );\n }\n\n function bridge(BridgeParams memory params) external payable {\n revert(\"not implemented\");\n }\n\n function relay(bytes memory request) external payable {\n revert(\"not implemented\");\n }\n\n function prove(bytes memory request, bytes32 destTxHash) external {\n revert(\"not implemented\");\n }\n\n function canClaim(bytes32 transactionid, address relayer) external view returns (bool) {\n revert(\"not implemented\");\n }\n\n function claim(bytes memory request, address to) external {\n revert(\"not implemented\");\n }\n\n function dispute(bytes32 transactionId) external {\n revert(\"not implemented\");\n }\n\n function refund(bytes memory request) external {\n revert(\"not implemented\");\n }\n}\n","language":"Solidity","languageVersion":"0.8.20","compilerVersion":"0.8.20","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"","srcMapRuntime":"","abiDefinition":[{"inputs":[],"name":"AccessControlBadConfirmation","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"bytes32","name":"neededRole","type":"bytes32"}],"name":"AccessControlUnauthorizedAccount","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"previousAdminRole","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"newAdminRole","type":"bytes32"}],"name":"RoleAdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleRevoked","type":"event"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleAdmin","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"uint256","name":"index","type":"uint256"}],"name":"getRoleMember","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleMemberCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"grantRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"hasRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"callerConfirmation","type":"address"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"revokeRole","outputs":[],"stateMutability":"nonpayable","type":"function"}],"userDoc":{"kind":"user","methods":{},"version":1},"developerDoc":{"details":"External interface of AccessControlEnumerable declared to support ERC165 detection.","errors":{"AccessControlBadConfirmation()":[{"details":"The caller of a function is not the expected one. NOTE: Don't confuse with {AccessControlUnauthorizedAccount}."}],"AccessControlUnauthorizedAccount(address,bytes32)":[{"details":"The `account` is missing a role."}]},"events":{"RoleAdminChanged(bytes32,bytes32,bytes32)":{"details":"Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole` `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite {RoleAdminChanged} not being emitted signaling this."},"RoleGranted(bytes32,address,address)":{"details":"Emitted when `account` is granted `role`. `sender` is the account that originated the contract call, an admin role bearer except when using {AccessControl-_setupRole}."},"RoleRevoked(bytes32,address,address)":{"details":"Emitted when `account` is revoked `role`. `sender` is the account that originated the contract call: - if using `revokeRole`, it is the admin role bearer - if using `renounceRole`, it is the role bearer (i.e. `account`)"}},"kind":"dev","methods":{"getRoleAdmin(bytes32)":{"details":"Returns the admin role that controls `role`. See {grantRole} and {revokeRole}. To change a role's admin, use {AccessControl-_setRoleAdmin}."},"getRoleMember(bytes32,uint256)":{"details":"Returns one of the accounts that have `role`. `index` must be a value between 0 and {getRoleMemberCount}, non-inclusive. Role bearers are not sorted in any particular way, and their ordering may change at any point. WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure you perform all queries on the same block. See the following https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post] for more information."},"getRoleMemberCount(bytes32)":{"details":"Returns the number of accounts that have `role`. Can be used together with {getRoleMember} to enumerate all bearers of a role."},"grantRole(bytes32,address)":{"details":"Grants `role` to `account`. If `account` had not been already granted `role`, emits a {RoleGranted} event. Requirements: - the caller must have ``role``'s admin role."},"hasRole(bytes32,address)":{"details":"Returns `true` if `account` has been granted `role`."},"renounceRole(bytes32,address)":{"details":"Revokes `role` from the calling account. Roles are often managed via {grantRole} and {revokeRole}: this function's purpose is to provide a mechanism for accounts to lose their privileges if they are compromised (such as when a trusted device is misplaced). If the calling account had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must be `callerConfirmation`."},"revokeRole(bytes32,address)":{"details":"Revokes `role` from `account`. If `account` had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must have ``role``'s admin role."}},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.20+commit.a1b79de6\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[],\"name\":\"AccessControlBadConfirmation\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"neededRole\",\"type\":\"bytes32\"}],\"name\":\"AccessControlUnauthorizedAccount\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"previousAdminRole\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"newAdminRole\",\"type\":\"bytes32\"}],\"name\":\"RoleAdminChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleGranted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleRevoked\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"}],\"name\":\"getRoleAdmin\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"index\",\"type\":\"uint256\"}],\"name\":\"getRoleMember\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"}],\"name\":\"getRoleMemberCount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"grantRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"hasRole\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"callerConfirmation\",\"type\":\"address\"}],\"name\":\"renounceRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"revokeRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"details\":\"External interface of AccessControlEnumerable declared to support ERC165 detection.\",\"errors\":{\"AccessControlBadConfirmation()\":[{\"details\":\"The caller of a function is not the expected one. NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\"}],\"AccessControlUnauthorizedAccount(address,bytes32)\":[{\"details\":\"The `account` is missing a role.\"}]},\"events\":{\"RoleAdminChanged(bytes32,bytes32,bytes32)\":{\"details\":\"Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole` `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite {RoleAdminChanged} not being emitted signaling this.\"},\"RoleGranted(bytes32,address,address)\":{\"details\":\"Emitted when `account` is granted `role`. `sender` is the account that originated the contract call, an admin role bearer except when using {AccessControl-_setupRole}.\"},\"RoleRevoked(bytes32,address,address)\":{\"details\":\"Emitted when `account` is revoked `role`. `sender` is the account that originated the contract call: - if using `revokeRole`, it is the admin role bearer - if using `renounceRole`, it is the role bearer (i.e. `account`)\"}},\"kind\":\"dev\",\"methods\":{\"getRoleAdmin(bytes32)\":{\"details\":\"Returns the admin role that controls `role`. See {grantRole} and {revokeRole}. To change a role's admin, use {AccessControl-_setRoleAdmin}.\"},\"getRoleMember(bytes32,uint256)\":{\"details\":\"Returns one of the accounts that have `role`. `index` must be a value between 0 and {getRoleMemberCount}, non-inclusive. Role bearers are not sorted in any particular way, and their ordering may change at any point. WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure you perform all queries on the same block. See the following https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post] for more information.\"},\"getRoleMemberCount(bytes32)\":{\"details\":\"Returns the number of accounts that have `role`. Can be used together with {getRoleMember} to enumerate all bearers of a role.\"},\"grantRole(bytes32,address)\":{\"details\":\"Grants `role` to `account`. If `account` had not been already granted `role`, emits a {RoleGranted} event. Requirements: - the caller must have ``role``'s admin role.\"},\"hasRole(bytes32,address)\":{\"details\":\"Returns `true` if `account` has been granted `role`.\"},\"renounceRole(bytes32,address)\":{\"details\":\"Revokes `role` from the calling account. Roles are often managed via {grantRole} and {revokeRole}: this function's purpose is to provide a mechanism for accounts to lose their privileges if they are compromised (such as when a trusted device is misplaced). If the calling account had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must be `callerConfirmation`.\"},\"revokeRole(bytes32,address)\":{\"details\":\"Revokes `role` from `account`. If `account` had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must have ``role``'s admin role.\"}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeMock.sol\":\"IAccessControlEnumerable\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeMock.sol\":{\"keccak256\":\"0x620e81214ecd324ae8b971219291f176c454ce76fb1c01d656428096da8f1366\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://18e556772c12e13aa2d52a50cc7c48e676c8d5af22b90adaf7befb39cdd08e64\",\"dweb:/ipfs/QmPrQc98TxHCFMeuFNADyjr6Nqo52rHhHy1LBcsVdMRXjL\"]}},\"version\":1}"},"hashes":{"getRoleAdmin(bytes32)":"248a9ca3","getRoleMember(bytes32,uint256)":"9010d07c","getRoleMemberCount(bytes32)":"ca15c873","grantRole(bytes32,address)":"2f2ff15d","hasRole(bytes32,address)":"91d14854","renounceRole(bytes32,address)":"36568abe","revokeRole(bytes32,address)":"d547741f"}},"solidity/FastBridgeMock.sol:IAdmin":{"code":"0x","runtime-code":"0x","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.20 ^0.8.20;\n\n// contracts/interfaces/IAdmin.sol\n\ninterface IAdmin {\n // ============ Events ============\n\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n event ChainGasAmountUpdated(uint256 oldChainGasAmount, uint256 newChainGasAmount);\n\n // ============ Methods ============\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n\n function setChainGasAmount(uint256 newChainGasAmount) external;\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/libs/Errors.sol\n\nerror DeadlineExceeded();\nerror DeadlineNotExceeded();\nerror DeadlineTooShort();\nerror InsufficientOutputAmount();\n\nerror MsgValueIncorrect();\nerror PoolNotFound();\nerror TokenAddressMismatch();\nerror TokenNotContract();\nerror TokenNotETH();\nerror TokensIdentical();\n\nerror ChainIncorrect();\nerror AmountIncorrect();\nerror ZeroAddress();\n\nerror DisputePeriodNotPassed();\nerror DisputePeriodPassed();\nerror SenderIncorrect();\nerror StatusIncorrect();\nerror TransactionIdIncorrect();\nerror TransactionRelayed();\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// contracts/libs/UniversalToken.sol\n\nlibrary UniversalTokenLib {\n using SafeERC20 for IERC20;\n\n address internal constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Transfers tokens to the given account. Reverts if transfer is not successful.\n /// @dev This might trigger fallback, if ETH is transferred to the contract.\n /// Make sure this can not lead to reentrancy attacks.\n function universalTransfer(address token, address to, uint256 value) internal {\n // Don't do anything, if need to send tokens to this address\n if (to == address(this)) return;\n // Don't do anything, if trying to send zero value\n if (value == 0) return;\n if (token == ETH_ADDRESS) {\n /// @dev Note: this can potentially lead to executing code in `to`.\n // solhint-disable-next-line avoid-low-level-calls\n (bool success,) = to.call{value: value}(\"\");\n require(success, \"ETH transfer failed\");\n } else {\n IERC20(token).safeTransfer(to, value);\n }\n }\n\n /// @notice Issues an infinite allowance to the spender, if the current allowance is insufficient\n /// to spend the given amount.\n function universalApproveInfinity(address token, address spender, uint256 amountToSpend) internal {\n // ETH Chad doesn't require your approval\n if (token == ETH_ADDRESS) return;\n // No-op if allowance is already sufficient\n uint256 allowance = IERC20(token).allowance(address(this), spender);\n if (allowance \u003e= amountToSpend) return;\n // Otherwise, reset approval to 0 and set to max allowance\n if (allowance \u003e 0) IERC20(token).safeDecreaseAllowance(spender, allowance);\n IERC20(token).safeIncreaseAllowance(spender, type(uint256).max);\n }\n\n /// @notice Returns the balance of the given token (or native ETH) for the given account.\n function universalBalanceOf(address token, address account) internal view returns (uint256) {\n if (token == ETH_ADDRESS) {\n return account.balance;\n } else {\n return IERC20(token).balanceOf(account);\n }\n }\n\n /// @dev Checks that token is a contract and not ETH_ADDRESS.\n function assertIsContract(address token) internal view {\n // Check that ETH_ADDRESS was not used (in case this is a predeploy on any of the chains)\n if (token == UniversalTokenLib.ETH_ADDRESS) revert TokenNotContract();\n // Check that token is not an EOA\n if (token.code.length == 0) revert TokenNotContract();\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/Admin.sol\n\ncontract Admin is IAdmin, AccessControlEnumerable {\n using UniversalTokenLib for address;\n\n bytes32 public constant RELAYER_ROLE = keccak256(\"RELAYER_ROLE\");\n bytes32 public constant REFUNDER_ROLE = keccak256(\"REFUNDER_ROLE\");\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n uint256 public constant FEE_BPS = 1e6;\n uint256 public constant FEE_RATE_MAX = 0.01e6; // max 1% on origin amount\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Chain gas amount to forward as rebate if requested\n uint256 public chainGasAmount;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n }\n\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n require(newFeeRate \u003c= FEE_RATE_MAX, \"newFeeRate \u003e max\");\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n token.universalTransfer(recipient, feeAmount);\n emit FeesSwept(token, recipient, feeAmount);\n }\n\n function setChainGasAmount(uint256 newChainGasAmount) external onlyRole(GOVERNOR_ROLE) {\n uint256 oldChainGasAmount = chainGasAmount;\n chainGasAmount = newChainGasAmount;\n emit ChainGasAmountUpdated(oldChainGasAmount, newChainGasAmount);\n }\n}\n\n// contracts/FastBridge.sol\n\ncontract FastBridge is IFastBridge, Admin {\n using SafeERC20 for IERC20;\n using UniversalTokenLib for address;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Delay for a transaction after which it could be permisionlessly refunded\n uint256 public constant REFUND_DELAY = 7 days;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeStatus) public bridgeStatuses;\n /// @notice Proof of relayed bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeProof) public bridgeProofs;\n /// @notice Whether bridge has been relayed on destination chain\n mapping(bytes32 =\u003e bool) public bridgeRelays;\n\n /// @dev to prevent replays\n uint256 public nonce;\n // @dev the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @notice Pulls a requested token from the user to the requested recipient.\n /// @dev Be careful of re-entrancy issues when msg.value \u003e 0 and recipient != address(this)\n function _pullToken(address recipient, address token, uint256 amount) internal returns (uint256 amountPulled) {\n if (token != UniversalTokenLib.ETH_ADDRESS) {\n token.assertIsContract();\n // Record token balance before transfer\n amountPulled = IERC20(token).balanceOf(recipient);\n // Token needs to be pulled only if msg.value is zero\n // This way user can specify WETH as the origin asset\n IERC20(token).safeTransferFrom(msg.sender, recipient, amount);\n // Use the difference between the recorded balance and the current balance as the amountPulled\n amountPulled = IERC20(token).balanceOf(recipient) - amountPulled;\n } else {\n // Otherwise, we need to check that ETH amount matches msg.value\n if (amount != msg.value) revert MsgValueIncorrect();\n // Transfer value to recipient if not this address\n if (recipient != address(this)) token.universalTransfer(recipient, amount);\n // We will forward msg.value in the external call later, if recipient is not this contract\n amountPulled = msg.value;\n }\n }\n\n /// @inheritdoc IFastBridge\n function getBridgeTransaction(bytes memory request) public pure returns (BridgeTransaction memory) {\n return abi.decode(request, (BridgeTransaction));\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n // check bridge params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n\n // transfer tokens to bridge contract\n // @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _pullToken(address(this), params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n\n // set status to requested\n bytes memory request = abi.encode(\n BridgeTransaction({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n sendChainGas: params.sendChainGas,\n deadline: params.deadline,\n nonce: nonce++ // increment nonce on every bridge\n })\n );\n bytes32 transactionId = keccak256(request);\n bridgeStatuses[transactionId] = BridgeStatus.REQUESTED;\n\n emit BridgeRequested(\n transactionId,\n params.sender,\n request,\n params.dstChainId,\n params.originToken,\n params.destToken,\n originAmount,\n params.destAmount,\n params.sendChainGas\n );\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes memory request) external payable onlyRole(RELAYER_ROLE) {\n bytes32 transactionId = keccak256(request);\n BridgeTransaction memory transaction = getBridgeTransaction(request);\n if (transaction.destChainId != uint32(block.chainid)) revert ChainIncorrect();\n\n // check haven't exceeded deadline for relay to happen\n if (block.timestamp \u003e transaction.deadline) revert DeadlineExceeded();\n\n // mark bridge transaction as relayed\n if (bridgeRelays[transactionId]) revert TransactionRelayed();\n bridgeRelays[transactionId] = true;\n\n // transfer tokens to recipient on destination chain and gas rebate if requested\n address to = transaction.destRecipient;\n address token = transaction.destToken;\n uint256 amount = transaction.destAmount;\n\n uint256 rebate = chainGasAmount;\n if (!transaction.sendChainGas) {\n // forward erc20\n rebate = 0;\n _pullToken(to, token, amount);\n } else if (token == UniversalTokenLib.ETH_ADDRESS) {\n // lump in gas rebate into amount in native gas token\n _pullToken(to, token, amount + rebate);\n } else {\n // forward erc20 then forward gas rebate in native gas token\n _pullToken(to, token, amount);\n _pullToken(to, UniversalTokenLib.ETH_ADDRESS, rebate);\n }\n\n emit BridgeRelayed(\n transactionId,\n msg.sender,\n to,\n transaction.originChainId,\n transaction.originToken,\n transaction.destToken,\n transaction.originAmount,\n transaction.destAmount,\n rebate\n );\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes memory request, bytes32 destTxHash) external onlyRole(RELAYER_ROLE) {\n bytes32 transactionId = keccak256(request);\n // update bridge tx status given proof provided\n if (bridgeStatuses[transactionId] != BridgeStatus.REQUESTED) revert StatusIncorrect();\n bridgeStatuses[transactionId] = BridgeStatus.RELAYER_PROVED;\n bridgeProofs[transactionId] = BridgeProof({timestamp: uint96(block.timestamp), relayer: msg.sender}); // overflow ok\n\n emit BridgeProofProvided(transactionId, msg.sender, destTxHash);\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint96(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint96).max but\n /// proof.timestamp \u003c type(uint96).max via unchecked statement\n /// @param proof The bridge proof\n /// @return delta Time delta since proof submitted\n function _timeSince(BridgeProof memory proof) internal view returns (uint256 delta) {\n unchecked {\n delta = uint96(block.timestamp) - proof.timestamp;\n }\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n if (bridgeStatuses[transactionId] != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n BridgeProof memory proof = bridgeProofs[transactionId];\n if (proof.relayer != relayer) revert SenderIncorrect();\n return _timeSince(proof) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes memory request, address to) external onlyRole(RELAYER_ROLE) {\n bytes32 transactionId = keccak256(request);\n BridgeTransaction memory transaction = getBridgeTransaction(request);\n\n // update bridge tx status if able to claim origin collateral\n if (bridgeStatuses[transactionId] != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n\n BridgeProof memory proof = bridgeProofs[transactionId];\n if (proof.relayer != msg.sender) revert SenderIncorrect();\n if (_timeSince(proof) \u003c= DISPUTE_PERIOD) revert DisputePeriodNotPassed();\n\n bridgeStatuses[transactionId] = BridgeStatus.RELAYER_CLAIMED;\n\n // update protocol fees if origin fee amount exists\n if (transaction.originFeeAmount \u003e 0) protocolFees[transaction.originToken] += transaction.originFeeAmount;\n\n // transfer origin collateral less fee to specified address\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositClaimed(transactionId, msg.sender, to, token, amount);\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n if (bridgeStatuses[transactionId] != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(bridgeProofs[transactionId]) \u003e DISPUTE_PERIOD) revert DisputePeriodPassed();\n\n // @dev relayer gets slashed effectively if dest relay has gone thru\n bridgeStatuses[transactionId] = BridgeStatus.REQUESTED;\n delete bridgeProofs[transactionId];\n\n emit BridgeProofDisputed(transactionId, msg.sender);\n }\n\n /// @inheritdoc IFastBridge\n function refund(bytes memory request) external {\n bytes32 transactionId = keccak256(request);\n BridgeTransaction memory transaction = getBridgeTransaction(request);\n\n if (hasRole(REFUNDER_ROLE, msg.sender)) {\n // Refunder can refund if deadline has passed\n if (block.timestamp \u003c= transaction.deadline) revert DeadlineNotExceeded();\n } else {\n // Permissionless refund is allowed after REFUND_DELAY\n if (block.timestamp \u003c= transaction.deadline + REFUND_DELAY) revert DeadlineNotExceeded();\n }\n\n // set status to refunded if still in requested state\n if (bridgeStatuses[transactionId] != BridgeStatus.REQUESTED) revert StatusIncorrect();\n bridgeStatuses[transactionId] = BridgeStatus.REFUNDED;\n\n // transfer origin collateral back to original sender\n address to = transaction.originSender;\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount + transaction.originFeeAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n }\n}\n\n// test/FastBridgeMock.sol\n\ncontract FastBridgeMock is IFastBridge, Admin {\n // @dev the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @dev to prevent replays\n uint256 public nonce;\n\n function getBridgeTransaction(bytes memory request) public pure returns (BridgeTransaction memory) {\n return abi.decode(request, (BridgeTransaction));\n }\n\n // used for testing in go.\n // see: https://ethereum.stackexchange.com/questions/21155/how-to-expose-enum-in-solidity-contract\n // make sure to update fastbridge/status.go if this changes\n // or underliyng enum changes.\n //\n // TODO: a foundry test should be added to ensure this is always in sync.\n function getEnumKeyByValue(FastBridge.BridgeStatus keyValue) public pure returns (string memory) {\n if (FastBridge.BridgeStatus.NULL == keyValue) return \"NULL\";\n if (FastBridge.BridgeStatus.REQUESTED == keyValue) return \"REQUESTED\";\n if (FastBridge.BridgeStatus.RELAYER_PROVED == keyValue) return \"RELAYER_PROVED\";\n if (FastBridge.BridgeStatus.RELAYER_CLAIMED == keyValue) return \"RELAYER_CLAIMED\";\n if (FastBridge.BridgeStatus.REFUNDED == keyValue) return \"REFUNDED\";\n return \"\";\n }\n\n function mockBridgeRequest(bytes32 transactionId, address sender, BridgeParams memory params) external {\n uint256 originFeeAmount = (params.originAmount * protocolFeeRate) / FEE_BPS;\n params.originAmount -= originFeeAmount;\n\n bytes memory request = abi.encode(\n BridgeTransaction({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: params.originAmount, // includes relayer fee\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n sendChainGas: params.sendChainGas,\n deadline: params.deadline,\n nonce: nonce++ // increment nonce on every bridge\n })\n );\n\n emit BridgeRequested(\n transactionId,\n params.sender,\n request,\n params.dstChainId,\n params.originToken,\n params.destToken,\n params.originAmount,\n params.destAmount,\n params.sendChainGas\n );\n }\n\n function mockBridgeRequestRaw(bytes32 transactionId, address sender, bytes memory request) external {\n BridgeTransaction memory transaction = getBridgeTransaction(request);\n emit BridgeRequested(\n transactionId,\n transaction.originSender,\n request,\n transaction.destChainId,\n transaction.originToken,\n transaction.destToken,\n transaction.originAmount,\n transaction.destAmount,\n transaction.sendChainGas\n );\n }\n\n function mockBridgeRelayer(\n bytes32 transactionId,\n address relayer,\n address to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n )\n external\n {\n emit BridgeRelayed(\n transactionId, relayer, to, originChainId, originToken, destToken, originAmount, destAmount, chainGasAmount\n );\n }\n\n function bridge(BridgeParams memory params) external payable {\n revert(\"not implemented\");\n }\n\n function relay(bytes memory request) external payable {\n revert(\"not implemented\");\n }\n\n function prove(bytes memory request, bytes32 destTxHash) external {\n revert(\"not implemented\");\n }\n\n function canClaim(bytes32 transactionid, address relayer) external view returns (bool) {\n revert(\"not implemented\");\n }\n\n function claim(bytes memory request, address to) external {\n revert(\"not implemented\");\n }\n\n function dispute(bytes32 transactionId) external {\n revert(\"not implemented\");\n }\n\n function refund(bytes memory request) external {\n revert(\"not implemented\");\n }\n}\n","language":"Solidity","languageVersion":"0.8.20","compilerVersion":"0.8.20","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"","srcMapRuntime":"","abiDefinition":[{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldChainGasAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newChainGasAmount","type":"uint256"}],"name":"ChainGasAmountUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldFeeRate","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newFeeRate","type":"uint256"}],"name":"FeeRateUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"address","name":"recipient","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"FeesSwept","type":"event"},{"inputs":[{"internalType":"uint256","name":"newChainGasAmount","type":"uint256"}],"name":"setChainGasAmount","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"newFeeRate","type":"uint256"}],"name":"setProtocolFeeRate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"address","name":"recipient","type":"address"}],"name":"sweepProtocolFees","outputs":[],"stateMutability":"nonpayable","type":"function"}],"userDoc":{"kind":"user","methods":{},"version":1},"developerDoc":{"kind":"dev","methods":{},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.20+commit.a1b79de6\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"oldChainGasAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newChainGasAmount\",\"type\":\"uint256\"}],\"name\":\"ChainGasAmountUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"oldFeeRate\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newFeeRate\",\"type\":\"uint256\"}],\"name\":\"FeeRateUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"FeesSwept\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"newChainGasAmount\",\"type\":\"uint256\"}],\"name\":\"setChainGasAmount\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"newFeeRate\",\"type\":\"uint256\"}],\"name\":\"setProtocolFeeRate\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"}],\"name\":\"sweepProtocolFees\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeMock.sol\":\"IAdmin\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeMock.sol\":{\"keccak256\":\"0x620e81214ecd324ae8b971219291f176c454ce76fb1c01d656428096da8f1366\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://18e556772c12e13aa2d52a50cc7c48e676c8d5af22b90adaf7befb39cdd08e64\",\"dweb:/ipfs/QmPrQc98TxHCFMeuFNADyjr6Nqo52rHhHy1LBcsVdMRXjL\"]}},\"version\":1}"},"hashes":{"setChainGasAmount(uint256)":"b250fe6b","setProtocolFeeRate(uint256)":"b13aa2d6","sweepProtocolFees(address,address)":"06f333f2"}},"solidity/FastBridgeMock.sol:IERC165":{"code":"0x","runtime-code":"0x","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.20 ^0.8.20;\n\n// contracts/interfaces/IAdmin.sol\n\ninterface IAdmin {\n // ============ Events ============\n\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n event ChainGasAmountUpdated(uint256 oldChainGasAmount, uint256 newChainGasAmount);\n\n // ============ Methods ============\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n\n function setChainGasAmount(uint256 newChainGasAmount) external;\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/libs/Errors.sol\n\nerror DeadlineExceeded();\nerror DeadlineNotExceeded();\nerror DeadlineTooShort();\nerror InsufficientOutputAmount();\n\nerror MsgValueIncorrect();\nerror PoolNotFound();\nerror TokenAddressMismatch();\nerror TokenNotContract();\nerror TokenNotETH();\nerror TokensIdentical();\n\nerror ChainIncorrect();\nerror AmountIncorrect();\nerror ZeroAddress();\n\nerror DisputePeriodNotPassed();\nerror DisputePeriodPassed();\nerror SenderIncorrect();\nerror StatusIncorrect();\nerror TransactionIdIncorrect();\nerror TransactionRelayed();\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// contracts/libs/UniversalToken.sol\n\nlibrary UniversalTokenLib {\n using SafeERC20 for IERC20;\n\n address internal constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Transfers tokens to the given account. Reverts if transfer is not successful.\n /// @dev This might trigger fallback, if ETH is transferred to the contract.\n /// Make sure this can not lead to reentrancy attacks.\n function universalTransfer(address token, address to, uint256 value) internal {\n // Don't do anything, if need to send tokens to this address\n if (to == address(this)) return;\n // Don't do anything, if trying to send zero value\n if (value == 0) return;\n if (token == ETH_ADDRESS) {\n /// @dev Note: this can potentially lead to executing code in `to`.\n // solhint-disable-next-line avoid-low-level-calls\n (bool success,) = to.call{value: value}(\"\");\n require(success, \"ETH transfer failed\");\n } else {\n IERC20(token).safeTransfer(to, value);\n }\n }\n\n /// @notice Issues an infinite allowance to the spender, if the current allowance is insufficient\n /// to spend the given amount.\n function universalApproveInfinity(address token, address spender, uint256 amountToSpend) internal {\n // ETH Chad doesn't require your approval\n if (token == ETH_ADDRESS) return;\n // No-op if allowance is already sufficient\n uint256 allowance = IERC20(token).allowance(address(this), spender);\n if (allowance \u003e= amountToSpend) return;\n // Otherwise, reset approval to 0 and set to max allowance\n if (allowance \u003e 0) IERC20(token).safeDecreaseAllowance(spender, allowance);\n IERC20(token).safeIncreaseAllowance(spender, type(uint256).max);\n }\n\n /// @notice Returns the balance of the given token (or native ETH) for the given account.\n function universalBalanceOf(address token, address account) internal view returns (uint256) {\n if (token == ETH_ADDRESS) {\n return account.balance;\n } else {\n return IERC20(token).balanceOf(account);\n }\n }\n\n /// @dev Checks that token is a contract and not ETH_ADDRESS.\n function assertIsContract(address token) internal view {\n // Check that ETH_ADDRESS was not used (in case this is a predeploy on any of the chains)\n if (token == UniversalTokenLib.ETH_ADDRESS) revert TokenNotContract();\n // Check that token is not an EOA\n if (token.code.length == 0) revert TokenNotContract();\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/Admin.sol\n\ncontract Admin is IAdmin, AccessControlEnumerable {\n using UniversalTokenLib for address;\n\n bytes32 public constant RELAYER_ROLE = keccak256(\"RELAYER_ROLE\");\n bytes32 public constant REFUNDER_ROLE = keccak256(\"REFUNDER_ROLE\");\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n uint256 public constant FEE_BPS = 1e6;\n uint256 public constant FEE_RATE_MAX = 0.01e6; // max 1% on origin amount\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Chain gas amount to forward as rebate if requested\n uint256 public chainGasAmount;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n }\n\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n require(newFeeRate \u003c= FEE_RATE_MAX, \"newFeeRate \u003e max\");\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n token.universalTransfer(recipient, feeAmount);\n emit FeesSwept(token, recipient, feeAmount);\n }\n\n function setChainGasAmount(uint256 newChainGasAmount) external onlyRole(GOVERNOR_ROLE) {\n uint256 oldChainGasAmount = chainGasAmount;\n chainGasAmount = newChainGasAmount;\n emit ChainGasAmountUpdated(oldChainGasAmount, newChainGasAmount);\n }\n}\n\n// contracts/FastBridge.sol\n\ncontract FastBridge is IFastBridge, Admin {\n using SafeERC20 for IERC20;\n using UniversalTokenLib for address;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Delay for a transaction after which it could be permisionlessly refunded\n uint256 public constant REFUND_DELAY = 7 days;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeStatus) public bridgeStatuses;\n /// @notice Proof of relayed bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeProof) public bridgeProofs;\n /// @notice Whether bridge has been relayed on destination chain\n mapping(bytes32 =\u003e bool) public bridgeRelays;\n\n /// @dev to prevent replays\n uint256 public nonce;\n // @dev the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @notice Pulls a requested token from the user to the requested recipient.\n /// @dev Be careful of re-entrancy issues when msg.value \u003e 0 and recipient != address(this)\n function _pullToken(address recipient, address token, uint256 amount) internal returns (uint256 amountPulled) {\n if (token != UniversalTokenLib.ETH_ADDRESS) {\n token.assertIsContract();\n // Record token balance before transfer\n amountPulled = IERC20(token).balanceOf(recipient);\n // Token needs to be pulled only if msg.value is zero\n // This way user can specify WETH as the origin asset\n IERC20(token).safeTransferFrom(msg.sender, recipient, amount);\n // Use the difference between the recorded balance and the current balance as the amountPulled\n amountPulled = IERC20(token).balanceOf(recipient) - amountPulled;\n } else {\n // Otherwise, we need to check that ETH amount matches msg.value\n if (amount != msg.value) revert MsgValueIncorrect();\n // Transfer value to recipient if not this address\n if (recipient != address(this)) token.universalTransfer(recipient, amount);\n // We will forward msg.value in the external call later, if recipient is not this contract\n amountPulled = msg.value;\n }\n }\n\n /// @inheritdoc IFastBridge\n function getBridgeTransaction(bytes memory request) public pure returns (BridgeTransaction memory) {\n return abi.decode(request, (BridgeTransaction));\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n // check bridge params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n\n // transfer tokens to bridge contract\n // @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _pullToken(address(this), params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n\n // set status to requested\n bytes memory request = abi.encode(\n BridgeTransaction({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n sendChainGas: params.sendChainGas,\n deadline: params.deadline,\n nonce: nonce++ // increment nonce on every bridge\n })\n );\n bytes32 transactionId = keccak256(request);\n bridgeStatuses[transactionId] = BridgeStatus.REQUESTED;\n\n emit BridgeRequested(\n transactionId,\n params.sender,\n request,\n params.dstChainId,\n params.originToken,\n params.destToken,\n originAmount,\n params.destAmount,\n params.sendChainGas\n );\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes memory request) external payable onlyRole(RELAYER_ROLE) {\n bytes32 transactionId = keccak256(request);\n BridgeTransaction memory transaction = getBridgeTransaction(request);\n if (transaction.destChainId != uint32(block.chainid)) revert ChainIncorrect();\n\n // check haven't exceeded deadline for relay to happen\n if (block.timestamp \u003e transaction.deadline) revert DeadlineExceeded();\n\n // mark bridge transaction as relayed\n if (bridgeRelays[transactionId]) revert TransactionRelayed();\n bridgeRelays[transactionId] = true;\n\n // transfer tokens to recipient on destination chain and gas rebate if requested\n address to = transaction.destRecipient;\n address token = transaction.destToken;\n uint256 amount = transaction.destAmount;\n\n uint256 rebate = chainGasAmount;\n if (!transaction.sendChainGas) {\n // forward erc20\n rebate = 0;\n _pullToken(to, token, amount);\n } else if (token == UniversalTokenLib.ETH_ADDRESS) {\n // lump in gas rebate into amount in native gas token\n _pullToken(to, token, amount + rebate);\n } else {\n // forward erc20 then forward gas rebate in native gas token\n _pullToken(to, token, amount);\n _pullToken(to, UniversalTokenLib.ETH_ADDRESS, rebate);\n }\n\n emit BridgeRelayed(\n transactionId,\n msg.sender,\n to,\n transaction.originChainId,\n transaction.originToken,\n transaction.destToken,\n transaction.originAmount,\n transaction.destAmount,\n rebate\n );\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes memory request, bytes32 destTxHash) external onlyRole(RELAYER_ROLE) {\n bytes32 transactionId = keccak256(request);\n // update bridge tx status given proof provided\n if (bridgeStatuses[transactionId] != BridgeStatus.REQUESTED) revert StatusIncorrect();\n bridgeStatuses[transactionId] = BridgeStatus.RELAYER_PROVED;\n bridgeProofs[transactionId] = BridgeProof({timestamp: uint96(block.timestamp), relayer: msg.sender}); // overflow ok\n\n emit BridgeProofProvided(transactionId, msg.sender, destTxHash);\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint96(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint96).max but\n /// proof.timestamp \u003c type(uint96).max via unchecked statement\n /// @param proof The bridge proof\n /// @return delta Time delta since proof submitted\n function _timeSince(BridgeProof memory proof) internal view returns (uint256 delta) {\n unchecked {\n delta = uint96(block.timestamp) - proof.timestamp;\n }\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n if (bridgeStatuses[transactionId] != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n BridgeProof memory proof = bridgeProofs[transactionId];\n if (proof.relayer != relayer) revert SenderIncorrect();\n return _timeSince(proof) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes memory request, address to) external onlyRole(RELAYER_ROLE) {\n bytes32 transactionId = keccak256(request);\n BridgeTransaction memory transaction = getBridgeTransaction(request);\n\n // update bridge tx status if able to claim origin collateral\n if (bridgeStatuses[transactionId] != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n\n BridgeProof memory proof = bridgeProofs[transactionId];\n if (proof.relayer != msg.sender) revert SenderIncorrect();\n if (_timeSince(proof) \u003c= DISPUTE_PERIOD) revert DisputePeriodNotPassed();\n\n bridgeStatuses[transactionId] = BridgeStatus.RELAYER_CLAIMED;\n\n // update protocol fees if origin fee amount exists\n if (transaction.originFeeAmount \u003e 0) protocolFees[transaction.originToken] += transaction.originFeeAmount;\n\n // transfer origin collateral less fee to specified address\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositClaimed(transactionId, msg.sender, to, token, amount);\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n if (bridgeStatuses[transactionId] != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(bridgeProofs[transactionId]) \u003e DISPUTE_PERIOD) revert DisputePeriodPassed();\n\n // @dev relayer gets slashed effectively if dest relay has gone thru\n bridgeStatuses[transactionId] = BridgeStatus.REQUESTED;\n delete bridgeProofs[transactionId];\n\n emit BridgeProofDisputed(transactionId, msg.sender);\n }\n\n /// @inheritdoc IFastBridge\n function refund(bytes memory request) external {\n bytes32 transactionId = keccak256(request);\n BridgeTransaction memory transaction = getBridgeTransaction(request);\n\n if (hasRole(REFUNDER_ROLE, msg.sender)) {\n // Refunder can refund if deadline has passed\n if (block.timestamp \u003c= transaction.deadline) revert DeadlineNotExceeded();\n } else {\n // Permissionless refund is allowed after REFUND_DELAY\n if (block.timestamp \u003c= transaction.deadline + REFUND_DELAY) revert DeadlineNotExceeded();\n }\n\n // set status to refunded if still in requested state\n if (bridgeStatuses[transactionId] != BridgeStatus.REQUESTED) revert StatusIncorrect();\n bridgeStatuses[transactionId] = BridgeStatus.REFUNDED;\n\n // transfer origin collateral back to original sender\n address to = transaction.originSender;\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount + transaction.originFeeAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n }\n}\n\n// test/FastBridgeMock.sol\n\ncontract FastBridgeMock is IFastBridge, Admin {\n // @dev the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @dev to prevent replays\n uint256 public nonce;\n\n function getBridgeTransaction(bytes memory request) public pure returns (BridgeTransaction memory) {\n return abi.decode(request, (BridgeTransaction));\n }\n\n // used for testing in go.\n // see: https://ethereum.stackexchange.com/questions/21155/how-to-expose-enum-in-solidity-contract\n // make sure to update fastbridge/status.go if this changes\n // or underliyng enum changes.\n //\n // TODO: a foundry test should be added to ensure this is always in sync.\n function getEnumKeyByValue(FastBridge.BridgeStatus keyValue) public pure returns (string memory) {\n if (FastBridge.BridgeStatus.NULL == keyValue) return \"NULL\";\n if (FastBridge.BridgeStatus.REQUESTED == keyValue) return \"REQUESTED\";\n if (FastBridge.BridgeStatus.RELAYER_PROVED == keyValue) return \"RELAYER_PROVED\";\n if (FastBridge.BridgeStatus.RELAYER_CLAIMED == keyValue) return \"RELAYER_CLAIMED\";\n if (FastBridge.BridgeStatus.REFUNDED == keyValue) return \"REFUNDED\";\n return \"\";\n }\n\n function mockBridgeRequest(bytes32 transactionId, address sender, BridgeParams memory params) external {\n uint256 originFeeAmount = (params.originAmount * protocolFeeRate) / FEE_BPS;\n params.originAmount -= originFeeAmount;\n\n bytes memory request = abi.encode(\n BridgeTransaction({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: params.originAmount, // includes relayer fee\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n sendChainGas: params.sendChainGas,\n deadline: params.deadline,\n nonce: nonce++ // increment nonce on every bridge\n })\n );\n\n emit BridgeRequested(\n transactionId,\n params.sender,\n request,\n params.dstChainId,\n params.originToken,\n params.destToken,\n params.originAmount,\n params.destAmount,\n params.sendChainGas\n );\n }\n\n function mockBridgeRequestRaw(bytes32 transactionId, address sender, bytes memory request) external {\n BridgeTransaction memory transaction = getBridgeTransaction(request);\n emit BridgeRequested(\n transactionId,\n transaction.originSender,\n request,\n transaction.destChainId,\n transaction.originToken,\n transaction.destToken,\n transaction.originAmount,\n transaction.destAmount,\n transaction.sendChainGas\n );\n }\n\n function mockBridgeRelayer(\n bytes32 transactionId,\n address relayer,\n address to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n )\n external\n {\n emit BridgeRelayed(\n transactionId, relayer, to, originChainId, originToken, destToken, originAmount, destAmount, chainGasAmount\n );\n }\n\n function bridge(BridgeParams memory params) external payable {\n revert(\"not implemented\");\n }\n\n function relay(bytes memory request) external payable {\n revert(\"not implemented\");\n }\n\n function prove(bytes memory request, bytes32 destTxHash) external {\n revert(\"not implemented\");\n }\n\n function canClaim(bytes32 transactionid, address relayer) external view returns (bool) {\n revert(\"not implemented\");\n }\n\n function claim(bytes memory request, address to) external {\n revert(\"not implemented\");\n }\n\n function dispute(bytes32 transactionId) external {\n revert(\"not implemented\");\n }\n\n function refund(bytes memory request) external {\n revert(\"not implemented\");\n }\n}\n","language":"Solidity","languageVersion":"0.8.20","compilerVersion":"0.8.20","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"","srcMapRuntime":"","abiDefinition":[{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"}],"userDoc":{"kind":"user","methods":{},"version":1},"developerDoc":{"details":"Interface of the ERC165 standard, as defined in the https://eips.ethereum.org/EIPS/eip-165[EIP]. Implementers can declare support of contract interfaces, which can then be queried by others ({ERC165Checker}). For an implementation, see {ERC165}.","kind":"dev","methods":{"supportsInterface(bytes4)":{"details":"Returns true if this contract implements the interface defined by `interfaceId`. See the corresponding https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section] to learn more about how these ids are created. This function call must use less than 30 000 gas."}},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.20+commit.a1b79de6\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"bytes4\",\"name\":\"interfaceId\",\"type\":\"bytes4\"}],\"name\":\"supportsInterface\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"}],\"devdoc\":{\"details\":\"Interface of the ERC165 standard, as defined in the https://eips.ethereum.org/EIPS/eip-165[EIP]. Implementers can declare support of contract interfaces, which can then be queried by others ({ERC165Checker}). For an implementation, see {ERC165}.\",\"kind\":\"dev\",\"methods\":{\"supportsInterface(bytes4)\":{\"details\":\"Returns true if this contract implements the interface defined by `interfaceId`. See the corresponding https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section] to learn more about how these ids are created. This function call must use less than 30 000 gas.\"}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeMock.sol\":\"IERC165\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeMock.sol\":{\"keccak256\":\"0x620e81214ecd324ae8b971219291f176c454ce76fb1c01d656428096da8f1366\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://18e556772c12e13aa2d52a50cc7c48e676c8d5af22b90adaf7befb39cdd08e64\",\"dweb:/ipfs/QmPrQc98TxHCFMeuFNADyjr6Nqo52rHhHy1LBcsVdMRXjL\"]}},\"version\":1}"},"hashes":{"supportsInterface(bytes4)":"01ffc9a7"}},"solidity/FastBridgeMock.sol:IERC20":{"code":"0x","runtime-code":"0x","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.20 ^0.8.20;\n\n// contracts/interfaces/IAdmin.sol\n\ninterface IAdmin {\n // ============ Events ============\n\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n event ChainGasAmountUpdated(uint256 oldChainGasAmount, uint256 newChainGasAmount);\n\n // ============ Methods ============\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n\n function setChainGasAmount(uint256 newChainGasAmount) external;\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/libs/Errors.sol\n\nerror DeadlineExceeded();\nerror DeadlineNotExceeded();\nerror DeadlineTooShort();\nerror InsufficientOutputAmount();\n\nerror MsgValueIncorrect();\nerror PoolNotFound();\nerror TokenAddressMismatch();\nerror TokenNotContract();\nerror TokenNotETH();\nerror TokensIdentical();\n\nerror ChainIncorrect();\nerror AmountIncorrect();\nerror ZeroAddress();\n\nerror DisputePeriodNotPassed();\nerror DisputePeriodPassed();\nerror SenderIncorrect();\nerror StatusIncorrect();\nerror TransactionIdIncorrect();\nerror TransactionRelayed();\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// contracts/libs/UniversalToken.sol\n\nlibrary UniversalTokenLib {\n using SafeERC20 for IERC20;\n\n address internal constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Transfers tokens to the given account. Reverts if transfer is not successful.\n /// @dev This might trigger fallback, if ETH is transferred to the contract.\n /// Make sure this can not lead to reentrancy attacks.\n function universalTransfer(address token, address to, uint256 value) internal {\n // Don't do anything, if need to send tokens to this address\n if (to == address(this)) return;\n // Don't do anything, if trying to send zero value\n if (value == 0) return;\n if (token == ETH_ADDRESS) {\n /// @dev Note: this can potentially lead to executing code in `to`.\n // solhint-disable-next-line avoid-low-level-calls\n (bool success,) = to.call{value: value}(\"\");\n require(success, \"ETH transfer failed\");\n } else {\n IERC20(token).safeTransfer(to, value);\n }\n }\n\n /// @notice Issues an infinite allowance to the spender, if the current allowance is insufficient\n /// to spend the given amount.\n function universalApproveInfinity(address token, address spender, uint256 amountToSpend) internal {\n // ETH Chad doesn't require your approval\n if (token == ETH_ADDRESS) return;\n // No-op if allowance is already sufficient\n uint256 allowance = IERC20(token).allowance(address(this), spender);\n if (allowance \u003e= amountToSpend) return;\n // Otherwise, reset approval to 0 and set to max allowance\n if (allowance \u003e 0) IERC20(token).safeDecreaseAllowance(spender, allowance);\n IERC20(token).safeIncreaseAllowance(spender, type(uint256).max);\n }\n\n /// @notice Returns the balance of the given token (or native ETH) for the given account.\n function universalBalanceOf(address token, address account) internal view returns (uint256) {\n if (token == ETH_ADDRESS) {\n return account.balance;\n } else {\n return IERC20(token).balanceOf(account);\n }\n }\n\n /// @dev Checks that token is a contract and not ETH_ADDRESS.\n function assertIsContract(address token) internal view {\n // Check that ETH_ADDRESS was not used (in case this is a predeploy on any of the chains)\n if (token == UniversalTokenLib.ETH_ADDRESS) revert TokenNotContract();\n // Check that token is not an EOA\n if (token.code.length == 0) revert TokenNotContract();\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/Admin.sol\n\ncontract Admin is IAdmin, AccessControlEnumerable {\n using UniversalTokenLib for address;\n\n bytes32 public constant RELAYER_ROLE = keccak256(\"RELAYER_ROLE\");\n bytes32 public constant REFUNDER_ROLE = keccak256(\"REFUNDER_ROLE\");\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n uint256 public constant FEE_BPS = 1e6;\n uint256 public constant FEE_RATE_MAX = 0.01e6; // max 1% on origin amount\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Chain gas amount to forward as rebate if requested\n uint256 public chainGasAmount;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n }\n\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n require(newFeeRate \u003c= FEE_RATE_MAX, \"newFeeRate \u003e max\");\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n token.universalTransfer(recipient, feeAmount);\n emit FeesSwept(token, recipient, feeAmount);\n }\n\n function setChainGasAmount(uint256 newChainGasAmount) external onlyRole(GOVERNOR_ROLE) {\n uint256 oldChainGasAmount = chainGasAmount;\n chainGasAmount = newChainGasAmount;\n emit ChainGasAmountUpdated(oldChainGasAmount, newChainGasAmount);\n }\n}\n\n// contracts/FastBridge.sol\n\ncontract FastBridge is IFastBridge, Admin {\n using SafeERC20 for IERC20;\n using UniversalTokenLib for address;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Delay for a transaction after which it could be permisionlessly refunded\n uint256 public constant REFUND_DELAY = 7 days;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeStatus) public bridgeStatuses;\n /// @notice Proof of relayed bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeProof) public bridgeProofs;\n /// @notice Whether bridge has been relayed on destination chain\n mapping(bytes32 =\u003e bool) public bridgeRelays;\n\n /// @dev to prevent replays\n uint256 public nonce;\n // @dev the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @notice Pulls a requested token from the user to the requested recipient.\n /// @dev Be careful of re-entrancy issues when msg.value \u003e 0 and recipient != address(this)\n function _pullToken(address recipient, address token, uint256 amount) internal returns (uint256 amountPulled) {\n if (token != UniversalTokenLib.ETH_ADDRESS) {\n token.assertIsContract();\n // Record token balance before transfer\n amountPulled = IERC20(token).balanceOf(recipient);\n // Token needs to be pulled only if msg.value is zero\n // This way user can specify WETH as the origin asset\n IERC20(token).safeTransferFrom(msg.sender, recipient, amount);\n // Use the difference between the recorded balance and the current balance as the amountPulled\n amountPulled = IERC20(token).balanceOf(recipient) - amountPulled;\n } else {\n // Otherwise, we need to check that ETH amount matches msg.value\n if (amount != msg.value) revert MsgValueIncorrect();\n // Transfer value to recipient if not this address\n if (recipient != address(this)) token.universalTransfer(recipient, amount);\n // We will forward msg.value in the external call later, if recipient is not this contract\n amountPulled = msg.value;\n }\n }\n\n /// @inheritdoc IFastBridge\n function getBridgeTransaction(bytes memory request) public pure returns (BridgeTransaction memory) {\n return abi.decode(request, (BridgeTransaction));\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n // check bridge params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n\n // transfer tokens to bridge contract\n // @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _pullToken(address(this), params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n\n // set status to requested\n bytes memory request = abi.encode(\n BridgeTransaction({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n sendChainGas: params.sendChainGas,\n deadline: params.deadline,\n nonce: nonce++ // increment nonce on every bridge\n })\n );\n bytes32 transactionId = keccak256(request);\n bridgeStatuses[transactionId] = BridgeStatus.REQUESTED;\n\n emit BridgeRequested(\n transactionId,\n params.sender,\n request,\n params.dstChainId,\n params.originToken,\n params.destToken,\n originAmount,\n params.destAmount,\n params.sendChainGas\n );\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes memory request) external payable onlyRole(RELAYER_ROLE) {\n bytes32 transactionId = keccak256(request);\n BridgeTransaction memory transaction = getBridgeTransaction(request);\n if (transaction.destChainId != uint32(block.chainid)) revert ChainIncorrect();\n\n // check haven't exceeded deadline for relay to happen\n if (block.timestamp \u003e transaction.deadline) revert DeadlineExceeded();\n\n // mark bridge transaction as relayed\n if (bridgeRelays[transactionId]) revert TransactionRelayed();\n bridgeRelays[transactionId] = true;\n\n // transfer tokens to recipient on destination chain and gas rebate if requested\n address to = transaction.destRecipient;\n address token = transaction.destToken;\n uint256 amount = transaction.destAmount;\n\n uint256 rebate = chainGasAmount;\n if (!transaction.sendChainGas) {\n // forward erc20\n rebate = 0;\n _pullToken(to, token, amount);\n } else if (token == UniversalTokenLib.ETH_ADDRESS) {\n // lump in gas rebate into amount in native gas token\n _pullToken(to, token, amount + rebate);\n } else {\n // forward erc20 then forward gas rebate in native gas token\n _pullToken(to, token, amount);\n _pullToken(to, UniversalTokenLib.ETH_ADDRESS, rebate);\n }\n\n emit BridgeRelayed(\n transactionId,\n msg.sender,\n to,\n transaction.originChainId,\n transaction.originToken,\n transaction.destToken,\n transaction.originAmount,\n transaction.destAmount,\n rebate\n );\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes memory request, bytes32 destTxHash) external onlyRole(RELAYER_ROLE) {\n bytes32 transactionId = keccak256(request);\n // update bridge tx status given proof provided\n if (bridgeStatuses[transactionId] != BridgeStatus.REQUESTED) revert StatusIncorrect();\n bridgeStatuses[transactionId] = BridgeStatus.RELAYER_PROVED;\n bridgeProofs[transactionId] = BridgeProof({timestamp: uint96(block.timestamp), relayer: msg.sender}); // overflow ok\n\n emit BridgeProofProvided(transactionId, msg.sender, destTxHash);\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint96(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint96).max but\n /// proof.timestamp \u003c type(uint96).max via unchecked statement\n /// @param proof The bridge proof\n /// @return delta Time delta since proof submitted\n function _timeSince(BridgeProof memory proof) internal view returns (uint256 delta) {\n unchecked {\n delta = uint96(block.timestamp) - proof.timestamp;\n }\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n if (bridgeStatuses[transactionId] != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n BridgeProof memory proof = bridgeProofs[transactionId];\n if (proof.relayer != relayer) revert SenderIncorrect();\n return _timeSince(proof) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes memory request, address to) external onlyRole(RELAYER_ROLE) {\n bytes32 transactionId = keccak256(request);\n BridgeTransaction memory transaction = getBridgeTransaction(request);\n\n // update bridge tx status if able to claim origin collateral\n if (bridgeStatuses[transactionId] != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n\n BridgeProof memory proof = bridgeProofs[transactionId];\n if (proof.relayer != msg.sender) revert SenderIncorrect();\n if (_timeSince(proof) \u003c= DISPUTE_PERIOD) revert DisputePeriodNotPassed();\n\n bridgeStatuses[transactionId] = BridgeStatus.RELAYER_CLAIMED;\n\n // update protocol fees if origin fee amount exists\n if (transaction.originFeeAmount \u003e 0) protocolFees[transaction.originToken] += transaction.originFeeAmount;\n\n // transfer origin collateral less fee to specified address\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositClaimed(transactionId, msg.sender, to, token, amount);\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n if (bridgeStatuses[transactionId] != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(bridgeProofs[transactionId]) \u003e DISPUTE_PERIOD) revert DisputePeriodPassed();\n\n // @dev relayer gets slashed effectively if dest relay has gone thru\n bridgeStatuses[transactionId] = BridgeStatus.REQUESTED;\n delete bridgeProofs[transactionId];\n\n emit BridgeProofDisputed(transactionId, msg.sender);\n }\n\n /// @inheritdoc IFastBridge\n function refund(bytes memory request) external {\n bytes32 transactionId = keccak256(request);\n BridgeTransaction memory transaction = getBridgeTransaction(request);\n\n if (hasRole(REFUNDER_ROLE, msg.sender)) {\n // Refunder can refund if deadline has passed\n if (block.timestamp \u003c= transaction.deadline) revert DeadlineNotExceeded();\n } else {\n // Permissionless refund is allowed after REFUND_DELAY\n if (block.timestamp \u003c= transaction.deadline + REFUND_DELAY) revert DeadlineNotExceeded();\n }\n\n // set status to refunded if still in requested state\n if (bridgeStatuses[transactionId] != BridgeStatus.REQUESTED) revert StatusIncorrect();\n bridgeStatuses[transactionId] = BridgeStatus.REFUNDED;\n\n // transfer origin collateral back to original sender\n address to = transaction.originSender;\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount + transaction.originFeeAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n }\n}\n\n// test/FastBridgeMock.sol\n\ncontract FastBridgeMock is IFastBridge, Admin {\n // @dev the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @dev to prevent replays\n uint256 public nonce;\n\n function getBridgeTransaction(bytes memory request) public pure returns (BridgeTransaction memory) {\n return abi.decode(request, (BridgeTransaction));\n }\n\n // used for testing in go.\n // see: https://ethereum.stackexchange.com/questions/21155/how-to-expose-enum-in-solidity-contract\n // make sure to update fastbridge/status.go if this changes\n // or underliyng enum changes.\n //\n // TODO: a foundry test should be added to ensure this is always in sync.\n function getEnumKeyByValue(FastBridge.BridgeStatus keyValue) public pure returns (string memory) {\n if (FastBridge.BridgeStatus.NULL == keyValue) return \"NULL\";\n if (FastBridge.BridgeStatus.REQUESTED == keyValue) return \"REQUESTED\";\n if (FastBridge.BridgeStatus.RELAYER_PROVED == keyValue) return \"RELAYER_PROVED\";\n if (FastBridge.BridgeStatus.RELAYER_CLAIMED == keyValue) return \"RELAYER_CLAIMED\";\n if (FastBridge.BridgeStatus.REFUNDED == keyValue) return \"REFUNDED\";\n return \"\";\n }\n\n function mockBridgeRequest(bytes32 transactionId, address sender, BridgeParams memory params) external {\n uint256 originFeeAmount = (params.originAmount * protocolFeeRate) / FEE_BPS;\n params.originAmount -= originFeeAmount;\n\n bytes memory request = abi.encode(\n BridgeTransaction({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: params.originAmount, // includes relayer fee\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n sendChainGas: params.sendChainGas,\n deadline: params.deadline,\n nonce: nonce++ // increment nonce on every bridge\n })\n );\n\n emit BridgeRequested(\n transactionId,\n params.sender,\n request,\n params.dstChainId,\n params.originToken,\n params.destToken,\n params.originAmount,\n params.destAmount,\n params.sendChainGas\n );\n }\n\n function mockBridgeRequestRaw(bytes32 transactionId, address sender, bytes memory request) external {\n BridgeTransaction memory transaction = getBridgeTransaction(request);\n emit BridgeRequested(\n transactionId,\n transaction.originSender,\n request,\n transaction.destChainId,\n transaction.originToken,\n transaction.destToken,\n transaction.originAmount,\n transaction.destAmount,\n transaction.sendChainGas\n );\n }\n\n function mockBridgeRelayer(\n bytes32 transactionId,\n address relayer,\n address to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n )\n external\n {\n emit BridgeRelayed(\n transactionId, relayer, to, originChainId, originToken, destToken, originAmount, destAmount, chainGasAmount\n );\n }\n\n function bridge(BridgeParams memory params) external payable {\n revert(\"not implemented\");\n }\n\n function relay(bytes memory request) external payable {\n revert(\"not implemented\");\n }\n\n function prove(bytes memory request, bytes32 destTxHash) external {\n revert(\"not implemented\");\n }\n\n function canClaim(bytes32 transactionid, address relayer) external view returns (bool) {\n revert(\"not implemented\");\n }\n\n function claim(bytes memory request, address to) external {\n revert(\"not implemented\");\n }\n\n function dispute(bytes32 transactionId) external {\n revert(\"not implemented\");\n }\n\n function refund(bytes memory request) external {\n revert(\"not implemented\");\n }\n}\n","language":"Solidity","languageVersion":"0.8.20","compilerVersion":"0.8.20","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"","srcMapRuntime":"","abiDefinition":[{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Transfer","type":"event"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"}],"userDoc":{"kind":"user","methods":{},"version":1},"developerDoc":{"details":"Interface of the ERC20 standard as defined in the EIP.","events":{"Approval(address,address,uint256)":{"details":"Emitted when the allowance of a `spender` for an `owner` is set by a call to {approve}. `value` is the new allowance."},"Transfer(address,address,uint256)":{"details":"Emitted when `value` tokens are moved from one account (`from`) to another (`to`). Note that `value` may be zero."}},"kind":"dev","methods":{"allowance(address,address)":{"details":"Returns the remaining number of tokens that `spender` will be allowed to spend on behalf of `owner` through {transferFrom}. This is zero by default. This value changes when {approve} or {transferFrom} are called."},"approve(address,uint256)":{"details":"Sets a `value` amount of tokens as the allowance of `spender` over the caller's tokens. Returns a boolean value indicating whether the operation succeeded. IMPORTANT: Beware that changing an allowance with this method brings the risk that someone may use both the old and the new allowance by unfortunate transaction ordering. One possible solution to mitigate this race condition is to first reduce the spender's allowance to 0 and set the desired value afterwards: https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 Emits an {Approval} event."},"balanceOf(address)":{"details":"Returns the value of tokens owned by `account`."},"totalSupply()":{"details":"Returns the value of tokens in existence."},"transfer(address,uint256)":{"details":"Moves a `value` amount of tokens from the caller's account to `to`. Returns a boolean value indicating whether the operation succeeded. Emits a {Transfer} event."},"transferFrom(address,address,uint256)":{"details":"Moves a `value` amount of tokens from `from` to `to` using the allowance mechanism. `value` is then deducted from the caller's allowance. Returns a boolean value indicating whether the operation succeeded. Emits a {Transfer} event."}},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.20+commit.a1b79de6\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"Approval\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"Transfer\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"}],\"name\":\"allowance\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"approve\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"balanceOf\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"totalSupply\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"transfer\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"transferFrom\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"details\":\"Interface of the ERC20 standard as defined in the EIP.\",\"events\":{\"Approval(address,address,uint256)\":{\"details\":\"Emitted when the allowance of a `spender` for an `owner` is set by a call to {approve}. `value` is the new allowance.\"},\"Transfer(address,address,uint256)\":{\"details\":\"Emitted when `value` tokens are moved from one account (`from`) to another (`to`). Note that `value` may be zero.\"}},\"kind\":\"dev\",\"methods\":{\"allowance(address,address)\":{\"details\":\"Returns the remaining number of tokens that `spender` will be allowed to spend on behalf of `owner` through {transferFrom}. This is zero by default. This value changes when {approve} or {transferFrom} are called.\"},\"approve(address,uint256)\":{\"details\":\"Sets a `value` amount of tokens as the allowance of `spender` over the caller's tokens. Returns a boolean value indicating whether the operation succeeded. IMPORTANT: Beware that changing an allowance with this method brings the risk that someone may use both the old and the new allowance by unfortunate transaction ordering. One possible solution to mitigate this race condition is to first reduce the spender's allowance to 0 and set the desired value afterwards: https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 Emits an {Approval} event.\"},\"balanceOf(address)\":{\"details\":\"Returns the value of tokens owned by `account`.\"},\"totalSupply()\":{\"details\":\"Returns the value of tokens in existence.\"},\"transfer(address,uint256)\":{\"details\":\"Moves a `value` amount of tokens from the caller's account to `to`. Returns a boolean value indicating whether the operation succeeded. Emits a {Transfer} event.\"},\"transferFrom(address,address,uint256)\":{\"details\":\"Moves a `value` amount of tokens from `from` to `to` using the allowance mechanism. `value` is then deducted from the caller's allowance. Returns a boolean value indicating whether the operation succeeded. Emits a {Transfer} event.\"}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeMock.sol\":\"IERC20\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeMock.sol\":{\"keccak256\":\"0x620e81214ecd324ae8b971219291f176c454ce76fb1c01d656428096da8f1366\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://18e556772c12e13aa2d52a50cc7c48e676c8d5af22b90adaf7befb39cdd08e64\",\"dweb:/ipfs/QmPrQc98TxHCFMeuFNADyjr6Nqo52rHhHy1LBcsVdMRXjL\"]}},\"version\":1}"},"hashes":{"allowance(address,address)":"dd62ed3e","approve(address,uint256)":"095ea7b3","balanceOf(address)":"70a08231","totalSupply()":"18160ddd","transfer(address,uint256)":"a9059cbb","transferFrom(address,address,uint256)":"23b872dd"}},"solidity/FastBridgeMock.sol:IERC20Permit":{"code":"0x","runtime-code":"0x","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.20 ^0.8.20;\n\n// contracts/interfaces/IAdmin.sol\n\ninterface IAdmin {\n // ============ Events ============\n\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n event ChainGasAmountUpdated(uint256 oldChainGasAmount, uint256 newChainGasAmount);\n\n // ============ Methods ============\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n\n function setChainGasAmount(uint256 newChainGasAmount) external;\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/libs/Errors.sol\n\nerror DeadlineExceeded();\nerror DeadlineNotExceeded();\nerror DeadlineTooShort();\nerror InsufficientOutputAmount();\n\nerror MsgValueIncorrect();\nerror PoolNotFound();\nerror TokenAddressMismatch();\nerror TokenNotContract();\nerror TokenNotETH();\nerror TokensIdentical();\n\nerror ChainIncorrect();\nerror AmountIncorrect();\nerror ZeroAddress();\n\nerror DisputePeriodNotPassed();\nerror DisputePeriodPassed();\nerror SenderIncorrect();\nerror StatusIncorrect();\nerror TransactionIdIncorrect();\nerror TransactionRelayed();\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// contracts/libs/UniversalToken.sol\n\nlibrary UniversalTokenLib {\n using SafeERC20 for IERC20;\n\n address internal constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Transfers tokens to the given account. Reverts if transfer is not successful.\n /// @dev This might trigger fallback, if ETH is transferred to the contract.\n /// Make sure this can not lead to reentrancy attacks.\n function universalTransfer(address token, address to, uint256 value) internal {\n // Don't do anything, if need to send tokens to this address\n if (to == address(this)) return;\n // Don't do anything, if trying to send zero value\n if (value == 0) return;\n if (token == ETH_ADDRESS) {\n /// @dev Note: this can potentially lead to executing code in `to`.\n // solhint-disable-next-line avoid-low-level-calls\n (bool success,) = to.call{value: value}(\"\");\n require(success, \"ETH transfer failed\");\n } else {\n IERC20(token).safeTransfer(to, value);\n }\n }\n\n /// @notice Issues an infinite allowance to the spender, if the current allowance is insufficient\n /// to spend the given amount.\n function universalApproveInfinity(address token, address spender, uint256 amountToSpend) internal {\n // ETH Chad doesn't require your approval\n if (token == ETH_ADDRESS) return;\n // No-op if allowance is already sufficient\n uint256 allowance = IERC20(token).allowance(address(this), spender);\n if (allowance \u003e= amountToSpend) return;\n // Otherwise, reset approval to 0 and set to max allowance\n if (allowance \u003e 0) IERC20(token).safeDecreaseAllowance(spender, allowance);\n IERC20(token).safeIncreaseAllowance(spender, type(uint256).max);\n }\n\n /// @notice Returns the balance of the given token (or native ETH) for the given account.\n function universalBalanceOf(address token, address account) internal view returns (uint256) {\n if (token == ETH_ADDRESS) {\n return account.balance;\n } else {\n return IERC20(token).balanceOf(account);\n }\n }\n\n /// @dev Checks that token is a contract and not ETH_ADDRESS.\n function assertIsContract(address token) internal view {\n // Check that ETH_ADDRESS was not used (in case this is a predeploy on any of the chains)\n if (token == UniversalTokenLib.ETH_ADDRESS) revert TokenNotContract();\n // Check that token is not an EOA\n if (token.code.length == 0) revert TokenNotContract();\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/Admin.sol\n\ncontract Admin is IAdmin, AccessControlEnumerable {\n using UniversalTokenLib for address;\n\n bytes32 public constant RELAYER_ROLE = keccak256(\"RELAYER_ROLE\");\n bytes32 public constant REFUNDER_ROLE = keccak256(\"REFUNDER_ROLE\");\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n uint256 public constant FEE_BPS = 1e6;\n uint256 public constant FEE_RATE_MAX = 0.01e6; // max 1% on origin amount\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Chain gas amount to forward as rebate if requested\n uint256 public chainGasAmount;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n }\n\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n require(newFeeRate \u003c= FEE_RATE_MAX, \"newFeeRate \u003e max\");\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n token.universalTransfer(recipient, feeAmount);\n emit FeesSwept(token, recipient, feeAmount);\n }\n\n function setChainGasAmount(uint256 newChainGasAmount) external onlyRole(GOVERNOR_ROLE) {\n uint256 oldChainGasAmount = chainGasAmount;\n chainGasAmount = newChainGasAmount;\n emit ChainGasAmountUpdated(oldChainGasAmount, newChainGasAmount);\n }\n}\n\n// contracts/FastBridge.sol\n\ncontract FastBridge is IFastBridge, Admin {\n using SafeERC20 for IERC20;\n using UniversalTokenLib for address;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Delay for a transaction after which it could be permisionlessly refunded\n uint256 public constant REFUND_DELAY = 7 days;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeStatus) public bridgeStatuses;\n /// @notice Proof of relayed bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeProof) public bridgeProofs;\n /// @notice Whether bridge has been relayed on destination chain\n mapping(bytes32 =\u003e bool) public bridgeRelays;\n\n /// @dev to prevent replays\n uint256 public nonce;\n // @dev the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @notice Pulls a requested token from the user to the requested recipient.\n /// @dev Be careful of re-entrancy issues when msg.value \u003e 0 and recipient != address(this)\n function _pullToken(address recipient, address token, uint256 amount) internal returns (uint256 amountPulled) {\n if (token != UniversalTokenLib.ETH_ADDRESS) {\n token.assertIsContract();\n // Record token balance before transfer\n amountPulled = IERC20(token).balanceOf(recipient);\n // Token needs to be pulled only if msg.value is zero\n // This way user can specify WETH as the origin asset\n IERC20(token).safeTransferFrom(msg.sender, recipient, amount);\n // Use the difference between the recorded balance and the current balance as the amountPulled\n amountPulled = IERC20(token).balanceOf(recipient) - amountPulled;\n } else {\n // Otherwise, we need to check that ETH amount matches msg.value\n if (amount != msg.value) revert MsgValueIncorrect();\n // Transfer value to recipient if not this address\n if (recipient != address(this)) token.universalTransfer(recipient, amount);\n // We will forward msg.value in the external call later, if recipient is not this contract\n amountPulled = msg.value;\n }\n }\n\n /// @inheritdoc IFastBridge\n function getBridgeTransaction(bytes memory request) public pure returns (BridgeTransaction memory) {\n return abi.decode(request, (BridgeTransaction));\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n // check bridge params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n\n // transfer tokens to bridge contract\n // @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _pullToken(address(this), params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n\n // set status to requested\n bytes memory request = abi.encode(\n BridgeTransaction({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n sendChainGas: params.sendChainGas,\n deadline: params.deadline,\n nonce: nonce++ // increment nonce on every bridge\n })\n );\n bytes32 transactionId = keccak256(request);\n bridgeStatuses[transactionId] = BridgeStatus.REQUESTED;\n\n emit BridgeRequested(\n transactionId,\n params.sender,\n request,\n params.dstChainId,\n params.originToken,\n params.destToken,\n originAmount,\n params.destAmount,\n params.sendChainGas\n );\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes memory request) external payable onlyRole(RELAYER_ROLE) {\n bytes32 transactionId = keccak256(request);\n BridgeTransaction memory transaction = getBridgeTransaction(request);\n if (transaction.destChainId != uint32(block.chainid)) revert ChainIncorrect();\n\n // check haven't exceeded deadline for relay to happen\n if (block.timestamp \u003e transaction.deadline) revert DeadlineExceeded();\n\n // mark bridge transaction as relayed\n if (bridgeRelays[transactionId]) revert TransactionRelayed();\n bridgeRelays[transactionId] = true;\n\n // transfer tokens to recipient on destination chain and gas rebate if requested\n address to = transaction.destRecipient;\n address token = transaction.destToken;\n uint256 amount = transaction.destAmount;\n\n uint256 rebate = chainGasAmount;\n if (!transaction.sendChainGas) {\n // forward erc20\n rebate = 0;\n _pullToken(to, token, amount);\n } else if (token == UniversalTokenLib.ETH_ADDRESS) {\n // lump in gas rebate into amount in native gas token\n _pullToken(to, token, amount + rebate);\n } else {\n // forward erc20 then forward gas rebate in native gas token\n _pullToken(to, token, amount);\n _pullToken(to, UniversalTokenLib.ETH_ADDRESS, rebate);\n }\n\n emit BridgeRelayed(\n transactionId,\n msg.sender,\n to,\n transaction.originChainId,\n transaction.originToken,\n transaction.destToken,\n transaction.originAmount,\n transaction.destAmount,\n rebate\n );\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes memory request, bytes32 destTxHash) external onlyRole(RELAYER_ROLE) {\n bytes32 transactionId = keccak256(request);\n // update bridge tx status given proof provided\n if (bridgeStatuses[transactionId] != BridgeStatus.REQUESTED) revert StatusIncorrect();\n bridgeStatuses[transactionId] = BridgeStatus.RELAYER_PROVED;\n bridgeProofs[transactionId] = BridgeProof({timestamp: uint96(block.timestamp), relayer: msg.sender}); // overflow ok\n\n emit BridgeProofProvided(transactionId, msg.sender, destTxHash);\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint96(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint96).max but\n /// proof.timestamp \u003c type(uint96).max via unchecked statement\n /// @param proof The bridge proof\n /// @return delta Time delta since proof submitted\n function _timeSince(BridgeProof memory proof) internal view returns (uint256 delta) {\n unchecked {\n delta = uint96(block.timestamp) - proof.timestamp;\n }\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n if (bridgeStatuses[transactionId] != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n BridgeProof memory proof = bridgeProofs[transactionId];\n if (proof.relayer != relayer) revert SenderIncorrect();\n return _timeSince(proof) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes memory request, address to) external onlyRole(RELAYER_ROLE) {\n bytes32 transactionId = keccak256(request);\n BridgeTransaction memory transaction = getBridgeTransaction(request);\n\n // update bridge tx status if able to claim origin collateral\n if (bridgeStatuses[transactionId] != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n\n BridgeProof memory proof = bridgeProofs[transactionId];\n if (proof.relayer != msg.sender) revert SenderIncorrect();\n if (_timeSince(proof) \u003c= DISPUTE_PERIOD) revert DisputePeriodNotPassed();\n\n bridgeStatuses[transactionId] = BridgeStatus.RELAYER_CLAIMED;\n\n // update protocol fees if origin fee amount exists\n if (transaction.originFeeAmount \u003e 0) protocolFees[transaction.originToken] += transaction.originFeeAmount;\n\n // transfer origin collateral less fee to specified address\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositClaimed(transactionId, msg.sender, to, token, amount);\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n if (bridgeStatuses[transactionId] != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(bridgeProofs[transactionId]) \u003e DISPUTE_PERIOD) revert DisputePeriodPassed();\n\n // @dev relayer gets slashed effectively if dest relay has gone thru\n bridgeStatuses[transactionId] = BridgeStatus.REQUESTED;\n delete bridgeProofs[transactionId];\n\n emit BridgeProofDisputed(transactionId, msg.sender);\n }\n\n /// @inheritdoc IFastBridge\n function refund(bytes memory request) external {\n bytes32 transactionId = keccak256(request);\n BridgeTransaction memory transaction = getBridgeTransaction(request);\n\n if (hasRole(REFUNDER_ROLE, msg.sender)) {\n // Refunder can refund if deadline has passed\n if (block.timestamp \u003c= transaction.deadline) revert DeadlineNotExceeded();\n } else {\n // Permissionless refund is allowed after REFUND_DELAY\n if (block.timestamp \u003c= transaction.deadline + REFUND_DELAY) revert DeadlineNotExceeded();\n }\n\n // set status to refunded if still in requested state\n if (bridgeStatuses[transactionId] != BridgeStatus.REQUESTED) revert StatusIncorrect();\n bridgeStatuses[transactionId] = BridgeStatus.REFUNDED;\n\n // transfer origin collateral back to original sender\n address to = transaction.originSender;\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount + transaction.originFeeAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n }\n}\n\n// test/FastBridgeMock.sol\n\ncontract FastBridgeMock is IFastBridge, Admin {\n // @dev the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @dev to prevent replays\n uint256 public nonce;\n\n function getBridgeTransaction(bytes memory request) public pure returns (BridgeTransaction memory) {\n return abi.decode(request, (BridgeTransaction));\n }\n\n // used for testing in go.\n // see: https://ethereum.stackexchange.com/questions/21155/how-to-expose-enum-in-solidity-contract\n // make sure to update fastbridge/status.go if this changes\n // or underliyng enum changes.\n //\n // TODO: a foundry test should be added to ensure this is always in sync.\n function getEnumKeyByValue(FastBridge.BridgeStatus keyValue) public pure returns (string memory) {\n if (FastBridge.BridgeStatus.NULL == keyValue) return \"NULL\";\n if (FastBridge.BridgeStatus.REQUESTED == keyValue) return \"REQUESTED\";\n if (FastBridge.BridgeStatus.RELAYER_PROVED == keyValue) return \"RELAYER_PROVED\";\n if (FastBridge.BridgeStatus.RELAYER_CLAIMED == keyValue) return \"RELAYER_CLAIMED\";\n if (FastBridge.BridgeStatus.REFUNDED == keyValue) return \"REFUNDED\";\n return \"\";\n }\n\n function mockBridgeRequest(bytes32 transactionId, address sender, BridgeParams memory params) external {\n uint256 originFeeAmount = (params.originAmount * protocolFeeRate) / FEE_BPS;\n params.originAmount -= originFeeAmount;\n\n bytes memory request = abi.encode(\n BridgeTransaction({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: params.originAmount, // includes relayer fee\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n sendChainGas: params.sendChainGas,\n deadline: params.deadline,\n nonce: nonce++ // increment nonce on every bridge\n })\n );\n\n emit BridgeRequested(\n transactionId,\n params.sender,\n request,\n params.dstChainId,\n params.originToken,\n params.destToken,\n params.originAmount,\n params.destAmount,\n params.sendChainGas\n );\n }\n\n function mockBridgeRequestRaw(bytes32 transactionId, address sender, bytes memory request) external {\n BridgeTransaction memory transaction = getBridgeTransaction(request);\n emit BridgeRequested(\n transactionId,\n transaction.originSender,\n request,\n transaction.destChainId,\n transaction.originToken,\n transaction.destToken,\n transaction.originAmount,\n transaction.destAmount,\n transaction.sendChainGas\n );\n }\n\n function mockBridgeRelayer(\n bytes32 transactionId,\n address relayer,\n address to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n )\n external\n {\n emit BridgeRelayed(\n transactionId, relayer, to, originChainId, originToken, destToken, originAmount, destAmount, chainGasAmount\n );\n }\n\n function bridge(BridgeParams memory params) external payable {\n revert(\"not implemented\");\n }\n\n function relay(bytes memory request) external payable {\n revert(\"not implemented\");\n }\n\n function prove(bytes memory request, bytes32 destTxHash) external {\n revert(\"not implemented\");\n }\n\n function canClaim(bytes32 transactionid, address relayer) external view returns (bool) {\n revert(\"not implemented\");\n }\n\n function claim(bytes memory request, address to) external {\n revert(\"not implemented\");\n }\n\n function dispute(bytes32 transactionId) external {\n revert(\"not implemented\");\n }\n\n function refund(bytes memory request) external {\n revert(\"not implemented\");\n }\n}\n","language":"Solidity","languageVersion":"0.8.20","compilerVersion":"0.8.20","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"","srcMapRuntime":"","abiDefinition":[{"inputs":[],"name":"DOMAIN_SEPARATOR","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"nonces","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"permit","outputs":[],"stateMutability":"nonpayable","type":"function"}],"userDoc":{"kind":"user","methods":{},"version":1},"developerDoc":{"details":"Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in https://eips.ethereum.org/EIPS/eip-2612[EIP-2612]. Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't need to send a transaction, and thus is not required to hold Ether at all. ==== Security Considerations There are two important considerations concerning the use of `permit`. The first is that a valid permit signature expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be considered as an intention to spend the allowance in any specific way. The second is that because permits have built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be generally recommended is: ```solidity function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public { try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {} doThing(..., value); } function doThing(..., uint256 value) public { token.safeTransferFrom(msg.sender, address(this), value); ... } ``` Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also {SafeERC20-safeTransferFrom}). Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so contracts should have entry points that don't rely on permit.","kind":"dev","methods":{"DOMAIN_SEPARATOR()":{"details":"Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}."},"nonces(address)":{"details":"Returns the current nonce for `owner`. This value must be included whenever a signature is generated for {permit}. Every successful call to {permit} increases ``owner``'s nonce by one. This prevents a signature from being used multiple times."},"permit(address,address,uint256,uint256,uint8,bytes32,bytes32)":{"details":"Sets `value` as the allowance of `spender` over ``owner``'s tokens, given ``owner``'s signed approval. IMPORTANT: The same issues {IERC20-approve} has related to transaction ordering also apply here. Emits an {Approval} event. Requirements: - `spender` cannot be the zero address. - `deadline` must be a timestamp in the future. - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner` over the EIP712-formatted function arguments. - the signature must use ``owner``'s current nonce (see {nonces}). For more information on the signature format, see the https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP section]. CAUTION: See Security Considerations above."}},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.20+commit.a1b79de6\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[],\"name\":\"DOMAIN_SEPARATOR\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"}],\"name\":\"nonces\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"},{\"internalType\":\"uint8\",\"name\":\"v\",\"type\":\"uint8\"},{\"internalType\":\"bytes32\",\"name\":\"r\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"s\",\"type\":\"bytes32\"}],\"name\":\"permit\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"details\":\"Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in https://eips.ethereum.org/EIPS/eip-2612[EIP-2612]. Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't need to send a transaction, and thus is not required to hold Ether at all. ==== Security Considerations There are two important considerations concerning the use of `permit`. The first is that a valid permit signature expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be considered as an intention to spend the allowance in any specific way. The second is that because permits have built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be generally recommended is: ```solidity function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public { try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {} doThing(..., value); } function doThing(..., uint256 value) public { token.safeTransferFrom(msg.sender, address(this), value); ... } ``` Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also {SafeERC20-safeTransferFrom}). Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so contracts should have entry points that don't rely on permit.\",\"kind\":\"dev\",\"methods\":{\"DOMAIN_SEPARATOR()\":{\"details\":\"Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\"},\"nonces(address)\":{\"details\":\"Returns the current nonce for `owner`. This value must be included whenever a signature is generated for {permit}. Every successful call to {permit} increases ``owner``'s nonce by one. This prevents a signature from being used multiple times.\"},\"permit(address,address,uint256,uint256,uint8,bytes32,bytes32)\":{\"details\":\"Sets `value` as the allowance of `spender` over ``owner``'s tokens, given ``owner``'s signed approval. IMPORTANT: The same issues {IERC20-approve} has related to transaction ordering also apply here. Emits an {Approval} event. Requirements: - `spender` cannot be the zero address. - `deadline` must be a timestamp in the future. - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner` over the EIP712-formatted function arguments. - the signature must use ``owner``'s current nonce (see {nonces}). For more information on the signature format, see the https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP section]. CAUTION: See Security Considerations above.\"}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeMock.sol\":\"IERC20Permit\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeMock.sol\":{\"keccak256\":\"0x620e81214ecd324ae8b971219291f176c454ce76fb1c01d656428096da8f1366\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://18e556772c12e13aa2d52a50cc7c48e676c8d5af22b90adaf7befb39cdd08e64\",\"dweb:/ipfs/QmPrQc98TxHCFMeuFNADyjr6Nqo52rHhHy1LBcsVdMRXjL\"]}},\"version\":1}"},"hashes":{"DOMAIN_SEPARATOR()":"3644e515","nonces(address)":"7ecebe00","permit(address,address,uint256,uint256,uint8,bytes32,bytes32)":"d505accf"}},"solidity/FastBridgeMock.sol:IFastBridge":{"code":"0x","runtime-code":"0x","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.20 ^0.8.20;\n\n// contracts/interfaces/IAdmin.sol\n\ninterface IAdmin {\n // ============ Events ============\n\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n event ChainGasAmountUpdated(uint256 oldChainGasAmount, uint256 newChainGasAmount);\n\n // ============ Methods ============\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n\n function setChainGasAmount(uint256 newChainGasAmount) external;\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/libs/Errors.sol\n\nerror DeadlineExceeded();\nerror DeadlineNotExceeded();\nerror DeadlineTooShort();\nerror InsufficientOutputAmount();\n\nerror MsgValueIncorrect();\nerror PoolNotFound();\nerror TokenAddressMismatch();\nerror TokenNotContract();\nerror TokenNotETH();\nerror TokensIdentical();\n\nerror ChainIncorrect();\nerror AmountIncorrect();\nerror ZeroAddress();\n\nerror DisputePeriodNotPassed();\nerror DisputePeriodPassed();\nerror SenderIncorrect();\nerror StatusIncorrect();\nerror TransactionIdIncorrect();\nerror TransactionRelayed();\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// contracts/libs/UniversalToken.sol\n\nlibrary UniversalTokenLib {\n using SafeERC20 for IERC20;\n\n address internal constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Transfers tokens to the given account. Reverts if transfer is not successful.\n /// @dev This might trigger fallback, if ETH is transferred to the contract.\n /// Make sure this can not lead to reentrancy attacks.\n function universalTransfer(address token, address to, uint256 value) internal {\n // Don't do anything, if need to send tokens to this address\n if (to == address(this)) return;\n // Don't do anything, if trying to send zero value\n if (value == 0) return;\n if (token == ETH_ADDRESS) {\n /// @dev Note: this can potentially lead to executing code in `to`.\n // solhint-disable-next-line avoid-low-level-calls\n (bool success,) = to.call{value: value}(\"\");\n require(success, \"ETH transfer failed\");\n } else {\n IERC20(token).safeTransfer(to, value);\n }\n }\n\n /// @notice Issues an infinite allowance to the spender, if the current allowance is insufficient\n /// to spend the given amount.\n function universalApproveInfinity(address token, address spender, uint256 amountToSpend) internal {\n // ETH Chad doesn't require your approval\n if (token == ETH_ADDRESS) return;\n // No-op if allowance is already sufficient\n uint256 allowance = IERC20(token).allowance(address(this), spender);\n if (allowance \u003e= amountToSpend) return;\n // Otherwise, reset approval to 0 and set to max allowance\n if (allowance \u003e 0) IERC20(token).safeDecreaseAllowance(spender, allowance);\n IERC20(token).safeIncreaseAllowance(spender, type(uint256).max);\n }\n\n /// @notice Returns the balance of the given token (or native ETH) for the given account.\n function universalBalanceOf(address token, address account) internal view returns (uint256) {\n if (token == ETH_ADDRESS) {\n return account.balance;\n } else {\n return IERC20(token).balanceOf(account);\n }\n }\n\n /// @dev Checks that token is a contract and not ETH_ADDRESS.\n function assertIsContract(address token) internal view {\n // Check that ETH_ADDRESS was not used (in case this is a predeploy on any of the chains)\n if (token == UniversalTokenLib.ETH_ADDRESS) revert TokenNotContract();\n // Check that token is not an EOA\n if (token.code.length == 0) revert TokenNotContract();\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/Admin.sol\n\ncontract Admin is IAdmin, AccessControlEnumerable {\n using UniversalTokenLib for address;\n\n bytes32 public constant RELAYER_ROLE = keccak256(\"RELAYER_ROLE\");\n bytes32 public constant REFUNDER_ROLE = keccak256(\"REFUNDER_ROLE\");\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n uint256 public constant FEE_BPS = 1e6;\n uint256 public constant FEE_RATE_MAX = 0.01e6; // max 1% on origin amount\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Chain gas amount to forward as rebate if requested\n uint256 public chainGasAmount;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n }\n\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n require(newFeeRate \u003c= FEE_RATE_MAX, \"newFeeRate \u003e max\");\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n token.universalTransfer(recipient, feeAmount);\n emit FeesSwept(token, recipient, feeAmount);\n }\n\n function setChainGasAmount(uint256 newChainGasAmount) external onlyRole(GOVERNOR_ROLE) {\n uint256 oldChainGasAmount = chainGasAmount;\n chainGasAmount = newChainGasAmount;\n emit ChainGasAmountUpdated(oldChainGasAmount, newChainGasAmount);\n }\n}\n\n// contracts/FastBridge.sol\n\ncontract FastBridge is IFastBridge, Admin {\n using SafeERC20 for IERC20;\n using UniversalTokenLib for address;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Delay for a transaction after which it could be permisionlessly refunded\n uint256 public constant REFUND_DELAY = 7 days;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeStatus) public bridgeStatuses;\n /// @notice Proof of relayed bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeProof) public bridgeProofs;\n /// @notice Whether bridge has been relayed on destination chain\n mapping(bytes32 =\u003e bool) public bridgeRelays;\n\n /// @dev to prevent replays\n uint256 public nonce;\n // @dev the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @notice Pulls a requested token from the user to the requested recipient.\n /// @dev Be careful of re-entrancy issues when msg.value \u003e 0 and recipient != address(this)\n function _pullToken(address recipient, address token, uint256 amount) internal returns (uint256 amountPulled) {\n if (token != UniversalTokenLib.ETH_ADDRESS) {\n token.assertIsContract();\n // Record token balance before transfer\n amountPulled = IERC20(token).balanceOf(recipient);\n // Token needs to be pulled only if msg.value is zero\n // This way user can specify WETH as the origin asset\n IERC20(token).safeTransferFrom(msg.sender, recipient, amount);\n // Use the difference between the recorded balance and the current balance as the amountPulled\n amountPulled = IERC20(token).balanceOf(recipient) - amountPulled;\n } else {\n // Otherwise, we need to check that ETH amount matches msg.value\n if (amount != msg.value) revert MsgValueIncorrect();\n // Transfer value to recipient if not this address\n if (recipient != address(this)) token.universalTransfer(recipient, amount);\n // We will forward msg.value in the external call later, if recipient is not this contract\n amountPulled = msg.value;\n }\n }\n\n /// @inheritdoc IFastBridge\n function getBridgeTransaction(bytes memory request) public pure returns (BridgeTransaction memory) {\n return abi.decode(request, (BridgeTransaction));\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n // check bridge params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n\n // transfer tokens to bridge contract\n // @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _pullToken(address(this), params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n\n // set status to requested\n bytes memory request = abi.encode(\n BridgeTransaction({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n sendChainGas: params.sendChainGas,\n deadline: params.deadline,\n nonce: nonce++ // increment nonce on every bridge\n })\n );\n bytes32 transactionId = keccak256(request);\n bridgeStatuses[transactionId] = BridgeStatus.REQUESTED;\n\n emit BridgeRequested(\n transactionId,\n params.sender,\n request,\n params.dstChainId,\n params.originToken,\n params.destToken,\n originAmount,\n params.destAmount,\n params.sendChainGas\n );\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes memory request) external payable onlyRole(RELAYER_ROLE) {\n bytes32 transactionId = keccak256(request);\n BridgeTransaction memory transaction = getBridgeTransaction(request);\n if (transaction.destChainId != uint32(block.chainid)) revert ChainIncorrect();\n\n // check haven't exceeded deadline for relay to happen\n if (block.timestamp \u003e transaction.deadline) revert DeadlineExceeded();\n\n // mark bridge transaction as relayed\n if (bridgeRelays[transactionId]) revert TransactionRelayed();\n bridgeRelays[transactionId] = true;\n\n // transfer tokens to recipient on destination chain and gas rebate if requested\n address to = transaction.destRecipient;\n address token = transaction.destToken;\n uint256 amount = transaction.destAmount;\n\n uint256 rebate = chainGasAmount;\n if (!transaction.sendChainGas) {\n // forward erc20\n rebate = 0;\n _pullToken(to, token, amount);\n } else if (token == UniversalTokenLib.ETH_ADDRESS) {\n // lump in gas rebate into amount in native gas token\n _pullToken(to, token, amount + rebate);\n } else {\n // forward erc20 then forward gas rebate in native gas token\n _pullToken(to, token, amount);\n _pullToken(to, UniversalTokenLib.ETH_ADDRESS, rebate);\n }\n\n emit BridgeRelayed(\n transactionId,\n msg.sender,\n to,\n transaction.originChainId,\n transaction.originToken,\n transaction.destToken,\n transaction.originAmount,\n transaction.destAmount,\n rebate\n );\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes memory request, bytes32 destTxHash) external onlyRole(RELAYER_ROLE) {\n bytes32 transactionId = keccak256(request);\n // update bridge tx status given proof provided\n if (bridgeStatuses[transactionId] != BridgeStatus.REQUESTED) revert StatusIncorrect();\n bridgeStatuses[transactionId] = BridgeStatus.RELAYER_PROVED;\n bridgeProofs[transactionId] = BridgeProof({timestamp: uint96(block.timestamp), relayer: msg.sender}); // overflow ok\n\n emit BridgeProofProvided(transactionId, msg.sender, destTxHash);\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint96(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint96).max but\n /// proof.timestamp \u003c type(uint96).max via unchecked statement\n /// @param proof The bridge proof\n /// @return delta Time delta since proof submitted\n function _timeSince(BridgeProof memory proof) internal view returns (uint256 delta) {\n unchecked {\n delta = uint96(block.timestamp) - proof.timestamp;\n }\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n if (bridgeStatuses[transactionId] != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n BridgeProof memory proof = bridgeProofs[transactionId];\n if (proof.relayer != relayer) revert SenderIncorrect();\n return _timeSince(proof) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes memory request, address to) external onlyRole(RELAYER_ROLE) {\n bytes32 transactionId = keccak256(request);\n BridgeTransaction memory transaction = getBridgeTransaction(request);\n\n // update bridge tx status if able to claim origin collateral\n if (bridgeStatuses[transactionId] != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n\n BridgeProof memory proof = bridgeProofs[transactionId];\n if (proof.relayer != msg.sender) revert SenderIncorrect();\n if (_timeSince(proof) \u003c= DISPUTE_PERIOD) revert DisputePeriodNotPassed();\n\n bridgeStatuses[transactionId] = BridgeStatus.RELAYER_CLAIMED;\n\n // update protocol fees if origin fee amount exists\n if (transaction.originFeeAmount \u003e 0) protocolFees[transaction.originToken] += transaction.originFeeAmount;\n\n // transfer origin collateral less fee to specified address\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositClaimed(transactionId, msg.sender, to, token, amount);\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n if (bridgeStatuses[transactionId] != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(bridgeProofs[transactionId]) \u003e DISPUTE_PERIOD) revert DisputePeriodPassed();\n\n // @dev relayer gets slashed effectively if dest relay has gone thru\n bridgeStatuses[transactionId] = BridgeStatus.REQUESTED;\n delete bridgeProofs[transactionId];\n\n emit BridgeProofDisputed(transactionId, msg.sender);\n }\n\n /// @inheritdoc IFastBridge\n function refund(bytes memory request) external {\n bytes32 transactionId = keccak256(request);\n BridgeTransaction memory transaction = getBridgeTransaction(request);\n\n if (hasRole(REFUNDER_ROLE, msg.sender)) {\n // Refunder can refund if deadline has passed\n if (block.timestamp \u003c= transaction.deadline) revert DeadlineNotExceeded();\n } else {\n // Permissionless refund is allowed after REFUND_DELAY\n if (block.timestamp \u003c= transaction.deadline + REFUND_DELAY) revert DeadlineNotExceeded();\n }\n\n // set status to refunded if still in requested state\n if (bridgeStatuses[transactionId] != BridgeStatus.REQUESTED) revert StatusIncorrect();\n bridgeStatuses[transactionId] = BridgeStatus.REFUNDED;\n\n // transfer origin collateral back to original sender\n address to = transaction.originSender;\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount + transaction.originFeeAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n }\n}\n\n// test/FastBridgeMock.sol\n\ncontract FastBridgeMock is IFastBridge, Admin {\n // @dev the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @dev to prevent replays\n uint256 public nonce;\n\n function getBridgeTransaction(bytes memory request) public pure returns (BridgeTransaction memory) {\n return abi.decode(request, (BridgeTransaction));\n }\n\n // used for testing in go.\n // see: https://ethereum.stackexchange.com/questions/21155/how-to-expose-enum-in-solidity-contract\n // make sure to update fastbridge/status.go if this changes\n // or underliyng enum changes.\n //\n // TODO: a foundry test should be added to ensure this is always in sync.\n function getEnumKeyByValue(FastBridge.BridgeStatus keyValue) public pure returns (string memory) {\n if (FastBridge.BridgeStatus.NULL == keyValue) return \"NULL\";\n if (FastBridge.BridgeStatus.REQUESTED == keyValue) return \"REQUESTED\";\n if (FastBridge.BridgeStatus.RELAYER_PROVED == keyValue) return \"RELAYER_PROVED\";\n if (FastBridge.BridgeStatus.RELAYER_CLAIMED == keyValue) return \"RELAYER_CLAIMED\";\n if (FastBridge.BridgeStatus.REFUNDED == keyValue) return \"REFUNDED\";\n return \"\";\n }\n\n function mockBridgeRequest(bytes32 transactionId, address sender, BridgeParams memory params) external {\n uint256 originFeeAmount = (params.originAmount * protocolFeeRate) / FEE_BPS;\n params.originAmount -= originFeeAmount;\n\n bytes memory request = abi.encode(\n BridgeTransaction({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: params.originAmount, // includes relayer fee\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n sendChainGas: params.sendChainGas,\n deadline: params.deadline,\n nonce: nonce++ // increment nonce on every bridge\n })\n );\n\n emit BridgeRequested(\n transactionId,\n params.sender,\n request,\n params.dstChainId,\n params.originToken,\n params.destToken,\n params.originAmount,\n params.destAmount,\n params.sendChainGas\n );\n }\n\n function mockBridgeRequestRaw(bytes32 transactionId, address sender, bytes memory request) external {\n BridgeTransaction memory transaction = getBridgeTransaction(request);\n emit BridgeRequested(\n transactionId,\n transaction.originSender,\n request,\n transaction.destChainId,\n transaction.originToken,\n transaction.destToken,\n transaction.originAmount,\n transaction.destAmount,\n transaction.sendChainGas\n );\n }\n\n function mockBridgeRelayer(\n bytes32 transactionId,\n address relayer,\n address to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n )\n external\n {\n emit BridgeRelayed(\n transactionId, relayer, to, originChainId, originToken, destToken, originAmount, destAmount, chainGasAmount\n );\n }\n\n function bridge(BridgeParams memory params) external payable {\n revert(\"not implemented\");\n }\n\n function relay(bytes memory request) external payable {\n revert(\"not implemented\");\n }\n\n function prove(bytes memory request, bytes32 destTxHash) external {\n revert(\"not implemented\");\n }\n\n function canClaim(bytes32 transactionid, address relayer) external view returns (bool) {\n revert(\"not implemented\");\n }\n\n function claim(bytes memory request, address to) external {\n revert(\"not implemented\");\n }\n\n function dispute(bytes32 transactionId) external {\n revert(\"not implemented\");\n }\n\n function refund(bytes memory request) external {\n revert(\"not implemented\");\n }\n}\n","language":"Solidity","languageVersion":"0.8.20","compilerVersion":"0.8.20","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"","srcMapRuntime":"","abiDefinition":[{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"relayer","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"BridgeDepositClaimed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"BridgeDepositRefunded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"relayer","type":"address"}],"name":"BridgeProofDisputed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"relayer","type":"address"},{"indexed":false,"internalType":"bytes32","name":"transactionHash","type":"bytes32"}],"name":"BridgeProofProvided","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"relayer","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint32","name":"originChainId","type":"uint32"},{"indexed":false,"internalType":"address","name":"originToken","type":"address"},{"indexed":false,"internalType":"address","name":"destToken","type":"address"},{"indexed":false,"internalType":"uint256","name":"originAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"destAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"chainGasAmount","type":"uint256"}],"name":"BridgeRelayed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"bytes","name":"request","type":"bytes"},{"indexed":false,"internalType":"uint32","name":"destChainId","type":"uint32"},{"indexed":false,"internalType":"address","name":"originToken","type":"address"},{"indexed":false,"internalType":"address","name":"destToken","type":"address"},{"indexed":false,"internalType":"uint256","name":"originAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"destAmount","type":"uint256"},{"indexed":false,"internalType":"bool","name":"sendChainGas","type":"bool"}],"name":"BridgeRequested","type":"event"},{"inputs":[{"components":[{"internalType":"uint32","name":"dstChainId","type":"uint32"},{"internalType":"address","name":"sender","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"address","name":"originToken","type":"address"},{"internalType":"address","name":"destToken","type":"address"},{"internalType":"uint256","name":"originAmount","type":"uint256"},{"internalType":"uint256","name":"destAmount","type":"uint256"},{"internalType":"bool","name":"sendChainGas","type":"bool"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"internalType":"struct IFastBridge.BridgeParams","name":"params","type":"tuple"}],"name":"bridge","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"internalType":"address","name":"relayer","type":"address"}],"name":"canClaim","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"},{"internalType":"address","name":"to","type":"address"}],"name":"claim","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"transactionId","type":"bytes32"}],"name":"dispute","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"}],"name":"getBridgeTransaction","outputs":[{"components":[{"internalType":"uint32","name":"originChainId","type":"uint32"},{"internalType":"uint32","name":"destChainId","type":"uint32"},{"internalType":"address","name":"originSender","type":"address"},{"internalType":"address","name":"destRecipient","type":"address"},{"internalType":"address","name":"originToken","type":"address"},{"internalType":"address","name":"destToken","type":"address"},{"internalType":"uint256","name":"originAmount","type":"uint256"},{"internalType":"uint256","name":"destAmount","type":"uint256"},{"internalType":"uint256","name":"originFeeAmount","type":"uint256"},{"internalType":"bool","name":"sendChainGas","type":"bool"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint256","name":"nonce","type":"uint256"}],"internalType":"struct IFastBridge.BridgeTransaction","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"},{"internalType":"bytes32","name":"destTxHash","type":"bytes32"}],"name":"prove","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"}],"name":"refund","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"}],"name":"relay","outputs":[],"stateMutability":"payable","type":"function"}],"userDoc":{"kind":"user","methods":{"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256))":{"notice":"Initiates bridge on origin chain to be relayed by off-chain relayer"},"canClaim(bytes32,address)":{"notice":"Checks if the dispute period has passed so bridge deposit can be claimed"},"claim(bytes,address)":{"notice":"Completes bridge transaction on origin chain by claiming originally deposited capital"},"dispute(bytes32)":{"notice":"Disputes an outstanding proof in case relayer provided dest chain tx is invalid"},"getBridgeTransaction(bytes)":{"notice":"Decodes bridge request into a bridge transaction"},"prove(bytes,bytes32)":{"notice":"Provides proof on origin side that relayer provided funds on destination side of bridge transaction"},"refund(bytes)":{"notice":"Refunds an outstanding bridge transaction in case optimistic bridging failed"},"relay(bytes)":{"notice":"Relays destination side of bridge transaction by off-chain relayer"}},"version":1},"developerDoc":{"kind":"dev","methods":{"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256))":{"params":{"params":"The parameters required to bridge"}},"canClaim(bytes32,address)":{"params":{"relayer":"The address of the relayer attempting to claim","transactionId":"The transaction id associated with the encoded bridge transaction to check"}},"claim(bytes,address)":{"params":{"request":"The encoded bridge transaction to claim on origin chain","to":"The recipient address of the funds"}},"dispute(bytes32)":{"params":{"transactionId":"The transaction id associated with the encoded bridge transaction to dispute"}},"getBridgeTransaction(bytes)":{"params":{"request":"The bridge request to decode"}},"prove(bytes,bytes32)":{"params":{"destTxHash":"The destination tx hash proving bridge transaction was relayed","request":"The encoded bridge transaction to prove on origin chain"}},"refund(bytes)":{"params":{"request":"The encoded bridge transaction to refund"}},"relay(bytes)":{"params":{"request":"The encoded bridge transaction to relay on destination chain"}}},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.20+commit.a1b79de6\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"BridgeDepositClaimed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"BridgeDepositRefunded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"name\":\"BridgeProofDisputed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"transactionHash\",\"type\":\"bytes32\"}],\"name\":\"BridgeProofProvided\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"originChainId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"chainGasAmount\",\"type\":\"uint256\"}],\"name\":\"BridgeRelayed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"destChainId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"sendChainGas\",\"type\":\"bool\"}],\"name\":\"BridgeRequested\",\"type\":\"event\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"dstChainId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"sendChainGas\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"}],\"internalType\":\"struct IFastBridge.BridgeParams\",\"name\":\"params\",\"type\":\"tuple\"}],\"name\":\"bridge\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"name\":\"canClaim\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"claim\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"}],\"name\":\"dispute\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"getBridgeTransaction\",\"outputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"originChainId\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"destChainId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"originSender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destRecipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"originFeeAmount\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"sendChainGas\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"}],\"internalType\":\"struct IFastBridge.BridgeTransaction\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"},{\"internalType\":\"bytes32\",\"name\":\"destTxHash\",\"type\":\"bytes32\"}],\"name\":\"prove\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"refund\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"relay\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{\"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256))\":{\"params\":{\"params\":\"The parameters required to bridge\"}},\"canClaim(bytes32,address)\":{\"params\":{\"relayer\":\"The address of the relayer attempting to claim\",\"transactionId\":\"The transaction id associated with the encoded bridge transaction to check\"}},\"claim(bytes,address)\":{\"params\":{\"request\":\"The encoded bridge transaction to claim on origin chain\",\"to\":\"The recipient address of the funds\"}},\"dispute(bytes32)\":{\"params\":{\"transactionId\":\"The transaction id associated with the encoded bridge transaction to dispute\"}},\"getBridgeTransaction(bytes)\":{\"params\":{\"request\":\"The bridge request to decode\"}},\"prove(bytes,bytes32)\":{\"params\":{\"destTxHash\":\"The destination tx hash proving bridge transaction was relayed\",\"request\":\"The encoded bridge transaction to prove on origin chain\"}},\"refund(bytes)\":{\"params\":{\"request\":\"The encoded bridge transaction to refund\"}},\"relay(bytes)\":{\"params\":{\"request\":\"The encoded bridge transaction to relay on destination chain\"}}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256))\":{\"notice\":\"Initiates bridge on origin chain to be relayed by off-chain relayer\"},\"canClaim(bytes32,address)\":{\"notice\":\"Checks if the dispute period has passed so bridge deposit can be claimed\"},\"claim(bytes,address)\":{\"notice\":\"Completes bridge transaction on origin chain by claiming originally deposited capital\"},\"dispute(bytes32)\":{\"notice\":\"Disputes an outstanding proof in case relayer provided dest chain tx is invalid\"},\"getBridgeTransaction(bytes)\":{\"notice\":\"Decodes bridge request into a bridge transaction\"},\"prove(bytes,bytes32)\":{\"notice\":\"Provides proof on origin side that relayer provided funds on destination side of bridge transaction\"},\"refund(bytes)\":{\"notice\":\"Refunds an outstanding bridge transaction in case optimistic bridging failed\"},\"relay(bytes)\":{\"notice\":\"Relays destination side of bridge transaction by off-chain relayer\"}},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeMock.sol\":\"IFastBridge\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeMock.sol\":{\"keccak256\":\"0x620e81214ecd324ae8b971219291f176c454ce76fb1c01d656428096da8f1366\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://18e556772c12e13aa2d52a50cc7c48e676c8d5af22b90adaf7befb39cdd08e64\",\"dweb:/ipfs/QmPrQc98TxHCFMeuFNADyjr6Nqo52rHhHy1LBcsVdMRXjL\"]}},\"version\":1}"},"hashes":{"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256))":"45851694","canClaim(bytes32,address)":"aa9641ab","claim(bytes,address)":"41fcb612","dispute(bytes32)":"add98c70","getBridgeTransaction(bytes)":"ac11fb1a","prove(bytes,bytes32)":"886d36ff","refund(bytes)":"5eb7d946","relay(bytes)":"8f0d6f17"}},"solidity/FastBridgeMock.sol:SafeERC20":{"code":"0x60566037600b82828239805160001a607314602a57634e487b7160e01b600052600060045260246000fd5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600080fdfea2646970667358221220c9ee2b1c91328c4f3496cd535cd06e2517aa82f2297fd1e3b5006b41112840f764736f6c63430008140033","runtime-code":"0x73000000000000000000000000000000000000000030146080604052600080fdfea2646970667358221220c9ee2b1c91328c4f3496cd535cd06e2517aa82f2297fd1e3b5006b41112840f764736f6c63430008140033","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.20 ^0.8.20;\n\n// contracts/interfaces/IAdmin.sol\n\ninterface IAdmin {\n // ============ Events ============\n\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n event ChainGasAmountUpdated(uint256 oldChainGasAmount, uint256 newChainGasAmount);\n\n // ============ Methods ============\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n\n function setChainGasAmount(uint256 newChainGasAmount) external;\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/libs/Errors.sol\n\nerror DeadlineExceeded();\nerror DeadlineNotExceeded();\nerror DeadlineTooShort();\nerror InsufficientOutputAmount();\n\nerror MsgValueIncorrect();\nerror PoolNotFound();\nerror TokenAddressMismatch();\nerror TokenNotContract();\nerror TokenNotETH();\nerror TokensIdentical();\n\nerror ChainIncorrect();\nerror AmountIncorrect();\nerror ZeroAddress();\n\nerror DisputePeriodNotPassed();\nerror DisputePeriodPassed();\nerror SenderIncorrect();\nerror StatusIncorrect();\nerror TransactionIdIncorrect();\nerror TransactionRelayed();\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// contracts/libs/UniversalToken.sol\n\nlibrary UniversalTokenLib {\n using SafeERC20 for IERC20;\n\n address internal constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Transfers tokens to the given account. Reverts if transfer is not successful.\n /// @dev This might trigger fallback, if ETH is transferred to the contract.\n /// Make sure this can not lead to reentrancy attacks.\n function universalTransfer(address token, address to, uint256 value) internal {\n // Don't do anything, if need to send tokens to this address\n if (to == address(this)) return;\n // Don't do anything, if trying to send zero value\n if (value == 0) return;\n if (token == ETH_ADDRESS) {\n /// @dev Note: this can potentially lead to executing code in `to`.\n // solhint-disable-next-line avoid-low-level-calls\n (bool success,) = to.call{value: value}(\"\");\n require(success, \"ETH transfer failed\");\n } else {\n IERC20(token).safeTransfer(to, value);\n }\n }\n\n /// @notice Issues an infinite allowance to the spender, if the current allowance is insufficient\n /// to spend the given amount.\n function universalApproveInfinity(address token, address spender, uint256 amountToSpend) internal {\n // ETH Chad doesn't require your approval\n if (token == ETH_ADDRESS) return;\n // No-op if allowance is already sufficient\n uint256 allowance = IERC20(token).allowance(address(this), spender);\n if (allowance \u003e= amountToSpend) return;\n // Otherwise, reset approval to 0 and set to max allowance\n if (allowance \u003e 0) IERC20(token).safeDecreaseAllowance(spender, allowance);\n IERC20(token).safeIncreaseAllowance(spender, type(uint256).max);\n }\n\n /// @notice Returns the balance of the given token (or native ETH) for the given account.\n function universalBalanceOf(address token, address account) internal view returns (uint256) {\n if (token == ETH_ADDRESS) {\n return account.balance;\n } else {\n return IERC20(token).balanceOf(account);\n }\n }\n\n /// @dev Checks that token is a contract and not ETH_ADDRESS.\n function assertIsContract(address token) internal view {\n // Check that ETH_ADDRESS was not used (in case this is a predeploy on any of the chains)\n if (token == UniversalTokenLib.ETH_ADDRESS) revert TokenNotContract();\n // Check that token is not an EOA\n if (token.code.length == 0) revert TokenNotContract();\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/Admin.sol\n\ncontract Admin is IAdmin, AccessControlEnumerable {\n using UniversalTokenLib for address;\n\n bytes32 public constant RELAYER_ROLE = keccak256(\"RELAYER_ROLE\");\n bytes32 public constant REFUNDER_ROLE = keccak256(\"REFUNDER_ROLE\");\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n uint256 public constant FEE_BPS = 1e6;\n uint256 public constant FEE_RATE_MAX = 0.01e6; // max 1% on origin amount\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Chain gas amount to forward as rebate if requested\n uint256 public chainGasAmount;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n }\n\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n require(newFeeRate \u003c= FEE_RATE_MAX, \"newFeeRate \u003e max\");\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n token.universalTransfer(recipient, feeAmount);\n emit FeesSwept(token, recipient, feeAmount);\n }\n\n function setChainGasAmount(uint256 newChainGasAmount) external onlyRole(GOVERNOR_ROLE) {\n uint256 oldChainGasAmount = chainGasAmount;\n chainGasAmount = newChainGasAmount;\n emit ChainGasAmountUpdated(oldChainGasAmount, newChainGasAmount);\n }\n}\n\n// contracts/FastBridge.sol\n\ncontract FastBridge is IFastBridge, Admin {\n using SafeERC20 for IERC20;\n using UniversalTokenLib for address;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Delay for a transaction after which it could be permisionlessly refunded\n uint256 public constant REFUND_DELAY = 7 days;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeStatus) public bridgeStatuses;\n /// @notice Proof of relayed bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeProof) public bridgeProofs;\n /// @notice Whether bridge has been relayed on destination chain\n mapping(bytes32 =\u003e bool) public bridgeRelays;\n\n /// @dev to prevent replays\n uint256 public nonce;\n // @dev the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @notice Pulls a requested token from the user to the requested recipient.\n /// @dev Be careful of re-entrancy issues when msg.value \u003e 0 and recipient != address(this)\n function _pullToken(address recipient, address token, uint256 amount) internal returns (uint256 amountPulled) {\n if (token != UniversalTokenLib.ETH_ADDRESS) {\n token.assertIsContract();\n // Record token balance before transfer\n amountPulled = IERC20(token).balanceOf(recipient);\n // Token needs to be pulled only if msg.value is zero\n // This way user can specify WETH as the origin asset\n IERC20(token).safeTransferFrom(msg.sender, recipient, amount);\n // Use the difference between the recorded balance and the current balance as the amountPulled\n amountPulled = IERC20(token).balanceOf(recipient) - amountPulled;\n } else {\n // Otherwise, we need to check that ETH amount matches msg.value\n if (amount != msg.value) revert MsgValueIncorrect();\n // Transfer value to recipient if not this address\n if (recipient != address(this)) token.universalTransfer(recipient, amount);\n // We will forward msg.value in the external call later, if recipient is not this contract\n amountPulled = msg.value;\n }\n }\n\n /// @inheritdoc IFastBridge\n function getBridgeTransaction(bytes memory request) public pure returns (BridgeTransaction memory) {\n return abi.decode(request, (BridgeTransaction));\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n // check bridge params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n\n // transfer tokens to bridge contract\n // @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _pullToken(address(this), params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n\n // set status to requested\n bytes memory request = abi.encode(\n BridgeTransaction({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n sendChainGas: params.sendChainGas,\n deadline: params.deadline,\n nonce: nonce++ // increment nonce on every bridge\n })\n );\n bytes32 transactionId = keccak256(request);\n bridgeStatuses[transactionId] = BridgeStatus.REQUESTED;\n\n emit BridgeRequested(\n transactionId,\n params.sender,\n request,\n params.dstChainId,\n params.originToken,\n params.destToken,\n originAmount,\n params.destAmount,\n params.sendChainGas\n );\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes memory request) external payable onlyRole(RELAYER_ROLE) {\n bytes32 transactionId = keccak256(request);\n BridgeTransaction memory transaction = getBridgeTransaction(request);\n if (transaction.destChainId != uint32(block.chainid)) revert ChainIncorrect();\n\n // check haven't exceeded deadline for relay to happen\n if (block.timestamp \u003e transaction.deadline) revert DeadlineExceeded();\n\n // mark bridge transaction as relayed\n if (bridgeRelays[transactionId]) revert TransactionRelayed();\n bridgeRelays[transactionId] = true;\n\n // transfer tokens to recipient on destination chain and gas rebate if requested\n address to = transaction.destRecipient;\n address token = transaction.destToken;\n uint256 amount = transaction.destAmount;\n\n uint256 rebate = chainGasAmount;\n if (!transaction.sendChainGas) {\n // forward erc20\n rebate = 0;\n _pullToken(to, token, amount);\n } else if (token == UniversalTokenLib.ETH_ADDRESS) {\n // lump in gas rebate into amount in native gas token\n _pullToken(to, token, amount + rebate);\n } else {\n // forward erc20 then forward gas rebate in native gas token\n _pullToken(to, token, amount);\n _pullToken(to, UniversalTokenLib.ETH_ADDRESS, rebate);\n }\n\n emit BridgeRelayed(\n transactionId,\n msg.sender,\n to,\n transaction.originChainId,\n transaction.originToken,\n transaction.destToken,\n transaction.originAmount,\n transaction.destAmount,\n rebate\n );\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes memory request, bytes32 destTxHash) external onlyRole(RELAYER_ROLE) {\n bytes32 transactionId = keccak256(request);\n // update bridge tx status given proof provided\n if (bridgeStatuses[transactionId] != BridgeStatus.REQUESTED) revert StatusIncorrect();\n bridgeStatuses[transactionId] = BridgeStatus.RELAYER_PROVED;\n bridgeProofs[transactionId] = BridgeProof({timestamp: uint96(block.timestamp), relayer: msg.sender}); // overflow ok\n\n emit BridgeProofProvided(transactionId, msg.sender, destTxHash);\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint96(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint96).max but\n /// proof.timestamp \u003c type(uint96).max via unchecked statement\n /// @param proof The bridge proof\n /// @return delta Time delta since proof submitted\n function _timeSince(BridgeProof memory proof) internal view returns (uint256 delta) {\n unchecked {\n delta = uint96(block.timestamp) - proof.timestamp;\n }\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n if (bridgeStatuses[transactionId] != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n BridgeProof memory proof = bridgeProofs[transactionId];\n if (proof.relayer != relayer) revert SenderIncorrect();\n return _timeSince(proof) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes memory request, address to) external onlyRole(RELAYER_ROLE) {\n bytes32 transactionId = keccak256(request);\n BridgeTransaction memory transaction = getBridgeTransaction(request);\n\n // update bridge tx status if able to claim origin collateral\n if (bridgeStatuses[transactionId] != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n\n BridgeProof memory proof = bridgeProofs[transactionId];\n if (proof.relayer != msg.sender) revert SenderIncorrect();\n if (_timeSince(proof) \u003c= DISPUTE_PERIOD) revert DisputePeriodNotPassed();\n\n bridgeStatuses[transactionId] = BridgeStatus.RELAYER_CLAIMED;\n\n // update protocol fees if origin fee amount exists\n if (transaction.originFeeAmount \u003e 0) protocolFees[transaction.originToken] += transaction.originFeeAmount;\n\n // transfer origin collateral less fee to specified address\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositClaimed(transactionId, msg.sender, to, token, amount);\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n if (bridgeStatuses[transactionId] != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(bridgeProofs[transactionId]) \u003e DISPUTE_PERIOD) revert DisputePeriodPassed();\n\n // @dev relayer gets slashed effectively if dest relay has gone thru\n bridgeStatuses[transactionId] = BridgeStatus.REQUESTED;\n delete bridgeProofs[transactionId];\n\n emit BridgeProofDisputed(transactionId, msg.sender);\n }\n\n /// @inheritdoc IFastBridge\n function refund(bytes memory request) external {\n bytes32 transactionId = keccak256(request);\n BridgeTransaction memory transaction = getBridgeTransaction(request);\n\n if (hasRole(REFUNDER_ROLE, msg.sender)) {\n // Refunder can refund if deadline has passed\n if (block.timestamp \u003c= transaction.deadline) revert DeadlineNotExceeded();\n } else {\n // Permissionless refund is allowed after REFUND_DELAY\n if (block.timestamp \u003c= transaction.deadline + REFUND_DELAY) revert DeadlineNotExceeded();\n }\n\n // set status to refunded if still in requested state\n if (bridgeStatuses[transactionId] != BridgeStatus.REQUESTED) revert StatusIncorrect();\n bridgeStatuses[transactionId] = BridgeStatus.REFUNDED;\n\n // transfer origin collateral back to original sender\n address to = transaction.originSender;\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount + transaction.originFeeAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n }\n}\n\n// test/FastBridgeMock.sol\n\ncontract FastBridgeMock is IFastBridge, Admin {\n // @dev the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @dev to prevent replays\n uint256 public nonce;\n\n function getBridgeTransaction(bytes memory request) public pure returns (BridgeTransaction memory) {\n return abi.decode(request, (BridgeTransaction));\n }\n\n // used for testing in go.\n // see: https://ethereum.stackexchange.com/questions/21155/how-to-expose-enum-in-solidity-contract\n // make sure to update fastbridge/status.go if this changes\n // or underliyng enum changes.\n //\n // TODO: a foundry test should be added to ensure this is always in sync.\n function getEnumKeyByValue(FastBridge.BridgeStatus keyValue) public pure returns (string memory) {\n if (FastBridge.BridgeStatus.NULL == keyValue) return \"NULL\";\n if (FastBridge.BridgeStatus.REQUESTED == keyValue) return \"REQUESTED\";\n if (FastBridge.BridgeStatus.RELAYER_PROVED == keyValue) return \"RELAYER_PROVED\";\n if (FastBridge.BridgeStatus.RELAYER_CLAIMED == keyValue) return \"RELAYER_CLAIMED\";\n if (FastBridge.BridgeStatus.REFUNDED == keyValue) return \"REFUNDED\";\n return \"\";\n }\n\n function mockBridgeRequest(bytes32 transactionId, address sender, BridgeParams memory params) external {\n uint256 originFeeAmount = (params.originAmount * protocolFeeRate) / FEE_BPS;\n params.originAmount -= originFeeAmount;\n\n bytes memory request = abi.encode(\n BridgeTransaction({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: params.originAmount, // includes relayer fee\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n sendChainGas: params.sendChainGas,\n deadline: params.deadline,\n nonce: nonce++ // increment nonce on every bridge\n })\n );\n\n emit BridgeRequested(\n transactionId,\n params.sender,\n request,\n params.dstChainId,\n params.originToken,\n params.destToken,\n params.originAmount,\n params.destAmount,\n params.sendChainGas\n );\n }\n\n function mockBridgeRequestRaw(bytes32 transactionId, address sender, bytes memory request) external {\n BridgeTransaction memory transaction = getBridgeTransaction(request);\n emit BridgeRequested(\n transactionId,\n transaction.originSender,\n request,\n transaction.destChainId,\n transaction.originToken,\n transaction.destToken,\n transaction.originAmount,\n transaction.destAmount,\n transaction.sendChainGas\n );\n }\n\n function mockBridgeRelayer(\n bytes32 transactionId,\n address relayer,\n address to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n )\n external\n {\n emit BridgeRelayed(\n transactionId, relayer, to, originChainId, originToken, destToken, originAmount, destAmount, chainGasAmount\n );\n }\n\n function bridge(BridgeParams memory params) external payable {\n revert(\"not implemented\");\n }\n\n function relay(bytes memory request) external payable {\n revert(\"not implemented\");\n }\n\n function prove(bytes memory request, bytes32 destTxHash) external {\n revert(\"not implemented\");\n }\n\n function canClaim(bytes32 transactionid, address relayer) external view returns (bool) {\n revert(\"not implemented\");\n }\n\n function claim(bytes memory request, address to) external {\n revert(\"not implemented\");\n }\n\n function dispute(bytes32 transactionId) external {\n revert(\"not implemented\");\n }\n\n function refund(bytes memory request) external {\n revert(\"not implemented\");\n }\n}\n","language":"Solidity","languageVersion":"0.8.20","compilerVersion":"0.8.20","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"39250:5018:0:-:0;;;;;;;;;;;;;;;-1:-1:-1;;;39250:5018:0;;;;;;;;;;;;;;;;;","srcMapRuntime":"39250:5018:0:-:0;;;;;;;;","abiDefinition":[{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"currentAllowance","type":"uint256"},{"internalType":"uint256","name":"requestedDecrease","type":"uint256"}],"name":"SafeERC20FailedDecreaseAllowance","type":"error"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"SafeERC20FailedOperation","type":"error"}],"userDoc":{"kind":"user","methods":{},"version":1},"developerDoc":{"details":"Wrappers around ERC20 operations that throw on failure (when the token contract returns false). Tokens that return no value (and instead revert or throw on failure) are also supported, non-reverting calls are assumed to be successful. To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract, which allows you to call the safe operations as `token.safeTransfer(...)`, etc.","errors":{"SafeERC20FailedDecreaseAllowance(address,uint256,uint256)":[{"details":"Indicates a failed `decreaseAllowance` request."}],"SafeERC20FailedOperation(address)":[{"details":"An operation with an ERC20 token failed."}]},"kind":"dev","methods":{},"title":"SafeERC20","version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.20+commit.a1b79de6\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"currentAllowance\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"requestedDecrease\",\"type\":\"uint256\"}],\"name\":\"SafeERC20FailedDecreaseAllowance\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"}],\"name\":\"SafeERC20FailedOperation\",\"type\":\"error\"}],\"devdoc\":{\"details\":\"Wrappers around ERC20 operations that throw on failure (when the token contract returns false). Tokens that return no value (and instead revert or throw on failure) are also supported, non-reverting calls are assumed to be successful. To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract, which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\",\"errors\":{\"SafeERC20FailedDecreaseAllowance(address,uint256,uint256)\":[{\"details\":\"Indicates a failed `decreaseAllowance` request.\"}],\"SafeERC20FailedOperation(address)\":[{\"details\":\"An operation with an ERC20 token failed.\"}]},\"kind\":\"dev\",\"methods\":{},\"title\":\"SafeERC20\",\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeMock.sol\":\"SafeERC20\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeMock.sol\":{\"keccak256\":\"0x620e81214ecd324ae8b971219291f176c454ce76fb1c01d656428096da8f1366\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://18e556772c12e13aa2d52a50cc7c48e676c8d5af22b90adaf7befb39cdd08e64\",\"dweb:/ipfs/QmPrQc98TxHCFMeuFNADyjr6Nqo52rHhHy1LBcsVdMRXjL\"]}},\"version\":1}"},"hashes":{}},"solidity/FastBridgeMock.sol:UniversalTokenLib":{"code":"0x60566037600b82828239805160001a607314602a57634e487b7160e01b600052600060045260246000fd5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600080fdfea26469706673582212202023f39864841dc931462dc7b8bdf9ede1735f580a13a3476b5bff0f5f9ca81b64736f6c63430008140033","runtime-code":"0x73000000000000000000000000000000000000000030146080604052600080fdfea26469706673582212202023f39864841dc931462dc7b8bdf9ede1735f580a13a3476b5bff0f5f9ca81b64736f6c63430008140033","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.20 ^0.8.20;\n\n// contracts/interfaces/IAdmin.sol\n\ninterface IAdmin {\n // ============ Events ============\n\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n event ChainGasAmountUpdated(uint256 oldChainGasAmount, uint256 newChainGasAmount);\n\n // ============ Methods ============\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n\n function setChainGasAmount(uint256 newChainGasAmount) external;\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/libs/Errors.sol\n\nerror DeadlineExceeded();\nerror DeadlineNotExceeded();\nerror DeadlineTooShort();\nerror InsufficientOutputAmount();\n\nerror MsgValueIncorrect();\nerror PoolNotFound();\nerror TokenAddressMismatch();\nerror TokenNotContract();\nerror TokenNotETH();\nerror TokensIdentical();\n\nerror ChainIncorrect();\nerror AmountIncorrect();\nerror ZeroAddress();\n\nerror DisputePeriodNotPassed();\nerror DisputePeriodPassed();\nerror SenderIncorrect();\nerror StatusIncorrect();\nerror TransactionIdIncorrect();\nerror TransactionRelayed();\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// contracts/libs/UniversalToken.sol\n\nlibrary UniversalTokenLib {\n using SafeERC20 for IERC20;\n\n address internal constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Transfers tokens to the given account. Reverts if transfer is not successful.\n /// @dev This might trigger fallback, if ETH is transferred to the contract.\n /// Make sure this can not lead to reentrancy attacks.\n function universalTransfer(address token, address to, uint256 value) internal {\n // Don't do anything, if need to send tokens to this address\n if (to == address(this)) return;\n // Don't do anything, if trying to send zero value\n if (value == 0) return;\n if (token == ETH_ADDRESS) {\n /// @dev Note: this can potentially lead to executing code in `to`.\n // solhint-disable-next-line avoid-low-level-calls\n (bool success,) = to.call{value: value}(\"\");\n require(success, \"ETH transfer failed\");\n } else {\n IERC20(token).safeTransfer(to, value);\n }\n }\n\n /// @notice Issues an infinite allowance to the spender, if the current allowance is insufficient\n /// to spend the given amount.\n function universalApproveInfinity(address token, address spender, uint256 amountToSpend) internal {\n // ETH Chad doesn't require your approval\n if (token == ETH_ADDRESS) return;\n // No-op if allowance is already sufficient\n uint256 allowance = IERC20(token).allowance(address(this), spender);\n if (allowance \u003e= amountToSpend) return;\n // Otherwise, reset approval to 0 and set to max allowance\n if (allowance \u003e 0) IERC20(token).safeDecreaseAllowance(spender, allowance);\n IERC20(token).safeIncreaseAllowance(spender, type(uint256).max);\n }\n\n /// @notice Returns the balance of the given token (or native ETH) for the given account.\n function universalBalanceOf(address token, address account) internal view returns (uint256) {\n if (token == ETH_ADDRESS) {\n return account.balance;\n } else {\n return IERC20(token).balanceOf(account);\n }\n }\n\n /// @dev Checks that token is a contract and not ETH_ADDRESS.\n function assertIsContract(address token) internal view {\n // Check that ETH_ADDRESS was not used (in case this is a predeploy on any of the chains)\n if (token == UniversalTokenLib.ETH_ADDRESS) revert TokenNotContract();\n // Check that token is not an EOA\n if (token.code.length == 0) revert TokenNotContract();\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/Admin.sol\n\ncontract Admin is IAdmin, AccessControlEnumerable {\n using UniversalTokenLib for address;\n\n bytes32 public constant RELAYER_ROLE = keccak256(\"RELAYER_ROLE\");\n bytes32 public constant REFUNDER_ROLE = keccak256(\"REFUNDER_ROLE\");\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n uint256 public constant FEE_BPS = 1e6;\n uint256 public constant FEE_RATE_MAX = 0.01e6; // max 1% on origin amount\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Chain gas amount to forward as rebate if requested\n uint256 public chainGasAmount;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n }\n\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n require(newFeeRate \u003c= FEE_RATE_MAX, \"newFeeRate \u003e max\");\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n token.universalTransfer(recipient, feeAmount);\n emit FeesSwept(token, recipient, feeAmount);\n }\n\n function setChainGasAmount(uint256 newChainGasAmount) external onlyRole(GOVERNOR_ROLE) {\n uint256 oldChainGasAmount = chainGasAmount;\n chainGasAmount = newChainGasAmount;\n emit ChainGasAmountUpdated(oldChainGasAmount, newChainGasAmount);\n }\n}\n\n// contracts/FastBridge.sol\n\ncontract FastBridge is IFastBridge, Admin {\n using SafeERC20 for IERC20;\n using UniversalTokenLib for address;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Delay for a transaction after which it could be permisionlessly refunded\n uint256 public constant REFUND_DELAY = 7 days;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeStatus) public bridgeStatuses;\n /// @notice Proof of relayed bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeProof) public bridgeProofs;\n /// @notice Whether bridge has been relayed on destination chain\n mapping(bytes32 =\u003e bool) public bridgeRelays;\n\n /// @dev to prevent replays\n uint256 public nonce;\n // @dev the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @notice Pulls a requested token from the user to the requested recipient.\n /// @dev Be careful of re-entrancy issues when msg.value \u003e 0 and recipient != address(this)\n function _pullToken(address recipient, address token, uint256 amount) internal returns (uint256 amountPulled) {\n if (token != UniversalTokenLib.ETH_ADDRESS) {\n token.assertIsContract();\n // Record token balance before transfer\n amountPulled = IERC20(token).balanceOf(recipient);\n // Token needs to be pulled only if msg.value is zero\n // This way user can specify WETH as the origin asset\n IERC20(token).safeTransferFrom(msg.sender, recipient, amount);\n // Use the difference between the recorded balance and the current balance as the amountPulled\n amountPulled = IERC20(token).balanceOf(recipient) - amountPulled;\n } else {\n // Otherwise, we need to check that ETH amount matches msg.value\n if (amount != msg.value) revert MsgValueIncorrect();\n // Transfer value to recipient if not this address\n if (recipient != address(this)) token.universalTransfer(recipient, amount);\n // We will forward msg.value in the external call later, if recipient is not this contract\n amountPulled = msg.value;\n }\n }\n\n /// @inheritdoc IFastBridge\n function getBridgeTransaction(bytes memory request) public pure returns (BridgeTransaction memory) {\n return abi.decode(request, (BridgeTransaction));\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n // check bridge params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n\n // transfer tokens to bridge contract\n // @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _pullToken(address(this), params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n\n // set status to requested\n bytes memory request = abi.encode(\n BridgeTransaction({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n sendChainGas: params.sendChainGas,\n deadline: params.deadline,\n nonce: nonce++ // increment nonce on every bridge\n })\n );\n bytes32 transactionId = keccak256(request);\n bridgeStatuses[transactionId] = BridgeStatus.REQUESTED;\n\n emit BridgeRequested(\n transactionId,\n params.sender,\n request,\n params.dstChainId,\n params.originToken,\n params.destToken,\n originAmount,\n params.destAmount,\n params.sendChainGas\n );\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes memory request) external payable onlyRole(RELAYER_ROLE) {\n bytes32 transactionId = keccak256(request);\n BridgeTransaction memory transaction = getBridgeTransaction(request);\n if (transaction.destChainId != uint32(block.chainid)) revert ChainIncorrect();\n\n // check haven't exceeded deadline for relay to happen\n if (block.timestamp \u003e transaction.deadline) revert DeadlineExceeded();\n\n // mark bridge transaction as relayed\n if (bridgeRelays[transactionId]) revert TransactionRelayed();\n bridgeRelays[transactionId] = true;\n\n // transfer tokens to recipient on destination chain and gas rebate if requested\n address to = transaction.destRecipient;\n address token = transaction.destToken;\n uint256 amount = transaction.destAmount;\n\n uint256 rebate = chainGasAmount;\n if (!transaction.sendChainGas) {\n // forward erc20\n rebate = 0;\n _pullToken(to, token, amount);\n } else if (token == UniversalTokenLib.ETH_ADDRESS) {\n // lump in gas rebate into amount in native gas token\n _pullToken(to, token, amount + rebate);\n } else {\n // forward erc20 then forward gas rebate in native gas token\n _pullToken(to, token, amount);\n _pullToken(to, UniversalTokenLib.ETH_ADDRESS, rebate);\n }\n\n emit BridgeRelayed(\n transactionId,\n msg.sender,\n to,\n transaction.originChainId,\n transaction.originToken,\n transaction.destToken,\n transaction.originAmount,\n transaction.destAmount,\n rebate\n );\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes memory request, bytes32 destTxHash) external onlyRole(RELAYER_ROLE) {\n bytes32 transactionId = keccak256(request);\n // update bridge tx status given proof provided\n if (bridgeStatuses[transactionId] != BridgeStatus.REQUESTED) revert StatusIncorrect();\n bridgeStatuses[transactionId] = BridgeStatus.RELAYER_PROVED;\n bridgeProofs[transactionId] = BridgeProof({timestamp: uint96(block.timestamp), relayer: msg.sender}); // overflow ok\n\n emit BridgeProofProvided(transactionId, msg.sender, destTxHash);\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint96(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint96).max but\n /// proof.timestamp \u003c type(uint96).max via unchecked statement\n /// @param proof The bridge proof\n /// @return delta Time delta since proof submitted\n function _timeSince(BridgeProof memory proof) internal view returns (uint256 delta) {\n unchecked {\n delta = uint96(block.timestamp) - proof.timestamp;\n }\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n if (bridgeStatuses[transactionId] != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n BridgeProof memory proof = bridgeProofs[transactionId];\n if (proof.relayer != relayer) revert SenderIncorrect();\n return _timeSince(proof) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes memory request, address to) external onlyRole(RELAYER_ROLE) {\n bytes32 transactionId = keccak256(request);\n BridgeTransaction memory transaction = getBridgeTransaction(request);\n\n // update bridge tx status if able to claim origin collateral\n if (bridgeStatuses[transactionId] != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n\n BridgeProof memory proof = bridgeProofs[transactionId];\n if (proof.relayer != msg.sender) revert SenderIncorrect();\n if (_timeSince(proof) \u003c= DISPUTE_PERIOD) revert DisputePeriodNotPassed();\n\n bridgeStatuses[transactionId] = BridgeStatus.RELAYER_CLAIMED;\n\n // update protocol fees if origin fee amount exists\n if (transaction.originFeeAmount \u003e 0) protocolFees[transaction.originToken] += transaction.originFeeAmount;\n\n // transfer origin collateral less fee to specified address\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositClaimed(transactionId, msg.sender, to, token, amount);\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n if (bridgeStatuses[transactionId] != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(bridgeProofs[transactionId]) \u003e DISPUTE_PERIOD) revert DisputePeriodPassed();\n\n // @dev relayer gets slashed effectively if dest relay has gone thru\n bridgeStatuses[transactionId] = BridgeStatus.REQUESTED;\n delete bridgeProofs[transactionId];\n\n emit BridgeProofDisputed(transactionId, msg.sender);\n }\n\n /// @inheritdoc IFastBridge\n function refund(bytes memory request) external {\n bytes32 transactionId = keccak256(request);\n BridgeTransaction memory transaction = getBridgeTransaction(request);\n\n if (hasRole(REFUNDER_ROLE, msg.sender)) {\n // Refunder can refund if deadline has passed\n if (block.timestamp \u003c= transaction.deadline) revert DeadlineNotExceeded();\n } else {\n // Permissionless refund is allowed after REFUND_DELAY\n if (block.timestamp \u003c= transaction.deadline + REFUND_DELAY) revert DeadlineNotExceeded();\n }\n\n // set status to refunded if still in requested state\n if (bridgeStatuses[transactionId] != BridgeStatus.REQUESTED) revert StatusIncorrect();\n bridgeStatuses[transactionId] = BridgeStatus.REFUNDED;\n\n // transfer origin collateral back to original sender\n address to = transaction.originSender;\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount + transaction.originFeeAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n }\n}\n\n// test/FastBridgeMock.sol\n\ncontract FastBridgeMock is IFastBridge, Admin {\n // @dev the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @dev to prevent replays\n uint256 public nonce;\n\n function getBridgeTransaction(bytes memory request) public pure returns (BridgeTransaction memory) {\n return abi.decode(request, (BridgeTransaction));\n }\n\n // used for testing in go.\n // see: https://ethereum.stackexchange.com/questions/21155/how-to-expose-enum-in-solidity-contract\n // make sure to update fastbridge/status.go if this changes\n // or underliyng enum changes.\n //\n // TODO: a foundry test should be added to ensure this is always in sync.\n function getEnumKeyByValue(FastBridge.BridgeStatus keyValue) public pure returns (string memory) {\n if (FastBridge.BridgeStatus.NULL == keyValue) return \"NULL\";\n if (FastBridge.BridgeStatus.REQUESTED == keyValue) return \"REQUESTED\";\n if (FastBridge.BridgeStatus.RELAYER_PROVED == keyValue) return \"RELAYER_PROVED\";\n if (FastBridge.BridgeStatus.RELAYER_CLAIMED == keyValue) return \"RELAYER_CLAIMED\";\n if (FastBridge.BridgeStatus.REFUNDED == keyValue) return \"REFUNDED\";\n return \"\";\n }\n\n function mockBridgeRequest(bytes32 transactionId, address sender, BridgeParams memory params) external {\n uint256 originFeeAmount = (params.originAmount * protocolFeeRate) / FEE_BPS;\n params.originAmount -= originFeeAmount;\n\n bytes memory request = abi.encode(\n BridgeTransaction({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: params.originAmount, // includes relayer fee\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n sendChainGas: params.sendChainGas,\n deadline: params.deadline,\n nonce: nonce++ // increment nonce on every bridge\n })\n );\n\n emit BridgeRequested(\n transactionId,\n params.sender,\n request,\n params.dstChainId,\n params.originToken,\n params.destToken,\n params.originAmount,\n params.destAmount,\n params.sendChainGas\n );\n }\n\n function mockBridgeRequestRaw(bytes32 transactionId, address sender, bytes memory request) external {\n BridgeTransaction memory transaction = getBridgeTransaction(request);\n emit BridgeRequested(\n transactionId,\n transaction.originSender,\n request,\n transaction.destChainId,\n transaction.originToken,\n transaction.destToken,\n transaction.originAmount,\n transaction.destAmount,\n transaction.sendChainGas\n );\n }\n\n function mockBridgeRelayer(\n bytes32 transactionId,\n address relayer,\n address to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n )\n external\n {\n emit BridgeRelayed(\n transactionId, relayer, to, originChainId, originToken, destToken, originAmount, destAmount, chainGasAmount\n );\n }\n\n function bridge(BridgeParams memory params) external payable {\n revert(\"not implemented\");\n }\n\n function relay(bytes memory request) external payable {\n revert(\"not implemented\");\n }\n\n function prove(bytes memory request, bytes32 destTxHash) external {\n revert(\"not implemented\");\n }\n\n function canClaim(bytes32 transactionid, address relayer) external view returns (bool) {\n revert(\"not implemented\");\n }\n\n function claim(bytes memory request, address to) external {\n revert(\"not implemented\");\n }\n\n function dispute(bytes32 transactionId) external {\n revert(\"not implemented\");\n }\n\n function refund(bytes memory request) external {\n revert(\"not implemented\");\n }\n}\n","language":"Solidity","languageVersion":"0.8.20","compilerVersion":"0.8.20","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"51209:2551:0:-:0;;;;;;;;;;;;;;;-1:-1:-1;;;51209:2551:0;;;;;;;;;;;;;;;;;","srcMapRuntime":"51209:2551:0:-:0;;;;;;;;","abiDefinition":[],"userDoc":{"kind":"user","methods":{},"version":1},"developerDoc":{"kind":"dev","methods":{},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.20+commit.a1b79de6\"},\"language\":\"Solidity\",\"output\":{\"abi\":[],\"devdoc\":{\"kind\":\"dev\",\"methods\":{},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeMock.sol\":\"UniversalTokenLib\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeMock.sol\":{\"keccak256\":\"0x620e81214ecd324ae8b971219291f176c454ce76fb1c01d656428096da8f1366\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://18e556772c12e13aa2d52a50cc7c48e676c8d5af22b90adaf7befb39cdd08e64\",\"dweb:/ipfs/QmPrQc98TxHCFMeuFNADyjr6Nqo52rHhHy1LBcsVdMRXjL\"]}},\"version\":1}"},"hashes":{}}} \ No newline at end of file +{"solidity/FastBridgeMock.sol:AccessControl":{"code":"0x","runtime-code":"0x","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.20 ^0.8.20 ^0.8.4;\n\n// contracts/interfaces/IAdmin.sol\n\ninterface IAdmin {\n // ============ Events ============\n\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n event ChainGasAmountUpdated(uint256 oldChainGasAmount, uint256 newChainGasAmount);\n\n // ============ Methods ============\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n\n function setChainGasAmount(uint256 newChainGasAmount) external;\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IMulticallTarget.sol\n\n/// @notice Interface for a contract that can be called multiple times by the same caller. Inspired by MulticallV3:\n/// https://github.com/mds1/multicall/blob/master/src/Multicall3.sol\ninterface IMulticallTarget {\n struct Result {\n bool success;\n bytes returnData;\n }\n\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external;\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results);\n}\n\n// contracts/libs/Errors.sol\n\nerror DeadlineExceeded();\nerror DeadlineNotExceeded();\nerror DeadlineTooShort();\nerror InsufficientOutputAmount();\n\nerror MsgValueIncorrect();\nerror PoolNotFound();\nerror TokenAddressMismatch();\nerror TokenNotContract();\nerror TokenNotETH();\nerror TokensIdentical();\n\nerror ChainIncorrect();\nerror AmountIncorrect();\nerror ZeroAddress();\n\nerror DisputePeriodNotPassed();\nerror DisputePeriodPassed();\nerror SenderIncorrect();\nerror StatusIncorrect();\nerror TransactionIdIncorrect();\nerror TransactionRelayed();\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// contracts/utils/MulticallTarget.sol\n\n// solhint-disable avoid-low-level-calls\n/// @notice Template for a contract that supports batched calls (preserving the msg.sender).\n/// Only calls with zero msg.value could be batched.\nabstract contract MulticallTarget is IMulticallTarget {\n error MulticallTarget__UndeterminedRevert();\n\n /// @notice Perform a batched call to this contract, preserving the msg.sender.\n /// The return data from each call is discarded.\n /// @dev The method is non-payable, so only calls with `msg.value == 0` could be batched.\n /// It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag.\n /// Otherwise, the whole batch call will be reverted with the original revert reason.\n /// @param data List of abi-encoded calldata for the calls to perform.\n /// @param ignoreReverts Whether to ignore the revert errors from the calls.\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external {\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\n if (!success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(result);\n }\n }\n }\n\n /// @notice Perform a batched call to this contract, preserving the msg.sender.\n /// The return data from each call is preserved.\n /// @dev The method is non-payable, so only calls with `msg.value == 0` could be batched.\n /// It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag.\n /// Otherwise, the whole batch call will be reverted with the original revert reason.\n /// @param data List of abi-encoded calldata for the calls to perform.\n /// @param ignoreReverts Whether to ignore the revert errors from the calls.\n /// @return results List of results from the calls: `(success, returnData)`.\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results)\n {\n results = new Result[](data.length);\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (results[i].success, results[i].returnData) = address(this).delegatecall(data[i]);\n if (!results[i].success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(results[i].returnData);\n }\n }\n }\n\n /// @dev Bubbles the revert message from the underlying call.\n /// Note: preserves the same custom error or revert string, if one was used.\n /// Source: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v5.0.2/contracts/utils/Address.sol#L143-L158\n function _bubbleRevert(bytes memory returnData) internal pure {\n // Look for revert reason and bubble it up if present\n if (returnData.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n // solhint-disable-next-line no-inline-assembly\n assembly {\n let returndata_size := mload(returnData)\n revert(add(32, returnData), returndata_size)\n }\n } else {\n revert MulticallTarget__UndeterminedRevert();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// contracts/libs/UniversalToken.sol\n\nlibrary UniversalTokenLib {\n using SafeERC20 for IERC20;\n\n address internal constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Transfers tokens to the given account. Reverts if transfer is not successful.\n /// @dev This might trigger fallback, if ETH is transferred to the contract.\n /// Make sure this can not lead to reentrancy attacks.\n function universalTransfer(address token, address to, uint256 value) internal {\n // Don't do anything, if need to send tokens to this address\n if (to == address(this)) return;\n // Don't do anything, if trying to send zero value\n if (value == 0) return;\n if (token == ETH_ADDRESS) {\n /// @dev Note: this can potentially lead to executing code in `to`.\n // solhint-disable-next-line avoid-low-level-calls\n (bool success,) = to.call{value: value}(\"\");\n require(success, \"ETH transfer failed\");\n } else {\n IERC20(token).safeTransfer(to, value);\n }\n }\n\n /// @notice Issues an infinite allowance to the spender, if the current allowance is insufficient\n /// to spend the given amount.\n function universalApproveInfinity(address token, address spender, uint256 amountToSpend) internal {\n // ETH Chad doesn't require your approval\n if (token == ETH_ADDRESS) return;\n // No-op if allowance is already sufficient\n uint256 allowance = IERC20(token).allowance(address(this), spender);\n if (allowance \u003e= amountToSpend) return;\n // Otherwise, reset approval to 0 and set to max allowance\n if (allowance \u003e 0) IERC20(token).safeDecreaseAllowance(spender, allowance);\n IERC20(token).safeIncreaseAllowance(spender, type(uint256).max);\n }\n\n /// @notice Returns the balance of the given token (or native ETH) for the given account.\n function universalBalanceOf(address token, address account) internal view returns (uint256) {\n if (token == ETH_ADDRESS) {\n return account.balance;\n } else {\n return IERC20(token).balanceOf(account);\n }\n }\n\n /// @dev Checks that token is a contract and not ETH_ADDRESS.\n function assertIsContract(address token) internal view {\n // Check that ETH_ADDRESS was not used (in case this is a predeploy on any of the chains)\n if (token == UniversalTokenLib.ETH_ADDRESS) revert TokenNotContract();\n // Check that token is not an EOA\n if (token.code.length == 0) revert TokenNotContract();\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/Admin.sol\n\ncontract Admin is IAdmin, AccessControlEnumerable {\n using UniversalTokenLib for address;\n\n bytes32 public constant RELAYER_ROLE = keccak256(\"RELAYER_ROLE\");\n bytes32 public constant REFUNDER_ROLE = keccak256(\"REFUNDER_ROLE\");\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n uint256 public constant FEE_BPS = 1e6;\n uint256 public constant FEE_RATE_MAX = 0.01e6; // max 1% on origin amount\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Chain gas amount to forward as rebate if requested\n uint256 public chainGasAmount;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n }\n\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n require(newFeeRate \u003c= FEE_RATE_MAX, \"newFeeRate \u003e max\");\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n token.universalTransfer(recipient, feeAmount);\n emit FeesSwept(token, recipient, feeAmount);\n }\n\n function setChainGasAmount(uint256 newChainGasAmount) external onlyRole(GOVERNOR_ROLE) {\n uint256 oldChainGasAmount = chainGasAmount;\n chainGasAmount = newChainGasAmount;\n emit ChainGasAmountUpdated(oldChainGasAmount, newChainGasAmount);\n }\n}\n\n// contracts/FastBridge.sol\n\ncontract FastBridge is IFastBridge, MulticallTarget, Admin {\n using SafeERC20 for IERC20;\n using UniversalTokenLib for address;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Delay for a transaction after which it could be permisionlessly refunded\n uint256 public constant REFUND_DELAY = 7 days;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeStatus) public bridgeStatuses;\n /// @notice Proof of relayed bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeProof) public bridgeProofs;\n /// @notice Whether bridge has been relayed on destination chain\n mapping(bytes32 =\u003e bool) public bridgeRelays;\n\n /// @dev to prevent replays\n uint256 public nonce;\n // @dev the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @notice Pulls a requested token from the user to the requested recipient.\n /// @dev Be careful of re-entrancy issues when msg.value \u003e 0 and recipient != address(this)\n function _pullToken(address recipient, address token, uint256 amount) internal returns (uint256 amountPulled) {\n if (token != UniversalTokenLib.ETH_ADDRESS) {\n token.assertIsContract();\n // Record token balance before transfer\n amountPulled = IERC20(token).balanceOf(recipient);\n // Token needs to be pulled only if msg.value is zero\n // This way user can specify WETH as the origin asset\n IERC20(token).safeTransferFrom(msg.sender, recipient, amount);\n // Use the difference between the recorded balance and the current balance as the amountPulled\n amountPulled = IERC20(token).balanceOf(recipient) - amountPulled;\n } else {\n // Otherwise, we need to check that ETH amount matches msg.value\n if (amount != msg.value) revert MsgValueIncorrect();\n // Transfer value to recipient if not this address\n if (recipient != address(this)) token.universalTransfer(recipient, amount);\n // We will forward msg.value in the external call later, if recipient is not this contract\n amountPulled = msg.value;\n }\n }\n\n /// @inheritdoc IFastBridge\n function getBridgeTransaction(bytes memory request) public pure returns (BridgeTransaction memory) {\n return abi.decode(request, (BridgeTransaction));\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n // check bridge params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n\n // transfer tokens to bridge contract\n // @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _pullToken(address(this), params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n\n // set status to requested\n bytes memory request = abi.encode(\n BridgeTransaction({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n sendChainGas: params.sendChainGas,\n deadline: params.deadline,\n nonce: nonce++ // increment nonce on every bridge\n })\n );\n bytes32 transactionId = keccak256(request);\n bridgeStatuses[transactionId] = BridgeStatus.REQUESTED;\n\n emit BridgeRequested(\n transactionId,\n params.sender,\n request,\n params.dstChainId,\n params.originToken,\n params.destToken,\n originAmount,\n params.destAmount,\n params.sendChainGas\n );\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes memory request) external payable onlyRole(RELAYER_ROLE) {\n bytes32 transactionId = keccak256(request);\n BridgeTransaction memory transaction = getBridgeTransaction(request);\n if (transaction.destChainId != uint32(block.chainid)) revert ChainIncorrect();\n\n // check haven't exceeded deadline for relay to happen\n if (block.timestamp \u003e transaction.deadline) revert DeadlineExceeded();\n\n // mark bridge transaction as relayed\n if (bridgeRelays[transactionId]) revert TransactionRelayed();\n bridgeRelays[transactionId] = true;\n\n // transfer tokens to recipient on destination chain and gas rebate if requested\n address to = transaction.destRecipient;\n address token = transaction.destToken;\n uint256 amount = transaction.destAmount;\n\n uint256 rebate = chainGasAmount;\n if (!transaction.sendChainGas) {\n // forward erc20\n rebate = 0;\n _pullToken(to, token, amount);\n } else if (token == UniversalTokenLib.ETH_ADDRESS) {\n // lump in gas rebate into amount in native gas token\n _pullToken(to, token, amount + rebate);\n } else {\n // forward erc20 then forward gas rebate in native gas token\n _pullToken(to, token, amount);\n _pullToken(to, UniversalTokenLib.ETH_ADDRESS, rebate);\n }\n\n emit BridgeRelayed(\n transactionId,\n msg.sender,\n to,\n transaction.originChainId,\n transaction.originToken,\n transaction.destToken,\n transaction.originAmount,\n transaction.destAmount,\n rebate\n );\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes memory request, bytes32 destTxHash) external onlyRole(RELAYER_ROLE) {\n bytes32 transactionId = keccak256(request);\n // update bridge tx status given proof provided\n if (bridgeStatuses[transactionId] != BridgeStatus.REQUESTED) revert StatusIncorrect();\n bridgeStatuses[transactionId] = BridgeStatus.RELAYER_PROVED;\n bridgeProofs[transactionId] = BridgeProof({timestamp: uint96(block.timestamp), relayer: msg.sender}); // overflow ok\n\n emit BridgeProofProvided(transactionId, msg.sender, destTxHash);\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint96(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint96).max but\n /// proof.timestamp \u003c type(uint96).max via unchecked statement\n /// @param proof The bridge proof\n /// @return delta Time delta since proof submitted\n function _timeSince(BridgeProof memory proof) internal view returns (uint256 delta) {\n unchecked {\n delta = uint96(block.timestamp) - proof.timestamp;\n }\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n if (bridgeStatuses[transactionId] != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n BridgeProof memory proof = bridgeProofs[transactionId];\n if (proof.relayer != relayer) revert SenderIncorrect();\n return _timeSince(proof) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes memory request, address to) external onlyRole(RELAYER_ROLE) {\n bytes32 transactionId = keccak256(request);\n BridgeTransaction memory transaction = getBridgeTransaction(request);\n\n // update bridge tx status if able to claim origin collateral\n if (bridgeStatuses[transactionId] != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n\n BridgeProof memory proof = bridgeProofs[transactionId];\n if (proof.relayer != msg.sender) revert SenderIncorrect();\n if (_timeSince(proof) \u003c= DISPUTE_PERIOD) revert DisputePeriodNotPassed();\n\n bridgeStatuses[transactionId] = BridgeStatus.RELAYER_CLAIMED;\n\n // update protocol fees if origin fee amount exists\n if (transaction.originFeeAmount \u003e 0) protocolFees[transaction.originToken] += transaction.originFeeAmount;\n\n // transfer origin collateral less fee to specified address\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositClaimed(transactionId, msg.sender, to, token, amount);\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n if (bridgeStatuses[transactionId] != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(bridgeProofs[transactionId]) \u003e DISPUTE_PERIOD) revert DisputePeriodPassed();\n\n // @dev relayer gets slashed effectively if dest relay has gone thru\n bridgeStatuses[transactionId] = BridgeStatus.REQUESTED;\n delete bridgeProofs[transactionId];\n\n emit BridgeProofDisputed(transactionId, msg.sender);\n }\n\n /// @inheritdoc IFastBridge\n function refund(bytes memory request) external {\n bytes32 transactionId = keccak256(request);\n BridgeTransaction memory transaction = getBridgeTransaction(request);\n\n if (hasRole(REFUNDER_ROLE, msg.sender)) {\n // Refunder can refund if deadline has passed\n if (block.timestamp \u003c= transaction.deadline) revert DeadlineNotExceeded();\n } else {\n // Permissionless refund is allowed after REFUND_DELAY\n if (block.timestamp \u003c= transaction.deadline + REFUND_DELAY) revert DeadlineNotExceeded();\n }\n\n // set status to refunded if still in requested state\n if (bridgeStatuses[transactionId] != BridgeStatus.REQUESTED) revert StatusIncorrect();\n bridgeStatuses[transactionId] = BridgeStatus.REFUNDED;\n\n // transfer origin collateral back to original sender\n address to = transaction.originSender;\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount + transaction.originFeeAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n }\n}\n\n// test/FastBridgeMock.sol\n\ncontract FastBridgeMock is IFastBridge, Admin {\n // @dev the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @dev to prevent replays\n uint256 public nonce;\n\n /// @notice We include an empty \"test\" function so that this contract does not appear in the coverage report.\n function testFastBridgeMock() external {}\n\n function getBridgeTransaction(bytes memory request) public pure returns (BridgeTransaction memory) {\n return abi.decode(request, (BridgeTransaction));\n }\n\n // used for testing in go.\n // see: https://ethereum.stackexchange.com/questions/21155/how-to-expose-enum-in-solidity-contract\n // make sure to update fastbridge/status.go if this changes\n // or underliyng enum changes.\n //\n // TODO: a foundry test should be added to ensure this is always in sync.\n function getEnumKeyByValue(FastBridge.BridgeStatus keyValue) public pure returns (string memory) {\n if (FastBridge.BridgeStatus.NULL == keyValue) return \"NULL\";\n if (FastBridge.BridgeStatus.REQUESTED == keyValue) return \"REQUESTED\";\n if (FastBridge.BridgeStatus.RELAYER_PROVED == keyValue) return \"RELAYER_PROVED\";\n if (FastBridge.BridgeStatus.RELAYER_CLAIMED == keyValue) return \"RELAYER_CLAIMED\";\n if (FastBridge.BridgeStatus.REFUNDED == keyValue) return \"REFUNDED\";\n return \"\";\n }\n\n function mockBridgeRequest(bytes32 transactionId, address sender, BridgeParams memory params) external {\n sender;\n uint256 originFeeAmount = (params.originAmount * protocolFeeRate) / FEE_BPS;\n params.originAmount -= originFeeAmount;\n\n bytes memory request = abi.encode(\n BridgeTransaction({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: params.originAmount, // includes relayer fee\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n sendChainGas: params.sendChainGas,\n deadline: params.deadline,\n nonce: nonce++ // increment nonce on every bridge\n })\n );\n\n emit BridgeRequested(\n transactionId,\n params.sender,\n request,\n params.dstChainId,\n params.originToken,\n params.destToken,\n params.originAmount,\n params.destAmount,\n params.sendChainGas\n );\n }\n\n function mockBridgeRequestRaw(bytes32 transactionId, address sender, bytes memory request) external {\n sender;\n BridgeTransaction memory transaction = getBridgeTransaction(request);\n emit BridgeRequested(\n transactionId,\n transaction.originSender,\n request,\n transaction.destChainId,\n transaction.originToken,\n transaction.destToken,\n transaction.originAmount,\n transaction.destAmount,\n transaction.sendChainGas\n );\n }\n\n function mockBridgeRelayer(\n bytes32 transactionId,\n address relayer,\n address to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n )\n external\n {\n emit BridgeRelayed(\n transactionId, relayer, to, originChainId, originToken, destToken, originAmount, destAmount, chainGasAmount\n );\n }\n\n function bridge(BridgeParams memory) external payable {\n revert(\"not implemented\");\n }\n\n function relay(bytes memory) external payable {\n revert(\"not implemented\");\n }\n\n function prove(bytes memory, bytes32) external pure {\n revert(\"not implemented\");\n }\n\n function canClaim(bytes32, address) external pure returns (bool) {\n revert(\"not implemented\");\n }\n\n function claim(bytes memory, address) external pure {\n revert(\"not implemented\");\n }\n\n function dispute(bytes32) external pure {\n revert(\"not implemented\");\n }\n\n function refund(bytes memory) external pure {\n revert(\"not implemented\");\n }\n}\n","language":"Solidity","languageVersion":"0.8.20","compilerVersion":"0.8.20","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"","srcMapRuntime":"","abiDefinition":[{"inputs":[],"name":"AccessControlBadConfirmation","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"bytes32","name":"neededRole","type":"bytes32"}],"name":"AccessControlUnauthorizedAccount","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"previousAdminRole","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"newAdminRole","type":"bytes32"}],"name":"RoleAdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleRevoked","type":"event"},{"inputs":[],"name":"DEFAULT_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleAdmin","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"grantRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"hasRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"callerConfirmation","type":"address"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"revokeRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"}],"userDoc":{"kind":"user","methods":{},"version":1},"developerDoc":{"details":"Contract module that allows children to implement role-based access control mechanisms. This is a lightweight version that doesn't allow enumerating role members except through off-chain means by accessing the contract event logs. Some applications may benefit from on-chain enumerability, for those cases see {AccessControlEnumerable}. Roles are referred to by their `bytes32` identifier. These should be exposed in the external API and be unique. The best way to achieve this is by using `public constant` hash digests: ```solidity bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\"); ``` Roles can be used to represent a set of permissions. To restrict access to a function call, use {hasRole}: ```solidity function foo() public { require(hasRole(MY_ROLE, msg.sender)); ... } ``` Roles can be granted and revoked dynamically via the {grantRole} and {revokeRole} functions. Each role has an associated admin role, and only accounts that have a role's admin role can call {grantRole} and {revokeRole}. By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means that only accounts with this role will be able to grant or revoke other roles. More complex role relationships can be created by using {_setRoleAdmin}. WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to grant and revoke this role. Extra precautions should be taken to secure accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules} to enforce additional security measures for this role.","errors":{"AccessControlBadConfirmation()":[{"details":"The caller of a function is not the expected one. NOTE: Don't confuse with {AccessControlUnauthorizedAccount}."}],"AccessControlUnauthorizedAccount(address,bytes32)":[{"details":"The `account` is missing a role."}]},"events":{"RoleAdminChanged(bytes32,bytes32,bytes32)":{"details":"Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole` `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite {RoleAdminChanged} not being emitted signaling this."},"RoleGranted(bytes32,address,address)":{"details":"Emitted when `account` is granted `role`. `sender` is the account that originated the contract call, an admin role bearer except when using {AccessControl-_setupRole}."},"RoleRevoked(bytes32,address,address)":{"details":"Emitted when `account` is revoked `role`. `sender` is the account that originated the contract call: - if using `revokeRole`, it is the admin role bearer - if using `renounceRole`, it is the role bearer (i.e. `account`)"}},"kind":"dev","methods":{"getRoleAdmin(bytes32)":{"details":"Returns the admin role that controls `role`. See {grantRole} and {revokeRole}. To change a role's admin, use {_setRoleAdmin}."},"grantRole(bytes32,address)":{"details":"Grants `role` to `account`. If `account` had not been already granted `role`, emits a {RoleGranted} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleGranted} event."},"hasRole(bytes32,address)":{"details":"Returns `true` if `account` has been granted `role`."},"renounceRole(bytes32,address)":{"details":"Revokes `role` from the calling account. Roles are often managed via {grantRole} and {revokeRole}: this function's purpose is to provide a mechanism for accounts to lose their privileges if they are compromised (such as when a trusted device is misplaced). If the calling account had been revoked `role`, emits a {RoleRevoked} event. Requirements: - the caller must be `callerConfirmation`. May emit a {RoleRevoked} event."},"revokeRole(bytes32,address)":{"details":"Revokes `role` from `account`. If `account` had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleRevoked} event."},"supportsInterface(bytes4)":{"details":"See {IERC165-supportsInterface}."}},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.20+commit.a1b79de6\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[],\"name\":\"AccessControlBadConfirmation\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"neededRole\",\"type\":\"bytes32\"}],\"name\":\"AccessControlUnauthorizedAccount\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"previousAdminRole\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"newAdminRole\",\"type\":\"bytes32\"}],\"name\":\"RoleAdminChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleGranted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleRevoked\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"DEFAULT_ADMIN_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"}],\"name\":\"getRoleAdmin\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"grantRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"hasRole\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"callerConfirmation\",\"type\":\"address\"}],\"name\":\"renounceRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"revokeRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes4\",\"name\":\"interfaceId\",\"type\":\"bytes4\"}],\"name\":\"supportsInterface\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"}],\"devdoc\":{\"details\":\"Contract module that allows children to implement role-based access control mechanisms. This is a lightweight version that doesn't allow enumerating role members except through off-chain means by accessing the contract event logs. Some applications may benefit from on-chain enumerability, for those cases see {AccessControlEnumerable}. Roles are referred to by their `bytes32` identifier. These should be exposed in the external API and be unique. The best way to achieve this is by using `public constant` hash digests: ```solidity bytes32 public constant MY_ROLE = keccak256(\\\"MY_ROLE\\\"); ``` Roles can be used to represent a set of permissions. To restrict access to a function call, use {hasRole}: ```solidity function foo() public { require(hasRole(MY_ROLE, msg.sender)); ... } ``` Roles can be granted and revoked dynamically via the {grantRole} and {revokeRole} functions. Each role has an associated admin role, and only accounts that have a role's admin role can call {grantRole} and {revokeRole}. By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means that only accounts with this role will be able to grant or revoke other roles. More complex role relationships can be created by using {_setRoleAdmin}. WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to grant and revoke this role. Extra precautions should be taken to secure accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules} to enforce additional security measures for this role.\",\"errors\":{\"AccessControlBadConfirmation()\":[{\"details\":\"The caller of a function is not the expected one. NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\"}],\"AccessControlUnauthorizedAccount(address,bytes32)\":[{\"details\":\"The `account` is missing a role.\"}]},\"events\":{\"RoleAdminChanged(bytes32,bytes32,bytes32)\":{\"details\":\"Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole` `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite {RoleAdminChanged} not being emitted signaling this.\"},\"RoleGranted(bytes32,address,address)\":{\"details\":\"Emitted when `account` is granted `role`. `sender` is the account that originated the contract call, an admin role bearer except when using {AccessControl-_setupRole}.\"},\"RoleRevoked(bytes32,address,address)\":{\"details\":\"Emitted when `account` is revoked `role`. `sender` is the account that originated the contract call: - if using `revokeRole`, it is the admin role bearer - if using `renounceRole`, it is the role bearer (i.e. `account`)\"}},\"kind\":\"dev\",\"methods\":{\"getRoleAdmin(bytes32)\":{\"details\":\"Returns the admin role that controls `role`. See {grantRole} and {revokeRole}. To change a role's admin, use {_setRoleAdmin}.\"},\"grantRole(bytes32,address)\":{\"details\":\"Grants `role` to `account`. If `account` had not been already granted `role`, emits a {RoleGranted} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleGranted} event.\"},\"hasRole(bytes32,address)\":{\"details\":\"Returns `true` if `account` has been granted `role`.\"},\"renounceRole(bytes32,address)\":{\"details\":\"Revokes `role` from the calling account. Roles are often managed via {grantRole} and {revokeRole}: this function's purpose is to provide a mechanism for accounts to lose their privileges if they are compromised (such as when a trusted device is misplaced). If the calling account had been revoked `role`, emits a {RoleRevoked} event. Requirements: - the caller must be `callerConfirmation`. May emit a {RoleRevoked} event.\"},\"revokeRole(bytes32,address)\":{\"details\":\"Revokes `role` from `account`. If `account` had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleRevoked} event.\"},\"supportsInterface(bytes4)\":{\"details\":\"See {IERC165-supportsInterface}.\"}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeMock.sol\":\"AccessControl\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeMock.sol\":{\"keccak256\":\"0xf2751f52f8216801d500da7464ad01f3c23a8286e155e2dcba6d21d6e7fd95a0\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://85d2edab24ebe321043d2b88038437e8f443a0ef26fa2139c72dcc2bc7fbc602\",\"dweb:/ipfs/QmcULiFPFJzFDT4aupVSDreXz8uHxcABb5nxpAG4zYzfNN\"]}},\"version\":1}"},"hashes":{"DEFAULT_ADMIN_ROLE()":"a217fddf","getRoleAdmin(bytes32)":"248a9ca3","grantRole(bytes32,address)":"2f2ff15d","hasRole(bytes32,address)":"91d14854","renounceRole(bytes32,address)":"36568abe","revokeRole(bytes32,address)":"d547741f","supportsInterface(bytes4)":"01ffc9a7"}},"solidity/FastBridgeMock.sol:AccessControlEnumerable":{"code":"0x","runtime-code":"0x","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.20 ^0.8.20 ^0.8.4;\n\n// contracts/interfaces/IAdmin.sol\n\ninterface IAdmin {\n // ============ Events ============\n\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n event ChainGasAmountUpdated(uint256 oldChainGasAmount, uint256 newChainGasAmount);\n\n // ============ Methods ============\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n\n function setChainGasAmount(uint256 newChainGasAmount) external;\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IMulticallTarget.sol\n\n/// @notice Interface for a contract that can be called multiple times by the same caller. Inspired by MulticallV3:\n/// https://github.com/mds1/multicall/blob/master/src/Multicall3.sol\ninterface IMulticallTarget {\n struct Result {\n bool success;\n bytes returnData;\n }\n\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external;\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results);\n}\n\n// contracts/libs/Errors.sol\n\nerror DeadlineExceeded();\nerror DeadlineNotExceeded();\nerror DeadlineTooShort();\nerror InsufficientOutputAmount();\n\nerror MsgValueIncorrect();\nerror PoolNotFound();\nerror TokenAddressMismatch();\nerror TokenNotContract();\nerror TokenNotETH();\nerror TokensIdentical();\n\nerror ChainIncorrect();\nerror AmountIncorrect();\nerror ZeroAddress();\n\nerror DisputePeriodNotPassed();\nerror DisputePeriodPassed();\nerror SenderIncorrect();\nerror StatusIncorrect();\nerror TransactionIdIncorrect();\nerror TransactionRelayed();\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// contracts/utils/MulticallTarget.sol\n\n// solhint-disable avoid-low-level-calls\n/// @notice Template for a contract that supports batched calls (preserving the msg.sender).\n/// Only calls with zero msg.value could be batched.\nabstract contract MulticallTarget is IMulticallTarget {\n error MulticallTarget__UndeterminedRevert();\n\n /// @notice Perform a batched call to this contract, preserving the msg.sender.\n /// The return data from each call is discarded.\n /// @dev The method is non-payable, so only calls with `msg.value == 0` could be batched.\n /// It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag.\n /// Otherwise, the whole batch call will be reverted with the original revert reason.\n /// @param data List of abi-encoded calldata for the calls to perform.\n /// @param ignoreReverts Whether to ignore the revert errors from the calls.\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external {\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\n if (!success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(result);\n }\n }\n }\n\n /// @notice Perform a batched call to this contract, preserving the msg.sender.\n /// The return data from each call is preserved.\n /// @dev The method is non-payable, so only calls with `msg.value == 0` could be batched.\n /// It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag.\n /// Otherwise, the whole batch call will be reverted with the original revert reason.\n /// @param data List of abi-encoded calldata for the calls to perform.\n /// @param ignoreReverts Whether to ignore the revert errors from the calls.\n /// @return results List of results from the calls: `(success, returnData)`.\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results)\n {\n results = new Result[](data.length);\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (results[i].success, results[i].returnData) = address(this).delegatecall(data[i]);\n if (!results[i].success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(results[i].returnData);\n }\n }\n }\n\n /// @dev Bubbles the revert message from the underlying call.\n /// Note: preserves the same custom error or revert string, if one was used.\n /// Source: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v5.0.2/contracts/utils/Address.sol#L143-L158\n function _bubbleRevert(bytes memory returnData) internal pure {\n // Look for revert reason and bubble it up if present\n if (returnData.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n // solhint-disable-next-line no-inline-assembly\n assembly {\n let returndata_size := mload(returnData)\n revert(add(32, returnData), returndata_size)\n }\n } else {\n revert MulticallTarget__UndeterminedRevert();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// contracts/libs/UniversalToken.sol\n\nlibrary UniversalTokenLib {\n using SafeERC20 for IERC20;\n\n address internal constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Transfers tokens to the given account. Reverts if transfer is not successful.\n /// @dev This might trigger fallback, if ETH is transferred to the contract.\n /// Make sure this can not lead to reentrancy attacks.\n function universalTransfer(address token, address to, uint256 value) internal {\n // Don't do anything, if need to send tokens to this address\n if (to == address(this)) return;\n // Don't do anything, if trying to send zero value\n if (value == 0) return;\n if (token == ETH_ADDRESS) {\n /// @dev Note: this can potentially lead to executing code in `to`.\n // solhint-disable-next-line avoid-low-level-calls\n (bool success,) = to.call{value: value}(\"\");\n require(success, \"ETH transfer failed\");\n } else {\n IERC20(token).safeTransfer(to, value);\n }\n }\n\n /// @notice Issues an infinite allowance to the spender, if the current allowance is insufficient\n /// to spend the given amount.\n function universalApproveInfinity(address token, address spender, uint256 amountToSpend) internal {\n // ETH Chad doesn't require your approval\n if (token == ETH_ADDRESS) return;\n // No-op if allowance is already sufficient\n uint256 allowance = IERC20(token).allowance(address(this), spender);\n if (allowance \u003e= amountToSpend) return;\n // Otherwise, reset approval to 0 and set to max allowance\n if (allowance \u003e 0) IERC20(token).safeDecreaseAllowance(spender, allowance);\n IERC20(token).safeIncreaseAllowance(spender, type(uint256).max);\n }\n\n /// @notice Returns the balance of the given token (or native ETH) for the given account.\n function universalBalanceOf(address token, address account) internal view returns (uint256) {\n if (token == ETH_ADDRESS) {\n return account.balance;\n } else {\n return IERC20(token).balanceOf(account);\n }\n }\n\n /// @dev Checks that token is a contract and not ETH_ADDRESS.\n function assertIsContract(address token) internal view {\n // Check that ETH_ADDRESS was not used (in case this is a predeploy on any of the chains)\n if (token == UniversalTokenLib.ETH_ADDRESS) revert TokenNotContract();\n // Check that token is not an EOA\n if (token.code.length == 0) revert TokenNotContract();\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/Admin.sol\n\ncontract Admin is IAdmin, AccessControlEnumerable {\n using UniversalTokenLib for address;\n\n bytes32 public constant RELAYER_ROLE = keccak256(\"RELAYER_ROLE\");\n bytes32 public constant REFUNDER_ROLE = keccak256(\"REFUNDER_ROLE\");\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n uint256 public constant FEE_BPS = 1e6;\n uint256 public constant FEE_RATE_MAX = 0.01e6; // max 1% on origin amount\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Chain gas amount to forward as rebate if requested\n uint256 public chainGasAmount;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n }\n\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n require(newFeeRate \u003c= FEE_RATE_MAX, \"newFeeRate \u003e max\");\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n token.universalTransfer(recipient, feeAmount);\n emit FeesSwept(token, recipient, feeAmount);\n }\n\n function setChainGasAmount(uint256 newChainGasAmount) external onlyRole(GOVERNOR_ROLE) {\n uint256 oldChainGasAmount = chainGasAmount;\n chainGasAmount = newChainGasAmount;\n emit ChainGasAmountUpdated(oldChainGasAmount, newChainGasAmount);\n }\n}\n\n// contracts/FastBridge.sol\n\ncontract FastBridge is IFastBridge, MulticallTarget, Admin {\n using SafeERC20 for IERC20;\n using UniversalTokenLib for address;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Delay for a transaction after which it could be permisionlessly refunded\n uint256 public constant REFUND_DELAY = 7 days;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeStatus) public bridgeStatuses;\n /// @notice Proof of relayed bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeProof) public bridgeProofs;\n /// @notice Whether bridge has been relayed on destination chain\n mapping(bytes32 =\u003e bool) public bridgeRelays;\n\n /// @dev to prevent replays\n uint256 public nonce;\n // @dev the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @notice Pulls a requested token from the user to the requested recipient.\n /// @dev Be careful of re-entrancy issues when msg.value \u003e 0 and recipient != address(this)\n function _pullToken(address recipient, address token, uint256 amount) internal returns (uint256 amountPulled) {\n if (token != UniversalTokenLib.ETH_ADDRESS) {\n token.assertIsContract();\n // Record token balance before transfer\n amountPulled = IERC20(token).balanceOf(recipient);\n // Token needs to be pulled only if msg.value is zero\n // This way user can specify WETH as the origin asset\n IERC20(token).safeTransferFrom(msg.sender, recipient, amount);\n // Use the difference between the recorded balance and the current balance as the amountPulled\n amountPulled = IERC20(token).balanceOf(recipient) - amountPulled;\n } else {\n // Otherwise, we need to check that ETH amount matches msg.value\n if (amount != msg.value) revert MsgValueIncorrect();\n // Transfer value to recipient if not this address\n if (recipient != address(this)) token.universalTransfer(recipient, amount);\n // We will forward msg.value in the external call later, if recipient is not this contract\n amountPulled = msg.value;\n }\n }\n\n /// @inheritdoc IFastBridge\n function getBridgeTransaction(bytes memory request) public pure returns (BridgeTransaction memory) {\n return abi.decode(request, (BridgeTransaction));\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n // check bridge params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n\n // transfer tokens to bridge contract\n // @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _pullToken(address(this), params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n\n // set status to requested\n bytes memory request = abi.encode(\n BridgeTransaction({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n sendChainGas: params.sendChainGas,\n deadline: params.deadline,\n nonce: nonce++ // increment nonce on every bridge\n })\n );\n bytes32 transactionId = keccak256(request);\n bridgeStatuses[transactionId] = BridgeStatus.REQUESTED;\n\n emit BridgeRequested(\n transactionId,\n params.sender,\n request,\n params.dstChainId,\n params.originToken,\n params.destToken,\n originAmount,\n params.destAmount,\n params.sendChainGas\n );\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes memory request) external payable onlyRole(RELAYER_ROLE) {\n bytes32 transactionId = keccak256(request);\n BridgeTransaction memory transaction = getBridgeTransaction(request);\n if (transaction.destChainId != uint32(block.chainid)) revert ChainIncorrect();\n\n // check haven't exceeded deadline for relay to happen\n if (block.timestamp \u003e transaction.deadline) revert DeadlineExceeded();\n\n // mark bridge transaction as relayed\n if (bridgeRelays[transactionId]) revert TransactionRelayed();\n bridgeRelays[transactionId] = true;\n\n // transfer tokens to recipient on destination chain and gas rebate if requested\n address to = transaction.destRecipient;\n address token = transaction.destToken;\n uint256 amount = transaction.destAmount;\n\n uint256 rebate = chainGasAmount;\n if (!transaction.sendChainGas) {\n // forward erc20\n rebate = 0;\n _pullToken(to, token, amount);\n } else if (token == UniversalTokenLib.ETH_ADDRESS) {\n // lump in gas rebate into amount in native gas token\n _pullToken(to, token, amount + rebate);\n } else {\n // forward erc20 then forward gas rebate in native gas token\n _pullToken(to, token, amount);\n _pullToken(to, UniversalTokenLib.ETH_ADDRESS, rebate);\n }\n\n emit BridgeRelayed(\n transactionId,\n msg.sender,\n to,\n transaction.originChainId,\n transaction.originToken,\n transaction.destToken,\n transaction.originAmount,\n transaction.destAmount,\n rebate\n );\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes memory request, bytes32 destTxHash) external onlyRole(RELAYER_ROLE) {\n bytes32 transactionId = keccak256(request);\n // update bridge tx status given proof provided\n if (bridgeStatuses[transactionId] != BridgeStatus.REQUESTED) revert StatusIncorrect();\n bridgeStatuses[transactionId] = BridgeStatus.RELAYER_PROVED;\n bridgeProofs[transactionId] = BridgeProof({timestamp: uint96(block.timestamp), relayer: msg.sender}); // overflow ok\n\n emit BridgeProofProvided(transactionId, msg.sender, destTxHash);\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint96(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint96).max but\n /// proof.timestamp \u003c type(uint96).max via unchecked statement\n /// @param proof The bridge proof\n /// @return delta Time delta since proof submitted\n function _timeSince(BridgeProof memory proof) internal view returns (uint256 delta) {\n unchecked {\n delta = uint96(block.timestamp) - proof.timestamp;\n }\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n if (bridgeStatuses[transactionId] != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n BridgeProof memory proof = bridgeProofs[transactionId];\n if (proof.relayer != relayer) revert SenderIncorrect();\n return _timeSince(proof) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes memory request, address to) external onlyRole(RELAYER_ROLE) {\n bytes32 transactionId = keccak256(request);\n BridgeTransaction memory transaction = getBridgeTransaction(request);\n\n // update bridge tx status if able to claim origin collateral\n if (bridgeStatuses[transactionId] != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n\n BridgeProof memory proof = bridgeProofs[transactionId];\n if (proof.relayer != msg.sender) revert SenderIncorrect();\n if (_timeSince(proof) \u003c= DISPUTE_PERIOD) revert DisputePeriodNotPassed();\n\n bridgeStatuses[transactionId] = BridgeStatus.RELAYER_CLAIMED;\n\n // update protocol fees if origin fee amount exists\n if (transaction.originFeeAmount \u003e 0) protocolFees[transaction.originToken] += transaction.originFeeAmount;\n\n // transfer origin collateral less fee to specified address\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositClaimed(transactionId, msg.sender, to, token, amount);\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n if (bridgeStatuses[transactionId] != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(bridgeProofs[transactionId]) \u003e DISPUTE_PERIOD) revert DisputePeriodPassed();\n\n // @dev relayer gets slashed effectively if dest relay has gone thru\n bridgeStatuses[transactionId] = BridgeStatus.REQUESTED;\n delete bridgeProofs[transactionId];\n\n emit BridgeProofDisputed(transactionId, msg.sender);\n }\n\n /// @inheritdoc IFastBridge\n function refund(bytes memory request) external {\n bytes32 transactionId = keccak256(request);\n BridgeTransaction memory transaction = getBridgeTransaction(request);\n\n if (hasRole(REFUNDER_ROLE, msg.sender)) {\n // Refunder can refund if deadline has passed\n if (block.timestamp \u003c= transaction.deadline) revert DeadlineNotExceeded();\n } else {\n // Permissionless refund is allowed after REFUND_DELAY\n if (block.timestamp \u003c= transaction.deadline + REFUND_DELAY) revert DeadlineNotExceeded();\n }\n\n // set status to refunded if still in requested state\n if (bridgeStatuses[transactionId] != BridgeStatus.REQUESTED) revert StatusIncorrect();\n bridgeStatuses[transactionId] = BridgeStatus.REFUNDED;\n\n // transfer origin collateral back to original sender\n address to = transaction.originSender;\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount + transaction.originFeeAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n }\n}\n\n// test/FastBridgeMock.sol\n\ncontract FastBridgeMock is IFastBridge, Admin {\n // @dev the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @dev to prevent replays\n uint256 public nonce;\n\n /// @notice We include an empty \"test\" function so that this contract does not appear in the coverage report.\n function testFastBridgeMock() external {}\n\n function getBridgeTransaction(bytes memory request) public pure returns (BridgeTransaction memory) {\n return abi.decode(request, (BridgeTransaction));\n }\n\n // used for testing in go.\n // see: https://ethereum.stackexchange.com/questions/21155/how-to-expose-enum-in-solidity-contract\n // make sure to update fastbridge/status.go if this changes\n // or underliyng enum changes.\n //\n // TODO: a foundry test should be added to ensure this is always in sync.\n function getEnumKeyByValue(FastBridge.BridgeStatus keyValue) public pure returns (string memory) {\n if (FastBridge.BridgeStatus.NULL == keyValue) return \"NULL\";\n if (FastBridge.BridgeStatus.REQUESTED == keyValue) return \"REQUESTED\";\n if (FastBridge.BridgeStatus.RELAYER_PROVED == keyValue) return \"RELAYER_PROVED\";\n if (FastBridge.BridgeStatus.RELAYER_CLAIMED == keyValue) return \"RELAYER_CLAIMED\";\n if (FastBridge.BridgeStatus.REFUNDED == keyValue) return \"REFUNDED\";\n return \"\";\n }\n\n function mockBridgeRequest(bytes32 transactionId, address sender, BridgeParams memory params) external {\n sender;\n uint256 originFeeAmount = (params.originAmount * protocolFeeRate) / FEE_BPS;\n params.originAmount -= originFeeAmount;\n\n bytes memory request = abi.encode(\n BridgeTransaction({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: params.originAmount, // includes relayer fee\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n sendChainGas: params.sendChainGas,\n deadline: params.deadline,\n nonce: nonce++ // increment nonce on every bridge\n })\n );\n\n emit BridgeRequested(\n transactionId,\n params.sender,\n request,\n params.dstChainId,\n params.originToken,\n params.destToken,\n params.originAmount,\n params.destAmount,\n params.sendChainGas\n );\n }\n\n function mockBridgeRequestRaw(bytes32 transactionId, address sender, bytes memory request) external {\n sender;\n BridgeTransaction memory transaction = getBridgeTransaction(request);\n emit BridgeRequested(\n transactionId,\n transaction.originSender,\n request,\n transaction.destChainId,\n transaction.originToken,\n transaction.destToken,\n transaction.originAmount,\n transaction.destAmount,\n transaction.sendChainGas\n );\n }\n\n function mockBridgeRelayer(\n bytes32 transactionId,\n address relayer,\n address to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n )\n external\n {\n emit BridgeRelayed(\n transactionId, relayer, to, originChainId, originToken, destToken, originAmount, destAmount, chainGasAmount\n );\n }\n\n function bridge(BridgeParams memory) external payable {\n revert(\"not implemented\");\n }\n\n function relay(bytes memory) external payable {\n revert(\"not implemented\");\n }\n\n function prove(bytes memory, bytes32) external pure {\n revert(\"not implemented\");\n }\n\n function canClaim(bytes32, address) external pure returns (bool) {\n revert(\"not implemented\");\n }\n\n function claim(bytes memory, address) external pure {\n revert(\"not implemented\");\n }\n\n function dispute(bytes32) external pure {\n revert(\"not implemented\");\n }\n\n function refund(bytes memory) external pure {\n revert(\"not implemented\");\n }\n}\n","language":"Solidity","languageVersion":"0.8.20","compilerVersion":"0.8.20","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"","srcMapRuntime":"","abiDefinition":[{"inputs":[],"name":"AccessControlBadConfirmation","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"bytes32","name":"neededRole","type":"bytes32"}],"name":"AccessControlUnauthorizedAccount","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"previousAdminRole","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"newAdminRole","type":"bytes32"}],"name":"RoleAdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleRevoked","type":"event"},{"inputs":[],"name":"DEFAULT_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleAdmin","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"uint256","name":"index","type":"uint256"}],"name":"getRoleMember","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleMemberCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"grantRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"hasRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"callerConfirmation","type":"address"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"revokeRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"}],"userDoc":{"kind":"user","methods":{},"version":1},"developerDoc":{"details":"Extension of {AccessControl} that allows enumerating the members of each role.","errors":{"AccessControlBadConfirmation()":[{"details":"The caller of a function is not the expected one. NOTE: Don't confuse with {AccessControlUnauthorizedAccount}."}],"AccessControlUnauthorizedAccount(address,bytes32)":[{"details":"The `account` is missing a role."}]},"events":{"RoleAdminChanged(bytes32,bytes32,bytes32)":{"details":"Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole` `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite {RoleAdminChanged} not being emitted signaling this."},"RoleGranted(bytes32,address,address)":{"details":"Emitted when `account` is granted `role`. `sender` is the account that originated the contract call, an admin role bearer except when using {AccessControl-_setupRole}."},"RoleRevoked(bytes32,address,address)":{"details":"Emitted when `account` is revoked `role`. `sender` is the account that originated the contract call: - if using `revokeRole`, it is the admin role bearer - if using `renounceRole`, it is the role bearer (i.e. `account`)"}},"kind":"dev","methods":{"getRoleAdmin(bytes32)":{"details":"Returns the admin role that controls `role`. See {grantRole} and {revokeRole}. To change a role's admin, use {_setRoleAdmin}."},"getRoleMember(bytes32,uint256)":{"details":"Returns one of the accounts that have `role`. `index` must be a value between 0 and {getRoleMemberCount}, non-inclusive. Role bearers are not sorted in any particular way, and their ordering may change at any point. WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure you perform all queries on the same block. See the following https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post] for more information."},"getRoleMemberCount(bytes32)":{"details":"Returns the number of accounts that have `role`. Can be used together with {getRoleMember} to enumerate all bearers of a role."},"grantRole(bytes32,address)":{"details":"Grants `role` to `account`. If `account` had not been already granted `role`, emits a {RoleGranted} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleGranted} event."},"hasRole(bytes32,address)":{"details":"Returns `true` if `account` has been granted `role`."},"renounceRole(bytes32,address)":{"details":"Revokes `role` from the calling account. Roles are often managed via {grantRole} and {revokeRole}: this function's purpose is to provide a mechanism for accounts to lose their privileges if they are compromised (such as when a trusted device is misplaced). If the calling account had been revoked `role`, emits a {RoleRevoked} event. Requirements: - the caller must be `callerConfirmation`. May emit a {RoleRevoked} event."},"revokeRole(bytes32,address)":{"details":"Revokes `role` from `account`. If `account` had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleRevoked} event."},"supportsInterface(bytes4)":{"details":"See {IERC165-supportsInterface}."}},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.20+commit.a1b79de6\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[],\"name\":\"AccessControlBadConfirmation\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"neededRole\",\"type\":\"bytes32\"}],\"name\":\"AccessControlUnauthorizedAccount\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"previousAdminRole\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"newAdminRole\",\"type\":\"bytes32\"}],\"name\":\"RoleAdminChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleGranted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleRevoked\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"DEFAULT_ADMIN_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"}],\"name\":\"getRoleAdmin\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"index\",\"type\":\"uint256\"}],\"name\":\"getRoleMember\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"}],\"name\":\"getRoleMemberCount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"grantRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"hasRole\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"callerConfirmation\",\"type\":\"address\"}],\"name\":\"renounceRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"revokeRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes4\",\"name\":\"interfaceId\",\"type\":\"bytes4\"}],\"name\":\"supportsInterface\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"}],\"devdoc\":{\"details\":\"Extension of {AccessControl} that allows enumerating the members of each role.\",\"errors\":{\"AccessControlBadConfirmation()\":[{\"details\":\"The caller of a function is not the expected one. NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\"}],\"AccessControlUnauthorizedAccount(address,bytes32)\":[{\"details\":\"The `account` is missing a role.\"}]},\"events\":{\"RoleAdminChanged(bytes32,bytes32,bytes32)\":{\"details\":\"Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole` `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite {RoleAdminChanged} not being emitted signaling this.\"},\"RoleGranted(bytes32,address,address)\":{\"details\":\"Emitted when `account` is granted `role`. `sender` is the account that originated the contract call, an admin role bearer except when using {AccessControl-_setupRole}.\"},\"RoleRevoked(bytes32,address,address)\":{\"details\":\"Emitted when `account` is revoked `role`. `sender` is the account that originated the contract call: - if using `revokeRole`, it is the admin role bearer - if using `renounceRole`, it is the role bearer (i.e. `account`)\"}},\"kind\":\"dev\",\"methods\":{\"getRoleAdmin(bytes32)\":{\"details\":\"Returns the admin role that controls `role`. See {grantRole} and {revokeRole}. To change a role's admin, use {_setRoleAdmin}.\"},\"getRoleMember(bytes32,uint256)\":{\"details\":\"Returns one of the accounts that have `role`. `index` must be a value between 0 and {getRoleMemberCount}, non-inclusive. Role bearers are not sorted in any particular way, and their ordering may change at any point. WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure you perform all queries on the same block. See the following https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post] for more information.\"},\"getRoleMemberCount(bytes32)\":{\"details\":\"Returns the number of accounts that have `role`. Can be used together with {getRoleMember} to enumerate all bearers of a role.\"},\"grantRole(bytes32,address)\":{\"details\":\"Grants `role` to `account`. If `account` had not been already granted `role`, emits a {RoleGranted} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleGranted} event.\"},\"hasRole(bytes32,address)\":{\"details\":\"Returns `true` if `account` has been granted `role`.\"},\"renounceRole(bytes32,address)\":{\"details\":\"Revokes `role` from the calling account. Roles are often managed via {grantRole} and {revokeRole}: this function's purpose is to provide a mechanism for accounts to lose their privileges if they are compromised (such as when a trusted device is misplaced). If the calling account had been revoked `role`, emits a {RoleRevoked} event. Requirements: - the caller must be `callerConfirmation`. May emit a {RoleRevoked} event.\"},\"revokeRole(bytes32,address)\":{\"details\":\"Revokes `role` from `account`. If `account` had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleRevoked} event.\"},\"supportsInterface(bytes4)\":{\"details\":\"See {IERC165-supportsInterface}.\"}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeMock.sol\":\"AccessControlEnumerable\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeMock.sol\":{\"keccak256\":\"0xf2751f52f8216801d500da7464ad01f3c23a8286e155e2dcba6d21d6e7fd95a0\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://85d2edab24ebe321043d2b88038437e8f443a0ef26fa2139c72dcc2bc7fbc602\",\"dweb:/ipfs/QmcULiFPFJzFDT4aupVSDreXz8uHxcABb5nxpAG4zYzfNN\"]}},\"version\":1}"},"hashes":{"DEFAULT_ADMIN_ROLE()":"a217fddf","getRoleAdmin(bytes32)":"248a9ca3","getRoleMember(bytes32,uint256)":"9010d07c","getRoleMemberCount(bytes32)":"ca15c873","grantRole(bytes32,address)":"2f2ff15d","hasRole(bytes32,address)":"91d14854","renounceRole(bytes32,address)":"36568abe","revokeRole(bytes32,address)":"d547741f","supportsInterface(bytes4)":"01ffc9a7"}},"solidity/FastBridgeMock.sol:Address":{"code":"0x60566037600b82828239805160001a607314602a57634e487b7160e01b600052600060045260246000fd5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600080fdfea2646970667358221220d19ff64d6e75d44d1945372c19c9bd8fcbe60ec22dd02143e88fdd9d7a948d3564736f6c63430008140033","runtime-code":"0x73000000000000000000000000000000000000000030146080604052600080fdfea2646970667358221220d19ff64d6e75d44d1945372c19c9bd8fcbe60ec22dd02143e88fdd9d7a948d3564736f6c63430008140033","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.20 ^0.8.20 ^0.8.4;\n\n// contracts/interfaces/IAdmin.sol\n\ninterface IAdmin {\n // ============ Events ============\n\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n event ChainGasAmountUpdated(uint256 oldChainGasAmount, uint256 newChainGasAmount);\n\n // ============ Methods ============\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n\n function setChainGasAmount(uint256 newChainGasAmount) external;\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IMulticallTarget.sol\n\n/// @notice Interface for a contract that can be called multiple times by the same caller. Inspired by MulticallV3:\n/// https://github.com/mds1/multicall/blob/master/src/Multicall3.sol\ninterface IMulticallTarget {\n struct Result {\n bool success;\n bytes returnData;\n }\n\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external;\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results);\n}\n\n// contracts/libs/Errors.sol\n\nerror DeadlineExceeded();\nerror DeadlineNotExceeded();\nerror DeadlineTooShort();\nerror InsufficientOutputAmount();\n\nerror MsgValueIncorrect();\nerror PoolNotFound();\nerror TokenAddressMismatch();\nerror TokenNotContract();\nerror TokenNotETH();\nerror TokensIdentical();\n\nerror ChainIncorrect();\nerror AmountIncorrect();\nerror ZeroAddress();\n\nerror DisputePeriodNotPassed();\nerror DisputePeriodPassed();\nerror SenderIncorrect();\nerror StatusIncorrect();\nerror TransactionIdIncorrect();\nerror TransactionRelayed();\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// contracts/utils/MulticallTarget.sol\n\n// solhint-disable avoid-low-level-calls\n/// @notice Template for a contract that supports batched calls (preserving the msg.sender).\n/// Only calls with zero msg.value could be batched.\nabstract contract MulticallTarget is IMulticallTarget {\n error MulticallTarget__UndeterminedRevert();\n\n /// @notice Perform a batched call to this contract, preserving the msg.sender.\n /// The return data from each call is discarded.\n /// @dev The method is non-payable, so only calls with `msg.value == 0` could be batched.\n /// It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag.\n /// Otherwise, the whole batch call will be reverted with the original revert reason.\n /// @param data List of abi-encoded calldata for the calls to perform.\n /// @param ignoreReverts Whether to ignore the revert errors from the calls.\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external {\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\n if (!success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(result);\n }\n }\n }\n\n /// @notice Perform a batched call to this contract, preserving the msg.sender.\n /// The return data from each call is preserved.\n /// @dev The method is non-payable, so only calls with `msg.value == 0` could be batched.\n /// It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag.\n /// Otherwise, the whole batch call will be reverted with the original revert reason.\n /// @param data List of abi-encoded calldata for the calls to perform.\n /// @param ignoreReverts Whether to ignore the revert errors from the calls.\n /// @return results List of results from the calls: `(success, returnData)`.\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results)\n {\n results = new Result[](data.length);\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (results[i].success, results[i].returnData) = address(this).delegatecall(data[i]);\n if (!results[i].success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(results[i].returnData);\n }\n }\n }\n\n /// @dev Bubbles the revert message from the underlying call.\n /// Note: preserves the same custom error or revert string, if one was used.\n /// Source: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v5.0.2/contracts/utils/Address.sol#L143-L158\n function _bubbleRevert(bytes memory returnData) internal pure {\n // Look for revert reason and bubble it up if present\n if (returnData.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n // solhint-disable-next-line no-inline-assembly\n assembly {\n let returndata_size := mload(returnData)\n revert(add(32, returnData), returndata_size)\n }\n } else {\n revert MulticallTarget__UndeterminedRevert();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// contracts/libs/UniversalToken.sol\n\nlibrary UniversalTokenLib {\n using SafeERC20 for IERC20;\n\n address internal constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Transfers tokens to the given account. Reverts if transfer is not successful.\n /// @dev This might trigger fallback, if ETH is transferred to the contract.\n /// Make sure this can not lead to reentrancy attacks.\n function universalTransfer(address token, address to, uint256 value) internal {\n // Don't do anything, if need to send tokens to this address\n if (to == address(this)) return;\n // Don't do anything, if trying to send zero value\n if (value == 0) return;\n if (token == ETH_ADDRESS) {\n /// @dev Note: this can potentially lead to executing code in `to`.\n // solhint-disable-next-line avoid-low-level-calls\n (bool success,) = to.call{value: value}(\"\");\n require(success, \"ETH transfer failed\");\n } else {\n IERC20(token).safeTransfer(to, value);\n }\n }\n\n /// @notice Issues an infinite allowance to the spender, if the current allowance is insufficient\n /// to spend the given amount.\n function universalApproveInfinity(address token, address spender, uint256 amountToSpend) internal {\n // ETH Chad doesn't require your approval\n if (token == ETH_ADDRESS) return;\n // No-op if allowance is already sufficient\n uint256 allowance = IERC20(token).allowance(address(this), spender);\n if (allowance \u003e= amountToSpend) return;\n // Otherwise, reset approval to 0 and set to max allowance\n if (allowance \u003e 0) IERC20(token).safeDecreaseAllowance(spender, allowance);\n IERC20(token).safeIncreaseAllowance(spender, type(uint256).max);\n }\n\n /// @notice Returns the balance of the given token (or native ETH) for the given account.\n function universalBalanceOf(address token, address account) internal view returns (uint256) {\n if (token == ETH_ADDRESS) {\n return account.balance;\n } else {\n return IERC20(token).balanceOf(account);\n }\n }\n\n /// @dev Checks that token is a contract and not ETH_ADDRESS.\n function assertIsContract(address token) internal view {\n // Check that ETH_ADDRESS was not used (in case this is a predeploy on any of the chains)\n if (token == UniversalTokenLib.ETH_ADDRESS) revert TokenNotContract();\n // Check that token is not an EOA\n if (token.code.length == 0) revert TokenNotContract();\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/Admin.sol\n\ncontract Admin is IAdmin, AccessControlEnumerable {\n using UniversalTokenLib for address;\n\n bytes32 public constant RELAYER_ROLE = keccak256(\"RELAYER_ROLE\");\n bytes32 public constant REFUNDER_ROLE = keccak256(\"REFUNDER_ROLE\");\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n uint256 public constant FEE_BPS = 1e6;\n uint256 public constant FEE_RATE_MAX = 0.01e6; // max 1% on origin amount\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Chain gas amount to forward as rebate if requested\n uint256 public chainGasAmount;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n }\n\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n require(newFeeRate \u003c= FEE_RATE_MAX, \"newFeeRate \u003e max\");\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n token.universalTransfer(recipient, feeAmount);\n emit FeesSwept(token, recipient, feeAmount);\n }\n\n function setChainGasAmount(uint256 newChainGasAmount) external onlyRole(GOVERNOR_ROLE) {\n uint256 oldChainGasAmount = chainGasAmount;\n chainGasAmount = newChainGasAmount;\n emit ChainGasAmountUpdated(oldChainGasAmount, newChainGasAmount);\n }\n}\n\n// contracts/FastBridge.sol\n\ncontract FastBridge is IFastBridge, MulticallTarget, Admin {\n using SafeERC20 for IERC20;\n using UniversalTokenLib for address;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Delay for a transaction after which it could be permisionlessly refunded\n uint256 public constant REFUND_DELAY = 7 days;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeStatus) public bridgeStatuses;\n /// @notice Proof of relayed bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeProof) public bridgeProofs;\n /// @notice Whether bridge has been relayed on destination chain\n mapping(bytes32 =\u003e bool) public bridgeRelays;\n\n /// @dev to prevent replays\n uint256 public nonce;\n // @dev the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @notice Pulls a requested token from the user to the requested recipient.\n /// @dev Be careful of re-entrancy issues when msg.value \u003e 0 and recipient != address(this)\n function _pullToken(address recipient, address token, uint256 amount) internal returns (uint256 amountPulled) {\n if (token != UniversalTokenLib.ETH_ADDRESS) {\n token.assertIsContract();\n // Record token balance before transfer\n amountPulled = IERC20(token).balanceOf(recipient);\n // Token needs to be pulled only if msg.value is zero\n // This way user can specify WETH as the origin asset\n IERC20(token).safeTransferFrom(msg.sender, recipient, amount);\n // Use the difference between the recorded balance and the current balance as the amountPulled\n amountPulled = IERC20(token).balanceOf(recipient) - amountPulled;\n } else {\n // Otherwise, we need to check that ETH amount matches msg.value\n if (amount != msg.value) revert MsgValueIncorrect();\n // Transfer value to recipient if not this address\n if (recipient != address(this)) token.universalTransfer(recipient, amount);\n // We will forward msg.value in the external call later, if recipient is not this contract\n amountPulled = msg.value;\n }\n }\n\n /// @inheritdoc IFastBridge\n function getBridgeTransaction(bytes memory request) public pure returns (BridgeTransaction memory) {\n return abi.decode(request, (BridgeTransaction));\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n // check bridge params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n\n // transfer tokens to bridge contract\n // @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _pullToken(address(this), params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n\n // set status to requested\n bytes memory request = abi.encode(\n BridgeTransaction({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n sendChainGas: params.sendChainGas,\n deadline: params.deadline,\n nonce: nonce++ // increment nonce on every bridge\n })\n );\n bytes32 transactionId = keccak256(request);\n bridgeStatuses[transactionId] = BridgeStatus.REQUESTED;\n\n emit BridgeRequested(\n transactionId,\n params.sender,\n request,\n params.dstChainId,\n params.originToken,\n params.destToken,\n originAmount,\n params.destAmount,\n params.sendChainGas\n );\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes memory request) external payable onlyRole(RELAYER_ROLE) {\n bytes32 transactionId = keccak256(request);\n BridgeTransaction memory transaction = getBridgeTransaction(request);\n if (transaction.destChainId != uint32(block.chainid)) revert ChainIncorrect();\n\n // check haven't exceeded deadline for relay to happen\n if (block.timestamp \u003e transaction.deadline) revert DeadlineExceeded();\n\n // mark bridge transaction as relayed\n if (bridgeRelays[transactionId]) revert TransactionRelayed();\n bridgeRelays[transactionId] = true;\n\n // transfer tokens to recipient on destination chain and gas rebate if requested\n address to = transaction.destRecipient;\n address token = transaction.destToken;\n uint256 amount = transaction.destAmount;\n\n uint256 rebate = chainGasAmount;\n if (!transaction.sendChainGas) {\n // forward erc20\n rebate = 0;\n _pullToken(to, token, amount);\n } else if (token == UniversalTokenLib.ETH_ADDRESS) {\n // lump in gas rebate into amount in native gas token\n _pullToken(to, token, amount + rebate);\n } else {\n // forward erc20 then forward gas rebate in native gas token\n _pullToken(to, token, amount);\n _pullToken(to, UniversalTokenLib.ETH_ADDRESS, rebate);\n }\n\n emit BridgeRelayed(\n transactionId,\n msg.sender,\n to,\n transaction.originChainId,\n transaction.originToken,\n transaction.destToken,\n transaction.originAmount,\n transaction.destAmount,\n rebate\n );\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes memory request, bytes32 destTxHash) external onlyRole(RELAYER_ROLE) {\n bytes32 transactionId = keccak256(request);\n // update bridge tx status given proof provided\n if (bridgeStatuses[transactionId] != BridgeStatus.REQUESTED) revert StatusIncorrect();\n bridgeStatuses[transactionId] = BridgeStatus.RELAYER_PROVED;\n bridgeProofs[transactionId] = BridgeProof({timestamp: uint96(block.timestamp), relayer: msg.sender}); // overflow ok\n\n emit BridgeProofProvided(transactionId, msg.sender, destTxHash);\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint96(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint96).max but\n /// proof.timestamp \u003c type(uint96).max via unchecked statement\n /// @param proof The bridge proof\n /// @return delta Time delta since proof submitted\n function _timeSince(BridgeProof memory proof) internal view returns (uint256 delta) {\n unchecked {\n delta = uint96(block.timestamp) - proof.timestamp;\n }\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n if (bridgeStatuses[transactionId] != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n BridgeProof memory proof = bridgeProofs[transactionId];\n if (proof.relayer != relayer) revert SenderIncorrect();\n return _timeSince(proof) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes memory request, address to) external onlyRole(RELAYER_ROLE) {\n bytes32 transactionId = keccak256(request);\n BridgeTransaction memory transaction = getBridgeTransaction(request);\n\n // update bridge tx status if able to claim origin collateral\n if (bridgeStatuses[transactionId] != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n\n BridgeProof memory proof = bridgeProofs[transactionId];\n if (proof.relayer != msg.sender) revert SenderIncorrect();\n if (_timeSince(proof) \u003c= DISPUTE_PERIOD) revert DisputePeriodNotPassed();\n\n bridgeStatuses[transactionId] = BridgeStatus.RELAYER_CLAIMED;\n\n // update protocol fees if origin fee amount exists\n if (transaction.originFeeAmount \u003e 0) protocolFees[transaction.originToken] += transaction.originFeeAmount;\n\n // transfer origin collateral less fee to specified address\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositClaimed(transactionId, msg.sender, to, token, amount);\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n if (bridgeStatuses[transactionId] != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(bridgeProofs[transactionId]) \u003e DISPUTE_PERIOD) revert DisputePeriodPassed();\n\n // @dev relayer gets slashed effectively if dest relay has gone thru\n bridgeStatuses[transactionId] = BridgeStatus.REQUESTED;\n delete bridgeProofs[transactionId];\n\n emit BridgeProofDisputed(transactionId, msg.sender);\n }\n\n /// @inheritdoc IFastBridge\n function refund(bytes memory request) external {\n bytes32 transactionId = keccak256(request);\n BridgeTransaction memory transaction = getBridgeTransaction(request);\n\n if (hasRole(REFUNDER_ROLE, msg.sender)) {\n // Refunder can refund if deadline has passed\n if (block.timestamp \u003c= transaction.deadline) revert DeadlineNotExceeded();\n } else {\n // Permissionless refund is allowed after REFUND_DELAY\n if (block.timestamp \u003c= transaction.deadline + REFUND_DELAY) revert DeadlineNotExceeded();\n }\n\n // set status to refunded if still in requested state\n if (bridgeStatuses[transactionId] != BridgeStatus.REQUESTED) revert StatusIncorrect();\n bridgeStatuses[transactionId] = BridgeStatus.REFUNDED;\n\n // transfer origin collateral back to original sender\n address to = transaction.originSender;\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount + transaction.originFeeAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n }\n}\n\n// test/FastBridgeMock.sol\n\ncontract FastBridgeMock is IFastBridge, Admin {\n // @dev the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @dev to prevent replays\n uint256 public nonce;\n\n /// @notice We include an empty \"test\" function so that this contract does not appear in the coverage report.\n function testFastBridgeMock() external {}\n\n function getBridgeTransaction(bytes memory request) public pure returns (BridgeTransaction memory) {\n return abi.decode(request, (BridgeTransaction));\n }\n\n // used for testing in go.\n // see: https://ethereum.stackexchange.com/questions/21155/how-to-expose-enum-in-solidity-contract\n // make sure to update fastbridge/status.go if this changes\n // or underliyng enum changes.\n //\n // TODO: a foundry test should be added to ensure this is always in sync.\n function getEnumKeyByValue(FastBridge.BridgeStatus keyValue) public pure returns (string memory) {\n if (FastBridge.BridgeStatus.NULL == keyValue) return \"NULL\";\n if (FastBridge.BridgeStatus.REQUESTED == keyValue) return \"REQUESTED\";\n if (FastBridge.BridgeStatus.RELAYER_PROVED == keyValue) return \"RELAYER_PROVED\";\n if (FastBridge.BridgeStatus.RELAYER_CLAIMED == keyValue) return \"RELAYER_CLAIMED\";\n if (FastBridge.BridgeStatus.REFUNDED == keyValue) return \"REFUNDED\";\n return \"\";\n }\n\n function mockBridgeRequest(bytes32 transactionId, address sender, BridgeParams memory params) external {\n sender;\n uint256 originFeeAmount = (params.originAmount * protocolFeeRate) / FEE_BPS;\n params.originAmount -= originFeeAmount;\n\n bytes memory request = abi.encode(\n BridgeTransaction({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: params.originAmount, // includes relayer fee\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n sendChainGas: params.sendChainGas,\n deadline: params.deadline,\n nonce: nonce++ // increment nonce on every bridge\n })\n );\n\n emit BridgeRequested(\n transactionId,\n params.sender,\n request,\n params.dstChainId,\n params.originToken,\n params.destToken,\n params.originAmount,\n params.destAmount,\n params.sendChainGas\n );\n }\n\n function mockBridgeRequestRaw(bytes32 transactionId, address sender, bytes memory request) external {\n sender;\n BridgeTransaction memory transaction = getBridgeTransaction(request);\n emit BridgeRequested(\n transactionId,\n transaction.originSender,\n request,\n transaction.destChainId,\n transaction.originToken,\n transaction.destToken,\n transaction.originAmount,\n transaction.destAmount,\n transaction.sendChainGas\n );\n }\n\n function mockBridgeRelayer(\n bytes32 transactionId,\n address relayer,\n address to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n )\n external\n {\n emit BridgeRelayed(\n transactionId, relayer, to, originChainId, originToken, destToken, originAmount, destAmount, chainGasAmount\n );\n }\n\n function bridge(BridgeParams memory) external payable {\n revert(\"not implemented\");\n }\n\n function relay(bytes memory) external payable {\n revert(\"not implemented\");\n }\n\n function prove(bytes memory, bytes32) external pure {\n revert(\"not implemented\");\n }\n\n function canClaim(bytes32, address) external pure returns (bool) {\n revert(\"not implemented\");\n }\n\n function claim(bytes memory, address) external pure {\n revert(\"not implemented\");\n }\n\n function dispute(bytes32) external pure {\n revert(\"not implemented\");\n }\n\n function refund(bytes memory) external pure {\n revert(\"not implemented\");\n }\n}\n","language":"Solidity","languageVersion":"0.8.20","compilerVersion":"0.8.20","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"16180:6066:0:-:0;;;;;;;;;;;;;;;-1:-1:-1;;;16180:6066:0;;;;;;;;;;;;;;;;;","srcMapRuntime":"16180:6066:0:-:0;;;;;;;;","abiDefinition":[{"inputs":[{"internalType":"address","name":"target","type":"address"}],"name":"AddressEmptyCode","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"AddressInsufficientBalance","type":"error"},{"inputs":[],"name":"FailedInnerCall","type":"error"}],"userDoc":{"kind":"user","methods":{},"version":1},"developerDoc":{"details":"Collection of functions related to the address type","errors":{"AddressEmptyCode(address)":[{"details":"There's no code at `target` (it is not a contract)."}],"AddressInsufficientBalance(address)":[{"details":"The ETH balance of the account is not enough to perform the operation."}],"FailedInnerCall()":[{"details":"A call to an address target failed. The target may have reverted."}]},"kind":"dev","methods":{},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.20+commit.a1b79de6\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"}],\"name\":\"AddressEmptyCode\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"AddressInsufficientBalance\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"FailedInnerCall\",\"type\":\"error\"}],\"devdoc\":{\"details\":\"Collection of functions related to the address type\",\"errors\":{\"AddressEmptyCode(address)\":[{\"details\":\"There's no code at `target` (it is not a contract).\"}],\"AddressInsufficientBalance(address)\":[{\"details\":\"The ETH balance of the account is not enough to perform the operation.\"}],\"FailedInnerCall()\":[{\"details\":\"A call to an address target failed. The target may have reverted.\"}]},\"kind\":\"dev\",\"methods\":{},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeMock.sol\":\"Address\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeMock.sol\":{\"keccak256\":\"0xf2751f52f8216801d500da7464ad01f3c23a8286e155e2dcba6d21d6e7fd95a0\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://85d2edab24ebe321043d2b88038437e8f443a0ef26fa2139c72dcc2bc7fbc602\",\"dweb:/ipfs/QmcULiFPFJzFDT4aupVSDreXz8uHxcABb5nxpAG4zYzfNN\"]}},\"version\":1}"},"hashes":{}},"solidity/FastBridgeMock.sol:Admin":{"code":"0x60806040523480156200001157600080fd5b50604051620014123803806200141283398101604081905262000034916200018e565b6200004160008262000049565b5050620001b9565b60008062000058848462000086565b905080156200007d5760008481526001602052604090206200007b908462000134565b505b90505b92915050565b6000828152602081815260408083206001600160a01b038516845290915281205460ff166200012b576000838152602081815260408083206001600160a01b03861684529091529020805460ff19166001179055620000e23390565b6001600160a01b0316826001600160a01b0316847f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a450600162000080565b50600062000080565b60006200007d836001600160a01b03841660008181526001830160205260408120546200012b5750815460018181018455600084815260208082209093018490558454848252828601909352604090209190915562000080565b600060208284031215620001a157600080fd5b81516001600160a01b03811681146200007d57600080fd5b61124980620001c96000396000f3fe608060405234801561001057600080fd5b50600436106101775760003560e01c806391d14854116100d8578063bf333f2c1161008c578063d547741f11610066578063d547741f14610385578063dcf844a714610398578063e00a83e0146103b857600080fd5b8063bf333f2c14610341578063ca15c8731461034b578063ccc574901461035e57600080fd5b8063a217fddf116100bd578063a217fddf14610313578063b13aa2d61461031b578063b250fe6b1461032e57600080fd5b806391d14854146102a8578063926d7d7f146102ec57600080fd5b80632f2ff15d1161012f57806358f858801161011457806358f85880146102405780635960ccf2146102495780639010d07c1461027057600080fd5b80632f2ff15d1461021a57806336568abe1461022d57600080fd5b806306f333f21161016057806306f333f2146101d95780630f5f6ed7146101ee578063248a9ca3146101f757600080fd5b806301ffc9a71461017c57806303ed0ee5146101a4575b600080fd5b61018f61018a366004611013565b6103c1565b60405190151581526020015b60405180910390f35b6101cb7f043c983c49d46f0e102151eaf8085d4a2e6571d5df2d47b013f39bddfd4a639d81565b60405190815260200161019b565b6101ec6101e736600461107e565b61041d565b005b6101cb61271081565b6101cb6102053660046110b1565b60009081526020819052604090206001015490565b6101ec6102283660046110ca565b61050b565b6101ec61023b3660046110ca565b610536565b6101cb60025481565b6101cb7fdb9556138406326f00296e13ea2ad7db24ba82381212d816b1a40c23b466b32781565b61028361027e3660046110ed565b61058f565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200161019b565b61018f6102b63660046110ca565b60009182526020828152604080842073ffffffffffffffffffffffffffffffffffffffff93909316845291905290205460ff1690565b6101cb7fe2b7fb3b832174769106daebcfd6d1970523240dda11281102db9363b83b0dc481565b6101cb600081565b6101ec6103293660046110b1565b6105ae565b6101ec61033c3660046110b1565b610690565b6101cb620f424081565b6101cb6103593660046110b1565b6106f8565b6101cb7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f5581565b6101ec6103933660046110ca565b61070f565b6101cb6103a636600461110f565b60036020526000908152604090205481565b6101cb60045481565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f5a05180f000000000000000000000000000000000000000000000000000000001480610417575061041782610734565b92915050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f55610447816107cb565b73ffffffffffffffffffffffffffffffffffffffff83166000908152600360205260408120549081900361047b5750505050565b73ffffffffffffffffffffffffffffffffffffffff84166000818152600360205260408120556104ac9084836107d8565b6040805173ffffffffffffffffffffffffffffffffffffffff8087168252851660208201529081018290527f244e51bc38c1452fa8aaf487bcb4bca36c2baa3a5fbdb776b1eabd8dc6d277cd9060600160405180910390a1505b505050565b600082815260208190526040902060010154610526816107cb565b610530838361092f565b50505050565b73ffffffffffffffffffffffffffffffffffffffff81163314610585576040517f6697b23200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6105068282610964565b60008281526001602052604081206105a79083610991565b9392505050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f556105d8816107cb565b612710821115610649576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f6e657746656552617465203e206d61780000000000000000000000000000000060448201526064015b60405180910390fd5b600280549083905560408051828152602081018590527f14914da2bf76024616fbe1859783fcd4dbddcb179b1f3a854949fbf920dcb95791015b60405180910390a1505050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f556106ba816107cb565b600480549083905560408051828152602081018590527f5cf09b12f3f56b4c564d51b25b40360af6d795198adb61ae0806a36c294323fa9101610683565b60008181526001602052604081206104179061099d565b60008281526020819052604090206001015461072a816107cb565b6105308383610964565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f7965db0b00000000000000000000000000000000000000000000000000000000148061041757507f01ffc9a7000000000000000000000000000000000000000000000000000000007fffffffff00000000000000000000000000000000000000000000000000000000831614610417565b6107d581336109a7565b50565b3073ffffffffffffffffffffffffffffffffffffffff8316036107fa57505050565b8060000361080757505050565b7fffffffffffffffffffffffff111111111111111111111111111111111111111273ffffffffffffffffffffffffffffffffffffffff84160161090e5760008273ffffffffffffffffffffffffffffffffffffffff168260405160006040518083038185875af1925050503d806000811461089e576040519150601f19603f3d011682016040523d82523d6000602084013e6108a3565b606091505b5050905080610530576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f455448207472616e73666572206661696c6564000000000000000000000000006044820152606401610640565b61050673ffffffffffffffffffffffffffffffffffffffff84168383610a31565b60008061093c8484610abe565b905080156105a757600084815260016020526040902061095c9084610bba565b509392505050565b6000806109718484610bdc565b905080156105a757600084815260016020526040902061095c9084610c97565b60006105a78383610cb9565b6000610417825490565b60008281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915290205460ff16610a2d576040517fe2517d3f00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8216600482015260248101839052604401610640565b5050565b6040805173ffffffffffffffffffffffffffffffffffffffff8416602482015260448082018490528251808303909101815260649091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fa9059cbb00000000000000000000000000000000000000000000000000000000179052610506908490610ce3565b60008281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915281205460ff16610bb25760008381526020818152604080832073ffffffffffffffffffffffffffffffffffffffff86168452909152902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055610b503390565b73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16847f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a4506001610417565b506000610417565b60006105a78373ffffffffffffffffffffffffffffffffffffffff8416610d79565b60008281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915281205460ff1615610bb25760008381526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8616808552925280832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016905551339286917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a4506001610417565b60006105a78373ffffffffffffffffffffffffffffffffffffffff8416610dc0565b6000826000018281548110610cd057610cd061112a565b9060005260206000200154905092915050565b6000610d0573ffffffffffffffffffffffffffffffffffffffff841683610eb3565b90508051600014158015610d2a575080806020019051810190610d289190611159565b155b15610506576040517f5274afe700000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff84166004820152602401610640565b6000818152600183016020526040812054610bb257508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155610417565b60008181526001830160205260408120548015610ea9576000610de460018361117b565b8554909150600090610df89060019061117b565b9050808214610e5d576000866000018281548110610e1857610e1861112a565b9060005260206000200154905080876000018481548110610e3b57610e3b61112a565b6000918252602080832090910192909255918252600188019052604090208390555b8554869080610e6e57610e6e6111b5565b600190038181906000526020600020016000905590558560010160008681526020019081526020016000206000905560019350505050610417565b6000915050610417565b60606105a783836000846000808573ffffffffffffffffffffffffffffffffffffffff168486604051610ee691906111e4565b60006040518083038185875af1925050503d8060008114610f23576040519150601f19603f3d011682016040523d82523d6000602084013e610f28565b606091505b5091509150610f38868383610f42565b9695505050505050565b606082610f5757610f5282610fd1565b6105a7565b8151158015610f7b575073ffffffffffffffffffffffffffffffffffffffff84163b155b15610fca576040517f9996b31500000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff85166004820152602401610640565b50806105a7565b805115610fe15780518082602001fd5b6040517f1425ea4200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006020828403121561102557600080fd5b81357fffffffff00000000000000000000000000000000000000000000000000000000811681146105a757600080fd5b803573ffffffffffffffffffffffffffffffffffffffff8116811461107957600080fd5b919050565b6000806040838503121561109157600080fd5b61109a83611055565b91506110a860208401611055565b90509250929050565b6000602082840312156110c357600080fd5b5035919050565b600080604083850312156110dd57600080fd5b823591506110a860208401611055565b6000806040838503121561110057600080fd5b50508035926020909101359150565b60006020828403121561112157600080fd5b6105a782611055565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60006020828403121561116b57600080fd5b815180151581146105a757600080fd5b81810381811115610417577f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fd5b6000825160005b8181101561120557602081860181015185830152016111eb565b50600092019182525091905056fea26469706673582212208b32889d103161da471a6c3bbc957a6d1f6866bfcc129ed80af1c666033956c464736f6c63430008140033","runtime-code":"0x608060405234801561001057600080fd5b50600436106101775760003560e01c806391d14854116100d8578063bf333f2c1161008c578063d547741f11610066578063d547741f14610385578063dcf844a714610398578063e00a83e0146103b857600080fd5b8063bf333f2c14610341578063ca15c8731461034b578063ccc574901461035e57600080fd5b8063a217fddf116100bd578063a217fddf14610313578063b13aa2d61461031b578063b250fe6b1461032e57600080fd5b806391d14854146102a8578063926d7d7f146102ec57600080fd5b80632f2ff15d1161012f57806358f858801161011457806358f85880146102405780635960ccf2146102495780639010d07c1461027057600080fd5b80632f2ff15d1461021a57806336568abe1461022d57600080fd5b806306f333f21161016057806306f333f2146101d95780630f5f6ed7146101ee578063248a9ca3146101f757600080fd5b806301ffc9a71461017c57806303ed0ee5146101a4575b600080fd5b61018f61018a366004611013565b6103c1565b60405190151581526020015b60405180910390f35b6101cb7f043c983c49d46f0e102151eaf8085d4a2e6571d5df2d47b013f39bddfd4a639d81565b60405190815260200161019b565b6101ec6101e736600461107e565b61041d565b005b6101cb61271081565b6101cb6102053660046110b1565b60009081526020819052604090206001015490565b6101ec6102283660046110ca565b61050b565b6101ec61023b3660046110ca565b610536565b6101cb60025481565b6101cb7fdb9556138406326f00296e13ea2ad7db24ba82381212d816b1a40c23b466b32781565b61028361027e3660046110ed565b61058f565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200161019b565b61018f6102b63660046110ca565b60009182526020828152604080842073ffffffffffffffffffffffffffffffffffffffff93909316845291905290205460ff1690565b6101cb7fe2b7fb3b832174769106daebcfd6d1970523240dda11281102db9363b83b0dc481565b6101cb600081565b6101ec6103293660046110b1565b6105ae565b6101ec61033c3660046110b1565b610690565b6101cb620f424081565b6101cb6103593660046110b1565b6106f8565b6101cb7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f5581565b6101ec6103933660046110ca565b61070f565b6101cb6103a636600461110f565b60036020526000908152604090205481565b6101cb60045481565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f5a05180f000000000000000000000000000000000000000000000000000000001480610417575061041782610734565b92915050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f55610447816107cb565b73ffffffffffffffffffffffffffffffffffffffff83166000908152600360205260408120549081900361047b5750505050565b73ffffffffffffffffffffffffffffffffffffffff84166000818152600360205260408120556104ac9084836107d8565b6040805173ffffffffffffffffffffffffffffffffffffffff8087168252851660208201529081018290527f244e51bc38c1452fa8aaf487bcb4bca36c2baa3a5fbdb776b1eabd8dc6d277cd9060600160405180910390a1505b505050565b600082815260208190526040902060010154610526816107cb565b610530838361092f565b50505050565b73ffffffffffffffffffffffffffffffffffffffff81163314610585576040517f6697b23200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6105068282610964565b60008281526001602052604081206105a79083610991565b9392505050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f556105d8816107cb565b612710821115610649576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f6e657746656552617465203e206d61780000000000000000000000000000000060448201526064015b60405180910390fd5b600280549083905560408051828152602081018590527f14914da2bf76024616fbe1859783fcd4dbddcb179b1f3a854949fbf920dcb95791015b60405180910390a1505050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f556106ba816107cb565b600480549083905560408051828152602081018590527f5cf09b12f3f56b4c564d51b25b40360af6d795198adb61ae0806a36c294323fa9101610683565b60008181526001602052604081206104179061099d565b60008281526020819052604090206001015461072a816107cb565b6105308383610964565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f7965db0b00000000000000000000000000000000000000000000000000000000148061041757507f01ffc9a7000000000000000000000000000000000000000000000000000000007fffffffff00000000000000000000000000000000000000000000000000000000831614610417565b6107d581336109a7565b50565b3073ffffffffffffffffffffffffffffffffffffffff8316036107fa57505050565b8060000361080757505050565b7fffffffffffffffffffffffff111111111111111111111111111111111111111273ffffffffffffffffffffffffffffffffffffffff84160161090e5760008273ffffffffffffffffffffffffffffffffffffffff168260405160006040518083038185875af1925050503d806000811461089e576040519150601f19603f3d011682016040523d82523d6000602084013e6108a3565b606091505b5050905080610530576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f455448207472616e73666572206661696c6564000000000000000000000000006044820152606401610640565b61050673ffffffffffffffffffffffffffffffffffffffff84168383610a31565b60008061093c8484610abe565b905080156105a757600084815260016020526040902061095c9084610bba565b509392505050565b6000806109718484610bdc565b905080156105a757600084815260016020526040902061095c9084610c97565b60006105a78383610cb9565b6000610417825490565b60008281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915290205460ff16610a2d576040517fe2517d3f00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8216600482015260248101839052604401610640565b5050565b6040805173ffffffffffffffffffffffffffffffffffffffff8416602482015260448082018490528251808303909101815260649091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fa9059cbb00000000000000000000000000000000000000000000000000000000179052610506908490610ce3565b60008281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915281205460ff16610bb25760008381526020818152604080832073ffffffffffffffffffffffffffffffffffffffff86168452909152902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055610b503390565b73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16847f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a4506001610417565b506000610417565b60006105a78373ffffffffffffffffffffffffffffffffffffffff8416610d79565b60008281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915281205460ff1615610bb25760008381526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8616808552925280832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016905551339286917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a4506001610417565b60006105a78373ffffffffffffffffffffffffffffffffffffffff8416610dc0565b6000826000018281548110610cd057610cd061112a565b9060005260206000200154905092915050565b6000610d0573ffffffffffffffffffffffffffffffffffffffff841683610eb3565b90508051600014158015610d2a575080806020019051810190610d289190611159565b155b15610506576040517f5274afe700000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff84166004820152602401610640565b6000818152600183016020526040812054610bb257508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155610417565b60008181526001830160205260408120548015610ea9576000610de460018361117b565b8554909150600090610df89060019061117b565b9050808214610e5d576000866000018281548110610e1857610e1861112a565b9060005260206000200154905080876000018481548110610e3b57610e3b61112a565b6000918252602080832090910192909255918252600188019052604090208390555b8554869080610e6e57610e6e6111b5565b600190038181906000526020600020016000905590558560010160008681526020019081526020016000206000905560019350505050610417565b6000915050610417565b60606105a783836000846000808573ffffffffffffffffffffffffffffffffffffffff168486604051610ee691906111e4565b60006040518083038185875af1925050503d8060008114610f23576040519150601f19603f3d011682016040523d82523d6000602084013e610f28565b606091505b5091509150610f38868383610f42565b9695505050505050565b606082610f5757610f5282610fd1565b6105a7565b8151158015610f7b575073ffffffffffffffffffffffffffffffffffffffff84163b155b15610fca576040517f9996b31500000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff85166004820152602401610640565b50806105a7565b805115610fe15780518082602001fd5b6040517f1425ea4200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006020828403121561102557600080fd5b81357fffffffff00000000000000000000000000000000000000000000000000000000811681146105a757600080fd5b803573ffffffffffffffffffffffffffffffffffffffff8116811461107957600080fd5b919050565b6000806040838503121561109157600080fd5b61109a83611055565b91506110a860208401611055565b90509250929050565b6000602082840312156110c357600080fd5b5035919050565b600080604083850312156110dd57600080fd5b823591506110a860208401611055565b6000806040838503121561110057600080fd5b50508035926020909101359150565b60006020828403121561112157600080fd5b6105a782611055565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60006020828403121561116b57600080fd5b815180151581146105a757600080fd5b81810381811115610417577f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fd5b6000825160005b8181101561120557602081860181015185830152016111eb565b50600092019182525091905056fea26469706673582212208b32889d103161da471a6c3bbc957a6d1f6866bfcc129ed80af1c666033956c464736f6c63430008140033","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.20 ^0.8.20 ^0.8.4;\n\n// contracts/interfaces/IAdmin.sol\n\ninterface IAdmin {\n // ============ Events ============\n\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n event ChainGasAmountUpdated(uint256 oldChainGasAmount, uint256 newChainGasAmount);\n\n // ============ Methods ============\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n\n function setChainGasAmount(uint256 newChainGasAmount) external;\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IMulticallTarget.sol\n\n/// @notice Interface for a contract that can be called multiple times by the same caller. Inspired by MulticallV3:\n/// https://github.com/mds1/multicall/blob/master/src/Multicall3.sol\ninterface IMulticallTarget {\n struct Result {\n bool success;\n bytes returnData;\n }\n\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external;\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results);\n}\n\n// contracts/libs/Errors.sol\n\nerror DeadlineExceeded();\nerror DeadlineNotExceeded();\nerror DeadlineTooShort();\nerror InsufficientOutputAmount();\n\nerror MsgValueIncorrect();\nerror PoolNotFound();\nerror TokenAddressMismatch();\nerror TokenNotContract();\nerror TokenNotETH();\nerror TokensIdentical();\n\nerror ChainIncorrect();\nerror AmountIncorrect();\nerror ZeroAddress();\n\nerror DisputePeriodNotPassed();\nerror DisputePeriodPassed();\nerror SenderIncorrect();\nerror StatusIncorrect();\nerror TransactionIdIncorrect();\nerror TransactionRelayed();\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// contracts/utils/MulticallTarget.sol\n\n// solhint-disable avoid-low-level-calls\n/// @notice Template for a contract that supports batched calls (preserving the msg.sender).\n/// Only calls with zero msg.value could be batched.\nabstract contract MulticallTarget is IMulticallTarget {\n error MulticallTarget__UndeterminedRevert();\n\n /// @notice Perform a batched call to this contract, preserving the msg.sender.\n /// The return data from each call is discarded.\n /// @dev The method is non-payable, so only calls with `msg.value == 0` could be batched.\n /// It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag.\n /// Otherwise, the whole batch call will be reverted with the original revert reason.\n /// @param data List of abi-encoded calldata for the calls to perform.\n /// @param ignoreReverts Whether to ignore the revert errors from the calls.\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external {\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\n if (!success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(result);\n }\n }\n }\n\n /// @notice Perform a batched call to this contract, preserving the msg.sender.\n /// The return data from each call is preserved.\n /// @dev The method is non-payable, so only calls with `msg.value == 0` could be batched.\n /// It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag.\n /// Otherwise, the whole batch call will be reverted with the original revert reason.\n /// @param data List of abi-encoded calldata for the calls to perform.\n /// @param ignoreReverts Whether to ignore the revert errors from the calls.\n /// @return results List of results from the calls: `(success, returnData)`.\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results)\n {\n results = new Result[](data.length);\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (results[i].success, results[i].returnData) = address(this).delegatecall(data[i]);\n if (!results[i].success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(results[i].returnData);\n }\n }\n }\n\n /// @dev Bubbles the revert message from the underlying call.\n /// Note: preserves the same custom error or revert string, if one was used.\n /// Source: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v5.0.2/contracts/utils/Address.sol#L143-L158\n function _bubbleRevert(bytes memory returnData) internal pure {\n // Look for revert reason and bubble it up if present\n if (returnData.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n // solhint-disable-next-line no-inline-assembly\n assembly {\n let returndata_size := mload(returnData)\n revert(add(32, returnData), returndata_size)\n }\n } else {\n revert MulticallTarget__UndeterminedRevert();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// contracts/libs/UniversalToken.sol\n\nlibrary UniversalTokenLib {\n using SafeERC20 for IERC20;\n\n address internal constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Transfers tokens to the given account. Reverts if transfer is not successful.\n /// @dev This might trigger fallback, if ETH is transferred to the contract.\n /// Make sure this can not lead to reentrancy attacks.\n function universalTransfer(address token, address to, uint256 value) internal {\n // Don't do anything, if need to send tokens to this address\n if (to == address(this)) return;\n // Don't do anything, if trying to send zero value\n if (value == 0) return;\n if (token == ETH_ADDRESS) {\n /// @dev Note: this can potentially lead to executing code in `to`.\n // solhint-disable-next-line avoid-low-level-calls\n (bool success,) = to.call{value: value}(\"\");\n require(success, \"ETH transfer failed\");\n } else {\n IERC20(token).safeTransfer(to, value);\n }\n }\n\n /// @notice Issues an infinite allowance to the spender, if the current allowance is insufficient\n /// to spend the given amount.\n function universalApproveInfinity(address token, address spender, uint256 amountToSpend) internal {\n // ETH Chad doesn't require your approval\n if (token == ETH_ADDRESS) return;\n // No-op if allowance is already sufficient\n uint256 allowance = IERC20(token).allowance(address(this), spender);\n if (allowance \u003e= amountToSpend) return;\n // Otherwise, reset approval to 0 and set to max allowance\n if (allowance \u003e 0) IERC20(token).safeDecreaseAllowance(spender, allowance);\n IERC20(token).safeIncreaseAllowance(spender, type(uint256).max);\n }\n\n /// @notice Returns the balance of the given token (or native ETH) for the given account.\n function universalBalanceOf(address token, address account) internal view returns (uint256) {\n if (token == ETH_ADDRESS) {\n return account.balance;\n } else {\n return IERC20(token).balanceOf(account);\n }\n }\n\n /// @dev Checks that token is a contract and not ETH_ADDRESS.\n function assertIsContract(address token) internal view {\n // Check that ETH_ADDRESS was not used (in case this is a predeploy on any of the chains)\n if (token == UniversalTokenLib.ETH_ADDRESS) revert TokenNotContract();\n // Check that token is not an EOA\n if (token.code.length == 0) revert TokenNotContract();\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/Admin.sol\n\ncontract Admin is IAdmin, AccessControlEnumerable {\n using UniversalTokenLib for address;\n\n bytes32 public constant RELAYER_ROLE = keccak256(\"RELAYER_ROLE\");\n bytes32 public constant REFUNDER_ROLE = keccak256(\"REFUNDER_ROLE\");\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n uint256 public constant FEE_BPS = 1e6;\n uint256 public constant FEE_RATE_MAX = 0.01e6; // max 1% on origin amount\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Chain gas amount to forward as rebate if requested\n uint256 public chainGasAmount;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n }\n\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n require(newFeeRate \u003c= FEE_RATE_MAX, \"newFeeRate \u003e max\");\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n token.universalTransfer(recipient, feeAmount);\n emit FeesSwept(token, recipient, feeAmount);\n }\n\n function setChainGasAmount(uint256 newChainGasAmount) external onlyRole(GOVERNOR_ROLE) {\n uint256 oldChainGasAmount = chainGasAmount;\n chainGasAmount = newChainGasAmount;\n emit ChainGasAmountUpdated(oldChainGasAmount, newChainGasAmount);\n }\n}\n\n// contracts/FastBridge.sol\n\ncontract FastBridge is IFastBridge, MulticallTarget, Admin {\n using SafeERC20 for IERC20;\n using UniversalTokenLib for address;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Delay for a transaction after which it could be permisionlessly refunded\n uint256 public constant REFUND_DELAY = 7 days;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeStatus) public bridgeStatuses;\n /// @notice Proof of relayed bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeProof) public bridgeProofs;\n /// @notice Whether bridge has been relayed on destination chain\n mapping(bytes32 =\u003e bool) public bridgeRelays;\n\n /// @dev to prevent replays\n uint256 public nonce;\n // @dev the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @notice Pulls a requested token from the user to the requested recipient.\n /// @dev Be careful of re-entrancy issues when msg.value \u003e 0 and recipient != address(this)\n function _pullToken(address recipient, address token, uint256 amount) internal returns (uint256 amountPulled) {\n if (token != UniversalTokenLib.ETH_ADDRESS) {\n token.assertIsContract();\n // Record token balance before transfer\n amountPulled = IERC20(token).balanceOf(recipient);\n // Token needs to be pulled only if msg.value is zero\n // This way user can specify WETH as the origin asset\n IERC20(token).safeTransferFrom(msg.sender, recipient, amount);\n // Use the difference between the recorded balance and the current balance as the amountPulled\n amountPulled = IERC20(token).balanceOf(recipient) - amountPulled;\n } else {\n // Otherwise, we need to check that ETH amount matches msg.value\n if (amount != msg.value) revert MsgValueIncorrect();\n // Transfer value to recipient if not this address\n if (recipient != address(this)) token.universalTransfer(recipient, amount);\n // We will forward msg.value in the external call later, if recipient is not this contract\n amountPulled = msg.value;\n }\n }\n\n /// @inheritdoc IFastBridge\n function getBridgeTransaction(bytes memory request) public pure returns (BridgeTransaction memory) {\n return abi.decode(request, (BridgeTransaction));\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n // check bridge params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n\n // transfer tokens to bridge contract\n // @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _pullToken(address(this), params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n\n // set status to requested\n bytes memory request = abi.encode(\n BridgeTransaction({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n sendChainGas: params.sendChainGas,\n deadline: params.deadline,\n nonce: nonce++ // increment nonce on every bridge\n })\n );\n bytes32 transactionId = keccak256(request);\n bridgeStatuses[transactionId] = BridgeStatus.REQUESTED;\n\n emit BridgeRequested(\n transactionId,\n params.sender,\n request,\n params.dstChainId,\n params.originToken,\n params.destToken,\n originAmount,\n params.destAmount,\n params.sendChainGas\n );\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes memory request) external payable onlyRole(RELAYER_ROLE) {\n bytes32 transactionId = keccak256(request);\n BridgeTransaction memory transaction = getBridgeTransaction(request);\n if (transaction.destChainId != uint32(block.chainid)) revert ChainIncorrect();\n\n // check haven't exceeded deadline for relay to happen\n if (block.timestamp \u003e transaction.deadline) revert DeadlineExceeded();\n\n // mark bridge transaction as relayed\n if (bridgeRelays[transactionId]) revert TransactionRelayed();\n bridgeRelays[transactionId] = true;\n\n // transfer tokens to recipient on destination chain and gas rebate if requested\n address to = transaction.destRecipient;\n address token = transaction.destToken;\n uint256 amount = transaction.destAmount;\n\n uint256 rebate = chainGasAmount;\n if (!transaction.sendChainGas) {\n // forward erc20\n rebate = 0;\n _pullToken(to, token, amount);\n } else if (token == UniversalTokenLib.ETH_ADDRESS) {\n // lump in gas rebate into amount in native gas token\n _pullToken(to, token, amount + rebate);\n } else {\n // forward erc20 then forward gas rebate in native gas token\n _pullToken(to, token, amount);\n _pullToken(to, UniversalTokenLib.ETH_ADDRESS, rebate);\n }\n\n emit BridgeRelayed(\n transactionId,\n msg.sender,\n to,\n transaction.originChainId,\n transaction.originToken,\n transaction.destToken,\n transaction.originAmount,\n transaction.destAmount,\n rebate\n );\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes memory request, bytes32 destTxHash) external onlyRole(RELAYER_ROLE) {\n bytes32 transactionId = keccak256(request);\n // update bridge tx status given proof provided\n if (bridgeStatuses[transactionId] != BridgeStatus.REQUESTED) revert StatusIncorrect();\n bridgeStatuses[transactionId] = BridgeStatus.RELAYER_PROVED;\n bridgeProofs[transactionId] = BridgeProof({timestamp: uint96(block.timestamp), relayer: msg.sender}); // overflow ok\n\n emit BridgeProofProvided(transactionId, msg.sender, destTxHash);\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint96(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint96).max but\n /// proof.timestamp \u003c type(uint96).max via unchecked statement\n /// @param proof The bridge proof\n /// @return delta Time delta since proof submitted\n function _timeSince(BridgeProof memory proof) internal view returns (uint256 delta) {\n unchecked {\n delta = uint96(block.timestamp) - proof.timestamp;\n }\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n if (bridgeStatuses[transactionId] != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n BridgeProof memory proof = bridgeProofs[transactionId];\n if (proof.relayer != relayer) revert SenderIncorrect();\n return _timeSince(proof) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes memory request, address to) external onlyRole(RELAYER_ROLE) {\n bytes32 transactionId = keccak256(request);\n BridgeTransaction memory transaction = getBridgeTransaction(request);\n\n // update bridge tx status if able to claim origin collateral\n if (bridgeStatuses[transactionId] != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n\n BridgeProof memory proof = bridgeProofs[transactionId];\n if (proof.relayer != msg.sender) revert SenderIncorrect();\n if (_timeSince(proof) \u003c= DISPUTE_PERIOD) revert DisputePeriodNotPassed();\n\n bridgeStatuses[transactionId] = BridgeStatus.RELAYER_CLAIMED;\n\n // update protocol fees if origin fee amount exists\n if (transaction.originFeeAmount \u003e 0) protocolFees[transaction.originToken] += transaction.originFeeAmount;\n\n // transfer origin collateral less fee to specified address\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositClaimed(transactionId, msg.sender, to, token, amount);\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n if (bridgeStatuses[transactionId] != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(bridgeProofs[transactionId]) \u003e DISPUTE_PERIOD) revert DisputePeriodPassed();\n\n // @dev relayer gets slashed effectively if dest relay has gone thru\n bridgeStatuses[transactionId] = BridgeStatus.REQUESTED;\n delete bridgeProofs[transactionId];\n\n emit BridgeProofDisputed(transactionId, msg.sender);\n }\n\n /// @inheritdoc IFastBridge\n function refund(bytes memory request) external {\n bytes32 transactionId = keccak256(request);\n BridgeTransaction memory transaction = getBridgeTransaction(request);\n\n if (hasRole(REFUNDER_ROLE, msg.sender)) {\n // Refunder can refund if deadline has passed\n if (block.timestamp \u003c= transaction.deadline) revert DeadlineNotExceeded();\n } else {\n // Permissionless refund is allowed after REFUND_DELAY\n if (block.timestamp \u003c= transaction.deadline + REFUND_DELAY) revert DeadlineNotExceeded();\n }\n\n // set status to refunded if still in requested state\n if (bridgeStatuses[transactionId] != BridgeStatus.REQUESTED) revert StatusIncorrect();\n bridgeStatuses[transactionId] = BridgeStatus.REFUNDED;\n\n // transfer origin collateral back to original sender\n address to = transaction.originSender;\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount + transaction.originFeeAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n }\n}\n\n// test/FastBridgeMock.sol\n\ncontract FastBridgeMock is IFastBridge, Admin {\n // @dev the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @dev to prevent replays\n uint256 public nonce;\n\n /// @notice We include an empty \"test\" function so that this contract does not appear in the coverage report.\n function testFastBridgeMock() external {}\n\n function getBridgeTransaction(bytes memory request) public pure returns (BridgeTransaction memory) {\n return abi.decode(request, (BridgeTransaction));\n }\n\n // used for testing in go.\n // see: https://ethereum.stackexchange.com/questions/21155/how-to-expose-enum-in-solidity-contract\n // make sure to update fastbridge/status.go if this changes\n // or underliyng enum changes.\n //\n // TODO: a foundry test should be added to ensure this is always in sync.\n function getEnumKeyByValue(FastBridge.BridgeStatus keyValue) public pure returns (string memory) {\n if (FastBridge.BridgeStatus.NULL == keyValue) return \"NULL\";\n if (FastBridge.BridgeStatus.REQUESTED == keyValue) return \"REQUESTED\";\n if (FastBridge.BridgeStatus.RELAYER_PROVED == keyValue) return \"RELAYER_PROVED\";\n if (FastBridge.BridgeStatus.RELAYER_CLAIMED == keyValue) return \"RELAYER_CLAIMED\";\n if (FastBridge.BridgeStatus.REFUNDED == keyValue) return \"REFUNDED\";\n return \"\";\n }\n\n function mockBridgeRequest(bytes32 transactionId, address sender, BridgeParams memory params) external {\n sender;\n uint256 originFeeAmount = (params.originAmount * protocolFeeRate) / FEE_BPS;\n params.originAmount -= originFeeAmount;\n\n bytes memory request = abi.encode(\n BridgeTransaction({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: params.originAmount, // includes relayer fee\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n sendChainGas: params.sendChainGas,\n deadline: params.deadline,\n nonce: nonce++ // increment nonce on every bridge\n })\n );\n\n emit BridgeRequested(\n transactionId,\n params.sender,\n request,\n params.dstChainId,\n params.originToken,\n params.destToken,\n params.originAmount,\n params.destAmount,\n params.sendChainGas\n );\n }\n\n function mockBridgeRequestRaw(bytes32 transactionId, address sender, bytes memory request) external {\n sender;\n BridgeTransaction memory transaction = getBridgeTransaction(request);\n emit BridgeRequested(\n transactionId,\n transaction.originSender,\n request,\n transaction.destChainId,\n transaction.originToken,\n transaction.destToken,\n transaction.originAmount,\n transaction.destAmount,\n transaction.sendChainGas\n );\n }\n\n function mockBridgeRelayer(\n bytes32 transactionId,\n address relayer,\n address to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n )\n external\n {\n emit BridgeRelayed(\n transactionId, relayer, to, originChainId, originToken, destToken, originAmount, destAmount, chainGasAmount\n );\n }\n\n function bridge(BridgeParams memory) external payable {\n revert(\"not implemented\");\n }\n\n function relay(bytes memory) external payable {\n revert(\"not implemented\");\n }\n\n function prove(bytes memory, bytes32) external pure {\n revert(\"not implemented\");\n }\n\n function canClaim(bytes32, address) external pure returns (bool) {\n revert(\"not implemented\");\n }\n\n function claim(bytes memory, address) external pure {\n revert(\"not implemented\");\n }\n\n function dispute(bytes32) external pure {\n revert(\"not implemented\");\n }\n\n function refund(bytes memory) external pure {\n revert(\"not implemented\");\n }\n}\n","language":"Solidity","languageVersion":"0.8.20","compilerVersion":"0.8.20","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"60939:1843:0:-:0;;;61766:83;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;61804:38;50976:4;61835:6;61804:10;:38::i;:::-;;61766:83;60939:1843;;60289:257;60375:4;;60406:31;60423:4;60429:7;60406:16;:31::i;:::-;60391:46;;60451:7;60447:69;;;60474:18;;;;:12;:18;;;;;:31;;60497:7;60474:22;:31::i;:::-;;60447:69;60532:7;-1:-1:-1;60289:257:0;;;;;:::o;54923:316::-;55000:4;51698:12;;;;;;;;;;;-1:-1:-1;;;;;51698:29:0;;;;;;;;;;;;55016:217;;55059:6;:12;;;;;;;;;;;-1:-1:-1;;;;;55059:29:0;;;;;;;;;:36;;-1:-1:-1;;55059:36:0;55091:4;55059:36;;;55141:12;22984:10;;22905:96;55141:12;-1:-1:-1;;;;;55114:40:0;55132:7;-1:-1:-1;;;;;55114:40:0;55126:4;55114:40;;;;;;;;;;-1:-1:-1;55175:4:0;55168:11;;55016:217;-1:-1:-1;55217:5:0;55210:12;;32429:150;32499:4;32522:50;32527:3;-1:-1:-1;;;;;32547:23:0;;26417:4;28473:21;;;:14;;;:21;;;;;;26433:321;;-1:-1:-1;26475:23:0;;;;;;;;:11;:23;;;;;;;;;;;;;26657:18;;26633:21;;;:14;;;:21;;;;;;:42;;;;26689:11;;14:290:1;84:6;137:2;125:9;116:7;112:23;108:32;105:52;;;153:1;150;143:12;105:52;179:16;;-1:-1:-1;;;;;224:31:1;;214:42;;204:70;;270:1;267;260:12;14:290;60939:1843:0;;;;;;","srcMapRuntime":"60939:1843:0:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;58949:212;;;;;;:::i;:::-;;:::i;:::-;;;516:14:1;;509:22;491:41;;479:2;464:18;58949:212:0;;;;;;;;61179:60;;61216:23;61179:60;;;;;689:25:1;;;677:2;662:18;61179:60:0;543:177:1;62151:359:0;;;;;;:::i;:::-;;:::i;:::-;;61361:45;;61400:6;61361:45;;52554:120;;;;;;:::i;:::-;52619:7;52645:12;;;;;;;;;;:22;;;;52554:120;52970:136;;;;;;:::i;:::-;;:::i;54072:245::-;;;;;;:::i;:::-;;:::i;61523:30::-;;;;;;61107:66;;61147:26;61107:66;;59746:142;;;;;;:::i;:::-;;:::i;:::-;;;2246:42:1;2234:55;;;2216:74;;2204:2;2189:18;59746:142:0;2070:226:1;51598:136:0;;;;;;:::i;:::-;51675:4;51698:12;;;;;;;;;;;:29;;;;;;;;;;;;;;;;51598:136;61037:64;;61076:25;61037:64;;50931:49;;50976:4;50931:49;;61855:290;;;;;;:::i;:::-;;:::i;62516:264::-;;;;;;:::i;:::-;;:::i;61318:37::-;;61352:3;61318:37;;60056:131;;;;;;:::i;:::-;;:::i;61245:66::-;;61285:26;61245:66;;53386:138;;;;;;:::i;:::-;;:::i;61609:47::-;;;;;;:::i;:::-;;;;;;;;;;;;;;61730:29;;;;;;58949:212;59034:4;59057:57;;;59072:42;59057:57;;:97;;;59118:36;59142:11;59118:23;:36::i;:::-;59050:104;58949:212;-1:-1:-1;;58949:212:0:o;62151:359::-;61285:26;51208:16;51219:4;51208:10;:16::i;:::-;62275:19:::1;::::0;::::1;62255:17;62275:19:::0;;;:12:::1;:19;::::0;;;;;;62308:14;;;62304:27:::1;;62324:7;62151:359:::0;;;:::o;62304:27::-:1;62372:19;::::0;::::1;62394:1;62372:19:::0;;;:12:::1;:19;::::0;;;;:23;62405:45:::1;::::0;62429:9;62440;62405:23:::1;:45::i;:::-;62465:38;::::0;;2889:42:1;2958:15;;;2940:34;;3010:15;;3005:2;2990:18;;2983:43;3042:18;;;3035:34;;;62465:38:0::1;::::0;2867:2:1;2852:18;62465:38:0::1;;;;;;;62245:265;51234:1;62151:359:::0;;;:::o;52970:136::-;52619:7;52645:12;;;;;;;;;;:22;;;51208:16;51219:4;51208:10;:16::i;:::-;53074:25:::1;53085:4;53091:7;53074:10;:25::i;:::-;;52970:136:::0;;;:::o;54072:245::-;54165:34;;;22984:10;54165:34;54161:102;;54222:30;;;;;;;;;;;;;;54161:102;54273:37;54285:4;54291:18;54273:11;:37::i;59746:142::-;59827:7;59853:18;;;:12;:18;;;;;:28;;59875:5;59853:21;:28::i;:::-;59846:35;59746:142;-1:-1:-1;;;59746:142:0:o;61855:290::-;61285:26;51208:16;51219:4;51208:10;:16::i;:::-;61400:6:::1;61954:10;:26;;61946:55;;;::::0;::::1;::::0;;3282:2:1;61946:55:0::1;::::0;::::1;3264:21:1::0;3321:2;3301:18;;;3294:30;3360:18;3340;;;3333:46;3396:18;;61946:55:0::1;;;;;;;;;62032:15;::::0;;62057:28;;;;62100:38:::1;::::0;;3599:25:1;;;3655:2;3640:18;;3633:34;;;62100:38:0::1;::::0;3572:18:1;62100:38:0::1;;;;;;;;61936:209;61855:290:::0;;:::o;62516:264::-;61285:26;51208:16;51219:4;51208:10;:16::i;:::-;62641:14:::1;::::0;;62665:34;;;;62714:59:::1;::::0;;3599:25:1;;;3655:2;3640:18;;3633:34;;;62714:59:0::1;::::0;3572:18:1;62714:59:0::1;3425:248:1::0;60056:131:0;60127:7;60153:18;;;:12;:18;;;;;:27;;:25;:27::i;53386:138::-;52619:7;52645:12;;;;;;;;;;:22;;;51208:16;51219:4;51208:10;:16::i;:::-;53491:26:::1;53503:4;53509:7;53491:11;:26::i;51309:202::-:0;51394:4;51417:47;;;51432:32;51417:47;;:87;;-1:-1:-1;43224:25:0;43209:40;;;;51468:36;43110:146;51943:103;52009:30;52020:4;22984:10;52009;:30::i;:::-;51943:103;:::o;56221:653::-;56396:4;56382:19;;;;56378:32;;56221:653;;;:::o;56378:32::-;56482:5;56491:1;56482:10;56478:23;;56221:653;;;:::o;56478:23::-;56514:20;;;;;56510:358;;56694:12;56711:2;:7;;56726:5;56711:25;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;56693:43;;;56758:7;56750:39;;;;;;;4090:2:1;56750:39:0;;;4072:21:1;4129:2;4109:18;;;4102:30;4168:21;4148:18;;;4141:49;4207:18;;56750:39:0;3888:343:1;56510:358:0;56820:37;:26;;;56847:2;56851:5;56820:26;:37::i;60289:257::-;60375:4;60391:12;60406:31;60423:4;60429:7;60406:16;:31::i;:::-;60391:46;;60451:7;60447:69;;;60474:18;;;;:12;:18;;;;;:31;;60497:7;60474:22;:31::i;:::-;;60532:7;60289:257;-1:-1:-1;;;60289:257:0:o;60649:262::-;60736:4;60752:12;60767:32;60785:4;60791:7;60767:17;:32::i;:::-;60752:47;;60813:7;60809:72;;;60836:18;;;;:12;:18;;;;;:34;;60862:7;60836:25;:34::i;33687:156::-;33761:7;33811:22;33815:3;33827:5;33811:3;:22::i;33230:115::-;33293:7;33319:19;33327:3;28669:18;;28587:107;52176:197;51675:4;51698:12;;;;;;;;;;;:29;;;;;;;;;;;;;52259:108;;52309:47;;;;;4440:42:1;4428:55;;52309:47:0;;;4410:74:1;4500:18;;;4493:34;;;4383:18;;52309:47:0;4236:297:1;52259:108:0;52176:197;;:::o;44426:160::-;44535:43;;;44550:14;4428:55:1;;44535:43:0;;;4410:74:1;4500:18;;;;4493:34;;;44535:43:0;;;;;;;;;;4383:18:1;;;;44535:43:0;;;;;;;;;;;;;;44508:71;;44528:5;;44508:19;:71::i;54923:316::-;55000:4;51698:12;;;;;;;;;;;:29;;;;;;;;;;;;;55016:217;;55059:6;:12;;;;;;;;;;;:29;;;;;;;;;;:36;;;;55091:4;55059:36;;;55141:12;22984:10;;22905:96;55141:12;55114:40;;55132:7;55114:40;;55126:4;55114:40;;;;;;;;;;-1:-1:-1;55175:4:0;55168:11;;55016:217;-1:-1:-1;55217:5:0;55210:12;;32429:150;32499:4;32522:50;32527:3;32547:23;;;32522:4;:50::i;55474:317::-;55552:4;51698:12;;;;;;;;;;;:29;;;;;;;;;;;;;55568:217;;;55642:5;55610:12;;;;;;;;;;;:29;;;;;;;;;;;:37;;;;;;55666:40;22984:10;;55610:12;;55666:40;;55642:5;55666:40;-1:-1:-1;55727:4:0;55720:11;;32747:156;32820:4;32843:53;32851:3;32871:23;;;32843:7;:53::i;29036:118::-;29103:7;29129:3;:11;;29141:5;29129:18;;;;;;;;:::i;:::-;;;;;;;;;29122:25;;29036:118;;;;:::o;47182:629::-;47601:23;47627:33;:27;;;47655:4;47627:27;:33::i;:::-;47601:59;;47674:10;:17;47695:1;47674:22;;:57;;;;;47712:10;47701:30;;;;;;;;;;;;:::i;:::-;47700:31;47674:57;47670:135;;;47754:40;;;;;2246:42:1;2234:55;;47754:40:0;;;2216:74:1;2189:18;;47754:40:0;2070:226:1;26354:406:0;26417:4;28473:21;;;:14;;;:21;;;;;;26433:321;;-1:-1:-1;26475:23:0;;;;;;;;:11;:23;;;;;;;;;;;;;26657:18;;26633:21;;;:14;;;:21;;;;;;:42;;;;26689:11;;26928:1368;26994:4;27123:21;;;:14;;;:21;;;;;;27159:13;;27155:1135;;27526:18;27547:12;27558:1;27547:8;:12;:::i;:::-;27593:18;;27526:33;;-1:-1:-1;27573:17:0;;27593:22;;27614:1;;27593:22;:::i;:::-;27573:42;;27648:9;27634:10;:23;27630:378;;27677:17;27697:3;:11;;27709:9;27697:22;;;;;;;;:::i;:::-;;;;;;;;;27677:42;;27844:9;27818:3;:11;;27830:10;27818:23;;;;;;;;:::i;:::-;;;;;;;;;;;;:35;;;;27957:25;;;:14;;;:25;;;;;:36;;;27630:378;28086:17;;:3;;:17;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;28189:3;:14;;:21;28204:5;28189:21;;;;;;;;;;;28182:28;;;28232:4;28225:11;;;;;;;27155:1135;28274:5;28267:12;;;;;18690:151;18765:12;18796:38;18818:6;18826:4;18832:1;18765:12;19406;19420:23;19447:6;:11;;19466:5;19473:4;19447:31;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;19405:73;;;;19495:55;19522:6;19530:7;19539:10;19495:26;:55::i;:::-;19488:62;19165:392;-1:-1:-1;;;;;;19165:392:0:o;20610:582::-;20754:12;20783:7;20778:408;;20806:19;20814:10;20806:7;:19::i;:::-;20778:408;;;21030:17;;:22;:49;;;;-1:-1:-1;21056:18:0;;;;:23;21030:49;21026:119;;;21106:24;;;;;2246:42:1;2234:55;;21106:24:0;;;2216:74:1;2189:18;;21106:24:0;2070:226:1;21026:119:0;-1:-1:-1;21165:10:0;21158:17;;21728:516;21859:17;;:21;21855:383;;22087:10;22081:17;22143:15;22130:10;22126:2;22122:19;22115:44;21855:383;22210:17;;;;;;;;;;;;;;14:332:1;72:6;125:2;113:9;104:7;100:23;96:32;93:52;;;141:1;138;131:12;93:52;180:9;167:23;230:66;223:5;219:78;212:5;209:89;199:117;;312:1;309;302:12;725:196;793:20;;853:42;842:54;;832:65;;822:93;;911:1;908;901:12;822:93;725:196;;;:::o;926:260::-;994:6;1002;1055:2;1043:9;1034:7;1030:23;1026:32;1023:52;;;1071:1;1068;1061:12;1023:52;1094:29;1113:9;1094:29;:::i;:::-;1084:39;;1142:38;1176:2;1165:9;1161:18;1142:38;:::i;:::-;1132:48;;926:260;;;;;:::o;1373:180::-;1432:6;1485:2;1473:9;1464:7;1460:23;1456:32;1453:52;;;1501:1;1498;1491:12;1453:52;-1:-1:-1;1524:23:1;;1373:180;-1:-1:-1;1373:180:1:o;1558:254::-;1626:6;1634;1687:2;1675:9;1666:7;1662:23;1658:32;1655:52;;;1703:1;1700;1693:12;1655:52;1739:9;1726:23;1716:33;;1768:38;1802:2;1791:9;1787:18;1768:38;:::i;1817:248::-;1885:6;1893;1946:2;1934:9;1925:7;1921:23;1917:32;1914:52;;;1962:1;1959;1952:12;1914:52;-1:-1:-1;;1985:23:1;;;2055:2;2040:18;;;2027:32;;-1:-1:-1;1817:248:1:o;2486:186::-;2545:6;2598:2;2586:9;2577:7;2573:23;2569:32;2566:52;;;2614:1;2611;2604:12;2566:52;2637:29;2656:9;2637:29;:::i;4840:184::-;4892:77;4889:1;4882:88;4989:4;4986:1;4979:15;5013:4;5010:1;5003:15;5029:277;5096:6;5149:2;5137:9;5128:7;5124:23;5120:32;5117:52;;;5165:1;5162;5155:12;5117:52;5197:9;5191:16;5250:5;5243:13;5236:21;5229:5;5226:32;5216:60;;5272:1;5269;5262:12;5311:282;5378:9;;;5399:11;;;5396:191;;;5443:77;5440:1;5433:88;5544:4;5541:1;5534:15;5572:4;5569:1;5562:15;5598:184;5650:77;5647:1;5640:88;5747:4;5744:1;5737:15;5771:4;5768:1;5761:15;5787:412;5916:3;5954:6;5948:13;5979:1;5989:129;6003:6;6000:1;5997:13;5989:129;;;6101:4;6085:14;;;6081:25;;6075:32;6062:11;;;6055:53;6018:12;5989:129;;;-1:-1:-1;6173:1:1;6137:16;;6162:13;;;-1:-1:-1;6137:16:1;5787:412;-1:-1:-1;5787:412:1:o","abiDefinition":[{"inputs":[{"internalType":"address","name":"_owner","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AccessControlBadConfirmation","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"bytes32","name":"neededRole","type":"bytes32"}],"name":"AccessControlUnauthorizedAccount","type":"error"},{"inputs":[{"internalType":"address","name":"target","type":"address"}],"name":"AddressEmptyCode","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"AddressInsufficientBalance","type":"error"},{"inputs":[],"name":"FailedInnerCall","type":"error"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"SafeERC20FailedOperation","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldChainGasAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newChainGasAmount","type":"uint256"}],"name":"ChainGasAmountUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldFeeRate","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newFeeRate","type":"uint256"}],"name":"FeeRateUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"address","name":"recipient","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"FeesSwept","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"previousAdminRole","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"newAdminRole","type":"bytes32"}],"name":"RoleAdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleRevoked","type":"event"},{"inputs":[],"name":"DEFAULT_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"FEE_BPS","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"FEE_RATE_MAX","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"GOVERNOR_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"GUARD_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"REFUNDER_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"RELAYER_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"chainGasAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleAdmin","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"uint256","name":"index","type":"uint256"}],"name":"getRoleMember","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleMemberCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"grantRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"hasRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"protocolFeeRate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"protocolFees","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"callerConfirmation","type":"address"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"revokeRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"newChainGasAmount","type":"uint256"}],"name":"setChainGasAmount","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"newFeeRate","type":"uint256"}],"name":"setProtocolFeeRate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"address","name":"recipient","type":"address"}],"name":"sweepProtocolFees","outputs":[],"stateMutability":"nonpayable","type":"function"}],"userDoc":{"kind":"user","methods":{"chainGasAmount()":{"notice":"Chain gas amount to forward as rebate if requested"},"protocolFeeRate()":{"notice":"Protocol fee rate taken on origin amount deposited in origin chain"},"protocolFees(address)":{"notice":"Protocol fee amounts accumulated"}},"version":1},"developerDoc":{"errors":{"AccessControlBadConfirmation()":[{"details":"The caller of a function is not the expected one. NOTE: Don't confuse with {AccessControlUnauthorizedAccount}."}],"AccessControlUnauthorizedAccount(address,bytes32)":[{"details":"The `account` is missing a role."}],"AddressEmptyCode(address)":[{"details":"There's no code at `target` (it is not a contract)."}],"AddressInsufficientBalance(address)":[{"details":"The ETH balance of the account is not enough to perform the operation."}],"FailedInnerCall()":[{"details":"A call to an address target failed. The target may have reverted."}],"SafeERC20FailedOperation(address)":[{"details":"An operation with an ERC20 token failed."}]},"events":{"RoleAdminChanged(bytes32,bytes32,bytes32)":{"details":"Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole` `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite {RoleAdminChanged} not being emitted signaling this."},"RoleGranted(bytes32,address,address)":{"details":"Emitted when `account` is granted `role`. `sender` is the account that originated the contract call, an admin role bearer except when using {AccessControl-_setupRole}."},"RoleRevoked(bytes32,address,address)":{"details":"Emitted when `account` is revoked `role`. `sender` is the account that originated the contract call: - if using `revokeRole`, it is the admin role bearer - if using `renounceRole`, it is the role bearer (i.e. `account`)"}},"kind":"dev","methods":{"getRoleAdmin(bytes32)":{"details":"Returns the admin role that controls `role`. See {grantRole} and {revokeRole}. To change a role's admin, use {_setRoleAdmin}."},"getRoleMember(bytes32,uint256)":{"details":"Returns one of the accounts that have `role`. `index` must be a value between 0 and {getRoleMemberCount}, non-inclusive. Role bearers are not sorted in any particular way, and their ordering may change at any point. WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure you perform all queries on the same block. See the following https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post] for more information."},"getRoleMemberCount(bytes32)":{"details":"Returns the number of accounts that have `role`. Can be used together with {getRoleMember} to enumerate all bearers of a role."},"grantRole(bytes32,address)":{"details":"Grants `role` to `account`. If `account` had not been already granted `role`, emits a {RoleGranted} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleGranted} event."},"hasRole(bytes32,address)":{"details":"Returns `true` if `account` has been granted `role`."},"renounceRole(bytes32,address)":{"details":"Revokes `role` from the calling account. Roles are often managed via {grantRole} and {revokeRole}: this function's purpose is to provide a mechanism for accounts to lose their privileges if they are compromised (such as when a trusted device is misplaced). If the calling account had been revoked `role`, emits a {RoleRevoked} event. Requirements: - the caller must be `callerConfirmation`. May emit a {RoleRevoked} event."},"revokeRole(bytes32,address)":{"details":"Revokes `role` from `account`. If `account` had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleRevoked} event."},"supportsInterface(bytes4)":{"details":"See {IERC165-supportsInterface}."}},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.20+commit.a1b79de6\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_owner\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"AccessControlBadConfirmation\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"neededRole\",\"type\":\"bytes32\"}],\"name\":\"AccessControlUnauthorizedAccount\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"}],\"name\":\"AddressEmptyCode\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"AddressInsufficientBalance\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"FailedInnerCall\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"}],\"name\":\"SafeERC20FailedOperation\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"oldChainGasAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newChainGasAmount\",\"type\":\"uint256\"}],\"name\":\"ChainGasAmountUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"oldFeeRate\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newFeeRate\",\"type\":\"uint256\"}],\"name\":\"FeeRateUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"FeesSwept\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"previousAdminRole\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"newAdminRole\",\"type\":\"bytes32\"}],\"name\":\"RoleAdminChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleGranted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleRevoked\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"DEFAULT_ADMIN_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"FEE_BPS\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"FEE_RATE_MAX\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"GOVERNOR_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"GUARD_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"REFUNDER_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"RELAYER_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"chainGasAmount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"}],\"name\":\"getRoleAdmin\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"index\",\"type\":\"uint256\"}],\"name\":\"getRoleMember\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"}],\"name\":\"getRoleMemberCount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"grantRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"hasRole\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"protocolFeeRate\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"protocolFees\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"callerConfirmation\",\"type\":\"address\"}],\"name\":\"renounceRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"revokeRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"newChainGasAmount\",\"type\":\"uint256\"}],\"name\":\"setChainGasAmount\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"newFeeRate\",\"type\":\"uint256\"}],\"name\":\"setProtocolFeeRate\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes4\",\"name\":\"interfaceId\",\"type\":\"bytes4\"}],\"name\":\"supportsInterface\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"}],\"name\":\"sweepProtocolFees\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"errors\":{\"AccessControlBadConfirmation()\":[{\"details\":\"The caller of a function is not the expected one. NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\"}],\"AccessControlUnauthorizedAccount(address,bytes32)\":[{\"details\":\"The `account` is missing a role.\"}],\"AddressEmptyCode(address)\":[{\"details\":\"There's no code at `target` (it is not a contract).\"}],\"AddressInsufficientBalance(address)\":[{\"details\":\"The ETH balance of the account is not enough to perform the operation.\"}],\"FailedInnerCall()\":[{\"details\":\"A call to an address target failed. The target may have reverted.\"}],\"SafeERC20FailedOperation(address)\":[{\"details\":\"An operation with an ERC20 token failed.\"}]},\"events\":{\"RoleAdminChanged(bytes32,bytes32,bytes32)\":{\"details\":\"Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole` `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite {RoleAdminChanged} not being emitted signaling this.\"},\"RoleGranted(bytes32,address,address)\":{\"details\":\"Emitted when `account` is granted `role`. `sender` is the account that originated the contract call, an admin role bearer except when using {AccessControl-_setupRole}.\"},\"RoleRevoked(bytes32,address,address)\":{\"details\":\"Emitted when `account` is revoked `role`. `sender` is the account that originated the contract call: - if using `revokeRole`, it is the admin role bearer - if using `renounceRole`, it is the role bearer (i.e. `account`)\"}},\"kind\":\"dev\",\"methods\":{\"getRoleAdmin(bytes32)\":{\"details\":\"Returns the admin role that controls `role`. See {grantRole} and {revokeRole}. To change a role's admin, use {_setRoleAdmin}.\"},\"getRoleMember(bytes32,uint256)\":{\"details\":\"Returns one of the accounts that have `role`. `index` must be a value between 0 and {getRoleMemberCount}, non-inclusive. Role bearers are not sorted in any particular way, and their ordering may change at any point. WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure you perform all queries on the same block. See the following https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post] for more information.\"},\"getRoleMemberCount(bytes32)\":{\"details\":\"Returns the number of accounts that have `role`. Can be used together with {getRoleMember} to enumerate all bearers of a role.\"},\"grantRole(bytes32,address)\":{\"details\":\"Grants `role` to `account`. If `account` had not been already granted `role`, emits a {RoleGranted} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleGranted} event.\"},\"hasRole(bytes32,address)\":{\"details\":\"Returns `true` if `account` has been granted `role`.\"},\"renounceRole(bytes32,address)\":{\"details\":\"Revokes `role` from the calling account. Roles are often managed via {grantRole} and {revokeRole}: this function's purpose is to provide a mechanism for accounts to lose their privileges if they are compromised (such as when a trusted device is misplaced). If the calling account had been revoked `role`, emits a {RoleRevoked} event. Requirements: - the caller must be `callerConfirmation`. May emit a {RoleRevoked} event.\"},\"revokeRole(bytes32,address)\":{\"details\":\"Revokes `role` from `account`. If `account` had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleRevoked} event.\"},\"supportsInterface(bytes4)\":{\"details\":\"See {IERC165-supportsInterface}.\"}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"chainGasAmount()\":{\"notice\":\"Chain gas amount to forward as rebate if requested\"},\"protocolFeeRate()\":{\"notice\":\"Protocol fee rate taken on origin amount deposited in origin chain\"},\"protocolFees(address)\":{\"notice\":\"Protocol fee amounts accumulated\"}},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeMock.sol\":\"Admin\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeMock.sol\":{\"keccak256\":\"0xf2751f52f8216801d500da7464ad01f3c23a8286e155e2dcba6d21d6e7fd95a0\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://85d2edab24ebe321043d2b88038437e8f443a0ef26fa2139c72dcc2bc7fbc602\",\"dweb:/ipfs/QmcULiFPFJzFDT4aupVSDreXz8uHxcABb5nxpAG4zYzfNN\"]}},\"version\":1}"},"hashes":{"DEFAULT_ADMIN_ROLE()":"a217fddf","FEE_BPS()":"bf333f2c","FEE_RATE_MAX()":"0f5f6ed7","GOVERNOR_ROLE()":"ccc57490","GUARD_ROLE()":"03ed0ee5","REFUNDER_ROLE()":"5960ccf2","RELAYER_ROLE()":"926d7d7f","chainGasAmount()":"e00a83e0","getRoleAdmin(bytes32)":"248a9ca3","getRoleMember(bytes32,uint256)":"9010d07c","getRoleMemberCount(bytes32)":"ca15c873","grantRole(bytes32,address)":"2f2ff15d","hasRole(bytes32,address)":"91d14854","protocolFeeRate()":"58f85880","protocolFees(address)":"dcf844a7","renounceRole(bytes32,address)":"36568abe","revokeRole(bytes32,address)":"d547741f","setChainGasAmount(uint256)":"b250fe6b","setProtocolFeeRate(uint256)":"b13aa2d6","supportsInterface(bytes4)":"01ffc9a7","sweepProtocolFees(address,address)":"06f333f2"}},"solidity/FastBridgeMock.sol:Context":{"code":"0x","runtime-code":"0x","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.20 ^0.8.20 ^0.8.4;\n\n// contracts/interfaces/IAdmin.sol\n\ninterface IAdmin {\n // ============ Events ============\n\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n event ChainGasAmountUpdated(uint256 oldChainGasAmount, uint256 newChainGasAmount);\n\n // ============ Methods ============\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n\n function setChainGasAmount(uint256 newChainGasAmount) external;\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IMulticallTarget.sol\n\n/// @notice Interface for a contract that can be called multiple times by the same caller. Inspired by MulticallV3:\n/// https://github.com/mds1/multicall/blob/master/src/Multicall3.sol\ninterface IMulticallTarget {\n struct Result {\n bool success;\n bytes returnData;\n }\n\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external;\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results);\n}\n\n// contracts/libs/Errors.sol\n\nerror DeadlineExceeded();\nerror DeadlineNotExceeded();\nerror DeadlineTooShort();\nerror InsufficientOutputAmount();\n\nerror MsgValueIncorrect();\nerror PoolNotFound();\nerror TokenAddressMismatch();\nerror TokenNotContract();\nerror TokenNotETH();\nerror TokensIdentical();\n\nerror ChainIncorrect();\nerror AmountIncorrect();\nerror ZeroAddress();\n\nerror DisputePeriodNotPassed();\nerror DisputePeriodPassed();\nerror SenderIncorrect();\nerror StatusIncorrect();\nerror TransactionIdIncorrect();\nerror TransactionRelayed();\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// contracts/utils/MulticallTarget.sol\n\n// solhint-disable avoid-low-level-calls\n/// @notice Template for a contract that supports batched calls (preserving the msg.sender).\n/// Only calls with zero msg.value could be batched.\nabstract contract MulticallTarget is IMulticallTarget {\n error MulticallTarget__UndeterminedRevert();\n\n /// @notice Perform a batched call to this contract, preserving the msg.sender.\n /// The return data from each call is discarded.\n /// @dev The method is non-payable, so only calls with `msg.value == 0` could be batched.\n /// It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag.\n /// Otherwise, the whole batch call will be reverted with the original revert reason.\n /// @param data List of abi-encoded calldata for the calls to perform.\n /// @param ignoreReverts Whether to ignore the revert errors from the calls.\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external {\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\n if (!success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(result);\n }\n }\n }\n\n /// @notice Perform a batched call to this contract, preserving the msg.sender.\n /// The return data from each call is preserved.\n /// @dev The method is non-payable, so only calls with `msg.value == 0` could be batched.\n /// It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag.\n /// Otherwise, the whole batch call will be reverted with the original revert reason.\n /// @param data List of abi-encoded calldata for the calls to perform.\n /// @param ignoreReverts Whether to ignore the revert errors from the calls.\n /// @return results List of results from the calls: `(success, returnData)`.\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results)\n {\n results = new Result[](data.length);\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (results[i].success, results[i].returnData) = address(this).delegatecall(data[i]);\n if (!results[i].success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(results[i].returnData);\n }\n }\n }\n\n /// @dev Bubbles the revert message from the underlying call.\n /// Note: preserves the same custom error or revert string, if one was used.\n /// Source: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v5.0.2/contracts/utils/Address.sol#L143-L158\n function _bubbleRevert(bytes memory returnData) internal pure {\n // Look for revert reason and bubble it up if present\n if (returnData.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n // solhint-disable-next-line no-inline-assembly\n assembly {\n let returndata_size := mload(returnData)\n revert(add(32, returnData), returndata_size)\n }\n } else {\n revert MulticallTarget__UndeterminedRevert();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// contracts/libs/UniversalToken.sol\n\nlibrary UniversalTokenLib {\n using SafeERC20 for IERC20;\n\n address internal constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Transfers tokens to the given account. Reverts if transfer is not successful.\n /// @dev This might trigger fallback, if ETH is transferred to the contract.\n /// Make sure this can not lead to reentrancy attacks.\n function universalTransfer(address token, address to, uint256 value) internal {\n // Don't do anything, if need to send tokens to this address\n if (to == address(this)) return;\n // Don't do anything, if trying to send zero value\n if (value == 0) return;\n if (token == ETH_ADDRESS) {\n /// @dev Note: this can potentially lead to executing code in `to`.\n // solhint-disable-next-line avoid-low-level-calls\n (bool success,) = to.call{value: value}(\"\");\n require(success, \"ETH transfer failed\");\n } else {\n IERC20(token).safeTransfer(to, value);\n }\n }\n\n /// @notice Issues an infinite allowance to the spender, if the current allowance is insufficient\n /// to spend the given amount.\n function universalApproveInfinity(address token, address spender, uint256 amountToSpend) internal {\n // ETH Chad doesn't require your approval\n if (token == ETH_ADDRESS) return;\n // No-op if allowance is already sufficient\n uint256 allowance = IERC20(token).allowance(address(this), spender);\n if (allowance \u003e= amountToSpend) return;\n // Otherwise, reset approval to 0 and set to max allowance\n if (allowance \u003e 0) IERC20(token).safeDecreaseAllowance(spender, allowance);\n IERC20(token).safeIncreaseAllowance(spender, type(uint256).max);\n }\n\n /// @notice Returns the balance of the given token (or native ETH) for the given account.\n function universalBalanceOf(address token, address account) internal view returns (uint256) {\n if (token == ETH_ADDRESS) {\n return account.balance;\n } else {\n return IERC20(token).balanceOf(account);\n }\n }\n\n /// @dev Checks that token is a contract and not ETH_ADDRESS.\n function assertIsContract(address token) internal view {\n // Check that ETH_ADDRESS was not used (in case this is a predeploy on any of the chains)\n if (token == UniversalTokenLib.ETH_ADDRESS) revert TokenNotContract();\n // Check that token is not an EOA\n if (token.code.length == 0) revert TokenNotContract();\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/Admin.sol\n\ncontract Admin is IAdmin, AccessControlEnumerable {\n using UniversalTokenLib for address;\n\n bytes32 public constant RELAYER_ROLE = keccak256(\"RELAYER_ROLE\");\n bytes32 public constant REFUNDER_ROLE = keccak256(\"REFUNDER_ROLE\");\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n uint256 public constant FEE_BPS = 1e6;\n uint256 public constant FEE_RATE_MAX = 0.01e6; // max 1% on origin amount\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Chain gas amount to forward as rebate if requested\n uint256 public chainGasAmount;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n }\n\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n require(newFeeRate \u003c= FEE_RATE_MAX, \"newFeeRate \u003e max\");\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n token.universalTransfer(recipient, feeAmount);\n emit FeesSwept(token, recipient, feeAmount);\n }\n\n function setChainGasAmount(uint256 newChainGasAmount) external onlyRole(GOVERNOR_ROLE) {\n uint256 oldChainGasAmount = chainGasAmount;\n chainGasAmount = newChainGasAmount;\n emit ChainGasAmountUpdated(oldChainGasAmount, newChainGasAmount);\n }\n}\n\n// contracts/FastBridge.sol\n\ncontract FastBridge is IFastBridge, MulticallTarget, Admin {\n using SafeERC20 for IERC20;\n using UniversalTokenLib for address;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Delay for a transaction after which it could be permisionlessly refunded\n uint256 public constant REFUND_DELAY = 7 days;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeStatus) public bridgeStatuses;\n /// @notice Proof of relayed bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeProof) public bridgeProofs;\n /// @notice Whether bridge has been relayed on destination chain\n mapping(bytes32 =\u003e bool) public bridgeRelays;\n\n /// @dev to prevent replays\n uint256 public nonce;\n // @dev the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @notice Pulls a requested token from the user to the requested recipient.\n /// @dev Be careful of re-entrancy issues when msg.value \u003e 0 and recipient != address(this)\n function _pullToken(address recipient, address token, uint256 amount) internal returns (uint256 amountPulled) {\n if (token != UniversalTokenLib.ETH_ADDRESS) {\n token.assertIsContract();\n // Record token balance before transfer\n amountPulled = IERC20(token).balanceOf(recipient);\n // Token needs to be pulled only if msg.value is zero\n // This way user can specify WETH as the origin asset\n IERC20(token).safeTransferFrom(msg.sender, recipient, amount);\n // Use the difference between the recorded balance and the current balance as the amountPulled\n amountPulled = IERC20(token).balanceOf(recipient) - amountPulled;\n } else {\n // Otherwise, we need to check that ETH amount matches msg.value\n if (amount != msg.value) revert MsgValueIncorrect();\n // Transfer value to recipient if not this address\n if (recipient != address(this)) token.universalTransfer(recipient, amount);\n // We will forward msg.value in the external call later, if recipient is not this contract\n amountPulled = msg.value;\n }\n }\n\n /// @inheritdoc IFastBridge\n function getBridgeTransaction(bytes memory request) public pure returns (BridgeTransaction memory) {\n return abi.decode(request, (BridgeTransaction));\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n // check bridge params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n\n // transfer tokens to bridge contract\n // @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _pullToken(address(this), params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n\n // set status to requested\n bytes memory request = abi.encode(\n BridgeTransaction({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n sendChainGas: params.sendChainGas,\n deadline: params.deadline,\n nonce: nonce++ // increment nonce on every bridge\n })\n );\n bytes32 transactionId = keccak256(request);\n bridgeStatuses[transactionId] = BridgeStatus.REQUESTED;\n\n emit BridgeRequested(\n transactionId,\n params.sender,\n request,\n params.dstChainId,\n params.originToken,\n params.destToken,\n originAmount,\n params.destAmount,\n params.sendChainGas\n );\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes memory request) external payable onlyRole(RELAYER_ROLE) {\n bytes32 transactionId = keccak256(request);\n BridgeTransaction memory transaction = getBridgeTransaction(request);\n if (transaction.destChainId != uint32(block.chainid)) revert ChainIncorrect();\n\n // check haven't exceeded deadline for relay to happen\n if (block.timestamp \u003e transaction.deadline) revert DeadlineExceeded();\n\n // mark bridge transaction as relayed\n if (bridgeRelays[transactionId]) revert TransactionRelayed();\n bridgeRelays[transactionId] = true;\n\n // transfer tokens to recipient on destination chain and gas rebate if requested\n address to = transaction.destRecipient;\n address token = transaction.destToken;\n uint256 amount = transaction.destAmount;\n\n uint256 rebate = chainGasAmount;\n if (!transaction.sendChainGas) {\n // forward erc20\n rebate = 0;\n _pullToken(to, token, amount);\n } else if (token == UniversalTokenLib.ETH_ADDRESS) {\n // lump in gas rebate into amount in native gas token\n _pullToken(to, token, amount + rebate);\n } else {\n // forward erc20 then forward gas rebate in native gas token\n _pullToken(to, token, amount);\n _pullToken(to, UniversalTokenLib.ETH_ADDRESS, rebate);\n }\n\n emit BridgeRelayed(\n transactionId,\n msg.sender,\n to,\n transaction.originChainId,\n transaction.originToken,\n transaction.destToken,\n transaction.originAmount,\n transaction.destAmount,\n rebate\n );\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes memory request, bytes32 destTxHash) external onlyRole(RELAYER_ROLE) {\n bytes32 transactionId = keccak256(request);\n // update bridge tx status given proof provided\n if (bridgeStatuses[transactionId] != BridgeStatus.REQUESTED) revert StatusIncorrect();\n bridgeStatuses[transactionId] = BridgeStatus.RELAYER_PROVED;\n bridgeProofs[transactionId] = BridgeProof({timestamp: uint96(block.timestamp), relayer: msg.sender}); // overflow ok\n\n emit BridgeProofProvided(transactionId, msg.sender, destTxHash);\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint96(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint96).max but\n /// proof.timestamp \u003c type(uint96).max via unchecked statement\n /// @param proof The bridge proof\n /// @return delta Time delta since proof submitted\n function _timeSince(BridgeProof memory proof) internal view returns (uint256 delta) {\n unchecked {\n delta = uint96(block.timestamp) - proof.timestamp;\n }\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n if (bridgeStatuses[transactionId] != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n BridgeProof memory proof = bridgeProofs[transactionId];\n if (proof.relayer != relayer) revert SenderIncorrect();\n return _timeSince(proof) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes memory request, address to) external onlyRole(RELAYER_ROLE) {\n bytes32 transactionId = keccak256(request);\n BridgeTransaction memory transaction = getBridgeTransaction(request);\n\n // update bridge tx status if able to claim origin collateral\n if (bridgeStatuses[transactionId] != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n\n BridgeProof memory proof = bridgeProofs[transactionId];\n if (proof.relayer != msg.sender) revert SenderIncorrect();\n if (_timeSince(proof) \u003c= DISPUTE_PERIOD) revert DisputePeriodNotPassed();\n\n bridgeStatuses[transactionId] = BridgeStatus.RELAYER_CLAIMED;\n\n // update protocol fees if origin fee amount exists\n if (transaction.originFeeAmount \u003e 0) protocolFees[transaction.originToken] += transaction.originFeeAmount;\n\n // transfer origin collateral less fee to specified address\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositClaimed(transactionId, msg.sender, to, token, amount);\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n if (bridgeStatuses[transactionId] != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(bridgeProofs[transactionId]) \u003e DISPUTE_PERIOD) revert DisputePeriodPassed();\n\n // @dev relayer gets slashed effectively if dest relay has gone thru\n bridgeStatuses[transactionId] = BridgeStatus.REQUESTED;\n delete bridgeProofs[transactionId];\n\n emit BridgeProofDisputed(transactionId, msg.sender);\n }\n\n /// @inheritdoc IFastBridge\n function refund(bytes memory request) external {\n bytes32 transactionId = keccak256(request);\n BridgeTransaction memory transaction = getBridgeTransaction(request);\n\n if (hasRole(REFUNDER_ROLE, msg.sender)) {\n // Refunder can refund if deadline has passed\n if (block.timestamp \u003c= transaction.deadline) revert DeadlineNotExceeded();\n } else {\n // Permissionless refund is allowed after REFUND_DELAY\n if (block.timestamp \u003c= transaction.deadline + REFUND_DELAY) revert DeadlineNotExceeded();\n }\n\n // set status to refunded if still in requested state\n if (bridgeStatuses[transactionId] != BridgeStatus.REQUESTED) revert StatusIncorrect();\n bridgeStatuses[transactionId] = BridgeStatus.REFUNDED;\n\n // transfer origin collateral back to original sender\n address to = transaction.originSender;\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount + transaction.originFeeAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n }\n}\n\n// test/FastBridgeMock.sol\n\ncontract FastBridgeMock is IFastBridge, Admin {\n // @dev the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @dev to prevent replays\n uint256 public nonce;\n\n /// @notice We include an empty \"test\" function so that this contract does not appear in the coverage report.\n function testFastBridgeMock() external {}\n\n function getBridgeTransaction(bytes memory request) public pure returns (BridgeTransaction memory) {\n return abi.decode(request, (BridgeTransaction));\n }\n\n // used for testing in go.\n // see: https://ethereum.stackexchange.com/questions/21155/how-to-expose-enum-in-solidity-contract\n // make sure to update fastbridge/status.go if this changes\n // or underliyng enum changes.\n //\n // TODO: a foundry test should be added to ensure this is always in sync.\n function getEnumKeyByValue(FastBridge.BridgeStatus keyValue) public pure returns (string memory) {\n if (FastBridge.BridgeStatus.NULL == keyValue) return \"NULL\";\n if (FastBridge.BridgeStatus.REQUESTED == keyValue) return \"REQUESTED\";\n if (FastBridge.BridgeStatus.RELAYER_PROVED == keyValue) return \"RELAYER_PROVED\";\n if (FastBridge.BridgeStatus.RELAYER_CLAIMED == keyValue) return \"RELAYER_CLAIMED\";\n if (FastBridge.BridgeStatus.REFUNDED == keyValue) return \"REFUNDED\";\n return \"\";\n }\n\n function mockBridgeRequest(bytes32 transactionId, address sender, BridgeParams memory params) external {\n sender;\n uint256 originFeeAmount = (params.originAmount * protocolFeeRate) / FEE_BPS;\n params.originAmount -= originFeeAmount;\n\n bytes memory request = abi.encode(\n BridgeTransaction({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: params.originAmount, // includes relayer fee\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n sendChainGas: params.sendChainGas,\n deadline: params.deadline,\n nonce: nonce++ // increment nonce on every bridge\n })\n );\n\n emit BridgeRequested(\n transactionId,\n params.sender,\n request,\n params.dstChainId,\n params.originToken,\n params.destToken,\n params.originAmount,\n params.destAmount,\n params.sendChainGas\n );\n }\n\n function mockBridgeRequestRaw(bytes32 transactionId, address sender, bytes memory request) external {\n sender;\n BridgeTransaction memory transaction = getBridgeTransaction(request);\n emit BridgeRequested(\n transactionId,\n transaction.originSender,\n request,\n transaction.destChainId,\n transaction.originToken,\n transaction.destToken,\n transaction.originAmount,\n transaction.destAmount,\n transaction.sendChainGas\n );\n }\n\n function mockBridgeRelayer(\n bytes32 transactionId,\n address relayer,\n address to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n )\n external\n {\n emit BridgeRelayed(\n transactionId, relayer, to, originChainId, originToken, destToken, originAmount, destAmount, chainGasAmount\n );\n }\n\n function bridge(BridgeParams memory) external payable {\n revert(\"not implemented\");\n }\n\n function relay(bytes memory) external payable {\n revert(\"not implemented\");\n }\n\n function prove(bytes memory, bytes32) external pure {\n revert(\"not implemented\");\n }\n\n function canClaim(bytes32, address) external pure returns (bool) {\n revert(\"not implemented\");\n }\n\n function claim(bytes memory, address) external pure {\n revert(\"not implemented\");\n }\n\n function dispute(bytes32) external pure {\n revert(\"not implemented\");\n }\n\n function refund(bytes memory) external pure {\n revert(\"not implemented\");\n }\n}\n","language":"Solidity","languageVersion":"0.8.20","compilerVersion":"0.8.20","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"","srcMapRuntime":"","abiDefinition":[],"userDoc":{"kind":"user","methods":{},"version":1},"developerDoc":{"details":"Provides information about the current execution context, including the sender of the transaction and its data. While these are generally available via msg.sender and msg.data, they should not be accessed in such a direct manner, since when dealing with meta-transactions the account sending and paying for execution may not be the actual sender (as far as an application is concerned). This contract is only required for intermediate, library-like contracts.","kind":"dev","methods":{},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.20+commit.a1b79de6\"},\"language\":\"Solidity\",\"output\":{\"abi\":[],\"devdoc\":{\"details\":\"Provides information about the current execution context, including the sender of the transaction and its data. While these are generally available via msg.sender and msg.data, they should not be accessed in such a direct manner, since when dealing with meta-transactions the account sending and paying for execution may not be the actual sender (as far as an application is concerned). This contract is only required for intermediate, library-like contracts.\",\"kind\":\"dev\",\"methods\":{},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeMock.sol\":\"Context\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeMock.sol\":{\"keccak256\":\"0xf2751f52f8216801d500da7464ad01f3c23a8286e155e2dcba6d21d6e7fd95a0\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://85d2edab24ebe321043d2b88038437e8f443a0ef26fa2139c72dcc2bc7fbc602\",\"dweb:/ipfs/QmcULiFPFJzFDT4aupVSDreXz8uHxcABb5nxpAG4zYzfNN\"]}},\"version\":1}"},"hashes":{}},"solidity/FastBridgeMock.sol:ERC165":{"code":"0x","runtime-code":"0x","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.20 ^0.8.20 ^0.8.4;\n\n// contracts/interfaces/IAdmin.sol\n\ninterface IAdmin {\n // ============ Events ============\n\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n event ChainGasAmountUpdated(uint256 oldChainGasAmount, uint256 newChainGasAmount);\n\n // ============ Methods ============\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n\n function setChainGasAmount(uint256 newChainGasAmount) external;\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IMulticallTarget.sol\n\n/// @notice Interface for a contract that can be called multiple times by the same caller. Inspired by MulticallV3:\n/// https://github.com/mds1/multicall/blob/master/src/Multicall3.sol\ninterface IMulticallTarget {\n struct Result {\n bool success;\n bytes returnData;\n }\n\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external;\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results);\n}\n\n// contracts/libs/Errors.sol\n\nerror DeadlineExceeded();\nerror DeadlineNotExceeded();\nerror DeadlineTooShort();\nerror InsufficientOutputAmount();\n\nerror MsgValueIncorrect();\nerror PoolNotFound();\nerror TokenAddressMismatch();\nerror TokenNotContract();\nerror TokenNotETH();\nerror TokensIdentical();\n\nerror ChainIncorrect();\nerror AmountIncorrect();\nerror ZeroAddress();\n\nerror DisputePeriodNotPassed();\nerror DisputePeriodPassed();\nerror SenderIncorrect();\nerror StatusIncorrect();\nerror TransactionIdIncorrect();\nerror TransactionRelayed();\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// contracts/utils/MulticallTarget.sol\n\n// solhint-disable avoid-low-level-calls\n/// @notice Template for a contract that supports batched calls (preserving the msg.sender).\n/// Only calls with zero msg.value could be batched.\nabstract contract MulticallTarget is IMulticallTarget {\n error MulticallTarget__UndeterminedRevert();\n\n /// @notice Perform a batched call to this contract, preserving the msg.sender.\n /// The return data from each call is discarded.\n /// @dev The method is non-payable, so only calls with `msg.value == 0` could be batched.\n /// It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag.\n /// Otherwise, the whole batch call will be reverted with the original revert reason.\n /// @param data List of abi-encoded calldata for the calls to perform.\n /// @param ignoreReverts Whether to ignore the revert errors from the calls.\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external {\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\n if (!success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(result);\n }\n }\n }\n\n /// @notice Perform a batched call to this contract, preserving the msg.sender.\n /// The return data from each call is preserved.\n /// @dev The method is non-payable, so only calls with `msg.value == 0` could be batched.\n /// It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag.\n /// Otherwise, the whole batch call will be reverted with the original revert reason.\n /// @param data List of abi-encoded calldata for the calls to perform.\n /// @param ignoreReverts Whether to ignore the revert errors from the calls.\n /// @return results List of results from the calls: `(success, returnData)`.\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results)\n {\n results = new Result[](data.length);\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (results[i].success, results[i].returnData) = address(this).delegatecall(data[i]);\n if (!results[i].success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(results[i].returnData);\n }\n }\n }\n\n /// @dev Bubbles the revert message from the underlying call.\n /// Note: preserves the same custom error or revert string, if one was used.\n /// Source: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v5.0.2/contracts/utils/Address.sol#L143-L158\n function _bubbleRevert(bytes memory returnData) internal pure {\n // Look for revert reason and bubble it up if present\n if (returnData.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n // solhint-disable-next-line no-inline-assembly\n assembly {\n let returndata_size := mload(returnData)\n revert(add(32, returnData), returndata_size)\n }\n } else {\n revert MulticallTarget__UndeterminedRevert();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// contracts/libs/UniversalToken.sol\n\nlibrary UniversalTokenLib {\n using SafeERC20 for IERC20;\n\n address internal constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Transfers tokens to the given account. Reverts if transfer is not successful.\n /// @dev This might trigger fallback, if ETH is transferred to the contract.\n /// Make sure this can not lead to reentrancy attacks.\n function universalTransfer(address token, address to, uint256 value) internal {\n // Don't do anything, if need to send tokens to this address\n if (to == address(this)) return;\n // Don't do anything, if trying to send zero value\n if (value == 0) return;\n if (token == ETH_ADDRESS) {\n /// @dev Note: this can potentially lead to executing code in `to`.\n // solhint-disable-next-line avoid-low-level-calls\n (bool success,) = to.call{value: value}(\"\");\n require(success, \"ETH transfer failed\");\n } else {\n IERC20(token).safeTransfer(to, value);\n }\n }\n\n /// @notice Issues an infinite allowance to the spender, if the current allowance is insufficient\n /// to spend the given amount.\n function universalApproveInfinity(address token, address spender, uint256 amountToSpend) internal {\n // ETH Chad doesn't require your approval\n if (token == ETH_ADDRESS) return;\n // No-op if allowance is already sufficient\n uint256 allowance = IERC20(token).allowance(address(this), spender);\n if (allowance \u003e= amountToSpend) return;\n // Otherwise, reset approval to 0 and set to max allowance\n if (allowance \u003e 0) IERC20(token).safeDecreaseAllowance(spender, allowance);\n IERC20(token).safeIncreaseAllowance(spender, type(uint256).max);\n }\n\n /// @notice Returns the balance of the given token (or native ETH) for the given account.\n function universalBalanceOf(address token, address account) internal view returns (uint256) {\n if (token == ETH_ADDRESS) {\n return account.balance;\n } else {\n return IERC20(token).balanceOf(account);\n }\n }\n\n /// @dev Checks that token is a contract and not ETH_ADDRESS.\n function assertIsContract(address token) internal view {\n // Check that ETH_ADDRESS was not used (in case this is a predeploy on any of the chains)\n if (token == UniversalTokenLib.ETH_ADDRESS) revert TokenNotContract();\n // Check that token is not an EOA\n if (token.code.length == 0) revert TokenNotContract();\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/Admin.sol\n\ncontract Admin is IAdmin, AccessControlEnumerable {\n using UniversalTokenLib for address;\n\n bytes32 public constant RELAYER_ROLE = keccak256(\"RELAYER_ROLE\");\n bytes32 public constant REFUNDER_ROLE = keccak256(\"REFUNDER_ROLE\");\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n uint256 public constant FEE_BPS = 1e6;\n uint256 public constant FEE_RATE_MAX = 0.01e6; // max 1% on origin amount\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Chain gas amount to forward as rebate if requested\n uint256 public chainGasAmount;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n }\n\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n require(newFeeRate \u003c= FEE_RATE_MAX, \"newFeeRate \u003e max\");\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n token.universalTransfer(recipient, feeAmount);\n emit FeesSwept(token, recipient, feeAmount);\n }\n\n function setChainGasAmount(uint256 newChainGasAmount) external onlyRole(GOVERNOR_ROLE) {\n uint256 oldChainGasAmount = chainGasAmount;\n chainGasAmount = newChainGasAmount;\n emit ChainGasAmountUpdated(oldChainGasAmount, newChainGasAmount);\n }\n}\n\n// contracts/FastBridge.sol\n\ncontract FastBridge is IFastBridge, MulticallTarget, Admin {\n using SafeERC20 for IERC20;\n using UniversalTokenLib for address;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Delay for a transaction after which it could be permisionlessly refunded\n uint256 public constant REFUND_DELAY = 7 days;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeStatus) public bridgeStatuses;\n /// @notice Proof of relayed bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeProof) public bridgeProofs;\n /// @notice Whether bridge has been relayed on destination chain\n mapping(bytes32 =\u003e bool) public bridgeRelays;\n\n /// @dev to prevent replays\n uint256 public nonce;\n // @dev the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @notice Pulls a requested token from the user to the requested recipient.\n /// @dev Be careful of re-entrancy issues when msg.value \u003e 0 and recipient != address(this)\n function _pullToken(address recipient, address token, uint256 amount) internal returns (uint256 amountPulled) {\n if (token != UniversalTokenLib.ETH_ADDRESS) {\n token.assertIsContract();\n // Record token balance before transfer\n amountPulled = IERC20(token).balanceOf(recipient);\n // Token needs to be pulled only if msg.value is zero\n // This way user can specify WETH as the origin asset\n IERC20(token).safeTransferFrom(msg.sender, recipient, amount);\n // Use the difference between the recorded balance and the current balance as the amountPulled\n amountPulled = IERC20(token).balanceOf(recipient) - amountPulled;\n } else {\n // Otherwise, we need to check that ETH amount matches msg.value\n if (amount != msg.value) revert MsgValueIncorrect();\n // Transfer value to recipient if not this address\n if (recipient != address(this)) token.universalTransfer(recipient, amount);\n // We will forward msg.value in the external call later, if recipient is not this contract\n amountPulled = msg.value;\n }\n }\n\n /// @inheritdoc IFastBridge\n function getBridgeTransaction(bytes memory request) public pure returns (BridgeTransaction memory) {\n return abi.decode(request, (BridgeTransaction));\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n // check bridge params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n\n // transfer tokens to bridge contract\n // @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _pullToken(address(this), params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n\n // set status to requested\n bytes memory request = abi.encode(\n BridgeTransaction({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n sendChainGas: params.sendChainGas,\n deadline: params.deadline,\n nonce: nonce++ // increment nonce on every bridge\n })\n );\n bytes32 transactionId = keccak256(request);\n bridgeStatuses[transactionId] = BridgeStatus.REQUESTED;\n\n emit BridgeRequested(\n transactionId,\n params.sender,\n request,\n params.dstChainId,\n params.originToken,\n params.destToken,\n originAmount,\n params.destAmount,\n params.sendChainGas\n );\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes memory request) external payable onlyRole(RELAYER_ROLE) {\n bytes32 transactionId = keccak256(request);\n BridgeTransaction memory transaction = getBridgeTransaction(request);\n if (transaction.destChainId != uint32(block.chainid)) revert ChainIncorrect();\n\n // check haven't exceeded deadline for relay to happen\n if (block.timestamp \u003e transaction.deadline) revert DeadlineExceeded();\n\n // mark bridge transaction as relayed\n if (bridgeRelays[transactionId]) revert TransactionRelayed();\n bridgeRelays[transactionId] = true;\n\n // transfer tokens to recipient on destination chain and gas rebate if requested\n address to = transaction.destRecipient;\n address token = transaction.destToken;\n uint256 amount = transaction.destAmount;\n\n uint256 rebate = chainGasAmount;\n if (!transaction.sendChainGas) {\n // forward erc20\n rebate = 0;\n _pullToken(to, token, amount);\n } else if (token == UniversalTokenLib.ETH_ADDRESS) {\n // lump in gas rebate into amount in native gas token\n _pullToken(to, token, amount + rebate);\n } else {\n // forward erc20 then forward gas rebate in native gas token\n _pullToken(to, token, amount);\n _pullToken(to, UniversalTokenLib.ETH_ADDRESS, rebate);\n }\n\n emit BridgeRelayed(\n transactionId,\n msg.sender,\n to,\n transaction.originChainId,\n transaction.originToken,\n transaction.destToken,\n transaction.originAmount,\n transaction.destAmount,\n rebate\n );\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes memory request, bytes32 destTxHash) external onlyRole(RELAYER_ROLE) {\n bytes32 transactionId = keccak256(request);\n // update bridge tx status given proof provided\n if (bridgeStatuses[transactionId] != BridgeStatus.REQUESTED) revert StatusIncorrect();\n bridgeStatuses[transactionId] = BridgeStatus.RELAYER_PROVED;\n bridgeProofs[transactionId] = BridgeProof({timestamp: uint96(block.timestamp), relayer: msg.sender}); // overflow ok\n\n emit BridgeProofProvided(transactionId, msg.sender, destTxHash);\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint96(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint96).max but\n /// proof.timestamp \u003c type(uint96).max via unchecked statement\n /// @param proof The bridge proof\n /// @return delta Time delta since proof submitted\n function _timeSince(BridgeProof memory proof) internal view returns (uint256 delta) {\n unchecked {\n delta = uint96(block.timestamp) - proof.timestamp;\n }\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n if (bridgeStatuses[transactionId] != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n BridgeProof memory proof = bridgeProofs[transactionId];\n if (proof.relayer != relayer) revert SenderIncorrect();\n return _timeSince(proof) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes memory request, address to) external onlyRole(RELAYER_ROLE) {\n bytes32 transactionId = keccak256(request);\n BridgeTransaction memory transaction = getBridgeTransaction(request);\n\n // update bridge tx status if able to claim origin collateral\n if (bridgeStatuses[transactionId] != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n\n BridgeProof memory proof = bridgeProofs[transactionId];\n if (proof.relayer != msg.sender) revert SenderIncorrect();\n if (_timeSince(proof) \u003c= DISPUTE_PERIOD) revert DisputePeriodNotPassed();\n\n bridgeStatuses[transactionId] = BridgeStatus.RELAYER_CLAIMED;\n\n // update protocol fees if origin fee amount exists\n if (transaction.originFeeAmount \u003e 0) protocolFees[transaction.originToken] += transaction.originFeeAmount;\n\n // transfer origin collateral less fee to specified address\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositClaimed(transactionId, msg.sender, to, token, amount);\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n if (bridgeStatuses[transactionId] != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(bridgeProofs[transactionId]) \u003e DISPUTE_PERIOD) revert DisputePeriodPassed();\n\n // @dev relayer gets slashed effectively if dest relay has gone thru\n bridgeStatuses[transactionId] = BridgeStatus.REQUESTED;\n delete bridgeProofs[transactionId];\n\n emit BridgeProofDisputed(transactionId, msg.sender);\n }\n\n /// @inheritdoc IFastBridge\n function refund(bytes memory request) external {\n bytes32 transactionId = keccak256(request);\n BridgeTransaction memory transaction = getBridgeTransaction(request);\n\n if (hasRole(REFUNDER_ROLE, msg.sender)) {\n // Refunder can refund if deadline has passed\n if (block.timestamp \u003c= transaction.deadline) revert DeadlineNotExceeded();\n } else {\n // Permissionless refund is allowed after REFUND_DELAY\n if (block.timestamp \u003c= transaction.deadline + REFUND_DELAY) revert DeadlineNotExceeded();\n }\n\n // set status to refunded if still in requested state\n if (bridgeStatuses[transactionId] != BridgeStatus.REQUESTED) revert StatusIncorrect();\n bridgeStatuses[transactionId] = BridgeStatus.REFUNDED;\n\n // transfer origin collateral back to original sender\n address to = transaction.originSender;\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount + transaction.originFeeAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n }\n}\n\n// test/FastBridgeMock.sol\n\ncontract FastBridgeMock is IFastBridge, Admin {\n // @dev the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @dev to prevent replays\n uint256 public nonce;\n\n /// @notice We include an empty \"test\" function so that this contract does not appear in the coverage report.\n function testFastBridgeMock() external {}\n\n function getBridgeTransaction(bytes memory request) public pure returns (BridgeTransaction memory) {\n return abi.decode(request, (BridgeTransaction));\n }\n\n // used for testing in go.\n // see: https://ethereum.stackexchange.com/questions/21155/how-to-expose-enum-in-solidity-contract\n // make sure to update fastbridge/status.go if this changes\n // or underliyng enum changes.\n //\n // TODO: a foundry test should be added to ensure this is always in sync.\n function getEnumKeyByValue(FastBridge.BridgeStatus keyValue) public pure returns (string memory) {\n if (FastBridge.BridgeStatus.NULL == keyValue) return \"NULL\";\n if (FastBridge.BridgeStatus.REQUESTED == keyValue) return \"REQUESTED\";\n if (FastBridge.BridgeStatus.RELAYER_PROVED == keyValue) return \"RELAYER_PROVED\";\n if (FastBridge.BridgeStatus.RELAYER_CLAIMED == keyValue) return \"RELAYER_CLAIMED\";\n if (FastBridge.BridgeStatus.REFUNDED == keyValue) return \"REFUNDED\";\n return \"\";\n }\n\n function mockBridgeRequest(bytes32 transactionId, address sender, BridgeParams memory params) external {\n sender;\n uint256 originFeeAmount = (params.originAmount * protocolFeeRate) / FEE_BPS;\n params.originAmount -= originFeeAmount;\n\n bytes memory request = abi.encode(\n BridgeTransaction({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: params.originAmount, // includes relayer fee\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n sendChainGas: params.sendChainGas,\n deadline: params.deadline,\n nonce: nonce++ // increment nonce on every bridge\n })\n );\n\n emit BridgeRequested(\n transactionId,\n params.sender,\n request,\n params.dstChainId,\n params.originToken,\n params.destToken,\n params.originAmount,\n params.destAmount,\n params.sendChainGas\n );\n }\n\n function mockBridgeRequestRaw(bytes32 transactionId, address sender, bytes memory request) external {\n sender;\n BridgeTransaction memory transaction = getBridgeTransaction(request);\n emit BridgeRequested(\n transactionId,\n transaction.originSender,\n request,\n transaction.destChainId,\n transaction.originToken,\n transaction.destToken,\n transaction.originAmount,\n transaction.destAmount,\n transaction.sendChainGas\n );\n }\n\n function mockBridgeRelayer(\n bytes32 transactionId,\n address relayer,\n address to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n )\n external\n {\n emit BridgeRelayed(\n transactionId, relayer, to, originChainId, originToken, destToken, originAmount, destAmount, chainGasAmount\n );\n }\n\n function bridge(BridgeParams memory) external payable {\n revert(\"not implemented\");\n }\n\n function relay(bytes memory) external payable {\n revert(\"not implemented\");\n }\n\n function prove(bytes memory, bytes32) external pure {\n revert(\"not implemented\");\n }\n\n function canClaim(bytes32, address) external pure returns (bool) {\n revert(\"not implemented\");\n }\n\n function claim(bytes memory, address) external pure {\n revert(\"not implemented\");\n }\n\n function dispute(bytes32) external pure {\n revert(\"not implemented\");\n }\n\n function refund(bytes memory) external pure {\n revert(\"not implemented\");\n }\n}\n","language":"Solidity","languageVersion":"0.8.20","compilerVersion":"0.8.20","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"","srcMapRuntime":"","abiDefinition":[{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"}],"userDoc":{"kind":"user","methods":{},"version":1},"developerDoc":{"details":"Implementation of the {IERC165} interface. Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check for the additional interface id that will be supported. For example: ```solidity function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId); } ```","kind":"dev","methods":{"supportsInterface(bytes4)":{"details":"See {IERC165-supportsInterface}."}},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.20+commit.a1b79de6\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"bytes4\",\"name\":\"interfaceId\",\"type\":\"bytes4\"}],\"name\":\"supportsInterface\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"}],\"devdoc\":{\"details\":\"Implementation of the {IERC165} interface. Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check for the additional interface id that will be supported. For example: ```solidity function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId); } ```\",\"kind\":\"dev\",\"methods\":{\"supportsInterface(bytes4)\":{\"details\":\"See {IERC165-supportsInterface}.\"}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeMock.sol\":\"ERC165\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeMock.sol\":{\"keccak256\":\"0xf2751f52f8216801d500da7464ad01f3c23a8286e155e2dcba6d21d6e7fd95a0\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://85d2edab24ebe321043d2b88038437e8f443a0ef26fa2139c72dcc2bc7fbc602\",\"dweb:/ipfs/QmcULiFPFJzFDT4aupVSDreXz8uHxcABb5nxpAG4zYzfNN\"]}},\"version\":1}"},"hashes":{"supportsInterface(bytes4)":"01ffc9a7"}},"solidity/FastBridgeMock.sol:EnumerableSet":{"code":"0x60566037600b82828239805160001a607314602a57634e487b7160e01b600052600060045260246000fd5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600080fdfea26469706673582212200a382fa821943728900498ca83a11a0bb08c358f5c346e82519f2d9e93b2c4cb64736f6c63430008140033","runtime-code":"0x73000000000000000000000000000000000000000030146080604052600080fdfea26469706673582212200a382fa821943728900498ca83a11a0bb08c358f5c346e82519f2d9e93b2c4cb64736f6c63430008140033","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.20 ^0.8.20 ^0.8.4;\n\n// contracts/interfaces/IAdmin.sol\n\ninterface IAdmin {\n // ============ Events ============\n\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n event ChainGasAmountUpdated(uint256 oldChainGasAmount, uint256 newChainGasAmount);\n\n // ============ Methods ============\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n\n function setChainGasAmount(uint256 newChainGasAmount) external;\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IMulticallTarget.sol\n\n/// @notice Interface for a contract that can be called multiple times by the same caller. Inspired by MulticallV3:\n/// https://github.com/mds1/multicall/blob/master/src/Multicall3.sol\ninterface IMulticallTarget {\n struct Result {\n bool success;\n bytes returnData;\n }\n\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external;\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results);\n}\n\n// contracts/libs/Errors.sol\n\nerror DeadlineExceeded();\nerror DeadlineNotExceeded();\nerror DeadlineTooShort();\nerror InsufficientOutputAmount();\n\nerror MsgValueIncorrect();\nerror PoolNotFound();\nerror TokenAddressMismatch();\nerror TokenNotContract();\nerror TokenNotETH();\nerror TokensIdentical();\n\nerror ChainIncorrect();\nerror AmountIncorrect();\nerror ZeroAddress();\n\nerror DisputePeriodNotPassed();\nerror DisputePeriodPassed();\nerror SenderIncorrect();\nerror StatusIncorrect();\nerror TransactionIdIncorrect();\nerror TransactionRelayed();\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// contracts/utils/MulticallTarget.sol\n\n// solhint-disable avoid-low-level-calls\n/// @notice Template for a contract that supports batched calls (preserving the msg.sender).\n/// Only calls with zero msg.value could be batched.\nabstract contract MulticallTarget is IMulticallTarget {\n error MulticallTarget__UndeterminedRevert();\n\n /// @notice Perform a batched call to this contract, preserving the msg.sender.\n /// The return data from each call is discarded.\n /// @dev The method is non-payable, so only calls with `msg.value == 0` could be batched.\n /// It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag.\n /// Otherwise, the whole batch call will be reverted with the original revert reason.\n /// @param data List of abi-encoded calldata for the calls to perform.\n /// @param ignoreReverts Whether to ignore the revert errors from the calls.\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external {\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\n if (!success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(result);\n }\n }\n }\n\n /// @notice Perform a batched call to this contract, preserving the msg.sender.\n /// The return data from each call is preserved.\n /// @dev The method is non-payable, so only calls with `msg.value == 0` could be batched.\n /// It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag.\n /// Otherwise, the whole batch call will be reverted with the original revert reason.\n /// @param data List of abi-encoded calldata for the calls to perform.\n /// @param ignoreReverts Whether to ignore the revert errors from the calls.\n /// @return results List of results from the calls: `(success, returnData)`.\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results)\n {\n results = new Result[](data.length);\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (results[i].success, results[i].returnData) = address(this).delegatecall(data[i]);\n if (!results[i].success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(results[i].returnData);\n }\n }\n }\n\n /// @dev Bubbles the revert message from the underlying call.\n /// Note: preserves the same custom error or revert string, if one was used.\n /// Source: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v5.0.2/contracts/utils/Address.sol#L143-L158\n function _bubbleRevert(bytes memory returnData) internal pure {\n // Look for revert reason and bubble it up if present\n if (returnData.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n // solhint-disable-next-line no-inline-assembly\n assembly {\n let returndata_size := mload(returnData)\n revert(add(32, returnData), returndata_size)\n }\n } else {\n revert MulticallTarget__UndeterminedRevert();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// contracts/libs/UniversalToken.sol\n\nlibrary UniversalTokenLib {\n using SafeERC20 for IERC20;\n\n address internal constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Transfers tokens to the given account. Reverts if transfer is not successful.\n /// @dev This might trigger fallback, if ETH is transferred to the contract.\n /// Make sure this can not lead to reentrancy attacks.\n function universalTransfer(address token, address to, uint256 value) internal {\n // Don't do anything, if need to send tokens to this address\n if (to == address(this)) return;\n // Don't do anything, if trying to send zero value\n if (value == 0) return;\n if (token == ETH_ADDRESS) {\n /// @dev Note: this can potentially lead to executing code in `to`.\n // solhint-disable-next-line avoid-low-level-calls\n (bool success,) = to.call{value: value}(\"\");\n require(success, \"ETH transfer failed\");\n } else {\n IERC20(token).safeTransfer(to, value);\n }\n }\n\n /// @notice Issues an infinite allowance to the spender, if the current allowance is insufficient\n /// to spend the given amount.\n function universalApproveInfinity(address token, address spender, uint256 amountToSpend) internal {\n // ETH Chad doesn't require your approval\n if (token == ETH_ADDRESS) return;\n // No-op if allowance is already sufficient\n uint256 allowance = IERC20(token).allowance(address(this), spender);\n if (allowance \u003e= amountToSpend) return;\n // Otherwise, reset approval to 0 and set to max allowance\n if (allowance \u003e 0) IERC20(token).safeDecreaseAllowance(spender, allowance);\n IERC20(token).safeIncreaseAllowance(spender, type(uint256).max);\n }\n\n /// @notice Returns the balance of the given token (or native ETH) for the given account.\n function universalBalanceOf(address token, address account) internal view returns (uint256) {\n if (token == ETH_ADDRESS) {\n return account.balance;\n } else {\n return IERC20(token).balanceOf(account);\n }\n }\n\n /// @dev Checks that token is a contract and not ETH_ADDRESS.\n function assertIsContract(address token) internal view {\n // Check that ETH_ADDRESS was not used (in case this is a predeploy on any of the chains)\n if (token == UniversalTokenLib.ETH_ADDRESS) revert TokenNotContract();\n // Check that token is not an EOA\n if (token.code.length == 0) revert TokenNotContract();\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/Admin.sol\n\ncontract Admin is IAdmin, AccessControlEnumerable {\n using UniversalTokenLib for address;\n\n bytes32 public constant RELAYER_ROLE = keccak256(\"RELAYER_ROLE\");\n bytes32 public constant REFUNDER_ROLE = keccak256(\"REFUNDER_ROLE\");\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n uint256 public constant FEE_BPS = 1e6;\n uint256 public constant FEE_RATE_MAX = 0.01e6; // max 1% on origin amount\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Chain gas amount to forward as rebate if requested\n uint256 public chainGasAmount;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n }\n\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n require(newFeeRate \u003c= FEE_RATE_MAX, \"newFeeRate \u003e max\");\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n token.universalTransfer(recipient, feeAmount);\n emit FeesSwept(token, recipient, feeAmount);\n }\n\n function setChainGasAmount(uint256 newChainGasAmount) external onlyRole(GOVERNOR_ROLE) {\n uint256 oldChainGasAmount = chainGasAmount;\n chainGasAmount = newChainGasAmount;\n emit ChainGasAmountUpdated(oldChainGasAmount, newChainGasAmount);\n }\n}\n\n// contracts/FastBridge.sol\n\ncontract FastBridge is IFastBridge, MulticallTarget, Admin {\n using SafeERC20 for IERC20;\n using UniversalTokenLib for address;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Delay for a transaction after which it could be permisionlessly refunded\n uint256 public constant REFUND_DELAY = 7 days;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeStatus) public bridgeStatuses;\n /// @notice Proof of relayed bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeProof) public bridgeProofs;\n /// @notice Whether bridge has been relayed on destination chain\n mapping(bytes32 =\u003e bool) public bridgeRelays;\n\n /// @dev to prevent replays\n uint256 public nonce;\n // @dev the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @notice Pulls a requested token from the user to the requested recipient.\n /// @dev Be careful of re-entrancy issues when msg.value \u003e 0 and recipient != address(this)\n function _pullToken(address recipient, address token, uint256 amount) internal returns (uint256 amountPulled) {\n if (token != UniversalTokenLib.ETH_ADDRESS) {\n token.assertIsContract();\n // Record token balance before transfer\n amountPulled = IERC20(token).balanceOf(recipient);\n // Token needs to be pulled only if msg.value is zero\n // This way user can specify WETH as the origin asset\n IERC20(token).safeTransferFrom(msg.sender, recipient, amount);\n // Use the difference between the recorded balance and the current balance as the amountPulled\n amountPulled = IERC20(token).balanceOf(recipient) - amountPulled;\n } else {\n // Otherwise, we need to check that ETH amount matches msg.value\n if (amount != msg.value) revert MsgValueIncorrect();\n // Transfer value to recipient if not this address\n if (recipient != address(this)) token.universalTransfer(recipient, amount);\n // We will forward msg.value in the external call later, if recipient is not this contract\n amountPulled = msg.value;\n }\n }\n\n /// @inheritdoc IFastBridge\n function getBridgeTransaction(bytes memory request) public pure returns (BridgeTransaction memory) {\n return abi.decode(request, (BridgeTransaction));\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n // check bridge params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n\n // transfer tokens to bridge contract\n // @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _pullToken(address(this), params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n\n // set status to requested\n bytes memory request = abi.encode(\n BridgeTransaction({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n sendChainGas: params.sendChainGas,\n deadline: params.deadline,\n nonce: nonce++ // increment nonce on every bridge\n })\n );\n bytes32 transactionId = keccak256(request);\n bridgeStatuses[transactionId] = BridgeStatus.REQUESTED;\n\n emit BridgeRequested(\n transactionId,\n params.sender,\n request,\n params.dstChainId,\n params.originToken,\n params.destToken,\n originAmount,\n params.destAmount,\n params.sendChainGas\n );\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes memory request) external payable onlyRole(RELAYER_ROLE) {\n bytes32 transactionId = keccak256(request);\n BridgeTransaction memory transaction = getBridgeTransaction(request);\n if (transaction.destChainId != uint32(block.chainid)) revert ChainIncorrect();\n\n // check haven't exceeded deadline for relay to happen\n if (block.timestamp \u003e transaction.deadline) revert DeadlineExceeded();\n\n // mark bridge transaction as relayed\n if (bridgeRelays[transactionId]) revert TransactionRelayed();\n bridgeRelays[transactionId] = true;\n\n // transfer tokens to recipient on destination chain and gas rebate if requested\n address to = transaction.destRecipient;\n address token = transaction.destToken;\n uint256 amount = transaction.destAmount;\n\n uint256 rebate = chainGasAmount;\n if (!transaction.sendChainGas) {\n // forward erc20\n rebate = 0;\n _pullToken(to, token, amount);\n } else if (token == UniversalTokenLib.ETH_ADDRESS) {\n // lump in gas rebate into amount in native gas token\n _pullToken(to, token, amount + rebate);\n } else {\n // forward erc20 then forward gas rebate in native gas token\n _pullToken(to, token, amount);\n _pullToken(to, UniversalTokenLib.ETH_ADDRESS, rebate);\n }\n\n emit BridgeRelayed(\n transactionId,\n msg.sender,\n to,\n transaction.originChainId,\n transaction.originToken,\n transaction.destToken,\n transaction.originAmount,\n transaction.destAmount,\n rebate\n );\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes memory request, bytes32 destTxHash) external onlyRole(RELAYER_ROLE) {\n bytes32 transactionId = keccak256(request);\n // update bridge tx status given proof provided\n if (bridgeStatuses[transactionId] != BridgeStatus.REQUESTED) revert StatusIncorrect();\n bridgeStatuses[transactionId] = BridgeStatus.RELAYER_PROVED;\n bridgeProofs[transactionId] = BridgeProof({timestamp: uint96(block.timestamp), relayer: msg.sender}); // overflow ok\n\n emit BridgeProofProvided(transactionId, msg.sender, destTxHash);\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint96(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint96).max but\n /// proof.timestamp \u003c type(uint96).max via unchecked statement\n /// @param proof The bridge proof\n /// @return delta Time delta since proof submitted\n function _timeSince(BridgeProof memory proof) internal view returns (uint256 delta) {\n unchecked {\n delta = uint96(block.timestamp) - proof.timestamp;\n }\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n if (bridgeStatuses[transactionId] != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n BridgeProof memory proof = bridgeProofs[transactionId];\n if (proof.relayer != relayer) revert SenderIncorrect();\n return _timeSince(proof) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes memory request, address to) external onlyRole(RELAYER_ROLE) {\n bytes32 transactionId = keccak256(request);\n BridgeTransaction memory transaction = getBridgeTransaction(request);\n\n // update bridge tx status if able to claim origin collateral\n if (bridgeStatuses[transactionId] != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n\n BridgeProof memory proof = bridgeProofs[transactionId];\n if (proof.relayer != msg.sender) revert SenderIncorrect();\n if (_timeSince(proof) \u003c= DISPUTE_PERIOD) revert DisputePeriodNotPassed();\n\n bridgeStatuses[transactionId] = BridgeStatus.RELAYER_CLAIMED;\n\n // update protocol fees if origin fee amount exists\n if (transaction.originFeeAmount \u003e 0) protocolFees[transaction.originToken] += transaction.originFeeAmount;\n\n // transfer origin collateral less fee to specified address\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositClaimed(transactionId, msg.sender, to, token, amount);\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n if (bridgeStatuses[transactionId] != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(bridgeProofs[transactionId]) \u003e DISPUTE_PERIOD) revert DisputePeriodPassed();\n\n // @dev relayer gets slashed effectively if dest relay has gone thru\n bridgeStatuses[transactionId] = BridgeStatus.REQUESTED;\n delete bridgeProofs[transactionId];\n\n emit BridgeProofDisputed(transactionId, msg.sender);\n }\n\n /// @inheritdoc IFastBridge\n function refund(bytes memory request) external {\n bytes32 transactionId = keccak256(request);\n BridgeTransaction memory transaction = getBridgeTransaction(request);\n\n if (hasRole(REFUNDER_ROLE, msg.sender)) {\n // Refunder can refund if deadline has passed\n if (block.timestamp \u003c= transaction.deadline) revert DeadlineNotExceeded();\n } else {\n // Permissionless refund is allowed after REFUND_DELAY\n if (block.timestamp \u003c= transaction.deadline + REFUND_DELAY) revert DeadlineNotExceeded();\n }\n\n // set status to refunded if still in requested state\n if (bridgeStatuses[transactionId] != BridgeStatus.REQUESTED) revert StatusIncorrect();\n bridgeStatuses[transactionId] = BridgeStatus.REFUNDED;\n\n // transfer origin collateral back to original sender\n address to = transaction.originSender;\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount + transaction.originFeeAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n }\n}\n\n// test/FastBridgeMock.sol\n\ncontract FastBridgeMock is IFastBridge, Admin {\n // @dev the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @dev to prevent replays\n uint256 public nonce;\n\n /// @notice We include an empty \"test\" function so that this contract does not appear in the coverage report.\n function testFastBridgeMock() external {}\n\n function getBridgeTransaction(bytes memory request) public pure returns (BridgeTransaction memory) {\n return abi.decode(request, (BridgeTransaction));\n }\n\n // used for testing in go.\n // see: https://ethereum.stackexchange.com/questions/21155/how-to-expose-enum-in-solidity-contract\n // make sure to update fastbridge/status.go if this changes\n // or underliyng enum changes.\n //\n // TODO: a foundry test should be added to ensure this is always in sync.\n function getEnumKeyByValue(FastBridge.BridgeStatus keyValue) public pure returns (string memory) {\n if (FastBridge.BridgeStatus.NULL == keyValue) return \"NULL\";\n if (FastBridge.BridgeStatus.REQUESTED == keyValue) return \"REQUESTED\";\n if (FastBridge.BridgeStatus.RELAYER_PROVED == keyValue) return \"RELAYER_PROVED\";\n if (FastBridge.BridgeStatus.RELAYER_CLAIMED == keyValue) return \"RELAYER_CLAIMED\";\n if (FastBridge.BridgeStatus.REFUNDED == keyValue) return \"REFUNDED\";\n return \"\";\n }\n\n function mockBridgeRequest(bytes32 transactionId, address sender, BridgeParams memory params) external {\n sender;\n uint256 originFeeAmount = (params.originAmount * protocolFeeRate) / FEE_BPS;\n params.originAmount -= originFeeAmount;\n\n bytes memory request = abi.encode(\n BridgeTransaction({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: params.originAmount, // includes relayer fee\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n sendChainGas: params.sendChainGas,\n deadline: params.deadline,\n nonce: nonce++ // increment nonce on every bridge\n })\n );\n\n emit BridgeRequested(\n transactionId,\n params.sender,\n request,\n params.dstChainId,\n params.originToken,\n params.destToken,\n params.originAmount,\n params.destAmount,\n params.sendChainGas\n );\n }\n\n function mockBridgeRequestRaw(bytes32 transactionId, address sender, bytes memory request) external {\n sender;\n BridgeTransaction memory transaction = getBridgeTransaction(request);\n emit BridgeRequested(\n transactionId,\n transaction.originSender,\n request,\n transaction.destChainId,\n transaction.originToken,\n transaction.destToken,\n transaction.originAmount,\n transaction.destAmount,\n transaction.sendChainGas\n );\n }\n\n function mockBridgeRelayer(\n bytes32 transactionId,\n address relayer,\n address to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n )\n external\n {\n emit BridgeRelayed(\n transactionId, relayer, to, originChainId, originToken, destToken, originAmount, destAmount, chainGasAmount\n );\n }\n\n function bridge(BridgeParams memory) external payable {\n revert(\"not implemented\");\n }\n\n function relay(bytes memory) external payable {\n revert(\"not implemented\");\n }\n\n function prove(bytes memory, bytes32) external pure {\n revert(\"not implemented\");\n }\n\n function canClaim(bytes32, address) external pure returns (bool) {\n revert(\"not implemented\");\n }\n\n function claim(bytes memory, address) external pure {\n revert(\"not implemented\");\n }\n\n function dispute(bytes32) external pure {\n revert(\"not implemented\");\n }\n\n function refund(bytes memory) external pure {\n revert(\"not implemented\");\n }\n}\n","language":"Solidity","languageVersion":"0.8.20","compilerVersion":"0.8.20","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"25443:11640:0:-:0;;;;;;;;;;;;;;;-1:-1:-1;;;25443:11640:0;;;;;;;;;;;;;;;;;","srcMapRuntime":"25443:11640:0:-:0;;;;;;;;","abiDefinition":[],"userDoc":{"kind":"user","methods":{},"version":1},"developerDoc":{"details":"Library for managing https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive types. Sets have the following properties: - Elements are added, removed, and checked for existence in constant time (O(1)). - Elements are enumerated in O(n). No guarantees are made on the ordering. ```solidity contract Example { // Add the library methods using EnumerableSet for EnumerableSet.AddressSet; // Declare a set state variable EnumerableSet.AddressSet private mySet; } ``` As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`) and `uint256` (`UintSet`) are supported. [WARNING] ==== Trying to delete such a structure from storage will likely result in data corruption, rendering the structure unusable. See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info. In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an array of EnumerableSet. ====","kind":"dev","methods":{},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.20+commit.a1b79de6\"},\"language\":\"Solidity\",\"output\":{\"abi\":[],\"devdoc\":{\"details\":\"Library for managing https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive types. Sets have the following properties: - Elements are added, removed, and checked for existence in constant time (O(1)). - Elements are enumerated in O(n). No guarantees are made on the ordering. ```solidity contract Example { // Add the library methods using EnumerableSet for EnumerableSet.AddressSet; // Declare a set state variable EnumerableSet.AddressSet private mySet; } ``` As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`) and `uint256` (`UintSet`) are supported. [WARNING] ==== Trying to delete such a structure from storage will likely result in data corruption, rendering the structure unusable. See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info. In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an array of EnumerableSet. ====\",\"kind\":\"dev\",\"methods\":{},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeMock.sol\":\"EnumerableSet\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeMock.sol\":{\"keccak256\":\"0xf2751f52f8216801d500da7464ad01f3c23a8286e155e2dcba6d21d6e7fd95a0\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://85d2edab24ebe321043d2b88038437e8f443a0ef26fa2139c72dcc2bc7fbc602\",\"dweb:/ipfs/QmcULiFPFJzFDT4aupVSDreXz8uHxcABb5nxpAG4zYzfNN\"]}},\"version\":1}"},"hashes":{}},"solidity/FastBridgeMock.sol:FastBridge":{"code":"0x60a06040523480156200001157600080fd5b506040516200322638038062003226833981016040819052620000349162000194565b80620000426000826200004f565b50504360805250620001bf565b6000806200005e84846200008c565b90508015620000835760008481526001602052604090206200008190846200013a565b505b90505b92915050565b6000828152602081815260408083206001600160a01b038516845290915281205460ff1662000131576000838152602081815260408083206001600160a01b03861684529091529020805460ff19166001179055620000e83390565b6001600160a01b0316826001600160a01b0316847f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a450600162000086565b50600062000086565b600062000083836001600160a01b0384166000818152600183016020526040812054620001315750815460018181018455600084815260208082209093018490558454848252828601909352604090209190915562000086565b600060208284031215620001a757600080fd5b81516001600160a01b03811681146200008357600080fd5b60805161304b620001db60003960006106d4015261304b6000f3fe6080604052600436106102a05760003560e01c80638f0d6f171161016e578063add98c70116100cb578063ca15c8731161007f578063d547741f11610064578063d547741f14610824578063dcf844a714610844578063e00a83e01461087157600080fd5b8063ca15c873146107d0578063ccc57490146107f057600080fd5b8063b13aa2d6116100b0578063b13aa2d614610779578063b250fe6b14610799578063bf333f2c146107b957600080fd5b8063add98c7014610743578063affed0e01461076357600080fd5b8063a217fddf11610122578063a5bbe22b11610107578063a5bbe22b14610502578063aa9641ab146106f6578063ac11fb1a1461071657600080fd5b8063a217fddf146106ad578063a3ec191a146106c257600080fd5b806391ad50391161015357806391ad5039146105b357806391d1485414610635578063926d7d7f1461067957600080fd5b80638f0d6f17146105685780639010d07c1461057b57600080fd5b8063385c1d2f1161021c5780635960ccf2116101d0578063820688d5116101b5578063820688d5146105025780638379a24f14610518578063886d36ff1461054857600080fd5b80635960ccf2146104ae5780635eb7d946146104e257600080fd5b806341fcb6121161020157806341fcb61214610465578063458516941461048557806358f858801461049857600080fd5b8063385c1d2f146104185780633f61331d1461044557600080fd5b80630f5f6ed711610273578063248a9ca311610258578063248a9ca3146103a85780632f2ff15d146103d857806336568abe146103f857600080fd5b80630f5f6ed71461037b578063190da5951461039157600080fd5b806301ffc9a7146102a557806303ed0ee5146102da578063051287bc1461031c57806306f333f214610359575b600080fd5b3480156102b157600080fd5b506102c56102c0366004612602565b610887565b60405190151581526020015b60405180910390f35b3480156102e657600080fd5b5061030e7f043c983c49d46f0e102151eaf8085d4a2e6571d5df2d47b013f39bddfd4a639d81565b6040519081526020016102d1565b34801561032857600080fd5b5061034c610337366004612644565b60056020526000908152604090205460ff1681565b6040516102d1919061268c565b34801561036557600080fd5b506103796103743660046126f2565b6108e3565b005b34801561038757600080fd5b5061030e61271081565b34801561039d57600080fd5b5061030e62093a8081565b3480156103b457600080fd5b5061030e6103c3366004612644565b60009081526020819052604090206001015490565b3480156103e457600080fd5b506103796103f336600461272b565b6109aa565b34801561040457600080fd5b5061037961041336600461272b565b6109d5565b34801561042457600080fd5b50610438610433366004612769565b610a21565b6040516102d1919061285d565b34801561045157600080fd5b50610379610460366004612769565b610bb7565b34801561047157600080fd5b50610379610480366004612a19565b610c6a565b610379610493366004612a7d565b610ea3565b3480156104a457600080fd5b5061030e60025481565b3480156104ba57600080fd5b5061030e7fdb9556138406326f00296e13ea2ad7db24ba82381212d816b1a40c23b466b32781565b3480156104ee57600080fd5b506103796104fd366004612b20565b6111b1565b34801561050e57600080fd5b5061030e61070881565b34801561052457600080fd5b506102c5610533366004612644565b60076020526000908152604090205460ff1681565b34801561055457600080fd5b50610379610563366004612b5d565b611389565b610379610576366004612b20565b6114bc565b34801561058757600080fd5b5061059b610596366004612ba2565b611703565b6040516001600160a01b0390911681526020016102d1565b3480156105bf57600080fd5b506106096105ce366004612644565b6006602052600090815260409020546bffffffffffffffffffffffff8116906c0100000000000000000000000090046001600160a01b031682565b604080516bffffffffffffffffffffffff90931683526001600160a01b039091166020830152016102d1565b34801561064157600080fd5b506102c561065036600461272b565b6000918252602082815260408084206001600160a01b0393909316845291905290205460ff1690565b34801561068557600080fd5b5061030e7fe2b7fb3b832174769106daebcfd6d1970523240dda11281102db9363b83b0dc481565b3480156106b957600080fd5b5061030e600081565b3480156106ce57600080fd5b5061030e7f000000000000000000000000000000000000000000000000000000000000000081565b34801561070257600080fd5b506102c561071136600461272b565b611722565b34801561072257600080fd5b50610736610731366004612b20565b611825565b6040516102d19190612bc4565b34801561074f57600080fd5b5061037961075e366004612644565b611898565b34801561076f57600080fd5b5061030e60085481565b34801561078557600080fd5b50610379610794366004612644565b611a01565b3480156107a557600080fd5b506103796107b4366004612644565b611ae3565b3480156107c557600080fd5b5061030e620f424081565b3480156107dc57600080fd5b5061030e6107eb366004612644565b611b4b565b3480156107fc57600080fd5b5061030e7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f5581565b34801561083057600080fd5b5061037961083f36600461272b565b611b62565b34801561085057600080fd5b5061030e61085f366004612caa565b60036020526000908152604090205481565b34801561087d57600080fd5b5061030e60045481565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f5a05180f0000000000000000000000000000000000000000000000000000000014806108dd57506108dd82611b87565b92915050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f5561090d81611c1e565b6001600160a01b038316600090815260036020526040812054908190036109345750505050565b6001600160a01b038416600081815260036020526040812055610958908483611c2b565b604080516001600160a01b038087168252851660208201529081018290527f244e51bc38c1452fa8aaf487bcb4bca36c2baa3a5fbdb776b1eabd8dc6d277cd9060600160405180910390a1505b505050565b6000828152602081905260409020600101546109c581611c1e565b6109cf8383611d4e565b50505050565b6001600160a01b0381163314610a17576040517f6697b23200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6109a58282611d7b565b60608267ffffffffffffffff811115610a3c57610a3c6128f1565b604051908082528060200260200182016040528015610a8257816020015b604080518082019091526000815260606020820152815260200190600190039081610a5a5790505b50905060005b83811015610baf5730858583818110610aa357610aa3612cc7565b9050602002810190610ab59190612cf6565b604051610ac3929190612d62565b600060405180830381855af49150503d8060008114610afe576040519150601f19603f3d011682016040523d82523d6000602084013e610b03565b606091505b50838381518110610b1657610b16612cc7565b6020026020010151600001848481518110610b3357610b33612cc7565b602002602001015160200182905282151515158152505050818181518110610b5d57610b5d612cc7565b602002602001015160000151158015610b74575082155b15610b9f57610b9f828281518110610b8e57610b8e612cc7565b602002602001015160200151611da8565b610ba881612da1565b9050610a88565b509392505050565b60005b828110156109cf5760008030868685818110610bd857610bd8612cc7565b9050602002810190610bea9190612cf6565b604051610bf8929190612d62565b600060405180830381855af49150503d8060008114610c33576040519150601f19603f3d011682016040523d82523d6000602084013e610c38565b606091505b509150915081158015610c49575083155b15610c5757610c5781611da8565b505080610c6390612da1565b9050610bba565b7fe2b7fb3b832174769106daebcfd6d1970523240dda11281102db9363b83b0dc4610c9481611c1e565b825160208401206000610ca685611825565b9050600260008381526005602052604090205460ff166004811115610ccd57610ccd61265d565b14610d04576040517f4145817200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000828152600660209081526040918290208251808401909352546bffffffffffffffffffffffff811683526c0100000000000000000000000090046001600160a01b03169082018190523314610d87576040517f4af43a9000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80516107089042036bffffffffffffffffffffffff1611610dd4576040517f1992d0bd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000838152600560205260409020805460ff1916600317905561010082015115610e305761010082015160808301516001600160a01b031660009081526003602052604081208054909190610e2a908490612dd9565b90915550505b608082015160c0830151610e4e6001600160a01b0383168883611c2b565b604080516001600160a01b03848116825260208201849052891691339188917f582211c35a2139ac3bbaac74663c6a1f56c6cbb658b41fe11fd45a82074ac67891015b60405180910390a45050505050505050565b46816000015163ffffffff1603610ee6576040517f7029fdf900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60a08101511580610ef9575060c0810151155b15610f30576040517fe38820c800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60608101516001600160a01b03161580610f55575060808101516001600160a01b0316155b15610f8c576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610f9861070842612dd9565b8161010001511015610fd6576040517f04b7fcc800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000610feb3083606001518460a00151611dea565b9050600080600254111561101857620f42406002548361100b9190612dec565b6110159190612e03565b90505b6110228183612e3e565b915060006040518061018001604052804663ffffffff168152602001856000015163ffffffff16815260200185602001516001600160a01b0316815260200185604001516001600160a01b0316815260200185606001516001600160a01b0316815260200185608001516001600160a01b031681526020018481526020018560c0015181526020018381526020018560e00151151581526020018561010001518152602001600860008154809291906110da90612da1565b9091555090526040516110f09190602001612bc4565b604080518083037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0018152828252805160208083019190912060008181526005835293909320805460ff191660011790558701518751606089015160808a015160c08b015160e08c015195985095966001600160a01b039094169587957f120ea0364f36cdac7983bcfdd55270ca09d7f9b314a2ebc425a3b01ab1d6403a956111a2958b959094909390928e92612e51565b60405180910390a35050505050565b8051602082012060006111c383611825565b3360009081527fd2043bf65931af3dbecf60d0db8f40e4160406d7beb00522f4200cf4944a1eb8602052604090205490915060ff161561124057806101400151421161123b576040517fe15ff9ea00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61128c565b62093a808161014001516112549190612dd9565b421161128c576040517fe15ff9ea00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600160008381526005602052604090205460ff1660048111156112b1576112b161265d565b146112e8576040517f4145817200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600082815260056020526040808220805460ff19166004179055820151608083015161010084015160c0850151929391926113239190612dd9565b90506113396001600160a01b0383168483611c2b565b604080516001600160a01b0384811682526020820184905285169187917fb4c55c0c9bc613519b920e88748090150b890a875d307f21bea7d4fb2e8bc958910160405180910390a3505050505050565b7fe2b7fb3b832174769106daebcfd6d1970523240dda11281102db9363b83b0dc46113b381611c1e565b82516020840120600160008281526005602052604090205460ff1660048111156113df576113df61265d565b14611416576040517f4145817200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008181526005602090815260408083208054600260ff19909116179055805180820182526bffffffffffffffffffffffff4281168252338285018181528787526006865295849020925195516001600160a01b03166c0100000000000000000000000002959091169490941790555185815283917f4ac8af8a2cd87193d64dfc7a3b8d9923b714ec528b18725d080aa1299be0c5e4910160405180910390a350505050565b7fe2b7fb3b832174769106daebcfd6d1970523240dda11281102db9363b83b0dc46114e681611c1e565b8151602083012060006114f884611825565b90504663ffffffff16816020015163ffffffff1614611543576040517f7029fdf900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b806101400151421115611582576040517f559895a300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008281526007602052604090205460ff16156115cb576040517fbef7bb7d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000828152600760205260409020805460ff19166001179055606081015160a082015160e08301516004546101208501516116145750600061160e848484611dea565b50611685565b7fffffffffffffffffffffffff11111111111111111111111111111111111111126001600160a01b038416016116585761160e84846116538486612dd9565b611dea565b611663848484611dea565b506116838473eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee83611dea565b505b845160808087015160a08089015160c0808b015160e08c01516040805163ffffffff90991689526001600160a01b0396871660208a0152938616938801939093526060870152938501528301849052861691339189917ff8ae392d784b1ea5e8881bfa586d81abf07ef4f1e2fc75f7fe51c90f05199a5c9101610e91565b600082815260016020526040812061171b9083611fb9565b9392505050565b6000600260008481526005602052604090205460ff1660048111156117495761174961265d565b14611780576040517f4145817200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000838152600660209081526040918290208251808401909352546bffffffffffffffffffffffff811683526001600160a01b036c010000000000000000000000009091048116918301829052841614611806576040517f4af43a9000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80516107089042036bffffffffffffffffffffffff1611949350505050565b604080516101808101825260008082526020808301829052928201819052606082018190526080820181905260a0820181905260c0820181905260e08201819052610100820181905261012082018190526101408201819052610160820152825190916108dd9184018101908401612ec8565b7f043c983c49d46f0e102151eaf8085d4a2e6571d5df2d47b013f39bddfd4a639d6118c281611c1e565b600260008381526005602052604090205460ff1660048111156118e7576118e761265d565b1461191e576040517f4145817200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000828152600660209081526040918290208251808401909352546bffffffffffffffffffffffff8082168085526c010000000000000000000000009092046001600160a01b031693909201929092526107089142031611156119ad576040517f3e908aac00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000828152600560209081526040808320805460ff19166001179055600690915280822082905551339184917f0695cf1d39b3055dcd0fe02d8b47eaf0d5a13e1996de925de59d0ef9b7f7fad49190a35050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f55611a2b81611c1e565b612710821115611a9c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f6e657746656552617465203e206d61780000000000000000000000000000000060448201526064015b60405180910390fd5b600280549083905560408051828152602081018590527f14914da2bf76024616fbe1859783fcd4dbddcb179b1f3a854949fbf920dcb95791015b60405180910390a1505050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f55611b0d81611c1e565b600480549083905560408051828152602081018590527f5cf09b12f3f56b4c564d51b25b40360af6d795198adb61ae0806a36c294323fa9101611ad6565b60008181526001602052604081206108dd90611fc5565b600082815260208190526040902060010154611b7d81611c1e565b6109cf8383611d7b565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f7965db0b0000000000000000000000000000000000000000000000000000000014806108dd57507f01ffc9a7000000000000000000000000000000000000000000000000000000007fffffffff000000000000000000000000000000000000000000000000000000008316146108dd565b611c288133611fcf565b50565b306001600160a01b03831603611c4057505050565b80600003611c4d57505050565b7fffffffffffffffffffffffff11111111111111111111111111111111111111126001600160a01b03841601611d3a576000826001600160a01b03168260405160006040518083038185875af1925050503d8060008114611cca576040519150601f19603f3d011682016040523d82523d6000602084013e611ccf565b606091505b50509050806109cf576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f455448207472616e73666572206661696c6564000000000000000000000000006044820152606401611a93565b6109a56001600160a01b038416838361203f565b600080611d5b84846120b3565b9050801561171b576000848152600160205260409020610baf908461215d565b600080611d888484612172565b9050801561171b576000848152600160205260409020610baf90846121f5565b805115611db85780518082602001fd5b6040517f5ead5a9d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006001600160a01b03831673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee14611f5357611e22836001600160a01b031661220a565b6040517f70a082310000000000000000000000000000000000000000000000000000000081526001600160a01b0385811660048301528416906370a0823190602401602060405180830381865afa158015611e81573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ea59190612f94565b9050611ebc6001600160a01b0384163386856122b0565b6040517f70a082310000000000000000000000000000000000000000000000000000000081526001600160a01b0385811660048301528291908516906370a0823190602401602060405180830381865afa158015611f1e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f429190612f94565b611f4c9190612e3e565b905061171b565b348214611f8c576040517f81de0bf300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600160a01b0384163014611fb057611fb06001600160a01b0384168584611c2b565b50349392505050565b600061171b83836122e9565b60006108dd825490565b6000828152602081815260408083206001600160a01b038516845290915290205460ff1661203b576040517fe2517d3f0000000000000000000000000000000000000000000000000000000081526001600160a01b038216600482015260248101839052604401611a93565b5050565b6040516001600160a01b038381166024830152604482018390526109a591859182169063a9059cbb906064015b604051602081830303815290604052915060e01b6020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8381831617835250505050612313565b6000828152602081815260408083206001600160a01b038516845290915281205460ff16612155576000838152602081815260408083206001600160a01b03861684529091529020805460ff1916600117905561210d3390565b6001600160a01b0316826001600160a01b0316847f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45060016108dd565b5060006108dd565b600061171b836001600160a01b03841661238f565b6000828152602081815260408083206001600160a01b038516845290915281205460ff1615612155576000838152602081815260408083206001600160a01b0386168085529252808320805460ff1916905551339286917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a45060016108dd565b600061171b836001600160a01b0384166123d6565b7fffffffffffffffffffffffff11111111111111111111111111111111111111126001600160a01b0382160161226c576040517f7f523fe800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b806001600160a01b03163b600003611c28576040517f7f523fe800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040516001600160a01b0384811660248301528381166044830152606482018390526109cf9186918216906323b872dd9060840161206c565b600082600001828154811061230057612300612cc7565b9060005260206000200154905092915050565b60006123286001600160a01b038416836124c9565b9050805160001415801561234d57508080602001905181019061234b9190612fad565b155b156109a5576040517f5274afe70000000000000000000000000000000000000000000000000000000081526001600160a01b0384166004820152602401611a93565b6000818152600183016020526040812054612155575081546001818101845560008481526020808220909301849055845484825282860190935260409020919091556108dd565b600081815260018301602052604081205480156124bf5760006123fa600183612e3e565b855490915060009061240e90600190612e3e565b905080821461247357600086600001828154811061242e5761242e612cc7565b906000526020600020015490508087600001848154811061245157612451612cc7565b6000918252602080832090910192909255918252600188019052604090208390555b855486908061248457612484612fca565b6001900381819060005260206000200160009055905585600101600086815260200190815260200160002060009055600193505050506108dd565b60009150506108dd565b606061171b8383600084600080856001600160a01b031684866040516124ef9190612ff9565b60006040518083038185875af1925050503d806000811461252c576040519150601f19603f3d011682016040523d82523d6000602084013e612531565b606091505b509150915061254186838361254b565b9695505050505050565b6060826125605761255b826125c0565b61171b565b815115801561257757506001600160a01b0384163b155b156125b9576040517f9996b3150000000000000000000000000000000000000000000000000000000081526001600160a01b0385166004820152602401611a93565b508061171b565b8051156125d05780518082602001fd5b6040517f1425ea4200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006020828403121561261457600080fd5b81357fffffffff000000000000000000000000000000000000000000000000000000008116811461171b57600080fd5b60006020828403121561265657600080fd5b5035919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b60208101600583106126c7577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b91905290565b6001600160a01b0381168114611c2857600080fd5b80356126ed816126cd565b919050565b6000806040838503121561270557600080fd5b8235612710816126cd565b91506020830135612720816126cd565b809150509250929050565b6000806040838503121561273e57600080fd5b823591506020830135612720816126cd565b8015158114611c2857600080fd5b80356126ed81612750565b60008060006040848603121561277e57600080fd5b833567ffffffffffffffff8082111561279657600080fd5b818601915086601f8301126127aa57600080fd5b8135818111156127b957600080fd5b8760208260051b85010111156127ce57600080fd5b602092830195509350508401356127e481612750565b809150509250925092565b60005b8381101561280a5781810151838201526020016127f2565b50506000910152565b6000815180845261282b8160208601602086016127ef565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b60006020808301818452808551808352604092508286019150828160051b87010184880160005b838110156128e3578883037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc001855281518051151584528701518784018790526128d087850182612813565b9588019593505090860190600101612884565b509098975050505050505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051610120810167ffffffffffffffff81118282101715612944576129446128f1565b60405290565b604051610180810167ffffffffffffffff81118282101715612944576129446128f1565b600082601f83011261297f57600080fd5b813567ffffffffffffffff8082111561299a5761299a6128f1565b604051601f83017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f011681019082821181831017156129e0576129e06128f1565b816040528381528660208588010111156129f957600080fd5b836020870160208301376000602085830101528094505050505092915050565b60008060408385031215612a2c57600080fd5b823567ffffffffffffffff811115612a4357600080fd5b612a4f8582860161296e565b9250506020830135612720816126cd565b63ffffffff81168114611c2857600080fd5b80356126ed81612a60565b60006101208284031215612a9057600080fd5b612a98612920565b612aa183612a72565b8152612aaf602084016126e2565b6020820152612ac0604084016126e2565b6040820152612ad1606084016126e2565b6060820152612ae2608084016126e2565b608082015260a083013560a082015260c083013560c0820152612b0760e0840161275e565b60e0820152610100928301359281019290925250919050565b600060208284031215612b3257600080fd5b813567ffffffffffffffff811115612b4957600080fd5b612b558482850161296e565b949350505050565b60008060408385031215612b7057600080fd5b823567ffffffffffffffff811115612b8757600080fd5b612b938582860161296e565b95602094909401359450505050565b60008060408385031215612bb557600080fd5b50508035926020909101359150565b815163ffffffff16815261018081016020830151612bea602084018263ffffffff169052565b506040830151612c0560408401826001600160a01b03169052565b506060830151612c2060608401826001600160a01b03169052565b506080830151612c3b60808401826001600160a01b03169052565b5060a0830151612c5660a08401826001600160a01b03169052565b5060c083015160c083015260e083015160e083015261010080840151818401525061012080840151612c8b8285018215159052565b5050610140838101519083015261016092830151929091019190915290565b600060208284031215612cbc57600080fd5b813561171b816126cd565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112612d2b57600080fd5b83018035915067ffffffffffffffff821115612d4657600080fd5b602001915036819003821315612d5b57600080fd5b9250929050565b8183823760009101908152919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203612dd257612dd2612d72565b5060010190565b808201808211156108dd576108dd612d72565b80820281158282048414176108dd576108dd612d72565b600082612e39577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b818103818111156108dd576108dd612d72565b60e081526000612e6460e083018a612813565b63ffffffff989098166020830152506001600160a01b039586166040820152939094166060840152608083019190915260a082015290151560c090910152919050565b80516126ed81612a60565b80516126ed816126cd565b80516126ed81612750565b60006101808284031215612edb57600080fd5b612ee361294a565b612eec83612ea7565b8152612efa60208401612ea7565b6020820152612f0b60408401612eb2565b6040820152612f1c60608401612eb2565b6060820152612f2d60808401612eb2565b6080820152612f3e60a08401612eb2565b60a082015260c083015160c082015260e083015160e0820152610100808401518183015250610120612f71818501612ebd565b908201526101408381015190820152610160928301519281019290925250919050565b600060208284031215612fa657600080fd5b5051919050565b600060208284031215612fbf57600080fd5b815161171b81612750565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fd5b6000825161300b8184602087016127ef565b919091019291505056fea2646970667358221220a96fddf13970542174791dd58f2a7c0d8038c41139bc7a4cec0696cb1cda555864736f6c63430008140033","runtime-code":"0x6080604052600436106102a05760003560e01c80638f0d6f171161016e578063add98c70116100cb578063ca15c8731161007f578063d547741f11610064578063d547741f14610824578063dcf844a714610844578063e00a83e01461087157600080fd5b8063ca15c873146107d0578063ccc57490146107f057600080fd5b8063b13aa2d6116100b0578063b13aa2d614610779578063b250fe6b14610799578063bf333f2c146107b957600080fd5b8063add98c7014610743578063affed0e01461076357600080fd5b8063a217fddf11610122578063a5bbe22b11610107578063a5bbe22b14610502578063aa9641ab146106f6578063ac11fb1a1461071657600080fd5b8063a217fddf146106ad578063a3ec191a146106c257600080fd5b806391ad50391161015357806391ad5039146105b357806391d1485414610635578063926d7d7f1461067957600080fd5b80638f0d6f17146105685780639010d07c1461057b57600080fd5b8063385c1d2f1161021c5780635960ccf2116101d0578063820688d5116101b5578063820688d5146105025780638379a24f14610518578063886d36ff1461054857600080fd5b80635960ccf2146104ae5780635eb7d946146104e257600080fd5b806341fcb6121161020157806341fcb61214610465578063458516941461048557806358f858801461049857600080fd5b8063385c1d2f146104185780633f61331d1461044557600080fd5b80630f5f6ed711610273578063248a9ca311610258578063248a9ca3146103a85780632f2ff15d146103d857806336568abe146103f857600080fd5b80630f5f6ed71461037b578063190da5951461039157600080fd5b806301ffc9a7146102a557806303ed0ee5146102da578063051287bc1461031c57806306f333f214610359575b600080fd5b3480156102b157600080fd5b506102c56102c0366004612602565b610887565b60405190151581526020015b60405180910390f35b3480156102e657600080fd5b5061030e7f043c983c49d46f0e102151eaf8085d4a2e6571d5df2d47b013f39bddfd4a639d81565b6040519081526020016102d1565b34801561032857600080fd5b5061034c610337366004612644565b60056020526000908152604090205460ff1681565b6040516102d1919061268c565b34801561036557600080fd5b506103796103743660046126f2565b6108e3565b005b34801561038757600080fd5b5061030e61271081565b34801561039d57600080fd5b5061030e62093a8081565b3480156103b457600080fd5b5061030e6103c3366004612644565b60009081526020819052604090206001015490565b3480156103e457600080fd5b506103796103f336600461272b565b6109aa565b34801561040457600080fd5b5061037961041336600461272b565b6109d5565b34801561042457600080fd5b50610438610433366004612769565b610a21565b6040516102d1919061285d565b34801561045157600080fd5b50610379610460366004612769565b610bb7565b34801561047157600080fd5b50610379610480366004612a19565b610c6a565b610379610493366004612a7d565b610ea3565b3480156104a457600080fd5b5061030e60025481565b3480156104ba57600080fd5b5061030e7fdb9556138406326f00296e13ea2ad7db24ba82381212d816b1a40c23b466b32781565b3480156104ee57600080fd5b506103796104fd366004612b20565b6111b1565b34801561050e57600080fd5b5061030e61070881565b34801561052457600080fd5b506102c5610533366004612644565b60076020526000908152604090205460ff1681565b34801561055457600080fd5b50610379610563366004612b5d565b611389565b610379610576366004612b20565b6114bc565b34801561058757600080fd5b5061059b610596366004612ba2565b611703565b6040516001600160a01b0390911681526020016102d1565b3480156105bf57600080fd5b506106096105ce366004612644565b6006602052600090815260409020546bffffffffffffffffffffffff8116906c0100000000000000000000000090046001600160a01b031682565b604080516bffffffffffffffffffffffff90931683526001600160a01b039091166020830152016102d1565b34801561064157600080fd5b506102c561065036600461272b565b6000918252602082815260408084206001600160a01b0393909316845291905290205460ff1690565b34801561068557600080fd5b5061030e7fe2b7fb3b832174769106daebcfd6d1970523240dda11281102db9363b83b0dc481565b3480156106b957600080fd5b5061030e600081565b3480156106ce57600080fd5b5061030e7f000000000000000000000000000000000000000000000000000000000000000081565b34801561070257600080fd5b506102c561071136600461272b565b611722565b34801561072257600080fd5b50610736610731366004612b20565b611825565b6040516102d19190612bc4565b34801561074f57600080fd5b5061037961075e366004612644565b611898565b34801561076f57600080fd5b5061030e60085481565b34801561078557600080fd5b50610379610794366004612644565b611a01565b3480156107a557600080fd5b506103796107b4366004612644565b611ae3565b3480156107c557600080fd5b5061030e620f424081565b3480156107dc57600080fd5b5061030e6107eb366004612644565b611b4b565b3480156107fc57600080fd5b5061030e7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f5581565b34801561083057600080fd5b5061037961083f36600461272b565b611b62565b34801561085057600080fd5b5061030e61085f366004612caa565b60036020526000908152604090205481565b34801561087d57600080fd5b5061030e60045481565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f5a05180f0000000000000000000000000000000000000000000000000000000014806108dd57506108dd82611b87565b92915050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f5561090d81611c1e565b6001600160a01b038316600090815260036020526040812054908190036109345750505050565b6001600160a01b038416600081815260036020526040812055610958908483611c2b565b604080516001600160a01b038087168252851660208201529081018290527f244e51bc38c1452fa8aaf487bcb4bca36c2baa3a5fbdb776b1eabd8dc6d277cd9060600160405180910390a1505b505050565b6000828152602081905260409020600101546109c581611c1e565b6109cf8383611d4e565b50505050565b6001600160a01b0381163314610a17576040517f6697b23200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6109a58282611d7b565b60608267ffffffffffffffff811115610a3c57610a3c6128f1565b604051908082528060200260200182016040528015610a8257816020015b604080518082019091526000815260606020820152815260200190600190039081610a5a5790505b50905060005b83811015610baf5730858583818110610aa357610aa3612cc7565b9050602002810190610ab59190612cf6565b604051610ac3929190612d62565b600060405180830381855af49150503d8060008114610afe576040519150601f19603f3d011682016040523d82523d6000602084013e610b03565b606091505b50838381518110610b1657610b16612cc7565b6020026020010151600001848481518110610b3357610b33612cc7565b602002602001015160200182905282151515158152505050818181518110610b5d57610b5d612cc7565b602002602001015160000151158015610b74575082155b15610b9f57610b9f828281518110610b8e57610b8e612cc7565b602002602001015160200151611da8565b610ba881612da1565b9050610a88565b509392505050565b60005b828110156109cf5760008030868685818110610bd857610bd8612cc7565b9050602002810190610bea9190612cf6565b604051610bf8929190612d62565b600060405180830381855af49150503d8060008114610c33576040519150601f19603f3d011682016040523d82523d6000602084013e610c38565b606091505b509150915081158015610c49575083155b15610c5757610c5781611da8565b505080610c6390612da1565b9050610bba565b7fe2b7fb3b832174769106daebcfd6d1970523240dda11281102db9363b83b0dc4610c9481611c1e565b825160208401206000610ca685611825565b9050600260008381526005602052604090205460ff166004811115610ccd57610ccd61265d565b14610d04576040517f4145817200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000828152600660209081526040918290208251808401909352546bffffffffffffffffffffffff811683526c0100000000000000000000000090046001600160a01b03169082018190523314610d87576040517f4af43a9000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80516107089042036bffffffffffffffffffffffff1611610dd4576040517f1992d0bd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000838152600560205260409020805460ff1916600317905561010082015115610e305761010082015160808301516001600160a01b031660009081526003602052604081208054909190610e2a908490612dd9565b90915550505b608082015160c0830151610e4e6001600160a01b0383168883611c2b565b604080516001600160a01b03848116825260208201849052891691339188917f582211c35a2139ac3bbaac74663c6a1f56c6cbb658b41fe11fd45a82074ac67891015b60405180910390a45050505050505050565b46816000015163ffffffff1603610ee6576040517f7029fdf900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60a08101511580610ef9575060c0810151155b15610f30576040517fe38820c800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60608101516001600160a01b03161580610f55575060808101516001600160a01b0316155b15610f8c576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610f9861070842612dd9565b8161010001511015610fd6576040517f04b7fcc800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000610feb3083606001518460a00151611dea565b9050600080600254111561101857620f42406002548361100b9190612dec565b6110159190612e03565b90505b6110228183612e3e565b915060006040518061018001604052804663ffffffff168152602001856000015163ffffffff16815260200185602001516001600160a01b0316815260200185604001516001600160a01b0316815260200185606001516001600160a01b0316815260200185608001516001600160a01b031681526020018481526020018560c0015181526020018381526020018560e00151151581526020018561010001518152602001600860008154809291906110da90612da1565b9091555090526040516110f09190602001612bc4565b604080518083037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0018152828252805160208083019190912060008181526005835293909320805460ff191660011790558701518751606089015160808a015160c08b015160e08c015195985095966001600160a01b039094169587957f120ea0364f36cdac7983bcfdd55270ca09d7f9b314a2ebc425a3b01ab1d6403a956111a2958b959094909390928e92612e51565b60405180910390a35050505050565b8051602082012060006111c383611825565b3360009081527fd2043bf65931af3dbecf60d0db8f40e4160406d7beb00522f4200cf4944a1eb8602052604090205490915060ff161561124057806101400151421161123b576040517fe15ff9ea00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61128c565b62093a808161014001516112549190612dd9565b421161128c576040517fe15ff9ea00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600160008381526005602052604090205460ff1660048111156112b1576112b161265d565b146112e8576040517f4145817200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600082815260056020526040808220805460ff19166004179055820151608083015161010084015160c0850151929391926113239190612dd9565b90506113396001600160a01b0383168483611c2b565b604080516001600160a01b0384811682526020820184905285169187917fb4c55c0c9bc613519b920e88748090150b890a875d307f21bea7d4fb2e8bc958910160405180910390a3505050505050565b7fe2b7fb3b832174769106daebcfd6d1970523240dda11281102db9363b83b0dc46113b381611c1e565b82516020840120600160008281526005602052604090205460ff1660048111156113df576113df61265d565b14611416576040517f4145817200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008181526005602090815260408083208054600260ff19909116179055805180820182526bffffffffffffffffffffffff4281168252338285018181528787526006865295849020925195516001600160a01b03166c0100000000000000000000000002959091169490941790555185815283917f4ac8af8a2cd87193d64dfc7a3b8d9923b714ec528b18725d080aa1299be0c5e4910160405180910390a350505050565b7fe2b7fb3b832174769106daebcfd6d1970523240dda11281102db9363b83b0dc46114e681611c1e565b8151602083012060006114f884611825565b90504663ffffffff16816020015163ffffffff1614611543576040517f7029fdf900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b806101400151421115611582576040517f559895a300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008281526007602052604090205460ff16156115cb576040517fbef7bb7d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000828152600760205260409020805460ff19166001179055606081015160a082015160e08301516004546101208501516116145750600061160e848484611dea565b50611685565b7fffffffffffffffffffffffff11111111111111111111111111111111111111126001600160a01b038416016116585761160e84846116538486612dd9565b611dea565b611663848484611dea565b506116838473eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee83611dea565b505b845160808087015160a08089015160c0808b015160e08c01516040805163ffffffff90991689526001600160a01b0396871660208a0152938616938801939093526060870152938501528301849052861691339189917ff8ae392d784b1ea5e8881bfa586d81abf07ef4f1e2fc75f7fe51c90f05199a5c9101610e91565b600082815260016020526040812061171b9083611fb9565b9392505050565b6000600260008481526005602052604090205460ff1660048111156117495761174961265d565b14611780576040517f4145817200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000838152600660209081526040918290208251808401909352546bffffffffffffffffffffffff811683526001600160a01b036c010000000000000000000000009091048116918301829052841614611806576040517f4af43a9000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80516107089042036bffffffffffffffffffffffff1611949350505050565b604080516101808101825260008082526020808301829052928201819052606082018190526080820181905260a0820181905260c0820181905260e08201819052610100820181905261012082018190526101408201819052610160820152825190916108dd9184018101908401612ec8565b7f043c983c49d46f0e102151eaf8085d4a2e6571d5df2d47b013f39bddfd4a639d6118c281611c1e565b600260008381526005602052604090205460ff1660048111156118e7576118e761265d565b1461191e576040517f4145817200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000828152600660209081526040918290208251808401909352546bffffffffffffffffffffffff8082168085526c010000000000000000000000009092046001600160a01b031693909201929092526107089142031611156119ad576040517f3e908aac00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000828152600560209081526040808320805460ff19166001179055600690915280822082905551339184917f0695cf1d39b3055dcd0fe02d8b47eaf0d5a13e1996de925de59d0ef9b7f7fad49190a35050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f55611a2b81611c1e565b612710821115611a9c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f6e657746656552617465203e206d61780000000000000000000000000000000060448201526064015b60405180910390fd5b600280549083905560408051828152602081018590527f14914da2bf76024616fbe1859783fcd4dbddcb179b1f3a854949fbf920dcb95791015b60405180910390a1505050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f55611b0d81611c1e565b600480549083905560408051828152602081018590527f5cf09b12f3f56b4c564d51b25b40360af6d795198adb61ae0806a36c294323fa9101611ad6565b60008181526001602052604081206108dd90611fc5565b600082815260208190526040902060010154611b7d81611c1e565b6109cf8383611d7b565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f7965db0b0000000000000000000000000000000000000000000000000000000014806108dd57507f01ffc9a7000000000000000000000000000000000000000000000000000000007fffffffff000000000000000000000000000000000000000000000000000000008316146108dd565b611c288133611fcf565b50565b306001600160a01b03831603611c4057505050565b80600003611c4d57505050565b7fffffffffffffffffffffffff11111111111111111111111111111111111111126001600160a01b03841601611d3a576000826001600160a01b03168260405160006040518083038185875af1925050503d8060008114611cca576040519150601f19603f3d011682016040523d82523d6000602084013e611ccf565b606091505b50509050806109cf576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f455448207472616e73666572206661696c6564000000000000000000000000006044820152606401611a93565b6109a56001600160a01b038416838361203f565b600080611d5b84846120b3565b9050801561171b576000848152600160205260409020610baf908461215d565b600080611d888484612172565b9050801561171b576000848152600160205260409020610baf90846121f5565b805115611db85780518082602001fd5b6040517f5ead5a9d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006001600160a01b03831673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee14611f5357611e22836001600160a01b031661220a565b6040517f70a082310000000000000000000000000000000000000000000000000000000081526001600160a01b0385811660048301528416906370a0823190602401602060405180830381865afa158015611e81573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ea59190612f94565b9050611ebc6001600160a01b0384163386856122b0565b6040517f70a082310000000000000000000000000000000000000000000000000000000081526001600160a01b0385811660048301528291908516906370a0823190602401602060405180830381865afa158015611f1e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f429190612f94565b611f4c9190612e3e565b905061171b565b348214611f8c576040517f81de0bf300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600160a01b0384163014611fb057611fb06001600160a01b0384168584611c2b565b50349392505050565b600061171b83836122e9565b60006108dd825490565b6000828152602081815260408083206001600160a01b038516845290915290205460ff1661203b576040517fe2517d3f0000000000000000000000000000000000000000000000000000000081526001600160a01b038216600482015260248101839052604401611a93565b5050565b6040516001600160a01b038381166024830152604482018390526109a591859182169063a9059cbb906064015b604051602081830303815290604052915060e01b6020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8381831617835250505050612313565b6000828152602081815260408083206001600160a01b038516845290915281205460ff16612155576000838152602081815260408083206001600160a01b03861684529091529020805460ff1916600117905561210d3390565b6001600160a01b0316826001600160a01b0316847f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45060016108dd565b5060006108dd565b600061171b836001600160a01b03841661238f565b6000828152602081815260408083206001600160a01b038516845290915281205460ff1615612155576000838152602081815260408083206001600160a01b0386168085529252808320805460ff1916905551339286917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a45060016108dd565b600061171b836001600160a01b0384166123d6565b7fffffffffffffffffffffffff11111111111111111111111111111111111111126001600160a01b0382160161226c576040517f7f523fe800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b806001600160a01b03163b600003611c28576040517f7f523fe800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040516001600160a01b0384811660248301528381166044830152606482018390526109cf9186918216906323b872dd9060840161206c565b600082600001828154811061230057612300612cc7565b9060005260206000200154905092915050565b60006123286001600160a01b038416836124c9565b9050805160001415801561234d57508080602001905181019061234b9190612fad565b155b156109a5576040517f5274afe70000000000000000000000000000000000000000000000000000000081526001600160a01b0384166004820152602401611a93565b6000818152600183016020526040812054612155575081546001818101845560008481526020808220909301849055845484825282860190935260409020919091556108dd565b600081815260018301602052604081205480156124bf5760006123fa600183612e3e565b855490915060009061240e90600190612e3e565b905080821461247357600086600001828154811061242e5761242e612cc7565b906000526020600020015490508087600001848154811061245157612451612cc7565b6000918252602080832090910192909255918252600188019052604090208390555b855486908061248457612484612fca565b6001900381819060005260206000200160009055905585600101600086815260200190815260200160002060009055600193505050506108dd565b60009150506108dd565b606061171b8383600084600080856001600160a01b031684866040516124ef9190612ff9565b60006040518083038185875af1925050503d806000811461252c576040519150601f19603f3d011682016040523d82523d6000602084013e612531565b606091505b509150915061254186838361254b565b9695505050505050565b6060826125605761255b826125c0565b61171b565b815115801561257757506001600160a01b0384163b155b156125b9576040517f9996b3150000000000000000000000000000000000000000000000000000000081526001600160a01b0385166004820152602401611a93565b508061171b565b8051156125d05780518082602001fd5b6040517f1425ea4200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006020828403121561261457600080fd5b81357fffffffff000000000000000000000000000000000000000000000000000000008116811461171b57600080fd5b60006020828403121561265657600080fd5b5035919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b60208101600583106126c7577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b91905290565b6001600160a01b0381168114611c2857600080fd5b80356126ed816126cd565b919050565b6000806040838503121561270557600080fd5b8235612710816126cd565b91506020830135612720816126cd565b809150509250929050565b6000806040838503121561273e57600080fd5b823591506020830135612720816126cd565b8015158114611c2857600080fd5b80356126ed81612750565b60008060006040848603121561277e57600080fd5b833567ffffffffffffffff8082111561279657600080fd5b818601915086601f8301126127aa57600080fd5b8135818111156127b957600080fd5b8760208260051b85010111156127ce57600080fd5b602092830195509350508401356127e481612750565b809150509250925092565b60005b8381101561280a5781810151838201526020016127f2565b50506000910152565b6000815180845261282b8160208601602086016127ef565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b60006020808301818452808551808352604092508286019150828160051b87010184880160005b838110156128e3578883037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc001855281518051151584528701518784018790526128d087850182612813565b9588019593505090860190600101612884565b509098975050505050505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051610120810167ffffffffffffffff81118282101715612944576129446128f1565b60405290565b604051610180810167ffffffffffffffff81118282101715612944576129446128f1565b600082601f83011261297f57600080fd5b813567ffffffffffffffff8082111561299a5761299a6128f1565b604051601f83017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f011681019082821181831017156129e0576129e06128f1565b816040528381528660208588010111156129f957600080fd5b836020870160208301376000602085830101528094505050505092915050565b60008060408385031215612a2c57600080fd5b823567ffffffffffffffff811115612a4357600080fd5b612a4f8582860161296e565b9250506020830135612720816126cd565b63ffffffff81168114611c2857600080fd5b80356126ed81612a60565b60006101208284031215612a9057600080fd5b612a98612920565b612aa183612a72565b8152612aaf602084016126e2565b6020820152612ac0604084016126e2565b6040820152612ad1606084016126e2565b6060820152612ae2608084016126e2565b608082015260a083013560a082015260c083013560c0820152612b0760e0840161275e565b60e0820152610100928301359281019290925250919050565b600060208284031215612b3257600080fd5b813567ffffffffffffffff811115612b4957600080fd5b612b558482850161296e565b949350505050565b60008060408385031215612b7057600080fd5b823567ffffffffffffffff811115612b8757600080fd5b612b938582860161296e565b95602094909401359450505050565b60008060408385031215612bb557600080fd5b50508035926020909101359150565b815163ffffffff16815261018081016020830151612bea602084018263ffffffff169052565b506040830151612c0560408401826001600160a01b03169052565b506060830151612c2060608401826001600160a01b03169052565b506080830151612c3b60808401826001600160a01b03169052565b5060a0830151612c5660a08401826001600160a01b03169052565b5060c083015160c083015260e083015160e083015261010080840151818401525061012080840151612c8b8285018215159052565b5050610140838101519083015261016092830151929091019190915290565b600060208284031215612cbc57600080fd5b813561171b816126cd565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112612d2b57600080fd5b83018035915067ffffffffffffffff821115612d4657600080fd5b602001915036819003821315612d5b57600080fd5b9250929050565b8183823760009101908152919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203612dd257612dd2612d72565b5060010190565b808201808211156108dd576108dd612d72565b80820281158282048414176108dd576108dd612d72565b600082612e39577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b818103818111156108dd576108dd612d72565b60e081526000612e6460e083018a612813565b63ffffffff989098166020830152506001600160a01b039586166040820152939094166060840152608083019190915260a082015290151560c090910152919050565b80516126ed81612a60565b80516126ed816126cd565b80516126ed81612750565b60006101808284031215612edb57600080fd5b612ee361294a565b612eec83612ea7565b8152612efa60208401612ea7565b6020820152612f0b60408401612eb2565b6040820152612f1c60608401612eb2565b6060820152612f2d60808401612eb2565b6080820152612f3e60a08401612eb2565b60a082015260c083015160c082015260e083015160e0820152610100808401518183015250610120612f71818501612ebd565b908201526101408381015190820152610160928301519281019290925250919050565b600060208284031215612fa657600080fd5b5051919050565b600060208284031215612fbf57600080fd5b815161171b81612750565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fd5b6000825161300b8184602087016127ef565b919091019291505056fea2646970667358221220a96fddf13970542174791dd58f2a7c0d8038c41139bc7a4cec0696cb1cda555864736f6c63430008140033","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.20 ^0.8.20 ^0.8.4;\n\n// contracts/interfaces/IAdmin.sol\n\ninterface IAdmin {\n // ============ Events ============\n\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n event ChainGasAmountUpdated(uint256 oldChainGasAmount, uint256 newChainGasAmount);\n\n // ============ Methods ============\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n\n function setChainGasAmount(uint256 newChainGasAmount) external;\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IMulticallTarget.sol\n\n/// @notice Interface for a contract that can be called multiple times by the same caller. Inspired by MulticallV3:\n/// https://github.com/mds1/multicall/blob/master/src/Multicall3.sol\ninterface IMulticallTarget {\n struct Result {\n bool success;\n bytes returnData;\n }\n\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external;\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results);\n}\n\n// contracts/libs/Errors.sol\n\nerror DeadlineExceeded();\nerror DeadlineNotExceeded();\nerror DeadlineTooShort();\nerror InsufficientOutputAmount();\n\nerror MsgValueIncorrect();\nerror PoolNotFound();\nerror TokenAddressMismatch();\nerror TokenNotContract();\nerror TokenNotETH();\nerror TokensIdentical();\n\nerror ChainIncorrect();\nerror AmountIncorrect();\nerror ZeroAddress();\n\nerror DisputePeriodNotPassed();\nerror DisputePeriodPassed();\nerror SenderIncorrect();\nerror StatusIncorrect();\nerror TransactionIdIncorrect();\nerror TransactionRelayed();\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// contracts/utils/MulticallTarget.sol\n\n// solhint-disable avoid-low-level-calls\n/// @notice Template for a contract that supports batched calls (preserving the msg.sender).\n/// Only calls with zero msg.value could be batched.\nabstract contract MulticallTarget is IMulticallTarget {\n error MulticallTarget__UndeterminedRevert();\n\n /// @notice Perform a batched call to this contract, preserving the msg.sender.\n /// The return data from each call is discarded.\n /// @dev The method is non-payable, so only calls with `msg.value == 0` could be batched.\n /// It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag.\n /// Otherwise, the whole batch call will be reverted with the original revert reason.\n /// @param data List of abi-encoded calldata for the calls to perform.\n /// @param ignoreReverts Whether to ignore the revert errors from the calls.\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external {\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\n if (!success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(result);\n }\n }\n }\n\n /// @notice Perform a batched call to this contract, preserving the msg.sender.\n /// The return data from each call is preserved.\n /// @dev The method is non-payable, so only calls with `msg.value == 0` could be batched.\n /// It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag.\n /// Otherwise, the whole batch call will be reverted with the original revert reason.\n /// @param data List of abi-encoded calldata for the calls to perform.\n /// @param ignoreReverts Whether to ignore the revert errors from the calls.\n /// @return results List of results from the calls: `(success, returnData)`.\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results)\n {\n results = new Result[](data.length);\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (results[i].success, results[i].returnData) = address(this).delegatecall(data[i]);\n if (!results[i].success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(results[i].returnData);\n }\n }\n }\n\n /// @dev Bubbles the revert message from the underlying call.\n /// Note: preserves the same custom error or revert string, if one was used.\n /// Source: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v5.0.2/contracts/utils/Address.sol#L143-L158\n function _bubbleRevert(bytes memory returnData) internal pure {\n // Look for revert reason and bubble it up if present\n if (returnData.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n // solhint-disable-next-line no-inline-assembly\n assembly {\n let returndata_size := mload(returnData)\n revert(add(32, returnData), returndata_size)\n }\n } else {\n revert MulticallTarget__UndeterminedRevert();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// contracts/libs/UniversalToken.sol\n\nlibrary UniversalTokenLib {\n using SafeERC20 for IERC20;\n\n address internal constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Transfers tokens to the given account. Reverts if transfer is not successful.\n /// @dev This might trigger fallback, if ETH is transferred to the contract.\n /// Make sure this can not lead to reentrancy attacks.\n function universalTransfer(address token, address to, uint256 value) internal {\n // Don't do anything, if need to send tokens to this address\n if (to == address(this)) return;\n // Don't do anything, if trying to send zero value\n if (value == 0) return;\n if (token == ETH_ADDRESS) {\n /// @dev Note: this can potentially lead to executing code in `to`.\n // solhint-disable-next-line avoid-low-level-calls\n (bool success,) = to.call{value: value}(\"\");\n require(success, \"ETH transfer failed\");\n } else {\n IERC20(token).safeTransfer(to, value);\n }\n }\n\n /// @notice Issues an infinite allowance to the spender, if the current allowance is insufficient\n /// to spend the given amount.\n function universalApproveInfinity(address token, address spender, uint256 amountToSpend) internal {\n // ETH Chad doesn't require your approval\n if (token == ETH_ADDRESS) return;\n // No-op if allowance is already sufficient\n uint256 allowance = IERC20(token).allowance(address(this), spender);\n if (allowance \u003e= amountToSpend) return;\n // Otherwise, reset approval to 0 and set to max allowance\n if (allowance \u003e 0) IERC20(token).safeDecreaseAllowance(spender, allowance);\n IERC20(token).safeIncreaseAllowance(spender, type(uint256).max);\n }\n\n /// @notice Returns the balance of the given token (or native ETH) for the given account.\n function universalBalanceOf(address token, address account) internal view returns (uint256) {\n if (token == ETH_ADDRESS) {\n return account.balance;\n } else {\n return IERC20(token).balanceOf(account);\n }\n }\n\n /// @dev Checks that token is a contract and not ETH_ADDRESS.\n function assertIsContract(address token) internal view {\n // Check that ETH_ADDRESS was not used (in case this is a predeploy on any of the chains)\n if (token == UniversalTokenLib.ETH_ADDRESS) revert TokenNotContract();\n // Check that token is not an EOA\n if (token.code.length == 0) revert TokenNotContract();\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/Admin.sol\n\ncontract Admin is IAdmin, AccessControlEnumerable {\n using UniversalTokenLib for address;\n\n bytes32 public constant RELAYER_ROLE = keccak256(\"RELAYER_ROLE\");\n bytes32 public constant REFUNDER_ROLE = keccak256(\"REFUNDER_ROLE\");\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n uint256 public constant FEE_BPS = 1e6;\n uint256 public constant FEE_RATE_MAX = 0.01e6; // max 1% on origin amount\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Chain gas amount to forward as rebate if requested\n uint256 public chainGasAmount;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n }\n\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n require(newFeeRate \u003c= FEE_RATE_MAX, \"newFeeRate \u003e max\");\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n token.universalTransfer(recipient, feeAmount);\n emit FeesSwept(token, recipient, feeAmount);\n }\n\n function setChainGasAmount(uint256 newChainGasAmount) external onlyRole(GOVERNOR_ROLE) {\n uint256 oldChainGasAmount = chainGasAmount;\n chainGasAmount = newChainGasAmount;\n emit ChainGasAmountUpdated(oldChainGasAmount, newChainGasAmount);\n }\n}\n\n// contracts/FastBridge.sol\n\ncontract FastBridge is IFastBridge, MulticallTarget, Admin {\n using SafeERC20 for IERC20;\n using UniversalTokenLib for address;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Delay for a transaction after which it could be permisionlessly refunded\n uint256 public constant REFUND_DELAY = 7 days;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeStatus) public bridgeStatuses;\n /// @notice Proof of relayed bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeProof) public bridgeProofs;\n /// @notice Whether bridge has been relayed on destination chain\n mapping(bytes32 =\u003e bool) public bridgeRelays;\n\n /// @dev to prevent replays\n uint256 public nonce;\n // @dev the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @notice Pulls a requested token from the user to the requested recipient.\n /// @dev Be careful of re-entrancy issues when msg.value \u003e 0 and recipient != address(this)\n function _pullToken(address recipient, address token, uint256 amount) internal returns (uint256 amountPulled) {\n if (token != UniversalTokenLib.ETH_ADDRESS) {\n token.assertIsContract();\n // Record token balance before transfer\n amountPulled = IERC20(token).balanceOf(recipient);\n // Token needs to be pulled only if msg.value is zero\n // This way user can specify WETH as the origin asset\n IERC20(token).safeTransferFrom(msg.sender, recipient, amount);\n // Use the difference between the recorded balance and the current balance as the amountPulled\n amountPulled = IERC20(token).balanceOf(recipient) - amountPulled;\n } else {\n // Otherwise, we need to check that ETH amount matches msg.value\n if (amount != msg.value) revert MsgValueIncorrect();\n // Transfer value to recipient if not this address\n if (recipient != address(this)) token.universalTransfer(recipient, amount);\n // We will forward msg.value in the external call later, if recipient is not this contract\n amountPulled = msg.value;\n }\n }\n\n /// @inheritdoc IFastBridge\n function getBridgeTransaction(bytes memory request) public pure returns (BridgeTransaction memory) {\n return abi.decode(request, (BridgeTransaction));\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n // check bridge params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n\n // transfer tokens to bridge contract\n // @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _pullToken(address(this), params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n\n // set status to requested\n bytes memory request = abi.encode(\n BridgeTransaction({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n sendChainGas: params.sendChainGas,\n deadline: params.deadline,\n nonce: nonce++ // increment nonce on every bridge\n })\n );\n bytes32 transactionId = keccak256(request);\n bridgeStatuses[transactionId] = BridgeStatus.REQUESTED;\n\n emit BridgeRequested(\n transactionId,\n params.sender,\n request,\n params.dstChainId,\n params.originToken,\n params.destToken,\n originAmount,\n params.destAmount,\n params.sendChainGas\n );\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes memory request) external payable onlyRole(RELAYER_ROLE) {\n bytes32 transactionId = keccak256(request);\n BridgeTransaction memory transaction = getBridgeTransaction(request);\n if (transaction.destChainId != uint32(block.chainid)) revert ChainIncorrect();\n\n // check haven't exceeded deadline for relay to happen\n if (block.timestamp \u003e transaction.deadline) revert DeadlineExceeded();\n\n // mark bridge transaction as relayed\n if (bridgeRelays[transactionId]) revert TransactionRelayed();\n bridgeRelays[transactionId] = true;\n\n // transfer tokens to recipient on destination chain and gas rebate if requested\n address to = transaction.destRecipient;\n address token = transaction.destToken;\n uint256 amount = transaction.destAmount;\n\n uint256 rebate = chainGasAmount;\n if (!transaction.sendChainGas) {\n // forward erc20\n rebate = 0;\n _pullToken(to, token, amount);\n } else if (token == UniversalTokenLib.ETH_ADDRESS) {\n // lump in gas rebate into amount in native gas token\n _pullToken(to, token, amount + rebate);\n } else {\n // forward erc20 then forward gas rebate in native gas token\n _pullToken(to, token, amount);\n _pullToken(to, UniversalTokenLib.ETH_ADDRESS, rebate);\n }\n\n emit BridgeRelayed(\n transactionId,\n msg.sender,\n to,\n transaction.originChainId,\n transaction.originToken,\n transaction.destToken,\n transaction.originAmount,\n transaction.destAmount,\n rebate\n );\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes memory request, bytes32 destTxHash) external onlyRole(RELAYER_ROLE) {\n bytes32 transactionId = keccak256(request);\n // update bridge tx status given proof provided\n if (bridgeStatuses[transactionId] != BridgeStatus.REQUESTED) revert StatusIncorrect();\n bridgeStatuses[transactionId] = BridgeStatus.RELAYER_PROVED;\n bridgeProofs[transactionId] = BridgeProof({timestamp: uint96(block.timestamp), relayer: msg.sender}); // overflow ok\n\n emit BridgeProofProvided(transactionId, msg.sender, destTxHash);\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint96(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint96).max but\n /// proof.timestamp \u003c type(uint96).max via unchecked statement\n /// @param proof The bridge proof\n /// @return delta Time delta since proof submitted\n function _timeSince(BridgeProof memory proof) internal view returns (uint256 delta) {\n unchecked {\n delta = uint96(block.timestamp) - proof.timestamp;\n }\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n if (bridgeStatuses[transactionId] != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n BridgeProof memory proof = bridgeProofs[transactionId];\n if (proof.relayer != relayer) revert SenderIncorrect();\n return _timeSince(proof) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes memory request, address to) external onlyRole(RELAYER_ROLE) {\n bytes32 transactionId = keccak256(request);\n BridgeTransaction memory transaction = getBridgeTransaction(request);\n\n // update bridge tx status if able to claim origin collateral\n if (bridgeStatuses[transactionId] != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n\n BridgeProof memory proof = bridgeProofs[transactionId];\n if (proof.relayer != msg.sender) revert SenderIncorrect();\n if (_timeSince(proof) \u003c= DISPUTE_PERIOD) revert DisputePeriodNotPassed();\n\n bridgeStatuses[transactionId] = BridgeStatus.RELAYER_CLAIMED;\n\n // update protocol fees if origin fee amount exists\n if (transaction.originFeeAmount \u003e 0) protocolFees[transaction.originToken] += transaction.originFeeAmount;\n\n // transfer origin collateral less fee to specified address\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositClaimed(transactionId, msg.sender, to, token, amount);\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n if (bridgeStatuses[transactionId] != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(bridgeProofs[transactionId]) \u003e DISPUTE_PERIOD) revert DisputePeriodPassed();\n\n // @dev relayer gets slashed effectively if dest relay has gone thru\n bridgeStatuses[transactionId] = BridgeStatus.REQUESTED;\n delete bridgeProofs[transactionId];\n\n emit BridgeProofDisputed(transactionId, msg.sender);\n }\n\n /// @inheritdoc IFastBridge\n function refund(bytes memory request) external {\n bytes32 transactionId = keccak256(request);\n BridgeTransaction memory transaction = getBridgeTransaction(request);\n\n if (hasRole(REFUNDER_ROLE, msg.sender)) {\n // Refunder can refund if deadline has passed\n if (block.timestamp \u003c= transaction.deadline) revert DeadlineNotExceeded();\n } else {\n // Permissionless refund is allowed after REFUND_DELAY\n if (block.timestamp \u003c= transaction.deadline + REFUND_DELAY) revert DeadlineNotExceeded();\n }\n\n // set status to refunded if still in requested state\n if (bridgeStatuses[transactionId] != BridgeStatus.REQUESTED) revert StatusIncorrect();\n bridgeStatuses[transactionId] = BridgeStatus.REFUNDED;\n\n // transfer origin collateral back to original sender\n address to = transaction.originSender;\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount + transaction.originFeeAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n }\n}\n\n// test/FastBridgeMock.sol\n\ncontract FastBridgeMock is IFastBridge, Admin {\n // @dev the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @dev to prevent replays\n uint256 public nonce;\n\n /// @notice We include an empty \"test\" function so that this contract does not appear in the coverage report.\n function testFastBridgeMock() external {}\n\n function getBridgeTransaction(bytes memory request) public pure returns (BridgeTransaction memory) {\n return abi.decode(request, (BridgeTransaction));\n }\n\n // used for testing in go.\n // see: https://ethereum.stackexchange.com/questions/21155/how-to-expose-enum-in-solidity-contract\n // make sure to update fastbridge/status.go if this changes\n // or underliyng enum changes.\n //\n // TODO: a foundry test should be added to ensure this is always in sync.\n function getEnumKeyByValue(FastBridge.BridgeStatus keyValue) public pure returns (string memory) {\n if (FastBridge.BridgeStatus.NULL == keyValue) return \"NULL\";\n if (FastBridge.BridgeStatus.REQUESTED == keyValue) return \"REQUESTED\";\n if (FastBridge.BridgeStatus.RELAYER_PROVED == keyValue) return \"RELAYER_PROVED\";\n if (FastBridge.BridgeStatus.RELAYER_CLAIMED == keyValue) return \"RELAYER_CLAIMED\";\n if (FastBridge.BridgeStatus.REFUNDED == keyValue) return \"REFUNDED\";\n return \"\";\n }\n\n function mockBridgeRequest(bytes32 transactionId, address sender, BridgeParams memory params) external {\n sender;\n uint256 originFeeAmount = (params.originAmount * protocolFeeRate) / FEE_BPS;\n params.originAmount -= originFeeAmount;\n\n bytes memory request = abi.encode(\n BridgeTransaction({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: params.originAmount, // includes relayer fee\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n sendChainGas: params.sendChainGas,\n deadline: params.deadline,\n nonce: nonce++ // increment nonce on every bridge\n })\n );\n\n emit BridgeRequested(\n transactionId,\n params.sender,\n request,\n params.dstChainId,\n params.originToken,\n params.destToken,\n params.originAmount,\n params.destAmount,\n params.sendChainGas\n );\n }\n\n function mockBridgeRequestRaw(bytes32 transactionId, address sender, bytes memory request) external {\n sender;\n BridgeTransaction memory transaction = getBridgeTransaction(request);\n emit BridgeRequested(\n transactionId,\n transaction.originSender,\n request,\n transaction.destChainId,\n transaction.originToken,\n transaction.destToken,\n transaction.originAmount,\n transaction.destAmount,\n transaction.sendChainGas\n );\n }\n\n function mockBridgeRelayer(\n bytes32 transactionId,\n address relayer,\n address to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n )\n external\n {\n emit BridgeRelayed(\n transactionId, relayer, to, originChainId, originToken, destToken, originAmount, destAmount, chainGasAmount\n );\n }\n\n function bridge(BridgeParams memory) external payable {\n revert(\"not implemented\");\n }\n\n function relay(bytes memory) external payable {\n revert(\"not implemented\");\n }\n\n function prove(bytes memory, bytes32) external pure {\n revert(\"not implemented\");\n }\n\n function canClaim(bytes32, address) external pure returns (bool) {\n revert(\"not implemented\");\n }\n\n function claim(bytes memory, address) external pure {\n revert(\"not implemented\");\n }\n\n function dispute(bytes32) external pure {\n revert(\"not implemented\");\n }\n\n function refund(bytes memory) external pure {\n revert(\"not implemented\");\n }\n}\n","language":"Solidity","languageVersion":"0.8.20","compilerVersion":"0.8.20","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"62813:11321:0:-:0;;;64005:85;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;64039:6;61804:38;50976:4;64039:6;61804:10;:38::i;:::-;-1:-1:-1;;64071:12:0::1;64057:26;::::0;-1:-1:-1;62813:11321:0;;60289:257;60375:4;;60406:31;60423:4;60429:7;60406:16;:31::i;:::-;60391:46;;60451:7;60447:69;;;60474:18;;;;:12;:18;;;;;:31;;60497:7;60474:22;:31::i;:::-;;60447:69;60532:7;-1:-1:-1;60289:257:0;;;;;:::o;54923:316::-;55000:4;51698:12;;;;;;;;;;;-1:-1:-1;;;;;51698:29:0;;;;;;;;;;;;55016:217;;55059:6;:12;;;;;;;;;;;-1:-1:-1;;;;;55059:29:0;;;;;;;;;:36;;-1:-1:-1;;55059:36:0;55091:4;55059:36;;;55141:12;22984:10;;22905:96;55141:12;-1:-1:-1;;;;;55114:40:0;55132:7;-1:-1:-1;;;;;55114:40:0;55126:4;55114:40;;;;;;;;;;-1:-1:-1;55175:4:0;55168:11;;55016:217;-1:-1:-1;55217:5:0;55210:12;;32429:150;32499:4;32522:50;32527:3;-1:-1:-1;;;;;32547:23:0;;26417:4;28473:21;;;:14;;;:21;;;;;;26433:321;;-1:-1:-1;26475:23:0;;;;;;;;:11;:23;;;;;;;;;;;;;26657:18;;26633:21;;;:14;;;:21;;;;;;:42;;;;26689:11;;14:290:1;84:6;137:2;125:9;116:7;112:23;108:32;105:52;;;153:1;150;143:12;105:52;179:16;;-1:-1:-1;;;;;224:31:1;;214:42;;204:70;;270:1;267;260:12;14:290;62813:11321:0;;;;;;;;;;;;","srcMapRuntime":"62813:11321:0:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;58949:212;;;;;;;;;;-1:-1:-1;58949:212:0;;;;;:::i;:::-;;:::i;:::-;;;612:14:1;;605:22;587:41;;575:2;560:18;58949:212:0;;;;;;;;61179:60;;;;;;;;;;;;61216:23;61179:60;;;;;785:25:1;;;773:2;758:18;61179:60:0;639:177:1;63557:54:0;;;;;;;;;;-1:-1:-1;63557:54:0;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;:::i;62151:359::-;;;;;;;;;;-1:-1:-1;62151:359:0;;;;;:::i;:::-;;:::i;:::-;;61361:45;;;;;;;;;;;;61400:6;61361:45;;63155;;;;;;;;;;;;63194:6;63155:45;;52554:120;;;;;;;;;;-1:-1:-1;52554:120:0;;;;;:::i;:::-;52619:7;52645:12;;;;;;;;;;:22;;;;52554:120;52970:136;;;;;;;;;;-1:-1:-1;52970:136:0;;;;;:::i;:::-;;:::i;54072:245::-;;;;;;;;;;-1:-1:-1;54072:245:0;;;;;:::i;:::-;;:::i;39411:875::-;;;;;;;;;;-1:-1:-1;39411:875:0;;;;;:::i;:::-;;:::i;:::-;;;;;;;:::i;38010:718::-;;;;;;;;;;-1:-1:-1;38010:718:0;;;;;:::i;:::-;;:::i;71232:1146::-;;;;;;;;;;-1:-1:-1;71232:1146:0;;;;;:::i;:::-;;:::i;65690:2114::-;;;;;;:::i;:::-;;:::i;61523:30::-;;;;;;;;;;;;;;;;61107:66;;;;;;;;;;;;61147:26;61107:66;;72979:1153;;;;;;;;;;-1:-1:-1;72979:1153:0;;;;;:::i;:::-;;:::i;63287:56::-;;;;;;;;;;;;63333:10;63287:56;;63802:44;;;;;;;;;;-1:-1:-1;63802:44:0;;;;;:::i;:::-;;;;;;;;;;;;;;;;69598:567;;;;;;;;;;-1:-1:-1;69598:567:0;;;;;:::i;:::-;;:::i;67842:1718::-;;;;;;:::i;:::-;;:::i;59746:142::-;;;;;;;;;;-1:-1:-1;59746:142:0;;;;;:::i;:::-;;:::i;:::-;;;-1:-1:-1;;;;;9843:55:1;;;9825:74;;9813:2;9798:18;59746:142:0;9679:226:1;63676:51:0;;;;;;;;;;-1:-1:-1;63676:51:0;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;63676:51:0;;;;;;;10112:26:1;10100:39;;;10082:58;;-1:-1:-1;;;;;10176:55:1;;;10171:2;10156:18;;10149:83;10055:18;63676:51:0;9910:328:1;51598:136:0;;;;;;;;;;-1:-1:-1;51598:136:0;;;;;:::i;:::-;51675:4;51698:12;;;;;;;;;;;-1:-1:-1;;;;;51698:29:0;;;;;;;;;;;;;;;51598:136;61037:64;;;;;;;;;;;;61076:25;61037:64;;50931:49;;;;;;;;;;-1:-1:-1;50931:49:0;50976:4;50931:49;;63962:36;;;;;;;;;;;;;;;70821:373;;;;;;;;;;-1:-1:-1;70821:373:0;;;;;:::i;:::-;;:::i;65489:163::-;;;;;;;;;;-1:-1:-1;65489:163:0;;;;;:::i;:::-;;:::i;:::-;;;;;;;:::i;72416:525::-;;;;;;;;;;-1:-1:-1;72416:525:0;;;;;:::i;:::-;;:::i;63885:20::-;;;;;;;;;;;;;;;;61855:290;;;;;;;;;;-1:-1:-1;61855:290:0;;;;;:::i;:::-;;:::i;62516:264::-;;;;;;;;;;-1:-1:-1;62516:264:0;;;;;:::i;:::-;;:::i;61318:37::-;;;;;;;;;;;;61352:3;61318:37;;60056:131;;;;;;;;;;-1:-1:-1;60056:131:0;;;;;:::i;:::-;;:::i;61245:66::-;;;;;;;;;;;;61285:26;61245:66;;53386:138;;;;;;;;;;-1:-1:-1;53386:138:0;;;;;:::i;:::-;;:::i;61609:47::-;;;;;;;;;;-1:-1:-1;61609:47:0;;;;;:::i;:::-;;;;;;;;;;;;;;61730:29;;;;;;;;;;;;;;;;58949:212;59034:4;59057:57;;;59072:42;59057:57;;:97;;;59118:36;59142:11;59118:23;:36::i;:::-;59050:104;58949:212;-1:-1:-1;;58949:212:0:o;62151:359::-;61285:26;51208:16;51219:4;51208:10;:16::i;:::-;-1:-1:-1;;;;;62275:19:0;::::1;62255:17;62275:19:::0;;;:12:::1;:19;::::0;;;;;;62308:14;;;62304:27:::1;;62324:7;62151:359:::0;;;:::o;62304:27::-:1;-1:-1:-1::0;;;;;62372:19:0;::::1;62394:1;62372:19:::0;;;:12:::1;:19;::::0;;;;:23;62405:45:::1;::::0;62429:9;62440;62405:23:::1;:45::i;:::-;62465:38;::::0;;-1:-1:-1;;;;;12438:15:1;;;12420:34;;12490:15;;12485:2;12470:18;;12463:43;12522:18;;;12515:34;;;62465:38:0::1;::::0;12347:2:1;12332:18;62465:38:0::1;;;;;;;62245:265;51234:1;62151:359:::0;;;:::o;52970:136::-;52619:7;52645:12;;;;;;;;;;:22;;;51208:16;51219:4;51208:10;:16::i;:::-;53074:25:::1;53085:4;53091:7;53074:10;:25::i;:::-;;52970:136:::0;;;:::o;54072:245::-;-1:-1:-1;;;;;54165:34:0;;22984:10;54165:34;54161:102;;54222:30;;;;;;;;;;;;;;54161:102;54273:37;54285:4;54291:18;54273:11;:37::i;39411:875::-;39540:23;39602:4;39589:25;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;;;;;;;;;;;;;39589:25:0;;;;;;;;;;;;;;;;39579:35;;39629:9;39624:656;39644:15;;;39624:656;;;40117:4;40136;;40141:1;40136:7;;;;;;;:::i;:::-;;;;;;;;;;;;:::i;:::-;40109:35;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;40064:7;40072:1;40064:10;;;;;;;;:::i;:::-;;;;;;;:18;;40084:7;40092:1;40084:10;;;;;;;;:::i;:::-;;;;;;;:21;;40063:81;;;;;;;;;;;;;40163:7;40171:1;40163:10;;;;;;;;:::i;:::-;;;;;;;:18;;;40162:19;:37;;;;;40186:13;40185:14;40162:37;40158:112;;;40219:36;40233:7;40241:1;40233:10;;;;;;;;:::i;:::-;;;;;;;:21;;;40219:13;:36::i;:::-;39661:3;;;:::i;:::-;;;39624:656;;;;39411:875;;;;;:::o;38010:718::-;38105:9;38100:622;38120:15;;;38100:622;;;38540:12;;38585:4;38604;;38609:1;38604:7;;;;;;;:::i;:::-;;;;;;;;;;;;:::i;:::-;38577:35;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;38539:73;;;;38631:7;38630:8;:26;;;;;38643:13;38642:14;38630:26;38626:86;;;38676:21;38690:6;38676:13;:21::i;:::-;38142:580;;38137:3;;;;:::i;:::-;;;38100:622;;71232:1146;61076:25;51208:16;51219:4;51208:10;:16::i;:::-;71347:18;;::::1;::::0;::::1;::::0;71323:21:::1;71414:29;71357:7:::0;71414:20:::1;:29::i;:::-;71375:68:::0;-1:-1:-1;71561:27:0::1;71528:29;::::0;;;:14:::1;:29;::::0;;;;;::::1;;:60;::::0;::::1;;;;;;:::i;:::-;;71524:90;;71597:17;;;;;;;;;;;;;;71524:90;71625:24;71652:27:::0;;;:12:::1;:27;::::0;;;;;;;;71625:54;;;;::::1;::::0;;;;::::1;::::0;::::1;::::0;;;;::::1;-1:-1:-1::0;;;;;71625:54:0::1;::::0;;::::1;::::0;;;71710:10:::1;71693:27;71689:57;;71729:17;;;;;;;;;;;;;;71689:57;70751:15:::0;;63049:10:::1;::::0;70732:15;70725:41;70717:49;;71760:35:::1;71756:72;;71804:24;;;;;;;;;;;;;;71756:72;71839:29;::::0;;;:14:::1;:29;::::0;;;;:60;;-1:-1:-1;;71839:60:0::1;71871:28;71839:60;::::0;;71974:27:::1;::::0;::::1;::::0;:31;71970:105:::1;;72048:27;::::0;::::1;::::0;72020:23:::1;::::0;::::1;::::0;-1:-1:-1;;;;;72007:37:0::1;;::::0;;;:12:::1;:37;::::0;;;;:68;;:37;;;:68:::1;::::0;72048:27;;72007:68:::1;:::i;:::-;::::0;;;-1:-1:-1;;71970:105:0::1;72170:23;::::0;::::1;::::0;72220:24:::1;::::0;::::1;::::0;72254:35:::1;-1:-1:-1::0;;;;;72254:23:0;::::1;72278:2:::0;72220:24;72254:23:::1;:35::i;:::-;72305:66;::::0;;-1:-1:-1;;;;;14321:55:1;;;14303:74;;14408:2;14393:18;;14386:34;;;72305:66:0;::::1;::::0;72341:10:::1;::::0;72326:13;;72305:66:::1;::::0;14276:18:1;72305:66:0::1;;;;;;;;71313:1065;;;;;71232:1146:::0;;;:::o;65690:2114::-;65817:13;65796:6;:17;;;:34;;;65792:63;;65839:16;;;;;;;;;;;;;;65792:63;65869:19;;;;:24;;:50;;-1:-1:-1;65897:17:0;;;;:22;65869:50;65865:80;;;65928:17;;;;;;;;;;;;;;65865:80;65959:18;;;;-1:-1:-1;;;;;65959:32:0;;;:66;;-1:-1:-1;65995:16:0;;;;-1:-1:-1;;;;;65995:30:0;;65959:66;65955:92;;;66034:13;;;;;;;;;;;;;;65955:92;66079:37;63333:10;66079:15;:37;:::i;:::-;66061:6;:15;;;:55;66057:86;;;66125:18;;;;;;;;;;;;;;66057:86;66278:20;66301:66;66320:4;66327:6;:18;;;66347:6;:19;;;66301:10;:66::i;:::-;66278:89;;66435:23;66490:1;66472:15;;:19;66468:85;;;61352:3;66527:15;;66512:12;:30;;;;:::i;:::-;66511:42;;;;:::i;:::-;66493:60;;66468:85;66563:31;66579:15;66563:31;;:::i;:::-;;;66707:20;66754:618;;;;;;;;66812:13;66754:618;;;;;;66857:6;:17;;;66754:618;;;;;;66906:6;:13;;;-1:-1:-1;;;;;66754:618:0;;;;;66952:6;:9;;;-1:-1:-1;;;;;66754:618:0;;;;;66992:6;:18;;;-1:-1:-1;;;;;66754:618:0;;;;;67039:6;:16;;;-1:-1:-1;;;;;66754:618:0;;;;;67087:12;66754:618;;;;67129:6;:17;;;66754:618;;;;67181:15;66754:618;;;;67228:6;:19;;;66754:618;;;;;;67275:6;:15;;;66754:618;;;;67315:5;;:7;;;;;;;;;:::i;:::-;;;;-1:-1:-1;66754:618:0;;66730:652;;;;;;;;:::i;:::-;;;;;;;;;;;;;;67416:18;;66730:652;67416:18;;;;;;;67392:21;67444:29;;;:14;:29;;;;;;:54;;-1:-1:-1;;67444:54:0;67476:22;67444:54;;;67570:13;;;67618:17;;67649:18;;;;67681:16;;;;67737:17;;;;67768:19;;;;66730:652;;-1:-1:-1;67416:18:0;;-1:-1:-1;;;;;67514:283:0;;;;67416:18;;67514:283;;;;66730:652;;67618:17;;67649:18;;67681:16;;67711:12;;67514:283;:::i;:::-;;;;;;;;65751:2053;;;;65690:2114;:::o;72979:1153::-;73060:18;;;;;;73036:21;73127:29;73070:7;73127:20;:29::i;:::-;73194:10;51675:4;51698:29;;;:12;;:29;:12;:29;;;73088:68;;-1:-1:-1;51698:29:0;;73167:382;;;73302:11;:20;;;73283:15;:39;73279:73;;73331:21;;;;;;;;;;;;;;73279:73;73167:382;;;63194:6;73473:11;:20;;;:35;;;;:::i;:::-;73454:15;:54;73450:88;;73517:21;;;;;;;;;;;;;;73450:88;73658:22;73625:29;;;;:14;:29;;;;;;;;:55;;;;;;;;:::i;:::-;;73621:85;;73689:17;;;;;;;;;;;;;;73621:85;73716:29;;;;:14;:29;;;;;;:53;;-1:-1:-1;;73716:53:0;73748:21;73716:53;;;73855:24;;;73905:23;;;;73982:27;;;;73955:24;;;;73855;;73905:23;;73955:54;;73982:27;73955:54;:::i;:::-;73938:71;-1:-1:-1;74019:35:0;-1:-1:-1;;;;;74019:23:0;;74043:2;73938:71;74019:23;:35::i;:::-;74070:55;;;-1:-1:-1;;;;;14321:55:1;;;14303:74;;14408:2;14393:18;;14386:34;;;74070:55:0;;;74092:13;;74070:55;;14276:18:1;74070:55:0;;;;;;;73026:1106;;;;;72979:1153;:::o;69598:567::-;61076:25;51208:16;51219:4;51208:10;:16::i;:::-;69721:18;;::::1;::::0;::::1;::::0;69842:22:::1;69809:29;::::0;;;:14:::1;:29;::::0;;;;;::::1;;:55;::::0;::::1;;;;;;:::i;:::-;;69805:85;;69873:17;;;;;;;;;;;;;;69805:85;69900:29;::::0;;;:14:::1;:29;::::0;;;;;;;:59;;69932:27:::1;-1:-1:-1::0;;69900:59:0;;::::1;;::::0;;69999:70;;;;::::1;::::0;;::::1;70030:15;69999:70:::0;::::1;::::0;;70057:10:::1;69999:70:::0;;::::1;::::0;;;69969:27;;;:12:::1;:27:::0;;;;;;:100;;;;-1:-1:-1;;;;;69969:100:0::1;::::0;::::1;::::0;;;::::1;::::0;;;::::1;::::0;;70100:58;785:25:1;;;69900:29:0;;70100:58:::1;::::0;758:18:1;70100:58:0::1;;;;;;;69687:478;69598:567:::0;;;:::o;67842:1718::-;61076:25;51208:16;51219:4;51208:10;:16::i;:::-;67953:18;;::::1;::::0;::::1;::::0;67929:21:::1;68020:29;67963:7:::0;68020:20:::1;:29::i;:::-;67981:68;;68097:13;68063:48;;:11;:23;;;:48;;;68059:77;;68120:16;;;;;;;;;;;;;;68059:77;68232:11;:20;;;68214:15;:38;68210:69;;;68261:18;;;;;;;;;;;;;;68210:69;68340:27;::::0;;;:12:::1;:27;::::0;;;;;::::1;;68336:60;;;68376:20;;;;;;;;;;;;;;68336:60;68406:27;::::0;;;:12:::1;:27;::::0;;;;:34;;-1:-1:-1;;68406:34:0::1;68436:4;68406:34;::::0;;68553:25:::1;::::0;::::1;::::0;68604:21:::1;::::0;::::1;::::0;68652:22:::1;::::0;::::1;::::0;68702:14:::1;::::0;68731:24:::1;::::0;::::1;::::0;68726:517:::1;;-1:-1:-1::0;68809:1:0::1;68824:29;68835:2:::0;68839:5;68846:6;68824:10:::1;:29::i;:::-;;68726:517;;;68874:38:::0;-1:-1:-1;;;;;68874:38:0;::::1;::::0;68870:373:::1;;68994:38;69005:2:::0;69009:5;69016:15:::1;69025:6:::0;69016;:15:::1;:::i;:::-;68994:10;:38::i;68870:373::-;69136:29;69147:2;69151:5;69158:6;69136:10;:29::i;:::-;;69179:53;69190:2;55938:42;69225:6;69179:10;:53::i;:::-;;68870:373;69352:25:::0;;69391:23:::1;::::0;;::::1;::::0;69428:21:::1;::::0;;::::1;::::0;69463:24:::1;::::0;;::::1;::::0;69501:22:::1;::::0;::::1;::::0;69258:295:::1;::::0;;16088:10:1;16076:23;;;16058:42;;-1:-1:-1;;;;;16197:15:1;;;16192:2;16177:18;;16170:43;16249:15;;;16229:18;;;16222:43;;;;16296:2;16281:18;;16274:34;16324:19;;;16317:35;16368:19;;16361:35;;;69258:295:0;::::1;::::0;69312:10:::1;::::0;69285:13;;69258:295:::1;::::0;16030:19:1;69258:295:0::1;15773:629:1::0;59746:142:0;59827:7;59853:18;;;:12;:18;;;;;:28;;59875:5;59853:21;:28::i;:::-;59846:35;59746:142;-1:-1:-1;;;59746:142:0:o;70821:373::-;70902:4;70955:27;70922:29;;;;:14;:29;;;;;;;;:60;;;;;;;;:::i;:::-;;70918:90;;70991:17;;;;;;;;;;;;;;70918:90;71018:24;71045:27;;;:12;:27;;;;;;;;;71018:54;;;;;;;;;;;;;;-1:-1:-1;;;;;71018:54:0;;;;;;;;;;;;71086:24;;;71082:54;;71119:17;;;;;;;;;;;;;;71082:54;70751:15;;63049:10;;70732:15;70725:41;70717:49;;71153:34;;70821:373;-1:-1:-1;;;;70821:373:0:o;65489:163::-;-1:-1:-1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;65605:40:0;;-1:-1:-1;;65605:40:0;;;;;;;;;;:::i;72416:525::-;61216:23;51208:16;51219:4;51208:10;:16::i;:::-;72533:27:::1;72500:29;::::0;;;:14:::1;:29;::::0;;;;;::::1;;:60;::::0;::::1;;;;;;:::i;:::-;;72496:90;;72569:17;;;;;;;;;;;;;;72496:90;72611:27;::::0;;;:12:::1;:27;::::0;;;;;;;;72600:39;;;;::::1;::::0;;;;::::1;::::0;;::::1;::::0;;;;;;::::1;-1:-1:-1::0;;;;;72600:39:0::1;::::0;;;::::1;::::0;;;;63049:10:::1;::::0;70732:15;70725:41;70717:49;72600:56:::1;72596:90;;;72665:21;;;;;;;;;;;;;;72596:90;72774:29;::::0;;;:14:::1;:29;::::0;;;;;;;:54;;-1:-1:-1;;72774:54:0::1;72806:22;72774:54;::::0;;72845:12:::1;:27:::0;;;;;;72838:34;;;72888:46;72923:10:::1;::::0;72774:29;;72888:46:::1;::::0;72774:29;72888:46:::1;72416:525:::0;;:::o;61855:290::-;61285:26;51208:16;51219:4;51208:10;:16::i;:::-;61400:6:::1;61954:10;:26;;61946:55;;;::::0;::::1;::::0;;18223:2:1;61946:55:0::1;::::0;::::1;18205:21:1::0;18262:2;18242:18;;;18235:30;18301:18;18281;;;18274:46;18337:18;;61946:55:0::1;;;;;;;;;62032:15;::::0;;62057:28;;;;62100:38:::1;::::0;;18540:25:1;;;18596:2;18581:18;;18574:34;;;62100:38:0::1;::::0;18513:18:1;62100:38:0::1;;;;;;;;61936:209;61855:290:::0;;:::o;62516:264::-;61285:26;51208:16;51219:4;51208:10;:16::i;:::-;62641:14:::1;::::0;;62665:34;;;;62714:59:::1;::::0;;18540:25:1;;;18596:2;18581:18;;18574:34;;;62714:59:0::1;::::0;18513:18:1;62714:59:0::1;18366:248:1::0;60056:131:0;60127:7;60153:18;;;:12;:18;;;;;:27;;:25;:27::i;53386:138::-;52619:7;52645:12;;;;;;;;;;:22;;;51208:16;51219:4;51208:10;:16::i;:::-;53491:26:::1;53503:4;53509:7;53491:11;:26::i;51309:202::-:0;51394:4;51417:47;;;51432:32;51417:47;;:87;;-1:-1:-1;43224:25:0;43209:40;;;;51468:36;43110:146;51943:103;52009:30;52020:4;22984:10;52009;:30::i;:::-;51943:103;:::o;56221:653::-;56396:4;-1:-1:-1;;;;;56382:19:0;;;56378:32;;56221:653;;;:::o;56378:32::-;56482:5;56491:1;56482:10;56478:23;;56221:653;;;:::o;56478:23::-;56514:20;-1:-1:-1;;;;;56514:20:0;;;56510:358;;56694:12;56711:2;-1:-1:-1;;;;;56711:7:0;56726:5;56711:25;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;56693:43;;;56758:7;56750:39;;;;;;;19031:2:1;56750:39:0;;;19013:21:1;19070:2;19050:18;;;19043:30;19109:21;19089:18;;;19082:49;19148:18;;56750:39:0;18829:343:1;56510:358:0;56820:37;-1:-1:-1;;;;;56820:26:0;;56847:2;56851:5;56820:26;:37::i;60289:257::-;60375:4;60391:12;60406:31;60423:4;60429:7;60406:16;:31::i;:::-;60391:46;;60451:7;60447:69;;;60474:18;;;;:12;:18;;;;;:31;;60497:7;60474:22;:31::i;60649:262::-;60736:4;60752:12;60767:32;60785:4;60791:7;60767:17;:32::i;:::-;60752:47;;60813:7;60809:72;;;60836:18;;;;:12;:18;;;;;:34;;60862:7;60836:25;:34::i;40560:556::-;40698:17;;:21;40694:416;;40939:10;40933:17;40995:15;40982:10;40978:2;40974:19;40967:44;40694:416;41062:37;;;;;;;;;;;;;;64274:1177;64362:20;-1:-1:-1;;;;;64398:38:0;;55938:42;64398:38;64394:1051;;64452:24;:5;-1:-1:-1;;;;;64452:22:0;;:24::i;:::-;64557:34;;;;;-1:-1:-1;;;;;9843:55:1;;;64557:34:0;;;9825:74:1;64557:23:0;;;;;9798:18:1;;64557:34:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;64542:49;-1:-1:-1;64737:61:0;-1:-1:-1;;;;;64737:30:0;;64768:10;64780:9;64791:6;64737:30;:61::i;:::-;64934:34;;;;;-1:-1:-1;;;;;9843:55:1;;;64934:34:0;;;9825:74:1;64971:12:0;;64934:23;;;;;;9798:18:1;;64934:34:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;:49;;;;:::i;:::-;64919:64;;64394:1051;;;65105:9;65095:6;:19;65091:51;;65123:19;;;;;;;;;;;;;;65091:51;-1:-1:-1;;;;;65223:26:0;;65244:4;65223:26;65219:74;;65251:42;-1:-1:-1;;;;;65251:23:0;;65275:9;65286:6;65251:23;:42::i;:::-;-1:-1:-1;65425:9:0;64274:1177;;;;;:::o;33687:156::-;33761:7;33811:22;33815:3;33827:5;33811:3;:22::i;33230:115::-;33293:7;33319:19;33327:3;28669:18;;28587:107;52176:197;51675:4;51698:12;;;;;;;;;;;-1:-1:-1;;;;;51698:29:0;;;;;;;;;;;;52259:108;;52309:47;;;;;-1:-1:-1;;;;;14321:55:1;;52309:47:0;;;14303:74:1;14393:18;;;14386:34;;;14276:18;;52309:47:0;14129:297:1;52259:108:0;52176:197;;:::o;44426:160::-;44535:43;;-1:-1:-1;;;;;14321:55:1;;;44535:43:0;;;14303:74:1;14393:18;;;14386:34;;;44508:71:0;;44528:5;;44550:14;;;;;14276:18:1;;44535:43:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;44508:19;:71::i;54923:316::-;55000:4;51698:12;;;;;;;;;;;-1:-1:-1;;;;;51698:29:0;;;;;;;;;;;;55016:217;;55059:6;:12;;;;;;;;;;;-1:-1:-1;;;;;55059:29:0;;;;;;;;;:36;;-1:-1:-1;;55059:36:0;55091:4;55059:36;;;55141:12;22984:10;;22905:96;55141:12;-1:-1:-1;;;;;55114:40:0;55132:7;-1:-1:-1;;;;;55114:40:0;55126:4;55114:40;;;;;;;;;;-1:-1:-1;55175:4:0;55168:11;;55016:217;-1:-1:-1;55217:5:0;55210:12;;32429:150;32499:4;32522:50;32527:3;-1:-1:-1;;;;;32547:23:0;;32522:4;:50::i;55474:317::-;55552:4;51698:12;;;;;;;;;;;-1:-1:-1;;;;;51698:29:0;;;;;;;;;;;;55568:217;;;55642:5;55610:12;;;;;;;;;;;-1:-1:-1;;;;;55610:29:0;;;;;;;;;;:37;;-1:-1:-1;;55610:37:0;;;55666:40;22984:10;;55610:12;;55666:40;;55642:5;55666:40;-1:-1:-1;55727:4:0;55720:11;;32747:156;32820:4;32843:53;32851:3;-1:-1:-1;;;;;32871:23:0;;32843:7;:53::i;58038:344::-;58205:38;-1:-1:-1;;;;;58205:38:0;;;58201:69;;58252:18;;;;;;;;;;;;;;58201:69;58326:5;-1:-1:-1;;;;;58326:17:0;;58347:1;58326:22;58322:53;;58357:18;;;;;;;;;;;;;;44825:188;44952:53;;-1:-1:-1;;;;;12438:15:1;;;44952:53:0;;;12420:34:1;12490:15;;;12470:18;;;12463:43;12522:18;;;12515:34;;;44925:81:0;;44945:5;;44967:18;;;;;12332::1;;44952:53:0;12157:398:1;29036:118:0;29103:7;29129:3;:11;;29141:5;29129:18;;;;;;;;:::i;:::-;;;;;;;;;29122:25;;29036:118;;;;:::o;47182:629::-;47601:23;47627:33;-1:-1:-1;;;;;47627:27:0;;47655:4;47627:27;:33::i;:::-;47601:59;;47674:10;:17;47695:1;47674:22;;:57;;;;;47712:10;47701:30;;;;;;;;;;;;:::i;:::-;47700:31;47674:57;47670:135;;;47754:40;;;;;-1:-1:-1;;;;;9843:55:1;;47754:40:0;;;9825:74:1;9798:18;;47754:40:0;9679:226:1;26354:406:0;26417:4;28473:21;;;:14;;;:21;;;;;;26433:321;;-1:-1:-1;26475:23:0;;;;;;;;:11;:23;;;;;;;;;;;;;26657:18;;26633:21;;;:14;;;:21;;;;;;:42;;;;26689:11;;26928:1368;26994:4;27123:21;;;:14;;;:21;;;;;;27159:13;;27155:1135;;27526:18;27547:12;27558:1;27547:8;:12;:::i;:::-;27593:18;;27526:33;;-1:-1:-1;27573:17:0;;27593:22;;27614:1;;27593:22;:::i;:::-;27573:42;;27648:9;27634:10;:23;27630:378;;27677:17;27697:3;:11;;27709:9;27697:22;;;;;;;;:::i;:::-;;;;;;;;;27677:42;;27844:9;27818:3;:11;;27830:10;27818:23;;;;;;;;:::i;:::-;;;;;;;;;;;;:35;;;;27957:25;;;:14;;;:25;;;;;:36;;;27630:378;28086:17;;:3;;:17;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;28189:3;:14;;:21;28204:5;28189:21;;;;;;;;;;;28182:28;;;28232:4;28225:11;;;;;;;27155:1135;28274:5;28267:12;;;;;18690:151;18765:12;18796:38;18818:6;18826:4;18832:1;18765:12;19406;19420:23;19447:6;-1:-1:-1;;;;;19447:11:0;19466:5;19473:4;19447:31;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;19405:73;;;;19495:55;19522:6;19530:7;19539:10;19495:26;:55::i;:::-;19488:62;19165:392;-1:-1:-1;;;;;;19165:392:0:o;20610:582::-;20754:12;20783:7;20778:408;;20806:19;20814:10;20806:7;:19::i;:::-;20778:408;;;21030:17;;:22;:49;;;;-1:-1:-1;;;;;;21056:18:0;;;:23;21030:49;21026:119;;;21106:24;;;;;-1:-1:-1;;;;;9843:55:1;;21106:24:0;;;9825:74:1;9798:18;;21106:24:0;9679:226:1;21026:119:0;-1:-1:-1;21165:10:0;21158:17;;21728:516;21859:17;;:21;21855:383;;22087:10;22081:17;22143:15;22130:10;22126:2;22122:19;22115:44;21855:383;22210:17;;;;;;;;;;;;;;14:332:1;72:6;125:2;113:9;104:7;100:23;96:32;93:52;;;141:1;138;131:12;93:52;180:9;167:23;230:66;223:5;219:78;212:5;209:89;199:117;;312:1;309;302:12;821:180;880:6;933:2;921:9;912:7;908:23;904:32;901:52;;;949:1;946;939:12;901:52;-1:-1:-1;972:23:1;;821:180;-1:-1:-1;821:180:1:o;1006:184::-;1058:77;1055:1;1048:88;1155:4;1152:1;1145:15;1179:4;1176:1;1169:15;1195:402;1344:2;1329:18;;1377:1;1366:13;;1356:201;;1413:77;1410:1;1403:88;1514:4;1511:1;1504:15;1542:4;1539:1;1532:15;1356:201;1566:25;;;1195:402;:::o;1602:154::-;-1:-1:-1;;;;;1681:5:1;1677:54;1670:5;1667:65;1657:93;;1746:1;1743;1736:12;1761:134;1829:20;;1858:31;1829:20;1858:31;:::i;:::-;1761:134;;;:::o;1900:388::-;1968:6;1976;2029:2;2017:9;2008:7;2004:23;2000:32;1997:52;;;2045:1;2042;2035:12;1997:52;2084:9;2071:23;2103:31;2128:5;2103:31;:::i;:::-;2153:5;-1:-1:-1;2210:2:1;2195:18;;2182:32;2223:33;2182:32;2223:33;:::i;:::-;2275:7;2265:17;;;1900:388;;;;;:::o;2475:315::-;2543:6;2551;2604:2;2592:9;2583:7;2579:23;2575:32;2572:52;;;2620:1;2617;2610:12;2572:52;2656:9;2643:23;2633:33;;2716:2;2705:9;2701:18;2688:32;2729:31;2754:5;2729:31;:::i;2795:118::-;2881:5;2874:13;2867:21;2860:5;2857:32;2847:60;;2903:1;2900;2893:12;2918:128;2983:20;;3012:28;2983:20;3012:28;:::i;3051:761::-;3154:6;3162;3170;3223:2;3211:9;3202:7;3198:23;3194:32;3191:52;;;3239:1;3236;3229:12;3191:52;3279:9;3266:23;3308:18;3349:2;3341:6;3338:14;3335:34;;;3365:1;3362;3355:12;3335:34;3403:6;3392:9;3388:22;3378:32;;3448:7;3441:4;3437:2;3433:13;3429:27;3419:55;;3470:1;3467;3460:12;3419:55;3510:2;3497:16;3536:2;3528:6;3525:14;3522:34;;;3552:1;3549;3542:12;3522:34;3607:7;3600:4;3590:6;3587:1;3583:14;3579:2;3575:23;3571:34;3568:47;3565:67;;;3628:1;3625;3618:12;3565:67;3659:4;3651:13;;;;-1:-1:-1;3683:6:1;-1:-1:-1;;3724:20:1;;3711:34;3754:28;3711:34;3754:28;:::i;:::-;3801:5;3791:15;;;3051:761;;;;;:::o;3817:250::-;3902:1;3912:113;3926:6;3923:1;3920:13;3912:113;;;4002:11;;;3996:18;3983:11;;;3976:39;3948:2;3941:10;3912:113;;;-1:-1:-1;;4059:1:1;4041:16;;4034:27;3817:250::o;4072:329::-;4113:3;4151:5;4145:12;4178:6;4173:3;4166:19;4194:76;4263:6;4256:4;4251:3;4247:14;4240:4;4233:5;4229:16;4194:76;:::i;:::-;4315:2;4303:15;4320:66;4299:88;4290:98;;;;4390:4;4286:109;;4072:329;-1:-1:-1;;4072:329:1:o;4406:1097::-;4594:4;4623:2;4663;4652:9;4648:18;4693:2;4682:9;4675:21;4716:6;4751;4745:13;4782:6;4774;4767:22;4808:2;4798:12;;4841:2;4830:9;4826:18;4819:25;;4903:2;4893:6;4890:1;4886:14;4875:9;4871:30;4867:39;4941:2;4933:6;4929:15;4962:1;4972:502;4986:6;4983:1;4980:13;4972:502;;;5051:22;;;5075:66;5047:95;5035:108;;5166:13;;5221:9;;5214:17;5207:25;5192:41;;5272:11;;5266:18;5304:15;;;5297:27;;;5347:47;5378:15;;;5266:18;5347:47;:::i;:::-;5452:12;;;;5337:57;-1:-1:-1;;5417:15:1;;;;5008:1;5001:9;4972:502;;;-1:-1:-1;5491:6:1;;4406:1097;-1:-1:-1;;;;;;;;4406:1097:1:o;5508:184::-;5560:77;5557:1;5550:88;5657:4;5654:1;5647:15;5681:4;5678:1;5671:15;5697:247;5764:2;5758:9;5806:3;5794:16;;5840:18;5825:34;;5861:22;;;5822:62;5819:88;;;5887:18;;:::i;:::-;5923:2;5916:22;5697:247;:::o;5949:252::-;6021:2;6015:9;6063:3;6051:16;;6097:18;6082:34;;6118:22;;;6079:62;6076:88;;;6144:18;;:::i;6206:777::-;6248:5;6301:3;6294:4;6286:6;6282:17;6278:27;6268:55;;6319:1;6316;6309:12;6268:55;6355:6;6342:20;6381:18;6418:2;6414;6411:10;6408:36;;;6424:18;;:::i;:::-;6558:2;6552:9;6620:4;6612:13;;6463:66;6608:22;;;6632:2;6604:31;6600:40;6588:53;;;6656:18;;;6676:22;;;6653:46;6650:72;;;6702:18;;:::i;:::-;6742:10;6738:2;6731:22;6777:2;6769:6;6762:18;6823:3;6816:4;6811:2;6803:6;6799:15;6795:26;6792:35;6789:55;;;6840:1;6837;6830:12;6789:55;6904:2;6897:4;6889:6;6885:17;6878:4;6870:6;6866:17;6853:54;6951:1;6944:4;6939:2;6931:6;6927:15;6923:26;6916:37;6971:6;6962:15;;;;;;6206:777;;;;:::o;6988:455::-;7065:6;7073;7126:2;7114:9;7105:7;7101:23;7097:32;7094:52;;;7142:1;7139;7132:12;7094:52;7182:9;7169:23;7215:18;7207:6;7204:30;7201:50;;;7247:1;7244;7237:12;7201:50;7270:49;7311:7;7302:6;7291:9;7287:22;7270:49;:::i;:::-;7260:59;;;7369:2;7358:9;7354:18;7341:32;7382:31;7407:5;7382:31;:::i;7448:121::-;7533:10;7526:5;7522:22;7515:5;7512:33;7502:61;;7559:1;7556;7549:12;7574:132;7641:20;;7670:30;7641:20;7670:30;:::i;7711:860::-;7799:6;7852:3;7840:9;7831:7;7827:23;7823:33;7820:53;;;7869:1;7866;7859:12;7820:53;7895:17;;:::i;:::-;7935:28;7953:9;7935:28;:::i;:::-;7928:5;7921:43;7996:38;8030:2;8019:9;8015:18;7996:38;:::i;:::-;7991:2;7984:5;7980:14;7973:62;8067:38;8101:2;8090:9;8086:18;8067:38;:::i;:::-;8062:2;8055:5;8051:14;8044:62;8138:38;8172:2;8161:9;8157:18;8138:38;:::i;:::-;8133:2;8126:5;8122:14;8115:62;8210:39;8244:3;8233:9;8229:19;8210:39;:::i;:::-;8204:3;8197:5;8193:15;8186:64;8311:3;8300:9;8296:19;8283:33;8277:3;8270:5;8266:15;8259:58;8378:3;8367:9;8363:19;8350:33;8344:3;8337:5;8333:15;8326:58;8417:36;8448:3;8437:9;8433:19;8417:36;:::i;:::-;8411:3;8400:15;;8393:61;8473:3;8521:18;;;8508:32;8492:14;;;8485:56;;;;-1:-1:-1;8404:5:1;7711:860;-1:-1:-1;7711:860:1:o;8576:320::-;8644:6;8697:2;8685:9;8676:7;8672:23;8668:32;8665:52;;;8713:1;8710;8703:12;8665:52;8753:9;8740:23;8786:18;8778:6;8775:30;8772:50;;;8818:1;8815;8808:12;8772:50;8841:49;8882:7;8873:6;8862:9;8858:22;8841:49;:::i;:::-;8831:59;8576:320;-1:-1:-1;;;;8576:320:1:o;8901:388::-;8978:6;8986;9039:2;9027:9;9018:7;9014:23;9010:32;9007:52;;;9055:1;9052;9045:12;9007:52;9095:9;9082:23;9128:18;9120:6;9117:30;9114:50;;;9160:1;9157;9150:12;9114:50;9183:49;9224:7;9215:6;9204:9;9200:22;9183:49;:::i;:::-;9173:59;9279:2;9264:18;;;;9251:32;;-1:-1:-1;;;;8901:388:1:o;9294:248::-;9362:6;9370;9423:2;9411:9;9402:7;9398:23;9394:32;9391:52;;;9439:1;9436;9429:12;9391:52;-1:-1:-1;;9462:23:1;;;9532:2;9517:18;;;9504:32;;-1:-1:-1;9294:248:1:o;10342:1373::-;10573:13;;10319:10;10308:22;10296:35;;10542:3;10527:19;;10645:4;10637:6;10633:17;10627:24;10660:53;10707:4;10696:9;10692:20;10678:12;10319:10;10308:22;10296:35;;10243:94;10660:53;;10762:4;10754:6;10750:17;10744:24;10777:56;10827:4;10816:9;10812:20;10796:14;-1:-1:-1;;;;;9613:54:1;9601:67;;9547:127;10777:56;;10882:4;10874:6;10870:17;10864:24;10897:56;10947:4;10936:9;10932:20;10916:14;-1:-1:-1;;;;;9613:54:1;9601:67;;9547:127;10897:56;;11002:4;10994:6;10990:17;10984:24;11017:56;11067:4;11056:9;11052:20;11036:14;-1:-1:-1;;;;;9613:54:1;9601:67;;9547:127;11017:56;;11122:4;11114:6;11110:17;11104:24;11137:56;11187:4;11176:9;11172:20;11156:14;-1:-1:-1;;;;;9613:54:1;9601:67;;9547:127;11137:56;;11249:4;11241:6;11237:17;11231:24;11224:4;11213:9;11209:20;11202:54;11312:4;11304:6;11300:17;11294:24;11287:4;11276:9;11272:20;11265:54;11338:6;11398:2;11390:6;11386:15;11380:22;11375:2;11364:9;11360:18;11353:50;;11422:6;11477:2;11469:6;11465:15;11459:22;11490:51;11537:2;11526:9;11522:18;11506:14;421:13;414:21;402:34;;351:91;11490:51;-1:-1:-1;;11560:6:1;11608:15;;;11602:22;11582:18;;;11575:50;11644:6;11692:15;;;11686:22;11666:18;;;;11659:50;;;;10342:1373;:::o;11905:247::-;11964:6;12017:2;12005:9;11996:7;11992:23;11988:32;11985:52;;;12033:1;12030;12023:12;11985:52;12072:9;12059:23;12091:31;12116:5;12091:31;:::i;12560:184::-;12612:77;12609:1;12602:88;12709:4;12706:1;12699:15;12733:4;12730:1;12723:15;12749:580;12826:4;12832:6;12892:11;12879:25;12982:66;12971:8;12955:14;12951:29;12947:102;12927:18;12923:127;12913:155;;13064:1;13061;13054:12;12913:155;13091:33;;13143:20;;;-1:-1:-1;13186:18:1;13175:30;;13172:50;;;13218:1;13215;13208:12;13172:50;13251:4;13239:17;;-1:-1:-1;13282:14:1;13278:27;;;13268:38;;13265:58;;;13319:1;13316;13309:12;13265:58;12749:580;;;;;:::o;13334:271::-;13517:6;13509;13504:3;13491:33;13473:3;13543:16;;13568:13;;;13543:16;13334:271;-1:-1:-1;13334:271:1:o;13610:184::-;13662:77;13659:1;13652:88;13759:4;13756:1;13749:15;13783:4;13780:1;13773:15;13799:195;13838:3;13869:66;13862:5;13859:77;13856:103;;13939:18;;:::i;:::-;-1:-1:-1;13986:1:1;13975:13;;13799:195::o;13999:125::-;14064:9;;;14085:10;;;14082:36;;;14098:18;;:::i;14431:168::-;14504:9;;;14535;;14552:15;;;14546:22;;14532:37;14522:71;;14573:18;;:::i;14604:274::-;14644:1;14670;14660:189;;14705:77;14702:1;14695:88;14806:4;14803:1;14796:15;14834:4;14831:1;14824:15;14660:189;-1:-1:-1;14863:9:1;;14604:274::o;14883:128::-;14950:9;;;14971:11;;;14968:37;;;14985:18;;:::i;15016:752::-;15323:3;15312:9;15305:22;15286:4;15344:45;15384:3;15373:9;15369:19;15361:6;15344:45;:::i;:::-;15437:10;15425:23;;;;15420:2;15405:18;;15398:51;-1:-1:-1;;;;;;15546:15:1;;;15541:2;15526:18;;15519:43;15598:15;;;;15593:2;15578:18;;15571:43;15645:3;15630:19;;15623:35;;;;15689:3;15674:19;;15667:35;15746:14;;15739:22;15733:3;15718:19;;;15711:51;15336:53;15016:752;-1:-1:-1;15016:752:1:o;16407:136::-;16485:13;;16507:30;16485:13;16507:30;:::i;16548:138::-;16627:13;;16649:31;16627:13;16649:31;:::i;16691:132::-;16767:13;;16789:28;16767:13;16789:28;:::i;16828:1188::-;16931:6;16984:3;16972:9;16963:7;16959:23;16955:33;16952:53;;;17001:1;16998;16991:12;16952:53;17027:22;;:::i;:::-;17072:39;17101:9;17072:39;:::i;:::-;17065:5;17058:54;17144:48;17188:2;17177:9;17173:18;17144:48;:::i;:::-;17139:2;17132:5;17128:14;17121:72;17225:49;17270:2;17259:9;17255:18;17225:49;:::i;:::-;17220:2;17213:5;17209:14;17202:73;17307:49;17352:2;17341:9;17337:18;17307:49;:::i;:::-;17302:2;17295:5;17291:14;17284:73;17390:50;17435:3;17424:9;17420:19;17390:50;:::i;:::-;17384:3;17377:5;17373:15;17366:75;17474:50;17519:3;17508:9;17504:19;17474:50;:::i;:::-;17468:3;17461:5;17457:15;17450:75;17579:3;17568:9;17564:19;17558:26;17552:3;17545:5;17541:15;17534:51;17639:3;17628:9;17624:19;17618:26;17612:3;17605:5;17601:15;17594:51;17664:3;17720:2;17709:9;17705:18;17699:25;17694:2;17687:5;17683:14;17676:49;;17744:3;17779:46;17821:2;17810:9;17806:18;17779:46;:::i;:::-;17763:14;;;17756:70;17845:3;17886:18;;;17880:25;17864:14;;;17857:49;17925:3;17966:18;;;17960:25;17944:14;;;17937:49;;;;-1:-1:-1;17767:5:1;16828:1188;-1:-1:-1;16828:1188:1:o;19177:184::-;19247:6;19300:2;19288:9;19279:7;19275:23;19271:32;19268:52;;;19316:1;19313;19306:12;19268:52;-1:-1:-1;19339:16:1;;19177:184;-1:-1:-1;19177:184:1:o;19668:245::-;19735:6;19788:2;19776:9;19767:7;19763:23;19759:32;19756:52;;;19804:1;19801;19794:12;19756:52;19836:9;19830:16;19855:28;19877:5;19855:28;:::i;19918:184::-;19970:77;19967:1;19960:88;20067:4;20064:1;20057:15;20091:4;20088:1;20081:15;20107:287;20236:3;20274:6;20268:13;20290:66;20349:6;20344:3;20337:4;20329:6;20325:17;20290:66;:::i;:::-;20372:16;;;;;20107:287;-1:-1:-1;;20107:287:1:o","abiDefinition":[{"inputs":[{"internalType":"address","name":"_owner","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AccessControlBadConfirmation","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"bytes32","name":"neededRole","type":"bytes32"}],"name":"AccessControlUnauthorizedAccount","type":"error"},{"inputs":[{"internalType":"address","name":"target","type":"address"}],"name":"AddressEmptyCode","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"AddressInsufficientBalance","type":"error"},{"inputs":[],"name":"AmountIncorrect","type":"error"},{"inputs":[],"name":"ChainIncorrect","type":"error"},{"inputs":[],"name":"DeadlineExceeded","type":"error"},{"inputs":[],"name":"DeadlineNotExceeded","type":"error"},{"inputs":[],"name":"DeadlineTooShort","type":"error"},{"inputs":[],"name":"DisputePeriodNotPassed","type":"error"},{"inputs":[],"name":"DisputePeriodPassed","type":"error"},{"inputs":[],"name":"FailedInnerCall","type":"error"},{"inputs":[],"name":"MsgValueIncorrect","type":"error"},{"inputs":[],"name":"MulticallTarget__UndeterminedRevert","type":"error"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"SafeERC20FailedOperation","type":"error"},{"inputs":[],"name":"SenderIncorrect","type":"error"},{"inputs":[],"name":"StatusIncorrect","type":"error"},{"inputs":[],"name":"TokenNotContract","type":"error"},{"inputs":[],"name":"TransactionRelayed","type":"error"},{"inputs":[],"name":"ZeroAddress","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"relayer","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"BridgeDepositClaimed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"BridgeDepositRefunded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"relayer","type":"address"}],"name":"BridgeProofDisputed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"relayer","type":"address"},{"indexed":false,"internalType":"bytes32","name":"transactionHash","type":"bytes32"}],"name":"BridgeProofProvided","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"relayer","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint32","name":"originChainId","type":"uint32"},{"indexed":false,"internalType":"address","name":"originToken","type":"address"},{"indexed":false,"internalType":"address","name":"destToken","type":"address"},{"indexed":false,"internalType":"uint256","name":"originAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"destAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"chainGasAmount","type":"uint256"}],"name":"BridgeRelayed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"bytes","name":"request","type":"bytes"},{"indexed":false,"internalType":"uint32","name":"destChainId","type":"uint32"},{"indexed":false,"internalType":"address","name":"originToken","type":"address"},{"indexed":false,"internalType":"address","name":"destToken","type":"address"},{"indexed":false,"internalType":"uint256","name":"originAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"destAmount","type":"uint256"},{"indexed":false,"internalType":"bool","name":"sendChainGas","type":"bool"}],"name":"BridgeRequested","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldChainGasAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newChainGasAmount","type":"uint256"}],"name":"ChainGasAmountUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldFeeRate","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newFeeRate","type":"uint256"}],"name":"FeeRateUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"address","name":"recipient","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"FeesSwept","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"previousAdminRole","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"newAdminRole","type":"bytes32"}],"name":"RoleAdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleRevoked","type":"event"},{"inputs":[],"name":"DEFAULT_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"DISPUTE_PERIOD","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"FEE_BPS","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"FEE_RATE_MAX","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"GOVERNOR_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"GUARD_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MIN_DEADLINE_PERIOD","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"REFUNDER_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"REFUND_DELAY","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"RELAYER_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"uint32","name":"dstChainId","type":"uint32"},{"internalType":"address","name":"sender","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"address","name":"originToken","type":"address"},{"internalType":"address","name":"destToken","type":"address"},{"internalType":"uint256","name":"originAmount","type":"uint256"},{"internalType":"uint256","name":"destAmount","type":"uint256"},{"internalType":"bool","name":"sendChainGas","type":"bool"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"internalType":"struct IFastBridge.BridgeParams","name":"params","type":"tuple"}],"name":"bridge","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"bridgeProofs","outputs":[{"internalType":"uint96","name":"timestamp","type":"uint96"},{"internalType":"address","name":"relayer","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"bridgeRelays","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"bridgeStatuses","outputs":[{"internalType":"enum FastBridge.BridgeStatus","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"internalType":"address","name":"relayer","type":"address"}],"name":"canClaim","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"chainGasAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"},{"internalType":"address","name":"to","type":"address"}],"name":"claim","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"deployBlock","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"transactionId","type":"bytes32"}],"name":"dispute","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"}],"name":"getBridgeTransaction","outputs":[{"components":[{"internalType":"uint32","name":"originChainId","type":"uint32"},{"internalType":"uint32","name":"destChainId","type":"uint32"},{"internalType":"address","name":"originSender","type":"address"},{"internalType":"address","name":"destRecipient","type":"address"},{"internalType":"address","name":"originToken","type":"address"},{"internalType":"address","name":"destToken","type":"address"},{"internalType":"uint256","name":"originAmount","type":"uint256"},{"internalType":"uint256","name":"destAmount","type":"uint256"},{"internalType":"uint256","name":"originFeeAmount","type":"uint256"},{"internalType":"bool","name":"sendChainGas","type":"bool"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint256","name":"nonce","type":"uint256"}],"internalType":"struct IFastBridge.BridgeTransaction","name":"","type":"tuple"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleAdmin","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"uint256","name":"index","type":"uint256"}],"name":"getRoleMember","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleMemberCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"grantRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"hasRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes[]","name":"data","type":"bytes[]"},{"internalType":"bool","name":"ignoreReverts","type":"bool"}],"name":"multicallNoResults","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes[]","name":"data","type":"bytes[]"},{"internalType":"bool","name":"ignoreReverts","type":"bool"}],"name":"multicallWithResults","outputs":[{"components":[{"internalType":"bool","name":"success","type":"bool"},{"internalType":"bytes","name":"returnData","type":"bytes"}],"internalType":"struct IMulticallTarget.Result[]","name":"results","type":"tuple[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"nonce","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"protocolFeeRate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"protocolFees","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"},{"internalType":"bytes32","name":"destTxHash","type":"bytes32"}],"name":"prove","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"}],"name":"refund","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"}],"name":"relay","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"callerConfirmation","type":"address"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"revokeRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"newChainGasAmount","type":"uint256"}],"name":"setChainGasAmount","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"newFeeRate","type":"uint256"}],"name":"setProtocolFeeRate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"address","name":"recipient","type":"address"}],"name":"sweepProtocolFees","outputs":[],"stateMutability":"nonpayable","type":"function"}],"userDoc":{"kind":"user","methods":{"DISPUTE_PERIOD()":{"notice":"Dispute period for relayed transactions"},"MIN_DEADLINE_PERIOD()":{"notice":"Minimum deadline period to relay a requested bridge transaction"},"REFUND_DELAY()":{"notice":"Delay for a transaction after which it could be permisionlessly refunded"},"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256))":{"notice":"Initiates bridge on origin chain to be relayed by off-chain relayer"},"bridgeProofs(bytes32)":{"notice":"Proof of relayed bridge tx on origin chain"},"bridgeRelays(bytes32)":{"notice":"Whether bridge has been relayed on destination chain"},"bridgeStatuses(bytes32)":{"notice":"Status of the bridge tx on origin chain"},"canClaim(bytes32,address)":{"notice":"Checks if the dispute period has passed so bridge deposit can be claimed"},"chainGasAmount()":{"notice":"Chain gas amount to forward as rebate if requested"},"claim(bytes,address)":{"notice":"Completes bridge transaction on origin chain by claiming originally deposited capital"},"dispute(bytes32)":{"notice":"Disputes an outstanding proof in case relayer provided dest chain tx is invalid"},"getBridgeTransaction(bytes)":{"notice":"Decodes bridge request into a bridge transaction"},"multicallNoResults(bytes[],bool)":{"notice":"Perform a batched call to this contract, preserving the msg.sender. The return data from each call is discarded."},"multicallWithResults(bytes[],bool)":{"notice":"Perform a batched call to this contract, preserving the msg.sender. The return data from each call is preserved."},"protocolFeeRate()":{"notice":"Protocol fee rate taken on origin amount deposited in origin chain"},"protocolFees(address)":{"notice":"Protocol fee amounts accumulated"},"prove(bytes,bytes32)":{"notice":"Provides proof on origin side that relayer provided funds on destination side of bridge transaction"},"refund(bytes)":{"notice":"Refunds an outstanding bridge transaction in case optimistic bridging failed"},"relay(bytes)":{"notice":"Relays destination side of bridge transaction by off-chain relayer"}},"version":1},"developerDoc":{"errors":{"AccessControlBadConfirmation()":[{"details":"The caller of a function is not the expected one. NOTE: Don't confuse with {AccessControlUnauthorizedAccount}."}],"AccessControlUnauthorizedAccount(address,bytes32)":[{"details":"The `account` is missing a role."}],"AddressEmptyCode(address)":[{"details":"There's no code at `target` (it is not a contract)."}],"AddressInsufficientBalance(address)":[{"details":"The ETH balance of the account is not enough to perform the operation."}],"FailedInnerCall()":[{"details":"A call to an address target failed. The target may have reverted."}],"SafeERC20FailedOperation(address)":[{"details":"An operation with an ERC20 token failed."}]},"events":{"RoleAdminChanged(bytes32,bytes32,bytes32)":{"details":"Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole` `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite {RoleAdminChanged} not being emitted signaling this."},"RoleGranted(bytes32,address,address)":{"details":"Emitted when `account` is granted `role`. `sender` is the account that originated the contract call, an admin role bearer except when using {AccessControl-_setupRole}."},"RoleRevoked(bytes32,address,address)":{"details":"Emitted when `account` is revoked `role`. `sender` is the account that originated the contract call: - if using `revokeRole`, it is the admin role bearer - if using `renounceRole`, it is the role bearer (i.e. `account`)"}},"kind":"dev","methods":{"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256))":{"params":{"params":"The parameters required to bridge"}},"canClaim(bytes32,address)":{"params":{"relayer":"The address of the relayer attempting to claim","transactionId":"The transaction id associated with the encoded bridge transaction to check"}},"claim(bytes,address)":{"params":{"request":"The encoded bridge transaction to claim on origin chain","to":"The recipient address of the funds"}},"dispute(bytes32)":{"params":{"transactionId":"The transaction id associated with the encoded bridge transaction to dispute"}},"getBridgeTransaction(bytes)":{"params":{"request":"The bridge request to decode"}},"getRoleAdmin(bytes32)":{"details":"Returns the admin role that controls `role`. See {grantRole} and {revokeRole}. To change a role's admin, use {_setRoleAdmin}."},"getRoleMember(bytes32,uint256)":{"details":"Returns one of the accounts that have `role`. `index` must be a value between 0 and {getRoleMemberCount}, non-inclusive. Role bearers are not sorted in any particular way, and their ordering may change at any point. WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure you perform all queries on the same block. See the following https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post] for more information."},"getRoleMemberCount(bytes32)":{"details":"Returns the number of accounts that have `role`. Can be used together with {getRoleMember} to enumerate all bearers of a role."},"grantRole(bytes32,address)":{"details":"Grants `role` to `account`. If `account` had not been already granted `role`, emits a {RoleGranted} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleGranted} event."},"hasRole(bytes32,address)":{"details":"Returns `true` if `account` has been granted `role`."},"multicallNoResults(bytes[],bool)":{"details":"The method is non-payable, so only calls with `msg.value == 0` could be batched. It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag. Otherwise, the whole batch call will be reverted with the original revert reason.","params":{"data":"List of abi-encoded calldata for the calls to perform.","ignoreReverts":"Whether to ignore the revert errors from the calls."}},"multicallWithResults(bytes[],bool)":{"details":"The method is non-payable, so only calls with `msg.value == 0` could be batched. It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag. Otherwise, the whole batch call will be reverted with the original revert reason.","params":{"data":"List of abi-encoded calldata for the calls to perform.","ignoreReverts":"Whether to ignore the revert errors from the calls."},"returns":{"results":" List of results from the calls: `(success, returnData)`."}},"prove(bytes,bytes32)":{"params":{"destTxHash":"The destination tx hash proving bridge transaction was relayed","request":"The encoded bridge transaction to prove on origin chain"}},"refund(bytes)":{"params":{"request":"The encoded bridge transaction to refund"}},"relay(bytes)":{"params":{"request":"The encoded bridge transaction to relay on destination chain"}},"renounceRole(bytes32,address)":{"details":"Revokes `role` from the calling account. Roles are often managed via {grantRole} and {revokeRole}: this function's purpose is to provide a mechanism for accounts to lose their privileges if they are compromised (such as when a trusted device is misplaced). If the calling account had been revoked `role`, emits a {RoleRevoked} event. Requirements: - the caller must be `callerConfirmation`. May emit a {RoleRevoked} event."},"revokeRole(bytes32,address)":{"details":"Revokes `role` from `account`. If `account` had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleRevoked} event."},"supportsInterface(bytes4)":{"details":"See {IERC165-supportsInterface}."}},"stateVariables":{"nonce":{"details":"to prevent replays"}},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.20+commit.a1b79de6\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_owner\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"AccessControlBadConfirmation\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"neededRole\",\"type\":\"bytes32\"}],\"name\":\"AccessControlUnauthorizedAccount\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"}],\"name\":\"AddressEmptyCode\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"AddressInsufficientBalance\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"AmountIncorrect\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ChainIncorrect\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DeadlineExceeded\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DeadlineNotExceeded\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DeadlineTooShort\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DisputePeriodNotPassed\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DisputePeriodPassed\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"FailedInnerCall\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"MsgValueIncorrect\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"MulticallTarget__UndeterminedRevert\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"}],\"name\":\"SafeERC20FailedOperation\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"SenderIncorrect\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"StatusIncorrect\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"TokenNotContract\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"TransactionRelayed\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ZeroAddress\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"BridgeDepositClaimed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"BridgeDepositRefunded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"name\":\"BridgeProofDisputed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"transactionHash\",\"type\":\"bytes32\"}],\"name\":\"BridgeProofProvided\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"originChainId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"chainGasAmount\",\"type\":\"uint256\"}],\"name\":\"BridgeRelayed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"destChainId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"sendChainGas\",\"type\":\"bool\"}],\"name\":\"BridgeRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"oldChainGasAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newChainGasAmount\",\"type\":\"uint256\"}],\"name\":\"ChainGasAmountUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"oldFeeRate\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newFeeRate\",\"type\":\"uint256\"}],\"name\":\"FeeRateUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"FeesSwept\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"previousAdminRole\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"newAdminRole\",\"type\":\"bytes32\"}],\"name\":\"RoleAdminChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleGranted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleRevoked\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"DEFAULT_ADMIN_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"DISPUTE_PERIOD\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"FEE_BPS\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"FEE_RATE_MAX\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"GOVERNOR_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"GUARD_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"MIN_DEADLINE_PERIOD\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"REFUNDER_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"REFUND_DELAY\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"RELAYER_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"dstChainId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"sendChainGas\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"}],\"internalType\":\"struct IFastBridge.BridgeParams\",\"name\":\"params\",\"type\":\"tuple\"}],\"name\":\"bridge\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"bridgeProofs\",\"outputs\":[{\"internalType\":\"uint96\",\"name\":\"timestamp\",\"type\":\"uint96\"},{\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"bridgeRelays\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"bridgeStatuses\",\"outputs\":[{\"internalType\":\"enum FastBridge.BridgeStatus\",\"name\":\"\",\"type\":\"uint8\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"name\":\"canClaim\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"chainGasAmount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"claim\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"deployBlock\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"}],\"name\":\"dispute\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"getBridgeTransaction\",\"outputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"originChainId\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"destChainId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"originSender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destRecipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"originFeeAmount\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"sendChainGas\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"}],\"internalType\":\"struct IFastBridge.BridgeTransaction\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"}],\"name\":\"getRoleAdmin\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"index\",\"type\":\"uint256\"}],\"name\":\"getRoleMember\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"}],\"name\":\"getRoleMemberCount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"grantRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"hasRole\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes[]\",\"name\":\"data\",\"type\":\"bytes[]\"},{\"internalType\":\"bool\",\"name\":\"ignoreReverts\",\"type\":\"bool\"}],\"name\":\"multicallNoResults\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes[]\",\"name\":\"data\",\"type\":\"bytes[]\"},{\"internalType\":\"bool\",\"name\":\"ignoreReverts\",\"type\":\"bool\"}],\"name\":\"multicallWithResults\",\"outputs\":[{\"components\":[{\"internalType\":\"bool\",\"name\":\"success\",\"type\":\"bool\"},{\"internalType\":\"bytes\",\"name\":\"returnData\",\"type\":\"bytes\"}],\"internalType\":\"struct IMulticallTarget.Result[]\",\"name\":\"results\",\"type\":\"tuple[]\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"nonce\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"protocolFeeRate\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"protocolFees\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"},{\"internalType\":\"bytes32\",\"name\":\"destTxHash\",\"type\":\"bytes32\"}],\"name\":\"prove\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"refund\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"relay\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"callerConfirmation\",\"type\":\"address\"}],\"name\":\"renounceRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"revokeRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"newChainGasAmount\",\"type\":\"uint256\"}],\"name\":\"setChainGasAmount\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"newFeeRate\",\"type\":\"uint256\"}],\"name\":\"setProtocolFeeRate\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes4\",\"name\":\"interfaceId\",\"type\":\"bytes4\"}],\"name\":\"supportsInterface\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"}],\"name\":\"sweepProtocolFees\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"errors\":{\"AccessControlBadConfirmation()\":[{\"details\":\"The caller of a function is not the expected one. NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\"}],\"AccessControlUnauthorizedAccount(address,bytes32)\":[{\"details\":\"The `account` is missing a role.\"}],\"AddressEmptyCode(address)\":[{\"details\":\"There's no code at `target` (it is not a contract).\"}],\"AddressInsufficientBalance(address)\":[{\"details\":\"The ETH balance of the account is not enough to perform the operation.\"}],\"FailedInnerCall()\":[{\"details\":\"A call to an address target failed. The target may have reverted.\"}],\"SafeERC20FailedOperation(address)\":[{\"details\":\"An operation with an ERC20 token failed.\"}]},\"events\":{\"RoleAdminChanged(bytes32,bytes32,bytes32)\":{\"details\":\"Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole` `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite {RoleAdminChanged} not being emitted signaling this.\"},\"RoleGranted(bytes32,address,address)\":{\"details\":\"Emitted when `account` is granted `role`. `sender` is the account that originated the contract call, an admin role bearer except when using {AccessControl-_setupRole}.\"},\"RoleRevoked(bytes32,address,address)\":{\"details\":\"Emitted when `account` is revoked `role`. `sender` is the account that originated the contract call: - if using `revokeRole`, it is the admin role bearer - if using `renounceRole`, it is the role bearer (i.e. `account`)\"}},\"kind\":\"dev\",\"methods\":{\"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256))\":{\"params\":{\"params\":\"The parameters required to bridge\"}},\"canClaim(bytes32,address)\":{\"params\":{\"relayer\":\"The address of the relayer attempting to claim\",\"transactionId\":\"The transaction id associated with the encoded bridge transaction to check\"}},\"claim(bytes,address)\":{\"params\":{\"request\":\"The encoded bridge transaction to claim on origin chain\",\"to\":\"The recipient address of the funds\"}},\"dispute(bytes32)\":{\"params\":{\"transactionId\":\"The transaction id associated with the encoded bridge transaction to dispute\"}},\"getBridgeTransaction(bytes)\":{\"params\":{\"request\":\"The bridge request to decode\"}},\"getRoleAdmin(bytes32)\":{\"details\":\"Returns the admin role that controls `role`. See {grantRole} and {revokeRole}. To change a role's admin, use {_setRoleAdmin}.\"},\"getRoleMember(bytes32,uint256)\":{\"details\":\"Returns one of the accounts that have `role`. `index` must be a value between 0 and {getRoleMemberCount}, non-inclusive. Role bearers are not sorted in any particular way, and their ordering may change at any point. WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure you perform all queries on the same block. See the following https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post] for more information.\"},\"getRoleMemberCount(bytes32)\":{\"details\":\"Returns the number of accounts that have `role`. Can be used together with {getRoleMember} to enumerate all bearers of a role.\"},\"grantRole(bytes32,address)\":{\"details\":\"Grants `role` to `account`. If `account` had not been already granted `role`, emits a {RoleGranted} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleGranted} event.\"},\"hasRole(bytes32,address)\":{\"details\":\"Returns `true` if `account` has been granted `role`.\"},\"multicallNoResults(bytes[],bool)\":{\"details\":\"The method is non-payable, so only calls with `msg.value == 0` could be batched. It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag. Otherwise, the whole batch call will be reverted with the original revert reason.\",\"params\":{\"data\":\"List of abi-encoded calldata for the calls to perform.\",\"ignoreReverts\":\"Whether to ignore the revert errors from the calls.\"}},\"multicallWithResults(bytes[],bool)\":{\"details\":\"The method is non-payable, so only calls with `msg.value == 0` could be batched. It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag. Otherwise, the whole batch call will be reverted with the original revert reason.\",\"params\":{\"data\":\"List of abi-encoded calldata for the calls to perform.\",\"ignoreReverts\":\"Whether to ignore the revert errors from the calls.\"},\"returns\":{\"results\":\" List of results from the calls: `(success, returnData)`.\"}},\"prove(bytes,bytes32)\":{\"params\":{\"destTxHash\":\"The destination tx hash proving bridge transaction was relayed\",\"request\":\"The encoded bridge transaction to prove on origin chain\"}},\"refund(bytes)\":{\"params\":{\"request\":\"The encoded bridge transaction to refund\"}},\"relay(bytes)\":{\"params\":{\"request\":\"The encoded bridge transaction to relay on destination chain\"}},\"renounceRole(bytes32,address)\":{\"details\":\"Revokes `role` from the calling account. Roles are often managed via {grantRole} and {revokeRole}: this function's purpose is to provide a mechanism for accounts to lose their privileges if they are compromised (such as when a trusted device is misplaced). If the calling account had been revoked `role`, emits a {RoleRevoked} event. Requirements: - the caller must be `callerConfirmation`. May emit a {RoleRevoked} event.\"},\"revokeRole(bytes32,address)\":{\"details\":\"Revokes `role` from `account`. If `account` had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleRevoked} event.\"},\"supportsInterface(bytes4)\":{\"details\":\"See {IERC165-supportsInterface}.\"}},\"stateVariables\":{\"nonce\":{\"details\":\"to prevent replays\"}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"DISPUTE_PERIOD()\":{\"notice\":\"Dispute period for relayed transactions\"},\"MIN_DEADLINE_PERIOD()\":{\"notice\":\"Minimum deadline period to relay a requested bridge transaction\"},\"REFUND_DELAY()\":{\"notice\":\"Delay for a transaction after which it could be permisionlessly refunded\"},\"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256))\":{\"notice\":\"Initiates bridge on origin chain to be relayed by off-chain relayer\"},\"bridgeProofs(bytes32)\":{\"notice\":\"Proof of relayed bridge tx on origin chain\"},\"bridgeRelays(bytes32)\":{\"notice\":\"Whether bridge has been relayed on destination chain\"},\"bridgeStatuses(bytes32)\":{\"notice\":\"Status of the bridge tx on origin chain\"},\"canClaim(bytes32,address)\":{\"notice\":\"Checks if the dispute period has passed so bridge deposit can be claimed\"},\"chainGasAmount()\":{\"notice\":\"Chain gas amount to forward as rebate if requested\"},\"claim(bytes,address)\":{\"notice\":\"Completes bridge transaction on origin chain by claiming originally deposited capital\"},\"dispute(bytes32)\":{\"notice\":\"Disputes an outstanding proof in case relayer provided dest chain tx is invalid\"},\"getBridgeTransaction(bytes)\":{\"notice\":\"Decodes bridge request into a bridge transaction\"},\"multicallNoResults(bytes[],bool)\":{\"notice\":\"Perform a batched call to this contract, preserving the msg.sender. The return data from each call is discarded.\"},\"multicallWithResults(bytes[],bool)\":{\"notice\":\"Perform a batched call to this contract, preserving the msg.sender. The return data from each call is preserved.\"},\"protocolFeeRate()\":{\"notice\":\"Protocol fee rate taken on origin amount deposited in origin chain\"},\"protocolFees(address)\":{\"notice\":\"Protocol fee amounts accumulated\"},\"prove(bytes,bytes32)\":{\"notice\":\"Provides proof on origin side that relayer provided funds on destination side of bridge transaction\"},\"refund(bytes)\":{\"notice\":\"Refunds an outstanding bridge transaction in case optimistic bridging failed\"},\"relay(bytes)\":{\"notice\":\"Relays destination side of bridge transaction by off-chain relayer\"}},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeMock.sol\":\"FastBridge\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeMock.sol\":{\"keccak256\":\"0xf2751f52f8216801d500da7464ad01f3c23a8286e155e2dcba6d21d6e7fd95a0\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://85d2edab24ebe321043d2b88038437e8f443a0ef26fa2139c72dcc2bc7fbc602\",\"dweb:/ipfs/QmcULiFPFJzFDT4aupVSDreXz8uHxcABb5nxpAG4zYzfNN\"]}},\"version\":1}"},"hashes":{"DEFAULT_ADMIN_ROLE()":"a217fddf","DISPUTE_PERIOD()":"a5bbe22b","FEE_BPS()":"bf333f2c","FEE_RATE_MAX()":"0f5f6ed7","GOVERNOR_ROLE()":"ccc57490","GUARD_ROLE()":"03ed0ee5","MIN_DEADLINE_PERIOD()":"820688d5","REFUNDER_ROLE()":"5960ccf2","REFUND_DELAY()":"190da595","RELAYER_ROLE()":"926d7d7f","bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256))":"45851694","bridgeProofs(bytes32)":"91ad5039","bridgeRelays(bytes32)":"8379a24f","bridgeStatuses(bytes32)":"051287bc","canClaim(bytes32,address)":"aa9641ab","chainGasAmount()":"e00a83e0","claim(bytes,address)":"41fcb612","deployBlock()":"a3ec191a","dispute(bytes32)":"add98c70","getBridgeTransaction(bytes)":"ac11fb1a","getRoleAdmin(bytes32)":"248a9ca3","getRoleMember(bytes32,uint256)":"9010d07c","getRoleMemberCount(bytes32)":"ca15c873","grantRole(bytes32,address)":"2f2ff15d","hasRole(bytes32,address)":"91d14854","multicallNoResults(bytes[],bool)":"3f61331d","multicallWithResults(bytes[],bool)":"385c1d2f","nonce()":"affed0e0","protocolFeeRate()":"58f85880","protocolFees(address)":"dcf844a7","prove(bytes,bytes32)":"886d36ff","refund(bytes)":"5eb7d946","relay(bytes)":"8f0d6f17","renounceRole(bytes32,address)":"36568abe","revokeRole(bytes32,address)":"d547741f","setChainGasAmount(uint256)":"b250fe6b","setProtocolFeeRate(uint256)":"b13aa2d6","supportsInterface(bytes4)":"01ffc9a7","sweepProtocolFees(address,address)":"06f333f2"}},"solidity/FastBridgeMock.sol:FastBridgeMock":{"code":"0x60a06040523480156200001157600080fd5b506040516200257538038062002575833981016040819052620000349162000194565b80620000426000826200004f565b50504360805250620001bf565b6000806200005e84846200008c565b90508015620000835760008481526001602052604090206200008190846200013a565b505b90505b92915050565b6000828152602081815260408083206001600160a01b038516845290915281205460ff1662000131576000838152602081815260408083206001600160a01b03861684529091529020805460ff19166001179055620000e83390565b6001600160a01b0316826001600160a01b0316847f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a450600162000086565b50600062000086565b600062000083836001600160a01b0384166000818152600183016020526040812054620001315750815460018181018455600084815260208082209093018490558454848252828601909352604090209190915562000086565b600060208284031215620001a757600080fd5b81516001600160a01b03811681146200008357600080fd5b60805161239a620001db6000396000610559015261239a6000f3fe60806040526004361061024f5760003560e01c8063926d7d7f11610138578063b13aa2d6116100b0578063ca15c8731161007f578063d547741f11610064578063d547741f14610704578063dcf844a714610724578063e00a83e01461075157600080fd5b8063ca15c873146106b0578063ccc57490146106d057600080fd5b8063b13aa2d614610639578063b250fe6b14610659578063bf333f2c14610679578063c72870cc1461069057600080fd5b8063ac11fb1a11610107578063add98c70116100ec578063add98c70146105e8578063aedf009d14610603578063affed0e01461062357600080fd5b8063ac11fb1a1461059b578063acaebbf1146105c857600080fd5b8063926d7d7f146104fe578063a217fddf14610532578063a3ec191a14610547578063aa9641ab1461057b57600080fd5b80634774fa38116101cb57806385ad903d1161019a5780638f0d6f171161017f5780638f0d6f171461045a5780639010d07c1461046857806391d14854146104ad57600080fd5b806385ad903d14610412578063886d36ff1461043f57600080fd5b80634774fa38146103a157806358f85880146103ad5780635960ccf2146103c35780635eb7d946146103f757600080fd5b8063248a9ca31161022257806336568abe1161020757806336568abe1461035357806341fcb61214610373578063458516941461039357600080fd5b8063248a9ca3146103035780632f2ff15d1461033357600080fd5b806301ffc9a71461025457806303ed0ee51461028957806306f333f2146102cb5780630f5f6ed7146102ed575b600080fd5b34801561026057600080fd5b5061027461026f366004611984565b610767565b60405190151581526020015b60405180910390f35b34801561029557600080fd5b506102bd7f043c983c49d46f0e102151eaf8085d4a2e6571d5df2d47b013f39bddfd4a639d81565b604051908152602001610280565b3480156102d757600080fd5b506102eb6102e63660046119f8565b6107c3565b005b3480156102f957600080fd5b506102bd61271081565b34801561030f57600080fd5b506102bd61031e366004611a31565b60009081526020819052604090206001015490565b34801561033f57600080fd5b506102eb61034e366004611a4a565b6108b1565b34801561035f57600080fd5b506102eb61036e366004611a4a565b6108dc565b34801561037f57600080fd5b506102eb61038e366004611b97565b610935565b6102eb61038e366004611cb7565b3480156102eb57600080fd5b3480156103b957600080fd5b506102bd60025481565b3480156103cf57600080fd5b506102bd7fdb9556138406326f00296e13ea2ad7db24ba82381212d816b1a40c23b466b32781565b34801561040357600080fd5b506102eb61038e366004611cd4565b34801561041e57600080fd5b5061043261042d366004611d11565b61099c565b6040516102809190611da0565b34801561044b57600080fd5b506102eb61038e366004611db3565b6102eb61038e366004611cd4565b34801561047457600080fd5b50610488610483366004611df8565b610b4c565b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610280565b3480156104b957600080fd5b506102746104c8366004611a4a565b60009182526020828152604080842073ffffffffffffffffffffffffffffffffffffffff93909316845291905290205460ff1690565b34801561050a57600080fd5b506102bd7fe2b7fb3b832174769106daebcfd6d1970523240dda11281102db9363b83b0dc481565b34801561053e57600080fd5b506102bd600081565b34801561055357600080fd5b506102bd7f000000000000000000000000000000000000000000000000000000000000000081565b34801561058757600080fd5b50610274610596366004611a4a565b610b6b565b3480156105a757600080fd5b506105bb6105b6366004611cd4565b610bd0565b6040516102809190611e1a565b3480156105d457600080fd5b506102eb6105e3366004611f34565b610c43565b3480156105f457600080fd5b506102eb61038e366004611a31565b34801561060f57600080fd5b506102eb61061e366004611f74565b610e13565b34801561062f57600080fd5b506102bd60055481565b34801561064557600080fd5b506102eb610654366004611a31565b610e9e565b34801561066557600080fd5b506102eb610674366004611a31565b610f7b565b34801561068557600080fd5b506102bd620f424081565b34801561069c57600080fd5b506102eb6106ab366004611fcd565b610fe3565b3480156106bc57600080fd5b506102bd6106cb366004611a31565b611069565b3480156106dc57600080fd5b506102bd7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f5581565b34801561071057600080fd5b506102eb61071f366004611a4a565b611080565b34801561073057600080fd5b506102bd61073f366004612065565b60036020526000908152604090205481565b34801561075d57600080fd5b506102bd60045481565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f5a05180f0000000000000000000000000000000000000000000000000000000014806107bd57506107bd826110a5565b92915050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f556107ed8161113c565b73ffffffffffffffffffffffffffffffffffffffff8316600090815260036020526040812054908190036108215750505050565b73ffffffffffffffffffffffffffffffffffffffff8416600081815260036020526040812055610852908483611149565b6040805173ffffffffffffffffffffffffffffffffffffffff8087168252851660208201529081018290527f244e51bc38c1452fa8aaf487bcb4bca36c2baa3a5fbdb776b1eabd8dc6d277cd9060600160405180910390a1505b505050565b6000828152602081905260409020600101546108cc8161113c565b6108d683836112a0565b50505050565b73ffffffffffffffffffffffffffffffffffffffff8116331461092b576040517f6697b23200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6108ac82826112d5565b6040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f6e6f7420696d706c656d656e746564000000000000000000000000000000000060448201526064015b60405180910390fd5b60608160048111156109b0576109b0612082565b6000036109f057505060408051808201909152600481527f4e554c4c00000000000000000000000000000000000000000000000000000000602082015290565b816004811115610a0257610a02612082565b600103610a4257505060408051808201909152600981527f5245515545535445440000000000000000000000000000000000000000000000602082015290565b816004811115610a5457610a54612082565b600203610a9457505060408051808201909152600e81527f52454c415945525f50524f564544000000000000000000000000000000000000602082015290565b816004811115610aa657610aa6612082565b600303610ae657505060408051808201909152600f81527f52454c415945525f434c41494d45440000000000000000000000000000000000602082015290565b816004811115610af857610af8612082565b600403610b3857505060408051808201909152600881527f524546554e444544000000000000000000000000000000000000000000000000602082015290565b505060408051602081019091526000815290565b6000828152600160205260408120610b649083611302565b9392505050565b6040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f6e6f7420696d706c656d656e74656400000000000000000000000000000000006044820152600090606401610993565b604080516101808101825260008082526020808301829052928201819052606082018190526080820181905260a0820181905260c0820181905260e08201819052610100820181905261012082018190526101408201819052610160820152825190916107bd91840181019084016120d2565b6000620f42406002548360a00151610c5b91906121cd565b610c6591906121e4565b9050808260a001818151610c79919061221f565b9150818152505060006040518061018001604052804663ffffffff168152602001846000015163ffffffff168152602001846020015173ffffffffffffffffffffffffffffffffffffffff168152602001846040015173ffffffffffffffffffffffffffffffffffffffff168152602001846060015173ffffffffffffffffffffffffffffffffffffffff168152602001846080015173ffffffffffffffffffffffffffffffffffffffff1681526020018460a0015181526020018460c0015181526020018381526020018460e0015115158152602001846101000151815260200160056000815480929190610d6e90612232565b909155509052604051610d849190602001611e1a565b6040516020818303038152906040529050826020015173ffffffffffffffffffffffffffffffffffffffff16857f120ea0364f36cdac7983bcfdd55270ca09d7f9b314a2ebc425a3b01ab1d6403a838660000151876060015188608001518960a001518a60c001518b60e00151604051610e04979695949392919061226a565b60405180910390a35050505050565b6000610e1e82610bd0565b9050806040015173ffffffffffffffffffffffffffffffffffffffff16847f120ea0364f36cdac7983bcfdd55270ca09d7f9b314a2ebc425a3b01ab1d6403a84846020015185608001518660a001518760c001518860e00151896101200151604051610e90979695949392919061226a565b60405180910390a350505050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f55610ec88161113c565b612710821115610f34576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f6e657746656552617465203e206d6178000000000000000000000000000000006044820152606401610993565b600280549083905560408051828152602081018590527f14914da2bf76024616fbe1859783fcd4dbddcb179b1f3a854949fbf920dcb95791015b60405180910390a1505050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f55610fa58161113c565b600480549083905560408051828152602081018590527f5cf09b12f3f56b4c564d51b25b40360af6d795198adb61ae0806a36c294323fa9101610f6e565b6040805163ffffffff8816815273ffffffffffffffffffffffffffffffffffffffff878116602083015286811682840152606082018690526080820185905260a082018490529151898316928b16918c917ff8ae392d784b1ea5e8881bfa586d81abf07ef4f1e2fc75f7fe51c90f05199a5c9181900360c00190a4505050505050505050565b60008181526001602052604081206107bd9061130e565b60008281526020819052604090206001015461109b8161113c565b6108d683836112d5565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f7965db0b0000000000000000000000000000000000000000000000000000000014806107bd57507f01ffc9a7000000000000000000000000000000000000000000000000000000007fffffffff000000000000000000000000000000000000000000000000000000008316146107bd565b6111468133611318565b50565b3073ffffffffffffffffffffffffffffffffffffffff83160361116b57505050565b8060000361117857505050565b7fffffffffffffffffffffffff111111111111111111111111111111111111111273ffffffffffffffffffffffffffffffffffffffff84160161127f5760008273ffffffffffffffffffffffffffffffffffffffff168260405160006040518083038185875af1925050503d806000811461120f576040519150601f19603f3d011682016040523d82523d6000602084013e611214565b606091505b50509050806108d6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f455448207472616e73666572206661696c6564000000000000000000000000006044820152606401610993565b6108ac73ffffffffffffffffffffffffffffffffffffffff841683836113a2565b6000806112ad848461142f565b90508015610b645760008481526001602052604090206112cd908461152b565b509392505050565b6000806112e2848461154d565b90508015610b645760008481526001602052604090206112cd9084611608565b6000610b64838361162a565b60006107bd825490565b60008281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915290205460ff1661139e576040517fe2517d3f00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8216600482015260248101839052604401610993565b5050565b6040805173ffffffffffffffffffffffffffffffffffffffff8416602482015260448082018490528251808303909101815260649091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fa9059cbb000000000000000000000000000000000000000000000000000000001790526108ac908490611654565b60008281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915281205460ff166115235760008381526020818152604080832073ffffffffffffffffffffffffffffffffffffffff86168452909152902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790556114c13390565b73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16847f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45060016107bd565b5060006107bd565b6000610b648373ffffffffffffffffffffffffffffffffffffffff84166116ea565b60008281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915281205460ff16156115235760008381526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8616808552925280832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016905551339286917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a45060016107bd565b6000610b648373ffffffffffffffffffffffffffffffffffffffff8416611731565b6000826000018281548110611641576116416122cd565b9060005260206000200154905092915050565b600061167673ffffffffffffffffffffffffffffffffffffffff841683611824565b9050805160001415801561169b57508080602001905181019061169991906122fc565b155b156108ac576040517f5274afe700000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff84166004820152602401610993565b6000818152600183016020526040812054611523575081546001818101845560008481526020808220909301849055845484825282860190935260409020919091556107bd565b6000818152600183016020526040812054801561181a57600061175560018361221f565b85549091506000906117699060019061221f565b90508082146117ce576000866000018281548110611789576117896122cd565b90600052602060002001549050808760000184815481106117ac576117ac6122cd565b6000918252602080832090910192909255918252600188019052604090208390555b85548690806117df576117df612319565b6001900381819060005260206000200160009055905585600101600086815260200190815260200160002060009055600193505050506107bd565b60009150506107bd565b6060610b6483836000846000808573ffffffffffffffffffffffffffffffffffffffff1684866040516118579190612348565b60006040518083038185875af1925050503d8060008114611894576040519150601f19603f3d011682016040523d82523d6000602084013e611899565b606091505b50915091506118a98683836118b3565b9695505050505050565b6060826118c8576118c382611942565b610b64565b81511580156118ec575073ffffffffffffffffffffffffffffffffffffffff84163b155b1561193b576040517f9996b31500000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff85166004820152602401610993565b5080610b64565b8051156119525780518082602001fd5b6040517f1425ea4200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006020828403121561199657600080fd5b81357fffffffff0000000000000000000000000000000000000000000000000000000081168114610b6457600080fd5b73ffffffffffffffffffffffffffffffffffffffff8116811461114657600080fd5b80356119f3816119c6565b919050565b60008060408385031215611a0b57600080fd5b8235611a16816119c6565b91506020830135611a26816119c6565b809150509250929050565b600060208284031215611a4357600080fd5b5035919050565b60008060408385031215611a5d57600080fd5b823591506020830135611a26816119c6565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051610120810167ffffffffffffffff81118282101715611ac257611ac2611a6f565b60405290565b604051610180810167ffffffffffffffff81118282101715611ac257611ac2611a6f565b600082601f830112611afd57600080fd5b813567ffffffffffffffff80821115611b1857611b18611a6f565b604051601f83017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f01168101908282118183101715611b5e57611b5e611a6f565b81604052838152866020858801011115611b7757600080fd5b836020870160208301376000602085830101528094505050505092915050565b60008060408385031215611baa57600080fd5b823567ffffffffffffffff811115611bc157600080fd5b611bcd85828601611aec565b9250506020830135611a26816119c6565b63ffffffff8116811461114657600080fd5b80356119f381611bde565b801515811461114657600080fd5b80356119f381611bfb565b60006101208284031215611c2757600080fd5b611c2f611a9e565b9050611c3a82611bf0565b8152611c48602083016119e8565b6020820152611c59604083016119e8565b6040820152611c6a606083016119e8565b6060820152611c7b608083016119e8565b608082015260a082013560a082015260c082013560c0820152611ca060e08301611c09565b60e082015261010080830135818301525092915050565b60006101208284031215611cca57600080fd5b610b648383611c14565b600060208284031215611ce657600080fd5b813567ffffffffffffffff811115611cfd57600080fd5b611d0984828501611aec565b949350505050565b600060208284031215611d2357600080fd5b813560058110610b6457600080fd5b60005b83811015611d4d578181015183820152602001611d35565b50506000910152565b60008151808452611d6e816020860160208601611d32565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b602081526000610b646020830184611d56565b60008060408385031215611dc657600080fd5b823567ffffffffffffffff811115611ddd57600080fd5b611de985828601611aec565b95602094909401359450505050565b60008060408385031215611e0b57600080fd5b50508035926020909101359150565b815163ffffffff16815261018081016020830151611e40602084018263ffffffff169052565b506040830151611e68604084018273ffffffffffffffffffffffffffffffffffffffff169052565b506060830151611e90606084018273ffffffffffffffffffffffffffffffffffffffff169052565b506080830151611eb8608084018273ffffffffffffffffffffffffffffffffffffffff169052565b5060a0830151611ee060a084018273ffffffffffffffffffffffffffffffffffffffff169052565b5060c083015160c083015260e083015160e083015261010080840151818401525061012080840151611f158285018215159052565b5050610140838101519083015261016092830151929091019190915290565b60008060006101608486031215611f4a57600080fd5b833592506020840135611f5c816119c6565b9150611f6b8560408601611c14565b90509250925092565b600080600060608486031215611f8957600080fd5b833592506020840135611f9b816119c6565b9150604084013567ffffffffffffffff811115611fb757600080fd5b611fc386828701611aec565b9150509250925092565b60008060008060008060008060006101208a8c031215611fec57600080fd5b8935985060208a0135611ffe816119c6565b975060408a013561200e816119c6565b965060608a013561201e81611bde565b955060808a013561202e816119c6565b945060a08a013561203e816119c6565b8094505060c08a0135925060e08a013591506101008a013590509295985092959850929598565b60006020828403121561207757600080fd5b8135610b64816119c6565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b80516119f381611bde565b80516119f3816119c6565b80516119f381611bfb565b600061018082840312156120e557600080fd5b6120ed611ac8565b6120f6836120b1565b8152612104602084016120b1565b6020820152612115604084016120bc565b6040820152612126606084016120bc565b6060820152612137608084016120bc565b608082015261214860a084016120bc565b60a082015260c083015160c082015260e083015160e082015261010080840151818301525061012061217b8185016120c7565b908201526101408381015190820152610160928301519281019290925250919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b80820281158282048414176107bd576107bd61219e565b60008261221a577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b818103818111156107bd576107bd61219e565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82036122635761226361219e565b5060010190565b60e08152600061227d60e083018a611d56565b63ffffffff9890981660208301525073ffffffffffffffffffffffffffffffffffffffff9586166040820152939094166060840152608083019190915260a082015290151560c090910152919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60006020828403121561230e57600080fd5b8151610b6481611bfb565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fd5b6000825161235a818460208701611d32565b919091019291505056fea2646970667358221220aba3477f2b2fe8af51fb1d8c4ab96118b12f29e32da3cc98e0fddac12acfe47464736f6c63430008140033","runtime-code":"0x60806040526004361061024f5760003560e01c8063926d7d7f11610138578063b13aa2d6116100b0578063ca15c8731161007f578063d547741f11610064578063d547741f14610704578063dcf844a714610724578063e00a83e01461075157600080fd5b8063ca15c873146106b0578063ccc57490146106d057600080fd5b8063b13aa2d614610639578063b250fe6b14610659578063bf333f2c14610679578063c72870cc1461069057600080fd5b8063ac11fb1a11610107578063add98c70116100ec578063add98c70146105e8578063aedf009d14610603578063affed0e01461062357600080fd5b8063ac11fb1a1461059b578063acaebbf1146105c857600080fd5b8063926d7d7f146104fe578063a217fddf14610532578063a3ec191a14610547578063aa9641ab1461057b57600080fd5b80634774fa38116101cb57806385ad903d1161019a5780638f0d6f171161017f5780638f0d6f171461045a5780639010d07c1461046857806391d14854146104ad57600080fd5b806385ad903d14610412578063886d36ff1461043f57600080fd5b80634774fa38146103a157806358f85880146103ad5780635960ccf2146103c35780635eb7d946146103f757600080fd5b8063248a9ca31161022257806336568abe1161020757806336568abe1461035357806341fcb61214610373578063458516941461039357600080fd5b8063248a9ca3146103035780632f2ff15d1461033357600080fd5b806301ffc9a71461025457806303ed0ee51461028957806306f333f2146102cb5780630f5f6ed7146102ed575b600080fd5b34801561026057600080fd5b5061027461026f366004611984565b610767565b60405190151581526020015b60405180910390f35b34801561029557600080fd5b506102bd7f043c983c49d46f0e102151eaf8085d4a2e6571d5df2d47b013f39bddfd4a639d81565b604051908152602001610280565b3480156102d757600080fd5b506102eb6102e63660046119f8565b6107c3565b005b3480156102f957600080fd5b506102bd61271081565b34801561030f57600080fd5b506102bd61031e366004611a31565b60009081526020819052604090206001015490565b34801561033f57600080fd5b506102eb61034e366004611a4a565b6108b1565b34801561035f57600080fd5b506102eb61036e366004611a4a565b6108dc565b34801561037f57600080fd5b506102eb61038e366004611b97565b610935565b6102eb61038e366004611cb7565b3480156102eb57600080fd5b3480156103b957600080fd5b506102bd60025481565b3480156103cf57600080fd5b506102bd7fdb9556138406326f00296e13ea2ad7db24ba82381212d816b1a40c23b466b32781565b34801561040357600080fd5b506102eb61038e366004611cd4565b34801561041e57600080fd5b5061043261042d366004611d11565b61099c565b6040516102809190611da0565b34801561044b57600080fd5b506102eb61038e366004611db3565b6102eb61038e366004611cd4565b34801561047457600080fd5b50610488610483366004611df8565b610b4c565b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610280565b3480156104b957600080fd5b506102746104c8366004611a4a565b60009182526020828152604080842073ffffffffffffffffffffffffffffffffffffffff93909316845291905290205460ff1690565b34801561050a57600080fd5b506102bd7fe2b7fb3b832174769106daebcfd6d1970523240dda11281102db9363b83b0dc481565b34801561053e57600080fd5b506102bd600081565b34801561055357600080fd5b506102bd7f000000000000000000000000000000000000000000000000000000000000000081565b34801561058757600080fd5b50610274610596366004611a4a565b610b6b565b3480156105a757600080fd5b506105bb6105b6366004611cd4565b610bd0565b6040516102809190611e1a565b3480156105d457600080fd5b506102eb6105e3366004611f34565b610c43565b3480156105f457600080fd5b506102eb61038e366004611a31565b34801561060f57600080fd5b506102eb61061e366004611f74565b610e13565b34801561062f57600080fd5b506102bd60055481565b34801561064557600080fd5b506102eb610654366004611a31565b610e9e565b34801561066557600080fd5b506102eb610674366004611a31565b610f7b565b34801561068557600080fd5b506102bd620f424081565b34801561069c57600080fd5b506102eb6106ab366004611fcd565b610fe3565b3480156106bc57600080fd5b506102bd6106cb366004611a31565b611069565b3480156106dc57600080fd5b506102bd7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f5581565b34801561071057600080fd5b506102eb61071f366004611a4a565b611080565b34801561073057600080fd5b506102bd61073f366004612065565b60036020526000908152604090205481565b34801561075d57600080fd5b506102bd60045481565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f5a05180f0000000000000000000000000000000000000000000000000000000014806107bd57506107bd826110a5565b92915050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f556107ed8161113c565b73ffffffffffffffffffffffffffffffffffffffff8316600090815260036020526040812054908190036108215750505050565b73ffffffffffffffffffffffffffffffffffffffff8416600081815260036020526040812055610852908483611149565b6040805173ffffffffffffffffffffffffffffffffffffffff8087168252851660208201529081018290527f244e51bc38c1452fa8aaf487bcb4bca36c2baa3a5fbdb776b1eabd8dc6d277cd9060600160405180910390a1505b505050565b6000828152602081905260409020600101546108cc8161113c565b6108d683836112a0565b50505050565b73ffffffffffffffffffffffffffffffffffffffff8116331461092b576040517f6697b23200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6108ac82826112d5565b6040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f6e6f7420696d706c656d656e746564000000000000000000000000000000000060448201526064015b60405180910390fd5b60608160048111156109b0576109b0612082565b6000036109f057505060408051808201909152600481527f4e554c4c00000000000000000000000000000000000000000000000000000000602082015290565b816004811115610a0257610a02612082565b600103610a4257505060408051808201909152600981527f5245515545535445440000000000000000000000000000000000000000000000602082015290565b816004811115610a5457610a54612082565b600203610a9457505060408051808201909152600e81527f52454c415945525f50524f564544000000000000000000000000000000000000602082015290565b816004811115610aa657610aa6612082565b600303610ae657505060408051808201909152600f81527f52454c415945525f434c41494d45440000000000000000000000000000000000602082015290565b816004811115610af857610af8612082565b600403610b3857505060408051808201909152600881527f524546554e444544000000000000000000000000000000000000000000000000602082015290565b505060408051602081019091526000815290565b6000828152600160205260408120610b649083611302565b9392505050565b6040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f6e6f7420696d706c656d656e74656400000000000000000000000000000000006044820152600090606401610993565b604080516101808101825260008082526020808301829052928201819052606082018190526080820181905260a0820181905260c0820181905260e08201819052610100820181905261012082018190526101408201819052610160820152825190916107bd91840181019084016120d2565b6000620f42406002548360a00151610c5b91906121cd565b610c6591906121e4565b9050808260a001818151610c79919061221f565b9150818152505060006040518061018001604052804663ffffffff168152602001846000015163ffffffff168152602001846020015173ffffffffffffffffffffffffffffffffffffffff168152602001846040015173ffffffffffffffffffffffffffffffffffffffff168152602001846060015173ffffffffffffffffffffffffffffffffffffffff168152602001846080015173ffffffffffffffffffffffffffffffffffffffff1681526020018460a0015181526020018460c0015181526020018381526020018460e0015115158152602001846101000151815260200160056000815480929190610d6e90612232565b909155509052604051610d849190602001611e1a565b6040516020818303038152906040529050826020015173ffffffffffffffffffffffffffffffffffffffff16857f120ea0364f36cdac7983bcfdd55270ca09d7f9b314a2ebc425a3b01ab1d6403a838660000151876060015188608001518960a001518a60c001518b60e00151604051610e04979695949392919061226a565b60405180910390a35050505050565b6000610e1e82610bd0565b9050806040015173ffffffffffffffffffffffffffffffffffffffff16847f120ea0364f36cdac7983bcfdd55270ca09d7f9b314a2ebc425a3b01ab1d6403a84846020015185608001518660a001518760c001518860e00151896101200151604051610e90979695949392919061226a565b60405180910390a350505050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f55610ec88161113c565b612710821115610f34576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f6e657746656552617465203e206d6178000000000000000000000000000000006044820152606401610993565b600280549083905560408051828152602081018590527f14914da2bf76024616fbe1859783fcd4dbddcb179b1f3a854949fbf920dcb95791015b60405180910390a1505050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f55610fa58161113c565b600480549083905560408051828152602081018590527f5cf09b12f3f56b4c564d51b25b40360af6d795198adb61ae0806a36c294323fa9101610f6e565b6040805163ffffffff8816815273ffffffffffffffffffffffffffffffffffffffff878116602083015286811682840152606082018690526080820185905260a082018490529151898316928b16918c917ff8ae392d784b1ea5e8881bfa586d81abf07ef4f1e2fc75f7fe51c90f05199a5c9181900360c00190a4505050505050505050565b60008181526001602052604081206107bd9061130e565b60008281526020819052604090206001015461109b8161113c565b6108d683836112d5565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f7965db0b0000000000000000000000000000000000000000000000000000000014806107bd57507f01ffc9a7000000000000000000000000000000000000000000000000000000007fffffffff000000000000000000000000000000000000000000000000000000008316146107bd565b6111468133611318565b50565b3073ffffffffffffffffffffffffffffffffffffffff83160361116b57505050565b8060000361117857505050565b7fffffffffffffffffffffffff111111111111111111111111111111111111111273ffffffffffffffffffffffffffffffffffffffff84160161127f5760008273ffffffffffffffffffffffffffffffffffffffff168260405160006040518083038185875af1925050503d806000811461120f576040519150601f19603f3d011682016040523d82523d6000602084013e611214565b606091505b50509050806108d6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f455448207472616e73666572206661696c6564000000000000000000000000006044820152606401610993565b6108ac73ffffffffffffffffffffffffffffffffffffffff841683836113a2565b6000806112ad848461142f565b90508015610b645760008481526001602052604090206112cd908461152b565b509392505050565b6000806112e2848461154d565b90508015610b645760008481526001602052604090206112cd9084611608565b6000610b64838361162a565b60006107bd825490565b60008281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915290205460ff1661139e576040517fe2517d3f00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8216600482015260248101839052604401610993565b5050565b6040805173ffffffffffffffffffffffffffffffffffffffff8416602482015260448082018490528251808303909101815260649091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fa9059cbb000000000000000000000000000000000000000000000000000000001790526108ac908490611654565b60008281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915281205460ff166115235760008381526020818152604080832073ffffffffffffffffffffffffffffffffffffffff86168452909152902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790556114c13390565b73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16847f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45060016107bd565b5060006107bd565b6000610b648373ffffffffffffffffffffffffffffffffffffffff84166116ea565b60008281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915281205460ff16156115235760008381526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8616808552925280832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016905551339286917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a45060016107bd565b6000610b648373ffffffffffffffffffffffffffffffffffffffff8416611731565b6000826000018281548110611641576116416122cd565b9060005260206000200154905092915050565b600061167673ffffffffffffffffffffffffffffffffffffffff841683611824565b9050805160001415801561169b57508080602001905181019061169991906122fc565b155b156108ac576040517f5274afe700000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff84166004820152602401610993565b6000818152600183016020526040812054611523575081546001818101845560008481526020808220909301849055845484825282860190935260409020919091556107bd565b6000818152600183016020526040812054801561181a57600061175560018361221f565b85549091506000906117699060019061221f565b90508082146117ce576000866000018281548110611789576117896122cd565b90600052602060002001549050808760000184815481106117ac576117ac6122cd565b6000918252602080832090910192909255918252600188019052604090208390555b85548690806117df576117df612319565b6001900381819060005260206000200160009055905585600101600086815260200190815260200160002060009055600193505050506107bd565b60009150506107bd565b6060610b6483836000846000808573ffffffffffffffffffffffffffffffffffffffff1684866040516118579190612348565b60006040518083038185875af1925050503d8060008114611894576040519150601f19603f3d011682016040523d82523d6000602084013e611899565b606091505b50915091506118a98683836118b3565b9695505050505050565b6060826118c8576118c382611942565b610b64565b81511580156118ec575073ffffffffffffffffffffffffffffffffffffffff84163b155b1561193b576040517f9996b31500000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff85166004820152602401610993565b5080610b64565b8051156119525780518082602001fd5b6040517f1425ea4200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006020828403121561199657600080fd5b81357fffffffff0000000000000000000000000000000000000000000000000000000081168114610b6457600080fd5b73ffffffffffffffffffffffffffffffffffffffff8116811461114657600080fd5b80356119f3816119c6565b919050565b60008060408385031215611a0b57600080fd5b8235611a16816119c6565b91506020830135611a26816119c6565b809150509250929050565b600060208284031215611a4357600080fd5b5035919050565b60008060408385031215611a5d57600080fd5b823591506020830135611a26816119c6565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051610120810167ffffffffffffffff81118282101715611ac257611ac2611a6f565b60405290565b604051610180810167ffffffffffffffff81118282101715611ac257611ac2611a6f565b600082601f830112611afd57600080fd5b813567ffffffffffffffff80821115611b1857611b18611a6f565b604051601f83017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f01168101908282118183101715611b5e57611b5e611a6f565b81604052838152866020858801011115611b7757600080fd5b836020870160208301376000602085830101528094505050505092915050565b60008060408385031215611baa57600080fd5b823567ffffffffffffffff811115611bc157600080fd5b611bcd85828601611aec565b9250506020830135611a26816119c6565b63ffffffff8116811461114657600080fd5b80356119f381611bde565b801515811461114657600080fd5b80356119f381611bfb565b60006101208284031215611c2757600080fd5b611c2f611a9e565b9050611c3a82611bf0565b8152611c48602083016119e8565b6020820152611c59604083016119e8565b6040820152611c6a606083016119e8565b6060820152611c7b608083016119e8565b608082015260a082013560a082015260c082013560c0820152611ca060e08301611c09565b60e082015261010080830135818301525092915050565b60006101208284031215611cca57600080fd5b610b648383611c14565b600060208284031215611ce657600080fd5b813567ffffffffffffffff811115611cfd57600080fd5b611d0984828501611aec565b949350505050565b600060208284031215611d2357600080fd5b813560058110610b6457600080fd5b60005b83811015611d4d578181015183820152602001611d35565b50506000910152565b60008151808452611d6e816020860160208601611d32565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b602081526000610b646020830184611d56565b60008060408385031215611dc657600080fd5b823567ffffffffffffffff811115611ddd57600080fd5b611de985828601611aec565b95602094909401359450505050565b60008060408385031215611e0b57600080fd5b50508035926020909101359150565b815163ffffffff16815261018081016020830151611e40602084018263ffffffff169052565b506040830151611e68604084018273ffffffffffffffffffffffffffffffffffffffff169052565b506060830151611e90606084018273ffffffffffffffffffffffffffffffffffffffff169052565b506080830151611eb8608084018273ffffffffffffffffffffffffffffffffffffffff169052565b5060a0830151611ee060a084018273ffffffffffffffffffffffffffffffffffffffff169052565b5060c083015160c083015260e083015160e083015261010080840151818401525061012080840151611f158285018215159052565b5050610140838101519083015261016092830151929091019190915290565b60008060006101608486031215611f4a57600080fd5b833592506020840135611f5c816119c6565b9150611f6b8560408601611c14565b90509250925092565b600080600060608486031215611f8957600080fd5b833592506020840135611f9b816119c6565b9150604084013567ffffffffffffffff811115611fb757600080fd5b611fc386828701611aec565b9150509250925092565b60008060008060008060008060006101208a8c031215611fec57600080fd5b8935985060208a0135611ffe816119c6565b975060408a013561200e816119c6565b965060608a013561201e81611bde565b955060808a013561202e816119c6565b945060a08a013561203e816119c6565b8094505060c08a0135925060e08a013591506101008a013590509295985092959850929598565b60006020828403121561207757600080fd5b8135610b64816119c6565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b80516119f381611bde565b80516119f3816119c6565b80516119f381611bfb565b600061018082840312156120e557600080fd5b6120ed611ac8565b6120f6836120b1565b8152612104602084016120b1565b6020820152612115604084016120bc565b6040820152612126606084016120bc565b6060820152612137608084016120bc565b608082015261214860a084016120bc565b60a082015260c083015160c082015260e083015160e082015261010080840151818301525061012061217b8185016120c7565b908201526101408381015190820152610160928301519281019290925250919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b80820281158282048414176107bd576107bd61219e565b60008261221a577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b818103818111156107bd576107bd61219e565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82036122635761226361219e565b5060010190565b60e08152600061227d60e083018a611d56565b63ffffffff9890981660208301525073ffffffffffffffffffffffffffffffffffffffff9586166040820152939094166060840152608083019190915260a082015290151560c090910152919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60006020828403121561230e57600080fd5b8151610b6481611bfb565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fd5b6000825161235a818460208701611d32565b919091019291505056fea2646970667358221220aba3477f2b2fe8af51fb1d8c4ab96118b12f29e32da3cc98e0fddac12acfe47464736f6c63430008140033","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.20 ^0.8.20 ^0.8.4;\n\n// contracts/interfaces/IAdmin.sol\n\ninterface IAdmin {\n // ============ Events ============\n\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n event ChainGasAmountUpdated(uint256 oldChainGasAmount, uint256 newChainGasAmount);\n\n // ============ Methods ============\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n\n function setChainGasAmount(uint256 newChainGasAmount) external;\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IMulticallTarget.sol\n\n/// @notice Interface for a contract that can be called multiple times by the same caller. Inspired by MulticallV3:\n/// https://github.com/mds1/multicall/blob/master/src/Multicall3.sol\ninterface IMulticallTarget {\n struct Result {\n bool success;\n bytes returnData;\n }\n\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external;\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results);\n}\n\n// contracts/libs/Errors.sol\n\nerror DeadlineExceeded();\nerror DeadlineNotExceeded();\nerror DeadlineTooShort();\nerror InsufficientOutputAmount();\n\nerror MsgValueIncorrect();\nerror PoolNotFound();\nerror TokenAddressMismatch();\nerror TokenNotContract();\nerror TokenNotETH();\nerror TokensIdentical();\n\nerror ChainIncorrect();\nerror AmountIncorrect();\nerror ZeroAddress();\n\nerror DisputePeriodNotPassed();\nerror DisputePeriodPassed();\nerror SenderIncorrect();\nerror StatusIncorrect();\nerror TransactionIdIncorrect();\nerror TransactionRelayed();\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// contracts/utils/MulticallTarget.sol\n\n// solhint-disable avoid-low-level-calls\n/// @notice Template for a contract that supports batched calls (preserving the msg.sender).\n/// Only calls with zero msg.value could be batched.\nabstract contract MulticallTarget is IMulticallTarget {\n error MulticallTarget__UndeterminedRevert();\n\n /// @notice Perform a batched call to this contract, preserving the msg.sender.\n /// The return data from each call is discarded.\n /// @dev The method is non-payable, so only calls with `msg.value == 0` could be batched.\n /// It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag.\n /// Otherwise, the whole batch call will be reverted with the original revert reason.\n /// @param data List of abi-encoded calldata for the calls to perform.\n /// @param ignoreReverts Whether to ignore the revert errors from the calls.\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external {\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\n if (!success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(result);\n }\n }\n }\n\n /// @notice Perform a batched call to this contract, preserving the msg.sender.\n /// The return data from each call is preserved.\n /// @dev The method is non-payable, so only calls with `msg.value == 0` could be batched.\n /// It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag.\n /// Otherwise, the whole batch call will be reverted with the original revert reason.\n /// @param data List of abi-encoded calldata for the calls to perform.\n /// @param ignoreReverts Whether to ignore the revert errors from the calls.\n /// @return results List of results from the calls: `(success, returnData)`.\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results)\n {\n results = new Result[](data.length);\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (results[i].success, results[i].returnData) = address(this).delegatecall(data[i]);\n if (!results[i].success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(results[i].returnData);\n }\n }\n }\n\n /// @dev Bubbles the revert message from the underlying call.\n /// Note: preserves the same custom error or revert string, if one was used.\n /// Source: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v5.0.2/contracts/utils/Address.sol#L143-L158\n function _bubbleRevert(bytes memory returnData) internal pure {\n // Look for revert reason and bubble it up if present\n if (returnData.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n // solhint-disable-next-line no-inline-assembly\n assembly {\n let returndata_size := mload(returnData)\n revert(add(32, returnData), returndata_size)\n }\n } else {\n revert MulticallTarget__UndeterminedRevert();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// contracts/libs/UniversalToken.sol\n\nlibrary UniversalTokenLib {\n using SafeERC20 for IERC20;\n\n address internal constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Transfers tokens to the given account. Reverts if transfer is not successful.\n /// @dev This might trigger fallback, if ETH is transferred to the contract.\n /// Make sure this can not lead to reentrancy attacks.\n function universalTransfer(address token, address to, uint256 value) internal {\n // Don't do anything, if need to send tokens to this address\n if (to == address(this)) return;\n // Don't do anything, if trying to send zero value\n if (value == 0) return;\n if (token == ETH_ADDRESS) {\n /// @dev Note: this can potentially lead to executing code in `to`.\n // solhint-disable-next-line avoid-low-level-calls\n (bool success,) = to.call{value: value}(\"\");\n require(success, \"ETH transfer failed\");\n } else {\n IERC20(token).safeTransfer(to, value);\n }\n }\n\n /// @notice Issues an infinite allowance to the spender, if the current allowance is insufficient\n /// to spend the given amount.\n function universalApproveInfinity(address token, address spender, uint256 amountToSpend) internal {\n // ETH Chad doesn't require your approval\n if (token == ETH_ADDRESS) return;\n // No-op if allowance is already sufficient\n uint256 allowance = IERC20(token).allowance(address(this), spender);\n if (allowance \u003e= amountToSpend) return;\n // Otherwise, reset approval to 0 and set to max allowance\n if (allowance \u003e 0) IERC20(token).safeDecreaseAllowance(spender, allowance);\n IERC20(token).safeIncreaseAllowance(spender, type(uint256).max);\n }\n\n /// @notice Returns the balance of the given token (or native ETH) for the given account.\n function universalBalanceOf(address token, address account) internal view returns (uint256) {\n if (token == ETH_ADDRESS) {\n return account.balance;\n } else {\n return IERC20(token).balanceOf(account);\n }\n }\n\n /// @dev Checks that token is a contract and not ETH_ADDRESS.\n function assertIsContract(address token) internal view {\n // Check that ETH_ADDRESS was not used (in case this is a predeploy on any of the chains)\n if (token == UniversalTokenLib.ETH_ADDRESS) revert TokenNotContract();\n // Check that token is not an EOA\n if (token.code.length == 0) revert TokenNotContract();\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/Admin.sol\n\ncontract Admin is IAdmin, AccessControlEnumerable {\n using UniversalTokenLib for address;\n\n bytes32 public constant RELAYER_ROLE = keccak256(\"RELAYER_ROLE\");\n bytes32 public constant REFUNDER_ROLE = keccak256(\"REFUNDER_ROLE\");\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n uint256 public constant FEE_BPS = 1e6;\n uint256 public constant FEE_RATE_MAX = 0.01e6; // max 1% on origin amount\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Chain gas amount to forward as rebate if requested\n uint256 public chainGasAmount;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n }\n\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n require(newFeeRate \u003c= FEE_RATE_MAX, \"newFeeRate \u003e max\");\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n token.universalTransfer(recipient, feeAmount);\n emit FeesSwept(token, recipient, feeAmount);\n }\n\n function setChainGasAmount(uint256 newChainGasAmount) external onlyRole(GOVERNOR_ROLE) {\n uint256 oldChainGasAmount = chainGasAmount;\n chainGasAmount = newChainGasAmount;\n emit ChainGasAmountUpdated(oldChainGasAmount, newChainGasAmount);\n }\n}\n\n// contracts/FastBridge.sol\n\ncontract FastBridge is IFastBridge, MulticallTarget, Admin {\n using SafeERC20 for IERC20;\n using UniversalTokenLib for address;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Delay for a transaction after which it could be permisionlessly refunded\n uint256 public constant REFUND_DELAY = 7 days;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeStatus) public bridgeStatuses;\n /// @notice Proof of relayed bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeProof) public bridgeProofs;\n /// @notice Whether bridge has been relayed on destination chain\n mapping(bytes32 =\u003e bool) public bridgeRelays;\n\n /// @dev to prevent replays\n uint256 public nonce;\n // @dev the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @notice Pulls a requested token from the user to the requested recipient.\n /// @dev Be careful of re-entrancy issues when msg.value \u003e 0 and recipient != address(this)\n function _pullToken(address recipient, address token, uint256 amount) internal returns (uint256 amountPulled) {\n if (token != UniversalTokenLib.ETH_ADDRESS) {\n token.assertIsContract();\n // Record token balance before transfer\n amountPulled = IERC20(token).balanceOf(recipient);\n // Token needs to be pulled only if msg.value is zero\n // This way user can specify WETH as the origin asset\n IERC20(token).safeTransferFrom(msg.sender, recipient, amount);\n // Use the difference between the recorded balance and the current balance as the amountPulled\n amountPulled = IERC20(token).balanceOf(recipient) - amountPulled;\n } else {\n // Otherwise, we need to check that ETH amount matches msg.value\n if (amount != msg.value) revert MsgValueIncorrect();\n // Transfer value to recipient if not this address\n if (recipient != address(this)) token.universalTransfer(recipient, amount);\n // We will forward msg.value in the external call later, if recipient is not this contract\n amountPulled = msg.value;\n }\n }\n\n /// @inheritdoc IFastBridge\n function getBridgeTransaction(bytes memory request) public pure returns (BridgeTransaction memory) {\n return abi.decode(request, (BridgeTransaction));\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n // check bridge params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n\n // transfer tokens to bridge contract\n // @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _pullToken(address(this), params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n\n // set status to requested\n bytes memory request = abi.encode(\n BridgeTransaction({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n sendChainGas: params.sendChainGas,\n deadline: params.deadline,\n nonce: nonce++ // increment nonce on every bridge\n })\n );\n bytes32 transactionId = keccak256(request);\n bridgeStatuses[transactionId] = BridgeStatus.REQUESTED;\n\n emit BridgeRequested(\n transactionId,\n params.sender,\n request,\n params.dstChainId,\n params.originToken,\n params.destToken,\n originAmount,\n params.destAmount,\n params.sendChainGas\n );\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes memory request) external payable onlyRole(RELAYER_ROLE) {\n bytes32 transactionId = keccak256(request);\n BridgeTransaction memory transaction = getBridgeTransaction(request);\n if (transaction.destChainId != uint32(block.chainid)) revert ChainIncorrect();\n\n // check haven't exceeded deadline for relay to happen\n if (block.timestamp \u003e transaction.deadline) revert DeadlineExceeded();\n\n // mark bridge transaction as relayed\n if (bridgeRelays[transactionId]) revert TransactionRelayed();\n bridgeRelays[transactionId] = true;\n\n // transfer tokens to recipient on destination chain and gas rebate if requested\n address to = transaction.destRecipient;\n address token = transaction.destToken;\n uint256 amount = transaction.destAmount;\n\n uint256 rebate = chainGasAmount;\n if (!transaction.sendChainGas) {\n // forward erc20\n rebate = 0;\n _pullToken(to, token, amount);\n } else if (token == UniversalTokenLib.ETH_ADDRESS) {\n // lump in gas rebate into amount in native gas token\n _pullToken(to, token, amount + rebate);\n } else {\n // forward erc20 then forward gas rebate in native gas token\n _pullToken(to, token, amount);\n _pullToken(to, UniversalTokenLib.ETH_ADDRESS, rebate);\n }\n\n emit BridgeRelayed(\n transactionId,\n msg.sender,\n to,\n transaction.originChainId,\n transaction.originToken,\n transaction.destToken,\n transaction.originAmount,\n transaction.destAmount,\n rebate\n );\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes memory request, bytes32 destTxHash) external onlyRole(RELAYER_ROLE) {\n bytes32 transactionId = keccak256(request);\n // update bridge tx status given proof provided\n if (bridgeStatuses[transactionId] != BridgeStatus.REQUESTED) revert StatusIncorrect();\n bridgeStatuses[transactionId] = BridgeStatus.RELAYER_PROVED;\n bridgeProofs[transactionId] = BridgeProof({timestamp: uint96(block.timestamp), relayer: msg.sender}); // overflow ok\n\n emit BridgeProofProvided(transactionId, msg.sender, destTxHash);\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint96(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint96).max but\n /// proof.timestamp \u003c type(uint96).max via unchecked statement\n /// @param proof The bridge proof\n /// @return delta Time delta since proof submitted\n function _timeSince(BridgeProof memory proof) internal view returns (uint256 delta) {\n unchecked {\n delta = uint96(block.timestamp) - proof.timestamp;\n }\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n if (bridgeStatuses[transactionId] != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n BridgeProof memory proof = bridgeProofs[transactionId];\n if (proof.relayer != relayer) revert SenderIncorrect();\n return _timeSince(proof) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes memory request, address to) external onlyRole(RELAYER_ROLE) {\n bytes32 transactionId = keccak256(request);\n BridgeTransaction memory transaction = getBridgeTransaction(request);\n\n // update bridge tx status if able to claim origin collateral\n if (bridgeStatuses[transactionId] != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n\n BridgeProof memory proof = bridgeProofs[transactionId];\n if (proof.relayer != msg.sender) revert SenderIncorrect();\n if (_timeSince(proof) \u003c= DISPUTE_PERIOD) revert DisputePeriodNotPassed();\n\n bridgeStatuses[transactionId] = BridgeStatus.RELAYER_CLAIMED;\n\n // update protocol fees if origin fee amount exists\n if (transaction.originFeeAmount \u003e 0) protocolFees[transaction.originToken] += transaction.originFeeAmount;\n\n // transfer origin collateral less fee to specified address\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositClaimed(transactionId, msg.sender, to, token, amount);\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n if (bridgeStatuses[transactionId] != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(bridgeProofs[transactionId]) \u003e DISPUTE_PERIOD) revert DisputePeriodPassed();\n\n // @dev relayer gets slashed effectively if dest relay has gone thru\n bridgeStatuses[transactionId] = BridgeStatus.REQUESTED;\n delete bridgeProofs[transactionId];\n\n emit BridgeProofDisputed(transactionId, msg.sender);\n }\n\n /// @inheritdoc IFastBridge\n function refund(bytes memory request) external {\n bytes32 transactionId = keccak256(request);\n BridgeTransaction memory transaction = getBridgeTransaction(request);\n\n if (hasRole(REFUNDER_ROLE, msg.sender)) {\n // Refunder can refund if deadline has passed\n if (block.timestamp \u003c= transaction.deadline) revert DeadlineNotExceeded();\n } else {\n // Permissionless refund is allowed after REFUND_DELAY\n if (block.timestamp \u003c= transaction.deadline + REFUND_DELAY) revert DeadlineNotExceeded();\n }\n\n // set status to refunded if still in requested state\n if (bridgeStatuses[transactionId] != BridgeStatus.REQUESTED) revert StatusIncorrect();\n bridgeStatuses[transactionId] = BridgeStatus.REFUNDED;\n\n // transfer origin collateral back to original sender\n address to = transaction.originSender;\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount + transaction.originFeeAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n }\n}\n\n// test/FastBridgeMock.sol\n\ncontract FastBridgeMock is IFastBridge, Admin {\n // @dev the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @dev to prevent replays\n uint256 public nonce;\n\n /// @notice We include an empty \"test\" function so that this contract does not appear in the coverage report.\n function testFastBridgeMock() external {}\n\n function getBridgeTransaction(bytes memory request) public pure returns (BridgeTransaction memory) {\n return abi.decode(request, (BridgeTransaction));\n }\n\n // used for testing in go.\n // see: https://ethereum.stackexchange.com/questions/21155/how-to-expose-enum-in-solidity-contract\n // make sure to update fastbridge/status.go if this changes\n // or underliyng enum changes.\n //\n // TODO: a foundry test should be added to ensure this is always in sync.\n function getEnumKeyByValue(FastBridge.BridgeStatus keyValue) public pure returns (string memory) {\n if (FastBridge.BridgeStatus.NULL == keyValue) return \"NULL\";\n if (FastBridge.BridgeStatus.REQUESTED == keyValue) return \"REQUESTED\";\n if (FastBridge.BridgeStatus.RELAYER_PROVED == keyValue) return \"RELAYER_PROVED\";\n if (FastBridge.BridgeStatus.RELAYER_CLAIMED == keyValue) return \"RELAYER_CLAIMED\";\n if (FastBridge.BridgeStatus.REFUNDED == keyValue) return \"REFUNDED\";\n return \"\";\n }\n\n function mockBridgeRequest(bytes32 transactionId, address sender, BridgeParams memory params) external {\n sender;\n uint256 originFeeAmount = (params.originAmount * protocolFeeRate) / FEE_BPS;\n params.originAmount -= originFeeAmount;\n\n bytes memory request = abi.encode(\n BridgeTransaction({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: params.originAmount, // includes relayer fee\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n sendChainGas: params.sendChainGas,\n deadline: params.deadline,\n nonce: nonce++ // increment nonce on every bridge\n })\n );\n\n emit BridgeRequested(\n transactionId,\n params.sender,\n request,\n params.dstChainId,\n params.originToken,\n params.destToken,\n params.originAmount,\n params.destAmount,\n params.sendChainGas\n );\n }\n\n function mockBridgeRequestRaw(bytes32 transactionId, address sender, bytes memory request) external {\n sender;\n BridgeTransaction memory transaction = getBridgeTransaction(request);\n emit BridgeRequested(\n transactionId,\n transaction.originSender,\n request,\n transaction.destChainId,\n transaction.originToken,\n transaction.destToken,\n transaction.originAmount,\n transaction.destAmount,\n transaction.sendChainGas\n );\n }\n\n function mockBridgeRelayer(\n bytes32 transactionId,\n address relayer,\n address to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n )\n external\n {\n emit BridgeRelayed(\n transactionId, relayer, to, originChainId, originToken, destToken, originAmount, destAmount, chainGasAmount\n );\n }\n\n function bridge(BridgeParams memory) external payable {\n revert(\"not implemented\");\n }\n\n function relay(bytes memory) external payable {\n revert(\"not implemented\");\n }\n\n function prove(bytes memory, bytes32) external pure {\n revert(\"not implemented\");\n }\n\n function canClaim(bytes32, address) external pure returns (bool) {\n revert(\"not implemented\");\n }\n\n function claim(bytes memory, address) external pure {\n revert(\"not implemented\");\n }\n\n function dispute(bytes32) external pure {\n revert(\"not implemented\");\n }\n\n function refund(bytes memory) external pure {\n revert(\"not implemented\");\n }\n}\n","language":"Solidity","languageVersion":"0.8.20","compilerVersion":"0.8.20","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"74164:4483:0:-:0;;;74310:85;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;74344:6;61804:38;50976:4;74344:6;61804:10;:38::i;:::-;-1:-1:-1;;74376:12:0::1;74362:26;::::0;-1:-1:-1;74164:4483:0;;60289:257;60375:4;;60406:31;60423:4;60429:7;60406:16;:31::i;:::-;60391:46;;60451:7;60447:69;;;60474:18;;;;:12;:18;;;;;:31;;60497:7;60474:22;:31::i;:::-;;60447:69;60532:7;-1:-1:-1;60289:257:0;;;;;:::o;54923:316::-;55000:4;51698:12;;;;;;;;;;;-1:-1:-1;;;;;51698:29:0;;;;;;;;;;;;55016:217;;55059:6;:12;;;;;;;;;;;-1:-1:-1;;;;;55059:29:0;;;;;;;;;:36;;-1:-1:-1;;55059:36:0;55091:4;55059:36;;;55141:12;22984:10;;22905:96;55141:12;-1:-1:-1;;;;;55114:40:0;55132:7;-1:-1:-1;;;;;55114:40:0;55126:4;55114:40;;;;;;;;;;-1:-1:-1;55175:4:0;55168:11;;55016:217;-1:-1:-1;55217:5:0;55210:12;;32429:150;32499:4;32522:50;32527:3;-1:-1:-1;;;;;32547:23:0;;26417:4;28473:21;;;:14;;;:21;;;;;;26433:321;;-1:-1:-1;26475:23:0;;;;;;;;:11;:23;;;;;;;;;;;;;26657:18;;26633:21;;;:14;;;:21;;;;;;:42;;;;26689:11;;14:290:1;84:6;137:2;125:9;116:7;112:23;108:32;105:52;;;153:1;150;143:12;105:52;179:16;;-1:-1:-1;;;;;224:31:1;;214:42;;204:70;;270:1;267;260:12;14:290;74164:4483:0;;;;;;;;;;;;","srcMapRuntime":"74164:4483:0:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;58949:212;;;;;;;;;;-1:-1:-1;58949:212:0;;;;;:::i;:::-;;:::i;:::-;;;612:14:1;;605:22;587:41;;575:2;560:18;58949:212:0;;;;;;;;61179:60;;;;;;;;;;;;61216:23;61179:60;;;;;785:25:1;;;773:2;758:18;61179:60:0;639:177:1;62151:359:0;;;;;;;;;;-1:-1:-1;62151:359:0;;;;;:::i;:::-;;:::i;:::-;;61361:45;;;;;;;;;;;;61400:6;61361:45;;52554:120;;;;;;;;;;-1:-1:-1;52554:120:0;;;;;:::i;:::-;52619:7;52645:12;;;;;;;;;;:22;;;;52554:120;52970:136;;;;;;;;;;-1:-1:-1;52970:136:0;;;;;:::i;:::-;;:::i;54072:245::-;;;;;;;;;;-1:-1:-1;54072:245:0;;;;;:::i;:::-;;:::i;78371:94::-;;;;;;;;;;-1:-1:-1;78371:94:0;;;;;:::i;:::-;;:::i;77962:96::-;;;;;;:::i;74574:41::-;;;;;;;;;61523:30;;;;;;;;;;;;;;;;61107:66;;;;;;;;;;;;61147:26;61107:66;;78559:86;;;;;;;;;;-1:-1:-1;78559:86:0;;;;;:::i;75108:528::-;;;;;;;;;;-1:-1:-1;75108:528:0;;;;;:::i;:::-;;:::i;:::-;;;;;;;:::i;78158:94::-;;;;;;;;;;-1:-1:-1;78158:94:0;;;;;:::i;78064:88::-;;;;;;:::i;59746:142::-;;;;;;;;;;-1:-1:-1;59746:142:0;;;;;:::i;:::-;;:::i;:::-;;;8086:42:1;8074:55;;;8056:74;;8044:2;8029:18;59746:142:0;7910:226:1;51598:136:0;;;;;;;;;;-1:-1:-1;51598:136:0;;;;;:::i;:::-;51675:4;51698:12;;;;;;;;;;;:29;;;;;;;;;;;;;;;;51598:136;61037:64;;;;;;;;;;;;61076:25;61037:64;;50931:49;;;;;;;;;;-1:-1:-1;50931:49:0;50976:4;50931:49;;74267:36;;;;;;;;;;;;;;;78258:107;;;;;;;;;;-1:-1:-1;78258:107:0;;;;;:::i;:::-;;:::i;74621:163::-;;;;;;;;;;-1:-1:-1;74621:163:0;;;;;:::i;:::-;;:::i;:::-;;;;;;;:::i;75642:1282::-;;;;;;;;;;-1:-1:-1;75642:1282:0;;;;;:::i;:::-;;:::i;78471:82::-;;;;;;;;;;-1:-1:-1;78471:82:0;;;;;:::i;76930:548::-;;;;;;;;;;-1:-1:-1;76930:548:0;;;;;:::i;:::-;;:::i;74433:20::-;;;;;;;;;;;;;;;;61855:290;;;;;;;;;;-1:-1:-1;61855:290:0;;;;;:::i;:::-;;:::i;62516:264::-;;;;;;;;;;-1:-1:-1;62516:264:0;;;;;:::i;:::-;;:::i;61318:37::-;;;;;;;;;;;;61352:3;61318:37;;77484:472;;;;;;;;;;-1:-1:-1;77484:472:0;;;;;:::i;:::-;;:::i;60056:131::-;;;;;;;;;;-1:-1:-1;60056:131:0;;;;;:::i;:::-;;:::i;61245:66::-;;;;;;;;;;;;61285:26;61245:66;;53386:138;;;;;;;;;;-1:-1:-1;53386:138:0;;;;;:::i;:::-;;:::i;61609:47::-;;;;;;;;;;-1:-1:-1;61609:47:0;;;;;:::i;:::-;;;;;;;;;;;;;;61730:29;;;;;;;;;;;;;;;;58949:212;59034:4;59057:57;;;59072:42;59057:57;;:97;;;59118:36;59142:11;59118:23;:36::i;:::-;59050:104;58949:212;-1:-1:-1;;58949:212:0:o;62151:359::-;61285:26;51208:16;51219:4;51208:10;:16::i;:::-;62275:19:::1;::::0;::::1;62255:17;62275:19:::0;;;:12:::1;:19;::::0;;;;;;62308:14;;;62304:27:::1;;62324:7;62151:359:::0;;;:::o;62304:27::-:1;62372:19;::::0;::::1;62394:1;62372:19:::0;;;:12:::1;:19;::::0;;;;:23;62405:45:::1;::::0;62429:9;62440;62405:23:::1;:45::i;:::-;62465:38;::::0;;12332:42:1;12401:15;;;12383:34;;12453:15;;12448:2;12433:18;;12426:43;12485:18;;;12478:34;;;62465:38:0::1;::::0;12310:2:1;12295:18;62465:38:0::1;;;;;;;62245:265;51234:1;62151:359:::0;;;:::o;52970:136::-;52619:7;52645:12;;;;;;;;;;:22;;;51208:16;51219:4;51208:10;:16::i;:::-;53074:25:::1;53085:4;53091:7;53074:10;:25::i;:::-;;52970:136:::0;;;:::o;54072:245::-;54165:34;;;22984:10;54165:34;54161:102;;54222:30;;;;;;;;;;;;;;54161:102;54273:37;54285:4;54291:18;54273:11;:37::i;78371:94::-;78433:25;;;;;12725:2:1;78433:25:0;;;12707:21:1;12764:2;12744:18;;;12737:30;12803:17;12783:18;;;12776:45;12838:18;;78433:25:0;;;;;;;;75108:528;75190:13;75251:8;75219:40;;;;;;;;:::i;:::-;:28;:40;75215:59;;-1:-1:-1;;75261:13:0;;;;;;;;;;;;;;;;;;75108:528::o;75215:59::-;75325:8;75288:45;;;;;;;;:::i;:::-;:33;:45;75284:69;;-1:-1:-1;;75335:18:0;;;;;;;;;;;;;;;;;;75108:528::o;75284:69::-;75409:8;75367:50;;;;;;;;:::i;:::-;:38;:50;75363:79;;-1:-1:-1;;75419:23:0;;;;;;;;;;;;;;;;;;75108:528::o;75363:79::-;75499:8;75456:51;;;;;;;;:::i;:::-;:39;:51;75452:81;;-1:-1:-1;;75509:24:0;;;;;;;;;;;;;;;;;;75108:528::o;75452:81::-;75583:8;75547:44;;;;;;;;:::i;:::-;:32;:44;75543:67;;-1:-1:-1;;75593:17:0;;;;;;;;;;;;;;;;;;75108:528::o;75543:67::-;-1:-1:-1;;75620:9:0;;;;;;;;;-1:-1:-1;75620:9:0;;;75108:528::o;59746:142::-;59827:7;59853:18;;;:12;:18;;;;;:28;;59875:5;59853:21;:28::i;:::-;59846:35;59746:142;-1:-1:-1;;;59746:142:0:o;78258:107::-;78333:25;;;;;12725:2:1;78333:25:0;;;12707:21:1;12764:2;12744:18;;;12737:30;12803:17;12783:18;;;12776:45;78317:4:0;;12838:18:1;;78333:25:0;12523:339:1;74621:163:0;-1:-1:-1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;74737:40:0;;-1:-1:-1;;74737:40:0;;;;;;;;;;:::i;75642:1282::-;75771:23;61352:3;75820:15;;75798:6;:19;;;:37;;;;:::i;:::-;75797:49;;;;:::i;:::-;75771:75;;75879:15;75856:6;:19;;:38;;;;;;;:::i;:::-;;;;;;;;75905:20;75952:649;;;;;;;;76010:13;75952:649;;;;;;76055:6;:17;;;75952:649;;;;;;76104:6;:13;;;75952:649;;;;;;76150:6;:9;;;75952:649;;;;;;76190:6;:18;;;75952:649;;;;;;76237:6;:16;;;75952:649;;;;;;76285:6;:19;;;75952:649;;;;76358:6;:17;;;75952:649;;;;76410:15;75952:649;;;;76457:6;:19;;;75952:649;;;;;;76504:6;:15;;;75952:649;;;;76544:5;;:7;;;;;;;;;:::i;:::-;;;;-1:-1:-1;75952:649:0;;75928:683;;;;;;;;:::i;:::-;;;;;;;;;;;;;75905:706;;76683:6;:13;;;76627:290;;76656:13;76627:290;76710:7;76731:6;:17;;;76762:6;:18;;;76794:6;:16;;;76824:6;:19;;;76857:6;:17;;;76888:6;:19;;;76627:290;;;;;;;;;;;;:::i;:::-;;;;;;;;75745:1179;;75642:1282;;;:::o;76930:548::-;77056:36;77095:29;77116:7;77095:20;:29::i;:::-;77056:68;;77195:11;:24;;;77139:332;;77168:13;77139:332;77233:7;77254:11;:23;;;77291:11;:23;;;77328:11;:21;;;77363:11;:24;;;77401:11;:22;;;77437:11;:24;;;77139:332;;;;;;;;;;;;:::i;:::-;;;;;;;;77030:448;76930:548;;;:::o;61855:290::-;61285:26;51208:16;51219:4;51208:10;:16::i;:::-;61400:6:::1;61954:10;:26;;61946:55;;;::::0;::::1;::::0;;16599:2:1;61946:55:0::1;::::0;::::1;16581:21:1::0;16638:2;16618:18;;;16611:30;16677:18;16657;;;16650:46;16713:18;;61946:55:0::1;16397:340:1::0;61946:55:0::1;62032:15;::::0;;62057:28;;;;62100:38:::1;::::0;;16916:25:1;;;16972:2;16957:18;;16950:34;;;62100:38:0::1;::::0;16889:18:1;62100:38:0::1;;;;;;;;61936:209;61855:290:::0;;:::o;62516:264::-;61285:26;51208:16;51219:4;51208:10;:16::i;:::-;62641:14:::1;::::0;;62665:34;;;;62714:59:::1;::::0;;16916:25:1;;;16972:2;16957:18;;16950:34;;;62714:59:0::1;::::0;16889:18:1;62714:59:0::1;16742:248:1::0;77484:472:0;77805:144;;;17310:10:1;17298:23;;17280:42;;77805:144:0;17419:15:1;;;17414:2;17399:18;;17392:43;17471:15;;;17451:18;;;17444:43;17518:2;17503:18;;17496:34;;;17561:3;17546:19;;17539:35;;;17605:3;17590:19;;17583:35;;;77805:144:0;;;;;;;;;77832:13;;77805:144;;;;;17267:3:1;77805:144:0;;;77484:472;;;;;;;;;:::o;60056:131::-;60127:7;60153:18;;;:12;:18;;;;;:27;;:25;:27::i;53386:138::-;52619:7;52645:12;;;;;;;;;;:22;;;51208:16;51219:4;51208:10;:16::i;:::-;53491:26:::1;53503:4;53509:7;53491:11;:26::i;51309:202::-:0;51394:4;51417:47;;;51432:32;51417:47;;:87;;-1:-1:-1;43224:25:0;43209:40;;;;51468:36;43110:146;51943:103;52009:30;52020:4;22984:10;52009;:30::i;:::-;51943:103;:::o;56221:653::-;56396:4;56382:19;;;;56378:32;;56221:653;;;:::o;56378:32::-;56482:5;56491:1;56482:10;56478:23;;56221:653;;;:::o;56478:23::-;56514:20;;;;;56510:358;;56694:12;56711:2;:7;;56726:5;56711:25;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;56693:43;;;56758:7;56750:39;;;;;;;18041:2:1;56750:39:0;;;18023:21:1;18080:2;18060:18;;;18053:30;18119:21;18099:18;;;18092:49;18158:18;;56750:39:0;17839:343:1;56510:358:0;56820:37;:26;;;56847:2;56851:5;56820:26;:37::i;60289:257::-;60375:4;60391:12;60406:31;60423:4;60429:7;60406:16;:31::i;:::-;60391:46;;60451:7;60447:69;;;60474:18;;;;:12;:18;;;;;:31;;60497:7;60474:22;:31::i;:::-;;60532:7;60289:257;-1:-1:-1;;;60289:257:0:o;60649:262::-;60736:4;60752:12;60767:32;60785:4;60791:7;60767:17;:32::i;:::-;60752:47;;60813:7;60809:72;;;60836:18;;;;:12;:18;;;;;:34;;60862:7;60836:25;:34::i;33687:156::-;33761:7;33811:22;33815:3;33827:5;33811:3;:22::i;33230:115::-;33293:7;33319:19;33327:3;28669:18;;28587:107;52176:197;51675:4;51698:12;;;;;;;;;;;:29;;;;;;;;;;;;;52259:108;;52309:47;;;;;18391:42:1;18379:55;;52309:47:0;;;18361:74:1;18451:18;;;18444:34;;;18334:18;;52309:47:0;18187:297:1;52259:108:0;52176:197;;:::o;44426:160::-;44535:43;;;44550:14;18379:55:1;;44535:43:0;;;18361:74:1;18451:18;;;;18444:34;;;44535:43:0;;;;;;;;;;18334:18:1;;;;44535:43:0;;;;;;;;;;;;;;44508:71;;44528:5;;44508:19;:71::i;54923:316::-;55000:4;51698:12;;;;;;;;;;;:29;;;;;;;;;;;;;55016:217;;55059:6;:12;;;;;;;;;;;:29;;;;;;;;;;:36;;;;55091:4;55059:36;;;55141:12;22984:10;;22905:96;55141:12;55114:40;;55132:7;55114:40;;55126:4;55114:40;;;;;;;;;;-1:-1:-1;55175:4:0;55168:11;;55016:217;-1:-1:-1;55217:5:0;55210:12;;32429:150;32499:4;32522:50;32527:3;32547:23;;;32522:4;:50::i;55474:317::-;55552:4;51698:12;;;;;;;;;;;:29;;;;;;;;;;;;;55568:217;;;55642:5;55610:12;;;;;;;;;;;:29;;;;;;;;;;;:37;;;;;;55666:40;22984:10;;55610:12;;55666:40;;55642:5;55666:40;-1:-1:-1;55727:4:0;55720:11;;32747:156;32820:4;32843:53;32851:3;32871:23;;;32843:7;:53::i;29036:118::-;29103:7;29129:3;:11;;29141:5;29129:18;;;;;;;;:::i;:::-;;;;;;;;;29122:25;;29036:118;;;;:::o;47182:629::-;47601:23;47627:33;:27;;;47655:4;47627:27;:33::i;:::-;47601:59;;47674:10;:17;47695:1;47674:22;;:57;;;;;47712:10;47701:30;;;;;;;;;;;;:::i;:::-;47700:31;47674:57;47670:135;;;47754:40;;;;;8086:42:1;8074:55;;47754:40:0;;;8056:74:1;8029:18;;47754:40:0;7910:226:1;26354:406:0;26417:4;28473:21;;;:14;;;:21;;;;;;26433:321;;-1:-1:-1;26475:23:0;;;;;;;;:11;:23;;;;;;;;;;;;;26657:18;;26633:21;;;:14;;;:21;;;;;;:42;;;;26689:11;;26928:1368;26994:4;27123:21;;;:14;;;:21;;;;;;27159:13;;27155:1135;;27526:18;27547:12;27558:1;27547:8;:12;:::i;:::-;27593:18;;27526:33;;-1:-1:-1;27573:17:0;;27593:22;;27614:1;;27593:22;:::i;:::-;27573:42;;27648:9;27634:10;:23;27630:378;;27677:17;27697:3;:11;;27709:9;27697:22;;;;;;;;:::i;:::-;;;;;;;;;27677:42;;27844:9;27818:3;:11;;27830:10;27818:23;;;;;;;;:::i;:::-;;;;;;;;;;;;:35;;;;27957:25;;;:14;;;:25;;;;;:36;;;27630:378;28086:17;;:3;;:17;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;28189:3;:14;;:21;28204:5;28189:21;;;;;;;;;;;28182:28;;;28232:4;28225:11;;;;;;;27155:1135;28274:5;28267:12;;;;;18690:151;18765:12;18796:38;18818:6;18826:4;18832:1;18765:12;19406;19420:23;19447:6;:11;;19466:5;19473:4;19447:31;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;19405:73;;;;19495:55;19522:6;19530:7;19539:10;19495:26;:55::i;:::-;19488:62;19165:392;-1:-1:-1;;;;;;19165:392:0:o;20610:582::-;20754:12;20783:7;20778:408;;20806:19;20814:10;20806:7;:19::i;:::-;20778:408;;;21030:17;;:22;:49;;;;-1:-1:-1;21056:18:0;;;;:23;21030:49;21026:119;;;21106:24;;;;;8086:42:1;8074:55;;21106:24:0;;;8056:74:1;8029:18;;21106:24:0;7910:226:1;21026:119:0;-1:-1:-1;21165:10:0;21158:17;;21728:516;21859:17;;:21;21855:383;;22087:10;22081:17;22143:15;22130:10;22126:2;22122:19;22115:44;21855:383;22210:17;;;;;;;;;;;;;;14:332:1;72:6;125:2;113:9;104:7;100:23;96:32;93:52;;;141:1;138;131:12;93:52;180:9;167:23;230:66;223:5;219:78;212:5;209:89;199:117;;312:1;309;302:12;821:154;907:42;900:5;896:54;889:5;886:65;876:93;;965:1;962;955:12;980:134;1048:20;;1077:31;1048:20;1077:31;:::i;:::-;980:134;;;:::o;1119:388::-;1187:6;1195;1248:2;1236:9;1227:7;1223:23;1219:32;1216:52;;;1264:1;1261;1254:12;1216:52;1303:9;1290:23;1322:31;1347:5;1322:31;:::i;:::-;1372:5;-1:-1:-1;1429:2:1;1414:18;;1401:32;1442:33;1401:32;1442:33;:::i;:::-;1494:7;1484:17;;;1119:388;;;;;:::o;1694:180::-;1753:6;1806:2;1794:9;1785:7;1781:23;1777:32;1774:52;;;1822:1;1819;1812:12;1774:52;-1:-1:-1;1845:23:1;;1694:180;-1:-1:-1;1694:180:1:o;1879:315::-;1947:6;1955;2008:2;1996:9;1987:7;1983:23;1979:32;1976:52;;;2024:1;2021;2014:12;1976:52;2060:9;2047:23;2037:33;;2120:2;2109:9;2105:18;2092:32;2133:31;2158:5;2133:31;:::i;2199:184::-;2251:77;2248:1;2241:88;2348:4;2345:1;2338:15;2372:4;2369:1;2362:15;2388:255;2460:2;2454:9;2502:6;2490:19;;2539:18;2524:34;;2560:22;;;2521:62;2518:88;;;2586:18;;:::i;:::-;2622:2;2615:22;2388:255;:::o;2648:247::-;2715:2;2709:9;2757:3;2745:16;;2791:18;2776:34;;2812:22;;;2773:62;2770:88;;;2838:18;;:::i;2900:777::-;2942:5;2995:3;2988:4;2980:6;2976:17;2972:27;2962:55;;3013:1;3010;3003:12;2962:55;3049:6;3036:20;3075:18;3112:2;3108;3105:10;3102:36;;;3118:18;;:::i;:::-;3252:2;3246:9;3314:4;3306:13;;3157:66;3302:22;;;3326:2;3298:31;3294:40;3282:53;;;3350:18;;;3370:22;;;3347:46;3344:72;;;3396:18;;:::i;:::-;3436:10;3432:2;3425:22;3471:2;3463:6;3456:18;3517:3;3510:4;3505:2;3497:6;3493:15;3489:26;3486:35;3483:55;;;3534:1;3531;3524:12;3483:55;3598:2;3591:4;3583:6;3579:17;3572:4;3564:6;3560:17;3547:54;3645:1;3638:4;3633:2;3625:6;3621:15;3617:26;3610:37;3665:6;3656:15;;;;;;2900:777;;;;:::o;3682:455::-;3759:6;3767;3820:2;3808:9;3799:7;3795:23;3791:32;3788:52;;;3836:1;3833;3826:12;3788:52;3876:9;3863:23;3909:18;3901:6;3898:30;3895:50;;;3941:1;3938;3931:12;3895:50;3964:49;4005:7;3996:6;3985:9;3981:22;3964:49;:::i;:::-;3954:59;;;4063:2;4052:9;4048:18;4035:32;4076:31;4101:5;4076:31;:::i;4142:121::-;4227:10;4220:5;4216:22;4209:5;4206:33;4196:61;;4253:1;4250;4243:12;4268:132;4335:20;;4364:30;4335:20;4364:30;:::i;4405:118::-;4491:5;4484:13;4477:21;4470:5;4467:32;4457:60;;4513:1;4510;4503:12;4528:128;4593:20;;4622:28;4593:20;4622:28;:::i;4661:806::-;4720:5;4768:6;4756:9;4751:3;4747:19;4743:32;4740:52;;;4788:1;4785;4778:12;4740:52;4810:22;;:::i;:::-;4801:31;;4855:28;4873:9;4855:28;:::i;:::-;4848:5;4841:43;4916:38;4950:2;4939:9;4935:18;4916:38;:::i;:::-;4911:2;4904:5;4900:14;4893:62;4987:38;5021:2;5010:9;5006:18;4987:38;:::i;:::-;4982:2;4975:5;4971:14;4964:62;5058:38;5092:2;5081:9;5077:18;5058:38;:::i;:::-;5053:2;5046:5;5042:14;5035:62;5130:39;5164:3;5153:9;5149:19;5130:39;:::i;:::-;5124:3;5117:5;5113:15;5106:64;5231:3;5220:9;5216:19;5203:33;5197:3;5190:5;5186:15;5179:58;5298:3;5287:9;5283:19;5270:33;5264:3;5257:5;5253:15;5246:58;5337:36;5368:3;5357:9;5353:19;5337:36;:::i;:::-;5331:3;5324:5;5320:15;5313:61;5393:3;5456:2;5445:9;5441:18;5428:32;5423:2;5416:5;5412:14;5405:56;;4661:806;;;;:::o;5472:237::-;5560:6;5613:3;5601:9;5592:7;5588:23;5584:33;5581:53;;;5630:1;5627;5620:12;5581:53;5653:50;5695:7;5684:9;5653:50;:::i;5714:320::-;5782:6;5835:2;5823:9;5814:7;5810:23;5806:32;5803:52;;;5851:1;5848;5841:12;5803:52;5891:9;5878:23;5924:18;5916:6;5913:30;5910:50;;;5956:1;5953;5946:12;5910:50;5979:49;6020:7;6011:6;6000:9;5996:22;5979:49;:::i;:::-;5969:59;5714:320;-1:-1:-1;;;;5714:320:1:o;6039:273::-;6115:6;6168:2;6156:9;6147:7;6143:23;6139:32;6136:52;;;6184:1;6181;6174:12;6136:52;6223:9;6210:23;6262:1;6255:5;6252:12;6242:40;;6278:1;6275;6268:12;6317:250;6402:1;6412:113;6426:6;6423:1;6420:13;6412:113;;;6502:11;;;6496:18;6483:11;;;6476:39;6448:2;6441:10;6412:113;;;-1:-1:-1;;6559:1:1;6541:16;;6534:27;6317:250::o;6572:330::-;6614:3;6652:5;6646:12;6679:6;6674:3;6667:19;6695:76;6764:6;6757:4;6752:3;6748:14;6741:4;6734:5;6730:16;6695:76;:::i;:::-;6816:2;6804:15;6821:66;6800:88;6791:98;;;;6891:4;6787:109;;6572:330;-1:-1:-1;;6572:330:1:o;6907:220::-;7056:2;7045:9;7038:21;7019:4;7076:45;7117:2;7106:9;7102:18;7094:6;7076:45;:::i;7132:388::-;7209:6;7217;7270:2;7258:9;7249:7;7245:23;7241:32;7238:52;;;7286:1;7283;7276:12;7238:52;7326:9;7313:23;7359:18;7351:6;7348:30;7345:50;;;7391:1;7388;7381:12;7345:50;7414:49;7455:7;7446:6;7435:9;7431:22;7414:49;:::i;:::-;7404:59;7510:2;7495:18;;;;7482:32;;-1:-1:-1;;;;7132:388:1:o;7525:248::-;7593:6;7601;7654:2;7642:9;7633:7;7629:23;7625:32;7622:52;;;7670:1;7667;7660:12;7622:52;-1:-1:-1;;7693:23:1;;;7763:2;7748:18;;;7735:32;;-1:-1:-1;7525:248:1:o;8240:1373::-;8471:13;;8217:10;8206:22;8194:35;;8440:3;8425:19;;8543:4;8535:6;8531:17;8525:24;8558:53;8605:4;8594:9;8590:20;8576:12;8217:10;8206:22;8194:35;;8141:94;8558:53;;8660:4;8652:6;8648:17;8642:24;8675:56;8725:4;8714:9;8710:20;8694:14;7855:42;7844:54;7832:67;;7778:127;8675:56;;8780:4;8772:6;8768:17;8762:24;8795:56;8845:4;8834:9;8830:20;8814:14;7855:42;7844:54;7832:67;;7778:127;8795:56;;8900:4;8892:6;8888:17;8882:24;8915:56;8965:4;8954:9;8950:20;8934:14;7855:42;7844:54;7832:67;;7778:127;8915:56;;9020:4;9012:6;9008:17;9002:24;9035:56;9085:4;9074:9;9070:20;9054:14;7855:42;7844:54;7832:67;;7778:127;9035:56;;9147:4;9139:6;9135:17;9129:24;9122:4;9111:9;9107:20;9100:54;9210:4;9202:6;9198:17;9192:24;9185:4;9174:9;9170:20;9163:54;9236:6;9296:2;9288:6;9284:15;9278:22;9273:2;9262:9;9258:18;9251:50;;9320:6;9375:2;9367:6;9363:15;9357:22;9388:51;9435:2;9424:9;9420:18;9404:14;421:13;414:21;402:34;;351:91;9388:51;-1:-1:-1;;9458:6:1;9506:15;;;9500:22;9480:18;;;9473:50;9542:6;9590:15;;;9584:22;9564:18;;;;9557:50;;;;8240:1373;:::o;9618:440::-;9724:6;9732;9740;9793:3;9781:9;9772:7;9768:23;9764:33;9761:53;;;9810:1;9807;9800:12;9761:53;9846:9;9833:23;9823:33;;9906:2;9895:9;9891:18;9878:32;9919:31;9944:5;9919:31;:::i;:::-;9969:5;-1:-1:-1;9993:59:1;10044:7;10039:2;10024:18;;9993:59;:::i;:::-;9983:69;;9618:440;;;;;:::o;10063:523::-;10149:6;10157;10165;10218:2;10206:9;10197:7;10193:23;10189:32;10186:52;;;10234:1;10231;10224:12;10186:52;10270:9;10257:23;10247:33;;10330:2;10319:9;10315:18;10302:32;10343:31;10368:5;10343:31;:::i;:::-;10393:5;-1:-1:-1;10449:2:1;10434:18;;10421:32;10476:18;10465:30;;10462:50;;;10508:1;10505;10498:12;10462:50;10531:49;10572:7;10563:6;10552:9;10548:22;10531:49;:::i;:::-;10521:59;;;10063:523;;;;;:::o;10776:1087::-;10906:6;10914;10922;10930;10938;10946;10954;10962;10970;11023:3;11011:9;11002:7;10998:23;10994:33;10991:53;;;11040:1;11037;11030:12;10991:53;11076:9;11063:23;11053:33;;11136:2;11125:9;11121:18;11108:32;11149:31;11174:5;11149:31;:::i;:::-;11199:5;-1:-1:-1;11256:2:1;11241:18;;11228:32;11269:33;11228:32;11269:33;:::i;:::-;11321:7;-1:-1:-1;11380:2:1;11365:18;;11352:32;11393;11352;11393;:::i;:::-;11444:7;-1:-1:-1;11503:3:1;11488:19;;11475:33;11517;11475;11517;:::i;:::-;11569:7;-1:-1:-1;11628:3:1;11613:19;;11600:33;11642;11600;11642;:::i;:::-;11694:7;11684:17;;;11748:3;11737:9;11733:19;11720:33;11710:43;;11800:3;11789:9;11785:19;11772:33;11762:43;;11852:3;11841:9;11837:19;11824:33;11814:43;;10776:1087;;;;;;;;;;;:::o;11868:247::-;11927:6;11980:2;11968:9;11959:7;11955:23;11951:32;11948:52;;;11996:1;11993;11986:12;11948:52;12035:9;12022:23;12054:31;12079:5;12054:31;:::i;12867:184::-;12919:77;12916:1;12909:88;13016:4;13013:1;13006:15;13040:4;13037:1;13030:15;13056:136;13134:13;;13156:30;13134:13;13156:30;:::i;13197:138::-;13276:13;;13298:31;13276:13;13298:31;:::i;13340:132::-;13416:13;;13438:28;13416:13;13438:28;:::i;13477:1183::-;13580:6;13633:3;13621:9;13612:7;13608:23;13604:33;13601:53;;;13650:1;13647;13640:12;13601:53;13676:17;;:::i;:::-;13716:39;13745:9;13716:39;:::i;:::-;13709:5;13702:54;13788:48;13832:2;13821:9;13817:18;13788:48;:::i;:::-;13783:2;13776:5;13772:14;13765:72;13869:49;13914:2;13903:9;13899:18;13869:49;:::i;:::-;13864:2;13857:5;13853:14;13846:73;13951:49;13996:2;13985:9;13981:18;13951:49;:::i;:::-;13946:2;13939:5;13935:14;13928:73;14034:50;14079:3;14068:9;14064:19;14034:50;:::i;:::-;14028:3;14021:5;14017:15;14010:75;14118:50;14163:3;14152:9;14148:19;14118:50;:::i;:::-;14112:3;14105:5;14101:15;14094:75;14223:3;14212:9;14208:19;14202:26;14196:3;14189:5;14185:15;14178:51;14283:3;14272:9;14268:19;14262:26;14256:3;14249:5;14245:15;14238:51;14308:3;14364:2;14353:9;14349:18;14343:25;14338:2;14331:5;14327:14;14320:49;;14388:3;14423:46;14465:2;14454:9;14450:18;14423:46;:::i;:::-;14407:14;;;14400:70;14489:3;14530:18;;;14524:25;14508:14;;;14501:49;14569:3;14610:18;;;14604:25;14588:14;;;14581:49;;;;-1:-1:-1;14411:5:1;13477:1183;-1:-1:-1;13477:1183:1:o;14665:184::-;14717:77;14714:1;14707:88;14814:4;14811:1;14804:15;14838:4;14835:1;14828:15;14854:168;14927:9;;;14958;;14975:15;;;14969:22;;14955:37;14945:71;;14996:18;;:::i;15027:274::-;15067:1;15093;15083:189;;15128:77;15125:1;15118:88;15229:4;15226:1;15219:15;15257:4;15254:1;15247:15;15083:189;-1:-1:-1;15286:9:1;;15027:274::o;15306:128::-;15373:9;;;15394:11;;;15391:37;;;15408:18;;:::i;15439:195::-;15478:3;15509:66;15502:5;15499:77;15496:103;;15579:18;;:::i;:::-;-1:-1:-1;15626:1:1;15615:13;;15439:195::o;15639:753::-;15946:3;15935:9;15928:22;15909:4;15967:46;16008:3;15997:9;15993:19;15985:6;15967:46;:::i;:::-;16061:10;16049:23;;;;16044:2;16029:18;;16022:51;-1:-1:-1;16092:42:1;16170:15;;;16165:2;16150:18;;16143:43;16222:15;;;;16217:2;16202:18;;16195:43;16269:3;16254:19;;16247:35;;;;16313:3;16298:19;;16291:35;16370:14;;16363:22;16357:3;16342:19;;;16335:51;15959:54;15639:753;-1:-1:-1;15639:753:1:o;18791:184::-;18843:77;18840:1;18833:88;18940:4;18937:1;18930:15;18964:4;18961:1;18954:15;18980:245;19047:6;19100:2;19088:9;19079:7;19075:23;19071:32;19068:52;;;19116:1;19113;19106:12;19068:52;19148:9;19142:16;19167:28;19189:5;19167:28;:::i;19230:184::-;19282:77;19279:1;19272:88;19379:4;19376:1;19369:15;19403:4;19400:1;19393:15;19419:287;19548:3;19586:6;19580:13;19602:66;19661:6;19656:3;19649:4;19641:6;19637:17;19602:66;:::i;:::-;19684:16;;;;;19419:287;-1:-1:-1;;19419:287:1:o","abiDefinition":[{"inputs":[{"internalType":"address","name":"_owner","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AccessControlBadConfirmation","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"bytes32","name":"neededRole","type":"bytes32"}],"name":"AccessControlUnauthorizedAccount","type":"error"},{"inputs":[{"internalType":"address","name":"target","type":"address"}],"name":"AddressEmptyCode","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"AddressInsufficientBalance","type":"error"},{"inputs":[],"name":"FailedInnerCall","type":"error"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"SafeERC20FailedOperation","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"relayer","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"BridgeDepositClaimed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"BridgeDepositRefunded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"relayer","type":"address"}],"name":"BridgeProofDisputed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"relayer","type":"address"},{"indexed":false,"internalType":"bytes32","name":"transactionHash","type":"bytes32"}],"name":"BridgeProofProvided","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"relayer","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint32","name":"originChainId","type":"uint32"},{"indexed":false,"internalType":"address","name":"originToken","type":"address"},{"indexed":false,"internalType":"address","name":"destToken","type":"address"},{"indexed":false,"internalType":"uint256","name":"originAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"destAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"chainGasAmount","type":"uint256"}],"name":"BridgeRelayed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"bytes","name":"request","type":"bytes"},{"indexed":false,"internalType":"uint32","name":"destChainId","type":"uint32"},{"indexed":false,"internalType":"address","name":"originToken","type":"address"},{"indexed":false,"internalType":"address","name":"destToken","type":"address"},{"indexed":false,"internalType":"uint256","name":"originAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"destAmount","type":"uint256"},{"indexed":false,"internalType":"bool","name":"sendChainGas","type":"bool"}],"name":"BridgeRequested","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldChainGasAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newChainGasAmount","type":"uint256"}],"name":"ChainGasAmountUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldFeeRate","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newFeeRate","type":"uint256"}],"name":"FeeRateUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"address","name":"recipient","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"FeesSwept","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"previousAdminRole","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"newAdminRole","type":"bytes32"}],"name":"RoleAdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleRevoked","type":"event"},{"inputs":[],"name":"DEFAULT_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"FEE_BPS","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"FEE_RATE_MAX","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"GOVERNOR_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"GUARD_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"REFUNDER_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"RELAYER_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"uint32","name":"dstChainId","type":"uint32"},{"internalType":"address","name":"sender","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"address","name":"originToken","type":"address"},{"internalType":"address","name":"destToken","type":"address"},{"internalType":"uint256","name":"originAmount","type":"uint256"},{"internalType":"uint256","name":"destAmount","type":"uint256"},{"internalType":"bool","name":"sendChainGas","type":"bool"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"internalType":"struct IFastBridge.BridgeParams","name":"","type":"tuple"}],"name":"bridge","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"},{"internalType":"address","name":"","type":"address"}],"name":"canClaim","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"chainGasAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"","type":"bytes"},{"internalType":"address","name":"","type":"address"}],"name":"claim","outputs":[],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"deployBlock","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"dispute","outputs":[],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"}],"name":"getBridgeTransaction","outputs":[{"components":[{"internalType":"uint32","name":"originChainId","type":"uint32"},{"internalType":"uint32","name":"destChainId","type":"uint32"},{"internalType":"address","name":"originSender","type":"address"},{"internalType":"address","name":"destRecipient","type":"address"},{"internalType":"address","name":"originToken","type":"address"},{"internalType":"address","name":"destToken","type":"address"},{"internalType":"uint256","name":"originAmount","type":"uint256"},{"internalType":"uint256","name":"destAmount","type":"uint256"},{"internalType":"uint256","name":"originFeeAmount","type":"uint256"},{"internalType":"bool","name":"sendChainGas","type":"bool"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint256","name":"nonce","type":"uint256"}],"internalType":"struct IFastBridge.BridgeTransaction","name":"","type":"tuple"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"enum FastBridge.BridgeStatus","name":"keyValue","type":"uint8"}],"name":"getEnumKeyByValue","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleAdmin","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"uint256","name":"index","type":"uint256"}],"name":"getRoleMember","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleMemberCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"grantRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"hasRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"internalType":"address","name":"relayer","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint32","name":"originChainId","type":"uint32"},{"internalType":"address","name":"originToken","type":"address"},{"internalType":"address","name":"destToken","type":"address"},{"internalType":"uint256","name":"originAmount","type":"uint256"},{"internalType":"uint256","name":"destAmount","type":"uint256"},{"internalType":"uint256","name":"chainGasAmount","type":"uint256"}],"name":"mockBridgeRelayer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"internalType":"address","name":"sender","type":"address"},{"components":[{"internalType":"uint32","name":"dstChainId","type":"uint32"},{"internalType":"address","name":"sender","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"address","name":"originToken","type":"address"},{"internalType":"address","name":"destToken","type":"address"},{"internalType":"uint256","name":"originAmount","type":"uint256"},{"internalType":"uint256","name":"destAmount","type":"uint256"},{"internalType":"bool","name":"sendChainGas","type":"bool"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"internalType":"struct IFastBridge.BridgeParams","name":"params","type":"tuple"}],"name":"mockBridgeRequest","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"internalType":"address","name":"sender","type":"address"},{"internalType":"bytes","name":"request","type":"bytes"}],"name":"mockBridgeRequestRaw","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"nonce","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"protocolFeeRate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"protocolFees","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"","type":"bytes"},{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"prove","outputs":[],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"bytes","name":"","type":"bytes"}],"name":"refund","outputs":[],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"bytes","name":"","type":"bytes"}],"name":"relay","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"callerConfirmation","type":"address"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"revokeRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"newChainGasAmount","type":"uint256"}],"name":"setChainGasAmount","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"newFeeRate","type":"uint256"}],"name":"setProtocolFeeRate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"address","name":"recipient","type":"address"}],"name":"sweepProtocolFees","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"testFastBridgeMock","outputs":[],"stateMutability":"nonpayable","type":"function"}],"userDoc":{"kind":"user","methods":{"chainGasAmount()":{"notice":"Chain gas amount to forward as rebate if requested"},"getBridgeTransaction(bytes)":{"notice":"Decodes bridge request into a bridge transaction"},"protocolFeeRate()":{"notice":"Protocol fee rate taken on origin amount deposited in origin chain"},"protocolFees(address)":{"notice":"Protocol fee amounts accumulated"},"testFastBridgeMock()":{"notice":"We include an empty \"test\" function so that this contract does not appear in the coverage report."}},"version":1},"developerDoc":{"errors":{"AccessControlBadConfirmation()":[{"details":"The caller of a function is not the expected one. NOTE: Don't confuse with {AccessControlUnauthorizedAccount}."}],"AccessControlUnauthorizedAccount(address,bytes32)":[{"details":"The `account` is missing a role."}],"AddressEmptyCode(address)":[{"details":"There's no code at `target` (it is not a contract)."}],"AddressInsufficientBalance(address)":[{"details":"The ETH balance of the account is not enough to perform the operation."}],"FailedInnerCall()":[{"details":"A call to an address target failed. The target may have reverted."}],"SafeERC20FailedOperation(address)":[{"details":"An operation with an ERC20 token failed."}]},"events":{"RoleAdminChanged(bytes32,bytes32,bytes32)":{"details":"Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole` `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite {RoleAdminChanged} not being emitted signaling this."},"RoleGranted(bytes32,address,address)":{"details":"Emitted when `account` is granted `role`. `sender` is the account that originated the contract call, an admin role bearer except when using {AccessControl-_setupRole}."},"RoleRevoked(bytes32,address,address)":{"details":"Emitted when `account` is revoked `role`. `sender` is the account that originated the contract call: - if using `revokeRole`, it is the admin role bearer - if using `renounceRole`, it is the role bearer (i.e. `account`)"}},"kind":"dev","methods":{"getBridgeTransaction(bytes)":{"params":{"request":"The bridge request to decode"}},"getRoleAdmin(bytes32)":{"details":"Returns the admin role that controls `role`. See {grantRole} and {revokeRole}. To change a role's admin, use {_setRoleAdmin}."},"getRoleMember(bytes32,uint256)":{"details":"Returns one of the accounts that have `role`. `index` must be a value between 0 and {getRoleMemberCount}, non-inclusive. Role bearers are not sorted in any particular way, and their ordering may change at any point. WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure you perform all queries on the same block. See the following https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post] for more information."},"getRoleMemberCount(bytes32)":{"details":"Returns the number of accounts that have `role`. Can be used together with {getRoleMember} to enumerate all bearers of a role."},"grantRole(bytes32,address)":{"details":"Grants `role` to `account`. If `account` had not been already granted `role`, emits a {RoleGranted} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleGranted} event."},"hasRole(bytes32,address)":{"details":"Returns `true` if `account` has been granted `role`."},"renounceRole(bytes32,address)":{"details":"Revokes `role` from the calling account. Roles are often managed via {grantRole} and {revokeRole}: this function's purpose is to provide a mechanism for accounts to lose their privileges if they are compromised (such as when a trusted device is misplaced). If the calling account had been revoked `role`, emits a {RoleRevoked} event. Requirements: - the caller must be `callerConfirmation`. May emit a {RoleRevoked} event."},"revokeRole(bytes32,address)":{"details":"Revokes `role` from `account`. If `account` had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleRevoked} event."},"supportsInterface(bytes4)":{"details":"See {IERC165-supportsInterface}."}},"stateVariables":{"nonce":{"details":"to prevent replays"}},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.20+commit.a1b79de6\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_owner\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"AccessControlBadConfirmation\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"neededRole\",\"type\":\"bytes32\"}],\"name\":\"AccessControlUnauthorizedAccount\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"}],\"name\":\"AddressEmptyCode\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"AddressInsufficientBalance\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"FailedInnerCall\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"}],\"name\":\"SafeERC20FailedOperation\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"BridgeDepositClaimed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"BridgeDepositRefunded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"name\":\"BridgeProofDisputed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"transactionHash\",\"type\":\"bytes32\"}],\"name\":\"BridgeProofProvided\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"originChainId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"chainGasAmount\",\"type\":\"uint256\"}],\"name\":\"BridgeRelayed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"destChainId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"sendChainGas\",\"type\":\"bool\"}],\"name\":\"BridgeRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"oldChainGasAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newChainGasAmount\",\"type\":\"uint256\"}],\"name\":\"ChainGasAmountUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"oldFeeRate\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newFeeRate\",\"type\":\"uint256\"}],\"name\":\"FeeRateUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"FeesSwept\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"previousAdminRole\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"newAdminRole\",\"type\":\"bytes32\"}],\"name\":\"RoleAdminChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleGranted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleRevoked\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"DEFAULT_ADMIN_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"FEE_BPS\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"FEE_RATE_MAX\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"GOVERNOR_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"GUARD_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"REFUNDER_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"RELAYER_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"dstChainId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"sendChainGas\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"}],\"internalType\":\"struct IFastBridge.BridgeParams\",\"name\":\"\",\"type\":\"tuple\"}],\"name\":\"bridge\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"canClaim\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"chainGasAmount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"claim\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"deployBlock\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"dispute\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"getBridgeTransaction\",\"outputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"originChainId\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"destChainId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"originSender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destRecipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"originFeeAmount\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"sendChainGas\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"}],\"internalType\":\"struct IFastBridge.BridgeTransaction\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"enum FastBridge.BridgeStatus\",\"name\":\"keyValue\",\"type\":\"uint8\"}],\"name\":\"getEnumKeyByValue\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"}],\"name\":\"getRoleAdmin\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"index\",\"type\":\"uint256\"}],\"name\":\"getRoleMember\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"}],\"name\":\"getRoleMemberCount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"grantRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"hasRole\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"uint32\",\"name\":\"originChainId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"chainGasAmount\",\"type\":\"uint256\"}],\"name\":\"mockBridgeRelayer\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"components\":[{\"internalType\":\"uint32\",\"name\":\"dstChainId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"sendChainGas\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"}],\"internalType\":\"struct IFastBridge.BridgeParams\",\"name\":\"params\",\"type\":\"tuple\"}],\"name\":\"mockBridgeRequest\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"mockBridgeRequestRaw\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"nonce\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"protocolFeeRate\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"protocolFees\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"},{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"prove\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"name\":\"refund\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"name\":\"relay\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"callerConfirmation\",\"type\":\"address\"}],\"name\":\"renounceRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"revokeRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"newChainGasAmount\",\"type\":\"uint256\"}],\"name\":\"setChainGasAmount\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"newFeeRate\",\"type\":\"uint256\"}],\"name\":\"setProtocolFeeRate\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes4\",\"name\":\"interfaceId\",\"type\":\"bytes4\"}],\"name\":\"supportsInterface\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"}],\"name\":\"sweepProtocolFees\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"testFastBridgeMock\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"errors\":{\"AccessControlBadConfirmation()\":[{\"details\":\"The caller of a function is not the expected one. NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\"}],\"AccessControlUnauthorizedAccount(address,bytes32)\":[{\"details\":\"The `account` is missing a role.\"}],\"AddressEmptyCode(address)\":[{\"details\":\"There's no code at `target` (it is not a contract).\"}],\"AddressInsufficientBalance(address)\":[{\"details\":\"The ETH balance of the account is not enough to perform the operation.\"}],\"FailedInnerCall()\":[{\"details\":\"A call to an address target failed. The target may have reverted.\"}],\"SafeERC20FailedOperation(address)\":[{\"details\":\"An operation with an ERC20 token failed.\"}]},\"events\":{\"RoleAdminChanged(bytes32,bytes32,bytes32)\":{\"details\":\"Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole` `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite {RoleAdminChanged} not being emitted signaling this.\"},\"RoleGranted(bytes32,address,address)\":{\"details\":\"Emitted when `account` is granted `role`. `sender` is the account that originated the contract call, an admin role bearer except when using {AccessControl-_setupRole}.\"},\"RoleRevoked(bytes32,address,address)\":{\"details\":\"Emitted when `account` is revoked `role`. `sender` is the account that originated the contract call: - if using `revokeRole`, it is the admin role bearer - if using `renounceRole`, it is the role bearer (i.e. `account`)\"}},\"kind\":\"dev\",\"methods\":{\"getBridgeTransaction(bytes)\":{\"params\":{\"request\":\"The bridge request to decode\"}},\"getRoleAdmin(bytes32)\":{\"details\":\"Returns the admin role that controls `role`. See {grantRole} and {revokeRole}. To change a role's admin, use {_setRoleAdmin}.\"},\"getRoleMember(bytes32,uint256)\":{\"details\":\"Returns one of the accounts that have `role`. `index` must be a value between 0 and {getRoleMemberCount}, non-inclusive. Role bearers are not sorted in any particular way, and their ordering may change at any point. WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure you perform all queries on the same block. See the following https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post] for more information.\"},\"getRoleMemberCount(bytes32)\":{\"details\":\"Returns the number of accounts that have `role`. Can be used together with {getRoleMember} to enumerate all bearers of a role.\"},\"grantRole(bytes32,address)\":{\"details\":\"Grants `role` to `account`. If `account` had not been already granted `role`, emits a {RoleGranted} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleGranted} event.\"},\"hasRole(bytes32,address)\":{\"details\":\"Returns `true` if `account` has been granted `role`.\"},\"renounceRole(bytes32,address)\":{\"details\":\"Revokes `role` from the calling account. Roles are often managed via {grantRole} and {revokeRole}: this function's purpose is to provide a mechanism for accounts to lose their privileges if they are compromised (such as when a trusted device is misplaced). If the calling account had been revoked `role`, emits a {RoleRevoked} event. Requirements: - the caller must be `callerConfirmation`. May emit a {RoleRevoked} event.\"},\"revokeRole(bytes32,address)\":{\"details\":\"Revokes `role` from `account`. If `account` had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleRevoked} event.\"},\"supportsInterface(bytes4)\":{\"details\":\"See {IERC165-supportsInterface}.\"}},\"stateVariables\":{\"nonce\":{\"details\":\"to prevent replays\"}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"chainGasAmount()\":{\"notice\":\"Chain gas amount to forward as rebate if requested\"},\"getBridgeTransaction(bytes)\":{\"notice\":\"Decodes bridge request into a bridge transaction\"},\"protocolFeeRate()\":{\"notice\":\"Protocol fee rate taken on origin amount deposited in origin chain\"},\"protocolFees(address)\":{\"notice\":\"Protocol fee amounts accumulated\"},\"testFastBridgeMock()\":{\"notice\":\"We include an empty \\\"test\\\" function so that this contract does not appear in the coverage report.\"}},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeMock.sol\":\"FastBridgeMock\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeMock.sol\":{\"keccak256\":\"0xf2751f52f8216801d500da7464ad01f3c23a8286e155e2dcba6d21d6e7fd95a0\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://85d2edab24ebe321043d2b88038437e8f443a0ef26fa2139c72dcc2bc7fbc602\",\"dweb:/ipfs/QmcULiFPFJzFDT4aupVSDreXz8uHxcABb5nxpAG4zYzfNN\"]}},\"version\":1}"},"hashes":{"DEFAULT_ADMIN_ROLE()":"a217fddf","FEE_BPS()":"bf333f2c","FEE_RATE_MAX()":"0f5f6ed7","GOVERNOR_ROLE()":"ccc57490","GUARD_ROLE()":"03ed0ee5","REFUNDER_ROLE()":"5960ccf2","RELAYER_ROLE()":"926d7d7f","bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256))":"45851694","canClaim(bytes32,address)":"aa9641ab","chainGasAmount()":"e00a83e0","claim(bytes,address)":"41fcb612","deployBlock()":"a3ec191a","dispute(bytes32)":"add98c70","getBridgeTransaction(bytes)":"ac11fb1a","getEnumKeyByValue(uint8)":"85ad903d","getRoleAdmin(bytes32)":"248a9ca3","getRoleMember(bytes32,uint256)":"9010d07c","getRoleMemberCount(bytes32)":"ca15c873","grantRole(bytes32,address)":"2f2ff15d","hasRole(bytes32,address)":"91d14854","mockBridgeRelayer(bytes32,address,address,uint32,address,address,uint256,uint256,uint256)":"c72870cc","mockBridgeRequest(bytes32,address,(uint32,address,address,address,address,uint256,uint256,bool,uint256))":"acaebbf1","mockBridgeRequestRaw(bytes32,address,bytes)":"aedf009d","nonce()":"affed0e0","protocolFeeRate()":"58f85880","protocolFees(address)":"dcf844a7","prove(bytes,bytes32)":"886d36ff","refund(bytes)":"5eb7d946","relay(bytes)":"8f0d6f17","renounceRole(bytes32,address)":"36568abe","revokeRole(bytes32,address)":"d547741f","setChainGasAmount(uint256)":"b250fe6b","setProtocolFeeRate(uint256)":"b13aa2d6","supportsInterface(bytes4)":"01ffc9a7","sweepProtocolFees(address,address)":"06f333f2","testFastBridgeMock()":"4774fa38"}},"solidity/FastBridgeMock.sol:IAccessControl":{"code":"0x","runtime-code":"0x","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.20 ^0.8.20 ^0.8.4;\n\n// contracts/interfaces/IAdmin.sol\n\ninterface IAdmin {\n // ============ Events ============\n\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n event ChainGasAmountUpdated(uint256 oldChainGasAmount, uint256 newChainGasAmount);\n\n // ============ Methods ============\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n\n function setChainGasAmount(uint256 newChainGasAmount) external;\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IMulticallTarget.sol\n\n/// @notice Interface for a contract that can be called multiple times by the same caller. Inspired by MulticallV3:\n/// https://github.com/mds1/multicall/blob/master/src/Multicall3.sol\ninterface IMulticallTarget {\n struct Result {\n bool success;\n bytes returnData;\n }\n\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external;\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results);\n}\n\n// contracts/libs/Errors.sol\n\nerror DeadlineExceeded();\nerror DeadlineNotExceeded();\nerror DeadlineTooShort();\nerror InsufficientOutputAmount();\n\nerror MsgValueIncorrect();\nerror PoolNotFound();\nerror TokenAddressMismatch();\nerror TokenNotContract();\nerror TokenNotETH();\nerror TokensIdentical();\n\nerror ChainIncorrect();\nerror AmountIncorrect();\nerror ZeroAddress();\n\nerror DisputePeriodNotPassed();\nerror DisputePeriodPassed();\nerror SenderIncorrect();\nerror StatusIncorrect();\nerror TransactionIdIncorrect();\nerror TransactionRelayed();\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// contracts/utils/MulticallTarget.sol\n\n// solhint-disable avoid-low-level-calls\n/// @notice Template for a contract that supports batched calls (preserving the msg.sender).\n/// Only calls with zero msg.value could be batched.\nabstract contract MulticallTarget is IMulticallTarget {\n error MulticallTarget__UndeterminedRevert();\n\n /// @notice Perform a batched call to this contract, preserving the msg.sender.\n /// The return data from each call is discarded.\n /// @dev The method is non-payable, so only calls with `msg.value == 0` could be batched.\n /// It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag.\n /// Otherwise, the whole batch call will be reverted with the original revert reason.\n /// @param data List of abi-encoded calldata for the calls to perform.\n /// @param ignoreReverts Whether to ignore the revert errors from the calls.\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external {\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\n if (!success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(result);\n }\n }\n }\n\n /// @notice Perform a batched call to this contract, preserving the msg.sender.\n /// The return data from each call is preserved.\n /// @dev The method is non-payable, so only calls with `msg.value == 0` could be batched.\n /// It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag.\n /// Otherwise, the whole batch call will be reverted with the original revert reason.\n /// @param data List of abi-encoded calldata for the calls to perform.\n /// @param ignoreReverts Whether to ignore the revert errors from the calls.\n /// @return results List of results from the calls: `(success, returnData)`.\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results)\n {\n results = new Result[](data.length);\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (results[i].success, results[i].returnData) = address(this).delegatecall(data[i]);\n if (!results[i].success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(results[i].returnData);\n }\n }\n }\n\n /// @dev Bubbles the revert message from the underlying call.\n /// Note: preserves the same custom error or revert string, if one was used.\n /// Source: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v5.0.2/contracts/utils/Address.sol#L143-L158\n function _bubbleRevert(bytes memory returnData) internal pure {\n // Look for revert reason and bubble it up if present\n if (returnData.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n // solhint-disable-next-line no-inline-assembly\n assembly {\n let returndata_size := mload(returnData)\n revert(add(32, returnData), returndata_size)\n }\n } else {\n revert MulticallTarget__UndeterminedRevert();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// contracts/libs/UniversalToken.sol\n\nlibrary UniversalTokenLib {\n using SafeERC20 for IERC20;\n\n address internal constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Transfers tokens to the given account. Reverts if transfer is not successful.\n /// @dev This might trigger fallback, if ETH is transferred to the contract.\n /// Make sure this can not lead to reentrancy attacks.\n function universalTransfer(address token, address to, uint256 value) internal {\n // Don't do anything, if need to send tokens to this address\n if (to == address(this)) return;\n // Don't do anything, if trying to send zero value\n if (value == 0) return;\n if (token == ETH_ADDRESS) {\n /// @dev Note: this can potentially lead to executing code in `to`.\n // solhint-disable-next-line avoid-low-level-calls\n (bool success,) = to.call{value: value}(\"\");\n require(success, \"ETH transfer failed\");\n } else {\n IERC20(token).safeTransfer(to, value);\n }\n }\n\n /// @notice Issues an infinite allowance to the spender, if the current allowance is insufficient\n /// to spend the given amount.\n function universalApproveInfinity(address token, address spender, uint256 amountToSpend) internal {\n // ETH Chad doesn't require your approval\n if (token == ETH_ADDRESS) return;\n // No-op if allowance is already sufficient\n uint256 allowance = IERC20(token).allowance(address(this), spender);\n if (allowance \u003e= amountToSpend) return;\n // Otherwise, reset approval to 0 and set to max allowance\n if (allowance \u003e 0) IERC20(token).safeDecreaseAllowance(spender, allowance);\n IERC20(token).safeIncreaseAllowance(spender, type(uint256).max);\n }\n\n /// @notice Returns the balance of the given token (or native ETH) for the given account.\n function universalBalanceOf(address token, address account) internal view returns (uint256) {\n if (token == ETH_ADDRESS) {\n return account.balance;\n } else {\n return IERC20(token).balanceOf(account);\n }\n }\n\n /// @dev Checks that token is a contract and not ETH_ADDRESS.\n function assertIsContract(address token) internal view {\n // Check that ETH_ADDRESS was not used (in case this is a predeploy on any of the chains)\n if (token == UniversalTokenLib.ETH_ADDRESS) revert TokenNotContract();\n // Check that token is not an EOA\n if (token.code.length == 0) revert TokenNotContract();\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/Admin.sol\n\ncontract Admin is IAdmin, AccessControlEnumerable {\n using UniversalTokenLib for address;\n\n bytes32 public constant RELAYER_ROLE = keccak256(\"RELAYER_ROLE\");\n bytes32 public constant REFUNDER_ROLE = keccak256(\"REFUNDER_ROLE\");\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n uint256 public constant FEE_BPS = 1e6;\n uint256 public constant FEE_RATE_MAX = 0.01e6; // max 1% on origin amount\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Chain gas amount to forward as rebate if requested\n uint256 public chainGasAmount;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n }\n\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n require(newFeeRate \u003c= FEE_RATE_MAX, \"newFeeRate \u003e max\");\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n token.universalTransfer(recipient, feeAmount);\n emit FeesSwept(token, recipient, feeAmount);\n }\n\n function setChainGasAmount(uint256 newChainGasAmount) external onlyRole(GOVERNOR_ROLE) {\n uint256 oldChainGasAmount = chainGasAmount;\n chainGasAmount = newChainGasAmount;\n emit ChainGasAmountUpdated(oldChainGasAmount, newChainGasAmount);\n }\n}\n\n// contracts/FastBridge.sol\n\ncontract FastBridge is IFastBridge, MulticallTarget, Admin {\n using SafeERC20 for IERC20;\n using UniversalTokenLib for address;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Delay for a transaction after which it could be permisionlessly refunded\n uint256 public constant REFUND_DELAY = 7 days;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeStatus) public bridgeStatuses;\n /// @notice Proof of relayed bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeProof) public bridgeProofs;\n /// @notice Whether bridge has been relayed on destination chain\n mapping(bytes32 =\u003e bool) public bridgeRelays;\n\n /// @dev to prevent replays\n uint256 public nonce;\n // @dev the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @notice Pulls a requested token from the user to the requested recipient.\n /// @dev Be careful of re-entrancy issues when msg.value \u003e 0 and recipient != address(this)\n function _pullToken(address recipient, address token, uint256 amount) internal returns (uint256 amountPulled) {\n if (token != UniversalTokenLib.ETH_ADDRESS) {\n token.assertIsContract();\n // Record token balance before transfer\n amountPulled = IERC20(token).balanceOf(recipient);\n // Token needs to be pulled only if msg.value is zero\n // This way user can specify WETH as the origin asset\n IERC20(token).safeTransferFrom(msg.sender, recipient, amount);\n // Use the difference between the recorded balance and the current balance as the amountPulled\n amountPulled = IERC20(token).balanceOf(recipient) - amountPulled;\n } else {\n // Otherwise, we need to check that ETH amount matches msg.value\n if (amount != msg.value) revert MsgValueIncorrect();\n // Transfer value to recipient if not this address\n if (recipient != address(this)) token.universalTransfer(recipient, amount);\n // We will forward msg.value in the external call later, if recipient is not this contract\n amountPulled = msg.value;\n }\n }\n\n /// @inheritdoc IFastBridge\n function getBridgeTransaction(bytes memory request) public pure returns (BridgeTransaction memory) {\n return abi.decode(request, (BridgeTransaction));\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n // check bridge params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n\n // transfer tokens to bridge contract\n // @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _pullToken(address(this), params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n\n // set status to requested\n bytes memory request = abi.encode(\n BridgeTransaction({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n sendChainGas: params.sendChainGas,\n deadline: params.deadline,\n nonce: nonce++ // increment nonce on every bridge\n })\n );\n bytes32 transactionId = keccak256(request);\n bridgeStatuses[transactionId] = BridgeStatus.REQUESTED;\n\n emit BridgeRequested(\n transactionId,\n params.sender,\n request,\n params.dstChainId,\n params.originToken,\n params.destToken,\n originAmount,\n params.destAmount,\n params.sendChainGas\n );\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes memory request) external payable onlyRole(RELAYER_ROLE) {\n bytes32 transactionId = keccak256(request);\n BridgeTransaction memory transaction = getBridgeTransaction(request);\n if (transaction.destChainId != uint32(block.chainid)) revert ChainIncorrect();\n\n // check haven't exceeded deadline for relay to happen\n if (block.timestamp \u003e transaction.deadline) revert DeadlineExceeded();\n\n // mark bridge transaction as relayed\n if (bridgeRelays[transactionId]) revert TransactionRelayed();\n bridgeRelays[transactionId] = true;\n\n // transfer tokens to recipient on destination chain and gas rebate if requested\n address to = transaction.destRecipient;\n address token = transaction.destToken;\n uint256 amount = transaction.destAmount;\n\n uint256 rebate = chainGasAmount;\n if (!transaction.sendChainGas) {\n // forward erc20\n rebate = 0;\n _pullToken(to, token, amount);\n } else if (token == UniversalTokenLib.ETH_ADDRESS) {\n // lump in gas rebate into amount in native gas token\n _pullToken(to, token, amount + rebate);\n } else {\n // forward erc20 then forward gas rebate in native gas token\n _pullToken(to, token, amount);\n _pullToken(to, UniversalTokenLib.ETH_ADDRESS, rebate);\n }\n\n emit BridgeRelayed(\n transactionId,\n msg.sender,\n to,\n transaction.originChainId,\n transaction.originToken,\n transaction.destToken,\n transaction.originAmount,\n transaction.destAmount,\n rebate\n );\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes memory request, bytes32 destTxHash) external onlyRole(RELAYER_ROLE) {\n bytes32 transactionId = keccak256(request);\n // update bridge tx status given proof provided\n if (bridgeStatuses[transactionId] != BridgeStatus.REQUESTED) revert StatusIncorrect();\n bridgeStatuses[transactionId] = BridgeStatus.RELAYER_PROVED;\n bridgeProofs[transactionId] = BridgeProof({timestamp: uint96(block.timestamp), relayer: msg.sender}); // overflow ok\n\n emit BridgeProofProvided(transactionId, msg.sender, destTxHash);\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint96(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint96).max but\n /// proof.timestamp \u003c type(uint96).max via unchecked statement\n /// @param proof The bridge proof\n /// @return delta Time delta since proof submitted\n function _timeSince(BridgeProof memory proof) internal view returns (uint256 delta) {\n unchecked {\n delta = uint96(block.timestamp) - proof.timestamp;\n }\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n if (bridgeStatuses[transactionId] != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n BridgeProof memory proof = bridgeProofs[transactionId];\n if (proof.relayer != relayer) revert SenderIncorrect();\n return _timeSince(proof) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes memory request, address to) external onlyRole(RELAYER_ROLE) {\n bytes32 transactionId = keccak256(request);\n BridgeTransaction memory transaction = getBridgeTransaction(request);\n\n // update bridge tx status if able to claim origin collateral\n if (bridgeStatuses[transactionId] != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n\n BridgeProof memory proof = bridgeProofs[transactionId];\n if (proof.relayer != msg.sender) revert SenderIncorrect();\n if (_timeSince(proof) \u003c= DISPUTE_PERIOD) revert DisputePeriodNotPassed();\n\n bridgeStatuses[transactionId] = BridgeStatus.RELAYER_CLAIMED;\n\n // update protocol fees if origin fee amount exists\n if (transaction.originFeeAmount \u003e 0) protocolFees[transaction.originToken] += transaction.originFeeAmount;\n\n // transfer origin collateral less fee to specified address\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositClaimed(transactionId, msg.sender, to, token, amount);\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n if (bridgeStatuses[transactionId] != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(bridgeProofs[transactionId]) \u003e DISPUTE_PERIOD) revert DisputePeriodPassed();\n\n // @dev relayer gets slashed effectively if dest relay has gone thru\n bridgeStatuses[transactionId] = BridgeStatus.REQUESTED;\n delete bridgeProofs[transactionId];\n\n emit BridgeProofDisputed(transactionId, msg.sender);\n }\n\n /// @inheritdoc IFastBridge\n function refund(bytes memory request) external {\n bytes32 transactionId = keccak256(request);\n BridgeTransaction memory transaction = getBridgeTransaction(request);\n\n if (hasRole(REFUNDER_ROLE, msg.sender)) {\n // Refunder can refund if deadline has passed\n if (block.timestamp \u003c= transaction.deadline) revert DeadlineNotExceeded();\n } else {\n // Permissionless refund is allowed after REFUND_DELAY\n if (block.timestamp \u003c= transaction.deadline + REFUND_DELAY) revert DeadlineNotExceeded();\n }\n\n // set status to refunded if still in requested state\n if (bridgeStatuses[transactionId] != BridgeStatus.REQUESTED) revert StatusIncorrect();\n bridgeStatuses[transactionId] = BridgeStatus.REFUNDED;\n\n // transfer origin collateral back to original sender\n address to = transaction.originSender;\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount + transaction.originFeeAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n }\n}\n\n// test/FastBridgeMock.sol\n\ncontract FastBridgeMock is IFastBridge, Admin {\n // @dev the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @dev to prevent replays\n uint256 public nonce;\n\n /// @notice We include an empty \"test\" function so that this contract does not appear in the coverage report.\n function testFastBridgeMock() external {}\n\n function getBridgeTransaction(bytes memory request) public pure returns (BridgeTransaction memory) {\n return abi.decode(request, (BridgeTransaction));\n }\n\n // used for testing in go.\n // see: https://ethereum.stackexchange.com/questions/21155/how-to-expose-enum-in-solidity-contract\n // make sure to update fastbridge/status.go if this changes\n // or underliyng enum changes.\n //\n // TODO: a foundry test should be added to ensure this is always in sync.\n function getEnumKeyByValue(FastBridge.BridgeStatus keyValue) public pure returns (string memory) {\n if (FastBridge.BridgeStatus.NULL == keyValue) return \"NULL\";\n if (FastBridge.BridgeStatus.REQUESTED == keyValue) return \"REQUESTED\";\n if (FastBridge.BridgeStatus.RELAYER_PROVED == keyValue) return \"RELAYER_PROVED\";\n if (FastBridge.BridgeStatus.RELAYER_CLAIMED == keyValue) return \"RELAYER_CLAIMED\";\n if (FastBridge.BridgeStatus.REFUNDED == keyValue) return \"REFUNDED\";\n return \"\";\n }\n\n function mockBridgeRequest(bytes32 transactionId, address sender, BridgeParams memory params) external {\n sender;\n uint256 originFeeAmount = (params.originAmount * protocolFeeRate) / FEE_BPS;\n params.originAmount -= originFeeAmount;\n\n bytes memory request = abi.encode(\n BridgeTransaction({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: params.originAmount, // includes relayer fee\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n sendChainGas: params.sendChainGas,\n deadline: params.deadline,\n nonce: nonce++ // increment nonce on every bridge\n })\n );\n\n emit BridgeRequested(\n transactionId,\n params.sender,\n request,\n params.dstChainId,\n params.originToken,\n params.destToken,\n params.originAmount,\n params.destAmount,\n params.sendChainGas\n );\n }\n\n function mockBridgeRequestRaw(bytes32 transactionId, address sender, bytes memory request) external {\n sender;\n BridgeTransaction memory transaction = getBridgeTransaction(request);\n emit BridgeRequested(\n transactionId,\n transaction.originSender,\n request,\n transaction.destChainId,\n transaction.originToken,\n transaction.destToken,\n transaction.originAmount,\n transaction.destAmount,\n transaction.sendChainGas\n );\n }\n\n function mockBridgeRelayer(\n bytes32 transactionId,\n address relayer,\n address to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n )\n external\n {\n emit BridgeRelayed(\n transactionId, relayer, to, originChainId, originToken, destToken, originAmount, destAmount, chainGasAmount\n );\n }\n\n function bridge(BridgeParams memory) external payable {\n revert(\"not implemented\");\n }\n\n function relay(bytes memory) external payable {\n revert(\"not implemented\");\n }\n\n function prove(bytes memory, bytes32) external pure {\n revert(\"not implemented\");\n }\n\n function canClaim(bytes32, address) external pure returns (bool) {\n revert(\"not implemented\");\n }\n\n function claim(bytes memory, address) external pure {\n revert(\"not implemented\");\n }\n\n function dispute(bytes32) external pure {\n revert(\"not implemented\");\n }\n\n function refund(bytes memory) external pure {\n revert(\"not implemented\");\n }\n}\n","language":"Solidity","languageVersion":"0.8.20","compilerVersion":"0.8.20","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"","srcMapRuntime":"","abiDefinition":[{"inputs":[],"name":"AccessControlBadConfirmation","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"bytes32","name":"neededRole","type":"bytes32"}],"name":"AccessControlUnauthorizedAccount","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"previousAdminRole","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"newAdminRole","type":"bytes32"}],"name":"RoleAdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleRevoked","type":"event"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleAdmin","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"grantRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"hasRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"callerConfirmation","type":"address"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"revokeRole","outputs":[],"stateMutability":"nonpayable","type":"function"}],"userDoc":{"kind":"user","methods":{},"version":1},"developerDoc":{"details":"External interface of AccessControl declared to support ERC165 detection.","errors":{"AccessControlBadConfirmation()":[{"details":"The caller of a function is not the expected one. NOTE: Don't confuse with {AccessControlUnauthorizedAccount}."}],"AccessControlUnauthorizedAccount(address,bytes32)":[{"details":"The `account` is missing a role."}]},"events":{"RoleAdminChanged(bytes32,bytes32,bytes32)":{"details":"Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole` `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite {RoleAdminChanged} not being emitted signaling this."},"RoleGranted(bytes32,address,address)":{"details":"Emitted when `account` is granted `role`. `sender` is the account that originated the contract call, an admin role bearer except when using {AccessControl-_setupRole}."},"RoleRevoked(bytes32,address,address)":{"details":"Emitted when `account` is revoked `role`. `sender` is the account that originated the contract call: - if using `revokeRole`, it is the admin role bearer - if using `renounceRole`, it is the role bearer (i.e. `account`)"}},"kind":"dev","methods":{"getRoleAdmin(bytes32)":{"details":"Returns the admin role that controls `role`. See {grantRole} and {revokeRole}. To change a role's admin, use {AccessControl-_setRoleAdmin}."},"grantRole(bytes32,address)":{"details":"Grants `role` to `account`. If `account` had not been already granted `role`, emits a {RoleGranted} event. Requirements: - the caller must have ``role``'s admin role."},"hasRole(bytes32,address)":{"details":"Returns `true` if `account` has been granted `role`."},"renounceRole(bytes32,address)":{"details":"Revokes `role` from the calling account. Roles are often managed via {grantRole} and {revokeRole}: this function's purpose is to provide a mechanism for accounts to lose their privileges if they are compromised (such as when a trusted device is misplaced). If the calling account had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must be `callerConfirmation`."},"revokeRole(bytes32,address)":{"details":"Revokes `role` from `account`. If `account` had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must have ``role``'s admin role."}},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.20+commit.a1b79de6\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[],\"name\":\"AccessControlBadConfirmation\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"neededRole\",\"type\":\"bytes32\"}],\"name\":\"AccessControlUnauthorizedAccount\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"previousAdminRole\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"newAdminRole\",\"type\":\"bytes32\"}],\"name\":\"RoleAdminChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleGranted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleRevoked\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"}],\"name\":\"getRoleAdmin\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"grantRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"hasRole\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"callerConfirmation\",\"type\":\"address\"}],\"name\":\"renounceRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"revokeRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"details\":\"External interface of AccessControl declared to support ERC165 detection.\",\"errors\":{\"AccessControlBadConfirmation()\":[{\"details\":\"The caller of a function is not the expected one. NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\"}],\"AccessControlUnauthorizedAccount(address,bytes32)\":[{\"details\":\"The `account` is missing a role.\"}]},\"events\":{\"RoleAdminChanged(bytes32,bytes32,bytes32)\":{\"details\":\"Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole` `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite {RoleAdminChanged} not being emitted signaling this.\"},\"RoleGranted(bytes32,address,address)\":{\"details\":\"Emitted when `account` is granted `role`. `sender` is the account that originated the contract call, an admin role bearer except when using {AccessControl-_setupRole}.\"},\"RoleRevoked(bytes32,address,address)\":{\"details\":\"Emitted when `account` is revoked `role`. `sender` is the account that originated the contract call: - if using `revokeRole`, it is the admin role bearer - if using `renounceRole`, it is the role bearer (i.e. `account`)\"}},\"kind\":\"dev\",\"methods\":{\"getRoleAdmin(bytes32)\":{\"details\":\"Returns the admin role that controls `role`. See {grantRole} and {revokeRole}. To change a role's admin, use {AccessControl-_setRoleAdmin}.\"},\"grantRole(bytes32,address)\":{\"details\":\"Grants `role` to `account`. If `account` had not been already granted `role`, emits a {RoleGranted} event. Requirements: - the caller must have ``role``'s admin role.\"},\"hasRole(bytes32,address)\":{\"details\":\"Returns `true` if `account` has been granted `role`.\"},\"renounceRole(bytes32,address)\":{\"details\":\"Revokes `role` from the calling account. Roles are often managed via {grantRole} and {revokeRole}: this function's purpose is to provide a mechanism for accounts to lose their privileges if they are compromised (such as when a trusted device is misplaced). If the calling account had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must be `callerConfirmation`.\"},\"revokeRole(bytes32,address)\":{\"details\":\"Revokes `role` from `account`. If `account` had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must have ``role``'s admin role.\"}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeMock.sol\":\"IAccessControl\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeMock.sol\":{\"keccak256\":\"0xf2751f52f8216801d500da7464ad01f3c23a8286e155e2dcba6d21d6e7fd95a0\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://85d2edab24ebe321043d2b88038437e8f443a0ef26fa2139c72dcc2bc7fbc602\",\"dweb:/ipfs/QmcULiFPFJzFDT4aupVSDreXz8uHxcABb5nxpAG4zYzfNN\"]}},\"version\":1}"},"hashes":{"getRoleAdmin(bytes32)":"248a9ca3","grantRole(bytes32,address)":"2f2ff15d","hasRole(bytes32,address)":"91d14854","renounceRole(bytes32,address)":"36568abe","revokeRole(bytes32,address)":"d547741f"}},"solidity/FastBridgeMock.sol:IAccessControlEnumerable":{"code":"0x","runtime-code":"0x","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.20 ^0.8.20 ^0.8.4;\n\n// contracts/interfaces/IAdmin.sol\n\ninterface IAdmin {\n // ============ Events ============\n\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n event ChainGasAmountUpdated(uint256 oldChainGasAmount, uint256 newChainGasAmount);\n\n // ============ Methods ============\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n\n function setChainGasAmount(uint256 newChainGasAmount) external;\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IMulticallTarget.sol\n\n/// @notice Interface for a contract that can be called multiple times by the same caller. Inspired by MulticallV3:\n/// https://github.com/mds1/multicall/blob/master/src/Multicall3.sol\ninterface IMulticallTarget {\n struct Result {\n bool success;\n bytes returnData;\n }\n\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external;\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results);\n}\n\n// contracts/libs/Errors.sol\n\nerror DeadlineExceeded();\nerror DeadlineNotExceeded();\nerror DeadlineTooShort();\nerror InsufficientOutputAmount();\n\nerror MsgValueIncorrect();\nerror PoolNotFound();\nerror TokenAddressMismatch();\nerror TokenNotContract();\nerror TokenNotETH();\nerror TokensIdentical();\n\nerror ChainIncorrect();\nerror AmountIncorrect();\nerror ZeroAddress();\n\nerror DisputePeriodNotPassed();\nerror DisputePeriodPassed();\nerror SenderIncorrect();\nerror StatusIncorrect();\nerror TransactionIdIncorrect();\nerror TransactionRelayed();\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// contracts/utils/MulticallTarget.sol\n\n// solhint-disable avoid-low-level-calls\n/// @notice Template for a contract that supports batched calls (preserving the msg.sender).\n/// Only calls with zero msg.value could be batched.\nabstract contract MulticallTarget is IMulticallTarget {\n error MulticallTarget__UndeterminedRevert();\n\n /// @notice Perform a batched call to this contract, preserving the msg.sender.\n /// The return data from each call is discarded.\n /// @dev The method is non-payable, so only calls with `msg.value == 0` could be batched.\n /// It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag.\n /// Otherwise, the whole batch call will be reverted with the original revert reason.\n /// @param data List of abi-encoded calldata for the calls to perform.\n /// @param ignoreReverts Whether to ignore the revert errors from the calls.\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external {\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\n if (!success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(result);\n }\n }\n }\n\n /// @notice Perform a batched call to this contract, preserving the msg.sender.\n /// The return data from each call is preserved.\n /// @dev The method is non-payable, so only calls with `msg.value == 0` could be batched.\n /// It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag.\n /// Otherwise, the whole batch call will be reverted with the original revert reason.\n /// @param data List of abi-encoded calldata for the calls to perform.\n /// @param ignoreReverts Whether to ignore the revert errors from the calls.\n /// @return results List of results from the calls: `(success, returnData)`.\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results)\n {\n results = new Result[](data.length);\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (results[i].success, results[i].returnData) = address(this).delegatecall(data[i]);\n if (!results[i].success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(results[i].returnData);\n }\n }\n }\n\n /// @dev Bubbles the revert message from the underlying call.\n /// Note: preserves the same custom error or revert string, if one was used.\n /// Source: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v5.0.2/contracts/utils/Address.sol#L143-L158\n function _bubbleRevert(bytes memory returnData) internal pure {\n // Look for revert reason and bubble it up if present\n if (returnData.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n // solhint-disable-next-line no-inline-assembly\n assembly {\n let returndata_size := mload(returnData)\n revert(add(32, returnData), returndata_size)\n }\n } else {\n revert MulticallTarget__UndeterminedRevert();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// contracts/libs/UniversalToken.sol\n\nlibrary UniversalTokenLib {\n using SafeERC20 for IERC20;\n\n address internal constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Transfers tokens to the given account. Reverts if transfer is not successful.\n /// @dev This might trigger fallback, if ETH is transferred to the contract.\n /// Make sure this can not lead to reentrancy attacks.\n function universalTransfer(address token, address to, uint256 value) internal {\n // Don't do anything, if need to send tokens to this address\n if (to == address(this)) return;\n // Don't do anything, if trying to send zero value\n if (value == 0) return;\n if (token == ETH_ADDRESS) {\n /// @dev Note: this can potentially lead to executing code in `to`.\n // solhint-disable-next-line avoid-low-level-calls\n (bool success,) = to.call{value: value}(\"\");\n require(success, \"ETH transfer failed\");\n } else {\n IERC20(token).safeTransfer(to, value);\n }\n }\n\n /// @notice Issues an infinite allowance to the spender, if the current allowance is insufficient\n /// to spend the given amount.\n function universalApproveInfinity(address token, address spender, uint256 amountToSpend) internal {\n // ETH Chad doesn't require your approval\n if (token == ETH_ADDRESS) return;\n // No-op if allowance is already sufficient\n uint256 allowance = IERC20(token).allowance(address(this), spender);\n if (allowance \u003e= amountToSpend) return;\n // Otherwise, reset approval to 0 and set to max allowance\n if (allowance \u003e 0) IERC20(token).safeDecreaseAllowance(spender, allowance);\n IERC20(token).safeIncreaseAllowance(spender, type(uint256).max);\n }\n\n /// @notice Returns the balance of the given token (or native ETH) for the given account.\n function universalBalanceOf(address token, address account) internal view returns (uint256) {\n if (token == ETH_ADDRESS) {\n return account.balance;\n } else {\n return IERC20(token).balanceOf(account);\n }\n }\n\n /// @dev Checks that token is a contract and not ETH_ADDRESS.\n function assertIsContract(address token) internal view {\n // Check that ETH_ADDRESS was not used (in case this is a predeploy on any of the chains)\n if (token == UniversalTokenLib.ETH_ADDRESS) revert TokenNotContract();\n // Check that token is not an EOA\n if (token.code.length == 0) revert TokenNotContract();\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/Admin.sol\n\ncontract Admin is IAdmin, AccessControlEnumerable {\n using UniversalTokenLib for address;\n\n bytes32 public constant RELAYER_ROLE = keccak256(\"RELAYER_ROLE\");\n bytes32 public constant REFUNDER_ROLE = keccak256(\"REFUNDER_ROLE\");\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n uint256 public constant FEE_BPS = 1e6;\n uint256 public constant FEE_RATE_MAX = 0.01e6; // max 1% on origin amount\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Chain gas amount to forward as rebate if requested\n uint256 public chainGasAmount;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n }\n\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n require(newFeeRate \u003c= FEE_RATE_MAX, \"newFeeRate \u003e max\");\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n token.universalTransfer(recipient, feeAmount);\n emit FeesSwept(token, recipient, feeAmount);\n }\n\n function setChainGasAmount(uint256 newChainGasAmount) external onlyRole(GOVERNOR_ROLE) {\n uint256 oldChainGasAmount = chainGasAmount;\n chainGasAmount = newChainGasAmount;\n emit ChainGasAmountUpdated(oldChainGasAmount, newChainGasAmount);\n }\n}\n\n// contracts/FastBridge.sol\n\ncontract FastBridge is IFastBridge, MulticallTarget, Admin {\n using SafeERC20 for IERC20;\n using UniversalTokenLib for address;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Delay for a transaction after which it could be permisionlessly refunded\n uint256 public constant REFUND_DELAY = 7 days;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeStatus) public bridgeStatuses;\n /// @notice Proof of relayed bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeProof) public bridgeProofs;\n /// @notice Whether bridge has been relayed on destination chain\n mapping(bytes32 =\u003e bool) public bridgeRelays;\n\n /// @dev to prevent replays\n uint256 public nonce;\n // @dev the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @notice Pulls a requested token from the user to the requested recipient.\n /// @dev Be careful of re-entrancy issues when msg.value \u003e 0 and recipient != address(this)\n function _pullToken(address recipient, address token, uint256 amount) internal returns (uint256 amountPulled) {\n if (token != UniversalTokenLib.ETH_ADDRESS) {\n token.assertIsContract();\n // Record token balance before transfer\n amountPulled = IERC20(token).balanceOf(recipient);\n // Token needs to be pulled only if msg.value is zero\n // This way user can specify WETH as the origin asset\n IERC20(token).safeTransferFrom(msg.sender, recipient, amount);\n // Use the difference between the recorded balance and the current balance as the amountPulled\n amountPulled = IERC20(token).balanceOf(recipient) - amountPulled;\n } else {\n // Otherwise, we need to check that ETH amount matches msg.value\n if (amount != msg.value) revert MsgValueIncorrect();\n // Transfer value to recipient if not this address\n if (recipient != address(this)) token.universalTransfer(recipient, amount);\n // We will forward msg.value in the external call later, if recipient is not this contract\n amountPulled = msg.value;\n }\n }\n\n /// @inheritdoc IFastBridge\n function getBridgeTransaction(bytes memory request) public pure returns (BridgeTransaction memory) {\n return abi.decode(request, (BridgeTransaction));\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n // check bridge params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n\n // transfer tokens to bridge contract\n // @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _pullToken(address(this), params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n\n // set status to requested\n bytes memory request = abi.encode(\n BridgeTransaction({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n sendChainGas: params.sendChainGas,\n deadline: params.deadline,\n nonce: nonce++ // increment nonce on every bridge\n })\n );\n bytes32 transactionId = keccak256(request);\n bridgeStatuses[transactionId] = BridgeStatus.REQUESTED;\n\n emit BridgeRequested(\n transactionId,\n params.sender,\n request,\n params.dstChainId,\n params.originToken,\n params.destToken,\n originAmount,\n params.destAmount,\n params.sendChainGas\n );\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes memory request) external payable onlyRole(RELAYER_ROLE) {\n bytes32 transactionId = keccak256(request);\n BridgeTransaction memory transaction = getBridgeTransaction(request);\n if (transaction.destChainId != uint32(block.chainid)) revert ChainIncorrect();\n\n // check haven't exceeded deadline for relay to happen\n if (block.timestamp \u003e transaction.deadline) revert DeadlineExceeded();\n\n // mark bridge transaction as relayed\n if (bridgeRelays[transactionId]) revert TransactionRelayed();\n bridgeRelays[transactionId] = true;\n\n // transfer tokens to recipient on destination chain and gas rebate if requested\n address to = transaction.destRecipient;\n address token = transaction.destToken;\n uint256 amount = transaction.destAmount;\n\n uint256 rebate = chainGasAmount;\n if (!transaction.sendChainGas) {\n // forward erc20\n rebate = 0;\n _pullToken(to, token, amount);\n } else if (token == UniversalTokenLib.ETH_ADDRESS) {\n // lump in gas rebate into amount in native gas token\n _pullToken(to, token, amount + rebate);\n } else {\n // forward erc20 then forward gas rebate in native gas token\n _pullToken(to, token, amount);\n _pullToken(to, UniversalTokenLib.ETH_ADDRESS, rebate);\n }\n\n emit BridgeRelayed(\n transactionId,\n msg.sender,\n to,\n transaction.originChainId,\n transaction.originToken,\n transaction.destToken,\n transaction.originAmount,\n transaction.destAmount,\n rebate\n );\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes memory request, bytes32 destTxHash) external onlyRole(RELAYER_ROLE) {\n bytes32 transactionId = keccak256(request);\n // update bridge tx status given proof provided\n if (bridgeStatuses[transactionId] != BridgeStatus.REQUESTED) revert StatusIncorrect();\n bridgeStatuses[transactionId] = BridgeStatus.RELAYER_PROVED;\n bridgeProofs[transactionId] = BridgeProof({timestamp: uint96(block.timestamp), relayer: msg.sender}); // overflow ok\n\n emit BridgeProofProvided(transactionId, msg.sender, destTxHash);\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint96(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint96).max but\n /// proof.timestamp \u003c type(uint96).max via unchecked statement\n /// @param proof The bridge proof\n /// @return delta Time delta since proof submitted\n function _timeSince(BridgeProof memory proof) internal view returns (uint256 delta) {\n unchecked {\n delta = uint96(block.timestamp) - proof.timestamp;\n }\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n if (bridgeStatuses[transactionId] != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n BridgeProof memory proof = bridgeProofs[transactionId];\n if (proof.relayer != relayer) revert SenderIncorrect();\n return _timeSince(proof) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes memory request, address to) external onlyRole(RELAYER_ROLE) {\n bytes32 transactionId = keccak256(request);\n BridgeTransaction memory transaction = getBridgeTransaction(request);\n\n // update bridge tx status if able to claim origin collateral\n if (bridgeStatuses[transactionId] != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n\n BridgeProof memory proof = bridgeProofs[transactionId];\n if (proof.relayer != msg.sender) revert SenderIncorrect();\n if (_timeSince(proof) \u003c= DISPUTE_PERIOD) revert DisputePeriodNotPassed();\n\n bridgeStatuses[transactionId] = BridgeStatus.RELAYER_CLAIMED;\n\n // update protocol fees if origin fee amount exists\n if (transaction.originFeeAmount \u003e 0) protocolFees[transaction.originToken] += transaction.originFeeAmount;\n\n // transfer origin collateral less fee to specified address\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositClaimed(transactionId, msg.sender, to, token, amount);\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n if (bridgeStatuses[transactionId] != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(bridgeProofs[transactionId]) \u003e DISPUTE_PERIOD) revert DisputePeriodPassed();\n\n // @dev relayer gets slashed effectively if dest relay has gone thru\n bridgeStatuses[transactionId] = BridgeStatus.REQUESTED;\n delete bridgeProofs[transactionId];\n\n emit BridgeProofDisputed(transactionId, msg.sender);\n }\n\n /// @inheritdoc IFastBridge\n function refund(bytes memory request) external {\n bytes32 transactionId = keccak256(request);\n BridgeTransaction memory transaction = getBridgeTransaction(request);\n\n if (hasRole(REFUNDER_ROLE, msg.sender)) {\n // Refunder can refund if deadline has passed\n if (block.timestamp \u003c= transaction.deadline) revert DeadlineNotExceeded();\n } else {\n // Permissionless refund is allowed after REFUND_DELAY\n if (block.timestamp \u003c= transaction.deadline + REFUND_DELAY) revert DeadlineNotExceeded();\n }\n\n // set status to refunded if still in requested state\n if (bridgeStatuses[transactionId] != BridgeStatus.REQUESTED) revert StatusIncorrect();\n bridgeStatuses[transactionId] = BridgeStatus.REFUNDED;\n\n // transfer origin collateral back to original sender\n address to = transaction.originSender;\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount + transaction.originFeeAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n }\n}\n\n// test/FastBridgeMock.sol\n\ncontract FastBridgeMock is IFastBridge, Admin {\n // @dev the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @dev to prevent replays\n uint256 public nonce;\n\n /// @notice We include an empty \"test\" function so that this contract does not appear in the coverage report.\n function testFastBridgeMock() external {}\n\n function getBridgeTransaction(bytes memory request) public pure returns (BridgeTransaction memory) {\n return abi.decode(request, (BridgeTransaction));\n }\n\n // used for testing in go.\n // see: https://ethereum.stackexchange.com/questions/21155/how-to-expose-enum-in-solidity-contract\n // make sure to update fastbridge/status.go if this changes\n // or underliyng enum changes.\n //\n // TODO: a foundry test should be added to ensure this is always in sync.\n function getEnumKeyByValue(FastBridge.BridgeStatus keyValue) public pure returns (string memory) {\n if (FastBridge.BridgeStatus.NULL == keyValue) return \"NULL\";\n if (FastBridge.BridgeStatus.REQUESTED == keyValue) return \"REQUESTED\";\n if (FastBridge.BridgeStatus.RELAYER_PROVED == keyValue) return \"RELAYER_PROVED\";\n if (FastBridge.BridgeStatus.RELAYER_CLAIMED == keyValue) return \"RELAYER_CLAIMED\";\n if (FastBridge.BridgeStatus.REFUNDED == keyValue) return \"REFUNDED\";\n return \"\";\n }\n\n function mockBridgeRequest(bytes32 transactionId, address sender, BridgeParams memory params) external {\n sender;\n uint256 originFeeAmount = (params.originAmount * protocolFeeRate) / FEE_BPS;\n params.originAmount -= originFeeAmount;\n\n bytes memory request = abi.encode(\n BridgeTransaction({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: params.originAmount, // includes relayer fee\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n sendChainGas: params.sendChainGas,\n deadline: params.deadline,\n nonce: nonce++ // increment nonce on every bridge\n })\n );\n\n emit BridgeRequested(\n transactionId,\n params.sender,\n request,\n params.dstChainId,\n params.originToken,\n params.destToken,\n params.originAmount,\n params.destAmount,\n params.sendChainGas\n );\n }\n\n function mockBridgeRequestRaw(bytes32 transactionId, address sender, bytes memory request) external {\n sender;\n BridgeTransaction memory transaction = getBridgeTransaction(request);\n emit BridgeRequested(\n transactionId,\n transaction.originSender,\n request,\n transaction.destChainId,\n transaction.originToken,\n transaction.destToken,\n transaction.originAmount,\n transaction.destAmount,\n transaction.sendChainGas\n );\n }\n\n function mockBridgeRelayer(\n bytes32 transactionId,\n address relayer,\n address to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n )\n external\n {\n emit BridgeRelayed(\n transactionId, relayer, to, originChainId, originToken, destToken, originAmount, destAmount, chainGasAmount\n );\n }\n\n function bridge(BridgeParams memory) external payable {\n revert(\"not implemented\");\n }\n\n function relay(bytes memory) external payable {\n revert(\"not implemented\");\n }\n\n function prove(bytes memory, bytes32) external pure {\n revert(\"not implemented\");\n }\n\n function canClaim(bytes32, address) external pure returns (bool) {\n revert(\"not implemented\");\n }\n\n function claim(bytes memory, address) external pure {\n revert(\"not implemented\");\n }\n\n function dispute(bytes32) external pure {\n revert(\"not implemented\");\n }\n\n function refund(bytes memory) external pure {\n revert(\"not implemented\");\n }\n}\n","language":"Solidity","languageVersion":"0.8.20","compilerVersion":"0.8.20","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"","srcMapRuntime":"","abiDefinition":[{"inputs":[],"name":"AccessControlBadConfirmation","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"bytes32","name":"neededRole","type":"bytes32"}],"name":"AccessControlUnauthorizedAccount","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"previousAdminRole","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"newAdminRole","type":"bytes32"}],"name":"RoleAdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleRevoked","type":"event"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleAdmin","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"uint256","name":"index","type":"uint256"}],"name":"getRoleMember","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleMemberCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"grantRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"hasRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"callerConfirmation","type":"address"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"revokeRole","outputs":[],"stateMutability":"nonpayable","type":"function"}],"userDoc":{"kind":"user","methods":{},"version":1},"developerDoc":{"details":"External interface of AccessControlEnumerable declared to support ERC165 detection.","errors":{"AccessControlBadConfirmation()":[{"details":"The caller of a function is not the expected one. NOTE: Don't confuse with {AccessControlUnauthorizedAccount}."}],"AccessControlUnauthorizedAccount(address,bytes32)":[{"details":"The `account` is missing a role."}]},"events":{"RoleAdminChanged(bytes32,bytes32,bytes32)":{"details":"Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole` `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite {RoleAdminChanged} not being emitted signaling this."},"RoleGranted(bytes32,address,address)":{"details":"Emitted when `account` is granted `role`. `sender` is the account that originated the contract call, an admin role bearer except when using {AccessControl-_setupRole}."},"RoleRevoked(bytes32,address,address)":{"details":"Emitted when `account` is revoked `role`. `sender` is the account that originated the contract call: - if using `revokeRole`, it is the admin role bearer - if using `renounceRole`, it is the role bearer (i.e. `account`)"}},"kind":"dev","methods":{"getRoleAdmin(bytes32)":{"details":"Returns the admin role that controls `role`. See {grantRole} and {revokeRole}. To change a role's admin, use {AccessControl-_setRoleAdmin}."},"getRoleMember(bytes32,uint256)":{"details":"Returns one of the accounts that have `role`. `index` must be a value between 0 and {getRoleMemberCount}, non-inclusive. Role bearers are not sorted in any particular way, and their ordering may change at any point. WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure you perform all queries on the same block. See the following https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post] for more information."},"getRoleMemberCount(bytes32)":{"details":"Returns the number of accounts that have `role`. Can be used together with {getRoleMember} to enumerate all bearers of a role."},"grantRole(bytes32,address)":{"details":"Grants `role` to `account`. If `account` had not been already granted `role`, emits a {RoleGranted} event. Requirements: - the caller must have ``role``'s admin role."},"hasRole(bytes32,address)":{"details":"Returns `true` if `account` has been granted `role`."},"renounceRole(bytes32,address)":{"details":"Revokes `role` from the calling account. Roles are often managed via {grantRole} and {revokeRole}: this function's purpose is to provide a mechanism for accounts to lose their privileges if they are compromised (such as when a trusted device is misplaced). If the calling account had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must be `callerConfirmation`."},"revokeRole(bytes32,address)":{"details":"Revokes `role` from `account`. If `account` had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must have ``role``'s admin role."}},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.20+commit.a1b79de6\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[],\"name\":\"AccessControlBadConfirmation\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"neededRole\",\"type\":\"bytes32\"}],\"name\":\"AccessControlUnauthorizedAccount\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"previousAdminRole\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"newAdminRole\",\"type\":\"bytes32\"}],\"name\":\"RoleAdminChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleGranted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleRevoked\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"}],\"name\":\"getRoleAdmin\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"index\",\"type\":\"uint256\"}],\"name\":\"getRoleMember\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"}],\"name\":\"getRoleMemberCount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"grantRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"hasRole\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"callerConfirmation\",\"type\":\"address\"}],\"name\":\"renounceRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"revokeRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"details\":\"External interface of AccessControlEnumerable declared to support ERC165 detection.\",\"errors\":{\"AccessControlBadConfirmation()\":[{\"details\":\"The caller of a function is not the expected one. NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\"}],\"AccessControlUnauthorizedAccount(address,bytes32)\":[{\"details\":\"The `account` is missing a role.\"}]},\"events\":{\"RoleAdminChanged(bytes32,bytes32,bytes32)\":{\"details\":\"Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole` `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite {RoleAdminChanged} not being emitted signaling this.\"},\"RoleGranted(bytes32,address,address)\":{\"details\":\"Emitted when `account` is granted `role`. `sender` is the account that originated the contract call, an admin role bearer except when using {AccessControl-_setupRole}.\"},\"RoleRevoked(bytes32,address,address)\":{\"details\":\"Emitted when `account` is revoked `role`. `sender` is the account that originated the contract call: - if using `revokeRole`, it is the admin role bearer - if using `renounceRole`, it is the role bearer (i.e. `account`)\"}},\"kind\":\"dev\",\"methods\":{\"getRoleAdmin(bytes32)\":{\"details\":\"Returns the admin role that controls `role`. See {grantRole} and {revokeRole}. To change a role's admin, use {AccessControl-_setRoleAdmin}.\"},\"getRoleMember(bytes32,uint256)\":{\"details\":\"Returns one of the accounts that have `role`. `index` must be a value between 0 and {getRoleMemberCount}, non-inclusive. Role bearers are not sorted in any particular way, and their ordering may change at any point. WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure you perform all queries on the same block. See the following https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post] for more information.\"},\"getRoleMemberCount(bytes32)\":{\"details\":\"Returns the number of accounts that have `role`. Can be used together with {getRoleMember} to enumerate all bearers of a role.\"},\"grantRole(bytes32,address)\":{\"details\":\"Grants `role` to `account`. If `account` had not been already granted `role`, emits a {RoleGranted} event. Requirements: - the caller must have ``role``'s admin role.\"},\"hasRole(bytes32,address)\":{\"details\":\"Returns `true` if `account` has been granted `role`.\"},\"renounceRole(bytes32,address)\":{\"details\":\"Revokes `role` from the calling account. Roles are often managed via {grantRole} and {revokeRole}: this function's purpose is to provide a mechanism for accounts to lose their privileges if they are compromised (such as when a trusted device is misplaced). If the calling account had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must be `callerConfirmation`.\"},\"revokeRole(bytes32,address)\":{\"details\":\"Revokes `role` from `account`. If `account` had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must have ``role``'s admin role.\"}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeMock.sol\":\"IAccessControlEnumerable\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeMock.sol\":{\"keccak256\":\"0xf2751f52f8216801d500da7464ad01f3c23a8286e155e2dcba6d21d6e7fd95a0\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://85d2edab24ebe321043d2b88038437e8f443a0ef26fa2139c72dcc2bc7fbc602\",\"dweb:/ipfs/QmcULiFPFJzFDT4aupVSDreXz8uHxcABb5nxpAG4zYzfNN\"]}},\"version\":1}"},"hashes":{"getRoleAdmin(bytes32)":"248a9ca3","getRoleMember(bytes32,uint256)":"9010d07c","getRoleMemberCount(bytes32)":"ca15c873","grantRole(bytes32,address)":"2f2ff15d","hasRole(bytes32,address)":"91d14854","renounceRole(bytes32,address)":"36568abe","revokeRole(bytes32,address)":"d547741f"}},"solidity/FastBridgeMock.sol:IAdmin":{"code":"0x","runtime-code":"0x","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.20 ^0.8.20 ^0.8.4;\n\n// contracts/interfaces/IAdmin.sol\n\ninterface IAdmin {\n // ============ Events ============\n\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n event ChainGasAmountUpdated(uint256 oldChainGasAmount, uint256 newChainGasAmount);\n\n // ============ Methods ============\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n\n function setChainGasAmount(uint256 newChainGasAmount) external;\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IMulticallTarget.sol\n\n/// @notice Interface for a contract that can be called multiple times by the same caller. Inspired by MulticallV3:\n/// https://github.com/mds1/multicall/blob/master/src/Multicall3.sol\ninterface IMulticallTarget {\n struct Result {\n bool success;\n bytes returnData;\n }\n\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external;\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results);\n}\n\n// contracts/libs/Errors.sol\n\nerror DeadlineExceeded();\nerror DeadlineNotExceeded();\nerror DeadlineTooShort();\nerror InsufficientOutputAmount();\n\nerror MsgValueIncorrect();\nerror PoolNotFound();\nerror TokenAddressMismatch();\nerror TokenNotContract();\nerror TokenNotETH();\nerror TokensIdentical();\n\nerror ChainIncorrect();\nerror AmountIncorrect();\nerror ZeroAddress();\n\nerror DisputePeriodNotPassed();\nerror DisputePeriodPassed();\nerror SenderIncorrect();\nerror StatusIncorrect();\nerror TransactionIdIncorrect();\nerror TransactionRelayed();\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// contracts/utils/MulticallTarget.sol\n\n// solhint-disable avoid-low-level-calls\n/// @notice Template for a contract that supports batched calls (preserving the msg.sender).\n/// Only calls with zero msg.value could be batched.\nabstract contract MulticallTarget is IMulticallTarget {\n error MulticallTarget__UndeterminedRevert();\n\n /// @notice Perform a batched call to this contract, preserving the msg.sender.\n /// The return data from each call is discarded.\n /// @dev The method is non-payable, so only calls with `msg.value == 0` could be batched.\n /// It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag.\n /// Otherwise, the whole batch call will be reverted with the original revert reason.\n /// @param data List of abi-encoded calldata for the calls to perform.\n /// @param ignoreReverts Whether to ignore the revert errors from the calls.\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external {\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\n if (!success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(result);\n }\n }\n }\n\n /// @notice Perform a batched call to this contract, preserving the msg.sender.\n /// The return data from each call is preserved.\n /// @dev The method is non-payable, so only calls with `msg.value == 0` could be batched.\n /// It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag.\n /// Otherwise, the whole batch call will be reverted with the original revert reason.\n /// @param data List of abi-encoded calldata for the calls to perform.\n /// @param ignoreReverts Whether to ignore the revert errors from the calls.\n /// @return results List of results from the calls: `(success, returnData)`.\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results)\n {\n results = new Result[](data.length);\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (results[i].success, results[i].returnData) = address(this).delegatecall(data[i]);\n if (!results[i].success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(results[i].returnData);\n }\n }\n }\n\n /// @dev Bubbles the revert message from the underlying call.\n /// Note: preserves the same custom error or revert string, if one was used.\n /// Source: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v5.0.2/contracts/utils/Address.sol#L143-L158\n function _bubbleRevert(bytes memory returnData) internal pure {\n // Look for revert reason and bubble it up if present\n if (returnData.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n // solhint-disable-next-line no-inline-assembly\n assembly {\n let returndata_size := mload(returnData)\n revert(add(32, returnData), returndata_size)\n }\n } else {\n revert MulticallTarget__UndeterminedRevert();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// contracts/libs/UniversalToken.sol\n\nlibrary UniversalTokenLib {\n using SafeERC20 for IERC20;\n\n address internal constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Transfers tokens to the given account. Reverts if transfer is not successful.\n /// @dev This might trigger fallback, if ETH is transferred to the contract.\n /// Make sure this can not lead to reentrancy attacks.\n function universalTransfer(address token, address to, uint256 value) internal {\n // Don't do anything, if need to send tokens to this address\n if (to == address(this)) return;\n // Don't do anything, if trying to send zero value\n if (value == 0) return;\n if (token == ETH_ADDRESS) {\n /// @dev Note: this can potentially lead to executing code in `to`.\n // solhint-disable-next-line avoid-low-level-calls\n (bool success,) = to.call{value: value}(\"\");\n require(success, \"ETH transfer failed\");\n } else {\n IERC20(token).safeTransfer(to, value);\n }\n }\n\n /// @notice Issues an infinite allowance to the spender, if the current allowance is insufficient\n /// to spend the given amount.\n function universalApproveInfinity(address token, address spender, uint256 amountToSpend) internal {\n // ETH Chad doesn't require your approval\n if (token == ETH_ADDRESS) return;\n // No-op if allowance is already sufficient\n uint256 allowance = IERC20(token).allowance(address(this), spender);\n if (allowance \u003e= amountToSpend) return;\n // Otherwise, reset approval to 0 and set to max allowance\n if (allowance \u003e 0) IERC20(token).safeDecreaseAllowance(spender, allowance);\n IERC20(token).safeIncreaseAllowance(spender, type(uint256).max);\n }\n\n /// @notice Returns the balance of the given token (or native ETH) for the given account.\n function universalBalanceOf(address token, address account) internal view returns (uint256) {\n if (token == ETH_ADDRESS) {\n return account.balance;\n } else {\n return IERC20(token).balanceOf(account);\n }\n }\n\n /// @dev Checks that token is a contract and not ETH_ADDRESS.\n function assertIsContract(address token) internal view {\n // Check that ETH_ADDRESS was not used (in case this is a predeploy on any of the chains)\n if (token == UniversalTokenLib.ETH_ADDRESS) revert TokenNotContract();\n // Check that token is not an EOA\n if (token.code.length == 0) revert TokenNotContract();\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/Admin.sol\n\ncontract Admin is IAdmin, AccessControlEnumerable {\n using UniversalTokenLib for address;\n\n bytes32 public constant RELAYER_ROLE = keccak256(\"RELAYER_ROLE\");\n bytes32 public constant REFUNDER_ROLE = keccak256(\"REFUNDER_ROLE\");\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n uint256 public constant FEE_BPS = 1e6;\n uint256 public constant FEE_RATE_MAX = 0.01e6; // max 1% on origin amount\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Chain gas amount to forward as rebate if requested\n uint256 public chainGasAmount;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n }\n\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n require(newFeeRate \u003c= FEE_RATE_MAX, \"newFeeRate \u003e max\");\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n token.universalTransfer(recipient, feeAmount);\n emit FeesSwept(token, recipient, feeAmount);\n }\n\n function setChainGasAmount(uint256 newChainGasAmount) external onlyRole(GOVERNOR_ROLE) {\n uint256 oldChainGasAmount = chainGasAmount;\n chainGasAmount = newChainGasAmount;\n emit ChainGasAmountUpdated(oldChainGasAmount, newChainGasAmount);\n }\n}\n\n// contracts/FastBridge.sol\n\ncontract FastBridge is IFastBridge, MulticallTarget, Admin {\n using SafeERC20 for IERC20;\n using UniversalTokenLib for address;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Delay for a transaction after which it could be permisionlessly refunded\n uint256 public constant REFUND_DELAY = 7 days;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeStatus) public bridgeStatuses;\n /// @notice Proof of relayed bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeProof) public bridgeProofs;\n /// @notice Whether bridge has been relayed on destination chain\n mapping(bytes32 =\u003e bool) public bridgeRelays;\n\n /// @dev to prevent replays\n uint256 public nonce;\n // @dev the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @notice Pulls a requested token from the user to the requested recipient.\n /// @dev Be careful of re-entrancy issues when msg.value \u003e 0 and recipient != address(this)\n function _pullToken(address recipient, address token, uint256 amount) internal returns (uint256 amountPulled) {\n if (token != UniversalTokenLib.ETH_ADDRESS) {\n token.assertIsContract();\n // Record token balance before transfer\n amountPulled = IERC20(token).balanceOf(recipient);\n // Token needs to be pulled only if msg.value is zero\n // This way user can specify WETH as the origin asset\n IERC20(token).safeTransferFrom(msg.sender, recipient, amount);\n // Use the difference between the recorded balance and the current balance as the amountPulled\n amountPulled = IERC20(token).balanceOf(recipient) - amountPulled;\n } else {\n // Otherwise, we need to check that ETH amount matches msg.value\n if (amount != msg.value) revert MsgValueIncorrect();\n // Transfer value to recipient if not this address\n if (recipient != address(this)) token.universalTransfer(recipient, amount);\n // We will forward msg.value in the external call later, if recipient is not this contract\n amountPulled = msg.value;\n }\n }\n\n /// @inheritdoc IFastBridge\n function getBridgeTransaction(bytes memory request) public pure returns (BridgeTransaction memory) {\n return abi.decode(request, (BridgeTransaction));\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n // check bridge params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n\n // transfer tokens to bridge contract\n // @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _pullToken(address(this), params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n\n // set status to requested\n bytes memory request = abi.encode(\n BridgeTransaction({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n sendChainGas: params.sendChainGas,\n deadline: params.deadline,\n nonce: nonce++ // increment nonce on every bridge\n })\n );\n bytes32 transactionId = keccak256(request);\n bridgeStatuses[transactionId] = BridgeStatus.REQUESTED;\n\n emit BridgeRequested(\n transactionId,\n params.sender,\n request,\n params.dstChainId,\n params.originToken,\n params.destToken,\n originAmount,\n params.destAmount,\n params.sendChainGas\n );\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes memory request) external payable onlyRole(RELAYER_ROLE) {\n bytes32 transactionId = keccak256(request);\n BridgeTransaction memory transaction = getBridgeTransaction(request);\n if (transaction.destChainId != uint32(block.chainid)) revert ChainIncorrect();\n\n // check haven't exceeded deadline for relay to happen\n if (block.timestamp \u003e transaction.deadline) revert DeadlineExceeded();\n\n // mark bridge transaction as relayed\n if (bridgeRelays[transactionId]) revert TransactionRelayed();\n bridgeRelays[transactionId] = true;\n\n // transfer tokens to recipient on destination chain and gas rebate if requested\n address to = transaction.destRecipient;\n address token = transaction.destToken;\n uint256 amount = transaction.destAmount;\n\n uint256 rebate = chainGasAmount;\n if (!transaction.sendChainGas) {\n // forward erc20\n rebate = 0;\n _pullToken(to, token, amount);\n } else if (token == UniversalTokenLib.ETH_ADDRESS) {\n // lump in gas rebate into amount in native gas token\n _pullToken(to, token, amount + rebate);\n } else {\n // forward erc20 then forward gas rebate in native gas token\n _pullToken(to, token, amount);\n _pullToken(to, UniversalTokenLib.ETH_ADDRESS, rebate);\n }\n\n emit BridgeRelayed(\n transactionId,\n msg.sender,\n to,\n transaction.originChainId,\n transaction.originToken,\n transaction.destToken,\n transaction.originAmount,\n transaction.destAmount,\n rebate\n );\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes memory request, bytes32 destTxHash) external onlyRole(RELAYER_ROLE) {\n bytes32 transactionId = keccak256(request);\n // update bridge tx status given proof provided\n if (bridgeStatuses[transactionId] != BridgeStatus.REQUESTED) revert StatusIncorrect();\n bridgeStatuses[transactionId] = BridgeStatus.RELAYER_PROVED;\n bridgeProofs[transactionId] = BridgeProof({timestamp: uint96(block.timestamp), relayer: msg.sender}); // overflow ok\n\n emit BridgeProofProvided(transactionId, msg.sender, destTxHash);\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint96(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint96).max but\n /// proof.timestamp \u003c type(uint96).max via unchecked statement\n /// @param proof The bridge proof\n /// @return delta Time delta since proof submitted\n function _timeSince(BridgeProof memory proof) internal view returns (uint256 delta) {\n unchecked {\n delta = uint96(block.timestamp) - proof.timestamp;\n }\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n if (bridgeStatuses[transactionId] != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n BridgeProof memory proof = bridgeProofs[transactionId];\n if (proof.relayer != relayer) revert SenderIncorrect();\n return _timeSince(proof) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes memory request, address to) external onlyRole(RELAYER_ROLE) {\n bytes32 transactionId = keccak256(request);\n BridgeTransaction memory transaction = getBridgeTransaction(request);\n\n // update bridge tx status if able to claim origin collateral\n if (bridgeStatuses[transactionId] != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n\n BridgeProof memory proof = bridgeProofs[transactionId];\n if (proof.relayer != msg.sender) revert SenderIncorrect();\n if (_timeSince(proof) \u003c= DISPUTE_PERIOD) revert DisputePeriodNotPassed();\n\n bridgeStatuses[transactionId] = BridgeStatus.RELAYER_CLAIMED;\n\n // update protocol fees if origin fee amount exists\n if (transaction.originFeeAmount \u003e 0) protocolFees[transaction.originToken] += transaction.originFeeAmount;\n\n // transfer origin collateral less fee to specified address\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositClaimed(transactionId, msg.sender, to, token, amount);\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n if (bridgeStatuses[transactionId] != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(bridgeProofs[transactionId]) \u003e DISPUTE_PERIOD) revert DisputePeriodPassed();\n\n // @dev relayer gets slashed effectively if dest relay has gone thru\n bridgeStatuses[transactionId] = BridgeStatus.REQUESTED;\n delete bridgeProofs[transactionId];\n\n emit BridgeProofDisputed(transactionId, msg.sender);\n }\n\n /// @inheritdoc IFastBridge\n function refund(bytes memory request) external {\n bytes32 transactionId = keccak256(request);\n BridgeTransaction memory transaction = getBridgeTransaction(request);\n\n if (hasRole(REFUNDER_ROLE, msg.sender)) {\n // Refunder can refund if deadline has passed\n if (block.timestamp \u003c= transaction.deadline) revert DeadlineNotExceeded();\n } else {\n // Permissionless refund is allowed after REFUND_DELAY\n if (block.timestamp \u003c= transaction.deadline + REFUND_DELAY) revert DeadlineNotExceeded();\n }\n\n // set status to refunded if still in requested state\n if (bridgeStatuses[transactionId] != BridgeStatus.REQUESTED) revert StatusIncorrect();\n bridgeStatuses[transactionId] = BridgeStatus.REFUNDED;\n\n // transfer origin collateral back to original sender\n address to = transaction.originSender;\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount + transaction.originFeeAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n }\n}\n\n// test/FastBridgeMock.sol\n\ncontract FastBridgeMock is IFastBridge, Admin {\n // @dev the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @dev to prevent replays\n uint256 public nonce;\n\n /// @notice We include an empty \"test\" function so that this contract does not appear in the coverage report.\n function testFastBridgeMock() external {}\n\n function getBridgeTransaction(bytes memory request) public pure returns (BridgeTransaction memory) {\n return abi.decode(request, (BridgeTransaction));\n }\n\n // used for testing in go.\n // see: https://ethereum.stackexchange.com/questions/21155/how-to-expose-enum-in-solidity-contract\n // make sure to update fastbridge/status.go if this changes\n // or underliyng enum changes.\n //\n // TODO: a foundry test should be added to ensure this is always in sync.\n function getEnumKeyByValue(FastBridge.BridgeStatus keyValue) public pure returns (string memory) {\n if (FastBridge.BridgeStatus.NULL == keyValue) return \"NULL\";\n if (FastBridge.BridgeStatus.REQUESTED == keyValue) return \"REQUESTED\";\n if (FastBridge.BridgeStatus.RELAYER_PROVED == keyValue) return \"RELAYER_PROVED\";\n if (FastBridge.BridgeStatus.RELAYER_CLAIMED == keyValue) return \"RELAYER_CLAIMED\";\n if (FastBridge.BridgeStatus.REFUNDED == keyValue) return \"REFUNDED\";\n return \"\";\n }\n\n function mockBridgeRequest(bytes32 transactionId, address sender, BridgeParams memory params) external {\n sender;\n uint256 originFeeAmount = (params.originAmount * protocolFeeRate) / FEE_BPS;\n params.originAmount -= originFeeAmount;\n\n bytes memory request = abi.encode(\n BridgeTransaction({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: params.originAmount, // includes relayer fee\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n sendChainGas: params.sendChainGas,\n deadline: params.deadline,\n nonce: nonce++ // increment nonce on every bridge\n })\n );\n\n emit BridgeRequested(\n transactionId,\n params.sender,\n request,\n params.dstChainId,\n params.originToken,\n params.destToken,\n params.originAmount,\n params.destAmount,\n params.sendChainGas\n );\n }\n\n function mockBridgeRequestRaw(bytes32 transactionId, address sender, bytes memory request) external {\n sender;\n BridgeTransaction memory transaction = getBridgeTransaction(request);\n emit BridgeRequested(\n transactionId,\n transaction.originSender,\n request,\n transaction.destChainId,\n transaction.originToken,\n transaction.destToken,\n transaction.originAmount,\n transaction.destAmount,\n transaction.sendChainGas\n );\n }\n\n function mockBridgeRelayer(\n bytes32 transactionId,\n address relayer,\n address to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n )\n external\n {\n emit BridgeRelayed(\n transactionId, relayer, to, originChainId, originToken, destToken, originAmount, destAmount, chainGasAmount\n );\n }\n\n function bridge(BridgeParams memory) external payable {\n revert(\"not implemented\");\n }\n\n function relay(bytes memory) external payable {\n revert(\"not implemented\");\n }\n\n function prove(bytes memory, bytes32) external pure {\n revert(\"not implemented\");\n }\n\n function canClaim(bytes32, address) external pure returns (bool) {\n revert(\"not implemented\");\n }\n\n function claim(bytes memory, address) external pure {\n revert(\"not implemented\");\n }\n\n function dispute(bytes32) external pure {\n revert(\"not implemented\");\n }\n\n function refund(bytes memory) external pure {\n revert(\"not implemented\");\n }\n}\n","language":"Solidity","languageVersion":"0.8.20","compilerVersion":"0.8.20","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"","srcMapRuntime":"","abiDefinition":[{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldChainGasAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newChainGasAmount","type":"uint256"}],"name":"ChainGasAmountUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldFeeRate","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newFeeRate","type":"uint256"}],"name":"FeeRateUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"address","name":"recipient","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"FeesSwept","type":"event"},{"inputs":[{"internalType":"uint256","name":"newChainGasAmount","type":"uint256"}],"name":"setChainGasAmount","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"newFeeRate","type":"uint256"}],"name":"setProtocolFeeRate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"address","name":"recipient","type":"address"}],"name":"sweepProtocolFees","outputs":[],"stateMutability":"nonpayable","type":"function"}],"userDoc":{"kind":"user","methods":{},"version":1},"developerDoc":{"kind":"dev","methods":{},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.20+commit.a1b79de6\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"oldChainGasAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newChainGasAmount\",\"type\":\"uint256\"}],\"name\":\"ChainGasAmountUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"oldFeeRate\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newFeeRate\",\"type\":\"uint256\"}],\"name\":\"FeeRateUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"FeesSwept\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"newChainGasAmount\",\"type\":\"uint256\"}],\"name\":\"setChainGasAmount\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"newFeeRate\",\"type\":\"uint256\"}],\"name\":\"setProtocolFeeRate\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"}],\"name\":\"sweepProtocolFees\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeMock.sol\":\"IAdmin\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeMock.sol\":{\"keccak256\":\"0xf2751f52f8216801d500da7464ad01f3c23a8286e155e2dcba6d21d6e7fd95a0\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://85d2edab24ebe321043d2b88038437e8f443a0ef26fa2139c72dcc2bc7fbc602\",\"dweb:/ipfs/QmcULiFPFJzFDT4aupVSDreXz8uHxcABb5nxpAG4zYzfNN\"]}},\"version\":1}"},"hashes":{"setChainGasAmount(uint256)":"b250fe6b","setProtocolFeeRate(uint256)":"b13aa2d6","sweepProtocolFees(address,address)":"06f333f2"}},"solidity/FastBridgeMock.sol:IERC165":{"code":"0x","runtime-code":"0x","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.20 ^0.8.20 ^0.8.4;\n\n// contracts/interfaces/IAdmin.sol\n\ninterface IAdmin {\n // ============ Events ============\n\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n event ChainGasAmountUpdated(uint256 oldChainGasAmount, uint256 newChainGasAmount);\n\n // ============ Methods ============\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n\n function setChainGasAmount(uint256 newChainGasAmount) external;\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IMulticallTarget.sol\n\n/// @notice Interface for a contract that can be called multiple times by the same caller. Inspired by MulticallV3:\n/// https://github.com/mds1/multicall/blob/master/src/Multicall3.sol\ninterface IMulticallTarget {\n struct Result {\n bool success;\n bytes returnData;\n }\n\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external;\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results);\n}\n\n// contracts/libs/Errors.sol\n\nerror DeadlineExceeded();\nerror DeadlineNotExceeded();\nerror DeadlineTooShort();\nerror InsufficientOutputAmount();\n\nerror MsgValueIncorrect();\nerror PoolNotFound();\nerror TokenAddressMismatch();\nerror TokenNotContract();\nerror TokenNotETH();\nerror TokensIdentical();\n\nerror ChainIncorrect();\nerror AmountIncorrect();\nerror ZeroAddress();\n\nerror DisputePeriodNotPassed();\nerror DisputePeriodPassed();\nerror SenderIncorrect();\nerror StatusIncorrect();\nerror TransactionIdIncorrect();\nerror TransactionRelayed();\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// contracts/utils/MulticallTarget.sol\n\n// solhint-disable avoid-low-level-calls\n/// @notice Template for a contract that supports batched calls (preserving the msg.sender).\n/// Only calls with zero msg.value could be batched.\nabstract contract MulticallTarget is IMulticallTarget {\n error MulticallTarget__UndeterminedRevert();\n\n /// @notice Perform a batched call to this contract, preserving the msg.sender.\n /// The return data from each call is discarded.\n /// @dev The method is non-payable, so only calls with `msg.value == 0` could be batched.\n /// It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag.\n /// Otherwise, the whole batch call will be reverted with the original revert reason.\n /// @param data List of abi-encoded calldata for the calls to perform.\n /// @param ignoreReverts Whether to ignore the revert errors from the calls.\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external {\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\n if (!success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(result);\n }\n }\n }\n\n /// @notice Perform a batched call to this contract, preserving the msg.sender.\n /// The return data from each call is preserved.\n /// @dev The method is non-payable, so only calls with `msg.value == 0` could be batched.\n /// It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag.\n /// Otherwise, the whole batch call will be reverted with the original revert reason.\n /// @param data List of abi-encoded calldata for the calls to perform.\n /// @param ignoreReverts Whether to ignore the revert errors from the calls.\n /// @return results List of results from the calls: `(success, returnData)`.\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results)\n {\n results = new Result[](data.length);\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (results[i].success, results[i].returnData) = address(this).delegatecall(data[i]);\n if (!results[i].success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(results[i].returnData);\n }\n }\n }\n\n /// @dev Bubbles the revert message from the underlying call.\n /// Note: preserves the same custom error or revert string, if one was used.\n /// Source: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v5.0.2/contracts/utils/Address.sol#L143-L158\n function _bubbleRevert(bytes memory returnData) internal pure {\n // Look for revert reason and bubble it up if present\n if (returnData.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n // solhint-disable-next-line no-inline-assembly\n assembly {\n let returndata_size := mload(returnData)\n revert(add(32, returnData), returndata_size)\n }\n } else {\n revert MulticallTarget__UndeterminedRevert();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// contracts/libs/UniversalToken.sol\n\nlibrary UniversalTokenLib {\n using SafeERC20 for IERC20;\n\n address internal constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Transfers tokens to the given account. Reverts if transfer is not successful.\n /// @dev This might trigger fallback, if ETH is transferred to the contract.\n /// Make sure this can not lead to reentrancy attacks.\n function universalTransfer(address token, address to, uint256 value) internal {\n // Don't do anything, if need to send tokens to this address\n if (to == address(this)) return;\n // Don't do anything, if trying to send zero value\n if (value == 0) return;\n if (token == ETH_ADDRESS) {\n /// @dev Note: this can potentially lead to executing code in `to`.\n // solhint-disable-next-line avoid-low-level-calls\n (bool success,) = to.call{value: value}(\"\");\n require(success, \"ETH transfer failed\");\n } else {\n IERC20(token).safeTransfer(to, value);\n }\n }\n\n /// @notice Issues an infinite allowance to the spender, if the current allowance is insufficient\n /// to spend the given amount.\n function universalApproveInfinity(address token, address spender, uint256 amountToSpend) internal {\n // ETH Chad doesn't require your approval\n if (token == ETH_ADDRESS) return;\n // No-op if allowance is already sufficient\n uint256 allowance = IERC20(token).allowance(address(this), spender);\n if (allowance \u003e= amountToSpend) return;\n // Otherwise, reset approval to 0 and set to max allowance\n if (allowance \u003e 0) IERC20(token).safeDecreaseAllowance(spender, allowance);\n IERC20(token).safeIncreaseAllowance(spender, type(uint256).max);\n }\n\n /// @notice Returns the balance of the given token (or native ETH) for the given account.\n function universalBalanceOf(address token, address account) internal view returns (uint256) {\n if (token == ETH_ADDRESS) {\n return account.balance;\n } else {\n return IERC20(token).balanceOf(account);\n }\n }\n\n /// @dev Checks that token is a contract and not ETH_ADDRESS.\n function assertIsContract(address token) internal view {\n // Check that ETH_ADDRESS was not used (in case this is a predeploy on any of the chains)\n if (token == UniversalTokenLib.ETH_ADDRESS) revert TokenNotContract();\n // Check that token is not an EOA\n if (token.code.length == 0) revert TokenNotContract();\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/Admin.sol\n\ncontract Admin is IAdmin, AccessControlEnumerable {\n using UniversalTokenLib for address;\n\n bytes32 public constant RELAYER_ROLE = keccak256(\"RELAYER_ROLE\");\n bytes32 public constant REFUNDER_ROLE = keccak256(\"REFUNDER_ROLE\");\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n uint256 public constant FEE_BPS = 1e6;\n uint256 public constant FEE_RATE_MAX = 0.01e6; // max 1% on origin amount\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Chain gas amount to forward as rebate if requested\n uint256 public chainGasAmount;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n }\n\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n require(newFeeRate \u003c= FEE_RATE_MAX, \"newFeeRate \u003e max\");\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n token.universalTransfer(recipient, feeAmount);\n emit FeesSwept(token, recipient, feeAmount);\n }\n\n function setChainGasAmount(uint256 newChainGasAmount) external onlyRole(GOVERNOR_ROLE) {\n uint256 oldChainGasAmount = chainGasAmount;\n chainGasAmount = newChainGasAmount;\n emit ChainGasAmountUpdated(oldChainGasAmount, newChainGasAmount);\n }\n}\n\n// contracts/FastBridge.sol\n\ncontract FastBridge is IFastBridge, MulticallTarget, Admin {\n using SafeERC20 for IERC20;\n using UniversalTokenLib for address;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Delay for a transaction after which it could be permisionlessly refunded\n uint256 public constant REFUND_DELAY = 7 days;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeStatus) public bridgeStatuses;\n /// @notice Proof of relayed bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeProof) public bridgeProofs;\n /// @notice Whether bridge has been relayed on destination chain\n mapping(bytes32 =\u003e bool) public bridgeRelays;\n\n /// @dev to prevent replays\n uint256 public nonce;\n // @dev the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @notice Pulls a requested token from the user to the requested recipient.\n /// @dev Be careful of re-entrancy issues when msg.value \u003e 0 and recipient != address(this)\n function _pullToken(address recipient, address token, uint256 amount) internal returns (uint256 amountPulled) {\n if (token != UniversalTokenLib.ETH_ADDRESS) {\n token.assertIsContract();\n // Record token balance before transfer\n amountPulled = IERC20(token).balanceOf(recipient);\n // Token needs to be pulled only if msg.value is zero\n // This way user can specify WETH as the origin asset\n IERC20(token).safeTransferFrom(msg.sender, recipient, amount);\n // Use the difference between the recorded balance and the current balance as the amountPulled\n amountPulled = IERC20(token).balanceOf(recipient) - amountPulled;\n } else {\n // Otherwise, we need to check that ETH amount matches msg.value\n if (amount != msg.value) revert MsgValueIncorrect();\n // Transfer value to recipient if not this address\n if (recipient != address(this)) token.universalTransfer(recipient, amount);\n // We will forward msg.value in the external call later, if recipient is not this contract\n amountPulled = msg.value;\n }\n }\n\n /// @inheritdoc IFastBridge\n function getBridgeTransaction(bytes memory request) public pure returns (BridgeTransaction memory) {\n return abi.decode(request, (BridgeTransaction));\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n // check bridge params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n\n // transfer tokens to bridge contract\n // @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _pullToken(address(this), params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n\n // set status to requested\n bytes memory request = abi.encode(\n BridgeTransaction({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n sendChainGas: params.sendChainGas,\n deadline: params.deadline,\n nonce: nonce++ // increment nonce on every bridge\n })\n );\n bytes32 transactionId = keccak256(request);\n bridgeStatuses[transactionId] = BridgeStatus.REQUESTED;\n\n emit BridgeRequested(\n transactionId,\n params.sender,\n request,\n params.dstChainId,\n params.originToken,\n params.destToken,\n originAmount,\n params.destAmount,\n params.sendChainGas\n );\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes memory request) external payable onlyRole(RELAYER_ROLE) {\n bytes32 transactionId = keccak256(request);\n BridgeTransaction memory transaction = getBridgeTransaction(request);\n if (transaction.destChainId != uint32(block.chainid)) revert ChainIncorrect();\n\n // check haven't exceeded deadline for relay to happen\n if (block.timestamp \u003e transaction.deadline) revert DeadlineExceeded();\n\n // mark bridge transaction as relayed\n if (bridgeRelays[transactionId]) revert TransactionRelayed();\n bridgeRelays[transactionId] = true;\n\n // transfer tokens to recipient on destination chain and gas rebate if requested\n address to = transaction.destRecipient;\n address token = transaction.destToken;\n uint256 amount = transaction.destAmount;\n\n uint256 rebate = chainGasAmount;\n if (!transaction.sendChainGas) {\n // forward erc20\n rebate = 0;\n _pullToken(to, token, amount);\n } else if (token == UniversalTokenLib.ETH_ADDRESS) {\n // lump in gas rebate into amount in native gas token\n _pullToken(to, token, amount + rebate);\n } else {\n // forward erc20 then forward gas rebate in native gas token\n _pullToken(to, token, amount);\n _pullToken(to, UniversalTokenLib.ETH_ADDRESS, rebate);\n }\n\n emit BridgeRelayed(\n transactionId,\n msg.sender,\n to,\n transaction.originChainId,\n transaction.originToken,\n transaction.destToken,\n transaction.originAmount,\n transaction.destAmount,\n rebate\n );\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes memory request, bytes32 destTxHash) external onlyRole(RELAYER_ROLE) {\n bytes32 transactionId = keccak256(request);\n // update bridge tx status given proof provided\n if (bridgeStatuses[transactionId] != BridgeStatus.REQUESTED) revert StatusIncorrect();\n bridgeStatuses[transactionId] = BridgeStatus.RELAYER_PROVED;\n bridgeProofs[transactionId] = BridgeProof({timestamp: uint96(block.timestamp), relayer: msg.sender}); // overflow ok\n\n emit BridgeProofProvided(transactionId, msg.sender, destTxHash);\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint96(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint96).max but\n /// proof.timestamp \u003c type(uint96).max via unchecked statement\n /// @param proof The bridge proof\n /// @return delta Time delta since proof submitted\n function _timeSince(BridgeProof memory proof) internal view returns (uint256 delta) {\n unchecked {\n delta = uint96(block.timestamp) - proof.timestamp;\n }\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n if (bridgeStatuses[transactionId] != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n BridgeProof memory proof = bridgeProofs[transactionId];\n if (proof.relayer != relayer) revert SenderIncorrect();\n return _timeSince(proof) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes memory request, address to) external onlyRole(RELAYER_ROLE) {\n bytes32 transactionId = keccak256(request);\n BridgeTransaction memory transaction = getBridgeTransaction(request);\n\n // update bridge tx status if able to claim origin collateral\n if (bridgeStatuses[transactionId] != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n\n BridgeProof memory proof = bridgeProofs[transactionId];\n if (proof.relayer != msg.sender) revert SenderIncorrect();\n if (_timeSince(proof) \u003c= DISPUTE_PERIOD) revert DisputePeriodNotPassed();\n\n bridgeStatuses[transactionId] = BridgeStatus.RELAYER_CLAIMED;\n\n // update protocol fees if origin fee amount exists\n if (transaction.originFeeAmount \u003e 0) protocolFees[transaction.originToken] += transaction.originFeeAmount;\n\n // transfer origin collateral less fee to specified address\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositClaimed(transactionId, msg.sender, to, token, amount);\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n if (bridgeStatuses[transactionId] != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(bridgeProofs[transactionId]) \u003e DISPUTE_PERIOD) revert DisputePeriodPassed();\n\n // @dev relayer gets slashed effectively if dest relay has gone thru\n bridgeStatuses[transactionId] = BridgeStatus.REQUESTED;\n delete bridgeProofs[transactionId];\n\n emit BridgeProofDisputed(transactionId, msg.sender);\n }\n\n /// @inheritdoc IFastBridge\n function refund(bytes memory request) external {\n bytes32 transactionId = keccak256(request);\n BridgeTransaction memory transaction = getBridgeTransaction(request);\n\n if (hasRole(REFUNDER_ROLE, msg.sender)) {\n // Refunder can refund if deadline has passed\n if (block.timestamp \u003c= transaction.deadline) revert DeadlineNotExceeded();\n } else {\n // Permissionless refund is allowed after REFUND_DELAY\n if (block.timestamp \u003c= transaction.deadline + REFUND_DELAY) revert DeadlineNotExceeded();\n }\n\n // set status to refunded if still in requested state\n if (bridgeStatuses[transactionId] != BridgeStatus.REQUESTED) revert StatusIncorrect();\n bridgeStatuses[transactionId] = BridgeStatus.REFUNDED;\n\n // transfer origin collateral back to original sender\n address to = transaction.originSender;\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount + transaction.originFeeAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n }\n}\n\n// test/FastBridgeMock.sol\n\ncontract FastBridgeMock is IFastBridge, Admin {\n // @dev the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @dev to prevent replays\n uint256 public nonce;\n\n /// @notice We include an empty \"test\" function so that this contract does not appear in the coverage report.\n function testFastBridgeMock() external {}\n\n function getBridgeTransaction(bytes memory request) public pure returns (BridgeTransaction memory) {\n return abi.decode(request, (BridgeTransaction));\n }\n\n // used for testing in go.\n // see: https://ethereum.stackexchange.com/questions/21155/how-to-expose-enum-in-solidity-contract\n // make sure to update fastbridge/status.go if this changes\n // or underliyng enum changes.\n //\n // TODO: a foundry test should be added to ensure this is always in sync.\n function getEnumKeyByValue(FastBridge.BridgeStatus keyValue) public pure returns (string memory) {\n if (FastBridge.BridgeStatus.NULL == keyValue) return \"NULL\";\n if (FastBridge.BridgeStatus.REQUESTED == keyValue) return \"REQUESTED\";\n if (FastBridge.BridgeStatus.RELAYER_PROVED == keyValue) return \"RELAYER_PROVED\";\n if (FastBridge.BridgeStatus.RELAYER_CLAIMED == keyValue) return \"RELAYER_CLAIMED\";\n if (FastBridge.BridgeStatus.REFUNDED == keyValue) return \"REFUNDED\";\n return \"\";\n }\n\n function mockBridgeRequest(bytes32 transactionId, address sender, BridgeParams memory params) external {\n sender;\n uint256 originFeeAmount = (params.originAmount * protocolFeeRate) / FEE_BPS;\n params.originAmount -= originFeeAmount;\n\n bytes memory request = abi.encode(\n BridgeTransaction({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: params.originAmount, // includes relayer fee\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n sendChainGas: params.sendChainGas,\n deadline: params.deadline,\n nonce: nonce++ // increment nonce on every bridge\n })\n );\n\n emit BridgeRequested(\n transactionId,\n params.sender,\n request,\n params.dstChainId,\n params.originToken,\n params.destToken,\n params.originAmount,\n params.destAmount,\n params.sendChainGas\n );\n }\n\n function mockBridgeRequestRaw(bytes32 transactionId, address sender, bytes memory request) external {\n sender;\n BridgeTransaction memory transaction = getBridgeTransaction(request);\n emit BridgeRequested(\n transactionId,\n transaction.originSender,\n request,\n transaction.destChainId,\n transaction.originToken,\n transaction.destToken,\n transaction.originAmount,\n transaction.destAmount,\n transaction.sendChainGas\n );\n }\n\n function mockBridgeRelayer(\n bytes32 transactionId,\n address relayer,\n address to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n )\n external\n {\n emit BridgeRelayed(\n transactionId, relayer, to, originChainId, originToken, destToken, originAmount, destAmount, chainGasAmount\n );\n }\n\n function bridge(BridgeParams memory) external payable {\n revert(\"not implemented\");\n }\n\n function relay(bytes memory) external payable {\n revert(\"not implemented\");\n }\n\n function prove(bytes memory, bytes32) external pure {\n revert(\"not implemented\");\n }\n\n function canClaim(bytes32, address) external pure returns (bool) {\n revert(\"not implemented\");\n }\n\n function claim(bytes memory, address) external pure {\n revert(\"not implemented\");\n }\n\n function dispute(bytes32) external pure {\n revert(\"not implemented\");\n }\n\n function refund(bytes memory) external pure {\n revert(\"not implemented\");\n }\n}\n","language":"Solidity","languageVersion":"0.8.20","compilerVersion":"0.8.20","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"","srcMapRuntime":"","abiDefinition":[{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"}],"userDoc":{"kind":"user","methods":{},"version":1},"developerDoc":{"details":"Interface of the ERC165 standard, as defined in the https://eips.ethereum.org/EIPS/eip-165[EIP]. Implementers can declare support of contract interfaces, which can then be queried by others ({ERC165Checker}). For an implementation, see {ERC165}.","kind":"dev","methods":{"supportsInterface(bytes4)":{"details":"Returns true if this contract implements the interface defined by `interfaceId`. See the corresponding https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section] to learn more about how these ids are created. This function call must use less than 30 000 gas."}},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.20+commit.a1b79de6\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"bytes4\",\"name\":\"interfaceId\",\"type\":\"bytes4\"}],\"name\":\"supportsInterface\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"}],\"devdoc\":{\"details\":\"Interface of the ERC165 standard, as defined in the https://eips.ethereum.org/EIPS/eip-165[EIP]. Implementers can declare support of contract interfaces, which can then be queried by others ({ERC165Checker}). For an implementation, see {ERC165}.\",\"kind\":\"dev\",\"methods\":{\"supportsInterface(bytes4)\":{\"details\":\"Returns true if this contract implements the interface defined by `interfaceId`. See the corresponding https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section] to learn more about how these ids are created. This function call must use less than 30 000 gas.\"}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeMock.sol\":\"IERC165\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeMock.sol\":{\"keccak256\":\"0xf2751f52f8216801d500da7464ad01f3c23a8286e155e2dcba6d21d6e7fd95a0\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://85d2edab24ebe321043d2b88038437e8f443a0ef26fa2139c72dcc2bc7fbc602\",\"dweb:/ipfs/QmcULiFPFJzFDT4aupVSDreXz8uHxcABb5nxpAG4zYzfNN\"]}},\"version\":1}"},"hashes":{"supportsInterface(bytes4)":"01ffc9a7"}},"solidity/FastBridgeMock.sol:IERC20":{"code":"0x","runtime-code":"0x","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.20 ^0.8.20 ^0.8.4;\n\n// contracts/interfaces/IAdmin.sol\n\ninterface IAdmin {\n // ============ Events ============\n\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n event ChainGasAmountUpdated(uint256 oldChainGasAmount, uint256 newChainGasAmount);\n\n // ============ Methods ============\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n\n function setChainGasAmount(uint256 newChainGasAmount) external;\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IMulticallTarget.sol\n\n/// @notice Interface for a contract that can be called multiple times by the same caller. Inspired by MulticallV3:\n/// https://github.com/mds1/multicall/blob/master/src/Multicall3.sol\ninterface IMulticallTarget {\n struct Result {\n bool success;\n bytes returnData;\n }\n\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external;\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results);\n}\n\n// contracts/libs/Errors.sol\n\nerror DeadlineExceeded();\nerror DeadlineNotExceeded();\nerror DeadlineTooShort();\nerror InsufficientOutputAmount();\n\nerror MsgValueIncorrect();\nerror PoolNotFound();\nerror TokenAddressMismatch();\nerror TokenNotContract();\nerror TokenNotETH();\nerror TokensIdentical();\n\nerror ChainIncorrect();\nerror AmountIncorrect();\nerror ZeroAddress();\n\nerror DisputePeriodNotPassed();\nerror DisputePeriodPassed();\nerror SenderIncorrect();\nerror StatusIncorrect();\nerror TransactionIdIncorrect();\nerror TransactionRelayed();\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// contracts/utils/MulticallTarget.sol\n\n// solhint-disable avoid-low-level-calls\n/// @notice Template for a contract that supports batched calls (preserving the msg.sender).\n/// Only calls with zero msg.value could be batched.\nabstract contract MulticallTarget is IMulticallTarget {\n error MulticallTarget__UndeterminedRevert();\n\n /// @notice Perform a batched call to this contract, preserving the msg.sender.\n /// The return data from each call is discarded.\n /// @dev The method is non-payable, so only calls with `msg.value == 0` could be batched.\n /// It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag.\n /// Otherwise, the whole batch call will be reverted with the original revert reason.\n /// @param data List of abi-encoded calldata for the calls to perform.\n /// @param ignoreReverts Whether to ignore the revert errors from the calls.\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external {\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\n if (!success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(result);\n }\n }\n }\n\n /// @notice Perform a batched call to this contract, preserving the msg.sender.\n /// The return data from each call is preserved.\n /// @dev The method is non-payable, so only calls with `msg.value == 0` could be batched.\n /// It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag.\n /// Otherwise, the whole batch call will be reverted with the original revert reason.\n /// @param data List of abi-encoded calldata for the calls to perform.\n /// @param ignoreReverts Whether to ignore the revert errors from the calls.\n /// @return results List of results from the calls: `(success, returnData)`.\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results)\n {\n results = new Result[](data.length);\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (results[i].success, results[i].returnData) = address(this).delegatecall(data[i]);\n if (!results[i].success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(results[i].returnData);\n }\n }\n }\n\n /// @dev Bubbles the revert message from the underlying call.\n /// Note: preserves the same custom error or revert string, if one was used.\n /// Source: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v5.0.2/contracts/utils/Address.sol#L143-L158\n function _bubbleRevert(bytes memory returnData) internal pure {\n // Look for revert reason and bubble it up if present\n if (returnData.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n // solhint-disable-next-line no-inline-assembly\n assembly {\n let returndata_size := mload(returnData)\n revert(add(32, returnData), returndata_size)\n }\n } else {\n revert MulticallTarget__UndeterminedRevert();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// contracts/libs/UniversalToken.sol\n\nlibrary UniversalTokenLib {\n using SafeERC20 for IERC20;\n\n address internal constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Transfers tokens to the given account. Reverts if transfer is not successful.\n /// @dev This might trigger fallback, if ETH is transferred to the contract.\n /// Make sure this can not lead to reentrancy attacks.\n function universalTransfer(address token, address to, uint256 value) internal {\n // Don't do anything, if need to send tokens to this address\n if (to == address(this)) return;\n // Don't do anything, if trying to send zero value\n if (value == 0) return;\n if (token == ETH_ADDRESS) {\n /// @dev Note: this can potentially lead to executing code in `to`.\n // solhint-disable-next-line avoid-low-level-calls\n (bool success,) = to.call{value: value}(\"\");\n require(success, \"ETH transfer failed\");\n } else {\n IERC20(token).safeTransfer(to, value);\n }\n }\n\n /// @notice Issues an infinite allowance to the spender, if the current allowance is insufficient\n /// to spend the given amount.\n function universalApproveInfinity(address token, address spender, uint256 amountToSpend) internal {\n // ETH Chad doesn't require your approval\n if (token == ETH_ADDRESS) return;\n // No-op if allowance is already sufficient\n uint256 allowance = IERC20(token).allowance(address(this), spender);\n if (allowance \u003e= amountToSpend) return;\n // Otherwise, reset approval to 0 and set to max allowance\n if (allowance \u003e 0) IERC20(token).safeDecreaseAllowance(spender, allowance);\n IERC20(token).safeIncreaseAllowance(spender, type(uint256).max);\n }\n\n /// @notice Returns the balance of the given token (or native ETH) for the given account.\n function universalBalanceOf(address token, address account) internal view returns (uint256) {\n if (token == ETH_ADDRESS) {\n return account.balance;\n } else {\n return IERC20(token).balanceOf(account);\n }\n }\n\n /// @dev Checks that token is a contract and not ETH_ADDRESS.\n function assertIsContract(address token) internal view {\n // Check that ETH_ADDRESS was not used (in case this is a predeploy on any of the chains)\n if (token == UniversalTokenLib.ETH_ADDRESS) revert TokenNotContract();\n // Check that token is not an EOA\n if (token.code.length == 0) revert TokenNotContract();\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/Admin.sol\n\ncontract Admin is IAdmin, AccessControlEnumerable {\n using UniversalTokenLib for address;\n\n bytes32 public constant RELAYER_ROLE = keccak256(\"RELAYER_ROLE\");\n bytes32 public constant REFUNDER_ROLE = keccak256(\"REFUNDER_ROLE\");\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n uint256 public constant FEE_BPS = 1e6;\n uint256 public constant FEE_RATE_MAX = 0.01e6; // max 1% on origin amount\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Chain gas amount to forward as rebate if requested\n uint256 public chainGasAmount;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n }\n\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n require(newFeeRate \u003c= FEE_RATE_MAX, \"newFeeRate \u003e max\");\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n token.universalTransfer(recipient, feeAmount);\n emit FeesSwept(token, recipient, feeAmount);\n }\n\n function setChainGasAmount(uint256 newChainGasAmount) external onlyRole(GOVERNOR_ROLE) {\n uint256 oldChainGasAmount = chainGasAmount;\n chainGasAmount = newChainGasAmount;\n emit ChainGasAmountUpdated(oldChainGasAmount, newChainGasAmount);\n }\n}\n\n// contracts/FastBridge.sol\n\ncontract FastBridge is IFastBridge, MulticallTarget, Admin {\n using SafeERC20 for IERC20;\n using UniversalTokenLib for address;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Delay for a transaction after which it could be permisionlessly refunded\n uint256 public constant REFUND_DELAY = 7 days;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeStatus) public bridgeStatuses;\n /// @notice Proof of relayed bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeProof) public bridgeProofs;\n /// @notice Whether bridge has been relayed on destination chain\n mapping(bytes32 =\u003e bool) public bridgeRelays;\n\n /// @dev to prevent replays\n uint256 public nonce;\n // @dev the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @notice Pulls a requested token from the user to the requested recipient.\n /// @dev Be careful of re-entrancy issues when msg.value \u003e 0 and recipient != address(this)\n function _pullToken(address recipient, address token, uint256 amount) internal returns (uint256 amountPulled) {\n if (token != UniversalTokenLib.ETH_ADDRESS) {\n token.assertIsContract();\n // Record token balance before transfer\n amountPulled = IERC20(token).balanceOf(recipient);\n // Token needs to be pulled only if msg.value is zero\n // This way user can specify WETH as the origin asset\n IERC20(token).safeTransferFrom(msg.sender, recipient, amount);\n // Use the difference between the recorded balance and the current balance as the amountPulled\n amountPulled = IERC20(token).balanceOf(recipient) - amountPulled;\n } else {\n // Otherwise, we need to check that ETH amount matches msg.value\n if (amount != msg.value) revert MsgValueIncorrect();\n // Transfer value to recipient if not this address\n if (recipient != address(this)) token.universalTransfer(recipient, amount);\n // We will forward msg.value in the external call later, if recipient is not this contract\n amountPulled = msg.value;\n }\n }\n\n /// @inheritdoc IFastBridge\n function getBridgeTransaction(bytes memory request) public pure returns (BridgeTransaction memory) {\n return abi.decode(request, (BridgeTransaction));\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n // check bridge params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n\n // transfer tokens to bridge contract\n // @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _pullToken(address(this), params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n\n // set status to requested\n bytes memory request = abi.encode(\n BridgeTransaction({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n sendChainGas: params.sendChainGas,\n deadline: params.deadline,\n nonce: nonce++ // increment nonce on every bridge\n })\n );\n bytes32 transactionId = keccak256(request);\n bridgeStatuses[transactionId] = BridgeStatus.REQUESTED;\n\n emit BridgeRequested(\n transactionId,\n params.sender,\n request,\n params.dstChainId,\n params.originToken,\n params.destToken,\n originAmount,\n params.destAmount,\n params.sendChainGas\n );\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes memory request) external payable onlyRole(RELAYER_ROLE) {\n bytes32 transactionId = keccak256(request);\n BridgeTransaction memory transaction = getBridgeTransaction(request);\n if (transaction.destChainId != uint32(block.chainid)) revert ChainIncorrect();\n\n // check haven't exceeded deadline for relay to happen\n if (block.timestamp \u003e transaction.deadline) revert DeadlineExceeded();\n\n // mark bridge transaction as relayed\n if (bridgeRelays[transactionId]) revert TransactionRelayed();\n bridgeRelays[transactionId] = true;\n\n // transfer tokens to recipient on destination chain and gas rebate if requested\n address to = transaction.destRecipient;\n address token = transaction.destToken;\n uint256 amount = transaction.destAmount;\n\n uint256 rebate = chainGasAmount;\n if (!transaction.sendChainGas) {\n // forward erc20\n rebate = 0;\n _pullToken(to, token, amount);\n } else if (token == UniversalTokenLib.ETH_ADDRESS) {\n // lump in gas rebate into amount in native gas token\n _pullToken(to, token, amount + rebate);\n } else {\n // forward erc20 then forward gas rebate in native gas token\n _pullToken(to, token, amount);\n _pullToken(to, UniversalTokenLib.ETH_ADDRESS, rebate);\n }\n\n emit BridgeRelayed(\n transactionId,\n msg.sender,\n to,\n transaction.originChainId,\n transaction.originToken,\n transaction.destToken,\n transaction.originAmount,\n transaction.destAmount,\n rebate\n );\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes memory request, bytes32 destTxHash) external onlyRole(RELAYER_ROLE) {\n bytes32 transactionId = keccak256(request);\n // update bridge tx status given proof provided\n if (bridgeStatuses[transactionId] != BridgeStatus.REQUESTED) revert StatusIncorrect();\n bridgeStatuses[transactionId] = BridgeStatus.RELAYER_PROVED;\n bridgeProofs[transactionId] = BridgeProof({timestamp: uint96(block.timestamp), relayer: msg.sender}); // overflow ok\n\n emit BridgeProofProvided(transactionId, msg.sender, destTxHash);\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint96(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint96).max but\n /// proof.timestamp \u003c type(uint96).max via unchecked statement\n /// @param proof The bridge proof\n /// @return delta Time delta since proof submitted\n function _timeSince(BridgeProof memory proof) internal view returns (uint256 delta) {\n unchecked {\n delta = uint96(block.timestamp) - proof.timestamp;\n }\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n if (bridgeStatuses[transactionId] != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n BridgeProof memory proof = bridgeProofs[transactionId];\n if (proof.relayer != relayer) revert SenderIncorrect();\n return _timeSince(proof) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes memory request, address to) external onlyRole(RELAYER_ROLE) {\n bytes32 transactionId = keccak256(request);\n BridgeTransaction memory transaction = getBridgeTransaction(request);\n\n // update bridge tx status if able to claim origin collateral\n if (bridgeStatuses[transactionId] != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n\n BridgeProof memory proof = bridgeProofs[transactionId];\n if (proof.relayer != msg.sender) revert SenderIncorrect();\n if (_timeSince(proof) \u003c= DISPUTE_PERIOD) revert DisputePeriodNotPassed();\n\n bridgeStatuses[transactionId] = BridgeStatus.RELAYER_CLAIMED;\n\n // update protocol fees if origin fee amount exists\n if (transaction.originFeeAmount \u003e 0) protocolFees[transaction.originToken] += transaction.originFeeAmount;\n\n // transfer origin collateral less fee to specified address\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositClaimed(transactionId, msg.sender, to, token, amount);\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n if (bridgeStatuses[transactionId] != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(bridgeProofs[transactionId]) \u003e DISPUTE_PERIOD) revert DisputePeriodPassed();\n\n // @dev relayer gets slashed effectively if dest relay has gone thru\n bridgeStatuses[transactionId] = BridgeStatus.REQUESTED;\n delete bridgeProofs[transactionId];\n\n emit BridgeProofDisputed(transactionId, msg.sender);\n }\n\n /// @inheritdoc IFastBridge\n function refund(bytes memory request) external {\n bytes32 transactionId = keccak256(request);\n BridgeTransaction memory transaction = getBridgeTransaction(request);\n\n if (hasRole(REFUNDER_ROLE, msg.sender)) {\n // Refunder can refund if deadline has passed\n if (block.timestamp \u003c= transaction.deadline) revert DeadlineNotExceeded();\n } else {\n // Permissionless refund is allowed after REFUND_DELAY\n if (block.timestamp \u003c= transaction.deadline + REFUND_DELAY) revert DeadlineNotExceeded();\n }\n\n // set status to refunded if still in requested state\n if (bridgeStatuses[transactionId] != BridgeStatus.REQUESTED) revert StatusIncorrect();\n bridgeStatuses[transactionId] = BridgeStatus.REFUNDED;\n\n // transfer origin collateral back to original sender\n address to = transaction.originSender;\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount + transaction.originFeeAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n }\n}\n\n// test/FastBridgeMock.sol\n\ncontract FastBridgeMock is IFastBridge, Admin {\n // @dev the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @dev to prevent replays\n uint256 public nonce;\n\n /// @notice We include an empty \"test\" function so that this contract does not appear in the coverage report.\n function testFastBridgeMock() external {}\n\n function getBridgeTransaction(bytes memory request) public pure returns (BridgeTransaction memory) {\n return abi.decode(request, (BridgeTransaction));\n }\n\n // used for testing in go.\n // see: https://ethereum.stackexchange.com/questions/21155/how-to-expose-enum-in-solidity-contract\n // make sure to update fastbridge/status.go if this changes\n // or underliyng enum changes.\n //\n // TODO: a foundry test should be added to ensure this is always in sync.\n function getEnumKeyByValue(FastBridge.BridgeStatus keyValue) public pure returns (string memory) {\n if (FastBridge.BridgeStatus.NULL == keyValue) return \"NULL\";\n if (FastBridge.BridgeStatus.REQUESTED == keyValue) return \"REQUESTED\";\n if (FastBridge.BridgeStatus.RELAYER_PROVED == keyValue) return \"RELAYER_PROVED\";\n if (FastBridge.BridgeStatus.RELAYER_CLAIMED == keyValue) return \"RELAYER_CLAIMED\";\n if (FastBridge.BridgeStatus.REFUNDED == keyValue) return \"REFUNDED\";\n return \"\";\n }\n\n function mockBridgeRequest(bytes32 transactionId, address sender, BridgeParams memory params) external {\n sender;\n uint256 originFeeAmount = (params.originAmount * protocolFeeRate) / FEE_BPS;\n params.originAmount -= originFeeAmount;\n\n bytes memory request = abi.encode(\n BridgeTransaction({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: params.originAmount, // includes relayer fee\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n sendChainGas: params.sendChainGas,\n deadline: params.deadline,\n nonce: nonce++ // increment nonce on every bridge\n })\n );\n\n emit BridgeRequested(\n transactionId,\n params.sender,\n request,\n params.dstChainId,\n params.originToken,\n params.destToken,\n params.originAmount,\n params.destAmount,\n params.sendChainGas\n );\n }\n\n function mockBridgeRequestRaw(bytes32 transactionId, address sender, bytes memory request) external {\n sender;\n BridgeTransaction memory transaction = getBridgeTransaction(request);\n emit BridgeRequested(\n transactionId,\n transaction.originSender,\n request,\n transaction.destChainId,\n transaction.originToken,\n transaction.destToken,\n transaction.originAmount,\n transaction.destAmount,\n transaction.sendChainGas\n );\n }\n\n function mockBridgeRelayer(\n bytes32 transactionId,\n address relayer,\n address to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n )\n external\n {\n emit BridgeRelayed(\n transactionId, relayer, to, originChainId, originToken, destToken, originAmount, destAmount, chainGasAmount\n );\n }\n\n function bridge(BridgeParams memory) external payable {\n revert(\"not implemented\");\n }\n\n function relay(bytes memory) external payable {\n revert(\"not implemented\");\n }\n\n function prove(bytes memory, bytes32) external pure {\n revert(\"not implemented\");\n }\n\n function canClaim(bytes32, address) external pure returns (bool) {\n revert(\"not implemented\");\n }\n\n function claim(bytes memory, address) external pure {\n revert(\"not implemented\");\n }\n\n function dispute(bytes32) external pure {\n revert(\"not implemented\");\n }\n\n function refund(bytes memory) external pure {\n revert(\"not implemented\");\n }\n}\n","language":"Solidity","languageVersion":"0.8.20","compilerVersion":"0.8.20","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"","srcMapRuntime":"","abiDefinition":[{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Transfer","type":"event"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"}],"userDoc":{"kind":"user","methods":{},"version":1},"developerDoc":{"details":"Interface of the ERC20 standard as defined in the EIP.","events":{"Approval(address,address,uint256)":{"details":"Emitted when the allowance of a `spender` for an `owner` is set by a call to {approve}. `value` is the new allowance."},"Transfer(address,address,uint256)":{"details":"Emitted when `value` tokens are moved from one account (`from`) to another (`to`). Note that `value` may be zero."}},"kind":"dev","methods":{"allowance(address,address)":{"details":"Returns the remaining number of tokens that `spender` will be allowed to spend on behalf of `owner` through {transferFrom}. This is zero by default. This value changes when {approve} or {transferFrom} are called."},"approve(address,uint256)":{"details":"Sets a `value` amount of tokens as the allowance of `spender` over the caller's tokens. Returns a boolean value indicating whether the operation succeeded. IMPORTANT: Beware that changing an allowance with this method brings the risk that someone may use both the old and the new allowance by unfortunate transaction ordering. One possible solution to mitigate this race condition is to first reduce the spender's allowance to 0 and set the desired value afterwards: https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 Emits an {Approval} event."},"balanceOf(address)":{"details":"Returns the value of tokens owned by `account`."},"totalSupply()":{"details":"Returns the value of tokens in existence."},"transfer(address,uint256)":{"details":"Moves a `value` amount of tokens from the caller's account to `to`. Returns a boolean value indicating whether the operation succeeded. Emits a {Transfer} event."},"transferFrom(address,address,uint256)":{"details":"Moves a `value` amount of tokens from `from` to `to` using the allowance mechanism. `value` is then deducted from the caller's allowance. Returns a boolean value indicating whether the operation succeeded. Emits a {Transfer} event."}},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.20+commit.a1b79de6\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"Approval\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"Transfer\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"}],\"name\":\"allowance\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"approve\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"balanceOf\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"totalSupply\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"transfer\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"transferFrom\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"details\":\"Interface of the ERC20 standard as defined in the EIP.\",\"events\":{\"Approval(address,address,uint256)\":{\"details\":\"Emitted when the allowance of a `spender` for an `owner` is set by a call to {approve}. `value` is the new allowance.\"},\"Transfer(address,address,uint256)\":{\"details\":\"Emitted when `value` tokens are moved from one account (`from`) to another (`to`). Note that `value` may be zero.\"}},\"kind\":\"dev\",\"methods\":{\"allowance(address,address)\":{\"details\":\"Returns the remaining number of tokens that `spender` will be allowed to spend on behalf of `owner` through {transferFrom}. This is zero by default. This value changes when {approve} or {transferFrom} are called.\"},\"approve(address,uint256)\":{\"details\":\"Sets a `value` amount of tokens as the allowance of `spender` over the caller's tokens. Returns a boolean value indicating whether the operation succeeded. IMPORTANT: Beware that changing an allowance with this method brings the risk that someone may use both the old and the new allowance by unfortunate transaction ordering. One possible solution to mitigate this race condition is to first reduce the spender's allowance to 0 and set the desired value afterwards: https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 Emits an {Approval} event.\"},\"balanceOf(address)\":{\"details\":\"Returns the value of tokens owned by `account`.\"},\"totalSupply()\":{\"details\":\"Returns the value of tokens in existence.\"},\"transfer(address,uint256)\":{\"details\":\"Moves a `value` amount of tokens from the caller's account to `to`. Returns a boolean value indicating whether the operation succeeded. Emits a {Transfer} event.\"},\"transferFrom(address,address,uint256)\":{\"details\":\"Moves a `value` amount of tokens from `from` to `to` using the allowance mechanism. `value` is then deducted from the caller's allowance. Returns a boolean value indicating whether the operation succeeded. Emits a {Transfer} event.\"}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeMock.sol\":\"IERC20\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeMock.sol\":{\"keccak256\":\"0xf2751f52f8216801d500da7464ad01f3c23a8286e155e2dcba6d21d6e7fd95a0\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://85d2edab24ebe321043d2b88038437e8f443a0ef26fa2139c72dcc2bc7fbc602\",\"dweb:/ipfs/QmcULiFPFJzFDT4aupVSDreXz8uHxcABb5nxpAG4zYzfNN\"]}},\"version\":1}"},"hashes":{"allowance(address,address)":"dd62ed3e","approve(address,uint256)":"095ea7b3","balanceOf(address)":"70a08231","totalSupply()":"18160ddd","transfer(address,uint256)":"a9059cbb","transferFrom(address,address,uint256)":"23b872dd"}},"solidity/FastBridgeMock.sol:IERC20Permit":{"code":"0x","runtime-code":"0x","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.20 ^0.8.20 ^0.8.4;\n\n// contracts/interfaces/IAdmin.sol\n\ninterface IAdmin {\n // ============ Events ============\n\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n event ChainGasAmountUpdated(uint256 oldChainGasAmount, uint256 newChainGasAmount);\n\n // ============ Methods ============\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n\n function setChainGasAmount(uint256 newChainGasAmount) external;\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IMulticallTarget.sol\n\n/// @notice Interface for a contract that can be called multiple times by the same caller. Inspired by MulticallV3:\n/// https://github.com/mds1/multicall/blob/master/src/Multicall3.sol\ninterface IMulticallTarget {\n struct Result {\n bool success;\n bytes returnData;\n }\n\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external;\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results);\n}\n\n// contracts/libs/Errors.sol\n\nerror DeadlineExceeded();\nerror DeadlineNotExceeded();\nerror DeadlineTooShort();\nerror InsufficientOutputAmount();\n\nerror MsgValueIncorrect();\nerror PoolNotFound();\nerror TokenAddressMismatch();\nerror TokenNotContract();\nerror TokenNotETH();\nerror TokensIdentical();\n\nerror ChainIncorrect();\nerror AmountIncorrect();\nerror ZeroAddress();\n\nerror DisputePeriodNotPassed();\nerror DisputePeriodPassed();\nerror SenderIncorrect();\nerror StatusIncorrect();\nerror TransactionIdIncorrect();\nerror TransactionRelayed();\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// contracts/utils/MulticallTarget.sol\n\n// solhint-disable avoid-low-level-calls\n/// @notice Template for a contract that supports batched calls (preserving the msg.sender).\n/// Only calls with zero msg.value could be batched.\nabstract contract MulticallTarget is IMulticallTarget {\n error MulticallTarget__UndeterminedRevert();\n\n /// @notice Perform a batched call to this contract, preserving the msg.sender.\n /// The return data from each call is discarded.\n /// @dev The method is non-payable, so only calls with `msg.value == 0` could be batched.\n /// It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag.\n /// Otherwise, the whole batch call will be reverted with the original revert reason.\n /// @param data List of abi-encoded calldata for the calls to perform.\n /// @param ignoreReverts Whether to ignore the revert errors from the calls.\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external {\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\n if (!success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(result);\n }\n }\n }\n\n /// @notice Perform a batched call to this contract, preserving the msg.sender.\n /// The return data from each call is preserved.\n /// @dev The method is non-payable, so only calls with `msg.value == 0` could be batched.\n /// It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag.\n /// Otherwise, the whole batch call will be reverted with the original revert reason.\n /// @param data List of abi-encoded calldata for the calls to perform.\n /// @param ignoreReverts Whether to ignore the revert errors from the calls.\n /// @return results List of results from the calls: `(success, returnData)`.\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results)\n {\n results = new Result[](data.length);\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (results[i].success, results[i].returnData) = address(this).delegatecall(data[i]);\n if (!results[i].success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(results[i].returnData);\n }\n }\n }\n\n /// @dev Bubbles the revert message from the underlying call.\n /// Note: preserves the same custom error or revert string, if one was used.\n /// Source: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v5.0.2/contracts/utils/Address.sol#L143-L158\n function _bubbleRevert(bytes memory returnData) internal pure {\n // Look for revert reason and bubble it up if present\n if (returnData.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n // solhint-disable-next-line no-inline-assembly\n assembly {\n let returndata_size := mload(returnData)\n revert(add(32, returnData), returndata_size)\n }\n } else {\n revert MulticallTarget__UndeterminedRevert();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// contracts/libs/UniversalToken.sol\n\nlibrary UniversalTokenLib {\n using SafeERC20 for IERC20;\n\n address internal constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Transfers tokens to the given account. Reverts if transfer is not successful.\n /// @dev This might trigger fallback, if ETH is transferred to the contract.\n /// Make sure this can not lead to reentrancy attacks.\n function universalTransfer(address token, address to, uint256 value) internal {\n // Don't do anything, if need to send tokens to this address\n if (to == address(this)) return;\n // Don't do anything, if trying to send zero value\n if (value == 0) return;\n if (token == ETH_ADDRESS) {\n /// @dev Note: this can potentially lead to executing code in `to`.\n // solhint-disable-next-line avoid-low-level-calls\n (bool success,) = to.call{value: value}(\"\");\n require(success, \"ETH transfer failed\");\n } else {\n IERC20(token).safeTransfer(to, value);\n }\n }\n\n /// @notice Issues an infinite allowance to the spender, if the current allowance is insufficient\n /// to spend the given amount.\n function universalApproveInfinity(address token, address spender, uint256 amountToSpend) internal {\n // ETH Chad doesn't require your approval\n if (token == ETH_ADDRESS) return;\n // No-op if allowance is already sufficient\n uint256 allowance = IERC20(token).allowance(address(this), spender);\n if (allowance \u003e= amountToSpend) return;\n // Otherwise, reset approval to 0 and set to max allowance\n if (allowance \u003e 0) IERC20(token).safeDecreaseAllowance(spender, allowance);\n IERC20(token).safeIncreaseAllowance(spender, type(uint256).max);\n }\n\n /// @notice Returns the balance of the given token (or native ETH) for the given account.\n function universalBalanceOf(address token, address account) internal view returns (uint256) {\n if (token == ETH_ADDRESS) {\n return account.balance;\n } else {\n return IERC20(token).balanceOf(account);\n }\n }\n\n /// @dev Checks that token is a contract and not ETH_ADDRESS.\n function assertIsContract(address token) internal view {\n // Check that ETH_ADDRESS was not used (in case this is a predeploy on any of the chains)\n if (token == UniversalTokenLib.ETH_ADDRESS) revert TokenNotContract();\n // Check that token is not an EOA\n if (token.code.length == 0) revert TokenNotContract();\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/Admin.sol\n\ncontract Admin is IAdmin, AccessControlEnumerable {\n using UniversalTokenLib for address;\n\n bytes32 public constant RELAYER_ROLE = keccak256(\"RELAYER_ROLE\");\n bytes32 public constant REFUNDER_ROLE = keccak256(\"REFUNDER_ROLE\");\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n uint256 public constant FEE_BPS = 1e6;\n uint256 public constant FEE_RATE_MAX = 0.01e6; // max 1% on origin amount\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Chain gas amount to forward as rebate if requested\n uint256 public chainGasAmount;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n }\n\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n require(newFeeRate \u003c= FEE_RATE_MAX, \"newFeeRate \u003e max\");\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n token.universalTransfer(recipient, feeAmount);\n emit FeesSwept(token, recipient, feeAmount);\n }\n\n function setChainGasAmount(uint256 newChainGasAmount) external onlyRole(GOVERNOR_ROLE) {\n uint256 oldChainGasAmount = chainGasAmount;\n chainGasAmount = newChainGasAmount;\n emit ChainGasAmountUpdated(oldChainGasAmount, newChainGasAmount);\n }\n}\n\n// contracts/FastBridge.sol\n\ncontract FastBridge is IFastBridge, MulticallTarget, Admin {\n using SafeERC20 for IERC20;\n using UniversalTokenLib for address;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Delay for a transaction after which it could be permisionlessly refunded\n uint256 public constant REFUND_DELAY = 7 days;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeStatus) public bridgeStatuses;\n /// @notice Proof of relayed bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeProof) public bridgeProofs;\n /// @notice Whether bridge has been relayed on destination chain\n mapping(bytes32 =\u003e bool) public bridgeRelays;\n\n /// @dev to prevent replays\n uint256 public nonce;\n // @dev the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @notice Pulls a requested token from the user to the requested recipient.\n /// @dev Be careful of re-entrancy issues when msg.value \u003e 0 and recipient != address(this)\n function _pullToken(address recipient, address token, uint256 amount) internal returns (uint256 amountPulled) {\n if (token != UniversalTokenLib.ETH_ADDRESS) {\n token.assertIsContract();\n // Record token balance before transfer\n amountPulled = IERC20(token).balanceOf(recipient);\n // Token needs to be pulled only if msg.value is zero\n // This way user can specify WETH as the origin asset\n IERC20(token).safeTransferFrom(msg.sender, recipient, amount);\n // Use the difference between the recorded balance and the current balance as the amountPulled\n amountPulled = IERC20(token).balanceOf(recipient) - amountPulled;\n } else {\n // Otherwise, we need to check that ETH amount matches msg.value\n if (amount != msg.value) revert MsgValueIncorrect();\n // Transfer value to recipient if not this address\n if (recipient != address(this)) token.universalTransfer(recipient, amount);\n // We will forward msg.value in the external call later, if recipient is not this contract\n amountPulled = msg.value;\n }\n }\n\n /// @inheritdoc IFastBridge\n function getBridgeTransaction(bytes memory request) public pure returns (BridgeTransaction memory) {\n return abi.decode(request, (BridgeTransaction));\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n // check bridge params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n\n // transfer tokens to bridge contract\n // @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _pullToken(address(this), params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n\n // set status to requested\n bytes memory request = abi.encode(\n BridgeTransaction({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n sendChainGas: params.sendChainGas,\n deadline: params.deadline,\n nonce: nonce++ // increment nonce on every bridge\n })\n );\n bytes32 transactionId = keccak256(request);\n bridgeStatuses[transactionId] = BridgeStatus.REQUESTED;\n\n emit BridgeRequested(\n transactionId,\n params.sender,\n request,\n params.dstChainId,\n params.originToken,\n params.destToken,\n originAmount,\n params.destAmount,\n params.sendChainGas\n );\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes memory request) external payable onlyRole(RELAYER_ROLE) {\n bytes32 transactionId = keccak256(request);\n BridgeTransaction memory transaction = getBridgeTransaction(request);\n if (transaction.destChainId != uint32(block.chainid)) revert ChainIncorrect();\n\n // check haven't exceeded deadline for relay to happen\n if (block.timestamp \u003e transaction.deadline) revert DeadlineExceeded();\n\n // mark bridge transaction as relayed\n if (bridgeRelays[transactionId]) revert TransactionRelayed();\n bridgeRelays[transactionId] = true;\n\n // transfer tokens to recipient on destination chain and gas rebate if requested\n address to = transaction.destRecipient;\n address token = transaction.destToken;\n uint256 amount = transaction.destAmount;\n\n uint256 rebate = chainGasAmount;\n if (!transaction.sendChainGas) {\n // forward erc20\n rebate = 0;\n _pullToken(to, token, amount);\n } else if (token == UniversalTokenLib.ETH_ADDRESS) {\n // lump in gas rebate into amount in native gas token\n _pullToken(to, token, amount + rebate);\n } else {\n // forward erc20 then forward gas rebate in native gas token\n _pullToken(to, token, amount);\n _pullToken(to, UniversalTokenLib.ETH_ADDRESS, rebate);\n }\n\n emit BridgeRelayed(\n transactionId,\n msg.sender,\n to,\n transaction.originChainId,\n transaction.originToken,\n transaction.destToken,\n transaction.originAmount,\n transaction.destAmount,\n rebate\n );\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes memory request, bytes32 destTxHash) external onlyRole(RELAYER_ROLE) {\n bytes32 transactionId = keccak256(request);\n // update bridge tx status given proof provided\n if (bridgeStatuses[transactionId] != BridgeStatus.REQUESTED) revert StatusIncorrect();\n bridgeStatuses[transactionId] = BridgeStatus.RELAYER_PROVED;\n bridgeProofs[transactionId] = BridgeProof({timestamp: uint96(block.timestamp), relayer: msg.sender}); // overflow ok\n\n emit BridgeProofProvided(transactionId, msg.sender, destTxHash);\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint96(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint96).max but\n /// proof.timestamp \u003c type(uint96).max via unchecked statement\n /// @param proof The bridge proof\n /// @return delta Time delta since proof submitted\n function _timeSince(BridgeProof memory proof) internal view returns (uint256 delta) {\n unchecked {\n delta = uint96(block.timestamp) - proof.timestamp;\n }\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n if (bridgeStatuses[transactionId] != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n BridgeProof memory proof = bridgeProofs[transactionId];\n if (proof.relayer != relayer) revert SenderIncorrect();\n return _timeSince(proof) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes memory request, address to) external onlyRole(RELAYER_ROLE) {\n bytes32 transactionId = keccak256(request);\n BridgeTransaction memory transaction = getBridgeTransaction(request);\n\n // update bridge tx status if able to claim origin collateral\n if (bridgeStatuses[transactionId] != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n\n BridgeProof memory proof = bridgeProofs[transactionId];\n if (proof.relayer != msg.sender) revert SenderIncorrect();\n if (_timeSince(proof) \u003c= DISPUTE_PERIOD) revert DisputePeriodNotPassed();\n\n bridgeStatuses[transactionId] = BridgeStatus.RELAYER_CLAIMED;\n\n // update protocol fees if origin fee amount exists\n if (transaction.originFeeAmount \u003e 0) protocolFees[transaction.originToken] += transaction.originFeeAmount;\n\n // transfer origin collateral less fee to specified address\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositClaimed(transactionId, msg.sender, to, token, amount);\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n if (bridgeStatuses[transactionId] != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(bridgeProofs[transactionId]) \u003e DISPUTE_PERIOD) revert DisputePeriodPassed();\n\n // @dev relayer gets slashed effectively if dest relay has gone thru\n bridgeStatuses[transactionId] = BridgeStatus.REQUESTED;\n delete bridgeProofs[transactionId];\n\n emit BridgeProofDisputed(transactionId, msg.sender);\n }\n\n /// @inheritdoc IFastBridge\n function refund(bytes memory request) external {\n bytes32 transactionId = keccak256(request);\n BridgeTransaction memory transaction = getBridgeTransaction(request);\n\n if (hasRole(REFUNDER_ROLE, msg.sender)) {\n // Refunder can refund if deadline has passed\n if (block.timestamp \u003c= transaction.deadline) revert DeadlineNotExceeded();\n } else {\n // Permissionless refund is allowed after REFUND_DELAY\n if (block.timestamp \u003c= transaction.deadline + REFUND_DELAY) revert DeadlineNotExceeded();\n }\n\n // set status to refunded if still in requested state\n if (bridgeStatuses[transactionId] != BridgeStatus.REQUESTED) revert StatusIncorrect();\n bridgeStatuses[transactionId] = BridgeStatus.REFUNDED;\n\n // transfer origin collateral back to original sender\n address to = transaction.originSender;\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount + transaction.originFeeAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n }\n}\n\n// test/FastBridgeMock.sol\n\ncontract FastBridgeMock is IFastBridge, Admin {\n // @dev the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @dev to prevent replays\n uint256 public nonce;\n\n /// @notice We include an empty \"test\" function so that this contract does not appear in the coverage report.\n function testFastBridgeMock() external {}\n\n function getBridgeTransaction(bytes memory request) public pure returns (BridgeTransaction memory) {\n return abi.decode(request, (BridgeTransaction));\n }\n\n // used for testing in go.\n // see: https://ethereum.stackexchange.com/questions/21155/how-to-expose-enum-in-solidity-contract\n // make sure to update fastbridge/status.go if this changes\n // or underliyng enum changes.\n //\n // TODO: a foundry test should be added to ensure this is always in sync.\n function getEnumKeyByValue(FastBridge.BridgeStatus keyValue) public pure returns (string memory) {\n if (FastBridge.BridgeStatus.NULL == keyValue) return \"NULL\";\n if (FastBridge.BridgeStatus.REQUESTED == keyValue) return \"REQUESTED\";\n if (FastBridge.BridgeStatus.RELAYER_PROVED == keyValue) return \"RELAYER_PROVED\";\n if (FastBridge.BridgeStatus.RELAYER_CLAIMED == keyValue) return \"RELAYER_CLAIMED\";\n if (FastBridge.BridgeStatus.REFUNDED == keyValue) return \"REFUNDED\";\n return \"\";\n }\n\n function mockBridgeRequest(bytes32 transactionId, address sender, BridgeParams memory params) external {\n sender;\n uint256 originFeeAmount = (params.originAmount * protocolFeeRate) / FEE_BPS;\n params.originAmount -= originFeeAmount;\n\n bytes memory request = abi.encode(\n BridgeTransaction({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: params.originAmount, // includes relayer fee\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n sendChainGas: params.sendChainGas,\n deadline: params.deadline,\n nonce: nonce++ // increment nonce on every bridge\n })\n );\n\n emit BridgeRequested(\n transactionId,\n params.sender,\n request,\n params.dstChainId,\n params.originToken,\n params.destToken,\n params.originAmount,\n params.destAmount,\n params.sendChainGas\n );\n }\n\n function mockBridgeRequestRaw(bytes32 transactionId, address sender, bytes memory request) external {\n sender;\n BridgeTransaction memory transaction = getBridgeTransaction(request);\n emit BridgeRequested(\n transactionId,\n transaction.originSender,\n request,\n transaction.destChainId,\n transaction.originToken,\n transaction.destToken,\n transaction.originAmount,\n transaction.destAmount,\n transaction.sendChainGas\n );\n }\n\n function mockBridgeRelayer(\n bytes32 transactionId,\n address relayer,\n address to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n )\n external\n {\n emit BridgeRelayed(\n transactionId, relayer, to, originChainId, originToken, destToken, originAmount, destAmount, chainGasAmount\n );\n }\n\n function bridge(BridgeParams memory) external payable {\n revert(\"not implemented\");\n }\n\n function relay(bytes memory) external payable {\n revert(\"not implemented\");\n }\n\n function prove(bytes memory, bytes32) external pure {\n revert(\"not implemented\");\n }\n\n function canClaim(bytes32, address) external pure returns (bool) {\n revert(\"not implemented\");\n }\n\n function claim(bytes memory, address) external pure {\n revert(\"not implemented\");\n }\n\n function dispute(bytes32) external pure {\n revert(\"not implemented\");\n }\n\n function refund(bytes memory) external pure {\n revert(\"not implemented\");\n }\n}\n","language":"Solidity","languageVersion":"0.8.20","compilerVersion":"0.8.20","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"","srcMapRuntime":"","abiDefinition":[{"inputs":[],"name":"DOMAIN_SEPARATOR","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"nonces","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"permit","outputs":[],"stateMutability":"nonpayable","type":"function"}],"userDoc":{"kind":"user","methods":{},"version":1},"developerDoc":{"details":"Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in https://eips.ethereum.org/EIPS/eip-2612[EIP-2612]. Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't need to send a transaction, and thus is not required to hold Ether at all. ==== Security Considerations There are two important considerations concerning the use of `permit`. The first is that a valid permit signature expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be considered as an intention to spend the allowance in any specific way. The second is that because permits have built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be generally recommended is: ```solidity function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public { try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {} doThing(..., value); } function doThing(..., uint256 value) public { token.safeTransferFrom(msg.sender, address(this), value); ... } ``` Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also {SafeERC20-safeTransferFrom}). Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so contracts should have entry points that don't rely on permit.","kind":"dev","methods":{"DOMAIN_SEPARATOR()":{"details":"Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}."},"nonces(address)":{"details":"Returns the current nonce for `owner`. This value must be included whenever a signature is generated for {permit}. Every successful call to {permit} increases ``owner``'s nonce by one. This prevents a signature from being used multiple times."},"permit(address,address,uint256,uint256,uint8,bytes32,bytes32)":{"details":"Sets `value` as the allowance of `spender` over ``owner``'s tokens, given ``owner``'s signed approval. IMPORTANT: The same issues {IERC20-approve} has related to transaction ordering also apply here. Emits an {Approval} event. Requirements: - `spender` cannot be the zero address. - `deadline` must be a timestamp in the future. - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner` over the EIP712-formatted function arguments. - the signature must use ``owner``'s current nonce (see {nonces}). For more information on the signature format, see the https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP section]. CAUTION: See Security Considerations above."}},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.20+commit.a1b79de6\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[],\"name\":\"DOMAIN_SEPARATOR\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"}],\"name\":\"nonces\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"},{\"internalType\":\"uint8\",\"name\":\"v\",\"type\":\"uint8\"},{\"internalType\":\"bytes32\",\"name\":\"r\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"s\",\"type\":\"bytes32\"}],\"name\":\"permit\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"details\":\"Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in https://eips.ethereum.org/EIPS/eip-2612[EIP-2612]. Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't need to send a transaction, and thus is not required to hold Ether at all. ==== Security Considerations There are two important considerations concerning the use of `permit`. The first is that a valid permit signature expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be considered as an intention to spend the allowance in any specific way. The second is that because permits have built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be generally recommended is: ```solidity function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public { try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {} doThing(..., value); } function doThing(..., uint256 value) public { token.safeTransferFrom(msg.sender, address(this), value); ... } ``` Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also {SafeERC20-safeTransferFrom}). Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so contracts should have entry points that don't rely on permit.\",\"kind\":\"dev\",\"methods\":{\"DOMAIN_SEPARATOR()\":{\"details\":\"Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\"},\"nonces(address)\":{\"details\":\"Returns the current nonce for `owner`. This value must be included whenever a signature is generated for {permit}. Every successful call to {permit} increases ``owner``'s nonce by one. This prevents a signature from being used multiple times.\"},\"permit(address,address,uint256,uint256,uint8,bytes32,bytes32)\":{\"details\":\"Sets `value` as the allowance of `spender` over ``owner``'s tokens, given ``owner``'s signed approval. IMPORTANT: The same issues {IERC20-approve} has related to transaction ordering also apply here. Emits an {Approval} event. Requirements: - `spender` cannot be the zero address. - `deadline` must be a timestamp in the future. - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner` over the EIP712-formatted function arguments. - the signature must use ``owner``'s current nonce (see {nonces}). For more information on the signature format, see the https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP section]. CAUTION: See Security Considerations above.\"}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeMock.sol\":\"IERC20Permit\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeMock.sol\":{\"keccak256\":\"0xf2751f52f8216801d500da7464ad01f3c23a8286e155e2dcba6d21d6e7fd95a0\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://85d2edab24ebe321043d2b88038437e8f443a0ef26fa2139c72dcc2bc7fbc602\",\"dweb:/ipfs/QmcULiFPFJzFDT4aupVSDreXz8uHxcABb5nxpAG4zYzfNN\"]}},\"version\":1}"},"hashes":{"DOMAIN_SEPARATOR()":"3644e515","nonces(address)":"7ecebe00","permit(address,address,uint256,uint256,uint8,bytes32,bytes32)":"d505accf"}},"solidity/FastBridgeMock.sol:IFastBridge":{"code":"0x","runtime-code":"0x","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.20 ^0.8.20 ^0.8.4;\n\n// contracts/interfaces/IAdmin.sol\n\ninterface IAdmin {\n // ============ Events ============\n\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n event ChainGasAmountUpdated(uint256 oldChainGasAmount, uint256 newChainGasAmount);\n\n // ============ Methods ============\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n\n function setChainGasAmount(uint256 newChainGasAmount) external;\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IMulticallTarget.sol\n\n/// @notice Interface for a contract that can be called multiple times by the same caller. Inspired by MulticallV3:\n/// https://github.com/mds1/multicall/blob/master/src/Multicall3.sol\ninterface IMulticallTarget {\n struct Result {\n bool success;\n bytes returnData;\n }\n\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external;\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results);\n}\n\n// contracts/libs/Errors.sol\n\nerror DeadlineExceeded();\nerror DeadlineNotExceeded();\nerror DeadlineTooShort();\nerror InsufficientOutputAmount();\n\nerror MsgValueIncorrect();\nerror PoolNotFound();\nerror TokenAddressMismatch();\nerror TokenNotContract();\nerror TokenNotETH();\nerror TokensIdentical();\n\nerror ChainIncorrect();\nerror AmountIncorrect();\nerror ZeroAddress();\n\nerror DisputePeriodNotPassed();\nerror DisputePeriodPassed();\nerror SenderIncorrect();\nerror StatusIncorrect();\nerror TransactionIdIncorrect();\nerror TransactionRelayed();\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// contracts/utils/MulticallTarget.sol\n\n// solhint-disable avoid-low-level-calls\n/// @notice Template for a contract that supports batched calls (preserving the msg.sender).\n/// Only calls with zero msg.value could be batched.\nabstract contract MulticallTarget is IMulticallTarget {\n error MulticallTarget__UndeterminedRevert();\n\n /// @notice Perform a batched call to this contract, preserving the msg.sender.\n /// The return data from each call is discarded.\n /// @dev The method is non-payable, so only calls with `msg.value == 0` could be batched.\n /// It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag.\n /// Otherwise, the whole batch call will be reverted with the original revert reason.\n /// @param data List of abi-encoded calldata for the calls to perform.\n /// @param ignoreReverts Whether to ignore the revert errors from the calls.\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external {\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\n if (!success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(result);\n }\n }\n }\n\n /// @notice Perform a batched call to this contract, preserving the msg.sender.\n /// The return data from each call is preserved.\n /// @dev The method is non-payable, so only calls with `msg.value == 0` could be batched.\n /// It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag.\n /// Otherwise, the whole batch call will be reverted with the original revert reason.\n /// @param data List of abi-encoded calldata for the calls to perform.\n /// @param ignoreReverts Whether to ignore the revert errors from the calls.\n /// @return results List of results from the calls: `(success, returnData)`.\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results)\n {\n results = new Result[](data.length);\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (results[i].success, results[i].returnData) = address(this).delegatecall(data[i]);\n if (!results[i].success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(results[i].returnData);\n }\n }\n }\n\n /// @dev Bubbles the revert message from the underlying call.\n /// Note: preserves the same custom error or revert string, if one was used.\n /// Source: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v5.0.2/contracts/utils/Address.sol#L143-L158\n function _bubbleRevert(bytes memory returnData) internal pure {\n // Look for revert reason and bubble it up if present\n if (returnData.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n // solhint-disable-next-line no-inline-assembly\n assembly {\n let returndata_size := mload(returnData)\n revert(add(32, returnData), returndata_size)\n }\n } else {\n revert MulticallTarget__UndeterminedRevert();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// contracts/libs/UniversalToken.sol\n\nlibrary UniversalTokenLib {\n using SafeERC20 for IERC20;\n\n address internal constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Transfers tokens to the given account. Reverts if transfer is not successful.\n /// @dev This might trigger fallback, if ETH is transferred to the contract.\n /// Make sure this can not lead to reentrancy attacks.\n function universalTransfer(address token, address to, uint256 value) internal {\n // Don't do anything, if need to send tokens to this address\n if (to == address(this)) return;\n // Don't do anything, if trying to send zero value\n if (value == 0) return;\n if (token == ETH_ADDRESS) {\n /// @dev Note: this can potentially lead to executing code in `to`.\n // solhint-disable-next-line avoid-low-level-calls\n (bool success,) = to.call{value: value}(\"\");\n require(success, \"ETH transfer failed\");\n } else {\n IERC20(token).safeTransfer(to, value);\n }\n }\n\n /// @notice Issues an infinite allowance to the spender, if the current allowance is insufficient\n /// to spend the given amount.\n function universalApproveInfinity(address token, address spender, uint256 amountToSpend) internal {\n // ETH Chad doesn't require your approval\n if (token == ETH_ADDRESS) return;\n // No-op if allowance is already sufficient\n uint256 allowance = IERC20(token).allowance(address(this), spender);\n if (allowance \u003e= amountToSpend) return;\n // Otherwise, reset approval to 0 and set to max allowance\n if (allowance \u003e 0) IERC20(token).safeDecreaseAllowance(spender, allowance);\n IERC20(token).safeIncreaseAllowance(spender, type(uint256).max);\n }\n\n /// @notice Returns the balance of the given token (or native ETH) for the given account.\n function universalBalanceOf(address token, address account) internal view returns (uint256) {\n if (token == ETH_ADDRESS) {\n return account.balance;\n } else {\n return IERC20(token).balanceOf(account);\n }\n }\n\n /// @dev Checks that token is a contract and not ETH_ADDRESS.\n function assertIsContract(address token) internal view {\n // Check that ETH_ADDRESS was not used (in case this is a predeploy on any of the chains)\n if (token == UniversalTokenLib.ETH_ADDRESS) revert TokenNotContract();\n // Check that token is not an EOA\n if (token.code.length == 0) revert TokenNotContract();\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/Admin.sol\n\ncontract Admin is IAdmin, AccessControlEnumerable {\n using UniversalTokenLib for address;\n\n bytes32 public constant RELAYER_ROLE = keccak256(\"RELAYER_ROLE\");\n bytes32 public constant REFUNDER_ROLE = keccak256(\"REFUNDER_ROLE\");\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n uint256 public constant FEE_BPS = 1e6;\n uint256 public constant FEE_RATE_MAX = 0.01e6; // max 1% on origin amount\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Chain gas amount to forward as rebate if requested\n uint256 public chainGasAmount;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n }\n\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n require(newFeeRate \u003c= FEE_RATE_MAX, \"newFeeRate \u003e max\");\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n token.universalTransfer(recipient, feeAmount);\n emit FeesSwept(token, recipient, feeAmount);\n }\n\n function setChainGasAmount(uint256 newChainGasAmount) external onlyRole(GOVERNOR_ROLE) {\n uint256 oldChainGasAmount = chainGasAmount;\n chainGasAmount = newChainGasAmount;\n emit ChainGasAmountUpdated(oldChainGasAmount, newChainGasAmount);\n }\n}\n\n// contracts/FastBridge.sol\n\ncontract FastBridge is IFastBridge, MulticallTarget, Admin {\n using SafeERC20 for IERC20;\n using UniversalTokenLib for address;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Delay for a transaction after which it could be permisionlessly refunded\n uint256 public constant REFUND_DELAY = 7 days;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeStatus) public bridgeStatuses;\n /// @notice Proof of relayed bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeProof) public bridgeProofs;\n /// @notice Whether bridge has been relayed on destination chain\n mapping(bytes32 =\u003e bool) public bridgeRelays;\n\n /// @dev to prevent replays\n uint256 public nonce;\n // @dev the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @notice Pulls a requested token from the user to the requested recipient.\n /// @dev Be careful of re-entrancy issues when msg.value \u003e 0 and recipient != address(this)\n function _pullToken(address recipient, address token, uint256 amount) internal returns (uint256 amountPulled) {\n if (token != UniversalTokenLib.ETH_ADDRESS) {\n token.assertIsContract();\n // Record token balance before transfer\n amountPulled = IERC20(token).balanceOf(recipient);\n // Token needs to be pulled only if msg.value is zero\n // This way user can specify WETH as the origin asset\n IERC20(token).safeTransferFrom(msg.sender, recipient, amount);\n // Use the difference between the recorded balance and the current balance as the amountPulled\n amountPulled = IERC20(token).balanceOf(recipient) - amountPulled;\n } else {\n // Otherwise, we need to check that ETH amount matches msg.value\n if (amount != msg.value) revert MsgValueIncorrect();\n // Transfer value to recipient if not this address\n if (recipient != address(this)) token.universalTransfer(recipient, amount);\n // We will forward msg.value in the external call later, if recipient is not this contract\n amountPulled = msg.value;\n }\n }\n\n /// @inheritdoc IFastBridge\n function getBridgeTransaction(bytes memory request) public pure returns (BridgeTransaction memory) {\n return abi.decode(request, (BridgeTransaction));\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n // check bridge params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n\n // transfer tokens to bridge contract\n // @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _pullToken(address(this), params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n\n // set status to requested\n bytes memory request = abi.encode(\n BridgeTransaction({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n sendChainGas: params.sendChainGas,\n deadline: params.deadline,\n nonce: nonce++ // increment nonce on every bridge\n })\n );\n bytes32 transactionId = keccak256(request);\n bridgeStatuses[transactionId] = BridgeStatus.REQUESTED;\n\n emit BridgeRequested(\n transactionId,\n params.sender,\n request,\n params.dstChainId,\n params.originToken,\n params.destToken,\n originAmount,\n params.destAmount,\n params.sendChainGas\n );\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes memory request) external payable onlyRole(RELAYER_ROLE) {\n bytes32 transactionId = keccak256(request);\n BridgeTransaction memory transaction = getBridgeTransaction(request);\n if (transaction.destChainId != uint32(block.chainid)) revert ChainIncorrect();\n\n // check haven't exceeded deadline for relay to happen\n if (block.timestamp \u003e transaction.deadline) revert DeadlineExceeded();\n\n // mark bridge transaction as relayed\n if (bridgeRelays[transactionId]) revert TransactionRelayed();\n bridgeRelays[transactionId] = true;\n\n // transfer tokens to recipient on destination chain and gas rebate if requested\n address to = transaction.destRecipient;\n address token = transaction.destToken;\n uint256 amount = transaction.destAmount;\n\n uint256 rebate = chainGasAmount;\n if (!transaction.sendChainGas) {\n // forward erc20\n rebate = 0;\n _pullToken(to, token, amount);\n } else if (token == UniversalTokenLib.ETH_ADDRESS) {\n // lump in gas rebate into amount in native gas token\n _pullToken(to, token, amount + rebate);\n } else {\n // forward erc20 then forward gas rebate in native gas token\n _pullToken(to, token, amount);\n _pullToken(to, UniversalTokenLib.ETH_ADDRESS, rebate);\n }\n\n emit BridgeRelayed(\n transactionId,\n msg.sender,\n to,\n transaction.originChainId,\n transaction.originToken,\n transaction.destToken,\n transaction.originAmount,\n transaction.destAmount,\n rebate\n );\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes memory request, bytes32 destTxHash) external onlyRole(RELAYER_ROLE) {\n bytes32 transactionId = keccak256(request);\n // update bridge tx status given proof provided\n if (bridgeStatuses[transactionId] != BridgeStatus.REQUESTED) revert StatusIncorrect();\n bridgeStatuses[transactionId] = BridgeStatus.RELAYER_PROVED;\n bridgeProofs[transactionId] = BridgeProof({timestamp: uint96(block.timestamp), relayer: msg.sender}); // overflow ok\n\n emit BridgeProofProvided(transactionId, msg.sender, destTxHash);\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint96(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint96).max but\n /// proof.timestamp \u003c type(uint96).max via unchecked statement\n /// @param proof The bridge proof\n /// @return delta Time delta since proof submitted\n function _timeSince(BridgeProof memory proof) internal view returns (uint256 delta) {\n unchecked {\n delta = uint96(block.timestamp) - proof.timestamp;\n }\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n if (bridgeStatuses[transactionId] != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n BridgeProof memory proof = bridgeProofs[transactionId];\n if (proof.relayer != relayer) revert SenderIncorrect();\n return _timeSince(proof) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes memory request, address to) external onlyRole(RELAYER_ROLE) {\n bytes32 transactionId = keccak256(request);\n BridgeTransaction memory transaction = getBridgeTransaction(request);\n\n // update bridge tx status if able to claim origin collateral\n if (bridgeStatuses[transactionId] != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n\n BridgeProof memory proof = bridgeProofs[transactionId];\n if (proof.relayer != msg.sender) revert SenderIncorrect();\n if (_timeSince(proof) \u003c= DISPUTE_PERIOD) revert DisputePeriodNotPassed();\n\n bridgeStatuses[transactionId] = BridgeStatus.RELAYER_CLAIMED;\n\n // update protocol fees if origin fee amount exists\n if (transaction.originFeeAmount \u003e 0) protocolFees[transaction.originToken] += transaction.originFeeAmount;\n\n // transfer origin collateral less fee to specified address\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositClaimed(transactionId, msg.sender, to, token, amount);\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n if (bridgeStatuses[transactionId] != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(bridgeProofs[transactionId]) \u003e DISPUTE_PERIOD) revert DisputePeriodPassed();\n\n // @dev relayer gets slashed effectively if dest relay has gone thru\n bridgeStatuses[transactionId] = BridgeStatus.REQUESTED;\n delete bridgeProofs[transactionId];\n\n emit BridgeProofDisputed(transactionId, msg.sender);\n }\n\n /// @inheritdoc IFastBridge\n function refund(bytes memory request) external {\n bytes32 transactionId = keccak256(request);\n BridgeTransaction memory transaction = getBridgeTransaction(request);\n\n if (hasRole(REFUNDER_ROLE, msg.sender)) {\n // Refunder can refund if deadline has passed\n if (block.timestamp \u003c= transaction.deadline) revert DeadlineNotExceeded();\n } else {\n // Permissionless refund is allowed after REFUND_DELAY\n if (block.timestamp \u003c= transaction.deadline + REFUND_DELAY) revert DeadlineNotExceeded();\n }\n\n // set status to refunded if still in requested state\n if (bridgeStatuses[transactionId] != BridgeStatus.REQUESTED) revert StatusIncorrect();\n bridgeStatuses[transactionId] = BridgeStatus.REFUNDED;\n\n // transfer origin collateral back to original sender\n address to = transaction.originSender;\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount + transaction.originFeeAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n }\n}\n\n// test/FastBridgeMock.sol\n\ncontract FastBridgeMock is IFastBridge, Admin {\n // @dev the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @dev to prevent replays\n uint256 public nonce;\n\n /// @notice We include an empty \"test\" function so that this contract does not appear in the coverage report.\n function testFastBridgeMock() external {}\n\n function getBridgeTransaction(bytes memory request) public pure returns (BridgeTransaction memory) {\n return abi.decode(request, (BridgeTransaction));\n }\n\n // used for testing in go.\n // see: https://ethereum.stackexchange.com/questions/21155/how-to-expose-enum-in-solidity-contract\n // make sure to update fastbridge/status.go if this changes\n // or underliyng enum changes.\n //\n // TODO: a foundry test should be added to ensure this is always in sync.\n function getEnumKeyByValue(FastBridge.BridgeStatus keyValue) public pure returns (string memory) {\n if (FastBridge.BridgeStatus.NULL == keyValue) return \"NULL\";\n if (FastBridge.BridgeStatus.REQUESTED == keyValue) return \"REQUESTED\";\n if (FastBridge.BridgeStatus.RELAYER_PROVED == keyValue) return \"RELAYER_PROVED\";\n if (FastBridge.BridgeStatus.RELAYER_CLAIMED == keyValue) return \"RELAYER_CLAIMED\";\n if (FastBridge.BridgeStatus.REFUNDED == keyValue) return \"REFUNDED\";\n return \"\";\n }\n\n function mockBridgeRequest(bytes32 transactionId, address sender, BridgeParams memory params) external {\n sender;\n uint256 originFeeAmount = (params.originAmount * protocolFeeRate) / FEE_BPS;\n params.originAmount -= originFeeAmount;\n\n bytes memory request = abi.encode(\n BridgeTransaction({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: params.originAmount, // includes relayer fee\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n sendChainGas: params.sendChainGas,\n deadline: params.deadline,\n nonce: nonce++ // increment nonce on every bridge\n })\n );\n\n emit BridgeRequested(\n transactionId,\n params.sender,\n request,\n params.dstChainId,\n params.originToken,\n params.destToken,\n params.originAmount,\n params.destAmount,\n params.sendChainGas\n );\n }\n\n function mockBridgeRequestRaw(bytes32 transactionId, address sender, bytes memory request) external {\n sender;\n BridgeTransaction memory transaction = getBridgeTransaction(request);\n emit BridgeRequested(\n transactionId,\n transaction.originSender,\n request,\n transaction.destChainId,\n transaction.originToken,\n transaction.destToken,\n transaction.originAmount,\n transaction.destAmount,\n transaction.sendChainGas\n );\n }\n\n function mockBridgeRelayer(\n bytes32 transactionId,\n address relayer,\n address to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n )\n external\n {\n emit BridgeRelayed(\n transactionId, relayer, to, originChainId, originToken, destToken, originAmount, destAmount, chainGasAmount\n );\n }\n\n function bridge(BridgeParams memory) external payable {\n revert(\"not implemented\");\n }\n\n function relay(bytes memory) external payable {\n revert(\"not implemented\");\n }\n\n function prove(bytes memory, bytes32) external pure {\n revert(\"not implemented\");\n }\n\n function canClaim(bytes32, address) external pure returns (bool) {\n revert(\"not implemented\");\n }\n\n function claim(bytes memory, address) external pure {\n revert(\"not implemented\");\n }\n\n function dispute(bytes32) external pure {\n revert(\"not implemented\");\n }\n\n function refund(bytes memory) external pure {\n revert(\"not implemented\");\n }\n}\n","language":"Solidity","languageVersion":"0.8.20","compilerVersion":"0.8.20","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"","srcMapRuntime":"","abiDefinition":[{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"relayer","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"BridgeDepositClaimed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"BridgeDepositRefunded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"relayer","type":"address"}],"name":"BridgeProofDisputed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"relayer","type":"address"},{"indexed":false,"internalType":"bytes32","name":"transactionHash","type":"bytes32"}],"name":"BridgeProofProvided","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"relayer","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint32","name":"originChainId","type":"uint32"},{"indexed":false,"internalType":"address","name":"originToken","type":"address"},{"indexed":false,"internalType":"address","name":"destToken","type":"address"},{"indexed":false,"internalType":"uint256","name":"originAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"destAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"chainGasAmount","type":"uint256"}],"name":"BridgeRelayed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"bytes","name":"request","type":"bytes"},{"indexed":false,"internalType":"uint32","name":"destChainId","type":"uint32"},{"indexed":false,"internalType":"address","name":"originToken","type":"address"},{"indexed":false,"internalType":"address","name":"destToken","type":"address"},{"indexed":false,"internalType":"uint256","name":"originAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"destAmount","type":"uint256"},{"indexed":false,"internalType":"bool","name":"sendChainGas","type":"bool"}],"name":"BridgeRequested","type":"event"},{"inputs":[{"components":[{"internalType":"uint32","name":"dstChainId","type":"uint32"},{"internalType":"address","name":"sender","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"address","name":"originToken","type":"address"},{"internalType":"address","name":"destToken","type":"address"},{"internalType":"uint256","name":"originAmount","type":"uint256"},{"internalType":"uint256","name":"destAmount","type":"uint256"},{"internalType":"bool","name":"sendChainGas","type":"bool"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"internalType":"struct IFastBridge.BridgeParams","name":"params","type":"tuple"}],"name":"bridge","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"internalType":"address","name":"relayer","type":"address"}],"name":"canClaim","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"},{"internalType":"address","name":"to","type":"address"}],"name":"claim","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"transactionId","type":"bytes32"}],"name":"dispute","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"}],"name":"getBridgeTransaction","outputs":[{"components":[{"internalType":"uint32","name":"originChainId","type":"uint32"},{"internalType":"uint32","name":"destChainId","type":"uint32"},{"internalType":"address","name":"originSender","type":"address"},{"internalType":"address","name":"destRecipient","type":"address"},{"internalType":"address","name":"originToken","type":"address"},{"internalType":"address","name":"destToken","type":"address"},{"internalType":"uint256","name":"originAmount","type":"uint256"},{"internalType":"uint256","name":"destAmount","type":"uint256"},{"internalType":"uint256","name":"originFeeAmount","type":"uint256"},{"internalType":"bool","name":"sendChainGas","type":"bool"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint256","name":"nonce","type":"uint256"}],"internalType":"struct IFastBridge.BridgeTransaction","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"},{"internalType":"bytes32","name":"destTxHash","type":"bytes32"}],"name":"prove","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"}],"name":"refund","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"}],"name":"relay","outputs":[],"stateMutability":"payable","type":"function"}],"userDoc":{"kind":"user","methods":{"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256))":{"notice":"Initiates bridge on origin chain to be relayed by off-chain relayer"},"canClaim(bytes32,address)":{"notice":"Checks if the dispute period has passed so bridge deposit can be claimed"},"claim(bytes,address)":{"notice":"Completes bridge transaction on origin chain by claiming originally deposited capital"},"dispute(bytes32)":{"notice":"Disputes an outstanding proof in case relayer provided dest chain tx is invalid"},"getBridgeTransaction(bytes)":{"notice":"Decodes bridge request into a bridge transaction"},"prove(bytes,bytes32)":{"notice":"Provides proof on origin side that relayer provided funds on destination side of bridge transaction"},"refund(bytes)":{"notice":"Refunds an outstanding bridge transaction in case optimistic bridging failed"},"relay(bytes)":{"notice":"Relays destination side of bridge transaction by off-chain relayer"}},"version":1},"developerDoc":{"kind":"dev","methods":{"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256))":{"params":{"params":"The parameters required to bridge"}},"canClaim(bytes32,address)":{"params":{"relayer":"The address of the relayer attempting to claim","transactionId":"The transaction id associated with the encoded bridge transaction to check"}},"claim(bytes,address)":{"params":{"request":"The encoded bridge transaction to claim on origin chain","to":"The recipient address of the funds"}},"dispute(bytes32)":{"params":{"transactionId":"The transaction id associated with the encoded bridge transaction to dispute"}},"getBridgeTransaction(bytes)":{"params":{"request":"The bridge request to decode"}},"prove(bytes,bytes32)":{"params":{"destTxHash":"The destination tx hash proving bridge transaction was relayed","request":"The encoded bridge transaction to prove on origin chain"}},"refund(bytes)":{"params":{"request":"The encoded bridge transaction to refund"}},"relay(bytes)":{"params":{"request":"The encoded bridge transaction to relay on destination chain"}}},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.20+commit.a1b79de6\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"BridgeDepositClaimed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"BridgeDepositRefunded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"name\":\"BridgeProofDisputed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"transactionHash\",\"type\":\"bytes32\"}],\"name\":\"BridgeProofProvided\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"originChainId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"chainGasAmount\",\"type\":\"uint256\"}],\"name\":\"BridgeRelayed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"destChainId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"sendChainGas\",\"type\":\"bool\"}],\"name\":\"BridgeRequested\",\"type\":\"event\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"dstChainId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"sendChainGas\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"}],\"internalType\":\"struct IFastBridge.BridgeParams\",\"name\":\"params\",\"type\":\"tuple\"}],\"name\":\"bridge\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"name\":\"canClaim\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"claim\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"}],\"name\":\"dispute\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"getBridgeTransaction\",\"outputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"originChainId\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"destChainId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"originSender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destRecipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"originFeeAmount\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"sendChainGas\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"}],\"internalType\":\"struct IFastBridge.BridgeTransaction\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"},{\"internalType\":\"bytes32\",\"name\":\"destTxHash\",\"type\":\"bytes32\"}],\"name\":\"prove\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"refund\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"relay\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{\"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256))\":{\"params\":{\"params\":\"The parameters required to bridge\"}},\"canClaim(bytes32,address)\":{\"params\":{\"relayer\":\"The address of the relayer attempting to claim\",\"transactionId\":\"The transaction id associated with the encoded bridge transaction to check\"}},\"claim(bytes,address)\":{\"params\":{\"request\":\"The encoded bridge transaction to claim on origin chain\",\"to\":\"The recipient address of the funds\"}},\"dispute(bytes32)\":{\"params\":{\"transactionId\":\"The transaction id associated with the encoded bridge transaction to dispute\"}},\"getBridgeTransaction(bytes)\":{\"params\":{\"request\":\"The bridge request to decode\"}},\"prove(bytes,bytes32)\":{\"params\":{\"destTxHash\":\"The destination tx hash proving bridge transaction was relayed\",\"request\":\"The encoded bridge transaction to prove on origin chain\"}},\"refund(bytes)\":{\"params\":{\"request\":\"The encoded bridge transaction to refund\"}},\"relay(bytes)\":{\"params\":{\"request\":\"The encoded bridge transaction to relay on destination chain\"}}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256))\":{\"notice\":\"Initiates bridge on origin chain to be relayed by off-chain relayer\"},\"canClaim(bytes32,address)\":{\"notice\":\"Checks if the dispute period has passed so bridge deposit can be claimed\"},\"claim(bytes,address)\":{\"notice\":\"Completes bridge transaction on origin chain by claiming originally deposited capital\"},\"dispute(bytes32)\":{\"notice\":\"Disputes an outstanding proof in case relayer provided dest chain tx is invalid\"},\"getBridgeTransaction(bytes)\":{\"notice\":\"Decodes bridge request into a bridge transaction\"},\"prove(bytes,bytes32)\":{\"notice\":\"Provides proof on origin side that relayer provided funds on destination side of bridge transaction\"},\"refund(bytes)\":{\"notice\":\"Refunds an outstanding bridge transaction in case optimistic bridging failed\"},\"relay(bytes)\":{\"notice\":\"Relays destination side of bridge transaction by off-chain relayer\"}},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeMock.sol\":\"IFastBridge\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeMock.sol\":{\"keccak256\":\"0xf2751f52f8216801d500da7464ad01f3c23a8286e155e2dcba6d21d6e7fd95a0\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://85d2edab24ebe321043d2b88038437e8f443a0ef26fa2139c72dcc2bc7fbc602\",\"dweb:/ipfs/QmcULiFPFJzFDT4aupVSDreXz8uHxcABb5nxpAG4zYzfNN\"]}},\"version\":1}"},"hashes":{"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256))":"45851694","canClaim(bytes32,address)":"aa9641ab","claim(bytes,address)":"41fcb612","dispute(bytes32)":"add98c70","getBridgeTransaction(bytes)":"ac11fb1a","prove(bytes,bytes32)":"886d36ff","refund(bytes)":"5eb7d946","relay(bytes)":"8f0d6f17"}},"solidity/FastBridgeMock.sol:IMulticallTarget":{"code":"0x","runtime-code":"0x","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.20 ^0.8.20 ^0.8.4;\n\n// contracts/interfaces/IAdmin.sol\n\ninterface IAdmin {\n // ============ Events ============\n\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n event ChainGasAmountUpdated(uint256 oldChainGasAmount, uint256 newChainGasAmount);\n\n // ============ Methods ============\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n\n function setChainGasAmount(uint256 newChainGasAmount) external;\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IMulticallTarget.sol\n\n/// @notice Interface for a contract that can be called multiple times by the same caller. Inspired by MulticallV3:\n/// https://github.com/mds1/multicall/blob/master/src/Multicall3.sol\ninterface IMulticallTarget {\n struct Result {\n bool success;\n bytes returnData;\n }\n\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external;\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results);\n}\n\n// contracts/libs/Errors.sol\n\nerror DeadlineExceeded();\nerror DeadlineNotExceeded();\nerror DeadlineTooShort();\nerror InsufficientOutputAmount();\n\nerror MsgValueIncorrect();\nerror PoolNotFound();\nerror TokenAddressMismatch();\nerror TokenNotContract();\nerror TokenNotETH();\nerror TokensIdentical();\n\nerror ChainIncorrect();\nerror AmountIncorrect();\nerror ZeroAddress();\n\nerror DisputePeriodNotPassed();\nerror DisputePeriodPassed();\nerror SenderIncorrect();\nerror StatusIncorrect();\nerror TransactionIdIncorrect();\nerror TransactionRelayed();\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// contracts/utils/MulticallTarget.sol\n\n// solhint-disable avoid-low-level-calls\n/// @notice Template for a contract that supports batched calls (preserving the msg.sender).\n/// Only calls with zero msg.value could be batched.\nabstract contract MulticallTarget is IMulticallTarget {\n error MulticallTarget__UndeterminedRevert();\n\n /// @notice Perform a batched call to this contract, preserving the msg.sender.\n /// The return data from each call is discarded.\n /// @dev The method is non-payable, so only calls with `msg.value == 0` could be batched.\n /// It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag.\n /// Otherwise, the whole batch call will be reverted with the original revert reason.\n /// @param data List of abi-encoded calldata for the calls to perform.\n /// @param ignoreReverts Whether to ignore the revert errors from the calls.\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external {\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\n if (!success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(result);\n }\n }\n }\n\n /// @notice Perform a batched call to this contract, preserving the msg.sender.\n /// The return data from each call is preserved.\n /// @dev The method is non-payable, so only calls with `msg.value == 0` could be batched.\n /// It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag.\n /// Otherwise, the whole batch call will be reverted with the original revert reason.\n /// @param data List of abi-encoded calldata for the calls to perform.\n /// @param ignoreReverts Whether to ignore the revert errors from the calls.\n /// @return results List of results from the calls: `(success, returnData)`.\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results)\n {\n results = new Result[](data.length);\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (results[i].success, results[i].returnData) = address(this).delegatecall(data[i]);\n if (!results[i].success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(results[i].returnData);\n }\n }\n }\n\n /// @dev Bubbles the revert message from the underlying call.\n /// Note: preserves the same custom error or revert string, if one was used.\n /// Source: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v5.0.2/contracts/utils/Address.sol#L143-L158\n function _bubbleRevert(bytes memory returnData) internal pure {\n // Look for revert reason and bubble it up if present\n if (returnData.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n // solhint-disable-next-line no-inline-assembly\n assembly {\n let returndata_size := mload(returnData)\n revert(add(32, returnData), returndata_size)\n }\n } else {\n revert MulticallTarget__UndeterminedRevert();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// contracts/libs/UniversalToken.sol\n\nlibrary UniversalTokenLib {\n using SafeERC20 for IERC20;\n\n address internal constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Transfers tokens to the given account. Reverts if transfer is not successful.\n /// @dev This might trigger fallback, if ETH is transferred to the contract.\n /// Make sure this can not lead to reentrancy attacks.\n function universalTransfer(address token, address to, uint256 value) internal {\n // Don't do anything, if need to send tokens to this address\n if (to == address(this)) return;\n // Don't do anything, if trying to send zero value\n if (value == 0) return;\n if (token == ETH_ADDRESS) {\n /// @dev Note: this can potentially lead to executing code in `to`.\n // solhint-disable-next-line avoid-low-level-calls\n (bool success,) = to.call{value: value}(\"\");\n require(success, \"ETH transfer failed\");\n } else {\n IERC20(token).safeTransfer(to, value);\n }\n }\n\n /// @notice Issues an infinite allowance to the spender, if the current allowance is insufficient\n /// to spend the given amount.\n function universalApproveInfinity(address token, address spender, uint256 amountToSpend) internal {\n // ETH Chad doesn't require your approval\n if (token == ETH_ADDRESS) return;\n // No-op if allowance is already sufficient\n uint256 allowance = IERC20(token).allowance(address(this), spender);\n if (allowance \u003e= amountToSpend) return;\n // Otherwise, reset approval to 0 and set to max allowance\n if (allowance \u003e 0) IERC20(token).safeDecreaseAllowance(spender, allowance);\n IERC20(token).safeIncreaseAllowance(spender, type(uint256).max);\n }\n\n /// @notice Returns the balance of the given token (or native ETH) for the given account.\n function universalBalanceOf(address token, address account) internal view returns (uint256) {\n if (token == ETH_ADDRESS) {\n return account.balance;\n } else {\n return IERC20(token).balanceOf(account);\n }\n }\n\n /// @dev Checks that token is a contract and not ETH_ADDRESS.\n function assertIsContract(address token) internal view {\n // Check that ETH_ADDRESS was not used (in case this is a predeploy on any of the chains)\n if (token == UniversalTokenLib.ETH_ADDRESS) revert TokenNotContract();\n // Check that token is not an EOA\n if (token.code.length == 0) revert TokenNotContract();\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/Admin.sol\n\ncontract Admin is IAdmin, AccessControlEnumerable {\n using UniversalTokenLib for address;\n\n bytes32 public constant RELAYER_ROLE = keccak256(\"RELAYER_ROLE\");\n bytes32 public constant REFUNDER_ROLE = keccak256(\"REFUNDER_ROLE\");\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n uint256 public constant FEE_BPS = 1e6;\n uint256 public constant FEE_RATE_MAX = 0.01e6; // max 1% on origin amount\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Chain gas amount to forward as rebate if requested\n uint256 public chainGasAmount;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n }\n\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n require(newFeeRate \u003c= FEE_RATE_MAX, \"newFeeRate \u003e max\");\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n token.universalTransfer(recipient, feeAmount);\n emit FeesSwept(token, recipient, feeAmount);\n }\n\n function setChainGasAmount(uint256 newChainGasAmount) external onlyRole(GOVERNOR_ROLE) {\n uint256 oldChainGasAmount = chainGasAmount;\n chainGasAmount = newChainGasAmount;\n emit ChainGasAmountUpdated(oldChainGasAmount, newChainGasAmount);\n }\n}\n\n// contracts/FastBridge.sol\n\ncontract FastBridge is IFastBridge, MulticallTarget, Admin {\n using SafeERC20 for IERC20;\n using UniversalTokenLib for address;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Delay for a transaction after which it could be permisionlessly refunded\n uint256 public constant REFUND_DELAY = 7 days;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeStatus) public bridgeStatuses;\n /// @notice Proof of relayed bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeProof) public bridgeProofs;\n /// @notice Whether bridge has been relayed on destination chain\n mapping(bytes32 =\u003e bool) public bridgeRelays;\n\n /// @dev to prevent replays\n uint256 public nonce;\n // @dev the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @notice Pulls a requested token from the user to the requested recipient.\n /// @dev Be careful of re-entrancy issues when msg.value \u003e 0 and recipient != address(this)\n function _pullToken(address recipient, address token, uint256 amount) internal returns (uint256 amountPulled) {\n if (token != UniversalTokenLib.ETH_ADDRESS) {\n token.assertIsContract();\n // Record token balance before transfer\n amountPulled = IERC20(token).balanceOf(recipient);\n // Token needs to be pulled only if msg.value is zero\n // This way user can specify WETH as the origin asset\n IERC20(token).safeTransferFrom(msg.sender, recipient, amount);\n // Use the difference between the recorded balance and the current balance as the amountPulled\n amountPulled = IERC20(token).balanceOf(recipient) - amountPulled;\n } else {\n // Otherwise, we need to check that ETH amount matches msg.value\n if (amount != msg.value) revert MsgValueIncorrect();\n // Transfer value to recipient if not this address\n if (recipient != address(this)) token.universalTransfer(recipient, amount);\n // We will forward msg.value in the external call later, if recipient is not this contract\n amountPulled = msg.value;\n }\n }\n\n /// @inheritdoc IFastBridge\n function getBridgeTransaction(bytes memory request) public pure returns (BridgeTransaction memory) {\n return abi.decode(request, (BridgeTransaction));\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n // check bridge params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n\n // transfer tokens to bridge contract\n // @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _pullToken(address(this), params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n\n // set status to requested\n bytes memory request = abi.encode(\n BridgeTransaction({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n sendChainGas: params.sendChainGas,\n deadline: params.deadline,\n nonce: nonce++ // increment nonce on every bridge\n })\n );\n bytes32 transactionId = keccak256(request);\n bridgeStatuses[transactionId] = BridgeStatus.REQUESTED;\n\n emit BridgeRequested(\n transactionId,\n params.sender,\n request,\n params.dstChainId,\n params.originToken,\n params.destToken,\n originAmount,\n params.destAmount,\n params.sendChainGas\n );\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes memory request) external payable onlyRole(RELAYER_ROLE) {\n bytes32 transactionId = keccak256(request);\n BridgeTransaction memory transaction = getBridgeTransaction(request);\n if (transaction.destChainId != uint32(block.chainid)) revert ChainIncorrect();\n\n // check haven't exceeded deadline for relay to happen\n if (block.timestamp \u003e transaction.deadline) revert DeadlineExceeded();\n\n // mark bridge transaction as relayed\n if (bridgeRelays[transactionId]) revert TransactionRelayed();\n bridgeRelays[transactionId] = true;\n\n // transfer tokens to recipient on destination chain and gas rebate if requested\n address to = transaction.destRecipient;\n address token = transaction.destToken;\n uint256 amount = transaction.destAmount;\n\n uint256 rebate = chainGasAmount;\n if (!transaction.sendChainGas) {\n // forward erc20\n rebate = 0;\n _pullToken(to, token, amount);\n } else if (token == UniversalTokenLib.ETH_ADDRESS) {\n // lump in gas rebate into amount in native gas token\n _pullToken(to, token, amount + rebate);\n } else {\n // forward erc20 then forward gas rebate in native gas token\n _pullToken(to, token, amount);\n _pullToken(to, UniversalTokenLib.ETH_ADDRESS, rebate);\n }\n\n emit BridgeRelayed(\n transactionId,\n msg.sender,\n to,\n transaction.originChainId,\n transaction.originToken,\n transaction.destToken,\n transaction.originAmount,\n transaction.destAmount,\n rebate\n );\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes memory request, bytes32 destTxHash) external onlyRole(RELAYER_ROLE) {\n bytes32 transactionId = keccak256(request);\n // update bridge tx status given proof provided\n if (bridgeStatuses[transactionId] != BridgeStatus.REQUESTED) revert StatusIncorrect();\n bridgeStatuses[transactionId] = BridgeStatus.RELAYER_PROVED;\n bridgeProofs[transactionId] = BridgeProof({timestamp: uint96(block.timestamp), relayer: msg.sender}); // overflow ok\n\n emit BridgeProofProvided(transactionId, msg.sender, destTxHash);\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint96(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint96).max but\n /// proof.timestamp \u003c type(uint96).max via unchecked statement\n /// @param proof The bridge proof\n /// @return delta Time delta since proof submitted\n function _timeSince(BridgeProof memory proof) internal view returns (uint256 delta) {\n unchecked {\n delta = uint96(block.timestamp) - proof.timestamp;\n }\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n if (bridgeStatuses[transactionId] != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n BridgeProof memory proof = bridgeProofs[transactionId];\n if (proof.relayer != relayer) revert SenderIncorrect();\n return _timeSince(proof) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes memory request, address to) external onlyRole(RELAYER_ROLE) {\n bytes32 transactionId = keccak256(request);\n BridgeTransaction memory transaction = getBridgeTransaction(request);\n\n // update bridge tx status if able to claim origin collateral\n if (bridgeStatuses[transactionId] != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n\n BridgeProof memory proof = bridgeProofs[transactionId];\n if (proof.relayer != msg.sender) revert SenderIncorrect();\n if (_timeSince(proof) \u003c= DISPUTE_PERIOD) revert DisputePeriodNotPassed();\n\n bridgeStatuses[transactionId] = BridgeStatus.RELAYER_CLAIMED;\n\n // update protocol fees if origin fee amount exists\n if (transaction.originFeeAmount \u003e 0) protocolFees[transaction.originToken] += transaction.originFeeAmount;\n\n // transfer origin collateral less fee to specified address\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositClaimed(transactionId, msg.sender, to, token, amount);\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n if (bridgeStatuses[transactionId] != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(bridgeProofs[transactionId]) \u003e DISPUTE_PERIOD) revert DisputePeriodPassed();\n\n // @dev relayer gets slashed effectively if dest relay has gone thru\n bridgeStatuses[transactionId] = BridgeStatus.REQUESTED;\n delete bridgeProofs[transactionId];\n\n emit BridgeProofDisputed(transactionId, msg.sender);\n }\n\n /// @inheritdoc IFastBridge\n function refund(bytes memory request) external {\n bytes32 transactionId = keccak256(request);\n BridgeTransaction memory transaction = getBridgeTransaction(request);\n\n if (hasRole(REFUNDER_ROLE, msg.sender)) {\n // Refunder can refund if deadline has passed\n if (block.timestamp \u003c= transaction.deadline) revert DeadlineNotExceeded();\n } else {\n // Permissionless refund is allowed after REFUND_DELAY\n if (block.timestamp \u003c= transaction.deadline + REFUND_DELAY) revert DeadlineNotExceeded();\n }\n\n // set status to refunded if still in requested state\n if (bridgeStatuses[transactionId] != BridgeStatus.REQUESTED) revert StatusIncorrect();\n bridgeStatuses[transactionId] = BridgeStatus.REFUNDED;\n\n // transfer origin collateral back to original sender\n address to = transaction.originSender;\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount + transaction.originFeeAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n }\n}\n\n// test/FastBridgeMock.sol\n\ncontract FastBridgeMock is IFastBridge, Admin {\n // @dev the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @dev to prevent replays\n uint256 public nonce;\n\n /// @notice We include an empty \"test\" function so that this contract does not appear in the coverage report.\n function testFastBridgeMock() external {}\n\n function getBridgeTransaction(bytes memory request) public pure returns (BridgeTransaction memory) {\n return abi.decode(request, (BridgeTransaction));\n }\n\n // used for testing in go.\n // see: https://ethereum.stackexchange.com/questions/21155/how-to-expose-enum-in-solidity-contract\n // make sure to update fastbridge/status.go if this changes\n // or underliyng enum changes.\n //\n // TODO: a foundry test should be added to ensure this is always in sync.\n function getEnumKeyByValue(FastBridge.BridgeStatus keyValue) public pure returns (string memory) {\n if (FastBridge.BridgeStatus.NULL == keyValue) return \"NULL\";\n if (FastBridge.BridgeStatus.REQUESTED == keyValue) return \"REQUESTED\";\n if (FastBridge.BridgeStatus.RELAYER_PROVED == keyValue) return \"RELAYER_PROVED\";\n if (FastBridge.BridgeStatus.RELAYER_CLAIMED == keyValue) return \"RELAYER_CLAIMED\";\n if (FastBridge.BridgeStatus.REFUNDED == keyValue) return \"REFUNDED\";\n return \"\";\n }\n\n function mockBridgeRequest(bytes32 transactionId, address sender, BridgeParams memory params) external {\n sender;\n uint256 originFeeAmount = (params.originAmount * protocolFeeRate) / FEE_BPS;\n params.originAmount -= originFeeAmount;\n\n bytes memory request = abi.encode(\n BridgeTransaction({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: params.originAmount, // includes relayer fee\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n sendChainGas: params.sendChainGas,\n deadline: params.deadline,\n nonce: nonce++ // increment nonce on every bridge\n })\n );\n\n emit BridgeRequested(\n transactionId,\n params.sender,\n request,\n params.dstChainId,\n params.originToken,\n params.destToken,\n params.originAmount,\n params.destAmount,\n params.sendChainGas\n );\n }\n\n function mockBridgeRequestRaw(bytes32 transactionId, address sender, bytes memory request) external {\n sender;\n BridgeTransaction memory transaction = getBridgeTransaction(request);\n emit BridgeRequested(\n transactionId,\n transaction.originSender,\n request,\n transaction.destChainId,\n transaction.originToken,\n transaction.destToken,\n transaction.originAmount,\n transaction.destAmount,\n transaction.sendChainGas\n );\n }\n\n function mockBridgeRelayer(\n bytes32 transactionId,\n address relayer,\n address to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n )\n external\n {\n emit BridgeRelayed(\n transactionId, relayer, to, originChainId, originToken, destToken, originAmount, destAmount, chainGasAmount\n );\n }\n\n function bridge(BridgeParams memory) external payable {\n revert(\"not implemented\");\n }\n\n function relay(bytes memory) external payable {\n revert(\"not implemented\");\n }\n\n function prove(bytes memory, bytes32) external pure {\n revert(\"not implemented\");\n }\n\n function canClaim(bytes32, address) external pure returns (bool) {\n revert(\"not implemented\");\n }\n\n function claim(bytes memory, address) external pure {\n revert(\"not implemented\");\n }\n\n function dispute(bytes32) external pure {\n revert(\"not implemented\");\n }\n\n function refund(bytes memory) external pure {\n revert(\"not implemented\");\n }\n}\n","language":"Solidity","languageVersion":"0.8.20","compilerVersion":"0.8.20","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"","srcMapRuntime":"","abiDefinition":[{"inputs":[{"internalType":"bytes[]","name":"data","type":"bytes[]"},{"internalType":"bool","name":"ignoreReverts","type":"bool"}],"name":"multicallNoResults","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes[]","name":"data","type":"bytes[]"},{"internalType":"bool","name":"ignoreReverts","type":"bool"}],"name":"multicallWithResults","outputs":[{"components":[{"internalType":"bool","name":"success","type":"bool"},{"internalType":"bytes","name":"returnData","type":"bytes"}],"internalType":"struct IMulticallTarget.Result[]","name":"results","type":"tuple[]"}],"stateMutability":"nonpayable","type":"function"}],"userDoc":{"kind":"user","methods":{},"notice":"Interface for a contract that can be called multiple times by the same caller. Inspired by MulticallV3: https://github.com/mds1/multicall/blob/master/src/Multicall3.sol","version":1},"developerDoc":{"kind":"dev","methods":{},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.20+commit.a1b79de6\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"bytes[]\",\"name\":\"data\",\"type\":\"bytes[]\"},{\"internalType\":\"bool\",\"name\":\"ignoreReverts\",\"type\":\"bool\"}],\"name\":\"multicallNoResults\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes[]\",\"name\":\"data\",\"type\":\"bytes[]\"},{\"internalType\":\"bool\",\"name\":\"ignoreReverts\",\"type\":\"bool\"}],\"name\":\"multicallWithResults\",\"outputs\":[{\"components\":[{\"internalType\":\"bool\",\"name\":\"success\",\"type\":\"bool\"},{\"internalType\":\"bytes\",\"name\":\"returnData\",\"type\":\"bytes\"}],\"internalType\":\"struct IMulticallTarget.Result[]\",\"name\":\"results\",\"type\":\"tuple[]\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"notice\":\"Interface for a contract that can be called multiple times by the same caller. Inspired by MulticallV3: https://github.com/mds1/multicall/blob/master/src/Multicall3.sol\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeMock.sol\":\"IMulticallTarget\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeMock.sol\":{\"keccak256\":\"0xf2751f52f8216801d500da7464ad01f3c23a8286e155e2dcba6d21d6e7fd95a0\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://85d2edab24ebe321043d2b88038437e8f443a0ef26fa2139c72dcc2bc7fbc602\",\"dweb:/ipfs/QmcULiFPFJzFDT4aupVSDreXz8uHxcABb5nxpAG4zYzfNN\"]}},\"version\":1}"},"hashes":{"multicallNoResults(bytes[],bool)":"3f61331d","multicallWithResults(bytes[],bool)":"385c1d2f"}},"solidity/FastBridgeMock.sol:MulticallTarget":{"code":"0x","runtime-code":"0x","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.20 ^0.8.20 ^0.8.4;\n\n// contracts/interfaces/IAdmin.sol\n\ninterface IAdmin {\n // ============ Events ============\n\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n event ChainGasAmountUpdated(uint256 oldChainGasAmount, uint256 newChainGasAmount);\n\n // ============ Methods ============\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n\n function setChainGasAmount(uint256 newChainGasAmount) external;\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IMulticallTarget.sol\n\n/// @notice Interface for a contract that can be called multiple times by the same caller. Inspired by MulticallV3:\n/// https://github.com/mds1/multicall/blob/master/src/Multicall3.sol\ninterface IMulticallTarget {\n struct Result {\n bool success;\n bytes returnData;\n }\n\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external;\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results);\n}\n\n// contracts/libs/Errors.sol\n\nerror DeadlineExceeded();\nerror DeadlineNotExceeded();\nerror DeadlineTooShort();\nerror InsufficientOutputAmount();\n\nerror MsgValueIncorrect();\nerror PoolNotFound();\nerror TokenAddressMismatch();\nerror TokenNotContract();\nerror TokenNotETH();\nerror TokensIdentical();\n\nerror ChainIncorrect();\nerror AmountIncorrect();\nerror ZeroAddress();\n\nerror DisputePeriodNotPassed();\nerror DisputePeriodPassed();\nerror SenderIncorrect();\nerror StatusIncorrect();\nerror TransactionIdIncorrect();\nerror TransactionRelayed();\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// contracts/utils/MulticallTarget.sol\n\n// solhint-disable avoid-low-level-calls\n/// @notice Template for a contract that supports batched calls (preserving the msg.sender).\n/// Only calls with zero msg.value could be batched.\nabstract contract MulticallTarget is IMulticallTarget {\n error MulticallTarget__UndeterminedRevert();\n\n /// @notice Perform a batched call to this contract, preserving the msg.sender.\n /// The return data from each call is discarded.\n /// @dev The method is non-payable, so only calls with `msg.value == 0` could be batched.\n /// It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag.\n /// Otherwise, the whole batch call will be reverted with the original revert reason.\n /// @param data List of abi-encoded calldata for the calls to perform.\n /// @param ignoreReverts Whether to ignore the revert errors from the calls.\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external {\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\n if (!success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(result);\n }\n }\n }\n\n /// @notice Perform a batched call to this contract, preserving the msg.sender.\n /// The return data from each call is preserved.\n /// @dev The method is non-payable, so only calls with `msg.value == 0` could be batched.\n /// It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag.\n /// Otherwise, the whole batch call will be reverted with the original revert reason.\n /// @param data List of abi-encoded calldata for the calls to perform.\n /// @param ignoreReverts Whether to ignore the revert errors from the calls.\n /// @return results List of results from the calls: `(success, returnData)`.\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results)\n {\n results = new Result[](data.length);\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (results[i].success, results[i].returnData) = address(this).delegatecall(data[i]);\n if (!results[i].success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(results[i].returnData);\n }\n }\n }\n\n /// @dev Bubbles the revert message from the underlying call.\n /// Note: preserves the same custom error or revert string, if one was used.\n /// Source: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v5.0.2/contracts/utils/Address.sol#L143-L158\n function _bubbleRevert(bytes memory returnData) internal pure {\n // Look for revert reason and bubble it up if present\n if (returnData.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n // solhint-disable-next-line no-inline-assembly\n assembly {\n let returndata_size := mload(returnData)\n revert(add(32, returnData), returndata_size)\n }\n } else {\n revert MulticallTarget__UndeterminedRevert();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// contracts/libs/UniversalToken.sol\n\nlibrary UniversalTokenLib {\n using SafeERC20 for IERC20;\n\n address internal constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Transfers tokens to the given account. Reverts if transfer is not successful.\n /// @dev This might trigger fallback, if ETH is transferred to the contract.\n /// Make sure this can not lead to reentrancy attacks.\n function universalTransfer(address token, address to, uint256 value) internal {\n // Don't do anything, if need to send tokens to this address\n if (to == address(this)) return;\n // Don't do anything, if trying to send zero value\n if (value == 0) return;\n if (token == ETH_ADDRESS) {\n /// @dev Note: this can potentially lead to executing code in `to`.\n // solhint-disable-next-line avoid-low-level-calls\n (bool success,) = to.call{value: value}(\"\");\n require(success, \"ETH transfer failed\");\n } else {\n IERC20(token).safeTransfer(to, value);\n }\n }\n\n /// @notice Issues an infinite allowance to the spender, if the current allowance is insufficient\n /// to spend the given amount.\n function universalApproveInfinity(address token, address spender, uint256 amountToSpend) internal {\n // ETH Chad doesn't require your approval\n if (token == ETH_ADDRESS) return;\n // No-op if allowance is already sufficient\n uint256 allowance = IERC20(token).allowance(address(this), spender);\n if (allowance \u003e= amountToSpend) return;\n // Otherwise, reset approval to 0 and set to max allowance\n if (allowance \u003e 0) IERC20(token).safeDecreaseAllowance(spender, allowance);\n IERC20(token).safeIncreaseAllowance(spender, type(uint256).max);\n }\n\n /// @notice Returns the balance of the given token (or native ETH) for the given account.\n function universalBalanceOf(address token, address account) internal view returns (uint256) {\n if (token == ETH_ADDRESS) {\n return account.balance;\n } else {\n return IERC20(token).balanceOf(account);\n }\n }\n\n /// @dev Checks that token is a contract and not ETH_ADDRESS.\n function assertIsContract(address token) internal view {\n // Check that ETH_ADDRESS was not used (in case this is a predeploy on any of the chains)\n if (token == UniversalTokenLib.ETH_ADDRESS) revert TokenNotContract();\n // Check that token is not an EOA\n if (token.code.length == 0) revert TokenNotContract();\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/Admin.sol\n\ncontract Admin is IAdmin, AccessControlEnumerable {\n using UniversalTokenLib for address;\n\n bytes32 public constant RELAYER_ROLE = keccak256(\"RELAYER_ROLE\");\n bytes32 public constant REFUNDER_ROLE = keccak256(\"REFUNDER_ROLE\");\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n uint256 public constant FEE_BPS = 1e6;\n uint256 public constant FEE_RATE_MAX = 0.01e6; // max 1% on origin amount\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Chain gas amount to forward as rebate if requested\n uint256 public chainGasAmount;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n }\n\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n require(newFeeRate \u003c= FEE_RATE_MAX, \"newFeeRate \u003e max\");\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n token.universalTransfer(recipient, feeAmount);\n emit FeesSwept(token, recipient, feeAmount);\n }\n\n function setChainGasAmount(uint256 newChainGasAmount) external onlyRole(GOVERNOR_ROLE) {\n uint256 oldChainGasAmount = chainGasAmount;\n chainGasAmount = newChainGasAmount;\n emit ChainGasAmountUpdated(oldChainGasAmount, newChainGasAmount);\n }\n}\n\n// contracts/FastBridge.sol\n\ncontract FastBridge is IFastBridge, MulticallTarget, Admin {\n using SafeERC20 for IERC20;\n using UniversalTokenLib for address;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Delay for a transaction after which it could be permisionlessly refunded\n uint256 public constant REFUND_DELAY = 7 days;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeStatus) public bridgeStatuses;\n /// @notice Proof of relayed bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeProof) public bridgeProofs;\n /// @notice Whether bridge has been relayed on destination chain\n mapping(bytes32 =\u003e bool) public bridgeRelays;\n\n /// @dev to prevent replays\n uint256 public nonce;\n // @dev the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @notice Pulls a requested token from the user to the requested recipient.\n /// @dev Be careful of re-entrancy issues when msg.value \u003e 0 and recipient != address(this)\n function _pullToken(address recipient, address token, uint256 amount) internal returns (uint256 amountPulled) {\n if (token != UniversalTokenLib.ETH_ADDRESS) {\n token.assertIsContract();\n // Record token balance before transfer\n amountPulled = IERC20(token).balanceOf(recipient);\n // Token needs to be pulled only if msg.value is zero\n // This way user can specify WETH as the origin asset\n IERC20(token).safeTransferFrom(msg.sender, recipient, amount);\n // Use the difference between the recorded balance and the current balance as the amountPulled\n amountPulled = IERC20(token).balanceOf(recipient) - amountPulled;\n } else {\n // Otherwise, we need to check that ETH amount matches msg.value\n if (amount != msg.value) revert MsgValueIncorrect();\n // Transfer value to recipient if not this address\n if (recipient != address(this)) token.universalTransfer(recipient, amount);\n // We will forward msg.value in the external call later, if recipient is not this contract\n amountPulled = msg.value;\n }\n }\n\n /// @inheritdoc IFastBridge\n function getBridgeTransaction(bytes memory request) public pure returns (BridgeTransaction memory) {\n return abi.decode(request, (BridgeTransaction));\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n // check bridge params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n\n // transfer tokens to bridge contract\n // @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _pullToken(address(this), params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n\n // set status to requested\n bytes memory request = abi.encode(\n BridgeTransaction({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n sendChainGas: params.sendChainGas,\n deadline: params.deadline,\n nonce: nonce++ // increment nonce on every bridge\n })\n );\n bytes32 transactionId = keccak256(request);\n bridgeStatuses[transactionId] = BridgeStatus.REQUESTED;\n\n emit BridgeRequested(\n transactionId,\n params.sender,\n request,\n params.dstChainId,\n params.originToken,\n params.destToken,\n originAmount,\n params.destAmount,\n params.sendChainGas\n );\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes memory request) external payable onlyRole(RELAYER_ROLE) {\n bytes32 transactionId = keccak256(request);\n BridgeTransaction memory transaction = getBridgeTransaction(request);\n if (transaction.destChainId != uint32(block.chainid)) revert ChainIncorrect();\n\n // check haven't exceeded deadline for relay to happen\n if (block.timestamp \u003e transaction.deadline) revert DeadlineExceeded();\n\n // mark bridge transaction as relayed\n if (bridgeRelays[transactionId]) revert TransactionRelayed();\n bridgeRelays[transactionId] = true;\n\n // transfer tokens to recipient on destination chain and gas rebate if requested\n address to = transaction.destRecipient;\n address token = transaction.destToken;\n uint256 amount = transaction.destAmount;\n\n uint256 rebate = chainGasAmount;\n if (!transaction.sendChainGas) {\n // forward erc20\n rebate = 0;\n _pullToken(to, token, amount);\n } else if (token == UniversalTokenLib.ETH_ADDRESS) {\n // lump in gas rebate into amount in native gas token\n _pullToken(to, token, amount + rebate);\n } else {\n // forward erc20 then forward gas rebate in native gas token\n _pullToken(to, token, amount);\n _pullToken(to, UniversalTokenLib.ETH_ADDRESS, rebate);\n }\n\n emit BridgeRelayed(\n transactionId,\n msg.sender,\n to,\n transaction.originChainId,\n transaction.originToken,\n transaction.destToken,\n transaction.originAmount,\n transaction.destAmount,\n rebate\n );\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes memory request, bytes32 destTxHash) external onlyRole(RELAYER_ROLE) {\n bytes32 transactionId = keccak256(request);\n // update bridge tx status given proof provided\n if (bridgeStatuses[transactionId] != BridgeStatus.REQUESTED) revert StatusIncorrect();\n bridgeStatuses[transactionId] = BridgeStatus.RELAYER_PROVED;\n bridgeProofs[transactionId] = BridgeProof({timestamp: uint96(block.timestamp), relayer: msg.sender}); // overflow ok\n\n emit BridgeProofProvided(transactionId, msg.sender, destTxHash);\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint96(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint96).max but\n /// proof.timestamp \u003c type(uint96).max via unchecked statement\n /// @param proof The bridge proof\n /// @return delta Time delta since proof submitted\n function _timeSince(BridgeProof memory proof) internal view returns (uint256 delta) {\n unchecked {\n delta = uint96(block.timestamp) - proof.timestamp;\n }\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n if (bridgeStatuses[transactionId] != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n BridgeProof memory proof = bridgeProofs[transactionId];\n if (proof.relayer != relayer) revert SenderIncorrect();\n return _timeSince(proof) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes memory request, address to) external onlyRole(RELAYER_ROLE) {\n bytes32 transactionId = keccak256(request);\n BridgeTransaction memory transaction = getBridgeTransaction(request);\n\n // update bridge tx status if able to claim origin collateral\n if (bridgeStatuses[transactionId] != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n\n BridgeProof memory proof = bridgeProofs[transactionId];\n if (proof.relayer != msg.sender) revert SenderIncorrect();\n if (_timeSince(proof) \u003c= DISPUTE_PERIOD) revert DisputePeriodNotPassed();\n\n bridgeStatuses[transactionId] = BridgeStatus.RELAYER_CLAIMED;\n\n // update protocol fees if origin fee amount exists\n if (transaction.originFeeAmount \u003e 0) protocolFees[transaction.originToken] += transaction.originFeeAmount;\n\n // transfer origin collateral less fee to specified address\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositClaimed(transactionId, msg.sender, to, token, amount);\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n if (bridgeStatuses[transactionId] != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(bridgeProofs[transactionId]) \u003e DISPUTE_PERIOD) revert DisputePeriodPassed();\n\n // @dev relayer gets slashed effectively if dest relay has gone thru\n bridgeStatuses[transactionId] = BridgeStatus.REQUESTED;\n delete bridgeProofs[transactionId];\n\n emit BridgeProofDisputed(transactionId, msg.sender);\n }\n\n /// @inheritdoc IFastBridge\n function refund(bytes memory request) external {\n bytes32 transactionId = keccak256(request);\n BridgeTransaction memory transaction = getBridgeTransaction(request);\n\n if (hasRole(REFUNDER_ROLE, msg.sender)) {\n // Refunder can refund if deadline has passed\n if (block.timestamp \u003c= transaction.deadline) revert DeadlineNotExceeded();\n } else {\n // Permissionless refund is allowed after REFUND_DELAY\n if (block.timestamp \u003c= transaction.deadline + REFUND_DELAY) revert DeadlineNotExceeded();\n }\n\n // set status to refunded if still in requested state\n if (bridgeStatuses[transactionId] != BridgeStatus.REQUESTED) revert StatusIncorrect();\n bridgeStatuses[transactionId] = BridgeStatus.REFUNDED;\n\n // transfer origin collateral back to original sender\n address to = transaction.originSender;\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount + transaction.originFeeAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n }\n}\n\n// test/FastBridgeMock.sol\n\ncontract FastBridgeMock is IFastBridge, Admin {\n // @dev the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @dev to prevent replays\n uint256 public nonce;\n\n /// @notice We include an empty \"test\" function so that this contract does not appear in the coverage report.\n function testFastBridgeMock() external {}\n\n function getBridgeTransaction(bytes memory request) public pure returns (BridgeTransaction memory) {\n return abi.decode(request, (BridgeTransaction));\n }\n\n // used for testing in go.\n // see: https://ethereum.stackexchange.com/questions/21155/how-to-expose-enum-in-solidity-contract\n // make sure to update fastbridge/status.go if this changes\n // or underliyng enum changes.\n //\n // TODO: a foundry test should be added to ensure this is always in sync.\n function getEnumKeyByValue(FastBridge.BridgeStatus keyValue) public pure returns (string memory) {\n if (FastBridge.BridgeStatus.NULL == keyValue) return \"NULL\";\n if (FastBridge.BridgeStatus.REQUESTED == keyValue) return \"REQUESTED\";\n if (FastBridge.BridgeStatus.RELAYER_PROVED == keyValue) return \"RELAYER_PROVED\";\n if (FastBridge.BridgeStatus.RELAYER_CLAIMED == keyValue) return \"RELAYER_CLAIMED\";\n if (FastBridge.BridgeStatus.REFUNDED == keyValue) return \"REFUNDED\";\n return \"\";\n }\n\n function mockBridgeRequest(bytes32 transactionId, address sender, BridgeParams memory params) external {\n sender;\n uint256 originFeeAmount = (params.originAmount * protocolFeeRate) / FEE_BPS;\n params.originAmount -= originFeeAmount;\n\n bytes memory request = abi.encode(\n BridgeTransaction({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: params.originAmount, // includes relayer fee\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n sendChainGas: params.sendChainGas,\n deadline: params.deadline,\n nonce: nonce++ // increment nonce on every bridge\n })\n );\n\n emit BridgeRequested(\n transactionId,\n params.sender,\n request,\n params.dstChainId,\n params.originToken,\n params.destToken,\n params.originAmount,\n params.destAmount,\n params.sendChainGas\n );\n }\n\n function mockBridgeRequestRaw(bytes32 transactionId, address sender, bytes memory request) external {\n sender;\n BridgeTransaction memory transaction = getBridgeTransaction(request);\n emit BridgeRequested(\n transactionId,\n transaction.originSender,\n request,\n transaction.destChainId,\n transaction.originToken,\n transaction.destToken,\n transaction.originAmount,\n transaction.destAmount,\n transaction.sendChainGas\n );\n }\n\n function mockBridgeRelayer(\n bytes32 transactionId,\n address relayer,\n address to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n )\n external\n {\n emit BridgeRelayed(\n transactionId, relayer, to, originChainId, originToken, destToken, originAmount, destAmount, chainGasAmount\n );\n }\n\n function bridge(BridgeParams memory) external payable {\n revert(\"not implemented\");\n }\n\n function relay(bytes memory) external payable {\n revert(\"not implemented\");\n }\n\n function prove(bytes memory, bytes32) external pure {\n revert(\"not implemented\");\n }\n\n function canClaim(bytes32, address) external pure returns (bool) {\n revert(\"not implemented\");\n }\n\n function claim(bytes memory, address) external pure {\n revert(\"not implemented\");\n }\n\n function dispute(bytes32) external pure {\n revert(\"not implemented\");\n }\n\n function refund(bytes memory) external pure {\n revert(\"not implemented\");\n }\n}\n","language":"Solidity","languageVersion":"0.8.20","compilerVersion":"0.8.20","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"","srcMapRuntime":"","abiDefinition":[{"inputs":[],"name":"MulticallTarget__UndeterminedRevert","type":"error"},{"inputs":[{"internalType":"bytes[]","name":"data","type":"bytes[]"},{"internalType":"bool","name":"ignoreReverts","type":"bool"}],"name":"multicallNoResults","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes[]","name":"data","type":"bytes[]"},{"internalType":"bool","name":"ignoreReverts","type":"bool"}],"name":"multicallWithResults","outputs":[{"components":[{"internalType":"bool","name":"success","type":"bool"},{"internalType":"bytes","name":"returnData","type":"bytes"}],"internalType":"struct IMulticallTarget.Result[]","name":"results","type":"tuple[]"}],"stateMutability":"nonpayable","type":"function"}],"userDoc":{"kind":"user","methods":{"multicallNoResults(bytes[],bool)":{"notice":"Perform a batched call to this contract, preserving the msg.sender. The return data from each call is discarded."},"multicallWithResults(bytes[],bool)":{"notice":"Perform a batched call to this contract, preserving the msg.sender. The return data from each call is preserved."}},"notice":"Template for a contract that supports batched calls (preserving the msg.sender). Only calls with zero msg.value could be batched.","version":1},"developerDoc":{"kind":"dev","methods":{"multicallNoResults(bytes[],bool)":{"details":"The method is non-payable, so only calls with `msg.value == 0` could be batched. It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag. Otherwise, the whole batch call will be reverted with the original revert reason.","params":{"data":"List of abi-encoded calldata for the calls to perform.","ignoreReverts":"Whether to ignore the revert errors from the calls."}},"multicallWithResults(bytes[],bool)":{"details":"The method is non-payable, so only calls with `msg.value == 0` could be batched. It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag. Otherwise, the whole batch call will be reverted with the original revert reason.","params":{"data":"List of abi-encoded calldata for the calls to perform.","ignoreReverts":"Whether to ignore the revert errors from the calls."},"returns":{"results":" List of results from the calls: `(success, returnData)`."}}},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.20+commit.a1b79de6\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[],\"name\":\"MulticallTarget__UndeterminedRevert\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"bytes[]\",\"name\":\"data\",\"type\":\"bytes[]\"},{\"internalType\":\"bool\",\"name\":\"ignoreReverts\",\"type\":\"bool\"}],\"name\":\"multicallNoResults\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes[]\",\"name\":\"data\",\"type\":\"bytes[]\"},{\"internalType\":\"bool\",\"name\":\"ignoreReverts\",\"type\":\"bool\"}],\"name\":\"multicallWithResults\",\"outputs\":[{\"components\":[{\"internalType\":\"bool\",\"name\":\"success\",\"type\":\"bool\"},{\"internalType\":\"bytes\",\"name\":\"returnData\",\"type\":\"bytes\"}],\"internalType\":\"struct IMulticallTarget.Result[]\",\"name\":\"results\",\"type\":\"tuple[]\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{\"multicallNoResults(bytes[],bool)\":{\"details\":\"The method is non-payable, so only calls with `msg.value == 0` could be batched. It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag. Otherwise, the whole batch call will be reverted with the original revert reason.\",\"params\":{\"data\":\"List of abi-encoded calldata for the calls to perform.\",\"ignoreReverts\":\"Whether to ignore the revert errors from the calls.\"}},\"multicallWithResults(bytes[],bool)\":{\"details\":\"The method is non-payable, so only calls with `msg.value == 0` could be batched. It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag. Otherwise, the whole batch call will be reverted with the original revert reason.\",\"params\":{\"data\":\"List of abi-encoded calldata for the calls to perform.\",\"ignoreReverts\":\"Whether to ignore the revert errors from the calls.\"},\"returns\":{\"results\":\" List of results from the calls: `(success, returnData)`.\"}}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"multicallNoResults(bytes[],bool)\":{\"notice\":\"Perform a batched call to this contract, preserving the msg.sender. The return data from each call is discarded.\"},\"multicallWithResults(bytes[],bool)\":{\"notice\":\"Perform a batched call to this contract, preserving the msg.sender. The return data from each call is preserved.\"}},\"notice\":\"Template for a contract that supports batched calls (preserving the msg.sender). Only calls with zero msg.value could be batched.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeMock.sol\":\"MulticallTarget\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeMock.sol\":{\"keccak256\":\"0xf2751f52f8216801d500da7464ad01f3c23a8286e155e2dcba6d21d6e7fd95a0\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://85d2edab24ebe321043d2b88038437e8f443a0ef26fa2139c72dcc2bc7fbc602\",\"dweb:/ipfs/QmcULiFPFJzFDT4aupVSDreXz8uHxcABb5nxpAG4zYzfNN\"]}},\"version\":1}"},"hashes":{"multicallNoResults(bytes[],bool)":"3f61331d","multicallWithResults(bytes[],bool)":"385c1d2f"}},"solidity/FastBridgeMock.sol:SafeERC20":{"code":"0x60566037600b82828239805160001a607314602a57634e487b7160e01b600052600060045260246000fd5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600080fdfea264697066735822122095b019b39709f79687d9e5b44e40378a5a332da0a4d6c1fd704a420d3d83d79564736f6c63430008140033","runtime-code":"0x73000000000000000000000000000000000000000030146080604052600080fdfea264697066735822122095b019b39709f79687d9e5b44e40378a5a332da0a4d6c1fd704a420d3d83d79564736f6c63430008140033","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.20 ^0.8.20 ^0.8.4;\n\n// contracts/interfaces/IAdmin.sol\n\ninterface IAdmin {\n // ============ Events ============\n\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n event ChainGasAmountUpdated(uint256 oldChainGasAmount, uint256 newChainGasAmount);\n\n // ============ Methods ============\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n\n function setChainGasAmount(uint256 newChainGasAmount) external;\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IMulticallTarget.sol\n\n/// @notice Interface for a contract that can be called multiple times by the same caller. Inspired by MulticallV3:\n/// https://github.com/mds1/multicall/blob/master/src/Multicall3.sol\ninterface IMulticallTarget {\n struct Result {\n bool success;\n bytes returnData;\n }\n\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external;\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results);\n}\n\n// contracts/libs/Errors.sol\n\nerror DeadlineExceeded();\nerror DeadlineNotExceeded();\nerror DeadlineTooShort();\nerror InsufficientOutputAmount();\n\nerror MsgValueIncorrect();\nerror PoolNotFound();\nerror TokenAddressMismatch();\nerror TokenNotContract();\nerror TokenNotETH();\nerror TokensIdentical();\n\nerror ChainIncorrect();\nerror AmountIncorrect();\nerror ZeroAddress();\n\nerror DisputePeriodNotPassed();\nerror DisputePeriodPassed();\nerror SenderIncorrect();\nerror StatusIncorrect();\nerror TransactionIdIncorrect();\nerror TransactionRelayed();\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// contracts/utils/MulticallTarget.sol\n\n// solhint-disable avoid-low-level-calls\n/// @notice Template for a contract that supports batched calls (preserving the msg.sender).\n/// Only calls with zero msg.value could be batched.\nabstract contract MulticallTarget is IMulticallTarget {\n error MulticallTarget__UndeterminedRevert();\n\n /// @notice Perform a batched call to this contract, preserving the msg.sender.\n /// The return data from each call is discarded.\n /// @dev The method is non-payable, so only calls with `msg.value == 0` could be batched.\n /// It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag.\n /// Otherwise, the whole batch call will be reverted with the original revert reason.\n /// @param data List of abi-encoded calldata for the calls to perform.\n /// @param ignoreReverts Whether to ignore the revert errors from the calls.\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external {\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\n if (!success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(result);\n }\n }\n }\n\n /// @notice Perform a batched call to this contract, preserving the msg.sender.\n /// The return data from each call is preserved.\n /// @dev The method is non-payable, so only calls with `msg.value == 0` could be batched.\n /// It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag.\n /// Otherwise, the whole batch call will be reverted with the original revert reason.\n /// @param data List of abi-encoded calldata for the calls to perform.\n /// @param ignoreReverts Whether to ignore the revert errors from the calls.\n /// @return results List of results from the calls: `(success, returnData)`.\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results)\n {\n results = new Result[](data.length);\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (results[i].success, results[i].returnData) = address(this).delegatecall(data[i]);\n if (!results[i].success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(results[i].returnData);\n }\n }\n }\n\n /// @dev Bubbles the revert message from the underlying call.\n /// Note: preserves the same custom error or revert string, if one was used.\n /// Source: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v5.0.2/contracts/utils/Address.sol#L143-L158\n function _bubbleRevert(bytes memory returnData) internal pure {\n // Look for revert reason and bubble it up if present\n if (returnData.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n // solhint-disable-next-line no-inline-assembly\n assembly {\n let returndata_size := mload(returnData)\n revert(add(32, returnData), returndata_size)\n }\n } else {\n revert MulticallTarget__UndeterminedRevert();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// contracts/libs/UniversalToken.sol\n\nlibrary UniversalTokenLib {\n using SafeERC20 for IERC20;\n\n address internal constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Transfers tokens to the given account. Reverts if transfer is not successful.\n /// @dev This might trigger fallback, if ETH is transferred to the contract.\n /// Make sure this can not lead to reentrancy attacks.\n function universalTransfer(address token, address to, uint256 value) internal {\n // Don't do anything, if need to send tokens to this address\n if (to == address(this)) return;\n // Don't do anything, if trying to send zero value\n if (value == 0) return;\n if (token == ETH_ADDRESS) {\n /// @dev Note: this can potentially lead to executing code in `to`.\n // solhint-disable-next-line avoid-low-level-calls\n (bool success,) = to.call{value: value}(\"\");\n require(success, \"ETH transfer failed\");\n } else {\n IERC20(token).safeTransfer(to, value);\n }\n }\n\n /// @notice Issues an infinite allowance to the spender, if the current allowance is insufficient\n /// to spend the given amount.\n function universalApproveInfinity(address token, address spender, uint256 amountToSpend) internal {\n // ETH Chad doesn't require your approval\n if (token == ETH_ADDRESS) return;\n // No-op if allowance is already sufficient\n uint256 allowance = IERC20(token).allowance(address(this), spender);\n if (allowance \u003e= amountToSpend) return;\n // Otherwise, reset approval to 0 and set to max allowance\n if (allowance \u003e 0) IERC20(token).safeDecreaseAllowance(spender, allowance);\n IERC20(token).safeIncreaseAllowance(spender, type(uint256).max);\n }\n\n /// @notice Returns the balance of the given token (or native ETH) for the given account.\n function universalBalanceOf(address token, address account) internal view returns (uint256) {\n if (token == ETH_ADDRESS) {\n return account.balance;\n } else {\n return IERC20(token).balanceOf(account);\n }\n }\n\n /// @dev Checks that token is a contract and not ETH_ADDRESS.\n function assertIsContract(address token) internal view {\n // Check that ETH_ADDRESS was not used (in case this is a predeploy on any of the chains)\n if (token == UniversalTokenLib.ETH_ADDRESS) revert TokenNotContract();\n // Check that token is not an EOA\n if (token.code.length == 0) revert TokenNotContract();\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/Admin.sol\n\ncontract Admin is IAdmin, AccessControlEnumerable {\n using UniversalTokenLib for address;\n\n bytes32 public constant RELAYER_ROLE = keccak256(\"RELAYER_ROLE\");\n bytes32 public constant REFUNDER_ROLE = keccak256(\"REFUNDER_ROLE\");\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n uint256 public constant FEE_BPS = 1e6;\n uint256 public constant FEE_RATE_MAX = 0.01e6; // max 1% on origin amount\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Chain gas amount to forward as rebate if requested\n uint256 public chainGasAmount;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n }\n\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n require(newFeeRate \u003c= FEE_RATE_MAX, \"newFeeRate \u003e max\");\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n token.universalTransfer(recipient, feeAmount);\n emit FeesSwept(token, recipient, feeAmount);\n }\n\n function setChainGasAmount(uint256 newChainGasAmount) external onlyRole(GOVERNOR_ROLE) {\n uint256 oldChainGasAmount = chainGasAmount;\n chainGasAmount = newChainGasAmount;\n emit ChainGasAmountUpdated(oldChainGasAmount, newChainGasAmount);\n }\n}\n\n// contracts/FastBridge.sol\n\ncontract FastBridge is IFastBridge, MulticallTarget, Admin {\n using SafeERC20 for IERC20;\n using UniversalTokenLib for address;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Delay for a transaction after which it could be permisionlessly refunded\n uint256 public constant REFUND_DELAY = 7 days;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeStatus) public bridgeStatuses;\n /// @notice Proof of relayed bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeProof) public bridgeProofs;\n /// @notice Whether bridge has been relayed on destination chain\n mapping(bytes32 =\u003e bool) public bridgeRelays;\n\n /// @dev to prevent replays\n uint256 public nonce;\n // @dev the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @notice Pulls a requested token from the user to the requested recipient.\n /// @dev Be careful of re-entrancy issues when msg.value \u003e 0 and recipient != address(this)\n function _pullToken(address recipient, address token, uint256 amount) internal returns (uint256 amountPulled) {\n if (token != UniversalTokenLib.ETH_ADDRESS) {\n token.assertIsContract();\n // Record token balance before transfer\n amountPulled = IERC20(token).balanceOf(recipient);\n // Token needs to be pulled only if msg.value is zero\n // This way user can specify WETH as the origin asset\n IERC20(token).safeTransferFrom(msg.sender, recipient, amount);\n // Use the difference between the recorded balance and the current balance as the amountPulled\n amountPulled = IERC20(token).balanceOf(recipient) - amountPulled;\n } else {\n // Otherwise, we need to check that ETH amount matches msg.value\n if (amount != msg.value) revert MsgValueIncorrect();\n // Transfer value to recipient if not this address\n if (recipient != address(this)) token.universalTransfer(recipient, amount);\n // We will forward msg.value in the external call later, if recipient is not this contract\n amountPulled = msg.value;\n }\n }\n\n /// @inheritdoc IFastBridge\n function getBridgeTransaction(bytes memory request) public pure returns (BridgeTransaction memory) {\n return abi.decode(request, (BridgeTransaction));\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n // check bridge params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n\n // transfer tokens to bridge contract\n // @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _pullToken(address(this), params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n\n // set status to requested\n bytes memory request = abi.encode(\n BridgeTransaction({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n sendChainGas: params.sendChainGas,\n deadline: params.deadline,\n nonce: nonce++ // increment nonce on every bridge\n })\n );\n bytes32 transactionId = keccak256(request);\n bridgeStatuses[transactionId] = BridgeStatus.REQUESTED;\n\n emit BridgeRequested(\n transactionId,\n params.sender,\n request,\n params.dstChainId,\n params.originToken,\n params.destToken,\n originAmount,\n params.destAmount,\n params.sendChainGas\n );\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes memory request) external payable onlyRole(RELAYER_ROLE) {\n bytes32 transactionId = keccak256(request);\n BridgeTransaction memory transaction = getBridgeTransaction(request);\n if (transaction.destChainId != uint32(block.chainid)) revert ChainIncorrect();\n\n // check haven't exceeded deadline for relay to happen\n if (block.timestamp \u003e transaction.deadline) revert DeadlineExceeded();\n\n // mark bridge transaction as relayed\n if (bridgeRelays[transactionId]) revert TransactionRelayed();\n bridgeRelays[transactionId] = true;\n\n // transfer tokens to recipient on destination chain and gas rebate if requested\n address to = transaction.destRecipient;\n address token = transaction.destToken;\n uint256 amount = transaction.destAmount;\n\n uint256 rebate = chainGasAmount;\n if (!transaction.sendChainGas) {\n // forward erc20\n rebate = 0;\n _pullToken(to, token, amount);\n } else if (token == UniversalTokenLib.ETH_ADDRESS) {\n // lump in gas rebate into amount in native gas token\n _pullToken(to, token, amount + rebate);\n } else {\n // forward erc20 then forward gas rebate in native gas token\n _pullToken(to, token, amount);\n _pullToken(to, UniversalTokenLib.ETH_ADDRESS, rebate);\n }\n\n emit BridgeRelayed(\n transactionId,\n msg.sender,\n to,\n transaction.originChainId,\n transaction.originToken,\n transaction.destToken,\n transaction.originAmount,\n transaction.destAmount,\n rebate\n );\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes memory request, bytes32 destTxHash) external onlyRole(RELAYER_ROLE) {\n bytes32 transactionId = keccak256(request);\n // update bridge tx status given proof provided\n if (bridgeStatuses[transactionId] != BridgeStatus.REQUESTED) revert StatusIncorrect();\n bridgeStatuses[transactionId] = BridgeStatus.RELAYER_PROVED;\n bridgeProofs[transactionId] = BridgeProof({timestamp: uint96(block.timestamp), relayer: msg.sender}); // overflow ok\n\n emit BridgeProofProvided(transactionId, msg.sender, destTxHash);\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint96(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint96).max but\n /// proof.timestamp \u003c type(uint96).max via unchecked statement\n /// @param proof The bridge proof\n /// @return delta Time delta since proof submitted\n function _timeSince(BridgeProof memory proof) internal view returns (uint256 delta) {\n unchecked {\n delta = uint96(block.timestamp) - proof.timestamp;\n }\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n if (bridgeStatuses[transactionId] != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n BridgeProof memory proof = bridgeProofs[transactionId];\n if (proof.relayer != relayer) revert SenderIncorrect();\n return _timeSince(proof) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes memory request, address to) external onlyRole(RELAYER_ROLE) {\n bytes32 transactionId = keccak256(request);\n BridgeTransaction memory transaction = getBridgeTransaction(request);\n\n // update bridge tx status if able to claim origin collateral\n if (bridgeStatuses[transactionId] != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n\n BridgeProof memory proof = bridgeProofs[transactionId];\n if (proof.relayer != msg.sender) revert SenderIncorrect();\n if (_timeSince(proof) \u003c= DISPUTE_PERIOD) revert DisputePeriodNotPassed();\n\n bridgeStatuses[transactionId] = BridgeStatus.RELAYER_CLAIMED;\n\n // update protocol fees if origin fee amount exists\n if (transaction.originFeeAmount \u003e 0) protocolFees[transaction.originToken] += transaction.originFeeAmount;\n\n // transfer origin collateral less fee to specified address\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositClaimed(transactionId, msg.sender, to, token, amount);\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n if (bridgeStatuses[transactionId] != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(bridgeProofs[transactionId]) \u003e DISPUTE_PERIOD) revert DisputePeriodPassed();\n\n // @dev relayer gets slashed effectively if dest relay has gone thru\n bridgeStatuses[transactionId] = BridgeStatus.REQUESTED;\n delete bridgeProofs[transactionId];\n\n emit BridgeProofDisputed(transactionId, msg.sender);\n }\n\n /// @inheritdoc IFastBridge\n function refund(bytes memory request) external {\n bytes32 transactionId = keccak256(request);\n BridgeTransaction memory transaction = getBridgeTransaction(request);\n\n if (hasRole(REFUNDER_ROLE, msg.sender)) {\n // Refunder can refund if deadline has passed\n if (block.timestamp \u003c= transaction.deadline) revert DeadlineNotExceeded();\n } else {\n // Permissionless refund is allowed after REFUND_DELAY\n if (block.timestamp \u003c= transaction.deadline + REFUND_DELAY) revert DeadlineNotExceeded();\n }\n\n // set status to refunded if still in requested state\n if (bridgeStatuses[transactionId] != BridgeStatus.REQUESTED) revert StatusIncorrect();\n bridgeStatuses[transactionId] = BridgeStatus.REFUNDED;\n\n // transfer origin collateral back to original sender\n address to = transaction.originSender;\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount + transaction.originFeeAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n }\n}\n\n// test/FastBridgeMock.sol\n\ncontract FastBridgeMock is IFastBridge, Admin {\n // @dev the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @dev to prevent replays\n uint256 public nonce;\n\n /// @notice We include an empty \"test\" function so that this contract does not appear in the coverage report.\n function testFastBridgeMock() external {}\n\n function getBridgeTransaction(bytes memory request) public pure returns (BridgeTransaction memory) {\n return abi.decode(request, (BridgeTransaction));\n }\n\n // used for testing in go.\n // see: https://ethereum.stackexchange.com/questions/21155/how-to-expose-enum-in-solidity-contract\n // make sure to update fastbridge/status.go if this changes\n // or underliyng enum changes.\n //\n // TODO: a foundry test should be added to ensure this is always in sync.\n function getEnumKeyByValue(FastBridge.BridgeStatus keyValue) public pure returns (string memory) {\n if (FastBridge.BridgeStatus.NULL == keyValue) return \"NULL\";\n if (FastBridge.BridgeStatus.REQUESTED == keyValue) return \"REQUESTED\";\n if (FastBridge.BridgeStatus.RELAYER_PROVED == keyValue) return \"RELAYER_PROVED\";\n if (FastBridge.BridgeStatus.RELAYER_CLAIMED == keyValue) return \"RELAYER_CLAIMED\";\n if (FastBridge.BridgeStatus.REFUNDED == keyValue) return \"REFUNDED\";\n return \"\";\n }\n\n function mockBridgeRequest(bytes32 transactionId, address sender, BridgeParams memory params) external {\n sender;\n uint256 originFeeAmount = (params.originAmount * protocolFeeRate) / FEE_BPS;\n params.originAmount -= originFeeAmount;\n\n bytes memory request = abi.encode(\n BridgeTransaction({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: params.originAmount, // includes relayer fee\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n sendChainGas: params.sendChainGas,\n deadline: params.deadline,\n nonce: nonce++ // increment nonce on every bridge\n })\n );\n\n emit BridgeRequested(\n transactionId,\n params.sender,\n request,\n params.dstChainId,\n params.originToken,\n params.destToken,\n params.originAmount,\n params.destAmount,\n params.sendChainGas\n );\n }\n\n function mockBridgeRequestRaw(bytes32 transactionId, address sender, bytes memory request) external {\n sender;\n BridgeTransaction memory transaction = getBridgeTransaction(request);\n emit BridgeRequested(\n transactionId,\n transaction.originSender,\n request,\n transaction.destChainId,\n transaction.originToken,\n transaction.destToken,\n transaction.originAmount,\n transaction.destAmount,\n transaction.sendChainGas\n );\n }\n\n function mockBridgeRelayer(\n bytes32 transactionId,\n address relayer,\n address to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n )\n external\n {\n emit BridgeRelayed(\n transactionId, relayer, to, originChainId, originToken, destToken, originAmount, destAmount, chainGasAmount\n );\n }\n\n function bridge(BridgeParams memory) external payable {\n revert(\"not implemented\");\n }\n\n function relay(bytes memory) external payable {\n revert(\"not implemented\");\n }\n\n function prove(bytes memory, bytes32) external pure {\n revert(\"not implemented\");\n }\n\n function canClaim(bytes32, address) external pure returns (bool) {\n revert(\"not implemented\");\n }\n\n function claim(bytes memory, address) external pure {\n revert(\"not implemented\");\n }\n\n function dispute(bytes32) external pure {\n revert(\"not implemented\");\n }\n\n function refund(bytes memory) external pure {\n revert(\"not implemented\");\n }\n}\n","language":"Solidity","languageVersion":"0.8.20","compilerVersion":"0.8.20","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"43874:5018:0:-:0;;;;;;;;;;;;;;;-1:-1:-1;;;43874:5018:0;;;;;;;;;;;;;;;;;","srcMapRuntime":"43874:5018:0:-:0;;;;;;;;","abiDefinition":[{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"currentAllowance","type":"uint256"},{"internalType":"uint256","name":"requestedDecrease","type":"uint256"}],"name":"SafeERC20FailedDecreaseAllowance","type":"error"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"SafeERC20FailedOperation","type":"error"}],"userDoc":{"kind":"user","methods":{},"version":1},"developerDoc":{"details":"Wrappers around ERC20 operations that throw on failure (when the token contract returns false). Tokens that return no value (and instead revert or throw on failure) are also supported, non-reverting calls are assumed to be successful. To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract, which allows you to call the safe operations as `token.safeTransfer(...)`, etc.","errors":{"SafeERC20FailedDecreaseAllowance(address,uint256,uint256)":[{"details":"Indicates a failed `decreaseAllowance` request."}],"SafeERC20FailedOperation(address)":[{"details":"An operation with an ERC20 token failed."}]},"kind":"dev","methods":{},"title":"SafeERC20","version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.20+commit.a1b79de6\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"currentAllowance\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"requestedDecrease\",\"type\":\"uint256\"}],\"name\":\"SafeERC20FailedDecreaseAllowance\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"}],\"name\":\"SafeERC20FailedOperation\",\"type\":\"error\"}],\"devdoc\":{\"details\":\"Wrappers around ERC20 operations that throw on failure (when the token contract returns false). Tokens that return no value (and instead revert or throw on failure) are also supported, non-reverting calls are assumed to be successful. To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract, which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\",\"errors\":{\"SafeERC20FailedDecreaseAllowance(address,uint256,uint256)\":[{\"details\":\"Indicates a failed `decreaseAllowance` request.\"}],\"SafeERC20FailedOperation(address)\":[{\"details\":\"An operation with an ERC20 token failed.\"}]},\"kind\":\"dev\",\"methods\":{},\"title\":\"SafeERC20\",\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeMock.sol\":\"SafeERC20\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeMock.sol\":{\"keccak256\":\"0xf2751f52f8216801d500da7464ad01f3c23a8286e155e2dcba6d21d6e7fd95a0\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://85d2edab24ebe321043d2b88038437e8f443a0ef26fa2139c72dcc2bc7fbc602\",\"dweb:/ipfs/QmcULiFPFJzFDT4aupVSDreXz8uHxcABb5nxpAG4zYzfNN\"]}},\"version\":1}"},"hashes":{}},"solidity/FastBridgeMock.sol:UniversalTokenLib":{"code":"0x60566037600b82828239805160001a607314602a57634e487b7160e01b600052600060045260246000fd5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600080fdfea264697066735822122087b87767f0bafa66071dc27ec91229435afb6d496e62ef4ad0e258952a2f5c9064736f6c63430008140033","runtime-code":"0x73000000000000000000000000000000000000000030146080604052600080fdfea264697066735822122087b87767f0bafa66071dc27ec91229435afb6d496e62ef4ad0e258952a2f5c9064736f6c63430008140033","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.20 ^0.8.20 ^0.8.4;\n\n// contracts/interfaces/IAdmin.sol\n\ninterface IAdmin {\n // ============ Events ============\n\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n event ChainGasAmountUpdated(uint256 oldChainGasAmount, uint256 newChainGasAmount);\n\n // ============ Methods ============\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n\n function setChainGasAmount(uint256 newChainGasAmount) external;\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IMulticallTarget.sol\n\n/// @notice Interface for a contract that can be called multiple times by the same caller. Inspired by MulticallV3:\n/// https://github.com/mds1/multicall/blob/master/src/Multicall3.sol\ninterface IMulticallTarget {\n struct Result {\n bool success;\n bytes returnData;\n }\n\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external;\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results);\n}\n\n// contracts/libs/Errors.sol\n\nerror DeadlineExceeded();\nerror DeadlineNotExceeded();\nerror DeadlineTooShort();\nerror InsufficientOutputAmount();\n\nerror MsgValueIncorrect();\nerror PoolNotFound();\nerror TokenAddressMismatch();\nerror TokenNotContract();\nerror TokenNotETH();\nerror TokensIdentical();\n\nerror ChainIncorrect();\nerror AmountIncorrect();\nerror ZeroAddress();\n\nerror DisputePeriodNotPassed();\nerror DisputePeriodPassed();\nerror SenderIncorrect();\nerror StatusIncorrect();\nerror TransactionIdIncorrect();\nerror TransactionRelayed();\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// contracts/utils/MulticallTarget.sol\n\n// solhint-disable avoid-low-level-calls\n/// @notice Template for a contract that supports batched calls (preserving the msg.sender).\n/// Only calls with zero msg.value could be batched.\nabstract contract MulticallTarget is IMulticallTarget {\n error MulticallTarget__UndeterminedRevert();\n\n /// @notice Perform a batched call to this contract, preserving the msg.sender.\n /// The return data from each call is discarded.\n /// @dev The method is non-payable, so only calls with `msg.value == 0` could be batched.\n /// It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag.\n /// Otherwise, the whole batch call will be reverted with the original revert reason.\n /// @param data List of abi-encoded calldata for the calls to perform.\n /// @param ignoreReverts Whether to ignore the revert errors from the calls.\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external {\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\n if (!success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(result);\n }\n }\n }\n\n /// @notice Perform a batched call to this contract, preserving the msg.sender.\n /// The return data from each call is preserved.\n /// @dev The method is non-payable, so only calls with `msg.value == 0` could be batched.\n /// It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag.\n /// Otherwise, the whole batch call will be reverted with the original revert reason.\n /// @param data List of abi-encoded calldata for the calls to perform.\n /// @param ignoreReverts Whether to ignore the revert errors from the calls.\n /// @return results List of results from the calls: `(success, returnData)`.\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results)\n {\n results = new Result[](data.length);\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (results[i].success, results[i].returnData) = address(this).delegatecall(data[i]);\n if (!results[i].success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(results[i].returnData);\n }\n }\n }\n\n /// @dev Bubbles the revert message from the underlying call.\n /// Note: preserves the same custom error or revert string, if one was used.\n /// Source: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v5.0.2/contracts/utils/Address.sol#L143-L158\n function _bubbleRevert(bytes memory returnData) internal pure {\n // Look for revert reason and bubble it up if present\n if (returnData.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n // solhint-disable-next-line no-inline-assembly\n assembly {\n let returndata_size := mload(returnData)\n revert(add(32, returnData), returndata_size)\n }\n } else {\n revert MulticallTarget__UndeterminedRevert();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// contracts/libs/UniversalToken.sol\n\nlibrary UniversalTokenLib {\n using SafeERC20 for IERC20;\n\n address internal constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Transfers tokens to the given account. Reverts if transfer is not successful.\n /// @dev This might trigger fallback, if ETH is transferred to the contract.\n /// Make sure this can not lead to reentrancy attacks.\n function universalTransfer(address token, address to, uint256 value) internal {\n // Don't do anything, if need to send tokens to this address\n if (to == address(this)) return;\n // Don't do anything, if trying to send zero value\n if (value == 0) return;\n if (token == ETH_ADDRESS) {\n /// @dev Note: this can potentially lead to executing code in `to`.\n // solhint-disable-next-line avoid-low-level-calls\n (bool success,) = to.call{value: value}(\"\");\n require(success, \"ETH transfer failed\");\n } else {\n IERC20(token).safeTransfer(to, value);\n }\n }\n\n /// @notice Issues an infinite allowance to the spender, if the current allowance is insufficient\n /// to spend the given amount.\n function universalApproveInfinity(address token, address spender, uint256 amountToSpend) internal {\n // ETH Chad doesn't require your approval\n if (token == ETH_ADDRESS) return;\n // No-op if allowance is already sufficient\n uint256 allowance = IERC20(token).allowance(address(this), spender);\n if (allowance \u003e= amountToSpend) return;\n // Otherwise, reset approval to 0 and set to max allowance\n if (allowance \u003e 0) IERC20(token).safeDecreaseAllowance(spender, allowance);\n IERC20(token).safeIncreaseAllowance(spender, type(uint256).max);\n }\n\n /// @notice Returns the balance of the given token (or native ETH) for the given account.\n function universalBalanceOf(address token, address account) internal view returns (uint256) {\n if (token == ETH_ADDRESS) {\n return account.balance;\n } else {\n return IERC20(token).balanceOf(account);\n }\n }\n\n /// @dev Checks that token is a contract and not ETH_ADDRESS.\n function assertIsContract(address token) internal view {\n // Check that ETH_ADDRESS was not used (in case this is a predeploy on any of the chains)\n if (token == UniversalTokenLib.ETH_ADDRESS) revert TokenNotContract();\n // Check that token is not an EOA\n if (token.code.length == 0) revert TokenNotContract();\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/Admin.sol\n\ncontract Admin is IAdmin, AccessControlEnumerable {\n using UniversalTokenLib for address;\n\n bytes32 public constant RELAYER_ROLE = keccak256(\"RELAYER_ROLE\");\n bytes32 public constant REFUNDER_ROLE = keccak256(\"REFUNDER_ROLE\");\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n uint256 public constant FEE_BPS = 1e6;\n uint256 public constant FEE_RATE_MAX = 0.01e6; // max 1% on origin amount\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Chain gas amount to forward as rebate if requested\n uint256 public chainGasAmount;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n }\n\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n require(newFeeRate \u003c= FEE_RATE_MAX, \"newFeeRate \u003e max\");\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n token.universalTransfer(recipient, feeAmount);\n emit FeesSwept(token, recipient, feeAmount);\n }\n\n function setChainGasAmount(uint256 newChainGasAmount) external onlyRole(GOVERNOR_ROLE) {\n uint256 oldChainGasAmount = chainGasAmount;\n chainGasAmount = newChainGasAmount;\n emit ChainGasAmountUpdated(oldChainGasAmount, newChainGasAmount);\n }\n}\n\n// contracts/FastBridge.sol\n\ncontract FastBridge is IFastBridge, MulticallTarget, Admin {\n using SafeERC20 for IERC20;\n using UniversalTokenLib for address;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Delay for a transaction after which it could be permisionlessly refunded\n uint256 public constant REFUND_DELAY = 7 days;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeStatus) public bridgeStatuses;\n /// @notice Proof of relayed bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeProof) public bridgeProofs;\n /// @notice Whether bridge has been relayed on destination chain\n mapping(bytes32 =\u003e bool) public bridgeRelays;\n\n /// @dev to prevent replays\n uint256 public nonce;\n // @dev the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @notice Pulls a requested token from the user to the requested recipient.\n /// @dev Be careful of re-entrancy issues when msg.value \u003e 0 and recipient != address(this)\n function _pullToken(address recipient, address token, uint256 amount) internal returns (uint256 amountPulled) {\n if (token != UniversalTokenLib.ETH_ADDRESS) {\n token.assertIsContract();\n // Record token balance before transfer\n amountPulled = IERC20(token).balanceOf(recipient);\n // Token needs to be pulled only if msg.value is zero\n // This way user can specify WETH as the origin asset\n IERC20(token).safeTransferFrom(msg.sender, recipient, amount);\n // Use the difference between the recorded balance and the current balance as the amountPulled\n amountPulled = IERC20(token).balanceOf(recipient) - amountPulled;\n } else {\n // Otherwise, we need to check that ETH amount matches msg.value\n if (amount != msg.value) revert MsgValueIncorrect();\n // Transfer value to recipient if not this address\n if (recipient != address(this)) token.universalTransfer(recipient, amount);\n // We will forward msg.value in the external call later, if recipient is not this contract\n amountPulled = msg.value;\n }\n }\n\n /// @inheritdoc IFastBridge\n function getBridgeTransaction(bytes memory request) public pure returns (BridgeTransaction memory) {\n return abi.decode(request, (BridgeTransaction));\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n // check bridge params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n\n // transfer tokens to bridge contract\n // @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _pullToken(address(this), params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n\n // set status to requested\n bytes memory request = abi.encode(\n BridgeTransaction({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n sendChainGas: params.sendChainGas,\n deadline: params.deadline,\n nonce: nonce++ // increment nonce on every bridge\n })\n );\n bytes32 transactionId = keccak256(request);\n bridgeStatuses[transactionId] = BridgeStatus.REQUESTED;\n\n emit BridgeRequested(\n transactionId,\n params.sender,\n request,\n params.dstChainId,\n params.originToken,\n params.destToken,\n originAmount,\n params.destAmount,\n params.sendChainGas\n );\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes memory request) external payable onlyRole(RELAYER_ROLE) {\n bytes32 transactionId = keccak256(request);\n BridgeTransaction memory transaction = getBridgeTransaction(request);\n if (transaction.destChainId != uint32(block.chainid)) revert ChainIncorrect();\n\n // check haven't exceeded deadline for relay to happen\n if (block.timestamp \u003e transaction.deadline) revert DeadlineExceeded();\n\n // mark bridge transaction as relayed\n if (bridgeRelays[transactionId]) revert TransactionRelayed();\n bridgeRelays[transactionId] = true;\n\n // transfer tokens to recipient on destination chain and gas rebate if requested\n address to = transaction.destRecipient;\n address token = transaction.destToken;\n uint256 amount = transaction.destAmount;\n\n uint256 rebate = chainGasAmount;\n if (!transaction.sendChainGas) {\n // forward erc20\n rebate = 0;\n _pullToken(to, token, amount);\n } else if (token == UniversalTokenLib.ETH_ADDRESS) {\n // lump in gas rebate into amount in native gas token\n _pullToken(to, token, amount + rebate);\n } else {\n // forward erc20 then forward gas rebate in native gas token\n _pullToken(to, token, amount);\n _pullToken(to, UniversalTokenLib.ETH_ADDRESS, rebate);\n }\n\n emit BridgeRelayed(\n transactionId,\n msg.sender,\n to,\n transaction.originChainId,\n transaction.originToken,\n transaction.destToken,\n transaction.originAmount,\n transaction.destAmount,\n rebate\n );\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes memory request, bytes32 destTxHash) external onlyRole(RELAYER_ROLE) {\n bytes32 transactionId = keccak256(request);\n // update bridge tx status given proof provided\n if (bridgeStatuses[transactionId] != BridgeStatus.REQUESTED) revert StatusIncorrect();\n bridgeStatuses[transactionId] = BridgeStatus.RELAYER_PROVED;\n bridgeProofs[transactionId] = BridgeProof({timestamp: uint96(block.timestamp), relayer: msg.sender}); // overflow ok\n\n emit BridgeProofProvided(transactionId, msg.sender, destTxHash);\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint96(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint96).max but\n /// proof.timestamp \u003c type(uint96).max via unchecked statement\n /// @param proof The bridge proof\n /// @return delta Time delta since proof submitted\n function _timeSince(BridgeProof memory proof) internal view returns (uint256 delta) {\n unchecked {\n delta = uint96(block.timestamp) - proof.timestamp;\n }\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n if (bridgeStatuses[transactionId] != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n BridgeProof memory proof = bridgeProofs[transactionId];\n if (proof.relayer != relayer) revert SenderIncorrect();\n return _timeSince(proof) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes memory request, address to) external onlyRole(RELAYER_ROLE) {\n bytes32 transactionId = keccak256(request);\n BridgeTransaction memory transaction = getBridgeTransaction(request);\n\n // update bridge tx status if able to claim origin collateral\n if (bridgeStatuses[transactionId] != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n\n BridgeProof memory proof = bridgeProofs[transactionId];\n if (proof.relayer != msg.sender) revert SenderIncorrect();\n if (_timeSince(proof) \u003c= DISPUTE_PERIOD) revert DisputePeriodNotPassed();\n\n bridgeStatuses[transactionId] = BridgeStatus.RELAYER_CLAIMED;\n\n // update protocol fees if origin fee amount exists\n if (transaction.originFeeAmount \u003e 0) protocolFees[transaction.originToken] += transaction.originFeeAmount;\n\n // transfer origin collateral less fee to specified address\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositClaimed(transactionId, msg.sender, to, token, amount);\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n if (bridgeStatuses[transactionId] != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(bridgeProofs[transactionId]) \u003e DISPUTE_PERIOD) revert DisputePeriodPassed();\n\n // @dev relayer gets slashed effectively if dest relay has gone thru\n bridgeStatuses[transactionId] = BridgeStatus.REQUESTED;\n delete bridgeProofs[transactionId];\n\n emit BridgeProofDisputed(transactionId, msg.sender);\n }\n\n /// @inheritdoc IFastBridge\n function refund(bytes memory request) external {\n bytes32 transactionId = keccak256(request);\n BridgeTransaction memory transaction = getBridgeTransaction(request);\n\n if (hasRole(REFUNDER_ROLE, msg.sender)) {\n // Refunder can refund if deadline has passed\n if (block.timestamp \u003c= transaction.deadline) revert DeadlineNotExceeded();\n } else {\n // Permissionless refund is allowed after REFUND_DELAY\n if (block.timestamp \u003c= transaction.deadline + REFUND_DELAY) revert DeadlineNotExceeded();\n }\n\n // set status to refunded if still in requested state\n if (bridgeStatuses[transactionId] != BridgeStatus.REQUESTED) revert StatusIncorrect();\n bridgeStatuses[transactionId] = BridgeStatus.REFUNDED;\n\n // transfer origin collateral back to original sender\n address to = transaction.originSender;\n address token = transaction.originToken;\n uint256 amount = transaction.originAmount + transaction.originFeeAmount;\n token.universalTransfer(to, amount);\n\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n }\n}\n\n// test/FastBridgeMock.sol\n\ncontract FastBridgeMock is IFastBridge, Admin {\n // @dev the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @dev to prevent replays\n uint256 public nonce;\n\n /// @notice We include an empty \"test\" function so that this contract does not appear in the coverage report.\n function testFastBridgeMock() external {}\n\n function getBridgeTransaction(bytes memory request) public pure returns (BridgeTransaction memory) {\n return abi.decode(request, (BridgeTransaction));\n }\n\n // used for testing in go.\n // see: https://ethereum.stackexchange.com/questions/21155/how-to-expose-enum-in-solidity-contract\n // make sure to update fastbridge/status.go if this changes\n // or underliyng enum changes.\n //\n // TODO: a foundry test should be added to ensure this is always in sync.\n function getEnumKeyByValue(FastBridge.BridgeStatus keyValue) public pure returns (string memory) {\n if (FastBridge.BridgeStatus.NULL == keyValue) return \"NULL\";\n if (FastBridge.BridgeStatus.REQUESTED == keyValue) return \"REQUESTED\";\n if (FastBridge.BridgeStatus.RELAYER_PROVED == keyValue) return \"RELAYER_PROVED\";\n if (FastBridge.BridgeStatus.RELAYER_CLAIMED == keyValue) return \"RELAYER_CLAIMED\";\n if (FastBridge.BridgeStatus.REFUNDED == keyValue) return \"REFUNDED\";\n return \"\";\n }\n\n function mockBridgeRequest(bytes32 transactionId, address sender, BridgeParams memory params) external {\n sender;\n uint256 originFeeAmount = (params.originAmount * protocolFeeRate) / FEE_BPS;\n params.originAmount -= originFeeAmount;\n\n bytes memory request = abi.encode(\n BridgeTransaction({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: params.originAmount, // includes relayer fee\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n sendChainGas: params.sendChainGas,\n deadline: params.deadline,\n nonce: nonce++ // increment nonce on every bridge\n })\n );\n\n emit BridgeRequested(\n transactionId,\n params.sender,\n request,\n params.dstChainId,\n params.originToken,\n params.destToken,\n params.originAmount,\n params.destAmount,\n params.sendChainGas\n );\n }\n\n function mockBridgeRequestRaw(bytes32 transactionId, address sender, bytes memory request) external {\n sender;\n BridgeTransaction memory transaction = getBridgeTransaction(request);\n emit BridgeRequested(\n transactionId,\n transaction.originSender,\n request,\n transaction.destChainId,\n transaction.originToken,\n transaction.destToken,\n transaction.originAmount,\n transaction.destAmount,\n transaction.sendChainGas\n );\n }\n\n function mockBridgeRelayer(\n bytes32 transactionId,\n address relayer,\n address to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n )\n external\n {\n emit BridgeRelayed(\n transactionId, relayer, to, originChainId, originToken, destToken, originAmount, destAmount, chainGasAmount\n );\n }\n\n function bridge(BridgeParams memory) external payable {\n revert(\"not implemented\");\n }\n\n function relay(bytes memory) external payable {\n revert(\"not implemented\");\n }\n\n function prove(bytes memory, bytes32) external pure {\n revert(\"not implemented\");\n }\n\n function canClaim(bytes32, address) external pure returns (bool) {\n revert(\"not implemented\");\n }\n\n function claim(bytes memory, address) external pure {\n revert(\"not implemented\");\n }\n\n function dispute(bytes32) external pure {\n revert(\"not implemented\");\n }\n\n function refund(bytes memory) external pure {\n revert(\"not implemented\");\n }\n}\n","language":"Solidity","languageVersion":"0.8.20","compilerVersion":"0.8.20","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"55833:2551:0:-:0;;;;;;;;;;;;;;;-1:-1:-1;;;55833:2551:0;;;;;;;;;;;;;;;;;","srcMapRuntime":"55833:2551:0:-:0;;;;;;;;","abiDefinition":[],"userDoc":{"kind":"user","methods":{},"version":1},"developerDoc":{"kind":"dev","methods":{},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.20+commit.a1b79de6\"},\"language\":\"Solidity\",\"output\":{\"abi\":[],\"devdoc\":{\"kind\":\"dev\",\"methods\":{},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeMock.sol\":\"UniversalTokenLib\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeMock.sol\":{\"keccak256\":\"0xf2751f52f8216801d500da7464ad01f3c23a8286e155e2dcba6d21d6e7fd95a0\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://85d2edab24ebe321043d2b88038437e8f443a0ef26fa2139c72dcc2bc7fbc602\",\"dweb:/ipfs/QmcULiFPFJzFDT4aupVSDreXz8uHxcABb5nxpAG4zYzfNN\"]}},\"version\":1}"},"hashes":{}}} \ No newline at end of file diff --git a/services/rfq/contracts/testcontracts/recipientmock/recipientmock.abigen.go b/services/rfq/contracts/testcontracts/recipientmock/recipientmock.abigen.go index 05fdb417a5..0df68b9d44 100644 --- a/services/rfq/contracts/testcontracts/recipientmock/recipientmock.abigen.go +++ b/services/rfq/contracts/testcontracts/recipientmock/recipientmock.abigen.go @@ -29,120 +29,120 @@ var ( _ = abi.ConvertType ) -// IFastBridgeRecipientMetaData contains all meta data concerning the IFastBridgeRecipient contract. -var IFastBridgeRecipientMetaData = &bind.MetaData{ - ABI: "[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"callParams\",\"type\":\"bytes\"}],\"name\":\"fastBridgeTransferReceived\",\"outputs\":[{\"internalType\":\"bytes4\",\"name\":\"\",\"type\":\"bytes4\"}],\"stateMutability\":\"payable\",\"type\":\"function\"}]", +// IZapRecipientMetaData contains all meta data concerning the IZapRecipient contract. +var IZapRecipientMetaData = &bind.MetaData{ + ABI: "[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"zapData\",\"type\":\"bytes\"}],\"name\":\"zap\",\"outputs\":[{\"internalType\":\"bytes4\",\"name\":\"\",\"type\":\"bytes4\"}],\"stateMutability\":\"payable\",\"type\":\"function\"}]", Sigs: map[string]string{ - "461e0c21": "fastBridgeTransferReceived(address,uint256,bytes)", + "e85e13dd": "zap(address,uint256,bytes)", }, } -// IFastBridgeRecipientABI is the input ABI used to generate the binding from. -// Deprecated: Use IFastBridgeRecipientMetaData.ABI instead. -var IFastBridgeRecipientABI = IFastBridgeRecipientMetaData.ABI +// IZapRecipientABI is the input ABI used to generate the binding from. +// Deprecated: Use IZapRecipientMetaData.ABI instead. +var IZapRecipientABI = IZapRecipientMetaData.ABI -// Deprecated: Use IFastBridgeRecipientMetaData.Sigs instead. -// IFastBridgeRecipientFuncSigs maps the 4-byte function signature to its string representation. -var IFastBridgeRecipientFuncSigs = IFastBridgeRecipientMetaData.Sigs +// Deprecated: Use IZapRecipientMetaData.Sigs instead. +// IZapRecipientFuncSigs maps the 4-byte function signature to its string representation. +var IZapRecipientFuncSigs = IZapRecipientMetaData.Sigs -// IFastBridgeRecipient is an auto generated Go binding around an Ethereum contract. -type IFastBridgeRecipient struct { - IFastBridgeRecipientCaller // Read-only binding to the contract - IFastBridgeRecipientTransactor // Write-only binding to the contract - IFastBridgeRecipientFilterer // Log filterer for contract events +// IZapRecipient is an auto generated Go binding around an Ethereum contract. +type IZapRecipient struct { + IZapRecipientCaller // Read-only binding to the contract + IZapRecipientTransactor // Write-only binding to the contract + IZapRecipientFilterer // Log filterer for contract events } -// IFastBridgeRecipientCaller is an auto generated read-only Go binding around an Ethereum contract. -type IFastBridgeRecipientCaller struct { +// IZapRecipientCaller is an auto generated read-only Go binding around an Ethereum contract. +type IZapRecipientCaller struct { contract *bind.BoundContract // Generic contract wrapper for the low level calls } -// IFastBridgeRecipientTransactor is an auto generated write-only Go binding around an Ethereum contract. -type IFastBridgeRecipientTransactor struct { +// IZapRecipientTransactor is an auto generated write-only Go binding around an Ethereum contract. +type IZapRecipientTransactor struct { contract *bind.BoundContract // Generic contract wrapper for the low level calls } -// IFastBridgeRecipientFilterer is an auto generated log filtering Go binding around an Ethereum contract events. -type IFastBridgeRecipientFilterer struct { +// IZapRecipientFilterer is an auto generated log filtering Go binding around an Ethereum contract events. +type IZapRecipientFilterer struct { contract *bind.BoundContract // Generic contract wrapper for the low level calls } -// IFastBridgeRecipientSession is an auto generated Go binding around an Ethereum contract, +// IZapRecipientSession is an auto generated Go binding around an Ethereum contract, // with pre-set call and transact options. -type IFastBridgeRecipientSession struct { - Contract *IFastBridgeRecipient // Generic contract binding to set the session for - CallOpts bind.CallOpts // Call options to use throughout this session - TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +type IZapRecipientSession struct { + Contract *IZapRecipient // Generic contract binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session } -// IFastBridgeRecipientCallerSession is an auto generated read-only Go binding around an Ethereum contract, +// IZapRecipientCallerSession is an auto generated read-only Go binding around an Ethereum contract, // with pre-set call options. -type IFastBridgeRecipientCallerSession struct { - Contract *IFastBridgeRecipientCaller // Generic contract caller binding to set the session for - CallOpts bind.CallOpts // Call options to use throughout this session +type IZapRecipientCallerSession struct { + Contract *IZapRecipientCaller // Generic contract caller binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session } -// IFastBridgeRecipientTransactorSession is an auto generated write-only Go binding around an Ethereum contract, +// IZapRecipientTransactorSession is an auto generated write-only Go binding around an Ethereum contract, // with pre-set transact options. -type IFastBridgeRecipientTransactorSession struct { - Contract *IFastBridgeRecipientTransactor // Generic contract transactor binding to set the session for - TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +type IZapRecipientTransactorSession struct { + Contract *IZapRecipientTransactor // Generic contract transactor binding to set the session for + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session } -// IFastBridgeRecipientRaw is an auto generated low-level Go binding around an Ethereum contract. -type IFastBridgeRecipientRaw struct { - Contract *IFastBridgeRecipient // Generic contract binding to access the raw methods on +// IZapRecipientRaw is an auto generated low-level Go binding around an Ethereum contract. +type IZapRecipientRaw struct { + Contract *IZapRecipient // Generic contract binding to access the raw methods on } -// IFastBridgeRecipientCallerRaw is an auto generated low-level read-only Go binding around an Ethereum contract. -type IFastBridgeRecipientCallerRaw struct { - Contract *IFastBridgeRecipientCaller // Generic read-only contract binding to access the raw methods on +// IZapRecipientCallerRaw is an auto generated low-level read-only Go binding around an Ethereum contract. +type IZapRecipientCallerRaw struct { + Contract *IZapRecipientCaller // Generic read-only contract binding to access the raw methods on } -// IFastBridgeRecipientTransactorRaw is an auto generated low-level write-only Go binding around an Ethereum contract. -type IFastBridgeRecipientTransactorRaw struct { - Contract *IFastBridgeRecipientTransactor // Generic write-only contract binding to access the raw methods on +// IZapRecipientTransactorRaw is an auto generated low-level write-only Go binding around an Ethereum contract. +type IZapRecipientTransactorRaw struct { + Contract *IZapRecipientTransactor // Generic write-only contract binding to access the raw methods on } -// NewIFastBridgeRecipient creates a new instance of IFastBridgeRecipient, bound to a specific deployed contract. -func NewIFastBridgeRecipient(address common.Address, backend bind.ContractBackend) (*IFastBridgeRecipient, error) { - contract, err := bindIFastBridgeRecipient(address, backend, backend, backend) +// NewIZapRecipient creates a new instance of IZapRecipient, bound to a specific deployed contract. +func NewIZapRecipient(address common.Address, backend bind.ContractBackend) (*IZapRecipient, error) { + contract, err := bindIZapRecipient(address, backend, backend, backend) if err != nil { return nil, err } - return &IFastBridgeRecipient{IFastBridgeRecipientCaller: IFastBridgeRecipientCaller{contract: contract}, IFastBridgeRecipientTransactor: IFastBridgeRecipientTransactor{contract: contract}, IFastBridgeRecipientFilterer: IFastBridgeRecipientFilterer{contract: contract}}, nil + return &IZapRecipient{IZapRecipientCaller: IZapRecipientCaller{contract: contract}, IZapRecipientTransactor: IZapRecipientTransactor{contract: contract}, IZapRecipientFilterer: IZapRecipientFilterer{contract: contract}}, nil } -// NewIFastBridgeRecipientCaller creates a new read-only instance of IFastBridgeRecipient, bound to a specific deployed contract. -func NewIFastBridgeRecipientCaller(address common.Address, caller bind.ContractCaller) (*IFastBridgeRecipientCaller, error) { - contract, err := bindIFastBridgeRecipient(address, caller, nil, nil) +// NewIZapRecipientCaller creates a new read-only instance of IZapRecipient, bound to a specific deployed contract. +func NewIZapRecipientCaller(address common.Address, caller bind.ContractCaller) (*IZapRecipientCaller, error) { + contract, err := bindIZapRecipient(address, caller, nil, nil) if err != nil { return nil, err } - return &IFastBridgeRecipientCaller{contract: contract}, nil + return &IZapRecipientCaller{contract: contract}, nil } -// NewIFastBridgeRecipientTransactor creates a new write-only instance of IFastBridgeRecipient, bound to a specific deployed contract. -func NewIFastBridgeRecipientTransactor(address common.Address, transactor bind.ContractTransactor) (*IFastBridgeRecipientTransactor, error) { - contract, err := bindIFastBridgeRecipient(address, nil, transactor, nil) +// NewIZapRecipientTransactor creates a new write-only instance of IZapRecipient, bound to a specific deployed contract. +func NewIZapRecipientTransactor(address common.Address, transactor bind.ContractTransactor) (*IZapRecipientTransactor, error) { + contract, err := bindIZapRecipient(address, nil, transactor, nil) if err != nil { return nil, err } - return &IFastBridgeRecipientTransactor{contract: contract}, nil + return &IZapRecipientTransactor{contract: contract}, nil } -// NewIFastBridgeRecipientFilterer creates a new log filterer instance of IFastBridgeRecipient, bound to a specific deployed contract. -func NewIFastBridgeRecipientFilterer(address common.Address, filterer bind.ContractFilterer) (*IFastBridgeRecipientFilterer, error) { - contract, err := bindIFastBridgeRecipient(address, nil, nil, filterer) +// NewIZapRecipientFilterer creates a new log filterer instance of IZapRecipient, bound to a specific deployed contract. +func NewIZapRecipientFilterer(address common.Address, filterer bind.ContractFilterer) (*IZapRecipientFilterer, error) { + contract, err := bindIZapRecipient(address, nil, nil, filterer) if err != nil { return nil, err } - return &IFastBridgeRecipientFilterer{contract: contract}, nil + return &IZapRecipientFilterer{contract: contract}, nil } -// bindIFastBridgeRecipient binds a generic wrapper to an already deployed contract. -func bindIFastBridgeRecipient(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) { - parsed, err := IFastBridgeRecipientMetaData.GetAbi() +// bindIZapRecipient binds a generic wrapper to an already deployed contract. +func bindIZapRecipient(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) { + parsed, err := IZapRecipientMetaData.GetAbi() if err != nil { return nil, err } @@ -153,68 +153,69 @@ func bindIFastBridgeRecipient(address common.Address, caller bind.ContractCaller // sets the output to result. The result type might be a single field for simple // returns, a slice of interfaces for anonymous returns and a struct for named // returns. -func (_IFastBridgeRecipient *IFastBridgeRecipientRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { - return _IFastBridgeRecipient.Contract.IFastBridgeRecipientCaller.contract.Call(opts, result, method, params...) +func (_IZapRecipient *IZapRecipientRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _IZapRecipient.Contract.IZapRecipientCaller.contract.Call(opts, result, method, params...) } // Transfer initiates a plain transaction to move funds to the contract, calling // its default method if one is available. -func (_IFastBridgeRecipient *IFastBridgeRecipientRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { - return _IFastBridgeRecipient.Contract.IFastBridgeRecipientTransactor.contract.Transfer(opts) +func (_IZapRecipient *IZapRecipientRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _IZapRecipient.Contract.IZapRecipientTransactor.contract.Transfer(opts) } // Transact invokes the (paid) contract method with params as input values. -func (_IFastBridgeRecipient *IFastBridgeRecipientRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { - return _IFastBridgeRecipient.Contract.IFastBridgeRecipientTransactor.contract.Transact(opts, method, params...) +func (_IZapRecipient *IZapRecipientRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _IZapRecipient.Contract.IZapRecipientTransactor.contract.Transact(opts, method, params...) } // Call invokes the (constant) contract method with params as input values and // sets the output to result. The result type might be a single field for simple // returns, a slice of interfaces for anonymous returns and a struct for named // returns. -func (_IFastBridgeRecipient *IFastBridgeRecipientCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { - return _IFastBridgeRecipient.Contract.contract.Call(opts, result, method, params...) +func (_IZapRecipient *IZapRecipientCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _IZapRecipient.Contract.contract.Call(opts, result, method, params...) } // Transfer initiates a plain transaction to move funds to the contract, calling // its default method if one is available. -func (_IFastBridgeRecipient *IFastBridgeRecipientTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { - return _IFastBridgeRecipient.Contract.contract.Transfer(opts) +func (_IZapRecipient *IZapRecipientTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _IZapRecipient.Contract.contract.Transfer(opts) } // Transact invokes the (paid) contract method with params as input values. -func (_IFastBridgeRecipient *IFastBridgeRecipientTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { - return _IFastBridgeRecipient.Contract.contract.Transact(opts, method, params...) +func (_IZapRecipient *IZapRecipientTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _IZapRecipient.Contract.contract.Transact(opts, method, params...) } -// FastBridgeTransferReceived is a paid mutator transaction binding the contract method 0x461e0c21. +// Zap is a paid mutator transaction binding the contract method 0xe85e13dd. // -// Solidity: function fastBridgeTransferReceived(address token, uint256 amount, bytes callParams) payable returns(bytes4) -func (_IFastBridgeRecipient *IFastBridgeRecipientTransactor) FastBridgeTransferReceived(opts *bind.TransactOpts, token common.Address, amount *big.Int, callParams []byte) (*types.Transaction, error) { - return _IFastBridgeRecipient.contract.Transact(opts, "fastBridgeTransferReceived", token, amount, callParams) +// Solidity: function zap(address token, uint256 amount, bytes zapData) payable returns(bytes4) +func (_IZapRecipient *IZapRecipientTransactor) Zap(opts *bind.TransactOpts, token common.Address, amount *big.Int, zapData []byte) (*types.Transaction, error) { + return _IZapRecipient.contract.Transact(opts, "zap", token, amount, zapData) } -// FastBridgeTransferReceived is a paid mutator transaction binding the contract method 0x461e0c21. +// Zap is a paid mutator transaction binding the contract method 0xe85e13dd. // -// Solidity: function fastBridgeTransferReceived(address token, uint256 amount, bytes callParams) payable returns(bytes4) -func (_IFastBridgeRecipient *IFastBridgeRecipientSession) FastBridgeTransferReceived(token common.Address, amount *big.Int, callParams []byte) (*types.Transaction, error) { - return _IFastBridgeRecipient.Contract.FastBridgeTransferReceived(&_IFastBridgeRecipient.TransactOpts, token, amount, callParams) +// Solidity: function zap(address token, uint256 amount, bytes zapData) payable returns(bytes4) +func (_IZapRecipient *IZapRecipientSession) Zap(token common.Address, amount *big.Int, zapData []byte) (*types.Transaction, error) { + return _IZapRecipient.Contract.Zap(&_IZapRecipient.TransactOpts, token, amount, zapData) } -// FastBridgeTransferReceived is a paid mutator transaction binding the contract method 0x461e0c21. +// Zap is a paid mutator transaction binding the contract method 0xe85e13dd. // -// Solidity: function fastBridgeTransferReceived(address token, uint256 amount, bytes callParams) payable returns(bytes4) -func (_IFastBridgeRecipient *IFastBridgeRecipientTransactorSession) FastBridgeTransferReceived(token common.Address, amount *big.Int, callParams []byte) (*types.Transaction, error) { - return _IFastBridgeRecipient.Contract.FastBridgeTransferReceived(&_IFastBridgeRecipient.TransactOpts, token, amount, callParams) +// Solidity: function zap(address token, uint256 amount, bytes zapData) payable returns(bytes4) +func (_IZapRecipient *IZapRecipientTransactorSession) Zap(token common.Address, amount *big.Int, zapData []byte) (*types.Transaction, error) { + return _IZapRecipient.Contract.Zap(&_IZapRecipient.TransactOpts, token, amount, zapData) } // RecipientMockMetaData contains all meta data concerning the RecipientMock contract. var RecipientMockMetaData = &bind.MetaData{ - ABI: "[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"name\":\"fastBridgeTransferReceived\",\"outputs\":[{\"internalType\":\"bytes4\",\"name\":\"\",\"type\":\"bytes4\"}],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"stateMutability\":\"payable\",\"type\":\"receive\"}]", + ABI: "[{\"inputs\":[],\"name\":\"testRecipientMock\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"name\":\"zap\",\"outputs\":[{\"internalType\":\"bytes4\",\"name\":\"\",\"type\":\"bytes4\"}],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"stateMutability\":\"payable\",\"type\":\"receive\"}]", Sigs: map[string]string{ - "461e0c21": "fastBridgeTransferReceived(address,uint256,bytes)", + "b239c091": "testRecipientMock()", + "e85e13dd": "zap(address,uint256,bytes)", }, - Bin: "0x608060405234801561001057600080fd5b50610202806100206000396000f3fe6080604052600436106100225760003560e01c8063461e0c211461002e57600080fd5b3661002957005b600080fd5b61006461003c3660046100c8565b7f461e0c21000000000000000000000000000000000000000000000000000000009392505050565b6040517fffffffff00000000000000000000000000000000000000000000000000000000909116815260200160405180910390f35b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6000806000606084860312156100dd57600080fd5b833573ffffffffffffffffffffffffffffffffffffffff8116811461010157600080fd5b925060208401359150604084013567ffffffffffffffff8082111561012557600080fd5b818601915086601f83011261013957600080fd5b81358181111561014b5761014b610099565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f0116810190838211818310171561019157610191610099565b816040528281528960208487010111156101aa57600080fd5b826020860160208301376000602084830101528095505050505050925092509256fea2646970667358221220f1a74d56eefc9976c67d52f3119adaca862e91740662087e97a8e47c248fbb1d64736f6c63430008140033", + Bin: "0x608060405234801561001057600080fd5b5061021b806100206000396000f3fe60806040526004361061002d5760003560e01c8063b239c09114610039578063e85e13dd1461004757600080fd5b3661003457005b600080fd5b34801561004557600080fd5b005b61007d6100553660046100e1565b7fe85e13dd000000000000000000000000000000000000000000000000000000009392505050565b6040517fffffffff00000000000000000000000000000000000000000000000000000000909116815260200160405180910390f35b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6000806000606084860312156100f657600080fd5b833573ffffffffffffffffffffffffffffffffffffffff8116811461011a57600080fd5b925060208401359150604084013567ffffffffffffffff8082111561013e57600080fd5b818601915086601f83011261015257600080fd5b813581811115610164576101646100b2565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f011681019083821181831017156101aa576101aa6100b2565b816040528281528960208487010111156101c357600080fd5b826020860160208301376000602084830101528095505050505050925092509256fea26469706673582212206a5bc8b6ce97f6638e1238777c2558656268131efa652b2ea633dc4c60fe400a64736f6c63430008140033", } // RecipientMockABI is the input ABI used to generate the binding from. @@ -388,25 +389,46 @@ func (_RecipientMock *RecipientMockTransactorRaw) Transact(opts *bind.TransactOp return _RecipientMock.Contract.contract.Transact(opts, method, params...) } -// FastBridgeTransferReceived is a paid mutator transaction binding the contract method 0x461e0c21. +// TestRecipientMock is a paid mutator transaction binding the contract method 0xb239c091. +// +// Solidity: function testRecipientMock() returns() +func (_RecipientMock *RecipientMockTransactor) TestRecipientMock(opts *bind.TransactOpts) (*types.Transaction, error) { + return _RecipientMock.contract.Transact(opts, "testRecipientMock") +} + +// TestRecipientMock is a paid mutator transaction binding the contract method 0xb239c091. +// +// Solidity: function testRecipientMock() returns() +func (_RecipientMock *RecipientMockSession) TestRecipientMock() (*types.Transaction, error) { + return _RecipientMock.Contract.TestRecipientMock(&_RecipientMock.TransactOpts) +} + +// TestRecipientMock is a paid mutator transaction binding the contract method 0xb239c091. +// +// Solidity: function testRecipientMock() returns() +func (_RecipientMock *RecipientMockTransactorSession) TestRecipientMock() (*types.Transaction, error) { + return _RecipientMock.Contract.TestRecipientMock(&_RecipientMock.TransactOpts) +} + +// Zap is a paid mutator transaction binding the contract method 0xe85e13dd. // -// Solidity: function fastBridgeTransferReceived(address , uint256 , bytes ) payable returns(bytes4) -func (_RecipientMock *RecipientMockTransactor) FastBridgeTransferReceived(opts *bind.TransactOpts, arg0 common.Address, arg1 *big.Int, arg2 []byte) (*types.Transaction, error) { - return _RecipientMock.contract.Transact(opts, "fastBridgeTransferReceived", arg0, arg1, arg2) +// Solidity: function zap(address , uint256 , bytes ) payable returns(bytes4) +func (_RecipientMock *RecipientMockTransactor) Zap(opts *bind.TransactOpts, arg0 common.Address, arg1 *big.Int, arg2 []byte) (*types.Transaction, error) { + return _RecipientMock.contract.Transact(opts, "zap", arg0, arg1, arg2) } -// FastBridgeTransferReceived is a paid mutator transaction binding the contract method 0x461e0c21. +// Zap is a paid mutator transaction binding the contract method 0xe85e13dd. // -// Solidity: function fastBridgeTransferReceived(address , uint256 , bytes ) payable returns(bytes4) -func (_RecipientMock *RecipientMockSession) FastBridgeTransferReceived(arg0 common.Address, arg1 *big.Int, arg2 []byte) (*types.Transaction, error) { - return _RecipientMock.Contract.FastBridgeTransferReceived(&_RecipientMock.TransactOpts, arg0, arg1, arg2) +// Solidity: function zap(address , uint256 , bytes ) payable returns(bytes4) +func (_RecipientMock *RecipientMockSession) Zap(arg0 common.Address, arg1 *big.Int, arg2 []byte) (*types.Transaction, error) { + return _RecipientMock.Contract.Zap(&_RecipientMock.TransactOpts, arg0, arg1, arg2) } -// FastBridgeTransferReceived is a paid mutator transaction binding the contract method 0x461e0c21. +// Zap is a paid mutator transaction binding the contract method 0xe85e13dd. // -// Solidity: function fastBridgeTransferReceived(address , uint256 , bytes ) payable returns(bytes4) -func (_RecipientMock *RecipientMockTransactorSession) FastBridgeTransferReceived(arg0 common.Address, arg1 *big.Int, arg2 []byte) (*types.Transaction, error) { - return _RecipientMock.Contract.FastBridgeTransferReceived(&_RecipientMock.TransactOpts, arg0, arg1, arg2) +// Solidity: function zap(address , uint256 , bytes ) payable returns(bytes4) +func (_RecipientMock *RecipientMockTransactorSession) Zap(arg0 common.Address, arg1 *big.Int, arg2 []byte) (*types.Transaction, error) { + return _RecipientMock.Contract.Zap(&_RecipientMock.TransactOpts, arg0, arg1, arg2) } // Receive is a paid mutator transaction binding the contract receive function. diff --git a/services/rfq/contracts/testcontracts/recipientmock/recipientmock.contractinfo.json b/services/rfq/contracts/testcontracts/recipientmock/recipientmock.contractinfo.json index 9db7be468b..201b66392d 100644 --- a/services/rfq/contracts/testcontracts/recipientmock/recipientmock.contractinfo.json +++ b/services/rfq/contracts/testcontracts/recipientmock/recipientmock.contractinfo.json @@ -1 +1 @@ -{"solidity/RecipientMock.sol:IFastBridgeRecipient":{"code":"0x","runtime-code":"0x","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\n// contracts/interfaces/IFastBridgeRecipient.sol\n\ninterface IFastBridgeRecipient {\n function fastBridgeTransferReceived(\n address token,\n uint256 amount,\n bytes memory callParams\n )\n external\n payable\n returns (bytes4);\n}\n\n// test/mocks/RecipientMock.sol\n\n/// @notice Recipient mock for testing purposes. DO NOT USE IN PRODUCTION.\ncontract RecipientMock is IFastBridgeRecipient {\n /// @notice Mock needs to accept ETH\n receive() external payable {}\n\n /// @notice Minimal viable implementation of the fastBridgeTransferReceived hook.\n function fastBridgeTransferReceived(address, uint256, bytes memory) external payable returns (bytes4) {\n return IFastBridgeRecipient.fastBridgeTransferReceived.selector;\n }\n}\n","language":"Solidity","languageVersion":"0.8.20","compilerVersion":"0.8.20","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"","srcMapRuntime":"","abiDefinition":[{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"bytes","name":"callParams","type":"bytes"}],"name":"fastBridgeTransferReceived","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"payable","type":"function"}],"userDoc":{"kind":"user","methods":{},"version":1},"developerDoc":{"kind":"dev","methods":{},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.20+commit.a1b79de6\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"callParams\",\"type\":\"bytes\"}],\"name\":\"fastBridgeTransferReceived\",\"outputs\":[{\"internalType\":\"bytes4\",\"name\":\"\",\"type\":\"bytes4\"}],\"stateMutability\":\"payable\",\"type\":\"function\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/RecipientMock.sol\":\"IFastBridgeRecipient\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/RecipientMock.sol\":{\"keccak256\":\"0xb8f940be952dc310c5d546785516c6d77f8abe7f6a852ee6ab4b3f1c33534b41\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://fb32a814c5a9088d1881eec57e12c3ebe91503be5b6be1c0c212b46bdbca89a7\",\"dweb:/ipfs/QmTQFfCjLPqVsxw7B6c4CNZMbtKJrg6mctRsTwaXqVDeLe\"]}},\"version\":1}"},"hashes":{"fastBridgeTransferReceived(address,uint256,bytes)":"461e0c21"}},"solidity/RecipientMock.sol:RecipientMock":{"code":"0x608060405234801561001057600080fd5b50610202806100206000396000f3fe6080604052600436106100225760003560e01c8063461e0c211461002e57600080fd5b3661002957005b600080fd5b61006461003c3660046100c8565b7f461e0c21000000000000000000000000000000000000000000000000000000009392505050565b6040517fffffffff00000000000000000000000000000000000000000000000000000000909116815260200160405180910390f35b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6000806000606084860312156100dd57600080fd5b833573ffffffffffffffffffffffffffffffffffffffff8116811461010157600080fd5b925060208401359150604084013567ffffffffffffffff8082111561012557600080fd5b818601915086601f83011261013957600080fd5b81358181111561014b5761014b610099565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f0116810190838211818310171561019157610191610099565b816040528281528960208487010111156101aa57600080fd5b826020860160208301376000602084830101528095505050505050925092509256fea2646970667358221220f1a74d56eefc9976c67d52f3119adaca862e91740662087e97a8e47c248fbb1d64736f6c63430008140033","runtime-code":"0x6080604052600436106100225760003560e01c8063461e0c211461002e57600080fd5b3661002957005b600080fd5b61006461003c3660046100c8565b7f461e0c21000000000000000000000000000000000000000000000000000000009392505050565b6040517fffffffff00000000000000000000000000000000000000000000000000000000909116815260200160405180910390f35b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6000806000606084860312156100dd57600080fd5b833573ffffffffffffffffffffffffffffffffffffffff8116811461010157600080fd5b925060208401359150604084013567ffffffffffffffff8082111561012557600080fd5b818601915086601f83011261013957600080fd5b81358181111561014b5761014b610099565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f0116810190838211818310171561019157610191610099565b816040528281528960208487010111156101aa57600080fd5b826020860160208301376000602084830101528095505050505050925092509256fea2646970667358221220f1a74d56eefc9976c67d52f3119adaca862e91740662087e97a8e47c248fbb1d64736f6c63430008140033","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\n// contracts/interfaces/IFastBridgeRecipient.sol\n\ninterface IFastBridgeRecipient {\n function fastBridgeTransferReceived(\n address token,\n uint256 amount,\n bytes memory callParams\n )\n external\n payable\n returns (bytes4);\n}\n\n// test/mocks/RecipientMock.sol\n\n/// @notice Recipient mock for testing purposes. DO NOT USE IN PRODUCTION.\ncontract RecipientMock is IFastBridgeRecipient {\n /// @notice Mock needs to accept ETH\n receive() external payable {}\n\n /// @notice Minimal viable implementation of the fastBridgeTransferReceived hook.\n function fastBridgeTransferReceived(address, uint256, bytes memory) external payable returns (bytes4) {\n return IFastBridgeRecipient.fastBridgeTransferReceived.selector;\n }\n}\n","language":"Solidity","languageVersion":"0.8.20","compilerVersion":"0.8.20","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"436:399:0:-:0;;;;;;;;;;;;;;;;;;;","srcMapRuntime":"436:399:0:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;651:182;;;;;;:::i;:::-;770:56;651:182;;;;;;;;;1627:66:1;1615:79;;;1597:98;;1585:2;1570:18;651:182:0;;;;;;;14:184:1;66:77;63:1;56:88;163:4;160:1;153:15;187:4;184:1;177:15;203:1245;289:6;297;305;358:2;346:9;337:7;333:23;329:32;326:52;;;374:1;371;364:12;326:52;413:9;400:23;463:42;456:5;452:54;445:5;442:65;432:93;;521:1;518;511:12;432:93;544:5;-1:-1:-1;596:2:1;581:18;;568:32;;-1:-1:-1;651:2:1;636:18;;623:32;674:18;704:14;;;701:34;;;731:1;728;721:12;701:34;769:6;758:9;754:22;744:32;;814:7;807:4;803:2;799:13;795:27;785:55;;836:1;833;826:12;785:55;872:2;859:16;894:2;890;887:10;884:36;;;900:18;;:::i;:::-;1034:2;1028:9;1096:4;1088:13;;939:66;1084:22;;;1108:2;1080:31;1076:40;1064:53;;;1132:18;;;1152:22;;;1129:46;1126:72;;;1178:18;;:::i;:::-;1218:10;1214:2;1207:22;1253:2;1245:6;1238:18;1293:7;1288:2;1283;1279;1275:11;1271:20;1268:33;1265:53;;;1314:1;1311;1304:12;1265:53;1370:2;1365;1361;1357:11;1352:2;1344:6;1340:15;1327:46;1415:1;1410:2;1405;1397:6;1393:15;1389:24;1382:35;1436:6;1426:16;;;;;;;203:1245;;;;;:::o","abiDefinition":[{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"bytes","name":"","type":"bytes"}],"name":"fastBridgeTransferReceived","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"payable","type":"function"},{"stateMutability":"payable","type":"receive"}],"userDoc":{"kind":"user","methods":{"fastBridgeTransferReceived(address,uint256,bytes)":{"notice":"Minimal viable implementation of the fastBridgeTransferReceived hook."}},"notice":"Recipient mock for testing purposes. DO NOT USE IN PRODUCTION.","version":1},"developerDoc":{"kind":"dev","methods":{},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.20+commit.a1b79de6\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"name\":\"fastBridgeTransferReceived\",\"outputs\":[{\"internalType\":\"bytes4\",\"name\":\"\",\"type\":\"bytes4\"}],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"stateMutability\":\"payable\",\"type\":\"receive\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"fastBridgeTransferReceived(address,uint256,bytes)\":{\"notice\":\"Minimal viable implementation of the fastBridgeTransferReceived hook.\"}},\"notice\":\"Recipient mock for testing purposes. DO NOT USE IN PRODUCTION.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/RecipientMock.sol\":\"RecipientMock\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/RecipientMock.sol\":{\"keccak256\":\"0xb8f940be952dc310c5d546785516c6d77f8abe7f6a852ee6ab4b3f1c33534b41\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://fb32a814c5a9088d1881eec57e12c3ebe91503be5b6be1c0c212b46bdbca89a7\",\"dweb:/ipfs/QmTQFfCjLPqVsxw7B6c4CNZMbtKJrg6mctRsTwaXqVDeLe\"]}},\"version\":1}"},"hashes":{"fastBridgeTransferReceived(address,uint256,bytes)":"461e0c21"}}} \ No newline at end of file +{"solidity/RecipientMock.sol:IZapRecipient":{"code":"0x","runtime-code":"0x","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity ^0.8.4;\n\n// contracts/interfaces/IZapRecipient.sol\n\ninterface IZapRecipient {\n function zap(address token, uint256 amount, bytes memory zapData) external payable returns (bytes4);\n}\n\n// test/mocks/RecipientMock.sol\n\n// solhint-disable no-empty-blocks\n/// @notice Recipient mock for testing purposes. DO NOT USE IN PRODUCTION.\ncontract RecipientMock is IZapRecipient {\n /// @notice Mock needs to accept ETH\n receive() external payable {}\n\n /// @notice We include an empty \"test\" function so that this contract does not appear in the coverage report.\n function testRecipientMock() external {}\n\n /// @notice Minimal viable implementation of the zap hook.\n function zap(address, uint256, bytes memory) external payable returns (bytes4) {\n return IZapRecipient.zap.selector;\n }\n}\n","language":"Solidity","languageVersion":"0.8.20","compilerVersion":"0.8.20","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"","srcMapRuntime":"","abiDefinition":[{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"bytes","name":"zapData","type":"bytes"}],"name":"zap","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"payable","type":"function"}],"userDoc":{"kind":"user","methods":{},"version":1},"developerDoc":{"kind":"dev","methods":{},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.20+commit.a1b79de6\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"zapData\",\"type\":\"bytes\"}],\"name\":\"zap\",\"outputs\":[{\"internalType\":\"bytes4\",\"name\":\"\",\"type\":\"bytes4\"}],\"stateMutability\":\"payable\",\"type\":\"function\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/RecipientMock.sol\":\"IZapRecipient\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/RecipientMock.sol\":{\"keccak256\":\"0x067e55596cf94a7c1153b5d38e7a3376d971c52b1e5401bb23be3715fbeea345\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://65911afd25e38ae2d4d6d64f8c587874da876a2b76fcb36e79f89692478ddc2a\",\"dweb:/ipfs/QmYKnsF1Xoo63nbwCVKWEc3UrpZu8UBEUNeT4CCmxSqc6Y\"]}},\"version\":1}"},"hashes":{"zap(address,uint256,bytes)":"e85e13dd"}},"solidity/RecipientMock.sol:RecipientMock":{"code":"0x608060405234801561001057600080fd5b5061021b806100206000396000f3fe60806040526004361061002d5760003560e01c8063b239c09114610039578063e85e13dd1461004757600080fd5b3661003457005b600080fd5b34801561004557600080fd5b005b61007d6100553660046100e1565b7fe85e13dd000000000000000000000000000000000000000000000000000000009392505050565b6040517fffffffff00000000000000000000000000000000000000000000000000000000909116815260200160405180910390f35b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6000806000606084860312156100f657600080fd5b833573ffffffffffffffffffffffffffffffffffffffff8116811461011a57600080fd5b925060208401359150604084013567ffffffffffffffff8082111561013e57600080fd5b818601915086601f83011261015257600080fd5b813581811115610164576101646100b2565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f011681019083821181831017156101aa576101aa6100b2565b816040528281528960208487010111156101c357600080fd5b826020860160208301376000602084830101528095505050505050925092509256fea26469706673582212206a5bc8b6ce97f6638e1238777c2558656268131efa652b2ea633dc4c60fe400a64736f6c63430008140033","runtime-code":"0x60806040526004361061002d5760003560e01c8063b239c09114610039578063e85e13dd1461004757600080fd5b3661003457005b600080fd5b34801561004557600080fd5b005b61007d6100553660046100e1565b7fe85e13dd000000000000000000000000000000000000000000000000000000009392505050565b6040517fffffffff00000000000000000000000000000000000000000000000000000000909116815260200160405180910390f35b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6000806000606084860312156100f657600080fd5b833573ffffffffffffffffffffffffffffffffffffffff8116811461011a57600080fd5b925060208401359150604084013567ffffffffffffffff8082111561013e57600080fd5b818601915086601f83011261015257600080fd5b813581811115610164576101646100b2565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f011681019083821181831017156101aa576101aa6100b2565b816040528281528960208487010111156101c357600080fd5b826020860160208301376000602084830101528095505050505050925092509256fea26469706673582212206a5bc8b6ce97f6638e1238777c2558656268131efa652b2ea633dc4c60fe400a64736f6c63430008140033","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity ^0.8.4;\n\n// contracts/interfaces/IZapRecipient.sol\n\ninterface IZapRecipient {\n function zap(address token, uint256 amount, bytes memory zapData) external payable returns (bytes4);\n}\n\n// test/mocks/RecipientMock.sol\n\n// solhint-disable no-empty-blocks\n/// @notice Recipient mock for testing purposes. DO NOT USE IN PRODUCTION.\ncontract RecipientMock is IZapRecipient {\n /// @notice Mock needs to accept ETH\n receive() external payable {}\n\n /// @notice We include an empty \"test\" function so that this contract does not appear in the coverage report.\n function testRecipientMock() external {}\n\n /// @notice Minimal viable implementation of the zap hook.\n function zap(address, uint256, bytes memory) external payable returns (bytes4) {\n return IZapRecipient.zap.selector;\n }\n}\n","language":"Solidity","languageVersion":"0.8.20","compilerVersion":"0.8.20","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"377:476:0:-:0;;;;;;;;;;;;;;;;;;;","srcMapRuntime":"377:476:0:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;613:40;;;;;;;;;;;722:129;;;;;;:::i;:::-;818:26;722:129;;;;;;;;;1627:66:1;1615:79;;;1597:98;;1585:2;1570:18;722:129:0;;;;;;;14:184:1;66:77;63:1;56:88;163:4;160:1;153:15;187:4;184:1;177:15;203:1245;289:6;297;305;358:2;346:9;337:7;333:23;329:32;326:52;;;374:1;371;364:12;326:52;413:9;400:23;463:42;456:5;452:54;445:5;442:65;432:93;;521:1;518;511:12;432:93;544:5;-1:-1:-1;596:2:1;581:18;;568:32;;-1:-1:-1;651:2:1;636:18;;623:32;674:18;704:14;;;701:34;;;731:1;728;721:12;701:34;769:6;758:9;754:22;744:32;;814:7;807:4;803:2;799:13;795:27;785:55;;836:1;833;826:12;785:55;872:2;859:16;894:2;890;887:10;884:36;;;900:18;;:::i;:::-;1034:2;1028:9;1096:4;1088:13;;939:66;1084:22;;;1108:2;1080:31;1076:40;1064:53;;;1132:18;;;1152:22;;;1129:46;1126:72;;;1178:18;;:::i;:::-;1218:10;1214:2;1207:22;1253:2;1245:6;1238:18;1293:7;1288:2;1283;1279;1275:11;1271:20;1268:33;1265:53;;;1314:1;1311;1304:12;1265:53;1370:2;1365;1361;1357:11;1352:2;1344:6;1340:15;1327:46;1415:1;1410:2;1405;1397:6;1393:15;1389:24;1382:35;1436:6;1426:16;;;;;;;203:1245;;;;;:::o","abiDefinition":[{"inputs":[],"name":"testRecipientMock","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"bytes","name":"","type":"bytes"}],"name":"zap","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"payable","type":"function"},{"stateMutability":"payable","type":"receive"}],"userDoc":{"kind":"user","methods":{"testRecipientMock()":{"notice":"We include an empty \"test\" function so that this contract does not appear in the coverage report."},"zap(address,uint256,bytes)":{"notice":"Minimal viable implementation of the zap hook."}},"notice":"Recipient mock for testing purposes. DO NOT USE IN PRODUCTION.","version":1},"developerDoc":{"kind":"dev","methods":{},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.20+commit.a1b79de6\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[],\"name\":\"testRecipientMock\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"name\":\"zap\",\"outputs\":[{\"internalType\":\"bytes4\",\"name\":\"\",\"type\":\"bytes4\"}],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"stateMutability\":\"payable\",\"type\":\"receive\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"testRecipientMock()\":{\"notice\":\"We include an empty \\\"test\\\" function so that this contract does not appear in the coverage report.\"},\"zap(address,uint256,bytes)\":{\"notice\":\"Minimal viable implementation of the zap hook.\"}},\"notice\":\"Recipient mock for testing purposes. DO NOT USE IN PRODUCTION.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/RecipientMock.sol\":\"RecipientMock\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/RecipientMock.sol\":{\"keccak256\":\"0x067e55596cf94a7c1153b5d38e7a3376d971c52b1e5401bb23be3715fbeea345\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://65911afd25e38ae2d4d6d64f8c587874da876a2b76fcb36e79f89692478ddc2a\",\"dweb:/ipfs/QmYKnsF1Xoo63nbwCVKWEc3UrpZu8UBEUNeT4CCmxSqc6Y\"]}},\"version\":1}"},"hashes":{"testRecipientMock()":"b239c091","zap(address,uint256,bytes)":"e85e13dd"}}} \ No newline at end of file diff --git a/services/rfq/e2e/rfq_test.go b/services/rfq/e2e/rfq_test.go index c5a777079f..975b75a959 100644 --- a/services/rfq/e2e/rfq_test.go +++ b/services/rfq/e2e/rfq_test.go @@ -394,7 +394,7 @@ func (i *IntegrationSuite) TestETHtoETH() { } //nolint:gosec -func (i *IntegrationSuite) TestArbitraryCall() { +func (i *IntegrationSuite) TestZap() { // start the relayer and guard go func() { _ = i.relayer.Start(i.GetTestContext()) @@ -475,8 +475,8 @@ func (i *IntegrationSuite) TestArbitraryCall() { paramsV2 := fastbridgev2.IFastBridgeV2BridgeParamsV2{ QuoteRelayer: i.relayerWallet.Address(), QuoteExclusivitySeconds: new(big.Int).SetInt64(30), - CallParams: []byte("Hello, world!"), - CallValue: big.NewInt(1_337_420), + ZapData: []byte("Hello, world!"), + ZapNative: big.NewInt(1_337_420), } tx, err = originFastBridge.Bridge0(auth.TransactOpts, params, paramsV2) i.NoError(err) diff --git a/services/rfq/relayer/chain/chain.go b/services/rfq/relayer/chain/chain.go index f11e43a314..07ffd4896b 100644 --- a/services/rfq/relayer/chain/chain.go +++ b/services/rfq/relayer/chain/chain.go @@ -77,8 +77,8 @@ func (c Chain) SubmitRelay(ctx context.Context, request reldb.QuoteRequest) (uin // Check to see if ETH should be sent to destination if util.IsGasToken(request.Transaction.DestToken) { gasAmount = request.Transaction.DestAmount - } else if request.Transaction.CallValue != nil { - gasAmount = request.Transaction.CallValue + } else if request.Transaction.ZapNative != nil { + gasAmount = request.Transaction.ZapNative } else if request.TransactionV1.SendChainGas { gasAmount, err = c.Bridge.ChainGasAmount(&bind.CallOpts{Context: ctx}) if err != nil { diff --git a/services/rfq/relayer/relapi/server_test.go b/services/rfq/relayer/relapi/server_test.go index e269f4b32c..6301fdff93 100644 --- a/services/rfq/relayer/relapi/server_test.go +++ b/services/rfq/relayer/relapi/server_test.go @@ -211,8 +211,8 @@ func (c *RelayerServerSuite) getTestQuoteRequest(status reldb.QuoteRequestStatus Nonce: big.NewInt(0), ExclusivityEndTime: big.NewInt(0), OriginFeeAmount: big.NewInt(0), - CallValue: big.NewInt(0), - CallParams: []byte{}, + ZapNative: big.NewInt(0), + ZapData: []byte{}, }, OriginTxHash: common.HexToHash("0x0000000"), DestTxHash: common.HexToHash("0x0000001"), diff --git a/services/rfq/relayer/reldb/base/model.go b/services/rfq/relayer/reldb/base/model.go index 6991c501ea..fd69e03772 100644 --- a/services/rfq/relayer/reldb/base/model.go +++ b/services/rfq/relayer/reldb/base/model.go @@ -78,8 +78,8 @@ type RequestForQuote struct { DestAmount decimal.Decimal `gorm:"index"` // OriginFeeAmount is the origin fee amount OriginFeeAmount decimal.Decimal - // CallValue is the call value - CallValue decimal.Decimal + // ZapNative is the zap native value + ZapNative decimal.Decimal // DestTxHash is the destination tx hash DestTxHash sql.NullString // Deadline is the deadline for the relay @@ -91,8 +91,8 @@ type RequestForQuote struct { ExclusivityRelayer string // ExclusivityEndTime is the exclusivity end time ExclusivityEndTime time.Time - // CallParams is the call params - CallParams []byte + // ZapData is the zap data + ZapData []byte // SendChainGas is whether the relay should send gas to the destination chain SendChainGas bool // Status is the current status of the event @@ -148,8 +148,8 @@ func FromQuoteRequest(request reldb.QuoteRequest) RequestForQuote { DestAmountOriginal: request.Transaction.DestAmount.String(), DestAmount: decimal.NewFromBigInt(request.Transaction.DestAmount, int32(request.DestTokenDecimals)), OriginFeeAmount: decimal.NewFromBigInt(request.Transaction.OriginFeeAmount, int32(request.OriginTokenDecimals)), - CallValue: decimal.NewFromBigInt(request.Transaction.CallValue, int32(nativeTokenDecimals)), - CallParams: request.Transaction.CallParams, + ZapNative: decimal.NewFromBigInt(request.Transaction.ZapNative, int32(nativeTokenDecimals)), + ZapData: request.Transaction.ZapData, Deadline: time.Unix(int64(request.Transaction.Deadline.Uint64()), 0), OriginNonce: int(request.Transaction.Nonce.Uint64()), SendChainGas: request.TransactionV1.SendChainGas, @@ -239,10 +239,10 @@ func (r RequestForQuote) ToQuoteRequest() (*reldb.QuoteRequest, error) { OriginAmount: new(big.Int).Div(r.OriginAmount.BigInt(), big.NewInt(int64(math.Pow10(int(r.OriginTokenDecimals))))), DestAmount: new(big.Int).Div(r.DestAmount.BigInt(), big.NewInt(int64(math.Pow10(int(r.DestTokenDecimals))))), OriginFeeAmount: new(big.Int).Div(r.OriginFeeAmount.BigInt(), big.NewInt(int64(math.Pow10(int(r.OriginTokenDecimals))))), - CallValue: new(big.Int).Div(r.CallValue.BigInt(), big.NewInt(int64(math.Pow10(int(nativeTokenDecimals))))), + ZapNative: new(big.Int).Div(r.ZapNative.BigInt(), big.NewInt(int64(math.Pow10(int(nativeTokenDecimals))))), + ZapData: r.ZapData, ExclusivityRelayer: common.HexToAddress(r.ExclusivityRelayer), ExclusivityEndTime: big.NewInt(r.ExclusivityEndTime.Unix()), - CallParams: r.CallParams, Deadline: big.NewInt(r.Deadline.Unix()), Nonce: big.NewInt(int64(r.OriginNonce)), }, diff --git a/services/rfq/relayer/reldb/base/model_test.go b/services/rfq/relayer/reldb/base/model_test.go index 505a555633..ba2210f351 100644 --- a/services/rfq/relayer/reldb/base/model_test.go +++ b/services/rfq/relayer/reldb/base/model_test.go @@ -36,8 +36,8 @@ func TestRoundtripBetweenFromQuoteRequestAndToQuoteRequest(t *testing.T) { Nonce: big.NewInt(1), ExclusivityEndTime: big.NewInt(0), OriginFeeAmount: big.NewInt(0), - CallValue: big.NewInt(0), - CallParams: []byte{}, + ZapNative: big.NewInt(0), + ZapData: []byte{}, }, Status: reldb.QuoteRequestStatus(1), } From 83cef1de2ceb886958ccda1a9a12f161d0e05e5d Mon Sep 17 00:00:00 2001 From: dwasse Date: Thu, 14 Nov 2024 14:03:53 -0600 Subject: [PATCH 47/85] feat(rfq-api): don't respond to passive quotes for requests with zap params [SLT-430, SLT-432] (#3388) * Feat: add zap params to api model * Feat: don't consider quotes with zap data as passive quotes * Feat: add test cases for zap quotes * Cleanup: lint --- services/rfq/api/model/request.go | 5 ++++- services/rfq/api/rest/rfq_test.go | 10 ++++++++++ services/rfq/api/rest/server.go | 29 ++++++++++++++++++++++------- services/rfq/api/rest/ws.go | 6 +++++- 4 files changed, 41 insertions(+), 9 deletions(-) diff --git a/services/rfq/api/model/request.go b/services/rfq/api/model/request.go index 212ebdffcb..bbc5c1aa88 100644 --- a/services/rfq/api/model/request.go +++ b/services/rfq/api/model/request.go @@ -55,8 +55,11 @@ type QuoteData struct { DestChainID int `json:"dest_chain_id"` OriginTokenAddr string `json:"origin_token_addr"` DestTokenAddr string `json:"dest_token_addr"` - OriginAmountExact string `json:"origin_amount_exact"` + OriginAmount string `json:"origin_amount"` ExpirationWindow int64 `json:"expiration_window"` + ZapData string `json:"zap_data"` + ZapNative string `json:"zap_native"` + OriginAmountExact string `json:"origin_amount_exact"` DestAmount *string `json:"dest_amount"` RelayerAddress *string `json:"relayer_address"` QuoteID *string `json:"quote_id"` diff --git a/services/rfq/api/rest/rfq_test.go b/services/rfq/api/rest/rfq_test.go index 75245cc464..0e8c01875d 100644 --- a/services/rfq/api/rest/rfq_test.go +++ b/services/rfq/api/rest/rfq_test.go @@ -307,6 +307,16 @@ func (c *ServerSuite) TestActiveRFQFallbackToPassive() { c.Assert().Equal("passive", userQuoteResp.QuoteType) c.Assert().Equal("998000", userQuoteResp.DestAmount) // destAmount is quote destAmount minus fixed fee c.Assert().Equal(c.relayerWallets[0].Address().Hex(), userQuoteResp.RelayerAddress) + + // Submit a user quote request with zap data + userQuoteReq.Data.ZapData = "abc" + userQuoteReq.Data.ZapNative = "100" + userQuoteResp, err = userClient.PutRFQRequest(c.GetTestContext(), userQuoteReq) + c.Require().NoError(err) + + // Assert the response + c.Assert().False(userQuoteResp.Success) + c.Assert().Equal("no quotes found", userQuoteResp.Reason) } func (c *ServerSuite) TestActiveRFQPassiveBestQuote() { diff --git a/services/rfq/api/rest/server.go b/services/rfq/api/rest/server.go index 5470e0d4f0..d748e55295 100644 --- a/services/rfq/api/rest/server.go +++ b/services/rfq/api/rest/server.go @@ -4,6 +4,7 @@ package rest import ( "context" "encoding/json" + "math/big" "fmt" "net/http" @@ -532,19 +533,21 @@ func (r *QuoterAPIServer) PutRFQRequest(c *gin.Context) { span.SetAttributes(attribute.Bool("is_active_rfq", isActiveRFQ)) // if specified, fetch the active quote. always consider passive quotes - var activeQuote *model.QuoteData + var activeQuote, passiveQuote *model.QuoteData if isActiveRFQ { activeQuote = r.handleActiveRFQ(ctx, &req, requestID) if activeQuote != nil && activeQuote.DestAmount != nil { span.SetAttributes(attribute.String("active_quote_dest_amount", *activeQuote.DestAmount)) } } - passiveQuote, err := r.handlePassiveRFQ(ctx, &req) - if err != nil { - logger.Error("Error handling passive RFQ", "error", err) - } - if passiveQuote != nil && passiveQuote.DestAmount != nil { - span.SetAttributes(attribute.String("passive_quote_dest_amount", *passiveQuote.DestAmount)) + if !isZapQuote(&req) { + passiveQuote, err = r.handlePassiveRFQ(ctx, &req) + if err != nil { + logger.Error("Error handling passive RFQ", "error", err) + } + if passiveQuote != nil && passiveQuote.DestAmount != nil { + span.SetAttributes(attribute.String("passive_quote_dest_amount", *passiveQuote.DestAmount)) + } } quote := getBestQuote(activeQuote, passiveQuote) @@ -576,6 +579,18 @@ func (r *QuoterAPIServer) PutRFQRequest(c *gin.Context) { c.JSON(http.StatusOK, resp) } +func isZapQuote(req *model.PutRFQRequest) bool { + if req.Data.ZapData != "" { + return true + } + + zapNative, ok := new(big.Int).SetString(req.Data.ZapNative, 10) + if !ok { + return false + } + return zapNative.Sign() != 0 +} + func (r *QuoterAPIServer) recordLatestQuoteAge(ctx context.Context, observer metric.Observer) (err error) { if r.handler == nil || r.latestQuoteAgeGauge == nil { return nil diff --git a/services/rfq/api/rest/ws.go b/services/rfq/api/rest/ws.go index 99ba0cfa19..445ed47876 100644 --- a/services/rfq/api/rest/ws.go +++ b/services/rfq/api/rest/ws.go @@ -198,6 +198,8 @@ func (c *wsClient) sendRelayerRequest(ctx context.Context, req *model.WsRFQReque // handleRelayerMessage handles messages from the relayer. // An error returned will result in the websocket connection being closed. +// +//nolint:cyclop func (c *wsClient) handleRelayerMessage(ctx context.Context, msg []byte) (err error) { _, span := c.handler.Tracer().Start(ctx, "handleRelayerMessage", trace.WithAttributes( attribute.String("relayer_address", c.relayerAddr), @@ -235,7 +237,9 @@ func (c *wsClient) handleRelayerMessage(ctx context.Context, msg []byte) (err er } case SendQuoteOp: err = c.handleSendQuote(ctx, rfqMsg.Content) - logger.Errorf("error handling send quote: %v", err) + if err != nil { + logger.Errorf("error handling send quote: %v", err) + } default: logger.Errorf("received unexpected operation from relayer: %s", rfqMsg.Op) return nil From 9dd3998c8149909b7884306cdd63f58089faea4a Mon Sep 17 00:00:00 2001 From: dwasse Date: Wed, 20 Nov 2024 15:27:18 -0600 Subject: [PATCH 48/85] feat(rfq-api): add v2 contracts to rfq api endpoint [SLT-429] (#3387) * Feat: add v2 contracts to rfq api endpoint * Feat: add separate role caches for v1/v2 * Fix: build * Feat: add checkRoleParallel() * Fix: build * Feat: add validation for contract versions * Cleanup: lint * Cleaup: remove log --- contrib/opbot/botmd/commands.go | 3 +- services/rfq/api/client/suite_test.go | 6 +- services/rfq/api/config/config.go | 14 +-- services/rfq/api/model/response.go | 8 +- services/rfq/api/rest/handler.go | 41 ++++++-- services/rfq/api/rest/server.go | 144 ++++++++++++++++++++------ services/rfq/api/rest/server_test.go | 3 +- services/rfq/api/rest/suite_test.go | 6 +- services/rfq/e2e/setup_test.go | 2 +- 9 files changed, 169 insertions(+), 58 deletions(-) diff --git a/contrib/opbot/botmd/commands.go b/contrib/opbot/botmd/commands.go index bf49c6a98f..02258337af 100644 --- a/contrib/opbot/botmd/commands.go +++ b/contrib/opbot/botmd/commands.go @@ -371,7 +371,8 @@ func (b *Bot) makeFastBridge(ctx context.Context, chainID uint32) (*fastbridge.F return nil, fmt.Errorf("error getting chain client for chain ID %d: %w", chainID, err) } - contractAddress, ok := contracts.Contracts[chainID] + // TODO: handle v2 contract if specified + contractAddress, ok := contracts.ContractsV1[chainID] if !ok { return nil, fmt.Errorf("no contract address for chain ID") } diff --git a/services/rfq/api/client/suite_test.go b/services/rfq/api/client/suite_test.go index e87436fcca..183cd0b13b 100644 --- a/services/rfq/api/client/suite_test.go +++ b/services/rfq/api/client/suite_test.go @@ -85,7 +85,11 @@ func (c *ClientSuite) SetupTest() { DSN: filet.TmpFile(c.T(), "", "").Name(), }, OmniRPCURL: testOmnirpc, - Bridges: map[uint32]string{ + FastBridgeContractsV1: map[uint32]string{ + 1: ethFastBridgeAddress.Hex(), + 42161: arbFastBridgeAddress.Hex(), + }, + FastBridgeContractsV2: map[uint32]string{ 1: ethFastBridgeAddress.Hex(), 42161: arbFastBridgeAddress.Hex(), }, diff --git a/services/rfq/api/config/config.go b/services/rfq/api/config/config.go index 4c4456f246..13225a1c95 100644 --- a/services/rfq/api/config/config.go +++ b/services/rfq/api/config/config.go @@ -19,13 +19,13 @@ type DatabaseConfig struct { // Config is the configuration for the RFQ Quoter. type Config struct { - Database DatabaseConfig `yaml:"database"` - OmniRPCURL string `yaml:"omnirpc_url"` - // bridges is a map of chainid->address - Bridges map[uint32]string `yaml:"bridges"` - Port string `yaml:"port"` - RelayAckTimeout time.Duration `yaml:"relay_ack_timeout"` - MaxQuoteAge time.Duration `yaml:"max_quote_age"` + Database DatabaseConfig `yaml:"database"` + OmniRPCURL string `yaml:"omnirpc_url"` + FastBridgeContractsV1 map[uint32]string `yaml:"fast_bridge_contracts_v1"` + FastBridgeContractsV2 map[uint32]string `yaml:"fast_bridge_contracts_v2"` + Port string `yaml:"port"` + RelayAckTimeout time.Duration `yaml:"relay_ack_timeout"` + MaxQuoteAge time.Duration `yaml:"max_quote_age"` } const defaultRelayAckTimeout = 30 * time.Second diff --git a/services/rfq/api/model/response.go b/services/rfq/api/model/response.go index b6624ff6b9..bcdb58d462 100644 --- a/services/rfq/api/model/response.go +++ b/services/rfq/api/model/response.go @@ -41,10 +41,12 @@ type PutRelayAckResponse struct { RelayerAddress string `json:"relayer_address"` } -// GetContractsResponse contains the schema for a GET /contract response. +// GetContractsResponse contains the schema for a GET /contracts response. type GetContractsResponse struct { - // Contracts is a map of chain id to contract address - Contracts map[uint32]string `json:"contracts"` + // ContractsV1 is a map of chain id to contract address for v1 fast bridge contracts + ContractsV1 map[uint32]string `json:"contracts_v1"` + // ContractsV2 is a map of chain id to contract address for v2 fast bridge contracts + ContractsV2 map[uint32]string `json:"contracts_v2"` } // ActiveRFQMessage represents the general structure of WebSocket messages for Active RFQ. diff --git a/services/rfq/api/rest/handler.go b/services/rfq/api/rest/handler.go index dd91873362..6fd40bec0b 100644 --- a/services/rfq/api/rest/handler.go +++ b/services/rfq/api/rest/handler.go @@ -6,6 +6,7 @@ import ( "strconv" "time" + "github.com/ethereum/go-ethereum/common" "github.com/synapsecns/sanguine/services/rfq/api/config" "github.com/gin-gonic/gin" @@ -69,7 +70,7 @@ func (h *Handler) ModifyQuote(c *gin.Context) { return } - dbQuote, err := parseDBQuote(*putRequest, relayerAddr) + dbQuote, err := parseDBQuote(h.cfg, *putRequest, relayerAddr) if err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) return @@ -117,7 +118,7 @@ func (h *Handler) ModifyBulkQuotes(c *gin.Context) { dbQuotes := []*db.Quote{} for _, quoteReq := range putRequest.Quotes { - dbQuote, err := parseDBQuote(quoteReq, relayerAddr) + dbQuote, err := parseDBQuote(h.cfg, quoteReq, relayerAddr) if err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid quote request"}) return @@ -134,7 +135,7 @@ func (h *Handler) ModifyBulkQuotes(c *gin.Context) { } //nolint:gosec -func parseDBQuote(putRequest model.PutRelayerQuoteRequest, relayerAddr interface{}) (*db.Quote, error) { +func parseDBQuote(cfg config.Config, putRequest model.PutRelayerQuoteRequest, relayerAddr interface{}) (*db.Quote, error) { destAmount, err := decimal.NewFromString(putRequest.DestAmount) if err != nil { return nil, fmt.Errorf("invalid DestAmount") @@ -147,6 +148,12 @@ func parseDBQuote(putRequest model.PutRelayerQuoteRequest, relayerAddr interface if err != nil { return nil, fmt.Errorf("invalid FixedFee") } + + err = validateFastBridgeAddresses(cfg, putRequest) + if err != nil { + return nil, fmt.Errorf("invalid fast bridge addresses: %w", err) + } + // nolint: forcetypeassert return &db.Quote{ OriginChainID: uint64(putRequest.OriginChainID), @@ -163,6 +170,24 @@ func parseDBQuote(putRequest model.PutRelayerQuoteRequest, relayerAddr interface }, nil } +//nolint:gosec +func validateFastBridgeAddresses(cfg config.Config, putRequest model.PutRelayerQuoteRequest) error { + // Check V1 contracts + isV1Origin := common.HexToAddress(cfg.FastBridgeContractsV1[uint32(putRequest.OriginChainID)]) == common.HexToAddress(putRequest.OriginFastBridgeAddress) + isV1Dest := common.HexToAddress(cfg.FastBridgeContractsV1[uint32(putRequest.DestChainID)]) == common.HexToAddress(putRequest.DestFastBridgeAddress) + + // Check V2 contracts + isV2Origin := common.HexToAddress(cfg.FastBridgeContractsV2[uint32(putRequest.OriginChainID)]) == common.HexToAddress(putRequest.OriginFastBridgeAddress) + isV2Dest := common.HexToAddress(cfg.FastBridgeContractsV2[uint32(putRequest.DestChainID)]) == common.HexToAddress(putRequest.DestFastBridgeAddress) + + // Valid if both addresses match either V1 or V2 + if (isV1Origin && isV1Dest) || (isV2Origin && isV2Dest) { + return nil + } + + return fmt.Errorf("origin and destination fast bridge addresses must match either V1 or V2") +} + //nolint:gosec func quoteResponseFromDBQuote(dbQuote *db.Quote) *model.GetQuoteResponse { return &model.GetQuoteResponse{ @@ -301,12 +326,10 @@ func dbActiveQuoteRequestToModel(dbQuote *db.ActiveQuoteRequest) *model.GetOpenQ // @Header 200 {string} X-Api-Version "API Version Number - See docs for more info" // @Router /contracts [get]. func (h *Handler) GetContracts(c *gin.Context) { - // Convert quotes from db model to api model - contracts := make(map[uint32]string) - for chainID, address := range h.cfg.Bridges { - contracts[chainID] = address - } - c.JSON(http.StatusOK, model.GetContractsResponse{Contracts: contracts}) + c.JSON(http.StatusOK, model.GetContractsResponse{ + ContractsV1: h.cfg.FastBridgeContractsV1, + ContractsV2: h.cfg.FastBridgeContractsV2, + }) } func filterQuoteAge(cfg config.Config, dbQuotes []*db.Quote) []*db.Quote { diff --git a/services/rfq/api/rest/server.go b/services/rfq/api/rest/server.go index d748e55295..cdf3d59529 100644 --- a/services/rfq/api/rest/server.go +++ b/services/rfq/api/rest/server.go @@ -20,6 +20,7 @@ import ( "go.opentelemetry.io/otel/attribute" "go.opentelemetry.io/otel/metric" "go.opentelemetry.io/otel/trace" + "golang.org/x/sync/errgroup" "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" @@ -35,6 +36,7 @@ import ( "github.com/synapsecns/sanguine/services/rfq/api/docs" "github.com/synapsecns/sanguine/services/rfq/api/model" "github.com/synapsecns/sanguine/services/rfq/contracts/fastbridge" + "github.com/synapsecns/sanguine/services/rfq/contracts/fastbridgev2" "github.com/synapsecns/sanguine/services/rfq/relayer/relapi" ) @@ -51,15 +53,17 @@ func getCurrentVersion() (string, error) { // QuoterAPIServer is a struct that holds the configuration, database connection, gin engine, RPC client, metrics handler, and fast bridge contracts. // It is used to initialize and run the API server. type QuoterAPIServer struct { - cfg config.Config - db db.APIDB - engine *gin.Engine - upgrader websocket.Upgrader - omnirpcClient omniClient.RPCClient - handler metrics.Handler - meter metric.Meter - fastBridgeContracts map[uint32]*fastbridge.FastBridge - roleCache map[uint32]*ttlcache.Cache[string, bool] + cfg config.Config + db db.APIDB + engine *gin.Engine + upgrader websocket.Upgrader + omnirpcClient omniClient.RPCClient + handler metrics.Handler + meter metric.Meter + fastBridgeContractsV1 map[uint32]*fastbridge.FastBridge + fastBridgeContractsV2 map[uint32]*fastbridgev2.FastBridgeV2 + roleCacheV1 map[uint32]*ttlcache.Cache[string, bool] + roleCacheV2 map[uint32]*ttlcache.Cache[string, bool] // relayAckCache contains a set of transactionID values that reflect // transactions that have been acked for relay relayAckCache *ttlcache.Cache[string, string] @@ -96,23 +100,47 @@ func NewAPI( docs.SwaggerInfo.Title = "RFQ Quoter API" - bridges := make(map[uint32]*fastbridge.FastBridge) - roles := make(map[uint32]*ttlcache.Cache[string, bool]) - for chainID, bridge := range cfg.Bridges { + fastBridgeContractsV1 := make(map[uint32]*fastbridge.FastBridge) + rolesV1 := make(map[uint32]*ttlcache.Cache[string, bool]) + for chainID, contract := range cfg.FastBridgeContractsV1 { chainClient, err := omniRPCClient.GetChainClient(ctx, int(chainID)) if err != nil { return nil, fmt.Errorf("could not create omnirpc client: %w", err) } - bridges[chainID], err = fastbridge.NewFastBridge(common.HexToAddress(bridge), chainClient) + fastBridgeContractsV1[chainID], err = fastbridge.NewFastBridge(common.HexToAddress(contract), chainClient) if err != nil { return nil, fmt.Errorf("could not create bridge contract: %w", err) } // create the roles cache - roles[chainID] = ttlcache.New[string, bool]( + rolesV1[chainID] = ttlcache.New[string, bool]( ttlcache.WithTTL[string, bool](cacheInterval), ) - roleCache := roles[chainID] + roleCache := rolesV1[chainID] + go roleCache.Start() + go func() { + <-ctx.Done() + roleCache.Stop() + }() + } + + fastBridgeContractsV2 := make(map[uint32]*fastbridgev2.FastBridgeV2) + rolesV2 := make(map[uint32]*ttlcache.Cache[string, bool]) + for chainID, contract := range cfg.FastBridgeContractsV2 { + chainClient, err := omniRPCClient.GetChainClient(ctx, int(chainID)) + if err != nil { + return nil, fmt.Errorf("could not create omnirpc client: %w", err) + } + fastBridgeContractsV2[chainID], err = fastbridgev2.NewFastBridgeV2(common.HexToAddress(contract), chainClient) + if err != nil { + return nil, fmt.Errorf("could not create bridge contract: %w", err) + } + + // create the roles cache + rolesV2[chainID] = ttlcache.New[string, bool]( + ttlcache.WithTTL[string, bool](cacheInterval), + ) + roleCache := rolesV2[chainID] go roleCache.Start() go func() { <-ctx.Done() @@ -132,17 +160,19 @@ func NewAPI( }() q := &QuoterAPIServer{ - cfg: cfg, - db: store, - omnirpcClient: omniRPCClient, - handler: handler, - meter: handler.Meter(meterName), - fastBridgeContracts: bridges, - roleCache: roles, - relayAckCache: relayAckCache, - ackMux: sync.Mutex{}, - wsClients: xsync.NewMapOf[WsClient](), - pubSubManager: NewPubSubManager(), + cfg: cfg, + db: store, + omnirpcClient: omniRPCClient, + handler: handler, + meter: handler.Meter(meterName), + fastBridgeContractsV1: fastBridgeContractsV1, + fastBridgeContractsV2: fastBridgeContractsV2, + roleCacheV1: rolesV1, + roleCacheV2: rolesV2, + relayAckCache: relayAckCache, + ackMux: sync.Mutex{}, + wsClients: xsync.NewMapOf[WsClient](), + pubSubManager: NewPubSubManager(), } // Prometheus metrics setup @@ -298,7 +328,7 @@ func (r *QuoterAPIServer) AuthMiddleware() gin.HandlerFunc { // Authenticate and fetch the address from the request var addressRecovered *common.Address for _, destChainID := range destChainIDs { - addr, err := r.checkRole(c, destChainID) + addr, err := r.checkRoleParallel(c, destChainID) if err != nil { c.JSON(http.StatusBadRequest, gin.H{"msg": err.Error()}) c.Abort() @@ -321,11 +351,57 @@ func (r *QuoterAPIServer) AuthMiddleware() gin.HandlerFunc { } } -func (r *QuoterAPIServer) checkRole(c *gin.Context, destChainID uint32) (addressRecovered common.Address, err error) { - bridge, ok := r.fastBridgeContracts[destChainID] - if !ok { - err = fmt.Errorf("dest chain id not supported: %d", destChainID) - return addressRecovered, err +type roleContract interface { + HasRole(opts *bind.CallOpts, role [32]byte, account common.Address) (bool, error) +} + +func (r *QuoterAPIServer) checkRoleParallel(c *gin.Context, destChainID uint32) (addressRecovered common.Address, err error) { + g := new(errgroup.Group) + var v1Addr, v2Addr common.Address + var v1Err, v2Err error + + g.Go(func() error { + v1Addr, v1Err = r.checkRole(c, destChainID, true) + return v1Err + }) + + g.Go(func() error { + v2Addr, v2Err = r.checkRole(c, destChainID, false) + return v2Err + }) + + err = g.Wait() + if v1Addr != (common.Address{}) { + return v1Addr, nil + } + if v2Addr != (common.Address{}) { + return v2Addr, nil + } + if err != nil { + return common.Address{}, fmt.Errorf("role check failed: %w", err) + } + + return common.Address{}, fmt.Errorf("role check failed for both v1 and v2") +} + +func (r *QuoterAPIServer) checkRole(c *gin.Context, destChainID uint32, useV1 bool) (addressRecovered common.Address, err error) { + var bridge roleContract + var roleCache *ttlcache.Cache[string, bool] + var ok bool + if useV1 { + bridge, ok = r.fastBridgeContractsV1[destChainID] + if !ok { + err = fmt.Errorf("dest chain id not supported: %d", destChainID) + return addressRecovered, err + } + roleCache = r.roleCacheV1[destChainID] + } else { + bridge, ok = r.fastBridgeContractsV2[destChainID] + if !ok { + err = fmt.Errorf("dest chain id not supported: %d", destChainID) + return addressRecovered, err + } + roleCache = r.roleCacheV2[destChainID] } ops := &bind.CallOpts{Context: c} @@ -340,7 +416,7 @@ func (r *QuoterAPIServer) checkRole(c *gin.Context, destChainID uint32) (address } // Check and update cache - cachedRoleItem := r.roleCache[destChainID].Get(addressRecovered.Hex()) + cachedRoleItem := roleCache.Get(addressRecovered.Hex()) var hasRole bool if cachedRoleItem == nil || cachedRoleItem.IsExpired() { @@ -350,7 +426,7 @@ func (r *QuoterAPIServer) checkRole(c *gin.Context, destChainID uint32) (address return addressRecovered, fmt.Errorf("unable to check relayer role on-chain: %w", err) } // Update cache - r.roleCache[destChainID].Set(addressRecovered.Hex(), hasRole, cacheInterval) + roleCache.Set(addressRecovered.Hex(), hasRole, cacheInterval) } else { // Use cached value hasRole = cachedRoleItem.Value() diff --git a/services/rfq/api/rest/server_test.go b/services/rfq/api/rest/server_test.go index 8f9431ee75..e29143dfaa 100644 --- a/services/rfq/api/rest/server_test.go +++ b/services/rfq/api/rest/server_test.go @@ -607,5 +607,6 @@ func (c *ServerSuite) TestContracts() { contracts, err := client.GetRFQContracts(c.GetTestContext()) c.Require().NoError(err) - c.Require().Len(contracts.Contracts, 2) + c.Require().Len(contracts.ContractsV1, 2) + c.Require().Len(contracts.ContractsV2, 2) } diff --git a/services/rfq/api/rest/suite_test.go b/services/rfq/api/rest/suite_test.go index 755b4882ca..64454dcc02 100644 --- a/services/rfq/api/rest/suite_test.go +++ b/services/rfq/api/rest/suite_test.go @@ -82,7 +82,11 @@ func (c *ServerSuite) SetupTest() { DSN: filet.TmpFile(c.T(), "", "").Name(), }, OmniRPCURL: testOmnirpc, - Bridges: map[uint32]string{ + FastBridgeContractsV1: map[uint32]string{ + 1: ethFastBridgeAddress.Hex(), + 42161: arbFastBridgeAddress.Hex(), + }, + FastBridgeContractsV2: map[uint32]string{ 1: ethFastBridgeAddress.Hex(), 42161: arbFastBridgeAddress.Hex(), }, diff --git a/services/rfq/e2e/setup_test.go b/services/rfq/e2e/setup_test.go index c3a2cf9e7b..d8ce6d8fab 100644 --- a/services/rfq/e2e/setup_test.go +++ b/services/rfq/e2e/setup_test.go @@ -59,7 +59,7 @@ func (i *IntegrationSuite) setupQuoterAPI() { DSN: dbPath, }, OmniRPCURL: i.omniServer, - Bridges: map[uint32]string{ + FastBridgeContractsV1: map[uint32]string{ originBackendChainID: i.manager.Get(i.GetTestContext(), i.originBackend, testutil.FastBridgeType).Address().String(), destBackendChainID: i.manager.Get(i.GetTestContext(), i.destBackend, testutil.FastBridgeType).Address().String(), }, From d3be2ff8671855fa2aea625e118bf1790537e1ba Mon Sep 17 00:00:00 2001 From: Daniel Wasserman Date: Wed, 20 Nov 2024 16:01:31 -0600 Subject: [PATCH 49/85] Fix: tests --- services/rfq/api/rest/server_test.go | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/services/rfq/api/rest/server_test.go b/services/rfq/api/rest/server_test.go index e29143dfaa..a4c0fc97b8 100644 --- a/services/rfq/api/rest/server_test.go +++ b/services/rfq/api/rest/server_test.go @@ -539,15 +539,20 @@ func (c *ServerSuite) prepareAuthHeader(wallet wallet.Wallet) (string, error) { } // sendPutQuoteRequest sends a PUT request to the server with the given authorization header. +// +//nolint:gosec func (c *ServerSuite) sendPutQuoteRequest(header string) (*http.Response, error) { // Prepare the PUT request with JSON data. client := &http.Client{} putData := model.PutRelayerQuoteRequest{ - DestChainID: 42161, - DestTokenAddr: "0xDestTokenAddr", - DestAmount: "100.0", - MaxOriginAmount: "200.0", - FixedFee: "10.0", + OriginChainID: c.originChainID, + DestChainID: c.destChainID, + DestTokenAddr: "0xDestTokenAddr", + DestAmount: "100.0", + MaxOriginAmount: "200.0", + FixedFee: "10.0", + OriginFastBridgeAddress: c.cfg.FastBridgeContractsV1[uint32(c.originChainID)], + DestFastBridgeAddress: c.cfg.FastBridgeContractsV1[uint32(c.destChainID)], } jsonData, err := json.Marshal(putData) if err != nil { From 8edcb7bb7f61fc112179517a1d645f7d13110eac Mon Sep 17 00:00:00 2001 From: Daniel Wasserman Date: Wed, 20 Nov 2024 16:15:38 -0600 Subject: [PATCH 50/85] Fix: tests --- services/rfq/api/rest/server.go | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/services/rfq/api/rest/server.go b/services/rfq/api/rest/server.go index 47a75c0828..63b155dfc8 100644 --- a/services/rfq/api/rest/server.go +++ b/services/rfq/api/rest/server.go @@ -360,21 +360,24 @@ func (r *QuoterAPIServer) checkRoleParallel(c *gin.Context, destChainID uint32) var v1Addr, v2Addr common.Address var v1Err, v2Err error + var v1Ok, v2Ok bool g.Go(func() error { v1Addr, v1Err = r.checkRole(c, destChainID, true) + v1Ok = v1Err == nil return v1Err }) g.Go(func() error { v2Addr, v2Err = r.checkRole(c, destChainID, false) + v2Ok = v2Err == nil return v2Err }) err = g.Wait() - if v1Addr != (common.Address{}) { + if v1Ok { return v1Addr, nil } - if v2Addr != (common.Address{}) { + if v2Ok { return v2Addr, nil } if err != nil { From 884d9aef6b103d17d50d467e545e95b7e9a8afe5 Mon Sep 17 00:00:00 2001 From: dwasse Date: Fri, 22 Nov 2024 11:36:21 -0600 Subject: [PATCH 51/85] feat(rfq-api): check both relayer role and quoter role (#3399) * Fix: regen * Fix: build * Feat: check both quoter role and relayer role * logging nit * Feat: parallelize role checking --------- Co-authored-by: parodime --- services/rfq/api/rest/server.go | 16 +- .../fastbridgev2/fastbridgev2.abigen.go | 1880 ++++++++++------- .../fastbridgev2.contractinfo.json | 2 +- services/rfq/e2e/setup_test.go | 19 +- 4 files changed, 1103 insertions(+), 814 deletions(-) diff --git a/services/rfq/api/rest/server.go b/services/rfq/api/rest/server.go index 63b155dfc8..e8b3a02dc3 100644 --- a/services/rfq/api/rest/server.go +++ b/services/rfq/api/rest/server.go @@ -358,17 +358,18 @@ type roleContract interface { func (r *QuoterAPIServer) checkRoleParallel(c *gin.Context, destChainID uint32) (addressRecovered common.Address, err error) { g := new(errgroup.Group) var v1Addr, v2Addr common.Address + var v1Ok, v2Ok bool var v1Err, v2Err error - var v1Ok, v2Ok bool + quoterRole := crypto.Keccak256Hash([]byte("QUOTER_ROLE")) + relayerRole := crypto.Keccak256Hash([]byte("RELAYER_ROLE")) g.Go(func() error { - v1Addr, v1Err = r.checkRole(c, destChainID, true) + v1Addr, v1Err = r.checkRole(c, destChainID, true, relayerRole) v1Ok = v1Err == nil return v1Err }) - g.Go(func() error { - v2Addr, v2Err = r.checkRole(c, destChainID, false) + v2Addr, v2Err = r.checkRole(c, destChainID, false, quoterRole) v2Ok = v2Err == nil return v2Err }) @@ -387,7 +388,7 @@ func (r *QuoterAPIServer) checkRoleParallel(c *gin.Context, destChainID uint32) return common.Address{}, fmt.Errorf("role check failed for both v1 and v2") } -func (r *QuoterAPIServer) checkRole(c *gin.Context, destChainID uint32, useV1 bool) (addressRecovered common.Address, err error) { +func (r *QuoterAPIServer) checkRole(c *gin.Context, destChainID uint32, useV1 bool, role [32]byte) (addressRecovered common.Address, err error) { var bridge roleContract var roleCache *ttlcache.Cache[string, bool] var ok bool @@ -408,7 +409,6 @@ func (r *QuoterAPIServer) checkRole(c *gin.Context, destChainID uint32, useV1 bo } ops := &bind.CallOpts{Context: c} - relayerRole := crypto.Keccak256Hash([]byte("RELAYER_ROLE")) // authenticate relayer signature with EIP191 deadline := time.Now().Unix() - 1000 // TODO: Replace with some type of r.cfg.AuthExpiryDelta @@ -424,9 +424,9 @@ func (r *QuoterAPIServer) checkRole(c *gin.Context, destChainID uint32, useV1 bo if cachedRoleItem == nil || cachedRoleItem.IsExpired() { // Cache miss or expired, check on-chain - hasRole, err = bridge.HasRole(ops, relayerRole, addressRecovered) + hasRole, err = bridge.HasRole(ops, role, addressRecovered) if err != nil { - return addressRecovered, fmt.Errorf("unable to check relayer role on-chain: %w", err) + return addressRecovered, fmt.Errorf("unable to check role on-chain: %w", err) } // Update cache roleCache.Set(addressRecovered.Hex(), hasRole, cacheInterval) diff --git a/services/rfq/contracts/fastbridgev2/fastbridgev2.abigen.go b/services/rfq/contracts/fastbridgev2/fastbridgev2.abigen.go index 10b4a12eb5..9e110199da 100644 --- a/services/rfq/contracts/fastbridgev2/fastbridgev2.abigen.go +++ b/services/rfq/contracts/fastbridgev2/fastbridgev2.abigen.go @@ -1833,7 +1833,7 @@ func (_AccessControlEnumerable *AccessControlEnumerableFilterer) ParseRoleRevoke // AddressMetaData contains all meta data concerning the Address contract. var AddressMetaData = &bind.MetaData{ ABI: "[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"}],\"name\":\"AddressEmptyCode\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"AddressInsufficientBalance\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"FailedInnerCall\",\"type\":\"error\"}]", - Bin: "0x60566037600b82828239805160001a607314602a57634e487b7160e01b600052600060045260246000fd5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600080fdfea2646970667358221220bf1b9d7d74d58f093eea1b088fdbcad7f67374661fae1ab5815d7a31130f2fb864736f6c63430008180033", + Bin: "0x60566037600b82828239805160001a607314602a57634e487b7160e01b600052600060045260246000fd5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600080fdfea264697066735822122053e3727ad57bc90f5560dc5a255131033ea91c54c8a147cf6df38af4aac448d564736f6c63430008180033", } // AddressABI is the input ABI used to generate the binding from. @@ -2003,17 +2003,22 @@ func (_Address *AddressTransactorRaw) Transact(opts *bind.TransactOpts, method s return _Address.Contract.contract.Transact(opts, method, params...) } -// AdminMetaData contains all meta data concerning the Admin contract. -var AdminMetaData = &bind.MetaData{ - ABI: "[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_owner\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"AccessControlBadConfirmation\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"neededRole\",\"type\":\"bytes32\"}],\"name\":\"AccessControlUnauthorizedAccount\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"}],\"name\":\"AddressEmptyCode\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"AddressInsufficientBalance\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"FailedInnerCall\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"}],\"name\":\"SafeERC20FailedOperation\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"oldChainGasAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newChainGasAmount\",\"type\":\"uint256\"}],\"name\":\"ChainGasAmountUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"oldFeeRate\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newFeeRate\",\"type\":\"uint256\"}],\"name\":\"FeeRateUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"FeesSwept\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"previousAdminRole\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"newAdminRole\",\"type\":\"bytes32\"}],\"name\":\"RoleAdminChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleGranted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleRevoked\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"DEFAULT_ADMIN_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"FEE_BPS\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"FEE_RATE_MAX\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"GOVERNOR_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"GUARD_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"REFUNDER_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"RELAYER_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"chainGasAmount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"}],\"name\":\"getRoleAdmin\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"index\",\"type\":\"uint256\"}],\"name\":\"getRoleMember\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"}],\"name\":\"getRoleMemberCount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"grantRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"hasRole\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"protocolFeeRate\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"protocolFees\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"callerConfirmation\",\"type\":\"address\"}],\"name\":\"renounceRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"revokeRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"newChainGasAmount\",\"type\":\"uint256\"}],\"name\":\"setChainGasAmount\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"newFeeRate\",\"type\":\"uint256\"}],\"name\":\"setProtocolFeeRate\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes4\",\"name\":\"interfaceId\",\"type\":\"bytes4\"}],\"name\":\"supportsInterface\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"}],\"name\":\"sweepProtocolFees\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", +// AdminV2MetaData contains all meta data concerning the AdminV2 contract. +var AdminV2MetaData = &bind.MetaData{ + ABI: "[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_owner\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"AccessControlBadConfirmation\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"neededRole\",\"type\":\"bytes32\"}],\"name\":\"AccessControlUnauthorizedAccount\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"}],\"name\":\"AddressEmptyCode\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"AddressInsufficientBalance\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"CancelDelayBelowMin\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"FailedInnerCall\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"FeeRateAboveMax\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"}],\"name\":\"SafeERC20FailedOperation\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"oldCancelDelay\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newCancelDelay\",\"type\":\"uint256\"}],\"name\":\"CancelDelayUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"oldFeeRate\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newFeeRate\",\"type\":\"uint256\"}],\"name\":\"FeeRateUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"FeesSwept\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"previousAdminRole\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"newAdminRole\",\"type\":\"bytes32\"}],\"name\":\"RoleAdminChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleGranted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleRevoked\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"CANCELER_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"DEFAULT_ADMIN_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"DEFAULT_CANCEL_DELAY\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"FEE_BPS\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"FEE_RATE_MAX\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"GOVERNOR_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"GUARD_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"MIN_CANCEL_DELAY\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"NATIVE_GAS_TOKEN\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"PROVER_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"QUOTER_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"cancelDelay\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"chainGasAmount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"}],\"name\":\"getRoleAdmin\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"index\",\"type\":\"uint256\"}],\"name\":\"getRoleMember\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"}],\"name\":\"getRoleMemberCount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"grantRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"hasRole\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"protocolFeeRate\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"protocolFees\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"callerConfirmation\",\"type\":\"address\"}],\"name\":\"renounceRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"revokeRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"newCancelDelay\",\"type\":\"uint256\"}],\"name\":\"setCancelDelay\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"newFeeRate\",\"type\":\"uint256\"}],\"name\":\"setProtocolFeeRate\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes4\",\"name\":\"interfaceId\",\"type\":\"bytes4\"}],\"name\":\"supportsInterface\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"}],\"name\":\"sweepProtocolFees\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", Sigs: map[string]string{ + "02d2ff66": "CANCELER_ROLE()", "a217fddf": "DEFAULT_ADMIN_ROLE()", + "930ac180": "DEFAULT_CANCEL_DELAY()", "bf333f2c": "FEE_BPS()", "0f5f6ed7": "FEE_RATE_MAX()", "ccc57490": "GOVERNOR_ROLE()", "03ed0ee5": "GUARD_ROLE()", - "5960ccf2": "REFUNDER_ROLE()", - "926d7d7f": "RELAYER_ROLE()", + "922b7487": "MIN_CANCEL_DELAY()", + "0f862f1e": "NATIVE_GAS_TOKEN()", + "dc9a4ef6": "PROVER_ROLE()", + "7ebe815c": "QUOTER_ROLE()", + "638a0f09": "cancelDelay()", "e00a83e0": "chainGasAmount()", "248a9ca3": "getRoleAdmin(bytes32)", "9010d07c": "getRoleMember(bytes32,uint256)", @@ -2024,29 +2029,29 @@ var AdminMetaData = &bind.MetaData{ "dcf844a7": "protocolFees(address)", "36568abe": "renounceRole(bytes32,address)", "d547741f": "revokeRole(bytes32,address)", - "b250fe6b": "setChainGasAmount(uint256)", + "1ea327c5": "setCancelDelay(uint256)", "b13aa2d6": "setProtocolFeeRate(uint256)", "01ffc9a7": "supportsInterface(bytes4)", "06f333f2": "sweepProtocolFees(address,address)", }, - Bin: "0x60806040523480156200001157600080fd5b50604051620014123803806200141283398101604081905262000034916200018e565b6200004160008262000049565b5050620001b9565b60008062000058848462000086565b905080156200007d5760008481526001602052604090206200007b908462000134565b505b90505b92915050565b6000828152602081815260408083206001600160a01b038516845290915281205460ff166200012b576000838152602081815260408083206001600160a01b03861684529091529020805460ff19166001179055620000e23390565b6001600160a01b0316826001600160a01b0316847f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a450600162000080565b50600062000080565b60006200007d836001600160a01b03841660008181526001830160205260408120546200012b5750815460018181018455600084815260208082209093018490558454848252828601909352604090209190915562000080565b600060208284031215620001a157600080fd5b81516001600160a01b03811681146200007d57600080fd5b61124980620001c96000396000f3fe608060405234801561001057600080fd5b50600436106101775760003560e01c806391d14854116100d8578063bf333f2c1161008c578063d547741f11610066578063d547741f14610385578063dcf844a714610398578063e00a83e0146103b857600080fd5b8063bf333f2c14610341578063ca15c8731461034b578063ccc574901461035e57600080fd5b8063a217fddf116100bd578063a217fddf14610313578063b13aa2d61461031b578063b250fe6b1461032e57600080fd5b806391d14854146102a8578063926d7d7f146102ec57600080fd5b80632f2ff15d1161012f57806358f858801161011457806358f85880146102405780635960ccf2146102495780639010d07c1461027057600080fd5b80632f2ff15d1461021a57806336568abe1461022d57600080fd5b806306f333f21161016057806306f333f2146101d95780630f5f6ed7146101ee578063248a9ca3146101f757600080fd5b806301ffc9a71461017c57806303ed0ee5146101a4575b600080fd5b61018f61018a366004611013565b6103c1565b60405190151581526020015b60405180910390f35b6101cb7f043c983c49d46f0e102151eaf8085d4a2e6571d5df2d47b013f39bddfd4a639d81565b60405190815260200161019b565b6101ec6101e736600461107e565b61041d565b005b6101cb61271081565b6101cb6102053660046110b1565b60009081526020819052604090206001015490565b6101ec6102283660046110ca565b61050b565b6101ec61023b3660046110ca565b610536565b6101cb60025481565b6101cb7fdb9556138406326f00296e13ea2ad7db24ba82381212d816b1a40c23b466b32781565b61028361027e3660046110ed565b61058f565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200161019b565b61018f6102b63660046110ca565b60009182526020828152604080842073ffffffffffffffffffffffffffffffffffffffff93909316845291905290205460ff1690565b6101cb7fe2b7fb3b832174769106daebcfd6d1970523240dda11281102db9363b83b0dc481565b6101cb600081565b6101ec6103293660046110b1565b6105ae565b6101ec61033c3660046110b1565b610690565b6101cb620f424081565b6101cb6103593660046110b1565b6106f8565b6101cb7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f5581565b6101ec6103933660046110ca565b61070f565b6101cb6103a636600461110f565b60036020526000908152604090205481565b6101cb60045481565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f5a05180f000000000000000000000000000000000000000000000000000000001480610417575061041782610734565b92915050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f55610447816107cb565b73ffffffffffffffffffffffffffffffffffffffff83166000908152600360205260408120549081900361047b5750505050565b73ffffffffffffffffffffffffffffffffffffffff84166000818152600360205260408120556104ac9084836107d8565b6040805173ffffffffffffffffffffffffffffffffffffffff8087168252851660208201529081018290527f244e51bc38c1452fa8aaf487bcb4bca36c2baa3a5fbdb776b1eabd8dc6d277cd9060600160405180910390a1505b505050565b600082815260208190526040902060010154610526816107cb565b610530838361092f565b50505050565b73ffffffffffffffffffffffffffffffffffffffff81163314610585576040517f6697b23200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6105068282610964565b60008281526001602052604081206105a79083610991565b9392505050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f556105d8816107cb565b612710821115610649576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f6e657746656552617465203e206d61780000000000000000000000000000000060448201526064015b60405180910390fd5b600280549083905560408051828152602081018590527f14914da2bf76024616fbe1859783fcd4dbddcb179b1f3a854949fbf920dcb95791015b60405180910390a1505050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f556106ba816107cb565b600480549083905560408051828152602081018590527f5cf09b12f3f56b4c564d51b25b40360af6d795198adb61ae0806a36c294323fa9101610683565b60008181526001602052604081206104179061099d565b60008281526020819052604090206001015461072a816107cb565b6105308383610964565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f7965db0b00000000000000000000000000000000000000000000000000000000148061041757507f01ffc9a7000000000000000000000000000000000000000000000000000000007fffffffff00000000000000000000000000000000000000000000000000000000831614610417565b6107d581336109a7565b50565b3073ffffffffffffffffffffffffffffffffffffffff8316036107fa57505050565b8060000361080757505050565b7fffffffffffffffffffffffff111111111111111111111111111111111111111273ffffffffffffffffffffffffffffffffffffffff84160161090e5760008273ffffffffffffffffffffffffffffffffffffffff168260405160006040518083038185875af1925050503d806000811461089e576040519150601f19603f3d011682016040523d82523d6000602084013e6108a3565b606091505b5050905080610530576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f455448207472616e73666572206661696c6564000000000000000000000000006044820152606401610640565b61050673ffffffffffffffffffffffffffffffffffffffff84168383610a31565b60008061093c8484610abe565b905080156105a757600084815260016020526040902061095c9084610bba565b509392505050565b6000806109718484610bdc565b905080156105a757600084815260016020526040902061095c9084610c97565b60006105a78383610cb9565b6000610417825490565b60008281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915290205460ff16610a2d576040517fe2517d3f00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8216600482015260248101839052604401610640565b5050565b6040805173ffffffffffffffffffffffffffffffffffffffff8416602482015260448082018490528251808303909101815260649091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fa9059cbb00000000000000000000000000000000000000000000000000000000179052610506908490610ce3565b60008281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915281205460ff16610bb25760008381526020818152604080832073ffffffffffffffffffffffffffffffffffffffff86168452909152902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055610b503390565b73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16847f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a4506001610417565b506000610417565b60006105a78373ffffffffffffffffffffffffffffffffffffffff8416610d79565b60008281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915281205460ff1615610bb25760008381526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8616808552925280832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016905551339286917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a4506001610417565b60006105a78373ffffffffffffffffffffffffffffffffffffffff8416610dc0565b6000826000018281548110610cd057610cd061112a565b9060005260206000200154905092915050565b6000610d0573ffffffffffffffffffffffffffffffffffffffff841683610eb3565b90508051600014158015610d2a575080806020019051810190610d289190611159565b155b15610506576040517f5274afe700000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff84166004820152602401610640565b6000818152600183016020526040812054610bb257508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155610417565b60008181526001830160205260408120548015610ea9576000610de460018361117b565b8554909150600090610df89060019061117b565b9050808214610e5d576000866000018281548110610e1857610e1861112a565b9060005260206000200154905080876000018481548110610e3b57610e3b61112a565b6000918252602080832090910192909255918252600188019052604090208390555b8554869080610e6e57610e6e6111b5565b600190038181906000526020600020016000905590558560010160008681526020019081526020016000206000905560019350505050610417565b6000915050610417565b60606105a783836000846000808573ffffffffffffffffffffffffffffffffffffffff168486604051610ee691906111e4565b60006040518083038185875af1925050503d8060008114610f23576040519150601f19603f3d011682016040523d82523d6000602084013e610f28565b606091505b5091509150610f38868383610f42565b9695505050505050565b606082610f5757610f5282610fd1565b6105a7565b8151158015610f7b575073ffffffffffffffffffffffffffffffffffffffff84163b155b15610fca576040517f9996b31500000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff85166004820152602401610640565b50806105a7565b805115610fe15780518082602001fd5b6040517f1425ea4200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006020828403121561102557600080fd5b81357fffffffff00000000000000000000000000000000000000000000000000000000811681146105a757600080fd5b803573ffffffffffffffffffffffffffffffffffffffff8116811461107957600080fd5b919050565b6000806040838503121561109157600080fd5b61109a83611055565b91506110a860208401611055565b90509250929050565b6000602082840312156110c357600080fd5b5035919050565b600080604083850312156110dd57600080fd5b823591506110a860208401611055565b6000806040838503121561110057600080fd5b50508035926020909101359150565b60006020828403121561112157600080fd5b6105a782611055565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60006020828403121561116b57600080fd5b815180151581146105a757600080fd5b81810381811115610417577f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fd5b6000825160005b8181101561120557602081860181015185830152016111eb565b50600092019182525091905056fea2646970667358221220cf33c3d4da69e4a6aeddfcb46cd394bfc44899f75312d31fd8c8e38dff96ab9764736f6c63430008180033", + Bin: "0x60a060405260006080523480156200001657600080fd5b50604051620015763803806200157683398101604081905262000039916200020a565b620000466000826200005c565b50620000556201518062000099565b5062000235565b6000806200006b848462000102565b90508015620000905760008481526001602052604090206200008e9084620001b0565b505b90505b92915050565b610e10811015620000bd57604051630e0ea5c760e01b815260040160405180910390fd5b600480549082905560408051828152602081018490527f909f9078b2f6eac1d10f2aae793656c5a67511eb627ebd1d2cb1eb9c0ab94c95910160405180910390a15050565b6000828152602081815260408083206001600160a01b038516845290915281205460ff16620001a7576000838152602081815260408083206001600160a01b03861684529091529020805460ff191660011790556200015e3390565b6001600160a01b0316826001600160a01b0316847f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a450600162000093565b50600062000093565b600062000090836001600160a01b0384166000818152600183016020526040812054620001a75750815460018181018455600084815260208082209093018490558454848252828601909352604090209190915562000093565b6000602082840312156200021d57600080fd5b81516001600160a01b03811681146200009057600080fd5b60805161132562000251600039600061045201526113256000f3fe608060405234801561001057600080fd5b50600436106101ae5760003560e01c80639010d07c116100ee578063bf333f2c11610097578063d547741f11610071578063d547741f146103f3578063dc9a4ef614610406578063dcf844a71461042d578063e00a83e01461044d57600080fd5b8063bf333f2c146103af578063ca15c873146103b9578063ccc57490146103cc57600080fd5b8063930ac180116100c8578063930ac1801461038a578063a217fddf14610394578063b13aa2d61461039c57600080fd5b80639010d07c1461032a57806391d148541461033d578063922b74871461038157600080fd5b80631ea327c51161015b57806336568abe1161013557806336568abe146102de57806358f85880146102f1578063638a0f09146102fa5780637ebe815c1461030357600080fd5b80631ea327c514610295578063248a9ca3146102a85780632f2ff15d146102cb57600080fd5b806306f333f21161018c57806306f333f2146102375780630f5f6ed71461024c5780630f862f1e1461025557600080fd5b806301ffc9a7146101b357806302d2ff66146101db57806303ed0ee514610210575b600080fd5b6101c66101c13660046110ef565b610474565b60405190151581526020015b60405180910390f35b6102027febfdca8e46c0b8dacf9989ee613e35727eadd20a1d5e5ad01a53968c7e5fe07a81565b6040519081526020016101d2565b6102027f043c983c49d46f0e102151eaf8085d4a2e6571d5df2d47b013f39bddfd4a639d81565b61024a61024536600461115a565b6104d0565b005b61020261271081565b61027073eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee81565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016101d2565b61024a6102a336600461118d565b610611565b6102026102b636600461118d565b60009081526020819052604090206001015490565b61024a6102d93660046111a6565b610648565b61024a6102ec3660046111a6565b61066d565b61020260025481565b61020260045481565b6102027f9a04aea0a349253cc7277afafdf6ead6729a3972a47ffb40eaef2c93d4e1bfea81565b6102706103383660046111c9565b6106c6565b6101c661034b3660046111a6565b60009182526020828152604080842073ffffffffffffffffffffffffffffffffffffffff93909316845291905290205460ff1690565b610202610e1081565b6102026201518081565b610202600081565b61024a6103aa36600461118d565b6106e5565b610202620f424081565b6102026103c736600461118d565b610791565b6102027f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f5581565b61024a6104013660046111a6565b6107a8565b6102027f60044782a422109ac08a415e44260ad5d3bad63d96ebe1fac0363399642ee3f281565b61020261043b3660046111eb565b60036020526000908152604090205481565b6102027f000000000000000000000000000000000000000000000000000000000000000081565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f5a05180f0000000000000000000000000000000000000000000000000000000014806104ca57506104ca826107cd565b92915050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f556104fa81610864565b73ffffffffffffffffffffffffffffffffffffffff83166000908152600360205260408120549081900361052e5750505050565b73ffffffffffffffffffffffffffffffffffffffff8481166000818152600360209081526040808320929092558151928352928616928201929092529081018290527f244e51bc38c1452fa8aaf487bcb4bca36c2baa3a5fbdb776b1eabd8dc6d277cd9060600160405180910390a17fffffffffffffffffffffffff111111111111111111111111111111111111111273ffffffffffffffffffffffffffffffffffffffff8516016105e9576105e48382610871565b61060a565b61060a73ffffffffffffffffffffffffffffffffffffffff8516848361094c565b505b505050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f5561063b81610864565b610644826109d9565b5050565b60008281526020819052604090206001015461066381610864565b61060a8383610a5a565b73ffffffffffffffffffffffffffffffffffffffff811633146106bc576040517f6697b23200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61060c8282610a8f565b60008281526001602052604081206106de9083610abc565b9392505050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f5561070f81610864565b61271082111561074b576040517f9b569b8100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600280549083905560408051828152602081018590527f14914da2bf76024616fbe1859783fcd4dbddcb179b1f3a854949fbf920dcb957910160405180910390a1505050565b60008181526001602052604081206104ca90610ac8565b6000828152602081905260409020600101546107c381610864565b61060a8383610a8f565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f7965db0b0000000000000000000000000000000000000000000000000000000014806104ca57507f01ffc9a7000000000000000000000000000000000000000000000000000000007fffffffff000000000000000000000000000000000000000000000000000000008316146104ca565b61086e8133610ad2565b50565b804710156108b2576040517fcd7860590000000000000000000000000000000000000000000000000000000081523060048201526024015b60405180910390fd5b60008273ffffffffffffffffffffffffffffffffffffffff168260405160006040518083038185875af1925050503d806000811461090c576040519150601f19603f3d011682016040523d82523d6000602084013e610911565b606091505b505090508061060c576040517f1425ea4200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040805173ffffffffffffffffffffffffffffffffffffffff8416602482015260448082018490528251808303909101815260649091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fa9059cbb0000000000000000000000000000000000000000000000000000000017905261060c908490610b58565b610e10811015610a15576040517f0e0ea5c700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600480549082905560408051828152602081018490527f909f9078b2f6eac1d10f2aae793656c5a67511eb627ebd1d2cb1eb9c0ab94c95910160405180910390a15050565b600080610a678484610bee565b905080156106de576000848152600160205260409020610a879084610cea565b509392505050565b600080610a9c8484610d0c565b905080156106de576000848152600160205260409020610a879084610dc7565b60006106de8383610de9565b60006104ca825490565b60008281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915290205460ff16610644576040517fe2517d3f00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff82166004820152602481018390526044016108a9565b6000610b7a73ffffffffffffffffffffffffffffffffffffffff841683610e13565b90508051600014158015610b9f575080806020019051810190610b9d9190611206565b155b1561060c576040517f5274afe700000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff841660048201526024016108a9565b60008281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915281205460ff16610ce25760008381526020818152604080832073ffffffffffffffffffffffffffffffffffffffff86168452909152902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055610c803390565b73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16847f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45060016104ca565b5060006104ca565b60006106de8373ffffffffffffffffffffffffffffffffffffffff8416610e21565b60008281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915281205460ff1615610ce25760008381526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8616808552925280832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016905551339286917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a45060016104ca565b60006106de8373ffffffffffffffffffffffffffffffffffffffff8416610e68565b6000826000018281548110610e0057610e00611228565b9060005260206000200154905092915050565b60606106de83836000610f5b565b6000818152600183016020526040812054610ce2575081546001818101845560008481526020808220909301849055845484825282860190935260409020919091556104ca565b60008181526001830160205260408120548015610f51576000610e8c600183611257565b8554909150600090610ea090600190611257565b9050808214610f05576000866000018281548110610ec057610ec0611228565b9060005260206000200154905080876000018481548110610ee357610ee3611228565b6000918252602080832090910192909255918252600188019052604090208390555b8554869080610f1657610f16611291565b6001900381819060005260206000200160009055905585600101600086815260200190815260200160002060009055600193505050506104ca565b60009150506104ca565b606081471015610f99576040517fcd7860590000000000000000000000000000000000000000000000000000000081523060048201526024016108a9565b6000808573ffffffffffffffffffffffffffffffffffffffff168486604051610fc291906112c0565b60006040518083038185875af1925050503d8060008114610fff576040519150601f19603f3d011682016040523d82523d6000602084013e611004565b606091505b509150915061101486838361101e565b9695505050505050565b6060826110335761102e826110ad565b6106de565b8151158015611057575073ffffffffffffffffffffffffffffffffffffffff84163b155b156110a6576040517f9996b31500000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff851660048201526024016108a9565b50806106de565b8051156110bd5780518082602001fd5b6040517f1425ea4200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006020828403121561110157600080fd5b81357fffffffff00000000000000000000000000000000000000000000000000000000811681146106de57600080fd5b803573ffffffffffffffffffffffffffffffffffffffff8116811461115557600080fd5b919050565b6000806040838503121561116d57600080fd5b61117683611131565b915061118460208401611131565b90509250929050565b60006020828403121561119f57600080fd5b5035919050565b600080604083850312156111b957600080fd5b8235915061118460208401611131565b600080604083850312156111dc57600080fd5b50508035926020909101359150565b6000602082840312156111fd57600080fd5b6106de82611131565b60006020828403121561121857600080fd5b815180151581146106de57600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b818103818111156104ca577f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fd5b6000825160005b818110156112e157602081860181015185830152016112c7565b50600092019182525091905056fea264697066735822122079d04eeec7c857b32065468d4b56344ced14fdee358cfecc2cfd327dbced278e64736f6c63430008180033", } -// AdminABI is the input ABI used to generate the binding from. -// Deprecated: Use AdminMetaData.ABI instead. -var AdminABI = AdminMetaData.ABI +// AdminV2ABI is the input ABI used to generate the binding from. +// Deprecated: Use AdminV2MetaData.ABI instead. +var AdminV2ABI = AdminV2MetaData.ABI -// Deprecated: Use AdminMetaData.Sigs instead. -// AdminFuncSigs maps the 4-byte function signature to its string representation. -var AdminFuncSigs = AdminMetaData.Sigs +// Deprecated: Use AdminV2MetaData.Sigs instead. +// AdminV2FuncSigs maps the 4-byte function signature to its string representation. +var AdminV2FuncSigs = AdminV2MetaData.Sigs -// AdminBin is the compiled bytecode used for deploying new contracts. -// Deprecated: Use AdminMetaData.Bin instead. -var AdminBin = AdminMetaData.Bin +// AdminV2Bin is the compiled bytecode used for deploying new contracts. +// Deprecated: Use AdminV2MetaData.Bin instead. +var AdminV2Bin = AdminV2MetaData.Bin -// DeployAdmin deploys a new Ethereum contract, binding an instance of Admin to it. -func DeployAdmin(auth *bind.TransactOpts, backend bind.ContractBackend, _owner common.Address) (common.Address, *types.Transaction, *Admin, error) { - parsed, err := AdminMetaData.GetAbi() +// DeployAdminV2 deploys a new Ethereum contract, binding an instance of AdminV2 to it. +func DeployAdminV2(auth *bind.TransactOpts, backend bind.ContractBackend, _owner common.Address) (common.Address, *types.Transaction, *AdminV2, error) { + parsed, err := AdminV2MetaData.GetAbi() if err != nil { return common.Address{}, nil, nil, err } @@ -2054,111 +2059,111 @@ func DeployAdmin(auth *bind.TransactOpts, backend bind.ContractBackend, _owner c return common.Address{}, nil, nil, errors.New("GetABI returned nil") } - address, tx, contract, err := bind.DeployContract(auth, *parsed, common.FromHex(AdminBin), backend, _owner) + address, tx, contract, err := bind.DeployContract(auth, *parsed, common.FromHex(AdminV2Bin), backend, _owner) if err != nil { return common.Address{}, nil, nil, err } - return address, tx, &Admin{AdminCaller: AdminCaller{contract: contract}, AdminTransactor: AdminTransactor{contract: contract}, AdminFilterer: AdminFilterer{contract: contract}}, nil + return address, tx, &AdminV2{AdminV2Caller: AdminV2Caller{contract: contract}, AdminV2Transactor: AdminV2Transactor{contract: contract}, AdminV2Filterer: AdminV2Filterer{contract: contract}}, nil } -// Admin is an auto generated Go binding around an Ethereum contract. -type Admin struct { - AdminCaller // Read-only binding to the contract - AdminTransactor // Write-only binding to the contract - AdminFilterer // Log filterer for contract events +// AdminV2 is an auto generated Go binding around an Ethereum contract. +type AdminV2 struct { + AdminV2Caller // Read-only binding to the contract + AdminV2Transactor // Write-only binding to the contract + AdminV2Filterer // Log filterer for contract events } -// AdminCaller is an auto generated read-only Go binding around an Ethereum contract. -type AdminCaller struct { +// AdminV2Caller is an auto generated read-only Go binding around an Ethereum contract. +type AdminV2Caller struct { contract *bind.BoundContract // Generic contract wrapper for the low level calls } -// AdminTransactor is an auto generated write-only Go binding around an Ethereum contract. -type AdminTransactor struct { +// AdminV2Transactor is an auto generated write-only Go binding around an Ethereum contract. +type AdminV2Transactor struct { contract *bind.BoundContract // Generic contract wrapper for the low level calls } -// AdminFilterer is an auto generated log filtering Go binding around an Ethereum contract events. -type AdminFilterer struct { +// AdminV2Filterer is an auto generated log filtering Go binding around an Ethereum contract events. +type AdminV2Filterer struct { contract *bind.BoundContract // Generic contract wrapper for the low level calls } -// AdminSession is an auto generated Go binding around an Ethereum contract, +// AdminV2Session is an auto generated Go binding around an Ethereum contract, // with pre-set call and transact options. -type AdminSession struct { - Contract *Admin // Generic contract binding to set the session for +type AdminV2Session struct { + Contract *AdminV2 // Generic contract binding to set the session for CallOpts bind.CallOpts // Call options to use throughout this session TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session } -// AdminCallerSession is an auto generated read-only Go binding around an Ethereum contract, +// AdminV2CallerSession is an auto generated read-only Go binding around an Ethereum contract, // with pre-set call options. -type AdminCallerSession struct { - Contract *AdminCaller // Generic contract caller binding to set the session for - CallOpts bind.CallOpts // Call options to use throughout this session +type AdminV2CallerSession struct { + Contract *AdminV2Caller // Generic contract caller binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session } -// AdminTransactorSession is an auto generated write-only Go binding around an Ethereum contract, +// AdminV2TransactorSession is an auto generated write-only Go binding around an Ethereum contract, // with pre-set transact options. -type AdminTransactorSession struct { - Contract *AdminTransactor // Generic contract transactor binding to set the session for - TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +type AdminV2TransactorSession struct { + Contract *AdminV2Transactor // Generic contract transactor binding to set the session for + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session } -// AdminRaw is an auto generated low-level Go binding around an Ethereum contract. -type AdminRaw struct { - Contract *Admin // Generic contract binding to access the raw methods on +// AdminV2Raw is an auto generated low-level Go binding around an Ethereum contract. +type AdminV2Raw struct { + Contract *AdminV2 // Generic contract binding to access the raw methods on } -// AdminCallerRaw is an auto generated low-level read-only Go binding around an Ethereum contract. -type AdminCallerRaw struct { - Contract *AdminCaller // Generic read-only contract binding to access the raw methods on +// AdminV2CallerRaw is an auto generated low-level read-only Go binding around an Ethereum contract. +type AdminV2CallerRaw struct { + Contract *AdminV2Caller // Generic read-only contract binding to access the raw methods on } -// AdminTransactorRaw is an auto generated low-level write-only Go binding around an Ethereum contract. -type AdminTransactorRaw struct { - Contract *AdminTransactor // Generic write-only contract binding to access the raw methods on +// AdminV2TransactorRaw is an auto generated low-level write-only Go binding around an Ethereum contract. +type AdminV2TransactorRaw struct { + Contract *AdminV2Transactor // Generic write-only contract binding to access the raw methods on } -// NewAdmin creates a new instance of Admin, bound to a specific deployed contract. -func NewAdmin(address common.Address, backend bind.ContractBackend) (*Admin, error) { - contract, err := bindAdmin(address, backend, backend, backend) +// NewAdminV2 creates a new instance of AdminV2, bound to a specific deployed contract. +func NewAdminV2(address common.Address, backend bind.ContractBackend) (*AdminV2, error) { + contract, err := bindAdminV2(address, backend, backend, backend) if err != nil { return nil, err } - return &Admin{AdminCaller: AdminCaller{contract: contract}, AdminTransactor: AdminTransactor{contract: contract}, AdminFilterer: AdminFilterer{contract: contract}}, nil + return &AdminV2{AdminV2Caller: AdminV2Caller{contract: contract}, AdminV2Transactor: AdminV2Transactor{contract: contract}, AdminV2Filterer: AdminV2Filterer{contract: contract}}, nil } -// NewAdminCaller creates a new read-only instance of Admin, bound to a specific deployed contract. -func NewAdminCaller(address common.Address, caller bind.ContractCaller) (*AdminCaller, error) { - contract, err := bindAdmin(address, caller, nil, nil) +// NewAdminV2Caller creates a new read-only instance of AdminV2, bound to a specific deployed contract. +func NewAdminV2Caller(address common.Address, caller bind.ContractCaller) (*AdminV2Caller, error) { + contract, err := bindAdminV2(address, caller, nil, nil) if err != nil { return nil, err } - return &AdminCaller{contract: contract}, nil + return &AdminV2Caller{contract: contract}, nil } -// NewAdminTransactor creates a new write-only instance of Admin, bound to a specific deployed contract. -func NewAdminTransactor(address common.Address, transactor bind.ContractTransactor) (*AdminTransactor, error) { - contract, err := bindAdmin(address, nil, transactor, nil) +// NewAdminV2Transactor creates a new write-only instance of AdminV2, bound to a specific deployed contract. +func NewAdminV2Transactor(address common.Address, transactor bind.ContractTransactor) (*AdminV2Transactor, error) { + contract, err := bindAdminV2(address, nil, transactor, nil) if err != nil { return nil, err } - return &AdminTransactor{contract: contract}, nil + return &AdminV2Transactor{contract: contract}, nil } -// NewAdminFilterer creates a new log filterer instance of Admin, bound to a specific deployed contract. -func NewAdminFilterer(address common.Address, filterer bind.ContractFilterer) (*AdminFilterer, error) { - contract, err := bindAdmin(address, nil, nil, filterer) +// NewAdminV2Filterer creates a new log filterer instance of AdminV2, bound to a specific deployed contract. +func NewAdminV2Filterer(address common.Address, filterer bind.ContractFilterer) (*AdminV2Filterer, error) { + contract, err := bindAdminV2(address, nil, nil, filterer) if err != nil { return nil, err } - return &AdminFilterer{contract: contract}, nil + return &AdminV2Filterer{contract: contract}, nil } -// bindAdmin binds a generic wrapper to an already deployed contract. -func bindAdmin(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) { - parsed, err := AdminMetaData.GetAbi() +// bindAdminV2 binds a generic wrapper to an already deployed contract. +func bindAdminV2(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) { + parsed, err := AdminV2MetaData.GetAbi() if err != nil { return nil, err } @@ -2169,46 +2174,77 @@ func bindAdmin(address common.Address, caller bind.ContractCaller, transactor bi // sets the output to result. The result type might be a single field for simple // returns, a slice of interfaces for anonymous returns and a struct for named // returns. -func (_Admin *AdminRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { - return _Admin.Contract.AdminCaller.contract.Call(opts, result, method, params...) +func (_AdminV2 *AdminV2Raw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _AdminV2.Contract.AdminV2Caller.contract.Call(opts, result, method, params...) } // Transfer initiates a plain transaction to move funds to the contract, calling // its default method if one is available. -func (_Admin *AdminRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { - return _Admin.Contract.AdminTransactor.contract.Transfer(opts) +func (_AdminV2 *AdminV2Raw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _AdminV2.Contract.AdminV2Transactor.contract.Transfer(opts) } // Transact invokes the (paid) contract method with params as input values. -func (_Admin *AdminRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { - return _Admin.Contract.AdminTransactor.contract.Transact(opts, method, params...) +func (_AdminV2 *AdminV2Raw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _AdminV2.Contract.AdminV2Transactor.contract.Transact(opts, method, params...) } // Call invokes the (constant) contract method with params as input values and // sets the output to result. The result type might be a single field for simple // returns, a slice of interfaces for anonymous returns and a struct for named // returns. -func (_Admin *AdminCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { - return _Admin.Contract.contract.Call(opts, result, method, params...) +func (_AdminV2 *AdminV2CallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _AdminV2.Contract.contract.Call(opts, result, method, params...) } // Transfer initiates a plain transaction to move funds to the contract, calling // its default method if one is available. -func (_Admin *AdminTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { - return _Admin.Contract.contract.Transfer(opts) +func (_AdminV2 *AdminV2TransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _AdminV2.Contract.contract.Transfer(opts) } // Transact invokes the (paid) contract method with params as input values. -func (_Admin *AdminTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { - return _Admin.Contract.contract.Transact(opts, method, params...) +func (_AdminV2 *AdminV2TransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _AdminV2.Contract.contract.Transact(opts, method, params...) +} + +// CANCELERROLE is a free data retrieval call binding the contract method 0x02d2ff66. +// +// Solidity: function CANCELER_ROLE() view returns(bytes32) +func (_AdminV2 *AdminV2Caller) CANCELERROLE(opts *bind.CallOpts) ([32]byte, error) { + var out []interface{} + err := _AdminV2.contract.Call(opts, &out, "CANCELER_ROLE") + + if err != nil { + return *new([32]byte), err + } + + out0 := *abi.ConvertType(out[0], new([32]byte)).(*[32]byte) + + return out0, err + +} + +// CANCELERROLE is a free data retrieval call binding the contract method 0x02d2ff66. +// +// Solidity: function CANCELER_ROLE() view returns(bytes32) +func (_AdminV2 *AdminV2Session) CANCELERROLE() ([32]byte, error) { + return _AdminV2.Contract.CANCELERROLE(&_AdminV2.CallOpts) +} + +// CANCELERROLE is a free data retrieval call binding the contract method 0x02d2ff66. +// +// Solidity: function CANCELER_ROLE() view returns(bytes32) +func (_AdminV2 *AdminV2CallerSession) CANCELERROLE() ([32]byte, error) { + return _AdminV2.Contract.CANCELERROLE(&_AdminV2.CallOpts) } // DEFAULTADMINROLE is a free data retrieval call binding the contract method 0xa217fddf. // // Solidity: function DEFAULT_ADMIN_ROLE() view returns(bytes32) -func (_Admin *AdminCaller) DEFAULTADMINROLE(opts *bind.CallOpts) ([32]byte, error) { +func (_AdminV2 *AdminV2Caller) DEFAULTADMINROLE(opts *bind.CallOpts) ([32]byte, error) { var out []interface{} - err := _Admin.contract.Call(opts, &out, "DEFAULT_ADMIN_ROLE") + err := _AdminV2.contract.Call(opts, &out, "DEFAULT_ADMIN_ROLE") if err != nil { return *new([32]byte), err @@ -2223,23 +2259,54 @@ func (_Admin *AdminCaller) DEFAULTADMINROLE(opts *bind.CallOpts) ([32]byte, erro // DEFAULTADMINROLE is a free data retrieval call binding the contract method 0xa217fddf. // // Solidity: function DEFAULT_ADMIN_ROLE() view returns(bytes32) -func (_Admin *AdminSession) DEFAULTADMINROLE() ([32]byte, error) { - return _Admin.Contract.DEFAULTADMINROLE(&_Admin.CallOpts) +func (_AdminV2 *AdminV2Session) DEFAULTADMINROLE() ([32]byte, error) { + return _AdminV2.Contract.DEFAULTADMINROLE(&_AdminV2.CallOpts) } // DEFAULTADMINROLE is a free data retrieval call binding the contract method 0xa217fddf. // // Solidity: function DEFAULT_ADMIN_ROLE() view returns(bytes32) -func (_Admin *AdminCallerSession) DEFAULTADMINROLE() ([32]byte, error) { - return _Admin.Contract.DEFAULTADMINROLE(&_Admin.CallOpts) +func (_AdminV2 *AdminV2CallerSession) DEFAULTADMINROLE() ([32]byte, error) { + return _AdminV2.Contract.DEFAULTADMINROLE(&_AdminV2.CallOpts) +} + +// DEFAULTCANCELDELAY is a free data retrieval call binding the contract method 0x930ac180. +// +// Solidity: function DEFAULT_CANCEL_DELAY() view returns(uint256) +func (_AdminV2 *AdminV2Caller) DEFAULTCANCELDELAY(opts *bind.CallOpts) (*big.Int, error) { + var out []interface{} + err := _AdminV2.contract.Call(opts, &out, "DEFAULT_CANCEL_DELAY") + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// DEFAULTCANCELDELAY is a free data retrieval call binding the contract method 0x930ac180. +// +// Solidity: function DEFAULT_CANCEL_DELAY() view returns(uint256) +func (_AdminV2 *AdminV2Session) DEFAULTCANCELDELAY() (*big.Int, error) { + return _AdminV2.Contract.DEFAULTCANCELDELAY(&_AdminV2.CallOpts) +} + +// DEFAULTCANCELDELAY is a free data retrieval call binding the contract method 0x930ac180. +// +// Solidity: function DEFAULT_CANCEL_DELAY() view returns(uint256) +func (_AdminV2 *AdminV2CallerSession) DEFAULTCANCELDELAY() (*big.Int, error) { + return _AdminV2.Contract.DEFAULTCANCELDELAY(&_AdminV2.CallOpts) } // FEEBPS is a free data retrieval call binding the contract method 0xbf333f2c. // // Solidity: function FEE_BPS() view returns(uint256) -func (_Admin *AdminCaller) FEEBPS(opts *bind.CallOpts) (*big.Int, error) { +func (_AdminV2 *AdminV2Caller) FEEBPS(opts *bind.CallOpts) (*big.Int, error) { var out []interface{} - err := _Admin.contract.Call(opts, &out, "FEE_BPS") + err := _AdminV2.contract.Call(opts, &out, "FEE_BPS") if err != nil { return *new(*big.Int), err @@ -2254,23 +2321,23 @@ func (_Admin *AdminCaller) FEEBPS(opts *bind.CallOpts) (*big.Int, error) { // FEEBPS is a free data retrieval call binding the contract method 0xbf333f2c. // // Solidity: function FEE_BPS() view returns(uint256) -func (_Admin *AdminSession) FEEBPS() (*big.Int, error) { - return _Admin.Contract.FEEBPS(&_Admin.CallOpts) +func (_AdminV2 *AdminV2Session) FEEBPS() (*big.Int, error) { + return _AdminV2.Contract.FEEBPS(&_AdminV2.CallOpts) } // FEEBPS is a free data retrieval call binding the contract method 0xbf333f2c. // // Solidity: function FEE_BPS() view returns(uint256) -func (_Admin *AdminCallerSession) FEEBPS() (*big.Int, error) { - return _Admin.Contract.FEEBPS(&_Admin.CallOpts) +func (_AdminV2 *AdminV2CallerSession) FEEBPS() (*big.Int, error) { + return _AdminV2.Contract.FEEBPS(&_AdminV2.CallOpts) } // FEERATEMAX is a free data retrieval call binding the contract method 0x0f5f6ed7. // // Solidity: function FEE_RATE_MAX() view returns(uint256) -func (_Admin *AdminCaller) FEERATEMAX(opts *bind.CallOpts) (*big.Int, error) { +func (_AdminV2 *AdminV2Caller) FEERATEMAX(opts *bind.CallOpts) (*big.Int, error) { var out []interface{} - err := _Admin.contract.Call(opts, &out, "FEE_RATE_MAX") + err := _AdminV2.contract.Call(opts, &out, "FEE_RATE_MAX") if err != nil { return *new(*big.Int), err @@ -2285,23 +2352,23 @@ func (_Admin *AdminCaller) FEERATEMAX(opts *bind.CallOpts) (*big.Int, error) { // FEERATEMAX is a free data retrieval call binding the contract method 0x0f5f6ed7. // // Solidity: function FEE_RATE_MAX() view returns(uint256) -func (_Admin *AdminSession) FEERATEMAX() (*big.Int, error) { - return _Admin.Contract.FEERATEMAX(&_Admin.CallOpts) +func (_AdminV2 *AdminV2Session) FEERATEMAX() (*big.Int, error) { + return _AdminV2.Contract.FEERATEMAX(&_AdminV2.CallOpts) } // FEERATEMAX is a free data retrieval call binding the contract method 0x0f5f6ed7. // // Solidity: function FEE_RATE_MAX() view returns(uint256) -func (_Admin *AdminCallerSession) FEERATEMAX() (*big.Int, error) { - return _Admin.Contract.FEERATEMAX(&_Admin.CallOpts) +func (_AdminV2 *AdminV2CallerSession) FEERATEMAX() (*big.Int, error) { + return _AdminV2.Contract.FEERATEMAX(&_AdminV2.CallOpts) } // GOVERNORROLE is a free data retrieval call binding the contract method 0xccc57490. // // Solidity: function GOVERNOR_ROLE() view returns(bytes32) -func (_Admin *AdminCaller) GOVERNORROLE(opts *bind.CallOpts) ([32]byte, error) { +func (_AdminV2 *AdminV2Caller) GOVERNORROLE(opts *bind.CallOpts) ([32]byte, error) { var out []interface{} - err := _Admin.contract.Call(opts, &out, "GOVERNOR_ROLE") + err := _AdminV2.contract.Call(opts, &out, "GOVERNOR_ROLE") if err != nil { return *new([32]byte), err @@ -2316,23 +2383,23 @@ func (_Admin *AdminCaller) GOVERNORROLE(opts *bind.CallOpts) ([32]byte, error) { // GOVERNORROLE is a free data retrieval call binding the contract method 0xccc57490. // // Solidity: function GOVERNOR_ROLE() view returns(bytes32) -func (_Admin *AdminSession) GOVERNORROLE() ([32]byte, error) { - return _Admin.Contract.GOVERNORROLE(&_Admin.CallOpts) +func (_AdminV2 *AdminV2Session) GOVERNORROLE() ([32]byte, error) { + return _AdminV2.Contract.GOVERNORROLE(&_AdminV2.CallOpts) } // GOVERNORROLE is a free data retrieval call binding the contract method 0xccc57490. // // Solidity: function GOVERNOR_ROLE() view returns(bytes32) -func (_Admin *AdminCallerSession) GOVERNORROLE() ([32]byte, error) { - return _Admin.Contract.GOVERNORROLE(&_Admin.CallOpts) +func (_AdminV2 *AdminV2CallerSession) GOVERNORROLE() ([32]byte, error) { + return _AdminV2.Contract.GOVERNORROLE(&_AdminV2.CallOpts) } // GUARDROLE is a free data retrieval call binding the contract method 0x03ed0ee5. // // Solidity: function GUARD_ROLE() view returns(bytes32) -func (_Admin *AdminCaller) GUARDROLE(opts *bind.CallOpts) ([32]byte, error) { +func (_AdminV2 *AdminV2Caller) GUARDROLE(opts *bind.CallOpts) ([32]byte, error) { var out []interface{} - err := _Admin.contract.Call(opts, &out, "GUARD_ROLE") + err := _AdminV2.contract.Call(opts, &out, "GUARD_ROLE") if err != nil { return *new([32]byte), err @@ -2347,23 +2414,85 @@ func (_Admin *AdminCaller) GUARDROLE(opts *bind.CallOpts) ([32]byte, error) { // GUARDROLE is a free data retrieval call binding the contract method 0x03ed0ee5. // // Solidity: function GUARD_ROLE() view returns(bytes32) -func (_Admin *AdminSession) GUARDROLE() ([32]byte, error) { - return _Admin.Contract.GUARDROLE(&_Admin.CallOpts) +func (_AdminV2 *AdminV2Session) GUARDROLE() ([32]byte, error) { + return _AdminV2.Contract.GUARDROLE(&_AdminV2.CallOpts) } // GUARDROLE is a free data retrieval call binding the contract method 0x03ed0ee5. // // Solidity: function GUARD_ROLE() view returns(bytes32) -func (_Admin *AdminCallerSession) GUARDROLE() ([32]byte, error) { - return _Admin.Contract.GUARDROLE(&_Admin.CallOpts) +func (_AdminV2 *AdminV2CallerSession) GUARDROLE() ([32]byte, error) { + return _AdminV2.Contract.GUARDROLE(&_AdminV2.CallOpts) +} + +// MINCANCELDELAY is a free data retrieval call binding the contract method 0x922b7487. +// +// Solidity: function MIN_CANCEL_DELAY() view returns(uint256) +func (_AdminV2 *AdminV2Caller) MINCANCELDELAY(opts *bind.CallOpts) (*big.Int, error) { + var out []interface{} + err := _AdminV2.contract.Call(opts, &out, "MIN_CANCEL_DELAY") + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + } -// REFUNDERROLE is a free data retrieval call binding the contract method 0x5960ccf2. +// MINCANCELDELAY is a free data retrieval call binding the contract method 0x922b7487. // -// Solidity: function REFUNDER_ROLE() view returns(bytes32) -func (_Admin *AdminCaller) REFUNDERROLE(opts *bind.CallOpts) ([32]byte, error) { +// Solidity: function MIN_CANCEL_DELAY() view returns(uint256) +func (_AdminV2 *AdminV2Session) MINCANCELDELAY() (*big.Int, error) { + return _AdminV2.Contract.MINCANCELDELAY(&_AdminV2.CallOpts) +} + +// MINCANCELDELAY is a free data retrieval call binding the contract method 0x922b7487. +// +// Solidity: function MIN_CANCEL_DELAY() view returns(uint256) +func (_AdminV2 *AdminV2CallerSession) MINCANCELDELAY() (*big.Int, error) { + return _AdminV2.Contract.MINCANCELDELAY(&_AdminV2.CallOpts) +} + +// NATIVEGASTOKEN is a free data retrieval call binding the contract method 0x0f862f1e. +// +// Solidity: function NATIVE_GAS_TOKEN() view returns(address) +func (_AdminV2 *AdminV2Caller) NATIVEGASTOKEN(opts *bind.CallOpts) (common.Address, error) { var out []interface{} - err := _Admin.contract.Call(opts, &out, "REFUNDER_ROLE") + err := _AdminV2.contract.Call(opts, &out, "NATIVE_GAS_TOKEN") + + if err != nil { + return *new(common.Address), err + } + + out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) + + return out0, err + +} + +// NATIVEGASTOKEN is a free data retrieval call binding the contract method 0x0f862f1e. +// +// Solidity: function NATIVE_GAS_TOKEN() view returns(address) +func (_AdminV2 *AdminV2Session) NATIVEGASTOKEN() (common.Address, error) { + return _AdminV2.Contract.NATIVEGASTOKEN(&_AdminV2.CallOpts) +} + +// NATIVEGASTOKEN is a free data retrieval call binding the contract method 0x0f862f1e. +// +// Solidity: function NATIVE_GAS_TOKEN() view returns(address) +func (_AdminV2 *AdminV2CallerSession) NATIVEGASTOKEN() (common.Address, error) { + return _AdminV2.Contract.NATIVEGASTOKEN(&_AdminV2.CallOpts) +} + +// PROVERROLE is a free data retrieval call binding the contract method 0xdc9a4ef6. +// +// Solidity: function PROVER_ROLE() view returns(bytes32) +func (_AdminV2 *AdminV2Caller) PROVERROLE(opts *bind.CallOpts) ([32]byte, error) { + var out []interface{} + err := _AdminV2.contract.Call(opts, &out, "PROVER_ROLE") if err != nil { return *new([32]byte), err @@ -2375,26 +2504,26 @@ func (_Admin *AdminCaller) REFUNDERROLE(opts *bind.CallOpts) ([32]byte, error) { } -// REFUNDERROLE is a free data retrieval call binding the contract method 0x5960ccf2. +// PROVERROLE is a free data retrieval call binding the contract method 0xdc9a4ef6. // -// Solidity: function REFUNDER_ROLE() view returns(bytes32) -func (_Admin *AdminSession) REFUNDERROLE() ([32]byte, error) { - return _Admin.Contract.REFUNDERROLE(&_Admin.CallOpts) +// Solidity: function PROVER_ROLE() view returns(bytes32) +func (_AdminV2 *AdminV2Session) PROVERROLE() ([32]byte, error) { + return _AdminV2.Contract.PROVERROLE(&_AdminV2.CallOpts) } -// REFUNDERROLE is a free data retrieval call binding the contract method 0x5960ccf2. +// PROVERROLE is a free data retrieval call binding the contract method 0xdc9a4ef6. // -// Solidity: function REFUNDER_ROLE() view returns(bytes32) -func (_Admin *AdminCallerSession) REFUNDERROLE() ([32]byte, error) { - return _Admin.Contract.REFUNDERROLE(&_Admin.CallOpts) +// Solidity: function PROVER_ROLE() view returns(bytes32) +func (_AdminV2 *AdminV2CallerSession) PROVERROLE() ([32]byte, error) { + return _AdminV2.Contract.PROVERROLE(&_AdminV2.CallOpts) } -// RELAYERROLE is a free data retrieval call binding the contract method 0x926d7d7f. +// QUOTERROLE is a free data retrieval call binding the contract method 0x7ebe815c. // -// Solidity: function RELAYER_ROLE() view returns(bytes32) -func (_Admin *AdminCaller) RELAYERROLE(opts *bind.CallOpts) ([32]byte, error) { +// Solidity: function QUOTER_ROLE() view returns(bytes32) +func (_AdminV2 *AdminV2Caller) QUOTERROLE(opts *bind.CallOpts) ([32]byte, error) { var out []interface{} - err := _Admin.contract.Call(opts, &out, "RELAYER_ROLE") + err := _AdminV2.contract.Call(opts, &out, "QUOTER_ROLE") if err != nil { return *new([32]byte), err @@ -2406,26 +2535,57 @@ func (_Admin *AdminCaller) RELAYERROLE(opts *bind.CallOpts) ([32]byte, error) { } -// RELAYERROLE is a free data retrieval call binding the contract method 0x926d7d7f. +// QUOTERROLE is a free data retrieval call binding the contract method 0x7ebe815c. +// +// Solidity: function QUOTER_ROLE() view returns(bytes32) +func (_AdminV2 *AdminV2Session) QUOTERROLE() ([32]byte, error) { + return _AdminV2.Contract.QUOTERROLE(&_AdminV2.CallOpts) +} + +// QUOTERROLE is a free data retrieval call binding the contract method 0x7ebe815c. +// +// Solidity: function QUOTER_ROLE() view returns(bytes32) +func (_AdminV2 *AdminV2CallerSession) QUOTERROLE() ([32]byte, error) { + return _AdminV2.Contract.QUOTERROLE(&_AdminV2.CallOpts) +} + +// CancelDelay is a free data retrieval call binding the contract method 0x638a0f09. +// +// Solidity: function cancelDelay() view returns(uint256) +func (_AdminV2 *AdminV2Caller) CancelDelay(opts *bind.CallOpts) (*big.Int, error) { + var out []interface{} + err := _AdminV2.contract.Call(opts, &out, "cancelDelay") + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// CancelDelay is a free data retrieval call binding the contract method 0x638a0f09. // -// Solidity: function RELAYER_ROLE() view returns(bytes32) -func (_Admin *AdminSession) RELAYERROLE() ([32]byte, error) { - return _Admin.Contract.RELAYERROLE(&_Admin.CallOpts) +// Solidity: function cancelDelay() view returns(uint256) +func (_AdminV2 *AdminV2Session) CancelDelay() (*big.Int, error) { + return _AdminV2.Contract.CancelDelay(&_AdminV2.CallOpts) } -// RELAYERROLE is a free data retrieval call binding the contract method 0x926d7d7f. +// CancelDelay is a free data retrieval call binding the contract method 0x638a0f09. // -// Solidity: function RELAYER_ROLE() view returns(bytes32) -func (_Admin *AdminCallerSession) RELAYERROLE() ([32]byte, error) { - return _Admin.Contract.RELAYERROLE(&_Admin.CallOpts) +// Solidity: function cancelDelay() view returns(uint256) +func (_AdminV2 *AdminV2CallerSession) CancelDelay() (*big.Int, error) { + return _AdminV2.Contract.CancelDelay(&_AdminV2.CallOpts) } // ChainGasAmount is a free data retrieval call binding the contract method 0xe00a83e0. // // Solidity: function chainGasAmount() view returns(uint256) -func (_Admin *AdminCaller) ChainGasAmount(opts *bind.CallOpts) (*big.Int, error) { +func (_AdminV2 *AdminV2Caller) ChainGasAmount(opts *bind.CallOpts) (*big.Int, error) { var out []interface{} - err := _Admin.contract.Call(opts, &out, "chainGasAmount") + err := _AdminV2.contract.Call(opts, &out, "chainGasAmount") if err != nil { return *new(*big.Int), err @@ -2440,23 +2600,23 @@ func (_Admin *AdminCaller) ChainGasAmount(opts *bind.CallOpts) (*big.Int, error) // ChainGasAmount is a free data retrieval call binding the contract method 0xe00a83e0. // // Solidity: function chainGasAmount() view returns(uint256) -func (_Admin *AdminSession) ChainGasAmount() (*big.Int, error) { - return _Admin.Contract.ChainGasAmount(&_Admin.CallOpts) +func (_AdminV2 *AdminV2Session) ChainGasAmount() (*big.Int, error) { + return _AdminV2.Contract.ChainGasAmount(&_AdminV2.CallOpts) } // ChainGasAmount is a free data retrieval call binding the contract method 0xe00a83e0. // // Solidity: function chainGasAmount() view returns(uint256) -func (_Admin *AdminCallerSession) ChainGasAmount() (*big.Int, error) { - return _Admin.Contract.ChainGasAmount(&_Admin.CallOpts) +func (_AdminV2 *AdminV2CallerSession) ChainGasAmount() (*big.Int, error) { + return _AdminV2.Contract.ChainGasAmount(&_AdminV2.CallOpts) } // GetRoleAdmin is a free data retrieval call binding the contract method 0x248a9ca3. // // Solidity: function getRoleAdmin(bytes32 role) view returns(bytes32) -func (_Admin *AdminCaller) GetRoleAdmin(opts *bind.CallOpts, role [32]byte) ([32]byte, error) { +func (_AdminV2 *AdminV2Caller) GetRoleAdmin(opts *bind.CallOpts, role [32]byte) ([32]byte, error) { var out []interface{} - err := _Admin.contract.Call(opts, &out, "getRoleAdmin", role) + err := _AdminV2.contract.Call(opts, &out, "getRoleAdmin", role) if err != nil { return *new([32]byte), err @@ -2471,23 +2631,23 @@ func (_Admin *AdminCaller) GetRoleAdmin(opts *bind.CallOpts, role [32]byte) ([32 // GetRoleAdmin is a free data retrieval call binding the contract method 0x248a9ca3. // // Solidity: function getRoleAdmin(bytes32 role) view returns(bytes32) -func (_Admin *AdminSession) GetRoleAdmin(role [32]byte) ([32]byte, error) { - return _Admin.Contract.GetRoleAdmin(&_Admin.CallOpts, role) +func (_AdminV2 *AdminV2Session) GetRoleAdmin(role [32]byte) ([32]byte, error) { + return _AdminV2.Contract.GetRoleAdmin(&_AdminV2.CallOpts, role) } // GetRoleAdmin is a free data retrieval call binding the contract method 0x248a9ca3. // // Solidity: function getRoleAdmin(bytes32 role) view returns(bytes32) -func (_Admin *AdminCallerSession) GetRoleAdmin(role [32]byte) ([32]byte, error) { - return _Admin.Contract.GetRoleAdmin(&_Admin.CallOpts, role) +func (_AdminV2 *AdminV2CallerSession) GetRoleAdmin(role [32]byte) ([32]byte, error) { + return _AdminV2.Contract.GetRoleAdmin(&_AdminV2.CallOpts, role) } // GetRoleMember is a free data retrieval call binding the contract method 0x9010d07c. // // Solidity: function getRoleMember(bytes32 role, uint256 index) view returns(address) -func (_Admin *AdminCaller) GetRoleMember(opts *bind.CallOpts, role [32]byte, index *big.Int) (common.Address, error) { +func (_AdminV2 *AdminV2Caller) GetRoleMember(opts *bind.CallOpts, role [32]byte, index *big.Int) (common.Address, error) { var out []interface{} - err := _Admin.contract.Call(opts, &out, "getRoleMember", role, index) + err := _AdminV2.contract.Call(opts, &out, "getRoleMember", role, index) if err != nil { return *new(common.Address), err @@ -2502,23 +2662,23 @@ func (_Admin *AdminCaller) GetRoleMember(opts *bind.CallOpts, role [32]byte, ind // GetRoleMember is a free data retrieval call binding the contract method 0x9010d07c. // // Solidity: function getRoleMember(bytes32 role, uint256 index) view returns(address) -func (_Admin *AdminSession) GetRoleMember(role [32]byte, index *big.Int) (common.Address, error) { - return _Admin.Contract.GetRoleMember(&_Admin.CallOpts, role, index) +func (_AdminV2 *AdminV2Session) GetRoleMember(role [32]byte, index *big.Int) (common.Address, error) { + return _AdminV2.Contract.GetRoleMember(&_AdminV2.CallOpts, role, index) } // GetRoleMember is a free data retrieval call binding the contract method 0x9010d07c. // // Solidity: function getRoleMember(bytes32 role, uint256 index) view returns(address) -func (_Admin *AdminCallerSession) GetRoleMember(role [32]byte, index *big.Int) (common.Address, error) { - return _Admin.Contract.GetRoleMember(&_Admin.CallOpts, role, index) +func (_AdminV2 *AdminV2CallerSession) GetRoleMember(role [32]byte, index *big.Int) (common.Address, error) { + return _AdminV2.Contract.GetRoleMember(&_AdminV2.CallOpts, role, index) } // GetRoleMemberCount is a free data retrieval call binding the contract method 0xca15c873. // // Solidity: function getRoleMemberCount(bytes32 role) view returns(uint256) -func (_Admin *AdminCaller) GetRoleMemberCount(opts *bind.CallOpts, role [32]byte) (*big.Int, error) { +func (_AdminV2 *AdminV2Caller) GetRoleMemberCount(opts *bind.CallOpts, role [32]byte) (*big.Int, error) { var out []interface{} - err := _Admin.contract.Call(opts, &out, "getRoleMemberCount", role) + err := _AdminV2.contract.Call(opts, &out, "getRoleMemberCount", role) if err != nil { return *new(*big.Int), err @@ -2533,23 +2693,23 @@ func (_Admin *AdminCaller) GetRoleMemberCount(opts *bind.CallOpts, role [32]byte // GetRoleMemberCount is a free data retrieval call binding the contract method 0xca15c873. // // Solidity: function getRoleMemberCount(bytes32 role) view returns(uint256) -func (_Admin *AdminSession) GetRoleMemberCount(role [32]byte) (*big.Int, error) { - return _Admin.Contract.GetRoleMemberCount(&_Admin.CallOpts, role) +func (_AdminV2 *AdminV2Session) GetRoleMemberCount(role [32]byte) (*big.Int, error) { + return _AdminV2.Contract.GetRoleMemberCount(&_AdminV2.CallOpts, role) } // GetRoleMemberCount is a free data retrieval call binding the contract method 0xca15c873. // // Solidity: function getRoleMemberCount(bytes32 role) view returns(uint256) -func (_Admin *AdminCallerSession) GetRoleMemberCount(role [32]byte) (*big.Int, error) { - return _Admin.Contract.GetRoleMemberCount(&_Admin.CallOpts, role) +func (_AdminV2 *AdminV2CallerSession) GetRoleMemberCount(role [32]byte) (*big.Int, error) { + return _AdminV2.Contract.GetRoleMemberCount(&_AdminV2.CallOpts, role) } // HasRole is a free data retrieval call binding the contract method 0x91d14854. // // Solidity: function hasRole(bytes32 role, address account) view returns(bool) -func (_Admin *AdminCaller) HasRole(opts *bind.CallOpts, role [32]byte, account common.Address) (bool, error) { +func (_AdminV2 *AdminV2Caller) HasRole(opts *bind.CallOpts, role [32]byte, account common.Address) (bool, error) { var out []interface{} - err := _Admin.contract.Call(opts, &out, "hasRole", role, account) + err := _AdminV2.contract.Call(opts, &out, "hasRole", role, account) if err != nil { return *new(bool), err @@ -2564,23 +2724,23 @@ func (_Admin *AdminCaller) HasRole(opts *bind.CallOpts, role [32]byte, account c // HasRole is a free data retrieval call binding the contract method 0x91d14854. // // Solidity: function hasRole(bytes32 role, address account) view returns(bool) -func (_Admin *AdminSession) HasRole(role [32]byte, account common.Address) (bool, error) { - return _Admin.Contract.HasRole(&_Admin.CallOpts, role, account) +func (_AdminV2 *AdminV2Session) HasRole(role [32]byte, account common.Address) (bool, error) { + return _AdminV2.Contract.HasRole(&_AdminV2.CallOpts, role, account) } // HasRole is a free data retrieval call binding the contract method 0x91d14854. // // Solidity: function hasRole(bytes32 role, address account) view returns(bool) -func (_Admin *AdminCallerSession) HasRole(role [32]byte, account common.Address) (bool, error) { - return _Admin.Contract.HasRole(&_Admin.CallOpts, role, account) +func (_AdminV2 *AdminV2CallerSession) HasRole(role [32]byte, account common.Address) (bool, error) { + return _AdminV2.Contract.HasRole(&_AdminV2.CallOpts, role, account) } // ProtocolFeeRate is a free data retrieval call binding the contract method 0x58f85880. // // Solidity: function protocolFeeRate() view returns(uint256) -func (_Admin *AdminCaller) ProtocolFeeRate(opts *bind.CallOpts) (*big.Int, error) { +func (_AdminV2 *AdminV2Caller) ProtocolFeeRate(opts *bind.CallOpts) (*big.Int, error) { var out []interface{} - err := _Admin.contract.Call(opts, &out, "protocolFeeRate") + err := _AdminV2.contract.Call(opts, &out, "protocolFeeRate") if err != nil { return *new(*big.Int), err @@ -2595,23 +2755,23 @@ func (_Admin *AdminCaller) ProtocolFeeRate(opts *bind.CallOpts) (*big.Int, error // ProtocolFeeRate is a free data retrieval call binding the contract method 0x58f85880. // // Solidity: function protocolFeeRate() view returns(uint256) -func (_Admin *AdminSession) ProtocolFeeRate() (*big.Int, error) { - return _Admin.Contract.ProtocolFeeRate(&_Admin.CallOpts) +func (_AdminV2 *AdminV2Session) ProtocolFeeRate() (*big.Int, error) { + return _AdminV2.Contract.ProtocolFeeRate(&_AdminV2.CallOpts) } // ProtocolFeeRate is a free data retrieval call binding the contract method 0x58f85880. // // Solidity: function protocolFeeRate() view returns(uint256) -func (_Admin *AdminCallerSession) ProtocolFeeRate() (*big.Int, error) { - return _Admin.Contract.ProtocolFeeRate(&_Admin.CallOpts) +func (_AdminV2 *AdminV2CallerSession) ProtocolFeeRate() (*big.Int, error) { + return _AdminV2.Contract.ProtocolFeeRate(&_AdminV2.CallOpts) } // ProtocolFees is a free data retrieval call binding the contract method 0xdcf844a7. // // Solidity: function protocolFees(address ) view returns(uint256) -func (_Admin *AdminCaller) ProtocolFees(opts *bind.CallOpts, arg0 common.Address) (*big.Int, error) { +func (_AdminV2 *AdminV2Caller) ProtocolFees(opts *bind.CallOpts, arg0 common.Address) (*big.Int, error) { var out []interface{} - err := _Admin.contract.Call(opts, &out, "protocolFees", arg0) + err := _AdminV2.contract.Call(opts, &out, "protocolFees", arg0) if err != nil { return *new(*big.Int), err @@ -2626,23 +2786,23 @@ func (_Admin *AdminCaller) ProtocolFees(opts *bind.CallOpts, arg0 common.Address // ProtocolFees is a free data retrieval call binding the contract method 0xdcf844a7. // // Solidity: function protocolFees(address ) view returns(uint256) -func (_Admin *AdminSession) ProtocolFees(arg0 common.Address) (*big.Int, error) { - return _Admin.Contract.ProtocolFees(&_Admin.CallOpts, arg0) +func (_AdminV2 *AdminV2Session) ProtocolFees(arg0 common.Address) (*big.Int, error) { + return _AdminV2.Contract.ProtocolFees(&_AdminV2.CallOpts, arg0) } // ProtocolFees is a free data retrieval call binding the contract method 0xdcf844a7. // // Solidity: function protocolFees(address ) view returns(uint256) -func (_Admin *AdminCallerSession) ProtocolFees(arg0 common.Address) (*big.Int, error) { - return _Admin.Contract.ProtocolFees(&_Admin.CallOpts, arg0) +func (_AdminV2 *AdminV2CallerSession) ProtocolFees(arg0 common.Address) (*big.Int, error) { + return _AdminV2.Contract.ProtocolFees(&_AdminV2.CallOpts, arg0) } // SupportsInterface is a free data retrieval call binding the contract method 0x01ffc9a7. // // Solidity: function supportsInterface(bytes4 interfaceId) view returns(bool) -func (_Admin *AdminCaller) SupportsInterface(opts *bind.CallOpts, interfaceId [4]byte) (bool, error) { +func (_AdminV2 *AdminV2Caller) SupportsInterface(opts *bind.CallOpts, interfaceId [4]byte) (bool, error) { var out []interface{} - err := _Admin.contract.Call(opts, &out, "supportsInterface", interfaceId) + err := _AdminV2.contract.Call(opts, &out, "supportsInterface", interfaceId) if err != nil { return *new(bool), err @@ -2657,146 +2817,146 @@ func (_Admin *AdminCaller) SupportsInterface(opts *bind.CallOpts, interfaceId [4 // SupportsInterface is a free data retrieval call binding the contract method 0x01ffc9a7. // // Solidity: function supportsInterface(bytes4 interfaceId) view returns(bool) -func (_Admin *AdminSession) SupportsInterface(interfaceId [4]byte) (bool, error) { - return _Admin.Contract.SupportsInterface(&_Admin.CallOpts, interfaceId) +func (_AdminV2 *AdminV2Session) SupportsInterface(interfaceId [4]byte) (bool, error) { + return _AdminV2.Contract.SupportsInterface(&_AdminV2.CallOpts, interfaceId) } // SupportsInterface is a free data retrieval call binding the contract method 0x01ffc9a7. // // Solidity: function supportsInterface(bytes4 interfaceId) view returns(bool) -func (_Admin *AdminCallerSession) SupportsInterface(interfaceId [4]byte) (bool, error) { - return _Admin.Contract.SupportsInterface(&_Admin.CallOpts, interfaceId) +func (_AdminV2 *AdminV2CallerSession) SupportsInterface(interfaceId [4]byte) (bool, error) { + return _AdminV2.Contract.SupportsInterface(&_AdminV2.CallOpts, interfaceId) } // GrantRole is a paid mutator transaction binding the contract method 0x2f2ff15d. // // Solidity: function grantRole(bytes32 role, address account) returns() -func (_Admin *AdminTransactor) GrantRole(opts *bind.TransactOpts, role [32]byte, account common.Address) (*types.Transaction, error) { - return _Admin.contract.Transact(opts, "grantRole", role, account) +func (_AdminV2 *AdminV2Transactor) GrantRole(opts *bind.TransactOpts, role [32]byte, account common.Address) (*types.Transaction, error) { + return _AdminV2.contract.Transact(opts, "grantRole", role, account) } // GrantRole is a paid mutator transaction binding the contract method 0x2f2ff15d. // // Solidity: function grantRole(bytes32 role, address account) returns() -func (_Admin *AdminSession) GrantRole(role [32]byte, account common.Address) (*types.Transaction, error) { - return _Admin.Contract.GrantRole(&_Admin.TransactOpts, role, account) +func (_AdminV2 *AdminV2Session) GrantRole(role [32]byte, account common.Address) (*types.Transaction, error) { + return _AdminV2.Contract.GrantRole(&_AdminV2.TransactOpts, role, account) } // GrantRole is a paid mutator transaction binding the contract method 0x2f2ff15d. // // Solidity: function grantRole(bytes32 role, address account) returns() -func (_Admin *AdminTransactorSession) GrantRole(role [32]byte, account common.Address) (*types.Transaction, error) { - return _Admin.Contract.GrantRole(&_Admin.TransactOpts, role, account) +func (_AdminV2 *AdminV2TransactorSession) GrantRole(role [32]byte, account common.Address) (*types.Transaction, error) { + return _AdminV2.Contract.GrantRole(&_AdminV2.TransactOpts, role, account) } // RenounceRole is a paid mutator transaction binding the contract method 0x36568abe. // // Solidity: function renounceRole(bytes32 role, address callerConfirmation) returns() -func (_Admin *AdminTransactor) RenounceRole(opts *bind.TransactOpts, role [32]byte, callerConfirmation common.Address) (*types.Transaction, error) { - return _Admin.contract.Transact(opts, "renounceRole", role, callerConfirmation) +func (_AdminV2 *AdminV2Transactor) RenounceRole(opts *bind.TransactOpts, role [32]byte, callerConfirmation common.Address) (*types.Transaction, error) { + return _AdminV2.contract.Transact(opts, "renounceRole", role, callerConfirmation) } // RenounceRole is a paid mutator transaction binding the contract method 0x36568abe. // // Solidity: function renounceRole(bytes32 role, address callerConfirmation) returns() -func (_Admin *AdminSession) RenounceRole(role [32]byte, callerConfirmation common.Address) (*types.Transaction, error) { - return _Admin.Contract.RenounceRole(&_Admin.TransactOpts, role, callerConfirmation) +func (_AdminV2 *AdminV2Session) RenounceRole(role [32]byte, callerConfirmation common.Address) (*types.Transaction, error) { + return _AdminV2.Contract.RenounceRole(&_AdminV2.TransactOpts, role, callerConfirmation) } // RenounceRole is a paid mutator transaction binding the contract method 0x36568abe. // // Solidity: function renounceRole(bytes32 role, address callerConfirmation) returns() -func (_Admin *AdminTransactorSession) RenounceRole(role [32]byte, callerConfirmation common.Address) (*types.Transaction, error) { - return _Admin.Contract.RenounceRole(&_Admin.TransactOpts, role, callerConfirmation) +func (_AdminV2 *AdminV2TransactorSession) RenounceRole(role [32]byte, callerConfirmation common.Address) (*types.Transaction, error) { + return _AdminV2.Contract.RenounceRole(&_AdminV2.TransactOpts, role, callerConfirmation) } // RevokeRole is a paid mutator transaction binding the contract method 0xd547741f. // // Solidity: function revokeRole(bytes32 role, address account) returns() -func (_Admin *AdminTransactor) RevokeRole(opts *bind.TransactOpts, role [32]byte, account common.Address) (*types.Transaction, error) { - return _Admin.contract.Transact(opts, "revokeRole", role, account) +func (_AdminV2 *AdminV2Transactor) RevokeRole(opts *bind.TransactOpts, role [32]byte, account common.Address) (*types.Transaction, error) { + return _AdminV2.contract.Transact(opts, "revokeRole", role, account) } // RevokeRole is a paid mutator transaction binding the contract method 0xd547741f. // // Solidity: function revokeRole(bytes32 role, address account) returns() -func (_Admin *AdminSession) RevokeRole(role [32]byte, account common.Address) (*types.Transaction, error) { - return _Admin.Contract.RevokeRole(&_Admin.TransactOpts, role, account) +func (_AdminV2 *AdminV2Session) RevokeRole(role [32]byte, account common.Address) (*types.Transaction, error) { + return _AdminV2.Contract.RevokeRole(&_AdminV2.TransactOpts, role, account) } // RevokeRole is a paid mutator transaction binding the contract method 0xd547741f. // // Solidity: function revokeRole(bytes32 role, address account) returns() -func (_Admin *AdminTransactorSession) RevokeRole(role [32]byte, account common.Address) (*types.Transaction, error) { - return _Admin.Contract.RevokeRole(&_Admin.TransactOpts, role, account) +func (_AdminV2 *AdminV2TransactorSession) RevokeRole(role [32]byte, account common.Address) (*types.Transaction, error) { + return _AdminV2.Contract.RevokeRole(&_AdminV2.TransactOpts, role, account) } -// SetChainGasAmount is a paid mutator transaction binding the contract method 0xb250fe6b. +// SetCancelDelay is a paid mutator transaction binding the contract method 0x1ea327c5. // -// Solidity: function setChainGasAmount(uint256 newChainGasAmount) returns() -func (_Admin *AdminTransactor) SetChainGasAmount(opts *bind.TransactOpts, newChainGasAmount *big.Int) (*types.Transaction, error) { - return _Admin.contract.Transact(opts, "setChainGasAmount", newChainGasAmount) +// Solidity: function setCancelDelay(uint256 newCancelDelay) returns() +func (_AdminV2 *AdminV2Transactor) SetCancelDelay(opts *bind.TransactOpts, newCancelDelay *big.Int) (*types.Transaction, error) { + return _AdminV2.contract.Transact(opts, "setCancelDelay", newCancelDelay) } -// SetChainGasAmount is a paid mutator transaction binding the contract method 0xb250fe6b. +// SetCancelDelay is a paid mutator transaction binding the contract method 0x1ea327c5. // -// Solidity: function setChainGasAmount(uint256 newChainGasAmount) returns() -func (_Admin *AdminSession) SetChainGasAmount(newChainGasAmount *big.Int) (*types.Transaction, error) { - return _Admin.Contract.SetChainGasAmount(&_Admin.TransactOpts, newChainGasAmount) +// Solidity: function setCancelDelay(uint256 newCancelDelay) returns() +func (_AdminV2 *AdminV2Session) SetCancelDelay(newCancelDelay *big.Int) (*types.Transaction, error) { + return _AdminV2.Contract.SetCancelDelay(&_AdminV2.TransactOpts, newCancelDelay) } -// SetChainGasAmount is a paid mutator transaction binding the contract method 0xb250fe6b. +// SetCancelDelay is a paid mutator transaction binding the contract method 0x1ea327c5. // -// Solidity: function setChainGasAmount(uint256 newChainGasAmount) returns() -func (_Admin *AdminTransactorSession) SetChainGasAmount(newChainGasAmount *big.Int) (*types.Transaction, error) { - return _Admin.Contract.SetChainGasAmount(&_Admin.TransactOpts, newChainGasAmount) +// Solidity: function setCancelDelay(uint256 newCancelDelay) returns() +func (_AdminV2 *AdminV2TransactorSession) SetCancelDelay(newCancelDelay *big.Int) (*types.Transaction, error) { + return _AdminV2.Contract.SetCancelDelay(&_AdminV2.TransactOpts, newCancelDelay) } // SetProtocolFeeRate is a paid mutator transaction binding the contract method 0xb13aa2d6. // // Solidity: function setProtocolFeeRate(uint256 newFeeRate) returns() -func (_Admin *AdminTransactor) SetProtocolFeeRate(opts *bind.TransactOpts, newFeeRate *big.Int) (*types.Transaction, error) { - return _Admin.contract.Transact(opts, "setProtocolFeeRate", newFeeRate) +func (_AdminV2 *AdminV2Transactor) SetProtocolFeeRate(opts *bind.TransactOpts, newFeeRate *big.Int) (*types.Transaction, error) { + return _AdminV2.contract.Transact(opts, "setProtocolFeeRate", newFeeRate) } // SetProtocolFeeRate is a paid mutator transaction binding the contract method 0xb13aa2d6. // // Solidity: function setProtocolFeeRate(uint256 newFeeRate) returns() -func (_Admin *AdminSession) SetProtocolFeeRate(newFeeRate *big.Int) (*types.Transaction, error) { - return _Admin.Contract.SetProtocolFeeRate(&_Admin.TransactOpts, newFeeRate) +func (_AdminV2 *AdminV2Session) SetProtocolFeeRate(newFeeRate *big.Int) (*types.Transaction, error) { + return _AdminV2.Contract.SetProtocolFeeRate(&_AdminV2.TransactOpts, newFeeRate) } // SetProtocolFeeRate is a paid mutator transaction binding the contract method 0xb13aa2d6. // // Solidity: function setProtocolFeeRate(uint256 newFeeRate) returns() -func (_Admin *AdminTransactorSession) SetProtocolFeeRate(newFeeRate *big.Int) (*types.Transaction, error) { - return _Admin.Contract.SetProtocolFeeRate(&_Admin.TransactOpts, newFeeRate) +func (_AdminV2 *AdminV2TransactorSession) SetProtocolFeeRate(newFeeRate *big.Int) (*types.Transaction, error) { + return _AdminV2.Contract.SetProtocolFeeRate(&_AdminV2.TransactOpts, newFeeRate) } // SweepProtocolFees is a paid mutator transaction binding the contract method 0x06f333f2. // // Solidity: function sweepProtocolFees(address token, address recipient) returns() -func (_Admin *AdminTransactor) SweepProtocolFees(opts *bind.TransactOpts, token common.Address, recipient common.Address) (*types.Transaction, error) { - return _Admin.contract.Transact(opts, "sweepProtocolFees", token, recipient) +func (_AdminV2 *AdminV2Transactor) SweepProtocolFees(opts *bind.TransactOpts, token common.Address, recipient common.Address) (*types.Transaction, error) { + return _AdminV2.contract.Transact(opts, "sweepProtocolFees", token, recipient) } // SweepProtocolFees is a paid mutator transaction binding the contract method 0x06f333f2. // // Solidity: function sweepProtocolFees(address token, address recipient) returns() -func (_Admin *AdminSession) SweepProtocolFees(token common.Address, recipient common.Address) (*types.Transaction, error) { - return _Admin.Contract.SweepProtocolFees(&_Admin.TransactOpts, token, recipient) +func (_AdminV2 *AdminV2Session) SweepProtocolFees(token common.Address, recipient common.Address) (*types.Transaction, error) { + return _AdminV2.Contract.SweepProtocolFees(&_AdminV2.TransactOpts, token, recipient) } // SweepProtocolFees is a paid mutator transaction binding the contract method 0x06f333f2. // // Solidity: function sweepProtocolFees(address token, address recipient) returns() -func (_Admin *AdminTransactorSession) SweepProtocolFees(token common.Address, recipient common.Address) (*types.Transaction, error) { - return _Admin.Contract.SweepProtocolFees(&_Admin.TransactOpts, token, recipient) +func (_AdminV2 *AdminV2TransactorSession) SweepProtocolFees(token common.Address, recipient common.Address) (*types.Transaction, error) { + return _AdminV2.Contract.SweepProtocolFees(&_AdminV2.TransactOpts, token, recipient) } -// AdminChainGasAmountUpdatedIterator is returned from FilterChainGasAmountUpdated and is used to iterate over the raw logs and unpacked data for ChainGasAmountUpdated events raised by the Admin contract. -type AdminChainGasAmountUpdatedIterator struct { - Event *AdminChainGasAmountUpdated // Event containing the contract specifics and raw log +// AdminV2CancelDelayUpdatedIterator is returned from FilterCancelDelayUpdated and is used to iterate over the raw logs and unpacked data for CancelDelayUpdated events raised by the AdminV2 contract. +type AdminV2CancelDelayUpdatedIterator struct { + Event *AdminV2CancelDelayUpdated // Event containing the contract specifics and raw log contract *bind.BoundContract // Generic contract to use for unpacking event data event string // Event name to use for unpacking event data @@ -2810,7 +2970,7 @@ type AdminChainGasAmountUpdatedIterator struct { // Next advances the iterator to the subsequent event, returning whether there // are any more events found. In case of a retrieval or parsing error, false is // returned and Error() can be queried for the exact failure. -func (it *AdminChainGasAmountUpdatedIterator) Next() bool { +func (it *AdminV2CancelDelayUpdatedIterator) Next() bool { // If the iterator failed, stop iterating if it.fail != nil { return false @@ -2819,7 +2979,7 @@ func (it *AdminChainGasAmountUpdatedIterator) Next() bool { if it.done { select { case log := <-it.logs: - it.Event = new(AdminChainGasAmountUpdated) + it.Event = new(AdminV2CancelDelayUpdated) if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { it.fail = err return false @@ -2834,7 +2994,7 @@ func (it *AdminChainGasAmountUpdatedIterator) Next() bool { // Iterator still in progress, wait for either a data or an error event select { case log := <-it.logs: - it.Event = new(AdminChainGasAmountUpdated) + it.Event = new(AdminV2CancelDelayUpdated) if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { it.fail = err return false @@ -2850,42 +3010,42 @@ func (it *AdminChainGasAmountUpdatedIterator) Next() bool { } // Error returns any retrieval or parsing error occurred during filtering. -func (it *AdminChainGasAmountUpdatedIterator) Error() error { +func (it *AdminV2CancelDelayUpdatedIterator) Error() error { return it.fail } // Close terminates the iteration process, releasing any pending underlying // resources. -func (it *AdminChainGasAmountUpdatedIterator) Close() error { +func (it *AdminV2CancelDelayUpdatedIterator) Close() error { it.sub.Unsubscribe() return nil } -// AdminChainGasAmountUpdated represents a ChainGasAmountUpdated event raised by the Admin contract. -type AdminChainGasAmountUpdated struct { - OldChainGasAmount *big.Int - NewChainGasAmount *big.Int - Raw types.Log // Blockchain specific contextual infos +// AdminV2CancelDelayUpdated represents a CancelDelayUpdated event raised by the AdminV2 contract. +type AdminV2CancelDelayUpdated struct { + OldCancelDelay *big.Int + NewCancelDelay *big.Int + Raw types.Log // Blockchain specific contextual infos } -// FilterChainGasAmountUpdated is a free log retrieval operation binding the contract event 0x5cf09b12f3f56b4c564d51b25b40360af6d795198adb61ae0806a36c294323fa. +// FilterCancelDelayUpdated is a free log retrieval operation binding the contract event 0x909f9078b2f6eac1d10f2aae793656c5a67511eb627ebd1d2cb1eb9c0ab94c95. // -// Solidity: event ChainGasAmountUpdated(uint256 oldChainGasAmount, uint256 newChainGasAmount) -func (_Admin *AdminFilterer) FilterChainGasAmountUpdated(opts *bind.FilterOpts) (*AdminChainGasAmountUpdatedIterator, error) { +// Solidity: event CancelDelayUpdated(uint256 oldCancelDelay, uint256 newCancelDelay) +func (_AdminV2 *AdminV2Filterer) FilterCancelDelayUpdated(opts *bind.FilterOpts) (*AdminV2CancelDelayUpdatedIterator, error) { - logs, sub, err := _Admin.contract.FilterLogs(opts, "ChainGasAmountUpdated") + logs, sub, err := _AdminV2.contract.FilterLogs(opts, "CancelDelayUpdated") if err != nil { return nil, err } - return &AdminChainGasAmountUpdatedIterator{contract: _Admin.contract, event: "ChainGasAmountUpdated", logs: logs, sub: sub}, nil + return &AdminV2CancelDelayUpdatedIterator{contract: _AdminV2.contract, event: "CancelDelayUpdated", logs: logs, sub: sub}, nil } -// WatchChainGasAmountUpdated is a free log subscription operation binding the contract event 0x5cf09b12f3f56b4c564d51b25b40360af6d795198adb61ae0806a36c294323fa. +// WatchCancelDelayUpdated is a free log subscription operation binding the contract event 0x909f9078b2f6eac1d10f2aae793656c5a67511eb627ebd1d2cb1eb9c0ab94c95. // -// Solidity: event ChainGasAmountUpdated(uint256 oldChainGasAmount, uint256 newChainGasAmount) -func (_Admin *AdminFilterer) WatchChainGasAmountUpdated(opts *bind.WatchOpts, sink chan<- *AdminChainGasAmountUpdated) (event.Subscription, error) { +// Solidity: event CancelDelayUpdated(uint256 oldCancelDelay, uint256 newCancelDelay) +func (_AdminV2 *AdminV2Filterer) WatchCancelDelayUpdated(opts *bind.WatchOpts, sink chan<- *AdminV2CancelDelayUpdated) (event.Subscription, error) { - logs, sub, err := _Admin.contract.WatchLogs(opts, "ChainGasAmountUpdated") + logs, sub, err := _AdminV2.contract.WatchLogs(opts, "CancelDelayUpdated") if err != nil { return nil, err } @@ -2895,8 +3055,8 @@ func (_Admin *AdminFilterer) WatchChainGasAmountUpdated(opts *bind.WatchOpts, si select { case log := <-logs: // New log arrived, parse the event and forward to the user - event := new(AdminChainGasAmountUpdated) - if err := _Admin.contract.UnpackLog(event, "ChainGasAmountUpdated", log); err != nil { + event := new(AdminV2CancelDelayUpdated) + if err := _AdminV2.contract.UnpackLog(event, "CancelDelayUpdated", log); err != nil { return err } event.Raw = log @@ -2917,21 +3077,21 @@ func (_Admin *AdminFilterer) WatchChainGasAmountUpdated(opts *bind.WatchOpts, si }), nil } -// ParseChainGasAmountUpdated is a log parse operation binding the contract event 0x5cf09b12f3f56b4c564d51b25b40360af6d795198adb61ae0806a36c294323fa. +// ParseCancelDelayUpdated is a log parse operation binding the contract event 0x909f9078b2f6eac1d10f2aae793656c5a67511eb627ebd1d2cb1eb9c0ab94c95. // -// Solidity: event ChainGasAmountUpdated(uint256 oldChainGasAmount, uint256 newChainGasAmount) -func (_Admin *AdminFilterer) ParseChainGasAmountUpdated(log types.Log) (*AdminChainGasAmountUpdated, error) { - event := new(AdminChainGasAmountUpdated) - if err := _Admin.contract.UnpackLog(event, "ChainGasAmountUpdated", log); err != nil { +// Solidity: event CancelDelayUpdated(uint256 oldCancelDelay, uint256 newCancelDelay) +func (_AdminV2 *AdminV2Filterer) ParseCancelDelayUpdated(log types.Log) (*AdminV2CancelDelayUpdated, error) { + event := new(AdminV2CancelDelayUpdated) + if err := _AdminV2.contract.UnpackLog(event, "CancelDelayUpdated", log); err != nil { return nil, err } event.Raw = log return event, nil } -// AdminFeeRateUpdatedIterator is returned from FilterFeeRateUpdated and is used to iterate over the raw logs and unpacked data for FeeRateUpdated events raised by the Admin contract. -type AdminFeeRateUpdatedIterator struct { - Event *AdminFeeRateUpdated // Event containing the contract specifics and raw log +// AdminV2FeeRateUpdatedIterator is returned from FilterFeeRateUpdated and is used to iterate over the raw logs and unpacked data for FeeRateUpdated events raised by the AdminV2 contract. +type AdminV2FeeRateUpdatedIterator struct { + Event *AdminV2FeeRateUpdated // Event containing the contract specifics and raw log contract *bind.BoundContract // Generic contract to use for unpacking event data event string // Event name to use for unpacking event data @@ -2945,7 +3105,7 @@ type AdminFeeRateUpdatedIterator struct { // Next advances the iterator to the subsequent event, returning whether there // are any more events found. In case of a retrieval or parsing error, false is // returned and Error() can be queried for the exact failure. -func (it *AdminFeeRateUpdatedIterator) Next() bool { +func (it *AdminV2FeeRateUpdatedIterator) Next() bool { // If the iterator failed, stop iterating if it.fail != nil { return false @@ -2954,7 +3114,7 @@ func (it *AdminFeeRateUpdatedIterator) Next() bool { if it.done { select { case log := <-it.logs: - it.Event = new(AdminFeeRateUpdated) + it.Event = new(AdminV2FeeRateUpdated) if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { it.fail = err return false @@ -2969,7 +3129,7 @@ func (it *AdminFeeRateUpdatedIterator) Next() bool { // Iterator still in progress, wait for either a data or an error event select { case log := <-it.logs: - it.Event = new(AdminFeeRateUpdated) + it.Event = new(AdminV2FeeRateUpdated) if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { it.fail = err return false @@ -2985,19 +3145,19 @@ func (it *AdminFeeRateUpdatedIterator) Next() bool { } // Error returns any retrieval or parsing error occurred during filtering. -func (it *AdminFeeRateUpdatedIterator) Error() error { +func (it *AdminV2FeeRateUpdatedIterator) Error() error { return it.fail } // Close terminates the iteration process, releasing any pending underlying // resources. -func (it *AdminFeeRateUpdatedIterator) Close() error { +func (it *AdminV2FeeRateUpdatedIterator) Close() error { it.sub.Unsubscribe() return nil } -// AdminFeeRateUpdated represents a FeeRateUpdated event raised by the Admin contract. -type AdminFeeRateUpdated struct { +// AdminV2FeeRateUpdated represents a FeeRateUpdated event raised by the AdminV2 contract. +type AdminV2FeeRateUpdated struct { OldFeeRate *big.Int NewFeeRate *big.Int Raw types.Log // Blockchain specific contextual infos @@ -3006,21 +3166,21 @@ type AdminFeeRateUpdated struct { // FilterFeeRateUpdated is a free log retrieval operation binding the contract event 0x14914da2bf76024616fbe1859783fcd4dbddcb179b1f3a854949fbf920dcb957. // // Solidity: event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate) -func (_Admin *AdminFilterer) FilterFeeRateUpdated(opts *bind.FilterOpts) (*AdminFeeRateUpdatedIterator, error) { +func (_AdminV2 *AdminV2Filterer) FilterFeeRateUpdated(opts *bind.FilterOpts) (*AdminV2FeeRateUpdatedIterator, error) { - logs, sub, err := _Admin.contract.FilterLogs(opts, "FeeRateUpdated") + logs, sub, err := _AdminV2.contract.FilterLogs(opts, "FeeRateUpdated") if err != nil { return nil, err } - return &AdminFeeRateUpdatedIterator{contract: _Admin.contract, event: "FeeRateUpdated", logs: logs, sub: sub}, nil + return &AdminV2FeeRateUpdatedIterator{contract: _AdminV2.contract, event: "FeeRateUpdated", logs: logs, sub: sub}, nil } // WatchFeeRateUpdated is a free log subscription operation binding the contract event 0x14914da2bf76024616fbe1859783fcd4dbddcb179b1f3a854949fbf920dcb957. // // Solidity: event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate) -func (_Admin *AdminFilterer) WatchFeeRateUpdated(opts *bind.WatchOpts, sink chan<- *AdminFeeRateUpdated) (event.Subscription, error) { +func (_AdminV2 *AdminV2Filterer) WatchFeeRateUpdated(opts *bind.WatchOpts, sink chan<- *AdminV2FeeRateUpdated) (event.Subscription, error) { - logs, sub, err := _Admin.contract.WatchLogs(opts, "FeeRateUpdated") + logs, sub, err := _AdminV2.contract.WatchLogs(opts, "FeeRateUpdated") if err != nil { return nil, err } @@ -3030,8 +3190,8 @@ func (_Admin *AdminFilterer) WatchFeeRateUpdated(opts *bind.WatchOpts, sink chan select { case log := <-logs: // New log arrived, parse the event and forward to the user - event := new(AdminFeeRateUpdated) - if err := _Admin.contract.UnpackLog(event, "FeeRateUpdated", log); err != nil { + event := new(AdminV2FeeRateUpdated) + if err := _AdminV2.contract.UnpackLog(event, "FeeRateUpdated", log); err != nil { return err } event.Raw = log @@ -3055,18 +3215,18 @@ func (_Admin *AdminFilterer) WatchFeeRateUpdated(opts *bind.WatchOpts, sink chan // ParseFeeRateUpdated is a log parse operation binding the contract event 0x14914da2bf76024616fbe1859783fcd4dbddcb179b1f3a854949fbf920dcb957. // // Solidity: event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate) -func (_Admin *AdminFilterer) ParseFeeRateUpdated(log types.Log) (*AdminFeeRateUpdated, error) { - event := new(AdminFeeRateUpdated) - if err := _Admin.contract.UnpackLog(event, "FeeRateUpdated", log); err != nil { +func (_AdminV2 *AdminV2Filterer) ParseFeeRateUpdated(log types.Log) (*AdminV2FeeRateUpdated, error) { + event := new(AdminV2FeeRateUpdated) + if err := _AdminV2.contract.UnpackLog(event, "FeeRateUpdated", log); err != nil { return nil, err } event.Raw = log return event, nil } -// AdminFeesSweptIterator is returned from FilterFeesSwept and is used to iterate over the raw logs and unpacked data for FeesSwept events raised by the Admin contract. -type AdminFeesSweptIterator struct { - Event *AdminFeesSwept // Event containing the contract specifics and raw log +// AdminV2FeesSweptIterator is returned from FilterFeesSwept and is used to iterate over the raw logs and unpacked data for FeesSwept events raised by the AdminV2 contract. +type AdminV2FeesSweptIterator struct { + Event *AdminV2FeesSwept // Event containing the contract specifics and raw log contract *bind.BoundContract // Generic contract to use for unpacking event data event string // Event name to use for unpacking event data @@ -3080,7 +3240,7 @@ type AdminFeesSweptIterator struct { // Next advances the iterator to the subsequent event, returning whether there // are any more events found. In case of a retrieval or parsing error, false is // returned and Error() can be queried for the exact failure. -func (it *AdminFeesSweptIterator) Next() bool { +func (it *AdminV2FeesSweptIterator) Next() bool { // If the iterator failed, stop iterating if it.fail != nil { return false @@ -3089,7 +3249,7 @@ func (it *AdminFeesSweptIterator) Next() bool { if it.done { select { case log := <-it.logs: - it.Event = new(AdminFeesSwept) + it.Event = new(AdminV2FeesSwept) if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { it.fail = err return false @@ -3104,7 +3264,7 @@ func (it *AdminFeesSweptIterator) Next() bool { // Iterator still in progress, wait for either a data or an error event select { case log := <-it.logs: - it.Event = new(AdminFeesSwept) + it.Event = new(AdminV2FeesSwept) if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { it.fail = err return false @@ -3120,19 +3280,19 @@ func (it *AdminFeesSweptIterator) Next() bool { } // Error returns any retrieval or parsing error occurred during filtering. -func (it *AdminFeesSweptIterator) Error() error { +func (it *AdminV2FeesSweptIterator) Error() error { return it.fail } // Close terminates the iteration process, releasing any pending underlying // resources. -func (it *AdminFeesSweptIterator) Close() error { +func (it *AdminV2FeesSweptIterator) Close() error { it.sub.Unsubscribe() return nil } -// AdminFeesSwept represents a FeesSwept event raised by the Admin contract. -type AdminFeesSwept struct { +// AdminV2FeesSwept represents a FeesSwept event raised by the AdminV2 contract. +type AdminV2FeesSwept struct { Token common.Address Recipient common.Address Amount *big.Int @@ -3142,21 +3302,21 @@ type AdminFeesSwept struct { // FilterFeesSwept is a free log retrieval operation binding the contract event 0x244e51bc38c1452fa8aaf487bcb4bca36c2baa3a5fbdb776b1eabd8dc6d277cd. // // Solidity: event FeesSwept(address token, address recipient, uint256 amount) -func (_Admin *AdminFilterer) FilterFeesSwept(opts *bind.FilterOpts) (*AdminFeesSweptIterator, error) { +func (_AdminV2 *AdminV2Filterer) FilterFeesSwept(opts *bind.FilterOpts) (*AdminV2FeesSweptIterator, error) { - logs, sub, err := _Admin.contract.FilterLogs(opts, "FeesSwept") + logs, sub, err := _AdminV2.contract.FilterLogs(opts, "FeesSwept") if err != nil { return nil, err } - return &AdminFeesSweptIterator{contract: _Admin.contract, event: "FeesSwept", logs: logs, sub: sub}, nil + return &AdminV2FeesSweptIterator{contract: _AdminV2.contract, event: "FeesSwept", logs: logs, sub: sub}, nil } // WatchFeesSwept is a free log subscription operation binding the contract event 0x244e51bc38c1452fa8aaf487bcb4bca36c2baa3a5fbdb776b1eabd8dc6d277cd. // // Solidity: event FeesSwept(address token, address recipient, uint256 amount) -func (_Admin *AdminFilterer) WatchFeesSwept(opts *bind.WatchOpts, sink chan<- *AdminFeesSwept) (event.Subscription, error) { +func (_AdminV2 *AdminV2Filterer) WatchFeesSwept(opts *bind.WatchOpts, sink chan<- *AdminV2FeesSwept) (event.Subscription, error) { - logs, sub, err := _Admin.contract.WatchLogs(opts, "FeesSwept") + logs, sub, err := _AdminV2.contract.WatchLogs(opts, "FeesSwept") if err != nil { return nil, err } @@ -3166,8 +3326,8 @@ func (_Admin *AdminFilterer) WatchFeesSwept(opts *bind.WatchOpts, sink chan<- *A select { case log := <-logs: // New log arrived, parse the event and forward to the user - event := new(AdminFeesSwept) - if err := _Admin.contract.UnpackLog(event, "FeesSwept", log); err != nil { + event := new(AdminV2FeesSwept) + if err := _AdminV2.contract.UnpackLog(event, "FeesSwept", log); err != nil { return err } event.Raw = log @@ -3191,18 +3351,18 @@ func (_Admin *AdminFilterer) WatchFeesSwept(opts *bind.WatchOpts, sink chan<- *A // ParseFeesSwept is a log parse operation binding the contract event 0x244e51bc38c1452fa8aaf487bcb4bca36c2baa3a5fbdb776b1eabd8dc6d277cd. // // Solidity: event FeesSwept(address token, address recipient, uint256 amount) -func (_Admin *AdminFilterer) ParseFeesSwept(log types.Log) (*AdminFeesSwept, error) { - event := new(AdminFeesSwept) - if err := _Admin.contract.UnpackLog(event, "FeesSwept", log); err != nil { +func (_AdminV2 *AdminV2Filterer) ParseFeesSwept(log types.Log) (*AdminV2FeesSwept, error) { + event := new(AdminV2FeesSwept) + if err := _AdminV2.contract.UnpackLog(event, "FeesSwept", log); err != nil { return nil, err } event.Raw = log return event, nil } -// AdminRoleAdminChangedIterator is returned from FilterRoleAdminChanged and is used to iterate over the raw logs and unpacked data for RoleAdminChanged events raised by the Admin contract. -type AdminRoleAdminChangedIterator struct { - Event *AdminRoleAdminChanged // Event containing the contract specifics and raw log +// AdminV2RoleAdminChangedIterator is returned from FilterRoleAdminChanged and is used to iterate over the raw logs and unpacked data for RoleAdminChanged events raised by the AdminV2 contract. +type AdminV2RoleAdminChangedIterator struct { + Event *AdminV2RoleAdminChanged // Event containing the contract specifics and raw log contract *bind.BoundContract // Generic contract to use for unpacking event data event string // Event name to use for unpacking event data @@ -3216,7 +3376,7 @@ type AdminRoleAdminChangedIterator struct { // Next advances the iterator to the subsequent event, returning whether there // are any more events found. In case of a retrieval or parsing error, false is // returned and Error() can be queried for the exact failure. -func (it *AdminRoleAdminChangedIterator) Next() bool { +func (it *AdminV2RoleAdminChangedIterator) Next() bool { // If the iterator failed, stop iterating if it.fail != nil { return false @@ -3225,7 +3385,7 @@ func (it *AdminRoleAdminChangedIterator) Next() bool { if it.done { select { case log := <-it.logs: - it.Event = new(AdminRoleAdminChanged) + it.Event = new(AdminV2RoleAdminChanged) if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { it.fail = err return false @@ -3240,7 +3400,7 @@ func (it *AdminRoleAdminChangedIterator) Next() bool { // Iterator still in progress, wait for either a data or an error event select { case log := <-it.logs: - it.Event = new(AdminRoleAdminChanged) + it.Event = new(AdminV2RoleAdminChanged) if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { it.fail = err return false @@ -3256,19 +3416,19 @@ func (it *AdminRoleAdminChangedIterator) Next() bool { } // Error returns any retrieval or parsing error occurred during filtering. -func (it *AdminRoleAdminChangedIterator) Error() error { +func (it *AdminV2RoleAdminChangedIterator) Error() error { return it.fail } // Close terminates the iteration process, releasing any pending underlying // resources. -func (it *AdminRoleAdminChangedIterator) Close() error { +func (it *AdminV2RoleAdminChangedIterator) Close() error { it.sub.Unsubscribe() return nil } -// AdminRoleAdminChanged represents a RoleAdminChanged event raised by the Admin contract. -type AdminRoleAdminChanged struct { +// AdminV2RoleAdminChanged represents a RoleAdminChanged event raised by the AdminV2 contract. +type AdminV2RoleAdminChanged struct { Role [32]byte PreviousAdminRole [32]byte NewAdminRole [32]byte @@ -3278,7 +3438,7 @@ type AdminRoleAdminChanged struct { // FilterRoleAdminChanged is a free log retrieval operation binding the contract event 0xbd79b86ffe0ab8e8776151514217cd7cacd52c909f66475c3af44e129f0b00ff. // // Solidity: event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole) -func (_Admin *AdminFilterer) FilterRoleAdminChanged(opts *bind.FilterOpts, role [][32]byte, previousAdminRole [][32]byte, newAdminRole [][32]byte) (*AdminRoleAdminChangedIterator, error) { +func (_AdminV2 *AdminV2Filterer) FilterRoleAdminChanged(opts *bind.FilterOpts, role [][32]byte, previousAdminRole [][32]byte, newAdminRole [][32]byte) (*AdminV2RoleAdminChangedIterator, error) { var roleRule []interface{} for _, roleItem := range role { @@ -3293,17 +3453,17 @@ func (_Admin *AdminFilterer) FilterRoleAdminChanged(opts *bind.FilterOpts, role newAdminRoleRule = append(newAdminRoleRule, newAdminRoleItem) } - logs, sub, err := _Admin.contract.FilterLogs(opts, "RoleAdminChanged", roleRule, previousAdminRoleRule, newAdminRoleRule) + logs, sub, err := _AdminV2.contract.FilterLogs(opts, "RoleAdminChanged", roleRule, previousAdminRoleRule, newAdminRoleRule) if err != nil { return nil, err } - return &AdminRoleAdminChangedIterator{contract: _Admin.contract, event: "RoleAdminChanged", logs: logs, sub: sub}, nil + return &AdminV2RoleAdminChangedIterator{contract: _AdminV2.contract, event: "RoleAdminChanged", logs: logs, sub: sub}, nil } // WatchRoleAdminChanged is a free log subscription operation binding the contract event 0xbd79b86ffe0ab8e8776151514217cd7cacd52c909f66475c3af44e129f0b00ff. // // Solidity: event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole) -func (_Admin *AdminFilterer) WatchRoleAdminChanged(opts *bind.WatchOpts, sink chan<- *AdminRoleAdminChanged, role [][32]byte, previousAdminRole [][32]byte, newAdminRole [][32]byte) (event.Subscription, error) { +func (_AdminV2 *AdminV2Filterer) WatchRoleAdminChanged(opts *bind.WatchOpts, sink chan<- *AdminV2RoleAdminChanged, role [][32]byte, previousAdminRole [][32]byte, newAdminRole [][32]byte) (event.Subscription, error) { var roleRule []interface{} for _, roleItem := range role { @@ -3318,7 +3478,7 @@ func (_Admin *AdminFilterer) WatchRoleAdminChanged(opts *bind.WatchOpts, sink ch newAdminRoleRule = append(newAdminRoleRule, newAdminRoleItem) } - logs, sub, err := _Admin.contract.WatchLogs(opts, "RoleAdminChanged", roleRule, previousAdminRoleRule, newAdminRoleRule) + logs, sub, err := _AdminV2.contract.WatchLogs(opts, "RoleAdminChanged", roleRule, previousAdminRoleRule, newAdminRoleRule) if err != nil { return nil, err } @@ -3328,8 +3488,8 @@ func (_Admin *AdminFilterer) WatchRoleAdminChanged(opts *bind.WatchOpts, sink ch select { case log := <-logs: // New log arrived, parse the event and forward to the user - event := new(AdminRoleAdminChanged) - if err := _Admin.contract.UnpackLog(event, "RoleAdminChanged", log); err != nil { + event := new(AdminV2RoleAdminChanged) + if err := _AdminV2.contract.UnpackLog(event, "RoleAdminChanged", log); err != nil { return err } event.Raw = log @@ -3353,18 +3513,18 @@ func (_Admin *AdminFilterer) WatchRoleAdminChanged(opts *bind.WatchOpts, sink ch // ParseRoleAdminChanged is a log parse operation binding the contract event 0xbd79b86ffe0ab8e8776151514217cd7cacd52c909f66475c3af44e129f0b00ff. // // Solidity: event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole) -func (_Admin *AdminFilterer) ParseRoleAdminChanged(log types.Log) (*AdminRoleAdminChanged, error) { - event := new(AdminRoleAdminChanged) - if err := _Admin.contract.UnpackLog(event, "RoleAdminChanged", log); err != nil { +func (_AdminV2 *AdminV2Filterer) ParseRoleAdminChanged(log types.Log) (*AdminV2RoleAdminChanged, error) { + event := new(AdminV2RoleAdminChanged) + if err := _AdminV2.contract.UnpackLog(event, "RoleAdminChanged", log); err != nil { return nil, err } event.Raw = log return event, nil } -// AdminRoleGrantedIterator is returned from FilterRoleGranted and is used to iterate over the raw logs and unpacked data for RoleGranted events raised by the Admin contract. -type AdminRoleGrantedIterator struct { - Event *AdminRoleGranted // Event containing the contract specifics and raw log +// AdminV2RoleGrantedIterator is returned from FilterRoleGranted and is used to iterate over the raw logs and unpacked data for RoleGranted events raised by the AdminV2 contract. +type AdminV2RoleGrantedIterator struct { + Event *AdminV2RoleGranted // Event containing the contract specifics and raw log contract *bind.BoundContract // Generic contract to use for unpacking event data event string // Event name to use for unpacking event data @@ -3378,7 +3538,7 @@ type AdminRoleGrantedIterator struct { // Next advances the iterator to the subsequent event, returning whether there // are any more events found. In case of a retrieval or parsing error, false is // returned and Error() can be queried for the exact failure. -func (it *AdminRoleGrantedIterator) Next() bool { +func (it *AdminV2RoleGrantedIterator) Next() bool { // If the iterator failed, stop iterating if it.fail != nil { return false @@ -3387,7 +3547,7 @@ func (it *AdminRoleGrantedIterator) Next() bool { if it.done { select { case log := <-it.logs: - it.Event = new(AdminRoleGranted) + it.Event = new(AdminV2RoleGranted) if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { it.fail = err return false @@ -3402,7 +3562,7 @@ func (it *AdminRoleGrantedIterator) Next() bool { // Iterator still in progress, wait for either a data or an error event select { case log := <-it.logs: - it.Event = new(AdminRoleGranted) + it.Event = new(AdminV2RoleGranted) if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { it.fail = err return false @@ -3418,19 +3578,19 @@ func (it *AdminRoleGrantedIterator) Next() bool { } // Error returns any retrieval or parsing error occurred during filtering. -func (it *AdminRoleGrantedIterator) Error() error { +func (it *AdminV2RoleGrantedIterator) Error() error { return it.fail } // Close terminates the iteration process, releasing any pending underlying // resources. -func (it *AdminRoleGrantedIterator) Close() error { +func (it *AdminV2RoleGrantedIterator) Close() error { it.sub.Unsubscribe() return nil } -// AdminRoleGranted represents a RoleGranted event raised by the Admin contract. -type AdminRoleGranted struct { +// AdminV2RoleGranted represents a RoleGranted event raised by the AdminV2 contract. +type AdminV2RoleGranted struct { Role [32]byte Account common.Address Sender common.Address @@ -3440,7 +3600,7 @@ type AdminRoleGranted struct { // FilterRoleGranted is a free log retrieval operation binding the contract event 0x2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d. // // Solidity: event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender) -func (_Admin *AdminFilterer) FilterRoleGranted(opts *bind.FilterOpts, role [][32]byte, account []common.Address, sender []common.Address) (*AdminRoleGrantedIterator, error) { +func (_AdminV2 *AdminV2Filterer) FilterRoleGranted(opts *bind.FilterOpts, role [][32]byte, account []common.Address, sender []common.Address) (*AdminV2RoleGrantedIterator, error) { var roleRule []interface{} for _, roleItem := range role { @@ -3455,17 +3615,17 @@ func (_Admin *AdminFilterer) FilterRoleGranted(opts *bind.FilterOpts, role [][32 senderRule = append(senderRule, senderItem) } - logs, sub, err := _Admin.contract.FilterLogs(opts, "RoleGranted", roleRule, accountRule, senderRule) + logs, sub, err := _AdminV2.contract.FilterLogs(opts, "RoleGranted", roleRule, accountRule, senderRule) if err != nil { return nil, err } - return &AdminRoleGrantedIterator{contract: _Admin.contract, event: "RoleGranted", logs: logs, sub: sub}, nil + return &AdminV2RoleGrantedIterator{contract: _AdminV2.contract, event: "RoleGranted", logs: logs, sub: sub}, nil } // WatchRoleGranted is a free log subscription operation binding the contract event 0x2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d. // // Solidity: event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender) -func (_Admin *AdminFilterer) WatchRoleGranted(opts *bind.WatchOpts, sink chan<- *AdminRoleGranted, role [][32]byte, account []common.Address, sender []common.Address) (event.Subscription, error) { +func (_AdminV2 *AdminV2Filterer) WatchRoleGranted(opts *bind.WatchOpts, sink chan<- *AdminV2RoleGranted, role [][32]byte, account []common.Address, sender []common.Address) (event.Subscription, error) { var roleRule []interface{} for _, roleItem := range role { @@ -3480,7 +3640,7 @@ func (_Admin *AdminFilterer) WatchRoleGranted(opts *bind.WatchOpts, sink chan<- senderRule = append(senderRule, senderItem) } - logs, sub, err := _Admin.contract.WatchLogs(opts, "RoleGranted", roleRule, accountRule, senderRule) + logs, sub, err := _AdminV2.contract.WatchLogs(opts, "RoleGranted", roleRule, accountRule, senderRule) if err != nil { return nil, err } @@ -3490,8 +3650,8 @@ func (_Admin *AdminFilterer) WatchRoleGranted(opts *bind.WatchOpts, sink chan<- select { case log := <-logs: // New log arrived, parse the event and forward to the user - event := new(AdminRoleGranted) - if err := _Admin.contract.UnpackLog(event, "RoleGranted", log); err != nil { + event := new(AdminV2RoleGranted) + if err := _AdminV2.contract.UnpackLog(event, "RoleGranted", log); err != nil { return err } event.Raw = log @@ -3515,18 +3675,18 @@ func (_Admin *AdminFilterer) WatchRoleGranted(opts *bind.WatchOpts, sink chan<- // ParseRoleGranted is a log parse operation binding the contract event 0x2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d. // // Solidity: event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender) -func (_Admin *AdminFilterer) ParseRoleGranted(log types.Log) (*AdminRoleGranted, error) { - event := new(AdminRoleGranted) - if err := _Admin.contract.UnpackLog(event, "RoleGranted", log); err != nil { +func (_AdminV2 *AdminV2Filterer) ParseRoleGranted(log types.Log) (*AdminV2RoleGranted, error) { + event := new(AdminV2RoleGranted) + if err := _AdminV2.contract.UnpackLog(event, "RoleGranted", log); err != nil { return nil, err } event.Raw = log return event, nil } -// AdminRoleRevokedIterator is returned from FilterRoleRevoked and is used to iterate over the raw logs and unpacked data for RoleRevoked events raised by the Admin contract. -type AdminRoleRevokedIterator struct { - Event *AdminRoleRevoked // Event containing the contract specifics and raw log +// AdminV2RoleRevokedIterator is returned from FilterRoleRevoked and is used to iterate over the raw logs and unpacked data for RoleRevoked events raised by the AdminV2 contract. +type AdminV2RoleRevokedIterator struct { + Event *AdminV2RoleRevoked // Event containing the contract specifics and raw log contract *bind.BoundContract // Generic contract to use for unpacking event data event string // Event name to use for unpacking event data @@ -3540,7 +3700,7 @@ type AdminRoleRevokedIterator struct { // Next advances the iterator to the subsequent event, returning whether there // are any more events found. In case of a retrieval or parsing error, false is // returned and Error() can be queried for the exact failure. -func (it *AdminRoleRevokedIterator) Next() bool { +func (it *AdminV2RoleRevokedIterator) Next() bool { // If the iterator failed, stop iterating if it.fail != nil { return false @@ -3549,7 +3709,7 @@ func (it *AdminRoleRevokedIterator) Next() bool { if it.done { select { case log := <-it.logs: - it.Event = new(AdminRoleRevoked) + it.Event = new(AdminV2RoleRevoked) if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { it.fail = err return false @@ -3564,7 +3724,7 @@ func (it *AdminRoleRevokedIterator) Next() bool { // Iterator still in progress, wait for either a data or an error event select { case log := <-it.logs: - it.Event = new(AdminRoleRevoked) + it.Event = new(AdminV2RoleRevoked) if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { it.fail = err return false @@ -3580,19 +3740,19 @@ func (it *AdminRoleRevokedIterator) Next() bool { } // Error returns any retrieval or parsing error occurred during filtering. -func (it *AdminRoleRevokedIterator) Error() error { +func (it *AdminV2RoleRevokedIterator) Error() error { return it.fail } // Close terminates the iteration process, releasing any pending underlying // resources. -func (it *AdminRoleRevokedIterator) Close() error { +func (it *AdminV2RoleRevokedIterator) Close() error { it.sub.Unsubscribe() return nil } -// AdminRoleRevoked represents a RoleRevoked event raised by the Admin contract. -type AdminRoleRevoked struct { +// AdminV2RoleRevoked represents a RoleRevoked event raised by the AdminV2 contract. +type AdminV2RoleRevoked struct { Role [32]byte Account common.Address Sender common.Address @@ -3602,7 +3762,7 @@ type AdminRoleRevoked struct { // FilterRoleRevoked is a free log retrieval operation binding the contract event 0xf6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b. // // Solidity: event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender) -func (_Admin *AdminFilterer) FilterRoleRevoked(opts *bind.FilterOpts, role [][32]byte, account []common.Address, sender []common.Address) (*AdminRoleRevokedIterator, error) { +func (_AdminV2 *AdminV2Filterer) FilterRoleRevoked(opts *bind.FilterOpts, role [][32]byte, account []common.Address, sender []common.Address) (*AdminV2RoleRevokedIterator, error) { var roleRule []interface{} for _, roleItem := range role { @@ -3617,17 +3777,17 @@ func (_Admin *AdminFilterer) FilterRoleRevoked(opts *bind.FilterOpts, role [][32 senderRule = append(senderRule, senderItem) } - logs, sub, err := _Admin.contract.FilterLogs(opts, "RoleRevoked", roleRule, accountRule, senderRule) + logs, sub, err := _AdminV2.contract.FilterLogs(opts, "RoleRevoked", roleRule, accountRule, senderRule) if err != nil { return nil, err } - return &AdminRoleRevokedIterator{contract: _Admin.contract, event: "RoleRevoked", logs: logs, sub: sub}, nil + return &AdminV2RoleRevokedIterator{contract: _AdminV2.contract, event: "RoleRevoked", logs: logs, sub: sub}, nil } // WatchRoleRevoked is a free log subscription operation binding the contract event 0xf6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b. // // Solidity: event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender) -func (_Admin *AdminFilterer) WatchRoleRevoked(opts *bind.WatchOpts, sink chan<- *AdminRoleRevoked, role [][32]byte, account []common.Address, sender []common.Address) (event.Subscription, error) { +func (_AdminV2 *AdminV2Filterer) WatchRoleRevoked(opts *bind.WatchOpts, sink chan<- *AdminV2RoleRevoked, role [][32]byte, account []common.Address, sender []common.Address) (event.Subscription, error) { var roleRule []interface{} for _, roleItem := range role { @@ -3642,7 +3802,7 @@ func (_Admin *AdminFilterer) WatchRoleRevoked(opts *bind.WatchOpts, sink chan<- senderRule = append(senderRule, senderItem) } - logs, sub, err := _Admin.contract.WatchLogs(opts, "RoleRevoked", roleRule, accountRule, senderRule) + logs, sub, err := _AdminV2.contract.WatchLogs(opts, "RoleRevoked", roleRule, accountRule, senderRule) if err != nil { return nil, err } @@ -3652,8 +3812,8 @@ func (_Admin *AdminFilterer) WatchRoleRevoked(opts *bind.WatchOpts, sink chan<- select { case log := <-logs: // New log arrived, parse the event and forward to the user - event := new(AdminRoleRevoked) - if err := _Admin.contract.UnpackLog(event, "RoleRevoked", log); err != nil { + event := new(AdminV2RoleRevoked) + if err := _AdminV2.contract.UnpackLog(event, "RoleRevoked", log); err != nil { return err } event.Raw = log @@ -3677,9 +3837,9 @@ func (_Admin *AdminFilterer) WatchRoleRevoked(opts *bind.WatchOpts, sink chan<- // ParseRoleRevoked is a log parse operation binding the contract event 0xf6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b. // // Solidity: event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender) -func (_Admin *AdminFilterer) ParseRoleRevoked(log types.Log) (*AdminRoleRevoked, error) { - event := new(AdminRoleRevoked) - if err := _Admin.contract.UnpackLog(event, "RoleRevoked", log); err != nil { +func (_AdminV2 *AdminV2Filterer) ParseRoleRevoked(log types.Log) (*AdminV2RoleRevoked, error) { + event := new(AdminV2RoleRevoked) + if err := _AdminV2.contract.UnpackLog(event, "RoleRevoked", log); err != nil { return nil, err } event.Raw = log @@ -3689,7 +3849,7 @@ func (_Admin *AdminFilterer) ParseRoleRevoked(log types.Log) (*AdminRoleRevoked, // BridgeTransactionV2LibMetaData contains all meta data concerning the BridgeTransactionV2Lib contract. var BridgeTransactionV2LibMetaData = &bind.MetaData{ ABI: "[{\"inputs\":[],\"name\":\"BridgeTransactionV2__InvalidEncodedTx\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint16\",\"name\":\"version\",\"type\":\"uint16\"}],\"name\":\"BridgeTransactionV2__UnsupportedVersion\",\"type\":\"error\"}]", - Bin: "0x60566037600b82828239805160001a607314602a57634e487b7160e01b600052600060045260246000fd5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600080fdfea2646970667358221220c0d1e2256fb16b1e19ad4848dc80aafe3c3f70b204e139f256b5d6095b52dd5564736f6c63430008180033", + Bin: "0x60566037600b82828239805160001a607314602a57634e487b7160e01b600052600060045260246000fd5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600080fdfea2646970667358221220736bb5e8e495fb3a776c3cad8b30577c46279a088f4f89b0d509badbef3da01f64736f6c63430008180033", } // BridgeTransactionV2LibABI is the input ABI used to generate the binding from. @@ -4202,7 +4362,7 @@ func (_ERC165 *ERC165CallerSession) SupportsInterface(interfaceId [4]byte) (bool // EnumerableSetMetaData contains all meta data concerning the EnumerableSet contract. var EnumerableSetMetaData = &bind.MetaData{ ABI: "[]", - Bin: "0x60566037600b82828239805160001a607314602a57634e487b7160e01b600052600060045260246000fd5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600080fdfea26469706673582212202a0689afaebf6ffa0f4d0a6fe04b9b6e642f8ef83c8db74e665e9fc77d71999964736f6c63430008180033", + Bin: "0x60566037600b82828239805160001a607314602a57634e487b7160e01b600052600060045260246000fd5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600080fdfea2646970667358221220cb930ba14bc69bdf61a9326099568898423db2bde70050effda1b23aa9e9dc9e64736f6c63430008180033", } // EnumerableSetABI is the input ABI used to generate the binding from. @@ -4374,20 +4534,22 @@ func (_EnumerableSet *EnumerableSetTransactorRaw) Transact(opts *bind.TransactOp // FastBridgeV2MetaData contains all meta data concerning the FastBridgeV2 contract. var FastBridgeV2MetaData = &bind.MetaData{ - ABI: "[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_owner\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"AccessControlBadConfirmation\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"neededRole\",\"type\":\"bytes32\"}],\"name\":\"AccessControlUnauthorizedAccount\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"}],\"name\":\"AddressEmptyCode\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"AddressInsufficientBalance\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"AmountIncorrect\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"BridgeTransactionV2__InvalidEncodedTx\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint16\",\"name\":\"version\",\"type\":\"uint16\"}],\"name\":\"BridgeTransactionV2__UnsupportedVersion\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ChainIncorrect\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DeadlineExceeded\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DeadlineNotExceeded\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DeadlineTooShort\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DisputePeriodNotPassed\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DisputePeriodPassed\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ExclusivityParamsIncorrect\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ExclusivityPeriodNotPassed\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"FailedInnerCall\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"MsgValueIncorrect\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"MulticallTarget__UndeterminedRevert\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"RecipientIncorrectReturnValue\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"RecipientNoReturnValue\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"}],\"name\":\"SafeERC20FailedOperation\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"SenderIncorrect\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"StatusIncorrect\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"TokenNotContract\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"TransactionRelayed\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ZapDataLengthAboveMax\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ZapNativeNotSupported\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ZeroAddress\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"BridgeDepositClaimed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"BridgeDepositRefunded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"name\":\"BridgeProofDisputed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"transactionHash\",\"type\":\"bytes32\"}],\"name\":\"BridgeProofProvided\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"quoteId\",\"type\":\"bytes\"}],\"name\":\"BridgeQuoteDetails\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"originChainId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"chainGasAmount\",\"type\":\"uint256\"}],\"name\":\"BridgeRelayed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"destChainId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"sendChainGas\",\"type\":\"bool\"}],\"name\":\"BridgeRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"oldChainGasAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newChainGasAmount\",\"type\":\"uint256\"}],\"name\":\"ChainGasAmountUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"oldFeeRate\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newFeeRate\",\"type\":\"uint256\"}],\"name\":\"FeeRateUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"FeesSwept\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"previousAdminRole\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"newAdminRole\",\"type\":\"bytes32\"}],\"name\":\"RoleAdminChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleGranted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleRevoked\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"DEFAULT_ADMIN_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"DISPUTE_PERIOD\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"FEE_BPS\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"FEE_RATE_MAX\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"GOVERNOR_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"GUARD_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"MAX_ZAP_DATA_LENGTH\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"MIN_DEADLINE_PERIOD\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"NATIVE_GAS_TOKEN\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"REFUNDER_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"REFUND_DELAY\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"RELAYER_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"dstChainId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"sendChainGas\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"}],\"internalType\":\"structIFastBridge.BridgeParams\",\"name\":\"params\",\"type\":\"tuple\"}],\"name\":\"bridge\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"dstChainId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"sendChainGas\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"}],\"internalType\":\"structIFastBridge.BridgeParams\",\"name\":\"params\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"quoteRelayer\",\"type\":\"address\"},{\"internalType\":\"int256\",\"name\":\"quoteExclusivitySeconds\",\"type\":\"int256\"},{\"internalType\":\"bytes\",\"name\":\"quoteId\",\"type\":\"bytes\"},{\"internalType\":\"uint256\",\"name\":\"zapNative\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"zapData\",\"type\":\"bytes\"}],\"internalType\":\"structIFastBridgeV2.BridgeParamsV2\",\"name\":\"paramsV2\",\"type\":\"tuple\"}],\"name\":\"bridge\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"}],\"name\":\"bridgeProofs\",\"outputs\":[{\"internalType\":\"uint96\",\"name\":\"timestamp\",\"type\":\"uint96\"},{\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"bridgeRelayDetails\",\"outputs\":[{\"internalType\":\"uint48\",\"name\":\"blockNumber\",\"type\":\"uint48\"},{\"internalType\":\"uint48\",\"name\":\"blockTimestamp\",\"type\":\"uint48\"},{\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"}],\"name\":\"bridgeRelays\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"}],\"name\":\"bridgeStatuses\",\"outputs\":[{\"internalType\":\"enumIFastBridgeV2.BridgeStatus\",\"name\":\"status\",\"type\":\"uint8\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"bridgeTxDetails\",\"outputs\":[{\"internalType\":\"enumIFastBridgeV2.BridgeStatus\",\"name\":\"status\",\"type\":\"uint8\"},{\"internalType\":\"uint32\",\"name\":\"destChainId\",\"type\":\"uint32\"},{\"internalType\":\"uint56\",\"name\":\"proofBlockTimestamp\",\"type\":\"uint56\"},{\"internalType\":\"address\",\"name\":\"proofRelayer\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"name\":\"canClaim\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"chainGasAmount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"claim\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"claim\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"deployBlock\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"}],\"name\":\"dispute\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"getBridgeTransaction\",\"outputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"originChainId\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"destChainId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"originSender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destRecipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"originFeeAmount\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"sendChainGas\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"}],\"internalType\":\"structIFastBridge.BridgeTransaction\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"getBridgeTransactionV2\",\"outputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"originChainId\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"destChainId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"originSender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destRecipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"originFeeAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"exclusivityRelayer\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"exclusivityEndTime\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"zapNative\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"zapData\",\"type\":\"bytes\"}],\"internalType\":\"structIFastBridgeV2.BridgeTransactionV2\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"}],\"name\":\"getRoleAdmin\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"index\",\"type\":\"uint256\"}],\"name\":\"getRoleMember\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"}],\"name\":\"getRoleMemberCount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"grantRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"hasRole\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes[]\",\"name\":\"data\",\"type\":\"bytes[]\"},{\"internalType\":\"bool\",\"name\":\"ignoreReverts\",\"type\":\"bool\"}],\"name\":\"multicallNoResults\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes[]\",\"name\":\"data\",\"type\":\"bytes[]\"},{\"internalType\":\"bool\",\"name\":\"ignoreReverts\",\"type\":\"bool\"}],\"name\":\"multicallWithResults\",\"outputs\":[{\"components\":[{\"internalType\":\"bool\",\"name\":\"success\",\"type\":\"bool\"},{\"internalType\":\"bytes\",\"name\":\"returnData\",\"type\":\"bytes\"}],\"internalType\":\"structIMulticallTarget.Result[]\",\"name\":\"results\",\"type\":\"tuple[]\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"nonce\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"protocolFeeRate\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"protocolFees\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"destTxHash\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"name\":\"prove\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"},{\"internalType\":\"bytes32\",\"name\":\"destTxHash\",\"type\":\"bytes32\"}],\"name\":\"prove\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"refund\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"relay\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"},{\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"name\":\"relay\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"callerConfirmation\",\"type\":\"address\"}],\"name\":\"renounceRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"revokeRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"senderNonces\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"newChainGasAmount\",\"type\":\"uint256\"}],\"name\":\"setChainGasAmount\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"newFeeRate\",\"type\":\"uint256\"}],\"name\":\"setProtocolFeeRate\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes4\",\"name\":\"interfaceId\",\"type\":\"bytes4\"}],\"name\":\"supportsInterface\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"}],\"name\":\"sweepProtocolFees\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", + ABI: "[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_owner\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"AccessControlBadConfirmation\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"neededRole\",\"type\":\"bytes32\"}],\"name\":\"AccessControlUnauthorizedAccount\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"}],\"name\":\"AddressEmptyCode\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"AddressInsufficientBalance\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"AmountIncorrect\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"BridgeTransactionV2__InvalidEncodedTx\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint16\",\"name\":\"version\",\"type\":\"uint16\"}],\"name\":\"BridgeTransactionV2__UnsupportedVersion\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"CancelDelayBelowMin\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ChainIncorrect\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DeadlineExceeded\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DeadlineNotExceeded\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DeadlineTooShort\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DisputePeriodNotPassed\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DisputePeriodPassed\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ExclusivityParamsIncorrect\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ExclusivityPeriodNotPassed\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"FailedInnerCall\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"FeeRateAboveMax\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"MsgValueIncorrect\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"MulticallTarget__UndeterminedRevert\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"RecipientIncorrectReturnValue\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"RecipientNoReturnValue\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"}],\"name\":\"SafeERC20FailedOperation\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"SenderIncorrect\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"StatusIncorrect\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"TokenNotContract\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"TransactionRelayed\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ZapDataLengthAboveMax\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ZapNativeNotSupported\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ZeroAddress\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"BridgeDepositClaimed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"BridgeDepositRefunded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"name\":\"BridgeProofDisputed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"transactionHash\",\"type\":\"bytes32\"}],\"name\":\"BridgeProofProvided\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"quoteId\",\"type\":\"bytes\"}],\"name\":\"BridgeQuoteDetails\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"originChainId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"chainGasAmount\",\"type\":\"uint256\"}],\"name\":\"BridgeRelayed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"destChainId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"sendChainGas\",\"type\":\"bool\"}],\"name\":\"BridgeRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"oldCancelDelay\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newCancelDelay\",\"type\":\"uint256\"}],\"name\":\"CancelDelayUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"oldFeeRate\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newFeeRate\",\"type\":\"uint256\"}],\"name\":\"FeeRateUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"FeesSwept\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"previousAdminRole\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"newAdminRole\",\"type\":\"bytes32\"}],\"name\":\"RoleAdminChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleGranted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleRevoked\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"CANCELER_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"DEFAULT_ADMIN_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"DEFAULT_CANCEL_DELAY\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"DISPUTE_PERIOD\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"FEE_BPS\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"FEE_RATE_MAX\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"GOVERNOR_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"GUARD_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"MAX_ZAP_DATA_LENGTH\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"MIN_CANCEL_DELAY\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"MIN_DEADLINE_PERIOD\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"NATIVE_GAS_TOKEN\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"PROVER_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"QUOTER_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"dstChainId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"sendChainGas\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"}],\"internalType\":\"structIFastBridge.BridgeParams\",\"name\":\"params\",\"type\":\"tuple\"}],\"name\":\"bridge\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"dstChainId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"sendChainGas\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"}],\"internalType\":\"structIFastBridge.BridgeParams\",\"name\":\"params\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"quoteRelayer\",\"type\":\"address\"},{\"internalType\":\"int256\",\"name\":\"quoteExclusivitySeconds\",\"type\":\"int256\"},{\"internalType\":\"bytes\",\"name\":\"quoteId\",\"type\":\"bytes\"},{\"internalType\":\"uint256\",\"name\":\"zapNative\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"zapData\",\"type\":\"bytes\"}],\"internalType\":\"structIFastBridgeV2.BridgeParamsV2\",\"name\":\"paramsV2\",\"type\":\"tuple\"}],\"name\":\"bridge\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"}],\"name\":\"bridgeProofs\",\"outputs\":[{\"internalType\":\"uint96\",\"name\":\"timestamp\",\"type\":\"uint96\"},{\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"bridgeRelayDetails\",\"outputs\":[{\"internalType\":\"uint48\",\"name\":\"blockNumber\",\"type\":\"uint48\"},{\"internalType\":\"uint48\",\"name\":\"blockTimestamp\",\"type\":\"uint48\"},{\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"}],\"name\":\"bridgeRelays\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"}],\"name\":\"bridgeStatuses\",\"outputs\":[{\"internalType\":\"enumIFastBridgeV2.BridgeStatus\",\"name\":\"status\",\"type\":\"uint8\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"bridgeTxDetails\",\"outputs\":[{\"internalType\":\"enumIFastBridgeV2.BridgeStatus\",\"name\":\"status\",\"type\":\"uint8\"},{\"internalType\":\"uint32\",\"name\":\"destChainId\",\"type\":\"uint32\"},{\"internalType\":\"uint56\",\"name\":\"proofBlockTimestamp\",\"type\":\"uint56\"},{\"internalType\":\"address\",\"name\":\"proofRelayer\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"name\":\"canClaim\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"cancel\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"cancelDelay\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"chainGasAmount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"claim\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"claim\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"deployBlock\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"}],\"name\":\"dispute\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"getBridgeTransaction\",\"outputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"originChainId\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"destChainId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"originSender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destRecipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"originFeeAmount\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"sendChainGas\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"}],\"internalType\":\"structIFastBridge.BridgeTransaction\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"getBridgeTransactionV2\",\"outputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"originChainId\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"destChainId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"originSender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destRecipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"originFeeAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"exclusivityRelayer\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"exclusivityEndTime\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"zapNative\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"zapData\",\"type\":\"bytes\"}],\"internalType\":\"structIFastBridgeV2.BridgeTransactionV2\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"}],\"name\":\"getRoleAdmin\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"index\",\"type\":\"uint256\"}],\"name\":\"getRoleMember\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"}],\"name\":\"getRoleMemberCount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"grantRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"hasRole\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes[]\",\"name\":\"data\",\"type\":\"bytes[]\"},{\"internalType\":\"bool\",\"name\":\"ignoreReverts\",\"type\":\"bool\"}],\"name\":\"multicallNoResults\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes[]\",\"name\":\"data\",\"type\":\"bytes[]\"},{\"internalType\":\"bool\",\"name\":\"ignoreReverts\",\"type\":\"bool\"}],\"name\":\"multicallWithResults\",\"outputs\":[{\"components\":[{\"internalType\":\"bool\",\"name\":\"success\",\"type\":\"bool\"},{\"internalType\":\"bytes\",\"name\":\"returnData\",\"type\":\"bytes\"}],\"internalType\":\"structIMulticallTarget.Result[]\",\"name\":\"results\",\"type\":\"tuple[]\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"nonce\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"protocolFeeRate\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"protocolFees\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"destTxHash\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"name\":\"prove\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"},{\"internalType\":\"bytes32\",\"name\":\"destTxHash\",\"type\":\"bytes32\"}],\"name\":\"prove\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"refund\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"relay\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"},{\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"name\":\"relay\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"callerConfirmation\",\"type\":\"address\"}],\"name\":\"renounceRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"revokeRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"senderNonces\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"newCancelDelay\",\"type\":\"uint256\"}],\"name\":\"setCancelDelay\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"newFeeRate\",\"type\":\"uint256\"}],\"name\":\"setProtocolFeeRate\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes4\",\"name\":\"interfaceId\",\"type\":\"bytes4\"}],\"name\":\"supportsInterface\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"}],\"name\":\"sweepProtocolFees\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", Sigs: map[string]string{ + "02d2ff66": "CANCELER_ROLE()", "a217fddf": "DEFAULT_ADMIN_ROLE()", + "930ac180": "DEFAULT_CANCEL_DELAY()", "a5bbe22b": "DISPUTE_PERIOD()", "bf333f2c": "FEE_BPS()", "0f5f6ed7": "FEE_RATE_MAX()", "ccc57490": "GOVERNOR_ROLE()", "03ed0ee5": "GUARD_ROLE()", "54eff068": "MAX_ZAP_DATA_LENGTH()", + "922b7487": "MIN_CANCEL_DELAY()", "820688d5": "MIN_DEADLINE_PERIOD()", "0f862f1e": "NATIVE_GAS_TOKEN()", - "5960ccf2": "REFUNDER_ROLE()", - "190da595": "REFUND_DELAY()", - "926d7d7f": "RELAYER_ROLE()", + "dc9a4ef6": "PROVER_ROLE()", + "7ebe815c": "QUOTER_ROLE()", "45851694": "bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256))", "bfc7c607": "bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256),(address,int256,bytes,uint256,bytes))", "91ad5039": "bridgeProofs(bytes32)", @@ -4396,6 +4558,8 @@ var FastBridgeV2MetaData = &bind.MetaData{ "051287bc": "bridgeStatuses(bytes32)", "63787e52": "bridgeTxDetails(bytes32)", "aa9641ab": "canClaim(bytes32,address)", + "3c5beeb4": "cancel(bytes)", + "638a0f09": "cancelDelay()", "e00a83e0": "chainGasAmount()", "c63ff8dd": "claim(bytes)", "41fcb612": "claim(bytes,address)", @@ -4421,12 +4585,12 @@ var FastBridgeV2MetaData = &bind.MetaData{ "36568abe": "renounceRole(bytes32,address)", "d547741f": "revokeRole(bytes32,address)", "295710ff": "senderNonces(address)", - "b250fe6b": "setChainGasAmount(uint256)", + "1ea327c5": "setCancelDelay(uint256)", "b13aa2d6": "setProtocolFeeRate(uint256)", "01ffc9a7": "supportsInterface(bytes4)", "06f333f2": "sweepProtocolFees(address,address)", }, - Bin: "0x60c060405260006080523480156200001657600080fd5b506040516200475c3803806200475c833981016040819052620000399162000199565b806200004760008262000054565b50504360a05250620001c4565b60008062000063848462000091565b90508015620000885760008481526001602052604090206200008690846200013f565b505b90505b92915050565b6000828152602081815260408083206001600160a01b038516845290915281205460ff1662000136576000838152602081815260408083206001600160a01b03861684529091529020805460ff19166001179055620000ed3390565b6001600160a01b0316826001600160a01b0316847f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45060016200008b565b5060006200008b565b600062000088836001600160a01b038416600081815260018301602052604081205462000136575081546001818101845560008481526020808220909301849055845484825282860190935260409020919091556200008b565b600060208284031215620001ac57600080fd5b81516001600160a01b03811681146200008857600080fd5b60805160a051614572620001ea60003960006108b30152600061095401526145726000f3fe60806040526004361061031e5760003560e01c8063886d36ff116101a5578063add98c70116100ec578063c63ff8dd11610095578063ccc574901161006f578063ccc5749014610aad578063d547741f14610ae1578063dcf844a714610b01578063e00a83e014610b2e57600080fd5b8063c63ff8dd146109e0578063c79371b114610a00578063ca15c87314610a8d57600080fd5b8063b250fe6b116100c6578063b250fe6b14610996578063bf333f2c146109b6578063bfc7c607146109cd57600080fd5b8063add98c7014610922578063affed0e014610942578063b13aa2d61461097657600080fd5b80639c9545f01161014e578063a5bbe22b11610128578063a5bbe22b146106ca578063aa9641ab146108d5578063ac11fb1a146108f557600080fd5b80639c9545f014610879578063a217fddf1461088c578063a3ec191a146108a157600080fd5b806391ad50391161017f57806391ad50391461077b57806391d1485414610801578063926d7d7f1461084557600080fd5b8063886d36ff146107285780638f0d6f17146107485780639010d07c1461075b57600080fd5b8063385c1d2f116102695780635960ccf21161021257806363787e52116101ec57806363787e5214610650578063820688d5146106ca5780638379a24f146106e057600080fd5b80635960ccf2146105cf5780635aa6ccba146106035780635eb7d9461461063057600080fd5b80634585169411610243578063458516941461059057806354eff068146105a357806358f85880146105b957600080fd5b8063385c1d2f146105235780633f61331d1461055057806341fcb6121461057057600080fd5b806318e4357d116102cb578063295710ff116102a5578063295710ff146104b65780632f2ff15d146104e357806336568abe1461050357600080fd5b806318e4357d1461044f578063190da5951461046f578063248a9ca31461048657600080fd5b806306f333f2116102fc57806306f333f2146103d75780630f5f6ed7146103f95780630f862f1e1461040f57600080fd5b806301ffc9a71461032357806303ed0ee514610358578063051287bc1461039a575b600080fd5b34801561032f57600080fd5b5061034361033e36600461351e565b610b44565b60405190151581526020015b60405180910390f35b34801561036457600080fd5b5061038c7f043c983c49d46f0e102151eaf8085d4a2e6571d5df2d47b013f39bddfd4a639d81565b60405190815260200161034f565b3480156103a657600080fd5b506103ca6103b5366004613560565b60009081526005602052604090205460ff1690565b60405161034f91906135e3565b3480156103e357600080fd5b506103f76103f2366004613616565b610ba0565b005b34801561040557600080fd5b5061038c61271081565b34801561041b57600080fd5b5061043773eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee81565b6040516001600160a01b03909116815260200161034f565b34801561045b57600080fd5b506103f761046a36600461364f565b610c67565b34801561047b57600080fd5b5061038c62093a8081565b34801561049257600080fd5b5061038c6104a1366004613560565b60009081526020819052604090206001015490565b3480156104c257600080fd5b5061038c6104d1366004613688565b60076020526000908152604090205481565b3480156104ef57600080fd5b506103f76104fe3660046136a5565b610d7c565b34801561050f57600080fd5b506103f761051e3660046136a5565b610da7565b34801561052f57600080fd5b5061054361053e3660046136e3565b610df3565b60405161034f91906137ae565b34801561055c57600080fd5b506103f761056b3660046136e3565b610f81565b34801561057c57600080fd5b506103f761058b36600461388d565b61102b565b6103f761059e366004613a8e565b61129d565b3480156105af57600080fd5b5061038c61ffff81565b3480156105c557600080fd5b5061038c60025481565b3480156105db57600080fd5b5061038c7fdb9556138406326f00296e13ea2ad7db24ba82381212d816b1a40c23b466b32781565b34801561060f57600080fd5b5061062361061e366004613aab565b6112fa565b60405161034f9190613aed565b34801561063c57600080fd5b506103f761064b366004613aab565b6113c7565b34801561065c57600080fd5b506106ba61066b366004613560565b60056020526000908152604090205460ff811690610100810463ffffffff169065010000000000810466ffffffffffffff16906c0100000000000000000000000090046001600160a01b031684565b60405161034f9493929190613c0a565b3480156106d657600080fd5b5061038c61070881565b3480156106ec57600080fd5b506103436106fb366004613560565b6000908152600660205260409020546c0100000000000000000000000090046001600160a01b0316151590565b34801561073457600080fd5b506103f7610743366004613c4b565b6115c9565b6103f7610756366004613aab565b6115f5565b34801561076757600080fd5b50610437610776366004613c97565b611604565b34801561078757600080fd5b506107d5610796366004613560565b60009081526005602052604090205465010000000000810466ffffffffffffff16916c010000000000000000000000009091046001600160a01b031690565b604080516bffffffffffffffffffffffff90931683526001600160a01b0390911660208301520161034f565b34801561080d57600080fd5b5061034361081c3660046136a5565b6000918252602082815260408084206001600160a01b0393909316845291905290205460ff1690565b34801561085157600080fd5b5061038c7fe2b7fb3b832174769106daebcfd6d1970523240dda11281102db9363b83b0dc481565b6103f761088736600461388d565b61161c565b34801561089857600080fd5b5061038c600081565b3480156108ad57600080fd5b5061038c7f000000000000000000000000000000000000000000000000000000000000000081565b3480156108e157600080fd5b506103436108f03660046136a5565b6118d6565b34801561090157600080fd5b50610915610910366004613aab565b6119ad565b60405161034f9190613cb9565b34801561092e57600080fd5b506103f761093d366004613560565b611b61565b34801561094e57600080fd5b5061038c7f000000000000000000000000000000000000000000000000000000000000000081565b34801561098257600080fd5b506103f7610991366004613560565b611cab565b3480156109a257600080fd5b506103f76109b1366004613560565b611d8d565b3480156109c257600080fd5b5061038c620f424081565b6103f76109db366004613e1d565b611df5565b3480156109ec57600080fd5b506103f76109fb366004613aab565b612084565b348015610a0c57600080fd5b50610a5f610a1b366004613560565b60066020526000908152604090205465ffffffffffff8082169166010000000000008104909116906c0100000000000000000000000090046001600160a01b031683565b6040805165ffffffffffff94851681529390921660208401526001600160a01b03169082015260600161034f565b348015610a9957600080fd5b5061038c610aa8366004613560565b612090565b348015610ab957600080fd5b5061038c7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f5581565b348015610aed57600080fd5b506103f7610afc3660046136a5565b6120a7565b348015610b0d57600080fd5b5061038c610b1c366004613688565b60036020526000908152604090205481565b348015610b3a57600080fd5b5061038c60045481565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f5a05180f000000000000000000000000000000000000000000000000000000001480610b9a5750610b9a826120cc565b92915050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f55610bca81612163565b6001600160a01b03831660009081526003602052604081205490819003610bf15750505050565b6001600160a01b038416600081815260036020526040812055610c1590848361216d565b604080516001600160a01b038087168252851660208201529081018290527f244e51bc38c1452fa8aaf487bcb4bca36c2baa3a5fbdb776b1eabd8dc6d277cd9060600160405180910390a1505b505050565b7fe2b7fb3b832174769106daebcfd6d1970523240dda11281102db9363b83b0dc4610c9181612163565b60008481526005602052604090206001815460ff166004811115610cb757610cb7613579565b14610cee576040517f4145817200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80546001600160a01b0384166c0100000000000000000000000081026bffffffffffffffffffffffff66ffffffffffffff421665010000000000021664ffffffff009093169290921791909117600217825560405185815286907f4ac8af8a2cd87193d64dfc7a3b8d9923b714ec528b18725d080aa1299be0c5e49060200160405180910390a35050505050565b600082815260208190526040902060010154610d9781612163565b610da18383612290565b50505050565b6001600160a01b0381163314610de9576040517f6697b23200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610c6282826122bd565b60608267ffffffffffffffff811115610e0e57610e0e6138d9565b604051908082528060200260200182016040528015610e5457816020015b604080518082019091526000815260606020820152815260200190600190039081610e2c5790505b50905060005b83811015610f795730858583818110610e7557610e75613eeb565b9050602002810190610e879190613f1a565b604051610e95929190613f7f565b600060405180830381855af49150503d8060008114610ed0576040519150601f19603f3d011682016040523d82523d6000602084013e610ed5565b606091505b50838381518110610ee857610ee8613eeb565b6020026020010151600001848481518110610f0557610f05613eeb565b602002602001015160200182905282151515158152505050818181518110610f2f57610f2f613eeb565b602002602001015160000151158015610f46575082155b15610f7157610f71828281518110610f6057610f60613eeb565b6020026020010151602001516122ea565b600101610e5a565b509392505050565b60005b82811015610da15760008030868685818110610fa257610fa2613eeb565b9050602002810190610fb49190613f1a565b604051610fc2929190613f7f565b600060405180830381855af49150503d8060008114610ffd576040519150601f19603f3d011682016040523d82523d6000602084013e611002565b606091505b509150915081158015611013575083155b1561102157611021816122ea565b5050600101610f84565b611035838361232c565b60008383604051611047929190613f7f565b604080519182900390912060008181526005602052919091208054919250906c0100000000000000000000000081046001600160a01b03169060ff81169065010000000000900466ffffffffffffff1660028260048111156110ab576110ab613579565b146110e2576040517f4145817200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6107084282900366ffffffffffffff1611611129576040517f1992d0bd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600160a01b03861661113f57829550611181565b6001600160a01b0383163314611181576040517f4af43a9000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b83547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166003178455603288013560601c605a890135609a8a013580156111f0576001600160a01b038316600090815260036020526040812080548392906111ea908490613fbe565b90915550505b604080516001600160a01b03858116825260208201859052808c1692908916918b917f582211c35a2139ac3bbaac74663c6a1f56c6cbb658b41fe11fd45a82074ac678910160405180910390a47fffffffffffffffffffffffff11111111111111111111111111111111111111126001600160a01b0384160161127c5761127789836123ad565b611290565b6112906001600160a01b0384168a84612476565b5050505050505050505050565b6112f7816040518060a0016040528060006001600160a01b03168152602001600081526020016040518060200160405280600081525081526020016000815260200160405180602001604052806000815250815250611df5565b50565b6113ac604051806101e00160405280600063ffffffff168152602001600063ffffffff16815260200160006001600160a01b0316815260200160006001600160a01b0316815260200160006001600160a01b0316815260200160006001600160a01b03168152602001600081526020016000815260200160008152602001600081526020016000815260200160006001600160a01b031681526020016000815260200160008152602001606081525090565b6113b6838361232c565b6113c083836124ea565b9392505050565b6113d1828261232c565b600082826040516113e3929190613f7f565b604080519182900390912060008181526005602052919091209091506001815460ff16600481111561141757611417613579565b1461144e576040517f4145817200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b3360009081527fd2043bf65931af3dbecf60d0db8f40e4160406d7beb00522f4200cf4944a1eb8602052604090205460ba8501359060ff1661149a5761149762093a8082613fbe565b90505b8042116114d3576040517fe15ff9ea00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b81547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166004178255600a850135606090811c906032870135901c6000611522609a890135605a8a0135613fbe565b604080516001600160a01b03858116825260208201849052825193945086169289927fb4c55c0c9bc613519b920e88748090150b890a875d307f21bea7d4fb2e8bc958928290030190a37fffffffffffffffffffffffff11111111111111111111111111111111111111126001600160a01b038316016115ab576115a683826123ad565b6115bf565b6115bf6001600160a01b0383168483612476565b5050505050505050565b6115d3838361232c565b610c6283836040516115e6929190613f7f565b60405180910390208233610c67565b61160082823361161c565b5050565b60008281526001602052604081206113c0908361268c565b611626838361232c565b60008383604051611638929190613f7f565b6040518091039020905061164e84848385612698565b6040805160608101825265ffffffffffff438116825242811660208084019182526001600160a01b038088168587019081526000888152600690935295822094518554935196519091166c01000000000000000000000000026bffffffffffffffffffffffff9685166601000000000000027fffffffffffffffffffffffffffffffffffffffff0000000000000000000000009094169190941617919091179390931617905561170285601e013560601c90565b9050604685013560601c607a86013561012e8701356001600160a01b03808516908716867ff8ae392d784b1ea5e8881bfa586d81abf07ef4f1e2fc75f7fe51c90f05199a5c60028c013560e01c6040805163ffffffff92909216825260328e0135606090811c60208401526001600160a01b038a1683830152605a8f0135908301526080820188905260a08201879052519081900360c00190a47fffffffffffffffffffffffff11111111111111111111111111111111111111126001600160a01b03841601611842578015611804576040517f846dedc000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b81341461183d576040517f81de0bf300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611890565b80341461187b576040517f81de0bf300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6118906001600160a01b03841633868561282d565b36600061189d8a8a612866565b909250905080156118ba576118b58686868585612882565b6118ca565b34156118ca576118ca86346123ad565b50505050505050505050565b60008281526005602052604081206002815460ff1660048111156118fc576118fc613579565b14611933576040517f4145817200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80546001600160a01b038481166c010000000000000000000000009092041614611989576040517f4af43a9000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b546107086501000000000090910466ffffffffffffff908116420316119392505050565b6040805161018081018252600080825260208201819052818301819052606082018190526080820181905260a0820181905260c0820181905260e0820181905261010082018190526101208201819052610140820181905261016082015290517f5aa6ccba0000000000000000000000000000000000000000000000000000000081523090635aa6ccba90611a489086908690600401613ffc565b600060405180830381865afa925050508015611a8657506040513d6000823e601f3d908101601f19168201604052611a83919081019061406b565b60015b611a9d57611a96828401846141a0565b9050610b9a565b604051806101800160405280826000015163ffffffff168152602001826020015163ffffffff16815260200182604001516001600160a01b0316815260200182606001516001600160a01b0316815260200182608001516001600160a01b031681526020018260a001516001600160a01b031681526020018260c0015181526020018260e0015181526020018261010001518152602001826101a0015160001415151581526020018261012001518152602001826101400151815250915050610b9a565b7f043c983c49d46f0e102151eaf8085d4a2e6571d5df2d47b013f39bddfd4a639d611b8b81612163565b600082815260056020526040902080546c0100000000000000000000000081046001600160a01b03169060ff81169065010000000000900466ffffffffffffff166002826004811115611be057611be0613579565b14611c17576040517f4145817200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6107084282900366ffffffffffffff161115611c5f576040517f3e908aac00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b835464ffffffff001660011784556040516001600160a01b0384169087907f0695cf1d39b3055dcd0fe02d8b47eaf0d5a13e1996de925de59d0ef9b7f7fad490600090a3505050505050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f55611cd581612163565b612710821115611d46576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f6e657746656552617465203e206d61780000000000000000000000000000000060448201526064015b60405180910390fd5b600280549083905560408051828152602081018590527f14914da2bf76024616fbe1859783fcd4dbddcb179b1f3a854949fbf920dcb95791015b60405180910390a1505050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f55611db781612163565b600480549083905560408051828152602081018590527f5cf09b12f3f56b4c564d51b25b40360af6d795198adb61ae0806a36c294323fa9101611d80565b80516000906001600160a01b031615611e1a576020820151611e17904261426c565b90505b611e258383836129de565b6000611e3984606001518560a00151612c62565b90506000806002541115611e7257620f424060025483611e599190614294565b611e6391906142ab565b9050611e6f81836142e6565b91505b6000611f7b604051806101e001604052804663ffffffff168152602001886000015163ffffffff16815260200188602001516001600160a01b0316815260200188604001516001600160a01b0316815260200188606001516001600160a01b0316815260200188608001516001600160a01b031681526020018581526020018860c0015181526020018481526020018861010001518152602001600760008a602001516001600160a01b03166001600160a01b031681526020019081526020016000206000815480929190611f46906142f9565b90915550815287516001600160a01b031660208201526040810187905260608089015190820152608080890151910152612e75565b805160208083019190912060008181526005835260409081902080548b5163ffffffff8116610100027fffffffffffffffffffffffffffffffffffffffffffffffffffffff000000000090921691909117600117909155928a01516060808c015160808d015160c08e0151928d0151945197985094966001600160a01b039093169587957f120ea0364f36cdac7983bcfdd55270ca09d7f9b314a2ebc425a3b01ab1d6403a95612037958b959394938e92909190151590614331565b60405180910390a3807f3120e2bb59c86aca6890191a589a96af3662838efa374fbdcdf4c95bfe4a6c0e87604001516040516120739190614387565b60405180910390a250505050505050565b6116008282600061102b565b6000818152600160205260408120610b9a90612fba565b6000828152602081905260409020600101546120c281612163565b610da183836122bd565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f7965db0b000000000000000000000000000000000000000000000000000000001480610b9a57507f01ffc9a7000000000000000000000000000000000000000000000000000000007fffffffff00000000000000000000000000000000000000000000000000000000831614610b9a565b6112f78133612fc4565b306001600160a01b0383160361218257505050565b8060000361218f57505050565b7fffffffffffffffffffffffff11111111111111111111111111111111111111126001600160a01b0384160161227c576000826001600160a01b03168260405160006040518083038185875af1925050503d806000811461220c576040519150601f19603f3d011682016040523d82523d6000602084013e612211565b606091505b5050905080610da1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f455448207472616e73666572206661696c6564000000000000000000000000006044820152606401611d3d565b610c626001600160a01b0384168383612476565b60008061229d8484613030565b905080156113c0576000848152600160205260409020610f7990846130f8565b6000806122ca848461310d565b905080156113c0576000848152600160205260409020610f7990846131ae565b8051156122fa5780518082602001fd5b6040517f5ead5a9d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61014e811015612368576040517f6ee0e17100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b813560f01c60028114610c62576040517f8bd977e700000000000000000000000000000000000000000000000000000000815261ffff82166004820152602401611d3d565b804710156123e9576040517fcd786059000000000000000000000000000000000000000000000000000000008152306004820152602401611d3d565b6000826001600160a01b03168260405160006040518083038185875af1925050503d8060008114612436576040519150601f19603f3d011682016040523d82523d6000602084013e61243b565b606091505b5050905080610c62576040517f1425ea4200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040516001600160a01b03838116602483015260448201839052610c6291859182169063a9059cbb906064015b604051602081830303815290604052915060e01b6020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff83818316178352505050506131c3565b61259c604051806101e00160405280600063ffffffff168152602001600063ffffffff16815260200160006001600160a01b0316815260200160006001600160a01b0316815260200160006001600160a01b0316815260200160006001600160a01b03168152602001600081526020016000815260200160008152602001600081526020016000815260200160006001600160a01b031681526020016000815260200160008152602001606081525090565b600283013560e090811c82526006840135811c6020830152600a840135606090811c6040840152601e850135811c818401526032850135811c60808401526046850135811c60a0840152605a85013560c0840152607a85013591830191909152609a84013561010083015260ba84013561012083015260da84013561014083015260fa840135901c61016082015261010e83013561018082015261012e8301356101a082015261264c8383612866565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152505050506101c082015292915050565b60006113c0838361323f565b6001600160a01b0381166126d8576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000828152600660205260409020546c0100000000000000000000000090046001600160a01b031615612737576040517fbef7bb7d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600684013560e01c4614612777576040517f7029fdf900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60ba8401354211156127b5576040517f559895a300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60fa84013560601c80158015906127de5750816001600160a01b0316816001600160a01b031614155b80156127ef575061010e8501354211155b15612826576040517f14be123200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5050505050565b6040516001600160a01b038481166024830152838116604483015260648201839052610da19186918216906323b872dd906084016124a3565b3660006128778361014e818761439a565b915091509250929050565b60006128fd868686868660405160240161289f94939291906143c4565b60408051601f198184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fe85e13dd0000000000000000000000000000000000000000000000000000000017905234613269565b9050805160000361293a576040517f1a95ad2600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8051602014612975576040517ff3725cca00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7fe85e13dd0000000000000000000000000000000000000000000000000000000061299f826143ed565b146129d6576040517ff3725cca00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b505050505050565b46836000015163ffffffff1603612a21576040517f7029fdf900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60a08301511580612a34575060c0830151155b15612a6b576040517fe38820c800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60208301516001600160a01b03161580612a90575060408301516001600160a01b0316155b15612ac7576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60608301516001600160a01b03161580612aec575060808301516001600160a01b0316155b15612b23576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b612b2f61070842613fbe565b8361010001511015612b6d576040517f04b7fcc800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61ffff8260800151511115612bae576040517f177a70e100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b606082015115801590612be1575060808301516001600160a01b031673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee145b15612c18576040517f846dedc000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000811280612c2b575082610100015181135b15610c62576040517f352807b900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60007fffffffffffffffffffffffff11111111111111111111111111111111111111126001600160a01b03841601612cd457348214612ccd576040517f81de0bf300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5034610b9a565b3415612d0c576040517f81de0bf300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b826001600160a01b03163b600003612d50576040517f7f523fe800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201526001600160a01b038416906370a0823190602401602060405180830381865afa158015612dad573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612dd19190614432565b9050612de86001600160a01b03841633308561282d565b6040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015281906001600160a01b038516906370a0823190602401602060405180830381865afa158015612e47573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612e6b9190614432565b6113c091906142e6565b8051602080830151604080850151606086810151608088015160a089015160c08a015195517e02000000000000000000000000000000000000000000000000000000000000988101989098527fffffffff0000000000000000000000000000000000000000000000000000000060e0998a1b811660228a01529690981b90951660268701527fffffffffffffffffffffffffffffffffffffffff00000000000000000000000092821b8316602a870152811b8216603e86015292831b8116605285015293821b9093166066830152607a820192909252600090609a0160408051601f198184030181529082905260e08501516101008601516101208701516101408801516101608901516101808a01516101a08b01516101c08c0151979950612fa3988a989060200161444b565b604051602081830303815290604052915050919050565b6000610b9a825490565b6000828152602081815260408083206001600160a01b038516845290915290205460ff16611600576040517fe2517d3f0000000000000000000000000000000000000000000000000000000081526001600160a01b038216600482015260248101839052604401611d3d565b6000828152602081815260408083206001600160a01b038516845290915281205460ff166130f0576000838152602081815260408083206001600160a01b0386168452909152902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790556130a83390565b6001600160a01b0316826001600160a01b0316847f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a4506001610b9a565b506000610b9a565b60006113c0836001600160a01b03841661331f565b6000828152602081815260408083206001600160a01b038516845290915281205460ff16156130f0576000838152602081815260408083206001600160a01b038616808552925280832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016905551339286917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a4506001610b9a565b60006113c0836001600160a01b038416613366565b60006131d86001600160a01b03841683613459565b905080516000141580156131fd5750808060200190518101906131fb91906144d4565b155b15610c62576040517f5274afe70000000000000000000000000000000000000000000000000000000081526001600160a01b0384166004820152602401611d3d565b600082600001828154811061325657613256613eeb565b9060005260206000200154905092915050565b6060814710156132a7576040517fcd786059000000000000000000000000000000000000000000000000000000008152306004820152602401611d3d565b600080856001600160a01b031684866040516132c391906144f1565b60006040518083038185875af1925050503d8060008114613300576040519150601f19603f3d011682016040523d82523d6000602084013e613305565b606091505b5091509150613315868383613467565b9695505050505050565b60008181526001830160205260408120546130f057508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155610b9a565b6000818152600183016020526040812054801561344f57600061338a6001836142e6565b855490915060009061339e906001906142e6565b90508082146134035760008660000182815481106133be576133be613eeb565b90600052602060002001549050808760000184815481106133e1576133e1613eeb565b6000918252602080832090910192909255918252600188019052604090208390555b85548690806134145761341461450d565b600190038181906000526020600020016000905590558560010160008681526020019081526020016000206000905560019350505050610b9a565b6000915050610b9a565b60606113c083836000613269565b60608261347c57613477826134dc565b6113c0565b815115801561349357506001600160a01b0384163b155b156134d5576040517f9996b3150000000000000000000000000000000000000000000000000000000081526001600160a01b0385166004820152602401611d3d565b50806113c0565b8051156134ec5780518082602001fd5b6040517f1425ea4200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006020828403121561353057600080fd5b81357fffffffff00000000000000000000000000000000000000000000000000000000811681146113c057600080fd5b60006020828403121561357257600080fd5b5035919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b600581106135df577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b9052565b60208101610b9a82846135a8565b6001600160a01b03811681146112f757600080fd5b8035613611816135f1565b919050565b6000806040838503121561362957600080fd5b8235613634816135f1565b91506020830135613644816135f1565b809150509250929050565b60008060006060848603121561366457600080fd5b8335925060208401359150604084013561367d816135f1565b809150509250925092565b60006020828403121561369a57600080fd5b81356113c0816135f1565b600080604083850312156136b857600080fd5b823591506020830135613644816135f1565b80151581146112f757600080fd5b8035613611816136ca565b6000806000604084860312156136f857600080fd5b833567ffffffffffffffff8082111561371057600080fd5b818601915086601f83011261372457600080fd5b81358181111561373357600080fd5b8760208260051b850101111561374857600080fd5b6020928301955093505084013561367d816136ca565b60005b83811015613779578181015183820152602001613761565b50506000910152565b6000815180845261379a81602086016020860161375e565b601f01601f19169290920160200192915050565b600060208083018184528085518083526040925060408601915060408160051b87010184880160005b83811015613836578883037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc0018552815180511515845287015187840187905261382387850182613782565b95880195935050908601906001016137d7565b509098975050505050505050565b60008083601f84011261385657600080fd5b50813567ffffffffffffffff81111561386e57600080fd5b60208301915083602082850101111561388657600080fd5b9250929050565b6000806000604084860312156138a257600080fd5b833567ffffffffffffffff8111156138b957600080fd5b6138c586828701613844565b909450925050602084013561367d816135f1565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051610120810167ffffffffffffffff8111828210171561392c5761392c6138d9565b60405290565b60405160a0810167ffffffffffffffff8111828210171561392c5761392c6138d9565b6040516101e0810167ffffffffffffffff8111828210171561392c5761392c6138d9565b604051610180810167ffffffffffffffff8111828210171561392c5761392c6138d9565b604051601f8201601f1916810167ffffffffffffffff811182821017156139c6576139c66138d9565b604052919050565b63ffffffff811681146112f757600080fd5b8035613611816139ce565b600061012082840312156139fe57600080fd5b613a06613908565b9050613a11826139e0565b8152613a1f60208301613606565b6020820152613a3060408301613606565b6040820152613a4160608301613606565b6060820152613a5260808301613606565b608082015260a082013560a082015260c082013560c0820152613a7760e083016136d8565b60e082015261010080830135818301525092915050565b60006101208284031215613aa157600080fd5b6113c083836139eb565b60008060208385031215613abe57600080fd5b823567ffffffffffffffff811115613ad557600080fd5b613ae185828601613844565b90969095509350505050565b60208152613b0460208201835163ffffffff169052565b60006020830151613b1d604084018263ffffffff169052565b5060408301516001600160a01b03811660608401525060608301516001600160a01b03811660808401525060808301516001600160a01b03811660a08401525060a08301516001600160a01b03811660c08401525060c083015160e08381019190915283015161010080840191909152830151610120808401919091528301516101408084019190915283015161016080840191909152830151610180613bce818501836001600160a01b03169052565b8401516101a0848101919091528401516101c0808501919091528401516101e0808501529050613c02610200840182613782565b949350505050565b60808101613c1882876135a8565b63ffffffff8516602083015266ffffffffffffff841660408301526001600160a01b038316606083015295945050505050565b600080600060408486031215613c6057600080fd5b833567ffffffffffffffff811115613c7757600080fd5b613c8386828701613844565b909790965060209590950135949350505050565b60008060408385031215613caa57600080fd5b50508035926020909101359150565b815163ffffffff16815261018081016020830151613cdf602084018263ffffffff169052565b506040830151613cfa60408401826001600160a01b03169052565b506060830151613d1560608401826001600160a01b03169052565b506080830151613d3060808401826001600160a01b03169052565b5060a0830151613d4b60a08401826001600160a01b03169052565b5060c083015160c083015260e083015160e083015261010080840151818401525061012080840151613d808285018215159052565b5050610140838101519083015261016092830151929091019190915290565b600067ffffffffffffffff821115613db957613db96138d9565b50601f01601f191660200190565b600082601f830112613dd857600080fd5b8135613deb613de682613d9f565b61399d565b818152846020838601011115613e0057600080fd5b816020850160208301376000918101602001919091529392505050565b6000806101408385031215613e3157600080fd5b613e3b84846139eb565b915061012083013567ffffffffffffffff80821115613e5957600080fd5b9084019060a08287031215613e6d57600080fd5b613e75613932565b8235613e80816135f1565b815260208381013590820152604083013582811115613e9e57600080fd5b613eaa88828601613dc7565b60408301525060608301356060820152608083013582811115613ecc57600080fd5b613ed888828601613dc7565b6080830152508093505050509250929050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112613f4f57600080fd5b83018035915067ffffffffffffffff821115613f6a57600080fd5b60200191503681900382131561388657600080fd5b8183823760009101908152919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b80820180821115610b9a57610b9a613f8f565b818352818160208501375060006020828401015260006020601f19601f840116840101905092915050565b602081526000613c02602083018486613fd1565b8051613611816139ce565b8051613611816135f1565b600082601f83011261403757600080fd5b8151614045613de682613d9f565b81815284602083860101111561405a57600080fd5b613c0282602083016020870161375e565b60006020828403121561407d57600080fd5b815167ffffffffffffffff8082111561409557600080fd5b908301906101e082860312156140aa57600080fd5b6140b2613955565b6140bb83614010565b81526140c960208401614010565b60208201526140da6040840161401b565b60408201526140eb6060840161401b565b60608201526140fc6080840161401b565b608082015261410d60a0840161401b565b60a082015260c0838101519082015260e0808401519082015261010080840151908201526101208084015190820152610140808401519082015261016061415581850161401b565b9082015261018083810151908201526101a080840151908201526101c0808401518381111561418357600080fd5b61418f88828701614026565b918301919091525095945050505050565b600061018082840312156141b357600080fd5b6141bb613979565b6141c4836139e0565b81526141d2602084016139e0565b60208201526141e360408401613606565b60408201526141f460608401613606565b606082015261420560808401613606565b608082015261421660a08401613606565b60a082015260c083013560c082015260e083013560e08201526101008084013581830152506101206142498185016136d8565b908201526101408381013590820152610160928301359281019290925250919050565b808201828112600083128015821682158216171561428c5761428c613f8f565b505092915050565b8082028115828204841417610b9a57610b9a613f8f565b6000826142e1577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b81810381811115610b9a57610b9a613f8f565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820361432a5761432a613f8f565b5060010190565b60e08152600061434460e083018a613782565b63ffffffff989098166020830152506001600160a01b039586166040820152939094166060840152608083019190915260a082015290151560c090910152919050565b6020815260006113c06020830184613782565b600080858511156143aa57600080fd5b838611156143b757600080fd5b5050820193919092039150565b6001600160a01b0385168152836020820152606060408201526000613315606083018486613fd1565b8051602080830151919081101561442c577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8160200360031b1b821691505b50919050565b60006020828403121561444457600080fd5b5051919050565b60008a5161445d818460208f0161375e565b80830190508a81528960208201528860408201528760608201527fffffffffffffffffffffffffffffffffffffffff0000000000000000000000008760601b1660808201528560948201528460b482015283516144c18160d484016020880161375e565b0160d4019b9a5050505050505050505050565b6000602082840312156144e657600080fd5b81516113c0816136ca565b6000825161450381846020870161375e565b9190910192915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fdfea26469706673582212209a48ddc6013fa0ddcb3b8a930e8c7e75c40dab4d351f72ddd07978c3a1539f2764736f6c63430008180033", + Bin: "0x60e06040526000608081905260a0523480156200001b57600080fd5b50604051620047ee380380620047ee8339810160408190526200003e9162000215565b806200004c60008262000067565b506200005b62015180620000a4565b50504360c05262000240565b6000806200007684846200010d565b905080156200009b576000848152600160205260409020620000999084620001bb565b505b90505b92915050565b610e10811015620000c857604051630e0ea5c760e01b815260040160405180910390fd5b600480549082905560408051828152602081018490527f909f9078b2f6eac1d10f2aae793656c5a67511eb627ebd1d2cb1eb9c0ab94c95910160405180910390a15050565b6000828152602081815260408083206001600160a01b038516845290915281205460ff16620001b2576000838152602081815260408083206001600160a01b03861684529091529020805460ff19166001179055620001693390565b6001600160a01b0316826001600160a01b0316847f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45060016200009e565b5060006200009e565b60006200009b836001600160a01b0384166000818152600183016020526040812054620001b2575081546001818101845560008481526020808220909301849055845484825282860190935260409020919091556200009e565b6000602082840312156200022857600080fd5b81516001600160a01b03811681146200009b57600080fd5b60805160a05160c05161457e62000270600039600061094b015260006109ec01526000610bec015261457e6000f3fe60806040526004361061034a5760003560e01c80638379a24f116101bb578063ac11fb1a116100f7578063c79371b111610095578063d547741f1161006f578063d547741f14610b59578063dc9a4ef614610b79578063dcf844a714610bad578063e00a83e014610bda57600080fd5b8063c79371b114610a78578063ca15c87314610b05578063ccc5749014610b2557600080fd5b8063b13aa2d6116100d1578063b13aa2d614610a0e578063bf333f2c14610a2e578063bfc7c60714610a45578063c63ff8dd14610a5857600080fd5b8063ac11fb1a1461098d578063add98c70146109ba578063affed0e0146109da57600080fd5b8063922b748711610164578063a217fddf1161013e578063a217fddf14610924578063a3ec191a14610939578063a5bbe22b14610769578063aa9641ab1461096d57600080fd5b8063922b7487146108e4578063930ac180146108fa5780639c9545f01461091157600080fd5b80639010d07c116101955780639010d07c146107fa57806391ad50391461081a57806391d14854146108a057600080fd5b80638379a24f1461077f578063886d36ff146107c75780638f0d6f17146107e757600080fd5b8063385c1d2f1161028a57806358f858801161023357806363787e521161020d57806363787e52146106a5578063638a0f091461071f5780637ebe815c14610735578063820688d51461076957600080fd5b806358f85880146106425780635aa6ccba146106585780635eb7d9461461068557600080fd5b806341fcb6121161026457806341fcb612146105f9578063458516941461061957806354eff0681461062c57600080fd5b8063385c1d2f1461058c5780633c5beeb4146105b95780633f61331d146105d957600080fd5b80630f862f1e116102f7578063248a9ca3116102d1578063248a9ca3146104ef578063295710ff1461051f5780632f2ff15d1461054c57806336568abe1461056c57600080fd5b80630f862f1e1461046f57806318e4357d146104af5780631ea327c5146104cf57600080fd5b8063051287bc11610328578063051287bc146103fa57806306f333f2146104375780630f5f6ed71461045957600080fd5b806301ffc9a71461034f57806302d2ff661461038457806303ed0ee5146103c6575b600080fd5b34801561035b57600080fd5b5061036f61036a36600461352a565b610c0e565b60405190151581526020015b60405180910390f35b34801561039057600080fd5b506103b87febfdca8e46c0b8dacf9989ee613e35727eadd20a1d5e5ad01a53968c7e5fe07a81565b60405190815260200161037b565b3480156103d257600080fd5b506103b87f043c983c49d46f0e102151eaf8085d4a2e6571d5df2d47b013f39bddfd4a639d81565b34801561040657600080fd5b5061042a61041536600461356c565b60009081526005602052604090205460ff1690565b60405161037b91906135ef565b34801561044357600080fd5b50610457610452366004613622565b610c6a565b005b34801561046557600080fd5b506103b861271081565b34801561047b57600080fd5b5061049773eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee81565b6040516001600160a01b03909116815260200161037b565b3480156104bb57600080fd5b506104576104ca36600461365b565b610d77565b3480156104db57600080fd5b506104576104ea36600461356c565b610e8c565b3480156104fb57600080fd5b506103b861050a36600461356c565b60009081526020819052604090206001015490565b34801561052b57600080fd5b506103b861053a366004613694565b60076020526000908152604090205481565b34801561055857600080fd5b506104576105673660046136b1565b610ec3565b34801561057857600080fd5b506104576105873660046136b1565b610ee8565b34801561059857600080fd5b506105ac6105a73660046136ef565b610f34565b60405161037b91906137ba565b3480156105c557600080fd5b506104576105d4366004613899565b6110c2565b3480156105e557600080fd5b506104576105f43660046136ef565b6112c4565b34801561060557600080fd5b506104576106143660046138db565b61136e565b610457610627366004613adc565b6115e0565b34801561063857600080fd5b506103b861ffff81565b34801561064e57600080fd5b506103b860025481565b34801561066457600080fd5b50610678610673366004613899565b61163d565b60405161037b9190613af9565b34801561069157600080fd5b506104576106a0366004613899565b61170a565b3480156106b157600080fd5b5061070f6106c036600461356c565b60056020526000908152604090205460ff811690610100810463ffffffff169065010000000000810466ffffffffffffff16906c0100000000000000000000000090046001600160a01b031684565b60405161037b9493929190613c16565b34801561072b57600080fd5b506103b860045481565b34801561074157600080fd5b506103b87f9a04aea0a349253cc7277afafdf6ead6729a3972a47ffb40eaef2c93d4e1bfea81565b34801561077557600080fd5b506103b861070881565b34801561078b57600080fd5b5061036f61079a36600461356c565b6000908152600660205260409020546c0100000000000000000000000090046001600160a01b0316151590565b3480156107d357600080fd5b506104576107e2366004613c57565b611714565b6104576107f5366004613899565b611740565b34801561080657600080fd5b50610497610815366004613ca3565b61174b565b34801561082657600080fd5b5061087461083536600461356c565b60009081526005602052604090205465010000000000810466ffffffffffffff16916c010000000000000000000000009091046001600160a01b031690565b604080516bffffffffffffffffffffffff90931683526001600160a01b0390911660208301520161037b565b3480156108ac57600080fd5b5061036f6108bb3660046136b1565b6000918252602082815260408084206001600160a01b0393909316845291905290205460ff1690565b3480156108f057600080fd5b506103b8610e1081565b34801561090657600080fd5b506103b86201518081565b61045761091f3660046138db565b611763565b34801561093057600080fd5b506103b8600081565b34801561094557600080fd5b506103b87f000000000000000000000000000000000000000000000000000000000000000081565b34801561097957600080fd5b5061036f6109883660046136b1565b611a1d565b34801561099957600080fd5b506109ad6109a8366004613899565b611af4565b60405161037b9190613cc5565b3480156109c657600080fd5b506104576109d536600461356c565b611ca8565b3480156109e657600080fd5b506103b87f000000000000000000000000000000000000000000000000000000000000000081565b348015610a1a57600080fd5b50610457610a2936600461356c565b611df2565b348015610a3a57600080fd5b506103b8620f424081565b610457610a53366004613e29565b611e9e565b348015610a6457600080fd5b50610457610a73366004613899565b61212d565b348015610a8457600080fd5b50610ad7610a9336600461356c565b60066020526000908152604090205465ffffffffffff8082169166010000000000008104909116906c0100000000000000000000000090046001600160a01b031683565b6040805165ffffffffffff94851681529390921660208401526001600160a01b03169082015260600161037b565b348015610b1157600080fd5b506103b8610b2036600461356c565b612139565b348015610b3157600080fd5b506103b87f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f5581565b348015610b6557600080fd5b50610457610b743660046136b1565b612150565b348015610b8557600080fd5b506103b87f60044782a422109ac08a415e44260ad5d3bad63d96ebe1fac0363399642ee3f281565b348015610bb957600080fd5b506103b8610bc8366004613694565b60036020526000908152604090205481565b348015610be657600080fd5b506103b87f000000000000000000000000000000000000000000000000000000000000000081565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f5a05180f000000000000000000000000000000000000000000000000000000001480610c645750610c6482612175565b92915050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f55610c948161220c565b6001600160a01b03831660009081526003602052604081205490819003610cbb5750505050565b6001600160a01b038481166000818152600360209081526040808320929092558151928352928616928201929092529081018290527f244e51bc38c1452fa8aaf487bcb4bca36c2baa3a5fbdb776b1eabd8dc6d277cd9060600160405180910390a17fffffffffffffffffffffffff11111111111111111111111111111111111111126001600160a01b03851601610d5c57610d578382612216565b610d70565b610d706001600160a01b03851684836122e4565b505b505050565b7f60044782a422109ac08a415e44260ad5d3bad63d96ebe1fac0363399642ee3f2610da18161220c565b60008481526005602052604090206001815460ff166004811115610dc757610dc7613585565b14610dfe576040517f4145817200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80546001600160a01b0384166c0100000000000000000000000081026bffffffffffffffffffffffff66ffffffffffffff421665010000000000021664ffffffff009093169290921791909117600217825560405185815286907f4ac8af8a2cd87193d64dfc7a3b8d9923b714ec528b18725d080aa1299be0c5e49060200160405180910390a35050505050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f55610eb68161220c565b610ebf82612358565b5050565b600082815260208190526040902060010154610ede8161220c565b610d7083836123d9565b6001600160a01b0381163314610f2a576040517f6697b23200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610d728282612406565b60608267ffffffffffffffff811115610f4f57610f4f613927565b604051908082528060200260200182016040528015610f9557816020015b604080518082019091526000815260606020820152815260200190600190039081610f6d5790505b50905060005b838110156110ba5730858583818110610fb657610fb6613ef7565b9050602002810190610fc89190613f26565b604051610fd6929190613f8b565b600060405180830381855af49150503d8060008114611011576040519150601f19603f3d011682016040523d82523d6000602084013e611016565b606091505b5083838151811061102957611029613ef7565b602002602001015160000184848151811061104657611046613ef7565b60200260200101516020018290528215151515815250505081818151811061107057611070613ef7565b602002602001015160000151158015611087575082155b156110b2576110b28282815181106110a1576110a1613ef7565b602002602001015160200151612433565b600101610f9b565b509392505050565b6110cc8282612475565b600082826040516110de929190613f8b565b604080519182900390912060008181526005602052919091209091506001815460ff16600481111561111257611112613585565b14611149576040517f4145817200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b3360009081527f4527d8b28c468984933d33ae052f26b21c15ca0e7fdec762bba08e540e237001602052604090205460ba8501359060ff16611195576004546111929082613fca565b90505b8042116111ce576040517fe15ff9ea00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b81547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166004178255600a850135606090811c906032870135901c600061121d609a890135605a8a0135613fca565b604080516001600160a01b03858116825260208201849052825193945086169289927fb4c55c0c9bc613519b920e88748090150b890a875d307f21bea7d4fb2e8bc958928290030190a37fffffffffffffffffffffffff11111111111111111111111111111111111111126001600160a01b038316016112a6576112a18382612216565b6112ba565b6112ba6001600160a01b03831684836122e4565b5050505050505050565b60005b82811015610d7057600080308686858181106112e5576112e5613ef7565b90506020028101906112f79190613f26565b604051611305929190613f8b565b600060405180830381855af49150503d8060008114611340576040519150601f19603f3d011682016040523d82523d6000602084013e611345565b606091505b509150915081158015611356575083155b156113645761136481612433565b50506001016112c7565b6113788383612475565b6000838360405161138a929190613f8b565b604080519182900390912060008181526005602052919091208054919250906c0100000000000000000000000081046001600160a01b03169060ff81169065010000000000900466ffffffffffffff1660028260048111156113ee576113ee613585565b14611425576040517f4145817200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6107084282900366ffffffffffffff161161146c576040517f1992d0bd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600160a01b038616611482578295506114c4565b6001600160a01b03831633146114c4576040517f4af43a9000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b83547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166003178455603288013560601c605a890135609a8a01358015611533576001600160a01b0383166000908152600360205260408120805483929061152d908490613fca565b90915550505b604080516001600160a01b03858116825260208201859052808c1692908916918b917f582211c35a2139ac3bbaac74663c6a1f56c6cbb658b41fe11fd45a82074ac678910160405180910390a47fffffffffffffffffffffffff11111111111111111111111111111111111111126001600160a01b038416016115bf576115ba8983612216565b6115d3565b6115d36001600160a01b0384168a846122e4565b5050505050505050505050565b61163a816040518060a0016040528060006001600160a01b03168152602001600081526020016040518060200160405280600081525081526020016000815260200160405180602001604052806000815250815250611e9e565b50565b6116ef604051806101e00160405280600063ffffffff168152602001600063ffffffff16815260200160006001600160a01b0316815260200160006001600160a01b0316815260200160006001600160a01b0316815260200160006001600160a01b03168152602001600081526020016000815260200160008152602001600081526020016000815260200160006001600160a01b031681526020016000815260200160008152602001606081525090565b6116f98383612475565b61170383836124f6565b9392505050565b610ebf82826110c2565b61171e8383612475565b610d728383604051611731929190613f8b565b60405180910390208233610d77565b610ebf828233611763565b60008281526001602052604081206117039083612698565b61176d8383612475565b6000838360405161177f929190613f8b565b60405180910390209050611795848483856126a4565b6040805160608101825265ffffffffffff438116825242811660208084019182526001600160a01b038088168587019081526000888152600690935295822094518554935196519091166c01000000000000000000000000026bffffffffffffffffffffffff9685166601000000000000027fffffffffffffffffffffffffffffffffffffffff0000000000000000000000009094169190941617919091179390931617905561184985601e013560601c90565b9050604685013560601c607a86013561012e8701356001600160a01b03808516908716867ff8ae392d784b1ea5e8881bfa586d81abf07ef4f1e2fc75f7fe51c90f05199a5c60028c013560e01c6040805163ffffffff92909216825260328e0135606090811c60208401526001600160a01b038a1683830152605a8f0135908301526080820188905260a08201879052519081900360c00190a47fffffffffffffffffffffffff11111111111111111111111111111111111111126001600160a01b0384160161198957801561194b576040517f846dedc000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b813414611984576040517f81de0bf300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6119d7565b8034146119c2576040517f81de0bf300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6119d76001600160a01b038416338685612839565b3660006119e48a8a612872565b90925090508015611a01576119fc868686858561288e565b611a11565b3415611a1157611a118634612216565b50505050505050505050565b60008281526005602052604081206002815460ff166004811115611a4357611a43613585565b14611a7a576040517f4145817200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80546001600160a01b038481166c010000000000000000000000009092041614611ad0576040517f4af43a9000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b546107086501000000000090910466ffffffffffffff908116420316119392505050565b6040805161018081018252600080825260208201819052818301819052606082018190526080820181905260a0820181905260c0820181905260e0820181905261010082018190526101208201819052610140820181905261016082015290517f5aa6ccba0000000000000000000000000000000000000000000000000000000081523090635aa6ccba90611b8f9086908690600401614008565b600060405180830381865afa925050508015611bcd57506040513d6000823e601f3d908101601f19168201604052611bca9190810190614077565b60015b611be457611bdd828401846141ac565b9050610c64565b604051806101800160405280826000015163ffffffff168152602001826020015163ffffffff16815260200182604001516001600160a01b0316815260200182606001516001600160a01b0316815260200182608001516001600160a01b031681526020018260a001516001600160a01b031681526020018260c0015181526020018260e0015181526020018261010001518152602001826101a0015160001415151581526020018261012001518152602001826101400151815250915050610c64565b7f043c983c49d46f0e102151eaf8085d4a2e6571d5df2d47b013f39bddfd4a639d611cd28161220c565b600082815260056020526040902080546c0100000000000000000000000081046001600160a01b03169060ff81169065010000000000900466ffffffffffffff166002826004811115611d2757611d27613585565b14611d5e576040517f4145817200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6107084282900366ffffffffffffff161115611da6576040517f3e908aac00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b835464ffffffff001660011784556040516001600160a01b0384169087907f0695cf1d39b3055dcd0fe02d8b47eaf0d5a13e1996de925de59d0ef9b7f7fad490600090a3505050505050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f55611e1c8161220c565b612710821115611e58576040517f9b569b8100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600280549083905560408051828152602081018590527f14914da2bf76024616fbe1859783fcd4dbddcb179b1f3a854949fbf920dcb957910160405180910390a1505050565b80516000906001600160a01b031615611ec3576020820151611ec09042614278565b90505b611ece8383836129ea565b6000611ee284606001518560a00151612c6e565b90506000806002541115611f1b57620f424060025483611f0291906142a0565b611f0c91906142b7565b9050611f1881836142f2565b91505b6000612024604051806101e001604052804663ffffffff168152602001886000015163ffffffff16815260200188602001516001600160a01b0316815260200188604001516001600160a01b0316815260200188606001516001600160a01b0316815260200188608001516001600160a01b031681526020018581526020018860c0015181526020018481526020018861010001518152602001600760008a602001516001600160a01b03166001600160a01b031681526020019081526020016000206000815480929190611fef90614305565b90915550815287516001600160a01b031660208201526040810187905260608089015190820152608080890151910152612e81565b805160208083019190912060008181526005835260409081902080548b5163ffffffff8116610100027fffffffffffffffffffffffffffffffffffffffffffffffffffffff000000000090921691909117600117909155928a01516060808c015160808d015160c08e0151928d0151945197985094966001600160a01b039093169587957f120ea0364f36cdac7983bcfdd55270ca09d7f9b314a2ebc425a3b01ab1d6403a956120e0958b959394938e9290919015159061433d565b60405180910390a3807f3120e2bb59c86aca6890191a589a96af3662838efa374fbdcdf4c95bfe4a6c0e876040015160405161211c9190614393565b60405180910390a250505050505050565b610ebf8282600061136e565b6000818152600160205260408120610c6490612fc6565b60008281526020819052604090206001015461216b8161220c565b610d708383612406565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f7965db0b000000000000000000000000000000000000000000000000000000001480610c6457507f01ffc9a7000000000000000000000000000000000000000000000000000000007fffffffff00000000000000000000000000000000000000000000000000000000831614610c64565b61163a8133612fd0565b80471015612257576040517fcd7860590000000000000000000000000000000000000000000000000000000081523060048201526024015b60405180910390fd5b6000826001600160a01b03168260405160006040518083038185875af1925050503d80600081146122a4576040519150601f19603f3d011682016040523d82523d6000602084013e6122a9565b606091505b5050905080610d72576040517f1425ea4200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040516001600160a01b03838116602483015260448201839052610d7291859182169063a9059cbb906064015b604051602081830303815290604052915060e01b6020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff838183161783525050505061303c565b610e10811015612394576040517f0e0ea5c700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600480549082905560408051828152602081018490527f909f9078b2f6eac1d10f2aae793656c5a67511eb627ebd1d2cb1eb9c0ab94c95910160405180910390a15050565b6000806123e684846130b8565b905080156117035760008481526001602052604090206110ba9084613180565b6000806124138484613195565b905080156117035760008481526001602052604090206110ba9084613236565b8051156124435780518082602001fd5b6040517f5ead5a9d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61014e8110156124b1576040517f6ee0e17100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b813560f01c60028114610d72576040517f8bd977e700000000000000000000000000000000000000000000000000000000815261ffff8216600482015260240161224e565b6125a8604051806101e00160405280600063ffffffff168152602001600063ffffffff16815260200160006001600160a01b0316815260200160006001600160a01b0316815260200160006001600160a01b0316815260200160006001600160a01b03168152602001600081526020016000815260200160008152602001600081526020016000815260200160006001600160a01b031681526020016000815260200160008152602001606081525090565b600283013560e090811c82526006840135811c6020830152600a840135606090811c6040840152601e850135811c818401526032850135811c60808401526046850135811c60a0840152605a85013560c0840152607a85013591830191909152609a84013561010083015260ba84013561012083015260da84013561014083015260fa840135901c61016082015261010e83013561018082015261012e8301356101a08201526126588383612872565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152505050506101c082015292915050565b6000611703838361324b565b6001600160a01b0381166126e4576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000828152600660205260409020546c0100000000000000000000000090046001600160a01b031615612743576040517fbef7bb7d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600684013560e01c4614612783576040517f7029fdf900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60ba8401354211156127c1576040517f559895a300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60fa84013560601c80158015906127ea5750816001600160a01b0316816001600160a01b031614155b80156127fb575061010e8501354211155b15612832576040517f14be123200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5050505050565b6040516001600160a01b038481166024830152838116604483015260648201839052610d709186918216906323b872dd90608401612311565b3660006128838361014e81876143a6565b915091509250929050565b600061290986868686866040516024016128ab94939291906143d0565b60408051601f198184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fe85e13dd0000000000000000000000000000000000000000000000000000000017905234613275565b90508051600003612946576040517f1a95ad2600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8051602014612981576040517ff3725cca00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7fe85e13dd000000000000000000000000000000000000000000000000000000006129ab826143f9565b146129e2576040517ff3725cca00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b505050505050565b46836000015163ffffffff1603612a2d576040517f7029fdf900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60a08301511580612a40575060c0830151155b15612a77576040517fe38820c800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60208301516001600160a01b03161580612a9c575060408301516001600160a01b0316155b15612ad3576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60608301516001600160a01b03161580612af8575060808301516001600160a01b0316155b15612b2f576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b612b3b61070842613fca565b8361010001511015612b79576040517f04b7fcc800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61ffff8260800151511115612bba576040517f177a70e100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b606082015115801590612bed575060808301516001600160a01b031673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee145b15612c24576040517f846dedc000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000811280612c37575082610100015181135b15610d72576040517f352807b900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60007fffffffffffffffffffffffff11111111111111111111111111111111111111126001600160a01b03841601612ce057348214612cd9576040517f81de0bf300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5034610c64565b3415612d18576040517f81de0bf300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b826001600160a01b03163b600003612d5c576040517f7f523fe800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201526001600160a01b038416906370a0823190602401602060405180830381865afa158015612db9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612ddd919061443e565b9050612df46001600160a01b038416333085612839565b6040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015281906001600160a01b038516906370a0823190602401602060405180830381865afa158015612e53573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612e77919061443e565b61170391906142f2565b8051602080830151604080850151606086810151608088015160a089015160c08a015195517e02000000000000000000000000000000000000000000000000000000000000988101989098527fffffffff0000000000000000000000000000000000000000000000000000000060e0998a1b811660228a01529690981b90951660268701527fffffffffffffffffffffffffffffffffffffffff00000000000000000000000092821b8316602a870152811b8216603e86015292831b8116605285015293821b9093166066830152607a820192909252600090609a0160408051601f198184030181529082905260e08501516101008601516101208701516101408801516101608901516101808a01516101a08b01516101c08c0151979950612faf988a9890602001614457565b604051602081830303815290604052915050919050565b6000610c64825490565b6000828152602081815260408083206001600160a01b038516845290915290205460ff16610ebf576040517fe2517d3f0000000000000000000000000000000000000000000000000000000081526001600160a01b03821660048201526024810183905260440161224e565b60006130516001600160a01b0384168361332b565b9050805160001415801561307657508080602001905181019061307491906144e0565b155b15610d72576040517f5274afe70000000000000000000000000000000000000000000000000000000081526001600160a01b038416600482015260240161224e565b6000828152602081815260408083206001600160a01b038516845290915281205460ff16613178576000838152602081815260408083206001600160a01b0386168452909152902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790556131303390565b6001600160a01b0316826001600160a01b0316847f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a4506001610c64565b506000610c64565b6000611703836001600160a01b038416613339565b6000828152602081815260408083206001600160a01b038516845290915281205460ff1615613178576000838152602081815260408083206001600160a01b038616808552925280832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016905551339286917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a4506001610c64565b6000611703836001600160a01b038416613380565b600082600001828154811061326257613262613ef7565b9060005260206000200154905092915050565b6060814710156132b3576040517fcd78605900000000000000000000000000000000000000000000000000000000815230600482015260240161224e565b600080856001600160a01b031684866040516132cf91906144fd565b60006040518083038185875af1925050503d806000811461330c576040519150601f19603f3d011682016040523d82523d6000602084013e613311565b606091505b5091509150613321868383613473565b9695505050505050565b606061170383836000613275565b600081815260018301602052604081205461317857508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155610c64565b600081815260018301602052604081205480156134695760006133a46001836142f2565b85549091506000906133b8906001906142f2565b905080821461341d5760008660000182815481106133d8576133d8613ef7565b90600052602060002001549050808760000184815481106133fb576133fb613ef7565b6000918252602080832090910192909255918252600188019052604090208390555b855486908061342e5761342e614519565b600190038181906000526020600020016000905590558560010160008681526020019081526020016000206000905560019350505050610c64565b6000915050610c64565b60608261348857613483826134e8565b611703565b815115801561349f57506001600160a01b0384163b155b156134e1576040517f9996b3150000000000000000000000000000000000000000000000000000000081526001600160a01b038516600482015260240161224e565b5080611703565b8051156134f85780518082602001fd5b6040517f1425ea4200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006020828403121561353c57600080fd5b81357fffffffff000000000000000000000000000000000000000000000000000000008116811461170357600080fd5b60006020828403121561357e57600080fd5b5035919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b600581106135eb577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b9052565b60208101610c6482846135b4565b6001600160a01b038116811461163a57600080fd5b803561361d816135fd565b919050565b6000806040838503121561363557600080fd5b8235613640816135fd565b91506020830135613650816135fd565b809150509250929050565b60008060006060848603121561367057600080fd5b83359250602084013591506040840135613689816135fd565b809150509250925092565b6000602082840312156136a657600080fd5b8135611703816135fd565b600080604083850312156136c457600080fd5b823591506020830135613650816135fd565b801515811461163a57600080fd5b803561361d816136d6565b60008060006040848603121561370457600080fd5b833567ffffffffffffffff8082111561371c57600080fd5b818601915086601f83011261373057600080fd5b81358181111561373f57600080fd5b8760208260051b850101111561375457600080fd5b60209283019550935050840135613689816136d6565b60005b8381101561378557818101518382015260200161376d565b50506000910152565b600081518084526137a681602086016020860161376a565b601f01601f19169290920160200192915050565b600060208083018184528085518083526040925060408601915060408160051b87010184880160005b83811015613842578883037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc0018552815180511515845287015187840187905261382f8785018261378e565b95880195935050908601906001016137e3565b509098975050505050505050565b60008083601f84011261386257600080fd5b50813567ffffffffffffffff81111561387a57600080fd5b60208301915083602082850101111561389257600080fd5b9250929050565b600080602083850312156138ac57600080fd5b823567ffffffffffffffff8111156138c357600080fd5b6138cf85828601613850565b90969095509350505050565b6000806000604084860312156138f057600080fd5b833567ffffffffffffffff81111561390757600080fd5b61391386828701613850565b9094509250506020840135613689816135fd565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051610120810167ffffffffffffffff8111828210171561397a5761397a613927565b60405290565b60405160a0810167ffffffffffffffff8111828210171561397a5761397a613927565b6040516101e0810167ffffffffffffffff8111828210171561397a5761397a613927565b604051610180810167ffffffffffffffff8111828210171561397a5761397a613927565b604051601f8201601f1916810167ffffffffffffffff81118282101715613a1457613a14613927565b604052919050565b63ffffffff8116811461163a57600080fd5b803561361d81613a1c565b60006101208284031215613a4c57600080fd5b613a54613956565b9050613a5f82613a2e565b8152613a6d60208301613612565b6020820152613a7e60408301613612565b6040820152613a8f60608301613612565b6060820152613aa060808301613612565b608082015260a082013560a082015260c082013560c0820152613ac560e083016136e4565b60e082015261010080830135818301525092915050565b60006101208284031215613aef57600080fd5b6117038383613a39565b60208152613b1060208201835163ffffffff169052565b60006020830151613b29604084018263ffffffff169052565b5060408301516001600160a01b03811660608401525060608301516001600160a01b03811660808401525060808301516001600160a01b03811660a08401525060a08301516001600160a01b03811660c08401525060c083015160e08381019190915283015161010080840191909152830151610120808401919091528301516101408084019190915283015161016080840191909152830151610180613bda818501836001600160a01b03169052565b8401516101a0848101919091528401516101c0808501919091528401516101e0808501529050613c0e61020084018261378e565b949350505050565b60808101613c2482876135b4565b63ffffffff8516602083015266ffffffffffffff841660408301526001600160a01b038316606083015295945050505050565b600080600060408486031215613c6c57600080fd5b833567ffffffffffffffff811115613c8357600080fd5b613c8f86828701613850565b909790965060209590950135949350505050565b60008060408385031215613cb657600080fd5b50508035926020909101359150565b815163ffffffff16815261018081016020830151613ceb602084018263ffffffff169052565b506040830151613d0660408401826001600160a01b03169052565b506060830151613d2160608401826001600160a01b03169052565b506080830151613d3c60808401826001600160a01b03169052565b5060a0830151613d5760a08401826001600160a01b03169052565b5060c083015160c083015260e083015160e083015261010080840151818401525061012080840151613d8c8285018215159052565b5050610140838101519083015261016092830151929091019190915290565b600067ffffffffffffffff821115613dc557613dc5613927565b50601f01601f191660200190565b600082601f830112613de457600080fd5b8135613df7613df282613dab565b6139eb565b818152846020838601011115613e0c57600080fd5b816020850160208301376000918101602001919091529392505050565b6000806101408385031215613e3d57600080fd5b613e478484613a39565b915061012083013567ffffffffffffffff80821115613e6557600080fd5b9084019060a08287031215613e7957600080fd5b613e81613980565b8235613e8c816135fd565b815260208381013590820152604083013582811115613eaa57600080fd5b613eb688828601613dd3565b60408301525060608301356060820152608083013582811115613ed857600080fd5b613ee488828601613dd3565b6080830152508093505050509250929050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112613f5b57600080fd5b83018035915067ffffffffffffffff821115613f7657600080fd5b60200191503681900382131561389257600080fd5b8183823760009101908152919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b80820180821115610c6457610c64613f9b565b818352818160208501375060006020828401015260006020601f19601f840116840101905092915050565b602081526000613c0e602083018486613fdd565b805161361d81613a1c565b805161361d816135fd565b600082601f83011261404357600080fd5b8151614051613df282613dab565b81815284602083860101111561406657600080fd5b613c0e82602083016020870161376a565b60006020828403121561408957600080fd5b815167ffffffffffffffff808211156140a157600080fd5b908301906101e082860312156140b657600080fd5b6140be6139a3565b6140c78361401c565b81526140d56020840161401c565b60208201526140e660408401614027565b60408201526140f760608401614027565b606082015261410860808401614027565b608082015261411960a08401614027565b60a082015260c0838101519082015260e08084015190820152610100808401519082015261012080840151908201526101408084015190820152610160614161818501614027565b9082015261018083810151908201526101a080840151908201526101c0808401518381111561418f57600080fd5b61419b88828701614032565b918301919091525095945050505050565b600061018082840312156141bf57600080fd5b6141c76139c7565b6141d083613a2e565b81526141de60208401613a2e565b60208201526141ef60408401613612565b604082015261420060608401613612565b606082015261421160808401613612565b608082015261422260a08401613612565b60a082015260c083013560c082015260e083013560e08201526101008084013581830152506101206142558185016136e4565b908201526101408381013590820152610160928301359281019290925250919050565b808201828112600083128015821682158216171561429857614298613f9b565b505092915050565b8082028115828204841417610c6457610c64613f9b565b6000826142ed577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b81810381811115610c6457610c64613f9b565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820361433657614336613f9b565b5060010190565b60e08152600061435060e083018a61378e565b63ffffffff989098166020830152506001600160a01b039586166040820152939094166060840152608083019190915260a082015290151560c090910152919050565b602081526000611703602083018461378e565b600080858511156143b657600080fd5b838611156143c357600080fd5b5050820193919092039150565b6001600160a01b0385168152836020820152606060408201526000613321606083018486613fdd565b80516020808301519190811015614438577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8160200360031b1b821691505b50919050565b60006020828403121561445057600080fd5b5051919050565b60008a51614469818460208f0161376a565b80830190508a81528960208201528860408201528760608201527fffffffffffffffffffffffffffffffffffffffff0000000000000000000000008760601b1660808201528560948201528460b482015283516144cd8160d484016020880161376a565b0160d4019b9a5050505050505050505050565b6000602082840312156144f257600080fd5b8151611703816136d6565b6000825161450f81846020870161376a565b9190910192915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fdfea2646970667358221220ff0963a32deca1c739f82fff423c2a4ab1b1e197296c902578ae57133c488fd564736f6c63430008180033", } // FastBridgeV2ABI is the input ABI used to generate the binding from. @@ -4600,6 +4764,37 @@ func (_FastBridgeV2 *FastBridgeV2TransactorRaw) Transact(opts *bind.TransactOpts return _FastBridgeV2.Contract.contract.Transact(opts, method, params...) } +// CANCELERROLE is a free data retrieval call binding the contract method 0x02d2ff66. +// +// Solidity: function CANCELER_ROLE() view returns(bytes32) +func (_FastBridgeV2 *FastBridgeV2Caller) CANCELERROLE(opts *bind.CallOpts) ([32]byte, error) { + var out []interface{} + err := _FastBridgeV2.contract.Call(opts, &out, "CANCELER_ROLE") + + if err != nil { + return *new([32]byte), err + } + + out0 := *abi.ConvertType(out[0], new([32]byte)).(*[32]byte) + + return out0, err + +} + +// CANCELERROLE is a free data retrieval call binding the contract method 0x02d2ff66. +// +// Solidity: function CANCELER_ROLE() view returns(bytes32) +func (_FastBridgeV2 *FastBridgeV2Session) CANCELERROLE() ([32]byte, error) { + return _FastBridgeV2.Contract.CANCELERROLE(&_FastBridgeV2.CallOpts) +} + +// CANCELERROLE is a free data retrieval call binding the contract method 0x02d2ff66. +// +// Solidity: function CANCELER_ROLE() view returns(bytes32) +func (_FastBridgeV2 *FastBridgeV2CallerSession) CANCELERROLE() ([32]byte, error) { + return _FastBridgeV2.Contract.CANCELERROLE(&_FastBridgeV2.CallOpts) +} + // DEFAULTADMINROLE is a free data retrieval call binding the contract method 0xa217fddf. // // Solidity: function DEFAULT_ADMIN_ROLE() view returns(bytes32) @@ -4631,6 +4826,37 @@ func (_FastBridgeV2 *FastBridgeV2CallerSession) DEFAULTADMINROLE() ([32]byte, er return _FastBridgeV2.Contract.DEFAULTADMINROLE(&_FastBridgeV2.CallOpts) } +// DEFAULTCANCELDELAY is a free data retrieval call binding the contract method 0x930ac180. +// +// Solidity: function DEFAULT_CANCEL_DELAY() view returns(uint256) +func (_FastBridgeV2 *FastBridgeV2Caller) DEFAULTCANCELDELAY(opts *bind.CallOpts) (*big.Int, error) { + var out []interface{} + err := _FastBridgeV2.contract.Call(opts, &out, "DEFAULT_CANCEL_DELAY") + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// DEFAULTCANCELDELAY is a free data retrieval call binding the contract method 0x930ac180. +// +// Solidity: function DEFAULT_CANCEL_DELAY() view returns(uint256) +func (_FastBridgeV2 *FastBridgeV2Session) DEFAULTCANCELDELAY() (*big.Int, error) { + return _FastBridgeV2.Contract.DEFAULTCANCELDELAY(&_FastBridgeV2.CallOpts) +} + +// DEFAULTCANCELDELAY is a free data retrieval call binding the contract method 0x930ac180. +// +// Solidity: function DEFAULT_CANCEL_DELAY() view returns(uint256) +func (_FastBridgeV2 *FastBridgeV2CallerSession) DEFAULTCANCELDELAY() (*big.Int, error) { + return _FastBridgeV2.Contract.DEFAULTCANCELDELAY(&_FastBridgeV2.CallOpts) +} + // DISPUTEPERIOD is a free data retrieval call binding the contract method 0xa5bbe22b. // // Solidity: function DISPUTE_PERIOD() view returns(uint256) @@ -4817,6 +5043,37 @@ func (_FastBridgeV2 *FastBridgeV2CallerSession) MAXZAPDATALENGTH() (*big.Int, er return _FastBridgeV2.Contract.MAXZAPDATALENGTH(&_FastBridgeV2.CallOpts) } +// MINCANCELDELAY is a free data retrieval call binding the contract method 0x922b7487. +// +// Solidity: function MIN_CANCEL_DELAY() view returns(uint256) +func (_FastBridgeV2 *FastBridgeV2Caller) MINCANCELDELAY(opts *bind.CallOpts) (*big.Int, error) { + var out []interface{} + err := _FastBridgeV2.contract.Call(opts, &out, "MIN_CANCEL_DELAY") + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// MINCANCELDELAY is a free data retrieval call binding the contract method 0x922b7487. +// +// Solidity: function MIN_CANCEL_DELAY() view returns(uint256) +func (_FastBridgeV2 *FastBridgeV2Session) MINCANCELDELAY() (*big.Int, error) { + return _FastBridgeV2.Contract.MINCANCELDELAY(&_FastBridgeV2.CallOpts) +} + +// MINCANCELDELAY is a free data retrieval call binding the contract method 0x922b7487. +// +// Solidity: function MIN_CANCEL_DELAY() view returns(uint256) +func (_FastBridgeV2 *FastBridgeV2CallerSession) MINCANCELDELAY() (*big.Int, error) { + return _FastBridgeV2.Contract.MINCANCELDELAY(&_FastBridgeV2.CallOpts) +} + // MINDEADLINEPERIOD is a free data retrieval call binding the contract method 0x820688d5. // // Solidity: function MIN_DEADLINE_PERIOD() view returns(uint256) @@ -4879,12 +5136,12 @@ func (_FastBridgeV2 *FastBridgeV2CallerSession) NATIVEGASTOKEN() (common.Address return _FastBridgeV2.Contract.NATIVEGASTOKEN(&_FastBridgeV2.CallOpts) } -// REFUNDERROLE is a free data retrieval call binding the contract method 0x5960ccf2. +// PROVERROLE is a free data retrieval call binding the contract method 0xdc9a4ef6. // -// Solidity: function REFUNDER_ROLE() view returns(bytes32) -func (_FastBridgeV2 *FastBridgeV2Caller) REFUNDERROLE(opts *bind.CallOpts) ([32]byte, error) { +// Solidity: function PROVER_ROLE() view returns(bytes32) +func (_FastBridgeV2 *FastBridgeV2Caller) PROVERROLE(opts *bind.CallOpts) ([32]byte, error) { var out []interface{} - err := _FastBridgeV2.contract.Call(opts, &out, "REFUNDER_ROLE") + err := _FastBridgeV2.contract.Call(opts, &out, "PROVER_ROLE") if err != nil { return *new([32]byte), err @@ -4896,57 +5153,26 @@ func (_FastBridgeV2 *FastBridgeV2Caller) REFUNDERROLE(opts *bind.CallOpts) ([32] } -// REFUNDERROLE is a free data retrieval call binding the contract method 0x5960ccf2. +// PROVERROLE is a free data retrieval call binding the contract method 0xdc9a4ef6. // -// Solidity: function REFUNDER_ROLE() view returns(bytes32) -func (_FastBridgeV2 *FastBridgeV2Session) REFUNDERROLE() ([32]byte, error) { - return _FastBridgeV2.Contract.REFUNDERROLE(&_FastBridgeV2.CallOpts) +// Solidity: function PROVER_ROLE() view returns(bytes32) +func (_FastBridgeV2 *FastBridgeV2Session) PROVERROLE() ([32]byte, error) { + return _FastBridgeV2.Contract.PROVERROLE(&_FastBridgeV2.CallOpts) } -// REFUNDERROLE is a free data retrieval call binding the contract method 0x5960ccf2. +// PROVERROLE is a free data retrieval call binding the contract method 0xdc9a4ef6. // -// Solidity: function REFUNDER_ROLE() view returns(bytes32) -func (_FastBridgeV2 *FastBridgeV2CallerSession) REFUNDERROLE() ([32]byte, error) { - return _FastBridgeV2.Contract.REFUNDERROLE(&_FastBridgeV2.CallOpts) +// Solidity: function PROVER_ROLE() view returns(bytes32) +func (_FastBridgeV2 *FastBridgeV2CallerSession) PROVERROLE() ([32]byte, error) { + return _FastBridgeV2.Contract.PROVERROLE(&_FastBridgeV2.CallOpts) } -// REFUNDDELAY is a free data retrieval call binding the contract method 0x190da595. +// QUOTERROLE is a free data retrieval call binding the contract method 0x7ebe815c. // -// Solidity: function REFUND_DELAY() view returns(uint256) -func (_FastBridgeV2 *FastBridgeV2Caller) REFUNDDELAY(opts *bind.CallOpts) (*big.Int, error) { +// Solidity: function QUOTER_ROLE() view returns(bytes32) +func (_FastBridgeV2 *FastBridgeV2Caller) QUOTERROLE(opts *bind.CallOpts) ([32]byte, error) { var out []interface{} - err := _FastBridgeV2.contract.Call(opts, &out, "REFUND_DELAY") - - if err != nil { - return *new(*big.Int), err - } - - out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) - - return out0, err - -} - -// REFUNDDELAY is a free data retrieval call binding the contract method 0x190da595. -// -// Solidity: function REFUND_DELAY() view returns(uint256) -func (_FastBridgeV2 *FastBridgeV2Session) REFUNDDELAY() (*big.Int, error) { - return _FastBridgeV2.Contract.REFUNDDELAY(&_FastBridgeV2.CallOpts) -} - -// REFUNDDELAY is a free data retrieval call binding the contract method 0x190da595. -// -// Solidity: function REFUND_DELAY() view returns(uint256) -func (_FastBridgeV2 *FastBridgeV2CallerSession) REFUNDDELAY() (*big.Int, error) { - return _FastBridgeV2.Contract.REFUNDDELAY(&_FastBridgeV2.CallOpts) -} - -// RELAYERROLE is a free data retrieval call binding the contract method 0x926d7d7f. -// -// Solidity: function RELAYER_ROLE() view returns(bytes32) -func (_FastBridgeV2 *FastBridgeV2Caller) RELAYERROLE(opts *bind.CallOpts) ([32]byte, error) { - var out []interface{} - err := _FastBridgeV2.contract.Call(opts, &out, "RELAYER_ROLE") + err := _FastBridgeV2.contract.Call(opts, &out, "QUOTER_ROLE") if err != nil { return *new([32]byte), err @@ -4958,18 +5184,18 @@ func (_FastBridgeV2 *FastBridgeV2Caller) RELAYERROLE(opts *bind.CallOpts) ([32]b } -// RELAYERROLE is a free data retrieval call binding the contract method 0x926d7d7f. +// QUOTERROLE is a free data retrieval call binding the contract method 0x7ebe815c. // -// Solidity: function RELAYER_ROLE() view returns(bytes32) -func (_FastBridgeV2 *FastBridgeV2Session) RELAYERROLE() ([32]byte, error) { - return _FastBridgeV2.Contract.RELAYERROLE(&_FastBridgeV2.CallOpts) +// Solidity: function QUOTER_ROLE() view returns(bytes32) +func (_FastBridgeV2 *FastBridgeV2Session) QUOTERROLE() ([32]byte, error) { + return _FastBridgeV2.Contract.QUOTERROLE(&_FastBridgeV2.CallOpts) } -// RELAYERROLE is a free data retrieval call binding the contract method 0x926d7d7f. +// QUOTERROLE is a free data retrieval call binding the contract method 0x7ebe815c. // -// Solidity: function RELAYER_ROLE() view returns(bytes32) -func (_FastBridgeV2 *FastBridgeV2CallerSession) RELAYERROLE() ([32]byte, error) { - return _FastBridgeV2.Contract.RELAYERROLE(&_FastBridgeV2.CallOpts) +// Solidity: function QUOTER_ROLE() view returns(bytes32) +func (_FastBridgeV2 *FastBridgeV2CallerSession) QUOTERROLE() ([32]byte, error) { + return _FastBridgeV2.Contract.QUOTERROLE(&_FastBridgeV2.CallOpts) } // BridgeProofs is a free data retrieval call binding the contract method 0x91ad5039. @@ -5215,6 +5441,37 @@ func (_FastBridgeV2 *FastBridgeV2CallerSession) CanClaim(transactionId [32]byte, return _FastBridgeV2.Contract.CanClaim(&_FastBridgeV2.CallOpts, transactionId, relayer) } +// CancelDelay is a free data retrieval call binding the contract method 0x638a0f09. +// +// Solidity: function cancelDelay() view returns(uint256) +func (_FastBridgeV2 *FastBridgeV2Caller) CancelDelay(opts *bind.CallOpts) (*big.Int, error) { + var out []interface{} + err := _FastBridgeV2.contract.Call(opts, &out, "cancelDelay") + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// CancelDelay is a free data retrieval call binding the contract method 0x638a0f09. +// +// Solidity: function cancelDelay() view returns(uint256) +func (_FastBridgeV2 *FastBridgeV2Session) CancelDelay() (*big.Int, error) { + return _FastBridgeV2.Contract.CancelDelay(&_FastBridgeV2.CallOpts) +} + +// CancelDelay is a free data retrieval call binding the contract method 0x638a0f09. +// +// Solidity: function cancelDelay() view returns(uint256) +func (_FastBridgeV2 *FastBridgeV2CallerSession) CancelDelay() (*big.Int, error) { + return _FastBridgeV2.Contract.CancelDelay(&_FastBridgeV2.CallOpts) +} + // ChainGasAmount is a free data retrieval call binding the contract method 0xe00a83e0. // // Solidity: function chainGasAmount() view returns(uint256) @@ -5660,6 +5917,27 @@ func (_FastBridgeV2 *FastBridgeV2TransactorSession) Bridge0(params IFastBridgeBr return _FastBridgeV2.Contract.Bridge0(&_FastBridgeV2.TransactOpts, params, paramsV2) } +// Cancel is a paid mutator transaction binding the contract method 0x3c5beeb4. +// +// Solidity: function cancel(bytes request) returns() +func (_FastBridgeV2 *FastBridgeV2Transactor) Cancel(opts *bind.TransactOpts, request []byte) (*types.Transaction, error) { + return _FastBridgeV2.contract.Transact(opts, "cancel", request) +} + +// Cancel is a paid mutator transaction binding the contract method 0x3c5beeb4. +// +// Solidity: function cancel(bytes request) returns() +func (_FastBridgeV2 *FastBridgeV2Session) Cancel(request []byte) (*types.Transaction, error) { + return _FastBridgeV2.Contract.Cancel(&_FastBridgeV2.TransactOpts, request) +} + +// Cancel is a paid mutator transaction binding the contract method 0x3c5beeb4. +// +// Solidity: function cancel(bytes request) returns() +func (_FastBridgeV2 *FastBridgeV2TransactorSession) Cancel(request []byte) (*types.Transaction, error) { + return _FastBridgeV2.Contract.Cancel(&_FastBridgeV2.TransactOpts, request) +} + // Claim is a paid mutator transaction binding the contract method 0x41fcb612. // // Solidity: function claim(bytes request, address to) returns() @@ -5933,25 +6211,25 @@ func (_FastBridgeV2 *FastBridgeV2TransactorSession) RevokeRole(role [32]byte, ac return _FastBridgeV2.Contract.RevokeRole(&_FastBridgeV2.TransactOpts, role, account) } -// SetChainGasAmount is a paid mutator transaction binding the contract method 0xb250fe6b. +// SetCancelDelay is a paid mutator transaction binding the contract method 0x1ea327c5. // -// Solidity: function setChainGasAmount(uint256 newChainGasAmount) returns() -func (_FastBridgeV2 *FastBridgeV2Transactor) SetChainGasAmount(opts *bind.TransactOpts, newChainGasAmount *big.Int) (*types.Transaction, error) { - return _FastBridgeV2.contract.Transact(opts, "setChainGasAmount", newChainGasAmount) +// Solidity: function setCancelDelay(uint256 newCancelDelay) returns() +func (_FastBridgeV2 *FastBridgeV2Transactor) SetCancelDelay(opts *bind.TransactOpts, newCancelDelay *big.Int) (*types.Transaction, error) { + return _FastBridgeV2.contract.Transact(opts, "setCancelDelay", newCancelDelay) } -// SetChainGasAmount is a paid mutator transaction binding the contract method 0xb250fe6b. +// SetCancelDelay is a paid mutator transaction binding the contract method 0x1ea327c5. // -// Solidity: function setChainGasAmount(uint256 newChainGasAmount) returns() -func (_FastBridgeV2 *FastBridgeV2Session) SetChainGasAmount(newChainGasAmount *big.Int) (*types.Transaction, error) { - return _FastBridgeV2.Contract.SetChainGasAmount(&_FastBridgeV2.TransactOpts, newChainGasAmount) +// Solidity: function setCancelDelay(uint256 newCancelDelay) returns() +func (_FastBridgeV2 *FastBridgeV2Session) SetCancelDelay(newCancelDelay *big.Int) (*types.Transaction, error) { + return _FastBridgeV2.Contract.SetCancelDelay(&_FastBridgeV2.TransactOpts, newCancelDelay) } -// SetChainGasAmount is a paid mutator transaction binding the contract method 0xb250fe6b. +// SetCancelDelay is a paid mutator transaction binding the contract method 0x1ea327c5. // -// Solidity: function setChainGasAmount(uint256 newChainGasAmount) returns() -func (_FastBridgeV2 *FastBridgeV2TransactorSession) SetChainGasAmount(newChainGasAmount *big.Int) (*types.Transaction, error) { - return _FastBridgeV2.Contract.SetChainGasAmount(&_FastBridgeV2.TransactOpts, newChainGasAmount) +// Solidity: function setCancelDelay(uint256 newCancelDelay) returns() +func (_FastBridgeV2 *FastBridgeV2TransactorSession) SetCancelDelay(newCancelDelay *big.Int) (*types.Transaction, error) { + return _FastBridgeV2.Contract.SetCancelDelay(&_FastBridgeV2.TransactOpts, newCancelDelay) } // SetProtocolFeeRate is a paid mutator transaction binding the contract method 0xb13aa2d6. @@ -7095,9 +7373,9 @@ func (_FastBridgeV2 *FastBridgeV2Filterer) ParseBridgeRequested(log types.Log) ( return event, nil } -// FastBridgeV2ChainGasAmountUpdatedIterator is returned from FilterChainGasAmountUpdated and is used to iterate over the raw logs and unpacked data for ChainGasAmountUpdated events raised by the FastBridgeV2 contract. -type FastBridgeV2ChainGasAmountUpdatedIterator struct { - Event *FastBridgeV2ChainGasAmountUpdated // Event containing the contract specifics and raw log +// FastBridgeV2CancelDelayUpdatedIterator is returned from FilterCancelDelayUpdated and is used to iterate over the raw logs and unpacked data for CancelDelayUpdated events raised by the FastBridgeV2 contract. +type FastBridgeV2CancelDelayUpdatedIterator struct { + Event *FastBridgeV2CancelDelayUpdated // Event containing the contract specifics and raw log contract *bind.BoundContract // Generic contract to use for unpacking event data event string // Event name to use for unpacking event data @@ -7111,7 +7389,7 @@ type FastBridgeV2ChainGasAmountUpdatedIterator struct { // Next advances the iterator to the subsequent event, returning whether there // are any more events found. In case of a retrieval or parsing error, false is // returned and Error() can be queried for the exact failure. -func (it *FastBridgeV2ChainGasAmountUpdatedIterator) Next() bool { +func (it *FastBridgeV2CancelDelayUpdatedIterator) Next() bool { // If the iterator failed, stop iterating if it.fail != nil { return false @@ -7120,7 +7398,7 @@ func (it *FastBridgeV2ChainGasAmountUpdatedIterator) Next() bool { if it.done { select { case log := <-it.logs: - it.Event = new(FastBridgeV2ChainGasAmountUpdated) + it.Event = new(FastBridgeV2CancelDelayUpdated) if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { it.fail = err return false @@ -7135,7 +7413,7 @@ func (it *FastBridgeV2ChainGasAmountUpdatedIterator) Next() bool { // Iterator still in progress, wait for either a data or an error event select { case log := <-it.logs: - it.Event = new(FastBridgeV2ChainGasAmountUpdated) + it.Event = new(FastBridgeV2CancelDelayUpdated) if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { it.fail = err return false @@ -7151,42 +7429,42 @@ func (it *FastBridgeV2ChainGasAmountUpdatedIterator) Next() bool { } // Error returns any retrieval or parsing error occurred during filtering. -func (it *FastBridgeV2ChainGasAmountUpdatedIterator) Error() error { +func (it *FastBridgeV2CancelDelayUpdatedIterator) Error() error { return it.fail } // Close terminates the iteration process, releasing any pending underlying // resources. -func (it *FastBridgeV2ChainGasAmountUpdatedIterator) Close() error { +func (it *FastBridgeV2CancelDelayUpdatedIterator) Close() error { it.sub.Unsubscribe() return nil } -// FastBridgeV2ChainGasAmountUpdated represents a ChainGasAmountUpdated event raised by the FastBridgeV2 contract. -type FastBridgeV2ChainGasAmountUpdated struct { - OldChainGasAmount *big.Int - NewChainGasAmount *big.Int - Raw types.Log // Blockchain specific contextual infos +// FastBridgeV2CancelDelayUpdated represents a CancelDelayUpdated event raised by the FastBridgeV2 contract. +type FastBridgeV2CancelDelayUpdated struct { + OldCancelDelay *big.Int + NewCancelDelay *big.Int + Raw types.Log // Blockchain specific contextual infos } -// FilterChainGasAmountUpdated is a free log retrieval operation binding the contract event 0x5cf09b12f3f56b4c564d51b25b40360af6d795198adb61ae0806a36c294323fa. +// FilterCancelDelayUpdated is a free log retrieval operation binding the contract event 0x909f9078b2f6eac1d10f2aae793656c5a67511eb627ebd1d2cb1eb9c0ab94c95. // -// Solidity: event ChainGasAmountUpdated(uint256 oldChainGasAmount, uint256 newChainGasAmount) -func (_FastBridgeV2 *FastBridgeV2Filterer) FilterChainGasAmountUpdated(opts *bind.FilterOpts) (*FastBridgeV2ChainGasAmountUpdatedIterator, error) { +// Solidity: event CancelDelayUpdated(uint256 oldCancelDelay, uint256 newCancelDelay) +func (_FastBridgeV2 *FastBridgeV2Filterer) FilterCancelDelayUpdated(opts *bind.FilterOpts) (*FastBridgeV2CancelDelayUpdatedIterator, error) { - logs, sub, err := _FastBridgeV2.contract.FilterLogs(opts, "ChainGasAmountUpdated") + logs, sub, err := _FastBridgeV2.contract.FilterLogs(opts, "CancelDelayUpdated") if err != nil { return nil, err } - return &FastBridgeV2ChainGasAmountUpdatedIterator{contract: _FastBridgeV2.contract, event: "ChainGasAmountUpdated", logs: logs, sub: sub}, nil + return &FastBridgeV2CancelDelayUpdatedIterator{contract: _FastBridgeV2.contract, event: "CancelDelayUpdated", logs: logs, sub: sub}, nil } -// WatchChainGasAmountUpdated is a free log subscription operation binding the contract event 0x5cf09b12f3f56b4c564d51b25b40360af6d795198adb61ae0806a36c294323fa. +// WatchCancelDelayUpdated is a free log subscription operation binding the contract event 0x909f9078b2f6eac1d10f2aae793656c5a67511eb627ebd1d2cb1eb9c0ab94c95. // -// Solidity: event ChainGasAmountUpdated(uint256 oldChainGasAmount, uint256 newChainGasAmount) -func (_FastBridgeV2 *FastBridgeV2Filterer) WatchChainGasAmountUpdated(opts *bind.WatchOpts, sink chan<- *FastBridgeV2ChainGasAmountUpdated) (event.Subscription, error) { +// Solidity: event CancelDelayUpdated(uint256 oldCancelDelay, uint256 newCancelDelay) +func (_FastBridgeV2 *FastBridgeV2Filterer) WatchCancelDelayUpdated(opts *bind.WatchOpts, sink chan<- *FastBridgeV2CancelDelayUpdated) (event.Subscription, error) { - logs, sub, err := _FastBridgeV2.contract.WatchLogs(opts, "ChainGasAmountUpdated") + logs, sub, err := _FastBridgeV2.contract.WatchLogs(opts, "CancelDelayUpdated") if err != nil { return nil, err } @@ -7196,8 +7474,8 @@ func (_FastBridgeV2 *FastBridgeV2Filterer) WatchChainGasAmountUpdated(opts *bind select { case log := <-logs: // New log arrived, parse the event and forward to the user - event := new(FastBridgeV2ChainGasAmountUpdated) - if err := _FastBridgeV2.contract.UnpackLog(event, "ChainGasAmountUpdated", log); err != nil { + event := new(FastBridgeV2CancelDelayUpdated) + if err := _FastBridgeV2.contract.UnpackLog(event, "CancelDelayUpdated", log); err != nil { return err } event.Raw = log @@ -7218,12 +7496,12 @@ func (_FastBridgeV2 *FastBridgeV2Filterer) WatchChainGasAmountUpdated(opts *bind }), nil } -// ParseChainGasAmountUpdated is a log parse operation binding the contract event 0x5cf09b12f3f56b4c564d51b25b40360af6d795198adb61ae0806a36c294323fa. +// ParseCancelDelayUpdated is a log parse operation binding the contract event 0x909f9078b2f6eac1d10f2aae793656c5a67511eb627ebd1d2cb1eb9c0ab94c95. // -// Solidity: event ChainGasAmountUpdated(uint256 oldChainGasAmount, uint256 newChainGasAmount) -func (_FastBridgeV2 *FastBridgeV2Filterer) ParseChainGasAmountUpdated(log types.Log) (*FastBridgeV2ChainGasAmountUpdated, error) { - event := new(FastBridgeV2ChainGasAmountUpdated) - if err := _FastBridgeV2.contract.UnpackLog(event, "ChainGasAmountUpdated", log); err != nil { +// Solidity: event CancelDelayUpdated(uint256 oldCancelDelay, uint256 newCancelDelay) +func (_FastBridgeV2 *FastBridgeV2Filterer) ParseCancelDelayUpdated(log types.Log) (*FastBridgeV2CancelDelayUpdated, error) { + event := new(FastBridgeV2CancelDelayUpdated) + if err := _FastBridgeV2.contract.UnpackLog(event, "CancelDelayUpdated", log); err != nil { return nil, err } event.Raw = log @@ -9597,122 +9875,122 @@ func (_IAccessControlEnumerable *IAccessControlEnumerableFilterer) ParseRoleRevo return event, nil } -// IAdminMetaData contains all meta data concerning the IAdmin contract. -var IAdminMetaData = &bind.MetaData{ - ABI: "[{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"oldChainGasAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newChainGasAmount\",\"type\":\"uint256\"}],\"name\":\"ChainGasAmountUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"oldFeeRate\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newFeeRate\",\"type\":\"uint256\"}],\"name\":\"FeeRateUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"FeesSwept\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"newChainGasAmount\",\"type\":\"uint256\"}],\"name\":\"setChainGasAmount\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"newFeeRate\",\"type\":\"uint256\"}],\"name\":\"setProtocolFeeRate\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"}],\"name\":\"sweepProtocolFees\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", +// IAdminV2MetaData contains all meta data concerning the IAdminV2 contract. +var IAdminV2MetaData = &bind.MetaData{ + ABI: "[{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"oldCancelDelay\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newCancelDelay\",\"type\":\"uint256\"}],\"name\":\"CancelDelayUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"oldFeeRate\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newFeeRate\",\"type\":\"uint256\"}],\"name\":\"FeeRateUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"FeesSwept\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"newCancelDelay\",\"type\":\"uint256\"}],\"name\":\"setCancelDelay\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"newFeeRate\",\"type\":\"uint256\"}],\"name\":\"setProtocolFeeRate\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"}],\"name\":\"sweepProtocolFees\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", Sigs: map[string]string{ - "b250fe6b": "setChainGasAmount(uint256)", + "1ea327c5": "setCancelDelay(uint256)", "b13aa2d6": "setProtocolFeeRate(uint256)", "06f333f2": "sweepProtocolFees(address,address)", }, } -// IAdminABI is the input ABI used to generate the binding from. -// Deprecated: Use IAdminMetaData.ABI instead. -var IAdminABI = IAdminMetaData.ABI +// IAdminV2ABI is the input ABI used to generate the binding from. +// Deprecated: Use IAdminV2MetaData.ABI instead. +var IAdminV2ABI = IAdminV2MetaData.ABI -// Deprecated: Use IAdminMetaData.Sigs instead. -// IAdminFuncSigs maps the 4-byte function signature to its string representation. -var IAdminFuncSigs = IAdminMetaData.Sigs +// Deprecated: Use IAdminV2MetaData.Sigs instead. +// IAdminV2FuncSigs maps the 4-byte function signature to its string representation. +var IAdminV2FuncSigs = IAdminV2MetaData.Sigs -// IAdmin is an auto generated Go binding around an Ethereum contract. -type IAdmin struct { - IAdminCaller // Read-only binding to the contract - IAdminTransactor // Write-only binding to the contract - IAdminFilterer // Log filterer for contract events +// IAdminV2 is an auto generated Go binding around an Ethereum contract. +type IAdminV2 struct { + IAdminV2Caller // Read-only binding to the contract + IAdminV2Transactor // Write-only binding to the contract + IAdminV2Filterer // Log filterer for contract events } -// IAdminCaller is an auto generated read-only Go binding around an Ethereum contract. -type IAdminCaller struct { +// IAdminV2Caller is an auto generated read-only Go binding around an Ethereum contract. +type IAdminV2Caller struct { contract *bind.BoundContract // Generic contract wrapper for the low level calls } -// IAdminTransactor is an auto generated write-only Go binding around an Ethereum contract. -type IAdminTransactor struct { +// IAdminV2Transactor is an auto generated write-only Go binding around an Ethereum contract. +type IAdminV2Transactor struct { contract *bind.BoundContract // Generic contract wrapper for the low level calls } -// IAdminFilterer is an auto generated log filtering Go binding around an Ethereum contract events. -type IAdminFilterer struct { +// IAdminV2Filterer is an auto generated log filtering Go binding around an Ethereum contract events. +type IAdminV2Filterer struct { contract *bind.BoundContract // Generic contract wrapper for the low level calls } -// IAdminSession is an auto generated Go binding around an Ethereum contract, +// IAdminV2Session is an auto generated Go binding around an Ethereum contract, // with pre-set call and transact options. -type IAdminSession struct { - Contract *IAdmin // Generic contract binding to set the session for +type IAdminV2Session struct { + Contract *IAdminV2 // Generic contract binding to set the session for CallOpts bind.CallOpts // Call options to use throughout this session TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session } -// IAdminCallerSession is an auto generated read-only Go binding around an Ethereum contract, +// IAdminV2CallerSession is an auto generated read-only Go binding around an Ethereum contract, // with pre-set call options. -type IAdminCallerSession struct { - Contract *IAdminCaller // Generic contract caller binding to set the session for - CallOpts bind.CallOpts // Call options to use throughout this session +type IAdminV2CallerSession struct { + Contract *IAdminV2Caller // Generic contract caller binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session } -// IAdminTransactorSession is an auto generated write-only Go binding around an Ethereum contract, +// IAdminV2TransactorSession is an auto generated write-only Go binding around an Ethereum contract, // with pre-set transact options. -type IAdminTransactorSession struct { - Contract *IAdminTransactor // Generic contract transactor binding to set the session for - TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +type IAdminV2TransactorSession struct { + Contract *IAdminV2Transactor // Generic contract transactor binding to set the session for + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session } -// IAdminRaw is an auto generated low-level Go binding around an Ethereum contract. -type IAdminRaw struct { - Contract *IAdmin // Generic contract binding to access the raw methods on +// IAdminV2Raw is an auto generated low-level Go binding around an Ethereum contract. +type IAdminV2Raw struct { + Contract *IAdminV2 // Generic contract binding to access the raw methods on } -// IAdminCallerRaw is an auto generated low-level read-only Go binding around an Ethereum contract. -type IAdminCallerRaw struct { - Contract *IAdminCaller // Generic read-only contract binding to access the raw methods on +// IAdminV2CallerRaw is an auto generated low-level read-only Go binding around an Ethereum contract. +type IAdminV2CallerRaw struct { + Contract *IAdminV2Caller // Generic read-only contract binding to access the raw methods on } -// IAdminTransactorRaw is an auto generated low-level write-only Go binding around an Ethereum contract. -type IAdminTransactorRaw struct { - Contract *IAdminTransactor // Generic write-only contract binding to access the raw methods on +// IAdminV2TransactorRaw is an auto generated low-level write-only Go binding around an Ethereum contract. +type IAdminV2TransactorRaw struct { + Contract *IAdminV2Transactor // Generic write-only contract binding to access the raw methods on } -// NewIAdmin creates a new instance of IAdmin, bound to a specific deployed contract. -func NewIAdmin(address common.Address, backend bind.ContractBackend) (*IAdmin, error) { - contract, err := bindIAdmin(address, backend, backend, backend) +// NewIAdminV2 creates a new instance of IAdminV2, bound to a specific deployed contract. +func NewIAdminV2(address common.Address, backend bind.ContractBackend) (*IAdminV2, error) { + contract, err := bindIAdminV2(address, backend, backend, backend) if err != nil { return nil, err } - return &IAdmin{IAdminCaller: IAdminCaller{contract: contract}, IAdminTransactor: IAdminTransactor{contract: contract}, IAdminFilterer: IAdminFilterer{contract: contract}}, nil + return &IAdminV2{IAdminV2Caller: IAdminV2Caller{contract: contract}, IAdminV2Transactor: IAdminV2Transactor{contract: contract}, IAdminV2Filterer: IAdminV2Filterer{contract: contract}}, nil } -// NewIAdminCaller creates a new read-only instance of IAdmin, bound to a specific deployed contract. -func NewIAdminCaller(address common.Address, caller bind.ContractCaller) (*IAdminCaller, error) { - contract, err := bindIAdmin(address, caller, nil, nil) +// NewIAdminV2Caller creates a new read-only instance of IAdminV2, bound to a specific deployed contract. +func NewIAdminV2Caller(address common.Address, caller bind.ContractCaller) (*IAdminV2Caller, error) { + contract, err := bindIAdminV2(address, caller, nil, nil) if err != nil { return nil, err } - return &IAdminCaller{contract: contract}, nil + return &IAdminV2Caller{contract: contract}, nil } -// NewIAdminTransactor creates a new write-only instance of IAdmin, bound to a specific deployed contract. -func NewIAdminTransactor(address common.Address, transactor bind.ContractTransactor) (*IAdminTransactor, error) { - contract, err := bindIAdmin(address, nil, transactor, nil) +// NewIAdminV2Transactor creates a new write-only instance of IAdminV2, bound to a specific deployed contract. +func NewIAdminV2Transactor(address common.Address, transactor bind.ContractTransactor) (*IAdminV2Transactor, error) { + contract, err := bindIAdminV2(address, nil, transactor, nil) if err != nil { return nil, err } - return &IAdminTransactor{contract: contract}, nil + return &IAdminV2Transactor{contract: contract}, nil } -// NewIAdminFilterer creates a new log filterer instance of IAdmin, bound to a specific deployed contract. -func NewIAdminFilterer(address common.Address, filterer bind.ContractFilterer) (*IAdminFilterer, error) { - contract, err := bindIAdmin(address, nil, nil, filterer) +// NewIAdminV2Filterer creates a new log filterer instance of IAdminV2, bound to a specific deployed contract. +func NewIAdminV2Filterer(address common.Address, filterer bind.ContractFilterer) (*IAdminV2Filterer, error) { + contract, err := bindIAdminV2(address, nil, nil, filterer) if err != nil { return nil, err } - return &IAdminFilterer{contract: contract}, nil + return &IAdminV2Filterer{contract: contract}, nil } -// bindIAdmin binds a generic wrapper to an already deployed contract. -func bindIAdmin(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) { - parsed, err := IAdminMetaData.GetAbi() +// bindIAdminV2 binds a generic wrapper to an already deployed contract. +func bindIAdminV2(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) { + parsed, err := IAdminV2MetaData.GetAbi() if err != nil { return nil, err } @@ -9723,106 +10001,106 @@ func bindIAdmin(address common.Address, caller bind.ContractCaller, transactor b // sets the output to result. The result type might be a single field for simple // returns, a slice of interfaces for anonymous returns and a struct for named // returns. -func (_IAdmin *IAdminRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { - return _IAdmin.Contract.IAdminCaller.contract.Call(opts, result, method, params...) +func (_IAdminV2 *IAdminV2Raw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _IAdminV2.Contract.IAdminV2Caller.contract.Call(opts, result, method, params...) } // Transfer initiates a plain transaction to move funds to the contract, calling // its default method if one is available. -func (_IAdmin *IAdminRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { - return _IAdmin.Contract.IAdminTransactor.contract.Transfer(opts) +func (_IAdminV2 *IAdminV2Raw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _IAdminV2.Contract.IAdminV2Transactor.contract.Transfer(opts) } // Transact invokes the (paid) contract method with params as input values. -func (_IAdmin *IAdminRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { - return _IAdmin.Contract.IAdminTransactor.contract.Transact(opts, method, params...) +func (_IAdminV2 *IAdminV2Raw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _IAdminV2.Contract.IAdminV2Transactor.contract.Transact(opts, method, params...) } // Call invokes the (constant) contract method with params as input values and // sets the output to result. The result type might be a single field for simple // returns, a slice of interfaces for anonymous returns and a struct for named // returns. -func (_IAdmin *IAdminCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { - return _IAdmin.Contract.contract.Call(opts, result, method, params...) +func (_IAdminV2 *IAdminV2CallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _IAdminV2.Contract.contract.Call(opts, result, method, params...) } // Transfer initiates a plain transaction to move funds to the contract, calling // its default method if one is available. -func (_IAdmin *IAdminTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { - return _IAdmin.Contract.contract.Transfer(opts) +func (_IAdminV2 *IAdminV2TransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _IAdminV2.Contract.contract.Transfer(opts) } // Transact invokes the (paid) contract method with params as input values. -func (_IAdmin *IAdminTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { - return _IAdmin.Contract.contract.Transact(opts, method, params...) +func (_IAdminV2 *IAdminV2TransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _IAdminV2.Contract.contract.Transact(opts, method, params...) } -// SetChainGasAmount is a paid mutator transaction binding the contract method 0xb250fe6b. +// SetCancelDelay is a paid mutator transaction binding the contract method 0x1ea327c5. // -// Solidity: function setChainGasAmount(uint256 newChainGasAmount) returns() -func (_IAdmin *IAdminTransactor) SetChainGasAmount(opts *bind.TransactOpts, newChainGasAmount *big.Int) (*types.Transaction, error) { - return _IAdmin.contract.Transact(opts, "setChainGasAmount", newChainGasAmount) +// Solidity: function setCancelDelay(uint256 newCancelDelay) returns() +func (_IAdminV2 *IAdminV2Transactor) SetCancelDelay(opts *bind.TransactOpts, newCancelDelay *big.Int) (*types.Transaction, error) { + return _IAdminV2.contract.Transact(opts, "setCancelDelay", newCancelDelay) } -// SetChainGasAmount is a paid mutator transaction binding the contract method 0xb250fe6b. +// SetCancelDelay is a paid mutator transaction binding the contract method 0x1ea327c5. // -// Solidity: function setChainGasAmount(uint256 newChainGasAmount) returns() -func (_IAdmin *IAdminSession) SetChainGasAmount(newChainGasAmount *big.Int) (*types.Transaction, error) { - return _IAdmin.Contract.SetChainGasAmount(&_IAdmin.TransactOpts, newChainGasAmount) +// Solidity: function setCancelDelay(uint256 newCancelDelay) returns() +func (_IAdminV2 *IAdminV2Session) SetCancelDelay(newCancelDelay *big.Int) (*types.Transaction, error) { + return _IAdminV2.Contract.SetCancelDelay(&_IAdminV2.TransactOpts, newCancelDelay) } -// SetChainGasAmount is a paid mutator transaction binding the contract method 0xb250fe6b. +// SetCancelDelay is a paid mutator transaction binding the contract method 0x1ea327c5. // -// Solidity: function setChainGasAmount(uint256 newChainGasAmount) returns() -func (_IAdmin *IAdminTransactorSession) SetChainGasAmount(newChainGasAmount *big.Int) (*types.Transaction, error) { - return _IAdmin.Contract.SetChainGasAmount(&_IAdmin.TransactOpts, newChainGasAmount) +// Solidity: function setCancelDelay(uint256 newCancelDelay) returns() +func (_IAdminV2 *IAdminV2TransactorSession) SetCancelDelay(newCancelDelay *big.Int) (*types.Transaction, error) { + return _IAdminV2.Contract.SetCancelDelay(&_IAdminV2.TransactOpts, newCancelDelay) } // SetProtocolFeeRate is a paid mutator transaction binding the contract method 0xb13aa2d6. // // Solidity: function setProtocolFeeRate(uint256 newFeeRate) returns() -func (_IAdmin *IAdminTransactor) SetProtocolFeeRate(opts *bind.TransactOpts, newFeeRate *big.Int) (*types.Transaction, error) { - return _IAdmin.contract.Transact(opts, "setProtocolFeeRate", newFeeRate) +func (_IAdminV2 *IAdminV2Transactor) SetProtocolFeeRate(opts *bind.TransactOpts, newFeeRate *big.Int) (*types.Transaction, error) { + return _IAdminV2.contract.Transact(opts, "setProtocolFeeRate", newFeeRate) } // SetProtocolFeeRate is a paid mutator transaction binding the contract method 0xb13aa2d6. // // Solidity: function setProtocolFeeRate(uint256 newFeeRate) returns() -func (_IAdmin *IAdminSession) SetProtocolFeeRate(newFeeRate *big.Int) (*types.Transaction, error) { - return _IAdmin.Contract.SetProtocolFeeRate(&_IAdmin.TransactOpts, newFeeRate) +func (_IAdminV2 *IAdminV2Session) SetProtocolFeeRate(newFeeRate *big.Int) (*types.Transaction, error) { + return _IAdminV2.Contract.SetProtocolFeeRate(&_IAdminV2.TransactOpts, newFeeRate) } // SetProtocolFeeRate is a paid mutator transaction binding the contract method 0xb13aa2d6. // // Solidity: function setProtocolFeeRate(uint256 newFeeRate) returns() -func (_IAdmin *IAdminTransactorSession) SetProtocolFeeRate(newFeeRate *big.Int) (*types.Transaction, error) { - return _IAdmin.Contract.SetProtocolFeeRate(&_IAdmin.TransactOpts, newFeeRate) +func (_IAdminV2 *IAdminV2TransactorSession) SetProtocolFeeRate(newFeeRate *big.Int) (*types.Transaction, error) { + return _IAdminV2.Contract.SetProtocolFeeRate(&_IAdminV2.TransactOpts, newFeeRate) } // SweepProtocolFees is a paid mutator transaction binding the contract method 0x06f333f2. // // Solidity: function sweepProtocolFees(address token, address recipient) returns() -func (_IAdmin *IAdminTransactor) SweepProtocolFees(opts *bind.TransactOpts, token common.Address, recipient common.Address) (*types.Transaction, error) { - return _IAdmin.contract.Transact(opts, "sweepProtocolFees", token, recipient) +func (_IAdminV2 *IAdminV2Transactor) SweepProtocolFees(opts *bind.TransactOpts, token common.Address, recipient common.Address) (*types.Transaction, error) { + return _IAdminV2.contract.Transact(opts, "sweepProtocolFees", token, recipient) } // SweepProtocolFees is a paid mutator transaction binding the contract method 0x06f333f2. // // Solidity: function sweepProtocolFees(address token, address recipient) returns() -func (_IAdmin *IAdminSession) SweepProtocolFees(token common.Address, recipient common.Address) (*types.Transaction, error) { - return _IAdmin.Contract.SweepProtocolFees(&_IAdmin.TransactOpts, token, recipient) +func (_IAdminV2 *IAdminV2Session) SweepProtocolFees(token common.Address, recipient common.Address) (*types.Transaction, error) { + return _IAdminV2.Contract.SweepProtocolFees(&_IAdminV2.TransactOpts, token, recipient) } // SweepProtocolFees is a paid mutator transaction binding the contract method 0x06f333f2. // // Solidity: function sweepProtocolFees(address token, address recipient) returns() -func (_IAdmin *IAdminTransactorSession) SweepProtocolFees(token common.Address, recipient common.Address) (*types.Transaction, error) { - return _IAdmin.Contract.SweepProtocolFees(&_IAdmin.TransactOpts, token, recipient) +func (_IAdminV2 *IAdminV2TransactorSession) SweepProtocolFees(token common.Address, recipient common.Address) (*types.Transaction, error) { + return _IAdminV2.Contract.SweepProtocolFees(&_IAdminV2.TransactOpts, token, recipient) } -// IAdminChainGasAmountUpdatedIterator is returned from FilterChainGasAmountUpdated and is used to iterate over the raw logs and unpacked data for ChainGasAmountUpdated events raised by the IAdmin contract. -type IAdminChainGasAmountUpdatedIterator struct { - Event *IAdminChainGasAmountUpdated // Event containing the contract specifics and raw log +// IAdminV2CancelDelayUpdatedIterator is returned from FilterCancelDelayUpdated and is used to iterate over the raw logs and unpacked data for CancelDelayUpdated events raised by the IAdminV2 contract. +type IAdminV2CancelDelayUpdatedIterator struct { + Event *IAdminV2CancelDelayUpdated // Event containing the contract specifics and raw log contract *bind.BoundContract // Generic contract to use for unpacking event data event string // Event name to use for unpacking event data @@ -9836,7 +10114,7 @@ type IAdminChainGasAmountUpdatedIterator struct { // Next advances the iterator to the subsequent event, returning whether there // are any more events found. In case of a retrieval or parsing error, false is // returned and Error() can be queried for the exact failure. -func (it *IAdminChainGasAmountUpdatedIterator) Next() bool { +func (it *IAdminV2CancelDelayUpdatedIterator) Next() bool { // If the iterator failed, stop iterating if it.fail != nil { return false @@ -9845,7 +10123,7 @@ func (it *IAdminChainGasAmountUpdatedIterator) Next() bool { if it.done { select { case log := <-it.logs: - it.Event = new(IAdminChainGasAmountUpdated) + it.Event = new(IAdminV2CancelDelayUpdated) if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { it.fail = err return false @@ -9860,7 +10138,7 @@ func (it *IAdminChainGasAmountUpdatedIterator) Next() bool { // Iterator still in progress, wait for either a data or an error event select { case log := <-it.logs: - it.Event = new(IAdminChainGasAmountUpdated) + it.Event = new(IAdminV2CancelDelayUpdated) if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { it.fail = err return false @@ -9876,42 +10154,42 @@ func (it *IAdminChainGasAmountUpdatedIterator) Next() bool { } // Error returns any retrieval or parsing error occurred during filtering. -func (it *IAdminChainGasAmountUpdatedIterator) Error() error { +func (it *IAdminV2CancelDelayUpdatedIterator) Error() error { return it.fail } // Close terminates the iteration process, releasing any pending underlying // resources. -func (it *IAdminChainGasAmountUpdatedIterator) Close() error { +func (it *IAdminV2CancelDelayUpdatedIterator) Close() error { it.sub.Unsubscribe() return nil } -// IAdminChainGasAmountUpdated represents a ChainGasAmountUpdated event raised by the IAdmin contract. -type IAdminChainGasAmountUpdated struct { - OldChainGasAmount *big.Int - NewChainGasAmount *big.Int - Raw types.Log // Blockchain specific contextual infos +// IAdminV2CancelDelayUpdated represents a CancelDelayUpdated event raised by the IAdminV2 contract. +type IAdminV2CancelDelayUpdated struct { + OldCancelDelay *big.Int + NewCancelDelay *big.Int + Raw types.Log // Blockchain specific contextual infos } -// FilterChainGasAmountUpdated is a free log retrieval operation binding the contract event 0x5cf09b12f3f56b4c564d51b25b40360af6d795198adb61ae0806a36c294323fa. +// FilterCancelDelayUpdated is a free log retrieval operation binding the contract event 0x909f9078b2f6eac1d10f2aae793656c5a67511eb627ebd1d2cb1eb9c0ab94c95. // -// Solidity: event ChainGasAmountUpdated(uint256 oldChainGasAmount, uint256 newChainGasAmount) -func (_IAdmin *IAdminFilterer) FilterChainGasAmountUpdated(opts *bind.FilterOpts) (*IAdminChainGasAmountUpdatedIterator, error) { +// Solidity: event CancelDelayUpdated(uint256 oldCancelDelay, uint256 newCancelDelay) +func (_IAdminV2 *IAdminV2Filterer) FilterCancelDelayUpdated(opts *bind.FilterOpts) (*IAdminV2CancelDelayUpdatedIterator, error) { - logs, sub, err := _IAdmin.contract.FilterLogs(opts, "ChainGasAmountUpdated") + logs, sub, err := _IAdminV2.contract.FilterLogs(opts, "CancelDelayUpdated") if err != nil { return nil, err } - return &IAdminChainGasAmountUpdatedIterator{contract: _IAdmin.contract, event: "ChainGasAmountUpdated", logs: logs, sub: sub}, nil + return &IAdminV2CancelDelayUpdatedIterator{contract: _IAdminV2.contract, event: "CancelDelayUpdated", logs: logs, sub: sub}, nil } -// WatchChainGasAmountUpdated is a free log subscription operation binding the contract event 0x5cf09b12f3f56b4c564d51b25b40360af6d795198adb61ae0806a36c294323fa. +// WatchCancelDelayUpdated is a free log subscription operation binding the contract event 0x909f9078b2f6eac1d10f2aae793656c5a67511eb627ebd1d2cb1eb9c0ab94c95. // -// Solidity: event ChainGasAmountUpdated(uint256 oldChainGasAmount, uint256 newChainGasAmount) -func (_IAdmin *IAdminFilterer) WatchChainGasAmountUpdated(opts *bind.WatchOpts, sink chan<- *IAdminChainGasAmountUpdated) (event.Subscription, error) { +// Solidity: event CancelDelayUpdated(uint256 oldCancelDelay, uint256 newCancelDelay) +func (_IAdminV2 *IAdminV2Filterer) WatchCancelDelayUpdated(opts *bind.WatchOpts, sink chan<- *IAdminV2CancelDelayUpdated) (event.Subscription, error) { - logs, sub, err := _IAdmin.contract.WatchLogs(opts, "ChainGasAmountUpdated") + logs, sub, err := _IAdminV2.contract.WatchLogs(opts, "CancelDelayUpdated") if err != nil { return nil, err } @@ -9921,8 +10199,8 @@ func (_IAdmin *IAdminFilterer) WatchChainGasAmountUpdated(opts *bind.WatchOpts, select { case log := <-logs: // New log arrived, parse the event and forward to the user - event := new(IAdminChainGasAmountUpdated) - if err := _IAdmin.contract.UnpackLog(event, "ChainGasAmountUpdated", log); err != nil { + event := new(IAdminV2CancelDelayUpdated) + if err := _IAdminV2.contract.UnpackLog(event, "CancelDelayUpdated", log); err != nil { return err } event.Raw = log @@ -9943,21 +10221,21 @@ func (_IAdmin *IAdminFilterer) WatchChainGasAmountUpdated(opts *bind.WatchOpts, }), nil } -// ParseChainGasAmountUpdated is a log parse operation binding the contract event 0x5cf09b12f3f56b4c564d51b25b40360af6d795198adb61ae0806a36c294323fa. +// ParseCancelDelayUpdated is a log parse operation binding the contract event 0x909f9078b2f6eac1d10f2aae793656c5a67511eb627ebd1d2cb1eb9c0ab94c95. // -// Solidity: event ChainGasAmountUpdated(uint256 oldChainGasAmount, uint256 newChainGasAmount) -func (_IAdmin *IAdminFilterer) ParseChainGasAmountUpdated(log types.Log) (*IAdminChainGasAmountUpdated, error) { - event := new(IAdminChainGasAmountUpdated) - if err := _IAdmin.contract.UnpackLog(event, "ChainGasAmountUpdated", log); err != nil { +// Solidity: event CancelDelayUpdated(uint256 oldCancelDelay, uint256 newCancelDelay) +func (_IAdminV2 *IAdminV2Filterer) ParseCancelDelayUpdated(log types.Log) (*IAdminV2CancelDelayUpdated, error) { + event := new(IAdminV2CancelDelayUpdated) + if err := _IAdminV2.contract.UnpackLog(event, "CancelDelayUpdated", log); err != nil { return nil, err } event.Raw = log return event, nil } -// IAdminFeeRateUpdatedIterator is returned from FilterFeeRateUpdated and is used to iterate over the raw logs and unpacked data for FeeRateUpdated events raised by the IAdmin contract. -type IAdminFeeRateUpdatedIterator struct { - Event *IAdminFeeRateUpdated // Event containing the contract specifics and raw log +// IAdminV2FeeRateUpdatedIterator is returned from FilterFeeRateUpdated and is used to iterate over the raw logs and unpacked data for FeeRateUpdated events raised by the IAdminV2 contract. +type IAdminV2FeeRateUpdatedIterator struct { + Event *IAdminV2FeeRateUpdated // Event containing the contract specifics and raw log contract *bind.BoundContract // Generic contract to use for unpacking event data event string // Event name to use for unpacking event data @@ -9971,7 +10249,7 @@ type IAdminFeeRateUpdatedIterator struct { // Next advances the iterator to the subsequent event, returning whether there // are any more events found. In case of a retrieval or parsing error, false is // returned and Error() can be queried for the exact failure. -func (it *IAdminFeeRateUpdatedIterator) Next() bool { +func (it *IAdminV2FeeRateUpdatedIterator) Next() bool { // If the iterator failed, stop iterating if it.fail != nil { return false @@ -9980,7 +10258,7 @@ func (it *IAdminFeeRateUpdatedIterator) Next() bool { if it.done { select { case log := <-it.logs: - it.Event = new(IAdminFeeRateUpdated) + it.Event = new(IAdminV2FeeRateUpdated) if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { it.fail = err return false @@ -9995,7 +10273,7 @@ func (it *IAdminFeeRateUpdatedIterator) Next() bool { // Iterator still in progress, wait for either a data or an error event select { case log := <-it.logs: - it.Event = new(IAdminFeeRateUpdated) + it.Event = new(IAdminV2FeeRateUpdated) if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { it.fail = err return false @@ -10011,19 +10289,19 @@ func (it *IAdminFeeRateUpdatedIterator) Next() bool { } // Error returns any retrieval or parsing error occurred during filtering. -func (it *IAdminFeeRateUpdatedIterator) Error() error { +func (it *IAdminV2FeeRateUpdatedIterator) Error() error { return it.fail } // Close terminates the iteration process, releasing any pending underlying // resources. -func (it *IAdminFeeRateUpdatedIterator) Close() error { +func (it *IAdminV2FeeRateUpdatedIterator) Close() error { it.sub.Unsubscribe() return nil } -// IAdminFeeRateUpdated represents a FeeRateUpdated event raised by the IAdmin contract. -type IAdminFeeRateUpdated struct { +// IAdminV2FeeRateUpdated represents a FeeRateUpdated event raised by the IAdminV2 contract. +type IAdminV2FeeRateUpdated struct { OldFeeRate *big.Int NewFeeRate *big.Int Raw types.Log // Blockchain specific contextual infos @@ -10032,21 +10310,21 @@ type IAdminFeeRateUpdated struct { // FilterFeeRateUpdated is a free log retrieval operation binding the contract event 0x14914da2bf76024616fbe1859783fcd4dbddcb179b1f3a854949fbf920dcb957. // // Solidity: event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate) -func (_IAdmin *IAdminFilterer) FilterFeeRateUpdated(opts *bind.FilterOpts) (*IAdminFeeRateUpdatedIterator, error) { +func (_IAdminV2 *IAdminV2Filterer) FilterFeeRateUpdated(opts *bind.FilterOpts) (*IAdminV2FeeRateUpdatedIterator, error) { - logs, sub, err := _IAdmin.contract.FilterLogs(opts, "FeeRateUpdated") + logs, sub, err := _IAdminV2.contract.FilterLogs(opts, "FeeRateUpdated") if err != nil { return nil, err } - return &IAdminFeeRateUpdatedIterator{contract: _IAdmin.contract, event: "FeeRateUpdated", logs: logs, sub: sub}, nil + return &IAdminV2FeeRateUpdatedIterator{contract: _IAdminV2.contract, event: "FeeRateUpdated", logs: logs, sub: sub}, nil } // WatchFeeRateUpdated is a free log subscription operation binding the contract event 0x14914da2bf76024616fbe1859783fcd4dbddcb179b1f3a854949fbf920dcb957. // // Solidity: event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate) -func (_IAdmin *IAdminFilterer) WatchFeeRateUpdated(opts *bind.WatchOpts, sink chan<- *IAdminFeeRateUpdated) (event.Subscription, error) { +func (_IAdminV2 *IAdminV2Filterer) WatchFeeRateUpdated(opts *bind.WatchOpts, sink chan<- *IAdminV2FeeRateUpdated) (event.Subscription, error) { - logs, sub, err := _IAdmin.contract.WatchLogs(opts, "FeeRateUpdated") + logs, sub, err := _IAdminV2.contract.WatchLogs(opts, "FeeRateUpdated") if err != nil { return nil, err } @@ -10056,8 +10334,8 @@ func (_IAdmin *IAdminFilterer) WatchFeeRateUpdated(opts *bind.WatchOpts, sink ch select { case log := <-logs: // New log arrived, parse the event and forward to the user - event := new(IAdminFeeRateUpdated) - if err := _IAdmin.contract.UnpackLog(event, "FeeRateUpdated", log); err != nil { + event := new(IAdminV2FeeRateUpdated) + if err := _IAdminV2.contract.UnpackLog(event, "FeeRateUpdated", log); err != nil { return err } event.Raw = log @@ -10081,18 +10359,18 @@ func (_IAdmin *IAdminFilterer) WatchFeeRateUpdated(opts *bind.WatchOpts, sink ch // ParseFeeRateUpdated is a log parse operation binding the contract event 0x14914da2bf76024616fbe1859783fcd4dbddcb179b1f3a854949fbf920dcb957. // // Solidity: event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate) -func (_IAdmin *IAdminFilterer) ParseFeeRateUpdated(log types.Log) (*IAdminFeeRateUpdated, error) { - event := new(IAdminFeeRateUpdated) - if err := _IAdmin.contract.UnpackLog(event, "FeeRateUpdated", log); err != nil { +func (_IAdminV2 *IAdminV2Filterer) ParseFeeRateUpdated(log types.Log) (*IAdminV2FeeRateUpdated, error) { + event := new(IAdminV2FeeRateUpdated) + if err := _IAdminV2.contract.UnpackLog(event, "FeeRateUpdated", log); err != nil { return nil, err } event.Raw = log return event, nil } -// IAdminFeesSweptIterator is returned from FilterFeesSwept and is used to iterate over the raw logs and unpacked data for FeesSwept events raised by the IAdmin contract. -type IAdminFeesSweptIterator struct { - Event *IAdminFeesSwept // Event containing the contract specifics and raw log +// IAdminV2FeesSweptIterator is returned from FilterFeesSwept and is used to iterate over the raw logs and unpacked data for FeesSwept events raised by the IAdminV2 contract. +type IAdminV2FeesSweptIterator struct { + Event *IAdminV2FeesSwept // Event containing the contract specifics and raw log contract *bind.BoundContract // Generic contract to use for unpacking event data event string // Event name to use for unpacking event data @@ -10106,7 +10384,7 @@ type IAdminFeesSweptIterator struct { // Next advances the iterator to the subsequent event, returning whether there // are any more events found. In case of a retrieval or parsing error, false is // returned and Error() can be queried for the exact failure. -func (it *IAdminFeesSweptIterator) Next() bool { +func (it *IAdminV2FeesSweptIterator) Next() bool { // If the iterator failed, stop iterating if it.fail != nil { return false @@ -10115,7 +10393,7 @@ func (it *IAdminFeesSweptIterator) Next() bool { if it.done { select { case log := <-it.logs: - it.Event = new(IAdminFeesSwept) + it.Event = new(IAdminV2FeesSwept) if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { it.fail = err return false @@ -10130,7 +10408,7 @@ func (it *IAdminFeesSweptIterator) Next() bool { // Iterator still in progress, wait for either a data or an error event select { case log := <-it.logs: - it.Event = new(IAdminFeesSwept) + it.Event = new(IAdminV2FeesSwept) if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { it.fail = err return false @@ -10146,19 +10424,19 @@ func (it *IAdminFeesSweptIterator) Next() bool { } // Error returns any retrieval or parsing error occurred during filtering. -func (it *IAdminFeesSweptIterator) Error() error { +func (it *IAdminV2FeesSweptIterator) Error() error { return it.fail } // Close terminates the iteration process, releasing any pending underlying // resources. -func (it *IAdminFeesSweptIterator) Close() error { +func (it *IAdminV2FeesSweptIterator) Close() error { it.sub.Unsubscribe() return nil } -// IAdminFeesSwept represents a FeesSwept event raised by the IAdmin contract. -type IAdminFeesSwept struct { +// IAdminV2FeesSwept represents a FeesSwept event raised by the IAdminV2 contract. +type IAdminV2FeesSwept struct { Token common.Address Recipient common.Address Amount *big.Int @@ -10168,21 +10446,21 @@ type IAdminFeesSwept struct { // FilterFeesSwept is a free log retrieval operation binding the contract event 0x244e51bc38c1452fa8aaf487bcb4bca36c2baa3a5fbdb776b1eabd8dc6d277cd. // // Solidity: event FeesSwept(address token, address recipient, uint256 amount) -func (_IAdmin *IAdminFilterer) FilterFeesSwept(opts *bind.FilterOpts) (*IAdminFeesSweptIterator, error) { +func (_IAdminV2 *IAdminV2Filterer) FilterFeesSwept(opts *bind.FilterOpts) (*IAdminV2FeesSweptIterator, error) { - logs, sub, err := _IAdmin.contract.FilterLogs(opts, "FeesSwept") + logs, sub, err := _IAdminV2.contract.FilterLogs(opts, "FeesSwept") if err != nil { return nil, err } - return &IAdminFeesSweptIterator{contract: _IAdmin.contract, event: "FeesSwept", logs: logs, sub: sub}, nil + return &IAdminV2FeesSweptIterator{contract: _IAdminV2.contract, event: "FeesSwept", logs: logs, sub: sub}, nil } // WatchFeesSwept is a free log subscription operation binding the contract event 0x244e51bc38c1452fa8aaf487bcb4bca36c2baa3a5fbdb776b1eabd8dc6d277cd. // // Solidity: event FeesSwept(address token, address recipient, uint256 amount) -func (_IAdmin *IAdminFilterer) WatchFeesSwept(opts *bind.WatchOpts, sink chan<- *IAdminFeesSwept) (event.Subscription, error) { +func (_IAdminV2 *IAdminV2Filterer) WatchFeesSwept(opts *bind.WatchOpts, sink chan<- *IAdminV2FeesSwept) (event.Subscription, error) { - logs, sub, err := _IAdmin.contract.WatchLogs(opts, "FeesSwept") + logs, sub, err := _IAdminV2.contract.WatchLogs(opts, "FeesSwept") if err != nil { return nil, err } @@ -10192,8 +10470,8 @@ func (_IAdmin *IAdminFilterer) WatchFeesSwept(opts *bind.WatchOpts, sink chan<- select { case log := <-logs: // New log arrived, parse the event and forward to the user - event := new(IAdminFeesSwept) - if err := _IAdmin.contract.UnpackLog(event, "FeesSwept", log); err != nil { + event := new(IAdminV2FeesSwept) + if err := _IAdminV2.contract.UnpackLog(event, "FeesSwept", log); err != nil { return err } event.Raw = log @@ -10217,15 +10495,166 @@ func (_IAdmin *IAdminFilterer) WatchFeesSwept(opts *bind.WatchOpts, sink chan<- // ParseFeesSwept is a log parse operation binding the contract event 0x244e51bc38c1452fa8aaf487bcb4bca36c2baa3a5fbdb776b1eabd8dc6d277cd. // // Solidity: event FeesSwept(address token, address recipient, uint256 amount) -func (_IAdmin *IAdminFilterer) ParseFeesSwept(log types.Log) (*IAdminFeesSwept, error) { - event := new(IAdminFeesSwept) - if err := _IAdmin.contract.UnpackLog(event, "FeesSwept", log); err != nil { +func (_IAdminV2 *IAdminV2Filterer) ParseFeesSwept(log types.Log) (*IAdminV2FeesSwept, error) { + event := new(IAdminV2FeesSwept) + if err := _IAdminV2.contract.UnpackLog(event, "FeesSwept", log); err != nil { return nil, err } event.Raw = log return event, nil } +// IAdminV2ErrorsMetaData contains all meta data concerning the IAdminV2Errors contract. +var IAdminV2ErrorsMetaData = &bind.MetaData{ + ABI: "[{\"inputs\":[],\"name\":\"CancelDelayBelowMin\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"FeeRateAboveMax\",\"type\":\"error\"}]", +} + +// IAdminV2ErrorsABI is the input ABI used to generate the binding from. +// Deprecated: Use IAdminV2ErrorsMetaData.ABI instead. +var IAdminV2ErrorsABI = IAdminV2ErrorsMetaData.ABI + +// IAdminV2Errors is an auto generated Go binding around an Ethereum contract. +type IAdminV2Errors struct { + IAdminV2ErrorsCaller // Read-only binding to the contract + IAdminV2ErrorsTransactor // Write-only binding to the contract + IAdminV2ErrorsFilterer // Log filterer for contract events +} + +// IAdminV2ErrorsCaller is an auto generated read-only Go binding around an Ethereum contract. +type IAdminV2ErrorsCaller struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// IAdminV2ErrorsTransactor is an auto generated write-only Go binding around an Ethereum contract. +type IAdminV2ErrorsTransactor struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// IAdminV2ErrorsFilterer is an auto generated log filtering Go binding around an Ethereum contract events. +type IAdminV2ErrorsFilterer struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// IAdminV2ErrorsSession is an auto generated Go binding around an Ethereum contract, +// with pre-set call and transact options. +type IAdminV2ErrorsSession struct { + Contract *IAdminV2Errors // Generic contract binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// IAdminV2ErrorsCallerSession is an auto generated read-only Go binding around an Ethereum contract, +// with pre-set call options. +type IAdminV2ErrorsCallerSession struct { + Contract *IAdminV2ErrorsCaller // Generic contract caller binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session +} + +// IAdminV2ErrorsTransactorSession is an auto generated write-only Go binding around an Ethereum contract, +// with pre-set transact options. +type IAdminV2ErrorsTransactorSession struct { + Contract *IAdminV2ErrorsTransactor // Generic contract transactor binding to set the session for + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// IAdminV2ErrorsRaw is an auto generated low-level Go binding around an Ethereum contract. +type IAdminV2ErrorsRaw struct { + Contract *IAdminV2Errors // Generic contract binding to access the raw methods on +} + +// IAdminV2ErrorsCallerRaw is an auto generated low-level read-only Go binding around an Ethereum contract. +type IAdminV2ErrorsCallerRaw struct { + Contract *IAdminV2ErrorsCaller // Generic read-only contract binding to access the raw methods on +} + +// IAdminV2ErrorsTransactorRaw is an auto generated low-level write-only Go binding around an Ethereum contract. +type IAdminV2ErrorsTransactorRaw struct { + Contract *IAdminV2ErrorsTransactor // Generic write-only contract binding to access the raw methods on +} + +// NewIAdminV2Errors creates a new instance of IAdminV2Errors, bound to a specific deployed contract. +func NewIAdminV2Errors(address common.Address, backend bind.ContractBackend) (*IAdminV2Errors, error) { + contract, err := bindIAdminV2Errors(address, backend, backend, backend) + if err != nil { + return nil, err + } + return &IAdminV2Errors{IAdminV2ErrorsCaller: IAdminV2ErrorsCaller{contract: contract}, IAdminV2ErrorsTransactor: IAdminV2ErrorsTransactor{contract: contract}, IAdminV2ErrorsFilterer: IAdminV2ErrorsFilterer{contract: contract}}, nil +} + +// NewIAdminV2ErrorsCaller creates a new read-only instance of IAdminV2Errors, bound to a specific deployed contract. +func NewIAdminV2ErrorsCaller(address common.Address, caller bind.ContractCaller) (*IAdminV2ErrorsCaller, error) { + contract, err := bindIAdminV2Errors(address, caller, nil, nil) + if err != nil { + return nil, err + } + return &IAdminV2ErrorsCaller{contract: contract}, nil +} + +// NewIAdminV2ErrorsTransactor creates a new write-only instance of IAdminV2Errors, bound to a specific deployed contract. +func NewIAdminV2ErrorsTransactor(address common.Address, transactor bind.ContractTransactor) (*IAdminV2ErrorsTransactor, error) { + contract, err := bindIAdminV2Errors(address, nil, transactor, nil) + if err != nil { + return nil, err + } + return &IAdminV2ErrorsTransactor{contract: contract}, nil +} + +// NewIAdminV2ErrorsFilterer creates a new log filterer instance of IAdminV2Errors, bound to a specific deployed contract. +func NewIAdminV2ErrorsFilterer(address common.Address, filterer bind.ContractFilterer) (*IAdminV2ErrorsFilterer, error) { + contract, err := bindIAdminV2Errors(address, nil, nil, filterer) + if err != nil { + return nil, err + } + return &IAdminV2ErrorsFilterer{contract: contract}, nil +} + +// bindIAdminV2Errors binds a generic wrapper to an already deployed contract. +func bindIAdminV2Errors(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) { + parsed, err := IAdminV2ErrorsMetaData.GetAbi() + if err != nil { + return nil, err + } + return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil +} + +// Call invokes the (constant) contract method with params as input values and +// sets the output to result. The result type might be a single field for simple +// returns, a slice of interfaces for anonymous returns and a struct for named +// returns. +func (_IAdminV2Errors *IAdminV2ErrorsRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _IAdminV2Errors.Contract.IAdminV2ErrorsCaller.contract.Call(opts, result, method, params...) +} + +// Transfer initiates a plain transaction to move funds to the contract, calling +// its default method if one is available. +func (_IAdminV2Errors *IAdminV2ErrorsRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _IAdminV2Errors.Contract.IAdminV2ErrorsTransactor.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_IAdminV2Errors *IAdminV2ErrorsRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _IAdminV2Errors.Contract.IAdminV2ErrorsTransactor.contract.Transact(opts, method, params...) +} + +// Call invokes the (constant) contract method with params as input values and +// sets the output to result. The result type might be a single field for simple +// returns, a slice of interfaces for anonymous returns and a struct for named +// returns. +func (_IAdminV2Errors *IAdminV2ErrorsCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _IAdminV2Errors.Contract.contract.Call(opts, result, method, params...) +} + +// Transfer initiates a plain transaction to move funds to the contract, calling +// its default method if one is available. +func (_IAdminV2Errors *IAdminV2ErrorsTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _IAdminV2Errors.Contract.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_IAdminV2Errors *IAdminV2ErrorsTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _IAdminV2Errors.Contract.contract.Transact(opts, method, params...) +} + // IERC165MetaData contains all meta data concerning the IERC165 contract. var IERC165MetaData = &bind.MetaData{ ABI: "[{\"inputs\":[{\"internalType\":\"bytes4\",\"name\":\"interfaceId\",\"type\":\"bytes4\"}],\"name\":\"supportsInterface\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"}]", @@ -12594,7 +13023,7 @@ func (_IFastBridge *IFastBridgeFilterer) ParseBridgeRequested(log types.Log) (*I // IFastBridgeV2MetaData contains all meta data concerning the IFastBridgeV2 contract. var IFastBridgeV2MetaData = &bind.MetaData{ - ABI: "[{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"BridgeDepositClaimed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"BridgeDepositRefunded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"name\":\"BridgeProofDisputed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"transactionHash\",\"type\":\"bytes32\"}],\"name\":\"BridgeProofProvided\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"quoteId\",\"type\":\"bytes\"}],\"name\":\"BridgeQuoteDetails\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"originChainId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"chainGasAmount\",\"type\":\"uint256\"}],\"name\":\"BridgeRelayed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"destChainId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"sendChainGas\",\"type\":\"bool\"}],\"name\":\"BridgeRequested\",\"type\":\"event\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"dstChainId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"sendChainGas\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"}],\"internalType\":\"structIFastBridge.BridgeParams\",\"name\":\"params\",\"type\":\"tuple\"}],\"name\":\"bridge\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"dstChainId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"sendChainGas\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"}],\"internalType\":\"structIFastBridge.BridgeParams\",\"name\":\"params\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"quoteRelayer\",\"type\":\"address\"},{\"internalType\":\"int256\",\"name\":\"quoteExclusivitySeconds\",\"type\":\"int256\"},{\"internalType\":\"bytes\",\"name\":\"quoteId\",\"type\":\"bytes\"},{\"internalType\":\"uint256\",\"name\":\"zapNative\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"zapData\",\"type\":\"bytes\"}],\"internalType\":\"structIFastBridgeV2.BridgeParamsV2\",\"name\":\"paramsV2\",\"type\":\"tuple\"}],\"name\":\"bridge\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"}],\"name\":\"bridgeProofs\",\"outputs\":[{\"internalType\":\"uint96\",\"name\":\"timestamp\",\"type\":\"uint96\"},{\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"}],\"name\":\"bridgeRelays\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"}],\"name\":\"bridgeStatuses\",\"outputs\":[{\"internalType\":\"enumIFastBridgeV2.BridgeStatus\",\"name\":\"\",\"type\":\"uint8\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"name\":\"canClaim\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"claim\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"claim\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"}],\"name\":\"dispute\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"getBridgeTransaction\",\"outputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"originChainId\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"destChainId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"originSender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destRecipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"originFeeAmount\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"sendChainGas\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"}],\"internalType\":\"structIFastBridge.BridgeTransaction\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"getBridgeTransactionV2\",\"outputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"originChainId\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"destChainId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"originSender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destRecipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"originFeeAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"exclusivityRelayer\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"exclusivityEndTime\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"zapNative\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"zapData\",\"type\":\"bytes\"}],\"internalType\":\"structIFastBridgeV2.BridgeTransactionV2\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"destTxHash\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"name\":\"prove\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"},{\"internalType\":\"bytes32\",\"name\":\"destTxHash\",\"type\":\"bytes32\"}],\"name\":\"prove\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"refund\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"relay\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"},{\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"name\":\"relay\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"}]", + ABI: "[{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"BridgeDepositClaimed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"BridgeDepositRefunded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"name\":\"BridgeProofDisputed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"transactionHash\",\"type\":\"bytes32\"}],\"name\":\"BridgeProofProvided\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"quoteId\",\"type\":\"bytes\"}],\"name\":\"BridgeQuoteDetails\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"originChainId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"chainGasAmount\",\"type\":\"uint256\"}],\"name\":\"BridgeRelayed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"destChainId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"sendChainGas\",\"type\":\"bool\"}],\"name\":\"BridgeRequested\",\"type\":\"event\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"dstChainId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"sendChainGas\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"}],\"internalType\":\"structIFastBridge.BridgeParams\",\"name\":\"params\",\"type\":\"tuple\"}],\"name\":\"bridge\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"dstChainId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"sendChainGas\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"}],\"internalType\":\"structIFastBridge.BridgeParams\",\"name\":\"params\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"quoteRelayer\",\"type\":\"address\"},{\"internalType\":\"int256\",\"name\":\"quoteExclusivitySeconds\",\"type\":\"int256\"},{\"internalType\":\"bytes\",\"name\":\"quoteId\",\"type\":\"bytes\"},{\"internalType\":\"uint256\",\"name\":\"zapNative\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"zapData\",\"type\":\"bytes\"}],\"internalType\":\"structIFastBridgeV2.BridgeParamsV2\",\"name\":\"paramsV2\",\"type\":\"tuple\"}],\"name\":\"bridge\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"}],\"name\":\"bridgeProofs\",\"outputs\":[{\"internalType\":\"uint96\",\"name\":\"timestamp\",\"type\":\"uint96\"},{\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"}],\"name\":\"bridgeRelays\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"}],\"name\":\"bridgeStatuses\",\"outputs\":[{\"internalType\":\"enumIFastBridgeV2.BridgeStatus\",\"name\":\"\",\"type\":\"uint8\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"name\":\"canClaim\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"cancel\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"claim\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"claim\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"}],\"name\":\"dispute\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"getBridgeTransaction\",\"outputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"originChainId\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"destChainId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"originSender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destRecipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"originFeeAmount\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"sendChainGas\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"}],\"internalType\":\"structIFastBridge.BridgeTransaction\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"getBridgeTransactionV2\",\"outputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"originChainId\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"destChainId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"originSender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destRecipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"originFeeAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"exclusivityRelayer\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"exclusivityEndTime\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"zapNative\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"zapData\",\"type\":\"bytes\"}],\"internalType\":\"structIFastBridgeV2.BridgeTransactionV2\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"destTxHash\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"name\":\"prove\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"},{\"internalType\":\"bytes32\",\"name\":\"destTxHash\",\"type\":\"bytes32\"}],\"name\":\"prove\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"refund\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"relay\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"},{\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"name\":\"relay\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"}]", Sigs: map[string]string{ "45851694": "bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256))", "bfc7c607": "bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256),(address,int256,bytes,uint256,bytes))", @@ -12602,6 +13031,7 @@ var IFastBridgeV2MetaData = &bind.MetaData{ "8379a24f": "bridgeRelays(bytes32)", "051287bc": "bridgeStatuses(bytes32)", "aa9641ab": "canClaim(bytes32,address)", + "3c5beeb4": "cancel(bytes)", "c63ff8dd": "claim(bytes)", "41fcb612": "claim(bytes,address)", "add98c70": "dispute(bytes32)", @@ -13007,6 +13437,27 @@ func (_IFastBridgeV2 *IFastBridgeV2TransactorSession) Bridge0(params IFastBridge return _IFastBridgeV2.Contract.Bridge0(&_IFastBridgeV2.TransactOpts, params, paramsV2) } +// Cancel is a paid mutator transaction binding the contract method 0x3c5beeb4. +// +// Solidity: function cancel(bytes request) returns() +func (_IFastBridgeV2 *IFastBridgeV2Transactor) Cancel(opts *bind.TransactOpts, request []byte) (*types.Transaction, error) { + return _IFastBridgeV2.contract.Transact(opts, "cancel", request) +} + +// Cancel is a paid mutator transaction binding the contract method 0x3c5beeb4. +// +// Solidity: function cancel(bytes request) returns() +func (_IFastBridgeV2 *IFastBridgeV2Session) Cancel(request []byte) (*types.Transaction, error) { + return _IFastBridgeV2.Contract.Cancel(&_IFastBridgeV2.TransactOpts, request) +} + +// Cancel is a paid mutator transaction binding the contract method 0x3c5beeb4. +// +// Solidity: function cancel(bytes request) returns() +func (_IFastBridgeV2 *IFastBridgeV2TransactorSession) Cancel(request []byte) (*types.Transaction, error) { + return _IFastBridgeV2.Contract.Cancel(&_IFastBridgeV2.TransactOpts, request) +} + // Claim is a paid mutator transaction binding the contract method 0x41fcb612. // // Solidity: function claim(bytes request, address to) returns() @@ -15009,7 +15460,7 @@ func (_MulticallTarget *MulticallTargetTransactorSession) MulticallWithResults(d // SafeERC20MetaData contains all meta data concerning the SafeERC20 contract. var SafeERC20MetaData = &bind.MetaData{ ABI: "[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"currentAllowance\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"requestedDecrease\",\"type\":\"uint256\"}],\"name\":\"SafeERC20FailedDecreaseAllowance\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"}],\"name\":\"SafeERC20FailedOperation\",\"type\":\"error\"}]", - Bin: "0x60566037600b82828239805160001a607314602a57634e487b7160e01b600052600060045260246000fd5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600080fdfea26469706673582212209fa7c4bd491bc75459d04b74ec3df4cf5631b4ff0438eacdbdda406ccb78986b64736f6c63430008180033", + Bin: "0x60566037600b82828239805160001a607314602a57634e487b7160e01b600052600060045260246000fd5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600080fdfea2646970667358221220fc15551e7cd0cae1476ceeb26ea6d8e21a222c930b99686cddd49777e215b49764736f6c63430008180033", } // SafeERC20ABI is the input ABI used to generate the binding from. @@ -15178,176 +15629,3 @@ func (_SafeERC20 *SafeERC20TransactorRaw) Transfer(opts *bind.TransactOpts) (*ty func (_SafeERC20 *SafeERC20TransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { return _SafeERC20.Contract.contract.Transact(opts, method, params...) } - -// UniversalTokenLibMetaData contains all meta data concerning the UniversalTokenLib contract. -var UniversalTokenLibMetaData = &bind.MetaData{ - ABI: "[]", - Bin: "0x60566037600b82828239805160001a607314602a57634e487b7160e01b600052600060045260246000fd5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600080fdfea26469706673582212208ee6f45538d68dae1182af6006877f66fc2bb57b5fe35283c7b3ccf352c1148364736f6c63430008180033", -} - -// UniversalTokenLibABI is the input ABI used to generate the binding from. -// Deprecated: Use UniversalTokenLibMetaData.ABI instead. -var UniversalTokenLibABI = UniversalTokenLibMetaData.ABI - -// UniversalTokenLibBin is the compiled bytecode used for deploying new contracts. -// Deprecated: Use UniversalTokenLibMetaData.Bin instead. -var UniversalTokenLibBin = UniversalTokenLibMetaData.Bin - -// DeployUniversalTokenLib deploys a new Ethereum contract, binding an instance of UniversalTokenLib to it. -func DeployUniversalTokenLib(auth *bind.TransactOpts, backend bind.ContractBackend) (common.Address, *types.Transaction, *UniversalTokenLib, error) { - parsed, err := UniversalTokenLibMetaData.GetAbi() - if err != nil { - return common.Address{}, nil, nil, err - } - if parsed == nil { - return common.Address{}, nil, nil, errors.New("GetABI returned nil") - } - - address, tx, contract, err := bind.DeployContract(auth, *parsed, common.FromHex(UniversalTokenLibBin), backend) - if err != nil { - return common.Address{}, nil, nil, err - } - return address, tx, &UniversalTokenLib{UniversalTokenLibCaller: UniversalTokenLibCaller{contract: contract}, UniversalTokenLibTransactor: UniversalTokenLibTransactor{contract: contract}, UniversalTokenLibFilterer: UniversalTokenLibFilterer{contract: contract}}, nil -} - -// UniversalTokenLib is an auto generated Go binding around an Ethereum contract. -type UniversalTokenLib struct { - UniversalTokenLibCaller // Read-only binding to the contract - UniversalTokenLibTransactor // Write-only binding to the contract - UniversalTokenLibFilterer // Log filterer for contract events -} - -// UniversalTokenLibCaller is an auto generated read-only Go binding around an Ethereum contract. -type UniversalTokenLibCaller struct { - contract *bind.BoundContract // Generic contract wrapper for the low level calls -} - -// UniversalTokenLibTransactor is an auto generated write-only Go binding around an Ethereum contract. -type UniversalTokenLibTransactor struct { - contract *bind.BoundContract // Generic contract wrapper for the low level calls -} - -// UniversalTokenLibFilterer is an auto generated log filtering Go binding around an Ethereum contract events. -type UniversalTokenLibFilterer struct { - contract *bind.BoundContract // Generic contract wrapper for the low level calls -} - -// UniversalTokenLibSession is an auto generated Go binding around an Ethereum contract, -// with pre-set call and transact options. -type UniversalTokenLibSession struct { - Contract *UniversalTokenLib // Generic contract binding to set the session for - CallOpts bind.CallOpts // Call options to use throughout this session - TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session -} - -// UniversalTokenLibCallerSession is an auto generated read-only Go binding around an Ethereum contract, -// with pre-set call options. -type UniversalTokenLibCallerSession struct { - Contract *UniversalTokenLibCaller // Generic contract caller binding to set the session for - CallOpts bind.CallOpts // Call options to use throughout this session -} - -// UniversalTokenLibTransactorSession is an auto generated write-only Go binding around an Ethereum contract, -// with pre-set transact options. -type UniversalTokenLibTransactorSession struct { - Contract *UniversalTokenLibTransactor // Generic contract transactor binding to set the session for - TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session -} - -// UniversalTokenLibRaw is an auto generated low-level Go binding around an Ethereum contract. -type UniversalTokenLibRaw struct { - Contract *UniversalTokenLib // Generic contract binding to access the raw methods on -} - -// UniversalTokenLibCallerRaw is an auto generated low-level read-only Go binding around an Ethereum contract. -type UniversalTokenLibCallerRaw struct { - Contract *UniversalTokenLibCaller // Generic read-only contract binding to access the raw methods on -} - -// UniversalTokenLibTransactorRaw is an auto generated low-level write-only Go binding around an Ethereum contract. -type UniversalTokenLibTransactorRaw struct { - Contract *UniversalTokenLibTransactor // Generic write-only contract binding to access the raw methods on -} - -// NewUniversalTokenLib creates a new instance of UniversalTokenLib, bound to a specific deployed contract. -func NewUniversalTokenLib(address common.Address, backend bind.ContractBackend) (*UniversalTokenLib, error) { - contract, err := bindUniversalTokenLib(address, backend, backend, backend) - if err != nil { - return nil, err - } - return &UniversalTokenLib{UniversalTokenLibCaller: UniversalTokenLibCaller{contract: contract}, UniversalTokenLibTransactor: UniversalTokenLibTransactor{contract: contract}, UniversalTokenLibFilterer: UniversalTokenLibFilterer{contract: contract}}, nil -} - -// NewUniversalTokenLibCaller creates a new read-only instance of UniversalTokenLib, bound to a specific deployed contract. -func NewUniversalTokenLibCaller(address common.Address, caller bind.ContractCaller) (*UniversalTokenLibCaller, error) { - contract, err := bindUniversalTokenLib(address, caller, nil, nil) - if err != nil { - return nil, err - } - return &UniversalTokenLibCaller{contract: contract}, nil -} - -// NewUniversalTokenLibTransactor creates a new write-only instance of UniversalTokenLib, bound to a specific deployed contract. -func NewUniversalTokenLibTransactor(address common.Address, transactor bind.ContractTransactor) (*UniversalTokenLibTransactor, error) { - contract, err := bindUniversalTokenLib(address, nil, transactor, nil) - if err != nil { - return nil, err - } - return &UniversalTokenLibTransactor{contract: contract}, nil -} - -// NewUniversalTokenLibFilterer creates a new log filterer instance of UniversalTokenLib, bound to a specific deployed contract. -func NewUniversalTokenLibFilterer(address common.Address, filterer bind.ContractFilterer) (*UniversalTokenLibFilterer, error) { - contract, err := bindUniversalTokenLib(address, nil, nil, filterer) - if err != nil { - return nil, err - } - return &UniversalTokenLibFilterer{contract: contract}, nil -} - -// bindUniversalTokenLib binds a generic wrapper to an already deployed contract. -func bindUniversalTokenLib(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) { - parsed, err := UniversalTokenLibMetaData.GetAbi() - if err != nil { - return nil, err - } - return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil -} - -// Call invokes the (constant) contract method with params as input values and -// sets the output to result. The result type might be a single field for simple -// returns, a slice of interfaces for anonymous returns and a struct for named -// returns. -func (_UniversalTokenLib *UniversalTokenLibRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { - return _UniversalTokenLib.Contract.UniversalTokenLibCaller.contract.Call(opts, result, method, params...) -} - -// Transfer initiates a plain transaction to move funds to the contract, calling -// its default method if one is available. -func (_UniversalTokenLib *UniversalTokenLibRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { - return _UniversalTokenLib.Contract.UniversalTokenLibTransactor.contract.Transfer(opts) -} - -// Transact invokes the (paid) contract method with params as input values. -func (_UniversalTokenLib *UniversalTokenLibRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { - return _UniversalTokenLib.Contract.UniversalTokenLibTransactor.contract.Transact(opts, method, params...) -} - -// Call invokes the (constant) contract method with params as input values and -// sets the output to result. The result type might be a single field for simple -// returns, a slice of interfaces for anonymous returns and a struct for named -// returns. -func (_UniversalTokenLib *UniversalTokenLibCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { - return _UniversalTokenLib.Contract.contract.Call(opts, result, method, params...) -} - -// Transfer initiates a plain transaction to move funds to the contract, calling -// its default method if one is available. -func (_UniversalTokenLib *UniversalTokenLibTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { - return _UniversalTokenLib.Contract.contract.Transfer(opts) -} - -// Transact invokes the (paid) contract method with params as input values. -func (_UniversalTokenLib *UniversalTokenLibTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { - return _UniversalTokenLib.Contract.contract.Transact(opts, method, params...) -} diff --git a/services/rfq/contracts/fastbridgev2/fastbridgev2.contractinfo.json b/services/rfq/contracts/fastbridgev2/fastbridgev2.contractinfo.json index 0b0fe18444..5c09314059 100644 --- a/services/rfq/contracts/fastbridgev2/fastbridgev2.contractinfo.json +++ b/services/rfq/contracts/fastbridgev2/fastbridgev2.contractinfo.json @@ -1 +1 @@ -{"solidity/FastBridgeV2.sol:AccessControl":{"code":"0x","runtime-code":"0x","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.24 ^0.8.20 ^0.8.4;\n\n// contracts/interfaces/IAdmin.sol\n\ninterface IAdmin {\n // ============ Events ============\n\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n event ChainGasAmountUpdated(uint256 oldChainGasAmount, uint256 newChainGasAmount);\n\n // ============ Methods ============\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n\n function setChainGasAmount(uint256 newChainGasAmount) external;\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IFastBridgeV2Errors.sol\n\ninterface IFastBridgeV2Errors {\n error AmountIncorrect();\n error ChainIncorrect();\n error ExclusivityParamsIncorrect();\n error MsgValueIncorrect();\n error SenderIncorrect();\n error StatusIncorrect();\n error TokenNotContract();\n error ZapDataLengthAboveMax();\n error ZapNativeNotSupported();\n error ZeroAddress();\n\n error RecipientIncorrectReturnValue();\n error RecipientNoReturnValue();\n\n error DeadlineExceeded();\n error DeadlineNotExceeded();\n error DeadlineTooShort();\n error DisputePeriodNotPassed();\n error DisputePeriodPassed();\n error ExclusivityPeriodNotPassed();\n\n error TransactionRelayed();\n}\n\n// contracts/interfaces/IMulticallTarget.sol\n\n/// @notice Interface for a contract that can be called multiple times by the same caller. Inspired by MulticallV3:\n/// https://github.com/mds1/multicall/blob/master/src/Multicall3.sol\ninterface IMulticallTarget {\n struct Result {\n bool success;\n bytes returnData;\n }\n\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external;\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results);\n}\n\n// contracts/interfaces/IZapRecipient.sol\n\ninterface IZapRecipient {\n function zap(address token, uint256 amount, bytes memory zapData) external payable returns (bytes4);\n}\n\n// contracts/libs/Errors.sol\n\nerror DeadlineExceeded();\nerror DeadlineNotExceeded();\nerror DeadlineTooShort();\nerror InsufficientOutputAmount();\n\nerror MsgValueIncorrect();\nerror PoolNotFound();\nerror TokenAddressMismatch();\nerror TokenNotContract();\nerror TokenNotETH();\nerror TokensIdentical();\n\nerror ChainIncorrect();\nerror AmountIncorrect();\nerror ZeroAddress();\n\nerror DisputePeriodNotPassed();\nerror DisputePeriodPassed();\nerror SenderIncorrect();\nerror StatusIncorrect();\nerror TransactionIdIncorrect();\nerror TransactionRelayed();\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// contracts/interfaces/IFastBridgeV2.sol\n\ninterface IFastBridgeV2 is IFastBridge {\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n struct BridgeTxDetails {\n BridgeStatus status;\n uint32 destChainId;\n uint56 proofBlockTimestamp;\n address proofRelayer;\n }\n\n struct BridgeRelay {\n uint48 blockNumber;\n uint48 blockTimestamp;\n address relayer;\n }\n\n /// @notice New params introduced in the FastBridgeV2.\n /// We are passing fields from the older BridgeParams struct outside of this struct\n /// for backwards compatibility.\n /// Note: quoteRelayer and quoteExclusivitySeconds are either both zero (indicating no exclusivity)\n /// or both non-zero (indicating exclusivity for the given period).\n /// Note: zapNative \u003e 0 can NOT be used with destToken = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE (native token)\n /// @param quoteRelayer Relayer that provided the quote for the transaction\n /// @param quoteExclusivitySeconds Period of time the quote relayer is guaranteed exclusivity after user's deposit\n /// @param quoteId Unique quote identifier used for tracking the quote\n /// @param zapNative ETH value to send to the recipient (if any)\n /// @param zapData Parameters for the Zap to the destination recipient (if any)\n struct BridgeParamsV2 {\n address quoteRelayer;\n int256 quoteExclusivitySeconds;\n bytes quoteId;\n uint256 zapNative;\n bytes zapData;\n }\n\n /// @notice Updated bridge transaction struct to include parameters introduced in FastBridgeV2.\n /// Note: only `exclusivityRelayer` can fill such a transaction until `exclusivityEndTime`.\n struct BridgeTransactionV2 {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n // Note: sendChainGas flag from V1 is deprecated\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n address exclusivityRelayer;\n uint256 exclusivityEndTime;\n uint256 zapNative; // ETH value to send to the recipient (if any)\n bytes zapData; // data to pass for the Zap action (if any)\n }\n\n event BridgeQuoteDetails(bytes32 indexed transactionId, bytes quoteId);\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability\n /// to provide temporary exclusivity fill rights for the quote relayer.\n /// @param params The parameters required to bridge\n /// @param paramsV2 The parameters for exclusivity fill rights (optional, can be left empty)\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function relay(bytes memory request, address relayer) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param transactionId The transaction id associated with the encoded bridge transaction to prove\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital.\n /// @notice Can only send funds to the relayer address on the proof.\n /// @param request The encoded bridge transaction to claim on origin chain\n function claim(bytes memory request) external;\n /// @notice Checks if a transaction has been relayed\n /// @param transactionId The ID of the transaction to check\n /// @return True if the transaction has been relayed, false otherwise\n function bridgeRelays(bytes32 transactionId) external view returns (bool);\n\n /// @notice Returns the status of a bridge transaction\n /// @param transactionId The ID of the bridge transaction\n /// @return BridgeStatus Status of the bridge transaction\n function bridgeStatuses(bytes32 transactionId) external view returns (BridgeStatus);\n\n /// @notice Returns the timestamp and relayer of a bridge proof\n /// @param transactionId The ID of the bridge transaction\n /// @return timestamp The timestamp of the bridge proof\n /// @return relayer The relayer address of the bridge proof\n function bridgeProofs(bytes32 transactionId) external view returns (uint96 timestamp, address relayer);\n\n /// @notice Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\n /// @param request The bridge request to decode\n function getBridgeTransactionV2(bytes memory request) external view returns (BridgeTransactionV2 memory);\n}\n\n// contracts/utils/MulticallTarget.sol\n\n// solhint-disable avoid-low-level-calls\n/// @notice Template for a contract that supports batched calls (preserving the msg.sender).\n/// Only calls with zero msg.value could be batched.\nabstract contract MulticallTarget is IMulticallTarget {\n error MulticallTarget__UndeterminedRevert();\n\n /// @notice Perform a batched call to this contract, preserving the msg.sender.\n /// The return data from each call is discarded.\n /// @dev The method is non-payable, so only calls with `msg.value == 0` could be batched.\n /// It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag.\n /// Otherwise, the whole batch call will be reverted with the original revert reason.\n /// @param data List of abi-encoded calldata for the calls to perform.\n /// @param ignoreReverts Whether to ignore the revert errors from the calls.\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external {\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\n if (!success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(result);\n }\n }\n }\n\n /// @notice Perform a batched call to this contract, preserving the msg.sender.\n /// The return data from each call is preserved.\n /// @dev The method is non-payable, so only calls with `msg.value == 0` could be batched.\n /// It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag.\n /// Otherwise, the whole batch call will be reverted with the original revert reason.\n /// @param data List of abi-encoded calldata for the calls to perform.\n /// @param ignoreReverts Whether to ignore the revert errors from the calls.\n /// @return results List of results from the calls: `(success, returnData)`.\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results)\n {\n results = new Result[](data.length);\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (results[i].success, results[i].returnData) = address(this).delegatecall(data[i]);\n if (!results[i].success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(results[i].returnData);\n }\n }\n }\n\n /// @dev Bubbles the revert message from the underlying call.\n /// Note: preserves the same custom error or revert string, if one was used.\n /// Source: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v5.0.2/contracts/utils/Address.sol#L143-L158\n function _bubbleRevert(bytes memory returnData) internal pure {\n // Look for revert reason and bubble it up if present\n if (returnData.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n // solhint-disable-next-line no-inline-assembly\n assembly {\n let returndata_size := mload(returnData)\n revert(add(32, returnData), returndata_size)\n }\n } else {\n revert MulticallTarget__UndeterminedRevert();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// contracts/libs/BridgeTransactionV2.sol\n\n// solhint-disable no-inline-assembly\nlibrary BridgeTransactionV2Lib {\n uint16 internal constant VERSION = 2;\n\n // Offsets of the fields in the packed BridgeTransactionV2 struct\n // uint16 version [000 .. 002)\n // uint32 originChainId [002 .. 006)\n // uint32 destChainId [006 .. 010)\n // address originSender [010 .. 030)\n // address destRecipient [030 .. 050)\n // address originToken [050 .. 070)\n // address destToken [070 .. 090)\n // uint256 originAmount [090 .. 122)\n // uint256 destAmount [122 .. 154)\n // uint256 originFeeAmount [154 .. 186)\n // uint256 deadline [186 .. 218)\n // uint256 nonce [218 .. 250)\n // address exclusivityRelayer [250 .. 270)\n // uint256 exclusivityEndTime [270 .. 302)\n // uint256 zapNative [302 .. 334)\n // bytes zapData [334 .. ***)\n\n // forgefmt: disable-start\n uint256 private constant OFFSET_ORIGIN_CHAIN_ID = 2;\n uint256 private constant OFFSET_DEST_CHAIN_ID = 6;\n uint256 private constant OFFSET_ORIGIN_SENDER = 10;\n uint256 private constant OFFSET_DEST_RECIPIENT = 30;\n uint256 private constant OFFSET_ORIGIN_TOKEN = 50;\n uint256 private constant OFFSET_DEST_TOKEN = 70;\n uint256 private constant OFFSET_ORIGIN_AMOUNT = 90;\n uint256 private constant OFFSET_DEST_AMOUNT = 122;\n uint256 private constant OFFSET_ORIGIN_FEE_AMOUNT = 154;\n uint256 private constant OFFSET_DEADLINE = 186;\n uint256 private constant OFFSET_NONCE = 218;\n uint256 private constant OFFSET_EXCLUSIVITY_RELAYER = 250;\n uint256 private constant OFFSET_EXCLUSIVITY_END_TIME = 270;\n uint256 private constant OFFSET_ZAP_NATIVE = 302;\n uint256 private constant OFFSET_ZAP_DATA = 334;\n // forgefmt: disable-end\n\n error BridgeTransactionV2__InvalidEncodedTx();\n error BridgeTransactionV2__UnsupportedVersion(uint16 version);\n\n /// @notice Validates the encoded transaction to be a tightly packed encoded payload for BridgeTransactionV2.\n /// @dev Checks the minimum length and the version, use this function before decoding any of the fields.\n function validateV2(bytes calldata encodedTx) internal pure {\n // Check the minimum length: must at least include all static fields.\n if (encodedTx.length \u003c OFFSET_ZAP_DATA) revert BridgeTransactionV2__InvalidEncodedTx();\n // Once we validated the length, we can be sure that the version field is present.\n uint16 version_ = version(encodedTx);\n if (version_ != VERSION) revert BridgeTransactionV2__UnsupportedVersion(version_);\n }\n\n /// @notice Encodes the BridgeTransactionV2 struct by tightly packing the fields.\n /// @dev `abi.decode` will not work as a result of the tightly packed fields. Use `decodeV2` to decode instead.\n function encodeV2(IFastBridgeV2.BridgeTransactionV2 memory bridgeTx) internal pure returns (bytes memory) {\n // We split the encoding into two parts to avoid stack-too-deep error\n bytes memory firstPart = abi.encodePacked(\n VERSION,\n bridgeTx.originChainId,\n bridgeTx.destChainId,\n bridgeTx.originSender,\n bridgeTx.destRecipient,\n bridgeTx.originToken,\n bridgeTx.destToken,\n bridgeTx.originAmount\n );\n return abi.encodePacked(\n firstPart,\n bridgeTx.destAmount,\n bridgeTx.originFeeAmount,\n // Note: we skip the deprecated `sendChainGas` flag, which was present in BridgeTransaction V1\n bridgeTx.deadline,\n bridgeTx.nonce,\n // New V2 fields: exclusivity\n bridgeTx.exclusivityRelayer,\n bridgeTx.exclusivityEndTime,\n // New V2 fields: Zap\n bridgeTx.zapNative,\n bridgeTx.zapData\n );\n }\n\n /// @notice Decodes the BridgeTransactionV2 struct from the encoded transaction.\n /// @dev Encoded BridgeTransactionV2 struct must be tightly packed.\n /// Use `validateV2` before decoding to ensure the encoded transaction is valid.\n function decodeV2(bytes calldata encodedTx)\n internal\n pure\n returns (IFastBridgeV2.BridgeTransactionV2 memory bridgeTx)\n {\n bridgeTx.originChainId = originChainId(encodedTx);\n bridgeTx.destChainId = destChainId(encodedTx);\n bridgeTx.originSender = originSender(encodedTx);\n bridgeTx.destRecipient = destRecipient(encodedTx);\n bridgeTx.originToken = originToken(encodedTx);\n bridgeTx.destToken = destToken(encodedTx);\n bridgeTx.originAmount = originAmount(encodedTx);\n bridgeTx.destAmount = destAmount(encodedTx);\n bridgeTx.originFeeAmount = originFeeAmount(encodedTx);\n bridgeTx.deadline = deadline(encodedTx);\n bridgeTx.nonce = nonce(encodedTx);\n bridgeTx.exclusivityRelayer = exclusivityRelayer(encodedTx);\n bridgeTx.exclusivityEndTime = exclusivityEndTime(encodedTx);\n bridgeTx.zapNative = zapNative(encodedTx);\n bridgeTx.zapData = zapData(encodedTx);\n }\n\n /// @notice Extracts the version from the encoded transaction.\n function version(bytes calldata encodedTx) internal pure returns (uint16 version_) {\n // Load 32 bytes from the start and shift it 240 bits to the right to get the highest 16 bits.\n assembly {\n version_ := shr(240, calldataload(encodedTx.offset))\n }\n }\n\n /// @notice Extracts the origin chain ID from the encoded transaction.\n function originChainId(bytes calldata encodedTx) internal pure returns (uint32 originChainId_) {\n // Load 32 bytes from the offset and shift it 224 bits to the right to get the highest 32 bits.\n assembly {\n originChainId_ := shr(224, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_CHAIN_ID)))\n }\n }\n\n /// @notice Extracts the destination chain ID from the encoded transaction.\n function destChainId(bytes calldata encodedTx) internal pure returns (uint32 destChainId_) {\n // Load 32 bytes from the offset and shift it 224 bits to the right to get the highest 32 bits.\n assembly {\n destChainId_ := shr(224, calldataload(add(encodedTx.offset, OFFSET_DEST_CHAIN_ID)))\n }\n }\n\n /// @notice Extracts the origin sender from the encoded transaction.\n function originSender(bytes calldata encodedTx) internal pure returns (address originSender_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n originSender_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_SENDER)))\n }\n }\n\n /// @notice Extracts the destination recipient from the encoded transaction.\n function destRecipient(bytes calldata encodedTx) internal pure returns (address destRecipient_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n destRecipient_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_DEST_RECIPIENT)))\n }\n }\n\n /// @notice Extracts the origin token from the encoded transaction.\n function originToken(bytes calldata encodedTx) internal pure returns (address originToken_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n originToken_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_TOKEN)))\n }\n }\n\n /// @notice Extracts the destination token from the encoded transaction.\n function destToken(bytes calldata encodedTx) internal pure returns (address destToken_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n destToken_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_DEST_TOKEN)))\n }\n }\n\n /// @notice Extracts the origin amount from the encoded transaction.\n function originAmount(bytes calldata encodedTx) internal pure returns (uint256 originAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n originAmount_ := calldataload(add(encodedTx.offset, OFFSET_ORIGIN_AMOUNT))\n }\n }\n\n /// @notice Extracts the destination amount from the encoded transaction.\n function destAmount(bytes calldata encodedTx) internal pure returns (uint256 destAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n destAmount_ := calldataload(add(encodedTx.offset, OFFSET_DEST_AMOUNT))\n }\n }\n\n /// @notice Extracts the origin fee amount from the encoded transaction.\n function originFeeAmount(bytes calldata encodedTx) internal pure returns (uint256 originFeeAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n originFeeAmount_ := calldataload(add(encodedTx.offset, OFFSET_ORIGIN_FEE_AMOUNT))\n }\n }\n\n /// @notice Extracts the deadline from the encoded transaction.\n function deadline(bytes calldata encodedTx) internal pure returns (uint256 deadline_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n deadline_ := calldataload(add(encodedTx.offset, OFFSET_DEADLINE))\n }\n }\n\n /// @notice Extracts the nonce from the encoded transaction.\n function nonce(bytes calldata encodedTx) internal pure returns (uint256 nonce_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n nonce_ := calldataload(add(encodedTx.offset, OFFSET_NONCE))\n }\n }\n\n /// @notice Extracts the exclusivity relayer from the encoded transaction.\n function exclusivityRelayer(bytes calldata encodedTx) internal pure returns (address exclusivityRelayer_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n exclusivityRelayer_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_EXCLUSIVITY_RELAYER)))\n }\n }\n\n /// @notice Extracts the exclusivity end time from the encoded transaction.\n function exclusivityEndTime(bytes calldata encodedTx) internal pure returns (uint256 exclusivityEndTime_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n exclusivityEndTime_ := calldataload(add(encodedTx.offset, OFFSET_EXCLUSIVITY_END_TIME))\n }\n }\n\n /// @notice Extracts the Zap's native value from the encoded transaction.\n function zapNative(bytes calldata encodedTx) internal pure returns (uint256 zapNative_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n zapNative_ := calldataload(add(encodedTx.offset, OFFSET_ZAP_NATIVE))\n }\n }\n\n /// @notice Extracts the Zap's data from the encoded transaction.\n function zapData(bytes calldata encodedTx) internal pure returns (bytes calldata zapData_) {\n zapData_ = encodedTx[OFFSET_ZAP_DATA:];\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// contracts/libs/UniversalToken.sol\n\nlibrary UniversalTokenLib {\n using SafeERC20 for IERC20;\n\n address internal constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Transfers tokens to the given account. Reverts if transfer is not successful.\n /// @dev This might trigger fallback, if ETH is transferred to the contract.\n /// Make sure this can not lead to reentrancy attacks.\n function universalTransfer(address token, address to, uint256 value) internal {\n // Don't do anything, if need to send tokens to this address\n if (to == address(this)) return;\n // Don't do anything, if trying to send zero value\n if (value == 0) return;\n if (token == ETH_ADDRESS) {\n /// @dev Note: this can potentially lead to executing code in `to`.\n // solhint-disable-next-line avoid-low-level-calls\n (bool success,) = to.call{value: value}(\"\");\n require(success, \"ETH transfer failed\");\n } else {\n IERC20(token).safeTransfer(to, value);\n }\n }\n\n /// @notice Issues an infinite allowance to the spender, if the current allowance is insufficient\n /// to spend the given amount.\n function universalApproveInfinity(address token, address spender, uint256 amountToSpend) internal {\n // ETH Chad doesn't require your approval\n if (token == ETH_ADDRESS) return;\n // No-op if allowance is already sufficient\n uint256 allowance = IERC20(token).allowance(address(this), spender);\n if (allowance \u003e= amountToSpend) return;\n // Otherwise, reset approval to 0 and set to max allowance\n if (allowance \u003e 0) IERC20(token).safeDecreaseAllowance(spender, allowance);\n IERC20(token).safeIncreaseAllowance(spender, type(uint256).max);\n }\n\n /// @notice Returns the balance of the given token (or native ETH) for the given account.\n function universalBalanceOf(address token, address account) internal view returns (uint256) {\n if (token == ETH_ADDRESS) {\n return account.balance;\n } else {\n return IERC20(token).balanceOf(account);\n }\n }\n\n /// @dev Checks that token is a contract and not ETH_ADDRESS.\n function assertIsContract(address token) internal view {\n // Check that ETH_ADDRESS was not used (in case this is a predeploy on any of the chains)\n if (token == UniversalTokenLib.ETH_ADDRESS) revert TokenNotContract();\n // Check that token is not an EOA\n if (token.code.length == 0) revert TokenNotContract();\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/Admin.sol\n\ncontract Admin is IAdmin, AccessControlEnumerable {\n using UniversalTokenLib for address;\n\n bytes32 public constant RELAYER_ROLE = keccak256(\"RELAYER_ROLE\");\n bytes32 public constant REFUNDER_ROLE = keccak256(\"REFUNDER_ROLE\");\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n uint256 public constant FEE_BPS = 1e6;\n uint256 public constant FEE_RATE_MAX = 0.01e6; // max 1% on origin amount\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Chain gas amount to forward as rebate if requested\n uint256 public chainGasAmount;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n }\n\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n require(newFeeRate \u003c= FEE_RATE_MAX, \"newFeeRate \u003e max\");\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n token.universalTransfer(recipient, feeAmount);\n emit FeesSwept(token, recipient, feeAmount);\n }\n\n function setChainGasAmount(uint256 newChainGasAmount) external onlyRole(GOVERNOR_ROLE) {\n uint256 oldChainGasAmount = chainGasAmount;\n chainGasAmount = newChainGasAmount;\n emit ChainGasAmountUpdated(oldChainGasAmount, newChainGasAmount);\n }\n}\n\n// contracts/FastBridgeV2.sol\n\n/// @notice FastBridgeV2 is a contract for bridging tokens across chains.\ncontract FastBridgeV2 is Admin, MulticallTarget, IFastBridgeV2, IFastBridgeV2Errors {\n using BridgeTransactionV2Lib for bytes;\n using SafeERC20 for IERC20;\n\n /// @notice Address reserved for native gas token (ETH on Ethereum and most L2s, AVAX on Avalanche, etc)\n address public constant NATIVE_GAS_TOKEN = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Delay for a transaction after which it could be permisionlessly refunded\n uint256 public constant REFUND_DELAY = 7 days;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n /// @notice Maximum length of accepted zapData\n uint256 public constant MAX_ZAP_DATA_LENGTH = 2 ** 16 - 1;\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeTxDetails) public bridgeTxDetails;\n /// @notice Relay details on destination chain\n mapping(bytes32 =\u003e BridgeRelay) public bridgeRelayDetails;\n /// @notice Unique bridge nonces tracked per originSender\n mapping(address =\u003e uint256) public senderNonces;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Replaced by senderNonces\n uint256 public immutable nonce = 0;\n /// @notice the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n bridge({\n params: params,\n paramsV2: BridgeParamsV2({\n quoteRelayer: address(0),\n quoteExclusivitySeconds: 0,\n quoteId: bytes(\"\"),\n zapNative: 0,\n zapData: bytes(\"\")\n })\n });\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes calldata request) external payable {\n // relay override will validate the request\n relay({request: request, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes calldata request, bytes32 destTxHash) external {\n request.validateV2();\n prove({transactionId: keccak256(request), destTxHash: destTxHash, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridgeV2\n function claim(bytes calldata request) external {\n // claim override will validate the request\n claim({request: request, to: address(0)});\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Aggregate the read operations from the same storage slot\n address disputedRelayer = $.proofRelayer;\n BridgeStatus status = $.status;\n uint56 proofBlockTimestamp = $.proofBlockTimestamp;\n // Can only dispute a RELAYER_PROVED transaction within the dispute period\n if (status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(proofBlockTimestamp) \u003e DISPUTE_PERIOD) {\n revert DisputePeriodPassed();\n }\n // Update status to REQUESTED and delete the disputed proof details\n // Note: these are storage writes\n $.status = BridgeStatus.REQUESTED;\n $.proofRelayer = address(0);\n $.proofBlockTimestamp = 0;\n\n emit BridgeProofDisputed(transactionId, disputedRelayer);\n }\n\n /// @inheritdoc IFastBridge\n function refund(bytes calldata request) external {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Can only refund a REQUESTED transaction after its deadline expires\n if ($.status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n uint256 deadline = request.deadline();\n // Permissionless refund is only allowed after REFUND_DELAY on top of the deadline\n if (!hasRole(REFUNDER_ROLE, msg.sender)) deadline += REFUND_DELAY;\n if (block.timestamp \u003c= deadline) revert DeadlineNotExceeded();\n // Update status to REFUNDED and return the full amount (collateral + protocol fees) to the original sender.\n // The protocol fees are only updated when the transaction is claimed, so we don't need to update them here.\n // Note: this is a storage write\n $.status = BridgeStatus.REFUNDED;\n\n address to = request.originSender();\n address token = request.originToken();\n uint256 amount = request.originAmount() + request.originFeeAmount();\n // Emit the event before any external calls\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n // Complete the user refund as the last transaction action\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(to), amount);\n } else {\n IERC20(token).safeTransfer(to, amount);\n }\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // The correct relayer can only claim a RELAYER_PROVED transaction after the dispute period\n if ($.status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if ($.proofRelayer != relayer) revert SenderIncorrect();\n return _timeSince($.proofBlockTimestamp) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n /// @dev This method is added to achieve backwards compatibility with decoding requests into V1 structs:\n /// - `zapNative` is partially reported as a zero/non-zero flag\n /// - `zapData` is ignored\n /// In order to process all kinds of requests use getBridgeTransactionV2 instead.\n function getBridgeTransaction(bytes calldata request) external view returns (BridgeTransaction memory) {\n // Try decoding into V2 struct first. This will revert if V1 struct is passed\n try this.getBridgeTransactionV2(request) returns (BridgeTransactionV2 memory txV2) {\n // Note: we entirely ignore the zapData field, as it was not present in V1\n return BridgeTransaction({\n originChainId: txV2.originChainId,\n destChainId: txV2.destChainId,\n originSender: txV2.originSender,\n destRecipient: txV2.destRecipient,\n originToken: txV2.originToken,\n destToken: txV2.destToken,\n originAmount: txV2.originAmount,\n destAmount: txV2.destAmount,\n originFeeAmount: txV2.originFeeAmount,\n sendChainGas: txV2.zapNative != 0,\n deadline: txV2.deadline,\n nonce: txV2.nonce\n });\n } catch {\n // Fallback to V1 struct\n return abi.decode(request, (BridgeTransaction));\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function getBridgeTransactionV2(bytes calldata request) external pure returns (BridgeTransactionV2 memory) {\n request.validateV2();\n return BridgeTransactionV2Lib.decodeV2(request);\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) public payable {\n int256 exclusivityEndTime = 0;\n // if relayer exclusivity is not intended for this bridge, set exclusivityEndTime to static zero\n // otherwise, set exclusivity to expire at the current block ts offset by quoteExclusivitySeconds\n if (paramsV2.quoteRelayer != address(0)) {\n exclusivityEndTime = int256(block.timestamp) + paramsV2.quoteExclusivitySeconds;\n }\n _validateBridgeParams(params, paramsV2, exclusivityEndTime);\n\n // transfer tokens to bridge contract\n /// @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _takeBridgedUserAsset(params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) {\n originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n }\n\n // set status to requested\n bytes memory request = BridgeTransactionV2Lib.encodeV2(\n BridgeTransactionV2({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n deadline: params.deadline,\n nonce: senderNonces[params.sender]++, // increment nonce on every bridge\n exclusivityRelayer: paramsV2.quoteRelayer,\n // We checked exclusivityEndTime to be in range [0 .. params.deadline] above, so can safely cast\n exclusivityEndTime: uint256(exclusivityEndTime),\n zapNative: paramsV2.zapNative,\n zapData: paramsV2.zapData\n })\n );\n bytes32 transactionId = keccak256(request);\n // Note: the tx status will be updated throughout the tx lifecycle, while destChainId is set once here\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n bridgeTxDetails[transactionId].destChainId = params.dstChainId;\n\n emit BridgeRequested({\n transactionId: transactionId,\n sender: params.sender,\n request: request,\n destChainId: params.dstChainId,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n sendChainGas: paramsV2.zapNative != 0\n });\n emit BridgeQuoteDetails(transactionId, paramsV2.quoteId);\n }\n\n /// @inheritdoc IFastBridgeV2\n function relay(bytes calldata request, address relayer) public payable {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n _validateRelayParams(request, transactionId, relayer);\n // mark bridge transaction as relayed\n bridgeRelayDetails[transactionId] =\n BridgeRelay({blockNumber: uint48(block.number), blockTimestamp: uint48(block.timestamp), relayer: relayer});\n\n // transfer tokens to recipient on destination chain and trigger Zap if requested\n address to = request.destRecipient();\n address token = request.destToken();\n uint256 amount = request.destAmount();\n uint256 zapNative = request.zapNative();\n\n // Emit the event before any external calls\n emit BridgeRelayed({\n transactionId: transactionId,\n relayer: relayer,\n to: to,\n originChainId: request.originChainId(),\n originToken: request.originToken(),\n destToken: token,\n originAmount: request.originAmount(),\n destAmount: amount,\n chainGasAmount: zapNative\n });\n\n // All state changes have been done at this point, can proceed to the external calls.\n // This follows the checks-effects-interactions pattern to mitigate potential reentrancy attacks.\n if (token == NATIVE_GAS_TOKEN) {\n // For the native gas token, additional zapNative is not allowed\n if (zapNative != 0) revert ZapNativeNotSupported();\n // Check that the correct msg.value was sent\n if (msg.value != amount) revert MsgValueIncorrect();\n // Don't do a native transfer yet: we will handle it alongside the Zap below\n } else {\n // For ERC20s, we check that the correct msg.value was sent\n if (msg.value != zapNative) revert MsgValueIncorrect();\n // We need to transfer the tokens from the Relayer to the recipient first before performing an\n // optional post-transfer Zap.\n IERC20(token).safeTransferFrom(msg.sender, to, amount);\n }\n // At this point we have done:\n // - Transferred the requested amount of ERC20 tokens to the recipient.\n // At this point we have confirmed:\n // - For ERC20s: msg.value matches the requested zapNative amount.\n // - For the native gas token: msg.value matches the requested destAmount.\n // Remaining optional things to do:\n // - Forward the full msg.value to the recipient (if non-zero).\n // - Trigger a Zap (if zapData is present).\n bytes calldata zapData = request.zapData();\n if (zapData.length != 0) {\n // Zap Data is present: Zap has been requested by the recipient. Trigger it forwarding the full msg.value.\n\n // Note: if token has a fee on transfers, the recipient will have received less than `amount`.\n // This is a very niche edge case and should be handled by the recipient contract.\n _triggerZapWithChecks({recipient: to, token: token, amount: amount, zapData: zapData});\n } else if (msg.value != 0) {\n // Zap Data is missing, but msg.value was sent. This could happen in two different cases:\n // - Relay with the native gas token is happening.\n // - Relay with ERC20 is happening, with a `zapNative \u003e 0` request.\n // In both cases, we need to transfer the full msg.value to the recipient.\n Address.sendValue(payable(to), msg.value);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) public onlyRole(RELAYER_ROLE) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n\n // Can only prove a REQUESTED transaction\n if ($.status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n // Update status to RELAYER_PROVED and store the proof details\n // Note: these are storage writes\n $.status = BridgeStatus.RELAYER_PROVED;\n $.proofBlockTimestamp = uint56(block.timestamp);\n $.proofRelayer = relayer;\n\n emit BridgeProofProvided(transactionId, relayer, destTxHash);\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes calldata request, address to) public {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Aggregate the read operations from the same storage slot\n address proofRelayer = $.proofRelayer;\n BridgeStatus status = $.status;\n uint56 proofBlockTimestamp = $.proofBlockTimestamp;\n\n // Can only claim a RELAYER_PROVED transaction after the dispute period\n if (status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(proofBlockTimestamp) \u003c= DISPUTE_PERIOD) {\n revert DisputePeriodNotPassed();\n }\n\n if (to == address(0)) {\n // Anyone could claim the funds to the proven relayer on their behalf\n to = proofRelayer;\n } else if (proofRelayer != msg.sender) {\n // Only the proven relayer could specify an address to claim the funds to\n revert SenderIncorrect();\n }\n\n // Update status to RELAYER_CLAIMED and transfer the origin collateral to the specified claim address\n // Note: this is a storage write\n $.status = BridgeStatus.RELAYER_CLAIMED;\n\n address token = request.originToken();\n uint256 amount = request.originAmount();\n // Update protocol fees if origin fee amount exists\n uint256 originFeeAmount = request.originFeeAmount();\n if (originFeeAmount \u003e 0) protocolFees[token] += originFeeAmount;\n // Emit the event before any external calls\n emit BridgeDepositClaimed(transactionId, proofRelayer, to, token, amount);\n // Complete the relayer claim as the last transaction action\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(to), amount);\n } else {\n IERC20(token).safeTransfer(to, amount);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeStatuses(bytes32 transactionId) public view returns (BridgeStatus status) {\n return bridgeTxDetails[transactionId].status;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeProofs(bytes32 transactionId) public view returns (uint96 timestamp, address relayer) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n\n timestamp = $.proofBlockTimestamp;\n relayer = $.proofRelayer;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeRelays(bytes32 transactionId) public view returns (bool) {\n // has this transactionId been relayed?\n return bridgeRelayDetails[transactionId].relayer != address(0);\n }\n\n /// @notice Takes the bridged asset from the user into FastBridgeV2 custody. It will be later\n /// claimed by the relayer who completed the relay on destination chain, or refunded back to the user,\n /// should no one complete the relay.\n function _takeBridgedUserAsset(address token, uint256 amount) internal returns (uint256 amountTaken) {\n if (token == NATIVE_GAS_TOKEN) {\n // For the native gas token, we just need to check that the supplied msg.value is correct.\n // Supplied `msg.value` is already in FastBridgeV2 custody.\n if (amount != msg.value) revert MsgValueIncorrect();\n amountTaken = msg.value;\n } else {\n // For ERC20s, token is explicitly transferred from the user to FastBridgeV2.\n // We don't allow non-zero `msg.value` to avoid extra funds from being stuck in FastBridgeV2.\n if (msg.value != 0) revert MsgValueIncorrect();\n // Throw an explicit error if the provided token address is not a contract\n if (token.code.length == 0) revert TokenNotContract();\n amountTaken = IERC20(token).balanceOf(address(this));\n IERC20(token).safeTransferFrom(msg.sender, address(this), amount);\n // Use the balance difference as the amount taken in case of fee on transfer tokens.\n amountTaken = IERC20(token).balanceOf(address(this)) - amountTaken;\n }\n }\n\n /// @notice Calls the Recipient's hook function with the specified zapData and performs\n /// all the necessary checks for the returned value.\n function _triggerZapWithChecks(address recipient, address token, uint256 amount, bytes calldata zapData) internal {\n // This will bubble any revert messages from the hook function\n bytes memory returnData = Address.functionCallWithValue({\n target: recipient,\n data: abi.encodeCall(IZapRecipient.zap, (token, amount, zapData)),\n // Note: see `relay()` for reasoning behind passing msg.value\n value: msg.value\n });\n // Explicit revert if no return data at all\n if (returnData.length == 0) revert RecipientNoReturnValue();\n // Check that exactly a single return value was returned\n if (returnData.length != 32) revert RecipientIncorrectReturnValue();\n // Return value should be abi-encoded hook function selector\n if (bytes32(returnData) != bytes32(IZapRecipient.zap.selector)) {\n revert RecipientIncorrectReturnValue();\n }\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint56(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint56).max but\n /// proof.timestamp \u003c type(uint56).max via unchecked statement\n /// @param proofBlockTimestamp The bridge proof block timestamp\n /// @return delta Time delta since proof submitted\n function _timeSince(uint56 proofBlockTimestamp) internal view returns (uint256 delta) {\n unchecked {\n delta = uint56(block.timestamp) - proofBlockTimestamp;\n }\n }\n\n /// @notice Performs all the necessary checks for a bridge to happen.\n /// @dev There's no good way to refactor this function to reduce cyclomatic complexity due to\n /// the number of checks that need to be performed, so we skip the code-complexity rule here.\n // solhint-disable-next-line code-complexity\n function _validateBridgeParams(\n BridgeParams memory params,\n BridgeParamsV2 memory paramsV2,\n int256 exclusivityEndTime\n )\n internal\n view\n {\n // Check V1 (legacy) params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.sender == address(0) || params.to == address(0)) revert ZeroAddress();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n // Check V2 params\n if (paramsV2.zapData.length \u003e MAX_ZAP_DATA_LENGTH) revert ZapDataLengthAboveMax();\n if (paramsV2.zapNative != 0 \u0026\u0026 params.destToken == NATIVE_GAS_TOKEN) {\n revert ZapNativeNotSupported();\n }\n // exclusivityEndTime must be in range [0 .. params.deadline]\n if (exclusivityEndTime \u003c 0 || exclusivityEndTime \u003e int256(params.deadline)) {\n revert ExclusivityParamsIncorrect();\n }\n }\n\n /// @notice Performs all the necessary checks for a relay to happen.\n function _validateRelayParams(bytes calldata request, bytes32 transactionId, address relayer) internal view {\n if (relayer == address(0)) revert ZeroAddress();\n // Check if the transaction has already been relayed\n if (bridgeRelays(transactionId)) revert TransactionRelayed();\n if (request.destChainId() != block.chainid) revert ChainIncorrect();\n // Check the deadline for relay to happen\n if (block.timestamp \u003e request.deadline()) revert DeadlineExceeded();\n // Check the exclusivity period, if it is still ongoing\n address exclRelayer = request.exclusivityRelayer();\n if (exclRelayer != address(0) \u0026\u0026 exclRelayer != relayer \u0026\u0026 block.timestamp \u003c= request.exclusivityEndTime()) {\n revert ExclusivityPeriodNotPassed();\n }\n }\n}\n","language":"Solidity","languageVersion":"0.8.24","compilerVersion":"0.8.24","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"","srcMapRuntime":"","abiDefinition":[{"inputs":[],"name":"AccessControlBadConfirmation","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"bytes32","name":"neededRole","type":"bytes32"}],"name":"AccessControlUnauthorizedAccount","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"previousAdminRole","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"newAdminRole","type":"bytes32"}],"name":"RoleAdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleRevoked","type":"event"},{"inputs":[],"name":"DEFAULT_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleAdmin","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"grantRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"hasRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"callerConfirmation","type":"address"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"revokeRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"}],"userDoc":{"kind":"user","methods":{},"version":1},"developerDoc":{"details":"Contract module that allows children to implement role-based access control mechanisms. This is a lightweight version that doesn't allow enumerating role members except through off-chain means by accessing the contract event logs. Some applications may benefit from on-chain enumerability, for those cases see {AccessControlEnumerable}. Roles are referred to by their `bytes32` identifier. These should be exposed in the external API and be unique. The best way to achieve this is by using `public constant` hash digests: ```solidity bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\"); ``` Roles can be used to represent a set of permissions. To restrict access to a function call, use {hasRole}: ```solidity function foo() public { require(hasRole(MY_ROLE, msg.sender)); ... } ``` Roles can be granted and revoked dynamically via the {grantRole} and {revokeRole} functions. Each role has an associated admin role, and only accounts that have a role's admin role can call {grantRole} and {revokeRole}. By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means that only accounts with this role will be able to grant or revoke other roles. More complex role relationships can be created by using {_setRoleAdmin}. WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to grant and revoke this role. Extra precautions should be taken to secure accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules} to enforce additional security measures for this role.","errors":{"AccessControlBadConfirmation()":[{"details":"The caller of a function is not the expected one. NOTE: Don't confuse with {AccessControlUnauthorizedAccount}."}],"AccessControlUnauthorizedAccount(address,bytes32)":[{"details":"The `account` is missing a role."}]},"events":{"RoleAdminChanged(bytes32,bytes32,bytes32)":{"details":"Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole` `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite {RoleAdminChanged} not being emitted signaling this."},"RoleGranted(bytes32,address,address)":{"details":"Emitted when `account` is granted `role`. `sender` is the account that originated the contract call, an admin role bearer except when using {AccessControl-_setupRole}."},"RoleRevoked(bytes32,address,address)":{"details":"Emitted when `account` is revoked `role`. `sender` is the account that originated the contract call: - if using `revokeRole`, it is the admin role bearer - if using `renounceRole`, it is the role bearer (i.e. `account`)"}},"kind":"dev","methods":{"getRoleAdmin(bytes32)":{"details":"Returns the admin role that controls `role`. See {grantRole} and {revokeRole}. To change a role's admin, use {_setRoleAdmin}."},"grantRole(bytes32,address)":{"details":"Grants `role` to `account`. If `account` had not been already granted `role`, emits a {RoleGranted} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleGranted} event."},"hasRole(bytes32,address)":{"details":"Returns `true` if `account` has been granted `role`."},"renounceRole(bytes32,address)":{"details":"Revokes `role` from the calling account. Roles are often managed via {grantRole} and {revokeRole}: this function's purpose is to provide a mechanism for accounts to lose their privileges if they are compromised (such as when a trusted device is misplaced). If the calling account had been revoked `role`, emits a {RoleRevoked} event. Requirements: - the caller must be `callerConfirmation`. May emit a {RoleRevoked} event."},"revokeRole(bytes32,address)":{"details":"Revokes `role` from `account`. If `account` had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleRevoked} event."},"supportsInterface(bytes4)":{"details":"See {IERC165-supportsInterface}."}},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[],\"name\":\"AccessControlBadConfirmation\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"neededRole\",\"type\":\"bytes32\"}],\"name\":\"AccessControlUnauthorizedAccount\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"previousAdminRole\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"newAdminRole\",\"type\":\"bytes32\"}],\"name\":\"RoleAdminChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleGranted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleRevoked\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"DEFAULT_ADMIN_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"}],\"name\":\"getRoleAdmin\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"grantRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"hasRole\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"callerConfirmation\",\"type\":\"address\"}],\"name\":\"renounceRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"revokeRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes4\",\"name\":\"interfaceId\",\"type\":\"bytes4\"}],\"name\":\"supportsInterface\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"}],\"devdoc\":{\"details\":\"Contract module that allows children to implement role-based access control mechanisms. This is a lightweight version that doesn't allow enumerating role members except through off-chain means by accessing the contract event logs. Some applications may benefit from on-chain enumerability, for those cases see {AccessControlEnumerable}. Roles are referred to by their `bytes32` identifier. These should be exposed in the external API and be unique. The best way to achieve this is by using `public constant` hash digests: ```solidity bytes32 public constant MY_ROLE = keccak256(\\\"MY_ROLE\\\"); ``` Roles can be used to represent a set of permissions. To restrict access to a function call, use {hasRole}: ```solidity function foo() public { require(hasRole(MY_ROLE, msg.sender)); ... } ``` Roles can be granted and revoked dynamically via the {grantRole} and {revokeRole} functions. Each role has an associated admin role, and only accounts that have a role's admin role can call {grantRole} and {revokeRole}. By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means that only accounts with this role will be able to grant or revoke other roles. More complex role relationships can be created by using {_setRoleAdmin}. WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to grant and revoke this role. Extra precautions should be taken to secure accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules} to enforce additional security measures for this role.\",\"errors\":{\"AccessControlBadConfirmation()\":[{\"details\":\"The caller of a function is not the expected one. NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\"}],\"AccessControlUnauthorizedAccount(address,bytes32)\":[{\"details\":\"The `account` is missing a role.\"}]},\"events\":{\"RoleAdminChanged(bytes32,bytes32,bytes32)\":{\"details\":\"Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole` `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite {RoleAdminChanged} not being emitted signaling this.\"},\"RoleGranted(bytes32,address,address)\":{\"details\":\"Emitted when `account` is granted `role`. `sender` is the account that originated the contract call, an admin role bearer except when using {AccessControl-_setupRole}.\"},\"RoleRevoked(bytes32,address,address)\":{\"details\":\"Emitted when `account` is revoked `role`. `sender` is the account that originated the contract call: - if using `revokeRole`, it is the admin role bearer - if using `renounceRole`, it is the role bearer (i.e. `account`)\"}},\"kind\":\"dev\",\"methods\":{\"getRoleAdmin(bytes32)\":{\"details\":\"Returns the admin role that controls `role`. See {grantRole} and {revokeRole}. To change a role's admin, use {_setRoleAdmin}.\"},\"grantRole(bytes32,address)\":{\"details\":\"Grants `role` to `account`. If `account` had not been already granted `role`, emits a {RoleGranted} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleGranted} event.\"},\"hasRole(bytes32,address)\":{\"details\":\"Returns `true` if `account` has been granted `role`.\"},\"renounceRole(bytes32,address)\":{\"details\":\"Revokes `role` from the calling account. Roles are often managed via {grantRole} and {revokeRole}: this function's purpose is to provide a mechanism for accounts to lose their privileges if they are compromised (such as when a trusted device is misplaced). If the calling account had been revoked `role`, emits a {RoleRevoked} event. Requirements: - the caller must be `callerConfirmation`. May emit a {RoleRevoked} event.\"},\"revokeRole(bytes32,address)\":{\"details\":\"Revokes `role` from `account`. If `account` had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleRevoked} event.\"},\"supportsInterface(bytes4)\":{\"details\":\"See {IERC165-supportsInterface}.\"}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeV2.sol\":\"AccessControl\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeV2.sol\":{\"keccak256\":\"0x5069b55ca07f21bfe30b2a43c18a18318c8af9c181b2dcb07c290825efd70f34\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://273dc020a49d08e50126bbea0d7f783f79d08c702f2fdbc560618d24af308acc\",\"dweb:/ipfs/QmXJ2UVzFc8EPB74RT4CXQPC4xw66jt4T13poyfyd3UERh\"]}},\"version\":1}"},"hashes":{"DEFAULT_ADMIN_ROLE()":"a217fddf","getRoleAdmin(bytes32)":"248a9ca3","grantRole(bytes32,address)":"2f2ff15d","hasRole(bytes32,address)":"91d14854","renounceRole(bytes32,address)":"36568abe","revokeRole(bytes32,address)":"d547741f","supportsInterface(bytes4)":"01ffc9a7"}},"solidity/FastBridgeV2.sol:AccessControlEnumerable":{"code":"0x","runtime-code":"0x","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.24 ^0.8.20 ^0.8.4;\n\n// contracts/interfaces/IAdmin.sol\n\ninterface IAdmin {\n // ============ Events ============\n\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n event ChainGasAmountUpdated(uint256 oldChainGasAmount, uint256 newChainGasAmount);\n\n // ============ Methods ============\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n\n function setChainGasAmount(uint256 newChainGasAmount) external;\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IFastBridgeV2Errors.sol\n\ninterface IFastBridgeV2Errors {\n error AmountIncorrect();\n error ChainIncorrect();\n error ExclusivityParamsIncorrect();\n error MsgValueIncorrect();\n error SenderIncorrect();\n error StatusIncorrect();\n error TokenNotContract();\n error ZapDataLengthAboveMax();\n error ZapNativeNotSupported();\n error ZeroAddress();\n\n error RecipientIncorrectReturnValue();\n error RecipientNoReturnValue();\n\n error DeadlineExceeded();\n error DeadlineNotExceeded();\n error DeadlineTooShort();\n error DisputePeriodNotPassed();\n error DisputePeriodPassed();\n error ExclusivityPeriodNotPassed();\n\n error TransactionRelayed();\n}\n\n// contracts/interfaces/IMulticallTarget.sol\n\n/// @notice Interface for a contract that can be called multiple times by the same caller. Inspired by MulticallV3:\n/// https://github.com/mds1/multicall/blob/master/src/Multicall3.sol\ninterface IMulticallTarget {\n struct Result {\n bool success;\n bytes returnData;\n }\n\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external;\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results);\n}\n\n// contracts/interfaces/IZapRecipient.sol\n\ninterface IZapRecipient {\n function zap(address token, uint256 amount, bytes memory zapData) external payable returns (bytes4);\n}\n\n// contracts/libs/Errors.sol\n\nerror DeadlineExceeded();\nerror DeadlineNotExceeded();\nerror DeadlineTooShort();\nerror InsufficientOutputAmount();\n\nerror MsgValueIncorrect();\nerror PoolNotFound();\nerror TokenAddressMismatch();\nerror TokenNotContract();\nerror TokenNotETH();\nerror TokensIdentical();\n\nerror ChainIncorrect();\nerror AmountIncorrect();\nerror ZeroAddress();\n\nerror DisputePeriodNotPassed();\nerror DisputePeriodPassed();\nerror SenderIncorrect();\nerror StatusIncorrect();\nerror TransactionIdIncorrect();\nerror TransactionRelayed();\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// contracts/interfaces/IFastBridgeV2.sol\n\ninterface IFastBridgeV2 is IFastBridge {\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n struct BridgeTxDetails {\n BridgeStatus status;\n uint32 destChainId;\n uint56 proofBlockTimestamp;\n address proofRelayer;\n }\n\n struct BridgeRelay {\n uint48 blockNumber;\n uint48 blockTimestamp;\n address relayer;\n }\n\n /// @notice New params introduced in the FastBridgeV2.\n /// We are passing fields from the older BridgeParams struct outside of this struct\n /// for backwards compatibility.\n /// Note: quoteRelayer and quoteExclusivitySeconds are either both zero (indicating no exclusivity)\n /// or both non-zero (indicating exclusivity for the given period).\n /// Note: zapNative \u003e 0 can NOT be used with destToken = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE (native token)\n /// @param quoteRelayer Relayer that provided the quote for the transaction\n /// @param quoteExclusivitySeconds Period of time the quote relayer is guaranteed exclusivity after user's deposit\n /// @param quoteId Unique quote identifier used for tracking the quote\n /// @param zapNative ETH value to send to the recipient (if any)\n /// @param zapData Parameters for the Zap to the destination recipient (if any)\n struct BridgeParamsV2 {\n address quoteRelayer;\n int256 quoteExclusivitySeconds;\n bytes quoteId;\n uint256 zapNative;\n bytes zapData;\n }\n\n /// @notice Updated bridge transaction struct to include parameters introduced in FastBridgeV2.\n /// Note: only `exclusivityRelayer` can fill such a transaction until `exclusivityEndTime`.\n struct BridgeTransactionV2 {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n // Note: sendChainGas flag from V1 is deprecated\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n address exclusivityRelayer;\n uint256 exclusivityEndTime;\n uint256 zapNative; // ETH value to send to the recipient (if any)\n bytes zapData; // data to pass for the Zap action (if any)\n }\n\n event BridgeQuoteDetails(bytes32 indexed transactionId, bytes quoteId);\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability\n /// to provide temporary exclusivity fill rights for the quote relayer.\n /// @param params The parameters required to bridge\n /// @param paramsV2 The parameters for exclusivity fill rights (optional, can be left empty)\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function relay(bytes memory request, address relayer) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param transactionId The transaction id associated with the encoded bridge transaction to prove\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital.\n /// @notice Can only send funds to the relayer address on the proof.\n /// @param request The encoded bridge transaction to claim on origin chain\n function claim(bytes memory request) external;\n /// @notice Checks if a transaction has been relayed\n /// @param transactionId The ID of the transaction to check\n /// @return True if the transaction has been relayed, false otherwise\n function bridgeRelays(bytes32 transactionId) external view returns (bool);\n\n /// @notice Returns the status of a bridge transaction\n /// @param transactionId The ID of the bridge transaction\n /// @return BridgeStatus Status of the bridge transaction\n function bridgeStatuses(bytes32 transactionId) external view returns (BridgeStatus);\n\n /// @notice Returns the timestamp and relayer of a bridge proof\n /// @param transactionId The ID of the bridge transaction\n /// @return timestamp The timestamp of the bridge proof\n /// @return relayer The relayer address of the bridge proof\n function bridgeProofs(bytes32 transactionId) external view returns (uint96 timestamp, address relayer);\n\n /// @notice Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\n /// @param request The bridge request to decode\n function getBridgeTransactionV2(bytes memory request) external view returns (BridgeTransactionV2 memory);\n}\n\n// contracts/utils/MulticallTarget.sol\n\n// solhint-disable avoid-low-level-calls\n/// @notice Template for a contract that supports batched calls (preserving the msg.sender).\n/// Only calls with zero msg.value could be batched.\nabstract contract MulticallTarget is IMulticallTarget {\n error MulticallTarget__UndeterminedRevert();\n\n /// @notice Perform a batched call to this contract, preserving the msg.sender.\n /// The return data from each call is discarded.\n /// @dev The method is non-payable, so only calls with `msg.value == 0` could be batched.\n /// It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag.\n /// Otherwise, the whole batch call will be reverted with the original revert reason.\n /// @param data List of abi-encoded calldata for the calls to perform.\n /// @param ignoreReverts Whether to ignore the revert errors from the calls.\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external {\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\n if (!success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(result);\n }\n }\n }\n\n /// @notice Perform a batched call to this contract, preserving the msg.sender.\n /// The return data from each call is preserved.\n /// @dev The method is non-payable, so only calls with `msg.value == 0` could be batched.\n /// It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag.\n /// Otherwise, the whole batch call will be reverted with the original revert reason.\n /// @param data List of abi-encoded calldata for the calls to perform.\n /// @param ignoreReverts Whether to ignore the revert errors from the calls.\n /// @return results List of results from the calls: `(success, returnData)`.\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results)\n {\n results = new Result[](data.length);\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (results[i].success, results[i].returnData) = address(this).delegatecall(data[i]);\n if (!results[i].success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(results[i].returnData);\n }\n }\n }\n\n /// @dev Bubbles the revert message from the underlying call.\n /// Note: preserves the same custom error or revert string, if one was used.\n /// Source: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v5.0.2/contracts/utils/Address.sol#L143-L158\n function _bubbleRevert(bytes memory returnData) internal pure {\n // Look for revert reason and bubble it up if present\n if (returnData.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n // solhint-disable-next-line no-inline-assembly\n assembly {\n let returndata_size := mload(returnData)\n revert(add(32, returnData), returndata_size)\n }\n } else {\n revert MulticallTarget__UndeterminedRevert();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// contracts/libs/BridgeTransactionV2.sol\n\n// solhint-disable no-inline-assembly\nlibrary BridgeTransactionV2Lib {\n uint16 internal constant VERSION = 2;\n\n // Offsets of the fields in the packed BridgeTransactionV2 struct\n // uint16 version [000 .. 002)\n // uint32 originChainId [002 .. 006)\n // uint32 destChainId [006 .. 010)\n // address originSender [010 .. 030)\n // address destRecipient [030 .. 050)\n // address originToken [050 .. 070)\n // address destToken [070 .. 090)\n // uint256 originAmount [090 .. 122)\n // uint256 destAmount [122 .. 154)\n // uint256 originFeeAmount [154 .. 186)\n // uint256 deadline [186 .. 218)\n // uint256 nonce [218 .. 250)\n // address exclusivityRelayer [250 .. 270)\n // uint256 exclusivityEndTime [270 .. 302)\n // uint256 zapNative [302 .. 334)\n // bytes zapData [334 .. ***)\n\n // forgefmt: disable-start\n uint256 private constant OFFSET_ORIGIN_CHAIN_ID = 2;\n uint256 private constant OFFSET_DEST_CHAIN_ID = 6;\n uint256 private constant OFFSET_ORIGIN_SENDER = 10;\n uint256 private constant OFFSET_DEST_RECIPIENT = 30;\n uint256 private constant OFFSET_ORIGIN_TOKEN = 50;\n uint256 private constant OFFSET_DEST_TOKEN = 70;\n uint256 private constant OFFSET_ORIGIN_AMOUNT = 90;\n uint256 private constant OFFSET_DEST_AMOUNT = 122;\n uint256 private constant OFFSET_ORIGIN_FEE_AMOUNT = 154;\n uint256 private constant OFFSET_DEADLINE = 186;\n uint256 private constant OFFSET_NONCE = 218;\n uint256 private constant OFFSET_EXCLUSIVITY_RELAYER = 250;\n uint256 private constant OFFSET_EXCLUSIVITY_END_TIME = 270;\n uint256 private constant OFFSET_ZAP_NATIVE = 302;\n uint256 private constant OFFSET_ZAP_DATA = 334;\n // forgefmt: disable-end\n\n error BridgeTransactionV2__InvalidEncodedTx();\n error BridgeTransactionV2__UnsupportedVersion(uint16 version);\n\n /// @notice Validates the encoded transaction to be a tightly packed encoded payload for BridgeTransactionV2.\n /// @dev Checks the minimum length and the version, use this function before decoding any of the fields.\n function validateV2(bytes calldata encodedTx) internal pure {\n // Check the minimum length: must at least include all static fields.\n if (encodedTx.length \u003c OFFSET_ZAP_DATA) revert BridgeTransactionV2__InvalidEncodedTx();\n // Once we validated the length, we can be sure that the version field is present.\n uint16 version_ = version(encodedTx);\n if (version_ != VERSION) revert BridgeTransactionV2__UnsupportedVersion(version_);\n }\n\n /// @notice Encodes the BridgeTransactionV2 struct by tightly packing the fields.\n /// @dev `abi.decode` will not work as a result of the tightly packed fields. Use `decodeV2` to decode instead.\n function encodeV2(IFastBridgeV2.BridgeTransactionV2 memory bridgeTx) internal pure returns (bytes memory) {\n // We split the encoding into two parts to avoid stack-too-deep error\n bytes memory firstPart = abi.encodePacked(\n VERSION,\n bridgeTx.originChainId,\n bridgeTx.destChainId,\n bridgeTx.originSender,\n bridgeTx.destRecipient,\n bridgeTx.originToken,\n bridgeTx.destToken,\n bridgeTx.originAmount\n );\n return abi.encodePacked(\n firstPart,\n bridgeTx.destAmount,\n bridgeTx.originFeeAmount,\n // Note: we skip the deprecated `sendChainGas` flag, which was present in BridgeTransaction V1\n bridgeTx.deadline,\n bridgeTx.nonce,\n // New V2 fields: exclusivity\n bridgeTx.exclusivityRelayer,\n bridgeTx.exclusivityEndTime,\n // New V2 fields: Zap\n bridgeTx.zapNative,\n bridgeTx.zapData\n );\n }\n\n /// @notice Decodes the BridgeTransactionV2 struct from the encoded transaction.\n /// @dev Encoded BridgeTransactionV2 struct must be tightly packed.\n /// Use `validateV2` before decoding to ensure the encoded transaction is valid.\n function decodeV2(bytes calldata encodedTx)\n internal\n pure\n returns (IFastBridgeV2.BridgeTransactionV2 memory bridgeTx)\n {\n bridgeTx.originChainId = originChainId(encodedTx);\n bridgeTx.destChainId = destChainId(encodedTx);\n bridgeTx.originSender = originSender(encodedTx);\n bridgeTx.destRecipient = destRecipient(encodedTx);\n bridgeTx.originToken = originToken(encodedTx);\n bridgeTx.destToken = destToken(encodedTx);\n bridgeTx.originAmount = originAmount(encodedTx);\n bridgeTx.destAmount = destAmount(encodedTx);\n bridgeTx.originFeeAmount = originFeeAmount(encodedTx);\n bridgeTx.deadline = deadline(encodedTx);\n bridgeTx.nonce = nonce(encodedTx);\n bridgeTx.exclusivityRelayer = exclusivityRelayer(encodedTx);\n bridgeTx.exclusivityEndTime = exclusivityEndTime(encodedTx);\n bridgeTx.zapNative = zapNative(encodedTx);\n bridgeTx.zapData = zapData(encodedTx);\n }\n\n /// @notice Extracts the version from the encoded transaction.\n function version(bytes calldata encodedTx) internal pure returns (uint16 version_) {\n // Load 32 bytes from the start and shift it 240 bits to the right to get the highest 16 bits.\n assembly {\n version_ := shr(240, calldataload(encodedTx.offset))\n }\n }\n\n /// @notice Extracts the origin chain ID from the encoded transaction.\n function originChainId(bytes calldata encodedTx) internal pure returns (uint32 originChainId_) {\n // Load 32 bytes from the offset and shift it 224 bits to the right to get the highest 32 bits.\n assembly {\n originChainId_ := shr(224, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_CHAIN_ID)))\n }\n }\n\n /// @notice Extracts the destination chain ID from the encoded transaction.\n function destChainId(bytes calldata encodedTx) internal pure returns (uint32 destChainId_) {\n // Load 32 bytes from the offset and shift it 224 bits to the right to get the highest 32 bits.\n assembly {\n destChainId_ := shr(224, calldataload(add(encodedTx.offset, OFFSET_DEST_CHAIN_ID)))\n }\n }\n\n /// @notice Extracts the origin sender from the encoded transaction.\n function originSender(bytes calldata encodedTx) internal pure returns (address originSender_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n originSender_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_SENDER)))\n }\n }\n\n /// @notice Extracts the destination recipient from the encoded transaction.\n function destRecipient(bytes calldata encodedTx) internal pure returns (address destRecipient_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n destRecipient_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_DEST_RECIPIENT)))\n }\n }\n\n /// @notice Extracts the origin token from the encoded transaction.\n function originToken(bytes calldata encodedTx) internal pure returns (address originToken_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n originToken_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_TOKEN)))\n }\n }\n\n /// @notice Extracts the destination token from the encoded transaction.\n function destToken(bytes calldata encodedTx) internal pure returns (address destToken_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n destToken_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_DEST_TOKEN)))\n }\n }\n\n /// @notice Extracts the origin amount from the encoded transaction.\n function originAmount(bytes calldata encodedTx) internal pure returns (uint256 originAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n originAmount_ := calldataload(add(encodedTx.offset, OFFSET_ORIGIN_AMOUNT))\n }\n }\n\n /// @notice Extracts the destination amount from the encoded transaction.\n function destAmount(bytes calldata encodedTx) internal pure returns (uint256 destAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n destAmount_ := calldataload(add(encodedTx.offset, OFFSET_DEST_AMOUNT))\n }\n }\n\n /// @notice Extracts the origin fee amount from the encoded transaction.\n function originFeeAmount(bytes calldata encodedTx) internal pure returns (uint256 originFeeAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n originFeeAmount_ := calldataload(add(encodedTx.offset, OFFSET_ORIGIN_FEE_AMOUNT))\n }\n }\n\n /// @notice Extracts the deadline from the encoded transaction.\n function deadline(bytes calldata encodedTx) internal pure returns (uint256 deadline_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n deadline_ := calldataload(add(encodedTx.offset, OFFSET_DEADLINE))\n }\n }\n\n /// @notice Extracts the nonce from the encoded transaction.\n function nonce(bytes calldata encodedTx) internal pure returns (uint256 nonce_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n nonce_ := calldataload(add(encodedTx.offset, OFFSET_NONCE))\n }\n }\n\n /// @notice Extracts the exclusivity relayer from the encoded transaction.\n function exclusivityRelayer(bytes calldata encodedTx) internal pure returns (address exclusivityRelayer_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n exclusivityRelayer_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_EXCLUSIVITY_RELAYER)))\n }\n }\n\n /// @notice Extracts the exclusivity end time from the encoded transaction.\n function exclusivityEndTime(bytes calldata encodedTx) internal pure returns (uint256 exclusivityEndTime_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n exclusivityEndTime_ := calldataload(add(encodedTx.offset, OFFSET_EXCLUSIVITY_END_TIME))\n }\n }\n\n /// @notice Extracts the Zap's native value from the encoded transaction.\n function zapNative(bytes calldata encodedTx) internal pure returns (uint256 zapNative_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n zapNative_ := calldataload(add(encodedTx.offset, OFFSET_ZAP_NATIVE))\n }\n }\n\n /// @notice Extracts the Zap's data from the encoded transaction.\n function zapData(bytes calldata encodedTx) internal pure returns (bytes calldata zapData_) {\n zapData_ = encodedTx[OFFSET_ZAP_DATA:];\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// contracts/libs/UniversalToken.sol\n\nlibrary UniversalTokenLib {\n using SafeERC20 for IERC20;\n\n address internal constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Transfers tokens to the given account. Reverts if transfer is not successful.\n /// @dev This might trigger fallback, if ETH is transferred to the contract.\n /// Make sure this can not lead to reentrancy attacks.\n function universalTransfer(address token, address to, uint256 value) internal {\n // Don't do anything, if need to send tokens to this address\n if (to == address(this)) return;\n // Don't do anything, if trying to send zero value\n if (value == 0) return;\n if (token == ETH_ADDRESS) {\n /// @dev Note: this can potentially lead to executing code in `to`.\n // solhint-disable-next-line avoid-low-level-calls\n (bool success,) = to.call{value: value}(\"\");\n require(success, \"ETH transfer failed\");\n } else {\n IERC20(token).safeTransfer(to, value);\n }\n }\n\n /// @notice Issues an infinite allowance to the spender, if the current allowance is insufficient\n /// to spend the given amount.\n function universalApproveInfinity(address token, address spender, uint256 amountToSpend) internal {\n // ETH Chad doesn't require your approval\n if (token == ETH_ADDRESS) return;\n // No-op if allowance is already sufficient\n uint256 allowance = IERC20(token).allowance(address(this), spender);\n if (allowance \u003e= amountToSpend) return;\n // Otherwise, reset approval to 0 and set to max allowance\n if (allowance \u003e 0) IERC20(token).safeDecreaseAllowance(spender, allowance);\n IERC20(token).safeIncreaseAllowance(spender, type(uint256).max);\n }\n\n /// @notice Returns the balance of the given token (or native ETH) for the given account.\n function universalBalanceOf(address token, address account) internal view returns (uint256) {\n if (token == ETH_ADDRESS) {\n return account.balance;\n } else {\n return IERC20(token).balanceOf(account);\n }\n }\n\n /// @dev Checks that token is a contract and not ETH_ADDRESS.\n function assertIsContract(address token) internal view {\n // Check that ETH_ADDRESS was not used (in case this is a predeploy on any of the chains)\n if (token == UniversalTokenLib.ETH_ADDRESS) revert TokenNotContract();\n // Check that token is not an EOA\n if (token.code.length == 0) revert TokenNotContract();\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/Admin.sol\n\ncontract Admin is IAdmin, AccessControlEnumerable {\n using UniversalTokenLib for address;\n\n bytes32 public constant RELAYER_ROLE = keccak256(\"RELAYER_ROLE\");\n bytes32 public constant REFUNDER_ROLE = keccak256(\"REFUNDER_ROLE\");\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n uint256 public constant FEE_BPS = 1e6;\n uint256 public constant FEE_RATE_MAX = 0.01e6; // max 1% on origin amount\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Chain gas amount to forward as rebate if requested\n uint256 public chainGasAmount;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n }\n\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n require(newFeeRate \u003c= FEE_RATE_MAX, \"newFeeRate \u003e max\");\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n token.universalTransfer(recipient, feeAmount);\n emit FeesSwept(token, recipient, feeAmount);\n }\n\n function setChainGasAmount(uint256 newChainGasAmount) external onlyRole(GOVERNOR_ROLE) {\n uint256 oldChainGasAmount = chainGasAmount;\n chainGasAmount = newChainGasAmount;\n emit ChainGasAmountUpdated(oldChainGasAmount, newChainGasAmount);\n }\n}\n\n// contracts/FastBridgeV2.sol\n\n/// @notice FastBridgeV2 is a contract for bridging tokens across chains.\ncontract FastBridgeV2 is Admin, MulticallTarget, IFastBridgeV2, IFastBridgeV2Errors {\n using BridgeTransactionV2Lib for bytes;\n using SafeERC20 for IERC20;\n\n /// @notice Address reserved for native gas token (ETH on Ethereum and most L2s, AVAX on Avalanche, etc)\n address public constant NATIVE_GAS_TOKEN = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Delay for a transaction after which it could be permisionlessly refunded\n uint256 public constant REFUND_DELAY = 7 days;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n /// @notice Maximum length of accepted zapData\n uint256 public constant MAX_ZAP_DATA_LENGTH = 2 ** 16 - 1;\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeTxDetails) public bridgeTxDetails;\n /// @notice Relay details on destination chain\n mapping(bytes32 =\u003e BridgeRelay) public bridgeRelayDetails;\n /// @notice Unique bridge nonces tracked per originSender\n mapping(address =\u003e uint256) public senderNonces;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Replaced by senderNonces\n uint256 public immutable nonce = 0;\n /// @notice the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n bridge({\n params: params,\n paramsV2: BridgeParamsV2({\n quoteRelayer: address(0),\n quoteExclusivitySeconds: 0,\n quoteId: bytes(\"\"),\n zapNative: 0,\n zapData: bytes(\"\")\n })\n });\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes calldata request) external payable {\n // relay override will validate the request\n relay({request: request, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes calldata request, bytes32 destTxHash) external {\n request.validateV2();\n prove({transactionId: keccak256(request), destTxHash: destTxHash, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridgeV2\n function claim(bytes calldata request) external {\n // claim override will validate the request\n claim({request: request, to: address(0)});\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Aggregate the read operations from the same storage slot\n address disputedRelayer = $.proofRelayer;\n BridgeStatus status = $.status;\n uint56 proofBlockTimestamp = $.proofBlockTimestamp;\n // Can only dispute a RELAYER_PROVED transaction within the dispute period\n if (status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(proofBlockTimestamp) \u003e DISPUTE_PERIOD) {\n revert DisputePeriodPassed();\n }\n // Update status to REQUESTED and delete the disputed proof details\n // Note: these are storage writes\n $.status = BridgeStatus.REQUESTED;\n $.proofRelayer = address(0);\n $.proofBlockTimestamp = 0;\n\n emit BridgeProofDisputed(transactionId, disputedRelayer);\n }\n\n /// @inheritdoc IFastBridge\n function refund(bytes calldata request) external {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Can only refund a REQUESTED transaction after its deadline expires\n if ($.status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n uint256 deadline = request.deadline();\n // Permissionless refund is only allowed after REFUND_DELAY on top of the deadline\n if (!hasRole(REFUNDER_ROLE, msg.sender)) deadline += REFUND_DELAY;\n if (block.timestamp \u003c= deadline) revert DeadlineNotExceeded();\n // Update status to REFUNDED and return the full amount (collateral + protocol fees) to the original sender.\n // The protocol fees are only updated when the transaction is claimed, so we don't need to update them here.\n // Note: this is a storage write\n $.status = BridgeStatus.REFUNDED;\n\n address to = request.originSender();\n address token = request.originToken();\n uint256 amount = request.originAmount() + request.originFeeAmount();\n // Emit the event before any external calls\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n // Complete the user refund as the last transaction action\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(to), amount);\n } else {\n IERC20(token).safeTransfer(to, amount);\n }\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // The correct relayer can only claim a RELAYER_PROVED transaction after the dispute period\n if ($.status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if ($.proofRelayer != relayer) revert SenderIncorrect();\n return _timeSince($.proofBlockTimestamp) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n /// @dev This method is added to achieve backwards compatibility with decoding requests into V1 structs:\n /// - `zapNative` is partially reported as a zero/non-zero flag\n /// - `zapData` is ignored\n /// In order to process all kinds of requests use getBridgeTransactionV2 instead.\n function getBridgeTransaction(bytes calldata request) external view returns (BridgeTransaction memory) {\n // Try decoding into V2 struct first. This will revert if V1 struct is passed\n try this.getBridgeTransactionV2(request) returns (BridgeTransactionV2 memory txV2) {\n // Note: we entirely ignore the zapData field, as it was not present in V1\n return BridgeTransaction({\n originChainId: txV2.originChainId,\n destChainId: txV2.destChainId,\n originSender: txV2.originSender,\n destRecipient: txV2.destRecipient,\n originToken: txV2.originToken,\n destToken: txV2.destToken,\n originAmount: txV2.originAmount,\n destAmount: txV2.destAmount,\n originFeeAmount: txV2.originFeeAmount,\n sendChainGas: txV2.zapNative != 0,\n deadline: txV2.deadline,\n nonce: txV2.nonce\n });\n } catch {\n // Fallback to V1 struct\n return abi.decode(request, (BridgeTransaction));\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function getBridgeTransactionV2(bytes calldata request) external pure returns (BridgeTransactionV2 memory) {\n request.validateV2();\n return BridgeTransactionV2Lib.decodeV2(request);\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) public payable {\n int256 exclusivityEndTime = 0;\n // if relayer exclusivity is not intended for this bridge, set exclusivityEndTime to static zero\n // otherwise, set exclusivity to expire at the current block ts offset by quoteExclusivitySeconds\n if (paramsV2.quoteRelayer != address(0)) {\n exclusivityEndTime = int256(block.timestamp) + paramsV2.quoteExclusivitySeconds;\n }\n _validateBridgeParams(params, paramsV2, exclusivityEndTime);\n\n // transfer tokens to bridge contract\n /// @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _takeBridgedUserAsset(params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) {\n originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n }\n\n // set status to requested\n bytes memory request = BridgeTransactionV2Lib.encodeV2(\n BridgeTransactionV2({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n deadline: params.deadline,\n nonce: senderNonces[params.sender]++, // increment nonce on every bridge\n exclusivityRelayer: paramsV2.quoteRelayer,\n // We checked exclusivityEndTime to be in range [0 .. params.deadline] above, so can safely cast\n exclusivityEndTime: uint256(exclusivityEndTime),\n zapNative: paramsV2.zapNative,\n zapData: paramsV2.zapData\n })\n );\n bytes32 transactionId = keccak256(request);\n // Note: the tx status will be updated throughout the tx lifecycle, while destChainId is set once here\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n bridgeTxDetails[transactionId].destChainId = params.dstChainId;\n\n emit BridgeRequested({\n transactionId: transactionId,\n sender: params.sender,\n request: request,\n destChainId: params.dstChainId,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n sendChainGas: paramsV2.zapNative != 0\n });\n emit BridgeQuoteDetails(transactionId, paramsV2.quoteId);\n }\n\n /// @inheritdoc IFastBridgeV2\n function relay(bytes calldata request, address relayer) public payable {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n _validateRelayParams(request, transactionId, relayer);\n // mark bridge transaction as relayed\n bridgeRelayDetails[transactionId] =\n BridgeRelay({blockNumber: uint48(block.number), blockTimestamp: uint48(block.timestamp), relayer: relayer});\n\n // transfer tokens to recipient on destination chain and trigger Zap if requested\n address to = request.destRecipient();\n address token = request.destToken();\n uint256 amount = request.destAmount();\n uint256 zapNative = request.zapNative();\n\n // Emit the event before any external calls\n emit BridgeRelayed({\n transactionId: transactionId,\n relayer: relayer,\n to: to,\n originChainId: request.originChainId(),\n originToken: request.originToken(),\n destToken: token,\n originAmount: request.originAmount(),\n destAmount: amount,\n chainGasAmount: zapNative\n });\n\n // All state changes have been done at this point, can proceed to the external calls.\n // This follows the checks-effects-interactions pattern to mitigate potential reentrancy attacks.\n if (token == NATIVE_GAS_TOKEN) {\n // For the native gas token, additional zapNative is not allowed\n if (zapNative != 0) revert ZapNativeNotSupported();\n // Check that the correct msg.value was sent\n if (msg.value != amount) revert MsgValueIncorrect();\n // Don't do a native transfer yet: we will handle it alongside the Zap below\n } else {\n // For ERC20s, we check that the correct msg.value was sent\n if (msg.value != zapNative) revert MsgValueIncorrect();\n // We need to transfer the tokens from the Relayer to the recipient first before performing an\n // optional post-transfer Zap.\n IERC20(token).safeTransferFrom(msg.sender, to, amount);\n }\n // At this point we have done:\n // - Transferred the requested amount of ERC20 tokens to the recipient.\n // At this point we have confirmed:\n // - For ERC20s: msg.value matches the requested zapNative amount.\n // - For the native gas token: msg.value matches the requested destAmount.\n // Remaining optional things to do:\n // - Forward the full msg.value to the recipient (if non-zero).\n // - Trigger a Zap (if zapData is present).\n bytes calldata zapData = request.zapData();\n if (zapData.length != 0) {\n // Zap Data is present: Zap has been requested by the recipient. Trigger it forwarding the full msg.value.\n\n // Note: if token has a fee on transfers, the recipient will have received less than `amount`.\n // This is a very niche edge case and should be handled by the recipient contract.\n _triggerZapWithChecks({recipient: to, token: token, amount: amount, zapData: zapData});\n } else if (msg.value != 0) {\n // Zap Data is missing, but msg.value was sent. This could happen in two different cases:\n // - Relay with the native gas token is happening.\n // - Relay with ERC20 is happening, with a `zapNative \u003e 0` request.\n // In both cases, we need to transfer the full msg.value to the recipient.\n Address.sendValue(payable(to), msg.value);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) public onlyRole(RELAYER_ROLE) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n\n // Can only prove a REQUESTED transaction\n if ($.status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n // Update status to RELAYER_PROVED and store the proof details\n // Note: these are storage writes\n $.status = BridgeStatus.RELAYER_PROVED;\n $.proofBlockTimestamp = uint56(block.timestamp);\n $.proofRelayer = relayer;\n\n emit BridgeProofProvided(transactionId, relayer, destTxHash);\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes calldata request, address to) public {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Aggregate the read operations from the same storage slot\n address proofRelayer = $.proofRelayer;\n BridgeStatus status = $.status;\n uint56 proofBlockTimestamp = $.proofBlockTimestamp;\n\n // Can only claim a RELAYER_PROVED transaction after the dispute period\n if (status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(proofBlockTimestamp) \u003c= DISPUTE_PERIOD) {\n revert DisputePeriodNotPassed();\n }\n\n if (to == address(0)) {\n // Anyone could claim the funds to the proven relayer on their behalf\n to = proofRelayer;\n } else if (proofRelayer != msg.sender) {\n // Only the proven relayer could specify an address to claim the funds to\n revert SenderIncorrect();\n }\n\n // Update status to RELAYER_CLAIMED and transfer the origin collateral to the specified claim address\n // Note: this is a storage write\n $.status = BridgeStatus.RELAYER_CLAIMED;\n\n address token = request.originToken();\n uint256 amount = request.originAmount();\n // Update protocol fees if origin fee amount exists\n uint256 originFeeAmount = request.originFeeAmount();\n if (originFeeAmount \u003e 0) protocolFees[token] += originFeeAmount;\n // Emit the event before any external calls\n emit BridgeDepositClaimed(transactionId, proofRelayer, to, token, amount);\n // Complete the relayer claim as the last transaction action\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(to), amount);\n } else {\n IERC20(token).safeTransfer(to, amount);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeStatuses(bytes32 transactionId) public view returns (BridgeStatus status) {\n return bridgeTxDetails[transactionId].status;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeProofs(bytes32 transactionId) public view returns (uint96 timestamp, address relayer) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n\n timestamp = $.proofBlockTimestamp;\n relayer = $.proofRelayer;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeRelays(bytes32 transactionId) public view returns (bool) {\n // has this transactionId been relayed?\n return bridgeRelayDetails[transactionId].relayer != address(0);\n }\n\n /// @notice Takes the bridged asset from the user into FastBridgeV2 custody. It will be later\n /// claimed by the relayer who completed the relay on destination chain, or refunded back to the user,\n /// should no one complete the relay.\n function _takeBridgedUserAsset(address token, uint256 amount) internal returns (uint256 amountTaken) {\n if (token == NATIVE_GAS_TOKEN) {\n // For the native gas token, we just need to check that the supplied msg.value is correct.\n // Supplied `msg.value` is already in FastBridgeV2 custody.\n if (amount != msg.value) revert MsgValueIncorrect();\n amountTaken = msg.value;\n } else {\n // For ERC20s, token is explicitly transferred from the user to FastBridgeV2.\n // We don't allow non-zero `msg.value` to avoid extra funds from being stuck in FastBridgeV2.\n if (msg.value != 0) revert MsgValueIncorrect();\n // Throw an explicit error if the provided token address is not a contract\n if (token.code.length == 0) revert TokenNotContract();\n amountTaken = IERC20(token).balanceOf(address(this));\n IERC20(token).safeTransferFrom(msg.sender, address(this), amount);\n // Use the balance difference as the amount taken in case of fee on transfer tokens.\n amountTaken = IERC20(token).balanceOf(address(this)) - amountTaken;\n }\n }\n\n /// @notice Calls the Recipient's hook function with the specified zapData and performs\n /// all the necessary checks for the returned value.\n function _triggerZapWithChecks(address recipient, address token, uint256 amount, bytes calldata zapData) internal {\n // This will bubble any revert messages from the hook function\n bytes memory returnData = Address.functionCallWithValue({\n target: recipient,\n data: abi.encodeCall(IZapRecipient.zap, (token, amount, zapData)),\n // Note: see `relay()` for reasoning behind passing msg.value\n value: msg.value\n });\n // Explicit revert if no return data at all\n if (returnData.length == 0) revert RecipientNoReturnValue();\n // Check that exactly a single return value was returned\n if (returnData.length != 32) revert RecipientIncorrectReturnValue();\n // Return value should be abi-encoded hook function selector\n if (bytes32(returnData) != bytes32(IZapRecipient.zap.selector)) {\n revert RecipientIncorrectReturnValue();\n }\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint56(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint56).max but\n /// proof.timestamp \u003c type(uint56).max via unchecked statement\n /// @param proofBlockTimestamp The bridge proof block timestamp\n /// @return delta Time delta since proof submitted\n function _timeSince(uint56 proofBlockTimestamp) internal view returns (uint256 delta) {\n unchecked {\n delta = uint56(block.timestamp) - proofBlockTimestamp;\n }\n }\n\n /// @notice Performs all the necessary checks for a bridge to happen.\n /// @dev There's no good way to refactor this function to reduce cyclomatic complexity due to\n /// the number of checks that need to be performed, so we skip the code-complexity rule here.\n // solhint-disable-next-line code-complexity\n function _validateBridgeParams(\n BridgeParams memory params,\n BridgeParamsV2 memory paramsV2,\n int256 exclusivityEndTime\n )\n internal\n view\n {\n // Check V1 (legacy) params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.sender == address(0) || params.to == address(0)) revert ZeroAddress();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n // Check V2 params\n if (paramsV2.zapData.length \u003e MAX_ZAP_DATA_LENGTH) revert ZapDataLengthAboveMax();\n if (paramsV2.zapNative != 0 \u0026\u0026 params.destToken == NATIVE_GAS_TOKEN) {\n revert ZapNativeNotSupported();\n }\n // exclusivityEndTime must be in range [0 .. params.deadline]\n if (exclusivityEndTime \u003c 0 || exclusivityEndTime \u003e int256(params.deadline)) {\n revert ExclusivityParamsIncorrect();\n }\n }\n\n /// @notice Performs all the necessary checks for a relay to happen.\n function _validateRelayParams(bytes calldata request, bytes32 transactionId, address relayer) internal view {\n if (relayer == address(0)) revert ZeroAddress();\n // Check if the transaction has already been relayed\n if (bridgeRelays(transactionId)) revert TransactionRelayed();\n if (request.destChainId() != block.chainid) revert ChainIncorrect();\n // Check the deadline for relay to happen\n if (block.timestamp \u003e request.deadline()) revert DeadlineExceeded();\n // Check the exclusivity period, if it is still ongoing\n address exclRelayer = request.exclusivityRelayer();\n if (exclRelayer != address(0) \u0026\u0026 exclRelayer != relayer \u0026\u0026 block.timestamp \u003c= request.exclusivityEndTime()) {\n revert ExclusivityPeriodNotPassed();\n }\n }\n}\n","language":"Solidity","languageVersion":"0.8.24","compilerVersion":"0.8.24","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"","srcMapRuntime":"","abiDefinition":[{"inputs":[],"name":"AccessControlBadConfirmation","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"bytes32","name":"neededRole","type":"bytes32"}],"name":"AccessControlUnauthorizedAccount","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"previousAdminRole","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"newAdminRole","type":"bytes32"}],"name":"RoleAdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleRevoked","type":"event"},{"inputs":[],"name":"DEFAULT_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleAdmin","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"uint256","name":"index","type":"uint256"}],"name":"getRoleMember","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleMemberCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"grantRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"hasRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"callerConfirmation","type":"address"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"revokeRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"}],"userDoc":{"kind":"user","methods":{},"version":1},"developerDoc":{"details":"Extension of {AccessControl} that allows enumerating the members of each role.","errors":{"AccessControlBadConfirmation()":[{"details":"The caller of a function is not the expected one. NOTE: Don't confuse with {AccessControlUnauthorizedAccount}."}],"AccessControlUnauthorizedAccount(address,bytes32)":[{"details":"The `account` is missing a role."}]},"events":{"RoleAdminChanged(bytes32,bytes32,bytes32)":{"details":"Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole` `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite {RoleAdminChanged} not being emitted signaling this."},"RoleGranted(bytes32,address,address)":{"details":"Emitted when `account` is granted `role`. `sender` is the account that originated the contract call, an admin role bearer except when using {AccessControl-_setupRole}."},"RoleRevoked(bytes32,address,address)":{"details":"Emitted when `account` is revoked `role`. `sender` is the account that originated the contract call: - if using `revokeRole`, it is the admin role bearer - if using `renounceRole`, it is the role bearer (i.e. `account`)"}},"kind":"dev","methods":{"getRoleAdmin(bytes32)":{"details":"Returns the admin role that controls `role`. See {grantRole} and {revokeRole}. To change a role's admin, use {_setRoleAdmin}."},"getRoleMember(bytes32,uint256)":{"details":"Returns one of the accounts that have `role`. `index` must be a value between 0 and {getRoleMemberCount}, non-inclusive. Role bearers are not sorted in any particular way, and their ordering may change at any point. WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure you perform all queries on the same block. See the following https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post] for more information."},"getRoleMemberCount(bytes32)":{"details":"Returns the number of accounts that have `role`. Can be used together with {getRoleMember} to enumerate all bearers of a role."},"grantRole(bytes32,address)":{"details":"Grants `role` to `account`. If `account` had not been already granted `role`, emits a {RoleGranted} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleGranted} event."},"hasRole(bytes32,address)":{"details":"Returns `true` if `account` has been granted `role`."},"renounceRole(bytes32,address)":{"details":"Revokes `role` from the calling account. Roles are often managed via {grantRole} and {revokeRole}: this function's purpose is to provide a mechanism for accounts to lose their privileges if they are compromised (such as when a trusted device is misplaced). If the calling account had been revoked `role`, emits a {RoleRevoked} event. Requirements: - the caller must be `callerConfirmation`. May emit a {RoleRevoked} event."},"revokeRole(bytes32,address)":{"details":"Revokes `role` from `account`. If `account` had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleRevoked} event."},"supportsInterface(bytes4)":{"details":"See {IERC165-supportsInterface}."}},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[],\"name\":\"AccessControlBadConfirmation\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"neededRole\",\"type\":\"bytes32\"}],\"name\":\"AccessControlUnauthorizedAccount\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"previousAdminRole\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"newAdminRole\",\"type\":\"bytes32\"}],\"name\":\"RoleAdminChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleGranted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleRevoked\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"DEFAULT_ADMIN_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"}],\"name\":\"getRoleAdmin\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"index\",\"type\":\"uint256\"}],\"name\":\"getRoleMember\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"}],\"name\":\"getRoleMemberCount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"grantRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"hasRole\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"callerConfirmation\",\"type\":\"address\"}],\"name\":\"renounceRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"revokeRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes4\",\"name\":\"interfaceId\",\"type\":\"bytes4\"}],\"name\":\"supportsInterface\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"}],\"devdoc\":{\"details\":\"Extension of {AccessControl} that allows enumerating the members of each role.\",\"errors\":{\"AccessControlBadConfirmation()\":[{\"details\":\"The caller of a function is not the expected one. NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\"}],\"AccessControlUnauthorizedAccount(address,bytes32)\":[{\"details\":\"The `account` is missing a role.\"}]},\"events\":{\"RoleAdminChanged(bytes32,bytes32,bytes32)\":{\"details\":\"Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole` `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite {RoleAdminChanged} not being emitted signaling this.\"},\"RoleGranted(bytes32,address,address)\":{\"details\":\"Emitted when `account` is granted `role`. `sender` is the account that originated the contract call, an admin role bearer except when using {AccessControl-_setupRole}.\"},\"RoleRevoked(bytes32,address,address)\":{\"details\":\"Emitted when `account` is revoked `role`. `sender` is the account that originated the contract call: - if using `revokeRole`, it is the admin role bearer - if using `renounceRole`, it is the role bearer (i.e. `account`)\"}},\"kind\":\"dev\",\"methods\":{\"getRoleAdmin(bytes32)\":{\"details\":\"Returns the admin role that controls `role`. See {grantRole} and {revokeRole}. To change a role's admin, use {_setRoleAdmin}.\"},\"getRoleMember(bytes32,uint256)\":{\"details\":\"Returns one of the accounts that have `role`. `index` must be a value between 0 and {getRoleMemberCount}, non-inclusive. Role bearers are not sorted in any particular way, and their ordering may change at any point. WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure you perform all queries on the same block. See the following https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post] for more information.\"},\"getRoleMemberCount(bytes32)\":{\"details\":\"Returns the number of accounts that have `role`. Can be used together with {getRoleMember} to enumerate all bearers of a role.\"},\"grantRole(bytes32,address)\":{\"details\":\"Grants `role` to `account`. If `account` had not been already granted `role`, emits a {RoleGranted} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleGranted} event.\"},\"hasRole(bytes32,address)\":{\"details\":\"Returns `true` if `account` has been granted `role`.\"},\"renounceRole(bytes32,address)\":{\"details\":\"Revokes `role` from the calling account. Roles are often managed via {grantRole} and {revokeRole}: this function's purpose is to provide a mechanism for accounts to lose their privileges if they are compromised (such as when a trusted device is misplaced). If the calling account had been revoked `role`, emits a {RoleRevoked} event. Requirements: - the caller must be `callerConfirmation`. May emit a {RoleRevoked} event.\"},\"revokeRole(bytes32,address)\":{\"details\":\"Revokes `role` from `account`. If `account` had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleRevoked} event.\"},\"supportsInterface(bytes4)\":{\"details\":\"See {IERC165-supportsInterface}.\"}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeV2.sol\":\"AccessControlEnumerable\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeV2.sol\":{\"keccak256\":\"0x5069b55ca07f21bfe30b2a43c18a18318c8af9c181b2dcb07c290825efd70f34\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://273dc020a49d08e50126bbea0d7f783f79d08c702f2fdbc560618d24af308acc\",\"dweb:/ipfs/QmXJ2UVzFc8EPB74RT4CXQPC4xw66jt4T13poyfyd3UERh\"]}},\"version\":1}"},"hashes":{"DEFAULT_ADMIN_ROLE()":"a217fddf","getRoleAdmin(bytes32)":"248a9ca3","getRoleMember(bytes32,uint256)":"9010d07c","getRoleMemberCount(bytes32)":"ca15c873","grantRole(bytes32,address)":"2f2ff15d","hasRole(bytes32,address)":"91d14854","renounceRole(bytes32,address)":"36568abe","revokeRole(bytes32,address)":"d547741f","supportsInterface(bytes4)":"01ffc9a7"}},"solidity/FastBridgeV2.sol:Address":{"code":"0x60566037600b82828239805160001a607314602a57634e487b7160e01b600052600060045260246000fd5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600080fdfea2646970667358221220bf1b9d7d74d58f093eea1b088fdbcad7f67374661fae1ab5815d7a31130f2fb864736f6c63430008180033","runtime-code":"0x73000000000000000000000000000000000000000030146080604052600080fdfea2646970667358221220bf1b9d7d74d58f093eea1b088fdbcad7f67374661fae1ab5815d7a31130f2fb864736f6c63430008180033","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.24 ^0.8.20 ^0.8.4;\n\n// contracts/interfaces/IAdmin.sol\n\ninterface IAdmin {\n // ============ Events ============\n\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n event ChainGasAmountUpdated(uint256 oldChainGasAmount, uint256 newChainGasAmount);\n\n // ============ Methods ============\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n\n function setChainGasAmount(uint256 newChainGasAmount) external;\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IFastBridgeV2Errors.sol\n\ninterface IFastBridgeV2Errors {\n error AmountIncorrect();\n error ChainIncorrect();\n error ExclusivityParamsIncorrect();\n error MsgValueIncorrect();\n error SenderIncorrect();\n error StatusIncorrect();\n error TokenNotContract();\n error ZapDataLengthAboveMax();\n error ZapNativeNotSupported();\n error ZeroAddress();\n\n error RecipientIncorrectReturnValue();\n error RecipientNoReturnValue();\n\n error DeadlineExceeded();\n error DeadlineNotExceeded();\n error DeadlineTooShort();\n error DisputePeriodNotPassed();\n error DisputePeriodPassed();\n error ExclusivityPeriodNotPassed();\n\n error TransactionRelayed();\n}\n\n// contracts/interfaces/IMulticallTarget.sol\n\n/// @notice Interface for a contract that can be called multiple times by the same caller. Inspired by MulticallV3:\n/// https://github.com/mds1/multicall/blob/master/src/Multicall3.sol\ninterface IMulticallTarget {\n struct Result {\n bool success;\n bytes returnData;\n }\n\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external;\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results);\n}\n\n// contracts/interfaces/IZapRecipient.sol\n\ninterface IZapRecipient {\n function zap(address token, uint256 amount, bytes memory zapData) external payable returns (bytes4);\n}\n\n// contracts/libs/Errors.sol\n\nerror DeadlineExceeded();\nerror DeadlineNotExceeded();\nerror DeadlineTooShort();\nerror InsufficientOutputAmount();\n\nerror MsgValueIncorrect();\nerror PoolNotFound();\nerror TokenAddressMismatch();\nerror TokenNotContract();\nerror TokenNotETH();\nerror TokensIdentical();\n\nerror ChainIncorrect();\nerror AmountIncorrect();\nerror ZeroAddress();\n\nerror DisputePeriodNotPassed();\nerror DisputePeriodPassed();\nerror SenderIncorrect();\nerror StatusIncorrect();\nerror TransactionIdIncorrect();\nerror TransactionRelayed();\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// contracts/interfaces/IFastBridgeV2.sol\n\ninterface IFastBridgeV2 is IFastBridge {\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n struct BridgeTxDetails {\n BridgeStatus status;\n uint32 destChainId;\n uint56 proofBlockTimestamp;\n address proofRelayer;\n }\n\n struct BridgeRelay {\n uint48 blockNumber;\n uint48 blockTimestamp;\n address relayer;\n }\n\n /// @notice New params introduced in the FastBridgeV2.\n /// We are passing fields from the older BridgeParams struct outside of this struct\n /// for backwards compatibility.\n /// Note: quoteRelayer and quoteExclusivitySeconds are either both zero (indicating no exclusivity)\n /// or both non-zero (indicating exclusivity for the given period).\n /// Note: zapNative \u003e 0 can NOT be used with destToken = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE (native token)\n /// @param quoteRelayer Relayer that provided the quote for the transaction\n /// @param quoteExclusivitySeconds Period of time the quote relayer is guaranteed exclusivity after user's deposit\n /// @param quoteId Unique quote identifier used for tracking the quote\n /// @param zapNative ETH value to send to the recipient (if any)\n /// @param zapData Parameters for the Zap to the destination recipient (if any)\n struct BridgeParamsV2 {\n address quoteRelayer;\n int256 quoteExclusivitySeconds;\n bytes quoteId;\n uint256 zapNative;\n bytes zapData;\n }\n\n /// @notice Updated bridge transaction struct to include parameters introduced in FastBridgeV2.\n /// Note: only `exclusivityRelayer` can fill such a transaction until `exclusivityEndTime`.\n struct BridgeTransactionV2 {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n // Note: sendChainGas flag from V1 is deprecated\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n address exclusivityRelayer;\n uint256 exclusivityEndTime;\n uint256 zapNative; // ETH value to send to the recipient (if any)\n bytes zapData; // data to pass for the Zap action (if any)\n }\n\n event BridgeQuoteDetails(bytes32 indexed transactionId, bytes quoteId);\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability\n /// to provide temporary exclusivity fill rights for the quote relayer.\n /// @param params The parameters required to bridge\n /// @param paramsV2 The parameters for exclusivity fill rights (optional, can be left empty)\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function relay(bytes memory request, address relayer) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param transactionId The transaction id associated with the encoded bridge transaction to prove\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital.\n /// @notice Can only send funds to the relayer address on the proof.\n /// @param request The encoded bridge transaction to claim on origin chain\n function claim(bytes memory request) external;\n /// @notice Checks if a transaction has been relayed\n /// @param transactionId The ID of the transaction to check\n /// @return True if the transaction has been relayed, false otherwise\n function bridgeRelays(bytes32 transactionId) external view returns (bool);\n\n /// @notice Returns the status of a bridge transaction\n /// @param transactionId The ID of the bridge transaction\n /// @return BridgeStatus Status of the bridge transaction\n function bridgeStatuses(bytes32 transactionId) external view returns (BridgeStatus);\n\n /// @notice Returns the timestamp and relayer of a bridge proof\n /// @param transactionId The ID of the bridge transaction\n /// @return timestamp The timestamp of the bridge proof\n /// @return relayer The relayer address of the bridge proof\n function bridgeProofs(bytes32 transactionId) external view returns (uint96 timestamp, address relayer);\n\n /// @notice Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\n /// @param request The bridge request to decode\n function getBridgeTransactionV2(bytes memory request) external view returns (BridgeTransactionV2 memory);\n}\n\n// contracts/utils/MulticallTarget.sol\n\n// solhint-disable avoid-low-level-calls\n/// @notice Template for a contract that supports batched calls (preserving the msg.sender).\n/// Only calls with zero msg.value could be batched.\nabstract contract MulticallTarget is IMulticallTarget {\n error MulticallTarget__UndeterminedRevert();\n\n /// @notice Perform a batched call to this contract, preserving the msg.sender.\n /// The return data from each call is discarded.\n /// @dev The method is non-payable, so only calls with `msg.value == 0` could be batched.\n /// It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag.\n /// Otherwise, the whole batch call will be reverted with the original revert reason.\n /// @param data List of abi-encoded calldata for the calls to perform.\n /// @param ignoreReverts Whether to ignore the revert errors from the calls.\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external {\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\n if (!success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(result);\n }\n }\n }\n\n /// @notice Perform a batched call to this contract, preserving the msg.sender.\n /// The return data from each call is preserved.\n /// @dev The method is non-payable, so only calls with `msg.value == 0` could be batched.\n /// It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag.\n /// Otherwise, the whole batch call will be reverted with the original revert reason.\n /// @param data List of abi-encoded calldata for the calls to perform.\n /// @param ignoreReverts Whether to ignore the revert errors from the calls.\n /// @return results List of results from the calls: `(success, returnData)`.\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results)\n {\n results = new Result[](data.length);\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (results[i].success, results[i].returnData) = address(this).delegatecall(data[i]);\n if (!results[i].success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(results[i].returnData);\n }\n }\n }\n\n /// @dev Bubbles the revert message from the underlying call.\n /// Note: preserves the same custom error or revert string, if one was used.\n /// Source: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v5.0.2/contracts/utils/Address.sol#L143-L158\n function _bubbleRevert(bytes memory returnData) internal pure {\n // Look for revert reason and bubble it up if present\n if (returnData.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n // solhint-disable-next-line no-inline-assembly\n assembly {\n let returndata_size := mload(returnData)\n revert(add(32, returnData), returndata_size)\n }\n } else {\n revert MulticallTarget__UndeterminedRevert();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// contracts/libs/BridgeTransactionV2.sol\n\n// solhint-disable no-inline-assembly\nlibrary BridgeTransactionV2Lib {\n uint16 internal constant VERSION = 2;\n\n // Offsets of the fields in the packed BridgeTransactionV2 struct\n // uint16 version [000 .. 002)\n // uint32 originChainId [002 .. 006)\n // uint32 destChainId [006 .. 010)\n // address originSender [010 .. 030)\n // address destRecipient [030 .. 050)\n // address originToken [050 .. 070)\n // address destToken [070 .. 090)\n // uint256 originAmount [090 .. 122)\n // uint256 destAmount [122 .. 154)\n // uint256 originFeeAmount [154 .. 186)\n // uint256 deadline [186 .. 218)\n // uint256 nonce [218 .. 250)\n // address exclusivityRelayer [250 .. 270)\n // uint256 exclusivityEndTime [270 .. 302)\n // uint256 zapNative [302 .. 334)\n // bytes zapData [334 .. ***)\n\n // forgefmt: disable-start\n uint256 private constant OFFSET_ORIGIN_CHAIN_ID = 2;\n uint256 private constant OFFSET_DEST_CHAIN_ID = 6;\n uint256 private constant OFFSET_ORIGIN_SENDER = 10;\n uint256 private constant OFFSET_DEST_RECIPIENT = 30;\n uint256 private constant OFFSET_ORIGIN_TOKEN = 50;\n uint256 private constant OFFSET_DEST_TOKEN = 70;\n uint256 private constant OFFSET_ORIGIN_AMOUNT = 90;\n uint256 private constant OFFSET_DEST_AMOUNT = 122;\n uint256 private constant OFFSET_ORIGIN_FEE_AMOUNT = 154;\n uint256 private constant OFFSET_DEADLINE = 186;\n uint256 private constant OFFSET_NONCE = 218;\n uint256 private constant OFFSET_EXCLUSIVITY_RELAYER = 250;\n uint256 private constant OFFSET_EXCLUSIVITY_END_TIME = 270;\n uint256 private constant OFFSET_ZAP_NATIVE = 302;\n uint256 private constant OFFSET_ZAP_DATA = 334;\n // forgefmt: disable-end\n\n error BridgeTransactionV2__InvalidEncodedTx();\n error BridgeTransactionV2__UnsupportedVersion(uint16 version);\n\n /// @notice Validates the encoded transaction to be a tightly packed encoded payload for BridgeTransactionV2.\n /// @dev Checks the minimum length and the version, use this function before decoding any of the fields.\n function validateV2(bytes calldata encodedTx) internal pure {\n // Check the minimum length: must at least include all static fields.\n if (encodedTx.length \u003c OFFSET_ZAP_DATA) revert BridgeTransactionV2__InvalidEncodedTx();\n // Once we validated the length, we can be sure that the version field is present.\n uint16 version_ = version(encodedTx);\n if (version_ != VERSION) revert BridgeTransactionV2__UnsupportedVersion(version_);\n }\n\n /// @notice Encodes the BridgeTransactionV2 struct by tightly packing the fields.\n /// @dev `abi.decode` will not work as a result of the tightly packed fields. Use `decodeV2` to decode instead.\n function encodeV2(IFastBridgeV2.BridgeTransactionV2 memory bridgeTx) internal pure returns (bytes memory) {\n // We split the encoding into two parts to avoid stack-too-deep error\n bytes memory firstPart = abi.encodePacked(\n VERSION,\n bridgeTx.originChainId,\n bridgeTx.destChainId,\n bridgeTx.originSender,\n bridgeTx.destRecipient,\n bridgeTx.originToken,\n bridgeTx.destToken,\n bridgeTx.originAmount\n );\n return abi.encodePacked(\n firstPart,\n bridgeTx.destAmount,\n bridgeTx.originFeeAmount,\n // Note: we skip the deprecated `sendChainGas` flag, which was present in BridgeTransaction V1\n bridgeTx.deadline,\n bridgeTx.nonce,\n // New V2 fields: exclusivity\n bridgeTx.exclusivityRelayer,\n bridgeTx.exclusivityEndTime,\n // New V2 fields: Zap\n bridgeTx.zapNative,\n bridgeTx.zapData\n );\n }\n\n /// @notice Decodes the BridgeTransactionV2 struct from the encoded transaction.\n /// @dev Encoded BridgeTransactionV2 struct must be tightly packed.\n /// Use `validateV2` before decoding to ensure the encoded transaction is valid.\n function decodeV2(bytes calldata encodedTx)\n internal\n pure\n returns (IFastBridgeV2.BridgeTransactionV2 memory bridgeTx)\n {\n bridgeTx.originChainId = originChainId(encodedTx);\n bridgeTx.destChainId = destChainId(encodedTx);\n bridgeTx.originSender = originSender(encodedTx);\n bridgeTx.destRecipient = destRecipient(encodedTx);\n bridgeTx.originToken = originToken(encodedTx);\n bridgeTx.destToken = destToken(encodedTx);\n bridgeTx.originAmount = originAmount(encodedTx);\n bridgeTx.destAmount = destAmount(encodedTx);\n bridgeTx.originFeeAmount = originFeeAmount(encodedTx);\n bridgeTx.deadline = deadline(encodedTx);\n bridgeTx.nonce = nonce(encodedTx);\n bridgeTx.exclusivityRelayer = exclusivityRelayer(encodedTx);\n bridgeTx.exclusivityEndTime = exclusivityEndTime(encodedTx);\n bridgeTx.zapNative = zapNative(encodedTx);\n bridgeTx.zapData = zapData(encodedTx);\n }\n\n /// @notice Extracts the version from the encoded transaction.\n function version(bytes calldata encodedTx) internal pure returns (uint16 version_) {\n // Load 32 bytes from the start and shift it 240 bits to the right to get the highest 16 bits.\n assembly {\n version_ := shr(240, calldataload(encodedTx.offset))\n }\n }\n\n /// @notice Extracts the origin chain ID from the encoded transaction.\n function originChainId(bytes calldata encodedTx) internal pure returns (uint32 originChainId_) {\n // Load 32 bytes from the offset and shift it 224 bits to the right to get the highest 32 bits.\n assembly {\n originChainId_ := shr(224, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_CHAIN_ID)))\n }\n }\n\n /// @notice Extracts the destination chain ID from the encoded transaction.\n function destChainId(bytes calldata encodedTx) internal pure returns (uint32 destChainId_) {\n // Load 32 bytes from the offset and shift it 224 bits to the right to get the highest 32 bits.\n assembly {\n destChainId_ := shr(224, calldataload(add(encodedTx.offset, OFFSET_DEST_CHAIN_ID)))\n }\n }\n\n /// @notice Extracts the origin sender from the encoded transaction.\n function originSender(bytes calldata encodedTx) internal pure returns (address originSender_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n originSender_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_SENDER)))\n }\n }\n\n /// @notice Extracts the destination recipient from the encoded transaction.\n function destRecipient(bytes calldata encodedTx) internal pure returns (address destRecipient_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n destRecipient_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_DEST_RECIPIENT)))\n }\n }\n\n /// @notice Extracts the origin token from the encoded transaction.\n function originToken(bytes calldata encodedTx) internal pure returns (address originToken_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n originToken_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_TOKEN)))\n }\n }\n\n /// @notice Extracts the destination token from the encoded transaction.\n function destToken(bytes calldata encodedTx) internal pure returns (address destToken_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n destToken_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_DEST_TOKEN)))\n }\n }\n\n /// @notice Extracts the origin amount from the encoded transaction.\n function originAmount(bytes calldata encodedTx) internal pure returns (uint256 originAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n originAmount_ := calldataload(add(encodedTx.offset, OFFSET_ORIGIN_AMOUNT))\n }\n }\n\n /// @notice Extracts the destination amount from the encoded transaction.\n function destAmount(bytes calldata encodedTx) internal pure returns (uint256 destAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n destAmount_ := calldataload(add(encodedTx.offset, OFFSET_DEST_AMOUNT))\n }\n }\n\n /// @notice Extracts the origin fee amount from the encoded transaction.\n function originFeeAmount(bytes calldata encodedTx) internal pure returns (uint256 originFeeAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n originFeeAmount_ := calldataload(add(encodedTx.offset, OFFSET_ORIGIN_FEE_AMOUNT))\n }\n }\n\n /// @notice Extracts the deadline from the encoded transaction.\n function deadline(bytes calldata encodedTx) internal pure returns (uint256 deadline_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n deadline_ := calldataload(add(encodedTx.offset, OFFSET_DEADLINE))\n }\n }\n\n /// @notice Extracts the nonce from the encoded transaction.\n function nonce(bytes calldata encodedTx) internal pure returns (uint256 nonce_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n nonce_ := calldataload(add(encodedTx.offset, OFFSET_NONCE))\n }\n }\n\n /// @notice Extracts the exclusivity relayer from the encoded transaction.\n function exclusivityRelayer(bytes calldata encodedTx) internal pure returns (address exclusivityRelayer_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n exclusivityRelayer_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_EXCLUSIVITY_RELAYER)))\n }\n }\n\n /// @notice Extracts the exclusivity end time from the encoded transaction.\n function exclusivityEndTime(bytes calldata encodedTx) internal pure returns (uint256 exclusivityEndTime_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n exclusivityEndTime_ := calldataload(add(encodedTx.offset, OFFSET_EXCLUSIVITY_END_TIME))\n }\n }\n\n /// @notice Extracts the Zap's native value from the encoded transaction.\n function zapNative(bytes calldata encodedTx) internal pure returns (uint256 zapNative_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n zapNative_ := calldataload(add(encodedTx.offset, OFFSET_ZAP_NATIVE))\n }\n }\n\n /// @notice Extracts the Zap's data from the encoded transaction.\n function zapData(bytes calldata encodedTx) internal pure returns (bytes calldata zapData_) {\n zapData_ = encodedTx[OFFSET_ZAP_DATA:];\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// contracts/libs/UniversalToken.sol\n\nlibrary UniversalTokenLib {\n using SafeERC20 for IERC20;\n\n address internal constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Transfers tokens to the given account. Reverts if transfer is not successful.\n /// @dev This might trigger fallback, if ETH is transferred to the contract.\n /// Make sure this can not lead to reentrancy attacks.\n function universalTransfer(address token, address to, uint256 value) internal {\n // Don't do anything, if need to send tokens to this address\n if (to == address(this)) return;\n // Don't do anything, if trying to send zero value\n if (value == 0) return;\n if (token == ETH_ADDRESS) {\n /// @dev Note: this can potentially lead to executing code in `to`.\n // solhint-disable-next-line avoid-low-level-calls\n (bool success,) = to.call{value: value}(\"\");\n require(success, \"ETH transfer failed\");\n } else {\n IERC20(token).safeTransfer(to, value);\n }\n }\n\n /// @notice Issues an infinite allowance to the spender, if the current allowance is insufficient\n /// to spend the given amount.\n function universalApproveInfinity(address token, address spender, uint256 amountToSpend) internal {\n // ETH Chad doesn't require your approval\n if (token == ETH_ADDRESS) return;\n // No-op if allowance is already sufficient\n uint256 allowance = IERC20(token).allowance(address(this), spender);\n if (allowance \u003e= amountToSpend) return;\n // Otherwise, reset approval to 0 and set to max allowance\n if (allowance \u003e 0) IERC20(token).safeDecreaseAllowance(spender, allowance);\n IERC20(token).safeIncreaseAllowance(spender, type(uint256).max);\n }\n\n /// @notice Returns the balance of the given token (or native ETH) for the given account.\n function universalBalanceOf(address token, address account) internal view returns (uint256) {\n if (token == ETH_ADDRESS) {\n return account.balance;\n } else {\n return IERC20(token).balanceOf(account);\n }\n }\n\n /// @dev Checks that token is a contract and not ETH_ADDRESS.\n function assertIsContract(address token) internal view {\n // Check that ETH_ADDRESS was not used (in case this is a predeploy on any of the chains)\n if (token == UniversalTokenLib.ETH_ADDRESS) revert TokenNotContract();\n // Check that token is not an EOA\n if (token.code.length == 0) revert TokenNotContract();\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/Admin.sol\n\ncontract Admin is IAdmin, AccessControlEnumerable {\n using UniversalTokenLib for address;\n\n bytes32 public constant RELAYER_ROLE = keccak256(\"RELAYER_ROLE\");\n bytes32 public constant REFUNDER_ROLE = keccak256(\"REFUNDER_ROLE\");\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n uint256 public constant FEE_BPS = 1e6;\n uint256 public constant FEE_RATE_MAX = 0.01e6; // max 1% on origin amount\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Chain gas amount to forward as rebate if requested\n uint256 public chainGasAmount;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n }\n\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n require(newFeeRate \u003c= FEE_RATE_MAX, \"newFeeRate \u003e max\");\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n token.universalTransfer(recipient, feeAmount);\n emit FeesSwept(token, recipient, feeAmount);\n }\n\n function setChainGasAmount(uint256 newChainGasAmount) external onlyRole(GOVERNOR_ROLE) {\n uint256 oldChainGasAmount = chainGasAmount;\n chainGasAmount = newChainGasAmount;\n emit ChainGasAmountUpdated(oldChainGasAmount, newChainGasAmount);\n }\n}\n\n// contracts/FastBridgeV2.sol\n\n/// @notice FastBridgeV2 is a contract for bridging tokens across chains.\ncontract FastBridgeV2 is Admin, MulticallTarget, IFastBridgeV2, IFastBridgeV2Errors {\n using BridgeTransactionV2Lib for bytes;\n using SafeERC20 for IERC20;\n\n /// @notice Address reserved for native gas token (ETH on Ethereum and most L2s, AVAX on Avalanche, etc)\n address public constant NATIVE_GAS_TOKEN = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Delay for a transaction after which it could be permisionlessly refunded\n uint256 public constant REFUND_DELAY = 7 days;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n /// @notice Maximum length of accepted zapData\n uint256 public constant MAX_ZAP_DATA_LENGTH = 2 ** 16 - 1;\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeTxDetails) public bridgeTxDetails;\n /// @notice Relay details on destination chain\n mapping(bytes32 =\u003e BridgeRelay) public bridgeRelayDetails;\n /// @notice Unique bridge nonces tracked per originSender\n mapping(address =\u003e uint256) public senderNonces;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Replaced by senderNonces\n uint256 public immutable nonce = 0;\n /// @notice the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n bridge({\n params: params,\n paramsV2: BridgeParamsV2({\n quoteRelayer: address(0),\n quoteExclusivitySeconds: 0,\n quoteId: bytes(\"\"),\n zapNative: 0,\n zapData: bytes(\"\")\n })\n });\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes calldata request) external payable {\n // relay override will validate the request\n relay({request: request, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes calldata request, bytes32 destTxHash) external {\n request.validateV2();\n prove({transactionId: keccak256(request), destTxHash: destTxHash, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridgeV2\n function claim(bytes calldata request) external {\n // claim override will validate the request\n claim({request: request, to: address(0)});\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Aggregate the read operations from the same storage slot\n address disputedRelayer = $.proofRelayer;\n BridgeStatus status = $.status;\n uint56 proofBlockTimestamp = $.proofBlockTimestamp;\n // Can only dispute a RELAYER_PROVED transaction within the dispute period\n if (status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(proofBlockTimestamp) \u003e DISPUTE_PERIOD) {\n revert DisputePeriodPassed();\n }\n // Update status to REQUESTED and delete the disputed proof details\n // Note: these are storage writes\n $.status = BridgeStatus.REQUESTED;\n $.proofRelayer = address(0);\n $.proofBlockTimestamp = 0;\n\n emit BridgeProofDisputed(transactionId, disputedRelayer);\n }\n\n /// @inheritdoc IFastBridge\n function refund(bytes calldata request) external {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Can only refund a REQUESTED transaction after its deadline expires\n if ($.status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n uint256 deadline = request.deadline();\n // Permissionless refund is only allowed after REFUND_DELAY on top of the deadline\n if (!hasRole(REFUNDER_ROLE, msg.sender)) deadline += REFUND_DELAY;\n if (block.timestamp \u003c= deadline) revert DeadlineNotExceeded();\n // Update status to REFUNDED and return the full amount (collateral + protocol fees) to the original sender.\n // The protocol fees are only updated when the transaction is claimed, so we don't need to update them here.\n // Note: this is a storage write\n $.status = BridgeStatus.REFUNDED;\n\n address to = request.originSender();\n address token = request.originToken();\n uint256 amount = request.originAmount() + request.originFeeAmount();\n // Emit the event before any external calls\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n // Complete the user refund as the last transaction action\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(to), amount);\n } else {\n IERC20(token).safeTransfer(to, amount);\n }\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // The correct relayer can only claim a RELAYER_PROVED transaction after the dispute period\n if ($.status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if ($.proofRelayer != relayer) revert SenderIncorrect();\n return _timeSince($.proofBlockTimestamp) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n /// @dev This method is added to achieve backwards compatibility with decoding requests into V1 structs:\n /// - `zapNative` is partially reported as a zero/non-zero flag\n /// - `zapData` is ignored\n /// In order to process all kinds of requests use getBridgeTransactionV2 instead.\n function getBridgeTransaction(bytes calldata request) external view returns (BridgeTransaction memory) {\n // Try decoding into V2 struct first. This will revert if V1 struct is passed\n try this.getBridgeTransactionV2(request) returns (BridgeTransactionV2 memory txV2) {\n // Note: we entirely ignore the zapData field, as it was not present in V1\n return BridgeTransaction({\n originChainId: txV2.originChainId,\n destChainId: txV2.destChainId,\n originSender: txV2.originSender,\n destRecipient: txV2.destRecipient,\n originToken: txV2.originToken,\n destToken: txV2.destToken,\n originAmount: txV2.originAmount,\n destAmount: txV2.destAmount,\n originFeeAmount: txV2.originFeeAmount,\n sendChainGas: txV2.zapNative != 0,\n deadline: txV2.deadline,\n nonce: txV2.nonce\n });\n } catch {\n // Fallback to V1 struct\n return abi.decode(request, (BridgeTransaction));\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function getBridgeTransactionV2(bytes calldata request) external pure returns (BridgeTransactionV2 memory) {\n request.validateV2();\n return BridgeTransactionV2Lib.decodeV2(request);\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) public payable {\n int256 exclusivityEndTime = 0;\n // if relayer exclusivity is not intended for this bridge, set exclusivityEndTime to static zero\n // otherwise, set exclusivity to expire at the current block ts offset by quoteExclusivitySeconds\n if (paramsV2.quoteRelayer != address(0)) {\n exclusivityEndTime = int256(block.timestamp) + paramsV2.quoteExclusivitySeconds;\n }\n _validateBridgeParams(params, paramsV2, exclusivityEndTime);\n\n // transfer tokens to bridge contract\n /// @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _takeBridgedUserAsset(params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) {\n originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n }\n\n // set status to requested\n bytes memory request = BridgeTransactionV2Lib.encodeV2(\n BridgeTransactionV2({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n deadline: params.deadline,\n nonce: senderNonces[params.sender]++, // increment nonce on every bridge\n exclusivityRelayer: paramsV2.quoteRelayer,\n // We checked exclusivityEndTime to be in range [0 .. params.deadline] above, so can safely cast\n exclusivityEndTime: uint256(exclusivityEndTime),\n zapNative: paramsV2.zapNative,\n zapData: paramsV2.zapData\n })\n );\n bytes32 transactionId = keccak256(request);\n // Note: the tx status will be updated throughout the tx lifecycle, while destChainId is set once here\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n bridgeTxDetails[transactionId].destChainId = params.dstChainId;\n\n emit BridgeRequested({\n transactionId: transactionId,\n sender: params.sender,\n request: request,\n destChainId: params.dstChainId,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n sendChainGas: paramsV2.zapNative != 0\n });\n emit BridgeQuoteDetails(transactionId, paramsV2.quoteId);\n }\n\n /// @inheritdoc IFastBridgeV2\n function relay(bytes calldata request, address relayer) public payable {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n _validateRelayParams(request, transactionId, relayer);\n // mark bridge transaction as relayed\n bridgeRelayDetails[transactionId] =\n BridgeRelay({blockNumber: uint48(block.number), blockTimestamp: uint48(block.timestamp), relayer: relayer});\n\n // transfer tokens to recipient on destination chain and trigger Zap if requested\n address to = request.destRecipient();\n address token = request.destToken();\n uint256 amount = request.destAmount();\n uint256 zapNative = request.zapNative();\n\n // Emit the event before any external calls\n emit BridgeRelayed({\n transactionId: transactionId,\n relayer: relayer,\n to: to,\n originChainId: request.originChainId(),\n originToken: request.originToken(),\n destToken: token,\n originAmount: request.originAmount(),\n destAmount: amount,\n chainGasAmount: zapNative\n });\n\n // All state changes have been done at this point, can proceed to the external calls.\n // This follows the checks-effects-interactions pattern to mitigate potential reentrancy attacks.\n if (token == NATIVE_GAS_TOKEN) {\n // For the native gas token, additional zapNative is not allowed\n if (zapNative != 0) revert ZapNativeNotSupported();\n // Check that the correct msg.value was sent\n if (msg.value != amount) revert MsgValueIncorrect();\n // Don't do a native transfer yet: we will handle it alongside the Zap below\n } else {\n // For ERC20s, we check that the correct msg.value was sent\n if (msg.value != zapNative) revert MsgValueIncorrect();\n // We need to transfer the tokens from the Relayer to the recipient first before performing an\n // optional post-transfer Zap.\n IERC20(token).safeTransferFrom(msg.sender, to, amount);\n }\n // At this point we have done:\n // - Transferred the requested amount of ERC20 tokens to the recipient.\n // At this point we have confirmed:\n // - For ERC20s: msg.value matches the requested zapNative amount.\n // - For the native gas token: msg.value matches the requested destAmount.\n // Remaining optional things to do:\n // - Forward the full msg.value to the recipient (if non-zero).\n // - Trigger a Zap (if zapData is present).\n bytes calldata zapData = request.zapData();\n if (zapData.length != 0) {\n // Zap Data is present: Zap has been requested by the recipient. Trigger it forwarding the full msg.value.\n\n // Note: if token has a fee on transfers, the recipient will have received less than `amount`.\n // This is a very niche edge case and should be handled by the recipient contract.\n _triggerZapWithChecks({recipient: to, token: token, amount: amount, zapData: zapData});\n } else if (msg.value != 0) {\n // Zap Data is missing, but msg.value was sent. This could happen in two different cases:\n // - Relay with the native gas token is happening.\n // - Relay with ERC20 is happening, with a `zapNative \u003e 0` request.\n // In both cases, we need to transfer the full msg.value to the recipient.\n Address.sendValue(payable(to), msg.value);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) public onlyRole(RELAYER_ROLE) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n\n // Can only prove a REQUESTED transaction\n if ($.status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n // Update status to RELAYER_PROVED and store the proof details\n // Note: these are storage writes\n $.status = BridgeStatus.RELAYER_PROVED;\n $.proofBlockTimestamp = uint56(block.timestamp);\n $.proofRelayer = relayer;\n\n emit BridgeProofProvided(transactionId, relayer, destTxHash);\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes calldata request, address to) public {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Aggregate the read operations from the same storage slot\n address proofRelayer = $.proofRelayer;\n BridgeStatus status = $.status;\n uint56 proofBlockTimestamp = $.proofBlockTimestamp;\n\n // Can only claim a RELAYER_PROVED transaction after the dispute period\n if (status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(proofBlockTimestamp) \u003c= DISPUTE_PERIOD) {\n revert DisputePeriodNotPassed();\n }\n\n if (to == address(0)) {\n // Anyone could claim the funds to the proven relayer on their behalf\n to = proofRelayer;\n } else if (proofRelayer != msg.sender) {\n // Only the proven relayer could specify an address to claim the funds to\n revert SenderIncorrect();\n }\n\n // Update status to RELAYER_CLAIMED and transfer the origin collateral to the specified claim address\n // Note: this is a storage write\n $.status = BridgeStatus.RELAYER_CLAIMED;\n\n address token = request.originToken();\n uint256 amount = request.originAmount();\n // Update protocol fees if origin fee amount exists\n uint256 originFeeAmount = request.originFeeAmount();\n if (originFeeAmount \u003e 0) protocolFees[token] += originFeeAmount;\n // Emit the event before any external calls\n emit BridgeDepositClaimed(transactionId, proofRelayer, to, token, amount);\n // Complete the relayer claim as the last transaction action\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(to), amount);\n } else {\n IERC20(token).safeTransfer(to, amount);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeStatuses(bytes32 transactionId) public view returns (BridgeStatus status) {\n return bridgeTxDetails[transactionId].status;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeProofs(bytes32 transactionId) public view returns (uint96 timestamp, address relayer) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n\n timestamp = $.proofBlockTimestamp;\n relayer = $.proofRelayer;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeRelays(bytes32 transactionId) public view returns (bool) {\n // has this transactionId been relayed?\n return bridgeRelayDetails[transactionId].relayer != address(0);\n }\n\n /// @notice Takes the bridged asset from the user into FastBridgeV2 custody. It will be later\n /// claimed by the relayer who completed the relay on destination chain, or refunded back to the user,\n /// should no one complete the relay.\n function _takeBridgedUserAsset(address token, uint256 amount) internal returns (uint256 amountTaken) {\n if (token == NATIVE_GAS_TOKEN) {\n // For the native gas token, we just need to check that the supplied msg.value is correct.\n // Supplied `msg.value` is already in FastBridgeV2 custody.\n if (amount != msg.value) revert MsgValueIncorrect();\n amountTaken = msg.value;\n } else {\n // For ERC20s, token is explicitly transferred from the user to FastBridgeV2.\n // We don't allow non-zero `msg.value` to avoid extra funds from being stuck in FastBridgeV2.\n if (msg.value != 0) revert MsgValueIncorrect();\n // Throw an explicit error if the provided token address is not a contract\n if (token.code.length == 0) revert TokenNotContract();\n amountTaken = IERC20(token).balanceOf(address(this));\n IERC20(token).safeTransferFrom(msg.sender, address(this), amount);\n // Use the balance difference as the amount taken in case of fee on transfer tokens.\n amountTaken = IERC20(token).balanceOf(address(this)) - amountTaken;\n }\n }\n\n /// @notice Calls the Recipient's hook function with the specified zapData and performs\n /// all the necessary checks for the returned value.\n function _triggerZapWithChecks(address recipient, address token, uint256 amount, bytes calldata zapData) internal {\n // This will bubble any revert messages from the hook function\n bytes memory returnData = Address.functionCallWithValue({\n target: recipient,\n data: abi.encodeCall(IZapRecipient.zap, (token, amount, zapData)),\n // Note: see `relay()` for reasoning behind passing msg.value\n value: msg.value\n });\n // Explicit revert if no return data at all\n if (returnData.length == 0) revert RecipientNoReturnValue();\n // Check that exactly a single return value was returned\n if (returnData.length != 32) revert RecipientIncorrectReturnValue();\n // Return value should be abi-encoded hook function selector\n if (bytes32(returnData) != bytes32(IZapRecipient.zap.selector)) {\n revert RecipientIncorrectReturnValue();\n }\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint56(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint56).max but\n /// proof.timestamp \u003c type(uint56).max via unchecked statement\n /// @param proofBlockTimestamp The bridge proof block timestamp\n /// @return delta Time delta since proof submitted\n function _timeSince(uint56 proofBlockTimestamp) internal view returns (uint256 delta) {\n unchecked {\n delta = uint56(block.timestamp) - proofBlockTimestamp;\n }\n }\n\n /// @notice Performs all the necessary checks for a bridge to happen.\n /// @dev There's no good way to refactor this function to reduce cyclomatic complexity due to\n /// the number of checks that need to be performed, so we skip the code-complexity rule here.\n // solhint-disable-next-line code-complexity\n function _validateBridgeParams(\n BridgeParams memory params,\n BridgeParamsV2 memory paramsV2,\n int256 exclusivityEndTime\n )\n internal\n view\n {\n // Check V1 (legacy) params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.sender == address(0) || params.to == address(0)) revert ZeroAddress();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n // Check V2 params\n if (paramsV2.zapData.length \u003e MAX_ZAP_DATA_LENGTH) revert ZapDataLengthAboveMax();\n if (paramsV2.zapNative != 0 \u0026\u0026 params.destToken == NATIVE_GAS_TOKEN) {\n revert ZapNativeNotSupported();\n }\n // exclusivityEndTime must be in range [0 .. params.deadline]\n if (exclusivityEndTime \u003c 0 || exclusivityEndTime \u003e int256(params.deadline)) {\n revert ExclusivityParamsIncorrect();\n }\n }\n\n /// @notice Performs all the necessary checks for a relay to happen.\n function _validateRelayParams(bytes calldata request, bytes32 transactionId, address relayer) internal view {\n if (relayer == address(0)) revert ZeroAddress();\n // Check if the transaction has already been relayed\n if (bridgeRelays(transactionId)) revert TransactionRelayed();\n if (request.destChainId() != block.chainid) revert ChainIncorrect();\n // Check the deadline for relay to happen\n if (block.timestamp \u003e request.deadline()) revert DeadlineExceeded();\n // Check the exclusivity period, if it is still ongoing\n address exclRelayer = request.exclusivityRelayer();\n if (exclRelayer != address(0) \u0026\u0026 exclRelayer != relayer \u0026\u0026 block.timestamp \u003c= request.exclusivityEndTime()) {\n revert ExclusivityPeriodNotPassed();\n }\n }\n}\n","language":"Solidity","languageVersion":"0.8.24","compilerVersion":"0.8.24","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"17068:6066:0:-:0;;;;;;;;;;;;;;;-1:-1:-1;;;17068:6066:0;;;;;;;;;;;;;;;;;","srcMapRuntime":"17068:6066:0:-:0;;;;;;;;","abiDefinition":[{"inputs":[{"internalType":"address","name":"target","type":"address"}],"name":"AddressEmptyCode","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"AddressInsufficientBalance","type":"error"},{"inputs":[],"name":"FailedInnerCall","type":"error"}],"userDoc":{"kind":"user","methods":{},"version":1},"developerDoc":{"details":"Collection of functions related to the address type","errors":{"AddressEmptyCode(address)":[{"details":"There's no code at `target` (it is not a contract)."}],"AddressInsufficientBalance(address)":[{"details":"The ETH balance of the account is not enough to perform the operation."}],"FailedInnerCall()":[{"details":"A call to an address target failed. The target may have reverted."}]},"kind":"dev","methods":{},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"}],\"name\":\"AddressEmptyCode\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"AddressInsufficientBalance\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"FailedInnerCall\",\"type\":\"error\"}],\"devdoc\":{\"details\":\"Collection of functions related to the address type\",\"errors\":{\"AddressEmptyCode(address)\":[{\"details\":\"There's no code at `target` (it is not a contract).\"}],\"AddressInsufficientBalance(address)\":[{\"details\":\"The ETH balance of the account is not enough to perform the operation.\"}],\"FailedInnerCall()\":[{\"details\":\"A call to an address target failed. The target may have reverted.\"}]},\"kind\":\"dev\",\"methods\":{},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeV2.sol\":\"Address\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeV2.sol\":{\"keccak256\":\"0x5069b55ca07f21bfe30b2a43c18a18318c8af9c181b2dcb07c290825efd70f34\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://273dc020a49d08e50126bbea0d7f783f79d08c702f2fdbc560618d24af308acc\",\"dweb:/ipfs/QmXJ2UVzFc8EPB74RT4CXQPC4xw66jt4T13poyfyd3UERh\"]}},\"version\":1}"},"hashes":{}},"solidity/FastBridgeV2.sol:Admin":{"code":"0x60806040523480156200001157600080fd5b50604051620014123803806200141283398101604081905262000034916200018e565b6200004160008262000049565b5050620001b9565b60008062000058848462000086565b905080156200007d5760008481526001602052604090206200007b908462000134565b505b90505b92915050565b6000828152602081815260408083206001600160a01b038516845290915281205460ff166200012b576000838152602081815260408083206001600160a01b03861684529091529020805460ff19166001179055620000e23390565b6001600160a01b0316826001600160a01b0316847f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a450600162000080565b50600062000080565b60006200007d836001600160a01b03841660008181526001830160205260408120546200012b5750815460018181018455600084815260208082209093018490558454848252828601909352604090209190915562000080565b600060208284031215620001a157600080fd5b81516001600160a01b03811681146200007d57600080fd5b61124980620001c96000396000f3fe608060405234801561001057600080fd5b50600436106101775760003560e01c806391d14854116100d8578063bf333f2c1161008c578063d547741f11610066578063d547741f14610385578063dcf844a714610398578063e00a83e0146103b857600080fd5b8063bf333f2c14610341578063ca15c8731461034b578063ccc574901461035e57600080fd5b8063a217fddf116100bd578063a217fddf14610313578063b13aa2d61461031b578063b250fe6b1461032e57600080fd5b806391d14854146102a8578063926d7d7f146102ec57600080fd5b80632f2ff15d1161012f57806358f858801161011457806358f85880146102405780635960ccf2146102495780639010d07c1461027057600080fd5b80632f2ff15d1461021a57806336568abe1461022d57600080fd5b806306f333f21161016057806306f333f2146101d95780630f5f6ed7146101ee578063248a9ca3146101f757600080fd5b806301ffc9a71461017c57806303ed0ee5146101a4575b600080fd5b61018f61018a366004611013565b6103c1565b60405190151581526020015b60405180910390f35b6101cb7f043c983c49d46f0e102151eaf8085d4a2e6571d5df2d47b013f39bddfd4a639d81565b60405190815260200161019b565b6101ec6101e736600461107e565b61041d565b005b6101cb61271081565b6101cb6102053660046110b1565b60009081526020819052604090206001015490565b6101ec6102283660046110ca565b61050b565b6101ec61023b3660046110ca565b610536565b6101cb60025481565b6101cb7fdb9556138406326f00296e13ea2ad7db24ba82381212d816b1a40c23b466b32781565b61028361027e3660046110ed565b61058f565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200161019b565b61018f6102b63660046110ca565b60009182526020828152604080842073ffffffffffffffffffffffffffffffffffffffff93909316845291905290205460ff1690565b6101cb7fe2b7fb3b832174769106daebcfd6d1970523240dda11281102db9363b83b0dc481565b6101cb600081565b6101ec6103293660046110b1565b6105ae565b6101ec61033c3660046110b1565b610690565b6101cb620f424081565b6101cb6103593660046110b1565b6106f8565b6101cb7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f5581565b6101ec6103933660046110ca565b61070f565b6101cb6103a636600461110f565b60036020526000908152604090205481565b6101cb60045481565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f5a05180f000000000000000000000000000000000000000000000000000000001480610417575061041782610734565b92915050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f55610447816107cb565b73ffffffffffffffffffffffffffffffffffffffff83166000908152600360205260408120549081900361047b5750505050565b73ffffffffffffffffffffffffffffffffffffffff84166000818152600360205260408120556104ac9084836107d8565b6040805173ffffffffffffffffffffffffffffffffffffffff8087168252851660208201529081018290527f244e51bc38c1452fa8aaf487bcb4bca36c2baa3a5fbdb776b1eabd8dc6d277cd9060600160405180910390a1505b505050565b600082815260208190526040902060010154610526816107cb565b610530838361092f565b50505050565b73ffffffffffffffffffffffffffffffffffffffff81163314610585576040517f6697b23200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6105068282610964565b60008281526001602052604081206105a79083610991565b9392505050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f556105d8816107cb565b612710821115610649576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f6e657746656552617465203e206d61780000000000000000000000000000000060448201526064015b60405180910390fd5b600280549083905560408051828152602081018590527f14914da2bf76024616fbe1859783fcd4dbddcb179b1f3a854949fbf920dcb95791015b60405180910390a1505050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f556106ba816107cb565b600480549083905560408051828152602081018590527f5cf09b12f3f56b4c564d51b25b40360af6d795198adb61ae0806a36c294323fa9101610683565b60008181526001602052604081206104179061099d565b60008281526020819052604090206001015461072a816107cb565b6105308383610964565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f7965db0b00000000000000000000000000000000000000000000000000000000148061041757507f01ffc9a7000000000000000000000000000000000000000000000000000000007fffffffff00000000000000000000000000000000000000000000000000000000831614610417565b6107d581336109a7565b50565b3073ffffffffffffffffffffffffffffffffffffffff8316036107fa57505050565b8060000361080757505050565b7fffffffffffffffffffffffff111111111111111111111111111111111111111273ffffffffffffffffffffffffffffffffffffffff84160161090e5760008273ffffffffffffffffffffffffffffffffffffffff168260405160006040518083038185875af1925050503d806000811461089e576040519150601f19603f3d011682016040523d82523d6000602084013e6108a3565b606091505b5050905080610530576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f455448207472616e73666572206661696c6564000000000000000000000000006044820152606401610640565b61050673ffffffffffffffffffffffffffffffffffffffff84168383610a31565b60008061093c8484610abe565b905080156105a757600084815260016020526040902061095c9084610bba565b509392505050565b6000806109718484610bdc565b905080156105a757600084815260016020526040902061095c9084610c97565b60006105a78383610cb9565b6000610417825490565b60008281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915290205460ff16610a2d576040517fe2517d3f00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8216600482015260248101839052604401610640565b5050565b6040805173ffffffffffffffffffffffffffffffffffffffff8416602482015260448082018490528251808303909101815260649091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fa9059cbb00000000000000000000000000000000000000000000000000000000179052610506908490610ce3565b60008281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915281205460ff16610bb25760008381526020818152604080832073ffffffffffffffffffffffffffffffffffffffff86168452909152902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055610b503390565b73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16847f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a4506001610417565b506000610417565b60006105a78373ffffffffffffffffffffffffffffffffffffffff8416610d79565b60008281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915281205460ff1615610bb25760008381526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8616808552925280832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016905551339286917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a4506001610417565b60006105a78373ffffffffffffffffffffffffffffffffffffffff8416610dc0565b6000826000018281548110610cd057610cd061112a565b9060005260206000200154905092915050565b6000610d0573ffffffffffffffffffffffffffffffffffffffff841683610eb3565b90508051600014158015610d2a575080806020019051810190610d289190611159565b155b15610506576040517f5274afe700000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff84166004820152602401610640565b6000818152600183016020526040812054610bb257508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155610417565b60008181526001830160205260408120548015610ea9576000610de460018361117b565b8554909150600090610df89060019061117b565b9050808214610e5d576000866000018281548110610e1857610e1861112a565b9060005260206000200154905080876000018481548110610e3b57610e3b61112a565b6000918252602080832090910192909255918252600188019052604090208390555b8554869080610e6e57610e6e6111b5565b600190038181906000526020600020016000905590558560010160008681526020019081526020016000206000905560019350505050610417565b6000915050610417565b60606105a783836000846000808573ffffffffffffffffffffffffffffffffffffffff168486604051610ee691906111e4565b60006040518083038185875af1925050503d8060008114610f23576040519150601f19603f3d011682016040523d82523d6000602084013e610f28565b606091505b5091509150610f38868383610f42565b9695505050505050565b606082610f5757610f5282610fd1565b6105a7565b8151158015610f7b575073ffffffffffffffffffffffffffffffffffffffff84163b155b15610fca576040517f9996b31500000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff85166004820152602401610640565b50806105a7565b805115610fe15780518082602001fd5b6040517f1425ea4200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006020828403121561102557600080fd5b81357fffffffff00000000000000000000000000000000000000000000000000000000811681146105a757600080fd5b803573ffffffffffffffffffffffffffffffffffffffff8116811461107957600080fd5b919050565b6000806040838503121561109157600080fd5b61109a83611055565b91506110a860208401611055565b90509250929050565b6000602082840312156110c357600080fd5b5035919050565b600080604083850312156110dd57600080fd5b823591506110a860208401611055565b6000806040838503121561110057600080fd5b50508035926020909101359150565b60006020828403121561112157600080fd5b6105a782611055565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60006020828403121561116b57600080fd5b815180151581146105a757600080fd5b81810381811115610417577f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fd5b6000825160005b8181101561120557602081860181015185830152016111eb565b50600092019182525091905056fea2646970667358221220cf33c3d4da69e4a6aeddfcb46cd394bfc44899f75312d31fd8c8e38dff96ab9764736f6c63430008180033","runtime-code":"0x608060405234801561001057600080fd5b50600436106101775760003560e01c806391d14854116100d8578063bf333f2c1161008c578063d547741f11610066578063d547741f14610385578063dcf844a714610398578063e00a83e0146103b857600080fd5b8063bf333f2c14610341578063ca15c8731461034b578063ccc574901461035e57600080fd5b8063a217fddf116100bd578063a217fddf14610313578063b13aa2d61461031b578063b250fe6b1461032e57600080fd5b806391d14854146102a8578063926d7d7f146102ec57600080fd5b80632f2ff15d1161012f57806358f858801161011457806358f85880146102405780635960ccf2146102495780639010d07c1461027057600080fd5b80632f2ff15d1461021a57806336568abe1461022d57600080fd5b806306f333f21161016057806306f333f2146101d95780630f5f6ed7146101ee578063248a9ca3146101f757600080fd5b806301ffc9a71461017c57806303ed0ee5146101a4575b600080fd5b61018f61018a366004611013565b6103c1565b60405190151581526020015b60405180910390f35b6101cb7f043c983c49d46f0e102151eaf8085d4a2e6571d5df2d47b013f39bddfd4a639d81565b60405190815260200161019b565b6101ec6101e736600461107e565b61041d565b005b6101cb61271081565b6101cb6102053660046110b1565b60009081526020819052604090206001015490565b6101ec6102283660046110ca565b61050b565b6101ec61023b3660046110ca565b610536565b6101cb60025481565b6101cb7fdb9556138406326f00296e13ea2ad7db24ba82381212d816b1a40c23b466b32781565b61028361027e3660046110ed565b61058f565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200161019b565b61018f6102b63660046110ca565b60009182526020828152604080842073ffffffffffffffffffffffffffffffffffffffff93909316845291905290205460ff1690565b6101cb7fe2b7fb3b832174769106daebcfd6d1970523240dda11281102db9363b83b0dc481565b6101cb600081565b6101ec6103293660046110b1565b6105ae565b6101ec61033c3660046110b1565b610690565b6101cb620f424081565b6101cb6103593660046110b1565b6106f8565b6101cb7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f5581565b6101ec6103933660046110ca565b61070f565b6101cb6103a636600461110f565b60036020526000908152604090205481565b6101cb60045481565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f5a05180f000000000000000000000000000000000000000000000000000000001480610417575061041782610734565b92915050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f55610447816107cb565b73ffffffffffffffffffffffffffffffffffffffff83166000908152600360205260408120549081900361047b5750505050565b73ffffffffffffffffffffffffffffffffffffffff84166000818152600360205260408120556104ac9084836107d8565b6040805173ffffffffffffffffffffffffffffffffffffffff8087168252851660208201529081018290527f244e51bc38c1452fa8aaf487bcb4bca36c2baa3a5fbdb776b1eabd8dc6d277cd9060600160405180910390a1505b505050565b600082815260208190526040902060010154610526816107cb565b610530838361092f565b50505050565b73ffffffffffffffffffffffffffffffffffffffff81163314610585576040517f6697b23200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6105068282610964565b60008281526001602052604081206105a79083610991565b9392505050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f556105d8816107cb565b612710821115610649576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f6e657746656552617465203e206d61780000000000000000000000000000000060448201526064015b60405180910390fd5b600280549083905560408051828152602081018590527f14914da2bf76024616fbe1859783fcd4dbddcb179b1f3a854949fbf920dcb95791015b60405180910390a1505050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f556106ba816107cb565b600480549083905560408051828152602081018590527f5cf09b12f3f56b4c564d51b25b40360af6d795198adb61ae0806a36c294323fa9101610683565b60008181526001602052604081206104179061099d565b60008281526020819052604090206001015461072a816107cb565b6105308383610964565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f7965db0b00000000000000000000000000000000000000000000000000000000148061041757507f01ffc9a7000000000000000000000000000000000000000000000000000000007fffffffff00000000000000000000000000000000000000000000000000000000831614610417565b6107d581336109a7565b50565b3073ffffffffffffffffffffffffffffffffffffffff8316036107fa57505050565b8060000361080757505050565b7fffffffffffffffffffffffff111111111111111111111111111111111111111273ffffffffffffffffffffffffffffffffffffffff84160161090e5760008273ffffffffffffffffffffffffffffffffffffffff168260405160006040518083038185875af1925050503d806000811461089e576040519150601f19603f3d011682016040523d82523d6000602084013e6108a3565b606091505b5050905080610530576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f455448207472616e73666572206661696c6564000000000000000000000000006044820152606401610640565b61050673ffffffffffffffffffffffffffffffffffffffff84168383610a31565b60008061093c8484610abe565b905080156105a757600084815260016020526040902061095c9084610bba565b509392505050565b6000806109718484610bdc565b905080156105a757600084815260016020526040902061095c9084610c97565b60006105a78383610cb9565b6000610417825490565b60008281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915290205460ff16610a2d576040517fe2517d3f00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8216600482015260248101839052604401610640565b5050565b6040805173ffffffffffffffffffffffffffffffffffffffff8416602482015260448082018490528251808303909101815260649091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fa9059cbb00000000000000000000000000000000000000000000000000000000179052610506908490610ce3565b60008281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915281205460ff16610bb25760008381526020818152604080832073ffffffffffffffffffffffffffffffffffffffff86168452909152902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055610b503390565b73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16847f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a4506001610417565b506000610417565b60006105a78373ffffffffffffffffffffffffffffffffffffffff8416610d79565b60008281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915281205460ff1615610bb25760008381526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8616808552925280832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016905551339286917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a4506001610417565b60006105a78373ffffffffffffffffffffffffffffffffffffffff8416610dc0565b6000826000018281548110610cd057610cd061112a565b9060005260206000200154905092915050565b6000610d0573ffffffffffffffffffffffffffffffffffffffff841683610eb3565b90508051600014158015610d2a575080806020019051810190610d289190611159565b155b15610506576040517f5274afe700000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff84166004820152602401610640565b6000818152600183016020526040812054610bb257508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155610417565b60008181526001830160205260408120548015610ea9576000610de460018361117b565b8554909150600090610df89060019061117b565b9050808214610e5d576000866000018281548110610e1857610e1861112a565b9060005260206000200154905080876000018481548110610e3b57610e3b61112a565b6000918252602080832090910192909255918252600188019052604090208390555b8554869080610e6e57610e6e6111b5565b600190038181906000526020600020016000905590558560010160008681526020019081526020016000206000905560019350505050610417565b6000915050610417565b60606105a783836000846000808573ffffffffffffffffffffffffffffffffffffffff168486604051610ee691906111e4565b60006040518083038185875af1925050503d8060008114610f23576040519150601f19603f3d011682016040523d82523d6000602084013e610f28565b606091505b5091509150610f38868383610f42565b9695505050505050565b606082610f5757610f5282610fd1565b6105a7565b8151158015610f7b575073ffffffffffffffffffffffffffffffffffffffff84163b155b15610fca576040517f9996b31500000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff85166004820152602401610640565b50806105a7565b805115610fe15780518082602001fd5b6040517f1425ea4200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006020828403121561102557600080fd5b81357fffffffff00000000000000000000000000000000000000000000000000000000811681146105a757600080fd5b803573ffffffffffffffffffffffffffffffffffffffff8116811461107957600080fd5b919050565b6000806040838503121561109157600080fd5b61109a83611055565b91506110a860208401611055565b90509250929050565b6000602082840312156110c357600080fd5b5035919050565b600080604083850312156110dd57600080fd5b823591506110a860208401611055565b6000806040838503121561110057600080fd5b50508035926020909101359150565b60006020828403121561112157600080fd5b6105a782611055565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60006020828403121561116b57600080fd5b815180151581146105a757600080fd5b81810381811115610417577f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fd5b6000825160005b8181101561120557602081860181015185830152016111eb565b50600092019182525091905056fea2646970667358221220cf33c3d4da69e4a6aeddfcb46cd394bfc44899f75312d31fd8c8e38dff96ab9764736f6c63430008180033","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.24 ^0.8.20 ^0.8.4;\n\n// contracts/interfaces/IAdmin.sol\n\ninterface IAdmin {\n // ============ Events ============\n\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n event ChainGasAmountUpdated(uint256 oldChainGasAmount, uint256 newChainGasAmount);\n\n // ============ Methods ============\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n\n function setChainGasAmount(uint256 newChainGasAmount) external;\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IFastBridgeV2Errors.sol\n\ninterface IFastBridgeV2Errors {\n error AmountIncorrect();\n error ChainIncorrect();\n error ExclusivityParamsIncorrect();\n error MsgValueIncorrect();\n error SenderIncorrect();\n error StatusIncorrect();\n error TokenNotContract();\n error ZapDataLengthAboveMax();\n error ZapNativeNotSupported();\n error ZeroAddress();\n\n error RecipientIncorrectReturnValue();\n error RecipientNoReturnValue();\n\n error DeadlineExceeded();\n error DeadlineNotExceeded();\n error DeadlineTooShort();\n error DisputePeriodNotPassed();\n error DisputePeriodPassed();\n error ExclusivityPeriodNotPassed();\n\n error TransactionRelayed();\n}\n\n// contracts/interfaces/IMulticallTarget.sol\n\n/// @notice Interface for a contract that can be called multiple times by the same caller. Inspired by MulticallV3:\n/// https://github.com/mds1/multicall/blob/master/src/Multicall3.sol\ninterface IMulticallTarget {\n struct Result {\n bool success;\n bytes returnData;\n }\n\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external;\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results);\n}\n\n// contracts/interfaces/IZapRecipient.sol\n\ninterface IZapRecipient {\n function zap(address token, uint256 amount, bytes memory zapData) external payable returns (bytes4);\n}\n\n// contracts/libs/Errors.sol\n\nerror DeadlineExceeded();\nerror DeadlineNotExceeded();\nerror DeadlineTooShort();\nerror InsufficientOutputAmount();\n\nerror MsgValueIncorrect();\nerror PoolNotFound();\nerror TokenAddressMismatch();\nerror TokenNotContract();\nerror TokenNotETH();\nerror TokensIdentical();\n\nerror ChainIncorrect();\nerror AmountIncorrect();\nerror ZeroAddress();\n\nerror DisputePeriodNotPassed();\nerror DisputePeriodPassed();\nerror SenderIncorrect();\nerror StatusIncorrect();\nerror TransactionIdIncorrect();\nerror TransactionRelayed();\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// contracts/interfaces/IFastBridgeV2.sol\n\ninterface IFastBridgeV2 is IFastBridge {\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n struct BridgeTxDetails {\n BridgeStatus status;\n uint32 destChainId;\n uint56 proofBlockTimestamp;\n address proofRelayer;\n }\n\n struct BridgeRelay {\n uint48 blockNumber;\n uint48 blockTimestamp;\n address relayer;\n }\n\n /// @notice New params introduced in the FastBridgeV2.\n /// We are passing fields from the older BridgeParams struct outside of this struct\n /// for backwards compatibility.\n /// Note: quoteRelayer and quoteExclusivitySeconds are either both zero (indicating no exclusivity)\n /// or both non-zero (indicating exclusivity for the given period).\n /// Note: zapNative \u003e 0 can NOT be used with destToken = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE (native token)\n /// @param quoteRelayer Relayer that provided the quote for the transaction\n /// @param quoteExclusivitySeconds Period of time the quote relayer is guaranteed exclusivity after user's deposit\n /// @param quoteId Unique quote identifier used for tracking the quote\n /// @param zapNative ETH value to send to the recipient (if any)\n /// @param zapData Parameters for the Zap to the destination recipient (if any)\n struct BridgeParamsV2 {\n address quoteRelayer;\n int256 quoteExclusivitySeconds;\n bytes quoteId;\n uint256 zapNative;\n bytes zapData;\n }\n\n /// @notice Updated bridge transaction struct to include parameters introduced in FastBridgeV2.\n /// Note: only `exclusivityRelayer` can fill such a transaction until `exclusivityEndTime`.\n struct BridgeTransactionV2 {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n // Note: sendChainGas flag from V1 is deprecated\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n address exclusivityRelayer;\n uint256 exclusivityEndTime;\n uint256 zapNative; // ETH value to send to the recipient (if any)\n bytes zapData; // data to pass for the Zap action (if any)\n }\n\n event BridgeQuoteDetails(bytes32 indexed transactionId, bytes quoteId);\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability\n /// to provide temporary exclusivity fill rights for the quote relayer.\n /// @param params The parameters required to bridge\n /// @param paramsV2 The parameters for exclusivity fill rights (optional, can be left empty)\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function relay(bytes memory request, address relayer) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param transactionId The transaction id associated with the encoded bridge transaction to prove\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital.\n /// @notice Can only send funds to the relayer address on the proof.\n /// @param request The encoded bridge transaction to claim on origin chain\n function claim(bytes memory request) external;\n /// @notice Checks if a transaction has been relayed\n /// @param transactionId The ID of the transaction to check\n /// @return True if the transaction has been relayed, false otherwise\n function bridgeRelays(bytes32 transactionId) external view returns (bool);\n\n /// @notice Returns the status of a bridge transaction\n /// @param transactionId The ID of the bridge transaction\n /// @return BridgeStatus Status of the bridge transaction\n function bridgeStatuses(bytes32 transactionId) external view returns (BridgeStatus);\n\n /// @notice Returns the timestamp and relayer of a bridge proof\n /// @param transactionId The ID of the bridge transaction\n /// @return timestamp The timestamp of the bridge proof\n /// @return relayer The relayer address of the bridge proof\n function bridgeProofs(bytes32 transactionId) external view returns (uint96 timestamp, address relayer);\n\n /// @notice Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\n /// @param request The bridge request to decode\n function getBridgeTransactionV2(bytes memory request) external view returns (BridgeTransactionV2 memory);\n}\n\n// contracts/utils/MulticallTarget.sol\n\n// solhint-disable avoid-low-level-calls\n/// @notice Template for a contract that supports batched calls (preserving the msg.sender).\n/// Only calls with zero msg.value could be batched.\nabstract contract MulticallTarget is IMulticallTarget {\n error MulticallTarget__UndeterminedRevert();\n\n /// @notice Perform a batched call to this contract, preserving the msg.sender.\n /// The return data from each call is discarded.\n /// @dev The method is non-payable, so only calls with `msg.value == 0` could be batched.\n /// It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag.\n /// Otherwise, the whole batch call will be reverted with the original revert reason.\n /// @param data List of abi-encoded calldata for the calls to perform.\n /// @param ignoreReverts Whether to ignore the revert errors from the calls.\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external {\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\n if (!success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(result);\n }\n }\n }\n\n /// @notice Perform a batched call to this contract, preserving the msg.sender.\n /// The return data from each call is preserved.\n /// @dev The method is non-payable, so only calls with `msg.value == 0` could be batched.\n /// It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag.\n /// Otherwise, the whole batch call will be reverted with the original revert reason.\n /// @param data List of abi-encoded calldata for the calls to perform.\n /// @param ignoreReverts Whether to ignore the revert errors from the calls.\n /// @return results List of results from the calls: `(success, returnData)`.\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results)\n {\n results = new Result[](data.length);\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (results[i].success, results[i].returnData) = address(this).delegatecall(data[i]);\n if (!results[i].success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(results[i].returnData);\n }\n }\n }\n\n /// @dev Bubbles the revert message from the underlying call.\n /// Note: preserves the same custom error or revert string, if one was used.\n /// Source: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v5.0.2/contracts/utils/Address.sol#L143-L158\n function _bubbleRevert(bytes memory returnData) internal pure {\n // Look for revert reason and bubble it up if present\n if (returnData.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n // solhint-disable-next-line no-inline-assembly\n assembly {\n let returndata_size := mload(returnData)\n revert(add(32, returnData), returndata_size)\n }\n } else {\n revert MulticallTarget__UndeterminedRevert();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// contracts/libs/BridgeTransactionV2.sol\n\n// solhint-disable no-inline-assembly\nlibrary BridgeTransactionV2Lib {\n uint16 internal constant VERSION = 2;\n\n // Offsets of the fields in the packed BridgeTransactionV2 struct\n // uint16 version [000 .. 002)\n // uint32 originChainId [002 .. 006)\n // uint32 destChainId [006 .. 010)\n // address originSender [010 .. 030)\n // address destRecipient [030 .. 050)\n // address originToken [050 .. 070)\n // address destToken [070 .. 090)\n // uint256 originAmount [090 .. 122)\n // uint256 destAmount [122 .. 154)\n // uint256 originFeeAmount [154 .. 186)\n // uint256 deadline [186 .. 218)\n // uint256 nonce [218 .. 250)\n // address exclusivityRelayer [250 .. 270)\n // uint256 exclusivityEndTime [270 .. 302)\n // uint256 zapNative [302 .. 334)\n // bytes zapData [334 .. ***)\n\n // forgefmt: disable-start\n uint256 private constant OFFSET_ORIGIN_CHAIN_ID = 2;\n uint256 private constant OFFSET_DEST_CHAIN_ID = 6;\n uint256 private constant OFFSET_ORIGIN_SENDER = 10;\n uint256 private constant OFFSET_DEST_RECIPIENT = 30;\n uint256 private constant OFFSET_ORIGIN_TOKEN = 50;\n uint256 private constant OFFSET_DEST_TOKEN = 70;\n uint256 private constant OFFSET_ORIGIN_AMOUNT = 90;\n uint256 private constant OFFSET_DEST_AMOUNT = 122;\n uint256 private constant OFFSET_ORIGIN_FEE_AMOUNT = 154;\n uint256 private constant OFFSET_DEADLINE = 186;\n uint256 private constant OFFSET_NONCE = 218;\n uint256 private constant OFFSET_EXCLUSIVITY_RELAYER = 250;\n uint256 private constant OFFSET_EXCLUSIVITY_END_TIME = 270;\n uint256 private constant OFFSET_ZAP_NATIVE = 302;\n uint256 private constant OFFSET_ZAP_DATA = 334;\n // forgefmt: disable-end\n\n error BridgeTransactionV2__InvalidEncodedTx();\n error BridgeTransactionV2__UnsupportedVersion(uint16 version);\n\n /// @notice Validates the encoded transaction to be a tightly packed encoded payload for BridgeTransactionV2.\n /// @dev Checks the minimum length and the version, use this function before decoding any of the fields.\n function validateV2(bytes calldata encodedTx) internal pure {\n // Check the minimum length: must at least include all static fields.\n if (encodedTx.length \u003c OFFSET_ZAP_DATA) revert BridgeTransactionV2__InvalidEncodedTx();\n // Once we validated the length, we can be sure that the version field is present.\n uint16 version_ = version(encodedTx);\n if (version_ != VERSION) revert BridgeTransactionV2__UnsupportedVersion(version_);\n }\n\n /// @notice Encodes the BridgeTransactionV2 struct by tightly packing the fields.\n /// @dev `abi.decode` will not work as a result of the tightly packed fields. Use `decodeV2` to decode instead.\n function encodeV2(IFastBridgeV2.BridgeTransactionV2 memory bridgeTx) internal pure returns (bytes memory) {\n // We split the encoding into two parts to avoid stack-too-deep error\n bytes memory firstPart = abi.encodePacked(\n VERSION,\n bridgeTx.originChainId,\n bridgeTx.destChainId,\n bridgeTx.originSender,\n bridgeTx.destRecipient,\n bridgeTx.originToken,\n bridgeTx.destToken,\n bridgeTx.originAmount\n );\n return abi.encodePacked(\n firstPart,\n bridgeTx.destAmount,\n bridgeTx.originFeeAmount,\n // Note: we skip the deprecated `sendChainGas` flag, which was present in BridgeTransaction V1\n bridgeTx.deadline,\n bridgeTx.nonce,\n // New V2 fields: exclusivity\n bridgeTx.exclusivityRelayer,\n bridgeTx.exclusivityEndTime,\n // New V2 fields: Zap\n bridgeTx.zapNative,\n bridgeTx.zapData\n );\n }\n\n /// @notice Decodes the BridgeTransactionV2 struct from the encoded transaction.\n /// @dev Encoded BridgeTransactionV2 struct must be tightly packed.\n /// Use `validateV2` before decoding to ensure the encoded transaction is valid.\n function decodeV2(bytes calldata encodedTx)\n internal\n pure\n returns (IFastBridgeV2.BridgeTransactionV2 memory bridgeTx)\n {\n bridgeTx.originChainId = originChainId(encodedTx);\n bridgeTx.destChainId = destChainId(encodedTx);\n bridgeTx.originSender = originSender(encodedTx);\n bridgeTx.destRecipient = destRecipient(encodedTx);\n bridgeTx.originToken = originToken(encodedTx);\n bridgeTx.destToken = destToken(encodedTx);\n bridgeTx.originAmount = originAmount(encodedTx);\n bridgeTx.destAmount = destAmount(encodedTx);\n bridgeTx.originFeeAmount = originFeeAmount(encodedTx);\n bridgeTx.deadline = deadline(encodedTx);\n bridgeTx.nonce = nonce(encodedTx);\n bridgeTx.exclusivityRelayer = exclusivityRelayer(encodedTx);\n bridgeTx.exclusivityEndTime = exclusivityEndTime(encodedTx);\n bridgeTx.zapNative = zapNative(encodedTx);\n bridgeTx.zapData = zapData(encodedTx);\n }\n\n /// @notice Extracts the version from the encoded transaction.\n function version(bytes calldata encodedTx) internal pure returns (uint16 version_) {\n // Load 32 bytes from the start and shift it 240 bits to the right to get the highest 16 bits.\n assembly {\n version_ := shr(240, calldataload(encodedTx.offset))\n }\n }\n\n /// @notice Extracts the origin chain ID from the encoded transaction.\n function originChainId(bytes calldata encodedTx) internal pure returns (uint32 originChainId_) {\n // Load 32 bytes from the offset and shift it 224 bits to the right to get the highest 32 bits.\n assembly {\n originChainId_ := shr(224, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_CHAIN_ID)))\n }\n }\n\n /// @notice Extracts the destination chain ID from the encoded transaction.\n function destChainId(bytes calldata encodedTx) internal pure returns (uint32 destChainId_) {\n // Load 32 bytes from the offset and shift it 224 bits to the right to get the highest 32 bits.\n assembly {\n destChainId_ := shr(224, calldataload(add(encodedTx.offset, OFFSET_DEST_CHAIN_ID)))\n }\n }\n\n /// @notice Extracts the origin sender from the encoded transaction.\n function originSender(bytes calldata encodedTx) internal pure returns (address originSender_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n originSender_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_SENDER)))\n }\n }\n\n /// @notice Extracts the destination recipient from the encoded transaction.\n function destRecipient(bytes calldata encodedTx) internal pure returns (address destRecipient_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n destRecipient_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_DEST_RECIPIENT)))\n }\n }\n\n /// @notice Extracts the origin token from the encoded transaction.\n function originToken(bytes calldata encodedTx) internal pure returns (address originToken_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n originToken_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_TOKEN)))\n }\n }\n\n /// @notice Extracts the destination token from the encoded transaction.\n function destToken(bytes calldata encodedTx) internal pure returns (address destToken_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n destToken_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_DEST_TOKEN)))\n }\n }\n\n /// @notice Extracts the origin amount from the encoded transaction.\n function originAmount(bytes calldata encodedTx) internal pure returns (uint256 originAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n originAmount_ := calldataload(add(encodedTx.offset, OFFSET_ORIGIN_AMOUNT))\n }\n }\n\n /// @notice Extracts the destination amount from the encoded transaction.\n function destAmount(bytes calldata encodedTx) internal pure returns (uint256 destAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n destAmount_ := calldataload(add(encodedTx.offset, OFFSET_DEST_AMOUNT))\n }\n }\n\n /// @notice Extracts the origin fee amount from the encoded transaction.\n function originFeeAmount(bytes calldata encodedTx) internal pure returns (uint256 originFeeAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n originFeeAmount_ := calldataload(add(encodedTx.offset, OFFSET_ORIGIN_FEE_AMOUNT))\n }\n }\n\n /// @notice Extracts the deadline from the encoded transaction.\n function deadline(bytes calldata encodedTx) internal pure returns (uint256 deadline_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n deadline_ := calldataload(add(encodedTx.offset, OFFSET_DEADLINE))\n }\n }\n\n /// @notice Extracts the nonce from the encoded transaction.\n function nonce(bytes calldata encodedTx) internal pure returns (uint256 nonce_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n nonce_ := calldataload(add(encodedTx.offset, OFFSET_NONCE))\n }\n }\n\n /// @notice Extracts the exclusivity relayer from the encoded transaction.\n function exclusivityRelayer(bytes calldata encodedTx) internal pure returns (address exclusivityRelayer_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n exclusivityRelayer_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_EXCLUSIVITY_RELAYER)))\n }\n }\n\n /// @notice Extracts the exclusivity end time from the encoded transaction.\n function exclusivityEndTime(bytes calldata encodedTx) internal pure returns (uint256 exclusivityEndTime_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n exclusivityEndTime_ := calldataload(add(encodedTx.offset, OFFSET_EXCLUSIVITY_END_TIME))\n }\n }\n\n /// @notice Extracts the Zap's native value from the encoded transaction.\n function zapNative(bytes calldata encodedTx) internal pure returns (uint256 zapNative_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n zapNative_ := calldataload(add(encodedTx.offset, OFFSET_ZAP_NATIVE))\n }\n }\n\n /// @notice Extracts the Zap's data from the encoded transaction.\n function zapData(bytes calldata encodedTx) internal pure returns (bytes calldata zapData_) {\n zapData_ = encodedTx[OFFSET_ZAP_DATA:];\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// contracts/libs/UniversalToken.sol\n\nlibrary UniversalTokenLib {\n using SafeERC20 for IERC20;\n\n address internal constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Transfers tokens to the given account. Reverts if transfer is not successful.\n /// @dev This might trigger fallback, if ETH is transferred to the contract.\n /// Make sure this can not lead to reentrancy attacks.\n function universalTransfer(address token, address to, uint256 value) internal {\n // Don't do anything, if need to send tokens to this address\n if (to == address(this)) return;\n // Don't do anything, if trying to send zero value\n if (value == 0) return;\n if (token == ETH_ADDRESS) {\n /// @dev Note: this can potentially lead to executing code in `to`.\n // solhint-disable-next-line avoid-low-level-calls\n (bool success,) = to.call{value: value}(\"\");\n require(success, \"ETH transfer failed\");\n } else {\n IERC20(token).safeTransfer(to, value);\n }\n }\n\n /// @notice Issues an infinite allowance to the spender, if the current allowance is insufficient\n /// to spend the given amount.\n function universalApproveInfinity(address token, address spender, uint256 amountToSpend) internal {\n // ETH Chad doesn't require your approval\n if (token == ETH_ADDRESS) return;\n // No-op if allowance is already sufficient\n uint256 allowance = IERC20(token).allowance(address(this), spender);\n if (allowance \u003e= amountToSpend) return;\n // Otherwise, reset approval to 0 and set to max allowance\n if (allowance \u003e 0) IERC20(token).safeDecreaseAllowance(spender, allowance);\n IERC20(token).safeIncreaseAllowance(spender, type(uint256).max);\n }\n\n /// @notice Returns the balance of the given token (or native ETH) for the given account.\n function universalBalanceOf(address token, address account) internal view returns (uint256) {\n if (token == ETH_ADDRESS) {\n return account.balance;\n } else {\n return IERC20(token).balanceOf(account);\n }\n }\n\n /// @dev Checks that token is a contract and not ETH_ADDRESS.\n function assertIsContract(address token) internal view {\n // Check that ETH_ADDRESS was not used (in case this is a predeploy on any of the chains)\n if (token == UniversalTokenLib.ETH_ADDRESS) revert TokenNotContract();\n // Check that token is not an EOA\n if (token.code.length == 0) revert TokenNotContract();\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/Admin.sol\n\ncontract Admin is IAdmin, AccessControlEnumerable {\n using UniversalTokenLib for address;\n\n bytes32 public constant RELAYER_ROLE = keccak256(\"RELAYER_ROLE\");\n bytes32 public constant REFUNDER_ROLE = keccak256(\"REFUNDER_ROLE\");\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n uint256 public constant FEE_BPS = 1e6;\n uint256 public constant FEE_RATE_MAX = 0.01e6; // max 1% on origin amount\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Chain gas amount to forward as rebate if requested\n uint256 public chainGasAmount;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n }\n\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n require(newFeeRate \u003c= FEE_RATE_MAX, \"newFeeRate \u003e max\");\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n token.universalTransfer(recipient, feeAmount);\n emit FeesSwept(token, recipient, feeAmount);\n }\n\n function setChainGasAmount(uint256 newChainGasAmount) external onlyRole(GOVERNOR_ROLE) {\n uint256 oldChainGasAmount = chainGasAmount;\n chainGasAmount = newChainGasAmount;\n emit ChainGasAmountUpdated(oldChainGasAmount, newChainGasAmount);\n }\n}\n\n// contracts/FastBridgeV2.sol\n\n/// @notice FastBridgeV2 is a contract for bridging tokens across chains.\ncontract FastBridgeV2 is Admin, MulticallTarget, IFastBridgeV2, IFastBridgeV2Errors {\n using BridgeTransactionV2Lib for bytes;\n using SafeERC20 for IERC20;\n\n /// @notice Address reserved for native gas token (ETH on Ethereum and most L2s, AVAX on Avalanche, etc)\n address public constant NATIVE_GAS_TOKEN = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Delay for a transaction after which it could be permisionlessly refunded\n uint256 public constant REFUND_DELAY = 7 days;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n /// @notice Maximum length of accepted zapData\n uint256 public constant MAX_ZAP_DATA_LENGTH = 2 ** 16 - 1;\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeTxDetails) public bridgeTxDetails;\n /// @notice Relay details on destination chain\n mapping(bytes32 =\u003e BridgeRelay) public bridgeRelayDetails;\n /// @notice Unique bridge nonces tracked per originSender\n mapping(address =\u003e uint256) public senderNonces;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Replaced by senderNonces\n uint256 public immutable nonce = 0;\n /// @notice the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n bridge({\n params: params,\n paramsV2: BridgeParamsV2({\n quoteRelayer: address(0),\n quoteExclusivitySeconds: 0,\n quoteId: bytes(\"\"),\n zapNative: 0,\n zapData: bytes(\"\")\n })\n });\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes calldata request) external payable {\n // relay override will validate the request\n relay({request: request, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes calldata request, bytes32 destTxHash) external {\n request.validateV2();\n prove({transactionId: keccak256(request), destTxHash: destTxHash, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridgeV2\n function claim(bytes calldata request) external {\n // claim override will validate the request\n claim({request: request, to: address(0)});\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Aggregate the read operations from the same storage slot\n address disputedRelayer = $.proofRelayer;\n BridgeStatus status = $.status;\n uint56 proofBlockTimestamp = $.proofBlockTimestamp;\n // Can only dispute a RELAYER_PROVED transaction within the dispute period\n if (status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(proofBlockTimestamp) \u003e DISPUTE_PERIOD) {\n revert DisputePeriodPassed();\n }\n // Update status to REQUESTED and delete the disputed proof details\n // Note: these are storage writes\n $.status = BridgeStatus.REQUESTED;\n $.proofRelayer = address(0);\n $.proofBlockTimestamp = 0;\n\n emit BridgeProofDisputed(transactionId, disputedRelayer);\n }\n\n /// @inheritdoc IFastBridge\n function refund(bytes calldata request) external {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Can only refund a REQUESTED transaction after its deadline expires\n if ($.status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n uint256 deadline = request.deadline();\n // Permissionless refund is only allowed after REFUND_DELAY on top of the deadline\n if (!hasRole(REFUNDER_ROLE, msg.sender)) deadline += REFUND_DELAY;\n if (block.timestamp \u003c= deadline) revert DeadlineNotExceeded();\n // Update status to REFUNDED and return the full amount (collateral + protocol fees) to the original sender.\n // The protocol fees are only updated when the transaction is claimed, so we don't need to update them here.\n // Note: this is a storage write\n $.status = BridgeStatus.REFUNDED;\n\n address to = request.originSender();\n address token = request.originToken();\n uint256 amount = request.originAmount() + request.originFeeAmount();\n // Emit the event before any external calls\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n // Complete the user refund as the last transaction action\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(to), amount);\n } else {\n IERC20(token).safeTransfer(to, amount);\n }\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // The correct relayer can only claim a RELAYER_PROVED transaction after the dispute period\n if ($.status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if ($.proofRelayer != relayer) revert SenderIncorrect();\n return _timeSince($.proofBlockTimestamp) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n /// @dev This method is added to achieve backwards compatibility with decoding requests into V1 structs:\n /// - `zapNative` is partially reported as a zero/non-zero flag\n /// - `zapData` is ignored\n /// In order to process all kinds of requests use getBridgeTransactionV2 instead.\n function getBridgeTransaction(bytes calldata request) external view returns (BridgeTransaction memory) {\n // Try decoding into V2 struct first. This will revert if V1 struct is passed\n try this.getBridgeTransactionV2(request) returns (BridgeTransactionV2 memory txV2) {\n // Note: we entirely ignore the zapData field, as it was not present in V1\n return BridgeTransaction({\n originChainId: txV2.originChainId,\n destChainId: txV2.destChainId,\n originSender: txV2.originSender,\n destRecipient: txV2.destRecipient,\n originToken: txV2.originToken,\n destToken: txV2.destToken,\n originAmount: txV2.originAmount,\n destAmount: txV2.destAmount,\n originFeeAmount: txV2.originFeeAmount,\n sendChainGas: txV2.zapNative != 0,\n deadline: txV2.deadline,\n nonce: txV2.nonce\n });\n } catch {\n // Fallback to V1 struct\n return abi.decode(request, (BridgeTransaction));\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function getBridgeTransactionV2(bytes calldata request) external pure returns (BridgeTransactionV2 memory) {\n request.validateV2();\n return BridgeTransactionV2Lib.decodeV2(request);\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) public payable {\n int256 exclusivityEndTime = 0;\n // if relayer exclusivity is not intended for this bridge, set exclusivityEndTime to static zero\n // otherwise, set exclusivity to expire at the current block ts offset by quoteExclusivitySeconds\n if (paramsV2.quoteRelayer != address(0)) {\n exclusivityEndTime = int256(block.timestamp) + paramsV2.quoteExclusivitySeconds;\n }\n _validateBridgeParams(params, paramsV2, exclusivityEndTime);\n\n // transfer tokens to bridge contract\n /// @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _takeBridgedUserAsset(params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) {\n originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n }\n\n // set status to requested\n bytes memory request = BridgeTransactionV2Lib.encodeV2(\n BridgeTransactionV2({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n deadline: params.deadline,\n nonce: senderNonces[params.sender]++, // increment nonce on every bridge\n exclusivityRelayer: paramsV2.quoteRelayer,\n // We checked exclusivityEndTime to be in range [0 .. params.deadline] above, so can safely cast\n exclusivityEndTime: uint256(exclusivityEndTime),\n zapNative: paramsV2.zapNative,\n zapData: paramsV2.zapData\n })\n );\n bytes32 transactionId = keccak256(request);\n // Note: the tx status will be updated throughout the tx lifecycle, while destChainId is set once here\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n bridgeTxDetails[transactionId].destChainId = params.dstChainId;\n\n emit BridgeRequested({\n transactionId: transactionId,\n sender: params.sender,\n request: request,\n destChainId: params.dstChainId,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n sendChainGas: paramsV2.zapNative != 0\n });\n emit BridgeQuoteDetails(transactionId, paramsV2.quoteId);\n }\n\n /// @inheritdoc IFastBridgeV2\n function relay(bytes calldata request, address relayer) public payable {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n _validateRelayParams(request, transactionId, relayer);\n // mark bridge transaction as relayed\n bridgeRelayDetails[transactionId] =\n BridgeRelay({blockNumber: uint48(block.number), blockTimestamp: uint48(block.timestamp), relayer: relayer});\n\n // transfer tokens to recipient on destination chain and trigger Zap if requested\n address to = request.destRecipient();\n address token = request.destToken();\n uint256 amount = request.destAmount();\n uint256 zapNative = request.zapNative();\n\n // Emit the event before any external calls\n emit BridgeRelayed({\n transactionId: transactionId,\n relayer: relayer,\n to: to,\n originChainId: request.originChainId(),\n originToken: request.originToken(),\n destToken: token,\n originAmount: request.originAmount(),\n destAmount: amount,\n chainGasAmount: zapNative\n });\n\n // All state changes have been done at this point, can proceed to the external calls.\n // This follows the checks-effects-interactions pattern to mitigate potential reentrancy attacks.\n if (token == NATIVE_GAS_TOKEN) {\n // For the native gas token, additional zapNative is not allowed\n if (zapNative != 0) revert ZapNativeNotSupported();\n // Check that the correct msg.value was sent\n if (msg.value != amount) revert MsgValueIncorrect();\n // Don't do a native transfer yet: we will handle it alongside the Zap below\n } else {\n // For ERC20s, we check that the correct msg.value was sent\n if (msg.value != zapNative) revert MsgValueIncorrect();\n // We need to transfer the tokens from the Relayer to the recipient first before performing an\n // optional post-transfer Zap.\n IERC20(token).safeTransferFrom(msg.sender, to, amount);\n }\n // At this point we have done:\n // - Transferred the requested amount of ERC20 tokens to the recipient.\n // At this point we have confirmed:\n // - For ERC20s: msg.value matches the requested zapNative amount.\n // - For the native gas token: msg.value matches the requested destAmount.\n // Remaining optional things to do:\n // - Forward the full msg.value to the recipient (if non-zero).\n // - Trigger a Zap (if zapData is present).\n bytes calldata zapData = request.zapData();\n if (zapData.length != 0) {\n // Zap Data is present: Zap has been requested by the recipient. Trigger it forwarding the full msg.value.\n\n // Note: if token has a fee on transfers, the recipient will have received less than `amount`.\n // This is a very niche edge case and should be handled by the recipient contract.\n _triggerZapWithChecks({recipient: to, token: token, amount: amount, zapData: zapData});\n } else if (msg.value != 0) {\n // Zap Data is missing, but msg.value was sent. This could happen in two different cases:\n // - Relay with the native gas token is happening.\n // - Relay with ERC20 is happening, with a `zapNative \u003e 0` request.\n // In both cases, we need to transfer the full msg.value to the recipient.\n Address.sendValue(payable(to), msg.value);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) public onlyRole(RELAYER_ROLE) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n\n // Can only prove a REQUESTED transaction\n if ($.status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n // Update status to RELAYER_PROVED and store the proof details\n // Note: these are storage writes\n $.status = BridgeStatus.RELAYER_PROVED;\n $.proofBlockTimestamp = uint56(block.timestamp);\n $.proofRelayer = relayer;\n\n emit BridgeProofProvided(transactionId, relayer, destTxHash);\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes calldata request, address to) public {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Aggregate the read operations from the same storage slot\n address proofRelayer = $.proofRelayer;\n BridgeStatus status = $.status;\n uint56 proofBlockTimestamp = $.proofBlockTimestamp;\n\n // Can only claim a RELAYER_PROVED transaction after the dispute period\n if (status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(proofBlockTimestamp) \u003c= DISPUTE_PERIOD) {\n revert DisputePeriodNotPassed();\n }\n\n if (to == address(0)) {\n // Anyone could claim the funds to the proven relayer on their behalf\n to = proofRelayer;\n } else if (proofRelayer != msg.sender) {\n // Only the proven relayer could specify an address to claim the funds to\n revert SenderIncorrect();\n }\n\n // Update status to RELAYER_CLAIMED and transfer the origin collateral to the specified claim address\n // Note: this is a storage write\n $.status = BridgeStatus.RELAYER_CLAIMED;\n\n address token = request.originToken();\n uint256 amount = request.originAmount();\n // Update protocol fees if origin fee amount exists\n uint256 originFeeAmount = request.originFeeAmount();\n if (originFeeAmount \u003e 0) protocolFees[token] += originFeeAmount;\n // Emit the event before any external calls\n emit BridgeDepositClaimed(transactionId, proofRelayer, to, token, amount);\n // Complete the relayer claim as the last transaction action\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(to), amount);\n } else {\n IERC20(token).safeTransfer(to, amount);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeStatuses(bytes32 transactionId) public view returns (BridgeStatus status) {\n return bridgeTxDetails[transactionId].status;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeProofs(bytes32 transactionId) public view returns (uint96 timestamp, address relayer) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n\n timestamp = $.proofBlockTimestamp;\n relayer = $.proofRelayer;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeRelays(bytes32 transactionId) public view returns (bool) {\n // has this transactionId been relayed?\n return bridgeRelayDetails[transactionId].relayer != address(0);\n }\n\n /// @notice Takes the bridged asset from the user into FastBridgeV2 custody. It will be later\n /// claimed by the relayer who completed the relay on destination chain, or refunded back to the user,\n /// should no one complete the relay.\n function _takeBridgedUserAsset(address token, uint256 amount) internal returns (uint256 amountTaken) {\n if (token == NATIVE_GAS_TOKEN) {\n // For the native gas token, we just need to check that the supplied msg.value is correct.\n // Supplied `msg.value` is already in FastBridgeV2 custody.\n if (amount != msg.value) revert MsgValueIncorrect();\n amountTaken = msg.value;\n } else {\n // For ERC20s, token is explicitly transferred from the user to FastBridgeV2.\n // We don't allow non-zero `msg.value` to avoid extra funds from being stuck in FastBridgeV2.\n if (msg.value != 0) revert MsgValueIncorrect();\n // Throw an explicit error if the provided token address is not a contract\n if (token.code.length == 0) revert TokenNotContract();\n amountTaken = IERC20(token).balanceOf(address(this));\n IERC20(token).safeTransferFrom(msg.sender, address(this), amount);\n // Use the balance difference as the amount taken in case of fee on transfer tokens.\n amountTaken = IERC20(token).balanceOf(address(this)) - amountTaken;\n }\n }\n\n /// @notice Calls the Recipient's hook function with the specified zapData and performs\n /// all the necessary checks for the returned value.\n function _triggerZapWithChecks(address recipient, address token, uint256 amount, bytes calldata zapData) internal {\n // This will bubble any revert messages from the hook function\n bytes memory returnData = Address.functionCallWithValue({\n target: recipient,\n data: abi.encodeCall(IZapRecipient.zap, (token, amount, zapData)),\n // Note: see `relay()` for reasoning behind passing msg.value\n value: msg.value\n });\n // Explicit revert if no return data at all\n if (returnData.length == 0) revert RecipientNoReturnValue();\n // Check that exactly a single return value was returned\n if (returnData.length != 32) revert RecipientIncorrectReturnValue();\n // Return value should be abi-encoded hook function selector\n if (bytes32(returnData) != bytes32(IZapRecipient.zap.selector)) {\n revert RecipientIncorrectReturnValue();\n }\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint56(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint56).max but\n /// proof.timestamp \u003c type(uint56).max via unchecked statement\n /// @param proofBlockTimestamp The bridge proof block timestamp\n /// @return delta Time delta since proof submitted\n function _timeSince(uint56 proofBlockTimestamp) internal view returns (uint256 delta) {\n unchecked {\n delta = uint56(block.timestamp) - proofBlockTimestamp;\n }\n }\n\n /// @notice Performs all the necessary checks for a bridge to happen.\n /// @dev There's no good way to refactor this function to reduce cyclomatic complexity due to\n /// the number of checks that need to be performed, so we skip the code-complexity rule here.\n // solhint-disable-next-line code-complexity\n function _validateBridgeParams(\n BridgeParams memory params,\n BridgeParamsV2 memory paramsV2,\n int256 exclusivityEndTime\n )\n internal\n view\n {\n // Check V1 (legacy) params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.sender == address(0) || params.to == address(0)) revert ZeroAddress();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n // Check V2 params\n if (paramsV2.zapData.length \u003e MAX_ZAP_DATA_LENGTH) revert ZapDataLengthAboveMax();\n if (paramsV2.zapNative != 0 \u0026\u0026 params.destToken == NATIVE_GAS_TOKEN) {\n revert ZapNativeNotSupported();\n }\n // exclusivityEndTime must be in range [0 .. params.deadline]\n if (exclusivityEndTime \u003c 0 || exclusivityEndTime \u003e int256(params.deadline)) {\n revert ExclusivityParamsIncorrect();\n }\n }\n\n /// @notice Performs all the necessary checks for a relay to happen.\n function _validateRelayParams(bytes calldata request, bytes32 transactionId, address relayer) internal view {\n if (relayer == address(0)) revert ZeroAddress();\n // Check if the transaction has already been relayed\n if (bridgeRelays(transactionId)) revert TransactionRelayed();\n if (request.destChainId() != block.chainid) revert ChainIncorrect();\n // Check the deadline for relay to happen\n if (block.timestamp \u003e request.deadline()) revert DeadlineExceeded();\n // Check the exclusivity period, if it is still ongoing\n address exclRelayer = request.exclusivityRelayer();\n if (exclRelayer != address(0) \u0026\u0026 exclRelayer != relayer \u0026\u0026 block.timestamp \u003c= request.exclusivityEndTime()) {\n revert ExclusivityPeriodNotPassed();\n }\n }\n}\n","language":"Solidity","languageVersion":"0.8.24","compilerVersion":"0.8.24","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"78879:1843:0:-:0;;;79706:83;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;79744:38;68916:4;79775:6;79744:10;:38::i;:::-;;79706:83;78879:1843;;78229:257;78315:4;;78346:31;78363:4;78369:7;78346:16;:31::i;:::-;78331:46;;78391:7;78387:69;;;78414:18;;;;:12;:18;;;;;:31;;78437:7;78414:22;:31::i;:::-;;78387:69;78472:7;-1:-1:-1;78229:257:0;;;;;:::o;72863:316::-;72940:4;69638:12;;;;;;;;;;;-1:-1:-1;;;;;69638:29:0;;;;;;;;;;;;72956:217;;72999:6;:12;;;;;;;;;;;-1:-1:-1;;;;;72999:29:0;;;;;;;;;:36;;-1:-1:-1;;72999:36:0;73031:4;72999:36;;;73081:12;23872:10;;23793:96;73081:12;-1:-1:-1;;;;;73054:40:0;73072:7;-1:-1:-1;;;;;73054:40:0;73066:4;73054:40;;;;;;;;;;-1:-1:-1;73115:4:0;73108:11;;72956:217;-1:-1:-1;73157:5:0;73150:12;;33317:150;33387:4;33410:50;33415:3;-1:-1:-1;;;;;33435:23:0;;27305:4;29361:21;;;:14;;;:21;;;;;;27321:321;;-1:-1:-1;27363:23:0;;;;;;;;:11;:23;;;;;;;;;;;;;27545:18;;27521:21;;;:14;;;:21;;;;;;:42;;;;27577:11;;14:290:1;84:6;137:2;125:9;116:7;112:23;108:32;105:52;;;153:1;150;143:12;105:52;179:16;;-1:-1:-1;;;;;224:31:1;;214:42;;204:70;;270:1;267;260:12;14:290;78879:1843:0;;;;;;","srcMapRuntime":"78879:1843:0:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;76889:212;;;;;;:::i;:::-;;:::i;:::-;;;516:14:1;;509:22;491:41;;479:2;464:18;76889:212:0;;;;;;;;79119:60;;79156:23;79119:60;;;;;689:25:1;;;677:2;662:18;79119:60:0;543:177:1;80091:359:0;;;;;;:::i;:::-;;:::i;:::-;;79301:45;;79340:6;79301:45;;70494:120;;;;;;:::i;:::-;70559:7;70585:12;;;;;;;;;;:22;;;;70494:120;70910:136;;;;;;:::i;:::-;;:::i;72012:245::-;;;;;;:::i;:::-;;:::i;79463:30::-;;;;;;79047:66;;79087:26;79047:66;;77686:142;;;;;;:::i;:::-;;:::i;:::-;;;2246:42:1;2234:55;;;2216:74;;2204:2;2189:18;77686:142:0;2070:226:1;69538:136:0;;;;;;:::i;:::-;69615:4;69638:12;;;;;;;;;;;:29;;;;;;;;;;;;;;;;69538:136;78977:64;;79016:25;78977:64;;68871:49;;68916:4;68871:49;;79795:290;;;;;;:::i;:::-;;:::i;80456:264::-;;;;;;:::i;:::-;;:::i;79258:37::-;;79292:3;79258:37;;77996:131;;;;;;:::i;:::-;;:::i;79185:66::-;;79225:26;79185:66;;71326:138;;;;;;:::i;:::-;;:::i;79549:47::-;;;;;;:::i;:::-;;;;;;;;;;;;;;79670:29;;;;;;76889:212;76974:4;76997:57;;;77012:42;76997:57;;:97;;;77058:36;77082:11;77058:23;:36::i;:::-;76990:104;76889:212;-1:-1:-1;;76889:212:0:o;80091:359::-;79225:26;69148:16;69159:4;69148:10;:16::i;:::-;80215:19:::1;::::0;::::1;80195:17;80215:19:::0;;;:12:::1;:19;::::0;;;;;;80248:14;;;80244:27:::1;;80264:7;80091:359:::0;;;:::o;80244:27::-:1;80312:19;::::0;::::1;80334:1;80312:19:::0;;;:12:::1;:19;::::0;;;;:23;80345:45:::1;::::0;80369:9;80380;80345:23:::1;:45::i;:::-;80405:38;::::0;;2889:42:1;2958:15;;;2940:34;;3010:15;;3005:2;2990:18;;2983:43;3042:18;;;3035:34;;;80405:38:0::1;::::0;2867:2:1;2852:18;80405:38:0::1;;;;;;;80185:265;69174:1;80091:359:::0;;;:::o;70910:136::-;70559:7;70585:12;;;;;;;;;;:22;;;69148:16;69159:4;69148:10;:16::i;:::-;71014:25:::1;71025:4;71031:7;71014:10;:25::i;:::-;;70910:136:::0;;;:::o;72012:245::-;72105:34;;;23872:10;72105:34;72101:102;;72162:30;;;;;;;;;;;;;;72101:102;72213:37;72225:4;72231:18;72213:11;:37::i;77686:142::-;77767:7;77793:18;;;:12;:18;;;;;:28;;77815:5;77793:21;:28::i;:::-;77786:35;77686:142;-1:-1:-1;;;77686:142:0:o;79795:290::-;79225:26;69148:16;69159:4;69148:10;:16::i;:::-;79340:6:::1;79894:10;:26;;79886:55;;;::::0;::::1;::::0;;3282:2:1;79886:55:0::1;::::0;::::1;3264:21:1::0;3321:2;3301:18;;;3294:30;3360:18;3340;;;3333:46;3396:18;;79886:55:0::1;;;;;;;;;79972:15;::::0;;79997:28;;;;80040:38:::1;::::0;;3599:25:1;;;3655:2;3640:18;;3633:34;;;80040:38:0::1;::::0;3572:18:1;80040:38:0::1;;;;;;;;79876:209;79795:290:::0;;:::o;80456:264::-;79225:26;69148:16;69159:4;69148:10;:16::i;:::-;80581:14:::1;::::0;;80605:34;;;;80654:59:::1;::::0;;3599:25:1;;;3655:2;3640:18;;3633:34;;;80654:59:0::1;::::0;3572:18:1;80654:59:0::1;3425:248:1::0;77996:131:0;78067:7;78093:18;;;:12;:18;;;;;:27;;:25;:27::i;71326:138::-;70559:7;70585:12;;;;;;;;;;:22;;;69148:16;69159:4;69148:10;:16::i;:::-;71431:26:::1;71443:4;71449:7;71431:11;:26::i;69249:202::-:0;69334:4;69357:47;;;69372:32;69357:47;;:87;;-1:-1:-1;49585:25:0;49570:40;;;;69408:36;49471:146;69883:103;69949:30;69960:4;23872:10;69949;:30::i;:::-;69883:103;:::o;74161:653::-;74336:4;74322:19;;;;74318:32;;74161:653;;;:::o;74318:32::-;74422:5;74431:1;74422:10;74418:23;;74161:653;;;:::o;74418:23::-;74454:20;;;;;74450:358;;74634:12;74651:2;:7;;74666:5;74651:25;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;74633:43;;;74698:7;74690:39;;;;;;;4090:2:1;74690:39:0;;;4072:21:1;4129:2;4109:18;;;4102:30;4168:21;4148:18;;;4141:49;4207:18;;74690:39:0;3888:343:1;74450:358:0;74760:37;:26;;;74787:2;74791:5;74760:26;:37::i;78229:257::-;78315:4;78331:12;78346:31;78363:4;78369:7;78346:16;:31::i;:::-;78331:46;;78391:7;78387:69;;;78414:18;;;;:12;:18;;;;;:31;;78437:7;78414:22;:31::i;:::-;;78472:7;78229:257;-1:-1:-1;;;78229:257:0:o;78589:262::-;78676:4;78692:12;78707:32;78725:4;78731:7;78707:17;:32::i;:::-;78692:47;;78753:7;78749:72;;;78776:18;;;;:12;:18;;;;;:34;;78802:7;78776:25;:34::i;34575:156::-;34649:7;34699:22;34703:3;34715:5;34699:3;:22::i;34118:115::-;34181:7;34207:19;34215:3;29557:18;;29475:107;70116:197;69615:4;69638:12;;;;;;;;;;;:29;;;;;;;;;;;;;70199:108;;70249:47;;;;;4440:42:1;4428:55;;70249:47:0;;;4410:74:1;4500:18;;;4493:34;;;4383:18;;70249:47:0;4236:297:1;70199:108:0;70116:197;;:::o;62366:160::-;62475:43;;;62490:14;4428:55:1;;62475:43:0;;;4410:74:1;4500:18;;;;4493:34;;;62475:43:0;;;;;;;;;;4383:18:1;;;;62475:43:0;;;;;;;;;;;;;;62448:71;;62468:5;;62448:19;:71::i;72863:316::-;72940:4;69638:12;;;;;;;;;;;:29;;;;;;;;;;;;;72956:217;;72999:6;:12;;;;;;;;;;;:29;;;;;;;;;;:36;;;;73031:4;72999:36;;;73081:12;23872:10;;23793:96;73081:12;73054:40;;73072:7;73054:40;;73066:4;73054:40;;;;;;;;;;-1:-1:-1;73115:4:0;73108:11;;72956:217;-1:-1:-1;73157:5:0;73150:12;;33317:150;33387:4;33410:50;33415:3;33435:23;;;33410:4;:50::i;73414:317::-;73492:4;69638:12;;;;;;;;;;;:29;;;;;;;;;;;;;73508:217;;;73582:5;73550:12;;;;;;;;;;;:29;;;;;;;;;;;:37;;;;;;73606:40;23872:10;;73550:12;;73606:40;;73582:5;73606:40;-1:-1:-1;73667:4:0;73660:11;;33635:156;33708:4;33731:53;33739:3;33759:23;;;33731:7;:53::i;29924:118::-;29991:7;30017:3;:11;;30029:5;30017:18;;;;;;;;:::i;:::-;;;;;;;;;30010:25;;29924:118;;;;:::o;65122:629::-;65541:23;65567:33;:27;;;65595:4;65567:27;:33::i;:::-;65541:59;;65614:10;:17;65635:1;65614:22;;:57;;;;;65652:10;65641:30;;;;;;;;;;;;:::i;:::-;65640:31;65614:57;65610:135;;;65694:40;;;;;2246:42:1;2234:55;;65694:40:0;;;2216:74:1;2189:18;;65694:40:0;2070:226:1;27242:406:0;27305:4;29361:21;;;:14;;;:21;;;;;;27321:321;;-1:-1:-1;27363:23:0;;;;;;;;:11;:23;;;;;;;;;;;;;27545:18;;27521:21;;;:14;;;:21;;;;;;:42;;;;27577:11;;27816:1368;27882:4;28011:21;;;:14;;;:21;;;;;;28047:13;;28043:1135;;28414:18;28435:12;28446:1;28435:8;:12;:::i;:::-;28481:18;;28414:33;;-1:-1:-1;28461:17:0;;28481:22;;28502:1;;28481:22;:::i;:::-;28461:42;;28536:9;28522:10;:23;28518:378;;28565:17;28585:3;:11;;28597:9;28585:22;;;;;;;;:::i;:::-;;;;;;;;;28565:42;;28732:9;28706:3;:11;;28718:10;28706:23;;;;;;;;:::i;:::-;;;;;;;;;;;;:35;;;;28845:25;;;:14;;;:25;;;;;:36;;;28518:378;28974:17;;:3;;:17;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;29077:3;:14;;:21;29092:5;29077:21;;;;;;;;;;;29070:28;;;29120:4;29113:11;;;;;;;28043:1135;29162:5;29155:12;;;;;19578:151;19653:12;19684:38;19706:6;19714:4;19720:1;19653:12;20294;20308:23;20335:6;:11;;20354:5;20361:4;20335:31;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;20293:73;;;;20383:55;20410:6;20418:7;20427:10;20383:26;:55::i;:::-;20376:62;20053:392;-1:-1:-1;;;;;;20053:392:0:o;21498:582::-;21642:12;21671:7;21666:408;;21694:19;21702:10;21694:7;:19::i;:::-;21666:408;;;21918:17;;:22;:49;;;;-1:-1:-1;21944:18:0;;;;:23;21918:49;21914:119;;;21994:24;;;;;2246:42:1;2234:55;;21994:24:0;;;2216:74:1;2189:18;;21994:24:0;2070:226:1;21914:119:0;-1:-1:-1;22053:10:0;22046:17;;22616:516;22747:17;;:21;22743:383;;22975:10;22969:17;23031:15;23018:10;23014:2;23010:19;23003:44;22743:383;23098:17;;;;;;;;;;;;;;14:332:1;72:6;125:2;113:9;104:7;100:23;96:32;93:52;;;141:1;138;131:12;93:52;180:9;167:23;230:66;223:5;219:78;212:5;209:89;199:117;;312:1;309;302:12;725:196;793:20;;853:42;842:54;;832:65;;822:93;;911:1;908;901:12;822:93;725:196;;;:::o;926:260::-;994:6;1002;1055:2;1043:9;1034:7;1030:23;1026:32;1023:52;;;1071:1;1068;1061:12;1023:52;1094:29;1113:9;1094:29;:::i;:::-;1084:39;;1142:38;1176:2;1165:9;1161:18;1142:38;:::i;:::-;1132:48;;926:260;;;;;:::o;1373:180::-;1432:6;1485:2;1473:9;1464:7;1460:23;1456:32;1453:52;;;1501:1;1498;1491:12;1453:52;-1:-1:-1;1524:23:1;;1373:180;-1:-1:-1;1373:180:1:o;1558:254::-;1626:6;1634;1687:2;1675:9;1666:7;1662:23;1658:32;1655:52;;;1703:1;1700;1693:12;1655:52;1739:9;1726:23;1716:33;;1768:38;1802:2;1791:9;1787:18;1768:38;:::i;1817:248::-;1885:6;1893;1946:2;1934:9;1925:7;1921:23;1917:32;1914:52;;;1962:1;1959;1952:12;1914:52;-1:-1:-1;;1985:23:1;;;2055:2;2040:18;;;2027:32;;-1:-1:-1;1817:248:1:o;2486:186::-;2545:6;2598:2;2586:9;2577:7;2573:23;2569:32;2566:52;;;2614:1;2611;2604:12;2566:52;2637:29;2656:9;2637:29;:::i;4840:184::-;4892:77;4889:1;4882:88;4989:4;4986:1;4979:15;5013:4;5010:1;5003:15;5029:277;5096:6;5149:2;5137:9;5128:7;5124:23;5120:32;5117:52;;;5165:1;5162;5155:12;5117:52;5197:9;5191:16;5250:5;5243:13;5236:21;5229:5;5226:32;5216:60;;5272:1;5269;5262:12;5311:282;5378:9;;;5399:11;;;5396:191;;;5443:77;5440:1;5433:88;5544:4;5541:1;5534:15;5572:4;5569:1;5562:15;5598:184;5650:77;5647:1;5640:88;5747:4;5744:1;5737:15;5771:4;5768:1;5761:15;5787:412;5916:3;5954:6;5948:13;5979:1;5989:129;6003:6;6000:1;5997:13;5989:129;;;6101:4;6085:14;;;6081:25;;6075:32;6062:11;;;6055:53;6018:12;5989:129;;;-1:-1:-1;6173:1:1;6137:16;;6162:13;;;-1:-1:-1;6137:16:1;5787:412;-1:-1:-1;5787:412:1:o","abiDefinition":[{"inputs":[{"internalType":"address","name":"_owner","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AccessControlBadConfirmation","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"bytes32","name":"neededRole","type":"bytes32"}],"name":"AccessControlUnauthorizedAccount","type":"error"},{"inputs":[{"internalType":"address","name":"target","type":"address"}],"name":"AddressEmptyCode","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"AddressInsufficientBalance","type":"error"},{"inputs":[],"name":"FailedInnerCall","type":"error"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"SafeERC20FailedOperation","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldChainGasAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newChainGasAmount","type":"uint256"}],"name":"ChainGasAmountUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldFeeRate","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newFeeRate","type":"uint256"}],"name":"FeeRateUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"address","name":"recipient","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"FeesSwept","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"previousAdminRole","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"newAdminRole","type":"bytes32"}],"name":"RoleAdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleRevoked","type":"event"},{"inputs":[],"name":"DEFAULT_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"FEE_BPS","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"FEE_RATE_MAX","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"GOVERNOR_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"GUARD_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"REFUNDER_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"RELAYER_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"chainGasAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleAdmin","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"uint256","name":"index","type":"uint256"}],"name":"getRoleMember","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleMemberCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"grantRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"hasRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"protocolFeeRate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"protocolFees","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"callerConfirmation","type":"address"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"revokeRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"newChainGasAmount","type":"uint256"}],"name":"setChainGasAmount","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"newFeeRate","type":"uint256"}],"name":"setProtocolFeeRate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"address","name":"recipient","type":"address"}],"name":"sweepProtocolFees","outputs":[],"stateMutability":"nonpayable","type":"function"}],"userDoc":{"kind":"user","methods":{"chainGasAmount()":{"notice":"Chain gas amount to forward as rebate if requested"},"protocolFeeRate()":{"notice":"Protocol fee rate taken on origin amount deposited in origin chain"},"protocolFees(address)":{"notice":"Protocol fee amounts accumulated"}},"version":1},"developerDoc":{"errors":{"AccessControlBadConfirmation()":[{"details":"The caller of a function is not the expected one. NOTE: Don't confuse with {AccessControlUnauthorizedAccount}."}],"AccessControlUnauthorizedAccount(address,bytes32)":[{"details":"The `account` is missing a role."}],"AddressEmptyCode(address)":[{"details":"There's no code at `target` (it is not a contract)."}],"AddressInsufficientBalance(address)":[{"details":"The ETH balance of the account is not enough to perform the operation."}],"FailedInnerCall()":[{"details":"A call to an address target failed. The target may have reverted."}],"SafeERC20FailedOperation(address)":[{"details":"An operation with an ERC20 token failed."}]},"events":{"RoleAdminChanged(bytes32,bytes32,bytes32)":{"details":"Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole` `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite {RoleAdminChanged} not being emitted signaling this."},"RoleGranted(bytes32,address,address)":{"details":"Emitted when `account` is granted `role`. `sender` is the account that originated the contract call, an admin role bearer except when using {AccessControl-_setupRole}."},"RoleRevoked(bytes32,address,address)":{"details":"Emitted when `account` is revoked `role`. `sender` is the account that originated the contract call: - if using `revokeRole`, it is the admin role bearer - if using `renounceRole`, it is the role bearer (i.e. `account`)"}},"kind":"dev","methods":{"getRoleAdmin(bytes32)":{"details":"Returns the admin role that controls `role`. See {grantRole} and {revokeRole}. To change a role's admin, use {_setRoleAdmin}."},"getRoleMember(bytes32,uint256)":{"details":"Returns one of the accounts that have `role`. `index` must be a value between 0 and {getRoleMemberCount}, non-inclusive. Role bearers are not sorted in any particular way, and their ordering may change at any point. WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure you perform all queries on the same block. See the following https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post] for more information."},"getRoleMemberCount(bytes32)":{"details":"Returns the number of accounts that have `role`. Can be used together with {getRoleMember} to enumerate all bearers of a role."},"grantRole(bytes32,address)":{"details":"Grants `role` to `account`. If `account` had not been already granted `role`, emits a {RoleGranted} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleGranted} event."},"hasRole(bytes32,address)":{"details":"Returns `true` if `account` has been granted `role`."},"renounceRole(bytes32,address)":{"details":"Revokes `role` from the calling account. Roles are often managed via {grantRole} and {revokeRole}: this function's purpose is to provide a mechanism for accounts to lose their privileges if they are compromised (such as when a trusted device is misplaced). If the calling account had been revoked `role`, emits a {RoleRevoked} event. Requirements: - the caller must be `callerConfirmation`. May emit a {RoleRevoked} event."},"revokeRole(bytes32,address)":{"details":"Revokes `role` from `account`. If `account` had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleRevoked} event."},"supportsInterface(bytes4)":{"details":"See {IERC165-supportsInterface}."}},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_owner\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"AccessControlBadConfirmation\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"neededRole\",\"type\":\"bytes32\"}],\"name\":\"AccessControlUnauthorizedAccount\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"}],\"name\":\"AddressEmptyCode\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"AddressInsufficientBalance\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"FailedInnerCall\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"}],\"name\":\"SafeERC20FailedOperation\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"oldChainGasAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newChainGasAmount\",\"type\":\"uint256\"}],\"name\":\"ChainGasAmountUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"oldFeeRate\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newFeeRate\",\"type\":\"uint256\"}],\"name\":\"FeeRateUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"FeesSwept\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"previousAdminRole\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"newAdminRole\",\"type\":\"bytes32\"}],\"name\":\"RoleAdminChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleGranted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleRevoked\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"DEFAULT_ADMIN_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"FEE_BPS\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"FEE_RATE_MAX\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"GOVERNOR_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"GUARD_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"REFUNDER_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"RELAYER_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"chainGasAmount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"}],\"name\":\"getRoleAdmin\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"index\",\"type\":\"uint256\"}],\"name\":\"getRoleMember\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"}],\"name\":\"getRoleMemberCount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"grantRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"hasRole\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"protocolFeeRate\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"protocolFees\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"callerConfirmation\",\"type\":\"address\"}],\"name\":\"renounceRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"revokeRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"newChainGasAmount\",\"type\":\"uint256\"}],\"name\":\"setChainGasAmount\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"newFeeRate\",\"type\":\"uint256\"}],\"name\":\"setProtocolFeeRate\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes4\",\"name\":\"interfaceId\",\"type\":\"bytes4\"}],\"name\":\"supportsInterface\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"}],\"name\":\"sweepProtocolFees\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"errors\":{\"AccessControlBadConfirmation()\":[{\"details\":\"The caller of a function is not the expected one. NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\"}],\"AccessControlUnauthorizedAccount(address,bytes32)\":[{\"details\":\"The `account` is missing a role.\"}],\"AddressEmptyCode(address)\":[{\"details\":\"There's no code at `target` (it is not a contract).\"}],\"AddressInsufficientBalance(address)\":[{\"details\":\"The ETH balance of the account is not enough to perform the operation.\"}],\"FailedInnerCall()\":[{\"details\":\"A call to an address target failed. The target may have reverted.\"}],\"SafeERC20FailedOperation(address)\":[{\"details\":\"An operation with an ERC20 token failed.\"}]},\"events\":{\"RoleAdminChanged(bytes32,bytes32,bytes32)\":{\"details\":\"Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole` `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite {RoleAdminChanged} not being emitted signaling this.\"},\"RoleGranted(bytes32,address,address)\":{\"details\":\"Emitted when `account` is granted `role`. `sender` is the account that originated the contract call, an admin role bearer except when using {AccessControl-_setupRole}.\"},\"RoleRevoked(bytes32,address,address)\":{\"details\":\"Emitted when `account` is revoked `role`. `sender` is the account that originated the contract call: - if using `revokeRole`, it is the admin role bearer - if using `renounceRole`, it is the role bearer (i.e. `account`)\"}},\"kind\":\"dev\",\"methods\":{\"getRoleAdmin(bytes32)\":{\"details\":\"Returns the admin role that controls `role`. See {grantRole} and {revokeRole}. To change a role's admin, use {_setRoleAdmin}.\"},\"getRoleMember(bytes32,uint256)\":{\"details\":\"Returns one of the accounts that have `role`. `index` must be a value between 0 and {getRoleMemberCount}, non-inclusive. Role bearers are not sorted in any particular way, and their ordering may change at any point. WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure you perform all queries on the same block. See the following https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post] for more information.\"},\"getRoleMemberCount(bytes32)\":{\"details\":\"Returns the number of accounts that have `role`. Can be used together with {getRoleMember} to enumerate all bearers of a role.\"},\"grantRole(bytes32,address)\":{\"details\":\"Grants `role` to `account`. If `account` had not been already granted `role`, emits a {RoleGranted} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleGranted} event.\"},\"hasRole(bytes32,address)\":{\"details\":\"Returns `true` if `account` has been granted `role`.\"},\"renounceRole(bytes32,address)\":{\"details\":\"Revokes `role` from the calling account. Roles are often managed via {grantRole} and {revokeRole}: this function's purpose is to provide a mechanism for accounts to lose their privileges if they are compromised (such as when a trusted device is misplaced). If the calling account had been revoked `role`, emits a {RoleRevoked} event. Requirements: - the caller must be `callerConfirmation`. May emit a {RoleRevoked} event.\"},\"revokeRole(bytes32,address)\":{\"details\":\"Revokes `role` from `account`. If `account` had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleRevoked} event.\"},\"supportsInterface(bytes4)\":{\"details\":\"See {IERC165-supportsInterface}.\"}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"chainGasAmount()\":{\"notice\":\"Chain gas amount to forward as rebate if requested\"},\"protocolFeeRate()\":{\"notice\":\"Protocol fee rate taken on origin amount deposited in origin chain\"},\"protocolFees(address)\":{\"notice\":\"Protocol fee amounts accumulated\"}},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeV2.sol\":\"Admin\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeV2.sol\":{\"keccak256\":\"0x5069b55ca07f21bfe30b2a43c18a18318c8af9c181b2dcb07c290825efd70f34\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://273dc020a49d08e50126bbea0d7f783f79d08c702f2fdbc560618d24af308acc\",\"dweb:/ipfs/QmXJ2UVzFc8EPB74RT4CXQPC4xw66jt4T13poyfyd3UERh\"]}},\"version\":1}"},"hashes":{"DEFAULT_ADMIN_ROLE()":"a217fddf","FEE_BPS()":"bf333f2c","FEE_RATE_MAX()":"0f5f6ed7","GOVERNOR_ROLE()":"ccc57490","GUARD_ROLE()":"03ed0ee5","REFUNDER_ROLE()":"5960ccf2","RELAYER_ROLE()":"926d7d7f","chainGasAmount()":"e00a83e0","getRoleAdmin(bytes32)":"248a9ca3","getRoleMember(bytes32,uint256)":"9010d07c","getRoleMemberCount(bytes32)":"ca15c873","grantRole(bytes32,address)":"2f2ff15d","hasRole(bytes32,address)":"91d14854","protocolFeeRate()":"58f85880","protocolFees(address)":"dcf844a7","renounceRole(bytes32,address)":"36568abe","revokeRole(bytes32,address)":"d547741f","setChainGasAmount(uint256)":"b250fe6b","setProtocolFeeRate(uint256)":"b13aa2d6","supportsInterface(bytes4)":"01ffc9a7","sweepProtocolFees(address,address)":"06f333f2"}},"solidity/FastBridgeV2.sol:BridgeTransactionV2Lib":{"code":"0x60566037600b82828239805160001a607314602a57634e487b7160e01b600052600060045260246000fd5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600080fdfea2646970667358221220c0d1e2256fb16b1e19ad4848dc80aafe3c3f70b204e139f256b5d6095b52dd5564736f6c63430008180033","runtime-code":"0x73000000000000000000000000000000000000000030146080604052600080fdfea2646970667358221220c0d1e2256fb16b1e19ad4848dc80aafe3c3f70b204e139f256b5d6095b52dd5564736f6c63430008180033","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.24 ^0.8.20 ^0.8.4;\n\n// contracts/interfaces/IAdmin.sol\n\ninterface IAdmin {\n // ============ Events ============\n\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n event ChainGasAmountUpdated(uint256 oldChainGasAmount, uint256 newChainGasAmount);\n\n // ============ Methods ============\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n\n function setChainGasAmount(uint256 newChainGasAmount) external;\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IFastBridgeV2Errors.sol\n\ninterface IFastBridgeV2Errors {\n error AmountIncorrect();\n error ChainIncorrect();\n error ExclusivityParamsIncorrect();\n error MsgValueIncorrect();\n error SenderIncorrect();\n error StatusIncorrect();\n error TokenNotContract();\n error ZapDataLengthAboveMax();\n error ZapNativeNotSupported();\n error ZeroAddress();\n\n error RecipientIncorrectReturnValue();\n error RecipientNoReturnValue();\n\n error DeadlineExceeded();\n error DeadlineNotExceeded();\n error DeadlineTooShort();\n error DisputePeriodNotPassed();\n error DisputePeriodPassed();\n error ExclusivityPeriodNotPassed();\n\n error TransactionRelayed();\n}\n\n// contracts/interfaces/IMulticallTarget.sol\n\n/// @notice Interface for a contract that can be called multiple times by the same caller. Inspired by MulticallV3:\n/// https://github.com/mds1/multicall/blob/master/src/Multicall3.sol\ninterface IMulticallTarget {\n struct Result {\n bool success;\n bytes returnData;\n }\n\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external;\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results);\n}\n\n// contracts/interfaces/IZapRecipient.sol\n\ninterface IZapRecipient {\n function zap(address token, uint256 amount, bytes memory zapData) external payable returns (bytes4);\n}\n\n// contracts/libs/Errors.sol\n\nerror DeadlineExceeded();\nerror DeadlineNotExceeded();\nerror DeadlineTooShort();\nerror InsufficientOutputAmount();\n\nerror MsgValueIncorrect();\nerror PoolNotFound();\nerror TokenAddressMismatch();\nerror TokenNotContract();\nerror TokenNotETH();\nerror TokensIdentical();\n\nerror ChainIncorrect();\nerror AmountIncorrect();\nerror ZeroAddress();\n\nerror DisputePeriodNotPassed();\nerror DisputePeriodPassed();\nerror SenderIncorrect();\nerror StatusIncorrect();\nerror TransactionIdIncorrect();\nerror TransactionRelayed();\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// contracts/interfaces/IFastBridgeV2.sol\n\ninterface IFastBridgeV2 is IFastBridge {\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n struct BridgeTxDetails {\n BridgeStatus status;\n uint32 destChainId;\n uint56 proofBlockTimestamp;\n address proofRelayer;\n }\n\n struct BridgeRelay {\n uint48 blockNumber;\n uint48 blockTimestamp;\n address relayer;\n }\n\n /// @notice New params introduced in the FastBridgeV2.\n /// We are passing fields from the older BridgeParams struct outside of this struct\n /// for backwards compatibility.\n /// Note: quoteRelayer and quoteExclusivitySeconds are either both zero (indicating no exclusivity)\n /// or both non-zero (indicating exclusivity for the given period).\n /// Note: zapNative \u003e 0 can NOT be used with destToken = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE (native token)\n /// @param quoteRelayer Relayer that provided the quote for the transaction\n /// @param quoteExclusivitySeconds Period of time the quote relayer is guaranteed exclusivity after user's deposit\n /// @param quoteId Unique quote identifier used for tracking the quote\n /// @param zapNative ETH value to send to the recipient (if any)\n /// @param zapData Parameters for the Zap to the destination recipient (if any)\n struct BridgeParamsV2 {\n address quoteRelayer;\n int256 quoteExclusivitySeconds;\n bytes quoteId;\n uint256 zapNative;\n bytes zapData;\n }\n\n /// @notice Updated bridge transaction struct to include parameters introduced in FastBridgeV2.\n /// Note: only `exclusivityRelayer` can fill such a transaction until `exclusivityEndTime`.\n struct BridgeTransactionV2 {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n // Note: sendChainGas flag from V1 is deprecated\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n address exclusivityRelayer;\n uint256 exclusivityEndTime;\n uint256 zapNative; // ETH value to send to the recipient (if any)\n bytes zapData; // data to pass for the Zap action (if any)\n }\n\n event BridgeQuoteDetails(bytes32 indexed transactionId, bytes quoteId);\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability\n /// to provide temporary exclusivity fill rights for the quote relayer.\n /// @param params The parameters required to bridge\n /// @param paramsV2 The parameters for exclusivity fill rights (optional, can be left empty)\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function relay(bytes memory request, address relayer) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param transactionId The transaction id associated with the encoded bridge transaction to prove\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital.\n /// @notice Can only send funds to the relayer address on the proof.\n /// @param request The encoded bridge transaction to claim on origin chain\n function claim(bytes memory request) external;\n /// @notice Checks if a transaction has been relayed\n /// @param transactionId The ID of the transaction to check\n /// @return True if the transaction has been relayed, false otherwise\n function bridgeRelays(bytes32 transactionId) external view returns (bool);\n\n /// @notice Returns the status of a bridge transaction\n /// @param transactionId The ID of the bridge transaction\n /// @return BridgeStatus Status of the bridge transaction\n function bridgeStatuses(bytes32 transactionId) external view returns (BridgeStatus);\n\n /// @notice Returns the timestamp and relayer of a bridge proof\n /// @param transactionId The ID of the bridge transaction\n /// @return timestamp The timestamp of the bridge proof\n /// @return relayer The relayer address of the bridge proof\n function bridgeProofs(bytes32 transactionId) external view returns (uint96 timestamp, address relayer);\n\n /// @notice Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\n /// @param request The bridge request to decode\n function getBridgeTransactionV2(bytes memory request) external view returns (BridgeTransactionV2 memory);\n}\n\n// contracts/utils/MulticallTarget.sol\n\n// solhint-disable avoid-low-level-calls\n/// @notice Template for a contract that supports batched calls (preserving the msg.sender).\n/// Only calls with zero msg.value could be batched.\nabstract contract MulticallTarget is IMulticallTarget {\n error MulticallTarget__UndeterminedRevert();\n\n /// @notice Perform a batched call to this contract, preserving the msg.sender.\n /// The return data from each call is discarded.\n /// @dev The method is non-payable, so only calls with `msg.value == 0` could be batched.\n /// It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag.\n /// Otherwise, the whole batch call will be reverted with the original revert reason.\n /// @param data List of abi-encoded calldata for the calls to perform.\n /// @param ignoreReverts Whether to ignore the revert errors from the calls.\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external {\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\n if (!success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(result);\n }\n }\n }\n\n /// @notice Perform a batched call to this contract, preserving the msg.sender.\n /// The return data from each call is preserved.\n /// @dev The method is non-payable, so only calls with `msg.value == 0` could be batched.\n /// It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag.\n /// Otherwise, the whole batch call will be reverted with the original revert reason.\n /// @param data List of abi-encoded calldata for the calls to perform.\n /// @param ignoreReverts Whether to ignore the revert errors from the calls.\n /// @return results List of results from the calls: `(success, returnData)`.\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results)\n {\n results = new Result[](data.length);\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (results[i].success, results[i].returnData) = address(this).delegatecall(data[i]);\n if (!results[i].success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(results[i].returnData);\n }\n }\n }\n\n /// @dev Bubbles the revert message from the underlying call.\n /// Note: preserves the same custom error or revert string, if one was used.\n /// Source: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v5.0.2/contracts/utils/Address.sol#L143-L158\n function _bubbleRevert(bytes memory returnData) internal pure {\n // Look for revert reason and bubble it up if present\n if (returnData.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n // solhint-disable-next-line no-inline-assembly\n assembly {\n let returndata_size := mload(returnData)\n revert(add(32, returnData), returndata_size)\n }\n } else {\n revert MulticallTarget__UndeterminedRevert();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// contracts/libs/BridgeTransactionV2.sol\n\n// solhint-disable no-inline-assembly\nlibrary BridgeTransactionV2Lib {\n uint16 internal constant VERSION = 2;\n\n // Offsets of the fields in the packed BridgeTransactionV2 struct\n // uint16 version [000 .. 002)\n // uint32 originChainId [002 .. 006)\n // uint32 destChainId [006 .. 010)\n // address originSender [010 .. 030)\n // address destRecipient [030 .. 050)\n // address originToken [050 .. 070)\n // address destToken [070 .. 090)\n // uint256 originAmount [090 .. 122)\n // uint256 destAmount [122 .. 154)\n // uint256 originFeeAmount [154 .. 186)\n // uint256 deadline [186 .. 218)\n // uint256 nonce [218 .. 250)\n // address exclusivityRelayer [250 .. 270)\n // uint256 exclusivityEndTime [270 .. 302)\n // uint256 zapNative [302 .. 334)\n // bytes zapData [334 .. ***)\n\n // forgefmt: disable-start\n uint256 private constant OFFSET_ORIGIN_CHAIN_ID = 2;\n uint256 private constant OFFSET_DEST_CHAIN_ID = 6;\n uint256 private constant OFFSET_ORIGIN_SENDER = 10;\n uint256 private constant OFFSET_DEST_RECIPIENT = 30;\n uint256 private constant OFFSET_ORIGIN_TOKEN = 50;\n uint256 private constant OFFSET_DEST_TOKEN = 70;\n uint256 private constant OFFSET_ORIGIN_AMOUNT = 90;\n uint256 private constant OFFSET_DEST_AMOUNT = 122;\n uint256 private constant OFFSET_ORIGIN_FEE_AMOUNT = 154;\n uint256 private constant OFFSET_DEADLINE = 186;\n uint256 private constant OFFSET_NONCE = 218;\n uint256 private constant OFFSET_EXCLUSIVITY_RELAYER = 250;\n uint256 private constant OFFSET_EXCLUSIVITY_END_TIME = 270;\n uint256 private constant OFFSET_ZAP_NATIVE = 302;\n uint256 private constant OFFSET_ZAP_DATA = 334;\n // forgefmt: disable-end\n\n error BridgeTransactionV2__InvalidEncodedTx();\n error BridgeTransactionV2__UnsupportedVersion(uint16 version);\n\n /// @notice Validates the encoded transaction to be a tightly packed encoded payload for BridgeTransactionV2.\n /// @dev Checks the minimum length and the version, use this function before decoding any of the fields.\n function validateV2(bytes calldata encodedTx) internal pure {\n // Check the minimum length: must at least include all static fields.\n if (encodedTx.length \u003c OFFSET_ZAP_DATA) revert BridgeTransactionV2__InvalidEncodedTx();\n // Once we validated the length, we can be sure that the version field is present.\n uint16 version_ = version(encodedTx);\n if (version_ != VERSION) revert BridgeTransactionV2__UnsupportedVersion(version_);\n }\n\n /// @notice Encodes the BridgeTransactionV2 struct by tightly packing the fields.\n /// @dev `abi.decode` will not work as a result of the tightly packed fields. Use `decodeV2` to decode instead.\n function encodeV2(IFastBridgeV2.BridgeTransactionV2 memory bridgeTx) internal pure returns (bytes memory) {\n // We split the encoding into two parts to avoid stack-too-deep error\n bytes memory firstPart = abi.encodePacked(\n VERSION,\n bridgeTx.originChainId,\n bridgeTx.destChainId,\n bridgeTx.originSender,\n bridgeTx.destRecipient,\n bridgeTx.originToken,\n bridgeTx.destToken,\n bridgeTx.originAmount\n );\n return abi.encodePacked(\n firstPart,\n bridgeTx.destAmount,\n bridgeTx.originFeeAmount,\n // Note: we skip the deprecated `sendChainGas` flag, which was present in BridgeTransaction V1\n bridgeTx.deadline,\n bridgeTx.nonce,\n // New V2 fields: exclusivity\n bridgeTx.exclusivityRelayer,\n bridgeTx.exclusivityEndTime,\n // New V2 fields: Zap\n bridgeTx.zapNative,\n bridgeTx.zapData\n );\n }\n\n /// @notice Decodes the BridgeTransactionV2 struct from the encoded transaction.\n /// @dev Encoded BridgeTransactionV2 struct must be tightly packed.\n /// Use `validateV2` before decoding to ensure the encoded transaction is valid.\n function decodeV2(bytes calldata encodedTx)\n internal\n pure\n returns (IFastBridgeV2.BridgeTransactionV2 memory bridgeTx)\n {\n bridgeTx.originChainId = originChainId(encodedTx);\n bridgeTx.destChainId = destChainId(encodedTx);\n bridgeTx.originSender = originSender(encodedTx);\n bridgeTx.destRecipient = destRecipient(encodedTx);\n bridgeTx.originToken = originToken(encodedTx);\n bridgeTx.destToken = destToken(encodedTx);\n bridgeTx.originAmount = originAmount(encodedTx);\n bridgeTx.destAmount = destAmount(encodedTx);\n bridgeTx.originFeeAmount = originFeeAmount(encodedTx);\n bridgeTx.deadline = deadline(encodedTx);\n bridgeTx.nonce = nonce(encodedTx);\n bridgeTx.exclusivityRelayer = exclusivityRelayer(encodedTx);\n bridgeTx.exclusivityEndTime = exclusivityEndTime(encodedTx);\n bridgeTx.zapNative = zapNative(encodedTx);\n bridgeTx.zapData = zapData(encodedTx);\n }\n\n /// @notice Extracts the version from the encoded transaction.\n function version(bytes calldata encodedTx) internal pure returns (uint16 version_) {\n // Load 32 bytes from the start and shift it 240 bits to the right to get the highest 16 bits.\n assembly {\n version_ := shr(240, calldataload(encodedTx.offset))\n }\n }\n\n /// @notice Extracts the origin chain ID from the encoded transaction.\n function originChainId(bytes calldata encodedTx) internal pure returns (uint32 originChainId_) {\n // Load 32 bytes from the offset and shift it 224 bits to the right to get the highest 32 bits.\n assembly {\n originChainId_ := shr(224, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_CHAIN_ID)))\n }\n }\n\n /// @notice Extracts the destination chain ID from the encoded transaction.\n function destChainId(bytes calldata encodedTx) internal pure returns (uint32 destChainId_) {\n // Load 32 bytes from the offset and shift it 224 bits to the right to get the highest 32 bits.\n assembly {\n destChainId_ := shr(224, calldataload(add(encodedTx.offset, OFFSET_DEST_CHAIN_ID)))\n }\n }\n\n /// @notice Extracts the origin sender from the encoded transaction.\n function originSender(bytes calldata encodedTx) internal pure returns (address originSender_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n originSender_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_SENDER)))\n }\n }\n\n /// @notice Extracts the destination recipient from the encoded transaction.\n function destRecipient(bytes calldata encodedTx) internal pure returns (address destRecipient_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n destRecipient_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_DEST_RECIPIENT)))\n }\n }\n\n /// @notice Extracts the origin token from the encoded transaction.\n function originToken(bytes calldata encodedTx) internal pure returns (address originToken_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n originToken_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_TOKEN)))\n }\n }\n\n /// @notice Extracts the destination token from the encoded transaction.\n function destToken(bytes calldata encodedTx) internal pure returns (address destToken_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n destToken_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_DEST_TOKEN)))\n }\n }\n\n /// @notice Extracts the origin amount from the encoded transaction.\n function originAmount(bytes calldata encodedTx) internal pure returns (uint256 originAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n originAmount_ := calldataload(add(encodedTx.offset, OFFSET_ORIGIN_AMOUNT))\n }\n }\n\n /// @notice Extracts the destination amount from the encoded transaction.\n function destAmount(bytes calldata encodedTx) internal pure returns (uint256 destAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n destAmount_ := calldataload(add(encodedTx.offset, OFFSET_DEST_AMOUNT))\n }\n }\n\n /// @notice Extracts the origin fee amount from the encoded transaction.\n function originFeeAmount(bytes calldata encodedTx) internal pure returns (uint256 originFeeAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n originFeeAmount_ := calldataload(add(encodedTx.offset, OFFSET_ORIGIN_FEE_AMOUNT))\n }\n }\n\n /// @notice Extracts the deadline from the encoded transaction.\n function deadline(bytes calldata encodedTx) internal pure returns (uint256 deadline_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n deadline_ := calldataload(add(encodedTx.offset, OFFSET_DEADLINE))\n }\n }\n\n /// @notice Extracts the nonce from the encoded transaction.\n function nonce(bytes calldata encodedTx) internal pure returns (uint256 nonce_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n nonce_ := calldataload(add(encodedTx.offset, OFFSET_NONCE))\n }\n }\n\n /// @notice Extracts the exclusivity relayer from the encoded transaction.\n function exclusivityRelayer(bytes calldata encodedTx) internal pure returns (address exclusivityRelayer_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n exclusivityRelayer_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_EXCLUSIVITY_RELAYER)))\n }\n }\n\n /// @notice Extracts the exclusivity end time from the encoded transaction.\n function exclusivityEndTime(bytes calldata encodedTx) internal pure returns (uint256 exclusivityEndTime_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n exclusivityEndTime_ := calldataload(add(encodedTx.offset, OFFSET_EXCLUSIVITY_END_TIME))\n }\n }\n\n /// @notice Extracts the Zap's native value from the encoded transaction.\n function zapNative(bytes calldata encodedTx) internal pure returns (uint256 zapNative_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n zapNative_ := calldataload(add(encodedTx.offset, OFFSET_ZAP_NATIVE))\n }\n }\n\n /// @notice Extracts the Zap's data from the encoded transaction.\n function zapData(bytes calldata encodedTx) internal pure returns (bytes calldata zapData_) {\n zapData_ = encodedTx[OFFSET_ZAP_DATA:];\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// contracts/libs/UniversalToken.sol\n\nlibrary UniversalTokenLib {\n using SafeERC20 for IERC20;\n\n address internal constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Transfers tokens to the given account. Reverts if transfer is not successful.\n /// @dev This might trigger fallback, if ETH is transferred to the contract.\n /// Make sure this can not lead to reentrancy attacks.\n function universalTransfer(address token, address to, uint256 value) internal {\n // Don't do anything, if need to send tokens to this address\n if (to == address(this)) return;\n // Don't do anything, if trying to send zero value\n if (value == 0) return;\n if (token == ETH_ADDRESS) {\n /// @dev Note: this can potentially lead to executing code in `to`.\n // solhint-disable-next-line avoid-low-level-calls\n (bool success,) = to.call{value: value}(\"\");\n require(success, \"ETH transfer failed\");\n } else {\n IERC20(token).safeTransfer(to, value);\n }\n }\n\n /// @notice Issues an infinite allowance to the spender, if the current allowance is insufficient\n /// to spend the given amount.\n function universalApproveInfinity(address token, address spender, uint256 amountToSpend) internal {\n // ETH Chad doesn't require your approval\n if (token == ETH_ADDRESS) return;\n // No-op if allowance is already sufficient\n uint256 allowance = IERC20(token).allowance(address(this), spender);\n if (allowance \u003e= amountToSpend) return;\n // Otherwise, reset approval to 0 and set to max allowance\n if (allowance \u003e 0) IERC20(token).safeDecreaseAllowance(spender, allowance);\n IERC20(token).safeIncreaseAllowance(spender, type(uint256).max);\n }\n\n /// @notice Returns the balance of the given token (or native ETH) for the given account.\n function universalBalanceOf(address token, address account) internal view returns (uint256) {\n if (token == ETH_ADDRESS) {\n return account.balance;\n } else {\n return IERC20(token).balanceOf(account);\n }\n }\n\n /// @dev Checks that token is a contract and not ETH_ADDRESS.\n function assertIsContract(address token) internal view {\n // Check that ETH_ADDRESS was not used (in case this is a predeploy on any of the chains)\n if (token == UniversalTokenLib.ETH_ADDRESS) revert TokenNotContract();\n // Check that token is not an EOA\n if (token.code.length == 0) revert TokenNotContract();\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/Admin.sol\n\ncontract Admin is IAdmin, AccessControlEnumerable {\n using UniversalTokenLib for address;\n\n bytes32 public constant RELAYER_ROLE = keccak256(\"RELAYER_ROLE\");\n bytes32 public constant REFUNDER_ROLE = keccak256(\"REFUNDER_ROLE\");\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n uint256 public constant FEE_BPS = 1e6;\n uint256 public constant FEE_RATE_MAX = 0.01e6; // max 1% on origin amount\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Chain gas amount to forward as rebate if requested\n uint256 public chainGasAmount;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n }\n\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n require(newFeeRate \u003c= FEE_RATE_MAX, \"newFeeRate \u003e max\");\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n token.universalTransfer(recipient, feeAmount);\n emit FeesSwept(token, recipient, feeAmount);\n }\n\n function setChainGasAmount(uint256 newChainGasAmount) external onlyRole(GOVERNOR_ROLE) {\n uint256 oldChainGasAmount = chainGasAmount;\n chainGasAmount = newChainGasAmount;\n emit ChainGasAmountUpdated(oldChainGasAmount, newChainGasAmount);\n }\n}\n\n// contracts/FastBridgeV2.sol\n\n/// @notice FastBridgeV2 is a contract for bridging tokens across chains.\ncontract FastBridgeV2 is Admin, MulticallTarget, IFastBridgeV2, IFastBridgeV2Errors {\n using BridgeTransactionV2Lib for bytes;\n using SafeERC20 for IERC20;\n\n /// @notice Address reserved for native gas token (ETH on Ethereum and most L2s, AVAX on Avalanche, etc)\n address public constant NATIVE_GAS_TOKEN = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Delay for a transaction after which it could be permisionlessly refunded\n uint256 public constant REFUND_DELAY = 7 days;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n /// @notice Maximum length of accepted zapData\n uint256 public constant MAX_ZAP_DATA_LENGTH = 2 ** 16 - 1;\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeTxDetails) public bridgeTxDetails;\n /// @notice Relay details on destination chain\n mapping(bytes32 =\u003e BridgeRelay) public bridgeRelayDetails;\n /// @notice Unique bridge nonces tracked per originSender\n mapping(address =\u003e uint256) public senderNonces;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Replaced by senderNonces\n uint256 public immutable nonce = 0;\n /// @notice the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n bridge({\n params: params,\n paramsV2: BridgeParamsV2({\n quoteRelayer: address(0),\n quoteExclusivitySeconds: 0,\n quoteId: bytes(\"\"),\n zapNative: 0,\n zapData: bytes(\"\")\n })\n });\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes calldata request) external payable {\n // relay override will validate the request\n relay({request: request, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes calldata request, bytes32 destTxHash) external {\n request.validateV2();\n prove({transactionId: keccak256(request), destTxHash: destTxHash, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridgeV2\n function claim(bytes calldata request) external {\n // claim override will validate the request\n claim({request: request, to: address(0)});\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Aggregate the read operations from the same storage slot\n address disputedRelayer = $.proofRelayer;\n BridgeStatus status = $.status;\n uint56 proofBlockTimestamp = $.proofBlockTimestamp;\n // Can only dispute a RELAYER_PROVED transaction within the dispute period\n if (status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(proofBlockTimestamp) \u003e DISPUTE_PERIOD) {\n revert DisputePeriodPassed();\n }\n // Update status to REQUESTED and delete the disputed proof details\n // Note: these are storage writes\n $.status = BridgeStatus.REQUESTED;\n $.proofRelayer = address(0);\n $.proofBlockTimestamp = 0;\n\n emit BridgeProofDisputed(transactionId, disputedRelayer);\n }\n\n /// @inheritdoc IFastBridge\n function refund(bytes calldata request) external {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Can only refund a REQUESTED transaction after its deadline expires\n if ($.status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n uint256 deadline = request.deadline();\n // Permissionless refund is only allowed after REFUND_DELAY on top of the deadline\n if (!hasRole(REFUNDER_ROLE, msg.sender)) deadline += REFUND_DELAY;\n if (block.timestamp \u003c= deadline) revert DeadlineNotExceeded();\n // Update status to REFUNDED and return the full amount (collateral + protocol fees) to the original sender.\n // The protocol fees are only updated when the transaction is claimed, so we don't need to update them here.\n // Note: this is a storage write\n $.status = BridgeStatus.REFUNDED;\n\n address to = request.originSender();\n address token = request.originToken();\n uint256 amount = request.originAmount() + request.originFeeAmount();\n // Emit the event before any external calls\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n // Complete the user refund as the last transaction action\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(to), amount);\n } else {\n IERC20(token).safeTransfer(to, amount);\n }\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // The correct relayer can only claim a RELAYER_PROVED transaction after the dispute period\n if ($.status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if ($.proofRelayer != relayer) revert SenderIncorrect();\n return _timeSince($.proofBlockTimestamp) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n /// @dev This method is added to achieve backwards compatibility with decoding requests into V1 structs:\n /// - `zapNative` is partially reported as a zero/non-zero flag\n /// - `zapData` is ignored\n /// In order to process all kinds of requests use getBridgeTransactionV2 instead.\n function getBridgeTransaction(bytes calldata request) external view returns (BridgeTransaction memory) {\n // Try decoding into V2 struct first. This will revert if V1 struct is passed\n try this.getBridgeTransactionV2(request) returns (BridgeTransactionV2 memory txV2) {\n // Note: we entirely ignore the zapData field, as it was not present in V1\n return BridgeTransaction({\n originChainId: txV2.originChainId,\n destChainId: txV2.destChainId,\n originSender: txV2.originSender,\n destRecipient: txV2.destRecipient,\n originToken: txV2.originToken,\n destToken: txV2.destToken,\n originAmount: txV2.originAmount,\n destAmount: txV2.destAmount,\n originFeeAmount: txV2.originFeeAmount,\n sendChainGas: txV2.zapNative != 0,\n deadline: txV2.deadline,\n nonce: txV2.nonce\n });\n } catch {\n // Fallback to V1 struct\n return abi.decode(request, (BridgeTransaction));\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function getBridgeTransactionV2(bytes calldata request) external pure returns (BridgeTransactionV2 memory) {\n request.validateV2();\n return BridgeTransactionV2Lib.decodeV2(request);\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) public payable {\n int256 exclusivityEndTime = 0;\n // if relayer exclusivity is not intended for this bridge, set exclusivityEndTime to static zero\n // otherwise, set exclusivity to expire at the current block ts offset by quoteExclusivitySeconds\n if (paramsV2.quoteRelayer != address(0)) {\n exclusivityEndTime = int256(block.timestamp) + paramsV2.quoteExclusivitySeconds;\n }\n _validateBridgeParams(params, paramsV2, exclusivityEndTime);\n\n // transfer tokens to bridge contract\n /// @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _takeBridgedUserAsset(params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) {\n originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n }\n\n // set status to requested\n bytes memory request = BridgeTransactionV2Lib.encodeV2(\n BridgeTransactionV2({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n deadline: params.deadline,\n nonce: senderNonces[params.sender]++, // increment nonce on every bridge\n exclusivityRelayer: paramsV2.quoteRelayer,\n // We checked exclusivityEndTime to be in range [0 .. params.deadline] above, so can safely cast\n exclusivityEndTime: uint256(exclusivityEndTime),\n zapNative: paramsV2.zapNative,\n zapData: paramsV2.zapData\n })\n );\n bytes32 transactionId = keccak256(request);\n // Note: the tx status will be updated throughout the tx lifecycle, while destChainId is set once here\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n bridgeTxDetails[transactionId].destChainId = params.dstChainId;\n\n emit BridgeRequested({\n transactionId: transactionId,\n sender: params.sender,\n request: request,\n destChainId: params.dstChainId,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n sendChainGas: paramsV2.zapNative != 0\n });\n emit BridgeQuoteDetails(transactionId, paramsV2.quoteId);\n }\n\n /// @inheritdoc IFastBridgeV2\n function relay(bytes calldata request, address relayer) public payable {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n _validateRelayParams(request, transactionId, relayer);\n // mark bridge transaction as relayed\n bridgeRelayDetails[transactionId] =\n BridgeRelay({blockNumber: uint48(block.number), blockTimestamp: uint48(block.timestamp), relayer: relayer});\n\n // transfer tokens to recipient on destination chain and trigger Zap if requested\n address to = request.destRecipient();\n address token = request.destToken();\n uint256 amount = request.destAmount();\n uint256 zapNative = request.zapNative();\n\n // Emit the event before any external calls\n emit BridgeRelayed({\n transactionId: transactionId,\n relayer: relayer,\n to: to,\n originChainId: request.originChainId(),\n originToken: request.originToken(),\n destToken: token,\n originAmount: request.originAmount(),\n destAmount: amount,\n chainGasAmount: zapNative\n });\n\n // All state changes have been done at this point, can proceed to the external calls.\n // This follows the checks-effects-interactions pattern to mitigate potential reentrancy attacks.\n if (token == NATIVE_GAS_TOKEN) {\n // For the native gas token, additional zapNative is not allowed\n if (zapNative != 0) revert ZapNativeNotSupported();\n // Check that the correct msg.value was sent\n if (msg.value != amount) revert MsgValueIncorrect();\n // Don't do a native transfer yet: we will handle it alongside the Zap below\n } else {\n // For ERC20s, we check that the correct msg.value was sent\n if (msg.value != zapNative) revert MsgValueIncorrect();\n // We need to transfer the tokens from the Relayer to the recipient first before performing an\n // optional post-transfer Zap.\n IERC20(token).safeTransferFrom(msg.sender, to, amount);\n }\n // At this point we have done:\n // - Transferred the requested amount of ERC20 tokens to the recipient.\n // At this point we have confirmed:\n // - For ERC20s: msg.value matches the requested zapNative amount.\n // - For the native gas token: msg.value matches the requested destAmount.\n // Remaining optional things to do:\n // - Forward the full msg.value to the recipient (if non-zero).\n // - Trigger a Zap (if zapData is present).\n bytes calldata zapData = request.zapData();\n if (zapData.length != 0) {\n // Zap Data is present: Zap has been requested by the recipient. Trigger it forwarding the full msg.value.\n\n // Note: if token has a fee on transfers, the recipient will have received less than `amount`.\n // This is a very niche edge case and should be handled by the recipient contract.\n _triggerZapWithChecks({recipient: to, token: token, amount: amount, zapData: zapData});\n } else if (msg.value != 0) {\n // Zap Data is missing, but msg.value was sent. This could happen in two different cases:\n // - Relay with the native gas token is happening.\n // - Relay with ERC20 is happening, with a `zapNative \u003e 0` request.\n // In both cases, we need to transfer the full msg.value to the recipient.\n Address.sendValue(payable(to), msg.value);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) public onlyRole(RELAYER_ROLE) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n\n // Can only prove a REQUESTED transaction\n if ($.status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n // Update status to RELAYER_PROVED and store the proof details\n // Note: these are storage writes\n $.status = BridgeStatus.RELAYER_PROVED;\n $.proofBlockTimestamp = uint56(block.timestamp);\n $.proofRelayer = relayer;\n\n emit BridgeProofProvided(transactionId, relayer, destTxHash);\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes calldata request, address to) public {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Aggregate the read operations from the same storage slot\n address proofRelayer = $.proofRelayer;\n BridgeStatus status = $.status;\n uint56 proofBlockTimestamp = $.proofBlockTimestamp;\n\n // Can only claim a RELAYER_PROVED transaction after the dispute period\n if (status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(proofBlockTimestamp) \u003c= DISPUTE_PERIOD) {\n revert DisputePeriodNotPassed();\n }\n\n if (to == address(0)) {\n // Anyone could claim the funds to the proven relayer on their behalf\n to = proofRelayer;\n } else if (proofRelayer != msg.sender) {\n // Only the proven relayer could specify an address to claim the funds to\n revert SenderIncorrect();\n }\n\n // Update status to RELAYER_CLAIMED and transfer the origin collateral to the specified claim address\n // Note: this is a storage write\n $.status = BridgeStatus.RELAYER_CLAIMED;\n\n address token = request.originToken();\n uint256 amount = request.originAmount();\n // Update protocol fees if origin fee amount exists\n uint256 originFeeAmount = request.originFeeAmount();\n if (originFeeAmount \u003e 0) protocolFees[token] += originFeeAmount;\n // Emit the event before any external calls\n emit BridgeDepositClaimed(transactionId, proofRelayer, to, token, amount);\n // Complete the relayer claim as the last transaction action\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(to), amount);\n } else {\n IERC20(token).safeTransfer(to, amount);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeStatuses(bytes32 transactionId) public view returns (BridgeStatus status) {\n return bridgeTxDetails[transactionId].status;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeProofs(bytes32 transactionId) public view returns (uint96 timestamp, address relayer) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n\n timestamp = $.proofBlockTimestamp;\n relayer = $.proofRelayer;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeRelays(bytes32 transactionId) public view returns (bool) {\n // has this transactionId been relayed?\n return bridgeRelayDetails[transactionId].relayer != address(0);\n }\n\n /// @notice Takes the bridged asset from the user into FastBridgeV2 custody. It will be later\n /// claimed by the relayer who completed the relay on destination chain, or refunded back to the user,\n /// should no one complete the relay.\n function _takeBridgedUserAsset(address token, uint256 amount) internal returns (uint256 amountTaken) {\n if (token == NATIVE_GAS_TOKEN) {\n // For the native gas token, we just need to check that the supplied msg.value is correct.\n // Supplied `msg.value` is already in FastBridgeV2 custody.\n if (amount != msg.value) revert MsgValueIncorrect();\n amountTaken = msg.value;\n } else {\n // For ERC20s, token is explicitly transferred from the user to FastBridgeV2.\n // We don't allow non-zero `msg.value` to avoid extra funds from being stuck in FastBridgeV2.\n if (msg.value != 0) revert MsgValueIncorrect();\n // Throw an explicit error if the provided token address is not a contract\n if (token.code.length == 0) revert TokenNotContract();\n amountTaken = IERC20(token).balanceOf(address(this));\n IERC20(token).safeTransferFrom(msg.sender, address(this), amount);\n // Use the balance difference as the amount taken in case of fee on transfer tokens.\n amountTaken = IERC20(token).balanceOf(address(this)) - amountTaken;\n }\n }\n\n /// @notice Calls the Recipient's hook function with the specified zapData and performs\n /// all the necessary checks for the returned value.\n function _triggerZapWithChecks(address recipient, address token, uint256 amount, bytes calldata zapData) internal {\n // This will bubble any revert messages from the hook function\n bytes memory returnData = Address.functionCallWithValue({\n target: recipient,\n data: abi.encodeCall(IZapRecipient.zap, (token, amount, zapData)),\n // Note: see `relay()` for reasoning behind passing msg.value\n value: msg.value\n });\n // Explicit revert if no return data at all\n if (returnData.length == 0) revert RecipientNoReturnValue();\n // Check that exactly a single return value was returned\n if (returnData.length != 32) revert RecipientIncorrectReturnValue();\n // Return value should be abi-encoded hook function selector\n if (bytes32(returnData) != bytes32(IZapRecipient.zap.selector)) {\n revert RecipientIncorrectReturnValue();\n }\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint56(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint56).max but\n /// proof.timestamp \u003c type(uint56).max via unchecked statement\n /// @param proofBlockTimestamp The bridge proof block timestamp\n /// @return delta Time delta since proof submitted\n function _timeSince(uint56 proofBlockTimestamp) internal view returns (uint256 delta) {\n unchecked {\n delta = uint56(block.timestamp) - proofBlockTimestamp;\n }\n }\n\n /// @notice Performs all the necessary checks for a bridge to happen.\n /// @dev There's no good way to refactor this function to reduce cyclomatic complexity due to\n /// the number of checks that need to be performed, so we skip the code-complexity rule here.\n // solhint-disable-next-line code-complexity\n function _validateBridgeParams(\n BridgeParams memory params,\n BridgeParamsV2 memory paramsV2,\n int256 exclusivityEndTime\n )\n internal\n view\n {\n // Check V1 (legacy) params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.sender == address(0) || params.to == address(0)) revert ZeroAddress();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n // Check V2 params\n if (paramsV2.zapData.length \u003e MAX_ZAP_DATA_LENGTH) revert ZapDataLengthAboveMax();\n if (paramsV2.zapNative != 0 \u0026\u0026 params.destToken == NATIVE_GAS_TOKEN) {\n revert ZapNativeNotSupported();\n }\n // exclusivityEndTime must be in range [0 .. params.deadline]\n if (exclusivityEndTime \u003c 0 || exclusivityEndTime \u003e int256(params.deadline)) {\n revert ExclusivityParamsIncorrect();\n }\n }\n\n /// @notice Performs all the necessary checks for a relay to happen.\n function _validateRelayParams(bytes calldata request, bytes32 transactionId, address relayer) internal view {\n if (relayer == address(0)) revert ZeroAddress();\n // Check if the transaction has already been relayed\n if (bridgeRelays(transactionId)) revert TransactionRelayed();\n if (request.destChainId() != block.chainid) revert ChainIncorrect();\n // Check the deadline for relay to happen\n if (block.timestamp \u003e request.deadline()) revert DeadlineExceeded();\n // Check the exclusivity period, if it is still ongoing\n address exclRelayer = request.exclusivityRelayer();\n if (exclRelayer != address(0) \u0026\u0026 exclRelayer != relayer \u0026\u0026 block.timestamp \u003c= request.exclusivityEndTime()) {\n revert ExclusivityPeriodNotPassed();\n }\n }\n}\n","language":"Solidity","languageVersion":"0.8.24","compilerVersion":"0.8.24","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"49702:11496:0:-:0;;;;;;;;;;;;;;;-1:-1:-1;;;49702:11496:0;;;;;;;;;;;;;;;;;","srcMapRuntime":"49702:11496:0:-:0;;;;;;;;","abiDefinition":[{"inputs":[],"name":"BridgeTransactionV2__InvalidEncodedTx","type":"error"},{"inputs":[{"internalType":"uint16","name":"version","type":"uint16"}],"name":"BridgeTransactionV2__UnsupportedVersion","type":"error"}],"userDoc":{"kind":"user","methods":{},"version":1},"developerDoc":{"kind":"dev","methods":{},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[],\"name\":\"BridgeTransactionV2__InvalidEncodedTx\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint16\",\"name\":\"version\",\"type\":\"uint16\"}],\"name\":\"BridgeTransactionV2__UnsupportedVersion\",\"type\":\"error\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeV2.sol\":\"BridgeTransactionV2Lib\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeV2.sol\":{\"keccak256\":\"0x5069b55ca07f21bfe30b2a43c18a18318c8af9c181b2dcb07c290825efd70f34\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://273dc020a49d08e50126bbea0d7f783f79d08c702f2fdbc560618d24af308acc\",\"dweb:/ipfs/QmXJ2UVzFc8EPB74RT4CXQPC4xw66jt4T13poyfyd3UERh\"]}},\"version\":1}"},"hashes":{}},"solidity/FastBridgeV2.sol:Context":{"code":"0x","runtime-code":"0x","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.24 ^0.8.20 ^0.8.4;\n\n// contracts/interfaces/IAdmin.sol\n\ninterface IAdmin {\n // ============ Events ============\n\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n event ChainGasAmountUpdated(uint256 oldChainGasAmount, uint256 newChainGasAmount);\n\n // ============ Methods ============\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n\n function setChainGasAmount(uint256 newChainGasAmount) external;\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IFastBridgeV2Errors.sol\n\ninterface IFastBridgeV2Errors {\n error AmountIncorrect();\n error ChainIncorrect();\n error ExclusivityParamsIncorrect();\n error MsgValueIncorrect();\n error SenderIncorrect();\n error StatusIncorrect();\n error TokenNotContract();\n error ZapDataLengthAboveMax();\n error ZapNativeNotSupported();\n error ZeroAddress();\n\n error RecipientIncorrectReturnValue();\n error RecipientNoReturnValue();\n\n error DeadlineExceeded();\n error DeadlineNotExceeded();\n error DeadlineTooShort();\n error DisputePeriodNotPassed();\n error DisputePeriodPassed();\n error ExclusivityPeriodNotPassed();\n\n error TransactionRelayed();\n}\n\n// contracts/interfaces/IMulticallTarget.sol\n\n/// @notice Interface for a contract that can be called multiple times by the same caller. Inspired by MulticallV3:\n/// https://github.com/mds1/multicall/blob/master/src/Multicall3.sol\ninterface IMulticallTarget {\n struct Result {\n bool success;\n bytes returnData;\n }\n\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external;\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results);\n}\n\n// contracts/interfaces/IZapRecipient.sol\n\ninterface IZapRecipient {\n function zap(address token, uint256 amount, bytes memory zapData) external payable returns (bytes4);\n}\n\n// contracts/libs/Errors.sol\n\nerror DeadlineExceeded();\nerror DeadlineNotExceeded();\nerror DeadlineTooShort();\nerror InsufficientOutputAmount();\n\nerror MsgValueIncorrect();\nerror PoolNotFound();\nerror TokenAddressMismatch();\nerror TokenNotContract();\nerror TokenNotETH();\nerror TokensIdentical();\n\nerror ChainIncorrect();\nerror AmountIncorrect();\nerror ZeroAddress();\n\nerror DisputePeriodNotPassed();\nerror DisputePeriodPassed();\nerror SenderIncorrect();\nerror StatusIncorrect();\nerror TransactionIdIncorrect();\nerror TransactionRelayed();\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// contracts/interfaces/IFastBridgeV2.sol\n\ninterface IFastBridgeV2 is IFastBridge {\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n struct BridgeTxDetails {\n BridgeStatus status;\n uint32 destChainId;\n uint56 proofBlockTimestamp;\n address proofRelayer;\n }\n\n struct BridgeRelay {\n uint48 blockNumber;\n uint48 blockTimestamp;\n address relayer;\n }\n\n /// @notice New params introduced in the FastBridgeV2.\n /// We are passing fields from the older BridgeParams struct outside of this struct\n /// for backwards compatibility.\n /// Note: quoteRelayer and quoteExclusivitySeconds are either both zero (indicating no exclusivity)\n /// or both non-zero (indicating exclusivity for the given period).\n /// Note: zapNative \u003e 0 can NOT be used with destToken = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE (native token)\n /// @param quoteRelayer Relayer that provided the quote for the transaction\n /// @param quoteExclusivitySeconds Period of time the quote relayer is guaranteed exclusivity after user's deposit\n /// @param quoteId Unique quote identifier used for tracking the quote\n /// @param zapNative ETH value to send to the recipient (if any)\n /// @param zapData Parameters for the Zap to the destination recipient (if any)\n struct BridgeParamsV2 {\n address quoteRelayer;\n int256 quoteExclusivitySeconds;\n bytes quoteId;\n uint256 zapNative;\n bytes zapData;\n }\n\n /// @notice Updated bridge transaction struct to include parameters introduced in FastBridgeV2.\n /// Note: only `exclusivityRelayer` can fill such a transaction until `exclusivityEndTime`.\n struct BridgeTransactionV2 {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n // Note: sendChainGas flag from V1 is deprecated\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n address exclusivityRelayer;\n uint256 exclusivityEndTime;\n uint256 zapNative; // ETH value to send to the recipient (if any)\n bytes zapData; // data to pass for the Zap action (if any)\n }\n\n event BridgeQuoteDetails(bytes32 indexed transactionId, bytes quoteId);\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability\n /// to provide temporary exclusivity fill rights for the quote relayer.\n /// @param params The parameters required to bridge\n /// @param paramsV2 The parameters for exclusivity fill rights (optional, can be left empty)\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function relay(bytes memory request, address relayer) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param transactionId The transaction id associated with the encoded bridge transaction to prove\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital.\n /// @notice Can only send funds to the relayer address on the proof.\n /// @param request The encoded bridge transaction to claim on origin chain\n function claim(bytes memory request) external;\n /// @notice Checks if a transaction has been relayed\n /// @param transactionId The ID of the transaction to check\n /// @return True if the transaction has been relayed, false otherwise\n function bridgeRelays(bytes32 transactionId) external view returns (bool);\n\n /// @notice Returns the status of a bridge transaction\n /// @param transactionId The ID of the bridge transaction\n /// @return BridgeStatus Status of the bridge transaction\n function bridgeStatuses(bytes32 transactionId) external view returns (BridgeStatus);\n\n /// @notice Returns the timestamp and relayer of a bridge proof\n /// @param transactionId The ID of the bridge transaction\n /// @return timestamp The timestamp of the bridge proof\n /// @return relayer The relayer address of the bridge proof\n function bridgeProofs(bytes32 transactionId) external view returns (uint96 timestamp, address relayer);\n\n /// @notice Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\n /// @param request The bridge request to decode\n function getBridgeTransactionV2(bytes memory request) external view returns (BridgeTransactionV2 memory);\n}\n\n// contracts/utils/MulticallTarget.sol\n\n// solhint-disable avoid-low-level-calls\n/// @notice Template for a contract that supports batched calls (preserving the msg.sender).\n/// Only calls with zero msg.value could be batched.\nabstract contract MulticallTarget is IMulticallTarget {\n error MulticallTarget__UndeterminedRevert();\n\n /// @notice Perform a batched call to this contract, preserving the msg.sender.\n /// The return data from each call is discarded.\n /// @dev The method is non-payable, so only calls with `msg.value == 0` could be batched.\n /// It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag.\n /// Otherwise, the whole batch call will be reverted with the original revert reason.\n /// @param data List of abi-encoded calldata for the calls to perform.\n /// @param ignoreReverts Whether to ignore the revert errors from the calls.\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external {\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\n if (!success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(result);\n }\n }\n }\n\n /// @notice Perform a batched call to this contract, preserving the msg.sender.\n /// The return data from each call is preserved.\n /// @dev The method is non-payable, so only calls with `msg.value == 0` could be batched.\n /// It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag.\n /// Otherwise, the whole batch call will be reverted with the original revert reason.\n /// @param data List of abi-encoded calldata for the calls to perform.\n /// @param ignoreReverts Whether to ignore the revert errors from the calls.\n /// @return results List of results from the calls: `(success, returnData)`.\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results)\n {\n results = new Result[](data.length);\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (results[i].success, results[i].returnData) = address(this).delegatecall(data[i]);\n if (!results[i].success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(results[i].returnData);\n }\n }\n }\n\n /// @dev Bubbles the revert message from the underlying call.\n /// Note: preserves the same custom error or revert string, if one was used.\n /// Source: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v5.0.2/contracts/utils/Address.sol#L143-L158\n function _bubbleRevert(bytes memory returnData) internal pure {\n // Look for revert reason and bubble it up if present\n if (returnData.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n // solhint-disable-next-line no-inline-assembly\n assembly {\n let returndata_size := mload(returnData)\n revert(add(32, returnData), returndata_size)\n }\n } else {\n revert MulticallTarget__UndeterminedRevert();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// contracts/libs/BridgeTransactionV2.sol\n\n// solhint-disable no-inline-assembly\nlibrary BridgeTransactionV2Lib {\n uint16 internal constant VERSION = 2;\n\n // Offsets of the fields in the packed BridgeTransactionV2 struct\n // uint16 version [000 .. 002)\n // uint32 originChainId [002 .. 006)\n // uint32 destChainId [006 .. 010)\n // address originSender [010 .. 030)\n // address destRecipient [030 .. 050)\n // address originToken [050 .. 070)\n // address destToken [070 .. 090)\n // uint256 originAmount [090 .. 122)\n // uint256 destAmount [122 .. 154)\n // uint256 originFeeAmount [154 .. 186)\n // uint256 deadline [186 .. 218)\n // uint256 nonce [218 .. 250)\n // address exclusivityRelayer [250 .. 270)\n // uint256 exclusivityEndTime [270 .. 302)\n // uint256 zapNative [302 .. 334)\n // bytes zapData [334 .. ***)\n\n // forgefmt: disable-start\n uint256 private constant OFFSET_ORIGIN_CHAIN_ID = 2;\n uint256 private constant OFFSET_DEST_CHAIN_ID = 6;\n uint256 private constant OFFSET_ORIGIN_SENDER = 10;\n uint256 private constant OFFSET_DEST_RECIPIENT = 30;\n uint256 private constant OFFSET_ORIGIN_TOKEN = 50;\n uint256 private constant OFFSET_DEST_TOKEN = 70;\n uint256 private constant OFFSET_ORIGIN_AMOUNT = 90;\n uint256 private constant OFFSET_DEST_AMOUNT = 122;\n uint256 private constant OFFSET_ORIGIN_FEE_AMOUNT = 154;\n uint256 private constant OFFSET_DEADLINE = 186;\n uint256 private constant OFFSET_NONCE = 218;\n uint256 private constant OFFSET_EXCLUSIVITY_RELAYER = 250;\n uint256 private constant OFFSET_EXCLUSIVITY_END_TIME = 270;\n uint256 private constant OFFSET_ZAP_NATIVE = 302;\n uint256 private constant OFFSET_ZAP_DATA = 334;\n // forgefmt: disable-end\n\n error BridgeTransactionV2__InvalidEncodedTx();\n error BridgeTransactionV2__UnsupportedVersion(uint16 version);\n\n /// @notice Validates the encoded transaction to be a tightly packed encoded payload for BridgeTransactionV2.\n /// @dev Checks the minimum length and the version, use this function before decoding any of the fields.\n function validateV2(bytes calldata encodedTx) internal pure {\n // Check the minimum length: must at least include all static fields.\n if (encodedTx.length \u003c OFFSET_ZAP_DATA) revert BridgeTransactionV2__InvalidEncodedTx();\n // Once we validated the length, we can be sure that the version field is present.\n uint16 version_ = version(encodedTx);\n if (version_ != VERSION) revert BridgeTransactionV2__UnsupportedVersion(version_);\n }\n\n /// @notice Encodes the BridgeTransactionV2 struct by tightly packing the fields.\n /// @dev `abi.decode` will not work as a result of the tightly packed fields. Use `decodeV2` to decode instead.\n function encodeV2(IFastBridgeV2.BridgeTransactionV2 memory bridgeTx) internal pure returns (bytes memory) {\n // We split the encoding into two parts to avoid stack-too-deep error\n bytes memory firstPart = abi.encodePacked(\n VERSION,\n bridgeTx.originChainId,\n bridgeTx.destChainId,\n bridgeTx.originSender,\n bridgeTx.destRecipient,\n bridgeTx.originToken,\n bridgeTx.destToken,\n bridgeTx.originAmount\n );\n return abi.encodePacked(\n firstPart,\n bridgeTx.destAmount,\n bridgeTx.originFeeAmount,\n // Note: we skip the deprecated `sendChainGas` flag, which was present in BridgeTransaction V1\n bridgeTx.deadline,\n bridgeTx.nonce,\n // New V2 fields: exclusivity\n bridgeTx.exclusivityRelayer,\n bridgeTx.exclusivityEndTime,\n // New V2 fields: Zap\n bridgeTx.zapNative,\n bridgeTx.zapData\n );\n }\n\n /// @notice Decodes the BridgeTransactionV2 struct from the encoded transaction.\n /// @dev Encoded BridgeTransactionV2 struct must be tightly packed.\n /// Use `validateV2` before decoding to ensure the encoded transaction is valid.\n function decodeV2(bytes calldata encodedTx)\n internal\n pure\n returns (IFastBridgeV2.BridgeTransactionV2 memory bridgeTx)\n {\n bridgeTx.originChainId = originChainId(encodedTx);\n bridgeTx.destChainId = destChainId(encodedTx);\n bridgeTx.originSender = originSender(encodedTx);\n bridgeTx.destRecipient = destRecipient(encodedTx);\n bridgeTx.originToken = originToken(encodedTx);\n bridgeTx.destToken = destToken(encodedTx);\n bridgeTx.originAmount = originAmount(encodedTx);\n bridgeTx.destAmount = destAmount(encodedTx);\n bridgeTx.originFeeAmount = originFeeAmount(encodedTx);\n bridgeTx.deadline = deadline(encodedTx);\n bridgeTx.nonce = nonce(encodedTx);\n bridgeTx.exclusivityRelayer = exclusivityRelayer(encodedTx);\n bridgeTx.exclusivityEndTime = exclusivityEndTime(encodedTx);\n bridgeTx.zapNative = zapNative(encodedTx);\n bridgeTx.zapData = zapData(encodedTx);\n }\n\n /// @notice Extracts the version from the encoded transaction.\n function version(bytes calldata encodedTx) internal pure returns (uint16 version_) {\n // Load 32 bytes from the start and shift it 240 bits to the right to get the highest 16 bits.\n assembly {\n version_ := shr(240, calldataload(encodedTx.offset))\n }\n }\n\n /// @notice Extracts the origin chain ID from the encoded transaction.\n function originChainId(bytes calldata encodedTx) internal pure returns (uint32 originChainId_) {\n // Load 32 bytes from the offset and shift it 224 bits to the right to get the highest 32 bits.\n assembly {\n originChainId_ := shr(224, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_CHAIN_ID)))\n }\n }\n\n /// @notice Extracts the destination chain ID from the encoded transaction.\n function destChainId(bytes calldata encodedTx) internal pure returns (uint32 destChainId_) {\n // Load 32 bytes from the offset and shift it 224 bits to the right to get the highest 32 bits.\n assembly {\n destChainId_ := shr(224, calldataload(add(encodedTx.offset, OFFSET_DEST_CHAIN_ID)))\n }\n }\n\n /// @notice Extracts the origin sender from the encoded transaction.\n function originSender(bytes calldata encodedTx) internal pure returns (address originSender_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n originSender_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_SENDER)))\n }\n }\n\n /// @notice Extracts the destination recipient from the encoded transaction.\n function destRecipient(bytes calldata encodedTx) internal pure returns (address destRecipient_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n destRecipient_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_DEST_RECIPIENT)))\n }\n }\n\n /// @notice Extracts the origin token from the encoded transaction.\n function originToken(bytes calldata encodedTx) internal pure returns (address originToken_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n originToken_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_TOKEN)))\n }\n }\n\n /// @notice Extracts the destination token from the encoded transaction.\n function destToken(bytes calldata encodedTx) internal pure returns (address destToken_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n destToken_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_DEST_TOKEN)))\n }\n }\n\n /// @notice Extracts the origin amount from the encoded transaction.\n function originAmount(bytes calldata encodedTx) internal pure returns (uint256 originAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n originAmount_ := calldataload(add(encodedTx.offset, OFFSET_ORIGIN_AMOUNT))\n }\n }\n\n /// @notice Extracts the destination amount from the encoded transaction.\n function destAmount(bytes calldata encodedTx) internal pure returns (uint256 destAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n destAmount_ := calldataload(add(encodedTx.offset, OFFSET_DEST_AMOUNT))\n }\n }\n\n /// @notice Extracts the origin fee amount from the encoded transaction.\n function originFeeAmount(bytes calldata encodedTx) internal pure returns (uint256 originFeeAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n originFeeAmount_ := calldataload(add(encodedTx.offset, OFFSET_ORIGIN_FEE_AMOUNT))\n }\n }\n\n /// @notice Extracts the deadline from the encoded transaction.\n function deadline(bytes calldata encodedTx) internal pure returns (uint256 deadline_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n deadline_ := calldataload(add(encodedTx.offset, OFFSET_DEADLINE))\n }\n }\n\n /// @notice Extracts the nonce from the encoded transaction.\n function nonce(bytes calldata encodedTx) internal pure returns (uint256 nonce_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n nonce_ := calldataload(add(encodedTx.offset, OFFSET_NONCE))\n }\n }\n\n /// @notice Extracts the exclusivity relayer from the encoded transaction.\n function exclusivityRelayer(bytes calldata encodedTx) internal pure returns (address exclusivityRelayer_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n exclusivityRelayer_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_EXCLUSIVITY_RELAYER)))\n }\n }\n\n /// @notice Extracts the exclusivity end time from the encoded transaction.\n function exclusivityEndTime(bytes calldata encodedTx) internal pure returns (uint256 exclusivityEndTime_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n exclusivityEndTime_ := calldataload(add(encodedTx.offset, OFFSET_EXCLUSIVITY_END_TIME))\n }\n }\n\n /// @notice Extracts the Zap's native value from the encoded transaction.\n function zapNative(bytes calldata encodedTx) internal pure returns (uint256 zapNative_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n zapNative_ := calldataload(add(encodedTx.offset, OFFSET_ZAP_NATIVE))\n }\n }\n\n /// @notice Extracts the Zap's data from the encoded transaction.\n function zapData(bytes calldata encodedTx) internal pure returns (bytes calldata zapData_) {\n zapData_ = encodedTx[OFFSET_ZAP_DATA:];\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// contracts/libs/UniversalToken.sol\n\nlibrary UniversalTokenLib {\n using SafeERC20 for IERC20;\n\n address internal constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Transfers tokens to the given account. Reverts if transfer is not successful.\n /// @dev This might trigger fallback, if ETH is transferred to the contract.\n /// Make sure this can not lead to reentrancy attacks.\n function universalTransfer(address token, address to, uint256 value) internal {\n // Don't do anything, if need to send tokens to this address\n if (to == address(this)) return;\n // Don't do anything, if trying to send zero value\n if (value == 0) return;\n if (token == ETH_ADDRESS) {\n /// @dev Note: this can potentially lead to executing code in `to`.\n // solhint-disable-next-line avoid-low-level-calls\n (bool success,) = to.call{value: value}(\"\");\n require(success, \"ETH transfer failed\");\n } else {\n IERC20(token).safeTransfer(to, value);\n }\n }\n\n /// @notice Issues an infinite allowance to the spender, if the current allowance is insufficient\n /// to spend the given amount.\n function universalApproveInfinity(address token, address spender, uint256 amountToSpend) internal {\n // ETH Chad doesn't require your approval\n if (token == ETH_ADDRESS) return;\n // No-op if allowance is already sufficient\n uint256 allowance = IERC20(token).allowance(address(this), spender);\n if (allowance \u003e= amountToSpend) return;\n // Otherwise, reset approval to 0 and set to max allowance\n if (allowance \u003e 0) IERC20(token).safeDecreaseAllowance(spender, allowance);\n IERC20(token).safeIncreaseAllowance(spender, type(uint256).max);\n }\n\n /// @notice Returns the balance of the given token (or native ETH) for the given account.\n function universalBalanceOf(address token, address account) internal view returns (uint256) {\n if (token == ETH_ADDRESS) {\n return account.balance;\n } else {\n return IERC20(token).balanceOf(account);\n }\n }\n\n /// @dev Checks that token is a contract and not ETH_ADDRESS.\n function assertIsContract(address token) internal view {\n // Check that ETH_ADDRESS was not used (in case this is a predeploy on any of the chains)\n if (token == UniversalTokenLib.ETH_ADDRESS) revert TokenNotContract();\n // Check that token is not an EOA\n if (token.code.length == 0) revert TokenNotContract();\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/Admin.sol\n\ncontract Admin is IAdmin, AccessControlEnumerable {\n using UniversalTokenLib for address;\n\n bytes32 public constant RELAYER_ROLE = keccak256(\"RELAYER_ROLE\");\n bytes32 public constant REFUNDER_ROLE = keccak256(\"REFUNDER_ROLE\");\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n uint256 public constant FEE_BPS = 1e6;\n uint256 public constant FEE_RATE_MAX = 0.01e6; // max 1% on origin amount\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Chain gas amount to forward as rebate if requested\n uint256 public chainGasAmount;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n }\n\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n require(newFeeRate \u003c= FEE_RATE_MAX, \"newFeeRate \u003e max\");\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n token.universalTransfer(recipient, feeAmount);\n emit FeesSwept(token, recipient, feeAmount);\n }\n\n function setChainGasAmount(uint256 newChainGasAmount) external onlyRole(GOVERNOR_ROLE) {\n uint256 oldChainGasAmount = chainGasAmount;\n chainGasAmount = newChainGasAmount;\n emit ChainGasAmountUpdated(oldChainGasAmount, newChainGasAmount);\n }\n}\n\n// contracts/FastBridgeV2.sol\n\n/// @notice FastBridgeV2 is a contract for bridging tokens across chains.\ncontract FastBridgeV2 is Admin, MulticallTarget, IFastBridgeV2, IFastBridgeV2Errors {\n using BridgeTransactionV2Lib for bytes;\n using SafeERC20 for IERC20;\n\n /// @notice Address reserved for native gas token (ETH on Ethereum and most L2s, AVAX on Avalanche, etc)\n address public constant NATIVE_GAS_TOKEN = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Delay for a transaction after which it could be permisionlessly refunded\n uint256 public constant REFUND_DELAY = 7 days;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n /// @notice Maximum length of accepted zapData\n uint256 public constant MAX_ZAP_DATA_LENGTH = 2 ** 16 - 1;\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeTxDetails) public bridgeTxDetails;\n /// @notice Relay details on destination chain\n mapping(bytes32 =\u003e BridgeRelay) public bridgeRelayDetails;\n /// @notice Unique bridge nonces tracked per originSender\n mapping(address =\u003e uint256) public senderNonces;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Replaced by senderNonces\n uint256 public immutable nonce = 0;\n /// @notice the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n bridge({\n params: params,\n paramsV2: BridgeParamsV2({\n quoteRelayer: address(0),\n quoteExclusivitySeconds: 0,\n quoteId: bytes(\"\"),\n zapNative: 0,\n zapData: bytes(\"\")\n })\n });\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes calldata request) external payable {\n // relay override will validate the request\n relay({request: request, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes calldata request, bytes32 destTxHash) external {\n request.validateV2();\n prove({transactionId: keccak256(request), destTxHash: destTxHash, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridgeV2\n function claim(bytes calldata request) external {\n // claim override will validate the request\n claim({request: request, to: address(0)});\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Aggregate the read operations from the same storage slot\n address disputedRelayer = $.proofRelayer;\n BridgeStatus status = $.status;\n uint56 proofBlockTimestamp = $.proofBlockTimestamp;\n // Can only dispute a RELAYER_PROVED transaction within the dispute period\n if (status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(proofBlockTimestamp) \u003e DISPUTE_PERIOD) {\n revert DisputePeriodPassed();\n }\n // Update status to REQUESTED and delete the disputed proof details\n // Note: these are storage writes\n $.status = BridgeStatus.REQUESTED;\n $.proofRelayer = address(0);\n $.proofBlockTimestamp = 0;\n\n emit BridgeProofDisputed(transactionId, disputedRelayer);\n }\n\n /// @inheritdoc IFastBridge\n function refund(bytes calldata request) external {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Can only refund a REQUESTED transaction after its deadline expires\n if ($.status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n uint256 deadline = request.deadline();\n // Permissionless refund is only allowed after REFUND_DELAY on top of the deadline\n if (!hasRole(REFUNDER_ROLE, msg.sender)) deadline += REFUND_DELAY;\n if (block.timestamp \u003c= deadline) revert DeadlineNotExceeded();\n // Update status to REFUNDED and return the full amount (collateral + protocol fees) to the original sender.\n // The protocol fees are only updated when the transaction is claimed, so we don't need to update them here.\n // Note: this is a storage write\n $.status = BridgeStatus.REFUNDED;\n\n address to = request.originSender();\n address token = request.originToken();\n uint256 amount = request.originAmount() + request.originFeeAmount();\n // Emit the event before any external calls\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n // Complete the user refund as the last transaction action\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(to), amount);\n } else {\n IERC20(token).safeTransfer(to, amount);\n }\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // The correct relayer can only claim a RELAYER_PROVED transaction after the dispute period\n if ($.status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if ($.proofRelayer != relayer) revert SenderIncorrect();\n return _timeSince($.proofBlockTimestamp) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n /// @dev This method is added to achieve backwards compatibility with decoding requests into V1 structs:\n /// - `zapNative` is partially reported as a zero/non-zero flag\n /// - `zapData` is ignored\n /// In order to process all kinds of requests use getBridgeTransactionV2 instead.\n function getBridgeTransaction(bytes calldata request) external view returns (BridgeTransaction memory) {\n // Try decoding into V2 struct first. This will revert if V1 struct is passed\n try this.getBridgeTransactionV2(request) returns (BridgeTransactionV2 memory txV2) {\n // Note: we entirely ignore the zapData field, as it was not present in V1\n return BridgeTransaction({\n originChainId: txV2.originChainId,\n destChainId: txV2.destChainId,\n originSender: txV2.originSender,\n destRecipient: txV2.destRecipient,\n originToken: txV2.originToken,\n destToken: txV2.destToken,\n originAmount: txV2.originAmount,\n destAmount: txV2.destAmount,\n originFeeAmount: txV2.originFeeAmount,\n sendChainGas: txV2.zapNative != 0,\n deadline: txV2.deadline,\n nonce: txV2.nonce\n });\n } catch {\n // Fallback to V1 struct\n return abi.decode(request, (BridgeTransaction));\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function getBridgeTransactionV2(bytes calldata request) external pure returns (BridgeTransactionV2 memory) {\n request.validateV2();\n return BridgeTransactionV2Lib.decodeV2(request);\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) public payable {\n int256 exclusivityEndTime = 0;\n // if relayer exclusivity is not intended for this bridge, set exclusivityEndTime to static zero\n // otherwise, set exclusivity to expire at the current block ts offset by quoteExclusivitySeconds\n if (paramsV2.quoteRelayer != address(0)) {\n exclusivityEndTime = int256(block.timestamp) + paramsV2.quoteExclusivitySeconds;\n }\n _validateBridgeParams(params, paramsV2, exclusivityEndTime);\n\n // transfer tokens to bridge contract\n /// @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _takeBridgedUserAsset(params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) {\n originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n }\n\n // set status to requested\n bytes memory request = BridgeTransactionV2Lib.encodeV2(\n BridgeTransactionV2({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n deadline: params.deadline,\n nonce: senderNonces[params.sender]++, // increment nonce on every bridge\n exclusivityRelayer: paramsV2.quoteRelayer,\n // We checked exclusivityEndTime to be in range [0 .. params.deadline] above, so can safely cast\n exclusivityEndTime: uint256(exclusivityEndTime),\n zapNative: paramsV2.zapNative,\n zapData: paramsV2.zapData\n })\n );\n bytes32 transactionId = keccak256(request);\n // Note: the tx status will be updated throughout the tx lifecycle, while destChainId is set once here\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n bridgeTxDetails[transactionId].destChainId = params.dstChainId;\n\n emit BridgeRequested({\n transactionId: transactionId,\n sender: params.sender,\n request: request,\n destChainId: params.dstChainId,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n sendChainGas: paramsV2.zapNative != 0\n });\n emit BridgeQuoteDetails(transactionId, paramsV2.quoteId);\n }\n\n /// @inheritdoc IFastBridgeV2\n function relay(bytes calldata request, address relayer) public payable {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n _validateRelayParams(request, transactionId, relayer);\n // mark bridge transaction as relayed\n bridgeRelayDetails[transactionId] =\n BridgeRelay({blockNumber: uint48(block.number), blockTimestamp: uint48(block.timestamp), relayer: relayer});\n\n // transfer tokens to recipient on destination chain and trigger Zap if requested\n address to = request.destRecipient();\n address token = request.destToken();\n uint256 amount = request.destAmount();\n uint256 zapNative = request.zapNative();\n\n // Emit the event before any external calls\n emit BridgeRelayed({\n transactionId: transactionId,\n relayer: relayer,\n to: to,\n originChainId: request.originChainId(),\n originToken: request.originToken(),\n destToken: token,\n originAmount: request.originAmount(),\n destAmount: amount,\n chainGasAmount: zapNative\n });\n\n // All state changes have been done at this point, can proceed to the external calls.\n // This follows the checks-effects-interactions pattern to mitigate potential reentrancy attacks.\n if (token == NATIVE_GAS_TOKEN) {\n // For the native gas token, additional zapNative is not allowed\n if (zapNative != 0) revert ZapNativeNotSupported();\n // Check that the correct msg.value was sent\n if (msg.value != amount) revert MsgValueIncorrect();\n // Don't do a native transfer yet: we will handle it alongside the Zap below\n } else {\n // For ERC20s, we check that the correct msg.value was sent\n if (msg.value != zapNative) revert MsgValueIncorrect();\n // We need to transfer the tokens from the Relayer to the recipient first before performing an\n // optional post-transfer Zap.\n IERC20(token).safeTransferFrom(msg.sender, to, amount);\n }\n // At this point we have done:\n // - Transferred the requested amount of ERC20 tokens to the recipient.\n // At this point we have confirmed:\n // - For ERC20s: msg.value matches the requested zapNative amount.\n // - For the native gas token: msg.value matches the requested destAmount.\n // Remaining optional things to do:\n // - Forward the full msg.value to the recipient (if non-zero).\n // - Trigger a Zap (if zapData is present).\n bytes calldata zapData = request.zapData();\n if (zapData.length != 0) {\n // Zap Data is present: Zap has been requested by the recipient. Trigger it forwarding the full msg.value.\n\n // Note: if token has a fee on transfers, the recipient will have received less than `amount`.\n // This is a very niche edge case and should be handled by the recipient contract.\n _triggerZapWithChecks({recipient: to, token: token, amount: amount, zapData: zapData});\n } else if (msg.value != 0) {\n // Zap Data is missing, but msg.value was sent. This could happen in two different cases:\n // - Relay with the native gas token is happening.\n // - Relay with ERC20 is happening, with a `zapNative \u003e 0` request.\n // In both cases, we need to transfer the full msg.value to the recipient.\n Address.sendValue(payable(to), msg.value);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) public onlyRole(RELAYER_ROLE) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n\n // Can only prove a REQUESTED transaction\n if ($.status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n // Update status to RELAYER_PROVED and store the proof details\n // Note: these are storage writes\n $.status = BridgeStatus.RELAYER_PROVED;\n $.proofBlockTimestamp = uint56(block.timestamp);\n $.proofRelayer = relayer;\n\n emit BridgeProofProvided(transactionId, relayer, destTxHash);\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes calldata request, address to) public {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Aggregate the read operations from the same storage slot\n address proofRelayer = $.proofRelayer;\n BridgeStatus status = $.status;\n uint56 proofBlockTimestamp = $.proofBlockTimestamp;\n\n // Can only claim a RELAYER_PROVED transaction after the dispute period\n if (status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(proofBlockTimestamp) \u003c= DISPUTE_PERIOD) {\n revert DisputePeriodNotPassed();\n }\n\n if (to == address(0)) {\n // Anyone could claim the funds to the proven relayer on their behalf\n to = proofRelayer;\n } else if (proofRelayer != msg.sender) {\n // Only the proven relayer could specify an address to claim the funds to\n revert SenderIncorrect();\n }\n\n // Update status to RELAYER_CLAIMED and transfer the origin collateral to the specified claim address\n // Note: this is a storage write\n $.status = BridgeStatus.RELAYER_CLAIMED;\n\n address token = request.originToken();\n uint256 amount = request.originAmount();\n // Update protocol fees if origin fee amount exists\n uint256 originFeeAmount = request.originFeeAmount();\n if (originFeeAmount \u003e 0) protocolFees[token] += originFeeAmount;\n // Emit the event before any external calls\n emit BridgeDepositClaimed(transactionId, proofRelayer, to, token, amount);\n // Complete the relayer claim as the last transaction action\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(to), amount);\n } else {\n IERC20(token).safeTransfer(to, amount);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeStatuses(bytes32 transactionId) public view returns (BridgeStatus status) {\n return bridgeTxDetails[transactionId].status;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeProofs(bytes32 transactionId) public view returns (uint96 timestamp, address relayer) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n\n timestamp = $.proofBlockTimestamp;\n relayer = $.proofRelayer;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeRelays(bytes32 transactionId) public view returns (bool) {\n // has this transactionId been relayed?\n return bridgeRelayDetails[transactionId].relayer != address(0);\n }\n\n /// @notice Takes the bridged asset from the user into FastBridgeV2 custody. It will be later\n /// claimed by the relayer who completed the relay on destination chain, or refunded back to the user,\n /// should no one complete the relay.\n function _takeBridgedUserAsset(address token, uint256 amount) internal returns (uint256 amountTaken) {\n if (token == NATIVE_GAS_TOKEN) {\n // For the native gas token, we just need to check that the supplied msg.value is correct.\n // Supplied `msg.value` is already in FastBridgeV2 custody.\n if (amount != msg.value) revert MsgValueIncorrect();\n amountTaken = msg.value;\n } else {\n // For ERC20s, token is explicitly transferred from the user to FastBridgeV2.\n // We don't allow non-zero `msg.value` to avoid extra funds from being stuck in FastBridgeV2.\n if (msg.value != 0) revert MsgValueIncorrect();\n // Throw an explicit error if the provided token address is not a contract\n if (token.code.length == 0) revert TokenNotContract();\n amountTaken = IERC20(token).balanceOf(address(this));\n IERC20(token).safeTransferFrom(msg.sender, address(this), amount);\n // Use the balance difference as the amount taken in case of fee on transfer tokens.\n amountTaken = IERC20(token).balanceOf(address(this)) - amountTaken;\n }\n }\n\n /// @notice Calls the Recipient's hook function with the specified zapData and performs\n /// all the necessary checks for the returned value.\n function _triggerZapWithChecks(address recipient, address token, uint256 amount, bytes calldata zapData) internal {\n // This will bubble any revert messages from the hook function\n bytes memory returnData = Address.functionCallWithValue({\n target: recipient,\n data: abi.encodeCall(IZapRecipient.zap, (token, amount, zapData)),\n // Note: see `relay()` for reasoning behind passing msg.value\n value: msg.value\n });\n // Explicit revert if no return data at all\n if (returnData.length == 0) revert RecipientNoReturnValue();\n // Check that exactly a single return value was returned\n if (returnData.length != 32) revert RecipientIncorrectReturnValue();\n // Return value should be abi-encoded hook function selector\n if (bytes32(returnData) != bytes32(IZapRecipient.zap.selector)) {\n revert RecipientIncorrectReturnValue();\n }\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint56(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint56).max but\n /// proof.timestamp \u003c type(uint56).max via unchecked statement\n /// @param proofBlockTimestamp The bridge proof block timestamp\n /// @return delta Time delta since proof submitted\n function _timeSince(uint56 proofBlockTimestamp) internal view returns (uint256 delta) {\n unchecked {\n delta = uint56(block.timestamp) - proofBlockTimestamp;\n }\n }\n\n /// @notice Performs all the necessary checks for a bridge to happen.\n /// @dev There's no good way to refactor this function to reduce cyclomatic complexity due to\n /// the number of checks that need to be performed, so we skip the code-complexity rule here.\n // solhint-disable-next-line code-complexity\n function _validateBridgeParams(\n BridgeParams memory params,\n BridgeParamsV2 memory paramsV2,\n int256 exclusivityEndTime\n )\n internal\n view\n {\n // Check V1 (legacy) params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.sender == address(0) || params.to == address(0)) revert ZeroAddress();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n // Check V2 params\n if (paramsV2.zapData.length \u003e MAX_ZAP_DATA_LENGTH) revert ZapDataLengthAboveMax();\n if (paramsV2.zapNative != 0 \u0026\u0026 params.destToken == NATIVE_GAS_TOKEN) {\n revert ZapNativeNotSupported();\n }\n // exclusivityEndTime must be in range [0 .. params.deadline]\n if (exclusivityEndTime \u003c 0 || exclusivityEndTime \u003e int256(params.deadline)) {\n revert ExclusivityParamsIncorrect();\n }\n }\n\n /// @notice Performs all the necessary checks for a relay to happen.\n function _validateRelayParams(bytes calldata request, bytes32 transactionId, address relayer) internal view {\n if (relayer == address(0)) revert ZeroAddress();\n // Check if the transaction has already been relayed\n if (bridgeRelays(transactionId)) revert TransactionRelayed();\n if (request.destChainId() != block.chainid) revert ChainIncorrect();\n // Check the deadline for relay to happen\n if (block.timestamp \u003e request.deadline()) revert DeadlineExceeded();\n // Check the exclusivity period, if it is still ongoing\n address exclRelayer = request.exclusivityRelayer();\n if (exclRelayer != address(0) \u0026\u0026 exclRelayer != relayer \u0026\u0026 block.timestamp \u003c= request.exclusivityEndTime()) {\n revert ExclusivityPeriodNotPassed();\n }\n }\n}\n","language":"Solidity","languageVersion":"0.8.24","compilerVersion":"0.8.24","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"","srcMapRuntime":"","abiDefinition":[],"userDoc":{"kind":"user","methods":{},"version":1},"developerDoc":{"details":"Provides information about the current execution context, including the sender of the transaction and its data. While these are generally available via msg.sender and msg.data, they should not be accessed in such a direct manner, since when dealing with meta-transactions the account sending and paying for execution may not be the actual sender (as far as an application is concerned). This contract is only required for intermediate, library-like contracts.","kind":"dev","methods":{},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[],\"devdoc\":{\"details\":\"Provides information about the current execution context, including the sender of the transaction and its data. While these are generally available via msg.sender and msg.data, they should not be accessed in such a direct manner, since when dealing with meta-transactions the account sending and paying for execution may not be the actual sender (as far as an application is concerned). This contract is only required for intermediate, library-like contracts.\",\"kind\":\"dev\",\"methods\":{},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeV2.sol\":\"Context\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeV2.sol\":{\"keccak256\":\"0x5069b55ca07f21bfe30b2a43c18a18318c8af9c181b2dcb07c290825efd70f34\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://273dc020a49d08e50126bbea0d7f783f79d08c702f2fdbc560618d24af308acc\",\"dweb:/ipfs/QmXJ2UVzFc8EPB74RT4CXQPC4xw66jt4T13poyfyd3UERh\"]}},\"version\":1}"},"hashes":{}},"solidity/FastBridgeV2.sol:ERC165":{"code":"0x","runtime-code":"0x","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.24 ^0.8.20 ^0.8.4;\n\n// contracts/interfaces/IAdmin.sol\n\ninterface IAdmin {\n // ============ Events ============\n\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n event ChainGasAmountUpdated(uint256 oldChainGasAmount, uint256 newChainGasAmount);\n\n // ============ Methods ============\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n\n function setChainGasAmount(uint256 newChainGasAmount) external;\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IFastBridgeV2Errors.sol\n\ninterface IFastBridgeV2Errors {\n error AmountIncorrect();\n error ChainIncorrect();\n error ExclusivityParamsIncorrect();\n error MsgValueIncorrect();\n error SenderIncorrect();\n error StatusIncorrect();\n error TokenNotContract();\n error ZapDataLengthAboveMax();\n error ZapNativeNotSupported();\n error ZeroAddress();\n\n error RecipientIncorrectReturnValue();\n error RecipientNoReturnValue();\n\n error DeadlineExceeded();\n error DeadlineNotExceeded();\n error DeadlineTooShort();\n error DisputePeriodNotPassed();\n error DisputePeriodPassed();\n error ExclusivityPeriodNotPassed();\n\n error TransactionRelayed();\n}\n\n// contracts/interfaces/IMulticallTarget.sol\n\n/// @notice Interface for a contract that can be called multiple times by the same caller. Inspired by MulticallV3:\n/// https://github.com/mds1/multicall/blob/master/src/Multicall3.sol\ninterface IMulticallTarget {\n struct Result {\n bool success;\n bytes returnData;\n }\n\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external;\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results);\n}\n\n// contracts/interfaces/IZapRecipient.sol\n\ninterface IZapRecipient {\n function zap(address token, uint256 amount, bytes memory zapData) external payable returns (bytes4);\n}\n\n// contracts/libs/Errors.sol\n\nerror DeadlineExceeded();\nerror DeadlineNotExceeded();\nerror DeadlineTooShort();\nerror InsufficientOutputAmount();\n\nerror MsgValueIncorrect();\nerror PoolNotFound();\nerror TokenAddressMismatch();\nerror TokenNotContract();\nerror TokenNotETH();\nerror TokensIdentical();\n\nerror ChainIncorrect();\nerror AmountIncorrect();\nerror ZeroAddress();\n\nerror DisputePeriodNotPassed();\nerror DisputePeriodPassed();\nerror SenderIncorrect();\nerror StatusIncorrect();\nerror TransactionIdIncorrect();\nerror TransactionRelayed();\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// contracts/interfaces/IFastBridgeV2.sol\n\ninterface IFastBridgeV2 is IFastBridge {\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n struct BridgeTxDetails {\n BridgeStatus status;\n uint32 destChainId;\n uint56 proofBlockTimestamp;\n address proofRelayer;\n }\n\n struct BridgeRelay {\n uint48 blockNumber;\n uint48 blockTimestamp;\n address relayer;\n }\n\n /// @notice New params introduced in the FastBridgeV2.\n /// We are passing fields from the older BridgeParams struct outside of this struct\n /// for backwards compatibility.\n /// Note: quoteRelayer and quoteExclusivitySeconds are either both zero (indicating no exclusivity)\n /// or both non-zero (indicating exclusivity for the given period).\n /// Note: zapNative \u003e 0 can NOT be used with destToken = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE (native token)\n /// @param quoteRelayer Relayer that provided the quote for the transaction\n /// @param quoteExclusivitySeconds Period of time the quote relayer is guaranteed exclusivity after user's deposit\n /// @param quoteId Unique quote identifier used for tracking the quote\n /// @param zapNative ETH value to send to the recipient (if any)\n /// @param zapData Parameters for the Zap to the destination recipient (if any)\n struct BridgeParamsV2 {\n address quoteRelayer;\n int256 quoteExclusivitySeconds;\n bytes quoteId;\n uint256 zapNative;\n bytes zapData;\n }\n\n /// @notice Updated bridge transaction struct to include parameters introduced in FastBridgeV2.\n /// Note: only `exclusivityRelayer` can fill such a transaction until `exclusivityEndTime`.\n struct BridgeTransactionV2 {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n // Note: sendChainGas flag from V1 is deprecated\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n address exclusivityRelayer;\n uint256 exclusivityEndTime;\n uint256 zapNative; // ETH value to send to the recipient (if any)\n bytes zapData; // data to pass for the Zap action (if any)\n }\n\n event BridgeQuoteDetails(bytes32 indexed transactionId, bytes quoteId);\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability\n /// to provide temporary exclusivity fill rights for the quote relayer.\n /// @param params The parameters required to bridge\n /// @param paramsV2 The parameters for exclusivity fill rights (optional, can be left empty)\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function relay(bytes memory request, address relayer) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param transactionId The transaction id associated with the encoded bridge transaction to prove\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital.\n /// @notice Can only send funds to the relayer address on the proof.\n /// @param request The encoded bridge transaction to claim on origin chain\n function claim(bytes memory request) external;\n /// @notice Checks if a transaction has been relayed\n /// @param transactionId The ID of the transaction to check\n /// @return True if the transaction has been relayed, false otherwise\n function bridgeRelays(bytes32 transactionId) external view returns (bool);\n\n /// @notice Returns the status of a bridge transaction\n /// @param transactionId The ID of the bridge transaction\n /// @return BridgeStatus Status of the bridge transaction\n function bridgeStatuses(bytes32 transactionId) external view returns (BridgeStatus);\n\n /// @notice Returns the timestamp and relayer of a bridge proof\n /// @param transactionId The ID of the bridge transaction\n /// @return timestamp The timestamp of the bridge proof\n /// @return relayer The relayer address of the bridge proof\n function bridgeProofs(bytes32 transactionId) external view returns (uint96 timestamp, address relayer);\n\n /// @notice Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\n /// @param request The bridge request to decode\n function getBridgeTransactionV2(bytes memory request) external view returns (BridgeTransactionV2 memory);\n}\n\n// contracts/utils/MulticallTarget.sol\n\n// solhint-disable avoid-low-level-calls\n/// @notice Template for a contract that supports batched calls (preserving the msg.sender).\n/// Only calls with zero msg.value could be batched.\nabstract contract MulticallTarget is IMulticallTarget {\n error MulticallTarget__UndeterminedRevert();\n\n /// @notice Perform a batched call to this contract, preserving the msg.sender.\n /// The return data from each call is discarded.\n /// @dev The method is non-payable, so only calls with `msg.value == 0` could be batched.\n /// It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag.\n /// Otherwise, the whole batch call will be reverted with the original revert reason.\n /// @param data List of abi-encoded calldata for the calls to perform.\n /// @param ignoreReverts Whether to ignore the revert errors from the calls.\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external {\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\n if (!success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(result);\n }\n }\n }\n\n /// @notice Perform a batched call to this contract, preserving the msg.sender.\n /// The return data from each call is preserved.\n /// @dev The method is non-payable, so only calls with `msg.value == 0` could be batched.\n /// It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag.\n /// Otherwise, the whole batch call will be reverted with the original revert reason.\n /// @param data List of abi-encoded calldata for the calls to perform.\n /// @param ignoreReverts Whether to ignore the revert errors from the calls.\n /// @return results List of results from the calls: `(success, returnData)`.\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results)\n {\n results = new Result[](data.length);\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (results[i].success, results[i].returnData) = address(this).delegatecall(data[i]);\n if (!results[i].success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(results[i].returnData);\n }\n }\n }\n\n /// @dev Bubbles the revert message from the underlying call.\n /// Note: preserves the same custom error or revert string, if one was used.\n /// Source: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v5.0.2/contracts/utils/Address.sol#L143-L158\n function _bubbleRevert(bytes memory returnData) internal pure {\n // Look for revert reason and bubble it up if present\n if (returnData.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n // solhint-disable-next-line no-inline-assembly\n assembly {\n let returndata_size := mload(returnData)\n revert(add(32, returnData), returndata_size)\n }\n } else {\n revert MulticallTarget__UndeterminedRevert();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// contracts/libs/BridgeTransactionV2.sol\n\n// solhint-disable no-inline-assembly\nlibrary BridgeTransactionV2Lib {\n uint16 internal constant VERSION = 2;\n\n // Offsets of the fields in the packed BridgeTransactionV2 struct\n // uint16 version [000 .. 002)\n // uint32 originChainId [002 .. 006)\n // uint32 destChainId [006 .. 010)\n // address originSender [010 .. 030)\n // address destRecipient [030 .. 050)\n // address originToken [050 .. 070)\n // address destToken [070 .. 090)\n // uint256 originAmount [090 .. 122)\n // uint256 destAmount [122 .. 154)\n // uint256 originFeeAmount [154 .. 186)\n // uint256 deadline [186 .. 218)\n // uint256 nonce [218 .. 250)\n // address exclusivityRelayer [250 .. 270)\n // uint256 exclusivityEndTime [270 .. 302)\n // uint256 zapNative [302 .. 334)\n // bytes zapData [334 .. ***)\n\n // forgefmt: disable-start\n uint256 private constant OFFSET_ORIGIN_CHAIN_ID = 2;\n uint256 private constant OFFSET_DEST_CHAIN_ID = 6;\n uint256 private constant OFFSET_ORIGIN_SENDER = 10;\n uint256 private constant OFFSET_DEST_RECIPIENT = 30;\n uint256 private constant OFFSET_ORIGIN_TOKEN = 50;\n uint256 private constant OFFSET_DEST_TOKEN = 70;\n uint256 private constant OFFSET_ORIGIN_AMOUNT = 90;\n uint256 private constant OFFSET_DEST_AMOUNT = 122;\n uint256 private constant OFFSET_ORIGIN_FEE_AMOUNT = 154;\n uint256 private constant OFFSET_DEADLINE = 186;\n uint256 private constant OFFSET_NONCE = 218;\n uint256 private constant OFFSET_EXCLUSIVITY_RELAYER = 250;\n uint256 private constant OFFSET_EXCLUSIVITY_END_TIME = 270;\n uint256 private constant OFFSET_ZAP_NATIVE = 302;\n uint256 private constant OFFSET_ZAP_DATA = 334;\n // forgefmt: disable-end\n\n error BridgeTransactionV2__InvalidEncodedTx();\n error BridgeTransactionV2__UnsupportedVersion(uint16 version);\n\n /// @notice Validates the encoded transaction to be a tightly packed encoded payload for BridgeTransactionV2.\n /// @dev Checks the minimum length and the version, use this function before decoding any of the fields.\n function validateV2(bytes calldata encodedTx) internal pure {\n // Check the minimum length: must at least include all static fields.\n if (encodedTx.length \u003c OFFSET_ZAP_DATA) revert BridgeTransactionV2__InvalidEncodedTx();\n // Once we validated the length, we can be sure that the version field is present.\n uint16 version_ = version(encodedTx);\n if (version_ != VERSION) revert BridgeTransactionV2__UnsupportedVersion(version_);\n }\n\n /// @notice Encodes the BridgeTransactionV2 struct by tightly packing the fields.\n /// @dev `abi.decode` will not work as a result of the tightly packed fields. Use `decodeV2` to decode instead.\n function encodeV2(IFastBridgeV2.BridgeTransactionV2 memory bridgeTx) internal pure returns (bytes memory) {\n // We split the encoding into two parts to avoid stack-too-deep error\n bytes memory firstPart = abi.encodePacked(\n VERSION,\n bridgeTx.originChainId,\n bridgeTx.destChainId,\n bridgeTx.originSender,\n bridgeTx.destRecipient,\n bridgeTx.originToken,\n bridgeTx.destToken,\n bridgeTx.originAmount\n );\n return abi.encodePacked(\n firstPart,\n bridgeTx.destAmount,\n bridgeTx.originFeeAmount,\n // Note: we skip the deprecated `sendChainGas` flag, which was present in BridgeTransaction V1\n bridgeTx.deadline,\n bridgeTx.nonce,\n // New V2 fields: exclusivity\n bridgeTx.exclusivityRelayer,\n bridgeTx.exclusivityEndTime,\n // New V2 fields: Zap\n bridgeTx.zapNative,\n bridgeTx.zapData\n );\n }\n\n /// @notice Decodes the BridgeTransactionV2 struct from the encoded transaction.\n /// @dev Encoded BridgeTransactionV2 struct must be tightly packed.\n /// Use `validateV2` before decoding to ensure the encoded transaction is valid.\n function decodeV2(bytes calldata encodedTx)\n internal\n pure\n returns (IFastBridgeV2.BridgeTransactionV2 memory bridgeTx)\n {\n bridgeTx.originChainId = originChainId(encodedTx);\n bridgeTx.destChainId = destChainId(encodedTx);\n bridgeTx.originSender = originSender(encodedTx);\n bridgeTx.destRecipient = destRecipient(encodedTx);\n bridgeTx.originToken = originToken(encodedTx);\n bridgeTx.destToken = destToken(encodedTx);\n bridgeTx.originAmount = originAmount(encodedTx);\n bridgeTx.destAmount = destAmount(encodedTx);\n bridgeTx.originFeeAmount = originFeeAmount(encodedTx);\n bridgeTx.deadline = deadline(encodedTx);\n bridgeTx.nonce = nonce(encodedTx);\n bridgeTx.exclusivityRelayer = exclusivityRelayer(encodedTx);\n bridgeTx.exclusivityEndTime = exclusivityEndTime(encodedTx);\n bridgeTx.zapNative = zapNative(encodedTx);\n bridgeTx.zapData = zapData(encodedTx);\n }\n\n /// @notice Extracts the version from the encoded transaction.\n function version(bytes calldata encodedTx) internal pure returns (uint16 version_) {\n // Load 32 bytes from the start and shift it 240 bits to the right to get the highest 16 bits.\n assembly {\n version_ := shr(240, calldataload(encodedTx.offset))\n }\n }\n\n /// @notice Extracts the origin chain ID from the encoded transaction.\n function originChainId(bytes calldata encodedTx) internal pure returns (uint32 originChainId_) {\n // Load 32 bytes from the offset and shift it 224 bits to the right to get the highest 32 bits.\n assembly {\n originChainId_ := shr(224, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_CHAIN_ID)))\n }\n }\n\n /// @notice Extracts the destination chain ID from the encoded transaction.\n function destChainId(bytes calldata encodedTx) internal pure returns (uint32 destChainId_) {\n // Load 32 bytes from the offset and shift it 224 bits to the right to get the highest 32 bits.\n assembly {\n destChainId_ := shr(224, calldataload(add(encodedTx.offset, OFFSET_DEST_CHAIN_ID)))\n }\n }\n\n /// @notice Extracts the origin sender from the encoded transaction.\n function originSender(bytes calldata encodedTx) internal pure returns (address originSender_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n originSender_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_SENDER)))\n }\n }\n\n /// @notice Extracts the destination recipient from the encoded transaction.\n function destRecipient(bytes calldata encodedTx) internal pure returns (address destRecipient_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n destRecipient_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_DEST_RECIPIENT)))\n }\n }\n\n /// @notice Extracts the origin token from the encoded transaction.\n function originToken(bytes calldata encodedTx) internal pure returns (address originToken_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n originToken_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_TOKEN)))\n }\n }\n\n /// @notice Extracts the destination token from the encoded transaction.\n function destToken(bytes calldata encodedTx) internal pure returns (address destToken_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n destToken_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_DEST_TOKEN)))\n }\n }\n\n /// @notice Extracts the origin amount from the encoded transaction.\n function originAmount(bytes calldata encodedTx) internal pure returns (uint256 originAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n originAmount_ := calldataload(add(encodedTx.offset, OFFSET_ORIGIN_AMOUNT))\n }\n }\n\n /// @notice Extracts the destination amount from the encoded transaction.\n function destAmount(bytes calldata encodedTx) internal pure returns (uint256 destAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n destAmount_ := calldataload(add(encodedTx.offset, OFFSET_DEST_AMOUNT))\n }\n }\n\n /// @notice Extracts the origin fee amount from the encoded transaction.\n function originFeeAmount(bytes calldata encodedTx) internal pure returns (uint256 originFeeAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n originFeeAmount_ := calldataload(add(encodedTx.offset, OFFSET_ORIGIN_FEE_AMOUNT))\n }\n }\n\n /// @notice Extracts the deadline from the encoded transaction.\n function deadline(bytes calldata encodedTx) internal pure returns (uint256 deadline_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n deadline_ := calldataload(add(encodedTx.offset, OFFSET_DEADLINE))\n }\n }\n\n /// @notice Extracts the nonce from the encoded transaction.\n function nonce(bytes calldata encodedTx) internal pure returns (uint256 nonce_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n nonce_ := calldataload(add(encodedTx.offset, OFFSET_NONCE))\n }\n }\n\n /// @notice Extracts the exclusivity relayer from the encoded transaction.\n function exclusivityRelayer(bytes calldata encodedTx) internal pure returns (address exclusivityRelayer_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n exclusivityRelayer_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_EXCLUSIVITY_RELAYER)))\n }\n }\n\n /// @notice Extracts the exclusivity end time from the encoded transaction.\n function exclusivityEndTime(bytes calldata encodedTx) internal pure returns (uint256 exclusivityEndTime_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n exclusivityEndTime_ := calldataload(add(encodedTx.offset, OFFSET_EXCLUSIVITY_END_TIME))\n }\n }\n\n /// @notice Extracts the Zap's native value from the encoded transaction.\n function zapNative(bytes calldata encodedTx) internal pure returns (uint256 zapNative_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n zapNative_ := calldataload(add(encodedTx.offset, OFFSET_ZAP_NATIVE))\n }\n }\n\n /// @notice Extracts the Zap's data from the encoded transaction.\n function zapData(bytes calldata encodedTx) internal pure returns (bytes calldata zapData_) {\n zapData_ = encodedTx[OFFSET_ZAP_DATA:];\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// contracts/libs/UniversalToken.sol\n\nlibrary UniversalTokenLib {\n using SafeERC20 for IERC20;\n\n address internal constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Transfers tokens to the given account. Reverts if transfer is not successful.\n /// @dev This might trigger fallback, if ETH is transferred to the contract.\n /// Make sure this can not lead to reentrancy attacks.\n function universalTransfer(address token, address to, uint256 value) internal {\n // Don't do anything, if need to send tokens to this address\n if (to == address(this)) return;\n // Don't do anything, if trying to send zero value\n if (value == 0) return;\n if (token == ETH_ADDRESS) {\n /// @dev Note: this can potentially lead to executing code in `to`.\n // solhint-disable-next-line avoid-low-level-calls\n (bool success,) = to.call{value: value}(\"\");\n require(success, \"ETH transfer failed\");\n } else {\n IERC20(token).safeTransfer(to, value);\n }\n }\n\n /// @notice Issues an infinite allowance to the spender, if the current allowance is insufficient\n /// to spend the given amount.\n function universalApproveInfinity(address token, address spender, uint256 amountToSpend) internal {\n // ETH Chad doesn't require your approval\n if (token == ETH_ADDRESS) return;\n // No-op if allowance is already sufficient\n uint256 allowance = IERC20(token).allowance(address(this), spender);\n if (allowance \u003e= amountToSpend) return;\n // Otherwise, reset approval to 0 and set to max allowance\n if (allowance \u003e 0) IERC20(token).safeDecreaseAllowance(spender, allowance);\n IERC20(token).safeIncreaseAllowance(spender, type(uint256).max);\n }\n\n /// @notice Returns the balance of the given token (or native ETH) for the given account.\n function universalBalanceOf(address token, address account) internal view returns (uint256) {\n if (token == ETH_ADDRESS) {\n return account.balance;\n } else {\n return IERC20(token).balanceOf(account);\n }\n }\n\n /// @dev Checks that token is a contract and not ETH_ADDRESS.\n function assertIsContract(address token) internal view {\n // Check that ETH_ADDRESS was not used (in case this is a predeploy on any of the chains)\n if (token == UniversalTokenLib.ETH_ADDRESS) revert TokenNotContract();\n // Check that token is not an EOA\n if (token.code.length == 0) revert TokenNotContract();\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/Admin.sol\n\ncontract Admin is IAdmin, AccessControlEnumerable {\n using UniversalTokenLib for address;\n\n bytes32 public constant RELAYER_ROLE = keccak256(\"RELAYER_ROLE\");\n bytes32 public constant REFUNDER_ROLE = keccak256(\"REFUNDER_ROLE\");\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n uint256 public constant FEE_BPS = 1e6;\n uint256 public constant FEE_RATE_MAX = 0.01e6; // max 1% on origin amount\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Chain gas amount to forward as rebate if requested\n uint256 public chainGasAmount;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n }\n\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n require(newFeeRate \u003c= FEE_RATE_MAX, \"newFeeRate \u003e max\");\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n token.universalTransfer(recipient, feeAmount);\n emit FeesSwept(token, recipient, feeAmount);\n }\n\n function setChainGasAmount(uint256 newChainGasAmount) external onlyRole(GOVERNOR_ROLE) {\n uint256 oldChainGasAmount = chainGasAmount;\n chainGasAmount = newChainGasAmount;\n emit ChainGasAmountUpdated(oldChainGasAmount, newChainGasAmount);\n }\n}\n\n// contracts/FastBridgeV2.sol\n\n/// @notice FastBridgeV2 is a contract for bridging tokens across chains.\ncontract FastBridgeV2 is Admin, MulticallTarget, IFastBridgeV2, IFastBridgeV2Errors {\n using BridgeTransactionV2Lib for bytes;\n using SafeERC20 for IERC20;\n\n /// @notice Address reserved for native gas token (ETH on Ethereum and most L2s, AVAX on Avalanche, etc)\n address public constant NATIVE_GAS_TOKEN = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Delay for a transaction after which it could be permisionlessly refunded\n uint256 public constant REFUND_DELAY = 7 days;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n /// @notice Maximum length of accepted zapData\n uint256 public constant MAX_ZAP_DATA_LENGTH = 2 ** 16 - 1;\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeTxDetails) public bridgeTxDetails;\n /// @notice Relay details on destination chain\n mapping(bytes32 =\u003e BridgeRelay) public bridgeRelayDetails;\n /// @notice Unique bridge nonces tracked per originSender\n mapping(address =\u003e uint256) public senderNonces;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Replaced by senderNonces\n uint256 public immutable nonce = 0;\n /// @notice the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n bridge({\n params: params,\n paramsV2: BridgeParamsV2({\n quoteRelayer: address(0),\n quoteExclusivitySeconds: 0,\n quoteId: bytes(\"\"),\n zapNative: 0,\n zapData: bytes(\"\")\n })\n });\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes calldata request) external payable {\n // relay override will validate the request\n relay({request: request, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes calldata request, bytes32 destTxHash) external {\n request.validateV2();\n prove({transactionId: keccak256(request), destTxHash: destTxHash, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridgeV2\n function claim(bytes calldata request) external {\n // claim override will validate the request\n claim({request: request, to: address(0)});\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Aggregate the read operations from the same storage slot\n address disputedRelayer = $.proofRelayer;\n BridgeStatus status = $.status;\n uint56 proofBlockTimestamp = $.proofBlockTimestamp;\n // Can only dispute a RELAYER_PROVED transaction within the dispute period\n if (status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(proofBlockTimestamp) \u003e DISPUTE_PERIOD) {\n revert DisputePeriodPassed();\n }\n // Update status to REQUESTED and delete the disputed proof details\n // Note: these are storage writes\n $.status = BridgeStatus.REQUESTED;\n $.proofRelayer = address(0);\n $.proofBlockTimestamp = 0;\n\n emit BridgeProofDisputed(transactionId, disputedRelayer);\n }\n\n /// @inheritdoc IFastBridge\n function refund(bytes calldata request) external {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Can only refund a REQUESTED transaction after its deadline expires\n if ($.status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n uint256 deadline = request.deadline();\n // Permissionless refund is only allowed after REFUND_DELAY on top of the deadline\n if (!hasRole(REFUNDER_ROLE, msg.sender)) deadline += REFUND_DELAY;\n if (block.timestamp \u003c= deadline) revert DeadlineNotExceeded();\n // Update status to REFUNDED and return the full amount (collateral + protocol fees) to the original sender.\n // The protocol fees are only updated when the transaction is claimed, so we don't need to update them here.\n // Note: this is a storage write\n $.status = BridgeStatus.REFUNDED;\n\n address to = request.originSender();\n address token = request.originToken();\n uint256 amount = request.originAmount() + request.originFeeAmount();\n // Emit the event before any external calls\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n // Complete the user refund as the last transaction action\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(to), amount);\n } else {\n IERC20(token).safeTransfer(to, amount);\n }\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // The correct relayer can only claim a RELAYER_PROVED transaction after the dispute period\n if ($.status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if ($.proofRelayer != relayer) revert SenderIncorrect();\n return _timeSince($.proofBlockTimestamp) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n /// @dev This method is added to achieve backwards compatibility with decoding requests into V1 structs:\n /// - `zapNative` is partially reported as a zero/non-zero flag\n /// - `zapData` is ignored\n /// In order to process all kinds of requests use getBridgeTransactionV2 instead.\n function getBridgeTransaction(bytes calldata request) external view returns (BridgeTransaction memory) {\n // Try decoding into V2 struct first. This will revert if V1 struct is passed\n try this.getBridgeTransactionV2(request) returns (BridgeTransactionV2 memory txV2) {\n // Note: we entirely ignore the zapData field, as it was not present in V1\n return BridgeTransaction({\n originChainId: txV2.originChainId,\n destChainId: txV2.destChainId,\n originSender: txV2.originSender,\n destRecipient: txV2.destRecipient,\n originToken: txV2.originToken,\n destToken: txV2.destToken,\n originAmount: txV2.originAmount,\n destAmount: txV2.destAmount,\n originFeeAmount: txV2.originFeeAmount,\n sendChainGas: txV2.zapNative != 0,\n deadline: txV2.deadline,\n nonce: txV2.nonce\n });\n } catch {\n // Fallback to V1 struct\n return abi.decode(request, (BridgeTransaction));\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function getBridgeTransactionV2(bytes calldata request) external pure returns (BridgeTransactionV2 memory) {\n request.validateV2();\n return BridgeTransactionV2Lib.decodeV2(request);\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) public payable {\n int256 exclusivityEndTime = 0;\n // if relayer exclusivity is not intended for this bridge, set exclusivityEndTime to static zero\n // otherwise, set exclusivity to expire at the current block ts offset by quoteExclusivitySeconds\n if (paramsV2.quoteRelayer != address(0)) {\n exclusivityEndTime = int256(block.timestamp) + paramsV2.quoteExclusivitySeconds;\n }\n _validateBridgeParams(params, paramsV2, exclusivityEndTime);\n\n // transfer tokens to bridge contract\n /// @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _takeBridgedUserAsset(params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) {\n originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n }\n\n // set status to requested\n bytes memory request = BridgeTransactionV2Lib.encodeV2(\n BridgeTransactionV2({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n deadline: params.deadline,\n nonce: senderNonces[params.sender]++, // increment nonce on every bridge\n exclusivityRelayer: paramsV2.quoteRelayer,\n // We checked exclusivityEndTime to be in range [0 .. params.deadline] above, so can safely cast\n exclusivityEndTime: uint256(exclusivityEndTime),\n zapNative: paramsV2.zapNative,\n zapData: paramsV2.zapData\n })\n );\n bytes32 transactionId = keccak256(request);\n // Note: the tx status will be updated throughout the tx lifecycle, while destChainId is set once here\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n bridgeTxDetails[transactionId].destChainId = params.dstChainId;\n\n emit BridgeRequested({\n transactionId: transactionId,\n sender: params.sender,\n request: request,\n destChainId: params.dstChainId,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n sendChainGas: paramsV2.zapNative != 0\n });\n emit BridgeQuoteDetails(transactionId, paramsV2.quoteId);\n }\n\n /// @inheritdoc IFastBridgeV2\n function relay(bytes calldata request, address relayer) public payable {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n _validateRelayParams(request, transactionId, relayer);\n // mark bridge transaction as relayed\n bridgeRelayDetails[transactionId] =\n BridgeRelay({blockNumber: uint48(block.number), blockTimestamp: uint48(block.timestamp), relayer: relayer});\n\n // transfer tokens to recipient on destination chain and trigger Zap if requested\n address to = request.destRecipient();\n address token = request.destToken();\n uint256 amount = request.destAmount();\n uint256 zapNative = request.zapNative();\n\n // Emit the event before any external calls\n emit BridgeRelayed({\n transactionId: transactionId,\n relayer: relayer,\n to: to,\n originChainId: request.originChainId(),\n originToken: request.originToken(),\n destToken: token,\n originAmount: request.originAmount(),\n destAmount: amount,\n chainGasAmount: zapNative\n });\n\n // All state changes have been done at this point, can proceed to the external calls.\n // This follows the checks-effects-interactions pattern to mitigate potential reentrancy attacks.\n if (token == NATIVE_GAS_TOKEN) {\n // For the native gas token, additional zapNative is not allowed\n if (zapNative != 0) revert ZapNativeNotSupported();\n // Check that the correct msg.value was sent\n if (msg.value != amount) revert MsgValueIncorrect();\n // Don't do a native transfer yet: we will handle it alongside the Zap below\n } else {\n // For ERC20s, we check that the correct msg.value was sent\n if (msg.value != zapNative) revert MsgValueIncorrect();\n // We need to transfer the tokens from the Relayer to the recipient first before performing an\n // optional post-transfer Zap.\n IERC20(token).safeTransferFrom(msg.sender, to, amount);\n }\n // At this point we have done:\n // - Transferred the requested amount of ERC20 tokens to the recipient.\n // At this point we have confirmed:\n // - For ERC20s: msg.value matches the requested zapNative amount.\n // - For the native gas token: msg.value matches the requested destAmount.\n // Remaining optional things to do:\n // - Forward the full msg.value to the recipient (if non-zero).\n // - Trigger a Zap (if zapData is present).\n bytes calldata zapData = request.zapData();\n if (zapData.length != 0) {\n // Zap Data is present: Zap has been requested by the recipient. Trigger it forwarding the full msg.value.\n\n // Note: if token has a fee on transfers, the recipient will have received less than `amount`.\n // This is a very niche edge case and should be handled by the recipient contract.\n _triggerZapWithChecks({recipient: to, token: token, amount: amount, zapData: zapData});\n } else if (msg.value != 0) {\n // Zap Data is missing, but msg.value was sent. This could happen in two different cases:\n // - Relay with the native gas token is happening.\n // - Relay with ERC20 is happening, with a `zapNative \u003e 0` request.\n // In both cases, we need to transfer the full msg.value to the recipient.\n Address.sendValue(payable(to), msg.value);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) public onlyRole(RELAYER_ROLE) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n\n // Can only prove a REQUESTED transaction\n if ($.status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n // Update status to RELAYER_PROVED and store the proof details\n // Note: these are storage writes\n $.status = BridgeStatus.RELAYER_PROVED;\n $.proofBlockTimestamp = uint56(block.timestamp);\n $.proofRelayer = relayer;\n\n emit BridgeProofProvided(transactionId, relayer, destTxHash);\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes calldata request, address to) public {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Aggregate the read operations from the same storage slot\n address proofRelayer = $.proofRelayer;\n BridgeStatus status = $.status;\n uint56 proofBlockTimestamp = $.proofBlockTimestamp;\n\n // Can only claim a RELAYER_PROVED transaction after the dispute period\n if (status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(proofBlockTimestamp) \u003c= DISPUTE_PERIOD) {\n revert DisputePeriodNotPassed();\n }\n\n if (to == address(0)) {\n // Anyone could claim the funds to the proven relayer on their behalf\n to = proofRelayer;\n } else if (proofRelayer != msg.sender) {\n // Only the proven relayer could specify an address to claim the funds to\n revert SenderIncorrect();\n }\n\n // Update status to RELAYER_CLAIMED and transfer the origin collateral to the specified claim address\n // Note: this is a storage write\n $.status = BridgeStatus.RELAYER_CLAIMED;\n\n address token = request.originToken();\n uint256 amount = request.originAmount();\n // Update protocol fees if origin fee amount exists\n uint256 originFeeAmount = request.originFeeAmount();\n if (originFeeAmount \u003e 0) protocolFees[token] += originFeeAmount;\n // Emit the event before any external calls\n emit BridgeDepositClaimed(transactionId, proofRelayer, to, token, amount);\n // Complete the relayer claim as the last transaction action\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(to), amount);\n } else {\n IERC20(token).safeTransfer(to, amount);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeStatuses(bytes32 transactionId) public view returns (BridgeStatus status) {\n return bridgeTxDetails[transactionId].status;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeProofs(bytes32 transactionId) public view returns (uint96 timestamp, address relayer) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n\n timestamp = $.proofBlockTimestamp;\n relayer = $.proofRelayer;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeRelays(bytes32 transactionId) public view returns (bool) {\n // has this transactionId been relayed?\n return bridgeRelayDetails[transactionId].relayer != address(0);\n }\n\n /// @notice Takes the bridged asset from the user into FastBridgeV2 custody. It will be later\n /// claimed by the relayer who completed the relay on destination chain, or refunded back to the user,\n /// should no one complete the relay.\n function _takeBridgedUserAsset(address token, uint256 amount) internal returns (uint256 amountTaken) {\n if (token == NATIVE_GAS_TOKEN) {\n // For the native gas token, we just need to check that the supplied msg.value is correct.\n // Supplied `msg.value` is already in FastBridgeV2 custody.\n if (amount != msg.value) revert MsgValueIncorrect();\n amountTaken = msg.value;\n } else {\n // For ERC20s, token is explicitly transferred from the user to FastBridgeV2.\n // We don't allow non-zero `msg.value` to avoid extra funds from being stuck in FastBridgeV2.\n if (msg.value != 0) revert MsgValueIncorrect();\n // Throw an explicit error if the provided token address is not a contract\n if (token.code.length == 0) revert TokenNotContract();\n amountTaken = IERC20(token).balanceOf(address(this));\n IERC20(token).safeTransferFrom(msg.sender, address(this), amount);\n // Use the balance difference as the amount taken in case of fee on transfer tokens.\n amountTaken = IERC20(token).balanceOf(address(this)) - amountTaken;\n }\n }\n\n /// @notice Calls the Recipient's hook function with the specified zapData and performs\n /// all the necessary checks for the returned value.\n function _triggerZapWithChecks(address recipient, address token, uint256 amount, bytes calldata zapData) internal {\n // This will bubble any revert messages from the hook function\n bytes memory returnData = Address.functionCallWithValue({\n target: recipient,\n data: abi.encodeCall(IZapRecipient.zap, (token, amount, zapData)),\n // Note: see `relay()` for reasoning behind passing msg.value\n value: msg.value\n });\n // Explicit revert if no return data at all\n if (returnData.length == 0) revert RecipientNoReturnValue();\n // Check that exactly a single return value was returned\n if (returnData.length != 32) revert RecipientIncorrectReturnValue();\n // Return value should be abi-encoded hook function selector\n if (bytes32(returnData) != bytes32(IZapRecipient.zap.selector)) {\n revert RecipientIncorrectReturnValue();\n }\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint56(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint56).max but\n /// proof.timestamp \u003c type(uint56).max via unchecked statement\n /// @param proofBlockTimestamp The bridge proof block timestamp\n /// @return delta Time delta since proof submitted\n function _timeSince(uint56 proofBlockTimestamp) internal view returns (uint256 delta) {\n unchecked {\n delta = uint56(block.timestamp) - proofBlockTimestamp;\n }\n }\n\n /// @notice Performs all the necessary checks for a bridge to happen.\n /// @dev There's no good way to refactor this function to reduce cyclomatic complexity due to\n /// the number of checks that need to be performed, so we skip the code-complexity rule here.\n // solhint-disable-next-line code-complexity\n function _validateBridgeParams(\n BridgeParams memory params,\n BridgeParamsV2 memory paramsV2,\n int256 exclusivityEndTime\n )\n internal\n view\n {\n // Check V1 (legacy) params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.sender == address(0) || params.to == address(0)) revert ZeroAddress();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n // Check V2 params\n if (paramsV2.zapData.length \u003e MAX_ZAP_DATA_LENGTH) revert ZapDataLengthAboveMax();\n if (paramsV2.zapNative != 0 \u0026\u0026 params.destToken == NATIVE_GAS_TOKEN) {\n revert ZapNativeNotSupported();\n }\n // exclusivityEndTime must be in range [0 .. params.deadline]\n if (exclusivityEndTime \u003c 0 || exclusivityEndTime \u003e int256(params.deadline)) {\n revert ExclusivityParamsIncorrect();\n }\n }\n\n /// @notice Performs all the necessary checks for a relay to happen.\n function _validateRelayParams(bytes calldata request, bytes32 transactionId, address relayer) internal view {\n if (relayer == address(0)) revert ZeroAddress();\n // Check if the transaction has already been relayed\n if (bridgeRelays(transactionId)) revert TransactionRelayed();\n if (request.destChainId() != block.chainid) revert ChainIncorrect();\n // Check the deadline for relay to happen\n if (block.timestamp \u003e request.deadline()) revert DeadlineExceeded();\n // Check the exclusivity period, if it is still ongoing\n address exclRelayer = request.exclusivityRelayer();\n if (exclRelayer != address(0) \u0026\u0026 exclRelayer != relayer \u0026\u0026 block.timestamp \u003c= request.exclusivityEndTime()) {\n revert ExclusivityPeriodNotPassed();\n }\n }\n}\n","language":"Solidity","languageVersion":"0.8.24","compilerVersion":"0.8.24","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"","srcMapRuntime":"","abiDefinition":[{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"}],"userDoc":{"kind":"user","methods":{},"version":1},"developerDoc":{"details":"Implementation of the {IERC165} interface. Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check for the additional interface id that will be supported. For example: ```solidity function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId); } ```","kind":"dev","methods":{"supportsInterface(bytes4)":{"details":"See {IERC165-supportsInterface}."}},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"bytes4\",\"name\":\"interfaceId\",\"type\":\"bytes4\"}],\"name\":\"supportsInterface\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"}],\"devdoc\":{\"details\":\"Implementation of the {IERC165} interface. Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check for the additional interface id that will be supported. For example: ```solidity function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId); } ```\",\"kind\":\"dev\",\"methods\":{\"supportsInterface(bytes4)\":{\"details\":\"See {IERC165-supportsInterface}.\"}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeV2.sol\":\"ERC165\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeV2.sol\":{\"keccak256\":\"0x5069b55ca07f21bfe30b2a43c18a18318c8af9c181b2dcb07c290825efd70f34\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://273dc020a49d08e50126bbea0d7f783f79d08c702f2fdbc560618d24af308acc\",\"dweb:/ipfs/QmXJ2UVzFc8EPB74RT4CXQPC4xw66jt4T13poyfyd3UERh\"]}},\"version\":1}"},"hashes":{"supportsInterface(bytes4)":"01ffc9a7"}},"solidity/FastBridgeV2.sol:EnumerableSet":{"code":"0x60566037600b82828239805160001a607314602a57634e487b7160e01b600052600060045260246000fd5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600080fdfea26469706673582212202a0689afaebf6ffa0f4d0a6fe04b9b6e642f8ef83c8db74e665e9fc77d71999964736f6c63430008180033","runtime-code":"0x73000000000000000000000000000000000000000030146080604052600080fdfea26469706673582212202a0689afaebf6ffa0f4d0a6fe04b9b6e642f8ef83c8db74e665e9fc77d71999964736f6c63430008180033","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.24 ^0.8.20 ^0.8.4;\n\n// contracts/interfaces/IAdmin.sol\n\ninterface IAdmin {\n // ============ Events ============\n\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n event ChainGasAmountUpdated(uint256 oldChainGasAmount, uint256 newChainGasAmount);\n\n // ============ Methods ============\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n\n function setChainGasAmount(uint256 newChainGasAmount) external;\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IFastBridgeV2Errors.sol\n\ninterface IFastBridgeV2Errors {\n error AmountIncorrect();\n error ChainIncorrect();\n error ExclusivityParamsIncorrect();\n error MsgValueIncorrect();\n error SenderIncorrect();\n error StatusIncorrect();\n error TokenNotContract();\n error ZapDataLengthAboveMax();\n error ZapNativeNotSupported();\n error ZeroAddress();\n\n error RecipientIncorrectReturnValue();\n error RecipientNoReturnValue();\n\n error DeadlineExceeded();\n error DeadlineNotExceeded();\n error DeadlineTooShort();\n error DisputePeriodNotPassed();\n error DisputePeriodPassed();\n error ExclusivityPeriodNotPassed();\n\n error TransactionRelayed();\n}\n\n// contracts/interfaces/IMulticallTarget.sol\n\n/// @notice Interface for a contract that can be called multiple times by the same caller. Inspired by MulticallV3:\n/// https://github.com/mds1/multicall/blob/master/src/Multicall3.sol\ninterface IMulticallTarget {\n struct Result {\n bool success;\n bytes returnData;\n }\n\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external;\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results);\n}\n\n// contracts/interfaces/IZapRecipient.sol\n\ninterface IZapRecipient {\n function zap(address token, uint256 amount, bytes memory zapData) external payable returns (bytes4);\n}\n\n// contracts/libs/Errors.sol\n\nerror DeadlineExceeded();\nerror DeadlineNotExceeded();\nerror DeadlineTooShort();\nerror InsufficientOutputAmount();\n\nerror MsgValueIncorrect();\nerror PoolNotFound();\nerror TokenAddressMismatch();\nerror TokenNotContract();\nerror TokenNotETH();\nerror TokensIdentical();\n\nerror ChainIncorrect();\nerror AmountIncorrect();\nerror ZeroAddress();\n\nerror DisputePeriodNotPassed();\nerror DisputePeriodPassed();\nerror SenderIncorrect();\nerror StatusIncorrect();\nerror TransactionIdIncorrect();\nerror TransactionRelayed();\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// contracts/interfaces/IFastBridgeV2.sol\n\ninterface IFastBridgeV2 is IFastBridge {\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n struct BridgeTxDetails {\n BridgeStatus status;\n uint32 destChainId;\n uint56 proofBlockTimestamp;\n address proofRelayer;\n }\n\n struct BridgeRelay {\n uint48 blockNumber;\n uint48 blockTimestamp;\n address relayer;\n }\n\n /// @notice New params introduced in the FastBridgeV2.\n /// We are passing fields from the older BridgeParams struct outside of this struct\n /// for backwards compatibility.\n /// Note: quoteRelayer and quoteExclusivitySeconds are either both zero (indicating no exclusivity)\n /// or both non-zero (indicating exclusivity for the given period).\n /// Note: zapNative \u003e 0 can NOT be used with destToken = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE (native token)\n /// @param quoteRelayer Relayer that provided the quote for the transaction\n /// @param quoteExclusivitySeconds Period of time the quote relayer is guaranteed exclusivity after user's deposit\n /// @param quoteId Unique quote identifier used for tracking the quote\n /// @param zapNative ETH value to send to the recipient (if any)\n /// @param zapData Parameters for the Zap to the destination recipient (if any)\n struct BridgeParamsV2 {\n address quoteRelayer;\n int256 quoteExclusivitySeconds;\n bytes quoteId;\n uint256 zapNative;\n bytes zapData;\n }\n\n /// @notice Updated bridge transaction struct to include parameters introduced in FastBridgeV2.\n /// Note: only `exclusivityRelayer` can fill such a transaction until `exclusivityEndTime`.\n struct BridgeTransactionV2 {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n // Note: sendChainGas flag from V1 is deprecated\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n address exclusivityRelayer;\n uint256 exclusivityEndTime;\n uint256 zapNative; // ETH value to send to the recipient (if any)\n bytes zapData; // data to pass for the Zap action (if any)\n }\n\n event BridgeQuoteDetails(bytes32 indexed transactionId, bytes quoteId);\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability\n /// to provide temporary exclusivity fill rights for the quote relayer.\n /// @param params The parameters required to bridge\n /// @param paramsV2 The parameters for exclusivity fill rights (optional, can be left empty)\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function relay(bytes memory request, address relayer) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param transactionId The transaction id associated with the encoded bridge transaction to prove\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital.\n /// @notice Can only send funds to the relayer address on the proof.\n /// @param request The encoded bridge transaction to claim on origin chain\n function claim(bytes memory request) external;\n /// @notice Checks if a transaction has been relayed\n /// @param transactionId The ID of the transaction to check\n /// @return True if the transaction has been relayed, false otherwise\n function bridgeRelays(bytes32 transactionId) external view returns (bool);\n\n /// @notice Returns the status of a bridge transaction\n /// @param transactionId The ID of the bridge transaction\n /// @return BridgeStatus Status of the bridge transaction\n function bridgeStatuses(bytes32 transactionId) external view returns (BridgeStatus);\n\n /// @notice Returns the timestamp and relayer of a bridge proof\n /// @param transactionId The ID of the bridge transaction\n /// @return timestamp The timestamp of the bridge proof\n /// @return relayer The relayer address of the bridge proof\n function bridgeProofs(bytes32 transactionId) external view returns (uint96 timestamp, address relayer);\n\n /// @notice Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\n /// @param request The bridge request to decode\n function getBridgeTransactionV2(bytes memory request) external view returns (BridgeTransactionV2 memory);\n}\n\n// contracts/utils/MulticallTarget.sol\n\n// solhint-disable avoid-low-level-calls\n/// @notice Template for a contract that supports batched calls (preserving the msg.sender).\n/// Only calls with zero msg.value could be batched.\nabstract contract MulticallTarget is IMulticallTarget {\n error MulticallTarget__UndeterminedRevert();\n\n /// @notice Perform a batched call to this contract, preserving the msg.sender.\n /// The return data from each call is discarded.\n /// @dev The method is non-payable, so only calls with `msg.value == 0` could be batched.\n /// It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag.\n /// Otherwise, the whole batch call will be reverted with the original revert reason.\n /// @param data List of abi-encoded calldata for the calls to perform.\n /// @param ignoreReverts Whether to ignore the revert errors from the calls.\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external {\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\n if (!success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(result);\n }\n }\n }\n\n /// @notice Perform a batched call to this contract, preserving the msg.sender.\n /// The return data from each call is preserved.\n /// @dev The method is non-payable, so only calls with `msg.value == 0` could be batched.\n /// It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag.\n /// Otherwise, the whole batch call will be reverted with the original revert reason.\n /// @param data List of abi-encoded calldata for the calls to perform.\n /// @param ignoreReverts Whether to ignore the revert errors from the calls.\n /// @return results List of results from the calls: `(success, returnData)`.\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results)\n {\n results = new Result[](data.length);\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (results[i].success, results[i].returnData) = address(this).delegatecall(data[i]);\n if (!results[i].success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(results[i].returnData);\n }\n }\n }\n\n /// @dev Bubbles the revert message from the underlying call.\n /// Note: preserves the same custom error or revert string, if one was used.\n /// Source: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v5.0.2/contracts/utils/Address.sol#L143-L158\n function _bubbleRevert(bytes memory returnData) internal pure {\n // Look for revert reason and bubble it up if present\n if (returnData.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n // solhint-disable-next-line no-inline-assembly\n assembly {\n let returndata_size := mload(returnData)\n revert(add(32, returnData), returndata_size)\n }\n } else {\n revert MulticallTarget__UndeterminedRevert();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// contracts/libs/BridgeTransactionV2.sol\n\n// solhint-disable no-inline-assembly\nlibrary BridgeTransactionV2Lib {\n uint16 internal constant VERSION = 2;\n\n // Offsets of the fields in the packed BridgeTransactionV2 struct\n // uint16 version [000 .. 002)\n // uint32 originChainId [002 .. 006)\n // uint32 destChainId [006 .. 010)\n // address originSender [010 .. 030)\n // address destRecipient [030 .. 050)\n // address originToken [050 .. 070)\n // address destToken [070 .. 090)\n // uint256 originAmount [090 .. 122)\n // uint256 destAmount [122 .. 154)\n // uint256 originFeeAmount [154 .. 186)\n // uint256 deadline [186 .. 218)\n // uint256 nonce [218 .. 250)\n // address exclusivityRelayer [250 .. 270)\n // uint256 exclusivityEndTime [270 .. 302)\n // uint256 zapNative [302 .. 334)\n // bytes zapData [334 .. ***)\n\n // forgefmt: disable-start\n uint256 private constant OFFSET_ORIGIN_CHAIN_ID = 2;\n uint256 private constant OFFSET_DEST_CHAIN_ID = 6;\n uint256 private constant OFFSET_ORIGIN_SENDER = 10;\n uint256 private constant OFFSET_DEST_RECIPIENT = 30;\n uint256 private constant OFFSET_ORIGIN_TOKEN = 50;\n uint256 private constant OFFSET_DEST_TOKEN = 70;\n uint256 private constant OFFSET_ORIGIN_AMOUNT = 90;\n uint256 private constant OFFSET_DEST_AMOUNT = 122;\n uint256 private constant OFFSET_ORIGIN_FEE_AMOUNT = 154;\n uint256 private constant OFFSET_DEADLINE = 186;\n uint256 private constant OFFSET_NONCE = 218;\n uint256 private constant OFFSET_EXCLUSIVITY_RELAYER = 250;\n uint256 private constant OFFSET_EXCLUSIVITY_END_TIME = 270;\n uint256 private constant OFFSET_ZAP_NATIVE = 302;\n uint256 private constant OFFSET_ZAP_DATA = 334;\n // forgefmt: disable-end\n\n error BridgeTransactionV2__InvalidEncodedTx();\n error BridgeTransactionV2__UnsupportedVersion(uint16 version);\n\n /// @notice Validates the encoded transaction to be a tightly packed encoded payload for BridgeTransactionV2.\n /// @dev Checks the minimum length and the version, use this function before decoding any of the fields.\n function validateV2(bytes calldata encodedTx) internal pure {\n // Check the minimum length: must at least include all static fields.\n if (encodedTx.length \u003c OFFSET_ZAP_DATA) revert BridgeTransactionV2__InvalidEncodedTx();\n // Once we validated the length, we can be sure that the version field is present.\n uint16 version_ = version(encodedTx);\n if (version_ != VERSION) revert BridgeTransactionV2__UnsupportedVersion(version_);\n }\n\n /// @notice Encodes the BridgeTransactionV2 struct by tightly packing the fields.\n /// @dev `abi.decode` will not work as a result of the tightly packed fields. Use `decodeV2` to decode instead.\n function encodeV2(IFastBridgeV2.BridgeTransactionV2 memory bridgeTx) internal pure returns (bytes memory) {\n // We split the encoding into two parts to avoid stack-too-deep error\n bytes memory firstPart = abi.encodePacked(\n VERSION,\n bridgeTx.originChainId,\n bridgeTx.destChainId,\n bridgeTx.originSender,\n bridgeTx.destRecipient,\n bridgeTx.originToken,\n bridgeTx.destToken,\n bridgeTx.originAmount\n );\n return abi.encodePacked(\n firstPart,\n bridgeTx.destAmount,\n bridgeTx.originFeeAmount,\n // Note: we skip the deprecated `sendChainGas` flag, which was present in BridgeTransaction V1\n bridgeTx.deadline,\n bridgeTx.nonce,\n // New V2 fields: exclusivity\n bridgeTx.exclusivityRelayer,\n bridgeTx.exclusivityEndTime,\n // New V2 fields: Zap\n bridgeTx.zapNative,\n bridgeTx.zapData\n );\n }\n\n /// @notice Decodes the BridgeTransactionV2 struct from the encoded transaction.\n /// @dev Encoded BridgeTransactionV2 struct must be tightly packed.\n /// Use `validateV2` before decoding to ensure the encoded transaction is valid.\n function decodeV2(bytes calldata encodedTx)\n internal\n pure\n returns (IFastBridgeV2.BridgeTransactionV2 memory bridgeTx)\n {\n bridgeTx.originChainId = originChainId(encodedTx);\n bridgeTx.destChainId = destChainId(encodedTx);\n bridgeTx.originSender = originSender(encodedTx);\n bridgeTx.destRecipient = destRecipient(encodedTx);\n bridgeTx.originToken = originToken(encodedTx);\n bridgeTx.destToken = destToken(encodedTx);\n bridgeTx.originAmount = originAmount(encodedTx);\n bridgeTx.destAmount = destAmount(encodedTx);\n bridgeTx.originFeeAmount = originFeeAmount(encodedTx);\n bridgeTx.deadline = deadline(encodedTx);\n bridgeTx.nonce = nonce(encodedTx);\n bridgeTx.exclusivityRelayer = exclusivityRelayer(encodedTx);\n bridgeTx.exclusivityEndTime = exclusivityEndTime(encodedTx);\n bridgeTx.zapNative = zapNative(encodedTx);\n bridgeTx.zapData = zapData(encodedTx);\n }\n\n /// @notice Extracts the version from the encoded transaction.\n function version(bytes calldata encodedTx) internal pure returns (uint16 version_) {\n // Load 32 bytes from the start and shift it 240 bits to the right to get the highest 16 bits.\n assembly {\n version_ := shr(240, calldataload(encodedTx.offset))\n }\n }\n\n /// @notice Extracts the origin chain ID from the encoded transaction.\n function originChainId(bytes calldata encodedTx) internal pure returns (uint32 originChainId_) {\n // Load 32 bytes from the offset and shift it 224 bits to the right to get the highest 32 bits.\n assembly {\n originChainId_ := shr(224, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_CHAIN_ID)))\n }\n }\n\n /// @notice Extracts the destination chain ID from the encoded transaction.\n function destChainId(bytes calldata encodedTx) internal pure returns (uint32 destChainId_) {\n // Load 32 bytes from the offset and shift it 224 bits to the right to get the highest 32 bits.\n assembly {\n destChainId_ := shr(224, calldataload(add(encodedTx.offset, OFFSET_DEST_CHAIN_ID)))\n }\n }\n\n /// @notice Extracts the origin sender from the encoded transaction.\n function originSender(bytes calldata encodedTx) internal pure returns (address originSender_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n originSender_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_SENDER)))\n }\n }\n\n /// @notice Extracts the destination recipient from the encoded transaction.\n function destRecipient(bytes calldata encodedTx) internal pure returns (address destRecipient_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n destRecipient_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_DEST_RECIPIENT)))\n }\n }\n\n /// @notice Extracts the origin token from the encoded transaction.\n function originToken(bytes calldata encodedTx) internal pure returns (address originToken_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n originToken_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_TOKEN)))\n }\n }\n\n /// @notice Extracts the destination token from the encoded transaction.\n function destToken(bytes calldata encodedTx) internal pure returns (address destToken_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n destToken_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_DEST_TOKEN)))\n }\n }\n\n /// @notice Extracts the origin amount from the encoded transaction.\n function originAmount(bytes calldata encodedTx) internal pure returns (uint256 originAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n originAmount_ := calldataload(add(encodedTx.offset, OFFSET_ORIGIN_AMOUNT))\n }\n }\n\n /// @notice Extracts the destination amount from the encoded transaction.\n function destAmount(bytes calldata encodedTx) internal pure returns (uint256 destAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n destAmount_ := calldataload(add(encodedTx.offset, OFFSET_DEST_AMOUNT))\n }\n }\n\n /// @notice Extracts the origin fee amount from the encoded transaction.\n function originFeeAmount(bytes calldata encodedTx) internal pure returns (uint256 originFeeAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n originFeeAmount_ := calldataload(add(encodedTx.offset, OFFSET_ORIGIN_FEE_AMOUNT))\n }\n }\n\n /// @notice Extracts the deadline from the encoded transaction.\n function deadline(bytes calldata encodedTx) internal pure returns (uint256 deadline_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n deadline_ := calldataload(add(encodedTx.offset, OFFSET_DEADLINE))\n }\n }\n\n /// @notice Extracts the nonce from the encoded transaction.\n function nonce(bytes calldata encodedTx) internal pure returns (uint256 nonce_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n nonce_ := calldataload(add(encodedTx.offset, OFFSET_NONCE))\n }\n }\n\n /// @notice Extracts the exclusivity relayer from the encoded transaction.\n function exclusivityRelayer(bytes calldata encodedTx) internal pure returns (address exclusivityRelayer_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n exclusivityRelayer_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_EXCLUSIVITY_RELAYER)))\n }\n }\n\n /// @notice Extracts the exclusivity end time from the encoded transaction.\n function exclusivityEndTime(bytes calldata encodedTx) internal pure returns (uint256 exclusivityEndTime_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n exclusivityEndTime_ := calldataload(add(encodedTx.offset, OFFSET_EXCLUSIVITY_END_TIME))\n }\n }\n\n /// @notice Extracts the Zap's native value from the encoded transaction.\n function zapNative(bytes calldata encodedTx) internal pure returns (uint256 zapNative_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n zapNative_ := calldataload(add(encodedTx.offset, OFFSET_ZAP_NATIVE))\n }\n }\n\n /// @notice Extracts the Zap's data from the encoded transaction.\n function zapData(bytes calldata encodedTx) internal pure returns (bytes calldata zapData_) {\n zapData_ = encodedTx[OFFSET_ZAP_DATA:];\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// contracts/libs/UniversalToken.sol\n\nlibrary UniversalTokenLib {\n using SafeERC20 for IERC20;\n\n address internal constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Transfers tokens to the given account. Reverts if transfer is not successful.\n /// @dev This might trigger fallback, if ETH is transferred to the contract.\n /// Make sure this can not lead to reentrancy attacks.\n function universalTransfer(address token, address to, uint256 value) internal {\n // Don't do anything, if need to send tokens to this address\n if (to == address(this)) return;\n // Don't do anything, if trying to send zero value\n if (value == 0) return;\n if (token == ETH_ADDRESS) {\n /// @dev Note: this can potentially lead to executing code in `to`.\n // solhint-disable-next-line avoid-low-level-calls\n (bool success,) = to.call{value: value}(\"\");\n require(success, \"ETH transfer failed\");\n } else {\n IERC20(token).safeTransfer(to, value);\n }\n }\n\n /// @notice Issues an infinite allowance to the spender, if the current allowance is insufficient\n /// to spend the given amount.\n function universalApproveInfinity(address token, address spender, uint256 amountToSpend) internal {\n // ETH Chad doesn't require your approval\n if (token == ETH_ADDRESS) return;\n // No-op if allowance is already sufficient\n uint256 allowance = IERC20(token).allowance(address(this), spender);\n if (allowance \u003e= amountToSpend) return;\n // Otherwise, reset approval to 0 and set to max allowance\n if (allowance \u003e 0) IERC20(token).safeDecreaseAllowance(spender, allowance);\n IERC20(token).safeIncreaseAllowance(spender, type(uint256).max);\n }\n\n /// @notice Returns the balance of the given token (or native ETH) for the given account.\n function universalBalanceOf(address token, address account) internal view returns (uint256) {\n if (token == ETH_ADDRESS) {\n return account.balance;\n } else {\n return IERC20(token).balanceOf(account);\n }\n }\n\n /// @dev Checks that token is a contract and not ETH_ADDRESS.\n function assertIsContract(address token) internal view {\n // Check that ETH_ADDRESS was not used (in case this is a predeploy on any of the chains)\n if (token == UniversalTokenLib.ETH_ADDRESS) revert TokenNotContract();\n // Check that token is not an EOA\n if (token.code.length == 0) revert TokenNotContract();\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/Admin.sol\n\ncontract Admin is IAdmin, AccessControlEnumerable {\n using UniversalTokenLib for address;\n\n bytes32 public constant RELAYER_ROLE = keccak256(\"RELAYER_ROLE\");\n bytes32 public constant REFUNDER_ROLE = keccak256(\"REFUNDER_ROLE\");\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n uint256 public constant FEE_BPS = 1e6;\n uint256 public constant FEE_RATE_MAX = 0.01e6; // max 1% on origin amount\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Chain gas amount to forward as rebate if requested\n uint256 public chainGasAmount;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n }\n\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n require(newFeeRate \u003c= FEE_RATE_MAX, \"newFeeRate \u003e max\");\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n token.universalTransfer(recipient, feeAmount);\n emit FeesSwept(token, recipient, feeAmount);\n }\n\n function setChainGasAmount(uint256 newChainGasAmount) external onlyRole(GOVERNOR_ROLE) {\n uint256 oldChainGasAmount = chainGasAmount;\n chainGasAmount = newChainGasAmount;\n emit ChainGasAmountUpdated(oldChainGasAmount, newChainGasAmount);\n }\n}\n\n// contracts/FastBridgeV2.sol\n\n/// @notice FastBridgeV2 is a contract for bridging tokens across chains.\ncontract FastBridgeV2 is Admin, MulticallTarget, IFastBridgeV2, IFastBridgeV2Errors {\n using BridgeTransactionV2Lib for bytes;\n using SafeERC20 for IERC20;\n\n /// @notice Address reserved for native gas token (ETH on Ethereum and most L2s, AVAX on Avalanche, etc)\n address public constant NATIVE_GAS_TOKEN = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Delay for a transaction after which it could be permisionlessly refunded\n uint256 public constant REFUND_DELAY = 7 days;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n /// @notice Maximum length of accepted zapData\n uint256 public constant MAX_ZAP_DATA_LENGTH = 2 ** 16 - 1;\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeTxDetails) public bridgeTxDetails;\n /// @notice Relay details on destination chain\n mapping(bytes32 =\u003e BridgeRelay) public bridgeRelayDetails;\n /// @notice Unique bridge nonces tracked per originSender\n mapping(address =\u003e uint256) public senderNonces;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Replaced by senderNonces\n uint256 public immutable nonce = 0;\n /// @notice the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n bridge({\n params: params,\n paramsV2: BridgeParamsV2({\n quoteRelayer: address(0),\n quoteExclusivitySeconds: 0,\n quoteId: bytes(\"\"),\n zapNative: 0,\n zapData: bytes(\"\")\n })\n });\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes calldata request) external payable {\n // relay override will validate the request\n relay({request: request, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes calldata request, bytes32 destTxHash) external {\n request.validateV2();\n prove({transactionId: keccak256(request), destTxHash: destTxHash, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridgeV2\n function claim(bytes calldata request) external {\n // claim override will validate the request\n claim({request: request, to: address(0)});\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Aggregate the read operations from the same storage slot\n address disputedRelayer = $.proofRelayer;\n BridgeStatus status = $.status;\n uint56 proofBlockTimestamp = $.proofBlockTimestamp;\n // Can only dispute a RELAYER_PROVED transaction within the dispute period\n if (status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(proofBlockTimestamp) \u003e DISPUTE_PERIOD) {\n revert DisputePeriodPassed();\n }\n // Update status to REQUESTED and delete the disputed proof details\n // Note: these are storage writes\n $.status = BridgeStatus.REQUESTED;\n $.proofRelayer = address(0);\n $.proofBlockTimestamp = 0;\n\n emit BridgeProofDisputed(transactionId, disputedRelayer);\n }\n\n /// @inheritdoc IFastBridge\n function refund(bytes calldata request) external {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Can only refund a REQUESTED transaction after its deadline expires\n if ($.status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n uint256 deadline = request.deadline();\n // Permissionless refund is only allowed after REFUND_DELAY on top of the deadline\n if (!hasRole(REFUNDER_ROLE, msg.sender)) deadline += REFUND_DELAY;\n if (block.timestamp \u003c= deadline) revert DeadlineNotExceeded();\n // Update status to REFUNDED and return the full amount (collateral + protocol fees) to the original sender.\n // The protocol fees are only updated when the transaction is claimed, so we don't need to update them here.\n // Note: this is a storage write\n $.status = BridgeStatus.REFUNDED;\n\n address to = request.originSender();\n address token = request.originToken();\n uint256 amount = request.originAmount() + request.originFeeAmount();\n // Emit the event before any external calls\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n // Complete the user refund as the last transaction action\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(to), amount);\n } else {\n IERC20(token).safeTransfer(to, amount);\n }\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // The correct relayer can only claim a RELAYER_PROVED transaction after the dispute period\n if ($.status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if ($.proofRelayer != relayer) revert SenderIncorrect();\n return _timeSince($.proofBlockTimestamp) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n /// @dev This method is added to achieve backwards compatibility with decoding requests into V1 structs:\n /// - `zapNative` is partially reported as a zero/non-zero flag\n /// - `zapData` is ignored\n /// In order to process all kinds of requests use getBridgeTransactionV2 instead.\n function getBridgeTransaction(bytes calldata request) external view returns (BridgeTransaction memory) {\n // Try decoding into V2 struct first. This will revert if V1 struct is passed\n try this.getBridgeTransactionV2(request) returns (BridgeTransactionV2 memory txV2) {\n // Note: we entirely ignore the zapData field, as it was not present in V1\n return BridgeTransaction({\n originChainId: txV2.originChainId,\n destChainId: txV2.destChainId,\n originSender: txV2.originSender,\n destRecipient: txV2.destRecipient,\n originToken: txV2.originToken,\n destToken: txV2.destToken,\n originAmount: txV2.originAmount,\n destAmount: txV2.destAmount,\n originFeeAmount: txV2.originFeeAmount,\n sendChainGas: txV2.zapNative != 0,\n deadline: txV2.deadline,\n nonce: txV2.nonce\n });\n } catch {\n // Fallback to V1 struct\n return abi.decode(request, (BridgeTransaction));\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function getBridgeTransactionV2(bytes calldata request) external pure returns (BridgeTransactionV2 memory) {\n request.validateV2();\n return BridgeTransactionV2Lib.decodeV2(request);\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) public payable {\n int256 exclusivityEndTime = 0;\n // if relayer exclusivity is not intended for this bridge, set exclusivityEndTime to static zero\n // otherwise, set exclusivity to expire at the current block ts offset by quoteExclusivitySeconds\n if (paramsV2.quoteRelayer != address(0)) {\n exclusivityEndTime = int256(block.timestamp) + paramsV2.quoteExclusivitySeconds;\n }\n _validateBridgeParams(params, paramsV2, exclusivityEndTime);\n\n // transfer tokens to bridge contract\n /// @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _takeBridgedUserAsset(params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) {\n originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n }\n\n // set status to requested\n bytes memory request = BridgeTransactionV2Lib.encodeV2(\n BridgeTransactionV2({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n deadline: params.deadline,\n nonce: senderNonces[params.sender]++, // increment nonce on every bridge\n exclusivityRelayer: paramsV2.quoteRelayer,\n // We checked exclusivityEndTime to be in range [0 .. params.deadline] above, so can safely cast\n exclusivityEndTime: uint256(exclusivityEndTime),\n zapNative: paramsV2.zapNative,\n zapData: paramsV2.zapData\n })\n );\n bytes32 transactionId = keccak256(request);\n // Note: the tx status will be updated throughout the tx lifecycle, while destChainId is set once here\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n bridgeTxDetails[transactionId].destChainId = params.dstChainId;\n\n emit BridgeRequested({\n transactionId: transactionId,\n sender: params.sender,\n request: request,\n destChainId: params.dstChainId,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n sendChainGas: paramsV2.zapNative != 0\n });\n emit BridgeQuoteDetails(transactionId, paramsV2.quoteId);\n }\n\n /// @inheritdoc IFastBridgeV2\n function relay(bytes calldata request, address relayer) public payable {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n _validateRelayParams(request, transactionId, relayer);\n // mark bridge transaction as relayed\n bridgeRelayDetails[transactionId] =\n BridgeRelay({blockNumber: uint48(block.number), blockTimestamp: uint48(block.timestamp), relayer: relayer});\n\n // transfer tokens to recipient on destination chain and trigger Zap if requested\n address to = request.destRecipient();\n address token = request.destToken();\n uint256 amount = request.destAmount();\n uint256 zapNative = request.zapNative();\n\n // Emit the event before any external calls\n emit BridgeRelayed({\n transactionId: transactionId,\n relayer: relayer,\n to: to,\n originChainId: request.originChainId(),\n originToken: request.originToken(),\n destToken: token,\n originAmount: request.originAmount(),\n destAmount: amount,\n chainGasAmount: zapNative\n });\n\n // All state changes have been done at this point, can proceed to the external calls.\n // This follows the checks-effects-interactions pattern to mitigate potential reentrancy attacks.\n if (token == NATIVE_GAS_TOKEN) {\n // For the native gas token, additional zapNative is not allowed\n if (zapNative != 0) revert ZapNativeNotSupported();\n // Check that the correct msg.value was sent\n if (msg.value != amount) revert MsgValueIncorrect();\n // Don't do a native transfer yet: we will handle it alongside the Zap below\n } else {\n // For ERC20s, we check that the correct msg.value was sent\n if (msg.value != zapNative) revert MsgValueIncorrect();\n // We need to transfer the tokens from the Relayer to the recipient first before performing an\n // optional post-transfer Zap.\n IERC20(token).safeTransferFrom(msg.sender, to, amount);\n }\n // At this point we have done:\n // - Transferred the requested amount of ERC20 tokens to the recipient.\n // At this point we have confirmed:\n // - For ERC20s: msg.value matches the requested zapNative amount.\n // - For the native gas token: msg.value matches the requested destAmount.\n // Remaining optional things to do:\n // - Forward the full msg.value to the recipient (if non-zero).\n // - Trigger a Zap (if zapData is present).\n bytes calldata zapData = request.zapData();\n if (zapData.length != 0) {\n // Zap Data is present: Zap has been requested by the recipient. Trigger it forwarding the full msg.value.\n\n // Note: if token has a fee on transfers, the recipient will have received less than `amount`.\n // This is a very niche edge case and should be handled by the recipient contract.\n _triggerZapWithChecks({recipient: to, token: token, amount: amount, zapData: zapData});\n } else if (msg.value != 0) {\n // Zap Data is missing, but msg.value was sent. This could happen in two different cases:\n // - Relay with the native gas token is happening.\n // - Relay with ERC20 is happening, with a `zapNative \u003e 0` request.\n // In both cases, we need to transfer the full msg.value to the recipient.\n Address.sendValue(payable(to), msg.value);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) public onlyRole(RELAYER_ROLE) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n\n // Can only prove a REQUESTED transaction\n if ($.status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n // Update status to RELAYER_PROVED and store the proof details\n // Note: these are storage writes\n $.status = BridgeStatus.RELAYER_PROVED;\n $.proofBlockTimestamp = uint56(block.timestamp);\n $.proofRelayer = relayer;\n\n emit BridgeProofProvided(transactionId, relayer, destTxHash);\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes calldata request, address to) public {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Aggregate the read operations from the same storage slot\n address proofRelayer = $.proofRelayer;\n BridgeStatus status = $.status;\n uint56 proofBlockTimestamp = $.proofBlockTimestamp;\n\n // Can only claim a RELAYER_PROVED transaction after the dispute period\n if (status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(proofBlockTimestamp) \u003c= DISPUTE_PERIOD) {\n revert DisputePeriodNotPassed();\n }\n\n if (to == address(0)) {\n // Anyone could claim the funds to the proven relayer on their behalf\n to = proofRelayer;\n } else if (proofRelayer != msg.sender) {\n // Only the proven relayer could specify an address to claim the funds to\n revert SenderIncorrect();\n }\n\n // Update status to RELAYER_CLAIMED and transfer the origin collateral to the specified claim address\n // Note: this is a storage write\n $.status = BridgeStatus.RELAYER_CLAIMED;\n\n address token = request.originToken();\n uint256 amount = request.originAmount();\n // Update protocol fees if origin fee amount exists\n uint256 originFeeAmount = request.originFeeAmount();\n if (originFeeAmount \u003e 0) protocolFees[token] += originFeeAmount;\n // Emit the event before any external calls\n emit BridgeDepositClaimed(transactionId, proofRelayer, to, token, amount);\n // Complete the relayer claim as the last transaction action\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(to), amount);\n } else {\n IERC20(token).safeTransfer(to, amount);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeStatuses(bytes32 transactionId) public view returns (BridgeStatus status) {\n return bridgeTxDetails[transactionId].status;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeProofs(bytes32 transactionId) public view returns (uint96 timestamp, address relayer) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n\n timestamp = $.proofBlockTimestamp;\n relayer = $.proofRelayer;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeRelays(bytes32 transactionId) public view returns (bool) {\n // has this transactionId been relayed?\n return bridgeRelayDetails[transactionId].relayer != address(0);\n }\n\n /// @notice Takes the bridged asset from the user into FastBridgeV2 custody. It will be later\n /// claimed by the relayer who completed the relay on destination chain, or refunded back to the user,\n /// should no one complete the relay.\n function _takeBridgedUserAsset(address token, uint256 amount) internal returns (uint256 amountTaken) {\n if (token == NATIVE_GAS_TOKEN) {\n // For the native gas token, we just need to check that the supplied msg.value is correct.\n // Supplied `msg.value` is already in FastBridgeV2 custody.\n if (amount != msg.value) revert MsgValueIncorrect();\n amountTaken = msg.value;\n } else {\n // For ERC20s, token is explicitly transferred from the user to FastBridgeV2.\n // We don't allow non-zero `msg.value` to avoid extra funds from being stuck in FastBridgeV2.\n if (msg.value != 0) revert MsgValueIncorrect();\n // Throw an explicit error if the provided token address is not a contract\n if (token.code.length == 0) revert TokenNotContract();\n amountTaken = IERC20(token).balanceOf(address(this));\n IERC20(token).safeTransferFrom(msg.sender, address(this), amount);\n // Use the balance difference as the amount taken in case of fee on transfer tokens.\n amountTaken = IERC20(token).balanceOf(address(this)) - amountTaken;\n }\n }\n\n /// @notice Calls the Recipient's hook function with the specified zapData and performs\n /// all the necessary checks for the returned value.\n function _triggerZapWithChecks(address recipient, address token, uint256 amount, bytes calldata zapData) internal {\n // This will bubble any revert messages from the hook function\n bytes memory returnData = Address.functionCallWithValue({\n target: recipient,\n data: abi.encodeCall(IZapRecipient.zap, (token, amount, zapData)),\n // Note: see `relay()` for reasoning behind passing msg.value\n value: msg.value\n });\n // Explicit revert if no return data at all\n if (returnData.length == 0) revert RecipientNoReturnValue();\n // Check that exactly a single return value was returned\n if (returnData.length != 32) revert RecipientIncorrectReturnValue();\n // Return value should be abi-encoded hook function selector\n if (bytes32(returnData) != bytes32(IZapRecipient.zap.selector)) {\n revert RecipientIncorrectReturnValue();\n }\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint56(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint56).max but\n /// proof.timestamp \u003c type(uint56).max via unchecked statement\n /// @param proofBlockTimestamp The bridge proof block timestamp\n /// @return delta Time delta since proof submitted\n function _timeSince(uint56 proofBlockTimestamp) internal view returns (uint256 delta) {\n unchecked {\n delta = uint56(block.timestamp) - proofBlockTimestamp;\n }\n }\n\n /// @notice Performs all the necessary checks for a bridge to happen.\n /// @dev There's no good way to refactor this function to reduce cyclomatic complexity due to\n /// the number of checks that need to be performed, so we skip the code-complexity rule here.\n // solhint-disable-next-line code-complexity\n function _validateBridgeParams(\n BridgeParams memory params,\n BridgeParamsV2 memory paramsV2,\n int256 exclusivityEndTime\n )\n internal\n view\n {\n // Check V1 (legacy) params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.sender == address(0) || params.to == address(0)) revert ZeroAddress();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n // Check V2 params\n if (paramsV2.zapData.length \u003e MAX_ZAP_DATA_LENGTH) revert ZapDataLengthAboveMax();\n if (paramsV2.zapNative != 0 \u0026\u0026 params.destToken == NATIVE_GAS_TOKEN) {\n revert ZapNativeNotSupported();\n }\n // exclusivityEndTime must be in range [0 .. params.deadline]\n if (exclusivityEndTime \u003c 0 || exclusivityEndTime \u003e int256(params.deadline)) {\n revert ExclusivityParamsIncorrect();\n }\n }\n\n /// @notice Performs all the necessary checks for a relay to happen.\n function _validateRelayParams(bytes calldata request, bytes32 transactionId, address relayer) internal view {\n if (relayer == address(0)) revert ZeroAddress();\n // Check if the transaction has already been relayed\n if (bridgeRelays(transactionId)) revert TransactionRelayed();\n if (request.destChainId() != block.chainid) revert ChainIncorrect();\n // Check the deadline for relay to happen\n if (block.timestamp \u003e request.deadline()) revert DeadlineExceeded();\n // Check the exclusivity period, if it is still ongoing\n address exclRelayer = request.exclusivityRelayer();\n if (exclRelayer != address(0) \u0026\u0026 exclRelayer != relayer \u0026\u0026 block.timestamp \u003c= request.exclusivityEndTime()) {\n revert ExclusivityPeriodNotPassed();\n }\n }\n}\n","language":"Solidity","languageVersion":"0.8.24","compilerVersion":"0.8.24","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"26331:11640:0:-:0;;;;;;;;;;;;;;;-1:-1:-1;;;26331:11640:0;;;;;;;;;;;;;;;;;","srcMapRuntime":"26331:11640:0:-:0;;;;;;;;","abiDefinition":[],"userDoc":{"kind":"user","methods":{},"version":1},"developerDoc":{"details":"Library for managing https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive types. Sets have the following properties: - Elements are added, removed, and checked for existence in constant time (O(1)). - Elements are enumerated in O(n). No guarantees are made on the ordering. ```solidity contract Example { // Add the library methods using EnumerableSet for EnumerableSet.AddressSet; // Declare a set state variable EnumerableSet.AddressSet private mySet; } ``` As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`) and `uint256` (`UintSet`) are supported. [WARNING] ==== Trying to delete such a structure from storage will likely result in data corruption, rendering the structure unusable. See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info. In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an array of EnumerableSet. ====","kind":"dev","methods":{},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[],\"devdoc\":{\"details\":\"Library for managing https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive types. Sets have the following properties: - Elements are added, removed, and checked for existence in constant time (O(1)). - Elements are enumerated in O(n). No guarantees are made on the ordering. ```solidity contract Example { // Add the library methods using EnumerableSet for EnumerableSet.AddressSet; // Declare a set state variable EnumerableSet.AddressSet private mySet; } ``` As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`) and `uint256` (`UintSet`) are supported. [WARNING] ==== Trying to delete such a structure from storage will likely result in data corruption, rendering the structure unusable. See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info. In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an array of EnumerableSet. ====\",\"kind\":\"dev\",\"methods\":{},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeV2.sol\":\"EnumerableSet\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeV2.sol\":{\"keccak256\":\"0x5069b55ca07f21bfe30b2a43c18a18318c8af9c181b2dcb07c290825efd70f34\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://273dc020a49d08e50126bbea0d7f783f79d08c702f2fdbc560618d24af308acc\",\"dweb:/ipfs/QmXJ2UVzFc8EPB74RT4CXQPC4xw66jt4T13poyfyd3UERh\"]}},\"version\":1}"},"hashes":{}},"solidity/FastBridgeV2.sol:FastBridgeV2":{"code":"0x60c060405260006080523480156200001657600080fd5b506040516200475c3803806200475c833981016040819052620000399162000199565b806200004760008262000054565b50504360a05250620001c4565b60008062000063848462000091565b90508015620000885760008481526001602052604090206200008690846200013f565b505b90505b92915050565b6000828152602081815260408083206001600160a01b038516845290915281205460ff1662000136576000838152602081815260408083206001600160a01b03861684529091529020805460ff19166001179055620000ed3390565b6001600160a01b0316826001600160a01b0316847f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45060016200008b565b5060006200008b565b600062000088836001600160a01b038416600081815260018301602052604081205462000136575081546001818101845560008481526020808220909301849055845484825282860190935260409020919091556200008b565b600060208284031215620001ac57600080fd5b81516001600160a01b03811681146200008857600080fd5b60805160a051614572620001ea60003960006108b30152600061095401526145726000f3fe60806040526004361061031e5760003560e01c8063886d36ff116101a5578063add98c70116100ec578063c63ff8dd11610095578063ccc574901161006f578063ccc5749014610aad578063d547741f14610ae1578063dcf844a714610b01578063e00a83e014610b2e57600080fd5b8063c63ff8dd146109e0578063c79371b114610a00578063ca15c87314610a8d57600080fd5b8063b250fe6b116100c6578063b250fe6b14610996578063bf333f2c146109b6578063bfc7c607146109cd57600080fd5b8063add98c7014610922578063affed0e014610942578063b13aa2d61461097657600080fd5b80639c9545f01161014e578063a5bbe22b11610128578063a5bbe22b146106ca578063aa9641ab146108d5578063ac11fb1a146108f557600080fd5b80639c9545f014610879578063a217fddf1461088c578063a3ec191a146108a157600080fd5b806391ad50391161017f57806391ad50391461077b57806391d1485414610801578063926d7d7f1461084557600080fd5b8063886d36ff146107285780638f0d6f17146107485780639010d07c1461075b57600080fd5b8063385c1d2f116102695780635960ccf21161021257806363787e52116101ec57806363787e5214610650578063820688d5146106ca5780638379a24f146106e057600080fd5b80635960ccf2146105cf5780635aa6ccba146106035780635eb7d9461461063057600080fd5b80634585169411610243578063458516941461059057806354eff068146105a357806358f85880146105b957600080fd5b8063385c1d2f146105235780633f61331d1461055057806341fcb6121461057057600080fd5b806318e4357d116102cb578063295710ff116102a5578063295710ff146104b65780632f2ff15d146104e357806336568abe1461050357600080fd5b806318e4357d1461044f578063190da5951461046f578063248a9ca31461048657600080fd5b806306f333f2116102fc57806306f333f2146103d75780630f5f6ed7146103f95780630f862f1e1461040f57600080fd5b806301ffc9a71461032357806303ed0ee514610358578063051287bc1461039a575b600080fd5b34801561032f57600080fd5b5061034361033e36600461351e565b610b44565b60405190151581526020015b60405180910390f35b34801561036457600080fd5b5061038c7f043c983c49d46f0e102151eaf8085d4a2e6571d5df2d47b013f39bddfd4a639d81565b60405190815260200161034f565b3480156103a657600080fd5b506103ca6103b5366004613560565b60009081526005602052604090205460ff1690565b60405161034f91906135e3565b3480156103e357600080fd5b506103f76103f2366004613616565b610ba0565b005b34801561040557600080fd5b5061038c61271081565b34801561041b57600080fd5b5061043773eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee81565b6040516001600160a01b03909116815260200161034f565b34801561045b57600080fd5b506103f761046a36600461364f565b610c67565b34801561047b57600080fd5b5061038c62093a8081565b34801561049257600080fd5b5061038c6104a1366004613560565b60009081526020819052604090206001015490565b3480156104c257600080fd5b5061038c6104d1366004613688565b60076020526000908152604090205481565b3480156104ef57600080fd5b506103f76104fe3660046136a5565b610d7c565b34801561050f57600080fd5b506103f761051e3660046136a5565b610da7565b34801561052f57600080fd5b5061054361053e3660046136e3565b610df3565b60405161034f91906137ae565b34801561055c57600080fd5b506103f761056b3660046136e3565b610f81565b34801561057c57600080fd5b506103f761058b36600461388d565b61102b565b6103f761059e366004613a8e565b61129d565b3480156105af57600080fd5b5061038c61ffff81565b3480156105c557600080fd5b5061038c60025481565b3480156105db57600080fd5b5061038c7fdb9556138406326f00296e13ea2ad7db24ba82381212d816b1a40c23b466b32781565b34801561060f57600080fd5b5061062361061e366004613aab565b6112fa565b60405161034f9190613aed565b34801561063c57600080fd5b506103f761064b366004613aab565b6113c7565b34801561065c57600080fd5b506106ba61066b366004613560565b60056020526000908152604090205460ff811690610100810463ffffffff169065010000000000810466ffffffffffffff16906c0100000000000000000000000090046001600160a01b031684565b60405161034f9493929190613c0a565b3480156106d657600080fd5b5061038c61070881565b3480156106ec57600080fd5b506103436106fb366004613560565b6000908152600660205260409020546c0100000000000000000000000090046001600160a01b0316151590565b34801561073457600080fd5b506103f7610743366004613c4b565b6115c9565b6103f7610756366004613aab565b6115f5565b34801561076757600080fd5b50610437610776366004613c97565b611604565b34801561078757600080fd5b506107d5610796366004613560565b60009081526005602052604090205465010000000000810466ffffffffffffff16916c010000000000000000000000009091046001600160a01b031690565b604080516bffffffffffffffffffffffff90931683526001600160a01b0390911660208301520161034f565b34801561080d57600080fd5b5061034361081c3660046136a5565b6000918252602082815260408084206001600160a01b0393909316845291905290205460ff1690565b34801561085157600080fd5b5061038c7fe2b7fb3b832174769106daebcfd6d1970523240dda11281102db9363b83b0dc481565b6103f761088736600461388d565b61161c565b34801561089857600080fd5b5061038c600081565b3480156108ad57600080fd5b5061038c7f000000000000000000000000000000000000000000000000000000000000000081565b3480156108e157600080fd5b506103436108f03660046136a5565b6118d6565b34801561090157600080fd5b50610915610910366004613aab565b6119ad565b60405161034f9190613cb9565b34801561092e57600080fd5b506103f761093d366004613560565b611b61565b34801561094e57600080fd5b5061038c7f000000000000000000000000000000000000000000000000000000000000000081565b34801561098257600080fd5b506103f7610991366004613560565b611cab565b3480156109a257600080fd5b506103f76109b1366004613560565b611d8d565b3480156109c257600080fd5b5061038c620f424081565b6103f76109db366004613e1d565b611df5565b3480156109ec57600080fd5b506103f76109fb366004613aab565b612084565b348015610a0c57600080fd5b50610a5f610a1b366004613560565b60066020526000908152604090205465ffffffffffff8082169166010000000000008104909116906c0100000000000000000000000090046001600160a01b031683565b6040805165ffffffffffff94851681529390921660208401526001600160a01b03169082015260600161034f565b348015610a9957600080fd5b5061038c610aa8366004613560565b612090565b348015610ab957600080fd5b5061038c7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f5581565b348015610aed57600080fd5b506103f7610afc3660046136a5565b6120a7565b348015610b0d57600080fd5b5061038c610b1c366004613688565b60036020526000908152604090205481565b348015610b3a57600080fd5b5061038c60045481565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f5a05180f000000000000000000000000000000000000000000000000000000001480610b9a5750610b9a826120cc565b92915050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f55610bca81612163565b6001600160a01b03831660009081526003602052604081205490819003610bf15750505050565b6001600160a01b038416600081815260036020526040812055610c1590848361216d565b604080516001600160a01b038087168252851660208201529081018290527f244e51bc38c1452fa8aaf487bcb4bca36c2baa3a5fbdb776b1eabd8dc6d277cd9060600160405180910390a1505b505050565b7fe2b7fb3b832174769106daebcfd6d1970523240dda11281102db9363b83b0dc4610c9181612163565b60008481526005602052604090206001815460ff166004811115610cb757610cb7613579565b14610cee576040517f4145817200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80546001600160a01b0384166c0100000000000000000000000081026bffffffffffffffffffffffff66ffffffffffffff421665010000000000021664ffffffff009093169290921791909117600217825560405185815286907f4ac8af8a2cd87193d64dfc7a3b8d9923b714ec528b18725d080aa1299be0c5e49060200160405180910390a35050505050565b600082815260208190526040902060010154610d9781612163565b610da18383612290565b50505050565b6001600160a01b0381163314610de9576040517f6697b23200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610c6282826122bd565b60608267ffffffffffffffff811115610e0e57610e0e6138d9565b604051908082528060200260200182016040528015610e5457816020015b604080518082019091526000815260606020820152815260200190600190039081610e2c5790505b50905060005b83811015610f795730858583818110610e7557610e75613eeb565b9050602002810190610e879190613f1a565b604051610e95929190613f7f565b600060405180830381855af49150503d8060008114610ed0576040519150601f19603f3d011682016040523d82523d6000602084013e610ed5565b606091505b50838381518110610ee857610ee8613eeb565b6020026020010151600001848481518110610f0557610f05613eeb565b602002602001015160200182905282151515158152505050818181518110610f2f57610f2f613eeb565b602002602001015160000151158015610f46575082155b15610f7157610f71828281518110610f6057610f60613eeb565b6020026020010151602001516122ea565b600101610e5a565b509392505050565b60005b82811015610da15760008030868685818110610fa257610fa2613eeb565b9050602002810190610fb49190613f1a565b604051610fc2929190613f7f565b600060405180830381855af49150503d8060008114610ffd576040519150601f19603f3d011682016040523d82523d6000602084013e611002565b606091505b509150915081158015611013575083155b1561102157611021816122ea565b5050600101610f84565b611035838361232c565b60008383604051611047929190613f7f565b604080519182900390912060008181526005602052919091208054919250906c0100000000000000000000000081046001600160a01b03169060ff81169065010000000000900466ffffffffffffff1660028260048111156110ab576110ab613579565b146110e2576040517f4145817200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6107084282900366ffffffffffffff1611611129576040517f1992d0bd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600160a01b03861661113f57829550611181565b6001600160a01b0383163314611181576040517f4af43a9000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b83547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166003178455603288013560601c605a890135609a8a013580156111f0576001600160a01b038316600090815260036020526040812080548392906111ea908490613fbe565b90915550505b604080516001600160a01b03858116825260208201859052808c1692908916918b917f582211c35a2139ac3bbaac74663c6a1f56c6cbb658b41fe11fd45a82074ac678910160405180910390a47fffffffffffffffffffffffff11111111111111111111111111111111111111126001600160a01b0384160161127c5761127789836123ad565b611290565b6112906001600160a01b0384168a84612476565b5050505050505050505050565b6112f7816040518060a0016040528060006001600160a01b03168152602001600081526020016040518060200160405280600081525081526020016000815260200160405180602001604052806000815250815250611df5565b50565b6113ac604051806101e00160405280600063ffffffff168152602001600063ffffffff16815260200160006001600160a01b0316815260200160006001600160a01b0316815260200160006001600160a01b0316815260200160006001600160a01b03168152602001600081526020016000815260200160008152602001600081526020016000815260200160006001600160a01b031681526020016000815260200160008152602001606081525090565b6113b6838361232c565b6113c083836124ea565b9392505050565b6113d1828261232c565b600082826040516113e3929190613f7f565b604080519182900390912060008181526005602052919091209091506001815460ff16600481111561141757611417613579565b1461144e576040517f4145817200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b3360009081527fd2043bf65931af3dbecf60d0db8f40e4160406d7beb00522f4200cf4944a1eb8602052604090205460ba8501359060ff1661149a5761149762093a8082613fbe565b90505b8042116114d3576040517fe15ff9ea00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b81547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166004178255600a850135606090811c906032870135901c6000611522609a890135605a8a0135613fbe565b604080516001600160a01b03858116825260208201849052825193945086169289927fb4c55c0c9bc613519b920e88748090150b890a875d307f21bea7d4fb2e8bc958928290030190a37fffffffffffffffffffffffff11111111111111111111111111111111111111126001600160a01b038316016115ab576115a683826123ad565b6115bf565b6115bf6001600160a01b0383168483612476565b5050505050505050565b6115d3838361232c565b610c6283836040516115e6929190613f7f565b60405180910390208233610c67565b61160082823361161c565b5050565b60008281526001602052604081206113c0908361268c565b611626838361232c565b60008383604051611638929190613f7f565b6040518091039020905061164e84848385612698565b6040805160608101825265ffffffffffff438116825242811660208084019182526001600160a01b038088168587019081526000888152600690935295822094518554935196519091166c01000000000000000000000000026bffffffffffffffffffffffff9685166601000000000000027fffffffffffffffffffffffffffffffffffffffff0000000000000000000000009094169190941617919091179390931617905561170285601e013560601c90565b9050604685013560601c607a86013561012e8701356001600160a01b03808516908716867ff8ae392d784b1ea5e8881bfa586d81abf07ef4f1e2fc75f7fe51c90f05199a5c60028c013560e01c6040805163ffffffff92909216825260328e0135606090811c60208401526001600160a01b038a1683830152605a8f0135908301526080820188905260a08201879052519081900360c00190a47fffffffffffffffffffffffff11111111111111111111111111111111111111126001600160a01b03841601611842578015611804576040517f846dedc000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b81341461183d576040517f81de0bf300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611890565b80341461187b576040517f81de0bf300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6118906001600160a01b03841633868561282d565b36600061189d8a8a612866565b909250905080156118ba576118b58686868585612882565b6118ca565b34156118ca576118ca86346123ad565b50505050505050505050565b60008281526005602052604081206002815460ff1660048111156118fc576118fc613579565b14611933576040517f4145817200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80546001600160a01b038481166c010000000000000000000000009092041614611989576040517f4af43a9000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b546107086501000000000090910466ffffffffffffff908116420316119392505050565b6040805161018081018252600080825260208201819052818301819052606082018190526080820181905260a0820181905260c0820181905260e0820181905261010082018190526101208201819052610140820181905261016082015290517f5aa6ccba0000000000000000000000000000000000000000000000000000000081523090635aa6ccba90611a489086908690600401613ffc565b600060405180830381865afa925050508015611a8657506040513d6000823e601f3d908101601f19168201604052611a83919081019061406b565b60015b611a9d57611a96828401846141a0565b9050610b9a565b604051806101800160405280826000015163ffffffff168152602001826020015163ffffffff16815260200182604001516001600160a01b0316815260200182606001516001600160a01b0316815260200182608001516001600160a01b031681526020018260a001516001600160a01b031681526020018260c0015181526020018260e0015181526020018261010001518152602001826101a0015160001415151581526020018261012001518152602001826101400151815250915050610b9a565b7f043c983c49d46f0e102151eaf8085d4a2e6571d5df2d47b013f39bddfd4a639d611b8b81612163565b600082815260056020526040902080546c0100000000000000000000000081046001600160a01b03169060ff81169065010000000000900466ffffffffffffff166002826004811115611be057611be0613579565b14611c17576040517f4145817200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6107084282900366ffffffffffffff161115611c5f576040517f3e908aac00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b835464ffffffff001660011784556040516001600160a01b0384169087907f0695cf1d39b3055dcd0fe02d8b47eaf0d5a13e1996de925de59d0ef9b7f7fad490600090a3505050505050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f55611cd581612163565b612710821115611d46576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f6e657746656552617465203e206d61780000000000000000000000000000000060448201526064015b60405180910390fd5b600280549083905560408051828152602081018590527f14914da2bf76024616fbe1859783fcd4dbddcb179b1f3a854949fbf920dcb95791015b60405180910390a1505050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f55611db781612163565b600480549083905560408051828152602081018590527f5cf09b12f3f56b4c564d51b25b40360af6d795198adb61ae0806a36c294323fa9101611d80565b80516000906001600160a01b031615611e1a576020820151611e17904261426c565b90505b611e258383836129de565b6000611e3984606001518560a00151612c62565b90506000806002541115611e7257620f424060025483611e599190614294565b611e6391906142ab565b9050611e6f81836142e6565b91505b6000611f7b604051806101e001604052804663ffffffff168152602001886000015163ffffffff16815260200188602001516001600160a01b0316815260200188604001516001600160a01b0316815260200188606001516001600160a01b0316815260200188608001516001600160a01b031681526020018581526020018860c0015181526020018481526020018861010001518152602001600760008a602001516001600160a01b03166001600160a01b031681526020019081526020016000206000815480929190611f46906142f9565b90915550815287516001600160a01b031660208201526040810187905260608089015190820152608080890151910152612e75565b805160208083019190912060008181526005835260409081902080548b5163ffffffff8116610100027fffffffffffffffffffffffffffffffffffffffffffffffffffffff000000000090921691909117600117909155928a01516060808c015160808d015160c08e0151928d0151945197985094966001600160a01b039093169587957f120ea0364f36cdac7983bcfdd55270ca09d7f9b314a2ebc425a3b01ab1d6403a95612037958b959394938e92909190151590614331565b60405180910390a3807f3120e2bb59c86aca6890191a589a96af3662838efa374fbdcdf4c95bfe4a6c0e87604001516040516120739190614387565b60405180910390a250505050505050565b6116008282600061102b565b6000818152600160205260408120610b9a90612fba565b6000828152602081905260409020600101546120c281612163565b610da183836122bd565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f7965db0b000000000000000000000000000000000000000000000000000000001480610b9a57507f01ffc9a7000000000000000000000000000000000000000000000000000000007fffffffff00000000000000000000000000000000000000000000000000000000831614610b9a565b6112f78133612fc4565b306001600160a01b0383160361218257505050565b8060000361218f57505050565b7fffffffffffffffffffffffff11111111111111111111111111111111111111126001600160a01b0384160161227c576000826001600160a01b03168260405160006040518083038185875af1925050503d806000811461220c576040519150601f19603f3d011682016040523d82523d6000602084013e612211565b606091505b5050905080610da1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f455448207472616e73666572206661696c6564000000000000000000000000006044820152606401611d3d565b610c626001600160a01b0384168383612476565b60008061229d8484613030565b905080156113c0576000848152600160205260409020610f7990846130f8565b6000806122ca848461310d565b905080156113c0576000848152600160205260409020610f7990846131ae565b8051156122fa5780518082602001fd5b6040517f5ead5a9d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61014e811015612368576040517f6ee0e17100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b813560f01c60028114610c62576040517f8bd977e700000000000000000000000000000000000000000000000000000000815261ffff82166004820152602401611d3d565b804710156123e9576040517fcd786059000000000000000000000000000000000000000000000000000000008152306004820152602401611d3d565b6000826001600160a01b03168260405160006040518083038185875af1925050503d8060008114612436576040519150601f19603f3d011682016040523d82523d6000602084013e61243b565b606091505b5050905080610c62576040517f1425ea4200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040516001600160a01b03838116602483015260448201839052610c6291859182169063a9059cbb906064015b604051602081830303815290604052915060e01b6020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff83818316178352505050506131c3565b61259c604051806101e00160405280600063ffffffff168152602001600063ffffffff16815260200160006001600160a01b0316815260200160006001600160a01b0316815260200160006001600160a01b0316815260200160006001600160a01b03168152602001600081526020016000815260200160008152602001600081526020016000815260200160006001600160a01b031681526020016000815260200160008152602001606081525090565b600283013560e090811c82526006840135811c6020830152600a840135606090811c6040840152601e850135811c818401526032850135811c60808401526046850135811c60a0840152605a85013560c0840152607a85013591830191909152609a84013561010083015260ba84013561012083015260da84013561014083015260fa840135901c61016082015261010e83013561018082015261012e8301356101a082015261264c8383612866565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152505050506101c082015292915050565b60006113c0838361323f565b6001600160a01b0381166126d8576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000828152600660205260409020546c0100000000000000000000000090046001600160a01b031615612737576040517fbef7bb7d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600684013560e01c4614612777576040517f7029fdf900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60ba8401354211156127b5576040517f559895a300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60fa84013560601c80158015906127de5750816001600160a01b0316816001600160a01b031614155b80156127ef575061010e8501354211155b15612826576040517f14be123200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5050505050565b6040516001600160a01b038481166024830152838116604483015260648201839052610da19186918216906323b872dd906084016124a3565b3660006128778361014e818761439a565b915091509250929050565b60006128fd868686868660405160240161289f94939291906143c4565b60408051601f198184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fe85e13dd0000000000000000000000000000000000000000000000000000000017905234613269565b9050805160000361293a576040517f1a95ad2600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8051602014612975576040517ff3725cca00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7fe85e13dd0000000000000000000000000000000000000000000000000000000061299f826143ed565b146129d6576040517ff3725cca00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b505050505050565b46836000015163ffffffff1603612a21576040517f7029fdf900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60a08301511580612a34575060c0830151155b15612a6b576040517fe38820c800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60208301516001600160a01b03161580612a90575060408301516001600160a01b0316155b15612ac7576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60608301516001600160a01b03161580612aec575060808301516001600160a01b0316155b15612b23576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b612b2f61070842613fbe565b8361010001511015612b6d576040517f04b7fcc800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61ffff8260800151511115612bae576040517f177a70e100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b606082015115801590612be1575060808301516001600160a01b031673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee145b15612c18576040517f846dedc000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000811280612c2b575082610100015181135b15610c62576040517f352807b900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60007fffffffffffffffffffffffff11111111111111111111111111111111111111126001600160a01b03841601612cd457348214612ccd576040517f81de0bf300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5034610b9a565b3415612d0c576040517f81de0bf300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b826001600160a01b03163b600003612d50576040517f7f523fe800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201526001600160a01b038416906370a0823190602401602060405180830381865afa158015612dad573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612dd19190614432565b9050612de86001600160a01b03841633308561282d565b6040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015281906001600160a01b038516906370a0823190602401602060405180830381865afa158015612e47573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612e6b9190614432565b6113c091906142e6565b8051602080830151604080850151606086810151608088015160a089015160c08a015195517e02000000000000000000000000000000000000000000000000000000000000988101989098527fffffffff0000000000000000000000000000000000000000000000000000000060e0998a1b811660228a01529690981b90951660268701527fffffffffffffffffffffffffffffffffffffffff00000000000000000000000092821b8316602a870152811b8216603e86015292831b8116605285015293821b9093166066830152607a820192909252600090609a0160408051601f198184030181529082905260e08501516101008601516101208701516101408801516101608901516101808a01516101a08b01516101c08c0151979950612fa3988a989060200161444b565b604051602081830303815290604052915050919050565b6000610b9a825490565b6000828152602081815260408083206001600160a01b038516845290915290205460ff16611600576040517fe2517d3f0000000000000000000000000000000000000000000000000000000081526001600160a01b038216600482015260248101839052604401611d3d565b6000828152602081815260408083206001600160a01b038516845290915281205460ff166130f0576000838152602081815260408083206001600160a01b0386168452909152902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790556130a83390565b6001600160a01b0316826001600160a01b0316847f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a4506001610b9a565b506000610b9a565b60006113c0836001600160a01b03841661331f565b6000828152602081815260408083206001600160a01b038516845290915281205460ff16156130f0576000838152602081815260408083206001600160a01b038616808552925280832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016905551339286917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a4506001610b9a565b60006113c0836001600160a01b038416613366565b60006131d86001600160a01b03841683613459565b905080516000141580156131fd5750808060200190518101906131fb91906144d4565b155b15610c62576040517f5274afe70000000000000000000000000000000000000000000000000000000081526001600160a01b0384166004820152602401611d3d565b600082600001828154811061325657613256613eeb565b9060005260206000200154905092915050565b6060814710156132a7576040517fcd786059000000000000000000000000000000000000000000000000000000008152306004820152602401611d3d565b600080856001600160a01b031684866040516132c391906144f1565b60006040518083038185875af1925050503d8060008114613300576040519150601f19603f3d011682016040523d82523d6000602084013e613305565b606091505b5091509150613315868383613467565b9695505050505050565b60008181526001830160205260408120546130f057508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155610b9a565b6000818152600183016020526040812054801561344f57600061338a6001836142e6565b855490915060009061339e906001906142e6565b90508082146134035760008660000182815481106133be576133be613eeb565b90600052602060002001549050808760000184815481106133e1576133e1613eeb565b6000918252602080832090910192909255918252600188019052604090208390555b85548690806134145761341461450d565b600190038181906000526020600020016000905590558560010160008681526020019081526020016000206000905560019350505050610b9a565b6000915050610b9a565b60606113c083836000613269565b60608261347c57613477826134dc565b6113c0565b815115801561349357506001600160a01b0384163b155b156134d5576040517f9996b3150000000000000000000000000000000000000000000000000000000081526001600160a01b0385166004820152602401611d3d565b50806113c0565b8051156134ec5780518082602001fd5b6040517f1425ea4200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006020828403121561353057600080fd5b81357fffffffff00000000000000000000000000000000000000000000000000000000811681146113c057600080fd5b60006020828403121561357257600080fd5b5035919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b600581106135df577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b9052565b60208101610b9a82846135a8565b6001600160a01b03811681146112f757600080fd5b8035613611816135f1565b919050565b6000806040838503121561362957600080fd5b8235613634816135f1565b91506020830135613644816135f1565b809150509250929050565b60008060006060848603121561366457600080fd5b8335925060208401359150604084013561367d816135f1565b809150509250925092565b60006020828403121561369a57600080fd5b81356113c0816135f1565b600080604083850312156136b857600080fd5b823591506020830135613644816135f1565b80151581146112f757600080fd5b8035613611816136ca565b6000806000604084860312156136f857600080fd5b833567ffffffffffffffff8082111561371057600080fd5b818601915086601f83011261372457600080fd5b81358181111561373357600080fd5b8760208260051b850101111561374857600080fd5b6020928301955093505084013561367d816136ca565b60005b83811015613779578181015183820152602001613761565b50506000910152565b6000815180845261379a81602086016020860161375e565b601f01601f19169290920160200192915050565b600060208083018184528085518083526040925060408601915060408160051b87010184880160005b83811015613836578883037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc0018552815180511515845287015187840187905261382387850182613782565b95880195935050908601906001016137d7565b509098975050505050505050565b60008083601f84011261385657600080fd5b50813567ffffffffffffffff81111561386e57600080fd5b60208301915083602082850101111561388657600080fd5b9250929050565b6000806000604084860312156138a257600080fd5b833567ffffffffffffffff8111156138b957600080fd5b6138c586828701613844565b909450925050602084013561367d816135f1565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051610120810167ffffffffffffffff8111828210171561392c5761392c6138d9565b60405290565b60405160a0810167ffffffffffffffff8111828210171561392c5761392c6138d9565b6040516101e0810167ffffffffffffffff8111828210171561392c5761392c6138d9565b604051610180810167ffffffffffffffff8111828210171561392c5761392c6138d9565b604051601f8201601f1916810167ffffffffffffffff811182821017156139c6576139c66138d9565b604052919050565b63ffffffff811681146112f757600080fd5b8035613611816139ce565b600061012082840312156139fe57600080fd5b613a06613908565b9050613a11826139e0565b8152613a1f60208301613606565b6020820152613a3060408301613606565b6040820152613a4160608301613606565b6060820152613a5260808301613606565b608082015260a082013560a082015260c082013560c0820152613a7760e083016136d8565b60e082015261010080830135818301525092915050565b60006101208284031215613aa157600080fd5b6113c083836139eb565b60008060208385031215613abe57600080fd5b823567ffffffffffffffff811115613ad557600080fd5b613ae185828601613844565b90969095509350505050565b60208152613b0460208201835163ffffffff169052565b60006020830151613b1d604084018263ffffffff169052565b5060408301516001600160a01b03811660608401525060608301516001600160a01b03811660808401525060808301516001600160a01b03811660a08401525060a08301516001600160a01b03811660c08401525060c083015160e08381019190915283015161010080840191909152830151610120808401919091528301516101408084019190915283015161016080840191909152830151610180613bce818501836001600160a01b03169052565b8401516101a0848101919091528401516101c0808501919091528401516101e0808501529050613c02610200840182613782565b949350505050565b60808101613c1882876135a8565b63ffffffff8516602083015266ffffffffffffff841660408301526001600160a01b038316606083015295945050505050565b600080600060408486031215613c6057600080fd5b833567ffffffffffffffff811115613c7757600080fd5b613c8386828701613844565b909790965060209590950135949350505050565b60008060408385031215613caa57600080fd5b50508035926020909101359150565b815163ffffffff16815261018081016020830151613cdf602084018263ffffffff169052565b506040830151613cfa60408401826001600160a01b03169052565b506060830151613d1560608401826001600160a01b03169052565b506080830151613d3060808401826001600160a01b03169052565b5060a0830151613d4b60a08401826001600160a01b03169052565b5060c083015160c083015260e083015160e083015261010080840151818401525061012080840151613d808285018215159052565b5050610140838101519083015261016092830151929091019190915290565b600067ffffffffffffffff821115613db957613db96138d9565b50601f01601f191660200190565b600082601f830112613dd857600080fd5b8135613deb613de682613d9f565b61399d565b818152846020838601011115613e0057600080fd5b816020850160208301376000918101602001919091529392505050565b6000806101408385031215613e3157600080fd5b613e3b84846139eb565b915061012083013567ffffffffffffffff80821115613e5957600080fd5b9084019060a08287031215613e6d57600080fd5b613e75613932565b8235613e80816135f1565b815260208381013590820152604083013582811115613e9e57600080fd5b613eaa88828601613dc7565b60408301525060608301356060820152608083013582811115613ecc57600080fd5b613ed888828601613dc7565b6080830152508093505050509250929050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112613f4f57600080fd5b83018035915067ffffffffffffffff821115613f6a57600080fd5b60200191503681900382131561388657600080fd5b8183823760009101908152919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b80820180821115610b9a57610b9a613f8f565b818352818160208501375060006020828401015260006020601f19601f840116840101905092915050565b602081526000613c02602083018486613fd1565b8051613611816139ce565b8051613611816135f1565b600082601f83011261403757600080fd5b8151614045613de682613d9f565b81815284602083860101111561405a57600080fd5b613c0282602083016020870161375e565b60006020828403121561407d57600080fd5b815167ffffffffffffffff8082111561409557600080fd5b908301906101e082860312156140aa57600080fd5b6140b2613955565b6140bb83614010565b81526140c960208401614010565b60208201526140da6040840161401b565b60408201526140eb6060840161401b565b60608201526140fc6080840161401b565b608082015261410d60a0840161401b565b60a082015260c0838101519082015260e0808401519082015261010080840151908201526101208084015190820152610140808401519082015261016061415581850161401b565b9082015261018083810151908201526101a080840151908201526101c0808401518381111561418357600080fd5b61418f88828701614026565b918301919091525095945050505050565b600061018082840312156141b357600080fd5b6141bb613979565b6141c4836139e0565b81526141d2602084016139e0565b60208201526141e360408401613606565b60408201526141f460608401613606565b606082015261420560808401613606565b608082015261421660a08401613606565b60a082015260c083013560c082015260e083013560e08201526101008084013581830152506101206142498185016136d8565b908201526101408381013590820152610160928301359281019290925250919050565b808201828112600083128015821682158216171561428c5761428c613f8f565b505092915050565b8082028115828204841417610b9a57610b9a613f8f565b6000826142e1577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b81810381811115610b9a57610b9a613f8f565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820361432a5761432a613f8f565b5060010190565b60e08152600061434460e083018a613782565b63ffffffff989098166020830152506001600160a01b039586166040820152939094166060840152608083019190915260a082015290151560c090910152919050565b6020815260006113c06020830184613782565b600080858511156143aa57600080fd5b838611156143b757600080fd5b5050820193919092039150565b6001600160a01b0385168152836020820152606060408201526000613315606083018486613fd1565b8051602080830151919081101561442c577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8160200360031b1b821691505b50919050565b60006020828403121561444457600080fd5b5051919050565b60008a5161445d818460208f0161375e565b80830190508a81528960208201528860408201528760608201527fffffffffffffffffffffffffffffffffffffffff0000000000000000000000008760601b1660808201528560948201528460b482015283516144c18160d484016020880161375e565b0160d4019b9a5050505050505050505050565b6000602082840312156144e657600080fd5b81516113c0816136ca565b6000825161450381846020870161375e565b9190910192915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fdfea26469706673582212209a48ddc6013fa0ddcb3b8a930e8c7e75c40dab4d351f72ddd07978c3a1539f2764736f6c63430008180033","runtime-code":"0x60806040526004361061031e5760003560e01c8063886d36ff116101a5578063add98c70116100ec578063c63ff8dd11610095578063ccc574901161006f578063ccc5749014610aad578063d547741f14610ae1578063dcf844a714610b01578063e00a83e014610b2e57600080fd5b8063c63ff8dd146109e0578063c79371b114610a00578063ca15c87314610a8d57600080fd5b8063b250fe6b116100c6578063b250fe6b14610996578063bf333f2c146109b6578063bfc7c607146109cd57600080fd5b8063add98c7014610922578063affed0e014610942578063b13aa2d61461097657600080fd5b80639c9545f01161014e578063a5bbe22b11610128578063a5bbe22b146106ca578063aa9641ab146108d5578063ac11fb1a146108f557600080fd5b80639c9545f014610879578063a217fddf1461088c578063a3ec191a146108a157600080fd5b806391ad50391161017f57806391ad50391461077b57806391d1485414610801578063926d7d7f1461084557600080fd5b8063886d36ff146107285780638f0d6f17146107485780639010d07c1461075b57600080fd5b8063385c1d2f116102695780635960ccf21161021257806363787e52116101ec57806363787e5214610650578063820688d5146106ca5780638379a24f146106e057600080fd5b80635960ccf2146105cf5780635aa6ccba146106035780635eb7d9461461063057600080fd5b80634585169411610243578063458516941461059057806354eff068146105a357806358f85880146105b957600080fd5b8063385c1d2f146105235780633f61331d1461055057806341fcb6121461057057600080fd5b806318e4357d116102cb578063295710ff116102a5578063295710ff146104b65780632f2ff15d146104e357806336568abe1461050357600080fd5b806318e4357d1461044f578063190da5951461046f578063248a9ca31461048657600080fd5b806306f333f2116102fc57806306f333f2146103d75780630f5f6ed7146103f95780630f862f1e1461040f57600080fd5b806301ffc9a71461032357806303ed0ee514610358578063051287bc1461039a575b600080fd5b34801561032f57600080fd5b5061034361033e36600461351e565b610b44565b60405190151581526020015b60405180910390f35b34801561036457600080fd5b5061038c7f043c983c49d46f0e102151eaf8085d4a2e6571d5df2d47b013f39bddfd4a639d81565b60405190815260200161034f565b3480156103a657600080fd5b506103ca6103b5366004613560565b60009081526005602052604090205460ff1690565b60405161034f91906135e3565b3480156103e357600080fd5b506103f76103f2366004613616565b610ba0565b005b34801561040557600080fd5b5061038c61271081565b34801561041b57600080fd5b5061043773eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee81565b6040516001600160a01b03909116815260200161034f565b34801561045b57600080fd5b506103f761046a36600461364f565b610c67565b34801561047b57600080fd5b5061038c62093a8081565b34801561049257600080fd5b5061038c6104a1366004613560565b60009081526020819052604090206001015490565b3480156104c257600080fd5b5061038c6104d1366004613688565b60076020526000908152604090205481565b3480156104ef57600080fd5b506103f76104fe3660046136a5565b610d7c565b34801561050f57600080fd5b506103f761051e3660046136a5565b610da7565b34801561052f57600080fd5b5061054361053e3660046136e3565b610df3565b60405161034f91906137ae565b34801561055c57600080fd5b506103f761056b3660046136e3565b610f81565b34801561057c57600080fd5b506103f761058b36600461388d565b61102b565b6103f761059e366004613a8e565b61129d565b3480156105af57600080fd5b5061038c61ffff81565b3480156105c557600080fd5b5061038c60025481565b3480156105db57600080fd5b5061038c7fdb9556138406326f00296e13ea2ad7db24ba82381212d816b1a40c23b466b32781565b34801561060f57600080fd5b5061062361061e366004613aab565b6112fa565b60405161034f9190613aed565b34801561063c57600080fd5b506103f761064b366004613aab565b6113c7565b34801561065c57600080fd5b506106ba61066b366004613560565b60056020526000908152604090205460ff811690610100810463ffffffff169065010000000000810466ffffffffffffff16906c0100000000000000000000000090046001600160a01b031684565b60405161034f9493929190613c0a565b3480156106d657600080fd5b5061038c61070881565b3480156106ec57600080fd5b506103436106fb366004613560565b6000908152600660205260409020546c0100000000000000000000000090046001600160a01b0316151590565b34801561073457600080fd5b506103f7610743366004613c4b565b6115c9565b6103f7610756366004613aab565b6115f5565b34801561076757600080fd5b50610437610776366004613c97565b611604565b34801561078757600080fd5b506107d5610796366004613560565b60009081526005602052604090205465010000000000810466ffffffffffffff16916c010000000000000000000000009091046001600160a01b031690565b604080516bffffffffffffffffffffffff90931683526001600160a01b0390911660208301520161034f565b34801561080d57600080fd5b5061034361081c3660046136a5565b6000918252602082815260408084206001600160a01b0393909316845291905290205460ff1690565b34801561085157600080fd5b5061038c7fe2b7fb3b832174769106daebcfd6d1970523240dda11281102db9363b83b0dc481565b6103f761088736600461388d565b61161c565b34801561089857600080fd5b5061038c600081565b3480156108ad57600080fd5b5061038c7f000000000000000000000000000000000000000000000000000000000000000081565b3480156108e157600080fd5b506103436108f03660046136a5565b6118d6565b34801561090157600080fd5b50610915610910366004613aab565b6119ad565b60405161034f9190613cb9565b34801561092e57600080fd5b506103f761093d366004613560565b611b61565b34801561094e57600080fd5b5061038c7f000000000000000000000000000000000000000000000000000000000000000081565b34801561098257600080fd5b506103f7610991366004613560565b611cab565b3480156109a257600080fd5b506103f76109b1366004613560565b611d8d565b3480156109c257600080fd5b5061038c620f424081565b6103f76109db366004613e1d565b611df5565b3480156109ec57600080fd5b506103f76109fb366004613aab565b612084565b348015610a0c57600080fd5b50610a5f610a1b366004613560565b60066020526000908152604090205465ffffffffffff8082169166010000000000008104909116906c0100000000000000000000000090046001600160a01b031683565b6040805165ffffffffffff94851681529390921660208401526001600160a01b03169082015260600161034f565b348015610a9957600080fd5b5061038c610aa8366004613560565b612090565b348015610ab957600080fd5b5061038c7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f5581565b348015610aed57600080fd5b506103f7610afc3660046136a5565b6120a7565b348015610b0d57600080fd5b5061038c610b1c366004613688565b60036020526000908152604090205481565b348015610b3a57600080fd5b5061038c60045481565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f5a05180f000000000000000000000000000000000000000000000000000000001480610b9a5750610b9a826120cc565b92915050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f55610bca81612163565b6001600160a01b03831660009081526003602052604081205490819003610bf15750505050565b6001600160a01b038416600081815260036020526040812055610c1590848361216d565b604080516001600160a01b038087168252851660208201529081018290527f244e51bc38c1452fa8aaf487bcb4bca36c2baa3a5fbdb776b1eabd8dc6d277cd9060600160405180910390a1505b505050565b7fe2b7fb3b832174769106daebcfd6d1970523240dda11281102db9363b83b0dc4610c9181612163565b60008481526005602052604090206001815460ff166004811115610cb757610cb7613579565b14610cee576040517f4145817200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80546001600160a01b0384166c0100000000000000000000000081026bffffffffffffffffffffffff66ffffffffffffff421665010000000000021664ffffffff009093169290921791909117600217825560405185815286907f4ac8af8a2cd87193d64dfc7a3b8d9923b714ec528b18725d080aa1299be0c5e49060200160405180910390a35050505050565b600082815260208190526040902060010154610d9781612163565b610da18383612290565b50505050565b6001600160a01b0381163314610de9576040517f6697b23200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610c6282826122bd565b60608267ffffffffffffffff811115610e0e57610e0e6138d9565b604051908082528060200260200182016040528015610e5457816020015b604080518082019091526000815260606020820152815260200190600190039081610e2c5790505b50905060005b83811015610f795730858583818110610e7557610e75613eeb565b9050602002810190610e879190613f1a565b604051610e95929190613f7f565b600060405180830381855af49150503d8060008114610ed0576040519150601f19603f3d011682016040523d82523d6000602084013e610ed5565b606091505b50838381518110610ee857610ee8613eeb565b6020026020010151600001848481518110610f0557610f05613eeb565b602002602001015160200182905282151515158152505050818181518110610f2f57610f2f613eeb565b602002602001015160000151158015610f46575082155b15610f7157610f71828281518110610f6057610f60613eeb565b6020026020010151602001516122ea565b600101610e5a565b509392505050565b60005b82811015610da15760008030868685818110610fa257610fa2613eeb565b9050602002810190610fb49190613f1a565b604051610fc2929190613f7f565b600060405180830381855af49150503d8060008114610ffd576040519150601f19603f3d011682016040523d82523d6000602084013e611002565b606091505b509150915081158015611013575083155b1561102157611021816122ea565b5050600101610f84565b611035838361232c565b60008383604051611047929190613f7f565b604080519182900390912060008181526005602052919091208054919250906c0100000000000000000000000081046001600160a01b03169060ff81169065010000000000900466ffffffffffffff1660028260048111156110ab576110ab613579565b146110e2576040517f4145817200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6107084282900366ffffffffffffff1611611129576040517f1992d0bd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600160a01b03861661113f57829550611181565b6001600160a01b0383163314611181576040517f4af43a9000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b83547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166003178455603288013560601c605a890135609a8a013580156111f0576001600160a01b038316600090815260036020526040812080548392906111ea908490613fbe565b90915550505b604080516001600160a01b03858116825260208201859052808c1692908916918b917f582211c35a2139ac3bbaac74663c6a1f56c6cbb658b41fe11fd45a82074ac678910160405180910390a47fffffffffffffffffffffffff11111111111111111111111111111111111111126001600160a01b0384160161127c5761127789836123ad565b611290565b6112906001600160a01b0384168a84612476565b5050505050505050505050565b6112f7816040518060a0016040528060006001600160a01b03168152602001600081526020016040518060200160405280600081525081526020016000815260200160405180602001604052806000815250815250611df5565b50565b6113ac604051806101e00160405280600063ffffffff168152602001600063ffffffff16815260200160006001600160a01b0316815260200160006001600160a01b0316815260200160006001600160a01b0316815260200160006001600160a01b03168152602001600081526020016000815260200160008152602001600081526020016000815260200160006001600160a01b031681526020016000815260200160008152602001606081525090565b6113b6838361232c565b6113c083836124ea565b9392505050565b6113d1828261232c565b600082826040516113e3929190613f7f565b604080519182900390912060008181526005602052919091209091506001815460ff16600481111561141757611417613579565b1461144e576040517f4145817200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b3360009081527fd2043bf65931af3dbecf60d0db8f40e4160406d7beb00522f4200cf4944a1eb8602052604090205460ba8501359060ff1661149a5761149762093a8082613fbe565b90505b8042116114d3576040517fe15ff9ea00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b81547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166004178255600a850135606090811c906032870135901c6000611522609a890135605a8a0135613fbe565b604080516001600160a01b03858116825260208201849052825193945086169289927fb4c55c0c9bc613519b920e88748090150b890a875d307f21bea7d4fb2e8bc958928290030190a37fffffffffffffffffffffffff11111111111111111111111111111111111111126001600160a01b038316016115ab576115a683826123ad565b6115bf565b6115bf6001600160a01b0383168483612476565b5050505050505050565b6115d3838361232c565b610c6283836040516115e6929190613f7f565b60405180910390208233610c67565b61160082823361161c565b5050565b60008281526001602052604081206113c0908361268c565b611626838361232c565b60008383604051611638929190613f7f565b6040518091039020905061164e84848385612698565b6040805160608101825265ffffffffffff438116825242811660208084019182526001600160a01b038088168587019081526000888152600690935295822094518554935196519091166c01000000000000000000000000026bffffffffffffffffffffffff9685166601000000000000027fffffffffffffffffffffffffffffffffffffffff0000000000000000000000009094169190941617919091179390931617905561170285601e013560601c90565b9050604685013560601c607a86013561012e8701356001600160a01b03808516908716867ff8ae392d784b1ea5e8881bfa586d81abf07ef4f1e2fc75f7fe51c90f05199a5c60028c013560e01c6040805163ffffffff92909216825260328e0135606090811c60208401526001600160a01b038a1683830152605a8f0135908301526080820188905260a08201879052519081900360c00190a47fffffffffffffffffffffffff11111111111111111111111111111111111111126001600160a01b03841601611842578015611804576040517f846dedc000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b81341461183d576040517f81de0bf300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611890565b80341461187b576040517f81de0bf300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6118906001600160a01b03841633868561282d565b36600061189d8a8a612866565b909250905080156118ba576118b58686868585612882565b6118ca565b34156118ca576118ca86346123ad565b50505050505050505050565b60008281526005602052604081206002815460ff1660048111156118fc576118fc613579565b14611933576040517f4145817200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80546001600160a01b038481166c010000000000000000000000009092041614611989576040517f4af43a9000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b546107086501000000000090910466ffffffffffffff908116420316119392505050565b6040805161018081018252600080825260208201819052818301819052606082018190526080820181905260a0820181905260c0820181905260e0820181905261010082018190526101208201819052610140820181905261016082015290517f5aa6ccba0000000000000000000000000000000000000000000000000000000081523090635aa6ccba90611a489086908690600401613ffc565b600060405180830381865afa925050508015611a8657506040513d6000823e601f3d908101601f19168201604052611a83919081019061406b565b60015b611a9d57611a96828401846141a0565b9050610b9a565b604051806101800160405280826000015163ffffffff168152602001826020015163ffffffff16815260200182604001516001600160a01b0316815260200182606001516001600160a01b0316815260200182608001516001600160a01b031681526020018260a001516001600160a01b031681526020018260c0015181526020018260e0015181526020018261010001518152602001826101a0015160001415151581526020018261012001518152602001826101400151815250915050610b9a565b7f043c983c49d46f0e102151eaf8085d4a2e6571d5df2d47b013f39bddfd4a639d611b8b81612163565b600082815260056020526040902080546c0100000000000000000000000081046001600160a01b03169060ff81169065010000000000900466ffffffffffffff166002826004811115611be057611be0613579565b14611c17576040517f4145817200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6107084282900366ffffffffffffff161115611c5f576040517f3e908aac00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b835464ffffffff001660011784556040516001600160a01b0384169087907f0695cf1d39b3055dcd0fe02d8b47eaf0d5a13e1996de925de59d0ef9b7f7fad490600090a3505050505050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f55611cd581612163565b612710821115611d46576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f6e657746656552617465203e206d61780000000000000000000000000000000060448201526064015b60405180910390fd5b600280549083905560408051828152602081018590527f14914da2bf76024616fbe1859783fcd4dbddcb179b1f3a854949fbf920dcb95791015b60405180910390a1505050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f55611db781612163565b600480549083905560408051828152602081018590527f5cf09b12f3f56b4c564d51b25b40360af6d795198adb61ae0806a36c294323fa9101611d80565b80516000906001600160a01b031615611e1a576020820151611e17904261426c565b90505b611e258383836129de565b6000611e3984606001518560a00151612c62565b90506000806002541115611e7257620f424060025483611e599190614294565b611e6391906142ab565b9050611e6f81836142e6565b91505b6000611f7b604051806101e001604052804663ffffffff168152602001886000015163ffffffff16815260200188602001516001600160a01b0316815260200188604001516001600160a01b0316815260200188606001516001600160a01b0316815260200188608001516001600160a01b031681526020018581526020018860c0015181526020018481526020018861010001518152602001600760008a602001516001600160a01b03166001600160a01b031681526020019081526020016000206000815480929190611f46906142f9565b90915550815287516001600160a01b031660208201526040810187905260608089015190820152608080890151910152612e75565b805160208083019190912060008181526005835260409081902080548b5163ffffffff8116610100027fffffffffffffffffffffffffffffffffffffffffffffffffffffff000000000090921691909117600117909155928a01516060808c015160808d015160c08e0151928d0151945197985094966001600160a01b039093169587957f120ea0364f36cdac7983bcfdd55270ca09d7f9b314a2ebc425a3b01ab1d6403a95612037958b959394938e92909190151590614331565b60405180910390a3807f3120e2bb59c86aca6890191a589a96af3662838efa374fbdcdf4c95bfe4a6c0e87604001516040516120739190614387565b60405180910390a250505050505050565b6116008282600061102b565b6000818152600160205260408120610b9a90612fba565b6000828152602081905260409020600101546120c281612163565b610da183836122bd565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f7965db0b000000000000000000000000000000000000000000000000000000001480610b9a57507f01ffc9a7000000000000000000000000000000000000000000000000000000007fffffffff00000000000000000000000000000000000000000000000000000000831614610b9a565b6112f78133612fc4565b306001600160a01b0383160361218257505050565b8060000361218f57505050565b7fffffffffffffffffffffffff11111111111111111111111111111111111111126001600160a01b0384160161227c576000826001600160a01b03168260405160006040518083038185875af1925050503d806000811461220c576040519150601f19603f3d011682016040523d82523d6000602084013e612211565b606091505b5050905080610da1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f455448207472616e73666572206661696c6564000000000000000000000000006044820152606401611d3d565b610c626001600160a01b0384168383612476565b60008061229d8484613030565b905080156113c0576000848152600160205260409020610f7990846130f8565b6000806122ca848461310d565b905080156113c0576000848152600160205260409020610f7990846131ae565b8051156122fa5780518082602001fd5b6040517f5ead5a9d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61014e811015612368576040517f6ee0e17100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b813560f01c60028114610c62576040517f8bd977e700000000000000000000000000000000000000000000000000000000815261ffff82166004820152602401611d3d565b804710156123e9576040517fcd786059000000000000000000000000000000000000000000000000000000008152306004820152602401611d3d565b6000826001600160a01b03168260405160006040518083038185875af1925050503d8060008114612436576040519150601f19603f3d011682016040523d82523d6000602084013e61243b565b606091505b5050905080610c62576040517f1425ea4200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040516001600160a01b03838116602483015260448201839052610c6291859182169063a9059cbb906064015b604051602081830303815290604052915060e01b6020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff83818316178352505050506131c3565b61259c604051806101e00160405280600063ffffffff168152602001600063ffffffff16815260200160006001600160a01b0316815260200160006001600160a01b0316815260200160006001600160a01b0316815260200160006001600160a01b03168152602001600081526020016000815260200160008152602001600081526020016000815260200160006001600160a01b031681526020016000815260200160008152602001606081525090565b600283013560e090811c82526006840135811c6020830152600a840135606090811c6040840152601e850135811c818401526032850135811c60808401526046850135811c60a0840152605a85013560c0840152607a85013591830191909152609a84013561010083015260ba84013561012083015260da84013561014083015260fa840135901c61016082015261010e83013561018082015261012e8301356101a082015261264c8383612866565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152505050506101c082015292915050565b60006113c0838361323f565b6001600160a01b0381166126d8576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000828152600660205260409020546c0100000000000000000000000090046001600160a01b031615612737576040517fbef7bb7d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600684013560e01c4614612777576040517f7029fdf900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60ba8401354211156127b5576040517f559895a300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60fa84013560601c80158015906127de5750816001600160a01b0316816001600160a01b031614155b80156127ef575061010e8501354211155b15612826576040517f14be123200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5050505050565b6040516001600160a01b038481166024830152838116604483015260648201839052610da19186918216906323b872dd906084016124a3565b3660006128778361014e818761439a565b915091509250929050565b60006128fd868686868660405160240161289f94939291906143c4565b60408051601f198184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fe85e13dd0000000000000000000000000000000000000000000000000000000017905234613269565b9050805160000361293a576040517f1a95ad2600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8051602014612975576040517ff3725cca00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7fe85e13dd0000000000000000000000000000000000000000000000000000000061299f826143ed565b146129d6576040517ff3725cca00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b505050505050565b46836000015163ffffffff1603612a21576040517f7029fdf900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60a08301511580612a34575060c0830151155b15612a6b576040517fe38820c800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60208301516001600160a01b03161580612a90575060408301516001600160a01b0316155b15612ac7576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60608301516001600160a01b03161580612aec575060808301516001600160a01b0316155b15612b23576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b612b2f61070842613fbe565b8361010001511015612b6d576040517f04b7fcc800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61ffff8260800151511115612bae576040517f177a70e100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b606082015115801590612be1575060808301516001600160a01b031673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee145b15612c18576040517f846dedc000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000811280612c2b575082610100015181135b15610c62576040517f352807b900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60007fffffffffffffffffffffffff11111111111111111111111111111111111111126001600160a01b03841601612cd457348214612ccd576040517f81de0bf300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5034610b9a565b3415612d0c576040517f81de0bf300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b826001600160a01b03163b600003612d50576040517f7f523fe800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201526001600160a01b038416906370a0823190602401602060405180830381865afa158015612dad573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612dd19190614432565b9050612de86001600160a01b03841633308561282d565b6040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015281906001600160a01b038516906370a0823190602401602060405180830381865afa158015612e47573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612e6b9190614432565b6113c091906142e6565b8051602080830151604080850151606086810151608088015160a089015160c08a015195517e02000000000000000000000000000000000000000000000000000000000000988101989098527fffffffff0000000000000000000000000000000000000000000000000000000060e0998a1b811660228a01529690981b90951660268701527fffffffffffffffffffffffffffffffffffffffff00000000000000000000000092821b8316602a870152811b8216603e86015292831b8116605285015293821b9093166066830152607a820192909252600090609a0160408051601f198184030181529082905260e08501516101008601516101208701516101408801516101608901516101808a01516101a08b01516101c08c0151979950612fa3988a989060200161444b565b604051602081830303815290604052915050919050565b6000610b9a825490565b6000828152602081815260408083206001600160a01b038516845290915290205460ff16611600576040517fe2517d3f0000000000000000000000000000000000000000000000000000000081526001600160a01b038216600482015260248101839052604401611d3d565b6000828152602081815260408083206001600160a01b038516845290915281205460ff166130f0576000838152602081815260408083206001600160a01b0386168452909152902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790556130a83390565b6001600160a01b0316826001600160a01b0316847f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a4506001610b9a565b506000610b9a565b60006113c0836001600160a01b03841661331f565b6000828152602081815260408083206001600160a01b038516845290915281205460ff16156130f0576000838152602081815260408083206001600160a01b038616808552925280832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016905551339286917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a4506001610b9a565b60006113c0836001600160a01b038416613366565b60006131d86001600160a01b03841683613459565b905080516000141580156131fd5750808060200190518101906131fb91906144d4565b155b15610c62576040517f5274afe70000000000000000000000000000000000000000000000000000000081526001600160a01b0384166004820152602401611d3d565b600082600001828154811061325657613256613eeb565b9060005260206000200154905092915050565b6060814710156132a7576040517fcd786059000000000000000000000000000000000000000000000000000000008152306004820152602401611d3d565b600080856001600160a01b031684866040516132c391906144f1565b60006040518083038185875af1925050503d8060008114613300576040519150601f19603f3d011682016040523d82523d6000602084013e613305565b606091505b5091509150613315868383613467565b9695505050505050565b60008181526001830160205260408120546130f057508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155610b9a565b6000818152600183016020526040812054801561344f57600061338a6001836142e6565b855490915060009061339e906001906142e6565b90508082146134035760008660000182815481106133be576133be613eeb565b90600052602060002001549050808760000184815481106133e1576133e1613eeb565b6000918252602080832090910192909255918252600188019052604090208390555b85548690806134145761341461450d565b600190038181906000526020600020016000905590558560010160008681526020019081526020016000206000905560019350505050610b9a565b6000915050610b9a565b60606113c083836000613269565b60608261347c57613477826134dc565b6113c0565b815115801561349357506001600160a01b0384163b155b156134d5576040517f9996b3150000000000000000000000000000000000000000000000000000000081526001600160a01b0385166004820152602401611d3d565b50806113c0565b8051156134ec5780518082602001fd5b6040517f1425ea4200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006020828403121561353057600080fd5b81357fffffffff00000000000000000000000000000000000000000000000000000000811681146113c057600080fd5b60006020828403121561357257600080fd5b5035919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b600581106135df577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b9052565b60208101610b9a82846135a8565b6001600160a01b03811681146112f757600080fd5b8035613611816135f1565b919050565b6000806040838503121561362957600080fd5b8235613634816135f1565b91506020830135613644816135f1565b809150509250929050565b60008060006060848603121561366457600080fd5b8335925060208401359150604084013561367d816135f1565b809150509250925092565b60006020828403121561369a57600080fd5b81356113c0816135f1565b600080604083850312156136b857600080fd5b823591506020830135613644816135f1565b80151581146112f757600080fd5b8035613611816136ca565b6000806000604084860312156136f857600080fd5b833567ffffffffffffffff8082111561371057600080fd5b818601915086601f83011261372457600080fd5b81358181111561373357600080fd5b8760208260051b850101111561374857600080fd5b6020928301955093505084013561367d816136ca565b60005b83811015613779578181015183820152602001613761565b50506000910152565b6000815180845261379a81602086016020860161375e565b601f01601f19169290920160200192915050565b600060208083018184528085518083526040925060408601915060408160051b87010184880160005b83811015613836578883037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc0018552815180511515845287015187840187905261382387850182613782565b95880195935050908601906001016137d7565b509098975050505050505050565b60008083601f84011261385657600080fd5b50813567ffffffffffffffff81111561386e57600080fd5b60208301915083602082850101111561388657600080fd5b9250929050565b6000806000604084860312156138a257600080fd5b833567ffffffffffffffff8111156138b957600080fd5b6138c586828701613844565b909450925050602084013561367d816135f1565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051610120810167ffffffffffffffff8111828210171561392c5761392c6138d9565b60405290565b60405160a0810167ffffffffffffffff8111828210171561392c5761392c6138d9565b6040516101e0810167ffffffffffffffff8111828210171561392c5761392c6138d9565b604051610180810167ffffffffffffffff8111828210171561392c5761392c6138d9565b604051601f8201601f1916810167ffffffffffffffff811182821017156139c6576139c66138d9565b604052919050565b63ffffffff811681146112f757600080fd5b8035613611816139ce565b600061012082840312156139fe57600080fd5b613a06613908565b9050613a11826139e0565b8152613a1f60208301613606565b6020820152613a3060408301613606565b6040820152613a4160608301613606565b6060820152613a5260808301613606565b608082015260a082013560a082015260c082013560c0820152613a7760e083016136d8565b60e082015261010080830135818301525092915050565b60006101208284031215613aa157600080fd5b6113c083836139eb565b60008060208385031215613abe57600080fd5b823567ffffffffffffffff811115613ad557600080fd5b613ae185828601613844565b90969095509350505050565b60208152613b0460208201835163ffffffff169052565b60006020830151613b1d604084018263ffffffff169052565b5060408301516001600160a01b03811660608401525060608301516001600160a01b03811660808401525060808301516001600160a01b03811660a08401525060a08301516001600160a01b03811660c08401525060c083015160e08381019190915283015161010080840191909152830151610120808401919091528301516101408084019190915283015161016080840191909152830151610180613bce818501836001600160a01b03169052565b8401516101a0848101919091528401516101c0808501919091528401516101e0808501529050613c02610200840182613782565b949350505050565b60808101613c1882876135a8565b63ffffffff8516602083015266ffffffffffffff841660408301526001600160a01b038316606083015295945050505050565b600080600060408486031215613c6057600080fd5b833567ffffffffffffffff811115613c7757600080fd5b613c8386828701613844565b909790965060209590950135949350505050565b60008060408385031215613caa57600080fd5b50508035926020909101359150565b815163ffffffff16815261018081016020830151613cdf602084018263ffffffff169052565b506040830151613cfa60408401826001600160a01b03169052565b506060830151613d1560608401826001600160a01b03169052565b506080830151613d3060808401826001600160a01b03169052565b5060a0830151613d4b60a08401826001600160a01b03169052565b5060c083015160c083015260e083015160e083015261010080840151818401525061012080840151613d808285018215159052565b5050610140838101519083015261016092830151929091019190915290565b600067ffffffffffffffff821115613db957613db96138d9565b50601f01601f191660200190565b600082601f830112613dd857600080fd5b8135613deb613de682613d9f565b61399d565b818152846020838601011115613e0057600080fd5b816020850160208301376000918101602001919091529392505050565b6000806101408385031215613e3157600080fd5b613e3b84846139eb565b915061012083013567ffffffffffffffff80821115613e5957600080fd5b9084019060a08287031215613e6d57600080fd5b613e75613932565b8235613e80816135f1565b815260208381013590820152604083013582811115613e9e57600080fd5b613eaa88828601613dc7565b60408301525060608301356060820152608083013582811115613ecc57600080fd5b613ed888828601613dc7565b6080830152508093505050509250929050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112613f4f57600080fd5b83018035915067ffffffffffffffff821115613f6a57600080fd5b60200191503681900382131561388657600080fd5b8183823760009101908152919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b80820180821115610b9a57610b9a613f8f565b818352818160208501375060006020828401015260006020601f19601f840116840101905092915050565b602081526000613c02602083018486613fd1565b8051613611816139ce565b8051613611816135f1565b600082601f83011261403757600080fd5b8151614045613de682613d9f565b81815284602083860101111561405a57600080fd5b613c0282602083016020870161375e565b60006020828403121561407d57600080fd5b815167ffffffffffffffff8082111561409557600080fd5b908301906101e082860312156140aa57600080fd5b6140b2613955565b6140bb83614010565b81526140c960208401614010565b60208201526140da6040840161401b565b60408201526140eb6060840161401b565b60608201526140fc6080840161401b565b608082015261410d60a0840161401b565b60a082015260c0838101519082015260e0808401519082015261010080840151908201526101208084015190820152610140808401519082015261016061415581850161401b565b9082015261018083810151908201526101a080840151908201526101c0808401518381111561418357600080fd5b61418f88828701614026565b918301919091525095945050505050565b600061018082840312156141b357600080fd5b6141bb613979565b6141c4836139e0565b81526141d2602084016139e0565b60208201526141e360408401613606565b60408201526141f460608401613606565b606082015261420560808401613606565b608082015261421660a08401613606565b60a082015260c083013560c082015260e083013560e08201526101008084013581830152506101206142498185016136d8565b908201526101408381013590820152610160928301359281019290925250919050565b808201828112600083128015821682158216171561428c5761428c613f8f565b505092915050565b8082028115828204841417610b9a57610b9a613f8f565b6000826142e1577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b81810381811115610b9a57610b9a613f8f565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820361432a5761432a613f8f565b5060010190565b60e08152600061434460e083018a613782565b63ffffffff989098166020830152506001600160a01b039586166040820152939094166060840152608083019190915260a082015290151560c090910152919050565b6020815260006113c06020830184613782565b600080858511156143aa57600080fd5b838611156143b757600080fd5b5050820193919092039150565b6001600160a01b0385168152836020820152606060408201526000613315606083018486613fd1565b8051602080830151919081101561442c577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8160200360031b1b821691505b50919050565b60006020828403121561444457600080fd5b5051919050565b60008a5161445d818460208f0161375e565b80830190508a81528960208201528860408201528760608201527fffffffffffffffffffffffffffffffffffffffff0000000000000000000000008760601b1660808201528560948201528460b482015283516144c18160d484016020880161375e565b0160d4019b9a5050505050505050505050565b6000602082840312156144e657600080fd5b81516113c0816136ca565b6000825161450381846020870161375e565b9190910192915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fdfea26469706673582212209a48ddc6013fa0ddcb3b8a930e8c7e75c40dab4d351f72ddd07978c3a1539f2764736f6c63430008180033","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.24 ^0.8.20 ^0.8.4;\n\n// contracts/interfaces/IAdmin.sol\n\ninterface IAdmin {\n // ============ Events ============\n\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n event ChainGasAmountUpdated(uint256 oldChainGasAmount, uint256 newChainGasAmount);\n\n // ============ Methods ============\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n\n function setChainGasAmount(uint256 newChainGasAmount) external;\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IFastBridgeV2Errors.sol\n\ninterface IFastBridgeV2Errors {\n error AmountIncorrect();\n error ChainIncorrect();\n error ExclusivityParamsIncorrect();\n error MsgValueIncorrect();\n error SenderIncorrect();\n error StatusIncorrect();\n error TokenNotContract();\n error ZapDataLengthAboveMax();\n error ZapNativeNotSupported();\n error ZeroAddress();\n\n error RecipientIncorrectReturnValue();\n error RecipientNoReturnValue();\n\n error DeadlineExceeded();\n error DeadlineNotExceeded();\n error DeadlineTooShort();\n error DisputePeriodNotPassed();\n error DisputePeriodPassed();\n error ExclusivityPeriodNotPassed();\n\n error TransactionRelayed();\n}\n\n// contracts/interfaces/IMulticallTarget.sol\n\n/// @notice Interface for a contract that can be called multiple times by the same caller. Inspired by MulticallV3:\n/// https://github.com/mds1/multicall/blob/master/src/Multicall3.sol\ninterface IMulticallTarget {\n struct Result {\n bool success;\n bytes returnData;\n }\n\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external;\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results);\n}\n\n// contracts/interfaces/IZapRecipient.sol\n\ninterface IZapRecipient {\n function zap(address token, uint256 amount, bytes memory zapData) external payable returns (bytes4);\n}\n\n// contracts/libs/Errors.sol\n\nerror DeadlineExceeded();\nerror DeadlineNotExceeded();\nerror DeadlineTooShort();\nerror InsufficientOutputAmount();\n\nerror MsgValueIncorrect();\nerror PoolNotFound();\nerror TokenAddressMismatch();\nerror TokenNotContract();\nerror TokenNotETH();\nerror TokensIdentical();\n\nerror ChainIncorrect();\nerror AmountIncorrect();\nerror ZeroAddress();\n\nerror DisputePeriodNotPassed();\nerror DisputePeriodPassed();\nerror SenderIncorrect();\nerror StatusIncorrect();\nerror TransactionIdIncorrect();\nerror TransactionRelayed();\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// contracts/interfaces/IFastBridgeV2.sol\n\ninterface IFastBridgeV2 is IFastBridge {\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n struct BridgeTxDetails {\n BridgeStatus status;\n uint32 destChainId;\n uint56 proofBlockTimestamp;\n address proofRelayer;\n }\n\n struct BridgeRelay {\n uint48 blockNumber;\n uint48 blockTimestamp;\n address relayer;\n }\n\n /// @notice New params introduced in the FastBridgeV2.\n /// We are passing fields from the older BridgeParams struct outside of this struct\n /// for backwards compatibility.\n /// Note: quoteRelayer and quoteExclusivitySeconds are either both zero (indicating no exclusivity)\n /// or both non-zero (indicating exclusivity for the given period).\n /// Note: zapNative \u003e 0 can NOT be used with destToken = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE (native token)\n /// @param quoteRelayer Relayer that provided the quote for the transaction\n /// @param quoteExclusivitySeconds Period of time the quote relayer is guaranteed exclusivity after user's deposit\n /// @param quoteId Unique quote identifier used for tracking the quote\n /// @param zapNative ETH value to send to the recipient (if any)\n /// @param zapData Parameters for the Zap to the destination recipient (if any)\n struct BridgeParamsV2 {\n address quoteRelayer;\n int256 quoteExclusivitySeconds;\n bytes quoteId;\n uint256 zapNative;\n bytes zapData;\n }\n\n /// @notice Updated bridge transaction struct to include parameters introduced in FastBridgeV2.\n /// Note: only `exclusivityRelayer` can fill such a transaction until `exclusivityEndTime`.\n struct BridgeTransactionV2 {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n // Note: sendChainGas flag from V1 is deprecated\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n address exclusivityRelayer;\n uint256 exclusivityEndTime;\n uint256 zapNative; // ETH value to send to the recipient (if any)\n bytes zapData; // data to pass for the Zap action (if any)\n }\n\n event BridgeQuoteDetails(bytes32 indexed transactionId, bytes quoteId);\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability\n /// to provide temporary exclusivity fill rights for the quote relayer.\n /// @param params The parameters required to bridge\n /// @param paramsV2 The parameters for exclusivity fill rights (optional, can be left empty)\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function relay(bytes memory request, address relayer) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param transactionId The transaction id associated with the encoded bridge transaction to prove\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital.\n /// @notice Can only send funds to the relayer address on the proof.\n /// @param request The encoded bridge transaction to claim on origin chain\n function claim(bytes memory request) external;\n /// @notice Checks if a transaction has been relayed\n /// @param transactionId The ID of the transaction to check\n /// @return True if the transaction has been relayed, false otherwise\n function bridgeRelays(bytes32 transactionId) external view returns (bool);\n\n /// @notice Returns the status of a bridge transaction\n /// @param transactionId The ID of the bridge transaction\n /// @return BridgeStatus Status of the bridge transaction\n function bridgeStatuses(bytes32 transactionId) external view returns (BridgeStatus);\n\n /// @notice Returns the timestamp and relayer of a bridge proof\n /// @param transactionId The ID of the bridge transaction\n /// @return timestamp The timestamp of the bridge proof\n /// @return relayer The relayer address of the bridge proof\n function bridgeProofs(bytes32 transactionId) external view returns (uint96 timestamp, address relayer);\n\n /// @notice Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\n /// @param request The bridge request to decode\n function getBridgeTransactionV2(bytes memory request) external view returns (BridgeTransactionV2 memory);\n}\n\n// contracts/utils/MulticallTarget.sol\n\n// solhint-disable avoid-low-level-calls\n/// @notice Template for a contract that supports batched calls (preserving the msg.sender).\n/// Only calls with zero msg.value could be batched.\nabstract contract MulticallTarget is IMulticallTarget {\n error MulticallTarget__UndeterminedRevert();\n\n /// @notice Perform a batched call to this contract, preserving the msg.sender.\n /// The return data from each call is discarded.\n /// @dev The method is non-payable, so only calls with `msg.value == 0` could be batched.\n /// It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag.\n /// Otherwise, the whole batch call will be reverted with the original revert reason.\n /// @param data List of abi-encoded calldata for the calls to perform.\n /// @param ignoreReverts Whether to ignore the revert errors from the calls.\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external {\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\n if (!success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(result);\n }\n }\n }\n\n /// @notice Perform a batched call to this contract, preserving the msg.sender.\n /// The return data from each call is preserved.\n /// @dev The method is non-payable, so only calls with `msg.value == 0` could be batched.\n /// It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag.\n /// Otherwise, the whole batch call will be reverted with the original revert reason.\n /// @param data List of abi-encoded calldata for the calls to perform.\n /// @param ignoreReverts Whether to ignore the revert errors from the calls.\n /// @return results List of results from the calls: `(success, returnData)`.\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results)\n {\n results = new Result[](data.length);\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (results[i].success, results[i].returnData) = address(this).delegatecall(data[i]);\n if (!results[i].success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(results[i].returnData);\n }\n }\n }\n\n /// @dev Bubbles the revert message from the underlying call.\n /// Note: preserves the same custom error or revert string, if one was used.\n /// Source: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v5.0.2/contracts/utils/Address.sol#L143-L158\n function _bubbleRevert(bytes memory returnData) internal pure {\n // Look for revert reason and bubble it up if present\n if (returnData.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n // solhint-disable-next-line no-inline-assembly\n assembly {\n let returndata_size := mload(returnData)\n revert(add(32, returnData), returndata_size)\n }\n } else {\n revert MulticallTarget__UndeterminedRevert();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// contracts/libs/BridgeTransactionV2.sol\n\n// solhint-disable no-inline-assembly\nlibrary BridgeTransactionV2Lib {\n uint16 internal constant VERSION = 2;\n\n // Offsets of the fields in the packed BridgeTransactionV2 struct\n // uint16 version [000 .. 002)\n // uint32 originChainId [002 .. 006)\n // uint32 destChainId [006 .. 010)\n // address originSender [010 .. 030)\n // address destRecipient [030 .. 050)\n // address originToken [050 .. 070)\n // address destToken [070 .. 090)\n // uint256 originAmount [090 .. 122)\n // uint256 destAmount [122 .. 154)\n // uint256 originFeeAmount [154 .. 186)\n // uint256 deadline [186 .. 218)\n // uint256 nonce [218 .. 250)\n // address exclusivityRelayer [250 .. 270)\n // uint256 exclusivityEndTime [270 .. 302)\n // uint256 zapNative [302 .. 334)\n // bytes zapData [334 .. ***)\n\n // forgefmt: disable-start\n uint256 private constant OFFSET_ORIGIN_CHAIN_ID = 2;\n uint256 private constant OFFSET_DEST_CHAIN_ID = 6;\n uint256 private constant OFFSET_ORIGIN_SENDER = 10;\n uint256 private constant OFFSET_DEST_RECIPIENT = 30;\n uint256 private constant OFFSET_ORIGIN_TOKEN = 50;\n uint256 private constant OFFSET_DEST_TOKEN = 70;\n uint256 private constant OFFSET_ORIGIN_AMOUNT = 90;\n uint256 private constant OFFSET_DEST_AMOUNT = 122;\n uint256 private constant OFFSET_ORIGIN_FEE_AMOUNT = 154;\n uint256 private constant OFFSET_DEADLINE = 186;\n uint256 private constant OFFSET_NONCE = 218;\n uint256 private constant OFFSET_EXCLUSIVITY_RELAYER = 250;\n uint256 private constant OFFSET_EXCLUSIVITY_END_TIME = 270;\n uint256 private constant OFFSET_ZAP_NATIVE = 302;\n uint256 private constant OFFSET_ZAP_DATA = 334;\n // forgefmt: disable-end\n\n error BridgeTransactionV2__InvalidEncodedTx();\n error BridgeTransactionV2__UnsupportedVersion(uint16 version);\n\n /// @notice Validates the encoded transaction to be a tightly packed encoded payload for BridgeTransactionV2.\n /// @dev Checks the minimum length and the version, use this function before decoding any of the fields.\n function validateV2(bytes calldata encodedTx) internal pure {\n // Check the minimum length: must at least include all static fields.\n if (encodedTx.length \u003c OFFSET_ZAP_DATA) revert BridgeTransactionV2__InvalidEncodedTx();\n // Once we validated the length, we can be sure that the version field is present.\n uint16 version_ = version(encodedTx);\n if (version_ != VERSION) revert BridgeTransactionV2__UnsupportedVersion(version_);\n }\n\n /// @notice Encodes the BridgeTransactionV2 struct by tightly packing the fields.\n /// @dev `abi.decode` will not work as a result of the tightly packed fields. Use `decodeV2` to decode instead.\n function encodeV2(IFastBridgeV2.BridgeTransactionV2 memory bridgeTx) internal pure returns (bytes memory) {\n // We split the encoding into two parts to avoid stack-too-deep error\n bytes memory firstPart = abi.encodePacked(\n VERSION,\n bridgeTx.originChainId,\n bridgeTx.destChainId,\n bridgeTx.originSender,\n bridgeTx.destRecipient,\n bridgeTx.originToken,\n bridgeTx.destToken,\n bridgeTx.originAmount\n );\n return abi.encodePacked(\n firstPart,\n bridgeTx.destAmount,\n bridgeTx.originFeeAmount,\n // Note: we skip the deprecated `sendChainGas` flag, which was present in BridgeTransaction V1\n bridgeTx.deadline,\n bridgeTx.nonce,\n // New V2 fields: exclusivity\n bridgeTx.exclusivityRelayer,\n bridgeTx.exclusivityEndTime,\n // New V2 fields: Zap\n bridgeTx.zapNative,\n bridgeTx.zapData\n );\n }\n\n /// @notice Decodes the BridgeTransactionV2 struct from the encoded transaction.\n /// @dev Encoded BridgeTransactionV2 struct must be tightly packed.\n /// Use `validateV2` before decoding to ensure the encoded transaction is valid.\n function decodeV2(bytes calldata encodedTx)\n internal\n pure\n returns (IFastBridgeV2.BridgeTransactionV2 memory bridgeTx)\n {\n bridgeTx.originChainId = originChainId(encodedTx);\n bridgeTx.destChainId = destChainId(encodedTx);\n bridgeTx.originSender = originSender(encodedTx);\n bridgeTx.destRecipient = destRecipient(encodedTx);\n bridgeTx.originToken = originToken(encodedTx);\n bridgeTx.destToken = destToken(encodedTx);\n bridgeTx.originAmount = originAmount(encodedTx);\n bridgeTx.destAmount = destAmount(encodedTx);\n bridgeTx.originFeeAmount = originFeeAmount(encodedTx);\n bridgeTx.deadline = deadline(encodedTx);\n bridgeTx.nonce = nonce(encodedTx);\n bridgeTx.exclusivityRelayer = exclusivityRelayer(encodedTx);\n bridgeTx.exclusivityEndTime = exclusivityEndTime(encodedTx);\n bridgeTx.zapNative = zapNative(encodedTx);\n bridgeTx.zapData = zapData(encodedTx);\n }\n\n /// @notice Extracts the version from the encoded transaction.\n function version(bytes calldata encodedTx) internal pure returns (uint16 version_) {\n // Load 32 bytes from the start and shift it 240 bits to the right to get the highest 16 bits.\n assembly {\n version_ := shr(240, calldataload(encodedTx.offset))\n }\n }\n\n /// @notice Extracts the origin chain ID from the encoded transaction.\n function originChainId(bytes calldata encodedTx) internal pure returns (uint32 originChainId_) {\n // Load 32 bytes from the offset and shift it 224 bits to the right to get the highest 32 bits.\n assembly {\n originChainId_ := shr(224, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_CHAIN_ID)))\n }\n }\n\n /// @notice Extracts the destination chain ID from the encoded transaction.\n function destChainId(bytes calldata encodedTx) internal pure returns (uint32 destChainId_) {\n // Load 32 bytes from the offset and shift it 224 bits to the right to get the highest 32 bits.\n assembly {\n destChainId_ := shr(224, calldataload(add(encodedTx.offset, OFFSET_DEST_CHAIN_ID)))\n }\n }\n\n /// @notice Extracts the origin sender from the encoded transaction.\n function originSender(bytes calldata encodedTx) internal pure returns (address originSender_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n originSender_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_SENDER)))\n }\n }\n\n /// @notice Extracts the destination recipient from the encoded transaction.\n function destRecipient(bytes calldata encodedTx) internal pure returns (address destRecipient_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n destRecipient_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_DEST_RECIPIENT)))\n }\n }\n\n /// @notice Extracts the origin token from the encoded transaction.\n function originToken(bytes calldata encodedTx) internal pure returns (address originToken_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n originToken_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_TOKEN)))\n }\n }\n\n /// @notice Extracts the destination token from the encoded transaction.\n function destToken(bytes calldata encodedTx) internal pure returns (address destToken_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n destToken_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_DEST_TOKEN)))\n }\n }\n\n /// @notice Extracts the origin amount from the encoded transaction.\n function originAmount(bytes calldata encodedTx) internal pure returns (uint256 originAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n originAmount_ := calldataload(add(encodedTx.offset, OFFSET_ORIGIN_AMOUNT))\n }\n }\n\n /// @notice Extracts the destination amount from the encoded transaction.\n function destAmount(bytes calldata encodedTx) internal pure returns (uint256 destAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n destAmount_ := calldataload(add(encodedTx.offset, OFFSET_DEST_AMOUNT))\n }\n }\n\n /// @notice Extracts the origin fee amount from the encoded transaction.\n function originFeeAmount(bytes calldata encodedTx) internal pure returns (uint256 originFeeAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n originFeeAmount_ := calldataload(add(encodedTx.offset, OFFSET_ORIGIN_FEE_AMOUNT))\n }\n }\n\n /// @notice Extracts the deadline from the encoded transaction.\n function deadline(bytes calldata encodedTx) internal pure returns (uint256 deadline_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n deadline_ := calldataload(add(encodedTx.offset, OFFSET_DEADLINE))\n }\n }\n\n /// @notice Extracts the nonce from the encoded transaction.\n function nonce(bytes calldata encodedTx) internal pure returns (uint256 nonce_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n nonce_ := calldataload(add(encodedTx.offset, OFFSET_NONCE))\n }\n }\n\n /// @notice Extracts the exclusivity relayer from the encoded transaction.\n function exclusivityRelayer(bytes calldata encodedTx) internal pure returns (address exclusivityRelayer_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n exclusivityRelayer_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_EXCLUSIVITY_RELAYER)))\n }\n }\n\n /// @notice Extracts the exclusivity end time from the encoded transaction.\n function exclusivityEndTime(bytes calldata encodedTx) internal pure returns (uint256 exclusivityEndTime_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n exclusivityEndTime_ := calldataload(add(encodedTx.offset, OFFSET_EXCLUSIVITY_END_TIME))\n }\n }\n\n /// @notice Extracts the Zap's native value from the encoded transaction.\n function zapNative(bytes calldata encodedTx) internal pure returns (uint256 zapNative_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n zapNative_ := calldataload(add(encodedTx.offset, OFFSET_ZAP_NATIVE))\n }\n }\n\n /// @notice Extracts the Zap's data from the encoded transaction.\n function zapData(bytes calldata encodedTx) internal pure returns (bytes calldata zapData_) {\n zapData_ = encodedTx[OFFSET_ZAP_DATA:];\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// contracts/libs/UniversalToken.sol\n\nlibrary UniversalTokenLib {\n using SafeERC20 for IERC20;\n\n address internal constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Transfers tokens to the given account. Reverts if transfer is not successful.\n /// @dev This might trigger fallback, if ETH is transferred to the contract.\n /// Make sure this can not lead to reentrancy attacks.\n function universalTransfer(address token, address to, uint256 value) internal {\n // Don't do anything, if need to send tokens to this address\n if (to == address(this)) return;\n // Don't do anything, if trying to send zero value\n if (value == 0) return;\n if (token == ETH_ADDRESS) {\n /// @dev Note: this can potentially lead to executing code in `to`.\n // solhint-disable-next-line avoid-low-level-calls\n (bool success,) = to.call{value: value}(\"\");\n require(success, \"ETH transfer failed\");\n } else {\n IERC20(token).safeTransfer(to, value);\n }\n }\n\n /// @notice Issues an infinite allowance to the spender, if the current allowance is insufficient\n /// to spend the given amount.\n function universalApproveInfinity(address token, address spender, uint256 amountToSpend) internal {\n // ETH Chad doesn't require your approval\n if (token == ETH_ADDRESS) return;\n // No-op if allowance is already sufficient\n uint256 allowance = IERC20(token).allowance(address(this), spender);\n if (allowance \u003e= amountToSpend) return;\n // Otherwise, reset approval to 0 and set to max allowance\n if (allowance \u003e 0) IERC20(token).safeDecreaseAllowance(spender, allowance);\n IERC20(token).safeIncreaseAllowance(spender, type(uint256).max);\n }\n\n /// @notice Returns the balance of the given token (or native ETH) for the given account.\n function universalBalanceOf(address token, address account) internal view returns (uint256) {\n if (token == ETH_ADDRESS) {\n return account.balance;\n } else {\n return IERC20(token).balanceOf(account);\n }\n }\n\n /// @dev Checks that token is a contract and not ETH_ADDRESS.\n function assertIsContract(address token) internal view {\n // Check that ETH_ADDRESS was not used (in case this is a predeploy on any of the chains)\n if (token == UniversalTokenLib.ETH_ADDRESS) revert TokenNotContract();\n // Check that token is not an EOA\n if (token.code.length == 0) revert TokenNotContract();\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/Admin.sol\n\ncontract Admin is IAdmin, AccessControlEnumerable {\n using UniversalTokenLib for address;\n\n bytes32 public constant RELAYER_ROLE = keccak256(\"RELAYER_ROLE\");\n bytes32 public constant REFUNDER_ROLE = keccak256(\"REFUNDER_ROLE\");\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n uint256 public constant FEE_BPS = 1e6;\n uint256 public constant FEE_RATE_MAX = 0.01e6; // max 1% on origin amount\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Chain gas amount to forward as rebate if requested\n uint256 public chainGasAmount;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n }\n\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n require(newFeeRate \u003c= FEE_RATE_MAX, \"newFeeRate \u003e max\");\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n token.universalTransfer(recipient, feeAmount);\n emit FeesSwept(token, recipient, feeAmount);\n }\n\n function setChainGasAmount(uint256 newChainGasAmount) external onlyRole(GOVERNOR_ROLE) {\n uint256 oldChainGasAmount = chainGasAmount;\n chainGasAmount = newChainGasAmount;\n emit ChainGasAmountUpdated(oldChainGasAmount, newChainGasAmount);\n }\n}\n\n// contracts/FastBridgeV2.sol\n\n/// @notice FastBridgeV2 is a contract for bridging tokens across chains.\ncontract FastBridgeV2 is Admin, MulticallTarget, IFastBridgeV2, IFastBridgeV2Errors {\n using BridgeTransactionV2Lib for bytes;\n using SafeERC20 for IERC20;\n\n /// @notice Address reserved for native gas token (ETH on Ethereum and most L2s, AVAX on Avalanche, etc)\n address public constant NATIVE_GAS_TOKEN = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Delay for a transaction after which it could be permisionlessly refunded\n uint256 public constant REFUND_DELAY = 7 days;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n /// @notice Maximum length of accepted zapData\n uint256 public constant MAX_ZAP_DATA_LENGTH = 2 ** 16 - 1;\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeTxDetails) public bridgeTxDetails;\n /// @notice Relay details on destination chain\n mapping(bytes32 =\u003e BridgeRelay) public bridgeRelayDetails;\n /// @notice Unique bridge nonces tracked per originSender\n mapping(address =\u003e uint256) public senderNonces;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Replaced by senderNonces\n uint256 public immutable nonce = 0;\n /// @notice the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n bridge({\n params: params,\n paramsV2: BridgeParamsV2({\n quoteRelayer: address(0),\n quoteExclusivitySeconds: 0,\n quoteId: bytes(\"\"),\n zapNative: 0,\n zapData: bytes(\"\")\n })\n });\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes calldata request) external payable {\n // relay override will validate the request\n relay({request: request, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes calldata request, bytes32 destTxHash) external {\n request.validateV2();\n prove({transactionId: keccak256(request), destTxHash: destTxHash, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridgeV2\n function claim(bytes calldata request) external {\n // claim override will validate the request\n claim({request: request, to: address(0)});\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Aggregate the read operations from the same storage slot\n address disputedRelayer = $.proofRelayer;\n BridgeStatus status = $.status;\n uint56 proofBlockTimestamp = $.proofBlockTimestamp;\n // Can only dispute a RELAYER_PROVED transaction within the dispute period\n if (status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(proofBlockTimestamp) \u003e DISPUTE_PERIOD) {\n revert DisputePeriodPassed();\n }\n // Update status to REQUESTED and delete the disputed proof details\n // Note: these are storage writes\n $.status = BridgeStatus.REQUESTED;\n $.proofRelayer = address(0);\n $.proofBlockTimestamp = 0;\n\n emit BridgeProofDisputed(transactionId, disputedRelayer);\n }\n\n /// @inheritdoc IFastBridge\n function refund(bytes calldata request) external {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Can only refund a REQUESTED transaction after its deadline expires\n if ($.status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n uint256 deadline = request.deadline();\n // Permissionless refund is only allowed after REFUND_DELAY on top of the deadline\n if (!hasRole(REFUNDER_ROLE, msg.sender)) deadline += REFUND_DELAY;\n if (block.timestamp \u003c= deadline) revert DeadlineNotExceeded();\n // Update status to REFUNDED and return the full amount (collateral + protocol fees) to the original sender.\n // The protocol fees are only updated when the transaction is claimed, so we don't need to update them here.\n // Note: this is a storage write\n $.status = BridgeStatus.REFUNDED;\n\n address to = request.originSender();\n address token = request.originToken();\n uint256 amount = request.originAmount() + request.originFeeAmount();\n // Emit the event before any external calls\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n // Complete the user refund as the last transaction action\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(to), amount);\n } else {\n IERC20(token).safeTransfer(to, amount);\n }\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // The correct relayer can only claim a RELAYER_PROVED transaction after the dispute period\n if ($.status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if ($.proofRelayer != relayer) revert SenderIncorrect();\n return _timeSince($.proofBlockTimestamp) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n /// @dev This method is added to achieve backwards compatibility with decoding requests into V1 structs:\n /// - `zapNative` is partially reported as a zero/non-zero flag\n /// - `zapData` is ignored\n /// In order to process all kinds of requests use getBridgeTransactionV2 instead.\n function getBridgeTransaction(bytes calldata request) external view returns (BridgeTransaction memory) {\n // Try decoding into V2 struct first. This will revert if V1 struct is passed\n try this.getBridgeTransactionV2(request) returns (BridgeTransactionV2 memory txV2) {\n // Note: we entirely ignore the zapData field, as it was not present in V1\n return BridgeTransaction({\n originChainId: txV2.originChainId,\n destChainId: txV2.destChainId,\n originSender: txV2.originSender,\n destRecipient: txV2.destRecipient,\n originToken: txV2.originToken,\n destToken: txV2.destToken,\n originAmount: txV2.originAmount,\n destAmount: txV2.destAmount,\n originFeeAmount: txV2.originFeeAmount,\n sendChainGas: txV2.zapNative != 0,\n deadline: txV2.deadline,\n nonce: txV2.nonce\n });\n } catch {\n // Fallback to V1 struct\n return abi.decode(request, (BridgeTransaction));\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function getBridgeTransactionV2(bytes calldata request) external pure returns (BridgeTransactionV2 memory) {\n request.validateV2();\n return BridgeTransactionV2Lib.decodeV2(request);\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) public payable {\n int256 exclusivityEndTime = 0;\n // if relayer exclusivity is not intended for this bridge, set exclusivityEndTime to static zero\n // otherwise, set exclusivity to expire at the current block ts offset by quoteExclusivitySeconds\n if (paramsV2.quoteRelayer != address(0)) {\n exclusivityEndTime = int256(block.timestamp) + paramsV2.quoteExclusivitySeconds;\n }\n _validateBridgeParams(params, paramsV2, exclusivityEndTime);\n\n // transfer tokens to bridge contract\n /// @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _takeBridgedUserAsset(params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) {\n originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n }\n\n // set status to requested\n bytes memory request = BridgeTransactionV2Lib.encodeV2(\n BridgeTransactionV2({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n deadline: params.deadline,\n nonce: senderNonces[params.sender]++, // increment nonce on every bridge\n exclusivityRelayer: paramsV2.quoteRelayer,\n // We checked exclusivityEndTime to be in range [0 .. params.deadline] above, so can safely cast\n exclusivityEndTime: uint256(exclusivityEndTime),\n zapNative: paramsV2.zapNative,\n zapData: paramsV2.zapData\n })\n );\n bytes32 transactionId = keccak256(request);\n // Note: the tx status will be updated throughout the tx lifecycle, while destChainId is set once here\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n bridgeTxDetails[transactionId].destChainId = params.dstChainId;\n\n emit BridgeRequested({\n transactionId: transactionId,\n sender: params.sender,\n request: request,\n destChainId: params.dstChainId,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n sendChainGas: paramsV2.zapNative != 0\n });\n emit BridgeQuoteDetails(transactionId, paramsV2.quoteId);\n }\n\n /// @inheritdoc IFastBridgeV2\n function relay(bytes calldata request, address relayer) public payable {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n _validateRelayParams(request, transactionId, relayer);\n // mark bridge transaction as relayed\n bridgeRelayDetails[transactionId] =\n BridgeRelay({blockNumber: uint48(block.number), blockTimestamp: uint48(block.timestamp), relayer: relayer});\n\n // transfer tokens to recipient on destination chain and trigger Zap if requested\n address to = request.destRecipient();\n address token = request.destToken();\n uint256 amount = request.destAmount();\n uint256 zapNative = request.zapNative();\n\n // Emit the event before any external calls\n emit BridgeRelayed({\n transactionId: transactionId,\n relayer: relayer,\n to: to,\n originChainId: request.originChainId(),\n originToken: request.originToken(),\n destToken: token,\n originAmount: request.originAmount(),\n destAmount: amount,\n chainGasAmount: zapNative\n });\n\n // All state changes have been done at this point, can proceed to the external calls.\n // This follows the checks-effects-interactions pattern to mitigate potential reentrancy attacks.\n if (token == NATIVE_GAS_TOKEN) {\n // For the native gas token, additional zapNative is not allowed\n if (zapNative != 0) revert ZapNativeNotSupported();\n // Check that the correct msg.value was sent\n if (msg.value != amount) revert MsgValueIncorrect();\n // Don't do a native transfer yet: we will handle it alongside the Zap below\n } else {\n // For ERC20s, we check that the correct msg.value was sent\n if (msg.value != zapNative) revert MsgValueIncorrect();\n // We need to transfer the tokens from the Relayer to the recipient first before performing an\n // optional post-transfer Zap.\n IERC20(token).safeTransferFrom(msg.sender, to, amount);\n }\n // At this point we have done:\n // - Transferred the requested amount of ERC20 tokens to the recipient.\n // At this point we have confirmed:\n // - For ERC20s: msg.value matches the requested zapNative amount.\n // - For the native gas token: msg.value matches the requested destAmount.\n // Remaining optional things to do:\n // - Forward the full msg.value to the recipient (if non-zero).\n // - Trigger a Zap (if zapData is present).\n bytes calldata zapData = request.zapData();\n if (zapData.length != 0) {\n // Zap Data is present: Zap has been requested by the recipient. Trigger it forwarding the full msg.value.\n\n // Note: if token has a fee on transfers, the recipient will have received less than `amount`.\n // This is a very niche edge case and should be handled by the recipient contract.\n _triggerZapWithChecks({recipient: to, token: token, amount: amount, zapData: zapData});\n } else if (msg.value != 0) {\n // Zap Data is missing, but msg.value was sent. This could happen in two different cases:\n // - Relay with the native gas token is happening.\n // - Relay with ERC20 is happening, with a `zapNative \u003e 0` request.\n // In both cases, we need to transfer the full msg.value to the recipient.\n Address.sendValue(payable(to), msg.value);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) public onlyRole(RELAYER_ROLE) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n\n // Can only prove a REQUESTED transaction\n if ($.status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n // Update status to RELAYER_PROVED and store the proof details\n // Note: these are storage writes\n $.status = BridgeStatus.RELAYER_PROVED;\n $.proofBlockTimestamp = uint56(block.timestamp);\n $.proofRelayer = relayer;\n\n emit BridgeProofProvided(transactionId, relayer, destTxHash);\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes calldata request, address to) public {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Aggregate the read operations from the same storage slot\n address proofRelayer = $.proofRelayer;\n BridgeStatus status = $.status;\n uint56 proofBlockTimestamp = $.proofBlockTimestamp;\n\n // Can only claim a RELAYER_PROVED transaction after the dispute period\n if (status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(proofBlockTimestamp) \u003c= DISPUTE_PERIOD) {\n revert DisputePeriodNotPassed();\n }\n\n if (to == address(0)) {\n // Anyone could claim the funds to the proven relayer on their behalf\n to = proofRelayer;\n } else if (proofRelayer != msg.sender) {\n // Only the proven relayer could specify an address to claim the funds to\n revert SenderIncorrect();\n }\n\n // Update status to RELAYER_CLAIMED and transfer the origin collateral to the specified claim address\n // Note: this is a storage write\n $.status = BridgeStatus.RELAYER_CLAIMED;\n\n address token = request.originToken();\n uint256 amount = request.originAmount();\n // Update protocol fees if origin fee amount exists\n uint256 originFeeAmount = request.originFeeAmount();\n if (originFeeAmount \u003e 0) protocolFees[token] += originFeeAmount;\n // Emit the event before any external calls\n emit BridgeDepositClaimed(transactionId, proofRelayer, to, token, amount);\n // Complete the relayer claim as the last transaction action\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(to), amount);\n } else {\n IERC20(token).safeTransfer(to, amount);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeStatuses(bytes32 transactionId) public view returns (BridgeStatus status) {\n return bridgeTxDetails[transactionId].status;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeProofs(bytes32 transactionId) public view returns (uint96 timestamp, address relayer) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n\n timestamp = $.proofBlockTimestamp;\n relayer = $.proofRelayer;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeRelays(bytes32 transactionId) public view returns (bool) {\n // has this transactionId been relayed?\n return bridgeRelayDetails[transactionId].relayer != address(0);\n }\n\n /// @notice Takes the bridged asset from the user into FastBridgeV2 custody. It will be later\n /// claimed by the relayer who completed the relay on destination chain, or refunded back to the user,\n /// should no one complete the relay.\n function _takeBridgedUserAsset(address token, uint256 amount) internal returns (uint256 amountTaken) {\n if (token == NATIVE_GAS_TOKEN) {\n // For the native gas token, we just need to check that the supplied msg.value is correct.\n // Supplied `msg.value` is already in FastBridgeV2 custody.\n if (amount != msg.value) revert MsgValueIncorrect();\n amountTaken = msg.value;\n } else {\n // For ERC20s, token is explicitly transferred from the user to FastBridgeV2.\n // We don't allow non-zero `msg.value` to avoid extra funds from being stuck in FastBridgeV2.\n if (msg.value != 0) revert MsgValueIncorrect();\n // Throw an explicit error if the provided token address is not a contract\n if (token.code.length == 0) revert TokenNotContract();\n amountTaken = IERC20(token).balanceOf(address(this));\n IERC20(token).safeTransferFrom(msg.sender, address(this), amount);\n // Use the balance difference as the amount taken in case of fee on transfer tokens.\n amountTaken = IERC20(token).balanceOf(address(this)) - amountTaken;\n }\n }\n\n /// @notice Calls the Recipient's hook function with the specified zapData and performs\n /// all the necessary checks for the returned value.\n function _triggerZapWithChecks(address recipient, address token, uint256 amount, bytes calldata zapData) internal {\n // This will bubble any revert messages from the hook function\n bytes memory returnData = Address.functionCallWithValue({\n target: recipient,\n data: abi.encodeCall(IZapRecipient.zap, (token, amount, zapData)),\n // Note: see `relay()` for reasoning behind passing msg.value\n value: msg.value\n });\n // Explicit revert if no return data at all\n if (returnData.length == 0) revert RecipientNoReturnValue();\n // Check that exactly a single return value was returned\n if (returnData.length != 32) revert RecipientIncorrectReturnValue();\n // Return value should be abi-encoded hook function selector\n if (bytes32(returnData) != bytes32(IZapRecipient.zap.selector)) {\n revert RecipientIncorrectReturnValue();\n }\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint56(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint56).max but\n /// proof.timestamp \u003c type(uint56).max via unchecked statement\n /// @param proofBlockTimestamp The bridge proof block timestamp\n /// @return delta Time delta since proof submitted\n function _timeSince(uint56 proofBlockTimestamp) internal view returns (uint256 delta) {\n unchecked {\n delta = uint56(block.timestamp) - proofBlockTimestamp;\n }\n }\n\n /// @notice Performs all the necessary checks for a bridge to happen.\n /// @dev There's no good way to refactor this function to reduce cyclomatic complexity due to\n /// the number of checks that need to be performed, so we skip the code-complexity rule here.\n // solhint-disable-next-line code-complexity\n function _validateBridgeParams(\n BridgeParams memory params,\n BridgeParamsV2 memory paramsV2,\n int256 exclusivityEndTime\n )\n internal\n view\n {\n // Check V1 (legacy) params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.sender == address(0) || params.to == address(0)) revert ZeroAddress();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n // Check V2 params\n if (paramsV2.zapData.length \u003e MAX_ZAP_DATA_LENGTH) revert ZapDataLengthAboveMax();\n if (paramsV2.zapNative != 0 \u0026\u0026 params.destToken == NATIVE_GAS_TOKEN) {\n revert ZapNativeNotSupported();\n }\n // exclusivityEndTime must be in range [0 .. params.deadline]\n if (exclusivityEndTime \u003c 0 || exclusivityEndTime \u003e int256(params.deadline)) {\n revert ExclusivityParamsIncorrect();\n }\n }\n\n /// @notice Performs all the necessary checks for a relay to happen.\n function _validateRelayParams(bytes calldata request, bytes32 transactionId, address relayer) internal view {\n if (relayer == address(0)) revert ZeroAddress();\n // Check if the transaction has already been relayed\n if (bridgeRelays(transactionId)) revert TransactionRelayed();\n if (request.destChainId() != block.chainid) revert ChainIncorrect();\n // Check the deadline for relay to happen\n if (block.timestamp \u003e request.deadline()) revert DeadlineExceeded();\n // Check the exclusivity period, if it is still ongoing\n address exclRelayer = request.exclusivityRelayer();\n if (exclRelayer != address(0) \u0026\u0026 exclRelayer != relayer \u0026\u0026 block.timestamp \u003c= request.exclusivityEndTime()) {\n revert ExclusivityPeriodNotPassed();\n }\n }\n}\n","language":"Solidity","languageVersion":"0.8.24","compilerVersion":"0.8.24","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"80829:22781:0:-:0;;;82190:1;82157:34;;82295:85;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;82329:6;79744:38;68916:4;82329:6;79744:10;:38::i;:::-;-1:-1:-1;;82361:12:0::1;82347:26;::::0;-1:-1:-1;80829:22781:0;;78229:257;78315:4;;78346:31;78363:4;78369:7;78346:16;:31::i;:::-;78331:46;;78391:7;78387:69;;;78414:18;;;;:12;:18;;;;;:31;;78437:7;78414:22;:31::i;:::-;;78387:69;78472:7;-1:-1:-1;78229:257:0;;;;;:::o;72863:316::-;72940:4;69638:12;;;;;;;;;;;-1:-1:-1;;;;;69638:29:0;;;;;;;;;;;;72956:217;;72999:6;:12;;;;;;;;;;;-1:-1:-1;;;;;72999:29:0;;;;;;;;;:36;;-1:-1:-1;;72999:36:0;73031:4;72999:36;;;73081:12;23872:10;;23793:96;73081:12;-1:-1:-1;;;;;73054:40:0;73072:7;-1:-1:-1;;;;;73054:40:0;73066:4;73054:40;;;;;;;;;;-1:-1:-1;73115:4:0;73108:11;;72956:217;-1:-1:-1;73157:5:0;73150:12;;33317:150;33387:4;33410:50;33415:3;-1:-1:-1;;;;;33435:23:0;;27305:4;29361:21;;;:14;;;:21;;;;;;27321:321;;-1:-1:-1;27363:23:0;;;;;;;;:11;:23;;;;;;;;;;;;;27545:18;;27521:21;;;:14;;;:21;;;;;;:42;;;;27577:11;;14:290:1;84:6;137:2;125:9;116:7;112:23;108:32;105:52;;;153:1;150;143:12;105:52;179:16;;-1:-1:-1;;;;;224:31:1;;214:42;;204:70;;270:1;267;260:12;14:290;80829:22781:0;;;;;;;;;;;;;;;;;;","srcMapRuntime":"80829:22781:0:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;76889:212;;;;;;;;;;-1:-1:-1;76889:212:0;;;;;:::i;:::-;;:::i;:::-;;;612:14:1;;605:22;587:41;;575:2;560:18;76889:212:0;;;;;;;;79119:60;;;;;;;;;;;;79156:23;79119:60;;;;;785:25:1;;;773:2;758:18;79119:60:0;639:177:1;97373:150:0;;;;;;;;;;-1:-1:-1;97373:150:0;;;;;:::i;:::-;97441:19;97479:30;;;:15;:30;;;;;:37;;;;97373:150;;;;;;;;:::i;80091:359::-;;;;;;;;;;-1:-1:-1;80091:359:0;;;;;:::i;:::-;;:::i;:::-;;79301:45;;;;;;;;;;;;79340:6;79301:45;;81105:85;;;;;;;;;;;;81148:42;81105:85;;;;;-1:-1:-1;;;;;2885:55:1;;;2867:74;;2855:2;2840:18;81105:85:0;2721:226:1;94762:628:0;;;;;;;;;;-1:-1:-1;94762:628:0;;;;;:::i;:::-;;:::i;81400:45::-;;;;;;;;;;;;81439:6;81400:45;;70494:120;;;;;;;;;;-1:-1:-1;70494:120:0;;;;;:::i;:::-;70559:7;70585:12;;;;;;;;;;:22;;;;70494:120;82006:47;;;;;;;;;;-1:-1:-1;82006:47:0;;;;;:::i;:::-;;;;;;;;;;;;;;70910:136;;;;;;;;;;-1:-1:-1;70910:136:0;;;;;:::i;:::-;;:::i;72012:245::-;;;;;;;;;;-1:-1:-1;72012:245:0;;;;;:::i;:::-;;:::i;45772:875::-;;;;;;;;;;-1:-1:-1;45772:875:0;;;;;:::i;:::-;;:::i;:::-;;;;;;;:::i;44371:718::-;;;;;;;;;;-1:-1:-1;44371:718:0;;;;;:::i;:::-;;:::i;95428:1905::-;;;;;;;;;;-1:-1:-1;95428:1905:0;;;;;:::i;:::-;;:::i;82418:366::-;;;;;;:::i;:::-;;:::i;81646:57::-;;;;;;;;;;;;81692:11;81646:57;;79463:30;;;;;;;;;;;;;;;;79047:66;;;;;;;;;;;;79087:26;79047:66;;87939:201;;;;;;;;;;-1:-1:-1;87939:201:0;;;;;:::i;:::-;;:::i;:::-;;;;;;;:::i;84446:1490::-;;;;;;;;;;-1:-1:-1;84446:1490:0;;;;;:::i;:::-;;:::i;81766:58::-;;;;;;;;;;-1:-1:-1;81766:58:0;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;81766:58:0;;;;;;;;;;;;;:::i;81532:56::-;;;;;;;;;;;;81578:10;81532:56;;97857:199;;;;;;;;;;-1:-1:-1;97857:199:0;;;;;:::i;:::-;97923:4;97994:33;;;:18;:33;;;;;:41;;;;-1:-1:-1;;;;;97994:41:0;:55;;;97857:199;83031:202;;;;;;;;;;-1:-1:-1;83031:202:0;;;;;:::i;:::-;;:::i;82822:171::-;;;;;;:::i;:::-;;:::i;77686:142::-;;;;;;;;;;-1:-1:-1;77686:142:0;;;;;:::i;:::-;;:::i;97563:254::-;;;;;;;;;;-1:-1:-1;97563:254:0;;;;;:::i;:::-;97629:16;97702:30;;;:15;:30;;;;;97755:21;;;;;;;97796:14;;;;-1:-1:-1;;;;;97796:14:0;;97563:254;;;;;14243:26:1;14231:39;;;14213:58;;-1:-1:-1;;;;;14307:55:1;;;14302:2;14287:18;;14280:83;14186:18;97563:254:0;14041:328:1;69538:136:0;;;;;;;;;;-1:-1:-1;69538:136:0;;;;;:::i;:::-;69615:4;69638:12;;;;;;;;;;;-1:-1:-1;;;;;69638:29:0;;;;;;;;;;;;;;;69538:136;78977:64;;;;;;;;;;;;79016:25;78977:64;;91163:3559;;;;;;:::i;:::-;;:::i;68871:49::-;;;;;;;;;;-1:-1:-1;68871:49:0;68916:4;68871:49;;82252:36;;;;;;;;;;;;;;;85974:473;;;;;;;;;;-1:-1:-1;85974:473:0;;;;;:::i;:::-;;:::i;86779:1120::-;;;;;;;;;;-1:-1:-1;86779:1120:0;;;;;:::i;:::-;;:::i;:::-;;;;;;;:::i;83469:939::-;;;;;;;;;;-1:-1:-1;83469:939:0;;;;;:::i;:::-;;:::i;82157:34::-;;;;;;;;;;;;;;;79795:290;;;;;;;;;;-1:-1:-1;79795:290:0;;;;;:::i;:::-;;:::i;80456:264::-;;;;;;;;;;-1:-1:-1;80456:264:0;;;;;:::i;:::-;;:::i;79258:37::-;;;;;;;;;;;;79292:3;79258:37;;88180:2943;;;;;;:::i;:::-;;:::i;83273:158::-;;;;;;;;;;-1:-1:-1;83273:158:0;;;;;:::i;:::-;;:::i;81881:57::-;;;;;;;;;;-1:-1:-1;81881:57:0;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;81881:57:0;;;;;;;18029:14:1;18070:15;;;18052:34;;18122:15;;;;18117:2;18102:18;;18095:43;-1:-1:-1;;;;;18174:55:1;18154:18;;;18147:83;18007:2;17992:18;81881:57:0;17821:415:1;77996:131:0;;;;;;;;;;-1:-1:-1;77996:131:0;;;;;:::i;:::-;;:::i;79185:66::-;;;;;;;;;;;;79225:26;79185:66;;71326:138;;;;;;;;;;-1:-1:-1;71326:138:0;;;;;:::i;:::-;;:::i;79549:47::-;;;;;;;;;;-1:-1:-1;79549:47:0;;;;;:::i;:::-;;;;;;;;;;;;;;79670:29;;;;;;;;;;;;;;;;76889:212;76974:4;76997:57;;;77012:42;76997:57;;:97;;;77058:36;77082:11;77058:23;:36::i;:::-;76990:104;76889:212;-1:-1:-1;;76889:212:0:o;80091:359::-;79225:26;69148:16;69159:4;69148:10;:16::i;:::-;-1:-1:-1;;;;;80215:19:0;::::1;80195:17;80215:19:::0;;;:12:::1;:19;::::0;;;;;;80248:14;;;80244:27:::1;;80264:7;80091:359:::0;;;:::o;80244:27::-:1;-1:-1:-1::0;;;;;80312:19:0;::::1;80334:1;80312:19:::0;;;:12:::1;:19;::::0;;;;:23;80345:45:::1;::::0;80369:9;80380;80345:23:::1;:45::i;:::-;80405:38;::::0;;-1:-1:-1;;;;;18522:15:1;;;18504:34;;18574:15;;18569:2;18554:18;;18547:43;18606:18;;;18599:34;;;80405:38:0::1;::::0;18431:2:1;18416:18;80405:38:0::1;;;;;;;80185:265;69174:1;80091:359:::0;;;:::o;94762:628::-;79016:25;69148:16;69159:4;69148:10;:16::i;:::-;94877:25:::1;94905:30:::0;;;:15:::1;:30;::::0;;;;95012:22:::1;95000:8:::0;;::::1;;:34;::::0;::::1;;;;;;:::i;:::-;;94996:64;;95043:17;;;;;;;;;;;;;;94996:64;95183:38:::0;;-1:-1:-1;;;;;95288:24:0;::::1;::::0;;::::1;::::0;95231:47:::1;95262:15;95231:47;::::0;::::1;95288:24:::0;;;;;;;;;;;;;95194:27:::1;95288:24:::0;;;95328:55:::1;::::0;785:25:1;;;95348:13:0;;95328:55:::1;::::0;773:2:1;758:18;95328:55:0::1;;;;;;;94867:523;94762:628:::0;;;;:::o;70910:136::-;70559:7;70585:12;;;;;;;;;;:22;;;69148:16;69159:4;69148:10;:16::i;:::-;71014:25:::1;71025:4;71031:7;71014:10;:25::i;:::-;;70910:136:::0;;;:::o;72012:245::-;-1:-1:-1;;;;;72105:34:0;;23872:10;72105:34;72101:102;;72162:30;;;;;;;;;;;;;;72101:102;72213:37;72225:4;72231:18;72213:11;:37::i;45772:875::-;45901:23;45963:4;45950:25;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;;;;;;;;;;;;;45950:25:0;;;;;;;;;;;;;;;;45940:35;;45990:9;45985:656;46005:15;;;45985:656;;;46478:4;46497;;46502:1;46497:7;;;;;;;:::i;:::-;;;;;;;;;;;;:::i;:::-;46470:35;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;46425:7;46433:1;46425:10;;;;;;;;:::i;:::-;;;;;;;:18;;46445:7;46453:1;46445:10;;;;;;;;:::i;:::-;;;;;;;:21;;46424:81;;;;;;;;;;;;;46524:7;46532:1;46524:10;;;;;;;;:::i;:::-;;;;;;;:18;;;46523:19;:37;;;;;46547:13;46546:14;46523:37;46519:112;;;46580:36;46594:7;46602:1;46594:10;;;;;;;;:::i;:::-;;;;;;;:21;;;46580:13;:36::i;:::-;46022:3;;45985:656;;;;45772:875;;;;;:::o;44371:718::-;44466:9;44461:622;44481:15;;;44461:622;;;44901:12;;44946:4;44965;;44970:1;44965:7;;;;;;;:::i;:::-;;;;;;;;;;;;:::i;:::-;44938:35;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;44900:73;;;;44992:7;44991:8;:26;;;;;45004:13;45003:14;44991:26;44987:86;;;45037:21;45051:6;45037:13;:21::i;:::-;-1:-1:-1;;44498:3:0;;44461:622;;95428:1905;95496:20;:7;;:18;:20::i;:::-;95526:21;95560:7;;95550:18;;;;;;;:::i;:::-;;;;;;;;;;;95578:25;95606:30;;;:15;:30;;;;;;95737:14;;95550:18;;-1:-1:-1;95606:30:0;95737:14;;;-1:-1:-1;;;;;95737:14:0;;95783:8;;;;95830:21;;;;;95956:27;95946:6;:37;;;;;;;;:::i;:::-;;95942:67;;95992:17;;;;;;;;;;;;;;95942:67;81294:10;101199:15;101192:45;;;101184:53;;96023:49;96019:111;;96095:24;;;;;;;;;;;;;;96019:111;-1:-1:-1;;;;;96144:16:0;;96140:319;;96263:12;96258:17;;96140:319;;;-1:-1:-1;;;;;96296:26:0;;96312:10;96296:26;96292:167;;96431:17;;;;;;;;;;;;;;96292:167;96620:39;;;;96631:28;96620:39;;;57393:19;57371:42;;57358:56;57354:2;57350:65;58183:20;58161:43;;58148:57;58971:24;58949:47;;58936:61;96891:19;;96887:63;;-1:-1:-1;;;;;96912:19:0;;;;;;:12;:19;;;;;:38;;96935:15;;96912:19;:38;;96935:15;;96912:38;:::i;:::-;;;;-1:-1:-1;;96887:63:0;97017:68;;;-1:-1:-1;;;;;20205:55:1;;;20187:74;;20292:2;20277:18;;20270:34;;;97017:68:0;;;;;;;;97038:13;;97017:68;;20160:18:1;97017:68:0;;;;;;;97168:25;-1:-1:-1;;;;;97168:25:0;;;97164:163;;97209:38;97235:2;97240:6;97209:17;:38::i;:::-;97164:163;;;97278:38;-1:-1:-1;;;;;97278:26:0;;97305:2;97309:6;97278:26;:38::i;:::-;95486:1847;;;;;;;;95428:1905;;;:::o;82418:366::-;82489:288;82518:6;82548:218;;;;;;;;82603:1;-1:-1:-1;;;;;82548:218:0;;;;;82648:1;82548:218;;;;82676:9;;;;;;;;;;;;82548:218;;;;82714:1;82548:218;;;;82742:9;;;;;;;;;;;;82548:218;;;82489:6;:288::i;:::-;82418:366;:::o;87939:201::-;88018:26;-1:-1:-1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;88018:26:0;88056:20;:7;;:18;:20::i;:::-;88093:40;88125:7;;88093:31;:40::i;:::-;88086:47;87939:201;-1:-1:-1;;;87939:201:0:o;84446:1490::-;84505:20;:7;;:18;:20::i;:::-;84535:21;84569:7;;84559:18;;;;;;;:::i;:::-;;;;;;;;;;;84587:25;84615:30;;;:15;:30;;;;;;84559:18;;-1:-1:-1;84749:22:0;84737:8;;;;:34;;;;;;;;:::i;:::-;;84733:64;;84780:17;;;;;;;;;;;;;;84733:64;84973:10;84807:16;69638:29;;;:12;;:29;:12;:29;;;59347:15;59325:38;;59312:52;;69638:29;;84945:65;;84986:24;81439:6;84986:24;;:::i;:::-;;;84945:65;85043:8;85024:15;:27;85020:61;;85060:21;;;;;;;;;;;;;;85020:61;85366:32;;;;85377:21;85366:32;;;56567:20;56545:43;;56532:57;56528:2;56524:66;;;;57393:19;57371:42;;57358:56;57350:65;;-1:-1:-1;85518:50:0;58971:24;58949:47;;58936:61;58183:20;58161:43;;58148:57;85518:50;:::i;:::-;85635:55;;;-1:-1:-1;;;;;20205:55:1;;;20187:74;;20292:2;20277:18;;20270:34;;;85635:55:0;;20270:34:1;;-1:-1:-1;85635:55:0;;;85657:13;;85635:55;;;;;;;;85771:25;-1:-1:-1;;;;;85771:25:0;;;85767:163;;85812:38;85838:2;85843:6;85812:17;:38::i;:::-;85767:163;;;85881:38;-1:-1:-1;;;;;85881:26:0;;85908:2;85912:6;85881:26;:38::i;:::-;84495:1441;;;;;;84446:1490;;:::o;83031:202::-;83109:20;:7;;:18;:20::i;:::-;83139:87;83171:7;;83161:18;;;;;;;:::i;:::-;;;;;;;;83193:10;83214;83139:5;:87::i;82822:171::-;82940:46;82956:7;;82974:10;82940:5;:46::i;:::-;82822:171;;:::o;77686:142::-;77767:7;77793:18;;;:12;:18;;;;;:28;;77815:5;77793:21;:28::i;91163:3559::-;91244:20;:7;;:18;:20::i;:::-;91274:21;91308:7;;91298:18;;;;;;;:::i;:::-;;;;;;;;91274:42;;91326:53;91347:7;;91356:13;91371:7;91326:20;:53::i;:::-;91483:107;;;;;;;;;91516:12;91483:107;;;;91554:15;91483:107;;;;;;;;;-1:-1:-1;;;;;91483:107:0;;;;;;;;;-1:-1:-1;91435:33:0;;;:18;:33;;;;;;:155;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;91704:23;:7;56987:21;56965:44;56952:58;56948:2;56944:67;;56693:334;91704:23;91691:36;-1:-1:-1;57796:17:0;57774:40;;57761:54;57757:2;57753:63;58571:18;58549:41;;58536:55;60939:17;60917:40;;60904:54;-1:-1:-1;;;;;91936:368:0;;;;;;91979:13;91936:368;55743:22;55721:45;;55708:59;55703:3;55699:69;91936:368;;;20630:10:1;20618:23;;;;20600:42;;57393:19:0;57371:42;;57358:56;57354:2;57350:65;;;20734:2:1;20719:18;;20712:43;-1:-1:-1;;;;;20791:15:1;;20771:18;;;20764:43;58183:20:0;58161:43;;58148:57;20823:18:1;;;20816:34;20881:3;20866:19;;20859:35;;;20925:3;20910:19;;20903:35;;;91936:368:0;;;;;20587:3:1;91936:368:0;;;92519:25;-1:-1:-1;;;;;92519:25:0;;;92515:769;;92641:14;;92637:50;;92664:23;;;;;;;;;;;;;;92637:50;92775:6;92762:9;:19;92758:51;;92790:19;;;;;;;;;;;;;;92758:51;92515:769;;;93018:9;93005;:22;93001:54;;93036:19;;;;;;;;;;;;;;93001:54;93219;-1:-1:-1;;;;;93219:30:0;;93250:10;93262:2;93266:6;93219:30;:54::i;:::-;93782:22;;93807:17;:7;;:15;:17::i;:::-;93782:42;;-1:-1:-1;93782:42:0;-1:-1:-1;93838:19:0;;93834:882;;94195:86;94229:2;94240:5;94255:6;94272:7;;94195:21;:86::i;:::-;93834:882;;;94302:9;:14;94298:418;;94664:41;94690:2;94695:9;94664:17;:41::i;:::-;91234:3488;;;;;;;91163:3559;;;:::o;85974:473::-;86055:4;86099:30;;;:15;:30;;;;;86255:27;86243:8;;;;:39;;;;;;;;:::i;:::-;;86239:69;;86291:17;;;;;;;;;;;;;;86239:69;86322:14;;-1:-1:-1;;;;;86322:25:0;;;:14;;;;;:25;86318:55;;86356:17;;;;;;;;;;;;;;86318:55;86401:21;81294:10;86401:21;;;;;;;;101199:15;101192:45;101184:53;86390:50;;;-1:-1:-1;;;85974:473:0:o;86779:1120::-;-1:-1:-1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;86982:36:0;;;;;:4;;:27;;:36;;87010:7;;;;86982:36;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;86982:36:0;;;;;;;;;;;;:::i;:::-;;;86978:915;;87842:40;;;;87853:7;87842:40;:::i;:::-;87835:47;;;;86978:915;87169:597;;;;;;;;87220:4;:18;;;87169:597;;;;;;87269:4;:16;;;87169:597;;;;;;87317:4;:17;;;-1:-1:-1;;;;;87169:597:0;;;;;87367:4;:18;;;-1:-1:-1;;;;;87169:597:0;;;;;87416:4;:16;;;-1:-1:-1;;;;;87169:597:0;;;;;87461:4;:14;;;-1:-1:-1;;;;;87169:597:0;;;;;87507:4;:17;;;87169:597;;;;87554:4;:15;;;87169:597;;;;87604:4;:20;;;87169:597;;;;87656:4;:14;;;87674:1;87656:19;;87169:597;;;;;;87703:4;:13;;;87169:597;;;;87741:4;:10;;;87169:597;;;87162:604;;;;;83469:939;79156:23;69148:16;69159:4;69148:10;:16::i;:::-;83549:25:::1;83577:30:::0;;;:15:::1;:30;::::0;;;;83711:14;;;;::::1;-1:-1:-1::0;;;;;83711:14:0::1;::::0;83757:8:::1;::::0;::::1;::::0;83804:21;;::::1;;;83932:27;83922:6;:37;;;;;;;;:::i;:::-;;83918:67;;83968:17;;;;;;;;;;;;;;83918:67;81294:10;101199:15:::0;101192:45;;;101184:53;;83999:48:::1;83995:107;;;84070:21;;;;;;;;;;;;;;83995:107;84229:33:::0;;84309:25;;84240:22:::1;84309:25:::0;;;84350:51:::1;::::0;-1:-1:-1;;;;;84350:51:0;::::1;::::0;84370:13;;84350:51:::1;::::0;-1:-1:-1;;84350:51:0::1;83539:869;;;;83469:939:::0;;:::o;79795:290::-;79225:26;69148:16;69159:4;69148:10;:16::i;:::-;79340:6:::1;79894:10;:26;;79886:55;;;::::0;::::1;::::0;;25277:2:1;79886:55:0::1;::::0;::::1;25259:21:1::0;25316:2;25296:18;;;25289:30;25355:18;25335;;;25328:46;25391:18;;79886:55:0::1;;;;;;;;;79972:15;::::0;;79997:28;;;;80040:38:::1;::::0;;25594:25:1;;;25650:2;25635:18;;25628:34;;;80040:38:0::1;::::0;25567:18:1;80040:38:0::1;;;;;;;;79876:209;79795:290:::0;;:::o;80456:264::-;79225:26;69148:16;69159:4;69148:10;:16::i;:::-;80581:14:::1;::::0;;80605:34;;;;80654:59:::1;::::0;;25594:25:1;;;25650:2;25635:18;;25628:34;;;80654:59:0::1;::::0;25567:18:1;80654:59:0::1;25420:248:1::0;88180:2943:0;88535:21;;88281:25;;-1:-1:-1;;;;;88535:35:0;;88531:145;;88633:32;;;;88607:58;;88614:15;88607:58;:::i;:::-;88586:79;;88531:145;88685:59;88707:6;88715:8;88725:18;88685:21;:59::i;:::-;88880:20;88903:62;88925:6;:18;;;88945:6;:19;;;88903:21;:62::i;:::-;88880:85;;89033:23;89088:1;89070:15;;:19;89066:222;;;79292:3;89139:15;;89124:12;:30;;;;:::i;:::-;89123:42;;;;:::i;:::-;89105:60;-1:-1:-1;89179:31:0;89105:60;89179:31;;:::i;:::-;;;89066:222;89333:20;89356:973;89401:918;;;;;;;;89461:13;89401:918;;;;;;89506:6;:17;;;89401:918;;;;;;89555:6;:13;;;-1:-1:-1;;;;;89401:918:0;;;;;89601:6;:9;;;-1:-1:-1;;;;;89401:918:0;;;;;89641:6;:18;;;-1:-1:-1;;;;;89401:918:0;;;;;89688:6;:16;;;-1:-1:-1;;;;;89401:918:0;;;;;89736:12;89401:918;;;;89778:6;:17;;;89401:918;;;;89830:15;89401:918;;;;89873:6;:15;;;89401:918;;;;89913:12;:27;89926:6;:13;;;-1:-1:-1;;;;;89913:27:0;-1:-1:-1;;;;;89913:27:0;;;;;;;;;;;;;:29;;;;;;;;;:::i;:::-;;;;-1:-1:-1;89401:918:0;;90015:21;;-1:-1:-1;;;;;89401:918:0;;;;;;;;;;;;90243:18;;;;89401:918;;;;;90288:16;;;;89401:918;;;89356:31;:973::i;:::-;90363:18;;;;;;;;;;90339:21;90502:30;;;:15;:30;;;;;;;:62;;90619:17;;90574:62;;;;;;;;;;;;;90542:22;90574:62;;;;90732:13;;;;90846:18;;;;;90889:16;;;;90971:17;;;;91016:18;;;;90652:398;;90363:18;;-1:-1:-1;90363:18:0;;-1:-1:-1;;;;;90652:398:0;;;;90363:18;;90652:398;;;;90363:18;;90619:17;;90846:18;90933:12;;90971:17;;91016:23;;;;90652:398;:::i;:::-;;;;;;;;91084:13;91065:51;91099:8;:16;;;91065:51;;;;;;:::i;:::-;;;;;;;;88271:2852;;;;;88180:2943;;:::o;83273:158::-;83383:41;83399:7;;83420:1;83383:5;:41::i;77996:131::-;78067:7;78093:18;;;:12;:18;;;;;:27;;:25;:27::i;71326:138::-;70559:7;70585:12;;;;;;;;;;:22;;;69148:16;69159:4;69148:10;:16::i;:::-;71431:26:::1;71443:4;71449:7;71431:11;:26::i;69249:202::-:0;69334:4;69357:47;;;69372:32;69357:47;;:87;;-1:-1:-1;49585:25:0;49570:40;;;;69408:36;49471:146;69883:103;69949:30;69960:4;23872:10;69949;:30::i;74161:653::-;74336:4;-1:-1:-1;;;;;74322:19:0;;;74318:32;;74161:653;;;:::o;74318:32::-;74422:5;74431:1;74422:10;74418:23;;74161:653;;;:::o;74418:23::-;74454:20;-1:-1:-1;;;;;74454:20:0;;;74450:358;;74634:12;74651:2;-1:-1:-1;;;;;74651:7:0;74666:5;74651:25;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;74633:43;;;74698:7;74690:39;;;;;;;28070:2:1;74690:39:0;;;28052:21:1;28109:2;28089:18;;;28082:30;28148:21;28128:18;;;28121:49;28187:18;;74690:39:0;27868:343:1;74450:358:0;74760:37;-1:-1:-1;;;;;74760:26:0;;74787:2;74791:5;74760:26;:37::i;78229:257::-;78315:4;78331:12;78346:31;78363:4;78369:7;78346:16;:31::i;:::-;78331:46;;78391:7;78387:69;;;78414:18;;;;:12;:18;;;;;:31;;78437:7;78414:22;:31::i;78589:262::-;78676:4;78692:12;78707:32;78725:4;78731:7;78707:17;:32::i;:::-;78692:47;;78753:7;78749:72;;;78776:18;;;;:12;:18;;;;;:34;;78802:7;78776:25;:34::i;46921:556::-;47059:17;;:21;47055:416;;47300:10;47294:17;47356:15;47343:10;47339:2;47335:19;47328:44;47055:416;47423:37;;;;;;;;;;;;;;52055:469;51674:3;52207:34;;52203:86;;;52250:39;;;;;;;;;;;;;;52203:86;55321:30;;55316:3;55312:40;49774:1;52440:19;;52436:81;;52468:49;;;;;28390:6:1;28378:19;;52468:49:0;;;28360:38:1;28333:18;;52468:49:0;28216:188:1;18404:331:0;18513:6;18489:21;:30;18485:109;;;18542:41;;;;;18577:4;18542:41;;;2867:74:1;2840:18;;18542:41:0;2721:226:1;18485:109:0;18605:12;18623:9;-1:-1:-1;;;;;18623:14:0;18645:6;18623:33;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;18604:52;;;18671:7;18666:63;;18701:17;;;;;;;;;;;;;;62366:160;62475:43;;-1:-1:-1;;;;;20205:55:1;;;62475:43:0;;;20187:74:1;20277:18;;;20270:34;;;62448:71:0;;62468:5;;62490:14;;;;;20160:18:1;;62475:43:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;62448:19;:71::i;54018:990::-;54109:49;-1:-1:-1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;54109:49:0;55743:22;55721:45;;55708:59;55703:3;55699:69;;;54174:49;;56158:20;56136:43;;56123:57;56114:67;;54233:20;;;:45;56567:20;56545:43;;56532:57;56528:2;56524:66;;;54288:21;;;:47;56987:21;56965:44;;56952:58;56944:67;;54345:22;;;:49;57393:19;57371:42;;57358:56;57350:65;;54404:20;;;:45;57796:17;57774:40;;57761:54;57753:63;;54459:18;;;:41;58183:20;58161:43;;58148:57;54510:21;;;:47;58571:18;58549:41;;58536:55;54567:19;;;:43;;;;58971:24;58949:47;;58936:61;54620:24;;;:53;59347:15;59325:38;;59312:52;54683:17;;;:39;59702:12;59680:35;;59667:49;54732:14;;;:33;60126:26;60104:49;;60091:63;60083:72;;54775:27;;;:59;60547:27;60525:50;;60512:64;54844:27;;;:59;60939:17;60917:40;;60904:54;54913:18;;;:41;54983:18;55721:45;54991:9;54983:7;:18::i;:::-;54964:37;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;54964:16:0;;;:37;:8;54018:990;-1:-1:-1;;54018:990:0:o;34575:156::-;34649:7;34699:22;34703:3;34715:5;34699:3;:22::i;102800:808::-;-1:-1:-1;;;;;102922:21:0;;102918:47;;102952:13;;;;;;;;;;;;;;102918:47;97923:4;97994:33;;;:18;:33;;;;;:41;;;;-1:-1:-1;;;;;97994:41:0;:55;103036:60;;103076:20;;;;;;;;;;;;;;103036:60;56158:20;56136:43;;56123:57;56118:3;56114:67;103135:13;103110:38;103106:67;;103157:16;;;;;;;;;;;;;;103106:67;59347:15;59325:38;;59312:52;103237:15;:36;103233:67;;;103282:18;;;;;;;;;;;;;;103233:67;60126:26;60104:49;;60091:63;60087:2;60083:72;103438:25;;;;;:51;;;103482:7;-1:-1:-1;;;;;103467:22:0;:11;-1:-1:-1;;;;;103467:22:0;;;103438:51;:102;;;;-1:-1:-1;60547:27:0;60525:50;;60512:64;103493:15;:47;;103438:102;103434:168;;;103563:28;;;;;;;;;;;;;;103434:168;102908:700;102800:808;;;;:::o;62765:188::-;62892:53;;-1:-1:-1;;;;;18522:15:1;;;62892:53:0;;;18504:34:1;18574:15;;;18554:18;;;18547:43;18606:18;;;18599:34;;;62865:81:0;;62885:5;;62907:18;;;;;18416::1;;62892:53:0;18241:398:1;61050:146:0;61116:23;;61162:27;:9;51674:3;61162:9;;:27;:::i;:::-;61151:38;;;;61050:146;;;;;:::o;99649:951::-;99844:23;99870:255;99922:9;99986:5;99993:6;100001:7;;99951:59;;;;;;;;;;;:::i;:::-;;;;-1:-1:-1;;99951:59:0;;;;;;;;;;;;;;;;;;;;100105:9;99870:29;:255::i;:::-;99844:281;;100191:10;:17;100212:1;100191:22;100187:59;;100222:24;;;;;;;;;;;;;;100187:59;100325:10;:17;100346:2;100325:23;100321:67;;100357:31;;;;;;;;;;;;;;100321:67;100502:26;100471:19;100479:10;100471:19;:::i;:::-;:58;100467:127;;100552:31;;;;;;;;;;;;;;100467:127;99763:837;99649:951;;;;;:::o;101579:1142::-;101832:13;101811:6;:17;;;:34;;;101807:63;;101854:16;;;;;;;;;;;;;;101807:63;101884:19;;;;:24;;:50;;-1:-1:-1;101912:17:0;;;;:22;101884:50;101880:80;;;101943:17;;;;;;;;;;;;;;101880:80;101974:13;;;;-1:-1:-1;;;;;101974:27:0;;;:54;;-1:-1:-1;102005:9:0;;;;-1:-1:-1;;;;;102005:23:0;;101974:54;101970:80;;;102037:13;;;;;;;;;;;;;;101970:80;102064:18;;;;-1:-1:-1;;;;;102064:32:0;;;:66;;-1:-1:-1;102100:16:0;;;;-1:-1:-1;;;;;102100:30:0;;102064:66;102060:92;;;102139:13;;;;;;;;;;;;;;102060:92;102184:37;81578:10;102184:15;:37;:::i;:::-;102166:6;:15;;;:55;102162:86;;;102230:18;;;;;;;;;;;;;;102162:86;81692:11;102289:8;:16;;;:23;:45;102285:81;;;102343:23;;;;;;;;;;;;;;102285:81;102380:18;;;;:23;;;;:63;;-1:-1:-1;102407:16:0;;;;-1:-1:-1;;;;;102407:36:0;81148:42;102407:36;102380:63;102376:124;;;102466:23;;;;;;;;;;;;;;102376:124;102604:1;102583:18;:22;:70;;;;102637:6;:15;;;102609:18;:44;102583:70;102579:136;;;102676:28;;;;;;;;;;;;;;98309:1185;98389:19;98424:25;-1:-1:-1;;;;;98424:25:0;;;98420:1068;;98654:9;98644:6;:19;98640:51;;98672:19;;;;;;;;;;;;;;98640:51;-1:-1:-1;98719:9:0;98420:1068;;;98959:9;:14;98955:46;;98982:19;;;;;;;;;;;;;;98955:46;99106:5;-1:-1:-1;;;;;99106:17:0;;99127:1;99106:22;99102:53;;99137:18;;;;;;;;;;;;;;99102:53;99183:38;;;;;99215:4;99183:38;;;2867:74:1;-1:-1:-1;;;;;99183:23:0;;;;;2840:18:1;;99183:38:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;99169:52;-1:-1:-1;99235:65:0;-1:-1:-1;;;;;99235:30:0;;99266:10;99286:4;99293:6;99235:30;:65::i;:::-;99425:38;;;;;99457:4;99425:38;;;2867:74:1;99466:11:0;;-1:-1:-1;;;;;99425:23:0;;;;;2840:18:1;;99425:38:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;:52;;;;:::i;52732:1038::-;53002:22;;53038:20;;;;;53072:21;;;;;52824:12;53107:22;;;;53143:20;;;;53177:18;;;;53209:21;;;;52951:289;;30071:16:1;52951:289:0;;;30055:102:1;;;;30176:66;30279:3;30275:16;;;30271:25;;30258:11;;;30251:46;30330:16;;;;30326:25;;;30313:11;;;30306:46;30371:66;30471:15;;;30467:24;;30453:12;;;30446:46;30526:15;;30522:24;;30508:12;;;30501:46;30581:15;;;30577:24;;30563:12;;;30556:46;30636:15;;;30632:24;;;30618:12;;;30611:46;30673:12;;;30666:28;;;;52926:22:0;;30710:13:1;;52951:289:0;;;-1:-1:-1;;52951:289:0;;;;;;;;;;53310:19;;;;53343:24;;;;53488:17;;;;53519:14;;;;53589:27;;;;53630;;;;53705:18;;;;53737:16;;;;52951:289;;-1:-1:-1;53257:506:0;;52951:289;;53737:16;52951:289;53257:506;;:::i;:::-;;;;;;;;;;;;;53250:513;;;52732:1038;;;:::o;34118:115::-;34181:7;34207:19;34215:3;29557:18;;29475:107;70116:197;69615:4;69638:12;;;;;;;;;;;-1:-1:-1;;;;;69638:29:0;;;;;;;;;;;;70199:108;;70249:47;;;;;-1:-1:-1;;;;;20205:55:1;;70249:47:0;;;20187:74:1;20277:18;;;20270:34;;;20160:18;;70249:47:0;20013:297:1;72863:316:0;72940:4;69638:12;;;;;;;;;;;-1:-1:-1;;;;;69638:29:0;;;;;;;;;;;;72956:217;;72999:6;:12;;;;;;;;;;;-1:-1:-1;;;;;72999:29:0;;;;;;;;;:36;;;;73031:4;72999:36;;;73081:12;23872:10;;23793:96;73081:12;-1:-1:-1;;;;;73054:40:0;73072:7;-1:-1:-1;;;;;73054:40:0;73066:4;73054:40;;;;;;;;;;-1:-1:-1;73115:4:0;73108:11;;72956:217;-1:-1:-1;73157:5:0;73150:12;;33317:150;33387:4;33410:50;33415:3;-1:-1:-1;;;;;33435:23:0;;33410:4;:50::i;73414:317::-;73492:4;69638:12;;;;;;;;;;;-1:-1:-1;;;;;69638:29:0;;;;;;;;;;;;73508:217;;;73582:5;73550:12;;;;;;;;;;;-1:-1:-1;;;;;73550:29:0;;;;;;;;;;:37;;;;;;73606:40;23872:10;;73550:12;;73606:40;;73582:5;73606:40;-1:-1:-1;73667:4:0;73660:11;;33635:156;33708:4;33731:53;33739:3;-1:-1:-1;;;;;33759:23:0;;33731:7;:53::i;65122:629::-;65541:23;65567:33;-1:-1:-1;;;;;65567:27:0;;65595:4;65567:27;:33::i;:::-;65541:59;;65614:10;:17;65635:1;65614:22;;:57;;;;;65652:10;65641:30;;;;;;;;;;;;:::i;:::-;65640:31;65614:57;65610:135;;;65694:40;;;;;-1:-1:-1;;;;;2885:55:1;;65694:40:0;;;2867:74:1;2840:18;;65694:40:0;2721:226:1;29924:118:0;29991:7;30017:3;:11;;30029:5;30017:18;;;;;;;;:::i;:::-;;;;;;;;;30010:25;;29924:118;;;;:::o;20053:392::-;20152:12;20204:5;20180:21;:29;20176:108;;;20232:41;;;;;20267:4;20232:41;;;2867:74:1;2840:18;;20232:41:0;2721:226:1;20176:108:0;20294:12;20308:23;20335:6;-1:-1:-1;;;;;20335:11:0;20354:5;20361:4;20335:31;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;20293:73;;;;20383:55;20410:6;20418:7;20427:10;20383:26;:55::i;:::-;20376:62;20053:392;-1:-1:-1;;;;;;20053:392:0:o;27242:406::-;27305:4;29361:21;;;:14;;;:21;;;;;;27321:321;;-1:-1:-1;27363:23:0;;;;;;;;:11;:23;;;;;;;;;;;;;27545:18;;27521:21;;;:14;;;:21;;;;;;:42;;;;27577:11;;27816:1368;27882:4;28011:21;;;:14;;;:21;;;;;;28047:13;;28043:1135;;28414:18;28435:12;28446:1;28435:8;:12;:::i;:::-;28481:18;;28414:33;;-1:-1:-1;28461:17:0;;28481:22;;28502:1;;28481:22;:::i;:::-;28461:42;;28536:9;28522:10;:23;28518:378;;28565:17;28585:3;:11;;28597:9;28585:22;;;;;;;;:::i;:::-;;;;;;;;;28565:42;;28732:9;28706:3;:11;;28718:10;28706:23;;;;;;;;:::i;:::-;;;;;;;;;;;;:35;;;;28845:25;;;:14;;;:25;;;;;:36;;;28518:378;28974:17;;:3;;:17;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;29077:3;:14;;:21;29092:5;29077:21;;;;;;;;;;;29070:28;;;29120:4;29113:11;;;;;;;28043:1135;29162:5;29155:12;;;;;19578:151;19653:12;19684:38;19706:6;19714:4;19720:1;19684:21;:38::i;21498:582::-;21642:12;21671:7;21666:408;;21694:19;21702:10;21694:7;:19::i;:::-;21666:408;;;21918:17;;:22;:49;;;;-1:-1:-1;;;;;;21944:18:0;;;:23;21918:49;21914:119;;;21994:24;;;;;-1:-1:-1;;;;;2885:55:1;;21994:24:0;;;2867:74:1;2840:18;;21994:24:0;2721:226:1;21914:119:0;-1:-1:-1;22053:10:0;22046:17;;22616:516;22747:17;;:21;22743:383;;22975:10;22969:17;23031:15;23018:10;23014:2;23010:19;23003:44;22743:383;23098:17;;;;;;;;;;;;;;14:332:1;72:6;125:2;113:9;104:7;100:23;96:32;93:52;;;141:1;138;131:12;93:52;180:9;167:23;230:66;223:5;219:78;212:5;209:89;199:117;;312:1;309;302:12;821:180;880:6;933:2;921:9;912:7;908:23;904:32;901:52;;;949:1;946;939:12;901:52;-1:-1:-1;972:23:1;;821:180;-1:-1:-1;821:180:1:o;1006:184::-;1058:77;1055:1;1048:88;1155:4;1152:1;1145:15;1179:4;1176:1;1169:15;1195:297;1279:1;1272:5;1269:12;1259:200;;1315:77;1312:1;1305:88;1416:4;1413:1;1406:15;1444:4;1441:1;1434:15;1259:200;1468:18;;1195:297::o;1497:214::-;1646:2;1631:18;;1658:47;1635:9;1687:6;1658:47;:::i;1716:154::-;-1:-1:-1;;;;;1795:5:1;1791:54;1784:5;1781:65;1771:93;;1860:1;1857;1850:12;1875:134;1943:20;;1972:31;1943:20;1972:31;:::i;:::-;1875:134;;;:::o;2014:388::-;2082:6;2090;2143:2;2131:9;2122:7;2118:23;2114:32;2111:52;;;2159:1;2156;2149:12;2111:52;2198:9;2185:23;2217:31;2242:5;2217:31;:::i;:::-;2267:5;-1:-1:-1;2324:2:1;2309:18;;2296:32;2337:33;2296:32;2337:33;:::i;:::-;2389:7;2379:17;;;2014:388;;;;;:::o;2952:383::-;3029:6;3037;3045;3098:2;3086:9;3077:7;3073:23;3069:32;3066:52;;;3114:1;3111;3104:12;3066:52;3150:9;3137:23;3127:33;;3207:2;3196:9;3192:18;3179:32;3169:42;;3261:2;3250:9;3246:18;3233:32;3274:31;3299:5;3274:31;:::i;:::-;3324:5;3314:15;;;2952:383;;;;;:::o;3340:247::-;3399:6;3452:2;3440:9;3431:7;3427:23;3423:32;3420:52;;;3468:1;3465;3458:12;3420:52;3507:9;3494:23;3526:31;3551:5;3526:31;:::i;3592:315::-;3660:6;3668;3721:2;3709:9;3700:7;3696:23;3692:32;3689:52;;;3737:1;3734;3727:12;3689:52;3773:9;3760:23;3750:33;;3833:2;3822:9;3818:18;3805:32;3846:31;3871:5;3846:31;:::i;3912:118::-;3998:5;3991:13;3984:21;3977:5;3974:32;3964:60;;4020:1;4017;4010:12;4035:128;4100:20;;4129:28;4100:20;4129:28;:::i;4168:761::-;4271:6;4279;4287;4340:2;4328:9;4319:7;4315:23;4311:32;4308:52;;;4356:1;4353;4346:12;4308:52;4396:9;4383:23;4425:18;4466:2;4458:6;4455:14;4452:34;;;4482:1;4479;4472:12;4452:34;4520:6;4509:9;4505:22;4495:32;;4565:7;4558:4;4554:2;4550:13;4546:27;4536:55;;4587:1;4584;4577:12;4536:55;4627:2;4614:16;4653:2;4645:6;4642:14;4639:34;;;4669:1;4666;4659:12;4639:34;4724:7;4717:4;4707:6;4704:1;4700:14;4696:2;4692:23;4688:34;4685:47;4682:67;;;4745:1;4742;4735:12;4682:67;4776:4;4768:13;;;;-1:-1:-1;4800:6:1;-1:-1:-1;;4841:20:1;;4828:34;4871:28;4828:34;4871:28;:::i;4934:250::-;5019:1;5029:113;5043:6;5040:1;5037:13;5029:113;;;5119:11;;;5113:18;5100:11;;;5093:39;5065:2;5058:10;5029:113;;;-1:-1:-1;;5176:1:1;5158:16;;5151:27;4934:250::o;5189:329::-;5230:3;5268:5;5262:12;5295:6;5290:3;5283:19;5311:76;5380:6;5373:4;5368:3;5364:14;5357:4;5350:5;5346:16;5311:76;:::i;:::-;5432:2;5420:15;-1:-1:-1;;5416:88:1;5407:98;;;;5507:4;5403:109;;5189:329;-1:-1:-1;;5189:329:1:o;5523:1097::-;5711:4;5740:2;5780;5769:9;5765:18;5810:2;5799:9;5792:21;5833:6;5868;5862:13;5899:6;5891;5884:22;5925:2;5915:12;;5958:2;5947:9;5943:18;5936:25;;6020:2;6010:6;6007:1;6003:14;5992:9;5988:30;5984:39;6058:2;6050:6;6046:15;6079:1;6089:502;6103:6;6100:1;6097:13;6089:502;;;6168:22;;;6192:66;6164:95;6152:108;;6283:13;;6338:9;;6331:17;6324:25;6309:41;;6389:11;;6383:18;6421:15;;;6414:27;;;6464:47;6495:15;;;6383:18;6464:47;:::i;:::-;6569:12;;;;6454:57;-1:-1:-1;;6534:15:1;;;;6125:1;6118:9;6089:502;;;-1:-1:-1;6608:6:1;;5523:1097;-1:-1:-1;;;;;;;;5523:1097:1:o;6625:347::-;6676:8;6686:6;6740:3;6733:4;6725:6;6721:17;6717:27;6707:55;;6758:1;6755;6748:12;6707:55;-1:-1:-1;6781:20:1;;6824:18;6813:30;;6810:50;;;6856:1;6853;6846:12;6810:50;6893:4;6885:6;6881:17;6869:29;;6945:3;6938:4;6929:6;6921;6917:19;6913:30;6910:39;6907:59;;;6962:1;6959;6952:12;6907:59;6625:347;;;;;:::o;6977:544::-;7056:6;7064;7072;7125:2;7113:9;7104:7;7100:23;7096:32;7093:52;;;7141:1;7138;7131:12;7093:52;7181:9;7168:23;7214:18;7206:6;7203:30;7200:50;;;7246:1;7243;7236:12;7200:50;7285:58;7335:7;7326:6;7315:9;7311:22;7285:58;:::i;:::-;7362:8;;-1:-1:-1;7259:84:1;-1:-1:-1;;7447:2:1;7432:18;;7419:32;7460:31;7419:32;7460:31;:::i;7526:184::-;7578:77;7575:1;7568:88;7675:4;7672:1;7665:15;7699:4;7696:1;7689:15;7715:255;7787:2;7781:9;7829:6;7817:19;;7866:18;7851:34;;7887:22;;;7848:62;7845:88;;;7913:18;;:::i;:::-;7949:2;7942:22;7715:255;:::o;7975:253::-;8047:2;8041:9;8089:4;8077:17;;8124:18;8109:34;;8145:22;;;8106:62;8103:88;;;8171:18;;:::i;8233:255::-;8305:2;8299:9;8347:6;8335:19;;8384:18;8369:34;;8405:22;;;8366:62;8363:88;;;8431:18;;:::i;8493:252::-;8565:2;8559:9;8607:3;8595:16;;8641:18;8626:34;;8662:22;;;8623:62;8620:88;;;8688:18;;:::i;8750:334::-;8821:2;8815:9;8877:2;8867:13;;-1:-1:-1;;8863:86:1;8851:99;;8980:18;8965:34;;9001:22;;;8962:62;8959:88;;;9027:18;;:::i;:::-;9063:2;9056:22;8750:334;;-1:-1:-1;8750:334:1:o;9089:121::-;9174:10;9167:5;9163:22;9156:5;9153:33;9143:61;;9200:1;9197;9190:12;9215:132;9282:20;;9311:30;9282:20;9311:30;:::i;9352:806::-;9411:5;9459:6;9447:9;9442:3;9438:19;9434:32;9431:52;;;9479:1;9476;9469:12;9431:52;9501:22;;:::i;:::-;9492:31;;9546:28;9564:9;9546:28;:::i;:::-;9539:5;9532:43;9607:38;9641:2;9630:9;9626:18;9607:38;:::i;:::-;9602:2;9595:5;9591:14;9584:62;9678:38;9712:2;9701:9;9697:18;9678:38;:::i;:::-;9673:2;9666:5;9662:14;9655:62;9749:38;9783:2;9772:9;9768:18;9749:38;:::i;:::-;9744:2;9737:5;9733:14;9726:62;9821:39;9855:3;9844:9;9840:19;9821:39;:::i;:::-;9815:3;9808:5;9804:15;9797:64;9922:3;9911:9;9907:19;9894:33;9888:3;9881:5;9877:15;9870:58;9989:3;9978:9;9974:19;9961:33;9955:3;9948:5;9944:15;9937:58;10028:36;10059:3;10048:9;10044:19;10028:36;:::i;:::-;10022:3;10015:5;10011:15;10004:61;10084:3;10147:2;10136:9;10132:18;10119:32;10114:2;10107:5;10103:14;10096:56;;9352:806;;;;:::o;10163:237::-;10251:6;10304:3;10292:9;10283:7;10279:23;10275:33;10272:53;;;10321:1;10318;10311:12;10272:53;10344:50;10386:7;10375:9;10344:50;:::i;10405:409::-;10475:6;10483;10536:2;10524:9;10515:7;10511:23;10507:32;10504:52;;;10552:1;10549;10542:12;10504:52;10592:9;10579:23;10625:18;10617:6;10614:30;10611:50;;;10657:1;10654;10647:12;10611:50;10696:58;10746:7;10737:6;10726:9;10722:22;10696:58;:::i;:::-;10773:8;;10670:84;;-1:-1:-1;10405:409:1;-1:-1:-1;;;;10405:409:1:o;10918:1865::-;11121:2;11110:9;11103:21;11133:52;11181:2;11170:9;11166:18;11157:6;11151:13;10895:10;10884:22;10872:35;;10819:94;11133:52;11084:4;11232:2;11224:6;11220:15;11214:22;11245:51;11292:2;11281:9;11277:18;11263:12;10895:10;10884:22;10872:35;;10819:94;11245:51;-1:-1:-1;11345:2:1;11333:15;;11327:22;-1:-1:-1;;;;;2655:54:1;;11408:2;11393:18;;2643:67;-1:-1:-1;11461:2:1;11449:15;;11443:22;-1:-1:-1;;;;;2655:54:1;;11524:3;11509:19;;2643:67;-1:-1:-1;11578:3:1;11566:16;;11560:23;-1:-1:-1;;;;;2655:54:1;;11642:3;11627:19;;2643:67;-1:-1:-1;11696:3:1;11684:16;;11678:23;-1:-1:-1;;;;;2655:54:1;;11760:3;11745:19;;2643:67;-1:-1:-1;11820:3:1;11808:16;;11802:23;11796:3;11781:19;;;11774:52;;;;11851:16;;11845:23;11887:3;11906:18;;;11899:30;;;;11954:15;;11948:22;11989:3;12008:18;;;12001:30;;;;12056:15;;12050:22;12091:3;12110:18;;;12103:30;;;;12158:15;;12152:22;12193:3;12212:18;;;12205:30;;;;12272:15;;12266:22;12307:3;12319:54;12354:18;;;12266:22;-1:-1:-1;;;;;2655:54:1;2643:67;;2589:127;12319:54;12399:15;;12393:22;12435:3;12454:19;;;12447:32;;;;12505:16;;12499:23;12542:3;12561:19;;;12554:32;;;;12623:16;;12617:23;12660:6;12682:19;;;12675:32;12617:23;-1:-1:-1;12724:53:1;12772:3;12757:19;;12617:23;12724:53;:::i;:::-;12716:61;10918:1865;-1:-1:-1;;;;10918:1865:1:o;12788:513::-;13017:3;13002:19;;13030:47;13006:9;13059:6;13030:47;:::i;:::-;13125:10;13117:6;13113:23;13108:2;13097:9;13093:18;13086:51;13185:16;13177:6;13173:29;13168:2;13157:9;13153:18;13146:57;-1:-1:-1;;;;;13243:6:1;13239:55;13234:2;13223:9;13219:18;13212:83;12788:513;;;;;;;:::o;13306:477::-;13385:6;13393;13401;13454:2;13442:9;13433:7;13429:23;13425:32;13422:52;;;13470:1;13467;13460:12;13422:52;13510:9;13497:23;13543:18;13535:6;13532:30;13529:50;;;13575:1;13572;13565:12;13529:50;13614:58;13664:7;13655:6;13644:9;13640:22;13614:58;:::i;:::-;13691:8;;13588:84;;-1:-1:-1;13773:2:1;13758:18;;;;13745:32;;13306:477;-1:-1:-1;;;;13306:477:1:o;13788:248::-;13856:6;13864;13917:2;13905:9;13896:7;13892:23;13888:32;13885:52;;;13933:1;13930;13923:12;13885:52;-1:-1:-1;;13956:23:1;;;14026:2;14011:18;;;13998:32;;-1:-1:-1;13788:248:1:o;14374:1373::-;14605:13;;10895:10;10884:22;10872:35;;14574:3;14559:19;;14677:4;14669:6;14665:17;14659:24;14692:53;14739:4;14728:9;14724:20;14710:12;10895:10;10884:22;10872:35;;10819:94;14692:53;;14794:4;14786:6;14782:17;14776:24;14809:56;14859:4;14848:9;14844:20;14828:14;-1:-1:-1;;;;;2655:54:1;2643:67;;2589:127;14809:56;;14914:4;14906:6;14902:17;14896:24;14929:56;14979:4;14968:9;14964:20;14948:14;-1:-1:-1;;;;;2655:54:1;2643:67;;2589:127;14929:56;;15034:4;15026:6;15022:17;15016:24;15049:56;15099:4;15088:9;15084:20;15068:14;-1:-1:-1;;;;;2655:54:1;2643:67;;2589:127;15049:56;;15154:4;15146:6;15142:17;15136:24;15169:56;15219:4;15208:9;15204:20;15188:14;-1:-1:-1;;;;;2655:54:1;2643:67;;2589:127;15169:56;;15281:4;15273:6;15269:17;15263:24;15256:4;15245:9;15241:20;15234:54;15344:4;15336:6;15332:17;15326:24;15319:4;15308:9;15304:20;15297:54;15370:6;15430:2;15422:6;15418:15;15412:22;15407:2;15396:9;15392:18;15385:50;;15454:6;15509:2;15501:6;15497:15;15491:22;15522:51;15569:2;15558:9;15554:18;15538:14;421:13;414:21;402:34;;351:91;15522:51;-1:-1:-1;;15592:6:1;15640:15;;;15634:22;15614:18;;;15607:50;15676:6;15724:15;;;15718:22;15698:18;;;;15691:50;;;;14374:1373;:::o;15937:245::-;15985:4;16018:18;16010:6;16007:30;16004:56;;;16040:18;;:::i;:::-;-1:-1:-1;16097:2:1;16085:15;-1:-1:-1;;16081:88:1;16171:4;16077:99;;15937:245::o;16187:462::-;16229:5;16282:3;16275:4;16267:6;16263:17;16259:27;16249:55;;16300:1;16297;16290:12;16249:55;16336:6;16323:20;16367:48;16383:31;16411:2;16383:31;:::i;:::-;16367:48;:::i;:::-;16440:2;16431:7;16424:19;16486:3;16479:4;16474:2;16466:6;16462:15;16458:26;16455:35;16452:55;;;16503:1;16500;16493:12;16452:55;16568:2;16561:4;16553:6;16549:17;16542:4;16533:7;16529:18;16516:55;16616:1;16591:16;;;16609:4;16587:27;16580:38;;;;16595:7;16187:462;-1:-1:-1;;;16187:462:1:o;16654:1162::-;16783:6;16791;16844:3;16832:9;16823:7;16819:23;16815:33;16812:53;;;16861:1;16858;16851:12;16812:53;16884:50;16926:7;16915:9;16884:50;:::i;:::-;16874:60;;16985:3;16974:9;16970:19;16957:33;17009:18;17050:2;17042:6;17039:14;17036:34;;;17066:1;17063;17056:12;17036:34;17089:22;;;;17145:4;17127:16;;;17123:27;17120:47;;;17163:1;17160;17153:12;17120:47;17189:22;;:::i;:::-;17248:2;17235:16;17260:33;17285:7;17260:33;:::i;:::-;17302:22;;17377:2;17369:11;;;17356:25;17340:14;;;17333:49;17428:2;17420:11;;17407:25;17444:16;;;17441:36;;;17473:1;17470;17463:12;17441:36;17509:44;17545:7;17534:8;17530:2;17526:17;17509:44;:::i;:::-;17504:2;17497:5;17493:14;17486:68;;17607:2;17603;17599:11;17586:25;17581:2;17574:5;17570:14;17563:49;17658:3;17654:2;17650:12;17637:26;17688:2;17678:8;17675:16;17672:36;;;17704:1;17701;17694:12;17672:36;17741:44;17777:7;17766:8;17762:2;17758:17;17741:44;:::i;:::-;17735:3;17728:5;17724:15;17717:69;;17805:5;17795:15;;;;;16654:1162;;;;;:::o;18644:184::-;18696:77;18693:1;18686:88;18793:4;18790:1;18783:15;18817:4;18814:1;18807:15;18833:580;18910:4;18916:6;18976:11;18963:25;19066:66;19055:8;19039:14;19035:29;19031:102;19011:18;19007:127;18997:155;;19148:1;19145;19138:12;18997:155;19175:33;;19227:20;;;-1:-1:-1;19270:18:1;19259:30;;19256:50;;;19302:1;19299;19292:12;19256:50;19335:4;19323:17;;-1:-1:-1;19366:14:1;19362:27;;;19352:38;;19349:58;;;19403:1;19400;19393:12;19418:271;19601:6;19593;19588:3;19575:33;19557:3;19627:16;;19652:13;;;19627:16;19418:271;-1:-1:-1;19418:271:1:o;19694:184::-;19746:77;19743:1;19736:88;19843:4;19840:1;19833:15;19867:4;19864:1;19857:15;19883:125;19948:9;;;19969:10;;;19966:36;;;19982:18;;:::i;20949:325::-;21037:6;21032:3;21025:19;21089:6;21082:5;21075:4;21070:3;21066:14;21053:43;;21141:1;21134:4;21125:6;21120:3;21116:16;21112:27;21105:38;21007:3;21263:4;-1:-1:-1;;21188:2:1;21180:6;21176:15;21172:88;21167:3;21163:98;21159:109;21152:116;;20949:325;;;;:::o;21279:244::-;21436:2;21425:9;21418:21;21399:4;21456:61;21513:2;21502:9;21498:18;21490:6;21482;21456:61;:::i;21528:136::-;21606:13;;21628:30;21606:13;21628:30;:::i;21669:138::-;21748:13;;21770:31;21748:13;21770:31;:::i;21812:441::-;21865:5;21918:3;21911:4;21903:6;21899:17;21895:27;21885:55;;21936:1;21933;21926:12;21885:55;21965:6;21959:13;21996:48;22012:31;22040:2;22012:31;:::i;21996:48::-;22069:2;22060:7;22053:19;22115:3;22108:4;22103:2;22095:6;22091:15;22087:26;22084:35;22081:55;;;22132:1;22129;22122:12;22081:55;22145:77;22219:2;22212:4;22203:7;22199:18;22192:4;22184:6;22180:17;22145:77;:::i;22258:1672::-;22365:6;22418:2;22406:9;22397:7;22393:23;22389:32;22386:52;;;22434:1;22431;22424:12;22386:52;22467:9;22461:16;22496:18;22537:2;22529:6;22526:14;22523:34;;;22553:1;22550;22543:12;22523:34;22576:22;;;;22632:6;22614:16;;;22610:29;22607:49;;;22652:1;22649;22642:12;22607:49;22678:22;;:::i;:::-;22723:32;22752:2;22723:32;:::i;:::-;22716:5;22709:47;22788:41;22825:2;22821;22817:11;22788:41;:::i;:::-;22783:2;22776:5;22772:14;22765:65;22862:42;22900:2;22896;22892:11;22862:42;:::i;:::-;22857:2;22850:5;22846:14;22839:66;22937:42;22975:2;22971;22967:11;22937:42;:::i;:::-;22932:2;22925:5;22921:14;22914:66;23013:43;23051:3;23047:2;23043:12;23013:43;:::i;:::-;23007:3;23000:5;22996:15;22989:68;23090:43;23128:3;23124:2;23120:12;23090:43;:::i;:::-;23084:3;23073:15;;23066:68;23181:3;23173:12;;;23167:19;23150:15;;;23143:44;23234:3;23226:12;;;23220:19;23203:15;;;23196:44;23259:3;23300:11;;;23294:18;23278:14;;;23271:42;23332:3;23373:11;;;23367:18;23351:14;;;23344:42;23405:3;23446:11;;;23440:18;23424:14;;;23417:42;23478:3;23513:42;23543:11;;;23513:42;:::i;:::-;23497:14;;;23490:66;23575:3;23616:11;;;23610:18;23594:14;;;23587:42;23648:3;23689:11;;;23683:18;23667:14;;;23660:42;23721:3;23755:11;;;23749:18;23779:16;;;23776:36;;;23808:1;23805;23798:12;23776:36;23844:55;23891:7;23880:8;23876:2;23872:17;23844:55;:::i;:::-;23828:14;;;23821:79;;;;-1:-1:-1;23832:5:1;22258:1672;-1:-1:-1;;;;;22258:1672:1:o;23935:1135::-;24027:6;24080:3;24068:9;24059:7;24055:23;24051:33;24048:53;;;24097:1;24094;24087:12;24048:53;24123:22;;:::i;:::-;24168:28;24186:9;24168:28;:::i;:::-;24161:5;24154:43;24229:37;24262:2;24251:9;24247:18;24229:37;:::i;:::-;24224:2;24217:5;24213:14;24206:61;24299:38;24333:2;24322:9;24318:18;24299:38;:::i;:::-;24294:2;24287:5;24283:14;24276:62;24370:38;24404:2;24393:9;24389:18;24370:38;:::i;:::-;24365:2;24358:5;24354:14;24347:62;24442:39;24476:3;24465:9;24461:19;24442:39;:::i;:::-;24436:3;24429:5;24425:15;24418:64;24515:39;24549:3;24538:9;24534:19;24515:39;:::i;:::-;24509:3;24502:5;24498:15;24491:64;24616:3;24605:9;24601:19;24588:33;24582:3;24575:5;24571:15;24564:58;24683:3;24672:9;24668:19;24655:33;24649:3;24642:5;24638:15;24631:58;24708:3;24771:2;24760:9;24756:18;24743:32;24738:2;24731:5;24727:14;24720:56;;24795:3;24830:35;24861:2;24850:9;24846:18;24830:35;:::i;:::-;24814:14;;;24807:59;24885:3;24933:18;;;24920:32;24904:14;;;24897:56;24972:3;25020:18;;;25007:32;24991:14;;;24984:56;;;;-1:-1:-1;24818:5:1;23935:1135;-1:-1:-1;23935:1135:1:o;25673:216::-;25737:9;;;25765:11;;;25712:3;25795:9;;25823:10;;25819:19;;25848:10;;25840:19;;25816:44;25813:70;;;25863:18;;:::i;:::-;25813:70;;25673:216;;;;:::o;25894:168::-;25967:9;;;25998;;26015:15;;;26009:22;;25995:37;25985:71;;26036:18;;:::i;26067:274::-;26107:1;26133;26123:189;;26168:77;26165:1;26158:88;26269:4;26266:1;26259:15;26297:4;26294:1;26287:15;26123:189;-1:-1:-1;26326:9:1;;26067:274::o;26346:128::-;26413:9;;;26434:11;;;26431:37;;;26448:18;;:::i;26479:195::-;26518:3;26549:66;26542:5;26539:77;26536:103;;26619:18;;:::i;:::-;-1:-1:-1;26666:1:1;26655:13;;26479:195::o;26679:752::-;26986:3;26975:9;26968:22;26949:4;27007:45;27047:3;27036:9;27032:19;27024:6;27007:45;:::i;:::-;27100:10;27088:23;;;;27083:2;27068:18;;27061:51;-1:-1:-1;;;;;;27209:15:1;;;27204:2;27189:18;;27182:43;27261:15;;;;27256:2;27241:18;;27234:43;27308:3;27293:19;;27286:35;;;;27352:3;27337:19;;27330:35;27409:14;;27402:22;27396:3;27381:19;;;27374:51;26999:53;26679:752;-1:-1:-1;26679:752:1:o;27436:217::-;27583:2;27572:9;27565:21;27546:4;27603:44;27643:2;27632:9;27628:18;27620:6;27603:44;:::i;28409:331::-;28514:9;28525;28567:8;28555:10;28552:24;28549:44;;;28589:1;28586;28579:12;28549:44;28618:6;28608:8;28605:20;28602:40;;;28638:1;28635;28628:12;28602:40;-1:-1:-1;;28664:23:1;;;28709:25;;;;;-1:-1:-1;28409:331:1:o;28745:435::-;-1:-1:-1;;;;;28962:6:1;28958:55;28947:9;28940:74;29050:6;29045:2;29034:9;29030:18;29023:34;29093:2;29088;29077:9;29073:18;29066:30;28921:4;29113:61;29170:2;29159:9;29155:18;29147:6;29139;29113:61;:::i;29185:357::-;29303:12;;29350:4;29339:16;;;29333:23;;29303:12;29368:16;;29365:171;;;29458:66;29448:6;29442:4;29438:17;29435:1;29431:25;29427:98;29420:5;29416:110;29407:119;;29365:171;;29185:357;;;:::o;29547:184::-;29617:6;29670:2;29658:9;29649:7;29645:23;29641:32;29638:52;;;29686:1;29683;29676:12;29638:52;-1:-1:-1;29709:16:1;;29547:184;-1:-1:-1;29547:184:1:o;30734:1059::-;31105:3;31143:6;31137:13;31159:66;31218:6;31213:3;31206:4;31198:6;31194:17;31159:66;:::i;:::-;31256:6;31251:3;31247:16;31234:29;;31286:6;31279:5;31272:21;31327:6;31320:4;31313:5;31309:16;31302:32;31366:6;31361:2;31354:5;31350:14;31343:30;31405:6;31400:2;31393:5;31389:14;31382:30;31466:66;31457:6;31453:2;31449:15;31445:88;31439:3;31432:5;31428:15;31421:113;31567:6;31561:3;31554:5;31550:15;31543:31;31607:6;31601:3;31594:5;31590:15;31583:31;31645:6;31639:13;31661:80;31732:8;31726:3;31719:5;31715:15;31708:4;31700:6;31696:17;31661:80;:::i;:::-;31761:20;31783:3;31757:30;;30734:1059;-1:-1:-1;;;;;;;;;;;30734:1059:1:o;32100:245::-;32167:6;32220:2;32208:9;32199:7;32195:23;32191:32;32188:52;;;32236:1;32233;32226:12;32188:52;32268:9;32262:16;32287:28;32309:5;32287:28;:::i;32350:287::-;32479:3;32517:6;32511:13;32533:66;32592:6;32587:3;32580:4;32572:6;32568:17;32533:66;:::i;:::-;32615:16;;;;;32350:287;-1:-1:-1;;32350:287:1:o;32642:184::-;32694:77;32691:1;32684:88;32791:4;32788:1;32781:15;32815:4;32812:1;32805:15","abiDefinition":[{"inputs":[{"internalType":"address","name":"_owner","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AccessControlBadConfirmation","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"bytes32","name":"neededRole","type":"bytes32"}],"name":"AccessControlUnauthorizedAccount","type":"error"},{"inputs":[{"internalType":"address","name":"target","type":"address"}],"name":"AddressEmptyCode","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"AddressInsufficientBalance","type":"error"},{"inputs":[],"name":"AmountIncorrect","type":"error"},{"inputs":[],"name":"BridgeTransactionV2__InvalidEncodedTx","type":"error"},{"inputs":[{"internalType":"uint16","name":"version","type":"uint16"}],"name":"BridgeTransactionV2__UnsupportedVersion","type":"error"},{"inputs":[],"name":"ChainIncorrect","type":"error"},{"inputs":[],"name":"DeadlineExceeded","type":"error"},{"inputs":[],"name":"DeadlineNotExceeded","type":"error"},{"inputs":[],"name":"DeadlineTooShort","type":"error"},{"inputs":[],"name":"DisputePeriodNotPassed","type":"error"},{"inputs":[],"name":"DisputePeriodPassed","type":"error"},{"inputs":[],"name":"ExclusivityParamsIncorrect","type":"error"},{"inputs":[],"name":"ExclusivityPeriodNotPassed","type":"error"},{"inputs":[],"name":"FailedInnerCall","type":"error"},{"inputs":[],"name":"MsgValueIncorrect","type":"error"},{"inputs":[],"name":"MulticallTarget__UndeterminedRevert","type":"error"},{"inputs":[],"name":"RecipientIncorrectReturnValue","type":"error"},{"inputs":[],"name":"RecipientNoReturnValue","type":"error"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"SafeERC20FailedOperation","type":"error"},{"inputs":[],"name":"SenderIncorrect","type":"error"},{"inputs":[],"name":"StatusIncorrect","type":"error"},{"inputs":[],"name":"TokenNotContract","type":"error"},{"inputs":[],"name":"TransactionRelayed","type":"error"},{"inputs":[],"name":"ZapDataLengthAboveMax","type":"error"},{"inputs":[],"name":"ZapNativeNotSupported","type":"error"},{"inputs":[],"name":"ZeroAddress","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"relayer","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"BridgeDepositClaimed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"BridgeDepositRefunded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"relayer","type":"address"}],"name":"BridgeProofDisputed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"relayer","type":"address"},{"indexed":false,"internalType":"bytes32","name":"transactionHash","type":"bytes32"}],"name":"BridgeProofProvided","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":false,"internalType":"bytes","name":"quoteId","type":"bytes"}],"name":"BridgeQuoteDetails","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"relayer","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint32","name":"originChainId","type":"uint32"},{"indexed":false,"internalType":"address","name":"originToken","type":"address"},{"indexed":false,"internalType":"address","name":"destToken","type":"address"},{"indexed":false,"internalType":"uint256","name":"originAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"destAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"chainGasAmount","type":"uint256"}],"name":"BridgeRelayed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"bytes","name":"request","type":"bytes"},{"indexed":false,"internalType":"uint32","name":"destChainId","type":"uint32"},{"indexed":false,"internalType":"address","name":"originToken","type":"address"},{"indexed":false,"internalType":"address","name":"destToken","type":"address"},{"indexed":false,"internalType":"uint256","name":"originAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"destAmount","type":"uint256"},{"indexed":false,"internalType":"bool","name":"sendChainGas","type":"bool"}],"name":"BridgeRequested","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldChainGasAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newChainGasAmount","type":"uint256"}],"name":"ChainGasAmountUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldFeeRate","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newFeeRate","type":"uint256"}],"name":"FeeRateUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"address","name":"recipient","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"FeesSwept","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"previousAdminRole","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"newAdminRole","type":"bytes32"}],"name":"RoleAdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleRevoked","type":"event"},{"inputs":[],"name":"DEFAULT_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"DISPUTE_PERIOD","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"FEE_BPS","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"FEE_RATE_MAX","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"GOVERNOR_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"GUARD_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_ZAP_DATA_LENGTH","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MIN_DEADLINE_PERIOD","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"NATIVE_GAS_TOKEN","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"REFUNDER_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"REFUND_DELAY","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"RELAYER_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"uint32","name":"dstChainId","type":"uint32"},{"internalType":"address","name":"sender","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"address","name":"originToken","type":"address"},{"internalType":"address","name":"destToken","type":"address"},{"internalType":"uint256","name":"originAmount","type":"uint256"},{"internalType":"uint256","name":"destAmount","type":"uint256"},{"internalType":"bool","name":"sendChainGas","type":"bool"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"internalType":"struct IFastBridge.BridgeParams","name":"params","type":"tuple"}],"name":"bridge","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"uint32","name":"dstChainId","type":"uint32"},{"internalType":"address","name":"sender","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"address","name":"originToken","type":"address"},{"internalType":"address","name":"destToken","type":"address"},{"internalType":"uint256","name":"originAmount","type":"uint256"},{"internalType":"uint256","name":"destAmount","type":"uint256"},{"internalType":"bool","name":"sendChainGas","type":"bool"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"internalType":"struct IFastBridge.BridgeParams","name":"params","type":"tuple"},{"components":[{"internalType":"address","name":"quoteRelayer","type":"address"},{"internalType":"int256","name":"quoteExclusivitySeconds","type":"int256"},{"internalType":"bytes","name":"quoteId","type":"bytes"},{"internalType":"uint256","name":"zapNative","type":"uint256"},{"internalType":"bytes","name":"zapData","type":"bytes"}],"internalType":"struct IFastBridgeV2.BridgeParamsV2","name":"paramsV2","type":"tuple"}],"name":"bridge","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"transactionId","type":"bytes32"}],"name":"bridgeProofs","outputs":[{"internalType":"uint96","name":"timestamp","type":"uint96"},{"internalType":"address","name":"relayer","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"bridgeRelayDetails","outputs":[{"internalType":"uint48","name":"blockNumber","type":"uint48"},{"internalType":"uint48","name":"blockTimestamp","type":"uint48"},{"internalType":"address","name":"relayer","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"transactionId","type":"bytes32"}],"name":"bridgeRelays","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"transactionId","type":"bytes32"}],"name":"bridgeStatuses","outputs":[{"internalType":"enum IFastBridgeV2.BridgeStatus","name":"status","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"bridgeTxDetails","outputs":[{"internalType":"enum IFastBridgeV2.BridgeStatus","name":"status","type":"uint8"},{"internalType":"uint32","name":"destChainId","type":"uint32"},{"internalType":"uint56","name":"proofBlockTimestamp","type":"uint56"},{"internalType":"address","name":"proofRelayer","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"internalType":"address","name":"relayer","type":"address"}],"name":"canClaim","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"chainGasAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"},{"internalType":"address","name":"to","type":"address"}],"name":"claim","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"}],"name":"claim","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"deployBlock","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"transactionId","type":"bytes32"}],"name":"dispute","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"}],"name":"getBridgeTransaction","outputs":[{"components":[{"internalType":"uint32","name":"originChainId","type":"uint32"},{"internalType":"uint32","name":"destChainId","type":"uint32"},{"internalType":"address","name":"originSender","type":"address"},{"internalType":"address","name":"destRecipient","type":"address"},{"internalType":"address","name":"originToken","type":"address"},{"internalType":"address","name":"destToken","type":"address"},{"internalType":"uint256","name":"originAmount","type":"uint256"},{"internalType":"uint256","name":"destAmount","type":"uint256"},{"internalType":"uint256","name":"originFeeAmount","type":"uint256"},{"internalType":"bool","name":"sendChainGas","type":"bool"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint256","name":"nonce","type":"uint256"}],"internalType":"struct IFastBridge.BridgeTransaction","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"}],"name":"getBridgeTransactionV2","outputs":[{"components":[{"internalType":"uint32","name":"originChainId","type":"uint32"},{"internalType":"uint32","name":"destChainId","type":"uint32"},{"internalType":"address","name":"originSender","type":"address"},{"internalType":"address","name":"destRecipient","type":"address"},{"internalType":"address","name":"originToken","type":"address"},{"internalType":"address","name":"destToken","type":"address"},{"internalType":"uint256","name":"originAmount","type":"uint256"},{"internalType":"uint256","name":"destAmount","type":"uint256"},{"internalType":"uint256","name":"originFeeAmount","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"address","name":"exclusivityRelayer","type":"address"},{"internalType":"uint256","name":"exclusivityEndTime","type":"uint256"},{"internalType":"uint256","name":"zapNative","type":"uint256"},{"internalType":"bytes","name":"zapData","type":"bytes"}],"internalType":"struct IFastBridgeV2.BridgeTransactionV2","name":"","type":"tuple"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleAdmin","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"uint256","name":"index","type":"uint256"}],"name":"getRoleMember","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleMemberCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"grantRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"hasRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes[]","name":"data","type":"bytes[]"},{"internalType":"bool","name":"ignoreReverts","type":"bool"}],"name":"multicallNoResults","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes[]","name":"data","type":"bytes[]"},{"internalType":"bool","name":"ignoreReverts","type":"bool"}],"name":"multicallWithResults","outputs":[{"components":[{"internalType":"bool","name":"success","type":"bool"},{"internalType":"bytes","name":"returnData","type":"bytes"}],"internalType":"struct IMulticallTarget.Result[]","name":"results","type":"tuple[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"nonce","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"protocolFeeRate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"protocolFees","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"internalType":"bytes32","name":"destTxHash","type":"bytes32"},{"internalType":"address","name":"relayer","type":"address"}],"name":"prove","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"},{"internalType":"bytes32","name":"destTxHash","type":"bytes32"}],"name":"prove","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"}],"name":"refund","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"}],"name":"relay","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"},{"internalType":"address","name":"relayer","type":"address"}],"name":"relay","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"callerConfirmation","type":"address"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"revokeRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"senderNonces","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"newChainGasAmount","type":"uint256"}],"name":"setChainGasAmount","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"newFeeRate","type":"uint256"}],"name":"setProtocolFeeRate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"address","name":"recipient","type":"address"}],"name":"sweepProtocolFees","outputs":[],"stateMutability":"nonpayable","type":"function"}],"userDoc":{"kind":"user","methods":{"DISPUTE_PERIOD()":{"notice":"Dispute period for relayed transactions"},"MAX_ZAP_DATA_LENGTH()":{"notice":"Maximum length of accepted zapData"},"MIN_DEADLINE_PERIOD()":{"notice":"Minimum deadline period to relay a requested bridge transaction"},"NATIVE_GAS_TOKEN()":{"notice":"Address reserved for native gas token (ETH on Ethereum and most L2s, AVAX on Avalanche, etc)"},"REFUND_DELAY()":{"notice":"Delay for a transaction after which it could be permisionlessly refunded"},"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256))":{"notice":"Initiates bridge on origin chain to be relayed by off-chain relayer"},"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256),(address,int256,bytes,uint256,bytes))":{"notice":"Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability to provide temporary exclusivity fill rights for the quote relayer."},"bridgeProofs(bytes32)":{"notice":"Returns the timestamp and relayer of a bridge proof"},"bridgeRelayDetails(bytes32)":{"notice":"Relay details on destination chain"},"bridgeRelays(bytes32)":{"notice":"Checks if a transaction has been relayed"},"bridgeStatuses(bytes32)":{"notice":"Returns the status of a bridge transaction"},"bridgeTxDetails(bytes32)":{"notice":"Status of the bridge tx on origin chain"},"canClaim(bytes32,address)":{"notice":"Checks if the dispute period has passed so bridge deposit can be claimed"},"chainGasAmount()":{"notice":"Chain gas amount to forward as rebate if requested"},"claim(bytes)":{"notice":"Completes bridge transaction on origin chain by claiming originally deposited capital.Can only send funds to the relayer address on the proof."},"claim(bytes,address)":{"notice":"Completes bridge transaction on origin chain by claiming originally deposited capital"},"deployBlock()":{"notice":"the block the contract was deployed at"},"dispute(bytes32)":{"notice":"Disputes an outstanding proof in case relayer provided dest chain tx is invalid"},"getBridgeTransaction(bytes)":{"notice":"Decodes bridge request into a bridge transaction"},"getBridgeTransactionV2(bytes)":{"notice":"Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2"},"multicallNoResults(bytes[],bool)":{"notice":"Perform a batched call to this contract, preserving the msg.sender. The return data from each call is discarded."},"multicallWithResults(bytes[],bool)":{"notice":"Perform a batched call to this contract, preserving the msg.sender. The return data from each call is preserved."},"nonce()":{"notice":"This is deprecated and should not be used."},"protocolFeeRate()":{"notice":"Protocol fee rate taken on origin amount deposited in origin chain"},"protocolFees(address)":{"notice":"Protocol fee amounts accumulated"},"prove(bytes,bytes32)":{"notice":"Provides proof on origin side that relayer provided funds on destination side of bridge transaction"},"prove(bytes32,bytes32,address)":{"notice":"Provides proof on origin side that relayer provided funds on destination side of bridge transaction"},"refund(bytes)":{"notice":"Refunds an outstanding bridge transaction in case optimistic bridging failed"},"relay(bytes)":{"notice":"Relays destination side of bridge transaction by off-chain relayer"},"relay(bytes,address)":{"notice":"Relays destination side of bridge transaction by off-chain relayer"},"senderNonces(address)":{"notice":"Unique bridge nonces tracked per originSender"}},"notice":"FastBridgeV2 is a contract for bridging tokens across chains.","version":1},"developerDoc":{"errors":{"AccessControlBadConfirmation()":[{"details":"The caller of a function is not the expected one. NOTE: Don't confuse with {AccessControlUnauthorizedAccount}."}],"AccessControlUnauthorizedAccount(address,bytes32)":[{"details":"The `account` is missing a role."}],"AddressEmptyCode(address)":[{"details":"There's no code at `target` (it is not a contract)."}],"AddressInsufficientBalance(address)":[{"details":"The ETH balance of the account is not enough to perform the operation."}],"FailedInnerCall()":[{"details":"A call to an address target failed. The target may have reverted."}],"SafeERC20FailedOperation(address)":[{"details":"An operation with an ERC20 token failed."}]},"events":{"RoleAdminChanged(bytes32,bytes32,bytes32)":{"details":"Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole` `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite {RoleAdminChanged} not being emitted signaling this."},"RoleGranted(bytes32,address,address)":{"details":"Emitted when `account` is granted `role`. `sender` is the account that originated the contract call, an admin role bearer except when using {AccessControl-_setupRole}."},"RoleRevoked(bytes32,address,address)":{"details":"Emitted when `account` is revoked `role`. `sender` is the account that originated the contract call: - if using `revokeRole`, it is the admin role bearer - if using `renounceRole`, it is the role bearer (i.e. `account`)"}},"kind":"dev","methods":{"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256))":{"params":{"params":"The parameters required to bridge"}},"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256),(address,int256,bytes,uint256,bytes))":{"params":{"params":"The parameters required to bridge","paramsV2":"The parameters for exclusivity fill rights (optional, can be left empty)"}},"bridgeProofs(bytes32)":{"params":{"transactionId":"The ID of the bridge transaction"},"returns":{"relayer":"The relayer address of the bridge proof","timestamp":"The timestamp of the bridge proof"}},"bridgeRelays(bytes32)":{"params":{"transactionId":"The ID of the transaction to check"},"returns":{"_0":"True if the transaction has been relayed, false otherwise"}},"bridgeStatuses(bytes32)":{"params":{"transactionId":"The ID of the bridge transaction"},"returns":{"status":"BridgeStatus Status of the bridge transaction"}},"canClaim(bytes32,address)":{"params":{"relayer":"The address of the relayer attempting to claim","transactionId":"The transaction id associated with the encoded bridge transaction to check"}},"claim(bytes)":{"params":{"request":"The encoded bridge transaction to claim on origin chain"}},"claim(bytes,address)":{"params":{"request":"The encoded bridge transaction to claim on origin chain","to":"The recipient address of the funds"}},"dispute(bytes32)":{"params":{"transactionId":"The transaction id associated with the encoded bridge transaction to dispute"}},"getBridgeTransaction(bytes)":{"details":"This method is added to achieve backwards compatibility with decoding requests into V1 structs: - `zapNative` is partially reported as a zero/non-zero flag - `zapData` is ignored In order to process all kinds of requests use getBridgeTransactionV2 instead.","params":{"request":"The bridge request to decode"}},"getBridgeTransactionV2(bytes)":{"params":{"request":"The bridge request to decode"}},"getRoleAdmin(bytes32)":{"details":"Returns the admin role that controls `role`. See {grantRole} and {revokeRole}. To change a role's admin, use {_setRoleAdmin}."},"getRoleMember(bytes32,uint256)":{"details":"Returns one of the accounts that have `role`. `index` must be a value between 0 and {getRoleMemberCount}, non-inclusive. Role bearers are not sorted in any particular way, and their ordering may change at any point. WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure you perform all queries on the same block. See the following https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post] for more information."},"getRoleMemberCount(bytes32)":{"details":"Returns the number of accounts that have `role`. Can be used together with {getRoleMember} to enumerate all bearers of a role."},"grantRole(bytes32,address)":{"details":"Grants `role` to `account`. If `account` had not been already granted `role`, emits a {RoleGranted} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleGranted} event."},"hasRole(bytes32,address)":{"details":"Returns `true` if `account` has been granted `role`."},"multicallNoResults(bytes[],bool)":{"details":"The method is non-payable, so only calls with `msg.value == 0` could be batched. It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag. Otherwise, the whole batch call will be reverted with the original revert reason.","params":{"data":"List of abi-encoded calldata for the calls to perform.","ignoreReverts":"Whether to ignore the revert errors from the calls."}},"multicallWithResults(bytes[],bool)":{"details":"The method is non-payable, so only calls with `msg.value == 0` could be batched. It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag. Otherwise, the whole batch call will be reverted with the original revert reason.","params":{"data":"List of abi-encoded calldata for the calls to perform.","ignoreReverts":"Whether to ignore the revert errors from the calls."},"returns":{"results":" List of results from the calls: `(success, returnData)`."}},"prove(bytes,bytes32)":{"params":{"destTxHash":"The destination tx hash proving bridge transaction was relayed","request":"The encoded bridge transaction to prove on origin chain"}},"prove(bytes32,bytes32,address)":{"params":{"destTxHash":"The destination tx hash proving bridge transaction was relayed","relayer":"The address of the relaying entity which should have control of the origin funds when claimed","transactionId":"The transaction id associated with the encoded bridge transaction to prove"}},"refund(bytes)":{"params":{"request":"The encoded bridge transaction to refund"}},"relay(bytes)":{"params":{"request":"The encoded bridge transaction to relay on destination chain"}},"relay(bytes,address)":{"params":{"relayer":"The address of the relaying entity which should have control of the origin funds when claimed","request":"The encoded bridge transaction to relay on destination chain"}},"renounceRole(bytes32,address)":{"details":"Revokes `role` from the calling account. Roles are often managed via {grantRole} and {revokeRole}: this function's purpose is to provide a mechanism for accounts to lose their privileges if they are compromised (such as when a trusted device is misplaced). If the calling account had been revoked `role`, emits a {RoleRevoked} event. Requirements: - the caller must be `callerConfirmation`. May emit a {RoleRevoked} event."},"revokeRole(bytes32,address)":{"details":"Revokes `role` from `account`. If `account` had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleRevoked} event."},"supportsInterface(bytes4)":{"details":"See {IERC165-supportsInterface}."}},"stateVariables":{"nonce":{"details":"Replaced by senderNonces"}},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_owner\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"AccessControlBadConfirmation\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"neededRole\",\"type\":\"bytes32\"}],\"name\":\"AccessControlUnauthorizedAccount\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"}],\"name\":\"AddressEmptyCode\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"AddressInsufficientBalance\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"AmountIncorrect\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"BridgeTransactionV2__InvalidEncodedTx\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint16\",\"name\":\"version\",\"type\":\"uint16\"}],\"name\":\"BridgeTransactionV2__UnsupportedVersion\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ChainIncorrect\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DeadlineExceeded\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DeadlineNotExceeded\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DeadlineTooShort\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DisputePeriodNotPassed\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DisputePeriodPassed\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ExclusivityParamsIncorrect\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ExclusivityPeriodNotPassed\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"FailedInnerCall\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"MsgValueIncorrect\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"MulticallTarget__UndeterminedRevert\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"RecipientIncorrectReturnValue\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"RecipientNoReturnValue\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"}],\"name\":\"SafeERC20FailedOperation\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"SenderIncorrect\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"StatusIncorrect\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"TokenNotContract\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"TransactionRelayed\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ZapDataLengthAboveMax\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ZapNativeNotSupported\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ZeroAddress\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"BridgeDepositClaimed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"BridgeDepositRefunded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"name\":\"BridgeProofDisputed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"transactionHash\",\"type\":\"bytes32\"}],\"name\":\"BridgeProofProvided\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"quoteId\",\"type\":\"bytes\"}],\"name\":\"BridgeQuoteDetails\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"originChainId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"chainGasAmount\",\"type\":\"uint256\"}],\"name\":\"BridgeRelayed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"destChainId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"sendChainGas\",\"type\":\"bool\"}],\"name\":\"BridgeRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"oldChainGasAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newChainGasAmount\",\"type\":\"uint256\"}],\"name\":\"ChainGasAmountUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"oldFeeRate\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newFeeRate\",\"type\":\"uint256\"}],\"name\":\"FeeRateUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"FeesSwept\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"previousAdminRole\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"newAdminRole\",\"type\":\"bytes32\"}],\"name\":\"RoleAdminChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleGranted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleRevoked\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"DEFAULT_ADMIN_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"DISPUTE_PERIOD\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"FEE_BPS\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"FEE_RATE_MAX\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"GOVERNOR_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"GUARD_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"MAX_ZAP_DATA_LENGTH\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"MIN_DEADLINE_PERIOD\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"NATIVE_GAS_TOKEN\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"REFUNDER_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"REFUND_DELAY\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"RELAYER_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"dstChainId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"sendChainGas\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"}],\"internalType\":\"struct IFastBridge.BridgeParams\",\"name\":\"params\",\"type\":\"tuple\"}],\"name\":\"bridge\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"dstChainId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"sendChainGas\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"}],\"internalType\":\"struct IFastBridge.BridgeParams\",\"name\":\"params\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"quoteRelayer\",\"type\":\"address\"},{\"internalType\":\"int256\",\"name\":\"quoteExclusivitySeconds\",\"type\":\"int256\"},{\"internalType\":\"bytes\",\"name\":\"quoteId\",\"type\":\"bytes\"},{\"internalType\":\"uint256\",\"name\":\"zapNative\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"zapData\",\"type\":\"bytes\"}],\"internalType\":\"struct IFastBridgeV2.BridgeParamsV2\",\"name\":\"paramsV2\",\"type\":\"tuple\"}],\"name\":\"bridge\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"}],\"name\":\"bridgeProofs\",\"outputs\":[{\"internalType\":\"uint96\",\"name\":\"timestamp\",\"type\":\"uint96\"},{\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"bridgeRelayDetails\",\"outputs\":[{\"internalType\":\"uint48\",\"name\":\"blockNumber\",\"type\":\"uint48\"},{\"internalType\":\"uint48\",\"name\":\"blockTimestamp\",\"type\":\"uint48\"},{\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"}],\"name\":\"bridgeRelays\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"}],\"name\":\"bridgeStatuses\",\"outputs\":[{\"internalType\":\"enum IFastBridgeV2.BridgeStatus\",\"name\":\"status\",\"type\":\"uint8\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"bridgeTxDetails\",\"outputs\":[{\"internalType\":\"enum IFastBridgeV2.BridgeStatus\",\"name\":\"status\",\"type\":\"uint8\"},{\"internalType\":\"uint32\",\"name\":\"destChainId\",\"type\":\"uint32\"},{\"internalType\":\"uint56\",\"name\":\"proofBlockTimestamp\",\"type\":\"uint56\"},{\"internalType\":\"address\",\"name\":\"proofRelayer\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"name\":\"canClaim\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"chainGasAmount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"claim\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"claim\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"deployBlock\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"}],\"name\":\"dispute\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"getBridgeTransaction\",\"outputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"originChainId\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"destChainId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"originSender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destRecipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"originFeeAmount\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"sendChainGas\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"}],\"internalType\":\"struct IFastBridge.BridgeTransaction\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"getBridgeTransactionV2\",\"outputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"originChainId\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"destChainId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"originSender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destRecipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"originFeeAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"exclusivityRelayer\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"exclusivityEndTime\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"zapNative\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"zapData\",\"type\":\"bytes\"}],\"internalType\":\"struct IFastBridgeV2.BridgeTransactionV2\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"}],\"name\":\"getRoleAdmin\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"index\",\"type\":\"uint256\"}],\"name\":\"getRoleMember\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"}],\"name\":\"getRoleMemberCount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"grantRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"hasRole\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes[]\",\"name\":\"data\",\"type\":\"bytes[]\"},{\"internalType\":\"bool\",\"name\":\"ignoreReverts\",\"type\":\"bool\"}],\"name\":\"multicallNoResults\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes[]\",\"name\":\"data\",\"type\":\"bytes[]\"},{\"internalType\":\"bool\",\"name\":\"ignoreReverts\",\"type\":\"bool\"}],\"name\":\"multicallWithResults\",\"outputs\":[{\"components\":[{\"internalType\":\"bool\",\"name\":\"success\",\"type\":\"bool\"},{\"internalType\":\"bytes\",\"name\":\"returnData\",\"type\":\"bytes\"}],\"internalType\":\"struct IMulticallTarget.Result[]\",\"name\":\"results\",\"type\":\"tuple[]\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"nonce\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"protocolFeeRate\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"protocolFees\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"destTxHash\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"name\":\"prove\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"},{\"internalType\":\"bytes32\",\"name\":\"destTxHash\",\"type\":\"bytes32\"}],\"name\":\"prove\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"refund\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"relay\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"},{\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"name\":\"relay\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"callerConfirmation\",\"type\":\"address\"}],\"name\":\"renounceRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"revokeRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"senderNonces\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"newChainGasAmount\",\"type\":\"uint256\"}],\"name\":\"setChainGasAmount\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"newFeeRate\",\"type\":\"uint256\"}],\"name\":\"setProtocolFeeRate\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes4\",\"name\":\"interfaceId\",\"type\":\"bytes4\"}],\"name\":\"supportsInterface\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"}],\"name\":\"sweepProtocolFees\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"errors\":{\"AccessControlBadConfirmation()\":[{\"details\":\"The caller of a function is not the expected one. NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\"}],\"AccessControlUnauthorizedAccount(address,bytes32)\":[{\"details\":\"The `account` is missing a role.\"}],\"AddressEmptyCode(address)\":[{\"details\":\"There's no code at `target` (it is not a contract).\"}],\"AddressInsufficientBalance(address)\":[{\"details\":\"The ETH balance of the account is not enough to perform the operation.\"}],\"FailedInnerCall()\":[{\"details\":\"A call to an address target failed. The target may have reverted.\"}],\"SafeERC20FailedOperation(address)\":[{\"details\":\"An operation with an ERC20 token failed.\"}]},\"events\":{\"RoleAdminChanged(bytes32,bytes32,bytes32)\":{\"details\":\"Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole` `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite {RoleAdminChanged} not being emitted signaling this.\"},\"RoleGranted(bytes32,address,address)\":{\"details\":\"Emitted when `account` is granted `role`. `sender` is the account that originated the contract call, an admin role bearer except when using {AccessControl-_setupRole}.\"},\"RoleRevoked(bytes32,address,address)\":{\"details\":\"Emitted when `account` is revoked `role`. `sender` is the account that originated the contract call: - if using `revokeRole`, it is the admin role bearer - if using `renounceRole`, it is the role bearer (i.e. `account`)\"}},\"kind\":\"dev\",\"methods\":{\"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256))\":{\"params\":{\"params\":\"The parameters required to bridge\"}},\"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256),(address,int256,bytes,uint256,bytes))\":{\"params\":{\"params\":\"The parameters required to bridge\",\"paramsV2\":\"The parameters for exclusivity fill rights (optional, can be left empty)\"}},\"bridgeProofs(bytes32)\":{\"params\":{\"transactionId\":\"The ID of the bridge transaction\"},\"returns\":{\"relayer\":\"The relayer address of the bridge proof\",\"timestamp\":\"The timestamp of the bridge proof\"}},\"bridgeRelays(bytes32)\":{\"params\":{\"transactionId\":\"The ID of the transaction to check\"},\"returns\":{\"_0\":\"True if the transaction has been relayed, false otherwise\"}},\"bridgeStatuses(bytes32)\":{\"params\":{\"transactionId\":\"The ID of the bridge transaction\"},\"returns\":{\"status\":\"BridgeStatus Status of the bridge transaction\"}},\"canClaim(bytes32,address)\":{\"params\":{\"relayer\":\"The address of the relayer attempting to claim\",\"transactionId\":\"The transaction id associated with the encoded bridge transaction to check\"}},\"claim(bytes)\":{\"params\":{\"request\":\"The encoded bridge transaction to claim on origin chain\"}},\"claim(bytes,address)\":{\"params\":{\"request\":\"The encoded bridge transaction to claim on origin chain\",\"to\":\"The recipient address of the funds\"}},\"dispute(bytes32)\":{\"params\":{\"transactionId\":\"The transaction id associated with the encoded bridge transaction to dispute\"}},\"getBridgeTransaction(bytes)\":{\"details\":\"This method is added to achieve backwards compatibility with decoding requests into V1 structs: - `zapNative` is partially reported as a zero/non-zero flag - `zapData` is ignored In order to process all kinds of requests use getBridgeTransactionV2 instead.\",\"params\":{\"request\":\"The bridge request to decode\"}},\"getBridgeTransactionV2(bytes)\":{\"params\":{\"request\":\"The bridge request to decode\"}},\"getRoleAdmin(bytes32)\":{\"details\":\"Returns the admin role that controls `role`. See {grantRole} and {revokeRole}. To change a role's admin, use {_setRoleAdmin}.\"},\"getRoleMember(bytes32,uint256)\":{\"details\":\"Returns one of the accounts that have `role`. `index` must be a value between 0 and {getRoleMemberCount}, non-inclusive. Role bearers are not sorted in any particular way, and their ordering may change at any point. WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure you perform all queries on the same block. See the following https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post] for more information.\"},\"getRoleMemberCount(bytes32)\":{\"details\":\"Returns the number of accounts that have `role`. Can be used together with {getRoleMember} to enumerate all bearers of a role.\"},\"grantRole(bytes32,address)\":{\"details\":\"Grants `role` to `account`. If `account` had not been already granted `role`, emits a {RoleGranted} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleGranted} event.\"},\"hasRole(bytes32,address)\":{\"details\":\"Returns `true` if `account` has been granted `role`.\"},\"multicallNoResults(bytes[],bool)\":{\"details\":\"The method is non-payable, so only calls with `msg.value == 0` could be batched. It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag. Otherwise, the whole batch call will be reverted with the original revert reason.\",\"params\":{\"data\":\"List of abi-encoded calldata for the calls to perform.\",\"ignoreReverts\":\"Whether to ignore the revert errors from the calls.\"}},\"multicallWithResults(bytes[],bool)\":{\"details\":\"The method is non-payable, so only calls with `msg.value == 0` could be batched. It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag. Otherwise, the whole batch call will be reverted with the original revert reason.\",\"params\":{\"data\":\"List of abi-encoded calldata for the calls to perform.\",\"ignoreReverts\":\"Whether to ignore the revert errors from the calls.\"},\"returns\":{\"results\":\" List of results from the calls: `(success, returnData)`.\"}},\"prove(bytes,bytes32)\":{\"params\":{\"destTxHash\":\"The destination tx hash proving bridge transaction was relayed\",\"request\":\"The encoded bridge transaction to prove on origin chain\"}},\"prove(bytes32,bytes32,address)\":{\"params\":{\"destTxHash\":\"The destination tx hash proving bridge transaction was relayed\",\"relayer\":\"The address of the relaying entity which should have control of the origin funds when claimed\",\"transactionId\":\"The transaction id associated with the encoded bridge transaction to prove\"}},\"refund(bytes)\":{\"params\":{\"request\":\"The encoded bridge transaction to refund\"}},\"relay(bytes)\":{\"params\":{\"request\":\"The encoded bridge transaction to relay on destination chain\"}},\"relay(bytes,address)\":{\"params\":{\"relayer\":\"The address of the relaying entity which should have control of the origin funds when claimed\",\"request\":\"The encoded bridge transaction to relay on destination chain\"}},\"renounceRole(bytes32,address)\":{\"details\":\"Revokes `role` from the calling account. Roles are often managed via {grantRole} and {revokeRole}: this function's purpose is to provide a mechanism for accounts to lose their privileges if they are compromised (such as when a trusted device is misplaced). If the calling account had been revoked `role`, emits a {RoleRevoked} event. Requirements: - the caller must be `callerConfirmation`. May emit a {RoleRevoked} event.\"},\"revokeRole(bytes32,address)\":{\"details\":\"Revokes `role` from `account`. If `account` had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleRevoked} event.\"},\"supportsInterface(bytes4)\":{\"details\":\"See {IERC165-supportsInterface}.\"}},\"stateVariables\":{\"nonce\":{\"details\":\"Replaced by senderNonces\"}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"DISPUTE_PERIOD()\":{\"notice\":\"Dispute period for relayed transactions\"},\"MAX_ZAP_DATA_LENGTH()\":{\"notice\":\"Maximum length of accepted zapData\"},\"MIN_DEADLINE_PERIOD()\":{\"notice\":\"Minimum deadline period to relay a requested bridge transaction\"},\"NATIVE_GAS_TOKEN()\":{\"notice\":\"Address reserved for native gas token (ETH on Ethereum and most L2s, AVAX on Avalanche, etc)\"},\"REFUND_DELAY()\":{\"notice\":\"Delay for a transaction after which it could be permisionlessly refunded\"},\"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256))\":{\"notice\":\"Initiates bridge on origin chain to be relayed by off-chain relayer\"},\"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256),(address,int256,bytes,uint256,bytes))\":{\"notice\":\"Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability to provide temporary exclusivity fill rights for the quote relayer.\"},\"bridgeProofs(bytes32)\":{\"notice\":\"Returns the timestamp and relayer of a bridge proof\"},\"bridgeRelayDetails(bytes32)\":{\"notice\":\"Relay details on destination chain\"},\"bridgeRelays(bytes32)\":{\"notice\":\"Checks if a transaction has been relayed\"},\"bridgeStatuses(bytes32)\":{\"notice\":\"Returns the status of a bridge transaction\"},\"bridgeTxDetails(bytes32)\":{\"notice\":\"Status of the bridge tx on origin chain\"},\"canClaim(bytes32,address)\":{\"notice\":\"Checks if the dispute period has passed so bridge deposit can be claimed\"},\"chainGasAmount()\":{\"notice\":\"Chain gas amount to forward as rebate if requested\"},\"claim(bytes)\":{\"notice\":\"Completes bridge transaction on origin chain by claiming originally deposited capital.Can only send funds to the relayer address on the proof.\"},\"claim(bytes,address)\":{\"notice\":\"Completes bridge transaction on origin chain by claiming originally deposited capital\"},\"deployBlock()\":{\"notice\":\"the block the contract was deployed at\"},\"dispute(bytes32)\":{\"notice\":\"Disputes an outstanding proof in case relayer provided dest chain tx is invalid\"},\"getBridgeTransaction(bytes)\":{\"notice\":\"Decodes bridge request into a bridge transaction\"},\"getBridgeTransactionV2(bytes)\":{\"notice\":\"Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\"},\"multicallNoResults(bytes[],bool)\":{\"notice\":\"Perform a batched call to this contract, preserving the msg.sender. The return data from each call is discarded.\"},\"multicallWithResults(bytes[],bool)\":{\"notice\":\"Perform a batched call to this contract, preserving the msg.sender. The return data from each call is preserved.\"},\"nonce()\":{\"notice\":\"This is deprecated and should not be used.\"},\"protocolFeeRate()\":{\"notice\":\"Protocol fee rate taken on origin amount deposited in origin chain\"},\"protocolFees(address)\":{\"notice\":\"Protocol fee amounts accumulated\"},\"prove(bytes,bytes32)\":{\"notice\":\"Provides proof on origin side that relayer provided funds on destination side of bridge transaction\"},\"prove(bytes32,bytes32,address)\":{\"notice\":\"Provides proof on origin side that relayer provided funds on destination side of bridge transaction\"},\"refund(bytes)\":{\"notice\":\"Refunds an outstanding bridge transaction in case optimistic bridging failed\"},\"relay(bytes)\":{\"notice\":\"Relays destination side of bridge transaction by off-chain relayer\"},\"relay(bytes,address)\":{\"notice\":\"Relays destination side of bridge transaction by off-chain relayer\"},\"senderNonces(address)\":{\"notice\":\"Unique bridge nonces tracked per originSender\"}},\"notice\":\"FastBridgeV2 is a contract for bridging tokens across chains.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeV2.sol\":\"FastBridgeV2\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeV2.sol\":{\"keccak256\":\"0x5069b55ca07f21bfe30b2a43c18a18318c8af9c181b2dcb07c290825efd70f34\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://273dc020a49d08e50126bbea0d7f783f79d08c702f2fdbc560618d24af308acc\",\"dweb:/ipfs/QmXJ2UVzFc8EPB74RT4CXQPC4xw66jt4T13poyfyd3UERh\"]}},\"version\":1}"},"hashes":{"DEFAULT_ADMIN_ROLE()":"a217fddf","DISPUTE_PERIOD()":"a5bbe22b","FEE_BPS()":"bf333f2c","FEE_RATE_MAX()":"0f5f6ed7","GOVERNOR_ROLE()":"ccc57490","GUARD_ROLE()":"03ed0ee5","MAX_ZAP_DATA_LENGTH()":"54eff068","MIN_DEADLINE_PERIOD()":"820688d5","NATIVE_GAS_TOKEN()":"0f862f1e","REFUNDER_ROLE()":"5960ccf2","REFUND_DELAY()":"190da595","RELAYER_ROLE()":"926d7d7f","bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256))":"45851694","bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256),(address,int256,bytes,uint256,bytes))":"bfc7c607","bridgeProofs(bytes32)":"91ad5039","bridgeRelayDetails(bytes32)":"c79371b1","bridgeRelays(bytes32)":"8379a24f","bridgeStatuses(bytes32)":"051287bc","bridgeTxDetails(bytes32)":"63787e52","canClaim(bytes32,address)":"aa9641ab","chainGasAmount()":"e00a83e0","claim(bytes)":"c63ff8dd","claim(bytes,address)":"41fcb612","deployBlock()":"a3ec191a","dispute(bytes32)":"add98c70","getBridgeTransaction(bytes)":"ac11fb1a","getBridgeTransactionV2(bytes)":"5aa6ccba","getRoleAdmin(bytes32)":"248a9ca3","getRoleMember(bytes32,uint256)":"9010d07c","getRoleMemberCount(bytes32)":"ca15c873","grantRole(bytes32,address)":"2f2ff15d","hasRole(bytes32,address)":"91d14854","multicallNoResults(bytes[],bool)":"3f61331d","multicallWithResults(bytes[],bool)":"385c1d2f","nonce()":"affed0e0","protocolFeeRate()":"58f85880","protocolFees(address)":"dcf844a7","prove(bytes,bytes32)":"886d36ff","prove(bytes32,bytes32,address)":"18e4357d","refund(bytes)":"5eb7d946","relay(bytes)":"8f0d6f17","relay(bytes,address)":"9c9545f0","renounceRole(bytes32,address)":"36568abe","revokeRole(bytes32,address)":"d547741f","senderNonces(address)":"295710ff","setChainGasAmount(uint256)":"b250fe6b","setProtocolFeeRate(uint256)":"b13aa2d6","supportsInterface(bytes4)":"01ffc9a7","sweepProtocolFees(address,address)":"06f333f2"}},"solidity/FastBridgeV2.sol:IAccessControl":{"code":"0x","runtime-code":"0x","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.24 ^0.8.20 ^0.8.4;\n\n// contracts/interfaces/IAdmin.sol\n\ninterface IAdmin {\n // ============ Events ============\n\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n event ChainGasAmountUpdated(uint256 oldChainGasAmount, uint256 newChainGasAmount);\n\n // ============ Methods ============\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n\n function setChainGasAmount(uint256 newChainGasAmount) external;\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IFastBridgeV2Errors.sol\n\ninterface IFastBridgeV2Errors {\n error AmountIncorrect();\n error ChainIncorrect();\n error ExclusivityParamsIncorrect();\n error MsgValueIncorrect();\n error SenderIncorrect();\n error StatusIncorrect();\n error TokenNotContract();\n error ZapDataLengthAboveMax();\n error ZapNativeNotSupported();\n error ZeroAddress();\n\n error RecipientIncorrectReturnValue();\n error RecipientNoReturnValue();\n\n error DeadlineExceeded();\n error DeadlineNotExceeded();\n error DeadlineTooShort();\n error DisputePeriodNotPassed();\n error DisputePeriodPassed();\n error ExclusivityPeriodNotPassed();\n\n error TransactionRelayed();\n}\n\n// contracts/interfaces/IMulticallTarget.sol\n\n/// @notice Interface for a contract that can be called multiple times by the same caller. Inspired by MulticallV3:\n/// https://github.com/mds1/multicall/blob/master/src/Multicall3.sol\ninterface IMulticallTarget {\n struct Result {\n bool success;\n bytes returnData;\n }\n\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external;\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results);\n}\n\n// contracts/interfaces/IZapRecipient.sol\n\ninterface IZapRecipient {\n function zap(address token, uint256 amount, bytes memory zapData) external payable returns (bytes4);\n}\n\n// contracts/libs/Errors.sol\n\nerror DeadlineExceeded();\nerror DeadlineNotExceeded();\nerror DeadlineTooShort();\nerror InsufficientOutputAmount();\n\nerror MsgValueIncorrect();\nerror PoolNotFound();\nerror TokenAddressMismatch();\nerror TokenNotContract();\nerror TokenNotETH();\nerror TokensIdentical();\n\nerror ChainIncorrect();\nerror AmountIncorrect();\nerror ZeroAddress();\n\nerror DisputePeriodNotPassed();\nerror DisputePeriodPassed();\nerror SenderIncorrect();\nerror StatusIncorrect();\nerror TransactionIdIncorrect();\nerror TransactionRelayed();\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// contracts/interfaces/IFastBridgeV2.sol\n\ninterface IFastBridgeV2 is IFastBridge {\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n struct BridgeTxDetails {\n BridgeStatus status;\n uint32 destChainId;\n uint56 proofBlockTimestamp;\n address proofRelayer;\n }\n\n struct BridgeRelay {\n uint48 blockNumber;\n uint48 blockTimestamp;\n address relayer;\n }\n\n /// @notice New params introduced in the FastBridgeV2.\n /// We are passing fields from the older BridgeParams struct outside of this struct\n /// for backwards compatibility.\n /// Note: quoteRelayer and quoteExclusivitySeconds are either both zero (indicating no exclusivity)\n /// or both non-zero (indicating exclusivity for the given period).\n /// Note: zapNative \u003e 0 can NOT be used with destToken = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE (native token)\n /// @param quoteRelayer Relayer that provided the quote for the transaction\n /// @param quoteExclusivitySeconds Period of time the quote relayer is guaranteed exclusivity after user's deposit\n /// @param quoteId Unique quote identifier used for tracking the quote\n /// @param zapNative ETH value to send to the recipient (if any)\n /// @param zapData Parameters for the Zap to the destination recipient (if any)\n struct BridgeParamsV2 {\n address quoteRelayer;\n int256 quoteExclusivitySeconds;\n bytes quoteId;\n uint256 zapNative;\n bytes zapData;\n }\n\n /// @notice Updated bridge transaction struct to include parameters introduced in FastBridgeV2.\n /// Note: only `exclusivityRelayer` can fill such a transaction until `exclusivityEndTime`.\n struct BridgeTransactionV2 {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n // Note: sendChainGas flag from V1 is deprecated\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n address exclusivityRelayer;\n uint256 exclusivityEndTime;\n uint256 zapNative; // ETH value to send to the recipient (if any)\n bytes zapData; // data to pass for the Zap action (if any)\n }\n\n event BridgeQuoteDetails(bytes32 indexed transactionId, bytes quoteId);\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability\n /// to provide temporary exclusivity fill rights for the quote relayer.\n /// @param params The parameters required to bridge\n /// @param paramsV2 The parameters for exclusivity fill rights (optional, can be left empty)\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function relay(bytes memory request, address relayer) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param transactionId The transaction id associated with the encoded bridge transaction to prove\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital.\n /// @notice Can only send funds to the relayer address on the proof.\n /// @param request The encoded bridge transaction to claim on origin chain\n function claim(bytes memory request) external;\n /// @notice Checks if a transaction has been relayed\n /// @param transactionId The ID of the transaction to check\n /// @return True if the transaction has been relayed, false otherwise\n function bridgeRelays(bytes32 transactionId) external view returns (bool);\n\n /// @notice Returns the status of a bridge transaction\n /// @param transactionId The ID of the bridge transaction\n /// @return BridgeStatus Status of the bridge transaction\n function bridgeStatuses(bytes32 transactionId) external view returns (BridgeStatus);\n\n /// @notice Returns the timestamp and relayer of a bridge proof\n /// @param transactionId The ID of the bridge transaction\n /// @return timestamp The timestamp of the bridge proof\n /// @return relayer The relayer address of the bridge proof\n function bridgeProofs(bytes32 transactionId) external view returns (uint96 timestamp, address relayer);\n\n /// @notice Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\n /// @param request The bridge request to decode\n function getBridgeTransactionV2(bytes memory request) external view returns (BridgeTransactionV2 memory);\n}\n\n// contracts/utils/MulticallTarget.sol\n\n// solhint-disable avoid-low-level-calls\n/// @notice Template for a contract that supports batched calls (preserving the msg.sender).\n/// Only calls with zero msg.value could be batched.\nabstract contract MulticallTarget is IMulticallTarget {\n error MulticallTarget__UndeterminedRevert();\n\n /// @notice Perform a batched call to this contract, preserving the msg.sender.\n /// The return data from each call is discarded.\n /// @dev The method is non-payable, so only calls with `msg.value == 0` could be batched.\n /// It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag.\n /// Otherwise, the whole batch call will be reverted with the original revert reason.\n /// @param data List of abi-encoded calldata for the calls to perform.\n /// @param ignoreReverts Whether to ignore the revert errors from the calls.\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external {\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\n if (!success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(result);\n }\n }\n }\n\n /// @notice Perform a batched call to this contract, preserving the msg.sender.\n /// The return data from each call is preserved.\n /// @dev The method is non-payable, so only calls with `msg.value == 0` could be batched.\n /// It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag.\n /// Otherwise, the whole batch call will be reverted with the original revert reason.\n /// @param data List of abi-encoded calldata for the calls to perform.\n /// @param ignoreReverts Whether to ignore the revert errors from the calls.\n /// @return results List of results from the calls: `(success, returnData)`.\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results)\n {\n results = new Result[](data.length);\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (results[i].success, results[i].returnData) = address(this).delegatecall(data[i]);\n if (!results[i].success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(results[i].returnData);\n }\n }\n }\n\n /// @dev Bubbles the revert message from the underlying call.\n /// Note: preserves the same custom error or revert string, if one was used.\n /// Source: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v5.0.2/contracts/utils/Address.sol#L143-L158\n function _bubbleRevert(bytes memory returnData) internal pure {\n // Look for revert reason and bubble it up if present\n if (returnData.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n // solhint-disable-next-line no-inline-assembly\n assembly {\n let returndata_size := mload(returnData)\n revert(add(32, returnData), returndata_size)\n }\n } else {\n revert MulticallTarget__UndeterminedRevert();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// contracts/libs/BridgeTransactionV2.sol\n\n// solhint-disable no-inline-assembly\nlibrary BridgeTransactionV2Lib {\n uint16 internal constant VERSION = 2;\n\n // Offsets of the fields in the packed BridgeTransactionV2 struct\n // uint16 version [000 .. 002)\n // uint32 originChainId [002 .. 006)\n // uint32 destChainId [006 .. 010)\n // address originSender [010 .. 030)\n // address destRecipient [030 .. 050)\n // address originToken [050 .. 070)\n // address destToken [070 .. 090)\n // uint256 originAmount [090 .. 122)\n // uint256 destAmount [122 .. 154)\n // uint256 originFeeAmount [154 .. 186)\n // uint256 deadline [186 .. 218)\n // uint256 nonce [218 .. 250)\n // address exclusivityRelayer [250 .. 270)\n // uint256 exclusivityEndTime [270 .. 302)\n // uint256 zapNative [302 .. 334)\n // bytes zapData [334 .. ***)\n\n // forgefmt: disable-start\n uint256 private constant OFFSET_ORIGIN_CHAIN_ID = 2;\n uint256 private constant OFFSET_DEST_CHAIN_ID = 6;\n uint256 private constant OFFSET_ORIGIN_SENDER = 10;\n uint256 private constant OFFSET_DEST_RECIPIENT = 30;\n uint256 private constant OFFSET_ORIGIN_TOKEN = 50;\n uint256 private constant OFFSET_DEST_TOKEN = 70;\n uint256 private constant OFFSET_ORIGIN_AMOUNT = 90;\n uint256 private constant OFFSET_DEST_AMOUNT = 122;\n uint256 private constant OFFSET_ORIGIN_FEE_AMOUNT = 154;\n uint256 private constant OFFSET_DEADLINE = 186;\n uint256 private constant OFFSET_NONCE = 218;\n uint256 private constant OFFSET_EXCLUSIVITY_RELAYER = 250;\n uint256 private constant OFFSET_EXCLUSIVITY_END_TIME = 270;\n uint256 private constant OFFSET_ZAP_NATIVE = 302;\n uint256 private constant OFFSET_ZAP_DATA = 334;\n // forgefmt: disable-end\n\n error BridgeTransactionV2__InvalidEncodedTx();\n error BridgeTransactionV2__UnsupportedVersion(uint16 version);\n\n /// @notice Validates the encoded transaction to be a tightly packed encoded payload for BridgeTransactionV2.\n /// @dev Checks the minimum length and the version, use this function before decoding any of the fields.\n function validateV2(bytes calldata encodedTx) internal pure {\n // Check the minimum length: must at least include all static fields.\n if (encodedTx.length \u003c OFFSET_ZAP_DATA) revert BridgeTransactionV2__InvalidEncodedTx();\n // Once we validated the length, we can be sure that the version field is present.\n uint16 version_ = version(encodedTx);\n if (version_ != VERSION) revert BridgeTransactionV2__UnsupportedVersion(version_);\n }\n\n /// @notice Encodes the BridgeTransactionV2 struct by tightly packing the fields.\n /// @dev `abi.decode` will not work as a result of the tightly packed fields. Use `decodeV2` to decode instead.\n function encodeV2(IFastBridgeV2.BridgeTransactionV2 memory bridgeTx) internal pure returns (bytes memory) {\n // We split the encoding into two parts to avoid stack-too-deep error\n bytes memory firstPart = abi.encodePacked(\n VERSION,\n bridgeTx.originChainId,\n bridgeTx.destChainId,\n bridgeTx.originSender,\n bridgeTx.destRecipient,\n bridgeTx.originToken,\n bridgeTx.destToken,\n bridgeTx.originAmount\n );\n return abi.encodePacked(\n firstPart,\n bridgeTx.destAmount,\n bridgeTx.originFeeAmount,\n // Note: we skip the deprecated `sendChainGas` flag, which was present in BridgeTransaction V1\n bridgeTx.deadline,\n bridgeTx.nonce,\n // New V2 fields: exclusivity\n bridgeTx.exclusivityRelayer,\n bridgeTx.exclusivityEndTime,\n // New V2 fields: Zap\n bridgeTx.zapNative,\n bridgeTx.zapData\n );\n }\n\n /// @notice Decodes the BridgeTransactionV2 struct from the encoded transaction.\n /// @dev Encoded BridgeTransactionV2 struct must be tightly packed.\n /// Use `validateV2` before decoding to ensure the encoded transaction is valid.\n function decodeV2(bytes calldata encodedTx)\n internal\n pure\n returns (IFastBridgeV2.BridgeTransactionV2 memory bridgeTx)\n {\n bridgeTx.originChainId = originChainId(encodedTx);\n bridgeTx.destChainId = destChainId(encodedTx);\n bridgeTx.originSender = originSender(encodedTx);\n bridgeTx.destRecipient = destRecipient(encodedTx);\n bridgeTx.originToken = originToken(encodedTx);\n bridgeTx.destToken = destToken(encodedTx);\n bridgeTx.originAmount = originAmount(encodedTx);\n bridgeTx.destAmount = destAmount(encodedTx);\n bridgeTx.originFeeAmount = originFeeAmount(encodedTx);\n bridgeTx.deadline = deadline(encodedTx);\n bridgeTx.nonce = nonce(encodedTx);\n bridgeTx.exclusivityRelayer = exclusivityRelayer(encodedTx);\n bridgeTx.exclusivityEndTime = exclusivityEndTime(encodedTx);\n bridgeTx.zapNative = zapNative(encodedTx);\n bridgeTx.zapData = zapData(encodedTx);\n }\n\n /// @notice Extracts the version from the encoded transaction.\n function version(bytes calldata encodedTx) internal pure returns (uint16 version_) {\n // Load 32 bytes from the start and shift it 240 bits to the right to get the highest 16 bits.\n assembly {\n version_ := shr(240, calldataload(encodedTx.offset))\n }\n }\n\n /// @notice Extracts the origin chain ID from the encoded transaction.\n function originChainId(bytes calldata encodedTx) internal pure returns (uint32 originChainId_) {\n // Load 32 bytes from the offset and shift it 224 bits to the right to get the highest 32 bits.\n assembly {\n originChainId_ := shr(224, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_CHAIN_ID)))\n }\n }\n\n /// @notice Extracts the destination chain ID from the encoded transaction.\n function destChainId(bytes calldata encodedTx) internal pure returns (uint32 destChainId_) {\n // Load 32 bytes from the offset and shift it 224 bits to the right to get the highest 32 bits.\n assembly {\n destChainId_ := shr(224, calldataload(add(encodedTx.offset, OFFSET_DEST_CHAIN_ID)))\n }\n }\n\n /// @notice Extracts the origin sender from the encoded transaction.\n function originSender(bytes calldata encodedTx) internal pure returns (address originSender_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n originSender_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_SENDER)))\n }\n }\n\n /// @notice Extracts the destination recipient from the encoded transaction.\n function destRecipient(bytes calldata encodedTx) internal pure returns (address destRecipient_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n destRecipient_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_DEST_RECIPIENT)))\n }\n }\n\n /// @notice Extracts the origin token from the encoded transaction.\n function originToken(bytes calldata encodedTx) internal pure returns (address originToken_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n originToken_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_TOKEN)))\n }\n }\n\n /// @notice Extracts the destination token from the encoded transaction.\n function destToken(bytes calldata encodedTx) internal pure returns (address destToken_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n destToken_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_DEST_TOKEN)))\n }\n }\n\n /// @notice Extracts the origin amount from the encoded transaction.\n function originAmount(bytes calldata encodedTx) internal pure returns (uint256 originAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n originAmount_ := calldataload(add(encodedTx.offset, OFFSET_ORIGIN_AMOUNT))\n }\n }\n\n /// @notice Extracts the destination amount from the encoded transaction.\n function destAmount(bytes calldata encodedTx) internal pure returns (uint256 destAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n destAmount_ := calldataload(add(encodedTx.offset, OFFSET_DEST_AMOUNT))\n }\n }\n\n /// @notice Extracts the origin fee amount from the encoded transaction.\n function originFeeAmount(bytes calldata encodedTx) internal pure returns (uint256 originFeeAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n originFeeAmount_ := calldataload(add(encodedTx.offset, OFFSET_ORIGIN_FEE_AMOUNT))\n }\n }\n\n /// @notice Extracts the deadline from the encoded transaction.\n function deadline(bytes calldata encodedTx) internal pure returns (uint256 deadline_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n deadline_ := calldataload(add(encodedTx.offset, OFFSET_DEADLINE))\n }\n }\n\n /// @notice Extracts the nonce from the encoded transaction.\n function nonce(bytes calldata encodedTx) internal pure returns (uint256 nonce_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n nonce_ := calldataload(add(encodedTx.offset, OFFSET_NONCE))\n }\n }\n\n /// @notice Extracts the exclusivity relayer from the encoded transaction.\n function exclusivityRelayer(bytes calldata encodedTx) internal pure returns (address exclusivityRelayer_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n exclusivityRelayer_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_EXCLUSIVITY_RELAYER)))\n }\n }\n\n /// @notice Extracts the exclusivity end time from the encoded transaction.\n function exclusivityEndTime(bytes calldata encodedTx) internal pure returns (uint256 exclusivityEndTime_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n exclusivityEndTime_ := calldataload(add(encodedTx.offset, OFFSET_EXCLUSIVITY_END_TIME))\n }\n }\n\n /// @notice Extracts the Zap's native value from the encoded transaction.\n function zapNative(bytes calldata encodedTx) internal pure returns (uint256 zapNative_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n zapNative_ := calldataload(add(encodedTx.offset, OFFSET_ZAP_NATIVE))\n }\n }\n\n /// @notice Extracts the Zap's data from the encoded transaction.\n function zapData(bytes calldata encodedTx) internal pure returns (bytes calldata zapData_) {\n zapData_ = encodedTx[OFFSET_ZAP_DATA:];\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// contracts/libs/UniversalToken.sol\n\nlibrary UniversalTokenLib {\n using SafeERC20 for IERC20;\n\n address internal constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Transfers tokens to the given account. Reverts if transfer is not successful.\n /// @dev This might trigger fallback, if ETH is transferred to the contract.\n /// Make sure this can not lead to reentrancy attacks.\n function universalTransfer(address token, address to, uint256 value) internal {\n // Don't do anything, if need to send tokens to this address\n if (to == address(this)) return;\n // Don't do anything, if trying to send zero value\n if (value == 0) return;\n if (token == ETH_ADDRESS) {\n /// @dev Note: this can potentially lead to executing code in `to`.\n // solhint-disable-next-line avoid-low-level-calls\n (bool success,) = to.call{value: value}(\"\");\n require(success, \"ETH transfer failed\");\n } else {\n IERC20(token).safeTransfer(to, value);\n }\n }\n\n /// @notice Issues an infinite allowance to the spender, if the current allowance is insufficient\n /// to spend the given amount.\n function universalApproveInfinity(address token, address spender, uint256 amountToSpend) internal {\n // ETH Chad doesn't require your approval\n if (token == ETH_ADDRESS) return;\n // No-op if allowance is already sufficient\n uint256 allowance = IERC20(token).allowance(address(this), spender);\n if (allowance \u003e= amountToSpend) return;\n // Otherwise, reset approval to 0 and set to max allowance\n if (allowance \u003e 0) IERC20(token).safeDecreaseAllowance(spender, allowance);\n IERC20(token).safeIncreaseAllowance(spender, type(uint256).max);\n }\n\n /// @notice Returns the balance of the given token (or native ETH) for the given account.\n function universalBalanceOf(address token, address account) internal view returns (uint256) {\n if (token == ETH_ADDRESS) {\n return account.balance;\n } else {\n return IERC20(token).balanceOf(account);\n }\n }\n\n /// @dev Checks that token is a contract and not ETH_ADDRESS.\n function assertIsContract(address token) internal view {\n // Check that ETH_ADDRESS was not used (in case this is a predeploy on any of the chains)\n if (token == UniversalTokenLib.ETH_ADDRESS) revert TokenNotContract();\n // Check that token is not an EOA\n if (token.code.length == 0) revert TokenNotContract();\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/Admin.sol\n\ncontract Admin is IAdmin, AccessControlEnumerable {\n using UniversalTokenLib for address;\n\n bytes32 public constant RELAYER_ROLE = keccak256(\"RELAYER_ROLE\");\n bytes32 public constant REFUNDER_ROLE = keccak256(\"REFUNDER_ROLE\");\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n uint256 public constant FEE_BPS = 1e6;\n uint256 public constant FEE_RATE_MAX = 0.01e6; // max 1% on origin amount\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Chain gas amount to forward as rebate if requested\n uint256 public chainGasAmount;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n }\n\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n require(newFeeRate \u003c= FEE_RATE_MAX, \"newFeeRate \u003e max\");\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n token.universalTransfer(recipient, feeAmount);\n emit FeesSwept(token, recipient, feeAmount);\n }\n\n function setChainGasAmount(uint256 newChainGasAmount) external onlyRole(GOVERNOR_ROLE) {\n uint256 oldChainGasAmount = chainGasAmount;\n chainGasAmount = newChainGasAmount;\n emit ChainGasAmountUpdated(oldChainGasAmount, newChainGasAmount);\n }\n}\n\n// contracts/FastBridgeV2.sol\n\n/// @notice FastBridgeV2 is a contract for bridging tokens across chains.\ncontract FastBridgeV2 is Admin, MulticallTarget, IFastBridgeV2, IFastBridgeV2Errors {\n using BridgeTransactionV2Lib for bytes;\n using SafeERC20 for IERC20;\n\n /// @notice Address reserved for native gas token (ETH on Ethereum and most L2s, AVAX on Avalanche, etc)\n address public constant NATIVE_GAS_TOKEN = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Delay for a transaction after which it could be permisionlessly refunded\n uint256 public constant REFUND_DELAY = 7 days;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n /// @notice Maximum length of accepted zapData\n uint256 public constant MAX_ZAP_DATA_LENGTH = 2 ** 16 - 1;\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeTxDetails) public bridgeTxDetails;\n /// @notice Relay details on destination chain\n mapping(bytes32 =\u003e BridgeRelay) public bridgeRelayDetails;\n /// @notice Unique bridge nonces tracked per originSender\n mapping(address =\u003e uint256) public senderNonces;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Replaced by senderNonces\n uint256 public immutable nonce = 0;\n /// @notice the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n bridge({\n params: params,\n paramsV2: BridgeParamsV2({\n quoteRelayer: address(0),\n quoteExclusivitySeconds: 0,\n quoteId: bytes(\"\"),\n zapNative: 0,\n zapData: bytes(\"\")\n })\n });\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes calldata request) external payable {\n // relay override will validate the request\n relay({request: request, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes calldata request, bytes32 destTxHash) external {\n request.validateV2();\n prove({transactionId: keccak256(request), destTxHash: destTxHash, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridgeV2\n function claim(bytes calldata request) external {\n // claim override will validate the request\n claim({request: request, to: address(0)});\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Aggregate the read operations from the same storage slot\n address disputedRelayer = $.proofRelayer;\n BridgeStatus status = $.status;\n uint56 proofBlockTimestamp = $.proofBlockTimestamp;\n // Can only dispute a RELAYER_PROVED transaction within the dispute period\n if (status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(proofBlockTimestamp) \u003e DISPUTE_PERIOD) {\n revert DisputePeriodPassed();\n }\n // Update status to REQUESTED and delete the disputed proof details\n // Note: these are storage writes\n $.status = BridgeStatus.REQUESTED;\n $.proofRelayer = address(0);\n $.proofBlockTimestamp = 0;\n\n emit BridgeProofDisputed(transactionId, disputedRelayer);\n }\n\n /// @inheritdoc IFastBridge\n function refund(bytes calldata request) external {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Can only refund a REQUESTED transaction after its deadline expires\n if ($.status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n uint256 deadline = request.deadline();\n // Permissionless refund is only allowed after REFUND_DELAY on top of the deadline\n if (!hasRole(REFUNDER_ROLE, msg.sender)) deadline += REFUND_DELAY;\n if (block.timestamp \u003c= deadline) revert DeadlineNotExceeded();\n // Update status to REFUNDED and return the full amount (collateral + protocol fees) to the original sender.\n // The protocol fees are only updated when the transaction is claimed, so we don't need to update them here.\n // Note: this is a storage write\n $.status = BridgeStatus.REFUNDED;\n\n address to = request.originSender();\n address token = request.originToken();\n uint256 amount = request.originAmount() + request.originFeeAmount();\n // Emit the event before any external calls\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n // Complete the user refund as the last transaction action\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(to), amount);\n } else {\n IERC20(token).safeTransfer(to, amount);\n }\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // The correct relayer can only claim a RELAYER_PROVED transaction after the dispute period\n if ($.status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if ($.proofRelayer != relayer) revert SenderIncorrect();\n return _timeSince($.proofBlockTimestamp) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n /// @dev This method is added to achieve backwards compatibility with decoding requests into V1 structs:\n /// - `zapNative` is partially reported as a zero/non-zero flag\n /// - `zapData` is ignored\n /// In order to process all kinds of requests use getBridgeTransactionV2 instead.\n function getBridgeTransaction(bytes calldata request) external view returns (BridgeTransaction memory) {\n // Try decoding into V2 struct first. This will revert if V1 struct is passed\n try this.getBridgeTransactionV2(request) returns (BridgeTransactionV2 memory txV2) {\n // Note: we entirely ignore the zapData field, as it was not present in V1\n return BridgeTransaction({\n originChainId: txV2.originChainId,\n destChainId: txV2.destChainId,\n originSender: txV2.originSender,\n destRecipient: txV2.destRecipient,\n originToken: txV2.originToken,\n destToken: txV2.destToken,\n originAmount: txV2.originAmount,\n destAmount: txV2.destAmount,\n originFeeAmount: txV2.originFeeAmount,\n sendChainGas: txV2.zapNative != 0,\n deadline: txV2.deadline,\n nonce: txV2.nonce\n });\n } catch {\n // Fallback to V1 struct\n return abi.decode(request, (BridgeTransaction));\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function getBridgeTransactionV2(bytes calldata request) external pure returns (BridgeTransactionV2 memory) {\n request.validateV2();\n return BridgeTransactionV2Lib.decodeV2(request);\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) public payable {\n int256 exclusivityEndTime = 0;\n // if relayer exclusivity is not intended for this bridge, set exclusivityEndTime to static zero\n // otherwise, set exclusivity to expire at the current block ts offset by quoteExclusivitySeconds\n if (paramsV2.quoteRelayer != address(0)) {\n exclusivityEndTime = int256(block.timestamp) + paramsV2.quoteExclusivitySeconds;\n }\n _validateBridgeParams(params, paramsV2, exclusivityEndTime);\n\n // transfer tokens to bridge contract\n /// @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _takeBridgedUserAsset(params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) {\n originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n }\n\n // set status to requested\n bytes memory request = BridgeTransactionV2Lib.encodeV2(\n BridgeTransactionV2({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n deadline: params.deadline,\n nonce: senderNonces[params.sender]++, // increment nonce on every bridge\n exclusivityRelayer: paramsV2.quoteRelayer,\n // We checked exclusivityEndTime to be in range [0 .. params.deadline] above, so can safely cast\n exclusivityEndTime: uint256(exclusivityEndTime),\n zapNative: paramsV2.zapNative,\n zapData: paramsV2.zapData\n })\n );\n bytes32 transactionId = keccak256(request);\n // Note: the tx status will be updated throughout the tx lifecycle, while destChainId is set once here\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n bridgeTxDetails[transactionId].destChainId = params.dstChainId;\n\n emit BridgeRequested({\n transactionId: transactionId,\n sender: params.sender,\n request: request,\n destChainId: params.dstChainId,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n sendChainGas: paramsV2.zapNative != 0\n });\n emit BridgeQuoteDetails(transactionId, paramsV2.quoteId);\n }\n\n /// @inheritdoc IFastBridgeV2\n function relay(bytes calldata request, address relayer) public payable {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n _validateRelayParams(request, transactionId, relayer);\n // mark bridge transaction as relayed\n bridgeRelayDetails[transactionId] =\n BridgeRelay({blockNumber: uint48(block.number), blockTimestamp: uint48(block.timestamp), relayer: relayer});\n\n // transfer tokens to recipient on destination chain and trigger Zap if requested\n address to = request.destRecipient();\n address token = request.destToken();\n uint256 amount = request.destAmount();\n uint256 zapNative = request.zapNative();\n\n // Emit the event before any external calls\n emit BridgeRelayed({\n transactionId: transactionId,\n relayer: relayer,\n to: to,\n originChainId: request.originChainId(),\n originToken: request.originToken(),\n destToken: token,\n originAmount: request.originAmount(),\n destAmount: amount,\n chainGasAmount: zapNative\n });\n\n // All state changes have been done at this point, can proceed to the external calls.\n // This follows the checks-effects-interactions pattern to mitigate potential reentrancy attacks.\n if (token == NATIVE_GAS_TOKEN) {\n // For the native gas token, additional zapNative is not allowed\n if (zapNative != 0) revert ZapNativeNotSupported();\n // Check that the correct msg.value was sent\n if (msg.value != amount) revert MsgValueIncorrect();\n // Don't do a native transfer yet: we will handle it alongside the Zap below\n } else {\n // For ERC20s, we check that the correct msg.value was sent\n if (msg.value != zapNative) revert MsgValueIncorrect();\n // We need to transfer the tokens from the Relayer to the recipient first before performing an\n // optional post-transfer Zap.\n IERC20(token).safeTransferFrom(msg.sender, to, amount);\n }\n // At this point we have done:\n // - Transferred the requested amount of ERC20 tokens to the recipient.\n // At this point we have confirmed:\n // - For ERC20s: msg.value matches the requested zapNative amount.\n // - For the native gas token: msg.value matches the requested destAmount.\n // Remaining optional things to do:\n // - Forward the full msg.value to the recipient (if non-zero).\n // - Trigger a Zap (if zapData is present).\n bytes calldata zapData = request.zapData();\n if (zapData.length != 0) {\n // Zap Data is present: Zap has been requested by the recipient. Trigger it forwarding the full msg.value.\n\n // Note: if token has a fee on transfers, the recipient will have received less than `amount`.\n // This is a very niche edge case and should be handled by the recipient contract.\n _triggerZapWithChecks({recipient: to, token: token, amount: amount, zapData: zapData});\n } else if (msg.value != 0) {\n // Zap Data is missing, but msg.value was sent. This could happen in two different cases:\n // - Relay with the native gas token is happening.\n // - Relay with ERC20 is happening, with a `zapNative \u003e 0` request.\n // In both cases, we need to transfer the full msg.value to the recipient.\n Address.sendValue(payable(to), msg.value);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) public onlyRole(RELAYER_ROLE) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n\n // Can only prove a REQUESTED transaction\n if ($.status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n // Update status to RELAYER_PROVED and store the proof details\n // Note: these are storage writes\n $.status = BridgeStatus.RELAYER_PROVED;\n $.proofBlockTimestamp = uint56(block.timestamp);\n $.proofRelayer = relayer;\n\n emit BridgeProofProvided(transactionId, relayer, destTxHash);\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes calldata request, address to) public {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Aggregate the read operations from the same storage slot\n address proofRelayer = $.proofRelayer;\n BridgeStatus status = $.status;\n uint56 proofBlockTimestamp = $.proofBlockTimestamp;\n\n // Can only claim a RELAYER_PROVED transaction after the dispute period\n if (status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(proofBlockTimestamp) \u003c= DISPUTE_PERIOD) {\n revert DisputePeriodNotPassed();\n }\n\n if (to == address(0)) {\n // Anyone could claim the funds to the proven relayer on their behalf\n to = proofRelayer;\n } else if (proofRelayer != msg.sender) {\n // Only the proven relayer could specify an address to claim the funds to\n revert SenderIncorrect();\n }\n\n // Update status to RELAYER_CLAIMED and transfer the origin collateral to the specified claim address\n // Note: this is a storage write\n $.status = BridgeStatus.RELAYER_CLAIMED;\n\n address token = request.originToken();\n uint256 amount = request.originAmount();\n // Update protocol fees if origin fee amount exists\n uint256 originFeeAmount = request.originFeeAmount();\n if (originFeeAmount \u003e 0) protocolFees[token] += originFeeAmount;\n // Emit the event before any external calls\n emit BridgeDepositClaimed(transactionId, proofRelayer, to, token, amount);\n // Complete the relayer claim as the last transaction action\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(to), amount);\n } else {\n IERC20(token).safeTransfer(to, amount);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeStatuses(bytes32 transactionId) public view returns (BridgeStatus status) {\n return bridgeTxDetails[transactionId].status;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeProofs(bytes32 transactionId) public view returns (uint96 timestamp, address relayer) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n\n timestamp = $.proofBlockTimestamp;\n relayer = $.proofRelayer;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeRelays(bytes32 transactionId) public view returns (bool) {\n // has this transactionId been relayed?\n return bridgeRelayDetails[transactionId].relayer != address(0);\n }\n\n /// @notice Takes the bridged asset from the user into FastBridgeV2 custody. It will be later\n /// claimed by the relayer who completed the relay on destination chain, or refunded back to the user,\n /// should no one complete the relay.\n function _takeBridgedUserAsset(address token, uint256 amount) internal returns (uint256 amountTaken) {\n if (token == NATIVE_GAS_TOKEN) {\n // For the native gas token, we just need to check that the supplied msg.value is correct.\n // Supplied `msg.value` is already in FastBridgeV2 custody.\n if (amount != msg.value) revert MsgValueIncorrect();\n amountTaken = msg.value;\n } else {\n // For ERC20s, token is explicitly transferred from the user to FastBridgeV2.\n // We don't allow non-zero `msg.value` to avoid extra funds from being stuck in FastBridgeV2.\n if (msg.value != 0) revert MsgValueIncorrect();\n // Throw an explicit error if the provided token address is not a contract\n if (token.code.length == 0) revert TokenNotContract();\n amountTaken = IERC20(token).balanceOf(address(this));\n IERC20(token).safeTransferFrom(msg.sender, address(this), amount);\n // Use the balance difference as the amount taken in case of fee on transfer tokens.\n amountTaken = IERC20(token).balanceOf(address(this)) - amountTaken;\n }\n }\n\n /// @notice Calls the Recipient's hook function with the specified zapData and performs\n /// all the necessary checks for the returned value.\n function _triggerZapWithChecks(address recipient, address token, uint256 amount, bytes calldata zapData) internal {\n // This will bubble any revert messages from the hook function\n bytes memory returnData = Address.functionCallWithValue({\n target: recipient,\n data: abi.encodeCall(IZapRecipient.zap, (token, amount, zapData)),\n // Note: see `relay()` for reasoning behind passing msg.value\n value: msg.value\n });\n // Explicit revert if no return data at all\n if (returnData.length == 0) revert RecipientNoReturnValue();\n // Check that exactly a single return value was returned\n if (returnData.length != 32) revert RecipientIncorrectReturnValue();\n // Return value should be abi-encoded hook function selector\n if (bytes32(returnData) != bytes32(IZapRecipient.zap.selector)) {\n revert RecipientIncorrectReturnValue();\n }\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint56(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint56).max but\n /// proof.timestamp \u003c type(uint56).max via unchecked statement\n /// @param proofBlockTimestamp The bridge proof block timestamp\n /// @return delta Time delta since proof submitted\n function _timeSince(uint56 proofBlockTimestamp) internal view returns (uint256 delta) {\n unchecked {\n delta = uint56(block.timestamp) - proofBlockTimestamp;\n }\n }\n\n /// @notice Performs all the necessary checks for a bridge to happen.\n /// @dev There's no good way to refactor this function to reduce cyclomatic complexity due to\n /// the number of checks that need to be performed, so we skip the code-complexity rule here.\n // solhint-disable-next-line code-complexity\n function _validateBridgeParams(\n BridgeParams memory params,\n BridgeParamsV2 memory paramsV2,\n int256 exclusivityEndTime\n )\n internal\n view\n {\n // Check V1 (legacy) params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.sender == address(0) || params.to == address(0)) revert ZeroAddress();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n // Check V2 params\n if (paramsV2.zapData.length \u003e MAX_ZAP_DATA_LENGTH) revert ZapDataLengthAboveMax();\n if (paramsV2.zapNative != 0 \u0026\u0026 params.destToken == NATIVE_GAS_TOKEN) {\n revert ZapNativeNotSupported();\n }\n // exclusivityEndTime must be in range [0 .. params.deadline]\n if (exclusivityEndTime \u003c 0 || exclusivityEndTime \u003e int256(params.deadline)) {\n revert ExclusivityParamsIncorrect();\n }\n }\n\n /// @notice Performs all the necessary checks for a relay to happen.\n function _validateRelayParams(bytes calldata request, bytes32 transactionId, address relayer) internal view {\n if (relayer == address(0)) revert ZeroAddress();\n // Check if the transaction has already been relayed\n if (bridgeRelays(transactionId)) revert TransactionRelayed();\n if (request.destChainId() != block.chainid) revert ChainIncorrect();\n // Check the deadline for relay to happen\n if (block.timestamp \u003e request.deadline()) revert DeadlineExceeded();\n // Check the exclusivity period, if it is still ongoing\n address exclRelayer = request.exclusivityRelayer();\n if (exclRelayer != address(0) \u0026\u0026 exclRelayer != relayer \u0026\u0026 block.timestamp \u003c= request.exclusivityEndTime()) {\n revert ExclusivityPeriodNotPassed();\n }\n }\n}\n","language":"Solidity","languageVersion":"0.8.24","compilerVersion":"0.8.24","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"","srcMapRuntime":"","abiDefinition":[{"inputs":[],"name":"AccessControlBadConfirmation","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"bytes32","name":"neededRole","type":"bytes32"}],"name":"AccessControlUnauthorizedAccount","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"previousAdminRole","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"newAdminRole","type":"bytes32"}],"name":"RoleAdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleRevoked","type":"event"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleAdmin","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"grantRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"hasRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"callerConfirmation","type":"address"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"revokeRole","outputs":[],"stateMutability":"nonpayable","type":"function"}],"userDoc":{"kind":"user","methods":{},"version":1},"developerDoc":{"details":"External interface of AccessControl declared to support ERC165 detection.","errors":{"AccessControlBadConfirmation()":[{"details":"The caller of a function is not the expected one. NOTE: Don't confuse with {AccessControlUnauthorizedAccount}."}],"AccessControlUnauthorizedAccount(address,bytes32)":[{"details":"The `account` is missing a role."}]},"events":{"RoleAdminChanged(bytes32,bytes32,bytes32)":{"details":"Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole` `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite {RoleAdminChanged} not being emitted signaling this."},"RoleGranted(bytes32,address,address)":{"details":"Emitted when `account` is granted `role`. `sender` is the account that originated the contract call, an admin role bearer except when using {AccessControl-_setupRole}."},"RoleRevoked(bytes32,address,address)":{"details":"Emitted when `account` is revoked `role`. `sender` is the account that originated the contract call: - if using `revokeRole`, it is the admin role bearer - if using `renounceRole`, it is the role bearer (i.e. `account`)"}},"kind":"dev","methods":{"getRoleAdmin(bytes32)":{"details":"Returns the admin role that controls `role`. See {grantRole} and {revokeRole}. To change a role's admin, use {AccessControl-_setRoleAdmin}."},"grantRole(bytes32,address)":{"details":"Grants `role` to `account`. If `account` had not been already granted `role`, emits a {RoleGranted} event. Requirements: - the caller must have ``role``'s admin role."},"hasRole(bytes32,address)":{"details":"Returns `true` if `account` has been granted `role`."},"renounceRole(bytes32,address)":{"details":"Revokes `role` from the calling account. Roles are often managed via {grantRole} and {revokeRole}: this function's purpose is to provide a mechanism for accounts to lose their privileges if they are compromised (such as when a trusted device is misplaced). If the calling account had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must be `callerConfirmation`."},"revokeRole(bytes32,address)":{"details":"Revokes `role` from `account`. If `account` had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must have ``role``'s admin role."}},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[],\"name\":\"AccessControlBadConfirmation\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"neededRole\",\"type\":\"bytes32\"}],\"name\":\"AccessControlUnauthorizedAccount\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"previousAdminRole\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"newAdminRole\",\"type\":\"bytes32\"}],\"name\":\"RoleAdminChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleGranted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleRevoked\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"}],\"name\":\"getRoleAdmin\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"grantRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"hasRole\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"callerConfirmation\",\"type\":\"address\"}],\"name\":\"renounceRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"revokeRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"details\":\"External interface of AccessControl declared to support ERC165 detection.\",\"errors\":{\"AccessControlBadConfirmation()\":[{\"details\":\"The caller of a function is not the expected one. NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\"}],\"AccessControlUnauthorizedAccount(address,bytes32)\":[{\"details\":\"The `account` is missing a role.\"}]},\"events\":{\"RoleAdminChanged(bytes32,bytes32,bytes32)\":{\"details\":\"Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole` `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite {RoleAdminChanged} not being emitted signaling this.\"},\"RoleGranted(bytes32,address,address)\":{\"details\":\"Emitted when `account` is granted `role`. `sender` is the account that originated the contract call, an admin role bearer except when using {AccessControl-_setupRole}.\"},\"RoleRevoked(bytes32,address,address)\":{\"details\":\"Emitted when `account` is revoked `role`. `sender` is the account that originated the contract call: - if using `revokeRole`, it is the admin role bearer - if using `renounceRole`, it is the role bearer (i.e. `account`)\"}},\"kind\":\"dev\",\"methods\":{\"getRoleAdmin(bytes32)\":{\"details\":\"Returns the admin role that controls `role`. See {grantRole} and {revokeRole}. To change a role's admin, use {AccessControl-_setRoleAdmin}.\"},\"grantRole(bytes32,address)\":{\"details\":\"Grants `role` to `account`. If `account` had not been already granted `role`, emits a {RoleGranted} event. Requirements: - the caller must have ``role``'s admin role.\"},\"hasRole(bytes32,address)\":{\"details\":\"Returns `true` if `account` has been granted `role`.\"},\"renounceRole(bytes32,address)\":{\"details\":\"Revokes `role` from the calling account. Roles are often managed via {grantRole} and {revokeRole}: this function's purpose is to provide a mechanism for accounts to lose their privileges if they are compromised (such as when a trusted device is misplaced). If the calling account had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must be `callerConfirmation`.\"},\"revokeRole(bytes32,address)\":{\"details\":\"Revokes `role` from `account`. If `account` had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must have ``role``'s admin role.\"}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeV2.sol\":\"IAccessControl\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeV2.sol\":{\"keccak256\":\"0x5069b55ca07f21bfe30b2a43c18a18318c8af9c181b2dcb07c290825efd70f34\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://273dc020a49d08e50126bbea0d7f783f79d08c702f2fdbc560618d24af308acc\",\"dweb:/ipfs/QmXJ2UVzFc8EPB74RT4CXQPC4xw66jt4T13poyfyd3UERh\"]}},\"version\":1}"},"hashes":{"getRoleAdmin(bytes32)":"248a9ca3","grantRole(bytes32,address)":"2f2ff15d","hasRole(bytes32,address)":"91d14854","renounceRole(bytes32,address)":"36568abe","revokeRole(bytes32,address)":"d547741f"}},"solidity/FastBridgeV2.sol:IAccessControlEnumerable":{"code":"0x","runtime-code":"0x","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.24 ^0.8.20 ^0.8.4;\n\n// contracts/interfaces/IAdmin.sol\n\ninterface IAdmin {\n // ============ Events ============\n\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n event ChainGasAmountUpdated(uint256 oldChainGasAmount, uint256 newChainGasAmount);\n\n // ============ Methods ============\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n\n function setChainGasAmount(uint256 newChainGasAmount) external;\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IFastBridgeV2Errors.sol\n\ninterface IFastBridgeV2Errors {\n error AmountIncorrect();\n error ChainIncorrect();\n error ExclusivityParamsIncorrect();\n error MsgValueIncorrect();\n error SenderIncorrect();\n error StatusIncorrect();\n error TokenNotContract();\n error ZapDataLengthAboveMax();\n error ZapNativeNotSupported();\n error ZeroAddress();\n\n error RecipientIncorrectReturnValue();\n error RecipientNoReturnValue();\n\n error DeadlineExceeded();\n error DeadlineNotExceeded();\n error DeadlineTooShort();\n error DisputePeriodNotPassed();\n error DisputePeriodPassed();\n error ExclusivityPeriodNotPassed();\n\n error TransactionRelayed();\n}\n\n// contracts/interfaces/IMulticallTarget.sol\n\n/// @notice Interface for a contract that can be called multiple times by the same caller. Inspired by MulticallV3:\n/// https://github.com/mds1/multicall/blob/master/src/Multicall3.sol\ninterface IMulticallTarget {\n struct Result {\n bool success;\n bytes returnData;\n }\n\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external;\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results);\n}\n\n// contracts/interfaces/IZapRecipient.sol\n\ninterface IZapRecipient {\n function zap(address token, uint256 amount, bytes memory zapData) external payable returns (bytes4);\n}\n\n// contracts/libs/Errors.sol\n\nerror DeadlineExceeded();\nerror DeadlineNotExceeded();\nerror DeadlineTooShort();\nerror InsufficientOutputAmount();\n\nerror MsgValueIncorrect();\nerror PoolNotFound();\nerror TokenAddressMismatch();\nerror TokenNotContract();\nerror TokenNotETH();\nerror TokensIdentical();\n\nerror ChainIncorrect();\nerror AmountIncorrect();\nerror ZeroAddress();\n\nerror DisputePeriodNotPassed();\nerror DisputePeriodPassed();\nerror SenderIncorrect();\nerror StatusIncorrect();\nerror TransactionIdIncorrect();\nerror TransactionRelayed();\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// contracts/interfaces/IFastBridgeV2.sol\n\ninterface IFastBridgeV2 is IFastBridge {\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n struct BridgeTxDetails {\n BridgeStatus status;\n uint32 destChainId;\n uint56 proofBlockTimestamp;\n address proofRelayer;\n }\n\n struct BridgeRelay {\n uint48 blockNumber;\n uint48 blockTimestamp;\n address relayer;\n }\n\n /// @notice New params introduced in the FastBridgeV2.\n /// We are passing fields from the older BridgeParams struct outside of this struct\n /// for backwards compatibility.\n /// Note: quoteRelayer and quoteExclusivitySeconds are either both zero (indicating no exclusivity)\n /// or both non-zero (indicating exclusivity for the given period).\n /// Note: zapNative \u003e 0 can NOT be used with destToken = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE (native token)\n /// @param quoteRelayer Relayer that provided the quote for the transaction\n /// @param quoteExclusivitySeconds Period of time the quote relayer is guaranteed exclusivity after user's deposit\n /// @param quoteId Unique quote identifier used for tracking the quote\n /// @param zapNative ETH value to send to the recipient (if any)\n /// @param zapData Parameters for the Zap to the destination recipient (if any)\n struct BridgeParamsV2 {\n address quoteRelayer;\n int256 quoteExclusivitySeconds;\n bytes quoteId;\n uint256 zapNative;\n bytes zapData;\n }\n\n /// @notice Updated bridge transaction struct to include parameters introduced in FastBridgeV2.\n /// Note: only `exclusivityRelayer` can fill such a transaction until `exclusivityEndTime`.\n struct BridgeTransactionV2 {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n // Note: sendChainGas flag from V1 is deprecated\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n address exclusivityRelayer;\n uint256 exclusivityEndTime;\n uint256 zapNative; // ETH value to send to the recipient (if any)\n bytes zapData; // data to pass for the Zap action (if any)\n }\n\n event BridgeQuoteDetails(bytes32 indexed transactionId, bytes quoteId);\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability\n /// to provide temporary exclusivity fill rights for the quote relayer.\n /// @param params The parameters required to bridge\n /// @param paramsV2 The parameters for exclusivity fill rights (optional, can be left empty)\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function relay(bytes memory request, address relayer) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param transactionId The transaction id associated with the encoded bridge transaction to prove\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital.\n /// @notice Can only send funds to the relayer address on the proof.\n /// @param request The encoded bridge transaction to claim on origin chain\n function claim(bytes memory request) external;\n /// @notice Checks if a transaction has been relayed\n /// @param transactionId The ID of the transaction to check\n /// @return True if the transaction has been relayed, false otherwise\n function bridgeRelays(bytes32 transactionId) external view returns (bool);\n\n /// @notice Returns the status of a bridge transaction\n /// @param transactionId The ID of the bridge transaction\n /// @return BridgeStatus Status of the bridge transaction\n function bridgeStatuses(bytes32 transactionId) external view returns (BridgeStatus);\n\n /// @notice Returns the timestamp and relayer of a bridge proof\n /// @param transactionId The ID of the bridge transaction\n /// @return timestamp The timestamp of the bridge proof\n /// @return relayer The relayer address of the bridge proof\n function bridgeProofs(bytes32 transactionId) external view returns (uint96 timestamp, address relayer);\n\n /// @notice Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\n /// @param request The bridge request to decode\n function getBridgeTransactionV2(bytes memory request) external view returns (BridgeTransactionV2 memory);\n}\n\n// contracts/utils/MulticallTarget.sol\n\n// solhint-disable avoid-low-level-calls\n/// @notice Template for a contract that supports batched calls (preserving the msg.sender).\n/// Only calls with zero msg.value could be batched.\nabstract contract MulticallTarget is IMulticallTarget {\n error MulticallTarget__UndeterminedRevert();\n\n /// @notice Perform a batched call to this contract, preserving the msg.sender.\n /// The return data from each call is discarded.\n /// @dev The method is non-payable, so only calls with `msg.value == 0` could be batched.\n /// It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag.\n /// Otherwise, the whole batch call will be reverted with the original revert reason.\n /// @param data List of abi-encoded calldata for the calls to perform.\n /// @param ignoreReverts Whether to ignore the revert errors from the calls.\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external {\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\n if (!success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(result);\n }\n }\n }\n\n /// @notice Perform a batched call to this contract, preserving the msg.sender.\n /// The return data from each call is preserved.\n /// @dev The method is non-payable, so only calls with `msg.value == 0` could be batched.\n /// It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag.\n /// Otherwise, the whole batch call will be reverted with the original revert reason.\n /// @param data List of abi-encoded calldata for the calls to perform.\n /// @param ignoreReverts Whether to ignore the revert errors from the calls.\n /// @return results List of results from the calls: `(success, returnData)`.\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results)\n {\n results = new Result[](data.length);\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (results[i].success, results[i].returnData) = address(this).delegatecall(data[i]);\n if (!results[i].success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(results[i].returnData);\n }\n }\n }\n\n /// @dev Bubbles the revert message from the underlying call.\n /// Note: preserves the same custom error or revert string, if one was used.\n /// Source: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v5.0.2/contracts/utils/Address.sol#L143-L158\n function _bubbleRevert(bytes memory returnData) internal pure {\n // Look for revert reason and bubble it up if present\n if (returnData.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n // solhint-disable-next-line no-inline-assembly\n assembly {\n let returndata_size := mload(returnData)\n revert(add(32, returnData), returndata_size)\n }\n } else {\n revert MulticallTarget__UndeterminedRevert();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// contracts/libs/BridgeTransactionV2.sol\n\n// solhint-disable no-inline-assembly\nlibrary BridgeTransactionV2Lib {\n uint16 internal constant VERSION = 2;\n\n // Offsets of the fields in the packed BridgeTransactionV2 struct\n // uint16 version [000 .. 002)\n // uint32 originChainId [002 .. 006)\n // uint32 destChainId [006 .. 010)\n // address originSender [010 .. 030)\n // address destRecipient [030 .. 050)\n // address originToken [050 .. 070)\n // address destToken [070 .. 090)\n // uint256 originAmount [090 .. 122)\n // uint256 destAmount [122 .. 154)\n // uint256 originFeeAmount [154 .. 186)\n // uint256 deadline [186 .. 218)\n // uint256 nonce [218 .. 250)\n // address exclusivityRelayer [250 .. 270)\n // uint256 exclusivityEndTime [270 .. 302)\n // uint256 zapNative [302 .. 334)\n // bytes zapData [334 .. ***)\n\n // forgefmt: disable-start\n uint256 private constant OFFSET_ORIGIN_CHAIN_ID = 2;\n uint256 private constant OFFSET_DEST_CHAIN_ID = 6;\n uint256 private constant OFFSET_ORIGIN_SENDER = 10;\n uint256 private constant OFFSET_DEST_RECIPIENT = 30;\n uint256 private constant OFFSET_ORIGIN_TOKEN = 50;\n uint256 private constant OFFSET_DEST_TOKEN = 70;\n uint256 private constant OFFSET_ORIGIN_AMOUNT = 90;\n uint256 private constant OFFSET_DEST_AMOUNT = 122;\n uint256 private constant OFFSET_ORIGIN_FEE_AMOUNT = 154;\n uint256 private constant OFFSET_DEADLINE = 186;\n uint256 private constant OFFSET_NONCE = 218;\n uint256 private constant OFFSET_EXCLUSIVITY_RELAYER = 250;\n uint256 private constant OFFSET_EXCLUSIVITY_END_TIME = 270;\n uint256 private constant OFFSET_ZAP_NATIVE = 302;\n uint256 private constant OFFSET_ZAP_DATA = 334;\n // forgefmt: disable-end\n\n error BridgeTransactionV2__InvalidEncodedTx();\n error BridgeTransactionV2__UnsupportedVersion(uint16 version);\n\n /// @notice Validates the encoded transaction to be a tightly packed encoded payload for BridgeTransactionV2.\n /// @dev Checks the minimum length and the version, use this function before decoding any of the fields.\n function validateV2(bytes calldata encodedTx) internal pure {\n // Check the minimum length: must at least include all static fields.\n if (encodedTx.length \u003c OFFSET_ZAP_DATA) revert BridgeTransactionV2__InvalidEncodedTx();\n // Once we validated the length, we can be sure that the version field is present.\n uint16 version_ = version(encodedTx);\n if (version_ != VERSION) revert BridgeTransactionV2__UnsupportedVersion(version_);\n }\n\n /// @notice Encodes the BridgeTransactionV2 struct by tightly packing the fields.\n /// @dev `abi.decode` will not work as a result of the tightly packed fields. Use `decodeV2` to decode instead.\n function encodeV2(IFastBridgeV2.BridgeTransactionV2 memory bridgeTx) internal pure returns (bytes memory) {\n // We split the encoding into two parts to avoid stack-too-deep error\n bytes memory firstPart = abi.encodePacked(\n VERSION,\n bridgeTx.originChainId,\n bridgeTx.destChainId,\n bridgeTx.originSender,\n bridgeTx.destRecipient,\n bridgeTx.originToken,\n bridgeTx.destToken,\n bridgeTx.originAmount\n );\n return abi.encodePacked(\n firstPart,\n bridgeTx.destAmount,\n bridgeTx.originFeeAmount,\n // Note: we skip the deprecated `sendChainGas` flag, which was present in BridgeTransaction V1\n bridgeTx.deadline,\n bridgeTx.nonce,\n // New V2 fields: exclusivity\n bridgeTx.exclusivityRelayer,\n bridgeTx.exclusivityEndTime,\n // New V2 fields: Zap\n bridgeTx.zapNative,\n bridgeTx.zapData\n );\n }\n\n /// @notice Decodes the BridgeTransactionV2 struct from the encoded transaction.\n /// @dev Encoded BridgeTransactionV2 struct must be tightly packed.\n /// Use `validateV2` before decoding to ensure the encoded transaction is valid.\n function decodeV2(bytes calldata encodedTx)\n internal\n pure\n returns (IFastBridgeV2.BridgeTransactionV2 memory bridgeTx)\n {\n bridgeTx.originChainId = originChainId(encodedTx);\n bridgeTx.destChainId = destChainId(encodedTx);\n bridgeTx.originSender = originSender(encodedTx);\n bridgeTx.destRecipient = destRecipient(encodedTx);\n bridgeTx.originToken = originToken(encodedTx);\n bridgeTx.destToken = destToken(encodedTx);\n bridgeTx.originAmount = originAmount(encodedTx);\n bridgeTx.destAmount = destAmount(encodedTx);\n bridgeTx.originFeeAmount = originFeeAmount(encodedTx);\n bridgeTx.deadline = deadline(encodedTx);\n bridgeTx.nonce = nonce(encodedTx);\n bridgeTx.exclusivityRelayer = exclusivityRelayer(encodedTx);\n bridgeTx.exclusivityEndTime = exclusivityEndTime(encodedTx);\n bridgeTx.zapNative = zapNative(encodedTx);\n bridgeTx.zapData = zapData(encodedTx);\n }\n\n /// @notice Extracts the version from the encoded transaction.\n function version(bytes calldata encodedTx) internal pure returns (uint16 version_) {\n // Load 32 bytes from the start and shift it 240 bits to the right to get the highest 16 bits.\n assembly {\n version_ := shr(240, calldataload(encodedTx.offset))\n }\n }\n\n /// @notice Extracts the origin chain ID from the encoded transaction.\n function originChainId(bytes calldata encodedTx) internal pure returns (uint32 originChainId_) {\n // Load 32 bytes from the offset and shift it 224 bits to the right to get the highest 32 bits.\n assembly {\n originChainId_ := shr(224, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_CHAIN_ID)))\n }\n }\n\n /// @notice Extracts the destination chain ID from the encoded transaction.\n function destChainId(bytes calldata encodedTx) internal pure returns (uint32 destChainId_) {\n // Load 32 bytes from the offset and shift it 224 bits to the right to get the highest 32 bits.\n assembly {\n destChainId_ := shr(224, calldataload(add(encodedTx.offset, OFFSET_DEST_CHAIN_ID)))\n }\n }\n\n /// @notice Extracts the origin sender from the encoded transaction.\n function originSender(bytes calldata encodedTx) internal pure returns (address originSender_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n originSender_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_SENDER)))\n }\n }\n\n /// @notice Extracts the destination recipient from the encoded transaction.\n function destRecipient(bytes calldata encodedTx) internal pure returns (address destRecipient_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n destRecipient_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_DEST_RECIPIENT)))\n }\n }\n\n /// @notice Extracts the origin token from the encoded transaction.\n function originToken(bytes calldata encodedTx) internal pure returns (address originToken_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n originToken_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_TOKEN)))\n }\n }\n\n /// @notice Extracts the destination token from the encoded transaction.\n function destToken(bytes calldata encodedTx) internal pure returns (address destToken_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n destToken_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_DEST_TOKEN)))\n }\n }\n\n /// @notice Extracts the origin amount from the encoded transaction.\n function originAmount(bytes calldata encodedTx) internal pure returns (uint256 originAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n originAmount_ := calldataload(add(encodedTx.offset, OFFSET_ORIGIN_AMOUNT))\n }\n }\n\n /// @notice Extracts the destination amount from the encoded transaction.\n function destAmount(bytes calldata encodedTx) internal pure returns (uint256 destAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n destAmount_ := calldataload(add(encodedTx.offset, OFFSET_DEST_AMOUNT))\n }\n }\n\n /// @notice Extracts the origin fee amount from the encoded transaction.\n function originFeeAmount(bytes calldata encodedTx) internal pure returns (uint256 originFeeAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n originFeeAmount_ := calldataload(add(encodedTx.offset, OFFSET_ORIGIN_FEE_AMOUNT))\n }\n }\n\n /// @notice Extracts the deadline from the encoded transaction.\n function deadline(bytes calldata encodedTx) internal pure returns (uint256 deadline_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n deadline_ := calldataload(add(encodedTx.offset, OFFSET_DEADLINE))\n }\n }\n\n /// @notice Extracts the nonce from the encoded transaction.\n function nonce(bytes calldata encodedTx) internal pure returns (uint256 nonce_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n nonce_ := calldataload(add(encodedTx.offset, OFFSET_NONCE))\n }\n }\n\n /// @notice Extracts the exclusivity relayer from the encoded transaction.\n function exclusivityRelayer(bytes calldata encodedTx) internal pure returns (address exclusivityRelayer_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n exclusivityRelayer_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_EXCLUSIVITY_RELAYER)))\n }\n }\n\n /// @notice Extracts the exclusivity end time from the encoded transaction.\n function exclusivityEndTime(bytes calldata encodedTx) internal pure returns (uint256 exclusivityEndTime_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n exclusivityEndTime_ := calldataload(add(encodedTx.offset, OFFSET_EXCLUSIVITY_END_TIME))\n }\n }\n\n /// @notice Extracts the Zap's native value from the encoded transaction.\n function zapNative(bytes calldata encodedTx) internal pure returns (uint256 zapNative_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n zapNative_ := calldataload(add(encodedTx.offset, OFFSET_ZAP_NATIVE))\n }\n }\n\n /// @notice Extracts the Zap's data from the encoded transaction.\n function zapData(bytes calldata encodedTx) internal pure returns (bytes calldata zapData_) {\n zapData_ = encodedTx[OFFSET_ZAP_DATA:];\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// contracts/libs/UniversalToken.sol\n\nlibrary UniversalTokenLib {\n using SafeERC20 for IERC20;\n\n address internal constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Transfers tokens to the given account. Reverts if transfer is not successful.\n /// @dev This might trigger fallback, if ETH is transferred to the contract.\n /// Make sure this can not lead to reentrancy attacks.\n function universalTransfer(address token, address to, uint256 value) internal {\n // Don't do anything, if need to send tokens to this address\n if (to == address(this)) return;\n // Don't do anything, if trying to send zero value\n if (value == 0) return;\n if (token == ETH_ADDRESS) {\n /// @dev Note: this can potentially lead to executing code in `to`.\n // solhint-disable-next-line avoid-low-level-calls\n (bool success,) = to.call{value: value}(\"\");\n require(success, \"ETH transfer failed\");\n } else {\n IERC20(token).safeTransfer(to, value);\n }\n }\n\n /// @notice Issues an infinite allowance to the spender, if the current allowance is insufficient\n /// to spend the given amount.\n function universalApproveInfinity(address token, address spender, uint256 amountToSpend) internal {\n // ETH Chad doesn't require your approval\n if (token == ETH_ADDRESS) return;\n // No-op if allowance is already sufficient\n uint256 allowance = IERC20(token).allowance(address(this), spender);\n if (allowance \u003e= amountToSpend) return;\n // Otherwise, reset approval to 0 and set to max allowance\n if (allowance \u003e 0) IERC20(token).safeDecreaseAllowance(spender, allowance);\n IERC20(token).safeIncreaseAllowance(spender, type(uint256).max);\n }\n\n /// @notice Returns the balance of the given token (or native ETH) for the given account.\n function universalBalanceOf(address token, address account) internal view returns (uint256) {\n if (token == ETH_ADDRESS) {\n return account.balance;\n } else {\n return IERC20(token).balanceOf(account);\n }\n }\n\n /// @dev Checks that token is a contract and not ETH_ADDRESS.\n function assertIsContract(address token) internal view {\n // Check that ETH_ADDRESS was not used (in case this is a predeploy on any of the chains)\n if (token == UniversalTokenLib.ETH_ADDRESS) revert TokenNotContract();\n // Check that token is not an EOA\n if (token.code.length == 0) revert TokenNotContract();\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/Admin.sol\n\ncontract Admin is IAdmin, AccessControlEnumerable {\n using UniversalTokenLib for address;\n\n bytes32 public constant RELAYER_ROLE = keccak256(\"RELAYER_ROLE\");\n bytes32 public constant REFUNDER_ROLE = keccak256(\"REFUNDER_ROLE\");\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n uint256 public constant FEE_BPS = 1e6;\n uint256 public constant FEE_RATE_MAX = 0.01e6; // max 1% on origin amount\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Chain gas amount to forward as rebate if requested\n uint256 public chainGasAmount;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n }\n\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n require(newFeeRate \u003c= FEE_RATE_MAX, \"newFeeRate \u003e max\");\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n token.universalTransfer(recipient, feeAmount);\n emit FeesSwept(token, recipient, feeAmount);\n }\n\n function setChainGasAmount(uint256 newChainGasAmount) external onlyRole(GOVERNOR_ROLE) {\n uint256 oldChainGasAmount = chainGasAmount;\n chainGasAmount = newChainGasAmount;\n emit ChainGasAmountUpdated(oldChainGasAmount, newChainGasAmount);\n }\n}\n\n// contracts/FastBridgeV2.sol\n\n/// @notice FastBridgeV2 is a contract for bridging tokens across chains.\ncontract FastBridgeV2 is Admin, MulticallTarget, IFastBridgeV2, IFastBridgeV2Errors {\n using BridgeTransactionV2Lib for bytes;\n using SafeERC20 for IERC20;\n\n /// @notice Address reserved for native gas token (ETH on Ethereum and most L2s, AVAX on Avalanche, etc)\n address public constant NATIVE_GAS_TOKEN = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Delay for a transaction after which it could be permisionlessly refunded\n uint256 public constant REFUND_DELAY = 7 days;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n /// @notice Maximum length of accepted zapData\n uint256 public constant MAX_ZAP_DATA_LENGTH = 2 ** 16 - 1;\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeTxDetails) public bridgeTxDetails;\n /// @notice Relay details on destination chain\n mapping(bytes32 =\u003e BridgeRelay) public bridgeRelayDetails;\n /// @notice Unique bridge nonces tracked per originSender\n mapping(address =\u003e uint256) public senderNonces;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Replaced by senderNonces\n uint256 public immutable nonce = 0;\n /// @notice the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n bridge({\n params: params,\n paramsV2: BridgeParamsV2({\n quoteRelayer: address(0),\n quoteExclusivitySeconds: 0,\n quoteId: bytes(\"\"),\n zapNative: 0,\n zapData: bytes(\"\")\n })\n });\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes calldata request) external payable {\n // relay override will validate the request\n relay({request: request, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes calldata request, bytes32 destTxHash) external {\n request.validateV2();\n prove({transactionId: keccak256(request), destTxHash: destTxHash, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridgeV2\n function claim(bytes calldata request) external {\n // claim override will validate the request\n claim({request: request, to: address(0)});\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Aggregate the read operations from the same storage slot\n address disputedRelayer = $.proofRelayer;\n BridgeStatus status = $.status;\n uint56 proofBlockTimestamp = $.proofBlockTimestamp;\n // Can only dispute a RELAYER_PROVED transaction within the dispute period\n if (status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(proofBlockTimestamp) \u003e DISPUTE_PERIOD) {\n revert DisputePeriodPassed();\n }\n // Update status to REQUESTED and delete the disputed proof details\n // Note: these are storage writes\n $.status = BridgeStatus.REQUESTED;\n $.proofRelayer = address(0);\n $.proofBlockTimestamp = 0;\n\n emit BridgeProofDisputed(transactionId, disputedRelayer);\n }\n\n /// @inheritdoc IFastBridge\n function refund(bytes calldata request) external {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Can only refund a REQUESTED transaction after its deadline expires\n if ($.status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n uint256 deadline = request.deadline();\n // Permissionless refund is only allowed after REFUND_DELAY on top of the deadline\n if (!hasRole(REFUNDER_ROLE, msg.sender)) deadline += REFUND_DELAY;\n if (block.timestamp \u003c= deadline) revert DeadlineNotExceeded();\n // Update status to REFUNDED and return the full amount (collateral + protocol fees) to the original sender.\n // The protocol fees are only updated when the transaction is claimed, so we don't need to update them here.\n // Note: this is a storage write\n $.status = BridgeStatus.REFUNDED;\n\n address to = request.originSender();\n address token = request.originToken();\n uint256 amount = request.originAmount() + request.originFeeAmount();\n // Emit the event before any external calls\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n // Complete the user refund as the last transaction action\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(to), amount);\n } else {\n IERC20(token).safeTransfer(to, amount);\n }\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // The correct relayer can only claim a RELAYER_PROVED transaction after the dispute period\n if ($.status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if ($.proofRelayer != relayer) revert SenderIncorrect();\n return _timeSince($.proofBlockTimestamp) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n /// @dev This method is added to achieve backwards compatibility with decoding requests into V1 structs:\n /// - `zapNative` is partially reported as a zero/non-zero flag\n /// - `zapData` is ignored\n /// In order to process all kinds of requests use getBridgeTransactionV2 instead.\n function getBridgeTransaction(bytes calldata request) external view returns (BridgeTransaction memory) {\n // Try decoding into V2 struct first. This will revert if V1 struct is passed\n try this.getBridgeTransactionV2(request) returns (BridgeTransactionV2 memory txV2) {\n // Note: we entirely ignore the zapData field, as it was not present in V1\n return BridgeTransaction({\n originChainId: txV2.originChainId,\n destChainId: txV2.destChainId,\n originSender: txV2.originSender,\n destRecipient: txV2.destRecipient,\n originToken: txV2.originToken,\n destToken: txV2.destToken,\n originAmount: txV2.originAmount,\n destAmount: txV2.destAmount,\n originFeeAmount: txV2.originFeeAmount,\n sendChainGas: txV2.zapNative != 0,\n deadline: txV2.deadline,\n nonce: txV2.nonce\n });\n } catch {\n // Fallback to V1 struct\n return abi.decode(request, (BridgeTransaction));\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function getBridgeTransactionV2(bytes calldata request) external pure returns (BridgeTransactionV2 memory) {\n request.validateV2();\n return BridgeTransactionV2Lib.decodeV2(request);\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) public payable {\n int256 exclusivityEndTime = 0;\n // if relayer exclusivity is not intended for this bridge, set exclusivityEndTime to static zero\n // otherwise, set exclusivity to expire at the current block ts offset by quoteExclusivitySeconds\n if (paramsV2.quoteRelayer != address(0)) {\n exclusivityEndTime = int256(block.timestamp) + paramsV2.quoteExclusivitySeconds;\n }\n _validateBridgeParams(params, paramsV2, exclusivityEndTime);\n\n // transfer tokens to bridge contract\n /// @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _takeBridgedUserAsset(params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) {\n originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n }\n\n // set status to requested\n bytes memory request = BridgeTransactionV2Lib.encodeV2(\n BridgeTransactionV2({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n deadline: params.deadline,\n nonce: senderNonces[params.sender]++, // increment nonce on every bridge\n exclusivityRelayer: paramsV2.quoteRelayer,\n // We checked exclusivityEndTime to be in range [0 .. params.deadline] above, so can safely cast\n exclusivityEndTime: uint256(exclusivityEndTime),\n zapNative: paramsV2.zapNative,\n zapData: paramsV2.zapData\n })\n );\n bytes32 transactionId = keccak256(request);\n // Note: the tx status will be updated throughout the tx lifecycle, while destChainId is set once here\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n bridgeTxDetails[transactionId].destChainId = params.dstChainId;\n\n emit BridgeRequested({\n transactionId: transactionId,\n sender: params.sender,\n request: request,\n destChainId: params.dstChainId,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n sendChainGas: paramsV2.zapNative != 0\n });\n emit BridgeQuoteDetails(transactionId, paramsV2.quoteId);\n }\n\n /// @inheritdoc IFastBridgeV2\n function relay(bytes calldata request, address relayer) public payable {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n _validateRelayParams(request, transactionId, relayer);\n // mark bridge transaction as relayed\n bridgeRelayDetails[transactionId] =\n BridgeRelay({blockNumber: uint48(block.number), blockTimestamp: uint48(block.timestamp), relayer: relayer});\n\n // transfer tokens to recipient on destination chain and trigger Zap if requested\n address to = request.destRecipient();\n address token = request.destToken();\n uint256 amount = request.destAmount();\n uint256 zapNative = request.zapNative();\n\n // Emit the event before any external calls\n emit BridgeRelayed({\n transactionId: transactionId,\n relayer: relayer,\n to: to,\n originChainId: request.originChainId(),\n originToken: request.originToken(),\n destToken: token,\n originAmount: request.originAmount(),\n destAmount: amount,\n chainGasAmount: zapNative\n });\n\n // All state changes have been done at this point, can proceed to the external calls.\n // This follows the checks-effects-interactions pattern to mitigate potential reentrancy attacks.\n if (token == NATIVE_GAS_TOKEN) {\n // For the native gas token, additional zapNative is not allowed\n if (zapNative != 0) revert ZapNativeNotSupported();\n // Check that the correct msg.value was sent\n if (msg.value != amount) revert MsgValueIncorrect();\n // Don't do a native transfer yet: we will handle it alongside the Zap below\n } else {\n // For ERC20s, we check that the correct msg.value was sent\n if (msg.value != zapNative) revert MsgValueIncorrect();\n // We need to transfer the tokens from the Relayer to the recipient first before performing an\n // optional post-transfer Zap.\n IERC20(token).safeTransferFrom(msg.sender, to, amount);\n }\n // At this point we have done:\n // - Transferred the requested amount of ERC20 tokens to the recipient.\n // At this point we have confirmed:\n // - For ERC20s: msg.value matches the requested zapNative amount.\n // - For the native gas token: msg.value matches the requested destAmount.\n // Remaining optional things to do:\n // - Forward the full msg.value to the recipient (if non-zero).\n // - Trigger a Zap (if zapData is present).\n bytes calldata zapData = request.zapData();\n if (zapData.length != 0) {\n // Zap Data is present: Zap has been requested by the recipient. Trigger it forwarding the full msg.value.\n\n // Note: if token has a fee on transfers, the recipient will have received less than `amount`.\n // This is a very niche edge case and should be handled by the recipient contract.\n _triggerZapWithChecks({recipient: to, token: token, amount: amount, zapData: zapData});\n } else if (msg.value != 0) {\n // Zap Data is missing, but msg.value was sent. This could happen in two different cases:\n // - Relay with the native gas token is happening.\n // - Relay with ERC20 is happening, with a `zapNative \u003e 0` request.\n // In both cases, we need to transfer the full msg.value to the recipient.\n Address.sendValue(payable(to), msg.value);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) public onlyRole(RELAYER_ROLE) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n\n // Can only prove a REQUESTED transaction\n if ($.status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n // Update status to RELAYER_PROVED and store the proof details\n // Note: these are storage writes\n $.status = BridgeStatus.RELAYER_PROVED;\n $.proofBlockTimestamp = uint56(block.timestamp);\n $.proofRelayer = relayer;\n\n emit BridgeProofProvided(transactionId, relayer, destTxHash);\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes calldata request, address to) public {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Aggregate the read operations from the same storage slot\n address proofRelayer = $.proofRelayer;\n BridgeStatus status = $.status;\n uint56 proofBlockTimestamp = $.proofBlockTimestamp;\n\n // Can only claim a RELAYER_PROVED transaction after the dispute period\n if (status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(proofBlockTimestamp) \u003c= DISPUTE_PERIOD) {\n revert DisputePeriodNotPassed();\n }\n\n if (to == address(0)) {\n // Anyone could claim the funds to the proven relayer on their behalf\n to = proofRelayer;\n } else if (proofRelayer != msg.sender) {\n // Only the proven relayer could specify an address to claim the funds to\n revert SenderIncorrect();\n }\n\n // Update status to RELAYER_CLAIMED and transfer the origin collateral to the specified claim address\n // Note: this is a storage write\n $.status = BridgeStatus.RELAYER_CLAIMED;\n\n address token = request.originToken();\n uint256 amount = request.originAmount();\n // Update protocol fees if origin fee amount exists\n uint256 originFeeAmount = request.originFeeAmount();\n if (originFeeAmount \u003e 0) protocolFees[token] += originFeeAmount;\n // Emit the event before any external calls\n emit BridgeDepositClaimed(transactionId, proofRelayer, to, token, amount);\n // Complete the relayer claim as the last transaction action\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(to), amount);\n } else {\n IERC20(token).safeTransfer(to, amount);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeStatuses(bytes32 transactionId) public view returns (BridgeStatus status) {\n return bridgeTxDetails[transactionId].status;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeProofs(bytes32 transactionId) public view returns (uint96 timestamp, address relayer) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n\n timestamp = $.proofBlockTimestamp;\n relayer = $.proofRelayer;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeRelays(bytes32 transactionId) public view returns (bool) {\n // has this transactionId been relayed?\n return bridgeRelayDetails[transactionId].relayer != address(0);\n }\n\n /// @notice Takes the bridged asset from the user into FastBridgeV2 custody. It will be later\n /// claimed by the relayer who completed the relay on destination chain, or refunded back to the user,\n /// should no one complete the relay.\n function _takeBridgedUserAsset(address token, uint256 amount) internal returns (uint256 amountTaken) {\n if (token == NATIVE_GAS_TOKEN) {\n // For the native gas token, we just need to check that the supplied msg.value is correct.\n // Supplied `msg.value` is already in FastBridgeV2 custody.\n if (amount != msg.value) revert MsgValueIncorrect();\n amountTaken = msg.value;\n } else {\n // For ERC20s, token is explicitly transferred from the user to FastBridgeV2.\n // We don't allow non-zero `msg.value` to avoid extra funds from being stuck in FastBridgeV2.\n if (msg.value != 0) revert MsgValueIncorrect();\n // Throw an explicit error if the provided token address is not a contract\n if (token.code.length == 0) revert TokenNotContract();\n amountTaken = IERC20(token).balanceOf(address(this));\n IERC20(token).safeTransferFrom(msg.sender, address(this), amount);\n // Use the balance difference as the amount taken in case of fee on transfer tokens.\n amountTaken = IERC20(token).balanceOf(address(this)) - amountTaken;\n }\n }\n\n /// @notice Calls the Recipient's hook function with the specified zapData and performs\n /// all the necessary checks for the returned value.\n function _triggerZapWithChecks(address recipient, address token, uint256 amount, bytes calldata zapData) internal {\n // This will bubble any revert messages from the hook function\n bytes memory returnData = Address.functionCallWithValue({\n target: recipient,\n data: abi.encodeCall(IZapRecipient.zap, (token, amount, zapData)),\n // Note: see `relay()` for reasoning behind passing msg.value\n value: msg.value\n });\n // Explicit revert if no return data at all\n if (returnData.length == 0) revert RecipientNoReturnValue();\n // Check that exactly a single return value was returned\n if (returnData.length != 32) revert RecipientIncorrectReturnValue();\n // Return value should be abi-encoded hook function selector\n if (bytes32(returnData) != bytes32(IZapRecipient.zap.selector)) {\n revert RecipientIncorrectReturnValue();\n }\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint56(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint56).max but\n /// proof.timestamp \u003c type(uint56).max via unchecked statement\n /// @param proofBlockTimestamp The bridge proof block timestamp\n /// @return delta Time delta since proof submitted\n function _timeSince(uint56 proofBlockTimestamp) internal view returns (uint256 delta) {\n unchecked {\n delta = uint56(block.timestamp) - proofBlockTimestamp;\n }\n }\n\n /// @notice Performs all the necessary checks for a bridge to happen.\n /// @dev There's no good way to refactor this function to reduce cyclomatic complexity due to\n /// the number of checks that need to be performed, so we skip the code-complexity rule here.\n // solhint-disable-next-line code-complexity\n function _validateBridgeParams(\n BridgeParams memory params,\n BridgeParamsV2 memory paramsV2,\n int256 exclusivityEndTime\n )\n internal\n view\n {\n // Check V1 (legacy) params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.sender == address(0) || params.to == address(0)) revert ZeroAddress();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n // Check V2 params\n if (paramsV2.zapData.length \u003e MAX_ZAP_DATA_LENGTH) revert ZapDataLengthAboveMax();\n if (paramsV2.zapNative != 0 \u0026\u0026 params.destToken == NATIVE_GAS_TOKEN) {\n revert ZapNativeNotSupported();\n }\n // exclusivityEndTime must be in range [0 .. params.deadline]\n if (exclusivityEndTime \u003c 0 || exclusivityEndTime \u003e int256(params.deadline)) {\n revert ExclusivityParamsIncorrect();\n }\n }\n\n /// @notice Performs all the necessary checks for a relay to happen.\n function _validateRelayParams(bytes calldata request, bytes32 transactionId, address relayer) internal view {\n if (relayer == address(0)) revert ZeroAddress();\n // Check if the transaction has already been relayed\n if (bridgeRelays(transactionId)) revert TransactionRelayed();\n if (request.destChainId() != block.chainid) revert ChainIncorrect();\n // Check the deadline for relay to happen\n if (block.timestamp \u003e request.deadline()) revert DeadlineExceeded();\n // Check the exclusivity period, if it is still ongoing\n address exclRelayer = request.exclusivityRelayer();\n if (exclRelayer != address(0) \u0026\u0026 exclRelayer != relayer \u0026\u0026 block.timestamp \u003c= request.exclusivityEndTime()) {\n revert ExclusivityPeriodNotPassed();\n }\n }\n}\n","language":"Solidity","languageVersion":"0.8.24","compilerVersion":"0.8.24","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"","srcMapRuntime":"","abiDefinition":[{"inputs":[],"name":"AccessControlBadConfirmation","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"bytes32","name":"neededRole","type":"bytes32"}],"name":"AccessControlUnauthorizedAccount","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"previousAdminRole","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"newAdminRole","type":"bytes32"}],"name":"RoleAdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleRevoked","type":"event"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleAdmin","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"uint256","name":"index","type":"uint256"}],"name":"getRoleMember","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleMemberCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"grantRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"hasRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"callerConfirmation","type":"address"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"revokeRole","outputs":[],"stateMutability":"nonpayable","type":"function"}],"userDoc":{"kind":"user","methods":{},"version":1},"developerDoc":{"details":"External interface of AccessControlEnumerable declared to support ERC165 detection.","errors":{"AccessControlBadConfirmation()":[{"details":"The caller of a function is not the expected one. NOTE: Don't confuse with {AccessControlUnauthorizedAccount}."}],"AccessControlUnauthorizedAccount(address,bytes32)":[{"details":"The `account` is missing a role."}]},"events":{"RoleAdminChanged(bytes32,bytes32,bytes32)":{"details":"Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole` `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite {RoleAdminChanged} not being emitted signaling this."},"RoleGranted(bytes32,address,address)":{"details":"Emitted when `account` is granted `role`. `sender` is the account that originated the contract call, an admin role bearer except when using {AccessControl-_setupRole}."},"RoleRevoked(bytes32,address,address)":{"details":"Emitted when `account` is revoked `role`. `sender` is the account that originated the contract call: - if using `revokeRole`, it is the admin role bearer - if using `renounceRole`, it is the role bearer (i.e. `account`)"}},"kind":"dev","methods":{"getRoleAdmin(bytes32)":{"details":"Returns the admin role that controls `role`. See {grantRole} and {revokeRole}. To change a role's admin, use {AccessControl-_setRoleAdmin}."},"getRoleMember(bytes32,uint256)":{"details":"Returns one of the accounts that have `role`. `index` must be a value between 0 and {getRoleMemberCount}, non-inclusive. Role bearers are not sorted in any particular way, and their ordering may change at any point. WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure you perform all queries on the same block. See the following https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post] for more information."},"getRoleMemberCount(bytes32)":{"details":"Returns the number of accounts that have `role`. Can be used together with {getRoleMember} to enumerate all bearers of a role."},"grantRole(bytes32,address)":{"details":"Grants `role` to `account`. If `account` had not been already granted `role`, emits a {RoleGranted} event. Requirements: - the caller must have ``role``'s admin role."},"hasRole(bytes32,address)":{"details":"Returns `true` if `account` has been granted `role`."},"renounceRole(bytes32,address)":{"details":"Revokes `role` from the calling account. Roles are often managed via {grantRole} and {revokeRole}: this function's purpose is to provide a mechanism for accounts to lose their privileges if they are compromised (such as when a trusted device is misplaced). If the calling account had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must be `callerConfirmation`."},"revokeRole(bytes32,address)":{"details":"Revokes `role` from `account`. If `account` had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must have ``role``'s admin role."}},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[],\"name\":\"AccessControlBadConfirmation\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"neededRole\",\"type\":\"bytes32\"}],\"name\":\"AccessControlUnauthorizedAccount\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"previousAdminRole\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"newAdminRole\",\"type\":\"bytes32\"}],\"name\":\"RoleAdminChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleGranted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleRevoked\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"}],\"name\":\"getRoleAdmin\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"index\",\"type\":\"uint256\"}],\"name\":\"getRoleMember\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"}],\"name\":\"getRoleMemberCount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"grantRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"hasRole\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"callerConfirmation\",\"type\":\"address\"}],\"name\":\"renounceRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"revokeRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"details\":\"External interface of AccessControlEnumerable declared to support ERC165 detection.\",\"errors\":{\"AccessControlBadConfirmation()\":[{\"details\":\"The caller of a function is not the expected one. NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\"}],\"AccessControlUnauthorizedAccount(address,bytes32)\":[{\"details\":\"The `account` is missing a role.\"}]},\"events\":{\"RoleAdminChanged(bytes32,bytes32,bytes32)\":{\"details\":\"Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole` `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite {RoleAdminChanged} not being emitted signaling this.\"},\"RoleGranted(bytes32,address,address)\":{\"details\":\"Emitted when `account` is granted `role`. `sender` is the account that originated the contract call, an admin role bearer except when using {AccessControl-_setupRole}.\"},\"RoleRevoked(bytes32,address,address)\":{\"details\":\"Emitted when `account` is revoked `role`. `sender` is the account that originated the contract call: - if using `revokeRole`, it is the admin role bearer - if using `renounceRole`, it is the role bearer (i.e. `account`)\"}},\"kind\":\"dev\",\"methods\":{\"getRoleAdmin(bytes32)\":{\"details\":\"Returns the admin role that controls `role`. See {grantRole} and {revokeRole}. To change a role's admin, use {AccessControl-_setRoleAdmin}.\"},\"getRoleMember(bytes32,uint256)\":{\"details\":\"Returns one of the accounts that have `role`. `index` must be a value between 0 and {getRoleMemberCount}, non-inclusive. Role bearers are not sorted in any particular way, and their ordering may change at any point. WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure you perform all queries on the same block. See the following https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post] for more information.\"},\"getRoleMemberCount(bytes32)\":{\"details\":\"Returns the number of accounts that have `role`. Can be used together with {getRoleMember} to enumerate all bearers of a role.\"},\"grantRole(bytes32,address)\":{\"details\":\"Grants `role` to `account`. If `account` had not been already granted `role`, emits a {RoleGranted} event. Requirements: - the caller must have ``role``'s admin role.\"},\"hasRole(bytes32,address)\":{\"details\":\"Returns `true` if `account` has been granted `role`.\"},\"renounceRole(bytes32,address)\":{\"details\":\"Revokes `role` from the calling account. Roles are often managed via {grantRole} and {revokeRole}: this function's purpose is to provide a mechanism for accounts to lose their privileges if they are compromised (such as when a trusted device is misplaced). If the calling account had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must be `callerConfirmation`.\"},\"revokeRole(bytes32,address)\":{\"details\":\"Revokes `role` from `account`. If `account` had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must have ``role``'s admin role.\"}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeV2.sol\":\"IAccessControlEnumerable\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeV2.sol\":{\"keccak256\":\"0x5069b55ca07f21bfe30b2a43c18a18318c8af9c181b2dcb07c290825efd70f34\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://273dc020a49d08e50126bbea0d7f783f79d08c702f2fdbc560618d24af308acc\",\"dweb:/ipfs/QmXJ2UVzFc8EPB74RT4CXQPC4xw66jt4T13poyfyd3UERh\"]}},\"version\":1}"},"hashes":{"getRoleAdmin(bytes32)":"248a9ca3","getRoleMember(bytes32,uint256)":"9010d07c","getRoleMemberCount(bytes32)":"ca15c873","grantRole(bytes32,address)":"2f2ff15d","hasRole(bytes32,address)":"91d14854","renounceRole(bytes32,address)":"36568abe","revokeRole(bytes32,address)":"d547741f"}},"solidity/FastBridgeV2.sol:IAdmin":{"code":"0x","runtime-code":"0x","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.24 ^0.8.20 ^0.8.4;\n\n// contracts/interfaces/IAdmin.sol\n\ninterface IAdmin {\n // ============ Events ============\n\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n event ChainGasAmountUpdated(uint256 oldChainGasAmount, uint256 newChainGasAmount);\n\n // ============ Methods ============\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n\n function setChainGasAmount(uint256 newChainGasAmount) external;\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IFastBridgeV2Errors.sol\n\ninterface IFastBridgeV2Errors {\n error AmountIncorrect();\n error ChainIncorrect();\n error ExclusivityParamsIncorrect();\n error MsgValueIncorrect();\n error SenderIncorrect();\n error StatusIncorrect();\n error TokenNotContract();\n error ZapDataLengthAboveMax();\n error ZapNativeNotSupported();\n error ZeroAddress();\n\n error RecipientIncorrectReturnValue();\n error RecipientNoReturnValue();\n\n error DeadlineExceeded();\n error DeadlineNotExceeded();\n error DeadlineTooShort();\n error DisputePeriodNotPassed();\n error DisputePeriodPassed();\n error ExclusivityPeriodNotPassed();\n\n error TransactionRelayed();\n}\n\n// contracts/interfaces/IMulticallTarget.sol\n\n/// @notice Interface for a contract that can be called multiple times by the same caller. Inspired by MulticallV3:\n/// https://github.com/mds1/multicall/blob/master/src/Multicall3.sol\ninterface IMulticallTarget {\n struct Result {\n bool success;\n bytes returnData;\n }\n\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external;\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results);\n}\n\n// contracts/interfaces/IZapRecipient.sol\n\ninterface IZapRecipient {\n function zap(address token, uint256 amount, bytes memory zapData) external payable returns (bytes4);\n}\n\n// contracts/libs/Errors.sol\n\nerror DeadlineExceeded();\nerror DeadlineNotExceeded();\nerror DeadlineTooShort();\nerror InsufficientOutputAmount();\n\nerror MsgValueIncorrect();\nerror PoolNotFound();\nerror TokenAddressMismatch();\nerror TokenNotContract();\nerror TokenNotETH();\nerror TokensIdentical();\n\nerror ChainIncorrect();\nerror AmountIncorrect();\nerror ZeroAddress();\n\nerror DisputePeriodNotPassed();\nerror DisputePeriodPassed();\nerror SenderIncorrect();\nerror StatusIncorrect();\nerror TransactionIdIncorrect();\nerror TransactionRelayed();\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// contracts/interfaces/IFastBridgeV2.sol\n\ninterface IFastBridgeV2 is IFastBridge {\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n struct BridgeTxDetails {\n BridgeStatus status;\n uint32 destChainId;\n uint56 proofBlockTimestamp;\n address proofRelayer;\n }\n\n struct BridgeRelay {\n uint48 blockNumber;\n uint48 blockTimestamp;\n address relayer;\n }\n\n /// @notice New params introduced in the FastBridgeV2.\n /// We are passing fields from the older BridgeParams struct outside of this struct\n /// for backwards compatibility.\n /// Note: quoteRelayer and quoteExclusivitySeconds are either both zero (indicating no exclusivity)\n /// or both non-zero (indicating exclusivity for the given period).\n /// Note: zapNative \u003e 0 can NOT be used with destToken = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE (native token)\n /// @param quoteRelayer Relayer that provided the quote for the transaction\n /// @param quoteExclusivitySeconds Period of time the quote relayer is guaranteed exclusivity after user's deposit\n /// @param quoteId Unique quote identifier used for tracking the quote\n /// @param zapNative ETH value to send to the recipient (if any)\n /// @param zapData Parameters for the Zap to the destination recipient (if any)\n struct BridgeParamsV2 {\n address quoteRelayer;\n int256 quoteExclusivitySeconds;\n bytes quoteId;\n uint256 zapNative;\n bytes zapData;\n }\n\n /// @notice Updated bridge transaction struct to include parameters introduced in FastBridgeV2.\n /// Note: only `exclusivityRelayer` can fill such a transaction until `exclusivityEndTime`.\n struct BridgeTransactionV2 {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n // Note: sendChainGas flag from V1 is deprecated\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n address exclusivityRelayer;\n uint256 exclusivityEndTime;\n uint256 zapNative; // ETH value to send to the recipient (if any)\n bytes zapData; // data to pass for the Zap action (if any)\n }\n\n event BridgeQuoteDetails(bytes32 indexed transactionId, bytes quoteId);\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability\n /// to provide temporary exclusivity fill rights for the quote relayer.\n /// @param params The parameters required to bridge\n /// @param paramsV2 The parameters for exclusivity fill rights (optional, can be left empty)\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function relay(bytes memory request, address relayer) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param transactionId The transaction id associated with the encoded bridge transaction to prove\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital.\n /// @notice Can only send funds to the relayer address on the proof.\n /// @param request The encoded bridge transaction to claim on origin chain\n function claim(bytes memory request) external;\n /// @notice Checks if a transaction has been relayed\n /// @param transactionId The ID of the transaction to check\n /// @return True if the transaction has been relayed, false otherwise\n function bridgeRelays(bytes32 transactionId) external view returns (bool);\n\n /// @notice Returns the status of a bridge transaction\n /// @param transactionId The ID of the bridge transaction\n /// @return BridgeStatus Status of the bridge transaction\n function bridgeStatuses(bytes32 transactionId) external view returns (BridgeStatus);\n\n /// @notice Returns the timestamp and relayer of a bridge proof\n /// @param transactionId The ID of the bridge transaction\n /// @return timestamp The timestamp of the bridge proof\n /// @return relayer The relayer address of the bridge proof\n function bridgeProofs(bytes32 transactionId) external view returns (uint96 timestamp, address relayer);\n\n /// @notice Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\n /// @param request The bridge request to decode\n function getBridgeTransactionV2(bytes memory request) external view returns (BridgeTransactionV2 memory);\n}\n\n// contracts/utils/MulticallTarget.sol\n\n// solhint-disable avoid-low-level-calls\n/// @notice Template for a contract that supports batched calls (preserving the msg.sender).\n/// Only calls with zero msg.value could be batched.\nabstract contract MulticallTarget is IMulticallTarget {\n error MulticallTarget__UndeterminedRevert();\n\n /// @notice Perform a batched call to this contract, preserving the msg.sender.\n /// The return data from each call is discarded.\n /// @dev The method is non-payable, so only calls with `msg.value == 0` could be batched.\n /// It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag.\n /// Otherwise, the whole batch call will be reverted with the original revert reason.\n /// @param data List of abi-encoded calldata for the calls to perform.\n /// @param ignoreReverts Whether to ignore the revert errors from the calls.\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external {\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\n if (!success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(result);\n }\n }\n }\n\n /// @notice Perform a batched call to this contract, preserving the msg.sender.\n /// The return data from each call is preserved.\n /// @dev The method is non-payable, so only calls with `msg.value == 0` could be batched.\n /// It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag.\n /// Otherwise, the whole batch call will be reverted with the original revert reason.\n /// @param data List of abi-encoded calldata for the calls to perform.\n /// @param ignoreReverts Whether to ignore the revert errors from the calls.\n /// @return results List of results from the calls: `(success, returnData)`.\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results)\n {\n results = new Result[](data.length);\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (results[i].success, results[i].returnData) = address(this).delegatecall(data[i]);\n if (!results[i].success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(results[i].returnData);\n }\n }\n }\n\n /// @dev Bubbles the revert message from the underlying call.\n /// Note: preserves the same custom error or revert string, if one was used.\n /// Source: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v5.0.2/contracts/utils/Address.sol#L143-L158\n function _bubbleRevert(bytes memory returnData) internal pure {\n // Look for revert reason and bubble it up if present\n if (returnData.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n // solhint-disable-next-line no-inline-assembly\n assembly {\n let returndata_size := mload(returnData)\n revert(add(32, returnData), returndata_size)\n }\n } else {\n revert MulticallTarget__UndeterminedRevert();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// contracts/libs/BridgeTransactionV2.sol\n\n// solhint-disable no-inline-assembly\nlibrary BridgeTransactionV2Lib {\n uint16 internal constant VERSION = 2;\n\n // Offsets of the fields in the packed BridgeTransactionV2 struct\n // uint16 version [000 .. 002)\n // uint32 originChainId [002 .. 006)\n // uint32 destChainId [006 .. 010)\n // address originSender [010 .. 030)\n // address destRecipient [030 .. 050)\n // address originToken [050 .. 070)\n // address destToken [070 .. 090)\n // uint256 originAmount [090 .. 122)\n // uint256 destAmount [122 .. 154)\n // uint256 originFeeAmount [154 .. 186)\n // uint256 deadline [186 .. 218)\n // uint256 nonce [218 .. 250)\n // address exclusivityRelayer [250 .. 270)\n // uint256 exclusivityEndTime [270 .. 302)\n // uint256 zapNative [302 .. 334)\n // bytes zapData [334 .. ***)\n\n // forgefmt: disable-start\n uint256 private constant OFFSET_ORIGIN_CHAIN_ID = 2;\n uint256 private constant OFFSET_DEST_CHAIN_ID = 6;\n uint256 private constant OFFSET_ORIGIN_SENDER = 10;\n uint256 private constant OFFSET_DEST_RECIPIENT = 30;\n uint256 private constant OFFSET_ORIGIN_TOKEN = 50;\n uint256 private constant OFFSET_DEST_TOKEN = 70;\n uint256 private constant OFFSET_ORIGIN_AMOUNT = 90;\n uint256 private constant OFFSET_DEST_AMOUNT = 122;\n uint256 private constant OFFSET_ORIGIN_FEE_AMOUNT = 154;\n uint256 private constant OFFSET_DEADLINE = 186;\n uint256 private constant OFFSET_NONCE = 218;\n uint256 private constant OFFSET_EXCLUSIVITY_RELAYER = 250;\n uint256 private constant OFFSET_EXCLUSIVITY_END_TIME = 270;\n uint256 private constant OFFSET_ZAP_NATIVE = 302;\n uint256 private constant OFFSET_ZAP_DATA = 334;\n // forgefmt: disable-end\n\n error BridgeTransactionV2__InvalidEncodedTx();\n error BridgeTransactionV2__UnsupportedVersion(uint16 version);\n\n /// @notice Validates the encoded transaction to be a tightly packed encoded payload for BridgeTransactionV2.\n /// @dev Checks the minimum length and the version, use this function before decoding any of the fields.\n function validateV2(bytes calldata encodedTx) internal pure {\n // Check the minimum length: must at least include all static fields.\n if (encodedTx.length \u003c OFFSET_ZAP_DATA) revert BridgeTransactionV2__InvalidEncodedTx();\n // Once we validated the length, we can be sure that the version field is present.\n uint16 version_ = version(encodedTx);\n if (version_ != VERSION) revert BridgeTransactionV2__UnsupportedVersion(version_);\n }\n\n /// @notice Encodes the BridgeTransactionV2 struct by tightly packing the fields.\n /// @dev `abi.decode` will not work as a result of the tightly packed fields. Use `decodeV2` to decode instead.\n function encodeV2(IFastBridgeV2.BridgeTransactionV2 memory bridgeTx) internal pure returns (bytes memory) {\n // We split the encoding into two parts to avoid stack-too-deep error\n bytes memory firstPart = abi.encodePacked(\n VERSION,\n bridgeTx.originChainId,\n bridgeTx.destChainId,\n bridgeTx.originSender,\n bridgeTx.destRecipient,\n bridgeTx.originToken,\n bridgeTx.destToken,\n bridgeTx.originAmount\n );\n return abi.encodePacked(\n firstPart,\n bridgeTx.destAmount,\n bridgeTx.originFeeAmount,\n // Note: we skip the deprecated `sendChainGas` flag, which was present in BridgeTransaction V1\n bridgeTx.deadline,\n bridgeTx.nonce,\n // New V2 fields: exclusivity\n bridgeTx.exclusivityRelayer,\n bridgeTx.exclusivityEndTime,\n // New V2 fields: Zap\n bridgeTx.zapNative,\n bridgeTx.zapData\n );\n }\n\n /// @notice Decodes the BridgeTransactionV2 struct from the encoded transaction.\n /// @dev Encoded BridgeTransactionV2 struct must be tightly packed.\n /// Use `validateV2` before decoding to ensure the encoded transaction is valid.\n function decodeV2(bytes calldata encodedTx)\n internal\n pure\n returns (IFastBridgeV2.BridgeTransactionV2 memory bridgeTx)\n {\n bridgeTx.originChainId = originChainId(encodedTx);\n bridgeTx.destChainId = destChainId(encodedTx);\n bridgeTx.originSender = originSender(encodedTx);\n bridgeTx.destRecipient = destRecipient(encodedTx);\n bridgeTx.originToken = originToken(encodedTx);\n bridgeTx.destToken = destToken(encodedTx);\n bridgeTx.originAmount = originAmount(encodedTx);\n bridgeTx.destAmount = destAmount(encodedTx);\n bridgeTx.originFeeAmount = originFeeAmount(encodedTx);\n bridgeTx.deadline = deadline(encodedTx);\n bridgeTx.nonce = nonce(encodedTx);\n bridgeTx.exclusivityRelayer = exclusivityRelayer(encodedTx);\n bridgeTx.exclusivityEndTime = exclusivityEndTime(encodedTx);\n bridgeTx.zapNative = zapNative(encodedTx);\n bridgeTx.zapData = zapData(encodedTx);\n }\n\n /// @notice Extracts the version from the encoded transaction.\n function version(bytes calldata encodedTx) internal pure returns (uint16 version_) {\n // Load 32 bytes from the start and shift it 240 bits to the right to get the highest 16 bits.\n assembly {\n version_ := shr(240, calldataload(encodedTx.offset))\n }\n }\n\n /// @notice Extracts the origin chain ID from the encoded transaction.\n function originChainId(bytes calldata encodedTx) internal pure returns (uint32 originChainId_) {\n // Load 32 bytes from the offset and shift it 224 bits to the right to get the highest 32 bits.\n assembly {\n originChainId_ := shr(224, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_CHAIN_ID)))\n }\n }\n\n /// @notice Extracts the destination chain ID from the encoded transaction.\n function destChainId(bytes calldata encodedTx) internal pure returns (uint32 destChainId_) {\n // Load 32 bytes from the offset and shift it 224 bits to the right to get the highest 32 bits.\n assembly {\n destChainId_ := shr(224, calldataload(add(encodedTx.offset, OFFSET_DEST_CHAIN_ID)))\n }\n }\n\n /// @notice Extracts the origin sender from the encoded transaction.\n function originSender(bytes calldata encodedTx) internal pure returns (address originSender_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n originSender_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_SENDER)))\n }\n }\n\n /// @notice Extracts the destination recipient from the encoded transaction.\n function destRecipient(bytes calldata encodedTx) internal pure returns (address destRecipient_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n destRecipient_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_DEST_RECIPIENT)))\n }\n }\n\n /// @notice Extracts the origin token from the encoded transaction.\n function originToken(bytes calldata encodedTx) internal pure returns (address originToken_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n originToken_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_TOKEN)))\n }\n }\n\n /// @notice Extracts the destination token from the encoded transaction.\n function destToken(bytes calldata encodedTx) internal pure returns (address destToken_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n destToken_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_DEST_TOKEN)))\n }\n }\n\n /// @notice Extracts the origin amount from the encoded transaction.\n function originAmount(bytes calldata encodedTx) internal pure returns (uint256 originAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n originAmount_ := calldataload(add(encodedTx.offset, OFFSET_ORIGIN_AMOUNT))\n }\n }\n\n /// @notice Extracts the destination amount from the encoded transaction.\n function destAmount(bytes calldata encodedTx) internal pure returns (uint256 destAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n destAmount_ := calldataload(add(encodedTx.offset, OFFSET_DEST_AMOUNT))\n }\n }\n\n /// @notice Extracts the origin fee amount from the encoded transaction.\n function originFeeAmount(bytes calldata encodedTx) internal pure returns (uint256 originFeeAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n originFeeAmount_ := calldataload(add(encodedTx.offset, OFFSET_ORIGIN_FEE_AMOUNT))\n }\n }\n\n /// @notice Extracts the deadline from the encoded transaction.\n function deadline(bytes calldata encodedTx) internal pure returns (uint256 deadline_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n deadline_ := calldataload(add(encodedTx.offset, OFFSET_DEADLINE))\n }\n }\n\n /// @notice Extracts the nonce from the encoded transaction.\n function nonce(bytes calldata encodedTx) internal pure returns (uint256 nonce_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n nonce_ := calldataload(add(encodedTx.offset, OFFSET_NONCE))\n }\n }\n\n /// @notice Extracts the exclusivity relayer from the encoded transaction.\n function exclusivityRelayer(bytes calldata encodedTx) internal pure returns (address exclusivityRelayer_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n exclusivityRelayer_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_EXCLUSIVITY_RELAYER)))\n }\n }\n\n /// @notice Extracts the exclusivity end time from the encoded transaction.\n function exclusivityEndTime(bytes calldata encodedTx) internal pure returns (uint256 exclusivityEndTime_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n exclusivityEndTime_ := calldataload(add(encodedTx.offset, OFFSET_EXCLUSIVITY_END_TIME))\n }\n }\n\n /// @notice Extracts the Zap's native value from the encoded transaction.\n function zapNative(bytes calldata encodedTx) internal pure returns (uint256 zapNative_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n zapNative_ := calldataload(add(encodedTx.offset, OFFSET_ZAP_NATIVE))\n }\n }\n\n /// @notice Extracts the Zap's data from the encoded transaction.\n function zapData(bytes calldata encodedTx) internal pure returns (bytes calldata zapData_) {\n zapData_ = encodedTx[OFFSET_ZAP_DATA:];\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// contracts/libs/UniversalToken.sol\n\nlibrary UniversalTokenLib {\n using SafeERC20 for IERC20;\n\n address internal constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Transfers tokens to the given account. Reverts if transfer is not successful.\n /// @dev This might trigger fallback, if ETH is transferred to the contract.\n /// Make sure this can not lead to reentrancy attacks.\n function universalTransfer(address token, address to, uint256 value) internal {\n // Don't do anything, if need to send tokens to this address\n if (to == address(this)) return;\n // Don't do anything, if trying to send zero value\n if (value == 0) return;\n if (token == ETH_ADDRESS) {\n /// @dev Note: this can potentially lead to executing code in `to`.\n // solhint-disable-next-line avoid-low-level-calls\n (bool success,) = to.call{value: value}(\"\");\n require(success, \"ETH transfer failed\");\n } else {\n IERC20(token).safeTransfer(to, value);\n }\n }\n\n /// @notice Issues an infinite allowance to the spender, if the current allowance is insufficient\n /// to spend the given amount.\n function universalApproveInfinity(address token, address spender, uint256 amountToSpend) internal {\n // ETH Chad doesn't require your approval\n if (token == ETH_ADDRESS) return;\n // No-op if allowance is already sufficient\n uint256 allowance = IERC20(token).allowance(address(this), spender);\n if (allowance \u003e= amountToSpend) return;\n // Otherwise, reset approval to 0 and set to max allowance\n if (allowance \u003e 0) IERC20(token).safeDecreaseAllowance(spender, allowance);\n IERC20(token).safeIncreaseAllowance(spender, type(uint256).max);\n }\n\n /// @notice Returns the balance of the given token (or native ETH) for the given account.\n function universalBalanceOf(address token, address account) internal view returns (uint256) {\n if (token == ETH_ADDRESS) {\n return account.balance;\n } else {\n return IERC20(token).balanceOf(account);\n }\n }\n\n /// @dev Checks that token is a contract and not ETH_ADDRESS.\n function assertIsContract(address token) internal view {\n // Check that ETH_ADDRESS was not used (in case this is a predeploy on any of the chains)\n if (token == UniversalTokenLib.ETH_ADDRESS) revert TokenNotContract();\n // Check that token is not an EOA\n if (token.code.length == 0) revert TokenNotContract();\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/Admin.sol\n\ncontract Admin is IAdmin, AccessControlEnumerable {\n using UniversalTokenLib for address;\n\n bytes32 public constant RELAYER_ROLE = keccak256(\"RELAYER_ROLE\");\n bytes32 public constant REFUNDER_ROLE = keccak256(\"REFUNDER_ROLE\");\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n uint256 public constant FEE_BPS = 1e6;\n uint256 public constant FEE_RATE_MAX = 0.01e6; // max 1% on origin amount\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Chain gas amount to forward as rebate if requested\n uint256 public chainGasAmount;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n }\n\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n require(newFeeRate \u003c= FEE_RATE_MAX, \"newFeeRate \u003e max\");\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n token.universalTransfer(recipient, feeAmount);\n emit FeesSwept(token, recipient, feeAmount);\n }\n\n function setChainGasAmount(uint256 newChainGasAmount) external onlyRole(GOVERNOR_ROLE) {\n uint256 oldChainGasAmount = chainGasAmount;\n chainGasAmount = newChainGasAmount;\n emit ChainGasAmountUpdated(oldChainGasAmount, newChainGasAmount);\n }\n}\n\n// contracts/FastBridgeV2.sol\n\n/// @notice FastBridgeV2 is a contract for bridging tokens across chains.\ncontract FastBridgeV2 is Admin, MulticallTarget, IFastBridgeV2, IFastBridgeV2Errors {\n using BridgeTransactionV2Lib for bytes;\n using SafeERC20 for IERC20;\n\n /// @notice Address reserved for native gas token (ETH on Ethereum and most L2s, AVAX on Avalanche, etc)\n address public constant NATIVE_GAS_TOKEN = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Delay for a transaction after which it could be permisionlessly refunded\n uint256 public constant REFUND_DELAY = 7 days;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n /// @notice Maximum length of accepted zapData\n uint256 public constant MAX_ZAP_DATA_LENGTH = 2 ** 16 - 1;\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeTxDetails) public bridgeTxDetails;\n /// @notice Relay details on destination chain\n mapping(bytes32 =\u003e BridgeRelay) public bridgeRelayDetails;\n /// @notice Unique bridge nonces tracked per originSender\n mapping(address =\u003e uint256) public senderNonces;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Replaced by senderNonces\n uint256 public immutable nonce = 0;\n /// @notice the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n bridge({\n params: params,\n paramsV2: BridgeParamsV2({\n quoteRelayer: address(0),\n quoteExclusivitySeconds: 0,\n quoteId: bytes(\"\"),\n zapNative: 0,\n zapData: bytes(\"\")\n })\n });\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes calldata request) external payable {\n // relay override will validate the request\n relay({request: request, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes calldata request, bytes32 destTxHash) external {\n request.validateV2();\n prove({transactionId: keccak256(request), destTxHash: destTxHash, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridgeV2\n function claim(bytes calldata request) external {\n // claim override will validate the request\n claim({request: request, to: address(0)});\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Aggregate the read operations from the same storage slot\n address disputedRelayer = $.proofRelayer;\n BridgeStatus status = $.status;\n uint56 proofBlockTimestamp = $.proofBlockTimestamp;\n // Can only dispute a RELAYER_PROVED transaction within the dispute period\n if (status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(proofBlockTimestamp) \u003e DISPUTE_PERIOD) {\n revert DisputePeriodPassed();\n }\n // Update status to REQUESTED and delete the disputed proof details\n // Note: these are storage writes\n $.status = BridgeStatus.REQUESTED;\n $.proofRelayer = address(0);\n $.proofBlockTimestamp = 0;\n\n emit BridgeProofDisputed(transactionId, disputedRelayer);\n }\n\n /// @inheritdoc IFastBridge\n function refund(bytes calldata request) external {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Can only refund a REQUESTED transaction after its deadline expires\n if ($.status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n uint256 deadline = request.deadline();\n // Permissionless refund is only allowed after REFUND_DELAY on top of the deadline\n if (!hasRole(REFUNDER_ROLE, msg.sender)) deadline += REFUND_DELAY;\n if (block.timestamp \u003c= deadline) revert DeadlineNotExceeded();\n // Update status to REFUNDED and return the full amount (collateral + protocol fees) to the original sender.\n // The protocol fees are only updated when the transaction is claimed, so we don't need to update them here.\n // Note: this is a storage write\n $.status = BridgeStatus.REFUNDED;\n\n address to = request.originSender();\n address token = request.originToken();\n uint256 amount = request.originAmount() + request.originFeeAmount();\n // Emit the event before any external calls\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n // Complete the user refund as the last transaction action\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(to), amount);\n } else {\n IERC20(token).safeTransfer(to, amount);\n }\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // The correct relayer can only claim a RELAYER_PROVED transaction after the dispute period\n if ($.status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if ($.proofRelayer != relayer) revert SenderIncorrect();\n return _timeSince($.proofBlockTimestamp) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n /// @dev This method is added to achieve backwards compatibility with decoding requests into V1 structs:\n /// - `zapNative` is partially reported as a zero/non-zero flag\n /// - `zapData` is ignored\n /// In order to process all kinds of requests use getBridgeTransactionV2 instead.\n function getBridgeTransaction(bytes calldata request) external view returns (BridgeTransaction memory) {\n // Try decoding into V2 struct first. This will revert if V1 struct is passed\n try this.getBridgeTransactionV2(request) returns (BridgeTransactionV2 memory txV2) {\n // Note: we entirely ignore the zapData field, as it was not present in V1\n return BridgeTransaction({\n originChainId: txV2.originChainId,\n destChainId: txV2.destChainId,\n originSender: txV2.originSender,\n destRecipient: txV2.destRecipient,\n originToken: txV2.originToken,\n destToken: txV2.destToken,\n originAmount: txV2.originAmount,\n destAmount: txV2.destAmount,\n originFeeAmount: txV2.originFeeAmount,\n sendChainGas: txV2.zapNative != 0,\n deadline: txV2.deadline,\n nonce: txV2.nonce\n });\n } catch {\n // Fallback to V1 struct\n return abi.decode(request, (BridgeTransaction));\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function getBridgeTransactionV2(bytes calldata request) external pure returns (BridgeTransactionV2 memory) {\n request.validateV2();\n return BridgeTransactionV2Lib.decodeV2(request);\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) public payable {\n int256 exclusivityEndTime = 0;\n // if relayer exclusivity is not intended for this bridge, set exclusivityEndTime to static zero\n // otherwise, set exclusivity to expire at the current block ts offset by quoteExclusivitySeconds\n if (paramsV2.quoteRelayer != address(0)) {\n exclusivityEndTime = int256(block.timestamp) + paramsV2.quoteExclusivitySeconds;\n }\n _validateBridgeParams(params, paramsV2, exclusivityEndTime);\n\n // transfer tokens to bridge contract\n /// @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _takeBridgedUserAsset(params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) {\n originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n }\n\n // set status to requested\n bytes memory request = BridgeTransactionV2Lib.encodeV2(\n BridgeTransactionV2({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n deadline: params.deadline,\n nonce: senderNonces[params.sender]++, // increment nonce on every bridge\n exclusivityRelayer: paramsV2.quoteRelayer,\n // We checked exclusivityEndTime to be in range [0 .. params.deadline] above, so can safely cast\n exclusivityEndTime: uint256(exclusivityEndTime),\n zapNative: paramsV2.zapNative,\n zapData: paramsV2.zapData\n })\n );\n bytes32 transactionId = keccak256(request);\n // Note: the tx status will be updated throughout the tx lifecycle, while destChainId is set once here\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n bridgeTxDetails[transactionId].destChainId = params.dstChainId;\n\n emit BridgeRequested({\n transactionId: transactionId,\n sender: params.sender,\n request: request,\n destChainId: params.dstChainId,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n sendChainGas: paramsV2.zapNative != 0\n });\n emit BridgeQuoteDetails(transactionId, paramsV2.quoteId);\n }\n\n /// @inheritdoc IFastBridgeV2\n function relay(bytes calldata request, address relayer) public payable {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n _validateRelayParams(request, transactionId, relayer);\n // mark bridge transaction as relayed\n bridgeRelayDetails[transactionId] =\n BridgeRelay({blockNumber: uint48(block.number), blockTimestamp: uint48(block.timestamp), relayer: relayer});\n\n // transfer tokens to recipient on destination chain and trigger Zap if requested\n address to = request.destRecipient();\n address token = request.destToken();\n uint256 amount = request.destAmount();\n uint256 zapNative = request.zapNative();\n\n // Emit the event before any external calls\n emit BridgeRelayed({\n transactionId: transactionId,\n relayer: relayer,\n to: to,\n originChainId: request.originChainId(),\n originToken: request.originToken(),\n destToken: token,\n originAmount: request.originAmount(),\n destAmount: amount,\n chainGasAmount: zapNative\n });\n\n // All state changes have been done at this point, can proceed to the external calls.\n // This follows the checks-effects-interactions pattern to mitigate potential reentrancy attacks.\n if (token == NATIVE_GAS_TOKEN) {\n // For the native gas token, additional zapNative is not allowed\n if (zapNative != 0) revert ZapNativeNotSupported();\n // Check that the correct msg.value was sent\n if (msg.value != amount) revert MsgValueIncorrect();\n // Don't do a native transfer yet: we will handle it alongside the Zap below\n } else {\n // For ERC20s, we check that the correct msg.value was sent\n if (msg.value != zapNative) revert MsgValueIncorrect();\n // We need to transfer the tokens from the Relayer to the recipient first before performing an\n // optional post-transfer Zap.\n IERC20(token).safeTransferFrom(msg.sender, to, amount);\n }\n // At this point we have done:\n // - Transferred the requested amount of ERC20 tokens to the recipient.\n // At this point we have confirmed:\n // - For ERC20s: msg.value matches the requested zapNative amount.\n // - For the native gas token: msg.value matches the requested destAmount.\n // Remaining optional things to do:\n // - Forward the full msg.value to the recipient (if non-zero).\n // - Trigger a Zap (if zapData is present).\n bytes calldata zapData = request.zapData();\n if (zapData.length != 0) {\n // Zap Data is present: Zap has been requested by the recipient. Trigger it forwarding the full msg.value.\n\n // Note: if token has a fee on transfers, the recipient will have received less than `amount`.\n // This is a very niche edge case and should be handled by the recipient contract.\n _triggerZapWithChecks({recipient: to, token: token, amount: amount, zapData: zapData});\n } else if (msg.value != 0) {\n // Zap Data is missing, but msg.value was sent. This could happen in two different cases:\n // - Relay with the native gas token is happening.\n // - Relay with ERC20 is happening, with a `zapNative \u003e 0` request.\n // In both cases, we need to transfer the full msg.value to the recipient.\n Address.sendValue(payable(to), msg.value);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) public onlyRole(RELAYER_ROLE) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n\n // Can only prove a REQUESTED transaction\n if ($.status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n // Update status to RELAYER_PROVED and store the proof details\n // Note: these are storage writes\n $.status = BridgeStatus.RELAYER_PROVED;\n $.proofBlockTimestamp = uint56(block.timestamp);\n $.proofRelayer = relayer;\n\n emit BridgeProofProvided(transactionId, relayer, destTxHash);\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes calldata request, address to) public {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Aggregate the read operations from the same storage slot\n address proofRelayer = $.proofRelayer;\n BridgeStatus status = $.status;\n uint56 proofBlockTimestamp = $.proofBlockTimestamp;\n\n // Can only claim a RELAYER_PROVED transaction after the dispute period\n if (status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(proofBlockTimestamp) \u003c= DISPUTE_PERIOD) {\n revert DisputePeriodNotPassed();\n }\n\n if (to == address(0)) {\n // Anyone could claim the funds to the proven relayer on their behalf\n to = proofRelayer;\n } else if (proofRelayer != msg.sender) {\n // Only the proven relayer could specify an address to claim the funds to\n revert SenderIncorrect();\n }\n\n // Update status to RELAYER_CLAIMED and transfer the origin collateral to the specified claim address\n // Note: this is a storage write\n $.status = BridgeStatus.RELAYER_CLAIMED;\n\n address token = request.originToken();\n uint256 amount = request.originAmount();\n // Update protocol fees if origin fee amount exists\n uint256 originFeeAmount = request.originFeeAmount();\n if (originFeeAmount \u003e 0) protocolFees[token] += originFeeAmount;\n // Emit the event before any external calls\n emit BridgeDepositClaimed(transactionId, proofRelayer, to, token, amount);\n // Complete the relayer claim as the last transaction action\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(to), amount);\n } else {\n IERC20(token).safeTransfer(to, amount);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeStatuses(bytes32 transactionId) public view returns (BridgeStatus status) {\n return bridgeTxDetails[transactionId].status;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeProofs(bytes32 transactionId) public view returns (uint96 timestamp, address relayer) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n\n timestamp = $.proofBlockTimestamp;\n relayer = $.proofRelayer;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeRelays(bytes32 transactionId) public view returns (bool) {\n // has this transactionId been relayed?\n return bridgeRelayDetails[transactionId].relayer != address(0);\n }\n\n /// @notice Takes the bridged asset from the user into FastBridgeV2 custody. It will be later\n /// claimed by the relayer who completed the relay on destination chain, or refunded back to the user,\n /// should no one complete the relay.\n function _takeBridgedUserAsset(address token, uint256 amount) internal returns (uint256 amountTaken) {\n if (token == NATIVE_GAS_TOKEN) {\n // For the native gas token, we just need to check that the supplied msg.value is correct.\n // Supplied `msg.value` is already in FastBridgeV2 custody.\n if (amount != msg.value) revert MsgValueIncorrect();\n amountTaken = msg.value;\n } else {\n // For ERC20s, token is explicitly transferred from the user to FastBridgeV2.\n // We don't allow non-zero `msg.value` to avoid extra funds from being stuck in FastBridgeV2.\n if (msg.value != 0) revert MsgValueIncorrect();\n // Throw an explicit error if the provided token address is not a contract\n if (token.code.length == 0) revert TokenNotContract();\n amountTaken = IERC20(token).balanceOf(address(this));\n IERC20(token).safeTransferFrom(msg.sender, address(this), amount);\n // Use the balance difference as the amount taken in case of fee on transfer tokens.\n amountTaken = IERC20(token).balanceOf(address(this)) - amountTaken;\n }\n }\n\n /// @notice Calls the Recipient's hook function with the specified zapData and performs\n /// all the necessary checks for the returned value.\n function _triggerZapWithChecks(address recipient, address token, uint256 amount, bytes calldata zapData) internal {\n // This will bubble any revert messages from the hook function\n bytes memory returnData = Address.functionCallWithValue({\n target: recipient,\n data: abi.encodeCall(IZapRecipient.zap, (token, amount, zapData)),\n // Note: see `relay()` for reasoning behind passing msg.value\n value: msg.value\n });\n // Explicit revert if no return data at all\n if (returnData.length == 0) revert RecipientNoReturnValue();\n // Check that exactly a single return value was returned\n if (returnData.length != 32) revert RecipientIncorrectReturnValue();\n // Return value should be abi-encoded hook function selector\n if (bytes32(returnData) != bytes32(IZapRecipient.zap.selector)) {\n revert RecipientIncorrectReturnValue();\n }\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint56(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint56).max but\n /// proof.timestamp \u003c type(uint56).max via unchecked statement\n /// @param proofBlockTimestamp The bridge proof block timestamp\n /// @return delta Time delta since proof submitted\n function _timeSince(uint56 proofBlockTimestamp) internal view returns (uint256 delta) {\n unchecked {\n delta = uint56(block.timestamp) - proofBlockTimestamp;\n }\n }\n\n /// @notice Performs all the necessary checks for a bridge to happen.\n /// @dev There's no good way to refactor this function to reduce cyclomatic complexity due to\n /// the number of checks that need to be performed, so we skip the code-complexity rule here.\n // solhint-disable-next-line code-complexity\n function _validateBridgeParams(\n BridgeParams memory params,\n BridgeParamsV2 memory paramsV2,\n int256 exclusivityEndTime\n )\n internal\n view\n {\n // Check V1 (legacy) params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.sender == address(0) || params.to == address(0)) revert ZeroAddress();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n // Check V2 params\n if (paramsV2.zapData.length \u003e MAX_ZAP_DATA_LENGTH) revert ZapDataLengthAboveMax();\n if (paramsV2.zapNative != 0 \u0026\u0026 params.destToken == NATIVE_GAS_TOKEN) {\n revert ZapNativeNotSupported();\n }\n // exclusivityEndTime must be in range [0 .. params.deadline]\n if (exclusivityEndTime \u003c 0 || exclusivityEndTime \u003e int256(params.deadline)) {\n revert ExclusivityParamsIncorrect();\n }\n }\n\n /// @notice Performs all the necessary checks for a relay to happen.\n function _validateRelayParams(bytes calldata request, bytes32 transactionId, address relayer) internal view {\n if (relayer == address(0)) revert ZeroAddress();\n // Check if the transaction has already been relayed\n if (bridgeRelays(transactionId)) revert TransactionRelayed();\n if (request.destChainId() != block.chainid) revert ChainIncorrect();\n // Check the deadline for relay to happen\n if (block.timestamp \u003e request.deadline()) revert DeadlineExceeded();\n // Check the exclusivity period, if it is still ongoing\n address exclRelayer = request.exclusivityRelayer();\n if (exclRelayer != address(0) \u0026\u0026 exclRelayer != relayer \u0026\u0026 block.timestamp \u003c= request.exclusivityEndTime()) {\n revert ExclusivityPeriodNotPassed();\n }\n }\n}\n","language":"Solidity","languageVersion":"0.8.24","compilerVersion":"0.8.24","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"","srcMapRuntime":"","abiDefinition":[{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldChainGasAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newChainGasAmount","type":"uint256"}],"name":"ChainGasAmountUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldFeeRate","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newFeeRate","type":"uint256"}],"name":"FeeRateUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"address","name":"recipient","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"FeesSwept","type":"event"},{"inputs":[{"internalType":"uint256","name":"newChainGasAmount","type":"uint256"}],"name":"setChainGasAmount","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"newFeeRate","type":"uint256"}],"name":"setProtocolFeeRate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"address","name":"recipient","type":"address"}],"name":"sweepProtocolFees","outputs":[],"stateMutability":"nonpayable","type":"function"}],"userDoc":{"kind":"user","methods":{},"version":1},"developerDoc":{"kind":"dev","methods":{},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"oldChainGasAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newChainGasAmount\",\"type\":\"uint256\"}],\"name\":\"ChainGasAmountUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"oldFeeRate\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newFeeRate\",\"type\":\"uint256\"}],\"name\":\"FeeRateUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"FeesSwept\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"newChainGasAmount\",\"type\":\"uint256\"}],\"name\":\"setChainGasAmount\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"newFeeRate\",\"type\":\"uint256\"}],\"name\":\"setProtocolFeeRate\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"}],\"name\":\"sweepProtocolFees\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeV2.sol\":\"IAdmin\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeV2.sol\":{\"keccak256\":\"0x5069b55ca07f21bfe30b2a43c18a18318c8af9c181b2dcb07c290825efd70f34\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://273dc020a49d08e50126bbea0d7f783f79d08c702f2fdbc560618d24af308acc\",\"dweb:/ipfs/QmXJ2UVzFc8EPB74RT4CXQPC4xw66jt4T13poyfyd3UERh\"]}},\"version\":1}"},"hashes":{"setChainGasAmount(uint256)":"b250fe6b","setProtocolFeeRate(uint256)":"b13aa2d6","sweepProtocolFees(address,address)":"06f333f2"}},"solidity/FastBridgeV2.sol:IERC165":{"code":"0x","runtime-code":"0x","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.24 ^0.8.20 ^0.8.4;\n\n// contracts/interfaces/IAdmin.sol\n\ninterface IAdmin {\n // ============ Events ============\n\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n event ChainGasAmountUpdated(uint256 oldChainGasAmount, uint256 newChainGasAmount);\n\n // ============ Methods ============\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n\n function setChainGasAmount(uint256 newChainGasAmount) external;\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IFastBridgeV2Errors.sol\n\ninterface IFastBridgeV2Errors {\n error AmountIncorrect();\n error ChainIncorrect();\n error ExclusivityParamsIncorrect();\n error MsgValueIncorrect();\n error SenderIncorrect();\n error StatusIncorrect();\n error TokenNotContract();\n error ZapDataLengthAboveMax();\n error ZapNativeNotSupported();\n error ZeroAddress();\n\n error RecipientIncorrectReturnValue();\n error RecipientNoReturnValue();\n\n error DeadlineExceeded();\n error DeadlineNotExceeded();\n error DeadlineTooShort();\n error DisputePeriodNotPassed();\n error DisputePeriodPassed();\n error ExclusivityPeriodNotPassed();\n\n error TransactionRelayed();\n}\n\n// contracts/interfaces/IMulticallTarget.sol\n\n/// @notice Interface for a contract that can be called multiple times by the same caller. Inspired by MulticallV3:\n/// https://github.com/mds1/multicall/blob/master/src/Multicall3.sol\ninterface IMulticallTarget {\n struct Result {\n bool success;\n bytes returnData;\n }\n\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external;\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results);\n}\n\n// contracts/interfaces/IZapRecipient.sol\n\ninterface IZapRecipient {\n function zap(address token, uint256 amount, bytes memory zapData) external payable returns (bytes4);\n}\n\n// contracts/libs/Errors.sol\n\nerror DeadlineExceeded();\nerror DeadlineNotExceeded();\nerror DeadlineTooShort();\nerror InsufficientOutputAmount();\n\nerror MsgValueIncorrect();\nerror PoolNotFound();\nerror TokenAddressMismatch();\nerror TokenNotContract();\nerror TokenNotETH();\nerror TokensIdentical();\n\nerror ChainIncorrect();\nerror AmountIncorrect();\nerror ZeroAddress();\n\nerror DisputePeriodNotPassed();\nerror DisputePeriodPassed();\nerror SenderIncorrect();\nerror StatusIncorrect();\nerror TransactionIdIncorrect();\nerror TransactionRelayed();\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// contracts/interfaces/IFastBridgeV2.sol\n\ninterface IFastBridgeV2 is IFastBridge {\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n struct BridgeTxDetails {\n BridgeStatus status;\n uint32 destChainId;\n uint56 proofBlockTimestamp;\n address proofRelayer;\n }\n\n struct BridgeRelay {\n uint48 blockNumber;\n uint48 blockTimestamp;\n address relayer;\n }\n\n /// @notice New params introduced in the FastBridgeV2.\n /// We are passing fields from the older BridgeParams struct outside of this struct\n /// for backwards compatibility.\n /// Note: quoteRelayer and quoteExclusivitySeconds are either both zero (indicating no exclusivity)\n /// or both non-zero (indicating exclusivity for the given period).\n /// Note: zapNative \u003e 0 can NOT be used with destToken = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE (native token)\n /// @param quoteRelayer Relayer that provided the quote for the transaction\n /// @param quoteExclusivitySeconds Period of time the quote relayer is guaranteed exclusivity after user's deposit\n /// @param quoteId Unique quote identifier used for tracking the quote\n /// @param zapNative ETH value to send to the recipient (if any)\n /// @param zapData Parameters for the Zap to the destination recipient (if any)\n struct BridgeParamsV2 {\n address quoteRelayer;\n int256 quoteExclusivitySeconds;\n bytes quoteId;\n uint256 zapNative;\n bytes zapData;\n }\n\n /// @notice Updated bridge transaction struct to include parameters introduced in FastBridgeV2.\n /// Note: only `exclusivityRelayer` can fill such a transaction until `exclusivityEndTime`.\n struct BridgeTransactionV2 {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n // Note: sendChainGas flag from V1 is deprecated\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n address exclusivityRelayer;\n uint256 exclusivityEndTime;\n uint256 zapNative; // ETH value to send to the recipient (if any)\n bytes zapData; // data to pass for the Zap action (if any)\n }\n\n event BridgeQuoteDetails(bytes32 indexed transactionId, bytes quoteId);\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability\n /// to provide temporary exclusivity fill rights for the quote relayer.\n /// @param params The parameters required to bridge\n /// @param paramsV2 The parameters for exclusivity fill rights (optional, can be left empty)\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function relay(bytes memory request, address relayer) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param transactionId The transaction id associated with the encoded bridge transaction to prove\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital.\n /// @notice Can only send funds to the relayer address on the proof.\n /// @param request The encoded bridge transaction to claim on origin chain\n function claim(bytes memory request) external;\n /// @notice Checks if a transaction has been relayed\n /// @param transactionId The ID of the transaction to check\n /// @return True if the transaction has been relayed, false otherwise\n function bridgeRelays(bytes32 transactionId) external view returns (bool);\n\n /// @notice Returns the status of a bridge transaction\n /// @param transactionId The ID of the bridge transaction\n /// @return BridgeStatus Status of the bridge transaction\n function bridgeStatuses(bytes32 transactionId) external view returns (BridgeStatus);\n\n /// @notice Returns the timestamp and relayer of a bridge proof\n /// @param transactionId The ID of the bridge transaction\n /// @return timestamp The timestamp of the bridge proof\n /// @return relayer The relayer address of the bridge proof\n function bridgeProofs(bytes32 transactionId) external view returns (uint96 timestamp, address relayer);\n\n /// @notice Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\n /// @param request The bridge request to decode\n function getBridgeTransactionV2(bytes memory request) external view returns (BridgeTransactionV2 memory);\n}\n\n// contracts/utils/MulticallTarget.sol\n\n// solhint-disable avoid-low-level-calls\n/// @notice Template for a contract that supports batched calls (preserving the msg.sender).\n/// Only calls with zero msg.value could be batched.\nabstract contract MulticallTarget is IMulticallTarget {\n error MulticallTarget__UndeterminedRevert();\n\n /// @notice Perform a batched call to this contract, preserving the msg.sender.\n /// The return data from each call is discarded.\n /// @dev The method is non-payable, so only calls with `msg.value == 0` could be batched.\n /// It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag.\n /// Otherwise, the whole batch call will be reverted with the original revert reason.\n /// @param data List of abi-encoded calldata for the calls to perform.\n /// @param ignoreReverts Whether to ignore the revert errors from the calls.\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external {\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\n if (!success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(result);\n }\n }\n }\n\n /// @notice Perform a batched call to this contract, preserving the msg.sender.\n /// The return data from each call is preserved.\n /// @dev The method is non-payable, so only calls with `msg.value == 0` could be batched.\n /// It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag.\n /// Otherwise, the whole batch call will be reverted with the original revert reason.\n /// @param data List of abi-encoded calldata for the calls to perform.\n /// @param ignoreReverts Whether to ignore the revert errors from the calls.\n /// @return results List of results from the calls: `(success, returnData)`.\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results)\n {\n results = new Result[](data.length);\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (results[i].success, results[i].returnData) = address(this).delegatecall(data[i]);\n if (!results[i].success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(results[i].returnData);\n }\n }\n }\n\n /// @dev Bubbles the revert message from the underlying call.\n /// Note: preserves the same custom error or revert string, if one was used.\n /// Source: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v5.0.2/contracts/utils/Address.sol#L143-L158\n function _bubbleRevert(bytes memory returnData) internal pure {\n // Look for revert reason and bubble it up if present\n if (returnData.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n // solhint-disable-next-line no-inline-assembly\n assembly {\n let returndata_size := mload(returnData)\n revert(add(32, returnData), returndata_size)\n }\n } else {\n revert MulticallTarget__UndeterminedRevert();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// contracts/libs/BridgeTransactionV2.sol\n\n// solhint-disable no-inline-assembly\nlibrary BridgeTransactionV2Lib {\n uint16 internal constant VERSION = 2;\n\n // Offsets of the fields in the packed BridgeTransactionV2 struct\n // uint16 version [000 .. 002)\n // uint32 originChainId [002 .. 006)\n // uint32 destChainId [006 .. 010)\n // address originSender [010 .. 030)\n // address destRecipient [030 .. 050)\n // address originToken [050 .. 070)\n // address destToken [070 .. 090)\n // uint256 originAmount [090 .. 122)\n // uint256 destAmount [122 .. 154)\n // uint256 originFeeAmount [154 .. 186)\n // uint256 deadline [186 .. 218)\n // uint256 nonce [218 .. 250)\n // address exclusivityRelayer [250 .. 270)\n // uint256 exclusivityEndTime [270 .. 302)\n // uint256 zapNative [302 .. 334)\n // bytes zapData [334 .. ***)\n\n // forgefmt: disable-start\n uint256 private constant OFFSET_ORIGIN_CHAIN_ID = 2;\n uint256 private constant OFFSET_DEST_CHAIN_ID = 6;\n uint256 private constant OFFSET_ORIGIN_SENDER = 10;\n uint256 private constant OFFSET_DEST_RECIPIENT = 30;\n uint256 private constant OFFSET_ORIGIN_TOKEN = 50;\n uint256 private constant OFFSET_DEST_TOKEN = 70;\n uint256 private constant OFFSET_ORIGIN_AMOUNT = 90;\n uint256 private constant OFFSET_DEST_AMOUNT = 122;\n uint256 private constant OFFSET_ORIGIN_FEE_AMOUNT = 154;\n uint256 private constant OFFSET_DEADLINE = 186;\n uint256 private constant OFFSET_NONCE = 218;\n uint256 private constant OFFSET_EXCLUSIVITY_RELAYER = 250;\n uint256 private constant OFFSET_EXCLUSIVITY_END_TIME = 270;\n uint256 private constant OFFSET_ZAP_NATIVE = 302;\n uint256 private constant OFFSET_ZAP_DATA = 334;\n // forgefmt: disable-end\n\n error BridgeTransactionV2__InvalidEncodedTx();\n error BridgeTransactionV2__UnsupportedVersion(uint16 version);\n\n /// @notice Validates the encoded transaction to be a tightly packed encoded payload for BridgeTransactionV2.\n /// @dev Checks the minimum length and the version, use this function before decoding any of the fields.\n function validateV2(bytes calldata encodedTx) internal pure {\n // Check the minimum length: must at least include all static fields.\n if (encodedTx.length \u003c OFFSET_ZAP_DATA) revert BridgeTransactionV2__InvalidEncodedTx();\n // Once we validated the length, we can be sure that the version field is present.\n uint16 version_ = version(encodedTx);\n if (version_ != VERSION) revert BridgeTransactionV2__UnsupportedVersion(version_);\n }\n\n /// @notice Encodes the BridgeTransactionV2 struct by tightly packing the fields.\n /// @dev `abi.decode` will not work as a result of the tightly packed fields. Use `decodeV2` to decode instead.\n function encodeV2(IFastBridgeV2.BridgeTransactionV2 memory bridgeTx) internal pure returns (bytes memory) {\n // We split the encoding into two parts to avoid stack-too-deep error\n bytes memory firstPart = abi.encodePacked(\n VERSION,\n bridgeTx.originChainId,\n bridgeTx.destChainId,\n bridgeTx.originSender,\n bridgeTx.destRecipient,\n bridgeTx.originToken,\n bridgeTx.destToken,\n bridgeTx.originAmount\n );\n return abi.encodePacked(\n firstPart,\n bridgeTx.destAmount,\n bridgeTx.originFeeAmount,\n // Note: we skip the deprecated `sendChainGas` flag, which was present in BridgeTransaction V1\n bridgeTx.deadline,\n bridgeTx.nonce,\n // New V2 fields: exclusivity\n bridgeTx.exclusivityRelayer,\n bridgeTx.exclusivityEndTime,\n // New V2 fields: Zap\n bridgeTx.zapNative,\n bridgeTx.zapData\n );\n }\n\n /// @notice Decodes the BridgeTransactionV2 struct from the encoded transaction.\n /// @dev Encoded BridgeTransactionV2 struct must be tightly packed.\n /// Use `validateV2` before decoding to ensure the encoded transaction is valid.\n function decodeV2(bytes calldata encodedTx)\n internal\n pure\n returns (IFastBridgeV2.BridgeTransactionV2 memory bridgeTx)\n {\n bridgeTx.originChainId = originChainId(encodedTx);\n bridgeTx.destChainId = destChainId(encodedTx);\n bridgeTx.originSender = originSender(encodedTx);\n bridgeTx.destRecipient = destRecipient(encodedTx);\n bridgeTx.originToken = originToken(encodedTx);\n bridgeTx.destToken = destToken(encodedTx);\n bridgeTx.originAmount = originAmount(encodedTx);\n bridgeTx.destAmount = destAmount(encodedTx);\n bridgeTx.originFeeAmount = originFeeAmount(encodedTx);\n bridgeTx.deadline = deadline(encodedTx);\n bridgeTx.nonce = nonce(encodedTx);\n bridgeTx.exclusivityRelayer = exclusivityRelayer(encodedTx);\n bridgeTx.exclusivityEndTime = exclusivityEndTime(encodedTx);\n bridgeTx.zapNative = zapNative(encodedTx);\n bridgeTx.zapData = zapData(encodedTx);\n }\n\n /// @notice Extracts the version from the encoded transaction.\n function version(bytes calldata encodedTx) internal pure returns (uint16 version_) {\n // Load 32 bytes from the start and shift it 240 bits to the right to get the highest 16 bits.\n assembly {\n version_ := shr(240, calldataload(encodedTx.offset))\n }\n }\n\n /// @notice Extracts the origin chain ID from the encoded transaction.\n function originChainId(bytes calldata encodedTx) internal pure returns (uint32 originChainId_) {\n // Load 32 bytes from the offset and shift it 224 bits to the right to get the highest 32 bits.\n assembly {\n originChainId_ := shr(224, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_CHAIN_ID)))\n }\n }\n\n /// @notice Extracts the destination chain ID from the encoded transaction.\n function destChainId(bytes calldata encodedTx) internal pure returns (uint32 destChainId_) {\n // Load 32 bytes from the offset and shift it 224 bits to the right to get the highest 32 bits.\n assembly {\n destChainId_ := shr(224, calldataload(add(encodedTx.offset, OFFSET_DEST_CHAIN_ID)))\n }\n }\n\n /// @notice Extracts the origin sender from the encoded transaction.\n function originSender(bytes calldata encodedTx) internal pure returns (address originSender_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n originSender_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_SENDER)))\n }\n }\n\n /// @notice Extracts the destination recipient from the encoded transaction.\n function destRecipient(bytes calldata encodedTx) internal pure returns (address destRecipient_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n destRecipient_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_DEST_RECIPIENT)))\n }\n }\n\n /// @notice Extracts the origin token from the encoded transaction.\n function originToken(bytes calldata encodedTx) internal pure returns (address originToken_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n originToken_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_TOKEN)))\n }\n }\n\n /// @notice Extracts the destination token from the encoded transaction.\n function destToken(bytes calldata encodedTx) internal pure returns (address destToken_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n destToken_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_DEST_TOKEN)))\n }\n }\n\n /// @notice Extracts the origin amount from the encoded transaction.\n function originAmount(bytes calldata encodedTx) internal pure returns (uint256 originAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n originAmount_ := calldataload(add(encodedTx.offset, OFFSET_ORIGIN_AMOUNT))\n }\n }\n\n /// @notice Extracts the destination amount from the encoded transaction.\n function destAmount(bytes calldata encodedTx) internal pure returns (uint256 destAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n destAmount_ := calldataload(add(encodedTx.offset, OFFSET_DEST_AMOUNT))\n }\n }\n\n /// @notice Extracts the origin fee amount from the encoded transaction.\n function originFeeAmount(bytes calldata encodedTx) internal pure returns (uint256 originFeeAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n originFeeAmount_ := calldataload(add(encodedTx.offset, OFFSET_ORIGIN_FEE_AMOUNT))\n }\n }\n\n /// @notice Extracts the deadline from the encoded transaction.\n function deadline(bytes calldata encodedTx) internal pure returns (uint256 deadline_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n deadline_ := calldataload(add(encodedTx.offset, OFFSET_DEADLINE))\n }\n }\n\n /// @notice Extracts the nonce from the encoded transaction.\n function nonce(bytes calldata encodedTx) internal pure returns (uint256 nonce_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n nonce_ := calldataload(add(encodedTx.offset, OFFSET_NONCE))\n }\n }\n\n /// @notice Extracts the exclusivity relayer from the encoded transaction.\n function exclusivityRelayer(bytes calldata encodedTx) internal pure returns (address exclusivityRelayer_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n exclusivityRelayer_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_EXCLUSIVITY_RELAYER)))\n }\n }\n\n /// @notice Extracts the exclusivity end time from the encoded transaction.\n function exclusivityEndTime(bytes calldata encodedTx) internal pure returns (uint256 exclusivityEndTime_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n exclusivityEndTime_ := calldataload(add(encodedTx.offset, OFFSET_EXCLUSIVITY_END_TIME))\n }\n }\n\n /// @notice Extracts the Zap's native value from the encoded transaction.\n function zapNative(bytes calldata encodedTx) internal pure returns (uint256 zapNative_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n zapNative_ := calldataload(add(encodedTx.offset, OFFSET_ZAP_NATIVE))\n }\n }\n\n /// @notice Extracts the Zap's data from the encoded transaction.\n function zapData(bytes calldata encodedTx) internal pure returns (bytes calldata zapData_) {\n zapData_ = encodedTx[OFFSET_ZAP_DATA:];\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// contracts/libs/UniversalToken.sol\n\nlibrary UniversalTokenLib {\n using SafeERC20 for IERC20;\n\n address internal constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Transfers tokens to the given account. Reverts if transfer is not successful.\n /// @dev This might trigger fallback, if ETH is transferred to the contract.\n /// Make sure this can not lead to reentrancy attacks.\n function universalTransfer(address token, address to, uint256 value) internal {\n // Don't do anything, if need to send tokens to this address\n if (to == address(this)) return;\n // Don't do anything, if trying to send zero value\n if (value == 0) return;\n if (token == ETH_ADDRESS) {\n /// @dev Note: this can potentially lead to executing code in `to`.\n // solhint-disable-next-line avoid-low-level-calls\n (bool success,) = to.call{value: value}(\"\");\n require(success, \"ETH transfer failed\");\n } else {\n IERC20(token).safeTransfer(to, value);\n }\n }\n\n /// @notice Issues an infinite allowance to the spender, if the current allowance is insufficient\n /// to spend the given amount.\n function universalApproveInfinity(address token, address spender, uint256 amountToSpend) internal {\n // ETH Chad doesn't require your approval\n if (token == ETH_ADDRESS) return;\n // No-op if allowance is already sufficient\n uint256 allowance = IERC20(token).allowance(address(this), spender);\n if (allowance \u003e= amountToSpend) return;\n // Otherwise, reset approval to 0 and set to max allowance\n if (allowance \u003e 0) IERC20(token).safeDecreaseAllowance(spender, allowance);\n IERC20(token).safeIncreaseAllowance(spender, type(uint256).max);\n }\n\n /// @notice Returns the balance of the given token (or native ETH) for the given account.\n function universalBalanceOf(address token, address account) internal view returns (uint256) {\n if (token == ETH_ADDRESS) {\n return account.balance;\n } else {\n return IERC20(token).balanceOf(account);\n }\n }\n\n /// @dev Checks that token is a contract and not ETH_ADDRESS.\n function assertIsContract(address token) internal view {\n // Check that ETH_ADDRESS was not used (in case this is a predeploy on any of the chains)\n if (token == UniversalTokenLib.ETH_ADDRESS) revert TokenNotContract();\n // Check that token is not an EOA\n if (token.code.length == 0) revert TokenNotContract();\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/Admin.sol\n\ncontract Admin is IAdmin, AccessControlEnumerable {\n using UniversalTokenLib for address;\n\n bytes32 public constant RELAYER_ROLE = keccak256(\"RELAYER_ROLE\");\n bytes32 public constant REFUNDER_ROLE = keccak256(\"REFUNDER_ROLE\");\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n uint256 public constant FEE_BPS = 1e6;\n uint256 public constant FEE_RATE_MAX = 0.01e6; // max 1% on origin amount\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Chain gas amount to forward as rebate if requested\n uint256 public chainGasAmount;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n }\n\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n require(newFeeRate \u003c= FEE_RATE_MAX, \"newFeeRate \u003e max\");\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n token.universalTransfer(recipient, feeAmount);\n emit FeesSwept(token, recipient, feeAmount);\n }\n\n function setChainGasAmount(uint256 newChainGasAmount) external onlyRole(GOVERNOR_ROLE) {\n uint256 oldChainGasAmount = chainGasAmount;\n chainGasAmount = newChainGasAmount;\n emit ChainGasAmountUpdated(oldChainGasAmount, newChainGasAmount);\n }\n}\n\n// contracts/FastBridgeV2.sol\n\n/// @notice FastBridgeV2 is a contract for bridging tokens across chains.\ncontract FastBridgeV2 is Admin, MulticallTarget, IFastBridgeV2, IFastBridgeV2Errors {\n using BridgeTransactionV2Lib for bytes;\n using SafeERC20 for IERC20;\n\n /// @notice Address reserved for native gas token (ETH on Ethereum and most L2s, AVAX on Avalanche, etc)\n address public constant NATIVE_GAS_TOKEN = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Delay for a transaction after which it could be permisionlessly refunded\n uint256 public constant REFUND_DELAY = 7 days;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n /// @notice Maximum length of accepted zapData\n uint256 public constant MAX_ZAP_DATA_LENGTH = 2 ** 16 - 1;\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeTxDetails) public bridgeTxDetails;\n /// @notice Relay details on destination chain\n mapping(bytes32 =\u003e BridgeRelay) public bridgeRelayDetails;\n /// @notice Unique bridge nonces tracked per originSender\n mapping(address =\u003e uint256) public senderNonces;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Replaced by senderNonces\n uint256 public immutable nonce = 0;\n /// @notice the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n bridge({\n params: params,\n paramsV2: BridgeParamsV2({\n quoteRelayer: address(0),\n quoteExclusivitySeconds: 0,\n quoteId: bytes(\"\"),\n zapNative: 0,\n zapData: bytes(\"\")\n })\n });\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes calldata request) external payable {\n // relay override will validate the request\n relay({request: request, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes calldata request, bytes32 destTxHash) external {\n request.validateV2();\n prove({transactionId: keccak256(request), destTxHash: destTxHash, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridgeV2\n function claim(bytes calldata request) external {\n // claim override will validate the request\n claim({request: request, to: address(0)});\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Aggregate the read operations from the same storage slot\n address disputedRelayer = $.proofRelayer;\n BridgeStatus status = $.status;\n uint56 proofBlockTimestamp = $.proofBlockTimestamp;\n // Can only dispute a RELAYER_PROVED transaction within the dispute period\n if (status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(proofBlockTimestamp) \u003e DISPUTE_PERIOD) {\n revert DisputePeriodPassed();\n }\n // Update status to REQUESTED and delete the disputed proof details\n // Note: these are storage writes\n $.status = BridgeStatus.REQUESTED;\n $.proofRelayer = address(0);\n $.proofBlockTimestamp = 0;\n\n emit BridgeProofDisputed(transactionId, disputedRelayer);\n }\n\n /// @inheritdoc IFastBridge\n function refund(bytes calldata request) external {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Can only refund a REQUESTED transaction after its deadline expires\n if ($.status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n uint256 deadline = request.deadline();\n // Permissionless refund is only allowed after REFUND_DELAY on top of the deadline\n if (!hasRole(REFUNDER_ROLE, msg.sender)) deadline += REFUND_DELAY;\n if (block.timestamp \u003c= deadline) revert DeadlineNotExceeded();\n // Update status to REFUNDED and return the full amount (collateral + protocol fees) to the original sender.\n // The protocol fees are only updated when the transaction is claimed, so we don't need to update them here.\n // Note: this is a storage write\n $.status = BridgeStatus.REFUNDED;\n\n address to = request.originSender();\n address token = request.originToken();\n uint256 amount = request.originAmount() + request.originFeeAmount();\n // Emit the event before any external calls\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n // Complete the user refund as the last transaction action\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(to), amount);\n } else {\n IERC20(token).safeTransfer(to, amount);\n }\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // The correct relayer can only claim a RELAYER_PROVED transaction after the dispute period\n if ($.status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if ($.proofRelayer != relayer) revert SenderIncorrect();\n return _timeSince($.proofBlockTimestamp) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n /// @dev This method is added to achieve backwards compatibility with decoding requests into V1 structs:\n /// - `zapNative` is partially reported as a zero/non-zero flag\n /// - `zapData` is ignored\n /// In order to process all kinds of requests use getBridgeTransactionV2 instead.\n function getBridgeTransaction(bytes calldata request) external view returns (BridgeTransaction memory) {\n // Try decoding into V2 struct first. This will revert if V1 struct is passed\n try this.getBridgeTransactionV2(request) returns (BridgeTransactionV2 memory txV2) {\n // Note: we entirely ignore the zapData field, as it was not present in V1\n return BridgeTransaction({\n originChainId: txV2.originChainId,\n destChainId: txV2.destChainId,\n originSender: txV2.originSender,\n destRecipient: txV2.destRecipient,\n originToken: txV2.originToken,\n destToken: txV2.destToken,\n originAmount: txV2.originAmount,\n destAmount: txV2.destAmount,\n originFeeAmount: txV2.originFeeAmount,\n sendChainGas: txV2.zapNative != 0,\n deadline: txV2.deadline,\n nonce: txV2.nonce\n });\n } catch {\n // Fallback to V1 struct\n return abi.decode(request, (BridgeTransaction));\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function getBridgeTransactionV2(bytes calldata request) external pure returns (BridgeTransactionV2 memory) {\n request.validateV2();\n return BridgeTransactionV2Lib.decodeV2(request);\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) public payable {\n int256 exclusivityEndTime = 0;\n // if relayer exclusivity is not intended for this bridge, set exclusivityEndTime to static zero\n // otherwise, set exclusivity to expire at the current block ts offset by quoteExclusivitySeconds\n if (paramsV2.quoteRelayer != address(0)) {\n exclusivityEndTime = int256(block.timestamp) + paramsV2.quoteExclusivitySeconds;\n }\n _validateBridgeParams(params, paramsV2, exclusivityEndTime);\n\n // transfer tokens to bridge contract\n /// @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _takeBridgedUserAsset(params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) {\n originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n }\n\n // set status to requested\n bytes memory request = BridgeTransactionV2Lib.encodeV2(\n BridgeTransactionV2({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n deadline: params.deadline,\n nonce: senderNonces[params.sender]++, // increment nonce on every bridge\n exclusivityRelayer: paramsV2.quoteRelayer,\n // We checked exclusivityEndTime to be in range [0 .. params.deadline] above, so can safely cast\n exclusivityEndTime: uint256(exclusivityEndTime),\n zapNative: paramsV2.zapNative,\n zapData: paramsV2.zapData\n })\n );\n bytes32 transactionId = keccak256(request);\n // Note: the tx status will be updated throughout the tx lifecycle, while destChainId is set once here\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n bridgeTxDetails[transactionId].destChainId = params.dstChainId;\n\n emit BridgeRequested({\n transactionId: transactionId,\n sender: params.sender,\n request: request,\n destChainId: params.dstChainId,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n sendChainGas: paramsV2.zapNative != 0\n });\n emit BridgeQuoteDetails(transactionId, paramsV2.quoteId);\n }\n\n /// @inheritdoc IFastBridgeV2\n function relay(bytes calldata request, address relayer) public payable {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n _validateRelayParams(request, transactionId, relayer);\n // mark bridge transaction as relayed\n bridgeRelayDetails[transactionId] =\n BridgeRelay({blockNumber: uint48(block.number), blockTimestamp: uint48(block.timestamp), relayer: relayer});\n\n // transfer tokens to recipient on destination chain and trigger Zap if requested\n address to = request.destRecipient();\n address token = request.destToken();\n uint256 amount = request.destAmount();\n uint256 zapNative = request.zapNative();\n\n // Emit the event before any external calls\n emit BridgeRelayed({\n transactionId: transactionId,\n relayer: relayer,\n to: to,\n originChainId: request.originChainId(),\n originToken: request.originToken(),\n destToken: token,\n originAmount: request.originAmount(),\n destAmount: amount,\n chainGasAmount: zapNative\n });\n\n // All state changes have been done at this point, can proceed to the external calls.\n // This follows the checks-effects-interactions pattern to mitigate potential reentrancy attacks.\n if (token == NATIVE_GAS_TOKEN) {\n // For the native gas token, additional zapNative is not allowed\n if (zapNative != 0) revert ZapNativeNotSupported();\n // Check that the correct msg.value was sent\n if (msg.value != amount) revert MsgValueIncorrect();\n // Don't do a native transfer yet: we will handle it alongside the Zap below\n } else {\n // For ERC20s, we check that the correct msg.value was sent\n if (msg.value != zapNative) revert MsgValueIncorrect();\n // We need to transfer the tokens from the Relayer to the recipient first before performing an\n // optional post-transfer Zap.\n IERC20(token).safeTransferFrom(msg.sender, to, amount);\n }\n // At this point we have done:\n // - Transferred the requested amount of ERC20 tokens to the recipient.\n // At this point we have confirmed:\n // - For ERC20s: msg.value matches the requested zapNative amount.\n // - For the native gas token: msg.value matches the requested destAmount.\n // Remaining optional things to do:\n // - Forward the full msg.value to the recipient (if non-zero).\n // - Trigger a Zap (if zapData is present).\n bytes calldata zapData = request.zapData();\n if (zapData.length != 0) {\n // Zap Data is present: Zap has been requested by the recipient. Trigger it forwarding the full msg.value.\n\n // Note: if token has a fee on transfers, the recipient will have received less than `amount`.\n // This is a very niche edge case and should be handled by the recipient contract.\n _triggerZapWithChecks({recipient: to, token: token, amount: amount, zapData: zapData});\n } else if (msg.value != 0) {\n // Zap Data is missing, but msg.value was sent. This could happen in two different cases:\n // - Relay with the native gas token is happening.\n // - Relay with ERC20 is happening, with a `zapNative \u003e 0` request.\n // In both cases, we need to transfer the full msg.value to the recipient.\n Address.sendValue(payable(to), msg.value);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) public onlyRole(RELAYER_ROLE) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n\n // Can only prove a REQUESTED transaction\n if ($.status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n // Update status to RELAYER_PROVED and store the proof details\n // Note: these are storage writes\n $.status = BridgeStatus.RELAYER_PROVED;\n $.proofBlockTimestamp = uint56(block.timestamp);\n $.proofRelayer = relayer;\n\n emit BridgeProofProvided(transactionId, relayer, destTxHash);\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes calldata request, address to) public {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Aggregate the read operations from the same storage slot\n address proofRelayer = $.proofRelayer;\n BridgeStatus status = $.status;\n uint56 proofBlockTimestamp = $.proofBlockTimestamp;\n\n // Can only claim a RELAYER_PROVED transaction after the dispute period\n if (status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(proofBlockTimestamp) \u003c= DISPUTE_PERIOD) {\n revert DisputePeriodNotPassed();\n }\n\n if (to == address(0)) {\n // Anyone could claim the funds to the proven relayer on their behalf\n to = proofRelayer;\n } else if (proofRelayer != msg.sender) {\n // Only the proven relayer could specify an address to claim the funds to\n revert SenderIncorrect();\n }\n\n // Update status to RELAYER_CLAIMED and transfer the origin collateral to the specified claim address\n // Note: this is a storage write\n $.status = BridgeStatus.RELAYER_CLAIMED;\n\n address token = request.originToken();\n uint256 amount = request.originAmount();\n // Update protocol fees if origin fee amount exists\n uint256 originFeeAmount = request.originFeeAmount();\n if (originFeeAmount \u003e 0) protocolFees[token] += originFeeAmount;\n // Emit the event before any external calls\n emit BridgeDepositClaimed(transactionId, proofRelayer, to, token, amount);\n // Complete the relayer claim as the last transaction action\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(to), amount);\n } else {\n IERC20(token).safeTransfer(to, amount);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeStatuses(bytes32 transactionId) public view returns (BridgeStatus status) {\n return bridgeTxDetails[transactionId].status;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeProofs(bytes32 transactionId) public view returns (uint96 timestamp, address relayer) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n\n timestamp = $.proofBlockTimestamp;\n relayer = $.proofRelayer;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeRelays(bytes32 transactionId) public view returns (bool) {\n // has this transactionId been relayed?\n return bridgeRelayDetails[transactionId].relayer != address(0);\n }\n\n /// @notice Takes the bridged asset from the user into FastBridgeV2 custody. It will be later\n /// claimed by the relayer who completed the relay on destination chain, or refunded back to the user,\n /// should no one complete the relay.\n function _takeBridgedUserAsset(address token, uint256 amount) internal returns (uint256 amountTaken) {\n if (token == NATIVE_GAS_TOKEN) {\n // For the native gas token, we just need to check that the supplied msg.value is correct.\n // Supplied `msg.value` is already in FastBridgeV2 custody.\n if (amount != msg.value) revert MsgValueIncorrect();\n amountTaken = msg.value;\n } else {\n // For ERC20s, token is explicitly transferred from the user to FastBridgeV2.\n // We don't allow non-zero `msg.value` to avoid extra funds from being stuck in FastBridgeV2.\n if (msg.value != 0) revert MsgValueIncorrect();\n // Throw an explicit error if the provided token address is not a contract\n if (token.code.length == 0) revert TokenNotContract();\n amountTaken = IERC20(token).balanceOf(address(this));\n IERC20(token).safeTransferFrom(msg.sender, address(this), amount);\n // Use the balance difference as the amount taken in case of fee on transfer tokens.\n amountTaken = IERC20(token).balanceOf(address(this)) - amountTaken;\n }\n }\n\n /// @notice Calls the Recipient's hook function with the specified zapData and performs\n /// all the necessary checks for the returned value.\n function _triggerZapWithChecks(address recipient, address token, uint256 amount, bytes calldata zapData) internal {\n // This will bubble any revert messages from the hook function\n bytes memory returnData = Address.functionCallWithValue({\n target: recipient,\n data: abi.encodeCall(IZapRecipient.zap, (token, amount, zapData)),\n // Note: see `relay()` for reasoning behind passing msg.value\n value: msg.value\n });\n // Explicit revert if no return data at all\n if (returnData.length == 0) revert RecipientNoReturnValue();\n // Check that exactly a single return value was returned\n if (returnData.length != 32) revert RecipientIncorrectReturnValue();\n // Return value should be abi-encoded hook function selector\n if (bytes32(returnData) != bytes32(IZapRecipient.zap.selector)) {\n revert RecipientIncorrectReturnValue();\n }\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint56(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint56).max but\n /// proof.timestamp \u003c type(uint56).max via unchecked statement\n /// @param proofBlockTimestamp The bridge proof block timestamp\n /// @return delta Time delta since proof submitted\n function _timeSince(uint56 proofBlockTimestamp) internal view returns (uint256 delta) {\n unchecked {\n delta = uint56(block.timestamp) - proofBlockTimestamp;\n }\n }\n\n /// @notice Performs all the necessary checks for a bridge to happen.\n /// @dev There's no good way to refactor this function to reduce cyclomatic complexity due to\n /// the number of checks that need to be performed, so we skip the code-complexity rule here.\n // solhint-disable-next-line code-complexity\n function _validateBridgeParams(\n BridgeParams memory params,\n BridgeParamsV2 memory paramsV2,\n int256 exclusivityEndTime\n )\n internal\n view\n {\n // Check V1 (legacy) params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.sender == address(0) || params.to == address(0)) revert ZeroAddress();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n // Check V2 params\n if (paramsV2.zapData.length \u003e MAX_ZAP_DATA_LENGTH) revert ZapDataLengthAboveMax();\n if (paramsV2.zapNative != 0 \u0026\u0026 params.destToken == NATIVE_GAS_TOKEN) {\n revert ZapNativeNotSupported();\n }\n // exclusivityEndTime must be in range [0 .. params.deadline]\n if (exclusivityEndTime \u003c 0 || exclusivityEndTime \u003e int256(params.deadline)) {\n revert ExclusivityParamsIncorrect();\n }\n }\n\n /// @notice Performs all the necessary checks for a relay to happen.\n function _validateRelayParams(bytes calldata request, bytes32 transactionId, address relayer) internal view {\n if (relayer == address(0)) revert ZeroAddress();\n // Check if the transaction has already been relayed\n if (bridgeRelays(transactionId)) revert TransactionRelayed();\n if (request.destChainId() != block.chainid) revert ChainIncorrect();\n // Check the deadline for relay to happen\n if (block.timestamp \u003e request.deadline()) revert DeadlineExceeded();\n // Check the exclusivity period, if it is still ongoing\n address exclRelayer = request.exclusivityRelayer();\n if (exclRelayer != address(0) \u0026\u0026 exclRelayer != relayer \u0026\u0026 block.timestamp \u003c= request.exclusivityEndTime()) {\n revert ExclusivityPeriodNotPassed();\n }\n }\n}\n","language":"Solidity","languageVersion":"0.8.24","compilerVersion":"0.8.24","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"","srcMapRuntime":"","abiDefinition":[{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"}],"userDoc":{"kind":"user","methods":{},"version":1},"developerDoc":{"details":"Interface of the ERC165 standard, as defined in the https://eips.ethereum.org/EIPS/eip-165[EIP]. Implementers can declare support of contract interfaces, which can then be queried by others ({ERC165Checker}). For an implementation, see {ERC165}.","kind":"dev","methods":{"supportsInterface(bytes4)":{"details":"Returns true if this contract implements the interface defined by `interfaceId`. See the corresponding https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section] to learn more about how these ids are created. This function call must use less than 30 000 gas."}},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"bytes4\",\"name\":\"interfaceId\",\"type\":\"bytes4\"}],\"name\":\"supportsInterface\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"}],\"devdoc\":{\"details\":\"Interface of the ERC165 standard, as defined in the https://eips.ethereum.org/EIPS/eip-165[EIP]. Implementers can declare support of contract interfaces, which can then be queried by others ({ERC165Checker}). For an implementation, see {ERC165}.\",\"kind\":\"dev\",\"methods\":{\"supportsInterface(bytes4)\":{\"details\":\"Returns true if this contract implements the interface defined by `interfaceId`. See the corresponding https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section] to learn more about how these ids are created. This function call must use less than 30 000 gas.\"}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeV2.sol\":\"IERC165\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeV2.sol\":{\"keccak256\":\"0x5069b55ca07f21bfe30b2a43c18a18318c8af9c181b2dcb07c290825efd70f34\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://273dc020a49d08e50126bbea0d7f783f79d08c702f2fdbc560618d24af308acc\",\"dweb:/ipfs/QmXJ2UVzFc8EPB74RT4CXQPC4xw66jt4T13poyfyd3UERh\"]}},\"version\":1}"},"hashes":{"supportsInterface(bytes4)":"01ffc9a7"}},"solidity/FastBridgeV2.sol:IERC20":{"code":"0x","runtime-code":"0x","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.24 ^0.8.20 ^0.8.4;\n\n// contracts/interfaces/IAdmin.sol\n\ninterface IAdmin {\n // ============ Events ============\n\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n event ChainGasAmountUpdated(uint256 oldChainGasAmount, uint256 newChainGasAmount);\n\n // ============ Methods ============\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n\n function setChainGasAmount(uint256 newChainGasAmount) external;\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IFastBridgeV2Errors.sol\n\ninterface IFastBridgeV2Errors {\n error AmountIncorrect();\n error ChainIncorrect();\n error ExclusivityParamsIncorrect();\n error MsgValueIncorrect();\n error SenderIncorrect();\n error StatusIncorrect();\n error TokenNotContract();\n error ZapDataLengthAboveMax();\n error ZapNativeNotSupported();\n error ZeroAddress();\n\n error RecipientIncorrectReturnValue();\n error RecipientNoReturnValue();\n\n error DeadlineExceeded();\n error DeadlineNotExceeded();\n error DeadlineTooShort();\n error DisputePeriodNotPassed();\n error DisputePeriodPassed();\n error ExclusivityPeriodNotPassed();\n\n error TransactionRelayed();\n}\n\n// contracts/interfaces/IMulticallTarget.sol\n\n/// @notice Interface for a contract that can be called multiple times by the same caller. Inspired by MulticallV3:\n/// https://github.com/mds1/multicall/blob/master/src/Multicall3.sol\ninterface IMulticallTarget {\n struct Result {\n bool success;\n bytes returnData;\n }\n\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external;\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results);\n}\n\n// contracts/interfaces/IZapRecipient.sol\n\ninterface IZapRecipient {\n function zap(address token, uint256 amount, bytes memory zapData) external payable returns (bytes4);\n}\n\n// contracts/libs/Errors.sol\n\nerror DeadlineExceeded();\nerror DeadlineNotExceeded();\nerror DeadlineTooShort();\nerror InsufficientOutputAmount();\n\nerror MsgValueIncorrect();\nerror PoolNotFound();\nerror TokenAddressMismatch();\nerror TokenNotContract();\nerror TokenNotETH();\nerror TokensIdentical();\n\nerror ChainIncorrect();\nerror AmountIncorrect();\nerror ZeroAddress();\n\nerror DisputePeriodNotPassed();\nerror DisputePeriodPassed();\nerror SenderIncorrect();\nerror StatusIncorrect();\nerror TransactionIdIncorrect();\nerror TransactionRelayed();\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// contracts/interfaces/IFastBridgeV2.sol\n\ninterface IFastBridgeV2 is IFastBridge {\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n struct BridgeTxDetails {\n BridgeStatus status;\n uint32 destChainId;\n uint56 proofBlockTimestamp;\n address proofRelayer;\n }\n\n struct BridgeRelay {\n uint48 blockNumber;\n uint48 blockTimestamp;\n address relayer;\n }\n\n /// @notice New params introduced in the FastBridgeV2.\n /// We are passing fields from the older BridgeParams struct outside of this struct\n /// for backwards compatibility.\n /// Note: quoteRelayer and quoteExclusivitySeconds are either both zero (indicating no exclusivity)\n /// or both non-zero (indicating exclusivity for the given period).\n /// Note: zapNative \u003e 0 can NOT be used with destToken = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE (native token)\n /// @param quoteRelayer Relayer that provided the quote for the transaction\n /// @param quoteExclusivitySeconds Period of time the quote relayer is guaranteed exclusivity after user's deposit\n /// @param quoteId Unique quote identifier used for tracking the quote\n /// @param zapNative ETH value to send to the recipient (if any)\n /// @param zapData Parameters for the Zap to the destination recipient (if any)\n struct BridgeParamsV2 {\n address quoteRelayer;\n int256 quoteExclusivitySeconds;\n bytes quoteId;\n uint256 zapNative;\n bytes zapData;\n }\n\n /// @notice Updated bridge transaction struct to include parameters introduced in FastBridgeV2.\n /// Note: only `exclusivityRelayer` can fill such a transaction until `exclusivityEndTime`.\n struct BridgeTransactionV2 {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n // Note: sendChainGas flag from V1 is deprecated\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n address exclusivityRelayer;\n uint256 exclusivityEndTime;\n uint256 zapNative; // ETH value to send to the recipient (if any)\n bytes zapData; // data to pass for the Zap action (if any)\n }\n\n event BridgeQuoteDetails(bytes32 indexed transactionId, bytes quoteId);\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability\n /// to provide temporary exclusivity fill rights for the quote relayer.\n /// @param params The parameters required to bridge\n /// @param paramsV2 The parameters for exclusivity fill rights (optional, can be left empty)\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function relay(bytes memory request, address relayer) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param transactionId The transaction id associated with the encoded bridge transaction to prove\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital.\n /// @notice Can only send funds to the relayer address on the proof.\n /// @param request The encoded bridge transaction to claim on origin chain\n function claim(bytes memory request) external;\n /// @notice Checks if a transaction has been relayed\n /// @param transactionId The ID of the transaction to check\n /// @return True if the transaction has been relayed, false otherwise\n function bridgeRelays(bytes32 transactionId) external view returns (bool);\n\n /// @notice Returns the status of a bridge transaction\n /// @param transactionId The ID of the bridge transaction\n /// @return BridgeStatus Status of the bridge transaction\n function bridgeStatuses(bytes32 transactionId) external view returns (BridgeStatus);\n\n /// @notice Returns the timestamp and relayer of a bridge proof\n /// @param transactionId The ID of the bridge transaction\n /// @return timestamp The timestamp of the bridge proof\n /// @return relayer The relayer address of the bridge proof\n function bridgeProofs(bytes32 transactionId) external view returns (uint96 timestamp, address relayer);\n\n /// @notice Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\n /// @param request The bridge request to decode\n function getBridgeTransactionV2(bytes memory request) external view returns (BridgeTransactionV2 memory);\n}\n\n// contracts/utils/MulticallTarget.sol\n\n// solhint-disable avoid-low-level-calls\n/// @notice Template for a contract that supports batched calls (preserving the msg.sender).\n/// Only calls with zero msg.value could be batched.\nabstract contract MulticallTarget is IMulticallTarget {\n error MulticallTarget__UndeterminedRevert();\n\n /// @notice Perform a batched call to this contract, preserving the msg.sender.\n /// The return data from each call is discarded.\n /// @dev The method is non-payable, so only calls with `msg.value == 0` could be batched.\n /// It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag.\n /// Otherwise, the whole batch call will be reverted with the original revert reason.\n /// @param data List of abi-encoded calldata for the calls to perform.\n /// @param ignoreReverts Whether to ignore the revert errors from the calls.\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external {\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\n if (!success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(result);\n }\n }\n }\n\n /// @notice Perform a batched call to this contract, preserving the msg.sender.\n /// The return data from each call is preserved.\n /// @dev The method is non-payable, so only calls with `msg.value == 0` could be batched.\n /// It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag.\n /// Otherwise, the whole batch call will be reverted with the original revert reason.\n /// @param data List of abi-encoded calldata for the calls to perform.\n /// @param ignoreReverts Whether to ignore the revert errors from the calls.\n /// @return results List of results from the calls: `(success, returnData)`.\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results)\n {\n results = new Result[](data.length);\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (results[i].success, results[i].returnData) = address(this).delegatecall(data[i]);\n if (!results[i].success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(results[i].returnData);\n }\n }\n }\n\n /// @dev Bubbles the revert message from the underlying call.\n /// Note: preserves the same custom error or revert string, if one was used.\n /// Source: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v5.0.2/contracts/utils/Address.sol#L143-L158\n function _bubbleRevert(bytes memory returnData) internal pure {\n // Look for revert reason and bubble it up if present\n if (returnData.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n // solhint-disable-next-line no-inline-assembly\n assembly {\n let returndata_size := mload(returnData)\n revert(add(32, returnData), returndata_size)\n }\n } else {\n revert MulticallTarget__UndeterminedRevert();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// contracts/libs/BridgeTransactionV2.sol\n\n// solhint-disable no-inline-assembly\nlibrary BridgeTransactionV2Lib {\n uint16 internal constant VERSION = 2;\n\n // Offsets of the fields in the packed BridgeTransactionV2 struct\n // uint16 version [000 .. 002)\n // uint32 originChainId [002 .. 006)\n // uint32 destChainId [006 .. 010)\n // address originSender [010 .. 030)\n // address destRecipient [030 .. 050)\n // address originToken [050 .. 070)\n // address destToken [070 .. 090)\n // uint256 originAmount [090 .. 122)\n // uint256 destAmount [122 .. 154)\n // uint256 originFeeAmount [154 .. 186)\n // uint256 deadline [186 .. 218)\n // uint256 nonce [218 .. 250)\n // address exclusivityRelayer [250 .. 270)\n // uint256 exclusivityEndTime [270 .. 302)\n // uint256 zapNative [302 .. 334)\n // bytes zapData [334 .. ***)\n\n // forgefmt: disable-start\n uint256 private constant OFFSET_ORIGIN_CHAIN_ID = 2;\n uint256 private constant OFFSET_DEST_CHAIN_ID = 6;\n uint256 private constant OFFSET_ORIGIN_SENDER = 10;\n uint256 private constant OFFSET_DEST_RECIPIENT = 30;\n uint256 private constant OFFSET_ORIGIN_TOKEN = 50;\n uint256 private constant OFFSET_DEST_TOKEN = 70;\n uint256 private constant OFFSET_ORIGIN_AMOUNT = 90;\n uint256 private constant OFFSET_DEST_AMOUNT = 122;\n uint256 private constant OFFSET_ORIGIN_FEE_AMOUNT = 154;\n uint256 private constant OFFSET_DEADLINE = 186;\n uint256 private constant OFFSET_NONCE = 218;\n uint256 private constant OFFSET_EXCLUSIVITY_RELAYER = 250;\n uint256 private constant OFFSET_EXCLUSIVITY_END_TIME = 270;\n uint256 private constant OFFSET_ZAP_NATIVE = 302;\n uint256 private constant OFFSET_ZAP_DATA = 334;\n // forgefmt: disable-end\n\n error BridgeTransactionV2__InvalidEncodedTx();\n error BridgeTransactionV2__UnsupportedVersion(uint16 version);\n\n /// @notice Validates the encoded transaction to be a tightly packed encoded payload for BridgeTransactionV2.\n /// @dev Checks the minimum length and the version, use this function before decoding any of the fields.\n function validateV2(bytes calldata encodedTx) internal pure {\n // Check the minimum length: must at least include all static fields.\n if (encodedTx.length \u003c OFFSET_ZAP_DATA) revert BridgeTransactionV2__InvalidEncodedTx();\n // Once we validated the length, we can be sure that the version field is present.\n uint16 version_ = version(encodedTx);\n if (version_ != VERSION) revert BridgeTransactionV2__UnsupportedVersion(version_);\n }\n\n /// @notice Encodes the BridgeTransactionV2 struct by tightly packing the fields.\n /// @dev `abi.decode` will not work as a result of the tightly packed fields. Use `decodeV2` to decode instead.\n function encodeV2(IFastBridgeV2.BridgeTransactionV2 memory bridgeTx) internal pure returns (bytes memory) {\n // We split the encoding into two parts to avoid stack-too-deep error\n bytes memory firstPart = abi.encodePacked(\n VERSION,\n bridgeTx.originChainId,\n bridgeTx.destChainId,\n bridgeTx.originSender,\n bridgeTx.destRecipient,\n bridgeTx.originToken,\n bridgeTx.destToken,\n bridgeTx.originAmount\n );\n return abi.encodePacked(\n firstPart,\n bridgeTx.destAmount,\n bridgeTx.originFeeAmount,\n // Note: we skip the deprecated `sendChainGas` flag, which was present in BridgeTransaction V1\n bridgeTx.deadline,\n bridgeTx.nonce,\n // New V2 fields: exclusivity\n bridgeTx.exclusivityRelayer,\n bridgeTx.exclusivityEndTime,\n // New V2 fields: Zap\n bridgeTx.zapNative,\n bridgeTx.zapData\n );\n }\n\n /// @notice Decodes the BridgeTransactionV2 struct from the encoded transaction.\n /// @dev Encoded BridgeTransactionV2 struct must be tightly packed.\n /// Use `validateV2` before decoding to ensure the encoded transaction is valid.\n function decodeV2(bytes calldata encodedTx)\n internal\n pure\n returns (IFastBridgeV2.BridgeTransactionV2 memory bridgeTx)\n {\n bridgeTx.originChainId = originChainId(encodedTx);\n bridgeTx.destChainId = destChainId(encodedTx);\n bridgeTx.originSender = originSender(encodedTx);\n bridgeTx.destRecipient = destRecipient(encodedTx);\n bridgeTx.originToken = originToken(encodedTx);\n bridgeTx.destToken = destToken(encodedTx);\n bridgeTx.originAmount = originAmount(encodedTx);\n bridgeTx.destAmount = destAmount(encodedTx);\n bridgeTx.originFeeAmount = originFeeAmount(encodedTx);\n bridgeTx.deadline = deadline(encodedTx);\n bridgeTx.nonce = nonce(encodedTx);\n bridgeTx.exclusivityRelayer = exclusivityRelayer(encodedTx);\n bridgeTx.exclusivityEndTime = exclusivityEndTime(encodedTx);\n bridgeTx.zapNative = zapNative(encodedTx);\n bridgeTx.zapData = zapData(encodedTx);\n }\n\n /// @notice Extracts the version from the encoded transaction.\n function version(bytes calldata encodedTx) internal pure returns (uint16 version_) {\n // Load 32 bytes from the start and shift it 240 bits to the right to get the highest 16 bits.\n assembly {\n version_ := shr(240, calldataload(encodedTx.offset))\n }\n }\n\n /// @notice Extracts the origin chain ID from the encoded transaction.\n function originChainId(bytes calldata encodedTx) internal pure returns (uint32 originChainId_) {\n // Load 32 bytes from the offset and shift it 224 bits to the right to get the highest 32 bits.\n assembly {\n originChainId_ := shr(224, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_CHAIN_ID)))\n }\n }\n\n /// @notice Extracts the destination chain ID from the encoded transaction.\n function destChainId(bytes calldata encodedTx) internal pure returns (uint32 destChainId_) {\n // Load 32 bytes from the offset and shift it 224 bits to the right to get the highest 32 bits.\n assembly {\n destChainId_ := shr(224, calldataload(add(encodedTx.offset, OFFSET_DEST_CHAIN_ID)))\n }\n }\n\n /// @notice Extracts the origin sender from the encoded transaction.\n function originSender(bytes calldata encodedTx) internal pure returns (address originSender_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n originSender_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_SENDER)))\n }\n }\n\n /// @notice Extracts the destination recipient from the encoded transaction.\n function destRecipient(bytes calldata encodedTx) internal pure returns (address destRecipient_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n destRecipient_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_DEST_RECIPIENT)))\n }\n }\n\n /// @notice Extracts the origin token from the encoded transaction.\n function originToken(bytes calldata encodedTx) internal pure returns (address originToken_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n originToken_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_TOKEN)))\n }\n }\n\n /// @notice Extracts the destination token from the encoded transaction.\n function destToken(bytes calldata encodedTx) internal pure returns (address destToken_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n destToken_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_DEST_TOKEN)))\n }\n }\n\n /// @notice Extracts the origin amount from the encoded transaction.\n function originAmount(bytes calldata encodedTx) internal pure returns (uint256 originAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n originAmount_ := calldataload(add(encodedTx.offset, OFFSET_ORIGIN_AMOUNT))\n }\n }\n\n /// @notice Extracts the destination amount from the encoded transaction.\n function destAmount(bytes calldata encodedTx) internal pure returns (uint256 destAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n destAmount_ := calldataload(add(encodedTx.offset, OFFSET_DEST_AMOUNT))\n }\n }\n\n /// @notice Extracts the origin fee amount from the encoded transaction.\n function originFeeAmount(bytes calldata encodedTx) internal pure returns (uint256 originFeeAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n originFeeAmount_ := calldataload(add(encodedTx.offset, OFFSET_ORIGIN_FEE_AMOUNT))\n }\n }\n\n /// @notice Extracts the deadline from the encoded transaction.\n function deadline(bytes calldata encodedTx) internal pure returns (uint256 deadline_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n deadline_ := calldataload(add(encodedTx.offset, OFFSET_DEADLINE))\n }\n }\n\n /// @notice Extracts the nonce from the encoded transaction.\n function nonce(bytes calldata encodedTx) internal pure returns (uint256 nonce_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n nonce_ := calldataload(add(encodedTx.offset, OFFSET_NONCE))\n }\n }\n\n /// @notice Extracts the exclusivity relayer from the encoded transaction.\n function exclusivityRelayer(bytes calldata encodedTx) internal pure returns (address exclusivityRelayer_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n exclusivityRelayer_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_EXCLUSIVITY_RELAYER)))\n }\n }\n\n /// @notice Extracts the exclusivity end time from the encoded transaction.\n function exclusivityEndTime(bytes calldata encodedTx) internal pure returns (uint256 exclusivityEndTime_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n exclusivityEndTime_ := calldataload(add(encodedTx.offset, OFFSET_EXCLUSIVITY_END_TIME))\n }\n }\n\n /// @notice Extracts the Zap's native value from the encoded transaction.\n function zapNative(bytes calldata encodedTx) internal pure returns (uint256 zapNative_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n zapNative_ := calldataload(add(encodedTx.offset, OFFSET_ZAP_NATIVE))\n }\n }\n\n /// @notice Extracts the Zap's data from the encoded transaction.\n function zapData(bytes calldata encodedTx) internal pure returns (bytes calldata zapData_) {\n zapData_ = encodedTx[OFFSET_ZAP_DATA:];\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// contracts/libs/UniversalToken.sol\n\nlibrary UniversalTokenLib {\n using SafeERC20 for IERC20;\n\n address internal constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Transfers tokens to the given account. Reverts if transfer is not successful.\n /// @dev This might trigger fallback, if ETH is transferred to the contract.\n /// Make sure this can not lead to reentrancy attacks.\n function universalTransfer(address token, address to, uint256 value) internal {\n // Don't do anything, if need to send tokens to this address\n if (to == address(this)) return;\n // Don't do anything, if trying to send zero value\n if (value == 0) return;\n if (token == ETH_ADDRESS) {\n /// @dev Note: this can potentially lead to executing code in `to`.\n // solhint-disable-next-line avoid-low-level-calls\n (bool success,) = to.call{value: value}(\"\");\n require(success, \"ETH transfer failed\");\n } else {\n IERC20(token).safeTransfer(to, value);\n }\n }\n\n /// @notice Issues an infinite allowance to the spender, if the current allowance is insufficient\n /// to spend the given amount.\n function universalApproveInfinity(address token, address spender, uint256 amountToSpend) internal {\n // ETH Chad doesn't require your approval\n if (token == ETH_ADDRESS) return;\n // No-op if allowance is already sufficient\n uint256 allowance = IERC20(token).allowance(address(this), spender);\n if (allowance \u003e= amountToSpend) return;\n // Otherwise, reset approval to 0 and set to max allowance\n if (allowance \u003e 0) IERC20(token).safeDecreaseAllowance(spender, allowance);\n IERC20(token).safeIncreaseAllowance(spender, type(uint256).max);\n }\n\n /// @notice Returns the balance of the given token (or native ETH) for the given account.\n function universalBalanceOf(address token, address account) internal view returns (uint256) {\n if (token == ETH_ADDRESS) {\n return account.balance;\n } else {\n return IERC20(token).balanceOf(account);\n }\n }\n\n /// @dev Checks that token is a contract and not ETH_ADDRESS.\n function assertIsContract(address token) internal view {\n // Check that ETH_ADDRESS was not used (in case this is a predeploy on any of the chains)\n if (token == UniversalTokenLib.ETH_ADDRESS) revert TokenNotContract();\n // Check that token is not an EOA\n if (token.code.length == 0) revert TokenNotContract();\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/Admin.sol\n\ncontract Admin is IAdmin, AccessControlEnumerable {\n using UniversalTokenLib for address;\n\n bytes32 public constant RELAYER_ROLE = keccak256(\"RELAYER_ROLE\");\n bytes32 public constant REFUNDER_ROLE = keccak256(\"REFUNDER_ROLE\");\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n uint256 public constant FEE_BPS = 1e6;\n uint256 public constant FEE_RATE_MAX = 0.01e6; // max 1% on origin amount\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Chain gas amount to forward as rebate if requested\n uint256 public chainGasAmount;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n }\n\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n require(newFeeRate \u003c= FEE_RATE_MAX, \"newFeeRate \u003e max\");\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n token.universalTransfer(recipient, feeAmount);\n emit FeesSwept(token, recipient, feeAmount);\n }\n\n function setChainGasAmount(uint256 newChainGasAmount) external onlyRole(GOVERNOR_ROLE) {\n uint256 oldChainGasAmount = chainGasAmount;\n chainGasAmount = newChainGasAmount;\n emit ChainGasAmountUpdated(oldChainGasAmount, newChainGasAmount);\n }\n}\n\n// contracts/FastBridgeV2.sol\n\n/// @notice FastBridgeV2 is a contract for bridging tokens across chains.\ncontract FastBridgeV2 is Admin, MulticallTarget, IFastBridgeV2, IFastBridgeV2Errors {\n using BridgeTransactionV2Lib for bytes;\n using SafeERC20 for IERC20;\n\n /// @notice Address reserved for native gas token (ETH on Ethereum and most L2s, AVAX on Avalanche, etc)\n address public constant NATIVE_GAS_TOKEN = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Delay for a transaction after which it could be permisionlessly refunded\n uint256 public constant REFUND_DELAY = 7 days;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n /// @notice Maximum length of accepted zapData\n uint256 public constant MAX_ZAP_DATA_LENGTH = 2 ** 16 - 1;\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeTxDetails) public bridgeTxDetails;\n /// @notice Relay details on destination chain\n mapping(bytes32 =\u003e BridgeRelay) public bridgeRelayDetails;\n /// @notice Unique bridge nonces tracked per originSender\n mapping(address =\u003e uint256) public senderNonces;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Replaced by senderNonces\n uint256 public immutable nonce = 0;\n /// @notice the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n bridge({\n params: params,\n paramsV2: BridgeParamsV2({\n quoteRelayer: address(0),\n quoteExclusivitySeconds: 0,\n quoteId: bytes(\"\"),\n zapNative: 0,\n zapData: bytes(\"\")\n })\n });\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes calldata request) external payable {\n // relay override will validate the request\n relay({request: request, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes calldata request, bytes32 destTxHash) external {\n request.validateV2();\n prove({transactionId: keccak256(request), destTxHash: destTxHash, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridgeV2\n function claim(bytes calldata request) external {\n // claim override will validate the request\n claim({request: request, to: address(0)});\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Aggregate the read operations from the same storage slot\n address disputedRelayer = $.proofRelayer;\n BridgeStatus status = $.status;\n uint56 proofBlockTimestamp = $.proofBlockTimestamp;\n // Can only dispute a RELAYER_PROVED transaction within the dispute period\n if (status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(proofBlockTimestamp) \u003e DISPUTE_PERIOD) {\n revert DisputePeriodPassed();\n }\n // Update status to REQUESTED and delete the disputed proof details\n // Note: these are storage writes\n $.status = BridgeStatus.REQUESTED;\n $.proofRelayer = address(0);\n $.proofBlockTimestamp = 0;\n\n emit BridgeProofDisputed(transactionId, disputedRelayer);\n }\n\n /// @inheritdoc IFastBridge\n function refund(bytes calldata request) external {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Can only refund a REQUESTED transaction after its deadline expires\n if ($.status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n uint256 deadline = request.deadline();\n // Permissionless refund is only allowed after REFUND_DELAY on top of the deadline\n if (!hasRole(REFUNDER_ROLE, msg.sender)) deadline += REFUND_DELAY;\n if (block.timestamp \u003c= deadline) revert DeadlineNotExceeded();\n // Update status to REFUNDED and return the full amount (collateral + protocol fees) to the original sender.\n // The protocol fees are only updated when the transaction is claimed, so we don't need to update them here.\n // Note: this is a storage write\n $.status = BridgeStatus.REFUNDED;\n\n address to = request.originSender();\n address token = request.originToken();\n uint256 amount = request.originAmount() + request.originFeeAmount();\n // Emit the event before any external calls\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n // Complete the user refund as the last transaction action\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(to), amount);\n } else {\n IERC20(token).safeTransfer(to, amount);\n }\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // The correct relayer can only claim a RELAYER_PROVED transaction after the dispute period\n if ($.status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if ($.proofRelayer != relayer) revert SenderIncorrect();\n return _timeSince($.proofBlockTimestamp) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n /// @dev This method is added to achieve backwards compatibility with decoding requests into V1 structs:\n /// - `zapNative` is partially reported as a zero/non-zero flag\n /// - `zapData` is ignored\n /// In order to process all kinds of requests use getBridgeTransactionV2 instead.\n function getBridgeTransaction(bytes calldata request) external view returns (BridgeTransaction memory) {\n // Try decoding into V2 struct first. This will revert if V1 struct is passed\n try this.getBridgeTransactionV2(request) returns (BridgeTransactionV2 memory txV2) {\n // Note: we entirely ignore the zapData field, as it was not present in V1\n return BridgeTransaction({\n originChainId: txV2.originChainId,\n destChainId: txV2.destChainId,\n originSender: txV2.originSender,\n destRecipient: txV2.destRecipient,\n originToken: txV2.originToken,\n destToken: txV2.destToken,\n originAmount: txV2.originAmount,\n destAmount: txV2.destAmount,\n originFeeAmount: txV2.originFeeAmount,\n sendChainGas: txV2.zapNative != 0,\n deadline: txV2.deadline,\n nonce: txV2.nonce\n });\n } catch {\n // Fallback to V1 struct\n return abi.decode(request, (BridgeTransaction));\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function getBridgeTransactionV2(bytes calldata request) external pure returns (BridgeTransactionV2 memory) {\n request.validateV2();\n return BridgeTransactionV2Lib.decodeV2(request);\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) public payable {\n int256 exclusivityEndTime = 0;\n // if relayer exclusivity is not intended for this bridge, set exclusivityEndTime to static zero\n // otherwise, set exclusivity to expire at the current block ts offset by quoteExclusivitySeconds\n if (paramsV2.quoteRelayer != address(0)) {\n exclusivityEndTime = int256(block.timestamp) + paramsV2.quoteExclusivitySeconds;\n }\n _validateBridgeParams(params, paramsV2, exclusivityEndTime);\n\n // transfer tokens to bridge contract\n /// @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _takeBridgedUserAsset(params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) {\n originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n }\n\n // set status to requested\n bytes memory request = BridgeTransactionV2Lib.encodeV2(\n BridgeTransactionV2({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n deadline: params.deadline,\n nonce: senderNonces[params.sender]++, // increment nonce on every bridge\n exclusivityRelayer: paramsV2.quoteRelayer,\n // We checked exclusivityEndTime to be in range [0 .. params.deadline] above, so can safely cast\n exclusivityEndTime: uint256(exclusivityEndTime),\n zapNative: paramsV2.zapNative,\n zapData: paramsV2.zapData\n })\n );\n bytes32 transactionId = keccak256(request);\n // Note: the tx status will be updated throughout the tx lifecycle, while destChainId is set once here\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n bridgeTxDetails[transactionId].destChainId = params.dstChainId;\n\n emit BridgeRequested({\n transactionId: transactionId,\n sender: params.sender,\n request: request,\n destChainId: params.dstChainId,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n sendChainGas: paramsV2.zapNative != 0\n });\n emit BridgeQuoteDetails(transactionId, paramsV2.quoteId);\n }\n\n /// @inheritdoc IFastBridgeV2\n function relay(bytes calldata request, address relayer) public payable {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n _validateRelayParams(request, transactionId, relayer);\n // mark bridge transaction as relayed\n bridgeRelayDetails[transactionId] =\n BridgeRelay({blockNumber: uint48(block.number), blockTimestamp: uint48(block.timestamp), relayer: relayer});\n\n // transfer tokens to recipient on destination chain and trigger Zap if requested\n address to = request.destRecipient();\n address token = request.destToken();\n uint256 amount = request.destAmount();\n uint256 zapNative = request.zapNative();\n\n // Emit the event before any external calls\n emit BridgeRelayed({\n transactionId: transactionId,\n relayer: relayer,\n to: to,\n originChainId: request.originChainId(),\n originToken: request.originToken(),\n destToken: token,\n originAmount: request.originAmount(),\n destAmount: amount,\n chainGasAmount: zapNative\n });\n\n // All state changes have been done at this point, can proceed to the external calls.\n // This follows the checks-effects-interactions pattern to mitigate potential reentrancy attacks.\n if (token == NATIVE_GAS_TOKEN) {\n // For the native gas token, additional zapNative is not allowed\n if (zapNative != 0) revert ZapNativeNotSupported();\n // Check that the correct msg.value was sent\n if (msg.value != amount) revert MsgValueIncorrect();\n // Don't do a native transfer yet: we will handle it alongside the Zap below\n } else {\n // For ERC20s, we check that the correct msg.value was sent\n if (msg.value != zapNative) revert MsgValueIncorrect();\n // We need to transfer the tokens from the Relayer to the recipient first before performing an\n // optional post-transfer Zap.\n IERC20(token).safeTransferFrom(msg.sender, to, amount);\n }\n // At this point we have done:\n // - Transferred the requested amount of ERC20 tokens to the recipient.\n // At this point we have confirmed:\n // - For ERC20s: msg.value matches the requested zapNative amount.\n // - For the native gas token: msg.value matches the requested destAmount.\n // Remaining optional things to do:\n // - Forward the full msg.value to the recipient (if non-zero).\n // - Trigger a Zap (if zapData is present).\n bytes calldata zapData = request.zapData();\n if (zapData.length != 0) {\n // Zap Data is present: Zap has been requested by the recipient. Trigger it forwarding the full msg.value.\n\n // Note: if token has a fee on transfers, the recipient will have received less than `amount`.\n // This is a very niche edge case and should be handled by the recipient contract.\n _triggerZapWithChecks({recipient: to, token: token, amount: amount, zapData: zapData});\n } else if (msg.value != 0) {\n // Zap Data is missing, but msg.value was sent. This could happen in two different cases:\n // - Relay with the native gas token is happening.\n // - Relay with ERC20 is happening, with a `zapNative \u003e 0` request.\n // In both cases, we need to transfer the full msg.value to the recipient.\n Address.sendValue(payable(to), msg.value);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) public onlyRole(RELAYER_ROLE) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n\n // Can only prove a REQUESTED transaction\n if ($.status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n // Update status to RELAYER_PROVED and store the proof details\n // Note: these are storage writes\n $.status = BridgeStatus.RELAYER_PROVED;\n $.proofBlockTimestamp = uint56(block.timestamp);\n $.proofRelayer = relayer;\n\n emit BridgeProofProvided(transactionId, relayer, destTxHash);\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes calldata request, address to) public {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Aggregate the read operations from the same storage slot\n address proofRelayer = $.proofRelayer;\n BridgeStatus status = $.status;\n uint56 proofBlockTimestamp = $.proofBlockTimestamp;\n\n // Can only claim a RELAYER_PROVED transaction after the dispute period\n if (status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(proofBlockTimestamp) \u003c= DISPUTE_PERIOD) {\n revert DisputePeriodNotPassed();\n }\n\n if (to == address(0)) {\n // Anyone could claim the funds to the proven relayer on their behalf\n to = proofRelayer;\n } else if (proofRelayer != msg.sender) {\n // Only the proven relayer could specify an address to claim the funds to\n revert SenderIncorrect();\n }\n\n // Update status to RELAYER_CLAIMED and transfer the origin collateral to the specified claim address\n // Note: this is a storage write\n $.status = BridgeStatus.RELAYER_CLAIMED;\n\n address token = request.originToken();\n uint256 amount = request.originAmount();\n // Update protocol fees if origin fee amount exists\n uint256 originFeeAmount = request.originFeeAmount();\n if (originFeeAmount \u003e 0) protocolFees[token] += originFeeAmount;\n // Emit the event before any external calls\n emit BridgeDepositClaimed(transactionId, proofRelayer, to, token, amount);\n // Complete the relayer claim as the last transaction action\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(to), amount);\n } else {\n IERC20(token).safeTransfer(to, amount);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeStatuses(bytes32 transactionId) public view returns (BridgeStatus status) {\n return bridgeTxDetails[transactionId].status;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeProofs(bytes32 transactionId) public view returns (uint96 timestamp, address relayer) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n\n timestamp = $.proofBlockTimestamp;\n relayer = $.proofRelayer;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeRelays(bytes32 transactionId) public view returns (bool) {\n // has this transactionId been relayed?\n return bridgeRelayDetails[transactionId].relayer != address(0);\n }\n\n /// @notice Takes the bridged asset from the user into FastBridgeV2 custody. It will be later\n /// claimed by the relayer who completed the relay on destination chain, or refunded back to the user,\n /// should no one complete the relay.\n function _takeBridgedUserAsset(address token, uint256 amount) internal returns (uint256 amountTaken) {\n if (token == NATIVE_GAS_TOKEN) {\n // For the native gas token, we just need to check that the supplied msg.value is correct.\n // Supplied `msg.value` is already in FastBridgeV2 custody.\n if (amount != msg.value) revert MsgValueIncorrect();\n amountTaken = msg.value;\n } else {\n // For ERC20s, token is explicitly transferred from the user to FastBridgeV2.\n // We don't allow non-zero `msg.value` to avoid extra funds from being stuck in FastBridgeV2.\n if (msg.value != 0) revert MsgValueIncorrect();\n // Throw an explicit error if the provided token address is not a contract\n if (token.code.length == 0) revert TokenNotContract();\n amountTaken = IERC20(token).balanceOf(address(this));\n IERC20(token).safeTransferFrom(msg.sender, address(this), amount);\n // Use the balance difference as the amount taken in case of fee on transfer tokens.\n amountTaken = IERC20(token).balanceOf(address(this)) - amountTaken;\n }\n }\n\n /// @notice Calls the Recipient's hook function with the specified zapData and performs\n /// all the necessary checks for the returned value.\n function _triggerZapWithChecks(address recipient, address token, uint256 amount, bytes calldata zapData) internal {\n // This will bubble any revert messages from the hook function\n bytes memory returnData = Address.functionCallWithValue({\n target: recipient,\n data: abi.encodeCall(IZapRecipient.zap, (token, amount, zapData)),\n // Note: see `relay()` for reasoning behind passing msg.value\n value: msg.value\n });\n // Explicit revert if no return data at all\n if (returnData.length == 0) revert RecipientNoReturnValue();\n // Check that exactly a single return value was returned\n if (returnData.length != 32) revert RecipientIncorrectReturnValue();\n // Return value should be abi-encoded hook function selector\n if (bytes32(returnData) != bytes32(IZapRecipient.zap.selector)) {\n revert RecipientIncorrectReturnValue();\n }\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint56(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint56).max but\n /// proof.timestamp \u003c type(uint56).max via unchecked statement\n /// @param proofBlockTimestamp The bridge proof block timestamp\n /// @return delta Time delta since proof submitted\n function _timeSince(uint56 proofBlockTimestamp) internal view returns (uint256 delta) {\n unchecked {\n delta = uint56(block.timestamp) - proofBlockTimestamp;\n }\n }\n\n /// @notice Performs all the necessary checks for a bridge to happen.\n /// @dev There's no good way to refactor this function to reduce cyclomatic complexity due to\n /// the number of checks that need to be performed, so we skip the code-complexity rule here.\n // solhint-disable-next-line code-complexity\n function _validateBridgeParams(\n BridgeParams memory params,\n BridgeParamsV2 memory paramsV2,\n int256 exclusivityEndTime\n )\n internal\n view\n {\n // Check V1 (legacy) params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.sender == address(0) || params.to == address(0)) revert ZeroAddress();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n // Check V2 params\n if (paramsV2.zapData.length \u003e MAX_ZAP_DATA_LENGTH) revert ZapDataLengthAboveMax();\n if (paramsV2.zapNative != 0 \u0026\u0026 params.destToken == NATIVE_GAS_TOKEN) {\n revert ZapNativeNotSupported();\n }\n // exclusivityEndTime must be in range [0 .. params.deadline]\n if (exclusivityEndTime \u003c 0 || exclusivityEndTime \u003e int256(params.deadline)) {\n revert ExclusivityParamsIncorrect();\n }\n }\n\n /// @notice Performs all the necessary checks for a relay to happen.\n function _validateRelayParams(bytes calldata request, bytes32 transactionId, address relayer) internal view {\n if (relayer == address(0)) revert ZeroAddress();\n // Check if the transaction has already been relayed\n if (bridgeRelays(transactionId)) revert TransactionRelayed();\n if (request.destChainId() != block.chainid) revert ChainIncorrect();\n // Check the deadline for relay to happen\n if (block.timestamp \u003e request.deadline()) revert DeadlineExceeded();\n // Check the exclusivity period, if it is still ongoing\n address exclRelayer = request.exclusivityRelayer();\n if (exclRelayer != address(0) \u0026\u0026 exclRelayer != relayer \u0026\u0026 block.timestamp \u003c= request.exclusivityEndTime()) {\n revert ExclusivityPeriodNotPassed();\n }\n }\n}\n","language":"Solidity","languageVersion":"0.8.24","compilerVersion":"0.8.24","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"","srcMapRuntime":"","abiDefinition":[{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Transfer","type":"event"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"}],"userDoc":{"kind":"user","methods":{},"version":1},"developerDoc":{"details":"Interface of the ERC20 standard as defined in the EIP.","events":{"Approval(address,address,uint256)":{"details":"Emitted when the allowance of a `spender` for an `owner` is set by a call to {approve}. `value` is the new allowance."},"Transfer(address,address,uint256)":{"details":"Emitted when `value` tokens are moved from one account (`from`) to another (`to`). Note that `value` may be zero."}},"kind":"dev","methods":{"allowance(address,address)":{"details":"Returns the remaining number of tokens that `spender` will be allowed to spend on behalf of `owner` through {transferFrom}. This is zero by default. This value changes when {approve} or {transferFrom} are called."},"approve(address,uint256)":{"details":"Sets a `value` amount of tokens as the allowance of `spender` over the caller's tokens. Returns a boolean value indicating whether the operation succeeded. IMPORTANT: Beware that changing an allowance with this method brings the risk that someone may use both the old and the new allowance by unfortunate transaction ordering. One possible solution to mitigate this race condition is to first reduce the spender's allowance to 0 and set the desired value afterwards: https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 Emits an {Approval} event."},"balanceOf(address)":{"details":"Returns the value of tokens owned by `account`."},"totalSupply()":{"details":"Returns the value of tokens in existence."},"transfer(address,uint256)":{"details":"Moves a `value` amount of tokens from the caller's account to `to`. Returns a boolean value indicating whether the operation succeeded. Emits a {Transfer} event."},"transferFrom(address,address,uint256)":{"details":"Moves a `value` amount of tokens from `from` to `to` using the allowance mechanism. `value` is then deducted from the caller's allowance. Returns a boolean value indicating whether the operation succeeded. Emits a {Transfer} event."}},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"Approval\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"Transfer\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"}],\"name\":\"allowance\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"approve\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"balanceOf\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"totalSupply\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"transfer\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"transferFrom\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"details\":\"Interface of the ERC20 standard as defined in the EIP.\",\"events\":{\"Approval(address,address,uint256)\":{\"details\":\"Emitted when the allowance of a `spender` for an `owner` is set by a call to {approve}. `value` is the new allowance.\"},\"Transfer(address,address,uint256)\":{\"details\":\"Emitted when `value` tokens are moved from one account (`from`) to another (`to`). Note that `value` may be zero.\"}},\"kind\":\"dev\",\"methods\":{\"allowance(address,address)\":{\"details\":\"Returns the remaining number of tokens that `spender` will be allowed to spend on behalf of `owner` through {transferFrom}. This is zero by default. This value changes when {approve} or {transferFrom} are called.\"},\"approve(address,uint256)\":{\"details\":\"Sets a `value` amount of tokens as the allowance of `spender` over the caller's tokens. Returns a boolean value indicating whether the operation succeeded. IMPORTANT: Beware that changing an allowance with this method brings the risk that someone may use both the old and the new allowance by unfortunate transaction ordering. One possible solution to mitigate this race condition is to first reduce the spender's allowance to 0 and set the desired value afterwards: https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 Emits an {Approval} event.\"},\"balanceOf(address)\":{\"details\":\"Returns the value of tokens owned by `account`.\"},\"totalSupply()\":{\"details\":\"Returns the value of tokens in existence.\"},\"transfer(address,uint256)\":{\"details\":\"Moves a `value` amount of tokens from the caller's account to `to`. Returns a boolean value indicating whether the operation succeeded. Emits a {Transfer} event.\"},\"transferFrom(address,address,uint256)\":{\"details\":\"Moves a `value` amount of tokens from `from` to `to` using the allowance mechanism. `value` is then deducted from the caller's allowance. Returns a boolean value indicating whether the operation succeeded. Emits a {Transfer} event.\"}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeV2.sol\":\"IERC20\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeV2.sol\":{\"keccak256\":\"0x5069b55ca07f21bfe30b2a43c18a18318c8af9c181b2dcb07c290825efd70f34\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://273dc020a49d08e50126bbea0d7f783f79d08c702f2fdbc560618d24af308acc\",\"dweb:/ipfs/QmXJ2UVzFc8EPB74RT4CXQPC4xw66jt4T13poyfyd3UERh\"]}},\"version\":1}"},"hashes":{"allowance(address,address)":"dd62ed3e","approve(address,uint256)":"095ea7b3","balanceOf(address)":"70a08231","totalSupply()":"18160ddd","transfer(address,uint256)":"a9059cbb","transferFrom(address,address,uint256)":"23b872dd"}},"solidity/FastBridgeV2.sol:IERC20Permit":{"code":"0x","runtime-code":"0x","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.24 ^0.8.20 ^0.8.4;\n\n// contracts/interfaces/IAdmin.sol\n\ninterface IAdmin {\n // ============ Events ============\n\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n event ChainGasAmountUpdated(uint256 oldChainGasAmount, uint256 newChainGasAmount);\n\n // ============ Methods ============\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n\n function setChainGasAmount(uint256 newChainGasAmount) external;\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IFastBridgeV2Errors.sol\n\ninterface IFastBridgeV2Errors {\n error AmountIncorrect();\n error ChainIncorrect();\n error ExclusivityParamsIncorrect();\n error MsgValueIncorrect();\n error SenderIncorrect();\n error StatusIncorrect();\n error TokenNotContract();\n error ZapDataLengthAboveMax();\n error ZapNativeNotSupported();\n error ZeroAddress();\n\n error RecipientIncorrectReturnValue();\n error RecipientNoReturnValue();\n\n error DeadlineExceeded();\n error DeadlineNotExceeded();\n error DeadlineTooShort();\n error DisputePeriodNotPassed();\n error DisputePeriodPassed();\n error ExclusivityPeriodNotPassed();\n\n error TransactionRelayed();\n}\n\n// contracts/interfaces/IMulticallTarget.sol\n\n/// @notice Interface for a contract that can be called multiple times by the same caller. Inspired by MulticallV3:\n/// https://github.com/mds1/multicall/blob/master/src/Multicall3.sol\ninterface IMulticallTarget {\n struct Result {\n bool success;\n bytes returnData;\n }\n\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external;\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results);\n}\n\n// contracts/interfaces/IZapRecipient.sol\n\ninterface IZapRecipient {\n function zap(address token, uint256 amount, bytes memory zapData) external payable returns (bytes4);\n}\n\n// contracts/libs/Errors.sol\n\nerror DeadlineExceeded();\nerror DeadlineNotExceeded();\nerror DeadlineTooShort();\nerror InsufficientOutputAmount();\n\nerror MsgValueIncorrect();\nerror PoolNotFound();\nerror TokenAddressMismatch();\nerror TokenNotContract();\nerror TokenNotETH();\nerror TokensIdentical();\n\nerror ChainIncorrect();\nerror AmountIncorrect();\nerror ZeroAddress();\n\nerror DisputePeriodNotPassed();\nerror DisputePeriodPassed();\nerror SenderIncorrect();\nerror StatusIncorrect();\nerror TransactionIdIncorrect();\nerror TransactionRelayed();\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// contracts/interfaces/IFastBridgeV2.sol\n\ninterface IFastBridgeV2 is IFastBridge {\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n struct BridgeTxDetails {\n BridgeStatus status;\n uint32 destChainId;\n uint56 proofBlockTimestamp;\n address proofRelayer;\n }\n\n struct BridgeRelay {\n uint48 blockNumber;\n uint48 blockTimestamp;\n address relayer;\n }\n\n /// @notice New params introduced in the FastBridgeV2.\n /// We are passing fields from the older BridgeParams struct outside of this struct\n /// for backwards compatibility.\n /// Note: quoteRelayer and quoteExclusivitySeconds are either both zero (indicating no exclusivity)\n /// or both non-zero (indicating exclusivity for the given period).\n /// Note: zapNative \u003e 0 can NOT be used with destToken = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE (native token)\n /// @param quoteRelayer Relayer that provided the quote for the transaction\n /// @param quoteExclusivitySeconds Period of time the quote relayer is guaranteed exclusivity after user's deposit\n /// @param quoteId Unique quote identifier used for tracking the quote\n /// @param zapNative ETH value to send to the recipient (if any)\n /// @param zapData Parameters for the Zap to the destination recipient (if any)\n struct BridgeParamsV2 {\n address quoteRelayer;\n int256 quoteExclusivitySeconds;\n bytes quoteId;\n uint256 zapNative;\n bytes zapData;\n }\n\n /// @notice Updated bridge transaction struct to include parameters introduced in FastBridgeV2.\n /// Note: only `exclusivityRelayer` can fill such a transaction until `exclusivityEndTime`.\n struct BridgeTransactionV2 {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n // Note: sendChainGas flag from V1 is deprecated\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n address exclusivityRelayer;\n uint256 exclusivityEndTime;\n uint256 zapNative; // ETH value to send to the recipient (if any)\n bytes zapData; // data to pass for the Zap action (if any)\n }\n\n event BridgeQuoteDetails(bytes32 indexed transactionId, bytes quoteId);\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability\n /// to provide temporary exclusivity fill rights for the quote relayer.\n /// @param params The parameters required to bridge\n /// @param paramsV2 The parameters for exclusivity fill rights (optional, can be left empty)\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function relay(bytes memory request, address relayer) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param transactionId The transaction id associated with the encoded bridge transaction to prove\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital.\n /// @notice Can only send funds to the relayer address on the proof.\n /// @param request The encoded bridge transaction to claim on origin chain\n function claim(bytes memory request) external;\n /// @notice Checks if a transaction has been relayed\n /// @param transactionId The ID of the transaction to check\n /// @return True if the transaction has been relayed, false otherwise\n function bridgeRelays(bytes32 transactionId) external view returns (bool);\n\n /// @notice Returns the status of a bridge transaction\n /// @param transactionId The ID of the bridge transaction\n /// @return BridgeStatus Status of the bridge transaction\n function bridgeStatuses(bytes32 transactionId) external view returns (BridgeStatus);\n\n /// @notice Returns the timestamp and relayer of a bridge proof\n /// @param transactionId The ID of the bridge transaction\n /// @return timestamp The timestamp of the bridge proof\n /// @return relayer The relayer address of the bridge proof\n function bridgeProofs(bytes32 transactionId) external view returns (uint96 timestamp, address relayer);\n\n /// @notice Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\n /// @param request The bridge request to decode\n function getBridgeTransactionV2(bytes memory request) external view returns (BridgeTransactionV2 memory);\n}\n\n// contracts/utils/MulticallTarget.sol\n\n// solhint-disable avoid-low-level-calls\n/// @notice Template for a contract that supports batched calls (preserving the msg.sender).\n/// Only calls with zero msg.value could be batched.\nabstract contract MulticallTarget is IMulticallTarget {\n error MulticallTarget__UndeterminedRevert();\n\n /// @notice Perform a batched call to this contract, preserving the msg.sender.\n /// The return data from each call is discarded.\n /// @dev The method is non-payable, so only calls with `msg.value == 0` could be batched.\n /// It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag.\n /// Otherwise, the whole batch call will be reverted with the original revert reason.\n /// @param data List of abi-encoded calldata for the calls to perform.\n /// @param ignoreReverts Whether to ignore the revert errors from the calls.\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external {\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\n if (!success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(result);\n }\n }\n }\n\n /// @notice Perform a batched call to this contract, preserving the msg.sender.\n /// The return data from each call is preserved.\n /// @dev The method is non-payable, so only calls with `msg.value == 0` could be batched.\n /// It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag.\n /// Otherwise, the whole batch call will be reverted with the original revert reason.\n /// @param data List of abi-encoded calldata for the calls to perform.\n /// @param ignoreReverts Whether to ignore the revert errors from the calls.\n /// @return results List of results from the calls: `(success, returnData)`.\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results)\n {\n results = new Result[](data.length);\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (results[i].success, results[i].returnData) = address(this).delegatecall(data[i]);\n if (!results[i].success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(results[i].returnData);\n }\n }\n }\n\n /// @dev Bubbles the revert message from the underlying call.\n /// Note: preserves the same custom error or revert string, if one was used.\n /// Source: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v5.0.2/contracts/utils/Address.sol#L143-L158\n function _bubbleRevert(bytes memory returnData) internal pure {\n // Look for revert reason and bubble it up if present\n if (returnData.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n // solhint-disable-next-line no-inline-assembly\n assembly {\n let returndata_size := mload(returnData)\n revert(add(32, returnData), returndata_size)\n }\n } else {\n revert MulticallTarget__UndeterminedRevert();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// contracts/libs/BridgeTransactionV2.sol\n\n// solhint-disable no-inline-assembly\nlibrary BridgeTransactionV2Lib {\n uint16 internal constant VERSION = 2;\n\n // Offsets of the fields in the packed BridgeTransactionV2 struct\n // uint16 version [000 .. 002)\n // uint32 originChainId [002 .. 006)\n // uint32 destChainId [006 .. 010)\n // address originSender [010 .. 030)\n // address destRecipient [030 .. 050)\n // address originToken [050 .. 070)\n // address destToken [070 .. 090)\n // uint256 originAmount [090 .. 122)\n // uint256 destAmount [122 .. 154)\n // uint256 originFeeAmount [154 .. 186)\n // uint256 deadline [186 .. 218)\n // uint256 nonce [218 .. 250)\n // address exclusivityRelayer [250 .. 270)\n // uint256 exclusivityEndTime [270 .. 302)\n // uint256 zapNative [302 .. 334)\n // bytes zapData [334 .. ***)\n\n // forgefmt: disable-start\n uint256 private constant OFFSET_ORIGIN_CHAIN_ID = 2;\n uint256 private constant OFFSET_DEST_CHAIN_ID = 6;\n uint256 private constant OFFSET_ORIGIN_SENDER = 10;\n uint256 private constant OFFSET_DEST_RECIPIENT = 30;\n uint256 private constant OFFSET_ORIGIN_TOKEN = 50;\n uint256 private constant OFFSET_DEST_TOKEN = 70;\n uint256 private constant OFFSET_ORIGIN_AMOUNT = 90;\n uint256 private constant OFFSET_DEST_AMOUNT = 122;\n uint256 private constant OFFSET_ORIGIN_FEE_AMOUNT = 154;\n uint256 private constant OFFSET_DEADLINE = 186;\n uint256 private constant OFFSET_NONCE = 218;\n uint256 private constant OFFSET_EXCLUSIVITY_RELAYER = 250;\n uint256 private constant OFFSET_EXCLUSIVITY_END_TIME = 270;\n uint256 private constant OFFSET_ZAP_NATIVE = 302;\n uint256 private constant OFFSET_ZAP_DATA = 334;\n // forgefmt: disable-end\n\n error BridgeTransactionV2__InvalidEncodedTx();\n error BridgeTransactionV2__UnsupportedVersion(uint16 version);\n\n /// @notice Validates the encoded transaction to be a tightly packed encoded payload for BridgeTransactionV2.\n /// @dev Checks the minimum length and the version, use this function before decoding any of the fields.\n function validateV2(bytes calldata encodedTx) internal pure {\n // Check the minimum length: must at least include all static fields.\n if (encodedTx.length \u003c OFFSET_ZAP_DATA) revert BridgeTransactionV2__InvalidEncodedTx();\n // Once we validated the length, we can be sure that the version field is present.\n uint16 version_ = version(encodedTx);\n if (version_ != VERSION) revert BridgeTransactionV2__UnsupportedVersion(version_);\n }\n\n /// @notice Encodes the BridgeTransactionV2 struct by tightly packing the fields.\n /// @dev `abi.decode` will not work as a result of the tightly packed fields. Use `decodeV2` to decode instead.\n function encodeV2(IFastBridgeV2.BridgeTransactionV2 memory bridgeTx) internal pure returns (bytes memory) {\n // We split the encoding into two parts to avoid stack-too-deep error\n bytes memory firstPart = abi.encodePacked(\n VERSION,\n bridgeTx.originChainId,\n bridgeTx.destChainId,\n bridgeTx.originSender,\n bridgeTx.destRecipient,\n bridgeTx.originToken,\n bridgeTx.destToken,\n bridgeTx.originAmount\n );\n return abi.encodePacked(\n firstPart,\n bridgeTx.destAmount,\n bridgeTx.originFeeAmount,\n // Note: we skip the deprecated `sendChainGas` flag, which was present in BridgeTransaction V1\n bridgeTx.deadline,\n bridgeTx.nonce,\n // New V2 fields: exclusivity\n bridgeTx.exclusivityRelayer,\n bridgeTx.exclusivityEndTime,\n // New V2 fields: Zap\n bridgeTx.zapNative,\n bridgeTx.zapData\n );\n }\n\n /// @notice Decodes the BridgeTransactionV2 struct from the encoded transaction.\n /// @dev Encoded BridgeTransactionV2 struct must be tightly packed.\n /// Use `validateV2` before decoding to ensure the encoded transaction is valid.\n function decodeV2(bytes calldata encodedTx)\n internal\n pure\n returns (IFastBridgeV2.BridgeTransactionV2 memory bridgeTx)\n {\n bridgeTx.originChainId = originChainId(encodedTx);\n bridgeTx.destChainId = destChainId(encodedTx);\n bridgeTx.originSender = originSender(encodedTx);\n bridgeTx.destRecipient = destRecipient(encodedTx);\n bridgeTx.originToken = originToken(encodedTx);\n bridgeTx.destToken = destToken(encodedTx);\n bridgeTx.originAmount = originAmount(encodedTx);\n bridgeTx.destAmount = destAmount(encodedTx);\n bridgeTx.originFeeAmount = originFeeAmount(encodedTx);\n bridgeTx.deadline = deadline(encodedTx);\n bridgeTx.nonce = nonce(encodedTx);\n bridgeTx.exclusivityRelayer = exclusivityRelayer(encodedTx);\n bridgeTx.exclusivityEndTime = exclusivityEndTime(encodedTx);\n bridgeTx.zapNative = zapNative(encodedTx);\n bridgeTx.zapData = zapData(encodedTx);\n }\n\n /// @notice Extracts the version from the encoded transaction.\n function version(bytes calldata encodedTx) internal pure returns (uint16 version_) {\n // Load 32 bytes from the start and shift it 240 bits to the right to get the highest 16 bits.\n assembly {\n version_ := shr(240, calldataload(encodedTx.offset))\n }\n }\n\n /// @notice Extracts the origin chain ID from the encoded transaction.\n function originChainId(bytes calldata encodedTx) internal pure returns (uint32 originChainId_) {\n // Load 32 bytes from the offset and shift it 224 bits to the right to get the highest 32 bits.\n assembly {\n originChainId_ := shr(224, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_CHAIN_ID)))\n }\n }\n\n /// @notice Extracts the destination chain ID from the encoded transaction.\n function destChainId(bytes calldata encodedTx) internal pure returns (uint32 destChainId_) {\n // Load 32 bytes from the offset and shift it 224 bits to the right to get the highest 32 bits.\n assembly {\n destChainId_ := shr(224, calldataload(add(encodedTx.offset, OFFSET_DEST_CHAIN_ID)))\n }\n }\n\n /// @notice Extracts the origin sender from the encoded transaction.\n function originSender(bytes calldata encodedTx) internal pure returns (address originSender_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n originSender_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_SENDER)))\n }\n }\n\n /// @notice Extracts the destination recipient from the encoded transaction.\n function destRecipient(bytes calldata encodedTx) internal pure returns (address destRecipient_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n destRecipient_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_DEST_RECIPIENT)))\n }\n }\n\n /// @notice Extracts the origin token from the encoded transaction.\n function originToken(bytes calldata encodedTx) internal pure returns (address originToken_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n originToken_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_TOKEN)))\n }\n }\n\n /// @notice Extracts the destination token from the encoded transaction.\n function destToken(bytes calldata encodedTx) internal pure returns (address destToken_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n destToken_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_DEST_TOKEN)))\n }\n }\n\n /// @notice Extracts the origin amount from the encoded transaction.\n function originAmount(bytes calldata encodedTx) internal pure returns (uint256 originAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n originAmount_ := calldataload(add(encodedTx.offset, OFFSET_ORIGIN_AMOUNT))\n }\n }\n\n /// @notice Extracts the destination amount from the encoded transaction.\n function destAmount(bytes calldata encodedTx) internal pure returns (uint256 destAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n destAmount_ := calldataload(add(encodedTx.offset, OFFSET_DEST_AMOUNT))\n }\n }\n\n /// @notice Extracts the origin fee amount from the encoded transaction.\n function originFeeAmount(bytes calldata encodedTx) internal pure returns (uint256 originFeeAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n originFeeAmount_ := calldataload(add(encodedTx.offset, OFFSET_ORIGIN_FEE_AMOUNT))\n }\n }\n\n /// @notice Extracts the deadline from the encoded transaction.\n function deadline(bytes calldata encodedTx) internal pure returns (uint256 deadline_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n deadline_ := calldataload(add(encodedTx.offset, OFFSET_DEADLINE))\n }\n }\n\n /// @notice Extracts the nonce from the encoded transaction.\n function nonce(bytes calldata encodedTx) internal pure returns (uint256 nonce_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n nonce_ := calldataload(add(encodedTx.offset, OFFSET_NONCE))\n }\n }\n\n /// @notice Extracts the exclusivity relayer from the encoded transaction.\n function exclusivityRelayer(bytes calldata encodedTx) internal pure returns (address exclusivityRelayer_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n exclusivityRelayer_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_EXCLUSIVITY_RELAYER)))\n }\n }\n\n /// @notice Extracts the exclusivity end time from the encoded transaction.\n function exclusivityEndTime(bytes calldata encodedTx) internal pure returns (uint256 exclusivityEndTime_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n exclusivityEndTime_ := calldataload(add(encodedTx.offset, OFFSET_EXCLUSIVITY_END_TIME))\n }\n }\n\n /// @notice Extracts the Zap's native value from the encoded transaction.\n function zapNative(bytes calldata encodedTx) internal pure returns (uint256 zapNative_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n zapNative_ := calldataload(add(encodedTx.offset, OFFSET_ZAP_NATIVE))\n }\n }\n\n /// @notice Extracts the Zap's data from the encoded transaction.\n function zapData(bytes calldata encodedTx) internal pure returns (bytes calldata zapData_) {\n zapData_ = encodedTx[OFFSET_ZAP_DATA:];\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// contracts/libs/UniversalToken.sol\n\nlibrary UniversalTokenLib {\n using SafeERC20 for IERC20;\n\n address internal constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Transfers tokens to the given account. Reverts if transfer is not successful.\n /// @dev This might trigger fallback, if ETH is transferred to the contract.\n /// Make sure this can not lead to reentrancy attacks.\n function universalTransfer(address token, address to, uint256 value) internal {\n // Don't do anything, if need to send tokens to this address\n if (to == address(this)) return;\n // Don't do anything, if trying to send zero value\n if (value == 0) return;\n if (token == ETH_ADDRESS) {\n /// @dev Note: this can potentially lead to executing code in `to`.\n // solhint-disable-next-line avoid-low-level-calls\n (bool success,) = to.call{value: value}(\"\");\n require(success, \"ETH transfer failed\");\n } else {\n IERC20(token).safeTransfer(to, value);\n }\n }\n\n /// @notice Issues an infinite allowance to the spender, if the current allowance is insufficient\n /// to spend the given amount.\n function universalApproveInfinity(address token, address spender, uint256 amountToSpend) internal {\n // ETH Chad doesn't require your approval\n if (token == ETH_ADDRESS) return;\n // No-op if allowance is already sufficient\n uint256 allowance = IERC20(token).allowance(address(this), spender);\n if (allowance \u003e= amountToSpend) return;\n // Otherwise, reset approval to 0 and set to max allowance\n if (allowance \u003e 0) IERC20(token).safeDecreaseAllowance(spender, allowance);\n IERC20(token).safeIncreaseAllowance(spender, type(uint256).max);\n }\n\n /// @notice Returns the balance of the given token (or native ETH) for the given account.\n function universalBalanceOf(address token, address account) internal view returns (uint256) {\n if (token == ETH_ADDRESS) {\n return account.balance;\n } else {\n return IERC20(token).balanceOf(account);\n }\n }\n\n /// @dev Checks that token is a contract and not ETH_ADDRESS.\n function assertIsContract(address token) internal view {\n // Check that ETH_ADDRESS was not used (in case this is a predeploy on any of the chains)\n if (token == UniversalTokenLib.ETH_ADDRESS) revert TokenNotContract();\n // Check that token is not an EOA\n if (token.code.length == 0) revert TokenNotContract();\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/Admin.sol\n\ncontract Admin is IAdmin, AccessControlEnumerable {\n using UniversalTokenLib for address;\n\n bytes32 public constant RELAYER_ROLE = keccak256(\"RELAYER_ROLE\");\n bytes32 public constant REFUNDER_ROLE = keccak256(\"REFUNDER_ROLE\");\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n uint256 public constant FEE_BPS = 1e6;\n uint256 public constant FEE_RATE_MAX = 0.01e6; // max 1% on origin amount\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Chain gas amount to forward as rebate if requested\n uint256 public chainGasAmount;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n }\n\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n require(newFeeRate \u003c= FEE_RATE_MAX, \"newFeeRate \u003e max\");\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n token.universalTransfer(recipient, feeAmount);\n emit FeesSwept(token, recipient, feeAmount);\n }\n\n function setChainGasAmount(uint256 newChainGasAmount) external onlyRole(GOVERNOR_ROLE) {\n uint256 oldChainGasAmount = chainGasAmount;\n chainGasAmount = newChainGasAmount;\n emit ChainGasAmountUpdated(oldChainGasAmount, newChainGasAmount);\n }\n}\n\n// contracts/FastBridgeV2.sol\n\n/// @notice FastBridgeV2 is a contract for bridging tokens across chains.\ncontract FastBridgeV2 is Admin, MulticallTarget, IFastBridgeV2, IFastBridgeV2Errors {\n using BridgeTransactionV2Lib for bytes;\n using SafeERC20 for IERC20;\n\n /// @notice Address reserved for native gas token (ETH on Ethereum and most L2s, AVAX on Avalanche, etc)\n address public constant NATIVE_GAS_TOKEN = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Delay for a transaction after which it could be permisionlessly refunded\n uint256 public constant REFUND_DELAY = 7 days;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n /// @notice Maximum length of accepted zapData\n uint256 public constant MAX_ZAP_DATA_LENGTH = 2 ** 16 - 1;\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeTxDetails) public bridgeTxDetails;\n /// @notice Relay details on destination chain\n mapping(bytes32 =\u003e BridgeRelay) public bridgeRelayDetails;\n /// @notice Unique bridge nonces tracked per originSender\n mapping(address =\u003e uint256) public senderNonces;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Replaced by senderNonces\n uint256 public immutable nonce = 0;\n /// @notice the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n bridge({\n params: params,\n paramsV2: BridgeParamsV2({\n quoteRelayer: address(0),\n quoteExclusivitySeconds: 0,\n quoteId: bytes(\"\"),\n zapNative: 0,\n zapData: bytes(\"\")\n })\n });\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes calldata request) external payable {\n // relay override will validate the request\n relay({request: request, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes calldata request, bytes32 destTxHash) external {\n request.validateV2();\n prove({transactionId: keccak256(request), destTxHash: destTxHash, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridgeV2\n function claim(bytes calldata request) external {\n // claim override will validate the request\n claim({request: request, to: address(0)});\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Aggregate the read operations from the same storage slot\n address disputedRelayer = $.proofRelayer;\n BridgeStatus status = $.status;\n uint56 proofBlockTimestamp = $.proofBlockTimestamp;\n // Can only dispute a RELAYER_PROVED transaction within the dispute period\n if (status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(proofBlockTimestamp) \u003e DISPUTE_PERIOD) {\n revert DisputePeriodPassed();\n }\n // Update status to REQUESTED and delete the disputed proof details\n // Note: these are storage writes\n $.status = BridgeStatus.REQUESTED;\n $.proofRelayer = address(0);\n $.proofBlockTimestamp = 0;\n\n emit BridgeProofDisputed(transactionId, disputedRelayer);\n }\n\n /// @inheritdoc IFastBridge\n function refund(bytes calldata request) external {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Can only refund a REQUESTED transaction after its deadline expires\n if ($.status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n uint256 deadline = request.deadline();\n // Permissionless refund is only allowed after REFUND_DELAY on top of the deadline\n if (!hasRole(REFUNDER_ROLE, msg.sender)) deadline += REFUND_DELAY;\n if (block.timestamp \u003c= deadline) revert DeadlineNotExceeded();\n // Update status to REFUNDED and return the full amount (collateral + protocol fees) to the original sender.\n // The protocol fees are only updated when the transaction is claimed, so we don't need to update them here.\n // Note: this is a storage write\n $.status = BridgeStatus.REFUNDED;\n\n address to = request.originSender();\n address token = request.originToken();\n uint256 amount = request.originAmount() + request.originFeeAmount();\n // Emit the event before any external calls\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n // Complete the user refund as the last transaction action\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(to), amount);\n } else {\n IERC20(token).safeTransfer(to, amount);\n }\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // The correct relayer can only claim a RELAYER_PROVED transaction after the dispute period\n if ($.status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if ($.proofRelayer != relayer) revert SenderIncorrect();\n return _timeSince($.proofBlockTimestamp) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n /// @dev This method is added to achieve backwards compatibility with decoding requests into V1 structs:\n /// - `zapNative` is partially reported as a zero/non-zero flag\n /// - `zapData` is ignored\n /// In order to process all kinds of requests use getBridgeTransactionV2 instead.\n function getBridgeTransaction(bytes calldata request) external view returns (BridgeTransaction memory) {\n // Try decoding into V2 struct first. This will revert if V1 struct is passed\n try this.getBridgeTransactionV2(request) returns (BridgeTransactionV2 memory txV2) {\n // Note: we entirely ignore the zapData field, as it was not present in V1\n return BridgeTransaction({\n originChainId: txV2.originChainId,\n destChainId: txV2.destChainId,\n originSender: txV2.originSender,\n destRecipient: txV2.destRecipient,\n originToken: txV2.originToken,\n destToken: txV2.destToken,\n originAmount: txV2.originAmount,\n destAmount: txV2.destAmount,\n originFeeAmount: txV2.originFeeAmount,\n sendChainGas: txV2.zapNative != 0,\n deadline: txV2.deadline,\n nonce: txV2.nonce\n });\n } catch {\n // Fallback to V1 struct\n return abi.decode(request, (BridgeTransaction));\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function getBridgeTransactionV2(bytes calldata request) external pure returns (BridgeTransactionV2 memory) {\n request.validateV2();\n return BridgeTransactionV2Lib.decodeV2(request);\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) public payable {\n int256 exclusivityEndTime = 0;\n // if relayer exclusivity is not intended for this bridge, set exclusivityEndTime to static zero\n // otherwise, set exclusivity to expire at the current block ts offset by quoteExclusivitySeconds\n if (paramsV2.quoteRelayer != address(0)) {\n exclusivityEndTime = int256(block.timestamp) + paramsV2.quoteExclusivitySeconds;\n }\n _validateBridgeParams(params, paramsV2, exclusivityEndTime);\n\n // transfer tokens to bridge contract\n /// @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _takeBridgedUserAsset(params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) {\n originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n }\n\n // set status to requested\n bytes memory request = BridgeTransactionV2Lib.encodeV2(\n BridgeTransactionV2({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n deadline: params.deadline,\n nonce: senderNonces[params.sender]++, // increment nonce on every bridge\n exclusivityRelayer: paramsV2.quoteRelayer,\n // We checked exclusivityEndTime to be in range [0 .. params.deadline] above, so can safely cast\n exclusivityEndTime: uint256(exclusivityEndTime),\n zapNative: paramsV2.zapNative,\n zapData: paramsV2.zapData\n })\n );\n bytes32 transactionId = keccak256(request);\n // Note: the tx status will be updated throughout the tx lifecycle, while destChainId is set once here\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n bridgeTxDetails[transactionId].destChainId = params.dstChainId;\n\n emit BridgeRequested({\n transactionId: transactionId,\n sender: params.sender,\n request: request,\n destChainId: params.dstChainId,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n sendChainGas: paramsV2.zapNative != 0\n });\n emit BridgeQuoteDetails(transactionId, paramsV2.quoteId);\n }\n\n /// @inheritdoc IFastBridgeV2\n function relay(bytes calldata request, address relayer) public payable {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n _validateRelayParams(request, transactionId, relayer);\n // mark bridge transaction as relayed\n bridgeRelayDetails[transactionId] =\n BridgeRelay({blockNumber: uint48(block.number), blockTimestamp: uint48(block.timestamp), relayer: relayer});\n\n // transfer tokens to recipient on destination chain and trigger Zap if requested\n address to = request.destRecipient();\n address token = request.destToken();\n uint256 amount = request.destAmount();\n uint256 zapNative = request.zapNative();\n\n // Emit the event before any external calls\n emit BridgeRelayed({\n transactionId: transactionId,\n relayer: relayer,\n to: to,\n originChainId: request.originChainId(),\n originToken: request.originToken(),\n destToken: token,\n originAmount: request.originAmount(),\n destAmount: amount,\n chainGasAmount: zapNative\n });\n\n // All state changes have been done at this point, can proceed to the external calls.\n // This follows the checks-effects-interactions pattern to mitigate potential reentrancy attacks.\n if (token == NATIVE_GAS_TOKEN) {\n // For the native gas token, additional zapNative is not allowed\n if (zapNative != 0) revert ZapNativeNotSupported();\n // Check that the correct msg.value was sent\n if (msg.value != amount) revert MsgValueIncorrect();\n // Don't do a native transfer yet: we will handle it alongside the Zap below\n } else {\n // For ERC20s, we check that the correct msg.value was sent\n if (msg.value != zapNative) revert MsgValueIncorrect();\n // We need to transfer the tokens from the Relayer to the recipient first before performing an\n // optional post-transfer Zap.\n IERC20(token).safeTransferFrom(msg.sender, to, amount);\n }\n // At this point we have done:\n // - Transferred the requested amount of ERC20 tokens to the recipient.\n // At this point we have confirmed:\n // - For ERC20s: msg.value matches the requested zapNative amount.\n // - For the native gas token: msg.value matches the requested destAmount.\n // Remaining optional things to do:\n // - Forward the full msg.value to the recipient (if non-zero).\n // - Trigger a Zap (if zapData is present).\n bytes calldata zapData = request.zapData();\n if (zapData.length != 0) {\n // Zap Data is present: Zap has been requested by the recipient. Trigger it forwarding the full msg.value.\n\n // Note: if token has a fee on transfers, the recipient will have received less than `amount`.\n // This is a very niche edge case and should be handled by the recipient contract.\n _triggerZapWithChecks({recipient: to, token: token, amount: amount, zapData: zapData});\n } else if (msg.value != 0) {\n // Zap Data is missing, but msg.value was sent. This could happen in two different cases:\n // - Relay with the native gas token is happening.\n // - Relay with ERC20 is happening, with a `zapNative \u003e 0` request.\n // In both cases, we need to transfer the full msg.value to the recipient.\n Address.sendValue(payable(to), msg.value);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) public onlyRole(RELAYER_ROLE) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n\n // Can only prove a REQUESTED transaction\n if ($.status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n // Update status to RELAYER_PROVED and store the proof details\n // Note: these are storage writes\n $.status = BridgeStatus.RELAYER_PROVED;\n $.proofBlockTimestamp = uint56(block.timestamp);\n $.proofRelayer = relayer;\n\n emit BridgeProofProvided(transactionId, relayer, destTxHash);\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes calldata request, address to) public {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Aggregate the read operations from the same storage slot\n address proofRelayer = $.proofRelayer;\n BridgeStatus status = $.status;\n uint56 proofBlockTimestamp = $.proofBlockTimestamp;\n\n // Can only claim a RELAYER_PROVED transaction after the dispute period\n if (status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(proofBlockTimestamp) \u003c= DISPUTE_PERIOD) {\n revert DisputePeriodNotPassed();\n }\n\n if (to == address(0)) {\n // Anyone could claim the funds to the proven relayer on their behalf\n to = proofRelayer;\n } else if (proofRelayer != msg.sender) {\n // Only the proven relayer could specify an address to claim the funds to\n revert SenderIncorrect();\n }\n\n // Update status to RELAYER_CLAIMED and transfer the origin collateral to the specified claim address\n // Note: this is a storage write\n $.status = BridgeStatus.RELAYER_CLAIMED;\n\n address token = request.originToken();\n uint256 amount = request.originAmount();\n // Update protocol fees if origin fee amount exists\n uint256 originFeeAmount = request.originFeeAmount();\n if (originFeeAmount \u003e 0) protocolFees[token] += originFeeAmount;\n // Emit the event before any external calls\n emit BridgeDepositClaimed(transactionId, proofRelayer, to, token, amount);\n // Complete the relayer claim as the last transaction action\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(to), amount);\n } else {\n IERC20(token).safeTransfer(to, amount);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeStatuses(bytes32 transactionId) public view returns (BridgeStatus status) {\n return bridgeTxDetails[transactionId].status;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeProofs(bytes32 transactionId) public view returns (uint96 timestamp, address relayer) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n\n timestamp = $.proofBlockTimestamp;\n relayer = $.proofRelayer;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeRelays(bytes32 transactionId) public view returns (bool) {\n // has this transactionId been relayed?\n return bridgeRelayDetails[transactionId].relayer != address(0);\n }\n\n /// @notice Takes the bridged asset from the user into FastBridgeV2 custody. It will be later\n /// claimed by the relayer who completed the relay on destination chain, or refunded back to the user,\n /// should no one complete the relay.\n function _takeBridgedUserAsset(address token, uint256 amount) internal returns (uint256 amountTaken) {\n if (token == NATIVE_GAS_TOKEN) {\n // For the native gas token, we just need to check that the supplied msg.value is correct.\n // Supplied `msg.value` is already in FastBridgeV2 custody.\n if (amount != msg.value) revert MsgValueIncorrect();\n amountTaken = msg.value;\n } else {\n // For ERC20s, token is explicitly transferred from the user to FastBridgeV2.\n // We don't allow non-zero `msg.value` to avoid extra funds from being stuck in FastBridgeV2.\n if (msg.value != 0) revert MsgValueIncorrect();\n // Throw an explicit error if the provided token address is not a contract\n if (token.code.length == 0) revert TokenNotContract();\n amountTaken = IERC20(token).balanceOf(address(this));\n IERC20(token).safeTransferFrom(msg.sender, address(this), amount);\n // Use the balance difference as the amount taken in case of fee on transfer tokens.\n amountTaken = IERC20(token).balanceOf(address(this)) - amountTaken;\n }\n }\n\n /// @notice Calls the Recipient's hook function with the specified zapData and performs\n /// all the necessary checks for the returned value.\n function _triggerZapWithChecks(address recipient, address token, uint256 amount, bytes calldata zapData) internal {\n // This will bubble any revert messages from the hook function\n bytes memory returnData = Address.functionCallWithValue({\n target: recipient,\n data: abi.encodeCall(IZapRecipient.zap, (token, amount, zapData)),\n // Note: see `relay()` for reasoning behind passing msg.value\n value: msg.value\n });\n // Explicit revert if no return data at all\n if (returnData.length == 0) revert RecipientNoReturnValue();\n // Check that exactly a single return value was returned\n if (returnData.length != 32) revert RecipientIncorrectReturnValue();\n // Return value should be abi-encoded hook function selector\n if (bytes32(returnData) != bytes32(IZapRecipient.zap.selector)) {\n revert RecipientIncorrectReturnValue();\n }\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint56(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint56).max but\n /// proof.timestamp \u003c type(uint56).max via unchecked statement\n /// @param proofBlockTimestamp The bridge proof block timestamp\n /// @return delta Time delta since proof submitted\n function _timeSince(uint56 proofBlockTimestamp) internal view returns (uint256 delta) {\n unchecked {\n delta = uint56(block.timestamp) - proofBlockTimestamp;\n }\n }\n\n /// @notice Performs all the necessary checks for a bridge to happen.\n /// @dev There's no good way to refactor this function to reduce cyclomatic complexity due to\n /// the number of checks that need to be performed, so we skip the code-complexity rule here.\n // solhint-disable-next-line code-complexity\n function _validateBridgeParams(\n BridgeParams memory params,\n BridgeParamsV2 memory paramsV2,\n int256 exclusivityEndTime\n )\n internal\n view\n {\n // Check V1 (legacy) params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.sender == address(0) || params.to == address(0)) revert ZeroAddress();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n // Check V2 params\n if (paramsV2.zapData.length \u003e MAX_ZAP_DATA_LENGTH) revert ZapDataLengthAboveMax();\n if (paramsV2.zapNative != 0 \u0026\u0026 params.destToken == NATIVE_GAS_TOKEN) {\n revert ZapNativeNotSupported();\n }\n // exclusivityEndTime must be in range [0 .. params.deadline]\n if (exclusivityEndTime \u003c 0 || exclusivityEndTime \u003e int256(params.deadline)) {\n revert ExclusivityParamsIncorrect();\n }\n }\n\n /// @notice Performs all the necessary checks for a relay to happen.\n function _validateRelayParams(bytes calldata request, bytes32 transactionId, address relayer) internal view {\n if (relayer == address(0)) revert ZeroAddress();\n // Check if the transaction has already been relayed\n if (bridgeRelays(transactionId)) revert TransactionRelayed();\n if (request.destChainId() != block.chainid) revert ChainIncorrect();\n // Check the deadline for relay to happen\n if (block.timestamp \u003e request.deadline()) revert DeadlineExceeded();\n // Check the exclusivity period, if it is still ongoing\n address exclRelayer = request.exclusivityRelayer();\n if (exclRelayer != address(0) \u0026\u0026 exclRelayer != relayer \u0026\u0026 block.timestamp \u003c= request.exclusivityEndTime()) {\n revert ExclusivityPeriodNotPassed();\n }\n }\n}\n","language":"Solidity","languageVersion":"0.8.24","compilerVersion":"0.8.24","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"","srcMapRuntime":"","abiDefinition":[{"inputs":[],"name":"DOMAIN_SEPARATOR","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"nonces","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"permit","outputs":[],"stateMutability":"nonpayable","type":"function"}],"userDoc":{"kind":"user","methods":{},"version":1},"developerDoc":{"details":"Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in https://eips.ethereum.org/EIPS/eip-2612[EIP-2612]. Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't need to send a transaction, and thus is not required to hold Ether at all. ==== Security Considerations There are two important considerations concerning the use of `permit`. The first is that a valid permit signature expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be considered as an intention to spend the allowance in any specific way. The second is that because permits have built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be generally recommended is: ```solidity function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public { try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {} doThing(..., value); } function doThing(..., uint256 value) public { token.safeTransferFrom(msg.sender, address(this), value); ... } ``` Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also {SafeERC20-safeTransferFrom}). Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so contracts should have entry points that don't rely on permit.","kind":"dev","methods":{"DOMAIN_SEPARATOR()":{"details":"Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}."},"nonces(address)":{"details":"Returns the current nonce for `owner`. This value must be included whenever a signature is generated for {permit}. Every successful call to {permit} increases ``owner``'s nonce by one. This prevents a signature from being used multiple times."},"permit(address,address,uint256,uint256,uint8,bytes32,bytes32)":{"details":"Sets `value` as the allowance of `spender` over ``owner``'s tokens, given ``owner``'s signed approval. IMPORTANT: The same issues {IERC20-approve} has related to transaction ordering also apply here. Emits an {Approval} event. Requirements: - `spender` cannot be the zero address. - `deadline` must be a timestamp in the future. - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner` over the EIP712-formatted function arguments. - the signature must use ``owner``'s current nonce (see {nonces}). For more information on the signature format, see the https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP section]. CAUTION: See Security Considerations above."}},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[],\"name\":\"DOMAIN_SEPARATOR\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"}],\"name\":\"nonces\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"},{\"internalType\":\"uint8\",\"name\":\"v\",\"type\":\"uint8\"},{\"internalType\":\"bytes32\",\"name\":\"r\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"s\",\"type\":\"bytes32\"}],\"name\":\"permit\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"details\":\"Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in https://eips.ethereum.org/EIPS/eip-2612[EIP-2612]. Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't need to send a transaction, and thus is not required to hold Ether at all. ==== Security Considerations There are two important considerations concerning the use of `permit`. The first is that a valid permit signature expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be considered as an intention to spend the allowance in any specific way. The second is that because permits have built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be generally recommended is: ```solidity function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public { try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {} doThing(..., value); } function doThing(..., uint256 value) public { token.safeTransferFrom(msg.sender, address(this), value); ... } ``` Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also {SafeERC20-safeTransferFrom}). Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so contracts should have entry points that don't rely on permit.\",\"kind\":\"dev\",\"methods\":{\"DOMAIN_SEPARATOR()\":{\"details\":\"Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\"},\"nonces(address)\":{\"details\":\"Returns the current nonce for `owner`. This value must be included whenever a signature is generated for {permit}. Every successful call to {permit} increases ``owner``'s nonce by one. This prevents a signature from being used multiple times.\"},\"permit(address,address,uint256,uint256,uint8,bytes32,bytes32)\":{\"details\":\"Sets `value` as the allowance of `spender` over ``owner``'s tokens, given ``owner``'s signed approval. IMPORTANT: The same issues {IERC20-approve} has related to transaction ordering also apply here. Emits an {Approval} event. Requirements: - `spender` cannot be the zero address. - `deadline` must be a timestamp in the future. - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner` over the EIP712-formatted function arguments. - the signature must use ``owner``'s current nonce (see {nonces}). For more information on the signature format, see the https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP section]. CAUTION: See Security Considerations above.\"}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeV2.sol\":\"IERC20Permit\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeV2.sol\":{\"keccak256\":\"0x5069b55ca07f21bfe30b2a43c18a18318c8af9c181b2dcb07c290825efd70f34\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://273dc020a49d08e50126bbea0d7f783f79d08c702f2fdbc560618d24af308acc\",\"dweb:/ipfs/QmXJ2UVzFc8EPB74RT4CXQPC4xw66jt4T13poyfyd3UERh\"]}},\"version\":1}"},"hashes":{"DOMAIN_SEPARATOR()":"3644e515","nonces(address)":"7ecebe00","permit(address,address,uint256,uint256,uint8,bytes32,bytes32)":"d505accf"}},"solidity/FastBridgeV2.sol:IFastBridge":{"code":"0x","runtime-code":"0x","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.24 ^0.8.20 ^0.8.4;\n\n// contracts/interfaces/IAdmin.sol\n\ninterface IAdmin {\n // ============ Events ============\n\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n event ChainGasAmountUpdated(uint256 oldChainGasAmount, uint256 newChainGasAmount);\n\n // ============ Methods ============\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n\n function setChainGasAmount(uint256 newChainGasAmount) external;\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IFastBridgeV2Errors.sol\n\ninterface IFastBridgeV2Errors {\n error AmountIncorrect();\n error ChainIncorrect();\n error ExclusivityParamsIncorrect();\n error MsgValueIncorrect();\n error SenderIncorrect();\n error StatusIncorrect();\n error TokenNotContract();\n error ZapDataLengthAboveMax();\n error ZapNativeNotSupported();\n error ZeroAddress();\n\n error RecipientIncorrectReturnValue();\n error RecipientNoReturnValue();\n\n error DeadlineExceeded();\n error DeadlineNotExceeded();\n error DeadlineTooShort();\n error DisputePeriodNotPassed();\n error DisputePeriodPassed();\n error ExclusivityPeriodNotPassed();\n\n error TransactionRelayed();\n}\n\n// contracts/interfaces/IMulticallTarget.sol\n\n/// @notice Interface for a contract that can be called multiple times by the same caller. Inspired by MulticallV3:\n/// https://github.com/mds1/multicall/blob/master/src/Multicall3.sol\ninterface IMulticallTarget {\n struct Result {\n bool success;\n bytes returnData;\n }\n\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external;\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results);\n}\n\n// contracts/interfaces/IZapRecipient.sol\n\ninterface IZapRecipient {\n function zap(address token, uint256 amount, bytes memory zapData) external payable returns (bytes4);\n}\n\n// contracts/libs/Errors.sol\n\nerror DeadlineExceeded();\nerror DeadlineNotExceeded();\nerror DeadlineTooShort();\nerror InsufficientOutputAmount();\n\nerror MsgValueIncorrect();\nerror PoolNotFound();\nerror TokenAddressMismatch();\nerror TokenNotContract();\nerror TokenNotETH();\nerror TokensIdentical();\n\nerror ChainIncorrect();\nerror AmountIncorrect();\nerror ZeroAddress();\n\nerror DisputePeriodNotPassed();\nerror DisputePeriodPassed();\nerror SenderIncorrect();\nerror StatusIncorrect();\nerror TransactionIdIncorrect();\nerror TransactionRelayed();\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// contracts/interfaces/IFastBridgeV2.sol\n\ninterface IFastBridgeV2 is IFastBridge {\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n struct BridgeTxDetails {\n BridgeStatus status;\n uint32 destChainId;\n uint56 proofBlockTimestamp;\n address proofRelayer;\n }\n\n struct BridgeRelay {\n uint48 blockNumber;\n uint48 blockTimestamp;\n address relayer;\n }\n\n /// @notice New params introduced in the FastBridgeV2.\n /// We are passing fields from the older BridgeParams struct outside of this struct\n /// for backwards compatibility.\n /// Note: quoteRelayer and quoteExclusivitySeconds are either both zero (indicating no exclusivity)\n /// or both non-zero (indicating exclusivity for the given period).\n /// Note: zapNative \u003e 0 can NOT be used with destToken = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE (native token)\n /// @param quoteRelayer Relayer that provided the quote for the transaction\n /// @param quoteExclusivitySeconds Period of time the quote relayer is guaranteed exclusivity after user's deposit\n /// @param quoteId Unique quote identifier used for tracking the quote\n /// @param zapNative ETH value to send to the recipient (if any)\n /// @param zapData Parameters for the Zap to the destination recipient (if any)\n struct BridgeParamsV2 {\n address quoteRelayer;\n int256 quoteExclusivitySeconds;\n bytes quoteId;\n uint256 zapNative;\n bytes zapData;\n }\n\n /// @notice Updated bridge transaction struct to include parameters introduced in FastBridgeV2.\n /// Note: only `exclusivityRelayer` can fill such a transaction until `exclusivityEndTime`.\n struct BridgeTransactionV2 {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n // Note: sendChainGas flag from V1 is deprecated\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n address exclusivityRelayer;\n uint256 exclusivityEndTime;\n uint256 zapNative; // ETH value to send to the recipient (if any)\n bytes zapData; // data to pass for the Zap action (if any)\n }\n\n event BridgeQuoteDetails(bytes32 indexed transactionId, bytes quoteId);\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability\n /// to provide temporary exclusivity fill rights for the quote relayer.\n /// @param params The parameters required to bridge\n /// @param paramsV2 The parameters for exclusivity fill rights (optional, can be left empty)\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function relay(bytes memory request, address relayer) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param transactionId The transaction id associated with the encoded bridge transaction to prove\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital.\n /// @notice Can only send funds to the relayer address on the proof.\n /// @param request The encoded bridge transaction to claim on origin chain\n function claim(bytes memory request) external;\n /// @notice Checks if a transaction has been relayed\n /// @param transactionId The ID of the transaction to check\n /// @return True if the transaction has been relayed, false otherwise\n function bridgeRelays(bytes32 transactionId) external view returns (bool);\n\n /// @notice Returns the status of a bridge transaction\n /// @param transactionId The ID of the bridge transaction\n /// @return BridgeStatus Status of the bridge transaction\n function bridgeStatuses(bytes32 transactionId) external view returns (BridgeStatus);\n\n /// @notice Returns the timestamp and relayer of a bridge proof\n /// @param transactionId The ID of the bridge transaction\n /// @return timestamp The timestamp of the bridge proof\n /// @return relayer The relayer address of the bridge proof\n function bridgeProofs(bytes32 transactionId) external view returns (uint96 timestamp, address relayer);\n\n /// @notice Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\n /// @param request The bridge request to decode\n function getBridgeTransactionV2(bytes memory request) external view returns (BridgeTransactionV2 memory);\n}\n\n// contracts/utils/MulticallTarget.sol\n\n// solhint-disable avoid-low-level-calls\n/// @notice Template for a contract that supports batched calls (preserving the msg.sender).\n/// Only calls with zero msg.value could be batched.\nabstract contract MulticallTarget is IMulticallTarget {\n error MulticallTarget__UndeterminedRevert();\n\n /// @notice Perform a batched call to this contract, preserving the msg.sender.\n /// The return data from each call is discarded.\n /// @dev The method is non-payable, so only calls with `msg.value == 0` could be batched.\n /// It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag.\n /// Otherwise, the whole batch call will be reverted with the original revert reason.\n /// @param data List of abi-encoded calldata for the calls to perform.\n /// @param ignoreReverts Whether to ignore the revert errors from the calls.\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external {\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\n if (!success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(result);\n }\n }\n }\n\n /// @notice Perform a batched call to this contract, preserving the msg.sender.\n /// The return data from each call is preserved.\n /// @dev The method is non-payable, so only calls with `msg.value == 0` could be batched.\n /// It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag.\n /// Otherwise, the whole batch call will be reverted with the original revert reason.\n /// @param data List of abi-encoded calldata for the calls to perform.\n /// @param ignoreReverts Whether to ignore the revert errors from the calls.\n /// @return results List of results from the calls: `(success, returnData)`.\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results)\n {\n results = new Result[](data.length);\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (results[i].success, results[i].returnData) = address(this).delegatecall(data[i]);\n if (!results[i].success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(results[i].returnData);\n }\n }\n }\n\n /// @dev Bubbles the revert message from the underlying call.\n /// Note: preserves the same custom error or revert string, if one was used.\n /// Source: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v5.0.2/contracts/utils/Address.sol#L143-L158\n function _bubbleRevert(bytes memory returnData) internal pure {\n // Look for revert reason and bubble it up if present\n if (returnData.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n // solhint-disable-next-line no-inline-assembly\n assembly {\n let returndata_size := mload(returnData)\n revert(add(32, returnData), returndata_size)\n }\n } else {\n revert MulticallTarget__UndeterminedRevert();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// contracts/libs/BridgeTransactionV2.sol\n\n// solhint-disable no-inline-assembly\nlibrary BridgeTransactionV2Lib {\n uint16 internal constant VERSION = 2;\n\n // Offsets of the fields in the packed BridgeTransactionV2 struct\n // uint16 version [000 .. 002)\n // uint32 originChainId [002 .. 006)\n // uint32 destChainId [006 .. 010)\n // address originSender [010 .. 030)\n // address destRecipient [030 .. 050)\n // address originToken [050 .. 070)\n // address destToken [070 .. 090)\n // uint256 originAmount [090 .. 122)\n // uint256 destAmount [122 .. 154)\n // uint256 originFeeAmount [154 .. 186)\n // uint256 deadline [186 .. 218)\n // uint256 nonce [218 .. 250)\n // address exclusivityRelayer [250 .. 270)\n // uint256 exclusivityEndTime [270 .. 302)\n // uint256 zapNative [302 .. 334)\n // bytes zapData [334 .. ***)\n\n // forgefmt: disable-start\n uint256 private constant OFFSET_ORIGIN_CHAIN_ID = 2;\n uint256 private constant OFFSET_DEST_CHAIN_ID = 6;\n uint256 private constant OFFSET_ORIGIN_SENDER = 10;\n uint256 private constant OFFSET_DEST_RECIPIENT = 30;\n uint256 private constant OFFSET_ORIGIN_TOKEN = 50;\n uint256 private constant OFFSET_DEST_TOKEN = 70;\n uint256 private constant OFFSET_ORIGIN_AMOUNT = 90;\n uint256 private constant OFFSET_DEST_AMOUNT = 122;\n uint256 private constant OFFSET_ORIGIN_FEE_AMOUNT = 154;\n uint256 private constant OFFSET_DEADLINE = 186;\n uint256 private constant OFFSET_NONCE = 218;\n uint256 private constant OFFSET_EXCLUSIVITY_RELAYER = 250;\n uint256 private constant OFFSET_EXCLUSIVITY_END_TIME = 270;\n uint256 private constant OFFSET_ZAP_NATIVE = 302;\n uint256 private constant OFFSET_ZAP_DATA = 334;\n // forgefmt: disable-end\n\n error BridgeTransactionV2__InvalidEncodedTx();\n error BridgeTransactionV2__UnsupportedVersion(uint16 version);\n\n /// @notice Validates the encoded transaction to be a tightly packed encoded payload for BridgeTransactionV2.\n /// @dev Checks the minimum length and the version, use this function before decoding any of the fields.\n function validateV2(bytes calldata encodedTx) internal pure {\n // Check the minimum length: must at least include all static fields.\n if (encodedTx.length \u003c OFFSET_ZAP_DATA) revert BridgeTransactionV2__InvalidEncodedTx();\n // Once we validated the length, we can be sure that the version field is present.\n uint16 version_ = version(encodedTx);\n if (version_ != VERSION) revert BridgeTransactionV2__UnsupportedVersion(version_);\n }\n\n /// @notice Encodes the BridgeTransactionV2 struct by tightly packing the fields.\n /// @dev `abi.decode` will not work as a result of the tightly packed fields. Use `decodeV2` to decode instead.\n function encodeV2(IFastBridgeV2.BridgeTransactionV2 memory bridgeTx) internal pure returns (bytes memory) {\n // We split the encoding into two parts to avoid stack-too-deep error\n bytes memory firstPart = abi.encodePacked(\n VERSION,\n bridgeTx.originChainId,\n bridgeTx.destChainId,\n bridgeTx.originSender,\n bridgeTx.destRecipient,\n bridgeTx.originToken,\n bridgeTx.destToken,\n bridgeTx.originAmount\n );\n return abi.encodePacked(\n firstPart,\n bridgeTx.destAmount,\n bridgeTx.originFeeAmount,\n // Note: we skip the deprecated `sendChainGas` flag, which was present in BridgeTransaction V1\n bridgeTx.deadline,\n bridgeTx.nonce,\n // New V2 fields: exclusivity\n bridgeTx.exclusivityRelayer,\n bridgeTx.exclusivityEndTime,\n // New V2 fields: Zap\n bridgeTx.zapNative,\n bridgeTx.zapData\n );\n }\n\n /// @notice Decodes the BridgeTransactionV2 struct from the encoded transaction.\n /// @dev Encoded BridgeTransactionV2 struct must be tightly packed.\n /// Use `validateV2` before decoding to ensure the encoded transaction is valid.\n function decodeV2(bytes calldata encodedTx)\n internal\n pure\n returns (IFastBridgeV2.BridgeTransactionV2 memory bridgeTx)\n {\n bridgeTx.originChainId = originChainId(encodedTx);\n bridgeTx.destChainId = destChainId(encodedTx);\n bridgeTx.originSender = originSender(encodedTx);\n bridgeTx.destRecipient = destRecipient(encodedTx);\n bridgeTx.originToken = originToken(encodedTx);\n bridgeTx.destToken = destToken(encodedTx);\n bridgeTx.originAmount = originAmount(encodedTx);\n bridgeTx.destAmount = destAmount(encodedTx);\n bridgeTx.originFeeAmount = originFeeAmount(encodedTx);\n bridgeTx.deadline = deadline(encodedTx);\n bridgeTx.nonce = nonce(encodedTx);\n bridgeTx.exclusivityRelayer = exclusivityRelayer(encodedTx);\n bridgeTx.exclusivityEndTime = exclusivityEndTime(encodedTx);\n bridgeTx.zapNative = zapNative(encodedTx);\n bridgeTx.zapData = zapData(encodedTx);\n }\n\n /// @notice Extracts the version from the encoded transaction.\n function version(bytes calldata encodedTx) internal pure returns (uint16 version_) {\n // Load 32 bytes from the start and shift it 240 bits to the right to get the highest 16 bits.\n assembly {\n version_ := shr(240, calldataload(encodedTx.offset))\n }\n }\n\n /// @notice Extracts the origin chain ID from the encoded transaction.\n function originChainId(bytes calldata encodedTx) internal pure returns (uint32 originChainId_) {\n // Load 32 bytes from the offset and shift it 224 bits to the right to get the highest 32 bits.\n assembly {\n originChainId_ := shr(224, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_CHAIN_ID)))\n }\n }\n\n /// @notice Extracts the destination chain ID from the encoded transaction.\n function destChainId(bytes calldata encodedTx) internal pure returns (uint32 destChainId_) {\n // Load 32 bytes from the offset and shift it 224 bits to the right to get the highest 32 bits.\n assembly {\n destChainId_ := shr(224, calldataload(add(encodedTx.offset, OFFSET_DEST_CHAIN_ID)))\n }\n }\n\n /// @notice Extracts the origin sender from the encoded transaction.\n function originSender(bytes calldata encodedTx) internal pure returns (address originSender_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n originSender_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_SENDER)))\n }\n }\n\n /// @notice Extracts the destination recipient from the encoded transaction.\n function destRecipient(bytes calldata encodedTx) internal pure returns (address destRecipient_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n destRecipient_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_DEST_RECIPIENT)))\n }\n }\n\n /// @notice Extracts the origin token from the encoded transaction.\n function originToken(bytes calldata encodedTx) internal pure returns (address originToken_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n originToken_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_TOKEN)))\n }\n }\n\n /// @notice Extracts the destination token from the encoded transaction.\n function destToken(bytes calldata encodedTx) internal pure returns (address destToken_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n destToken_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_DEST_TOKEN)))\n }\n }\n\n /// @notice Extracts the origin amount from the encoded transaction.\n function originAmount(bytes calldata encodedTx) internal pure returns (uint256 originAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n originAmount_ := calldataload(add(encodedTx.offset, OFFSET_ORIGIN_AMOUNT))\n }\n }\n\n /// @notice Extracts the destination amount from the encoded transaction.\n function destAmount(bytes calldata encodedTx) internal pure returns (uint256 destAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n destAmount_ := calldataload(add(encodedTx.offset, OFFSET_DEST_AMOUNT))\n }\n }\n\n /// @notice Extracts the origin fee amount from the encoded transaction.\n function originFeeAmount(bytes calldata encodedTx) internal pure returns (uint256 originFeeAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n originFeeAmount_ := calldataload(add(encodedTx.offset, OFFSET_ORIGIN_FEE_AMOUNT))\n }\n }\n\n /// @notice Extracts the deadline from the encoded transaction.\n function deadline(bytes calldata encodedTx) internal pure returns (uint256 deadline_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n deadline_ := calldataload(add(encodedTx.offset, OFFSET_DEADLINE))\n }\n }\n\n /// @notice Extracts the nonce from the encoded transaction.\n function nonce(bytes calldata encodedTx) internal pure returns (uint256 nonce_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n nonce_ := calldataload(add(encodedTx.offset, OFFSET_NONCE))\n }\n }\n\n /// @notice Extracts the exclusivity relayer from the encoded transaction.\n function exclusivityRelayer(bytes calldata encodedTx) internal pure returns (address exclusivityRelayer_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n exclusivityRelayer_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_EXCLUSIVITY_RELAYER)))\n }\n }\n\n /// @notice Extracts the exclusivity end time from the encoded transaction.\n function exclusivityEndTime(bytes calldata encodedTx) internal pure returns (uint256 exclusivityEndTime_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n exclusivityEndTime_ := calldataload(add(encodedTx.offset, OFFSET_EXCLUSIVITY_END_TIME))\n }\n }\n\n /// @notice Extracts the Zap's native value from the encoded transaction.\n function zapNative(bytes calldata encodedTx) internal pure returns (uint256 zapNative_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n zapNative_ := calldataload(add(encodedTx.offset, OFFSET_ZAP_NATIVE))\n }\n }\n\n /// @notice Extracts the Zap's data from the encoded transaction.\n function zapData(bytes calldata encodedTx) internal pure returns (bytes calldata zapData_) {\n zapData_ = encodedTx[OFFSET_ZAP_DATA:];\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// contracts/libs/UniversalToken.sol\n\nlibrary UniversalTokenLib {\n using SafeERC20 for IERC20;\n\n address internal constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Transfers tokens to the given account. Reverts if transfer is not successful.\n /// @dev This might trigger fallback, if ETH is transferred to the contract.\n /// Make sure this can not lead to reentrancy attacks.\n function universalTransfer(address token, address to, uint256 value) internal {\n // Don't do anything, if need to send tokens to this address\n if (to == address(this)) return;\n // Don't do anything, if trying to send zero value\n if (value == 0) return;\n if (token == ETH_ADDRESS) {\n /// @dev Note: this can potentially lead to executing code in `to`.\n // solhint-disable-next-line avoid-low-level-calls\n (bool success,) = to.call{value: value}(\"\");\n require(success, \"ETH transfer failed\");\n } else {\n IERC20(token).safeTransfer(to, value);\n }\n }\n\n /// @notice Issues an infinite allowance to the spender, if the current allowance is insufficient\n /// to spend the given amount.\n function universalApproveInfinity(address token, address spender, uint256 amountToSpend) internal {\n // ETH Chad doesn't require your approval\n if (token == ETH_ADDRESS) return;\n // No-op if allowance is already sufficient\n uint256 allowance = IERC20(token).allowance(address(this), spender);\n if (allowance \u003e= amountToSpend) return;\n // Otherwise, reset approval to 0 and set to max allowance\n if (allowance \u003e 0) IERC20(token).safeDecreaseAllowance(spender, allowance);\n IERC20(token).safeIncreaseAllowance(spender, type(uint256).max);\n }\n\n /// @notice Returns the balance of the given token (or native ETH) for the given account.\n function universalBalanceOf(address token, address account) internal view returns (uint256) {\n if (token == ETH_ADDRESS) {\n return account.balance;\n } else {\n return IERC20(token).balanceOf(account);\n }\n }\n\n /// @dev Checks that token is a contract and not ETH_ADDRESS.\n function assertIsContract(address token) internal view {\n // Check that ETH_ADDRESS was not used (in case this is a predeploy on any of the chains)\n if (token == UniversalTokenLib.ETH_ADDRESS) revert TokenNotContract();\n // Check that token is not an EOA\n if (token.code.length == 0) revert TokenNotContract();\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/Admin.sol\n\ncontract Admin is IAdmin, AccessControlEnumerable {\n using UniversalTokenLib for address;\n\n bytes32 public constant RELAYER_ROLE = keccak256(\"RELAYER_ROLE\");\n bytes32 public constant REFUNDER_ROLE = keccak256(\"REFUNDER_ROLE\");\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n uint256 public constant FEE_BPS = 1e6;\n uint256 public constant FEE_RATE_MAX = 0.01e6; // max 1% on origin amount\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Chain gas amount to forward as rebate if requested\n uint256 public chainGasAmount;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n }\n\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n require(newFeeRate \u003c= FEE_RATE_MAX, \"newFeeRate \u003e max\");\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n token.universalTransfer(recipient, feeAmount);\n emit FeesSwept(token, recipient, feeAmount);\n }\n\n function setChainGasAmount(uint256 newChainGasAmount) external onlyRole(GOVERNOR_ROLE) {\n uint256 oldChainGasAmount = chainGasAmount;\n chainGasAmount = newChainGasAmount;\n emit ChainGasAmountUpdated(oldChainGasAmount, newChainGasAmount);\n }\n}\n\n// contracts/FastBridgeV2.sol\n\n/// @notice FastBridgeV2 is a contract for bridging tokens across chains.\ncontract FastBridgeV2 is Admin, MulticallTarget, IFastBridgeV2, IFastBridgeV2Errors {\n using BridgeTransactionV2Lib for bytes;\n using SafeERC20 for IERC20;\n\n /// @notice Address reserved for native gas token (ETH on Ethereum and most L2s, AVAX on Avalanche, etc)\n address public constant NATIVE_GAS_TOKEN = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Delay for a transaction after which it could be permisionlessly refunded\n uint256 public constant REFUND_DELAY = 7 days;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n /// @notice Maximum length of accepted zapData\n uint256 public constant MAX_ZAP_DATA_LENGTH = 2 ** 16 - 1;\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeTxDetails) public bridgeTxDetails;\n /// @notice Relay details on destination chain\n mapping(bytes32 =\u003e BridgeRelay) public bridgeRelayDetails;\n /// @notice Unique bridge nonces tracked per originSender\n mapping(address =\u003e uint256) public senderNonces;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Replaced by senderNonces\n uint256 public immutable nonce = 0;\n /// @notice the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n bridge({\n params: params,\n paramsV2: BridgeParamsV2({\n quoteRelayer: address(0),\n quoteExclusivitySeconds: 0,\n quoteId: bytes(\"\"),\n zapNative: 0,\n zapData: bytes(\"\")\n })\n });\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes calldata request) external payable {\n // relay override will validate the request\n relay({request: request, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes calldata request, bytes32 destTxHash) external {\n request.validateV2();\n prove({transactionId: keccak256(request), destTxHash: destTxHash, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridgeV2\n function claim(bytes calldata request) external {\n // claim override will validate the request\n claim({request: request, to: address(0)});\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Aggregate the read operations from the same storage slot\n address disputedRelayer = $.proofRelayer;\n BridgeStatus status = $.status;\n uint56 proofBlockTimestamp = $.proofBlockTimestamp;\n // Can only dispute a RELAYER_PROVED transaction within the dispute period\n if (status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(proofBlockTimestamp) \u003e DISPUTE_PERIOD) {\n revert DisputePeriodPassed();\n }\n // Update status to REQUESTED and delete the disputed proof details\n // Note: these are storage writes\n $.status = BridgeStatus.REQUESTED;\n $.proofRelayer = address(0);\n $.proofBlockTimestamp = 0;\n\n emit BridgeProofDisputed(transactionId, disputedRelayer);\n }\n\n /// @inheritdoc IFastBridge\n function refund(bytes calldata request) external {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Can only refund a REQUESTED transaction after its deadline expires\n if ($.status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n uint256 deadline = request.deadline();\n // Permissionless refund is only allowed after REFUND_DELAY on top of the deadline\n if (!hasRole(REFUNDER_ROLE, msg.sender)) deadline += REFUND_DELAY;\n if (block.timestamp \u003c= deadline) revert DeadlineNotExceeded();\n // Update status to REFUNDED and return the full amount (collateral + protocol fees) to the original sender.\n // The protocol fees are only updated when the transaction is claimed, so we don't need to update them here.\n // Note: this is a storage write\n $.status = BridgeStatus.REFUNDED;\n\n address to = request.originSender();\n address token = request.originToken();\n uint256 amount = request.originAmount() + request.originFeeAmount();\n // Emit the event before any external calls\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n // Complete the user refund as the last transaction action\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(to), amount);\n } else {\n IERC20(token).safeTransfer(to, amount);\n }\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // The correct relayer can only claim a RELAYER_PROVED transaction after the dispute period\n if ($.status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if ($.proofRelayer != relayer) revert SenderIncorrect();\n return _timeSince($.proofBlockTimestamp) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n /// @dev This method is added to achieve backwards compatibility with decoding requests into V1 structs:\n /// - `zapNative` is partially reported as a zero/non-zero flag\n /// - `zapData` is ignored\n /// In order to process all kinds of requests use getBridgeTransactionV2 instead.\n function getBridgeTransaction(bytes calldata request) external view returns (BridgeTransaction memory) {\n // Try decoding into V2 struct first. This will revert if V1 struct is passed\n try this.getBridgeTransactionV2(request) returns (BridgeTransactionV2 memory txV2) {\n // Note: we entirely ignore the zapData field, as it was not present in V1\n return BridgeTransaction({\n originChainId: txV2.originChainId,\n destChainId: txV2.destChainId,\n originSender: txV2.originSender,\n destRecipient: txV2.destRecipient,\n originToken: txV2.originToken,\n destToken: txV2.destToken,\n originAmount: txV2.originAmount,\n destAmount: txV2.destAmount,\n originFeeAmount: txV2.originFeeAmount,\n sendChainGas: txV2.zapNative != 0,\n deadline: txV2.deadline,\n nonce: txV2.nonce\n });\n } catch {\n // Fallback to V1 struct\n return abi.decode(request, (BridgeTransaction));\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function getBridgeTransactionV2(bytes calldata request) external pure returns (BridgeTransactionV2 memory) {\n request.validateV2();\n return BridgeTransactionV2Lib.decodeV2(request);\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) public payable {\n int256 exclusivityEndTime = 0;\n // if relayer exclusivity is not intended for this bridge, set exclusivityEndTime to static zero\n // otherwise, set exclusivity to expire at the current block ts offset by quoteExclusivitySeconds\n if (paramsV2.quoteRelayer != address(0)) {\n exclusivityEndTime = int256(block.timestamp) + paramsV2.quoteExclusivitySeconds;\n }\n _validateBridgeParams(params, paramsV2, exclusivityEndTime);\n\n // transfer tokens to bridge contract\n /// @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _takeBridgedUserAsset(params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) {\n originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n }\n\n // set status to requested\n bytes memory request = BridgeTransactionV2Lib.encodeV2(\n BridgeTransactionV2({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n deadline: params.deadline,\n nonce: senderNonces[params.sender]++, // increment nonce on every bridge\n exclusivityRelayer: paramsV2.quoteRelayer,\n // We checked exclusivityEndTime to be in range [0 .. params.deadline] above, so can safely cast\n exclusivityEndTime: uint256(exclusivityEndTime),\n zapNative: paramsV2.zapNative,\n zapData: paramsV2.zapData\n })\n );\n bytes32 transactionId = keccak256(request);\n // Note: the tx status will be updated throughout the tx lifecycle, while destChainId is set once here\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n bridgeTxDetails[transactionId].destChainId = params.dstChainId;\n\n emit BridgeRequested({\n transactionId: transactionId,\n sender: params.sender,\n request: request,\n destChainId: params.dstChainId,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n sendChainGas: paramsV2.zapNative != 0\n });\n emit BridgeQuoteDetails(transactionId, paramsV2.quoteId);\n }\n\n /// @inheritdoc IFastBridgeV2\n function relay(bytes calldata request, address relayer) public payable {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n _validateRelayParams(request, transactionId, relayer);\n // mark bridge transaction as relayed\n bridgeRelayDetails[transactionId] =\n BridgeRelay({blockNumber: uint48(block.number), blockTimestamp: uint48(block.timestamp), relayer: relayer});\n\n // transfer tokens to recipient on destination chain and trigger Zap if requested\n address to = request.destRecipient();\n address token = request.destToken();\n uint256 amount = request.destAmount();\n uint256 zapNative = request.zapNative();\n\n // Emit the event before any external calls\n emit BridgeRelayed({\n transactionId: transactionId,\n relayer: relayer,\n to: to,\n originChainId: request.originChainId(),\n originToken: request.originToken(),\n destToken: token,\n originAmount: request.originAmount(),\n destAmount: amount,\n chainGasAmount: zapNative\n });\n\n // All state changes have been done at this point, can proceed to the external calls.\n // This follows the checks-effects-interactions pattern to mitigate potential reentrancy attacks.\n if (token == NATIVE_GAS_TOKEN) {\n // For the native gas token, additional zapNative is not allowed\n if (zapNative != 0) revert ZapNativeNotSupported();\n // Check that the correct msg.value was sent\n if (msg.value != amount) revert MsgValueIncorrect();\n // Don't do a native transfer yet: we will handle it alongside the Zap below\n } else {\n // For ERC20s, we check that the correct msg.value was sent\n if (msg.value != zapNative) revert MsgValueIncorrect();\n // We need to transfer the tokens from the Relayer to the recipient first before performing an\n // optional post-transfer Zap.\n IERC20(token).safeTransferFrom(msg.sender, to, amount);\n }\n // At this point we have done:\n // - Transferred the requested amount of ERC20 tokens to the recipient.\n // At this point we have confirmed:\n // - For ERC20s: msg.value matches the requested zapNative amount.\n // - For the native gas token: msg.value matches the requested destAmount.\n // Remaining optional things to do:\n // - Forward the full msg.value to the recipient (if non-zero).\n // - Trigger a Zap (if zapData is present).\n bytes calldata zapData = request.zapData();\n if (zapData.length != 0) {\n // Zap Data is present: Zap has been requested by the recipient. Trigger it forwarding the full msg.value.\n\n // Note: if token has a fee on transfers, the recipient will have received less than `amount`.\n // This is a very niche edge case and should be handled by the recipient contract.\n _triggerZapWithChecks({recipient: to, token: token, amount: amount, zapData: zapData});\n } else if (msg.value != 0) {\n // Zap Data is missing, but msg.value was sent. This could happen in two different cases:\n // - Relay with the native gas token is happening.\n // - Relay with ERC20 is happening, with a `zapNative \u003e 0` request.\n // In both cases, we need to transfer the full msg.value to the recipient.\n Address.sendValue(payable(to), msg.value);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) public onlyRole(RELAYER_ROLE) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n\n // Can only prove a REQUESTED transaction\n if ($.status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n // Update status to RELAYER_PROVED and store the proof details\n // Note: these are storage writes\n $.status = BridgeStatus.RELAYER_PROVED;\n $.proofBlockTimestamp = uint56(block.timestamp);\n $.proofRelayer = relayer;\n\n emit BridgeProofProvided(transactionId, relayer, destTxHash);\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes calldata request, address to) public {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Aggregate the read operations from the same storage slot\n address proofRelayer = $.proofRelayer;\n BridgeStatus status = $.status;\n uint56 proofBlockTimestamp = $.proofBlockTimestamp;\n\n // Can only claim a RELAYER_PROVED transaction after the dispute period\n if (status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(proofBlockTimestamp) \u003c= DISPUTE_PERIOD) {\n revert DisputePeriodNotPassed();\n }\n\n if (to == address(0)) {\n // Anyone could claim the funds to the proven relayer on their behalf\n to = proofRelayer;\n } else if (proofRelayer != msg.sender) {\n // Only the proven relayer could specify an address to claim the funds to\n revert SenderIncorrect();\n }\n\n // Update status to RELAYER_CLAIMED and transfer the origin collateral to the specified claim address\n // Note: this is a storage write\n $.status = BridgeStatus.RELAYER_CLAIMED;\n\n address token = request.originToken();\n uint256 amount = request.originAmount();\n // Update protocol fees if origin fee amount exists\n uint256 originFeeAmount = request.originFeeAmount();\n if (originFeeAmount \u003e 0) protocolFees[token] += originFeeAmount;\n // Emit the event before any external calls\n emit BridgeDepositClaimed(transactionId, proofRelayer, to, token, amount);\n // Complete the relayer claim as the last transaction action\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(to), amount);\n } else {\n IERC20(token).safeTransfer(to, amount);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeStatuses(bytes32 transactionId) public view returns (BridgeStatus status) {\n return bridgeTxDetails[transactionId].status;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeProofs(bytes32 transactionId) public view returns (uint96 timestamp, address relayer) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n\n timestamp = $.proofBlockTimestamp;\n relayer = $.proofRelayer;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeRelays(bytes32 transactionId) public view returns (bool) {\n // has this transactionId been relayed?\n return bridgeRelayDetails[transactionId].relayer != address(0);\n }\n\n /// @notice Takes the bridged asset from the user into FastBridgeV2 custody. It will be later\n /// claimed by the relayer who completed the relay on destination chain, or refunded back to the user,\n /// should no one complete the relay.\n function _takeBridgedUserAsset(address token, uint256 amount) internal returns (uint256 amountTaken) {\n if (token == NATIVE_GAS_TOKEN) {\n // For the native gas token, we just need to check that the supplied msg.value is correct.\n // Supplied `msg.value` is already in FastBridgeV2 custody.\n if (amount != msg.value) revert MsgValueIncorrect();\n amountTaken = msg.value;\n } else {\n // For ERC20s, token is explicitly transferred from the user to FastBridgeV2.\n // We don't allow non-zero `msg.value` to avoid extra funds from being stuck in FastBridgeV2.\n if (msg.value != 0) revert MsgValueIncorrect();\n // Throw an explicit error if the provided token address is not a contract\n if (token.code.length == 0) revert TokenNotContract();\n amountTaken = IERC20(token).balanceOf(address(this));\n IERC20(token).safeTransferFrom(msg.sender, address(this), amount);\n // Use the balance difference as the amount taken in case of fee on transfer tokens.\n amountTaken = IERC20(token).balanceOf(address(this)) - amountTaken;\n }\n }\n\n /// @notice Calls the Recipient's hook function with the specified zapData and performs\n /// all the necessary checks for the returned value.\n function _triggerZapWithChecks(address recipient, address token, uint256 amount, bytes calldata zapData) internal {\n // This will bubble any revert messages from the hook function\n bytes memory returnData = Address.functionCallWithValue({\n target: recipient,\n data: abi.encodeCall(IZapRecipient.zap, (token, amount, zapData)),\n // Note: see `relay()` for reasoning behind passing msg.value\n value: msg.value\n });\n // Explicit revert if no return data at all\n if (returnData.length == 0) revert RecipientNoReturnValue();\n // Check that exactly a single return value was returned\n if (returnData.length != 32) revert RecipientIncorrectReturnValue();\n // Return value should be abi-encoded hook function selector\n if (bytes32(returnData) != bytes32(IZapRecipient.zap.selector)) {\n revert RecipientIncorrectReturnValue();\n }\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint56(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint56).max but\n /// proof.timestamp \u003c type(uint56).max via unchecked statement\n /// @param proofBlockTimestamp The bridge proof block timestamp\n /// @return delta Time delta since proof submitted\n function _timeSince(uint56 proofBlockTimestamp) internal view returns (uint256 delta) {\n unchecked {\n delta = uint56(block.timestamp) - proofBlockTimestamp;\n }\n }\n\n /// @notice Performs all the necessary checks for a bridge to happen.\n /// @dev There's no good way to refactor this function to reduce cyclomatic complexity due to\n /// the number of checks that need to be performed, so we skip the code-complexity rule here.\n // solhint-disable-next-line code-complexity\n function _validateBridgeParams(\n BridgeParams memory params,\n BridgeParamsV2 memory paramsV2,\n int256 exclusivityEndTime\n )\n internal\n view\n {\n // Check V1 (legacy) params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.sender == address(0) || params.to == address(0)) revert ZeroAddress();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n // Check V2 params\n if (paramsV2.zapData.length \u003e MAX_ZAP_DATA_LENGTH) revert ZapDataLengthAboveMax();\n if (paramsV2.zapNative != 0 \u0026\u0026 params.destToken == NATIVE_GAS_TOKEN) {\n revert ZapNativeNotSupported();\n }\n // exclusivityEndTime must be in range [0 .. params.deadline]\n if (exclusivityEndTime \u003c 0 || exclusivityEndTime \u003e int256(params.deadline)) {\n revert ExclusivityParamsIncorrect();\n }\n }\n\n /// @notice Performs all the necessary checks for a relay to happen.\n function _validateRelayParams(bytes calldata request, bytes32 transactionId, address relayer) internal view {\n if (relayer == address(0)) revert ZeroAddress();\n // Check if the transaction has already been relayed\n if (bridgeRelays(transactionId)) revert TransactionRelayed();\n if (request.destChainId() != block.chainid) revert ChainIncorrect();\n // Check the deadline for relay to happen\n if (block.timestamp \u003e request.deadline()) revert DeadlineExceeded();\n // Check the exclusivity period, if it is still ongoing\n address exclRelayer = request.exclusivityRelayer();\n if (exclRelayer != address(0) \u0026\u0026 exclRelayer != relayer \u0026\u0026 block.timestamp \u003c= request.exclusivityEndTime()) {\n revert ExclusivityPeriodNotPassed();\n }\n }\n}\n","language":"Solidity","languageVersion":"0.8.24","compilerVersion":"0.8.24","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"","srcMapRuntime":"","abiDefinition":[{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"relayer","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"BridgeDepositClaimed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"BridgeDepositRefunded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"relayer","type":"address"}],"name":"BridgeProofDisputed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"relayer","type":"address"},{"indexed":false,"internalType":"bytes32","name":"transactionHash","type":"bytes32"}],"name":"BridgeProofProvided","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"relayer","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint32","name":"originChainId","type":"uint32"},{"indexed":false,"internalType":"address","name":"originToken","type":"address"},{"indexed":false,"internalType":"address","name":"destToken","type":"address"},{"indexed":false,"internalType":"uint256","name":"originAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"destAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"chainGasAmount","type":"uint256"}],"name":"BridgeRelayed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"bytes","name":"request","type":"bytes"},{"indexed":false,"internalType":"uint32","name":"destChainId","type":"uint32"},{"indexed":false,"internalType":"address","name":"originToken","type":"address"},{"indexed":false,"internalType":"address","name":"destToken","type":"address"},{"indexed":false,"internalType":"uint256","name":"originAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"destAmount","type":"uint256"},{"indexed":false,"internalType":"bool","name":"sendChainGas","type":"bool"}],"name":"BridgeRequested","type":"event"},{"inputs":[{"components":[{"internalType":"uint32","name":"dstChainId","type":"uint32"},{"internalType":"address","name":"sender","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"address","name":"originToken","type":"address"},{"internalType":"address","name":"destToken","type":"address"},{"internalType":"uint256","name":"originAmount","type":"uint256"},{"internalType":"uint256","name":"destAmount","type":"uint256"},{"internalType":"bool","name":"sendChainGas","type":"bool"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"internalType":"struct IFastBridge.BridgeParams","name":"params","type":"tuple"}],"name":"bridge","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"internalType":"address","name":"relayer","type":"address"}],"name":"canClaim","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"},{"internalType":"address","name":"to","type":"address"}],"name":"claim","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"transactionId","type":"bytes32"}],"name":"dispute","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"}],"name":"getBridgeTransaction","outputs":[{"components":[{"internalType":"uint32","name":"originChainId","type":"uint32"},{"internalType":"uint32","name":"destChainId","type":"uint32"},{"internalType":"address","name":"originSender","type":"address"},{"internalType":"address","name":"destRecipient","type":"address"},{"internalType":"address","name":"originToken","type":"address"},{"internalType":"address","name":"destToken","type":"address"},{"internalType":"uint256","name":"originAmount","type":"uint256"},{"internalType":"uint256","name":"destAmount","type":"uint256"},{"internalType":"uint256","name":"originFeeAmount","type":"uint256"},{"internalType":"bool","name":"sendChainGas","type":"bool"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint256","name":"nonce","type":"uint256"}],"internalType":"struct IFastBridge.BridgeTransaction","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"},{"internalType":"bytes32","name":"destTxHash","type":"bytes32"}],"name":"prove","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"}],"name":"refund","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"}],"name":"relay","outputs":[],"stateMutability":"payable","type":"function"}],"userDoc":{"kind":"user","methods":{"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256))":{"notice":"Initiates bridge on origin chain to be relayed by off-chain relayer"},"canClaim(bytes32,address)":{"notice":"Checks if the dispute period has passed so bridge deposit can be claimed"},"claim(bytes,address)":{"notice":"Completes bridge transaction on origin chain by claiming originally deposited capital"},"dispute(bytes32)":{"notice":"Disputes an outstanding proof in case relayer provided dest chain tx is invalid"},"getBridgeTransaction(bytes)":{"notice":"Decodes bridge request into a bridge transaction"},"prove(bytes,bytes32)":{"notice":"Provides proof on origin side that relayer provided funds on destination side of bridge transaction"},"refund(bytes)":{"notice":"Refunds an outstanding bridge transaction in case optimistic bridging failed"},"relay(bytes)":{"notice":"Relays destination side of bridge transaction by off-chain relayer"}},"version":1},"developerDoc":{"kind":"dev","methods":{"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256))":{"params":{"params":"The parameters required to bridge"}},"canClaim(bytes32,address)":{"params":{"relayer":"The address of the relayer attempting to claim","transactionId":"The transaction id associated with the encoded bridge transaction to check"}},"claim(bytes,address)":{"params":{"request":"The encoded bridge transaction to claim on origin chain","to":"The recipient address of the funds"}},"dispute(bytes32)":{"params":{"transactionId":"The transaction id associated with the encoded bridge transaction to dispute"}},"getBridgeTransaction(bytes)":{"params":{"request":"The bridge request to decode"}},"prove(bytes,bytes32)":{"params":{"destTxHash":"The destination tx hash proving bridge transaction was relayed","request":"The encoded bridge transaction to prove on origin chain"}},"refund(bytes)":{"params":{"request":"The encoded bridge transaction to refund"}},"relay(bytes)":{"params":{"request":"The encoded bridge transaction to relay on destination chain"}}},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"BridgeDepositClaimed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"BridgeDepositRefunded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"name\":\"BridgeProofDisputed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"transactionHash\",\"type\":\"bytes32\"}],\"name\":\"BridgeProofProvided\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"originChainId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"chainGasAmount\",\"type\":\"uint256\"}],\"name\":\"BridgeRelayed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"destChainId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"sendChainGas\",\"type\":\"bool\"}],\"name\":\"BridgeRequested\",\"type\":\"event\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"dstChainId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"sendChainGas\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"}],\"internalType\":\"struct IFastBridge.BridgeParams\",\"name\":\"params\",\"type\":\"tuple\"}],\"name\":\"bridge\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"name\":\"canClaim\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"claim\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"}],\"name\":\"dispute\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"getBridgeTransaction\",\"outputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"originChainId\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"destChainId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"originSender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destRecipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"originFeeAmount\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"sendChainGas\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"}],\"internalType\":\"struct IFastBridge.BridgeTransaction\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"},{\"internalType\":\"bytes32\",\"name\":\"destTxHash\",\"type\":\"bytes32\"}],\"name\":\"prove\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"refund\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"relay\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{\"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256))\":{\"params\":{\"params\":\"The parameters required to bridge\"}},\"canClaim(bytes32,address)\":{\"params\":{\"relayer\":\"The address of the relayer attempting to claim\",\"transactionId\":\"The transaction id associated with the encoded bridge transaction to check\"}},\"claim(bytes,address)\":{\"params\":{\"request\":\"The encoded bridge transaction to claim on origin chain\",\"to\":\"The recipient address of the funds\"}},\"dispute(bytes32)\":{\"params\":{\"transactionId\":\"The transaction id associated with the encoded bridge transaction to dispute\"}},\"getBridgeTransaction(bytes)\":{\"params\":{\"request\":\"The bridge request to decode\"}},\"prove(bytes,bytes32)\":{\"params\":{\"destTxHash\":\"The destination tx hash proving bridge transaction was relayed\",\"request\":\"The encoded bridge transaction to prove on origin chain\"}},\"refund(bytes)\":{\"params\":{\"request\":\"The encoded bridge transaction to refund\"}},\"relay(bytes)\":{\"params\":{\"request\":\"The encoded bridge transaction to relay on destination chain\"}}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256))\":{\"notice\":\"Initiates bridge on origin chain to be relayed by off-chain relayer\"},\"canClaim(bytes32,address)\":{\"notice\":\"Checks if the dispute period has passed so bridge deposit can be claimed\"},\"claim(bytes,address)\":{\"notice\":\"Completes bridge transaction on origin chain by claiming originally deposited capital\"},\"dispute(bytes32)\":{\"notice\":\"Disputes an outstanding proof in case relayer provided dest chain tx is invalid\"},\"getBridgeTransaction(bytes)\":{\"notice\":\"Decodes bridge request into a bridge transaction\"},\"prove(bytes,bytes32)\":{\"notice\":\"Provides proof on origin side that relayer provided funds on destination side of bridge transaction\"},\"refund(bytes)\":{\"notice\":\"Refunds an outstanding bridge transaction in case optimistic bridging failed\"},\"relay(bytes)\":{\"notice\":\"Relays destination side of bridge transaction by off-chain relayer\"}},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeV2.sol\":\"IFastBridge\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeV2.sol\":{\"keccak256\":\"0x5069b55ca07f21bfe30b2a43c18a18318c8af9c181b2dcb07c290825efd70f34\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://273dc020a49d08e50126bbea0d7f783f79d08c702f2fdbc560618d24af308acc\",\"dweb:/ipfs/QmXJ2UVzFc8EPB74RT4CXQPC4xw66jt4T13poyfyd3UERh\"]}},\"version\":1}"},"hashes":{"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256))":"45851694","canClaim(bytes32,address)":"aa9641ab","claim(bytes,address)":"41fcb612","dispute(bytes32)":"add98c70","getBridgeTransaction(bytes)":"ac11fb1a","prove(bytes,bytes32)":"886d36ff","refund(bytes)":"5eb7d946","relay(bytes)":"8f0d6f17"}},"solidity/FastBridgeV2.sol:IFastBridgeV2":{"code":"0x","runtime-code":"0x","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.24 ^0.8.20 ^0.8.4;\n\n// contracts/interfaces/IAdmin.sol\n\ninterface IAdmin {\n // ============ Events ============\n\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n event ChainGasAmountUpdated(uint256 oldChainGasAmount, uint256 newChainGasAmount);\n\n // ============ Methods ============\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n\n function setChainGasAmount(uint256 newChainGasAmount) external;\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IFastBridgeV2Errors.sol\n\ninterface IFastBridgeV2Errors {\n error AmountIncorrect();\n error ChainIncorrect();\n error ExclusivityParamsIncorrect();\n error MsgValueIncorrect();\n error SenderIncorrect();\n error StatusIncorrect();\n error TokenNotContract();\n error ZapDataLengthAboveMax();\n error ZapNativeNotSupported();\n error ZeroAddress();\n\n error RecipientIncorrectReturnValue();\n error RecipientNoReturnValue();\n\n error DeadlineExceeded();\n error DeadlineNotExceeded();\n error DeadlineTooShort();\n error DisputePeriodNotPassed();\n error DisputePeriodPassed();\n error ExclusivityPeriodNotPassed();\n\n error TransactionRelayed();\n}\n\n// contracts/interfaces/IMulticallTarget.sol\n\n/// @notice Interface for a contract that can be called multiple times by the same caller. Inspired by MulticallV3:\n/// https://github.com/mds1/multicall/blob/master/src/Multicall3.sol\ninterface IMulticallTarget {\n struct Result {\n bool success;\n bytes returnData;\n }\n\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external;\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results);\n}\n\n// contracts/interfaces/IZapRecipient.sol\n\ninterface IZapRecipient {\n function zap(address token, uint256 amount, bytes memory zapData) external payable returns (bytes4);\n}\n\n// contracts/libs/Errors.sol\n\nerror DeadlineExceeded();\nerror DeadlineNotExceeded();\nerror DeadlineTooShort();\nerror InsufficientOutputAmount();\n\nerror MsgValueIncorrect();\nerror PoolNotFound();\nerror TokenAddressMismatch();\nerror TokenNotContract();\nerror TokenNotETH();\nerror TokensIdentical();\n\nerror ChainIncorrect();\nerror AmountIncorrect();\nerror ZeroAddress();\n\nerror DisputePeriodNotPassed();\nerror DisputePeriodPassed();\nerror SenderIncorrect();\nerror StatusIncorrect();\nerror TransactionIdIncorrect();\nerror TransactionRelayed();\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// contracts/interfaces/IFastBridgeV2.sol\n\ninterface IFastBridgeV2 is IFastBridge {\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n struct BridgeTxDetails {\n BridgeStatus status;\n uint32 destChainId;\n uint56 proofBlockTimestamp;\n address proofRelayer;\n }\n\n struct BridgeRelay {\n uint48 blockNumber;\n uint48 blockTimestamp;\n address relayer;\n }\n\n /// @notice New params introduced in the FastBridgeV2.\n /// We are passing fields from the older BridgeParams struct outside of this struct\n /// for backwards compatibility.\n /// Note: quoteRelayer and quoteExclusivitySeconds are either both zero (indicating no exclusivity)\n /// or both non-zero (indicating exclusivity for the given period).\n /// Note: zapNative \u003e 0 can NOT be used with destToken = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE (native token)\n /// @param quoteRelayer Relayer that provided the quote for the transaction\n /// @param quoteExclusivitySeconds Period of time the quote relayer is guaranteed exclusivity after user's deposit\n /// @param quoteId Unique quote identifier used for tracking the quote\n /// @param zapNative ETH value to send to the recipient (if any)\n /// @param zapData Parameters for the Zap to the destination recipient (if any)\n struct BridgeParamsV2 {\n address quoteRelayer;\n int256 quoteExclusivitySeconds;\n bytes quoteId;\n uint256 zapNative;\n bytes zapData;\n }\n\n /// @notice Updated bridge transaction struct to include parameters introduced in FastBridgeV2.\n /// Note: only `exclusivityRelayer` can fill such a transaction until `exclusivityEndTime`.\n struct BridgeTransactionV2 {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n // Note: sendChainGas flag from V1 is deprecated\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n address exclusivityRelayer;\n uint256 exclusivityEndTime;\n uint256 zapNative; // ETH value to send to the recipient (if any)\n bytes zapData; // data to pass for the Zap action (if any)\n }\n\n event BridgeQuoteDetails(bytes32 indexed transactionId, bytes quoteId);\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability\n /// to provide temporary exclusivity fill rights for the quote relayer.\n /// @param params The parameters required to bridge\n /// @param paramsV2 The parameters for exclusivity fill rights (optional, can be left empty)\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function relay(bytes memory request, address relayer) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param transactionId The transaction id associated with the encoded bridge transaction to prove\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital.\n /// @notice Can only send funds to the relayer address on the proof.\n /// @param request The encoded bridge transaction to claim on origin chain\n function claim(bytes memory request) external;\n /// @notice Checks if a transaction has been relayed\n /// @param transactionId The ID of the transaction to check\n /// @return True if the transaction has been relayed, false otherwise\n function bridgeRelays(bytes32 transactionId) external view returns (bool);\n\n /// @notice Returns the status of a bridge transaction\n /// @param transactionId The ID of the bridge transaction\n /// @return BridgeStatus Status of the bridge transaction\n function bridgeStatuses(bytes32 transactionId) external view returns (BridgeStatus);\n\n /// @notice Returns the timestamp and relayer of a bridge proof\n /// @param transactionId The ID of the bridge transaction\n /// @return timestamp The timestamp of the bridge proof\n /// @return relayer The relayer address of the bridge proof\n function bridgeProofs(bytes32 transactionId) external view returns (uint96 timestamp, address relayer);\n\n /// @notice Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\n /// @param request The bridge request to decode\n function getBridgeTransactionV2(bytes memory request) external view returns (BridgeTransactionV2 memory);\n}\n\n// contracts/utils/MulticallTarget.sol\n\n// solhint-disable avoid-low-level-calls\n/// @notice Template for a contract that supports batched calls (preserving the msg.sender).\n/// Only calls with zero msg.value could be batched.\nabstract contract MulticallTarget is IMulticallTarget {\n error MulticallTarget__UndeterminedRevert();\n\n /// @notice Perform a batched call to this contract, preserving the msg.sender.\n /// The return data from each call is discarded.\n /// @dev The method is non-payable, so only calls with `msg.value == 0` could be batched.\n /// It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag.\n /// Otherwise, the whole batch call will be reverted with the original revert reason.\n /// @param data List of abi-encoded calldata for the calls to perform.\n /// @param ignoreReverts Whether to ignore the revert errors from the calls.\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external {\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\n if (!success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(result);\n }\n }\n }\n\n /// @notice Perform a batched call to this contract, preserving the msg.sender.\n /// The return data from each call is preserved.\n /// @dev The method is non-payable, so only calls with `msg.value == 0` could be batched.\n /// It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag.\n /// Otherwise, the whole batch call will be reverted with the original revert reason.\n /// @param data List of abi-encoded calldata for the calls to perform.\n /// @param ignoreReverts Whether to ignore the revert errors from the calls.\n /// @return results List of results from the calls: `(success, returnData)`.\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results)\n {\n results = new Result[](data.length);\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (results[i].success, results[i].returnData) = address(this).delegatecall(data[i]);\n if (!results[i].success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(results[i].returnData);\n }\n }\n }\n\n /// @dev Bubbles the revert message from the underlying call.\n /// Note: preserves the same custom error or revert string, if one was used.\n /// Source: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v5.0.2/contracts/utils/Address.sol#L143-L158\n function _bubbleRevert(bytes memory returnData) internal pure {\n // Look for revert reason and bubble it up if present\n if (returnData.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n // solhint-disable-next-line no-inline-assembly\n assembly {\n let returndata_size := mload(returnData)\n revert(add(32, returnData), returndata_size)\n }\n } else {\n revert MulticallTarget__UndeterminedRevert();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// contracts/libs/BridgeTransactionV2.sol\n\n// solhint-disable no-inline-assembly\nlibrary BridgeTransactionV2Lib {\n uint16 internal constant VERSION = 2;\n\n // Offsets of the fields in the packed BridgeTransactionV2 struct\n // uint16 version [000 .. 002)\n // uint32 originChainId [002 .. 006)\n // uint32 destChainId [006 .. 010)\n // address originSender [010 .. 030)\n // address destRecipient [030 .. 050)\n // address originToken [050 .. 070)\n // address destToken [070 .. 090)\n // uint256 originAmount [090 .. 122)\n // uint256 destAmount [122 .. 154)\n // uint256 originFeeAmount [154 .. 186)\n // uint256 deadline [186 .. 218)\n // uint256 nonce [218 .. 250)\n // address exclusivityRelayer [250 .. 270)\n // uint256 exclusivityEndTime [270 .. 302)\n // uint256 zapNative [302 .. 334)\n // bytes zapData [334 .. ***)\n\n // forgefmt: disable-start\n uint256 private constant OFFSET_ORIGIN_CHAIN_ID = 2;\n uint256 private constant OFFSET_DEST_CHAIN_ID = 6;\n uint256 private constant OFFSET_ORIGIN_SENDER = 10;\n uint256 private constant OFFSET_DEST_RECIPIENT = 30;\n uint256 private constant OFFSET_ORIGIN_TOKEN = 50;\n uint256 private constant OFFSET_DEST_TOKEN = 70;\n uint256 private constant OFFSET_ORIGIN_AMOUNT = 90;\n uint256 private constant OFFSET_DEST_AMOUNT = 122;\n uint256 private constant OFFSET_ORIGIN_FEE_AMOUNT = 154;\n uint256 private constant OFFSET_DEADLINE = 186;\n uint256 private constant OFFSET_NONCE = 218;\n uint256 private constant OFFSET_EXCLUSIVITY_RELAYER = 250;\n uint256 private constant OFFSET_EXCLUSIVITY_END_TIME = 270;\n uint256 private constant OFFSET_ZAP_NATIVE = 302;\n uint256 private constant OFFSET_ZAP_DATA = 334;\n // forgefmt: disable-end\n\n error BridgeTransactionV2__InvalidEncodedTx();\n error BridgeTransactionV2__UnsupportedVersion(uint16 version);\n\n /// @notice Validates the encoded transaction to be a tightly packed encoded payload for BridgeTransactionV2.\n /// @dev Checks the minimum length and the version, use this function before decoding any of the fields.\n function validateV2(bytes calldata encodedTx) internal pure {\n // Check the minimum length: must at least include all static fields.\n if (encodedTx.length \u003c OFFSET_ZAP_DATA) revert BridgeTransactionV2__InvalidEncodedTx();\n // Once we validated the length, we can be sure that the version field is present.\n uint16 version_ = version(encodedTx);\n if (version_ != VERSION) revert BridgeTransactionV2__UnsupportedVersion(version_);\n }\n\n /// @notice Encodes the BridgeTransactionV2 struct by tightly packing the fields.\n /// @dev `abi.decode` will not work as a result of the tightly packed fields. Use `decodeV2` to decode instead.\n function encodeV2(IFastBridgeV2.BridgeTransactionV2 memory bridgeTx) internal pure returns (bytes memory) {\n // We split the encoding into two parts to avoid stack-too-deep error\n bytes memory firstPart = abi.encodePacked(\n VERSION,\n bridgeTx.originChainId,\n bridgeTx.destChainId,\n bridgeTx.originSender,\n bridgeTx.destRecipient,\n bridgeTx.originToken,\n bridgeTx.destToken,\n bridgeTx.originAmount\n );\n return abi.encodePacked(\n firstPart,\n bridgeTx.destAmount,\n bridgeTx.originFeeAmount,\n // Note: we skip the deprecated `sendChainGas` flag, which was present in BridgeTransaction V1\n bridgeTx.deadline,\n bridgeTx.nonce,\n // New V2 fields: exclusivity\n bridgeTx.exclusivityRelayer,\n bridgeTx.exclusivityEndTime,\n // New V2 fields: Zap\n bridgeTx.zapNative,\n bridgeTx.zapData\n );\n }\n\n /// @notice Decodes the BridgeTransactionV2 struct from the encoded transaction.\n /// @dev Encoded BridgeTransactionV2 struct must be tightly packed.\n /// Use `validateV2` before decoding to ensure the encoded transaction is valid.\n function decodeV2(bytes calldata encodedTx)\n internal\n pure\n returns (IFastBridgeV2.BridgeTransactionV2 memory bridgeTx)\n {\n bridgeTx.originChainId = originChainId(encodedTx);\n bridgeTx.destChainId = destChainId(encodedTx);\n bridgeTx.originSender = originSender(encodedTx);\n bridgeTx.destRecipient = destRecipient(encodedTx);\n bridgeTx.originToken = originToken(encodedTx);\n bridgeTx.destToken = destToken(encodedTx);\n bridgeTx.originAmount = originAmount(encodedTx);\n bridgeTx.destAmount = destAmount(encodedTx);\n bridgeTx.originFeeAmount = originFeeAmount(encodedTx);\n bridgeTx.deadline = deadline(encodedTx);\n bridgeTx.nonce = nonce(encodedTx);\n bridgeTx.exclusivityRelayer = exclusivityRelayer(encodedTx);\n bridgeTx.exclusivityEndTime = exclusivityEndTime(encodedTx);\n bridgeTx.zapNative = zapNative(encodedTx);\n bridgeTx.zapData = zapData(encodedTx);\n }\n\n /// @notice Extracts the version from the encoded transaction.\n function version(bytes calldata encodedTx) internal pure returns (uint16 version_) {\n // Load 32 bytes from the start and shift it 240 bits to the right to get the highest 16 bits.\n assembly {\n version_ := shr(240, calldataload(encodedTx.offset))\n }\n }\n\n /// @notice Extracts the origin chain ID from the encoded transaction.\n function originChainId(bytes calldata encodedTx) internal pure returns (uint32 originChainId_) {\n // Load 32 bytes from the offset and shift it 224 bits to the right to get the highest 32 bits.\n assembly {\n originChainId_ := shr(224, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_CHAIN_ID)))\n }\n }\n\n /// @notice Extracts the destination chain ID from the encoded transaction.\n function destChainId(bytes calldata encodedTx) internal pure returns (uint32 destChainId_) {\n // Load 32 bytes from the offset and shift it 224 bits to the right to get the highest 32 bits.\n assembly {\n destChainId_ := shr(224, calldataload(add(encodedTx.offset, OFFSET_DEST_CHAIN_ID)))\n }\n }\n\n /// @notice Extracts the origin sender from the encoded transaction.\n function originSender(bytes calldata encodedTx) internal pure returns (address originSender_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n originSender_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_SENDER)))\n }\n }\n\n /// @notice Extracts the destination recipient from the encoded transaction.\n function destRecipient(bytes calldata encodedTx) internal pure returns (address destRecipient_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n destRecipient_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_DEST_RECIPIENT)))\n }\n }\n\n /// @notice Extracts the origin token from the encoded transaction.\n function originToken(bytes calldata encodedTx) internal pure returns (address originToken_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n originToken_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_TOKEN)))\n }\n }\n\n /// @notice Extracts the destination token from the encoded transaction.\n function destToken(bytes calldata encodedTx) internal pure returns (address destToken_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n destToken_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_DEST_TOKEN)))\n }\n }\n\n /// @notice Extracts the origin amount from the encoded transaction.\n function originAmount(bytes calldata encodedTx) internal pure returns (uint256 originAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n originAmount_ := calldataload(add(encodedTx.offset, OFFSET_ORIGIN_AMOUNT))\n }\n }\n\n /// @notice Extracts the destination amount from the encoded transaction.\n function destAmount(bytes calldata encodedTx) internal pure returns (uint256 destAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n destAmount_ := calldataload(add(encodedTx.offset, OFFSET_DEST_AMOUNT))\n }\n }\n\n /// @notice Extracts the origin fee amount from the encoded transaction.\n function originFeeAmount(bytes calldata encodedTx) internal pure returns (uint256 originFeeAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n originFeeAmount_ := calldataload(add(encodedTx.offset, OFFSET_ORIGIN_FEE_AMOUNT))\n }\n }\n\n /// @notice Extracts the deadline from the encoded transaction.\n function deadline(bytes calldata encodedTx) internal pure returns (uint256 deadline_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n deadline_ := calldataload(add(encodedTx.offset, OFFSET_DEADLINE))\n }\n }\n\n /// @notice Extracts the nonce from the encoded transaction.\n function nonce(bytes calldata encodedTx) internal pure returns (uint256 nonce_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n nonce_ := calldataload(add(encodedTx.offset, OFFSET_NONCE))\n }\n }\n\n /// @notice Extracts the exclusivity relayer from the encoded transaction.\n function exclusivityRelayer(bytes calldata encodedTx) internal pure returns (address exclusivityRelayer_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n exclusivityRelayer_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_EXCLUSIVITY_RELAYER)))\n }\n }\n\n /// @notice Extracts the exclusivity end time from the encoded transaction.\n function exclusivityEndTime(bytes calldata encodedTx) internal pure returns (uint256 exclusivityEndTime_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n exclusivityEndTime_ := calldataload(add(encodedTx.offset, OFFSET_EXCLUSIVITY_END_TIME))\n }\n }\n\n /// @notice Extracts the Zap's native value from the encoded transaction.\n function zapNative(bytes calldata encodedTx) internal pure returns (uint256 zapNative_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n zapNative_ := calldataload(add(encodedTx.offset, OFFSET_ZAP_NATIVE))\n }\n }\n\n /// @notice Extracts the Zap's data from the encoded transaction.\n function zapData(bytes calldata encodedTx) internal pure returns (bytes calldata zapData_) {\n zapData_ = encodedTx[OFFSET_ZAP_DATA:];\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// contracts/libs/UniversalToken.sol\n\nlibrary UniversalTokenLib {\n using SafeERC20 for IERC20;\n\n address internal constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Transfers tokens to the given account. Reverts if transfer is not successful.\n /// @dev This might trigger fallback, if ETH is transferred to the contract.\n /// Make sure this can not lead to reentrancy attacks.\n function universalTransfer(address token, address to, uint256 value) internal {\n // Don't do anything, if need to send tokens to this address\n if (to == address(this)) return;\n // Don't do anything, if trying to send zero value\n if (value == 0) return;\n if (token == ETH_ADDRESS) {\n /// @dev Note: this can potentially lead to executing code in `to`.\n // solhint-disable-next-line avoid-low-level-calls\n (bool success,) = to.call{value: value}(\"\");\n require(success, \"ETH transfer failed\");\n } else {\n IERC20(token).safeTransfer(to, value);\n }\n }\n\n /// @notice Issues an infinite allowance to the spender, if the current allowance is insufficient\n /// to spend the given amount.\n function universalApproveInfinity(address token, address spender, uint256 amountToSpend) internal {\n // ETH Chad doesn't require your approval\n if (token == ETH_ADDRESS) return;\n // No-op if allowance is already sufficient\n uint256 allowance = IERC20(token).allowance(address(this), spender);\n if (allowance \u003e= amountToSpend) return;\n // Otherwise, reset approval to 0 and set to max allowance\n if (allowance \u003e 0) IERC20(token).safeDecreaseAllowance(spender, allowance);\n IERC20(token).safeIncreaseAllowance(spender, type(uint256).max);\n }\n\n /// @notice Returns the balance of the given token (or native ETH) for the given account.\n function universalBalanceOf(address token, address account) internal view returns (uint256) {\n if (token == ETH_ADDRESS) {\n return account.balance;\n } else {\n return IERC20(token).balanceOf(account);\n }\n }\n\n /// @dev Checks that token is a contract and not ETH_ADDRESS.\n function assertIsContract(address token) internal view {\n // Check that ETH_ADDRESS was not used (in case this is a predeploy on any of the chains)\n if (token == UniversalTokenLib.ETH_ADDRESS) revert TokenNotContract();\n // Check that token is not an EOA\n if (token.code.length == 0) revert TokenNotContract();\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/Admin.sol\n\ncontract Admin is IAdmin, AccessControlEnumerable {\n using UniversalTokenLib for address;\n\n bytes32 public constant RELAYER_ROLE = keccak256(\"RELAYER_ROLE\");\n bytes32 public constant REFUNDER_ROLE = keccak256(\"REFUNDER_ROLE\");\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n uint256 public constant FEE_BPS = 1e6;\n uint256 public constant FEE_RATE_MAX = 0.01e6; // max 1% on origin amount\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Chain gas amount to forward as rebate if requested\n uint256 public chainGasAmount;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n }\n\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n require(newFeeRate \u003c= FEE_RATE_MAX, \"newFeeRate \u003e max\");\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n token.universalTransfer(recipient, feeAmount);\n emit FeesSwept(token, recipient, feeAmount);\n }\n\n function setChainGasAmount(uint256 newChainGasAmount) external onlyRole(GOVERNOR_ROLE) {\n uint256 oldChainGasAmount = chainGasAmount;\n chainGasAmount = newChainGasAmount;\n emit ChainGasAmountUpdated(oldChainGasAmount, newChainGasAmount);\n }\n}\n\n// contracts/FastBridgeV2.sol\n\n/// @notice FastBridgeV2 is a contract for bridging tokens across chains.\ncontract FastBridgeV2 is Admin, MulticallTarget, IFastBridgeV2, IFastBridgeV2Errors {\n using BridgeTransactionV2Lib for bytes;\n using SafeERC20 for IERC20;\n\n /// @notice Address reserved for native gas token (ETH on Ethereum and most L2s, AVAX on Avalanche, etc)\n address public constant NATIVE_GAS_TOKEN = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Delay for a transaction after which it could be permisionlessly refunded\n uint256 public constant REFUND_DELAY = 7 days;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n /// @notice Maximum length of accepted zapData\n uint256 public constant MAX_ZAP_DATA_LENGTH = 2 ** 16 - 1;\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeTxDetails) public bridgeTxDetails;\n /// @notice Relay details on destination chain\n mapping(bytes32 =\u003e BridgeRelay) public bridgeRelayDetails;\n /// @notice Unique bridge nonces tracked per originSender\n mapping(address =\u003e uint256) public senderNonces;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Replaced by senderNonces\n uint256 public immutable nonce = 0;\n /// @notice the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n bridge({\n params: params,\n paramsV2: BridgeParamsV2({\n quoteRelayer: address(0),\n quoteExclusivitySeconds: 0,\n quoteId: bytes(\"\"),\n zapNative: 0,\n zapData: bytes(\"\")\n })\n });\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes calldata request) external payable {\n // relay override will validate the request\n relay({request: request, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes calldata request, bytes32 destTxHash) external {\n request.validateV2();\n prove({transactionId: keccak256(request), destTxHash: destTxHash, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridgeV2\n function claim(bytes calldata request) external {\n // claim override will validate the request\n claim({request: request, to: address(0)});\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Aggregate the read operations from the same storage slot\n address disputedRelayer = $.proofRelayer;\n BridgeStatus status = $.status;\n uint56 proofBlockTimestamp = $.proofBlockTimestamp;\n // Can only dispute a RELAYER_PROVED transaction within the dispute period\n if (status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(proofBlockTimestamp) \u003e DISPUTE_PERIOD) {\n revert DisputePeriodPassed();\n }\n // Update status to REQUESTED and delete the disputed proof details\n // Note: these are storage writes\n $.status = BridgeStatus.REQUESTED;\n $.proofRelayer = address(0);\n $.proofBlockTimestamp = 0;\n\n emit BridgeProofDisputed(transactionId, disputedRelayer);\n }\n\n /// @inheritdoc IFastBridge\n function refund(bytes calldata request) external {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Can only refund a REQUESTED transaction after its deadline expires\n if ($.status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n uint256 deadline = request.deadline();\n // Permissionless refund is only allowed after REFUND_DELAY on top of the deadline\n if (!hasRole(REFUNDER_ROLE, msg.sender)) deadline += REFUND_DELAY;\n if (block.timestamp \u003c= deadline) revert DeadlineNotExceeded();\n // Update status to REFUNDED and return the full amount (collateral + protocol fees) to the original sender.\n // The protocol fees are only updated when the transaction is claimed, so we don't need to update them here.\n // Note: this is a storage write\n $.status = BridgeStatus.REFUNDED;\n\n address to = request.originSender();\n address token = request.originToken();\n uint256 amount = request.originAmount() + request.originFeeAmount();\n // Emit the event before any external calls\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n // Complete the user refund as the last transaction action\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(to), amount);\n } else {\n IERC20(token).safeTransfer(to, amount);\n }\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // The correct relayer can only claim a RELAYER_PROVED transaction after the dispute period\n if ($.status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if ($.proofRelayer != relayer) revert SenderIncorrect();\n return _timeSince($.proofBlockTimestamp) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n /// @dev This method is added to achieve backwards compatibility with decoding requests into V1 structs:\n /// - `zapNative` is partially reported as a zero/non-zero flag\n /// - `zapData` is ignored\n /// In order to process all kinds of requests use getBridgeTransactionV2 instead.\n function getBridgeTransaction(bytes calldata request) external view returns (BridgeTransaction memory) {\n // Try decoding into V2 struct first. This will revert if V1 struct is passed\n try this.getBridgeTransactionV2(request) returns (BridgeTransactionV2 memory txV2) {\n // Note: we entirely ignore the zapData field, as it was not present in V1\n return BridgeTransaction({\n originChainId: txV2.originChainId,\n destChainId: txV2.destChainId,\n originSender: txV2.originSender,\n destRecipient: txV2.destRecipient,\n originToken: txV2.originToken,\n destToken: txV2.destToken,\n originAmount: txV2.originAmount,\n destAmount: txV2.destAmount,\n originFeeAmount: txV2.originFeeAmount,\n sendChainGas: txV2.zapNative != 0,\n deadline: txV2.deadline,\n nonce: txV2.nonce\n });\n } catch {\n // Fallback to V1 struct\n return abi.decode(request, (BridgeTransaction));\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function getBridgeTransactionV2(bytes calldata request) external pure returns (BridgeTransactionV2 memory) {\n request.validateV2();\n return BridgeTransactionV2Lib.decodeV2(request);\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) public payable {\n int256 exclusivityEndTime = 0;\n // if relayer exclusivity is not intended for this bridge, set exclusivityEndTime to static zero\n // otherwise, set exclusivity to expire at the current block ts offset by quoteExclusivitySeconds\n if (paramsV2.quoteRelayer != address(0)) {\n exclusivityEndTime = int256(block.timestamp) + paramsV2.quoteExclusivitySeconds;\n }\n _validateBridgeParams(params, paramsV2, exclusivityEndTime);\n\n // transfer tokens to bridge contract\n /// @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _takeBridgedUserAsset(params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) {\n originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n }\n\n // set status to requested\n bytes memory request = BridgeTransactionV2Lib.encodeV2(\n BridgeTransactionV2({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n deadline: params.deadline,\n nonce: senderNonces[params.sender]++, // increment nonce on every bridge\n exclusivityRelayer: paramsV2.quoteRelayer,\n // We checked exclusivityEndTime to be in range [0 .. params.deadline] above, so can safely cast\n exclusivityEndTime: uint256(exclusivityEndTime),\n zapNative: paramsV2.zapNative,\n zapData: paramsV2.zapData\n })\n );\n bytes32 transactionId = keccak256(request);\n // Note: the tx status will be updated throughout the tx lifecycle, while destChainId is set once here\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n bridgeTxDetails[transactionId].destChainId = params.dstChainId;\n\n emit BridgeRequested({\n transactionId: transactionId,\n sender: params.sender,\n request: request,\n destChainId: params.dstChainId,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n sendChainGas: paramsV2.zapNative != 0\n });\n emit BridgeQuoteDetails(transactionId, paramsV2.quoteId);\n }\n\n /// @inheritdoc IFastBridgeV2\n function relay(bytes calldata request, address relayer) public payable {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n _validateRelayParams(request, transactionId, relayer);\n // mark bridge transaction as relayed\n bridgeRelayDetails[transactionId] =\n BridgeRelay({blockNumber: uint48(block.number), blockTimestamp: uint48(block.timestamp), relayer: relayer});\n\n // transfer tokens to recipient on destination chain and trigger Zap if requested\n address to = request.destRecipient();\n address token = request.destToken();\n uint256 amount = request.destAmount();\n uint256 zapNative = request.zapNative();\n\n // Emit the event before any external calls\n emit BridgeRelayed({\n transactionId: transactionId,\n relayer: relayer,\n to: to,\n originChainId: request.originChainId(),\n originToken: request.originToken(),\n destToken: token,\n originAmount: request.originAmount(),\n destAmount: amount,\n chainGasAmount: zapNative\n });\n\n // All state changes have been done at this point, can proceed to the external calls.\n // This follows the checks-effects-interactions pattern to mitigate potential reentrancy attacks.\n if (token == NATIVE_GAS_TOKEN) {\n // For the native gas token, additional zapNative is not allowed\n if (zapNative != 0) revert ZapNativeNotSupported();\n // Check that the correct msg.value was sent\n if (msg.value != amount) revert MsgValueIncorrect();\n // Don't do a native transfer yet: we will handle it alongside the Zap below\n } else {\n // For ERC20s, we check that the correct msg.value was sent\n if (msg.value != zapNative) revert MsgValueIncorrect();\n // We need to transfer the tokens from the Relayer to the recipient first before performing an\n // optional post-transfer Zap.\n IERC20(token).safeTransferFrom(msg.sender, to, amount);\n }\n // At this point we have done:\n // - Transferred the requested amount of ERC20 tokens to the recipient.\n // At this point we have confirmed:\n // - For ERC20s: msg.value matches the requested zapNative amount.\n // - For the native gas token: msg.value matches the requested destAmount.\n // Remaining optional things to do:\n // - Forward the full msg.value to the recipient (if non-zero).\n // - Trigger a Zap (if zapData is present).\n bytes calldata zapData = request.zapData();\n if (zapData.length != 0) {\n // Zap Data is present: Zap has been requested by the recipient. Trigger it forwarding the full msg.value.\n\n // Note: if token has a fee on transfers, the recipient will have received less than `amount`.\n // This is a very niche edge case and should be handled by the recipient contract.\n _triggerZapWithChecks({recipient: to, token: token, amount: amount, zapData: zapData});\n } else if (msg.value != 0) {\n // Zap Data is missing, but msg.value was sent. This could happen in two different cases:\n // - Relay with the native gas token is happening.\n // - Relay with ERC20 is happening, with a `zapNative \u003e 0` request.\n // In both cases, we need to transfer the full msg.value to the recipient.\n Address.sendValue(payable(to), msg.value);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) public onlyRole(RELAYER_ROLE) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n\n // Can only prove a REQUESTED transaction\n if ($.status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n // Update status to RELAYER_PROVED and store the proof details\n // Note: these are storage writes\n $.status = BridgeStatus.RELAYER_PROVED;\n $.proofBlockTimestamp = uint56(block.timestamp);\n $.proofRelayer = relayer;\n\n emit BridgeProofProvided(transactionId, relayer, destTxHash);\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes calldata request, address to) public {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Aggregate the read operations from the same storage slot\n address proofRelayer = $.proofRelayer;\n BridgeStatus status = $.status;\n uint56 proofBlockTimestamp = $.proofBlockTimestamp;\n\n // Can only claim a RELAYER_PROVED transaction after the dispute period\n if (status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(proofBlockTimestamp) \u003c= DISPUTE_PERIOD) {\n revert DisputePeriodNotPassed();\n }\n\n if (to == address(0)) {\n // Anyone could claim the funds to the proven relayer on their behalf\n to = proofRelayer;\n } else if (proofRelayer != msg.sender) {\n // Only the proven relayer could specify an address to claim the funds to\n revert SenderIncorrect();\n }\n\n // Update status to RELAYER_CLAIMED and transfer the origin collateral to the specified claim address\n // Note: this is a storage write\n $.status = BridgeStatus.RELAYER_CLAIMED;\n\n address token = request.originToken();\n uint256 amount = request.originAmount();\n // Update protocol fees if origin fee amount exists\n uint256 originFeeAmount = request.originFeeAmount();\n if (originFeeAmount \u003e 0) protocolFees[token] += originFeeAmount;\n // Emit the event before any external calls\n emit BridgeDepositClaimed(transactionId, proofRelayer, to, token, amount);\n // Complete the relayer claim as the last transaction action\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(to), amount);\n } else {\n IERC20(token).safeTransfer(to, amount);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeStatuses(bytes32 transactionId) public view returns (BridgeStatus status) {\n return bridgeTxDetails[transactionId].status;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeProofs(bytes32 transactionId) public view returns (uint96 timestamp, address relayer) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n\n timestamp = $.proofBlockTimestamp;\n relayer = $.proofRelayer;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeRelays(bytes32 transactionId) public view returns (bool) {\n // has this transactionId been relayed?\n return bridgeRelayDetails[transactionId].relayer != address(0);\n }\n\n /// @notice Takes the bridged asset from the user into FastBridgeV2 custody. It will be later\n /// claimed by the relayer who completed the relay on destination chain, or refunded back to the user,\n /// should no one complete the relay.\n function _takeBridgedUserAsset(address token, uint256 amount) internal returns (uint256 amountTaken) {\n if (token == NATIVE_GAS_TOKEN) {\n // For the native gas token, we just need to check that the supplied msg.value is correct.\n // Supplied `msg.value` is already in FastBridgeV2 custody.\n if (amount != msg.value) revert MsgValueIncorrect();\n amountTaken = msg.value;\n } else {\n // For ERC20s, token is explicitly transferred from the user to FastBridgeV2.\n // We don't allow non-zero `msg.value` to avoid extra funds from being stuck in FastBridgeV2.\n if (msg.value != 0) revert MsgValueIncorrect();\n // Throw an explicit error if the provided token address is not a contract\n if (token.code.length == 0) revert TokenNotContract();\n amountTaken = IERC20(token).balanceOf(address(this));\n IERC20(token).safeTransferFrom(msg.sender, address(this), amount);\n // Use the balance difference as the amount taken in case of fee on transfer tokens.\n amountTaken = IERC20(token).balanceOf(address(this)) - amountTaken;\n }\n }\n\n /// @notice Calls the Recipient's hook function with the specified zapData and performs\n /// all the necessary checks for the returned value.\n function _triggerZapWithChecks(address recipient, address token, uint256 amount, bytes calldata zapData) internal {\n // This will bubble any revert messages from the hook function\n bytes memory returnData = Address.functionCallWithValue({\n target: recipient,\n data: abi.encodeCall(IZapRecipient.zap, (token, amount, zapData)),\n // Note: see `relay()` for reasoning behind passing msg.value\n value: msg.value\n });\n // Explicit revert if no return data at all\n if (returnData.length == 0) revert RecipientNoReturnValue();\n // Check that exactly a single return value was returned\n if (returnData.length != 32) revert RecipientIncorrectReturnValue();\n // Return value should be abi-encoded hook function selector\n if (bytes32(returnData) != bytes32(IZapRecipient.zap.selector)) {\n revert RecipientIncorrectReturnValue();\n }\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint56(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint56).max but\n /// proof.timestamp \u003c type(uint56).max via unchecked statement\n /// @param proofBlockTimestamp The bridge proof block timestamp\n /// @return delta Time delta since proof submitted\n function _timeSince(uint56 proofBlockTimestamp) internal view returns (uint256 delta) {\n unchecked {\n delta = uint56(block.timestamp) - proofBlockTimestamp;\n }\n }\n\n /// @notice Performs all the necessary checks for a bridge to happen.\n /// @dev There's no good way to refactor this function to reduce cyclomatic complexity due to\n /// the number of checks that need to be performed, so we skip the code-complexity rule here.\n // solhint-disable-next-line code-complexity\n function _validateBridgeParams(\n BridgeParams memory params,\n BridgeParamsV2 memory paramsV2,\n int256 exclusivityEndTime\n )\n internal\n view\n {\n // Check V1 (legacy) params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.sender == address(0) || params.to == address(0)) revert ZeroAddress();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n // Check V2 params\n if (paramsV2.zapData.length \u003e MAX_ZAP_DATA_LENGTH) revert ZapDataLengthAboveMax();\n if (paramsV2.zapNative != 0 \u0026\u0026 params.destToken == NATIVE_GAS_TOKEN) {\n revert ZapNativeNotSupported();\n }\n // exclusivityEndTime must be in range [0 .. params.deadline]\n if (exclusivityEndTime \u003c 0 || exclusivityEndTime \u003e int256(params.deadline)) {\n revert ExclusivityParamsIncorrect();\n }\n }\n\n /// @notice Performs all the necessary checks for a relay to happen.\n function _validateRelayParams(bytes calldata request, bytes32 transactionId, address relayer) internal view {\n if (relayer == address(0)) revert ZeroAddress();\n // Check if the transaction has already been relayed\n if (bridgeRelays(transactionId)) revert TransactionRelayed();\n if (request.destChainId() != block.chainid) revert ChainIncorrect();\n // Check the deadline for relay to happen\n if (block.timestamp \u003e request.deadline()) revert DeadlineExceeded();\n // Check the exclusivity period, if it is still ongoing\n address exclRelayer = request.exclusivityRelayer();\n if (exclRelayer != address(0) \u0026\u0026 exclRelayer != relayer \u0026\u0026 block.timestamp \u003c= request.exclusivityEndTime()) {\n revert ExclusivityPeriodNotPassed();\n }\n }\n}\n","language":"Solidity","languageVersion":"0.8.24","compilerVersion":"0.8.24","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"","srcMapRuntime":"","abiDefinition":[{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"relayer","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"BridgeDepositClaimed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"BridgeDepositRefunded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"relayer","type":"address"}],"name":"BridgeProofDisputed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"relayer","type":"address"},{"indexed":false,"internalType":"bytes32","name":"transactionHash","type":"bytes32"}],"name":"BridgeProofProvided","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":false,"internalType":"bytes","name":"quoteId","type":"bytes"}],"name":"BridgeQuoteDetails","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"relayer","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint32","name":"originChainId","type":"uint32"},{"indexed":false,"internalType":"address","name":"originToken","type":"address"},{"indexed":false,"internalType":"address","name":"destToken","type":"address"},{"indexed":false,"internalType":"uint256","name":"originAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"destAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"chainGasAmount","type":"uint256"}],"name":"BridgeRelayed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"bytes","name":"request","type":"bytes"},{"indexed":false,"internalType":"uint32","name":"destChainId","type":"uint32"},{"indexed":false,"internalType":"address","name":"originToken","type":"address"},{"indexed":false,"internalType":"address","name":"destToken","type":"address"},{"indexed":false,"internalType":"uint256","name":"originAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"destAmount","type":"uint256"},{"indexed":false,"internalType":"bool","name":"sendChainGas","type":"bool"}],"name":"BridgeRequested","type":"event"},{"inputs":[{"components":[{"internalType":"uint32","name":"dstChainId","type":"uint32"},{"internalType":"address","name":"sender","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"address","name":"originToken","type":"address"},{"internalType":"address","name":"destToken","type":"address"},{"internalType":"uint256","name":"originAmount","type":"uint256"},{"internalType":"uint256","name":"destAmount","type":"uint256"},{"internalType":"bool","name":"sendChainGas","type":"bool"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"internalType":"struct IFastBridge.BridgeParams","name":"params","type":"tuple"}],"name":"bridge","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"uint32","name":"dstChainId","type":"uint32"},{"internalType":"address","name":"sender","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"address","name":"originToken","type":"address"},{"internalType":"address","name":"destToken","type":"address"},{"internalType":"uint256","name":"originAmount","type":"uint256"},{"internalType":"uint256","name":"destAmount","type":"uint256"},{"internalType":"bool","name":"sendChainGas","type":"bool"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"internalType":"struct IFastBridge.BridgeParams","name":"params","type":"tuple"},{"components":[{"internalType":"address","name":"quoteRelayer","type":"address"},{"internalType":"int256","name":"quoteExclusivitySeconds","type":"int256"},{"internalType":"bytes","name":"quoteId","type":"bytes"},{"internalType":"uint256","name":"zapNative","type":"uint256"},{"internalType":"bytes","name":"zapData","type":"bytes"}],"internalType":"struct IFastBridgeV2.BridgeParamsV2","name":"paramsV2","type":"tuple"}],"name":"bridge","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"transactionId","type":"bytes32"}],"name":"bridgeProofs","outputs":[{"internalType":"uint96","name":"timestamp","type":"uint96"},{"internalType":"address","name":"relayer","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"transactionId","type":"bytes32"}],"name":"bridgeRelays","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"transactionId","type":"bytes32"}],"name":"bridgeStatuses","outputs":[{"internalType":"enum IFastBridgeV2.BridgeStatus","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"internalType":"address","name":"relayer","type":"address"}],"name":"canClaim","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"},{"internalType":"address","name":"to","type":"address"}],"name":"claim","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"}],"name":"claim","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"transactionId","type":"bytes32"}],"name":"dispute","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"}],"name":"getBridgeTransaction","outputs":[{"components":[{"internalType":"uint32","name":"originChainId","type":"uint32"},{"internalType":"uint32","name":"destChainId","type":"uint32"},{"internalType":"address","name":"originSender","type":"address"},{"internalType":"address","name":"destRecipient","type":"address"},{"internalType":"address","name":"originToken","type":"address"},{"internalType":"address","name":"destToken","type":"address"},{"internalType":"uint256","name":"originAmount","type":"uint256"},{"internalType":"uint256","name":"destAmount","type":"uint256"},{"internalType":"uint256","name":"originFeeAmount","type":"uint256"},{"internalType":"bool","name":"sendChainGas","type":"bool"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint256","name":"nonce","type":"uint256"}],"internalType":"struct IFastBridge.BridgeTransaction","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"}],"name":"getBridgeTransactionV2","outputs":[{"components":[{"internalType":"uint32","name":"originChainId","type":"uint32"},{"internalType":"uint32","name":"destChainId","type":"uint32"},{"internalType":"address","name":"originSender","type":"address"},{"internalType":"address","name":"destRecipient","type":"address"},{"internalType":"address","name":"originToken","type":"address"},{"internalType":"address","name":"destToken","type":"address"},{"internalType":"uint256","name":"originAmount","type":"uint256"},{"internalType":"uint256","name":"destAmount","type":"uint256"},{"internalType":"uint256","name":"originFeeAmount","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"address","name":"exclusivityRelayer","type":"address"},{"internalType":"uint256","name":"exclusivityEndTime","type":"uint256"},{"internalType":"uint256","name":"zapNative","type":"uint256"},{"internalType":"bytes","name":"zapData","type":"bytes"}],"internalType":"struct IFastBridgeV2.BridgeTransactionV2","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"internalType":"bytes32","name":"destTxHash","type":"bytes32"},{"internalType":"address","name":"relayer","type":"address"}],"name":"prove","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"},{"internalType":"bytes32","name":"destTxHash","type":"bytes32"}],"name":"prove","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"}],"name":"refund","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"}],"name":"relay","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"},{"internalType":"address","name":"relayer","type":"address"}],"name":"relay","outputs":[],"stateMutability":"payable","type":"function"}],"userDoc":{"kind":"user","methods":{"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256))":{"notice":"Initiates bridge on origin chain to be relayed by off-chain relayer"},"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256),(address,int256,bytes,uint256,bytes))":{"notice":"Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability to provide temporary exclusivity fill rights for the quote relayer."},"bridgeProofs(bytes32)":{"notice":"Returns the timestamp and relayer of a bridge proof"},"bridgeRelays(bytes32)":{"notice":"Checks if a transaction has been relayed"},"bridgeStatuses(bytes32)":{"notice":"Returns the status of a bridge transaction"},"canClaim(bytes32,address)":{"notice":"Checks if the dispute period has passed so bridge deposit can be claimed"},"claim(bytes)":{"notice":"Completes bridge transaction on origin chain by claiming originally deposited capital.Can only send funds to the relayer address on the proof."},"claim(bytes,address)":{"notice":"Completes bridge transaction on origin chain by claiming originally deposited capital"},"dispute(bytes32)":{"notice":"Disputes an outstanding proof in case relayer provided dest chain tx is invalid"},"getBridgeTransaction(bytes)":{"notice":"Decodes bridge request into a bridge transaction"},"getBridgeTransactionV2(bytes)":{"notice":"Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2"},"prove(bytes,bytes32)":{"notice":"Provides proof on origin side that relayer provided funds on destination side of bridge transaction"},"prove(bytes32,bytes32,address)":{"notice":"Provides proof on origin side that relayer provided funds on destination side of bridge transaction"},"refund(bytes)":{"notice":"Refunds an outstanding bridge transaction in case optimistic bridging failed"},"relay(bytes)":{"notice":"Relays destination side of bridge transaction by off-chain relayer"},"relay(bytes,address)":{"notice":"Relays destination side of bridge transaction by off-chain relayer"}},"version":1},"developerDoc":{"kind":"dev","methods":{"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256))":{"params":{"params":"The parameters required to bridge"}},"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256),(address,int256,bytes,uint256,bytes))":{"params":{"params":"The parameters required to bridge","paramsV2":"The parameters for exclusivity fill rights (optional, can be left empty)"}},"bridgeProofs(bytes32)":{"params":{"transactionId":"The ID of the bridge transaction"},"returns":{"relayer":"The relayer address of the bridge proof","timestamp":"The timestamp of the bridge proof"}},"bridgeRelays(bytes32)":{"params":{"transactionId":"The ID of the transaction to check"},"returns":{"_0":"True if the transaction has been relayed, false otherwise"}},"bridgeStatuses(bytes32)":{"params":{"transactionId":"The ID of the bridge transaction"},"returns":{"_0":"BridgeStatus Status of the bridge transaction"}},"canClaim(bytes32,address)":{"params":{"relayer":"The address of the relayer attempting to claim","transactionId":"The transaction id associated with the encoded bridge transaction to check"}},"claim(bytes)":{"params":{"request":"The encoded bridge transaction to claim on origin chain"}},"claim(bytes,address)":{"params":{"request":"The encoded bridge transaction to claim on origin chain","to":"The recipient address of the funds"}},"dispute(bytes32)":{"params":{"transactionId":"The transaction id associated with the encoded bridge transaction to dispute"}},"getBridgeTransaction(bytes)":{"params":{"request":"The bridge request to decode"}},"getBridgeTransactionV2(bytes)":{"params":{"request":"The bridge request to decode"}},"prove(bytes,bytes32)":{"params":{"destTxHash":"The destination tx hash proving bridge transaction was relayed","request":"The encoded bridge transaction to prove on origin chain"}},"prove(bytes32,bytes32,address)":{"params":{"destTxHash":"The destination tx hash proving bridge transaction was relayed","relayer":"The address of the relaying entity which should have control of the origin funds when claimed","transactionId":"The transaction id associated with the encoded bridge transaction to prove"}},"refund(bytes)":{"params":{"request":"The encoded bridge transaction to refund"}},"relay(bytes)":{"params":{"request":"The encoded bridge transaction to relay on destination chain"}},"relay(bytes,address)":{"params":{"relayer":"The address of the relaying entity which should have control of the origin funds when claimed","request":"The encoded bridge transaction to relay on destination chain"}}},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"BridgeDepositClaimed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"BridgeDepositRefunded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"name\":\"BridgeProofDisputed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"transactionHash\",\"type\":\"bytes32\"}],\"name\":\"BridgeProofProvided\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"quoteId\",\"type\":\"bytes\"}],\"name\":\"BridgeQuoteDetails\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"originChainId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"chainGasAmount\",\"type\":\"uint256\"}],\"name\":\"BridgeRelayed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"destChainId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"sendChainGas\",\"type\":\"bool\"}],\"name\":\"BridgeRequested\",\"type\":\"event\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"dstChainId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"sendChainGas\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"}],\"internalType\":\"struct IFastBridge.BridgeParams\",\"name\":\"params\",\"type\":\"tuple\"}],\"name\":\"bridge\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"dstChainId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"sendChainGas\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"}],\"internalType\":\"struct IFastBridge.BridgeParams\",\"name\":\"params\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"quoteRelayer\",\"type\":\"address\"},{\"internalType\":\"int256\",\"name\":\"quoteExclusivitySeconds\",\"type\":\"int256\"},{\"internalType\":\"bytes\",\"name\":\"quoteId\",\"type\":\"bytes\"},{\"internalType\":\"uint256\",\"name\":\"zapNative\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"zapData\",\"type\":\"bytes\"}],\"internalType\":\"struct IFastBridgeV2.BridgeParamsV2\",\"name\":\"paramsV2\",\"type\":\"tuple\"}],\"name\":\"bridge\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"}],\"name\":\"bridgeProofs\",\"outputs\":[{\"internalType\":\"uint96\",\"name\":\"timestamp\",\"type\":\"uint96\"},{\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"}],\"name\":\"bridgeRelays\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"}],\"name\":\"bridgeStatuses\",\"outputs\":[{\"internalType\":\"enum IFastBridgeV2.BridgeStatus\",\"name\":\"\",\"type\":\"uint8\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"name\":\"canClaim\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"claim\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"claim\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"}],\"name\":\"dispute\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"getBridgeTransaction\",\"outputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"originChainId\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"destChainId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"originSender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destRecipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"originFeeAmount\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"sendChainGas\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"}],\"internalType\":\"struct IFastBridge.BridgeTransaction\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"getBridgeTransactionV2\",\"outputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"originChainId\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"destChainId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"originSender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destRecipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"originFeeAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"exclusivityRelayer\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"exclusivityEndTime\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"zapNative\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"zapData\",\"type\":\"bytes\"}],\"internalType\":\"struct IFastBridgeV2.BridgeTransactionV2\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"destTxHash\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"name\":\"prove\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"},{\"internalType\":\"bytes32\",\"name\":\"destTxHash\",\"type\":\"bytes32\"}],\"name\":\"prove\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"refund\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"relay\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"},{\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"name\":\"relay\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{\"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256))\":{\"params\":{\"params\":\"The parameters required to bridge\"}},\"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256),(address,int256,bytes,uint256,bytes))\":{\"params\":{\"params\":\"The parameters required to bridge\",\"paramsV2\":\"The parameters for exclusivity fill rights (optional, can be left empty)\"}},\"bridgeProofs(bytes32)\":{\"params\":{\"transactionId\":\"The ID of the bridge transaction\"},\"returns\":{\"relayer\":\"The relayer address of the bridge proof\",\"timestamp\":\"The timestamp of the bridge proof\"}},\"bridgeRelays(bytes32)\":{\"params\":{\"transactionId\":\"The ID of the transaction to check\"},\"returns\":{\"_0\":\"True if the transaction has been relayed, false otherwise\"}},\"bridgeStatuses(bytes32)\":{\"params\":{\"transactionId\":\"The ID of the bridge transaction\"},\"returns\":{\"_0\":\"BridgeStatus Status of the bridge transaction\"}},\"canClaim(bytes32,address)\":{\"params\":{\"relayer\":\"The address of the relayer attempting to claim\",\"transactionId\":\"The transaction id associated with the encoded bridge transaction to check\"}},\"claim(bytes)\":{\"params\":{\"request\":\"The encoded bridge transaction to claim on origin chain\"}},\"claim(bytes,address)\":{\"params\":{\"request\":\"The encoded bridge transaction to claim on origin chain\",\"to\":\"The recipient address of the funds\"}},\"dispute(bytes32)\":{\"params\":{\"transactionId\":\"The transaction id associated with the encoded bridge transaction to dispute\"}},\"getBridgeTransaction(bytes)\":{\"params\":{\"request\":\"The bridge request to decode\"}},\"getBridgeTransactionV2(bytes)\":{\"params\":{\"request\":\"The bridge request to decode\"}},\"prove(bytes,bytes32)\":{\"params\":{\"destTxHash\":\"The destination tx hash proving bridge transaction was relayed\",\"request\":\"The encoded bridge transaction to prove on origin chain\"}},\"prove(bytes32,bytes32,address)\":{\"params\":{\"destTxHash\":\"The destination tx hash proving bridge transaction was relayed\",\"relayer\":\"The address of the relaying entity which should have control of the origin funds when claimed\",\"transactionId\":\"The transaction id associated with the encoded bridge transaction to prove\"}},\"refund(bytes)\":{\"params\":{\"request\":\"The encoded bridge transaction to refund\"}},\"relay(bytes)\":{\"params\":{\"request\":\"The encoded bridge transaction to relay on destination chain\"}},\"relay(bytes,address)\":{\"params\":{\"relayer\":\"The address of the relaying entity which should have control of the origin funds when claimed\",\"request\":\"The encoded bridge transaction to relay on destination chain\"}}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256))\":{\"notice\":\"Initiates bridge on origin chain to be relayed by off-chain relayer\"},\"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256),(address,int256,bytes,uint256,bytes))\":{\"notice\":\"Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability to provide temporary exclusivity fill rights for the quote relayer.\"},\"bridgeProofs(bytes32)\":{\"notice\":\"Returns the timestamp and relayer of a bridge proof\"},\"bridgeRelays(bytes32)\":{\"notice\":\"Checks if a transaction has been relayed\"},\"bridgeStatuses(bytes32)\":{\"notice\":\"Returns the status of a bridge transaction\"},\"canClaim(bytes32,address)\":{\"notice\":\"Checks if the dispute period has passed so bridge deposit can be claimed\"},\"claim(bytes)\":{\"notice\":\"Completes bridge transaction on origin chain by claiming originally deposited capital.Can only send funds to the relayer address on the proof.\"},\"claim(bytes,address)\":{\"notice\":\"Completes bridge transaction on origin chain by claiming originally deposited capital\"},\"dispute(bytes32)\":{\"notice\":\"Disputes an outstanding proof in case relayer provided dest chain tx is invalid\"},\"getBridgeTransaction(bytes)\":{\"notice\":\"Decodes bridge request into a bridge transaction\"},\"getBridgeTransactionV2(bytes)\":{\"notice\":\"Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\"},\"prove(bytes,bytes32)\":{\"notice\":\"Provides proof on origin side that relayer provided funds on destination side of bridge transaction\"},\"prove(bytes32,bytes32,address)\":{\"notice\":\"Provides proof on origin side that relayer provided funds on destination side of bridge transaction\"},\"refund(bytes)\":{\"notice\":\"Refunds an outstanding bridge transaction in case optimistic bridging failed\"},\"relay(bytes)\":{\"notice\":\"Relays destination side of bridge transaction by off-chain relayer\"},\"relay(bytes,address)\":{\"notice\":\"Relays destination side of bridge transaction by off-chain relayer\"}},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeV2.sol\":\"IFastBridgeV2\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeV2.sol\":{\"keccak256\":\"0x5069b55ca07f21bfe30b2a43c18a18318c8af9c181b2dcb07c290825efd70f34\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://273dc020a49d08e50126bbea0d7f783f79d08c702f2fdbc560618d24af308acc\",\"dweb:/ipfs/QmXJ2UVzFc8EPB74RT4CXQPC4xw66jt4T13poyfyd3UERh\"]}},\"version\":1}"},"hashes":{"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256))":"45851694","bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256),(address,int256,bytes,uint256,bytes))":"bfc7c607","bridgeProofs(bytes32)":"91ad5039","bridgeRelays(bytes32)":"8379a24f","bridgeStatuses(bytes32)":"051287bc","canClaim(bytes32,address)":"aa9641ab","claim(bytes)":"c63ff8dd","claim(bytes,address)":"41fcb612","dispute(bytes32)":"add98c70","getBridgeTransaction(bytes)":"ac11fb1a","getBridgeTransactionV2(bytes)":"5aa6ccba","prove(bytes,bytes32)":"886d36ff","prove(bytes32,bytes32,address)":"18e4357d","refund(bytes)":"5eb7d946","relay(bytes)":"8f0d6f17","relay(bytes,address)":"9c9545f0"}},"solidity/FastBridgeV2.sol:IFastBridgeV2Errors":{"code":"0x","runtime-code":"0x","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.24 ^0.8.20 ^0.8.4;\n\n// contracts/interfaces/IAdmin.sol\n\ninterface IAdmin {\n // ============ Events ============\n\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n event ChainGasAmountUpdated(uint256 oldChainGasAmount, uint256 newChainGasAmount);\n\n // ============ Methods ============\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n\n function setChainGasAmount(uint256 newChainGasAmount) external;\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IFastBridgeV2Errors.sol\n\ninterface IFastBridgeV2Errors {\n error AmountIncorrect();\n error ChainIncorrect();\n error ExclusivityParamsIncorrect();\n error MsgValueIncorrect();\n error SenderIncorrect();\n error StatusIncorrect();\n error TokenNotContract();\n error ZapDataLengthAboveMax();\n error ZapNativeNotSupported();\n error ZeroAddress();\n\n error RecipientIncorrectReturnValue();\n error RecipientNoReturnValue();\n\n error DeadlineExceeded();\n error DeadlineNotExceeded();\n error DeadlineTooShort();\n error DisputePeriodNotPassed();\n error DisputePeriodPassed();\n error ExclusivityPeriodNotPassed();\n\n error TransactionRelayed();\n}\n\n// contracts/interfaces/IMulticallTarget.sol\n\n/// @notice Interface for a contract that can be called multiple times by the same caller. Inspired by MulticallV3:\n/// https://github.com/mds1/multicall/blob/master/src/Multicall3.sol\ninterface IMulticallTarget {\n struct Result {\n bool success;\n bytes returnData;\n }\n\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external;\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results);\n}\n\n// contracts/interfaces/IZapRecipient.sol\n\ninterface IZapRecipient {\n function zap(address token, uint256 amount, bytes memory zapData) external payable returns (bytes4);\n}\n\n// contracts/libs/Errors.sol\n\nerror DeadlineExceeded();\nerror DeadlineNotExceeded();\nerror DeadlineTooShort();\nerror InsufficientOutputAmount();\n\nerror MsgValueIncorrect();\nerror PoolNotFound();\nerror TokenAddressMismatch();\nerror TokenNotContract();\nerror TokenNotETH();\nerror TokensIdentical();\n\nerror ChainIncorrect();\nerror AmountIncorrect();\nerror ZeroAddress();\n\nerror DisputePeriodNotPassed();\nerror DisputePeriodPassed();\nerror SenderIncorrect();\nerror StatusIncorrect();\nerror TransactionIdIncorrect();\nerror TransactionRelayed();\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// contracts/interfaces/IFastBridgeV2.sol\n\ninterface IFastBridgeV2 is IFastBridge {\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n struct BridgeTxDetails {\n BridgeStatus status;\n uint32 destChainId;\n uint56 proofBlockTimestamp;\n address proofRelayer;\n }\n\n struct BridgeRelay {\n uint48 blockNumber;\n uint48 blockTimestamp;\n address relayer;\n }\n\n /// @notice New params introduced in the FastBridgeV2.\n /// We are passing fields from the older BridgeParams struct outside of this struct\n /// for backwards compatibility.\n /// Note: quoteRelayer and quoteExclusivitySeconds are either both zero (indicating no exclusivity)\n /// or both non-zero (indicating exclusivity for the given period).\n /// Note: zapNative \u003e 0 can NOT be used with destToken = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE (native token)\n /// @param quoteRelayer Relayer that provided the quote for the transaction\n /// @param quoteExclusivitySeconds Period of time the quote relayer is guaranteed exclusivity after user's deposit\n /// @param quoteId Unique quote identifier used for tracking the quote\n /// @param zapNative ETH value to send to the recipient (if any)\n /// @param zapData Parameters for the Zap to the destination recipient (if any)\n struct BridgeParamsV2 {\n address quoteRelayer;\n int256 quoteExclusivitySeconds;\n bytes quoteId;\n uint256 zapNative;\n bytes zapData;\n }\n\n /// @notice Updated bridge transaction struct to include parameters introduced in FastBridgeV2.\n /// Note: only `exclusivityRelayer` can fill such a transaction until `exclusivityEndTime`.\n struct BridgeTransactionV2 {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n // Note: sendChainGas flag from V1 is deprecated\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n address exclusivityRelayer;\n uint256 exclusivityEndTime;\n uint256 zapNative; // ETH value to send to the recipient (if any)\n bytes zapData; // data to pass for the Zap action (if any)\n }\n\n event BridgeQuoteDetails(bytes32 indexed transactionId, bytes quoteId);\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability\n /// to provide temporary exclusivity fill rights for the quote relayer.\n /// @param params The parameters required to bridge\n /// @param paramsV2 The parameters for exclusivity fill rights (optional, can be left empty)\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function relay(bytes memory request, address relayer) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param transactionId The transaction id associated with the encoded bridge transaction to prove\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital.\n /// @notice Can only send funds to the relayer address on the proof.\n /// @param request The encoded bridge transaction to claim on origin chain\n function claim(bytes memory request) external;\n /// @notice Checks if a transaction has been relayed\n /// @param transactionId The ID of the transaction to check\n /// @return True if the transaction has been relayed, false otherwise\n function bridgeRelays(bytes32 transactionId) external view returns (bool);\n\n /// @notice Returns the status of a bridge transaction\n /// @param transactionId The ID of the bridge transaction\n /// @return BridgeStatus Status of the bridge transaction\n function bridgeStatuses(bytes32 transactionId) external view returns (BridgeStatus);\n\n /// @notice Returns the timestamp and relayer of a bridge proof\n /// @param transactionId The ID of the bridge transaction\n /// @return timestamp The timestamp of the bridge proof\n /// @return relayer The relayer address of the bridge proof\n function bridgeProofs(bytes32 transactionId) external view returns (uint96 timestamp, address relayer);\n\n /// @notice Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\n /// @param request The bridge request to decode\n function getBridgeTransactionV2(bytes memory request) external view returns (BridgeTransactionV2 memory);\n}\n\n// contracts/utils/MulticallTarget.sol\n\n// solhint-disable avoid-low-level-calls\n/// @notice Template for a contract that supports batched calls (preserving the msg.sender).\n/// Only calls with zero msg.value could be batched.\nabstract contract MulticallTarget is IMulticallTarget {\n error MulticallTarget__UndeterminedRevert();\n\n /// @notice Perform a batched call to this contract, preserving the msg.sender.\n /// The return data from each call is discarded.\n /// @dev The method is non-payable, so only calls with `msg.value == 0` could be batched.\n /// It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag.\n /// Otherwise, the whole batch call will be reverted with the original revert reason.\n /// @param data List of abi-encoded calldata for the calls to perform.\n /// @param ignoreReverts Whether to ignore the revert errors from the calls.\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external {\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\n if (!success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(result);\n }\n }\n }\n\n /// @notice Perform a batched call to this contract, preserving the msg.sender.\n /// The return data from each call is preserved.\n /// @dev The method is non-payable, so only calls with `msg.value == 0` could be batched.\n /// It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag.\n /// Otherwise, the whole batch call will be reverted with the original revert reason.\n /// @param data List of abi-encoded calldata for the calls to perform.\n /// @param ignoreReverts Whether to ignore the revert errors from the calls.\n /// @return results List of results from the calls: `(success, returnData)`.\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results)\n {\n results = new Result[](data.length);\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (results[i].success, results[i].returnData) = address(this).delegatecall(data[i]);\n if (!results[i].success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(results[i].returnData);\n }\n }\n }\n\n /// @dev Bubbles the revert message from the underlying call.\n /// Note: preserves the same custom error or revert string, if one was used.\n /// Source: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v5.0.2/contracts/utils/Address.sol#L143-L158\n function _bubbleRevert(bytes memory returnData) internal pure {\n // Look for revert reason and bubble it up if present\n if (returnData.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n // solhint-disable-next-line no-inline-assembly\n assembly {\n let returndata_size := mload(returnData)\n revert(add(32, returnData), returndata_size)\n }\n } else {\n revert MulticallTarget__UndeterminedRevert();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// contracts/libs/BridgeTransactionV2.sol\n\n// solhint-disable no-inline-assembly\nlibrary BridgeTransactionV2Lib {\n uint16 internal constant VERSION = 2;\n\n // Offsets of the fields in the packed BridgeTransactionV2 struct\n // uint16 version [000 .. 002)\n // uint32 originChainId [002 .. 006)\n // uint32 destChainId [006 .. 010)\n // address originSender [010 .. 030)\n // address destRecipient [030 .. 050)\n // address originToken [050 .. 070)\n // address destToken [070 .. 090)\n // uint256 originAmount [090 .. 122)\n // uint256 destAmount [122 .. 154)\n // uint256 originFeeAmount [154 .. 186)\n // uint256 deadline [186 .. 218)\n // uint256 nonce [218 .. 250)\n // address exclusivityRelayer [250 .. 270)\n // uint256 exclusivityEndTime [270 .. 302)\n // uint256 zapNative [302 .. 334)\n // bytes zapData [334 .. ***)\n\n // forgefmt: disable-start\n uint256 private constant OFFSET_ORIGIN_CHAIN_ID = 2;\n uint256 private constant OFFSET_DEST_CHAIN_ID = 6;\n uint256 private constant OFFSET_ORIGIN_SENDER = 10;\n uint256 private constant OFFSET_DEST_RECIPIENT = 30;\n uint256 private constant OFFSET_ORIGIN_TOKEN = 50;\n uint256 private constant OFFSET_DEST_TOKEN = 70;\n uint256 private constant OFFSET_ORIGIN_AMOUNT = 90;\n uint256 private constant OFFSET_DEST_AMOUNT = 122;\n uint256 private constant OFFSET_ORIGIN_FEE_AMOUNT = 154;\n uint256 private constant OFFSET_DEADLINE = 186;\n uint256 private constant OFFSET_NONCE = 218;\n uint256 private constant OFFSET_EXCLUSIVITY_RELAYER = 250;\n uint256 private constant OFFSET_EXCLUSIVITY_END_TIME = 270;\n uint256 private constant OFFSET_ZAP_NATIVE = 302;\n uint256 private constant OFFSET_ZAP_DATA = 334;\n // forgefmt: disable-end\n\n error BridgeTransactionV2__InvalidEncodedTx();\n error BridgeTransactionV2__UnsupportedVersion(uint16 version);\n\n /// @notice Validates the encoded transaction to be a tightly packed encoded payload for BridgeTransactionV2.\n /// @dev Checks the minimum length and the version, use this function before decoding any of the fields.\n function validateV2(bytes calldata encodedTx) internal pure {\n // Check the minimum length: must at least include all static fields.\n if (encodedTx.length \u003c OFFSET_ZAP_DATA) revert BridgeTransactionV2__InvalidEncodedTx();\n // Once we validated the length, we can be sure that the version field is present.\n uint16 version_ = version(encodedTx);\n if (version_ != VERSION) revert BridgeTransactionV2__UnsupportedVersion(version_);\n }\n\n /// @notice Encodes the BridgeTransactionV2 struct by tightly packing the fields.\n /// @dev `abi.decode` will not work as a result of the tightly packed fields. Use `decodeV2` to decode instead.\n function encodeV2(IFastBridgeV2.BridgeTransactionV2 memory bridgeTx) internal pure returns (bytes memory) {\n // We split the encoding into two parts to avoid stack-too-deep error\n bytes memory firstPart = abi.encodePacked(\n VERSION,\n bridgeTx.originChainId,\n bridgeTx.destChainId,\n bridgeTx.originSender,\n bridgeTx.destRecipient,\n bridgeTx.originToken,\n bridgeTx.destToken,\n bridgeTx.originAmount\n );\n return abi.encodePacked(\n firstPart,\n bridgeTx.destAmount,\n bridgeTx.originFeeAmount,\n // Note: we skip the deprecated `sendChainGas` flag, which was present in BridgeTransaction V1\n bridgeTx.deadline,\n bridgeTx.nonce,\n // New V2 fields: exclusivity\n bridgeTx.exclusivityRelayer,\n bridgeTx.exclusivityEndTime,\n // New V2 fields: Zap\n bridgeTx.zapNative,\n bridgeTx.zapData\n );\n }\n\n /// @notice Decodes the BridgeTransactionV2 struct from the encoded transaction.\n /// @dev Encoded BridgeTransactionV2 struct must be tightly packed.\n /// Use `validateV2` before decoding to ensure the encoded transaction is valid.\n function decodeV2(bytes calldata encodedTx)\n internal\n pure\n returns (IFastBridgeV2.BridgeTransactionV2 memory bridgeTx)\n {\n bridgeTx.originChainId = originChainId(encodedTx);\n bridgeTx.destChainId = destChainId(encodedTx);\n bridgeTx.originSender = originSender(encodedTx);\n bridgeTx.destRecipient = destRecipient(encodedTx);\n bridgeTx.originToken = originToken(encodedTx);\n bridgeTx.destToken = destToken(encodedTx);\n bridgeTx.originAmount = originAmount(encodedTx);\n bridgeTx.destAmount = destAmount(encodedTx);\n bridgeTx.originFeeAmount = originFeeAmount(encodedTx);\n bridgeTx.deadline = deadline(encodedTx);\n bridgeTx.nonce = nonce(encodedTx);\n bridgeTx.exclusivityRelayer = exclusivityRelayer(encodedTx);\n bridgeTx.exclusivityEndTime = exclusivityEndTime(encodedTx);\n bridgeTx.zapNative = zapNative(encodedTx);\n bridgeTx.zapData = zapData(encodedTx);\n }\n\n /// @notice Extracts the version from the encoded transaction.\n function version(bytes calldata encodedTx) internal pure returns (uint16 version_) {\n // Load 32 bytes from the start and shift it 240 bits to the right to get the highest 16 bits.\n assembly {\n version_ := shr(240, calldataload(encodedTx.offset))\n }\n }\n\n /// @notice Extracts the origin chain ID from the encoded transaction.\n function originChainId(bytes calldata encodedTx) internal pure returns (uint32 originChainId_) {\n // Load 32 bytes from the offset and shift it 224 bits to the right to get the highest 32 bits.\n assembly {\n originChainId_ := shr(224, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_CHAIN_ID)))\n }\n }\n\n /// @notice Extracts the destination chain ID from the encoded transaction.\n function destChainId(bytes calldata encodedTx) internal pure returns (uint32 destChainId_) {\n // Load 32 bytes from the offset and shift it 224 bits to the right to get the highest 32 bits.\n assembly {\n destChainId_ := shr(224, calldataload(add(encodedTx.offset, OFFSET_DEST_CHAIN_ID)))\n }\n }\n\n /// @notice Extracts the origin sender from the encoded transaction.\n function originSender(bytes calldata encodedTx) internal pure returns (address originSender_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n originSender_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_SENDER)))\n }\n }\n\n /// @notice Extracts the destination recipient from the encoded transaction.\n function destRecipient(bytes calldata encodedTx) internal pure returns (address destRecipient_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n destRecipient_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_DEST_RECIPIENT)))\n }\n }\n\n /// @notice Extracts the origin token from the encoded transaction.\n function originToken(bytes calldata encodedTx) internal pure returns (address originToken_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n originToken_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_TOKEN)))\n }\n }\n\n /// @notice Extracts the destination token from the encoded transaction.\n function destToken(bytes calldata encodedTx) internal pure returns (address destToken_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n destToken_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_DEST_TOKEN)))\n }\n }\n\n /// @notice Extracts the origin amount from the encoded transaction.\n function originAmount(bytes calldata encodedTx) internal pure returns (uint256 originAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n originAmount_ := calldataload(add(encodedTx.offset, OFFSET_ORIGIN_AMOUNT))\n }\n }\n\n /// @notice Extracts the destination amount from the encoded transaction.\n function destAmount(bytes calldata encodedTx) internal pure returns (uint256 destAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n destAmount_ := calldataload(add(encodedTx.offset, OFFSET_DEST_AMOUNT))\n }\n }\n\n /// @notice Extracts the origin fee amount from the encoded transaction.\n function originFeeAmount(bytes calldata encodedTx) internal pure returns (uint256 originFeeAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n originFeeAmount_ := calldataload(add(encodedTx.offset, OFFSET_ORIGIN_FEE_AMOUNT))\n }\n }\n\n /// @notice Extracts the deadline from the encoded transaction.\n function deadline(bytes calldata encodedTx) internal pure returns (uint256 deadline_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n deadline_ := calldataload(add(encodedTx.offset, OFFSET_DEADLINE))\n }\n }\n\n /// @notice Extracts the nonce from the encoded transaction.\n function nonce(bytes calldata encodedTx) internal pure returns (uint256 nonce_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n nonce_ := calldataload(add(encodedTx.offset, OFFSET_NONCE))\n }\n }\n\n /// @notice Extracts the exclusivity relayer from the encoded transaction.\n function exclusivityRelayer(bytes calldata encodedTx) internal pure returns (address exclusivityRelayer_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n exclusivityRelayer_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_EXCLUSIVITY_RELAYER)))\n }\n }\n\n /// @notice Extracts the exclusivity end time from the encoded transaction.\n function exclusivityEndTime(bytes calldata encodedTx) internal pure returns (uint256 exclusivityEndTime_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n exclusivityEndTime_ := calldataload(add(encodedTx.offset, OFFSET_EXCLUSIVITY_END_TIME))\n }\n }\n\n /// @notice Extracts the Zap's native value from the encoded transaction.\n function zapNative(bytes calldata encodedTx) internal pure returns (uint256 zapNative_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n zapNative_ := calldataload(add(encodedTx.offset, OFFSET_ZAP_NATIVE))\n }\n }\n\n /// @notice Extracts the Zap's data from the encoded transaction.\n function zapData(bytes calldata encodedTx) internal pure returns (bytes calldata zapData_) {\n zapData_ = encodedTx[OFFSET_ZAP_DATA:];\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// contracts/libs/UniversalToken.sol\n\nlibrary UniversalTokenLib {\n using SafeERC20 for IERC20;\n\n address internal constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Transfers tokens to the given account. Reverts if transfer is not successful.\n /// @dev This might trigger fallback, if ETH is transferred to the contract.\n /// Make sure this can not lead to reentrancy attacks.\n function universalTransfer(address token, address to, uint256 value) internal {\n // Don't do anything, if need to send tokens to this address\n if (to == address(this)) return;\n // Don't do anything, if trying to send zero value\n if (value == 0) return;\n if (token == ETH_ADDRESS) {\n /// @dev Note: this can potentially lead to executing code in `to`.\n // solhint-disable-next-line avoid-low-level-calls\n (bool success,) = to.call{value: value}(\"\");\n require(success, \"ETH transfer failed\");\n } else {\n IERC20(token).safeTransfer(to, value);\n }\n }\n\n /// @notice Issues an infinite allowance to the spender, if the current allowance is insufficient\n /// to spend the given amount.\n function universalApproveInfinity(address token, address spender, uint256 amountToSpend) internal {\n // ETH Chad doesn't require your approval\n if (token == ETH_ADDRESS) return;\n // No-op if allowance is already sufficient\n uint256 allowance = IERC20(token).allowance(address(this), spender);\n if (allowance \u003e= amountToSpend) return;\n // Otherwise, reset approval to 0 and set to max allowance\n if (allowance \u003e 0) IERC20(token).safeDecreaseAllowance(spender, allowance);\n IERC20(token).safeIncreaseAllowance(spender, type(uint256).max);\n }\n\n /// @notice Returns the balance of the given token (or native ETH) for the given account.\n function universalBalanceOf(address token, address account) internal view returns (uint256) {\n if (token == ETH_ADDRESS) {\n return account.balance;\n } else {\n return IERC20(token).balanceOf(account);\n }\n }\n\n /// @dev Checks that token is a contract and not ETH_ADDRESS.\n function assertIsContract(address token) internal view {\n // Check that ETH_ADDRESS was not used (in case this is a predeploy on any of the chains)\n if (token == UniversalTokenLib.ETH_ADDRESS) revert TokenNotContract();\n // Check that token is not an EOA\n if (token.code.length == 0) revert TokenNotContract();\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/Admin.sol\n\ncontract Admin is IAdmin, AccessControlEnumerable {\n using UniversalTokenLib for address;\n\n bytes32 public constant RELAYER_ROLE = keccak256(\"RELAYER_ROLE\");\n bytes32 public constant REFUNDER_ROLE = keccak256(\"REFUNDER_ROLE\");\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n uint256 public constant FEE_BPS = 1e6;\n uint256 public constant FEE_RATE_MAX = 0.01e6; // max 1% on origin amount\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Chain gas amount to forward as rebate if requested\n uint256 public chainGasAmount;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n }\n\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n require(newFeeRate \u003c= FEE_RATE_MAX, \"newFeeRate \u003e max\");\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n token.universalTransfer(recipient, feeAmount);\n emit FeesSwept(token, recipient, feeAmount);\n }\n\n function setChainGasAmount(uint256 newChainGasAmount) external onlyRole(GOVERNOR_ROLE) {\n uint256 oldChainGasAmount = chainGasAmount;\n chainGasAmount = newChainGasAmount;\n emit ChainGasAmountUpdated(oldChainGasAmount, newChainGasAmount);\n }\n}\n\n// contracts/FastBridgeV2.sol\n\n/// @notice FastBridgeV2 is a contract for bridging tokens across chains.\ncontract FastBridgeV2 is Admin, MulticallTarget, IFastBridgeV2, IFastBridgeV2Errors {\n using BridgeTransactionV2Lib for bytes;\n using SafeERC20 for IERC20;\n\n /// @notice Address reserved for native gas token (ETH on Ethereum and most L2s, AVAX on Avalanche, etc)\n address public constant NATIVE_GAS_TOKEN = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Delay for a transaction after which it could be permisionlessly refunded\n uint256 public constant REFUND_DELAY = 7 days;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n /// @notice Maximum length of accepted zapData\n uint256 public constant MAX_ZAP_DATA_LENGTH = 2 ** 16 - 1;\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeTxDetails) public bridgeTxDetails;\n /// @notice Relay details on destination chain\n mapping(bytes32 =\u003e BridgeRelay) public bridgeRelayDetails;\n /// @notice Unique bridge nonces tracked per originSender\n mapping(address =\u003e uint256) public senderNonces;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Replaced by senderNonces\n uint256 public immutable nonce = 0;\n /// @notice the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n bridge({\n params: params,\n paramsV2: BridgeParamsV2({\n quoteRelayer: address(0),\n quoteExclusivitySeconds: 0,\n quoteId: bytes(\"\"),\n zapNative: 0,\n zapData: bytes(\"\")\n })\n });\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes calldata request) external payable {\n // relay override will validate the request\n relay({request: request, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes calldata request, bytes32 destTxHash) external {\n request.validateV2();\n prove({transactionId: keccak256(request), destTxHash: destTxHash, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridgeV2\n function claim(bytes calldata request) external {\n // claim override will validate the request\n claim({request: request, to: address(0)});\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Aggregate the read operations from the same storage slot\n address disputedRelayer = $.proofRelayer;\n BridgeStatus status = $.status;\n uint56 proofBlockTimestamp = $.proofBlockTimestamp;\n // Can only dispute a RELAYER_PROVED transaction within the dispute period\n if (status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(proofBlockTimestamp) \u003e DISPUTE_PERIOD) {\n revert DisputePeriodPassed();\n }\n // Update status to REQUESTED and delete the disputed proof details\n // Note: these are storage writes\n $.status = BridgeStatus.REQUESTED;\n $.proofRelayer = address(0);\n $.proofBlockTimestamp = 0;\n\n emit BridgeProofDisputed(transactionId, disputedRelayer);\n }\n\n /// @inheritdoc IFastBridge\n function refund(bytes calldata request) external {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Can only refund a REQUESTED transaction after its deadline expires\n if ($.status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n uint256 deadline = request.deadline();\n // Permissionless refund is only allowed after REFUND_DELAY on top of the deadline\n if (!hasRole(REFUNDER_ROLE, msg.sender)) deadline += REFUND_DELAY;\n if (block.timestamp \u003c= deadline) revert DeadlineNotExceeded();\n // Update status to REFUNDED and return the full amount (collateral + protocol fees) to the original sender.\n // The protocol fees are only updated when the transaction is claimed, so we don't need to update them here.\n // Note: this is a storage write\n $.status = BridgeStatus.REFUNDED;\n\n address to = request.originSender();\n address token = request.originToken();\n uint256 amount = request.originAmount() + request.originFeeAmount();\n // Emit the event before any external calls\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n // Complete the user refund as the last transaction action\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(to), amount);\n } else {\n IERC20(token).safeTransfer(to, amount);\n }\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // The correct relayer can only claim a RELAYER_PROVED transaction after the dispute period\n if ($.status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if ($.proofRelayer != relayer) revert SenderIncorrect();\n return _timeSince($.proofBlockTimestamp) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n /// @dev This method is added to achieve backwards compatibility with decoding requests into V1 structs:\n /// - `zapNative` is partially reported as a zero/non-zero flag\n /// - `zapData` is ignored\n /// In order to process all kinds of requests use getBridgeTransactionV2 instead.\n function getBridgeTransaction(bytes calldata request) external view returns (BridgeTransaction memory) {\n // Try decoding into V2 struct first. This will revert if V1 struct is passed\n try this.getBridgeTransactionV2(request) returns (BridgeTransactionV2 memory txV2) {\n // Note: we entirely ignore the zapData field, as it was not present in V1\n return BridgeTransaction({\n originChainId: txV2.originChainId,\n destChainId: txV2.destChainId,\n originSender: txV2.originSender,\n destRecipient: txV2.destRecipient,\n originToken: txV2.originToken,\n destToken: txV2.destToken,\n originAmount: txV2.originAmount,\n destAmount: txV2.destAmount,\n originFeeAmount: txV2.originFeeAmount,\n sendChainGas: txV2.zapNative != 0,\n deadline: txV2.deadline,\n nonce: txV2.nonce\n });\n } catch {\n // Fallback to V1 struct\n return abi.decode(request, (BridgeTransaction));\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function getBridgeTransactionV2(bytes calldata request) external pure returns (BridgeTransactionV2 memory) {\n request.validateV2();\n return BridgeTransactionV2Lib.decodeV2(request);\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) public payable {\n int256 exclusivityEndTime = 0;\n // if relayer exclusivity is not intended for this bridge, set exclusivityEndTime to static zero\n // otherwise, set exclusivity to expire at the current block ts offset by quoteExclusivitySeconds\n if (paramsV2.quoteRelayer != address(0)) {\n exclusivityEndTime = int256(block.timestamp) + paramsV2.quoteExclusivitySeconds;\n }\n _validateBridgeParams(params, paramsV2, exclusivityEndTime);\n\n // transfer tokens to bridge contract\n /// @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _takeBridgedUserAsset(params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) {\n originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n }\n\n // set status to requested\n bytes memory request = BridgeTransactionV2Lib.encodeV2(\n BridgeTransactionV2({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n deadline: params.deadline,\n nonce: senderNonces[params.sender]++, // increment nonce on every bridge\n exclusivityRelayer: paramsV2.quoteRelayer,\n // We checked exclusivityEndTime to be in range [0 .. params.deadline] above, so can safely cast\n exclusivityEndTime: uint256(exclusivityEndTime),\n zapNative: paramsV2.zapNative,\n zapData: paramsV2.zapData\n })\n );\n bytes32 transactionId = keccak256(request);\n // Note: the tx status will be updated throughout the tx lifecycle, while destChainId is set once here\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n bridgeTxDetails[transactionId].destChainId = params.dstChainId;\n\n emit BridgeRequested({\n transactionId: transactionId,\n sender: params.sender,\n request: request,\n destChainId: params.dstChainId,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n sendChainGas: paramsV2.zapNative != 0\n });\n emit BridgeQuoteDetails(transactionId, paramsV2.quoteId);\n }\n\n /// @inheritdoc IFastBridgeV2\n function relay(bytes calldata request, address relayer) public payable {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n _validateRelayParams(request, transactionId, relayer);\n // mark bridge transaction as relayed\n bridgeRelayDetails[transactionId] =\n BridgeRelay({blockNumber: uint48(block.number), blockTimestamp: uint48(block.timestamp), relayer: relayer});\n\n // transfer tokens to recipient on destination chain and trigger Zap if requested\n address to = request.destRecipient();\n address token = request.destToken();\n uint256 amount = request.destAmount();\n uint256 zapNative = request.zapNative();\n\n // Emit the event before any external calls\n emit BridgeRelayed({\n transactionId: transactionId,\n relayer: relayer,\n to: to,\n originChainId: request.originChainId(),\n originToken: request.originToken(),\n destToken: token,\n originAmount: request.originAmount(),\n destAmount: amount,\n chainGasAmount: zapNative\n });\n\n // All state changes have been done at this point, can proceed to the external calls.\n // This follows the checks-effects-interactions pattern to mitigate potential reentrancy attacks.\n if (token == NATIVE_GAS_TOKEN) {\n // For the native gas token, additional zapNative is not allowed\n if (zapNative != 0) revert ZapNativeNotSupported();\n // Check that the correct msg.value was sent\n if (msg.value != amount) revert MsgValueIncorrect();\n // Don't do a native transfer yet: we will handle it alongside the Zap below\n } else {\n // For ERC20s, we check that the correct msg.value was sent\n if (msg.value != zapNative) revert MsgValueIncorrect();\n // We need to transfer the tokens from the Relayer to the recipient first before performing an\n // optional post-transfer Zap.\n IERC20(token).safeTransferFrom(msg.sender, to, amount);\n }\n // At this point we have done:\n // - Transferred the requested amount of ERC20 tokens to the recipient.\n // At this point we have confirmed:\n // - For ERC20s: msg.value matches the requested zapNative amount.\n // - For the native gas token: msg.value matches the requested destAmount.\n // Remaining optional things to do:\n // - Forward the full msg.value to the recipient (if non-zero).\n // - Trigger a Zap (if zapData is present).\n bytes calldata zapData = request.zapData();\n if (zapData.length != 0) {\n // Zap Data is present: Zap has been requested by the recipient. Trigger it forwarding the full msg.value.\n\n // Note: if token has a fee on transfers, the recipient will have received less than `amount`.\n // This is a very niche edge case and should be handled by the recipient contract.\n _triggerZapWithChecks({recipient: to, token: token, amount: amount, zapData: zapData});\n } else if (msg.value != 0) {\n // Zap Data is missing, but msg.value was sent. This could happen in two different cases:\n // - Relay with the native gas token is happening.\n // - Relay with ERC20 is happening, with a `zapNative \u003e 0` request.\n // In both cases, we need to transfer the full msg.value to the recipient.\n Address.sendValue(payable(to), msg.value);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) public onlyRole(RELAYER_ROLE) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n\n // Can only prove a REQUESTED transaction\n if ($.status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n // Update status to RELAYER_PROVED and store the proof details\n // Note: these are storage writes\n $.status = BridgeStatus.RELAYER_PROVED;\n $.proofBlockTimestamp = uint56(block.timestamp);\n $.proofRelayer = relayer;\n\n emit BridgeProofProvided(transactionId, relayer, destTxHash);\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes calldata request, address to) public {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Aggregate the read operations from the same storage slot\n address proofRelayer = $.proofRelayer;\n BridgeStatus status = $.status;\n uint56 proofBlockTimestamp = $.proofBlockTimestamp;\n\n // Can only claim a RELAYER_PROVED transaction after the dispute period\n if (status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(proofBlockTimestamp) \u003c= DISPUTE_PERIOD) {\n revert DisputePeriodNotPassed();\n }\n\n if (to == address(0)) {\n // Anyone could claim the funds to the proven relayer on their behalf\n to = proofRelayer;\n } else if (proofRelayer != msg.sender) {\n // Only the proven relayer could specify an address to claim the funds to\n revert SenderIncorrect();\n }\n\n // Update status to RELAYER_CLAIMED and transfer the origin collateral to the specified claim address\n // Note: this is a storage write\n $.status = BridgeStatus.RELAYER_CLAIMED;\n\n address token = request.originToken();\n uint256 amount = request.originAmount();\n // Update protocol fees if origin fee amount exists\n uint256 originFeeAmount = request.originFeeAmount();\n if (originFeeAmount \u003e 0) protocolFees[token] += originFeeAmount;\n // Emit the event before any external calls\n emit BridgeDepositClaimed(transactionId, proofRelayer, to, token, amount);\n // Complete the relayer claim as the last transaction action\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(to), amount);\n } else {\n IERC20(token).safeTransfer(to, amount);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeStatuses(bytes32 transactionId) public view returns (BridgeStatus status) {\n return bridgeTxDetails[transactionId].status;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeProofs(bytes32 transactionId) public view returns (uint96 timestamp, address relayer) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n\n timestamp = $.proofBlockTimestamp;\n relayer = $.proofRelayer;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeRelays(bytes32 transactionId) public view returns (bool) {\n // has this transactionId been relayed?\n return bridgeRelayDetails[transactionId].relayer != address(0);\n }\n\n /// @notice Takes the bridged asset from the user into FastBridgeV2 custody. It will be later\n /// claimed by the relayer who completed the relay on destination chain, or refunded back to the user,\n /// should no one complete the relay.\n function _takeBridgedUserAsset(address token, uint256 amount) internal returns (uint256 amountTaken) {\n if (token == NATIVE_GAS_TOKEN) {\n // For the native gas token, we just need to check that the supplied msg.value is correct.\n // Supplied `msg.value` is already in FastBridgeV2 custody.\n if (amount != msg.value) revert MsgValueIncorrect();\n amountTaken = msg.value;\n } else {\n // For ERC20s, token is explicitly transferred from the user to FastBridgeV2.\n // We don't allow non-zero `msg.value` to avoid extra funds from being stuck in FastBridgeV2.\n if (msg.value != 0) revert MsgValueIncorrect();\n // Throw an explicit error if the provided token address is not a contract\n if (token.code.length == 0) revert TokenNotContract();\n amountTaken = IERC20(token).balanceOf(address(this));\n IERC20(token).safeTransferFrom(msg.sender, address(this), amount);\n // Use the balance difference as the amount taken in case of fee on transfer tokens.\n amountTaken = IERC20(token).balanceOf(address(this)) - amountTaken;\n }\n }\n\n /// @notice Calls the Recipient's hook function with the specified zapData and performs\n /// all the necessary checks for the returned value.\n function _triggerZapWithChecks(address recipient, address token, uint256 amount, bytes calldata zapData) internal {\n // This will bubble any revert messages from the hook function\n bytes memory returnData = Address.functionCallWithValue({\n target: recipient,\n data: abi.encodeCall(IZapRecipient.zap, (token, amount, zapData)),\n // Note: see `relay()` for reasoning behind passing msg.value\n value: msg.value\n });\n // Explicit revert if no return data at all\n if (returnData.length == 0) revert RecipientNoReturnValue();\n // Check that exactly a single return value was returned\n if (returnData.length != 32) revert RecipientIncorrectReturnValue();\n // Return value should be abi-encoded hook function selector\n if (bytes32(returnData) != bytes32(IZapRecipient.zap.selector)) {\n revert RecipientIncorrectReturnValue();\n }\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint56(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint56).max but\n /// proof.timestamp \u003c type(uint56).max via unchecked statement\n /// @param proofBlockTimestamp The bridge proof block timestamp\n /// @return delta Time delta since proof submitted\n function _timeSince(uint56 proofBlockTimestamp) internal view returns (uint256 delta) {\n unchecked {\n delta = uint56(block.timestamp) - proofBlockTimestamp;\n }\n }\n\n /// @notice Performs all the necessary checks for a bridge to happen.\n /// @dev There's no good way to refactor this function to reduce cyclomatic complexity due to\n /// the number of checks that need to be performed, so we skip the code-complexity rule here.\n // solhint-disable-next-line code-complexity\n function _validateBridgeParams(\n BridgeParams memory params,\n BridgeParamsV2 memory paramsV2,\n int256 exclusivityEndTime\n )\n internal\n view\n {\n // Check V1 (legacy) params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.sender == address(0) || params.to == address(0)) revert ZeroAddress();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n // Check V2 params\n if (paramsV2.zapData.length \u003e MAX_ZAP_DATA_LENGTH) revert ZapDataLengthAboveMax();\n if (paramsV2.zapNative != 0 \u0026\u0026 params.destToken == NATIVE_GAS_TOKEN) {\n revert ZapNativeNotSupported();\n }\n // exclusivityEndTime must be in range [0 .. params.deadline]\n if (exclusivityEndTime \u003c 0 || exclusivityEndTime \u003e int256(params.deadline)) {\n revert ExclusivityParamsIncorrect();\n }\n }\n\n /// @notice Performs all the necessary checks for a relay to happen.\n function _validateRelayParams(bytes calldata request, bytes32 transactionId, address relayer) internal view {\n if (relayer == address(0)) revert ZeroAddress();\n // Check if the transaction has already been relayed\n if (bridgeRelays(transactionId)) revert TransactionRelayed();\n if (request.destChainId() != block.chainid) revert ChainIncorrect();\n // Check the deadline for relay to happen\n if (block.timestamp \u003e request.deadline()) revert DeadlineExceeded();\n // Check the exclusivity period, if it is still ongoing\n address exclRelayer = request.exclusivityRelayer();\n if (exclRelayer != address(0) \u0026\u0026 exclRelayer != relayer \u0026\u0026 block.timestamp \u003c= request.exclusivityEndTime()) {\n revert ExclusivityPeriodNotPassed();\n }\n }\n}\n","language":"Solidity","languageVersion":"0.8.24","compilerVersion":"0.8.24","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"","srcMapRuntime":"","abiDefinition":[{"inputs":[],"name":"AmountIncorrect","type":"error"},{"inputs":[],"name":"ChainIncorrect","type":"error"},{"inputs":[],"name":"DeadlineExceeded","type":"error"},{"inputs":[],"name":"DeadlineNotExceeded","type":"error"},{"inputs":[],"name":"DeadlineTooShort","type":"error"},{"inputs":[],"name":"DisputePeriodNotPassed","type":"error"},{"inputs":[],"name":"DisputePeriodPassed","type":"error"},{"inputs":[],"name":"ExclusivityParamsIncorrect","type":"error"},{"inputs":[],"name":"ExclusivityPeriodNotPassed","type":"error"},{"inputs":[],"name":"MsgValueIncorrect","type":"error"},{"inputs":[],"name":"RecipientIncorrectReturnValue","type":"error"},{"inputs":[],"name":"RecipientNoReturnValue","type":"error"},{"inputs":[],"name":"SenderIncorrect","type":"error"},{"inputs":[],"name":"StatusIncorrect","type":"error"},{"inputs":[],"name":"TokenNotContract","type":"error"},{"inputs":[],"name":"TransactionRelayed","type":"error"},{"inputs":[],"name":"ZapDataLengthAboveMax","type":"error"},{"inputs":[],"name":"ZapNativeNotSupported","type":"error"},{"inputs":[],"name":"ZeroAddress","type":"error"}],"userDoc":{"kind":"user","methods":{},"version":1},"developerDoc":{"kind":"dev","methods":{},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[],\"name\":\"AmountIncorrect\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ChainIncorrect\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DeadlineExceeded\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DeadlineNotExceeded\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DeadlineTooShort\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DisputePeriodNotPassed\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DisputePeriodPassed\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ExclusivityParamsIncorrect\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ExclusivityPeriodNotPassed\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"MsgValueIncorrect\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"RecipientIncorrectReturnValue\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"RecipientNoReturnValue\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"SenderIncorrect\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"StatusIncorrect\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"TokenNotContract\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"TransactionRelayed\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ZapDataLengthAboveMax\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ZapNativeNotSupported\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ZeroAddress\",\"type\":\"error\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeV2.sol\":\"IFastBridgeV2Errors\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeV2.sol\":{\"keccak256\":\"0x5069b55ca07f21bfe30b2a43c18a18318c8af9c181b2dcb07c290825efd70f34\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://273dc020a49d08e50126bbea0d7f783f79d08c702f2fdbc560618d24af308acc\",\"dweb:/ipfs/QmXJ2UVzFc8EPB74RT4CXQPC4xw66jt4T13poyfyd3UERh\"]}},\"version\":1}"},"hashes":{}},"solidity/FastBridgeV2.sol:IMulticallTarget":{"code":"0x","runtime-code":"0x","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.24 ^0.8.20 ^0.8.4;\n\n// contracts/interfaces/IAdmin.sol\n\ninterface IAdmin {\n // ============ Events ============\n\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n event ChainGasAmountUpdated(uint256 oldChainGasAmount, uint256 newChainGasAmount);\n\n // ============ Methods ============\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n\n function setChainGasAmount(uint256 newChainGasAmount) external;\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IFastBridgeV2Errors.sol\n\ninterface IFastBridgeV2Errors {\n error AmountIncorrect();\n error ChainIncorrect();\n error ExclusivityParamsIncorrect();\n error MsgValueIncorrect();\n error SenderIncorrect();\n error StatusIncorrect();\n error TokenNotContract();\n error ZapDataLengthAboveMax();\n error ZapNativeNotSupported();\n error ZeroAddress();\n\n error RecipientIncorrectReturnValue();\n error RecipientNoReturnValue();\n\n error DeadlineExceeded();\n error DeadlineNotExceeded();\n error DeadlineTooShort();\n error DisputePeriodNotPassed();\n error DisputePeriodPassed();\n error ExclusivityPeriodNotPassed();\n\n error TransactionRelayed();\n}\n\n// contracts/interfaces/IMulticallTarget.sol\n\n/// @notice Interface for a contract that can be called multiple times by the same caller. Inspired by MulticallV3:\n/// https://github.com/mds1/multicall/blob/master/src/Multicall3.sol\ninterface IMulticallTarget {\n struct Result {\n bool success;\n bytes returnData;\n }\n\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external;\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results);\n}\n\n// contracts/interfaces/IZapRecipient.sol\n\ninterface IZapRecipient {\n function zap(address token, uint256 amount, bytes memory zapData) external payable returns (bytes4);\n}\n\n// contracts/libs/Errors.sol\n\nerror DeadlineExceeded();\nerror DeadlineNotExceeded();\nerror DeadlineTooShort();\nerror InsufficientOutputAmount();\n\nerror MsgValueIncorrect();\nerror PoolNotFound();\nerror TokenAddressMismatch();\nerror TokenNotContract();\nerror TokenNotETH();\nerror TokensIdentical();\n\nerror ChainIncorrect();\nerror AmountIncorrect();\nerror ZeroAddress();\n\nerror DisputePeriodNotPassed();\nerror DisputePeriodPassed();\nerror SenderIncorrect();\nerror StatusIncorrect();\nerror TransactionIdIncorrect();\nerror TransactionRelayed();\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// contracts/interfaces/IFastBridgeV2.sol\n\ninterface IFastBridgeV2 is IFastBridge {\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n struct BridgeTxDetails {\n BridgeStatus status;\n uint32 destChainId;\n uint56 proofBlockTimestamp;\n address proofRelayer;\n }\n\n struct BridgeRelay {\n uint48 blockNumber;\n uint48 blockTimestamp;\n address relayer;\n }\n\n /// @notice New params introduced in the FastBridgeV2.\n /// We are passing fields from the older BridgeParams struct outside of this struct\n /// for backwards compatibility.\n /// Note: quoteRelayer and quoteExclusivitySeconds are either both zero (indicating no exclusivity)\n /// or both non-zero (indicating exclusivity for the given period).\n /// Note: zapNative \u003e 0 can NOT be used with destToken = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE (native token)\n /// @param quoteRelayer Relayer that provided the quote for the transaction\n /// @param quoteExclusivitySeconds Period of time the quote relayer is guaranteed exclusivity after user's deposit\n /// @param quoteId Unique quote identifier used for tracking the quote\n /// @param zapNative ETH value to send to the recipient (if any)\n /// @param zapData Parameters for the Zap to the destination recipient (if any)\n struct BridgeParamsV2 {\n address quoteRelayer;\n int256 quoteExclusivitySeconds;\n bytes quoteId;\n uint256 zapNative;\n bytes zapData;\n }\n\n /// @notice Updated bridge transaction struct to include parameters introduced in FastBridgeV2.\n /// Note: only `exclusivityRelayer` can fill such a transaction until `exclusivityEndTime`.\n struct BridgeTransactionV2 {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n // Note: sendChainGas flag from V1 is deprecated\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n address exclusivityRelayer;\n uint256 exclusivityEndTime;\n uint256 zapNative; // ETH value to send to the recipient (if any)\n bytes zapData; // data to pass for the Zap action (if any)\n }\n\n event BridgeQuoteDetails(bytes32 indexed transactionId, bytes quoteId);\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability\n /// to provide temporary exclusivity fill rights for the quote relayer.\n /// @param params The parameters required to bridge\n /// @param paramsV2 The parameters for exclusivity fill rights (optional, can be left empty)\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function relay(bytes memory request, address relayer) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param transactionId The transaction id associated with the encoded bridge transaction to prove\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital.\n /// @notice Can only send funds to the relayer address on the proof.\n /// @param request The encoded bridge transaction to claim on origin chain\n function claim(bytes memory request) external;\n /// @notice Checks if a transaction has been relayed\n /// @param transactionId The ID of the transaction to check\n /// @return True if the transaction has been relayed, false otherwise\n function bridgeRelays(bytes32 transactionId) external view returns (bool);\n\n /// @notice Returns the status of a bridge transaction\n /// @param transactionId The ID of the bridge transaction\n /// @return BridgeStatus Status of the bridge transaction\n function bridgeStatuses(bytes32 transactionId) external view returns (BridgeStatus);\n\n /// @notice Returns the timestamp and relayer of a bridge proof\n /// @param transactionId The ID of the bridge transaction\n /// @return timestamp The timestamp of the bridge proof\n /// @return relayer The relayer address of the bridge proof\n function bridgeProofs(bytes32 transactionId) external view returns (uint96 timestamp, address relayer);\n\n /// @notice Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\n /// @param request The bridge request to decode\n function getBridgeTransactionV2(bytes memory request) external view returns (BridgeTransactionV2 memory);\n}\n\n// contracts/utils/MulticallTarget.sol\n\n// solhint-disable avoid-low-level-calls\n/// @notice Template for a contract that supports batched calls (preserving the msg.sender).\n/// Only calls with zero msg.value could be batched.\nabstract contract MulticallTarget is IMulticallTarget {\n error MulticallTarget__UndeterminedRevert();\n\n /// @notice Perform a batched call to this contract, preserving the msg.sender.\n /// The return data from each call is discarded.\n /// @dev The method is non-payable, so only calls with `msg.value == 0` could be batched.\n /// It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag.\n /// Otherwise, the whole batch call will be reverted with the original revert reason.\n /// @param data List of abi-encoded calldata for the calls to perform.\n /// @param ignoreReverts Whether to ignore the revert errors from the calls.\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external {\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\n if (!success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(result);\n }\n }\n }\n\n /// @notice Perform a batched call to this contract, preserving the msg.sender.\n /// The return data from each call is preserved.\n /// @dev The method is non-payable, so only calls with `msg.value == 0` could be batched.\n /// It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag.\n /// Otherwise, the whole batch call will be reverted with the original revert reason.\n /// @param data List of abi-encoded calldata for the calls to perform.\n /// @param ignoreReverts Whether to ignore the revert errors from the calls.\n /// @return results List of results from the calls: `(success, returnData)`.\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results)\n {\n results = new Result[](data.length);\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (results[i].success, results[i].returnData) = address(this).delegatecall(data[i]);\n if (!results[i].success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(results[i].returnData);\n }\n }\n }\n\n /// @dev Bubbles the revert message from the underlying call.\n /// Note: preserves the same custom error or revert string, if one was used.\n /// Source: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v5.0.2/contracts/utils/Address.sol#L143-L158\n function _bubbleRevert(bytes memory returnData) internal pure {\n // Look for revert reason and bubble it up if present\n if (returnData.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n // solhint-disable-next-line no-inline-assembly\n assembly {\n let returndata_size := mload(returnData)\n revert(add(32, returnData), returndata_size)\n }\n } else {\n revert MulticallTarget__UndeterminedRevert();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// contracts/libs/BridgeTransactionV2.sol\n\n// solhint-disable no-inline-assembly\nlibrary BridgeTransactionV2Lib {\n uint16 internal constant VERSION = 2;\n\n // Offsets of the fields in the packed BridgeTransactionV2 struct\n // uint16 version [000 .. 002)\n // uint32 originChainId [002 .. 006)\n // uint32 destChainId [006 .. 010)\n // address originSender [010 .. 030)\n // address destRecipient [030 .. 050)\n // address originToken [050 .. 070)\n // address destToken [070 .. 090)\n // uint256 originAmount [090 .. 122)\n // uint256 destAmount [122 .. 154)\n // uint256 originFeeAmount [154 .. 186)\n // uint256 deadline [186 .. 218)\n // uint256 nonce [218 .. 250)\n // address exclusivityRelayer [250 .. 270)\n // uint256 exclusivityEndTime [270 .. 302)\n // uint256 zapNative [302 .. 334)\n // bytes zapData [334 .. ***)\n\n // forgefmt: disable-start\n uint256 private constant OFFSET_ORIGIN_CHAIN_ID = 2;\n uint256 private constant OFFSET_DEST_CHAIN_ID = 6;\n uint256 private constant OFFSET_ORIGIN_SENDER = 10;\n uint256 private constant OFFSET_DEST_RECIPIENT = 30;\n uint256 private constant OFFSET_ORIGIN_TOKEN = 50;\n uint256 private constant OFFSET_DEST_TOKEN = 70;\n uint256 private constant OFFSET_ORIGIN_AMOUNT = 90;\n uint256 private constant OFFSET_DEST_AMOUNT = 122;\n uint256 private constant OFFSET_ORIGIN_FEE_AMOUNT = 154;\n uint256 private constant OFFSET_DEADLINE = 186;\n uint256 private constant OFFSET_NONCE = 218;\n uint256 private constant OFFSET_EXCLUSIVITY_RELAYER = 250;\n uint256 private constant OFFSET_EXCLUSIVITY_END_TIME = 270;\n uint256 private constant OFFSET_ZAP_NATIVE = 302;\n uint256 private constant OFFSET_ZAP_DATA = 334;\n // forgefmt: disable-end\n\n error BridgeTransactionV2__InvalidEncodedTx();\n error BridgeTransactionV2__UnsupportedVersion(uint16 version);\n\n /// @notice Validates the encoded transaction to be a tightly packed encoded payload for BridgeTransactionV2.\n /// @dev Checks the minimum length and the version, use this function before decoding any of the fields.\n function validateV2(bytes calldata encodedTx) internal pure {\n // Check the minimum length: must at least include all static fields.\n if (encodedTx.length \u003c OFFSET_ZAP_DATA) revert BridgeTransactionV2__InvalidEncodedTx();\n // Once we validated the length, we can be sure that the version field is present.\n uint16 version_ = version(encodedTx);\n if (version_ != VERSION) revert BridgeTransactionV2__UnsupportedVersion(version_);\n }\n\n /// @notice Encodes the BridgeTransactionV2 struct by tightly packing the fields.\n /// @dev `abi.decode` will not work as a result of the tightly packed fields. Use `decodeV2` to decode instead.\n function encodeV2(IFastBridgeV2.BridgeTransactionV2 memory bridgeTx) internal pure returns (bytes memory) {\n // We split the encoding into two parts to avoid stack-too-deep error\n bytes memory firstPart = abi.encodePacked(\n VERSION,\n bridgeTx.originChainId,\n bridgeTx.destChainId,\n bridgeTx.originSender,\n bridgeTx.destRecipient,\n bridgeTx.originToken,\n bridgeTx.destToken,\n bridgeTx.originAmount\n );\n return abi.encodePacked(\n firstPart,\n bridgeTx.destAmount,\n bridgeTx.originFeeAmount,\n // Note: we skip the deprecated `sendChainGas` flag, which was present in BridgeTransaction V1\n bridgeTx.deadline,\n bridgeTx.nonce,\n // New V2 fields: exclusivity\n bridgeTx.exclusivityRelayer,\n bridgeTx.exclusivityEndTime,\n // New V2 fields: Zap\n bridgeTx.zapNative,\n bridgeTx.zapData\n );\n }\n\n /// @notice Decodes the BridgeTransactionV2 struct from the encoded transaction.\n /// @dev Encoded BridgeTransactionV2 struct must be tightly packed.\n /// Use `validateV2` before decoding to ensure the encoded transaction is valid.\n function decodeV2(bytes calldata encodedTx)\n internal\n pure\n returns (IFastBridgeV2.BridgeTransactionV2 memory bridgeTx)\n {\n bridgeTx.originChainId = originChainId(encodedTx);\n bridgeTx.destChainId = destChainId(encodedTx);\n bridgeTx.originSender = originSender(encodedTx);\n bridgeTx.destRecipient = destRecipient(encodedTx);\n bridgeTx.originToken = originToken(encodedTx);\n bridgeTx.destToken = destToken(encodedTx);\n bridgeTx.originAmount = originAmount(encodedTx);\n bridgeTx.destAmount = destAmount(encodedTx);\n bridgeTx.originFeeAmount = originFeeAmount(encodedTx);\n bridgeTx.deadline = deadline(encodedTx);\n bridgeTx.nonce = nonce(encodedTx);\n bridgeTx.exclusivityRelayer = exclusivityRelayer(encodedTx);\n bridgeTx.exclusivityEndTime = exclusivityEndTime(encodedTx);\n bridgeTx.zapNative = zapNative(encodedTx);\n bridgeTx.zapData = zapData(encodedTx);\n }\n\n /// @notice Extracts the version from the encoded transaction.\n function version(bytes calldata encodedTx) internal pure returns (uint16 version_) {\n // Load 32 bytes from the start and shift it 240 bits to the right to get the highest 16 bits.\n assembly {\n version_ := shr(240, calldataload(encodedTx.offset))\n }\n }\n\n /// @notice Extracts the origin chain ID from the encoded transaction.\n function originChainId(bytes calldata encodedTx) internal pure returns (uint32 originChainId_) {\n // Load 32 bytes from the offset and shift it 224 bits to the right to get the highest 32 bits.\n assembly {\n originChainId_ := shr(224, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_CHAIN_ID)))\n }\n }\n\n /// @notice Extracts the destination chain ID from the encoded transaction.\n function destChainId(bytes calldata encodedTx) internal pure returns (uint32 destChainId_) {\n // Load 32 bytes from the offset and shift it 224 bits to the right to get the highest 32 bits.\n assembly {\n destChainId_ := shr(224, calldataload(add(encodedTx.offset, OFFSET_DEST_CHAIN_ID)))\n }\n }\n\n /// @notice Extracts the origin sender from the encoded transaction.\n function originSender(bytes calldata encodedTx) internal pure returns (address originSender_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n originSender_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_SENDER)))\n }\n }\n\n /// @notice Extracts the destination recipient from the encoded transaction.\n function destRecipient(bytes calldata encodedTx) internal pure returns (address destRecipient_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n destRecipient_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_DEST_RECIPIENT)))\n }\n }\n\n /// @notice Extracts the origin token from the encoded transaction.\n function originToken(bytes calldata encodedTx) internal pure returns (address originToken_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n originToken_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_TOKEN)))\n }\n }\n\n /// @notice Extracts the destination token from the encoded transaction.\n function destToken(bytes calldata encodedTx) internal pure returns (address destToken_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n destToken_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_DEST_TOKEN)))\n }\n }\n\n /// @notice Extracts the origin amount from the encoded transaction.\n function originAmount(bytes calldata encodedTx) internal pure returns (uint256 originAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n originAmount_ := calldataload(add(encodedTx.offset, OFFSET_ORIGIN_AMOUNT))\n }\n }\n\n /// @notice Extracts the destination amount from the encoded transaction.\n function destAmount(bytes calldata encodedTx) internal pure returns (uint256 destAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n destAmount_ := calldataload(add(encodedTx.offset, OFFSET_DEST_AMOUNT))\n }\n }\n\n /// @notice Extracts the origin fee amount from the encoded transaction.\n function originFeeAmount(bytes calldata encodedTx) internal pure returns (uint256 originFeeAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n originFeeAmount_ := calldataload(add(encodedTx.offset, OFFSET_ORIGIN_FEE_AMOUNT))\n }\n }\n\n /// @notice Extracts the deadline from the encoded transaction.\n function deadline(bytes calldata encodedTx) internal pure returns (uint256 deadline_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n deadline_ := calldataload(add(encodedTx.offset, OFFSET_DEADLINE))\n }\n }\n\n /// @notice Extracts the nonce from the encoded transaction.\n function nonce(bytes calldata encodedTx) internal pure returns (uint256 nonce_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n nonce_ := calldataload(add(encodedTx.offset, OFFSET_NONCE))\n }\n }\n\n /// @notice Extracts the exclusivity relayer from the encoded transaction.\n function exclusivityRelayer(bytes calldata encodedTx) internal pure returns (address exclusivityRelayer_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n exclusivityRelayer_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_EXCLUSIVITY_RELAYER)))\n }\n }\n\n /// @notice Extracts the exclusivity end time from the encoded transaction.\n function exclusivityEndTime(bytes calldata encodedTx) internal pure returns (uint256 exclusivityEndTime_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n exclusivityEndTime_ := calldataload(add(encodedTx.offset, OFFSET_EXCLUSIVITY_END_TIME))\n }\n }\n\n /// @notice Extracts the Zap's native value from the encoded transaction.\n function zapNative(bytes calldata encodedTx) internal pure returns (uint256 zapNative_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n zapNative_ := calldataload(add(encodedTx.offset, OFFSET_ZAP_NATIVE))\n }\n }\n\n /// @notice Extracts the Zap's data from the encoded transaction.\n function zapData(bytes calldata encodedTx) internal pure returns (bytes calldata zapData_) {\n zapData_ = encodedTx[OFFSET_ZAP_DATA:];\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// contracts/libs/UniversalToken.sol\n\nlibrary UniversalTokenLib {\n using SafeERC20 for IERC20;\n\n address internal constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Transfers tokens to the given account. Reverts if transfer is not successful.\n /// @dev This might trigger fallback, if ETH is transferred to the contract.\n /// Make sure this can not lead to reentrancy attacks.\n function universalTransfer(address token, address to, uint256 value) internal {\n // Don't do anything, if need to send tokens to this address\n if (to == address(this)) return;\n // Don't do anything, if trying to send zero value\n if (value == 0) return;\n if (token == ETH_ADDRESS) {\n /// @dev Note: this can potentially lead to executing code in `to`.\n // solhint-disable-next-line avoid-low-level-calls\n (bool success,) = to.call{value: value}(\"\");\n require(success, \"ETH transfer failed\");\n } else {\n IERC20(token).safeTransfer(to, value);\n }\n }\n\n /// @notice Issues an infinite allowance to the spender, if the current allowance is insufficient\n /// to spend the given amount.\n function universalApproveInfinity(address token, address spender, uint256 amountToSpend) internal {\n // ETH Chad doesn't require your approval\n if (token == ETH_ADDRESS) return;\n // No-op if allowance is already sufficient\n uint256 allowance = IERC20(token).allowance(address(this), spender);\n if (allowance \u003e= amountToSpend) return;\n // Otherwise, reset approval to 0 and set to max allowance\n if (allowance \u003e 0) IERC20(token).safeDecreaseAllowance(spender, allowance);\n IERC20(token).safeIncreaseAllowance(spender, type(uint256).max);\n }\n\n /// @notice Returns the balance of the given token (or native ETH) for the given account.\n function universalBalanceOf(address token, address account) internal view returns (uint256) {\n if (token == ETH_ADDRESS) {\n return account.balance;\n } else {\n return IERC20(token).balanceOf(account);\n }\n }\n\n /// @dev Checks that token is a contract and not ETH_ADDRESS.\n function assertIsContract(address token) internal view {\n // Check that ETH_ADDRESS was not used (in case this is a predeploy on any of the chains)\n if (token == UniversalTokenLib.ETH_ADDRESS) revert TokenNotContract();\n // Check that token is not an EOA\n if (token.code.length == 0) revert TokenNotContract();\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/Admin.sol\n\ncontract Admin is IAdmin, AccessControlEnumerable {\n using UniversalTokenLib for address;\n\n bytes32 public constant RELAYER_ROLE = keccak256(\"RELAYER_ROLE\");\n bytes32 public constant REFUNDER_ROLE = keccak256(\"REFUNDER_ROLE\");\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n uint256 public constant FEE_BPS = 1e6;\n uint256 public constant FEE_RATE_MAX = 0.01e6; // max 1% on origin amount\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Chain gas amount to forward as rebate if requested\n uint256 public chainGasAmount;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n }\n\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n require(newFeeRate \u003c= FEE_RATE_MAX, \"newFeeRate \u003e max\");\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n token.universalTransfer(recipient, feeAmount);\n emit FeesSwept(token, recipient, feeAmount);\n }\n\n function setChainGasAmount(uint256 newChainGasAmount) external onlyRole(GOVERNOR_ROLE) {\n uint256 oldChainGasAmount = chainGasAmount;\n chainGasAmount = newChainGasAmount;\n emit ChainGasAmountUpdated(oldChainGasAmount, newChainGasAmount);\n }\n}\n\n// contracts/FastBridgeV2.sol\n\n/// @notice FastBridgeV2 is a contract for bridging tokens across chains.\ncontract FastBridgeV2 is Admin, MulticallTarget, IFastBridgeV2, IFastBridgeV2Errors {\n using BridgeTransactionV2Lib for bytes;\n using SafeERC20 for IERC20;\n\n /// @notice Address reserved for native gas token (ETH on Ethereum and most L2s, AVAX on Avalanche, etc)\n address public constant NATIVE_GAS_TOKEN = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Delay for a transaction after which it could be permisionlessly refunded\n uint256 public constant REFUND_DELAY = 7 days;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n /// @notice Maximum length of accepted zapData\n uint256 public constant MAX_ZAP_DATA_LENGTH = 2 ** 16 - 1;\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeTxDetails) public bridgeTxDetails;\n /// @notice Relay details on destination chain\n mapping(bytes32 =\u003e BridgeRelay) public bridgeRelayDetails;\n /// @notice Unique bridge nonces tracked per originSender\n mapping(address =\u003e uint256) public senderNonces;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Replaced by senderNonces\n uint256 public immutable nonce = 0;\n /// @notice the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n bridge({\n params: params,\n paramsV2: BridgeParamsV2({\n quoteRelayer: address(0),\n quoteExclusivitySeconds: 0,\n quoteId: bytes(\"\"),\n zapNative: 0,\n zapData: bytes(\"\")\n })\n });\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes calldata request) external payable {\n // relay override will validate the request\n relay({request: request, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes calldata request, bytes32 destTxHash) external {\n request.validateV2();\n prove({transactionId: keccak256(request), destTxHash: destTxHash, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridgeV2\n function claim(bytes calldata request) external {\n // claim override will validate the request\n claim({request: request, to: address(0)});\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Aggregate the read operations from the same storage slot\n address disputedRelayer = $.proofRelayer;\n BridgeStatus status = $.status;\n uint56 proofBlockTimestamp = $.proofBlockTimestamp;\n // Can only dispute a RELAYER_PROVED transaction within the dispute period\n if (status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(proofBlockTimestamp) \u003e DISPUTE_PERIOD) {\n revert DisputePeriodPassed();\n }\n // Update status to REQUESTED and delete the disputed proof details\n // Note: these are storage writes\n $.status = BridgeStatus.REQUESTED;\n $.proofRelayer = address(0);\n $.proofBlockTimestamp = 0;\n\n emit BridgeProofDisputed(transactionId, disputedRelayer);\n }\n\n /// @inheritdoc IFastBridge\n function refund(bytes calldata request) external {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Can only refund a REQUESTED transaction after its deadline expires\n if ($.status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n uint256 deadline = request.deadline();\n // Permissionless refund is only allowed after REFUND_DELAY on top of the deadline\n if (!hasRole(REFUNDER_ROLE, msg.sender)) deadline += REFUND_DELAY;\n if (block.timestamp \u003c= deadline) revert DeadlineNotExceeded();\n // Update status to REFUNDED and return the full amount (collateral + protocol fees) to the original sender.\n // The protocol fees are only updated when the transaction is claimed, so we don't need to update them here.\n // Note: this is a storage write\n $.status = BridgeStatus.REFUNDED;\n\n address to = request.originSender();\n address token = request.originToken();\n uint256 amount = request.originAmount() + request.originFeeAmount();\n // Emit the event before any external calls\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n // Complete the user refund as the last transaction action\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(to), amount);\n } else {\n IERC20(token).safeTransfer(to, amount);\n }\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // The correct relayer can only claim a RELAYER_PROVED transaction after the dispute period\n if ($.status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if ($.proofRelayer != relayer) revert SenderIncorrect();\n return _timeSince($.proofBlockTimestamp) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n /// @dev This method is added to achieve backwards compatibility with decoding requests into V1 structs:\n /// - `zapNative` is partially reported as a zero/non-zero flag\n /// - `zapData` is ignored\n /// In order to process all kinds of requests use getBridgeTransactionV2 instead.\n function getBridgeTransaction(bytes calldata request) external view returns (BridgeTransaction memory) {\n // Try decoding into V2 struct first. This will revert if V1 struct is passed\n try this.getBridgeTransactionV2(request) returns (BridgeTransactionV2 memory txV2) {\n // Note: we entirely ignore the zapData field, as it was not present in V1\n return BridgeTransaction({\n originChainId: txV2.originChainId,\n destChainId: txV2.destChainId,\n originSender: txV2.originSender,\n destRecipient: txV2.destRecipient,\n originToken: txV2.originToken,\n destToken: txV2.destToken,\n originAmount: txV2.originAmount,\n destAmount: txV2.destAmount,\n originFeeAmount: txV2.originFeeAmount,\n sendChainGas: txV2.zapNative != 0,\n deadline: txV2.deadline,\n nonce: txV2.nonce\n });\n } catch {\n // Fallback to V1 struct\n return abi.decode(request, (BridgeTransaction));\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function getBridgeTransactionV2(bytes calldata request) external pure returns (BridgeTransactionV2 memory) {\n request.validateV2();\n return BridgeTransactionV2Lib.decodeV2(request);\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) public payable {\n int256 exclusivityEndTime = 0;\n // if relayer exclusivity is not intended for this bridge, set exclusivityEndTime to static zero\n // otherwise, set exclusivity to expire at the current block ts offset by quoteExclusivitySeconds\n if (paramsV2.quoteRelayer != address(0)) {\n exclusivityEndTime = int256(block.timestamp) + paramsV2.quoteExclusivitySeconds;\n }\n _validateBridgeParams(params, paramsV2, exclusivityEndTime);\n\n // transfer tokens to bridge contract\n /// @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _takeBridgedUserAsset(params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) {\n originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n }\n\n // set status to requested\n bytes memory request = BridgeTransactionV2Lib.encodeV2(\n BridgeTransactionV2({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n deadline: params.deadline,\n nonce: senderNonces[params.sender]++, // increment nonce on every bridge\n exclusivityRelayer: paramsV2.quoteRelayer,\n // We checked exclusivityEndTime to be in range [0 .. params.deadline] above, so can safely cast\n exclusivityEndTime: uint256(exclusivityEndTime),\n zapNative: paramsV2.zapNative,\n zapData: paramsV2.zapData\n })\n );\n bytes32 transactionId = keccak256(request);\n // Note: the tx status will be updated throughout the tx lifecycle, while destChainId is set once here\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n bridgeTxDetails[transactionId].destChainId = params.dstChainId;\n\n emit BridgeRequested({\n transactionId: transactionId,\n sender: params.sender,\n request: request,\n destChainId: params.dstChainId,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n sendChainGas: paramsV2.zapNative != 0\n });\n emit BridgeQuoteDetails(transactionId, paramsV2.quoteId);\n }\n\n /// @inheritdoc IFastBridgeV2\n function relay(bytes calldata request, address relayer) public payable {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n _validateRelayParams(request, transactionId, relayer);\n // mark bridge transaction as relayed\n bridgeRelayDetails[transactionId] =\n BridgeRelay({blockNumber: uint48(block.number), blockTimestamp: uint48(block.timestamp), relayer: relayer});\n\n // transfer tokens to recipient on destination chain and trigger Zap if requested\n address to = request.destRecipient();\n address token = request.destToken();\n uint256 amount = request.destAmount();\n uint256 zapNative = request.zapNative();\n\n // Emit the event before any external calls\n emit BridgeRelayed({\n transactionId: transactionId,\n relayer: relayer,\n to: to,\n originChainId: request.originChainId(),\n originToken: request.originToken(),\n destToken: token,\n originAmount: request.originAmount(),\n destAmount: amount,\n chainGasAmount: zapNative\n });\n\n // All state changes have been done at this point, can proceed to the external calls.\n // This follows the checks-effects-interactions pattern to mitigate potential reentrancy attacks.\n if (token == NATIVE_GAS_TOKEN) {\n // For the native gas token, additional zapNative is not allowed\n if (zapNative != 0) revert ZapNativeNotSupported();\n // Check that the correct msg.value was sent\n if (msg.value != amount) revert MsgValueIncorrect();\n // Don't do a native transfer yet: we will handle it alongside the Zap below\n } else {\n // For ERC20s, we check that the correct msg.value was sent\n if (msg.value != zapNative) revert MsgValueIncorrect();\n // We need to transfer the tokens from the Relayer to the recipient first before performing an\n // optional post-transfer Zap.\n IERC20(token).safeTransferFrom(msg.sender, to, amount);\n }\n // At this point we have done:\n // - Transferred the requested amount of ERC20 tokens to the recipient.\n // At this point we have confirmed:\n // - For ERC20s: msg.value matches the requested zapNative amount.\n // - For the native gas token: msg.value matches the requested destAmount.\n // Remaining optional things to do:\n // - Forward the full msg.value to the recipient (if non-zero).\n // - Trigger a Zap (if zapData is present).\n bytes calldata zapData = request.zapData();\n if (zapData.length != 0) {\n // Zap Data is present: Zap has been requested by the recipient. Trigger it forwarding the full msg.value.\n\n // Note: if token has a fee on transfers, the recipient will have received less than `amount`.\n // This is a very niche edge case and should be handled by the recipient contract.\n _triggerZapWithChecks({recipient: to, token: token, amount: amount, zapData: zapData});\n } else if (msg.value != 0) {\n // Zap Data is missing, but msg.value was sent. This could happen in two different cases:\n // - Relay with the native gas token is happening.\n // - Relay with ERC20 is happening, with a `zapNative \u003e 0` request.\n // In both cases, we need to transfer the full msg.value to the recipient.\n Address.sendValue(payable(to), msg.value);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) public onlyRole(RELAYER_ROLE) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n\n // Can only prove a REQUESTED transaction\n if ($.status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n // Update status to RELAYER_PROVED and store the proof details\n // Note: these are storage writes\n $.status = BridgeStatus.RELAYER_PROVED;\n $.proofBlockTimestamp = uint56(block.timestamp);\n $.proofRelayer = relayer;\n\n emit BridgeProofProvided(transactionId, relayer, destTxHash);\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes calldata request, address to) public {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Aggregate the read operations from the same storage slot\n address proofRelayer = $.proofRelayer;\n BridgeStatus status = $.status;\n uint56 proofBlockTimestamp = $.proofBlockTimestamp;\n\n // Can only claim a RELAYER_PROVED transaction after the dispute period\n if (status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(proofBlockTimestamp) \u003c= DISPUTE_PERIOD) {\n revert DisputePeriodNotPassed();\n }\n\n if (to == address(0)) {\n // Anyone could claim the funds to the proven relayer on their behalf\n to = proofRelayer;\n } else if (proofRelayer != msg.sender) {\n // Only the proven relayer could specify an address to claim the funds to\n revert SenderIncorrect();\n }\n\n // Update status to RELAYER_CLAIMED and transfer the origin collateral to the specified claim address\n // Note: this is a storage write\n $.status = BridgeStatus.RELAYER_CLAIMED;\n\n address token = request.originToken();\n uint256 amount = request.originAmount();\n // Update protocol fees if origin fee amount exists\n uint256 originFeeAmount = request.originFeeAmount();\n if (originFeeAmount \u003e 0) protocolFees[token] += originFeeAmount;\n // Emit the event before any external calls\n emit BridgeDepositClaimed(transactionId, proofRelayer, to, token, amount);\n // Complete the relayer claim as the last transaction action\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(to), amount);\n } else {\n IERC20(token).safeTransfer(to, amount);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeStatuses(bytes32 transactionId) public view returns (BridgeStatus status) {\n return bridgeTxDetails[transactionId].status;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeProofs(bytes32 transactionId) public view returns (uint96 timestamp, address relayer) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n\n timestamp = $.proofBlockTimestamp;\n relayer = $.proofRelayer;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeRelays(bytes32 transactionId) public view returns (bool) {\n // has this transactionId been relayed?\n return bridgeRelayDetails[transactionId].relayer != address(0);\n }\n\n /// @notice Takes the bridged asset from the user into FastBridgeV2 custody. It will be later\n /// claimed by the relayer who completed the relay on destination chain, or refunded back to the user,\n /// should no one complete the relay.\n function _takeBridgedUserAsset(address token, uint256 amount) internal returns (uint256 amountTaken) {\n if (token == NATIVE_GAS_TOKEN) {\n // For the native gas token, we just need to check that the supplied msg.value is correct.\n // Supplied `msg.value` is already in FastBridgeV2 custody.\n if (amount != msg.value) revert MsgValueIncorrect();\n amountTaken = msg.value;\n } else {\n // For ERC20s, token is explicitly transferred from the user to FastBridgeV2.\n // We don't allow non-zero `msg.value` to avoid extra funds from being stuck in FastBridgeV2.\n if (msg.value != 0) revert MsgValueIncorrect();\n // Throw an explicit error if the provided token address is not a contract\n if (token.code.length == 0) revert TokenNotContract();\n amountTaken = IERC20(token).balanceOf(address(this));\n IERC20(token).safeTransferFrom(msg.sender, address(this), amount);\n // Use the balance difference as the amount taken in case of fee on transfer tokens.\n amountTaken = IERC20(token).balanceOf(address(this)) - amountTaken;\n }\n }\n\n /// @notice Calls the Recipient's hook function with the specified zapData and performs\n /// all the necessary checks for the returned value.\n function _triggerZapWithChecks(address recipient, address token, uint256 amount, bytes calldata zapData) internal {\n // This will bubble any revert messages from the hook function\n bytes memory returnData = Address.functionCallWithValue({\n target: recipient,\n data: abi.encodeCall(IZapRecipient.zap, (token, amount, zapData)),\n // Note: see `relay()` for reasoning behind passing msg.value\n value: msg.value\n });\n // Explicit revert if no return data at all\n if (returnData.length == 0) revert RecipientNoReturnValue();\n // Check that exactly a single return value was returned\n if (returnData.length != 32) revert RecipientIncorrectReturnValue();\n // Return value should be abi-encoded hook function selector\n if (bytes32(returnData) != bytes32(IZapRecipient.zap.selector)) {\n revert RecipientIncorrectReturnValue();\n }\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint56(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint56).max but\n /// proof.timestamp \u003c type(uint56).max via unchecked statement\n /// @param proofBlockTimestamp The bridge proof block timestamp\n /// @return delta Time delta since proof submitted\n function _timeSince(uint56 proofBlockTimestamp) internal view returns (uint256 delta) {\n unchecked {\n delta = uint56(block.timestamp) - proofBlockTimestamp;\n }\n }\n\n /// @notice Performs all the necessary checks for a bridge to happen.\n /// @dev There's no good way to refactor this function to reduce cyclomatic complexity due to\n /// the number of checks that need to be performed, so we skip the code-complexity rule here.\n // solhint-disable-next-line code-complexity\n function _validateBridgeParams(\n BridgeParams memory params,\n BridgeParamsV2 memory paramsV2,\n int256 exclusivityEndTime\n )\n internal\n view\n {\n // Check V1 (legacy) params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.sender == address(0) || params.to == address(0)) revert ZeroAddress();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n // Check V2 params\n if (paramsV2.zapData.length \u003e MAX_ZAP_DATA_LENGTH) revert ZapDataLengthAboveMax();\n if (paramsV2.zapNative != 0 \u0026\u0026 params.destToken == NATIVE_GAS_TOKEN) {\n revert ZapNativeNotSupported();\n }\n // exclusivityEndTime must be in range [0 .. params.deadline]\n if (exclusivityEndTime \u003c 0 || exclusivityEndTime \u003e int256(params.deadline)) {\n revert ExclusivityParamsIncorrect();\n }\n }\n\n /// @notice Performs all the necessary checks for a relay to happen.\n function _validateRelayParams(bytes calldata request, bytes32 transactionId, address relayer) internal view {\n if (relayer == address(0)) revert ZeroAddress();\n // Check if the transaction has already been relayed\n if (bridgeRelays(transactionId)) revert TransactionRelayed();\n if (request.destChainId() != block.chainid) revert ChainIncorrect();\n // Check the deadline for relay to happen\n if (block.timestamp \u003e request.deadline()) revert DeadlineExceeded();\n // Check the exclusivity period, if it is still ongoing\n address exclRelayer = request.exclusivityRelayer();\n if (exclRelayer != address(0) \u0026\u0026 exclRelayer != relayer \u0026\u0026 block.timestamp \u003c= request.exclusivityEndTime()) {\n revert ExclusivityPeriodNotPassed();\n }\n }\n}\n","language":"Solidity","languageVersion":"0.8.24","compilerVersion":"0.8.24","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"","srcMapRuntime":"","abiDefinition":[{"inputs":[{"internalType":"bytes[]","name":"data","type":"bytes[]"},{"internalType":"bool","name":"ignoreReverts","type":"bool"}],"name":"multicallNoResults","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes[]","name":"data","type":"bytes[]"},{"internalType":"bool","name":"ignoreReverts","type":"bool"}],"name":"multicallWithResults","outputs":[{"components":[{"internalType":"bool","name":"success","type":"bool"},{"internalType":"bytes","name":"returnData","type":"bytes"}],"internalType":"struct IMulticallTarget.Result[]","name":"results","type":"tuple[]"}],"stateMutability":"nonpayable","type":"function"}],"userDoc":{"kind":"user","methods":{},"notice":"Interface for a contract that can be called multiple times by the same caller. Inspired by MulticallV3: https://github.com/mds1/multicall/blob/master/src/Multicall3.sol","version":1},"developerDoc":{"kind":"dev","methods":{},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"bytes[]\",\"name\":\"data\",\"type\":\"bytes[]\"},{\"internalType\":\"bool\",\"name\":\"ignoreReverts\",\"type\":\"bool\"}],\"name\":\"multicallNoResults\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes[]\",\"name\":\"data\",\"type\":\"bytes[]\"},{\"internalType\":\"bool\",\"name\":\"ignoreReverts\",\"type\":\"bool\"}],\"name\":\"multicallWithResults\",\"outputs\":[{\"components\":[{\"internalType\":\"bool\",\"name\":\"success\",\"type\":\"bool\"},{\"internalType\":\"bytes\",\"name\":\"returnData\",\"type\":\"bytes\"}],\"internalType\":\"struct IMulticallTarget.Result[]\",\"name\":\"results\",\"type\":\"tuple[]\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"notice\":\"Interface for a contract that can be called multiple times by the same caller. Inspired by MulticallV3: https://github.com/mds1/multicall/blob/master/src/Multicall3.sol\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeV2.sol\":\"IMulticallTarget\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeV2.sol\":{\"keccak256\":\"0x5069b55ca07f21bfe30b2a43c18a18318c8af9c181b2dcb07c290825efd70f34\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://273dc020a49d08e50126bbea0d7f783f79d08c702f2fdbc560618d24af308acc\",\"dweb:/ipfs/QmXJ2UVzFc8EPB74RT4CXQPC4xw66jt4T13poyfyd3UERh\"]}},\"version\":1}"},"hashes":{"multicallNoResults(bytes[],bool)":"3f61331d","multicallWithResults(bytes[],bool)":"385c1d2f"}},"solidity/FastBridgeV2.sol:IZapRecipient":{"code":"0x","runtime-code":"0x","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.24 ^0.8.20 ^0.8.4;\n\n// contracts/interfaces/IAdmin.sol\n\ninterface IAdmin {\n // ============ Events ============\n\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n event ChainGasAmountUpdated(uint256 oldChainGasAmount, uint256 newChainGasAmount);\n\n // ============ Methods ============\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n\n function setChainGasAmount(uint256 newChainGasAmount) external;\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IFastBridgeV2Errors.sol\n\ninterface IFastBridgeV2Errors {\n error AmountIncorrect();\n error ChainIncorrect();\n error ExclusivityParamsIncorrect();\n error MsgValueIncorrect();\n error SenderIncorrect();\n error StatusIncorrect();\n error TokenNotContract();\n error ZapDataLengthAboveMax();\n error ZapNativeNotSupported();\n error ZeroAddress();\n\n error RecipientIncorrectReturnValue();\n error RecipientNoReturnValue();\n\n error DeadlineExceeded();\n error DeadlineNotExceeded();\n error DeadlineTooShort();\n error DisputePeriodNotPassed();\n error DisputePeriodPassed();\n error ExclusivityPeriodNotPassed();\n\n error TransactionRelayed();\n}\n\n// contracts/interfaces/IMulticallTarget.sol\n\n/// @notice Interface for a contract that can be called multiple times by the same caller. Inspired by MulticallV3:\n/// https://github.com/mds1/multicall/blob/master/src/Multicall3.sol\ninterface IMulticallTarget {\n struct Result {\n bool success;\n bytes returnData;\n }\n\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external;\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results);\n}\n\n// contracts/interfaces/IZapRecipient.sol\n\ninterface IZapRecipient {\n function zap(address token, uint256 amount, bytes memory zapData) external payable returns (bytes4);\n}\n\n// contracts/libs/Errors.sol\n\nerror DeadlineExceeded();\nerror DeadlineNotExceeded();\nerror DeadlineTooShort();\nerror InsufficientOutputAmount();\n\nerror MsgValueIncorrect();\nerror PoolNotFound();\nerror TokenAddressMismatch();\nerror TokenNotContract();\nerror TokenNotETH();\nerror TokensIdentical();\n\nerror ChainIncorrect();\nerror AmountIncorrect();\nerror ZeroAddress();\n\nerror DisputePeriodNotPassed();\nerror DisputePeriodPassed();\nerror SenderIncorrect();\nerror StatusIncorrect();\nerror TransactionIdIncorrect();\nerror TransactionRelayed();\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// contracts/interfaces/IFastBridgeV2.sol\n\ninterface IFastBridgeV2 is IFastBridge {\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n struct BridgeTxDetails {\n BridgeStatus status;\n uint32 destChainId;\n uint56 proofBlockTimestamp;\n address proofRelayer;\n }\n\n struct BridgeRelay {\n uint48 blockNumber;\n uint48 blockTimestamp;\n address relayer;\n }\n\n /// @notice New params introduced in the FastBridgeV2.\n /// We are passing fields from the older BridgeParams struct outside of this struct\n /// for backwards compatibility.\n /// Note: quoteRelayer and quoteExclusivitySeconds are either both zero (indicating no exclusivity)\n /// or both non-zero (indicating exclusivity for the given period).\n /// Note: zapNative \u003e 0 can NOT be used with destToken = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE (native token)\n /// @param quoteRelayer Relayer that provided the quote for the transaction\n /// @param quoteExclusivitySeconds Period of time the quote relayer is guaranteed exclusivity after user's deposit\n /// @param quoteId Unique quote identifier used for tracking the quote\n /// @param zapNative ETH value to send to the recipient (if any)\n /// @param zapData Parameters for the Zap to the destination recipient (if any)\n struct BridgeParamsV2 {\n address quoteRelayer;\n int256 quoteExclusivitySeconds;\n bytes quoteId;\n uint256 zapNative;\n bytes zapData;\n }\n\n /// @notice Updated bridge transaction struct to include parameters introduced in FastBridgeV2.\n /// Note: only `exclusivityRelayer` can fill such a transaction until `exclusivityEndTime`.\n struct BridgeTransactionV2 {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n // Note: sendChainGas flag from V1 is deprecated\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n address exclusivityRelayer;\n uint256 exclusivityEndTime;\n uint256 zapNative; // ETH value to send to the recipient (if any)\n bytes zapData; // data to pass for the Zap action (if any)\n }\n\n event BridgeQuoteDetails(bytes32 indexed transactionId, bytes quoteId);\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability\n /// to provide temporary exclusivity fill rights for the quote relayer.\n /// @param params The parameters required to bridge\n /// @param paramsV2 The parameters for exclusivity fill rights (optional, can be left empty)\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function relay(bytes memory request, address relayer) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param transactionId The transaction id associated with the encoded bridge transaction to prove\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital.\n /// @notice Can only send funds to the relayer address on the proof.\n /// @param request The encoded bridge transaction to claim on origin chain\n function claim(bytes memory request) external;\n /// @notice Checks if a transaction has been relayed\n /// @param transactionId The ID of the transaction to check\n /// @return True if the transaction has been relayed, false otherwise\n function bridgeRelays(bytes32 transactionId) external view returns (bool);\n\n /// @notice Returns the status of a bridge transaction\n /// @param transactionId The ID of the bridge transaction\n /// @return BridgeStatus Status of the bridge transaction\n function bridgeStatuses(bytes32 transactionId) external view returns (BridgeStatus);\n\n /// @notice Returns the timestamp and relayer of a bridge proof\n /// @param transactionId The ID of the bridge transaction\n /// @return timestamp The timestamp of the bridge proof\n /// @return relayer The relayer address of the bridge proof\n function bridgeProofs(bytes32 transactionId) external view returns (uint96 timestamp, address relayer);\n\n /// @notice Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\n /// @param request The bridge request to decode\n function getBridgeTransactionV2(bytes memory request) external view returns (BridgeTransactionV2 memory);\n}\n\n// contracts/utils/MulticallTarget.sol\n\n// solhint-disable avoid-low-level-calls\n/// @notice Template for a contract that supports batched calls (preserving the msg.sender).\n/// Only calls with zero msg.value could be batched.\nabstract contract MulticallTarget is IMulticallTarget {\n error MulticallTarget__UndeterminedRevert();\n\n /// @notice Perform a batched call to this contract, preserving the msg.sender.\n /// The return data from each call is discarded.\n /// @dev The method is non-payable, so only calls with `msg.value == 0` could be batched.\n /// It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag.\n /// Otherwise, the whole batch call will be reverted with the original revert reason.\n /// @param data List of abi-encoded calldata for the calls to perform.\n /// @param ignoreReverts Whether to ignore the revert errors from the calls.\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external {\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\n if (!success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(result);\n }\n }\n }\n\n /// @notice Perform a batched call to this contract, preserving the msg.sender.\n /// The return data from each call is preserved.\n /// @dev The method is non-payable, so only calls with `msg.value == 0` could be batched.\n /// It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag.\n /// Otherwise, the whole batch call will be reverted with the original revert reason.\n /// @param data List of abi-encoded calldata for the calls to perform.\n /// @param ignoreReverts Whether to ignore the revert errors from the calls.\n /// @return results List of results from the calls: `(success, returnData)`.\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results)\n {\n results = new Result[](data.length);\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (results[i].success, results[i].returnData) = address(this).delegatecall(data[i]);\n if (!results[i].success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(results[i].returnData);\n }\n }\n }\n\n /// @dev Bubbles the revert message from the underlying call.\n /// Note: preserves the same custom error or revert string, if one was used.\n /// Source: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v5.0.2/contracts/utils/Address.sol#L143-L158\n function _bubbleRevert(bytes memory returnData) internal pure {\n // Look for revert reason and bubble it up if present\n if (returnData.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n // solhint-disable-next-line no-inline-assembly\n assembly {\n let returndata_size := mload(returnData)\n revert(add(32, returnData), returndata_size)\n }\n } else {\n revert MulticallTarget__UndeterminedRevert();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// contracts/libs/BridgeTransactionV2.sol\n\n// solhint-disable no-inline-assembly\nlibrary BridgeTransactionV2Lib {\n uint16 internal constant VERSION = 2;\n\n // Offsets of the fields in the packed BridgeTransactionV2 struct\n // uint16 version [000 .. 002)\n // uint32 originChainId [002 .. 006)\n // uint32 destChainId [006 .. 010)\n // address originSender [010 .. 030)\n // address destRecipient [030 .. 050)\n // address originToken [050 .. 070)\n // address destToken [070 .. 090)\n // uint256 originAmount [090 .. 122)\n // uint256 destAmount [122 .. 154)\n // uint256 originFeeAmount [154 .. 186)\n // uint256 deadline [186 .. 218)\n // uint256 nonce [218 .. 250)\n // address exclusivityRelayer [250 .. 270)\n // uint256 exclusivityEndTime [270 .. 302)\n // uint256 zapNative [302 .. 334)\n // bytes zapData [334 .. ***)\n\n // forgefmt: disable-start\n uint256 private constant OFFSET_ORIGIN_CHAIN_ID = 2;\n uint256 private constant OFFSET_DEST_CHAIN_ID = 6;\n uint256 private constant OFFSET_ORIGIN_SENDER = 10;\n uint256 private constant OFFSET_DEST_RECIPIENT = 30;\n uint256 private constant OFFSET_ORIGIN_TOKEN = 50;\n uint256 private constant OFFSET_DEST_TOKEN = 70;\n uint256 private constant OFFSET_ORIGIN_AMOUNT = 90;\n uint256 private constant OFFSET_DEST_AMOUNT = 122;\n uint256 private constant OFFSET_ORIGIN_FEE_AMOUNT = 154;\n uint256 private constant OFFSET_DEADLINE = 186;\n uint256 private constant OFFSET_NONCE = 218;\n uint256 private constant OFFSET_EXCLUSIVITY_RELAYER = 250;\n uint256 private constant OFFSET_EXCLUSIVITY_END_TIME = 270;\n uint256 private constant OFFSET_ZAP_NATIVE = 302;\n uint256 private constant OFFSET_ZAP_DATA = 334;\n // forgefmt: disable-end\n\n error BridgeTransactionV2__InvalidEncodedTx();\n error BridgeTransactionV2__UnsupportedVersion(uint16 version);\n\n /// @notice Validates the encoded transaction to be a tightly packed encoded payload for BridgeTransactionV2.\n /// @dev Checks the minimum length and the version, use this function before decoding any of the fields.\n function validateV2(bytes calldata encodedTx) internal pure {\n // Check the minimum length: must at least include all static fields.\n if (encodedTx.length \u003c OFFSET_ZAP_DATA) revert BridgeTransactionV2__InvalidEncodedTx();\n // Once we validated the length, we can be sure that the version field is present.\n uint16 version_ = version(encodedTx);\n if (version_ != VERSION) revert BridgeTransactionV2__UnsupportedVersion(version_);\n }\n\n /// @notice Encodes the BridgeTransactionV2 struct by tightly packing the fields.\n /// @dev `abi.decode` will not work as a result of the tightly packed fields. Use `decodeV2` to decode instead.\n function encodeV2(IFastBridgeV2.BridgeTransactionV2 memory bridgeTx) internal pure returns (bytes memory) {\n // We split the encoding into two parts to avoid stack-too-deep error\n bytes memory firstPart = abi.encodePacked(\n VERSION,\n bridgeTx.originChainId,\n bridgeTx.destChainId,\n bridgeTx.originSender,\n bridgeTx.destRecipient,\n bridgeTx.originToken,\n bridgeTx.destToken,\n bridgeTx.originAmount\n );\n return abi.encodePacked(\n firstPart,\n bridgeTx.destAmount,\n bridgeTx.originFeeAmount,\n // Note: we skip the deprecated `sendChainGas` flag, which was present in BridgeTransaction V1\n bridgeTx.deadline,\n bridgeTx.nonce,\n // New V2 fields: exclusivity\n bridgeTx.exclusivityRelayer,\n bridgeTx.exclusivityEndTime,\n // New V2 fields: Zap\n bridgeTx.zapNative,\n bridgeTx.zapData\n );\n }\n\n /// @notice Decodes the BridgeTransactionV2 struct from the encoded transaction.\n /// @dev Encoded BridgeTransactionV2 struct must be tightly packed.\n /// Use `validateV2` before decoding to ensure the encoded transaction is valid.\n function decodeV2(bytes calldata encodedTx)\n internal\n pure\n returns (IFastBridgeV2.BridgeTransactionV2 memory bridgeTx)\n {\n bridgeTx.originChainId = originChainId(encodedTx);\n bridgeTx.destChainId = destChainId(encodedTx);\n bridgeTx.originSender = originSender(encodedTx);\n bridgeTx.destRecipient = destRecipient(encodedTx);\n bridgeTx.originToken = originToken(encodedTx);\n bridgeTx.destToken = destToken(encodedTx);\n bridgeTx.originAmount = originAmount(encodedTx);\n bridgeTx.destAmount = destAmount(encodedTx);\n bridgeTx.originFeeAmount = originFeeAmount(encodedTx);\n bridgeTx.deadline = deadline(encodedTx);\n bridgeTx.nonce = nonce(encodedTx);\n bridgeTx.exclusivityRelayer = exclusivityRelayer(encodedTx);\n bridgeTx.exclusivityEndTime = exclusivityEndTime(encodedTx);\n bridgeTx.zapNative = zapNative(encodedTx);\n bridgeTx.zapData = zapData(encodedTx);\n }\n\n /// @notice Extracts the version from the encoded transaction.\n function version(bytes calldata encodedTx) internal pure returns (uint16 version_) {\n // Load 32 bytes from the start and shift it 240 bits to the right to get the highest 16 bits.\n assembly {\n version_ := shr(240, calldataload(encodedTx.offset))\n }\n }\n\n /// @notice Extracts the origin chain ID from the encoded transaction.\n function originChainId(bytes calldata encodedTx) internal pure returns (uint32 originChainId_) {\n // Load 32 bytes from the offset and shift it 224 bits to the right to get the highest 32 bits.\n assembly {\n originChainId_ := shr(224, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_CHAIN_ID)))\n }\n }\n\n /// @notice Extracts the destination chain ID from the encoded transaction.\n function destChainId(bytes calldata encodedTx) internal pure returns (uint32 destChainId_) {\n // Load 32 bytes from the offset and shift it 224 bits to the right to get the highest 32 bits.\n assembly {\n destChainId_ := shr(224, calldataload(add(encodedTx.offset, OFFSET_DEST_CHAIN_ID)))\n }\n }\n\n /// @notice Extracts the origin sender from the encoded transaction.\n function originSender(bytes calldata encodedTx) internal pure returns (address originSender_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n originSender_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_SENDER)))\n }\n }\n\n /// @notice Extracts the destination recipient from the encoded transaction.\n function destRecipient(bytes calldata encodedTx) internal pure returns (address destRecipient_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n destRecipient_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_DEST_RECIPIENT)))\n }\n }\n\n /// @notice Extracts the origin token from the encoded transaction.\n function originToken(bytes calldata encodedTx) internal pure returns (address originToken_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n originToken_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_TOKEN)))\n }\n }\n\n /// @notice Extracts the destination token from the encoded transaction.\n function destToken(bytes calldata encodedTx) internal pure returns (address destToken_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n destToken_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_DEST_TOKEN)))\n }\n }\n\n /// @notice Extracts the origin amount from the encoded transaction.\n function originAmount(bytes calldata encodedTx) internal pure returns (uint256 originAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n originAmount_ := calldataload(add(encodedTx.offset, OFFSET_ORIGIN_AMOUNT))\n }\n }\n\n /// @notice Extracts the destination amount from the encoded transaction.\n function destAmount(bytes calldata encodedTx) internal pure returns (uint256 destAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n destAmount_ := calldataload(add(encodedTx.offset, OFFSET_DEST_AMOUNT))\n }\n }\n\n /// @notice Extracts the origin fee amount from the encoded transaction.\n function originFeeAmount(bytes calldata encodedTx) internal pure returns (uint256 originFeeAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n originFeeAmount_ := calldataload(add(encodedTx.offset, OFFSET_ORIGIN_FEE_AMOUNT))\n }\n }\n\n /// @notice Extracts the deadline from the encoded transaction.\n function deadline(bytes calldata encodedTx) internal pure returns (uint256 deadline_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n deadline_ := calldataload(add(encodedTx.offset, OFFSET_DEADLINE))\n }\n }\n\n /// @notice Extracts the nonce from the encoded transaction.\n function nonce(bytes calldata encodedTx) internal pure returns (uint256 nonce_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n nonce_ := calldataload(add(encodedTx.offset, OFFSET_NONCE))\n }\n }\n\n /// @notice Extracts the exclusivity relayer from the encoded transaction.\n function exclusivityRelayer(bytes calldata encodedTx) internal pure returns (address exclusivityRelayer_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n exclusivityRelayer_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_EXCLUSIVITY_RELAYER)))\n }\n }\n\n /// @notice Extracts the exclusivity end time from the encoded transaction.\n function exclusivityEndTime(bytes calldata encodedTx) internal pure returns (uint256 exclusivityEndTime_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n exclusivityEndTime_ := calldataload(add(encodedTx.offset, OFFSET_EXCLUSIVITY_END_TIME))\n }\n }\n\n /// @notice Extracts the Zap's native value from the encoded transaction.\n function zapNative(bytes calldata encodedTx) internal pure returns (uint256 zapNative_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n zapNative_ := calldataload(add(encodedTx.offset, OFFSET_ZAP_NATIVE))\n }\n }\n\n /// @notice Extracts the Zap's data from the encoded transaction.\n function zapData(bytes calldata encodedTx) internal pure returns (bytes calldata zapData_) {\n zapData_ = encodedTx[OFFSET_ZAP_DATA:];\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// contracts/libs/UniversalToken.sol\n\nlibrary UniversalTokenLib {\n using SafeERC20 for IERC20;\n\n address internal constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Transfers tokens to the given account. Reverts if transfer is not successful.\n /// @dev This might trigger fallback, if ETH is transferred to the contract.\n /// Make sure this can not lead to reentrancy attacks.\n function universalTransfer(address token, address to, uint256 value) internal {\n // Don't do anything, if need to send tokens to this address\n if (to == address(this)) return;\n // Don't do anything, if trying to send zero value\n if (value == 0) return;\n if (token == ETH_ADDRESS) {\n /// @dev Note: this can potentially lead to executing code in `to`.\n // solhint-disable-next-line avoid-low-level-calls\n (bool success,) = to.call{value: value}(\"\");\n require(success, \"ETH transfer failed\");\n } else {\n IERC20(token).safeTransfer(to, value);\n }\n }\n\n /// @notice Issues an infinite allowance to the spender, if the current allowance is insufficient\n /// to spend the given amount.\n function universalApproveInfinity(address token, address spender, uint256 amountToSpend) internal {\n // ETH Chad doesn't require your approval\n if (token == ETH_ADDRESS) return;\n // No-op if allowance is already sufficient\n uint256 allowance = IERC20(token).allowance(address(this), spender);\n if (allowance \u003e= amountToSpend) return;\n // Otherwise, reset approval to 0 and set to max allowance\n if (allowance \u003e 0) IERC20(token).safeDecreaseAllowance(spender, allowance);\n IERC20(token).safeIncreaseAllowance(spender, type(uint256).max);\n }\n\n /// @notice Returns the balance of the given token (or native ETH) for the given account.\n function universalBalanceOf(address token, address account) internal view returns (uint256) {\n if (token == ETH_ADDRESS) {\n return account.balance;\n } else {\n return IERC20(token).balanceOf(account);\n }\n }\n\n /// @dev Checks that token is a contract and not ETH_ADDRESS.\n function assertIsContract(address token) internal view {\n // Check that ETH_ADDRESS was not used (in case this is a predeploy on any of the chains)\n if (token == UniversalTokenLib.ETH_ADDRESS) revert TokenNotContract();\n // Check that token is not an EOA\n if (token.code.length == 0) revert TokenNotContract();\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/Admin.sol\n\ncontract Admin is IAdmin, AccessControlEnumerable {\n using UniversalTokenLib for address;\n\n bytes32 public constant RELAYER_ROLE = keccak256(\"RELAYER_ROLE\");\n bytes32 public constant REFUNDER_ROLE = keccak256(\"REFUNDER_ROLE\");\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n uint256 public constant FEE_BPS = 1e6;\n uint256 public constant FEE_RATE_MAX = 0.01e6; // max 1% on origin amount\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Chain gas amount to forward as rebate if requested\n uint256 public chainGasAmount;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n }\n\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n require(newFeeRate \u003c= FEE_RATE_MAX, \"newFeeRate \u003e max\");\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n token.universalTransfer(recipient, feeAmount);\n emit FeesSwept(token, recipient, feeAmount);\n }\n\n function setChainGasAmount(uint256 newChainGasAmount) external onlyRole(GOVERNOR_ROLE) {\n uint256 oldChainGasAmount = chainGasAmount;\n chainGasAmount = newChainGasAmount;\n emit ChainGasAmountUpdated(oldChainGasAmount, newChainGasAmount);\n }\n}\n\n// contracts/FastBridgeV2.sol\n\n/// @notice FastBridgeV2 is a contract for bridging tokens across chains.\ncontract FastBridgeV2 is Admin, MulticallTarget, IFastBridgeV2, IFastBridgeV2Errors {\n using BridgeTransactionV2Lib for bytes;\n using SafeERC20 for IERC20;\n\n /// @notice Address reserved for native gas token (ETH on Ethereum and most L2s, AVAX on Avalanche, etc)\n address public constant NATIVE_GAS_TOKEN = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Delay for a transaction after which it could be permisionlessly refunded\n uint256 public constant REFUND_DELAY = 7 days;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n /// @notice Maximum length of accepted zapData\n uint256 public constant MAX_ZAP_DATA_LENGTH = 2 ** 16 - 1;\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeTxDetails) public bridgeTxDetails;\n /// @notice Relay details on destination chain\n mapping(bytes32 =\u003e BridgeRelay) public bridgeRelayDetails;\n /// @notice Unique bridge nonces tracked per originSender\n mapping(address =\u003e uint256) public senderNonces;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Replaced by senderNonces\n uint256 public immutable nonce = 0;\n /// @notice the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n bridge({\n params: params,\n paramsV2: BridgeParamsV2({\n quoteRelayer: address(0),\n quoteExclusivitySeconds: 0,\n quoteId: bytes(\"\"),\n zapNative: 0,\n zapData: bytes(\"\")\n })\n });\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes calldata request) external payable {\n // relay override will validate the request\n relay({request: request, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes calldata request, bytes32 destTxHash) external {\n request.validateV2();\n prove({transactionId: keccak256(request), destTxHash: destTxHash, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridgeV2\n function claim(bytes calldata request) external {\n // claim override will validate the request\n claim({request: request, to: address(0)});\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Aggregate the read operations from the same storage slot\n address disputedRelayer = $.proofRelayer;\n BridgeStatus status = $.status;\n uint56 proofBlockTimestamp = $.proofBlockTimestamp;\n // Can only dispute a RELAYER_PROVED transaction within the dispute period\n if (status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(proofBlockTimestamp) \u003e DISPUTE_PERIOD) {\n revert DisputePeriodPassed();\n }\n // Update status to REQUESTED and delete the disputed proof details\n // Note: these are storage writes\n $.status = BridgeStatus.REQUESTED;\n $.proofRelayer = address(0);\n $.proofBlockTimestamp = 0;\n\n emit BridgeProofDisputed(transactionId, disputedRelayer);\n }\n\n /// @inheritdoc IFastBridge\n function refund(bytes calldata request) external {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Can only refund a REQUESTED transaction after its deadline expires\n if ($.status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n uint256 deadline = request.deadline();\n // Permissionless refund is only allowed after REFUND_DELAY on top of the deadline\n if (!hasRole(REFUNDER_ROLE, msg.sender)) deadline += REFUND_DELAY;\n if (block.timestamp \u003c= deadline) revert DeadlineNotExceeded();\n // Update status to REFUNDED and return the full amount (collateral + protocol fees) to the original sender.\n // The protocol fees are only updated when the transaction is claimed, so we don't need to update them here.\n // Note: this is a storage write\n $.status = BridgeStatus.REFUNDED;\n\n address to = request.originSender();\n address token = request.originToken();\n uint256 amount = request.originAmount() + request.originFeeAmount();\n // Emit the event before any external calls\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n // Complete the user refund as the last transaction action\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(to), amount);\n } else {\n IERC20(token).safeTransfer(to, amount);\n }\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // The correct relayer can only claim a RELAYER_PROVED transaction after the dispute period\n if ($.status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if ($.proofRelayer != relayer) revert SenderIncorrect();\n return _timeSince($.proofBlockTimestamp) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n /// @dev This method is added to achieve backwards compatibility with decoding requests into V1 structs:\n /// - `zapNative` is partially reported as a zero/non-zero flag\n /// - `zapData` is ignored\n /// In order to process all kinds of requests use getBridgeTransactionV2 instead.\n function getBridgeTransaction(bytes calldata request) external view returns (BridgeTransaction memory) {\n // Try decoding into V2 struct first. This will revert if V1 struct is passed\n try this.getBridgeTransactionV2(request) returns (BridgeTransactionV2 memory txV2) {\n // Note: we entirely ignore the zapData field, as it was not present in V1\n return BridgeTransaction({\n originChainId: txV2.originChainId,\n destChainId: txV2.destChainId,\n originSender: txV2.originSender,\n destRecipient: txV2.destRecipient,\n originToken: txV2.originToken,\n destToken: txV2.destToken,\n originAmount: txV2.originAmount,\n destAmount: txV2.destAmount,\n originFeeAmount: txV2.originFeeAmount,\n sendChainGas: txV2.zapNative != 0,\n deadline: txV2.deadline,\n nonce: txV2.nonce\n });\n } catch {\n // Fallback to V1 struct\n return abi.decode(request, (BridgeTransaction));\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function getBridgeTransactionV2(bytes calldata request) external pure returns (BridgeTransactionV2 memory) {\n request.validateV2();\n return BridgeTransactionV2Lib.decodeV2(request);\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) public payable {\n int256 exclusivityEndTime = 0;\n // if relayer exclusivity is not intended for this bridge, set exclusivityEndTime to static zero\n // otherwise, set exclusivity to expire at the current block ts offset by quoteExclusivitySeconds\n if (paramsV2.quoteRelayer != address(0)) {\n exclusivityEndTime = int256(block.timestamp) + paramsV2.quoteExclusivitySeconds;\n }\n _validateBridgeParams(params, paramsV2, exclusivityEndTime);\n\n // transfer tokens to bridge contract\n /// @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _takeBridgedUserAsset(params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) {\n originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n }\n\n // set status to requested\n bytes memory request = BridgeTransactionV2Lib.encodeV2(\n BridgeTransactionV2({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n deadline: params.deadline,\n nonce: senderNonces[params.sender]++, // increment nonce on every bridge\n exclusivityRelayer: paramsV2.quoteRelayer,\n // We checked exclusivityEndTime to be in range [0 .. params.deadline] above, so can safely cast\n exclusivityEndTime: uint256(exclusivityEndTime),\n zapNative: paramsV2.zapNative,\n zapData: paramsV2.zapData\n })\n );\n bytes32 transactionId = keccak256(request);\n // Note: the tx status will be updated throughout the tx lifecycle, while destChainId is set once here\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n bridgeTxDetails[transactionId].destChainId = params.dstChainId;\n\n emit BridgeRequested({\n transactionId: transactionId,\n sender: params.sender,\n request: request,\n destChainId: params.dstChainId,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n sendChainGas: paramsV2.zapNative != 0\n });\n emit BridgeQuoteDetails(transactionId, paramsV2.quoteId);\n }\n\n /// @inheritdoc IFastBridgeV2\n function relay(bytes calldata request, address relayer) public payable {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n _validateRelayParams(request, transactionId, relayer);\n // mark bridge transaction as relayed\n bridgeRelayDetails[transactionId] =\n BridgeRelay({blockNumber: uint48(block.number), blockTimestamp: uint48(block.timestamp), relayer: relayer});\n\n // transfer tokens to recipient on destination chain and trigger Zap if requested\n address to = request.destRecipient();\n address token = request.destToken();\n uint256 amount = request.destAmount();\n uint256 zapNative = request.zapNative();\n\n // Emit the event before any external calls\n emit BridgeRelayed({\n transactionId: transactionId,\n relayer: relayer,\n to: to,\n originChainId: request.originChainId(),\n originToken: request.originToken(),\n destToken: token,\n originAmount: request.originAmount(),\n destAmount: amount,\n chainGasAmount: zapNative\n });\n\n // All state changes have been done at this point, can proceed to the external calls.\n // This follows the checks-effects-interactions pattern to mitigate potential reentrancy attacks.\n if (token == NATIVE_GAS_TOKEN) {\n // For the native gas token, additional zapNative is not allowed\n if (zapNative != 0) revert ZapNativeNotSupported();\n // Check that the correct msg.value was sent\n if (msg.value != amount) revert MsgValueIncorrect();\n // Don't do a native transfer yet: we will handle it alongside the Zap below\n } else {\n // For ERC20s, we check that the correct msg.value was sent\n if (msg.value != zapNative) revert MsgValueIncorrect();\n // We need to transfer the tokens from the Relayer to the recipient first before performing an\n // optional post-transfer Zap.\n IERC20(token).safeTransferFrom(msg.sender, to, amount);\n }\n // At this point we have done:\n // - Transferred the requested amount of ERC20 tokens to the recipient.\n // At this point we have confirmed:\n // - For ERC20s: msg.value matches the requested zapNative amount.\n // - For the native gas token: msg.value matches the requested destAmount.\n // Remaining optional things to do:\n // - Forward the full msg.value to the recipient (if non-zero).\n // - Trigger a Zap (if zapData is present).\n bytes calldata zapData = request.zapData();\n if (zapData.length != 0) {\n // Zap Data is present: Zap has been requested by the recipient. Trigger it forwarding the full msg.value.\n\n // Note: if token has a fee on transfers, the recipient will have received less than `amount`.\n // This is a very niche edge case and should be handled by the recipient contract.\n _triggerZapWithChecks({recipient: to, token: token, amount: amount, zapData: zapData});\n } else if (msg.value != 0) {\n // Zap Data is missing, but msg.value was sent. This could happen in two different cases:\n // - Relay with the native gas token is happening.\n // - Relay with ERC20 is happening, with a `zapNative \u003e 0` request.\n // In both cases, we need to transfer the full msg.value to the recipient.\n Address.sendValue(payable(to), msg.value);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) public onlyRole(RELAYER_ROLE) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n\n // Can only prove a REQUESTED transaction\n if ($.status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n // Update status to RELAYER_PROVED and store the proof details\n // Note: these are storage writes\n $.status = BridgeStatus.RELAYER_PROVED;\n $.proofBlockTimestamp = uint56(block.timestamp);\n $.proofRelayer = relayer;\n\n emit BridgeProofProvided(transactionId, relayer, destTxHash);\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes calldata request, address to) public {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Aggregate the read operations from the same storage slot\n address proofRelayer = $.proofRelayer;\n BridgeStatus status = $.status;\n uint56 proofBlockTimestamp = $.proofBlockTimestamp;\n\n // Can only claim a RELAYER_PROVED transaction after the dispute period\n if (status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(proofBlockTimestamp) \u003c= DISPUTE_PERIOD) {\n revert DisputePeriodNotPassed();\n }\n\n if (to == address(0)) {\n // Anyone could claim the funds to the proven relayer on their behalf\n to = proofRelayer;\n } else if (proofRelayer != msg.sender) {\n // Only the proven relayer could specify an address to claim the funds to\n revert SenderIncorrect();\n }\n\n // Update status to RELAYER_CLAIMED and transfer the origin collateral to the specified claim address\n // Note: this is a storage write\n $.status = BridgeStatus.RELAYER_CLAIMED;\n\n address token = request.originToken();\n uint256 amount = request.originAmount();\n // Update protocol fees if origin fee amount exists\n uint256 originFeeAmount = request.originFeeAmount();\n if (originFeeAmount \u003e 0) protocolFees[token] += originFeeAmount;\n // Emit the event before any external calls\n emit BridgeDepositClaimed(transactionId, proofRelayer, to, token, amount);\n // Complete the relayer claim as the last transaction action\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(to), amount);\n } else {\n IERC20(token).safeTransfer(to, amount);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeStatuses(bytes32 transactionId) public view returns (BridgeStatus status) {\n return bridgeTxDetails[transactionId].status;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeProofs(bytes32 transactionId) public view returns (uint96 timestamp, address relayer) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n\n timestamp = $.proofBlockTimestamp;\n relayer = $.proofRelayer;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeRelays(bytes32 transactionId) public view returns (bool) {\n // has this transactionId been relayed?\n return bridgeRelayDetails[transactionId].relayer != address(0);\n }\n\n /// @notice Takes the bridged asset from the user into FastBridgeV2 custody. It will be later\n /// claimed by the relayer who completed the relay on destination chain, or refunded back to the user,\n /// should no one complete the relay.\n function _takeBridgedUserAsset(address token, uint256 amount) internal returns (uint256 amountTaken) {\n if (token == NATIVE_GAS_TOKEN) {\n // For the native gas token, we just need to check that the supplied msg.value is correct.\n // Supplied `msg.value` is already in FastBridgeV2 custody.\n if (amount != msg.value) revert MsgValueIncorrect();\n amountTaken = msg.value;\n } else {\n // For ERC20s, token is explicitly transferred from the user to FastBridgeV2.\n // We don't allow non-zero `msg.value` to avoid extra funds from being stuck in FastBridgeV2.\n if (msg.value != 0) revert MsgValueIncorrect();\n // Throw an explicit error if the provided token address is not a contract\n if (token.code.length == 0) revert TokenNotContract();\n amountTaken = IERC20(token).balanceOf(address(this));\n IERC20(token).safeTransferFrom(msg.sender, address(this), amount);\n // Use the balance difference as the amount taken in case of fee on transfer tokens.\n amountTaken = IERC20(token).balanceOf(address(this)) - amountTaken;\n }\n }\n\n /// @notice Calls the Recipient's hook function with the specified zapData and performs\n /// all the necessary checks for the returned value.\n function _triggerZapWithChecks(address recipient, address token, uint256 amount, bytes calldata zapData) internal {\n // This will bubble any revert messages from the hook function\n bytes memory returnData = Address.functionCallWithValue({\n target: recipient,\n data: abi.encodeCall(IZapRecipient.zap, (token, amount, zapData)),\n // Note: see `relay()` for reasoning behind passing msg.value\n value: msg.value\n });\n // Explicit revert if no return data at all\n if (returnData.length == 0) revert RecipientNoReturnValue();\n // Check that exactly a single return value was returned\n if (returnData.length != 32) revert RecipientIncorrectReturnValue();\n // Return value should be abi-encoded hook function selector\n if (bytes32(returnData) != bytes32(IZapRecipient.zap.selector)) {\n revert RecipientIncorrectReturnValue();\n }\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint56(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint56).max but\n /// proof.timestamp \u003c type(uint56).max via unchecked statement\n /// @param proofBlockTimestamp The bridge proof block timestamp\n /// @return delta Time delta since proof submitted\n function _timeSince(uint56 proofBlockTimestamp) internal view returns (uint256 delta) {\n unchecked {\n delta = uint56(block.timestamp) - proofBlockTimestamp;\n }\n }\n\n /// @notice Performs all the necessary checks for a bridge to happen.\n /// @dev There's no good way to refactor this function to reduce cyclomatic complexity due to\n /// the number of checks that need to be performed, so we skip the code-complexity rule here.\n // solhint-disable-next-line code-complexity\n function _validateBridgeParams(\n BridgeParams memory params,\n BridgeParamsV2 memory paramsV2,\n int256 exclusivityEndTime\n )\n internal\n view\n {\n // Check V1 (legacy) params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.sender == address(0) || params.to == address(0)) revert ZeroAddress();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n // Check V2 params\n if (paramsV2.zapData.length \u003e MAX_ZAP_DATA_LENGTH) revert ZapDataLengthAboveMax();\n if (paramsV2.zapNative != 0 \u0026\u0026 params.destToken == NATIVE_GAS_TOKEN) {\n revert ZapNativeNotSupported();\n }\n // exclusivityEndTime must be in range [0 .. params.deadline]\n if (exclusivityEndTime \u003c 0 || exclusivityEndTime \u003e int256(params.deadline)) {\n revert ExclusivityParamsIncorrect();\n }\n }\n\n /// @notice Performs all the necessary checks for a relay to happen.\n function _validateRelayParams(bytes calldata request, bytes32 transactionId, address relayer) internal view {\n if (relayer == address(0)) revert ZeroAddress();\n // Check if the transaction has already been relayed\n if (bridgeRelays(transactionId)) revert TransactionRelayed();\n if (request.destChainId() != block.chainid) revert ChainIncorrect();\n // Check the deadline for relay to happen\n if (block.timestamp \u003e request.deadline()) revert DeadlineExceeded();\n // Check the exclusivity period, if it is still ongoing\n address exclRelayer = request.exclusivityRelayer();\n if (exclRelayer != address(0) \u0026\u0026 exclRelayer != relayer \u0026\u0026 block.timestamp \u003c= request.exclusivityEndTime()) {\n revert ExclusivityPeriodNotPassed();\n }\n }\n}\n","language":"Solidity","languageVersion":"0.8.24","compilerVersion":"0.8.24","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"","srcMapRuntime":"","abiDefinition":[{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"bytes","name":"zapData","type":"bytes"}],"name":"zap","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"payable","type":"function"}],"userDoc":{"kind":"user","methods":{},"version":1},"developerDoc":{"kind":"dev","methods":{},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"zapData\",\"type\":\"bytes\"}],\"name\":\"zap\",\"outputs\":[{\"internalType\":\"bytes4\",\"name\":\"\",\"type\":\"bytes4\"}],\"stateMutability\":\"payable\",\"type\":\"function\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeV2.sol\":\"IZapRecipient\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeV2.sol\":{\"keccak256\":\"0x5069b55ca07f21bfe30b2a43c18a18318c8af9c181b2dcb07c290825efd70f34\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://273dc020a49d08e50126bbea0d7f783f79d08c702f2fdbc560618d24af308acc\",\"dweb:/ipfs/QmXJ2UVzFc8EPB74RT4CXQPC4xw66jt4T13poyfyd3UERh\"]}},\"version\":1}"},"hashes":{"zap(address,uint256,bytes)":"e85e13dd"}},"solidity/FastBridgeV2.sol:MulticallTarget":{"code":"0x","runtime-code":"0x","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.24 ^0.8.20 ^0.8.4;\n\n// contracts/interfaces/IAdmin.sol\n\ninterface IAdmin {\n // ============ Events ============\n\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n event ChainGasAmountUpdated(uint256 oldChainGasAmount, uint256 newChainGasAmount);\n\n // ============ Methods ============\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n\n function setChainGasAmount(uint256 newChainGasAmount) external;\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IFastBridgeV2Errors.sol\n\ninterface IFastBridgeV2Errors {\n error AmountIncorrect();\n error ChainIncorrect();\n error ExclusivityParamsIncorrect();\n error MsgValueIncorrect();\n error SenderIncorrect();\n error StatusIncorrect();\n error TokenNotContract();\n error ZapDataLengthAboveMax();\n error ZapNativeNotSupported();\n error ZeroAddress();\n\n error RecipientIncorrectReturnValue();\n error RecipientNoReturnValue();\n\n error DeadlineExceeded();\n error DeadlineNotExceeded();\n error DeadlineTooShort();\n error DisputePeriodNotPassed();\n error DisputePeriodPassed();\n error ExclusivityPeriodNotPassed();\n\n error TransactionRelayed();\n}\n\n// contracts/interfaces/IMulticallTarget.sol\n\n/// @notice Interface for a contract that can be called multiple times by the same caller. Inspired by MulticallV3:\n/// https://github.com/mds1/multicall/blob/master/src/Multicall3.sol\ninterface IMulticallTarget {\n struct Result {\n bool success;\n bytes returnData;\n }\n\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external;\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results);\n}\n\n// contracts/interfaces/IZapRecipient.sol\n\ninterface IZapRecipient {\n function zap(address token, uint256 amount, bytes memory zapData) external payable returns (bytes4);\n}\n\n// contracts/libs/Errors.sol\n\nerror DeadlineExceeded();\nerror DeadlineNotExceeded();\nerror DeadlineTooShort();\nerror InsufficientOutputAmount();\n\nerror MsgValueIncorrect();\nerror PoolNotFound();\nerror TokenAddressMismatch();\nerror TokenNotContract();\nerror TokenNotETH();\nerror TokensIdentical();\n\nerror ChainIncorrect();\nerror AmountIncorrect();\nerror ZeroAddress();\n\nerror DisputePeriodNotPassed();\nerror DisputePeriodPassed();\nerror SenderIncorrect();\nerror StatusIncorrect();\nerror TransactionIdIncorrect();\nerror TransactionRelayed();\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// contracts/interfaces/IFastBridgeV2.sol\n\ninterface IFastBridgeV2 is IFastBridge {\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n struct BridgeTxDetails {\n BridgeStatus status;\n uint32 destChainId;\n uint56 proofBlockTimestamp;\n address proofRelayer;\n }\n\n struct BridgeRelay {\n uint48 blockNumber;\n uint48 blockTimestamp;\n address relayer;\n }\n\n /// @notice New params introduced in the FastBridgeV2.\n /// We are passing fields from the older BridgeParams struct outside of this struct\n /// for backwards compatibility.\n /// Note: quoteRelayer and quoteExclusivitySeconds are either both zero (indicating no exclusivity)\n /// or both non-zero (indicating exclusivity for the given period).\n /// Note: zapNative \u003e 0 can NOT be used with destToken = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE (native token)\n /// @param quoteRelayer Relayer that provided the quote for the transaction\n /// @param quoteExclusivitySeconds Period of time the quote relayer is guaranteed exclusivity after user's deposit\n /// @param quoteId Unique quote identifier used for tracking the quote\n /// @param zapNative ETH value to send to the recipient (if any)\n /// @param zapData Parameters for the Zap to the destination recipient (if any)\n struct BridgeParamsV2 {\n address quoteRelayer;\n int256 quoteExclusivitySeconds;\n bytes quoteId;\n uint256 zapNative;\n bytes zapData;\n }\n\n /// @notice Updated bridge transaction struct to include parameters introduced in FastBridgeV2.\n /// Note: only `exclusivityRelayer` can fill such a transaction until `exclusivityEndTime`.\n struct BridgeTransactionV2 {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n // Note: sendChainGas flag from V1 is deprecated\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n address exclusivityRelayer;\n uint256 exclusivityEndTime;\n uint256 zapNative; // ETH value to send to the recipient (if any)\n bytes zapData; // data to pass for the Zap action (if any)\n }\n\n event BridgeQuoteDetails(bytes32 indexed transactionId, bytes quoteId);\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability\n /// to provide temporary exclusivity fill rights for the quote relayer.\n /// @param params The parameters required to bridge\n /// @param paramsV2 The parameters for exclusivity fill rights (optional, can be left empty)\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function relay(bytes memory request, address relayer) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param transactionId The transaction id associated with the encoded bridge transaction to prove\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital.\n /// @notice Can only send funds to the relayer address on the proof.\n /// @param request The encoded bridge transaction to claim on origin chain\n function claim(bytes memory request) external;\n /// @notice Checks if a transaction has been relayed\n /// @param transactionId The ID of the transaction to check\n /// @return True if the transaction has been relayed, false otherwise\n function bridgeRelays(bytes32 transactionId) external view returns (bool);\n\n /// @notice Returns the status of a bridge transaction\n /// @param transactionId The ID of the bridge transaction\n /// @return BridgeStatus Status of the bridge transaction\n function bridgeStatuses(bytes32 transactionId) external view returns (BridgeStatus);\n\n /// @notice Returns the timestamp and relayer of a bridge proof\n /// @param transactionId The ID of the bridge transaction\n /// @return timestamp The timestamp of the bridge proof\n /// @return relayer The relayer address of the bridge proof\n function bridgeProofs(bytes32 transactionId) external view returns (uint96 timestamp, address relayer);\n\n /// @notice Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\n /// @param request The bridge request to decode\n function getBridgeTransactionV2(bytes memory request) external view returns (BridgeTransactionV2 memory);\n}\n\n// contracts/utils/MulticallTarget.sol\n\n// solhint-disable avoid-low-level-calls\n/// @notice Template for a contract that supports batched calls (preserving the msg.sender).\n/// Only calls with zero msg.value could be batched.\nabstract contract MulticallTarget is IMulticallTarget {\n error MulticallTarget__UndeterminedRevert();\n\n /// @notice Perform a batched call to this contract, preserving the msg.sender.\n /// The return data from each call is discarded.\n /// @dev The method is non-payable, so only calls with `msg.value == 0` could be batched.\n /// It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag.\n /// Otherwise, the whole batch call will be reverted with the original revert reason.\n /// @param data List of abi-encoded calldata for the calls to perform.\n /// @param ignoreReverts Whether to ignore the revert errors from the calls.\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external {\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\n if (!success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(result);\n }\n }\n }\n\n /// @notice Perform a batched call to this contract, preserving the msg.sender.\n /// The return data from each call is preserved.\n /// @dev The method is non-payable, so only calls with `msg.value == 0` could be batched.\n /// It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag.\n /// Otherwise, the whole batch call will be reverted with the original revert reason.\n /// @param data List of abi-encoded calldata for the calls to perform.\n /// @param ignoreReverts Whether to ignore the revert errors from the calls.\n /// @return results List of results from the calls: `(success, returnData)`.\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results)\n {\n results = new Result[](data.length);\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (results[i].success, results[i].returnData) = address(this).delegatecall(data[i]);\n if (!results[i].success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(results[i].returnData);\n }\n }\n }\n\n /// @dev Bubbles the revert message from the underlying call.\n /// Note: preserves the same custom error or revert string, if one was used.\n /// Source: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v5.0.2/contracts/utils/Address.sol#L143-L158\n function _bubbleRevert(bytes memory returnData) internal pure {\n // Look for revert reason and bubble it up if present\n if (returnData.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n // solhint-disable-next-line no-inline-assembly\n assembly {\n let returndata_size := mload(returnData)\n revert(add(32, returnData), returndata_size)\n }\n } else {\n revert MulticallTarget__UndeterminedRevert();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// contracts/libs/BridgeTransactionV2.sol\n\n// solhint-disable no-inline-assembly\nlibrary BridgeTransactionV2Lib {\n uint16 internal constant VERSION = 2;\n\n // Offsets of the fields in the packed BridgeTransactionV2 struct\n // uint16 version [000 .. 002)\n // uint32 originChainId [002 .. 006)\n // uint32 destChainId [006 .. 010)\n // address originSender [010 .. 030)\n // address destRecipient [030 .. 050)\n // address originToken [050 .. 070)\n // address destToken [070 .. 090)\n // uint256 originAmount [090 .. 122)\n // uint256 destAmount [122 .. 154)\n // uint256 originFeeAmount [154 .. 186)\n // uint256 deadline [186 .. 218)\n // uint256 nonce [218 .. 250)\n // address exclusivityRelayer [250 .. 270)\n // uint256 exclusivityEndTime [270 .. 302)\n // uint256 zapNative [302 .. 334)\n // bytes zapData [334 .. ***)\n\n // forgefmt: disable-start\n uint256 private constant OFFSET_ORIGIN_CHAIN_ID = 2;\n uint256 private constant OFFSET_DEST_CHAIN_ID = 6;\n uint256 private constant OFFSET_ORIGIN_SENDER = 10;\n uint256 private constant OFFSET_DEST_RECIPIENT = 30;\n uint256 private constant OFFSET_ORIGIN_TOKEN = 50;\n uint256 private constant OFFSET_DEST_TOKEN = 70;\n uint256 private constant OFFSET_ORIGIN_AMOUNT = 90;\n uint256 private constant OFFSET_DEST_AMOUNT = 122;\n uint256 private constant OFFSET_ORIGIN_FEE_AMOUNT = 154;\n uint256 private constant OFFSET_DEADLINE = 186;\n uint256 private constant OFFSET_NONCE = 218;\n uint256 private constant OFFSET_EXCLUSIVITY_RELAYER = 250;\n uint256 private constant OFFSET_EXCLUSIVITY_END_TIME = 270;\n uint256 private constant OFFSET_ZAP_NATIVE = 302;\n uint256 private constant OFFSET_ZAP_DATA = 334;\n // forgefmt: disable-end\n\n error BridgeTransactionV2__InvalidEncodedTx();\n error BridgeTransactionV2__UnsupportedVersion(uint16 version);\n\n /// @notice Validates the encoded transaction to be a tightly packed encoded payload for BridgeTransactionV2.\n /// @dev Checks the minimum length and the version, use this function before decoding any of the fields.\n function validateV2(bytes calldata encodedTx) internal pure {\n // Check the minimum length: must at least include all static fields.\n if (encodedTx.length \u003c OFFSET_ZAP_DATA) revert BridgeTransactionV2__InvalidEncodedTx();\n // Once we validated the length, we can be sure that the version field is present.\n uint16 version_ = version(encodedTx);\n if (version_ != VERSION) revert BridgeTransactionV2__UnsupportedVersion(version_);\n }\n\n /// @notice Encodes the BridgeTransactionV2 struct by tightly packing the fields.\n /// @dev `abi.decode` will not work as a result of the tightly packed fields. Use `decodeV2` to decode instead.\n function encodeV2(IFastBridgeV2.BridgeTransactionV2 memory bridgeTx) internal pure returns (bytes memory) {\n // We split the encoding into two parts to avoid stack-too-deep error\n bytes memory firstPart = abi.encodePacked(\n VERSION,\n bridgeTx.originChainId,\n bridgeTx.destChainId,\n bridgeTx.originSender,\n bridgeTx.destRecipient,\n bridgeTx.originToken,\n bridgeTx.destToken,\n bridgeTx.originAmount\n );\n return abi.encodePacked(\n firstPart,\n bridgeTx.destAmount,\n bridgeTx.originFeeAmount,\n // Note: we skip the deprecated `sendChainGas` flag, which was present in BridgeTransaction V1\n bridgeTx.deadline,\n bridgeTx.nonce,\n // New V2 fields: exclusivity\n bridgeTx.exclusivityRelayer,\n bridgeTx.exclusivityEndTime,\n // New V2 fields: Zap\n bridgeTx.zapNative,\n bridgeTx.zapData\n );\n }\n\n /// @notice Decodes the BridgeTransactionV2 struct from the encoded transaction.\n /// @dev Encoded BridgeTransactionV2 struct must be tightly packed.\n /// Use `validateV2` before decoding to ensure the encoded transaction is valid.\n function decodeV2(bytes calldata encodedTx)\n internal\n pure\n returns (IFastBridgeV2.BridgeTransactionV2 memory bridgeTx)\n {\n bridgeTx.originChainId = originChainId(encodedTx);\n bridgeTx.destChainId = destChainId(encodedTx);\n bridgeTx.originSender = originSender(encodedTx);\n bridgeTx.destRecipient = destRecipient(encodedTx);\n bridgeTx.originToken = originToken(encodedTx);\n bridgeTx.destToken = destToken(encodedTx);\n bridgeTx.originAmount = originAmount(encodedTx);\n bridgeTx.destAmount = destAmount(encodedTx);\n bridgeTx.originFeeAmount = originFeeAmount(encodedTx);\n bridgeTx.deadline = deadline(encodedTx);\n bridgeTx.nonce = nonce(encodedTx);\n bridgeTx.exclusivityRelayer = exclusivityRelayer(encodedTx);\n bridgeTx.exclusivityEndTime = exclusivityEndTime(encodedTx);\n bridgeTx.zapNative = zapNative(encodedTx);\n bridgeTx.zapData = zapData(encodedTx);\n }\n\n /// @notice Extracts the version from the encoded transaction.\n function version(bytes calldata encodedTx) internal pure returns (uint16 version_) {\n // Load 32 bytes from the start and shift it 240 bits to the right to get the highest 16 bits.\n assembly {\n version_ := shr(240, calldataload(encodedTx.offset))\n }\n }\n\n /// @notice Extracts the origin chain ID from the encoded transaction.\n function originChainId(bytes calldata encodedTx) internal pure returns (uint32 originChainId_) {\n // Load 32 bytes from the offset and shift it 224 bits to the right to get the highest 32 bits.\n assembly {\n originChainId_ := shr(224, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_CHAIN_ID)))\n }\n }\n\n /// @notice Extracts the destination chain ID from the encoded transaction.\n function destChainId(bytes calldata encodedTx) internal pure returns (uint32 destChainId_) {\n // Load 32 bytes from the offset and shift it 224 bits to the right to get the highest 32 bits.\n assembly {\n destChainId_ := shr(224, calldataload(add(encodedTx.offset, OFFSET_DEST_CHAIN_ID)))\n }\n }\n\n /// @notice Extracts the origin sender from the encoded transaction.\n function originSender(bytes calldata encodedTx) internal pure returns (address originSender_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n originSender_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_SENDER)))\n }\n }\n\n /// @notice Extracts the destination recipient from the encoded transaction.\n function destRecipient(bytes calldata encodedTx) internal pure returns (address destRecipient_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n destRecipient_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_DEST_RECIPIENT)))\n }\n }\n\n /// @notice Extracts the origin token from the encoded transaction.\n function originToken(bytes calldata encodedTx) internal pure returns (address originToken_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n originToken_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_TOKEN)))\n }\n }\n\n /// @notice Extracts the destination token from the encoded transaction.\n function destToken(bytes calldata encodedTx) internal pure returns (address destToken_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n destToken_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_DEST_TOKEN)))\n }\n }\n\n /// @notice Extracts the origin amount from the encoded transaction.\n function originAmount(bytes calldata encodedTx) internal pure returns (uint256 originAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n originAmount_ := calldataload(add(encodedTx.offset, OFFSET_ORIGIN_AMOUNT))\n }\n }\n\n /// @notice Extracts the destination amount from the encoded transaction.\n function destAmount(bytes calldata encodedTx) internal pure returns (uint256 destAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n destAmount_ := calldataload(add(encodedTx.offset, OFFSET_DEST_AMOUNT))\n }\n }\n\n /// @notice Extracts the origin fee amount from the encoded transaction.\n function originFeeAmount(bytes calldata encodedTx) internal pure returns (uint256 originFeeAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n originFeeAmount_ := calldataload(add(encodedTx.offset, OFFSET_ORIGIN_FEE_AMOUNT))\n }\n }\n\n /// @notice Extracts the deadline from the encoded transaction.\n function deadline(bytes calldata encodedTx) internal pure returns (uint256 deadline_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n deadline_ := calldataload(add(encodedTx.offset, OFFSET_DEADLINE))\n }\n }\n\n /// @notice Extracts the nonce from the encoded transaction.\n function nonce(bytes calldata encodedTx) internal pure returns (uint256 nonce_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n nonce_ := calldataload(add(encodedTx.offset, OFFSET_NONCE))\n }\n }\n\n /// @notice Extracts the exclusivity relayer from the encoded transaction.\n function exclusivityRelayer(bytes calldata encodedTx) internal pure returns (address exclusivityRelayer_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n exclusivityRelayer_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_EXCLUSIVITY_RELAYER)))\n }\n }\n\n /// @notice Extracts the exclusivity end time from the encoded transaction.\n function exclusivityEndTime(bytes calldata encodedTx) internal pure returns (uint256 exclusivityEndTime_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n exclusivityEndTime_ := calldataload(add(encodedTx.offset, OFFSET_EXCLUSIVITY_END_TIME))\n }\n }\n\n /// @notice Extracts the Zap's native value from the encoded transaction.\n function zapNative(bytes calldata encodedTx) internal pure returns (uint256 zapNative_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n zapNative_ := calldataload(add(encodedTx.offset, OFFSET_ZAP_NATIVE))\n }\n }\n\n /// @notice Extracts the Zap's data from the encoded transaction.\n function zapData(bytes calldata encodedTx) internal pure returns (bytes calldata zapData_) {\n zapData_ = encodedTx[OFFSET_ZAP_DATA:];\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// contracts/libs/UniversalToken.sol\n\nlibrary UniversalTokenLib {\n using SafeERC20 for IERC20;\n\n address internal constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Transfers tokens to the given account. Reverts if transfer is not successful.\n /// @dev This might trigger fallback, if ETH is transferred to the contract.\n /// Make sure this can not lead to reentrancy attacks.\n function universalTransfer(address token, address to, uint256 value) internal {\n // Don't do anything, if need to send tokens to this address\n if (to == address(this)) return;\n // Don't do anything, if trying to send zero value\n if (value == 0) return;\n if (token == ETH_ADDRESS) {\n /// @dev Note: this can potentially lead to executing code in `to`.\n // solhint-disable-next-line avoid-low-level-calls\n (bool success,) = to.call{value: value}(\"\");\n require(success, \"ETH transfer failed\");\n } else {\n IERC20(token).safeTransfer(to, value);\n }\n }\n\n /// @notice Issues an infinite allowance to the spender, if the current allowance is insufficient\n /// to spend the given amount.\n function universalApproveInfinity(address token, address spender, uint256 amountToSpend) internal {\n // ETH Chad doesn't require your approval\n if (token == ETH_ADDRESS) return;\n // No-op if allowance is already sufficient\n uint256 allowance = IERC20(token).allowance(address(this), spender);\n if (allowance \u003e= amountToSpend) return;\n // Otherwise, reset approval to 0 and set to max allowance\n if (allowance \u003e 0) IERC20(token).safeDecreaseAllowance(spender, allowance);\n IERC20(token).safeIncreaseAllowance(spender, type(uint256).max);\n }\n\n /// @notice Returns the balance of the given token (or native ETH) for the given account.\n function universalBalanceOf(address token, address account) internal view returns (uint256) {\n if (token == ETH_ADDRESS) {\n return account.balance;\n } else {\n return IERC20(token).balanceOf(account);\n }\n }\n\n /// @dev Checks that token is a contract and not ETH_ADDRESS.\n function assertIsContract(address token) internal view {\n // Check that ETH_ADDRESS was not used (in case this is a predeploy on any of the chains)\n if (token == UniversalTokenLib.ETH_ADDRESS) revert TokenNotContract();\n // Check that token is not an EOA\n if (token.code.length == 0) revert TokenNotContract();\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/Admin.sol\n\ncontract Admin is IAdmin, AccessControlEnumerable {\n using UniversalTokenLib for address;\n\n bytes32 public constant RELAYER_ROLE = keccak256(\"RELAYER_ROLE\");\n bytes32 public constant REFUNDER_ROLE = keccak256(\"REFUNDER_ROLE\");\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n uint256 public constant FEE_BPS = 1e6;\n uint256 public constant FEE_RATE_MAX = 0.01e6; // max 1% on origin amount\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Chain gas amount to forward as rebate if requested\n uint256 public chainGasAmount;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n }\n\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n require(newFeeRate \u003c= FEE_RATE_MAX, \"newFeeRate \u003e max\");\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n token.universalTransfer(recipient, feeAmount);\n emit FeesSwept(token, recipient, feeAmount);\n }\n\n function setChainGasAmount(uint256 newChainGasAmount) external onlyRole(GOVERNOR_ROLE) {\n uint256 oldChainGasAmount = chainGasAmount;\n chainGasAmount = newChainGasAmount;\n emit ChainGasAmountUpdated(oldChainGasAmount, newChainGasAmount);\n }\n}\n\n// contracts/FastBridgeV2.sol\n\n/// @notice FastBridgeV2 is a contract for bridging tokens across chains.\ncontract FastBridgeV2 is Admin, MulticallTarget, IFastBridgeV2, IFastBridgeV2Errors {\n using BridgeTransactionV2Lib for bytes;\n using SafeERC20 for IERC20;\n\n /// @notice Address reserved for native gas token (ETH on Ethereum and most L2s, AVAX on Avalanche, etc)\n address public constant NATIVE_GAS_TOKEN = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Delay for a transaction after which it could be permisionlessly refunded\n uint256 public constant REFUND_DELAY = 7 days;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n /// @notice Maximum length of accepted zapData\n uint256 public constant MAX_ZAP_DATA_LENGTH = 2 ** 16 - 1;\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeTxDetails) public bridgeTxDetails;\n /// @notice Relay details on destination chain\n mapping(bytes32 =\u003e BridgeRelay) public bridgeRelayDetails;\n /// @notice Unique bridge nonces tracked per originSender\n mapping(address =\u003e uint256) public senderNonces;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Replaced by senderNonces\n uint256 public immutable nonce = 0;\n /// @notice the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n bridge({\n params: params,\n paramsV2: BridgeParamsV2({\n quoteRelayer: address(0),\n quoteExclusivitySeconds: 0,\n quoteId: bytes(\"\"),\n zapNative: 0,\n zapData: bytes(\"\")\n })\n });\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes calldata request) external payable {\n // relay override will validate the request\n relay({request: request, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes calldata request, bytes32 destTxHash) external {\n request.validateV2();\n prove({transactionId: keccak256(request), destTxHash: destTxHash, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridgeV2\n function claim(bytes calldata request) external {\n // claim override will validate the request\n claim({request: request, to: address(0)});\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Aggregate the read operations from the same storage slot\n address disputedRelayer = $.proofRelayer;\n BridgeStatus status = $.status;\n uint56 proofBlockTimestamp = $.proofBlockTimestamp;\n // Can only dispute a RELAYER_PROVED transaction within the dispute period\n if (status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(proofBlockTimestamp) \u003e DISPUTE_PERIOD) {\n revert DisputePeriodPassed();\n }\n // Update status to REQUESTED and delete the disputed proof details\n // Note: these are storage writes\n $.status = BridgeStatus.REQUESTED;\n $.proofRelayer = address(0);\n $.proofBlockTimestamp = 0;\n\n emit BridgeProofDisputed(transactionId, disputedRelayer);\n }\n\n /// @inheritdoc IFastBridge\n function refund(bytes calldata request) external {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Can only refund a REQUESTED transaction after its deadline expires\n if ($.status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n uint256 deadline = request.deadline();\n // Permissionless refund is only allowed after REFUND_DELAY on top of the deadline\n if (!hasRole(REFUNDER_ROLE, msg.sender)) deadline += REFUND_DELAY;\n if (block.timestamp \u003c= deadline) revert DeadlineNotExceeded();\n // Update status to REFUNDED and return the full amount (collateral + protocol fees) to the original sender.\n // The protocol fees are only updated when the transaction is claimed, so we don't need to update them here.\n // Note: this is a storage write\n $.status = BridgeStatus.REFUNDED;\n\n address to = request.originSender();\n address token = request.originToken();\n uint256 amount = request.originAmount() + request.originFeeAmount();\n // Emit the event before any external calls\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n // Complete the user refund as the last transaction action\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(to), amount);\n } else {\n IERC20(token).safeTransfer(to, amount);\n }\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // The correct relayer can only claim a RELAYER_PROVED transaction after the dispute period\n if ($.status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if ($.proofRelayer != relayer) revert SenderIncorrect();\n return _timeSince($.proofBlockTimestamp) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n /// @dev This method is added to achieve backwards compatibility with decoding requests into V1 structs:\n /// - `zapNative` is partially reported as a zero/non-zero flag\n /// - `zapData` is ignored\n /// In order to process all kinds of requests use getBridgeTransactionV2 instead.\n function getBridgeTransaction(bytes calldata request) external view returns (BridgeTransaction memory) {\n // Try decoding into V2 struct first. This will revert if V1 struct is passed\n try this.getBridgeTransactionV2(request) returns (BridgeTransactionV2 memory txV2) {\n // Note: we entirely ignore the zapData field, as it was not present in V1\n return BridgeTransaction({\n originChainId: txV2.originChainId,\n destChainId: txV2.destChainId,\n originSender: txV2.originSender,\n destRecipient: txV2.destRecipient,\n originToken: txV2.originToken,\n destToken: txV2.destToken,\n originAmount: txV2.originAmount,\n destAmount: txV2.destAmount,\n originFeeAmount: txV2.originFeeAmount,\n sendChainGas: txV2.zapNative != 0,\n deadline: txV2.deadline,\n nonce: txV2.nonce\n });\n } catch {\n // Fallback to V1 struct\n return abi.decode(request, (BridgeTransaction));\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function getBridgeTransactionV2(bytes calldata request) external pure returns (BridgeTransactionV2 memory) {\n request.validateV2();\n return BridgeTransactionV2Lib.decodeV2(request);\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) public payable {\n int256 exclusivityEndTime = 0;\n // if relayer exclusivity is not intended for this bridge, set exclusivityEndTime to static zero\n // otherwise, set exclusivity to expire at the current block ts offset by quoteExclusivitySeconds\n if (paramsV2.quoteRelayer != address(0)) {\n exclusivityEndTime = int256(block.timestamp) + paramsV2.quoteExclusivitySeconds;\n }\n _validateBridgeParams(params, paramsV2, exclusivityEndTime);\n\n // transfer tokens to bridge contract\n /// @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _takeBridgedUserAsset(params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) {\n originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n }\n\n // set status to requested\n bytes memory request = BridgeTransactionV2Lib.encodeV2(\n BridgeTransactionV2({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n deadline: params.deadline,\n nonce: senderNonces[params.sender]++, // increment nonce on every bridge\n exclusivityRelayer: paramsV2.quoteRelayer,\n // We checked exclusivityEndTime to be in range [0 .. params.deadline] above, so can safely cast\n exclusivityEndTime: uint256(exclusivityEndTime),\n zapNative: paramsV2.zapNative,\n zapData: paramsV2.zapData\n })\n );\n bytes32 transactionId = keccak256(request);\n // Note: the tx status will be updated throughout the tx lifecycle, while destChainId is set once here\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n bridgeTxDetails[transactionId].destChainId = params.dstChainId;\n\n emit BridgeRequested({\n transactionId: transactionId,\n sender: params.sender,\n request: request,\n destChainId: params.dstChainId,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n sendChainGas: paramsV2.zapNative != 0\n });\n emit BridgeQuoteDetails(transactionId, paramsV2.quoteId);\n }\n\n /// @inheritdoc IFastBridgeV2\n function relay(bytes calldata request, address relayer) public payable {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n _validateRelayParams(request, transactionId, relayer);\n // mark bridge transaction as relayed\n bridgeRelayDetails[transactionId] =\n BridgeRelay({blockNumber: uint48(block.number), blockTimestamp: uint48(block.timestamp), relayer: relayer});\n\n // transfer tokens to recipient on destination chain and trigger Zap if requested\n address to = request.destRecipient();\n address token = request.destToken();\n uint256 amount = request.destAmount();\n uint256 zapNative = request.zapNative();\n\n // Emit the event before any external calls\n emit BridgeRelayed({\n transactionId: transactionId,\n relayer: relayer,\n to: to,\n originChainId: request.originChainId(),\n originToken: request.originToken(),\n destToken: token,\n originAmount: request.originAmount(),\n destAmount: amount,\n chainGasAmount: zapNative\n });\n\n // All state changes have been done at this point, can proceed to the external calls.\n // This follows the checks-effects-interactions pattern to mitigate potential reentrancy attacks.\n if (token == NATIVE_GAS_TOKEN) {\n // For the native gas token, additional zapNative is not allowed\n if (zapNative != 0) revert ZapNativeNotSupported();\n // Check that the correct msg.value was sent\n if (msg.value != amount) revert MsgValueIncorrect();\n // Don't do a native transfer yet: we will handle it alongside the Zap below\n } else {\n // For ERC20s, we check that the correct msg.value was sent\n if (msg.value != zapNative) revert MsgValueIncorrect();\n // We need to transfer the tokens from the Relayer to the recipient first before performing an\n // optional post-transfer Zap.\n IERC20(token).safeTransferFrom(msg.sender, to, amount);\n }\n // At this point we have done:\n // - Transferred the requested amount of ERC20 tokens to the recipient.\n // At this point we have confirmed:\n // - For ERC20s: msg.value matches the requested zapNative amount.\n // - For the native gas token: msg.value matches the requested destAmount.\n // Remaining optional things to do:\n // - Forward the full msg.value to the recipient (if non-zero).\n // - Trigger a Zap (if zapData is present).\n bytes calldata zapData = request.zapData();\n if (zapData.length != 0) {\n // Zap Data is present: Zap has been requested by the recipient. Trigger it forwarding the full msg.value.\n\n // Note: if token has a fee on transfers, the recipient will have received less than `amount`.\n // This is a very niche edge case and should be handled by the recipient contract.\n _triggerZapWithChecks({recipient: to, token: token, amount: amount, zapData: zapData});\n } else if (msg.value != 0) {\n // Zap Data is missing, but msg.value was sent. This could happen in two different cases:\n // - Relay with the native gas token is happening.\n // - Relay with ERC20 is happening, with a `zapNative \u003e 0` request.\n // In both cases, we need to transfer the full msg.value to the recipient.\n Address.sendValue(payable(to), msg.value);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) public onlyRole(RELAYER_ROLE) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n\n // Can only prove a REQUESTED transaction\n if ($.status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n // Update status to RELAYER_PROVED and store the proof details\n // Note: these are storage writes\n $.status = BridgeStatus.RELAYER_PROVED;\n $.proofBlockTimestamp = uint56(block.timestamp);\n $.proofRelayer = relayer;\n\n emit BridgeProofProvided(transactionId, relayer, destTxHash);\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes calldata request, address to) public {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Aggregate the read operations from the same storage slot\n address proofRelayer = $.proofRelayer;\n BridgeStatus status = $.status;\n uint56 proofBlockTimestamp = $.proofBlockTimestamp;\n\n // Can only claim a RELAYER_PROVED transaction after the dispute period\n if (status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(proofBlockTimestamp) \u003c= DISPUTE_PERIOD) {\n revert DisputePeriodNotPassed();\n }\n\n if (to == address(0)) {\n // Anyone could claim the funds to the proven relayer on their behalf\n to = proofRelayer;\n } else if (proofRelayer != msg.sender) {\n // Only the proven relayer could specify an address to claim the funds to\n revert SenderIncorrect();\n }\n\n // Update status to RELAYER_CLAIMED and transfer the origin collateral to the specified claim address\n // Note: this is a storage write\n $.status = BridgeStatus.RELAYER_CLAIMED;\n\n address token = request.originToken();\n uint256 amount = request.originAmount();\n // Update protocol fees if origin fee amount exists\n uint256 originFeeAmount = request.originFeeAmount();\n if (originFeeAmount \u003e 0) protocolFees[token] += originFeeAmount;\n // Emit the event before any external calls\n emit BridgeDepositClaimed(transactionId, proofRelayer, to, token, amount);\n // Complete the relayer claim as the last transaction action\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(to), amount);\n } else {\n IERC20(token).safeTransfer(to, amount);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeStatuses(bytes32 transactionId) public view returns (BridgeStatus status) {\n return bridgeTxDetails[transactionId].status;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeProofs(bytes32 transactionId) public view returns (uint96 timestamp, address relayer) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n\n timestamp = $.proofBlockTimestamp;\n relayer = $.proofRelayer;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeRelays(bytes32 transactionId) public view returns (bool) {\n // has this transactionId been relayed?\n return bridgeRelayDetails[transactionId].relayer != address(0);\n }\n\n /// @notice Takes the bridged asset from the user into FastBridgeV2 custody. It will be later\n /// claimed by the relayer who completed the relay on destination chain, or refunded back to the user,\n /// should no one complete the relay.\n function _takeBridgedUserAsset(address token, uint256 amount) internal returns (uint256 amountTaken) {\n if (token == NATIVE_GAS_TOKEN) {\n // For the native gas token, we just need to check that the supplied msg.value is correct.\n // Supplied `msg.value` is already in FastBridgeV2 custody.\n if (amount != msg.value) revert MsgValueIncorrect();\n amountTaken = msg.value;\n } else {\n // For ERC20s, token is explicitly transferred from the user to FastBridgeV2.\n // We don't allow non-zero `msg.value` to avoid extra funds from being stuck in FastBridgeV2.\n if (msg.value != 0) revert MsgValueIncorrect();\n // Throw an explicit error if the provided token address is not a contract\n if (token.code.length == 0) revert TokenNotContract();\n amountTaken = IERC20(token).balanceOf(address(this));\n IERC20(token).safeTransferFrom(msg.sender, address(this), amount);\n // Use the balance difference as the amount taken in case of fee on transfer tokens.\n amountTaken = IERC20(token).balanceOf(address(this)) - amountTaken;\n }\n }\n\n /// @notice Calls the Recipient's hook function with the specified zapData and performs\n /// all the necessary checks for the returned value.\n function _triggerZapWithChecks(address recipient, address token, uint256 amount, bytes calldata zapData) internal {\n // This will bubble any revert messages from the hook function\n bytes memory returnData = Address.functionCallWithValue({\n target: recipient,\n data: abi.encodeCall(IZapRecipient.zap, (token, amount, zapData)),\n // Note: see `relay()` for reasoning behind passing msg.value\n value: msg.value\n });\n // Explicit revert if no return data at all\n if (returnData.length == 0) revert RecipientNoReturnValue();\n // Check that exactly a single return value was returned\n if (returnData.length != 32) revert RecipientIncorrectReturnValue();\n // Return value should be abi-encoded hook function selector\n if (bytes32(returnData) != bytes32(IZapRecipient.zap.selector)) {\n revert RecipientIncorrectReturnValue();\n }\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint56(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint56).max but\n /// proof.timestamp \u003c type(uint56).max via unchecked statement\n /// @param proofBlockTimestamp The bridge proof block timestamp\n /// @return delta Time delta since proof submitted\n function _timeSince(uint56 proofBlockTimestamp) internal view returns (uint256 delta) {\n unchecked {\n delta = uint56(block.timestamp) - proofBlockTimestamp;\n }\n }\n\n /// @notice Performs all the necessary checks for a bridge to happen.\n /// @dev There's no good way to refactor this function to reduce cyclomatic complexity due to\n /// the number of checks that need to be performed, so we skip the code-complexity rule here.\n // solhint-disable-next-line code-complexity\n function _validateBridgeParams(\n BridgeParams memory params,\n BridgeParamsV2 memory paramsV2,\n int256 exclusivityEndTime\n )\n internal\n view\n {\n // Check V1 (legacy) params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.sender == address(0) || params.to == address(0)) revert ZeroAddress();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n // Check V2 params\n if (paramsV2.zapData.length \u003e MAX_ZAP_DATA_LENGTH) revert ZapDataLengthAboveMax();\n if (paramsV2.zapNative != 0 \u0026\u0026 params.destToken == NATIVE_GAS_TOKEN) {\n revert ZapNativeNotSupported();\n }\n // exclusivityEndTime must be in range [0 .. params.deadline]\n if (exclusivityEndTime \u003c 0 || exclusivityEndTime \u003e int256(params.deadline)) {\n revert ExclusivityParamsIncorrect();\n }\n }\n\n /// @notice Performs all the necessary checks for a relay to happen.\n function _validateRelayParams(bytes calldata request, bytes32 transactionId, address relayer) internal view {\n if (relayer == address(0)) revert ZeroAddress();\n // Check if the transaction has already been relayed\n if (bridgeRelays(transactionId)) revert TransactionRelayed();\n if (request.destChainId() != block.chainid) revert ChainIncorrect();\n // Check the deadline for relay to happen\n if (block.timestamp \u003e request.deadline()) revert DeadlineExceeded();\n // Check the exclusivity period, if it is still ongoing\n address exclRelayer = request.exclusivityRelayer();\n if (exclRelayer != address(0) \u0026\u0026 exclRelayer != relayer \u0026\u0026 block.timestamp \u003c= request.exclusivityEndTime()) {\n revert ExclusivityPeriodNotPassed();\n }\n }\n}\n","language":"Solidity","languageVersion":"0.8.24","compilerVersion":"0.8.24","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"","srcMapRuntime":"","abiDefinition":[{"inputs":[],"name":"MulticallTarget__UndeterminedRevert","type":"error"},{"inputs":[{"internalType":"bytes[]","name":"data","type":"bytes[]"},{"internalType":"bool","name":"ignoreReverts","type":"bool"}],"name":"multicallNoResults","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes[]","name":"data","type":"bytes[]"},{"internalType":"bool","name":"ignoreReverts","type":"bool"}],"name":"multicallWithResults","outputs":[{"components":[{"internalType":"bool","name":"success","type":"bool"},{"internalType":"bytes","name":"returnData","type":"bytes"}],"internalType":"struct IMulticallTarget.Result[]","name":"results","type":"tuple[]"}],"stateMutability":"nonpayable","type":"function"}],"userDoc":{"kind":"user","methods":{"multicallNoResults(bytes[],bool)":{"notice":"Perform a batched call to this contract, preserving the msg.sender. The return data from each call is discarded."},"multicallWithResults(bytes[],bool)":{"notice":"Perform a batched call to this contract, preserving the msg.sender. The return data from each call is preserved."}},"notice":"Template for a contract that supports batched calls (preserving the msg.sender). Only calls with zero msg.value could be batched.","version":1},"developerDoc":{"kind":"dev","methods":{"multicallNoResults(bytes[],bool)":{"details":"The method is non-payable, so only calls with `msg.value == 0` could be batched. It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag. Otherwise, the whole batch call will be reverted with the original revert reason.","params":{"data":"List of abi-encoded calldata for the calls to perform.","ignoreReverts":"Whether to ignore the revert errors from the calls."}},"multicallWithResults(bytes[],bool)":{"details":"The method is non-payable, so only calls with `msg.value == 0` could be batched. It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag. Otherwise, the whole batch call will be reverted with the original revert reason.","params":{"data":"List of abi-encoded calldata for the calls to perform.","ignoreReverts":"Whether to ignore the revert errors from the calls."},"returns":{"results":" List of results from the calls: `(success, returnData)`."}}},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[],\"name\":\"MulticallTarget__UndeterminedRevert\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"bytes[]\",\"name\":\"data\",\"type\":\"bytes[]\"},{\"internalType\":\"bool\",\"name\":\"ignoreReverts\",\"type\":\"bool\"}],\"name\":\"multicallNoResults\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes[]\",\"name\":\"data\",\"type\":\"bytes[]\"},{\"internalType\":\"bool\",\"name\":\"ignoreReverts\",\"type\":\"bool\"}],\"name\":\"multicallWithResults\",\"outputs\":[{\"components\":[{\"internalType\":\"bool\",\"name\":\"success\",\"type\":\"bool\"},{\"internalType\":\"bytes\",\"name\":\"returnData\",\"type\":\"bytes\"}],\"internalType\":\"struct IMulticallTarget.Result[]\",\"name\":\"results\",\"type\":\"tuple[]\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{\"multicallNoResults(bytes[],bool)\":{\"details\":\"The method is non-payable, so only calls with `msg.value == 0` could be batched. It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag. Otherwise, the whole batch call will be reverted with the original revert reason.\",\"params\":{\"data\":\"List of abi-encoded calldata for the calls to perform.\",\"ignoreReverts\":\"Whether to ignore the revert errors from the calls.\"}},\"multicallWithResults(bytes[],bool)\":{\"details\":\"The method is non-payable, so only calls with `msg.value == 0` could be batched. It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag. Otherwise, the whole batch call will be reverted with the original revert reason.\",\"params\":{\"data\":\"List of abi-encoded calldata for the calls to perform.\",\"ignoreReverts\":\"Whether to ignore the revert errors from the calls.\"},\"returns\":{\"results\":\" List of results from the calls: `(success, returnData)`.\"}}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"multicallNoResults(bytes[],bool)\":{\"notice\":\"Perform a batched call to this contract, preserving the msg.sender. The return data from each call is discarded.\"},\"multicallWithResults(bytes[],bool)\":{\"notice\":\"Perform a batched call to this contract, preserving the msg.sender. The return data from each call is preserved.\"}},\"notice\":\"Template for a contract that supports batched calls (preserving the msg.sender). Only calls with zero msg.value could be batched.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeV2.sol\":\"MulticallTarget\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeV2.sol\":{\"keccak256\":\"0x5069b55ca07f21bfe30b2a43c18a18318c8af9c181b2dcb07c290825efd70f34\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://273dc020a49d08e50126bbea0d7f783f79d08c702f2fdbc560618d24af308acc\",\"dweb:/ipfs/QmXJ2UVzFc8EPB74RT4CXQPC4xw66jt4T13poyfyd3UERh\"]}},\"version\":1}"},"hashes":{"multicallNoResults(bytes[],bool)":"3f61331d","multicallWithResults(bytes[],bool)":"385c1d2f"}},"solidity/FastBridgeV2.sol:SafeERC20":{"code":"0x60566037600b82828239805160001a607314602a57634e487b7160e01b600052600060045260246000fd5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600080fdfea26469706673582212209fa7c4bd491bc75459d04b74ec3df4cf5631b4ff0438eacdbdda406ccb78986b64736f6c63430008180033","runtime-code":"0x73000000000000000000000000000000000000000030146080604052600080fdfea26469706673582212209fa7c4bd491bc75459d04b74ec3df4cf5631b4ff0438eacdbdda406ccb78986b64736f6c63430008180033","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.24 ^0.8.20 ^0.8.4;\n\n// contracts/interfaces/IAdmin.sol\n\ninterface IAdmin {\n // ============ Events ============\n\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n event ChainGasAmountUpdated(uint256 oldChainGasAmount, uint256 newChainGasAmount);\n\n // ============ Methods ============\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n\n function setChainGasAmount(uint256 newChainGasAmount) external;\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IFastBridgeV2Errors.sol\n\ninterface IFastBridgeV2Errors {\n error AmountIncorrect();\n error ChainIncorrect();\n error ExclusivityParamsIncorrect();\n error MsgValueIncorrect();\n error SenderIncorrect();\n error StatusIncorrect();\n error TokenNotContract();\n error ZapDataLengthAboveMax();\n error ZapNativeNotSupported();\n error ZeroAddress();\n\n error RecipientIncorrectReturnValue();\n error RecipientNoReturnValue();\n\n error DeadlineExceeded();\n error DeadlineNotExceeded();\n error DeadlineTooShort();\n error DisputePeriodNotPassed();\n error DisputePeriodPassed();\n error ExclusivityPeriodNotPassed();\n\n error TransactionRelayed();\n}\n\n// contracts/interfaces/IMulticallTarget.sol\n\n/// @notice Interface for a contract that can be called multiple times by the same caller. Inspired by MulticallV3:\n/// https://github.com/mds1/multicall/blob/master/src/Multicall3.sol\ninterface IMulticallTarget {\n struct Result {\n bool success;\n bytes returnData;\n }\n\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external;\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results);\n}\n\n// contracts/interfaces/IZapRecipient.sol\n\ninterface IZapRecipient {\n function zap(address token, uint256 amount, bytes memory zapData) external payable returns (bytes4);\n}\n\n// contracts/libs/Errors.sol\n\nerror DeadlineExceeded();\nerror DeadlineNotExceeded();\nerror DeadlineTooShort();\nerror InsufficientOutputAmount();\n\nerror MsgValueIncorrect();\nerror PoolNotFound();\nerror TokenAddressMismatch();\nerror TokenNotContract();\nerror TokenNotETH();\nerror TokensIdentical();\n\nerror ChainIncorrect();\nerror AmountIncorrect();\nerror ZeroAddress();\n\nerror DisputePeriodNotPassed();\nerror DisputePeriodPassed();\nerror SenderIncorrect();\nerror StatusIncorrect();\nerror TransactionIdIncorrect();\nerror TransactionRelayed();\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// contracts/interfaces/IFastBridgeV2.sol\n\ninterface IFastBridgeV2 is IFastBridge {\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n struct BridgeTxDetails {\n BridgeStatus status;\n uint32 destChainId;\n uint56 proofBlockTimestamp;\n address proofRelayer;\n }\n\n struct BridgeRelay {\n uint48 blockNumber;\n uint48 blockTimestamp;\n address relayer;\n }\n\n /// @notice New params introduced in the FastBridgeV2.\n /// We are passing fields from the older BridgeParams struct outside of this struct\n /// for backwards compatibility.\n /// Note: quoteRelayer and quoteExclusivitySeconds are either both zero (indicating no exclusivity)\n /// or both non-zero (indicating exclusivity for the given period).\n /// Note: zapNative \u003e 0 can NOT be used with destToken = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE (native token)\n /// @param quoteRelayer Relayer that provided the quote for the transaction\n /// @param quoteExclusivitySeconds Period of time the quote relayer is guaranteed exclusivity after user's deposit\n /// @param quoteId Unique quote identifier used for tracking the quote\n /// @param zapNative ETH value to send to the recipient (if any)\n /// @param zapData Parameters for the Zap to the destination recipient (if any)\n struct BridgeParamsV2 {\n address quoteRelayer;\n int256 quoteExclusivitySeconds;\n bytes quoteId;\n uint256 zapNative;\n bytes zapData;\n }\n\n /// @notice Updated bridge transaction struct to include parameters introduced in FastBridgeV2.\n /// Note: only `exclusivityRelayer` can fill such a transaction until `exclusivityEndTime`.\n struct BridgeTransactionV2 {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n // Note: sendChainGas flag from V1 is deprecated\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n address exclusivityRelayer;\n uint256 exclusivityEndTime;\n uint256 zapNative; // ETH value to send to the recipient (if any)\n bytes zapData; // data to pass for the Zap action (if any)\n }\n\n event BridgeQuoteDetails(bytes32 indexed transactionId, bytes quoteId);\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability\n /// to provide temporary exclusivity fill rights for the quote relayer.\n /// @param params The parameters required to bridge\n /// @param paramsV2 The parameters for exclusivity fill rights (optional, can be left empty)\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function relay(bytes memory request, address relayer) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param transactionId The transaction id associated with the encoded bridge transaction to prove\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital.\n /// @notice Can only send funds to the relayer address on the proof.\n /// @param request The encoded bridge transaction to claim on origin chain\n function claim(bytes memory request) external;\n /// @notice Checks if a transaction has been relayed\n /// @param transactionId The ID of the transaction to check\n /// @return True if the transaction has been relayed, false otherwise\n function bridgeRelays(bytes32 transactionId) external view returns (bool);\n\n /// @notice Returns the status of a bridge transaction\n /// @param transactionId The ID of the bridge transaction\n /// @return BridgeStatus Status of the bridge transaction\n function bridgeStatuses(bytes32 transactionId) external view returns (BridgeStatus);\n\n /// @notice Returns the timestamp and relayer of a bridge proof\n /// @param transactionId The ID of the bridge transaction\n /// @return timestamp The timestamp of the bridge proof\n /// @return relayer The relayer address of the bridge proof\n function bridgeProofs(bytes32 transactionId) external view returns (uint96 timestamp, address relayer);\n\n /// @notice Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\n /// @param request The bridge request to decode\n function getBridgeTransactionV2(bytes memory request) external view returns (BridgeTransactionV2 memory);\n}\n\n// contracts/utils/MulticallTarget.sol\n\n// solhint-disable avoid-low-level-calls\n/// @notice Template for a contract that supports batched calls (preserving the msg.sender).\n/// Only calls with zero msg.value could be batched.\nabstract contract MulticallTarget is IMulticallTarget {\n error MulticallTarget__UndeterminedRevert();\n\n /// @notice Perform a batched call to this contract, preserving the msg.sender.\n /// The return data from each call is discarded.\n /// @dev The method is non-payable, so only calls with `msg.value == 0` could be batched.\n /// It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag.\n /// Otherwise, the whole batch call will be reverted with the original revert reason.\n /// @param data List of abi-encoded calldata for the calls to perform.\n /// @param ignoreReverts Whether to ignore the revert errors from the calls.\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external {\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\n if (!success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(result);\n }\n }\n }\n\n /// @notice Perform a batched call to this contract, preserving the msg.sender.\n /// The return data from each call is preserved.\n /// @dev The method is non-payable, so only calls with `msg.value == 0` could be batched.\n /// It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag.\n /// Otherwise, the whole batch call will be reverted with the original revert reason.\n /// @param data List of abi-encoded calldata for the calls to perform.\n /// @param ignoreReverts Whether to ignore the revert errors from the calls.\n /// @return results List of results from the calls: `(success, returnData)`.\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results)\n {\n results = new Result[](data.length);\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (results[i].success, results[i].returnData) = address(this).delegatecall(data[i]);\n if (!results[i].success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(results[i].returnData);\n }\n }\n }\n\n /// @dev Bubbles the revert message from the underlying call.\n /// Note: preserves the same custom error or revert string, if one was used.\n /// Source: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v5.0.2/contracts/utils/Address.sol#L143-L158\n function _bubbleRevert(bytes memory returnData) internal pure {\n // Look for revert reason and bubble it up if present\n if (returnData.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n // solhint-disable-next-line no-inline-assembly\n assembly {\n let returndata_size := mload(returnData)\n revert(add(32, returnData), returndata_size)\n }\n } else {\n revert MulticallTarget__UndeterminedRevert();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// contracts/libs/BridgeTransactionV2.sol\n\n// solhint-disable no-inline-assembly\nlibrary BridgeTransactionV2Lib {\n uint16 internal constant VERSION = 2;\n\n // Offsets of the fields in the packed BridgeTransactionV2 struct\n // uint16 version [000 .. 002)\n // uint32 originChainId [002 .. 006)\n // uint32 destChainId [006 .. 010)\n // address originSender [010 .. 030)\n // address destRecipient [030 .. 050)\n // address originToken [050 .. 070)\n // address destToken [070 .. 090)\n // uint256 originAmount [090 .. 122)\n // uint256 destAmount [122 .. 154)\n // uint256 originFeeAmount [154 .. 186)\n // uint256 deadline [186 .. 218)\n // uint256 nonce [218 .. 250)\n // address exclusivityRelayer [250 .. 270)\n // uint256 exclusivityEndTime [270 .. 302)\n // uint256 zapNative [302 .. 334)\n // bytes zapData [334 .. ***)\n\n // forgefmt: disable-start\n uint256 private constant OFFSET_ORIGIN_CHAIN_ID = 2;\n uint256 private constant OFFSET_DEST_CHAIN_ID = 6;\n uint256 private constant OFFSET_ORIGIN_SENDER = 10;\n uint256 private constant OFFSET_DEST_RECIPIENT = 30;\n uint256 private constant OFFSET_ORIGIN_TOKEN = 50;\n uint256 private constant OFFSET_DEST_TOKEN = 70;\n uint256 private constant OFFSET_ORIGIN_AMOUNT = 90;\n uint256 private constant OFFSET_DEST_AMOUNT = 122;\n uint256 private constant OFFSET_ORIGIN_FEE_AMOUNT = 154;\n uint256 private constant OFFSET_DEADLINE = 186;\n uint256 private constant OFFSET_NONCE = 218;\n uint256 private constant OFFSET_EXCLUSIVITY_RELAYER = 250;\n uint256 private constant OFFSET_EXCLUSIVITY_END_TIME = 270;\n uint256 private constant OFFSET_ZAP_NATIVE = 302;\n uint256 private constant OFFSET_ZAP_DATA = 334;\n // forgefmt: disable-end\n\n error BridgeTransactionV2__InvalidEncodedTx();\n error BridgeTransactionV2__UnsupportedVersion(uint16 version);\n\n /// @notice Validates the encoded transaction to be a tightly packed encoded payload for BridgeTransactionV2.\n /// @dev Checks the minimum length and the version, use this function before decoding any of the fields.\n function validateV2(bytes calldata encodedTx) internal pure {\n // Check the minimum length: must at least include all static fields.\n if (encodedTx.length \u003c OFFSET_ZAP_DATA) revert BridgeTransactionV2__InvalidEncodedTx();\n // Once we validated the length, we can be sure that the version field is present.\n uint16 version_ = version(encodedTx);\n if (version_ != VERSION) revert BridgeTransactionV2__UnsupportedVersion(version_);\n }\n\n /// @notice Encodes the BridgeTransactionV2 struct by tightly packing the fields.\n /// @dev `abi.decode` will not work as a result of the tightly packed fields. Use `decodeV2` to decode instead.\n function encodeV2(IFastBridgeV2.BridgeTransactionV2 memory bridgeTx) internal pure returns (bytes memory) {\n // We split the encoding into two parts to avoid stack-too-deep error\n bytes memory firstPart = abi.encodePacked(\n VERSION,\n bridgeTx.originChainId,\n bridgeTx.destChainId,\n bridgeTx.originSender,\n bridgeTx.destRecipient,\n bridgeTx.originToken,\n bridgeTx.destToken,\n bridgeTx.originAmount\n );\n return abi.encodePacked(\n firstPart,\n bridgeTx.destAmount,\n bridgeTx.originFeeAmount,\n // Note: we skip the deprecated `sendChainGas` flag, which was present in BridgeTransaction V1\n bridgeTx.deadline,\n bridgeTx.nonce,\n // New V2 fields: exclusivity\n bridgeTx.exclusivityRelayer,\n bridgeTx.exclusivityEndTime,\n // New V2 fields: Zap\n bridgeTx.zapNative,\n bridgeTx.zapData\n );\n }\n\n /// @notice Decodes the BridgeTransactionV2 struct from the encoded transaction.\n /// @dev Encoded BridgeTransactionV2 struct must be tightly packed.\n /// Use `validateV2` before decoding to ensure the encoded transaction is valid.\n function decodeV2(bytes calldata encodedTx)\n internal\n pure\n returns (IFastBridgeV2.BridgeTransactionV2 memory bridgeTx)\n {\n bridgeTx.originChainId = originChainId(encodedTx);\n bridgeTx.destChainId = destChainId(encodedTx);\n bridgeTx.originSender = originSender(encodedTx);\n bridgeTx.destRecipient = destRecipient(encodedTx);\n bridgeTx.originToken = originToken(encodedTx);\n bridgeTx.destToken = destToken(encodedTx);\n bridgeTx.originAmount = originAmount(encodedTx);\n bridgeTx.destAmount = destAmount(encodedTx);\n bridgeTx.originFeeAmount = originFeeAmount(encodedTx);\n bridgeTx.deadline = deadline(encodedTx);\n bridgeTx.nonce = nonce(encodedTx);\n bridgeTx.exclusivityRelayer = exclusivityRelayer(encodedTx);\n bridgeTx.exclusivityEndTime = exclusivityEndTime(encodedTx);\n bridgeTx.zapNative = zapNative(encodedTx);\n bridgeTx.zapData = zapData(encodedTx);\n }\n\n /// @notice Extracts the version from the encoded transaction.\n function version(bytes calldata encodedTx) internal pure returns (uint16 version_) {\n // Load 32 bytes from the start and shift it 240 bits to the right to get the highest 16 bits.\n assembly {\n version_ := shr(240, calldataload(encodedTx.offset))\n }\n }\n\n /// @notice Extracts the origin chain ID from the encoded transaction.\n function originChainId(bytes calldata encodedTx) internal pure returns (uint32 originChainId_) {\n // Load 32 bytes from the offset and shift it 224 bits to the right to get the highest 32 bits.\n assembly {\n originChainId_ := shr(224, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_CHAIN_ID)))\n }\n }\n\n /// @notice Extracts the destination chain ID from the encoded transaction.\n function destChainId(bytes calldata encodedTx) internal pure returns (uint32 destChainId_) {\n // Load 32 bytes from the offset and shift it 224 bits to the right to get the highest 32 bits.\n assembly {\n destChainId_ := shr(224, calldataload(add(encodedTx.offset, OFFSET_DEST_CHAIN_ID)))\n }\n }\n\n /// @notice Extracts the origin sender from the encoded transaction.\n function originSender(bytes calldata encodedTx) internal pure returns (address originSender_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n originSender_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_SENDER)))\n }\n }\n\n /// @notice Extracts the destination recipient from the encoded transaction.\n function destRecipient(bytes calldata encodedTx) internal pure returns (address destRecipient_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n destRecipient_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_DEST_RECIPIENT)))\n }\n }\n\n /// @notice Extracts the origin token from the encoded transaction.\n function originToken(bytes calldata encodedTx) internal pure returns (address originToken_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n originToken_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_TOKEN)))\n }\n }\n\n /// @notice Extracts the destination token from the encoded transaction.\n function destToken(bytes calldata encodedTx) internal pure returns (address destToken_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n destToken_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_DEST_TOKEN)))\n }\n }\n\n /// @notice Extracts the origin amount from the encoded transaction.\n function originAmount(bytes calldata encodedTx) internal pure returns (uint256 originAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n originAmount_ := calldataload(add(encodedTx.offset, OFFSET_ORIGIN_AMOUNT))\n }\n }\n\n /// @notice Extracts the destination amount from the encoded transaction.\n function destAmount(bytes calldata encodedTx) internal pure returns (uint256 destAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n destAmount_ := calldataload(add(encodedTx.offset, OFFSET_DEST_AMOUNT))\n }\n }\n\n /// @notice Extracts the origin fee amount from the encoded transaction.\n function originFeeAmount(bytes calldata encodedTx) internal pure returns (uint256 originFeeAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n originFeeAmount_ := calldataload(add(encodedTx.offset, OFFSET_ORIGIN_FEE_AMOUNT))\n }\n }\n\n /// @notice Extracts the deadline from the encoded transaction.\n function deadline(bytes calldata encodedTx) internal pure returns (uint256 deadline_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n deadline_ := calldataload(add(encodedTx.offset, OFFSET_DEADLINE))\n }\n }\n\n /// @notice Extracts the nonce from the encoded transaction.\n function nonce(bytes calldata encodedTx) internal pure returns (uint256 nonce_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n nonce_ := calldataload(add(encodedTx.offset, OFFSET_NONCE))\n }\n }\n\n /// @notice Extracts the exclusivity relayer from the encoded transaction.\n function exclusivityRelayer(bytes calldata encodedTx) internal pure returns (address exclusivityRelayer_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n exclusivityRelayer_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_EXCLUSIVITY_RELAYER)))\n }\n }\n\n /// @notice Extracts the exclusivity end time from the encoded transaction.\n function exclusivityEndTime(bytes calldata encodedTx) internal pure returns (uint256 exclusivityEndTime_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n exclusivityEndTime_ := calldataload(add(encodedTx.offset, OFFSET_EXCLUSIVITY_END_TIME))\n }\n }\n\n /// @notice Extracts the Zap's native value from the encoded transaction.\n function zapNative(bytes calldata encodedTx) internal pure returns (uint256 zapNative_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n zapNative_ := calldataload(add(encodedTx.offset, OFFSET_ZAP_NATIVE))\n }\n }\n\n /// @notice Extracts the Zap's data from the encoded transaction.\n function zapData(bytes calldata encodedTx) internal pure returns (bytes calldata zapData_) {\n zapData_ = encodedTx[OFFSET_ZAP_DATA:];\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// contracts/libs/UniversalToken.sol\n\nlibrary UniversalTokenLib {\n using SafeERC20 for IERC20;\n\n address internal constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Transfers tokens to the given account. Reverts if transfer is not successful.\n /// @dev This might trigger fallback, if ETH is transferred to the contract.\n /// Make sure this can not lead to reentrancy attacks.\n function universalTransfer(address token, address to, uint256 value) internal {\n // Don't do anything, if need to send tokens to this address\n if (to == address(this)) return;\n // Don't do anything, if trying to send zero value\n if (value == 0) return;\n if (token == ETH_ADDRESS) {\n /// @dev Note: this can potentially lead to executing code in `to`.\n // solhint-disable-next-line avoid-low-level-calls\n (bool success,) = to.call{value: value}(\"\");\n require(success, \"ETH transfer failed\");\n } else {\n IERC20(token).safeTransfer(to, value);\n }\n }\n\n /// @notice Issues an infinite allowance to the spender, if the current allowance is insufficient\n /// to spend the given amount.\n function universalApproveInfinity(address token, address spender, uint256 amountToSpend) internal {\n // ETH Chad doesn't require your approval\n if (token == ETH_ADDRESS) return;\n // No-op if allowance is already sufficient\n uint256 allowance = IERC20(token).allowance(address(this), spender);\n if (allowance \u003e= amountToSpend) return;\n // Otherwise, reset approval to 0 and set to max allowance\n if (allowance \u003e 0) IERC20(token).safeDecreaseAllowance(spender, allowance);\n IERC20(token).safeIncreaseAllowance(spender, type(uint256).max);\n }\n\n /// @notice Returns the balance of the given token (or native ETH) for the given account.\n function universalBalanceOf(address token, address account) internal view returns (uint256) {\n if (token == ETH_ADDRESS) {\n return account.balance;\n } else {\n return IERC20(token).balanceOf(account);\n }\n }\n\n /// @dev Checks that token is a contract and not ETH_ADDRESS.\n function assertIsContract(address token) internal view {\n // Check that ETH_ADDRESS was not used (in case this is a predeploy on any of the chains)\n if (token == UniversalTokenLib.ETH_ADDRESS) revert TokenNotContract();\n // Check that token is not an EOA\n if (token.code.length == 0) revert TokenNotContract();\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/Admin.sol\n\ncontract Admin is IAdmin, AccessControlEnumerable {\n using UniversalTokenLib for address;\n\n bytes32 public constant RELAYER_ROLE = keccak256(\"RELAYER_ROLE\");\n bytes32 public constant REFUNDER_ROLE = keccak256(\"REFUNDER_ROLE\");\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n uint256 public constant FEE_BPS = 1e6;\n uint256 public constant FEE_RATE_MAX = 0.01e6; // max 1% on origin amount\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Chain gas amount to forward as rebate if requested\n uint256 public chainGasAmount;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n }\n\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n require(newFeeRate \u003c= FEE_RATE_MAX, \"newFeeRate \u003e max\");\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n token.universalTransfer(recipient, feeAmount);\n emit FeesSwept(token, recipient, feeAmount);\n }\n\n function setChainGasAmount(uint256 newChainGasAmount) external onlyRole(GOVERNOR_ROLE) {\n uint256 oldChainGasAmount = chainGasAmount;\n chainGasAmount = newChainGasAmount;\n emit ChainGasAmountUpdated(oldChainGasAmount, newChainGasAmount);\n }\n}\n\n// contracts/FastBridgeV2.sol\n\n/// @notice FastBridgeV2 is a contract for bridging tokens across chains.\ncontract FastBridgeV2 is Admin, MulticallTarget, IFastBridgeV2, IFastBridgeV2Errors {\n using BridgeTransactionV2Lib for bytes;\n using SafeERC20 for IERC20;\n\n /// @notice Address reserved for native gas token (ETH on Ethereum and most L2s, AVAX on Avalanche, etc)\n address public constant NATIVE_GAS_TOKEN = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Delay for a transaction after which it could be permisionlessly refunded\n uint256 public constant REFUND_DELAY = 7 days;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n /// @notice Maximum length of accepted zapData\n uint256 public constant MAX_ZAP_DATA_LENGTH = 2 ** 16 - 1;\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeTxDetails) public bridgeTxDetails;\n /// @notice Relay details on destination chain\n mapping(bytes32 =\u003e BridgeRelay) public bridgeRelayDetails;\n /// @notice Unique bridge nonces tracked per originSender\n mapping(address =\u003e uint256) public senderNonces;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Replaced by senderNonces\n uint256 public immutable nonce = 0;\n /// @notice the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n bridge({\n params: params,\n paramsV2: BridgeParamsV2({\n quoteRelayer: address(0),\n quoteExclusivitySeconds: 0,\n quoteId: bytes(\"\"),\n zapNative: 0,\n zapData: bytes(\"\")\n })\n });\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes calldata request) external payable {\n // relay override will validate the request\n relay({request: request, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes calldata request, bytes32 destTxHash) external {\n request.validateV2();\n prove({transactionId: keccak256(request), destTxHash: destTxHash, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridgeV2\n function claim(bytes calldata request) external {\n // claim override will validate the request\n claim({request: request, to: address(0)});\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Aggregate the read operations from the same storage slot\n address disputedRelayer = $.proofRelayer;\n BridgeStatus status = $.status;\n uint56 proofBlockTimestamp = $.proofBlockTimestamp;\n // Can only dispute a RELAYER_PROVED transaction within the dispute period\n if (status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(proofBlockTimestamp) \u003e DISPUTE_PERIOD) {\n revert DisputePeriodPassed();\n }\n // Update status to REQUESTED and delete the disputed proof details\n // Note: these are storage writes\n $.status = BridgeStatus.REQUESTED;\n $.proofRelayer = address(0);\n $.proofBlockTimestamp = 0;\n\n emit BridgeProofDisputed(transactionId, disputedRelayer);\n }\n\n /// @inheritdoc IFastBridge\n function refund(bytes calldata request) external {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Can only refund a REQUESTED transaction after its deadline expires\n if ($.status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n uint256 deadline = request.deadline();\n // Permissionless refund is only allowed after REFUND_DELAY on top of the deadline\n if (!hasRole(REFUNDER_ROLE, msg.sender)) deadline += REFUND_DELAY;\n if (block.timestamp \u003c= deadline) revert DeadlineNotExceeded();\n // Update status to REFUNDED and return the full amount (collateral + protocol fees) to the original sender.\n // The protocol fees are only updated when the transaction is claimed, so we don't need to update them here.\n // Note: this is a storage write\n $.status = BridgeStatus.REFUNDED;\n\n address to = request.originSender();\n address token = request.originToken();\n uint256 amount = request.originAmount() + request.originFeeAmount();\n // Emit the event before any external calls\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n // Complete the user refund as the last transaction action\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(to), amount);\n } else {\n IERC20(token).safeTransfer(to, amount);\n }\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // The correct relayer can only claim a RELAYER_PROVED transaction after the dispute period\n if ($.status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if ($.proofRelayer != relayer) revert SenderIncorrect();\n return _timeSince($.proofBlockTimestamp) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n /// @dev This method is added to achieve backwards compatibility with decoding requests into V1 structs:\n /// - `zapNative` is partially reported as a zero/non-zero flag\n /// - `zapData` is ignored\n /// In order to process all kinds of requests use getBridgeTransactionV2 instead.\n function getBridgeTransaction(bytes calldata request) external view returns (BridgeTransaction memory) {\n // Try decoding into V2 struct first. This will revert if V1 struct is passed\n try this.getBridgeTransactionV2(request) returns (BridgeTransactionV2 memory txV2) {\n // Note: we entirely ignore the zapData field, as it was not present in V1\n return BridgeTransaction({\n originChainId: txV2.originChainId,\n destChainId: txV2.destChainId,\n originSender: txV2.originSender,\n destRecipient: txV2.destRecipient,\n originToken: txV2.originToken,\n destToken: txV2.destToken,\n originAmount: txV2.originAmount,\n destAmount: txV2.destAmount,\n originFeeAmount: txV2.originFeeAmount,\n sendChainGas: txV2.zapNative != 0,\n deadline: txV2.deadline,\n nonce: txV2.nonce\n });\n } catch {\n // Fallback to V1 struct\n return abi.decode(request, (BridgeTransaction));\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function getBridgeTransactionV2(bytes calldata request) external pure returns (BridgeTransactionV2 memory) {\n request.validateV2();\n return BridgeTransactionV2Lib.decodeV2(request);\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) public payable {\n int256 exclusivityEndTime = 0;\n // if relayer exclusivity is not intended for this bridge, set exclusivityEndTime to static zero\n // otherwise, set exclusivity to expire at the current block ts offset by quoteExclusivitySeconds\n if (paramsV2.quoteRelayer != address(0)) {\n exclusivityEndTime = int256(block.timestamp) + paramsV2.quoteExclusivitySeconds;\n }\n _validateBridgeParams(params, paramsV2, exclusivityEndTime);\n\n // transfer tokens to bridge contract\n /// @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _takeBridgedUserAsset(params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) {\n originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n }\n\n // set status to requested\n bytes memory request = BridgeTransactionV2Lib.encodeV2(\n BridgeTransactionV2({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n deadline: params.deadline,\n nonce: senderNonces[params.sender]++, // increment nonce on every bridge\n exclusivityRelayer: paramsV2.quoteRelayer,\n // We checked exclusivityEndTime to be in range [0 .. params.deadline] above, so can safely cast\n exclusivityEndTime: uint256(exclusivityEndTime),\n zapNative: paramsV2.zapNative,\n zapData: paramsV2.zapData\n })\n );\n bytes32 transactionId = keccak256(request);\n // Note: the tx status will be updated throughout the tx lifecycle, while destChainId is set once here\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n bridgeTxDetails[transactionId].destChainId = params.dstChainId;\n\n emit BridgeRequested({\n transactionId: transactionId,\n sender: params.sender,\n request: request,\n destChainId: params.dstChainId,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n sendChainGas: paramsV2.zapNative != 0\n });\n emit BridgeQuoteDetails(transactionId, paramsV2.quoteId);\n }\n\n /// @inheritdoc IFastBridgeV2\n function relay(bytes calldata request, address relayer) public payable {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n _validateRelayParams(request, transactionId, relayer);\n // mark bridge transaction as relayed\n bridgeRelayDetails[transactionId] =\n BridgeRelay({blockNumber: uint48(block.number), blockTimestamp: uint48(block.timestamp), relayer: relayer});\n\n // transfer tokens to recipient on destination chain and trigger Zap if requested\n address to = request.destRecipient();\n address token = request.destToken();\n uint256 amount = request.destAmount();\n uint256 zapNative = request.zapNative();\n\n // Emit the event before any external calls\n emit BridgeRelayed({\n transactionId: transactionId,\n relayer: relayer,\n to: to,\n originChainId: request.originChainId(),\n originToken: request.originToken(),\n destToken: token,\n originAmount: request.originAmount(),\n destAmount: amount,\n chainGasAmount: zapNative\n });\n\n // All state changes have been done at this point, can proceed to the external calls.\n // This follows the checks-effects-interactions pattern to mitigate potential reentrancy attacks.\n if (token == NATIVE_GAS_TOKEN) {\n // For the native gas token, additional zapNative is not allowed\n if (zapNative != 0) revert ZapNativeNotSupported();\n // Check that the correct msg.value was sent\n if (msg.value != amount) revert MsgValueIncorrect();\n // Don't do a native transfer yet: we will handle it alongside the Zap below\n } else {\n // For ERC20s, we check that the correct msg.value was sent\n if (msg.value != zapNative) revert MsgValueIncorrect();\n // We need to transfer the tokens from the Relayer to the recipient first before performing an\n // optional post-transfer Zap.\n IERC20(token).safeTransferFrom(msg.sender, to, amount);\n }\n // At this point we have done:\n // - Transferred the requested amount of ERC20 tokens to the recipient.\n // At this point we have confirmed:\n // - For ERC20s: msg.value matches the requested zapNative amount.\n // - For the native gas token: msg.value matches the requested destAmount.\n // Remaining optional things to do:\n // - Forward the full msg.value to the recipient (if non-zero).\n // - Trigger a Zap (if zapData is present).\n bytes calldata zapData = request.zapData();\n if (zapData.length != 0) {\n // Zap Data is present: Zap has been requested by the recipient. Trigger it forwarding the full msg.value.\n\n // Note: if token has a fee on transfers, the recipient will have received less than `amount`.\n // This is a very niche edge case and should be handled by the recipient contract.\n _triggerZapWithChecks({recipient: to, token: token, amount: amount, zapData: zapData});\n } else if (msg.value != 0) {\n // Zap Data is missing, but msg.value was sent. This could happen in two different cases:\n // - Relay with the native gas token is happening.\n // - Relay with ERC20 is happening, with a `zapNative \u003e 0` request.\n // In both cases, we need to transfer the full msg.value to the recipient.\n Address.sendValue(payable(to), msg.value);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) public onlyRole(RELAYER_ROLE) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n\n // Can only prove a REQUESTED transaction\n if ($.status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n // Update status to RELAYER_PROVED and store the proof details\n // Note: these are storage writes\n $.status = BridgeStatus.RELAYER_PROVED;\n $.proofBlockTimestamp = uint56(block.timestamp);\n $.proofRelayer = relayer;\n\n emit BridgeProofProvided(transactionId, relayer, destTxHash);\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes calldata request, address to) public {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Aggregate the read operations from the same storage slot\n address proofRelayer = $.proofRelayer;\n BridgeStatus status = $.status;\n uint56 proofBlockTimestamp = $.proofBlockTimestamp;\n\n // Can only claim a RELAYER_PROVED transaction after the dispute period\n if (status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(proofBlockTimestamp) \u003c= DISPUTE_PERIOD) {\n revert DisputePeriodNotPassed();\n }\n\n if (to == address(0)) {\n // Anyone could claim the funds to the proven relayer on their behalf\n to = proofRelayer;\n } else if (proofRelayer != msg.sender) {\n // Only the proven relayer could specify an address to claim the funds to\n revert SenderIncorrect();\n }\n\n // Update status to RELAYER_CLAIMED and transfer the origin collateral to the specified claim address\n // Note: this is a storage write\n $.status = BridgeStatus.RELAYER_CLAIMED;\n\n address token = request.originToken();\n uint256 amount = request.originAmount();\n // Update protocol fees if origin fee amount exists\n uint256 originFeeAmount = request.originFeeAmount();\n if (originFeeAmount \u003e 0) protocolFees[token] += originFeeAmount;\n // Emit the event before any external calls\n emit BridgeDepositClaimed(transactionId, proofRelayer, to, token, amount);\n // Complete the relayer claim as the last transaction action\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(to), amount);\n } else {\n IERC20(token).safeTransfer(to, amount);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeStatuses(bytes32 transactionId) public view returns (BridgeStatus status) {\n return bridgeTxDetails[transactionId].status;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeProofs(bytes32 transactionId) public view returns (uint96 timestamp, address relayer) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n\n timestamp = $.proofBlockTimestamp;\n relayer = $.proofRelayer;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeRelays(bytes32 transactionId) public view returns (bool) {\n // has this transactionId been relayed?\n return bridgeRelayDetails[transactionId].relayer != address(0);\n }\n\n /// @notice Takes the bridged asset from the user into FastBridgeV2 custody. It will be later\n /// claimed by the relayer who completed the relay on destination chain, or refunded back to the user,\n /// should no one complete the relay.\n function _takeBridgedUserAsset(address token, uint256 amount) internal returns (uint256 amountTaken) {\n if (token == NATIVE_GAS_TOKEN) {\n // For the native gas token, we just need to check that the supplied msg.value is correct.\n // Supplied `msg.value` is already in FastBridgeV2 custody.\n if (amount != msg.value) revert MsgValueIncorrect();\n amountTaken = msg.value;\n } else {\n // For ERC20s, token is explicitly transferred from the user to FastBridgeV2.\n // We don't allow non-zero `msg.value` to avoid extra funds from being stuck in FastBridgeV2.\n if (msg.value != 0) revert MsgValueIncorrect();\n // Throw an explicit error if the provided token address is not a contract\n if (token.code.length == 0) revert TokenNotContract();\n amountTaken = IERC20(token).balanceOf(address(this));\n IERC20(token).safeTransferFrom(msg.sender, address(this), amount);\n // Use the balance difference as the amount taken in case of fee on transfer tokens.\n amountTaken = IERC20(token).balanceOf(address(this)) - amountTaken;\n }\n }\n\n /// @notice Calls the Recipient's hook function with the specified zapData and performs\n /// all the necessary checks for the returned value.\n function _triggerZapWithChecks(address recipient, address token, uint256 amount, bytes calldata zapData) internal {\n // This will bubble any revert messages from the hook function\n bytes memory returnData = Address.functionCallWithValue({\n target: recipient,\n data: abi.encodeCall(IZapRecipient.zap, (token, amount, zapData)),\n // Note: see `relay()` for reasoning behind passing msg.value\n value: msg.value\n });\n // Explicit revert if no return data at all\n if (returnData.length == 0) revert RecipientNoReturnValue();\n // Check that exactly a single return value was returned\n if (returnData.length != 32) revert RecipientIncorrectReturnValue();\n // Return value should be abi-encoded hook function selector\n if (bytes32(returnData) != bytes32(IZapRecipient.zap.selector)) {\n revert RecipientIncorrectReturnValue();\n }\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint56(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint56).max but\n /// proof.timestamp \u003c type(uint56).max via unchecked statement\n /// @param proofBlockTimestamp The bridge proof block timestamp\n /// @return delta Time delta since proof submitted\n function _timeSince(uint56 proofBlockTimestamp) internal view returns (uint256 delta) {\n unchecked {\n delta = uint56(block.timestamp) - proofBlockTimestamp;\n }\n }\n\n /// @notice Performs all the necessary checks for a bridge to happen.\n /// @dev There's no good way to refactor this function to reduce cyclomatic complexity due to\n /// the number of checks that need to be performed, so we skip the code-complexity rule here.\n // solhint-disable-next-line code-complexity\n function _validateBridgeParams(\n BridgeParams memory params,\n BridgeParamsV2 memory paramsV2,\n int256 exclusivityEndTime\n )\n internal\n view\n {\n // Check V1 (legacy) params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.sender == address(0) || params.to == address(0)) revert ZeroAddress();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n // Check V2 params\n if (paramsV2.zapData.length \u003e MAX_ZAP_DATA_LENGTH) revert ZapDataLengthAboveMax();\n if (paramsV2.zapNative != 0 \u0026\u0026 params.destToken == NATIVE_GAS_TOKEN) {\n revert ZapNativeNotSupported();\n }\n // exclusivityEndTime must be in range [0 .. params.deadline]\n if (exclusivityEndTime \u003c 0 || exclusivityEndTime \u003e int256(params.deadline)) {\n revert ExclusivityParamsIncorrect();\n }\n }\n\n /// @notice Performs all the necessary checks for a relay to happen.\n function _validateRelayParams(bytes calldata request, bytes32 transactionId, address relayer) internal view {\n if (relayer == address(0)) revert ZeroAddress();\n // Check if the transaction has already been relayed\n if (bridgeRelays(transactionId)) revert TransactionRelayed();\n if (request.destChainId() != block.chainid) revert ChainIncorrect();\n // Check the deadline for relay to happen\n if (block.timestamp \u003e request.deadline()) revert DeadlineExceeded();\n // Check the exclusivity period, if it is still ongoing\n address exclRelayer = request.exclusivityRelayer();\n if (exclRelayer != address(0) \u0026\u0026 exclRelayer != relayer \u0026\u0026 block.timestamp \u003c= request.exclusivityEndTime()) {\n revert ExclusivityPeriodNotPassed();\n }\n }\n}\n","language":"Solidity","languageVersion":"0.8.24","compilerVersion":"0.8.24","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"61814:5018:0:-:0;;;;;;;;;;;;;;;-1:-1:-1;;;61814:5018:0;;;;;;;;;;;;;;;;;","srcMapRuntime":"61814:5018:0:-:0;;;;;;;;","abiDefinition":[{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"currentAllowance","type":"uint256"},{"internalType":"uint256","name":"requestedDecrease","type":"uint256"}],"name":"SafeERC20FailedDecreaseAllowance","type":"error"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"SafeERC20FailedOperation","type":"error"}],"userDoc":{"kind":"user","methods":{},"version":1},"developerDoc":{"details":"Wrappers around ERC20 operations that throw on failure (when the token contract returns false). Tokens that return no value (and instead revert or throw on failure) are also supported, non-reverting calls are assumed to be successful. To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract, which allows you to call the safe operations as `token.safeTransfer(...)`, etc.","errors":{"SafeERC20FailedDecreaseAllowance(address,uint256,uint256)":[{"details":"Indicates a failed `decreaseAllowance` request."}],"SafeERC20FailedOperation(address)":[{"details":"An operation with an ERC20 token failed."}]},"kind":"dev","methods":{},"title":"SafeERC20","version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"currentAllowance\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"requestedDecrease\",\"type\":\"uint256\"}],\"name\":\"SafeERC20FailedDecreaseAllowance\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"}],\"name\":\"SafeERC20FailedOperation\",\"type\":\"error\"}],\"devdoc\":{\"details\":\"Wrappers around ERC20 operations that throw on failure (when the token contract returns false). Tokens that return no value (and instead revert or throw on failure) are also supported, non-reverting calls are assumed to be successful. To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract, which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\",\"errors\":{\"SafeERC20FailedDecreaseAllowance(address,uint256,uint256)\":[{\"details\":\"Indicates a failed `decreaseAllowance` request.\"}],\"SafeERC20FailedOperation(address)\":[{\"details\":\"An operation with an ERC20 token failed.\"}]},\"kind\":\"dev\",\"methods\":{},\"title\":\"SafeERC20\",\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeV2.sol\":\"SafeERC20\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeV2.sol\":{\"keccak256\":\"0x5069b55ca07f21bfe30b2a43c18a18318c8af9c181b2dcb07c290825efd70f34\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://273dc020a49d08e50126bbea0d7f783f79d08c702f2fdbc560618d24af308acc\",\"dweb:/ipfs/QmXJ2UVzFc8EPB74RT4CXQPC4xw66jt4T13poyfyd3UERh\"]}},\"version\":1}"},"hashes":{}},"solidity/FastBridgeV2.sol:UniversalTokenLib":{"code":"0x60566037600b82828239805160001a607314602a57634e487b7160e01b600052600060045260246000fd5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600080fdfea26469706673582212208ee6f45538d68dae1182af6006877f66fc2bb57b5fe35283c7b3ccf352c1148364736f6c63430008180033","runtime-code":"0x73000000000000000000000000000000000000000030146080604052600080fdfea26469706673582212208ee6f45538d68dae1182af6006877f66fc2bb57b5fe35283c7b3ccf352c1148364736f6c63430008180033","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.24 ^0.8.20 ^0.8.4;\n\n// contracts/interfaces/IAdmin.sol\n\ninterface IAdmin {\n // ============ Events ============\n\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n event ChainGasAmountUpdated(uint256 oldChainGasAmount, uint256 newChainGasAmount);\n\n // ============ Methods ============\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n\n function setChainGasAmount(uint256 newChainGasAmount) external;\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IFastBridgeV2Errors.sol\n\ninterface IFastBridgeV2Errors {\n error AmountIncorrect();\n error ChainIncorrect();\n error ExclusivityParamsIncorrect();\n error MsgValueIncorrect();\n error SenderIncorrect();\n error StatusIncorrect();\n error TokenNotContract();\n error ZapDataLengthAboveMax();\n error ZapNativeNotSupported();\n error ZeroAddress();\n\n error RecipientIncorrectReturnValue();\n error RecipientNoReturnValue();\n\n error DeadlineExceeded();\n error DeadlineNotExceeded();\n error DeadlineTooShort();\n error DisputePeriodNotPassed();\n error DisputePeriodPassed();\n error ExclusivityPeriodNotPassed();\n\n error TransactionRelayed();\n}\n\n// contracts/interfaces/IMulticallTarget.sol\n\n/// @notice Interface for a contract that can be called multiple times by the same caller. Inspired by MulticallV3:\n/// https://github.com/mds1/multicall/blob/master/src/Multicall3.sol\ninterface IMulticallTarget {\n struct Result {\n bool success;\n bytes returnData;\n }\n\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external;\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results);\n}\n\n// contracts/interfaces/IZapRecipient.sol\n\ninterface IZapRecipient {\n function zap(address token, uint256 amount, bytes memory zapData) external payable returns (bytes4);\n}\n\n// contracts/libs/Errors.sol\n\nerror DeadlineExceeded();\nerror DeadlineNotExceeded();\nerror DeadlineTooShort();\nerror InsufficientOutputAmount();\n\nerror MsgValueIncorrect();\nerror PoolNotFound();\nerror TokenAddressMismatch();\nerror TokenNotContract();\nerror TokenNotETH();\nerror TokensIdentical();\n\nerror ChainIncorrect();\nerror AmountIncorrect();\nerror ZeroAddress();\n\nerror DisputePeriodNotPassed();\nerror DisputePeriodPassed();\nerror SenderIncorrect();\nerror StatusIncorrect();\nerror TransactionIdIncorrect();\nerror TransactionRelayed();\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// contracts/interfaces/IFastBridgeV2.sol\n\ninterface IFastBridgeV2 is IFastBridge {\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n struct BridgeTxDetails {\n BridgeStatus status;\n uint32 destChainId;\n uint56 proofBlockTimestamp;\n address proofRelayer;\n }\n\n struct BridgeRelay {\n uint48 blockNumber;\n uint48 blockTimestamp;\n address relayer;\n }\n\n /// @notice New params introduced in the FastBridgeV2.\n /// We are passing fields from the older BridgeParams struct outside of this struct\n /// for backwards compatibility.\n /// Note: quoteRelayer and quoteExclusivitySeconds are either both zero (indicating no exclusivity)\n /// or both non-zero (indicating exclusivity for the given period).\n /// Note: zapNative \u003e 0 can NOT be used with destToken = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE (native token)\n /// @param quoteRelayer Relayer that provided the quote for the transaction\n /// @param quoteExclusivitySeconds Period of time the quote relayer is guaranteed exclusivity after user's deposit\n /// @param quoteId Unique quote identifier used for tracking the quote\n /// @param zapNative ETH value to send to the recipient (if any)\n /// @param zapData Parameters for the Zap to the destination recipient (if any)\n struct BridgeParamsV2 {\n address quoteRelayer;\n int256 quoteExclusivitySeconds;\n bytes quoteId;\n uint256 zapNative;\n bytes zapData;\n }\n\n /// @notice Updated bridge transaction struct to include parameters introduced in FastBridgeV2.\n /// Note: only `exclusivityRelayer` can fill such a transaction until `exclusivityEndTime`.\n struct BridgeTransactionV2 {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n // Note: sendChainGas flag from V1 is deprecated\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n address exclusivityRelayer;\n uint256 exclusivityEndTime;\n uint256 zapNative; // ETH value to send to the recipient (if any)\n bytes zapData; // data to pass for the Zap action (if any)\n }\n\n event BridgeQuoteDetails(bytes32 indexed transactionId, bytes quoteId);\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability\n /// to provide temporary exclusivity fill rights for the quote relayer.\n /// @param params The parameters required to bridge\n /// @param paramsV2 The parameters for exclusivity fill rights (optional, can be left empty)\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function relay(bytes memory request, address relayer) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param transactionId The transaction id associated with the encoded bridge transaction to prove\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital.\n /// @notice Can only send funds to the relayer address on the proof.\n /// @param request The encoded bridge transaction to claim on origin chain\n function claim(bytes memory request) external;\n /// @notice Checks if a transaction has been relayed\n /// @param transactionId The ID of the transaction to check\n /// @return True if the transaction has been relayed, false otherwise\n function bridgeRelays(bytes32 transactionId) external view returns (bool);\n\n /// @notice Returns the status of a bridge transaction\n /// @param transactionId The ID of the bridge transaction\n /// @return BridgeStatus Status of the bridge transaction\n function bridgeStatuses(bytes32 transactionId) external view returns (BridgeStatus);\n\n /// @notice Returns the timestamp and relayer of a bridge proof\n /// @param transactionId The ID of the bridge transaction\n /// @return timestamp The timestamp of the bridge proof\n /// @return relayer The relayer address of the bridge proof\n function bridgeProofs(bytes32 transactionId) external view returns (uint96 timestamp, address relayer);\n\n /// @notice Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\n /// @param request The bridge request to decode\n function getBridgeTransactionV2(bytes memory request) external view returns (BridgeTransactionV2 memory);\n}\n\n// contracts/utils/MulticallTarget.sol\n\n// solhint-disable avoid-low-level-calls\n/// @notice Template for a contract that supports batched calls (preserving the msg.sender).\n/// Only calls with zero msg.value could be batched.\nabstract contract MulticallTarget is IMulticallTarget {\n error MulticallTarget__UndeterminedRevert();\n\n /// @notice Perform a batched call to this contract, preserving the msg.sender.\n /// The return data from each call is discarded.\n /// @dev The method is non-payable, so only calls with `msg.value == 0` could be batched.\n /// It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag.\n /// Otherwise, the whole batch call will be reverted with the original revert reason.\n /// @param data List of abi-encoded calldata for the calls to perform.\n /// @param ignoreReverts Whether to ignore the revert errors from the calls.\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external {\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\n if (!success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(result);\n }\n }\n }\n\n /// @notice Perform a batched call to this contract, preserving the msg.sender.\n /// The return data from each call is preserved.\n /// @dev The method is non-payable, so only calls with `msg.value == 0` could be batched.\n /// It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag.\n /// Otherwise, the whole batch call will be reverted with the original revert reason.\n /// @param data List of abi-encoded calldata for the calls to perform.\n /// @param ignoreReverts Whether to ignore the revert errors from the calls.\n /// @return results List of results from the calls: `(success, returnData)`.\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results)\n {\n results = new Result[](data.length);\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (results[i].success, results[i].returnData) = address(this).delegatecall(data[i]);\n if (!results[i].success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(results[i].returnData);\n }\n }\n }\n\n /// @dev Bubbles the revert message from the underlying call.\n /// Note: preserves the same custom error or revert string, if one was used.\n /// Source: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v5.0.2/contracts/utils/Address.sol#L143-L158\n function _bubbleRevert(bytes memory returnData) internal pure {\n // Look for revert reason and bubble it up if present\n if (returnData.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n // solhint-disable-next-line no-inline-assembly\n assembly {\n let returndata_size := mload(returnData)\n revert(add(32, returnData), returndata_size)\n }\n } else {\n revert MulticallTarget__UndeterminedRevert();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// contracts/libs/BridgeTransactionV2.sol\n\n// solhint-disable no-inline-assembly\nlibrary BridgeTransactionV2Lib {\n uint16 internal constant VERSION = 2;\n\n // Offsets of the fields in the packed BridgeTransactionV2 struct\n // uint16 version [000 .. 002)\n // uint32 originChainId [002 .. 006)\n // uint32 destChainId [006 .. 010)\n // address originSender [010 .. 030)\n // address destRecipient [030 .. 050)\n // address originToken [050 .. 070)\n // address destToken [070 .. 090)\n // uint256 originAmount [090 .. 122)\n // uint256 destAmount [122 .. 154)\n // uint256 originFeeAmount [154 .. 186)\n // uint256 deadline [186 .. 218)\n // uint256 nonce [218 .. 250)\n // address exclusivityRelayer [250 .. 270)\n // uint256 exclusivityEndTime [270 .. 302)\n // uint256 zapNative [302 .. 334)\n // bytes zapData [334 .. ***)\n\n // forgefmt: disable-start\n uint256 private constant OFFSET_ORIGIN_CHAIN_ID = 2;\n uint256 private constant OFFSET_DEST_CHAIN_ID = 6;\n uint256 private constant OFFSET_ORIGIN_SENDER = 10;\n uint256 private constant OFFSET_DEST_RECIPIENT = 30;\n uint256 private constant OFFSET_ORIGIN_TOKEN = 50;\n uint256 private constant OFFSET_DEST_TOKEN = 70;\n uint256 private constant OFFSET_ORIGIN_AMOUNT = 90;\n uint256 private constant OFFSET_DEST_AMOUNT = 122;\n uint256 private constant OFFSET_ORIGIN_FEE_AMOUNT = 154;\n uint256 private constant OFFSET_DEADLINE = 186;\n uint256 private constant OFFSET_NONCE = 218;\n uint256 private constant OFFSET_EXCLUSIVITY_RELAYER = 250;\n uint256 private constant OFFSET_EXCLUSIVITY_END_TIME = 270;\n uint256 private constant OFFSET_ZAP_NATIVE = 302;\n uint256 private constant OFFSET_ZAP_DATA = 334;\n // forgefmt: disable-end\n\n error BridgeTransactionV2__InvalidEncodedTx();\n error BridgeTransactionV2__UnsupportedVersion(uint16 version);\n\n /// @notice Validates the encoded transaction to be a tightly packed encoded payload for BridgeTransactionV2.\n /// @dev Checks the minimum length and the version, use this function before decoding any of the fields.\n function validateV2(bytes calldata encodedTx) internal pure {\n // Check the minimum length: must at least include all static fields.\n if (encodedTx.length \u003c OFFSET_ZAP_DATA) revert BridgeTransactionV2__InvalidEncodedTx();\n // Once we validated the length, we can be sure that the version field is present.\n uint16 version_ = version(encodedTx);\n if (version_ != VERSION) revert BridgeTransactionV2__UnsupportedVersion(version_);\n }\n\n /// @notice Encodes the BridgeTransactionV2 struct by tightly packing the fields.\n /// @dev `abi.decode` will not work as a result of the tightly packed fields. Use `decodeV2` to decode instead.\n function encodeV2(IFastBridgeV2.BridgeTransactionV2 memory bridgeTx) internal pure returns (bytes memory) {\n // We split the encoding into two parts to avoid stack-too-deep error\n bytes memory firstPart = abi.encodePacked(\n VERSION,\n bridgeTx.originChainId,\n bridgeTx.destChainId,\n bridgeTx.originSender,\n bridgeTx.destRecipient,\n bridgeTx.originToken,\n bridgeTx.destToken,\n bridgeTx.originAmount\n );\n return abi.encodePacked(\n firstPart,\n bridgeTx.destAmount,\n bridgeTx.originFeeAmount,\n // Note: we skip the deprecated `sendChainGas` flag, which was present in BridgeTransaction V1\n bridgeTx.deadline,\n bridgeTx.nonce,\n // New V2 fields: exclusivity\n bridgeTx.exclusivityRelayer,\n bridgeTx.exclusivityEndTime,\n // New V2 fields: Zap\n bridgeTx.zapNative,\n bridgeTx.zapData\n );\n }\n\n /// @notice Decodes the BridgeTransactionV2 struct from the encoded transaction.\n /// @dev Encoded BridgeTransactionV2 struct must be tightly packed.\n /// Use `validateV2` before decoding to ensure the encoded transaction is valid.\n function decodeV2(bytes calldata encodedTx)\n internal\n pure\n returns (IFastBridgeV2.BridgeTransactionV2 memory bridgeTx)\n {\n bridgeTx.originChainId = originChainId(encodedTx);\n bridgeTx.destChainId = destChainId(encodedTx);\n bridgeTx.originSender = originSender(encodedTx);\n bridgeTx.destRecipient = destRecipient(encodedTx);\n bridgeTx.originToken = originToken(encodedTx);\n bridgeTx.destToken = destToken(encodedTx);\n bridgeTx.originAmount = originAmount(encodedTx);\n bridgeTx.destAmount = destAmount(encodedTx);\n bridgeTx.originFeeAmount = originFeeAmount(encodedTx);\n bridgeTx.deadline = deadline(encodedTx);\n bridgeTx.nonce = nonce(encodedTx);\n bridgeTx.exclusivityRelayer = exclusivityRelayer(encodedTx);\n bridgeTx.exclusivityEndTime = exclusivityEndTime(encodedTx);\n bridgeTx.zapNative = zapNative(encodedTx);\n bridgeTx.zapData = zapData(encodedTx);\n }\n\n /// @notice Extracts the version from the encoded transaction.\n function version(bytes calldata encodedTx) internal pure returns (uint16 version_) {\n // Load 32 bytes from the start and shift it 240 bits to the right to get the highest 16 bits.\n assembly {\n version_ := shr(240, calldataload(encodedTx.offset))\n }\n }\n\n /// @notice Extracts the origin chain ID from the encoded transaction.\n function originChainId(bytes calldata encodedTx) internal pure returns (uint32 originChainId_) {\n // Load 32 bytes from the offset and shift it 224 bits to the right to get the highest 32 bits.\n assembly {\n originChainId_ := shr(224, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_CHAIN_ID)))\n }\n }\n\n /// @notice Extracts the destination chain ID from the encoded transaction.\n function destChainId(bytes calldata encodedTx) internal pure returns (uint32 destChainId_) {\n // Load 32 bytes from the offset and shift it 224 bits to the right to get the highest 32 bits.\n assembly {\n destChainId_ := shr(224, calldataload(add(encodedTx.offset, OFFSET_DEST_CHAIN_ID)))\n }\n }\n\n /// @notice Extracts the origin sender from the encoded transaction.\n function originSender(bytes calldata encodedTx) internal pure returns (address originSender_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n originSender_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_SENDER)))\n }\n }\n\n /// @notice Extracts the destination recipient from the encoded transaction.\n function destRecipient(bytes calldata encodedTx) internal pure returns (address destRecipient_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n destRecipient_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_DEST_RECIPIENT)))\n }\n }\n\n /// @notice Extracts the origin token from the encoded transaction.\n function originToken(bytes calldata encodedTx) internal pure returns (address originToken_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n originToken_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_TOKEN)))\n }\n }\n\n /// @notice Extracts the destination token from the encoded transaction.\n function destToken(bytes calldata encodedTx) internal pure returns (address destToken_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n destToken_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_DEST_TOKEN)))\n }\n }\n\n /// @notice Extracts the origin amount from the encoded transaction.\n function originAmount(bytes calldata encodedTx) internal pure returns (uint256 originAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n originAmount_ := calldataload(add(encodedTx.offset, OFFSET_ORIGIN_AMOUNT))\n }\n }\n\n /// @notice Extracts the destination amount from the encoded transaction.\n function destAmount(bytes calldata encodedTx) internal pure returns (uint256 destAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n destAmount_ := calldataload(add(encodedTx.offset, OFFSET_DEST_AMOUNT))\n }\n }\n\n /// @notice Extracts the origin fee amount from the encoded transaction.\n function originFeeAmount(bytes calldata encodedTx) internal pure returns (uint256 originFeeAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n originFeeAmount_ := calldataload(add(encodedTx.offset, OFFSET_ORIGIN_FEE_AMOUNT))\n }\n }\n\n /// @notice Extracts the deadline from the encoded transaction.\n function deadline(bytes calldata encodedTx) internal pure returns (uint256 deadline_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n deadline_ := calldataload(add(encodedTx.offset, OFFSET_DEADLINE))\n }\n }\n\n /// @notice Extracts the nonce from the encoded transaction.\n function nonce(bytes calldata encodedTx) internal pure returns (uint256 nonce_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n nonce_ := calldataload(add(encodedTx.offset, OFFSET_NONCE))\n }\n }\n\n /// @notice Extracts the exclusivity relayer from the encoded transaction.\n function exclusivityRelayer(bytes calldata encodedTx) internal pure returns (address exclusivityRelayer_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n exclusivityRelayer_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_EXCLUSIVITY_RELAYER)))\n }\n }\n\n /// @notice Extracts the exclusivity end time from the encoded transaction.\n function exclusivityEndTime(bytes calldata encodedTx) internal pure returns (uint256 exclusivityEndTime_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n exclusivityEndTime_ := calldataload(add(encodedTx.offset, OFFSET_EXCLUSIVITY_END_TIME))\n }\n }\n\n /// @notice Extracts the Zap's native value from the encoded transaction.\n function zapNative(bytes calldata encodedTx) internal pure returns (uint256 zapNative_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n zapNative_ := calldataload(add(encodedTx.offset, OFFSET_ZAP_NATIVE))\n }\n }\n\n /// @notice Extracts the Zap's data from the encoded transaction.\n function zapData(bytes calldata encodedTx) internal pure returns (bytes calldata zapData_) {\n zapData_ = encodedTx[OFFSET_ZAP_DATA:];\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// contracts/libs/UniversalToken.sol\n\nlibrary UniversalTokenLib {\n using SafeERC20 for IERC20;\n\n address internal constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Transfers tokens to the given account. Reverts if transfer is not successful.\n /// @dev This might trigger fallback, if ETH is transferred to the contract.\n /// Make sure this can not lead to reentrancy attacks.\n function universalTransfer(address token, address to, uint256 value) internal {\n // Don't do anything, if need to send tokens to this address\n if (to == address(this)) return;\n // Don't do anything, if trying to send zero value\n if (value == 0) return;\n if (token == ETH_ADDRESS) {\n /// @dev Note: this can potentially lead to executing code in `to`.\n // solhint-disable-next-line avoid-low-level-calls\n (bool success,) = to.call{value: value}(\"\");\n require(success, \"ETH transfer failed\");\n } else {\n IERC20(token).safeTransfer(to, value);\n }\n }\n\n /// @notice Issues an infinite allowance to the spender, if the current allowance is insufficient\n /// to spend the given amount.\n function universalApproveInfinity(address token, address spender, uint256 amountToSpend) internal {\n // ETH Chad doesn't require your approval\n if (token == ETH_ADDRESS) return;\n // No-op if allowance is already sufficient\n uint256 allowance = IERC20(token).allowance(address(this), spender);\n if (allowance \u003e= amountToSpend) return;\n // Otherwise, reset approval to 0 and set to max allowance\n if (allowance \u003e 0) IERC20(token).safeDecreaseAllowance(spender, allowance);\n IERC20(token).safeIncreaseAllowance(spender, type(uint256).max);\n }\n\n /// @notice Returns the balance of the given token (or native ETH) for the given account.\n function universalBalanceOf(address token, address account) internal view returns (uint256) {\n if (token == ETH_ADDRESS) {\n return account.balance;\n } else {\n return IERC20(token).balanceOf(account);\n }\n }\n\n /// @dev Checks that token is a contract and not ETH_ADDRESS.\n function assertIsContract(address token) internal view {\n // Check that ETH_ADDRESS was not used (in case this is a predeploy on any of the chains)\n if (token == UniversalTokenLib.ETH_ADDRESS) revert TokenNotContract();\n // Check that token is not an EOA\n if (token.code.length == 0) revert TokenNotContract();\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/Admin.sol\n\ncontract Admin is IAdmin, AccessControlEnumerable {\n using UniversalTokenLib for address;\n\n bytes32 public constant RELAYER_ROLE = keccak256(\"RELAYER_ROLE\");\n bytes32 public constant REFUNDER_ROLE = keccak256(\"REFUNDER_ROLE\");\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n uint256 public constant FEE_BPS = 1e6;\n uint256 public constant FEE_RATE_MAX = 0.01e6; // max 1% on origin amount\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Chain gas amount to forward as rebate if requested\n uint256 public chainGasAmount;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n }\n\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n require(newFeeRate \u003c= FEE_RATE_MAX, \"newFeeRate \u003e max\");\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n token.universalTransfer(recipient, feeAmount);\n emit FeesSwept(token, recipient, feeAmount);\n }\n\n function setChainGasAmount(uint256 newChainGasAmount) external onlyRole(GOVERNOR_ROLE) {\n uint256 oldChainGasAmount = chainGasAmount;\n chainGasAmount = newChainGasAmount;\n emit ChainGasAmountUpdated(oldChainGasAmount, newChainGasAmount);\n }\n}\n\n// contracts/FastBridgeV2.sol\n\n/// @notice FastBridgeV2 is a contract for bridging tokens across chains.\ncontract FastBridgeV2 is Admin, MulticallTarget, IFastBridgeV2, IFastBridgeV2Errors {\n using BridgeTransactionV2Lib for bytes;\n using SafeERC20 for IERC20;\n\n /// @notice Address reserved for native gas token (ETH on Ethereum and most L2s, AVAX on Avalanche, etc)\n address public constant NATIVE_GAS_TOKEN = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Delay for a transaction after which it could be permisionlessly refunded\n uint256 public constant REFUND_DELAY = 7 days;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n /// @notice Maximum length of accepted zapData\n uint256 public constant MAX_ZAP_DATA_LENGTH = 2 ** 16 - 1;\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeTxDetails) public bridgeTxDetails;\n /// @notice Relay details on destination chain\n mapping(bytes32 =\u003e BridgeRelay) public bridgeRelayDetails;\n /// @notice Unique bridge nonces tracked per originSender\n mapping(address =\u003e uint256) public senderNonces;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Replaced by senderNonces\n uint256 public immutable nonce = 0;\n /// @notice the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) Admin(_owner) {\n deployBlock = block.number;\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n bridge({\n params: params,\n paramsV2: BridgeParamsV2({\n quoteRelayer: address(0),\n quoteExclusivitySeconds: 0,\n quoteId: bytes(\"\"),\n zapNative: 0,\n zapData: bytes(\"\")\n })\n });\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes calldata request) external payable {\n // relay override will validate the request\n relay({request: request, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes calldata request, bytes32 destTxHash) external {\n request.validateV2();\n prove({transactionId: keccak256(request), destTxHash: destTxHash, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridgeV2\n function claim(bytes calldata request) external {\n // claim override will validate the request\n claim({request: request, to: address(0)});\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Aggregate the read operations from the same storage slot\n address disputedRelayer = $.proofRelayer;\n BridgeStatus status = $.status;\n uint56 proofBlockTimestamp = $.proofBlockTimestamp;\n // Can only dispute a RELAYER_PROVED transaction within the dispute period\n if (status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(proofBlockTimestamp) \u003e DISPUTE_PERIOD) {\n revert DisputePeriodPassed();\n }\n // Update status to REQUESTED and delete the disputed proof details\n // Note: these are storage writes\n $.status = BridgeStatus.REQUESTED;\n $.proofRelayer = address(0);\n $.proofBlockTimestamp = 0;\n\n emit BridgeProofDisputed(transactionId, disputedRelayer);\n }\n\n /// @inheritdoc IFastBridge\n function refund(bytes calldata request) external {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Can only refund a REQUESTED transaction after its deadline expires\n if ($.status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n uint256 deadline = request.deadline();\n // Permissionless refund is only allowed after REFUND_DELAY on top of the deadline\n if (!hasRole(REFUNDER_ROLE, msg.sender)) deadline += REFUND_DELAY;\n if (block.timestamp \u003c= deadline) revert DeadlineNotExceeded();\n // Update status to REFUNDED and return the full amount (collateral + protocol fees) to the original sender.\n // The protocol fees are only updated when the transaction is claimed, so we don't need to update them here.\n // Note: this is a storage write\n $.status = BridgeStatus.REFUNDED;\n\n address to = request.originSender();\n address token = request.originToken();\n uint256 amount = request.originAmount() + request.originFeeAmount();\n // Emit the event before any external calls\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n // Complete the user refund as the last transaction action\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(to), amount);\n } else {\n IERC20(token).safeTransfer(to, amount);\n }\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // The correct relayer can only claim a RELAYER_PROVED transaction after the dispute period\n if ($.status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if ($.proofRelayer != relayer) revert SenderIncorrect();\n return _timeSince($.proofBlockTimestamp) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n /// @dev This method is added to achieve backwards compatibility with decoding requests into V1 structs:\n /// - `zapNative` is partially reported as a zero/non-zero flag\n /// - `zapData` is ignored\n /// In order to process all kinds of requests use getBridgeTransactionV2 instead.\n function getBridgeTransaction(bytes calldata request) external view returns (BridgeTransaction memory) {\n // Try decoding into V2 struct first. This will revert if V1 struct is passed\n try this.getBridgeTransactionV2(request) returns (BridgeTransactionV2 memory txV2) {\n // Note: we entirely ignore the zapData field, as it was not present in V1\n return BridgeTransaction({\n originChainId: txV2.originChainId,\n destChainId: txV2.destChainId,\n originSender: txV2.originSender,\n destRecipient: txV2.destRecipient,\n originToken: txV2.originToken,\n destToken: txV2.destToken,\n originAmount: txV2.originAmount,\n destAmount: txV2.destAmount,\n originFeeAmount: txV2.originFeeAmount,\n sendChainGas: txV2.zapNative != 0,\n deadline: txV2.deadline,\n nonce: txV2.nonce\n });\n } catch {\n // Fallback to V1 struct\n return abi.decode(request, (BridgeTransaction));\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function getBridgeTransactionV2(bytes calldata request) external pure returns (BridgeTransactionV2 memory) {\n request.validateV2();\n return BridgeTransactionV2Lib.decodeV2(request);\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) public payable {\n int256 exclusivityEndTime = 0;\n // if relayer exclusivity is not intended for this bridge, set exclusivityEndTime to static zero\n // otherwise, set exclusivity to expire at the current block ts offset by quoteExclusivitySeconds\n if (paramsV2.quoteRelayer != address(0)) {\n exclusivityEndTime = int256(block.timestamp) + paramsV2.quoteExclusivitySeconds;\n }\n _validateBridgeParams(params, paramsV2, exclusivityEndTime);\n\n // transfer tokens to bridge contract\n /// @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _takeBridgedUserAsset(params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) {\n originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n }\n\n // set status to requested\n bytes memory request = BridgeTransactionV2Lib.encodeV2(\n BridgeTransactionV2({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n deadline: params.deadline,\n nonce: senderNonces[params.sender]++, // increment nonce on every bridge\n exclusivityRelayer: paramsV2.quoteRelayer,\n // We checked exclusivityEndTime to be in range [0 .. params.deadline] above, so can safely cast\n exclusivityEndTime: uint256(exclusivityEndTime),\n zapNative: paramsV2.zapNative,\n zapData: paramsV2.zapData\n })\n );\n bytes32 transactionId = keccak256(request);\n // Note: the tx status will be updated throughout the tx lifecycle, while destChainId is set once here\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n bridgeTxDetails[transactionId].destChainId = params.dstChainId;\n\n emit BridgeRequested({\n transactionId: transactionId,\n sender: params.sender,\n request: request,\n destChainId: params.dstChainId,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n sendChainGas: paramsV2.zapNative != 0\n });\n emit BridgeQuoteDetails(transactionId, paramsV2.quoteId);\n }\n\n /// @inheritdoc IFastBridgeV2\n function relay(bytes calldata request, address relayer) public payable {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n _validateRelayParams(request, transactionId, relayer);\n // mark bridge transaction as relayed\n bridgeRelayDetails[transactionId] =\n BridgeRelay({blockNumber: uint48(block.number), blockTimestamp: uint48(block.timestamp), relayer: relayer});\n\n // transfer tokens to recipient on destination chain and trigger Zap if requested\n address to = request.destRecipient();\n address token = request.destToken();\n uint256 amount = request.destAmount();\n uint256 zapNative = request.zapNative();\n\n // Emit the event before any external calls\n emit BridgeRelayed({\n transactionId: transactionId,\n relayer: relayer,\n to: to,\n originChainId: request.originChainId(),\n originToken: request.originToken(),\n destToken: token,\n originAmount: request.originAmount(),\n destAmount: amount,\n chainGasAmount: zapNative\n });\n\n // All state changes have been done at this point, can proceed to the external calls.\n // This follows the checks-effects-interactions pattern to mitigate potential reentrancy attacks.\n if (token == NATIVE_GAS_TOKEN) {\n // For the native gas token, additional zapNative is not allowed\n if (zapNative != 0) revert ZapNativeNotSupported();\n // Check that the correct msg.value was sent\n if (msg.value != amount) revert MsgValueIncorrect();\n // Don't do a native transfer yet: we will handle it alongside the Zap below\n } else {\n // For ERC20s, we check that the correct msg.value was sent\n if (msg.value != zapNative) revert MsgValueIncorrect();\n // We need to transfer the tokens from the Relayer to the recipient first before performing an\n // optional post-transfer Zap.\n IERC20(token).safeTransferFrom(msg.sender, to, amount);\n }\n // At this point we have done:\n // - Transferred the requested amount of ERC20 tokens to the recipient.\n // At this point we have confirmed:\n // - For ERC20s: msg.value matches the requested zapNative amount.\n // - For the native gas token: msg.value matches the requested destAmount.\n // Remaining optional things to do:\n // - Forward the full msg.value to the recipient (if non-zero).\n // - Trigger a Zap (if zapData is present).\n bytes calldata zapData = request.zapData();\n if (zapData.length != 0) {\n // Zap Data is present: Zap has been requested by the recipient. Trigger it forwarding the full msg.value.\n\n // Note: if token has a fee on transfers, the recipient will have received less than `amount`.\n // This is a very niche edge case and should be handled by the recipient contract.\n _triggerZapWithChecks({recipient: to, token: token, amount: amount, zapData: zapData});\n } else if (msg.value != 0) {\n // Zap Data is missing, but msg.value was sent. This could happen in two different cases:\n // - Relay with the native gas token is happening.\n // - Relay with ERC20 is happening, with a `zapNative \u003e 0` request.\n // In both cases, we need to transfer the full msg.value to the recipient.\n Address.sendValue(payable(to), msg.value);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) public onlyRole(RELAYER_ROLE) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n\n // Can only prove a REQUESTED transaction\n if ($.status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n // Update status to RELAYER_PROVED and store the proof details\n // Note: these are storage writes\n $.status = BridgeStatus.RELAYER_PROVED;\n $.proofBlockTimestamp = uint56(block.timestamp);\n $.proofRelayer = relayer;\n\n emit BridgeProofProvided(transactionId, relayer, destTxHash);\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes calldata request, address to) public {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Aggregate the read operations from the same storage slot\n address proofRelayer = $.proofRelayer;\n BridgeStatus status = $.status;\n uint56 proofBlockTimestamp = $.proofBlockTimestamp;\n\n // Can only claim a RELAYER_PROVED transaction after the dispute period\n if (status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(proofBlockTimestamp) \u003c= DISPUTE_PERIOD) {\n revert DisputePeriodNotPassed();\n }\n\n if (to == address(0)) {\n // Anyone could claim the funds to the proven relayer on their behalf\n to = proofRelayer;\n } else if (proofRelayer != msg.sender) {\n // Only the proven relayer could specify an address to claim the funds to\n revert SenderIncorrect();\n }\n\n // Update status to RELAYER_CLAIMED and transfer the origin collateral to the specified claim address\n // Note: this is a storage write\n $.status = BridgeStatus.RELAYER_CLAIMED;\n\n address token = request.originToken();\n uint256 amount = request.originAmount();\n // Update protocol fees if origin fee amount exists\n uint256 originFeeAmount = request.originFeeAmount();\n if (originFeeAmount \u003e 0) protocolFees[token] += originFeeAmount;\n // Emit the event before any external calls\n emit BridgeDepositClaimed(transactionId, proofRelayer, to, token, amount);\n // Complete the relayer claim as the last transaction action\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(to), amount);\n } else {\n IERC20(token).safeTransfer(to, amount);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeStatuses(bytes32 transactionId) public view returns (BridgeStatus status) {\n return bridgeTxDetails[transactionId].status;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeProofs(bytes32 transactionId) public view returns (uint96 timestamp, address relayer) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n\n timestamp = $.proofBlockTimestamp;\n relayer = $.proofRelayer;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeRelays(bytes32 transactionId) public view returns (bool) {\n // has this transactionId been relayed?\n return bridgeRelayDetails[transactionId].relayer != address(0);\n }\n\n /// @notice Takes the bridged asset from the user into FastBridgeV2 custody. It will be later\n /// claimed by the relayer who completed the relay on destination chain, or refunded back to the user,\n /// should no one complete the relay.\n function _takeBridgedUserAsset(address token, uint256 amount) internal returns (uint256 amountTaken) {\n if (token == NATIVE_GAS_TOKEN) {\n // For the native gas token, we just need to check that the supplied msg.value is correct.\n // Supplied `msg.value` is already in FastBridgeV2 custody.\n if (amount != msg.value) revert MsgValueIncorrect();\n amountTaken = msg.value;\n } else {\n // For ERC20s, token is explicitly transferred from the user to FastBridgeV2.\n // We don't allow non-zero `msg.value` to avoid extra funds from being stuck in FastBridgeV2.\n if (msg.value != 0) revert MsgValueIncorrect();\n // Throw an explicit error if the provided token address is not a contract\n if (token.code.length == 0) revert TokenNotContract();\n amountTaken = IERC20(token).balanceOf(address(this));\n IERC20(token).safeTransferFrom(msg.sender, address(this), amount);\n // Use the balance difference as the amount taken in case of fee on transfer tokens.\n amountTaken = IERC20(token).balanceOf(address(this)) - amountTaken;\n }\n }\n\n /// @notice Calls the Recipient's hook function with the specified zapData and performs\n /// all the necessary checks for the returned value.\n function _triggerZapWithChecks(address recipient, address token, uint256 amount, bytes calldata zapData) internal {\n // This will bubble any revert messages from the hook function\n bytes memory returnData = Address.functionCallWithValue({\n target: recipient,\n data: abi.encodeCall(IZapRecipient.zap, (token, amount, zapData)),\n // Note: see `relay()` for reasoning behind passing msg.value\n value: msg.value\n });\n // Explicit revert if no return data at all\n if (returnData.length == 0) revert RecipientNoReturnValue();\n // Check that exactly a single return value was returned\n if (returnData.length != 32) revert RecipientIncorrectReturnValue();\n // Return value should be abi-encoded hook function selector\n if (bytes32(returnData) != bytes32(IZapRecipient.zap.selector)) {\n revert RecipientIncorrectReturnValue();\n }\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint56(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint56).max but\n /// proof.timestamp \u003c type(uint56).max via unchecked statement\n /// @param proofBlockTimestamp The bridge proof block timestamp\n /// @return delta Time delta since proof submitted\n function _timeSince(uint56 proofBlockTimestamp) internal view returns (uint256 delta) {\n unchecked {\n delta = uint56(block.timestamp) - proofBlockTimestamp;\n }\n }\n\n /// @notice Performs all the necessary checks for a bridge to happen.\n /// @dev There's no good way to refactor this function to reduce cyclomatic complexity due to\n /// the number of checks that need to be performed, so we skip the code-complexity rule here.\n // solhint-disable-next-line code-complexity\n function _validateBridgeParams(\n BridgeParams memory params,\n BridgeParamsV2 memory paramsV2,\n int256 exclusivityEndTime\n )\n internal\n view\n {\n // Check V1 (legacy) params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.sender == address(0) || params.to == address(0)) revert ZeroAddress();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n // Check V2 params\n if (paramsV2.zapData.length \u003e MAX_ZAP_DATA_LENGTH) revert ZapDataLengthAboveMax();\n if (paramsV2.zapNative != 0 \u0026\u0026 params.destToken == NATIVE_GAS_TOKEN) {\n revert ZapNativeNotSupported();\n }\n // exclusivityEndTime must be in range [0 .. params.deadline]\n if (exclusivityEndTime \u003c 0 || exclusivityEndTime \u003e int256(params.deadline)) {\n revert ExclusivityParamsIncorrect();\n }\n }\n\n /// @notice Performs all the necessary checks for a relay to happen.\n function _validateRelayParams(bytes calldata request, bytes32 transactionId, address relayer) internal view {\n if (relayer == address(0)) revert ZeroAddress();\n // Check if the transaction has already been relayed\n if (bridgeRelays(transactionId)) revert TransactionRelayed();\n if (request.destChainId() != block.chainid) revert ChainIncorrect();\n // Check the deadline for relay to happen\n if (block.timestamp \u003e request.deadline()) revert DeadlineExceeded();\n // Check the exclusivity period, if it is still ongoing\n address exclRelayer = request.exclusivityRelayer();\n if (exclRelayer != address(0) \u0026\u0026 exclRelayer != relayer \u0026\u0026 block.timestamp \u003c= request.exclusivityEndTime()) {\n revert ExclusivityPeriodNotPassed();\n }\n }\n}\n","language":"Solidity","languageVersion":"0.8.24","compilerVersion":"0.8.24","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"73773:2551:0:-:0;;;;;;;;;;;;;;;-1:-1:-1;;;73773:2551:0;;;;;;;;;;;;;;;;;","srcMapRuntime":"73773:2551:0:-:0;;;;;;;;","abiDefinition":[],"userDoc":{"kind":"user","methods":{},"version":1},"developerDoc":{"kind":"dev","methods":{},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[],\"devdoc\":{\"kind\":\"dev\",\"methods\":{},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeV2.sol\":\"UniversalTokenLib\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeV2.sol\":{\"keccak256\":\"0x5069b55ca07f21bfe30b2a43c18a18318c8af9c181b2dcb07c290825efd70f34\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://273dc020a49d08e50126bbea0d7f783f79d08c702f2fdbc560618d24af308acc\",\"dweb:/ipfs/QmXJ2UVzFc8EPB74RT4CXQPC4xw66jt4T13poyfyd3UERh\"]}},\"version\":1}"},"hashes":{}}} \ No newline at end of file +{"solidity/FastBridgeV2.sol:AccessControl":{"code":"0x","runtime-code":"0x","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.24 ^0.8.20 ^0.8.4;\n\n// contracts/interfaces/IAdminV2.sol\n\ninterface IAdminV2 {\n event CancelDelayUpdated(uint256 oldCancelDelay, uint256 newCancelDelay);\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n function setCancelDelay(uint256 newCancelDelay) external;\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n}\n\n// contracts/interfaces/IAdminV2Errors.sol\n\ninterface IAdminV2Errors {\n error CancelDelayBelowMin();\n error FeeRateAboveMax();\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IFastBridgeV2Errors.sol\n\ninterface IFastBridgeV2Errors {\n error AmountIncorrect();\n error ChainIncorrect();\n error ExclusivityParamsIncorrect();\n error MsgValueIncorrect();\n error SenderIncorrect();\n error StatusIncorrect();\n error TokenNotContract();\n error ZapDataLengthAboveMax();\n error ZapNativeNotSupported();\n error ZeroAddress();\n\n error RecipientIncorrectReturnValue();\n error RecipientNoReturnValue();\n\n error DeadlineExceeded();\n error DeadlineNotExceeded();\n error DeadlineTooShort();\n error DisputePeriodNotPassed();\n error DisputePeriodPassed();\n error ExclusivityPeriodNotPassed();\n\n error TransactionRelayed();\n}\n\n// contracts/interfaces/IMulticallTarget.sol\n\n/// @notice Interface for a contract that can be called multiple times by the same caller. Inspired by MulticallV3:\n/// https://github.com/mds1/multicall/blob/master/src/Multicall3.sol\ninterface IMulticallTarget {\n struct Result {\n bool success;\n bytes returnData;\n }\n\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external;\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results);\n}\n\n// contracts/interfaces/IZapRecipient.sol\n\ninterface IZapRecipient {\n function zap(address token, uint256 amount, bytes memory zapData) external payable returns (bytes4);\n}\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// contracts/interfaces/IFastBridgeV2.sol\n\ninterface IFastBridgeV2 is IFastBridge {\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n struct BridgeTxDetails {\n BridgeStatus status;\n uint32 destChainId;\n uint56 proofBlockTimestamp;\n address proofRelayer;\n }\n\n struct BridgeRelay {\n uint48 blockNumber;\n uint48 blockTimestamp;\n address relayer;\n }\n\n /// @notice New params introduced in the FastBridgeV2.\n /// We are passing fields from the older BridgeParams struct outside of this struct\n /// for backwards compatibility.\n /// Note: quoteRelayer and quoteExclusivitySeconds are either both zero (indicating no exclusivity)\n /// or both non-zero (indicating exclusivity for the given period).\n /// Note: zapNative \u003e 0 can NOT be used with destToken = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE (native token)\n /// @param quoteRelayer Relayer that provided the quote for the transaction\n /// @param quoteExclusivitySeconds Period of time the quote relayer is guaranteed exclusivity after user's deposit\n /// @param quoteId Unique quote identifier used for tracking the quote\n /// @param zapNative ETH value to send to the recipient (if any)\n /// @param zapData Parameters for the Zap to the destination recipient (if any)\n struct BridgeParamsV2 {\n address quoteRelayer;\n int256 quoteExclusivitySeconds;\n bytes quoteId;\n uint256 zapNative;\n bytes zapData;\n }\n\n /// @notice Updated bridge transaction struct to include parameters introduced in FastBridgeV2.\n /// Note: only `exclusivityRelayer` can fill such a transaction until `exclusivityEndTime`.\n struct BridgeTransactionV2 {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n // Note: sendChainGas flag from V1 is deprecated\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n address exclusivityRelayer;\n uint256 exclusivityEndTime;\n uint256 zapNative; // ETH value to send to the recipient (if any)\n bytes zapData; // data to pass for the Zap action (if any)\n }\n\n event BridgeQuoteDetails(bytes32 indexed transactionId, bytes quoteId);\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability\n /// to provide temporary exclusivity fill rights for the quote relayer.\n /// @param params The parameters required to bridge\n /// @param paramsV2 The parameters for exclusivity fill rights (optional, can be left empty)\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function relay(bytes memory request, address relayer) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param transactionId The transaction id associated with the encoded bridge transaction to prove\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital.\n /// @notice Can only send funds to the relayer address on the proof.\n /// @param request The encoded bridge transaction to claim on origin chain\n function claim(bytes memory request) external;\n\n /// @notice Cancels an outstanding bridge transaction in case optimistic bridging failed and returns the full amount\n /// to the original sender.\n /// @param request The encoded bridge transaction to refund\n function cancel(bytes memory request) external;\n\n /// @notice Checks if a transaction has been relayed\n /// @param transactionId The ID of the transaction to check\n /// @return True if the transaction has been relayed, false otherwise\n function bridgeRelays(bytes32 transactionId) external view returns (bool);\n\n /// @notice Returns the status of a bridge transaction\n /// @param transactionId The ID of the bridge transaction\n /// @return BridgeStatus Status of the bridge transaction\n function bridgeStatuses(bytes32 transactionId) external view returns (BridgeStatus);\n\n /// @notice Returns the timestamp and relayer of a bridge proof\n /// @param transactionId The ID of the bridge transaction\n /// @return timestamp The timestamp of the bridge proof\n /// @return relayer The relayer address of the bridge proof\n function bridgeProofs(bytes32 transactionId) external view returns (uint96 timestamp, address relayer);\n\n /// @notice Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\n /// @param request The bridge request to decode\n function getBridgeTransactionV2(bytes memory request) external view returns (BridgeTransactionV2 memory);\n}\n\n// contracts/utils/MulticallTarget.sol\n\n// solhint-disable avoid-low-level-calls\n/// @notice Template for a contract that supports batched calls (preserving the msg.sender).\n/// Only calls with zero msg.value could be batched.\nabstract contract MulticallTarget is IMulticallTarget {\n error MulticallTarget__UndeterminedRevert();\n\n /// @notice Perform a batched call to this contract, preserving the msg.sender.\n /// The return data from each call is discarded.\n /// @dev The method is non-payable, so only calls with `msg.value == 0` could be batched.\n /// It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag.\n /// Otherwise, the whole batch call will be reverted with the original revert reason.\n /// @param data List of abi-encoded calldata for the calls to perform.\n /// @param ignoreReverts Whether to ignore the revert errors from the calls.\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external {\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\n if (!success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(result);\n }\n }\n }\n\n /// @notice Perform a batched call to this contract, preserving the msg.sender.\n /// The return data from each call is preserved.\n /// @dev The method is non-payable, so only calls with `msg.value == 0` could be batched.\n /// It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag.\n /// Otherwise, the whole batch call will be reverted with the original revert reason.\n /// @param data List of abi-encoded calldata for the calls to perform.\n /// @param ignoreReverts Whether to ignore the revert errors from the calls.\n /// @return results List of results from the calls: `(success, returnData)`.\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results)\n {\n results = new Result[](data.length);\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (results[i].success, results[i].returnData) = address(this).delegatecall(data[i]);\n if (!results[i].success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(results[i].returnData);\n }\n }\n }\n\n /// @dev Bubbles the revert message from the underlying call.\n /// Note: preserves the same custom error or revert string, if one was used.\n /// Source: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v5.0.2/contracts/utils/Address.sol#L143-L158\n function _bubbleRevert(bytes memory returnData) internal pure {\n // Look for revert reason and bubble it up if present\n if (returnData.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n // solhint-disable-next-line no-inline-assembly\n assembly {\n let returndata_size := mload(returnData)\n revert(add(32, returnData), returndata_size)\n }\n } else {\n revert MulticallTarget__UndeterminedRevert();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// contracts/libs/BridgeTransactionV2.sol\n\n// solhint-disable no-inline-assembly\nlibrary BridgeTransactionV2Lib {\n uint16 internal constant VERSION = 2;\n\n // Offsets of the fields in the packed BridgeTransactionV2 struct\n // uint16 version [000 .. 002)\n // uint32 originChainId [002 .. 006)\n // uint32 destChainId [006 .. 010)\n // address originSender [010 .. 030)\n // address destRecipient [030 .. 050)\n // address originToken [050 .. 070)\n // address destToken [070 .. 090)\n // uint256 originAmount [090 .. 122)\n // uint256 destAmount [122 .. 154)\n // uint256 originFeeAmount [154 .. 186)\n // uint256 deadline [186 .. 218)\n // uint256 nonce [218 .. 250)\n // address exclusivityRelayer [250 .. 270)\n // uint256 exclusivityEndTime [270 .. 302)\n // uint256 zapNative [302 .. 334)\n // bytes zapData [334 .. ***)\n\n // forgefmt: disable-start\n uint256 private constant OFFSET_ORIGIN_CHAIN_ID = 2;\n uint256 private constant OFFSET_DEST_CHAIN_ID = 6;\n uint256 private constant OFFSET_ORIGIN_SENDER = 10;\n uint256 private constant OFFSET_DEST_RECIPIENT = 30;\n uint256 private constant OFFSET_ORIGIN_TOKEN = 50;\n uint256 private constant OFFSET_DEST_TOKEN = 70;\n uint256 private constant OFFSET_ORIGIN_AMOUNT = 90;\n uint256 private constant OFFSET_DEST_AMOUNT = 122;\n uint256 private constant OFFSET_ORIGIN_FEE_AMOUNT = 154;\n uint256 private constant OFFSET_DEADLINE = 186;\n uint256 private constant OFFSET_NONCE = 218;\n uint256 private constant OFFSET_EXCLUSIVITY_RELAYER = 250;\n uint256 private constant OFFSET_EXCLUSIVITY_END_TIME = 270;\n uint256 private constant OFFSET_ZAP_NATIVE = 302;\n uint256 private constant OFFSET_ZAP_DATA = 334;\n // forgefmt: disable-end\n\n error BridgeTransactionV2__InvalidEncodedTx();\n error BridgeTransactionV2__UnsupportedVersion(uint16 version);\n\n /// @notice Validates the encoded transaction to be a tightly packed encoded payload for BridgeTransactionV2.\n /// @dev Checks the minimum length and the version, use this function before decoding any of the fields.\n function validateV2(bytes calldata encodedTx) internal pure {\n // Check the minimum length: must at least include all static fields.\n if (encodedTx.length \u003c OFFSET_ZAP_DATA) revert BridgeTransactionV2__InvalidEncodedTx();\n // Once we validated the length, we can be sure that the version field is present.\n uint16 version_ = version(encodedTx);\n if (version_ != VERSION) revert BridgeTransactionV2__UnsupportedVersion(version_);\n }\n\n /// @notice Encodes the BridgeTransactionV2 struct by tightly packing the fields.\n /// @dev `abi.decode` will not work as a result of the tightly packed fields. Use `decodeV2` to decode instead.\n function encodeV2(IFastBridgeV2.BridgeTransactionV2 memory bridgeTx) internal pure returns (bytes memory) {\n // We split the encoding into two parts to avoid stack-too-deep error\n bytes memory firstPart = abi.encodePacked(\n VERSION,\n bridgeTx.originChainId,\n bridgeTx.destChainId,\n bridgeTx.originSender,\n bridgeTx.destRecipient,\n bridgeTx.originToken,\n bridgeTx.destToken,\n bridgeTx.originAmount\n );\n return abi.encodePacked(\n firstPart,\n bridgeTx.destAmount,\n bridgeTx.originFeeAmount,\n // Note: we skip the deprecated `sendChainGas` flag, which was present in BridgeTransaction V1\n bridgeTx.deadline,\n bridgeTx.nonce,\n // New V2 fields: exclusivity\n bridgeTx.exclusivityRelayer,\n bridgeTx.exclusivityEndTime,\n // New V2 fields: Zap\n bridgeTx.zapNative,\n bridgeTx.zapData\n );\n }\n\n /// @notice Decodes the BridgeTransactionV2 struct from the encoded transaction.\n /// @dev Encoded BridgeTransactionV2 struct must be tightly packed.\n /// Use `validateV2` before decoding to ensure the encoded transaction is valid.\n function decodeV2(bytes calldata encodedTx)\n internal\n pure\n returns (IFastBridgeV2.BridgeTransactionV2 memory bridgeTx)\n {\n bridgeTx.originChainId = originChainId(encodedTx);\n bridgeTx.destChainId = destChainId(encodedTx);\n bridgeTx.originSender = originSender(encodedTx);\n bridgeTx.destRecipient = destRecipient(encodedTx);\n bridgeTx.originToken = originToken(encodedTx);\n bridgeTx.destToken = destToken(encodedTx);\n bridgeTx.originAmount = originAmount(encodedTx);\n bridgeTx.destAmount = destAmount(encodedTx);\n bridgeTx.originFeeAmount = originFeeAmount(encodedTx);\n bridgeTx.deadline = deadline(encodedTx);\n bridgeTx.nonce = nonce(encodedTx);\n bridgeTx.exclusivityRelayer = exclusivityRelayer(encodedTx);\n bridgeTx.exclusivityEndTime = exclusivityEndTime(encodedTx);\n bridgeTx.zapNative = zapNative(encodedTx);\n bridgeTx.zapData = zapData(encodedTx);\n }\n\n /// @notice Extracts the version from the encoded transaction.\n function version(bytes calldata encodedTx) internal pure returns (uint16 version_) {\n // Load 32 bytes from the start and shift it 240 bits to the right to get the highest 16 bits.\n assembly {\n version_ := shr(240, calldataload(encodedTx.offset))\n }\n }\n\n /// @notice Extracts the origin chain ID from the encoded transaction.\n function originChainId(bytes calldata encodedTx) internal pure returns (uint32 originChainId_) {\n // Load 32 bytes from the offset and shift it 224 bits to the right to get the highest 32 bits.\n assembly {\n originChainId_ := shr(224, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_CHAIN_ID)))\n }\n }\n\n /// @notice Extracts the destination chain ID from the encoded transaction.\n function destChainId(bytes calldata encodedTx) internal pure returns (uint32 destChainId_) {\n // Load 32 bytes from the offset and shift it 224 bits to the right to get the highest 32 bits.\n assembly {\n destChainId_ := shr(224, calldataload(add(encodedTx.offset, OFFSET_DEST_CHAIN_ID)))\n }\n }\n\n /// @notice Extracts the origin sender from the encoded transaction.\n function originSender(bytes calldata encodedTx) internal pure returns (address originSender_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n originSender_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_SENDER)))\n }\n }\n\n /// @notice Extracts the destination recipient from the encoded transaction.\n function destRecipient(bytes calldata encodedTx) internal pure returns (address destRecipient_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n destRecipient_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_DEST_RECIPIENT)))\n }\n }\n\n /// @notice Extracts the origin token from the encoded transaction.\n function originToken(bytes calldata encodedTx) internal pure returns (address originToken_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n originToken_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_TOKEN)))\n }\n }\n\n /// @notice Extracts the destination token from the encoded transaction.\n function destToken(bytes calldata encodedTx) internal pure returns (address destToken_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n destToken_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_DEST_TOKEN)))\n }\n }\n\n /// @notice Extracts the origin amount from the encoded transaction.\n function originAmount(bytes calldata encodedTx) internal pure returns (uint256 originAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n originAmount_ := calldataload(add(encodedTx.offset, OFFSET_ORIGIN_AMOUNT))\n }\n }\n\n /// @notice Extracts the destination amount from the encoded transaction.\n function destAmount(bytes calldata encodedTx) internal pure returns (uint256 destAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n destAmount_ := calldataload(add(encodedTx.offset, OFFSET_DEST_AMOUNT))\n }\n }\n\n /// @notice Extracts the origin fee amount from the encoded transaction.\n function originFeeAmount(bytes calldata encodedTx) internal pure returns (uint256 originFeeAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n originFeeAmount_ := calldataload(add(encodedTx.offset, OFFSET_ORIGIN_FEE_AMOUNT))\n }\n }\n\n /// @notice Extracts the deadline from the encoded transaction.\n function deadline(bytes calldata encodedTx) internal pure returns (uint256 deadline_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n deadline_ := calldataload(add(encodedTx.offset, OFFSET_DEADLINE))\n }\n }\n\n /// @notice Extracts the nonce from the encoded transaction.\n function nonce(bytes calldata encodedTx) internal pure returns (uint256 nonce_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n nonce_ := calldataload(add(encodedTx.offset, OFFSET_NONCE))\n }\n }\n\n /// @notice Extracts the exclusivity relayer from the encoded transaction.\n function exclusivityRelayer(bytes calldata encodedTx) internal pure returns (address exclusivityRelayer_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n exclusivityRelayer_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_EXCLUSIVITY_RELAYER)))\n }\n }\n\n /// @notice Extracts the exclusivity end time from the encoded transaction.\n function exclusivityEndTime(bytes calldata encodedTx) internal pure returns (uint256 exclusivityEndTime_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n exclusivityEndTime_ := calldataload(add(encodedTx.offset, OFFSET_EXCLUSIVITY_END_TIME))\n }\n }\n\n /// @notice Extracts the Zap's native value from the encoded transaction.\n function zapNative(bytes calldata encodedTx) internal pure returns (uint256 zapNative_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n zapNative_ := calldataload(add(encodedTx.offset, OFFSET_ZAP_NATIVE))\n }\n }\n\n /// @notice Extracts the Zap's data from the encoded transaction.\n function zapData(bytes calldata encodedTx) internal pure returns (bytes calldata zapData_) {\n zapData_ = encodedTx[OFFSET_ZAP_DATA:];\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/AdminV2.sol\n\ncontract AdminV2 is AccessControlEnumerable, IAdminV2, IAdminV2Errors {\n using SafeERC20 for IERC20;\n\n /// @notice Address reserved for native gas token (ETH on Ethereum and most L2s, AVAX on Avalanche, etc)\n address public constant NATIVE_GAS_TOKEN = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Role identifier for Quoter API's off-chain authentication.\n /// @dev Only addresses with this role can post FastBridge quotes to the API.\n bytes32 public constant QUOTER_ROLE = keccak256(\"QUOTER_ROLE\");\n\n /// @notice Role identifier for Prover's on-chain authentication in FastBridge.\n /// @dev Only addresses with this role can provide proofs that a FastBridge request has been relayed.\n bytes32 public constant PROVER_ROLE = keccak256(\"PROVER_ROLE\");\n\n /// @notice Role identifier for Guard's on-chain authentication in FastBridge.\n /// @dev Only addresses with this role can dispute submitted relay proofs during the dispute period.\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n\n /// @notice Role identifier for Canceler's on-chain authentication in FastBridge.\n /// @dev Only addresses with this role can cancel a FastBridge transaction without the cancel delay.\n bytes32 public constant CANCELER_ROLE = keccak256(\"CANCELER_ROLE\");\n\n /// @notice Role identifier for Governor's on-chain administrative authority.\n /// @dev Only addresses with this role can perform administrative tasks within the contract.\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n /// @notice Denominator for fee rates, represents 100%.\n uint256 public constant FEE_BPS = 1e6;\n /// @notice Maximum protocol fee rate: 1% on origin amount.\n uint256 public constant FEE_RATE_MAX = 0.01e6;\n\n /// @notice Minimum cancel delay that can be set by the governor.\n uint256 public constant MIN_CANCEL_DELAY = 1 hours;\n /// @notice Default cancel delay set during the contract deployment.\n uint256 public constant DEFAULT_CANCEL_DELAY = 1 days;\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Delay for a transaction after which it could be permisionlessly cancelled\n uint256 public cancelDelay;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Use ZapNative V2 requests instead.\n uint256 public immutable chainGasAmount = 0;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n _setCancelDelay(DEFAULT_CANCEL_DELAY);\n }\n\n /// @notice Allows the contract governor to set the cancel delay. The cancel delay is the time after the transaction\n /// deadline after which it can be permissionlessly cancelled, if it hasn't been proven by any of the Relayers.\n function setCancelDelay(uint256 newCancelDelay) external onlyRole(GOVERNOR_ROLE) {\n _setCancelDelay(newCancelDelay);\n }\n\n /// @notice Allows the contract governor to set the protocol fee rate. The protocol fee is taken from the origin\n /// amount only for completed and claimed transactions.\n /// @dev The protocol fee is abstracted away from the relayers, they always operate using the amounts after fees:\n /// what they see as the origin amount emitted in the log is what they get credited with.\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n if (newFeeRate \u003e FEE_RATE_MAX) revert FeeRateAboveMax();\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n /// @notice Allows the contract governor to sweep the accumulated protocol fees in the contract.\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n emit FeesSwept(token, recipient, feeAmount);\n /// Sweep the fees as the last transaction action\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(recipient), feeAmount);\n } else {\n IERC20(token).safeTransfer(recipient, feeAmount);\n }\n }\n\n /// @notice Internal function to set the cancel delay. Security checks are performed outside of this function.\n function _setCancelDelay(uint256 newCancelDelay) private {\n if (newCancelDelay \u003c MIN_CANCEL_DELAY) revert CancelDelayBelowMin();\n uint256 oldCancelDelay = cancelDelay;\n cancelDelay = newCancelDelay;\n emit CancelDelayUpdated(oldCancelDelay, newCancelDelay);\n }\n}\n\n// contracts/FastBridgeV2.sol\n\n/// @notice FastBridgeV2 is a contract for bridging tokens across chains.\ncontract FastBridgeV2 is AdminV2, MulticallTarget, IFastBridgeV2, IFastBridgeV2Errors {\n using BridgeTransactionV2Lib for bytes;\n using SafeERC20 for IERC20;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n /// @notice Maximum length of accepted zapData\n uint256 public constant MAX_ZAP_DATA_LENGTH = 2 ** 16 - 1;\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeTxDetails) public bridgeTxDetails;\n /// @notice Relay details on destination chain\n mapping(bytes32 =\u003e BridgeRelay) public bridgeRelayDetails;\n /// @notice Unique bridge nonces tracked per originSender\n mapping(address =\u003e uint256) public senderNonces;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Replaced by senderNonces\n uint256 public immutable nonce = 0;\n /// @notice the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) AdminV2(_owner) {\n deployBlock = block.number;\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n bridge({\n params: params,\n paramsV2: BridgeParamsV2({\n quoteRelayer: address(0),\n quoteExclusivitySeconds: 0,\n quoteId: bytes(\"\"),\n zapNative: 0,\n zapData: bytes(\"\")\n })\n });\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes calldata request) external payable {\n // relay override will validate the request\n relay({request: request, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes calldata request, bytes32 destTxHash) external {\n request.validateV2();\n prove({transactionId: keccak256(request), destTxHash: destTxHash, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridgeV2\n function claim(bytes calldata request) external {\n // claim override will validate the request\n claim({request: request, to: address(0)});\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Aggregate the read operations from the same storage slot\n address disputedRelayer = $.proofRelayer;\n BridgeStatus status = $.status;\n uint56 proofBlockTimestamp = $.proofBlockTimestamp;\n // Can only dispute a RELAYER_PROVED transaction within the dispute period\n if (status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(proofBlockTimestamp) \u003e DISPUTE_PERIOD) {\n revert DisputePeriodPassed();\n }\n // Update status to REQUESTED and delete the disputed proof details\n // Note: these are storage writes\n $.status = BridgeStatus.REQUESTED;\n $.proofRelayer = address(0);\n $.proofBlockTimestamp = 0;\n\n emit BridgeProofDisputed(transactionId, disputedRelayer);\n }\n\n /// Note: this function is deprecated and will be removed in a future version.\n /// @inheritdoc IFastBridge\n function refund(bytes calldata request) external {\n cancel(request);\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // The correct relayer can only claim a RELAYER_PROVED transaction after the dispute period\n if ($.status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if ($.proofRelayer != relayer) revert SenderIncorrect();\n return _timeSince($.proofBlockTimestamp) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n /// @dev This method is added to achieve backwards compatibility with decoding requests into V1 structs:\n /// - `zapNative` is partially reported as a zero/non-zero flag\n /// - `zapData` is ignored\n /// In order to process all kinds of requests use getBridgeTransactionV2 instead.\n function getBridgeTransaction(bytes calldata request) external view returns (BridgeTransaction memory) {\n // Try decoding into V2 struct first. This will revert if V1 struct is passed\n try this.getBridgeTransactionV2(request) returns (BridgeTransactionV2 memory txV2) {\n // Note: we entirely ignore the zapData field, as it was not present in V1\n return BridgeTransaction({\n originChainId: txV2.originChainId,\n destChainId: txV2.destChainId,\n originSender: txV2.originSender,\n destRecipient: txV2.destRecipient,\n originToken: txV2.originToken,\n destToken: txV2.destToken,\n originAmount: txV2.originAmount,\n destAmount: txV2.destAmount,\n originFeeAmount: txV2.originFeeAmount,\n sendChainGas: txV2.zapNative != 0,\n deadline: txV2.deadline,\n nonce: txV2.nonce\n });\n } catch {\n // Fallback to V1 struct\n return abi.decode(request, (BridgeTransaction));\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function getBridgeTransactionV2(bytes calldata request) external pure returns (BridgeTransactionV2 memory) {\n request.validateV2();\n return BridgeTransactionV2Lib.decodeV2(request);\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) public payable {\n int256 exclusivityEndTime = 0;\n // if relayer exclusivity is not intended for this bridge, set exclusivityEndTime to static zero\n // otherwise, set exclusivity to expire at the current block ts offset by quoteExclusivitySeconds\n if (paramsV2.quoteRelayer != address(0)) {\n exclusivityEndTime = int256(block.timestamp) + paramsV2.quoteExclusivitySeconds;\n }\n _validateBridgeParams(params, paramsV2, exclusivityEndTime);\n\n // transfer tokens to bridge contract\n /// @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _takeBridgedUserAsset(params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) {\n originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n }\n\n // set status to requested\n bytes memory request = BridgeTransactionV2Lib.encodeV2(\n BridgeTransactionV2({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n deadline: params.deadline,\n nonce: senderNonces[params.sender]++, // increment nonce on every bridge\n exclusivityRelayer: paramsV2.quoteRelayer,\n // We checked exclusivityEndTime to be in range [0 .. params.deadline] above, so can safely cast\n exclusivityEndTime: uint256(exclusivityEndTime),\n zapNative: paramsV2.zapNative,\n zapData: paramsV2.zapData\n })\n );\n bytes32 transactionId = keccak256(request);\n // Note: the tx status will be updated throughout the tx lifecycle, while destChainId is set once here\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n bridgeTxDetails[transactionId].destChainId = params.dstChainId;\n\n emit BridgeRequested({\n transactionId: transactionId,\n sender: params.sender,\n request: request,\n destChainId: params.dstChainId,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n sendChainGas: paramsV2.zapNative != 0\n });\n emit BridgeQuoteDetails(transactionId, paramsV2.quoteId);\n }\n\n /// @inheritdoc IFastBridgeV2\n function relay(bytes calldata request, address relayer) public payable {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n _validateRelayParams(request, transactionId, relayer);\n // mark bridge transaction as relayed\n bridgeRelayDetails[transactionId] =\n BridgeRelay({blockNumber: uint48(block.number), blockTimestamp: uint48(block.timestamp), relayer: relayer});\n\n // transfer tokens to recipient on destination chain and trigger Zap if requested\n address to = request.destRecipient();\n address token = request.destToken();\n uint256 amount = request.destAmount();\n uint256 zapNative = request.zapNative();\n\n // Emit the event before any external calls\n emit BridgeRelayed({\n transactionId: transactionId,\n relayer: relayer,\n to: to,\n originChainId: request.originChainId(),\n originToken: request.originToken(),\n destToken: token,\n originAmount: request.originAmount(),\n destAmount: amount,\n chainGasAmount: zapNative\n });\n\n // All state changes have been done at this point, can proceed to the external calls.\n // This follows the checks-effects-interactions pattern to mitigate potential reentrancy attacks.\n if (token == NATIVE_GAS_TOKEN) {\n // For the native gas token, additional zapNative is not allowed\n if (zapNative != 0) revert ZapNativeNotSupported();\n // Check that the correct msg.value was sent\n if (msg.value != amount) revert MsgValueIncorrect();\n // Don't do a native transfer yet: we will handle it alongside the Zap below\n } else {\n // For ERC20s, we check that the correct msg.value was sent\n if (msg.value != zapNative) revert MsgValueIncorrect();\n // We need to transfer the tokens from the Relayer to the recipient first before performing an\n // optional post-transfer Zap.\n IERC20(token).safeTransferFrom(msg.sender, to, amount);\n }\n // At this point we have done:\n // - Transferred the requested amount of ERC20 tokens to the recipient.\n // At this point we have confirmed:\n // - For ERC20s: msg.value matches the requested zapNative amount.\n // - For the native gas token: msg.value matches the requested destAmount.\n // Remaining optional things to do:\n // - Forward the full msg.value to the recipient (if non-zero).\n // - Trigger a Zap (if zapData is present).\n bytes calldata zapData = request.zapData();\n if (zapData.length != 0) {\n // Zap Data is present: Zap has been requested by the recipient. Trigger it forwarding the full msg.value.\n\n // Note: if token has a fee on transfers, the recipient will have received less than `amount`.\n // This is a very niche edge case and should be handled by the recipient contract.\n _triggerZapWithChecks({recipient: to, token: token, amount: amount, zapData: zapData});\n } else if (msg.value != 0) {\n // Zap Data is missing, but msg.value was sent. This could happen in two different cases:\n // - Relay with the native gas token is happening.\n // - Relay with ERC20 is happening, with a `zapNative \u003e 0` request.\n // In both cases, we need to transfer the full msg.value to the recipient.\n Address.sendValue(payable(to), msg.value);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) public onlyRole(PROVER_ROLE) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n\n // Can only prove a REQUESTED transaction\n if ($.status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n // Update status to RELAYER_PROVED and store the proof details\n // Note: these are storage writes\n $.status = BridgeStatus.RELAYER_PROVED;\n $.proofBlockTimestamp = uint56(block.timestamp);\n $.proofRelayer = relayer;\n\n emit BridgeProofProvided(transactionId, relayer, destTxHash);\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes calldata request, address to) public {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Aggregate the read operations from the same storage slot\n address proofRelayer = $.proofRelayer;\n BridgeStatus status = $.status;\n uint56 proofBlockTimestamp = $.proofBlockTimestamp;\n\n // Can only claim a RELAYER_PROVED transaction after the dispute period\n if (status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(proofBlockTimestamp) \u003c= DISPUTE_PERIOD) {\n revert DisputePeriodNotPassed();\n }\n\n if (to == address(0)) {\n // Anyone could claim the funds to the proven relayer on their behalf\n to = proofRelayer;\n } else if (proofRelayer != msg.sender) {\n // Only the proven relayer could specify an address to claim the funds to\n revert SenderIncorrect();\n }\n\n // Update status to RELAYER_CLAIMED and transfer the origin collateral to the specified claim address\n // Note: this is a storage write\n $.status = BridgeStatus.RELAYER_CLAIMED;\n\n address token = request.originToken();\n uint256 amount = request.originAmount();\n // Update protocol fees if origin fee amount exists\n uint256 originFeeAmount = request.originFeeAmount();\n if (originFeeAmount \u003e 0) protocolFees[token] += originFeeAmount;\n // Emit the event before any external calls\n emit BridgeDepositClaimed(transactionId, proofRelayer, to, token, amount);\n // Complete the relayer claim as the last transaction action\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(to), amount);\n } else {\n IERC20(token).safeTransfer(to, amount);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function cancel(bytes calldata request) public {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Can only cancel a REQUESTED transaction after its deadline expires\n if ($.status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n uint256 deadline = request.deadline();\n // Permissionless cancel is only allowed after `cancelDelay` on top of the deadline\n if (!hasRole(CANCELER_ROLE, msg.sender)) deadline += cancelDelay;\n if (block.timestamp \u003c= deadline) revert DeadlineNotExceeded();\n // Update status to REFUNDED and return the full amount (collateral + protocol fees) to the original sender.\n // The protocol fees are only updated when the transaction is claimed, so we don't need to update them here.\n // Note: this is a storage write\n $.status = BridgeStatus.REFUNDED;\n\n address to = request.originSender();\n address token = request.originToken();\n uint256 amount = request.originAmount() + request.originFeeAmount();\n // Emit the event before any external calls\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n // Complete the user cancel as the last transaction action\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(to), amount);\n } else {\n IERC20(token).safeTransfer(to, amount);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeStatuses(bytes32 transactionId) public view returns (BridgeStatus status) {\n return bridgeTxDetails[transactionId].status;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeProofs(bytes32 transactionId) public view returns (uint96 timestamp, address relayer) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n\n timestamp = $.proofBlockTimestamp;\n relayer = $.proofRelayer;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeRelays(bytes32 transactionId) public view returns (bool) {\n // has this transactionId been relayed?\n return bridgeRelayDetails[transactionId].relayer != address(0);\n }\n\n /// @notice Takes the bridged asset from the user into FastBridgeV2 custody. It will be later\n /// claimed by the relayer who completed the relay on destination chain, or transferred back to the user\n /// via the cancel function should no one complete the relay.\n function _takeBridgedUserAsset(address token, uint256 amount) internal returns (uint256 amountTaken) {\n if (token == NATIVE_GAS_TOKEN) {\n // For the native gas token, we just need to check that the supplied msg.value is correct.\n // Supplied `msg.value` is already in FastBridgeV2 custody.\n if (amount != msg.value) revert MsgValueIncorrect();\n amountTaken = msg.value;\n } else {\n // For ERC20s, token is explicitly transferred from the user to FastBridgeV2.\n // We don't allow non-zero `msg.value` to avoid extra funds from being stuck in FastBridgeV2.\n if (msg.value != 0) revert MsgValueIncorrect();\n // Throw an explicit error if the provided token address is not a contract\n if (token.code.length == 0) revert TokenNotContract();\n amountTaken = IERC20(token).balanceOf(address(this));\n IERC20(token).safeTransferFrom(msg.sender, address(this), amount);\n // Use the balance difference as the amount taken in case of fee on transfer tokens.\n amountTaken = IERC20(token).balanceOf(address(this)) - amountTaken;\n }\n }\n\n /// @notice Calls the Recipient's hook function with the specified zapData and performs\n /// all the necessary checks for the returned value.\n function _triggerZapWithChecks(address recipient, address token, uint256 amount, bytes calldata zapData) internal {\n // This will bubble any revert messages from the hook function\n bytes memory returnData = Address.functionCallWithValue({\n target: recipient,\n data: abi.encodeCall(IZapRecipient.zap, (token, amount, zapData)),\n // Note: see `relay()` for reasoning behind passing msg.value\n value: msg.value\n });\n // Explicit revert if no return data at all\n if (returnData.length == 0) revert RecipientNoReturnValue();\n // Check that exactly a single return value was returned\n if (returnData.length != 32) revert RecipientIncorrectReturnValue();\n // Return value should be abi-encoded hook function selector\n if (bytes32(returnData) != bytes32(IZapRecipient.zap.selector)) {\n revert RecipientIncorrectReturnValue();\n }\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint56(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint56).max but\n /// proof.timestamp \u003c type(uint56).max via unchecked statement\n /// @param proofBlockTimestamp The bridge proof block timestamp\n /// @return delta Time delta since proof submitted\n function _timeSince(uint56 proofBlockTimestamp) internal view returns (uint256 delta) {\n unchecked {\n delta = uint56(block.timestamp) - proofBlockTimestamp;\n }\n }\n\n /// @notice Performs all the necessary checks for a bridge to happen.\n /// @dev There's no good way to refactor this function to reduce cyclomatic complexity due to\n /// the number of checks that need to be performed, so we skip the code-complexity rule here.\n // solhint-disable-next-line code-complexity\n function _validateBridgeParams(\n BridgeParams memory params,\n BridgeParamsV2 memory paramsV2,\n int256 exclusivityEndTime\n )\n internal\n view\n {\n // Check V1 (legacy) params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.sender == address(0) || params.to == address(0)) revert ZeroAddress();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n // Check V2 params\n if (paramsV2.zapData.length \u003e MAX_ZAP_DATA_LENGTH) revert ZapDataLengthAboveMax();\n if (paramsV2.zapNative != 0 \u0026\u0026 params.destToken == NATIVE_GAS_TOKEN) {\n revert ZapNativeNotSupported();\n }\n // exclusivityEndTime must be in range [0 .. params.deadline]\n if (exclusivityEndTime \u003c 0 || exclusivityEndTime \u003e int256(params.deadline)) {\n revert ExclusivityParamsIncorrect();\n }\n }\n\n /// @notice Performs all the necessary checks for a relay to happen.\n function _validateRelayParams(bytes calldata request, bytes32 transactionId, address relayer) internal view {\n if (relayer == address(0)) revert ZeroAddress();\n // Check if the transaction has already been relayed\n if (bridgeRelays(transactionId)) revert TransactionRelayed();\n if (request.destChainId() != block.chainid) revert ChainIncorrect();\n // Check the deadline for relay to happen\n if (block.timestamp \u003e request.deadline()) revert DeadlineExceeded();\n // Check the exclusivity period, if it is still ongoing\n address exclRelayer = request.exclusivityRelayer();\n if (exclRelayer != address(0) \u0026\u0026 exclRelayer != relayer \u0026\u0026 block.timestamp \u003c= request.exclusivityEndTime()) {\n revert ExclusivityPeriodNotPassed();\n }\n }\n}\n","language":"Solidity","languageVersion":"0.8.24","compilerVersion":"0.8.24","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"","srcMapRuntime":"","abiDefinition":[{"inputs":[],"name":"AccessControlBadConfirmation","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"bytes32","name":"neededRole","type":"bytes32"}],"name":"AccessControlUnauthorizedAccount","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"previousAdminRole","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"newAdminRole","type":"bytes32"}],"name":"RoleAdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleRevoked","type":"event"},{"inputs":[],"name":"DEFAULT_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleAdmin","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"grantRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"hasRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"callerConfirmation","type":"address"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"revokeRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"}],"userDoc":{"kind":"user","methods":{},"version":1},"developerDoc":{"details":"Contract module that allows children to implement role-based access control mechanisms. This is a lightweight version that doesn't allow enumerating role members except through off-chain means by accessing the contract event logs. Some applications may benefit from on-chain enumerability, for those cases see {AccessControlEnumerable}. Roles are referred to by their `bytes32` identifier. These should be exposed in the external API and be unique. The best way to achieve this is by using `public constant` hash digests: ```solidity bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\"); ``` Roles can be used to represent a set of permissions. To restrict access to a function call, use {hasRole}: ```solidity function foo() public { require(hasRole(MY_ROLE, msg.sender)); ... } ``` Roles can be granted and revoked dynamically via the {grantRole} and {revokeRole} functions. Each role has an associated admin role, and only accounts that have a role's admin role can call {grantRole} and {revokeRole}. By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means that only accounts with this role will be able to grant or revoke other roles. More complex role relationships can be created by using {_setRoleAdmin}. WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to grant and revoke this role. Extra precautions should be taken to secure accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules} to enforce additional security measures for this role.","errors":{"AccessControlBadConfirmation()":[{"details":"The caller of a function is not the expected one. NOTE: Don't confuse with {AccessControlUnauthorizedAccount}."}],"AccessControlUnauthorizedAccount(address,bytes32)":[{"details":"The `account` is missing a role."}]},"events":{"RoleAdminChanged(bytes32,bytes32,bytes32)":{"details":"Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole` `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite {RoleAdminChanged} not being emitted signaling this."},"RoleGranted(bytes32,address,address)":{"details":"Emitted when `account` is granted `role`. `sender` is the account that originated the contract call, an admin role bearer except when using {AccessControl-_setupRole}."},"RoleRevoked(bytes32,address,address)":{"details":"Emitted when `account` is revoked `role`. `sender` is the account that originated the contract call: - if using `revokeRole`, it is the admin role bearer - if using `renounceRole`, it is the role bearer (i.e. `account`)"}},"kind":"dev","methods":{"getRoleAdmin(bytes32)":{"details":"Returns the admin role that controls `role`. See {grantRole} and {revokeRole}. To change a role's admin, use {_setRoleAdmin}."},"grantRole(bytes32,address)":{"details":"Grants `role` to `account`. If `account` had not been already granted `role`, emits a {RoleGranted} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleGranted} event."},"hasRole(bytes32,address)":{"details":"Returns `true` if `account` has been granted `role`."},"renounceRole(bytes32,address)":{"details":"Revokes `role` from the calling account. Roles are often managed via {grantRole} and {revokeRole}: this function's purpose is to provide a mechanism for accounts to lose their privileges if they are compromised (such as when a trusted device is misplaced). If the calling account had been revoked `role`, emits a {RoleRevoked} event. Requirements: - the caller must be `callerConfirmation`. May emit a {RoleRevoked} event."},"revokeRole(bytes32,address)":{"details":"Revokes `role` from `account`. If `account` had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleRevoked} event."},"supportsInterface(bytes4)":{"details":"See {IERC165-supportsInterface}."}},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[],\"name\":\"AccessControlBadConfirmation\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"neededRole\",\"type\":\"bytes32\"}],\"name\":\"AccessControlUnauthorizedAccount\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"previousAdminRole\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"newAdminRole\",\"type\":\"bytes32\"}],\"name\":\"RoleAdminChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleGranted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleRevoked\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"DEFAULT_ADMIN_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"}],\"name\":\"getRoleAdmin\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"grantRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"hasRole\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"callerConfirmation\",\"type\":\"address\"}],\"name\":\"renounceRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"revokeRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes4\",\"name\":\"interfaceId\",\"type\":\"bytes4\"}],\"name\":\"supportsInterface\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"}],\"devdoc\":{\"details\":\"Contract module that allows children to implement role-based access control mechanisms. This is a lightweight version that doesn't allow enumerating role members except through off-chain means by accessing the contract event logs. Some applications may benefit from on-chain enumerability, for those cases see {AccessControlEnumerable}. Roles are referred to by their `bytes32` identifier. These should be exposed in the external API and be unique. The best way to achieve this is by using `public constant` hash digests: ```solidity bytes32 public constant MY_ROLE = keccak256(\\\"MY_ROLE\\\"); ``` Roles can be used to represent a set of permissions. To restrict access to a function call, use {hasRole}: ```solidity function foo() public { require(hasRole(MY_ROLE, msg.sender)); ... } ``` Roles can be granted and revoked dynamically via the {grantRole} and {revokeRole} functions. Each role has an associated admin role, and only accounts that have a role's admin role can call {grantRole} and {revokeRole}. By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means that only accounts with this role will be able to grant or revoke other roles. More complex role relationships can be created by using {_setRoleAdmin}. WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to grant and revoke this role. Extra precautions should be taken to secure accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules} to enforce additional security measures for this role.\",\"errors\":{\"AccessControlBadConfirmation()\":[{\"details\":\"The caller of a function is not the expected one. NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\"}],\"AccessControlUnauthorizedAccount(address,bytes32)\":[{\"details\":\"The `account` is missing a role.\"}]},\"events\":{\"RoleAdminChanged(bytes32,bytes32,bytes32)\":{\"details\":\"Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole` `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite {RoleAdminChanged} not being emitted signaling this.\"},\"RoleGranted(bytes32,address,address)\":{\"details\":\"Emitted when `account` is granted `role`. `sender` is the account that originated the contract call, an admin role bearer except when using {AccessControl-_setupRole}.\"},\"RoleRevoked(bytes32,address,address)\":{\"details\":\"Emitted when `account` is revoked `role`. `sender` is the account that originated the contract call: - if using `revokeRole`, it is the admin role bearer - if using `renounceRole`, it is the role bearer (i.e. `account`)\"}},\"kind\":\"dev\",\"methods\":{\"getRoleAdmin(bytes32)\":{\"details\":\"Returns the admin role that controls `role`. See {grantRole} and {revokeRole}. To change a role's admin, use {_setRoleAdmin}.\"},\"grantRole(bytes32,address)\":{\"details\":\"Grants `role` to `account`. If `account` had not been already granted `role`, emits a {RoleGranted} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleGranted} event.\"},\"hasRole(bytes32,address)\":{\"details\":\"Returns `true` if `account` has been granted `role`.\"},\"renounceRole(bytes32,address)\":{\"details\":\"Revokes `role` from the calling account. Roles are often managed via {grantRole} and {revokeRole}: this function's purpose is to provide a mechanism for accounts to lose their privileges if they are compromised (such as when a trusted device is misplaced). If the calling account had been revoked `role`, emits a {RoleRevoked} event. Requirements: - the caller must be `callerConfirmation`. May emit a {RoleRevoked} event.\"},\"revokeRole(bytes32,address)\":{\"details\":\"Revokes `role` from `account`. If `account` had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleRevoked} event.\"},\"supportsInterface(bytes4)\":{\"details\":\"See {IERC165-supportsInterface}.\"}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeV2.sol\":\"AccessControl\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeV2.sol\":{\"keccak256\":\"0xac79c463688a682ca706a4ef95e7817b83548cdfa8182ba0426ac7e5e07613d8\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://b3ecb7097381287cafc3a73f3a2bb03565115ebb682a85064e0b0dc2f7e2919d\",\"dweb:/ipfs/QmatruW3nYZTksf3CeQ8wwiAG4c7xoEJBEp6drHPtFLBRK\"]}},\"version\":1}"},"hashes":{"DEFAULT_ADMIN_ROLE()":"a217fddf","getRoleAdmin(bytes32)":"248a9ca3","grantRole(bytes32,address)":"2f2ff15d","hasRole(bytes32,address)":"91d14854","renounceRole(bytes32,address)":"36568abe","revokeRole(bytes32,address)":"d547741f","supportsInterface(bytes4)":"01ffc9a7"}},"solidity/FastBridgeV2.sol:AccessControlEnumerable":{"code":"0x","runtime-code":"0x","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.24 ^0.8.20 ^0.8.4;\n\n// contracts/interfaces/IAdminV2.sol\n\ninterface IAdminV2 {\n event CancelDelayUpdated(uint256 oldCancelDelay, uint256 newCancelDelay);\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n function setCancelDelay(uint256 newCancelDelay) external;\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n}\n\n// contracts/interfaces/IAdminV2Errors.sol\n\ninterface IAdminV2Errors {\n error CancelDelayBelowMin();\n error FeeRateAboveMax();\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IFastBridgeV2Errors.sol\n\ninterface IFastBridgeV2Errors {\n error AmountIncorrect();\n error ChainIncorrect();\n error ExclusivityParamsIncorrect();\n error MsgValueIncorrect();\n error SenderIncorrect();\n error StatusIncorrect();\n error TokenNotContract();\n error ZapDataLengthAboveMax();\n error ZapNativeNotSupported();\n error ZeroAddress();\n\n error RecipientIncorrectReturnValue();\n error RecipientNoReturnValue();\n\n error DeadlineExceeded();\n error DeadlineNotExceeded();\n error DeadlineTooShort();\n error DisputePeriodNotPassed();\n error DisputePeriodPassed();\n error ExclusivityPeriodNotPassed();\n\n error TransactionRelayed();\n}\n\n// contracts/interfaces/IMulticallTarget.sol\n\n/// @notice Interface for a contract that can be called multiple times by the same caller. Inspired by MulticallV3:\n/// https://github.com/mds1/multicall/blob/master/src/Multicall3.sol\ninterface IMulticallTarget {\n struct Result {\n bool success;\n bytes returnData;\n }\n\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external;\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results);\n}\n\n// contracts/interfaces/IZapRecipient.sol\n\ninterface IZapRecipient {\n function zap(address token, uint256 amount, bytes memory zapData) external payable returns (bytes4);\n}\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// contracts/interfaces/IFastBridgeV2.sol\n\ninterface IFastBridgeV2 is IFastBridge {\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n struct BridgeTxDetails {\n BridgeStatus status;\n uint32 destChainId;\n uint56 proofBlockTimestamp;\n address proofRelayer;\n }\n\n struct BridgeRelay {\n uint48 blockNumber;\n uint48 blockTimestamp;\n address relayer;\n }\n\n /// @notice New params introduced in the FastBridgeV2.\n /// We are passing fields from the older BridgeParams struct outside of this struct\n /// for backwards compatibility.\n /// Note: quoteRelayer and quoteExclusivitySeconds are either both zero (indicating no exclusivity)\n /// or both non-zero (indicating exclusivity for the given period).\n /// Note: zapNative \u003e 0 can NOT be used with destToken = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE (native token)\n /// @param quoteRelayer Relayer that provided the quote for the transaction\n /// @param quoteExclusivitySeconds Period of time the quote relayer is guaranteed exclusivity after user's deposit\n /// @param quoteId Unique quote identifier used for tracking the quote\n /// @param zapNative ETH value to send to the recipient (if any)\n /// @param zapData Parameters for the Zap to the destination recipient (if any)\n struct BridgeParamsV2 {\n address quoteRelayer;\n int256 quoteExclusivitySeconds;\n bytes quoteId;\n uint256 zapNative;\n bytes zapData;\n }\n\n /// @notice Updated bridge transaction struct to include parameters introduced in FastBridgeV2.\n /// Note: only `exclusivityRelayer` can fill such a transaction until `exclusivityEndTime`.\n struct BridgeTransactionV2 {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n // Note: sendChainGas flag from V1 is deprecated\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n address exclusivityRelayer;\n uint256 exclusivityEndTime;\n uint256 zapNative; // ETH value to send to the recipient (if any)\n bytes zapData; // data to pass for the Zap action (if any)\n }\n\n event BridgeQuoteDetails(bytes32 indexed transactionId, bytes quoteId);\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability\n /// to provide temporary exclusivity fill rights for the quote relayer.\n /// @param params The parameters required to bridge\n /// @param paramsV2 The parameters for exclusivity fill rights (optional, can be left empty)\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function relay(bytes memory request, address relayer) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param transactionId The transaction id associated with the encoded bridge transaction to prove\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital.\n /// @notice Can only send funds to the relayer address on the proof.\n /// @param request The encoded bridge transaction to claim on origin chain\n function claim(bytes memory request) external;\n\n /// @notice Cancels an outstanding bridge transaction in case optimistic bridging failed and returns the full amount\n /// to the original sender.\n /// @param request The encoded bridge transaction to refund\n function cancel(bytes memory request) external;\n\n /// @notice Checks if a transaction has been relayed\n /// @param transactionId The ID of the transaction to check\n /// @return True if the transaction has been relayed, false otherwise\n function bridgeRelays(bytes32 transactionId) external view returns (bool);\n\n /// @notice Returns the status of a bridge transaction\n /// @param transactionId The ID of the bridge transaction\n /// @return BridgeStatus Status of the bridge transaction\n function bridgeStatuses(bytes32 transactionId) external view returns (BridgeStatus);\n\n /// @notice Returns the timestamp and relayer of a bridge proof\n /// @param transactionId The ID of the bridge transaction\n /// @return timestamp The timestamp of the bridge proof\n /// @return relayer The relayer address of the bridge proof\n function bridgeProofs(bytes32 transactionId) external view returns (uint96 timestamp, address relayer);\n\n /// @notice Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\n /// @param request The bridge request to decode\n function getBridgeTransactionV2(bytes memory request) external view returns (BridgeTransactionV2 memory);\n}\n\n// contracts/utils/MulticallTarget.sol\n\n// solhint-disable avoid-low-level-calls\n/// @notice Template for a contract that supports batched calls (preserving the msg.sender).\n/// Only calls with zero msg.value could be batched.\nabstract contract MulticallTarget is IMulticallTarget {\n error MulticallTarget__UndeterminedRevert();\n\n /// @notice Perform a batched call to this contract, preserving the msg.sender.\n /// The return data from each call is discarded.\n /// @dev The method is non-payable, so only calls with `msg.value == 0` could be batched.\n /// It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag.\n /// Otherwise, the whole batch call will be reverted with the original revert reason.\n /// @param data List of abi-encoded calldata for the calls to perform.\n /// @param ignoreReverts Whether to ignore the revert errors from the calls.\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external {\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\n if (!success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(result);\n }\n }\n }\n\n /// @notice Perform a batched call to this contract, preserving the msg.sender.\n /// The return data from each call is preserved.\n /// @dev The method is non-payable, so only calls with `msg.value == 0` could be batched.\n /// It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag.\n /// Otherwise, the whole batch call will be reverted with the original revert reason.\n /// @param data List of abi-encoded calldata for the calls to perform.\n /// @param ignoreReverts Whether to ignore the revert errors from the calls.\n /// @return results List of results from the calls: `(success, returnData)`.\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results)\n {\n results = new Result[](data.length);\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (results[i].success, results[i].returnData) = address(this).delegatecall(data[i]);\n if (!results[i].success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(results[i].returnData);\n }\n }\n }\n\n /// @dev Bubbles the revert message from the underlying call.\n /// Note: preserves the same custom error or revert string, if one was used.\n /// Source: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v5.0.2/contracts/utils/Address.sol#L143-L158\n function _bubbleRevert(bytes memory returnData) internal pure {\n // Look for revert reason and bubble it up if present\n if (returnData.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n // solhint-disable-next-line no-inline-assembly\n assembly {\n let returndata_size := mload(returnData)\n revert(add(32, returnData), returndata_size)\n }\n } else {\n revert MulticallTarget__UndeterminedRevert();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// contracts/libs/BridgeTransactionV2.sol\n\n// solhint-disable no-inline-assembly\nlibrary BridgeTransactionV2Lib {\n uint16 internal constant VERSION = 2;\n\n // Offsets of the fields in the packed BridgeTransactionV2 struct\n // uint16 version [000 .. 002)\n // uint32 originChainId [002 .. 006)\n // uint32 destChainId [006 .. 010)\n // address originSender [010 .. 030)\n // address destRecipient [030 .. 050)\n // address originToken [050 .. 070)\n // address destToken [070 .. 090)\n // uint256 originAmount [090 .. 122)\n // uint256 destAmount [122 .. 154)\n // uint256 originFeeAmount [154 .. 186)\n // uint256 deadline [186 .. 218)\n // uint256 nonce [218 .. 250)\n // address exclusivityRelayer [250 .. 270)\n // uint256 exclusivityEndTime [270 .. 302)\n // uint256 zapNative [302 .. 334)\n // bytes zapData [334 .. ***)\n\n // forgefmt: disable-start\n uint256 private constant OFFSET_ORIGIN_CHAIN_ID = 2;\n uint256 private constant OFFSET_DEST_CHAIN_ID = 6;\n uint256 private constant OFFSET_ORIGIN_SENDER = 10;\n uint256 private constant OFFSET_DEST_RECIPIENT = 30;\n uint256 private constant OFFSET_ORIGIN_TOKEN = 50;\n uint256 private constant OFFSET_DEST_TOKEN = 70;\n uint256 private constant OFFSET_ORIGIN_AMOUNT = 90;\n uint256 private constant OFFSET_DEST_AMOUNT = 122;\n uint256 private constant OFFSET_ORIGIN_FEE_AMOUNT = 154;\n uint256 private constant OFFSET_DEADLINE = 186;\n uint256 private constant OFFSET_NONCE = 218;\n uint256 private constant OFFSET_EXCLUSIVITY_RELAYER = 250;\n uint256 private constant OFFSET_EXCLUSIVITY_END_TIME = 270;\n uint256 private constant OFFSET_ZAP_NATIVE = 302;\n uint256 private constant OFFSET_ZAP_DATA = 334;\n // forgefmt: disable-end\n\n error BridgeTransactionV2__InvalidEncodedTx();\n error BridgeTransactionV2__UnsupportedVersion(uint16 version);\n\n /// @notice Validates the encoded transaction to be a tightly packed encoded payload for BridgeTransactionV2.\n /// @dev Checks the minimum length and the version, use this function before decoding any of the fields.\n function validateV2(bytes calldata encodedTx) internal pure {\n // Check the minimum length: must at least include all static fields.\n if (encodedTx.length \u003c OFFSET_ZAP_DATA) revert BridgeTransactionV2__InvalidEncodedTx();\n // Once we validated the length, we can be sure that the version field is present.\n uint16 version_ = version(encodedTx);\n if (version_ != VERSION) revert BridgeTransactionV2__UnsupportedVersion(version_);\n }\n\n /// @notice Encodes the BridgeTransactionV2 struct by tightly packing the fields.\n /// @dev `abi.decode` will not work as a result of the tightly packed fields. Use `decodeV2` to decode instead.\n function encodeV2(IFastBridgeV2.BridgeTransactionV2 memory bridgeTx) internal pure returns (bytes memory) {\n // We split the encoding into two parts to avoid stack-too-deep error\n bytes memory firstPart = abi.encodePacked(\n VERSION,\n bridgeTx.originChainId,\n bridgeTx.destChainId,\n bridgeTx.originSender,\n bridgeTx.destRecipient,\n bridgeTx.originToken,\n bridgeTx.destToken,\n bridgeTx.originAmount\n );\n return abi.encodePacked(\n firstPart,\n bridgeTx.destAmount,\n bridgeTx.originFeeAmount,\n // Note: we skip the deprecated `sendChainGas` flag, which was present in BridgeTransaction V1\n bridgeTx.deadline,\n bridgeTx.nonce,\n // New V2 fields: exclusivity\n bridgeTx.exclusivityRelayer,\n bridgeTx.exclusivityEndTime,\n // New V2 fields: Zap\n bridgeTx.zapNative,\n bridgeTx.zapData\n );\n }\n\n /// @notice Decodes the BridgeTransactionV2 struct from the encoded transaction.\n /// @dev Encoded BridgeTransactionV2 struct must be tightly packed.\n /// Use `validateV2` before decoding to ensure the encoded transaction is valid.\n function decodeV2(bytes calldata encodedTx)\n internal\n pure\n returns (IFastBridgeV2.BridgeTransactionV2 memory bridgeTx)\n {\n bridgeTx.originChainId = originChainId(encodedTx);\n bridgeTx.destChainId = destChainId(encodedTx);\n bridgeTx.originSender = originSender(encodedTx);\n bridgeTx.destRecipient = destRecipient(encodedTx);\n bridgeTx.originToken = originToken(encodedTx);\n bridgeTx.destToken = destToken(encodedTx);\n bridgeTx.originAmount = originAmount(encodedTx);\n bridgeTx.destAmount = destAmount(encodedTx);\n bridgeTx.originFeeAmount = originFeeAmount(encodedTx);\n bridgeTx.deadline = deadline(encodedTx);\n bridgeTx.nonce = nonce(encodedTx);\n bridgeTx.exclusivityRelayer = exclusivityRelayer(encodedTx);\n bridgeTx.exclusivityEndTime = exclusivityEndTime(encodedTx);\n bridgeTx.zapNative = zapNative(encodedTx);\n bridgeTx.zapData = zapData(encodedTx);\n }\n\n /// @notice Extracts the version from the encoded transaction.\n function version(bytes calldata encodedTx) internal pure returns (uint16 version_) {\n // Load 32 bytes from the start and shift it 240 bits to the right to get the highest 16 bits.\n assembly {\n version_ := shr(240, calldataload(encodedTx.offset))\n }\n }\n\n /// @notice Extracts the origin chain ID from the encoded transaction.\n function originChainId(bytes calldata encodedTx) internal pure returns (uint32 originChainId_) {\n // Load 32 bytes from the offset and shift it 224 bits to the right to get the highest 32 bits.\n assembly {\n originChainId_ := shr(224, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_CHAIN_ID)))\n }\n }\n\n /// @notice Extracts the destination chain ID from the encoded transaction.\n function destChainId(bytes calldata encodedTx) internal pure returns (uint32 destChainId_) {\n // Load 32 bytes from the offset and shift it 224 bits to the right to get the highest 32 bits.\n assembly {\n destChainId_ := shr(224, calldataload(add(encodedTx.offset, OFFSET_DEST_CHAIN_ID)))\n }\n }\n\n /// @notice Extracts the origin sender from the encoded transaction.\n function originSender(bytes calldata encodedTx) internal pure returns (address originSender_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n originSender_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_SENDER)))\n }\n }\n\n /// @notice Extracts the destination recipient from the encoded transaction.\n function destRecipient(bytes calldata encodedTx) internal pure returns (address destRecipient_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n destRecipient_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_DEST_RECIPIENT)))\n }\n }\n\n /// @notice Extracts the origin token from the encoded transaction.\n function originToken(bytes calldata encodedTx) internal pure returns (address originToken_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n originToken_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_TOKEN)))\n }\n }\n\n /// @notice Extracts the destination token from the encoded transaction.\n function destToken(bytes calldata encodedTx) internal pure returns (address destToken_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n destToken_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_DEST_TOKEN)))\n }\n }\n\n /// @notice Extracts the origin amount from the encoded transaction.\n function originAmount(bytes calldata encodedTx) internal pure returns (uint256 originAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n originAmount_ := calldataload(add(encodedTx.offset, OFFSET_ORIGIN_AMOUNT))\n }\n }\n\n /// @notice Extracts the destination amount from the encoded transaction.\n function destAmount(bytes calldata encodedTx) internal pure returns (uint256 destAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n destAmount_ := calldataload(add(encodedTx.offset, OFFSET_DEST_AMOUNT))\n }\n }\n\n /// @notice Extracts the origin fee amount from the encoded transaction.\n function originFeeAmount(bytes calldata encodedTx) internal pure returns (uint256 originFeeAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n originFeeAmount_ := calldataload(add(encodedTx.offset, OFFSET_ORIGIN_FEE_AMOUNT))\n }\n }\n\n /// @notice Extracts the deadline from the encoded transaction.\n function deadline(bytes calldata encodedTx) internal pure returns (uint256 deadline_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n deadline_ := calldataload(add(encodedTx.offset, OFFSET_DEADLINE))\n }\n }\n\n /// @notice Extracts the nonce from the encoded transaction.\n function nonce(bytes calldata encodedTx) internal pure returns (uint256 nonce_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n nonce_ := calldataload(add(encodedTx.offset, OFFSET_NONCE))\n }\n }\n\n /// @notice Extracts the exclusivity relayer from the encoded transaction.\n function exclusivityRelayer(bytes calldata encodedTx) internal pure returns (address exclusivityRelayer_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n exclusivityRelayer_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_EXCLUSIVITY_RELAYER)))\n }\n }\n\n /// @notice Extracts the exclusivity end time from the encoded transaction.\n function exclusivityEndTime(bytes calldata encodedTx) internal pure returns (uint256 exclusivityEndTime_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n exclusivityEndTime_ := calldataload(add(encodedTx.offset, OFFSET_EXCLUSIVITY_END_TIME))\n }\n }\n\n /// @notice Extracts the Zap's native value from the encoded transaction.\n function zapNative(bytes calldata encodedTx) internal pure returns (uint256 zapNative_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n zapNative_ := calldataload(add(encodedTx.offset, OFFSET_ZAP_NATIVE))\n }\n }\n\n /// @notice Extracts the Zap's data from the encoded transaction.\n function zapData(bytes calldata encodedTx) internal pure returns (bytes calldata zapData_) {\n zapData_ = encodedTx[OFFSET_ZAP_DATA:];\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/AdminV2.sol\n\ncontract AdminV2 is AccessControlEnumerable, IAdminV2, IAdminV2Errors {\n using SafeERC20 for IERC20;\n\n /// @notice Address reserved for native gas token (ETH on Ethereum and most L2s, AVAX on Avalanche, etc)\n address public constant NATIVE_GAS_TOKEN = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Role identifier for Quoter API's off-chain authentication.\n /// @dev Only addresses with this role can post FastBridge quotes to the API.\n bytes32 public constant QUOTER_ROLE = keccak256(\"QUOTER_ROLE\");\n\n /// @notice Role identifier for Prover's on-chain authentication in FastBridge.\n /// @dev Only addresses with this role can provide proofs that a FastBridge request has been relayed.\n bytes32 public constant PROVER_ROLE = keccak256(\"PROVER_ROLE\");\n\n /// @notice Role identifier for Guard's on-chain authentication in FastBridge.\n /// @dev Only addresses with this role can dispute submitted relay proofs during the dispute period.\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n\n /// @notice Role identifier for Canceler's on-chain authentication in FastBridge.\n /// @dev Only addresses with this role can cancel a FastBridge transaction without the cancel delay.\n bytes32 public constant CANCELER_ROLE = keccak256(\"CANCELER_ROLE\");\n\n /// @notice Role identifier for Governor's on-chain administrative authority.\n /// @dev Only addresses with this role can perform administrative tasks within the contract.\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n /// @notice Denominator for fee rates, represents 100%.\n uint256 public constant FEE_BPS = 1e6;\n /// @notice Maximum protocol fee rate: 1% on origin amount.\n uint256 public constant FEE_RATE_MAX = 0.01e6;\n\n /// @notice Minimum cancel delay that can be set by the governor.\n uint256 public constant MIN_CANCEL_DELAY = 1 hours;\n /// @notice Default cancel delay set during the contract deployment.\n uint256 public constant DEFAULT_CANCEL_DELAY = 1 days;\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Delay for a transaction after which it could be permisionlessly cancelled\n uint256 public cancelDelay;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Use ZapNative V2 requests instead.\n uint256 public immutable chainGasAmount = 0;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n _setCancelDelay(DEFAULT_CANCEL_DELAY);\n }\n\n /// @notice Allows the contract governor to set the cancel delay. The cancel delay is the time after the transaction\n /// deadline after which it can be permissionlessly cancelled, if it hasn't been proven by any of the Relayers.\n function setCancelDelay(uint256 newCancelDelay) external onlyRole(GOVERNOR_ROLE) {\n _setCancelDelay(newCancelDelay);\n }\n\n /// @notice Allows the contract governor to set the protocol fee rate. The protocol fee is taken from the origin\n /// amount only for completed and claimed transactions.\n /// @dev The protocol fee is abstracted away from the relayers, they always operate using the amounts after fees:\n /// what they see as the origin amount emitted in the log is what they get credited with.\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n if (newFeeRate \u003e FEE_RATE_MAX) revert FeeRateAboveMax();\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n /// @notice Allows the contract governor to sweep the accumulated protocol fees in the contract.\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n emit FeesSwept(token, recipient, feeAmount);\n /// Sweep the fees as the last transaction action\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(recipient), feeAmount);\n } else {\n IERC20(token).safeTransfer(recipient, feeAmount);\n }\n }\n\n /// @notice Internal function to set the cancel delay. Security checks are performed outside of this function.\n function _setCancelDelay(uint256 newCancelDelay) private {\n if (newCancelDelay \u003c MIN_CANCEL_DELAY) revert CancelDelayBelowMin();\n uint256 oldCancelDelay = cancelDelay;\n cancelDelay = newCancelDelay;\n emit CancelDelayUpdated(oldCancelDelay, newCancelDelay);\n }\n}\n\n// contracts/FastBridgeV2.sol\n\n/// @notice FastBridgeV2 is a contract for bridging tokens across chains.\ncontract FastBridgeV2 is AdminV2, MulticallTarget, IFastBridgeV2, IFastBridgeV2Errors {\n using BridgeTransactionV2Lib for bytes;\n using SafeERC20 for IERC20;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n /// @notice Maximum length of accepted zapData\n uint256 public constant MAX_ZAP_DATA_LENGTH = 2 ** 16 - 1;\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeTxDetails) public bridgeTxDetails;\n /// @notice Relay details on destination chain\n mapping(bytes32 =\u003e BridgeRelay) public bridgeRelayDetails;\n /// @notice Unique bridge nonces tracked per originSender\n mapping(address =\u003e uint256) public senderNonces;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Replaced by senderNonces\n uint256 public immutable nonce = 0;\n /// @notice the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) AdminV2(_owner) {\n deployBlock = block.number;\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n bridge({\n params: params,\n paramsV2: BridgeParamsV2({\n quoteRelayer: address(0),\n quoteExclusivitySeconds: 0,\n quoteId: bytes(\"\"),\n zapNative: 0,\n zapData: bytes(\"\")\n })\n });\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes calldata request) external payable {\n // relay override will validate the request\n relay({request: request, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes calldata request, bytes32 destTxHash) external {\n request.validateV2();\n prove({transactionId: keccak256(request), destTxHash: destTxHash, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridgeV2\n function claim(bytes calldata request) external {\n // claim override will validate the request\n claim({request: request, to: address(0)});\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Aggregate the read operations from the same storage slot\n address disputedRelayer = $.proofRelayer;\n BridgeStatus status = $.status;\n uint56 proofBlockTimestamp = $.proofBlockTimestamp;\n // Can only dispute a RELAYER_PROVED transaction within the dispute period\n if (status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(proofBlockTimestamp) \u003e DISPUTE_PERIOD) {\n revert DisputePeriodPassed();\n }\n // Update status to REQUESTED and delete the disputed proof details\n // Note: these are storage writes\n $.status = BridgeStatus.REQUESTED;\n $.proofRelayer = address(0);\n $.proofBlockTimestamp = 0;\n\n emit BridgeProofDisputed(transactionId, disputedRelayer);\n }\n\n /// Note: this function is deprecated and will be removed in a future version.\n /// @inheritdoc IFastBridge\n function refund(bytes calldata request) external {\n cancel(request);\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // The correct relayer can only claim a RELAYER_PROVED transaction after the dispute period\n if ($.status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if ($.proofRelayer != relayer) revert SenderIncorrect();\n return _timeSince($.proofBlockTimestamp) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n /// @dev This method is added to achieve backwards compatibility with decoding requests into V1 structs:\n /// - `zapNative` is partially reported as a zero/non-zero flag\n /// - `zapData` is ignored\n /// In order to process all kinds of requests use getBridgeTransactionV2 instead.\n function getBridgeTransaction(bytes calldata request) external view returns (BridgeTransaction memory) {\n // Try decoding into V2 struct first. This will revert if V1 struct is passed\n try this.getBridgeTransactionV2(request) returns (BridgeTransactionV2 memory txV2) {\n // Note: we entirely ignore the zapData field, as it was not present in V1\n return BridgeTransaction({\n originChainId: txV2.originChainId,\n destChainId: txV2.destChainId,\n originSender: txV2.originSender,\n destRecipient: txV2.destRecipient,\n originToken: txV2.originToken,\n destToken: txV2.destToken,\n originAmount: txV2.originAmount,\n destAmount: txV2.destAmount,\n originFeeAmount: txV2.originFeeAmount,\n sendChainGas: txV2.zapNative != 0,\n deadline: txV2.deadline,\n nonce: txV2.nonce\n });\n } catch {\n // Fallback to V1 struct\n return abi.decode(request, (BridgeTransaction));\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function getBridgeTransactionV2(bytes calldata request) external pure returns (BridgeTransactionV2 memory) {\n request.validateV2();\n return BridgeTransactionV2Lib.decodeV2(request);\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) public payable {\n int256 exclusivityEndTime = 0;\n // if relayer exclusivity is not intended for this bridge, set exclusivityEndTime to static zero\n // otherwise, set exclusivity to expire at the current block ts offset by quoteExclusivitySeconds\n if (paramsV2.quoteRelayer != address(0)) {\n exclusivityEndTime = int256(block.timestamp) + paramsV2.quoteExclusivitySeconds;\n }\n _validateBridgeParams(params, paramsV2, exclusivityEndTime);\n\n // transfer tokens to bridge contract\n /// @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _takeBridgedUserAsset(params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) {\n originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n }\n\n // set status to requested\n bytes memory request = BridgeTransactionV2Lib.encodeV2(\n BridgeTransactionV2({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n deadline: params.deadline,\n nonce: senderNonces[params.sender]++, // increment nonce on every bridge\n exclusivityRelayer: paramsV2.quoteRelayer,\n // We checked exclusivityEndTime to be in range [0 .. params.deadline] above, so can safely cast\n exclusivityEndTime: uint256(exclusivityEndTime),\n zapNative: paramsV2.zapNative,\n zapData: paramsV2.zapData\n })\n );\n bytes32 transactionId = keccak256(request);\n // Note: the tx status will be updated throughout the tx lifecycle, while destChainId is set once here\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n bridgeTxDetails[transactionId].destChainId = params.dstChainId;\n\n emit BridgeRequested({\n transactionId: transactionId,\n sender: params.sender,\n request: request,\n destChainId: params.dstChainId,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n sendChainGas: paramsV2.zapNative != 0\n });\n emit BridgeQuoteDetails(transactionId, paramsV2.quoteId);\n }\n\n /// @inheritdoc IFastBridgeV2\n function relay(bytes calldata request, address relayer) public payable {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n _validateRelayParams(request, transactionId, relayer);\n // mark bridge transaction as relayed\n bridgeRelayDetails[transactionId] =\n BridgeRelay({blockNumber: uint48(block.number), blockTimestamp: uint48(block.timestamp), relayer: relayer});\n\n // transfer tokens to recipient on destination chain and trigger Zap if requested\n address to = request.destRecipient();\n address token = request.destToken();\n uint256 amount = request.destAmount();\n uint256 zapNative = request.zapNative();\n\n // Emit the event before any external calls\n emit BridgeRelayed({\n transactionId: transactionId,\n relayer: relayer,\n to: to,\n originChainId: request.originChainId(),\n originToken: request.originToken(),\n destToken: token,\n originAmount: request.originAmount(),\n destAmount: amount,\n chainGasAmount: zapNative\n });\n\n // All state changes have been done at this point, can proceed to the external calls.\n // This follows the checks-effects-interactions pattern to mitigate potential reentrancy attacks.\n if (token == NATIVE_GAS_TOKEN) {\n // For the native gas token, additional zapNative is not allowed\n if (zapNative != 0) revert ZapNativeNotSupported();\n // Check that the correct msg.value was sent\n if (msg.value != amount) revert MsgValueIncorrect();\n // Don't do a native transfer yet: we will handle it alongside the Zap below\n } else {\n // For ERC20s, we check that the correct msg.value was sent\n if (msg.value != zapNative) revert MsgValueIncorrect();\n // We need to transfer the tokens from the Relayer to the recipient first before performing an\n // optional post-transfer Zap.\n IERC20(token).safeTransferFrom(msg.sender, to, amount);\n }\n // At this point we have done:\n // - Transferred the requested amount of ERC20 tokens to the recipient.\n // At this point we have confirmed:\n // - For ERC20s: msg.value matches the requested zapNative amount.\n // - For the native gas token: msg.value matches the requested destAmount.\n // Remaining optional things to do:\n // - Forward the full msg.value to the recipient (if non-zero).\n // - Trigger a Zap (if zapData is present).\n bytes calldata zapData = request.zapData();\n if (zapData.length != 0) {\n // Zap Data is present: Zap has been requested by the recipient. Trigger it forwarding the full msg.value.\n\n // Note: if token has a fee on transfers, the recipient will have received less than `amount`.\n // This is a very niche edge case and should be handled by the recipient contract.\n _triggerZapWithChecks({recipient: to, token: token, amount: amount, zapData: zapData});\n } else if (msg.value != 0) {\n // Zap Data is missing, but msg.value was sent. This could happen in two different cases:\n // - Relay with the native gas token is happening.\n // - Relay with ERC20 is happening, with a `zapNative \u003e 0` request.\n // In both cases, we need to transfer the full msg.value to the recipient.\n Address.sendValue(payable(to), msg.value);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) public onlyRole(PROVER_ROLE) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n\n // Can only prove a REQUESTED transaction\n if ($.status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n // Update status to RELAYER_PROVED and store the proof details\n // Note: these are storage writes\n $.status = BridgeStatus.RELAYER_PROVED;\n $.proofBlockTimestamp = uint56(block.timestamp);\n $.proofRelayer = relayer;\n\n emit BridgeProofProvided(transactionId, relayer, destTxHash);\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes calldata request, address to) public {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Aggregate the read operations from the same storage slot\n address proofRelayer = $.proofRelayer;\n BridgeStatus status = $.status;\n uint56 proofBlockTimestamp = $.proofBlockTimestamp;\n\n // Can only claim a RELAYER_PROVED transaction after the dispute period\n if (status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(proofBlockTimestamp) \u003c= DISPUTE_PERIOD) {\n revert DisputePeriodNotPassed();\n }\n\n if (to == address(0)) {\n // Anyone could claim the funds to the proven relayer on their behalf\n to = proofRelayer;\n } else if (proofRelayer != msg.sender) {\n // Only the proven relayer could specify an address to claim the funds to\n revert SenderIncorrect();\n }\n\n // Update status to RELAYER_CLAIMED and transfer the origin collateral to the specified claim address\n // Note: this is a storage write\n $.status = BridgeStatus.RELAYER_CLAIMED;\n\n address token = request.originToken();\n uint256 amount = request.originAmount();\n // Update protocol fees if origin fee amount exists\n uint256 originFeeAmount = request.originFeeAmount();\n if (originFeeAmount \u003e 0) protocolFees[token] += originFeeAmount;\n // Emit the event before any external calls\n emit BridgeDepositClaimed(transactionId, proofRelayer, to, token, amount);\n // Complete the relayer claim as the last transaction action\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(to), amount);\n } else {\n IERC20(token).safeTransfer(to, amount);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function cancel(bytes calldata request) public {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Can only cancel a REQUESTED transaction after its deadline expires\n if ($.status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n uint256 deadline = request.deadline();\n // Permissionless cancel is only allowed after `cancelDelay` on top of the deadline\n if (!hasRole(CANCELER_ROLE, msg.sender)) deadline += cancelDelay;\n if (block.timestamp \u003c= deadline) revert DeadlineNotExceeded();\n // Update status to REFUNDED and return the full amount (collateral + protocol fees) to the original sender.\n // The protocol fees are only updated when the transaction is claimed, so we don't need to update them here.\n // Note: this is a storage write\n $.status = BridgeStatus.REFUNDED;\n\n address to = request.originSender();\n address token = request.originToken();\n uint256 amount = request.originAmount() + request.originFeeAmount();\n // Emit the event before any external calls\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n // Complete the user cancel as the last transaction action\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(to), amount);\n } else {\n IERC20(token).safeTransfer(to, amount);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeStatuses(bytes32 transactionId) public view returns (BridgeStatus status) {\n return bridgeTxDetails[transactionId].status;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeProofs(bytes32 transactionId) public view returns (uint96 timestamp, address relayer) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n\n timestamp = $.proofBlockTimestamp;\n relayer = $.proofRelayer;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeRelays(bytes32 transactionId) public view returns (bool) {\n // has this transactionId been relayed?\n return bridgeRelayDetails[transactionId].relayer != address(0);\n }\n\n /// @notice Takes the bridged asset from the user into FastBridgeV2 custody. It will be later\n /// claimed by the relayer who completed the relay on destination chain, or transferred back to the user\n /// via the cancel function should no one complete the relay.\n function _takeBridgedUserAsset(address token, uint256 amount) internal returns (uint256 amountTaken) {\n if (token == NATIVE_GAS_TOKEN) {\n // For the native gas token, we just need to check that the supplied msg.value is correct.\n // Supplied `msg.value` is already in FastBridgeV2 custody.\n if (amount != msg.value) revert MsgValueIncorrect();\n amountTaken = msg.value;\n } else {\n // For ERC20s, token is explicitly transferred from the user to FastBridgeV2.\n // We don't allow non-zero `msg.value` to avoid extra funds from being stuck in FastBridgeV2.\n if (msg.value != 0) revert MsgValueIncorrect();\n // Throw an explicit error if the provided token address is not a contract\n if (token.code.length == 0) revert TokenNotContract();\n amountTaken = IERC20(token).balanceOf(address(this));\n IERC20(token).safeTransferFrom(msg.sender, address(this), amount);\n // Use the balance difference as the amount taken in case of fee on transfer tokens.\n amountTaken = IERC20(token).balanceOf(address(this)) - amountTaken;\n }\n }\n\n /// @notice Calls the Recipient's hook function with the specified zapData and performs\n /// all the necessary checks for the returned value.\n function _triggerZapWithChecks(address recipient, address token, uint256 amount, bytes calldata zapData) internal {\n // This will bubble any revert messages from the hook function\n bytes memory returnData = Address.functionCallWithValue({\n target: recipient,\n data: abi.encodeCall(IZapRecipient.zap, (token, amount, zapData)),\n // Note: see `relay()` for reasoning behind passing msg.value\n value: msg.value\n });\n // Explicit revert if no return data at all\n if (returnData.length == 0) revert RecipientNoReturnValue();\n // Check that exactly a single return value was returned\n if (returnData.length != 32) revert RecipientIncorrectReturnValue();\n // Return value should be abi-encoded hook function selector\n if (bytes32(returnData) != bytes32(IZapRecipient.zap.selector)) {\n revert RecipientIncorrectReturnValue();\n }\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint56(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint56).max but\n /// proof.timestamp \u003c type(uint56).max via unchecked statement\n /// @param proofBlockTimestamp The bridge proof block timestamp\n /// @return delta Time delta since proof submitted\n function _timeSince(uint56 proofBlockTimestamp) internal view returns (uint256 delta) {\n unchecked {\n delta = uint56(block.timestamp) - proofBlockTimestamp;\n }\n }\n\n /// @notice Performs all the necessary checks for a bridge to happen.\n /// @dev There's no good way to refactor this function to reduce cyclomatic complexity due to\n /// the number of checks that need to be performed, so we skip the code-complexity rule here.\n // solhint-disable-next-line code-complexity\n function _validateBridgeParams(\n BridgeParams memory params,\n BridgeParamsV2 memory paramsV2,\n int256 exclusivityEndTime\n )\n internal\n view\n {\n // Check V1 (legacy) params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.sender == address(0) || params.to == address(0)) revert ZeroAddress();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n // Check V2 params\n if (paramsV2.zapData.length \u003e MAX_ZAP_DATA_LENGTH) revert ZapDataLengthAboveMax();\n if (paramsV2.zapNative != 0 \u0026\u0026 params.destToken == NATIVE_GAS_TOKEN) {\n revert ZapNativeNotSupported();\n }\n // exclusivityEndTime must be in range [0 .. params.deadline]\n if (exclusivityEndTime \u003c 0 || exclusivityEndTime \u003e int256(params.deadline)) {\n revert ExclusivityParamsIncorrect();\n }\n }\n\n /// @notice Performs all the necessary checks for a relay to happen.\n function _validateRelayParams(bytes calldata request, bytes32 transactionId, address relayer) internal view {\n if (relayer == address(0)) revert ZeroAddress();\n // Check if the transaction has already been relayed\n if (bridgeRelays(transactionId)) revert TransactionRelayed();\n if (request.destChainId() != block.chainid) revert ChainIncorrect();\n // Check the deadline for relay to happen\n if (block.timestamp \u003e request.deadline()) revert DeadlineExceeded();\n // Check the exclusivity period, if it is still ongoing\n address exclRelayer = request.exclusivityRelayer();\n if (exclRelayer != address(0) \u0026\u0026 exclRelayer != relayer \u0026\u0026 block.timestamp \u003c= request.exclusivityEndTime()) {\n revert ExclusivityPeriodNotPassed();\n }\n }\n}\n","language":"Solidity","languageVersion":"0.8.24","compilerVersion":"0.8.24","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"","srcMapRuntime":"","abiDefinition":[{"inputs":[],"name":"AccessControlBadConfirmation","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"bytes32","name":"neededRole","type":"bytes32"}],"name":"AccessControlUnauthorizedAccount","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"previousAdminRole","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"newAdminRole","type":"bytes32"}],"name":"RoleAdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleRevoked","type":"event"},{"inputs":[],"name":"DEFAULT_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleAdmin","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"uint256","name":"index","type":"uint256"}],"name":"getRoleMember","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleMemberCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"grantRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"hasRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"callerConfirmation","type":"address"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"revokeRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"}],"userDoc":{"kind":"user","methods":{},"version":1},"developerDoc":{"details":"Extension of {AccessControl} that allows enumerating the members of each role.","errors":{"AccessControlBadConfirmation()":[{"details":"The caller of a function is not the expected one. NOTE: Don't confuse with {AccessControlUnauthorizedAccount}."}],"AccessControlUnauthorizedAccount(address,bytes32)":[{"details":"The `account` is missing a role."}]},"events":{"RoleAdminChanged(bytes32,bytes32,bytes32)":{"details":"Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole` `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite {RoleAdminChanged} not being emitted signaling this."},"RoleGranted(bytes32,address,address)":{"details":"Emitted when `account` is granted `role`. `sender` is the account that originated the contract call, an admin role bearer except when using {AccessControl-_setupRole}."},"RoleRevoked(bytes32,address,address)":{"details":"Emitted when `account` is revoked `role`. `sender` is the account that originated the contract call: - if using `revokeRole`, it is the admin role bearer - if using `renounceRole`, it is the role bearer (i.e. `account`)"}},"kind":"dev","methods":{"getRoleAdmin(bytes32)":{"details":"Returns the admin role that controls `role`. See {grantRole} and {revokeRole}. To change a role's admin, use {_setRoleAdmin}."},"getRoleMember(bytes32,uint256)":{"details":"Returns one of the accounts that have `role`. `index` must be a value between 0 and {getRoleMemberCount}, non-inclusive. Role bearers are not sorted in any particular way, and their ordering may change at any point. WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure you perform all queries on the same block. See the following https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post] for more information."},"getRoleMemberCount(bytes32)":{"details":"Returns the number of accounts that have `role`. Can be used together with {getRoleMember} to enumerate all bearers of a role."},"grantRole(bytes32,address)":{"details":"Grants `role` to `account`. If `account` had not been already granted `role`, emits a {RoleGranted} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleGranted} event."},"hasRole(bytes32,address)":{"details":"Returns `true` if `account` has been granted `role`."},"renounceRole(bytes32,address)":{"details":"Revokes `role` from the calling account. Roles are often managed via {grantRole} and {revokeRole}: this function's purpose is to provide a mechanism for accounts to lose their privileges if they are compromised (such as when a trusted device is misplaced). If the calling account had been revoked `role`, emits a {RoleRevoked} event. Requirements: - the caller must be `callerConfirmation`. May emit a {RoleRevoked} event."},"revokeRole(bytes32,address)":{"details":"Revokes `role` from `account`. If `account` had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleRevoked} event."},"supportsInterface(bytes4)":{"details":"See {IERC165-supportsInterface}."}},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[],\"name\":\"AccessControlBadConfirmation\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"neededRole\",\"type\":\"bytes32\"}],\"name\":\"AccessControlUnauthorizedAccount\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"previousAdminRole\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"newAdminRole\",\"type\":\"bytes32\"}],\"name\":\"RoleAdminChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleGranted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleRevoked\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"DEFAULT_ADMIN_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"}],\"name\":\"getRoleAdmin\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"index\",\"type\":\"uint256\"}],\"name\":\"getRoleMember\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"}],\"name\":\"getRoleMemberCount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"grantRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"hasRole\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"callerConfirmation\",\"type\":\"address\"}],\"name\":\"renounceRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"revokeRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes4\",\"name\":\"interfaceId\",\"type\":\"bytes4\"}],\"name\":\"supportsInterface\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"}],\"devdoc\":{\"details\":\"Extension of {AccessControl} that allows enumerating the members of each role.\",\"errors\":{\"AccessControlBadConfirmation()\":[{\"details\":\"The caller of a function is not the expected one. NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\"}],\"AccessControlUnauthorizedAccount(address,bytes32)\":[{\"details\":\"The `account` is missing a role.\"}]},\"events\":{\"RoleAdminChanged(bytes32,bytes32,bytes32)\":{\"details\":\"Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole` `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite {RoleAdminChanged} not being emitted signaling this.\"},\"RoleGranted(bytes32,address,address)\":{\"details\":\"Emitted when `account` is granted `role`. `sender` is the account that originated the contract call, an admin role bearer except when using {AccessControl-_setupRole}.\"},\"RoleRevoked(bytes32,address,address)\":{\"details\":\"Emitted when `account` is revoked `role`. `sender` is the account that originated the contract call: - if using `revokeRole`, it is the admin role bearer - if using `renounceRole`, it is the role bearer (i.e. `account`)\"}},\"kind\":\"dev\",\"methods\":{\"getRoleAdmin(bytes32)\":{\"details\":\"Returns the admin role that controls `role`. See {grantRole} and {revokeRole}. To change a role's admin, use {_setRoleAdmin}.\"},\"getRoleMember(bytes32,uint256)\":{\"details\":\"Returns one of the accounts that have `role`. `index` must be a value between 0 and {getRoleMemberCount}, non-inclusive. Role bearers are not sorted in any particular way, and their ordering may change at any point. WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure you perform all queries on the same block. See the following https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post] for more information.\"},\"getRoleMemberCount(bytes32)\":{\"details\":\"Returns the number of accounts that have `role`. Can be used together with {getRoleMember} to enumerate all bearers of a role.\"},\"grantRole(bytes32,address)\":{\"details\":\"Grants `role` to `account`. If `account` had not been already granted `role`, emits a {RoleGranted} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleGranted} event.\"},\"hasRole(bytes32,address)\":{\"details\":\"Returns `true` if `account` has been granted `role`.\"},\"renounceRole(bytes32,address)\":{\"details\":\"Revokes `role` from the calling account. Roles are often managed via {grantRole} and {revokeRole}: this function's purpose is to provide a mechanism for accounts to lose their privileges if they are compromised (such as when a trusted device is misplaced). If the calling account had been revoked `role`, emits a {RoleRevoked} event. Requirements: - the caller must be `callerConfirmation`. May emit a {RoleRevoked} event.\"},\"revokeRole(bytes32,address)\":{\"details\":\"Revokes `role` from `account`. If `account` had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleRevoked} event.\"},\"supportsInterface(bytes4)\":{\"details\":\"See {IERC165-supportsInterface}.\"}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeV2.sol\":\"AccessControlEnumerable\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeV2.sol\":{\"keccak256\":\"0xac79c463688a682ca706a4ef95e7817b83548cdfa8182ba0426ac7e5e07613d8\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://b3ecb7097381287cafc3a73f3a2bb03565115ebb682a85064e0b0dc2f7e2919d\",\"dweb:/ipfs/QmatruW3nYZTksf3CeQ8wwiAG4c7xoEJBEp6drHPtFLBRK\"]}},\"version\":1}"},"hashes":{"DEFAULT_ADMIN_ROLE()":"a217fddf","getRoleAdmin(bytes32)":"248a9ca3","getRoleMember(bytes32,uint256)":"9010d07c","getRoleMemberCount(bytes32)":"ca15c873","grantRole(bytes32,address)":"2f2ff15d","hasRole(bytes32,address)":"91d14854","renounceRole(bytes32,address)":"36568abe","revokeRole(bytes32,address)":"d547741f","supportsInterface(bytes4)":"01ffc9a7"}},"solidity/FastBridgeV2.sol:Address":{"code":"0x60566037600b82828239805160001a607314602a57634e487b7160e01b600052600060045260246000fd5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600080fdfea264697066735822122053e3727ad57bc90f5560dc5a255131033ea91c54c8a147cf6df38af4aac448d564736f6c63430008180033","runtime-code":"0x73000000000000000000000000000000000000000030146080604052600080fdfea264697066735822122053e3727ad57bc90f5560dc5a255131033ea91c54c8a147cf6df38af4aac448d564736f6c63430008180033","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.24 ^0.8.20 ^0.8.4;\n\n// contracts/interfaces/IAdminV2.sol\n\ninterface IAdminV2 {\n event CancelDelayUpdated(uint256 oldCancelDelay, uint256 newCancelDelay);\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n function setCancelDelay(uint256 newCancelDelay) external;\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n}\n\n// contracts/interfaces/IAdminV2Errors.sol\n\ninterface IAdminV2Errors {\n error CancelDelayBelowMin();\n error FeeRateAboveMax();\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IFastBridgeV2Errors.sol\n\ninterface IFastBridgeV2Errors {\n error AmountIncorrect();\n error ChainIncorrect();\n error ExclusivityParamsIncorrect();\n error MsgValueIncorrect();\n error SenderIncorrect();\n error StatusIncorrect();\n error TokenNotContract();\n error ZapDataLengthAboveMax();\n error ZapNativeNotSupported();\n error ZeroAddress();\n\n error RecipientIncorrectReturnValue();\n error RecipientNoReturnValue();\n\n error DeadlineExceeded();\n error DeadlineNotExceeded();\n error DeadlineTooShort();\n error DisputePeriodNotPassed();\n error DisputePeriodPassed();\n error ExclusivityPeriodNotPassed();\n\n error TransactionRelayed();\n}\n\n// contracts/interfaces/IMulticallTarget.sol\n\n/// @notice Interface for a contract that can be called multiple times by the same caller. Inspired by MulticallV3:\n/// https://github.com/mds1/multicall/blob/master/src/Multicall3.sol\ninterface IMulticallTarget {\n struct Result {\n bool success;\n bytes returnData;\n }\n\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external;\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results);\n}\n\n// contracts/interfaces/IZapRecipient.sol\n\ninterface IZapRecipient {\n function zap(address token, uint256 amount, bytes memory zapData) external payable returns (bytes4);\n}\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// contracts/interfaces/IFastBridgeV2.sol\n\ninterface IFastBridgeV2 is IFastBridge {\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n struct BridgeTxDetails {\n BridgeStatus status;\n uint32 destChainId;\n uint56 proofBlockTimestamp;\n address proofRelayer;\n }\n\n struct BridgeRelay {\n uint48 blockNumber;\n uint48 blockTimestamp;\n address relayer;\n }\n\n /// @notice New params introduced in the FastBridgeV2.\n /// We are passing fields from the older BridgeParams struct outside of this struct\n /// for backwards compatibility.\n /// Note: quoteRelayer and quoteExclusivitySeconds are either both zero (indicating no exclusivity)\n /// or both non-zero (indicating exclusivity for the given period).\n /// Note: zapNative \u003e 0 can NOT be used with destToken = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE (native token)\n /// @param quoteRelayer Relayer that provided the quote for the transaction\n /// @param quoteExclusivitySeconds Period of time the quote relayer is guaranteed exclusivity after user's deposit\n /// @param quoteId Unique quote identifier used for tracking the quote\n /// @param zapNative ETH value to send to the recipient (if any)\n /// @param zapData Parameters for the Zap to the destination recipient (if any)\n struct BridgeParamsV2 {\n address quoteRelayer;\n int256 quoteExclusivitySeconds;\n bytes quoteId;\n uint256 zapNative;\n bytes zapData;\n }\n\n /// @notice Updated bridge transaction struct to include parameters introduced in FastBridgeV2.\n /// Note: only `exclusivityRelayer` can fill such a transaction until `exclusivityEndTime`.\n struct BridgeTransactionV2 {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n // Note: sendChainGas flag from V1 is deprecated\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n address exclusivityRelayer;\n uint256 exclusivityEndTime;\n uint256 zapNative; // ETH value to send to the recipient (if any)\n bytes zapData; // data to pass for the Zap action (if any)\n }\n\n event BridgeQuoteDetails(bytes32 indexed transactionId, bytes quoteId);\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability\n /// to provide temporary exclusivity fill rights for the quote relayer.\n /// @param params The parameters required to bridge\n /// @param paramsV2 The parameters for exclusivity fill rights (optional, can be left empty)\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function relay(bytes memory request, address relayer) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param transactionId The transaction id associated with the encoded bridge transaction to prove\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital.\n /// @notice Can only send funds to the relayer address on the proof.\n /// @param request The encoded bridge transaction to claim on origin chain\n function claim(bytes memory request) external;\n\n /// @notice Cancels an outstanding bridge transaction in case optimistic bridging failed and returns the full amount\n /// to the original sender.\n /// @param request The encoded bridge transaction to refund\n function cancel(bytes memory request) external;\n\n /// @notice Checks if a transaction has been relayed\n /// @param transactionId The ID of the transaction to check\n /// @return True if the transaction has been relayed, false otherwise\n function bridgeRelays(bytes32 transactionId) external view returns (bool);\n\n /// @notice Returns the status of a bridge transaction\n /// @param transactionId The ID of the bridge transaction\n /// @return BridgeStatus Status of the bridge transaction\n function bridgeStatuses(bytes32 transactionId) external view returns (BridgeStatus);\n\n /// @notice Returns the timestamp and relayer of a bridge proof\n /// @param transactionId The ID of the bridge transaction\n /// @return timestamp The timestamp of the bridge proof\n /// @return relayer The relayer address of the bridge proof\n function bridgeProofs(bytes32 transactionId) external view returns (uint96 timestamp, address relayer);\n\n /// @notice Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\n /// @param request The bridge request to decode\n function getBridgeTransactionV2(bytes memory request) external view returns (BridgeTransactionV2 memory);\n}\n\n// contracts/utils/MulticallTarget.sol\n\n// solhint-disable avoid-low-level-calls\n/// @notice Template for a contract that supports batched calls (preserving the msg.sender).\n/// Only calls with zero msg.value could be batched.\nabstract contract MulticallTarget is IMulticallTarget {\n error MulticallTarget__UndeterminedRevert();\n\n /// @notice Perform a batched call to this contract, preserving the msg.sender.\n /// The return data from each call is discarded.\n /// @dev The method is non-payable, so only calls with `msg.value == 0` could be batched.\n /// It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag.\n /// Otherwise, the whole batch call will be reverted with the original revert reason.\n /// @param data List of abi-encoded calldata for the calls to perform.\n /// @param ignoreReverts Whether to ignore the revert errors from the calls.\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external {\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\n if (!success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(result);\n }\n }\n }\n\n /// @notice Perform a batched call to this contract, preserving the msg.sender.\n /// The return data from each call is preserved.\n /// @dev The method is non-payable, so only calls with `msg.value == 0` could be batched.\n /// It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag.\n /// Otherwise, the whole batch call will be reverted with the original revert reason.\n /// @param data List of abi-encoded calldata for the calls to perform.\n /// @param ignoreReverts Whether to ignore the revert errors from the calls.\n /// @return results List of results from the calls: `(success, returnData)`.\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results)\n {\n results = new Result[](data.length);\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (results[i].success, results[i].returnData) = address(this).delegatecall(data[i]);\n if (!results[i].success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(results[i].returnData);\n }\n }\n }\n\n /// @dev Bubbles the revert message from the underlying call.\n /// Note: preserves the same custom error or revert string, if one was used.\n /// Source: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v5.0.2/contracts/utils/Address.sol#L143-L158\n function _bubbleRevert(bytes memory returnData) internal pure {\n // Look for revert reason and bubble it up if present\n if (returnData.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n // solhint-disable-next-line no-inline-assembly\n assembly {\n let returndata_size := mload(returnData)\n revert(add(32, returnData), returndata_size)\n }\n } else {\n revert MulticallTarget__UndeterminedRevert();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// contracts/libs/BridgeTransactionV2.sol\n\n// solhint-disable no-inline-assembly\nlibrary BridgeTransactionV2Lib {\n uint16 internal constant VERSION = 2;\n\n // Offsets of the fields in the packed BridgeTransactionV2 struct\n // uint16 version [000 .. 002)\n // uint32 originChainId [002 .. 006)\n // uint32 destChainId [006 .. 010)\n // address originSender [010 .. 030)\n // address destRecipient [030 .. 050)\n // address originToken [050 .. 070)\n // address destToken [070 .. 090)\n // uint256 originAmount [090 .. 122)\n // uint256 destAmount [122 .. 154)\n // uint256 originFeeAmount [154 .. 186)\n // uint256 deadline [186 .. 218)\n // uint256 nonce [218 .. 250)\n // address exclusivityRelayer [250 .. 270)\n // uint256 exclusivityEndTime [270 .. 302)\n // uint256 zapNative [302 .. 334)\n // bytes zapData [334 .. ***)\n\n // forgefmt: disable-start\n uint256 private constant OFFSET_ORIGIN_CHAIN_ID = 2;\n uint256 private constant OFFSET_DEST_CHAIN_ID = 6;\n uint256 private constant OFFSET_ORIGIN_SENDER = 10;\n uint256 private constant OFFSET_DEST_RECIPIENT = 30;\n uint256 private constant OFFSET_ORIGIN_TOKEN = 50;\n uint256 private constant OFFSET_DEST_TOKEN = 70;\n uint256 private constant OFFSET_ORIGIN_AMOUNT = 90;\n uint256 private constant OFFSET_DEST_AMOUNT = 122;\n uint256 private constant OFFSET_ORIGIN_FEE_AMOUNT = 154;\n uint256 private constant OFFSET_DEADLINE = 186;\n uint256 private constant OFFSET_NONCE = 218;\n uint256 private constant OFFSET_EXCLUSIVITY_RELAYER = 250;\n uint256 private constant OFFSET_EXCLUSIVITY_END_TIME = 270;\n uint256 private constant OFFSET_ZAP_NATIVE = 302;\n uint256 private constant OFFSET_ZAP_DATA = 334;\n // forgefmt: disable-end\n\n error BridgeTransactionV2__InvalidEncodedTx();\n error BridgeTransactionV2__UnsupportedVersion(uint16 version);\n\n /// @notice Validates the encoded transaction to be a tightly packed encoded payload for BridgeTransactionV2.\n /// @dev Checks the minimum length and the version, use this function before decoding any of the fields.\n function validateV2(bytes calldata encodedTx) internal pure {\n // Check the minimum length: must at least include all static fields.\n if (encodedTx.length \u003c OFFSET_ZAP_DATA) revert BridgeTransactionV2__InvalidEncodedTx();\n // Once we validated the length, we can be sure that the version field is present.\n uint16 version_ = version(encodedTx);\n if (version_ != VERSION) revert BridgeTransactionV2__UnsupportedVersion(version_);\n }\n\n /// @notice Encodes the BridgeTransactionV2 struct by tightly packing the fields.\n /// @dev `abi.decode` will not work as a result of the tightly packed fields. Use `decodeV2` to decode instead.\n function encodeV2(IFastBridgeV2.BridgeTransactionV2 memory bridgeTx) internal pure returns (bytes memory) {\n // We split the encoding into two parts to avoid stack-too-deep error\n bytes memory firstPart = abi.encodePacked(\n VERSION,\n bridgeTx.originChainId,\n bridgeTx.destChainId,\n bridgeTx.originSender,\n bridgeTx.destRecipient,\n bridgeTx.originToken,\n bridgeTx.destToken,\n bridgeTx.originAmount\n );\n return abi.encodePacked(\n firstPart,\n bridgeTx.destAmount,\n bridgeTx.originFeeAmount,\n // Note: we skip the deprecated `sendChainGas` flag, which was present in BridgeTransaction V1\n bridgeTx.deadline,\n bridgeTx.nonce,\n // New V2 fields: exclusivity\n bridgeTx.exclusivityRelayer,\n bridgeTx.exclusivityEndTime,\n // New V2 fields: Zap\n bridgeTx.zapNative,\n bridgeTx.zapData\n );\n }\n\n /// @notice Decodes the BridgeTransactionV2 struct from the encoded transaction.\n /// @dev Encoded BridgeTransactionV2 struct must be tightly packed.\n /// Use `validateV2` before decoding to ensure the encoded transaction is valid.\n function decodeV2(bytes calldata encodedTx)\n internal\n pure\n returns (IFastBridgeV2.BridgeTransactionV2 memory bridgeTx)\n {\n bridgeTx.originChainId = originChainId(encodedTx);\n bridgeTx.destChainId = destChainId(encodedTx);\n bridgeTx.originSender = originSender(encodedTx);\n bridgeTx.destRecipient = destRecipient(encodedTx);\n bridgeTx.originToken = originToken(encodedTx);\n bridgeTx.destToken = destToken(encodedTx);\n bridgeTx.originAmount = originAmount(encodedTx);\n bridgeTx.destAmount = destAmount(encodedTx);\n bridgeTx.originFeeAmount = originFeeAmount(encodedTx);\n bridgeTx.deadline = deadline(encodedTx);\n bridgeTx.nonce = nonce(encodedTx);\n bridgeTx.exclusivityRelayer = exclusivityRelayer(encodedTx);\n bridgeTx.exclusivityEndTime = exclusivityEndTime(encodedTx);\n bridgeTx.zapNative = zapNative(encodedTx);\n bridgeTx.zapData = zapData(encodedTx);\n }\n\n /// @notice Extracts the version from the encoded transaction.\n function version(bytes calldata encodedTx) internal pure returns (uint16 version_) {\n // Load 32 bytes from the start and shift it 240 bits to the right to get the highest 16 bits.\n assembly {\n version_ := shr(240, calldataload(encodedTx.offset))\n }\n }\n\n /// @notice Extracts the origin chain ID from the encoded transaction.\n function originChainId(bytes calldata encodedTx) internal pure returns (uint32 originChainId_) {\n // Load 32 bytes from the offset and shift it 224 bits to the right to get the highest 32 bits.\n assembly {\n originChainId_ := shr(224, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_CHAIN_ID)))\n }\n }\n\n /// @notice Extracts the destination chain ID from the encoded transaction.\n function destChainId(bytes calldata encodedTx) internal pure returns (uint32 destChainId_) {\n // Load 32 bytes from the offset and shift it 224 bits to the right to get the highest 32 bits.\n assembly {\n destChainId_ := shr(224, calldataload(add(encodedTx.offset, OFFSET_DEST_CHAIN_ID)))\n }\n }\n\n /// @notice Extracts the origin sender from the encoded transaction.\n function originSender(bytes calldata encodedTx) internal pure returns (address originSender_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n originSender_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_SENDER)))\n }\n }\n\n /// @notice Extracts the destination recipient from the encoded transaction.\n function destRecipient(bytes calldata encodedTx) internal pure returns (address destRecipient_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n destRecipient_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_DEST_RECIPIENT)))\n }\n }\n\n /// @notice Extracts the origin token from the encoded transaction.\n function originToken(bytes calldata encodedTx) internal pure returns (address originToken_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n originToken_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_TOKEN)))\n }\n }\n\n /// @notice Extracts the destination token from the encoded transaction.\n function destToken(bytes calldata encodedTx) internal pure returns (address destToken_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n destToken_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_DEST_TOKEN)))\n }\n }\n\n /// @notice Extracts the origin amount from the encoded transaction.\n function originAmount(bytes calldata encodedTx) internal pure returns (uint256 originAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n originAmount_ := calldataload(add(encodedTx.offset, OFFSET_ORIGIN_AMOUNT))\n }\n }\n\n /// @notice Extracts the destination amount from the encoded transaction.\n function destAmount(bytes calldata encodedTx) internal pure returns (uint256 destAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n destAmount_ := calldataload(add(encodedTx.offset, OFFSET_DEST_AMOUNT))\n }\n }\n\n /// @notice Extracts the origin fee amount from the encoded transaction.\n function originFeeAmount(bytes calldata encodedTx) internal pure returns (uint256 originFeeAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n originFeeAmount_ := calldataload(add(encodedTx.offset, OFFSET_ORIGIN_FEE_AMOUNT))\n }\n }\n\n /// @notice Extracts the deadline from the encoded transaction.\n function deadline(bytes calldata encodedTx) internal pure returns (uint256 deadline_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n deadline_ := calldataload(add(encodedTx.offset, OFFSET_DEADLINE))\n }\n }\n\n /// @notice Extracts the nonce from the encoded transaction.\n function nonce(bytes calldata encodedTx) internal pure returns (uint256 nonce_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n nonce_ := calldataload(add(encodedTx.offset, OFFSET_NONCE))\n }\n }\n\n /// @notice Extracts the exclusivity relayer from the encoded transaction.\n function exclusivityRelayer(bytes calldata encodedTx) internal pure returns (address exclusivityRelayer_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n exclusivityRelayer_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_EXCLUSIVITY_RELAYER)))\n }\n }\n\n /// @notice Extracts the exclusivity end time from the encoded transaction.\n function exclusivityEndTime(bytes calldata encodedTx) internal pure returns (uint256 exclusivityEndTime_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n exclusivityEndTime_ := calldataload(add(encodedTx.offset, OFFSET_EXCLUSIVITY_END_TIME))\n }\n }\n\n /// @notice Extracts the Zap's native value from the encoded transaction.\n function zapNative(bytes calldata encodedTx) internal pure returns (uint256 zapNative_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n zapNative_ := calldataload(add(encodedTx.offset, OFFSET_ZAP_NATIVE))\n }\n }\n\n /// @notice Extracts the Zap's data from the encoded transaction.\n function zapData(bytes calldata encodedTx) internal pure returns (bytes calldata zapData_) {\n zapData_ = encodedTx[OFFSET_ZAP_DATA:];\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/AdminV2.sol\n\ncontract AdminV2 is AccessControlEnumerable, IAdminV2, IAdminV2Errors {\n using SafeERC20 for IERC20;\n\n /// @notice Address reserved for native gas token (ETH on Ethereum and most L2s, AVAX on Avalanche, etc)\n address public constant NATIVE_GAS_TOKEN = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Role identifier for Quoter API's off-chain authentication.\n /// @dev Only addresses with this role can post FastBridge quotes to the API.\n bytes32 public constant QUOTER_ROLE = keccak256(\"QUOTER_ROLE\");\n\n /// @notice Role identifier for Prover's on-chain authentication in FastBridge.\n /// @dev Only addresses with this role can provide proofs that a FastBridge request has been relayed.\n bytes32 public constant PROVER_ROLE = keccak256(\"PROVER_ROLE\");\n\n /// @notice Role identifier for Guard's on-chain authentication in FastBridge.\n /// @dev Only addresses with this role can dispute submitted relay proofs during the dispute period.\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n\n /// @notice Role identifier for Canceler's on-chain authentication in FastBridge.\n /// @dev Only addresses with this role can cancel a FastBridge transaction without the cancel delay.\n bytes32 public constant CANCELER_ROLE = keccak256(\"CANCELER_ROLE\");\n\n /// @notice Role identifier for Governor's on-chain administrative authority.\n /// @dev Only addresses with this role can perform administrative tasks within the contract.\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n /// @notice Denominator for fee rates, represents 100%.\n uint256 public constant FEE_BPS = 1e6;\n /// @notice Maximum protocol fee rate: 1% on origin amount.\n uint256 public constant FEE_RATE_MAX = 0.01e6;\n\n /// @notice Minimum cancel delay that can be set by the governor.\n uint256 public constant MIN_CANCEL_DELAY = 1 hours;\n /// @notice Default cancel delay set during the contract deployment.\n uint256 public constant DEFAULT_CANCEL_DELAY = 1 days;\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Delay for a transaction after which it could be permisionlessly cancelled\n uint256 public cancelDelay;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Use ZapNative V2 requests instead.\n uint256 public immutable chainGasAmount = 0;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n _setCancelDelay(DEFAULT_CANCEL_DELAY);\n }\n\n /// @notice Allows the contract governor to set the cancel delay. The cancel delay is the time after the transaction\n /// deadline after which it can be permissionlessly cancelled, if it hasn't been proven by any of the Relayers.\n function setCancelDelay(uint256 newCancelDelay) external onlyRole(GOVERNOR_ROLE) {\n _setCancelDelay(newCancelDelay);\n }\n\n /// @notice Allows the contract governor to set the protocol fee rate. The protocol fee is taken from the origin\n /// amount only for completed and claimed transactions.\n /// @dev The protocol fee is abstracted away from the relayers, they always operate using the amounts after fees:\n /// what they see as the origin amount emitted in the log is what they get credited with.\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n if (newFeeRate \u003e FEE_RATE_MAX) revert FeeRateAboveMax();\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n /// @notice Allows the contract governor to sweep the accumulated protocol fees in the contract.\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n emit FeesSwept(token, recipient, feeAmount);\n /// Sweep the fees as the last transaction action\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(recipient), feeAmount);\n } else {\n IERC20(token).safeTransfer(recipient, feeAmount);\n }\n }\n\n /// @notice Internal function to set the cancel delay. Security checks are performed outside of this function.\n function _setCancelDelay(uint256 newCancelDelay) private {\n if (newCancelDelay \u003c MIN_CANCEL_DELAY) revert CancelDelayBelowMin();\n uint256 oldCancelDelay = cancelDelay;\n cancelDelay = newCancelDelay;\n emit CancelDelayUpdated(oldCancelDelay, newCancelDelay);\n }\n}\n\n// contracts/FastBridgeV2.sol\n\n/// @notice FastBridgeV2 is a contract for bridging tokens across chains.\ncontract FastBridgeV2 is AdminV2, MulticallTarget, IFastBridgeV2, IFastBridgeV2Errors {\n using BridgeTransactionV2Lib for bytes;\n using SafeERC20 for IERC20;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n /// @notice Maximum length of accepted zapData\n uint256 public constant MAX_ZAP_DATA_LENGTH = 2 ** 16 - 1;\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeTxDetails) public bridgeTxDetails;\n /// @notice Relay details on destination chain\n mapping(bytes32 =\u003e BridgeRelay) public bridgeRelayDetails;\n /// @notice Unique bridge nonces tracked per originSender\n mapping(address =\u003e uint256) public senderNonces;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Replaced by senderNonces\n uint256 public immutable nonce = 0;\n /// @notice the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) AdminV2(_owner) {\n deployBlock = block.number;\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n bridge({\n params: params,\n paramsV2: BridgeParamsV2({\n quoteRelayer: address(0),\n quoteExclusivitySeconds: 0,\n quoteId: bytes(\"\"),\n zapNative: 0,\n zapData: bytes(\"\")\n })\n });\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes calldata request) external payable {\n // relay override will validate the request\n relay({request: request, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes calldata request, bytes32 destTxHash) external {\n request.validateV2();\n prove({transactionId: keccak256(request), destTxHash: destTxHash, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridgeV2\n function claim(bytes calldata request) external {\n // claim override will validate the request\n claim({request: request, to: address(0)});\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Aggregate the read operations from the same storage slot\n address disputedRelayer = $.proofRelayer;\n BridgeStatus status = $.status;\n uint56 proofBlockTimestamp = $.proofBlockTimestamp;\n // Can only dispute a RELAYER_PROVED transaction within the dispute period\n if (status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(proofBlockTimestamp) \u003e DISPUTE_PERIOD) {\n revert DisputePeriodPassed();\n }\n // Update status to REQUESTED and delete the disputed proof details\n // Note: these are storage writes\n $.status = BridgeStatus.REQUESTED;\n $.proofRelayer = address(0);\n $.proofBlockTimestamp = 0;\n\n emit BridgeProofDisputed(transactionId, disputedRelayer);\n }\n\n /// Note: this function is deprecated and will be removed in a future version.\n /// @inheritdoc IFastBridge\n function refund(bytes calldata request) external {\n cancel(request);\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // The correct relayer can only claim a RELAYER_PROVED transaction after the dispute period\n if ($.status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if ($.proofRelayer != relayer) revert SenderIncorrect();\n return _timeSince($.proofBlockTimestamp) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n /// @dev This method is added to achieve backwards compatibility with decoding requests into V1 structs:\n /// - `zapNative` is partially reported as a zero/non-zero flag\n /// - `zapData` is ignored\n /// In order to process all kinds of requests use getBridgeTransactionV2 instead.\n function getBridgeTransaction(bytes calldata request) external view returns (BridgeTransaction memory) {\n // Try decoding into V2 struct first. This will revert if V1 struct is passed\n try this.getBridgeTransactionV2(request) returns (BridgeTransactionV2 memory txV2) {\n // Note: we entirely ignore the zapData field, as it was not present in V1\n return BridgeTransaction({\n originChainId: txV2.originChainId,\n destChainId: txV2.destChainId,\n originSender: txV2.originSender,\n destRecipient: txV2.destRecipient,\n originToken: txV2.originToken,\n destToken: txV2.destToken,\n originAmount: txV2.originAmount,\n destAmount: txV2.destAmount,\n originFeeAmount: txV2.originFeeAmount,\n sendChainGas: txV2.zapNative != 0,\n deadline: txV2.deadline,\n nonce: txV2.nonce\n });\n } catch {\n // Fallback to V1 struct\n return abi.decode(request, (BridgeTransaction));\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function getBridgeTransactionV2(bytes calldata request) external pure returns (BridgeTransactionV2 memory) {\n request.validateV2();\n return BridgeTransactionV2Lib.decodeV2(request);\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) public payable {\n int256 exclusivityEndTime = 0;\n // if relayer exclusivity is not intended for this bridge, set exclusivityEndTime to static zero\n // otherwise, set exclusivity to expire at the current block ts offset by quoteExclusivitySeconds\n if (paramsV2.quoteRelayer != address(0)) {\n exclusivityEndTime = int256(block.timestamp) + paramsV2.quoteExclusivitySeconds;\n }\n _validateBridgeParams(params, paramsV2, exclusivityEndTime);\n\n // transfer tokens to bridge contract\n /// @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _takeBridgedUserAsset(params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) {\n originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n }\n\n // set status to requested\n bytes memory request = BridgeTransactionV2Lib.encodeV2(\n BridgeTransactionV2({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n deadline: params.deadline,\n nonce: senderNonces[params.sender]++, // increment nonce on every bridge\n exclusivityRelayer: paramsV2.quoteRelayer,\n // We checked exclusivityEndTime to be in range [0 .. params.deadline] above, so can safely cast\n exclusivityEndTime: uint256(exclusivityEndTime),\n zapNative: paramsV2.zapNative,\n zapData: paramsV2.zapData\n })\n );\n bytes32 transactionId = keccak256(request);\n // Note: the tx status will be updated throughout the tx lifecycle, while destChainId is set once here\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n bridgeTxDetails[transactionId].destChainId = params.dstChainId;\n\n emit BridgeRequested({\n transactionId: transactionId,\n sender: params.sender,\n request: request,\n destChainId: params.dstChainId,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n sendChainGas: paramsV2.zapNative != 0\n });\n emit BridgeQuoteDetails(transactionId, paramsV2.quoteId);\n }\n\n /// @inheritdoc IFastBridgeV2\n function relay(bytes calldata request, address relayer) public payable {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n _validateRelayParams(request, transactionId, relayer);\n // mark bridge transaction as relayed\n bridgeRelayDetails[transactionId] =\n BridgeRelay({blockNumber: uint48(block.number), blockTimestamp: uint48(block.timestamp), relayer: relayer});\n\n // transfer tokens to recipient on destination chain and trigger Zap if requested\n address to = request.destRecipient();\n address token = request.destToken();\n uint256 amount = request.destAmount();\n uint256 zapNative = request.zapNative();\n\n // Emit the event before any external calls\n emit BridgeRelayed({\n transactionId: transactionId,\n relayer: relayer,\n to: to,\n originChainId: request.originChainId(),\n originToken: request.originToken(),\n destToken: token,\n originAmount: request.originAmount(),\n destAmount: amount,\n chainGasAmount: zapNative\n });\n\n // All state changes have been done at this point, can proceed to the external calls.\n // This follows the checks-effects-interactions pattern to mitigate potential reentrancy attacks.\n if (token == NATIVE_GAS_TOKEN) {\n // For the native gas token, additional zapNative is not allowed\n if (zapNative != 0) revert ZapNativeNotSupported();\n // Check that the correct msg.value was sent\n if (msg.value != amount) revert MsgValueIncorrect();\n // Don't do a native transfer yet: we will handle it alongside the Zap below\n } else {\n // For ERC20s, we check that the correct msg.value was sent\n if (msg.value != zapNative) revert MsgValueIncorrect();\n // We need to transfer the tokens from the Relayer to the recipient first before performing an\n // optional post-transfer Zap.\n IERC20(token).safeTransferFrom(msg.sender, to, amount);\n }\n // At this point we have done:\n // - Transferred the requested amount of ERC20 tokens to the recipient.\n // At this point we have confirmed:\n // - For ERC20s: msg.value matches the requested zapNative amount.\n // - For the native gas token: msg.value matches the requested destAmount.\n // Remaining optional things to do:\n // - Forward the full msg.value to the recipient (if non-zero).\n // - Trigger a Zap (if zapData is present).\n bytes calldata zapData = request.zapData();\n if (zapData.length != 0) {\n // Zap Data is present: Zap has been requested by the recipient. Trigger it forwarding the full msg.value.\n\n // Note: if token has a fee on transfers, the recipient will have received less than `amount`.\n // This is a very niche edge case and should be handled by the recipient contract.\n _triggerZapWithChecks({recipient: to, token: token, amount: amount, zapData: zapData});\n } else if (msg.value != 0) {\n // Zap Data is missing, but msg.value was sent. This could happen in two different cases:\n // - Relay with the native gas token is happening.\n // - Relay with ERC20 is happening, with a `zapNative \u003e 0` request.\n // In both cases, we need to transfer the full msg.value to the recipient.\n Address.sendValue(payable(to), msg.value);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) public onlyRole(PROVER_ROLE) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n\n // Can only prove a REQUESTED transaction\n if ($.status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n // Update status to RELAYER_PROVED and store the proof details\n // Note: these are storage writes\n $.status = BridgeStatus.RELAYER_PROVED;\n $.proofBlockTimestamp = uint56(block.timestamp);\n $.proofRelayer = relayer;\n\n emit BridgeProofProvided(transactionId, relayer, destTxHash);\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes calldata request, address to) public {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Aggregate the read operations from the same storage slot\n address proofRelayer = $.proofRelayer;\n BridgeStatus status = $.status;\n uint56 proofBlockTimestamp = $.proofBlockTimestamp;\n\n // Can only claim a RELAYER_PROVED transaction after the dispute period\n if (status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(proofBlockTimestamp) \u003c= DISPUTE_PERIOD) {\n revert DisputePeriodNotPassed();\n }\n\n if (to == address(0)) {\n // Anyone could claim the funds to the proven relayer on their behalf\n to = proofRelayer;\n } else if (proofRelayer != msg.sender) {\n // Only the proven relayer could specify an address to claim the funds to\n revert SenderIncorrect();\n }\n\n // Update status to RELAYER_CLAIMED and transfer the origin collateral to the specified claim address\n // Note: this is a storage write\n $.status = BridgeStatus.RELAYER_CLAIMED;\n\n address token = request.originToken();\n uint256 amount = request.originAmount();\n // Update protocol fees if origin fee amount exists\n uint256 originFeeAmount = request.originFeeAmount();\n if (originFeeAmount \u003e 0) protocolFees[token] += originFeeAmount;\n // Emit the event before any external calls\n emit BridgeDepositClaimed(transactionId, proofRelayer, to, token, amount);\n // Complete the relayer claim as the last transaction action\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(to), amount);\n } else {\n IERC20(token).safeTransfer(to, amount);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function cancel(bytes calldata request) public {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Can only cancel a REQUESTED transaction after its deadline expires\n if ($.status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n uint256 deadline = request.deadline();\n // Permissionless cancel is only allowed after `cancelDelay` on top of the deadline\n if (!hasRole(CANCELER_ROLE, msg.sender)) deadline += cancelDelay;\n if (block.timestamp \u003c= deadline) revert DeadlineNotExceeded();\n // Update status to REFUNDED and return the full amount (collateral + protocol fees) to the original sender.\n // The protocol fees are only updated when the transaction is claimed, so we don't need to update them here.\n // Note: this is a storage write\n $.status = BridgeStatus.REFUNDED;\n\n address to = request.originSender();\n address token = request.originToken();\n uint256 amount = request.originAmount() + request.originFeeAmount();\n // Emit the event before any external calls\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n // Complete the user cancel as the last transaction action\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(to), amount);\n } else {\n IERC20(token).safeTransfer(to, amount);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeStatuses(bytes32 transactionId) public view returns (BridgeStatus status) {\n return bridgeTxDetails[transactionId].status;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeProofs(bytes32 transactionId) public view returns (uint96 timestamp, address relayer) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n\n timestamp = $.proofBlockTimestamp;\n relayer = $.proofRelayer;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeRelays(bytes32 transactionId) public view returns (bool) {\n // has this transactionId been relayed?\n return bridgeRelayDetails[transactionId].relayer != address(0);\n }\n\n /// @notice Takes the bridged asset from the user into FastBridgeV2 custody. It will be later\n /// claimed by the relayer who completed the relay on destination chain, or transferred back to the user\n /// via the cancel function should no one complete the relay.\n function _takeBridgedUserAsset(address token, uint256 amount) internal returns (uint256 amountTaken) {\n if (token == NATIVE_GAS_TOKEN) {\n // For the native gas token, we just need to check that the supplied msg.value is correct.\n // Supplied `msg.value` is already in FastBridgeV2 custody.\n if (amount != msg.value) revert MsgValueIncorrect();\n amountTaken = msg.value;\n } else {\n // For ERC20s, token is explicitly transferred from the user to FastBridgeV2.\n // We don't allow non-zero `msg.value` to avoid extra funds from being stuck in FastBridgeV2.\n if (msg.value != 0) revert MsgValueIncorrect();\n // Throw an explicit error if the provided token address is not a contract\n if (token.code.length == 0) revert TokenNotContract();\n amountTaken = IERC20(token).balanceOf(address(this));\n IERC20(token).safeTransferFrom(msg.sender, address(this), amount);\n // Use the balance difference as the amount taken in case of fee on transfer tokens.\n amountTaken = IERC20(token).balanceOf(address(this)) - amountTaken;\n }\n }\n\n /// @notice Calls the Recipient's hook function with the specified zapData and performs\n /// all the necessary checks for the returned value.\n function _triggerZapWithChecks(address recipient, address token, uint256 amount, bytes calldata zapData) internal {\n // This will bubble any revert messages from the hook function\n bytes memory returnData = Address.functionCallWithValue({\n target: recipient,\n data: abi.encodeCall(IZapRecipient.zap, (token, amount, zapData)),\n // Note: see `relay()` for reasoning behind passing msg.value\n value: msg.value\n });\n // Explicit revert if no return data at all\n if (returnData.length == 0) revert RecipientNoReturnValue();\n // Check that exactly a single return value was returned\n if (returnData.length != 32) revert RecipientIncorrectReturnValue();\n // Return value should be abi-encoded hook function selector\n if (bytes32(returnData) != bytes32(IZapRecipient.zap.selector)) {\n revert RecipientIncorrectReturnValue();\n }\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint56(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint56).max but\n /// proof.timestamp \u003c type(uint56).max via unchecked statement\n /// @param proofBlockTimestamp The bridge proof block timestamp\n /// @return delta Time delta since proof submitted\n function _timeSince(uint56 proofBlockTimestamp) internal view returns (uint256 delta) {\n unchecked {\n delta = uint56(block.timestamp) - proofBlockTimestamp;\n }\n }\n\n /// @notice Performs all the necessary checks for a bridge to happen.\n /// @dev There's no good way to refactor this function to reduce cyclomatic complexity due to\n /// the number of checks that need to be performed, so we skip the code-complexity rule here.\n // solhint-disable-next-line code-complexity\n function _validateBridgeParams(\n BridgeParams memory params,\n BridgeParamsV2 memory paramsV2,\n int256 exclusivityEndTime\n )\n internal\n view\n {\n // Check V1 (legacy) params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.sender == address(0) || params.to == address(0)) revert ZeroAddress();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n // Check V2 params\n if (paramsV2.zapData.length \u003e MAX_ZAP_DATA_LENGTH) revert ZapDataLengthAboveMax();\n if (paramsV2.zapNative != 0 \u0026\u0026 params.destToken == NATIVE_GAS_TOKEN) {\n revert ZapNativeNotSupported();\n }\n // exclusivityEndTime must be in range [0 .. params.deadline]\n if (exclusivityEndTime \u003c 0 || exclusivityEndTime \u003e int256(params.deadline)) {\n revert ExclusivityParamsIncorrect();\n }\n }\n\n /// @notice Performs all the necessary checks for a relay to happen.\n function _validateRelayParams(bytes calldata request, bytes32 transactionId, address relayer) internal view {\n if (relayer == address(0)) revert ZeroAddress();\n // Check if the transaction has already been relayed\n if (bridgeRelays(transactionId)) revert TransactionRelayed();\n if (request.destChainId() != block.chainid) revert ChainIncorrect();\n // Check the deadline for relay to happen\n if (block.timestamp \u003e request.deadline()) revert DeadlineExceeded();\n // Check the exclusivity period, if it is still ongoing\n address exclRelayer = request.exclusivityRelayer();\n if (exclRelayer != address(0) \u0026\u0026 exclRelayer != relayer \u0026\u0026 block.timestamp \u003c= request.exclusivityEndTime()) {\n revert ExclusivityPeriodNotPassed();\n }\n }\n}\n","language":"Solidity","languageVersion":"0.8.24","compilerVersion":"0.8.24","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"16568:6066:0:-:0;;;;;;;;;;;;;;;-1:-1:-1;;;16568:6066:0;;;;;;;;;;;;;;;;;","srcMapRuntime":"16568:6066:0:-:0;;;;;;;;","abiDefinition":[{"inputs":[{"internalType":"address","name":"target","type":"address"}],"name":"AddressEmptyCode","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"AddressInsufficientBalance","type":"error"},{"inputs":[],"name":"FailedInnerCall","type":"error"}],"userDoc":{"kind":"user","methods":{},"version":1},"developerDoc":{"details":"Collection of functions related to the address type","errors":{"AddressEmptyCode(address)":[{"details":"There's no code at `target` (it is not a contract)."}],"AddressInsufficientBalance(address)":[{"details":"The ETH balance of the account is not enough to perform the operation."}],"FailedInnerCall()":[{"details":"A call to an address target failed. The target may have reverted."}]},"kind":"dev","methods":{},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"}],\"name\":\"AddressEmptyCode\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"AddressInsufficientBalance\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"FailedInnerCall\",\"type\":\"error\"}],\"devdoc\":{\"details\":\"Collection of functions related to the address type\",\"errors\":{\"AddressEmptyCode(address)\":[{\"details\":\"There's no code at `target` (it is not a contract).\"}],\"AddressInsufficientBalance(address)\":[{\"details\":\"The ETH balance of the account is not enough to perform the operation.\"}],\"FailedInnerCall()\":[{\"details\":\"A call to an address target failed. The target may have reverted.\"}]},\"kind\":\"dev\",\"methods\":{},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeV2.sol\":\"Address\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeV2.sol\":{\"keccak256\":\"0xac79c463688a682ca706a4ef95e7817b83548cdfa8182ba0426ac7e5e07613d8\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://b3ecb7097381287cafc3a73f3a2bb03565115ebb682a85064e0b0dc2f7e2919d\",\"dweb:/ipfs/QmatruW3nYZTksf3CeQ8wwiAG4c7xoEJBEp6drHPtFLBRK\"]}},\"version\":1}"},"hashes":{}},"solidity/FastBridgeV2.sol:AdminV2":{"code":"0x60a060405260006080523480156200001657600080fd5b50604051620015763803806200157683398101604081905262000039916200020a565b620000466000826200005c565b50620000556201518062000099565b5062000235565b6000806200006b848462000102565b90508015620000905760008481526001602052604090206200008e9084620001b0565b505b90505b92915050565b610e10811015620000bd57604051630e0ea5c760e01b815260040160405180910390fd5b600480549082905560408051828152602081018490527f909f9078b2f6eac1d10f2aae793656c5a67511eb627ebd1d2cb1eb9c0ab94c95910160405180910390a15050565b6000828152602081815260408083206001600160a01b038516845290915281205460ff16620001a7576000838152602081815260408083206001600160a01b03861684529091529020805460ff191660011790556200015e3390565b6001600160a01b0316826001600160a01b0316847f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a450600162000093565b50600062000093565b600062000090836001600160a01b0384166000818152600183016020526040812054620001a75750815460018181018455600084815260208082209093018490558454848252828601909352604090209190915562000093565b6000602082840312156200021d57600080fd5b81516001600160a01b03811681146200009057600080fd5b60805161132562000251600039600061045201526113256000f3fe608060405234801561001057600080fd5b50600436106101ae5760003560e01c80639010d07c116100ee578063bf333f2c11610097578063d547741f11610071578063d547741f146103f3578063dc9a4ef614610406578063dcf844a71461042d578063e00a83e01461044d57600080fd5b8063bf333f2c146103af578063ca15c873146103b9578063ccc57490146103cc57600080fd5b8063930ac180116100c8578063930ac1801461038a578063a217fddf14610394578063b13aa2d61461039c57600080fd5b80639010d07c1461032a57806391d148541461033d578063922b74871461038157600080fd5b80631ea327c51161015b57806336568abe1161013557806336568abe146102de57806358f85880146102f1578063638a0f09146102fa5780637ebe815c1461030357600080fd5b80631ea327c514610295578063248a9ca3146102a85780632f2ff15d146102cb57600080fd5b806306f333f21161018c57806306f333f2146102375780630f5f6ed71461024c5780630f862f1e1461025557600080fd5b806301ffc9a7146101b357806302d2ff66146101db57806303ed0ee514610210575b600080fd5b6101c66101c13660046110ef565b610474565b60405190151581526020015b60405180910390f35b6102027febfdca8e46c0b8dacf9989ee613e35727eadd20a1d5e5ad01a53968c7e5fe07a81565b6040519081526020016101d2565b6102027f043c983c49d46f0e102151eaf8085d4a2e6571d5df2d47b013f39bddfd4a639d81565b61024a61024536600461115a565b6104d0565b005b61020261271081565b61027073eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee81565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016101d2565b61024a6102a336600461118d565b610611565b6102026102b636600461118d565b60009081526020819052604090206001015490565b61024a6102d93660046111a6565b610648565b61024a6102ec3660046111a6565b61066d565b61020260025481565b61020260045481565b6102027f9a04aea0a349253cc7277afafdf6ead6729a3972a47ffb40eaef2c93d4e1bfea81565b6102706103383660046111c9565b6106c6565b6101c661034b3660046111a6565b60009182526020828152604080842073ffffffffffffffffffffffffffffffffffffffff93909316845291905290205460ff1690565b610202610e1081565b6102026201518081565b610202600081565b61024a6103aa36600461118d565b6106e5565b610202620f424081565b6102026103c736600461118d565b610791565b6102027f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f5581565b61024a6104013660046111a6565b6107a8565b6102027f60044782a422109ac08a415e44260ad5d3bad63d96ebe1fac0363399642ee3f281565b61020261043b3660046111eb565b60036020526000908152604090205481565b6102027f000000000000000000000000000000000000000000000000000000000000000081565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f5a05180f0000000000000000000000000000000000000000000000000000000014806104ca57506104ca826107cd565b92915050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f556104fa81610864565b73ffffffffffffffffffffffffffffffffffffffff83166000908152600360205260408120549081900361052e5750505050565b73ffffffffffffffffffffffffffffffffffffffff8481166000818152600360209081526040808320929092558151928352928616928201929092529081018290527f244e51bc38c1452fa8aaf487bcb4bca36c2baa3a5fbdb776b1eabd8dc6d277cd9060600160405180910390a17fffffffffffffffffffffffff111111111111111111111111111111111111111273ffffffffffffffffffffffffffffffffffffffff8516016105e9576105e48382610871565b61060a565b61060a73ffffffffffffffffffffffffffffffffffffffff8516848361094c565b505b505050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f5561063b81610864565b610644826109d9565b5050565b60008281526020819052604090206001015461066381610864565b61060a8383610a5a565b73ffffffffffffffffffffffffffffffffffffffff811633146106bc576040517f6697b23200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61060c8282610a8f565b60008281526001602052604081206106de9083610abc565b9392505050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f5561070f81610864565b61271082111561074b576040517f9b569b8100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600280549083905560408051828152602081018590527f14914da2bf76024616fbe1859783fcd4dbddcb179b1f3a854949fbf920dcb957910160405180910390a1505050565b60008181526001602052604081206104ca90610ac8565b6000828152602081905260409020600101546107c381610864565b61060a8383610a8f565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f7965db0b0000000000000000000000000000000000000000000000000000000014806104ca57507f01ffc9a7000000000000000000000000000000000000000000000000000000007fffffffff000000000000000000000000000000000000000000000000000000008316146104ca565b61086e8133610ad2565b50565b804710156108b2576040517fcd7860590000000000000000000000000000000000000000000000000000000081523060048201526024015b60405180910390fd5b60008273ffffffffffffffffffffffffffffffffffffffff168260405160006040518083038185875af1925050503d806000811461090c576040519150601f19603f3d011682016040523d82523d6000602084013e610911565b606091505b505090508061060c576040517f1425ea4200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040805173ffffffffffffffffffffffffffffffffffffffff8416602482015260448082018490528251808303909101815260649091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fa9059cbb0000000000000000000000000000000000000000000000000000000017905261060c908490610b58565b610e10811015610a15576040517f0e0ea5c700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600480549082905560408051828152602081018490527f909f9078b2f6eac1d10f2aae793656c5a67511eb627ebd1d2cb1eb9c0ab94c95910160405180910390a15050565b600080610a678484610bee565b905080156106de576000848152600160205260409020610a879084610cea565b509392505050565b600080610a9c8484610d0c565b905080156106de576000848152600160205260409020610a879084610dc7565b60006106de8383610de9565b60006104ca825490565b60008281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915290205460ff16610644576040517fe2517d3f00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff82166004820152602481018390526044016108a9565b6000610b7a73ffffffffffffffffffffffffffffffffffffffff841683610e13565b90508051600014158015610b9f575080806020019051810190610b9d9190611206565b155b1561060c576040517f5274afe700000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff841660048201526024016108a9565b60008281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915281205460ff16610ce25760008381526020818152604080832073ffffffffffffffffffffffffffffffffffffffff86168452909152902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055610c803390565b73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16847f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45060016104ca565b5060006104ca565b60006106de8373ffffffffffffffffffffffffffffffffffffffff8416610e21565b60008281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915281205460ff1615610ce25760008381526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8616808552925280832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016905551339286917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a45060016104ca565b60006106de8373ffffffffffffffffffffffffffffffffffffffff8416610e68565b6000826000018281548110610e0057610e00611228565b9060005260206000200154905092915050565b60606106de83836000610f5b565b6000818152600183016020526040812054610ce2575081546001818101845560008481526020808220909301849055845484825282860190935260409020919091556104ca565b60008181526001830160205260408120548015610f51576000610e8c600183611257565b8554909150600090610ea090600190611257565b9050808214610f05576000866000018281548110610ec057610ec0611228565b9060005260206000200154905080876000018481548110610ee357610ee3611228565b6000918252602080832090910192909255918252600188019052604090208390555b8554869080610f1657610f16611291565b6001900381819060005260206000200160009055905585600101600086815260200190815260200160002060009055600193505050506104ca565b60009150506104ca565b606081471015610f99576040517fcd7860590000000000000000000000000000000000000000000000000000000081523060048201526024016108a9565b6000808573ffffffffffffffffffffffffffffffffffffffff168486604051610fc291906112c0565b60006040518083038185875af1925050503d8060008114610fff576040519150601f19603f3d011682016040523d82523d6000602084013e611004565b606091505b509150915061101486838361101e565b9695505050505050565b6060826110335761102e826110ad565b6106de565b8151158015611057575073ffffffffffffffffffffffffffffffffffffffff84163b155b156110a6576040517f9996b31500000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff851660048201526024016108a9565b50806106de565b8051156110bd5780518082602001fd5b6040517f1425ea4200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006020828403121561110157600080fd5b81357fffffffff00000000000000000000000000000000000000000000000000000000811681146106de57600080fd5b803573ffffffffffffffffffffffffffffffffffffffff8116811461115557600080fd5b919050565b6000806040838503121561116d57600080fd5b61117683611131565b915061118460208401611131565b90509250929050565b60006020828403121561119f57600080fd5b5035919050565b600080604083850312156111b957600080fd5b8235915061118460208401611131565b600080604083850312156111dc57600080fd5b50508035926020909101359150565b6000602082840312156111fd57600080fd5b6106de82611131565b60006020828403121561121857600080fd5b815180151581146106de57600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b818103818111156104ca577f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fd5b6000825160005b818110156112e157602081860181015185830152016112c7565b50600092019182525091905056fea264697066735822122079d04eeec7c857b32065468d4b56344ced14fdee358cfecc2cfd327dbced278e64736f6c63430008180033","runtime-code":"0x608060405234801561001057600080fd5b50600436106101ae5760003560e01c80639010d07c116100ee578063bf333f2c11610097578063d547741f11610071578063d547741f146103f3578063dc9a4ef614610406578063dcf844a71461042d578063e00a83e01461044d57600080fd5b8063bf333f2c146103af578063ca15c873146103b9578063ccc57490146103cc57600080fd5b8063930ac180116100c8578063930ac1801461038a578063a217fddf14610394578063b13aa2d61461039c57600080fd5b80639010d07c1461032a57806391d148541461033d578063922b74871461038157600080fd5b80631ea327c51161015b57806336568abe1161013557806336568abe146102de57806358f85880146102f1578063638a0f09146102fa5780637ebe815c1461030357600080fd5b80631ea327c514610295578063248a9ca3146102a85780632f2ff15d146102cb57600080fd5b806306f333f21161018c57806306f333f2146102375780630f5f6ed71461024c5780630f862f1e1461025557600080fd5b806301ffc9a7146101b357806302d2ff66146101db57806303ed0ee514610210575b600080fd5b6101c66101c13660046110ef565b610474565b60405190151581526020015b60405180910390f35b6102027febfdca8e46c0b8dacf9989ee613e35727eadd20a1d5e5ad01a53968c7e5fe07a81565b6040519081526020016101d2565b6102027f043c983c49d46f0e102151eaf8085d4a2e6571d5df2d47b013f39bddfd4a639d81565b61024a61024536600461115a565b6104d0565b005b61020261271081565b61027073eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee81565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016101d2565b61024a6102a336600461118d565b610611565b6102026102b636600461118d565b60009081526020819052604090206001015490565b61024a6102d93660046111a6565b610648565b61024a6102ec3660046111a6565b61066d565b61020260025481565b61020260045481565b6102027f9a04aea0a349253cc7277afafdf6ead6729a3972a47ffb40eaef2c93d4e1bfea81565b6102706103383660046111c9565b6106c6565b6101c661034b3660046111a6565b60009182526020828152604080842073ffffffffffffffffffffffffffffffffffffffff93909316845291905290205460ff1690565b610202610e1081565b6102026201518081565b610202600081565b61024a6103aa36600461118d565b6106e5565b610202620f424081565b6102026103c736600461118d565b610791565b6102027f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f5581565b61024a6104013660046111a6565b6107a8565b6102027f60044782a422109ac08a415e44260ad5d3bad63d96ebe1fac0363399642ee3f281565b61020261043b3660046111eb565b60036020526000908152604090205481565b6102027f000000000000000000000000000000000000000000000000000000000000000081565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f5a05180f0000000000000000000000000000000000000000000000000000000014806104ca57506104ca826107cd565b92915050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f556104fa81610864565b73ffffffffffffffffffffffffffffffffffffffff83166000908152600360205260408120549081900361052e5750505050565b73ffffffffffffffffffffffffffffffffffffffff8481166000818152600360209081526040808320929092558151928352928616928201929092529081018290527f244e51bc38c1452fa8aaf487bcb4bca36c2baa3a5fbdb776b1eabd8dc6d277cd9060600160405180910390a17fffffffffffffffffffffffff111111111111111111111111111111111111111273ffffffffffffffffffffffffffffffffffffffff8516016105e9576105e48382610871565b61060a565b61060a73ffffffffffffffffffffffffffffffffffffffff8516848361094c565b505b505050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f5561063b81610864565b610644826109d9565b5050565b60008281526020819052604090206001015461066381610864565b61060a8383610a5a565b73ffffffffffffffffffffffffffffffffffffffff811633146106bc576040517f6697b23200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61060c8282610a8f565b60008281526001602052604081206106de9083610abc565b9392505050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f5561070f81610864565b61271082111561074b576040517f9b569b8100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600280549083905560408051828152602081018590527f14914da2bf76024616fbe1859783fcd4dbddcb179b1f3a854949fbf920dcb957910160405180910390a1505050565b60008181526001602052604081206104ca90610ac8565b6000828152602081905260409020600101546107c381610864565b61060a8383610a8f565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f7965db0b0000000000000000000000000000000000000000000000000000000014806104ca57507f01ffc9a7000000000000000000000000000000000000000000000000000000007fffffffff000000000000000000000000000000000000000000000000000000008316146104ca565b61086e8133610ad2565b50565b804710156108b2576040517fcd7860590000000000000000000000000000000000000000000000000000000081523060048201526024015b60405180910390fd5b60008273ffffffffffffffffffffffffffffffffffffffff168260405160006040518083038185875af1925050503d806000811461090c576040519150601f19603f3d011682016040523d82523d6000602084013e610911565b606091505b505090508061060c576040517f1425ea4200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040805173ffffffffffffffffffffffffffffffffffffffff8416602482015260448082018490528251808303909101815260649091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fa9059cbb0000000000000000000000000000000000000000000000000000000017905261060c908490610b58565b610e10811015610a15576040517f0e0ea5c700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600480549082905560408051828152602081018490527f909f9078b2f6eac1d10f2aae793656c5a67511eb627ebd1d2cb1eb9c0ab94c95910160405180910390a15050565b600080610a678484610bee565b905080156106de576000848152600160205260409020610a879084610cea565b509392505050565b600080610a9c8484610d0c565b905080156106de576000848152600160205260409020610a879084610dc7565b60006106de8383610de9565b60006104ca825490565b60008281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915290205460ff16610644576040517fe2517d3f00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff82166004820152602481018390526044016108a9565b6000610b7a73ffffffffffffffffffffffffffffffffffffffff841683610e13565b90508051600014158015610b9f575080806020019051810190610b9d9190611206565b155b1561060c576040517f5274afe700000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff841660048201526024016108a9565b60008281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915281205460ff16610ce25760008381526020818152604080832073ffffffffffffffffffffffffffffffffffffffff86168452909152902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055610c803390565b73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16847f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45060016104ca565b5060006104ca565b60006106de8373ffffffffffffffffffffffffffffffffffffffff8416610e21565b60008281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915281205460ff1615610ce25760008381526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8616808552925280832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016905551339286917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a45060016104ca565b60006106de8373ffffffffffffffffffffffffffffffffffffffff8416610e68565b6000826000018281548110610e0057610e00611228565b9060005260206000200154905092915050565b60606106de83836000610f5b565b6000818152600183016020526040812054610ce2575081546001818101845560008481526020808220909301849055845484825282860190935260409020919091556104ca565b60008181526001830160205260408120548015610f51576000610e8c600183611257565b8554909150600090610ea090600190611257565b9050808214610f05576000866000018281548110610ec057610ec0611228565b9060005260206000200154905080876000018481548110610ee357610ee3611228565b6000918252602080832090910192909255918252600188019052604090208390555b8554869080610f1657610f16611291565b6001900381819060005260206000200160009055905585600101600086815260200190815260200160002060009055600193505050506104ca565b60009150506104ca565b606081471015610f99576040517fcd7860590000000000000000000000000000000000000000000000000000000081523060048201526024016108a9565b6000808573ffffffffffffffffffffffffffffffffffffffff168486604051610fc291906112c0565b60006040518083038185875af1925050503d8060008114610fff576040519150601f19603f3d011682016040523d82523d6000602084013e611004565b606091505b509150915061101486838361101e565b9695505050505050565b6060826110335761102e826110ad565b6106de565b8151158015611057575073ffffffffffffffffffffffffffffffffffffffff84163b155b156110a6576040517f9996b31500000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff851660048201526024016108a9565b50806106de565b8051156110bd5780518082602001fd5b6040517f1425ea4200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006020828403121561110157600080fd5b81357fffffffff00000000000000000000000000000000000000000000000000000000811681146106de57600080fd5b803573ffffffffffffffffffffffffffffffffffffffff8116811461115557600080fd5b919050565b6000806040838503121561116d57600080fd5b61117683611131565b915061118460208401611131565b90509250929050565b60006020828403121561119f57600080fd5b5035919050565b600080604083850312156111b957600080fd5b8235915061118460208401611131565b600080604083850312156111dc57600080fd5b50508035926020909101359150565b6000602082840312156111fd57600080fd5b6106de82611131565b60006020828403121561121857600080fd5b815180151581146106de57600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b818103818111156104ca577f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fd5b6000825160005b818110156112e157602081860181015185830152016112c7565b50600092019182525091905056fea264697066735822122079d04eeec7c857b32065468d4b56344ced14fdee358cfecc2cfd327dbced278e64736f6c63430008180033","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.24 ^0.8.20 ^0.8.4;\n\n// contracts/interfaces/IAdminV2.sol\n\ninterface IAdminV2 {\n event CancelDelayUpdated(uint256 oldCancelDelay, uint256 newCancelDelay);\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n function setCancelDelay(uint256 newCancelDelay) external;\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n}\n\n// contracts/interfaces/IAdminV2Errors.sol\n\ninterface IAdminV2Errors {\n error CancelDelayBelowMin();\n error FeeRateAboveMax();\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IFastBridgeV2Errors.sol\n\ninterface IFastBridgeV2Errors {\n error AmountIncorrect();\n error ChainIncorrect();\n error ExclusivityParamsIncorrect();\n error MsgValueIncorrect();\n error SenderIncorrect();\n error StatusIncorrect();\n error TokenNotContract();\n error ZapDataLengthAboveMax();\n error ZapNativeNotSupported();\n error ZeroAddress();\n\n error RecipientIncorrectReturnValue();\n error RecipientNoReturnValue();\n\n error DeadlineExceeded();\n error DeadlineNotExceeded();\n error DeadlineTooShort();\n error DisputePeriodNotPassed();\n error DisputePeriodPassed();\n error ExclusivityPeriodNotPassed();\n\n error TransactionRelayed();\n}\n\n// contracts/interfaces/IMulticallTarget.sol\n\n/// @notice Interface for a contract that can be called multiple times by the same caller. Inspired by MulticallV3:\n/// https://github.com/mds1/multicall/blob/master/src/Multicall3.sol\ninterface IMulticallTarget {\n struct Result {\n bool success;\n bytes returnData;\n }\n\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external;\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results);\n}\n\n// contracts/interfaces/IZapRecipient.sol\n\ninterface IZapRecipient {\n function zap(address token, uint256 amount, bytes memory zapData) external payable returns (bytes4);\n}\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// contracts/interfaces/IFastBridgeV2.sol\n\ninterface IFastBridgeV2 is IFastBridge {\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n struct BridgeTxDetails {\n BridgeStatus status;\n uint32 destChainId;\n uint56 proofBlockTimestamp;\n address proofRelayer;\n }\n\n struct BridgeRelay {\n uint48 blockNumber;\n uint48 blockTimestamp;\n address relayer;\n }\n\n /// @notice New params introduced in the FastBridgeV2.\n /// We are passing fields from the older BridgeParams struct outside of this struct\n /// for backwards compatibility.\n /// Note: quoteRelayer and quoteExclusivitySeconds are either both zero (indicating no exclusivity)\n /// or both non-zero (indicating exclusivity for the given period).\n /// Note: zapNative \u003e 0 can NOT be used with destToken = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE (native token)\n /// @param quoteRelayer Relayer that provided the quote for the transaction\n /// @param quoteExclusivitySeconds Period of time the quote relayer is guaranteed exclusivity after user's deposit\n /// @param quoteId Unique quote identifier used for tracking the quote\n /// @param zapNative ETH value to send to the recipient (if any)\n /// @param zapData Parameters for the Zap to the destination recipient (if any)\n struct BridgeParamsV2 {\n address quoteRelayer;\n int256 quoteExclusivitySeconds;\n bytes quoteId;\n uint256 zapNative;\n bytes zapData;\n }\n\n /// @notice Updated bridge transaction struct to include parameters introduced in FastBridgeV2.\n /// Note: only `exclusivityRelayer` can fill such a transaction until `exclusivityEndTime`.\n struct BridgeTransactionV2 {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n // Note: sendChainGas flag from V1 is deprecated\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n address exclusivityRelayer;\n uint256 exclusivityEndTime;\n uint256 zapNative; // ETH value to send to the recipient (if any)\n bytes zapData; // data to pass for the Zap action (if any)\n }\n\n event BridgeQuoteDetails(bytes32 indexed transactionId, bytes quoteId);\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability\n /// to provide temporary exclusivity fill rights for the quote relayer.\n /// @param params The parameters required to bridge\n /// @param paramsV2 The parameters for exclusivity fill rights (optional, can be left empty)\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function relay(bytes memory request, address relayer) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param transactionId The transaction id associated with the encoded bridge transaction to prove\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital.\n /// @notice Can only send funds to the relayer address on the proof.\n /// @param request The encoded bridge transaction to claim on origin chain\n function claim(bytes memory request) external;\n\n /// @notice Cancels an outstanding bridge transaction in case optimistic bridging failed and returns the full amount\n /// to the original sender.\n /// @param request The encoded bridge transaction to refund\n function cancel(bytes memory request) external;\n\n /// @notice Checks if a transaction has been relayed\n /// @param transactionId The ID of the transaction to check\n /// @return True if the transaction has been relayed, false otherwise\n function bridgeRelays(bytes32 transactionId) external view returns (bool);\n\n /// @notice Returns the status of a bridge transaction\n /// @param transactionId The ID of the bridge transaction\n /// @return BridgeStatus Status of the bridge transaction\n function bridgeStatuses(bytes32 transactionId) external view returns (BridgeStatus);\n\n /// @notice Returns the timestamp and relayer of a bridge proof\n /// @param transactionId The ID of the bridge transaction\n /// @return timestamp The timestamp of the bridge proof\n /// @return relayer The relayer address of the bridge proof\n function bridgeProofs(bytes32 transactionId) external view returns (uint96 timestamp, address relayer);\n\n /// @notice Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\n /// @param request The bridge request to decode\n function getBridgeTransactionV2(bytes memory request) external view returns (BridgeTransactionV2 memory);\n}\n\n// contracts/utils/MulticallTarget.sol\n\n// solhint-disable avoid-low-level-calls\n/// @notice Template for a contract that supports batched calls (preserving the msg.sender).\n/// Only calls with zero msg.value could be batched.\nabstract contract MulticallTarget is IMulticallTarget {\n error MulticallTarget__UndeterminedRevert();\n\n /// @notice Perform a batched call to this contract, preserving the msg.sender.\n /// The return data from each call is discarded.\n /// @dev The method is non-payable, so only calls with `msg.value == 0` could be batched.\n /// It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag.\n /// Otherwise, the whole batch call will be reverted with the original revert reason.\n /// @param data List of abi-encoded calldata for the calls to perform.\n /// @param ignoreReverts Whether to ignore the revert errors from the calls.\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external {\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\n if (!success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(result);\n }\n }\n }\n\n /// @notice Perform a batched call to this contract, preserving the msg.sender.\n /// The return data from each call is preserved.\n /// @dev The method is non-payable, so only calls with `msg.value == 0` could be batched.\n /// It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag.\n /// Otherwise, the whole batch call will be reverted with the original revert reason.\n /// @param data List of abi-encoded calldata for the calls to perform.\n /// @param ignoreReverts Whether to ignore the revert errors from the calls.\n /// @return results List of results from the calls: `(success, returnData)`.\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results)\n {\n results = new Result[](data.length);\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (results[i].success, results[i].returnData) = address(this).delegatecall(data[i]);\n if (!results[i].success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(results[i].returnData);\n }\n }\n }\n\n /// @dev Bubbles the revert message from the underlying call.\n /// Note: preserves the same custom error or revert string, if one was used.\n /// Source: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v5.0.2/contracts/utils/Address.sol#L143-L158\n function _bubbleRevert(bytes memory returnData) internal pure {\n // Look for revert reason and bubble it up if present\n if (returnData.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n // solhint-disable-next-line no-inline-assembly\n assembly {\n let returndata_size := mload(returnData)\n revert(add(32, returnData), returndata_size)\n }\n } else {\n revert MulticallTarget__UndeterminedRevert();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// contracts/libs/BridgeTransactionV2.sol\n\n// solhint-disable no-inline-assembly\nlibrary BridgeTransactionV2Lib {\n uint16 internal constant VERSION = 2;\n\n // Offsets of the fields in the packed BridgeTransactionV2 struct\n // uint16 version [000 .. 002)\n // uint32 originChainId [002 .. 006)\n // uint32 destChainId [006 .. 010)\n // address originSender [010 .. 030)\n // address destRecipient [030 .. 050)\n // address originToken [050 .. 070)\n // address destToken [070 .. 090)\n // uint256 originAmount [090 .. 122)\n // uint256 destAmount [122 .. 154)\n // uint256 originFeeAmount [154 .. 186)\n // uint256 deadline [186 .. 218)\n // uint256 nonce [218 .. 250)\n // address exclusivityRelayer [250 .. 270)\n // uint256 exclusivityEndTime [270 .. 302)\n // uint256 zapNative [302 .. 334)\n // bytes zapData [334 .. ***)\n\n // forgefmt: disable-start\n uint256 private constant OFFSET_ORIGIN_CHAIN_ID = 2;\n uint256 private constant OFFSET_DEST_CHAIN_ID = 6;\n uint256 private constant OFFSET_ORIGIN_SENDER = 10;\n uint256 private constant OFFSET_DEST_RECIPIENT = 30;\n uint256 private constant OFFSET_ORIGIN_TOKEN = 50;\n uint256 private constant OFFSET_DEST_TOKEN = 70;\n uint256 private constant OFFSET_ORIGIN_AMOUNT = 90;\n uint256 private constant OFFSET_DEST_AMOUNT = 122;\n uint256 private constant OFFSET_ORIGIN_FEE_AMOUNT = 154;\n uint256 private constant OFFSET_DEADLINE = 186;\n uint256 private constant OFFSET_NONCE = 218;\n uint256 private constant OFFSET_EXCLUSIVITY_RELAYER = 250;\n uint256 private constant OFFSET_EXCLUSIVITY_END_TIME = 270;\n uint256 private constant OFFSET_ZAP_NATIVE = 302;\n uint256 private constant OFFSET_ZAP_DATA = 334;\n // forgefmt: disable-end\n\n error BridgeTransactionV2__InvalidEncodedTx();\n error BridgeTransactionV2__UnsupportedVersion(uint16 version);\n\n /// @notice Validates the encoded transaction to be a tightly packed encoded payload for BridgeTransactionV2.\n /// @dev Checks the minimum length and the version, use this function before decoding any of the fields.\n function validateV2(bytes calldata encodedTx) internal pure {\n // Check the minimum length: must at least include all static fields.\n if (encodedTx.length \u003c OFFSET_ZAP_DATA) revert BridgeTransactionV2__InvalidEncodedTx();\n // Once we validated the length, we can be sure that the version field is present.\n uint16 version_ = version(encodedTx);\n if (version_ != VERSION) revert BridgeTransactionV2__UnsupportedVersion(version_);\n }\n\n /// @notice Encodes the BridgeTransactionV2 struct by tightly packing the fields.\n /// @dev `abi.decode` will not work as a result of the tightly packed fields. Use `decodeV2` to decode instead.\n function encodeV2(IFastBridgeV2.BridgeTransactionV2 memory bridgeTx) internal pure returns (bytes memory) {\n // We split the encoding into two parts to avoid stack-too-deep error\n bytes memory firstPart = abi.encodePacked(\n VERSION,\n bridgeTx.originChainId,\n bridgeTx.destChainId,\n bridgeTx.originSender,\n bridgeTx.destRecipient,\n bridgeTx.originToken,\n bridgeTx.destToken,\n bridgeTx.originAmount\n );\n return abi.encodePacked(\n firstPart,\n bridgeTx.destAmount,\n bridgeTx.originFeeAmount,\n // Note: we skip the deprecated `sendChainGas` flag, which was present in BridgeTransaction V1\n bridgeTx.deadline,\n bridgeTx.nonce,\n // New V2 fields: exclusivity\n bridgeTx.exclusivityRelayer,\n bridgeTx.exclusivityEndTime,\n // New V2 fields: Zap\n bridgeTx.zapNative,\n bridgeTx.zapData\n );\n }\n\n /// @notice Decodes the BridgeTransactionV2 struct from the encoded transaction.\n /// @dev Encoded BridgeTransactionV2 struct must be tightly packed.\n /// Use `validateV2` before decoding to ensure the encoded transaction is valid.\n function decodeV2(bytes calldata encodedTx)\n internal\n pure\n returns (IFastBridgeV2.BridgeTransactionV2 memory bridgeTx)\n {\n bridgeTx.originChainId = originChainId(encodedTx);\n bridgeTx.destChainId = destChainId(encodedTx);\n bridgeTx.originSender = originSender(encodedTx);\n bridgeTx.destRecipient = destRecipient(encodedTx);\n bridgeTx.originToken = originToken(encodedTx);\n bridgeTx.destToken = destToken(encodedTx);\n bridgeTx.originAmount = originAmount(encodedTx);\n bridgeTx.destAmount = destAmount(encodedTx);\n bridgeTx.originFeeAmount = originFeeAmount(encodedTx);\n bridgeTx.deadline = deadline(encodedTx);\n bridgeTx.nonce = nonce(encodedTx);\n bridgeTx.exclusivityRelayer = exclusivityRelayer(encodedTx);\n bridgeTx.exclusivityEndTime = exclusivityEndTime(encodedTx);\n bridgeTx.zapNative = zapNative(encodedTx);\n bridgeTx.zapData = zapData(encodedTx);\n }\n\n /// @notice Extracts the version from the encoded transaction.\n function version(bytes calldata encodedTx) internal pure returns (uint16 version_) {\n // Load 32 bytes from the start and shift it 240 bits to the right to get the highest 16 bits.\n assembly {\n version_ := shr(240, calldataload(encodedTx.offset))\n }\n }\n\n /// @notice Extracts the origin chain ID from the encoded transaction.\n function originChainId(bytes calldata encodedTx) internal pure returns (uint32 originChainId_) {\n // Load 32 bytes from the offset and shift it 224 bits to the right to get the highest 32 bits.\n assembly {\n originChainId_ := shr(224, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_CHAIN_ID)))\n }\n }\n\n /// @notice Extracts the destination chain ID from the encoded transaction.\n function destChainId(bytes calldata encodedTx) internal pure returns (uint32 destChainId_) {\n // Load 32 bytes from the offset and shift it 224 bits to the right to get the highest 32 bits.\n assembly {\n destChainId_ := shr(224, calldataload(add(encodedTx.offset, OFFSET_DEST_CHAIN_ID)))\n }\n }\n\n /// @notice Extracts the origin sender from the encoded transaction.\n function originSender(bytes calldata encodedTx) internal pure returns (address originSender_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n originSender_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_SENDER)))\n }\n }\n\n /// @notice Extracts the destination recipient from the encoded transaction.\n function destRecipient(bytes calldata encodedTx) internal pure returns (address destRecipient_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n destRecipient_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_DEST_RECIPIENT)))\n }\n }\n\n /// @notice Extracts the origin token from the encoded transaction.\n function originToken(bytes calldata encodedTx) internal pure returns (address originToken_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n originToken_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_TOKEN)))\n }\n }\n\n /// @notice Extracts the destination token from the encoded transaction.\n function destToken(bytes calldata encodedTx) internal pure returns (address destToken_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n destToken_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_DEST_TOKEN)))\n }\n }\n\n /// @notice Extracts the origin amount from the encoded transaction.\n function originAmount(bytes calldata encodedTx) internal pure returns (uint256 originAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n originAmount_ := calldataload(add(encodedTx.offset, OFFSET_ORIGIN_AMOUNT))\n }\n }\n\n /// @notice Extracts the destination amount from the encoded transaction.\n function destAmount(bytes calldata encodedTx) internal pure returns (uint256 destAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n destAmount_ := calldataload(add(encodedTx.offset, OFFSET_DEST_AMOUNT))\n }\n }\n\n /// @notice Extracts the origin fee amount from the encoded transaction.\n function originFeeAmount(bytes calldata encodedTx) internal pure returns (uint256 originFeeAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n originFeeAmount_ := calldataload(add(encodedTx.offset, OFFSET_ORIGIN_FEE_AMOUNT))\n }\n }\n\n /// @notice Extracts the deadline from the encoded transaction.\n function deadline(bytes calldata encodedTx) internal pure returns (uint256 deadline_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n deadline_ := calldataload(add(encodedTx.offset, OFFSET_DEADLINE))\n }\n }\n\n /// @notice Extracts the nonce from the encoded transaction.\n function nonce(bytes calldata encodedTx) internal pure returns (uint256 nonce_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n nonce_ := calldataload(add(encodedTx.offset, OFFSET_NONCE))\n }\n }\n\n /// @notice Extracts the exclusivity relayer from the encoded transaction.\n function exclusivityRelayer(bytes calldata encodedTx) internal pure returns (address exclusivityRelayer_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n exclusivityRelayer_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_EXCLUSIVITY_RELAYER)))\n }\n }\n\n /// @notice Extracts the exclusivity end time from the encoded transaction.\n function exclusivityEndTime(bytes calldata encodedTx) internal pure returns (uint256 exclusivityEndTime_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n exclusivityEndTime_ := calldataload(add(encodedTx.offset, OFFSET_EXCLUSIVITY_END_TIME))\n }\n }\n\n /// @notice Extracts the Zap's native value from the encoded transaction.\n function zapNative(bytes calldata encodedTx) internal pure returns (uint256 zapNative_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n zapNative_ := calldataload(add(encodedTx.offset, OFFSET_ZAP_NATIVE))\n }\n }\n\n /// @notice Extracts the Zap's data from the encoded transaction.\n function zapData(bytes calldata encodedTx) internal pure returns (bytes calldata zapData_) {\n zapData_ = encodedTx[OFFSET_ZAP_DATA:];\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/AdminV2.sol\n\ncontract AdminV2 is AccessControlEnumerable, IAdminV2, IAdminV2Errors {\n using SafeERC20 for IERC20;\n\n /// @notice Address reserved for native gas token (ETH on Ethereum and most L2s, AVAX on Avalanche, etc)\n address public constant NATIVE_GAS_TOKEN = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Role identifier for Quoter API's off-chain authentication.\n /// @dev Only addresses with this role can post FastBridge quotes to the API.\n bytes32 public constant QUOTER_ROLE = keccak256(\"QUOTER_ROLE\");\n\n /// @notice Role identifier for Prover's on-chain authentication in FastBridge.\n /// @dev Only addresses with this role can provide proofs that a FastBridge request has been relayed.\n bytes32 public constant PROVER_ROLE = keccak256(\"PROVER_ROLE\");\n\n /// @notice Role identifier for Guard's on-chain authentication in FastBridge.\n /// @dev Only addresses with this role can dispute submitted relay proofs during the dispute period.\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n\n /// @notice Role identifier for Canceler's on-chain authentication in FastBridge.\n /// @dev Only addresses with this role can cancel a FastBridge transaction without the cancel delay.\n bytes32 public constant CANCELER_ROLE = keccak256(\"CANCELER_ROLE\");\n\n /// @notice Role identifier for Governor's on-chain administrative authority.\n /// @dev Only addresses with this role can perform administrative tasks within the contract.\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n /// @notice Denominator for fee rates, represents 100%.\n uint256 public constant FEE_BPS = 1e6;\n /// @notice Maximum protocol fee rate: 1% on origin amount.\n uint256 public constant FEE_RATE_MAX = 0.01e6;\n\n /// @notice Minimum cancel delay that can be set by the governor.\n uint256 public constant MIN_CANCEL_DELAY = 1 hours;\n /// @notice Default cancel delay set during the contract deployment.\n uint256 public constant DEFAULT_CANCEL_DELAY = 1 days;\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Delay for a transaction after which it could be permisionlessly cancelled\n uint256 public cancelDelay;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Use ZapNative V2 requests instead.\n uint256 public immutable chainGasAmount = 0;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n _setCancelDelay(DEFAULT_CANCEL_DELAY);\n }\n\n /// @notice Allows the contract governor to set the cancel delay. The cancel delay is the time after the transaction\n /// deadline after which it can be permissionlessly cancelled, if it hasn't been proven by any of the Relayers.\n function setCancelDelay(uint256 newCancelDelay) external onlyRole(GOVERNOR_ROLE) {\n _setCancelDelay(newCancelDelay);\n }\n\n /// @notice Allows the contract governor to set the protocol fee rate. The protocol fee is taken from the origin\n /// amount only for completed and claimed transactions.\n /// @dev The protocol fee is abstracted away from the relayers, they always operate using the amounts after fees:\n /// what they see as the origin amount emitted in the log is what they get credited with.\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n if (newFeeRate \u003e FEE_RATE_MAX) revert FeeRateAboveMax();\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n /// @notice Allows the contract governor to sweep the accumulated protocol fees in the contract.\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n emit FeesSwept(token, recipient, feeAmount);\n /// Sweep the fees as the last transaction action\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(recipient), feeAmount);\n } else {\n IERC20(token).safeTransfer(recipient, feeAmount);\n }\n }\n\n /// @notice Internal function to set the cancel delay. Security checks are performed outside of this function.\n function _setCancelDelay(uint256 newCancelDelay) private {\n if (newCancelDelay \u003c MIN_CANCEL_DELAY) revert CancelDelayBelowMin();\n uint256 oldCancelDelay = cancelDelay;\n cancelDelay = newCancelDelay;\n emit CancelDelayUpdated(oldCancelDelay, newCancelDelay);\n }\n}\n\n// contracts/FastBridgeV2.sol\n\n/// @notice FastBridgeV2 is a contract for bridging tokens across chains.\ncontract FastBridgeV2 is AdminV2, MulticallTarget, IFastBridgeV2, IFastBridgeV2Errors {\n using BridgeTransactionV2Lib for bytes;\n using SafeERC20 for IERC20;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n /// @notice Maximum length of accepted zapData\n uint256 public constant MAX_ZAP_DATA_LENGTH = 2 ** 16 - 1;\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeTxDetails) public bridgeTxDetails;\n /// @notice Relay details on destination chain\n mapping(bytes32 =\u003e BridgeRelay) public bridgeRelayDetails;\n /// @notice Unique bridge nonces tracked per originSender\n mapping(address =\u003e uint256) public senderNonces;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Replaced by senderNonces\n uint256 public immutable nonce = 0;\n /// @notice the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) AdminV2(_owner) {\n deployBlock = block.number;\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n bridge({\n params: params,\n paramsV2: BridgeParamsV2({\n quoteRelayer: address(0),\n quoteExclusivitySeconds: 0,\n quoteId: bytes(\"\"),\n zapNative: 0,\n zapData: bytes(\"\")\n })\n });\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes calldata request) external payable {\n // relay override will validate the request\n relay({request: request, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes calldata request, bytes32 destTxHash) external {\n request.validateV2();\n prove({transactionId: keccak256(request), destTxHash: destTxHash, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridgeV2\n function claim(bytes calldata request) external {\n // claim override will validate the request\n claim({request: request, to: address(0)});\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Aggregate the read operations from the same storage slot\n address disputedRelayer = $.proofRelayer;\n BridgeStatus status = $.status;\n uint56 proofBlockTimestamp = $.proofBlockTimestamp;\n // Can only dispute a RELAYER_PROVED transaction within the dispute period\n if (status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(proofBlockTimestamp) \u003e DISPUTE_PERIOD) {\n revert DisputePeriodPassed();\n }\n // Update status to REQUESTED and delete the disputed proof details\n // Note: these are storage writes\n $.status = BridgeStatus.REQUESTED;\n $.proofRelayer = address(0);\n $.proofBlockTimestamp = 0;\n\n emit BridgeProofDisputed(transactionId, disputedRelayer);\n }\n\n /// Note: this function is deprecated and will be removed in a future version.\n /// @inheritdoc IFastBridge\n function refund(bytes calldata request) external {\n cancel(request);\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // The correct relayer can only claim a RELAYER_PROVED transaction after the dispute period\n if ($.status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if ($.proofRelayer != relayer) revert SenderIncorrect();\n return _timeSince($.proofBlockTimestamp) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n /// @dev This method is added to achieve backwards compatibility with decoding requests into V1 structs:\n /// - `zapNative` is partially reported as a zero/non-zero flag\n /// - `zapData` is ignored\n /// In order to process all kinds of requests use getBridgeTransactionV2 instead.\n function getBridgeTransaction(bytes calldata request) external view returns (BridgeTransaction memory) {\n // Try decoding into V2 struct first. This will revert if V1 struct is passed\n try this.getBridgeTransactionV2(request) returns (BridgeTransactionV2 memory txV2) {\n // Note: we entirely ignore the zapData field, as it was not present in V1\n return BridgeTransaction({\n originChainId: txV2.originChainId,\n destChainId: txV2.destChainId,\n originSender: txV2.originSender,\n destRecipient: txV2.destRecipient,\n originToken: txV2.originToken,\n destToken: txV2.destToken,\n originAmount: txV2.originAmount,\n destAmount: txV2.destAmount,\n originFeeAmount: txV2.originFeeAmount,\n sendChainGas: txV2.zapNative != 0,\n deadline: txV2.deadline,\n nonce: txV2.nonce\n });\n } catch {\n // Fallback to V1 struct\n return abi.decode(request, (BridgeTransaction));\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function getBridgeTransactionV2(bytes calldata request) external pure returns (BridgeTransactionV2 memory) {\n request.validateV2();\n return BridgeTransactionV2Lib.decodeV2(request);\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) public payable {\n int256 exclusivityEndTime = 0;\n // if relayer exclusivity is not intended for this bridge, set exclusivityEndTime to static zero\n // otherwise, set exclusivity to expire at the current block ts offset by quoteExclusivitySeconds\n if (paramsV2.quoteRelayer != address(0)) {\n exclusivityEndTime = int256(block.timestamp) + paramsV2.quoteExclusivitySeconds;\n }\n _validateBridgeParams(params, paramsV2, exclusivityEndTime);\n\n // transfer tokens to bridge contract\n /// @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _takeBridgedUserAsset(params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) {\n originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n }\n\n // set status to requested\n bytes memory request = BridgeTransactionV2Lib.encodeV2(\n BridgeTransactionV2({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n deadline: params.deadline,\n nonce: senderNonces[params.sender]++, // increment nonce on every bridge\n exclusivityRelayer: paramsV2.quoteRelayer,\n // We checked exclusivityEndTime to be in range [0 .. params.deadline] above, so can safely cast\n exclusivityEndTime: uint256(exclusivityEndTime),\n zapNative: paramsV2.zapNative,\n zapData: paramsV2.zapData\n })\n );\n bytes32 transactionId = keccak256(request);\n // Note: the tx status will be updated throughout the tx lifecycle, while destChainId is set once here\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n bridgeTxDetails[transactionId].destChainId = params.dstChainId;\n\n emit BridgeRequested({\n transactionId: transactionId,\n sender: params.sender,\n request: request,\n destChainId: params.dstChainId,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n sendChainGas: paramsV2.zapNative != 0\n });\n emit BridgeQuoteDetails(transactionId, paramsV2.quoteId);\n }\n\n /// @inheritdoc IFastBridgeV2\n function relay(bytes calldata request, address relayer) public payable {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n _validateRelayParams(request, transactionId, relayer);\n // mark bridge transaction as relayed\n bridgeRelayDetails[transactionId] =\n BridgeRelay({blockNumber: uint48(block.number), blockTimestamp: uint48(block.timestamp), relayer: relayer});\n\n // transfer tokens to recipient on destination chain and trigger Zap if requested\n address to = request.destRecipient();\n address token = request.destToken();\n uint256 amount = request.destAmount();\n uint256 zapNative = request.zapNative();\n\n // Emit the event before any external calls\n emit BridgeRelayed({\n transactionId: transactionId,\n relayer: relayer,\n to: to,\n originChainId: request.originChainId(),\n originToken: request.originToken(),\n destToken: token,\n originAmount: request.originAmount(),\n destAmount: amount,\n chainGasAmount: zapNative\n });\n\n // All state changes have been done at this point, can proceed to the external calls.\n // This follows the checks-effects-interactions pattern to mitigate potential reentrancy attacks.\n if (token == NATIVE_GAS_TOKEN) {\n // For the native gas token, additional zapNative is not allowed\n if (zapNative != 0) revert ZapNativeNotSupported();\n // Check that the correct msg.value was sent\n if (msg.value != amount) revert MsgValueIncorrect();\n // Don't do a native transfer yet: we will handle it alongside the Zap below\n } else {\n // For ERC20s, we check that the correct msg.value was sent\n if (msg.value != zapNative) revert MsgValueIncorrect();\n // We need to transfer the tokens from the Relayer to the recipient first before performing an\n // optional post-transfer Zap.\n IERC20(token).safeTransferFrom(msg.sender, to, amount);\n }\n // At this point we have done:\n // - Transferred the requested amount of ERC20 tokens to the recipient.\n // At this point we have confirmed:\n // - For ERC20s: msg.value matches the requested zapNative amount.\n // - For the native gas token: msg.value matches the requested destAmount.\n // Remaining optional things to do:\n // - Forward the full msg.value to the recipient (if non-zero).\n // - Trigger a Zap (if zapData is present).\n bytes calldata zapData = request.zapData();\n if (zapData.length != 0) {\n // Zap Data is present: Zap has been requested by the recipient. Trigger it forwarding the full msg.value.\n\n // Note: if token has a fee on transfers, the recipient will have received less than `amount`.\n // This is a very niche edge case and should be handled by the recipient contract.\n _triggerZapWithChecks({recipient: to, token: token, amount: amount, zapData: zapData});\n } else if (msg.value != 0) {\n // Zap Data is missing, but msg.value was sent. This could happen in two different cases:\n // - Relay with the native gas token is happening.\n // - Relay with ERC20 is happening, with a `zapNative \u003e 0` request.\n // In both cases, we need to transfer the full msg.value to the recipient.\n Address.sendValue(payable(to), msg.value);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) public onlyRole(PROVER_ROLE) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n\n // Can only prove a REQUESTED transaction\n if ($.status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n // Update status to RELAYER_PROVED and store the proof details\n // Note: these are storage writes\n $.status = BridgeStatus.RELAYER_PROVED;\n $.proofBlockTimestamp = uint56(block.timestamp);\n $.proofRelayer = relayer;\n\n emit BridgeProofProvided(transactionId, relayer, destTxHash);\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes calldata request, address to) public {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Aggregate the read operations from the same storage slot\n address proofRelayer = $.proofRelayer;\n BridgeStatus status = $.status;\n uint56 proofBlockTimestamp = $.proofBlockTimestamp;\n\n // Can only claim a RELAYER_PROVED transaction after the dispute period\n if (status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(proofBlockTimestamp) \u003c= DISPUTE_PERIOD) {\n revert DisputePeriodNotPassed();\n }\n\n if (to == address(0)) {\n // Anyone could claim the funds to the proven relayer on their behalf\n to = proofRelayer;\n } else if (proofRelayer != msg.sender) {\n // Only the proven relayer could specify an address to claim the funds to\n revert SenderIncorrect();\n }\n\n // Update status to RELAYER_CLAIMED and transfer the origin collateral to the specified claim address\n // Note: this is a storage write\n $.status = BridgeStatus.RELAYER_CLAIMED;\n\n address token = request.originToken();\n uint256 amount = request.originAmount();\n // Update protocol fees if origin fee amount exists\n uint256 originFeeAmount = request.originFeeAmount();\n if (originFeeAmount \u003e 0) protocolFees[token] += originFeeAmount;\n // Emit the event before any external calls\n emit BridgeDepositClaimed(transactionId, proofRelayer, to, token, amount);\n // Complete the relayer claim as the last transaction action\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(to), amount);\n } else {\n IERC20(token).safeTransfer(to, amount);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function cancel(bytes calldata request) public {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Can only cancel a REQUESTED transaction after its deadline expires\n if ($.status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n uint256 deadline = request.deadline();\n // Permissionless cancel is only allowed after `cancelDelay` on top of the deadline\n if (!hasRole(CANCELER_ROLE, msg.sender)) deadline += cancelDelay;\n if (block.timestamp \u003c= deadline) revert DeadlineNotExceeded();\n // Update status to REFUNDED and return the full amount (collateral + protocol fees) to the original sender.\n // The protocol fees are only updated when the transaction is claimed, so we don't need to update them here.\n // Note: this is a storage write\n $.status = BridgeStatus.REFUNDED;\n\n address to = request.originSender();\n address token = request.originToken();\n uint256 amount = request.originAmount() + request.originFeeAmount();\n // Emit the event before any external calls\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n // Complete the user cancel as the last transaction action\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(to), amount);\n } else {\n IERC20(token).safeTransfer(to, amount);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeStatuses(bytes32 transactionId) public view returns (BridgeStatus status) {\n return bridgeTxDetails[transactionId].status;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeProofs(bytes32 transactionId) public view returns (uint96 timestamp, address relayer) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n\n timestamp = $.proofBlockTimestamp;\n relayer = $.proofRelayer;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeRelays(bytes32 transactionId) public view returns (bool) {\n // has this transactionId been relayed?\n return bridgeRelayDetails[transactionId].relayer != address(0);\n }\n\n /// @notice Takes the bridged asset from the user into FastBridgeV2 custody. It will be later\n /// claimed by the relayer who completed the relay on destination chain, or transferred back to the user\n /// via the cancel function should no one complete the relay.\n function _takeBridgedUserAsset(address token, uint256 amount) internal returns (uint256 amountTaken) {\n if (token == NATIVE_GAS_TOKEN) {\n // For the native gas token, we just need to check that the supplied msg.value is correct.\n // Supplied `msg.value` is already in FastBridgeV2 custody.\n if (amount != msg.value) revert MsgValueIncorrect();\n amountTaken = msg.value;\n } else {\n // For ERC20s, token is explicitly transferred from the user to FastBridgeV2.\n // We don't allow non-zero `msg.value` to avoid extra funds from being stuck in FastBridgeV2.\n if (msg.value != 0) revert MsgValueIncorrect();\n // Throw an explicit error if the provided token address is not a contract\n if (token.code.length == 0) revert TokenNotContract();\n amountTaken = IERC20(token).balanceOf(address(this));\n IERC20(token).safeTransferFrom(msg.sender, address(this), amount);\n // Use the balance difference as the amount taken in case of fee on transfer tokens.\n amountTaken = IERC20(token).balanceOf(address(this)) - amountTaken;\n }\n }\n\n /// @notice Calls the Recipient's hook function with the specified zapData and performs\n /// all the necessary checks for the returned value.\n function _triggerZapWithChecks(address recipient, address token, uint256 amount, bytes calldata zapData) internal {\n // This will bubble any revert messages from the hook function\n bytes memory returnData = Address.functionCallWithValue({\n target: recipient,\n data: abi.encodeCall(IZapRecipient.zap, (token, amount, zapData)),\n // Note: see `relay()` for reasoning behind passing msg.value\n value: msg.value\n });\n // Explicit revert if no return data at all\n if (returnData.length == 0) revert RecipientNoReturnValue();\n // Check that exactly a single return value was returned\n if (returnData.length != 32) revert RecipientIncorrectReturnValue();\n // Return value should be abi-encoded hook function selector\n if (bytes32(returnData) != bytes32(IZapRecipient.zap.selector)) {\n revert RecipientIncorrectReturnValue();\n }\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint56(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint56).max but\n /// proof.timestamp \u003c type(uint56).max via unchecked statement\n /// @param proofBlockTimestamp The bridge proof block timestamp\n /// @return delta Time delta since proof submitted\n function _timeSince(uint56 proofBlockTimestamp) internal view returns (uint256 delta) {\n unchecked {\n delta = uint56(block.timestamp) - proofBlockTimestamp;\n }\n }\n\n /// @notice Performs all the necessary checks for a bridge to happen.\n /// @dev There's no good way to refactor this function to reduce cyclomatic complexity due to\n /// the number of checks that need to be performed, so we skip the code-complexity rule here.\n // solhint-disable-next-line code-complexity\n function _validateBridgeParams(\n BridgeParams memory params,\n BridgeParamsV2 memory paramsV2,\n int256 exclusivityEndTime\n )\n internal\n view\n {\n // Check V1 (legacy) params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.sender == address(0) || params.to == address(0)) revert ZeroAddress();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n // Check V2 params\n if (paramsV2.zapData.length \u003e MAX_ZAP_DATA_LENGTH) revert ZapDataLengthAboveMax();\n if (paramsV2.zapNative != 0 \u0026\u0026 params.destToken == NATIVE_GAS_TOKEN) {\n revert ZapNativeNotSupported();\n }\n // exclusivityEndTime must be in range [0 .. params.deadline]\n if (exclusivityEndTime \u003c 0 || exclusivityEndTime \u003e int256(params.deadline)) {\n revert ExclusivityParamsIncorrect();\n }\n }\n\n /// @notice Performs all the necessary checks for a relay to happen.\n function _validateRelayParams(bytes calldata request, bytes32 transactionId, address relayer) internal view {\n if (relayer == address(0)) revert ZeroAddress();\n // Check if the transaction has already been relayed\n if (bridgeRelays(transactionId)) revert TransactionRelayed();\n if (request.destChainId() != block.chainid) revert ChainIncorrect();\n // Check the deadline for relay to happen\n if (block.timestamp \u003e request.deadline()) revert DeadlineExceeded();\n // Check the exclusivity period, if it is still ongoing\n address exclRelayer = request.exclusivityRelayer();\n if (exclRelayer != address(0) \u0026\u0026 exclRelayer != relayer \u0026\u0026 block.timestamp \u003c= request.exclusivityEndTime()) {\n revert ExclusivityPeriodNotPassed();\n }\n }\n}\n","language":"Solidity","languageVersion":"0.8.24","compilerVersion":"0.8.24","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"76061:4808:0:-:0;;;78600:1;78558:43;;78608:130;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;78646:38;68687:4;78677:6;78646:10;:38::i;:::-;-1:-1:-1;78694:37:0;78092:6;78694:15;:37::i;:::-;78608:130;76061:4808;;75409:257;75495:4;;75526:31;75543:4;75549:7;75526:16;:31::i;:::-;75511:46;;75571:7;75567:69;;;75594:18;;;;:12;:18;;;;;:31;;75617:7;75594:22;:31::i;:::-;;75567:69;75652:7;-1:-1:-1;75409:257:0;;;;;:::o;80577:290::-;77959:7;80648:14;:33;80644:67;;;80690:21;;-1:-1:-1;;;80690:21:0;;;;;;;;;;;80644:67;80746:11;;;80767:28;;;;80810:50;;;483:25:1;;;539:2;524:18;;517:34;;;80810:50:0;;456:18:1;80810:50:0;;;;;;;80634:233;80577:290;:::o;72634:316::-;72711:4;69409:12;;;;;;;;;;;-1:-1:-1;;;;;69409:29:0;;;;;;;;;;;;72727:217;;72770:6;:12;;;;;;;;;;;-1:-1:-1;;;;;72770:29:0;;;;;;;;;:36;;-1:-1:-1;;72770:36:0;72802:4;72770:36;;;72852:12;23372:10;;23293:96;72852:12;-1:-1:-1;;;;;72825:40:0;72843:7;-1:-1:-1;;;;;72825:40:0;72837:4;72825:40;;;;;;;;;;-1:-1:-1;72886:4:0;72879:11;;72727:217;-1:-1:-1;72928:5:0;72921:12;;32817:150;32887:4;32910:50;32915:3;-1:-1:-1;;;;;32935:23:0;;26805:4;28861:21;;;:14;;;:21;;;;;;26821:321;;-1:-1:-1;26863:23:0;;;;;;;;:11;:23;;;;;;;;;;;;;27045:18;;27021:21;;;:14;;;:21;;;;;;:42;;;;27077:11;;14:290:1;84:6;137:2;125:9;116:7;112:23;108:32;105:52;;;153:1;150;143:12;105:52;179:16;;-1:-1:-1;;;;;224:31:1;;214:42;;204:70;;270:1;267;260:12;309:248;76061:4808:0;;;;;;;;;;;;","srcMapRuntime":"76061:4808:0:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;74069:212;;;;;;:::i;:::-;;:::i;:::-;;;516:14:1;;509:22;491:41;;479:2;464:18;74069:212:0;;;;;;;;77302:66;;77342:26;77302:66;;;;;689:25:1;;;677:2;662:18;77302:66:0;543:177:1;77044:60:0;;77081:23;77044:60;;79902:554;;;;;;:::i;:::-;;:::i;:::-;;77794:45;;77833:6;77794:45;;76279:85;;76322:42;76279:85;;;;;1549:42:1;1537:55;;;1519:74;;1507:2;1492:18;76279:85:0;1373:226:1;78981:129:0;;;;;;:::i;:::-;;:::i;70265:120::-;;;;;;:::i;:::-;70330:7;70356:12;;;;;;;;;;:22;;;;70265:120;70681:136;;;;;;:::i;:::-;;:::i;71783:245::-;;;;;;:::i;:::-;;:::i;78188:30::-;;;;;;78418:26;;;;;;76528:62;;76566:24;76528:62;;74866:142;;;;;;:::i;:::-;;:::i;69309:136::-;;;;;;:::i;:::-;69386:4;69409:12;;;;;;;;;;;:29;;;;;;;;;;;;;;;;69309:136;77916:50;;77959:7;77916:50;;78045:53;;78092:6;78045:53;;68642:49;;68687:4;68642:49;;79505:290;;;;;;:::i;:::-;;:::i;77687:37::-;;77721:3;77687:37;;75176:131;;;;;;:::i;:::-;;:::i;77554:66::-;;77594:26;77554:66;;71097:138;;;;;;:::i;:::-;;:::i;76787:62::-;;76825:24;76787:62;;78274:47;;;;;;:::i;:::-;;;;;;;;;;;;;;78558:43;;;;;74069:212;74154:4;74177:57;;;74192:42;74177:57;;:97;;;74238:36;74262:11;74238:23;:36::i;:::-;74170:104;74069:212;-1:-1:-1;;74069:212:0:o;79902:554::-;77594:26;68919:16;68930:4;68919:10;:16::i;:::-;80026:19:::1;::::0;::::1;80006:17;80026:19:::0;;;:12:::1;:19;::::0;;;;;;80059:14;;;80055:27:::1;;80075:7;79902:554:::0;;;:::o;80055:27::-:1;80123:19;::::0;;::::1;80145:1;80123:19:::0;;;:12:::1;:19;::::0;;;;;;;:23;;;;80161:38;;2940:34:1;;;3010:15;;;2990:18;;;2983:43;;;;3042:18;;;3035:34;;;80161:38:0::1;::::0;2867:2:1;2852:18;80161:38:0::1;;;;;;;80271:25:::0;::::1;::::0;::::1;::::0;80267:183:::1;;80312:48;80338:9;80350;80312:17;:48::i;:::-;80267:183;;;80391:48;:26;::::0;::::1;80418:9:::0;80429;80391:26:::1;:48::i;:::-;79996:460;68945:1;79902:554:::0;;;:::o;78981:129::-;77594:26;68919:16;68930:4;68919:10;:16::i;:::-;79072:31:::1;79088:14;79072:15;:31::i;:::-;78981:129:::0;;:::o;70681:136::-;70330:7;70356:12;;;;;;;;;;:22;;;68919:16;68930:4;68919:10;:16::i;:::-;70785:25:::1;70796:4;70802:7;70785:10;:25::i;71783:245::-:0;71876:34;;;23372:10;71876:34;71872:102;;71933:30;;;;;;;;;;;;;;71872:102;71984:37;71996:4;72002:18;71984:11;:37::i;74866:142::-;74947:7;74973:18;;;:12;:18;;;;;:28;;74995:5;74973:21;:28::i;:::-;74966:35;74866:142;-1:-1:-1;;;74866:142:0:o;79505:290::-;77594:26;68919:16;68930:4;68919:10;:16::i;:::-;77833:6:::1;79600:10;:25;79596:55;;;79634:17;;;;;;;;;;;;;;79596:55;79682:15;::::0;;79707:28;;;;79750:38:::1;::::0;;3254:25:1;;;3310:2;3295:18;;3288:34;;;79750:38:0::1;::::0;3227:18:1;79750:38:0::1;;;;;;;79586:209;79505:290:::0;;:::o;75176:131::-;75247:7;75273:18;;;:12;:18;;;;;:27;;:25;:27::i;71097:138::-;70330:7;70356:12;;;;;;;;;;:22;;;68919:16;68930:4;68919:10;:16::i;:::-;71202:26:::1;71214:4;71220:7;71202:11;:26::i;69020:202::-:0;69105:4;69128:47;;;69143:32;69128:47;;:87;;-1:-1:-1;49356:25:0;49341:40;;;;69179:36;49242:146;69654:103;69720:30;69731:4;23372:10;69720;:30::i;:::-;69654:103;:::o;17904:331::-;18013:6;17989:21;:30;17985:109;;;18042:41;;;;;18077:4;18042:41;;;1519:74:1;1492:18;;18042:41:0;;;;;;;;17985:109;18105:12;18123:9;:14;;18145:6;18123:33;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;18104:52;;;18171:7;18166:63;;18201:17;;;;;;;;;;;;;;62137:160;62246:43;;;62261:14;3735:55:1;;62246:43:0;;;3717:74:1;3807:18;;;;3800:34;;;62246:43:0;;;;;;;;;;3690:18:1;;;;62246:43:0;;;;;;;;;;;;;;62219:71;;62239:5;;62219:19;:71::i;80577:290::-;77959:7;80648:14;:33;80644:67;;;80690:21;;;;;;;;;;;;;;80644:67;80746:11;;;80767:28;;;;80810:50;;;3254:25:1;;;3310:2;3295:18;;3288:34;;;80810:50:0;;3227:18:1;80810:50:0;;;;;;;80634:233;80577:290;:::o;75409:257::-;75495:4;75511:12;75526:31;75543:4;75549:7;75526:16;:31::i;:::-;75511:46;;75571:7;75567:69;;;75594:18;;;;:12;:18;;;;;:31;;75617:7;75594:22;:31::i;:::-;;75652:7;75409:257;-1:-1:-1;;;75409:257:0:o;75769:262::-;75856:4;75872:12;75887:32;75905:4;75911:7;75887:17;:32::i;:::-;75872:47;;75933:7;75929:72;;;75956:18;;;;:12;:18;;;;;:34;;75982:7;75956:25;:34::i;34075:156::-;34149:7;34199:22;34203:3;34215:5;34199:3;:22::i;33618:115::-;33681:7;33707:19;33715:3;29057:18;;28975:107;69887:197;69386:4;69409:12;;;;;;;;;;;:29;;;;;;;;;;;;;69970:108;;70020:47;;;;;3747:42:1;3735:55;;70020:47:0;;;3717:74:1;3807:18;;;3800:34;;;3690:18;;70020:47:0;3543:297:1;64893:629:0;65312:23;65338:33;:27;;;65366:4;65338:27;:33::i;:::-;65312:59;;65385:10;:17;65406:1;65385:22;;:57;;;;;65423:10;65412:30;;;;;;;;;;;;:::i;:::-;65411:31;65385:57;65381:135;;;65465:40;;;;;1549:42:1;1537:55;;65465:40:0;;;1519:74:1;1492:18;;65465:40:0;1373:226:1;72634:316:0;72711:4;69409:12;;;;;;;;;;;:29;;;;;;;;;;;;;72727:217;;72770:6;:12;;;;;;;;;;;:29;;;;;;;;;;:36;;;;72802:4;72770:36;;;72852:12;23372:10;;23293:96;72852:12;72825:40;;72843:7;72825:40;;72837:4;72825:40;;;;;;;;;;-1:-1:-1;72886:4:0;72879:11;;72727:217;-1:-1:-1;72928:5:0;72921:12;;32817:150;32887:4;32910:50;32915:3;32935:23;;;32910:4;:50::i;73185:317::-;73263:4;69409:12;;;;;;;;;;;:29;;;;;;;;;;;;;73279:217;;;73353:5;73321:12;;;;;;;;;;;:29;;;;;;;;;;;:37;;;;;;73377:40;23372:10;;73321:12;;73377:40;;73353:5;73377:40;-1:-1:-1;73438:4:0;73431:11;;33135:156;33208:4;33231:53;33239:3;33259:23;;;33231:7;:53::i;29424:118::-;29491:7;29517:3;:11;;29529:5;29517:18;;;;;;;;:::i;:::-;;;;;;;;;29510:25;;29424:118;;;;:::o;19078:151::-;19153:12;19184:38;19206:6;19214:4;19220:1;19184:21;:38::i;26742:406::-;26805:4;28861:21;;;:14;;;:21;;;;;;26821:321;;-1:-1:-1;26863:23:0;;;;;;;;:11;:23;;;;;;;;;;;;;27045:18;;27021:21;;;:14;;;:21;;;;;;:42;;;;27077:11;;27316:1368;27382:4;27511:21;;;:14;;;:21;;;;;;27547:13;;27543:1135;;27914:18;27935:12;27946:1;27935:8;:12;:::i;:::-;27981:18;;27914:33;;-1:-1:-1;27961:17:0;;27981:22;;28002:1;;27981:22;:::i;:::-;27961:42;;28036:9;28022:10;:23;28018:378;;28065:17;28085:3;:11;;28097:9;28085:22;;;;;;;;:::i;:::-;;;;;;;;;28065:42;;28232:9;28206:3;:11;;28218:10;28206:23;;;;;;;;:::i;:::-;;;;;;;;;;;;:35;;;;28345:25;;;:14;;;:25;;;;;:36;;;28018:378;28474:17;;:3;;:17;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;28577:3;:14;;:21;28592:5;28577:21;;;;;;;;;;;28570:28;;;28620:4;28613:11;;;;;;;27543:1135;28662:5;28655:12;;;;;19553:392;19652:12;19704:5;19680:21;:29;19676:108;;;19732:41;;;;;19767:4;19732:41;;;1519:74:1;1492:18;;19732:41:0;1373:226:1;19676:108:0;19794:12;19808:23;19835:6;:11;;19854:5;19861:4;19835:31;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;19793:73;;;;19883:55;19910:6;19918:7;19927:10;19883:26;:55::i;:::-;19876:62;19553:392;-1:-1:-1;;;;;;19553:392:0:o;20998:582::-;21142:12;21171:7;21166:408;;21194:19;21202:10;21194:7;:19::i;:::-;21166:408;;;21418:17;;:22;:49;;;;-1:-1:-1;21444:18:0;;;;:23;21418:49;21414:119;;;21494:24;;;;;1549:42:1;1537:55;;21494:24:0;;;1519:74:1;1492:18;;21494:24:0;1373:226:1;21414:119:0;-1:-1:-1;21553:10:0;21546:17;;22116:516;22247:17;;:21;22243:383;;22475:10;22469:17;22531:15;22518:10;22514:2;22510:19;22503:44;22243:383;22598:17;;;;;;;;;;;;;;14:332:1;72:6;125:2;113:9;104:7;100:23;96:32;93:52;;;141:1;138;131:12;93:52;180:9;167:23;230:66;223:5;219:78;212:5;209:89;199:117;;312:1;309;302:12;725:196;793:20;;853:42;842:54;;832:65;;822:93;;911:1;908;901:12;822:93;725:196;;;:::o;926:260::-;994:6;1002;1055:2;1043:9;1034:7;1030:23;1026:32;1023:52;;;1071:1;1068;1061:12;1023:52;1094:29;1113:9;1094:29;:::i;:::-;1084:39;;1142:38;1176:2;1165:9;1161:18;1142:38;:::i;:::-;1132:48;;926:260;;;;;:::o;1604:180::-;1663:6;1716:2;1704:9;1695:7;1691:23;1687:32;1684:52;;;1732:1;1729;1722:12;1684:52;-1:-1:-1;1755:23:1;;1604:180;-1:-1:-1;1604:180:1:o;1974:254::-;2042:6;2050;2103:2;2091:9;2082:7;2078:23;2074:32;2071:52;;;2119:1;2116;2109:12;2071:52;2155:9;2142:23;2132:33;;2184:38;2218:2;2207:9;2203:18;2184:38;:::i;2233:248::-;2301:6;2309;2362:2;2350:9;2341:7;2337:23;2333:32;2330:52;;;2378:1;2375;2368:12;2330:52;-1:-1:-1;;2401:23:1;;;2471:2;2456:18;;;2443:32;;-1:-1:-1;2233:248:1:o;2486:186::-;2545:6;2598:2;2586:9;2577:7;2573:23;2569:32;2566:52;;;2614:1;2611;2604:12;2566:52;2637:29;2656:9;2637:29;:::i;4147:277::-;4214:6;4267:2;4255:9;4246:7;4242:23;4238:32;4235:52;;;4283:1;4280;4273:12;4235:52;4315:9;4309:16;4368:5;4361:13;4354:21;4347:5;4344:32;4334:60;;4390:1;4387;4380:12;4429:184;4481:77;4478:1;4471:88;4578:4;4575:1;4568:15;4602:4;4599:1;4592:15;4618:282;4685:9;;;4706:11;;;4703:191;;;4750:77;4747:1;4740:88;4851:4;4848:1;4841:15;4879:4;4876:1;4869:15;4905:184;4957:77;4954:1;4947:88;5054:4;5051:1;5044:15;5078:4;5075:1;5068:15;5094:412;5223:3;5261:6;5255:13;5286:1;5296:129;5310:6;5307:1;5304:13;5296:129;;;5408:4;5392:14;;;5388:25;;5382:32;5369:11;;;5362:53;5325:12;5296:129;;;-1:-1:-1;5480:1:1;5444:16;;5469:13;;;-1:-1:-1;5444:16:1;5094:412;-1:-1:-1;5094:412:1:o","abiDefinition":[{"inputs":[{"internalType":"address","name":"_owner","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AccessControlBadConfirmation","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"bytes32","name":"neededRole","type":"bytes32"}],"name":"AccessControlUnauthorizedAccount","type":"error"},{"inputs":[{"internalType":"address","name":"target","type":"address"}],"name":"AddressEmptyCode","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"AddressInsufficientBalance","type":"error"},{"inputs":[],"name":"CancelDelayBelowMin","type":"error"},{"inputs":[],"name":"FailedInnerCall","type":"error"},{"inputs":[],"name":"FeeRateAboveMax","type":"error"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"SafeERC20FailedOperation","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldCancelDelay","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newCancelDelay","type":"uint256"}],"name":"CancelDelayUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldFeeRate","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newFeeRate","type":"uint256"}],"name":"FeeRateUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"address","name":"recipient","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"FeesSwept","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"previousAdminRole","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"newAdminRole","type":"bytes32"}],"name":"RoleAdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleRevoked","type":"event"},{"inputs":[],"name":"CANCELER_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"DEFAULT_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"DEFAULT_CANCEL_DELAY","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"FEE_BPS","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"FEE_RATE_MAX","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"GOVERNOR_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"GUARD_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MIN_CANCEL_DELAY","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"NATIVE_GAS_TOKEN","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"PROVER_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"QUOTER_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"cancelDelay","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"chainGasAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleAdmin","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"uint256","name":"index","type":"uint256"}],"name":"getRoleMember","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleMemberCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"grantRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"hasRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"protocolFeeRate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"protocolFees","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"callerConfirmation","type":"address"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"revokeRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"newCancelDelay","type":"uint256"}],"name":"setCancelDelay","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"newFeeRate","type":"uint256"}],"name":"setProtocolFeeRate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"address","name":"recipient","type":"address"}],"name":"sweepProtocolFees","outputs":[],"stateMutability":"nonpayable","type":"function"}],"userDoc":{"kind":"user","methods":{"CANCELER_ROLE()":{"notice":"Role identifier for Canceler's on-chain authentication in FastBridge."},"DEFAULT_CANCEL_DELAY()":{"notice":"Default cancel delay set during the contract deployment."},"FEE_BPS()":{"notice":"Denominator for fee rates, represents 100%."},"FEE_RATE_MAX()":{"notice":"Maximum protocol fee rate: 1% on origin amount."},"GOVERNOR_ROLE()":{"notice":"Role identifier for Governor's on-chain administrative authority."},"GUARD_ROLE()":{"notice":"Role identifier for Guard's on-chain authentication in FastBridge."},"MIN_CANCEL_DELAY()":{"notice":"Minimum cancel delay that can be set by the governor."},"NATIVE_GAS_TOKEN()":{"notice":"Address reserved for native gas token (ETH on Ethereum and most L2s, AVAX on Avalanche, etc)"},"PROVER_ROLE()":{"notice":"Role identifier for Prover's on-chain authentication in FastBridge."},"QUOTER_ROLE()":{"notice":"Role identifier for Quoter API's off-chain authentication."},"cancelDelay()":{"notice":"Delay for a transaction after which it could be permisionlessly cancelled"},"chainGasAmount()":{"notice":"This is deprecated and should not be used."},"protocolFeeRate()":{"notice":"Protocol fee rate taken on origin amount deposited in origin chain"},"protocolFees(address)":{"notice":"Protocol fee amounts accumulated"},"setCancelDelay(uint256)":{"notice":"Allows the contract governor to set the cancel delay. The cancel delay is the time after the transaction deadline after which it can be permissionlessly cancelled, if it hasn't been proven by any of the Relayers."},"setProtocolFeeRate(uint256)":{"notice":"Allows the contract governor to set the protocol fee rate. The protocol fee is taken from the origin amount only for completed and claimed transactions."},"sweepProtocolFees(address,address)":{"notice":"Allows the contract governor to sweep the accumulated protocol fees in the contract."}},"version":1},"developerDoc":{"errors":{"AccessControlBadConfirmation()":[{"details":"The caller of a function is not the expected one. NOTE: Don't confuse with {AccessControlUnauthorizedAccount}."}],"AccessControlUnauthorizedAccount(address,bytes32)":[{"details":"The `account` is missing a role."}],"AddressEmptyCode(address)":[{"details":"There's no code at `target` (it is not a contract)."}],"AddressInsufficientBalance(address)":[{"details":"The ETH balance of the account is not enough to perform the operation."}],"FailedInnerCall()":[{"details":"A call to an address target failed. The target may have reverted."}],"SafeERC20FailedOperation(address)":[{"details":"An operation with an ERC20 token failed."}]},"events":{"RoleAdminChanged(bytes32,bytes32,bytes32)":{"details":"Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole` `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite {RoleAdminChanged} not being emitted signaling this."},"RoleGranted(bytes32,address,address)":{"details":"Emitted when `account` is granted `role`. `sender` is the account that originated the contract call, an admin role bearer except when using {AccessControl-_setupRole}."},"RoleRevoked(bytes32,address,address)":{"details":"Emitted when `account` is revoked `role`. `sender` is the account that originated the contract call: - if using `revokeRole`, it is the admin role bearer - if using `renounceRole`, it is the role bearer (i.e. `account`)"}},"kind":"dev","methods":{"getRoleAdmin(bytes32)":{"details":"Returns the admin role that controls `role`. See {grantRole} and {revokeRole}. To change a role's admin, use {_setRoleAdmin}."},"getRoleMember(bytes32,uint256)":{"details":"Returns one of the accounts that have `role`. `index` must be a value between 0 and {getRoleMemberCount}, non-inclusive. Role bearers are not sorted in any particular way, and their ordering may change at any point. WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure you perform all queries on the same block. See the following https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post] for more information."},"getRoleMemberCount(bytes32)":{"details":"Returns the number of accounts that have `role`. Can be used together with {getRoleMember} to enumerate all bearers of a role."},"grantRole(bytes32,address)":{"details":"Grants `role` to `account`. If `account` had not been already granted `role`, emits a {RoleGranted} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleGranted} event."},"hasRole(bytes32,address)":{"details":"Returns `true` if `account` has been granted `role`."},"renounceRole(bytes32,address)":{"details":"Revokes `role` from the calling account. Roles are often managed via {grantRole} and {revokeRole}: this function's purpose is to provide a mechanism for accounts to lose their privileges if they are compromised (such as when a trusted device is misplaced). If the calling account had been revoked `role`, emits a {RoleRevoked} event. Requirements: - the caller must be `callerConfirmation`. May emit a {RoleRevoked} event."},"revokeRole(bytes32,address)":{"details":"Revokes `role` from `account`. If `account` had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleRevoked} event."},"setProtocolFeeRate(uint256)":{"details":"The protocol fee is abstracted away from the relayers, they always operate using the amounts after fees: what they see as the origin amount emitted in the log is what they get credited with."},"supportsInterface(bytes4)":{"details":"See {IERC165-supportsInterface}."}},"stateVariables":{"CANCELER_ROLE":{"details":"Only addresses with this role can cancel a FastBridge transaction without the cancel delay."},"GOVERNOR_ROLE":{"details":"Only addresses with this role can perform administrative tasks within the contract."},"GUARD_ROLE":{"details":"Only addresses with this role can dispute submitted relay proofs during the dispute period."},"PROVER_ROLE":{"details":"Only addresses with this role can provide proofs that a FastBridge request has been relayed."},"QUOTER_ROLE":{"details":"Only addresses with this role can post FastBridge quotes to the API."},"chainGasAmount":{"details":"Use ZapNative V2 requests instead."}},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_owner\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"AccessControlBadConfirmation\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"neededRole\",\"type\":\"bytes32\"}],\"name\":\"AccessControlUnauthorizedAccount\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"}],\"name\":\"AddressEmptyCode\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"AddressInsufficientBalance\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"CancelDelayBelowMin\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"FailedInnerCall\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"FeeRateAboveMax\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"}],\"name\":\"SafeERC20FailedOperation\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"oldCancelDelay\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newCancelDelay\",\"type\":\"uint256\"}],\"name\":\"CancelDelayUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"oldFeeRate\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newFeeRate\",\"type\":\"uint256\"}],\"name\":\"FeeRateUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"FeesSwept\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"previousAdminRole\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"newAdminRole\",\"type\":\"bytes32\"}],\"name\":\"RoleAdminChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleGranted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleRevoked\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"CANCELER_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"DEFAULT_ADMIN_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"DEFAULT_CANCEL_DELAY\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"FEE_BPS\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"FEE_RATE_MAX\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"GOVERNOR_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"GUARD_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"MIN_CANCEL_DELAY\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"NATIVE_GAS_TOKEN\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"PROVER_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"QUOTER_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"cancelDelay\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"chainGasAmount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"}],\"name\":\"getRoleAdmin\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"index\",\"type\":\"uint256\"}],\"name\":\"getRoleMember\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"}],\"name\":\"getRoleMemberCount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"grantRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"hasRole\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"protocolFeeRate\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"protocolFees\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"callerConfirmation\",\"type\":\"address\"}],\"name\":\"renounceRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"revokeRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"newCancelDelay\",\"type\":\"uint256\"}],\"name\":\"setCancelDelay\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"newFeeRate\",\"type\":\"uint256\"}],\"name\":\"setProtocolFeeRate\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes4\",\"name\":\"interfaceId\",\"type\":\"bytes4\"}],\"name\":\"supportsInterface\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"}],\"name\":\"sweepProtocolFees\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"errors\":{\"AccessControlBadConfirmation()\":[{\"details\":\"The caller of a function is not the expected one. NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\"}],\"AccessControlUnauthorizedAccount(address,bytes32)\":[{\"details\":\"The `account` is missing a role.\"}],\"AddressEmptyCode(address)\":[{\"details\":\"There's no code at `target` (it is not a contract).\"}],\"AddressInsufficientBalance(address)\":[{\"details\":\"The ETH balance of the account is not enough to perform the operation.\"}],\"FailedInnerCall()\":[{\"details\":\"A call to an address target failed. The target may have reverted.\"}],\"SafeERC20FailedOperation(address)\":[{\"details\":\"An operation with an ERC20 token failed.\"}]},\"events\":{\"RoleAdminChanged(bytes32,bytes32,bytes32)\":{\"details\":\"Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole` `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite {RoleAdminChanged} not being emitted signaling this.\"},\"RoleGranted(bytes32,address,address)\":{\"details\":\"Emitted when `account` is granted `role`. `sender` is the account that originated the contract call, an admin role bearer except when using {AccessControl-_setupRole}.\"},\"RoleRevoked(bytes32,address,address)\":{\"details\":\"Emitted when `account` is revoked `role`. `sender` is the account that originated the contract call: - if using `revokeRole`, it is the admin role bearer - if using `renounceRole`, it is the role bearer (i.e. `account`)\"}},\"kind\":\"dev\",\"methods\":{\"getRoleAdmin(bytes32)\":{\"details\":\"Returns the admin role that controls `role`. See {grantRole} and {revokeRole}. To change a role's admin, use {_setRoleAdmin}.\"},\"getRoleMember(bytes32,uint256)\":{\"details\":\"Returns one of the accounts that have `role`. `index` must be a value between 0 and {getRoleMemberCount}, non-inclusive. Role bearers are not sorted in any particular way, and their ordering may change at any point. WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure you perform all queries on the same block. See the following https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post] for more information.\"},\"getRoleMemberCount(bytes32)\":{\"details\":\"Returns the number of accounts that have `role`. Can be used together with {getRoleMember} to enumerate all bearers of a role.\"},\"grantRole(bytes32,address)\":{\"details\":\"Grants `role` to `account`. If `account` had not been already granted `role`, emits a {RoleGranted} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleGranted} event.\"},\"hasRole(bytes32,address)\":{\"details\":\"Returns `true` if `account` has been granted `role`.\"},\"renounceRole(bytes32,address)\":{\"details\":\"Revokes `role` from the calling account. Roles are often managed via {grantRole} and {revokeRole}: this function's purpose is to provide a mechanism for accounts to lose their privileges if they are compromised (such as when a trusted device is misplaced). If the calling account had been revoked `role`, emits a {RoleRevoked} event. Requirements: - the caller must be `callerConfirmation`. May emit a {RoleRevoked} event.\"},\"revokeRole(bytes32,address)\":{\"details\":\"Revokes `role` from `account`. If `account` had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleRevoked} event.\"},\"setProtocolFeeRate(uint256)\":{\"details\":\"The protocol fee is abstracted away from the relayers, they always operate using the amounts after fees: what they see as the origin amount emitted in the log is what they get credited with.\"},\"supportsInterface(bytes4)\":{\"details\":\"See {IERC165-supportsInterface}.\"}},\"stateVariables\":{\"CANCELER_ROLE\":{\"details\":\"Only addresses with this role can cancel a FastBridge transaction without the cancel delay.\"},\"GOVERNOR_ROLE\":{\"details\":\"Only addresses with this role can perform administrative tasks within the contract.\"},\"GUARD_ROLE\":{\"details\":\"Only addresses with this role can dispute submitted relay proofs during the dispute period.\"},\"PROVER_ROLE\":{\"details\":\"Only addresses with this role can provide proofs that a FastBridge request has been relayed.\"},\"QUOTER_ROLE\":{\"details\":\"Only addresses with this role can post FastBridge quotes to the API.\"},\"chainGasAmount\":{\"details\":\"Use ZapNative V2 requests instead.\"}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"CANCELER_ROLE()\":{\"notice\":\"Role identifier for Canceler's on-chain authentication in FastBridge.\"},\"DEFAULT_CANCEL_DELAY()\":{\"notice\":\"Default cancel delay set during the contract deployment.\"},\"FEE_BPS()\":{\"notice\":\"Denominator for fee rates, represents 100%.\"},\"FEE_RATE_MAX()\":{\"notice\":\"Maximum protocol fee rate: 1% on origin amount.\"},\"GOVERNOR_ROLE()\":{\"notice\":\"Role identifier for Governor's on-chain administrative authority.\"},\"GUARD_ROLE()\":{\"notice\":\"Role identifier for Guard's on-chain authentication in FastBridge.\"},\"MIN_CANCEL_DELAY()\":{\"notice\":\"Minimum cancel delay that can be set by the governor.\"},\"NATIVE_GAS_TOKEN()\":{\"notice\":\"Address reserved for native gas token (ETH on Ethereum and most L2s, AVAX on Avalanche, etc)\"},\"PROVER_ROLE()\":{\"notice\":\"Role identifier for Prover's on-chain authentication in FastBridge.\"},\"QUOTER_ROLE()\":{\"notice\":\"Role identifier for Quoter API's off-chain authentication.\"},\"cancelDelay()\":{\"notice\":\"Delay for a transaction after which it could be permisionlessly cancelled\"},\"chainGasAmount()\":{\"notice\":\"This is deprecated and should not be used.\"},\"protocolFeeRate()\":{\"notice\":\"Protocol fee rate taken on origin amount deposited in origin chain\"},\"protocolFees(address)\":{\"notice\":\"Protocol fee amounts accumulated\"},\"setCancelDelay(uint256)\":{\"notice\":\"Allows the contract governor to set the cancel delay. The cancel delay is the time after the transaction deadline after which it can be permissionlessly cancelled, if it hasn't been proven by any of the Relayers.\"},\"setProtocolFeeRate(uint256)\":{\"notice\":\"Allows the contract governor to set the protocol fee rate. The protocol fee is taken from the origin amount only for completed and claimed transactions.\"},\"sweepProtocolFees(address,address)\":{\"notice\":\"Allows the contract governor to sweep the accumulated protocol fees in the contract.\"}},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeV2.sol\":\"AdminV2\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeV2.sol\":{\"keccak256\":\"0xac79c463688a682ca706a4ef95e7817b83548cdfa8182ba0426ac7e5e07613d8\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://b3ecb7097381287cafc3a73f3a2bb03565115ebb682a85064e0b0dc2f7e2919d\",\"dweb:/ipfs/QmatruW3nYZTksf3CeQ8wwiAG4c7xoEJBEp6drHPtFLBRK\"]}},\"version\":1}"},"hashes":{"CANCELER_ROLE()":"02d2ff66","DEFAULT_ADMIN_ROLE()":"a217fddf","DEFAULT_CANCEL_DELAY()":"930ac180","FEE_BPS()":"bf333f2c","FEE_RATE_MAX()":"0f5f6ed7","GOVERNOR_ROLE()":"ccc57490","GUARD_ROLE()":"03ed0ee5","MIN_CANCEL_DELAY()":"922b7487","NATIVE_GAS_TOKEN()":"0f862f1e","PROVER_ROLE()":"dc9a4ef6","QUOTER_ROLE()":"7ebe815c","cancelDelay()":"638a0f09","chainGasAmount()":"e00a83e0","getRoleAdmin(bytes32)":"248a9ca3","getRoleMember(bytes32,uint256)":"9010d07c","getRoleMemberCount(bytes32)":"ca15c873","grantRole(bytes32,address)":"2f2ff15d","hasRole(bytes32,address)":"91d14854","protocolFeeRate()":"58f85880","protocolFees(address)":"dcf844a7","renounceRole(bytes32,address)":"36568abe","revokeRole(bytes32,address)":"d547741f","setCancelDelay(uint256)":"1ea327c5","setProtocolFeeRate(uint256)":"b13aa2d6","supportsInterface(bytes4)":"01ffc9a7","sweepProtocolFees(address,address)":"06f333f2"}},"solidity/FastBridgeV2.sol:BridgeTransactionV2Lib":{"code":"0x60566037600b82828239805160001a607314602a57634e487b7160e01b600052600060045260246000fd5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600080fdfea2646970667358221220736bb5e8e495fb3a776c3cad8b30577c46279a088f4f89b0d509badbef3da01f64736f6c63430008180033","runtime-code":"0x73000000000000000000000000000000000000000030146080604052600080fdfea2646970667358221220736bb5e8e495fb3a776c3cad8b30577c46279a088f4f89b0d509badbef3da01f64736f6c63430008180033","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.24 ^0.8.20 ^0.8.4;\n\n// contracts/interfaces/IAdminV2.sol\n\ninterface IAdminV2 {\n event CancelDelayUpdated(uint256 oldCancelDelay, uint256 newCancelDelay);\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n function setCancelDelay(uint256 newCancelDelay) external;\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n}\n\n// contracts/interfaces/IAdminV2Errors.sol\n\ninterface IAdminV2Errors {\n error CancelDelayBelowMin();\n error FeeRateAboveMax();\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IFastBridgeV2Errors.sol\n\ninterface IFastBridgeV2Errors {\n error AmountIncorrect();\n error ChainIncorrect();\n error ExclusivityParamsIncorrect();\n error MsgValueIncorrect();\n error SenderIncorrect();\n error StatusIncorrect();\n error TokenNotContract();\n error ZapDataLengthAboveMax();\n error ZapNativeNotSupported();\n error ZeroAddress();\n\n error RecipientIncorrectReturnValue();\n error RecipientNoReturnValue();\n\n error DeadlineExceeded();\n error DeadlineNotExceeded();\n error DeadlineTooShort();\n error DisputePeriodNotPassed();\n error DisputePeriodPassed();\n error ExclusivityPeriodNotPassed();\n\n error TransactionRelayed();\n}\n\n// contracts/interfaces/IMulticallTarget.sol\n\n/// @notice Interface for a contract that can be called multiple times by the same caller. Inspired by MulticallV3:\n/// https://github.com/mds1/multicall/blob/master/src/Multicall3.sol\ninterface IMulticallTarget {\n struct Result {\n bool success;\n bytes returnData;\n }\n\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external;\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results);\n}\n\n// contracts/interfaces/IZapRecipient.sol\n\ninterface IZapRecipient {\n function zap(address token, uint256 amount, bytes memory zapData) external payable returns (bytes4);\n}\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// contracts/interfaces/IFastBridgeV2.sol\n\ninterface IFastBridgeV2 is IFastBridge {\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n struct BridgeTxDetails {\n BridgeStatus status;\n uint32 destChainId;\n uint56 proofBlockTimestamp;\n address proofRelayer;\n }\n\n struct BridgeRelay {\n uint48 blockNumber;\n uint48 blockTimestamp;\n address relayer;\n }\n\n /// @notice New params introduced in the FastBridgeV2.\n /// We are passing fields from the older BridgeParams struct outside of this struct\n /// for backwards compatibility.\n /// Note: quoteRelayer and quoteExclusivitySeconds are either both zero (indicating no exclusivity)\n /// or both non-zero (indicating exclusivity for the given period).\n /// Note: zapNative \u003e 0 can NOT be used with destToken = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE (native token)\n /// @param quoteRelayer Relayer that provided the quote for the transaction\n /// @param quoteExclusivitySeconds Period of time the quote relayer is guaranteed exclusivity after user's deposit\n /// @param quoteId Unique quote identifier used for tracking the quote\n /// @param zapNative ETH value to send to the recipient (if any)\n /// @param zapData Parameters for the Zap to the destination recipient (if any)\n struct BridgeParamsV2 {\n address quoteRelayer;\n int256 quoteExclusivitySeconds;\n bytes quoteId;\n uint256 zapNative;\n bytes zapData;\n }\n\n /// @notice Updated bridge transaction struct to include parameters introduced in FastBridgeV2.\n /// Note: only `exclusivityRelayer` can fill such a transaction until `exclusivityEndTime`.\n struct BridgeTransactionV2 {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n // Note: sendChainGas flag from V1 is deprecated\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n address exclusivityRelayer;\n uint256 exclusivityEndTime;\n uint256 zapNative; // ETH value to send to the recipient (if any)\n bytes zapData; // data to pass for the Zap action (if any)\n }\n\n event BridgeQuoteDetails(bytes32 indexed transactionId, bytes quoteId);\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability\n /// to provide temporary exclusivity fill rights for the quote relayer.\n /// @param params The parameters required to bridge\n /// @param paramsV2 The parameters for exclusivity fill rights (optional, can be left empty)\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function relay(bytes memory request, address relayer) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param transactionId The transaction id associated with the encoded bridge transaction to prove\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital.\n /// @notice Can only send funds to the relayer address on the proof.\n /// @param request The encoded bridge transaction to claim on origin chain\n function claim(bytes memory request) external;\n\n /// @notice Cancels an outstanding bridge transaction in case optimistic bridging failed and returns the full amount\n /// to the original sender.\n /// @param request The encoded bridge transaction to refund\n function cancel(bytes memory request) external;\n\n /// @notice Checks if a transaction has been relayed\n /// @param transactionId The ID of the transaction to check\n /// @return True if the transaction has been relayed, false otherwise\n function bridgeRelays(bytes32 transactionId) external view returns (bool);\n\n /// @notice Returns the status of a bridge transaction\n /// @param transactionId The ID of the bridge transaction\n /// @return BridgeStatus Status of the bridge transaction\n function bridgeStatuses(bytes32 transactionId) external view returns (BridgeStatus);\n\n /// @notice Returns the timestamp and relayer of a bridge proof\n /// @param transactionId The ID of the bridge transaction\n /// @return timestamp The timestamp of the bridge proof\n /// @return relayer The relayer address of the bridge proof\n function bridgeProofs(bytes32 transactionId) external view returns (uint96 timestamp, address relayer);\n\n /// @notice Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\n /// @param request The bridge request to decode\n function getBridgeTransactionV2(bytes memory request) external view returns (BridgeTransactionV2 memory);\n}\n\n// contracts/utils/MulticallTarget.sol\n\n// solhint-disable avoid-low-level-calls\n/// @notice Template for a contract that supports batched calls (preserving the msg.sender).\n/// Only calls with zero msg.value could be batched.\nabstract contract MulticallTarget is IMulticallTarget {\n error MulticallTarget__UndeterminedRevert();\n\n /// @notice Perform a batched call to this contract, preserving the msg.sender.\n /// The return data from each call is discarded.\n /// @dev The method is non-payable, so only calls with `msg.value == 0` could be batched.\n /// It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag.\n /// Otherwise, the whole batch call will be reverted with the original revert reason.\n /// @param data List of abi-encoded calldata for the calls to perform.\n /// @param ignoreReverts Whether to ignore the revert errors from the calls.\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external {\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\n if (!success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(result);\n }\n }\n }\n\n /// @notice Perform a batched call to this contract, preserving the msg.sender.\n /// The return data from each call is preserved.\n /// @dev The method is non-payable, so only calls with `msg.value == 0` could be batched.\n /// It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag.\n /// Otherwise, the whole batch call will be reverted with the original revert reason.\n /// @param data List of abi-encoded calldata for the calls to perform.\n /// @param ignoreReverts Whether to ignore the revert errors from the calls.\n /// @return results List of results from the calls: `(success, returnData)`.\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results)\n {\n results = new Result[](data.length);\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (results[i].success, results[i].returnData) = address(this).delegatecall(data[i]);\n if (!results[i].success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(results[i].returnData);\n }\n }\n }\n\n /// @dev Bubbles the revert message from the underlying call.\n /// Note: preserves the same custom error or revert string, if one was used.\n /// Source: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v5.0.2/contracts/utils/Address.sol#L143-L158\n function _bubbleRevert(bytes memory returnData) internal pure {\n // Look for revert reason and bubble it up if present\n if (returnData.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n // solhint-disable-next-line no-inline-assembly\n assembly {\n let returndata_size := mload(returnData)\n revert(add(32, returnData), returndata_size)\n }\n } else {\n revert MulticallTarget__UndeterminedRevert();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// contracts/libs/BridgeTransactionV2.sol\n\n// solhint-disable no-inline-assembly\nlibrary BridgeTransactionV2Lib {\n uint16 internal constant VERSION = 2;\n\n // Offsets of the fields in the packed BridgeTransactionV2 struct\n // uint16 version [000 .. 002)\n // uint32 originChainId [002 .. 006)\n // uint32 destChainId [006 .. 010)\n // address originSender [010 .. 030)\n // address destRecipient [030 .. 050)\n // address originToken [050 .. 070)\n // address destToken [070 .. 090)\n // uint256 originAmount [090 .. 122)\n // uint256 destAmount [122 .. 154)\n // uint256 originFeeAmount [154 .. 186)\n // uint256 deadline [186 .. 218)\n // uint256 nonce [218 .. 250)\n // address exclusivityRelayer [250 .. 270)\n // uint256 exclusivityEndTime [270 .. 302)\n // uint256 zapNative [302 .. 334)\n // bytes zapData [334 .. ***)\n\n // forgefmt: disable-start\n uint256 private constant OFFSET_ORIGIN_CHAIN_ID = 2;\n uint256 private constant OFFSET_DEST_CHAIN_ID = 6;\n uint256 private constant OFFSET_ORIGIN_SENDER = 10;\n uint256 private constant OFFSET_DEST_RECIPIENT = 30;\n uint256 private constant OFFSET_ORIGIN_TOKEN = 50;\n uint256 private constant OFFSET_DEST_TOKEN = 70;\n uint256 private constant OFFSET_ORIGIN_AMOUNT = 90;\n uint256 private constant OFFSET_DEST_AMOUNT = 122;\n uint256 private constant OFFSET_ORIGIN_FEE_AMOUNT = 154;\n uint256 private constant OFFSET_DEADLINE = 186;\n uint256 private constant OFFSET_NONCE = 218;\n uint256 private constant OFFSET_EXCLUSIVITY_RELAYER = 250;\n uint256 private constant OFFSET_EXCLUSIVITY_END_TIME = 270;\n uint256 private constant OFFSET_ZAP_NATIVE = 302;\n uint256 private constant OFFSET_ZAP_DATA = 334;\n // forgefmt: disable-end\n\n error BridgeTransactionV2__InvalidEncodedTx();\n error BridgeTransactionV2__UnsupportedVersion(uint16 version);\n\n /// @notice Validates the encoded transaction to be a tightly packed encoded payload for BridgeTransactionV2.\n /// @dev Checks the minimum length and the version, use this function before decoding any of the fields.\n function validateV2(bytes calldata encodedTx) internal pure {\n // Check the minimum length: must at least include all static fields.\n if (encodedTx.length \u003c OFFSET_ZAP_DATA) revert BridgeTransactionV2__InvalidEncodedTx();\n // Once we validated the length, we can be sure that the version field is present.\n uint16 version_ = version(encodedTx);\n if (version_ != VERSION) revert BridgeTransactionV2__UnsupportedVersion(version_);\n }\n\n /// @notice Encodes the BridgeTransactionV2 struct by tightly packing the fields.\n /// @dev `abi.decode` will not work as a result of the tightly packed fields. Use `decodeV2` to decode instead.\n function encodeV2(IFastBridgeV2.BridgeTransactionV2 memory bridgeTx) internal pure returns (bytes memory) {\n // We split the encoding into two parts to avoid stack-too-deep error\n bytes memory firstPart = abi.encodePacked(\n VERSION,\n bridgeTx.originChainId,\n bridgeTx.destChainId,\n bridgeTx.originSender,\n bridgeTx.destRecipient,\n bridgeTx.originToken,\n bridgeTx.destToken,\n bridgeTx.originAmount\n );\n return abi.encodePacked(\n firstPart,\n bridgeTx.destAmount,\n bridgeTx.originFeeAmount,\n // Note: we skip the deprecated `sendChainGas` flag, which was present in BridgeTransaction V1\n bridgeTx.deadline,\n bridgeTx.nonce,\n // New V2 fields: exclusivity\n bridgeTx.exclusivityRelayer,\n bridgeTx.exclusivityEndTime,\n // New V2 fields: Zap\n bridgeTx.zapNative,\n bridgeTx.zapData\n );\n }\n\n /// @notice Decodes the BridgeTransactionV2 struct from the encoded transaction.\n /// @dev Encoded BridgeTransactionV2 struct must be tightly packed.\n /// Use `validateV2` before decoding to ensure the encoded transaction is valid.\n function decodeV2(bytes calldata encodedTx)\n internal\n pure\n returns (IFastBridgeV2.BridgeTransactionV2 memory bridgeTx)\n {\n bridgeTx.originChainId = originChainId(encodedTx);\n bridgeTx.destChainId = destChainId(encodedTx);\n bridgeTx.originSender = originSender(encodedTx);\n bridgeTx.destRecipient = destRecipient(encodedTx);\n bridgeTx.originToken = originToken(encodedTx);\n bridgeTx.destToken = destToken(encodedTx);\n bridgeTx.originAmount = originAmount(encodedTx);\n bridgeTx.destAmount = destAmount(encodedTx);\n bridgeTx.originFeeAmount = originFeeAmount(encodedTx);\n bridgeTx.deadline = deadline(encodedTx);\n bridgeTx.nonce = nonce(encodedTx);\n bridgeTx.exclusivityRelayer = exclusivityRelayer(encodedTx);\n bridgeTx.exclusivityEndTime = exclusivityEndTime(encodedTx);\n bridgeTx.zapNative = zapNative(encodedTx);\n bridgeTx.zapData = zapData(encodedTx);\n }\n\n /// @notice Extracts the version from the encoded transaction.\n function version(bytes calldata encodedTx) internal pure returns (uint16 version_) {\n // Load 32 bytes from the start and shift it 240 bits to the right to get the highest 16 bits.\n assembly {\n version_ := shr(240, calldataload(encodedTx.offset))\n }\n }\n\n /// @notice Extracts the origin chain ID from the encoded transaction.\n function originChainId(bytes calldata encodedTx) internal pure returns (uint32 originChainId_) {\n // Load 32 bytes from the offset and shift it 224 bits to the right to get the highest 32 bits.\n assembly {\n originChainId_ := shr(224, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_CHAIN_ID)))\n }\n }\n\n /// @notice Extracts the destination chain ID from the encoded transaction.\n function destChainId(bytes calldata encodedTx) internal pure returns (uint32 destChainId_) {\n // Load 32 bytes from the offset and shift it 224 bits to the right to get the highest 32 bits.\n assembly {\n destChainId_ := shr(224, calldataload(add(encodedTx.offset, OFFSET_DEST_CHAIN_ID)))\n }\n }\n\n /// @notice Extracts the origin sender from the encoded transaction.\n function originSender(bytes calldata encodedTx) internal pure returns (address originSender_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n originSender_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_SENDER)))\n }\n }\n\n /// @notice Extracts the destination recipient from the encoded transaction.\n function destRecipient(bytes calldata encodedTx) internal pure returns (address destRecipient_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n destRecipient_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_DEST_RECIPIENT)))\n }\n }\n\n /// @notice Extracts the origin token from the encoded transaction.\n function originToken(bytes calldata encodedTx) internal pure returns (address originToken_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n originToken_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_TOKEN)))\n }\n }\n\n /// @notice Extracts the destination token from the encoded transaction.\n function destToken(bytes calldata encodedTx) internal pure returns (address destToken_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n destToken_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_DEST_TOKEN)))\n }\n }\n\n /// @notice Extracts the origin amount from the encoded transaction.\n function originAmount(bytes calldata encodedTx) internal pure returns (uint256 originAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n originAmount_ := calldataload(add(encodedTx.offset, OFFSET_ORIGIN_AMOUNT))\n }\n }\n\n /// @notice Extracts the destination amount from the encoded transaction.\n function destAmount(bytes calldata encodedTx) internal pure returns (uint256 destAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n destAmount_ := calldataload(add(encodedTx.offset, OFFSET_DEST_AMOUNT))\n }\n }\n\n /// @notice Extracts the origin fee amount from the encoded transaction.\n function originFeeAmount(bytes calldata encodedTx) internal pure returns (uint256 originFeeAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n originFeeAmount_ := calldataload(add(encodedTx.offset, OFFSET_ORIGIN_FEE_AMOUNT))\n }\n }\n\n /// @notice Extracts the deadline from the encoded transaction.\n function deadline(bytes calldata encodedTx) internal pure returns (uint256 deadline_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n deadline_ := calldataload(add(encodedTx.offset, OFFSET_DEADLINE))\n }\n }\n\n /// @notice Extracts the nonce from the encoded transaction.\n function nonce(bytes calldata encodedTx) internal pure returns (uint256 nonce_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n nonce_ := calldataload(add(encodedTx.offset, OFFSET_NONCE))\n }\n }\n\n /// @notice Extracts the exclusivity relayer from the encoded transaction.\n function exclusivityRelayer(bytes calldata encodedTx) internal pure returns (address exclusivityRelayer_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n exclusivityRelayer_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_EXCLUSIVITY_RELAYER)))\n }\n }\n\n /// @notice Extracts the exclusivity end time from the encoded transaction.\n function exclusivityEndTime(bytes calldata encodedTx) internal pure returns (uint256 exclusivityEndTime_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n exclusivityEndTime_ := calldataload(add(encodedTx.offset, OFFSET_EXCLUSIVITY_END_TIME))\n }\n }\n\n /// @notice Extracts the Zap's native value from the encoded transaction.\n function zapNative(bytes calldata encodedTx) internal pure returns (uint256 zapNative_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n zapNative_ := calldataload(add(encodedTx.offset, OFFSET_ZAP_NATIVE))\n }\n }\n\n /// @notice Extracts the Zap's data from the encoded transaction.\n function zapData(bytes calldata encodedTx) internal pure returns (bytes calldata zapData_) {\n zapData_ = encodedTx[OFFSET_ZAP_DATA:];\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/AdminV2.sol\n\ncontract AdminV2 is AccessControlEnumerable, IAdminV2, IAdminV2Errors {\n using SafeERC20 for IERC20;\n\n /// @notice Address reserved for native gas token (ETH on Ethereum and most L2s, AVAX on Avalanche, etc)\n address public constant NATIVE_GAS_TOKEN = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Role identifier for Quoter API's off-chain authentication.\n /// @dev Only addresses with this role can post FastBridge quotes to the API.\n bytes32 public constant QUOTER_ROLE = keccak256(\"QUOTER_ROLE\");\n\n /// @notice Role identifier for Prover's on-chain authentication in FastBridge.\n /// @dev Only addresses with this role can provide proofs that a FastBridge request has been relayed.\n bytes32 public constant PROVER_ROLE = keccak256(\"PROVER_ROLE\");\n\n /// @notice Role identifier for Guard's on-chain authentication in FastBridge.\n /// @dev Only addresses with this role can dispute submitted relay proofs during the dispute period.\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n\n /// @notice Role identifier for Canceler's on-chain authentication in FastBridge.\n /// @dev Only addresses with this role can cancel a FastBridge transaction without the cancel delay.\n bytes32 public constant CANCELER_ROLE = keccak256(\"CANCELER_ROLE\");\n\n /// @notice Role identifier for Governor's on-chain administrative authority.\n /// @dev Only addresses with this role can perform administrative tasks within the contract.\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n /// @notice Denominator for fee rates, represents 100%.\n uint256 public constant FEE_BPS = 1e6;\n /// @notice Maximum protocol fee rate: 1% on origin amount.\n uint256 public constant FEE_RATE_MAX = 0.01e6;\n\n /// @notice Minimum cancel delay that can be set by the governor.\n uint256 public constant MIN_CANCEL_DELAY = 1 hours;\n /// @notice Default cancel delay set during the contract deployment.\n uint256 public constant DEFAULT_CANCEL_DELAY = 1 days;\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Delay for a transaction after which it could be permisionlessly cancelled\n uint256 public cancelDelay;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Use ZapNative V2 requests instead.\n uint256 public immutable chainGasAmount = 0;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n _setCancelDelay(DEFAULT_CANCEL_DELAY);\n }\n\n /// @notice Allows the contract governor to set the cancel delay. The cancel delay is the time after the transaction\n /// deadline after which it can be permissionlessly cancelled, if it hasn't been proven by any of the Relayers.\n function setCancelDelay(uint256 newCancelDelay) external onlyRole(GOVERNOR_ROLE) {\n _setCancelDelay(newCancelDelay);\n }\n\n /// @notice Allows the contract governor to set the protocol fee rate. The protocol fee is taken from the origin\n /// amount only for completed and claimed transactions.\n /// @dev The protocol fee is abstracted away from the relayers, they always operate using the amounts after fees:\n /// what they see as the origin amount emitted in the log is what they get credited with.\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n if (newFeeRate \u003e FEE_RATE_MAX) revert FeeRateAboveMax();\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n /// @notice Allows the contract governor to sweep the accumulated protocol fees in the contract.\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n emit FeesSwept(token, recipient, feeAmount);\n /// Sweep the fees as the last transaction action\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(recipient), feeAmount);\n } else {\n IERC20(token).safeTransfer(recipient, feeAmount);\n }\n }\n\n /// @notice Internal function to set the cancel delay. Security checks are performed outside of this function.\n function _setCancelDelay(uint256 newCancelDelay) private {\n if (newCancelDelay \u003c MIN_CANCEL_DELAY) revert CancelDelayBelowMin();\n uint256 oldCancelDelay = cancelDelay;\n cancelDelay = newCancelDelay;\n emit CancelDelayUpdated(oldCancelDelay, newCancelDelay);\n }\n}\n\n// contracts/FastBridgeV2.sol\n\n/// @notice FastBridgeV2 is a contract for bridging tokens across chains.\ncontract FastBridgeV2 is AdminV2, MulticallTarget, IFastBridgeV2, IFastBridgeV2Errors {\n using BridgeTransactionV2Lib for bytes;\n using SafeERC20 for IERC20;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n /// @notice Maximum length of accepted zapData\n uint256 public constant MAX_ZAP_DATA_LENGTH = 2 ** 16 - 1;\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeTxDetails) public bridgeTxDetails;\n /// @notice Relay details on destination chain\n mapping(bytes32 =\u003e BridgeRelay) public bridgeRelayDetails;\n /// @notice Unique bridge nonces tracked per originSender\n mapping(address =\u003e uint256) public senderNonces;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Replaced by senderNonces\n uint256 public immutable nonce = 0;\n /// @notice the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) AdminV2(_owner) {\n deployBlock = block.number;\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n bridge({\n params: params,\n paramsV2: BridgeParamsV2({\n quoteRelayer: address(0),\n quoteExclusivitySeconds: 0,\n quoteId: bytes(\"\"),\n zapNative: 0,\n zapData: bytes(\"\")\n })\n });\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes calldata request) external payable {\n // relay override will validate the request\n relay({request: request, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes calldata request, bytes32 destTxHash) external {\n request.validateV2();\n prove({transactionId: keccak256(request), destTxHash: destTxHash, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridgeV2\n function claim(bytes calldata request) external {\n // claim override will validate the request\n claim({request: request, to: address(0)});\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Aggregate the read operations from the same storage slot\n address disputedRelayer = $.proofRelayer;\n BridgeStatus status = $.status;\n uint56 proofBlockTimestamp = $.proofBlockTimestamp;\n // Can only dispute a RELAYER_PROVED transaction within the dispute period\n if (status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(proofBlockTimestamp) \u003e DISPUTE_PERIOD) {\n revert DisputePeriodPassed();\n }\n // Update status to REQUESTED and delete the disputed proof details\n // Note: these are storage writes\n $.status = BridgeStatus.REQUESTED;\n $.proofRelayer = address(0);\n $.proofBlockTimestamp = 0;\n\n emit BridgeProofDisputed(transactionId, disputedRelayer);\n }\n\n /// Note: this function is deprecated and will be removed in a future version.\n /// @inheritdoc IFastBridge\n function refund(bytes calldata request) external {\n cancel(request);\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // The correct relayer can only claim a RELAYER_PROVED transaction after the dispute period\n if ($.status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if ($.proofRelayer != relayer) revert SenderIncorrect();\n return _timeSince($.proofBlockTimestamp) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n /// @dev This method is added to achieve backwards compatibility with decoding requests into V1 structs:\n /// - `zapNative` is partially reported as a zero/non-zero flag\n /// - `zapData` is ignored\n /// In order to process all kinds of requests use getBridgeTransactionV2 instead.\n function getBridgeTransaction(bytes calldata request) external view returns (BridgeTransaction memory) {\n // Try decoding into V2 struct first. This will revert if V1 struct is passed\n try this.getBridgeTransactionV2(request) returns (BridgeTransactionV2 memory txV2) {\n // Note: we entirely ignore the zapData field, as it was not present in V1\n return BridgeTransaction({\n originChainId: txV2.originChainId,\n destChainId: txV2.destChainId,\n originSender: txV2.originSender,\n destRecipient: txV2.destRecipient,\n originToken: txV2.originToken,\n destToken: txV2.destToken,\n originAmount: txV2.originAmount,\n destAmount: txV2.destAmount,\n originFeeAmount: txV2.originFeeAmount,\n sendChainGas: txV2.zapNative != 0,\n deadline: txV2.deadline,\n nonce: txV2.nonce\n });\n } catch {\n // Fallback to V1 struct\n return abi.decode(request, (BridgeTransaction));\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function getBridgeTransactionV2(bytes calldata request) external pure returns (BridgeTransactionV2 memory) {\n request.validateV2();\n return BridgeTransactionV2Lib.decodeV2(request);\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) public payable {\n int256 exclusivityEndTime = 0;\n // if relayer exclusivity is not intended for this bridge, set exclusivityEndTime to static zero\n // otherwise, set exclusivity to expire at the current block ts offset by quoteExclusivitySeconds\n if (paramsV2.quoteRelayer != address(0)) {\n exclusivityEndTime = int256(block.timestamp) + paramsV2.quoteExclusivitySeconds;\n }\n _validateBridgeParams(params, paramsV2, exclusivityEndTime);\n\n // transfer tokens to bridge contract\n /// @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _takeBridgedUserAsset(params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) {\n originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n }\n\n // set status to requested\n bytes memory request = BridgeTransactionV2Lib.encodeV2(\n BridgeTransactionV2({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n deadline: params.deadline,\n nonce: senderNonces[params.sender]++, // increment nonce on every bridge\n exclusivityRelayer: paramsV2.quoteRelayer,\n // We checked exclusivityEndTime to be in range [0 .. params.deadline] above, so can safely cast\n exclusivityEndTime: uint256(exclusivityEndTime),\n zapNative: paramsV2.zapNative,\n zapData: paramsV2.zapData\n })\n );\n bytes32 transactionId = keccak256(request);\n // Note: the tx status will be updated throughout the tx lifecycle, while destChainId is set once here\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n bridgeTxDetails[transactionId].destChainId = params.dstChainId;\n\n emit BridgeRequested({\n transactionId: transactionId,\n sender: params.sender,\n request: request,\n destChainId: params.dstChainId,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n sendChainGas: paramsV2.zapNative != 0\n });\n emit BridgeQuoteDetails(transactionId, paramsV2.quoteId);\n }\n\n /// @inheritdoc IFastBridgeV2\n function relay(bytes calldata request, address relayer) public payable {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n _validateRelayParams(request, transactionId, relayer);\n // mark bridge transaction as relayed\n bridgeRelayDetails[transactionId] =\n BridgeRelay({blockNumber: uint48(block.number), blockTimestamp: uint48(block.timestamp), relayer: relayer});\n\n // transfer tokens to recipient on destination chain and trigger Zap if requested\n address to = request.destRecipient();\n address token = request.destToken();\n uint256 amount = request.destAmount();\n uint256 zapNative = request.zapNative();\n\n // Emit the event before any external calls\n emit BridgeRelayed({\n transactionId: transactionId,\n relayer: relayer,\n to: to,\n originChainId: request.originChainId(),\n originToken: request.originToken(),\n destToken: token,\n originAmount: request.originAmount(),\n destAmount: amount,\n chainGasAmount: zapNative\n });\n\n // All state changes have been done at this point, can proceed to the external calls.\n // This follows the checks-effects-interactions pattern to mitigate potential reentrancy attacks.\n if (token == NATIVE_GAS_TOKEN) {\n // For the native gas token, additional zapNative is not allowed\n if (zapNative != 0) revert ZapNativeNotSupported();\n // Check that the correct msg.value was sent\n if (msg.value != amount) revert MsgValueIncorrect();\n // Don't do a native transfer yet: we will handle it alongside the Zap below\n } else {\n // For ERC20s, we check that the correct msg.value was sent\n if (msg.value != zapNative) revert MsgValueIncorrect();\n // We need to transfer the tokens from the Relayer to the recipient first before performing an\n // optional post-transfer Zap.\n IERC20(token).safeTransferFrom(msg.sender, to, amount);\n }\n // At this point we have done:\n // - Transferred the requested amount of ERC20 tokens to the recipient.\n // At this point we have confirmed:\n // - For ERC20s: msg.value matches the requested zapNative amount.\n // - For the native gas token: msg.value matches the requested destAmount.\n // Remaining optional things to do:\n // - Forward the full msg.value to the recipient (if non-zero).\n // - Trigger a Zap (if zapData is present).\n bytes calldata zapData = request.zapData();\n if (zapData.length != 0) {\n // Zap Data is present: Zap has been requested by the recipient. Trigger it forwarding the full msg.value.\n\n // Note: if token has a fee on transfers, the recipient will have received less than `amount`.\n // This is a very niche edge case and should be handled by the recipient contract.\n _triggerZapWithChecks({recipient: to, token: token, amount: amount, zapData: zapData});\n } else if (msg.value != 0) {\n // Zap Data is missing, but msg.value was sent. This could happen in two different cases:\n // - Relay with the native gas token is happening.\n // - Relay with ERC20 is happening, with a `zapNative \u003e 0` request.\n // In both cases, we need to transfer the full msg.value to the recipient.\n Address.sendValue(payable(to), msg.value);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) public onlyRole(PROVER_ROLE) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n\n // Can only prove a REQUESTED transaction\n if ($.status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n // Update status to RELAYER_PROVED and store the proof details\n // Note: these are storage writes\n $.status = BridgeStatus.RELAYER_PROVED;\n $.proofBlockTimestamp = uint56(block.timestamp);\n $.proofRelayer = relayer;\n\n emit BridgeProofProvided(transactionId, relayer, destTxHash);\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes calldata request, address to) public {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Aggregate the read operations from the same storage slot\n address proofRelayer = $.proofRelayer;\n BridgeStatus status = $.status;\n uint56 proofBlockTimestamp = $.proofBlockTimestamp;\n\n // Can only claim a RELAYER_PROVED transaction after the dispute period\n if (status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(proofBlockTimestamp) \u003c= DISPUTE_PERIOD) {\n revert DisputePeriodNotPassed();\n }\n\n if (to == address(0)) {\n // Anyone could claim the funds to the proven relayer on their behalf\n to = proofRelayer;\n } else if (proofRelayer != msg.sender) {\n // Only the proven relayer could specify an address to claim the funds to\n revert SenderIncorrect();\n }\n\n // Update status to RELAYER_CLAIMED and transfer the origin collateral to the specified claim address\n // Note: this is a storage write\n $.status = BridgeStatus.RELAYER_CLAIMED;\n\n address token = request.originToken();\n uint256 amount = request.originAmount();\n // Update protocol fees if origin fee amount exists\n uint256 originFeeAmount = request.originFeeAmount();\n if (originFeeAmount \u003e 0) protocolFees[token] += originFeeAmount;\n // Emit the event before any external calls\n emit BridgeDepositClaimed(transactionId, proofRelayer, to, token, amount);\n // Complete the relayer claim as the last transaction action\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(to), amount);\n } else {\n IERC20(token).safeTransfer(to, amount);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function cancel(bytes calldata request) public {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Can only cancel a REQUESTED transaction after its deadline expires\n if ($.status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n uint256 deadline = request.deadline();\n // Permissionless cancel is only allowed after `cancelDelay` on top of the deadline\n if (!hasRole(CANCELER_ROLE, msg.sender)) deadline += cancelDelay;\n if (block.timestamp \u003c= deadline) revert DeadlineNotExceeded();\n // Update status to REFUNDED and return the full amount (collateral + protocol fees) to the original sender.\n // The protocol fees are only updated when the transaction is claimed, so we don't need to update them here.\n // Note: this is a storage write\n $.status = BridgeStatus.REFUNDED;\n\n address to = request.originSender();\n address token = request.originToken();\n uint256 amount = request.originAmount() + request.originFeeAmount();\n // Emit the event before any external calls\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n // Complete the user cancel as the last transaction action\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(to), amount);\n } else {\n IERC20(token).safeTransfer(to, amount);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeStatuses(bytes32 transactionId) public view returns (BridgeStatus status) {\n return bridgeTxDetails[transactionId].status;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeProofs(bytes32 transactionId) public view returns (uint96 timestamp, address relayer) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n\n timestamp = $.proofBlockTimestamp;\n relayer = $.proofRelayer;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeRelays(bytes32 transactionId) public view returns (bool) {\n // has this transactionId been relayed?\n return bridgeRelayDetails[transactionId].relayer != address(0);\n }\n\n /// @notice Takes the bridged asset from the user into FastBridgeV2 custody. It will be later\n /// claimed by the relayer who completed the relay on destination chain, or transferred back to the user\n /// via the cancel function should no one complete the relay.\n function _takeBridgedUserAsset(address token, uint256 amount) internal returns (uint256 amountTaken) {\n if (token == NATIVE_GAS_TOKEN) {\n // For the native gas token, we just need to check that the supplied msg.value is correct.\n // Supplied `msg.value` is already in FastBridgeV2 custody.\n if (amount != msg.value) revert MsgValueIncorrect();\n amountTaken = msg.value;\n } else {\n // For ERC20s, token is explicitly transferred from the user to FastBridgeV2.\n // We don't allow non-zero `msg.value` to avoid extra funds from being stuck in FastBridgeV2.\n if (msg.value != 0) revert MsgValueIncorrect();\n // Throw an explicit error if the provided token address is not a contract\n if (token.code.length == 0) revert TokenNotContract();\n amountTaken = IERC20(token).balanceOf(address(this));\n IERC20(token).safeTransferFrom(msg.sender, address(this), amount);\n // Use the balance difference as the amount taken in case of fee on transfer tokens.\n amountTaken = IERC20(token).balanceOf(address(this)) - amountTaken;\n }\n }\n\n /// @notice Calls the Recipient's hook function with the specified zapData and performs\n /// all the necessary checks for the returned value.\n function _triggerZapWithChecks(address recipient, address token, uint256 amount, bytes calldata zapData) internal {\n // This will bubble any revert messages from the hook function\n bytes memory returnData = Address.functionCallWithValue({\n target: recipient,\n data: abi.encodeCall(IZapRecipient.zap, (token, amount, zapData)),\n // Note: see `relay()` for reasoning behind passing msg.value\n value: msg.value\n });\n // Explicit revert if no return data at all\n if (returnData.length == 0) revert RecipientNoReturnValue();\n // Check that exactly a single return value was returned\n if (returnData.length != 32) revert RecipientIncorrectReturnValue();\n // Return value should be abi-encoded hook function selector\n if (bytes32(returnData) != bytes32(IZapRecipient.zap.selector)) {\n revert RecipientIncorrectReturnValue();\n }\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint56(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint56).max but\n /// proof.timestamp \u003c type(uint56).max via unchecked statement\n /// @param proofBlockTimestamp The bridge proof block timestamp\n /// @return delta Time delta since proof submitted\n function _timeSince(uint56 proofBlockTimestamp) internal view returns (uint256 delta) {\n unchecked {\n delta = uint56(block.timestamp) - proofBlockTimestamp;\n }\n }\n\n /// @notice Performs all the necessary checks for a bridge to happen.\n /// @dev There's no good way to refactor this function to reduce cyclomatic complexity due to\n /// the number of checks that need to be performed, so we skip the code-complexity rule here.\n // solhint-disable-next-line code-complexity\n function _validateBridgeParams(\n BridgeParams memory params,\n BridgeParamsV2 memory paramsV2,\n int256 exclusivityEndTime\n )\n internal\n view\n {\n // Check V1 (legacy) params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.sender == address(0) || params.to == address(0)) revert ZeroAddress();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n // Check V2 params\n if (paramsV2.zapData.length \u003e MAX_ZAP_DATA_LENGTH) revert ZapDataLengthAboveMax();\n if (paramsV2.zapNative != 0 \u0026\u0026 params.destToken == NATIVE_GAS_TOKEN) {\n revert ZapNativeNotSupported();\n }\n // exclusivityEndTime must be in range [0 .. params.deadline]\n if (exclusivityEndTime \u003c 0 || exclusivityEndTime \u003e int256(params.deadline)) {\n revert ExclusivityParamsIncorrect();\n }\n }\n\n /// @notice Performs all the necessary checks for a relay to happen.\n function _validateRelayParams(bytes calldata request, bytes32 transactionId, address relayer) internal view {\n if (relayer == address(0)) revert ZeroAddress();\n // Check if the transaction has already been relayed\n if (bridgeRelays(transactionId)) revert TransactionRelayed();\n if (request.destChainId() != block.chainid) revert ChainIncorrect();\n // Check the deadline for relay to happen\n if (block.timestamp \u003e request.deadline()) revert DeadlineExceeded();\n // Check the exclusivity period, if it is still ongoing\n address exclRelayer = request.exclusivityRelayer();\n if (exclRelayer != address(0) \u0026\u0026 exclRelayer != relayer \u0026\u0026 block.timestamp \u003c= request.exclusivityEndTime()) {\n revert ExclusivityPeriodNotPassed();\n }\n }\n}\n","language":"Solidity","languageVersion":"0.8.24","compilerVersion":"0.8.24","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"49473:11496:0:-:0;;;;;;;;;;;;;;;-1:-1:-1;;;49473:11496:0;;;;;;;;;;;;;;;;;","srcMapRuntime":"49473:11496:0:-:0;;;;;;;;","abiDefinition":[{"inputs":[],"name":"BridgeTransactionV2__InvalidEncodedTx","type":"error"},{"inputs":[{"internalType":"uint16","name":"version","type":"uint16"}],"name":"BridgeTransactionV2__UnsupportedVersion","type":"error"}],"userDoc":{"kind":"user","methods":{},"version":1},"developerDoc":{"kind":"dev","methods":{},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[],\"name\":\"BridgeTransactionV2__InvalidEncodedTx\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint16\",\"name\":\"version\",\"type\":\"uint16\"}],\"name\":\"BridgeTransactionV2__UnsupportedVersion\",\"type\":\"error\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeV2.sol\":\"BridgeTransactionV2Lib\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeV2.sol\":{\"keccak256\":\"0xac79c463688a682ca706a4ef95e7817b83548cdfa8182ba0426ac7e5e07613d8\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://b3ecb7097381287cafc3a73f3a2bb03565115ebb682a85064e0b0dc2f7e2919d\",\"dweb:/ipfs/QmatruW3nYZTksf3CeQ8wwiAG4c7xoEJBEp6drHPtFLBRK\"]}},\"version\":1}"},"hashes":{}},"solidity/FastBridgeV2.sol:Context":{"code":"0x","runtime-code":"0x","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.24 ^0.8.20 ^0.8.4;\n\n// contracts/interfaces/IAdminV2.sol\n\ninterface IAdminV2 {\n event CancelDelayUpdated(uint256 oldCancelDelay, uint256 newCancelDelay);\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n function setCancelDelay(uint256 newCancelDelay) external;\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n}\n\n// contracts/interfaces/IAdminV2Errors.sol\n\ninterface IAdminV2Errors {\n error CancelDelayBelowMin();\n error FeeRateAboveMax();\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IFastBridgeV2Errors.sol\n\ninterface IFastBridgeV2Errors {\n error AmountIncorrect();\n error ChainIncorrect();\n error ExclusivityParamsIncorrect();\n error MsgValueIncorrect();\n error SenderIncorrect();\n error StatusIncorrect();\n error TokenNotContract();\n error ZapDataLengthAboveMax();\n error ZapNativeNotSupported();\n error ZeroAddress();\n\n error RecipientIncorrectReturnValue();\n error RecipientNoReturnValue();\n\n error DeadlineExceeded();\n error DeadlineNotExceeded();\n error DeadlineTooShort();\n error DisputePeriodNotPassed();\n error DisputePeriodPassed();\n error ExclusivityPeriodNotPassed();\n\n error TransactionRelayed();\n}\n\n// contracts/interfaces/IMulticallTarget.sol\n\n/// @notice Interface for a contract that can be called multiple times by the same caller. Inspired by MulticallV3:\n/// https://github.com/mds1/multicall/blob/master/src/Multicall3.sol\ninterface IMulticallTarget {\n struct Result {\n bool success;\n bytes returnData;\n }\n\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external;\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results);\n}\n\n// contracts/interfaces/IZapRecipient.sol\n\ninterface IZapRecipient {\n function zap(address token, uint256 amount, bytes memory zapData) external payable returns (bytes4);\n}\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// contracts/interfaces/IFastBridgeV2.sol\n\ninterface IFastBridgeV2 is IFastBridge {\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n struct BridgeTxDetails {\n BridgeStatus status;\n uint32 destChainId;\n uint56 proofBlockTimestamp;\n address proofRelayer;\n }\n\n struct BridgeRelay {\n uint48 blockNumber;\n uint48 blockTimestamp;\n address relayer;\n }\n\n /// @notice New params introduced in the FastBridgeV2.\n /// We are passing fields from the older BridgeParams struct outside of this struct\n /// for backwards compatibility.\n /// Note: quoteRelayer and quoteExclusivitySeconds are either both zero (indicating no exclusivity)\n /// or both non-zero (indicating exclusivity for the given period).\n /// Note: zapNative \u003e 0 can NOT be used with destToken = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE (native token)\n /// @param quoteRelayer Relayer that provided the quote for the transaction\n /// @param quoteExclusivitySeconds Period of time the quote relayer is guaranteed exclusivity after user's deposit\n /// @param quoteId Unique quote identifier used for tracking the quote\n /// @param zapNative ETH value to send to the recipient (if any)\n /// @param zapData Parameters for the Zap to the destination recipient (if any)\n struct BridgeParamsV2 {\n address quoteRelayer;\n int256 quoteExclusivitySeconds;\n bytes quoteId;\n uint256 zapNative;\n bytes zapData;\n }\n\n /// @notice Updated bridge transaction struct to include parameters introduced in FastBridgeV2.\n /// Note: only `exclusivityRelayer` can fill such a transaction until `exclusivityEndTime`.\n struct BridgeTransactionV2 {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n // Note: sendChainGas flag from V1 is deprecated\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n address exclusivityRelayer;\n uint256 exclusivityEndTime;\n uint256 zapNative; // ETH value to send to the recipient (if any)\n bytes zapData; // data to pass for the Zap action (if any)\n }\n\n event BridgeQuoteDetails(bytes32 indexed transactionId, bytes quoteId);\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability\n /// to provide temporary exclusivity fill rights for the quote relayer.\n /// @param params The parameters required to bridge\n /// @param paramsV2 The parameters for exclusivity fill rights (optional, can be left empty)\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function relay(bytes memory request, address relayer) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param transactionId The transaction id associated with the encoded bridge transaction to prove\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital.\n /// @notice Can only send funds to the relayer address on the proof.\n /// @param request The encoded bridge transaction to claim on origin chain\n function claim(bytes memory request) external;\n\n /// @notice Cancels an outstanding bridge transaction in case optimistic bridging failed and returns the full amount\n /// to the original sender.\n /// @param request The encoded bridge transaction to refund\n function cancel(bytes memory request) external;\n\n /// @notice Checks if a transaction has been relayed\n /// @param transactionId The ID of the transaction to check\n /// @return True if the transaction has been relayed, false otherwise\n function bridgeRelays(bytes32 transactionId) external view returns (bool);\n\n /// @notice Returns the status of a bridge transaction\n /// @param transactionId The ID of the bridge transaction\n /// @return BridgeStatus Status of the bridge transaction\n function bridgeStatuses(bytes32 transactionId) external view returns (BridgeStatus);\n\n /// @notice Returns the timestamp and relayer of a bridge proof\n /// @param transactionId The ID of the bridge transaction\n /// @return timestamp The timestamp of the bridge proof\n /// @return relayer The relayer address of the bridge proof\n function bridgeProofs(bytes32 transactionId) external view returns (uint96 timestamp, address relayer);\n\n /// @notice Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\n /// @param request The bridge request to decode\n function getBridgeTransactionV2(bytes memory request) external view returns (BridgeTransactionV2 memory);\n}\n\n// contracts/utils/MulticallTarget.sol\n\n// solhint-disable avoid-low-level-calls\n/// @notice Template for a contract that supports batched calls (preserving the msg.sender).\n/// Only calls with zero msg.value could be batched.\nabstract contract MulticallTarget is IMulticallTarget {\n error MulticallTarget__UndeterminedRevert();\n\n /// @notice Perform a batched call to this contract, preserving the msg.sender.\n /// The return data from each call is discarded.\n /// @dev The method is non-payable, so only calls with `msg.value == 0` could be batched.\n /// It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag.\n /// Otherwise, the whole batch call will be reverted with the original revert reason.\n /// @param data List of abi-encoded calldata for the calls to perform.\n /// @param ignoreReverts Whether to ignore the revert errors from the calls.\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external {\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\n if (!success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(result);\n }\n }\n }\n\n /// @notice Perform a batched call to this contract, preserving the msg.sender.\n /// The return data from each call is preserved.\n /// @dev The method is non-payable, so only calls with `msg.value == 0` could be batched.\n /// It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag.\n /// Otherwise, the whole batch call will be reverted with the original revert reason.\n /// @param data List of abi-encoded calldata for the calls to perform.\n /// @param ignoreReverts Whether to ignore the revert errors from the calls.\n /// @return results List of results from the calls: `(success, returnData)`.\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results)\n {\n results = new Result[](data.length);\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (results[i].success, results[i].returnData) = address(this).delegatecall(data[i]);\n if (!results[i].success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(results[i].returnData);\n }\n }\n }\n\n /// @dev Bubbles the revert message from the underlying call.\n /// Note: preserves the same custom error or revert string, if one was used.\n /// Source: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v5.0.2/contracts/utils/Address.sol#L143-L158\n function _bubbleRevert(bytes memory returnData) internal pure {\n // Look for revert reason and bubble it up if present\n if (returnData.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n // solhint-disable-next-line no-inline-assembly\n assembly {\n let returndata_size := mload(returnData)\n revert(add(32, returnData), returndata_size)\n }\n } else {\n revert MulticallTarget__UndeterminedRevert();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// contracts/libs/BridgeTransactionV2.sol\n\n// solhint-disable no-inline-assembly\nlibrary BridgeTransactionV2Lib {\n uint16 internal constant VERSION = 2;\n\n // Offsets of the fields in the packed BridgeTransactionV2 struct\n // uint16 version [000 .. 002)\n // uint32 originChainId [002 .. 006)\n // uint32 destChainId [006 .. 010)\n // address originSender [010 .. 030)\n // address destRecipient [030 .. 050)\n // address originToken [050 .. 070)\n // address destToken [070 .. 090)\n // uint256 originAmount [090 .. 122)\n // uint256 destAmount [122 .. 154)\n // uint256 originFeeAmount [154 .. 186)\n // uint256 deadline [186 .. 218)\n // uint256 nonce [218 .. 250)\n // address exclusivityRelayer [250 .. 270)\n // uint256 exclusivityEndTime [270 .. 302)\n // uint256 zapNative [302 .. 334)\n // bytes zapData [334 .. ***)\n\n // forgefmt: disable-start\n uint256 private constant OFFSET_ORIGIN_CHAIN_ID = 2;\n uint256 private constant OFFSET_DEST_CHAIN_ID = 6;\n uint256 private constant OFFSET_ORIGIN_SENDER = 10;\n uint256 private constant OFFSET_DEST_RECIPIENT = 30;\n uint256 private constant OFFSET_ORIGIN_TOKEN = 50;\n uint256 private constant OFFSET_DEST_TOKEN = 70;\n uint256 private constant OFFSET_ORIGIN_AMOUNT = 90;\n uint256 private constant OFFSET_DEST_AMOUNT = 122;\n uint256 private constant OFFSET_ORIGIN_FEE_AMOUNT = 154;\n uint256 private constant OFFSET_DEADLINE = 186;\n uint256 private constant OFFSET_NONCE = 218;\n uint256 private constant OFFSET_EXCLUSIVITY_RELAYER = 250;\n uint256 private constant OFFSET_EXCLUSIVITY_END_TIME = 270;\n uint256 private constant OFFSET_ZAP_NATIVE = 302;\n uint256 private constant OFFSET_ZAP_DATA = 334;\n // forgefmt: disable-end\n\n error BridgeTransactionV2__InvalidEncodedTx();\n error BridgeTransactionV2__UnsupportedVersion(uint16 version);\n\n /// @notice Validates the encoded transaction to be a tightly packed encoded payload for BridgeTransactionV2.\n /// @dev Checks the minimum length and the version, use this function before decoding any of the fields.\n function validateV2(bytes calldata encodedTx) internal pure {\n // Check the minimum length: must at least include all static fields.\n if (encodedTx.length \u003c OFFSET_ZAP_DATA) revert BridgeTransactionV2__InvalidEncodedTx();\n // Once we validated the length, we can be sure that the version field is present.\n uint16 version_ = version(encodedTx);\n if (version_ != VERSION) revert BridgeTransactionV2__UnsupportedVersion(version_);\n }\n\n /// @notice Encodes the BridgeTransactionV2 struct by tightly packing the fields.\n /// @dev `abi.decode` will not work as a result of the tightly packed fields. Use `decodeV2` to decode instead.\n function encodeV2(IFastBridgeV2.BridgeTransactionV2 memory bridgeTx) internal pure returns (bytes memory) {\n // We split the encoding into two parts to avoid stack-too-deep error\n bytes memory firstPart = abi.encodePacked(\n VERSION,\n bridgeTx.originChainId,\n bridgeTx.destChainId,\n bridgeTx.originSender,\n bridgeTx.destRecipient,\n bridgeTx.originToken,\n bridgeTx.destToken,\n bridgeTx.originAmount\n );\n return abi.encodePacked(\n firstPart,\n bridgeTx.destAmount,\n bridgeTx.originFeeAmount,\n // Note: we skip the deprecated `sendChainGas` flag, which was present in BridgeTransaction V1\n bridgeTx.deadline,\n bridgeTx.nonce,\n // New V2 fields: exclusivity\n bridgeTx.exclusivityRelayer,\n bridgeTx.exclusivityEndTime,\n // New V2 fields: Zap\n bridgeTx.zapNative,\n bridgeTx.zapData\n );\n }\n\n /// @notice Decodes the BridgeTransactionV2 struct from the encoded transaction.\n /// @dev Encoded BridgeTransactionV2 struct must be tightly packed.\n /// Use `validateV2` before decoding to ensure the encoded transaction is valid.\n function decodeV2(bytes calldata encodedTx)\n internal\n pure\n returns (IFastBridgeV2.BridgeTransactionV2 memory bridgeTx)\n {\n bridgeTx.originChainId = originChainId(encodedTx);\n bridgeTx.destChainId = destChainId(encodedTx);\n bridgeTx.originSender = originSender(encodedTx);\n bridgeTx.destRecipient = destRecipient(encodedTx);\n bridgeTx.originToken = originToken(encodedTx);\n bridgeTx.destToken = destToken(encodedTx);\n bridgeTx.originAmount = originAmount(encodedTx);\n bridgeTx.destAmount = destAmount(encodedTx);\n bridgeTx.originFeeAmount = originFeeAmount(encodedTx);\n bridgeTx.deadline = deadline(encodedTx);\n bridgeTx.nonce = nonce(encodedTx);\n bridgeTx.exclusivityRelayer = exclusivityRelayer(encodedTx);\n bridgeTx.exclusivityEndTime = exclusivityEndTime(encodedTx);\n bridgeTx.zapNative = zapNative(encodedTx);\n bridgeTx.zapData = zapData(encodedTx);\n }\n\n /// @notice Extracts the version from the encoded transaction.\n function version(bytes calldata encodedTx) internal pure returns (uint16 version_) {\n // Load 32 bytes from the start and shift it 240 bits to the right to get the highest 16 bits.\n assembly {\n version_ := shr(240, calldataload(encodedTx.offset))\n }\n }\n\n /// @notice Extracts the origin chain ID from the encoded transaction.\n function originChainId(bytes calldata encodedTx) internal pure returns (uint32 originChainId_) {\n // Load 32 bytes from the offset and shift it 224 bits to the right to get the highest 32 bits.\n assembly {\n originChainId_ := shr(224, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_CHAIN_ID)))\n }\n }\n\n /// @notice Extracts the destination chain ID from the encoded transaction.\n function destChainId(bytes calldata encodedTx) internal pure returns (uint32 destChainId_) {\n // Load 32 bytes from the offset and shift it 224 bits to the right to get the highest 32 bits.\n assembly {\n destChainId_ := shr(224, calldataload(add(encodedTx.offset, OFFSET_DEST_CHAIN_ID)))\n }\n }\n\n /// @notice Extracts the origin sender from the encoded transaction.\n function originSender(bytes calldata encodedTx) internal pure returns (address originSender_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n originSender_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_SENDER)))\n }\n }\n\n /// @notice Extracts the destination recipient from the encoded transaction.\n function destRecipient(bytes calldata encodedTx) internal pure returns (address destRecipient_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n destRecipient_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_DEST_RECIPIENT)))\n }\n }\n\n /// @notice Extracts the origin token from the encoded transaction.\n function originToken(bytes calldata encodedTx) internal pure returns (address originToken_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n originToken_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_TOKEN)))\n }\n }\n\n /// @notice Extracts the destination token from the encoded transaction.\n function destToken(bytes calldata encodedTx) internal pure returns (address destToken_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n destToken_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_DEST_TOKEN)))\n }\n }\n\n /// @notice Extracts the origin amount from the encoded transaction.\n function originAmount(bytes calldata encodedTx) internal pure returns (uint256 originAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n originAmount_ := calldataload(add(encodedTx.offset, OFFSET_ORIGIN_AMOUNT))\n }\n }\n\n /// @notice Extracts the destination amount from the encoded transaction.\n function destAmount(bytes calldata encodedTx) internal pure returns (uint256 destAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n destAmount_ := calldataload(add(encodedTx.offset, OFFSET_DEST_AMOUNT))\n }\n }\n\n /// @notice Extracts the origin fee amount from the encoded transaction.\n function originFeeAmount(bytes calldata encodedTx) internal pure returns (uint256 originFeeAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n originFeeAmount_ := calldataload(add(encodedTx.offset, OFFSET_ORIGIN_FEE_AMOUNT))\n }\n }\n\n /// @notice Extracts the deadline from the encoded transaction.\n function deadline(bytes calldata encodedTx) internal pure returns (uint256 deadline_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n deadline_ := calldataload(add(encodedTx.offset, OFFSET_DEADLINE))\n }\n }\n\n /// @notice Extracts the nonce from the encoded transaction.\n function nonce(bytes calldata encodedTx) internal pure returns (uint256 nonce_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n nonce_ := calldataload(add(encodedTx.offset, OFFSET_NONCE))\n }\n }\n\n /// @notice Extracts the exclusivity relayer from the encoded transaction.\n function exclusivityRelayer(bytes calldata encodedTx) internal pure returns (address exclusivityRelayer_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n exclusivityRelayer_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_EXCLUSIVITY_RELAYER)))\n }\n }\n\n /// @notice Extracts the exclusivity end time from the encoded transaction.\n function exclusivityEndTime(bytes calldata encodedTx) internal pure returns (uint256 exclusivityEndTime_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n exclusivityEndTime_ := calldataload(add(encodedTx.offset, OFFSET_EXCLUSIVITY_END_TIME))\n }\n }\n\n /// @notice Extracts the Zap's native value from the encoded transaction.\n function zapNative(bytes calldata encodedTx) internal pure returns (uint256 zapNative_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n zapNative_ := calldataload(add(encodedTx.offset, OFFSET_ZAP_NATIVE))\n }\n }\n\n /// @notice Extracts the Zap's data from the encoded transaction.\n function zapData(bytes calldata encodedTx) internal pure returns (bytes calldata zapData_) {\n zapData_ = encodedTx[OFFSET_ZAP_DATA:];\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/AdminV2.sol\n\ncontract AdminV2 is AccessControlEnumerable, IAdminV2, IAdminV2Errors {\n using SafeERC20 for IERC20;\n\n /// @notice Address reserved for native gas token (ETH on Ethereum and most L2s, AVAX on Avalanche, etc)\n address public constant NATIVE_GAS_TOKEN = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Role identifier for Quoter API's off-chain authentication.\n /// @dev Only addresses with this role can post FastBridge quotes to the API.\n bytes32 public constant QUOTER_ROLE = keccak256(\"QUOTER_ROLE\");\n\n /// @notice Role identifier for Prover's on-chain authentication in FastBridge.\n /// @dev Only addresses with this role can provide proofs that a FastBridge request has been relayed.\n bytes32 public constant PROVER_ROLE = keccak256(\"PROVER_ROLE\");\n\n /// @notice Role identifier for Guard's on-chain authentication in FastBridge.\n /// @dev Only addresses with this role can dispute submitted relay proofs during the dispute period.\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n\n /// @notice Role identifier for Canceler's on-chain authentication in FastBridge.\n /// @dev Only addresses with this role can cancel a FastBridge transaction without the cancel delay.\n bytes32 public constant CANCELER_ROLE = keccak256(\"CANCELER_ROLE\");\n\n /// @notice Role identifier for Governor's on-chain administrative authority.\n /// @dev Only addresses with this role can perform administrative tasks within the contract.\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n /// @notice Denominator for fee rates, represents 100%.\n uint256 public constant FEE_BPS = 1e6;\n /// @notice Maximum protocol fee rate: 1% on origin amount.\n uint256 public constant FEE_RATE_MAX = 0.01e6;\n\n /// @notice Minimum cancel delay that can be set by the governor.\n uint256 public constant MIN_CANCEL_DELAY = 1 hours;\n /// @notice Default cancel delay set during the contract deployment.\n uint256 public constant DEFAULT_CANCEL_DELAY = 1 days;\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Delay for a transaction after which it could be permisionlessly cancelled\n uint256 public cancelDelay;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Use ZapNative V2 requests instead.\n uint256 public immutable chainGasAmount = 0;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n _setCancelDelay(DEFAULT_CANCEL_DELAY);\n }\n\n /// @notice Allows the contract governor to set the cancel delay. The cancel delay is the time after the transaction\n /// deadline after which it can be permissionlessly cancelled, if it hasn't been proven by any of the Relayers.\n function setCancelDelay(uint256 newCancelDelay) external onlyRole(GOVERNOR_ROLE) {\n _setCancelDelay(newCancelDelay);\n }\n\n /// @notice Allows the contract governor to set the protocol fee rate. The protocol fee is taken from the origin\n /// amount only for completed and claimed transactions.\n /// @dev The protocol fee is abstracted away from the relayers, they always operate using the amounts after fees:\n /// what they see as the origin amount emitted in the log is what they get credited with.\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n if (newFeeRate \u003e FEE_RATE_MAX) revert FeeRateAboveMax();\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n /// @notice Allows the contract governor to sweep the accumulated protocol fees in the contract.\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n emit FeesSwept(token, recipient, feeAmount);\n /// Sweep the fees as the last transaction action\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(recipient), feeAmount);\n } else {\n IERC20(token).safeTransfer(recipient, feeAmount);\n }\n }\n\n /// @notice Internal function to set the cancel delay. Security checks are performed outside of this function.\n function _setCancelDelay(uint256 newCancelDelay) private {\n if (newCancelDelay \u003c MIN_CANCEL_DELAY) revert CancelDelayBelowMin();\n uint256 oldCancelDelay = cancelDelay;\n cancelDelay = newCancelDelay;\n emit CancelDelayUpdated(oldCancelDelay, newCancelDelay);\n }\n}\n\n// contracts/FastBridgeV2.sol\n\n/// @notice FastBridgeV2 is a contract for bridging tokens across chains.\ncontract FastBridgeV2 is AdminV2, MulticallTarget, IFastBridgeV2, IFastBridgeV2Errors {\n using BridgeTransactionV2Lib for bytes;\n using SafeERC20 for IERC20;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n /// @notice Maximum length of accepted zapData\n uint256 public constant MAX_ZAP_DATA_LENGTH = 2 ** 16 - 1;\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeTxDetails) public bridgeTxDetails;\n /// @notice Relay details on destination chain\n mapping(bytes32 =\u003e BridgeRelay) public bridgeRelayDetails;\n /// @notice Unique bridge nonces tracked per originSender\n mapping(address =\u003e uint256) public senderNonces;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Replaced by senderNonces\n uint256 public immutable nonce = 0;\n /// @notice the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) AdminV2(_owner) {\n deployBlock = block.number;\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n bridge({\n params: params,\n paramsV2: BridgeParamsV2({\n quoteRelayer: address(0),\n quoteExclusivitySeconds: 0,\n quoteId: bytes(\"\"),\n zapNative: 0,\n zapData: bytes(\"\")\n })\n });\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes calldata request) external payable {\n // relay override will validate the request\n relay({request: request, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes calldata request, bytes32 destTxHash) external {\n request.validateV2();\n prove({transactionId: keccak256(request), destTxHash: destTxHash, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridgeV2\n function claim(bytes calldata request) external {\n // claim override will validate the request\n claim({request: request, to: address(0)});\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Aggregate the read operations from the same storage slot\n address disputedRelayer = $.proofRelayer;\n BridgeStatus status = $.status;\n uint56 proofBlockTimestamp = $.proofBlockTimestamp;\n // Can only dispute a RELAYER_PROVED transaction within the dispute period\n if (status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(proofBlockTimestamp) \u003e DISPUTE_PERIOD) {\n revert DisputePeriodPassed();\n }\n // Update status to REQUESTED and delete the disputed proof details\n // Note: these are storage writes\n $.status = BridgeStatus.REQUESTED;\n $.proofRelayer = address(0);\n $.proofBlockTimestamp = 0;\n\n emit BridgeProofDisputed(transactionId, disputedRelayer);\n }\n\n /// Note: this function is deprecated and will be removed in a future version.\n /// @inheritdoc IFastBridge\n function refund(bytes calldata request) external {\n cancel(request);\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // The correct relayer can only claim a RELAYER_PROVED transaction after the dispute period\n if ($.status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if ($.proofRelayer != relayer) revert SenderIncorrect();\n return _timeSince($.proofBlockTimestamp) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n /// @dev This method is added to achieve backwards compatibility with decoding requests into V1 structs:\n /// - `zapNative` is partially reported as a zero/non-zero flag\n /// - `zapData` is ignored\n /// In order to process all kinds of requests use getBridgeTransactionV2 instead.\n function getBridgeTransaction(bytes calldata request) external view returns (BridgeTransaction memory) {\n // Try decoding into V2 struct first. This will revert if V1 struct is passed\n try this.getBridgeTransactionV2(request) returns (BridgeTransactionV2 memory txV2) {\n // Note: we entirely ignore the zapData field, as it was not present in V1\n return BridgeTransaction({\n originChainId: txV2.originChainId,\n destChainId: txV2.destChainId,\n originSender: txV2.originSender,\n destRecipient: txV2.destRecipient,\n originToken: txV2.originToken,\n destToken: txV2.destToken,\n originAmount: txV2.originAmount,\n destAmount: txV2.destAmount,\n originFeeAmount: txV2.originFeeAmount,\n sendChainGas: txV2.zapNative != 0,\n deadline: txV2.deadline,\n nonce: txV2.nonce\n });\n } catch {\n // Fallback to V1 struct\n return abi.decode(request, (BridgeTransaction));\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function getBridgeTransactionV2(bytes calldata request) external pure returns (BridgeTransactionV2 memory) {\n request.validateV2();\n return BridgeTransactionV2Lib.decodeV2(request);\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) public payable {\n int256 exclusivityEndTime = 0;\n // if relayer exclusivity is not intended for this bridge, set exclusivityEndTime to static zero\n // otherwise, set exclusivity to expire at the current block ts offset by quoteExclusivitySeconds\n if (paramsV2.quoteRelayer != address(0)) {\n exclusivityEndTime = int256(block.timestamp) + paramsV2.quoteExclusivitySeconds;\n }\n _validateBridgeParams(params, paramsV2, exclusivityEndTime);\n\n // transfer tokens to bridge contract\n /// @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _takeBridgedUserAsset(params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) {\n originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n }\n\n // set status to requested\n bytes memory request = BridgeTransactionV2Lib.encodeV2(\n BridgeTransactionV2({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n deadline: params.deadline,\n nonce: senderNonces[params.sender]++, // increment nonce on every bridge\n exclusivityRelayer: paramsV2.quoteRelayer,\n // We checked exclusivityEndTime to be in range [0 .. params.deadline] above, so can safely cast\n exclusivityEndTime: uint256(exclusivityEndTime),\n zapNative: paramsV2.zapNative,\n zapData: paramsV2.zapData\n })\n );\n bytes32 transactionId = keccak256(request);\n // Note: the tx status will be updated throughout the tx lifecycle, while destChainId is set once here\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n bridgeTxDetails[transactionId].destChainId = params.dstChainId;\n\n emit BridgeRequested({\n transactionId: transactionId,\n sender: params.sender,\n request: request,\n destChainId: params.dstChainId,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n sendChainGas: paramsV2.zapNative != 0\n });\n emit BridgeQuoteDetails(transactionId, paramsV2.quoteId);\n }\n\n /// @inheritdoc IFastBridgeV2\n function relay(bytes calldata request, address relayer) public payable {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n _validateRelayParams(request, transactionId, relayer);\n // mark bridge transaction as relayed\n bridgeRelayDetails[transactionId] =\n BridgeRelay({blockNumber: uint48(block.number), blockTimestamp: uint48(block.timestamp), relayer: relayer});\n\n // transfer tokens to recipient on destination chain and trigger Zap if requested\n address to = request.destRecipient();\n address token = request.destToken();\n uint256 amount = request.destAmount();\n uint256 zapNative = request.zapNative();\n\n // Emit the event before any external calls\n emit BridgeRelayed({\n transactionId: transactionId,\n relayer: relayer,\n to: to,\n originChainId: request.originChainId(),\n originToken: request.originToken(),\n destToken: token,\n originAmount: request.originAmount(),\n destAmount: amount,\n chainGasAmount: zapNative\n });\n\n // All state changes have been done at this point, can proceed to the external calls.\n // This follows the checks-effects-interactions pattern to mitigate potential reentrancy attacks.\n if (token == NATIVE_GAS_TOKEN) {\n // For the native gas token, additional zapNative is not allowed\n if (zapNative != 0) revert ZapNativeNotSupported();\n // Check that the correct msg.value was sent\n if (msg.value != amount) revert MsgValueIncorrect();\n // Don't do a native transfer yet: we will handle it alongside the Zap below\n } else {\n // For ERC20s, we check that the correct msg.value was sent\n if (msg.value != zapNative) revert MsgValueIncorrect();\n // We need to transfer the tokens from the Relayer to the recipient first before performing an\n // optional post-transfer Zap.\n IERC20(token).safeTransferFrom(msg.sender, to, amount);\n }\n // At this point we have done:\n // - Transferred the requested amount of ERC20 tokens to the recipient.\n // At this point we have confirmed:\n // - For ERC20s: msg.value matches the requested zapNative amount.\n // - For the native gas token: msg.value matches the requested destAmount.\n // Remaining optional things to do:\n // - Forward the full msg.value to the recipient (if non-zero).\n // - Trigger a Zap (if zapData is present).\n bytes calldata zapData = request.zapData();\n if (zapData.length != 0) {\n // Zap Data is present: Zap has been requested by the recipient. Trigger it forwarding the full msg.value.\n\n // Note: if token has a fee on transfers, the recipient will have received less than `amount`.\n // This is a very niche edge case and should be handled by the recipient contract.\n _triggerZapWithChecks({recipient: to, token: token, amount: amount, zapData: zapData});\n } else if (msg.value != 0) {\n // Zap Data is missing, but msg.value was sent. This could happen in two different cases:\n // - Relay with the native gas token is happening.\n // - Relay with ERC20 is happening, with a `zapNative \u003e 0` request.\n // In both cases, we need to transfer the full msg.value to the recipient.\n Address.sendValue(payable(to), msg.value);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) public onlyRole(PROVER_ROLE) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n\n // Can only prove a REQUESTED transaction\n if ($.status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n // Update status to RELAYER_PROVED and store the proof details\n // Note: these are storage writes\n $.status = BridgeStatus.RELAYER_PROVED;\n $.proofBlockTimestamp = uint56(block.timestamp);\n $.proofRelayer = relayer;\n\n emit BridgeProofProvided(transactionId, relayer, destTxHash);\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes calldata request, address to) public {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Aggregate the read operations from the same storage slot\n address proofRelayer = $.proofRelayer;\n BridgeStatus status = $.status;\n uint56 proofBlockTimestamp = $.proofBlockTimestamp;\n\n // Can only claim a RELAYER_PROVED transaction after the dispute period\n if (status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(proofBlockTimestamp) \u003c= DISPUTE_PERIOD) {\n revert DisputePeriodNotPassed();\n }\n\n if (to == address(0)) {\n // Anyone could claim the funds to the proven relayer on their behalf\n to = proofRelayer;\n } else if (proofRelayer != msg.sender) {\n // Only the proven relayer could specify an address to claim the funds to\n revert SenderIncorrect();\n }\n\n // Update status to RELAYER_CLAIMED and transfer the origin collateral to the specified claim address\n // Note: this is a storage write\n $.status = BridgeStatus.RELAYER_CLAIMED;\n\n address token = request.originToken();\n uint256 amount = request.originAmount();\n // Update protocol fees if origin fee amount exists\n uint256 originFeeAmount = request.originFeeAmount();\n if (originFeeAmount \u003e 0) protocolFees[token] += originFeeAmount;\n // Emit the event before any external calls\n emit BridgeDepositClaimed(transactionId, proofRelayer, to, token, amount);\n // Complete the relayer claim as the last transaction action\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(to), amount);\n } else {\n IERC20(token).safeTransfer(to, amount);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function cancel(bytes calldata request) public {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Can only cancel a REQUESTED transaction after its deadline expires\n if ($.status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n uint256 deadline = request.deadline();\n // Permissionless cancel is only allowed after `cancelDelay` on top of the deadline\n if (!hasRole(CANCELER_ROLE, msg.sender)) deadline += cancelDelay;\n if (block.timestamp \u003c= deadline) revert DeadlineNotExceeded();\n // Update status to REFUNDED and return the full amount (collateral + protocol fees) to the original sender.\n // The protocol fees are only updated when the transaction is claimed, so we don't need to update them here.\n // Note: this is a storage write\n $.status = BridgeStatus.REFUNDED;\n\n address to = request.originSender();\n address token = request.originToken();\n uint256 amount = request.originAmount() + request.originFeeAmount();\n // Emit the event before any external calls\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n // Complete the user cancel as the last transaction action\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(to), amount);\n } else {\n IERC20(token).safeTransfer(to, amount);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeStatuses(bytes32 transactionId) public view returns (BridgeStatus status) {\n return bridgeTxDetails[transactionId].status;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeProofs(bytes32 transactionId) public view returns (uint96 timestamp, address relayer) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n\n timestamp = $.proofBlockTimestamp;\n relayer = $.proofRelayer;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeRelays(bytes32 transactionId) public view returns (bool) {\n // has this transactionId been relayed?\n return bridgeRelayDetails[transactionId].relayer != address(0);\n }\n\n /// @notice Takes the bridged asset from the user into FastBridgeV2 custody. It will be later\n /// claimed by the relayer who completed the relay on destination chain, or transferred back to the user\n /// via the cancel function should no one complete the relay.\n function _takeBridgedUserAsset(address token, uint256 amount) internal returns (uint256 amountTaken) {\n if (token == NATIVE_GAS_TOKEN) {\n // For the native gas token, we just need to check that the supplied msg.value is correct.\n // Supplied `msg.value` is already in FastBridgeV2 custody.\n if (amount != msg.value) revert MsgValueIncorrect();\n amountTaken = msg.value;\n } else {\n // For ERC20s, token is explicitly transferred from the user to FastBridgeV2.\n // We don't allow non-zero `msg.value` to avoid extra funds from being stuck in FastBridgeV2.\n if (msg.value != 0) revert MsgValueIncorrect();\n // Throw an explicit error if the provided token address is not a contract\n if (token.code.length == 0) revert TokenNotContract();\n amountTaken = IERC20(token).balanceOf(address(this));\n IERC20(token).safeTransferFrom(msg.sender, address(this), amount);\n // Use the balance difference as the amount taken in case of fee on transfer tokens.\n amountTaken = IERC20(token).balanceOf(address(this)) - amountTaken;\n }\n }\n\n /// @notice Calls the Recipient's hook function with the specified zapData and performs\n /// all the necessary checks for the returned value.\n function _triggerZapWithChecks(address recipient, address token, uint256 amount, bytes calldata zapData) internal {\n // This will bubble any revert messages from the hook function\n bytes memory returnData = Address.functionCallWithValue({\n target: recipient,\n data: abi.encodeCall(IZapRecipient.zap, (token, amount, zapData)),\n // Note: see `relay()` for reasoning behind passing msg.value\n value: msg.value\n });\n // Explicit revert if no return data at all\n if (returnData.length == 0) revert RecipientNoReturnValue();\n // Check that exactly a single return value was returned\n if (returnData.length != 32) revert RecipientIncorrectReturnValue();\n // Return value should be abi-encoded hook function selector\n if (bytes32(returnData) != bytes32(IZapRecipient.zap.selector)) {\n revert RecipientIncorrectReturnValue();\n }\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint56(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint56).max but\n /// proof.timestamp \u003c type(uint56).max via unchecked statement\n /// @param proofBlockTimestamp The bridge proof block timestamp\n /// @return delta Time delta since proof submitted\n function _timeSince(uint56 proofBlockTimestamp) internal view returns (uint256 delta) {\n unchecked {\n delta = uint56(block.timestamp) - proofBlockTimestamp;\n }\n }\n\n /// @notice Performs all the necessary checks for a bridge to happen.\n /// @dev There's no good way to refactor this function to reduce cyclomatic complexity due to\n /// the number of checks that need to be performed, so we skip the code-complexity rule here.\n // solhint-disable-next-line code-complexity\n function _validateBridgeParams(\n BridgeParams memory params,\n BridgeParamsV2 memory paramsV2,\n int256 exclusivityEndTime\n )\n internal\n view\n {\n // Check V1 (legacy) params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.sender == address(0) || params.to == address(0)) revert ZeroAddress();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n // Check V2 params\n if (paramsV2.zapData.length \u003e MAX_ZAP_DATA_LENGTH) revert ZapDataLengthAboveMax();\n if (paramsV2.zapNative != 0 \u0026\u0026 params.destToken == NATIVE_GAS_TOKEN) {\n revert ZapNativeNotSupported();\n }\n // exclusivityEndTime must be in range [0 .. params.deadline]\n if (exclusivityEndTime \u003c 0 || exclusivityEndTime \u003e int256(params.deadline)) {\n revert ExclusivityParamsIncorrect();\n }\n }\n\n /// @notice Performs all the necessary checks for a relay to happen.\n function _validateRelayParams(bytes calldata request, bytes32 transactionId, address relayer) internal view {\n if (relayer == address(0)) revert ZeroAddress();\n // Check if the transaction has already been relayed\n if (bridgeRelays(transactionId)) revert TransactionRelayed();\n if (request.destChainId() != block.chainid) revert ChainIncorrect();\n // Check the deadline for relay to happen\n if (block.timestamp \u003e request.deadline()) revert DeadlineExceeded();\n // Check the exclusivity period, if it is still ongoing\n address exclRelayer = request.exclusivityRelayer();\n if (exclRelayer != address(0) \u0026\u0026 exclRelayer != relayer \u0026\u0026 block.timestamp \u003c= request.exclusivityEndTime()) {\n revert ExclusivityPeriodNotPassed();\n }\n }\n}\n","language":"Solidity","languageVersion":"0.8.24","compilerVersion":"0.8.24","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"","srcMapRuntime":"","abiDefinition":[],"userDoc":{"kind":"user","methods":{},"version":1},"developerDoc":{"details":"Provides information about the current execution context, including the sender of the transaction and its data. While these are generally available via msg.sender and msg.data, they should not be accessed in such a direct manner, since when dealing with meta-transactions the account sending and paying for execution may not be the actual sender (as far as an application is concerned). This contract is only required for intermediate, library-like contracts.","kind":"dev","methods":{},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[],\"devdoc\":{\"details\":\"Provides information about the current execution context, including the sender of the transaction and its data. While these are generally available via msg.sender and msg.data, they should not be accessed in such a direct manner, since when dealing with meta-transactions the account sending and paying for execution may not be the actual sender (as far as an application is concerned). This contract is only required for intermediate, library-like contracts.\",\"kind\":\"dev\",\"methods\":{},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeV2.sol\":\"Context\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeV2.sol\":{\"keccak256\":\"0xac79c463688a682ca706a4ef95e7817b83548cdfa8182ba0426ac7e5e07613d8\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://b3ecb7097381287cafc3a73f3a2bb03565115ebb682a85064e0b0dc2f7e2919d\",\"dweb:/ipfs/QmatruW3nYZTksf3CeQ8wwiAG4c7xoEJBEp6drHPtFLBRK\"]}},\"version\":1}"},"hashes":{}},"solidity/FastBridgeV2.sol:ERC165":{"code":"0x","runtime-code":"0x","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.24 ^0.8.20 ^0.8.4;\n\n// contracts/interfaces/IAdminV2.sol\n\ninterface IAdminV2 {\n event CancelDelayUpdated(uint256 oldCancelDelay, uint256 newCancelDelay);\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n function setCancelDelay(uint256 newCancelDelay) external;\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n}\n\n// contracts/interfaces/IAdminV2Errors.sol\n\ninterface IAdminV2Errors {\n error CancelDelayBelowMin();\n error FeeRateAboveMax();\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IFastBridgeV2Errors.sol\n\ninterface IFastBridgeV2Errors {\n error AmountIncorrect();\n error ChainIncorrect();\n error ExclusivityParamsIncorrect();\n error MsgValueIncorrect();\n error SenderIncorrect();\n error StatusIncorrect();\n error TokenNotContract();\n error ZapDataLengthAboveMax();\n error ZapNativeNotSupported();\n error ZeroAddress();\n\n error RecipientIncorrectReturnValue();\n error RecipientNoReturnValue();\n\n error DeadlineExceeded();\n error DeadlineNotExceeded();\n error DeadlineTooShort();\n error DisputePeriodNotPassed();\n error DisputePeriodPassed();\n error ExclusivityPeriodNotPassed();\n\n error TransactionRelayed();\n}\n\n// contracts/interfaces/IMulticallTarget.sol\n\n/// @notice Interface for a contract that can be called multiple times by the same caller. Inspired by MulticallV3:\n/// https://github.com/mds1/multicall/blob/master/src/Multicall3.sol\ninterface IMulticallTarget {\n struct Result {\n bool success;\n bytes returnData;\n }\n\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external;\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results);\n}\n\n// contracts/interfaces/IZapRecipient.sol\n\ninterface IZapRecipient {\n function zap(address token, uint256 amount, bytes memory zapData) external payable returns (bytes4);\n}\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// contracts/interfaces/IFastBridgeV2.sol\n\ninterface IFastBridgeV2 is IFastBridge {\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n struct BridgeTxDetails {\n BridgeStatus status;\n uint32 destChainId;\n uint56 proofBlockTimestamp;\n address proofRelayer;\n }\n\n struct BridgeRelay {\n uint48 blockNumber;\n uint48 blockTimestamp;\n address relayer;\n }\n\n /// @notice New params introduced in the FastBridgeV2.\n /// We are passing fields from the older BridgeParams struct outside of this struct\n /// for backwards compatibility.\n /// Note: quoteRelayer and quoteExclusivitySeconds are either both zero (indicating no exclusivity)\n /// or both non-zero (indicating exclusivity for the given period).\n /// Note: zapNative \u003e 0 can NOT be used with destToken = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE (native token)\n /// @param quoteRelayer Relayer that provided the quote for the transaction\n /// @param quoteExclusivitySeconds Period of time the quote relayer is guaranteed exclusivity after user's deposit\n /// @param quoteId Unique quote identifier used for tracking the quote\n /// @param zapNative ETH value to send to the recipient (if any)\n /// @param zapData Parameters for the Zap to the destination recipient (if any)\n struct BridgeParamsV2 {\n address quoteRelayer;\n int256 quoteExclusivitySeconds;\n bytes quoteId;\n uint256 zapNative;\n bytes zapData;\n }\n\n /// @notice Updated bridge transaction struct to include parameters introduced in FastBridgeV2.\n /// Note: only `exclusivityRelayer` can fill such a transaction until `exclusivityEndTime`.\n struct BridgeTransactionV2 {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n // Note: sendChainGas flag from V1 is deprecated\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n address exclusivityRelayer;\n uint256 exclusivityEndTime;\n uint256 zapNative; // ETH value to send to the recipient (if any)\n bytes zapData; // data to pass for the Zap action (if any)\n }\n\n event BridgeQuoteDetails(bytes32 indexed transactionId, bytes quoteId);\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability\n /// to provide temporary exclusivity fill rights for the quote relayer.\n /// @param params The parameters required to bridge\n /// @param paramsV2 The parameters for exclusivity fill rights (optional, can be left empty)\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function relay(bytes memory request, address relayer) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param transactionId The transaction id associated with the encoded bridge transaction to prove\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital.\n /// @notice Can only send funds to the relayer address on the proof.\n /// @param request The encoded bridge transaction to claim on origin chain\n function claim(bytes memory request) external;\n\n /// @notice Cancels an outstanding bridge transaction in case optimistic bridging failed and returns the full amount\n /// to the original sender.\n /// @param request The encoded bridge transaction to refund\n function cancel(bytes memory request) external;\n\n /// @notice Checks if a transaction has been relayed\n /// @param transactionId The ID of the transaction to check\n /// @return True if the transaction has been relayed, false otherwise\n function bridgeRelays(bytes32 transactionId) external view returns (bool);\n\n /// @notice Returns the status of a bridge transaction\n /// @param transactionId The ID of the bridge transaction\n /// @return BridgeStatus Status of the bridge transaction\n function bridgeStatuses(bytes32 transactionId) external view returns (BridgeStatus);\n\n /// @notice Returns the timestamp and relayer of a bridge proof\n /// @param transactionId The ID of the bridge transaction\n /// @return timestamp The timestamp of the bridge proof\n /// @return relayer The relayer address of the bridge proof\n function bridgeProofs(bytes32 transactionId) external view returns (uint96 timestamp, address relayer);\n\n /// @notice Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\n /// @param request The bridge request to decode\n function getBridgeTransactionV2(bytes memory request) external view returns (BridgeTransactionV2 memory);\n}\n\n// contracts/utils/MulticallTarget.sol\n\n// solhint-disable avoid-low-level-calls\n/// @notice Template for a contract that supports batched calls (preserving the msg.sender).\n/// Only calls with zero msg.value could be batched.\nabstract contract MulticallTarget is IMulticallTarget {\n error MulticallTarget__UndeterminedRevert();\n\n /// @notice Perform a batched call to this contract, preserving the msg.sender.\n /// The return data from each call is discarded.\n /// @dev The method is non-payable, so only calls with `msg.value == 0` could be batched.\n /// It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag.\n /// Otherwise, the whole batch call will be reverted with the original revert reason.\n /// @param data List of abi-encoded calldata for the calls to perform.\n /// @param ignoreReverts Whether to ignore the revert errors from the calls.\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external {\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\n if (!success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(result);\n }\n }\n }\n\n /// @notice Perform a batched call to this contract, preserving the msg.sender.\n /// The return data from each call is preserved.\n /// @dev The method is non-payable, so only calls with `msg.value == 0` could be batched.\n /// It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag.\n /// Otherwise, the whole batch call will be reverted with the original revert reason.\n /// @param data List of abi-encoded calldata for the calls to perform.\n /// @param ignoreReverts Whether to ignore the revert errors from the calls.\n /// @return results List of results from the calls: `(success, returnData)`.\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results)\n {\n results = new Result[](data.length);\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (results[i].success, results[i].returnData) = address(this).delegatecall(data[i]);\n if (!results[i].success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(results[i].returnData);\n }\n }\n }\n\n /// @dev Bubbles the revert message from the underlying call.\n /// Note: preserves the same custom error or revert string, if one was used.\n /// Source: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v5.0.2/contracts/utils/Address.sol#L143-L158\n function _bubbleRevert(bytes memory returnData) internal pure {\n // Look for revert reason and bubble it up if present\n if (returnData.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n // solhint-disable-next-line no-inline-assembly\n assembly {\n let returndata_size := mload(returnData)\n revert(add(32, returnData), returndata_size)\n }\n } else {\n revert MulticallTarget__UndeterminedRevert();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// contracts/libs/BridgeTransactionV2.sol\n\n// solhint-disable no-inline-assembly\nlibrary BridgeTransactionV2Lib {\n uint16 internal constant VERSION = 2;\n\n // Offsets of the fields in the packed BridgeTransactionV2 struct\n // uint16 version [000 .. 002)\n // uint32 originChainId [002 .. 006)\n // uint32 destChainId [006 .. 010)\n // address originSender [010 .. 030)\n // address destRecipient [030 .. 050)\n // address originToken [050 .. 070)\n // address destToken [070 .. 090)\n // uint256 originAmount [090 .. 122)\n // uint256 destAmount [122 .. 154)\n // uint256 originFeeAmount [154 .. 186)\n // uint256 deadline [186 .. 218)\n // uint256 nonce [218 .. 250)\n // address exclusivityRelayer [250 .. 270)\n // uint256 exclusivityEndTime [270 .. 302)\n // uint256 zapNative [302 .. 334)\n // bytes zapData [334 .. ***)\n\n // forgefmt: disable-start\n uint256 private constant OFFSET_ORIGIN_CHAIN_ID = 2;\n uint256 private constant OFFSET_DEST_CHAIN_ID = 6;\n uint256 private constant OFFSET_ORIGIN_SENDER = 10;\n uint256 private constant OFFSET_DEST_RECIPIENT = 30;\n uint256 private constant OFFSET_ORIGIN_TOKEN = 50;\n uint256 private constant OFFSET_DEST_TOKEN = 70;\n uint256 private constant OFFSET_ORIGIN_AMOUNT = 90;\n uint256 private constant OFFSET_DEST_AMOUNT = 122;\n uint256 private constant OFFSET_ORIGIN_FEE_AMOUNT = 154;\n uint256 private constant OFFSET_DEADLINE = 186;\n uint256 private constant OFFSET_NONCE = 218;\n uint256 private constant OFFSET_EXCLUSIVITY_RELAYER = 250;\n uint256 private constant OFFSET_EXCLUSIVITY_END_TIME = 270;\n uint256 private constant OFFSET_ZAP_NATIVE = 302;\n uint256 private constant OFFSET_ZAP_DATA = 334;\n // forgefmt: disable-end\n\n error BridgeTransactionV2__InvalidEncodedTx();\n error BridgeTransactionV2__UnsupportedVersion(uint16 version);\n\n /// @notice Validates the encoded transaction to be a tightly packed encoded payload for BridgeTransactionV2.\n /// @dev Checks the minimum length and the version, use this function before decoding any of the fields.\n function validateV2(bytes calldata encodedTx) internal pure {\n // Check the minimum length: must at least include all static fields.\n if (encodedTx.length \u003c OFFSET_ZAP_DATA) revert BridgeTransactionV2__InvalidEncodedTx();\n // Once we validated the length, we can be sure that the version field is present.\n uint16 version_ = version(encodedTx);\n if (version_ != VERSION) revert BridgeTransactionV2__UnsupportedVersion(version_);\n }\n\n /// @notice Encodes the BridgeTransactionV2 struct by tightly packing the fields.\n /// @dev `abi.decode` will not work as a result of the tightly packed fields. Use `decodeV2` to decode instead.\n function encodeV2(IFastBridgeV2.BridgeTransactionV2 memory bridgeTx) internal pure returns (bytes memory) {\n // We split the encoding into two parts to avoid stack-too-deep error\n bytes memory firstPart = abi.encodePacked(\n VERSION,\n bridgeTx.originChainId,\n bridgeTx.destChainId,\n bridgeTx.originSender,\n bridgeTx.destRecipient,\n bridgeTx.originToken,\n bridgeTx.destToken,\n bridgeTx.originAmount\n );\n return abi.encodePacked(\n firstPart,\n bridgeTx.destAmount,\n bridgeTx.originFeeAmount,\n // Note: we skip the deprecated `sendChainGas` flag, which was present in BridgeTransaction V1\n bridgeTx.deadline,\n bridgeTx.nonce,\n // New V2 fields: exclusivity\n bridgeTx.exclusivityRelayer,\n bridgeTx.exclusivityEndTime,\n // New V2 fields: Zap\n bridgeTx.zapNative,\n bridgeTx.zapData\n );\n }\n\n /// @notice Decodes the BridgeTransactionV2 struct from the encoded transaction.\n /// @dev Encoded BridgeTransactionV2 struct must be tightly packed.\n /// Use `validateV2` before decoding to ensure the encoded transaction is valid.\n function decodeV2(bytes calldata encodedTx)\n internal\n pure\n returns (IFastBridgeV2.BridgeTransactionV2 memory bridgeTx)\n {\n bridgeTx.originChainId = originChainId(encodedTx);\n bridgeTx.destChainId = destChainId(encodedTx);\n bridgeTx.originSender = originSender(encodedTx);\n bridgeTx.destRecipient = destRecipient(encodedTx);\n bridgeTx.originToken = originToken(encodedTx);\n bridgeTx.destToken = destToken(encodedTx);\n bridgeTx.originAmount = originAmount(encodedTx);\n bridgeTx.destAmount = destAmount(encodedTx);\n bridgeTx.originFeeAmount = originFeeAmount(encodedTx);\n bridgeTx.deadline = deadline(encodedTx);\n bridgeTx.nonce = nonce(encodedTx);\n bridgeTx.exclusivityRelayer = exclusivityRelayer(encodedTx);\n bridgeTx.exclusivityEndTime = exclusivityEndTime(encodedTx);\n bridgeTx.zapNative = zapNative(encodedTx);\n bridgeTx.zapData = zapData(encodedTx);\n }\n\n /// @notice Extracts the version from the encoded transaction.\n function version(bytes calldata encodedTx) internal pure returns (uint16 version_) {\n // Load 32 bytes from the start and shift it 240 bits to the right to get the highest 16 bits.\n assembly {\n version_ := shr(240, calldataload(encodedTx.offset))\n }\n }\n\n /// @notice Extracts the origin chain ID from the encoded transaction.\n function originChainId(bytes calldata encodedTx) internal pure returns (uint32 originChainId_) {\n // Load 32 bytes from the offset and shift it 224 bits to the right to get the highest 32 bits.\n assembly {\n originChainId_ := shr(224, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_CHAIN_ID)))\n }\n }\n\n /// @notice Extracts the destination chain ID from the encoded transaction.\n function destChainId(bytes calldata encodedTx) internal pure returns (uint32 destChainId_) {\n // Load 32 bytes from the offset and shift it 224 bits to the right to get the highest 32 bits.\n assembly {\n destChainId_ := shr(224, calldataload(add(encodedTx.offset, OFFSET_DEST_CHAIN_ID)))\n }\n }\n\n /// @notice Extracts the origin sender from the encoded transaction.\n function originSender(bytes calldata encodedTx) internal pure returns (address originSender_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n originSender_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_SENDER)))\n }\n }\n\n /// @notice Extracts the destination recipient from the encoded transaction.\n function destRecipient(bytes calldata encodedTx) internal pure returns (address destRecipient_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n destRecipient_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_DEST_RECIPIENT)))\n }\n }\n\n /// @notice Extracts the origin token from the encoded transaction.\n function originToken(bytes calldata encodedTx) internal pure returns (address originToken_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n originToken_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_TOKEN)))\n }\n }\n\n /// @notice Extracts the destination token from the encoded transaction.\n function destToken(bytes calldata encodedTx) internal pure returns (address destToken_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n destToken_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_DEST_TOKEN)))\n }\n }\n\n /// @notice Extracts the origin amount from the encoded transaction.\n function originAmount(bytes calldata encodedTx) internal pure returns (uint256 originAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n originAmount_ := calldataload(add(encodedTx.offset, OFFSET_ORIGIN_AMOUNT))\n }\n }\n\n /// @notice Extracts the destination amount from the encoded transaction.\n function destAmount(bytes calldata encodedTx) internal pure returns (uint256 destAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n destAmount_ := calldataload(add(encodedTx.offset, OFFSET_DEST_AMOUNT))\n }\n }\n\n /// @notice Extracts the origin fee amount from the encoded transaction.\n function originFeeAmount(bytes calldata encodedTx) internal pure returns (uint256 originFeeAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n originFeeAmount_ := calldataload(add(encodedTx.offset, OFFSET_ORIGIN_FEE_AMOUNT))\n }\n }\n\n /// @notice Extracts the deadline from the encoded transaction.\n function deadline(bytes calldata encodedTx) internal pure returns (uint256 deadline_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n deadline_ := calldataload(add(encodedTx.offset, OFFSET_DEADLINE))\n }\n }\n\n /// @notice Extracts the nonce from the encoded transaction.\n function nonce(bytes calldata encodedTx) internal pure returns (uint256 nonce_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n nonce_ := calldataload(add(encodedTx.offset, OFFSET_NONCE))\n }\n }\n\n /// @notice Extracts the exclusivity relayer from the encoded transaction.\n function exclusivityRelayer(bytes calldata encodedTx) internal pure returns (address exclusivityRelayer_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n exclusivityRelayer_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_EXCLUSIVITY_RELAYER)))\n }\n }\n\n /// @notice Extracts the exclusivity end time from the encoded transaction.\n function exclusivityEndTime(bytes calldata encodedTx) internal pure returns (uint256 exclusivityEndTime_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n exclusivityEndTime_ := calldataload(add(encodedTx.offset, OFFSET_EXCLUSIVITY_END_TIME))\n }\n }\n\n /// @notice Extracts the Zap's native value from the encoded transaction.\n function zapNative(bytes calldata encodedTx) internal pure returns (uint256 zapNative_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n zapNative_ := calldataload(add(encodedTx.offset, OFFSET_ZAP_NATIVE))\n }\n }\n\n /// @notice Extracts the Zap's data from the encoded transaction.\n function zapData(bytes calldata encodedTx) internal pure returns (bytes calldata zapData_) {\n zapData_ = encodedTx[OFFSET_ZAP_DATA:];\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/AdminV2.sol\n\ncontract AdminV2 is AccessControlEnumerable, IAdminV2, IAdminV2Errors {\n using SafeERC20 for IERC20;\n\n /// @notice Address reserved for native gas token (ETH on Ethereum and most L2s, AVAX on Avalanche, etc)\n address public constant NATIVE_GAS_TOKEN = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Role identifier for Quoter API's off-chain authentication.\n /// @dev Only addresses with this role can post FastBridge quotes to the API.\n bytes32 public constant QUOTER_ROLE = keccak256(\"QUOTER_ROLE\");\n\n /// @notice Role identifier for Prover's on-chain authentication in FastBridge.\n /// @dev Only addresses with this role can provide proofs that a FastBridge request has been relayed.\n bytes32 public constant PROVER_ROLE = keccak256(\"PROVER_ROLE\");\n\n /// @notice Role identifier for Guard's on-chain authentication in FastBridge.\n /// @dev Only addresses with this role can dispute submitted relay proofs during the dispute period.\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n\n /// @notice Role identifier for Canceler's on-chain authentication in FastBridge.\n /// @dev Only addresses with this role can cancel a FastBridge transaction without the cancel delay.\n bytes32 public constant CANCELER_ROLE = keccak256(\"CANCELER_ROLE\");\n\n /// @notice Role identifier for Governor's on-chain administrative authority.\n /// @dev Only addresses with this role can perform administrative tasks within the contract.\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n /// @notice Denominator for fee rates, represents 100%.\n uint256 public constant FEE_BPS = 1e6;\n /// @notice Maximum protocol fee rate: 1% on origin amount.\n uint256 public constant FEE_RATE_MAX = 0.01e6;\n\n /// @notice Minimum cancel delay that can be set by the governor.\n uint256 public constant MIN_CANCEL_DELAY = 1 hours;\n /// @notice Default cancel delay set during the contract deployment.\n uint256 public constant DEFAULT_CANCEL_DELAY = 1 days;\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Delay for a transaction after which it could be permisionlessly cancelled\n uint256 public cancelDelay;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Use ZapNative V2 requests instead.\n uint256 public immutable chainGasAmount = 0;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n _setCancelDelay(DEFAULT_CANCEL_DELAY);\n }\n\n /// @notice Allows the contract governor to set the cancel delay. The cancel delay is the time after the transaction\n /// deadline after which it can be permissionlessly cancelled, if it hasn't been proven by any of the Relayers.\n function setCancelDelay(uint256 newCancelDelay) external onlyRole(GOVERNOR_ROLE) {\n _setCancelDelay(newCancelDelay);\n }\n\n /// @notice Allows the contract governor to set the protocol fee rate. The protocol fee is taken from the origin\n /// amount only for completed and claimed transactions.\n /// @dev The protocol fee is abstracted away from the relayers, they always operate using the amounts after fees:\n /// what they see as the origin amount emitted in the log is what they get credited with.\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n if (newFeeRate \u003e FEE_RATE_MAX) revert FeeRateAboveMax();\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n /// @notice Allows the contract governor to sweep the accumulated protocol fees in the contract.\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n emit FeesSwept(token, recipient, feeAmount);\n /// Sweep the fees as the last transaction action\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(recipient), feeAmount);\n } else {\n IERC20(token).safeTransfer(recipient, feeAmount);\n }\n }\n\n /// @notice Internal function to set the cancel delay. Security checks are performed outside of this function.\n function _setCancelDelay(uint256 newCancelDelay) private {\n if (newCancelDelay \u003c MIN_CANCEL_DELAY) revert CancelDelayBelowMin();\n uint256 oldCancelDelay = cancelDelay;\n cancelDelay = newCancelDelay;\n emit CancelDelayUpdated(oldCancelDelay, newCancelDelay);\n }\n}\n\n// contracts/FastBridgeV2.sol\n\n/// @notice FastBridgeV2 is a contract for bridging tokens across chains.\ncontract FastBridgeV2 is AdminV2, MulticallTarget, IFastBridgeV2, IFastBridgeV2Errors {\n using BridgeTransactionV2Lib for bytes;\n using SafeERC20 for IERC20;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n /// @notice Maximum length of accepted zapData\n uint256 public constant MAX_ZAP_DATA_LENGTH = 2 ** 16 - 1;\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeTxDetails) public bridgeTxDetails;\n /// @notice Relay details on destination chain\n mapping(bytes32 =\u003e BridgeRelay) public bridgeRelayDetails;\n /// @notice Unique bridge nonces tracked per originSender\n mapping(address =\u003e uint256) public senderNonces;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Replaced by senderNonces\n uint256 public immutable nonce = 0;\n /// @notice the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) AdminV2(_owner) {\n deployBlock = block.number;\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n bridge({\n params: params,\n paramsV2: BridgeParamsV2({\n quoteRelayer: address(0),\n quoteExclusivitySeconds: 0,\n quoteId: bytes(\"\"),\n zapNative: 0,\n zapData: bytes(\"\")\n })\n });\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes calldata request) external payable {\n // relay override will validate the request\n relay({request: request, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes calldata request, bytes32 destTxHash) external {\n request.validateV2();\n prove({transactionId: keccak256(request), destTxHash: destTxHash, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridgeV2\n function claim(bytes calldata request) external {\n // claim override will validate the request\n claim({request: request, to: address(0)});\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Aggregate the read operations from the same storage slot\n address disputedRelayer = $.proofRelayer;\n BridgeStatus status = $.status;\n uint56 proofBlockTimestamp = $.proofBlockTimestamp;\n // Can only dispute a RELAYER_PROVED transaction within the dispute period\n if (status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(proofBlockTimestamp) \u003e DISPUTE_PERIOD) {\n revert DisputePeriodPassed();\n }\n // Update status to REQUESTED and delete the disputed proof details\n // Note: these are storage writes\n $.status = BridgeStatus.REQUESTED;\n $.proofRelayer = address(0);\n $.proofBlockTimestamp = 0;\n\n emit BridgeProofDisputed(transactionId, disputedRelayer);\n }\n\n /// Note: this function is deprecated and will be removed in a future version.\n /// @inheritdoc IFastBridge\n function refund(bytes calldata request) external {\n cancel(request);\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // The correct relayer can only claim a RELAYER_PROVED transaction after the dispute period\n if ($.status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if ($.proofRelayer != relayer) revert SenderIncorrect();\n return _timeSince($.proofBlockTimestamp) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n /// @dev This method is added to achieve backwards compatibility with decoding requests into V1 structs:\n /// - `zapNative` is partially reported as a zero/non-zero flag\n /// - `zapData` is ignored\n /// In order to process all kinds of requests use getBridgeTransactionV2 instead.\n function getBridgeTransaction(bytes calldata request) external view returns (BridgeTransaction memory) {\n // Try decoding into V2 struct first. This will revert if V1 struct is passed\n try this.getBridgeTransactionV2(request) returns (BridgeTransactionV2 memory txV2) {\n // Note: we entirely ignore the zapData field, as it was not present in V1\n return BridgeTransaction({\n originChainId: txV2.originChainId,\n destChainId: txV2.destChainId,\n originSender: txV2.originSender,\n destRecipient: txV2.destRecipient,\n originToken: txV2.originToken,\n destToken: txV2.destToken,\n originAmount: txV2.originAmount,\n destAmount: txV2.destAmount,\n originFeeAmount: txV2.originFeeAmount,\n sendChainGas: txV2.zapNative != 0,\n deadline: txV2.deadline,\n nonce: txV2.nonce\n });\n } catch {\n // Fallback to V1 struct\n return abi.decode(request, (BridgeTransaction));\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function getBridgeTransactionV2(bytes calldata request) external pure returns (BridgeTransactionV2 memory) {\n request.validateV2();\n return BridgeTransactionV2Lib.decodeV2(request);\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) public payable {\n int256 exclusivityEndTime = 0;\n // if relayer exclusivity is not intended for this bridge, set exclusivityEndTime to static zero\n // otherwise, set exclusivity to expire at the current block ts offset by quoteExclusivitySeconds\n if (paramsV2.quoteRelayer != address(0)) {\n exclusivityEndTime = int256(block.timestamp) + paramsV2.quoteExclusivitySeconds;\n }\n _validateBridgeParams(params, paramsV2, exclusivityEndTime);\n\n // transfer tokens to bridge contract\n /// @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _takeBridgedUserAsset(params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) {\n originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n }\n\n // set status to requested\n bytes memory request = BridgeTransactionV2Lib.encodeV2(\n BridgeTransactionV2({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n deadline: params.deadline,\n nonce: senderNonces[params.sender]++, // increment nonce on every bridge\n exclusivityRelayer: paramsV2.quoteRelayer,\n // We checked exclusivityEndTime to be in range [0 .. params.deadline] above, so can safely cast\n exclusivityEndTime: uint256(exclusivityEndTime),\n zapNative: paramsV2.zapNative,\n zapData: paramsV2.zapData\n })\n );\n bytes32 transactionId = keccak256(request);\n // Note: the tx status will be updated throughout the tx lifecycle, while destChainId is set once here\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n bridgeTxDetails[transactionId].destChainId = params.dstChainId;\n\n emit BridgeRequested({\n transactionId: transactionId,\n sender: params.sender,\n request: request,\n destChainId: params.dstChainId,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n sendChainGas: paramsV2.zapNative != 0\n });\n emit BridgeQuoteDetails(transactionId, paramsV2.quoteId);\n }\n\n /// @inheritdoc IFastBridgeV2\n function relay(bytes calldata request, address relayer) public payable {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n _validateRelayParams(request, transactionId, relayer);\n // mark bridge transaction as relayed\n bridgeRelayDetails[transactionId] =\n BridgeRelay({blockNumber: uint48(block.number), blockTimestamp: uint48(block.timestamp), relayer: relayer});\n\n // transfer tokens to recipient on destination chain and trigger Zap if requested\n address to = request.destRecipient();\n address token = request.destToken();\n uint256 amount = request.destAmount();\n uint256 zapNative = request.zapNative();\n\n // Emit the event before any external calls\n emit BridgeRelayed({\n transactionId: transactionId,\n relayer: relayer,\n to: to,\n originChainId: request.originChainId(),\n originToken: request.originToken(),\n destToken: token,\n originAmount: request.originAmount(),\n destAmount: amount,\n chainGasAmount: zapNative\n });\n\n // All state changes have been done at this point, can proceed to the external calls.\n // This follows the checks-effects-interactions pattern to mitigate potential reentrancy attacks.\n if (token == NATIVE_GAS_TOKEN) {\n // For the native gas token, additional zapNative is not allowed\n if (zapNative != 0) revert ZapNativeNotSupported();\n // Check that the correct msg.value was sent\n if (msg.value != amount) revert MsgValueIncorrect();\n // Don't do a native transfer yet: we will handle it alongside the Zap below\n } else {\n // For ERC20s, we check that the correct msg.value was sent\n if (msg.value != zapNative) revert MsgValueIncorrect();\n // We need to transfer the tokens from the Relayer to the recipient first before performing an\n // optional post-transfer Zap.\n IERC20(token).safeTransferFrom(msg.sender, to, amount);\n }\n // At this point we have done:\n // - Transferred the requested amount of ERC20 tokens to the recipient.\n // At this point we have confirmed:\n // - For ERC20s: msg.value matches the requested zapNative amount.\n // - For the native gas token: msg.value matches the requested destAmount.\n // Remaining optional things to do:\n // - Forward the full msg.value to the recipient (if non-zero).\n // - Trigger a Zap (if zapData is present).\n bytes calldata zapData = request.zapData();\n if (zapData.length != 0) {\n // Zap Data is present: Zap has been requested by the recipient. Trigger it forwarding the full msg.value.\n\n // Note: if token has a fee on transfers, the recipient will have received less than `amount`.\n // This is a very niche edge case and should be handled by the recipient contract.\n _triggerZapWithChecks({recipient: to, token: token, amount: amount, zapData: zapData});\n } else if (msg.value != 0) {\n // Zap Data is missing, but msg.value was sent. This could happen in two different cases:\n // - Relay with the native gas token is happening.\n // - Relay with ERC20 is happening, with a `zapNative \u003e 0` request.\n // In both cases, we need to transfer the full msg.value to the recipient.\n Address.sendValue(payable(to), msg.value);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) public onlyRole(PROVER_ROLE) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n\n // Can only prove a REQUESTED transaction\n if ($.status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n // Update status to RELAYER_PROVED and store the proof details\n // Note: these are storage writes\n $.status = BridgeStatus.RELAYER_PROVED;\n $.proofBlockTimestamp = uint56(block.timestamp);\n $.proofRelayer = relayer;\n\n emit BridgeProofProvided(transactionId, relayer, destTxHash);\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes calldata request, address to) public {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Aggregate the read operations from the same storage slot\n address proofRelayer = $.proofRelayer;\n BridgeStatus status = $.status;\n uint56 proofBlockTimestamp = $.proofBlockTimestamp;\n\n // Can only claim a RELAYER_PROVED transaction after the dispute period\n if (status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(proofBlockTimestamp) \u003c= DISPUTE_PERIOD) {\n revert DisputePeriodNotPassed();\n }\n\n if (to == address(0)) {\n // Anyone could claim the funds to the proven relayer on their behalf\n to = proofRelayer;\n } else if (proofRelayer != msg.sender) {\n // Only the proven relayer could specify an address to claim the funds to\n revert SenderIncorrect();\n }\n\n // Update status to RELAYER_CLAIMED and transfer the origin collateral to the specified claim address\n // Note: this is a storage write\n $.status = BridgeStatus.RELAYER_CLAIMED;\n\n address token = request.originToken();\n uint256 amount = request.originAmount();\n // Update protocol fees if origin fee amount exists\n uint256 originFeeAmount = request.originFeeAmount();\n if (originFeeAmount \u003e 0) protocolFees[token] += originFeeAmount;\n // Emit the event before any external calls\n emit BridgeDepositClaimed(transactionId, proofRelayer, to, token, amount);\n // Complete the relayer claim as the last transaction action\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(to), amount);\n } else {\n IERC20(token).safeTransfer(to, amount);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function cancel(bytes calldata request) public {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Can only cancel a REQUESTED transaction after its deadline expires\n if ($.status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n uint256 deadline = request.deadline();\n // Permissionless cancel is only allowed after `cancelDelay` on top of the deadline\n if (!hasRole(CANCELER_ROLE, msg.sender)) deadline += cancelDelay;\n if (block.timestamp \u003c= deadline) revert DeadlineNotExceeded();\n // Update status to REFUNDED and return the full amount (collateral + protocol fees) to the original sender.\n // The protocol fees are only updated when the transaction is claimed, so we don't need to update them here.\n // Note: this is a storage write\n $.status = BridgeStatus.REFUNDED;\n\n address to = request.originSender();\n address token = request.originToken();\n uint256 amount = request.originAmount() + request.originFeeAmount();\n // Emit the event before any external calls\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n // Complete the user cancel as the last transaction action\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(to), amount);\n } else {\n IERC20(token).safeTransfer(to, amount);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeStatuses(bytes32 transactionId) public view returns (BridgeStatus status) {\n return bridgeTxDetails[transactionId].status;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeProofs(bytes32 transactionId) public view returns (uint96 timestamp, address relayer) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n\n timestamp = $.proofBlockTimestamp;\n relayer = $.proofRelayer;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeRelays(bytes32 transactionId) public view returns (bool) {\n // has this transactionId been relayed?\n return bridgeRelayDetails[transactionId].relayer != address(0);\n }\n\n /// @notice Takes the bridged asset from the user into FastBridgeV2 custody. It will be later\n /// claimed by the relayer who completed the relay on destination chain, or transferred back to the user\n /// via the cancel function should no one complete the relay.\n function _takeBridgedUserAsset(address token, uint256 amount) internal returns (uint256 amountTaken) {\n if (token == NATIVE_GAS_TOKEN) {\n // For the native gas token, we just need to check that the supplied msg.value is correct.\n // Supplied `msg.value` is already in FastBridgeV2 custody.\n if (amount != msg.value) revert MsgValueIncorrect();\n amountTaken = msg.value;\n } else {\n // For ERC20s, token is explicitly transferred from the user to FastBridgeV2.\n // We don't allow non-zero `msg.value` to avoid extra funds from being stuck in FastBridgeV2.\n if (msg.value != 0) revert MsgValueIncorrect();\n // Throw an explicit error if the provided token address is not a contract\n if (token.code.length == 0) revert TokenNotContract();\n amountTaken = IERC20(token).balanceOf(address(this));\n IERC20(token).safeTransferFrom(msg.sender, address(this), amount);\n // Use the balance difference as the amount taken in case of fee on transfer tokens.\n amountTaken = IERC20(token).balanceOf(address(this)) - amountTaken;\n }\n }\n\n /// @notice Calls the Recipient's hook function with the specified zapData and performs\n /// all the necessary checks for the returned value.\n function _triggerZapWithChecks(address recipient, address token, uint256 amount, bytes calldata zapData) internal {\n // This will bubble any revert messages from the hook function\n bytes memory returnData = Address.functionCallWithValue({\n target: recipient,\n data: abi.encodeCall(IZapRecipient.zap, (token, amount, zapData)),\n // Note: see `relay()` for reasoning behind passing msg.value\n value: msg.value\n });\n // Explicit revert if no return data at all\n if (returnData.length == 0) revert RecipientNoReturnValue();\n // Check that exactly a single return value was returned\n if (returnData.length != 32) revert RecipientIncorrectReturnValue();\n // Return value should be abi-encoded hook function selector\n if (bytes32(returnData) != bytes32(IZapRecipient.zap.selector)) {\n revert RecipientIncorrectReturnValue();\n }\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint56(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint56).max but\n /// proof.timestamp \u003c type(uint56).max via unchecked statement\n /// @param proofBlockTimestamp The bridge proof block timestamp\n /// @return delta Time delta since proof submitted\n function _timeSince(uint56 proofBlockTimestamp) internal view returns (uint256 delta) {\n unchecked {\n delta = uint56(block.timestamp) - proofBlockTimestamp;\n }\n }\n\n /// @notice Performs all the necessary checks for a bridge to happen.\n /// @dev There's no good way to refactor this function to reduce cyclomatic complexity due to\n /// the number of checks that need to be performed, so we skip the code-complexity rule here.\n // solhint-disable-next-line code-complexity\n function _validateBridgeParams(\n BridgeParams memory params,\n BridgeParamsV2 memory paramsV2,\n int256 exclusivityEndTime\n )\n internal\n view\n {\n // Check V1 (legacy) params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.sender == address(0) || params.to == address(0)) revert ZeroAddress();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n // Check V2 params\n if (paramsV2.zapData.length \u003e MAX_ZAP_DATA_LENGTH) revert ZapDataLengthAboveMax();\n if (paramsV2.zapNative != 0 \u0026\u0026 params.destToken == NATIVE_GAS_TOKEN) {\n revert ZapNativeNotSupported();\n }\n // exclusivityEndTime must be in range [0 .. params.deadline]\n if (exclusivityEndTime \u003c 0 || exclusivityEndTime \u003e int256(params.deadline)) {\n revert ExclusivityParamsIncorrect();\n }\n }\n\n /// @notice Performs all the necessary checks for a relay to happen.\n function _validateRelayParams(bytes calldata request, bytes32 transactionId, address relayer) internal view {\n if (relayer == address(0)) revert ZeroAddress();\n // Check if the transaction has already been relayed\n if (bridgeRelays(transactionId)) revert TransactionRelayed();\n if (request.destChainId() != block.chainid) revert ChainIncorrect();\n // Check the deadline for relay to happen\n if (block.timestamp \u003e request.deadline()) revert DeadlineExceeded();\n // Check the exclusivity period, if it is still ongoing\n address exclRelayer = request.exclusivityRelayer();\n if (exclRelayer != address(0) \u0026\u0026 exclRelayer != relayer \u0026\u0026 block.timestamp \u003c= request.exclusivityEndTime()) {\n revert ExclusivityPeriodNotPassed();\n }\n }\n}\n","language":"Solidity","languageVersion":"0.8.24","compilerVersion":"0.8.24","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"","srcMapRuntime":"","abiDefinition":[{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"}],"userDoc":{"kind":"user","methods":{},"version":1},"developerDoc":{"details":"Implementation of the {IERC165} interface. Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check for the additional interface id that will be supported. For example: ```solidity function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId); } ```","kind":"dev","methods":{"supportsInterface(bytes4)":{"details":"See {IERC165-supportsInterface}."}},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"bytes4\",\"name\":\"interfaceId\",\"type\":\"bytes4\"}],\"name\":\"supportsInterface\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"}],\"devdoc\":{\"details\":\"Implementation of the {IERC165} interface. Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check for the additional interface id that will be supported. For example: ```solidity function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId); } ```\",\"kind\":\"dev\",\"methods\":{\"supportsInterface(bytes4)\":{\"details\":\"See {IERC165-supportsInterface}.\"}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeV2.sol\":\"ERC165\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeV2.sol\":{\"keccak256\":\"0xac79c463688a682ca706a4ef95e7817b83548cdfa8182ba0426ac7e5e07613d8\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://b3ecb7097381287cafc3a73f3a2bb03565115ebb682a85064e0b0dc2f7e2919d\",\"dweb:/ipfs/QmatruW3nYZTksf3CeQ8wwiAG4c7xoEJBEp6drHPtFLBRK\"]}},\"version\":1}"},"hashes":{"supportsInterface(bytes4)":"01ffc9a7"}},"solidity/FastBridgeV2.sol:EnumerableSet":{"code":"0x60566037600b82828239805160001a607314602a57634e487b7160e01b600052600060045260246000fd5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600080fdfea2646970667358221220cb930ba14bc69bdf61a9326099568898423db2bde70050effda1b23aa9e9dc9e64736f6c63430008180033","runtime-code":"0x73000000000000000000000000000000000000000030146080604052600080fdfea2646970667358221220cb930ba14bc69bdf61a9326099568898423db2bde70050effda1b23aa9e9dc9e64736f6c63430008180033","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.24 ^0.8.20 ^0.8.4;\n\n// contracts/interfaces/IAdminV2.sol\n\ninterface IAdminV2 {\n event CancelDelayUpdated(uint256 oldCancelDelay, uint256 newCancelDelay);\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n function setCancelDelay(uint256 newCancelDelay) external;\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n}\n\n// contracts/interfaces/IAdminV2Errors.sol\n\ninterface IAdminV2Errors {\n error CancelDelayBelowMin();\n error FeeRateAboveMax();\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IFastBridgeV2Errors.sol\n\ninterface IFastBridgeV2Errors {\n error AmountIncorrect();\n error ChainIncorrect();\n error ExclusivityParamsIncorrect();\n error MsgValueIncorrect();\n error SenderIncorrect();\n error StatusIncorrect();\n error TokenNotContract();\n error ZapDataLengthAboveMax();\n error ZapNativeNotSupported();\n error ZeroAddress();\n\n error RecipientIncorrectReturnValue();\n error RecipientNoReturnValue();\n\n error DeadlineExceeded();\n error DeadlineNotExceeded();\n error DeadlineTooShort();\n error DisputePeriodNotPassed();\n error DisputePeriodPassed();\n error ExclusivityPeriodNotPassed();\n\n error TransactionRelayed();\n}\n\n// contracts/interfaces/IMulticallTarget.sol\n\n/// @notice Interface for a contract that can be called multiple times by the same caller. Inspired by MulticallV3:\n/// https://github.com/mds1/multicall/blob/master/src/Multicall3.sol\ninterface IMulticallTarget {\n struct Result {\n bool success;\n bytes returnData;\n }\n\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external;\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results);\n}\n\n// contracts/interfaces/IZapRecipient.sol\n\ninterface IZapRecipient {\n function zap(address token, uint256 amount, bytes memory zapData) external payable returns (bytes4);\n}\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// contracts/interfaces/IFastBridgeV2.sol\n\ninterface IFastBridgeV2 is IFastBridge {\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n struct BridgeTxDetails {\n BridgeStatus status;\n uint32 destChainId;\n uint56 proofBlockTimestamp;\n address proofRelayer;\n }\n\n struct BridgeRelay {\n uint48 blockNumber;\n uint48 blockTimestamp;\n address relayer;\n }\n\n /// @notice New params introduced in the FastBridgeV2.\n /// We are passing fields from the older BridgeParams struct outside of this struct\n /// for backwards compatibility.\n /// Note: quoteRelayer and quoteExclusivitySeconds are either both zero (indicating no exclusivity)\n /// or both non-zero (indicating exclusivity for the given period).\n /// Note: zapNative \u003e 0 can NOT be used with destToken = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE (native token)\n /// @param quoteRelayer Relayer that provided the quote for the transaction\n /// @param quoteExclusivitySeconds Period of time the quote relayer is guaranteed exclusivity after user's deposit\n /// @param quoteId Unique quote identifier used for tracking the quote\n /// @param zapNative ETH value to send to the recipient (if any)\n /// @param zapData Parameters for the Zap to the destination recipient (if any)\n struct BridgeParamsV2 {\n address quoteRelayer;\n int256 quoteExclusivitySeconds;\n bytes quoteId;\n uint256 zapNative;\n bytes zapData;\n }\n\n /// @notice Updated bridge transaction struct to include parameters introduced in FastBridgeV2.\n /// Note: only `exclusivityRelayer` can fill such a transaction until `exclusivityEndTime`.\n struct BridgeTransactionV2 {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n // Note: sendChainGas flag from V1 is deprecated\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n address exclusivityRelayer;\n uint256 exclusivityEndTime;\n uint256 zapNative; // ETH value to send to the recipient (if any)\n bytes zapData; // data to pass for the Zap action (if any)\n }\n\n event BridgeQuoteDetails(bytes32 indexed transactionId, bytes quoteId);\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability\n /// to provide temporary exclusivity fill rights for the quote relayer.\n /// @param params The parameters required to bridge\n /// @param paramsV2 The parameters for exclusivity fill rights (optional, can be left empty)\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function relay(bytes memory request, address relayer) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param transactionId The transaction id associated with the encoded bridge transaction to prove\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital.\n /// @notice Can only send funds to the relayer address on the proof.\n /// @param request The encoded bridge transaction to claim on origin chain\n function claim(bytes memory request) external;\n\n /// @notice Cancels an outstanding bridge transaction in case optimistic bridging failed and returns the full amount\n /// to the original sender.\n /// @param request The encoded bridge transaction to refund\n function cancel(bytes memory request) external;\n\n /// @notice Checks if a transaction has been relayed\n /// @param transactionId The ID of the transaction to check\n /// @return True if the transaction has been relayed, false otherwise\n function bridgeRelays(bytes32 transactionId) external view returns (bool);\n\n /// @notice Returns the status of a bridge transaction\n /// @param transactionId The ID of the bridge transaction\n /// @return BridgeStatus Status of the bridge transaction\n function bridgeStatuses(bytes32 transactionId) external view returns (BridgeStatus);\n\n /// @notice Returns the timestamp and relayer of a bridge proof\n /// @param transactionId The ID of the bridge transaction\n /// @return timestamp The timestamp of the bridge proof\n /// @return relayer The relayer address of the bridge proof\n function bridgeProofs(bytes32 transactionId) external view returns (uint96 timestamp, address relayer);\n\n /// @notice Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\n /// @param request The bridge request to decode\n function getBridgeTransactionV2(bytes memory request) external view returns (BridgeTransactionV2 memory);\n}\n\n// contracts/utils/MulticallTarget.sol\n\n// solhint-disable avoid-low-level-calls\n/// @notice Template for a contract that supports batched calls (preserving the msg.sender).\n/// Only calls with zero msg.value could be batched.\nabstract contract MulticallTarget is IMulticallTarget {\n error MulticallTarget__UndeterminedRevert();\n\n /// @notice Perform a batched call to this contract, preserving the msg.sender.\n /// The return data from each call is discarded.\n /// @dev The method is non-payable, so only calls with `msg.value == 0` could be batched.\n /// It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag.\n /// Otherwise, the whole batch call will be reverted with the original revert reason.\n /// @param data List of abi-encoded calldata for the calls to perform.\n /// @param ignoreReverts Whether to ignore the revert errors from the calls.\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external {\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\n if (!success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(result);\n }\n }\n }\n\n /// @notice Perform a batched call to this contract, preserving the msg.sender.\n /// The return data from each call is preserved.\n /// @dev The method is non-payable, so only calls with `msg.value == 0` could be batched.\n /// It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag.\n /// Otherwise, the whole batch call will be reverted with the original revert reason.\n /// @param data List of abi-encoded calldata for the calls to perform.\n /// @param ignoreReverts Whether to ignore the revert errors from the calls.\n /// @return results List of results from the calls: `(success, returnData)`.\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results)\n {\n results = new Result[](data.length);\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (results[i].success, results[i].returnData) = address(this).delegatecall(data[i]);\n if (!results[i].success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(results[i].returnData);\n }\n }\n }\n\n /// @dev Bubbles the revert message from the underlying call.\n /// Note: preserves the same custom error or revert string, if one was used.\n /// Source: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v5.0.2/contracts/utils/Address.sol#L143-L158\n function _bubbleRevert(bytes memory returnData) internal pure {\n // Look for revert reason and bubble it up if present\n if (returnData.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n // solhint-disable-next-line no-inline-assembly\n assembly {\n let returndata_size := mload(returnData)\n revert(add(32, returnData), returndata_size)\n }\n } else {\n revert MulticallTarget__UndeterminedRevert();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// contracts/libs/BridgeTransactionV2.sol\n\n// solhint-disable no-inline-assembly\nlibrary BridgeTransactionV2Lib {\n uint16 internal constant VERSION = 2;\n\n // Offsets of the fields in the packed BridgeTransactionV2 struct\n // uint16 version [000 .. 002)\n // uint32 originChainId [002 .. 006)\n // uint32 destChainId [006 .. 010)\n // address originSender [010 .. 030)\n // address destRecipient [030 .. 050)\n // address originToken [050 .. 070)\n // address destToken [070 .. 090)\n // uint256 originAmount [090 .. 122)\n // uint256 destAmount [122 .. 154)\n // uint256 originFeeAmount [154 .. 186)\n // uint256 deadline [186 .. 218)\n // uint256 nonce [218 .. 250)\n // address exclusivityRelayer [250 .. 270)\n // uint256 exclusivityEndTime [270 .. 302)\n // uint256 zapNative [302 .. 334)\n // bytes zapData [334 .. ***)\n\n // forgefmt: disable-start\n uint256 private constant OFFSET_ORIGIN_CHAIN_ID = 2;\n uint256 private constant OFFSET_DEST_CHAIN_ID = 6;\n uint256 private constant OFFSET_ORIGIN_SENDER = 10;\n uint256 private constant OFFSET_DEST_RECIPIENT = 30;\n uint256 private constant OFFSET_ORIGIN_TOKEN = 50;\n uint256 private constant OFFSET_DEST_TOKEN = 70;\n uint256 private constant OFFSET_ORIGIN_AMOUNT = 90;\n uint256 private constant OFFSET_DEST_AMOUNT = 122;\n uint256 private constant OFFSET_ORIGIN_FEE_AMOUNT = 154;\n uint256 private constant OFFSET_DEADLINE = 186;\n uint256 private constant OFFSET_NONCE = 218;\n uint256 private constant OFFSET_EXCLUSIVITY_RELAYER = 250;\n uint256 private constant OFFSET_EXCLUSIVITY_END_TIME = 270;\n uint256 private constant OFFSET_ZAP_NATIVE = 302;\n uint256 private constant OFFSET_ZAP_DATA = 334;\n // forgefmt: disable-end\n\n error BridgeTransactionV2__InvalidEncodedTx();\n error BridgeTransactionV2__UnsupportedVersion(uint16 version);\n\n /// @notice Validates the encoded transaction to be a tightly packed encoded payload for BridgeTransactionV2.\n /// @dev Checks the minimum length and the version, use this function before decoding any of the fields.\n function validateV2(bytes calldata encodedTx) internal pure {\n // Check the minimum length: must at least include all static fields.\n if (encodedTx.length \u003c OFFSET_ZAP_DATA) revert BridgeTransactionV2__InvalidEncodedTx();\n // Once we validated the length, we can be sure that the version field is present.\n uint16 version_ = version(encodedTx);\n if (version_ != VERSION) revert BridgeTransactionV2__UnsupportedVersion(version_);\n }\n\n /// @notice Encodes the BridgeTransactionV2 struct by tightly packing the fields.\n /// @dev `abi.decode` will not work as a result of the tightly packed fields. Use `decodeV2` to decode instead.\n function encodeV2(IFastBridgeV2.BridgeTransactionV2 memory bridgeTx) internal pure returns (bytes memory) {\n // We split the encoding into two parts to avoid stack-too-deep error\n bytes memory firstPart = abi.encodePacked(\n VERSION,\n bridgeTx.originChainId,\n bridgeTx.destChainId,\n bridgeTx.originSender,\n bridgeTx.destRecipient,\n bridgeTx.originToken,\n bridgeTx.destToken,\n bridgeTx.originAmount\n );\n return abi.encodePacked(\n firstPart,\n bridgeTx.destAmount,\n bridgeTx.originFeeAmount,\n // Note: we skip the deprecated `sendChainGas` flag, which was present in BridgeTransaction V1\n bridgeTx.deadline,\n bridgeTx.nonce,\n // New V2 fields: exclusivity\n bridgeTx.exclusivityRelayer,\n bridgeTx.exclusivityEndTime,\n // New V2 fields: Zap\n bridgeTx.zapNative,\n bridgeTx.zapData\n );\n }\n\n /// @notice Decodes the BridgeTransactionV2 struct from the encoded transaction.\n /// @dev Encoded BridgeTransactionV2 struct must be tightly packed.\n /// Use `validateV2` before decoding to ensure the encoded transaction is valid.\n function decodeV2(bytes calldata encodedTx)\n internal\n pure\n returns (IFastBridgeV2.BridgeTransactionV2 memory bridgeTx)\n {\n bridgeTx.originChainId = originChainId(encodedTx);\n bridgeTx.destChainId = destChainId(encodedTx);\n bridgeTx.originSender = originSender(encodedTx);\n bridgeTx.destRecipient = destRecipient(encodedTx);\n bridgeTx.originToken = originToken(encodedTx);\n bridgeTx.destToken = destToken(encodedTx);\n bridgeTx.originAmount = originAmount(encodedTx);\n bridgeTx.destAmount = destAmount(encodedTx);\n bridgeTx.originFeeAmount = originFeeAmount(encodedTx);\n bridgeTx.deadline = deadline(encodedTx);\n bridgeTx.nonce = nonce(encodedTx);\n bridgeTx.exclusivityRelayer = exclusivityRelayer(encodedTx);\n bridgeTx.exclusivityEndTime = exclusivityEndTime(encodedTx);\n bridgeTx.zapNative = zapNative(encodedTx);\n bridgeTx.zapData = zapData(encodedTx);\n }\n\n /// @notice Extracts the version from the encoded transaction.\n function version(bytes calldata encodedTx) internal pure returns (uint16 version_) {\n // Load 32 bytes from the start and shift it 240 bits to the right to get the highest 16 bits.\n assembly {\n version_ := shr(240, calldataload(encodedTx.offset))\n }\n }\n\n /// @notice Extracts the origin chain ID from the encoded transaction.\n function originChainId(bytes calldata encodedTx) internal pure returns (uint32 originChainId_) {\n // Load 32 bytes from the offset and shift it 224 bits to the right to get the highest 32 bits.\n assembly {\n originChainId_ := shr(224, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_CHAIN_ID)))\n }\n }\n\n /// @notice Extracts the destination chain ID from the encoded transaction.\n function destChainId(bytes calldata encodedTx) internal pure returns (uint32 destChainId_) {\n // Load 32 bytes from the offset and shift it 224 bits to the right to get the highest 32 bits.\n assembly {\n destChainId_ := shr(224, calldataload(add(encodedTx.offset, OFFSET_DEST_CHAIN_ID)))\n }\n }\n\n /// @notice Extracts the origin sender from the encoded transaction.\n function originSender(bytes calldata encodedTx) internal pure returns (address originSender_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n originSender_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_SENDER)))\n }\n }\n\n /// @notice Extracts the destination recipient from the encoded transaction.\n function destRecipient(bytes calldata encodedTx) internal pure returns (address destRecipient_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n destRecipient_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_DEST_RECIPIENT)))\n }\n }\n\n /// @notice Extracts the origin token from the encoded transaction.\n function originToken(bytes calldata encodedTx) internal pure returns (address originToken_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n originToken_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_TOKEN)))\n }\n }\n\n /// @notice Extracts the destination token from the encoded transaction.\n function destToken(bytes calldata encodedTx) internal pure returns (address destToken_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n destToken_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_DEST_TOKEN)))\n }\n }\n\n /// @notice Extracts the origin amount from the encoded transaction.\n function originAmount(bytes calldata encodedTx) internal pure returns (uint256 originAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n originAmount_ := calldataload(add(encodedTx.offset, OFFSET_ORIGIN_AMOUNT))\n }\n }\n\n /// @notice Extracts the destination amount from the encoded transaction.\n function destAmount(bytes calldata encodedTx) internal pure returns (uint256 destAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n destAmount_ := calldataload(add(encodedTx.offset, OFFSET_DEST_AMOUNT))\n }\n }\n\n /// @notice Extracts the origin fee amount from the encoded transaction.\n function originFeeAmount(bytes calldata encodedTx) internal pure returns (uint256 originFeeAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n originFeeAmount_ := calldataload(add(encodedTx.offset, OFFSET_ORIGIN_FEE_AMOUNT))\n }\n }\n\n /// @notice Extracts the deadline from the encoded transaction.\n function deadline(bytes calldata encodedTx) internal pure returns (uint256 deadline_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n deadline_ := calldataload(add(encodedTx.offset, OFFSET_DEADLINE))\n }\n }\n\n /// @notice Extracts the nonce from the encoded transaction.\n function nonce(bytes calldata encodedTx) internal pure returns (uint256 nonce_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n nonce_ := calldataload(add(encodedTx.offset, OFFSET_NONCE))\n }\n }\n\n /// @notice Extracts the exclusivity relayer from the encoded transaction.\n function exclusivityRelayer(bytes calldata encodedTx) internal pure returns (address exclusivityRelayer_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n exclusivityRelayer_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_EXCLUSIVITY_RELAYER)))\n }\n }\n\n /// @notice Extracts the exclusivity end time from the encoded transaction.\n function exclusivityEndTime(bytes calldata encodedTx) internal pure returns (uint256 exclusivityEndTime_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n exclusivityEndTime_ := calldataload(add(encodedTx.offset, OFFSET_EXCLUSIVITY_END_TIME))\n }\n }\n\n /// @notice Extracts the Zap's native value from the encoded transaction.\n function zapNative(bytes calldata encodedTx) internal pure returns (uint256 zapNative_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n zapNative_ := calldataload(add(encodedTx.offset, OFFSET_ZAP_NATIVE))\n }\n }\n\n /// @notice Extracts the Zap's data from the encoded transaction.\n function zapData(bytes calldata encodedTx) internal pure returns (bytes calldata zapData_) {\n zapData_ = encodedTx[OFFSET_ZAP_DATA:];\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/AdminV2.sol\n\ncontract AdminV2 is AccessControlEnumerable, IAdminV2, IAdminV2Errors {\n using SafeERC20 for IERC20;\n\n /// @notice Address reserved for native gas token (ETH on Ethereum and most L2s, AVAX on Avalanche, etc)\n address public constant NATIVE_GAS_TOKEN = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Role identifier for Quoter API's off-chain authentication.\n /// @dev Only addresses with this role can post FastBridge quotes to the API.\n bytes32 public constant QUOTER_ROLE = keccak256(\"QUOTER_ROLE\");\n\n /// @notice Role identifier for Prover's on-chain authentication in FastBridge.\n /// @dev Only addresses with this role can provide proofs that a FastBridge request has been relayed.\n bytes32 public constant PROVER_ROLE = keccak256(\"PROVER_ROLE\");\n\n /// @notice Role identifier for Guard's on-chain authentication in FastBridge.\n /// @dev Only addresses with this role can dispute submitted relay proofs during the dispute period.\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n\n /// @notice Role identifier for Canceler's on-chain authentication in FastBridge.\n /// @dev Only addresses with this role can cancel a FastBridge transaction without the cancel delay.\n bytes32 public constant CANCELER_ROLE = keccak256(\"CANCELER_ROLE\");\n\n /// @notice Role identifier for Governor's on-chain administrative authority.\n /// @dev Only addresses with this role can perform administrative tasks within the contract.\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n /// @notice Denominator for fee rates, represents 100%.\n uint256 public constant FEE_BPS = 1e6;\n /// @notice Maximum protocol fee rate: 1% on origin amount.\n uint256 public constant FEE_RATE_MAX = 0.01e6;\n\n /// @notice Minimum cancel delay that can be set by the governor.\n uint256 public constant MIN_CANCEL_DELAY = 1 hours;\n /// @notice Default cancel delay set during the contract deployment.\n uint256 public constant DEFAULT_CANCEL_DELAY = 1 days;\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Delay for a transaction after which it could be permisionlessly cancelled\n uint256 public cancelDelay;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Use ZapNative V2 requests instead.\n uint256 public immutable chainGasAmount = 0;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n _setCancelDelay(DEFAULT_CANCEL_DELAY);\n }\n\n /// @notice Allows the contract governor to set the cancel delay. The cancel delay is the time after the transaction\n /// deadline after which it can be permissionlessly cancelled, if it hasn't been proven by any of the Relayers.\n function setCancelDelay(uint256 newCancelDelay) external onlyRole(GOVERNOR_ROLE) {\n _setCancelDelay(newCancelDelay);\n }\n\n /// @notice Allows the contract governor to set the protocol fee rate. The protocol fee is taken from the origin\n /// amount only for completed and claimed transactions.\n /// @dev The protocol fee is abstracted away from the relayers, they always operate using the amounts after fees:\n /// what they see as the origin amount emitted in the log is what they get credited with.\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n if (newFeeRate \u003e FEE_RATE_MAX) revert FeeRateAboveMax();\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n /// @notice Allows the contract governor to sweep the accumulated protocol fees in the contract.\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n emit FeesSwept(token, recipient, feeAmount);\n /// Sweep the fees as the last transaction action\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(recipient), feeAmount);\n } else {\n IERC20(token).safeTransfer(recipient, feeAmount);\n }\n }\n\n /// @notice Internal function to set the cancel delay. Security checks are performed outside of this function.\n function _setCancelDelay(uint256 newCancelDelay) private {\n if (newCancelDelay \u003c MIN_CANCEL_DELAY) revert CancelDelayBelowMin();\n uint256 oldCancelDelay = cancelDelay;\n cancelDelay = newCancelDelay;\n emit CancelDelayUpdated(oldCancelDelay, newCancelDelay);\n }\n}\n\n// contracts/FastBridgeV2.sol\n\n/// @notice FastBridgeV2 is a contract for bridging tokens across chains.\ncontract FastBridgeV2 is AdminV2, MulticallTarget, IFastBridgeV2, IFastBridgeV2Errors {\n using BridgeTransactionV2Lib for bytes;\n using SafeERC20 for IERC20;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n /// @notice Maximum length of accepted zapData\n uint256 public constant MAX_ZAP_DATA_LENGTH = 2 ** 16 - 1;\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeTxDetails) public bridgeTxDetails;\n /// @notice Relay details on destination chain\n mapping(bytes32 =\u003e BridgeRelay) public bridgeRelayDetails;\n /// @notice Unique bridge nonces tracked per originSender\n mapping(address =\u003e uint256) public senderNonces;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Replaced by senderNonces\n uint256 public immutable nonce = 0;\n /// @notice the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) AdminV2(_owner) {\n deployBlock = block.number;\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n bridge({\n params: params,\n paramsV2: BridgeParamsV2({\n quoteRelayer: address(0),\n quoteExclusivitySeconds: 0,\n quoteId: bytes(\"\"),\n zapNative: 0,\n zapData: bytes(\"\")\n })\n });\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes calldata request) external payable {\n // relay override will validate the request\n relay({request: request, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes calldata request, bytes32 destTxHash) external {\n request.validateV2();\n prove({transactionId: keccak256(request), destTxHash: destTxHash, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridgeV2\n function claim(bytes calldata request) external {\n // claim override will validate the request\n claim({request: request, to: address(0)});\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Aggregate the read operations from the same storage slot\n address disputedRelayer = $.proofRelayer;\n BridgeStatus status = $.status;\n uint56 proofBlockTimestamp = $.proofBlockTimestamp;\n // Can only dispute a RELAYER_PROVED transaction within the dispute period\n if (status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(proofBlockTimestamp) \u003e DISPUTE_PERIOD) {\n revert DisputePeriodPassed();\n }\n // Update status to REQUESTED and delete the disputed proof details\n // Note: these are storage writes\n $.status = BridgeStatus.REQUESTED;\n $.proofRelayer = address(0);\n $.proofBlockTimestamp = 0;\n\n emit BridgeProofDisputed(transactionId, disputedRelayer);\n }\n\n /// Note: this function is deprecated and will be removed in a future version.\n /// @inheritdoc IFastBridge\n function refund(bytes calldata request) external {\n cancel(request);\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // The correct relayer can only claim a RELAYER_PROVED transaction after the dispute period\n if ($.status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if ($.proofRelayer != relayer) revert SenderIncorrect();\n return _timeSince($.proofBlockTimestamp) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n /// @dev This method is added to achieve backwards compatibility with decoding requests into V1 structs:\n /// - `zapNative` is partially reported as a zero/non-zero flag\n /// - `zapData` is ignored\n /// In order to process all kinds of requests use getBridgeTransactionV2 instead.\n function getBridgeTransaction(bytes calldata request) external view returns (BridgeTransaction memory) {\n // Try decoding into V2 struct first. This will revert if V1 struct is passed\n try this.getBridgeTransactionV2(request) returns (BridgeTransactionV2 memory txV2) {\n // Note: we entirely ignore the zapData field, as it was not present in V1\n return BridgeTransaction({\n originChainId: txV2.originChainId,\n destChainId: txV2.destChainId,\n originSender: txV2.originSender,\n destRecipient: txV2.destRecipient,\n originToken: txV2.originToken,\n destToken: txV2.destToken,\n originAmount: txV2.originAmount,\n destAmount: txV2.destAmount,\n originFeeAmount: txV2.originFeeAmount,\n sendChainGas: txV2.zapNative != 0,\n deadline: txV2.deadline,\n nonce: txV2.nonce\n });\n } catch {\n // Fallback to V1 struct\n return abi.decode(request, (BridgeTransaction));\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function getBridgeTransactionV2(bytes calldata request) external pure returns (BridgeTransactionV2 memory) {\n request.validateV2();\n return BridgeTransactionV2Lib.decodeV2(request);\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) public payable {\n int256 exclusivityEndTime = 0;\n // if relayer exclusivity is not intended for this bridge, set exclusivityEndTime to static zero\n // otherwise, set exclusivity to expire at the current block ts offset by quoteExclusivitySeconds\n if (paramsV2.quoteRelayer != address(0)) {\n exclusivityEndTime = int256(block.timestamp) + paramsV2.quoteExclusivitySeconds;\n }\n _validateBridgeParams(params, paramsV2, exclusivityEndTime);\n\n // transfer tokens to bridge contract\n /// @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _takeBridgedUserAsset(params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) {\n originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n }\n\n // set status to requested\n bytes memory request = BridgeTransactionV2Lib.encodeV2(\n BridgeTransactionV2({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n deadline: params.deadline,\n nonce: senderNonces[params.sender]++, // increment nonce on every bridge\n exclusivityRelayer: paramsV2.quoteRelayer,\n // We checked exclusivityEndTime to be in range [0 .. params.deadline] above, so can safely cast\n exclusivityEndTime: uint256(exclusivityEndTime),\n zapNative: paramsV2.zapNative,\n zapData: paramsV2.zapData\n })\n );\n bytes32 transactionId = keccak256(request);\n // Note: the tx status will be updated throughout the tx lifecycle, while destChainId is set once here\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n bridgeTxDetails[transactionId].destChainId = params.dstChainId;\n\n emit BridgeRequested({\n transactionId: transactionId,\n sender: params.sender,\n request: request,\n destChainId: params.dstChainId,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n sendChainGas: paramsV2.zapNative != 0\n });\n emit BridgeQuoteDetails(transactionId, paramsV2.quoteId);\n }\n\n /// @inheritdoc IFastBridgeV2\n function relay(bytes calldata request, address relayer) public payable {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n _validateRelayParams(request, transactionId, relayer);\n // mark bridge transaction as relayed\n bridgeRelayDetails[transactionId] =\n BridgeRelay({blockNumber: uint48(block.number), blockTimestamp: uint48(block.timestamp), relayer: relayer});\n\n // transfer tokens to recipient on destination chain and trigger Zap if requested\n address to = request.destRecipient();\n address token = request.destToken();\n uint256 amount = request.destAmount();\n uint256 zapNative = request.zapNative();\n\n // Emit the event before any external calls\n emit BridgeRelayed({\n transactionId: transactionId,\n relayer: relayer,\n to: to,\n originChainId: request.originChainId(),\n originToken: request.originToken(),\n destToken: token,\n originAmount: request.originAmount(),\n destAmount: amount,\n chainGasAmount: zapNative\n });\n\n // All state changes have been done at this point, can proceed to the external calls.\n // This follows the checks-effects-interactions pattern to mitigate potential reentrancy attacks.\n if (token == NATIVE_GAS_TOKEN) {\n // For the native gas token, additional zapNative is not allowed\n if (zapNative != 0) revert ZapNativeNotSupported();\n // Check that the correct msg.value was sent\n if (msg.value != amount) revert MsgValueIncorrect();\n // Don't do a native transfer yet: we will handle it alongside the Zap below\n } else {\n // For ERC20s, we check that the correct msg.value was sent\n if (msg.value != zapNative) revert MsgValueIncorrect();\n // We need to transfer the tokens from the Relayer to the recipient first before performing an\n // optional post-transfer Zap.\n IERC20(token).safeTransferFrom(msg.sender, to, amount);\n }\n // At this point we have done:\n // - Transferred the requested amount of ERC20 tokens to the recipient.\n // At this point we have confirmed:\n // - For ERC20s: msg.value matches the requested zapNative amount.\n // - For the native gas token: msg.value matches the requested destAmount.\n // Remaining optional things to do:\n // - Forward the full msg.value to the recipient (if non-zero).\n // - Trigger a Zap (if zapData is present).\n bytes calldata zapData = request.zapData();\n if (zapData.length != 0) {\n // Zap Data is present: Zap has been requested by the recipient. Trigger it forwarding the full msg.value.\n\n // Note: if token has a fee on transfers, the recipient will have received less than `amount`.\n // This is a very niche edge case and should be handled by the recipient contract.\n _triggerZapWithChecks({recipient: to, token: token, amount: amount, zapData: zapData});\n } else if (msg.value != 0) {\n // Zap Data is missing, but msg.value was sent. This could happen in two different cases:\n // - Relay with the native gas token is happening.\n // - Relay with ERC20 is happening, with a `zapNative \u003e 0` request.\n // In both cases, we need to transfer the full msg.value to the recipient.\n Address.sendValue(payable(to), msg.value);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) public onlyRole(PROVER_ROLE) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n\n // Can only prove a REQUESTED transaction\n if ($.status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n // Update status to RELAYER_PROVED and store the proof details\n // Note: these are storage writes\n $.status = BridgeStatus.RELAYER_PROVED;\n $.proofBlockTimestamp = uint56(block.timestamp);\n $.proofRelayer = relayer;\n\n emit BridgeProofProvided(transactionId, relayer, destTxHash);\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes calldata request, address to) public {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Aggregate the read operations from the same storage slot\n address proofRelayer = $.proofRelayer;\n BridgeStatus status = $.status;\n uint56 proofBlockTimestamp = $.proofBlockTimestamp;\n\n // Can only claim a RELAYER_PROVED transaction after the dispute period\n if (status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(proofBlockTimestamp) \u003c= DISPUTE_PERIOD) {\n revert DisputePeriodNotPassed();\n }\n\n if (to == address(0)) {\n // Anyone could claim the funds to the proven relayer on their behalf\n to = proofRelayer;\n } else if (proofRelayer != msg.sender) {\n // Only the proven relayer could specify an address to claim the funds to\n revert SenderIncorrect();\n }\n\n // Update status to RELAYER_CLAIMED and transfer the origin collateral to the specified claim address\n // Note: this is a storage write\n $.status = BridgeStatus.RELAYER_CLAIMED;\n\n address token = request.originToken();\n uint256 amount = request.originAmount();\n // Update protocol fees if origin fee amount exists\n uint256 originFeeAmount = request.originFeeAmount();\n if (originFeeAmount \u003e 0) protocolFees[token] += originFeeAmount;\n // Emit the event before any external calls\n emit BridgeDepositClaimed(transactionId, proofRelayer, to, token, amount);\n // Complete the relayer claim as the last transaction action\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(to), amount);\n } else {\n IERC20(token).safeTransfer(to, amount);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function cancel(bytes calldata request) public {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Can only cancel a REQUESTED transaction after its deadline expires\n if ($.status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n uint256 deadline = request.deadline();\n // Permissionless cancel is only allowed after `cancelDelay` on top of the deadline\n if (!hasRole(CANCELER_ROLE, msg.sender)) deadline += cancelDelay;\n if (block.timestamp \u003c= deadline) revert DeadlineNotExceeded();\n // Update status to REFUNDED and return the full amount (collateral + protocol fees) to the original sender.\n // The protocol fees are only updated when the transaction is claimed, so we don't need to update them here.\n // Note: this is a storage write\n $.status = BridgeStatus.REFUNDED;\n\n address to = request.originSender();\n address token = request.originToken();\n uint256 amount = request.originAmount() + request.originFeeAmount();\n // Emit the event before any external calls\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n // Complete the user cancel as the last transaction action\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(to), amount);\n } else {\n IERC20(token).safeTransfer(to, amount);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeStatuses(bytes32 transactionId) public view returns (BridgeStatus status) {\n return bridgeTxDetails[transactionId].status;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeProofs(bytes32 transactionId) public view returns (uint96 timestamp, address relayer) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n\n timestamp = $.proofBlockTimestamp;\n relayer = $.proofRelayer;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeRelays(bytes32 transactionId) public view returns (bool) {\n // has this transactionId been relayed?\n return bridgeRelayDetails[transactionId].relayer != address(0);\n }\n\n /// @notice Takes the bridged asset from the user into FastBridgeV2 custody. It will be later\n /// claimed by the relayer who completed the relay on destination chain, or transferred back to the user\n /// via the cancel function should no one complete the relay.\n function _takeBridgedUserAsset(address token, uint256 amount) internal returns (uint256 amountTaken) {\n if (token == NATIVE_GAS_TOKEN) {\n // For the native gas token, we just need to check that the supplied msg.value is correct.\n // Supplied `msg.value` is already in FastBridgeV2 custody.\n if (amount != msg.value) revert MsgValueIncorrect();\n amountTaken = msg.value;\n } else {\n // For ERC20s, token is explicitly transferred from the user to FastBridgeV2.\n // We don't allow non-zero `msg.value` to avoid extra funds from being stuck in FastBridgeV2.\n if (msg.value != 0) revert MsgValueIncorrect();\n // Throw an explicit error if the provided token address is not a contract\n if (token.code.length == 0) revert TokenNotContract();\n amountTaken = IERC20(token).balanceOf(address(this));\n IERC20(token).safeTransferFrom(msg.sender, address(this), amount);\n // Use the balance difference as the amount taken in case of fee on transfer tokens.\n amountTaken = IERC20(token).balanceOf(address(this)) - amountTaken;\n }\n }\n\n /// @notice Calls the Recipient's hook function with the specified zapData and performs\n /// all the necessary checks for the returned value.\n function _triggerZapWithChecks(address recipient, address token, uint256 amount, bytes calldata zapData) internal {\n // This will bubble any revert messages from the hook function\n bytes memory returnData = Address.functionCallWithValue({\n target: recipient,\n data: abi.encodeCall(IZapRecipient.zap, (token, amount, zapData)),\n // Note: see `relay()` for reasoning behind passing msg.value\n value: msg.value\n });\n // Explicit revert if no return data at all\n if (returnData.length == 0) revert RecipientNoReturnValue();\n // Check that exactly a single return value was returned\n if (returnData.length != 32) revert RecipientIncorrectReturnValue();\n // Return value should be abi-encoded hook function selector\n if (bytes32(returnData) != bytes32(IZapRecipient.zap.selector)) {\n revert RecipientIncorrectReturnValue();\n }\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint56(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint56).max but\n /// proof.timestamp \u003c type(uint56).max via unchecked statement\n /// @param proofBlockTimestamp The bridge proof block timestamp\n /// @return delta Time delta since proof submitted\n function _timeSince(uint56 proofBlockTimestamp) internal view returns (uint256 delta) {\n unchecked {\n delta = uint56(block.timestamp) - proofBlockTimestamp;\n }\n }\n\n /// @notice Performs all the necessary checks for a bridge to happen.\n /// @dev There's no good way to refactor this function to reduce cyclomatic complexity due to\n /// the number of checks that need to be performed, so we skip the code-complexity rule here.\n // solhint-disable-next-line code-complexity\n function _validateBridgeParams(\n BridgeParams memory params,\n BridgeParamsV2 memory paramsV2,\n int256 exclusivityEndTime\n )\n internal\n view\n {\n // Check V1 (legacy) params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.sender == address(0) || params.to == address(0)) revert ZeroAddress();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n // Check V2 params\n if (paramsV2.zapData.length \u003e MAX_ZAP_DATA_LENGTH) revert ZapDataLengthAboveMax();\n if (paramsV2.zapNative != 0 \u0026\u0026 params.destToken == NATIVE_GAS_TOKEN) {\n revert ZapNativeNotSupported();\n }\n // exclusivityEndTime must be in range [0 .. params.deadline]\n if (exclusivityEndTime \u003c 0 || exclusivityEndTime \u003e int256(params.deadline)) {\n revert ExclusivityParamsIncorrect();\n }\n }\n\n /// @notice Performs all the necessary checks for a relay to happen.\n function _validateRelayParams(bytes calldata request, bytes32 transactionId, address relayer) internal view {\n if (relayer == address(0)) revert ZeroAddress();\n // Check if the transaction has already been relayed\n if (bridgeRelays(transactionId)) revert TransactionRelayed();\n if (request.destChainId() != block.chainid) revert ChainIncorrect();\n // Check the deadline for relay to happen\n if (block.timestamp \u003e request.deadline()) revert DeadlineExceeded();\n // Check the exclusivity period, if it is still ongoing\n address exclRelayer = request.exclusivityRelayer();\n if (exclRelayer != address(0) \u0026\u0026 exclRelayer != relayer \u0026\u0026 block.timestamp \u003c= request.exclusivityEndTime()) {\n revert ExclusivityPeriodNotPassed();\n }\n }\n}\n","language":"Solidity","languageVersion":"0.8.24","compilerVersion":"0.8.24","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"25831:11640:0:-:0;;;;;;;;;;;;;;;-1:-1:-1;;;25831:11640:0;;;;;;;;;;;;;;;;;","srcMapRuntime":"25831:11640:0:-:0;;;;;;;;","abiDefinition":[],"userDoc":{"kind":"user","methods":{},"version":1},"developerDoc":{"details":"Library for managing https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive types. Sets have the following properties: - Elements are added, removed, and checked for existence in constant time (O(1)). - Elements are enumerated in O(n). No guarantees are made on the ordering. ```solidity contract Example { // Add the library methods using EnumerableSet for EnumerableSet.AddressSet; // Declare a set state variable EnumerableSet.AddressSet private mySet; } ``` As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`) and `uint256` (`UintSet`) are supported. [WARNING] ==== Trying to delete such a structure from storage will likely result in data corruption, rendering the structure unusable. See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info. In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an array of EnumerableSet. ====","kind":"dev","methods":{},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[],\"devdoc\":{\"details\":\"Library for managing https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive types. Sets have the following properties: - Elements are added, removed, and checked for existence in constant time (O(1)). - Elements are enumerated in O(n). No guarantees are made on the ordering. ```solidity contract Example { // Add the library methods using EnumerableSet for EnumerableSet.AddressSet; // Declare a set state variable EnumerableSet.AddressSet private mySet; } ``` As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`) and `uint256` (`UintSet`) are supported. [WARNING] ==== Trying to delete such a structure from storage will likely result in data corruption, rendering the structure unusable. See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info. In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an array of EnumerableSet. ====\",\"kind\":\"dev\",\"methods\":{},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeV2.sol\":\"EnumerableSet\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeV2.sol\":{\"keccak256\":\"0xac79c463688a682ca706a4ef95e7817b83548cdfa8182ba0426ac7e5e07613d8\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://b3ecb7097381287cafc3a73f3a2bb03565115ebb682a85064e0b0dc2f7e2919d\",\"dweb:/ipfs/QmatruW3nYZTksf3CeQ8wwiAG4c7xoEJBEp6drHPtFLBRK\"]}},\"version\":1}"},"hashes":{}},"solidity/FastBridgeV2.sol:FastBridgeV2":{"code":"0x60e06040526000608081905260a0523480156200001b57600080fd5b50604051620047ee380380620047ee8339810160408190526200003e9162000215565b806200004c60008262000067565b506200005b62015180620000a4565b50504360c05262000240565b6000806200007684846200010d565b905080156200009b576000848152600160205260409020620000999084620001bb565b505b90505b92915050565b610e10811015620000c857604051630e0ea5c760e01b815260040160405180910390fd5b600480549082905560408051828152602081018490527f909f9078b2f6eac1d10f2aae793656c5a67511eb627ebd1d2cb1eb9c0ab94c95910160405180910390a15050565b6000828152602081815260408083206001600160a01b038516845290915281205460ff16620001b2576000838152602081815260408083206001600160a01b03861684529091529020805460ff19166001179055620001693390565b6001600160a01b0316826001600160a01b0316847f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45060016200009e565b5060006200009e565b60006200009b836001600160a01b0384166000818152600183016020526040812054620001b2575081546001818101845560008481526020808220909301849055845484825282860190935260409020919091556200009e565b6000602082840312156200022857600080fd5b81516001600160a01b03811681146200009b57600080fd5b60805160a05160c05161457e62000270600039600061094b015260006109ec01526000610bec015261457e6000f3fe60806040526004361061034a5760003560e01c80638379a24f116101bb578063ac11fb1a116100f7578063c79371b111610095578063d547741f1161006f578063d547741f14610b59578063dc9a4ef614610b79578063dcf844a714610bad578063e00a83e014610bda57600080fd5b8063c79371b114610a78578063ca15c87314610b05578063ccc5749014610b2557600080fd5b8063b13aa2d6116100d1578063b13aa2d614610a0e578063bf333f2c14610a2e578063bfc7c60714610a45578063c63ff8dd14610a5857600080fd5b8063ac11fb1a1461098d578063add98c70146109ba578063affed0e0146109da57600080fd5b8063922b748711610164578063a217fddf1161013e578063a217fddf14610924578063a3ec191a14610939578063a5bbe22b14610769578063aa9641ab1461096d57600080fd5b8063922b7487146108e4578063930ac180146108fa5780639c9545f01461091157600080fd5b80639010d07c116101955780639010d07c146107fa57806391ad50391461081a57806391d14854146108a057600080fd5b80638379a24f1461077f578063886d36ff146107c75780638f0d6f17146107e757600080fd5b8063385c1d2f1161028a57806358f858801161023357806363787e521161020d57806363787e52146106a5578063638a0f091461071f5780637ebe815c14610735578063820688d51461076957600080fd5b806358f85880146106425780635aa6ccba146106585780635eb7d9461461068557600080fd5b806341fcb6121161026457806341fcb612146105f9578063458516941461061957806354eff0681461062c57600080fd5b8063385c1d2f1461058c5780633c5beeb4146105b95780633f61331d146105d957600080fd5b80630f862f1e116102f7578063248a9ca3116102d1578063248a9ca3146104ef578063295710ff1461051f5780632f2ff15d1461054c57806336568abe1461056c57600080fd5b80630f862f1e1461046f57806318e4357d146104af5780631ea327c5146104cf57600080fd5b8063051287bc11610328578063051287bc146103fa57806306f333f2146104375780630f5f6ed71461045957600080fd5b806301ffc9a71461034f57806302d2ff661461038457806303ed0ee5146103c6575b600080fd5b34801561035b57600080fd5b5061036f61036a36600461352a565b610c0e565b60405190151581526020015b60405180910390f35b34801561039057600080fd5b506103b87febfdca8e46c0b8dacf9989ee613e35727eadd20a1d5e5ad01a53968c7e5fe07a81565b60405190815260200161037b565b3480156103d257600080fd5b506103b87f043c983c49d46f0e102151eaf8085d4a2e6571d5df2d47b013f39bddfd4a639d81565b34801561040657600080fd5b5061042a61041536600461356c565b60009081526005602052604090205460ff1690565b60405161037b91906135ef565b34801561044357600080fd5b50610457610452366004613622565b610c6a565b005b34801561046557600080fd5b506103b861271081565b34801561047b57600080fd5b5061049773eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee81565b6040516001600160a01b03909116815260200161037b565b3480156104bb57600080fd5b506104576104ca36600461365b565b610d77565b3480156104db57600080fd5b506104576104ea36600461356c565b610e8c565b3480156104fb57600080fd5b506103b861050a36600461356c565b60009081526020819052604090206001015490565b34801561052b57600080fd5b506103b861053a366004613694565b60076020526000908152604090205481565b34801561055857600080fd5b506104576105673660046136b1565b610ec3565b34801561057857600080fd5b506104576105873660046136b1565b610ee8565b34801561059857600080fd5b506105ac6105a73660046136ef565b610f34565b60405161037b91906137ba565b3480156105c557600080fd5b506104576105d4366004613899565b6110c2565b3480156105e557600080fd5b506104576105f43660046136ef565b6112c4565b34801561060557600080fd5b506104576106143660046138db565b61136e565b610457610627366004613adc565b6115e0565b34801561063857600080fd5b506103b861ffff81565b34801561064e57600080fd5b506103b860025481565b34801561066457600080fd5b50610678610673366004613899565b61163d565b60405161037b9190613af9565b34801561069157600080fd5b506104576106a0366004613899565b61170a565b3480156106b157600080fd5b5061070f6106c036600461356c565b60056020526000908152604090205460ff811690610100810463ffffffff169065010000000000810466ffffffffffffff16906c0100000000000000000000000090046001600160a01b031684565b60405161037b9493929190613c16565b34801561072b57600080fd5b506103b860045481565b34801561074157600080fd5b506103b87f9a04aea0a349253cc7277afafdf6ead6729a3972a47ffb40eaef2c93d4e1bfea81565b34801561077557600080fd5b506103b861070881565b34801561078b57600080fd5b5061036f61079a36600461356c565b6000908152600660205260409020546c0100000000000000000000000090046001600160a01b0316151590565b3480156107d357600080fd5b506104576107e2366004613c57565b611714565b6104576107f5366004613899565b611740565b34801561080657600080fd5b50610497610815366004613ca3565b61174b565b34801561082657600080fd5b5061087461083536600461356c565b60009081526005602052604090205465010000000000810466ffffffffffffff16916c010000000000000000000000009091046001600160a01b031690565b604080516bffffffffffffffffffffffff90931683526001600160a01b0390911660208301520161037b565b3480156108ac57600080fd5b5061036f6108bb3660046136b1565b6000918252602082815260408084206001600160a01b0393909316845291905290205460ff1690565b3480156108f057600080fd5b506103b8610e1081565b34801561090657600080fd5b506103b86201518081565b61045761091f3660046138db565b611763565b34801561093057600080fd5b506103b8600081565b34801561094557600080fd5b506103b87f000000000000000000000000000000000000000000000000000000000000000081565b34801561097957600080fd5b5061036f6109883660046136b1565b611a1d565b34801561099957600080fd5b506109ad6109a8366004613899565b611af4565b60405161037b9190613cc5565b3480156109c657600080fd5b506104576109d536600461356c565b611ca8565b3480156109e657600080fd5b506103b87f000000000000000000000000000000000000000000000000000000000000000081565b348015610a1a57600080fd5b50610457610a2936600461356c565b611df2565b348015610a3a57600080fd5b506103b8620f424081565b610457610a53366004613e29565b611e9e565b348015610a6457600080fd5b50610457610a73366004613899565b61212d565b348015610a8457600080fd5b50610ad7610a9336600461356c565b60066020526000908152604090205465ffffffffffff8082169166010000000000008104909116906c0100000000000000000000000090046001600160a01b031683565b6040805165ffffffffffff94851681529390921660208401526001600160a01b03169082015260600161037b565b348015610b1157600080fd5b506103b8610b2036600461356c565b612139565b348015610b3157600080fd5b506103b87f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f5581565b348015610b6557600080fd5b50610457610b743660046136b1565b612150565b348015610b8557600080fd5b506103b87f60044782a422109ac08a415e44260ad5d3bad63d96ebe1fac0363399642ee3f281565b348015610bb957600080fd5b506103b8610bc8366004613694565b60036020526000908152604090205481565b348015610be657600080fd5b506103b87f000000000000000000000000000000000000000000000000000000000000000081565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f5a05180f000000000000000000000000000000000000000000000000000000001480610c645750610c6482612175565b92915050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f55610c948161220c565b6001600160a01b03831660009081526003602052604081205490819003610cbb5750505050565b6001600160a01b038481166000818152600360209081526040808320929092558151928352928616928201929092529081018290527f244e51bc38c1452fa8aaf487bcb4bca36c2baa3a5fbdb776b1eabd8dc6d277cd9060600160405180910390a17fffffffffffffffffffffffff11111111111111111111111111111111111111126001600160a01b03851601610d5c57610d578382612216565b610d70565b610d706001600160a01b03851684836122e4565b505b505050565b7f60044782a422109ac08a415e44260ad5d3bad63d96ebe1fac0363399642ee3f2610da18161220c565b60008481526005602052604090206001815460ff166004811115610dc757610dc7613585565b14610dfe576040517f4145817200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80546001600160a01b0384166c0100000000000000000000000081026bffffffffffffffffffffffff66ffffffffffffff421665010000000000021664ffffffff009093169290921791909117600217825560405185815286907f4ac8af8a2cd87193d64dfc7a3b8d9923b714ec528b18725d080aa1299be0c5e49060200160405180910390a35050505050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f55610eb68161220c565b610ebf82612358565b5050565b600082815260208190526040902060010154610ede8161220c565b610d7083836123d9565b6001600160a01b0381163314610f2a576040517f6697b23200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610d728282612406565b60608267ffffffffffffffff811115610f4f57610f4f613927565b604051908082528060200260200182016040528015610f9557816020015b604080518082019091526000815260606020820152815260200190600190039081610f6d5790505b50905060005b838110156110ba5730858583818110610fb657610fb6613ef7565b9050602002810190610fc89190613f26565b604051610fd6929190613f8b565b600060405180830381855af49150503d8060008114611011576040519150601f19603f3d011682016040523d82523d6000602084013e611016565b606091505b5083838151811061102957611029613ef7565b602002602001015160000184848151811061104657611046613ef7565b60200260200101516020018290528215151515815250505081818151811061107057611070613ef7565b602002602001015160000151158015611087575082155b156110b2576110b28282815181106110a1576110a1613ef7565b602002602001015160200151612433565b600101610f9b565b509392505050565b6110cc8282612475565b600082826040516110de929190613f8b565b604080519182900390912060008181526005602052919091209091506001815460ff16600481111561111257611112613585565b14611149576040517f4145817200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b3360009081527f4527d8b28c468984933d33ae052f26b21c15ca0e7fdec762bba08e540e237001602052604090205460ba8501359060ff16611195576004546111929082613fca565b90505b8042116111ce576040517fe15ff9ea00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b81547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166004178255600a850135606090811c906032870135901c600061121d609a890135605a8a0135613fca565b604080516001600160a01b03858116825260208201849052825193945086169289927fb4c55c0c9bc613519b920e88748090150b890a875d307f21bea7d4fb2e8bc958928290030190a37fffffffffffffffffffffffff11111111111111111111111111111111111111126001600160a01b038316016112a6576112a18382612216565b6112ba565b6112ba6001600160a01b03831684836122e4565b5050505050505050565b60005b82811015610d7057600080308686858181106112e5576112e5613ef7565b90506020028101906112f79190613f26565b604051611305929190613f8b565b600060405180830381855af49150503d8060008114611340576040519150601f19603f3d011682016040523d82523d6000602084013e611345565b606091505b509150915081158015611356575083155b156113645761136481612433565b50506001016112c7565b6113788383612475565b6000838360405161138a929190613f8b565b604080519182900390912060008181526005602052919091208054919250906c0100000000000000000000000081046001600160a01b03169060ff81169065010000000000900466ffffffffffffff1660028260048111156113ee576113ee613585565b14611425576040517f4145817200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6107084282900366ffffffffffffff161161146c576040517f1992d0bd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600160a01b038616611482578295506114c4565b6001600160a01b03831633146114c4576040517f4af43a9000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b83547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166003178455603288013560601c605a890135609a8a01358015611533576001600160a01b0383166000908152600360205260408120805483929061152d908490613fca565b90915550505b604080516001600160a01b03858116825260208201859052808c1692908916918b917f582211c35a2139ac3bbaac74663c6a1f56c6cbb658b41fe11fd45a82074ac678910160405180910390a47fffffffffffffffffffffffff11111111111111111111111111111111111111126001600160a01b038416016115bf576115ba8983612216565b6115d3565b6115d36001600160a01b0384168a846122e4565b5050505050505050505050565b61163a816040518060a0016040528060006001600160a01b03168152602001600081526020016040518060200160405280600081525081526020016000815260200160405180602001604052806000815250815250611e9e565b50565b6116ef604051806101e00160405280600063ffffffff168152602001600063ffffffff16815260200160006001600160a01b0316815260200160006001600160a01b0316815260200160006001600160a01b0316815260200160006001600160a01b03168152602001600081526020016000815260200160008152602001600081526020016000815260200160006001600160a01b031681526020016000815260200160008152602001606081525090565b6116f98383612475565b61170383836124f6565b9392505050565b610ebf82826110c2565b61171e8383612475565b610d728383604051611731929190613f8b565b60405180910390208233610d77565b610ebf828233611763565b60008281526001602052604081206117039083612698565b61176d8383612475565b6000838360405161177f929190613f8b565b60405180910390209050611795848483856126a4565b6040805160608101825265ffffffffffff438116825242811660208084019182526001600160a01b038088168587019081526000888152600690935295822094518554935196519091166c01000000000000000000000000026bffffffffffffffffffffffff9685166601000000000000027fffffffffffffffffffffffffffffffffffffffff0000000000000000000000009094169190941617919091179390931617905561184985601e013560601c90565b9050604685013560601c607a86013561012e8701356001600160a01b03808516908716867ff8ae392d784b1ea5e8881bfa586d81abf07ef4f1e2fc75f7fe51c90f05199a5c60028c013560e01c6040805163ffffffff92909216825260328e0135606090811c60208401526001600160a01b038a1683830152605a8f0135908301526080820188905260a08201879052519081900360c00190a47fffffffffffffffffffffffff11111111111111111111111111111111111111126001600160a01b0384160161198957801561194b576040517f846dedc000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b813414611984576040517f81de0bf300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6119d7565b8034146119c2576040517f81de0bf300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6119d76001600160a01b038416338685612839565b3660006119e48a8a612872565b90925090508015611a01576119fc868686858561288e565b611a11565b3415611a1157611a118634612216565b50505050505050505050565b60008281526005602052604081206002815460ff166004811115611a4357611a43613585565b14611a7a576040517f4145817200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80546001600160a01b038481166c010000000000000000000000009092041614611ad0576040517f4af43a9000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b546107086501000000000090910466ffffffffffffff908116420316119392505050565b6040805161018081018252600080825260208201819052818301819052606082018190526080820181905260a0820181905260c0820181905260e0820181905261010082018190526101208201819052610140820181905261016082015290517f5aa6ccba0000000000000000000000000000000000000000000000000000000081523090635aa6ccba90611b8f9086908690600401614008565b600060405180830381865afa925050508015611bcd57506040513d6000823e601f3d908101601f19168201604052611bca9190810190614077565b60015b611be457611bdd828401846141ac565b9050610c64565b604051806101800160405280826000015163ffffffff168152602001826020015163ffffffff16815260200182604001516001600160a01b0316815260200182606001516001600160a01b0316815260200182608001516001600160a01b031681526020018260a001516001600160a01b031681526020018260c0015181526020018260e0015181526020018261010001518152602001826101a0015160001415151581526020018261012001518152602001826101400151815250915050610c64565b7f043c983c49d46f0e102151eaf8085d4a2e6571d5df2d47b013f39bddfd4a639d611cd28161220c565b600082815260056020526040902080546c0100000000000000000000000081046001600160a01b03169060ff81169065010000000000900466ffffffffffffff166002826004811115611d2757611d27613585565b14611d5e576040517f4145817200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6107084282900366ffffffffffffff161115611da6576040517f3e908aac00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b835464ffffffff001660011784556040516001600160a01b0384169087907f0695cf1d39b3055dcd0fe02d8b47eaf0d5a13e1996de925de59d0ef9b7f7fad490600090a3505050505050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f55611e1c8161220c565b612710821115611e58576040517f9b569b8100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600280549083905560408051828152602081018590527f14914da2bf76024616fbe1859783fcd4dbddcb179b1f3a854949fbf920dcb957910160405180910390a1505050565b80516000906001600160a01b031615611ec3576020820151611ec09042614278565b90505b611ece8383836129ea565b6000611ee284606001518560a00151612c6e565b90506000806002541115611f1b57620f424060025483611f0291906142a0565b611f0c91906142b7565b9050611f1881836142f2565b91505b6000612024604051806101e001604052804663ffffffff168152602001886000015163ffffffff16815260200188602001516001600160a01b0316815260200188604001516001600160a01b0316815260200188606001516001600160a01b0316815260200188608001516001600160a01b031681526020018581526020018860c0015181526020018481526020018861010001518152602001600760008a602001516001600160a01b03166001600160a01b031681526020019081526020016000206000815480929190611fef90614305565b90915550815287516001600160a01b031660208201526040810187905260608089015190820152608080890151910152612e81565b805160208083019190912060008181526005835260409081902080548b5163ffffffff8116610100027fffffffffffffffffffffffffffffffffffffffffffffffffffffff000000000090921691909117600117909155928a01516060808c015160808d015160c08e0151928d0151945197985094966001600160a01b039093169587957f120ea0364f36cdac7983bcfdd55270ca09d7f9b314a2ebc425a3b01ab1d6403a956120e0958b959394938e9290919015159061433d565b60405180910390a3807f3120e2bb59c86aca6890191a589a96af3662838efa374fbdcdf4c95bfe4a6c0e876040015160405161211c9190614393565b60405180910390a250505050505050565b610ebf8282600061136e565b6000818152600160205260408120610c6490612fc6565b60008281526020819052604090206001015461216b8161220c565b610d708383612406565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f7965db0b000000000000000000000000000000000000000000000000000000001480610c6457507f01ffc9a7000000000000000000000000000000000000000000000000000000007fffffffff00000000000000000000000000000000000000000000000000000000831614610c64565b61163a8133612fd0565b80471015612257576040517fcd7860590000000000000000000000000000000000000000000000000000000081523060048201526024015b60405180910390fd5b6000826001600160a01b03168260405160006040518083038185875af1925050503d80600081146122a4576040519150601f19603f3d011682016040523d82523d6000602084013e6122a9565b606091505b5050905080610d72576040517f1425ea4200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040516001600160a01b03838116602483015260448201839052610d7291859182169063a9059cbb906064015b604051602081830303815290604052915060e01b6020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff838183161783525050505061303c565b610e10811015612394576040517f0e0ea5c700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600480549082905560408051828152602081018490527f909f9078b2f6eac1d10f2aae793656c5a67511eb627ebd1d2cb1eb9c0ab94c95910160405180910390a15050565b6000806123e684846130b8565b905080156117035760008481526001602052604090206110ba9084613180565b6000806124138484613195565b905080156117035760008481526001602052604090206110ba9084613236565b8051156124435780518082602001fd5b6040517f5ead5a9d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61014e8110156124b1576040517f6ee0e17100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b813560f01c60028114610d72576040517f8bd977e700000000000000000000000000000000000000000000000000000000815261ffff8216600482015260240161224e565b6125a8604051806101e00160405280600063ffffffff168152602001600063ffffffff16815260200160006001600160a01b0316815260200160006001600160a01b0316815260200160006001600160a01b0316815260200160006001600160a01b03168152602001600081526020016000815260200160008152602001600081526020016000815260200160006001600160a01b031681526020016000815260200160008152602001606081525090565b600283013560e090811c82526006840135811c6020830152600a840135606090811c6040840152601e850135811c818401526032850135811c60808401526046850135811c60a0840152605a85013560c0840152607a85013591830191909152609a84013561010083015260ba84013561012083015260da84013561014083015260fa840135901c61016082015261010e83013561018082015261012e8301356101a08201526126588383612872565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152505050506101c082015292915050565b6000611703838361324b565b6001600160a01b0381166126e4576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000828152600660205260409020546c0100000000000000000000000090046001600160a01b031615612743576040517fbef7bb7d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600684013560e01c4614612783576040517f7029fdf900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60ba8401354211156127c1576040517f559895a300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60fa84013560601c80158015906127ea5750816001600160a01b0316816001600160a01b031614155b80156127fb575061010e8501354211155b15612832576040517f14be123200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5050505050565b6040516001600160a01b038481166024830152838116604483015260648201839052610d709186918216906323b872dd90608401612311565b3660006128838361014e81876143a6565b915091509250929050565b600061290986868686866040516024016128ab94939291906143d0565b60408051601f198184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fe85e13dd0000000000000000000000000000000000000000000000000000000017905234613275565b90508051600003612946576040517f1a95ad2600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8051602014612981576040517ff3725cca00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7fe85e13dd000000000000000000000000000000000000000000000000000000006129ab826143f9565b146129e2576040517ff3725cca00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b505050505050565b46836000015163ffffffff1603612a2d576040517f7029fdf900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60a08301511580612a40575060c0830151155b15612a77576040517fe38820c800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60208301516001600160a01b03161580612a9c575060408301516001600160a01b0316155b15612ad3576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60608301516001600160a01b03161580612af8575060808301516001600160a01b0316155b15612b2f576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b612b3b61070842613fca565b8361010001511015612b79576040517f04b7fcc800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61ffff8260800151511115612bba576040517f177a70e100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b606082015115801590612bed575060808301516001600160a01b031673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee145b15612c24576040517f846dedc000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000811280612c37575082610100015181135b15610d72576040517f352807b900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60007fffffffffffffffffffffffff11111111111111111111111111111111111111126001600160a01b03841601612ce057348214612cd9576040517f81de0bf300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5034610c64565b3415612d18576040517f81de0bf300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b826001600160a01b03163b600003612d5c576040517f7f523fe800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201526001600160a01b038416906370a0823190602401602060405180830381865afa158015612db9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612ddd919061443e565b9050612df46001600160a01b038416333085612839565b6040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015281906001600160a01b038516906370a0823190602401602060405180830381865afa158015612e53573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612e77919061443e565b61170391906142f2565b8051602080830151604080850151606086810151608088015160a089015160c08a015195517e02000000000000000000000000000000000000000000000000000000000000988101989098527fffffffff0000000000000000000000000000000000000000000000000000000060e0998a1b811660228a01529690981b90951660268701527fffffffffffffffffffffffffffffffffffffffff00000000000000000000000092821b8316602a870152811b8216603e86015292831b8116605285015293821b9093166066830152607a820192909252600090609a0160408051601f198184030181529082905260e08501516101008601516101208701516101408801516101608901516101808a01516101a08b01516101c08c0151979950612faf988a9890602001614457565b604051602081830303815290604052915050919050565b6000610c64825490565b6000828152602081815260408083206001600160a01b038516845290915290205460ff16610ebf576040517fe2517d3f0000000000000000000000000000000000000000000000000000000081526001600160a01b03821660048201526024810183905260440161224e565b60006130516001600160a01b0384168361332b565b9050805160001415801561307657508080602001905181019061307491906144e0565b155b15610d72576040517f5274afe70000000000000000000000000000000000000000000000000000000081526001600160a01b038416600482015260240161224e565b6000828152602081815260408083206001600160a01b038516845290915281205460ff16613178576000838152602081815260408083206001600160a01b0386168452909152902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790556131303390565b6001600160a01b0316826001600160a01b0316847f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a4506001610c64565b506000610c64565b6000611703836001600160a01b038416613339565b6000828152602081815260408083206001600160a01b038516845290915281205460ff1615613178576000838152602081815260408083206001600160a01b038616808552925280832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016905551339286917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a4506001610c64565b6000611703836001600160a01b038416613380565b600082600001828154811061326257613262613ef7565b9060005260206000200154905092915050565b6060814710156132b3576040517fcd78605900000000000000000000000000000000000000000000000000000000815230600482015260240161224e565b600080856001600160a01b031684866040516132cf91906144fd565b60006040518083038185875af1925050503d806000811461330c576040519150601f19603f3d011682016040523d82523d6000602084013e613311565b606091505b5091509150613321868383613473565b9695505050505050565b606061170383836000613275565b600081815260018301602052604081205461317857508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155610c64565b600081815260018301602052604081205480156134695760006133a46001836142f2565b85549091506000906133b8906001906142f2565b905080821461341d5760008660000182815481106133d8576133d8613ef7565b90600052602060002001549050808760000184815481106133fb576133fb613ef7565b6000918252602080832090910192909255918252600188019052604090208390555b855486908061342e5761342e614519565b600190038181906000526020600020016000905590558560010160008681526020019081526020016000206000905560019350505050610c64565b6000915050610c64565b60608261348857613483826134e8565b611703565b815115801561349f57506001600160a01b0384163b155b156134e1576040517f9996b3150000000000000000000000000000000000000000000000000000000081526001600160a01b038516600482015260240161224e565b5080611703565b8051156134f85780518082602001fd5b6040517f1425ea4200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006020828403121561353c57600080fd5b81357fffffffff000000000000000000000000000000000000000000000000000000008116811461170357600080fd5b60006020828403121561357e57600080fd5b5035919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b600581106135eb577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b9052565b60208101610c6482846135b4565b6001600160a01b038116811461163a57600080fd5b803561361d816135fd565b919050565b6000806040838503121561363557600080fd5b8235613640816135fd565b91506020830135613650816135fd565b809150509250929050565b60008060006060848603121561367057600080fd5b83359250602084013591506040840135613689816135fd565b809150509250925092565b6000602082840312156136a657600080fd5b8135611703816135fd565b600080604083850312156136c457600080fd5b823591506020830135613650816135fd565b801515811461163a57600080fd5b803561361d816136d6565b60008060006040848603121561370457600080fd5b833567ffffffffffffffff8082111561371c57600080fd5b818601915086601f83011261373057600080fd5b81358181111561373f57600080fd5b8760208260051b850101111561375457600080fd5b60209283019550935050840135613689816136d6565b60005b8381101561378557818101518382015260200161376d565b50506000910152565b600081518084526137a681602086016020860161376a565b601f01601f19169290920160200192915050565b600060208083018184528085518083526040925060408601915060408160051b87010184880160005b83811015613842578883037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc0018552815180511515845287015187840187905261382f8785018261378e565b95880195935050908601906001016137e3565b509098975050505050505050565b60008083601f84011261386257600080fd5b50813567ffffffffffffffff81111561387a57600080fd5b60208301915083602082850101111561389257600080fd5b9250929050565b600080602083850312156138ac57600080fd5b823567ffffffffffffffff8111156138c357600080fd5b6138cf85828601613850565b90969095509350505050565b6000806000604084860312156138f057600080fd5b833567ffffffffffffffff81111561390757600080fd5b61391386828701613850565b9094509250506020840135613689816135fd565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051610120810167ffffffffffffffff8111828210171561397a5761397a613927565b60405290565b60405160a0810167ffffffffffffffff8111828210171561397a5761397a613927565b6040516101e0810167ffffffffffffffff8111828210171561397a5761397a613927565b604051610180810167ffffffffffffffff8111828210171561397a5761397a613927565b604051601f8201601f1916810167ffffffffffffffff81118282101715613a1457613a14613927565b604052919050565b63ffffffff8116811461163a57600080fd5b803561361d81613a1c565b60006101208284031215613a4c57600080fd5b613a54613956565b9050613a5f82613a2e565b8152613a6d60208301613612565b6020820152613a7e60408301613612565b6040820152613a8f60608301613612565b6060820152613aa060808301613612565b608082015260a082013560a082015260c082013560c0820152613ac560e083016136e4565b60e082015261010080830135818301525092915050565b60006101208284031215613aef57600080fd5b6117038383613a39565b60208152613b1060208201835163ffffffff169052565b60006020830151613b29604084018263ffffffff169052565b5060408301516001600160a01b03811660608401525060608301516001600160a01b03811660808401525060808301516001600160a01b03811660a08401525060a08301516001600160a01b03811660c08401525060c083015160e08381019190915283015161010080840191909152830151610120808401919091528301516101408084019190915283015161016080840191909152830151610180613bda818501836001600160a01b03169052565b8401516101a0848101919091528401516101c0808501919091528401516101e0808501529050613c0e61020084018261378e565b949350505050565b60808101613c2482876135b4565b63ffffffff8516602083015266ffffffffffffff841660408301526001600160a01b038316606083015295945050505050565b600080600060408486031215613c6c57600080fd5b833567ffffffffffffffff811115613c8357600080fd5b613c8f86828701613850565b909790965060209590950135949350505050565b60008060408385031215613cb657600080fd5b50508035926020909101359150565b815163ffffffff16815261018081016020830151613ceb602084018263ffffffff169052565b506040830151613d0660408401826001600160a01b03169052565b506060830151613d2160608401826001600160a01b03169052565b506080830151613d3c60808401826001600160a01b03169052565b5060a0830151613d5760a08401826001600160a01b03169052565b5060c083015160c083015260e083015160e083015261010080840151818401525061012080840151613d8c8285018215159052565b5050610140838101519083015261016092830151929091019190915290565b600067ffffffffffffffff821115613dc557613dc5613927565b50601f01601f191660200190565b600082601f830112613de457600080fd5b8135613df7613df282613dab565b6139eb565b818152846020838601011115613e0c57600080fd5b816020850160208301376000918101602001919091529392505050565b6000806101408385031215613e3d57600080fd5b613e478484613a39565b915061012083013567ffffffffffffffff80821115613e6557600080fd5b9084019060a08287031215613e7957600080fd5b613e81613980565b8235613e8c816135fd565b815260208381013590820152604083013582811115613eaa57600080fd5b613eb688828601613dd3565b60408301525060608301356060820152608083013582811115613ed857600080fd5b613ee488828601613dd3565b6080830152508093505050509250929050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112613f5b57600080fd5b83018035915067ffffffffffffffff821115613f7657600080fd5b60200191503681900382131561389257600080fd5b8183823760009101908152919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b80820180821115610c6457610c64613f9b565b818352818160208501375060006020828401015260006020601f19601f840116840101905092915050565b602081526000613c0e602083018486613fdd565b805161361d81613a1c565b805161361d816135fd565b600082601f83011261404357600080fd5b8151614051613df282613dab565b81815284602083860101111561406657600080fd5b613c0e82602083016020870161376a565b60006020828403121561408957600080fd5b815167ffffffffffffffff808211156140a157600080fd5b908301906101e082860312156140b657600080fd5b6140be6139a3565b6140c78361401c565b81526140d56020840161401c565b60208201526140e660408401614027565b60408201526140f760608401614027565b606082015261410860808401614027565b608082015261411960a08401614027565b60a082015260c0838101519082015260e08084015190820152610100808401519082015261012080840151908201526101408084015190820152610160614161818501614027565b9082015261018083810151908201526101a080840151908201526101c0808401518381111561418f57600080fd5b61419b88828701614032565b918301919091525095945050505050565b600061018082840312156141bf57600080fd5b6141c76139c7565b6141d083613a2e565b81526141de60208401613a2e565b60208201526141ef60408401613612565b604082015261420060608401613612565b606082015261421160808401613612565b608082015261422260a08401613612565b60a082015260c083013560c082015260e083013560e08201526101008084013581830152506101206142558185016136e4565b908201526101408381013590820152610160928301359281019290925250919050565b808201828112600083128015821682158216171561429857614298613f9b565b505092915050565b8082028115828204841417610c6457610c64613f9b565b6000826142ed577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b81810381811115610c6457610c64613f9b565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820361433657614336613f9b565b5060010190565b60e08152600061435060e083018a61378e565b63ffffffff989098166020830152506001600160a01b039586166040820152939094166060840152608083019190915260a082015290151560c090910152919050565b602081526000611703602083018461378e565b600080858511156143b657600080fd5b838611156143c357600080fd5b5050820193919092039150565b6001600160a01b0385168152836020820152606060408201526000613321606083018486613fdd565b80516020808301519190811015614438577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8160200360031b1b821691505b50919050565b60006020828403121561445057600080fd5b5051919050565b60008a51614469818460208f0161376a565b80830190508a81528960208201528860408201528760608201527fffffffffffffffffffffffffffffffffffffffff0000000000000000000000008760601b1660808201528560948201528460b482015283516144cd8160d484016020880161376a565b0160d4019b9a5050505050505050505050565b6000602082840312156144f257600080fd5b8151611703816136d6565b6000825161450f81846020870161376a565b9190910192915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fdfea2646970667358221220ff0963a32deca1c739f82fff423c2a4ab1b1e197296c902578ae57133c488fd564736f6c63430008180033","runtime-code":"0x60806040526004361061034a5760003560e01c80638379a24f116101bb578063ac11fb1a116100f7578063c79371b111610095578063d547741f1161006f578063d547741f14610b59578063dc9a4ef614610b79578063dcf844a714610bad578063e00a83e014610bda57600080fd5b8063c79371b114610a78578063ca15c87314610b05578063ccc5749014610b2557600080fd5b8063b13aa2d6116100d1578063b13aa2d614610a0e578063bf333f2c14610a2e578063bfc7c60714610a45578063c63ff8dd14610a5857600080fd5b8063ac11fb1a1461098d578063add98c70146109ba578063affed0e0146109da57600080fd5b8063922b748711610164578063a217fddf1161013e578063a217fddf14610924578063a3ec191a14610939578063a5bbe22b14610769578063aa9641ab1461096d57600080fd5b8063922b7487146108e4578063930ac180146108fa5780639c9545f01461091157600080fd5b80639010d07c116101955780639010d07c146107fa57806391ad50391461081a57806391d14854146108a057600080fd5b80638379a24f1461077f578063886d36ff146107c75780638f0d6f17146107e757600080fd5b8063385c1d2f1161028a57806358f858801161023357806363787e521161020d57806363787e52146106a5578063638a0f091461071f5780637ebe815c14610735578063820688d51461076957600080fd5b806358f85880146106425780635aa6ccba146106585780635eb7d9461461068557600080fd5b806341fcb6121161026457806341fcb612146105f9578063458516941461061957806354eff0681461062c57600080fd5b8063385c1d2f1461058c5780633c5beeb4146105b95780633f61331d146105d957600080fd5b80630f862f1e116102f7578063248a9ca3116102d1578063248a9ca3146104ef578063295710ff1461051f5780632f2ff15d1461054c57806336568abe1461056c57600080fd5b80630f862f1e1461046f57806318e4357d146104af5780631ea327c5146104cf57600080fd5b8063051287bc11610328578063051287bc146103fa57806306f333f2146104375780630f5f6ed71461045957600080fd5b806301ffc9a71461034f57806302d2ff661461038457806303ed0ee5146103c6575b600080fd5b34801561035b57600080fd5b5061036f61036a36600461352a565b610c0e565b60405190151581526020015b60405180910390f35b34801561039057600080fd5b506103b87febfdca8e46c0b8dacf9989ee613e35727eadd20a1d5e5ad01a53968c7e5fe07a81565b60405190815260200161037b565b3480156103d257600080fd5b506103b87f043c983c49d46f0e102151eaf8085d4a2e6571d5df2d47b013f39bddfd4a639d81565b34801561040657600080fd5b5061042a61041536600461356c565b60009081526005602052604090205460ff1690565b60405161037b91906135ef565b34801561044357600080fd5b50610457610452366004613622565b610c6a565b005b34801561046557600080fd5b506103b861271081565b34801561047b57600080fd5b5061049773eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee81565b6040516001600160a01b03909116815260200161037b565b3480156104bb57600080fd5b506104576104ca36600461365b565b610d77565b3480156104db57600080fd5b506104576104ea36600461356c565b610e8c565b3480156104fb57600080fd5b506103b861050a36600461356c565b60009081526020819052604090206001015490565b34801561052b57600080fd5b506103b861053a366004613694565b60076020526000908152604090205481565b34801561055857600080fd5b506104576105673660046136b1565b610ec3565b34801561057857600080fd5b506104576105873660046136b1565b610ee8565b34801561059857600080fd5b506105ac6105a73660046136ef565b610f34565b60405161037b91906137ba565b3480156105c557600080fd5b506104576105d4366004613899565b6110c2565b3480156105e557600080fd5b506104576105f43660046136ef565b6112c4565b34801561060557600080fd5b506104576106143660046138db565b61136e565b610457610627366004613adc565b6115e0565b34801561063857600080fd5b506103b861ffff81565b34801561064e57600080fd5b506103b860025481565b34801561066457600080fd5b50610678610673366004613899565b61163d565b60405161037b9190613af9565b34801561069157600080fd5b506104576106a0366004613899565b61170a565b3480156106b157600080fd5b5061070f6106c036600461356c565b60056020526000908152604090205460ff811690610100810463ffffffff169065010000000000810466ffffffffffffff16906c0100000000000000000000000090046001600160a01b031684565b60405161037b9493929190613c16565b34801561072b57600080fd5b506103b860045481565b34801561074157600080fd5b506103b87f9a04aea0a349253cc7277afafdf6ead6729a3972a47ffb40eaef2c93d4e1bfea81565b34801561077557600080fd5b506103b861070881565b34801561078b57600080fd5b5061036f61079a36600461356c565b6000908152600660205260409020546c0100000000000000000000000090046001600160a01b0316151590565b3480156107d357600080fd5b506104576107e2366004613c57565b611714565b6104576107f5366004613899565b611740565b34801561080657600080fd5b50610497610815366004613ca3565b61174b565b34801561082657600080fd5b5061087461083536600461356c565b60009081526005602052604090205465010000000000810466ffffffffffffff16916c010000000000000000000000009091046001600160a01b031690565b604080516bffffffffffffffffffffffff90931683526001600160a01b0390911660208301520161037b565b3480156108ac57600080fd5b5061036f6108bb3660046136b1565b6000918252602082815260408084206001600160a01b0393909316845291905290205460ff1690565b3480156108f057600080fd5b506103b8610e1081565b34801561090657600080fd5b506103b86201518081565b61045761091f3660046138db565b611763565b34801561093057600080fd5b506103b8600081565b34801561094557600080fd5b506103b87f000000000000000000000000000000000000000000000000000000000000000081565b34801561097957600080fd5b5061036f6109883660046136b1565b611a1d565b34801561099957600080fd5b506109ad6109a8366004613899565b611af4565b60405161037b9190613cc5565b3480156109c657600080fd5b506104576109d536600461356c565b611ca8565b3480156109e657600080fd5b506103b87f000000000000000000000000000000000000000000000000000000000000000081565b348015610a1a57600080fd5b50610457610a2936600461356c565b611df2565b348015610a3a57600080fd5b506103b8620f424081565b610457610a53366004613e29565b611e9e565b348015610a6457600080fd5b50610457610a73366004613899565b61212d565b348015610a8457600080fd5b50610ad7610a9336600461356c565b60066020526000908152604090205465ffffffffffff8082169166010000000000008104909116906c0100000000000000000000000090046001600160a01b031683565b6040805165ffffffffffff94851681529390921660208401526001600160a01b03169082015260600161037b565b348015610b1157600080fd5b506103b8610b2036600461356c565b612139565b348015610b3157600080fd5b506103b87f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f5581565b348015610b6557600080fd5b50610457610b743660046136b1565b612150565b348015610b8557600080fd5b506103b87f60044782a422109ac08a415e44260ad5d3bad63d96ebe1fac0363399642ee3f281565b348015610bb957600080fd5b506103b8610bc8366004613694565b60036020526000908152604090205481565b348015610be657600080fd5b506103b87f000000000000000000000000000000000000000000000000000000000000000081565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f5a05180f000000000000000000000000000000000000000000000000000000001480610c645750610c6482612175565b92915050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f55610c948161220c565b6001600160a01b03831660009081526003602052604081205490819003610cbb5750505050565b6001600160a01b038481166000818152600360209081526040808320929092558151928352928616928201929092529081018290527f244e51bc38c1452fa8aaf487bcb4bca36c2baa3a5fbdb776b1eabd8dc6d277cd9060600160405180910390a17fffffffffffffffffffffffff11111111111111111111111111111111111111126001600160a01b03851601610d5c57610d578382612216565b610d70565b610d706001600160a01b03851684836122e4565b505b505050565b7f60044782a422109ac08a415e44260ad5d3bad63d96ebe1fac0363399642ee3f2610da18161220c565b60008481526005602052604090206001815460ff166004811115610dc757610dc7613585565b14610dfe576040517f4145817200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80546001600160a01b0384166c0100000000000000000000000081026bffffffffffffffffffffffff66ffffffffffffff421665010000000000021664ffffffff009093169290921791909117600217825560405185815286907f4ac8af8a2cd87193d64dfc7a3b8d9923b714ec528b18725d080aa1299be0c5e49060200160405180910390a35050505050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f55610eb68161220c565b610ebf82612358565b5050565b600082815260208190526040902060010154610ede8161220c565b610d7083836123d9565b6001600160a01b0381163314610f2a576040517f6697b23200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610d728282612406565b60608267ffffffffffffffff811115610f4f57610f4f613927565b604051908082528060200260200182016040528015610f9557816020015b604080518082019091526000815260606020820152815260200190600190039081610f6d5790505b50905060005b838110156110ba5730858583818110610fb657610fb6613ef7565b9050602002810190610fc89190613f26565b604051610fd6929190613f8b565b600060405180830381855af49150503d8060008114611011576040519150601f19603f3d011682016040523d82523d6000602084013e611016565b606091505b5083838151811061102957611029613ef7565b602002602001015160000184848151811061104657611046613ef7565b60200260200101516020018290528215151515815250505081818151811061107057611070613ef7565b602002602001015160000151158015611087575082155b156110b2576110b28282815181106110a1576110a1613ef7565b602002602001015160200151612433565b600101610f9b565b509392505050565b6110cc8282612475565b600082826040516110de929190613f8b565b604080519182900390912060008181526005602052919091209091506001815460ff16600481111561111257611112613585565b14611149576040517f4145817200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b3360009081527f4527d8b28c468984933d33ae052f26b21c15ca0e7fdec762bba08e540e237001602052604090205460ba8501359060ff16611195576004546111929082613fca565b90505b8042116111ce576040517fe15ff9ea00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b81547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166004178255600a850135606090811c906032870135901c600061121d609a890135605a8a0135613fca565b604080516001600160a01b03858116825260208201849052825193945086169289927fb4c55c0c9bc613519b920e88748090150b890a875d307f21bea7d4fb2e8bc958928290030190a37fffffffffffffffffffffffff11111111111111111111111111111111111111126001600160a01b038316016112a6576112a18382612216565b6112ba565b6112ba6001600160a01b03831684836122e4565b5050505050505050565b60005b82811015610d7057600080308686858181106112e5576112e5613ef7565b90506020028101906112f79190613f26565b604051611305929190613f8b565b600060405180830381855af49150503d8060008114611340576040519150601f19603f3d011682016040523d82523d6000602084013e611345565b606091505b509150915081158015611356575083155b156113645761136481612433565b50506001016112c7565b6113788383612475565b6000838360405161138a929190613f8b565b604080519182900390912060008181526005602052919091208054919250906c0100000000000000000000000081046001600160a01b03169060ff81169065010000000000900466ffffffffffffff1660028260048111156113ee576113ee613585565b14611425576040517f4145817200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6107084282900366ffffffffffffff161161146c576040517f1992d0bd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600160a01b038616611482578295506114c4565b6001600160a01b03831633146114c4576040517f4af43a9000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b83547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166003178455603288013560601c605a890135609a8a01358015611533576001600160a01b0383166000908152600360205260408120805483929061152d908490613fca565b90915550505b604080516001600160a01b03858116825260208201859052808c1692908916918b917f582211c35a2139ac3bbaac74663c6a1f56c6cbb658b41fe11fd45a82074ac678910160405180910390a47fffffffffffffffffffffffff11111111111111111111111111111111111111126001600160a01b038416016115bf576115ba8983612216565b6115d3565b6115d36001600160a01b0384168a846122e4565b5050505050505050505050565b61163a816040518060a0016040528060006001600160a01b03168152602001600081526020016040518060200160405280600081525081526020016000815260200160405180602001604052806000815250815250611e9e565b50565b6116ef604051806101e00160405280600063ffffffff168152602001600063ffffffff16815260200160006001600160a01b0316815260200160006001600160a01b0316815260200160006001600160a01b0316815260200160006001600160a01b03168152602001600081526020016000815260200160008152602001600081526020016000815260200160006001600160a01b031681526020016000815260200160008152602001606081525090565b6116f98383612475565b61170383836124f6565b9392505050565b610ebf82826110c2565b61171e8383612475565b610d728383604051611731929190613f8b565b60405180910390208233610d77565b610ebf828233611763565b60008281526001602052604081206117039083612698565b61176d8383612475565b6000838360405161177f929190613f8b565b60405180910390209050611795848483856126a4565b6040805160608101825265ffffffffffff438116825242811660208084019182526001600160a01b038088168587019081526000888152600690935295822094518554935196519091166c01000000000000000000000000026bffffffffffffffffffffffff9685166601000000000000027fffffffffffffffffffffffffffffffffffffffff0000000000000000000000009094169190941617919091179390931617905561184985601e013560601c90565b9050604685013560601c607a86013561012e8701356001600160a01b03808516908716867ff8ae392d784b1ea5e8881bfa586d81abf07ef4f1e2fc75f7fe51c90f05199a5c60028c013560e01c6040805163ffffffff92909216825260328e0135606090811c60208401526001600160a01b038a1683830152605a8f0135908301526080820188905260a08201879052519081900360c00190a47fffffffffffffffffffffffff11111111111111111111111111111111111111126001600160a01b0384160161198957801561194b576040517f846dedc000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b813414611984576040517f81de0bf300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6119d7565b8034146119c2576040517f81de0bf300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6119d76001600160a01b038416338685612839565b3660006119e48a8a612872565b90925090508015611a01576119fc868686858561288e565b611a11565b3415611a1157611a118634612216565b50505050505050505050565b60008281526005602052604081206002815460ff166004811115611a4357611a43613585565b14611a7a576040517f4145817200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80546001600160a01b038481166c010000000000000000000000009092041614611ad0576040517f4af43a9000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b546107086501000000000090910466ffffffffffffff908116420316119392505050565b6040805161018081018252600080825260208201819052818301819052606082018190526080820181905260a0820181905260c0820181905260e0820181905261010082018190526101208201819052610140820181905261016082015290517f5aa6ccba0000000000000000000000000000000000000000000000000000000081523090635aa6ccba90611b8f9086908690600401614008565b600060405180830381865afa925050508015611bcd57506040513d6000823e601f3d908101601f19168201604052611bca9190810190614077565b60015b611be457611bdd828401846141ac565b9050610c64565b604051806101800160405280826000015163ffffffff168152602001826020015163ffffffff16815260200182604001516001600160a01b0316815260200182606001516001600160a01b0316815260200182608001516001600160a01b031681526020018260a001516001600160a01b031681526020018260c0015181526020018260e0015181526020018261010001518152602001826101a0015160001415151581526020018261012001518152602001826101400151815250915050610c64565b7f043c983c49d46f0e102151eaf8085d4a2e6571d5df2d47b013f39bddfd4a639d611cd28161220c565b600082815260056020526040902080546c0100000000000000000000000081046001600160a01b03169060ff81169065010000000000900466ffffffffffffff166002826004811115611d2757611d27613585565b14611d5e576040517f4145817200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6107084282900366ffffffffffffff161115611da6576040517f3e908aac00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b835464ffffffff001660011784556040516001600160a01b0384169087907f0695cf1d39b3055dcd0fe02d8b47eaf0d5a13e1996de925de59d0ef9b7f7fad490600090a3505050505050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f55611e1c8161220c565b612710821115611e58576040517f9b569b8100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600280549083905560408051828152602081018590527f14914da2bf76024616fbe1859783fcd4dbddcb179b1f3a854949fbf920dcb957910160405180910390a1505050565b80516000906001600160a01b031615611ec3576020820151611ec09042614278565b90505b611ece8383836129ea565b6000611ee284606001518560a00151612c6e565b90506000806002541115611f1b57620f424060025483611f0291906142a0565b611f0c91906142b7565b9050611f1881836142f2565b91505b6000612024604051806101e001604052804663ffffffff168152602001886000015163ffffffff16815260200188602001516001600160a01b0316815260200188604001516001600160a01b0316815260200188606001516001600160a01b0316815260200188608001516001600160a01b031681526020018581526020018860c0015181526020018481526020018861010001518152602001600760008a602001516001600160a01b03166001600160a01b031681526020019081526020016000206000815480929190611fef90614305565b90915550815287516001600160a01b031660208201526040810187905260608089015190820152608080890151910152612e81565b805160208083019190912060008181526005835260409081902080548b5163ffffffff8116610100027fffffffffffffffffffffffffffffffffffffffffffffffffffffff000000000090921691909117600117909155928a01516060808c015160808d015160c08e0151928d0151945197985094966001600160a01b039093169587957f120ea0364f36cdac7983bcfdd55270ca09d7f9b314a2ebc425a3b01ab1d6403a956120e0958b959394938e9290919015159061433d565b60405180910390a3807f3120e2bb59c86aca6890191a589a96af3662838efa374fbdcdf4c95bfe4a6c0e876040015160405161211c9190614393565b60405180910390a250505050505050565b610ebf8282600061136e565b6000818152600160205260408120610c6490612fc6565b60008281526020819052604090206001015461216b8161220c565b610d708383612406565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f7965db0b000000000000000000000000000000000000000000000000000000001480610c6457507f01ffc9a7000000000000000000000000000000000000000000000000000000007fffffffff00000000000000000000000000000000000000000000000000000000831614610c64565b61163a8133612fd0565b80471015612257576040517fcd7860590000000000000000000000000000000000000000000000000000000081523060048201526024015b60405180910390fd5b6000826001600160a01b03168260405160006040518083038185875af1925050503d80600081146122a4576040519150601f19603f3d011682016040523d82523d6000602084013e6122a9565b606091505b5050905080610d72576040517f1425ea4200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040516001600160a01b03838116602483015260448201839052610d7291859182169063a9059cbb906064015b604051602081830303815290604052915060e01b6020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff838183161783525050505061303c565b610e10811015612394576040517f0e0ea5c700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600480549082905560408051828152602081018490527f909f9078b2f6eac1d10f2aae793656c5a67511eb627ebd1d2cb1eb9c0ab94c95910160405180910390a15050565b6000806123e684846130b8565b905080156117035760008481526001602052604090206110ba9084613180565b6000806124138484613195565b905080156117035760008481526001602052604090206110ba9084613236565b8051156124435780518082602001fd5b6040517f5ead5a9d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61014e8110156124b1576040517f6ee0e17100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b813560f01c60028114610d72576040517f8bd977e700000000000000000000000000000000000000000000000000000000815261ffff8216600482015260240161224e565b6125a8604051806101e00160405280600063ffffffff168152602001600063ffffffff16815260200160006001600160a01b0316815260200160006001600160a01b0316815260200160006001600160a01b0316815260200160006001600160a01b03168152602001600081526020016000815260200160008152602001600081526020016000815260200160006001600160a01b031681526020016000815260200160008152602001606081525090565b600283013560e090811c82526006840135811c6020830152600a840135606090811c6040840152601e850135811c818401526032850135811c60808401526046850135811c60a0840152605a85013560c0840152607a85013591830191909152609a84013561010083015260ba84013561012083015260da84013561014083015260fa840135901c61016082015261010e83013561018082015261012e8301356101a08201526126588383612872565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152505050506101c082015292915050565b6000611703838361324b565b6001600160a01b0381166126e4576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000828152600660205260409020546c0100000000000000000000000090046001600160a01b031615612743576040517fbef7bb7d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600684013560e01c4614612783576040517f7029fdf900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60ba8401354211156127c1576040517f559895a300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60fa84013560601c80158015906127ea5750816001600160a01b0316816001600160a01b031614155b80156127fb575061010e8501354211155b15612832576040517f14be123200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5050505050565b6040516001600160a01b038481166024830152838116604483015260648201839052610d709186918216906323b872dd90608401612311565b3660006128838361014e81876143a6565b915091509250929050565b600061290986868686866040516024016128ab94939291906143d0565b60408051601f198184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fe85e13dd0000000000000000000000000000000000000000000000000000000017905234613275565b90508051600003612946576040517f1a95ad2600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8051602014612981576040517ff3725cca00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7fe85e13dd000000000000000000000000000000000000000000000000000000006129ab826143f9565b146129e2576040517ff3725cca00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b505050505050565b46836000015163ffffffff1603612a2d576040517f7029fdf900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60a08301511580612a40575060c0830151155b15612a77576040517fe38820c800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60208301516001600160a01b03161580612a9c575060408301516001600160a01b0316155b15612ad3576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60608301516001600160a01b03161580612af8575060808301516001600160a01b0316155b15612b2f576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b612b3b61070842613fca565b8361010001511015612b79576040517f04b7fcc800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61ffff8260800151511115612bba576040517f177a70e100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b606082015115801590612bed575060808301516001600160a01b031673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee145b15612c24576040517f846dedc000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000811280612c37575082610100015181135b15610d72576040517f352807b900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60007fffffffffffffffffffffffff11111111111111111111111111111111111111126001600160a01b03841601612ce057348214612cd9576040517f81de0bf300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5034610c64565b3415612d18576040517f81de0bf300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b826001600160a01b03163b600003612d5c576040517f7f523fe800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201526001600160a01b038416906370a0823190602401602060405180830381865afa158015612db9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612ddd919061443e565b9050612df46001600160a01b038416333085612839565b6040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015281906001600160a01b038516906370a0823190602401602060405180830381865afa158015612e53573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612e77919061443e565b61170391906142f2565b8051602080830151604080850151606086810151608088015160a089015160c08a015195517e02000000000000000000000000000000000000000000000000000000000000988101989098527fffffffff0000000000000000000000000000000000000000000000000000000060e0998a1b811660228a01529690981b90951660268701527fffffffffffffffffffffffffffffffffffffffff00000000000000000000000092821b8316602a870152811b8216603e86015292831b8116605285015293821b9093166066830152607a820192909252600090609a0160408051601f198184030181529082905260e08501516101008601516101208701516101408801516101608901516101808a01516101a08b01516101c08c0151979950612faf988a9890602001614457565b604051602081830303815290604052915050919050565b6000610c64825490565b6000828152602081815260408083206001600160a01b038516845290915290205460ff16610ebf576040517fe2517d3f0000000000000000000000000000000000000000000000000000000081526001600160a01b03821660048201526024810183905260440161224e565b60006130516001600160a01b0384168361332b565b9050805160001415801561307657508080602001905181019061307491906144e0565b155b15610d72576040517f5274afe70000000000000000000000000000000000000000000000000000000081526001600160a01b038416600482015260240161224e565b6000828152602081815260408083206001600160a01b038516845290915281205460ff16613178576000838152602081815260408083206001600160a01b0386168452909152902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790556131303390565b6001600160a01b0316826001600160a01b0316847f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a4506001610c64565b506000610c64565b6000611703836001600160a01b038416613339565b6000828152602081815260408083206001600160a01b038516845290915281205460ff1615613178576000838152602081815260408083206001600160a01b038616808552925280832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016905551339286917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a4506001610c64565b6000611703836001600160a01b038416613380565b600082600001828154811061326257613262613ef7565b9060005260206000200154905092915050565b6060814710156132b3576040517fcd78605900000000000000000000000000000000000000000000000000000000815230600482015260240161224e565b600080856001600160a01b031684866040516132cf91906144fd565b60006040518083038185875af1925050503d806000811461330c576040519150601f19603f3d011682016040523d82523d6000602084013e613311565b606091505b5091509150613321868383613473565b9695505050505050565b606061170383836000613275565b600081815260018301602052604081205461317857508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155610c64565b600081815260018301602052604081205480156134695760006133a46001836142f2565b85549091506000906133b8906001906142f2565b905080821461341d5760008660000182815481106133d8576133d8613ef7565b90600052602060002001549050808760000184815481106133fb576133fb613ef7565b6000918252602080832090910192909255918252600188019052604090208390555b855486908061342e5761342e614519565b600190038181906000526020600020016000905590558560010160008681526020019081526020016000206000905560019350505050610c64565b6000915050610c64565b60608261348857613483826134e8565b611703565b815115801561349f57506001600160a01b0384163b155b156134e1576040517f9996b3150000000000000000000000000000000000000000000000000000000081526001600160a01b038516600482015260240161224e565b5080611703565b8051156134f85780518082602001fd5b6040517f1425ea4200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006020828403121561353c57600080fd5b81357fffffffff000000000000000000000000000000000000000000000000000000008116811461170357600080fd5b60006020828403121561357e57600080fd5b5035919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b600581106135eb577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b9052565b60208101610c6482846135b4565b6001600160a01b038116811461163a57600080fd5b803561361d816135fd565b919050565b6000806040838503121561363557600080fd5b8235613640816135fd565b91506020830135613650816135fd565b809150509250929050565b60008060006060848603121561367057600080fd5b83359250602084013591506040840135613689816135fd565b809150509250925092565b6000602082840312156136a657600080fd5b8135611703816135fd565b600080604083850312156136c457600080fd5b823591506020830135613650816135fd565b801515811461163a57600080fd5b803561361d816136d6565b60008060006040848603121561370457600080fd5b833567ffffffffffffffff8082111561371c57600080fd5b818601915086601f83011261373057600080fd5b81358181111561373f57600080fd5b8760208260051b850101111561375457600080fd5b60209283019550935050840135613689816136d6565b60005b8381101561378557818101518382015260200161376d565b50506000910152565b600081518084526137a681602086016020860161376a565b601f01601f19169290920160200192915050565b600060208083018184528085518083526040925060408601915060408160051b87010184880160005b83811015613842578883037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc0018552815180511515845287015187840187905261382f8785018261378e565b95880195935050908601906001016137e3565b509098975050505050505050565b60008083601f84011261386257600080fd5b50813567ffffffffffffffff81111561387a57600080fd5b60208301915083602082850101111561389257600080fd5b9250929050565b600080602083850312156138ac57600080fd5b823567ffffffffffffffff8111156138c357600080fd5b6138cf85828601613850565b90969095509350505050565b6000806000604084860312156138f057600080fd5b833567ffffffffffffffff81111561390757600080fd5b61391386828701613850565b9094509250506020840135613689816135fd565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051610120810167ffffffffffffffff8111828210171561397a5761397a613927565b60405290565b60405160a0810167ffffffffffffffff8111828210171561397a5761397a613927565b6040516101e0810167ffffffffffffffff8111828210171561397a5761397a613927565b604051610180810167ffffffffffffffff8111828210171561397a5761397a613927565b604051601f8201601f1916810167ffffffffffffffff81118282101715613a1457613a14613927565b604052919050565b63ffffffff8116811461163a57600080fd5b803561361d81613a1c565b60006101208284031215613a4c57600080fd5b613a54613956565b9050613a5f82613a2e565b8152613a6d60208301613612565b6020820152613a7e60408301613612565b6040820152613a8f60608301613612565b6060820152613aa060808301613612565b608082015260a082013560a082015260c082013560c0820152613ac560e083016136e4565b60e082015261010080830135818301525092915050565b60006101208284031215613aef57600080fd5b6117038383613a39565b60208152613b1060208201835163ffffffff169052565b60006020830151613b29604084018263ffffffff169052565b5060408301516001600160a01b03811660608401525060608301516001600160a01b03811660808401525060808301516001600160a01b03811660a08401525060a08301516001600160a01b03811660c08401525060c083015160e08381019190915283015161010080840191909152830151610120808401919091528301516101408084019190915283015161016080840191909152830151610180613bda818501836001600160a01b03169052565b8401516101a0848101919091528401516101c0808501919091528401516101e0808501529050613c0e61020084018261378e565b949350505050565b60808101613c2482876135b4565b63ffffffff8516602083015266ffffffffffffff841660408301526001600160a01b038316606083015295945050505050565b600080600060408486031215613c6c57600080fd5b833567ffffffffffffffff811115613c8357600080fd5b613c8f86828701613850565b909790965060209590950135949350505050565b60008060408385031215613cb657600080fd5b50508035926020909101359150565b815163ffffffff16815261018081016020830151613ceb602084018263ffffffff169052565b506040830151613d0660408401826001600160a01b03169052565b506060830151613d2160608401826001600160a01b03169052565b506080830151613d3c60808401826001600160a01b03169052565b5060a0830151613d5760a08401826001600160a01b03169052565b5060c083015160c083015260e083015160e083015261010080840151818401525061012080840151613d8c8285018215159052565b5050610140838101519083015261016092830151929091019190915290565b600067ffffffffffffffff821115613dc557613dc5613927565b50601f01601f191660200190565b600082601f830112613de457600080fd5b8135613df7613df282613dab565b6139eb565b818152846020838601011115613e0c57600080fd5b816020850160208301376000918101602001919091529392505050565b6000806101408385031215613e3d57600080fd5b613e478484613a39565b915061012083013567ffffffffffffffff80821115613e6557600080fd5b9084019060a08287031215613e7957600080fd5b613e81613980565b8235613e8c816135fd565b815260208381013590820152604083013582811115613eaa57600080fd5b613eb688828601613dd3565b60408301525060608301356060820152608083013582811115613ed857600080fd5b613ee488828601613dd3565b6080830152508093505050509250929050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112613f5b57600080fd5b83018035915067ffffffffffffffff821115613f7657600080fd5b60200191503681900382131561389257600080fd5b8183823760009101908152919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b80820180821115610c6457610c64613f9b565b818352818160208501375060006020828401015260006020601f19601f840116840101905092915050565b602081526000613c0e602083018486613fdd565b805161361d81613a1c565b805161361d816135fd565b600082601f83011261404357600080fd5b8151614051613df282613dab565b81815284602083860101111561406657600080fd5b613c0e82602083016020870161376a565b60006020828403121561408957600080fd5b815167ffffffffffffffff808211156140a157600080fd5b908301906101e082860312156140b657600080fd5b6140be6139a3565b6140c78361401c565b81526140d56020840161401c565b60208201526140e660408401614027565b60408201526140f760608401614027565b606082015261410860808401614027565b608082015261411960a08401614027565b60a082015260c0838101519082015260e08084015190820152610100808401519082015261012080840151908201526101408084015190820152610160614161818501614027565b9082015261018083810151908201526101a080840151908201526101c0808401518381111561418f57600080fd5b61419b88828701614032565b918301919091525095945050505050565b600061018082840312156141bf57600080fd5b6141c76139c7565b6141d083613a2e565b81526141de60208401613a2e565b60208201526141ef60408401613612565b604082015261420060608401613612565b606082015261421160808401613612565b608082015261422260a08401613612565b60a082015260c083013560c082015260e083013560e08201526101008084013581830152506101206142558185016136e4565b908201526101408381013590820152610160928301359281019290925250919050565b808201828112600083128015821682158216171561429857614298613f9b565b505092915050565b8082028115828204841417610c6457610c64613f9b565b6000826142ed577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b81810381811115610c6457610c64613f9b565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820361433657614336613f9b565b5060010190565b60e08152600061435060e083018a61378e565b63ffffffff989098166020830152506001600160a01b039586166040820152939094166060840152608083019190915260a082015290151560c090910152919050565b602081526000611703602083018461378e565b600080858511156143b657600080fd5b838611156143c357600080fd5b5050820193919092039150565b6001600160a01b0385168152836020820152606060408201526000613321606083018486613fdd565b80516020808301519190811015614438577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8160200360031b1b821691505b50919050565b60006020828403121561445057600080fd5b5051919050565b60008a51614469818460208f0161376a565b80830190508a81528960208201528860408201528760608201527fffffffffffffffffffffffffffffffffffffffff0000000000000000000000008760601b1660808201528560948201528460b482015283516144cd8160d484016020880161376a565b0160d4019b9a5050505050505050505050565b6000602082840312156144f257600080fd5b8151611703816136d6565b6000825161450f81846020870161376a565b9190910192915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fdfea2646970667358221220ff0963a32deca1c739f82fff423c2a4ab1b1e197296c902578ae57133c488fd564736f6c63430008180033","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.24 ^0.8.20 ^0.8.4;\n\n// contracts/interfaces/IAdminV2.sol\n\ninterface IAdminV2 {\n event CancelDelayUpdated(uint256 oldCancelDelay, uint256 newCancelDelay);\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n function setCancelDelay(uint256 newCancelDelay) external;\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n}\n\n// contracts/interfaces/IAdminV2Errors.sol\n\ninterface IAdminV2Errors {\n error CancelDelayBelowMin();\n error FeeRateAboveMax();\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IFastBridgeV2Errors.sol\n\ninterface IFastBridgeV2Errors {\n error AmountIncorrect();\n error ChainIncorrect();\n error ExclusivityParamsIncorrect();\n error MsgValueIncorrect();\n error SenderIncorrect();\n error StatusIncorrect();\n error TokenNotContract();\n error ZapDataLengthAboveMax();\n error ZapNativeNotSupported();\n error ZeroAddress();\n\n error RecipientIncorrectReturnValue();\n error RecipientNoReturnValue();\n\n error DeadlineExceeded();\n error DeadlineNotExceeded();\n error DeadlineTooShort();\n error DisputePeriodNotPassed();\n error DisputePeriodPassed();\n error ExclusivityPeriodNotPassed();\n\n error TransactionRelayed();\n}\n\n// contracts/interfaces/IMulticallTarget.sol\n\n/// @notice Interface for a contract that can be called multiple times by the same caller. Inspired by MulticallV3:\n/// https://github.com/mds1/multicall/blob/master/src/Multicall3.sol\ninterface IMulticallTarget {\n struct Result {\n bool success;\n bytes returnData;\n }\n\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external;\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results);\n}\n\n// contracts/interfaces/IZapRecipient.sol\n\ninterface IZapRecipient {\n function zap(address token, uint256 amount, bytes memory zapData) external payable returns (bytes4);\n}\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// contracts/interfaces/IFastBridgeV2.sol\n\ninterface IFastBridgeV2 is IFastBridge {\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n struct BridgeTxDetails {\n BridgeStatus status;\n uint32 destChainId;\n uint56 proofBlockTimestamp;\n address proofRelayer;\n }\n\n struct BridgeRelay {\n uint48 blockNumber;\n uint48 blockTimestamp;\n address relayer;\n }\n\n /// @notice New params introduced in the FastBridgeV2.\n /// We are passing fields from the older BridgeParams struct outside of this struct\n /// for backwards compatibility.\n /// Note: quoteRelayer and quoteExclusivitySeconds are either both zero (indicating no exclusivity)\n /// or both non-zero (indicating exclusivity for the given period).\n /// Note: zapNative \u003e 0 can NOT be used with destToken = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE (native token)\n /// @param quoteRelayer Relayer that provided the quote for the transaction\n /// @param quoteExclusivitySeconds Period of time the quote relayer is guaranteed exclusivity after user's deposit\n /// @param quoteId Unique quote identifier used for tracking the quote\n /// @param zapNative ETH value to send to the recipient (if any)\n /// @param zapData Parameters for the Zap to the destination recipient (if any)\n struct BridgeParamsV2 {\n address quoteRelayer;\n int256 quoteExclusivitySeconds;\n bytes quoteId;\n uint256 zapNative;\n bytes zapData;\n }\n\n /// @notice Updated bridge transaction struct to include parameters introduced in FastBridgeV2.\n /// Note: only `exclusivityRelayer` can fill such a transaction until `exclusivityEndTime`.\n struct BridgeTransactionV2 {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n // Note: sendChainGas flag from V1 is deprecated\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n address exclusivityRelayer;\n uint256 exclusivityEndTime;\n uint256 zapNative; // ETH value to send to the recipient (if any)\n bytes zapData; // data to pass for the Zap action (if any)\n }\n\n event BridgeQuoteDetails(bytes32 indexed transactionId, bytes quoteId);\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability\n /// to provide temporary exclusivity fill rights for the quote relayer.\n /// @param params The parameters required to bridge\n /// @param paramsV2 The parameters for exclusivity fill rights (optional, can be left empty)\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function relay(bytes memory request, address relayer) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param transactionId The transaction id associated with the encoded bridge transaction to prove\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital.\n /// @notice Can only send funds to the relayer address on the proof.\n /// @param request The encoded bridge transaction to claim on origin chain\n function claim(bytes memory request) external;\n\n /// @notice Cancels an outstanding bridge transaction in case optimistic bridging failed and returns the full amount\n /// to the original sender.\n /// @param request The encoded bridge transaction to refund\n function cancel(bytes memory request) external;\n\n /// @notice Checks if a transaction has been relayed\n /// @param transactionId The ID of the transaction to check\n /// @return True if the transaction has been relayed, false otherwise\n function bridgeRelays(bytes32 transactionId) external view returns (bool);\n\n /// @notice Returns the status of a bridge transaction\n /// @param transactionId The ID of the bridge transaction\n /// @return BridgeStatus Status of the bridge transaction\n function bridgeStatuses(bytes32 transactionId) external view returns (BridgeStatus);\n\n /// @notice Returns the timestamp and relayer of a bridge proof\n /// @param transactionId The ID of the bridge transaction\n /// @return timestamp The timestamp of the bridge proof\n /// @return relayer The relayer address of the bridge proof\n function bridgeProofs(bytes32 transactionId) external view returns (uint96 timestamp, address relayer);\n\n /// @notice Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\n /// @param request The bridge request to decode\n function getBridgeTransactionV2(bytes memory request) external view returns (BridgeTransactionV2 memory);\n}\n\n// contracts/utils/MulticallTarget.sol\n\n// solhint-disable avoid-low-level-calls\n/// @notice Template for a contract that supports batched calls (preserving the msg.sender).\n/// Only calls with zero msg.value could be batched.\nabstract contract MulticallTarget is IMulticallTarget {\n error MulticallTarget__UndeterminedRevert();\n\n /// @notice Perform a batched call to this contract, preserving the msg.sender.\n /// The return data from each call is discarded.\n /// @dev The method is non-payable, so only calls with `msg.value == 0` could be batched.\n /// It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag.\n /// Otherwise, the whole batch call will be reverted with the original revert reason.\n /// @param data List of abi-encoded calldata for the calls to perform.\n /// @param ignoreReverts Whether to ignore the revert errors from the calls.\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external {\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\n if (!success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(result);\n }\n }\n }\n\n /// @notice Perform a batched call to this contract, preserving the msg.sender.\n /// The return data from each call is preserved.\n /// @dev The method is non-payable, so only calls with `msg.value == 0` could be batched.\n /// It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag.\n /// Otherwise, the whole batch call will be reverted with the original revert reason.\n /// @param data List of abi-encoded calldata for the calls to perform.\n /// @param ignoreReverts Whether to ignore the revert errors from the calls.\n /// @return results List of results from the calls: `(success, returnData)`.\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results)\n {\n results = new Result[](data.length);\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (results[i].success, results[i].returnData) = address(this).delegatecall(data[i]);\n if (!results[i].success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(results[i].returnData);\n }\n }\n }\n\n /// @dev Bubbles the revert message from the underlying call.\n /// Note: preserves the same custom error or revert string, if one was used.\n /// Source: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v5.0.2/contracts/utils/Address.sol#L143-L158\n function _bubbleRevert(bytes memory returnData) internal pure {\n // Look for revert reason and bubble it up if present\n if (returnData.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n // solhint-disable-next-line no-inline-assembly\n assembly {\n let returndata_size := mload(returnData)\n revert(add(32, returnData), returndata_size)\n }\n } else {\n revert MulticallTarget__UndeterminedRevert();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// contracts/libs/BridgeTransactionV2.sol\n\n// solhint-disable no-inline-assembly\nlibrary BridgeTransactionV2Lib {\n uint16 internal constant VERSION = 2;\n\n // Offsets of the fields in the packed BridgeTransactionV2 struct\n // uint16 version [000 .. 002)\n // uint32 originChainId [002 .. 006)\n // uint32 destChainId [006 .. 010)\n // address originSender [010 .. 030)\n // address destRecipient [030 .. 050)\n // address originToken [050 .. 070)\n // address destToken [070 .. 090)\n // uint256 originAmount [090 .. 122)\n // uint256 destAmount [122 .. 154)\n // uint256 originFeeAmount [154 .. 186)\n // uint256 deadline [186 .. 218)\n // uint256 nonce [218 .. 250)\n // address exclusivityRelayer [250 .. 270)\n // uint256 exclusivityEndTime [270 .. 302)\n // uint256 zapNative [302 .. 334)\n // bytes zapData [334 .. ***)\n\n // forgefmt: disable-start\n uint256 private constant OFFSET_ORIGIN_CHAIN_ID = 2;\n uint256 private constant OFFSET_DEST_CHAIN_ID = 6;\n uint256 private constant OFFSET_ORIGIN_SENDER = 10;\n uint256 private constant OFFSET_DEST_RECIPIENT = 30;\n uint256 private constant OFFSET_ORIGIN_TOKEN = 50;\n uint256 private constant OFFSET_DEST_TOKEN = 70;\n uint256 private constant OFFSET_ORIGIN_AMOUNT = 90;\n uint256 private constant OFFSET_DEST_AMOUNT = 122;\n uint256 private constant OFFSET_ORIGIN_FEE_AMOUNT = 154;\n uint256 private constant OFFSET_DEADLINE = 186;\n uint256 private constant OFFSET_NONCE = 218;\n uint256 private constant OFFSET_EXCLUSIVITY_RELAYER = 250;\n uint256 private constant OFFSET_EXCLUSIVITY_END_TIME = 270;\n uint256 private constant OFFSET_ZAP_NATIVE = 302;\n uint256 private constant OFFSET_ZAP_DATA = 334;\n // forgefmt: disable-end\n\n error BridgeTransactionV2__InvalidEncodedTx();\n error BridgeTransactionV2__UnsupportedVersion(uint16 version);\n\n /// @notice Validates the encoded transaction to be a tightly packed encoded payload for BridgeTransactionV2.\n /// @dev Checks the minimum length and the version, use this function before decoding any of the fields.\n function validateV2(bytes calldata encodedTx) internal pure {\n // Check the minimum length: must at least include all static fields.\n if (encodedTx.length \u003c OFFSET_ZAP_DATA) revert BridgeTransactionV2__InvalidEncodedTx();\n // Once we validated the length, we can be sure that the version field is present.\n uint16 version_ = version(encodedTx);\n if (version_ != VERSION) revert BridgeTransactionV2__UnsupportedVersion(version_);\n }\n\n /// @notice Encodes the BridgeTransactionV2 struct by tightly packing the fields.\n /// @dev `abi.decode` will not work as a result of the tightly packed fields. Use `decodeV2` to decode instead.\n function encodeV2(IFastBridgeV2.BridgeTransactionV2 memory bridgeTx) internal pure returns (bytes memory) {\n // We split the encoding into two parts to avoid stack-too-deep error\n bytes memory firstPart = abi.encodePacked(\n VERSION,\n bridgeTx.originChainId,\n bridgeTx.destChainId,\n bridgeTx.originSender,\n bridgeTx.destRecipient,\n bridgeTx.originToken,\n bridgeTx.destToken,\n bridgeTx.originAmount\n );\n return abi.encodePacked(\n firstPart,\n bridgeTx.destAmount,\n bridgeTx.originFeeAmount,\n // Note: we skip the deprecated `sendChainGas` flag, which was present in BridgeTransaction V1\n bridgeTx.deadline,\n bridgeTx.nonce,\n // New V2 fields: exclusivity\n bridgeTx.exclusivityRelayer,\n bridgeTx.exclusivityEndTime,\n // New V2 fields: Zap\n bridgeTx.zapNative,\n bridgeTx.zapData\n );\n }\n\n /// @notice Decodes the BridgeTransactionV2 struct from the encoded transaction.\n /// @dev Encoded BridgeTransactionV2 struct must be tightly packed.\n /// Use `validateV2` before decoding to ensure the encoded transaction is valid.\n function decodeV2(bytes calldata encodedTx)\n internal\n pure\n returns (IFastBridgeV2.BridgeTransactionV2 memory bridgeTx)\n {\n bridgeTx.originChainId = originChainId(encodedTx);\n bridgeTx.destChainId = destChainId(encodedTx);\n bridgeTx.originSender = originSender(encodedTx);\n bridgeTx.destRecipient = destRecipient(encodedTx);\n bridgeTx.originToken = originToken(encodedTx);\n bridgeTx.destToken = destToken(encodedTx);\n bridgeTx.originAmount = originAmount(encodedTx);\n bridgeTx.destAmount = destAmount(encodedTx);\n bridgeTx.originFeeAmount = originFeeAmount(encodedTx);\n bridgeTx.deadline = deadline(encodedTx);\n bridgeTx.nonce = nonce(encodedTx);\n bridgeTx.exclusivityRelayer = exclusivityRelayer(encodedTx);\n bridgeTx.exclusivityEndTime = exclusivityEndTime(encodedTx);\n bridgeTx.zapNative = zapNative(encodedTx);\n bridgeTx.zapData = zapData(encodedTx);\n }\n\n /// @notice Extracts the version from the encoded transaction.\n function version(bytes calldata encodedTx) internal pure returns (uint16 version_) {\n // Load 32 bytes from the start and shift it 240 bits to the right to get the highest 16 bits.\n assembly {\n version_ := shr(240, calldataload(encodedTx.offset))\n }\n }\n\n /// @notice Extracts the origin chain ID from the encoded transaction.\n function originChainId(bytes calldata encodedTx) internal pure returns (uint32 originChainId_) {\n // Load 32 bytes from the offset and shift it 224 bits to the right to get the highest 32 bits.\n assembly {\n originChainId_ := shr(224, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_CHAIN_ID)))\n }\n }\n\n /// @notice Extracts the destination chain ID from the encoded transaction.\n function destChainId(bytes calldata encodedTx) internal pure returns (uint32 destChainId_) {\n // Load 32 bytes from the offset and shift it 224 bits to the right to get the highest 32 bits.\n assembly {\n destChainId_ := shr(224, calldataload(add(encodedTx.offset, OFFSET_DEST_CHAIN_ID)))\n }\n }\n\n /// @notice Extracts the origin sender from the encoded transaction.\n function originSender(bytes calldata encodedTx) internal pure returns (address originSender_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n originSender_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_SENDER)))\n }\n }\n\n /// @notice Extracts the destination recipient from the encoded transaction.\n function destRecipient(bytes calldata encodedTx) internal pure returns (address destRecipient_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n destRecipient_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_DEST_RECIPIENT)))\n }\n }\n\n /// @notice Extracts the origin token from the encoded transaction.\n function originToken(bytes calldata encodedTx) internal pure returns (address originToken_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n originToken_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_TOKEN)))\n }\n }\n\n /// @notice Extracts the destination token from the encoded transaction.\n function destToken(bytes calldata encodedTx) internal pure returns (address destToken_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n destToken_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_DEST_TOKEN)))\n }\n }\n\n /// @notice Extracts the origin amount from the encoded transaction.\n function originAmount(bytes calldata encodedTx) internal pure returns (uint256 originAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n originAmount_ := calldataload(add(encodedTx.offset, OFFSET_ORIGIN_AMOUNT))\n }\n }\n\n /// @notice Extracts the destination amount from the encoded transaction.\n function destAmount(bytes calldata encodedTx) internal pure returns (uint256 destAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n destAmount_ := calldataload(add(encodedTx.offset, OFFSET_DEST_AMOUNT))\n }\n }\n\n /// @notice Extracts the origin fee amount from the encoded transaction.\n function originFeeAmount(bytes calldata encodedTx) internal pure returns (uint256 originFeeAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n originFeeAmount_ := calldataload(add(encodedTx.offset, OFFSET_ORIGIN_FEE_AMOUNT))\n }\n }\n\n /// @notice Extracts the deadline from the encoded transaction.\n function deadline(bytes calldata encodedTx) internal pure returns (uint256 deadline_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n deadline_ := calldataload(add(encodedTx.offset, OFFSET_DEADLINE))\n }\n }\n\n /// @notice Extracts the nonce from the encoded transaction.\n function nonce(bytes calldata encodedTx) internal pure returns (uint256 nonce_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n nonce_ := calldataload(add(encodedTx.offset, OFFSET_NONCE))\n }\n }\n\n /// @notice Extracts the exclusivity relayer from the encoded transaction.\n function exclusivityRelayer(bytes calldata encodedTx) internal pure returns (address exclusivityRelayer_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n exclusivityRelayer_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_EXCLUSIVITY_RELAYER)))\n }\n }\n\n /// @notice Extracts the exclusivity end time from the encoded transaction.\n function exclusivityEndTime(bytes calldata encodedTx) internal pure returns (uint256 exclusivityEndTime_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n exclusivityEndTime_ := calldataload(add(encodedTx.offset, OFFSET_EXCLUSIVITY_END_TIME))\n }\n }\n\n /// @notice Extracts the Zap's native value from the encoded transaction.\n function zapNative(bytes calldata encodedTx) internal pure returns (uint256 zapNative_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n zapNative_ := calldataload(add(encodedTx.offset, OFFSET_ZAP_NATIVE))\n }\n }\n\n /// @notice Extracts the Zap's data from the encoded transaction.\n function zapData(bytes calldata encodedTx) internal pure returns (bytes calldata zapData_) {\n zapData_ = encodedTx[OFFSET_ZAP_DATA:];\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/AdminV2.sol\n\ncontract AdminV2 is AccessControlEnumerable, IAdminV2, IAdminV2Errors {\n using SafeERC20 for IERC20;\n\n /// @notice Address reserved for native gas token (ETH on Ethereum and most L2s, AVAX on Avalanche, etc)\n address public constant NATIVE_GAS_TOKEN = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Role identifier for Quoter API's off-chain authentication.\n /// @dev Only addresses with this role can post FastBridge quotes to the API.\n bytes32 public constant QUOTER_ROLE = keccak256(\"QUOTER_ROLE\");\n\n /// @notice Role identifier for Prover's on-chain authentication in FastBridge.\n /// @dev Only addresses with this role can provide proofs that a FastBridge request has been relayed.\n bytes32 public constant PROVER_ROLE = keccak256(\"PROVER_ROLE\");\n\n /// @notice Role identifier for Guard's on-chain authentication in FastBridge.\n /// @dev Only addresses with this role can dispute submitted relay proofs during the dispute period.\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n\n /// @notice Role identifier for Canceler's on-chain authentication in FastBridge.\n /// @dev Only addresses with this role can cancel a FastBridge transaction without the cancel delay.\n bytes32 public constant CANCELER_ROLE = keccak256(\"CANCELER_ROLE\");\n\n /// @notice Role identifier for Governor's on-chain administrative authority.\n /// @dev Only addresses with this role can perform administrative tasks within the contract.\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n /// @notice Denominator for fee rates, represents 100%.\n uint256 public constant FEE_BPS = 1e6;\n /// @notice Maximum protocol fee rate: 1% on origin amount.\n uint256 public constant FEE_RATE_MAX = 0.01e6;\n\n /// @notice Minimum cancel delay that can be set by the governor.\n uint256 public constant MIN_CANCEL_DELAY = 1 hours;\n /// @notice Default cancel delay set during the contract deployment.\n uint256 public constant DEFAULT_CANCEL_DELAY = 1 days;\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Delay for a transaction after which it could be permisionlessly cancelled\n uint256 public cancelDelay;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Use ZapNative V2 requests instead.\n uint256 public immutable chainGasAmount = 0;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n _setCancelDelay(DEFAULT_CANCEL_DELAY);\n }\n\n /// @notice Allows the contract governor to set the cancel delay. The cancel delay is the time after the transaction\n /// deadline after which it can be permissionlessly cancelled, if it hasn't been proven by any of the Relayers.\n function setCancelDelay(uint256 newCancelDelay) external onlyRole(GOVERNOR_ROLE) {\n _setCancelDelay(newCancelDelay);\n }\n\n /// @notice Allows the contract governor to set the protocol fee rate. The protocol fee is taken from the origin\n /// amount only for completed and claimed transactions.\n /// @dev The protocol fee is abstracted away from the relayers, they always operate using the amounts after fees:\n /// what they see as the origin amount emitted in the log is what they get credited with.\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n if (newFeeRate \u003e FEE_RATE_MAX) revert FeeRateAboveMax();\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n /// @notice Allows the contract governor to sweep the accumulated protocol fees in the contract.\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n emit FeesSwept(token, recipient, feeAmount);\n /// Sweep the fees as the last transaction action\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(recipient), feeAmount);\n } else {\n IERC20(token).safeTransfer(recipient, feeAmount);\n }\n }\n\n /// @notice Internal function to set the cancel delay. Security checks are performed outside of this function.\n function _setCancelDelay(uint256 newCancelDelay) private {\n if (newCancelDelay \u003c MIN_CANCEL_DELAY) revert CancelDelayBelowMin();\n uint256 oldCancelDelay = cancelDelay;\n cancelDelay = newCancelDelay;\n emit CancelDelayUpdated(oldCancelDelay, newCancelDelay);\n }\n}\n\n// contracts/FastBridgeV2.sol\n\n/// @notice FastBridgeV2 is a contract for bridging tokens across chains.\ncontract FastBridgeV2 is AdminV2, MulticallTarget, IFastBridgeV2, IFastBridgeV2Errors {\n using BridgeTransactionV2Lib for bytes;\n using SafeERC20 for IERC20;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n /// @notice Maximum length of accepted zapData\n uint256 public constant MAX_ZAP_DATA_LENGTH = 2 ** 16 - 1;\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeTxDetails) public bridgeTxDetails;\n /// @notice Relay details on destination chain\n mapping(bytes32 =\u003e BridgeRelay) public bridgeRelayDetails;\n /// @notice Unique bridge nonces tracked per originSender\n mapping(address =\u003e uint256) public senderNonces;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Replaced by senderNonces\n uint256 public immutable nonce = 0;\n /// @notice the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) AdminV2(_owner) {\n deployBlock = block.number;\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n bridge({\n params: params,\n paramsV2: BridgeParamsV2({\n quoteRelayer: address(0),\n quoteExclusivitySeconds: 0,\n quoteId: bytes(\"\"),\n zapNative: 0,\n zapData: bytes(\"\")\n })\n });\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes calldata request) external payable {\n // relay override will validate the request\n relay({request: request, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes calldata request, bytes32 destTxHash) external {\n request.validateV2();\n prove({transactionId: keccak256(request), destTxHash: destTxHash, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridgeV2\n function claim(bytes calldata request) external {\n // claim override will validate the request\n claim({request: request, to: address(0)});\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Aggregate the read operations from the same storage slot\n address disputedRelayer = $.proofRelayer;\n BridgeStatus status = $.status;\n uint56 proofBlockTimestamp = $.proofBlockTimestamp;\n // Can only dispute a RELAYER_PROVED transaction within the dispute period\n if (status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(proofBlockTimestamp) \u003e DISPUTE_PERIOD) {\n revert DisputePeriodPassed();\n }\n // Update status to REQUESTED and delete the disputed proof details\n // Note: these are storage writes\n $.status = BridgeStatus.REQUESTED;\n $.proofRelayer = address(0);\n $.proofBlockTimestamp = 0;\n\n emit BridgeProofDisputed(transactionId, disputedRelayer);\n }\n\n /// Note: this function is deprecated and will be removed in a future version.\n /// @inheritdoc IFastBridge\n function refund(bytes calldata request) external {\n cancel(request);\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // The correct relayer can only claim a RELAYER_PROVED transaction after the dispute period\n if ($.status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if ($.proofRelayer != relayer) revert SenderIncorrect();\n return _timeSince($.proofBlockTimestamp) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n /// @dev This method is added to achieve backwards compatibility with decoding requests into V1 structs:\n /// - `zapNative` is partially reported as a zero/non-zero flag\n /// - `zapData` is ignored\n /// In order to process all kinds of requests use getBridgeTransactionV2 instead.\n function getBridgeTransaction(bytes calldata request) external view returns (BridgeTransaction memory) {\n // Try decoding into V2 struct first. This will revert if V1 struct is passed\n try this.getBridgeTransactionV2(request) returns (BridgeTransactionV2 memory txV2) {\n // Note: we entirely ignore the zapData field, as it was not present in V1\n return BridgeTransaction({\n originChainId: txV2.originChainId,\n destChainId: txV2.destChainId,\n originSender: txV2.originSender,\n destRecipient: txV2.destRecipient,\n originToken: txV2.originToken,\n destToken: txV2.destToken,\n originAmount: txV2.originAmount,\n destAmount: txV2.destAmount,\n originFeeAmount: txV2.originFeeAmount,\n sendChainGas: txV2.zapNative != 0,\n deadline: txV2.deadline,\n nonce: txV2.nonce\n });\n } catch {\n // Fallback to V1 struct\n return abi.decode(request, (BridgeTransaction));\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function getBridgeTransactionV2(bytes calldata request) external pure returns (BridgeTransactionV2 memory) {\n request.validateV2();\n return BridgeTransactionV2Lib.decodeV2(request);\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) public payable {\n int256 exclusivityEndTime = 0;\n // if relayer exclusivity is not intended for this bridge, set exclusivityEndTime to static zero\n // otherwise, set exclusivity to expire at the current block ts offset by quoteExclusivitySeconds\n if (paramsV2.quoteRelayer != address(0)) {\n exclusivityEndTime = int256(block.timestamp) + paramsV2.quoteExclusivitySeconds;\n }\n _validateBridgeParams(params, paramsV2, exclusivityEndTime);\n\n // transfer tokens to bridge contract\n /// @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _takeBridgedUserAsset(params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) {\n originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n }\n\n // set status to requested\n bytes memory request = BridgeTransactionV2Lib.encodeV2(\n BridgeTransactionV2({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n deadline: params.deadline,\n nonce: senderNonces[params.sender]++, // increment nonce on every bridge\n exclusivityRelayer: paramsV2.quoteRelayer,\n // We checked exclusivityEndTime to be in range [0 .. params.deadline] above, so can safely cast\n exclusivityEndTime: uint256(exclusivityEndTime),\n zapNative: paramsV2.zapNative,\n zapData: paramsV2.zapData\n })\n );\n bytes32 transactionId = keccak256(request);\n // Note: the tx status will be updated throughout the tx lifecycle, while destChainId is set once here\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n bridgeTxDetails[transactionId].destChainId = params.dstChainId;\n\n emit BridgeRequested({\n transactionId: transactionId,\n sender: params.sender,\n request: request,\n destChainId: params.dstChainId,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n sendChainGas: paramsV2.zapNative != 0\n });\n emit BridgeQuoteDetails(transactionId, paramsV2.quoteId);\n }\n\n /// @inheritdoc IFastBridgeV2\n function relay(bytes calldata request, address relayer) public payable {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n _validateRelayParams(request, transactionId, relayer);\n // mark bridge transaction as relayed\n bridgeRelayDetails[transactionId] =\n BridgeRelay({blockNumber: uint48(block.number), blockTimestamp: uint48(block.timestamp), relayer: relayer});\n\n // transfer tokens to recipient on destination chain and trigger Zap if requested\n address to = request.destRecipient();\n address token = request.destToken();\n uint256 amount = request.destAmount();\n uint256 zapNative = request.zapNative();\n\n // Emit the event before any external calls\n emit BridgeRelayed({\n transactionId: transactionId,\n relayer: relayer,\n to: to,\n originChainId: request.originChainId(),\n originToken: request.originToken(),\n destToken: token,\n originAmount: request.originAmount(),\n destAmount: amount,\n chainGasAmount: zapNative\n });\n\n // All state changes have been done at this point, can proceed to the external calls.\n // This follows the checks-effects-interactions pattern to mitigate potential reentrancy attacks.\n if (token == NATIVE_GAS_TOKEN) {\n // For the native gas token, additional zapNative is not allowed\n if (zapNative != 0) revert ZapNativeNotSupported();\n // Check that the correct msg.value was sent\n if (msg.value != amount) revert MsgValueIncorrect();\n // Don't do a native transfer yet: we will handle it alongside the Zap below\n } else {\n // For ERC20s, we check that the correct msg.value was sent\n if (msg.value != zapNative) revert MsgValueIncorrect();\n // We need to transfer the tokens from the Relayer to the recipient first before performing an\n // optional post-transfer Zap.\n IERC20(token).safeTransferFrom(msg.sender, to, amount);\n }\n // At this point we have done:\n // - Transferred the requested amount of ERC20 tokens to the recipient.\n // At this point we have confirmed:\n // - For ERC20s: msg.value matches the requested zapNative amount.\n // - For the native gas token: msg.value matches the requested destAmount.\n // Remaining optional things to do:\n // - Forward the full msg.value to the recipient (if non-zero).\n // - Trigger a Zap (if zapData is present).\n bytes calldata zapData = request.zapData();\n if (zapData.length != 0) {\n // Zap Data is present: Zap has been requested by the recipient. Trigger it forwarding the full msg.value.\n\n // Note: if token has a fee on transfers, the recipient will have received less than `amount`.\n // This is a very niche edge case and should be handled by the recipient contract.\n _triggerZapWithChecks({recipient: to, token: token, amount: amount, zapData: zapData});\n } else if (msg.value != 0) {\n // Zap Data is missing, but msg.value was sent. This could happen in two different cases:\n // - Relay with the native gas token is happening.\n // - Relay with ERC20 is happening, with a `zapNative \u003e 0` request.\n // In both cases, we need to transfer the full msg.value to the recipient.\n Address.sendValue(payable(to), msg.value);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) public onlyRole(PROVER_ROLE) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n\n // Can only prove a REQUESTED transaction\n if ($.status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n // Update status to RELAYER_PROVED and store the proof details\n // Note: these are storage writes\n $.status = BridgeStatus.RELAYER_PROVED;\n $.proofBlockTimestamp = uint56(block.timestamp);\n $.proofRelayer = relayer;\n\n emit BridgeProofProvided(transactionId, relayer, destTxHash);\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes calldata request, address to) public {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Aggregate the read operations from the same storage slot\n address proofRelayer = $.proofRelayer;\n BridgeStatus status = $.status;\n uint56 proofBlockTimestamp = $.proofBlockTimestamp;\n\n // Can only claim a RELAYER_PROVED transaction after the dispute period\n if (status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(proofBlockTimestamp) \u003c= DISPUTE_PERIOD) {\n revert DisputePeriodNotPassed();\n }\n\n if (to == address(0)) {\n // Anyone could claim the funds to the proven relayer on their behalf\n to = proofRelayer;\n } else if (proofRelayer != msg.sender) {\n // Only the proven relayer could specify an address to claim the funds to\n revert SenderIncorrect();\n }\n\n // Update status to RELAYER_CLAIMED and transfer the origin collateral to the specified claim address\n // Note: this is a storage write\n $.status = BridgeStatus.RELAYER_CLAIMED;\n\n address token = request.originToken();\n uint256 amount = request.originAmount();\n // Update protocol fees if origin fee amount exists\n uint256 originFeeAmount = request.originFeeAmount();\n if (originFeeAmount \u003e 0) protocolFees[token] += originFeeAmount;\n // Emit the event before any external calls\n emit BridgeDepositClaimed(transactionId, proofRelayer, to, token, amount);\n // Complete the relayer claim as the last transaction action\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(to), amount);\n } else {\n IERC20(token).safeTransfer(to, amount);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function cancel(bytes calldata request) public {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Can only cancel a REQUESTED transaction after its deadline expires\n if ($.status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n uint256 deadline = request.deadline();\n // Permissionless cancel is only allowed after `cancelDelay` on top of the deadline\n if (!hasRole(CANCELER_ROLE, msg.sender)) deadline += cancelDelay;\n if (block.timestamp \u003c= deadline) revert DeadlineNotExceeded();\n // Update status to REFUNDED and return the full amount (collateral + protocol fees) to the original sender.\n // The protocol fees are only updated when the transaction is claimed, so we don't need to update them here.\n // Note: this is a storage write\n $.status = BridgeStatus.REFUNDED;\n\n address to = request.originSender();\n address token = request.originToken();\n uint256 amount = request.originAmount() + request.originFeeAmount();\n // Emit the event before any external calls\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n // Complete the user cancel as the last transaction action\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(to), amount);\n } else {\n IERC20(token).safeTransfer(to, amount);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeStatuses(bytes32 transactionId) public view returns (BridgeStatus status) {\n return bridgeTxDetails[transactionId].status;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeProofs(bytes32 transactionId) public view returns (uint96 timestamp, address relayer) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n\n timestamp = $.proofBlockTimestamp;\n relayer = $.proofRelayer;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeRelays(bytes32 transactionId) public view returns (bool) {\n // has this transactionId been relayed?\n return bridgeRelayDetails[transactionId].relayer != address(0);\n }\n\n /// @notice Takes the bridged asset from the user into FastBridgeV2 custody. It will be later\n /// claimed by the relayer who completed the relay on destination chain, or transferred back to the user\n /// via the cancel function should no one complete the relay.\n function _takeBridgedUserAsset(address token, uint256 amount) internal returns (uint256 amountTaken) {\n if (token == NATIVE_GAS_TOKEN) {\n // For the native gas token, we just need to check that the supplied msg.value is correct.\n // Supplied `msg.value` is already in FastBridgeV2 custody.\n if (amount != msg.value) revert MsgValueIncorrect();\n amountTaken = msg.value;\n } else {\n // For ERC20s, token is explicitly transferred from the user to FastBridgeV2.\n // We don't allow non-zero `msg.value` to avoid extra funds from being stuck in FastBridgeV2.\n if (msg.value != 0) revert MsgValueIncorrect();\n // Throw an explicit error if the provided token address is not a contract\n if (token.code.length == 0) revert TokenNotContract();\n amountTaken = IERC20(token).balanceOf(address(this));\n IERC20(token).safeTransferFrom(msg.sender, address(this), amount);\n // Use the balance difference as the amount taken in case of fee on transfer tokens.\n amountTaken = IERC20(token).balanceOf(address(this)) - amountTaken;\n }\n }\n\n /// @notice Calls the Recipient's hook function with the specified zapData and performs\n /// all the necessary checks for the returned value.\n function _triggerZapWithChecks(address recipient, address token, uint256 amount, bytes calldata zapData) internal {\n // This will bubble any revert messages from the hook function\n bytes memory returnData = Address.functionCallWithValue({\n target: recipient,\n data: abi.encodeCall(IZapRecipient.zap, (token, amount, zapData)),\n // Note: see `relay()` for reasoning behind passing msg.value\n value: msg.value\n });\n // Explicit revert if no return data at all\n if (returnData.length == 0) revert RecipientNoReturnValue();\n // Check that exactly a single return value was returned\n if (returnData.length != 32) revert RecipientIncorrectReturnValue();\n // Return value should be abi-encoded hook function selector\n if (bytes32(returnData) != bytes32(IZapRecipient.zap.selector)) {\n revert RecipientIncorrectReturnValue();\n }\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint56(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint56).max but\n /// proof.timestamp \u003c type(uint56).max via unchecked statement\n /// @param proofBlockTimestamp The bridge proof block timestamp\n /// @return delta Time delta since proof submitted\n function _timeSince(uint56 proofBlockTimestamp) internal view returns (uint256 delta) {\n unchecked {\n delta = uint56(block.timestamp) - proofBlockTimestamp;\n }\n }\n\n /// @notice Performs all the necessary checks for a bridge to happen.\n /// @dev There's no good way to refactor this function to reduce cyclomatic complexity due to\n /// the number of checks that need to be performed, so we skip the code-complexity rule here.\n // solhint-disable-next-line code-complexity\n function _validateBridgeParams(\n BridgeParams memory params,\n BridgeParamsV2 memory paramsV2,\n int256 exclusivityEndTime\n )\n internal\n view\n {\n // Check V1 (legacy) params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.sender == address(0) || params.to == address(0)) revert ZeroAddress();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n // Check V2 params\n if (paramsV2.zapData.length \u003e MAX_ZAP_DATA_LENGTH) revert ZapDataLengthAboveMax();\n if (paramsV2.zapNative != 0 \u0026\u0026 params.destToken == NATIVE_GAS_TOKEN) {\n revert ZapNativeNotSupported();\n }\n // exclusivityEndTime must be in range [0 .. params.deadline]\n if (exclusivityEndTime \u003c 0 || exclusivityEndTime \u003e int256(params.deadline)) {\n revert ExclusivityParamsIncorrect();\n }\n }\n\n /// @notice Performs all the necessary checks for a relay to happen.\n function _validateRelayParams(bytes calldata request, bytes32 transactionId, address relayer) internal view {\n if (relayer == address(0)) revert ZeroAddress();\n // Check if the transaction has already been relayed\n if (bridgeRelays(transactionId)) revert TransactionRelayed();\n if (request.destChainId() != block.chainid) revert ChainIncorrect();\n // Check the deadline for relay to happen\n if (block.timestamp \u003e request.deadline()) revert DeadlineExceeded();\n // Check the exclusivity period, if it is still ongoing\n address exclRelayer = request.exclusivityRelayer();\n if (exclRelayer != address(0) \u0026\u0026 exclRelayer != relayer \u0026\u0026 block.timestamp \u003c= request.exclusivityEndTime()) {\n revert ExclusivityPeriodNotPassed();\n }\n }\n}\n","language":"Solidity","languageVersion":"0.8.24","compilerVersion":"0.8.24","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"80976:22670:0:-:0;;;78600:1;78558:43;;;;81964:34;;82102:87;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;82138:6;78646:38;68687:4;82138:6;78646:10;:38::i;:::-;-1:-1:-1;78694:37:0;78092:6;78694:15;:37::i;:::-;-1:-1:-1;;82170:12:0::1;82156:26;::::0;80976:22670;;75409:257;75495:4;;75526:31;75543:4;75549:7;75526:16;:31::i;:::-;75511:46;;75571:7;75567:69;;;75594:18;;;;:12;:18;;;;;:31;;75617:7;75594:22;:31::i;:::-;;75567:69;75652:7;-1:-1:-1;75409:257:0;;;;;:::o;80577:290::-;77959:7;80648:14;:33;80644:67;;;80690:21;;-1:-1:-1;;;80690:21:0;;;;;;;;;;;80644:67;80746:11;;;80767:28;;;;80810:50;;;483:25:1;;;539:2;524:18;;517:34;;;80810:50:0;;456:18:1;80810:50:0;;;;;;;80634:233;80577:290;:::o;72634:316::-;72711:4;69409:12;;;;;;;;;;;-1:-1:-1;;;;;69409:29:0;;;;;;;;;;;;72727:217;;72770:6;:12;;;;;;;;;;;-1:-1:-1;;;;;72770:29:0;;;;;;;;;:36;;-1:-1:-1;;72770:36:0;72802:4;72770:36;;;72852:12;23372:10;;23293:96;72852:12;-1:-1:-1;;;;;72825:40:0;72843:7;-1:-1:-1;;;;;72825:40:0;72837:4;72825:40;;;;;;;;;;-1:-1:-1;72886:4:0;72879:11;;72727:217;-1:-1:-1;72928:5:0;72921:12;;32817:150;32887:4;32910:50;32915:3;-1:-1:-1;;;;;32935:23:0;;26805:4;28861:21;;;:14;;;:21;;;;;;26821:321;;-1:-1:-1;26863:23:0;;;;;;;;:11;:23;;;;;;;;;;;;;27045:18;;27021:21;;;:14;;;:21;;;;;;:42;;;;27077:11;;14:290:1;84:6;137:2;125:9;116:7;112:23;108:32;105:52;;;153:1;150;143:12;105:52;179:16;;-1:-1:-1;;;;;224:31:1;;214:42;;204:70;;270:1;267;260:12;309:248;80976:22670:0;;;;;;;;;;;;;;;;;;;;;;;;","srcMapRuntime":"80976:22670:0:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;74069:212;;;;;;;;;;-1:-1:-1;74069:212:0;;;;;:::i;:::-;;:::i;:::-;;;612:14:1;;605:22;587:41;;575:2;560:18;74069:212:0;;;;;;;;77302:66;;;;;;;;;;;;77342:26;77302:66;;;;;785:25:1;;;773:2;758:18;77302:66:0;639:177:1;77044:60:0;;;;;;;;;;;;77081:23;77044:60;;97383:150;;;;;;;;;;-1:-1:-1;97383:150:0;;;;;:::i;:::-;97451:19;97489:30;;;:15;:30;;;;;:37;;;;97383:150;;;;;;;;:::i;79902:554::-;;;;;;;;;;-1:-1:-1;79902:554:0;;;;;:::i;:::-;;:::i;:::-;;77794:45;;;;;;;;;;;;77833:6;77794:45;;76279:85;;;;;;;;;;;;76322:42;76279:85;;;;;-1:-1:-1;;;;;2885:55:1;;;2867:74;;2855:2;2840:18;76279:85:0;2721:226:1;93245:627:0;;;;;;;;;;-1:-1:-1;93245:627:0;;;;;:::i;:::-;;:::i;78981:129::-;;;;;;;;;;-1:-1:-1;78981:129:0;;;;;:::i;:::-;;:::i;70265:120::-;;;;;;;;;;-1:-1:-1;70265:120:0;;;;;:::i;:::-;70330:7;70356:12;;;;;;;;;;:22;;;;70265:120;81813:47;;;;;;;;;;-1:-1:-1;81813:47:0;;;;;:::i;:::-;;;;;;;;;;;;;;70681:136;;;;;;;;;;-1:-1:-1;70681:136:0;;;;;:::i;:::-;;:::i;71783:245::-;;;;;;;;;;-1:-1:-1;71783:245:0;;;;;:::i;:::-;;:::i;45543:875::-;;;;;;;;;;-1:-1:-1;45543:875:0;;;;;:::i;:::-;;:::i;:::-;;;;;;;:::i;95855:1488::-;;;;;;;;;;-1:-1:-1;95855:1488:0;;;;;:::i;:::-;;:::i;44142:718::-;;;;;;;;;;-1:-1:-1;44142:718:0;;;;;:::i;:::-;;:::i;93910:1905::-;;;;;;;;;;-1:-1:-1;93910:1905:0;;;;;:::i;:::-;;:::i;82227:366::-;;;;;;:::i;:::-;;:::i;81453:57::-;;;;;;;;;;;;81499:11;81453:57;;78188:30;;;;;;;;;;;;;;;;86422:201;;;;;;;;;;-1:-1:-1;86422:201:0;;;;;:::i;:::-;;:::i;:::-;;;;;;;:::i;84338:81::-;;;;;;;;;;-1:-1:-1;84338:81:0;;;;;:::i;:::-;;:::i;81573:58::-;;;;;;;;;;-1:-1:-1;81573:58:0;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;81573:58:0;;;;;;;;;;;;;:::i;78418:26::-;;;;;;;;;;;;;;;;76528:62;;;;;;;;;;;;76566:24;76528:62;;81339:56;;;;;;;;;;;;81385:10;81339:56;;97867:199;;;;;;;;;;-1:-1:-1;97867:199:0;;;;;:::i;:::-;97933:4;98004:33;;;:18;:33;;;;;:41;;;;-1:-1:-1;;;;;98004:41:0;:55;;;97867:199;82840:202;;;;;;;;;;-1:-1:-1;82840:202:0;;;;;:::i;:::-;;:::i;82631:171::-;;;;;;:::i;:::-;;:::i;74866:142::-;;;;;;;;;;-1:-1:-1;74866:142:0;;;;;:::i;:::-;;:::i;97573:254::-;;;;;;;;;;-1:-1:-1;97573:254:0;;;;;:::i;:::-;97639:16;97712:30;;;:15;:30;;;;;97765:21;;;;;;;97806:14;;;;-1:-1:-1;;;;;97806:14:0;;97573:254;;;;;14428:26:1;14416:39;;;14398:58;;-1:-1:-1;;;;;14492:55:1;;;14487:2;14472:18;;14465:83;14371:18;97573:254:0;14226:328:1;69309:136:0;;;;;;;;;;-1:-1:-1;69309:136:0;;;;;:::i;:::-;69386:4;69409:12;;;;;;;;;;;-1:-1:-1;;;;;69409:29:0;;;;;;;;;;;;;;;69309:136;77916:50;;;;;;;;;;;;77959:7;77916:50;;78045:53;;;;;;;;;;;;78092:6;78045:53;;89646:3559;;;;;;:::i;:::-;;:::i;68642:49::-;;;;;;;;;;-1:-1:-1;68642:49:0;68687:4;68642:49;;82059:36;;;;;;;;;;;;;;;84457:473;;;;;;;;;;-1:-1:-1;84457:473:0;;;;;:::i;:::-;;:::i;85262:1120::-;;;;;;;;;;-1:-1:-1;85262:1120:0;;;;;:::i;:::-;;:::i;:::-;;;;;;;:::i;83278:939::-;;;;;;;;;;-1:-1:-1;83278:939:0;;;;;:::i;:::-;;:::i;81964:34::-;;;;;;;;;;;;;;;79505:290;;;;;;;;;;-1:-1:-1;79505:290:0;;;;;:::i;:::-;;:::i;77687:37::-;;;;;;;;;;;;77721:3;77687:37;;86663:2943;;;;;;:::i;:::-;;:::i;83082:158::-;;;;;;;;;;-1:-1:-1;83082:158:0;;;;;:::i;:::-;;:::i;81688:57::-;;;;;;;;;;-1:-1:-1;81688:57:0;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;81688:57:0;;;;;;;18029:14:1;18070:15;;;18052:34;;18122:15;;;;18117:2;18102:18;;18095:43;-1:-1:-1;;;;;18174:55:1;18154:18;;;18147:83;18007:2;17992:18;81688:57:0;17821:415:1;75176:131:0;;;;;;;;;;-1:-1:-1;75176:131:0;;;;;:::i;:::-;;:::i;77554:66::-;;;;;;;;;;;;77594:26;77554:66;;71097:138;;;;;;;;;;-1:-1:-1;71097:138:0;;;;;:::i;:::-;;:::i;76787:62::-;;;;;;;;;;;;76825:24;76787:62;;78274:47;;;;;;;;;;-1:-1:-1;78274:47:0;;;;;:::i;:::-;;;;;;;;;;;;;;78558:43;;;;;;;;;;;;;;;74069:212;74154:4;74177:57;;;74192:42;74177:57;;:97;;;74238:36;74262:11;74238:23;:36::i;:::-;74170:104;74069:212;-1:-1:-1;;74069:212:0:o;79902:554::-;77594:26;68919:16;68930:4;68919:10;:16::i;:::-;-1:-1:-1;;;;;80026:19:0;::::1;80006:17;80026:19:::0;;;:12:::1;:19;::::0;;;;;;80059:14;;;80055:27:::1;;80075:7;79902:554:::0;;;:::o;80055:27::-:1;-1:-1:-1::0;;;;;80123:19:0;;::::1;80145:1;80123:19:::0;;;:12:::1;:19;::::0;;;;;;;:23;;;;80161:38;;18504:34:1;;;18574:15;;;18554:18;;;18547:43;;;;18606:18;;;18599:34;;;80161:38:0::1;::::0;18431:2:1;18416:18;80161:38:0::1;;;;;;;80271:25:::0;-1:-1:-1;;;;;80271:25:0;::::1;::::0;80267:183:::1;;80312:48;80338:9;80350;80312:17;:48::i;:::-;80267:183;;;80391:48;-1:-1:-1::0;;;;;80391:26:0;::::1;80418:9:::0;80429;80391:26:::1;:48::i;:::-;79996:460;68945:1;79902:554:::0;;;:::o;93245:627::-;76825:24;68919:16;68930:4;68919:10;:16::i;:::-;93359:25:::1;93387:30:::0;;;:15:::1;:30;::::0;;;;93494:22:::1;93482:8:::0;;::::1;;:34;::::0;::::1;;;;;;:::i;:::-;;93478:64;;93525:17;;;;;;;;;;;;;;93478:64;93665:38:::0;;-1:-1:-1;;;;;93770:24:0;::::1;::::0;;::::1;::::0;93713:47:::1;93744:15;93713:47;::::0;::::1;93770:24:::0;;;;;;;;;;;;;93676:27:::1;93770:24:::0;;;93810:55:::1;::::0;785:25:1;;;93830:13:0;;93810:55:::1;::::0;773:2:1;758:18;93810:55:0::1;;;;;;;93349:523;93245:627:::0;;;;:::o;78981:129::-;77594:26;68919:16;68930:4;68919:10;:16::i;:::-;79072:31:::1;79088:14;79072:15;:31::i;:::-;78981:129:::0;;:::o;70681:136::-;70330:7;70356:12;;;;;;;;;;:22;;;68919:16;68930:4;68919:10;:16::i;:::-;70785:25:::1;70796:4;70802:7;70785:10;:25::i;71783:245::-:0;-1:-1:-1;;;;;71876:34:0;;23372:10;71876:34;71872:102;;71933:30;;;;;;;;;;;;;;71872:102;71984:37;71996:4;72002:18;71984:11;:37::i;45543:875::-;45672:23;45734:4;45721:25;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;;;;;;;;;;;;;45721:25:0;;;;;;;;;;;;;;;;45711:35;;45761:9;45756:656;45776:15;;;45756:656;;;46249:4;46268;;46273:1;46268:7;;;;;;;:::i;:::-;;;;;;;;;;;;:::i;:::-;46241:35;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;46196:7;46204:1;46196:10;;;;;;;;:::i;:::-;;;;;;;:18;;46216:7;46224:1;46216:10;;;;;;;;:::i;:::-;;;;;;;:21;;46195:81;;;;;;;;;;;;;46295:7;46303:1;46295:10;;;;;;;;:::i;:::-;;;;;;;:18;;;46294:19;:37;;;;;46318:13;46317:14;46294:37;46290:112;;;46351:36;46365:7;46373:1;46365:10;;;;;;;;:::i;:::-;;;;;;;:21;;;46351:13;:36::i;:::-;45793:3;;45756:656;;;;45543:875;;;;;:::o;95855:1488::-;95912:20;:7;;:18;:20::i;:::-;95942:21;95976:7;;95966:18;;;;;;;:::i;:::-;;;;;;;;;;;95994:25;96022:30;;;:15;:30;;;;;;95966:18;;-1:-1:-1;96156:22:0;96144:8;;;;:34;;;;;;;;:::i;:::-;;96140:64;;96187:17;;;;;;;;;;;;;;96140:64;96381:10;96214:16;69409:29;;;:12;;:29;:12;:29;;;59118:15;59096:38;;59083:52;;69409:29;;96353:64;;96406:11;;96394:23;;;;:::i;:::-;;;96353:64;96450:8;96431:15;:27;96427:61;;96467:21;;;;;;;;;;;;;;96427:61;96773:32;;;;96784:21;96773:32;;;56338:20;56316:43;;56303:57;56299:2;56295:66;;;;57164:19;57142:42;;57129:56;57121:65;;-1:-1:-1;96925:50:0;58742:24;58720:47;;58707:61;57954:20;57932:43;;57919:57;96925:50;:::i;:::-;97042:55;;;-1:-1:-1;;;;;20205:55:1;;;20187:74;;20292:2;20277:18;;20270:34;;;97042:55:0;;20270:34:1;;-1:-1:-1;97042:55:0;;;97064:13;;97042:55;;;;;;;;97178:25;-1:-1:-1;;;;;97178:25:0;;;97174:163;;97219:38;97245:2;97250:6;97219:17;:38::i;:::-;97174:163;;;97288:38;-1:-1:-1;;;;;97288:26:0;;97315:2;97319:6;97288:26;:38::i;:::-;95902:1441;;;;;;95855:1488;;:::o;44142:718::-;44237:9;44232:622;44252:15;;;44232:622;;;44672:12;;44717:4;44736;;44741:1;44736:7;;;;;;;:::i;:::-;;;;;;;;;;;;:::i;:::-;44709:35;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;44671:73;;;;44763:7;44762:8;:26;;;;;44775:13;44774:14;44762:26;44758:86;;;44808:21;44822:6;44808:13;:21::i;:::-;-1:-1:-1;;44269:3:0;;44232:622;;93910:1905;93978:20;:7;;:18;:20::i;:::-;94008:21;94042:7;;94032:18;;;;;;;:::i;:::-;;;;;;;;;;;94060:25;94088:30;;;:15;:30;;;;;;94219:14;;94032:18;;-1:-1:-1;94088:30:0;94219:14;;;-1:-1:-1;;;;;94219:14:0;;94265:8;;;;94312:21;;;;;94438:27;94428:6;:37;;;;;;;;:::i;:::-;;94424:67;;94474:17;;;;;;;;;;;;;;94424:67;81242:10;101235:15;101228:45;;;101220:53;;94505:49;94501:111;;94577:24;;;;;;;;;;;;;;94501:111;-1:-1:-1;;;;;94626:16:0;;94622:319;;94745:12;94740:17;;94622:319;;;-1:-1:-1;;;;;94778:26:0;;94794:10;94778:26;94774:167;;94913:17;;;;;;;;;;;;;;94774:167;95102:39;;;;95113:28;95102:39;;;57164:19;57142:42;;57129:56;57125:2;57121:65;57954:20;57932:43;;57919:57;58742:24;58720:47;;58707:61;95373:19;;95369:63;;-1:-1:-1;;;;;95394:19:0;;;;;;:12;:19;;;;;:38;;95417:15;;95394:19;:38;;95417:15;;95394:38;:::i;:::-;;;;-1:-1:-1;;95369:63:0;95499:68;;;-1:-1:-1;;;;;20205:55:1;;;20187:74;;20292:2;20277:18;;20270:34;;;95499:68:0;;;;;;;;95520:13;;95499:68;;20160:18:1;95499:68:0;;;;;;;95650:25;-1:-1:-1;;;;;95650:25:0;;;95646:163;;95691:38;95717:2;95722:6;95691:17;:38::i;:::-;95646:163;;;95760:38;-1:-1:-1;;;;;95760:26:0;;95787:2;95791:6;95760:26;:38::i;:::-;93968:1847;;;;;;;;93910:1905;;;:::o;82227:366::-;82298:288;82327:6;82357:218;;;;;;;;82412:1;-1:-1:-1;;;;;82357:218:0;;;;;82457:1;82357:218;;;;82485:9;;;;;;;;;;;;82357:218;;;;82523:1;82357:218;;;;82551:9;;;;;;;;;;;;82357:218;;;82298:6;:288::i;:::-;82227:366;:::o;86422:201::-;86501:26;-1:-1:-1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;86501:26:0;86539:20;:7;;:18;:20::i;:::-;86576:40;86608:7;;86576:31;:40::i;:::-;86569:47;86422:201;-1:-1:-1;;;86422:201:0:o;84338:81::-;84397:15;84404:7;;84397:6;:15::i;82840:202::-;82918:20;:7;;:18;:20::i;:::-;82948:87;82980:7;;82970:18;;;;;;;:::i;:::-;;;;;;;;83002:10;83023;82948:5;:87::i;82631:171::-;82749:46;82765:7;;82783:10;82749:5;:46::i;74866:142::-;74947:7;74973:18;;;:12;:18;;;;;:28;;74995:5;74973:21;:28::i;89646:3559::-;89727:20;:7;;:18;:20::i;:::-;89757:21;89791:7;;89781:18;;;;;;;:::i;:::-;;;;;;;;89757:42;;89809:53;89830:7;;89839:13;89854:7;89809:20;:53::i;:::-;89966:107;;;;;;;;;89999:12;89966:107;;;;90037:15;89966:107;;;;;;;;;-1:-1:-1;;;;;89966:107:0;;;;;;;;;-1:-1:-1;89918:33:0;;;:18;:33;;;;;;:155;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;90187:23;:7;56758:21;56736:44;56723:58;56719:2;56715:67;;56464:334;90187:23;90174:36;-1:-1:-1;57567:17:0;57545:40;;57532:54;57528:2;57524:63;58342:18;58320:41;;58307:55;60710:17;60688:40;;60675:54;-1:-1:-1;;;;;90419:368:0;;;;;;90462:13;90419:368;55514:22;55492:45;;55479:59;55474:3;55470:69;90419:368;;;20630:10:1;20618:23;;;;20600:42;;57164:19:0;57142:42;;57129:56;57125:2;57121:65;;;20734:2:1;20719:18;;20712:43;-1:-1:-1;;;;;20791:15:1;;20771:18;;;20764:43;57954:20:0;57932:43;;57919:57;20823:18:1;;;20816:34;20881:3;20866:19;;20859:35;;;20925:3;20910:19;;20903:35;;;90419:368:0;;;;;20587:3:1;90419:368:0;;;91002:25;-1:-1:-1;;;;;91002:25:0;;;90998:769;;91124:14;;91120:50;;91147:23;;;;;;;;;;;;;;91120:50;91258:6;91245:9;:19;91241:51;;91273:19;;;;;;;;;;;;;;91241:51;90998:769;;;91501:9;91488;:22;91484:54;;91519:19;;;;;;;;;;;;;;91484:54;91702;-1:-1:-1;;;;;91702:30:0;;91733:10;91745:2;91749:6;91702:30;:54::i;:::-;92265:22;;92290:17;:7;;:15;:17::i;:::-;92265:42;;-1:-1:-1;92265:42:0;-1:-1:-1;92321:19:0;;92317:882;;92678:86;92712:2;92723:5;92738:6;92755:7;;92678:21;:86::i;:::-;92317:882;;;92785:9;:14;92781:418;;93147:41;93173:2;93178:9;93147:17;:41::i;:::-;89717:3488;;;;;;;89646:3559;;;:::o;84457:473::-;84538:4;84582:30;;;:15;:30;;;;;84738:27;84726:8;;;;:39;;;;;;;;:::i;:::-;;84722:69;;84774:17;;;;;;;;;;;;;;84722:69;84805:14;;-1:-1:-1;;;;;84805:25:0;;;:14;;;;;:25;84801:55;;84839:17;;;;;;;;;;;;;;84801:55;84884:21;81242:10;84884:21;;;;;;;;101235:15;101228:45;101220:53;84873:50;;;-1:-1:-1;;;84457:473:0:o;85262:1120::-;-1:-1:-1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;85465:36:0;;;;;:4;;:27;;:36;;85493:7;;;;85465:36;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;85465:36:0;;;;;;;;;;;;:::i;:::-;;;85461:915;;86325:40;;;;86336:7;86325:40;:::i;:::-;86318:47;;;;85461:915;85652:597;;;;;;;;85703:4;:18;;;85652:597;;;;;;85752:4;:16;;;85652:597;;;;;;85800:4;:17;;;-1:-1:-1;;;;;85652:597:0;;;;;85850:4;:18;;;-1:-1:-1;;;;;85652:597:0;;;;;85899:4;:16;;;-1:-1:-1;;;;;85652:597:0;;;;;85944:4;:14;;;-1:-1:-1;;;;;85652:597:0;;;;;85990:4;:17;;;85652:597;;;;86037:4;:15;;;85652:597;;;;86087:4;:20;;;85652:597;;;;86139:4;:14;;;86157:1;86139:19;;85652:597;;;;;;86186:4;:13;;;85652:597;;;;86224:4;:10;;;85652:597;;;85645:604;;;;;83278:939;77081:23;68919:16;68930:4;68919:10;:16::i;:::-;83358:25:::1;83386:30:::0;;;:15:::1;:30;::::0;;;;83520:14;;;;::::1;-1:-1:-1::0;;;;;83520:14:0::1;::::0;83566:8:::1;::::0;::::1;::::0;83613:21;;::::1;;;83741:27;83731:6;:37;;;;;;;;:::i;:::-;;83727:67;;83777:17;;;;;;;;;;;;;;83727:67;81242:10;101235:15:::0;101228:45;;;101220:53;;83808:48:::1;83804:107;;;83879:21;;;;;;;;;;;;;;83804:107;84038:33:::0;;84118:25;;84049:22:::1;84118:25:::0;;;84159:51:::1;::::0;-1:-1:-1;;;;;84159:51:0;::::1;::::0;84179:13;;84159:51:::1;::::0;-1:-1:-1;;84159:51:0::1;83348:869;;;;83278:939:::0;;:::o;79505:290::-;77594:26;68919:16;68930:4;68919:10;:16::i;:::-;77833:6:::1;79600:10;:25;79596:55;;;79634:17;;;;;;;;;;;;;;79596:55;79682:15;::::0;;79707:28;;;;79750:38:::1;::::0;;25249:25:1;;;25305:2;25290:18;;25283:34;;;79750:38:0::1;::::0;25222:18:1;79750:38:0::1;;;;;;;79586:209;79505:290:::0;;:::o;86663:2943::-;87018:21;;86764:25;;-1:-1:-1;;;;;87018:35:0;;87014:145;;87116:32;;;;87090:58;;87097:15;87090:58;:::i;:::-;87069:79;;87014:145;87168:59;87190:6;87198:8;87208:18;87168:21;:59::i;:::-;87363:20;87386:62;87408:6;:18;;;87428:6;:19;;;87386:21;:62::i;:::-;87363:85;;87516:23;87571:1;87553:15;;:19;87549:222;;;77721:3;87622:15;;87607:12;:30;;;;:::i;:::-;87606:42;;;;:::i;:::-;87588:60;-1:-1:-1;87662:31:0;87588:60;87662:31;;:::i;:::-;;;87549:222;87816:20;87839:973;87884:918;;;;;;;;87944:13;87884:918;;;;;;87989:6;:17;;;87884:918;;;;;;88038:6;:13;;;-1:-1:-1;;;;;87884:918:0;;;;;88084:6;:9;;;-1:-1:-1;;;;;87884:918:0;;;;;88124:6;:18;;;-1:-1:-1;;;;;87884:918:0;;;;;88171:6;:16;;;-1:-1:-1;;;;;87884:918:0;;;;;88219:12;87884:918;;;;88261:6;:17;;;87884:918;;;;88313:15;87884:918;;;;88356:6;:15;;;87884:918;;;;88396:12;:27;88409:6;:13;;;-1:-1:-1;;;;;88396:27:0;-1:-1:-1;;;;;88396:27:0;;;;;;;;;;;;;:29;;;;;;;;;:::i;:::-;;;;-1:-1:-1;87884:918:0;;88498:21;;-1:-1:-1;;;;;87884:918:0;;;;;;;;;;;;88726:18;;;;87884:918;;;;;88771:16;;;;87884:918;;;87839:31;:973::i;:::-;88846:18;;;;;;;;;;88822:21;88985:30;;;:15;:30;;;;;;;:62;;89102:17;;89057:62;;;;;;;;;;;;;89025:22;89057:62;;;;89215:13;;;;89329:18;;;;;89372:16;;;;89454:17;;;;89499:18;;;;89135:398;;88846:18;;-1:-1:-1;88846:18:0;;-1:-1:-1;;;;;89135:398:0;;;;88846:18;;89135:398;;;;88846:18;;89102:17;;89329:18;89416:12;;89454:17;;89499:23;;;;89135:398;:::i;:::-;;;;;;;;89567:13;89548:51;89582:8;:16;;;89548:51;;;;;;:::i;:::-;;;;;;;;86754:2852;;;;;86663:2943;;:::o;83082:158::-;83192:41;83208:7;;83229:1;83192:5;:41::i;75176:131::-;75247:7;75273:18;;;:12;:18;;;;;:27;;:25;:27::i;71097:138::-;70330:7;70356:12;;;;;;;;;;:22;;;68919:16;68930:4;68919:10;:16::i;:::-;71202:26:::1;71214:4;71220:7;71202:11;:26::i;69020:202::-:0;69105:4;69128:47;;;69143:32;69128:47;;:87;;-1:-1:-1;49356:25:0;49341:40;;;;69179:36;49242:146;69654:103;69720:30;69731:4;23372:10;69720;:30::i;17904:331::-;18013:6;17989:21;:30;17985:109;;;18042:41;;;;;18077:4;18042:41;;;2867:74:1;2840:18;;18042:41:0;;;;;;;;17985:109;18105:12;18123:9;-1:-1:-1;;;;;18123:14:0;18145:6;18123:33;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;18104:52;;;18171:7;18166:63;;18201:17;;;;;;;;;;;;;;62137:160;62246:43;;-1:-1:-1;;;;;20205:55:1;;;62246:43:0;;;20187:74:1;20277:18;;;20270:34;;;62219:71:0;;62239:5;;62261:14;;;;;20160:18:1;;62246:43:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;62219:19;:71::i;80577:290::-;77959:7;80648:14;:33;80644:67;;;80690:21;;;;;;;;;;;;;;80644:67;80746:11;;;80767:28;;;;80810:50;;;25249:25:1;;;25305:2;25290:18;;25283:34;;;80810:50:0;;25222:18:1;80810:50:0;;;;;;;80634:233;80577:290;:::o;75409:257::-;75495:4;75511:12;75526:31;75543:4;75549:7;75526:16;:31::i;:::-;75511:46;;75571:7;75567:69;;;75594:18;;;;:12;:18;;;;;:31;;75617:7;75594:22;:31::i;75769:262::-;75856:4;75872:12;75887:32;75905:4;75911:7;75887:17;:32::i;:::-;75872:47;;75933:7;75929:72;;;75956:18;;;;:12;:18;;;;;:34;;75982:7;75956:25;:34::i;46692:556::-;46830:17;;:21;46826:416;;47071:10;47065:17;47127:15;47114:10;47110:2;47106:19;47099:44;46826:416;47194:37;;;;;;;;;;;;;;51826:469;51445:3;51978:34;;51974:86;;;52021:39;;;;;;;;;;;;;;51974:86;55092:30;;55087:3;55083:40;49545:1;52211:19;;52207:81;;52239:49;;;;;27697:6:1;27685:19;;52239:49:0;;;27667:38:1;27640:18;;52239:49:0;27523:188:1;53789:990:0;53880:49;-1:-1:-1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;53880:49:0;55514:22;55492:45;;55479:59;55474:3;55470:69;;;53945:49;;55929:20;55907:43;;55894:57;55885:67;;54004:20;;;:45;56338:20;56316:43;;56303:57;56299:2;56295:66;;;54059:21;;;:47;56758:21;56736:44;;56723:58;56715:67;;54116:22;;;:49;57164:19;57142:42;;57129:56;57121:65;;54175:20;;;:45;57567:17;57545:40;;57532:54;57524:63;;54230:18;;;:41;57954:20;57932:43;;57919:57;54281:21;;;:47;58342:18;58320:41;;58307:55;54338:19;;;:43;;;;58742:24;58720:47;;58707:61;54391:24;;;:53;59118:15;59096:38;;59083:52;54454:17;;;:39;59473:12;59451:35;;59438:49;54503:14;;;:33;59897:26;59875:49;;59862:63;59854:72;;54546:27;;;:59;60318:27;60296:50;;60283:64;54615:27;;;:59;60710:17;60688:40;;60675:54;54684:18;;;:41;54754:18;55492:45;54762:9;54754:7;:18::i;:::-;54735:37;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;54735:16:0;;;:37;:8;53789:990;-1:-1:-1;;53789:990:0:o;34075:156::-;34149:7;34199:22;34203:3;34215:5;34199:3;:22::i;102836:808::-;-1:-1:-1;;;;;102958:21:0;;102954:47;;102988:13;;;;;;;;;;;;;;102954:47;97933:4;98004:33;;;:18;:33;;;;;:41;;;;-1:-1:-1;;;;;98004:41:0;:55;103072:60;;103112:20;;;;;;;;;;;;;;103072:60;55929:20;55907:43;;55894:57;55889:3;55885:67;103171:13;103146:38;103142:67;;103193:16;;;;;;;;;;;;;;103142:67;59118:15;59096:38;;59083:52;103273:15;:36;103269:67;;;103318:18;;;;;;;;;;;;;;103269:67;59897:26;59875:49;;59862:63;59858:2;59854:72;103474:25;;;;;:51;;;103518:7;-1:-1:-1;;;;;103503:22:0;:11;-1:-1:-1;;;;;103503:22:0;;;103474:51;:102;;;;-1:-1:-1;60318:27:0;60296:50;;60283:64;103529:15;:47;;103474:102;103470:168;;;103599:28;;;;;;;;;;;;;;103470:168;102944:700;102836:808;;;;:::o;62536:188::-;62663:53;;-1:-1:-1;;;;;18522:15:1;;;62663:53:0;;;18504:34:1;18574:15;;;18554:18;;;18547:43;18606:18;;;18599:34;;;62636:81:0;;62656:5;;62678:18;;;;;18416::1;;62663:53:0;18241:398:1;60821:146:0;60887:23;;60933:27;:9;51445:3;60933:9;;:27;:::i;:::-;60922:38;;;;60821:146;;;;;:::o;99685:951::-;99880:23;99906:255;99958:9;100022:5;100029:6;100037:7;;99987:59;;;;;;;;;;;:::i;:::-;;;;-1:-1:-1;;99987:59:0;;;;;;;;;;;;;;;;;;;;100141:9;99906:29;:255::i;:::-;99880:281;;100227:10;:17;100248:1;100227:22;100223:59;;100258:24;;;;;;;;;;;;;;100223:59;100361:10;:17;100382:2;100361:23;100357:67;;100393:31;;;;;;;;;;;;;;100357:67;100538:26;100507:19;100515:10;100507:19;:::i;:::-;:58;100503:127;;100588:31;;;;;;;;;;;;;;100503:127;99799:837;99685:951;;;;;:::o;101615:1142::-;101868:13;101847:6;:17;;;:34;;;101843:63;;101890:16;;;;;;;;;;;;;;101843:63;101920:19;;;;:24;;:50;;-1:-1:-1;101948:17:0;;;;:22;101920:50;101916:80;;;101979:17;;;;;;;;;;;;;;101916:80;102010:13;;;;-1:-1:-1;;;;;102010:27:0;;;:54;;-1:-1:-1;102041:9:0;;;;-1:-1:-1;;;;;102041:23:0;;102010:54;102006:80;;;102073:13;;;;;;;;;;;;;;102006:80;102100:18;;;;-1:-1:-1;;;;;102100:32:0;;;:66;;-1:-1:-1;102136:16:0;;;;-1:-1:-1;;;;;102136:30:0;;102100:66;102096:92;;;102175:13;;;;;;;;;;;;;;102096:92;102220:37;81385:10;102220:15;:37;:::i;:::-;102202:6;:15;;;:55;102198:86;;;102266:18;;;;;;;;;;;;;;102198:86;81499:11;102325:8;:16;;;:23;:45;102321:81;;;102379:23;;;;;;;;;;;;;;102321:81;102416:18;;;;:23;;;;:63;;-1:-1:-1;102443:16:0;;;;-1:-1:-1;;;;;102443:36:0;76322:42;102443:36;102416:63;102412:124;;;102502:23;;;;;;;;;;;;;;102412:124;102640:1;102619:18;:22;:70;;;;102673:6;:15;;;102645:18;:44;102619:70;102615:136;;;102712:28;;;;;;;;;;;;;;98345:1185;98425:19;98460:25;-1:-1:-1;;;;;98460:25:0;;;98456:1068;;98690:9;98680:6;:19;98676:51;;98708:19;;;;;;;;;;;;;;98676:51;-1:-1:-1;98755:9:0;98456:1068;;;98995:9;:14;98991:46;;99018:19;;;;;;;;;;;;;;98991:46;99142:5;-1:-1:-1;;;;;99142:17:0;;99163:1;99142:22;99138:53;;99173:18;;;;;;;;;;;;;;99138:53;99219:38;;;;;99251:4;99219:38;;;2867:74:1;-1:-1:-1;;;;;99219:23:0;;;;;2840:18:1;;99219:38:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;99205:52;-1:-1:-1;99271:65:0;-1:-1:-1;;;;;99271:30:0;;99302:10;99322:4;99329:6;99271:30;:65::i;:::-;99461:38;;;;;99493:4;99461:38;;;2867:74:1;99502:11:0;;-1:-1:-1;;;;;99461:23:0;;;;;2840:18:1;;99461:38:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;:52;;;;:::i;52503:1038::-;52773:22;;52809:20;;;;;52843:21;;;;;52595:12;52878:22;;;;52914:20;;;;52948:18;;;;52980:21;;;;52722:289;;29378:16:1;52722:289:0;;;29362:102:1;;;;29483:66;29586:3;29582:16;;;29578:25;;29565:11;;;29558:46;29637:16;;;;29633:25;;;29620:11;;;29613:46;29678:66;29778:15;;;29774:24;;29760:12;;;29753:46;29833:15;;29829:24;;29815:12;;;29808:46;29888:15;;;29884:24;;29870:12;;;29863:46;29943:15;;;29939:24;;;29925:12;;;29918:46;29980:12;;;29973:28;;;;52697:22:0;;30017:13:1;;52722:289:0;;;-1:-1:-1;;52722:289:0;;;;;;;;;;53081:19;;;;53114:24;;;;53259:17;;;;53290:14;;;;53360:27;;;;53401;;;;53476:18;;;;53508:16;;;;52722:289;;-1:-1:-1;53028:506:0;;52722:289;;53508:16;52722:289;53028:506;;:::i;:::-;;;;;;;;;;;;;53021:513;;;52503:1038;;;:::o;33618:115::-;33681:7;33707:19;33715:3;29057:18;;28975:107;69887:197;69386:4;69409:12;;;;;;;;;;;-1:-1:-1;;;;;69409:29:0;;;;;;;;;;;;69970:108;;70020:47;;;;;-1:-1:-1;;;;;20205:55:1;;70020:47:0;;;20187:74:1;20277:18;;;20270:34;;;20160:18;;70020:47:0;20013:297:1;64893:629:0;65312:23;65338:33;-1:-1:-1;;;;;65338:27:0;;65366:4;65338:27;:33::i;:::-;65312:59;;65385:10;:17;65406:1;65385:22;;:57;;;;;65423:10;65412:30;;;;;;;;;;;;:::i;:::-;65411:31;65385:57;65381:135;;;65465:40;;;;;-1:-1:-1;;;;;2885:55:1;;65465:40:0;;;2867:74:1;2840:18;;65465:40:0;2721:226:1;72634:316:0;72711:4;69409:12;;;;;;;;;;;-1:-1:-1;;;;;69409:29:0;;;;;;;;;;;;72727:217;;72770:6;:12;;;;;;;;;;;-1:-1:-1;;;;;72770:29:0;;;;;;;;;:36;;;;72802:4;72770:36;;;72852:12;23372:10;;23293:96;72852:12;-1:-1:-1;;;;;72825:40:0;72843:7;-1:-1:-1;;;;;72825:40:0;72837:4;72825:40;;;;;;;;;;-1:-1:-1;72886:4:0;72879:11;;72727:217;-1:-1:-1;72928:5:0;72921:12;;32817:150;32887:4;32910:50;32915:3;-1:-1:-1;;;;;32935:23:0;;32910:4;:50::i;73185:317::-;73263:4;69409:12;;;;;;;;;;;-1:-1:-1;;;;;69409:29:0;;;;;;;;;;;;73279:217;;;73353:5;73321:12;;;;;;;;;;;-1:-1:-1;;;;;73321:29:0;;;;;;;;;;:37;;;;;;73377:40;23372:10;;73321:12;;73377:40;;73353:5;73377:40;-1:-1:-1;73438:4:0;73431:11;;33135:156;33208:4;33231:53;33239:3;-1:-1:-1;;;;;33259:23:0;;33231:7;:53::i;29424:118::-;29491:7;29517:3;:11;;29529:5;29517:18;;;;;;;;:::i;:::-;;;;;;;;;29510:25;;29424:118;;;;:::o;19553:392::-;19652:12;19704:5;19680:21;:29;19676:108;;;19732:41;;;;;19767:4;19732:41;;;2867:74:1;2840:18;;19732:41:0;2721:226:1;19676:108:0;19794:12;19808:23;19835:6;-1:-1:-1;;;;;19835:11:0;19854:5;19861:4;19835:31;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;19793:73;;;;19883:55;19910:6;19918:7;19927:10;19883:26;:55::i;:::-;19876:62;19553:392;-1:-1:-1;;;;;;19553:392:0:o;19078:151::-;19153:12;19184:38;19206:6;19214:4;19220:1;19184:21;:38::i;26742:406::-;26805:4;28861:21;;;:14;;;:21;;;;;;26821:321;;-1:-1:-1;26863:23:0;;;;;;;;:11;:23;;;;;;;;;;;;;27045:18;;27021:21;;;:14;;;:21;;;;;;:42;;;;27077:11;;27316:1368;27382:4;27511:21;;;:14;;;:21;;;;;;27547:13;;27543:1135;;27914:18;27935:12;27946:1;27935:8;:12;:::i;:::-;27981:18;;27914:33;;-1:-1:-1;27961:17:0;;27981:22;;28002:1;;27981:22;:::i;:::-;27961:42;;28036:9;28022:10;:23;28018:378;;28065:17;28085:3;:11;;28097:9;28085:22;;;;;;;;:::i;:::-;;;;;;;;;28065:42;;28232:9;28206:3;:11;;28218:10;28206:23;;;;;;;;:::i;:::-;;;;;;;;;;;;:35;;;;28345:25;;;:14;;;:25;;;;;:36;;;28018:378;28474:17;;:3;;:17;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;28577:3;:14;;:21;28592:5;28577:21;;;;;;;;;;;28570:28;;;28620:4;28613:11;;;;;;;27543:1135;28662:5;28655:12;;;;;20998:582;21142:12;21171:7;21166:408;;21194:19;21202:10;21194:7;:19::i;:::-;21166:408;;;21418:17;;:22;:49;;;;-1:-1:-1;;;;;;21444:18:0;;;:23;21418:49;21414:119;;;21494:24;;;;;-1:-1:-1;;;;;2885:55:1;;21494:24:0;;;2867:74:1;2840:18;;21494:24:0;2721:226:1;21414:119:0;-1:-1:-1;21553:10:0;21546:17;;22116:516;22247:17;;:21;22243:383;;22475:10;22469:17;22531:15;22518:10;22514:2;22510:19;22503:44;22243:383;22598:17;;;;;;;;;;;;;;14:332:1;72:6;125:2;113:9;104:7;100:23;96:32;93:52;;;141:1;138;131:12;93:52;180:9;167:23;230:66;223:5;219:78;212:5;209:89;199:117;;312:1;309;302:12;821:180;880:6;933:2;921:9;912:7;908:23;904:32;901:52;;;949:1;946;939:12;901:52;-1:-1:-1;972:23:1;;821:180;-1:-1:-1;821:180:1:o;1006:184::-;1058:77;1055:1;1048:88;1155:4;1152:1;1145:15;1179:4;1176:1;1169:15;1195:297;1279:1;1272:5;1269:12;1259:200;;1315:77;1312:1;1305:88;1416:4;1413:1;1406:15;1444:4;1441:1;1434:15;1259:200;1468:18;;1195:297::o;1497:214::-;1646:2;1631:18;;1658:47;1635:9;1687:6;1658:47;:::i;1716:154::-;-1:-1:-1;;;;;1795:5:1;1791:54;1784:5;1781:65;1771:93;;1860:1;1857;1850:12;1875:134;1943:20;;1972:31;1943:20;1972:31;:::i;:::-;1875:134;;;:::o;2014:388::-;2082:6;2090;2143:2;2131:9;2122:7;2118:23;2114:32;2111:52;;;2159:1;2156;2149:12;2111:52;2198:9;2185:23;2217:31;2242:5;2217:31;:::i;:::-;2267:5;-1:-1:-1;2324:2:1;2309:18;;2296:32;2337:33;2296:32;2337:33;:::i;:::-;2389:7;2379:17;;;2014:388;;;;;:::o;2952:383::-;3029:6;3037;3045;3098:2;3086:9;3077:7;3073:23;3069:32;3066:52;;;3114:1;3111;3104:12;3066:52;3150:9;3137:23;3127:33;;3207:2;3196:9;3192:18;3179:32;3169:42;;3261:2;3250:9;3246:18;3233:32;3274:31;3299:5;3274:31;:::i;:::-;3324:5;3314:15;;;2952:383;;;;;:::o;3525:247::-;3584:6;3637:2;3625:9;3616:7;3612:23;3608:32;3605:52;;;3653:1;3650;3643:12;3605:52;3692:9;3679:23;3711:31;3736:5;3711:31;:::i;3777:315::-;3845:6;3853;3906:2;3894:9;3885:7;3881:23;3877:32;3874:52;;;3922:1;3919;3912:12;3874:52;3958:9;3945:23;3935:33;;4018:2;4007:9;4003:18;3990:32;4031:31;4056:5;4031:31;:::i;4097:118::-;4183:5;4176:13;4169:21;4162:5;4159:32;4149:60;;4205:1;4202;4195:12;4220:128;4285:20;;4314:28;4285:20;4314:28;:::i;4353:761::-;4456:6;4464;4472;4525:2;4513:9;4504:7;4500:23;4496:32;4493:52;;;4541:1;4538;4531:12;4493:52;4581:9;4568:23;4610:18;4651:2;4643:6;4640:14;4637:34;;;4667:1;4664;4657:12;4637:34;4705:6;4694:9;4690:22;4680:32;;4750:7;4743:4;4739:2;4735:13;4731:27;4721:55;;4772:1;4769;4762:12;4721:55;4812:2;4799:16;4838:2;4830:6;4827:14;4824:34;;;4854:1;4851;4844:12;4824:34;4909:7;4902:4;4892:6;4889:1;4885:14;4881:2;4877:23;4873:34;4870:47;4867:67;;;4930:1;4927;4920:12;4867:67;4961:4;4953:13;;;;-1:-1:-1;4985:6:1;-1:-1:-1;;5026:20:1;;5013:34;5056:28;5013:34;5056:28;:::i;5119:250::-;5204:1;5214:113;5228:6;5225:1;5222:13;5214:113;;;5304:11;;;5298:18;5285:11;;;5278:39;5250:2;5243:10;5214:113;;;-1:-1:-1;;5361:1:1;5343:16;;5336:27;5119:250::o;5374:329::-;5415:3;5453:5;5447:12;5480:6;5475:3;5468:19;5496:76;5565:6;5558:4;5553:3;5549:14;5542:4;5535:5;5531:16;5496:76;:::i;:::-;5617:2;5605:15;-1:-1:-1;;5601:88:1;5592:98;;;;5692:4;5588:109;;5374:329;-1:-1:-1;;5374:329:1:o;5708:1097::-;5896:4;5925:2;5965;5954:9;5950:18;5995:2;5984:9;5977:21;6018:6;6053;6047:13;6084:6;6076;6069:22;6110:2;6100:12;;6143:2;6132:9;6128:18;6121:25;;6205:2;6195:6;6192:1;6188:14;6177:9;6173:30;6169:39;6243:2;6235:6;6231:15;6264:1;6274:502;6288:6;6285:1;6282:13;6274:502;;;6353:22;;;6377:66;6349:95;6337:108;;6468:13;;6523:9;;6516:17;6509:25;6494:41;;6574:11;;6568:18;6606:15;;;6599:27;;;6649:47;6680:15;;;6568:18;6649:47;:::i;:::-;6754:12;;;;6639:57;-1:-1:-1;;6719:15:1;;;;6310:1;6303:9;6274:502;;;-1:-1:-1;6793:6:1;;5708:1097;-1:-1:-1;;;;;;;;5708:1097:1:o;6810:347::-;6861:8;6871:6;6925:3;6918:4;6910:6;6906:17;6902:27;6892:55;;6943:1;6940;6933:12;6892:55;-1:-1:-1;6966:20:1;;7009:18;6998:30;;6995:50;;;7041:1;7038;7031:12;6995:50;7078:4;7070:6;7066:17;7054:29;;7130:3;7123:4;7114:6;7106;7102:19;7098:30;7095:39;7092:59;;;7147:1;7144;7137:12;7092:59;6810:347;;;;;:::o;7162:409::-;7232:6;7240;7293:2;7281:9;7272:7;7268:23;7264:32;7261:52;;;7309:1;7306;7299:12;7261:52;7349:9;7336:23;7382:18;7374:6;7371:30;7368:50;;;7414:1;7411;7404:12;7368:50;7453:58;7503:7;7494:6;7483:9;7479:22;7453:58;:::i;:::-;7530:8;;7427:84;;-1:-1:-1;7162:409:1;-1:-1:-1;;;;7162:409:1:o;7576:544::-;7655:6;7663;7671;7724:2;7712:9;7703:7;7699:23;7695:32;7692:52;;;7740:1;7737;7730:12;7692:52;7780:9;7767:23;7813:18;7805:6;7802:30;7799:50;;;7845:1;7842;7835:12;7799:50;7884:58;7934:7;7925:6;7914:9;7910:22;7884:58;:::i;:::-;7961:8;;-1:-1:-1;7858:84:1;-1:-1:-1;;8046:2:1;8031:18;;8018:32;8059:31;8018:32;8059:31;:::i;8125:184::-;8177:77;8174:1;8167:88;8274:4;8271:1;8264:15;8298:4;8295:1;8288:15;8314:255;8386:2;8380:9;8428:6;8416:19;;8465:18;8450:34;;8486:22;;;8447:62;8444:88;;;8512:18;;:::i;:::-;8548:2;8541:22;8314:255;:::o;8574:253::-;8646:2;8640:9;8688:4;8676:17;;8723:18;8708:34;;8744:22;;;8705:62;8702:88;;;8770:18;;:::i;8832:255::-;8904:2;8898:9;8946:6;8934:19;;8983:18;8968:34;;9004:22;;;8965:62;8962:88;;;9030:18;;:::i;9092:252::-;9164:2;9158:9;9206:3;9194:16;;9240:18;9225:34;;9261:22;;;9222:62;9219:88;;;9287:18;;:::i;9349:334::-;9420:2;9414:9;9476:2;9466:13;;-1:-1:-1;;9462:86:1;9450:99;;9579:18;9564:34;;9600:22;;;9561:62;9558:88;;;9626:18;;:::i;:::-;9662:2;9655:22;9349:334;;-1:-1:-1;9349:334:1:o;9688:121::-;9773:10;9766:5;9762:22;9755:5;9752:33;9742:61;;9799:1;9796;9789:12;9814:132;9881:20;;9910:30;9881:20;9910:30;:::i;9951:806::-;10010:5;10058:6;10046:9;10041:3;10037:19;10033:32;10030:52;;;10078:1;10075;10068:12;10030:52;10100:22;;:::i;:::-;10091:31;;10145:28;10163:9;10145:28;:::i;:::-;10138:5;10131:43;10206:38;10240:2;10229:9;10225:18;10206:38;:::i;:::-;10201:2;10194:5;10190:14;10183:62;10277:38;10311:2;10300:9;10296:18;10277:38;:::i;:::-;10272:2;10265:5;10261:14;10254:62;10348:38;10382:2;10371:9;10367:18;10348:38;:::i;:::-;10343:2;10336:5;10332:14;10325:62;10420:39;10454:3;10443:9;10439:19;10420:39;:::i;:::-;10414:3;10407:5;10403:15;10396:64;10521:3;10510:9;10506:19;10493:33;10487:3;10480:5;10476:15;10469:58;10588:3;10577:9;10573:19;10560:33;10554:3;10547:5;10543:15;10536:58;10627:36;10658:3;10647:9;10643:19;10627:36;:::i;:::-;10621:3;10614:5;10610:15;10603:61;10683:3;10746:2;10735:9;10731:18;10718:32;10713:2;10706:5;10702:14;10695:56;;9951:806;;;;:::o;10762:237::-;10850:6;10903:3;10891:9;10882:7;10878:23;10874:33;10871:53;;;10920:1;10917;10910:12;10871:53;10943:50;10985:7;10974:9;10943:50;:::i;11103:1865::-;11306:2;11295:9;11288:21;11318:52;11366:2;11355:9;11351:18;11342:6;11336:13;11080:10;11069:22;11057:35;;11004:94;11318:52;11269:4;11417:2;11409:6;11405:15;11399:22;11430:51;11477:2;11466:9;11462:18;11448:12;11080:10;11069:22;11057:35;;11004:94;11430:51;-1:-1:-1;11530:2:1;11518:15;;11512:22;-1:-1:-1;;;;;2655:54:1;;11593:2;11578:18;;2643:67;-1:-1:-1;11646:2:1;11634:15;;11628:22;-1:-1:-1;;;;;2655:54:1;;11709:3;11694:19;;2643:67;-1:-1:-1;11763:3:1;11751:16;;11745:23;-1:-1:-1;;;;;2655:54:1;;11827:3;11812:19;;2643:67;-1:-1:-1;11881:3:1;11869:16;;11863:23;-1:-1:-1;;;;;2655:54:1;;11945:3;11930:19;;2643:67;-1:-1:-1;12005:3:1;11993:16;;11987:23;11981:3;11966:19;;;11959:52;;;;12036:16;;12030:23;12072:3;12091:18;;;12084:30;;;;12139:15;;12133:22;12174:3;12193:18;;;12186:30;;;;12241:15;;12235:22;12276:3;12295:18;;;12288:30;;;;12343:15;;12337:22;12378:3;12397:18;;;12390:30;;;;12457:15;;12451:22;12492:3;12504:54;12539:18;;;12451:22;-1:-1:-1;;;;;2655:54:1;2643:67;;2589:127;12504:54;12584:15;;12578:22;12620:3;12639:19;;;12632:32;;;;12690:16;;12684:23;12727:3;12746:19;;;12739:32;;;;12808:16;;12802:23;12845:6;12867:19;;;12860:32;12802:23;-1:-1:-1;12909:53:1;12957:3;12942:19;;12802:23;12909:53;:::i;:::-;12901:61;11103:1865;-1:-1:-1;;;;11103:1865:1:o;12973:513::-;13202:3;13187:19;;13215:47;13191:9;13244:6;13215:47;:::i;:::-;13310:10;13302:6;13298:23;13293:2;13282:9;13278:18;13271:51;13370:16;13362:6;13358:29;13353:2;13342:9;13338:18;13331:57;-1:-1:-1;;;;;13428:6:1;13424:55;13419:2;13408:9;13404:18;13397:83;12973:513;;;;;;;:::o;13491:477::-;13570:6;13578;13586;13639:2;13627:9;13618:7;13614:23;13610:32;13607:52;;;13655:1;13652;13645:12;13607:52;13695:9;13682:23;13728:18;13720:6;13717:30;13714:50;;;13760:1;13757;13750:12;13714:50;13799:58;13849:7;13840:6;13829:9;13825:22;13799:58;:::i;:::-;13876:8;;13773:84;;-1:-1:-1;13958:2:1;13943:18;;;;13930:32;;13491:477;-1:-1:-1;;;;13491:477:1:o;13973:248::-;14041:6;14049;14102:2;14090:9;14081:7;14077:23;14073:32;14070:52;;;14118:1;14115;14108:12;14070:52;-1:-1:-1;;14141:23:1;;;14211:2;14196:18;;;14183:32;;-1:-1:-1;13973:248:1:o;14559:1373::-;14790:13;;11080:10;11069:22;11057:35;;14759:3;14744:19;;14862:4;14854:6;14850:17;14844:24;14877:53;14924:4;14913:9;14909:20;14895:12;11080:10;11069:22;11057:35;;11004:94;14877:53;;14979:4;14971:6;14967:17;14961:24;14994:56;15044:4;15033:9;15029:20;15013:14;-1:-1:-1;;;;;2655:54:1;2643:67;;2589:127;14994:56;;15099:4;15091:6;15087:17;15081:24;15114:56;15164:4;15153:9;15149:20;15133:14;-1:-1:-1;;;;;2655:54:1;2643:67;;2589:127;15114:56;;15219:4;15211:6;15207:17;15201:24;15234:56;15284:4;15273:9;15269:20;15253:14;-1:-1:-1;;;;;2655:54:1;2643:67;;2589:127;15234:56;;15339:4;15331:6;15327:17;15321:24;15354:56;15404:4;15393:9;15389:20;15373:14;-1:-1:-1;;;;;2655:54:1;2643:67;;2589:127;15354:56;;15466:4;15458:6;15454:17;15448:24;15441:4;15430:9;15426:20;15419:54;15529:4;15521:6;15517:17;15511:24;15504:4;15493:9;15489:20;15482:54;15555:6;15615:2;15607:6;15603:15;15597:22;15592:2;15581:9;15577:18;15570:50;;15639:6;15694:2;15686:6;15682:15;15676:22;15707:51;15754:2;15743:9;15739:18;15723:14;421:13;414:21;402:34;;351:91;15707:51;-1:-1:-1;;15777:6:1;15825:15;;;15819:22;15799:18;;;15792:50;15861:6;15909:15;;;15903:22;15883:18;;;;15876:50;;;;14559:1373;:::o;15937:245::-;15985:4;16018:18;16010:6;16007:30;16004:56;;;16040:18;;:::i;:::-;-1:-1:-1;16097:2:1;16085:15;-1:-1:-1;;16081:88:1;16171:4;16077:99;;15937:245::o;16187:462::-;16229:5;16282:3;16275:4;16267:6;16263:17;16259:27;16249:55;;16300:1;16297;16290:12;16249:55;16336:6;16323:20;16367:48;16383:31;16411:2;16383:31;:::i;:::-;16367:48;:::i;:::-;16440:2;16431:7;16424:19;16486:3;16479:4;16474:2;16466:6;16462:15;16458:26;16455:35;16452:55;;;16503:1;16500;16493:12;16452:55;16568:2;16561:4;16553:6;16549:17;16542:4;16533:7;16529:18;16516:55;16616:1;16591:16;;;16609:4;16587:27;16580:38;;;;16595:7;16187:462;-1:-1:-1;;;16187:462:1:o;16654:1162::-;16783:6;16791;16844:3;16832:9;16823:7;16819:23;16815:33;16812:53;;;16861:1;16858;16851:12;16812:53;16884:50;16926:7;16915:9;16884:50;:::i;:::-;16874:60;;16985:3;16974:9;16970:19;16957:33;17009:18;17050:2;17042:6;17039:14;17036:34;;;17066:1;17063;17056:12;17036:34;17089:22;;;;17145:4;17127:16;;;17123:27;17120:47;;;17163:1;17160;17153:12;17120:47;17189:22;;:::i;:::-;17248:2;17235:16;17260:33;17285:7;17260:33;:::i;:::-;17302:22;;17377:2;17369:11;;;17356:25;17340:14;;;17333:49;17428:2;17420:11;;17407:25;17444:16;;;17441:36;;;17473:1;17470;17463:12;17441:36;17509:44;17545:7;17534:8;17530:2;17526:17;17509:44;:::i;:::-;17504:2;17497:5;17493:14;17486:68;;17607:2;17603;17599:11;17586:25;17581:2;17574:5;17570:14;17563:49;17658:3;17654:2;17650:12;17637:26;17688:2;17678:8;17675:16;17672:36;;;17704:1;17701;17694:12;17672:36;17741:44;17777:7;17766:8;17762:2;17758:17;17741:44;:::i;:::-;17735:3;17728:5;17724:15;17717:69;;17805:5;17795:15;;;;;16654:1162;;;;;:::o;18644:184::-;18696:77;18693:1;18686:88;18793:4;18790:1;18783:15;18817:4;18814:1;18807:15;18833:580;18910:4;18916:6;18976:11;18963:25;19066:66;19055:8;19039:14;19035:29;19031:102;19011:18;19007:127;18997:155;;19148:1;19145;19138:12;18997:155;19175:33;;19227:20;;;-1:-1:-1;19270:18:1;19259:30;;19256:50;;;19302:1;19299;19292:12;19256:50;19335:4;19323:17;;-1:-1:-1;19366:14:1;19362:27;;;19352:38;;19349:58;;;19403:1;19400;19393:12;19418:271;19601:6;19593;19588:3;19575:33;19557:3;19627:16;;19652:13;;;19627:16;19418:271;-1:-1:-1;19418:271:1:o;19694:184::-;19746:77;19743:1;19736:88;19843:4;19840:1;19833:15;19867:4;19864:1;19857:15;19883:125;19948:9;;;19969:10;;;19966:36;;;19982:18;;:::i;20949:325::-;21037:6;21032:3;21025:19;21089:6;21082:5;21075:4;21070:3;21066:14;21053:43;;21141:1;21134:4;21125:6;21120:3;21116:16;21112:27;21105:38;21007:3;21263:4;-1:-1:-1;;21188:2:1;21180:6;21176:15;21172:88;21167:3;21163:98;21159:109;21152:116;;20949:325;;;;:::o;21279:244::-;21436:2;21425:9;21418:21;21399:4;21456:61;21513:2;21502:9;21498:18;21490:6;21482;21456:61;:::i;21528:136::-;21606:13;;21628:30;21606:13;21628:30;:::i;21669:138::-;21748:13;;21770:31;21748:13;21770:31;:::i;21812:441::-;21865:5;21918:3;21911:4;21903:6;21899:17;21895:27;21885:55;;21936:1;21933;21926:12;21885:55;21965:6;21959:13;21996:48;22012:31;22040:2;22012:31;:::i;21996:48::-;22069:2;22060:7;22053:19;22115:3;22108:4;22103:2;22095:6;22091:15;22087:26;22084:35;22081:55;;;22132:1;22129;22122:12;22081:55;22145:77;22219:2;22212:4;22203:7;22199:18;22192:4;22184:6;22180:17;22145:77;:::i;22258:1672::-;22365:6;22418:2;22406:9;22397:7;22393:23;22389:32;22386:52;;;22434:1;22431;22424:12;22386:52;22467:9;22461:16;22496:18;22537:2;22529:6;22526:14;22523:34;;;22553:1;22550;22543:12;22523:34;22576:22;;;;22632:6;22614:16;;;22610:29;22607:49;;;22652:1;22649;22642:12;22607:49;22678:22;;:::i;:::-;22723:32;22752:2;22723:32;:::i;:::-;22716:5;22709:47;22788:41;22825:2;22821;22817:11;22788:41;:::i;:::-;22783:2;22776:5;22772:14;22765:65;22862:42;22900:2;22896;22892:11;22862:42;:::i;:::-;22857:2;22850:5;22846:14;22839:66;22937:42;22975:2;22971;22967:11;22937:42;:::i;:::-;22932:2;22925:5;22921:14;22914:66;23013:43;23051:3;23047:2;23043:12;23013:43;:::i;:::-;23007:3;23000:5;22996:15;22989:68;23090:43;23128:3;23124:2;23120:12;23090:43;:::i;:::-;23084:3;23073:15;;23066:68;23181:3;23173:12;;;23167:19;23150:15;;;23143:44;23234:3;23226:12;;;23220:19;23203:15;;;23196:44;23259:3;23300:11;;;23294:18;23278:14;;;23271:42;23332:3;23373:11;;;23367:18;23351:14;;;23344:42;23405:3;23446:11;;;23440:18;23424:14;;;23417:42;23478:3;23513:42;23543:11;;;23513:42;:::i;:::-;23497:14;;;23490:66;23575:3;23616:11;;;23610:18;23594:14;;;23587:42;23648:3;23689:11;;;23683:18;23667:14;;;23660:42;23721:3;23755:11;;;23749:18;23779:16;;;23776:36;;;23808:1;23805;23798:12;23776:36;23844:55;23891:7;23880:8;23876:2;23872:17;23844:55;:::i;:::-;23828:14;;;23821:79;;;;-1:-1:-1;23832:5:1;22258:1672;-1:-1:-1;;;;;22258:1672:1:o;23935:1135::-;24027:6;24080:3;24068:9;24059:7;24055:23;24051:33;24048:53;;;24097:1;24094;24087:12;24048:53;24123:22;;:::i;:::-;24168:28;24186:9;24168:28;:::i;:::-;24161:5;24154:43;24229:37;24262:2;24251:9;24247:18;24229:37;:::i;:::-;24224:2;24217:5;24213:14;24206:61;24299:38;24333:2;24322:9;24318:18;24299:38;:::i;:::-;24294:2;24287:5;24283:14;24276:62;24370:38;24404:2;24393:9;24389:18;24370:38;:::i;:::-;24365:2;24358:5;24354:14;24347:62;24442:39;24476:3;24465:9;24461:19;24442:39;:::i;:::-;24436:3;24429:5;24425:15;24418:64;24515:39;24549:3;24538:9;24534:19;24515:39;:::i;:::-;24509:3;24502:5;24498:15;24491:64;24616:3;24605:9;24601:19;24588:33;24582:3;24575:5;24571:15;24564:58;24683:3;24672:9;24668:19;24655:33;24649:3;24642:5;24638:15;24631:58;24708:3;24771:2;24760:9;24756:18;24743:32;24738:2;24731:5;24727:14;24720:56;;24795:3;24830:35;24861:2;24850:9;24846:18;24830:35;:::i;:::-;24814:14;;;24807:59;24885:3;24933:18;;;24920:32;24904:14;;;24897:56;24972:3;25020:18;;;25007:32;24991:14;;;24984:56;;;;-1:-1:-1;24818:5:1;23935:1135;-1:-1:-1;23935:1135:1:o;25328:216::-;25392:9;;;25420:11;;;25367:3;25450:9;;25478:10;;25474:19;;25503:10;;25495:19;;25471:44;25468:70;;;25518:18;;:::i;:::-;25468:70;;25328:216;;;;:::o;25549:168::-;25622:9;;;25653;;25670:15;;;25664:22;;25650:37;25640:71;;25691:18;;:::i;25722:274::-;25762:1;25788;25778:189;;25823:77;25820:1;25813:88;25924:4;25921:1;25914:15;25952:4;25949:1;25942:15;25778:189;-1:-1:-1;25981:9:1;;25722:274::o;26001:128::-;26068:9;;;26089:11;;;26086:37;;;26103:18;;:::i;26134:195::-;26173:3;26204:66;26197:5;26194:77;26191:103;;26274:18;;:::i;:::-;-1:-1:-1;26321:1:1;26310:13;;26134:195::o;26334:752::-;26641:3;26630:9;26623:22;26604:4;26662:45;26702:3;26691:9;26687:19;26679:6;26662:45;:::i;:::-;26755:10;26743:23;;;;26738:2;26723:18;;26716:51;-1:-1:-1;;;;;;26864:15:1;;;26859:2;26844:18;;26837:43;26916:15;;;;26911:2;26896:18;;26889:43;26963:3;26948:19;;26941:35;;;;27007:3;26992:19;;26985:35;27064:14;;27057:22;27051:3;27036:19;;;27029:51;26654:53;26334:752;-1:-1:-1;26334:752:1:o;27091:217::-;27238:2;27227:9;27220:21;27201:4;27258:44;27298:2;27287:9;27283:18;27275:6;27258:44;:::i;27716:331::-;27821:9;27832;27874:8;27862:10;27859:24;27856:44;;;27896:1;27893;27886:12;27856:44;27925:6;27915:8;27912:20;27909:40;;;27945:1;27942;27935:12;27909:40;-1:-1:-1;;27971:23:1;;;28016:25;;;;;-1:-1:-1;27716:331:1:o;28052:435::-;-1:-1:-1;;;;;28269:6:1;28265:55;28254:9;28247:74;28357:6;28352:2;28341:9;28337:18;28330:34;28400:2;28395;28384:9;28380:18;28373:30;28228:4;28420:61;28477:2;28466:9;28462:18;28454:6;28446;28420:61;:::i;28492:357::-;28610:12;;28657:4;28646:16;;;28640:23;;28610:12;28675:16;;28672:171;;;28765:66;28755:6;28749:4;28745:17;28742:1;28738:25;28734:98;28727:5;28723:110;28714:119;;28672:171;;28492:357;;;:::o;28854:184::-;28924:6;28977:2;28965:9;28956:7;28952:23;28948:32;28945:52;;;28993:1;28990;28983:12;28945:52;-1:-1:-1;29016:16:1;;28854:184;-1:-1:-1;28854:184:1:o;30041:1059::-;30412:3;30450:6;30444:13;30466:66;30525:6;30520:3;30513:4;30505:6;30501:17;30466:66;:::i;:::-;30563:6;30558:3;30554:16;30541:29;;30593:6;30586:5;30579:21;30634:6;30627:4;30620:5;30616:16;30609:32;30673:6;30668:2;30661:5;30657:14;30650:30;30712:6;30707:2;30700:5;30696:14;30689:30;30773:66;30764:6;30760:2;30756:15;30752:88;30746:3;30739:5;30735:15;30728:113;30874:6;30868:3;30861:5;30857:15;30850:31;30914:6;30908:3;30901:5;30897:15;30890:31;30952:6;30946:13;30968:80;31039:8;31033:3;31026:5;31022:15;31015:4;31007:6;31003:17;30968:80;:::i;:::-;31068:20;31090:3;31064:30;;30041:1059;-1:-1:-1;;;;;;;;;;;30041:1059:1:o;31407:245::-;31474:6;31527:2;31515:9;31506:7;31502:23;31498:32;31495:52;;;31543:1;31540;31533:12;31495:52;31575:9;31569:16;31594:28;31616:5;31594:28;:::i;31657:287::-;31786:3;31824:6;31818:13;31840:66;31899:6;31894:3;31887:4;31879:6;31875:17;31840:66;:::i;:::-;31922:16;;;;;31657:287;-1:-1:-1;;31657:287:1:o;31949:184::-;32001:77;31998:1;31991:88;32098:4;32095:1;32088:15;32122:4;32119:1;32112:15","abiDefinition":[{"inputs":[{"internalType":"address","name":"_owner","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AccessControlBadConfirmation","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"bytes32","name":"neededRole","type":"bytes32"}],"name":"AccessControlUnauthorizedAccount","type":"error"},{"inputs":[{"internalType":"address","name":"target","type":"address"}],"name":"AddressEmptyCode","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"AddressInsufficientBalance","type":"error"},{"inputs":[],"name":"AmountIncorrect","type":"error"},{"inputs":[],"name":"BridgeTransactionV2__InvalidEncodedTx","type":"error"},{"inputs":[{"internalType":"uint16","name":"version","type":"uint16"}],"name":"BridgeTransactionV2__UnsupportedVersion","type":"error"},{"inputs":[],"name":"CancelDelayBelowMin","type":"error"},{"inputs":[],"name":"ChainIncorrect","type":"error"},{"inputs":[],"name":"DeadlineExceeded","type":"error"},{"inputs":[],"name":"DeadlineNotExceeded","type":"error"},{"inputs":[],"name":"DeadlineTooShort","type":"error"},{"inputs":[],"name":"DisputePeriodNotPassed","type":"error"},{"inputs":[],"name":"DisputePeriodPassed","type":"error"},{"inputs":[],"name":"ExclusivityParamsIncorrect","type":"error"},{"inputs":[],"name":"ExclusivityPeriodNotPassed","type":"error"},{"inputs":[],"name":"FailedInnerCall","type":"error"},{"inputs":[],"name":"FeeRateAboveMax","type":"error"},{"inputs":[],"name":"MsgValueIncorrect","type":"error"},{"inputs":[],"name":"MulticallTarget__UndeterminedRevert","type":"error"},{"inputs":[],"name":"RecipientIncorrectReturnValue","type":"error"},{"inputs":[],"name":"RecipientNoReturnValue","type":"error"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"SafeERC20FailedOperation","type":"error"},{"inputs":[],"name":"SenderIncorrect","type":"error"},{"inputs":[],"name":"StatusIncorrect","type":"error"},{"inputs":[],"name":"TokenNotContract","type":"error"},{"inputs":[],"name":"TransactionRelayed","type":"error"},{"inputs":[],"name":"ZapDataLengthAboveMax","type":"error"},{"inputs":[],"name":"ZapNativeNotSupported","type":"error"},{"inputs":[],"name":"ZeroAddress","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"relayer","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"BridgeDepositClaimed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"BridgeDepositRefunded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"relayer","type":"address"}],"name":"BridgeProofDisputed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"relayer","type":"address"},{"indexed":false,"internalType":"bytes32","name":"transactionHash","type":"bytes32"}],"name":"BridgeProofProvided","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":false,"internalType":"bytes","name":"quoteId","type":"bytes"}],"name":"BridgeQuoteDetails","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"relayer","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint32","name":"originChainId","type":"uint32"},{"indexed":false,"internalType":"address","name":"originToken","type":"address"},{"indexed":false,"internalType":"address","name":"destToken","type":"address"},{"indexed":false,"internalType":"uint256","name":"originAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"destAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"chainGasAmount","type":"uint256"}],"name":"BridgeRelayed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"bytes","name":"request","type":"bytes"},{"indexed":false,"internalType":"uint32","name":"destChainId","type":"uint32"},{"indexed":false,"internalType":"address","name":"originToken","type":"address"},{"indexed":false,"internalType":"address","name":"destToken","type":"address"},{"indexed":false,"internalType":"uint256","name":"originAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"destAmount","type":"uint256"},{"indexed":false,"internalType":"bool","name":"sendChainGas","type":"bool"}],"name":"BridgeRequested","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldCancelDelay","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newCancelDelay","type":"uint256"}],"name":"CancelDelayUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldFeeRate","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newFeeRate","type":"uint256"}],"name":"FeeRateUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"address","name":"recipient","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"FeesSwept","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"previousAdminRole","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"newAdminRole","type":"bytes32"}],"name":"RoleAdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleRevoked","type":"event"},{"inputs":[],"name":"CANCELER_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"DEFAULT_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"DEFAULT_CANCEL_DELAY","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"DISPUTE_PERIOD","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"FEE_BPS","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"FEE_RATE_MAX","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"GOVERNOR_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"GUARD_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_ZAP_DATA_LENGTH","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MIN_CANCEL_DELAY","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MIN_DEADLINE_PERIOD","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"NATIVE_GAS_TOKEN","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"PROVER_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"QUOTER_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"uint32","name":"dstChainId","type":"uint32"},{"internalType":"address","name":"sender","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"address","name":"originToken","type":"address"},{"internalType":"address","name":"destToken","type":"address"},{"internalType":"uint256","name":"originAmount","type":"uint256"},{"internalType":"uint256","name":"destAmount","type":"uint256"},{"internalType":"bool","name":"sendChainGas","type":"bool"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"internalType":"struct IFastBridge.BridgeParams","name":"params","type":"tuple"}],"name":"bridge","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"uint32","name":"dstChainId","type":"uint32"},{"internalType":"address","name":"sender","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"address","name":"originToken","type":"address"},{"internalType":"address","name":"destToken","type":"address"},{"internalType":"uint256","name":"originAmount","type":"uint256"},{"internalType":"uint256","name":"destAmount","type":"uint256"},{"internalType":"bool","name":"sendChainGas","type":"bool"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"internalType":"struct IFastBridge.BridgeParams","name":"params","type":"tuple"},{"components":[{"internalType":"address","name":"quoteRelayer","type":"address"},{"internalType":"int256","name":"quoteExclusivitySeconds","type":"int256"},{"internalType":"bytes","name":"quoteId","type":"bytes"},{"internalType":"uint256","name":"zapNative","type":"uint256"},{"internalType":"bytes","name":"zapData","type":"bytes"}],"internalType":"struct IFastBridgeV2.BridgeParamsV2","name":"paramsV2","type":"tuple"}],"name":"bridge","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"transactionId","type":"bytes32"}],"name":"bridgeProofs","outputs":[{"internalType":"uint96","name":"timestamp","type":"uint96"},{"internalType":"address","name":"relayer","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"bridgeRelayDetails","outputs":[{"internalType":"uint48","name":"blockNumber","type":"uint48"},{"internalType":"uint48","name":"blockTimestamp","type":"uint48"},{"internalType":"address","name":"relayer","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"transactionId","type":"bytes32"}],"name":"bridgeRelays","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"transactionId","type":"bytes32"}],"name":"bridgeStatuses","outputs":[{"internalType":"enum IFastBridgeV2.BridgeStatus","name":"status","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"bridgeTxDetails","outputs":[{"internalType":"enum IFastBridgeV2.BridgeStatus","name":"status","type":"uint8"},{"internalType":"uint32","name":"destChainId","type":"uint32"},{"internalType":"uint56","name":"proofBlockTimestamp","type":"uint56"},{"internalType":"address","name":"proofRelayer","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"internalType":"address","name":"relayer","type":"address"}],"name":"canClaim","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"}],"name":"cancel","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"cancelDelay","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"chainGasAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"},{"internalType":"address","name":"to","type":"address"}],"name":"claim","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"}],"name":"claim","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"deployBlock","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"transactionId","type":"bytes32"}],"name":"dispute","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"}],"name":"getBridgeTransaction","outputs":[{"components":[{"internalType":"uint32","name":"originChainId","type":"uint32"},{"internalType":"uint32","name":"destChainId","type":"uint32"},{"internalType":"address","name":"originSender","type":"address"},{"internalType":"address","name":"destRecipient","type":"address"},{"internalType":"address","name":"originToken","type":"address"},{"internalType":"address","name":"destToken","type":"address"},{"internalType":"uint256","name":"originAmount","type":"uint256"},{"internalType":"uint256","name":"destAmount","type":"uint256"},{"internalType":"uint256","name":"originFeeAmount","type":"uint256"},{"internalType":"bool","name":"sendChainGas","type":"bool"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint256","name":"nonce","type":"uint256"}],"internalType":"struct IFastBridge.BridgeTransaction","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"}],"name":"getBridgeTransactionV2","outputs":[{"components":[{"internalType":"uint32","name":"originChainId","type":"uint32"},{"internalType":"uint32","name":"destChainId","type":"uint32"},{"internalType":"address","name":"originSender","type":"address"},{"internalType":"address","name":"destRecipient","type":"address"},{"internalType":"address","name":"originToken","type":"address"},{"internalType":"address","name":"destToken","type":"address"},{"internalType":"uint256","name":"originAmount","type":"uint256"},{"internalType":"uint256","name":"destAmount","type":"uint256"},{"internalType":"uint256","name":"originFeeAmount","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"address","name":"exclusivityRelayer","type":"address"},{"internalType":"uint256","name":"exclusivityEndTime","type":"uint256"},{"internalType":"uint256","name":"zapNative","type":"uint256"},{"internalType":"bytes","name":"zapData","type":"bytes"}],"internalType":"struct IFastBridgeV2.BridgeTransactionV2","name":"","type":"tuple"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleAdmin","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"uint256","name":"index","type":"uint256"}],"name":"getRoleMember","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleMemberCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"grantRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"hasRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes[]","name":"data","type":"bytes[]"},{"internalType":"bool","name":"ignoreReverts","type":"bool"}],"name":"multicallNoResults","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes[]","name":"data","type":"bytes[]"},{"internalType":"bool","name":"ignoreReverts","type":"bool"}],"name":"multicallWithResults","outputs":[{"components":[{"internalType":"bool","name":"success","type":"bool"},{"internalType":"bytes","name":"returnData","type":"bytes"}],"internalType":"struct IMulticallTarget.Result[]","name":"results","type":"tuple[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"nonce","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"protocolFeeRate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"protocolFees","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"internalType":"bytes32","name":"destTxHash","type":"bytes32"},{"internalType":"address","name":"relayer","type":"address"}],"name":"prove","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"},{"internalType":"bytes32","name":"destTxHash","type":"bytes32"}],"name":"prove","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"}],"name":"refund","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"}],"name":"relay","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"},{"internalType":"address","name":"relayer","type":"address"}],"name":"relay","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"callerConfirmation","type":"address"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"revokeRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"senderNonces","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"newCancelDelay","type":"uint256"}],"name":"setCancelDelay","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"newFeeRate","type":"uint256"}],"name":"setProtocolFeeRate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"address","name":"recipient","type":"address"}],"name":"sweepProtocolFees","outputs":[],"stateMutability":"nonpayable","type":"function"}],"userDoc":{"kind":"user","methods":{"CANCELER_ROLE()":{"notice":"Role identifier for Canceler's on-chain authentication in FastBridge."},"DEFAULT_CANCEL_DELAY()":{"notice":"Default cancel delay set during the contract deployment."},"DISPUTE_PERIOD()":{"notice":"Dispute period for relayed transactions"},"FEE_BPS()":{"notice":"Denominator for fee rates, represents 100%."},"FEE_RATE_MAX()":{"notice":"Maximum protocol fee rate: 1% on origin amount."},"GOVERNOR_ROLE()":{"notice":"Role identifier for Governor's on-chain administrative authority."},"GUARD_ROLE()":{"notice":"Role identifier for Guard's on-chain authentication in FastBridge."},"MAX_ZAP_DATA_LENGTH()":{"notice":"Maximum length of accepted zapData"},"MIN_CANCEL_DELAY()":{"notice":"Minimum cancel delay that can be set by the governor."},"MIN_DEADLINE_PERIOD()":{"notice":"Minimum deadline period to relay a requested bridge transaction"},"NATIVE_GAS_TOKEN()":{"notice":"Address reserved for native gas token (ETH on Ethereum and most L2s, AVAX on Avalanche, etc)"},"PROVER_ROLE()":{"notice":"Role identifier for Prover's on-chain authentication in FastBridge."},"QUOTER_ROLE()":{"notice":"Role identifier for Quoter API's off-chain authentication."},"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256))":{"notice":"Initiates bridge on origin chain to be relayed by off-chain relayer"},"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256),(address,int256,bytes,uint256,bytes))":{"notice":"Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability to provide temporary exclusivity fill rights for the quote relayer."},"bridgeProofs(bytes32)":{"notice":"Returns the timestamp and relayer of a bridge proof"},"bridgeRelayDetails(bytes32)":{"notice":"Relay details on destination chain"},"bridgeRelays(bytes32)":{"notice":"Checks if a transaction has been relayed"},"bridgeStatuses(bytes32)":{"notice":"Returns the status of a bridge transaction"},"bridgeTxDetails(bytes32)":{"notice":"Status of the bridge tx on origin chain"},"canClaim(bytes32,address)":{"notice":"Checks if the dispute period has passed so bridge deposit can be claimed"},"cancel(bytes)":{"notice":"Cancels an outstanding bridge transaction in case optimistic bridging failed and returns the full amount to the original sender."},"cancelDelay()":{"notice":"Delay for a transaction after which it could be permisionlessly cancelled"},"chainGasAmount()":{"notice":"This is deprecated and should not be used."},"claim(bytes)":{"notice":"Completes bridge transaction on origin chain by claiming originally deposited capital.Can only send funds to the relayer address on the proof."},"claim(bytes,address)":{"notice":"Completes bridge transaction on origin chain by claiming originally deposited capital"},"deployBlock()":{"notice":"the block the contract was deployed at"},"dispute(bytes32)":{"notice":"Disputes an outstanding proof in case relayer provided dest chain tx is invalid"},"getBridgeTransaction(bytes)":{"notice":"Decodes bridge request into a bridge transaction"},"getBridgeTransactionV2(bytes)":{"notice":"Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2"},"multicallNoResults(bytes[],bool)":{"notice":"Perform a batched call to this contract, preserving the msg.sender. The return data from each call is discarded."},"multicallWithResults(bytes[],bool)":{"notice":"Perform a batched call to this contract, preserving the msg.sender. The return data from each call is preserved."},"nonce()":{"notice":"This is deprecated and should not be used."},"protocolFeeRate()":{"notice":"Protocol fee rate taken on origin amount deposited in origin chain"},"protocolFees(address)":{"notice":"Protocol fee amounts accumulated"},"prove(bytes,bytes32)":{"notice":"Provides proof on origin side that relayer provided funds on destination side of bridge transaction"},"prove(bytes32,bytes32,address)":{"notice":"Provides proof on origin side that relayer provided funds on destination side of bridge transaction"},"refund(bytes)":{"notice":"Note: this function is deprecated and will be removed in a future version."},"relay(bytes)":{"notice":"Relays destination side of bridge transaction by off-chain relayer"},"relay(bytes,address)":{"notice":"Relays destination side of bridge transaction by off-chain relayer"},"senderNonces(address)":{"notice":"Unique bridge nonces tracked per originSender"},"setCancelDelay(uint256)":{"notice":"Allows the contract governor to set the cancel delay. The cancel delay is the time after the transaction deadline after which it can be permissionlessly cancelled, if it hasn't been proven by any of the Relayers."},"setProtocolFeeRate(uint256)":{"notice":"Allows the contract governor to set the protocol fee rate. The protocol fee is taken from the origin amount only for completed and claimed transactions."},"sweepProtocolFees(address,address)":{"notice":"Allows the contract governor to sweep the accumulated protocol fees in the contract."}},"notice":"FastBridgeV2 is a contract for bridging tokens across chains.","version":1},"developerDoc":{"errors":{"AccessControlBadConfirmation()":[{"details":"The caller of a function is not the expected one. NOTE: Don't confuse with {AccessControlUnauthorizedAccount}."}],"AccessControlUnauthorizedAccount(address,bytes32)":[{"details":"The `account` is missing a role."}],"AddressEmptyCode(address)":[{"details":"There's no code at `target` (it is not a contract)."}],"AddressInsufficientBalance(address)":[{"details":"The ETH balance of the account is not enough to perform the operation."}],"FailedInnerCall()":[{"details":"A call to an address target failed. The target may have reverted."}],"SafeERC20FailedOperation(address)":[{"details":"An operation with an ERC20 token failed."}]},"events":{"RoleAdminChanged(bytes32,bytes32,bytes32)":{"details":"Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole` `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite {RoleAdminChanged} not being emitted signaling this."},"RoleGranted(bytes32,address,address)":{"details":"Emitted when `account` is granted `role`. `sender` is the account that originated the contract call, an admin role bearer except when using {AccessControl-_setupRole}."},"RoleRevoked(bytes32,address,address)":{"details":"Emitted when `account` is revoked `role`. `sender` is the account that originated the contract call: - if using `revokeRole`, it is the admin role bearer - if using `renounceRole`, it is the role bearer (i.e. `account`)"}},"kind":"dev","methods":{"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256))":{"params":{"params":"The parameters required to bridge"}},"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256),(address,int256,bytes,uint256,bytes))":{"params":{"params":"The parameters required to bridge","paramsV2":"The parameters for exclusivity fill rights (optional, can be left empty)"}},"bridgeProofs(bytes32)":{"params":{"transactionId":"The ID of the bridge transaction"},"returns":{"relayer":"The relayer address of the bridge proof","timestamp":"The timestamp of the bridge proof"}},"bridgeRelays(bytes32)":{"params":{"transactionId":"The ID of the transaction to check"},"returns":{"_0":"True if the transaction has been relayed, false otherwise"}},"bridgeStatuses(bytes32)":{"params":{"transactionId":"The ID of the bridge transaction"},"returns":{"status":"BridgeStatus Status of the bridge transaction"}},"canClaim(bytes32,address)":{"params":{"relayer":"The address of the relayer attempting to claim","transactionId":"The transaction id associated with the encoded bridge transaction to check"}},"cancel(bytes)":{"params":{"request":"The encoded bridge transaction to refund"}},"claim(bytes)":{"params":{"request":"The encoded bridge transaction to claim on origin chain"}},"claim(bytes,address)":{"params":{"request":"The encoded bridge transaction to claim on origin chain","to":"The recipient address of the funds"}},"dispute(bytes32)":{"params":{"transactionId":"The transaction id associated with the encoded bridge transaction to dispute"}},"getBridgeTransaction(bytes)":{"details":"This method is added to achieve backwards compatibility with decoding requests into V1 structs: - `zapNative` is partially reported as a zero/non-zero flag - `zapData` is ignored In order to process all kinds of requests use getBridgeTransactionV2 instead.","params":{"request":"The bridge request to decode"}},"getBridgeTransactionV2(bytes)":{"params":{"request":"The bridge request to decode"}},"getRoleAdmin(bytes32)":{"details":"Returns the admin role that controls `role`. See {grantRole} and {revokeRole}. To change a role's admin, use {_setRoleAdmin}."},"getRoleMember(bytes32,uint256)":{"details":"Returns one of the accounts that have `role`. `index` must be a value between 0 and {getRoleMemberCount}, non-inclusive. Role bearers are not sorted in any particular way, and their ordering may change at any point. WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure you perform all queries on the same block. See the following https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post] for more information."},"getRoleMemberCount(bytes32)":{"details":"Returns the number of accounts that have `role`. Can be used together with {getRoleMember} to enumerate all bearers of a role."},"grantRole(bytes32,address)":{"details":"Grants `role` to `account`. If `account` had not been already granted `role`, emits a {RoleGranted} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleGranted} event."},"hasRole(bytes32,address)":{"details":"Returns `true` if `account` has been granted `role`."},"multicallNoResults(bytes[],bool)":{"details":"The method is non-payable, so only calls with `msg.value == 0` could be batched. It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag. Otherwise, the whole batch call will be reverted with the original revert reason.","params":{"data":"List of abi-encoded calldata for the calls to perform.","ignoreReverts":"Whether to ignore the revert errors from the calls."}},"multicallWithResults(bytes[],bool)":{"details":"The method is non-payable, so only calls with `msg.value == 0` could be batched. It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag. Otherwise, the whole batch call will be reverted with the original revert reason.","params":{"data":"List of abi-encoded calldata for the calls to perform.","ignoreReverts":"Whether to ignore the revert errors from the calls."},"returns":{"results":" List of results from the calls: `(success, returnData)`."}},"prove(bytes,bytes32)":{"params":{"destTxHash":"The destination tx hash proving bridge transaction was relayed","request":"The encoded bridge transaction to prove on origin chain"}},"prove(bytes32,bytes32,address)":{"params":{"destTxHash":"The destination tx hash proving bridge transaction was relayed","relayer":"The address of the relaying entity which should have control of the origin funds when claimed","transactionId":"The transaction id associated with the encoded bridge transaction to prove"}},"refund(bytes)":{"params":{"request":"The encoded bridge transaction to refund"}},"relay(bytes)":{"params":{"request":"The encoded bridge transaction to relay on destination chain"}},"relay(bytes,address)":{"params":{"relayer":"The address of the relaying entity which should have control of the origin funds when claimed","request":"The encoded bridge transaction to relay on destination chain"}},"renounceRole(bytes32,address)":{"details":"Revokes `role` from the calling account. Roles are often managed via {grantRole} and {revokeRole}: this function's purpose is to provide a mechanism for accounts to lose their privileges if they are compromised (such as when a trusted device is misplaced). If the calling account had been revoked `role`, emits a {RoleRevoked} event. Requirements: - the caller must be `callerConfirmation`. May emit a {RoleRevoked} event."},"revokeRole(bytes32,address)":{"details":"Revokes `role` from `account`. If `account` had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleRevoked} event."},"setProtocolFeeRate(uint256)":{"details":"The protocol fee is abstracted away from the relayers, they always operate using the amounts after fees: what they see as the origin amount emitted in the log is what they get credited with."},"supportsInterface(bytes4)":{"details":"See {IERC165-supportsInterface}."}},"stateVariables":{"nonce":{"details":"Replaced by senderNonces"}},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_owner\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"AccessControlBadConfirmation\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"neededRole\",\"type\":\"bytes32\"}],\"name\":\"AccessControlUnauthorizedAccount\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"}],\"name\":\"AddressEmptyCode\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"AddressInsufficientBalance\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"AmountIncorrect\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"BridgeTransactionV2__InvalidEncodedTx\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint16\",\"name\":\"version\",\"type\":\"uint16\"}],\"name\":\"BridgeTransactionV2__UnsupportedVersion\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"CancelDelayBelowMin\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ChainIncorrect\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DeadlineExceeded\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DeadlineNotExceeded\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DeadlineTooShort\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DisputePeriodNotPassed\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DisputePeriodPassed\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ExclusivityParamsIncorrect\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ExclusivityPeriodNotPassed\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"FailedInnerCall\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"FeeRateAboveMax\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"MsgValueIncorrect\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"MulticallTarget__UndeterminedRevert\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"RecipientIncorrectReturnValue\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"RecipientNoReturnValue\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"}],\"name\":\"SafeERC20FailedOperation\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"SenderIncorrect\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"StatusIncorrect\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"TokenNotContract\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"TransactionRelayed\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ZapDataLengthAboveMax\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ZapNativeNotSupported\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ZeroAddress\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"BridgeDepositClaimed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"BridgeDepositRefunded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"name\":\"BridgeProofDisputed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"transactionHash\",\"type\":\"bytes32\"}],\"name\":\"BridgeProofProvided\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"quoteId\",\"type\":\"bytes\"}],\"name\":\"BridgeQuoteDetails\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"originChainId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"chainGasAmount\",\"type\":\"uint256\"}],\"name\":\"BridgeRelayed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"destChainId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"sendChainGas\",\"type\":\"bool\"}],\"name\":\"BridgeRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"oldCancelDelay\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newCancelDelay\",\"type\":\"uint256\"}],\"name\":\"CancelDelayUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"oldFeeRate\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newFeeRate\",\"type\":\"uint256\"}],\"name\":\"FeeRateUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"FeesSwept\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"previousAdminRole\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"newAdminRole\",\"type\":\"bytes32\"}],\"name\":\"RoleAdminChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleGranted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleRevoked\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"CANCELER_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"DEFAULT_ADMIN_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"DEFAULT_CANCEL_DELAY\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"DISPUTE_PERIOD\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"FEE_BPS\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"FEE_RATE_MAX\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"GOVERNOR_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"GUARD_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"MAX_ZAP_DATA_LENGTH\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"MIN_CANCEL_DELAY\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"MIN_DEADLINE_PERIOD\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"NATIVE_GAS_TOKEN\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"PROVER_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"QUOTER_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"dstChainId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"sendChainGas\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"}],\"internalType\":\"struct IFastBridge.BridgeParams\",\"name\":\"params\",\"type\":\"tuple\"}],\"name\":\"bridge\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"dstChainId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"sendChainGas\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"}],\"internalType\":\"struct IFastBridge.BridgeParams\",\"name\":\"params\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"quoteRelayer\",\"type\":\"address\"},{\"internalType\":\"int256\",\"name\":\"quoteExclusivitySeconds\",\"type\":\"int256\"},{\"internalType\":\"bytes\",\"name\":\"quoteId\",\"type\":\"bytes\"},{\"internalType\":\"uint256\",\"name\":\"zapNative\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"zapData\",\"type\":\"bytes\"}],\"internalType\":\"struct IFastBridgeV2.BridgeParamsV2\",\"name\":\"paramsV2\",\"type\":\"tuple\"}],\"name\":\"bridge\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"}],\"name\":\"bridgeProofs\",\"outputs\":[{\"internalType\":\"uint96\",\"name\":\"timestamp\",\"type\":\"uint96\"},{\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"bridgeRelayDetails\",\"outputs\":[{\"internalType\":\"uint48\",\"name\":\"blockNumber\",\"type\":\"uint48\"},{\"internalType\":\"uint48\",\"name\":\"blockTimestamp\",\"type\":\"uint48\"},{\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"}],\"name\":\"bridgeRelays\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"}],\"name\":\"bridgeStatuses\",\"outputs\":[{\"internalType\":\"enum IFastBridgeV2.BridgeStatus\",\"name\":\"status\",\"type\":\"uint8\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"bridgeTxDetails\",\"outputs\":[{\"internalType\":\"enum IFastBridgeV2.BridgeStatus\",\"name\":\"status\",\"type\":\"uint8\"},{\"internalType\":\"uint32\",\"name\":\"destChainId\",\"type\":\"uint32\"},{\"internalType\":\"uint56\",\"name\":\"proofBlockTimestamp\",\"type\":\"uint56\"},{\"internalType\":\"address\",\"name\":\"proofRelayer\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"name\":\"canClaim\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"cancel\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"cancelDelay\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"chainGasAmount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"claim\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"claim\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"deployBlock\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"}],\"name\":\"dispute\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"getBridgeTransaction\",\"outputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"originChainId\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"destChainId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"originSender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destRecipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"originFeeAmount\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"sendChainGas\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"}],\"internalType\":\"struct IFastBridge.BridgeTransaction\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"getBridgeTransactionV2\",\"outputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"originChainId\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"destChainId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"originSender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destRecipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"originFeeAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"exclusivityRelayer\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"exclusivityEndTime\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"zapNative\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"zapData\",\"type\":\"bytes\"}],\"internalType\":\"struct IFastBridgeV2.BridgeTransactionV2\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"}],\"name\":\"getRoleAdmin\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"index\",\"type\":\"uint256\"}],\"name\":\"getRoleMember\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"}],\"name\":\"getRoleMemberCount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"grantRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"hasRole\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes[]\",\"name\":\"data\",\"type\":\"bytes[]\"},{\"internalType\":\"bool\",\"name\":\"ignoreReverts\",\"type\":\"bool\"}],\"name\":\"multicallNoResults\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes[]\",\"name\":\"data\",\"type\":\"bytes[]\"},{\"internalType\":\"bool\",\"name\":\"ignoreReverts\",\"type\":\"bool\"}],\"name\":\"multicallWithResults\",\"outputs\":[{\"components\":[{\"internalType\":\"bool\",\"name\":\"success\",\"type\":\"bool\"},{\"internalType\":\"bytes\",\"name\":\"returnData\",\"type\":\"bytes\"}],\"internalType\":\"struct IMulticallTarget.Result[]\",\"name\":\"results\",\"type\":\"tuple[]\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"nonce\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"protocolFeeRate\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"protocolFees\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"destTxHash\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"name\":\"prove\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"},{\"internalType\":\"bytes32\",\"name\":\"destTxHash\",\"type\":\"bytes32\"}],\"name\":\"prove\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"refund\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"relay\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"},{\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"name\":\"relay\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"callerConfirmation\",\"type\":\"address\"}],\"name\":\"renounceRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"revokeRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"senderNonces\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"newCancelDelay\",\"type\":\"uint256\"}],\"name\":\"setCancelDelay\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"newFeeRate\",\"type\":\"uint256\"}],\"name\":\"setProtocolFeeRate\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes4\",\"name\":\"interfaceId\",\"type\":\"bytes4\"}],\"name\":\"supportsInterface\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"}],\"name\":\"sweepProtocolFees\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"errors\":{\"AccessControlBadConfirmation()\":[{\"details\":\"The caller of a function is not the expected one. NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\"}],\"AccessControlUnauthorizedAccount(address,bytes32)\":[{\"details\":\"The `account` is missing a role.\"}],\"AddressEmptyCode(address)\":[{\"details\":\"There's no code at `target` (it is not a contract).\"}],\"AddressInsufficientBalance(address)\":[{\"details\":\"The ETH balance of the account is not enough to perform the operation.\"}],\"FailedInnerCall()\":[{\"details\":\"A call to an address target failed. The target may have reverted.\"}],\"SafeERC20FailedOperation(address)\":[{\"details\":\"An operation with an ERC20 token failed.\"}]},\"events\":{\"RoleAdminChanged(bytes32,bytes32,bytes32)\":{\"details\":\"Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole` `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite {RoleAdminChanged} not being emitted signaling this.\"},\"RoleGranted(bytes32,address,address)\":{\"details\":\"Emitted when `account` is granted `role`. `sender` is the account that originated the contract call, an admin role bearer except when using {AccessControl-_setupRole}.\"},\"RoleRevoked(bytes32,address,address)\":{\"details\":\"Emitted when `account` is revoked `role`. `sender` is the account that originated the contract call: - if using `revokeRole`, it is the admin role bearer - if using `renounceRole`, it is the role bearer (i.e. `account`)\"}},\"kind\":\"dev\",\"methods\":{\"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256))\":{\"params\":{\"params\":\"The parameters required to bridge\"}},\"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256),(address,int256,bytes,uint256,bytes))\":{\"params\":{\"params\":\"The parameters required to bridge\",\"paramsV2\":\"The parameters for exclusivity fill rights (optional, can be left empty)\"}},\"bridgeProofs(bytes32)\":{\"params\":{\"transactionId\":\"The ID of the bridge transaction\"},\"returns\":{\"relayer\":\"The relayer address of the bridge proof\",\"timestamp\":\"The timestamp of the bridge proof\"}},\"bridgeRelays(bytes32)\":{\"params\":{\"transactionId\":\"The ID of the transaction to check\"},\"returns\":{\"_0\":\"True if the transaction has been relayed, false otherwise\"}},\"bridgeStatuses(bytes32)\":{\"params\":{\"transactionId\":\"The ID of the bridge transaction\"},\"returns\":{\"status\":\"BridgeStatus Status of the bridge transaction\"}},\"canClaim(bytes32,address)\":{\"params\":{\"relayer\":\"The address of the relayer attempting to claim\",\"transactionId\":\"The transaction id associated with the encoded bridge transaction to check\"}},\"cancel(bytes)\":{\"params\":{\"request\":\"The encoded bridge transaction to refund\"}},\"claim(bytes)\":{\"params\":{\"request\":\"The encoded bridge transaction to claim on origin chain\"}},\"claim(bytes,address)\":{\"params\":{\"request\":\"The encoded bridge transaction to claim on origin chain\",\"to\":\"The recipient address of the funds\"}},\"dispute(bytes32)\":{\"params\":{\"transactionId\":\"The transaction id associated with the encoded bridge transaction to dispute\"}},\"getBridgeTransaction(bytes)\":{\"details\":\"This method is added to achieve backwards compatibility with decoding requests into V1 structs: - `zapNative` is partially reported as a zero/non-zero flag - `zapData` is ignored In order to process all kinds of requests use getBridgeTransactionV2 instead.\",\"params\":{\"request\":\"The bridge request to decode\"}},\"getBridgeTransactionV2(bytes)\":{\"params\":{\"request\":\"The bridge request to decode\"}},\"getRoleAdmin(bytes32)\":{\"details\":\"Returns the admin role that controls `role`. See {grantRole} and {revokeRole}. To change a role's admin, use {_setRoleAdmin}.\"},\"getRoleMember(bytes32,uint256)\":{\"details\":\"Returns one of the accounts that have `role`. `index` must be a value between 0 and {getRoleMemberCount}, non-inclusive. Role bearers are not sorted in any particular way, and their ordering may change at any point. WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure you perform all queries on the same block. See the following https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post] for more information.\"},\"getRoleMemberCount(bytes32)\":{\"details\":\"Returns the number of accounts that have `role`. Can be used together with {getRoleMember} to enumerate all bearers of a role.\"},\"grantRole(bytes32,address)\":{\"details\":\"Grants `role` to `account`. If `account` had not been already granted `role`, emits a {RoleGranted} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleGranted} event.\"},\"hasRole(bytes32,address)\":{\"details\":\"Returns `true` if `account` has been granted `role`.\"},\"multicallNoResults(bytes[],bool)\":{\"details\":\"The method is non-payable, so only calls with `msg.value == 0` could be batched. It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag. Otherwise, the whole batch call will be reverted with the original revert reason.\",\"params\":{\"data\":\"List of abi-encoded calldata for the calls to perform.\",\"ignoreReverts\":\"Whether to ignore the revert errors from the calls.\"}},\"multicallWithResults(bytes[],bool)\":{\"details\":\"The method is non-payable, so only calls with `msg.value == 0` could be batched. It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag. Otherwise, the whole batch call will be reverted with the original revert reason.\",\"params\":{\"data\":\"List of abi-encoded calldata for the calls to perform.\",\"ignoreReverts\":\"Whether to ignore the revert errors from the calls.\"},\"returns\":{\"results\":\" List of results from the calls: `(success, returnData)`.\"}},\"prove(bytes,bytes32)\":{\"params\":{\"destTxHash\":\"The destination tx hash proving bridge transaction was relayed\",\"request\":\"The encoded bridge transaction to prove on origin chain\"}},\"prove(bytes32,bytes32,address)\":{\"params\":{\"destTxHash\":\"The destination tx hash proving bridge transaction was relayed\",\"relayer\":\"The address of the relaying entity which should have control of the origin funds when claimed\",\"transactionId\":\"The transaction id associated with the encoded bridge transaction to prove\"}},\"refund(bytes)\":{\"params\":{\"request\":\"The encoded bridge transaction to refund\"}},\"relay(bytes)\":{\"params\":{\"request\":\"The encoded bridge transaction to relay on destination chain\"}},\"relay(bytes,address)\":{\"params\":{\"relayer\":\"The address of the relaying entity which should have control of the origin funds when claimed\",\"request\":\"The encoded bridge transaction to relay on destination chain\"}},\"renounceRole(bytes32,address)\":{\"details\":\"Revokes `role` from the calling account. Roles are often managed via {grantRole} and {revokeRole}: this function's purpose is to provide a mechanism for accounts to lose their privileges if they are compromised (such as when a trusted device is misplaced). If the calling account had been revoked `role`, emits a {RoleRevoked} event. Requirements: - the caller must be `callerConfirmation`. May emit a {RoleRevoked} event.\"},\"revokeRole(bytes32,address)\":{\"details\":\"Revokes `role` from `account`. If `account` had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleRevoked} event.\"},\"setProtocolFeeRate(uint256)\":{\"details\":\"The protocol fee is abstracted away from the relayers, they always operate using the amounts after fees: what they see as the origin amount emitted in the log is what they get credited with.\"},\"supportsInterface(bytes4)\":{\"details\":\"See {IERC165-supportsInterface}.\"}},\"stateVariables\":{\"nonce\":{\"details\":\"Replaced by senderNonces\"}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"CANCELER_ROLE()\":{\"notice\":\"Role identifier for Canceler's on-chain authentication in FastBridge.\"},\"DEFAULT_CANCEL_DELAY()\":{\"notice\":\"Default cancel delay set during the contract deployment.\"},\"DISPUTE_PERIOD()\":{\"notice\":\"Dispute period for relayed transactions\"},\"FEE_BPS()\":{\"notice\":\"Denominator for fee rates, represents 100%.\"},\"FEE_RATE_MAX()\":{\"notice\":\"Maximum protocol fee rate: 1% on origin amount.\"},\"GOVERNOR_ROLE()\":{\"notice\":\"Role identifier for Governor's on-chain administrative authority.\"},\"GUARD_ROLE()\":{\"notice\":\"Role identifier for Guard's on-chain authentication in FastBridge.\"},\"MAX_ZAP_DATA_LENGTH()\":{\"notice\":\"Maximum length of accepted zapData\"},\"MIN_CANCEL_DELAY()\":{\"notice\":\"Minimum cancel delay that can be set by the governor.\"},\"MIN_DEADLINE_PERIOD()\":{\"notice\":\"Minimum deadline period to relay a requested bridge transaction\"},\"NATIVE_GAS_TOKEN()\":{\"notice\":\"Address reserved for native gas token (ETH on Ethereum and most L2s, AVAX on Avalanche, etc)\"},\"PROVER_ROLE()\":{\"notice\":\"Role identifier for Prover's on-chain authentication in FastBridge.\"},\"QUOTER_ROLE()\":{\"notice\":\"Role identifier for Quoter API's off-chain authentication.\"},\"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256))\":{\"notice\":\"Initiates bridge on origin chain to be relayed by off-chain relayer\"},\"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256),(address,int256,bytes,uint256,bytes))\":{\"notice\":\"Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability to provide temporary exclusivity fill rights for the quote relayer.\"},\"bridgeProofs(bytes32)\":{\"notice\":\"Returns the timestamp and relayer of a bridge proof\"},\"bridgeRelayDetails(bytes32)\":{\"notice\":\"Relay details on destination chain\"},\"bridgeRelays(bytes32)\":{\"notice\":\"Checks if a transaction has been relayed\"},\"bridgeStatuses(bytes32)\":{\"notice\":\"Returns the status of a bridge transaction\"},\"bridgeTxDetails(bytes32)\":{\"notice\":\"Status of the bridge tx on origin chain\"},\"canClaim(bytes32,address)\":{\"notice\":\"Checks if the dispute period has passed so bridge deposit can be claimed\"},\"cancel(bytes)\":{\"notice\":\"Cancels an outstanding bridge transaction in case optimistic bridging failed and returns the full amount to the original sender.\"},\"cancelDelay()\":{\"notice\":\"Delay for a transaction after which it could be permisionlessly cancelled\"},\"chainGasAmount()\":{\"notice\":\"This is deprecated and should not be used.\"},\"claim(bytes)\":{\"notice\":\"Completes bridge transaction on origin chain by claiming originally deposited capital.Can only send funds to the relayer address on the proof.\"},\"claim(bytes,address)\":{\"notice\":\"Completes bridge transaction on origin chain by claiming originally deposited capital\"},\"deployBlock()\":{\"notice\":\"the block the contract was deployed at\"},\"dispute(bytes32)\":{\"notice\":\"Disputes an outstanding proof in case relayer provided dest chain tx is invalid\"},\"getBridgeTransaction(bytes)\":{\"notice\":\"Decodes bridge request into a bridge transaction\"},\"getBridgeTransactionV2(bytes)\":{\"notice\":\"Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\"},\"multicallNoResults(bytes[],bool)\":{\"notice\":\"Perform a batched call to this contract, preserving the msg.sender. The return data from each call is discarded.\"},\"multicallWithResults(bytes[],bool)\":{\"notice\":\"Perform a batched call to this contract, preserving the msg.sender. The return data from each call is preserved.\"},\"nonce()\":{\"notice\":\"This is deprecated and should not be used.\"},\"protocolFeeRate()\":{\"notice\":\"Protocol fee rate taken on origin amount deposited in origin chain\"},\"protocolFees(address)\":{\"notice\":\"Protocol fee amounts accumulated\"},\"prove(bytes,bytes32)\":{\"notice\":\"Provides proof on origin side that relayer provided funds on destination side of bridge transaction\"},\"prove(bytes32,bytes32,address)\":{\"notice\":\"Provides proof on origin side that relayer provided funds on destination side of bridge transaction\"},\"refund(bytes)\":{\"notice\":\"Note: this function is deprecated and will be removed in a future version.\"},\"relay(bytes)\":{\"notice\":\"Relays destination side of bridge transaction by off-chain relayer\"},\"relay(bytes,address)\":{\"notice\":\"Relays destination side of bridge transaction by off-chain relayer\"},\"senderNonces(address)\":{\"notice\":\"Unique bridge nonces tracked per originSender\"},\"setCancelDelay(uint256)\":{\"notice\":\"Allows the contract governor to set the cancel delay. The cancel delay is the time after the transaction deadline after which it can be permissionlessly cancelled, if it hasn't been proven by any of the Relayers.\"},\"setProtocolFeeRate(uint256)\":{\"notice\":\"Allows the contract governor to set the protocol fee rate. The protocol fee is taken from the origin amount only for completed and claimed transactions.\"},\"sweepProtocolFees(address,address)\":{\"notice\":\"Allows the contract governor to sweep the accumulated protocol fees in the contract.\"}},\"notice\":\"FastBridgeV2 is a contract for bridging tokens across chains.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeV2.sol\":\"FastBridgeV2\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeV2.sol\":{\"keccak256\":\"0xac79c463688a682ca706a4ef95e7817b83548cdfa8182ba0426ac7e5e07613d8\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://b3ecb7097381287cafc3a73f3a2bb03565115ebb682a85064e0b0dc2f7e2919d\",\"dweb:/ipfs/QmatruW3nYZTksf3CeQ8wwiAG4c7xoEJBEp6drHPtFLBRK\"]}},\"version\":1}"},"hashes":{"CANCELER_ROLE()":"02d2ff66","DEFAULT_ADMIN_ROLE()":"a217fddf","DEFAULT_CANCEL_DELAY()":"930ac180","DISPUTE_PERIOD()":"a5bbe22b","FEE_BPS()":"bf333f2c","FEE_RATE_MAX()":"0f5f6ed7","GOVERNOR_ROLE()":"ccc57490","GUARD_ROLE()":"03ed0ee5","MAX_ZAP_DATA_LENGTH()":"54eff068","MIN_CANCEL_DELAY()":"922b7487","MIN_DEADLINE_PERIOD()":"820688d5","NATIVE_GAS_TOKEN()":"0f862f1e","PROVER_ROLE()":"dc9a4ef6","QUOTER_ROLE()":"7ebe815c","bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256))":"45851694","bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256),(address,int256,bytes,uint256,bytes))":"bfc7c607","bridgeProofs(bytes32)":"91ad5039","bridgeRelayDetails(bytes32)":"c79371b1","bridgeRelays(bytes32)":"8379a24f","bridgeStatuses(bytes32)":"051287bc","bridgeTxDetails(bytes32)":"63787e52","canClaim(bytes32,address)":"aa9641ab","cancel(bytes)":"3c5beeb4","cancelDelay()":"638a0f09","chainGasAmount()":"e00a83e0","claim(bytes)":"c63ff8dd","claim(bytes,address)":"41fcb612","deployBlock()":"a3ec191a","dispute(bytes32)":"add98c70","getBridgeTransaction(bytes)":"ac11fb1a","getBridgeTransactionV2(bytes)":"5aa6ccba","getRoleAdmin(bytes32)":"248a9ca3","getRoleMember(bytes32,uint256)":"9010d07c","getRoleMemberCount(bytes32)":"ca15c873","grantRole(bytes32,address)":"2f2ff15d","hasRole(bytes32,address)":"91d14854","multicallNoResults(bytes[],bool)":"3f61331d","multicallWithResults(bytes[],bool)":"385c1d2f","nonce()":"affed0e0","protocolFeeRate()":"58f85880","protocolFees(address)":"dcf844a7","prove(bytes,bytes32)":"886d36ff","prove(bytes32,bytes32,address)":"18e4357d","refund(bytes)":"5eb7d946","relay(bytes)":"8f0d6f17","relay(bytes,address)":"9c9545f0","renounceRole(bytes32,address)":"36568abe","revokeRole(bytes32,address)":"d547741f","senderNonces(address)":"295710ff","setCancelDelay(uint256)":"1ea327c5","setProtocolFeeRate(uint256)":"b13aa2d6","supportsInterface(bytes4)":"01ffc9a7","sweepProtocolFees(address,address)":"06f333f2"}},"solidity/FastBridgeV2.sol:IAccessControl":{"code":"0x","runtime-code":"0x","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.24 ^0.8.20 ^0.8.4;\n\n// contracts/interfaces/IAdminV2.sol\n\ninterface IAdminV2 {\n event CancelDelayUpdated(uint256 oldCancelDelay, uint256 newCancelDelay);\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n function setCancelDelay(uint256 newCancelDelay) external;\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n}\n\n// contracts/interfaces/IAdminV2Errors.sol\n\ninterface IAdminV2Errors {\n error CancelDelayBelowMin();\n error FeeRateAboveMax();\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IFastBridgeV2Errors.sol\n\ninterface IFastBridgeV2Errors {\n error AmountIncorrect();\n error ChainIncorrect();\n error ExclusivityParamsIncorrect();\n error MsgValueIncorrect();\n error SenderIncorrect();\n error StatusIncorrect();\n error TokenNotContract();\n error ZapDataLengthAboveMax();\n error ZapNativeNotSupported();\n error ZeroAddress();\n\n error RecipientIncorrectReturnValue();\n error RecipientNoReturnValue();\n\n error DeadlineExceeded();\n error DeadlineNotExceeded();\n error DeadlineTooShort();\n error DisputePeriodNotPassed();\n error DisputePeriodPassed();\n error ExclusivityPeriodNotPassed();\n\n error TransactionRelayed();\n}\n\n// contracts/interfaces/IMulticallTarget.sol\n\n/// @notice Interface for a contract that can be called multiple times by the same caller. Inspired by MulticallV3:\n/// https://github.com/mds1/multicall/blob/master/src/Multicall3.sol\ninterface IMulticallTarget {\n struct Result {\n bool success;\n bytes returnData;\n }\n\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external;\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results);\n}\n\n// contracts/interfaces/IZapRecipient.sol\n\ninterface IZapRecipient {\n function zap(address token, uint256 amount, bytes memory zapData) external payable returns (bytes4);\n}\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// contracts/interfaces/IFastBridgeV2.sol\n\ninterface IFastBridgeV2 is IFastBridge {\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n struct BridgeTxDetails {\n BridgeStatus status;\n uint32 destChainId;\n uint56 proofBlockTimestamp;\n address proofRelayer;\n }\n\n struct BridgeRelay {\n uint48 blockNumber;\n uint48 blockTimestamp;\n address relayer;\n }\n\n /// @notice New params introduced in the FastBridgeV2.\n /// We are passing fields from the older BridgeParams struct outside of this struct\n /// for backwards compatibility.\n /// Note: quoteRelayer and quoteExclusivitySeconds are either both zero (indicating no exclusivity)\n /// or both non-zero (indicating exclusivity for the given period).\n /// Note: zapNative \u003e 0 can NOT be used with destToken = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE (native token)\n /// @param quoteRelayer Relayer that provided the quote for the transaction\n /// @param quoteExclusivitySeconds Period of time the quote relayer is guaranteed exclusivity after user's deposit\n /// @param quoteId Unique quote identifier used for tracking the quote\n /// @param zapNative ETH value to send to the recipient (if any)\n /// @param zapData Parameters for the Zap to the destination recipient (if any)\n struct BridgeParamsV2 {\n address quoteRelayer;\n int256 quoteExclusivitySeconds;\n bytes quoteId;\n uint256 zapNative;\n bytes zapData;\n }\n\n /// @notice Updated bridge transaction struct to include parameters introduced in FastBridgeV2.\n /// Note: only `exclusivityRelayer` can fill such a transaction until `exclusivityEndTime`.\n struct BridgeTransactionV2 {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n // Note: sendChainGas flag from V1 is deprecated\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n address exclusivityRelayer;\n uint256 exclusivityEndTime;\n uint256 zapNative; // ETH value to send to the recipient (if any)\n bytes zapData; // data to pass for the Zap action (if any)\n }\n\n event BridgeQuoteDetails(bytes32 indexed transactionId, bytes quoteId);\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability\n /// to provide temporary exclusivity fill rights for the quote relayer.\n /// @param params The parameters required to bridge\n /// @param paramsV2 The parameters for exclusivity fill rights (optional, can be left empty)\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function relay(bytes memory request, address relayer) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param transactionId The transaction id associated with the encoded bridge transaction to prove\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital.\n /// @notice Can only send funds to the relayer address on the proof.\n /// @param request The encoded bridge transaction to claim on origin chain\n function claim(bytes memory request) external;\n\n /// @notice Cancels an outstanding bridge transaction in case optimistic bridging failed and returns the full amount\n /// to the original sender.\n /// @param request The encoded bridge transaction to refund\n function cancel(bytes memory request) external;\n\n /// @notice Checks if a transaction has been relayed\n /// @param transactionId The ID of the transaction to check\n /// @return True if the transaction has been relayed, false otherwise\n function bridgeRelays(bytes32 transactionId) external view returns (bool);\n\n /// @notice Returns the status of a bridge transaction\n /// @param transactionId The ID of the bridge transaction\n /// @return BridgeStatus Status of the bridge transaction\n function bridgeStatuses(bytes32 transactionId) external view returns (BridgeStatus);\n\n /// @notice Returns the timestamp and relayer of a bridge proof\n /// @param transactionId The ID of the bridge transaction\n /// @return timestamp The timestamp of the bridge proof\n /// @return relayer The relayer address of the bridge proof\n function bridgeProofs(bytes32 transactionId) external view returns (uint96 timestamp, address relayer);\n\n /// @notice Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\n /// @param request The bridge request to decode\n function getBridgeTransactionV2(bytes memory request) external view returns (BridgeTransactionV2 memory);\n}\n\n// contracts/utils/MulticallTarget.sol\n\n// solhint-disable avoid-low-level-calls\n/// @notice Template for a contract that supports batched calls (preserving the msg.sender).\n/// Only calls with zero msg.value could be batched.\nabstract contract MulticallTarget is IMulticallTarget {\n error MulticallTarget__UndeterminedRevert();\n\n /// @notice Perform a batched call to this contract, preserving the msg.sender.\n /// The return data from each call is discarded.\n /// @dev The method is non-payable, so only calls with `msg.value == 0` could be batched.\n /// It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag.\n /// Otherwise, the whole batch call will be reverted with the original revert reason.\n /// @param data List of abi-encoded calldata for the calls to perform.\n /// @param ignoreReverts Whether to ignore the revert errors from the calls.\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external {\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\n if (!success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(result);\n }\n }\n }\n\n /// @notice Perform a batched call to this contract, preserving the msg.sender.\n /// The return data from each call is preserved.\n /// @dev The method is non-payable, so only calls with `msg.value == 0` could be batched.\n /// It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag.\n /// Otherwise, the whole batch call will be reverted with the original revert reason.\n /// @param data List of abi-encoded calldata for the calls to perform.\n /// @param ignoreReverts Whether to ignore the revert errors from the calls.\n /// @return results List of results from the calls: `(success, returnData)`.\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results)\n {\n results = new Result[](data.length);\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (results[i].success, results[i].returnData) = address(this).delegatecall(data[i]);\n if (!results[i].success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(results[i].returnData);\n }\n }\n }\n\n /// @dev Bubbles the revert message from the underlying call.\n /// Note: preserves the same custom error or revert string, if one was used.\n /// Source: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v5.0.2/contracts/utils/Address.sol#L143-L158\n function _bubbleRevert(bytes memory returnData) internal pure {\n // Look for revert reason and bubble it up if present\n if (returnData.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n // solhint-disable-next-line no-inline-assembly\n assembly {\n let returndata_size := mload(returnData)\n revert(add(32, returnData), returndata_size)\n }\n } else {\n revert MulticallTarget__UndeterminedRevert();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// contracts/libs/BridgeTransactionV2.sol\n\n// solhint-disable no-inline-assembly\nlibrary BridgeTransactionV2Lib {\n uint16 internal constant VERSION = 2;\n\n // Offsets of the fields in the packed BridgeTransactionV2 struct\n // uint16 version [000 .. 002)\n // uint32 originChainId [002 .. 006)\n // uint32 destChainId [006 .. 010)\n // address originSender [010 .. 030)\n // address destRecipient [030 .. 050)\n // address originToken [050 .. 070)\n // address destToken [070 .. 090)\n // uint256 originAmount [090 .. 122)\n // uint256 destAmount [122 .. 154)\n // uint256 originFeeAmount [154 .. 186)\n // uint256 deadline [186 .. 218)\n // uint256 nonce [218 .. 250)\n // address exclusivityRelayer [250 .. 270)\n // uint256 exclusivityEndTime [270 .. 302)\n // uint256 zapNative [302 .. 334)\n // bytes zapData [334 .. ***)\n\n // forgefmt: disable-start\n uint256 private constant OFFSET_ORIGIN_CHAIN_ID = 2;\n uint256 private constant OFFSET_DEST_CHAIN_ID = 6;\n uint256 private constant OFFSET_ORIGIN_SENDER = 10;\n uint256 private constant OFFSET_DEST_RECIPIENT = 30;\n uint256 private constant OFFSET_ORIGIN_TOKEN = 50;\n uint256 private constant OFFSET_DEST_TOKEN = 70;\n uint256 private constant OFFSET_ORIGIN_AMOUNT = 90;\n uint256 private constant OFFSET_DEST_AMOUNT = 122;\n uint256 private constant OFFSET_ORIGIN_FEE_AMOUNT = 154;\n uint256 private constant OFFSET_DEADLINE = 186;\n uint256 private constant OFFSET_NONCE = 218;\n uint256 private constant OFFSET_EXCLUSIVITY_RELAYER = 250;\n uint256 private constant OFFSET_EXCLUSIVITY_END_TIME = 270;\n uint256 private constant OFFSET_ZAP_NATIVE = 302;\n uint256 private constant OFFSET_ZAP_DATA = 334;\n // forgefmt: disable-end\n\n error BridgeTransactionV2__InvalidEncodedTx();\n error BridgeTransactionV2__UnsupportedVersion(uint16 version);\n\n /// @notice Validates the encoded transaction to be a tightly packed encoded payload for BridgeTransactionV2.\n /// @dev Checks the minimum length and the version, use this function before decoding any of the fields.\n function validateV2(bytes calldata encodedTx) internal pure {\n // Check the minimum length: must at least include all static fields.\n if (encodedTx.length \u003c OFFSET_ZAP_DATA) revert BridgeTransactionV2__InvalidEncodedTx();\n // Once we validated the length, we can be sure that the version field is present.\n uint16 version_ = version(encodedTx);\n if (version_ != VERSION) revert BridgeTransactionV2__UnsupportedVersion(version_);\n }\n\n /// @notice Encodes the BridgeTransactionV2 struct by tightly packing the fields.\n /// @dev `abi.decode` will not work as a result of the tightly packed fields. Use `decodeV2` to decode instead.\n function encodeV2(IFastBridgeV2.BridgeTransactionV2 memory bridgeTx) internal pure returns (bytes memory) {\n // We split the encoding into two parts to avoid stack-too-deep error\n bytes memory firstPart = abi.encodePacked(\n VERSION,\n bridgeTx.originChainId,\n bridgeTx.destChainId,\n bridgeTx.originSender,\n bridgeTx.destRecipient,\n bridgeTx.originToken,\n bridgeTx.destToken,\n bridgeTx.originAmount\n );\n return abi.encodePacked(\n firstPart,\n bridgeTx.destAmount,\n bridgeTx.originFeeAmount,\n // Note: we skip the deprecated `sendChainGas` flag, which was present in BridgeTransaction V1\n bridgeTx.deadline,\n bridgeTx.nonce,\n // New V2 fields: exclusivity\n bridgeTx.exclusivityRelayer,\n bridgeTx.exclusivityEndTime,\n // New V2 fields: Zap\n bridgeTx.zapNative,\n bridgeTx.zapData\n );\n }\n\n /// @notice Decodes the BridgeTransactionV2 struct from the encoded transaction.\n /// @dev Encoded BridgeTransactionV2 struct must be tightly packed.\n /// Use `validateV2` before decoding to ensure the encoded transaction is valid.\n function decodeV2(bytes calldata encodedTx)\n internal\n pure\n returns (IFastBridgeV2.BridgeTransactionV2 memory bridgeTx)\n {\n bridgeTx.originChainId = originChainId(encodedTx);\n bridgeTx.destChainId = destChainId(encodedTx);\n bridgeTx.originSender = originSender(encodedTx);\n bridgeTx.destRecipient = destRecipient(encodedTx);\n bridgeTx.originToken = originToken(encodedTx);\n bridgeTx.destToken = destToken(encodedTx);\n bridgeTx.originAmount = originAmount(encodedTx);\n bridgeTx.destAmount = destAmount(encodedTx);\n bridgeTx.originFeeAmount = originFeeAmount(encodedTx);\n bridgeTx.deadline = deadline(encodedTx);\n bridgeTx.nonce = nonce(encodedTx);\n bridgeTx.exclusivityRelayer = exclusivityRelayer(encodedTx);\n bridgeTx.exclusivityEndTime = exclusivityEndTime(encodedTx);\n bridgeTx.zapNative = zapNative(encodedTx);\n bridgeTx.zapData = zapData(encodedTx);\n }\n\n /// @notice Extracts the version from the encoded transaction.\n function version(bytes calldata encodedTx) internal pure returns (uint16 version_) {\n // Load 32 bytes from the start and shift it 240 bits to the right to get the highest 16 bits.\n assembly {\n version_ := shr(240, calldataload(encodedTx.offset))\n }\n }\n\n /// @notice Extracts the origin chain ID from the encoded transaction.\n function originChainId(bytes calldata encodedTx) internal pure returns (uint32 originChainId_) {\n // Load 32 bytes from the offset and shift it 224 bits to the right to get the highest 32 bits.\n assembly {\n originChainId_ := shr(224, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_CHAIN_ID)))\n }\n }\n\n /// @notice Extracts the destination chain ID from the encoded transaction.\n function destChainId(bytes calldata encodedTx) internal pure returns (uint32 destChainId_) {\n // Load 32 bytes from the offset and shift it 224 bits to the right to get the highest 32 bits.\n assembly {\n destChainId_ := shr(224, calldataload(add(encodedTx.offset, OFFSET_DEST_CHAIN_ID)))\n }\n }\n\n /// @notice Extracts the origin sender from the encoded transaction.\n function originSender(bytes calldata encodedTx) internal pure returns (address originSender_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n originSender_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_SENDER)))\n }\n }\n\n /// @notice Extracts the destination recipient from the encoded transaction.\n function destRecipient(bytes calldata encodedTx) internal pure returns (address destRecipient_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n destRecipient_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_DEST_RECIPIENT)))\n }\n }\n\n /// @notice Extracts the origin token from the encoded transaction.\n function originToken(bytes calldata encodedTx) internal pure returns (address originToken_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n originToken_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_TOKEN)))\n }\n }\n\n /// @notice Extracts the destination token from the encoded transaction.\n function destToken(bytes calldata encodedTx) internal pure returns (address destToken_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n destToken_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_DEST_TOKEN)))\n }\n }\n\n /// @notice Extracts the origin amount from the encoded transaction.\n function originAmount(bytes calldata encodedTx) internal pure returns (uint256 originAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n originAmount_ := calldataload(add(encodedTx.offset, OFFSET_ORIGIN_AMOUNT))\n }\n }\n\n /// @notice Extracts the destination amount from the encoded transaction.\n function destAmount(bytes calldata encodedTx) internal pure returns (uint256 destAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n destAmount_ := calldataload(add(encodedTx.offset, OFFSET_DEST_AMOUNT))\n }\n }\n\n /// @notice Extracts the origin fee amount from the encoded transaction.\n function originFeeAmount(bytes calldata encodedTx) internal pure returns (uint256 originFeeAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n originFeeAmount_ := calldataload(add(encodedTx.offset, OFFSET_ORIGIN_FEE_AMOUNT))\n }\n }\n\n /// @notice Extracts the deadline from the encoded transaction.\n function deadline(bytes calldata encodedTx) internal pure returns (uint256 deadline_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n deadline_ := calldataload(add(encodedTx.offset, OFFSET_DEADLINE))\n }\n }\n\n /// @notice Extracts the nonce from the encoded transaction.\n function nonce(bytes calldata encodedTx) internal pure returns (uint256 nonce_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n nonce_ := calldataload(add(encodedTx.offset, OFFSET_NONCE))\n }\n }\n\n /// @notice Extracts the exclusivity relayer from the encoded transaction.\n function exclusivityRelayer(bytes calldata encodedTx) internal pure returns (address exclusivityRelayer_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n exclusivityRelayer_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_EXCLUSIVITY_RELAYER)))\n }\n }\n\n /// @notice Extracts the exclusivity end time from the encoded transaction.\n function exclusivityEndTime(bytes calldata encodedTx) internal pure returns (uint256 exclusivityEndTime_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n exclusivityEndTime_ := calldataload(add(encodedTx.offset, OFFSET_EXCLUSIVITY_END_TIME))\n }\n }\n\n /// @notice Extracts the Zap's native value from the encoded transaction.\n function zapNative(bytes calldata encodedTx) internal pure returns (uint256 zapNative_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n zapNative_ := calldataload(add(encodedTx.offset, OFFSET_ZAP_NATIVE))\n }\n }\n\n /// @notice Extracts the Zap's data from the encoded transaction.\n function zapData(bytes calldata encodedTx) internal pure returns (bytes calldata zapData_) {\n zapData_ = encodedTx[OFFSET_ZAP_DATA:];\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/AdminV2.sol\n\ncontract AdminV2 is AccessControlEnumerable, IAdminV2, IAdminV2Errors {\n using SafeERC20 for IERC20;\n\n /// @notice Address reserved for native gas token (ETH on Ethereum and most L2s, AVAX on Avalanche, etc)\n address public constant NATIVE_GAS_TOKEN = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Role identifier for Quoter API's off-chain authentication.\n /// @dev Only addresses with this role can post FastBridge quotes to the API.\n bytes32 public constant QUOTER_ROLE = keccak256(\"QUOTER_ROLE\");\n\n /// @notice Role identifier for Prover's on-chain authentication in FastBridge.\n /// @dev Only addresses with this role can provide proofs that a FastBridge request has been relayed.\n bytes32 public constant PROVER_ROLE = keccak256(\"PROVER_ROLE\");\n\n /// @notice Role identifier for Guard's on-chain authentication in FastBridge.\n /// @dev Only addresses with this role can dispute submitted relay proofs during the dispute period.\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n\n /// @notice Role identifier for Canceler's on-chain authentication in FastBridge.\n /// @dev Only addresses with this role can cancel a FastBridge transaction without the cancel delay.\n bytes32 public constant CANCELER_ROLE = keccak256(\"CANCELER_ROLE\");\n\n /// @notice Role identifier for Governor's on-chain administrative authority.\n /// @dev Only addresses with this role can perform administrative tasks within the contract.\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n /// @notice Denominator for fee rates, represents 100%.\n uint256 public constant FEE_BPS = 1e6;\n /// @notice Maximum protocol fee rate: 1% on origin amount.\n uint256 public constant FEE_RATE_MAX = 0.01e6;\n\n /// @notice Minimum cancel delay that can be set by the governor.\n uint256 public constant MIN_CANCEL_DELAY = 1 hours;\n /// @notice Default cancel delay set during the contract deployment.\n uint256 public constant DEFAULT_CANCEL_DELAY = 1 days;\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Delay for a transaction after which it could be permisionlessly cancelled\n uint256 public cancelDelay;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Use ZapNative V2 requests instead.\n uint256 public immutable chainGasAmount = 0;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n _setCancelDelay(DEFAULT_CANCEL_DELAY);\n }\n\n /// @notice Allows the contract governor to set the cancel delay. The cancel delay is the time after the transaction\n /// deadline after which it can be permissionlessly cancelled, if it hasn't been proven by any of the Relayers.\n function setCancelDelay(uint256 newCancelDelay) external onlyRole(GOVERNOR_ROLE) {\n _setCancelDelay(newCancelDelay);\n }\n\n /// @notice Allows the contract governor to set the protocol fee rate. The protocol fee is taken from the origin\n /// amount only for completed and claimed transactions.\n /// @dev The protocol fee is abstracted away from the relayers, they always operate using the amounts after fees:\n /// what they see as the origin amount emitted in the log is what they get credited with.\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n if (newFeeRate \u003e FEE_RATE_MAX) revert FeeRateAboveMax();\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n /// @notice Allows the contract governor to sweep the accumulated protocol fees in the contract.\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n emit FeesSwept(token, recipient, feeAmount);\n /// Sweep the fees as the last transaction action\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(recipient), feeAmount);\n } else {\n IERC20(token).safeTransfer(recipient, feeAmount);\n }\n }\n\n /// @notice Internal function to set the cancel delay. Security checks are performed outside of this function.\n function _setCancelDelay(uint256 newCancelDelay) private {\n if (newCancelDelay \u003c MIN_CANCEL_DELAY) revert CancelDelayBelowMin();\n uint256 oldCancelDelay = cancelDelay;\n cancelDelay = newCancelDelay;\n emit CancelDelayUpdated(oldCancelDelay, newCancelDelay);\n }\n}\n\n// contracts/FastBridgeV2.sol\n\n/// @notice FastBridgeV2 is a contract for bridging tokens across chains.\ncontract FastBridgeV2 is AdminV2, MulticallTarget, IFastBridgeV2, IFastBridgeV2Errors {\n using BridgeTransactionV2Lib for bytes;\n using SafeERC20 for IERC20;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n /// @notice Maximum length of accepted zapData\n uint256 public constant MAX_ZAP_DATA_LENGTH = 2 ** 16 - 1;\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeTxDetails) public bridgeTxDetails;\n /// @notice Relay details on destination chain\n mapping(bytes32 =\u003e BridgeRelay) public bridgeRelayDetails;\n /// @notice Unique bridge nonces tracked per originSender\n mapping(address =\u003e uint256) public senderNonces;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Replaced by senderNonces\n uint256 public immutable nonce = 0;\n /// @notice the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) AdminV2(_owner) {\n deployBlock = block.number;\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n bridge({\n params: params,\n paramsV2: BridgeParamsV2({\n quoteRelayer: address(0),\n quoteExclusivitySeconds: 0,\n quoteId: bytes(\"\"),\n zapNative: 0,\n zapData: bytes(\"\")\n })\n });\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes calldata request) external payable {\n // relay override will validate the request\n relay({request: request, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes calldata request, bytes32 destTxHash) external {\n request.validateV2();\n prove({transactionId: keccak256(request), destTxHash: destTxHash, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridgeV2\n function claim(bytes calldata request) external {\n // claim override will validate the request\n claim({request: request, to: address(0)});\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Aggregate the read operations from the same storage slot\n address disputedRelayer = $.proofRelayer;\n BridgeStatus status = $.status;\n uint56 proofBlockTimestamp = $.proofBlockTimestamp;\n // Can only dispute a RELAYER_PROVED transaction within the dispute period\n if (status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(proofBlockTimestamp) \u003e DISPUTE_PERIOD) {\n revert DisputePeriodPassed();\n }\n // Update status to REQUESTED and delete the disputed proof details\n // Note: these are storage writes\n $.status = BridgeStatus.REQUESTED;\n $.proofRelayer = address(0);\n $.proofBlockTimestamp = 0;\n\n emit BridgeProofDisputed(transactionId, disputedRelayer);\n }\n\n /// Note: this function is deprecated and will be removed in a future version.\n /// @inheritdoc IFastBridge\n function refund(bytes calldata request) external {\n cancel(request);\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // The correct relayer can only claim a RELAYER_PROVED transaction after the dispute period\n if ($.status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if ($.proofRelayer != relayer) revert SenderIncorrect();\n return _timeSince($.proofBlockTimestamp) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n /// @dev This method is added to achieve backwards compatibility with decoding requests into V1 structs:\n /// - `zapNative` is partially reported as a zero/non-zero flag\n /// - `zapData` is ignored\n /// In order to process all kinds of requests use getBridgeTransactionV2 instead.\n function getBridgeTransaction(bytes calldata request) external view returns (BridgeTransaction memory) {\n // Try decoding into V2 struct first. This will revert if V1 struct is passed\n try this.getBridgeTransactionV2(request) returns (BridgeTransactionV2 memory txV2) {\n // Note: we entirely ignore the zapData field, as it was not present in V1\n return BridgeTransaction({\n originChainId: txV2.originChainId,\n destChainId: txV2.destChainId,\n originSender: txV2.originSender,\n destRecipient: txV2.destRecipient,\n originToken: txV2.originToken,\n destToken: txV2.destToken,\n originAmount: txV2.originAmount,\n destAmount: txV2.destAmount,\n originFeeAmount: txV2.originFeeAmount,\n sendChainGas: txV2.zapNative != 0,\n deadline: txV2.deadline,\n nonce: txV2.nonce\n });\n } catch {\n // Fallback to V1 struct\n return abi.decode(request, (BridgeTransaction));\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function getBridgeTransactionV2(bytes calldata request) external pure returns (BridgeTransactionV2 memory) {\n request.validateV2();\n return BridgeTransactionV2Lib.decodeV2(request);\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) public payable {\n int256 exclusivityEndTime = 0;\n // if relayer exclusivity is not intended for this bridge, set exclusivityEndTime to static zero\n // otherwise, set exclusivity to expire at the current block ts offset by quoteExclusivitySeconds\n if (paramsV2.quoteRelayer != address(0)) {\n exclusivityEndTime = int256(block.timestamp) + paramsV2.quoteExclusivitySeconds;\n }\n _validateBridgeParams(params, paramsV2, exclusivityEndTime);\n\n // transfer tokens to bridge contract\n /// @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _takeBridgedUserAsset(params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) {\n originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n }\n\n // set status to requested\n bytes memory request = BridgeTransactionV2Lib.encodeV2(\n BridgeTransactionV2({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n deadline: params.deadline,\n nonce: senderNonces[params.sender]++, // increment nonce on every bridge\n exclusivityRelayer: paramsV2.quoteRelayer,\n // We checked exclusivityEndTime to be in range [0 .. params.deadline] above, so can safely cast\n exclusivityEndTime: uint256(exclusivityEndTime),\n zapNative: paramsV2.zapNative,\n zapData: paramsV2.zapData\n })\n );\n bytes32 transactionId = keccak256(request);\n // Note: the tx status will be updated throughout the tx lifecycle, while destChainId is set once here\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n bridgeTxDetails[transactionId].destChainId = params.dstChainId;\n\n emit BridgeRequested({\n transactionId: transactionId,\n sender: params.sender,\n request: request,\n destChainId: params.dstChainId,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n sendChainGas: paramsV2.zapNative != 0\n });\n emit BridgeQuoteDetails(transactionId, paramsV2.quoteId);\n }\n\n /// @inheritdoc IFastBridgeV2\n function relay(bytes calldata request, address relayer) public payable {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n _validateRelayParams(request, transactionId, relayer);\n // mark bridge transaction as relayed\n bridgeRelayDetails[transactionId] =\n BridgeRelay({blockNumber: uint48(block.number), blockTimestamp: uint48(block.timestamp), relayer: relayer});\n\n // transfer tokens to recipient on destination chain and trigger Zap if requested\n address to = request.destRecipient();\n address token = request.destToken();\n uint256 amount = request.destAmount();\n uint256 zapNative = request.zapNative();\n\n // Emit the event before any external calls\n emit BridgeRelayed({\n transactionId: transactionId,\n relayer: relayer,\n to: to,\n originChainId: request.originChainId(),\n originToken: request.originToken(),\n destToken: token,\n originAmount: request.originAmount(),\n destAmount: amount,\n chainGasAmount: zapNative\n });\n\n // All state changes have been done at this point, can proceed to the external calls.\n // This follows the checks-effects-interactions pattern to mitigate potential reentrancy attacks.\n if (token == NATIVE_GAS_TOKEN) {\n // For the native gas token, additional zapNative is not allowed\n if (zapNative != 0) revert ZapNativeNotSupported();\n // Check that the correct msg.value was sent\n if (msg.value != amount) revert MsgValueIncorrect();\n // Don't do a native transfer yet: we will handle it alongside the Zap below\n } else {\n // For ERC20s, we check that the correct msg.value was sent\n if (msg.value != zapNative) revert MsgValueIncorrect();\n // We need to transfer the tokens from the Relayer to the recipient first before performing an\n // optional post-transfer Zap.\n IERC20(token).safeTransferFrom(msg.sender, to, amount);\n }\n // At this point we have done:\n // - Transferred the requested amount of ERC20 tokens to the recipient.\n // At this point we have confirmed:\n // - For ERC20s: msg.value matches the requested zapNative amount.\n // - For the native gas token: msg.value matches the requested destAmount.\n // Remaining optional things to do:\n // - Forward the full msg.value to the recipient (if non-zero).\n // - Trigger a Zap (if zapData is present).\n bytes calldata zapData = request.zapData();\n if (zapData.length != 0) {\n // Zap Data is present: Zap has been requested by the recipient. Trigger it forwarding the full msg.value.\n\n // Note: if token has a fee on transfers, the recipient will have received less than `amount`.\n // This is a very niche edge case and should be handled by the recipient contract.\n _triggerZapWithChecks({recipient: to, token: token, amount: amount, zapData: zapData});\n } else if (msg.value != 0) {\n // Zap Data is missing, but msg.value was sent. This could happen in two different cases:\n // - Relay with the native gas token is happening.\n // - Relay with ERC20 is happening, with a `zapNative \u003e 0` request.\n // In both cases, we need to transfer the full msg.value to the recipient.\n Address.sendValue(payable(to), msg.value);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) public onlyRole(PROVER_ROLE) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n\n // Can only prove a REQUESTED transaction\n if ($.status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n // Update status to RELAYER_PROVED and store the proof details\n // Note: these are storage writes\n $.status = BridgeStatus.RELAYER_PROVED;\n $.proofBlockTimestamp = uint56(block.timestamp);\n $.proofRelayer = relayer;\n\n emit BridgeProofProvided(transactionId, relayer, destTxHash);\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes calldata request, address to) public {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Aggregate the read operations from the same storage slot\n address proofRelayer = $.proofRelayer;\n BridgeStatus status = $.status;\n uint56 proofBlockTimestamp = $.proofBlockTimestamp;\n\n // Can only claim a RELAYER_PROVED transaction after the dispute period\n if (status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(proofBlockTimestamp) \u003c= DISPUTE_PERIOD) {\n revert DisputePeriodNotPassed();\n }\n\n if (to == address(0)) {\n // Anyone could claim the funds to the proven relayer on their behalf\n to = proofRelayer;\n } else if (proofRelayer != msg.sender) {\n // Only the proven relayer could specify an address to claim the funds to\n revert SenderIncorrect();\n }\n\n // Update status to RELAYER_CLAIMED and transfer the origin collateral to the specified claim address\n // Note: this is a storage write\n $.status = BridgeStatus.RELAYER_CLAIMED;\n\n address token = request.originToken();\n uint256 amount = request.originAmount();\n // Update protocol fees if origin fee amount exists\n uint256 originFeeAmount = request.originFeeAmount();\n if (originFeeAmount \u003e 0) protocolFees[token] += originFeeAmount;\n // Emit the event before any external calls\n emit BridgeDepositClaimed(transactionId, proofRelayer, to, token, amount);\n // Complete the relayer claim as the last transaction action\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(to), amount);\n } else {\n IERC20(token).safeTransfer(to, amount);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function cancel(bytes calldata request) public {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Can only cancel a REQUESTED transaction after its deadline expires\n if ($.status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n uint256 deadline = request.deadline();\n // Permissionless cancel is only allowed after `cancelDelay` on top of the deadline\n if (!hasRole(CANCELER_ROLE, msg.sender)) deadline += cancelDelay;\n if (block.timestamp \u003c= deadline) revert DeadlineNotExceeded();\n // Update status to REFUNDED and return the full amount (collateral + protocol fees) to the original sender.\n // The protocol fees are only updated when the transaction is claimed, so we don't need to update them here.\n // Note: this is a storage write\n $.status = BridgeStatus.REFUNDED;\n\n address to = request.originSender();\n address token = request.originToken();\n uint256 amount = request.originAmount() + request.originFeeAmount();\n // Emit the event before any external calls\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n // Complete the user cancel as the last transaction action\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(to), amount);\n } else {\n IERC20(token).safeTransfer(to, amount);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeStatuses(bytes32 transactionId) public view returns (BridgeStatus status) {\n return bridgeTxDetails[transactionId].status;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeProofs(bytes32 transactionId) public view returns (uint96 timestamp, address relayer) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n\n timestamp = $.proofBlockTimestamp;\n relayer = $.proofRelayer;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeRelays(bytes32 transactionId) public view returns (bool) {\n // has this transactionId been relayed?\n return bridgeRelayDetails[transactionId].relayer != address(0);\n }\n\n /// @notice Takes the bridged asset from the user into FastBridgeV2 custody. It will be later\n /// claimed by the relayer who completed the relay on destination chain, or transferred back to the user\n /// via the cancel function should no one complete the relay.\n function _takeBridgedUserAsset(address token, uint256 amount) internal returns (uint256 amountTaken) {\n if (token == NATIVE_GAS_TOKEN) {\n // For the native gas token, we just need to check that the supplied msg.value is correct.\n // Supplied `msg.value` is already in FastBridgeV2 custody.\n if (amount != msg.value) revert MsgValueIncorrect();\n amountTaken = msg.value;\n } else {\n // For ERC20s, token is explicitly transferred from the user to FastBridgeV2.\n // We don't allow non-zero `msg.value` to avoid extra funds from being stuck in FastBridgeV2.\n if (msg.value != 0) revert MsgValueIncorrect();\n // Throw an explicit error if the provided token address is not a contract\n if (token.code.length == 0) revert TokenNotContract();\n amountTaken = IERC20(token).balanceOf(address(this));\n IERC20(token).safeTransferFrom(msg.sender, address(this), amount);\n // Use the balance difference as the amount taken in case of fee on transfer tokens.\n amountTaken = IERC20(token).balanceOf(address(this)) - amountTaken;\n }\n }\n\n /// @notice Calls the Recipient's hook function with the specified zapData and performs\n /// all the necessary checks for the returned value.\n function _triggerZapWithChecks(address recipient, address token, uint256 amount, bytes calldata zapData) internal {\n // This will bubble any revert messages from the hook function\n bytes memory returnData = Address.functionCallWithValue({\n target: recipient,\n data: abi.encodeCall(IZapRecipient.zap, (token, amount, zapData)),\n // Note: see `relay()` for reasoning behind passing msg.value\n value: msg.value\n });\n // Explicit revert if no return data at all\n if (returnData.length == 0) revert RecipientNoReturnValue();\n // Check that exactly a single return value was returned\n if (returnData.length != 32) revert RecipientIncorrectReturnValue();\n // Return value should be abi-encoded hook function selector\n if (bytes32(returnData) != bytes32(IZapRecipient.zap.selector)) {\n revert RecipientIncorrectReturnValue();\n }\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint56(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint56).max but\n /// proof.timestamp \u003c type(uint56).max via unchecked statement\n /// @param proofBlockTimestamp The bridge proof block timestamp\n /// @return delta Time delta since proof submitted\n function _timeSince(uint56 proofBlockTimestamp) internal view returns (uint256 delta) {\n unchecked {\n delta = uint56(block.timestamp) - proofBlockTimestamp;\n }\n }\n\n /// @notice Performs all the necessary checks for a bridge to happen.\n /// @dev There's no good way to refactor this function to reduce cyclomatic complexity due to\n /// the number of checks that need to be performed, so we skip the code-complexity rule here.\n // solhint-disable-next-line code-complexity\n function _validateBridgeParams(\n BridgeParams memory params,\n BridgeParamsV2 memory paramsV2,\n int256 exclusivityEndTime\n )\n internal\n view\n {\n // Check V1 (legacy) params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.sender == address(0) || params.to == address(0)) revert ZeroAddress();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n // Check V2 params\n if (paramsV2.zapData.length \u003e MAX_ZAP_DATA_LENGTH) revert ZapDataLengthAboveMax();\n if (paramsV2.zapNative != 0 \u0026\u0026 params.destToken == NATIVE_GAS_TOKEN) {\n revert ZapNativeNotSupported();\n }\n // exclusivityEndTime must be in range [0 .. params.deadline]\n if (exclusivityEndTime \u003c 0 || exclusivityEndTime \u003e int256(params.deadline)) {\n revert ExclusivityParamsIncorrect();\n }\n }\n\n /// @notice Performs all the necessary checks for a relay to happen.\n function _validateRelayParams(bytes calldata request, bytes32 transactionId, address relayer) internal view {\n if (relayer == address(0)) revert ZeroAddress();\n // Check if the transaction has already been relayed\n if (bridgeRelays(transactionId)) revert TransactionRelayed();\n if (request.destChainId() != block.chainid) revert ChainIncorrect();\n // Check the deadline for relay to happen\n if (block.timestamp \u003e request.deadline()) revert DeadlineExceeded();\n // Check the exclusivity period, if it is still ongoing\n address exclRelayer = request.exclusivityRelayer();\n if (exclRelayer != address(0) \u0026\u0026 exclRelayer != relayer \u0026\u0026 block.timestamp \u003c= request.exclusivityEndTime()) {\n revert ExclusivityPeriodNotPassed();\n }\n }\n}\n","language":"Solidity","languageVersion":"0.8.24","compilerVersion":"0.8.24","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"","srcMapRuntime":"","abiDefinition":[{"inputs":[],"name":"AccessControlBadConfirmation","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"bytes32","name":"neededRole","type":"bytes32"}],"name":"AccessControlUnauthorizedAccount","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"previousAdminRole","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"newAdminRole","type":"bytes32"}],"name":"RoleAdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleRevoked","type":"event"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleAdmin","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"grantRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"hasRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"callerConfirmation","type":"address"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"revokeRole","outputs":[],"stateMutability":"nonpayable","type":"function"}],"userDoc":{"kind":"user","methods":{},"version":1},"developerDoc":{"details":"External interface of AccessControl declared to support ERC165 detection.","errors":{"AccessControlBadConfirmation()":[{"details":"The caller of a function is not the expected one. NOTE: Don't confuse with {AccessControlUnauthorizedAccount}."}],"AccessControlUnauthorizedAccount(address,bytes32)":[{"details":"The `account` is missing a role."}]},"events":{"RoleAdminChanged(bytes32,bytes32,bytes32)":{"details":"Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole` `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite {RoleAdminChanged} not being emitted signaling this."},"RoleGranted(bytes32,address,address)":{"details":"Emitted when `account` is granted `role`. `sender` is the account that originated the contract call, an admin role bearer except when using {AccessControl-_setupRole}."},"RoleRevoked(bytes32,address,address)":{"details":"Emitted when `account` is revoked `role`. `sender` is the account that originated the contract call: - if using `revokeRole`, it is the admin role bearer - if using `renounceRole`, it is the role bearer (i.e. `account`)"}},"kind":"dev","methods":{"getRoleAdmin(bytes32)":{"details":"Returns the admin role that controls `role`. See {grantRole} and {revokeRole}. To change a role's admin, use {AccessControl-_setRoleAdmin}."},"grantRole(bytes32,address)":{"details":"Grants `role` to `account`. If `account` had not been already granted `role`, emits a {RoleGranted} event. Requirements: - the caller must have ``role``'s admin role."},"hasRole(bytes32,address)":{"details":"Returns `true` if `account` has been granted `role`."},"renounceRole(bytes32,address)":{"details":"Revokes `role` from the calling account. Roles are often managed via {grantRole} and {revokeRole}: this function's purpose is to provide a mechanism for accounts to lose their privileges if they are compromised (such as when a trusted device is misplaced). If the calling account had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must be `callerConfirmation`."},"revokeRole(bytes32,address)":{"details":"Revokes `role` from `account`. If `account` had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must have ``role``'s admin role."}},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[],\"name\":\"AccessControlBadConfirmation\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"neededRole\",\"type\":\"bytes32\"}],\"name\":\"AccessControlUnauthorizedAccount\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"previousAdminRole\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"newAdminRole\",\"type\":\"bytes32\"}],\"name\":\"RoleAdminChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleGranted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleRevoked\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"}],\"name\":\"getRoleAdmin\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"grantRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"hasRole\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"callerConfirmation\",\"type\":\"address\"}],\"name\":\"renounceRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"revokeRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"details\":\"External interface of AccessControl declared to support ERC165 detection.\",\"errors\":{\"AccessControlBadConfirmation()\":[{\"details\":\"The caller of a function is not the expected one. NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\"}],\"AccessControlUnauthorizedAccount(address,bytes32)\":[{\"details\":\"The `account` is missing a role.\"}]},\"events\":{\"RoleAdminChanged(bytes32,bytes32,bytes32)\":{\"details\":\"Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole` `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite {RoleAdminChanged} not being emitted signaling this.\"},\"RoleGranted(bytes32,address,address)\":{\"details\":\"Emitted when `account` is granted `role`. `sender` is the account that originated the contract call, an admin role bearer except when using {AccessControl-_setupRole}.\"},\"RoleRevoked(bytes32,address,address)\":{\"details\":\"Emitted when `account` is revoked `role`. `sender` is the account that originated the contract call: - if using `revokeRole`, it is the admin role bearer - if using `renounceRole`, it is the role bearer (i.e. `account`)\"}},\"kind\":\"dev\",\"methods\":{\"getRoleAdmin(bytes32)\":{\"details\":\"Returns the admin role that controls `role`. See {grantRole} and {revokeRole}. To change a role's admin, use {AccessControl-_setRoleAdmin}.\"},\"grantRole(bytes32,address)\":{\"details\":\"Grants `role` to `account`. If `account` had not been already granted `role`, emits a {RoleGranted} event. Requirements: - the caller must have ``role``'s admin role.\"},\"hasRole(bytes32,address)\":{\"details\":\"Returns `true` if `account` has been granted `role`.\"},\"renounceRole(bytes32,address)\":{\"details\":\"Revokes `role` from the calling account. Roles are often managed via {grantRole} and {revokeRole}: this function's purpose is to provide a mechanism for accounts to lose their privileges if they are compromised (such as when a trusted device is misplaced). If the calling account had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must be `callerConfirmation`.\"},\"revokeRole(bytes32,address)\":{\"details\":\"Revokes `role` from `account`. If `account` had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must have ``role``'s admin role.\"}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeV2.sol\":\"IAccessControl\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeV2.sol\":{\"keccak256\":\"0xac79c463688a682ca706a4ef95e7817b83548cdfa8182ba0426ac7e5e07613d8\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://b3ecb7097381287cafc3a73f3a2bb03565115ebb682a85064e0b0dc2f7e2919d\",\"dweb:/ipfs/QmatruW3nYZTksf3CeQ8wwiAG4c7xoEJBEp6drHPtFLBRK\"]}},\"version\":1}"},"hashes":{"getRoleAdmin(bytes32)":"248a9ca3","grantRole(bytes32,address)":"2f2ff15d","hasRole(bytes32,address)":"91d14854","renounceRole(bytes32,address)":"36568abe","revokeRole(bytes32,address)":"d547741f"}},"solidity/FastBridgeV2.sol:IAccessControlEnumerable":{"code":"0x","runtime-code":"0x","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.24 ^0.8.20 ^0.8.4;\n\n// contracts/interfaces/IAdminV2.sol\n\ninterface IAdminV2 {\n event CancelDelayUpdated(uint256 oldCancelDelay, uint256 newCancelDelay);\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n function setCancelDelay(uint256 newCancelDelay) external;\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n}\n\n// contracts/interfaces/IAdminV2Errors.sol\n\ninterface IAdminV2Errors {\n error CancelDelayBelowMin();\n error FeeRateAboveMax();\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IFastBridgeV2Errors.sol\n\ninterface IFastBridgeV2Errors {\n error AmountIncorrect();\n error ChainIncorrect();\n error ExclusivityParamsIncorrect();\n error MsgValueIncorrect();\n error SenderIncorrect();\n error StatusIncorrect();\n error TokenNotContract();\n error ZapDataLengthAboveMax();\n error ZapNativeNotSupported();\n error ZeroAddress();\n\n error RecipientIncorrectReturnValue();\n error RecipientNoReturnValue();\n\n error DeadlineExceeded();\n error DeadlineNotExceeded();\n error DeadlineTooShort();\n error DisputePeriodNotPassed();\n error DisputePeriodPassed();\n error ExclusivityPeriodNotPassed();\n\n error TransactionRelayed();\n}\n\n// contracts/interfaces/IMulticallTarget.sol\n\n/// @notice Interface for a contract that can be called multiple times by the same caller. Inspired by MulticallV3:\n/// https://github.com/mds1/multicall/blob/master/src/Multicall3.sol\ninterface IMulticallTarget {\n struct Result {\n bool success;\n bytes returnData;\n }\n\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external;\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results);\n}\n\n// contracts/interfaces/IZapRecipient.sol\n\ninterface IZapRecipient {\n function zap(address token, uint256 amount, bytes memory zapData) external payable returns (bytes4);\n}\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// contracts/interfaces/IFastBridgeV2.sol\n\ninterface IFastBridgeV2 is IFastBridge {\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n struct BridgeTxDetails {\n BridgeStatus status;\n uint32 destChainId;\n uint56 proofBlockTimestamp;\n address proofRelayer;\n }\n\n struct BridgeRelay {\n uint48 blockNumber;\n uint48 blockTimestamp;\n address relayer;\n }\n\n /// @notice New params introduced in the FastBridgeV2.\n /// We are passing fields from the older BridgeParams struct outside of this struct\n /// for backwards compatibility.\n /// Note: quoteRelayer and quoteExclusivitySeconds are either both zero (indicating no exclusivity)\n /// or both non-zero (indicating exclusivity for the given period).\n /// Note: zapNative \u003e 0 can NOT be used with destToken = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE (native token)\n /// @param quoteRelayer Relayer that provided the quote for the transaction\n /// @param quoteExclusivitySeconds Period of time the quote relayer is guaranteed exclusivity after user's deposit\n /// @param quoteId Unique quote identifier used for tracking the quote\n /// @param zapNative ETH value to send to the recipient (if any)\n /// @param zapData Parameters for the Zap to the destination recipient (if any)\n struct BridgeParamsV2 {\n address quoteRelayer;\n int256 quoteExclusivitySeconds;\n bytes quoteId;\n uint256 zapNative;\n bytes zapData;\n }\n\n /// @notice Updated bridge transaction struct to include parameters introduced in FastBridgeV2.\n /// Note: only `exclusivityRelayer` can fill such a transaction until `exclusivityEndTime`.\n struct BridgeTransactionV2 {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n // Note: sendChainGas flag from V1 is deprecated\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n address exclusivityRelayer;\n uint256 exclusivityEndTime;\n uint256 zapNative; // ETH value to send to the recipient (if any)\n bytes zapData; // data to pass for the Zap action (if any)\n }\n\n event BridgeQuoteDetails(bytes32 indexed transactionId, bytes quoteId);\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability\n /// to provide temporary exclusivity fill rights for the quote relayer.\n /// @param params The parameters required to bridge\n /// @param paramsV2 The parameters for exclusivity fill rights (optional, can be left empty)\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function relay(bytes memory request, address relayer) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param transactionId The transaction id associated with the encoded bridge transaction to prove\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital.\n /// @notice Can only send funds to the relayer address on the proof.\n /// @param request The encoded bridge transaction to claim on origin chain\n function claim(bytes memory request) external;\n\n /// @notice Cancels an outstanding bridge transaction in case optimistic bridging failed and returns the full amount\n /// to the original sender.\n /// @param request The encoded bridge transaction to refund\n function cancel(bytes memory request) external;\n\n /// @notice Checks if a transaction has been relayed\n /// @param transactionId The ID of the transaction to check\n /// @return True if the transaction has been relayed, false otherwise\n function bridgeRelays(bytes32 transactionId) external view returns (bool);\n\n /// @notice Returns the status of a bridge transaction\n /// @param transactionId The ID of the bridge transaction\n /// @return BridgeStatus Status of the bridge transaction\n function bridgeStatuses(bytes32 transactionId) external view returns (BridgeStatus);\n\n /// @notice Returns the timestamp and relayer of a bridge proof\n /// @param transactionId The ID of the bridge transaction\n /// @return timestamp The timestamp of the bridge proof\n /// @return relayer The relayer address of the bridge proof\n function bridgeProofs(bytes32 transactionId) external view returns (uint96 timestamp, address relayer);\n\n /// @notice Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\n /// @param request The bridge request to decode\n function getBridgeTransactionV2(bytes memory request) external view returns (BridgeTransactionV2 memory);\n}\n\n// contracts/utils/MulticallTarget.sol\n\n// solhint-disable avoid-low-level-calls\n/// @notice Template for a contract that supports batched calls (preserving the msg.sender).\n/// Only calls with zero msg.value could be batched.\nabstract contract MulticallTarget is IMulticallTarget {\n error MulticallTarget__UndeterminedRevert();\n\n /// @notice Perform a batched call to this contract, preserving the msg.sender.\n /// The return data from each call is discarded.\n /// @dev The method is non-payable, so only calls with `msg.value == 0` could be batched.\n /// It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag.\n /// Otherwise, the whole batch call will be reverted with the original revert reason.\n /// @param data List of abi-encoded calldata for the calls to perform.\n /// @param ignoreReverts Whether to ignore the revert errors from the calls.\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external {\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\n if (!success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(result);\n }\n }\n }\n\n /// @notice Perform a batched call to this contract, preserving the msg.sender.\n /// The return data from each call is preserved.\n /// @dev The method is non-payable, so only calls with `msg.value == 0` could be batched.\n /// It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag.\n /// Otherwise, the whole batch call will be reverted with the original revert reason.\n /// @param data List of abi-encoded calldata for the calls to perform.\n /// @param ignoreReverts Whether to ignore the revert errors from the calls.\n /// @return results List of results from the calls: `(success, returnData)`.\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results)\n {\n results = new Result[](data.length);\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (results[i].success, results[i].returnData) = address(this).delegatecall(data[i]);\n if (!results[i].success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(results[i].returnData);\n }\n }\n }\n\n /// @dev Bubbles the revert message from the underlying call.\n /// Note: preserves the same custom error or revert string, if one was used.\n /// Source: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v5.0.2/contracts/utils/Address.sol#L143-L158\n function _bubbleRevert(bytes memory returnData) internal pure {\n // Look for revert reason and bubble it up if present\n if (returnData.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n // solhint-disable-next-line no-inline-assembly\n assembly {\n let returndata_size := mload(returnData)\n revert(add(32, returnData), returndata_size)\n }\n } else {\n revert MulticallTarget__UndeterminedRevert();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// contracts/libs/BridgeTransactionV2.sol\n\n// solhint-disable no-inline-assembly\nlibrary BridgeTransactionV2Lib {\n uint16 internal constant VERSION = 2;\n\n // Offsets of the fields in the packed BridgeTransactionV2 struct\n // uint16 version [000 .. 002)\n // uint32 originChainId [002 .. 006)\n // uint32 destChainId [006 .. 010)\n // address originSender [010 .. 030)\n // address destRecipient [030 .. 050)\n // address originToken [050 .. 070)\n // address destToken [070 .. 090)\n // uint256 originAmount [090 .. 122)\n // uint256 destAmount [122 .. 154)\n // uint256 originFeeAmount [154 .. 186)\n // uint256 deadline [186 .. 218)\n // uint256 nonce [218 .. 250)\n // address exclusivityRelayer [250 .. 270)\n // uint256 exclusivityEndTime [270 .. 302)\n // uint256 zapNative [302 .. 334)\n // bytes zapData [334 .. ***)\n\n // forgefmt: disable-start\n uint256 private constant OFFSET_ORIGIN_CHAIN_ID = 2;\n uint256 private constant OFFSET_DEST_CHAIN_ID = 6;\n uint256 private constant OFFSET_ORIGIN_SENDER = 10;\n uint256 private constant OFFSET_DEST_RECIPIENT = 30;\n uint256 private constant OFFSET_ORIGIN_TOKEN = 50;\n uint256 private constant OFFSET_DEST_TOKEN = 70;\n uint256 private constant OFFSET_ORIGIN_AMOUNT = 90;\n uint256 private constant OFFSET_DEST_AMOUNT = 122;\n uint256 private constant OFFSET_ORIGIN_FEE_AMOUNT = 154;\n uint256 private constant OFFSET_DEADLINE = 186;\n uint256 private constant OFFSET_NONCE = 218;\n uint256 private constant OFFSET_EXCLUSIVITY_RELAYER = 250;\n uint256 private constant OFFSET_EXCLUSIVITY_END_TIME = 270;\n uint256 private constant OFFSET_ZAP_NATIVE = 302;\n uint256 private constant OFFSET_ZAP_DATA = 334;\n // forgefmt: disable-end\n\n error BridgeTransactionV2__InvalidEncodedTx();\n error BridgeTransactionV2__UnsupportedVersion(uint16 version);\n\n /// @notice Validates the encoded transaction to be a tightly packed encoded payload for BridgeTransactionV2.\n /// @dev Checks the minimum length and the version, use this function before decoding any of the fields.\n function validateV2(bytes calldata encodedTx) internal pure {\n // Check the minimum length: must at least include all static fields.\n if (encodedTx.length \u003c OFFSET_ZAP_DATA) revert BridgeTransactionV2__InvalidEncodedTx();\n // Once we validated the length, we can be sure that the version field is present.\n uint16 version_ = version(encodedTx);\n if (version_ != VERSION) revert BridgeTransactionV2__UnsupportedVersion(version_);\n }\n\n /// @notice Encodes the BridgeTransactionV2 struct by tightly packing the fields.\n /// @dev `abi.decode` will not work as a result of the tightly packed fields. Use `decodeV2` to decode instead.\n function encodeV2(IFastBridgeV2.BridgeTransactionV2 memory bridgeTx) internal pure returns (bytes memory) {\n // We split the encoding into two parts to avoid stack-too-deep error\n bytes memory firstPart = abi.encodePacked(\n VERSION,\n bridgeTx.originChainId,\n bridgeTx.destChainId,\n bridgeTx.originSender,\n bridgeTx.destRecipient,\n bridgeTx.originToken,\n bridgeTx.destToken,\n bridgeTx.originAmount\n );\n return abi.encodePacked(\n firstPart,\n bridgeTx.destAmount,\n bridgeTx.originFeeAmount,\n // Note: we skip the deprecated `sendChainGas` flag, which was present in BridgeTransaction V1\n bridgeTx.deadline,\n bridgeTx.nonce,\n // New V2 fields: exclusivity\n bridgeTx.exclusivityRelayer,\n bridgeTx.exclusivityEndTime,\n // New V2 fields: Zap\n bridgeTx.zapNative,\n bridgeTx.zapData\n );\n }\n\n /// @notice Decodes the BridgeTransactionV2 struct from the encoded transaction.\n /// @dev Encoded BridgeTransactionV2 struct must be tightly packed.\n /// Use `validateV2` before decoding to ensure the encoded transaction is valid.\n function decodeV2(bytes calldata encodedTx)\n internal\n pure\n returns (IFastBridgeV2.BridgeTransactionV2 memory bridgeTx)\n {\n bridgeTx.originChainId = originChainId(encodedTx);\n bridgeTx.destChainId = destChainId(encodedTx);\n bridgeTx.originSender = originSender(encodedTx);\n bridgeTx.destRecipient = destRecipient(encodedTx);\n bridgeTx.originToken = originToken(encodedTx);\n bridgeTx.destToken = destToken(encodedTx);\n bridgeTx.originAmount = originAmount(encodedTx);\n bridgeTx.destAmount = destAmount(encodedTx);\n bridgeTx.originFeeAmount = originFeeAmount(encodedTx);\n bridgeTx.deadline = deadline(encodedTx);\n bridgeTx.nonce = nonce(encodedTx);\n bridgeTx.exclusivityRelayer = exclusivityRelayer(encodedTx);\n bridgeTx.exclusivityEndTime = exclusivityEndTime(encodedTx);\n bridgeTx.zapNative = zapNative(encodedTx);\n bridgeTx.zapData = zapData(encodedTx);\n }\n\n /// @notice Extracts the version from the encoded transaction.\n function version(bytes calldata encodedTx) internal pure returns (uint16 version_) {\n // Load 32 bytes from the start and shift it 240 bits to the right to get the highest 16 bits.\n assembly {\n version_ := shr(240, calldataload(encodedTx.offset))\n }\n }\n\n /// @notice Extracts the origin chain ID from the encoded transaction.\n function originChainId(bytes calldata encodedTx) internal pure returns (uint32 originChainId_) {\n // Load 32 bytes from the offset and shift it 224 bits to the right to get the highest 32 bits.\n assembly {\n originChainId_ := shr(224, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_CHAIN_ID)))\n }\n }\n\n /// @notice Extracts the destination chain ID from the encoded transaction.\n function destChainId(bytes calldata encodedTx) internal pure returns (uint32 destChainId_) {\n // Load 32 bytes from the offset and shift it 224 bits to the right to get the highest 32 bits.\n assembly {\n destChainId_ := shr(224, calldataload(add(encodedTx.offset, OFFSET_DEST_CHAIN_ID)))\n }\n }\n\n /// @notice Extracts the origin sender from the encoded transaction.\n function originSender(bytes calldata encodedTx) internal pure returns (address originSender_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n originSender_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_SENDER)))\n }\n }\n\n /// @notice Extracts the destination recipient from the encoded transaction.\n function destRecipient(bytes calldata encodedTx) internal pure returns (address destRecipient_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n destRecipient_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_DEST_RECIPIENT)))\n }\n }\n\n /// @notice Extracts the origin token from the encoded transaction.\n function originToken(bytes calldata encodedTx) internal pure returns (address originToken_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n originToken_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_TOKEN)))\n }\n }\n\n /// @notice Extracts the destination token from the encoded transaction.\n function destToken(bytes calldata encodedTx) internal pure returns (address destToken_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n destToken_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_DEST_TOKEN)))\n }\n }\n\n /// @notice Extracts the origin amount from the encoded transaction.\n function originAmount(bytes calldata encodedTx) internal pure returns (uint256 originAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n originAmount_ := calldataload(add(encodedTx.offset, OFFSET_ORIGIN_AMOUNT))\n }\n }\n\n /// @notice Extracts the destination amount from the encoded transaction.\n function destAmount(bytes calldata encodedTx) internal pure returns (uint256 destAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n destAmount_ := calldataload(add(encodedTx.offset, OFFSET_DEST_AMOUNT))\n }\n }\n\n /// @notice Extracts the origin fee amount from the encoded transaction.\n function originFeeAmount(bytes calldata encodedTx) internal pure returns (uint256 originFeeAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n originFeeAmount_ := calldataload(add(encodedTx.offset, OFFSET_ORIGIN_FEE_AMOUNT))\n }\n }\n\n /// @notice Extracts the deadline from the encoded transaction.\n function deadline(bytes calldata encodedTx) internal pure returns (uint256 deadline_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n deadline_ := calldataload(add(encodedTx.offset, OFFSET_DEADLINE))\n }\n }\n\n /// @notice Extracts the nonce from the encoded transaction.\n function nonce(bytes calldata encodedTx) internal pure returns (uint256 nonce_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n nonce_ := calldataload(add(encodedTx.offset, OFFSET_NONCE))\n }\n }\n\n /// @notice Extracts the exclusivity relayer from the encoded transaction.\n function exclusivityRelayer(bytes calldata encodedTx) internal pure returns (address exclusivityRelayer_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n exclusivityRelayer_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_EXCLUSIVITY_RELAYER)))\n }\n }\n\n /// @notice Extracts the exclusivity end time from the encoded transaction.\n function exclusivityEndTime(bytes calldata encodedTx) internal pure returns (uint256 exclusivityEndTime_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n exclusivityEndTime_ := calldataload(add(encodedTx.offset, OFFSET_EXCLUSIVITY_END_TIME))\n }\n }\n\n /// @notice Extracts the Zap's native value from the encoded transaction.\n function zapNative(bytes calldata encodedTx) internal pure returns (uint256 zapNative_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n zapNative_ := calldataload(add(encodedTx.offset, OFFSET_ZAP_NATIVE))\n }\n }\n\n /// @notice Extracts the Zap's data from the encoded transaction.\n function zapData(bytes calldata encodedTx) internal pure returns (bytes calldata zapData_) {\n zapData_ = encodedTx[OFFSET_ZAP_DATA:];\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/AdminV2.sol\n\ncontract AdminV2 is AccessControlEnumerable, IAdminV2, IAdminV2Errors {\n using SafeERC20 for IERC20;\n\n /// @notice Address reserved for native gas token (ETH on Ethereum and most L2s, AVAX on Avalanche, etc)\n address public constant NATIVE_GAS_TOKEN = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Role identifier for Quoter API's off-chain authentication.\n /// @dev Only addresses with this role can post FastBridge quotes to the API.\n bytes32 public constant QUOTER_ROLE = keccak256(\"QUOTER_ROLE\");\n\n /// @notice Role identifier for Prover's on-chain authentication in FastBridge.\n /// @dev Only addresses with this role can provide proofs that a FastBridge request has been relayed.\n bytes32 public constant PROVER_ROLE = keccak256(\"PROVER_ROLE\");\n\n /// @notice Role identifier for Guard's on-chain authentication in FastBridge.\n /// @dev Only addresses with this role can dispute submitted relay proofs during the dispute period.\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n\n /// @notice Role identifier for Canceler's on-chain authentication in FastBridge.\n /// @dev Only addresses with this role can cancel a FastBridge transaction without the cancel delay.\n bytes32 public constant CANCELER_ROLE = keccak256(\"CANCELER_ROLE\");\n\n /// @notice Role identifier for Governor's on-chain administrative authority.\n /// @dev Only addresses with this role can perform administrative tasks within the contract.\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n /// @notice Denominator for fee rates, represents 100%.\n uint256 public constant FEE_BPS = 1e6;\n /// @notice Maximum protocol fee rate: 1% on origin amount.\n uint256 public constant FEE_RATE_MAX = 0.01e6;\n\n /// @notice Minimum cancel delay that can be set by the governor.\n uint256 public constant MIN_CANCEL_DELAY = 1 hours;\n /// @notice Default cancel delay set during the contract deployment.\n uint256 public constant DEFAULT_CANCEL_DELAY = 1 days;\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Delay for a transaction after which it could be permisionlessly cancelled\n uint256 public cancelDelay;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Use ZapNative V2 requests instead.\n uint256 public immutable chainGasAmount = 0;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n _setCancelDelay(DEFAULT_CANCEL_DELAY);\n }\n\n /// @notice Allows the contract governor to set the cancel delay. The cancel delay is the time after the transaction\n /// deadline after which it can be permissionlessly cancelled, if it hasn't been proven by any of the Relayers.\n function setCancelDelay(uint256 newCancelDelay) external onlyRole(GOVERNOR_ROLE) {\n _setCancelDelay(newCancelDelay);\n }\n\n /// @notice Allows the contract governor to set the protocol fee rate. The protocol fee is taken from the origin\n /// amount only for completed and claimed transactions.\n /// @dev The protocol fee is abstracted away from the relayers, they always operate using the amounts after fees:\n /// what they see as the origin amount emitted in the log is what they get credited with.\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n if (newFeeRate \u003e FEE_RATE_MAX) revert FeeRateAboveMax();\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n /// @notice Allows the contract governor to sweep the accumulated protocol fees in the contract.\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n emit FeesSwept(token, recipient, feeAmount);\n /// Sweep the fees as the last transaction action\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(recipient), feeAmount);\n } else {\n IERC20(token).safeTransfer(recipient, feeAmount);\n }\n }\n\n /// @notice Internal function to set the cancel delay. Security checks are performed outside of this function.\n function _setCancelDelay(uint256 newCancelDelay) private {\n if (newCancelDelay \u003c MIN_CANCEL_DELAY) revert CancelDelayBelowMin();\n uint256 oldCancelDelay = cancelDelay;\n cancelDelay = newCancelDelay;\n emit CancelDelayUpdated(oldCancelDelay, newCancelDelay);\n }\n}\n\n// contracts/FastBridgeV2.sol\n\n/// @notice FastBridgeV2 is a contract for bridging tokens across chains.\ncontract FastBridgeV2 is AdminV2, MulticallTarget, IFastBridgeV2, IFastBridgeV2Errors {\n using BridgeTransactionV2Lib for bytes;\n using SafeERC20 for IERC20;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n /// @notice Maximum length of accepted zapData\n uint256 public constant MAX_ZAP_DATA_LENGTH = 2 ** 16 - 1;\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeTxDetails) public bridgeTxDetails;\n /// @notice Relay details on destination chain\n mapping(bytes32 =\u003e BridgeRelay) public bridgeRelayDetails;\n /// @notice Unique bridge nonces tracked per originSender\n mapping(address =\u003e uint256) public senderNonces;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Replaced by senderNonces\n uint256 public immutable nonce = 0;\n /// @notice the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) AdminV2(_owner) {\n deployBlock = block.number;\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n bridge({\n params: params,\n paramsV2: BridgeParamsV2({\n quoteRelayer: address(0),\n quoteExclusivitySeconds: 0,\n quoteId: bytes(\"\"),\n zapNative: 0,\n zapData: bytes(\"\")\n })\n });\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes calldata request) external payable {\n // relay override will validate the request\n relay({request: request, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes calldata request, bytes32 destTxHash) external {\n request.validateV2();\n prove({transactionId: keccak256(request), destTxHash: destTxHash, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridgeV2\n function claim(bytes calldata request) external {\n // claim override will validate the request\n claim({request: request, to: address(0)});\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Aggregate the read operations from the same storage slot\n address disputedRelayer = $.proofRelayer;\n BridgeStatus status = $.status;\n uint56 proofBlockTimestamp = $.proofBlockTimestamp;\n // Can only dispute a RELAYER_PROVED transaction within the dispute period\n if (status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(proofBlockTimestamp) \u003e DISPUTE_PERIOD) {\n revert DisputePeriodPassed();\n }\n // Update status to REQUESTED and delete the disputed proof details\n // Note: these are storage writes\n $.status = BridgeStatus.REQUESTED;\n $.proofRelayer = address(0);\n $.proofBlockTimestamp = 0;\n\n emit BridgeProofDisputed(transactionId, disputedRelayer);\n }\n\n /// Note: this function is deprecated and will be removed in a future version.\n /// @inheritdoc IFastBridge\n function refund(bytes calldata request) external {\n cancel(request);\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // The correct relayer can only claim a RELAYER_PROVED transaction after the dispute period\n if ($.status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if ($.proofRelayer != relayer) revert SenderIncorrect();\n return _timeSince($.proofBlockTimestamp) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n /// @dev This method is added to achieve backwards compatibility with decoding requests into V1 structs:\n /// - `zapNative` is partially reported as a zero/non-zero flag\n /// - `zapData` is ignored\n /// In order to process all kinds of requests use getBridgeTransactionV2 instead.\n function getBridgeTransaction(bytes calldata request) external view returns (BridgeTransaction memory) {\n // Try decoding into V2 struct first. This will revert if V1 struct is passed\n try this.getBridgeTransactionV2(request) returns (BridgeTransactionV2 memory txV2) {\n // Note: we entirely ignore the zapData field, as it was not present in V1\n return BridgeTransaction({\n originChainId: txV2.originChainId,\n destChainId: txV2.destChainId,\n originSender: txV2.originSender,\n destRecipient: txV2.destRecipient,\n originToken: txV2.originToken,\n destToken: txV2.destToken,\n originAmount: txV2.originAmount,\n destAmount: txV2.destAmount,\n originFeeAmount: txV2.originFeeAmount,\n sendChainGas: txV2.zapNative != 0,\n deadline: txV2.deadline,\n nonce: txV2.nonce\n });\n } catch {\n // Fallback to V1 struct\n return abi.decode(request, (BridgeTransaction));\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function getBridgeTransactionV2(bytes calldata request) external pure returns (BridgeTransactionV2 memory) {\n request.validateV2();\n return BridgeTransactionV2Lib.decodeV2(request);\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) public payable {\n int256 exclusivityEndTime = 0;\n // if relayer exclusivity is not intended for this bridge, set exclusivityEndTime to static zero\n // otherwise, set exclusivity to expire at the current block ts offset by quoteExclusivitySeconds\n if (paramsV2.quoteRelayer != address(0)) {\n exclusivityEndTime = int256(block.timestamp) + paramsV2.quoteExclusivitySeconds;\n }\n _validateBridgeParams(params, paramsV2, exclusivityEndTime);\n\n // transfer tokens to bridge contract\n /// @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _takeBridgedUserAsset(params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) {\n originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n }\n\n // set status to requested\n bytes memory request = BridgeTransactionV2Lib.encodeV2(\n BridgeTransactionV2({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n deadline: params.deadline,\n nonce: senderNonces[params.sender]++, // increment nonce on every bridge\n exclusivityRelayer: paramsV2.quoteRelayer,\n // We checked exclusivityEndTime to be in range [0 .. params.deadline] above, so can safely cast\n exclusivityEndTime: uint256(exclusivityEndTime),\n zapNative: paramsV2.zapNative,\n zapData: paramsV2.zapData\n })\n );\n bytes32 transactionId = keccak256(request);\n // Note: the tx status will be updated throughout the tx lifecycle, while destChainId is set once here\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n bridgeTxDetails[transactionId].destChainId = params.dstChainId;\n\n emit BridgeRequested({\n transactionId: transactionId,\n sender: params.sender,\n request: request,\n destChainId: params.dstChainId,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n sendChainGas: paramsV2.zapNative != 0\n });\n emit BridgeQuoteDetails(transactionId, paramsV2.quoteId);\n }\n\n /// @inheritdoc IFastBridgeV2\n function relay(bytes calldata request, address relayer) public payable {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n _validateRelayParams(request, transactionId, relayer);\n // mark bridge transaction as relayed\n bridgeRelayDetails[transactionId] =\n BridgeRelay({blockNumber: uint48(block.number), blockTimestamp: uint48(block.timestamp), relayer: relayer});\n\n // transfer tokens to recipient on destination chain and trigger Zap if requested\n address to = request.destRecipient();\n address token = request.destToken();\n uint256 amount = request.destAmount();\n uint256 zapNative = request.zapNative();\n\n // Emit the event before any external calls\n emit BridgeRelayed({\n transactionId: transactionId,\n relayer: relayer,\n to: to,\n originChainId: request.originChainId(),\n originToken: request.originToken(),\n destToken: token,\n originAmount: request.originAmount(),\n destAmount: amount,\n chainGasAmount: zapNative\n });\n\n // All state changes have been done at this point, can proceed to the external calls.\n // This follows the checks-effects-interactions pattern to mitigate potential reentrancy attacks.\n if (token == NATIVE_GAS_TOKEN) {\n // For the native gas token, additional zapNative is not allowed\n if (zapNative != 0) revert ZapNativeNotSupported();\n // Check that the correct msg.value was sent\n if (msg.value != amount) revert MsgValueIncorrect();\n // Don't do a native transfer yet: we will handle it alongside the Zap below\n } else {\n // For ERC20s, we check that the correct msg.value was sent\n if (msg.value != zapNative) revert MsgValueIncorrect();\n // We need to transfer the tokens from the Relayer to the recipient first before performing an\n // optional post-transfer Zap.\n IERC20(token).safeTransferFrom(msg.sender, to, amount);\n }\n // At this point we have done:\n // - Transferred the requested amount of ERC20 tokens to the recipient.\n // At this point we have confirmed:\n // - For ERC20s: msg.value matches the requested zapNative amount.\n // - For the native gas token: msg.value matches the requested destAmount.\n // Remaining optional things to do:\n // - Forward the full msg.value to the recipient (if non-zero).\n // - Trigger a Zap (if zapData is present).\n bytes calldata zapData = request.zapData();\n if (zapData.length != 0) {\n // Zap Data is present: Zap has been requested by the recipient. Trigger it forwarding the full msg.value.\n\n // Note: if token has a fee on transfers, the recipient will have received less than `amount`.\n // This is a very niche edge case and should be handled by the recipient contract.\n _triggerZapWithChecks({recipient: to, token: token, amount: amount, zapData: zapData});\n } else if (msg.value != 0) {\n // Zap Data is missing, but msg.value was sent. This could happen in two different cases:\n // - Relay with the native gas token is happening.\n // - Relay with ERC20 is happening, with a `zapNative \u003e 0` request.\n // In both cases, we need to transfer the full msg.value to the recipient.\n Address.sendValue(payable(to), msg.value);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) public onlyRole(PROVER_ROLE) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n\n // Can only prove a REQUESTED transaction\n if ($.status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n // Update status to RELAYER_PROVED and store the proof details\n // Note: these are storage writes\n $.status = BridgeStatus.RELAYER_PROVED;\n $.proofBlockTimestamp = uint56(block.timestamp);\n $.proofRelayer = relayer;\n\n emit BridgeProofProvided(transactionId, relayer, destTxHash);\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes calldata request, address to) public {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Aggregate the read operations from the same storage slot\n address proofRelayer = $.proofRelayer;\n BridgeStatus status = $.status;\n uint56 proofBlockTimestamp = $.proofBlockTimestamp;\n\n // Can only claim a RELAYER_PROVED transaction after the dispute period\n if (status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(proofBlockTimestamp) \u003c= DISPUTE_PERIOD) {\n revert DisputePeriodNotPassed();\n }\n\n if (to == address(0)) {\n // Anyone could claim the funds to the proven relayer on their behalf\n to = proofRelayer;\n } else if (proofRelayer != msg.sender) {\n // Only the proven relayer could specify an address to claim the funds to\n revert SenderIncorrect();\n }\n\n // Update status to RELAYER_CLAIMED and transfer the origin collateral to the specified claim address\n // Note: this is a storage write\n $.status = BridgeStatus.RELAYER_CLAIMED;\n\n address token = request.originToken();\n uint256 amount = request.originAmount();\n // Update protocol fees if origin fee amount exists\n uint256 originFeeAmount = request.originFeeAmount();\n if (originFeeAmount \u003e 0) protocolFees[token] += originFeeAmount;\n // Emit the event before any external calls\n emit BridgeDepositClaimed(transactionId, proofRelayer, to, token, amount);\n // Complete the relayer claim as the last transaction action\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(to), amount);\n } else {\n IERC20(token).safeTransfer(to, amount);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function cancel(bytes calldata request) public {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Can only cancel a REQUESTED transaction after its deadline expires\n if ($.status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n uint256 deadline = request.deadline();\n // Permissionless cancel is only allowed after `cancelDelay` on top of the deadline\n if (!hasRole(CANCELER_ROLE, msg.sender)) deadline += cancelDelay;\n if (block.timestamp \u003c= deadline) revert DeadlineNotExceeded();\n // Update status to REFUNDED and return the full amount (collateral + protocol fees) to the original sender.\n // The protocol fees are only updated when the transaction is claimed, so we don't need to update them here.\n // Note: this is a storage write\n $.status = BridgeStatus.REFUNDED;\n\n address to = request.originSender();\n address token = request.originToken();\n uint256 amount = request.originAmount() + request.originFeeAmount();\n // Emit the event before any external calls\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n // Complete the user cancel as the last transaction action\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(to), amount);\n } else {\n IERC20(token).safeTransfer(to, amount);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeStatuses(bytes32 transactionId) public view returns (BridgeStatus status) {\n return bridgeTxDetails[transactionId].status;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeProofs(bytes32 transactionId) public view returns (uint96 timestamp, address relayer) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n\n timestamp = $.proofBlockTimestamp;\n relayer = $.proofRelayer;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeRelays(bytes32 transactionId) public view returns (bool) {\n // has this transactionId been relayed?\n return bridgeRelayDetails[transactionId].relayer != address(0);\n }\n\n /// @notice Takes the bridged asset from the user into FastBridgeV2 custody. It will be later\n /// claimed by the relayer who completed the relay on destination chain, or transferred back to the user\n /// via the cancel function should no one complete the relay.\n function _takeBridgedUserAsset(address token, uint256 amount) internal returns (uint256 amountTaken) {\n if (token == NATIVE_GAS_TOKEN) {\n // For the native gas token, we just need to check that the supplied msg.value is correct.\n // Supplied `msg.value` is already in FastBridgeV2 custody.\n if (amount != msg.value) revert MsgValueIncorrect();\n amountTaken = msg.value;\n } else {\n // For ERC20s, token is explicitly transferred from the user to FastBridgeV2.\n // We don't allow non-zero `msg.value` to avoid extra funds from being stuck in FastBridgeV2.\n if (msg.value != 0) revert MsgValueIncorrect();\n // Throw an explicit error if the provided token address is not a contract\n if (token.code.length == 0) revert TokenNotContract();\n amountTaken = IERC20(token).balanceOf(address(this));\n IERC20(token).safeTransferFrom(msg.sender, address(this), amount);\n // Use the balance difference as the amount taken in case of fee on transfer tokens.\n amountTaken = IERC20(token).balanceOf(address(this)) - amountTaken;\n }\n }\n\n /// @notice Calls the Recipient's hook function with the specified zapData and performs\n /// all the necessary checks for the returned value.\n function _triggerZapWithChecks(address recipient, address token, uint256 amount, bytes calldata zapData) internal {\n // This will bubble any revert messages from the hook function\n bytes memory returnData = Address.functionCallWithValue({\n target: recipient,\n data: abi.encodeCall(IZapRecipient.zap, (token, amount, zapData)),\n // Note: see `relay()` for reasoning behind passing msg.value\n value: msg.value\n });\n // Explicit revert if no return data at all\n if (returnData.length == 0) revert RecipientNoReturnValue();\n // Check that exactly a single return value was returned\n if (returnData.length != 32) revert RecipientIncorrectReturnValue();\n // Return value should be abi-encoded hook function selector\n if (bytes32(returnData) != bytes32(IZapRecipient.zap.selector)) {\n revert RecipientIncorrectReturnValue();\n }\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint56(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint56).max but\n /// proof.timestamp \u003c type(uint56).max via unchecked statement\n /// @param proofBlockTimestamp The bridge proof block timestamp\n /// @return delta Time delta since proof submitted\n function _timeSince(uint56 proofBlockTimestamp) internal view returns (uint256 delta) {\n unchecked {\n delta = uint56(block.timestamp) - proofBlockTimestamp;\n }\n }\n\n /// @notice Performs all the necessary checks for a bridge to happen.\n /// @dev There's no good way to refactor this function to reduce cyclomatic complexity due to\n /// the number of checks that need to be performed, so we skip the code-complexity rule here.\n // solhint-disable-next-line code-complexity\n function _validateBridgeParams(\n BridgeParams memory params,\n BridgeParamsV2 memory paramsV2,\n int256 exclusivityEndTime\n )\n internal\n view\n {\n // Check V1 (legacy) params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.sender == address(0) || params.to == address(0)) revert ZeroAddress();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n // Check V2 params\n if (paramsV2.zapData.length \u003e MAX_ZAP_DATA_LENGTH) revert ZapDataLengthAboveMax();\n if (paramsV2.zapNative != 0 \u0026\u0026 params.destToken == NATIVE_GAS_TOKEN) {\n revert ZapNativeNotSupported();\n }\n // exclusivityEndTime must be in range [0 .. params.deadline]\n if (exclusivityEndTime \u003c 0 || exclusivityEndTime \u003e int256(params.deadline)) {\n revert ExclusivityParamsIncorrect();\n }\n }\n\n /// @notice Performs all the necessary checks for a relay to happen.\n function _validateRelayParams(bytes calldata request, bytes32 transactionId, address relayer) internal view {\n if (relayer == address(0)) revert ZeroAddress();\n // Check if the transaction has already been relayed\n if (bridgeRelays(transactionId)) revert TransactionRelayed();\n if (request.destChainId() != block.chainid) revert ChainIncorrect();\n // Check the deadline for relay to happen\n if (block.timestamp \u003e request.deadline()) revert DeadlineExceeded();\n // Check the exclusivity period, if it is still ongoing\n address exclRelayer = request.exclusivityRelayer();\n if (exclRelayer != address(0) \u0026\u0026 exclRelayer != relayer \u0026\u0026 block.timestamp \u003c= request.exclusivityEndTime()) {\n revert ExclusivityPeriodNotPassed();\n }\n }\n}\n","language":"Solidity","languageVersion":"0.8.24","compilerVersion":"0.8.24","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"","srcMapRuntime":"","abiDefinition":[{"inputs":[],"name":"AccessControlBadConfirmation","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"bytes32","name":"neededRole","type":"bytes32"}],"name":"AccessControlUnauthorizedAccount","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"previousAdminRole","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"newAdminRole","type":"bytes32"}],"name":"RoleAdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleRevoked","type":"event"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleAdmin","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"uint256","name":"index","type":"uint256"}],"name":"getRoleMember","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleMemberCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"grantRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"hasRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"callerConfirmation","type":"address"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"revokeRole","outputs":[],"stateMutability":"nonpayable","type":"function"}],"userDoc":{"kind":"user","methods":{},"version":1},"developerDoc":{"details":"External interface of AccessControlEnumerable declared to support ERC165 detection.","errors":{"AccessControlBadConfirmation()":[{"details":"The caller of a function is not the expected one. NOTE: Don't confuse with {AccessControlUnauthorizedAccount}."}],"AccessControlUnauthorizedAccount(address,bytes32)":[{"details":"The `account` is missing a role."}]},"events":{"RoleAdminChanged(bytes32,bytes32,bytes32)":{"details":"Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole` `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite {RoleAdminChanged} not being emitted signaling this."},"RoleGranted(bytes32,address,address)":{"details":"Emitted when `account` is granted `role`. `sender` is the account that originated the contract call, an admin role bearer except when using {AccessControl-_setupRole}."},"RoleRevoked(bytes32,address,address)":{"details":"Emitted when `account` is revoked `role`. `sender` is the account that originated the contract call: - if using `revokeRole`, it is the admin role bearer - if using `renounceRole`, it is the role bearer (i.e. `account`)"}},"kind":"dev","methods":{"getRoleAdmin(bytes32)":{"details":"Returns the admin role that controls `role`. See {grantRole} and {revokeRole}. To change a role's admin, use {AccessControl-_setRoleAdmin}."},"getRoleMember(bytes32,uint256)":{"details":"Returns one of the accounts that have `role`. `index` must be a value between 0 and {getRoleMemberCount}, non-inclusive. Role bearers are not sorted in any particular way, and their ordering may change at any point. WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure you perform all queries on the same block. See the following https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post] for more information."},"getRoleMemberCount(bytes32)":{"details":"Returns the number of accounts that have `role`. Can be used together with {getRoleMember} to enumerate all bearers of a role."},"grantRole(bytes32,address)":{"details":"Grants `role` to `account`. If `account` had not been already granted `role`, emits a {RoleGranted} event. Requirements: - the caller must have ``role``'s admin role."},"hasRole(bytes32,address)":{"details":"Returns `true` if `account` has been granted `role`."},"renounceRole(bytes32,address)":{"details":"Revokes `role` from the calling account. Roles are often managed via {grantRole} and {revokeRole}: this function's purpose is to provide a mechanism for accounts to lose their privileges if they are compromised (such as when a trusted device is misplaced). If the calling account had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must be `callerConfirmation`."},"revokeRole(bytes32,address)":{"details":"Revokes `role` from `account`. If `account` had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must have ``role``'s admin role."}},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[],\"name\":\"AccessControlBadConfirmation\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"neededRole\",\"type\":\"bytes32\"}],\"name\":\"AccessControlUnauthorizedAccount\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"previousAdminRole\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"newAdminRole\",\"type\":\"bytes32\"}],\"name\":\"RoleAdminChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleGranted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleRevoked\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"}],\"name\":\"getRoleAdmin\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"index\",\"type\":\"uint256\"}],\"name\":\"getRoleMember\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"}],\"name\":\"getRoleMemberCount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"grantRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"hasRole\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"callerConfirmation\",\"type\":\"address\"}],\"name\":\"renounceRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"revokeRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"details\":\"External interface of AccessControlEnumerable declared to support ERC165 detection.\",\"errors\":{\"AccessControlBadConfirmation()\":[{\"details\":\"The caller of a function is not the expected one. NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\"}],\"AccessControlUnauthorizedAccount(address,bytes32)\":[{\"details\":\"The `account` is missing a role.\"}]},\"events\":{\"RoleAdminChanged(bytes32,bytes32,bytes32)\":{\"details\":\"Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole` `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite {RoleAdminChanged} not being emitted signaling this.\"},\"RoleGranted(bytes32,address,address)\":{\"details\":\"Emitted when `account` is granted `role`. `sender` is the account that originated the contract call, an admin role bearer except when using {AccessControl-_setupRole}.\"},\"RoleRevoked(bytes32,address,address)\":{\"details\":\"Emitted when `account` is revoked `role`. `sender` is the account that originated the contract call: - if using `revokeRole`, it is the admin role bearer - if using `renounceRole`, it is the role bearer (i.e. `account`)\"}},\"kind\":\"dev\",\"methods\":{\"getRoleAdmin(bytes32)\":{\"details\":\"Returns the admin role that controls `role`. See {grantRole} and {revokeRole}. To change a role's admin, use {AccessControl-_setRoleAdmin}.\"},\"getRoleMember(bytes32,uint256)\":{\"details\":\"Returns one of the accounts that have `role`. `index` must be a value between 0 and {getRoleMemberCount}, non-inclusive. Role bearers are not sorted in any particular way, and their ordering may change at any point. WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure you perform all queries on the same block. See the following https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post] for more information.\"},\"getRoleMemberCount(bytes32)\":{\"details\":\"Returns the number of accounts that have `role`. Can be used together with {getRoleMember} to enumerate all bearers of a role.\"},\"grantRole(bytes32,address)\":{\"details\":\"Grants `role` to `account`. If `account` had not been already granted `role`, emits a {RoleGranted} event. Requirements: - the caller must have ``role``'s admin role.\"},\"hasRole(bytes32,address)\":{\"details\":\"Returns `true` if `account` has been granted `role`.\"},\"renounceRole(bytes32,address)\":{\"details\":\"Revokes `role` from the calling account. Roles are often managed via {grantRole} and {revokeRole}: this function's purpose is to provide a mechanism for accounts to lose their privileges if they are compromised (such as when a trusted device is misplaced). If the calling account had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must be `callerConfirmation`.\"},\"revokeRole(bytes32,address)\":{\"details\":\"Revokes `role` from `account`. If `account` had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must have ``role``'s admin role.\"}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeV2.sol\":\"IAccessControlEnumerable\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeV2.sol\":{\"keccak256\":\"0xac79c463688a682ca706a4ef95e7817b83548cdfa8182ba0426ac7e5e07613d8\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://b3ecb7097381287cafc3a73f3a2bb03565115ebb682a85064e0b0dc2f7e2919d\",\"dweb:/ipfs/QmatruW3nYZTksf3CeQ8wwiAG4c7xoEJBEp6drHPtFLBRK\"]}},\"version\":1}"},"hashes":{"getRoleAdmin(bytes32)":"248a9ca3","getRoleMember(bytes32,uint256)":"9010d07c","getRoleMemberCount(bytes32)":"ca15c873","grantRole(bytes32,address)":"2f2ff15d","hasRole(bytes32,address)":"91d14854","renounceRole(bytes32,address)":"36568abe","revokeRole(bytes32,address)":"d547741f"}},"solidity/FastBridgeV2.sol:IAdminV2":{"code":"0x","runtime-code":"0x","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.24 ^0.8.20 ^0.8.4;\n\n// contracts/interfaces/IAdminV2.sol\n\ninterface IAdminV2 {\n event CancelDelayUpdated(uint256 oldCancelDelay, uint256 newCancelDelay);\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n function setCancelDelay(uint256 newCancelDelay) external;\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n}\n\n// contracts/interfaces/IAdminV2Errors.sol\n\ninterface IAdminV2Errors {\n error CancelDelayBelowMin();\n error FeeRateAboveMax();\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IFastBridgeV2Errors.sol\n\ninterface IFastBridgeV2Errors {\n error AmountIncorrect();\n error ChainIncorrect();\n error ExclusivityParamsIncorrect();\n error MsgValueIncorrect();\n error SenderIncorrect();\n error StatusIncorrect();\n error TokenNotContract();\n error ZapDataLengthAboveMax();\n error ZapNativeNotSupported();\n error ZeroAddress();\n\n error RecipientIncorrectReturnValue();\n error RecipientNoReturnValue();\n\n error DeadlineExceeded();\n error DeadlineNotExceeded();\n error DeadlineTooShort();\n error DisputePeriodNotPassed();\n error DisputePeriodPassed();\n error ExclusivityPeriodNotPassed();\n\n error TransactionRelayed();\n}\n\n// contracts/interfaces/IMulticallTarget.sol\n\n/// @notice Interface for a contract that can be called multiple times by the same caller. Inspired by MulticallV3:\n/// https://github.com/mds1/multicall/blob/master/src/Multicall3.sol\ninterface IMulticallTarget {\n struct Result {\n bool success;\n bytes returnData;\n }\n\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external;\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results);\n}\n\n// contracts/interfaces/IZapRecipient.sol\n\ninterface IZapRecipient {\n function zap(address token, uint256 amount, bytes memory zapData) external payable returns (bytes4);\n}\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// contracts/interfaces/IFastBridgeV2.sol\n\ninterface IFastBridgeV2 is IFastBridge {\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n struct BridgeTxDetails {\n BridgeStatus status;\n uint32 destChainId;\n uint56 proofBlockTimestamp;\n address proofRelayer;\n }\n\n struct BridgeRelay {\n uint48 blockNumber;\n uint48 blockTimestamp;\n address relayer;\n }\n\n /// @notice New params introduced in the FastBridgeV2.\n /// We are passing fields from the older BridgeParams struct outside of this struct\n /// for backwards compatibility.\n /// Note: quoteRelayer and quoteExclusivitySeconds are either both zero (indicating no exclusivity)\n /// or both non-zero (indicating exclusivity for the given period).\n /// Note: zapNative \u003e 0 can NOT be used with destToken = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE (native token)\n /// @param quoteRelayer Relayer that provided the quote for the transaction\n /// @param quoteExclusivitySeconds Period of time the quote relayer is guaranteed exclusivity after user's deposit\n /// @param quoteId Unique quote identifier used for tracking the quote\n /// @param zapNative ETH value to send to the recipient (if any)\n /// @param zapData Parameters for the Zap to the destination recipient (if any)\n struct BridgeParamsV2 {\n address quoteRelayer;\n int256 quoteExclusivitySeconds;\n bytes quoteId;\n uint256 zapNative;\n bytes zapData;\n }\n\n /// @notice Updated bridge transaction struct to include parameters introduced in FastBridgeV2.\n /// Note: only `exclusivityRelayer` can fill such a transaction until `exclusivityEndTime`.\n struct BridgeTransactionV2 {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n // Note: sendChainGas flag from V1 is deprecated\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n address exclusivityRelayer;\n uint256 exclusivityEndTime;\n uint256 zapNative; // ETH value to send to the recipient (if any)\n bytes zapData; // data to pass for the Zap action (if any)\n }\n\n event BridgeQuoteDetails(bytes32 indexed transactionId, bytes quoteId);\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability\n /// to provide temporary exclusivity fill rights for the quote relayer.\n /// @param params The parameters required to bridge\n /// @param paramsV2 The parameters for exclusivity fill rights (optional, can be left empty)\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function relay(bytes memory request, address relayer) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param transactionId The transaction id associated with the encoded bridge transaction to prove\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital.\n /// @notice Can only send funds to the relayer address on the proof.\n /// @param request The encoded bridge transaction to claim on origin chain\n function claim(bytes memory request) external;\n\n /// @notice Cancels an outstanding bridge transaction in case optimistic bridging failed and returns the full amount\n /// to the original sender.\n /// @param request The encoded bridge transaction to refund\n function cancel(bytes memory request) external;\n\n /// @notice Checks if a transaction has been relayed\n /// @param transactionId The ID of the transaction to check\n /// @return True if the transaction has been relayed, false otherwise\n function bridgeRelays(bytes32 transactionId) external view returns (bool);\n\n /// @notice Returns the status of a bridge transaction\n /// @param transactionId The ID of the bridge transaction\n /// @return BridgeStatus Status of the bridge transaction\n function bridgeStatuses(bytes32 transactionId) external view returns (BridgeStatus);\n\n /// @notice Returns the timestamp and relayer of a bridge proof\n /// @param transactionId The ID of the bridge transaction\n /// @return timestamp The timestamp of the bridge proof\n /// @return relayer The relayer address of the bridge proof\n function bridgeProofs(bytes32 transactionId) external view returns (uint96 timestamp, address relayer);\n\n /// @notice Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\n /// @param request The bridge request to decode\n function getBridgeTransactionV2(bytes memory request) external view returns (BridgeTransactionV2 memory);\n}\n\n// contracts/utils/MulticallTarget.sol\n\n// solhint-disable avoid-low-level-calls\n/// @notice Template for a contract that supports batched calls (preserving the msg.sender).\n/// Only calls with zero msg.value could be batched.\nabstract contract MulticallTarget is IMulticallTarget {\n error MulticallTarget__UndeterminedRevert();\n\n /// @notice Perform a batched call to this contract, preserving the msg.sender.\n /// The return data from each call is discarded.\n /// @dev The method is non-payable, so only calls with `msg.value == 0` could be batched.\n /// It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag.\n /// Otherwise, the whole batch call will be reverted with the original revert reason.\n /// @param data List of abi-encoded calldata for the calls to perform.\n /// @param ignoreReverts Whether to ignore the revert errors from the calls.\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external {\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\n if (!success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(result);\n }\n }\n }\n\n /// @notice Perform a batched call to this contract, preserving the msg.sender.\n /// The return data from each call is preserved.\n /// @dev The method is non-payable, so only calls with `msg.value == 0` could be batched.\n /// It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag.\n /// Otherwise, the whole batch call will be reverted with the original revert reason.\n /// @param data List of abi-encoded calldata for the calls to perform.\n /// @param ignoreReverts Whether to ignore the revert errors from the calls.\n /// @return results List of results from the calls: `(success, returnData)`.\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results)\n {\n results = new Result[](data.length);\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (results[i].success, results[i].returnData) = address(this).delegatecall(data[i]);\n if (!results[i].success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(results[i].returnData);\n }\n }\n }\n\n /// @dev Bubbles the revert message from the underlying call.\n /// Note: preserves the same custom error or revert string, if one was used.\n /// Source: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v5.0.2/contracts/utils/Address.sol#L143-L158\n function _bubbleRevert(bytes memory returnData) internal pure {\n // Look for revert reason and bubble it up if present\n if (returnData.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n // solhint-disable-next-line no-inline-assembly\n assembly {\n let returndata_size := mload(returnData)\n revert(add(32, returnData), returndata_size)\n }\n } else {\n revert MulticallTarget__UndeterminedRevert();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// contracts/libs/BridgeTransactionV2.sol\n\n// solhint-disable no-inline-assembly\nlibrary BridgeTransactionV2Lib {\n uint16 internal constant VERSION = 2;\n\n // Offsets of the fields in the packed BridgeTransactionV2 struct\n // uint16 version [000 .. 002)\n // uint32 originChainId [002 .. 006)\n // uint32 destChainId [006 .. 010)\n // address originSender [010 .. 030)\n // address destRecipient [030 .. 050)\n // address originToken [050 .. 070)\n // address destToken [070 .. 090)\n // uint256 originAmount [090 .. 122)\n // uint256 destAmount [122 .. 154)\n // uint256 originFeeAmount [154 .. 186)\n // uint256 deadline [186 .. 218)\n // uint256 nonce [218 .. 250)\n // address exclusivityRelayer [250 .. 270)\n // uint256 exclusivityEndTime [270 .. 302)\n // uint256 zapNative [302 .. 334)\n // bytes zapData [334 .. ***)\n\n // forgefmt: disable-start\n uint256 private constant OFFSET_ORIGIN_CHAIN_ID = 2;\n uint256 private constant OFFSET_DEST_CHAIN_ID = 6;\n uint256 private constant OFFSET_ORIGIN_SENDER = 10;\n uint256 private constant OFFSET_DEST_RECIPIENT = 30;\n uint256 private constant OFFSET_ORIGIN_TOKEN = 50;\n uint256 private constant OFFSET_DEST_TOKEN = 70;\n uint256 private constant OFFSET_ORIGIN_AMOUNT = 90;\n uint256 private constant OFFSET_DEST_AMOUNT = 122;\n uint256 private constant OFFSET_ORIGIN_FEE_AMOUNT = 154;\n uint256 private constant OFFSET_DEADLINE = 186;\n uint256 private constant OFFSET_NONCE = 218;\n uint256 private constant OFFSET_EXCLUSIVITY_RELAYER = 250;\n uint256 private constant OFFSET_EXCLUSIVITY_END_TIME = 270;\n uint256 private constant OFFSET_ZAP_NATIVE = 302;\n uint256 private constant OFFSET_ZAP_DATA = 334;\n // forgefmt: disable-end\n\n error BridgeTransactionV2__InvalidEncodedTx();\n error BridgeTransactionV2__UnsupportedVersion(uint16 version);\n\n /// @notice Validates the encoded transaction to be a tightly packed encoded payload for BridgeTransactionV2.\n /// @dev Checks the minimum length and the version, use this function before decoding any of the fields.\n function validateV2(bytes calldata encodedTx) internal pure {\n // Check the minimum length: must at least include all static fields.\n if (encodedTx.length \u003c OFFSET_ZAP_DATA) revert BridgeTransactionV2__InvalidEncodedTx();\n // Once we validated the length, we can be sure that the version field is present.\n uint16 version_ = version(encodedTx);\n if (version_ != VERSION) revert BridgeTransactionV2__UnsupportedVersion(version_);\n }\n\n /// @notice Encodes the BridgeTransactionV2 struct by tightly packing the fields.\n /// @dev `abi.decode` will not work as a result of the tightly packed fields. Use `decodeV2` to decode instead.\n function encodeV2(IFastBridgeV2.BridgeTransactionV2 memory bridgeTx) internal pure returns (bytes memory) {\n // We split the encoding into two parts to avoid stack-too-deep error\n bytes memory firstPart = abi.encodePacked(\n VERSION,\n bridgeTx.originChainId,\n bridgeTx.destChainId,\n bridgeTx.originSender,\n bridgeTx.destRecipient,\n bridgeTx.originToken,\n bridgeTx.destToken,\n bridgeTx.originAmount\n );\n return abi.encodePacked(\n firstPart,\n bridgeTx.destAmount,\n bridgeTx.originFeeAmount,\n // Note: we skip the deprecated `sendChainGas` flag, which was present in BridgeTransaction V1\n bridgeTx.deadline,\n bridgeTx.nonce,\n // New V2 fields: exclusivity\n bridgeTx.exclusivityRelayer,\n bridgeTx.exclusivityEndTime,\n // New V2 fields: Zap\n bridgeTx.zapNative,\n bridgeTx.zapData\n );\n }\n\n /// @notice Decodes the BridgeTransactionV2 struct from the encoded transaction.\n /// @dev Encoded BridgeTransactionV2 struct must be tightly packed.\n /// Use `validateV2` before decoding to ensure the encoded transaction is valid.\n function decodeV2(bytes calldata encodedTx)\n internal\n pure\n returns (IFastBridgeV2.BridgeTransactionV2 memory bridgeTx)\n {\n bridgeTx.originChainId = originChainId(encodedTx);\n bridgeTx.destChainId = destChainId(encodedTx);\n bridgeTx.originSender = originSender(encodedTx);\n bridgeTx.destRecipient = destRecipient(encodedTx);\n bridgeTx.originToken = originToken(encodedTx);\n bridgeTx.destToken = destToken(encodedTx);\n bridgeTx.originAmount = originAmount(encodedTx);\n bridgeTx.destAmount = destAmount(encodedTx);\n bridgeTx.originFeeAmount = originFeeAmount(encodedTx);\n bridgeTx.deadline = deadline(encodedTx);\n bridgeTx.nonce = nonce(encodedTx);\n bridgeTx.exclusivityRelayer = exclusivityRelayer(encodedTx);\n bridgeTx.exclusivityEndTime = exclusivityEndTime(encodedTx);\n bridgeTx.zapNative = zapNative(encodedTx);\n bridgeTx.zapData = zapData(encodedTx);\n }\n\n /// @notice Extracts the version from the encoded transaction.\n function version(bytes calldata encodedTx) internal pure returns (uint16 version_) {\n // Load 32 bytes from the start and shift it 240 bits to the right to get the highest 16 bits.\n assembly {\n version_ := shr(240, calldataload(encodedTx.offset))\n }\n }\n\n /// @notice Extracts the origin chain ID from the encoded transaction.\n function originChainId(bytes calldata encodedTx) internal pure returns (uint32 originChainId_) {\n // Load 32 bytes from the offset and shift it 224 bits to the right to get the highest 32 bits.\n assembly {\n originChainId_ := shr(224, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_CHAIN_ID)))\n }\n }\n\n /// @notice Extracts the destination chain ID from the encoded transaction.\n function destChainId(bytes calldata encodedTx) internal pure returns (uint32 destChainId_) {\n // Load 32 bytes from the offset and shift it 224 bits to the right to get the highest 32 bits.\n assembly {\n destChainId_ := shr(224, calldataload(add(encodedTx.offset, OFFSET_DEST_CHAIN_ID)))\n }\n }\n\n /// @notice Extracts the origin sender from the encoded transaction.\n function originSender(bytes calldata encodedTx) internal pure returns (address originSender_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n originSender_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_SENDER)))\n }\n }\n\n /// @notice Extracts the destination recipient from the encoded transaction.\n function destRecipient(bytes calldata encodedTx) internal pure returns (address destRecipient_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n destRecipient_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_DEST_RECIPIENT)))\n }\n }\n\n /// @notice Extracts the origin token from the encoded transaction.\n function originToken(bytes calldata encodedTx) internal pure returns (address originToken_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n originToken_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_TOKEN)))\n }\n }\n\n /// @notice Extracts the destination token from the encoded transaction.\n function destToken(bytes calldata encodedTx) internal pure returns (address destToken_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n destToken_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_DEST_TOKEN)))\n }\n }\n\n /// @notice Extracts the origin amount from the encoded transaction.\n function originAmount(bytes calldata encodedTx) internal pure returns (uint256 originAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n originAmount_ := calldataload(add(encodedTx.offset, OFFSET_ORIGIN_AMOUNT))\n }\n }\n\n /// @notice Extracts the destination amount from the encoded transaction.\n function destAmount(bytes calldata encodedTx) internal pure returns (uint256 destAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n destAmount_ := calldataload(add(encodedTx.offset, OFFSET_DEST_AMOUNT))\n }\n }\n\n /// @notice Extracts the origin fee amount from the encoded transaction.\n function originFeeAmount(bytes calldata encodedTx) internal pure returns (uint256 originFeeAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n originFeeAmount_ := calldataload(add(encodedTx.offset, OFFSET_ORIGIN_FEE_AMOUNT))\n }\n }\n\n /// @notice Extracts the deadline from the encoded transaction.\n function deadline(bytes calldata encodedTx) internal pure returns (uint256 deadline_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n deadline_ := calldataload(add(encodedTx.offset, OFFSET_DEADLINE))\n }\n }\n\n /// @notice Extracts the nonce from the encoded transaction.\n function nonce(bytes calldata encodedTx) internal pure returns (uint256 nonce_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n nonce_ := calldataload(add(encodedTx.offset, OFFSET_NONCE))\n }\n }\n\n /// @notice Extracts the exclusivity relayer from the encoded transaction.\n function exclusivityRelayer(bytes calldata encodedTx) internal pure returns (address exclusivityRelayer_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n exclusivityRelayer_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_EXCLUSIVITY_RELAYER)))\n }\n }\n\n /// @notice Extracts the exclusivity end time from the encoded transaction.\n function exclusivityEndTime(bytes calldata encodedTx) internal pure returns (uint256 exclusivityEndTime_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n exclusivityEndTime_ := calldataload(add(encodedTx.offset, OFFSET_EXCLUSIVITY_END_TIME))\n }\n }\n\n /// @notice Extracts the Zap's native value from the encoded transaction.\n function zapNative(bytes calldata encodedTx) internal pure returns (uint256 zapNative_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n zapNative_ := calldataload(add(encodedTx.offset, OFFSET_ZAP_NATIVE))\n }\n }\n\n /// @notice Extracts the Zap's data from the encoded transaction.\n function zapData(bytes calldata encodedTx) internal pure returns (bytes calldata zapData_) {\n zapData_ = encodedTx[OFFSET_ZAP_DATA:];\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/AdminV2.sol\n\ncontract AdminV2 is AccessControlEnumerable, IAdminV2, IAdminV2Errors {\n using SafeERC20 for IERC20;\n\n /// @notice Address reserved for native gas token (ETH on Ethereum and most L2s, AVAX on Avalanche, etc)\n address public constant NATIVE_GAS_TOKEN = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Role identifier for Quoter API's off-chain authentication.\n /// @dev Only addresses with this role can post FastBridge quotes to the API.\n bytes32 public constant QUOTER_ROLE = keccak256(\"QUOTER_ROLE\");\n\n /// @notice Role identifier for Prover's on-chain authentication in FastBridge.\n /// @dev Only addresses with this role can provide proofs that a FastBridge request has been relayed.\n bytes32 public constant PROVER_ROLE = keccak256(\"PROVER_ROLE\");\n\n /// @notice Role identifier for Guard's on-chain authentication in FastBridge.\n /// @dev Only addresses with this role can dispute submitted relay proofs during the dispute period.\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n\n /// @notice Role identifier for Canceler's on-chain authentication in FastBridge.\n /// @dev Only addresses with this role can cancel a FastBridge transaction without the cancel delay.\n bytes32 public constant CANCELER_ROLE = keccak256(\"CANCELER_ROLE\");\n\n /// @notice Role identifier for Governor's on-chain administrative authority.\n /// @dev Only addresses with this role can perform administrative tasks within the contract.\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n /// @notice Denominator for fee rates, represents 100%.\n uint256 public constant FEE_BPS = 1e6;\n /// @notice Maximum protocol fee rate: 1% on origin amount.\n uint256 public constant FEE_RATE_MAX = 0.01e6;\n\n /// @notice Minimum cancel delay that can be set by the governor.\n uint256 public constant MIN_CANCEL_DELAY = 1 hours;\n /// @notice Default cancel delay set during the contract deployment.\n uint256 public constant DEFAULT_CANCEL_DELAY = 1 days;\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Delay for a transaction after which it could be permisionlessly cancelled\n uint256 public cancelDelay;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Use ZapNative V2 requests instead.\n uint256 public immutable chainGasAmount = 0;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n _setCancelDelay(DEFAULT_CANCEL_DELAY);\n }\n\n /// @notice Allows the contract governor to set the cancel delay. The cancel delay is the time after the transaction\n /// deadline after which it can be permissionlessly cancelled, if it hasn't been proven by any of the Relayers.\n function setCancelDelay(uint256 newCancelDelay) external onlyRole(GOVERNOR_ROLE) {\n _setCancelDelay(newCancelDelay);\n }\n\n /// @notice Allows the contract governor to set the protocol fee rate. The protocol fee is taken from the origin\n /// amount only for completed and claimed transactions.\n /// @dev The protocol fee is abstracted away from the relayers, they always operate using the amounts after fees:\n /// what they see as the origin amount emitted in the log is what they get credited with.\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n if (newFeeRate \u003e FEE_RATE_MAX) revert FeeRateAboveMax();\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n /// @notice Allows the contract governor to sweep the accumulated protocol fees in the contract.\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n emit FeesSwept(token, recipient, feeAmount);\n /// Sweep the fees as the last transaction action\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(recipient), feeAmount);\n } else {\n IERC20(token).safeTransfer(recipient, feeAmount);\n }\n }\n\n /// @notice Internal function to set the cancel delay. Security checks are performed outside of this function.\n function _setCancelDelay(uint256 newCancelDelay) private {\n if (newCancelDelay \u003c MIN_CANCEL_DELAY) revert CancelDelayBelowMin();\n uint256 oldCancelDelay = cancelDelay;\n cancelDelay = newCancelDelay;\n emit CancelDelayUpdated(oldCancelDelay, newCancelDelay);\n }\n}\n\n// contracts/FastBridgeV2.sol\n\n/// @notice FastBridgeV2 is a contract for bridging tokens across chains.\ncontract FastBridgeV2 is AdminV2, MulticallTarget, IFastBridgeV2, IFastBridgeV2Errors {\n using BridgeTransactionV2Lib for bytes;\n using SafeERC20 for IERC20;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n /// @notice Maximum length of accepted zapData\n uint256 public constant MAX_ZAP_DATA_LENGTH = 2 ** 16 - 1;\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeTxDetails) public bridgeTxDetails;\n /// @notice Relay details on destination chain\n mapping(bytes32 =\u003e BridgeRelay) public bridgeRelayDetails;\n /// @notice Unique bridge nonces tracked per originSender\n mapping(address =\u003e uint256) public senderNonces;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Replaced by senderNonces\n uint256 public immutable nonce = 0;\n /// @notice the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) AdminV2(_owner) {\n deployBlock = block.number;\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n bridge({\n params: params,\n paramsV2: BridgeParamsV2({\n quoteRelayer: address(0),\n quoteExclusivitySeconds: 0,\n quoteId: bytes(\"\"),\n zapNative: 0,\n zapData: bytes(\"\")\n })\n });\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes calldata request) external payable {\n // relay override will validate the request\n relay({request: request, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes calldata request, bytes32 destTxHash) external {\n request.validateV2();\n prove({transactionId: keccak256(request), destTxHash: destTxHash, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridgeV2\n function claim(bytes calldata request) external {\n // claim override will validate the request\n claim({request: request, to: address(0)});\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Aggregate the read operations from the same storage slot\n address disputedRelayer = $.proofRelayer;\n BridgeStatus status = $.status;\n uint56 proofBlockTimestamp = $.proofBlockTimestamp;\n // Can only dispute a RELAYER_PROVED transaction within the dispute period\n if (status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(proofBlockTimestamp) \u003e DISPUTE_PERIOD) {\n revert DisputePeriodPassed();\n }\n // Update status to REQUESTED and delete the disputed proof details\n // Note: these are storage writes\n $.status = BridgeStatus.REQUESTED;\n $.proofRelayer = address(0);\n $.proofBlockTimestamp = 0;\n\n emit BridgeProofDisputed(transactionId, disputedRelayer);\n }\n\n /// Note: this function is deprecated and will be removed in a future version.\n /// @inheritdoc IFastBridge\n function refund(bytes calldata request) external {\n cancel(request);\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // The correct relayer can only claim a RELAYER_PROVED transaction after the dispute period\n if ($.status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if ($.proofRelayer != relayer) revert SenderIncorrect();\n return _timeSince($.proofBlockTimestamp) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n /// @dev This method is added to achieve backwards compatibility with decoding requests into V1 structs:\n /// - `zapNative` is partially reported as a zero/non-zero flag\n /// - `zapData` is ignored\n /// In order to process all kinds of requests use getBridgeTransactionV2 instead.\n function getBridgeTransaction(bytes calldata request) external view returns (BridgeTransaction memory) {\n // Try decoding into V2 struct first. This will revert if V1 struct is passed\n try this.getBridgeTransactionV2(request) returns (BridgeTransactionV2 memory txV2) {\n // Note: we entirely ignore the zapData field, as it was not present in V1\n return BridgeTransaction({\n originChainId: txV2.originChainId,\n destChainId: txV2.destChainId,\n originSender: txV2.originSender,\n destRecipient: txV2.destRecipient,\n originToken: txV2.originToken,\n destToken: txV2.destToken,\n originAmount: txV2.originAmount,\n destAmount: txV2.destAmount,\n originFeeAmount: txV2.originFeeAmount,\n sendChainGas: txV2.zapNative != 0,\n deadline: txV2.deadline,\n nonce: txV2.nonce\n });\n } catch {\n // Fallback to V1 struct\n return abi.decode(request, (BridgeTransaction));\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function getBridgeTransactionV2(bytes calldata request) external pure returns (BridgeTransactionV2 memory) {\n request.validateV2();\n return BridgeTransactionV2Lib.decodeV2(request);\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) public payable {\n int256 exclusivityEndTime = 0;\n // if relayer exclusivity is not intended for this bridge, set exclusivityEndTime to static zero\n // otherwise, set exclusivity to expire at the current block ts offset by quoteExclusivitySeconds\n if (paramsV2.quoteRelayer != address(0)) {\n exclusivityEndTime = int256(block.timestamp) + paramsV2.quoteExclusivitySeconds;\n }\n _validateBridgeParams(params, paramsV2, exclusivityEndTime);\n\n // transfer tokens to bridge contract\n /// @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _takeBridgedUserAsset(params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) {\n originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n }\n\n // set status to requested\n bytes memory request = BridgeTransactionV2Lib.encodeV2(\n BridgeTransactionV2({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n deadline: params.deadline,\n nonce: senderNonces[params.sender]++, // increment nonce on every bridge\n exclusivityRelayer: paramsV2.quoteRelayer,\n // We checked exclusivityEndTime to be in range [0 .. params.deadline] above, so can safely cast\n exclusivityEndTime: uint256(exclusivityEndTime),\n zapNative: paramsV2.zapNative,\n zapData: paramsV2.zapData\n })\n );\n bytes32 transactionId = keccak256(request);\n // Note: the tx status will be updated throughout the tx lifecycle, while destChainId is set once here\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n bridgeTxDetails[transactionId].destChainId = params.dstChainId;\n\n emit BridgeRequested({\n transactionId: transactionId,\n sender: params.sender,\n request: request,\n destChainId: params.dstChainId,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n sendChainGas: paramsV2.zapNative != 0\n });\n emit BridgeQuoteDetails(transactionId, paramsV2.quoteId);\n }\n\n /// @inheritdoc IFastBridgeV2\n function relay(bytes calldata request, address relayer) public payable {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n _validateRelayParams(request, transactionId, relayer);\n // mark bridge transaction as relayed\n bridgeRelayDetails[transactionId] =\n BridgeRelay({blockNumber: uint48(block.number), blockTimestamp: uint48(block.timestamp), relayer: relayer});\n\n // transfer tokens to recipient on destination chain and trigger Zap if requested\n address to = request.destRecipient();\n address token = request.destToken();\n uint256 amount = request.destAmount();\n uint256 zapNative = request.zapNative();\n\n // Emit the event before any external calls\n emit BridgeRelayed({\n transactionId: transactionId,\n relayer: relayer,\n to: to,\n originChainId: request.originChainId(),\n originToken: request.originToken(),\n destToken: token,\n originAmount: request.originAmount(),\n destAmount: amount,\n chainGasAmount: zapNative\n });\n\n // All state changes have been done at this point, can proceed to the external calls.\n // This follows the checks-effects-interactions pattern to mitigate potential reentrancy attacks.\n if (token == NATIVE_GAS_TOKEN) {\n // For the native gas token, additional zapNative is not allowed\n if (zapNative != 0) revert ZapNativeNotSupported();\n // Check that the correct msg.value was sent\n if (msg.value != amount) revert MsgValueIncorrect();\n // Don't do a native transfer yet: we will handle it alongside the Zap below\n } else {\n // For ERC20s, we check that the correct msg.value was sent\n if (msg.value != zapNative) revert MsgValueIncorrect();\n // We need to transfer the tokens from the Relayer to the recipient first before performing an\n // optional post-transfer Zap.\n IERC20(token).safeTransferFrom(msg.sender, to, amount);\n }\n // At this point we have done:\n // - Transferred the requested amount of ERC20 tokens to the recipient.\n // At this point we have confirmed:\n // - For ERC20s: msg.value matches the requested zapNative amount.\n // - For the native gas token: msg.value matches the requested destAmount.\n // Remaining optional things to do:\n // - Forward the full msg.value to the recipient (if non-zero).\n // - Trigger a Zap (if zapData is present).\n bytes calldata zapData = request.zapData();\n if (zapData.length != 0) {\n // Zap Data is present: Zap has been requested by the recipient. Trigger it forwarding the full msg.value.\n\n // Note: if token has a fee on transfers, the recipient will have received less than `amount`.\n // This is a very niche edge case and should be handled by the recipient contract.\n _triggerZapWithChecks({recipient: to, token: token, amount: amount, zapData: zapData});\n } else if (msg.value != 0) {\n // Zap Data is missing, but msg.value was sent. This could happen in two different cases:\n // - Relay with the native gas token is happening.\n // - Relay with ERC20 is happening, with a `zapNative \u003e 0` request.\n // In both cases, we need to transfer the full msg.value to the recipient.\n Address.sendValue(payable(to), msg.value);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) public onlyRole(PROVER_ROLE) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n\n // Can only prove a REQUESTED transaction\n if ($.status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n // Update status to RELAYER_PROVED and store the proof details\n // Note: these are storage writes\n $.status = BridgeStatus.RELAYER_PROVED;\n $.proofBlockTimestamp = uint56(block.timestamp);\n $.proofRelayer = relayer;\n\n emit BridgeProofProvided(transactionId, relayer, destTxHash);\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes calldata request, address to) public {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Aggregate the read operations from the same storage slot\n address proofRelayer = $.proofRelayer;\n BridgeStatus status = $.status;\n uint56 proofBlockTimestamp = $.proofBlockTimestamp;\n\n // Can only claim a RELAYER_PROVED transaction after the dispute period\n if (status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(proofBlockTimestamp) \u003c= DISPUTE_PERIOD) {\n revert DisputePeriodNotPassed();\n }\n\n if (to == address(0)) {\n // Anyone could claim the funds to the proven relayer on their behalf\n to = proofRelayer;\n } else if (proofRelayer != msg.sender) {\n // Only the proven relayer could specify an address to claim the funds to\n revert SenderIncorrect();\n }\n\n // Update status to RELAYER_CLAIMED and transfer the origin collateral to the specified claim address\n // Note: this is a storage write\n $.status = BridgeStatus.RELAYER_CLAIMED;\n\n address token = request.originToken();\n uint256 amount = request.originAmount();\n // Update protocol fees if origin fee amount exists\n uint256 originFeeAmount = request.originFeeAmount();\n if (originFeeAmount \u003e 0) protocolFees[token] += originFeeAmount;\n // Emit the event before any external calls\n emit BridgeDepositClaimed(transactionId, proofRelayer, to, token, amount);\n // Complete the relayer claim as the last transaction action\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(to), amount);\n } else {\n IERC20(token).safeTransfer(to, amount);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function cancel(bytes calldata request) public {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Can only cancel a REQUESTED transaction after its deadline expires\n if ($.status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n uint256 deadline = request.deadline();\n // Permissionless cancel is only allowed after `cancelDelay` on top of the deadline\n if (!hasRole(CANCELER_ROLE, msg.sender)) deadline += cancelDelay;\n if (block.timestamp \u003c= deadline) revert DeadlineNotExceeded();\n // Update status to REFUNDED and return the full amount (collateral + protocol fees) to the original sender.\n // The protocol fees are only updated when the transaction is claimed, so we don't need to update them here.\n // Note: this is a storage write\n $.status = BridgeStatus.REFUNDED;\n\n address to = request.originSender();\n address token = request.originToken();\n uint256 amount = request.originAmount() + request.originFeeAmount();\n // Emit the event before any external calls\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n // Complete the user cancel as the last transaction action\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(to), amount);\n } else {\n IERC20(token).safeTransfer(to, amount);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeStatuses(bytes32 transactionId) public view returns (BridgeStatus status) {\n return bridgeTxDetails[transactionId].status;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeProofs(bytes32 transactionId) public view returns (uint96 timestamp, address relayer) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n\n timestamp = $.proofBlockTimestamp;\n relayer = $.proofRelayer;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeRelays(bytes32 transactionId) public view returns (bool) {\n // has this transactionId been relayed?\n return bridgeRelayDetails[transactionId].relayer != address(0);\n }\n\n /// @notice Takes the bridged asset from the user into FastBridgeV2 custody. It will be later\n /// claimed by the relayer who completed the relay on destination chain, or transferred back to the user\n /// via the cancel function should no one complete the relay.\n function _takeBridgedUserAsset(address token, uint256 amount) internal returns (uint256 amountTaken) {\n if (token == NATIVE_GAS_TOKEN) {\n // For the native gas token, we just need to check that the supplied msg.value is correct.\n // Supplied `msg.value` is already in FastBridgeV2 custody.\n if (amount != msg.value) revert MsgValueIncorrect();\n amountTaken = msg.value;\n } else {\n // For ERC20s, token is explicitly transferred from the user to FastBridgeV2.\n // We don't allow non-zero `msg.value` to avoid extra funds from being stuck in FastBridgeV2.\n if (msg.value != 0) revert MsgValueIncorrect();\n // Throw an explicit error if the provided token address is not a contract\n if (token.code.length == 0) revert TokenNotContract();\n amountTaken = IERC20(token).balanceOf(address(this));\n IERC20(token).safeTransferFrom(msg.sender, address(this), amount);\n // Use the balance difference as the amount taken in case of fee on transfer tokens.\n amountTaken = IERC20(token).balanceOf(address(this)) - amountTaken;\n }\n }\n\n /// @notice Calls the Recipient's hook function with the specified zapData and performs\n /// all the necessary checks for the returned value.\n function _triggerZapWithChecks(address recipient, address token, uint256 amount, bytes calldata zapData) internal {\n // This will bubble any revert messages from the hook function\n bytes memory returnData = Address.functionCallWithValue({\n target: recipient,\n data: abi.encodeCall(IZapRecipient.zap, (token, amount, zapData)),\n // Note: see `relay()` for reasoning behind passing msg.value\n value: msg.value\n });\n // Explicit revert if no return data at all\n if (returnData.length == 0) revert RecipientNoReturnValue();\n // Check that exactly a single return value was returned\n if (returnData.length != 32) revert RecipientIncorrectReturnValue();\n // Return value should be abi-encoded hook function selector\n if (bytes32(returnData) != bytes32(IZapRecipient.zap.selector)) {\n revert RecipientIncorrectReturnValue();\n }\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint56(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint56).max but\n /// proof.timestamp \u003c type(uint56).max via unchecked statement\n /// @param proofBlockTimestamp The bridge proof block timestamp\n /// @return delta Time delta since proof submitted\n function _timeSince(uint56 proofBlockTimestamp) internal view returns (uint256 delta) {\n unchecked {\n delta = uint56(block.timestamp) - proofBlockTimestamp;\n }\n }\n\n /// @notice Performs all the necessary checks for a bridge to happen.\n /// @dev There's no good way to refactor this function to reduce cyclomatic complexity due to\n /// the number of checks that need to be performed, so we skip the code-complexity rule here.\n // solhint-disable-next-line code-complexity\n function _validateBridgeParams(\n BridgeParams memory params,\n BridgeParamsV2 memory paramsV2,\n int256 exclusivityEndTime\n )\n internal\n view\n {\n // Check V1 (legacy) params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.sender == address(0) || params.to == address(0)) revert ZeroAddress();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n // Check V2 params\n if (paramsV2.zapData.length \u003e MAX_ZAP_DATA_LENGTH) revert ZapDataLengthAboveMax();\n if (paramsV2.zapNative != 0 \u0026\u0026 params.destToken == NATIVE_GAS_TOKEN) {\n revert ZapNativeNotSupported();\n }\n // exclusivityEndTime must be in range [0 .. params.deadline]\n if (exclusivityEndTime \u003c 0 || exclusivityEndTime \u003e int256(params.deadline)) {\n revert ExclusivityParamsIncorrect();\n }\n }\n\n /// @notice Performs all the necessary checks for a relay to happen.\n function _validateRelayParams(bytes calldata request, bytes32 transactionId, address relayer) internal view {\n if (relayer == address(0)) revert ZeroAddress();\n // Check if the transaction has already been relayed\n if (bridgeRelays(transactionId)) revert TransactionRelayed();\n if (request.destChainId() != block.chainid) revert ChainIncorrect();\n // Check the deadline for relay to happen\n if (block.timestamp \u003e request.deadline()) revert DeadlineExceeded();\n // Check the exclusivity period, if it is still ongoing\n address exclRelayer = request.exclusivityRelayer();\n if (exclRelayer != address(0) \u0026\u0026 exclRelayer != relayer \u0026\u0026 block.timestamp \u003c= request.exclusivityEndTime()) {\n revert ExclusivityPeriodNotPassed();\n }\n }\n}\n","language":"Solidity","languageVersion":"0.8.24","compilerVersion":"0.8.24","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"","srcMapRuntime":"","abiDefinition":[{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldCancelDelay","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newCancelDelay","type":"uint256"}],"name":"CancelDelayUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldFeeRate","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newFeeRate","type":"uint256"}],"name":"FeeRateUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"address","name":"recipient","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"FeesSwept","type":"event"},{"inputs":[{"internalType":"uint256","name":"newCancelDelay","type":"uint256"}],"name":"setCancelDelay","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"newFeeRate","type":"uint256"}],"name":"setProtocolFeeRate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"address","name":"recipient","type":"address"}],"name":"sweepProtocolFees","outputs":[],"stateMutability":"nonpayable","type":"function"}],"userDoc":{"kind":"user","methods":{},"version":1},"developerDoc":{"kind":"dev","methods":{},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"oldCancelDelay\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newCancelDelay\",\"type\":\"uint256\"}],\"name\":\"CancelDelayUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"oldFeeRate\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newFeeRate\",\"type\":\"uint256\"}],\"name\":\"FeeRateUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"FeesSwept\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"newCancelDelay\",\"type\":\"uint256\"}],\"name\":\"setCancelDelay\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"newFeeRate\",\"type\":\"uint256\"}],\"name\":\"setProtocolFeeRate\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"}],\"name\":\"sweepProtocolFees\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeV2.sol\":\"IAdminV2\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeV2.sol\":{\"keccak256\":\"0xac79c463688a682ca706a4ef95e7817b83548cdfa8182ba0426ac7e5e07613d8\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://b3ecb7097381287cafc3a73f3a2bb03565115ebb682a85064e0b0dc2f7e2919d\",\"dweb:/ipfs/QmatruW3nYZTksf3CeQ8wwiAG4c7xoEJBEp6drHPtFLBRK\"]}},\"version\":1}"},"hashes":{"setCancelDelay(uint256)":"1ea327c5","setProtocolFeeRate(uint256)":"b13aa2d6","sweepProtocolFees(address,address)":"06f333f2"}},"solidity/FastBridgeV2.sol:IAdminV2Errors":{"code":"0x","runtime-code":"0x","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.24 ^0.8.20 ^0.8.4;\n\n// contracts/interfaces/IAdminV2.sol\n\ninterface IAdminV2 {\n event CancelDelayUpdated(uint256 oldCancelDelay, uint256 newCancelDelay);\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n function setCancelDelay(uint256 newCancelDelay) external;\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n}\n\n// contracts/interfaces/IAdminV2Errors.sol\n\ninterface IAdminV2Errors {\n error CancelDelayBelowMin();\n error FeeRateAboveMax();\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IFastBridgeV2Errors.sol\n\ninterface IFastBridgeV2Errors {\n error AmountIncorrect();\n error ChainIncorrect();\n error ExclusivityParamsIncorrect();\n error MsgValueIncorrect();\n error SenderIncorrect();\n error StatusIncorrect();\n error TokenNotContract();\n error ZapDataLengthAboveMax();\n error ZapNativeNotSupported();\n error ZeroAddress();\n\n error RecipientIncorrectReturnValue();\n error RecipientNoReturnValue();\n\n error DeadlineExceeded();\n error DeadlineNotExceeded();\n error DeadlineTooShort();\n error DisputePeriodNotPassed();\n error DisputePeriodPassed();\n error ExclusivityPeriodNotPassed();\n\n error TransactionRelayed();\n}\n\n// contracts/interfaces/IMulticallTarget.sol\n\n/// @notice Interface for a contract that can be called multiple times by the same caller. Inspired by MulticallV3:\n/// https://github.com/mds1/multicall/blob/master/src/Multicall3.sol\ninterface IMulticallTarget {\n struct Result {\n bool success;\n bytes returnData;\n }\n\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external;\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results);\n}\n\n// contracts/interfaces/IZapRecipient.sol\n\ninterface IZapRecipient {\n function zap(address token, uint256 amount, bytes memory zapData) external payable returns (bytes4);\n}\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// contracts/interfaces/IFastBridgeV2.sol\n\ninterface IFastBridgeV2 is IFastBridge {\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n struct BridgeTxDetails {\n BridgeStatus status;\n uint32 destChainId;\n uint56 proofBlockTimestamp;\n address proofRelayer;\n }\n\n struct BridgeRelay {\n uint48 blockNumber;\n uint48 blockTimestamp;\n address relayer;\n }\n\n /// @notice New params introduced in the FastBridgeV2.\n /// We are passing fields from the older BridgeParams struct outside of this struct\n /// for backwards compatibility.\n /// Note: quoteRelayer and quoteExclusivitySeconds are either both zero (indicating no exclusivity)\n /// or both non-zero (indicating exclusivity for the given period).\n /// Note: zapNative \u003e 0 can NOT be used with destToken = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE (native token)\n /// @param quoteRelayer Relayer that provided the quote for the transaction\n /// @param quoteExclusivitySeconds Period of time the quote relayer is guaranteed exclusivity after user's deposit\n /// @param quoteId Unique quote identifier used for tracking the quote\n /// @param zapNative ETH value to send to the recipient (if any)\n /// @param zapData Parameters for the Zap to the destination recipient (if any)\n struct BridgeParamsV2 {\n address quoteRelayer;\n int256 quoteExclusivitySeconds;\n bytes quoteId;\n uint256 zapNative;\n bytes zapData;\n }\n\n /// @notice Updated bridge transaction struct to include parameters introduced in FastBridgeV2.\n /// Note: only `exclusivityRelayer` can fill such a transaction until `exclusivityEndTime`.\n struct BridgeTransactionV2 {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n // Note: sendChainGas flag from V1 is deprecated\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n address exclusivityRelayer;\n uint256 exclusivityEndTime;\n uint256 zapNative; // ETH value to send to the recipient (if any)\n bytes zapData; // data to pass for the Zap action (if any)\n }\n\n event BridgeQuoteDetails(bytes32 indexed transactionId, bytes quoteId);\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability\n /// to provide temporary exclusivity fill rights for the quote relayer.\n /// @param params The parameters required to bridge\n /// @param paramsV2 The parameters for exclusivity fill rights (optional, can be left empty)\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function relay(bytes memory request, address relayer) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param transactionId The transaction id associated with the encoded bridge transaction to prove\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital.\n /// @notice Can only send funds to the relayer address on the proof.\n /// @param request The encoded bridge transaction to claim on origin chain\n function claim(bytes memory request) external;\n\n /// @notice Cancels an outstanding bridge transaction in case optimistic bridging failed and returns the full amount\n /// to the original sender.\n /// @param request The encoded bridge transaction to refund\n function cancel(bytes memory request) external;\n\n /// @notice Checks if a transaction has been relayed\n /// @param transactionId The ID of the transaction to check\n /// @return True if the transaction has been relayed, false otherwise\n function bridgeRelays(bytes32 transactionId) external view returns (bool);\n\n /// @notice Returns the status of a bridge transaction\n /// @param transactionId The ID of the bridge transaction\n /// @return BridgeStatus Status of the bridge transaction\n function bridgeStatuses(bytes32 transactionId) external view returns (BridgeStatus);\n\n /// @notice Returns the timestamp and relayer of a bridge proof\n /// @param transactionId The ID of the bridge transaction\n /// @return timestamp The timestamp of the bridge proof\n /// @return relayer The relayer address of the bridge proof\n function bridgeProofs(bytes32 transactionId) external view returns (uint96 timestamp, address relayer);\n\n /// @notice Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\n /// @param request The bridge request to decode\n function getBridgeTransactionV2(bytes memory request) external view returns (BridgeTransactionV2 memory);\n}\n\n// contracts/utils/MulticallTarget.sol\n\n// solhint-disable avoid-low-level-calls\n/// @notice Template for a contract that supports batched calls (preserving the msg.sender).\n/// Only calls with zero msg.value could be batched.\nabstract contract MulticallTarget is IMulticallTarget {\n error MulticallTarget__UndeterminedRevert();\n\n /// @notice Perform a batched call to this contract, preserving the msg.sender.\n /// The return data from each call is discarded.\n /// @dev The method is non-payable, so only calls with `msg.value == 0` could be batched.\n /// It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag.\n /// Otherwise, the whole batch call will be reverted with the original revert reason.\n /// @param data List of abi-encoded calldata for the calls to perform.\n /// @param ignoreReverts Whether to ignore the revert errors from the calls.\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external {\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\n if (!success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(result);\n }\n }\n }\n\n /// @notice Perform a batched call to this contract, preserving the msg.sender.\n /// The return data from each call is preserved.\n /// @dev The method is non-payable, so only calls with `msg.value == 0` could be batched.\n /// It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag.\n /// Otherwise, the whole batch call will be reverted with the original revert reason.\n /// @param data List of abi-encoded calldata for the calls to perform.\n /// @param ignoreReverts Whether to ignore the revert errors from the calls.\n /// @return results List of results from the calls: `(success, returnData)`.\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results)\n {\n results = new Result[](data.length);\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (results[i].success, results[i].returnData) = address(this).delegatecall(data[i]);\n if (!results[i].success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(results[i].returnData);\n }\n }\n }\n\n /// @dev Bubbles the revert message from the underlying call.\n /// Note: preserves the same custom error or revert string, if one was used.\n /// Source: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v5.0.2/contracts/utils/Address.sol#L143-L158\n function _bubbleRevert(bytes memory returnData) internal pure {\n // Look for revert reason and bubble it up if present\n if (returnData.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n // solhint-disable-next-line no-inline-assembly\n assembly {\n let returndata_size := mload(returnData)\n revert(add(32, returnData), returndata_size)\n }\n } else {\n revert MulticallTarget__UndeterminedRevert();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// contracts/libs/BridgeTransactionV2.sol\n\n// solhint-disable no-inline-assembly\nlibrary BridgeTransactionV2Lib {\n uint16 internal constant VERSION = 2;\n\n // Offsets of the fields in the packed BridgeTransactionV2 struct\n // uint16 version [000 .. 002)\n // uint32 originChainId [002 .. 006)\n // uint32 destChainId [006 .. 010)\n // address originSender [010 .. 030)\n // address destRecipient [030 .. 050)\n // address originToken [050 .. 070)\n // address destToken [070 .. 090)\n // uint256 originAmount [090 .. 122)\n // uint256 destAmount [122 .. 154)\n // uint256 originFeeAmount [154 .. 186)\n // uint256 deadline [186 .. 218)\n // uint256 nonce [218 .. 250)\n // address exclusivityRelayer [250 .. 270)\n // uint256 exclusivityEndTime [270 .. 302)\n // uint256 zapNative [302 .. 334)\n // bytes zapData [334 .. ***)\n\n // forgefmt: disable-start\n uint256 private constant OFFSET_ORIGIN_CHAIN_ID = 2;\n uint256 private constant OFFSET_DEST_CHAIN_ID = 6;\n uint256 private constant OFFSET_ORIGIN_SENDER = 10;\n uint256 private constant OFFSET_DEST_RECIPIENT = 30;\n uint256 private constant OFFSET_ORIGIN_TOKEN = 50;\n uint256 private constant OFFSET_DEST_TOKEN = 70;\n uint256 private constant OFFSET_ORIGIN_AMOUNT = 90;\n uint256 private constant OFFSET_DEST_AMOUNT = 122;\n uint256 private constant OFFSET_ORIGIN_FEE_AMOUNT = 154;\n uint256 private constant OFFSET_DEADLINE = 186;\n uint256 private constant OFFSET_NONCE = 218;\n uint256 private constant OFFSET_EXCLUSIVITY_RELAYER = 250;\n uint256 private constant OFFSET_EXCLUSIVITY_END_TIME = 270;\n uint256 private constant OFFSET_ZAP_NATIVE = 302;\n uint256 private constant OFFSET_ZAP_DATA = 334;\n // forgefmt: disable-end\n\n error BridgeTransactionV2__InvalidEncodedTx();\n error BridgeTransactionV2__UnsupportedVersion(uint16 version);\n\n /// @notice Validates the encoded transaction to be a tightly packed encoded payload for BridgeTransactionV2.\n /// @dev Checks the minimum length and the version, use this function before decoding any of the fields.\n function validateV2(bytes calldata encodedTx) internal pure {\n // Check the minimum length: must at least include all static fields.\n if (encodedTx.length \u003c OFFSET_ZAP_DATA) revert BridgeTransactionV2__InvalidEncodedTx();\n // Once we validated the length, we can be sure that the version field is present.\n uint16 version_ = version(encodedTx);\n if (version_ != VERSION) revert BridgeTransactionV2__UnsupportedVersion(version_);\n }\n\n /// @notice Encodes the BridgeTransactionV2 struct by tightly packing the fields.\n /// @dev `abi.decode` will not work as a result of the tightly packed fields. Use `decodeV2` to decode instead.\n function encodeV2(IFastBridgeV2.BridgeTransactionV2 memory bridgeTx) internal pure returns (bytes memory) {\n // We split the encoding into two parts to avoid stack-too-deep error\n bytes memory firstPart = abi.encodePacked(\n VERSION,\n bridgeTx.originChainId,\n bridgeTx.destChainId,\n bridgeTx.originSender,\n bridgeTx.destRecipient,\n bridgeTx.originToken,\n bridgeTx.destToken,\n bridgeTx.originAmount\n );\n return abi.encodePacked(\n firstPart,\n bridgeTx.destAmount,\n bridgeTx.originFeeAmount,\n // Note: we skip the deprecated `sendChainGas` flag, which was present in BridgeTransaction V1\n bridgeTx.deadline,\n bridgeTx.nonce,\n // New V2 fields: exclusivity\n bridgeTx.exclusivityRelayer,\n bridgeTx.exclusivityEndTime,\n // New V2 fields: Zap\n bridgeTx.zapNative,\n bridgeTx.zapData\n );\n }\n\n /// @notice Decodes the BridgeTransactionV2 struct from the encoded transaction.\n /// @dev Encoded BridgeTransactionV2 struct must be tightly packed.\n /// Use `validateV2` before decoding to ensure the encoded transaction is valid.\n function decodeV2(bytes calldata encodedTx)\n internal\n pure\n returns (IFastBridgeV2.BridgeTransactionV2 memory bridgeTx)\n {\n bridgeTx.originChainId = originChainId(encodedTx);\n bridgeTx.destChainId = destChainId(encodedTx);\n bridgeTx.originSender = originSender(encodedTx);\n bridgeTx.destRecipient = destRecipient(encodedTx);\n bridgeTx.originToken = originToken(encodedTx);\n bridgeTx.destToken = destToken(encodedTx);\n bridgeTx.originAmount = originAmount(encodedTx);\n bridgeTx.destAmount = destAmount(encodedTx);\n bridgeTx.originFeeAmount = originFeeAmount(encodedTx);\n bridgeTx.deadline = deadline(encodedTx);\n bridgeTx.nonce = nonce(encodedTx);\n bridgeTx.exclusivityRelayer = exclusivityRelayer(encodedTx);\n bridgeTx.exclusivityEndTime = exclusivityEndTime(encodedTx);\n bridgeTx.zapNative = zapNative(encodedTx);\n bridgeTx.zapData = zapData(encodedTx);\n }\n\n /// @notice Extracts the version from the encoded transaction.\n function version(bytes calldata encodedTx) internal pure returns (uint16 version_) {\n // Load 32 bytes from the start and shift it 240 bits to the right to get the highest 16 bits.\n assembly {\n version_ := shr(240, calldataload(encodedTx.offset))\n }\n }\n\n /// @notice Extracts the origin chain ID from the encoded transaction.\n function originChainId(bytes calldata encodedTx) internal pure returns (uint32 originChainId_) {\n // Load 32 bytes from the offset and shift it 224 bits to the right to get the highest 32 bits.\n assembly {\n originChainId_ := shr(224, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_CHAIN_ID)))\n }\n }\n\n /// @notice Extracts the destination chain ID from the encoded transaction.\n function destChainId(bytes calldata encodedTx) internal pure returns (uint32 destChainId_) {\n // Load 32 bytes from the offset and shift it 224 bits to the right to get the highest 32 bits.\n assembly {\n destChainId_ := shr(224, calldataload(add(encodedTx.offset, OFFSET_DEST_CHAIN_ID)))\n }\n }\n\n /// @notice Extracts the origin sender from the encoded transaction.\n function originSender(bytes calldata encodedTx) internal pure returns (address originSender_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n originSender_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_SENDER)))\n }\n }\n\n /// @notice Extracts the destination recipient from the encoded transaction.\n function destRecipient(bytes calldata encodedTx) internal pure returns (address destRecipient_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n destRecipient_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_DEST_RECIPIENT)))\n }\n }\n\n /// @notice Extracts the origin token from the encoded transaction.\n function originToken(bytes calldata encodedTx) internal pure returns (address originToken_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n originToken_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_TOKEN)))\n }\n }\n\n /// @notice Extracts the destination token from the encoded transaction.\n function destToken(bytes calldata encodedTx) internal pure returns (address destToken_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n destToken_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_DEST_TOKEN)))\n }\n }\n\n /// @notice Extracts the origin amount from the encoded transaction.\n function originAmount(bytes calldata encodedTx) internal pure returns (uint256 originAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n originAmount_ := calldataload(add(encodedTx.offset, OFFSET_ORIGIN_AMOUNT))\n }\n }\n\n /// @notice Extracts the destination amount from the encoded transaction.\n function destAmount(bytes calldata encodedTx) internal pure returns (uint256 destAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n destAmount_ := calldataload(add(encodedTx.offset, OFFSET_DEST_AMOUNT))\n }\n }\n\n /// @notice Extracts the origin fee amount from the encoded transaction.\n function originFeeAmount(bytes calldata encodedTx) internal pure returns (uint256 originFeeAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n originFeeAmount_ := calldataload(add(encodedTx.offset, OFFSET_ORIGIN_FEE_AMOUNT))\n }\n }\n\n /// @notice Extracts the deadline from the encoded transaction.\n function deadline(bytes calldata encodedTx) internal pure returns (uint256 deadline_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n deadline_ := calldataload(add(encodedTx.offset, OFFSET_DEADLINE))\n }\n }\n\n /// @notice Extracts the nonce from the encoded transaction.\n function nonce(bytes calldata encodedTx) internal pure returns (uint256 nonce_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n nonce_ := calldataload(add(encodedTx.offset, OFFSET_NONCE))\n }\n }\n\n /// @notice Extracts the exclusivity relayer from the encoded transaction.\n function exclusivityRelayer(bytes calldata encodedTx) internal pure returns (address exclusivityRelayer_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n exclusivityRelayer_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_EXCLUSIVITY_RELAYER)))\n }\n }\n\n /// @notice Extracts the exclusivity end time from the encoded transaction.\n function exclusivityEndTime(bytes calldata encodedTx) internal pure returns (uint256 exclusivityEndTime_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n exclusivityEndTime_ := calldataload(add(encodedTx.offset, OFFSET_EXCLUSIVITY_END_TIME))\n }\n }\n\n /// @notice Extracts the Zap's native value from the encoded transaction.\n function zapNative(bytes calldata encodedTx) internal pure returns (uint256 zapNative_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n zapNative_ := calldataload(add(encodedTx.offset, OFFSET_ZAP_NATIVE))\n }\n }\n\n /// @notice Extracts the Zap's data from the encoded transaction.\n function zapData(bytes calldata encodedTx) internal pure returns (bytes calldata zapData_) {\n zapData_ = encodedTx[OFFSET_ZAP_DATA:];\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/AdminV2.sol\n\ncontract AdminV2 is AccessControlEnumerable, IAdminV2, IAdminV2Errors {\n using SafeERC20 for IERC20;\n\n /// @notice Address reserved for native gas token (ETH on Ethereum and most L2s, AVAX on Avalanche, etc)\n address public constant NATIVE_GAS_TOKEN = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Role identifier for Quoter API's off-chain authentication.\n /// @dev Only addresses with this role can post FastBridge quotes to the API.\n bytes32 public constant QUOTER_ROLE = keccak256(\"QUOTER_ROLE\");\n\n /// @notice Role identifier for Prover's on-chain authentication in FastBridge.\n /// @dev Only addresses with this role can provide proofs that a FastBridge request has been relayed.\n bytes32 public constant PROVER_ROLE = keccak256(\"PROVER_ROLE\");\n\n /// @notice Role identifier for Guard's on-chain authentication in FastBridge.\n /// @dev Only addresses with this role can dispute submitted relay proofs during the dispute period.\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n\n /// @notice Role identifier for Canceler's on-chain authentication in FastBridge.\n /// @dev Only addresses with this role can cancel a FastBridge transaction without the cancel delay.\n bytes32 public constant CANCELER_ROLE = keccak256(\"CANCELER_ROLE\");\n\n /// @notice Role identifier for Governor's on-chain administrative authority.\n /// @dev Only addresses with this role can perform administrative tasks within the contract.\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n /// @notice Denominator for fee rates, represents 100%.\n uint256 public constant FEE_BPS = 1e6;\n /// @notice Maximum protocol fee rate: 1% on origin amount.\n uint256 public constant FEE_RATE_MAX = 0.01e6;\n\n /// @notice Minimum cancel delay that can be set by the governor.\n uint256 public constant MIN_CANCEL_DELAY = 1 hours;\n /// @notice Default cancel delay set during the contract deployment.\n uint256 public constant DEFAULT_CANCEL_DELAY = 1 days;\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Delay for a transaction after which it could be permisionlessly cancelled\n uint256 public cancelDelay;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Use ZapNative V2 requests instead.\n uint256 public immutable chainGasAmount = 0;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n _setCancelDelay(DEFAULT_CANCEL_DELAY);\n }\n\n /// @notice Allows the contract governor to set the cancel delay. The cancel delay is the time after the transaction\n /// deadline after which it can be permissionlessly cancelled, if it hasn't been proven by any of the Relayers.\n function setCancelDelay(uint256 newCancelDelay) external onlyRole(GOVERNOR_ROLE) {\n _setCancelDelay(newCancelDelay);\n }\n\n /// @notice Allows the contract governor to set the protocol fee rate. The protocol fee is taken from the origin\n /// amount only for completed and claimed transactions.\n /// @dev The protocol fee is abstracted away from the relayers, they always operate using the amounts after fees:\n /// what they see as the origin amount emitted in the log is what they get credited with.\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n if (newFeeRate \u003e FEE_RATE_MAX) revert FeeRateAboveMax();\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n /// @notice Allows the contract governor to sweep the accumulated protocol fees in the contract.\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n emit FeesSwept(token, recipient, feeAmount);\n /// Sweep the fees as the last transaction action\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(recipient), feeAmount);\n } else {\n IERC20(token).safeTransfer(recipient, feeAmount);\n }\n }\n\n /// @notice Internal function to set the cancel delay. Security checks are performed outside of this function.\n function _setCancelDelay(uint256 newCancelDelay) private {\n if (newCancelDelay \u003c MIN_CANCEL_DELAY) revert CancelDelayBelowMin();\n uint256 oldCancelDelay = cancelDelay;\n cancelDelay = newCancelDelay;\n emit CancelDelayUpdated(oldCancelDelay, newCancelDelay);\n }\n}\n\n// contracts/FastBridgeV2.sol\n\n/// @notice FastBridgeV2 is a contract for bridging tokens across chains.\ncontract FastBridgeV2 is AdminV2, MulticallTarget, IFastBridgeV2, IFastBridgeV2Errors {\n using BridgeTransactionV2Lib for bytes;\n using SafeERC20 for IERC20;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n /// @notice Maximum length of accepted zapData\n uint256 public constant MAX_ZAP_DATA_LENGTH = 2 ** 16 - 1;\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeTxDetails) public bridgeTxDetails;\n /// @notice Relay details on destination chain\n mapping(bytes32 =\u003e BridgeRelay) public bridgeRelayDetails;\n /// @notice Unique bridge nonces tracked per originSender\n mapping(address =\u003e uint256) public senderNonces;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Replaced by senderNonces\n uint256 public immutable nonce = 0;\n /// @notice the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) AdminV2(_owner) {\n deployBlock = block.number;\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n bridge({\n params: params,\n paramsV2: BridgeParamsV2({\n quoteRelayer: address(0),\n quoteExclusivitySeconds: 0,\n quoteId: bytes(\"\"),\n zapNative: 0,\n zapData: bytes(\"\")\n })\n });\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes calldata request) external payable {\n // relay override will validate the request\n relay({request: request, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes calldata request, bytes32 destTxHash) external {\n request.validateV2();\n prove({transactionId: keccak256(request), destTxHash: destTxHash, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridgeV2\n function claim(bytes calldata request) external {\n // claim override will validate the request\n claim({request: request, to: address(0)});\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Aggregate the read operations from the same storage slot\n address disputedRelayer = $.proofRelayer;\n BridgeStatus status = $.status;\n uint56 proofBlockTimestamp = $.proofBlockTimestamp;\n // Can only dispute a RELAYER_PROVED transaction within the dispute period\n if (status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(proofBlockTimestamp) \u003e DISPUTE_PERIOD) {\n revert DisputePeriodPassed();\n }\n // Update status to REQUESTED and delete the disputed proof details\n // Note: these are storage writes\n $.status = BridgeStatus.REQUESTED;\n $.proofRelayer = address(0);\n $.proofBlockTimestamp = 0;\n\n emit BridgeProofDisputed(transactionId, disputedRelayer);\n }\n\n /// Note: this function is deprecated and will be removed in a future version.\n /// @inheritdoc IFastBridge\n function refund(bytes calldata request) external {\n cancel(request);\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // The correct relayer can only claim a RELAYER_PROVED transaction after the dispute period\n if ($.status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if ($.proofRelayer != relayer) revert SenderIncorrect();\n return _timeSince($.proofBlockTimestamp) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n /// @dev This method is added to achieve backwards compatibility with decoding requests into V1 structs:\n /// - `zapNative` is partially reported as a zero/non-zero flag\n /// - `zapData` is ignored\n /// In order to process all kinds of requests use getBridgeTransactionV2 instead.\n function getBridgeTransaction(bytes calldata request) external view returns (BridgeTransaction memory) {\n // Try decoding into V2 struct first. This will revert if V1 struct is passed\n try this.getBridgeTransactionV2(request) returns (BridgeTransactionV2 memory txV2) {\n // Note: we entirely ignore the zapData field, as it was not present in V1\n return BridgeTransaction({\n originChainId: txV2.originChainId,\n destChainId: txV2.destChainId,\n originSender: txV2.originSender,\n destRecipient: txV2.destRecipient,\n originToken: txV2.originToken,\n destToken: txV2.destToken,\n originAmount: txV2.originAmount,\n destAmount: txV2.destAmount,\n originFeeAmount: txV2.originFeeAmount,\n sendChainGas: txV2.zapNative != 0,\n deadline: txV2.deadline,\n nonce: txV2.nonce\n });\n } catch {\n // Fallback to V1 struct\n return abi.decode(request, (BridgeTransaction));\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function getBridgeTransactionV2(bytes calldata request) external pure returns (BridgeTransactionV2 memory) {\n request.validateV2();\n return BridgeTransactionV2Lib.decodeV2(request);\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) public payable {\n int256 exclusivityEndTime = 0;\n // if relayer exclusivity is not intended for this bridge, set exclusivityEndTime to static zero\n // otherwise, set exclusivity to expire at the current block ts offset by quoteExclusivitySeconds\n if (paramsV2.quoteRelayer != address(0)) {\n exclusivityEndTime = int256(block.timestamp) + paramsV2.quoteExclusivitySeconds;\n }\n _validateBridgeParams(params, paramsV2, exclusivityEndTime);\n\n // transfer tokens to bridge contract\n /// @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _takeBridgedUserAsset(params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) {\n originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n }\n\n // set status to requested\n bytes memory request = BridgeTransactionV2Lib.encodeV2(\n BridgeTransactionV2({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n deadline: params.deadline,\n nonce: senderNonces[params.sender]++, // increment nonce on every bridge\n exclusivityRelayer: paramsV2.quoteRelayer,\n // We checked exclusivityEndTime to be in range [0 .. params.deadline] above, so can safely cast\n exclusivityEndTime: uint256(exclusivityEndTime),\n zapNative: paramsV2.zapNative,\n zapData: paramsV2.zapData\n })\n );\n bytes32 transactionId = keccak256(request);\n // Note: the tx status will be updated throughout the tx lifecycle, while destChainId is set once here\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n bridgeTxDetails[transactionId].destChainId = params.dstChainId;\n\n emit BridgeRequested({\n transactionId: transactionId,\n sender: params.sender,\n request: request,\n destChainId: params.dstChainId,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n sendChainGas: paramsV2.zapNative != 0\n });\n emit BridgeQuoteDetails(transactionId, paramsV2.quoteId);\n }\n\n /// @inheritdoc IFastBridgeV2\n function relay(bytes calldata request, address relayer) public payable {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n _validateRelayParams(request, transactionId, relayer);\n // mark bridge transaction as relayed\n bridgeRelayDetails[transactionId] =\n BridgeRelay({blockNumber: uint48(block.number), blockTimestamp: uint48(block.timestamp), relayer: relayer});\n\n // transfer tokens to recipient on destination chain and trigger Zap if requested\n address to = request.destRecipient();\n address token = request.destToken();\n uint256 amount = request.destAmount();\n uint256 zapNative = request.zapNative();\n\n // Emit the event before any external calls\n emit BridgeRelayed({\n transactionId: transactionId,\n relayer: relayer,\n to: to,\n originChainId: request.originChainId(),\n originToken: request.originToken(),\n destToken: token,\n originAmount: request.originAmount(),\n destAmount: amount,\n chainGasAmount: zapNative\n });\n\n // All state changes have been done at this point, can proceed to the external calls.\n // This follows the checks-effects-interactions pattern to mitigate potential reentrancy attacks.\n if (token == NATIVE_GAS_TOKEN) {\n // For the native gas token, additional zapNative is not allowed\n if (zapNative != 0) revert ZapNativeNotSupported();\n // Check that the correct msg.value was sent\n if (msg.value != amount) revert MsgValueIncorrect();\n // Don't do a native transfer yet: we will handle it alongside the Zap below\n } else {\n // For ERC20s, we check that the correct msg.value was sent\n if (msg.value != zapNative) revert MsgValueIncorrect();\n // We need to transfer the tokens from the Relayer to the recipient first before performing an\n // optional post-transfer Zap.\n IERC20(token).safeTransferFrom(msg.sender, to, amount);\n }\n // At this point we have done:\n // - Transferred the requested amount of ERC20 tokens to the recipient.\n // At this point we have confirmed:\n // - For ERC20s: msg.value matches the requested zapNative amount.\n // - For the native gas token: msg.value matches the requested destAmount.\n // Remaining optional things to do:\n // - Forward the full msg.value to the recipient (if non-zero).\n // - Trigger a Zap (if zapData is present).\n bytes calldata zapData = request.zapData();\n if (zapData.length != 0) {\n // Zap Data is present: Zap has been requested by the recipient. Trigger it forwarding the full msg.value.\n\n // Note: if token has a fee on transfers, the recipient will have received less than `amount`.\n // This is a very niche edge case and should be handled by the recipient contract.\n _triggerZapWithChecks({recipient: to, token: token, amount: amount, zapData: zapData});\n } else if (msg.value != 0) {\n // Zap Data is missing, but msg.value was sent. This could happen in two different cases:\n // - Relay with the native gas token is happening.\n // - Relay with ERC20 is happening, with a `zapNative \u003e 0` request.\n // In both cases, we need to transfer the full msg.value to the recipient.\n Address.sendValue(payable(to), msg.value);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) public onlyRole(PROVER_ROLE) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n\n // Can only prove a REQUESTED transaction\n if ($.status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n // Update status to RELAYER_PROVED and store the proof details\n // Note: these are storage writes\n $.status = BridgeStatus.RELAYER_PROVED;\n $.proofBlockTimestamp = uint56(block.timestamp);\n $.proofRelayer = relayer;\n\n emit BridgeProofProvided(transactionId, relayer, destTxHash);\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes calldata request, address to) public {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Aggregate the read operations from the same storage slot\n address proofRelayer = $.proofRelayer;\n BridgeStatus status = $.status;\n uint56 proofBlockTimestamp = $.proofBlockTimestamp;\n\n // Can only claim a RELAYER_PROVED transaction after the dispute period\n if (status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(proofBlockTimestamp) \u003c= DISPUTE_PERIOD) {\n revert DisputePeriodNotPassed();\n }\n\n if (to == address(0)) {\n // Anyone could claim the funds to the proven relayer on their behalf\n to = proofRelayer;\n } else if (proofRelayer != msg.sender) {\n // Only the proven relayer could specify an address to claim the funds to\n revert SenderIncorrect();\n }\n\n // Update status to RELAYER_CLAIMED and transfer the origin collateral to the specified claim address\n // Note: this is a storage write\n $.status = BridgeStatus.RELAYER_CLAIMED;\n\n address token = request.originToken();\n uint256 amount = request.originAmount();\n // Update protocol fees if origin fee amount exists\n uint256 originFeeAmount = request.originFeeAmount();\n if (originFeeAmount \u003e 0) protocolFees[token] += originFeeAmount;\n // Emit the event before any external calls\n emit BridgeDepositClaimed(transactionId, proofRelayer, to, token, amount);\n // Complete the relayer claim as the last transaction action\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(to), amount);\n } else {\n IERC20(token).safeTransfer(to, amount);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function cancel(bytes calldata request) public {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Can only cancel a REQUESTED transaction after its deadline expires\n if ($.status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n uint256 deadline = request.deadline();\n // Permissionless cancel is only allowed after `cancelDelay` on top of the deadline\n if (!hasRole(CANCELER_ROLE, msg.sender)) deadline += cancelDelay;\n if (block.timestamp \u003c= deadline) revert DeadlineNotExceeded();\n // Update status to REFUNDED and return the full amount (collateral + protocol fees) to the original sender.\n // The protocol fees are only updated when the transaction is claimed, so we don't need to update them here.\n // Note: this is a storage write\n $.status = BridgeStatus.REFUNDED;\n\n address to = request.originSender();\n address token = request.originToken();\n uint256 amount = request.originAmount() + request.originFeeAmount();\n // Emit the event before any external calls\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n // Complete the user cancel as the last transaction action\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(to), amount);\n } else {\n IERC20(token).safeTransfer(to, amount);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeStatuses(bytes32 transactionId) public view returns (BridgeStatus status) {\n return bridgeTxDetails[transactionId].status;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeProofs(bytes32 transactionId) public view returns (uint96 timestamp, address relayer) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n\n timestamp = $.proofBlockTimestamp;\n relayer = $.proofRelayer;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeRelays(bytes32 transactionId) public view returns (bool) {\n // has this transactionId been relayed?\n return bridgeRelayDetails[transactionId].relayer != address(0);\n }\n\n /// @notice Takes the bridged asset from the user into FastBridgeV2 custody. It will be later\n /// claimed by the relayer who completed the relay on destination chain, or transferred back to the user\n /// via the cancel function should no one complete the relay.\n function _takeBridgedUserAsset(address token, uint256 amount) internal returns (uint256 amountTaken) {\n if (token == NATIVE_GAS_TOKEN) {\n // For the native gas token, we just need to check that the supplied msg.value is correct.\n // Supplied `msg.value` is already in FastBridgeV2 custody.\n if (amount != msg.value) revert MsgValueIncorrect();\n amountTaken = msg.value;\n } else {\n // For ERC20s, token is explicitly transferred from the user to FastBridgeV2.\n // We don't allow non-zero `msg.value` to avoid extra funds from being stuck in FastBridgeV2.\n if (msg.value != 0) revert MsgValueIncorrect();\n // Throw an explicit error if the provided token address is not a contract\n if (token.code.length == 0) revert TokenNotContract();\n amountTaken = IERC20(token).balanceOf(address(this));\n IERC20(token).safeTransferFrom(msg.sender, address(this), amount);\n // Use the balance difference as the amount taken in case of fee on transfer tokens.\n amountTaken = IERC20(token).balanceOf(address(this)) - amountTaken;\n }\n }\n\n /// @notice Calls the Recipient's hook function with the specified zapData and performs\n /// all the necessary checks for the returned value.\n function _triggerZapWithChecks(address recipient, address token, uint256 amount, bytes calldata zapData) internal {\n // This will bubble any revert messages from the hook function\n bytes memory returnData = Address.functionCallWithValue({\n target: recipient,\n data: abi.encodeCall(IZapRecipient.zap, (token, amount, zapData)),\n // Note: see `relay()` for reasoning behind passing msg.value\n value: msg.value\n });\n // Explicit revert if no return data at all\n if (returnData.length == 0) revert RecipientNoReturnValue();\n // Check that exactly a single return value was returned\n if (returnData.length != 32) revert RecipientIncorrectReturnValue();\n // Return value should be abi-encoded hook function selector\n if (bytes32(returnData) != bytes32(IZapRecipient.zap.selector)) {\n revert RecipientIncorrectReturnValue();\n }\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint56(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint56).max but\n /// proof.timestamp \u003c type(uint56).max via unchecked statement\n /// @param proofBlockTimestamp The bridge proof block timestamp\n /// @return delta Time delta since proof submitted\n function _timeSince(uint56 proofBlockTimestamp) internal view returns (uint256 delta) {\n unchecked {\n delta = uint56(block.timestamp) - proofBlockTimestamp;\n }\n }\n\n /// @notice Performs all the necessary checks for a bridge to happen.\n /// @dev There's no good way to refactor this function to reduce cyclomatic complexity due to\n /// the number of checks that need to be performed, so we skip the code-complexity rule here.\n // solhint-disable-next-line code-complexity\n function _validateBridgeParams(\n BridgeParams memory params,\n BridgeParamsV2 memory paramsV2,\n int256 exclusivityEndTime\n )\n internal\n view\n {\n // Check V1 (legacy) params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.sender == address(0) || params.to == address(0)) revert ZeroAddress();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n // Check V2 params\n if (paramsV2.zapData.length \u003e MAX_ZAP_DATA_LENGTH) revert ZapDataLengthAboveMax();\n if (paramsV2.zapNative != 0 \u0026\u0026 params.destToken == NATIVE_GAS_TOKEN) {\n revert ZapNativeNotSupported();\n }\n // exclusivityEndTime must be in range [0 .. params.deadline]\n if (exclusivityEndTime \u003c 0 || exclusivityEndTime \u003e int256(params.deadline)) {\n revert ExclusivityParamsIncorrect();\n }\n }\n\n /// @notice Performs all the necessary checks for a relay to happen.\n function _validateRelayParams(bytes calldata request, bytes32 transactionId, address relayer) internal view {\n if (relayer == address(0)) revert ZeroAddress();\n // Check if the transaction has already been relayed\n if (bridgeRelays(transactionId)) revert TransactionRelayed();\n if (request.destChainId() != block.chainid) revert ChainIncorrect();\n // Check the deadline for relay to happen\n if (block.timestamp \u003e request.deadline()) revert DeadlineExceeded();\n // Check the exclusivity period, if it is still ongoing\n address exclRelayer = request.exclusivityRelayer();\n if (exclRelayer != address(0) \u0026\u0026 exclRelayer != relayer \u0026\u0026 block.timestamp \u003c= request.exclusivityEndTime()) {\n revert ExclusivityPeriodNotPassed();\n }\n }\n}\n","language":"Solidity","languageVersion":"0.8.24","compilerVersion":"0.8.24","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"","srcMapRuntime":"","abiDefinition":[{"inputs":[],"name":"CancelDelayBelowMin","type":"error"},{"inputs":[],"name":"FeeRateAboveMax","type":"error"}],"userDoc":{"kind":"user","methods":{},"version":1},"developerDoc":{"kind":"dev","methods":{},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[],\"name\":\"CancelDelayBelowMin\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"FeeRateAboveMax\",\"type\":\"error\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeV2.sol\":\"IAdminV2Errors\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeV2.sol\":{\"keccak256\":\"0xac79c463688a682ca706a4ef95e7817b83548cdfa8182ba0426ac7e5e07613d8\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://b3ecb7097381287cafc3a73f3a2bb03565115ebb682a85064e0b0dc2f7e2919d\",\"dweb:/ipfs/QmatruW3nYZTksf3CeQ8wwiAG4c7xoEJBEp6drHPtFLBRK\"]}},\"version\":1}"},"hashes":{}},"solidity/FastBridgeV2.sol:IERC165":{"code":"0x","runtime-code":"0x","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.24 ^0.8.20 ^0.8.4;\n\n// contracts/interfaces/IAdminV2.sol\n\ninterface IAdminV2 {\n event CancelDelayUpdated(uint256 oldCancelDelay, uint256 newCancelDelay);\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n function setCancelDelay(uint256 newCancelDelay) external;\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n}\n\n// contracts/interfaces/IAdminV2Errors.sol\n\ninterface IAdminV2Errors {\n error CancelDelayBelowMin();\n error FeeRateAboveMax();\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IFastBridgeV2Errors.sol\n\ninterface IFastBridgeV2Errors {\n error AmountIncorrect();\n error ChainIncorrect();\n error ExclusivityParamsIncorrect();\n error MsgValueIncorrect();\n error SenderIncorrect();\n error StatusIncorrect();\n error TokenNotContract();\n error ZapDataLengthAboveMax();\n error ZapNativeNotSupported();\n error ZeroAddress();\n\n error RecipientIncorrectReturnValue();\n error RecipientNoReturnValue();\n\n error DeadlineExceeded();\n error DeadlineNotExceeded();\n error DeadlineTooShort();\n error DisputePeriodNotPassed();\n error DisputePeriodPassed();\n error ExclusivityPeriodNotPassed();\n\n error TransactionRelayed();\n}\n\n// contracts/interfaces/IMulticallTarget.sol\n\n/// @notice Interface for a contract that can be called multiple times by the same caller. Inspired by MulticallV3:\n/// https://github.com/mds1/multicall/blob/master/src/Multicall3.sol\ninterface IMulticallTarget {\n struct Result {\n bool success;\n bytes returnData;\n }\n\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external;\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results);\n}\n\n// contracts/interfaces/IZapRecipient.sol\n\ninterface IZapRecipient {\n function zap(address token, uint256 amount, bytes memory zapData) external payable returns (bytes4);\n}\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// contracts/interfaces/IFastBridgeV2.sol\n\ninterface IFastBridgeV2 is IFastBridge {\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n struct BridgeTxDetails {\n BridgeStatus status;\n uint32 destChainId;\n uint56 proofBlockTimestamp;\n address proofRelayer;\n }\n\n struct BridgeRelay {\n uint48 blockNumber;\n uint48 blockTimestamp;\n address relayer;\n }\n\n /// @notice New params introduced in the FastBridgeV2.\n /// We are passing fields from the older BridgeParams struct outside of this struct\n /// for backwards compatibility.\n /// Note: quoteRelayer and quoteExclusivitySeconds are either both zero (indicating no exclusivity)\n /// or both non-zero (indicating exclusivity for the given period).\n /// Note: zapNative \u003e 0 can NOT be used with destToken = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE (native token)\n /// @param quoteRelayer Relayer that provided the quote for the transaction\n /// @param quoteExclusivitySeconds Period of time the quote relayer is guaranteed exclusivity after user's deposit\n /// @param quoteId Unique quote identifier used for tracking the quote\n /// @param zapNative ETH value to send to the recipient (if any)\n /// @param zapData Parameters for the Zap to the destination recipient (if any)\n struct BridgeParamsV2 {\n address quoteRelayer;\n int256 quoteExclusivitySeconds;\n bytes quoteId;\n uint256 zapNative;\n bytes zapData;\n }\n\n /// @notice Updated bridge transaction struct to include parameters introduced in FastBridgeV2.\n /// Note: only `exclusivityRelayer` can fill such a transaction until `exclusivityEndTime`.\n struct BridgeTransactionV2 {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n // Note: sendChainGas flag from V1 is deprecated\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n address exclusivityRelayer;\n uint256 exclusivityEndTime;\n uint256 zapNative; // ETH value to send to the recipient (if any)\n bytes zapData; // data to pass for the Zap action (if any)\n }\n\n event BridgeQuoteDetails(bytes32 indexed transactionId, bytes quoteId);\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability\n /// to provide temporary exclusivity fill rights for the quote relayer.\n /// @param params The parameters required to bridge\n /// @param paramsV2 The parameters for exclusivity fill rights (optional, can be left empty)\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function relay(bytes memory request, address relayer) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param transactionId The transaction id associated with the encoded bridge transaction to prove\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital.\n /// @notice Can only send funds to the relayer address on the proof.\n /// @param request The encoded bridge transaction to claim on origin chain\n function claim(bytes memory request) external;\n\n /// @notice Cancels an outstanding bridge transaction in case optimistic bridging failed and returns the full amount\n /// to the original sender.\n /// @param request The encoded bridge transaction to refund\n function cancel(bytes memory request) external;\n\n /// @notice Checks if a transaction has been relayed\n /// @param transactionId The ID of the transaction to check\n /// @return True if the transaction has been relayed, false otherwise\n function bridgeRelays(bytes32 transactionId) external view returns (bool);\n\n /// @notice Returns the status of a bridge transaction\n /// @param transactionId The ID of the bridge transaction\n /// @return BridgeStatus Status of the bridge transaction\n function bridgeStatuses(bytes32 transactionId) external view returns (BridgeStatus);\n\n /// @notice Returns the timestamp and relayer of a bridge proof\n /// @param transactionId The ID of the bridge transaction\n /// @return timestamp The timestamp of the bridge proof\n /// @return relayer The relayer address of the bridge proof\n function bridgeProofs(bytes32 transactionId) external view returns (uint96 timestamp, address relayer);\n\n /// @notice Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\n /// @param request The bridge request to decode\n function getBridgeTransactionV2(bytes memory request) external view returns (BridgeTransactionV2 memory);\n}\n\n// contracts/utils/MulticallTarget.sol\n\n// solhint-disable avoid-low-level-calls\n/// @notice Template for a contract that supports batched calls (preserving the msg.sender).\n/// Only calls with zero msg.value could be batched.\nabstract contract MulticallTarget is IMulticallTarget {\n error MulticallTarget__UndeterminedRevert();\n\n /// @notice Perform a batched call to this contract, preserving the msg.sender.\n /// The return data from each call is discarded.\n /// @dev The method is non-payable, so only calls with `msg.value == 0` could be batched.\n /// It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag.\n /// Otherwise, the whole batch call will be reverted with the original revert reason.\n /// @param data List of abi-encoded calldata for the calls to perform.\n /// @param ignoreReverts Whether to ignore the revert errors from the calls.\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external {\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\n if (!success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(result);\n }\n }\n }\n\n /// @notice Perform a batched call to this contract, preserving the msg.sender.\n /// The return data from each call is preserved.\n /// @dev The method is non-payable, so only calls with `msg.value == 0` could be batched.\n /// It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag.\n /// Otherwise, the whole batch call will be reverted with the original revert reason.\n /// @param data List of abi-encoded calldata for the calls to perform.\n /// @param ignoreReverts Whether to ignore the revert errors from the calls.\n /// @return results List of results from the calls: `(success, returnData)`.\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results)\n {\n results = new Result[](data.length);\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (results[i].success, results[i].returnData) = address(this).delegatecall(data[i]);\n if (!results[i].success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(results[i].returnData);\n }\n }\n }\n\n /// @dev Bubbles the revert message from the underlying call.\n /// Note: preserves the same custom error or revert string, if one was used.\n /// Source: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v5.0.2/contracts/utils/Address.sol#L143-L158\n function _bubbleRevert(bytes memory returnData) internal pure {\n // Look for revert reason and bubble it up if present\n if (returnData.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n // solhint-disable-next-line no-inline-assembly\n assembly {\n let returndata_size := mload(returnData)\n revert(add(32, returnData), returndata_size)\n }\n } else {\n revert MulticallTarget__UndeterminedRevert();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// contracts/libs/BridgeTransactionV2.sol\n\n// solhint-disable no-inline-assembly\nlibrary BridgeTransactionV2Lib {\n uint16 internal constant VERSION = 2;\n\n // Offsets of the fields in the packed BridgeTransactionV2 struct\n // uint16 version [000 .. 002)\n // uint32 originChainId [002 .. 006)\n // uint32 destChainId [006 .. 010)\n // address originSender [010 .. 030)\n // address destRecipient [030 .. 050)\n // address originToken [050 .. 070)\n // address destToken [070 .. 090)\n // uint256 originAmount [090 .. 122)\n // uint256 destAmount [122 .. 154)\n // uint256 originFeeAmount [154 .. 186)\n // uint256 deadline [186 .. 218)\n // uint256 nonce [218 .. 250)\n // address exclusivityRelayer [250 .. 270)\n // uint256 exclusivityEndTime [270 .. 302)\n // uint256 zapNative [302 .. 334)\n // bytes zapData [334 .. ***)\n\n // forgefmt: disable-start\n uint256 private constant OFFSET_ORIGIN_CHAIN_ID = 2;\n uint256 private constant OFFSET_DEST_CHAIN_ID = 6;\n uint256 private constant OFFSET_ORIGIN_SENDER = 10;\n uint256 private constant OFFSET_DEST_RECIPIENT = 30;\n uint256 private constant OFFSET_ORIGIN_TOKEN = 50;\n uint256 private constant OFFSET_DEST_TOKEN = 70;\n uint256 private constant OFFSET_ORIGIN_AMOUNT = 90;\n uint256 private constant OFFSET_DEST_AMOUNT = 122;\n uint256 private constant OFFSET_ORIGIN_FEE_AMOUNT = 154;\n uint256 private constant OFFSET_DEADLINE = 186;\n uint256 private constant OFFSET_NONCE = 218;\n uint256 private constant OFFSET_EXCLUSIVITY_RELAYER = 250;\n uint256 private constant OFFSET_EXCLUSIVITY_END_TIME = 270;\n uint256 private constant OFFSET_ZAP_NATIVE = 302;\n uint256 private constant OFFSET_ZAP_DATA = 334;\n // forgefmt: disable-end\n\n error BridgeTransactionV2__InvalidEncodedTx();\n error BridgeTransactionV2__UnsupportedVersion(uint16 version);\n\n /// @notice Validates the encoded transaction to be a tightly packed encoded payload for BridgeTransactionV2.\n /// @dev Checks the minimum length and the version, use this function before decoding any of the fields.\n function validateV2(bytes calldata encodedTx) internal pure {\n // Check the minimum length: must at least include all static fields.\n if (encodedTx.length \u003c OFFSET_ZAP_DATA) revert BridgeTransactionV2__InvalidEncodedTx();\n // Once we validated the length, we can be sure that the version field is present.\n uint16 version_ = version(encodedTx);\n if (version_ != VERSION) revert BridgeTransactionV2__UnsupportedVersion(version_);\n }\n\n /// @notice Encodes the BridgeTransactionV2 struct by tightly packing the fields.\n /// @dev `abi.decode` will not work as a result of the tightly packed fields. Use `decodeV2` to decode instead.\n function encodeV2(IFastBridgeV2.BridgeTransactionV2 memory bridgeTx) internal pure returns (bytes memory) {\n // We split the encoding into two parts to avoid stack-too-deep error\n bytes memory firstPart = abi.encodePacked(\n VERSION,\n bridgeTx.originChainId,\n bridgeTx.destChainId,\n bridgeTx.originSender,\n bridgeTx.destRecipient,\n bridgeTx.originToken,\n bridgeTx.destToken,\n bridgeTx.originAmount\n );\n return abi.encodePacked(\n firstPart,\n bridgeTx.destAmount,\n bridgeTx.originFeeAmount,\n // Note: we skip the deprecated `sendChainGas` flag, which was present in BridgeTransaction V1\n bridgeTx.deadline,\n bridgeTx.nonce,\n // New V2 fields: exclusivity\n bridgeTx.exclusivityRelayer,\n bridgeTx.exclusivityEndTime,\n // New V2 fields: Zap\n bridgeTx.zapNative,\n bridgeTx.zapData\n );\n }\n\n /// @notice Decodes the BridgeTransactionV2 struct from the encoded transaction.\n /// @dev Encoded BridgeTransactionV2 struct must be tightly packed.\n /// Use `validateV2` before decoding to ensure the encoded transaction is valid.\n function decodeV2(bytes calldata encodedTx)\n internal\n pure\n returns (IFastBridgeV2.BridgeTransactionV2 memory bridgeTx)\n {\n bridgeTx.originChainId = originChainId(encodedTx);\n bridgeTx.destChainId = destChainId(encodedTx);\n bridgeTx.originSender = originSender(encodedTx);\n bridgeTx.destRecipient = destRecipient(encodedTx);\n bridgeTx.originToken = originToken(encodedTx);\n bridgeTx.destToken = destToken(encodedTx);\n bridgeTx.originAmount = originAmount(encodedTx);\n bridgeTx.destAmount = destAmount(encodedTx);\n bridgeTx.originFeeAmount = originFeeAmount(encodedTx);\n bridgeTx.deadline = deadline(encodedTx);\n bridgeTx.nonce = nonce(encodedTx);\n bridgeTx.exclusivityRelayer = exclusivityRelayer(encodedTx);\n bridgeTx.exclusivityEndTime = exclusivityEndTime(encodedTx);\n bridgeTx.zapNative = zapNative(encodedTx);\n bridgeTx.zapData = zapData(encodedTx);\n }\n\n /// @notice Extracts the version from the encoded transaction.\n function version(bytes calldata encodedTx) internal pure returns (uint16 version_) {\n // Load 32 bytes from the start and shift it 240 bits to the right to get the highest 16 bits.\n assembly {\n version_ := shr(240, calldataload(encodedTx.offset))\n }\n }\n\n /// @notice Extracts the origin chain ID from the encoded transaction.\n function originChainId(bytes calldata encodedTx) internal pure returns (uint32 originChainId_) {\n // Load 32 bytes from the offset and shift it 224 bits to the right to get the highest 32 bits.\n assembly {\n originChainId_ := shr(224, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_CHAIN_ID)))\n }\n }\n\n /// @notice Extracts the destination chain ID from the encoded transaction.\n function destChainId(bytes calldata encodedTx) internal pure returns (uint32 destChainId_) {\n // Load 32 bytes from the offset and shift it 224 bits to the right to get the highest 32 bits.\n assembly {\n destChainId_ := shr(224, calldataload(add(encodedTx.offset, OFFSET_DEST_CHAIN_ID)))\n }\n }\n\n /// @notice Extracts the origin sender from the encoded transaction.\n function originSender(bytes calldata encodedTx) internal pure returns (address originSender_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n originSender_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_SENDER)))\n }\n }\n\n /// @notice Extracts the destination recipient from the encoded transaction.\n function destRecipient(bytes calldata encodedTx) internal pure returns (address destRecipient_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n destRecipient_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_DEST_RECIPIENT)))\n }\n }\n\n /// @notice Extracts the origin token from the encoded transaction.\n function originToken(bytes calldata encodedTx) internal pure returns (address originToken_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n originToken_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_TOKEN)))\n }\n }\n\n /// @notice Extracts the destination token from the encoded transaction.\n function destToken(bytes calldata encodedTx) internal pure returns (address destToken_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n destToken_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_DEST_TOKEN)))\n }\n }\n\n /// @notice Extracts the origin amount from the encoded transaction.\n function originAmount(bytes calldata encodedTx) internal pure returns (uint256 originAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n originAmount_ := calldataload(add(encodedTx.offset, OFFSET_ORIGIN_AMOUNT))\n }\n }\n\n /// @notice Extracts the destination amount from the encoded transaction.\n function destAmount(bytes calldata encodedTx) internal pure returns (uint256 destAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n destAmount_ := calldataload(add(encodedTx.offset, OFFSET_DEST_AMOUNT))\n }\n }\n\n /// @notice Extracts the origin fee amount from the encoded transaction.\n function originFeeAmount(bytes calldata encodedTx) internal pure returns (uint256 originFeeAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n originFeeAmount_ := calldataload(add(encodedTx.offset, OFFSET_ORIGIN_FEE_AMOUNT))\n }\n }\n\n /// @notice Extracts the deadline from the encoded transaction.\n function deadline(bytes calldata encodedTx) internal pure returns (uint256 deadline_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n deadline_ := calldataload(add(encodedTx.offset, OFFSET_DEADLINE))\n }\n }\n\n /// @notice Extracts the nonce from the encoded transaction.\n function nonce(bytes calldata encodedTx) internal pure returns (uint256 nonce_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n nonce_ := calldataload(add(encodedTx.offset, OFFSET_NONCE))\n }\n }\n\n /// @notice Extracts the exclusivity relayer from the encoded transaction.\n function exclusivityRelayer(bytes calldata encodedTx) internal pure returns (address exclusivityRelayer_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n exclusivityRelayer_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_EXCLUSIVITY_RELAYER)))\n }\n }\n\n /// @notice Extracts the exclusivity end time from the encoded transaction.\n function exclusivityEndTime(bytes calldata encodedTx) internal pure returns (uint256 exclusivityEndTime_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n exclusivityEndTime_ := calldataload(add(encodedTx.offset, OFFSET_EXCLUSIVITY_END_TIME))\n }\n }\n\n /// @notice Extracts the Zap's native value from the encoded transaction.\n function zapNative(bytes calldata encodedTx) internal pure returns (uint256 zapNative_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n zapNative_ := calldataload(add(encodedTx.offset, OFFSET_ZAP_NATIVE))\n }\n }\n\n /// @notice Extracts the Zap's data from the encoded transaction.\n function zapData(bytes calldata encodedTx) internal pure returns (bytes calldata zapData_) {\n zapData_ = encodedTx[OFFSET_ZAP_DATA:];\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/AdminV2.sol\n\ncontract AdminV2 is AccessControlEnumerable, IAdminV2, IAdminV2Errors {\n using SafeERC20 for IERC20;\n\n /// @notice Address reserved for native gas token (ETH on Ethereum and most L2s, AVAX on Avalanche, etc)\n address public constant NATIVE_GAS_TOKEN = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Role identifier for Quoter API's off-chain authentication.\n /// @dev Only addresses with this role can post FastBridge quotes to the API.\n bytes32 public constant QUOTER_ROLE = keccak256(\"QUOTER_ROLE\");\n\n /// @notice Role identifier for Prover's on-chain authentication in FastBridge.\n /// @dev Only addresses with this role can provide proofs that a FastBridge request has been relayed.\n bytes32 public constant PROVER_ROLE = keccak256(\"PROVER_ROLE\");\n\n /// @notice Role identifier for Guard's on-chain authentication in FastBridge.\n /// @dev Only addresses with this role can dispute submitted relay proofs during the dispute period.\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n\n /// @notice Role identifier for Canceler's on-chain authentication in FastBridge.\n /// @dev Only addresses with this role can cancel a FastBridge transaction without the cancel delay.\n bytes32 public constant CANCELER_ROLE = keccak256(\"CANCELER_ROLE\");\n\n /// @notice Role identifier for Governor's on-chain administrative authority.\n /// @dev Only addresses with this role can perform administrative tasks within the contract.\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n /// @notice Denominator for fee rates, represents 100%.\n uint256 public constant FEE_BPS = 1e6;\n /// @notice Maximum protocol fee rate: 1% on origin amount.\n uint256 public constant FEE_RATE_MAX = 0.01e6;\n\n /// @notice Minimum cancel delay that can be set by the governor.\n uint256 public constant MIN_CANCEL_DELAY = 1 hours;\n /// @notice Default cancel delay set during the contract deployment.\n uint256 public constant DEFAULT_CANCEL_DELAY = 1 days;\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Delay for a transaction after which it could be permisionlessly cancelled\n uint256 public cancelDelay;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Use ZapNative V2 requests instead.\n uint256 public immutable chainGasAmount = 0;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n _setCancelDelay(DEFAULT_CANCEL_DELAY);\n }\n\n /// @notice Allows the contract governor to set the cancel delay. The cancel delay is the time after the transaction\n /// deadline after which it can be permissionlessly cancelled, if it hasn't been proven by any of the Relayers.\n function setCancelDelay(uint256 newCancelDelay) external onlyRole(GOVERNOR_ROLE) {\n _setCancelDelay(newCancelDelay);\n }\n\n /// @notice Allows the contract governor to set the protocol fee rate. The protocol fee is taken from the origin\n /// amount only for completed and claimed transactions.\n /// @dev The protocol fee is abstracted away from the relayers, they always operate using the amounts after fees:\n /// what they see as the origin amount emitted in the log is what they get credited with.\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n if (newFeeRate \u003e FEE_RATE_MAX) revert FeeRateAboveMax();\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n /// @notice Allows the contract governor to sweep the accumulated protocol fees in the contract.\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n emit FeesSwept(token, recipient, feeAmount);\n /// Sweep the fees as the last transaction action\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(recipient), feeAmount);\n } else {\n IERC20(token).safeTransfer(recipient, feeAmount);\n }\n }\n\n /// @notice Internal function to set the cancel delay. Security checks are performed outside of this function.\n function _setCancelDelay(uint256 newCancelDelay) private {\n if (newCancelDelay \u003c MIN_CANCEL_DELAY) revert CancelDelayBelowMin();\n uint256 oldCancelDelay = cancelDelay;\n cancelDelay = newCancelDelay;\n emit CancelDelayUpdated(oldCancelDelay, newCancelDelay);\n }\n}\n\n// contracts/FastBridgeV2.sol\n\n/// @notice FastBridgeV2 is a contract for bridging tokens across chains.\ncontract FastBridgeV2 is AdminV2, MulticallTarget, IFastBridgeV2, IFastBridgeV2Errors {\n using BridgeTransactionV2Lib for bytes;\n using SafeERC20 for IERC20;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n /// @notice Maximum length of accepted zapData\n uint256 public constant MAX_ZAP_DATA_LENGTH = 2 ** 16 - 1;\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeTxDetails) public bridgeTxDetails;\n /// @notice Relay details on destination chain\n mapping(bytes32 =\u003e BridgeRelay) public bridgeRelayDetails;\n /// @notice Unique bridge nonces tracked per originSender\n mapping(address =\u003e uint256) public senderNonces;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Replaced by senderNonces\n uint256 public immutable nonce = 0;\n /// @notice the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) AdminV2(_owner) {\n deployBlock = block.number;\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n bridge({\n params: params,\n paramsV2: BridgeParamsV2({\n quoteRelayer: address(0),\n quoteExclusivitySeconds: 0,\n quoteId: bytes(\"\"),\n zapNative: 0,\n zapData: bytes(\"\")\n })\n });\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes calldata request) external payable {\n // relay override will validate the request\n relay({request: request, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes calldata request, bytes32 destTxHash) external {\n request.validateV2();\n prove({transactionId: keccak256(request), destTxHash: destTxHash, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridgeV2\n function claim(bytes calldata request) external {\n // claim override will validate the request\n claim({request: request, to: address(0)});\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Aggregate the read operations from the same storage slot\n address disputedRelayer = $.proofRelayer;\n BridgeStatus status = $.status;\n uint56 proofBlockTimestamp = $.proofBlockTimestamp;\n // Can only dispute a RELAYER_PROVED transaction within the dispute period\n if (status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(proofBlockTimestamp) \u003e DISPUTE_PERIOD) {\n revert DisputePeriodPassed();\n }\n // Update status to REQUESTED and delete the disputed proof details\n // Note: these are storage writes\n $.status = BridgeStatus.REQUESTED;\n $.proofRelayer = address(0);\n $.proofBlockTimestamp = 0;\n\n emit BridgeProofDisputed(transactionId, disputedRelayer);\n }\n\n /// Note: this function is deprecated and will be removed in a future version.\n /// @inheritdoc IFastBridge\n function refund(bytes calldata request) external {\n cancel(request);\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // The correct relayer can only claim a RELAYER_PROVED transaction after the dispute period\n if ($.status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if ($.proofRelayer != relayer) revert SenderIncorrect();\n return _timeSince($.proofBlockTimestamp) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n /// @dev This method is added to achieve backwards compatibility with decoding requests into V1 structs:\n /// - `zapNative` is partially reported as a zero/non-zero flag\n /// - `zapData` is ignored\n /// In order to process all kinds of requests use getBridgeTransactionV2 instead.\n function getBridgeTransaction(bytes calldata request) external view returns (BridgeTransaction memory) {\n // Try decoding into V2 struct first. This will revert if V1 struct is passed\n try this.getBridgeTransactionV2(request) returns (BridgeTransactionV2 memory txV2) {\n // Note: we entirely ignore the zapData field, as it was not present in V1\n return BridgeTransaction({\n originChainId: txV2.originChainId,\n destChainId: txV2.destChainId,\n originSender: txV2.originSender,\n destRecipient: txV2.destRecipient,\n originToken: txV2.originToken,\n destToken: txV2.destToken,\n originAmount: txV2.originAmount,\n destAmount: txV2.destAmount,\n originFeeAmount: txV2.originFeeAmount,\n sendChainGas: txV2.zapNative != 0,\n deadline: txV2.deadline,\n nonce: txV2.nonce\n });\n } catch {\n // Fallback to V1 struct\n return abi.decode(request, (BridgeTransaction));\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function getBridgeTransactionV2(bytes calldata request) external pure returns (BridgeTransactionV2 memory) {\n request.validateV2();\n return BridgeTransactionV2Lib.decodeV2(request);\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) public payable {\n int256 exclusivityEndTime = 0;\n // if relayer exclusivity is not intended for this bridge, set exclusivityEndTime to static zero\n // otherwise, set exclusivity to expire at the current block ts offset by quoteExclusivitySeconds\n if (paramsV2.quoteRelayer != address(0)) {\n exclusivityEndTime = int256(block.timestamp) + paramsV2.quoteExclusivitySeconds;\n }\n _validateBridgeParams(params, paramsV2, exclusivityEndTime);\n\n // transfer tokens to bridge contract\n /// @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _takeBridgedUserAsset(params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) {\n originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n }\n\n // set status to requested\n bytes memory request = BridgeTransactionV2Lib.encodeV2(\n BridgeTransactionV2({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n deadline: params.deadline,\n nonce: senderNonces[params.sender]++, // increment nonce on every bridge\n exclusivityRelayer: paramsV2.quoteRelayer,\n // We checked exclusivityEndTime to be in range [0 .. params.deadline] above, so can safely cast\n exclusivityEndTime: uint256(exclusivityEndTime),\n zapNative: paramsV2.zapNative,\n zapData: paramsV2.zapData\n })\n );\n bytes32 transactionId = keccak256(request);\n // Note: the tx status will be updated throughout the tx lifecycle, while destChainId is set once here\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n bridgeTxDetails[transactionId].destChainId = params.dstChainId;\n\n emit BridgeRequested({\n transactionId: transactionId,\n sender: params.sender,\n request: request,\n destChainId: params.dstChainId,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n sendChainGas: paramsV2.zapNative != 0\n });\n emit BridgeQuoteDetails(transactionId, paramsV2.quoteId);\n }\n\n /// @inheritdoc IFastBridgeV2\n function relay(bytes calldata request, address relayer) public payable {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n _validateRelayParams(request, transactionId, relayer);\n // mark bridge transaction as relayed\n bridgeRelayDetails[transactionId] =\n BridgeRelay({blockNumber: uint48(block.number), blockTimestamp: uint48(block.timestamp), relayer: relayer});\n\n // transfer tokens to recipient on destination chain and trigger Zap if requested\n address to = request.destRecipient();\n address token = request.destToken();\n uint256 amount = request.destAmount();\n uint256 zapNative = request.zapNative();\n\n // Emit the event before any external calls\n emit BridgeRelayed({\n transactionId: transactionId,\n relayer: relayer,\n to: to,\n originChainId: request.originChainId(),\n originToken: request.originToken(),\n destToken: token,\n originAmount: request.originAmount(),\n destAmount: amount,\n chainGasAmount: zapNative\n });\n\n // All state changes have been done at this point, can proceed to the external calls.\n // This follows the checks-effects-interactions pattern to mitigate potential reentrancy attacks.\n if (token == NATIVE_GAS_TOKEN) {\n // For the native gas token, additional zapNative is not allowed\n if (zapNative != 0) revert ZapNativeNotSupported();\n // Check that the correct msg.value was sent\n if (msg.value != amount) revert MsgValueIncorrect();\n // Don't do a native transfer yet: we will handle it alongside the Zap below\n } else {\n // For ERC20s, we check that the correct msg.value was sent\n if (msg.value != zapNative) revert MsgValueIncorrect();\n // We need to transfer the tokens from the Relayer to the recipient first before performing an\n // optional post-transfer Zap.\n IERC20(token).safeTransferFrom(msg.sender, to, amount);\n }\n // At this point we have done:\n // - Transferred the requested amount of ERC20 tokens to the recipient.\n // At this point we have confirmed:\n // - For ERC20s: msg.value matches the requested zapNative amount.\n // - For the native gas token: msg.value matches the requested destAmount.\n // Remaining optional things to do:\n // - Forward the full msg.value to the recipient (if non-zero).\n // - Trigger a Zap (if zapData is present).\n bytes calldata zapData = request.zapData();\n if (zapData.length != 0) {\n // Zap Data is present: Zap has been requested by the recipient. Trigger it forwarding the full msg.value.\n\n // Note: if token has a fee on transfers, the recipient will have received less than `amount`.\n // This is a very niche edge case and should be handled by the recipient contract.\n _triggerZapWithChecks({recipient: to, token: token, amount: amount, zapData: zapData});\n } else if (msg.value != 0) {\n // Zap Data is missing, but msg.value was sent. This could happen in two different cases:\n // - Relay with the native gas token is happening.\n // - Relay with ERC20 is happening, with a `zapNative \u003e 0` request.\n // In both cases, we need to transfer the full msg.value to the recipient.\n Address.sendValue(payable(to), msg.value);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) public onlyRole(PROVER_ROLE) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n\n // Can only prove a REQUESTED transaction\n if ($.status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n // Update status to RELAYER_PROVED and store the proof details\n // Note: these are storage writes\n $.status = BridgeStatus.RELAYER_PROVED;\n $.proofBlockTimestamp = uint56(block.timestamp);\n $.proofRelayer = relayer;\n\n emit BridgeProofProvided(transactionId, relayer, destTxHash);\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes calldata request, address to) public {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Aggregate the read operations from the same storage slot\n address proofRelayer = $.proofRelayer;\n BridgeStatus status = $.status;\n uint56 proofBlockTimestamp = $.proofBlockTimestamp;\n\n // Can only claim a RELAYER_PROVED transaction after the dispute period\n if (status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(proofBlockTimestamp) \u003c= DISPUTE_PERIOD) {\n revert DisputePeriodNotPassed();\n }\n\n if (to == address(0)) {\n // Anyone could claim the funds to the proven relayer on their behalf\n to = proofRelayer;\n } else if (proofRelayer != msg.sender) {\n // Only the proven relayer could specify an address to claim the funds to\n revert SenderIncorrect();\n }\n\n // Update status to RELAYER_CLAIMED and transfer the origin collateral to the specified claim address\n // Note: this is a storage write\n $.status = BridgeStatus.RELAYER_CLAIMED;\n\n address token = request.originToken();\n uint256 amount = request.originAmount();\n // Update protocol fees if origin fee amount exists\n uint256 originFeeAmount = request.originFeeAmount();\n if (originFeeAmount \u003e 0) protocolFees[token] += originFeeAmount;\n // Emit the event before any external calls\n emit BridgeDepositClaimed(transactionId, proofRelayer, to, token, amount);\n // Complete the relayer claim as the last transaction action\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(to), amount);\n } else {\n IERC20(token).safeTransfer(to, amount);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function cancel(bytes calldata request) public {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Can only cancel a REQUESTED transaction after its deadline expires\n if ($.status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n uint256 deadline = request.deadline();\n // Permissionless cancel is only allowed after `cancelDelay` on top of the deadline\n if (!hasRole(CANCELER_ROLE, msg.sender)) deadline += cancelDelay;\n if (block.timestamp \u003c= deadline) revert DeadlineNotExceeded();\n // Update status to REFUNDED and return the full amount (collateral + protocol fees) to the original sender.\n // The protocol fees are only updated when the transaction is claimed, so we don't need to update them here.\n // Note: this is a storage write\n $.status = BridgeStatus.REFUNDED;\n\n address to = request.originSender();\n address token = request.originToken();\n uint256 amount = request.originAmount() + request.originFeeAmount();\n // Emit the event before any external calls\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n // Complete the user cancel as the last transaction action\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(to), amount);\n } else {\n IERC20(token).safeTransfer(to, amount);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeStatuses(bytes32 transactionId) public view returns (BridgeStatus status) {\n return bridgeTxDetails[transactionId].status;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeProofs(bytes32 transactionId) public view returns (uint96 timestamp, address relayer) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n\n timestamp = $.proofBlockTimestamp;\n relayer = $.proofRelayer;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeRelays(bytes32 transactionId) public view returns (bool) {\n // has this transactionId been relayed?\n return bridgeRelayDetails[transactionId].relayer != address(0);\n }\n\n /// @notice Takes the bridged asset from the user into FastBridgeV2 custody. It will be later\n /// claimed by the relayer who completed the relay on destination chain, or transferred back to the user\n /// via the cancel function should no one complete the relay.\n function _takeBridgedUserAsset(address token, uint256 amount) internal returns (uint256 amountTaken) {\n if (token == NATIVE_GAS_TOKEN) {\n // For the native gas token, we just need to check that the supplied msg.value is correct.\n // Supplied `msg.value` is already in FastBridgeV2 custody.\n if (amount != msg.value) revert MsgValueIncorrect();\n amountTaken = msg.value;\n } else {\n // For ERC20s, token is explicitly transferred from the user to FastBridgeV2.\n // We don't allow non-zero `msg.value` to avoid extra funds from being stuck in FastBridgeV2.\n if (msg.value != 0) revert MsgValueIncorrect();\n // Throw an explicit error if the provided token address is not a contract\n if (token.code.length == 0) revert TokenNotContract();\n amountTaken = IERC20(token).balanceOf(address(this));\n IERC20(token).safeTransferFrom(msg.sender, address(this), amount);\n // Use the balance difference as the amount taken in case of fee on transfer tokens.\n amountTaken = IERC20(token).balanceOf(address(this)) - amountTaken;\n }\n }\n\n /// @notice Calls the Recipient's hook function with the specified zapData and performs\n /// all the necessary checks for the returned value.\n function _triggerZapWithChecks(address recipient, address token, uint256 amount, bytes calldata zapData) internal {\n // This will bubble any revert messages from the hook function\n bytes memory returnData = Address.functionCallWithValue({\n target: recipient,\n data: abi.encodeCall(IZapRecipient.zap, (token, amount, zapData)),\n // Note: see `relay()` for reasoning behind passing msg.value\n value: msg.value\n });\n // Explicit revert if no return data at all\n if (returnData.length == 0) revert RecipientNoReturnValue();\n // Check that exactly a single return value was returned\n if (returnData.length != 32) revert RecipientIncorrectReturnValue();\n // Return value should be abi-encoded hook function selector\n if (bytes32(returnData) != bytes32(IZapRecipient.zap.selector)) {\n revert RecipientIncorrectReturnValue();\n }\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint56(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint56).max but\n /// proof.timestamp \u003c type(uint56).max via unchecked statement\n /// @param proofBlockTimestamp The bridge proof block timestamp\n /// @return delta Time delta since proof submitted\n function _timeSince(uint56 proofBlockTimestamp) internal view returns (uint256 delta) {\n unchecked {\n delta = uint56(block.timestamp) - proofBlockTimestamp;\n }\n }\n\n /// @notice Performs all the necessary checks for a bridge to happen.\n /// @dev There's no good way to refactor this function to reduce cyclomatic complexity due to\n /// the number of checks that need to be performed, so we skip the code-complexity rule here.\n // solhint-disable-next-line code-complexity\n function _validateBridgeParams(\n BridgeParams memory params,\n BridgeParamsV2 memory paramsV2,\n int256 exclusivityEndTime\n )\n internal\n view\n {\n // Check V1 (legacy) params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.sender == address(0) || params.to == address(0)) revert ZeroAddress();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n // Check V2 params\n if (paramsV2.zapData.length \u003e MAX_ZAP_DATA_LENGTH) revert ZapDataLengthAboveMax();\n if (paramsV2.zapNative != 0 \u0026\u0026 params.destToken == NATIVE_GAS_TOKEN) {\n revert ZapNativeNotSupported();\n }\n // exclusivityEndTime must be in range [0 .. params.deadline]\n if (exclusivityEndTime \u003c 0 || exclusivityEndTime \u003e int256(params.deadline)) {\n revert ExclusivityParamsIncorrect();\n }\n }\n\n /// @notice Performs all the necessary checks for a relay to happen.\n function _validateRelayParams(bytes calldata request, bytes32 transactionId, address relayer) internal view {\n if (relayer == address(0)) revert ZeroAddress();\n // Check if the transaction has already been relayed\n if (bridgeRelays(transactionId)) revert TransactionRelayed();\n if (request.destChainId() != block.chainid) revert ChainIncorrect();\n // Check the deadline for relay to happen\n if (block.timestamp \u003e request.deadline()) revert DeadlineExceeded();\n // Check the exclusivity period, if it is still ongoing\n address exclRelayer = request.exclusivityRelayer();\n if (exclRelayer != address(0) \u0026\u0026 exclRelayer != relayer \u0026\u0026 block.timestamp \u003c= request.exclusivityEndTime()) {\n revert ExclusivityPeriodNotPassed();\n }\n }\n}\n","language":"Solidity","languageVersion":"0.8.24","compilerVersion":"0.8.24","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"","srcMapRuntime":"","abiDefinition":[{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"}],"userDoc":{"kind":"user","methods":{},"version":1},"developerDoc":{"details":"Interface of the ERC165 standard, as defined in the https://eips.ethereum.org/EIPS/eip-165[EIP]. Implementers can declare support of contract interfaces, which can then be queried by others ({ERC165Checker}). For an implementation, see {ERC165}.","kind":"dev","methods":{"supportsInterface(bytes4)":{"details":"Returns true if this contract implements the interface defined by `interfaceId`. See the corresponding https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section] to learn more about how these ids are created. This function call must use less than 30 000 gas."}},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"bytes4\",\"name\":\"interfaceId\",\"type\":\"bytes4\"}],\"name\":\"supportsInterface\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"}],\"devdoc\":{\"details\":\"Interface of the ERC165 standard, as defined in the https://eips.ethereum.org/EIPS/eip-165[EIP]. Implementers can declare support of contract interfaces, which can then be queried by others ({ERC165Checker}). For an implementation, see {ERC165}.\",\"kind\":\"dev\",\"methods\":{\"supportsInterface(bytes4)\":{\"details\":\"Returns true if this contract implements the interface defined by `interfaceId`. See the corresponding https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section] to learn more about how these ids are created. This function call must use less than 30 000 gas.\"}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeV2.sol\":\"IERC165\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeV2.sol\":{\"keccak256\":\"0xac79c463688a682ca706a4ef95e7817b83548cdfa8182ba0426ac7e5e07613d8\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://b3ecb7097381287cafc3a73f3a2bb03565115ebb682a85064e0b0dc2f7e2919d\",\"dweb:/ipfs/QmatruW3nYZTksf3CeQ8wwiAG4c7xoEJBEp6drHPtFLBRK\"]}},\"version\":1}"},"hashes":{"supportsInterface(bytes4)":"01ffc9a7"}},"solidity/FastBridgeV2.sol:IERC20":{"code":"0x","runtime-code":"0x","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.24 ^0.8.20 ^0.8.4;\n\n// contracts/interfaces/IAdminV2.sol\n\ninterface IAdminV2 {\n event CancelDelayUpdated(uint256 oldCancelDelay, uint256 newCancelDelay);\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n function setCancelDelay(uint256 newCancelDelay) external;\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n}\n\n// contracts/interfaces/IAdminV2Errors.sol\n\ninterface IAdminV2Errors {\n error CancelDelayBelowMin();\n error FeeRateAboveMax();\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IFastBridgeV2Errors.sol\n\ninterface IFastBridgeV2Errors {\n error AmountIncorrect();\n error ChainIncorrect();\n error ExclusivityParamsIncorrect();\n error MsgValueIncorrect();\n error SenderIncorrect();\n error StatusIncorrect();\n error TokenNotContract();\n error ZapDataLengthAboveMax();\n error ZapNativeNotSupported();\n error ZeroAddress();\n\n error RecipientIncorrectReturnValue();\n error RecipientNoReturnValue();\n\n error DeadlineExceeded();\n error DeadlineNotExceeded();\n error DeadlineTooShort();\n error DisputePeriodNotPassed();\n error DisputePeriodPassed();\n error ExclusivityPeriodNotPassed();\n\n error TransactionRelayed();\n}\n\n// contracts/interfaces/IMulticallTarget.sol\n\n/// @notice Interface for a contract that can be called multiple times by the same caller. Inspired by MulticallV3:\n/// https://github.com/mds1/multicall/blob/master/src/Multicall3.sol\ninterface IMulticallTarget {\n struct Result {\n bool success;\n bytes returnData;\n }\n\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external;\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results);\n}\n\n// contracts/interfaces/IZapRecipient.sol\n\ninterface IZapRecipient {\n function zap(address token, uint256 amount, bytes memory zapData) external payable returns (bytes4);\n}\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// contracts/interfaces/IFastBridgeV2.sol\n\ninterface IFastBridgeV2 is IFastBridge {\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n struct BridgeTxDetails {\n BridgeStatus status;\n uint32 destChainId;\n uint56 proofBlockTimestamp;\n address proofRelayer;\n }\n\n struct BridgeRelay {\n uint48 blockNumber;\n uint48 blockTimestamp;\n address relayer;\n }\n\n /// @notice New params introduced in the FastBridgeV2.\n /// We are passing fields from the older BridgeParams struct outside of this struct\n /// for backwards compatibility.\n /// Note: quoteRelayer and quoteExclusivitySeconds are either both zero (indicating no exclusivity)\n /// or both non-zero (indicating exclusivity for the given period).\n /// Note: zapNative \u003e 0 can NOT be used with destToken = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE (native token)\n /// @param quoteRelayer Relayer that provided the quote for the transaction\n /// @param quoteExclusivitySeconds Period of time the quote relayer is guaranteed exclusivity after user's deposit\n /// @param quoteId Unique quote identifier used for tracking the quote\n /// @param zapNative ETH value to send to the recipient (if any)\n /// @param zapData Parameters for the Zap to the destination recipient (if any)\n struct BridgeParamsV2 {\n address quoteRelayer;\n int256 quoteExclusivitySeconds;\n bytes quoteId;\n uint256 zapNative;\n bytes zapData;\n }\n\n /// @notice Updated bridge transaction struct to include parameters introduced in FastBridgeV2.\n /// Note: only `exclusivityRelayer` can fill such a transaction until `exclusivityEndTime`.\n struct BridgeTransactionV2 {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n // Note: sendChainGas flag from V1 is deprecated\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n address exclusivityRelayer;\n uint256 exclusivityEndTime;\n uint256 zapNative; // ETH value to send to the recipient (if any)\n bytes zapData; // data to pass for the Zap action (if any)\n }\n\n event BridgeQuoteDetails(bytes32 indexed transactionId, bytes quoteId);\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability\n /// to provide temporary exclusivity fill rights for the quote relayer.\n /// @param params The parameters required to bridge\n /// @param paramsV2 The parameters for exclusivity fill rights (optional, can be left empty)\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function relay(bytes memory request, address relayer) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param transactionId The transaction id associated with the encoded bridge transaction to prove\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital.\n /// @notice Can only send funds to the relayer address on the proof.\n /// @param request The encoded bridge transaction to claim on origin chain\n function claim(bytes memory request) external;\n\n /// @notice Cancels an outstanding bridge transaction in case optimistic bridging failed and returns the full amount\n /// to the original sender.\n /// @param request The encoded bridge transaction to refund\n function cancel(bytes memory request) external;\n\n /// @notice Checks if a transaction has been relayed\n /// @param transactionId The ID of the transaction to check\n /// @return True if the transaction has been relayed, false otherwise\n function bridgeRelays(bytes32 transactionId) external view returns (bool);\n\n /// @notice Returns the status of a bridge transaction\n /// @param transactionId The ID of the bridge transaction\n /// @return BridgeStatus Status of the bridge transaction\n function bridgeStatuses(bytes32 transactionId) external view returns (BridgeStatus);\n\n /// @notice Returns the timestamp and relayer of a bridge proof\n /// @param transactionId The ID of the bridge transaction\n /// @return timestamp The timestamp of the bridge proof\n /// @return relayer The relayer address of the bridge proof\n function bridgeProofs(bytes32 transactionId) external view returns (uint96 timestamp, address relayer);\n\n /// @notice Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\n /// @param request The bridge request to decode\n function getBridgeTransactionV2(bytes memory request) external view returns (BridgeTransactionV2 memory);\n}\n\n// contracts/utils/MulticallTarget.sol\n\n// solhint-disable avoid-low-level-calls\n/// @notice Template for a contract that supports batched calls (preserving the msg.sender).\n/// Only calls with zero msg.value could be batched.\nabstract contract MulticallTarget is IMulticallTarget {\n error MulticallTarget__UndeterminedRevert();\n\n /// @notice Perform a batched call to this contract, preserving the msg.sender.\n /// The return data from each call is discarded.\n /// @dev The method is non-payable, so only calls with `msg.value == 0` could be batched.\n /// It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag.\n /// Otherwise, the whole batch call will be reverted with the original revert reason.\n /// @param data List of abi-encoded calldata for the calls to perform.\n /// @param ignoreReverts Whether to ignore the revert errors from the calls.\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external {\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\n if (!success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(result);\n }\n }\n }\n\n /// @notice Perform a batched call to this contract, preserving the msg.sender.\n /// The return data from each call is preserved.\n /// @dev The method is non-payable, so only calls with `msg.value == 0` could be batched.\n /// It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag.\n /// Otherwise, the whole batch call will be reverted with the original revert reason.\n /// @param data List of abi-encoded calldata for the calls to perform.\n /// @param ignoreReverts Whether to ignore the revert errors from the calls.\n /// @return results List of results from the calls: `(success, returnData)`.\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results)\n {\n results = new Result[](data.length);\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (results[i].success, results[i].returnData) = address(this).delegatecall(data[i]);\n if (!results[i].success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(results[i].returnData);\n }\n }\n }\n\n /// @dev Bubbles the revert message from the underlying call.\n /// Note: preserves the same custom error or revert string, if one was used.\n /// Source: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v5.0.2/contracts/utils/Address.sol#L143-L158\n function _bubbleRevert(bytes memory returnData) internal pure {\n // Look for revert reason and bubble it up if present\n if (returnData.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n // solhint-disable-next-line no-inline-assembly\n assembly {\n let returndata_size := mload(returnData)\n revert(add(32, returnData), returndata_size)\n }\n } else {\n revert MulticallTarget__UndeterminedRevert();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// contracts/libs/BridgeTransactionV2.sol\n\n// solhint-disable no-inline-assembly\nlibrary BridgeTransactionV2Lib {\n uint16 internal constant VERSION = 2;\n\n // Offsets of the fields in the packed BridgeTransactionV2 struct\n // uint16 version [000 .. 002)\n // uint32 originChainId [002 .. 006)\n // uint32 destChainId [006 .. 010)\n // address originSender [010 .. 030)\n // address destRecipient [030 .. 050)\n // address originToken [050 .. 070)\n // address destToken [070 .. 090)\n // uint256 originAmount [090 .. 122)\n // uint256 destAmount [122 .. 154)\n // uint256 originFeeAmount [154 .. 186)\n // uint256 deadline [186 .. 218)\n // uint256 nonce [218 .. 250)\n // address exclusivityRelayer [250 .. 270)\n // uint256 exclusivityEndTime [270 .. 302)\n // uint256 zapNative [302 .. 334)\n // bytes zapData [334 .. ***)\n\n // forgefmt: disable-start\n uint256 private constant OFFSET_ORIGIN_CHAIN_ID = 2;\n uint256 private constant OFFSET_DEST_CHAIN_ID = 6;\n uint256 private constant OFFSET_ORIGIN_SENDER = 10;\n uint256 private constant OFFSET_DEST_RECIPIENT = 30;\n uint256 private constant OFFSET_ORIGIN_TOKEN = 50;\n uint256 private constant OFFSET_DEST_TOKEN = 70;\n uint256 private constant OFFSET_ORIGIN_AMOUNT = 90;\n uint256 private constant OFFSET_DEST_AMOUNT = 122;\n uint256 private constant OFFSET_ORIGIN_FEE_AMOUNT = 154;\n uint256 private constant OFFSET_DEADLINE = 186;\n uint256 private constant OFFSET_NONCE = 218;\n uint256 private constant OFFSET_EXCLUSIVITY_RELAYER = 250;\n uint256 private constant OFFSET_EXCLUSIVITY_END_TIME = 270;\n uint256 private constant OFFSET_ZAP_NATIVE = 302;\n uint256 private constant OFFSET_ZAP_DATA = 334;\n // forgefmt: disable-end\n\n error BridgeTransactionV2__InvalidEncodedTx();\n error BridgeTransactionV2__UnsupportedVersion(uint16 version);\n\n /// @notice Validates the encoded transaction to be a tightly packed encoded payload for BridgeTransactionV2.\n /// @dev Checks the minimum length and the version, use this function before decoding any of the fields.\n function validateV2(bytes calldata encodedTx) internal pure {\n // Check the minimum length: must at least include all static fields.\n if (encodedTx.length \u003c OFFSET_ZAP_DATA) revert BridgeTransactionV2__InvalidEncodedTx();\n // Once we validated the length, we can be sure that the version field is present.\n uint16 version_ = version(encodedTx);\n if (version_ != VERSION) revert BridgeTransactionV2__UnsupportedVersion(version_);\n }\n\n /// @notice Encodes the BridgeTransactionV2 struct by tightly packing the fields.\n /// @dev `abi.decode` will not work as a result of the tightly packed fields. Use `decodeV2` to decode instead.\n function encodeV2(IFastBridgeV2.BridgeTransactionV2 memory bridgeTx) internal pure returns (bytes memory) {\n // We split the encoding into two parts to avoid stack-too-deep error\n bytes memory firstPart = abi.encodePacked(\n VERSION,\n bridgeTx.originChainId,\n bridgeTx.destChainId,\n bridgeTx.originSender,\n bridgeTx.destRecipient,\n bridgeTx.originToken,\n bridgeTx.destToken,\n bridgeTx.originAmount\n );\n return abi.encodePacked(\n firstPart,\n bridgeTx.destAmount,\n bridgeTx.originFeeAmount,\n // Note: we skip the deprecated `sendChainGas` flag, which was present in BridgeTransaction V1\n bridgeTx.deadline,\n bridgeTx.nonce,\n // New V2 fields: exclusivity\n bridgeTx.exclusivityRelayer,\n bridgeTx.exclusivityEndTime,\n // New V2 fields: Zap\n bridgeTx.zapNative,\n bridgeTx.zapData\n );\n }\n\n /// @notice Decodes the BridgeTransactionV2 struct from the encoded transaction.\n /// @dev Encoded BridgeTransactionV2 struct must be tightly packed.\n /// Use `validateV2` before decoding to ensure the encoded transaction is valid.\n function decodeV2(bytes calldata encodedTx)\n internal\n pure\n returns (IFastBridgeV2.BridgeTransactionV2 memory bridgeTx)\n {\n bridgeTx.originChainId = originChainId(encodedTx);\n bridgeTx.destChainId = destChainId(encodedTx);\n bridgeTx.originSender = originSender(encodedTx);\n bridgeTx.destRecipient = destRecipient(encodedTx);\n bridgeTx.originToken = originToken(encodedTx);\n bridgeTx.destToken = destToken(encodedTx);\n bridgeTx.originAmount = originAmount(encodedTx);\n bridgeTx.destAmount = destAmount(encodedTx);\n bridgeTx.originFeeAmount = originFeeAmount(encodedTx);\n bridgeTx.deadline = deadline(encodedTx);\n bridgeTx.nonce = nonce(encodedTx);\n bridgeTx.exclusivityRelayer = exclusivityRelayer(encodedTx);\n bridgeTx.exclusivityEndTime = exclusivityEndTime(encodedTx);\n bridgeTx.zapNative = zapNative(encodedTx);\n bridgeTx.zapData = zapData(encodedTx);\n }\n\n /// @notice Extracts the version from the encoded transaction.\n function version(bytes calldata encodedTx) internal pure returns (uint16 version_) {\n // Load 32 bytes from the start and shift it 240 bits to the right to get the highest 16 bits.\n assembly {\n version_ := shr(240, calldataload(encodedTx.offset))\n }\n }\n\n /// @notice Extracts the origin chain ID from the encoded transaction.\n function originChainId(bytes calldata encodedTx) internal pure returns (uint32 originChainId_) {\n // Load 32 bytes from the offset and shift it 224 bits to the right to get the highest 32 bits.\n assembly {\n originChainId_ := shr(224, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_CHAIN_ID)))\n }\n }\n\n /// @notice Extracts the destination chain ID from the encoded transaction.\n function destChainId(bytes calldata encodedTx) internal pure returns (uint32 destChainId_) {\n // Load 32 bytes from the offset and shift it 224 bits to the right to get the highest 32 bits.\n assembly {\n destChainId_ := shr(224, calldataload(add(encodedTx.offset, OFFSET_DEST_CHAIN_ID)))\n }\n }\n\n /// @notice Extracts the origin sender from the encoded transaction.\n function originSender(bytes calldata encodedTx) internal pure returns (address originSender_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n originSender_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_SENDER)))\n }\n }\n\n /// @notice Extracts the destination recipient from the encoded transaction.\n function destRecipient(bytes calldata encodedTx) internal pure returns (address destRecipient_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n destRecipient_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_DEST_RECIPIENT)))\n }\n }\n\n /// @notice Extracts the origin token from the encoded transaction.\n function originToken(bytes calldata encodedTx) internal pure returns (address originToken_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n originToken_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_TOKEN)))\n }\n }\n\n /// @notice Extracts the destination token from the encoded transaction.\n function destToken(bytes calldata encodedTx) internal pure returns (address destToken_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n destToken_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_DEST_TOKEN)))\n }\n }\n\n /// @notice Extracts the origin amount from the encoded transaction.\n function originAmount(bytes calldata encodedTx) internal pure returns (uint256 originAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n originAmount_ := calldataload(add(encodedTx.offset, OFFSET_ORIGIN_AMOUNT))\n }\n }\n\n /// @notice Extracts the destination amount from the encoded transaction.\n function destAmount(bytes calldata encodedTx) internal pure returns (uint256 destAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n destAmount_ := calldataload(add(encodedTx.offset, OFFSET_DEST_AMOUNT))\n }\n }\n\n /// @notice Extracts the origin fee amount from the encoded transaction.\n function originFeeAmount(bytes calldata encodedTx) internal pure returns (uint256 originFeeAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n originFeeAmount_ := calldataload(add(encodedTx.offset, OFFSET_ORIGIN_FEE_AMOUNT))\n }\n }\n\n /// @notice Extracts the deadline from the encoded transaction.\n function deadline(bytes calldata encodedTx) internal pure returns (uint256 deadline_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n deadline_ := calldataload(add(encodedTx.offset, OFFSET_DEADLINE))\n }\n }\n\n /// @notice Extracts the nonce from the encoded transaction.\n function nonce(bytes calldata encodedTx) internal pure returns (uint256 nonce_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n nonce_ := calldataload(add(encodedTx.offset, OFFSET_NONCE))\n }\n }\n\n /// @notice Extracts the exclusivity relayer from the encoded transaction.\n function exclusivityRelayer(bytes calldata encodedTx) internal pure returns (address exclusivityRelayer_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n exclusivityRelayer_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_EXCLUSIVITY_RELAYER)))\n }\n }\n\n /// @notice Extracts the exclusivity end time from the encoded transaction.\n function exclusivityEndTime(bytes calldata encodedTx) internal pure returns (uint256 exclusivityEndTime_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n exclusivityEndTime_ := calldataload(add(encodedTx.offset, OFFSET_EXCLUSIVITY_END_TIME))\n }\n }\n\n /// @notice Extracts the Zap's native value from the encoded transaction.\n function zapNative(bytes calldata encodedTx) internal pure returns (uint256 zapNative_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n zapNative_ := calldataload(add(encodedTx.offset, OFFSET_ZAP_NATIVE))\n }\n }\n\n /// @notice Extracts the Zap's data from the encoded transaction.\n function zapData(bytes calldata encodedTx) internal pure returns (bytes calldata zapData_) {\n zapData_ = encodedTx[OFFSET_ZAP_DATA:];\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/AdminV2.sol\n\ncontract AdminV2 is AccessControlEnumerable, IAdminV2, IAdminV2Errors {\n using SafeERC20 for IERC20;\n\n /// @notice Address reserved for native gas token (ETH on Ethereum and most L2s, AVAX on Avalanche, etc)\n address public constant NATIVE_GAS_TOKEN = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Role identifier for Quoter API's off-chain authentication.\n /// @dev Only addresses with this role can post FastBridge quotes to the API.\n bytes32 public constant QUOTER_ROLE = keccak256(\"QUOTER_ROLE\");\n\n /// @notice Role identifier for Prover's on-chain authentication in FastBridge.\n /// @dev Only addresses with this role can provide proofs that a FastBridge request has been relayed.\n bytes32 public constant PROVER_ROLE = keccak256(\"PROVER_ROLE\");\n\n /// @notice Role identifier for Guard's on-chain authentication in FastBridge.\n /// @dev Only addresses with this role can dispute submitted relay proofs during the dispute period.\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n\n /// @notice Role identifier for Canceler's on-chain authentication in FastBridge.\n /// @dev Only addresses with this role can cancel a FastBridge transaction without the cancel delay.\n bytes32 public constant CANCELER_ROLE = keccak256(\"CANCELER_ROLE\");\n\n /// @notice Role identifier for Governor's on-chain administrative authority.\n /// @dev Only addresses with this role can perform administrative tasks within the contract.\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n /// @notice Denominator for fee rates, represents 100%.\n uint256 public constant FEE_BPS = 1e6;\n /// @notice Maximum protocol fee rate: 1% on origin amount.\n uint256 public constant FEE_RATE_MAX = 0.01e6;\n\n /// @notice Minimum cancel delay that can be set by the governor.\n uint256 public constant MIN_CANCEL_DELAY = 1 hours;\n /// @notice Default cancel delay set during the contract deployment.\n uint256 public constant DEFAULT_CANCEL_DELAY = 1 days;\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Delay for a transaction after which it could be permisionlessly cancelled\n uint256 public cancelDelay;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Use ZapNative V2 requests instead.\n uint256 public immutable chainGasAmount = 0;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n _setCancelDelay(DEFAULT_CANCEL_DELAY);\n }\n\n /// @notice Allows the contract governor to set the cancel delay. The cancel delay is the time after the transaction\n /// deadline after which it can be permissionlessly cancelled, if it hasn't been proven by any of the Relayers.\n function setCancelDelay(uint256 newCancelDelay) external onlyRole(GOVERNOR_ROLE) {\n _setCancelDelay(newCancelDelay);\n }\n\n /// @notice Allows the contract governor to set the protocol fee rate. The protocol fee is taken from the origin\n /// amount only for completed and claimed transactions.\n /// @dev The protocol fee is abstracted away from the relayers, they always operate using the amounts after fees:\n /// what they see as the origin amount emitted in the log is what they get credited with.\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n if (newFeeRate \u003e FEE_RATE_MAX) revert FeeRateAboveMax();\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n /// @notice Allows the contract governor to sweep the accumulated protocol fees in the contract.\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n emit FeesSwept(token, recipient, feeAmount);\n /// Sweep the fees as the last transaction action\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(recipient), feeAmount);\n } else {\n IERC20(token).safeTransfer(recipient, feeAmount);\n }\n }\n\n /// @notice Internal function to set the cancel delay. Security checks are performed outside of this function.\n function _setCancelDelay(uint256 newCancelDelay) private {\n if (newCancelDelay \u003c MIN_CANCEL_DELAY) revert CancelDelayBelowMin();\n uint256 oldCancelDelay = cancelDelay;\n cancelDelay = newCancelDelay;\n emit CancelDelayUpdated(oldCancelDelay, newCancelDelay);\n }\n}\n\n// contracts/FastBridgeV2.sol\n\n/// @notice FastBridgeV2 is a contract for bridging tokens across chains.\ncontract FastBridgeV2 is AdminV2, MulticallTarget, IFastBridgeV2, IFastBridgeV2Errors {\n using BridgeTransactionV2Lib for bytes;\n using SafeERC20 for IERC20;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n /// @notice Maximum length of accepted zapData\n uint256 public constant MAX_ZAP_DATA_LENGTH = 2 ** 16 - 1;\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeTxDetails) public bridgeTxDetails;\n /// @notice Relay details on destination chain\n mapping(bytes32 =\u003e BridgeRelay) public bridgeRelayDetails;\n /// @notice Unique bridge nonces tracked per originSender\n mapping(address =\u003e uint256) public senderNonces;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Replaced by senderNonces\n uint256 public immutable nonce = 0;\n /// @notice the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) AdminV2(_owner) {\n deployBlock = block.number;\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n bridge({\n params: params,\n paramsV2: BridgeParamsV2({\n quoteRelayer: address(0),\n quoteExclusivitySeconds: 0,\n quoteId: bytes(\"\"),\n zapNative: 0,\n zapData: bytes(\"\")\n })\n });\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes calldata request) external payable {\n // relay override will validate the request\n relay({request: request, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes calldata request, bytes32 destTxHash) external {\n request.validateV2();\n prove({transactionId: keccak256(request), destTxHash: destTxHash, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridgeV2\n function claim(bytes calldata request) external {\n // claim override will validate the request\n claim({request: request, to: address(0)});\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Aggregate the read operations from the same storage slot\n address disputedRelayer = $.proofRelayer;\n BridgeStatus status = $.status;\n uint56 proofBlockTimestamp = $.proofBlockTimestamp;\n // Can only dispute a RELAYER_PROVED transaction within the dispute period\n if (status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(proofBlockTimestamp) \u003e DISPUTE_PERIOD) {\n revert DisputePeriodPassed();\n }\n // Update status to REQUESTED and delete the disputed proof details\n // Note: these are storage writes\n $.status = BridgeStatus.REQUESTED;\n $.proofRelayer = address(0);\n $.proofBlockTimestamp = 0;\n\n emit BridgeProofDisputed(transactionId, disputedRelayer);\n }\n\n /// Note: this function is deprecated and will be removed in a future version.\n /// @inheritdoc IFastBridge\n function refund(bytes calldata request) external {\n cancel(request);\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // The correct relayer can only claim a RELAYER_PROVED transaction after the dispute period\n if ($.status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if ($.proofRelayer != relayer) revert SenderIncorrect();\n return _timeSince($.proofBlockTimestamp) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n /// @dev This method is added to achieve backwards compatibility with decoding requests into V1 structs:\n /// - `zapNative` is partially reported as a zero/non-zero flag\n /// - `zapData` is ignored\n /// In order to process all kinds of requests use getBridgeTransactionV2 instead.\n function getBridgeTransaction(bytes calldata request) external view returns (BridgeTransaction memory) {\n // Try decoding into V2 struct first. This will revert if V1 struct is passed\n try this.getBridgeTransactionV2(request) returns (BridgeTransactionV2 memory txV2) {\n // Note: we entirely ignore the zapData field, as it was not present in V1\n return BridgeTransaction({\n originChainId: txV2.originChainId,\n destChainId: txV2.destChainId,\n originSender: txV2.originSender,\n destRecipient: txV2.destRecipient,\n originToken: txV2.originToken,\n destToken: txV2.destToken,\n originAmount: txV2.originAmount,\n destAmount: txV2.destAmount,\n originFeeAmount: txV2.originFeeAmount,\n sendChainGas: txV2.zapNative != 0,\n deadline: txV2.deadline,\n nonce: txV2.nonce\n });\n } catch {\n // Fallback to V1 struct\n return abi.decode(request, (BridgeTransaction));\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function getBridgeTransactionV2(bytes calldata request) external pure returns (BridgeTransactionV2 memory) {\n request.validateV2();\n return BridgeTransactionV2Lib.decodeV2(request);\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) public payable {\n int256 exclusivityEndTime = 0;\n // if relayer exclusivity is not intended for this bridge, set exclusivityEndTime to static zero\n // otherwise, set exclusivity to expire at the current block ts offset by quoteExclusivitySeconds\n if (paramsV2.quoteRelayer != address(0)) {\n exclusivityEndTime = int256(block.timestamp) + paramsV2.quoteExclusivitySeconds;\n }\n _validateBridgeParams(params, paramsV2, exclusivityEndTime);\n\n // transfer tokens to bridge contract\n /// @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _takeBridgedUserAsset(params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) {\n originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n }\n\n // set status to requested\n bytes memory request = BridgeTransactionV2Lib.encodeV2(\n BridgeTransactionV2({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n deadline: params.deadline,\n nonce: senderNonces[params.sender]++, // increment nonce on every bridge\n exclusivityRelayer: paramsV2.quoteRelayer,\n // We checked exclusivityEndTime to be in range [0 .. params.deadline] above, so can safely cast\n exclusivityEndTime: uint256(exclusivityEndTime),\n zapNative: paramsV2.zapNative,\n zapData: paramsV2.zapData\n })\n );\n bytes32 transactionId = keccak256(request);\n // Note: the tx status will be updated throughout the tx lifecycle, while destChainId is set once here\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n bridgeTxDetails[transactionId].destChainId = params.dstChainId;\n\n emit BridgeRequested({\n transactionId: transactionId,\n sender: params.sender,\n request: request,\n destChainId: params.dstChainId,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n sendChainGas: paramsV2.zapNative != 0\n });\n emit BridgeQuoteDetails(transactionId, paramsV2.quoteId);\n }\n\n /// @inheritdoc IFastBridgeV2\n function relay(bytes calldata request, address relayer) public payable {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n _validateRelayParams(request, transactionId, relayer);\n // mark bridge transaction as relayed\n bridgeRelayDetails[transactionId] =\n BridgeRelay({blockNumber: uint48(block.number), blockTimestamp: uint48(block.timestamp), relayer: relayer});\n\n // transfer tokens to recipient on destination chain and trigger Zap if requested\n address to = request.destRecipient();\n address token = request.destToken();\n uint256 amount = request.destAmount();\n uint256 zapNative = request.zapNative();\n\n // Emit the event before any external calls\n emit BridgeRelayed({\n transactionId: transactionId,\n relayer: relayer,\n to: to,\n originChainId: request.originChainId(),\n originToken: request.originToken(),\n destToken: token,\n originAmount: request.originAmount(),\n destAmount: amount,\n chainGasAmount: zapNative\n });\n\n // All state changes have been done at this point, can proceed to the external calls.\n // This follows the checks-effects-interactions pattern to mitigate potential reentrancy attacks.\n if (token == NATIVE_GAS_TOKEN) {\n // For the native gas token, additional zapNative is not allowed\n if (zapNative != 0) revert ZapNativeNotSupported();\n // Check that the correct msg.value was sent\n if (msg.value != amount) revert MsgValueIncorrect();\n // Don't do a native transfer yet: we will handle it alongside the Zap below\n } else {\n // For ERC20s, we check that the correct msg.value was sent\n if (msg.value != zapNative) revert MsgValueIncorrect();\n // We need to transfer the tokens from the Relayer to the recipient first before performing an\n // optional post-transfer Zap.\n IERC20(token).safeTransferFrom(msg.sender, to, amount);\n }\n // At this point we have done:\n // - Transferred the requested amount of ERC20 tokens to the recipient.\n // At this point we have confirmed:\n // - For ERC20s: msg.value matches the requested zapNative amount.\n // - For the native gas token: msg.value matches the requested destAmount.\n // Remaining optional things to do:\n // - Forward the full msg.value to the recipient (if non-zero).\n // - Trigger a Zap (if zapData is present).\n bytes calldata zapData = request.zapData();\n if (zapData.length != 0) {\n // Zap Data is present: Zap has been requested by the recipient. Trigger it forwarding the full msg.value.\n\n // Note: if token has a fee on transfers, the recipient will have received less than `amount`.\n // This is a very niche edge case and should be handled by the recipient contract.\n _triggerZapWithChecks({recipient: to, token: token, amount: amount, zapData: zapData});\n } else if (msg.value != 0) {\n // Zap Data is missing, but msg.value was sent. This could happen in two different cases:\n // - Relay with the native gas token is happening.\n // - Relay with ERC20 is happening, with a `zapNative \u003e 0` request.\n // In both cases, we need to transfer the full msg.value to the recipient.\n Address.sendValue(payable(to), msg.value);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) public onlyRole(PROVER_ROLE) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n\n // Can only prove a REQUESTED transaction\n if ($.status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n // Update status to RELAYER_PROVED and store the proof details\n // Note: these are storage writes\n $.status = BridgeStatus.RELAYER_PROVED;\n $.proofBlockTimestamp = uint56(block.timestamp);\n $.proofRelayer = relayer;\n\n emit BridgeProofProvided(transactionId, relayer, destTxHash);\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes calldata request, address to) public {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Aggregate the read operations from the same storage slot\n address proofRelayer = $.proofRelayer;\n BridgeStatus status = $.status;\n uint56 proofBlockTimestamp = $.proofBlockTimestamp;\n\n // Can only claim a RELAYER_PROVED transaction after the dispute period\n if (status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(proofBlockTimestamp) \u003c= DISPUTE_PERIOD) {\n revert DisputePeriodNotPassed();\n }\n\n if (to == address(0)) {\n // Anyone could claim the funds to the proven relayer on their behalf\n to = proofRelayer;\n } else if (proofRelayer != msg.sender) {\n // Only the proven relayer could specify an address to claim the funds to\n revert SenderIncorrect();\n }\n\n // Update status to RELAYER_CLAIMED and transfer the origin collateral to the specified claim address\n // Note: this is a storage write\n $.status = BridgeStatus.RELAYER_CLAIMED;\n\n address token = request.originToken();\n uint256 amount = request.originAmount();\n // Update protocol fees if origin fee amount exists\n uint256 originFeeAmount = request.originFeeAmount();\n if (originFeeAmount \u003e 0) protocolFees[token] += originFeeAmount;\n // Emit the event before any external calls\n emit BridgeDepositClaimed(transactionId, proofRelayer, to, token, amount);\n // Complete the relayer claim as the last transaction action\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(to), amount);\n } else {\n IERC20(token).safeTransfer(to, amount);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function cancel(bytes calldata request) public {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Can only cancel a REQUESTED transaction after its deadline expires\n if ($.status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n uint256 deadline = request.deadline();\n // Permissionless cancel is only allowed after `cancelDelay` on top of the deadline\n if (!hasRole(CANCELER_ROLE, msg.sender)) deadline += cancelDelay;\n if (block.timestamp \u003c= deadline) revert DeadlineNotExceeded();\n // Update status to REFUNDED and return the full amount (collateral + protocol fees) to the original sender.\n // The protocol fees are only updated when the transaction is claimed, so we don't need to update them here.\n // Note: this is a storage write\n $.status = BridgeStatus.REFUNDED;\n\n address to = request.originSender();\n address token = request.originToken();\n uint256 amount = request.originAmount() + request.originFeeAmount();\n // Emit the event before any external calls\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n // Complete the user cancel as the last transaction action\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(to), amount);\n } else {\n IERC20(token).safeTransfer(to, amount);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeStatuses(bytes32 transactionId) public view returns (BridgeStatus status) {\n return bridgeTxDetails[transactionId].status;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeProofs(bytes32 transactionId) public view returns (uint96 timestamp, address relayer) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n\n timestamp = $.proofBlockTimestamp;\n relayer = $.proofRelayer;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeRelays(bytes32 transactionId) public view returns (bool) {\n // has this transactionId been relayed?\n return bridgeRelayDetails[transactionId].relayer != address(0);\n }\n\n /// @notice Takes the bridged asset from the user into FastBridgeV2 custody. It will be later\n /// claimed by the relayer who completed the relay on destination chain, or transferred back to the user\n /// via the cancel function should no one complete the relay.\n function _takeBridgedUserAsset(address token, uint256 amount) internal returns (uint256 amountTaken) {\n if (token == NATIVE_GAS_TOKEN) {\n // For the native gas token, we just need to check that the supplied msg.value is correct.\n // Supplied `msg.value` is already in FastBridgeV2 custody.\n if (amount != msg.value) revert MsgValueIncorrect();\n amountTaken = msg.value;\n } else {\n // For ERC20s, token is explicitly transferred from the user to FastBridgeV2.\n // We don't allow non-zero `msg.value` to avoid extra funds from being stuck in FastBridgeV2.\n if (msg.value != 0) revert MsgValueIncorrect();\n // Throw an explicit error if the provided token address is not a contract\n if (token.code.length == 0) revert TokenNotContract();\n amountTaken = IERC20(token).balanceOf(address(this));\n IERC20(token).safeTransferFrom(msg.sender, address(this), amount);\n // Use the balance difference as the amount taken in case of fee on transfer tokens.\n amountTaken = IERC20(token).balanceOf(address(this)) - amountTaken;\n }\n }\n\n /// @notice Calls the Recipient's hook function with the specified zapData and performs\n /// all the necessary checks for the returned value.\n function _triggerZapWithChecks(address recipient, address token, uint256 amount, bytes calldata zapData) internal {\n // This will bubble any revert messages from the hook function\n bytes memory returnData = Address.functionCallWithValue({\n target: recipient,\n data: abi.encodeCall(IZapRecipient.zap, (token, amount, zapData)),\n // Note: see `relay()` for reasoning behind passing msg.value\n value: msg.value\n });\n // Explicit revert if no return data at all\n if (returnData.length == 0) revert RecipientNoReturnValue();\n // Check that exactly a single return value was returned\n if (returnData.length != 32) revert RecipientIncorrectReturnValue();\n // Return value should be abi-encoded hook function selector\n if (bytes32(returnData) != bytes32(IZapRecipient.zap.selector)) {\n revert RecipientIncorrectReturnValue();\n }\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint56(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint56).max but\n /// proof.timestamp \u003c type(uint56).max via unchecked statement\n /// @param proofBlockTimestamp The bridge proof block timestamp\n /// @return delta Time delta since proof submitted\n function _timeSince(uint56 proofBlockTimestamp) internal view returns (uint256 delta) {\n unchecked {\n delta = uint56(block.timestamp) - proofBlockTimestamp;\n }\n }\n\n /// @notice Performs all the necessary checks for a bridge to happen.\n /// @dev There's no good way to refactor this function to reduce cyclomatic complexity due to\n /// the number of checks that need to be performed, so we skip the code-complexity rule here.\n // solhint-disable-next-line code-complexity\n function _validateBridgeParams(\n BridgeParams memory params,\n BridgeParamsV2 memory paramsV2,\n int256 exclusivityEndTime\n )\n internal\n view\n {\n // Check V1 (legacy) params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.sender == address(0) || params.to == address(0)) revert ZeroAddress();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n // Check V2 params\n if (paramsV2.zapData.length \u003e MAX_ZAP_DATA_LENGTH) revert ZapDataLengthAboveMax();\n if (paramsV2.zapNative != 0 \u0026\u0026 params.destToken == NATIVE_GAS_TOKEN) {\n revert ZapNativeNotSupported();\n }\n // exclusivityEndTime must be in range [0 .. params.deadline]\n if (exclusivityEndTime \u003c 0 || exclusivityEndTime \u003e int256(params.deadline)) {\n revert ExclusivityParamsIncorrect();\n }\n }\n\n /// @notice Performs all the necessary checks for a relay to happen.\n function _validateRelayParams(bytes calldata request, bytes32 transactionId, address relayer) internal view {\n if (relayer == address(0)) revert ZeroAddress();\n // Check if the transaction has already been relayed\n if (bridgeRelays(transactionId)) revert TransactionRelayed();\n if (request.destChainId() != block.chainid) revert ChainIncorrect();\n // Check the deadline for relay to happen\n if (block.timestamp \u003e request.deadline()) revert DeadlineExceeded();\n // Check the exclusivity period, if it is still ongoing\n address exclRelayer = request.exclusivityRelayer();\n if (exclRelayer != address(0) \u0026\u0026 exclRelayer != relayer \u0026\u0026 block.timestamp \u003c= request.exclusivityEndTime()) {\n revert ExclusivityPeriodNotPassed();\n }\n }\n}\n","language":"Solidity","languageVersion":"0.8.24","compilerVersion":"0.8.24","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"","srcMapRuntime":"","abiDefinition":[{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Transfer","type":"event"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"}],"userDoc":{"kind":"user","methods":{},"version":1},"developerDoc":{"details":"Interface of the ERC20 standard as defined in the EIP.","events":{"Approval(address,address,uint256)":{"details":"Emitted when the allowance of a `spender` for an `owner` is set by a call to {approve}. `value` is the new allowance."},"Transfer(address,address,uint256)":{"details":"Emitted when `value` tokens are moved from one account (`from`) to another (`to`). Note that `value` may be zero."}},"kind":"dev","methods":{"allowance(address,address)":{"details":"Returns the remaining number of tokens that `spender` will be allowed to spend on behalf of `owner` through {transferFrom}. This is zero by default. This value changes when {approve} or {transferFrom} are called."},"approve(address,uint256)":{"details":"Sets a `value` amount of tokens as the allowance of `spender` over the caller's tokens. Returns a boolean value indicating whether the operation succeeded. IMPORTANT: Beware that changing an allowance with this method brings the risk that someone may use both the old and the new allowance by unfortunate transaction ordering. One possible solution to mitigate this race condition is to first reduce the spender's allowance to 0 and set the desired value afterwards: https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 Emits an {Approval} event."},"balanceOf(address)":{"details":"Returns the value of tokens owned by `account`."},"totalSupply()":{"details":"Returns the value of tokens in existence."},"transfer(address,uint256)":{"details":"Moves a `value` amount of tokens from the caller's account to `to`. Returns a boolean value indicating whether the operation succeeded. Emits a {Transfer} event."},"transferFrom(address,address,uint256)":{"details":"Moves a `value` amount of tokens from `from` to `to` using the allowance mechanism. `value` is then deducted from the caller's allowance. Returns a boolean value indicating whether the operation succeeded. Emits a {Transfer} event."}},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"Approval\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"Transfer\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"}],\"name\":\"allowance\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"approve\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"balanceOf\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"totalSupply\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"transfer\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"transferFrom\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"details\":\"Interface of the ERC20 standard as defined in the EIP.\",\"events\":{\"Approval(address,address,uint256)\":{\"details\":\"Emitted when the allowance of a `spender` for an `owner` is set by a call to {approve}. `value` is the new allowance.\"},\"Transfer(address,address,uint256)\":{\"details\":\"Emitted when `value` tokens are moved from one account (`from`) to another (`to`). Note that `value` may be zero.\"}},\"kind\":\"dev\",\"methods\":{\"allowance(address,address)\":{\"details\":\"Returns the remaining number of tokens that `spender` will be allowed to spend on behalf of `owner` through {transferFrom}. This is zero by default. This value changes when {approve} or {transferFrom} are called.\"},\"approve(address,uint256)\":{\"details\":\"Sets a `value` amount of tokens as the allowance of `spender` over the caller's tokens. Returns a boolean value indicating whether the operation succeeded. IMPORTANT: Beware that changing an allowance with this method brings the risk that someone may use both the old and the new allowance by unfortunate transaction ordering. One possible solution to mitigate this race condition is to first reduce the spender's allowance to 0 and set the desired value afterwards: https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 Emits an {Approval} event.\"},\"balanceOf(address)\":{\"details\":\"Returns the value of tokens owned by `account`.\"},\"totalSupply()\":{\"details\":\"Returns the value of tokens in existence.\"},\"transfer(address,uint256)\":{\"details\":\"Moves a `value` amount of tokens from the caller's account to `to`. Returns a boolean value indicating whether the operation succeeded. Emits a {Transfer} event.\"},\"transferFrom(address,address,uint256)\":{\"details\":\"Moves a `value` amount of tokens from `from` to `to` using the allowance mechanism. `value` is then deducted from the caller's allowance. Returns a boolean value indicating whether the operation succeeded. Emits a {Transfer} event.\"}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeV2.sol\":\"IERC20\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeV2.sol\":{\"keccak256\":\"0xac79c463688a682ca706a4ef95e7817b83548cdfa8182ba0426ac7e5e07613d8\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://b3ecb7097381287cafc3a73f3a2bb03565115ebb682a85064e0b0dc2f7e2919d\",\"dweb:/ipfs/QmatruW3nYZTksf3CeQ8wwiAG4c7xoEJBEp6drHPtFLBRK\"]}},\"version\":1}"},"hashes":{"allowance(address,address)":"dd62ed3e","approve(address,uint256)":"095ea7b3","balanceOf(address)":"70a08231","totalSupply()":"18160ddd","transfer(address,uint256)":"a9059cbb","transferFrom(address,address,uint256)":"23b872dd"}},"solidity/FastBridgeV2.sol:IERC20Permit":{"code":"0x","runtime-code":"0x","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.24 ^0.8.20 ^0.8.4;\n\n// contracts/interfaces/IAdminV2.sol\n\ninterface IAdminV2 {\n event CancelDelayUpdated(uint256 oldCancelDelay, uint256 newCancelDelay);\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n function setCancelDelay(uint256 newCancelDelay) external;\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n}\n\n// contracts/interfaces/IAdminV2Errors.sol\n\ninterface IAdminV2Errors {\n error CancelDelayBelowMin();\n error FeeRateAboveMax();\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IFastBridgeV2Errors.sol\n\ninterface IFastBridgeV2Errors {\n error AmountIncorrect();\n error ChainIncorrect();\n error ExclusivityParamsIncorrect();\n error MsgValueIncorrect();\n error SenderIncorrect();\n error StatusIncorrect();\n error TokenNotContract();\n error ZapDataLengthAboveMax();\n error ZapNativeNotSupported();\n error ZeroAddress();\n\n error RecipientIncorrectReturnValue();\n error RecipientNoReturnValue();\n\n error DeadlineExceeded();\n error DeadlineNotExceeded();\n error DeadlineTooShort();\n error DisputePeriodNotPassed();\n error DisputePeriodPassed();\n error ExclusivityPeriodNotPassed();\n\n error TransactionRelayed();\n}\n\n// contracts/interfaces/IMulticallTarget.sol\n\n/// @notice Interface for a contract that can be called multiple times by the same caller. Inspired by MulticallV3:\n/// https://github.com/mds1/multicall/blob/master/src/Multicall3.sol\ninterface IMulticallTarget {\n struct Result {\n bool success;\n bytes returnData;\n }\n\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external;\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results);\n}\n\n// contracts/interfaces/IZapRecipient.sol\n\ninterface IZapRecipient {\n function zap(address token, uint256 amount, bytes memory zapData) external payable returns (bytes4);\n}\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// contracts/interfaces/IFastBridgeV2.sol\n\ninterface IFastBridgeV2 is IFastBridge {\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n struct BridgeTxDetails {\n BridgeStatus status;\n uint32 destChainId;\n uint56 proofBlockTimestamp;\n address proofRelayer;\n }\n\n struct BridgeRelay {\n uint48 blockNumber;\n uint48 blockTimestamp;\n address relayer;\n }\n\n /// @notice New params introduced in the FastBridgeV2.\n /// We are passing fields from the older BridgeParams struct outside of this struct\n /// for backwards compatibility.\n /// Note: quoteRelayer and quoteExclusivitySeconds are either both zero (indicating no exclusivity)\n /// or both non-zero (indicating exclusivity for the given period).\n /// Note: zapNative \u003e 0 can NOT be used with destToken = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE (native token)\n /// @param quoteRelayer Relayer that provided the quote for the transaction\n /// @param quoteExclusivitySeconds Period of time the quote relayer is guaranteed exclusivity after user's deposit\n /// @param quoteId Unique quote identifier used for tracking the quote\n /// @param zapNative ETH value to send to the recipient (if any)\n /// @param zapData Parameters for the Zap to the destination recipient (if any)\n struct BridgeParamsV2 {\n address quoteRelayer;\n int256 quoteExclusivitySeconds;\n bytes quoteId;\n uint256 zapNative;\n bytes zapData;\n }\n\n /// @notice Updated bridge transaction struct to include parameters introduced in FastBridgeV2.\n /// Note: only `exclusivityRelayer` can fill such a transaction until `exclusivityEndTime`.\n struct BridgeTransactionV2 {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n // Note: sendChainGas flag from V1 is deprecated\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n address exclusivityRelayer;\n uint256 exclusivityEndTime;\n uint256 zapNative; // ETH value to send to the recipient (if any)\n bytes zapData; // data to pass for the Zap action (if any)\n }\n\n event BridgeQuoteDetails(bytes32 indexed transactionId, bytes quoteId);\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability\n /// to provide temporary exclusivity fill rights for the quote relayer.\n /// @param params The parameters required to bridge\n /// @param paramsV2 The parameters for exclusivity fill rights (optional, can be left empty)\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function relay(bytes memory request, address relayer) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param transactionId The transaction id associated with the encoded bridge transaction to prove\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital.\n /// @notice Can only send funds to the relayer address on the proof.\n /// @param request The encoded bridge transaction to claim on origin chain\n function claim(bytes memory request) external;\n\n /// @notice Cancels an outstanding bridge transaction in case optimistic bridging failed and returns the full amount\n /// to the original sender.\n /// @param request The encoded bridge transaction to refund\n function cancel(bytes memory request) external;\n\n /// @notice Checks if a transaction has been relayed\n /// @param transactionId The ID of the transaction to check\n /// @return True if the transaction has been relayed, false otherwise\n function bridgeRelays(bytes32 transactionId) external view returns (bool);\n\n /// @notice Returns the status of a bridge transaction\n /// @param transactionId The ID of the bridge transaction\n /// @return BridgeStatus Status of the bridge transaction\n function bridgeStatuses(bytes32 transactionId) external view returns (BridgeStatus);\n\n /// @notice Returns the timestamp and relayer of a bridge proof\n /// @param transactionId The ID of the bridge transaction\n /// @return timestamp The timestamp of the bridge proof\n /// @return relayer The relayer address of the bridge proof\n function bridgeProofs(bytes32 transactionId) external view returns (uint96 timestamp, address relayer);\n\n /// @notice Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\n /// @param request The bridge request to decode\n function getBridgeTransactionV2(bytes memory request) external view returns (BridgeTransactionV2 memory);\n}\n\n// contracts/utils/MulticallTarget.sol\n\n// solhint-disable avoid-low-level-calls\n/// @notice Template for a contract that supports batched calls (preserving the msg.sender).\n/// Only calls with zero msg.value could be batched.\nabstract contract MulticallTarget is IMulticallTarget {\n error MulticallTarget__UndeterminedRevert();\n\n /// @notice Perform a batched call to this contract, preserving the msg.sender.\n /// The return data from each call is discarded.\n /// @dev The method is non-payable, so only calls with `msg.value == 0` could be batched.\n /// It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag.\n /// Otherwise, the whole batch call will be reverted with the original revert reason.\n /// @param data List of abi-encoded calldata for the calls to perform.\n /// @param ignoreReverts Whether to ignore the revert errors from the calls.\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external {\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\n if (!success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(result);\n }\n }\n }\n\n /// @notice Perform a batched call to this contract, preserving the msg.sender.\n /// The return data from each call is preserved.\n /// @dev The method is non-payable, so only calls with `msg.value == 0` could be batched.\n /// It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag.\n /// Otherwise, the whole batch call will be reverted with the original revert reason.\n /// @param data List of abi-encoded calldata for the calls to perform.\n /// @param ignoreReverts Whether to ignore the revert errors from the calls.\n /// @return results List of results from the calls: `(success, returnData)`.\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results)\n {\n results = new Result[](data.length);\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (results[i].success, results[i].returnData) = address(this).delegatecall(data[i]);\n if (!results[i].success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(results[i].returnData);\n }\n }\n }\n\n /// @dev Bubbles the revert message from the underlying call.\n /// Note: preserves the same custom error or revert string, if one was used.\n /// Source: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v5.0.2/contracts/utils/Address.sol#L143-L158\n function _bubbleRevert(bytes memory returnData) internal pure {\n // Look for revert reason and bubble it up if present\n if (returnData.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n // solhint-disable-next-line no-inline-assembly\n assembly {\n let returndata_size := mload(returnData)\n revert(add(32, returnData), returndata_size)\n }\n } else {\n revert MulticallTarget__UndeterminedRevert();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// contracts/libs/BridgeTransactionV2.sol\n\n// solhint-disable no-inline-assembly\nlibrary BridgeTransactionV2Lib {\n uint16 internal constant VERSION = 2;\n\n // Offsets of the fields in the packed BridgeTransactionV2 struct\n // uint16 version [000 .. 002)\n // uint32 originChainId [002 .. 006)\n // uint32 destChainId [006 .. 010)\n // address originSender [010 .. 030)\n // address destRecipient [030 .. 050)\n // address originToken [050 .. 070)\n // address destToken [070 .. 090)\n // uint256 originAmount [090 .. 122)\n // uint256 destAmount [122 .. 154)\n // uint256 originFeeAmount [154 .. 186)\n // uint256 deadline [186 .. 218)\n // uint256 nonce [218 .. 250)\n // address exclusivityRelayer [250 .. 270)\n // uint256 exclusivityEndTime [270 .. 302)\n // uint256 zapNative [302 .. 334)\n // bytes zapData [334 .. ***)\n\n // forgefmt: disable-start\n uint256 private constant OFFSET_ORIGIN_CHAIN_ID = 2;\n uint256 private constant OFFSET_DEST_CHAIN_ID = 6;\n uint256 private constant OFFSET_ORIGIN_SENDER = 10;\n uint256 private constant OFFSET_DEST_RECIPIENT = 30;\n uint256 private constant OFFSET_ORIGIN_TOKEN = 50;\n uint256 private constant OFFSET_DEST_TOKEN = 70;\n uint256 private constant OFFSET_ORIGIN_AMOUNT = 90;\n uint256 private constant OFFSET_DEST_AMOUNT = 122;\n uint256 private constant OFFSET_ORIGIN_FEE_AMOUNT = 154;\n uint256 private constant OFFSET_DEADLINE = 186;\n uint256 private constant OFFSET_NONCE = 218;\n uint256 private constant OFFSET_EXCLUSIVITY_RELAYER = 250;\n uint256 private constant OFFSET_EXCLUSIVITY_END_TIME = 270;\n uint256 private constant OFFSET_ZAP_NATIVE = 302;\n uint256 private constant OFFSET_ZAP_DATA = 334;\n // forgefmt: disable-end\n\n error BridgeTransactionV2__InvalidEncodedTx();\n error BridgeTransactionV2__UnsupportedVersion(uint16 version);\n\n /// @notice Validates the encoded transaction to be a tightly packed encoded payload for BridgeTransactionV2.\n /// @dev Checks the minimum length and the version, use this function before decoding any of the fields.\n function validateV2(bytes calldata encodedTx) internal pure {\n // Check the minimum length: must at least include all static fields.\n if (encodedTx.length \u003c OFFSET_ZAP_DATA) revert BridgeTransactionV2__InvalidEncodedTx();\n // Once we validated the length, we can be sure that the version field is present.\n uint16 version_ = version(encodedTx);\n if (version_ != VERSION) revert BridgeTransactionV2__UnsupportedVersion(version_);\n }\n\n /// @notice Encodes the BridgeTransactionV2 struct by tightly packing the fields.\n /// @dev `abi.decode` will not work as a result of the tightly packed fields. Use `decodeV2` to decode instead.\n function encodeV2(IFastBridgeV2.BridgeTransactionV2 memory bridgeTx) internal pure returns (bytes memory) {\n // We split the encoding into two parts to avoid stack-too-deep error\n bytes memory firstPart = abi.encodePacked(\n VERSION,\n bridgeTx.originChainId,\n bridgeTx.destChainId,\n bridgeTx.originSender,\n bridgeTx.destRecipient,\n bridgeTx.originToken,\n bridgeTx.destToken,\n bridgeTx.originAmount\n );\n return abi.encodePacked(\n firstPart,\n bridgeTx.destAmount,\n bridgeTx.originFeeAmount,\n // Note: we skip the deprecated `sendChainGas` flag, which was present in BridgeTransaction V1\n bridgeTx.deadline,\n bridgeTx.nonce,\n // New V2 fields: exclusivity\n bridgeTx.exclusivityRelayer,\n bridgeTx.exclusivityEndTime,\n // New V2 fields: Zap\n bridgeTx.zapNative,\n bridgeTx.zapData\n );\n }\n\n /// @notice Decodes the BridgeTransactionV2 struct from the encoded transaction.\n /// @dev Encoded BridgeTransactionV2 struct must be tightly packed.\n /// Use `validateV2` before decoding to ensure the encoded transaction is valid.\n function decodeV2(bytes calldata encodedTx)\n internal\n pure\n returns (IFastBridgeV2.BridgeTransactionV2 memory bridgeTx)\n {\n bridgeTx.originChainId = originChainId(encodedTx);\n bridgeTx.destChainId = destChainId(encodedTx);\n bridgeTx.originSender = originSender(encodedTx);\n bridgeTx.destRecipient = destRecipient(encodedTx);\n bridgeTx.originToken = originToken(encodedTx);\n bridgeTx.destToken = destToken(encodedTx);\n bridgeTx.originAmount = originAmount(encodedTx);\n bridgeTx.destAmount = destAmount(encodedTx);\n bridgeTx.originFeeAmount = originFeeAmount(encodedTx);\n bridgeTx.deadline = deadline(encodedTx);\n bridgeTx.nonce = nonce(encodedTx);\n bridgeTx.exclusivityRelayer = exclusivityRelayer(encodedTx);\n bridgeTx.exclusivityEndTime = exclusivityEndTime(encodedTx);\n bridgeTx.zapNative = zapNative(encodedTx);\n bridgeTx.zapData = zapData(encodedTx);\n }\n\n /// @notice Extracts the version from the encoded transaction.\n function version(bytes calldata encodedTx) internal pure returns (uint16 version_) {\n // Load 32 bytes from the start and shift it 240 bits to the right to get the highest 16 bits.\n assembly {\n version_ := shr(240, calldataload(encodedTx.offset))\n }\n }\n\n /// @notice Extracts the origin chain ID from the encoded transaction.\n function originChainId(bytes calldata encodedTx) internal pure returns (uint32 originChainId_) {\n // Load 32 bytes from the offset and shift it 224 bits to the right to get the highest 32 bits.\n assembly {\n originChainId_ := shr(224, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_CHAIN_ID)))\n }\n }\n\n /// @notice Extracts the destination chain ID from the encoded transaction.\n function destChainId(bytes calldata encodedTx) internal pure returns (uint32 destChainId_) {\n // Load 32 bytes from the offset and shift it 224 bits to the right to get the highest 32 bits.\n assembly {\n destChainId_ := shr(224, calldataload(add(encodedTx.offset, OFFSET_DEST_CHAIN_ID)))\n }\n }\n\n /// @notice Extracts the origin sender from the encoded transaction.\n function originSender(bytes calldata encodedTx) internal pure returns (address originSender_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n originSender_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_SENDER)))\n }\n }\n\n /// @notice Extracts the destination recipient from the encoded transaction.\n function destRecipient(bytes calldata encodedTx) internal pure returns (address destRecipient_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n destRecipient_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_DEST_RECIPIENT)))\n }\n }\n\n /// @notice Extracts the origin token from the encoded transaction.\n function originToken(bytes calldata encodedTx) internal pure returns (address originToken_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n originToken_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_TOKEN)))\n }\n }\n\n /// @notice Extracts the destination token from the encoded transaction.\n function destToken(bytes calldata encodedTx) internal pure returns (address destToken_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n destToken_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_DEST_TOKEN)))\n }\n }\n\n /// @notice Extracts the origin amount from the encoded transaction.\n function originAmount(bytes calldata encodedTx) internal pure returns (uint256 originAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n originAmount_ := calldataload(add(encodedTx.offset, OFFSET_ORIGIN_AMOUNT))\n }\n }\n\n /// @notice Extracts the destination amount from the encoded transaction.\n function destAmount(bytes calldata encodedTx) internal pure returns (uint256 destAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n destAmount_ := calldataload(add(encodedTx.offset, OFFSET_DEST_AMOUNT))\n }\n }\n\n /// @notice Extracts the origin fee amount from the encoded transaction.\n function originFeeAmount(bytes calldata encodedTx) internal pure returns (uint256 originFeeAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n originFeeAmount_ := calldataload(add(encodedTx.offset, OFFSET_ORIGIN_FEE_AMOUNT))\n }\n }\n\n /// @notice Extracts the deadline from the encoded transaction.\n function deadline(bytes calldata encodedTx) internal pure returns (uint256 deadline_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n deadline_ := calldataload(add(encodedTx.offset, OFFSET_DEADLINE))\n }\n }\n\n /// @notice Extracts the nonce from the encoded transaction.\n function nonce(bytes calldata encodedTx) internal pure returns (uint256 nonce_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n nonce_ := calldataload(add(encodedTx.offset, OFFSET_NONCE))\n }\n }\n\n /// @notice Extracts the exclusivity relayer from the encoded transaction.\n function exclusivityRelayer(bytes calldata encodedTx) internal pure returns (address exclusivityRelayer_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n exclusivityRelayer_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_EXCLUSIVITY_RELAYER)))\n }\n }\n\n /// @notice Extracts the exclusivity end time from the encoded transaction.\n function exclusivityEndTime(bytes calldata encodedTx) internal pure returns (uint256 exclusivityEndTime_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n exclusivityEndTime_ := calldataload(add(encodedTx.offset, OFFSET_EXCLUSIVITY_END_TIME))\n }\n }\n\n /// @notice Extracts the Zap's native value from the encoded transaction.\n function zapNative(bytes calldata encodedTx) internal pure returns (uint256 zapNative_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n zapNative_ := calldataload(add(encodedTx.offset, OFFSET_ZAP_NATIVE))\n }\n }\n\n /// @notice Extracts the Zap's data from the encoded transaction.\n function zapData(bytes calldata encodedTx) internal pure returns (bytes calldata zapData_) {\n zapData_ = encodedTx[OFFSET_ZAP_DATA:];\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/AdminV2.sol\n\ncontract AdminV2 is AccessControlEnumerable, IAdminV2, IAdminV2Errors {\n using SafeERC20 for IERC20;\n\n /// @notice Address reserved for native gas token (ETH on Ethereum and most L2s, AVAX on Avalanche, etc)\n address public constant NATIVE_GAS_TOKEN = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Role identifier for Quoter API's off-chain authentication.\n /// @dev Only addresses with this role can post FastBridge quotes to the API.\n bytes32 public constant QUOTER_ROLE = keccak256(\"QUOTER_ROLE\");\n\n /// @notice Role identifier for Prover's on-chain authentication in FastBridge.\n /// @dev Only addresses with this role can provide proofs that a FastBridge request has been relayed.\n bytes32 public constant PROVER_ROLE = keccak256(\"PROVER_ROLE\");\n\n /// @notice Role identifier for Guard's on-chain authentication in FastBridge.\n /// @dev Only addresses with this role can dispute submitted relay proofs during the dispute period.\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n\n /// @notice Role identifier for Canceler's on-chain authentication in FastBridge.\n /// @dev Only addresses with this role can cancel a FastBridge transaction without the cancel delay.\n bytes32 public constant CANCELER_ROLE = keccak256(\"CANCELER_ROLE\");\n\n /// @notice Role identifier for Governor's on-chain administrative authority.\n /// @dev Only addresses with this role can perform administrative tasks within the contract.\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n /// @notice Denominator for fee rates, represents 100%.\n uint256 public constant FEE_BPS = 1e6;\n /// @notice Maximum protocol fee rate: 1% on origin amount.\n uint256 public constant FEE_RATE_MAX = 0.01e6;\n\n /// @notice Minimum cancel delay that can be set by the governor.\n uint256 public constant MIN_CANCEL_DELAY = 1 hours;\n /// @notice Default cancel delay set during the contract deployment.\n uint256 public constant DEFAULT_CANCEL_DELAY = 1 days;\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Delay for a transaction after which it could be permisionlessly cancelled\n uint256 public cancelDelay;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Use ZapNative V2 requests instead.\n uint256 public immutable chainGasAmount = 0;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n _setCancelDelay(DEFAULT_CANCEL_DELAY);\n }\n\n /// @notice Allows the contract governor to set the cancel delay. The cancel delay is the time after the transaction\n /// deadline after which it can be permissionlessly cancelled, if it hasn't been proven by any of the Relayers.\n function setCancelDelay(uint256 newCancelDelay) external onlyRole(GOVERNOR_ROLE) {\n _setCancelDelay(newCancelDelay);\n }\n\n /// @notice Allows the contract governor to set the protocol fee rate. The protocol fee is taken from the origin\n /// amount only for completed and claimed transactions.\n /// @dev The protocol fee is abstracted away from the relayers, they always operate using the amounts after fees:\n /// what they see as the origin amount emitted in the log is what they get credited with.\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n if (newFeeRate \u003e FEE_RATE_MAX) revert FeeRateAboveMax();\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n /// @notice Allows the contract governor to sweep the accumulated protocol fees in the contract.\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n emit FeesSwept(token, recipient, feeAmount);\n /// Sweep the fees as the last transaction action\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(recipient), feeAmount);\n } else {\n IERC20(token).safeTransfer(recipient, feeAmount);\n }\n }\n\n /// @notice Internal function to set the cancel delay. Security checks are performed outside of this function.\n function _setCancelDelay(uint256 newCancelDelay) private {\n if (newCancelDelay \u003c MIN_CANCEL_DELAY) revert CancelDelayBelowMin();\n uint256 oldCancelDelay = cancelDelay;\n cancelDelay = newCancelDelay;\n emit CancelDelayUpdated(oldCancelDelay, newCancelDelay);\n }\n}\n\n// contracts/FastBridgeV2.sol\n\n/// @notice FastBridgeV2 is a contract for bridging tokens across chains.\ncontract FastBridgeV2 is AdminV2, MulticallTarget, IFastBridgeV2, IFastBridgeV2Errors {\n using BridgeTransactionV2Lib for bytes;\n using SafeERC20 for IERC20;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n /// @notice Maximum length of accepted zapData\n uint256 public constant MAX_ZAP_DATA_LENGTH = 2 ** 16 - 1;\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeTxDetails) public bridgeTxDetails;\n /// @notice Relay details on destination chain\n mapping(bytes32 =\u003e BridgeRelay) public bridgeRelayDetails;\n /// @notice Unique bridge nonces tracked per originSender\n mapping(address =\u003e uint256) public senderNonces;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Replaced by senderNonces\n uint256 public immutable nonce = 0;\n /// @notice the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) AdminV2(_owner) {\n deployBlock = block.number;\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n bridge({\n params: params,\n paramsV2: BridgeParamsV2({\n quoteRelayer: address(0),\n quoteExclusivitySeconds: 0,\n quoteId: bytes(\"\"),\n zapNative: 0,\n zapData: bytes(\"\")\n })\n });\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes calldata request) external payable {\n // relay override will validate the request\n relay({request: request, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes calldata request, bytes32 destTxHash) external {\n request.validateV2();\n prove({transactionId: keccak256(request), destTxHash: destTxHash, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridgeV2\n function claim(bytes calldata request) external {\n // claim override will validate the request\n claim({request: request, to: address(0)});\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Aggregate the read operations from the same storage slot\n address disputedRelayer = $.proofRelayer;\n BridgeStatus status = $.status;\n uint56 proofBlockTimestamp = $.proofBlockTimestamp;\n // Can only dispute a RELAYER_PROVED transaction within the dispute period\n if (status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(proofBlockTimestamp) \u003e DISPUTE_PERIOD) {\n revert DisputePeriodPassed();\n }\n // Update status to REQUESTED and delete the disputed proof details\n // Note: these are storage writes\n $.status = BridgeStatus.REQUESTED;\n $.proofRelayer = address(0);\n $.proofBlockTimestamp = 0;\n\n emit BridgeProofDisputed(transactionId, disputedRelayer);\n }\n\n /// Note: this function is deprecated and will be removed in a future version.\n /// @inheritdoc IFastBridge\n function refund(bytes calldata request) external {\n cancel(request);\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // The correct relayer can only claim a RELAYER_PROVED transaction after the dispute period\n if ($.status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if ($.proofRelayer != relayer) revert SenderIncorrect();\n return _timeSince($.proofBlockTimestamp) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n /// @dev This method is added to achieve backwards compatibility with decoding requests into V1 structs:\n /// - `zapNative` is partially reported as a zero/non-zero flag\n /// - `zapData` is ignored\n /// In order to process all kinds of requests use getBridgeTransactionV2 instead.\n function getBridgeTransaction(bytes calldata request) external view returns (BridgeTransaction memory) {\n // Try decoding into V2 struct first. This will revert if V1 struct is passed\n try this.getBridgeTransactionV2(request) returns (BridgeTransactionV2 memory txV2) {\n // Note: we entirely ignore the zapData field, as it was not present in V1\n return BridgeTransaction({\n originChainId: txV2.originChainId,\n destChainId: txV2.destChainId,\n originSender: txV2.originSender,\n destRecipient: txV2.destRecipient,\n originToken: txV2.originToken,\n destToken: txV2.destToken,\n originAmount: txV2.originAmount,\n destAmount: txV2.destAmount,\n originFeeAmount: txV2.originFeeAmount,\n sendChainGas: txV2.zapNative != 0,\n deadline: txV2.deadline,\n nonce: txV2.nonce\n });\n } catch {\n // Fallback to V1 struct\n return abi.decode(request, (BridgeTransaction));\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function getBridgeTransactionV2(bytes calldata request) external pure returns (BridgeTransactionV2 memory) {\n request.validateV2();\n return BridgeTransactionV2Lib.decodeV2(request);\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) public payable {\n int256 exclusivityEndTime = 0;\n // if relayer exclusivity is not intended for this bridge, set exclusivityEndTime to static zero\n // otherwise, set exclusivity to expire at the current block ts offset by quoteExclusivitySeconds\n if (paramsV2.quoteRelayer != address(0)) {\n exclusivityEndTime = int256(block.timestamp) + paramsV2.quoteExclusivitySeconds;\n }\n _validateBridgeParams(params, paramsV2, exclusivityEndTime);\n\n // transfer tokens to bridge contract\n /// @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _takeBridgedUserAsset(params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) {\n originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n }\n\n // set status to requested\n bytes memory request = BridgeTransactionV2Lib.encodeV2(\n BridgeTransactionV2({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n deadline: params.deadline,\n nonce: senderNonces[params.sender]++, // increment nonce on every bridge\n exclusivityRelayer: paramsV2.quoteRelayer,\n // We checked exclusivityEndTime to be in range [0 .. params.deadline] above, so can safely cast\n exclusivityEndTime: uint256(exclusivityEndTime),\n zapNative: paramsV2.zapNative,\n zapData: paramsV2.zapData\n })\n );\n bytes32 transactionId = keccak256(request);\n // Note: the tx status will be updated throughout the tx lifecycle, while destChainId is set once here\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n bridgeTxDetails[transactionId].destChainId = params.dstChainId;\n\n emit BridgeRequested({\n transactionId: transactionId,\n sender: params.sender,\n request: request,\n destChainId: params.dstChainId,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n sendChainGas: paramsV2.zapNative != 0\n });\n emit BridgeQuoteDetails(transactionId, paramsV2.quoteId);\n }\n\n /// @inheritdoc IFastBridgeV2\n function relay(bytes calldata request, address relayer) public payable {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n _validateRelayParams(request, transactionId, relayer);\n // mark bridge transaction as relayed\n bridgeRelayDetails[transactionId] =\n BridgeRelay({blockNumber: uint48(block.number), blockTimestamp: uint48(block.timestamp), relayer: relayer});\n\n // transfer tokens to recipient on destination chain and trigger Zap if requested\n address to = request.destRecipient();\n address token = request.destToken();\n uint256 amount = request.destAmount();\n uint256 zapNative = request.zapNative();\n\n // Emit the event before any external calls\n emit BridgeRelayed({\n transactionId: transactionId,\n relayer: relayer,\n to: to,\n originChainId: request.originChainId(),\n originToken: request.originToken(),\n destToken: token,\n originAmount: request.originAmount(),\n destAmount: amount,\n chainGasAmount: zapNative\n });\n\n // All state changes have been done at this point, can proceed to the external calls.\n // This follows the checks-effects-interactions pattern to mitigate potential reentrancy attacks.\n if (token == NATIVE_GAS_TOKEN) {\n // For the native gas token, additional zapNative is not allowed\n if (zapNative != 0) revert ZapNativeNotSupported();\n // Check that the correct msg.value was sent\n if (msg.value != amount) revert MsgValueIncorrect();\n // Don't do a native transfer yet: we will handle it alongside the Zap below\n } else {\n // For ERC20s, we check that the correct msg.value was sent\n if (msg.value != zapNative) revert MsgValueIncorrect();\n // We need to transfer the tokens from the Relayer to the recipient first before performing an\n // optional post-transfer Zap.\n IERC20(token).safeTransferFrom(msg.sender, to, amount);\n }\n // At this point we have done:\n // - Transferred the requested amount of ERC20 tokens to the recipient.\n // At this point we have confirmed:\n // - For ERC20s: msg.value matches the requested zapNative amount.\n // - For the native gas token: msg.value matches the requested destAmount.\n // Remaining optional things to do:\n // - Forward the full msg.value to the recipient (if non-zero).\n // - Trigger a Zap (if zapData is present).\n bytes calldata zapData = request.zapData();\n if (zapData.length != 0) {\n // Zap Data is present: Zap has been requested by the recipient. Trigger it forwarding the full msg.value.\n\n // Note: if token has a fee on transfers, the recipient will have received less than `amount`.\n // This is a very niche edge case and should be handled by the recipient contract.\n _triggerZapWithChecks({recipient: to, token: token, amount: amount, zapData: zapData});\n } else if (msg.value != 0) {\n // Zap Data is missing, but msg.value was sent. This could happen in two different cases:\n // - Relay with the native gas token is happening.\n // - Relay with ERC20 is happening, with a `zapNative \u003e 0` request.\n // In both cases, we need to transfer the full msg.value to the recipient.\n Address.sendValue(payable(to), msg.value);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) public onlyRole(PROVER_ROLE) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n\n // Can only prove a REQUESTED transaction\n if ($.status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n // Update status to RELAYER_PROVED and store the proof details\n // Note: these are storage writes\n $.status = BridgeStatus.RELAYER_PROVED;\n $.proofBlockTimestamp = uint56(block.timestamp);\n $.proofRelayer = relayer;\n\n emit BridgeProofProvided(transactionId, relayer, destTxHash);\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes calldata request, address to) public {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Aggregate the read operations from the same storage slot\n address proofRelayer = $.proofRelayer;\n BridgeStatus status = $.status;\n uint56 proofBlockTimestamp = $.proofBlockTimestamp;\n\n // Can only claim a RELAYER_PROVED transaction after the dispute period\n if (status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(proofBlockTimestamp) \u003c= DISPUTE_PERIOD) {\n revert DisputePeriodNotPassed();\n }\n\n if (to == address(0)) {\n // Anyone could claim the funds to the proven relayer on their behalf\n to = proofRelayer;\n } else if (proofRelayer != msg.sender) {\n // Only the proven relayer could specify an address to claim the funds to\n revert SenderIncorrect();\n }\n\n // Update status to RELAYER_CLAIMED and transfer the origin collateral to the specified claim address\n // Note: this is a storage write\n $.status = BridgeStatus.RELAYER_CLAIMED;\n\n address token = request.originToken();\n uint256 amount = request.originAmount();\n // Update protocol fees if origin fee amount exists\n uint256 originFeeAmount = request.originFeeAmount();\n if (originFeeAmount \u003e 0) protocolFees[token] += originFeeAmount;\n // Emit the event before any external calls\n emit BridgeDepositClaimed(transactionId, proofRelayer, to, token, amount);\n // Complete the relayer claim as the last transaction action\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(to), amount);\n } else {\n IERC20(token).safeTransfer(to, amount);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function cancel(bytes calldata request) public {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Can only cancel a REQUESTED transaction after its deadline expires\n if ($.status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n uint256 deadline = request.deadline();\n // Permissionless cancel is only allowed after `cancelDelay` on top of the deadline\n if (!hasRole(CANCELER_ROLE, msg.sender)) deadline += cancelDelay;\n if (block.timestamp \u003c= deadline) revert DeadlineNotExceeded();\n // Update status to REFUNDED and return the full amount (collateral + protocol fees) to the original sender.\n // The protocol fees are only updated when the transaction is claimed, so we don't need to update them here.\n // Note: this is a storage write\n $.status = BridgeStatus.REFUNDED;\n\n address to = request.originSender();\n address token = request.originToken();\n uint256 amount = request.originAmount() + request.originFeeAmount();\n // Emit the event before any external calls\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n // Complete the user cancel as the last transaction action\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(to), amount);\n } else {\n IERC20(token).safeTransfer(to, amount);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeStatuses(bytes32 transactionId) public view returns (BridgeStatus status) {\n return bridgeTxDetails[transactionId].status;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeProofs(bytes32 transactionId) public view returns (uint96 timestamp, address relayer) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n\n timestamp = $.proofBlockTimestamp;\n relayer = $.proofRelayer;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeRelays(bytes32 transactionId) public view returns (bool) {\n // has this transactionId been relayed?\n return bridgeRelayDetails[transactionId].relayer != address(0);\n }\n\n /// @notice Takes the bridged asset from the user into FastBridgeV2 custody. It will be later\n /// claimed by the relayer who completed the relay on destination chain, or transferred back to the user\n /// via the cancel function should no one complete the relay.\n function _takeBridgedUserAsset(address token, uint256 amount) internal returns (uint256 amountTaken) {\n if (token == NATIVE_GAS_TOKEN) {\n // For the native gas token, we just need to check that the supplied msg.value is correct.\n // Supplied `msg.value` is already in FastBridgeV2 custody.\n if (amount != msg.value) revert MsgValueIncorrect();\n amountTaken = msg.value;\n } else {\n // For ERC20s, token is explicitly transferred from the user to FastBridgeV2.\n // We don't allow non-zero `msg.value` to avoid extra funds from being stuck in FastBridgeV2.\n if (msg.value != 0) revert MsgValueIncorrect();\n // Throw an explicit error if the provided token address is not a contract\n if (token.code.length == 0) revert TokenNotContract();\n amountTaken = IERC20(token).balanceOf(address(this));\n IERC20(token).safeTransferFrom(msg.sender, address(this), amount);\n // Use the balance difference as the amount taken in case of fee on transfer tokens.\n amountTaken = IERC20(token).balanceOf(address(this)) - amountTaken;\n }\n }\n\n /// @notice Calls the Recipient's hook function with the specified zapData and performs\n /// all the necessary checks for the returned value.\n function _triggerZapWithChecks(address recipient, address token, uint256 amount, bytes calldata zapData) internal {\n // This will bubble any revert messages from the hook function\n bytes memory returnData = Address.functionCallWithValue({\n target: recipient,\n data: abi.encodeCall(IZapRecipient.zap, (token, amount, zapData)),\n // Note: see `relay()` for reasoning behind passing msg.value\n value: msg.value\n });\n // Explicit revert if no return data at all\n if (returnData.length == 0) revert RecipientNoReturnValue();\n // Check that exactly a single return value was returned\n if (returnData.length != 32) revert RecipientIncorrectReturnValue();\n // Return value should be abi-encoded hook function selector\n if (bytes32(returnData) != bytes32(IZapRecipient.zap.selector)) {\n revert RecipientIncorrectReturnValue();\n }\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint56(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint56).max but\n /// proof.timestamp \u003c type(uint56).max via unchecked statement\n /// @param proofBlockTimestamp The bridge proof block timestamp\n /// @return delta Time delta since proof submitted\n function _timeSince(uint56 proofBlockTimestamp) internal view returns (uint256 delta) {\n unchecked {\n delta = uint56(block.timestamp) - proofBlockTimestamp;\n }\n }\n\n /// @notice Performs all the necessary checks for a bridge to happen.\n /// @dev There's no good way to refactor this function to reduce cyclomatic complexity due to\n /// the number of checks that need to be performed, so we skip the code-complexity rule here.\n // solhint-disable-next-line code-complexity\n function _validateBridgeParams(\n BridgeParams memory params,\n BridgeParamsV2 memory paramsV2,\n int256 exclusivityEndTime\n )\n internal\n view\n {\n // Check V1 (legacy) params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.sender == address(0) || params.to == address(0)) revert ZeroAddress();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n // Check V2 params\n if (paramsV2.zapData.length \u003e MAX_ZAP_DATA_LENGTH) revert ZapDataLengthAboveMax();\n if (paramsV2.zapNative != 0 \u0026\u0026 params.destToken == NATIVE_GAS_TOKEN) {\n revert ZapNativeNotSupported();\n }\n // exclusivityEndTime must be in range [0 .. params.deadline]\n if (exclusivityEndTime \u003c 0 || exclusivityEndTime \u003e int256(params.deadline)) {\n revert ExclusivityParamsIncorrect();\n }\n }\n\n /// @notice Performs all the necessary checks for a relay to happen.\n function _validateRelayParams(bytes calldata request, bytes32 transactionId, address relayer) internal view {\n if (relayer == address(0)) revert ZeroAddress();\n // Check if the transaction has already been relayed\n if (bridgeRelays(transactionId)) revert TransactionRelayed();\n if (request.destChainId() != block.chainid) revert ChainIncorrect();\n // Check the deadline for relay to happen\n if (block.timestamp \u003e request.deadline()) revert DeadlineExceeded();\n // Check the exclusivity period, if it is still ongoing\n address exclRelayer = request.exclusivityRelayer();\n if (exclRelayer != address(0) \u0026\u0026 exclRelayer != relayer \u0026\u0026 block.timestamp \u003c= request.exclusivityEndTime()) {\n revert ExclusivityPeriodNotPassed();\n }\n }\n}\n","language":"Solidity","languageVersion":"0.8.24","compilerVersion":"0.8.24","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"","srcMapRuntime":"","abiDefinition":[{"inputs":[],"name":"DOMAIN_SEPARATOR","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"nonces","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"permit","outputs":[],"stateMutability":"nonpayable","type":"function"}],"userDoc":{"kind":"user","methods":{},"version":1},"developerDoc":{"details":"Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in https://eips.ethereum.org/EIPS/eip-2612[EIP-2612]. Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't need to send a transaction, and thus is not required to hold Ether at all. ==== Security Considerations There are two important considerations concerning the use of `permit`. The first is that a valid permit signature expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be considered as an intention to spend the allowance in any specific way. The second is that because permits have built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be generally recommended is: ```solidity function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public { try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {} doThing(..., value); } function doThing(..., uint256 value) public { token.safeTransferFrom(msg.sender, address(this), value); ... } ``` Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also {SafeERC20-safeTransferFrom}). Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so contracts should have entry points that don't rely on permit.","kind":"dev","methods":{"DOMAIN_SEPARATOR()":{"details":"Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}."},"nonces(address)":{"details":"Returns the current nonce for `owner`. This value must be included whenever a signature is generated for {permit}. Every successful call to {permit} increases ``owner``'s nonce by one. This prevents a signature from being used multiple times."},"permit(address,address,uint256,uint256,uint8,bytes32,bytes32)":{"details":"Sets `value` as the allowance of `spender` over ``owner``'s tokens, given ``owner``'s signed approval. IMPORTANT: The same issues {IERC20-approve} has related to transaction ordering also apply here. Emits an {Approval} event. Requirements: - `spender` cannot be the zero address. - `deadline` must be a timestamp in the future. - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner` over the EIP712-formatted function arguments. - the signature must use ``owner``'s current nonce (see {nonces}). For more information on the signature format, see the https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP section]. CAUTION: See Security Considerations above."}},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[],\"name\":\"DOMAIN_SEPARATOR\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"}],\"name\":\"nonces\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"},{\"internalType\":\"uint8\",\"name\":\"v\",\"type\":\"uint8\"},{\"internalType\":\"bytes32\",\"name\":\"r\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"s\",\"type\":\"bytes32\"}],\"name\":\"permit\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"details\":\"Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in https://eips.ethereum.org/EIPS/eip-2612[EIP-2612]. Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't need to send a transaction, and thus is not required to hold Ether at all. ==== Security Considerations There are two important considerations concerning the use of `permit`. The first is that a valid permit signature expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be considered as an intention to spend the allowance in any specific way. The second is that because permits have built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be generally recommended is: ```solidity function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public { try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {} doThing(..., value); } function doThing(..., uint256 value) public { token.safeTransferFrom(msg.sender, address(this), value); ... } ``` Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also {SafeERC20-safeTransferFrom}). Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so contracts should have entry points that don't rely on permit.\",\"kind\":\"dev\",\"methods\":{\"DOMAIN_SEPARATOR()\":{\"details\":\"Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\"},\"nonces(address)\":{\"details\":\"Returns the current nonce for `owner`. This value must be included whenever a signature is generated for {permit}. Every successful call to {permit} increases ``owner``'s nonce by one. This prevents a signature from being used multiple times.\"},\"permit(address,address,uint256,uint256,uint8,bytes32,bytes32)\":{\"details\":\"Sets `value` as the allowance of `spender` over ``owner``'s tokens, given ``owner``'s signed approval. IMPORTANT: The same issues {IERC20-approve} has related to transaction ordering also apply here. Emits an {Approval} event. Requirements: - `spender` cannot be the zero address. - `deadline` must be a timestamp in the future. - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner` over the EIP712-formatted function arguments. - the signature must use ``owner``'s current nonce (see {nonces}). For more information on the signature format, see the https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP section]. CAUTION: See Security Considerations above.\"}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeV2.sol\":\"IERC20Permit\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeV2.sol\":{\"keccak256\":\"0xac79c463688a682ca706a4ef95e7817b83548cdfa8182ba0426ac7e5e07613d8\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://b3ecb7097381287cafc3a73f3a2bb03565115ebb682a85064e0b0dc2f7e2919d\",\"dweb:/ipfs/QmatruW3nYZTksf3CeQ8wwiAG4c7xoEJBEp6drHPtFLBRK\"]}},\"version\":1}"},"hashes":{"DOMAIN_SEPARATOR()":"3644e515","nonces(address)":"7ecebe00","permit(address,address,uint256,uint256,uint8,bytes32,bytes32)":"d505accf"}},"solidity/FastBridgeV2.sol:IFastBridge":{"code":"0x","runtime-code":"0x","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.24 ^0.8.20 ^0.8.4;\n\n// contracts/interfaces/IAdminV2.sol\n\ninterface IAdminV2 {\n event CancelDelayUpdated(uint256 oldCancelDelay, uint256 newCancelDelay);\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n function setCancelDelay(uint256 newCancelDelay) external;\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n}\n\n// contracts/interfaces/IAdminV2Errors.sol\n\ninterface IAdminV2Errors {\n error CancelDelayBelowMin();\n error FeeRateAboveMax();\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IFastBridgeV2Errors.sol\n\ninterface IFastBridgeV2Errors {\n error AmountIncorrect();\n error ChainIncorrect();\n error ExclusivityParamsIncorrect();\n error MsgValueIncorrect();\n error SenderIncorrect();\n error StatusIncorrect();\n error TokenNotContract();\n error ZapDataLengthAboveMax();\n error ZapNativeNotSupported();\n error ZeroAddress();\n\n error RecipientIncorrectReturnValue();\n error RecipientNoReturnValue();\n\n error DeadlineExceeded();\n error DeadlineNotExceeded();\n error DeadlineTooShort();\n error DisputePeriodNotPassed();\n error DisputePeriodPassed();\n error ExclusivityPeriodNotPassed();\n\n error TransactionRelayed();\n}\n\n// contracts/interfaces/IMulticallTarget.sol\n\n/// @notice Interface for a contract that can be called multiple times by the same caller. Inspired by MulticallV3:\n/// https://github.com/mds1/multicall/blob/master/src/Multicall3.sol\ninterface IMulticallTarget {\n struct Result {\n bool success;\n bytes returnData;\n }\n\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external;\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results);\n}\n\n// contracts/interfaces/IZapRecipient.sol\n\ninterface IZapRecipient {\n function zap(address token, uint256 amount, bytes memory zapData) external payable returns (bytes4);\n}\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// contracts/interfaces/IFastBridgeV2.sol\n\ninterface IFastBridgeV2 is IFastBridge {\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n struct BridgeTxDetails {\n BridgeStatus status;\n uint32 destChainId;\n uint56 proofBlockTimestamp;\n address proofRelayer;\n }\n\n struct BridgeRelay {\n uint48 blockNumber;\n uint48 blockTimestamp;\n address relayer;\n }\n\n /// @notice New params introduced in the FastBridgeV2.\n /// We are passing fields from the older BridgeParams struct outside of this struct\n /// for backwards compatibility.\n /// Note: quoteRelayer and quoteExclusivitySeconds are either both zero (indicating no exclusivity)\n /// or both non-zero (indicating exclusivity for the given period).\n /// Note: zapNative \u003e 0 can NOT be used with destToken = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE (native token)\n /// @param quoteRelayer Relayer that provided the quote for the transaction\n /// @param quoteExclusivitySeconds Period of time the quote relayer is guaranteed exclusivity after user's deposit\n /// @param quoteId Unique quote identifier used for tracking the quote\n /// @param zapNative ETH value to send to the recipient (if any)\n /// @param zapData Parameters for the Zap to the destination recipient (if any)\n struct BridgeParamsV2 {\n address quoteRelayer;\n int256 quoteExclusivitySeconds;\n bytes quoteId;\n uint256 zapNative;\n bytes zapData;\n }\n\n /// @notice Updated bridge transaction struct to include parameters introduced in FastBridgeV2.\n /// Note: only `exclusivityRelayer` can fill such a transaction until `exclusivityEndTime`.\n struct BridgeTransactionV2 {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n // Note: sendChainGas flag from V1 is deprecated\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n address exclusivityRelayer;\n uint256 exclusivityEndTime;\n uint256 zapNative; // ETH value to send to the recipient (if any)\n bytes zapData; // data to pass for the Zap action (if any)\n }\n\n event BridgeQuoteDetails(bytes32 indexed transactionId, bytes quoteId);\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability\n /// to provide temporary exclusivity fill rights for the quote relayer.\n /// @param params The parameters required to bridge\n /// @param paramsV2 The parameters for exclusivity fill rights (optional, can be left empty)\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function relay(bytes memory request, address relayer) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param transactionId The transaction id associated with the encoded bridge transaction to prove\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital.\n /// @notice Can only send funds to the relayer address on the proof.\n /// @param request The encoded bridge transaction to claim on origin chain\n function claim(bytes memory request) external;\n\n /// @notice Cancels an outstanding bridge transaction in case optimistic bridging failed and returns the full amount\n /// to the original sender.\n /// @param request The encoded bridge transaction to refund\n function cancel(bytes memory request) external;\n\n /// @notice Checks if a transaction has been relayed\n /// @param transactionId The ID of the transaction to check\n /// @return True if the transaction has been relayed, false otherwise\n function bridgeRelays(bytes32 transactionId) external view returns (bool);\n\n /// @notice Returns the status of a bridge transaction\n /// @param transactionId The ID of the bridge transaction\n /// @return BridgeStatus Status of the bridge transaction\n function bridgeStatuses(bytes32 transactionId) external view returns (BridgeStatus);\n\n /// @notice Returns the timestamp and relayer of a bridge proof\n /// @param transactionId The ID of the bridge transaction\n /// @return timestamp The timestamp of the bridge proof\n /// @return relayer The relayer address of the bridge proof\n function bridgeProofs(bytes32 transactionId) external view returns (uint96 timestamp, address relayer);\n\n /// @notice Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\n /// @param request The bridge request to decode\n function getBridgeTransactionV2(bytes memory request) external view returns (BridgeTransactionV2 memory);\n}\n\n// contracts/utils/MulticallTarget.sol\n\n// solhint-disable avoid-low-level-calls\n/// @notice Template for a contract that supports batched calls (preserving the msg.sender).\n/// Only calls with zero msg.value could be batched.\nabstract contract MulticallTarget is IMulticallTarget {\n error MulticallTarget__UndeterminedRevert();\n\n /// @notice Perform a batched call to this contract, preserving the msg.sender.\n /// The return data from each call is discarded.\n /// @dev The method is non-payable, so only calls with `msg.value == 0` could be batched.\n /// It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag.\n /// Otherwise, the whole batch call will be reverted with the original revert reason.\n /// @param data List of abi-encoded calldata for the calls to perform.\n /// @param ignoreReverts Whether to ignore the revert errors from the calls.\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external {\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\n if (!success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(result);\n }\n }\n }\n\n /// @notice Perform a batched call to this contract, preserving the msg.sender.\n /// The return data from each call is preserved.\n /// @dev The method is non-payable, so only calls with `msg.value == 0` could be batched.\n /// It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag.\n /// Otherwise, the whole batch call will be reverted with the original revert reason.\n /// @param data List of abi-encoded calldata for the calls to perform.\n /// @param ignoreReverts Whether to ignore the revert errors from the calls.\n /// @return results List of results from the calls: `(success, returnData)`.\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results)\n {\n results = new Result[](data.length);\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (results[i].success, results[i].returnData) = address(this).delegatecall(data[i]);\n if (!results[i].success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(results[i].returnData);\n }\n }\n }\n\n /// @dev Bubbles the revert message from the underlying call.\n /// Note: preserves the same custom error or revert string, if one was used.\n /// Source: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v5.0.2/contracts/utils/Address.sol#L143-L158\n function _bubbleRevert(bytes memory returnData) internal pure {\n // Look for revert reason and bubble it up if present\n if (returnData.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n // solhint-disable-next-line no-inline-assembly\n assembly {\n let returndata_size := mload(returnData)\n revert(add(32, returnData), returndata_size)\n }\n } else {\n revert MulticallTarget__UndeterminedRevert();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// contracts/libs/BridgeTransactionV2.sol\n\n// solhint-disable no-inline-assembly\nlibrary BridgeTransactionV2Lib {\n uint16 internal constant VERSION = 2;\n\n // Offsets of the fields in the packed BridgeTransactionV2 struct\n // uint16 version [000 .. 002)\n // uint32 originChainId [002 .. 006)\n // uint32 destChainId [006 .. 010)\n // address originSender [010 .. 030)\n // address destRecipient [030 .. 050)\n // address originToken [050 .. 070)\n // address destToken [070 .. 090)\n // uint256 originAmount [090 .. 122)\n // uint256 destAmount [122 .. 154)\n // uint256 originFeeAmount [154 .. 186)\n // uint256 deadline [186 .. 218)\n // uint256 nonce [218 .. 250)\n // address exclusivityRelayer [250 .. 270)\n // uint256 exclusivityEndTime [270 .. 302)\n // uint256 zapNative [302 .. 334)\n // bytes zapData [334 .. ***)\n\n // forgefmt: disable-start\n uint256 private constant OFFSET_ORIGIN_CHAIN_ID = 2;\n uint256 private constant OFFSET_DEST_CHAIN_ID = 6;\n uint256 private constant OFFSET_ORIGIN_SENDER = 10;\n uint256 private constant OFFSET_DEST_RECIPIENT = 30;\n uint256 private constant OFFSET_ORIGIN_TOKEN = 50;\n uint256 private constant OFFSET_DEST_TOKEN = 70;\n uint256 private constant OFFSET_ORIGIN_AMOUNT = 90;\n uint256 private constant OFFSET_DEST_AMOUNT = 122;\n uint256 private constant OFFSET_ORIGIN_FEE_AMOUNT = 154;\n uint256 private constant OFFSET_DEADLINE = 186;\n uint256 private constant OFFSET_NONCE = 218;\n uint256 private constant OFFSET_EXCLUSIVITY_RELAYER = 250;\n uint256 private constant OFFSET_EXCLUSIVITY_END_TIME = 270;\n uint256 private constant OFFSET_ZAP_NATIVE = 302;\n uint256 private constant OFFSET_ZAP_DATA = 334;\n // forgefmt: disable-end\n\n error BridgeTransactionV2__InvalidEncodedTx();\n error BridgeTransactionV2__UnsupportedVersion(uint16 version);\n\n /// @notice Validates the encoded transaction to be a tightly packed encoded payload for BridgeTransactionV2.\n /// @dev Checks the minimum length and the version, use this function before decoding any of the fields.\n function validateV2(bytes calldata encodedTx) internal pure {\n // Check the minimum length: must at least include all static fields.\n if (encodedTx.length \u003c OFFSET_ZAP_DATA) revert BridgeTransactionV2__InvalidEncodedTx();\n // Once we validated the length, we can be sure that the version field is present.\n uint16 version_ = version(encodedTx);\n if (version_ != VERSION) revert BridgeTransactionV2__UnsupportedVersion(version_);\n }\n\n /// @notice Encodes the BridgeTransactionV2 struct by tightly packing the fields.\n /// @dev `abi.decode` will not work as a result of the tightly packed fields. Use `decodeV2` to decode instead.\n function encodeV2(IFastBridgeV2.BridgeTransactionV2 memory bridgeTx) internal pure returns (bytes memory) {\n // We split the encoding into two parts to avoid stack-too-deep error\n bytes memory firstPart = abi.encodePacked(\n VERSION,\n bridgeTx.originChainId,\n bridgeTx.destChainId,\n bridgeTx.originSender,\n bridgeTx.destRecipient,\n bridgeTx.originToken,\n bridgeTx.destToken,\n bridgeTx.originAmount\n );\n return abi.encodePacked(\n firstPart,\n bridgeTx.destAmount,\n bridgeTx.originFeeAmount,\n // Note: we skip the deprecated `sendChainGas` flag, which was present in BridgeTransaction V1\n bridgeTx.deadline,\n bridgeTx.nonce,\n // New V2 fields: exclusivity\n bridgeTx.exclusivityRelayer,\n bridgeTx.exclusivityEndTime,\n // New V2 fields: Zap\n bridgeTx.zapNative,\n bridgeTx.zapData\n );\n }\n\n /// @notice Decodes the BridgeTransactionV2 struct from the encoded transaction.\n /// @dev Encoded BridgeTransactionV2 struct must be tightly packed.\n /// Use `validateV2` before decoding to ensure the encoded transaction is valid.\n function decodeV2(bytes calldata encodedTx)\n internal\n pure\n returns (IFastBridgeV2.BridgeTransactionV2 memory bridgeTx)\n {\n bridgeTx.originChainId = originChainId(encodedTx);\n bridgeTx.destChainId = destChainId(encodedTx);\n bridgeTx.originSender = originSender(encodedTx);\n bridgeTx.destRecipient = destRecipient(encodedTx);\n bridgeTx.originToken = originToken(encodedTx);\n bridgeTx.destToken = destToken(encodedTx);\n bridgeTx.originAmount = originAmount(encodedTx);\n bridgeTx.destAmount = destAmount(encodedTx);\n bridgeTx.originFeeAmount = originFeeAmount(encodedTx);\n bridgeTx.deadline = deadline(encodedTx);\n bridgeTx.nonce = nonce(encodedTx);\n bridgeTx.exclusivityRelayer = exclusivityRelayer(encodedTx);\n bridgeTx.exclusivityEndTime = exclusivityEndTime(encodedTx);\n bridgeTx.zapNative = zapNative(encodedTx);\n bridgeTx.zapData = zapData(encodedTx);\n }\n\n /// @notice Extracts the version from the encoded transaction.\n function version(bytes calldata encodedTx) internal pure returns (uint16 version_) {\n // Load 32 bytes from the start and shift it 240 bits to the right to get the highest 16 bits.\n assembly {\n version_ := shr(240, calldataload(encodedTx.offset))\n }\n }\n\n /// @notice Extracts the origin chain ID from the encoded transaction.\n function originChainId(bytes calldata encodedTx) internal pure returns (uint32 originChainId_) {\n // Load 32 bytes from the offset and shift it 224 bits to the right to get the highest 32 bits.\n assembly {\n originChainId_ := shr(224, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_CHAIN_ID)))\n }\n }\n\n /// @notice Extracts the destination chain ID from the encoded transaction.\n function destChainId(bytes calldata encodedTx) internal pure returns (uint32 destChainId_) {\n // Load 32 bytes from the offset and shift it 224 bits to the right to get the highest 32 bits.\n assembly {\n destChainId_ := shr(224, calldataload(add(encodedTx.offset, OFFSET_DEST_CHAIN_ID)))\n }\n }\n\n /// @notice Extracts the origin sender from the encoded transaction.\n function originSender(bytes calldata encodedTx) internal pure returns (address originSender_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n originSender_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_SENDER)))\n }\n }\n\n /// @notice Extracts the destination recipient from the encoded transaction.\n function destRecipient(bytes calldata encodedTx) internal pure returns (address destRecipient_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n destRecipient_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_DEST_RECIPIENT)))\n }\n }\n\n /// @notice Extracts the origin token from the encoded transaction.\n function originToken(bytes calldata encodedTx) internal pure returns (address originToken_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n originToken_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_TOKEN)))\n }\n }\n\n /// @notice Extracts the destination token from the encoded transaction.\n function destToken(bytes calldata encodedTx) internal pure returns (address destToken_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n destToken_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_DEST_TOKEN)))\n }\n }\n\n /// @notice Extracts the origin amount from the encoded transaction.\n function originAmount(bytes calldata encodedTx) internal pure returns (uint256 originAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n originAmount_ := calldataload(add(encodedTx.offset, OFFSET_ORIGIN_AMOUNT))\n }\n }\n\n /// @notice Extracts the destination amount from the encoded transaction.\n function destAmount(bytes calldata encodedTx) internal pure returns (uint256 destAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n destAmount_ := calldataload(add(encodedTx.offset, OFFSET_DEST_AMOUNT))\n }\n }\n\n /// @notice Extracts the origin fee amount from the encoded transaction.\n function originFeeAmount(bytes calldata encodedTx) internal pure returns (uint256 originFeeAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n originFeeAmount_ := calldataload(add(encodedTx.offset, OFFSET_ORIGIN_FEE_AMOUNT))\n }\n }\n\n /// @notice Extracts the deadline from the encoded transaction.\n function deadline(bytes calldata encodedTx) internal pure returns (uint256 deadline_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n deadline_ := calldataload(add(encodedTx.offset, OFFSET_DEADLINE))\n }\n }\n\n /// @notice Extracts the nonce from the encoded transaction.\n function nonce(bytes calldata encodedTx) internal pure returns (uint256 nonce_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n nonce_ := calldataload(add(encodedTx.offset, OFFSET_NONCE))\n }\n }\n\n /// @notice Extracts the exclusivity relayer from the encoded transaction.\n function exclusivityRelayer(bytes calldata encodedTx) internal pure returns (address exclusivityRelayer_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n exclusivityRelayer_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_EXCLUSIVITY_RELAYER)))\n }\n }\n\n /// @notice Extracts the exclusivity end time from the encoded transaction.\n function exclusivityEndTime(bytes calldata encodedTx) internal pure returns (uint256 exclusivityEndTime_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n exclusivityEndTime_ := calldataload(add(encodedTx.offset, OFFSET_EXCLUSIVITY_END_TIME))\n }\n }\n\n /// @notice Extracts the Zap's native value from the encoded transaction.\n function zapNative(bytes calldata encodedTx) internal pure returns (uint256 zapNative_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n zapNative_ := calldataload(add(encodedTx.offset, OFFSET_ZAP_NATIVE))\n }\n }\n\n /// @notice Extracts the Zap's data from the encoded transaction.\n function zapData(bytes calldata encodedTx) internal pure returns (bytes calldata zapData_) {\n zapData_ = encodedTx[OFFSET_ZAP_DATA:];\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/AdminV2.sol\n\ncontract AdminV2 is AccessControlEnumerable, IAdminV2, IAdminV2Errors {\n using SafeERC20 for IERC20;\n\n /// @notice Address reserved for native gas token (ETH on Ethereum and most L2s, AVAX on Avalanche, etc)\n address public constant NATIVE_GAS_TOKEN = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Role identifier for Quoter API's off-chain authentication.\n /// @dev Only addresses with this role can post FastBridge quotes to the API.\n bytes32 public constant QUOTER_ROLE = keccak256(\"QUOTER_ROLE\");\n\n /// @notice Role identifier for Prover's on-chain authentication in FastBridge.\n /// @dev Only addresses with this role can provide proofs that a FastBridge request has been relayed.\n bytes32 public constant PROVER_ROLE = keccak256(\"PROVER_ROLE\");\n\n /// @notice Role identifier for Guard's on-chain authentication in FastBridge.\n /// @dev Only addresses with this role can dispute submitted relay proofs during the dispute period.\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n\n /// @notice Role identifier for Canceler's on-chain authentication in FastBridge.\n /// @dev Only addresses with this role can cancel a FastBridge transaction without the cancel delay.\n bytes32 public constant CANCELER_ROLE = keccak256(\"CANCELER_ROLE\");\n\n /// @notice Role identifier for Governor's on-chain administrative authority.\n /// @dev Only addresses with this role can perform administrative tasks within the contract.\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n /// @notice Denominator for fee rates, represents 100%.\n uint256 public constant FEE_BPS = 1e6;\n /// @notice Maximum protocol fee rate: 1% on origin amount.\n uint256 public constant FEE_RATE_MAX = 0.01e6;\n\n /// @notice Minimum cancel delay that can be set by the governor.\n uint256 public constant MIN_CANCEL_DELAY = 1 hours;\n /// @notice Default cancel delay set during the contract deployment.\n uint256 public constant DEFAULT_CANCEL_DELAY = 1 days;\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Delay for a transaction after which it could be permisionlessly cancelled\n uint256 public cancelDelay;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Use ZapNative V2 requests instead.\n uint256 public immutable chainGasAmount = 0;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n _setCancelDelay(DEFAULT_CANCEL_DELAY);\n }\n\n /// @notice Allows the contract governor to set the cancel delay. The cancel delay is the time after the transaction\n /// deadline after which it can be permissionlessly cancelled, if it hasn't been proven by any of the Relayers.\n function setCancelDelay(uint256 newCancelDelay) external onlyRole(GOVERNOR_ROLE) {\n _setCancelDelay(newCancelDelay);\n }\n\n /// @notice Allows the contract governor to set the protocol fee rate. The protocol fee is taken from the origin\n /// amount only for completed and claimed transactions.\n /// @dev The protocol fee is abstracted away from the relayers, they always operate using the amounts after fees:\n /// what they see as the origin amount emitted in the log is what they get credited with.\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n if (newFeeRate \u003e FEE_RATE_MAX) revert FeeRateAboveMax();\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n /// @notice Allows the contract governor to sweep the accumulated protocol fees in the contract.\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n emit FeesSwept(token, recipient, feeAmount);\n /// Sweep the fees as the last transaction action\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(recipient), feeAmount);\n } else {\n IERC20(token).safeTransfer(recipient, feeAmount);\n }\n }\n\n /// @notice Internal function to set the cancel delay. Security checks are performed outside of this function.\n function _setCancelDelay(uint256 newCancelDelay) private {\n if (newCancelDelay \u003c MIN_CANCEL_DELAY) revert CancelDelayBelowMin();\n uint256 oldCancelDelay = cancelDelay;\n cancelDelay = newCancelDelay;\n emit CancelDelayUpdated(oldCancelDelay, newCancelDelay);\n }\n}\n\n// contracts/FastBridgeV2.sol\n\n/// @notice FastBridgeV2 is a contract for bridging tokens across chains.\ncontract FastBridgeV2 is AdminV2, MulticallTarget, IFastBridgeV2, IFastBridgeV2Errors {\n using BridgeTransactionV2Lib for bytes;\n using SafeERC20 for IERC20;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n /// @notice Maximum length of accepted zapData\n uint256 public constant MAX_ZAP_DATA_LENGTH = 2 ** 16 - 1;\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeTxDetails) public bridgeTxDetails;\n /// @notice Relay details on destination chain\n mapping(bytes32 =\u003e BridgeRelay) public bridgeRelayDetails;\n /// @notice Unique bridge nonces tracked per originSender\n mapping(address =\u003e uint256) public senderNonces;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Replaced by senderNonces\n uint256 public immutable nonce = 0;\n /// @notice the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) AdminV2(_owner) {\n deployBlock = block.number;\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n bridge({\n params: params,\n paramsV2: BridgeParamsV2({\n quoteRelayer: address(0),\n quoteExclusivitySeconds: 0,\n quoteId: bytes(\"\"),\n zapNative: 0,\n zapData: bytes(\"\")\n })\n });\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes calldata request) external payable {\n // relay override will validate the request\n relay({request: request, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes calldata request, bytes32 destTxHash) external {\n request.validateV2();\n prove({transactionId: keccak256(request), destTxHash: destTxHash, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridgeV2\n function claim(bytes calldata request) external {\n // claim override will validate the request\n claim({request: request, to: address(0)});\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Aggregate the read operations from the same storage slot\n address disputedRelayer = $.proofRelayer;\n BridgeStatus status = $.status;\n uint56 proofBlockTimestamp = $.proofBlockTimestamp;\n // Can only dispute a RELAYER_PROVED transaction within the dispute period\n if (status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(proofBlockTimestamp) \u003e DISPUTE_PERIOD) {\n revert DisputePeriodPassed();\n }\n // Update status to REQUESTED and delete the disputed proof details\n // Note: these are storage writes\n $.status = BridgeStatus.REQUESTED;\n $.proofRelayer = address(0);\n $.proofBlockTimestamp = 0;\n\n emit BridgeProofDisputed(transactionId, disputedRelayer);\n }\n\n /// Note: this function is deprecated and will be removed in a future version.\n /// @inheritdoc IFastBridge\n function refund(bytes calldata request) external {\n cancel(request);\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // The correct relayer can only claim a RELAYER_PROVED transaction after the dispute period\n if ($.status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if ($.proofRelayer != relayer) revert SenderIncorrect();\n return _timeSince($.proofBlockTimestamp) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n /// @dev This method is added to achieve backwards compatibility with decoding requests into V1 structs:\n /// - `zapNative` is partially reported as a zero/non-zero flag\n /// - `zapData` is ignored\n /// In order to process all kinds of requests use getBridgeTransactionV2 instead.\n function getBridgeTransaction(bytes calldata request) external view returns (BridgeTransaction memory) {\n // Try decoding into V2 struct first. This will revert if V1 struct is passed\n try this.getBridgeTransactionV2(request) returns (BridgeTransactionV2 memory txV2) {\n // Note: we entirely ignore the zapData field, as it was not present in V1\n return BridgeTransaction({\n originChainId: txV2.originChainId,\n destChainId: txV2.destChainId,\n originSender: txV2.originSender,\n destRecipient: txV2.destRecipient,\n originToken: txV2.originToken,\n destToken: txV2.destToken,\n originAmount: txV2.originAmount,\n destAmount: txV2.destAmount,\n originFeeAmount: txV2.originFeeAmount,\n sendChainGas: txV2.zapNative != 0,\n deadline: txV2.deadline,\n nonce: txV2.nonce\n });\n } catch {\n // Fallback to V1 struct\n return abi.decode(request, (BridgeTransaction));\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function getBridgeTransactionV2(bytes calldata request) external pure returns (BridgeTransactionV2 memory) {\n request.validateV2();\n return BridgeTransactionV2Lib.decodeV2(request);\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) public payable {\n int256 exclusivityEndTime = 0;\n // if relayer exclusivity is not intended for this bridge, set exclusivityEndTime to static zero\n // otherwise, set exclusivity to expire at the current block ts offset by quoteExclusivitySeconds\n if (paramsV2.quoteRelayer != address(0)) {\n exclusivityEndTime = int256(block.timestamp) + paramsV2.quoteExclusivitySeconds;\n }\n _validateBridgeParams(params, paramsV2, exclusivityEndTime);\n\n // transfer tokens to bridge contract\n /// @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _takeBridgedUserAsset(params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) {\n originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n }\n\n // set status to requested\n bytes memory request = BridgeTransactionV2Lib.encodeV2(\n BridgeTransactionV2({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n deadline: params.deadline,\n nonce: senderNonces[params.sender]++, // increment nonce on every bridge\n exclusivityRelayer: paramsV2.quoteRelayer,\n // We checked exclusivityEndTime to be in range [0 .. params.deadline] above, so can safely cast\n exclusivityEndTime: uint256(exclusivityEndTime),\n zapNative: paramsV2.zapNative,\n zapData: paramsV2.zapData\n })\n );\n bytes32 transactionId = keccak256(request);\n // Note: the tx status will be updated throughout the tx lifecycle, while destChainId is set once here\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n bridgeTxDetails[transactionId].destChainId = params.dstChainId;\n\n emit BridgeRequested({\n transactionId: transactionId,\n sender: params.sender,\n request: request,\n destChainId: params.dstChainId,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n sendChainGas: paramsV2.zapNative != 0\n });\n emit BridgeQuoteDetails(transactionId, paramsV2.quoteId);\n }\n\n /// @inheritdoc IFastBridgeV2\n function relay(bytes calldata request, address relayer) public payable {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n _validateRelayParams(request, transactionId, relayer);\n // mark bridge transaction as relayed\n bridgeRelayDetails[transactionId] =\n BridgeRelay({blockNumber: uint48(block.number), blockTimestamp: uint48(block.timestamp), relayer: relayer});\n\n // transfer tokens to recipient on destination chain and trigger Zap if requested\n address to = request.destRecipient();\n address token = request.destToken();\n uint256 amount = request.destAmount();\n uint256 zapNative = request.zapNative();\n\n // Emit the event before any external calls\n emit BridgeRelayed({\n transactionId: transactionId,\n relayer: relayer,\n to: to,\n originChainId: request.originChainId(),\n originToken: request.originToken(),\n destToken: token,\n originAmount: request.originAmount(),\n destAmount: amount,\n chainGasAmount: zapNative\n });\n\n // All state changes have been done at this point, can proceed to the external calls.\n // This follows the checks-effects-interactions pattern to mitigate potential reentrancy attacks.\n if (token == NATIVE_GAS_TOKEN) {\n // For the native gas token, additional zapNative is not allowed\n if (zapNative != 0) revert ZapNativeNotSupported();\n // Check that the correct msg.value was sent\n if (msg.value != amount) revert MsgValueIncorrect();\n // Don't do a native transfer yet: we will handle it alongside the Zap below\n } else {\n // For ERC20s, we check that the correct msg.value was sent\n if (msg.value != zapNative) revert MsgValueIncorrect();\n // We need to transfer the tokens from the Relayer to the recipient first before performing an\n // optional post-transfer Zap.\n IERC20(token).safeTransferFrom(msg.sender, to, amount);\n }\n // At this point we have done:\n // - Transferred the requested amount of ERC20 tokens to the recipient.\n // At this point we have confirmed:\n // - For ERC20s: msg.value matches the requested zapNative amount.\n // - For the native gas token: msg.value matches the requested destAmount.\n // Remaining optional things to do:\n // - Forward the full msg.value to the recipient (if non-zero).\n // - Trigger a Zap (if zapData is present).\n bytes calldata zapData = request.zapData();\n if (zapData.length != 0) {\n // Zap Data is present: Zap has been requested by the recipient. Trigger it forwarding the full msg.value.\n\n // Note: if token has a fee on transfers, the recipient will have received less than `amount`.\n // This is a very niche edge case and should be handled by the recipient contract.\n _triggerZapWithChecks({recipient: to, token: token, amount: amount, zapData: zapData});\n } else if (msg.value != 0) {\n // Zap Data is missing, but msg.value was sent. This could happen in two different cases:\n // - Relay with the native gas token is happening.\n // - Relay with ERC20 is happening, with a `zapNative \u003e 0` request.\n // In both cases, we need to transfer the full msg.value to the recipient.\n Address.sendValue(payable(to), msg.value);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) public onlyRole(PROVER_ROLE) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n\n // Can only prove a REQUESTED transaction\n if ($.status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n // Update status to RELAYER_PROVED and store the proof details\n // Note: these are storage writes\n $.status = BridgeStatus.RELAYER_PROVED;\n $.proofBlockTimestamp = uint56(block.timestamp);\n $.proofRelayer = relayer;\n\n emit BridgeProofProvided(transactionId, relayer, destTxHash);\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes calldata request, address to) public {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Aggregate the read operations from the same storage slot\n address proofRelayer = $.proofRelayer;\n BridgeStatus status = $.status;\n uint56 proofBlockTimestamp = $.proofBlockTimestamp;\n\n // Can only claim a RELAYER_PROVED transaction after the dispute period\n if (status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(proofBlockTimestamp) \u003c= DISPUTE_PERIOD) {\n revert DisputePeriodNotPassed();\n }\n\n if (to == address(0)) {\n // Anyone could claim the funds to the proven relayer on their behalf\n to = proofRelayer;\n } else if (proofRelayer != msg.sender) {\n // Only the proven relayer could specify an address to claim the funds to\n revert SenderIncorrect();\n }\n\n // Update status to RELAYER_CLAIMED and transfer the origin collateral to the specified claim address\n // Note: this is a storage write\n $.status = BridgeStatus.RELAYER_CLAIMED;\n\n address token = request.originToken();\n uint256 amount = request.originAmount();\n // Update protocol fees if origin fee amount exists\n uint256 originFeeAmount = request.originFeeAmount();\n if (originFeeAmount \u003e 0) protocolFees[token] += originFeeAmount;\n // Emit the event before any external calls\n emit BridgeDepositClaimed(transactionId, proofRelayer, to, token, amount);\n // Complete the relayer claim as the last transaction action\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(to), amount);\n } else {\n IERC20(token).safeTransfer(to, amount);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function cancel(bytes calldata request) public {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Can only cancel a REQUESTED transaction after its deadline expires\n if ($.status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n uint256 deadline = request.deadline();\n // Permissionless cancel is only allowed after `cancelDelay` on top of the deadline\n if (!hasRole(CANCELER_ROLE, msg.sender)) deadline += cancelDelay;\n if (block.timestamp \u003c= deadline) revert DeadlineNotExceeded();\n // Update status to REFUNDED and return the full amount (collateral + protocol fees) to the original sender.\n // The protocol fees are only updated when the transaction is claimed, so we don't need to update them here.\n // Note: this is a storage write\n $.status = BridgeStatus.REFUNDED;\n\n address to = request.originSender();\n address token = request.originToken();\n uint256 amount = request.originAmount() + request.originFeeAmount();\n // Emit the event before any external calls\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n // Complete the user cancel as the last transaction action\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(to), amount);\n } else {\n IERC20(token).safeTransfer(to, amount);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeStatuses(bytes32 transactionId) public view returns (BridgeStatus status) {\n return bridgeTxDetails[transactionId].status;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeProofs(bytes32 transactionId) public view returns (uint96 timestamp, address relayer) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n\n timestamp = $.proofBlockTimestamp;\n relayer = $.proofRelayer;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeRelays(bytes32 transactionId) public view returns (bool) {\n // has this transactionId been relayed?\n return bridgeRelayDetails[transactionId].relayer != address(0);\n }\n\n /// @notice Takes the bridged asset from the user into FastBridgeV2 custody. It will be later\n /// claimed by the relayer who completed the relay on destination chain, or transferred back to the user\n /// via the cancel function should no one complete the relay.\n function _takeBridgedUserAsset(address token, uint256 amount) internal returns (uint256 amountTaken) {\n if (token == NATIVE_GAS_TOKEN) {\n // For the native gas token, we just need to check that the supplied msg.value is correct.\n // Supplied `msg.value` is already in FastBridgeV2 custody.\n if (amount != msg.value) revert MsgValueIncorrect();\n amountTaken = msg.value;\n } else {\n // For ERC20s, token is explicitly transferred from the user to FastBridgeV2.\n // We don't allow non-zero `msg.value` to avoid extra funds from being stuck in FastBridgeV2.\n if (msg.value != 0) revert MsgValueIncorrect();\n // Throw an explicit error if the provided token address is not a contract\n if (token.code.length == 0) revert TokenNotContract();\n amountTaken = IERC20(token).balanceOf(address(this));\n IERC20(token).safeTransferFrom(msg.sender, address(this), amount);\n // Use the balance difference as the amount taken in case of fee on transfer tokens.\n amountTaken = IERC20(token).balanceOf(address(this)) - amountTaken;\n }\n }\n\n /// @notice Calls the Recipient's hook function with the specified zapData and performs\n /// all the necessary checks for the returned value.\n function _triggerZapWithChecks(address recipient, address token, uint256 amount, bytes calldata zapData) internal {\n // This will bubble any revert messages from the hook function\n bytes memory returnData = Address.functionCallWithValue({\n target: recipient,\n data: abi.encodeCall(IZapRecipient.zap, (token, amount, zapData)),\n // Note: see `relay()` for reasoning behind passing msg.value\n value: msg.value\n });\n // Explicit revert if no return data at all\n if (returnData.length == 0) revert RecipientNoReturnValue();\n // Check that exactly a single return value was returned\n if (returnData.length != 32) revert RecipientIncorrectReturnValue();\n // Return value should be abi-encoded hook function selector\n if (bytes32(returnData) != bytes32(IZapRecipient.zap.selector)) {\n revert RecipientIncorrectReturnValue();\n }\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint56(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint56).max but\n /// proof.timestamp \u003c type(uint56).max via unchecked statement\n /// @param proofBlockTimestamp The bridge proof block timestamp\n /// @return delta Time delta since proof submitted\n function _timeSince(uint56 proofBlockTimestamp) internal view returns (uint256 delta) {\n unchecked {\n delta = uint56(block.timestamp) - proofBlockTimestamp;\n }\n }\n\n /// @notice Performs all the necessary checks for a bridge to happen.\n /// @dev There's no good way to refactor this function to reduce cyclomatic complexity due to\n /// the number of checks that need to be performed, so we skip the code-complexity rule here.\n // solhint-disable-next-line code-complexity\n function _validateBridgeParams(\n BridgeParams memory params,\n BridgeParamsV2 memory paramsV2,\n int256 exclusivityEndTime\n )\n internal\n view\n {\n // Check V1 (legacy) params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.sender == address(0) || params.to == address(0)) revert ZeroAddress();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n // Check V2 params\n if (paramsV2.zapData.length \u003e MAX_ZAP_DATA_LENGTH) revert ZapDataLengthAboveMax();\n if (paramsV2.zapNative != 0 \u0026\u0026 params.destToken == NATIVE_GAS_TOKEN) {\n revert ZapNativeNotSupported();\n }\n // exclusivityEndTime must be in range [0 .. params.deadline]\n if (exclusivityEndTime \u003c 0 || exclusivityEndTime \u003e int256(params.deadline)) {\n revert ExclusivityParamsIncorrect();\n }\n }\n\n /// @notice Performs all the necessary checks for a relay to happen.\n function _validateRelayParams(bytes calldata request, bytes32 transactionId, address relayer) internal view {\n if (relayer == address(0)) revert ZeroAddress();\n // Check if the transaction has already been relayed\n if (bridgeRelays(transactionId)) revert TransactionRelayed();\n if (request.destChainId() != block.chainid) revert ChainIncorrect();\n // Check the deadline for relay to happen\n if (block.timestamp \u003e request.deadline()) revert DeadlineExceeded();\n // Check the exclusivity period, if it is still ongoing\n address exclRelayer = request.exclusivityRelayer();\n if (exclRelayer != address(0) \u0026\u0026 exclRelayer != relayer \u0026\u0026 block.timestamp \u003c= request.exclusivityEndTime()) {\n revert ExclusivityPeriodNotPassed();\n }\n }\n}\n","language":"Solidity","languageVersion":"0.8.24","compilerVersion":"0.8.24","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"","srcMapRuntime":"","abiDefinition":[{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"relayer","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"BridgeDepositClaimed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"BridgeDepositRefunded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"relayer","type":"address"}],"name":"BridgeProofDisputed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"relayer","type":"address"},{"indexed":false,"internalType":"bytes32","name":"transactionHash","type":"bytes32"}],"name":"BridgeProofProvided","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"relayer","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint32","name":"originChainId","type":"uint32"},{"indexed":false,"internalType":"address","name":"originToken","type":"address"},{"indexed":false,"internalType":"address","name":"destToken","type":"address"},{"indexed":false,"internalType":"uint256","name":"originAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"destAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"chainGasAmount","type":"uint256"}],"name":"BridgeRelayed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"bytes","name":"request","type":"bytes"},{"indexed":false,"internalType":"uint32","name":"destChainId","type":"uint32"},{"indexed":false,"internalType":"address","name":"originToken","type":"address"},{"indexed":false,"internalType":"address","name":"destToken","type":"address"},{"indexed":false,"internalType":"uint256","name":"originAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"destAmount","type":"uint256"},{"indexed":false,"internalType":"bool","name":"sendChainGas","type":"bool"}],"name":"BridgeRequested","type":"event"},{"inputs":[{"components":[{"internalType":"uint32","name":"dstChainId","type":"uint32"},{"internalType":"address","name":"sender","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"address","name":"originToken","type":"address"},{"internalType":"address","name":"destToken","type":"address"},{"internalType":"uint256","name":"originAmount","type":"uint256"},{"internalType":"uint256","name":"destAmount","type":"uint256"},{"internalType":"bool","name":"sendChainGas","type":"bool"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"internalType":"struct IFastBridge.BridgeParams","name":"params","type":"tuple"}],"name":"bridge","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"internalType":"address","name":"relayer","type":"address"}],"name":"canClaim","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"},{"internalType":"address","name":"to","type":"address"}],"name":"claim","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"transactionId","type":"bytes32"}],"name":"dispute","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"}],"name":"getBridgeTransaction","outputs":[{"components":[{"internalType":"uint32","name":"originChainId","type":"uint32"},{"internalType":"uint32","name":"destChainId","type":"uint32"},{"internalType":"address","name":"originSender","type":"address"},{"internalType":"address","name":"destRecipient","type":"address"},{"internalType":"address","name":"originToken","type":"address"},{"internalType":"address","name":"destToken","type":"address"},{"internalType":"uint256","name":"originAmount","type":"uint256"},{"internalType":"uint256","name":"destAmount","type":"uint256"},{"internalType":"uint256","name":"originFeeAmount","type":"uint256"},{"internalType":"bool","name":"sendChainGas","type":"bool"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint256","name":"nonce","type":"uint256"}],"internalType":"struct IFastBridge.BridgeTransaction","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"},{"internalType":"bytes32","name":"destTxHash","type":"bytes32"}],"name":"prove","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"}],"name":"refund","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"}],"name":"relay","outputs":[],"stateMutability":"payable","type":"function"}],"userDoc":{"kind":"user","methods":{"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256))":{"notice":"Initiates bridge on origin chain to be relayed by off-chain relayer"},"canClaim(bytes32,address)":{"notice":"Checks if the dispute period has passed so bridge deposit can be claimed"},"claim(bytes,address)":{"notice":"Completes bridge transaction on origin chain by claiming originally deposited capital"},"dispute(bytes32)":{"notice":"Disputes an outstanding proof in case relayer provided dest chain tx is invalid"},"getBridgeTransaction(bytes)":{"notice":"Decodes bridge request into a bridge transaction"},"prove(bytes,bytes32)":{"notice":"Provides proof on origin side that relayer provided funds on destination side of bridge transaction"},"refund(bytes)":{"notice":"Refunds an outstanding bridge transaction in case optimistic bridging failed"},"relay(bytes)":{"notice":"Relays destination side of bridge transaction by off-chain relayer"}},"version":1},"developerDoc":{"kind":"dev","methods":{"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256))":{"params":{"params":"The parameters required to bridge"}},"canClaim(bytes32,address)":{"params":{"relayer":"The address of the relayer attempting to claim","transactionId":"The transaction id associated with the encoded bridge transaction to check"}},"claim(bytes,address)":{"params":{"request":"The encoded bridge transaction to claim on origin chain","to":"The recipient address of the funds"}},"dispute(bytes32)":{"params":{"transactionId":"The transaction id associated with the encoded bridge transaction to dispute"}},"getBridgeTransaction(bytes)":{"params":{"request":"The bridge request to decode"}},"prove(bytes,bytes32)":{"params":{"destTxHash":"The destination tx hash proving bridge transaction was relayed","request":"The encoded bridge transaction to prove on origin chain"}},"refund(bytes)":{"params":{"request":"The encoded bridge transaction to refund"}},"relay(bytes)":{"params":{"request":"The encoded bridge transaction to relay on destination chain"}}},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"BridgeDepositClaimed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"BridgeDepositRefunded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"name\":\"BridgeProofDisputed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"transactionHash\",\"type\":\"bytes32\"}],\"name\":\"BridgeProofProvided\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"originChainId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"chainGasAmount\",\"type\":\"uint256\"}],\"name\":\"BridgeRelayed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"destChainId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"sendChainGas\",\"type\":\"bool\"}],\"name\":\"BridgeRequested\",\"type\":\"event\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"dstChainId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"sendChainGas\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"}],\"internalType\":\"struct IFastBridge.BridgeParams\",\"name\":\"params\",\"type\":\"tuple\"}],\"name\":\"bridge\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"name\":\"canClaim\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"claim\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"}],\"name\":\"dispute\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"getBridgeTransaction\",\"outputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"originChainId\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"destChainId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"originSender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destRecipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"originFeeAmount\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"sendChainGas\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"}],\"internalType\":\"struct IFastBridge.BridgeTransaction\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"},{\"internalType\":\"bytes32\",\"name\":\"destTxHash\",\"type\":\"bytes32\"}],\"name\":\"prove\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"refund\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"relay\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{\"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256))\":{\"params\":{\"params\":\"The parameters required to bridge\"}},\"canClaim(bytes32,address)\":{\"params\":{\"relayer\":\"The address of the relayer attempting to claim\",\"transactionId\":\"The transaction id associated with the encoded bridge transaction to check\"}},\"claim(bytes,address)\":{\"params\":{\"request\":\"The encoded bridge transaction to claim on origin chain\",\"to\":\"The recipient address of the funds\"}},\"dispute(bytes32)\":{\"params\":{\"transactionId\":\"The transaction id associated with the encoded bridge transaction to dispute\"}},\"getBridgeTransaction(bytes)\":{\"params\":{\"request\":\"The bridge request to decode\"}},\"prove(bytes,bytes32)\":{\"params\":{\"destTxHash\":\"The destination tx hash proving bridge transaction was relayed\",\"request\":\"The encoded bridge transaction to prove on origin chain\"}},\"refund(bytes)\":{\"params\":{\"request\":\"The encoded bridge transaction to refund\"}},\"relay(bytes)\":{\"params\":{\"request\":\"The encoded bridge transaction to relay on destination chain\"}}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256))\":{\"notice\":\"Initiates bridge on origin chain to be relayed by off-chain relayer\"},\"canClaim(bytes32,address)\":{\"notice\":\"Checks if the dispute period has passed so bridge deposit can be claimed\"},\"claim(bytes,address)\":{\"notice\":\"Completes bridge transaction on origin chain by claiming originally deposited capital\"},\"dispute(bytes32)\":{\"notice\":\"Disputes an outstanding proof in case relayer provided dest chain tx is invalid\"},\"getBridgeTransaction(bytes)\":{\"notice\":\"Decodes bridge request into a bridge transaction\"},\"prove(bytes,bytes32)\":{\"notice\":\"Provides proof on origin side that relayer provided funds on destination side of bridge transaction\"},\"refund(bytes)\":{\"notice\":\"Refunds an outstanding bridge transaction in case optimistic bridging failed\"},\"relay(bytes)\":{\"notice\":\"Relays destination side of bridge transaction by off-chain relayer\"}},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeV2.sol\":\"IFastBridge\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeV2.sol\":{\"keccak256\":\"0xac79c463688a682ca706a4ef95e7817b83548cdfa8182ba0426ac7e5e07613d8\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://b3ecb7097381287cafc3a73f3a2bb03565115ebb682a85064e0b0dc2f7e2919d\",\"dweb:/ipfs/QmatruW3nYZTksf3CeQ8wwiAG4c7xoEJBEp6drHPtFLBRK\"]}},\"version\":1}"},"hashes":{"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256))":"45851694","canClaim(bytes32,address)":"aa9641ab","claim(bytes,address)":"41fcb612","dispute(bytes32)":"add98c70","getBridgeTransaction(bytes)":"ac11fb1a","prove(bytes,bytes32)":"886d36ff","refund(bytes)":"5eb7d946","relay(bytes)":"8f0d6f17"}},"solidity/FastBridgeV2.sol:IFastBridgeV2":{"code":"0x","runtime-code":"0x","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.24 ^0.8.20 ^0.8.4;\n\n// contracts/interfaces/IAdminV2.sol\n\ninterface IAdminV2 {\n event CancelDelayUpdated(uint256 oldCancelDelay, uint256 newCancelDelay);\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n function setCancelDelay(uint256 newCancelDelay) external;\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n}\n\n// contracts/interfaces/IAdminV2Errors.sol\n\ninterface IAdminV2Errors {\n error CancelDelayBelowMin();\n error FeeRateAboveMax();\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IFastBridgeV2Errors.sol\n\ninterface IFastBridgeV2Errors {\n error AmountIncorrect();\n error ChainIncorrect();\n error ExclusivityParamsIncorrect();\n error MsgValueIncorrect();\n error SenderIncorrect();\n error StatusIncorrect();\n error TokenNotContract();\n error ZapDataLengthAboveMax();\n error ZapNativeNotSupported();\n error ZeroAddress();\n\n error RecipientIncorrectReturnValue();\n error RecipientNoReturnValue();\n\n error DeadlineExceeded();\n error DeadlineNotExceeded();\n error DeadlineTooShort();\n error DisputePeriodNotPassed();\n error DisputePeriodPassed();\n error ExclusivityPeriodNotPassed();\n\n error TransactionRelayed();\n}\n\n// contracts/interfaces/IMulticallTarget.sol\n\n/// @notice Interface for a contract that can be called multiple times by the same caller. Inspired by MulticallV3:\n/// https://github.com/mds1/multicall/blob/master/src/Multicall3.sol\ninterface IMulticallTarget {\n struct Result {\n bool success;\n bytes returnData;\n }\n\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external;\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results);\n}\n\n// contracts/interfaces/IZapRecipient.sol\n\ninterface IZapRecipient {\n function zap(address token, uint256 amount, bytes memory zapData) external payable returns (bytes4);\n}\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// contracts/interfaces/IFastBridgeV2.sol\n\ninterface IFastBridgeV2 is IFastBridge {\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n struct BridgeTxDetails {\n BridgeStatus status;\n uint32 destChainId;\n uint56 proofBlockTimestamp;\n address proofRelayer;\n }\n\n struct BridgeRelay {\n uint48 blockNumber;\n uint48 blockTimestamp;\n address relayer;\n }\n\n /// @notice New params introduced in the FastBridgeV2.\n /// We are passing fields from the older BridgeParams struct outside of this struct\n /// for backwards compatibility.\n /// Note: quoteRelayer and quoteExclusivitySeconds are either both zero (indicating no exclusivity)\n /// or both non-zero (indicating exclusivity for the given period).\n /// Note: zapNative \u003e 0 can NOT be used with destToken = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE (native token)\n /// @param quoteRelayer Relayer that provided the quote for the transaction\n /// @param quoteExclusivitySeconds Period of time the quote relayer is guaranteed exclusivity after user's deposit\n /// @param quoteId Unique quote identifier used for tracking the quote\n /// @param zapNative ETH value to send to the recipient (if any)\n /// @param zapData Parameters for the Zap to the destination recipient (if any)\n struct BridgeParamsV2 {\n address quoteRelayer;\n int256 quoteExclusivitySeconds;\n bytes quoteId;\n uint256 zapNative;\n bytes zapData;\n }\n\n /// @notice Updated bridge transaction struct to include parameters introduced in FastBridgeV2.\n /// Note: only `exclusivityRelayer` can fill such a transaction until `exclusivityEndTime`.\n struct BridgeTransactionV2 {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n // Note: sendChainGas flag from V1 is deprecated\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n address exclusivityRelayer;\n uint256 exclusivityEndTime;\n uint256 zapNative; // ETH value to send to the recipient (if any)\n bytes zapData; // data to pass for the Zap action (if any)\n }\n\n event BridgeQuoteDetails(bytes32 indexed transactionId, bytes quoteId);\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability\n /// to provide temporary exclusivity fill rights for the quote relayer.\n /// @param params The parameters required to bridge\n /// @param paramsV2 The parameters for exclusivity fill rights (optional, can be left empty)\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function relay(bytes memory request, address relayer) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param transactionId The transaction id associated with the encoded bridge transaction to prove\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital.\n /// @notice Can only send funds to the relayer address on the proof.\n /// @param request The encoded bridge transaction to claim on origin chain\n function claim(bytes memory request) external;\n\n /// @notice Cancels an outstanding bridge transaction in case optimistic bridging failed and returns the full amount\n /// to the original sender.\n /// @param request The encoded bridge transaction to refund\n function cancel(bytes memory request) external;\n\n /// @notice Checks if a transaction has been relayed\n /// @param transactionId The ID of the transaction to check\n /// @return True if the transaction has been relayed, false otherwise\n function bridgeRelays(bytes32 transactionId) external view returns (bool);\n\n /// @notice Returns the status of a bridge transaction\n /// @param transactionId The ID of the bridge transaction\n /// @return BridgeStatus Status of the bridge transaction\n function bridgeStatuses(bytes32 transactionId) external view returns (BridgeStatus);\n\n /// @notice Returns the timestamp and relayer of a bridge proof\n /// @param transactionId The ID of the bridge transaction\n /// @return timestamp The timestamp of the bridge proof\n /// @return relayer The relayer address of the bridge proof\n function bridgeProofs(bytes32 transactionId) external view returns (uint96 timestamp, address relayer);\n\n /// @notice Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\n /// @param request The bridge request to decode\n function getBridgeTransactionV2(bytes memory request) external view returns (BridgeTransactionV2 memory);\n}\n\n// contracts/utils/MulticallTarget.sol\n\n// solhint-disable avoid-low-level-calls\n/// @notice Template for a contract that supports batched calls (preserving the msg.sender).\n/// Only calls with zero msg.value could be batched.\nabstract contract MulticallTarget is IMulticallTarget {\n error MulticallTarget__UndeterminedRevert();\n\n /// @notice Perform a batched call to this contract, preserving the msg.sender.\n /// The return data from each call is discarded.\n /// @dev The method is non-payable, so only calls with `msg.value == 0` could be batched.\n /// It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag.\n /// Otherwise, the whole batch call will be reverted with the original revert reason.\n /// @param data List of abi-encoded calldata for the calls to perform.\n /// @param ignoreReverts Whether to ignore the revert errors from the calls.\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external {\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\n if (!success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(result);\n }\n }\n }\n\n /// @notice Perform a batched call to this contract, preserving the msg.sender.\n /// The return data from each call is preserved.\n /// @dev The method is non-payable, so only calls with `msg.value == 0` could be batched.\n /// It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag.\n /// Otherwise, the whole batch call will be reverted with the original revert reason.\n /// @param data List of abi-encoded calldata for the calls to perform.\n /// @param ignoreReverts Whether to ignore the revert errors from the calls.\n /// @return results List of results from the calls: `(success, returnData)`.\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results)\n {\n results = new Result[](data.length);\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (results[i].success, results[i].returnData) = address(this).delegatecall(data[i]);\n if (!results[i].success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(results[i].returnData);\n }\n }\n }\n\n /// @dev Bubbles the revert message from the underlying call.\n /// Note: preserves the same custom error or revert string, if one was used.\n /// Source: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v5.0.2/contracts/utils/Address.sol#L143-L158\n function _bubbleRevert(bytes memory returnData) internal pure {\n // Look for revert reason and bubble it up if present\n if (returnData.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n // solhint-disable-next-line no-inline-assembly\n assembly {\n let returndata_size := mload(returnData)\n revert(add(32, returnData), returndata_size)\n }\n } else {\n revert MulticallTarget__UndeterminedRevert();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// contracts/libs/BridgeTransactionV2.sol\n\n// solhint-disable no-inline-assembly\nlibrary BridgeTransactionV2Lib {\n uint16 internal constant VERSION = 2;\n\n // Offsets of the fields in the packed BridgeTransactionV2 struct\n // uint16 version [000 .. 002)\n // uint32 originChainId [002 .. 006)\n // uint32 destChainId [006 .. 010)\n // address originSender [010 .. 030)\n // address destRecipient [030 .. 050)\n // address originToken [050 .. 070)\n // address destToken [070 .. 090)\n // uint256 originAmount [090 .. 122)\n // uint256 destAmount [122 .. 154)\n // uint256 originFeeAmount [154 .. 186)\n // uint256 deadline [186 .. 218)\n // uint256 nonce [218 .. 250)\n // address exclusivityRelayer [250 .. 270)\n // uint256 exclusivityEndTime [270 .. 302)\n // uint256 zapNative [302 .. 334)\n // bytes zapData [334 .. ***)\n\n // forgefmt: disable-start\n uint256 private constant OFFSET_ORIGIN_CHAIN_ID = 2;\n uint256 private constant OFFSET_DEST_CHAIN_ID = 6;\n uint256 private constant OFFSET_ORIGIN_SENDER = 10;\n uint256 private constant OFFSET_DEST_RECIPIENT = 30;\n uint256 private constant OFFSET_ORIGIN_TOKEN = 50;\n uint256 private constant OFFSET_DEST_TOKEN = 70;\n uint256 private constant OFFSET_ORIGIN_AMOUNT = 90;\n uint256 private constant OFFSET_DEST_AMOUNT = 122;\n uint256 private constant OFFSET_ORIGIN_FEE_AMOUNT = 154;\n uint256 private constant OFFSET_DEADLINE = 186;\n uint256 private constant OFFSET_NONCE = 218;\n uint256 private constant OFFSET_EXCLUSIVITY_RELAYER = 250;\n uint256 private constant OFFSET_EXCLUSIVITY_END_TIME = 270;\n uint256 private constant OFFSET_ZAP_NATIVE = 302;\n uint256 private constant OFFSET_ZAP_DATA = 334;\n // forgefmt: disable-end\n\n error BridgeTransactionV2__InvalidEncodedTx();\n error BridgeTransactionV2__UnsupportedVersion(uint16 version);\n\n /// @notice Validates the encoded transaction to be a tightly packed encoded payload for BridgeTransactionV2.\n /// @dev Checks the minimum length and the version, use this function before decoding any of the fields.\n function validateV2(bytes calldata encodedTx) internal pure {\n // Check the minimum length: must at least include all static fields.\n if (encodedTx.length \u003c OFFSET_ZAP_DATA) revert BridgeTransactionV2__InvalidEncodedTx();\n // Once we validated the length, we can be sure that the version field is present.\n uint16 version_ = version(encodedTx);\n if (version_ != VERSION) revert BridgeTransactionV2__UnsupportedVersion(version_);\n }\n\n /// @notice Encodes the BridgeTransactionV2 struct by tightly packing the fields.\n /// @dev `abi.decode` will not work as a result of the tightly packed fields. Use `decodeV2` to decode instead.\n function encodeV2(IFastBridgeV2.BridgeTransactionV2 memory bridgeTx) internal pure returns (bytes memory) {\n // We split the encoding into two parts to avoid stack-too-deep error\n bytes memory firstPart = abi.encodePacked(\n VERSION,\n bridgeTx.originChainId,\n bridgeTx.destChainId,\n bridgeTx.originSender,\n bridgeTx.destRecipient,\n bridgeTx.originToken,\n bridgeTx.destToken,\n bridgeTx.originAmount\n );\n return abi.encodePacked(\n firstPart,\n bridgeTx.destAmount,\n bridgeTx.originFeeAmount,\n // Note: we skip the deprecated `sendChainGas` flag, which was present in BridgeTransaction V1\n bridgeTx.deadline,\n bridgeTx.nonce,\n // New V2 fields: exclusivity\n bridgeTx.exclusivityRelayer,\n bridgeTx.exclusivityEndTime,\n // New V2 fields: Zap\n bridgeTx.zapNative,\n bridgeTx.zapData\n );\n }\n\n /// @notice Decodes the BridgeTransactionV2 struct from the encoded transaction.\n /// @dev Encoded BridgeTransactionV2 struct must be tightly packed.\n /// Use `validateV2` before decoding to ensure the encoded transaction is valid.\n function decodeV2(bytes calldata encodedTx)\n internal\n pure\n returns (IFastBridgeV2.BridgeTransactionV2 memory bridgeTx)\n {\n bridgeTx.originChainId = originChainId(encodedTx);\n bridgeTx.destChainId = destChainId(encodedTx);\n bridgeTx.originSender = originSender(encodedTx);\n bridgeTx.destRecipient = destRecipient(encodedTx);\n bridgeTx.originToken = originToken(encodedTx);\n bridgeTx.destToken = destToken(encodedTx);\n bridgeTx.originAmount = originAmount(encodedTx);\n bridgeTx.destAmount = destAmount(encodedTx);\n bridgeTx.originFeeAmount = originFeeAmount(encodedTx);\n bridgeTx.deadline = deadline(encodedTx);\n bridgeTx.nonce = nonce(encodedTx);\n bridgeTx.exclusivityRelayer = exclusivityRelayer(encodedTx);\n bridgeTx.exclusivityEndTime = exclusivityEndTime(encodedTx);\n bridgeTx.zapNative = zapNative(encodedTx);\n bridgeTx.zapData = zapData(encodedTx);\n }\n\n /// @notice Extracts the version from the encoded transaction.\n function version(bytes calldata encodedTx) internal pure returns (uint16 version_) {\n // Load 32 bytes from the start and shift it 240 bits to the right to get the highest 16 bits.\n assembly {\n version_ := shr(240, calldataload(encodedTx.offset))\n }\n }\n\n /// @notice Extracts the origin chain ID from the encoded transaction.\n function originChainId(bytes calldata encodedTx) internal pure returns (uint32 originChainId_) {\n // Load 32 bytes from the offset and shift it 224 bits to the right to get the highest 32 bits.\n assembly {\n originChainId_ := shr(224, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_CHAIN_ID)))\n }\n }\n\n /// @notice Extracts the destination chain ID from the encoded transaction.\n function destChainId(bytes calldata encodedTx) internal pure returns (uint32 destChainId_) {\n // Load 32 bytes from the offset and shift it 224 bits to the right to get the highest 32 bits.\n assembly {\n destChainId_ := shr(224, calldataload(add(encodedTx.offset, OFFSET_DEST_CHAIN_ID)))\n }\n }\n\n /// @notice Extracts the origin sender from the encoded transaction.\n function originSender(bytes calldata encodedTx) internal pure returns (address originSender_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n originSender_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_SENDER)))\n }\n }\n\n /// @notice Extracts the destination recipient from the encoded transaction.\n function destRecipient(bytes calldata encodedTx) internal pure returns (address destRecipient_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n destRecipient_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_DEST_RECIPIENT)))\n }\n }\n\n /// @notice Extracts the origin token from the encoded transaction.\n function originToken(bytes calldata encodedTx) internal pure returns (address originToken_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n originToken_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_TOKEN)))\n }\n }\n\n /// @notice Extracts the destination token from the encoded transaction.\n function destToken(bytes calldata encodedTx) internal pure returns (address destToken_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n destToken_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_DEST_TOKEN)))\n }\n }\n\n /// @notice Extracts the origin amount from the encoded transaction.\n function originAmount(bytes calldata encodedTx) internal pure returns (uint256 originAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n originAmount_ := calldataload(add(encodedTx.offset, OFFSET_ORIGIN_AMOUNT))\n }\n }\n\n /// @notice Extracts the destination amount from the encoded transaction.\n function destAmount(bytes calldata encodedTx) internal pure returns (uint256 destAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n destAmount_ := calldataload(add(encodedTx.offset, OFFSET_DEST_AMOUNT))\n }\n }\n\n /// @notice Extracts the origin fee amount from the encoded transaction.\n function originFeeAmount(bytes calldata encodedTx) internal pure returns (uint256 originFeeAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n originFeeAmount_ := calldataload(add(encodedTx.offset, OFFSET_ORIGIN_FEE_AMOUNT))\n }\n }\n\n /// @notice Extracts the deadline from the encoded transaction.\n function deadline(bytes calldata encodedTx) internal pure returns (uint256 deadline_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n deadline_ := calldataload(add(encodedTx.offset, OFFSET_DEADLINE))\n }\n }\n\n /// @notice Extracts the nonce from the encoded transaction.\n function nonce(bytes calldata encodedTx) internal pure returns (uint256 nonce_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n nonce_ := calldataload(add(encodedTx.offset, OFFSET_NONCE))\n }\n }\n\n /// @notice Extracts the exclusivity relayer from the encoded transaction.\n function exclusivityRelayer(bytes calldata encodedTx) internal pure returns (address exclusivityRelayer_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n exclusivityRelayer_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_EXCLUSIVITY_RELAYER)))\n }\n }\n\n /// @notice Extracts the exclusivity end time from the encoded transaction.\n function exclusivityEndTime(bytes calldata encodedTx) internal pure returns (uint256 exclusivityEndTime_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n exclusivityEndTime_ := calldataload(add(encodedTx.offset, OFFSET_EXCLUSIVITY_END_TIME))\n }\n }\n\n /// @notice Extracts the Zap's native value from the encoded transaction.\n function zapNative(bytes calldata encodedTx) internal pure returns (uint256 zapNative_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n zapNative_ := calldataload(add(encodedTx.offset, OFFSET_ZAP_NATIVE))\n }\n }\n\n /// @notice Extracts the Zap's data from the encoded transaction.\n function zapData(bytes calldata encodedTx) internal pure returns (bytes calldata zapData_) {\n zapData_ = encodedTx[OFFSET_ZAP_DATA:];\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/AdminV2.sol\n\ncontract AdminV2 is AccessControlEnumerable, IAdminV2, IAdminV2Errors {\n using SafeERC20 for IERC20;\n\n /// @notice Address reserved for native gas token (ETH on Ethereum and most L2s, AVAX on Avalanche, etc)\n address public constant NATIVE_GAS_TOKEN = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Role identifier for Quoter API's off-chain authentication.\n /// @dev Only addresses with this role can post FastBridge quotes to the API.\n bytes32 public constant QUOTER_ROLE = keccak256(\"QUOTER_ROLE\");\n\n /// @notice Role identifier for Prover's on-chain authentication in FastBridge.\n /// @dev Only addresses with this role can provide proofs that a FastBridge request has been relayed.\n bytes32 public constant PROVER_ROLE = keccak256(\"PROVER_ROLE\");\n\n /// @notice Role identifier for Guard's on-chain authentication in FastBridge.\n /// @dev Only addresses with this role can dispute submitted relay proofs during the dispute period.\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n\n /// @notice Role identifier for Canceler's on-chain authentication in FastBridge.\n /// @dev Only addresses with this role can cancel a FastBridge transaction without the cancel delay.\n bytes32 public constant CANCELER_ROLE = keccak256(\"CANCELER_ROLE\");\n\n /// @notice Role identifier for Governor's on-chain administrative authority.\n /// @dev Only addresses with this role can perform administrative tasks within the contract.\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n /// @notice Denominator for fee rates, represents 100%.\n uint256 public constant FEE_BPS = 1e6;\n /// @notice Maximum protocol fee rate: 1% on origin amount.\n uint256 public constant FEE_RATE_MAX = 0.01e6;\n\n /// @notice Minimum cancel delay that can be set by the governor.\n uint256 public constant MIN_CANCEL_DELAY = 1 hours;\n /// @notice Default cancel delay set during the contract deployment.\n uint256 public constant DEFAULT_CANCEL_DELAY = 1 days;\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Delay for a transaction after which it could be permisionlessly cancelled\n uint256 public cancelDelay;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Use ZapNative V2 requests instead.\n uint256 public immutable chainGasAmount = 0;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n _setCancelDelay(DEFAULT_CANCEL_DELAY);\n }\n\n /// @notice Allows the contract governor to set the cancel delay. The cancel delay is the time after the transaction\n /// deadline after which it can be permissionlessly cancelled, if it hasn't been proven by any of the Relayers.\n function setCancelDelay(uint256 newCancelDelay) external onlyRole(GOVERNOR_ROLE) {\n _setCancelDelay(newCancelDelay);\n }\n\n /// @notice Allows the contract governor to set the protocol fee rate. The protocol fee is taken from the origin\n /// amount only for completed and claimed transactions.\n /// @dev The protocol fee is abstracted away from the relayers, they always operate using the amounts after fees:\n /// what they see as the origin amount emitted in the log is what they get credited with.\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n if (newFeeRate \u003e FEE_RATE_MAX) revert FeeRateAboveMax();\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n /// @notice Allows the contract governor to sweep the accumulated protocol fees in the contract.\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n emit FeesSwept(token, recipient, feeAmount);\n /// Sweep the fees as the last transaction action\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(recipient), feeAmount);\n } else {\n IERC20(token).safeTransfer(recipient, feeAmount);\n }\n }\n\n /// @notice Internal function to set the cancel delay. Security checks are performed outside of this function.\n function _setCancelDelay(uint256 newCancelDelay) private {\n if (newCancelDelay \u003c MIN_CANCEL_DELAY) revert CancelDelayBelowMin();\n uint256 oldCancelDelay = cancelDelay;\n cancelDelay = newCancelDelay;\n emit CancelDelayUpdated(oldCancelDelay, newCancelDelay);\n }\n}\n\n// contracts/FastBridgeV2.sol\n\n/// @notice FastBridgeV2 is a contract for bridging tokens across chains.\ncontract FastBridgeV2 is AdminV2, MulticallTarget, IFastBridgeV2, IFastBridgeV2Errors {\n using BridgeTransactionV2Lib for bytes;\n using SafeERC20 for IERC20;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n /// @notice Maximum length of accepted zapData\n uint256 public constant MAX_ZAP_DATA_LENGTH = 2 ** 16 - 1;\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeTxDetails) public bridgeTxDetails;\n /// @notice Relay details on destination chain\n mapping(bytes32 =\u003e BridgeRelay) public bridgeRelayDetails;\n /// @notice Unique bridge nonces tracked per originSender\n mapping(address =\u003e uint256) public senderNonces;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Replaced by senderNonces\n uint256 public immutable nonce = 0;\n /// @notice the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) AdminV2(_owner) {\n deployBlock = block.number;\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n bridge({\n params: params,\n paramsV2: BridgeParamsV2({\n quoteRelayer: address(0),\n quoteExclusivitySeconds: 0,\n quoteId: bytes(\"\"),\n zapNative: 0,\n zapData: bytes(\"\")\n })\n });\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes calldata request) external payable {\n // relay override will validate the request\n relay({request: request, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes calldata request, bytes32 destTxHash) external {\n request.validateV2();\n prove({transactionId: keccak256(request), destTxHash: destTxHash, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridgeV2\n function claim(bytes calldata request) external {\n // claim override will validate the request\n claim({request: request, to: address(0)});\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Aggregate the read operations from the same storage slot\n address disputedRelayer = $.proofRelayer;\n BridgeStatus status = $.status;\n uint56 proofBlockTimestamp = $.proofBlockTimestamp;\n // Can only dispute a RELAYER_PROVED transaction within the dispute period\n if (status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(proofBlockTimestamp) \u003e DISPUTE_PERIOD) {\n revert DisputePeriodPassed();\n }\n // Update status to REQUESTED and delete the disputed proof details\n // Note: these are storage writes\n $.status = BridgeStatus.REQUESTED;\n $.proofRelayer = address(0);\n $.proofBlockTimestamp = 0;\n\n emit BridgeProofDisputed(transactionId, disputedRelayer);\n }\n\n /// Note: this function is deprecated and will be removed in a future version.\n /// @inheritdoc IFastBridge\n function refund(bytes calldata request) external {\n cancel(request);\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // The correct relayer can only claim a RELAYER_PROVED transaction after the dispute period\n if ($.status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if ($.proofRelayer != relayer) revert SenderIncorrect();\n return _timeSince($.proofBlockTimestamp) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n /// @dev This method is added to achieve backwards compatibility with decoding requests into V1 structs:\n /// - `zapNative` is partially reported as a zero/non-zero flag\n /// - `zapData` is ignored\n /// In order to process all kinds of requests use getBridgeTransactionV2 instead.\n function getBridgeTransaction(bytes calldata request) external view returns (BridgeTransaction memory) {\n // Try decoding into V2 struct first. This will revert if V1 struct is passed\n try this.getBridgeTransactionV2(request) returns (BridgeTransactionV2 memory txV2) {\n // Note: we entirely ignore the zapData field, as it was not present in V1\n return BridgeTransaction({\n originChainId: txV2.originChainId,\n destChainId: txV2.destChainId,\n originSender: txV2.originSender,\n destRecipient: txV2.destRecipient,\n originToken: txV2.originToken,\n destToken: txV2.destToken,\n originAmount: txV2.originAmount,\n destAmount: txV2.destAmount,\n originFeeAmount: txV2.originFeeAmount,\n sendChainGas: txV2.zapNative != 0,\n deadline: txV2.deadline,\n nonce: txV2.nonce\n });\n } catch {\n // Fallback to V1 struct\n return abi.decode(request, (BridgeTransaction));\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function getBridgeTransactionV2(bytes calldata request) external pure returns (BridgeTransactionV2 memory) {\n request.validateV2();\n return BridgeTransactionV2Lib.decodeV2(request);\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) public payable {\n int256 exclusivityEndTime = 0;\n // if relayer exclusivity is not intended for this bridge, set exclusivityEndTime to static zero\n // otherwise, set exclusivity to expire at the current block ts offset by quoteExclusivitySeconds\n if (paramsV2.quoteRelayer != address(0)) {\n exclusivityEndTime = int256(block.timestamp) + paramsV2.quoteExclusivitySeconds;\n }\n _validateBridgeParams(params, paramsV2, exclusivityEndTime);\n\n // transfer tokens to bridge contract\n /// @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _takeBridgedUserAsset(params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) {\n originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n }\n\n // set status to requested\n bytes memory request = BridgeTransactionV2Lib.encodeV2(\n BridgeTransactionV2({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n deadline: params.deadline,\n nonce: senderNonces[params.sender]++, // increment nonce on every bridge\n exclusivityRelayer: paramsV2.quoteRelayer,\n // We checked exclusivityEndTime to be in range [0 .. params.deadline] above, so can safely cast\n exclusivityEndTime: uint256(exclusivityEndTime),\n zapNative: paramsV2.zapNative,\n zapData: paramsV2.zapData\n })\n );\n bytes32 transactionId = keccak256(request);\n // Note: the tx status will be updated throughout the tx lifecycle, while destChainId is set once here\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n bridgeTxDetails[transactionId].destChainId = params.dstChainId;\n\n emit BridgeRequested({\n transactionId: transactionId,\n sender: params.sender,\n request: request,\n destChainId: params.dstChainId,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n sendChainGas: paramsV2.zapNative != 0\n });\n emit BridgeQuoteDetails(transactionId, paramsV2.quoteId);\n }\n\n /// @inheritdoc IFastBridgeV2\n function relay(bytes calldata request, address relayer) public payable {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n _validateRelayParams(request, transactionId, relayer);\n // mark bridge transaction as relayed\n bridgeRelayDetails[transactionId] =\n BridgeRelay({blockNumber: uint48(block.number), blockTimestamp: uint48(block.timestamp), relayer: relayer});\n\n // transfer tokens to recipient on destination chain and trigger Zap if requested\n address to = request.destRecipient();\n address token = request.destToken();\n uint256 amount = request.destAmount();\n uint256 zapNative = request.zapNative();\n\n // Emit the event before any external calls\n emit BridgeRelayed({\n transactionId: transactionId,\n relayer: relayer,\n to: to,\n originChainId: request.originChainId(),\n originToken: request.originToken(),\n destToken: token,\n originAmount: request.originAmount(),\n destAmount: amount,\n chainGasAmount: zapNative\n });\n\n // All state changes have been done at this point, can proceed to the external calls.\n // This follows the checks-effects-interactions pattern to mitigate potential reentrancy attacks.\n if (token == NATIVE_GAS_TOKEN) {\n // For the native gas token, additional zapNative is not allowed\n if (zapNative != 0) revert ZapNativeNotSupported();\n // Check that the correct msg.value was sent\n if (msg.value != amount) revert MsgValueIncorrect();\n // Don't do a native transfer yet: we will handle it alongside the Zap below\n } else {\n // For ERC20s, we check that the correct msg.value was sent\n if (msg.value != zapNative) revert MsgValueIncorrect();\n // We need to transfer the tokens from the Relayer to the recipient first before performing an\n // optional post-transfer Zap.\n IERC20(token).safeTransferFrom(msg.sender, to, amount);\n }\n // At this point we have done:\n // - Transferred the requested amount of ERC20 tokens to the recipient.\n // At this point we have confirmed:\n // - For ERC20s: msg.value matches the requested zapNative amount.\n // - For the native gas token: msg.value matches the requested destAmount.\n // Remaining optional things to do:\n // - Forward the full msg.value to the recipient (if non-zero).\n // - Trigger a Zap (if zapData is present).\n bytes calldata zapData = request.zapData();\n if (zapData.length != 0) {\n // Zap Data is present: Zap has been requested by the recipient. Trigger it forwarding the full msg.value.\n\n // Note: if token has a fee on transfers, the recipient will have received less than `amount`.\n // This is a very niche edge case and should be handled by the recipient contract.\n _triggerZapWithChecks({recipient: to, token: token, amount: amount, zapData: zapData});\n } else if (msg.value != 0) {\n // Zap Data is missing, but msg.value was sent. This could happen in two different cases:\n // - Relay with the native gas token is happening.\n // - Relay with ERC20 is happening, with a `zapNative \u003e 0` request.\n // In both cases, we need to transfer the full msg.value to the recipient.\n Address.sendValue(payable(to), msg.value);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) public onlyRole(PROVER_ROLE) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n\n // Can only prove a REQUESTED transaction\n if ($.status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n // Update status to RELAYER_PROVED and store the proof details\n // Note: these are storage writes\n $.status = BridgeStatus.RELAYER_PROVED;\n $.proofBlockTimestamp = uint56(block.timestamp);\n $.proofRelayer = relayer;\n\n emit BridgeProofProvided(transactionId, relayer, destTxHash);\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes calldata request, address to) public {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Aggregate the read operations from the same storage slot\n address proofRelayer = $.proofRelayer;\n BridgeStatus status = $.status;\n uint56 proofBlockTimestamp = $.proofBlockTimestamp;\n\n // Can only claim a RELAYER_PROVED transaction after the dispute period\n if (status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(proofBlockTimestamp) \u003c= DISPUTE_PERIOD) {\n revert DisputePeriodNotPassed();\n }\n\n if (to == address(0)) {\n // Anyone could claim the funds to the proven relayer on their behalf\n to = proofRelayer;\n } else if (proofRelayer != msg.sender) {\n // Only the proven relayer could specify an address to claim the funds to\n revert SenderIncorrect();\n }\n\n // Update status to RELAYER_CLAIMED and transfer the origin collateral to the specified claim address\n // Note: this is a storage write\n $.status = BridgeStatus.RELAYER_CLAIMED;\n\n address token = request.originToken();\n uint256 amount = request.originAmount();\n // Update protocol fees if origin fee amount exists\n uint256 originFeeAmount = request.originFeeAmount();\n if (originFeeAmount \u003e 0) protocolFees[token] += originFeeAmount;\n // Emit the event before any external calls\n emit BridgeDepositClaimed(transactionId, proofRelayer, to, token, amount);\n // Complete the relayer claim as the last transaction action\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(to), amount);\n } else {\n IERC20(token).safeTransfer(to, amount);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function cancel(bytes calldata request) public {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Can only cancel a REQUESTED transaction after its deadline expires\n if ($.status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n uint256 deadline = request.deadline();\n // Permissionless cancel is only allowed after `cancelDelay` on top of the deadline\n if (!hasRole(CANCELER_ROLE, msg.sender)) deadline += cancelDelay;\n if (block.timestamp \u003c= deadline) revert DeadlineNotExceeded();\n // Update status to REFUNDED and return the full amount (collateral + protocol fees) to the original sender.\n // The protocol fees are only updated when the transaction is claimed, so we don't need to update them here.\n // Note: this is a storage write\n $.status = BridgeStatus.REFUNDED;\n\n address to = request.originSender();\n address token = request.originToken();\n uint256 amount = request.originAmount() + request.originFeeAmount();\n // Emit the event before any external calls\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n // Complete the user cancel as the last transaction action\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(to), amount);\n } else {\n IERC20(token).safeTransfer(to, amount);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeStatuses(bytes32 transactionId) public view returns (BridgeStatus status) {\n return bridgeTxDetails[transactionId].status;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeProofs(bytes32 transactionId) public view returns (uint96 timestamp, address relayer) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n\n timestamp = $.proofBlockTimestamp;\n relayer = $.proofRelayer;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeRelays(bytes32 transactionId) public view returns (bool) {\n // has this transactionId been relayed?\n return bridgeRelayDetails[transactionId].relayer != address(0);\n }\n\n /// @notice Takes the bridged asset from the user into FastBridgeV2 custody. It will be later\n /// claimed by the relayer who completed the relay on destination chain, or transferred back to the user\n /// via the cancel function should no one complete the relay.\n function _takeBridgedUserAsset(address token, uint256 amount) internal returns (uint256 amountTaken) {\n if (token == NATIVE_GAS_TOKEN) {\n // For the native gas token, we just need to check that the supplied msg.value is correct.\n // Supplied `msg.value` is already in FastBridgeV2 custody.\n if (amount != msg.value) revert MsgValueIncorrect();\n amountTaken = msg.value;\n } else {\n // For ERC20s, token is explicitly transferred from the user to FastBridgeV2.\n // We don't allow non-zero `msg.value` to avoid extra funds from being stuck in FastBridgeV2.\n if (msg.value != 0) revert MsgValueIncorrect();\n // Throw an explicit error if the provided token address is not a contract\n if (token.code.length == 0) revert TokenNotContract();\n amountTaken = IERC20(token).balanceOf(address(this));\n IERC20(token).safeTransferFrom(msg.sender, address(this), amount);\n // Use the balance difference as the amount taken in case of fee on transfer tokens.\n amountTaken = IERC20(token).balanceOf(address(this)) - amountTaken;\n }\n }\n\n /// @notice Calls the Recipient's hook function with the specified zapData and performs\n /// all the necessary checks for the returned value.\n function _triggerZapWithChecks(address recipient, address token, uint256 amount, bytes calldata zapData) internal {\n // This will bubble any revert messages from the hook function\n bytes memory returnData = Address.functionCallWithValue({\n target: recipient,\n data: abi.encodeCall(IZapRecipient.zap, (token, amount, zapData)),\n // Note: see `relay()` for reasoning behind passing msg.value\n value: msg.value\n });\n // Explicit revert if no return data at all\n if (returnData.length == 0) revert RecipientNoReturnValue();\n // Check that exactly a single return value was returned\n if (returnData.length != 32) revert RecipientIncorrectReturnValue();\n // Return value should be abi-encoded hook function selector\n if (bytes32(returnData) != bytes32(IZapRecipient.zap.selector)) {\n revert RecipientIncorrectReturnValue();\n }\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint56(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint56).max but\n /// proof.timestamp \u003c type(uint56).max via unchecked statement\n /// @param proofBlockTimestamp The bridge proof block timestamp\n /// @return delta Time delta since proof submitted\n function _timeSince(uint56 proofBlockTimestamp) internal view returns (uint256 delta) {\n unchecked {\n delta = uint56(block.timestamp) - proofBlockTimestamp;\n }\n }\n\n /// @notice Performs all the necessary checks for a bridge to happen.\n /// @dev There's no good way to refactor this function to reduce cyclomatic complexity due to\n /// the number of checks that need to be performed, so we skip the code-complexity rule here.\n // solhint-disable-next-line code-complexity\n function _validateBridgeParams(\n BridgeParams memory params,\n BridgeParamsV2 memory paramsV2,\n int256 exclusivityEndTime\n )\n internal\n view\n {\n // Check V1 (legacy) params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.sender == address(0) || params.to == address(0)) revert ZeroAddress();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n // Check V2 params\n if (paramsV2.zapData.length \u003e MAX_ZAP_DATA_LENGTH) revert ZapDataLengthAboveMax();\n if (paramsV2.zapNative != 0 \u0026\u0026 params.destToken == NATIVE_GAS_TOKEN) {\n revert ZapNativeNotSupported();\n }\n // exclusivityEndTime must be in range [0 .. params.deadline]\n if (exclusivityEndTime \u003c 0 || exclusivityEndTime \u003e int256(params.deadline)) {\n revert ExclusivityParamsIncorrect();\n }\n }\n\n /// @notice Performs all the necessary checks for a relay to happen.\n function _validateRelayParams(bytes calldata request, bytes32 transactionId, address relayer) internal view {\n if (relayer == address(0)) revert ZeroAddress();\n // Check if the transaction has already been relayed\n if (bridgeRelays(transactionId)) revert TransactionRelayed();\n if (request.destChainId() != block.chainid) revert ChainIncorrect();\n // Check the deadline for relay to happen\n if (block.timestamp \u003e request.deadline()) revert DeadlineExceeded();\n // Check the exclusivity period, if it is still ongoing\n address exclRelayer = request.exclusivityRelayer();\n if (exclRelayer != address(0) \u0026\u0026 exclRelayer != relayer \u0026\u0026 block.timestamp \u003c= request.exclusivityEndTime()) {\n revert ExclusivityPeriodNotPassed();\n }\n }\n}\n","language":"Solidity","languageVersion":"0.8.24","compilerVersion":"0.8.24","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"","srcMapRuntime":"","abiDefinition":[{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"relayer","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"BridgeDepositClaimed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"BridgeDepositRefunded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"relayer","type":"address"}],"name":"BridgeProofDisputed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"relayer","type":"address"},{"indexed":false,"internalType":"bytes32","name":"transactionHash","type":"bytes32"}],"name":"BridgeProofProvided","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":false,"internalType":"bytes","name":"quoteId","type":"bytes"}],"name":"BridgeQuoteDetails","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"relayer","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint32","name":"originChainId","type":"uint32"},{"indexed":false,"internalType":"address","name":"originToken","type":"address"},{"indexed":false,"internalType":"address","name":"destToken","type":"address"},{"indexed":false,"internalType":"uint256","name":"originAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"destAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"chainGasAmount","type":"uint256"}],"name":"BridgeRelayed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"bytes","name":"request","type":"bytes"},{"indexed":false,"internalType":"uint32","name":"destChainId","type":"uint32"},{"indexed":false,"internalType":"address","name":"originToken","type":"address"},{"indexed":false,"internalType":"address","name":"destToken","type":"address"},{"indexed":false,"internalType":"uint256","name":"originAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"destAmount","type":"uint256"},{"indexed":false,"internalType":"bool","name":"sendChainGas","type":"bool"}],"name":"BridgeRequested","type":"event"},{"inputs":[{"components":[{"internalType":"uint32","name":"dstChainId","type":"uint32"},{"internalType":"address","name":"sender","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"address","name":"originToken","type":"address"},{"internalType":"address","name":"destToken","type":"address"},{"internalType":"uint256","name":"originAmount","type":"uint256"},{"internalType":"uint256","name":"destAmount","type":"uint256"},{"internalType":"bool","name":"sendChainGas","type":"bool"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"internalType":"struct IFastBridge.BridgeParams","name":"params","type":"tuple"}],"name":"bridge","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"uint32","name":"dstChainId","type":"uint32"},{"internalType":"address","name":"sender","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"address","name":"originToken","type":"address"},{"internalType":"address","name":"destToken","type":"address"},{"internalType":"uint256","name":"originAmount","type":"uint256"},{"internalType":"uint256","name":"destAmount","type":"uint256"},{"internalType":"bool","name":"sendChainGas","type":"bool"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"internalType":"struct IFastBridge.BridgeParams","name":"params","type":"tuple"},{"components":[{"internalType":"address","name":"quoteRelayer","type":"address"},{"internalType":"int256","name":"quoteExclusivitySeconds","type":"int256"},{"internalType":"bytes","name":"quoteId","type":"bytes"},{"internalType":"uint256","name":"zapNative","type":"uint256"},{"internalType":"bytes","name":"zapData","type":"bytes"}],"internalType":"struct IFastBridgeV2.BridgeParamsV2","name":"paramsV2","type":"tuple"}],"name":"bridge","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"transactionId","type":"bytes32"}],"name":"bridgeProofs","outputs":[{"internalType":"uint96","name":"timestamp","type":"uint96"},{"internalType":"address","name":"relayer","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"transactionId","type":"bytes32"}],"name":"bridgeRelays","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"transactionId","type":"bytes32"}],"name":"bridgeStatuses","outputs":[{"internalType":"enum IFastBridgeV2.BridgeStatus","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"internalType":"address","name":"relayer","type":"address"}],"name":"canClaim","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"}],"name":"cancel","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"},{"internalType":"address","name":"to","type":"address"}],"name":"claim","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"}],"name":"claim","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"transactionId","type":"bytes32"}],"name":"dispute","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"}],"name":"getBridgeTransaction","outputs":[{"components":[{"internalType":"uint32","name":"originChainId","type":"uint32"},{"internalType":"uint32","name":"destChainId","type":"uint32"},{"internalType":"address","name":"originSender","type":"address"},{"internalType":"address","name":"destRecipient","type":"address"},{"internalType":"address","name":"originToken","type":"address"},{"internalType":"address","name":"destToken","type":"address"},{"internalType":"uint256","name":"originAmount","type":"uint256"},{"internalType":"uint256","name":"destAmount","type":"uint256"},{"internalType":"uint256","name":"originFeeAmount","type":"uint256"},{"internalType":"bool","name":"sendChainGas","type":"bool"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint256","name":"nonce","type":"uint256"}],"internalType":"struct IFastBridge.BridgeTransaction","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"}],"name":"getBridgeTransactionV2","outputs":[{"components":[{"internalType":"uint32","name":"originChainId","type":"uint32"},{"internalType":"uint32","name":"destChainId","type":"uint32"},{"internalType":"address","name":"originSender","type":"address"},{"internalType":"address","name":"destRecipient","type":"address"},{"internalType":"address","name":"originToken","type":"address"},{"internalType":"address","name":"destToken","type":"address"},{"internalType":"uint256","name":"originAmount","type":"uint256"},{"internalType":"uint256","name":"destAmount","type":"uint256"},{"internalType":"uint256","name":"originFeeAmount","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"address","name":"exclusivityRelayer","type":"address"},{"internalType":"uint256","name":"exclusivityEndTime","type":"uint256"},{"internalType":"uint256","name":"zapNative","type":"uint256"},{"internalType":"bytes","name":"zapData","type":"bytes"}],"internalType":"struct IFastBridgeV2.BridgeTransactionV2","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"internalType":"bytes32","name":"destTxHash","type":"bytes32"},{"internalType":"address","name":"relayer","type":"address"}],"name":"prove","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"},{"internalType":"bytes32","name":"destTxHash","type":"bytes32"}],"name":"prove","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"}],"name":"refund","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"}],"name":"relay","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"},{"internalType":"address","name":"relayer","type":"address"}],"name":"relay","outputs":[],"stateMutability":"payable","type":"function"}],"userDoc":{"kind":"user","methods":{"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256))":{"notice":"Initiates bridge on origin chain to be relayed by off-chain relayer"},"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256),(address,int256,bytes,uint256,bytes))":{"notice":"Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability to provide temporary exclusivity fill rights for the quote relayer."},"bridgeProofs(bytes32)":{"notice":"Returns the timestamp and relayer of a bridge proof"},"bridgeRelays(bytes32)":{"notice":"Checks if a transaction has been relayed"},"bridgeStatuses(bytes32)":{"notice":"Returns the status of a bridge transaction"},"canClaim(bytes32,address)":{"notice":"Checks if the dispute period has passed so bridge deposit can be claimed"},"cancel(bytes)":{"notice":"Cancels an outstanding bridge transaction in case optimistic bridging failed and returns the full amount to the original sender."},"claim(bytes)":{"notice":"Completes bridge transaction on origin chain by claiming originally deposited capital.Can only send funds to the relayer address on the proof."},"claim(bytes,address)":{"notice":"Completes bridge transaction on origin chain by claiming originally deposited capital"},"dispute(bytes32)":{"notice":"Disputes an outstanding proof in case relayer provided dest chain tx is invalid"},"getBridgeTransaction(bytes)":{"notice":"Decodes bridge request into a bridge transaction"},"getBridgeTransactionV2(bytes)":{"notice":"Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2"},"prove(bytes,bytes32)":{"notice":"Provides proof on origin side that relayer provided funds on destination side of bridge transaction"},"prove(bytes32,bytes32,address)":{"notice":"Provides proof on origin side that relayer provided funds on destination side of bridge transaction"},"refund(bytes)":{"notice":"Refunds an outstanding bridge transaction in case optimistic bridging failed"},"relay(bytes)":{"notice":"Relays destination side of bridge transaction by off-chain relayer"},"relay(bytes,address)":{"notice":"Relays destination side of bridge transaction by off-chain relayer"}},"version":1},"developerDoc":{"kind":"dev","methods":{"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256))":{"params":{"params":"The parameters required to bridge"}},"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256),(address,int256,bytes,uint256,bytes))":{"params":{"params":"The parameters required to bridge","paramsV2":"The parameters for exclusivity fill rights (optional, can be left empty)"}},"bridgeProofs(bytes32)":{"params":{"transactionId":"The ID of the bridge transaction"},"returns":{"relayer":"The relayer address of the bridge proof","timestamp":"The timestamp of the bridge proof"}},"bridgeRelays(bytes32)":{"params":{"transactionId":"The ID of the transaction to check"},"returns":{"_0":"True if the transaction has been relayed, false otherwise"}},"bridgeStatuses(bytes32)":{"params":{"transactionId":"The ID of the bridge transaction"},"returns":{"_0":"BridgeStatus Status of the bridge transaction"}},"canClaim(bytes32,address)":{"params":{"relayer":"The address of the relayer attempting to claim","transactionId":"The transaction id associated with the encoded bridge transaction to check"}},"cancel(bytes)":{"params":{"request":"The encoded bridge transaction to refund"}},"claim(bytes)":{"params":{"request":"The encoded bridge transaction to claim on origin chain"}},"claim(bytes,address)":{"params":{"request":"The encoded bridge transaction to claim on origin chain","to":"The recipient address of the funds"}},"dispute(bytes32)":{"params":{"transactionId":"The transaction id associated with the encoded bridge transaction to dispute"}},"getBridgeTransaction(bytes)":{"params":{"request":"The bridge request to decode"}},"getBridgeTransactionV2(bytes)":{"params":{"request":"The bridge request to decode"}},"prove(bytes,bytes32)":{"params":{"destTxHash":"The destination tx hash proving bridge transaction was relayed","request":"The encoded bridge transaction to prove on origin chain"}},"prove(bytes32,bytes32,address)":{"params":{"destTxHash":"The destination tx hash proving bridge transaction was relayed","relayer":"The address of the relaying entity which should have control of the origin funds when claimed","transactionId":"The transaction id associated with the encoded bridge transaction to prove"}},"refund(bytes)":{"params":{"request":"The encoded bridge transaction to refund"}},"relay(bytes)":{"params":{"request":"The encoded bridge transaction to relay on destination chain"}},"relay(bytes,address)":{"params":{"relayer":"The address of the relaying entity which should have control of the origin funds when claimed","request":"The encoded bridge transaction to relay on destination chain"}}},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"BridgeDepositClaimed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"BridgeDepositRefunded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"name\":\"BridgeProofDisputed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"transactionHash\",\"type\":\"bytes32\"}],\"name\":\"BridgeProofProvided\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"quoteId\",\"type\":\"bytes\"}],\"name\":\"BridgeQuoteDetails\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"originChainId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"chainGasAmount\",\"type\":\"uint256\"}],\"name\":\"BridgeRelayed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"destChainId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"sendChainGas\",\"type\":\"bool\"}],\"name\":\"BridgeRequested\",\"type\":\"event\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"dstChainId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"sendChainGas\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"}],\"internalType\":\"struct IFastBridge.BridgeParams\",\"name\":\"params\",\"type\":\"tuple\"}],\"name\":\"bridge\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"dstChainId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"sendChainGas\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"}],\"internalType\":\"struct IFastBridge.BridgeParams\",\"name\":\"params\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"quoteRelayer\",\"type\":\"address\"},{\"internalType\":\"int256\",\"name\":\"quoteExclusivitySeconds\",\"type\":\"int256\"},{\"internalType\":\"bytes\",\"name\":\"quoteId\",\"type\":\"bytes\"},{\"internalType\":\"uint256\",\"name\":\"zapNative\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"zapData\",\"type\":\"bytes\"}],\"internalType\":\"struct IFastBridgeV2.BridgeParamsV2\",\"name\":\"paramsV2\",\"type\":\"tuple\"}],\"name\":\"bridge\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"}],\"name\":\"bridgeProofs\",\"outputs\":[{\"internalType\":\"uint96\",\"name\":\"timestamp\",\"type\":\"uint96\"},{\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"}],\"name\":\"bridgeRelays\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"}],\"name\":\"bridgeStatuses\",\"outputs\":[{\"internalType\":\"enum IFastBridgeV2.BridgeStatus\",\"name\":\"\",\"type\":\"uint8\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"name\":\"canClaim\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"cancel\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"claim\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"claim\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"}],\"name\":\"dispute\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"getBridgeTransaction\",\"outputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"originChainId\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"destChainId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"originSender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destRecipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"originFeeAmount\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"sendChainGas\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"}],\"internalType\":\"struct IFastBridge.BridgeTransaction\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"getBridgeTransactionV2\",\"outputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"originChainId\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"destChainId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"originSender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destRecipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"originFeeAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"exclusivityRelayer\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"exclusivityEndTime\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"zapNative\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"zapData\",\"type\":\"bytes\"}],\"internalType\":\"struct IFastBridgeV2.BridgeTransactionV2\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"destTxHash\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"name\":\"prove\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"},{\"internalType\":\"bytes32\",\"name\":\"destTxHash\",\"type\":\"bytes32\"}],\"name\":\"prove\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"refund\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"relay\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"},{\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"name\":\"relay\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{\"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256))\":{\"params\":{\"params\":\"The parameters required to bridge\"}},\"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256),(address,int256,bytes,uint256,bytes))\":{\"params\":{\"params\":\"The parameters required to bridge\",\"paramsV2\":\"The parameters for exclusivity fill rights (optional, can be left empty)\"}},\"bridgeProofs(bytes32)\":{\"params\":{\"transactionId\":\"The ID of the bridge transaction\"},\"returns\":{\"relayer\":\"The relayer address of the bridge proof\",\"timestamp\":\"The timestamp of the bridge proof\"}},\"bridgeRelays(bytes32)\":{\"params\":{\"transactionId\":\"The ID of the transaction to check\"},\"returns\":{\"_0\":\"True if the transaction has been relayed, false otherwise\"}},\"bridgeStatuses(bytes32)\":{\"params\":{\"transactionId\":\"The ID of the bridge transaction\"},\"returns\":{\"_0\":\"BridgeStatus Status of the bridge transaction\"}},\"canClaim(bytes32,address)\":{\"params\":{\"relayer\":\"The address of the relayer attempting to claim\",\"transactionId\":\"The transaction id associated with the encoded bridge transaction to check\"}},\"cancel(bytes)\":{\"params\":{\"request\":\"The encoded bridge transaction to refund\"}},\"claim(bytes)\":{\"params\":{\"request\":\"The encoded bridge transaction to claim on origin chain\"}},\"claim(bytes,address)\":{\"params\":{\"request\":\"The encoded bridge transaction to claim on origin chain\",\"to\":\"The recipient address of the funds\"}},\"dispute(bytes32)\":{\"params\":{\"transactionId\":\"The transaction id associated with the encoded bridge transaction to dispute\"}},\"getBridgeTransaction(bytes)\":{\"params\":{\"request\":\"The bridge request to decode\"}},\"getBridgeTransactionV2(bytes)\":{\"params\":{\"request\":\"The bridge request to decode\"}},\"prove(bytes,bytes32)\":{\"params\":{\"destTxHash\":\"The destination tx hash proving bridge transaction was relayed\",\"request\":\"The encoded bridge transaction to prove on origin chain\"}},\"prove(bytes32,bytes32,address)\":{\"params\":{\"destTxHash\":\"The destination tx hash proving bridge transaction was relayed\",\"relayer\":\"The address of the relaying entity which should have control of the origin funds when claimed\",\"transactionId\":\"The transaction id associated with the encoded bridge transaction to prove\"}},\"refund(bytes)\":{\"params\":{\"request\":\"The encoded bridge transaction to refund\"}},\"relay(bytes)\":{\"params\":{\"request\":\"The encoded bridge transaction to relay on destination chain\"}},\"relay(bytes,address)\":{\"params\":{\"relayer\":\"The address of the relaying entity which should have control of the origin funds when claimed\",\"request\":\"The encoded bridge transaction to relay on destination chain\"}}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256))\":{\"notice\":\"Initiates bridge on origin chain to be relayed by off-chain relayer\"},\"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256),(address,int256,bytes,uint256,bytes))\":{\"notice\":\"Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability to provide temporary exclusivity fill rights for the quote relayer.\"},\"bridgeProofs(bytes32)\":{\"notice\":\"Returns the timestamp and relayer of a bridge proof\"},\"bridgeRelays(bytes32)\":{\"notice\":\"Checks if a transaction has been relayed\"},\"bridgeStatuses(bytes32)\":{\"notice\":\"Returns the status of a bridge transaction\"},\"canClaim(bytes32,address)\":{\"notice\":\"Checks if the dispute period has passed so bridge deposit can be claimed\"},\"cancel(bytes)\":{\"notice\":\"Cancels an outstanding bridge transaction in case optimistic bridging failed and returns the full amount to the original sender.\"},\"claim(bytes)\":{\"notice\":\"Completes bridge transaction on origin chain by claiming originally deposited capital.Can only send funds to the relayer address on the proof.\"},\"claim(bytes,address)\":{\"notice\":\"Completes bridge transaction on origin chain by claiming originally deposited capital\"},\"dispute(bytes32)\":{\"notice\":\"Disputes an outstanding proof in case relayer provided dest chain tx is invalid\"},\"getBridgeTransaction(bytes)\":{\"notice\":\"Decodes bridge request into a bridge transaction\"},\"getBridgeTransactionV2(bytes)\":{\"notice\":\"Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\"},\"prove(bytes,bytes32)\":{\"notice\":\"Provides proof on origin side that relayer provided funds on destination side of bridge transaction\"},\"prove(bytes32,bytes32,address)\":{\"notice\":\"Provides proof on origin side that relayer provided funds on destination side of bridge transaction\"},\"refund(bytes)\":{\"notice\":\"Refunds an outstanding bridge transaction in case optimistic bridging failed\"},\"relay(bytes)\":{\"notice\":\"Relays destination side of bridge transaction by off-chain relayer\"},\"relay(bytes,address)\":{\"notice\":\"Relays destination side of bridge transaction by off-chain relayer\"}},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeV2.sol\":\"IFastBridgeV2\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeV2.sol\":{\"keccak256\":\"0xac79c463688a682ca706a4ef95e7817b83548cdfa8182ba0426ac7e5e07613d8\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://b3ecb7097381287cafc3a73f3a2bb03565115ebb682a85064e0b0dc2f7e2919d\",\"dweb:/ipfs/QmatruW3nYZTksf3CeQ8wwiAG4c7xoEJBEp6drHPtFLBRK\"]}},\"version\":1}"},"hashes":{"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256))":"45851694","bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256),(address,int256,bytes,uint256,bytes))":"bfc7c607","bridgeProofs(bytes32)":"91ad5039","bridgeRelays(bytes32)":"8379a24f","bridgeStatuses(bytes32)":"051287bc","canClaim(bytes32,address)":"aa9641ab","cancel(bytes)":"3c5beeb4","claim(bytes)":"c63ff8dd","claim(bytes,address)":"41fcb612","dispute(bytes32)":"add98c70","getBridgeTransaction(bytes)":"ac11fb1a","getBridgeTransactionV2(bytes)":"5aa6ccba","prove(bytes,bytes32)":"886d36ff","prove(bytes32,bytes32,address)":"18e4357d","refund(bytes)":"5eb7d946","relay(bytes)":"8f0d6f17","relay(bytes,address)":"9c9545f0"}},"solidity/FastBridgeV2.sol:IFastBridgeV2Errors":{"code":"0x","runtime-code":"0x","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.24 ^0.8.20 ^0.8.4;\n\n// contracts/interfaces/IAdminV2.sol\n\ninterface IAdminV2 {\n event CancelDelayUpdated(uint256 oldCancelDelay, uint256 newCancelDelay);\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n function setCancelDelay(uint256 newCancelDelay) external;\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n}\n\n// contracts/interfaces/IAdminV2Errors.sol\n\ninterface IAdminV2Errors {\n error CancelDelayBelowMin();\n error FeeRateAboveMax();\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IFastBridgeV2Errors.sol\n\ninterface IFastBridgeV2Errors {\n error AmountIncorrect();\n error ChainIncorrect();\n error ExclusivityParamsIncorrect();\n error MsgValueIncorrect();\n error SenderIncorrect();\n error StatusIncorrect();\n error TokenNotContract();\n error ZapDataLengthAboveMax();\n error ZapNativeNotSupported();\n error ZeroAddress();\n\n error RecipientIncorrectReturnValue();\n error RecipientNoReturnValue();\n\n error DeadlineExceeded();\n error DeadlineNotExceeded();\n error DeadlineTooShort();\n error DisputePeriodNotPassed();\n error DisputePeriodPassed();\n error ExclusivityPeriodNotPassed();\n\n error TransactionRelayed();\n}\n\n// contracts/interfaces/IMulticallTarget.sol\n\n/// @notice Interface for a contract that can be called multiple times by the same caller. Inspired by MulticallV3:\n/// https://github.com/mds1/multicall/blob/master/src/Multicall3.sol\ninterface IMulticallTarget {\n struct Result {\n bool success;\n bytes returnData;\n }\n\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external;\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results);\n}\n\n// contracts/interfaces/IZapRecipient.sol\n\ninterface IZapRecipient {\n function zap(address token, uint256 amount, bytes memory zapData) external payable returns (bytes4);\n}\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// contracts/interfaces/IFastBridgeV2.sol\n\ninterface IFastBridgeV2 is IFastBridge {\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n struct BridgeTxDetails {\n BridgeStatus status;\n uint32 destChainId;\n uint56 proofBlockTimestamp;\n address proofRelayer;\n }\n\n struct BridgeRelay {\n uint48 blockNumber;\n uint48 blockTimestamp;\n address relayer;\n }\n\n /// @notice New params introduced in the FastBridgeV2.\n /// We are passing fields from the older BridgeParams struct outside of this struct\n /// for backwards compatibility.\n /// Note: quoteRelayer and quoteExclusivitySeconds are either both zero (indicating no exclusivity)\n /// or both non-zero (indicating exclusivity for the given period).\n /// Note: zapNative \u003e 0 can NOT be used with destToken = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE (native token)\n /// @param quoteRelayer Relayer that provided the quote for the transaction\n /// @param quoteExclusivitySeconds Period of time the quote relayer is guaranteed exclusivity after user's deposit\n /// @param quoteId Unique quote identifier used for tracking the quote\n /// @param zapNative ETH value to send to the recipient (if any)\n /// @param zapData Parameters for the Zap to the destination recipient (if any)\n struct BridgeParamsV2 {\n address quoteRelayer;\n int256 quoteExclusivitySeconds;\n bytes quoteId;\n uint256 zapNative;\n bytes zapData;\n }\n\n /// @notice Updated bridge transaction struct to include parameters introduced in FastBridgeV2.\n /// Note: only `exclusivityRelayer` can fill such a transaction until `exclusivityEndTime`.\n struct BridgeTransactionV2 {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n // Note: sendChainGas flag from V1 is deprecated\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n address exclusivityRelayer;\n uint256 exclusivityEndTime;\n uint256 zapNative; // ETH value to send to the recipient (if any)\n bytes zapData; // data to pass for the Zap action (if any)\n }\n\n event BridgeQuoteDetails(bytes32 indexed transactionId, bytes quoteId);\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability\n /// to provide temporary exclusivity fill rights for the quote relayer.\n /// @param params The parameters required to bridge\n /// @param paramsV2 The parameters for exclusivity fill rights (optional, can be left empty)\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function relay(bytes memory request, address relayer) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param transactionId The transaction id associated with the encoded bridge transaction to prove\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital.\n /// @notice Can only send funds to the relayer address on the proof.\n /// @param request The encoded bridge transaction to claim on origin chain\n function claim(bytes memory request) external;\n\n /// @notice Cancels an outstanding bridge transaction in case optimistic bridging failed and returns the full amount\n /// to the original sender.\n /// @param request The encoded bridge transaction to refund\n function cancel(bytes memory request) external;\n\n /// @notice Checks if a transaction has been relayed\n /// @param transactionId The ID of the transaction to check\n /// @return True if the transaction has been relayed, false otherwise\n function bridgeRelays(bytes32 transactionId) external view returns (bool);\n\n /// @notice Returns the status of a bridge transaction\n /// @param transactionId The ID of the bridge transaction\n /// @return BridgeStatus Status of the bridge transaction\n function bridgeStatuses(bytes32 transactionId) external view returns (BridgeStatus);\n\n /// @notice Returns the timestamp and relayer of a bridge proof\n /// @param transactionId The ID of the bridge transaction\n /// @return timestamp The timestamp of the bridge proof\n /// @return relayer The relayer address of the bridge proof\n function bridgeProofs(bytes32 transactionId) external view returns (uint96 timestamp, address relayer);\n\n /// @notice Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\n /// @param request The bridge request to decode\n function getBridgeTransactionV2(bytes memory request) external view returns (BridgeTransactionV2 memory);\n}\n\n// contracts/utils/MulticallTarget.sol\n\n// solhint-disable avoid-low-level-calls\n/// @notice Template for a contract that supports batched calls (preserving the msg.sender).\n/// Only calls with zero msg.value could be batched.\nabstract contract MulticallTarget is IMulticallTarget {\n error MulticallTarget__UndeterminedRevert();\n\n /// @notice Perform a batched call to this contract, preserving the msg.sender.\n /// The return data from each call is discarded.\n /// @dev The method is non-payable, so only calls with `msg.value == 0` could be batched.\n /// It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag.\n /// Otherwise, the whole batch call will be reverted with the original revert reason.\n /// @param data List of abi-encoded calldata for the calls to perform.\n /// @param ignoreReverts Whether to ignore the revert errors from the calls.\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external {\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\n if (!success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(result);\n }\n }\n }\n\n /// @notice Perform a batched call to this contract, preserving the msg.sender.\n /// The return data from each call is preserved.\n /// @dev The method is non-payable, so only calls with `msg.value == 0` could be batched.\n /// It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag.\n /// Otherwise, the whole batch call will be reverted with the original revert reason.\n /// @param data List of abi-encoded calldata for the calls to perform.\n /// @param ignoreReverts Whether to ignore the revert errors from the calls.\n /// @return results List of results from the calls: `(success, returnData)`.\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results)\n {\n results = new Result[](data.length);\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (results[i].success, results[i].returnData) = address(this).delegatecall(data[i]);\n if (!results[i].success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(results[i].returnData);\n }\n }\n }\n\n /// @dev Bubbles the revert message from the underlying call.\n /// Note: preserves the same custom error or revert string, if one was used.\n /// Source: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v5.0.2/contracts/utils/Address.sol#L143-L158\n function _bubbleRevert(bytes memory returnData) internal pure {\n // Look for revert reason and bubble it up if present\n if (returnData.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n // solhint-disable-next-line no-inline-assembly\n assembly {\n let returndata_size := mload(returnData)\n revert(add(32, returnData), returndata_size)\n }\n } else {\n revert MulticallTarget__UndeterminedRevert();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// contracts/libs/BridgeTransactionV2.sol\n\n// solhint-disable no-inline-assembly\nlibrary BridgeTransactionV2Lib {\n uint16 internal constant VERSION = 2;\n\n // Offsets of the fields in the packed BridgeTransactionV2 struct\n // uint16 version [000 .. 002)\n // uint32 originChainId [002 .. 006)\n // uint32 destChainId [006 .. 010)\n // address originSender [010 .. 030)\n // address destRecipient [030 .. 050)\n // address originToken [050 .. 070)\n // address destToken [070 .. 090)\n // uint256 originAmount [090 .. 122)\n // uint256 destAmount [122 .. 154)\n // uint256 originFeeAmount [154 .. 186)\n // uint256 deadline [186 .. 218)\n // uint256 nonce [218 .. 250)\n // address exclusivityRelayer [250 .. 270)\n // uint256 exclusivityEndTime [270 .. 302)\n // uint256 zapNative [302 .. 334)\n // bytes zapData [334 .. ***)\n\n // forgefmt: disable-start\n uint256 private constant OFFSET_ORIGIN_CHAIN_ID = 2;\n uint256 private constant OFFSET_DEST_CHAIN_ID = 6;\n uint256 private constant OFFSET_ORIGIN_SENDER = 10;\n uint256 private constant OFFSET_DEST_RECIPIENT = 30;\n uint256 private constant OFFSET_ORIGIN_TOKEN = 50;\n uint256 private constant OFFSET_DEST_TOKEN = 70;\n uint256 private constant OFFSET_ORIGIN_AMOUNT = 90;\n uint256 private constant OFFSET_DEST_AMOUNT = 122;\n uint256 private constant OFFSET_ORIGIN_FEE_AMOUNT = 154;\n uint256 private constant OFFSET_DEADLINE = 186;\n uint256 private constant OFFSET_NONCE = 218;\n uint256 private constant OFFSET_EXCLUSIVITY_RELAYER = 250;\n uint256 private constant OFFSET_EXCLUSIVITY_END_TIME = 270;\n uint256 private constant OFFSET_ZAP_NATIVE = 302;\n uint256 private constant OFFSET_ZAP_DATA = 334;\n // forgefmt: disable-end\n\n error BridgeTransactionV2__InvalidEncodedTx();\n error BridgeTransactionV2__UnsupportedVersion(uint16 version);\n\n /// @notice Validates the encoded transaction to be a tightly packed encoded payload for BridgeTransactionV2.\n /// @dev Checks the minimum length and the version, use this function before decoding any of the fields.\n function validateV2(bytes calldata encodedTx) internal pure {\n // Check the minimum length: must at least include all static fields.\n if (encodedTx.length \u003c OFFSET_ZAP_DATA) revert BridgeTransactionV2__InvalidEncodedTx();\n // Once we validated the length, we can be sure that the version field is present.\n uint16 version_ = version(encodedTx);\n if (version_ != VERSION) revert BridgeTransactionV2__UnsupportedVersion(version_);\n }\n\n /// @notice Encodes the BridgeTransactionV2 struct by tightly packing the fields.\n /// @dev `abi.decode` will not work as a result of the tightly packed fields. Use `decodeV2` to decode instead.\n function encodeV2(IFastBridgeV2.BridgeTransactionV2 memory bridgeTx) internal pure returns (bytes memory) {\n // We split the encoding into two parts to avoid stack-too-deep error\n bytes memory firstPart = abi.encodePacked(\n VERSION,\n bridgeTx.originChainId,\n bridgeTx.destChainId,\n bridgeTx.originSender,\n bridgeTx.destRecipient,\n bridgeTx.originToken,\n bridgeTx.destToken,\n bridgeTx.originAmount\n );\n return abi.encodePacked(\n firstPart,\n bridgeTx.destAmount,\n bridgeTx.originFeeAmount,\n // Note: we skip the deprecated `sendChainGas` flag, which was present in BridgeTransaction V1\n bridgeTx.deadline,\n bridgeTx.nonce,\n // New V2 fields: exclusivity\n bridgeTx.exclusivityRelayer,\n bridgeTx.exclusivityEndTime,\n // New V2 fields: Zap\n bridgeTx.zapNative,\n bridgeTx.zapData\n );\n }\n\n /// @notice Decodes the BridgeTransactionV2 struct from the encoded transaction.\n /// @dev Encoded BridgeTransactionV2 struct must be tightly packed.\n /// Use `validateV2` before decoding to ensure the encoded transaction is valid.\n function decodeV2(bytes calldata encodedTx)\n internal\n pure\n returns (IFastBridgeV2.BridgeTransactionV2 memory bridgeTx)\n {\n bridgeTx.originChainId = originChainId(encodedTx);\n bridgeTx.destChainId = destChainId(encodedTx);\n bridgeTx.originSender = originSender(encodedTx);\n bridgeTx.destRecipient = destRecipient(encodedTx);\n bridgeTx.originToken = originToken(encodedTx);\n bridgeTx.destToken = destToken(encodedTx);\n bridgeTx.originAmount = originAmount(encodedTx);\n bridgeTx.destAmount = destAmount(encodedTx);\n bridgeTx.originFeeAmount = originFeeAmount(encodedTx);\n bridgeTx.deadline = deadline(encodedTx);\n bridgeTx.nonce = nonce(encodedTx);\n bridgeTx.exclusivityRelayer = exclusivityRelayer(encodedTx);\n bridgeTx.exclusivityEndTime = exclusivityEndTime(encodedTx);\n bridgeTx.zapNative = zapNative(encodedTx);\n bridgeTx.zapData = zapData(encodedTx);\n }\n\n /// @notice Extracts the version from the encoded transaction.\n function version(bytes calldata encodedTx) internal pure returns (uint16 version_) {\n // Load 32 bytes from the start and shift it 240 bits to the right to get the highest 16 bits.\n assembly {\n version_ := shr(240, calldataload(encodedTx.offset))\n }\n }\n\n /// @notice Extracts the origin chain ID from the encoded transaction.\n function originChainId(bytes calldata encodedTx) internal pure returns (uint32 originChainId_) {\n // Load 32 bytes from the offset and shift it 224 bits to the right to get the highest 32 bits.\n assembly {\n originChainId_ := shr(224, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_CHAIN_ID)))\n }\n }\n\n /// @notice Extracts the destination chain ID from the encoded transaction.\n function destChainId(bytes calldata encodedTx) internal pure returns (uint32 destChainId_) {\n // Load 32 bytes from the offset and shift it 224 bits to the right to get the highest 32 bits.\n assembly {\n destChainId_ := shr(224, calldataload(add(encodedTx.offset, OFFSET_DEST_CHAIN_ID)))\n }\n }\n\n /// @notice Extracts the origin sender from the encoded transaction.\n function originSender(bytes calldata encodedTx) internal pure returns (address originSender_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n originSender_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_SENDER)))\n }\n }\n\n /// @notice Extracts the destination recipient from the encoded transaction.\n function destRecipient(bytes calldata encodedTx) internal pure returns (address destRecipient_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n destRecipient_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_DEST_RECIPIENT)))\n }\n }\n\n /// @notice Extracts the origin token from the encoded transaction.\n function originToken(bytes calldata encodedTx) internal pure returns (address originToken_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n originToken_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_TOKEN)))\n }\n }\n\n /// @notice Extracts the destination token from the encoded transaction.\n function destToken(bytes calldata encodedTx) internal pure returns (address destToken_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n destToken_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_DEST_TOKEN)))\n }\n }\n\n /// @notice Extracts the origin amount from the encoded transaction.\n function originAmount(bytes calldata encodedTx) internal pure returns (uint256 originAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n originAmount_ := calldataload(add(encodedTx.offset, OFFSET_ORIGIN_AMOUNT))\n }\n }\n\n /// @notice Extracts the destination amount from the encoded transaction.\n function destAmount(bytes calldata encodedTx) internal pure returns (uint256 destAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n destAmount_ := calldataload(add(encodedTx.offset, OFFSET_DEST_AMOUNT))\n }\n }\n\n /// @notice Extracts the origin fee amount from the encoded transaction.\n function originFeeAmount(bytes calldata encodedTx) internal pure returns (uint256 originFeeAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n originFeeAmount_ := calldataload(add(encodedTx.offset, OFFSET_ORIGIN_FEE_AMOUNT))\n }\n }\n\n /// @notice Extracts the deadline from the encoded transaction.\n function deadline(bytes calldata encodedTx) internal pure returns (uint256 deadline_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n deadline_ := calldataload(add(encodedTx.offset, OFFSET_DEADLINE))\n }\n }\n\n /// @notice Extracts the nonce from the encoded transaction.\n function nonce(bytes calldata encodedTx) internal pure returns (uint256 nonce_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n nonce_ := calldataload(add(encodedTx.offset, OFFSET_NONCE))\n }\n }\n\n /// @notice Extracts the exclusivity relayer from the encoded transaction.\n function exclusivityRelayer(bytes calldata encodedTx) internal pure returns (address exclusivityRelayer_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n exclusivityRelayer_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_EXCLUSIVITY_RELAYER)))\n }\n }\n\n /// @notice Extracts the exclusivity end time from the encoded transaction.\n function exclusivityEndTime(bytes calldata encodedTx) internal pure returns (uint256 exclusivityEndTime_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n exclusivityEndTime_ := calldataload(add(encodedTx.offset, OFFSET_EXCLUSIVITY_END_TIME))\n }\n }\n\n /// @notice Extracts the Zap's native value from the encoded transaction.\n function zapNative(bytes calldata encodedTx) internal pure returns (uint256 zapNative_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n zapNative_ := calldataload(add(encodedTx.offset, OFFSET_ZAP_NATIVE))\n }\n }\n\n /// @notice Extracts the Zap's data from the encoded transaction.\n function zapData(bytes calldata encodedTx) internal pure returns (bytes calldata zapData_) {\n zapData_ = encodedTx[OFFSET_ZAP_DATA:];\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/AdminV2.sol\n\ncontract AdminV2 is AccessControlEnumerable, IAdminV2, IAdminV2Errors {\n using SafeERC20 for IERC20;\n\n /// @notice Address reserved for native gas token (ETH on Ethereum and most L2s, AVAX on Avalanche, etc)\n address public constant NATIVE_GAS_TOKEN = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Role identifier for Quoter API's off-chain authentication.\n /// @dev Only addresses with this role can post FastBridge quotes to the API.\n bytes32 public constant QUOTER_ROLE = keccak256(\"QUOTER_ROLE\");\n\n /// @notice Role identifier for Prover's on-chain authentication in FastBridge.\n /// @dev Only addresses with this role can provide proofs that a FastBridge request has been relayed.\n bytes32 public constant PROVER_ROLE = keccak256(\"PROVER_ROLE\");\n\n /// @notice Role identifier for Guard's on-chain authentication in FastBridge.\n /// @dev Only addresses with this role can dispute submitted relay proofs during the dispute period.\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n\n /// @notice Role identifier for Canceler's on-chain authentication in FastBridge.\n /// @dev Only addresses with this role can cancel a FastBridge transaction without the cancel delay.\n bytes32 public constant CANCELER_ROLE = keccak256(\"CANCELER_ROLE\");\n\n /// @notice Role identifier for Governor's on-chain administrative authority.\n /// @dev Only addresses with this role can perform administrative tasks within the contract.\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n /// @notice Denominator for fee rates, represents 100%.\n uint256 public constant FEE_BPS = 1e6;\n /// @notice Maximum protocol fee rate: 1% on origin amount.\n uint256 public constant FEE_RATE_MAX = 0.01e6;\n\n /// @notice Minimum cancel delay that can be set by the governor.\n uint256 public constant MIN_CANCEL_DELAY = 1 hours;\n /// @notice Default cancel delay set during the contract deployment.\n uint256 public constant DEFAULT_CANCEL_DELAY = 1 days;\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Delay for a transaction after which it could be permisionlessly cancelled\n uint256 public cancelDelay;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Use ZapNative V2 requests instead.\n uint256 public immutable chainGasAmount = 0;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n _setCancelDelay(DEFAULT_CANCEL_DELAY);\n }\n\n /// @notice Allows the contract governor to set the cancel delay. The cancel delay is the time after the transaction\n /// deadline after which it can be permissionlessly cancelled, if it hasn't been proven by any of the Relayers.\n function setCancelDelay(uint256 newCancelDelay) external onlyRole(GOVERNOR_ROLE) {\n _setCancelDelay(newCancelDelay);\n }\n\n /// @notice Allows the contract governor to set the protocol fee rate. The protocol fee is taken from the origin\n /// amount only for completed and claimed transactions.\n /// @dev The protocol fee is abstracted away from the relayers, they always operate using the amounts after fees:\n /// what they see as the origin amount emitted in the log is what they get credited with.\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n if (newFeeRate \u003e FEE_RATE_MAX) revert FeeRateAboveMax();\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n /// @notice Allows the contract governor to sweep the accumulated protocol fees in the contract.\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n emit FeesSwept(token, recipient, feeAmount);\n /// Sweep the fees as the last transaction action\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(recipient), feeAmount);\n } else {\n IERC20(token).safeTransfer(recipient, feeAmount);\n }\n }\n\n /// @notice Internal function to set the cancel delay. Security checks are performed outside of this function.\n function _setCancelDelay(uint256 newCancelDelay) private {\n if (newCancelDelay \u003c MIN_CANCEL_DELAY) revert CancelDelayBelowMin();\n uint256 oldCancelDelay = cancelDelay;\n cancelDelay = newCancelDelay;\n emit CancelDelayUpdated(oldCancelDelay, newCancelDelay);\n }\n}\n\n// contracts/FastBridgeV2.sol\n\n/// @notice FastBridgeV2 is a contract for bridging tokens across chains.\ncontract FastBridgeV2 is AdminV2, MulticallTarget, IFastBridgeV2, IFastBridgeV2Errors {\n using BridgeTransactionV2Lib for bytes;\n using SafeERC20 for IERC20;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n /// @notice Maximum length of accepted zapData\n uint256 public constant MAX_ZAP_DATA_LENGTH = 2 ** 16 - 1;\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeTxDetails) public bridgeTxDetails;\n /// @notice Relay details on destination chain\n mapping(bytes32 =\u003e BridgeRelay) public bridgeRelayDetails;\n /// @notice Unique bridge nonces tracked per originSender\n mapping(address =\u003e uint256) public senderNonces;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Replaced by senderNonces\n uint256 public immutable nonce = 0;\n /// @notice the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) AdminV2(_owner) {\n deployBlock = block.number;\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n bridge({\n params: params,\n paramsV2: BridgeParamsV2({\n quoteRelayer: address(0),\n quoteExclusivitySeconds: 0,\n quoteId: bytes(\"\"),\n zapNative: 0,\n zapData: bytes(\"\")\n })\n });\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes calldata request) external payable {\n // relay override will validate the request\n relay({request: request, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes calldata request, bytes32 destTxHash) external {\n request.validateV2();\n prove({transactionId: keccak256(request), destTxHash: destTxHash, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridgeV2\n function claim(bytes calldata request) external {\n // claim override will validate the request\n claim({request: request, to: address(0)});\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Aggregate the read operations from the same storage slot\n address disputedRelayer = $.proofRelayer;\n BridgeStatus status = $.status;\n uint56 proofBlockTimestamp = $.proofBlockTimestamp;\n // Can only dispute a RELAYER_PROVED transaction within the dispute period\n if (status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(proofBlockTimestamp) \u003e DISPUTE_PERIOD) {\n revert DisputePeriodPassed();\n }\n // Update status to REQUESTED and delete the disputed proof details\n // Note: these are storage writes\n $.status = BridgeStatus.REQUESTED;\n $.proofRelayer = address(0);\n $.proofBlockTimestamp = 0;\n\n emit BridgeProofDisputed(transactionId, disputedRelayer);\n }\n\n /// Note: this function is deprecated and will be removed in a future version.\n /// @inheritdoc IFastBridge\n function refund(bytes calldata request) external {\n cancel(request);\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // The correct relayer can only claim a RELAYER_PROVED transaction after the dispute period\n if ($.status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if ($.proofRelayer != relayer) revert SenderIncorrect();\n return _timeSince($.proofBlockTimestamp) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n /// @dev This method is added to achieve backwards compatibility with decoding requests into V1 structs:\n /// - `zapNative` is partially reported as a zero/non-zero flag\n /// - `zapData` is ignored\n /// In order to process all kinds of requests use getBridgeTransactionV2 instead.\n function getBridgeTransaction(bytes calldata request) external view returns (BridgeTransaction memory) {\n // Try decoding into V2 struct first. This will revert if V1 struct is passed\n try this.getBridgeTransactionV2(request) returns (BridgeTransactionV2 memory txV2) {\n // Note: we entirely ignore the zapData field, as it was not present in V1\n return BridgeTransaction({\n originChainId: txV2.originChainId,\n destChainId: txV2.destChainId,\n originSender: txV2.originSender,\n destRecipient: txV2.destRecipient,\n originToken: txV2.originToken,\n destToken: txV2.destToken,\n originAmount: txV2.originAmount,\n destAmount: txV2.destAmount,\n originFeeAmount: txV2.originFeeAmount,\n sendChainGas: txV2.zapNative != 0,\n deadline: txV2.deadline,\n nonce: txV2.nonce\n });\n } catch {\n // Fallback to V1 struct\n return abi.decode(request, (BridgeTransaction));\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function getBridgeTransactionV2(bytes calldata request) external pure returns (BridgeTransactionV2 memory) {\n request.validateV2();\n return BridgeTransactionV2Lib.decodeV2(request);\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) public payable {\n int256 exclusivityEndTime = 0;\n // if relayer exclusivity is not intended for this bridge, set exclusivityEndTime to static zero\n // otherwise, set exclusivity to expire at the current block ts offset by quoteExclusivitySeconds\n if (paramsV2.quoteRelayer != address(0)) {\n exclusivityEndTime = int256(block.timestamp) + paramsV2.quoteExclusivitySeconds;\n }\n _validateBridgeParams(params, paramsV2, exclusivityEndTime);\n\n // transfer tokens to bridge contract\n /// @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _takeBridgedUserAsset(params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) {\n originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n }\n\n // set status to requested\n bytes memory request = BridgeTransactionV2Lib.encodeV2(\n BridgeTransactionV2({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n deadline: params.deadline,\n nonce: senderNonces[params.sender]++, // increment nonce on every bridge\n exclusivityRelayer: paramsV2.quoteRelayer,\n // We checked exclusivityEndTime to be in range [0 .. params.deadline] above, so can safely cast\n exclusivityEndTime: uint256(exclusivityEndTime),\n zapNative: paramsV2.zapNative,\n zapData: paramsV2.zapData\n })\n );\n bytes32 transactionId = keccak256(request);\n // Note: the tx status will be updated throughout the tx lifecycle, while destChainId is set once here\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n bridgeTxDetails[transactionId].destChainId = params.dstChainId;\n\n emit BridgeRequested({\n transactionId: transactionId,\n sender: params.sender,\n request: request,\n destChainId: params.dstChainId,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n sendChainGas: paramsV2.zapNative != 0\n });\n emit BridgeQuoteDetails(transactionId, paramsV2.quoteId);\n }\n\n /// @inheritdoc IFastBridgeV2\n function relay(bytes calldata request, address relayer) public payable {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n _validateRelayParams(request, transactionId, relayer);\n // mark bridge transaction as relayed\n bridgeRelayDetails[transactionId] =\n BridgeRelay({blockNumber: uint48(block.number), blockTimestamp: uint48(block.timestamp), relayer: relayer});\n\n // transfer tokens to recipient on destination chain and trigger Zap if requested\n address to = request.destRecipient();\n address token = request.destToken();\n uint256 amount = request.destAmount();\n uint256 zapNative = request.zapNative();\n\n // Emit the event before any external calls\n emit BridgeRelayed({\n transactionId: transactionId,\n relayer: relayer,\n to: to,\n originChainId: request.originChainId(),\n originToken: request.originToken(),\n destToken: token,\n originAmount: request.originAmount(),\n destAmount: amount,\n chainGasAmount: zapNative\n });\n\n // All state changes have been done at this point, can proceed to the external calls.\n // This follows the checks-effects-interactions pattern to mitigate potential reentrancy attacks.\n if (token == NATIVE_GAS_TOKEN) {\n // For the native gas token, additional zapNative is not allowed\n if (zapNative != 0) revert ZapNativeNotSupported();\n // Check that the correct msg.value was sent\n if (msg.value != amount) revert MsgValueIncorrect();\n // Don't do a native transfer yet: we will handle it alongside the Zap below\n } else {\n // For ERC20s, we check that the correct msg.value was sent\n if (msg.value != zapNative) revert MsgValueIncorrect();\n // We need to transfer the tokens from the Relayer to the recipient first before performing an\n // optional post-transfer Zap.\n IERC20(token).safeTransferFrom(msg.sender, to, amount);\n }\n // At this point we have done:\n // - Transferred the requested amount of ERC20 tokens to the recipient.\n // At this point we have confirmed:\n // - For ERC20s: msg.value matches the requested zapNative amount.\n // - For the native gas token: msg.value matches the requested destAmount.\n // Remaining optional things to do:\n // - Forward the full msg.value to the recipient (if non-zero).\n // - Trigger a Zap (if zapData is present).\n bytes calldata zapData = request.zapData();\n if (zapData.length != 0) {\n // Zap Data is present: Zap has been requested by the recipient. Trigger it forwarding the full msg.value.\n\n // Note: if token has a fee on transfers, the recipient will have received less than `amount`.\n // This is a very niche edge case and should be handled by the recipient contract.\n _triggerZapWithChecks({recipient: to, token: token, amount: amount, zapData: zapData});\n } else if (msg.value != 0) {\n // Zap Data is missing, but msg.value was sent. This could happen in two different cases:\n // - Relay with the native gas token is happening.\n // - Relay with ERC20 is happening, with a `zapNative \u003e 0` request.\n // In both cases, we need to transfer the full msg.value to the recipient.\n Address.sendValue(payable(to), msg.value);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) public onlyRole(PROVER_ROLE) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n\n // Can only prove a REQUESTED transaction\n if ($.status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n // Update status to RELAYER_PROVED and store the proof details\n // Note: these are storage writes\n $.status = BridgeStatus.RELAYER_PROVED;\n $.proofBlockTimestamp = uint56(block.timestamp);\n $.proofRelayer = relayer;\n\n emit BridgeProofProvided(transactionId, relayer, destTxHash);\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes calldata request, address to) public {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Aggregate the read operations from the same storage slot\n address proofRelayer = $.proofRelayer;\n BridgeStatus status = $.status;\n uint56 proofBlockTimestamp = $.proofBlockTimestamp;\n\n // Can only claim a RELAYER_PROVED transaction after the dispute period\n if (status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(proofBlockTimestamp) \u003c= DISPUTE_PERIOD) {\n revert DisputePeriodNotPassed();\n }\n\n if (to == address(0)) {\n // Anyone could claim the funds to the proven relayer on their behalf\n to = proofRelayer;\n } else if (proofRelayer != msg.sender) {\n // Only the proven relayer could specify an address to claim the funds to\n revert SenderIncorrect();\n }\n\n // Update status to RELAYER_CLAIMED and transfer the origin collateral to the specified claim address\n // Note: this is a storage write\n $.status = BridgeStatus.RELAYER_CLAIMED;\n\n address token = request.originToken();\n uint256 amount = request.originAmount();\n // Update protocol fees if origin fee amount exists\n uint256 originFeeAmount = request.originFeeAmount();\n if (originFeeAmount \u003e 0) protocolFees[token] += originFeeAmount;\n // Emit the event before any external calls\n emit BridgeDepositClaimed(transactionId, proofRelayer, to, token, amount);\n // Complete the relayer claim as the last transaction action\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(to), amount);\n } else {\n IERC20(token).safeTransfer(to, amount);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function cancel(bytes calldata request) public {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Can only cancel a REQUESTED transaction after its deadline expires\n if ($.status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n uint256 deadline = request.deadline();\n // Permissionless cancel is only allowed after `cancelDelay` on top of the deadline\n if (!hasRole(CANCELER_ROLE, msg.sender)) deadline += cancelDelay;\n if (block.timestamp \u003c= deadline) revert DeadlineNotExceeded();\n // Update status to REFUNDED and return the full amount (collateral + protocol fees) to the original sender.\n // The protocol fees are only updated when the transaction is claimed, so we don't need to update them here.\n // Note: this is a storage write\n $.status = BridgeStatus.REFUNDED;\n\n address to = request.originSender();\n address token = request.originToken();\n uint256 amount = request.originAmount() + request.originFeeAmount();\n // Emit the event before any external calls\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n // Complete the user cancel as the last transaction action\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(to), amount);\n } else {\n IERC20(token).safeTransfer(to, amount);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeStatuses(bytes32 transactionId) public view returns (BridgeStatus status) {\n return bridgeTxDetails[transactionId].status;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeProofs(bytes32 transactionId) public view returns (uint96 timestamp, address relayer) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n\n timestamp = $.proofBlockTimestamp;\n relayer = $.proofRelayer;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeRelays(bytes32 transactionId) public view returns (bool) {\n // has this transactionId been relayed?\n return bridgeRelayDetails[transactionId].relayer != address(0);\n }\n\n /// @notice Takes the bridged asset from the user into FastBridgeV2 custody. It will be later\n /// claimed by the relayer who completed the relay on destination chain, or transferred back to the user\n /// via the cancel function should no one complete the relay.\n function _takeBridgedUserAsset(address token, uint256 amount) internal returns (uint256 amountTaken) {\n if (token == NATIVE_GAS_TOKEN) {\n // For the native gas token, we just need to check that the supplied msg.value is correct.\n // Supplied `msg.value` is already in FastBridgeV2 custody.\n if (amount != msg.value) revert MsgValueIncorrect();\n amountTaken = msg.value;\n } else {\n // For ERC20s, token is explicitly transferred from the user to FastBridgeV2.\n // We don't allow non-zero `msg.value` to avoid extra funds from being stuck in FastBridgeV2.\n if (msg.value != 0) revert MsgValueIncorrect();\n // Throw an explicit error if the provided token address is not a contract\n if (token.code.length == 0) revert TokenNotContract();\n amountTaken = IERC20(token).balanceOf(address(this));\n IERC20(token).safeTransferFrom(msg.sender, address(this), amount);\n // Use the balance difference as the amount taken in case of fee on transfer tokens.\n amountTaken = IERC20(token).balanceOf(address(this)) - amountTaken;\n }\n }\n\n /// @notice Calls the Recipient's hook function with the specified zapData and performs\n /// all the necessary checks for the returned value.\n function _triggerZapWithChecks(address recipient, address token, uint256 amount, bytes calldata zapData) internal {\n // This will bubble any revert messages from the hook function\n bytes memory returnData = Address.functionCallWithValue({\n target: recipient,\n data: abi.encodeCall(IZapRecipient.zap, (token, amount, zapData)),\n // Note: see `relay()` for reasoning behind passing msg.value\n value: msg.value\n });\n // Explicit revert if no return data at all\n if (returnData.length == 0) revert RecipientNoReturnValue();\n // Check that exactly a single return value was returned\n if (returnData.length != 32) revert RecipientIncorrectReturnValue();\n // Return value should be abi-encoded hook function selector\n if (bytes32(returnData) != bytes32(IZapRecipient.zap.selector)) {\n revert RecipientIncorrectReturnValue();\n }\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint56(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint56).max but\n /// proof.timestamp \u003c type(uint56).max via unchecked statement\n /// @param proofBlockTimestamp The bridge proof block timestamp\n /// @return delta Time delta since proof submitted\n function _timeSince(uint56 proofBlockTimestamp) internal view returns (uint256 delta) {\n unchecked {\n delta = uint56(block.timestamp) - proofBlockTimestamp;\n }\n }\n\n /// @notice Performs all the necessary checks for a bridge to happen.\n /// @dev There's no good way to refactor this function to reduce cyclomatic complexity due to\n /// the number of checks that need to be performed, so we skip the code-complexity rule here.\n // solhint-disable-next-line code-complexity\n function _validateBridgeParams(\n BridgeParams memory params,\n BridgeParamsV2 memory paramsV2,\n int256 exclusivityEndTime\n )\n internal\n view\n {\n // Check V1 (legacy) params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.sender == address(0) || params.to == address(0)) revert ZeroAddress();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n // Check V2 params\n if (paramsV2.zapData.length \u003e MAX_ZAP_DATA_LENGTH) revert ZapDataLengthAboveMax();\n if (paramsV2.zapNative != 0 \u0026\u0026 params.destToken == NATIVE_GAS_TOKEN) {\n revert ZapNativeNotSupported();\n }\n // exclusivityEndTime must be in range [0 .. params.deadline]\n if (exclusivityEndTime \u003c 0 || exclusivityEndTime \u003e int256(params.deadline)) {\n revert ExclusivityParamsIncorrect();\n }\n }\n\n /// @notice Performs all the necessary checks for a relay to happen.\n function _validateRelayParams(bytes calldata request, bytes32 transactionId, address relayer) internal view {\n if (relayer == address(0)) revert ZeroAddress();\n // Check if the transaction has already been relayed\n if (bridgeRelays(transactionId)) revert TransactionRelayed();\n if (request.destChainId() != block.chainid) revert ChainIncorrect();\n // Check the deadline for relay to happen\n if (block.timestamp \u003e request.deadline()) revert DeadlineExceeded();\n // Check the exclusivity period, if it is still ongoing\n address exclRelayer = request.exclusivityRelayer();\n if (exclRelayer != address(0) \u0026\u0026 exclRelayer != relayer \u0026\u0026 block.timestamp \u003c= request.exclusivityEndTime()) {\n revert ExclusivityPeriodNotPassed();\n }\n }\n}\n","language":"Solidity","languageVersion":"0.8.24","compilerVersion":"0.8.24","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"","srcMapRuntime":"","abiDefinition":[{"inputs":[],"name":"AmountIncorrect","type":"error"},{"inputs":[],"name":"ChainIncorrect","type":"error"},{"inputs":[],"name":"DeadlineExceeded","type":"error"},{"inputs":[],"name":"DeadlineNotExceeded","type":"error"},{"inputs":[],"name":"DeadlineTooShort","type":"error"},{"inputs":[],"name":"DisputePeriodNotPassed","type":"error"},{"inputs":[],"name":"DisputePeriodPassed","type":"error"},{"inputs":[],"name":"ExclusivityParamsIncorrect","type":"error"},{"inputs":[],"name":"ExclusivityPeriodNotPassed","type":"error"},{"inputs":[],"name":"MsgValueIncorrect","type":"error"},{"inputs":[],"name":"RecipientIncorrectReturnValue","type":"error"},{"inputs":[],"name":"RecipientNoReturnValue","type":"error"},{"inputs":[],"name":"SenderIncorrect","type":"error"},{"inputs":[],"name":"StatusIncorrect","type":"error"},{"inputs":[],"name":"TokenNotContract","type":"error"},{"inputs":[],"name":"TransactionRelayed","type":"error"},{"inputs":[],"name":"ZapDataLengthAboveMax","type":"error"},{"inputs":[],"name":"ZapNativeNotSupported","type":"error"},{"inputs":[],"name":"ZeroAddress","type":"error"}],"userDoc":{"kind":"user","methods":{},"version":1},"developerDoc":{"kind":"dev","methods":{},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[],\"name\":\"AmountIncorrect\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ChainIncorrect\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DeadlineExceeded\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DeadlineNotExceeded\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DeadlineTooShort\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DisputePeriodNotPassed\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DisputePeriodPassed\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ExclusivityParamsIncorrect\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ExclusivityPeriodNotPassed\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"MsgValueIncorrect\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"RecipientIncorrectReturnValue\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"RecipientNoReturnValue\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"SenderIncorrect\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"StatusIncorrect\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"TokenNotContract\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"TransactionRelayed\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ZapDataLengthAboveMax\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ZapNativeNotSupported\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ZeroAddress\",\"type\":\"error\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeV2.sol\":\"IFastBridgeV2Errors\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeV2.sol\":{\"keccak256\":\"0xac79c463688a682ca706a4ef95e7817b83548cdfa8182ba0426ac7e5e07613d8\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://b3ecb7097381287cafc3a73f3a2bb03565115ebb682a85064e0b0dc2f7e2919d\",\"dweb:/ipfs/QmatruW3nYZTksf3CeQ8wwiAG4c7xoEJBEp6drHPtFLBRK\"]}},\"version\":1}"},"hashes":{}},"solidity/FastBridgeV2.sol:IMulticallTarget":{"code":"0x","runtime-code":"0x","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.24 ^0.8.20 ^0.8.4;\n\n// contracts/interfaces/IAdminV2.sol\n\ninterface IAdminV2 {\n event CancelDelayUpdated(uint256 oldCancelDelay, uint256 newCancelDelay);\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n function setCancelDelay(uint256 newCancelDelay) external;\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n}\n\n// contracts/interfaces/IAdminV2Errors.sol\n\ninterface IAdminV2Errors {\n error CancelDelayBelowMin();\n error FeeRateAboveMax();\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IFastBridgeV2Errors.sol\n\ninterface IFastBridgeV2Errors {\n error AmountIncorrect();\n error ChainIncorrect();\n error ExclusivityParamsIncorrect();\n error MsgValueIncorrect();\n error SenderIncorrect();\n error StatusIncorrect();\n error TokenNotContract();\n error ZapDataLengthAboveMax();\n error ZapNativeNotSupported();\n error ZeroAddress();\n\n error RecipientIncorrectReturnValue();\n error RecipientNoReturnValue();\n\n error DeadlineExceeded();\n error DeadlineNotExceeded();\n error DeadlineTooShort();\n error DisputePeriodNotPassed();\n error DisputePeriodPassed();\n error ExclusivityPeriodNotPassed();\n\n error TransactionRelayed();\n}\n\n// contracts/interfaces/IMulticallTarget.sol\n\n/// @notice Interface for a contract that can be called multiple times by the same caller. Inspired by MulticallV3:\n/// https://github.com/mds1/multicall/blob/master/src/Multicall3.sol\ninterface IMulticallTarget {\n struct Result {\n bool success;\n bytes returnData;\n }\n\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external;\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results);\n}\n\n// contracts/interfaces/IZapRecipient.sol\n\ninterface IZapRecipient {\n function zap(address token, uint256 amount, bytes memory zapData) external payable returns (bytes4);\n}\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// contracts/interfaces/IFastBridgeV2.sol\n\ninterface IFastBridgeV2 is IFastBridge {\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n struct BridgeTxDetails {\n BridgeStatus status;\n uint32 destChainId;\n uint56 proofBlockTimestamp;\n address proofRelayer;\n }\n\n struct BridgeRelay {\n uint48 blockNumber;\n uint48 blockTimestamp;\n address relayer;\n }\n\n /// @notice New params introduced in the FastBridgeV2.\n /// We are passing fields from the older BridgeParams struct outside of this struct\n /// for backwards compatibility.\n /// Note: quoteRelayer and quoteExclusivitySeconds are either both zero (indicating no exclusivity)\n /// or both non-zero (indicating exclusivity for the given period).\n /// Note: zapNative \u003e 0 can NOT be used with destToken = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE (native token)\n /// @param quoteRelayer Relayer that provided the quote for the transaction\n /// @param quoteExclusivitySeconds Period of time the quote relayer is guaranteed exclusivity after user's deposit\n /// @param quoteId Unique quote identifier used for tracking the quote\n /// @param zapNative ETH value to send to the recipient (if any)\n /// @param zapData Parameters for the Zap to the destination recipient (if any)\n struct BridgeParamsV2 {\n address quoteRelayer;\n int256 quoteExclusivitySeconds;\n bytes quoteId;\n uint256 zapNative;\n bytes zapData;\n }\n\n /// @notice Updated bridge transaction struct to include parameters introduced in FastBridgeV2.\n /// Note: only `exclusivityRelayer` can fill such a transaction until `exclusivityEndTime`.\n struct BridgeTransactionV2 {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n // Note: sendChainGas flag from V1 is deprecated\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n address exclusivityRelayer;\n uint256 exclusivityEndTime;\n uint256 zapNative; // ETH value to send to the recipient (if any)\n bytes zapData; // data to pass for the Zap action (if any)\n }\n\n event BridgeQuoteDetails(bytes32 indexed transactionId, bytes quoteId);\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability\n /// to provide temporary exclusivity fill rights for the quote relayer.\n /// @param params The parameters required to bridge\n /// @param paramsV2 The parameters for exclusivity fill rights (optional, can be left empty)\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function relay(bytes memory request, address relayer) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param transactionId The transaction id associated with the encoded bridge transaction to prove\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital.\n /// @notice Can only send funds to the relayer address on the proof.\n /// @param request The encoded bridge transaction to claim on origin chain\n function claim(bytes memory request) external;\n\n /// @notice Cancels an outstanding bridge transaction in case optimistic bridging failed and returns the full amount\n /// to the original sender.\n /// @param request The encoded bridge transaction to refund\n function cancel(bytes memory request) external;\n\n /// @notice Checks if a transaction has been relayed\n /// @param transactionId The ID of the transaction to check\n /// @return True if the transaction has been relayed, false otherwise\n function bridgeRelays(bytes32 transactionId) external view returns (bool);\n\n /// @notice Returns the status of a bridge transaction\n /// @param transactionId The ID of the bridge transaction\n /// @return BridgeStatus Status of the bridge transaction\n function bridgeStatuses(bytes32 transactionId) external view returns (BridgeStatus);\n\n /// @notice Returns the timestamp and relayer of a bridge proof\n /// @param transactionId The ID of the bridge transaction\n /// @return timestamp The timestamp of the bridge proof\n /// @return relayer The relayer address of the bridge proof\n function bridgeProofs(bytes32 transactionId) external view returns (uint96 timestamp, address relayer);\n\n /// @notice Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\n /// @param request The bridge request to decode\n function getBridgeTransactionV2(bytes memory request) external view returns (BridgeTransactionV2 memory);\n}\n\n// contracts/utils/MulticallTarget.sol\n\n// solhint-disable avoid-low-level-calls\n/// @notice Template for a contract that supports batched calls (preserving the msg.sender).\n/// Only calls with zero msg.value could be batched.\nabstract contract MulticallTarget is IMulticallTarget {\n error MulticallTarget__UndeterminedRevert();\n\n /// @notice Perform a batched call to this contract, preserving the msg.sender.\n /// The return data from each call is discarded.\n /// @dev The method is non-payable, so only calls with `msg.value == 0` could be batched.\n /// It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag.\n /// Otherwise, the whole batch call will be reverted with the original revert reason.\n /// @param data List of abi-encoded calldata for the calls to perform.\n /// @param ignoreReverts Whether to ignore the revert errors from the calls.\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external {\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\n if (!success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(result);\n }\n }\n }\n\n /// @notice Perform a batched call to this contract, preserving the msg.sender.\n /// The return data from each call is preserved.\n /// @dev The method is non-payable, so only calls with `msg.value == 0` could be batched.\n /// It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag.\n /// Otherwise, the whole batch call will be reverted with the original revert reason.\n /// @param data List of abi-encoded calldata for the calls to perform.\n /// @param ignoreReverts Whether to ignore the revert errors from the calls.\n /// @return results List of results from the calls: `(success, returnData)`.\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results)\n {\n results = new Result[](data.length);\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (results[i].success, results[i].returnData) = address(this).delegatecall(data[i]);\n if (!results[i].success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(results[i].returnData);\n }\n }\n }\n\n /// @dev Bubbles the revert message from the underlying call.\n /// Note: preserves the same custom error or revert string, if one was used.\n /// Source: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v5.0.2/contracts/utils/Address.sol#L143-L158\n function _bubbleRevert(bytes memory returnData) internal pure {\n // Look for revert reason and bubble it up if present\n if (returnData.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n // solhint-disable-next-line no-inline-assembly\n assembly {\n let returndata_size := mload(returnData)\n revert(add(32, returnData), returndata_size)\n }\n } else {\n revert MulticallTarget__UndeterminedRevert();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// contracts/libs/BridgeTransactionV2.sol\n\n// solhint-disable no-inline-assembly\nlibrary BridgeTransactionV2Lib {\n uint16 internal constant VERSION = 2;\n\n // Offsets of the fields in the packed BridgeTransactionV2 struct\n // uint16 version [000 .. 002)\n // uint32 originChainId [002 .. 006)\n // uint32 destChainId [006 .. 010)\n // address originSender [010 .. 030)\n // address destRecipient [030 .. 050)\n // address originToken [050 .. 070)\n // address destToken [070 .. 090)\n // uint256 originAmount [090 .. 122)\n // uint256 destAmount [122 .. 154)\n // uint256 originFeeAmount [154 .. 186)\n // uint256 deadline [186 .. 218)\n // uint256 nonce [218 .. 250)\n // address exclusivityRelayer [250 .. 270)\n // uint256 exclusivityEndTime [270 .. 302)\n // uint256 zapNative [302 .. 334)\n // bytes zapData [334 .. ***)\n\n // forgefmt: disable-start\n uint256 private constant OFFSET_ORIGIN_CHAIN_ID = 2;\n uint256 private constant OFFSET_DEST_CHAIN_ID = 6;\n uint256 private constant OFFSET_ORIGIN_SENDER = 10;\n uint256 private constant OFFSET_DEST_RECIPIENT = 30;\n uint256 private constant OFFSET_ORIGIN_TOKEN = 50;\n uint256 private constant OFFSET_DEST_TOKEN = 70;\n uint256 private constant OFFSET_ORIGIN_AMOUNT = 90;\n uint256 private constant OFFSET_DEST_AMOUNT = 122;\n uint256 private constant OFFSET_ORIGIN_FEE_AMOUNT = 154;\n uint256 private constant OFFSET_DEADLINE = 186;\n uint256 private constant OFFSET_NONCE = 218;\n uint256 private constant OFFSET_EXCLUSIVITY_RELAYER = 250;\n uint256 private constant OFFSET_EXCLUSIVITY_END_TIME = 270;\n uint256 private constant OFFSET_ZAP_NATIVE = 302;\n uint256 private constant OFFSET_ZAP_DATA = 334;\n // forgefmt: disable-end\n\n error BridgeTransactionV2__InvalidEncodedTx();\n error BridgeTransactionV2__UnsupportedVersion(uint16 version);\n\n /// @notice Validates the encoded transaction to be a tightly packed encoded payload for BridgeTransactionV2.\n /// @dev Checks the minimum length and the version, use this function before decoding any of the fields.\n function validateV2(bytes calldata encodedTx) internal pure {\n // Check the minimum length: must at least include all static fields.\n if (encodedTx.length \u003c OFFSET_ZAP_DATA) revert BridgeTransactionV2__InvalidEncodedTx();\n // Once we validated the length, we can be sure that the version field is present.\n uint16 version_ = version(encodedTx);\n if (version_ != VERSION) revert BridgeTransactionV2__UnsupportedVersion(version_);\n }\n\n /// @notice Encodes the BridgeTransactionV2 struct by tightly packing the fields.\n /// @dev `abi.decode` will not work as a result of the tightly packed fields. Use `decodeV2` to decode instead.\n function encodeV2(IFastBridgeV2.BridgeTransactionV2 memory bridgeTx) internal pure returns (bytes memory) {\n // We split the encoding into two parts to avoid stack-too-deep error\n bytes memory firstPart = abi.encodePacked(\n VERSION,\n bridgeTx.originChainId,\n bridgeTx.destChainId,\n bridgeTx.originSender,\n bridgeTx.destRecipient,\n bridgeTx.originToken,\n bridgeTx.destToken,\n bridgeTx.originAmount\n );\n return abi.encodePacked(\n firstPart,\n bridgeTx.destAmount,\n bridgeTx.originFeeAmount,\n // Note: we skip the deprecated `sendChainGas` flag, which was present in BridgeTransaction V1\n bridgeTx.deadline,\n bridgeTx.nonce,\n // New V2 fields: exclusivity\n bridgeTx.exclusivityRelayer,\n bridgeTx.exclusivityEndTime,\n // New V2 fields: Zap\n bridgeTx.zapNative,\n bridgeTx.zapData\n );\n }\n\n /// @notice Decodes the BridgeTransactionV2 struct from the encoded transaction.\n /// @dev Encoded BridgeTransactionV2 struct must be tightly packed.\n /// Use `validateV2` before decoding to ensure the encoded transaction is valid.\n function decodeV2(bytes calldata encodedTx)\n internal\n pure\n returns (IFastBridgeV2.BridgeTransactionV2 memory bridgeTx)\n {\n bridgeTx.originChainId = originChainId(encodedTx);\n bridgeTx.destChainId = destChainId(encodedTx);\n bridgeTx.originSender = originSender(encodedTx);\n bridgeTx.destRecipient = destRecipient(encodedTx);\n bridgeTx.originToken = originToken(encodedTx);\n bridgeTx.destToken = destToken(encodedTx);\n bridgeTx.originAmount = originAmount(encodedTx);\n bridgeTx.destAmount = destAmount(encodedTx);\n bridgeTx.originFeeAmount = originFeeAmount(encodedTx);\n bridgeTx.deadline = deadline(encodedTx);\n bridgeTx.nonce = nonce(encodedTx);\n bridgeTx.exclusivityRelayer = exclusivityRelayer(encodedTx);\n bridgeTx.exclusivityEndTime = exclusivityEndTime(encodedTx);\n bridgeTx.zapNative = zapNative(encodedTx);\n bridgeTx.zapData = zapData(encodedTx);\n }\n\n /// @notice Extracts the version from the encoded transaction.\n function version(bytes calldata encodedTx) internal pure returns (uint16 version_) {\n // Load 32 bytes from the start and shift it 240 bits to the right to get the highest 16 bits.\n assembly {\n version_ := shr(240, calldataload(encodedTx.offset))\n }\n }\n\n /// @notice Extracts the origin chain ID from the encoded transaction.\n function originChainId(bytes calldata encodedTx) internal pure returns (uint32 originChainId_) {\n // Load 32 bytes from the offset and shift it 224 bits to the right to get the highest 32 bits.\n assembly {\n originChainId_ := shr(224, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_CHAIN_ID)))\n }\n }\n\n /// @notice Extracts the destination chain ID from the encoded transaction.\n function destChainId(bytes calldata encodedTx) internal pure returns (uint32 destChainId_) {\n // Load 32 bytes from the offset and shift it 224 bits to the right to get the highest 32 bits.\n assembly {\n destChainId_ := shr(224, calldataload(add(encodedTx.offset, OFFSET_DEST_CHAIN_ID)))\n }\n }\n\n /// @notice Extracts the origin sender from the encoded transaction.\n function originSender(bytes calldata encodedTx) internal pure returns (address originSender_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n originSender_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_SENDER)))\n }\n }\n\n /// @notice Extracts the destination recipient from the encoded transaction.\n function destRecipient(bytes calldata encodedTx) internal pure returns (address destRecipient_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n destRecipient_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_DEST_RECIPIENT)))\n }\n }\n\n /// @notice Extracts the origin token from the encoded transaction.\n function originToken(bytes calldata encodedTx) internal pure returns (address originToken_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n originToken_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_TOKEN)))\n }\n }\n\n /// @notice Extracts the destination token from the encoded transaction.\n function destToken(bytes calldata encodedTx) internal pure returns (address destToken_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n destToken_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_DEST_TOKEN)))\n }\n }\n\n /// @notice Extracts the origin amount from the encoded transaction.\n function originAmount(bytes calldata encodedTx) internal pure returns (uint256 originAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n originAmount_ := calldataload(add(encodedTx.offset, OFFSET_ORIGIN_AMOUNT))\n }\n }\n\n /// @notice Extracts the destination amount from the encoded transaction.\n function destAmount(bytes calldata encodedTx) internal pure returns (uint256 destAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n destAmount_ := calldataload(add(encodedTx.offset, OFFSET_DEST_AMOUNT))\n }\n }\n\n /// @notice Extracts the origin fee amount from the encoded transaction.\n function originFeeAmount(bytes calldata encodedTx) internal pure returns (uint256 originFeeAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n originFeeAmount_ := calldataload(add(encodedTx.offset, OFFSET_ORIGIN_FEE_AMOUNT))\n }\n }\n\n /// @notice Extracts the deadline from the encoded transaction.\n function deadline(bytes calldata encodedTx) internal pure returns (uint256 deadline_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n deadline_ := calldataload(add(encodedTx.offset, OFFSET_DEADLINE))\n }\n }\n\n /// @notice Extracts the nonce from the encoded transaction.\n function nonce(bytes calldata encodedTx) internal pure returns (uint256 nonce_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n nonce_ := calldataload(add(encodedTx.offset, OFFSET_NONCE))\n }\n }\n\n /// @notice Extracts the exclusivity relayer from the encoded transaction.\n function exclusivityRelayer(bytes calldata encodedTx) internal pure returns (address exclusivityRelayer_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n exclusivityRelayer_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_EXCLUSIVITY_RELAYER)))\n }\n }\n\n /// @notice Extracts the exclusivity end time from the encoded transaction.\n function exclusivityEndTime(bytes calldata encodedTx) internal pure returns (uint256 exclusivityEndTime_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n exclusivityEndTime_ := calldataload(add(encodedTx.offset, OFFSET_EXCLUSIVITY_END_TIME))\n }\n }\n\n /// @notice Extracts the Zap's native value from the encoded transaction.\n function zapNative(bytes calldata encodedTx) internal pure returns (uint256 zapNative_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n zapNative_ := calldataload(add(encodedTx.offset, OFFSET_ZAP_NATIVE))\n }\n }\n\n /// @notice Extracts the Zap's data from the encoded transaction.\n function zapData(bytes calldata encodedTx) internal pure returns (bytes calldata zapData_) {\n zapData_ = encodedTx[OFFSET_ZAP_DATA:];\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/AdminV2.sol\n\ncontract AdminV2 is AccessControlEnumerable, IAdminV2, IAdminV2Errors {\n using SafeERC20 for IERC20;\n\n /// @notice Address reserved for native gas token (ETH on Ethereum and most L2s, AVAX on Avalanche, etc)\n address public constant NATIVE_GAS_TOKEN = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Role identifier for Quoter API's off-chain authentication.\n /// @dev Only addresses with this role can post FastBridge quotes to the API.\n bytes32 public constant QUOTER_ROLE = keccak256(\"QUOTER_ROLE\");\n\n /// @notice Role identifier for Prover's on-chain authentication in FastBridge.\n /// @dev Only addresses with this role can provide proofs that a FastBridge request has been relayed.\n bytes32 public constant PROVER_ROLE = keccak256(\"PROVER_ROLE\");\n\n /// @notice Role identifier for Guard's on-chain authentication in FastBridge.\n /// @dev Only addresses with this role can dispute submitted relay proofs during the dispute period.\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n\n /// @notice Role identifier for Canceler's on-chain authentication in FastBridge.\n /// @dev Only addresses with this role can cancel a FastBridge transaction without the cancel delay.\n bytes32 public constant CANCELER_ROLE = keccak256(\"CANCELER_ROLE\");\n\n /// @notice Role identifier for Governor's on-chain administrative authority.\n /// @dev Only addresses with this role can perform administrative tasks within the contract.\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n /// @notice Denominator for fee rates, represents 100%.\n uint256 public constant FEE_BPS = 1e6;\n /// @notice Maximum protocol fee rate: 1% on origin amount.\n uint256 public constant FEE_RATE_MAX = 0.01e6;\n\n /// @notice Minimum cancel delay that can be set by the governor.\n uint256 public constant MIN_CANCEL_DELAY = 1 hours;\n /// @notice Default cancel delay set during the contract deployment.\n uint256 public constant DEFAULT_CANCEL_DELAY = 1 days;\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Delay for a transaction after which it could be permisionlessly cancelled\n uint256 public cancelDelay;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Use ZapNative V2 requests instead.\n uint256 public immutable chainGasAmount = 0;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n _setCancelDelay(DEFAULT_CANCEL_DELAY);\n }\n\n /// @notice Allows the contract governor to set the cancel delay. The cancel delay is the time after the transaction\n /// deadline after which it can be permissionlessly cancelled, if it hasn't been proven by any of the Relayers.\n function setCancelDelay(uint256 newCancelDelay) external onlyRole(GOVERNOR_ROLE) {\n _setCancelDelay(newCancelDelay);\n }\n\n /// @notice Allows the contract governor to set the protocol fee rate. The protocol fee is taken from the origin\n /// amount only for completed and claimed transactions.\n /// @dev The protocol fee is abstracted away from the relayers, they always operate using the amounts after fees:\n /// what they see as the origin amount emitted in the log is what they get credited with.\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n if (newFeeRate \u003e FEE_RATE_MAX) revert FeeRateAboveMax();\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n /// @notice Allows the contract governor to sweep the accumulated protocol fees in the contract.\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n emit FeesSwept(token, recipient, feeAmount);\n /// Sweep the fees as the last transaction action\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(recipient), feeAmount);\n } else {\n IERC20(token).safeTransfer(recipient, feeAmount);\n }\n }\n\n /// @notice Internal function to set the cancel delay. Security checks are performed outside of this function.\n function _setCancelDelay(uint256 newCancelDelay) private {\n if (newCancelDelay \u003c MIN_CANCEL_DELAY) revert CancelDelayBelowMin();\n uint256 oldCancelDelay = cancelDelay;\n cancelDelay = newCancelDelay;\n emit CancelDelayUpdated(oldCancelDelay, newCancelDelay);\n }\n}\n\n// contracts/FastBridgeV2.sol\n\n/// @notice FastBridgeV2 is a contract for bridging tokens across chains.\ncontract FastBridgeV2 is AdminV2, MulticallTarget, IFastBridgeV2, IFastBridgeV2Errors {\n using BridgeTransactionV2Lib for bytes;\n using SafeERC20 for IERC20;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n /// @notice Maximum length of accepted zapData\n uint256 public constant MAX_ZAP_DATA_LENGTH = 2 ** 16 - 1;\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeTxDetails) public bridgeTxDetails;\n /// @notice Relay details on destination chain\n mapping(bytes32 =\u003e BridgeRelay) public bridgeRelayDetails;\n /// @notice Unique bridge nonces tracked per originSender\n mapping(address =\u003e uint256) public senderNonces;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Replaced by senderNonces\n uint256 public immutable nonce = 0;\n /// @notice the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) AdminV2(_owner) {\n deployBlock = block.number;\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n bridge({\n params: params,\n paramsV2: BridgeParamsV2({\n quoteRelayer: address(0),\n quoteExclusivitySeconds: 0,\n quoteId: bytes(\"\"),\n zapNative: 0,\n zapData: bytes(\"\")\n })\n });\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes calldata request) external payable {\n // relay override will validate the request\n relay({request: request, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes calldata request, bytes32 destTxHash) external {\n request.validateV2();\n prove({transactionId: keccak256(request), destTxHash: destTxHash, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridgeV2\n function claim(bytes calldata request) external {\n // claim override will validate the request\n claim({request: request, to: address(0)});\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Aggregate the read operations from the same storage slot\n address disputedRelayer = $.proofRelayer;\n BridgeStatus status = $.status;\n uint56 proofBlockTimestamp = $.proofBlockTimestamp;\n // Can only dispute a RELAYER_PROVED transaction within the dispute period\n if (status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(proofBlockTimestamp) \u003e DISPUTE_PERIOD) {\n revert DisputePeriodPassed();\n }\n // Update status to REQUESTED and delete the disputed proof details\n // Note: these are storage writes\n $.status = BridgeStatus.REQUESTED;\n $.proofRelayer = address(0);\n $.proofBlockTimestamp = 0;\n\n emit BridgeProofDisputed(transactionId, disputedRelayer);\n }\n\n /// Note: this function is deprecated and will be removed in a future version.\n /// @inheritdoc IFastBridge\n function refund(bytes calldata request) external {\n cancel(request);\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // The correct relayer can only claim a RELAYER_PROVED transaction after the dispute period\n if ($.status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if ($.proofRelayer != relayer) revert SenderIncorrect();\n return _timeSince($.proofBlockTimestamp) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n /// @dev This method is added to achieve backwards compatibility with decoding requests into V1 structs:\n /// - `zapNative` is partially reported as a zero/non-zero flag\n /// - `zapData` is ignored\n /// In order to process all kinds of requests use getBridgeTransactionV2 instead.\n function getBridgeTransaction(bytes calldata request) external view returns (BridgeTransaction memory) {\n // Try decoding into V2 struct first. This will revert if V1 struct is passed\n try this.getBridgeTransactionV2(request) returns (BridgeTransactionV2 memory txV2) {\n // Note: we entirely ignore the zapData field, as it was not present in V1\n return BridgeTransaction({\n originChainId: txV2.originChainId,\n destChainId: txV2.destChainId,\n originSender: txV2.originSender,\n destRecipient: txV2.destRecipient,\n originToken: txV2.originToken,\n destToken: txV2.destToken,\n originAmount: txV2.originAmount,\n destAmount: txV2.destAmount,\n originFeeAmount: txV2.originFeeAmount,\n sendChainGas: txV2.zapNative != 0,\n deadline: txV2.deadline,\n nonce: txV2.nonce\n });\n } catch {\n // Fallback to V1 struct\n return abi.decode(request, (BridgeTransaction));\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function getBridgeTransactionV2(bytes calldata request) external pure returns (BridgeTransactionV2 memory) {\n request.validateV2();\n return BridgeTransactionV2Lib.decodeV2(request);\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) public payable {\n int256 exclusivityEndTime = 0;\n // if relayer exclusivity is not intended for this bridge, set exclusivityEndTime to static zero\n // otherwise, set exclusivity to expire at the current block ts offset by quoteExclusivitySeconds\n if (paramsV2.quoteRelayer != address(0)) {\n exclusivityEndTime = int256(block.timestamp) + paramsV2.quoteExclusivitySeconds;\n }\n _validateBridgeParams(params, paramsV2, exclusivityEndTime);\n\n // transfer tokens to bridge contract\n /// @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _takeBridgedUserAsset(params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) {\n originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n }\n\n // set status to requested\n bytes memory request = BridgeTransactionV2Lib.encodeV2(\n BridgeTransactionV2({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n deadline: params.deadline,\n nonce: senderNonces[params.sender]++, // increment nonce on every bridge\n exclusivityRelayer: paramsV2.quoteRelayer,\n // We checked exclusivityEndTime to be in range [0 .. params.deadline] above, so can safely cast\n exclusivityEndTime: uint256(exclusivityEndTime),\n zapNative: paramsV2.zapNative,\n zapData: paramsV2.zapData\n })\n );\n bytes32 transactionId = keccak256(request);\n // Note: the tx status will be updated throughout the tx lifecycle, while destChainId is set once here\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n bridgeTxDetails[transactionId].destChainId = params.dstChainId;\n\n emit BridgeRequested({\n transactionId: transactionId,\n sender: params.sender,\n request: request,\n destChainId: params.dstChainId,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n sendChainGas: paramsV2.zapNative != 0\n });\n emit BridgeQuoteDetails(transactionId, paramsV2.quoteId);\n }\n\n /// @inheritdoc IFastBridgeV2\n function relay(bytes calldata request, address relayer) public payable {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n _validateRelayParams(request, transactionId, relayer);\n // mark bridge transaction as relayed\n bridgeRelayDetails[transactionId] =\n BridgeRelay({blockNumber: uint48(block.number), blockTimestamp: uint48(block.timestamp), relayer: relayer});\n\n // transfer tokens to recipient on destination chain and trigger Zap if requested\n address to = request.destRecipient();\n address token = request.destToken();\n uint256 amount = request.destAmount();\n uint256 zapNative = request.zapNative();\n\n // Emit the event before any external calls\n emit BridgeRelayed({\n transactionId: transactionId,\n relayer: relayer,\n to: to,\n originChainId: request.originChainId(),\n originToken: request.originToken(),\n destToken: token,\n originAmount: request.originAmount(),\n destAmount: amount,\n chainGasAmount: zapNative\n });\n\n // All state changes have been done at this point, can proceed to the external calls.\n // This follows the checks-effects-interactions pattern to mitigate potential reentrancy attacks.\n if (token == NATIVE_GAS_TOKEN) {\n // For the native gas token, additional zapNative is not allowed\n if (zapNative != 0) revert ZapNativeNotSupported();\n // Check that the correct msg.value was sent\n if (msg.value != amount) revert MsgValueIncorrect();\n // Don't do a native transfer yet: we will handle it alongside the Zap below\n } else {\n // For ERC20s, we check that the correct msg.value was sent\n if (msg.value != zapNative) revert MsgValueIncorrect();\n // We need to transfer the tokens from the Relayer to the recipient first before performing an\n // optional post-transfer Zap.\n IERC20(token).safeTransferFrom(msg.sender, to, amount);\n }\n // At this point we have done:\n // - Transferred the requested amount of ERC20 tokens to the recipient.\n // At this point we have confirmed:\n // - For ERC20s: msg.value matches the requested zapNative amount.\n // - For the native gas token: msg.value matches the requested destAmount.\n // Remaining optional things to do:\n // - Forward the full msg.value to the recipient (if non-zero).\n // - Trigger a Zap (if zapData is present).\n bytes calldata zapData = request.zapData();\n if (zapData.length != 0) {\n // Zap Data is present: Zap has been requested by the recipient. Trigger it forwarding the full msg.value.\n\n // Note: if token has a fee on transfers, the recipient will have received less than `amount`.\n // This is a very niche edge case and should be handled by the recipient contract.\n _triggerZapWithChecks({recipient: to, token: token, amount: amount, zapData: zapData});\n } else if (msg.value != 0) {\n // Zap Data is missing, but msg.value was sent. This could happen in two different cases:\n // - Relay with the native gas token is happening.\n // - Relay with ERC20 is happening, with a `zapNative \u003e 0` request.\n // In both cases, we need to transfer the full msg.value to the recipient.\n Address.sendValue(payable(to), msg.value);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) public onlyRole(PROVER_ROLE) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n\n // Can only prove a REQUESTED transaction\n if ($.status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n // Update status to RELAYER_PROVED and store the proof details\n // Note: these are storage writes\n $.status = BridgeStatus.RELAYER_PROVED;\n $.proofBlockTimestamp = uint56(block.timestamp);\n $.proofRelayer = relayer;\n\n emit BridgeProofProvided(transactionId, relayer, destTxHash);\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes calldata request, address to) public {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Aggregate the read operations from the same storage slot\n address proofRelayer = $.proofRelayer;\n BridgeStatus status = $.status;\n uint56 proofBlockTimestamp = $.proofBlockTimestamp;\n\n // Can only claim a RELAYER_PROVED transaction after the dispute period\n if (status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(proofBlockTimestamp) \u003c= DISPUTE_PERIOD) {\n revert DisputePeriodNotPassed();\n }\n\n if (to == address(0)) {\n // Anyone could claim the funds to the proven relayer on their behalf\n to = proofRelayer;\n } else if (proofRelayer != msg.sender) {\n // Only the proven relayer could specify an address to claim the funds to\n revert SenderIncorrect();\n }\n\n // Update status to RELAYER_CLAIMED and transfer the origin collateral to the specified claim address\n // Note: this is a storage write\n $.status = BridgeStatus.RELAYER_CLAIMED;\n\n address token = request.originToken();\n uint256 amount = request.originAmount();\n // Update protocol fees if origin fee amount exists\n uint256 originFeeAmount = request.originFeeAmount();\n if (originFeeAmount \u003e 0) protocolFees[token] += originFeeAmount;\n // Emit the event before any external calls\n emit BridgeDepositClaimed(transactionId, proofRelayer, to, token, amount);\n // Complete the relayer claim as the last transaction action\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(to), amount);\n } else {\n IERC20(token).safeTransfer(to, amount);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function cancel(bytes calldata request) public {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Can only cancel a REQUESTED transaction after its deadline expires\n if ($.status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n uint256 deadline = request.deadline();\n // Permissionless cancel is only allowed after `cancelDelay` on top of the deadline\n if (!hasRole(CANCELER_ROLE, msg.sender)) deadline += cancelDelay;\n if (block.timestamp \u003c= deadline) revert DeadlineNotExceeded();\n // Update status to REFUNDED and return the full amount (collateral + protocol fees) to the original sender.\n // The protocol fees are only updated when the transaction is claimed, so we don't need to update them here.\n // Note: this is a storage write\n $.status = BridgeStatus.REFUNDED;\n\n address to = request.originSender();\n address token = request.originToken();\n uint256 amount = request.originAmount() + request.originFeeAmount();\n // Emit the event before any external calls\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n // Complete the user cancel as the last transaction action\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(to), amount);\n } else {\n IERC20(token).safeTransfer(to, amount);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeStatuses(bytes32 transactionId) public view returns (BridgeStatus status) {\n return bridgeTxDetails[transactionId].status;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeProofs(bytes32 transactionId) public view returns (uint96 timestamp, address relayer) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n\n timestamp = $.proofBlockTimestamp;\n relayer = $.proofRelayer;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeRelays(bytes32 transactionId) public view returns (bool) {\n // has this transactionId been relayed?\n return bridgeRelayDetails[transactionId].relayer != address(0);\n }\n\n /// @notice Takes the bridged asset from the user into FastBridgeV2 custody. It will be later\n /// claimed by the relayer who completed the relay on destination chain, or transferred back to the user\n /// via the cancel function should no one complete the relay.\n function _takeBridgedUserAsset(address token, uint256 amount) internal returns (uint256 amountTaken) {\n if (token == NATIVE_GAS_TOKEN) {\n // For the native gas token, we just need to check that the supplied msg.value is correct.\n // Supplied `msg.value` is already in FastBridgeV2 custody.\n if (amount != msg.value) revert MsgValueIncorrect();\n amountTaken = msg.value;\n } else {\n // For ERC20s, token is explicitly transferred from the user to FastBridgeV2.\n // We don't allow non-zero `msg.value` to avoid extra funds from being stuck in FastBridgeV2.\n if (msg.value != 0) revert MsgValueIncorrect();\n // Throw an explicit error if the provided token address is not a contract\n if (token.code.length == 0) revert TokenNotContract();\n amountTaken = IERC20(token).balanceOf(address(this));\n IERC20(token).safeTransferFrom(msg.sender, address(this), amount);\n // Use the balance difference as the amount taken in case of fee on transfer tokens.\n amountTaken = IERC20(token).balanceOf(address(this)) - amountTaken;\n }\n }\n\n /// @notice Calls the Recipient's hook function with the specified zapData and performs\n /// all the necessary checks for the returned value.\n function _triggerZapWithChecks(address recipient, address token, uint256 amount, bytes calldata zapData) internal {\n // This will bubble any revert messages from the hook function\n bytes memory returnData = Address.functionCallWithValue({\n target: recipient,\n data: abi.encodeCall(IZapRecipient.zap, (token, amount, zapData)),\n // Note: see `relay()` for reasoning behind passing msg.value\n value: msg.value\n });\n // Explicit revert if no return data at all\n if (returnData.length == 0) revert RecipientNoReturnValue();\n // Check that exactly a single return value was returned\n if (returnData.length != 32) revert RecipientIncorrectReturnValue();\n // Return value should be abi-encoded hook function selector\n if (bytes32(returnData) != bytes32(IZapRecipient.zap.selector)) {\n revert RecipientIncorrectReturnValue();\n }\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint56(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint56).max but\n /// proof.timestamp \u003c type(uint56).max via unchecked statement\n /// @param proofBlockTimestamp The bridge proof block timestamp\n /// @return delta Time delta since proof submitted\n function _timeSince(uint56 proofBlockTimestamp) internal view returns (uint256 delta) {\n unchecked {\n delta = uint56(block.timestamp) - proofBlockTimestamp;\n }\n }\n\n /// @notice Performs all the necessary checks for a bridge to happen.\n /// @dev There's no good way to refactor this function to reduce cyclomatic complexity due to\n /// the number of checks that need to be performed, so we skip the code-complexity rule here.\n // solhint-disable-next-line code-complexity\n function _validateBridgeParams(\n BridgeParams memory params,\n BridgeParamsV2 memory paramsV2,\n int256 exclusivityEndTime\n )\n internal\n view\n {\n // Check V1 (legacy) params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.sender == address(0) || params.to == address(0)) revert ZeroAddress();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n // Check V2 params\n if (paramsV2.zapData.length \u003e MAX_ZAP_DATA_LENGTH) revert ZapDataLengthAboveMax();\n if (paramsV2.zapNative != 0 \u0026\u0026 params.destToken == NATIVE_GAS_TOKEN) {\n revert ZapNativeNotSupported();\n }\n // exclusivityEndTime must be in range [0 .. params.deadline]\n if (exclusivityEndTime \u003c 0 || exclusivityEndTime \u003e int256(params.deadline)) {\n revert ExclusivityParamsIncorrect();\n }\n }\n\n /// @notice Performs all the necessary checks for a relay to happen.\n function _validateRelayParams(bytes calldata request, bytes32 transactionId, address relayer) internal view {\n if (relayer == address(0)) revert ZeroAddress();\n // Check if the transaction has already been relayed\n if (bridgeRelays(transactionId)) revert TransactionRelayed();\n if (request.destChainId() != block.chainid) revert ChainIncorrect();\n // Check the deadline for relay to happen\n if (block.timestamp \u003e request.deadline()) revert DeadlineExceeded();\n // Check the exclusivity period, if it is still ongoing\n address exclRelayer = request.exclusivityRelayer();\n if (exclRelayer != address(0) \u0026\u0026 exclRelayer != relayer \u0026\u0026 block.timestamp \u003c= request.exclusivityEndTime()) {\n revert ExclusivityPeriodNotPassed();\n }\n }\n}\n","language":"Solidity","languageVersion":"0.8.24","compilerVersion":"0.8.24","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"","srcMapRuntime":"","abiDefinition":[{"inputs":[{"internalType":"bytes[]","name":"data","type":"bytes[]"},{"internalType":"bool","name":"ignoreReverts","type":"bool"}],"name":"multicallNoResults","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes[]","name":"data","type":"bytes[]"},{"internalType":"bool","name":"ignoreReverts","type":"bool"}],"name":"multicallWithResults","outputs":[{"components":[{"internalType":"bool","name":"success","type":"bool"},{"internalType":"bytes","name":"returnData","type":"bytes"}],"internalType":"struct IMulticallTarget.Result[]","name":"results","type":"tuple[]"}],"stateMutability":"nonpayable","type":"function"}],"userDoc":{"kind":"user","methods":{},"notice":"Interface for a contract that can be called multiple times by the same caller. Inspired by MulticallV3: https://github.com/mds1/multicall/blob/master/src/Multicall3.sol","version":1},"developerDoc":{"kind":"dev","methods":{},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"bytes[]\",\"name\":\"data\",\"type\":\"bytes[]\"},{\"internalType\":\"bool\",\"name\":\"ignoreReverts\",\"type\":\"bool\"}],\"name\":\"multicallNoResults\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes[]\",\"name\":\"data\",\"type\":\"bytes[]\"},{\"internalType\":\"bool\",\"name\":\"ignoreReverts\",\"type\":\"bool\"}],\"name\":\"multicallWithResults\",\"outputs\":[{\"components\":[{\"internalType\":\"bool\",\"name\":\"success\",\"type\":\"bool\"},{\"internalType\":\"bytes\",\"name\":\"returnData\",\"type\":\"bytes\"}],\"internalType\":\"struct IMulticallTarget.Result[]\",\"name\":\"results\",\"type\":\"tuple[]\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"notice\":\"Interface for a contract that can be called multiple times by the same caller. Inspired by MulticallV3: https://github.com/mds1/multicall/blob/master/src/Multicall3.sol\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeV2.sol\":\"IMulticallTarget\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeV2.sol\":{\"keccak256\":\"0xac79c463688a682ca706a4ef95e7817b83548cdfa8182ba0426ac7e5e07613d8\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://b3ecb7097381287cafc3a73f3a2bb03565115ebb682a85064e0b0dc2f7e2919d\",\"dweb:/ipfs/QmatruW3nYZTksf3CeQ8wwiAG4c7xoEJBEp6drHPtFLBRK\"]}},\"version\":1}"},"hashes":{"multicallNoResults(bytes[],bool)":"3f61331d","multicallWithResults(bytes[],bool)":"385c1d2f"}},"solidity/FastBridgeV2.sol:IZapRecipient":{"code":"0x","runtime-code":"0x","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.24 ^0.8.20 ^0.8.4;\n\n// contracts/interfaces/IAdminV2.sol\n\ninterface IAdminV2 {\n event CancelDelayUpdated(uint256 oldCancelDelay, uint256 newCancelDelay);\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n function setCancelDelay(uint256 newCancelDelay) external;\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n}\n\n// contracts/interfaces/IAdminV2Errors.sol\n\ninterface IAdminV2Errors {\n error CancelDelayBelowMin();\n error FeeRateAboveMax();\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IFastBridgeV2Errors.sol\n\ninterface IFastBridgeV2Errors {\n error AmountIncorrect();\n error ChainIncorrect();\n error ExclusivityParamsIncorrect();\n error MsgValueIncorrect();\n error SenderIncorrect();\n error StatusIncorrect();\n error TokenNotContract();\n error ZapDataLengthAboveMax();\n error ZapNativeNotSupported();\n error ZeroAddress();\n\n error RecipientIncorrectReturnValue();\n error RecipientNoReturnValue();\n\n error DeadlineExceeded();\n error DeadlineNotExceeded();\n error DeadlineTooShort();\n error DisputePeriodNotPassed();\n error DisputePeriodPassed();\n error ExclusivityPeriodNotPassed();\n\n error TransactionRelayed();\n}\n\n// contracts/interfaces/IMulticallTarget.sol\n\n/// @notice Interface for a contract that can be called multiple times by the same caller. Inspired by MulticallV3:\n/// https://github.com/mds1/multicall/blob/master/src/Multicall3.sol\ninterface IMulticallTarget {\n struct Result {\n bool success;\n bytes returnData;\n }\n\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external;\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results);\n}\n\n// contracts/interfaces/IZapRecipient.sol\n\ninterface IZapRecipient {\n function zap(address token, uint256 amount, bytes memory zapData) external payable returns (bytes4);\n}\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// contracts/interfaces/IFastBridgeV2.sol\n\ninterface IFastBridgeV2 is IFastBridge {\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n struct BridgeTxDetails {\n BridgeStatus status;\n uint32 destChainId;\n uint56 proofBlockTimestamp;\n address proofRelayer;\n }\n\n struct BridgeRelay {\n uint48 blockNumber;\n uint48 blockTimestamp;\n address relayer;\n }\n\n /// @notice New params introduced in the FastBridgeV2.\n /// We are passing fields from the older BridgeParams struct outside of this struct\n /// for backwards compatibility.\n /// Note: quoteRelayer and quoteExclusivitySeconds are either both zero (indicating no exclusivity)\n /// or both non-zero (indicating exclusivity for the given period).\n /// Note: zapNative \u003e 0 can NOT be used with destToken = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE (native token)\n /// @param quoteRelayer Relayer that provided the quote for the transaction\n /// @param quoteExclusivitySeconds Period of time the quote relayer is guaranteed exclusivity after user's deposit\n /// @param quoteId Unique quote identifier used for tracking the quote\n /// @param zapNative ETH value to send to the recipient (if any)\n /// @param zapData Parameters for the Zap to the destination recipient (if any)\n struct BridgeParamsV2 {\n address quoteRelayer;\n int256 quoteExclusivitySeconds;\n bytes quoteId;\n uint256 zapNative;\n bytes zapData;\n }\n\n /// @notice Updated bridge transaction struct to include parameters introduced in FastBridgeV2.\n /// Note: only `exclusivityRelayer` can fill such a transaction until `exclusivityEndTime`.\n struct BridgeTransactionV2 {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n // Note: sendChainGas flag from V1 is deprecated\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n address exclusivityRelayer;\n uint256 exclusivityEndTime;\n uint256 zapNative; // ETH value to send to the recipient (if any)\n bytes zapData; // data to pass for the Zap action (if any)\n }\n\n event BridgeQuoteDetails(bytes32 indexed transactionId, bytes quoteId);\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability\n /// to provide temporary exclusivity fill rights for the quote relayer.\n /// @param params The parameters required to bridge\n /// @param paramsV2 The parameters for exclusivity fill rights (optional, can be left empty)\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function relay(bytes memory request, address relayer) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param transactionId The transaction id associated with the encoded bridge transaction to prove\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital.\n /// @notice Can only send funds to the relayer address on the proof.\n /// @param request The encoded bridge transaction to claim on origin chain\n function claim(bytes memory request) external;\n\n /// @notice Cancels an outstanding bridge transaction in case optimistic bridging failed and returns the full amount\n /// to the original sender.\n /// @param request The encoded bridge transaction to refund\n function cancel(bytes memory request) external;\n\n /// @notice Checks if a transaction has been relayed\n /// @param transactionId The ID of the transaction to check\n /// @return True if the transaction has been relayed, false otherwise\n function bridgeRelays(bytes32 transactionId) external view returns (bool);\n\n /// @notice Returns the status of a bridge transaction\n /// @param transactionId The ID of the bridge transaction\n /// @return BridgeStatus Status of the bridge transaction\n function bridgeStatuses(bytes32 transactionId) external view returns (BridgeStatus);\n\n /// @notice Returns the timestamp and relayer of a bridge proof\n /// @param transactionId The ID of the bridge transaction\n /// @return timestamp The timestamp of the bridge proof\n /// @return relayer The relayer address of the bridge proof\n function bridgeProofs(bytes32 transactionId) external view returns (uint96 timestamp, address relayer);\n\n /// @notice Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\n /// @param request The bridge request to decode\n function getBridgeTransactionV2(bytes memory request) external view returns (BridgeTransactionV2 memory);\n}\n\n// contracts/utils/MulticallTarget.sol\n\n// solhint-disable avoid-low-level-calls\n/// @notice Template for a contract that supports batched calls (preserving the msg.sender).\n/// Only calls with zero msg.value could be batched.\nabstract contract MulticallTarget is IMulticallTarget {\n error MulticallTarget__UndeterminedRevert();\n\n /// @notice Perform a batched call to this contract, preserving the msg.sender.\n /// The return data from each call is discarded.\n /// @dev The method is non-payable, so only calls with `msg.value == 0` could be batched.\n /// It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag.\n /// Otherwise, the whole batch call will be reverted with the original revert reason.\n /// @param data List of abi-encoded calldata for the calls to perform.\n /// @param ignoreReverts Whether to ignore the revert errors from the calls.\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external {\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\n if (!success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(result);\n }\n }\n }\n\n /// @notice Perform a batched call to this contract, preserving the msg.sender.\n /// The return data from each call is preserved.\n /// @dev The method is non-payable, so only calls with `msg.value == 0` could be batched.\n /// It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag.\n /// Otherwise, the whole batch call will be reverted with the original revert reason.\n /// @param data List of abi-encoded calldata for the calls to perform.\n /// @param ignoreReverts Whether to ignore the revert errors from the calls.\n /// @return results List of results from the calls: `(success, returnData)`.\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results)\n {\n results = new Result[](data.length);\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (results[i].success, results[i].returnData) = address(this).delegatecall(data[i]);\n if (!results[i].success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(results[i].returnData);\n }\n }\n }\n\n /// @dev Bubbles the revert message from the underlying call.\n /// Note: preserves the same custom error or revert string, if one was used.\n /// Source: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v5.0.2/contracts/utils/Address.sol#L143-L158\n function _bubbleRevert(bytes memory returnData) internal pure {\n // Look for revert reason and bubble it up if present\n if (returnData.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n // solhint-disable-next-line no-inline-assembly\n assembly {\n let returndata_size := mload(returnData)\n revert(add(32, returnData), returndata_size)\n }\n } else {\n revert MulticallTarget__UndeterminedRevert();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// contracts/libs/BridgeTransactionV2.sol\n\n// solhint-disable no-inline-assembly\nlibrary BridgeTransactionV2Lib {\n uint16 internal constant VERSION = 2;\n\n // Offsets of the fields in the packed BridgeTransactionV2 struct\n // uint16 version [000 .. 002)\n // uint32 originChainId [002 .. 006)\n // uint32 destChainId [006 .. 010)\n // address originSender [010 .. 030)\n // address destRecipient [030 .. 050)\n // address originToken [050 .. 070)\n // address destToken [070 .. 090)\n // uint256 originAmount [090 .. 122)\n // uint256 destAmount [122 .. 154)\n // uint256 originFeeAmount [154 .. 186)\n // uint256 deadline [186 .. 218)\n // uint256 nonce [218 .. 250)\n // address exclusivityRelayer [250 .. 270)\n // uint256 exclusivityEndTime [270 .. 302)\n // uint256 zapNative [302 .. 334)\n // bytes zapData [334 .. ***)\n\n // forgefmt: disable-start\n uint256 private constant OFFSET_ORIGIN_CHAIN_ID = 2;\n uint256 private constant OFFSET_DEST_CHAIN_ID = 6;\n uint256 private constant OFFSET_ORIGIN_SENDER = 10;\n uint256 private constant OFFSET_DEST_RECIPIENT = 30;\n uint256 private constant OFFSET_ORIGIN_TOKEN = 50;\n uint256 private constant OFFSET_DEST_TOKEN = 70;\n uint256 private constant OFFSET_ORIGIN_AMOUNT = 90;\n uint256 private constant OFFSET_DEST_AMOUNT = 122;\n uint256 private constant OFFSET_ORIGIN_FEE_AMOUNT = 154;\n uint256 private constant OFFSET_DEADLINE = 186;\n uint256 private constant OFFSET_NONCE = 218;\n uint256 private constant OFFSET_EXCLUSIVITY_RELAYER = 250;\n uint256 private constant OFFSET_EXCLUSIVITY_END_TIME = 270;\n uint256 private constant OFFSET_ZAP_NATIVE = 302;\n uint256 private constant OFFSET_ZAP_DATA = 334;\n // forgefmt: disable-end\n\n error BridgeTransactionV2__InvalidEncodedTx();\n error BridgeTransactionV2__UnsupportedVersion(uint16 version);\n\n /// @notice Validates the encoded transaction to be a tightly packed encoded payload for BridgeTransactionV2.\n /// @dev Checks the minimum length and the version, use this function before decoding any of the fields.\n function validateV2(bytes calldata encodedTx) internal pure {\n // Check the minimum length: must at least include all static fields.\n if (encodedTx.length \u003c OFFSET_ZAP_DATA) revert BridgeTransactionV2__InvalidEncodedTx();\n // Once we validated the length, we can be sure that the version field is present.\n uint16 version_ = version(encodedTx);\n if (version_ != VERSION) revert BridgeTransactionV2__UnsupportedVersion(version_);\n }\n\n /// @notice Encodes the BridgeTransactionV2 struct by tightly packing the fields.\n /// @dev `abi.decode` will not work as a result of the tightly packed fields. Use `decodeV2` to decode instead.\n function encodeV2(IFastBridgeV2.BridgeTransactionV2 memory bridgeTx) internal pure returns (bytes memory) {\n // We split the encoding into two parts to avoid stack-too-deep error\n bytes memory firstPart = abi.encodePacked(\n VERSION,\n bridgeTx.originChainId,\n bridgeTx.destChainId,\n bridgeTx.originSender,\n bridgeTx.destRecipient,\n bridgeTx.originToken,\n bridgeTx.destToken,\n bridgeTx.originAmount\n );\n return abi.encodePacked(\n firstPart,\n bridgeTx.destAmount,\n bridgeTx.originFeeAmount,\n // Note: we skip the deprecated `sendChainGas` flag, which was present in BridgeTransaction V1\n bridgeTx.deadline,\n bridgeTx.nonce,\n // New V2 fields: exclusivity\n bridgeTx.exclusivityRelayer,\n bridgeTx.exclusivityEndTime,\n // New V2 fields: Zap\n bridgeTx.zapNative,\n bridgeTx.zapData\n );\n }\n\n /// @notice Decodes the BridgeTransactionV2 struct from the encoded transaction.\n /// @dev Encoded BridgeTransactionV2 struct must be tightly packed.\n /// Use `validateV2` before decoding to ensure the encoded transaction is valid.\n function decodeV2(bytes calldata encodedTx)\n internal\n pure\n returns (IFastBridgeV2.BridgeTransactionV2 memory bridgeTx)\n {\n bridgeTx.originChainId = originChainId(encodedTx);\n bridgeTx.destChainId = destChainId(encodedTx);\n bridgeTx.originSender = originSender(encodedTx);\n bridgeTx.destRecipient = destRecipient(encodedTx);\n bridgeTx.originToken = originToken(encodedTx);\n bridgeTx.destToken = destToken(encodedTx);\n bridgeTx.originAmount = originAmount(encodedTx);\n bridgeTx.destAmount = destAmount(encodedTx);\n bridgeTx.originFeeAmount = originFeeAmount(encodedTx);\n bridgeTx.deadline = deadline(encodedTx);\n bridgeTx.nonce = nonce(encodedTx);\n bridgeTx.exclusivityRelayer = exclusivityRelayer(encodedTx);\n bridgeTx.exclusivityEndTime = exclusivityEndTime(encodedTx);\n bridgeTx.zapNative = zapNative(encodedTx);\n bridgeTx.zapData = zapData(encodedTx);\n }\n\n /// @notice Extracts the version from the encoded transaction.\n function version(bytes calldata encodedTx) internal pure returns (uint16 version_) {\n // Load 32 bytes from the start and shift it 240 bits to the right to get the highest 16 bits.\n assembly {\n version_ := shr(240, calldataload(encodedTx.offset))\n }\n }\n\n /// @notice Extracts the origin chain ID from the encoded transaction.\n function originChainId(bytes calldata encodedTx) internal pure returns (uint32 originChainId_) {\n // Load 32 bytes from the offset and shift it 224 bits to the right to get the highest 32 bits.\n assembly {\n originChainId_ := shr(224, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_CHAIN_ID)))\n }\n }\n\n /// @notice Extracts the destination chain ID from the encoded transaction.\n function destChainId(bytes calldata encodedTx) internal pure returns (uint32 destChainId_) {\n // Load 32 bytes from the offset and shift it 224 bits to the right to get the highest 32 bits.\n assembly {\n destChainId_ := shr(224, calldataload(add(encodedTx.offset, OFFSET_DEST_CHAIN_ID)))\n }\n }\n\n /// @notice Extracts the origin sender from the encoded transaction.\n function originSender(bytes calldata encodedTx) internal pure returns (address originSender_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n originSender_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_SENDER)))\n }\n }\n\n /// @notice Extracts the destination recipient from the encoded transaction.\n function destRecipient(bytes calldata encodedTx) internal pure returns (address destRecipient_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n destRecipient_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_DEST_RECIPIENT)))\n }\n }\n\n /// @notice Extracts the origin token from the encoded transaction.\n function originToken(bytes calldata encodedTx) internal pure returns (address originToken_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n originToken_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_TOKEN)))\n }\n }\n\n /// @notice Extracts the destination token from the encoded transaction.\n function destToken(bytes calldata encodedTx) internal pure returns (address destToken_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n destToken_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_DEST_TOKEN)))\n }\n }\n\n /// @notice Extracts the origin amount from the encoded transaction.\n function originAmount(bytes calldata encodedTx) internal pure returns (uint256 originAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n originAmount_ := calldataload(add(encodedTx.offset, OFFSET_ORIGIN_AMOUNT))\n }\n }\n\n /// @notice Extracts the destination amount from the encoded transaction.\n function destAmount(bytes calldata encodedTx) internal pure returns (uint256 destAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n destAmount_ := calldataload(add(encodedTx.offset, OFFSET_DEST_AMOUNT))\n }\n }\n\n /// @notice Extracts the origin fee amount from the encoded transaction.\n function originFeeAmount(bytes calldata encodedTx) internal pure returns (uint256 originFeeAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n originFeeAmount_ := calldataload(add(encodedTx.offset, OFFSET_ORIGIN_FEE_AMOUNT))\n }\n }\n\n /// @notice Extracts the deadline from the encoded transaction.\n function deadline(bytes calldata encodedTx) internal pure returns (uint256 deadline_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n deadline_ := calldataload(add(encodedTx.offset, OFFSET_DEADLINE))\n }\n }\n\n /// @notice Extracts the nonce from the encoded transaction.\n function nonce(bytes calldata encodedTx) internal pure returns (uint256 nonce_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n nonce_ := calldataload(add(encodedTx.offset, OFFSET_NONCE))\n }\n }\n\n /// @notice Extracts the exclusivity relayer from the encoded transaction.\n function exclusivityRelayer(bytes calldata encodedTx) internal pure returns (address exclusivityRelayer_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n exclusivityRelayer_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_EXCLUSIVITY_RELAYER)))\n }\n }\n\n /// @notice Extracts the exclusivity end time from the encoded transaction.\n function exclusivityEndTime(bytes calldata encodedTx) internal pure returns (uint256 exclusivityEndTime_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n exclusivityEndTime_ := calldataload(add(encodedTx.offset, OFFSET_EXCLUSIVITY_END_TIME))\n }\n }\n\n /// @notice Extracts the Zap's native value from the encoded transaction.\n function zapNative(bytes calldata encodedTx) internal pure returns (uint256 zapNative_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n zapNative_ := calldataload(add(encodedTx.offset, OFFSET_ZAP_NATIVE))\n }\n }\n\n /// @notice Extracts the Zap's data from the encoded transaction.\n function zapData(bytes calldata encodedTx) internal pure returns (bytes calldata zapData_) {\n zapData_ = encodedTx[OFFSET_ZAP_DATA:];\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/AdminV2.sol\n\ncontract AdminV2 is AccessControlEnumerable, IAdminV2, IAdminV2Errors {\n using SafeERC20 for IERC20;\n\n /// @notice Address reserved for native gas token (ETH on Ethereum and most L2s, AVAX on Avalanche, etc)\n address public constant NATIVE_GAS_TOKEN = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Role identifier for Quoter API's off-chain authentication.\n /// @dev Only addresses with this role can post FastBridge quotes to the API.\n bytes32 public constant QUOTER_ROLE = keccak256(\"QUOTER_ROLE\");\n\n /// @notice Role identifier for Prover's on-chain authentication in FastBridge.\n /// @dev Only addresses with this role can provide proofs that a FastBridge request has been relayed.\n bytes32 public constant PROVER_ROLE = keccak256(\"PROVER_ROLE\");\n\n /// @notice Role identifier for Guard's on-chain authentication in FastBridge.\n /// @dev Only addresses with this role can dispute submitted relay proofs during the dispute period.\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n\n /// @notice Role identifier for Canceler's on-chain authentication in FastBridge.\n /// @dev Only addresses with this role can cancel a FastBridge transaction without the cancel delay.\n bytes32 public constant CANCELER_ROLE = keccak256(\"CANCELER_ROLE\");\n\n /// @notice Role identifier for Governor's on-chain administrative authority.\n /// @dev Only addresses with this role can perform administrative tasks within the contract.\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n /// @notice Denominator for fee rates, represents 100%.\n uint256 public constant FEE_BPS = 1e6;\n /// @notice Maximum protocol fee rate: 1% on origin amount.\n uint256 public constant FEE_RATE_MAX = 0.01e6;\n\n /// @notice Minimum cancel delay that can be set by the governor.\n uint256 public constant MIN_CANCEL_DELAY = 1 hours;\n /// @notice Default cancel delay set during the contract deployment.\n uint256 public constant DEFAULT_CANCEL_DELAY = 1 days;\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Delay for a transaction after which it could be permisionlessly cancelled\n uint256 public cancelDelay;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Use ZapNative V2 requests instead.\n uint256 public immutable chainGasAmount = 0;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n _setCancelDelay(DEFAULT_CANCEL_DELAY);\n }\n\n /// @notice Allows the contract governor to set the cancel delay. The cancel delay is the time after the transaction\n /// deadline after which it can be permissionlessly cancelled, if it hasn't been proven by any of the Relayers.\n function setCancelDelay(uint256 newCancelDelay) external onlyRole(GOVERNOR_ROLE) {\n _setCancelDelay(newCancelDelay);\n }\n\n /// @notice Allows the contract governor to set the protocol fee rate. The protocol fee is taken from the origin\n /// amount only for completed and claimed transactions.\n /// @dev The protocol fee is abstracted away from the relayers, they always operate using the amounts after fees:\n /// what they see as the origin amount emitted in the log is what they get credited with.\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n if (newFeeRate \u003e FEE_RATE_MAX) revert FeeRateAboveMax();\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n /// @notice Allows the contract governor to sweep the accumulated protocol fees in the contract.\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n emit FeesSwept(token, recipient, feeAmount);\n /// Sweep the fees as the last transaction action\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(recipient), feeAmount);\n } else {\n IERC20(token).safeTransfer(recipient, feeAmount);\n }\n }\n\n /// @notice Internal function to set the cancel delay. Security checks are performed outside of this function.\n function _setCancelDelay(uint256 newCancelDelay) private {\n if (newCancelDelay \u003c MIN_CANCEL_DELAY) revert CancelDelayBelowMin();\n uint256 oldCancelDelay = cancelDelay;\n cancelDelay = newCancelDelay;\n emit CancelDelayUpdated(oldCancelDelay, newCancelDelay);\n }\n}\n\n// contracts/FastBridgeV2.sol\n\n/// @notice FastBridgeV2 is a contract for bridging tokens across chains.\ncontract FastBridgeV2 is AdminV2, MulticallTarget, IFastBridgeV2, IFastBridgeV2Errors {\n using BridgeTransactionV2Lib for bytes;\n using SafeERC20 for IERC20;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n /// @notice Maximum length of accepted zapData\n uint256 public constant MAX_ZAP_DATA_LENGTH = 2 ** 16 - 1;\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeTxDetails) public bridgeTxDetails;\n /// @notice Relay details on destination chain\n mapping(bytes32 =\u003e BridgeRelay) public bridgeRelayDetails;\n /// @notice Unique bridge nonces tracked per originSender\n mapping(address =\u003e uint256) public senderNonces;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Replaced by senderNonces\n uint256 public immutable nonce = 0;\n /// @notice the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) AdminV2(_owner) {\n deployBlock = block.number;\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n bridge({\n params: params,\n paramsV2: BridgeParamsV2({\n quoteRelayer: address(0),\n quoteExclusivitySeconds: 0,\n quoteId: bytes(\"\"),\n zapNative: 0,\n zapData: bytes(\"\")\n })\n });\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes calldata request) external payable {\n // relay override will validate the request\n relay({request: request, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes calldata request, bytes32 destTxHash) external {\n request.validateV2();\n prove({transactionId: keccak256(request), destTxHash: destTxHash, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridgeV2\n function claim(bytes calldata request) external {\n // claim override will validate the request\n claim({request: request, to: address(0)});\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Aggregate the read operations from the same storage slot\n address disputedRelayer = $.proofRelayer;\n BridgeStatus status = $.status;\n uint56 proofBlockTimestamp = $.proofBlockTimestamp;\n // Can only dispute a RELAYER_PROVED transaction within the dispute period\n if (status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(proofBlockTimestamp) \u003e DISPUTE_PERIOD) {\n revert DisputePeriodPassed();\n }\n // Update status to REQUESTED and delete the disputed proof details\n // Note: these are storage writes\n $.status = BridgeStatus.REQUESTED;\n $.proofRelayer = address(0);\n $.proofBlockTimestamp = 0;\n\n emit BridgeProofDisputed(transactionId, disputedRelayer);\n }\n\n /// Note: this function is deprecated and will be removed in a future version.\n /// @inheritdoc IFastBridge\n function refund(bytes calldata request) external {\n cancel(request);\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // The correct relayer can only claim a RELAYER_PROVED transaction after the dispute period\n if ($.status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if ($.proofRelayer != relayer) revert SenderIncorrect();\n return _timeSince($.proofBlockTimestamp) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n /// @dev This method is added to achieve backwards compatibility with decoding requests into V1 structs:\n /// - `zapNative` is partially reported as a zero/non-zero flag\n /// - `zapData` is ignored\n /// In order to process all kinds of requests use getBridgeTransactionV2 instead.\n function getBridgeTransaction(bytes calldata request) external view returns (BridgeTransaction memory) {\n // Try decoding into V2 struct first. This will revert if V1 struct is passed\n try this.getBridgeTransactionV2(request) returns (BridgeTransactionV2 memory txV2) {\n // Note: we entirely ignore the zapData field, as it was not present in V1\n return BridgeTransaction({\n originChainId: txV2.originChainId,\n destChainId: txV2.destChainId,\n originSender: txV2.originSender,\n destRecipient: txV2.destRecipient,\n originToken: txV2.originToken,\n destToken: txV2.destToken,\n originAmount: txV2.originAmount,\n destAmount: txV2.destAmount,\n originFeeAmount: txV2.originFeeAmount,\n sendChainGas: txV2.zapNative != 0,\n deadline: txV2.deadline,\n nonce: txV2.nonce\n });\n } catch {\n // Fallback to V1 struct\n return abi.decode(request, (BridgeTransaction));\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function getBridgeTransactionV2(bytes calldata request) external pure returns (BridgeTransactionV2 memory) {\n request.validateV2();\n return BridgeTransactionV2Lib.decodeV2(request);\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) public payable {\n int256 exclusivityEndTime = 0;\n // if relayer exclusivity is not intended for this bridge, set exclusivityEndTime to static zero\n // otherwise, set exclusivity to expire at the current block ts offset by quoteExclusivitySeconds\n if (paramsV2.quoteRelayer != address(0)) {\n exclusivityEndTime = int256(block.timestamp) + paramsV2.quoteExclusivitySeconds;\n }\n _validateBridgeParams(params, paramsV2, exclusivityEndTime);\n\n // transfer tokens to bridge contract\n /// @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _takeBridgedUserAsset(params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) {\n originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n }\n\n // set status to requested\n bytes memory request = BridgeTransactionV2Lib.encodeV2(\n BridgeTransactionV2({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n deadline: params.deadline,\n nonce: senderNonces[params.sender]++, // increment nonce on every bridge\n exclusivityRelayer: paramsV2.quoteRelayer,\n // We checked exclusivityEndTime to be in range [0 .. params.deadline] above, so can safely cast\n exclusivityEndTime: uint256(exclusivityEndTime),\n zapNative: paramsV2.zapNative,\n zapData: paramsV2.zapData\n })\n );\n bytes32 transactionId = keccak256(request);\n // Note: the tx status will be updated throughout the tx lifecycle, while destChainId is set once here\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n bridgeTxDetails[transactionId].destChainId = params.dstChainId;\n\n emit BridgeRequested({\n transactionId: transactionId,\n sender: params.sender,\n request: request,\n destChainId: params.dstChainId,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n sendChainGas: paramsV2.zapNative != 0\n });\n emit BridgeQuoteDetails(transactionId, paramsV2.quoteId);\n }\n\n /// @inheritdoc IFastBridgeV2\n function relay(bytes calldata request, address relayer) public payable {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n _validateRelayParams(request, transactionId, relayer);\n // mark bridge transaction as relayed\n bridgeRelayDetails[transactionId] =\n BridgeRelay({blockNumber: uint48(block.number), blockTimestamp: uint48(block.timestamp), relayer: relayer});\n\n // transfer tokens to recipient on destination chain and trigger Zap if requested\n address to = request.destRecipient();\n address token = request.destToken();\n uint256 amount = request.destAmount();\n uint256 zapNative = request.zapNative();\n\n // Emit the event before any external calls\n emit BridgeRelayed({\n transactionId: transactionId,\n relayer: relayer,\n to: to,\n originChainId: request.originChainId(),\n originToken: request.originToken(),\n destToken: token,\n originAmount: request.originAmount(),\n destAmount: amount,\n chainGasAmount: zapNative\n });\n\n // All state changes have been done at this point, can proceed to the external calls.\n // This follows the checks-effects-interactions pattern to mitigate potential reentrancy attacks.\n if (token == NATIVE_GAS_TOKEN) {\n // For the native gas token, additional zapNative is not allowed\n if (zapNative != 0) revert ZapNativeNotSupported();\n // Check that the correct msg.value was sent\n if (msg.value != amount) revert MsgValueIncorrect();\n // Don't do a native transfer yet: we will handle it alongside the Zap below\n } else {\n // For ERC20s, we check that the correct msg.value was sent\n if (msg.value != zapNative) revert MsgValueIncorrect();\n // We need to transfer the tokens from the Relayer to the recipient first before performing an\n // optional post-transfer Zap.\n IERC20(token).safeTransferFrom(msg.sender, to, amount);\n }\n // At this point we have done:\n // - Transferred the requested amount of ERC20 tokens to the recipient.\n // At this point we have confirmed:\n // - For ERC20s: msg.value matches the requested zapNative amount.\n // - For the native gas token: msg.value matches the requested destAmount.\n // Remaining optional things to do:\n // - Forward the full msg.value to the recipient (if non-zero).\n // - Trigger a Zap (if zapData is present).\n bytes calldata zapData = request.zapData();\n if (zapData.length != 0) {\n // Zap Data is present: Zap has been requested by the recipient. Trigger it forwarding the full msg.value.\n\n // Note: if token has a fee on transfers, the recipient will have received less than `amount`.\n // This is a very niche edge case and should be handled by the recipient contract.\n _triggerZapWithChecks({recipient: to, token: token, amount: amount, zapData: zapData});\n } else if (msg.value != 0) {\n // Zap Data is missing, but msg.value was sent. This could happen in two different cases:\n // - Relay with the native gas token is happening.\n // - Relay with ERC20 is happening, with a `zapNative \u003e 0` request.\n // In both cases, we need to transfer the full msg.value to the recipient.\n Address.sendValue(payable(to), msg.value);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) public onlyRole(PROVER_ROLE) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n\n // Can only prove a REQUESTED transaction\n if ($.status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n // Update status to RELAYER_PROVED and store the proof details\n // Note: these are storage writes\n $.status = BridgeStatus.RELAYER_PROVED;\n $.proofBlockTimestamp = uint56(block.timestamp);\n $.proofRelayer = relayer;\n\n emit BridgeProofProvided(transactionId, relayer, destTxHash);\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes calldata request, address to) public {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Aggregate the read operations from the same storage slot\n address proofRelayer = $.proofRelayer;\n BridgeStatus status = $.status;\n uint56 proofBlockTimestamp = $.proofBlockTimestamp;\n\n // Can only claim a RELAYER_PROVED transaction after the dispute period\n if (status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(proofBlockTimestamp) \u003c= DISPUTE_PERIOD) {\n revert DisputePeriodNotPassed();\n }\n\n if (to == address(0)) {\n // Anyone could claim the funds to the proven relayer on their behalf\n to = proofRelayer;\n } else if (proofRelayer != msg.sender) {\n // Only the proven relayer could specify an address to claim the funds to\n revert SenderIncorrect();\n }\n\n // Update status to RELAYER_CLAIMED and transfer the origin collateral to the specified claim address\n // Note: this is a storage write\n $.status = BridgeStatus.RELAYER_CLAIMED;\n\n address token = request.originToken();\n uint256 amount = request.originAmount();\n // Update protocol fees if origin fee amount exists\n uint256 originFeeAmount = request.originFeeAmount();\n if (originFeeAmount \u003e 0) protocolFees[token] += originFeeAmount;\n // Emit the event before any external calls\n emit BridgeDepositClaimed(transactionId, proofRelayer, to, token, amount);\n // Complete the relayer claim as the last transaction action\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(to), amount);\n } else {\n IERC20(token).safeTransfer(to, amount);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function cancel(bytes calldata request) public {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Can only cancel a REQUESTED transaction after its deadline expires\n if ($.status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n uint256 deadline = request.deadline();\n // Permissionless cancel is only allowed after `cancelDelay` on top of the deadline\n if (!hasRole(CANCELER_ROLE, msg.sender)) deadline += cancelDelay;\n if (block.timestamp \u003c= deadline) revert DeadlineNotExceeded();\n // Update status to REFUNDED and return the full amount (collateral + protocol fees) to the original sender.\n // The protocol fees are only updated when the transaction is claimed, so we don't need to update them here.\n // Note: this is a storage write\n $.status = BridgeStatus.REFUNDED;\n\n address to = request.originSender();\n address token = request.originToken();\n uint256 amount = request.originAmount() + request.originFeeAmount();\n // Emit the event before any external calls\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n // Complete the user cancel as the last transaction action\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(to), amount);\n } else {\n IERC20(token).safeTransfer(to, amount);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeStatuses(bytes32 transactionId) public view returns (BridgeStatus status) {\n return bridgeTxDetails[transactionId].status;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeProofs(bytes32 transactionId) public view returns (uint96 timestamp, address relayer) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n\n timestamp = $.proofBlockTimestamp;\n relayer = $.proofRelayer;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeRelays(bytes32 transactionId) public view returns (bool) {\n // has this transactionId been relayed?\n return bridgeRelayDetails[transactionId].relayer != address(0);\n }\n\n /// @notice Takes the bridged asset from the user into FastBridgeV2 custody. It will be later\n /// claimed by the relayer who completed the relay on destination chain, or transferred back to the user\n /// via the cancel function should no one complete the relay.\n function _takeBridgedUserAsset(address token, uint256 amount) internal returns (uint256 amountTaken) {\n if (token == NATIVE_GAS_TOKEN) {\n // For the native gas token, we just need to check that the supplied msg.value is correct.\n // Supplied `msg.value` is already in FastBridgeV2 custody.\n if (amount != msg.value) revert MsgValueIncorrect();\n amountTaken = msg.value;\n } else {\n // For ERC20s, token is explicitly transferred from the user to FastBridgeV2.\n // We don't allow non-zero `msg.value` to avoid extra funds from being stuck in FastBridgeV2.\n if (msg.value != 0) revert MsgValueIncorrect();\n // Throw an explicit error if the provided token address is not a contract\n if (token.code.length == 0) revert TokenNotContract();\n amountTaken = IERC20(token).balanceOf(address(this));\n IERC20(token).safeTransferFrom(msg.sender, address(this), amount);\n // Use the balance difference as the amount taken in case of fee on transfer tokens.\n amountTaken = IERC20(token).balanceOf(address(this)) - amountTaken;\n }\n }\n\n /// @notice Calls the Recipient's hook function with the specified zapData and performs\n /// all the necessary checks for the returned value.\n function _triggerZapWithChecks(address recipient, address token, uint256 amount, bytes calldata zapData) internal {\n // This will bubble any revert messages from the hook function\n bytes memory returnData = Address.functionCallWithValue({\n target: recipient,\n data: abi.encodeCall(IZapRecipient.zap, (token, amount, zapData)),\n // Note: see `relay()` for reasoning behind passing msg.value\n value: msg.value\n });\n // Explicit revert if no return data at all\n if (returnData.length == 0) revert RecipientNoReturnValue();\n // Check that exactly a single return value was returned\n if (returnData.length != 32) revert RecipientIncorrectReturnValue();\n // Return value should be abi-encoded hook function selector\n if (bytes32(returnData) != bytes32(IZapRecipient.zap.selector)) {\n revert RecipientIncorrectReturnValue();\n }\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint56(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint56).max but\n /// proof.timestamp \u003c type(uint56).max via unchecked statement\n /// @param proofBlockTimestamp The bridge proof block timestamp\n /// @return delta Time delta since proof submitted\n function _timeSince(uint56 proofBlockTimestamp) internal view returns (uint256 delta) {\n unchecked {\n delta = uint56(block.timestamp) - proofBlockTimestamp;\n }\n }\n\n /// @notice Performs all the necessary checks for a bridge to happen.\n /// @dev There's no good way to refactor this function to reduce cyclomatic complexity due to\n /// the number of checks that need to be performed, so we skip the code-complexity rule here.\n // solhint-disable-next-line code-complexity\n function _validateBridgeParams(\n BridgeParams memory params,\n BridgeParamsV2 memory paramsV2,\n int256 exclusivityEndTime\n )\n internal\n view\n {\n // Check V1 (legacy) params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.sender == address(0) || params.to == address(0)) revert ZeroAddress();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n // Check V2 params\n if (paramsV2.zapData.length \u003e MAX_ZAP_DATA_LENGTH) revert ZapDataLengthAboveMax();\n if (paramsV2.zapNative != 0 \u0026\u0026 params.destToken == NATIVE_GAS_TOKEN) {\n revert ZapNativeNotSupported();\n }\n // exclusivityEndTime must be in range [0 .. params.deadline]\n if (exclusivityEndTime \u003c 0 || exclusivityEndTime \u003e int256(params.deadline)) {\n revert ExclusivityParamsIncorrect();\n }\n }\n\n /// @notice Performs all the necessary checks for a relay to happen.\n function _validateRelayParams(bytes calldata request, bytes32 transactionId, address relayer) internal view {\n if (relayer == address(0)) revert ZeroAddress();\n // Check if the transaction has already been relayed\n if (bridgeRelays(transactionId)) revert TransactionRelayed();\n if (request.destChainId() != block.chainid) revert ChainIncorrect();\n // Check the deadline for relay to happen\n if (block.timestamp \u003e request.deadline()) revert DeadlineExceeded();\n // Check the exclusivity period, if it is still ongoing\n address exclRelayer = request.exclusivityRelayer();\n if (exclRelayer != address(0) \u0026\u0026 exclRelayer != relayer \u0026\u0026 block.timestamp \u003c= request.exclusivityEndTime()) {\n revert ExclusivityPeriodNotPassed();\n }\n }\n}\n","language":"Solidity","languageVersion":"0.8.24","compilerVersion":"0.8.24","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"","srcMapRuntime":"","abiDefinition":[{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"bytes","name":"zapData","type":"bytes"}],"name":"zap","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"payable","type":"function"}],"userDoc":{"kind":"user","methods":{},"version":1},"developerDoc":{"kind":"dev","methods":{},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"zapData\",\"type\":\"bytes\"}],\"name\":\"zap\",\"outputs\":[{\"internalType\":\"bytes4\",\"name\":\"\",\"type\":\"bytes4\"}],\"stateMutability\":\"payable\",\"type\":\"function\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeV2.sol\":\"IZapRecipient\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeV2.sol\":{\"keccak256\":\"0xac79c463688a682ca706a4ef95e7817b83548cdfa8182ba0426ac7e5e07613d8\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://b3ecb7097381287cafc3a73f3a2bb03565115ebb682a85064e0b0dc2f7e2919d\",\"dweb:/ipfs/QmatruW3nYZTksf3CeQ8wwiAG4c7xoEJBEp6drHPtFLBRK\"]}},\"version\":1}"},"hashes":{"zap(address,uint256,bytes)":"e85e13dd"}},"solidity/FastBridgeV2.sol:MulticallTarget":{"code":"0x","runtime-code":"0x","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.24 ^0.8.20 ^0.8.4;\n\n// contracts/interfaces/IAdminV2.sol\n\ninterface IAdminV2 {\n event CancelDelayUpdated(uint256 oldCancelDelay, uint256 newCancelDelay);\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n function setCancelDelay(uint256 newCancelDelay) external;\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n}\n\n// contracts/interfaces/IAdminV2Errors.sol\n\ninterface IAdminV2Errors {\n error CancelDelayBelowMin();\n error FeeRateAboveMax();\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IFastBridgeV2Errors.sol\n\ninterface IFastBridgeV2Errors {\n error AmountIncorrect();\n error ChainIncorrect();\n error ExclusivityParamsIncorrect();\n error MsgValueIncorrect();\n error SenderIncorrect();\n error StatusIncorrect();\n error TokenNotContract();\n error ZapDataLengthAboveMax();\n error ZapNativeNotSupported();\n error ZeroAddress();\n\n error RecipientIncorrectReturnValue();\n error RecipientNoReturnValue();\n\n error DeadlineExceeded();\n error DeadlineNotExceeded();\n error DeadlineTooShort();\n error DisputePeriodNotPassed();\n error DisputePeriodPassed();\n error ExclusivityPeriodNotPassed();\n\n error TransactionRelayed();\n}\n\n// contracts/interfaces/IMulticallTarget.sol\n\n/// @notice Interface for a contract that can be called multiple times by the same caller. Inspired by MulticallV3:\n/// https://github.com/mds1/multicall/blob/master/src/Multicall3.sol\ninterface IMulticallTarget {\n struct Result {\n bool success;\n bytes returnData;\n }\n\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external;\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results);\n}\n\n// contracts/interfaces/IZapRecipient.sol\n\ninterface IZapRecipient {\n function zap(address token, uint256 amount, bytes memory zapData) external payable returns (bytes4);\n}\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// contracts/interfaces/IFastBridgeV2.sol\n\ninterface IFastBridgeV2 is IFastBridge {\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n struct BridgeTxDetails {\n BridgeStatus status;\n uint32 destChainId;\n uint56 proofBlockTimestamp;\n address proofRelayer;\n }\n\n struct BridgeRelay {\n uint48 blockNumber;\n uint48 blockTimestamp;\n address relayer;\n }\n\n /// @notice New params introduced in the FastBridgeV2.\n /// We are passing fields from the older BridgeParams struct outside of this struct\n /// for backwards compatibility.\n /// Note: quoteRelayer and quoteExclusivitySeconds are either both zero (indicating no exclusivity)\n /// or both non-zero (indicating exclusivity for the given period).\n /// Note: zapNative \u003e 0 can NOT be used with destToken = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE (native token)\n /// @param quoteRelayer Relayer that provided the quote for the transaction\n /// @param quoteExclusivitySeconds Period of time the quote relayer is guaranteed exclusivity after user's deposit\n /// @param quoteId Unique quote identifier used for tracking the quote\n /// @param zapNative ETH value to send to the recipient (if any)\n /// @param zapData Parameters for the Zap to the destination recipient (if any)\n struct BridgeParamsV2 {\n address quoteRelayer;\n int256 quoteExclusivitySeconds;\n bytes quoteId;\n uint256 zapNative;\n bytes zapData;\n }\n\n /// @notice Updated bridge transaction struct to include parameters introduced in FastBridgeV2.\n /// Note: only `exclusivityRelayer` can fill such a transaction until `exclusivityEndTime`.\n struct BridgeTransactionV2 {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n // Note: sendChainGas flag from V1 is deprecated\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n address exclusivityRelayer;\n uint256 exclusivityEndTime;\n uint256 zapNative; // ETH value to send to the recipient (if any)\n bytes zapData; // data to pass for the Zap action (if any)\n }\n\n event BridgeQuoteDetails(bytes32 indexed transactionId, bytes quoteId);\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability\n /// to provide temporary exclusivity fill rights for the quote relayer.\n /// @param params The parameters required to bridge\n /// @param paramsV2 The parameters for exclusivity fill rights (optional, can be left empty)\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function relay(bytes memory request, address relayer) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param transactionId The transaction id associated with the encoded bridge transaction to prove\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital.\n /// @notice Can only send funds to the relayer address on the proof.\n /// @param request The encoded bridge transaction to claim on origin chain\n function claim(bytes memory request) external;\n\n /// @notice Cancels an outstanding bridge transaction in case optimistic bridging failed and returns the full amount\n /// to the original sender.\n /// @param request The encoded bridge transaction to refund\n function cancel(bytes memory request) external;\n\n /// @notice Checks if a transaction has been relayed\n /// @param transactionId The ID of the transaction to check\n /// @return True if the transaction has been relayed, false otherwise\n function bridgeRelays(bytes32 transactionId) external view returns (bool);\n\n /// @notice Returns the status of a bridge transaction\n /// @param transactionId The ID of the bridge transaction\n /// @return BridgeStatus Status of the bridge transaction\n function bridgeStatuses(bytes32 transactionId) external view returns (BridgeStatus);\n\n /// @notice Returns the timestamp and relayer of a bridge proof\n /// @param transactionId The ID of the bridge transaction\n /// @return timestamp The timestamp of the bridge proof\n /// @return relayer The relayer address of the bridge proof\n function bridgeProofs(bytes32 transactionId) external view returns (uint96 timestamp, address relayer);\n\n /// @notice Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\n /// @param request The bridge request to decode\n function getBridgeTransactionV2(bytes memory request) external view returns (BridgeTransactionV2 memory);\n}\n\n// contracts/utils/MulticallTarget.sol\n\n// solhint-disable avoid-low-level-calls\n/// @notice Template for a contract that supports batched calls (preserving the msg.sender).\n/// Only calls with zero msg.value could be batched.\nabstract contract MulticallTarget is IMulticallTarget {\n error MulticallTarget__UndeterminedRevert();\n\n /// @notice Perform a batched call to this contract, preserving the msg.sender.\n /// The return data from each call is discarded.\n /// @dev The method is non-payable, so only calls with `msg.value == 0` could be batched.\n /// It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag.\n /// Otherwise, the whole batch call will be reverted with the original revert reason.\n /// @param data List of abi-encoded calldata for the calls to perform.\n /// @param ignoreReverts Whether to ignore the revert errors from the calls.\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external {\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\n if (!success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(result);\n }\n }\n }\n\n /// @notice Perform a batched call to this contract, preserving the msg.sender.\n /// The return data from each call is preserved.\n /// @dev The method is non-payable, so only calls with `msg.value == 0` could be batched.\n /// It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag.\n /// Otherwise, the whole batch call will be reverted with the original revert reason.\n /// @param data List of abi-encoded calldata for the calls to perform.\n /// @param ignoreReverts Whether to ignore the revert errors from the calls.\n /// @return results List of results from the calls: `(success, returnData)`.\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results)\n {\n results = new Result[](data.length);\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (results[i].success, results[i].returnData) = address(this).delegatecall(data[i]);\n if (!results[i].success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(results[i].returnData);\n }\n }\n }\n\n /// @dev Bubbles the revert message from the underlying call.\n /// Note: preserves the same custom error or revert string, if one was used.\n /// Source: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v5.0.2/contracts/utils/Address.sol#L143-L158\n function _bubbleRevert(bytes memory returnData) internal pure {\n // Look for revert reason and bubble it up if present\n if (returnData.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n // solhint-disable-next-line no-inline-assembly\n assembly {\n let returndata_size := mload(returnData)\n revert(add(32, returnData), returndata_size)\n }\n } else {\n revert MulticallTarget__UndeterminedRevert();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// contracts/libs/BridgeTransactionV2.sol\n\n// solhint-disable no-inline-assembly\nlibrary BridgeTransactionV2Lib {\n uint16 internal constant VERSION = 2;\n\n // Offsets of the fields in the packed BridgeTransactionV2 struct\n // uint16 version [000 .. 002)\n // uint32 originChainId [002 .. 006)\n // uint32 destChainId [006 .. 010)\n // address originSender [010 .. 030)\n // address destRecipient [030 .. 050)\n // address originToken [050 .. 070)\n // address destToken [070 .. 090)\n // uint256 originAmount [090 .. 122)\n // uint256 destAmount [122 .. 154)\n // uint256 originFeeAmount [154 .. 186)\n // uint256 deadline [186 .. 218)\n // uint256 nonce [218 .. 250)\n // address exclusivityRelayer [250 .. 270)\n // uint256 exclusivityEndTime [270 .. 302)\n // uint256 zapNative [302 .. 334)\n // bytes zapData [334 .. ***)\n\n // forgefmt: disable-start\n uint256 private constant OFFSET_ORIGIN_CHAIN_ID = 2;\n uint256 private constant OFFSET_DEST_CHAIN_ID = 6;\n uint256 private constant OFFSET_ORIGIN_SENDER = 10;\n uint256 private constant OFFSET_DEST_RECIPIENT = 30;\n uint256 private constant OFFSET_ORIGIN_TOKEN = 50;\n uint256 private constant OFFSET_DEST_TOKEN = 70;\n uint256 private constant OFFSET_ORIGIN_AMOUNT = 90;\n uint256 private constant OFFSET_DEST_AMOUNT = 122;\n uint256 private constant OFFSET_ORIGIN_FEE_AMOUNT = 154;\n uint256 private constant OFFSET_DEADLINE = 186;\n uint256 private constant OFFSET_NONCE = 218;\n uint256 private constant OFFSET_EXCLUSIVITY_RELAYER = 250;\n uint256 private constant OFFSET_EXCLUSIVITY_END_TIME = 270;\n uint256 private constant OFFSET_ZAP_NATIVE = 302;\n uint256 private constant OFFSET_ZAP_DATA = 334;\n // forgefmt: disable-end\n\n error BridgeTransactionV2__InvalidEncodedTx();\n error BridgeTransactionV2__UnsupportedVersion(uint16 version);\n\n /// @notice Validates the encoded transaction to be a tightly packed encoded payload for BridgeTransactionV2.\n /// @dev Checks the minimum length and the version, use this function before decoding any of the fields.\n function validateV2(bytes calldata encodedTx) internal pure {\n // Check the minimum length: must at least include all static fields.\n if (encodedTx.length \u003c OFFSET_ZAP_DATA) revert BridgeTransactionV2__InvalidEncodedTx();\n // Once we validated the length, we can be sure that the version field is present.\n uint16 version_ = version(encodedTx);\n if (version_ != VERSION) revert BridgeTransactionV2__UnsupportedVersion(version_);\n }\n\n /// @notice Encodes the BridgeTransactionV2 struct by tightly packing the fields.\n /// @dev `abi.decode` will not work as a result of the tightly packed fields. Use `decodeV2` to decode instead.\n function encodeV2(IFastBridgeV2.BridgeTransactionV2 memory bridgeTx) internal pure returns (bytes memory) {\n // We split the encoding into two parts to avoid stack-too-deep error\n bytes memory firstPart = abi.encodePacked(\n VERSION,\n bridgeTx.originChainId,\n bridgeTx.destChainId,\n bridgeTx.originSender,\n bridgeTx.destRecipient,\n bridgeTx.originToken,\n bridgeTx.destToken,\n bridgeTx.originAmount\n );\n return abi.encodePacked(\n firstPart,\n bridgeTx.destAmount,\n bridgeTx.originFeeAmount,\n // Note: we skip the deprecated `sendChainGas` flag, which was present in BridgeTransaction V1\n bridgeTx.deadline,\n bridgeTx.nonce,\n // New V2 fields: exclusivity\n bridgeTx.exclusivityRelayer,\n bridgeTx.exclusivityEndTime,\n // New V2 fields: Zap\n bridgeTx.zapNative,\n bridgeTx.zapData\n );\n }\n\n /// @notice Decodes the BridgeTransactionV2 struct from the encoded transaction.\n /// @dev Encoded BridgeTransactionV2 struct must be tightly packed.\n /// Use `validateV2` before decoding to ensure the encoded transaction is valid.\n function decodeV2(bytes calldata encodedTx)\n internal\n pure\n returns (IFastBridgeV2.BridgeTransactionV2 memory bridgeTx)\n {\n bridgeTx.originChainId = originChainId(encodedTx);\n bridgeTx.destChainId = destChainId(encodedTx);\n bridgeTx.originSender = originSender(encodedTx);\n bridgeTx.destRecipient = destRecipient(encodedTx);\n bridgeTx.originToken = originToken(encodedTx);\n bridgeTx.destToken = destToken(encodedTx);\n bridgeTx.originAmount = originAmount(encodedTx);\n bridgeTx.destAmount = destAmount(encodedTx);\n bridgeTx.originFeeAmount = originFeeAmount(encodedTx);\n bridgeTx.deadline = deadline(encodedTx);\n bridgeTx.nonce = nonce(encodedTx);\n bridgeTx.exclusivityRelayer = exclusivityRelayer(encodedTx);\n bridgeTx.exclusivityEndTime = exclusivityEndTime(encodedTx);\n bridgeTx.zapNative = zapNative(encodedTx);\n bridgeTx.zapData = zapData(encodedTx);\n }\n\n /// @notice Extracts the version from the encoded transaction.\n function version(bytes calldata encodedTx) internal pure returns (uint16 version_) {\n // Load 32 bytes from the start and shift it 240 bits to the right to get the highest 16 bits.\n assembly {\n version_ := shr(240, calldataload(encodedTx.offset))\n }\n }\n\n /// @notice Extracts the origin chain ID from the encoded transaction.\n function originChainId(bytes calldata encodedTx) internal pure returns (uint32 originChainId_) {\n // Load 32 bytes from the offset and shift it 224 bits to the right to get the highest 32 bits.\n assembly {\n originChainId_ := shr(224, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_CHAIN_ID)))\n }\n }\n\n /// @notice Extracts the destination chain ID from the encoded transaction.\n function destChainId(bytes calldata encodedTx) internal pure returns (uint32 destChainId_) {\n // Load 32 bytes from the offset and shift it 224 bits to the right to get the highest 32 bits.\n assembly {\n destChainId_ := shr(224, calldataload(add(encodedTx.offset, OFFSET_DEST_CHAIN_ID)))\n }\n }\n\n /// @notice Extracts the origin sender from the encoded transaction.\n function originSender(bytes calldata encodedTx) internal pure returns (address originSender_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n originSender_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_SENDER)))\n }\n }\n\n /// @notice Extracts the destination recipient from the encoded transaction.\n function destRecipient(bytes calldata encodedTx) internal pure returns (address destRecipient_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n destRecipient_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_DEST_RECIPIENT)))\n }\n }\n\n /// @notice Extracts the origin token from the encoded transaction.\n function originToken(bytes calldata encodedTx) internal pure returns (address originToken_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n originToken_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_TOKEN)))\n }\n }\n\n /// @notice Extracts the destination token from the encoded transaction.\n function destToken(bytes calldata encodedTx) internal pure returns (address destToken_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n destToken_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_DEST_TOKEN)))\n }\n }\n\n /// @notice Extracts the origin amount from the encoded transaction.\n function originAmount(bytes calldata encodedTx) internal pure returns (uint256 originAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n originAmount_ := calldataload(add(encodedTx.offset, OFFSET_ORIGIN_AMOUNT))\n }\n }\n\n /// @notice Extracts the destination amount from the encoded transaction.\n function destAmount(bytes calldata encodedTx) internal pure returns (uint256 destAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n destAmount_ := calldataload(add(encodedTx.offset, OFFSET_DEST_AMOUNT))\n }\n }\n\n /// @notice Extracts the origin fee amount from the encoded transaction.\n function originFeeAmount(bytes calldata encodedTx) internal pure returns (uint256 originFeeAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n originFeeAmount_ := calldataload(add(encodedTx.offset, OFFSET_ORIGIN_FEE_AMOUNT))\n }\n }\n\n /// @notice Extracts the deadline from the encoded transaction.\n function deadline(bytes calldata encodedTx) internal pure returns (uint256 deadline_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n deadline_ := calldataload(add(encodedTx.offset, OFFSET_DEADLINE))\n }\n }\n\n /// @notice Extracts the nonce from the encoded transaction.\n function nonce(bytes calldata encodedTx) internal pure returns (uint256 nonce_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n nonce_ := calldataload(add(encodedTx.offset, OFFSET_NONCE))\n }\n }\n\n /// @notice Extracts the exclusivity relayer from the encoded transaction.\n function exclusivityRelayer(bytes calldata encodedTx) internal pure returns (address exclusivityRelayer_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n exclusivityRelayer_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_EXCLUSIVITY_RELAYER)))\n }\n }\n\n /// @notice Extracts the exclusivity end time from the encoded transaction.\n function exclusivityEndTime(bytes calldata encodedTx) internal pure returns (uint256 exclusivityEndTime_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n exclusivityEndTime_ := calldataload(add(encodedTx.offset, OFFSET_EXCLUSIVITY_END_TIME))\n }\n }\n\n /// @notice Extracts the Zap's native value from the encoded transaction.\n function zapNative(bytes calldata encodedTx) internal pure returns (uint256 zapNative_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n zapNative_ := calldataload(add(encodedTx.offset, OFFSET_ZAP_NATIVE))\n }\n }\n\n /// @notice Extracts the Zap's data from the encoded transaction.\n function zapData(bytes calldata encodedTx) internal pure returns (bytes calldata zapData_) {\n zapData_ = encodedTx[OFFSET_ZAP_DATA:];\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/AdminV2.sol\n\ncontract AdminV2 is AccessControlEnumerable, IAdminV2, IAdminV2Errors {\n using SafeERC20 for IERC20;\n\n /// @notice Address reserved for native gas token (ETH on Ethereum and most L2s, AVAX on Avalanche, etc)\n address public constant NATIVE_GAS_TOKEN = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Role identifier for Quoter API's off-chain authentication.\n /// @dev Only addresses with this role can post FastBridge quotes to the API.\n bytes32 public constant QUOTER_ROLE = keccak256(\"QUOTER_ROLE\");\n\n /// @notice Role identifier for Prover's on-chain authentication in FastBridge.\n /// @dev Only addresses with this role can provide proofs that a FastBridge request has been relayed.\n bytes32 public constant PROVER_ROLE = keccak256(\"PROVER_ROLE\");\n\n /// @notice Role identifier for Guard's on-chain authentication in FastBridge.\n /// @dev Only addresses with this role can dispute submitted relay proofs during the dispute period.\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n\n /// @notice Role identifier for Canceler's on-chain authentication in FastBridge.\n /// @dev Only addresses with this role can cancel a FastBridge transaction without the cancel delay.\n bytes32 public constant CANCELER_ROLE = keccak256(\"CANCELER_ROLE\");\n\n /// @notice Role identifier for Governor's on-chain administrative authority.\n /// @dev Only addresses with this role can perform administrative tasks within the contract.\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n /// @notice Denominator for fee rates, represents 100%.\n uint256 public constant FEE_BPS = 1e6;\n /// @notice Maximum protocol fee rate: 1% on origin amount.\n uint256 public constant FEE_RATE_MAX = 0.01e6;\n\n /// @notice Minimum cancel delay that can be set by the governor.\n uint256 public constant MIN_CANCEL_DELAY = 1 hours;\n /// @notice Default cancel delay set during the contract deployment.\n uint256 public constant DEFAULT_CANCEL_DELAY = 1 days;\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Delay for a transaction after which it could be permisionlessly cancelled\n uint256 public cancelDelay;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Use ZapNative V2 requests instead.\n uint256 public immutable chainGasAmount = 0;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n _setCancelDelay(DEFAULT_CANCEL_DELAY);\n }\n\n /// @notice Allows the contract governor to set the cancel delay. The cancel delay is the time after the transaction\n /// deadline after which it can be permissionlessly cancelled, if it hasn't been proven by any of the Relayers.\n function setCancelDelay(uint256 newCancelDelay) external onlyRole(GOVERNOR_ROLE) {\n _setCancelDelay(newCancelDelay);\n }\n\n /// @notice Allows the contract governor to set the protocol fee rate. The protocol fee is taken from the origin\n /// amount only for completed and claimed transactions.\n /// @dev The protocol fee is abstracted away from the relayers, they always operate using the amounts after fees:\n /// what they see as the origin amount emitted in the log is what they get credited with.\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n if (newFeeRate \u003e FEE_RATE_MAX) revert FeeRateAboveMax();\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n /// @notice Allows the contract governor to sweep the accumulated protocol fees in the contract.\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n emit FeesSwept(token, recipient, feeAmount);\n /// Sweep the fees as the last transaction action\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(recipient), feeAmount);\n } else {\n IERC20(token).safeTransfer(recipient, feeAmount);\n }\n }\n\n /// @notice Internal function to set the cancel delay. Security checks are performed outside of this function.\n function _setCancelDelay(uint256 newCancelDelay) private {\n if (newCancelDelay \u003c MIN_CANCEL_DELAY) revert CancelDelayBelowMin();\n uint256 oldCancelDelay = cancelDelay;\n cancelDelay = newCancelDelay;\n emit CancelDelayUpdated(oldCancelDelay, newCancelDelay);\n }\n}\n\n// contracts/FastBridgeV2.sol\n\n/// @notice FastBridgeV2 is a contract for bridging tokens across chains.\ncontract FastBridgeV2 is AdminV2, MulticallTarget, IFastBridgeV2, IFastBridgeV2Errors {\n using BridgeTransactionV2Lib for bytes;\n using SafeERC20 for IERC20;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n /// @notice Maximum length of accepted zapData\n uint256 public constant MAX_ZAP_DATA_LENGTH = 2 ** 16 - 1;\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeTxDetails) public bridgeTxDetails;\n /// @notice Relay details on destination chain\n mapping(bytes32 =\u003e BridgeRelay) public bridgeRelayDetails;\n /// @notice Unique bridge nonces tracked per originSender\n mapping(address =\u003e uint256) public senderNonces;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Replaced by senderNonces\n uint256 public immutable nonce = 0;\n /// @notice the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) AdminV2(_owner) {\n deployBlock = block.number;\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n bridge({\n params: params,\n paramsV2: BridgeParamsV2({\n quoteRelayer: address(0),\n quoteExclusivitySeconds: 0,\n quoteId: bytes(\"\"),\n zapNative: 0,\n zapData: bytes(\"\")\n })\n });\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes calldata request) external payable {\n // relay override will validate the request\n relay({request: request, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes calldata request, bytes32 destTxHash) external {\n request.validateV2();\n prove({transactionId: keccak256(request), destTxHash: destTxHash, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridgeV2\n function claim(bytes calldata request) external {\n // claim override will validate the request\n claim({request: request, to: address(0)});\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Aggregate the read operations from the same storage slot\n address disputedRelayer = $.proofRelayer;\n BridgeStatus status = $.status;\n uint56 proofBlockTimestamp = $.proofBlockTimestamp;\n // Can only dispute a RELAYER_PROVED transaction within the dispute period\n if (status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(proofBlockTimestamp) \u003e DISPUTE_PERIOD) {\n revert DisputePeriodPassed();\n }\n // Update status to REQUESTED and delete the disputed proof details\n // Note: these are storage writes\n $.status = BridgeStatus.REQUESTED;\n $.proofRelayer = address(0);\n $.proofBlockTimestamp = 0;\n\n emit BridgeProofDisputed(transactionId, disputedRelayer);\n }\n\n /// Note: this function is deprecated and will be removed in a future version.\n /// @inheritdoc IFastBridge\n function refund(bytes calldata request) external {\n cancel(request);\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // The correct relayer can only claim a RELAYER_PROVED transaction after the dispute period\n if ($.status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if ($.proofRelayer != relayer) revert SenderIncorrect();\n return _timeSince($.proofBlockTimestamp) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n /// @dev This method is added to achieve backwards compatibility with decoding requests into V1 structs:\n /// - `zapNative` is partially reported as a zero/non-zero flag\n /// - `zapData` is ignored\n /// In order to process all kinds of requests use getBridgeTransactionV2 instead.\n function getBridgeTransaction(bytes calldata request) external view returns (BridgeTransaction memory) {\n // Try decoding into V2 struct first. This will revert if V1 struct is passed\n try this.getBridgeTransactionV2(request) returns (BridgeTransactionV2 memory txV2) {\n // Note: we entirely ignore the zapData field, as it was not present in V1\n return BridgeTransaction({\n originChainId: txV2.originChainId,\n destChainId: txV2.destChainId,\n originSender: txV2.originSender,\n destRecipient: txV2.destRecipient,\n originToken: txV2.originToken,\n destToken: txV2.destToken,\n originAmount: txV2.originAmount,\n destAmount: txV2.destAmount,\n originFeeAmount: txV2.originFeeAmount,\n sendChainGas: txV2.zapNative != 0,\n deadline: txV2.deadline,\n nonce: txV2.nonce\n });\n } catch {\n // Fallback to V1 struct\n return abi.decode(request, (BridgeTransaction));\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function getBridgeTransactionV2(bytes calldata request) external pure returns (BridgeTransactionV2 memory) {\n request.validateV2();\n return BridgeTransactionV2Lib.decodeV2(request);\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) public payable {\n int256 exclusivityEndTime = 0;\n // if relayer exclusivity is not intended for this bridge, set exclusivityEndTime to static zero\n // otherwise, set exclusivity to expire at the current block ts offset by quoteExclusivitySeconds\n if (paramsV2.quoteRelayer != address(0)) {\n exclusivityEndTime = int256(block.timestamp) + paramsV2.quoteExclusivitySeconds;\n }\n _validateBridgeParams(params, paramsV2, exclusivityEndTime);\n\n // transfer tokens to bridge contract\n /// @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _takeBridgedUserAsset(params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) {\n originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n }\n\n // set status to requested\n bytes memory request = BridgeTransactionV2Lib.encodeV2(\n BridgeTransactionV2({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n deadline: params.deadline,\n nonce: senderNonces[params.sender]++, // increment nonce on every bridge\n exclusivityRelayer: paramsV2.quoteRelayer,\n // We checked exclusivityEndTime to be in range [0 .. params.deadline] above, so can safely cast\n exclusivityEndTime: uint256(exclusivityEndTime),\n zapNative: paramsV2.zapNative,\n zapData: paramsV2.zapData\n })\n );\n bytes32 transactionId = keccak256(request);\n // Note: the tx status will be updated throughout the tx lifecycle, while destChainId is set once here\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n bridgeTxDetails[transactionId].destChainId = params.dstChainId;\n\n emit BridgeRequested({\n transactionId: transactionId,\n sender: params.sender,\n request: request,\n destChainId: params.dstChainId,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n sendChainGas: paramsV2.zapNative != 0\n });\n emit BridgeQuoteDetails(transactionId, paramsV2.quoteId);\n }\n\n /// @inheritdoc IFastBridgeV2\n function relay(bytes calldata request, address relayer) public payable {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n _validateRelayParams(request, transactionId, relayer);\n // mark bridge transaction as relayed\n bridgeRelayDetails[transactionId] =\n BridgeRelay({blockNumber: uint48(block.number), blockTimestamp: uint48(block.timestamp), relayer: relayer});\n\n // transfer tokens to recipient on destination chain and trigger Zap if requested\n address to = request.destRecipient();\n address token = request.destToken();\n uint256 amount = request.destAmount();\n uint256 zapNative = request.zapNative();\n\n // Emit the event before any external calls\n emit BridgeRelayed({\n transactionId: transactionId,\n relayer: relayer,\n to: to,\n originChainId: request.originChainId(),\n originToken: request.originToken(),\n destToken: token,\n originAmount: request.originAmount(),\n destAmount: amount,\n chainGasAmount: zapNative\n });\n\n // All state changes have been done at this point, can proceed to the external calls.\n // This follows the checks-effects-interactions pattern to mitigate potential reentrancy attacks.\n if (token == NATIVE_GAS_TOKEN) {\n // For the native gas token, additional zapNative is not allowed\n if (zapNative != 0) revert ZapNativeNotSupported();\n // Check that the correct msg.value was sent\n if (msg.value != amount) revert MsgValueIncorrect();\n // Don't do a native transfer yet: we will handle it alongside the Zap below\n } else {\n // For ERC20s, we check that the correct msg.value was sent\n if (msg.value != zapNative) revert MsgValueIncorrect();\n // We need to transfer the tokens from the Relayer to the recipient first before performing an\n // optional post-transfer Zap.\n IERC20(token).safeTransferFrom(msg.sender, to, amount);\n }\n // At this point we have done:\n // - Transferred the requested amount of ERC20 tokens to the recipient.\n // At this point we have confirmed:\n // - For ERC20s: msg.value matches the requested zapNative amount.\n // - For the native gas token: msg.value matches the requested destAmount.\n // Remaining optional things to do:\n // - Forward the full msg.value to the recipient (if non-zero).\n // - Trigger a Zap (if zapData is present).\n bytes calldata zapData = request.zapData();\n if (zapData.length != 0) {\n // Zap Data is present: Zap has been requested by the recipient. Trigger it forwarding the full msg.value.\n\n // Note: if token has a fee on transfers, the recipient will have received less than `amount`.\n // This is a very niche edge case and should be handled by the recipient contract.\n _triggerZapWithChecks({recipient: to, token: token, amount: amount, zapData: zapData});\n } else if (msg.value != 0) {\n // Zap Data is missing, but msg.value was sent. This could happen in two different cases:\n // - Relay with the native gas token is happening.\n // - Relay with ERC20 is happening, with a `zapNative \u003e 0` request.\n // In both cases, we need to transfer the full msg.value to the recipient.\n Address.sendValue(payable(to), msg.value);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) public onlyRole(PROVER_ROLE) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n\n // Can only prove a REQUESTED transaction\n if ($.status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n // Update status to RELAYER_PROVED and store the proof details\n // Note: these are storage writes\n $.status = BridgeStatus.RELAYER_PROVED;\n $.proofBlockTimestamp = uint56(block.timestamp);\n $.proofRelayer = relayer;\n\n emit BridgeProofProvided(transactionId, relayer, destTxHash);\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes calldata request, address to) public {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Aggregate the read operations from the same storage slot\n address proofRelayer = $.proofRelayer;\n BridgeStatus status = $.status;\n uint56 proofBlockTimestamp = $.proofBlockTimestamp;\n\n // Can only claim a RELAYER_PROVED transaction after the dispute period\n if (status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(proofBlockTimestamp) \u003c= DISPUTE_PERIOD) {\n revert DisputePeriodNotPassed();\n }\n\n if (to == address(0)) {\n // Anyone could claim the funds to the proven relayer on their behalf\n to = proofRelayer;\n } else if (proofRelayer != msg.sender) {\n // Only the proven relayer could specify an address to claim the funds to\n revert SenderIncorrect();\n }\n\n // Update status to RELAYER_CLAIMED and transfer the origin collateral to the specified claim address\n // Note: this is a storage write\n $.status = BridgeStatus.RELAYER_CLAIMED;\n\n address token = request.originToken();\n uint256 amount = request.originAmount();\n // Update protocol fees if origin fee amount exists\n uint256 originFeeAmount = request.originFeeAmount();\n if (originFeeAmount \u003e 0) protocolFees[token] += originFeeAmount;\n // Emit the event before any external calls\n emit BridgeDepositClaimed(transactionId, proofRelayer, to, token, amount);\n // Complete the relayer claim as the last transaction action\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(to), amount);\n } else {\n IERC20(token).safeTransfer(to, amount);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function cancel(bytes calldata request) public {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Can only cancel a REQUESTED transaction after its deadline expires\n if ($.status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n uint256 deadline = request.deadline();\n // Permissionless cancel is only allowed after `cancelDelay` on top of the deadline\n if (!hasRole(CANCELER_ROLE, msg.sender)) deadline += cancelDelay;\n if (block.timestamp \u003c= deadline) revert DeadlineNotExceeded();\n // Update status to REFUNDED and return the full amount (collateral + protocol fees) to the original sender.\n // The protocol fees are only updated when the transaction is claimed, so we don't need to update them here.\n // Note: this is a storage write\n $.status = BridgeStatus.REFUNDED;\n\n address to = request.originSender();\n address token = request.originToken();\n uint256 amount = request.originAmount() + request.originFeeAmount();\n // Emit the event before any external calls\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n // Complete the user cancel as the last transaction action\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(to), amount);\n } else {\n IERC20(token).safeTransfer(to, amount);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeStatuses(bytes32 transactionId) public view returns (BridgeStatus status) {\n return bridgeTxDetails[transactionId].status;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeProofs(bytes32 transactionId) public view returns (uint96 timestamp, address relayer) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n\n timestamp = $.proofBlockTimestamp;\n relayer = $.proofRelayer;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeRelays(bytes32 transactionId) public view returns (bool) {\n // has this transactionId been relayed?\n return bridgeRelayDetails[transactionId].relayer != address(0);\n }\n\n /// @notice Takes the bridged asset from the user into FastBridgeV2 custody. It will be later\n /// claimed by the relayer who completed the relay on destination chain, or transferred back to the user\n /// via the cancel function should no one complete the relay.\n function _takeBridgedUserAsset(address token, uint256 amount) internal returns (uint256 amountTaken) {\n if (token == NATIVE_GAS_TOKEN) {\n // For the native gas token, we just need to check that the supplied msg.value is correct.\n // Supplied `msg.value` is already in FastBridgeV2 custody.\n if (amount != msg.value) revert MsgValueIncorrect();\n amountTaken = msg.value;\n } else {\n // For ERC20s, token is explicitly transferred from the user to FastBridgeV2.\n // We don't allow non-zero `msg.value` to avoid extra funds from being stuck in FastBridgeV2.\n if (msg.value != 0) revert MsgValueIncorrect();\n // Throw an explicit error if the provided token address is not a contract\n if (token.code.length == 0) revert TokenNotContract();\n amountTaken = IERC20(token).balanceOf(address(this));\n IERC20(token).safeTransferFrom(msg.sender, address(this), amount);\n // Use the balance difference as the amount taken in case of fee on transfer tokens.\n amountTaken = IERC20(token).balanceOf(address(this)) - amountTaken;\n }\n }\n\n /// @notice Calls the Recipient's hook function with the specified zapData and performs\n /// all the necessary checks for the returned value.\n function _triggerZapWithChecks(address recipient, address token, uint256 amount, bytes calldata zapData) internal {\n // This will bubble any revert messages from the hook function\n bytes memory returnData = Address.functionCallWithValue({\n target: recipient,\n data: abi.encodeCall(IZapRecipient.zap, (token, amount, zapData)),\n // Note: see `relay()` for reasoning behind passing msg.value\n value: msg.value\n });\n // Explicit revert if no return data at all\n if (returnData.length == 0) revert RecipientNoReturnValue();\n // Check that exactly a single return value was returned\n if (returnData.length != 32) revert RecipientIncorrectReturnValue();\n // Return value should be abi-encoded hook function selector\n if (bytes32(returnData) != bytes32(IZapRecipient.zap.selector)) {\n revert RecipientIncorrectReturnValue();\n }\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint56(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint56).max but\n /// proof.timestamp \u003c type(uint56).max via unchecked statement\n /// @param proofBlockTimestamp The bridge proof block timestamp\n /// @return delta Time delta since proof submitted\n function _timeSince(uint56 proofBlockTimestamp) internal view returns (uint256 delta) {\n unchecked {\n delta = uint56(block.timestamp) - proofBlockTimestamp;\n }\n }\n\n /// @notice Performs all the necessary checks for a bridge to happen.\n /// @dev There's no good way to refactor this function to reduce cyclomatic complexity due to\n /// the number of checks that need to be performed, so we skip the code-complexity rule here.\n // solhint-disable-next-line code-complexity\n function _validateBridgeParams(\n BridgeParams memory params,\n BridgeParamsV2 memory paramsV2,\n int256 exclusivityEndTime\n )\n internal\n view\n {\n // Check V1 (legacy) params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.sender == address(0) || params.to == address(0)) revert ZeroAddress();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n // Check V2 params\n if (paramsV2.zapData.length \u003e MAX_ZAP_DATA_LENGTH) revert ZapDataLengthAboveMax();\n if (paramsV2.zapNative != 0 \u0026\u0026 params.destToken == NATIVE_GAS_TOKEN) {\n revert ZapNativeNotSupported();\n }\n // exclusivityEndTime must be in range [0 .. params.deadline]\n if (exclusivityEndTime \u003c 0 || exclusivityEndTime \u003e int256(params.deadline)) {\n revert ExclusivityParamsIncorrect();\n }\n }\n\n /// @notice Performs all the necessary checks for a relay to happen.\n function _validateRelayParams(bytes calldata request, bytes32 transactionId, address relayer) internal view {\n if (relayer == address(0)) revert ZeroAddress();\n // Check if the transaction has already been relayed\n if (bridgeRelays(transactionId)) revert TransactionRelayed();\n if (request.destChainId() != block.chainid) revert ChainIncorrect();\n // Check the deadline for relay to happen\n if (block.timestamp \u003e request.deadline()) revert DeadlineExceeded();\n // Check the exclusivity period, if it is still ongoing\n address exclRelayer = request.exclusivityRelayer();\n if (exclRelayer != address(0) \u0026\u0026 exclRelayer != relayer \u0026\u0026 block.timestamp \u003c= request.exclusivityEndTime()) {\n revert ExclusivityPeriodNotPassed();\n }\n }\n}\n","language":"Solidity","languageVersion":"0.8.24","compilerVersion":"0.8.24","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"","srcMapRuntime":"","abiDefinition":[{"inputs":[],"name":"MulticallTarget__UndeterminedRevert","type":"error"},{"inputs":[{"internalType":"bytes[]","name":"data","type":"bytes[]"},{"internalType":"bool","name":"ignoreReverts","type":"bool"}],"name":"multicallNoResults","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes[]","name":"data","type":"bytes[]"},{"internalType":"bool","name":"ignoreReverts","type":"bool"}],"name":"multicallWithResults","outputs":[{"components":[{"internalType":"bool","name":"success","type":"bool"},{"internalType":"bytes","name":"returnData","type":"bytes"}],"internalType":"struct IMulticallTarget.Result[]","name":"results","type":"tuple[]"}],"stateMutability":"nonpayable","type":"function"}],"userDoc":{"kind":"user","methods":{"multicallNoResults(bytes[],bool)":{"notice":"Perform a batched call to this contract, preserving the msg.sender. The return data from each call is discarded."},"multicallWithResults(bytes[],bool)":{"notice":"Perform a batched call to this contract, preserving the msg.sender. The return data from each call is preserved."}},"notice":"Template for a contract that supports batched calls (preserving the msg.sender). Only calls with zero msg.value could be batched.","version":1},"developerDoc":{"kind":"dev","methods":{"multicallNoResults(bytes[],bool)":{"details":"The method is non-payable, so only calls with `msg.value == 0` could be batched. It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag. Otherwise, the whole batch call will be reverted with the original revert reason.","params":{"data":"List of abi-encoded calldata for the calls to perform.","ignoreReverts":"Whether to ignore the revert errors from the calls."}},"multicallWithResults(bytes[],bool)":{"details":"The method is non-payable, so only calls with `msg.value == 0` could be batched. It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag. Otherwise, the whole batch call will be reverted with the original revert reason.","params":{"data":"List of abi-encoded calldata for the calls to perform.","ignoreReverts":"Whether to ignore the revert errors from the calls."},"returns":{"results":" List of results from the calls: `(success, returnData)`."}}},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[],\"name\":\"MulticallTarget__UndeterminedRevert\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"bytes[]\",\"name\":\"data\",\"type\":\"bytes[]\"},{\"internalType\":\"bool\",\"name\":\"ignoreReverts\",\"type\":\"bool\"}],\"name\":\"multicallNoResults\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes[]\",\"name\":\"data\",\"type\":\"bytes[]\"},{\"internalType\":\"bool\",\"name\":\"ignoreReverts\",\"type\":\"bool\"}],\"name\":\"multicallWithResults\",\"outputs\":[{\"components\":[{\"internalType\":\"bool\",\"name\":\"success\",\"type\":\"bool\"},{\"internalType\":\"bytes\",\"name\":\"returnData\",\"type\":\"bytes\"}],\"internalType\":\"struct IMulticallTarget.Result[]\",\"name\":\"results\",\"type\":\"tuple[]\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{\"multicallNoResults(bytes[],bool)\":{\"details\":\"The method is non-payable, so only calls with `msg.value == 0` could be batched. It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag. Otherwise, the whole batch call will be reverted with the original revert reason.\",\"params\":{\"data\":\"List of abi-encoded calldata for the calls to perform.\",\"ignoreReverts\":\"Whether to ignore the revert errors from the calls.\"}},\"multicallWithResults(bytes[],bool)\":{\"details\":\"The method is non-payable, so only calls with `msg.value == 0` could be batched. It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag. Otherwise, the whole batch call will be reverted with the original revert reason.\",\"params\":{\"data\":\"List of abi-encoded calldata for the calls to perform.\",\"ignoreReverts\":\"Whether to ignore the revert errors from the calls.\"},\"returns\":{\"results\":\" List of results from the calls: `(success, returnData)`.\"}}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"multicallNoResults(bytes[],bool)\":{\"notice\":\"Perform a batched call to this contract, preserving the msg.sender. The return data from each call is discarded.\"},\"multicallWithResults(bytes[],bool)\":{\"notice\":\"Perform a batched call to this contract, preserving the msg.sender. The return data from each call is preserved.\"}},\"notice\":\"Template for a contract that supports batched calls (preserving the msg.sender). Only calls with zero msg.value could be batched.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeV2.sol\":\"MulticallTarget\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeV2.sol\":{\"keccak256\":\"0xac79c463688a682ca706a4ef95e7817b83548cdfa8182ba0426ac7e5e07613d8\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://b3ecb7097381287cafc3a73f3a2bb03565115ebb682a85064e0b0dc2f7e2919d\",\"dweb:/ipfs/QmatruW3nYZTksf3CeQ8wwiAG4c7xoEJBEp6drHPtFLBRK\"]}},\"version\":1}"},"hashes":{"multicallNoResults(bytes[],bool)":"3f61331d","multicallWithResults(bytes[],bool)":"385c1d2f"}},"solidity/FastBridgeV2.sol:SafeERC20":{"code":"0x60566037600b82828239805160001a607314602a57634e487b7160e01b600052600060045260246000fd5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600080fdfea2646970667358221220fc15551e7cd0cae1476ceeb26ea6d8e21a222c930b99686cddd49777e215b49764736f6c63430008180033","runtime-code":"0x73000000000000000000000000000000000000000030146080604052600080fdfea2646970667358221220fc15551e7cd0cae1476ceeb26ea6d8e21a222c930b99686cddd49777e215b49764736f6c63430008180033","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.24 ^0.8.20 ^0.8.4;\n\n// contracts/interfaces/IAdminV2.sol\n\ninterface IAdminV2 {\n event CancelDelayUpdated(uint256 oldCancelDelay, uint256 newCancelDelay);\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n function setCancelDelay(uint256 newCancelDelay) external;\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n}\n\n// contracts/interfaces/IAdminV2Errors.sol\n\ninterface IAdminV2Errors {\n error CancelDelayBelowMin();\n error FeeRateAboveMax();\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IFastBridgeV2Errors.sol\n\ninterface IFastBridgeV2Errors {\n error AmountIncorrect();\n error ChainIncorrect();\n error ExclusivityParamsIncorrect();\n error MsgValueIncorrect();\n error SenderIncorrect();\n error StatusIncorrect();\n error TokenNotContract();\n error ZapDataLengthAboveMax();\n error ZapNativeNotSupported();\n error ZeroAddress();\n\n error RecipientIncorrectReturnValue();\n error RecipientNoReturnValue();\n\n error DeadlineExceeded();\n error DeadlineNotExceeded();\n error DeadlineTooShort();\n error DisputePeriodNotPassed();\n error DisputePeriodPassed();\n error ExclusivityPeriodNotPassed();\n\n error TransactionRelayed();\n}\n\n// contracts/interfaces/IMulticallTarget.sol\n\n/// @notice Interface for a contract that can be called multiple times by the same caller. Inspired by MulticallV3:\n/// https://github.com/mds1/multicall/blob/master/src/Multicall3.sol\ninterface IMulticallTarget {\n struct Result {\n bool success;\n bytes returnData;\n }\n\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external;\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results);\n}\n\n// contracts/interfaces/IZapRecipient.sol\n\ninterface IZapRecipient {\n function zap(address token, uint256 amount, bytes memory zapData) external payable returns (bytes4);\n}\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// contracts/interfaces/IFastBridgeV2.sol\n\ninterface IFastBridgeV2 is IFastBridge {\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n struct BridgeTxDetails {\n BridgeStatus status;\n uint32 destChainId;\n uint56 proofBlockTimestamp;\n address proofRelayer;\n }\n\n struct BridgeRelay {\n uint48 blockNumber;\n uint48 blockTimestamp;\n address relayer;\n }\n\n /// @notice New params introduced in the FastBridgeV2.\n /// We are passing fields from the older BridgeParams struct outside of this struct\n /// for backwards compatibility.\n /// Note: quoteRelayer and quoteExclusivitySeconds are either both zero (indicating no exclusivity)\n /// or both non-zero (indicating exclusivity for the given period).\n /// Note: zapNative \u003e 0 can NOT be used with destToken = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE (native token)\n /// @param quoteRelayer Relayer that provided the quote for the transaction\n /// @param quoteExclusivitySeconds Period of time the quote relayer is guaranteed exclusivity after user's deposit\n /// @param quoteId Unique quote identifier used for tracking the quote\n /// @param zapNative ETH value to send to the recipient (if any)\n /// @param zapData Parameters for the Zap to the destination recipient (if any)\n struct BridgeParamsV2 {\n address quoteRelayer;\n int256 quoteExclusivitySeconds;\n bytes quoteId;\n uint256 zapNative;\n bytes zapData;\n }\n\n /// @notice Updated bridge transaction struct to include parameters introduced in FastBridgeV2.\n /// Note: only `exclusivityRelayer` can fill such a transaction until `exclusivityEndTime`.\n struct BridgeTransactionV2 {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n // Note: sendChainGas flag from V1 is deprecated\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n address exclusivityRelayer;\n uint256 exclusivityEndTime;\n uint256 zapNative; // ETH value to send to the recipient (if any)\n bytes zapData; // data to pass for the Zap action (if any)\n }\n\n event BridgeQuoteDetails(bytes32 indexed transactionId, bytes quoteId);\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability\n /// to provide temporary exclusivity fill rights for the quote relayer.\n /// @param params The parameters required to bridge\n /// @param paramsV2 The parameters for exclusivity fill rights (optional, can be left empty)\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function relay(bytes memory request, address relayer) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param transactionId The transaction id associated with the encoded bridge transaction to prove\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital.\n /// @notice Can only send funds to the relayer address on the proof.\n /// @param request The encoded bridge transaction to claim on origin chain\n function claim(bytes memory request) external;\n\n /// @notice Cancels an outstanding bridge transaction in case optimistic bridging failed and returns the full amount\n /// to the original sender.\n /// @param request The encoded bridge transaction to refund\n function cancel(bytes memory request) external;\n\n /// @notice Checks if a transaction has been relayed\n /// @param transactionId The ID of the transaction to check\n /// @return True if the transaction has been relayed, false otherwise\n function bridgeRelays(bytes32 transactionId) external view returns (bool);\n\n /// @notice Returns the status of a bridge transaction\n /// @param transactionId The ID of the bridge transaction\n /// @return BridgeStatus Status of the bridge transaction\n function bridgeStatuses(bytes32 transactionId) external view returns (BridgeStatus);\n\n /// @notice Returns the timestamp and relayer of a bridge proof\n /// @param transactionId The ID of the bridge transaction\n /// @return timestamp The timestamp of the bridge proof\n /// @return relayer The relayer address of the bridge proof\n function bridgeProofs(bytes32 transactionId) external view returns (uint96 timestamp, address relayer);\n\n /// @notice Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\n /// @param request The bridge request to decode\n function getBridgeTransactionV2(bytes memory request) external view returns (BridgeTransactionV2 memory);\n}\n\n// contracts/utils/MulticallTarget.sol\n\n// solhint-disable avoid-low-level-calls\n/// @notice Template for a contract that supports batched calls (preserving the msg.sender).\n/// Only calls with zero msg.value could be batched.\nabstract contract MulticallTarget is IMulticallTarget {\n error MulticallTarget__UndeterminedRevert();\n\n /// @notice Perform a batched call to this contract, preserving the msg.sender.\n /// The return data from each call is discarded.\n /// @dev The method is non-payable, so only calls with `msg.value == 0` could be batched.\n /// It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag.\n /// Otherwise, the whole batch call will be reverted with the original revert reason.\n /// @param data List of abi-encoded calldata for the calls to perform.\n /// @param ignoreReverts Whether to ignore the revert errors from the calls.\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external {\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\n if (!success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(result);\n }\n }\n }\n\n /// @notice Perform a batched call to this contract, preserving the msg.sender.\n /// The return data from each call is preserved.\n /// @dev The method is non-payable, so only calls with `msg.value == 0` could be batched.\n /// It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag.\n /// Otherwise, the whole batch call will be reverted with the original revert reason.\n /// @param data List of abi-encoded calldata for the calls to perform.\n /// @param ignoreReverts Whether to ignore the revert errors from the calls.\n /// @return results List of results from the calls: `(success, returnData)`.\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results)\n {\n results = new Result[](data.length);\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (results[i].success, results[i].returnData) = address(this).delegatecall(data[i]);\n if (!results[i].success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(results[i].returnData);\n }\n }\n }\n\n /// @dev Bubbles the revert message from the underlying call.\n /// Note: preserves the same custom error or revert string, if one was used.\n /// Source: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v5.0.2/contracts/utils/Address.sol#L143-L158\n function _bubbleRevert(bytes memory returnData) internal pure {\n // Look for revert reason and bubble it up if present\n if (returnData.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n // solhint-disable-next-line no-inline-assembly\n assembly {\n let returndata_size := mload(returnData)\n revert(add(32, returnData), returndata_size)\n }\n } else {\n revert MulticallTarget__UndeterminedRevert();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// contracts/libs/BridgeTransactionV2.sol\n\n// solhint-disable no-inline-assembly\nlibrary BridgeTransactionV2Lib {\n uint16 internal constant VERSION = 2;\n\n // Offsets of the fields in the packed BridgeTransactionV2 struct\n // uint16 version [000 .. 002)\n // uint32 originChainId [002 .. 006)\n // uint32 destChainId [006 .. 010)\n // address originSender [010 .. 030)\n // address destRecipient [030 .. 050)\n // address originToken [050 .. 070)\n // address destToken [070 .. 090)\n // uint256 originAmount [090 .. 122)\n // uint256 destAmount [122 .. 154)\n // uint256 originFeeAmount [154 .. 186)\n // uint256 deadline [186 .. 218)\n // uint256 nonce [218 .. 250)\n // address exclusivityRelayer [250 .. 270)\n // uint256 exclusivityEndTime [270 .. 302)\n // uint256 zapNative [302 .. 334)\n // bytes zapData [334 .. ***)\n\n // forgefmt: disable-start\n uint256 private constant OFFSET_ORIGIN_CHAIN_ID = 2;\n uint256 private constant OFFSET_DEST_CHAIN_ID = 6;\n uint256 private constant OFFSET_ORIGIN_SENDER = 10;\n uint256 private constant OFFSET_DEST_RECIPIENT = 30;\n uint256 private constant OFFSET_ORIGIN_TOKEN = 50;\n uint256 private constant OFFSET_DEST_TOKEN = 70;\n uint256 private constant OFFSET_ORIGIN_AMOUNT = 90;\n uint256 private constant OFFSET_DEST_AMOUNT = 122;\n uint256 private constant OFFSET_ORIGIN_FEE_AMOUNT = 154;\n uint256 private constant OFFSET_DEADLINE = 186;\n uint256 private constant OFFSET_NONCE = 218;\n uint256 private constant OFFSET_EXCLUSIVITY_RELAYER = 250;\n uint256 private constant OFFSET_EXCLUSIVITY_END_TIME = 270;\n uint256 private constant OFFSET_ZAP_NATIVE = 302;\n uint256 private constant OFFSET_ZAP_DATA = 334;\n // forgefmt: disable-end\n\n error BridgeTransactionV2__InvalidEncodedTx();\n error BridgeTransactionV2__UnsupportedVersion(uint16 version);\n\n /// @notice Validates the encoded transaction to be a tightly packed encoded payload for BridgeTransactionV2.\n /// @dev Checks the minimum length and the version, use this function before decoding any of the fields.\n function validateV2(bytes calldata encodedTx) internal pure {\n // Check the minimum length: must at least include all static fields.\n if (encodedTx.length \u003c OFFSET_ZAP_DATA) revert BridgeTransactionV2__InvalidEncodedTx();\n // Once we validated the length, we can be sure that the version field is present.\n uint16 version_ = version(encodedTx);\n if (version_ != VERSION) revert BridgeTransactionV2__UnsupportedVersion(version_);\n }\n\n /// @notice Encodes the BridgeTransactionV2 struct by tightly packing the fields.\n /// @dev `abi.decode` will not work as a result of the tightly packed fields. Use `decodeV2` to decode instead.\n function encodeV2(IFastBridgeV2.BridgeTransactionV2 memory bridgeTx) internal pure returns (bytes memory) {\n // We split the encoding into two parts to avoid stack-too-deep error\n bytes memory firstPart = abi.encodePacked(\n VERSION,\n bridgeTx.originChainId,\n bridgeTx.destChainId,\n bridgeTx.originSender,\n bridgeTx.destRecipient,\n bridgeTx.originToken,\n bridgeTx.destToken,\n bridgeTx.originAmount\n );\n return abi.encodePacked(\n firstPart,\n bridgeTx.destAmount,\n bridgeTx.originFeeAmount,\n // Note: we skip the deprecated `sendChainGas` flag, which was present in BridgeTransaction V1\n bridgeTx.deadline,\n bridgeTx.nonce,\n // New V2 fields: exclusivity\n bridgeTx.exclusivityRelayer,\n bridgeTx.exclusivityEndTime,\n // New V2 fields: Zap\n bridgeTx.zapNative,\n bridgeTx.zapData\n );\n }\n\n /// @notice Decodes the BridgeTransactionV2 struct from the encoded transaction.\n /// @dev Encoded BridgeTransactionV2 struct must be tightly packed.\n /// Use `validateV2` before decoding to ensure the encoded transaction is valid.\n function decodeV2(bytes calldata encodedTx)\n internal\n pure\n returns (IFastBridgeV2.BridgeTransactionV2 memory bridgeTx)\n {\n bridgeTx.originChainId = originChainId(encodedTx);\n bridgeTx.destChainId = destChainId(encodedTx);\n bridgeTx.originSender = originSender(encodedTx);\n bridgeTx.destRecipient = destRecipient(encodedTx);\n bridgeTx.originToken = originToken(encodedTx);\n bridgeTx.destToken = destToken(encodedTx);\n bridgeTx.originAmount = originAmount(encodedTx);\n bridgeTx.destAmount = destAmount(encodedTx);\n bridgeTx.originFeeAmount = originFeeAmount(encodedTx);\n bridgeTx.deadline = deadline(encodedTx);\n bridgeTx.nonce = nonce(encodedTx);\n bridgeTx.exclusivityRelayer = exclusivityRelayer(encodedTx);\n bridgeTx.exclusivityEndTime = exclusivityEndTime(encodedTx);\n bridgeTx.zapNative = zapNative(encodedTx);\n bridgeTx.zapData = zapData(encodedTx);\n }\n\n /// @notice Extracts the version from the encoded transaction.\n function version(bytes calldata encodedTx) internal pure returns (uint16 version_) {\n // Load 32 bytes from the start and shift it 240 bits to the right to get the highest 16 bits.\n assembly {\n version_ := shr(240, calldataload(encodedTx.offset))\n }\n }\n\n /// @notice Extracts the origin chain ID from the encoded transaction.\n function originChainId(bytes calldata encodedTx) internal pure returns (uint32 originChainId_) {\n // Load 32 bytes from the offset and shift it 224 bits to the right to get the highest 32 bits.\n assembly {\n originChainId_ := shr(224, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_CHAIN_ID)))\n }\n }\n\n /// @notice Extracts the destination chain ID from the encoded transaction.\n function destChainId(bytes calldata encodedTx) internal pure returns (uint32 destChainId_) {\n // Load 32 bytes from the offset and shift it 224 bits to the right to get the highest 32 bits.\n assembly {\n destChainId_ := shr(224, calldataload(add(encodedTx.offset, OFFSET_DEST_CHAIN_ID)))\n }\n }\n\n /// @notice Extracts the origin sender from the encoded transaction.\n function originSender(bytes calldata encodedTx) internal pure returns (address originSender_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n originSender_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_SENDER)))\n }\n }\n\n /// @notice Extracts the destination recipient from the encoded transaction.\n function destRecipient(bytes calldata encodedTx) internal pure returns (address destRecipient_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n destRecipient_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_DEST_RECIPIENT)))\n }\n }\n\n /// @notice Extracts the origin token from the encoded transaction.\n function originToken(bytes calldata encodedTx) internal pure returns (address originToken_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n originToken_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_TOKEN)))\n }\n }\n\n /// @notice Extracts the destination token from the encoded transaction.\n function destToken(bytes calldata encodedTx) internal pure returns (address destToken_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n destToken_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_DEST_TOKEN)))\n }\n }\n\n /// @notice Extracts the origin amount from the encoded transaction.\n function originAmount(bytes calldata encodedTx) internal pure returns (uint256 originAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n originAmount_ := calldataload(add(encodedTx.offset, OFFSET_ORIGIN_AMOUNT))\n }\n }\n\n /// @notice Extracts the destination amount from the encoded transaction.\n function destAmount(bytes calldata encodedTx) internal pure returns (uint256 destAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n destAmount_ := calldataload(add(encodedTx.offset, OFFSET_DEST_AMOUNT))\n }\n }\n\n /// @notice Extracts the origin fee amount from the encoded transaction.\n function originFeeAmount(bytes calldata encodedTx) internal pure returns (uint256 originFeeAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n originFeeAmount_ := calldataload(add(encodedTx.offset, OFFSET_ORIGIN_FEE_AMOUNT))\n }\n }\n\n /// @notice Extracts the deadline from the encoded transaction.\n function deadline(bytes calldata encodedTx) internal pure returns (uint256 deadline_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n deadline_ := calldataload(add(encodedTx.offset, OFFSET_DEADLINE))\n }\n }\n\n /// @notice Extracts the nonce from the encoded transaction.\n function nonce(bytes calldata encodedTx) internal pure returns (uint256 nonce_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n nonce_ := calldataload(add(encodedTx.offset, OFFSET_NONCE))\n }\n }\n\n /// @notice Extracts the exclusivity relayer from the encoded transaction.\n function exclusivityRelayer(bytes calldata encodedTx) internal pure returns (address exclusivityRelayer_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n exclusivityRelayer_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_EXCLUSIVITY_RELAYER)))\n }\n }\n\n /// @notice Extracts the exclusivity end time from the encoded transaction.\n function exclusivityEndTime(bytes calldata encodedTx) internal pure returns (uint256 exclusivityEndTime_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n exclusivityEndTime_ := calldataload(add(encodedTx.offset, OFFSET_EXCLUSIVITY_END_TIME))\n }\n }\n\n /// @notice Extracts the Zap's native value from the encoded transaction.\n function zapNative(bytes calldata encodedTx) internal pure returns (uint256 zapNative_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n zapNative_ := calldataload(add(encodedTx.offset, OFFSET_ZAP_NATIVE))\n }\n }\n\n /// @notice Extracts the Zap's data from the encoded transaction.\n function zapData(bytes calldata encodedTx) internal pure returns (bytes calldata zapData_) {\n zapData_ = encodedTx[OFFSET_ZAP_DATA:];\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/AdminV2.sol\n\ncontract AdminV2 is AccessControlEnumerable, IAdminV2, IAdminV2Errors {\n using SafeERC20 for IERC20;\n\n /// @notice Address reserved for native gas token (ETH on Ethereum and most L2s, AVAX on Avalanche, etc)\n address public constant NATIVE_GAS_TOKEN = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Role identifier for Quoter API's off-chain authentication.\n /// @dev Only addresses with this role can post FastBridge quotes to the API.\n bytes32 public constant QUOTER_ROLE = keccak256(\"QUOTER_ROLE\");\n\n /// @notice Role identifier for Prover's on-chain authentication in FastBridge.\n /// @dev Only addresses with this role can provide proofs that a FastBridge request has been relayed.\n bytes32 public constant PROVER_ROLE = keccak256(\"PROVER_ROLE\");\n\n /// @notice Role identifier for Guard's on-chain authentication in FastBridge.\n /// @dev Only addresses with this role can dispute submitted relay proofs during the dispute period.\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n\n /// @notice Role identifier for Canceler's on-chain authentication in FastBridge.\n /// @dev Only addresses with this role can cancel a FastBridge transaction without the cancel delay.\n bytes32 public constant CANCELER_ROLE = keccak256(\"CANCELER_ROLE\");\n\n /// @notice Role identifier for Governor's on-chain administrative authority.\n /// @dev Only addresses with this role can perform administrative tasks within the contract.\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n /// @notice Denominator for fee rates, represents 100%.\n uint256 public constant FEE_BPS = 1e6;\n /// @notice Maximum protocol fee rate: 1% on origin amount.\n uint256 public constant FEE_RATE_MAX = 0.01e6;\n\n /// @notice Minimum cancel delay that can be set by the governor.\n uint256 public constant MIN_CANCEL_DELAY = 1 hours;\n /// @notice Default cancel delay set during the contract deployment.\n uint256 public constant DEFAULT_CANCEL_DELAY = 1 days;\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Delay for a transaction after which it could be permisionlessly cancelled\n uint256 public cancelDelay;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Use ZapNative V2 requests instead.\n uint256 public immutable chainGasAmount = 0;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n _setCancelDelay(DEFAULT_CANCEL_DELAY);\n }\n\n /// @notice Allows the contract governor to set the cancel delay. The cancel delay is the time after the transaction\n /// deadline after which it can be permissionlessly cancelled, if it hasn't been proven by any of the Relayers.\n function setCancelDelay(uint256 newCancelDelay) external onlyRole(GOVERNOR_ROLE) {\n _setCancelDelay(newCancelDelay);\n }\n\n /// @notice Allows the contract governor to set the protocol fee rate. The protocol fee is taken from the origin\n /// amount only for completed and claimed transactions.\n /// @dev The protocol fee is abstracted away from the relayers, they always operate using the amounts after fees:\n /// what they see as the origin amount emitted in the log is what they get credited with.\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n if (newFeeRate \u003e FEE_RATE_MAX) revert FeeRateAboveMax();\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n /// @notice Allows the contract governor to sweep the accumulated protocol fees in the contract.\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n emit FeesSwept(token, recipient, feeAmount);\n /// Sweep the fees as the last transaction action\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(recipient), feeAmount);\n } else {\n IERC20(token).safeTransfer(recipient, feeAmount);\n }\n }\n\n /// @notice Internal function to set the cancel delay. Security checks are performed outside of this function.\n function _setCancelDelay(uint256 newCancelDelay) private {\n if (newCancelDelay \u003c MIN_CANCEL_DELAY) revert CancelDelayBelowMin();\n uint256 oldCancelDelay = cancelDelay;\n cancelDelay = newCancelDelay;\n emit CancelDelayUpdated(oldCancelDelay, newCancelDelay);\n }\n}\n\n// contracts/FastBridgeV2.sol\n\n/// @notice FastBridgeV2 is a contract for bridging tokens across chains.\ncontract FastBridgeV2 is AdminV2, MulticallTarget, IFastBridgeV2, IFastBridgeV2Errors {\n using BridgeTransactionV2Lib for bytes;\n using SafeERC20 for IERC20;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n /// @notice Maximum length of accepted zapData\n uint256 public constant MAX_ZAP_DATA_LENGTH = 2 ** 16 - 1;\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeTxDetails) public bridgeTxDetails;\n /// @notice Relay details on destination chain\n mapping(bytes32 =\u003e BridgeRelay) public bridgeRelayDetails;\n /// @notice Unique bridge nonces tracked per originSender\n mapping(address =\u003e uint256) public senderNonces;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Replaced by senderNonces\n uint256 public immutable nonce = 0;\n /// @notice the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) AdminV2(_owner) {\n deployBlock = block.number;\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n bridge({\n params: params,\n paramsV2: BridgeParamsV2({\n quoteRelayer: address(0),\n quoteExclusivitySeconds: 0,\n quoteId: bytes(\"\"),\n zapNative: 0,\n zapData: bytes(\"\")\n })\n });\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes calldata request) external payable {\n // relay override will validate the request\n relay({request: request, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes calldata request, bytes32 destTxHash) external {\n request.validateV2();\n prove({transactionId: keccak256(request), destTxHash: destTxHash, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridgeV2\n function claim(bytes calldata request) external {\n // claim override will validate the request\n claim({request: request, to: address(0)});\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Aggregate the read operations from the same storage slot\n address disputedRelayer = $.proofRelayer;\n BridgeStatus status = $.status;\n uint56 proofBlockTimestamp = $.proofBlockTimestamp;\n // Can only dispute a RELAYER_PROVED transaction within the dispute period\n if (status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(proofBlockTimestamp) \u003e DISPUTE_PERIOD) {\n revert DisputePeriodPassed();\n }\n // Update status to REQUESTED and delete the disputed proof details\n // Note: these are storage writes\n $.status = BridgeStatus.REQUESTED;\n $.proofRelayer = address(0);\n $.proofBlockTimestamp = 0;\n\n emit BridgeProofDisputed(transactionId, disputedRelayer);\n }\n\n /// Note: this function is deprecated and will be removed in a future version.\n /// @inheritdoc IFastBridge\n function refund(bytes calldata request) external {\n cancel(request);\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // The correct relayer can only claim a RELAYER_PROVED transaction after the dispute period\n if ($.status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if ($.proofRelayer != relayer) revert SenderIncorrect();\n return _timeSince($.proofBlockTimestamp) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n /// @dev This method is added to achieve backwards compatibility with decoding requests into V1 structs:\n /// - `zapNative` is partially reported as a zero/non-zero flag\n /// - `zapData` is ignored\n /// In order to process all kinds of requests use getBridgeTransactionV2 instead.\n function getBridgeTransaction(bytes calldata request) external view returns (BridgeTransaction memory) {\n // Try decoding into V2 struct first. This will revert if V1 struct is passed\n try this.getBridgeTransactionV2(request) returns (BridgeTransactionV2 memory txV2) {\n // Note: we entirely ignore the zapData field, as it was not present in V1\n return BridgeTransaction({\n originChainId: txV2.originChainId,\n destChainId: txV2.destChainId,\n originSender: txV2.originSender,\n destRecipient: txV2.destRecipient,\n originToken: txV2.originToken,\n destToken: txV2.destToken,\n originAmount: txV2.originAmount,\n destAmount: txV2.destAmount,\n originFeeAmount: txV2.originFeeAmount,\n sendChainGas: txV2.zapNative != 0,\n deadline: txV2.deadline,\n nonce: txV2.nonce\n });\n } catch {\n // Fallback to V1 struct\n return abi.decode(request, (BridgeTransaction));\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function getBridgeTransactionV2(bytes calldata request) external pure returns (BridgeTransactionV2 memory) {\n request.validateV2();\n return BridgeTransactionV2Lib.decodeV2(request);\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) public payable {\n int256 exclusivityEndTime = 0;\n // if relayer exclusivity is not intended for this bridge, set exclusivityEndTime to static zero\n // otherwise, set exclusivity to expire at the current block ts offset by quoteExclusivitySeconds\n if (paramsV2.quoteRelayer != address(0)) {\n exclusivityEndTime = int256(block.timestamp) + paramsV2.quoteExclusivitySeconds;\n }\n _validateBridgeParams(params, paramsV2, exclusivityEndTime);\n\n // transfer tokens to bridge contract\n /// @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _takeBridgedUserAsset(params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) {\n originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n }\n\n // set status to requested\n bytes memory request = BridgeTransactionV2Lib.encodeV2(\n BridgeTransactionV2({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n deadline: params.deadline,\n nonce: senderNonces[params.sender]++, // increment nonce on every bridge\n exclusivityRelayer: paramsV2.quoteRelayer,\n // We checked exclusivityEndTime to be in range [0 .. params.deadline] above, so can safely cast\n exclusivityEndTime: uint256(exclusivityEndTime),\n zapNative: paramsV2.zapNative,\n zapData: paramsV2.zapData\n })\n );\n bytes32 transactionId = keccak256(request);\n // Note: the tx status will be updated throughout the tx lifecycle, while destChainId is set once here\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n bridgeTxDetails[transactionId].destChainId = params.dstChainId;\n\n emit BridgeRequested({\n transactionId: transactionId,\n sender: params.sender,\n request: request,\n destChainId: params.dstChainId,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n sendChainGas: paramsV2.zapNative != 0\n });\n emit BridgeQuoteDetails(transactionId, paramsV2.quoteId);\n }\n\n /// @inheritdoc IFastBridgeV2\n function relay(bytes calldata request, address relayer) public payable {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n _validateRelayParams(request, transactionId, relayer);\n // mark bridge transaction as relayed\n bridgeRelayDetails[transactionId] =\n BridgeRelay({blockNumber: uint48(block.number), blockTimestamp: uint48(block.timestamp), relayer: relayer});\n\n // transfer tokens to recipient on destination chain and trigger Zap if requested\n address to = request.destRecipient();\n address token = request.destToken();\n uint256 amount = request.destAmount();\n uint256 zapNative = request.zapNative();\n\n // Emit the event before any external calls\n emit BridgeRelayed({\n transactionId: transactionId,\n relayer: relayer,\n to: to,\n originChainId: request.originChainId(),\n originToken: request.originToken(),\n destToken: token,\n originAmount: request.originAmount(),\n destAmount: amount,\n chainGasAmount: zapNative\n });\n\n // All state changes have been done at this point, can proceed to the external calls.\n // This follows the checks-effects-interactions pattern to mitigate potential reentrancy attacks.\n if (token == NATIVE_GAS_TOKEN) {\n // For the native gas token, additional zapNative is not allowed\n if (zapNative != 0) revert ZapNativeNotSupported();\n // Check that the correct msg.value was sent\n if (msg.value != amount) revert MsgValueIncorrect();\n // Don't do a native transfer yet: we will handle it alongside the Zap below\n } else {\n // For ERC20s, we check that the correct msg.value was sent\n if (msg.value != zapNative) revert MsgValueIncorrect();\n // We need to transfer the tokens from the Relayer to the recipient first before performing an\n // optional post-transfer Zap.\n IERC20(token).safeTransferFrom(msg.sender, to, amount);\n }\n // At this point we have done:\n // - Transferred the requested amount of ERC20 tokens to the recipient.\n // At this point we have confirmed:\n // - For ERC20s: msg.value matches the requested zapNative amount.\n // - For the native gas token: msg.value matches the requested destAmount.\n // Remaining optional things to do:\n // - Forward the full msg.value to the recipient (if non-zero).\n // - Trigger a Zap (if zapData is present).\n bytes calldata zapData = request.zapData();\n if (zapData.length != 0) {\n // Zap Data is present: Zap has been requested by the recipient. Trigger it forwarding the full msg.value.\n\n // Note: if token has a fee on transfers, the recipient will have received less than `amount`.\n // This is a very niche edge case and should be handled by the recipient contract.\n _triggerZapWithChecks({recipient: to, token: token, amount: amount, zapData: zapData});\n } else if (msg.value != 0) {\n // Zap Data is missing, but msg.value was sent. This could happen in two different cases:\n // - Relay with the native gas token is happening.\n // - Relay with ERC20 is happening, with a `zapNative \u003e 0` request.\n // In both cases, we need to transfer the full msg.value to the recipient.\n Address.sendValue(payable(to), msg.value);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) public onlyRole(PROVER_ROLE) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n\n // Can only prove a REQUESTED transaction\n if ($.status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n // Update status to RELAYER_PROVED and store the proof details\n // Note: these are storage writes\n $.status = BridgeStatus.RELAYER_PROVED;\n $.proofBlockTimestamp = uint56(block.timestamp);\n $.proofRelayer = relayer;\n\n emit BridgeProofProvided(transactionId, relayer, destTxHash);\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes calldata request, address to) public {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Aggregate the read operations from the same storage slot\n address proofRelayer = $.proofRelayer;\n BridgeStatus status = $.status;\n uint56 proofBlockTimestamp = $.proofBlockTimestamp;\n\n // Can only claim a RELAYER_PROVED transaction after the dispute period\n if (status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(proofBlockTimestamp) \u003c= DISPUTE_PERIOD) {\n revert DisputePeriodNotPassed();\n }\n\n if (to == address(0)) {\n // Anyone could claim the funds to the proven relayer on their behalf\n to = proofRelayer;\n } else if (proofRelayer != msg.sender) {\n // Only the proven relayer could specify an address to claim the funds to\n revert SenderIncorrect();\n }\n\n // Update status to RELAYER_CLAIMED and transfer the origin collateral to the specified claim address\n // Note: this is a storage write\n $.status = BridgeStatus.RELAYER_CLAIMED;\n\n address token = request.originToken();\n uint256 amount = request.originAmount();\n // Update protocol fees if origin fee amount exists\n uint256 originFeeAmount = request.originFeeAmount();\n if (originFeeAmount \u003e 0) protocolFees[token] += originFeeAmount;\n // Emit the event before any external calls\n emit BridgeDepositClaimed(transactionId, proofRelayer, to, token, amount);\n // Complete the relayer claim as the last transaction action\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(to), amount);\n } else {\n IERC20(token).safeTransfer(to, amount);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function cancel(bytes calldata request) public {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Can only cancel a REQUESTED transaction after its deadline expires\n if ($.status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n uint256 deadline = request.deadline();\n // Permissionless cancel is only allowed after `cancelDelay` on top of the deadline\n if (!hasRole(CANCELER_ROLE, msg.sender)) deadline += cancelDelay;\n if (block.timestamp \u003c= deadline) revert DeadlineNotExceeded();\n // Update status to REFUNDED and return the full amount (collateral + protocol fees) to the original sender.\n // The protocol fees are only updated when the transaction is claimed, so we don't need to update them here.\n // Note: this is a storage write\n $.status = BridgeStatus.REFUNDED;\n\n address to = request.originSender();\n address token = request.originToken();\n uint256 amount = request.originAmount() + request.originFeeAmount();\n // Emit the event before any external calls\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n // Complete the user cancel as the last transaction action\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(to), amount);\n } else {\n IERC20(token).safeTransfer(to, amount);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeStatuses(bytes32 transactionId) public view returns (BridgeStatus status) {\n return bridgeTxDetails[transactionId].status;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeProofs(bytes32 transactionId) public view returns (uint96 timestamp, address relayer) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n\n timestamp = $.proofBlockTimestamp;\n relayer = $.proofRelayer;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeRelays(bytes32 transactionId) public view returns (bool) {\n // has this transactionId been relayed?\n return bridgeRelayDetails[transactionId].relayer != address(0);\n }\n\n /// @notice Takes the bridged asset from the user into FastBridgeV2 custody. It will be later\n /// claimed by the relayer who completed the relay on destination chain, or transferred back to the user\n /// via the cancel function should no one complete the relay.\n function _takeBridgedUserAsset(address token, uint256 amount) internal returns (uint256 amountTaken) {\n if (token == NATIVE_GAS_TOKEN) {\n // For the native gas token, we just need to check that the supplied msg.value is correct.\n // Supplied `msg.value` is already in FastBridgeV2 custody.\n if (amount != msg.value) revert MsgValueIncorrect();\n amountTaken = msg.value;\n } else {\n // For ERC20s, token is explicitly transferred from the user to FastBridgeV2.\n // We don't allow non-zero `msg.value` to avoid extra funds from being stuck in FastBridgeV2.\n if (msg.value != 0) revert MsgValueIncorrect();\n // Throw an explicit error if the provided token address is not a contract\n if (token.code.length == 0) revert TokenNotContract();\n amountTaken = IERC20(token).balanceOf(address(this));\n IERC20(token).safeTransferFrom(msg.sender, address(this), amount);\n // Use the balance difference as the amount taken in case of fee on transfer tokens.\n amountTaken = IERC20(token).balanceOf(address(this)) - amountTaken;\n }\n }\n\n /// @notice Calls the Recipient's hook function with the specified zapData and performs\n /// all the necessary checks for the returned value.\n function _triggerZapWithChecks(address recipient, address token, uint256 amount, bytes calldata zapData) internal {\n // This will bubble any revert messages from the hook function\n bytes memory returnData = Address.functionCallWithValue({\n target: recipient,\n data: abi.encodeCall(IZapRecipient.zap, (token, amount, zapData)),\n // Note: see `relay()` for reasoning behind passing msg.value\n value: msg.value\n });\n // Explicit revert if no return data at all\n if (returnData.length == 0) revert RecipientNoReturnValue();\n // Check that exactly a single return value was returned\n if (returnData.length != 32) revert RecipientIncorrectReturnValue();\n // Return value should be abi-encoded hook function selector\n if (bytes32(returnData) != bytes32(IZapRecipient.zap.selector)) {\n revert RecipientIncorrectReturnValue();\n }\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint56(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint56).max but\n /// proof.timestamp \u003c type(uint56).max via unchecked statement\n /// @param proofBlockTimestamp The bridge proof block timestamp\n /// @return delta Time delta since proof submitted\n function _timeSince(uint56 proofBlockTimestamp) internal view returns (uint256 delta) {\n unchecked {\n delta = uint56(block.timestamp) - proofBlockTimestamp;\n }\n }\n\n /// @notice Performs all the necessary checks for a bridge to happen.\n /// @dev There's no good way to refactor this function to reduce cyclomatic complexity due to\n /// the number of checks that need to be performed, so we skip the code-complexity rule here.\n // solhint-disable-next-line code-complexity\n function _validateBridgeParams(\n BridgeParams memory params,\n BridgeParamsV2 memory paramsV2,\n int256 exclusivityEndTime\n )\n internal\n view\n {\n // Check V1 (legacy) params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.sender == address(0) || params.to == address(0)) revert ZeroAddress();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n // Check V2 params\n if (paramsV2.zapData.length \u003e MAX_ZAP_DATA_LENGTH) revert ZapDataLengthAboveMax();\n if (paramsV2.zapNative != 0 \u0026\u0026 params.destToken == NATIVE_GAS_TOKEN) {\n revert ZapNativeNotSupported();\n }\n // exclusivityEndTime must be in range [0 .. params.deadline]\n if (exclusivityEndTime \u003c 0 || exclusivityEndTime \u003e int256(params.deadline)) {\n revert ExclusivityParamsIncorrect();\n }\n }\n\n /// @notice Performs all the necessary checks for a relay to happen.\n function _validateRelayParams(bytes calldata request, bytes32 transactionId, address relayer) internal view {\n if (relayer == address(0)) revert ZeroAddress();\n // Check if the transaction has already been relayed\n if (bridgeRelays(transactionId)) revert TransactionRelayed();\n if (request.destChainId() != block.chainid) revert ChainIncorrect();\n // Check the deadline for relay to happen\n if (block.timestamp \u003e request.deadline()) revert DeadlineExceeded();\n // Check the exclusivity period, if it is still ongoing\n address exclRelayer = request.exclusivityRelayer();\n if (exclRelayer != address(0) \u0026\u0026 exclRelayer != relayer \u0026\u0026 block.timestamp \u003c= request.exclusivityEndTime()) {\n revert ExclusivityPeriodNotPassed();\n }\n }\n}\n","language":"Solidity","languageVersion":"0.8.24","compilerVersion":"0.8.24","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"61585:5018:0:-:0;;;;;;;;;;;;;;;-1:-1:-1;;;61585:5018:0;;;;;;;;;;;;;;;;;","srcMapRuntime":"61585:5018:0:-:0;;;;;;;;","abiDefinition":[{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"currentAllowance","type":"uint256"},{"internalType":"uint256","name":"requestedDecrease","type":"uint256"}],"name":"SafeERC20FailedDecreaseAllowance","type":"error"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"SafeERC20FailedOperation","type":"error"}],"userDoc":{"kind":"user","methods":{},"version":1},"developerDoc":{"details":"Wrappers around ERC20 operations that throw on failure (when the token contract returns false). Tokens that return no value (and instead revert or throw on failure) are also supported, non-reverting calls are assumed to be successful. To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract, which allows you to call the safe operations as `token.safeTransfer(...)`, etc.","errors":{"SafeERC20FailedDecreaseAllowance(address,uint256,uint256)":[{"details":"Indicates a failed `decreaseAllowance` request."}],"SafeERC20FailedOperation(address)":[{"details":"An operation with an ERC20 token failed."}]},"kind":"dev","methods":{},"title":"SafeERC20","version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"currentAllowance\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"requestedDecrease\",\"type\":\"uint256\"}],\"name\":\"SafeERC20FailedDecreaseAllowance\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"}],\"name\":\"SafeERC20FailedOperation\",\"type\":\"error\"}],\"devdoc\":{\"details\":\"Wrappers around ERC20 operations that throw on failure (when the token contract returns false). Tokens that return no value (and instead revert or throw on failure) are also supported, non-reverting calls are assumed to be successful. To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract, which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\",\"errors\":{\"SafeERC20FailedDecreaseAllowance(address,uint256,uint256)\":[{\"details\":\"Indicates a failed `decreaseAllowance` request.\"}],\"SafeERC20FailedOperation(address)\":[{\"details\":\"An operation with an ERC20 token failed.\"}]},\"kind\":\"dev\",\"methods\":{},\"title\":\"SafeERC20\",\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeV2.sol\":\"SafeERC20\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeV2.sol\":{\"keccak256\":\"0xac79c463688a682ca706a4ef95e7817b83548cdfa8182ba0426ac7e5e07613d8\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://b3ecb7097381287cafc3a73f3a2bb03565115ebb682a85064e0b0dc2f7e2919d\",\"dweb:/ipfs/QmatruW3nYZTksf3CeQ8wwiAG4c7xoEJBEp6drHPtFLBRK\"]}},\"version\":1}"},"hashes":{}}} \ No newline at end of file diff --git a/services/rfq/e2e/setup_test.go b/services/rfq/e2e/setup_test.go index d8ce6d8fab..fe18c9a543 100644 --- a/services/rfq/e2e/setup_test.go +++ b/services/rfq/e2e/setup_test.go @@ -365,14 +365,25 @@ func (i *IntegrationSuite) setupRelayer() { metadata, rfqContract := i.manager.GetFastBridge(i.GetTestContext(), backend) txContext := backend.GetTxContext(i.GetTestContext(), metadata.OwnerPtr()) - relayerRole, err := rfqContract.RELAYERROLE(&bind.CallOpts{Context: i.GetTestContext()}) + proverRole, err := rfqContract.PROVERROLE(&bind.CallOpts{Context: i.GetTestContext()}) if err != nil { - return fmt.Errorf("could not get relayer role: %w", err) + return fmt.Errorf("could not get prover role: %w", err) } - tx, err := rfqContract.GrantRole(txContext.TransactOpts, relayerRole, i.relayerWallet.Address()) + tx, err := rfqContract.GrantRole(txContext.TransactOpts, proverRole, i.relayerWallet.Address()) if err != nil { - return fmt.Errorf("could not grant role: %w", err) + return fmt.Errorf("could not grant prover role: %w", err) + } + backend.WaitForConfirmation(i.GetTestContext(), tx) + + quoterRole, err := rfqContract.QUOTERROLE(&bind.CallOpts{Context: i.GetTestContext()}) + if err != nil { + return fmt.Errorf("could not get quoter role: %w", err) + } + + tx, err = rfqContract.GrantRole(txContext.TransactOpts, quoterRole, i.relayerWallet.Address()) + if err != nil { + return fmt.Errorf("could not grant quoter role: %w", err) } backend.WaitForConfirmation(i.GetTestContext(), tx) From aac6885c1d124e0c7d5f348db08db321e9a93aa0 Mon Sep 17 00:00:00 2001 From: Daniel Wasserman Date: Mon, 25 Nov 2024 14:14:26 -0500 Subject: [PATCH 52/85] [goreleaser] From 8f9d8ec0b8340415cb706d169577accd60d520e7 Mon Sep 17 00:00:00 2001 From: Daniel Wasserman Date: Tue, 26 Nov 2024 12:29:01 -0500 Subject: [PATCH 53/85] Regen contracts w/ function renaming --- .../fastbridgev2/fastbridgev2.abigen.go | 334 +++++++++--------- .../fastbridgev2.contractinfo.json | 2 +- services/rfq/e2e/rfq_test.go | 4 +- services/rfq/relayer/chain/chain.go | 2 +- services/rfq/relayer/service/handlers.go | 2 +- 5 files changed, 172 insertions(+), 172 deletions(-) diff --git a/services/rfq/contracts/fastbridgev2/fastbridgev2.abigen.go b/services/rfq/contracts/fastbridgev2/fastbridgev2.abigen.go index 9e110199da..4d006e8cf2 100644 --- a/services/rfq/contracts/fastbridgev2/fastbridgev2.abigen.go +++ b/services/rfq/contracts/fastbridgev2/fastbridgev2.abigen.go @@ -1833,7 +1833,7 @@ func (_AccessControlEnumerable *AccessControlEnumerableFilterer) ParseRoleRevoke // AddressMetaData contains all meta data concerning the Address contract. var AddressMetaData = &bind.MetaData{ ABI: "[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"}],\"name\":\"AddressEmptyCode\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"AddressInsufficientBalance\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"FailedInnerCall\",\"type\":\"error\"}]", - Bin: "0x60566037600b82828239805160001a607314602a57634e487b7160e01b600052600060045260246000fd5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600080fdfea264697066735822122053e3727ad57bc90f5560dc5a255131033ea91c54c8a147cf6df38af4aac448d564736f6c63430008180033", + Bin: "0x60566037600b82828239805160001a607314602a57634e487b7160e01b600052600060045260246000fd5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600080fdfea26469706673582212209a0af1109cd6979a77a02bde578408e1ed84d2bdf8d75fee43ff2aec21f2c23564736f6c63430008180033", } // AddressABI is the input ABI used to generate the binding from. @@ -2005,7 +2005,7 @@ func (_Address *AddressTransactorRaw) Transact(opts *bind.TransactOpts, method s // AdminV2MetaData contains all meta data concerning the AdminV2 contract. var AdminV2MetaData = &bind.MetaData{ - ABI: "[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_owner\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"AccessControlBadConfirmation\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"neededRole\",\"type\":\"bytes32\"}],\"name\":\"AccessControlUnauthorizedAccount\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"}],\"name\":\"AddressEmptyCode\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"AddressInsufficientBalance\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"CancelDelayBelowMin\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"FailedInnerCall\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"FeeRateAboveMax\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"}],\"name\":\"SafeERC20FailedOperation\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"oldCancelDelay\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newCancelDelay\",\"type\":\"uint256\"}],\"name\":\"CancelDelayUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"oldFeeRate\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newFeeRate\",\"type\":\"uint256\"}],\"name\":\"FeeRateUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"FeesSwept\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"previousAdminRole\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"newAdminRole\",\"type\":\"bytes32\"}],\"name\":\"RoleAdminChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleGranted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleRevoked\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"CANCELER_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"DEFAULT_ADMIN_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"DEFAULT_CANCEL_DELAY\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"FEE_BPS\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"FEE_RATE_MAX\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"GOVERNOR_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"GUARD_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"MIN_CANCEL_DELAY\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"NATIVE_GAS_TOKEN\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"PROVER_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"QUOTER_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"cancelDelay\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"chainGasAmount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"}],\"name\":\"getRoleAdmin\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"index\",\"type\":\"uint256\"}],\"name\":\"getRoleMember\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"}],\"name\":\"getRoleMemberCount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"grantRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"hasRole\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"protocolFeeRate\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"protocolFees\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"callerConfirmation\",\"type\":\"address\"}],\"name\":\"renounceRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"revokeRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"newCancelDelay\",\"type\":\"uint256\"}],\"name\":\"setCancelDelay\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"newFeeRate\",\"type\":\"uint256\"}],\"name\":\"setProtocolFeeRate\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes4\",\"name\":\"interfaceId\",\"type\":\"bytes4\"}],\"name\":\"supportsInterface\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"}],\"name\":\"sweepProtocolFees\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", + ABI: "[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"defaultAdmin\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"AccessControlBadConfirmation\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"neededRole\",\"type\":\"bytes32\"}],\"name\":\"AccessControlUnauthorizedAccount\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"}],\"name\":\"AddressEmptyCode\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"AddressInsufficientBalance\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"CancelDelayBelowMin\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"FailedInnerCall\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"FeeRateAboveMax\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"}],\"name\":\"SafeERC20FailedOperation\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"oldCancelDelay\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newCancelDelay\",\"type\":\"uint256\"}],\"name\":\"CancelDelayUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"oldFeeRate\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newFeeRate\",\"type\":\"uint256\"}],\"name\":\"FeeRateUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"FeesSwept\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"previousAdminRole\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"newAdminRole\",\"type\":\"bytes32\"}],\"name\":\"RoleAdminChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleGranted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleRevoked\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"CANCELER_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"DEFAULT_ADMIN_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"DEFAULT_CANCEL_DELAY\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"FEE_BPS\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"FEE_RATE_MAX\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"GOVERNOR_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"GUARD_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"MIN_CANCEL_DELAY\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"NATIVE_GAS_TOKEN\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"PROVER_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"QUOTER_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"cancelDelay\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"chainGasAmount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"}],\"name\":\"getRoleAdmin\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"index\",\"type\":\"uint256\"}],\"name\":\"getRoleMember\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"}],\"name\":\"getRoleMemberCount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"grantRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"hasRole\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"protocolFeeRate\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"protocolFees\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"callerConfirmation\",\"type\":\"address\"}],\"name\":\"renounceRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"revokeRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"newCancelDelay\",\"type\":\"uint256\"}],\"name\":\"setCancelDelay\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"newFeeRate\",\"type\":\"uint256\"}],\"name\":\"setProtocolFeeRate\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes4\",\"name\":\"interfaceId\",\"type\":\"bytes4\"}],\"name\":\"supportsInterface\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"}],\"name\":\"sweepProtocolFees\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", Sigs: map[string]string{ "02d2ff66": "CANCELER_ROLE()", "a217fddf": "DEFAULT_ADMIN_ROLE()", @@ -2034,7 +2034,7 @@ var AdminV2MetaData = &bind.MetaData{ "01ffc9a7": "supportsInterface(bytes4)", "06f333f2": "sweepProtocolFees(address,address)", }, - Bin: "0x60a060405260006080523480156200001657600080fd5b50604051620015763803806200157683398101604081905262000039916200020a565b620000466000826200005c565b50620000556201518062000099565b5062000235565b6000806200006b848462000102565b90508015620000905760008481526001602052604090206200008e9084620001b0565b505b90505b92915050565b610e10811015620000bd57604051630e0ea5c760e01b815260040160405180910390fd5b600480549082905560408051828152602081018490527f909f9078b2f6eac1d10f2aae793656c5a67511eb627ebd1d2cb1eb9c0ab94c95910160405180910390a15050565b6000828152602081815260408083206001600160a01b038516845290915281205460ff16620001a7576000838152602081815260408083206001600160a01b03861684529091529020805460ff191660011790556200015e3390565b6001600160a01b0316826001600160a01b0316847f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a450600162000093565b50600062000093565b600062000090836001600160a01b0384166000818152600183016020526040812054620001a75750815460018181018455600084815260208082209093018490558454848252828601909352604090209190915562000093565b6000602082840312156200021d57600080fd5b81516001600160a01b03811681146200009057600080fd5b60805161132562000251600039600061045201526113256000f3fe608060405234801561001057600080fd5b50600436106101ae5760003560e01c80639010d07c116100ee578063bf333f2c11610097578063d547741f11610071578063d547741f146103f3578063dc9a4ef614610406578063dcf844a71461042d578063e00a83e01461044d57600080fd5b8063bf333f2c146103af578063ca15c873146103b9578063ccc57490146103cc57600080fd5b8063930ac180116100c8578063930ac1801461038a578063a217fddf14610394578063b13aa2d61461039c57600080fd5b80639010d07c1461032a57806391d148541461033d578063922b74871461038157600080fd5b80631ea327c51161015b57806336568abe1161013557806336568abe146102de57806358f85880146102f1578063638a0f09146102fa5780637ebe815c1461030357600080fd5b80631ea327c514610295578063248a9ca3146102a85780632f2ff15d146102cb57600080fd5b806306f333f21161018c57806306f333f2146102375780630f5f6ed71461024c5780630f862f1e1461025557600080fd5b806301ffc9a7146101b357806302d2ff66146101db57806303ed0ee514610210575b600080fd5b6101c66101c13660046110ef565b610474565b60405190151581526020015b60405180910390f35b6102027febfdca8e46c0b8dacf9989ee613e35727eadd20a1d5e5ad01a53968c7e5fe07a81565b6040519081526020016101d2565b6102027f043c983c49d46f0e102151eaf8085d4a2e6571d5df2d47b013f39bddfd4a639d81565b61024a61024536600461115a565b6104d0565b005b61020261271081565b61027073eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee81565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016101d2565b61024a6102a336600461118d565b610611565b6102026102b636600461118d565b60009081526020819052604090206001015490565b61024a6102d93660046111a6565b610648565b61024a6102ec3660046111a6565b61066d565b61020260025481565b61020260045481565b6102027f9a04aea0a349253cc7277afafdf6ead6729a3972a47ffb40eaef2c93d4e1bfea81565b6102706103383660046111c9565b6106c6565b6101c661034b3660046111a6565b60009182526020828152604080842073ffffffffffffffffffffffffffffffffffffffff93909316845291905290205460ff1690565b610202610e1081565b6102026201518081565b610202600081565b61024a6103aa36600461118d565b6106e5565b610202620f424081565b6102026103c736600461118d565b610791565b6102027f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f5581565b61024a6104013660046111a6565b6107a8565b6102027f60044782a422109ac08a415e44260ad5d3bad63d96ebe1fac0363399642ee3f281565b61020261043b3660046111eb565b60036020526000908152604090205481565b6102027f000000000000000000000000000000000000000000000000000000000000000081565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f5a05180f0000000000000000000000000000000000000000000000000000000014806104ca57506104ca826107cd565b92915050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f556104fa81610864565b73ffffffffffffffffffffffffffffffffffffffff83166000908152600360205260408120549081900361052e5750505050565b73ffffffffffffffffffffffffffffffffffffffff8481166000818152600360209081526040808320929092558151928352928616928201929092529081018290527f244e51bc38c1452fa8aaf487bcb4bca36c2baa3a5fbdb776b1eabd8dc6d277cd9060600160405180910390a17fffffffffffffffffffffffff111111111111111111111111111111111111111273ffffffffffffffffffffffffffffffffffffffff8516016105e9576105e48382610871565b61060a565b61060a73ffffffffffffffffffffffffffffffffffffffff8516848361094c565b505b505050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f5561063b81610864565b610644826109d9565b5050565b60008281526020819052604090206001015461066381610864565b61060a8383610a5a565b73ffffffffffffffffffffffffffffffffffffffff811633146106bc576040517f6697b23200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61060c8282610a8f565b60008281526001602052604081206106de9083610abc565b9392505050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f5561070f81610864565b61271082111561074b576040517f9b569b8100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600280549083905560408051828152602081018590527f14914da2bf76024616fbe1859783fcd4dbddcb179b1f3a854949fbf920dcb957910160405180910390a1505050565b60008181526001602052604081206104ca90610ac8565b6000828152602081905260409020600101546107c381610864565b61060a8383610a8f565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f7965db0b0000000000000000000000000000000000000000000000000000000014806104ca57507f01ffc9a7000000000000000000000000000000000000000000000000000000007fffffffff000000000000000000000000000000000000000000000000000000008316146104ca565b61086e8133610ad2565b50565b804710156108b2576040517fcd7860590000000000000000000000000000000000000000000000000000000081523060048201526024015b60405180910390fd5b60008273ffffffffffffffffffffffffffffffffffffffff168260405160006040518083038185875af1925050503d806000811461090c576040519150601f19603f3d011682016040523d82523d6000602084013e610911565b606091505b505090508061060c576040517f1425ea4200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040805173ffffffffffffffffffffffffffffffffffffffff8416602482015260448082018490528251808303909101815260649091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fa9059cbb0000000000000000000000000000000000000000000000000000000017905261060c908490610b58565b610e10811015610a15576040517f0e0ea5c700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600480549082905560408051828152602081018490527f909f9078b2f6eac1d10f2aae793656c5a67511eb627ebd1d2cb1eb9c0ab94c95910160405180910390a15050565b600080610a678484610bee565b905080156106de576000848152600160205260409020610a879084610cea565b509392505050565b600080610a9c8484610d0c565b905080156106de576000848152600160205260409020610a879084610dc7565b60006106de8383610de9565b60006104ca825490565b60008281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915290205460ff16610644576040517fe2517d3f00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff82166004820152602481018390526044016108a9565b6000610b7a73ffffffffffffffffffffffffffffffffffffffff841683610e13565b90508051600014158015610b9f575080806020019051810190610b9d9190611206565b155b1561060c576040517f5274afe700000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff841660048201526024016108a9565b60008281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915281205460ff16610ce25760008381526020818152604080832073ffffffffffffffffffffffffffffffffffffffff86168452909152902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055610c803390565b73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16847f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45060016104ca565b5060006104ca565b60006106de8373ffffffffffffffffffffffffffffffffffffffff8416610e21565b60008281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915281205460ff1615610ce25760008381526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8616808552925280832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016905551339286917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a45060016104ca565b60006106de8373ffffffffffffffffffffffffffffffffffffffff8416610e68565b6000826000018281548110610e0057610e00611228565b9060005260206000200154905092915050565b60606106de83836000610f5b565b6000818152600183016020526040812054610ce2575081546001818101845560008481526020808220909301849055845484825282860190935260409020919091556104ca565b60008181526001830160205260408120548015610f51576000610e8c600183611257565b8554909150600090610ea090600190611257565b9050808214610f05576000866000018281548110610ec057610ec0611228565b9060005260206000200154905080876000018481548110610ee357610ee3611228565b6000918252602080832090910192909255918252600188019052604090208390555b8554869080610f1657610f16611291565b6001900381819060005260206000200160009055905585600101600086815260200190815260200160002060009055600193505050506104ca565b60009150506104ca565b606081471015610f99576040517fcd7860590000000000000000000000000000000000000000000000000000000081523060048201526024016108a9565b6000808573ffffffffffffffffffffffffffffffffffffffff168486604051610fc291906112c0565b60006040518083038185875af1925050503d8060008114610fff576040519150601f19603f3d011682016040523d82523d6000602084013e611004565b606091505b509150915061101486838361101e565b9695505050505050565b6060826110335761102e826110ad565b6106de565b8151158015611057575073ffffffffffffffffffffffffffffffffffffffff84163b155b156110a6576040517f9996b31500000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff851660048201526024016108a9565b50806106de565b8051156110bd5780518082602001fd5b6040517f1425ea4200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006020828403121561110157600080fd5b81357fffffffff00000000000000000000000000000000000000000000000000000000811681146106de57600080fd5b803573ffffffffffffffffffffffffffffffffffffffff8116811461115557600080fd5b919050565b6000806040838503121561116d57600080fd5b61117683611131565b915061118460208401611131565b90509250929050565b60006020828403121561119f57600080fd5b5035919050565b600080604083850312156111b957600080fd5b8235915061118460208401611131565b600080604083850312156111dc57600080fd5b50508035926020909101359150565b6000602082840312156111fd57600080fd5b6106de82611131565b60006020828403121561121857600080fd5b815180151581146106de57600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b818103818111156104ca577f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fd5b6000825160005b818110156112e157602081860181015185830152016112c7565b50600092019182525091905056fea264697066735822122079d04eeec7c857b32065468d4b56344ced14fdee358cfecc2cfd327dbced278e64736f6c63430008180033", + Bin: "0x60a060405260006080523480156200001657600080fd5b50604051620015763803806200157683398101604081905262000039916200020a565b620000466000826200005c565b50620000556201518062000099565b5062000235565b6000806200006b848462000102565b90508015620000905760008481526001602052604090206200008e9084620001b0565b505b90505b92915050565b610e10811015620000bd57604051630e0ea5c760e01b815260040160405180910390fd5b600480549082905560408051828152602081018490527f909f9078b2f6eac1d10f2aae793656c5a67511eb627ebd1d2cb1eb9c0ab94c95910160405180910390a15050565b6000828152602081815260408083206001600160a01b038516845290915281205460ff16620001a7576000838152602081815260408083206001600160a01b03861684529091529020805460ff191660011790556200015e3390565b6001600160a01b0316826001600160a01b0316847f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a450600162000093565b50600062000093565b600062000090836001600160a01b0384166000818152600183016020526040812054620001a75750815460018181018455600084815260208082209093018490558454848252828601909352604090209190915562000093565b6000602082840312156200021d57600080fd5b81516001600160a01b03811681146200009057600080fd5b60805161132562000251600039600061045201526113256000f3fe608060405234801561001057600080fd5b50600436106101ae5760003560e01c80639010d07c116100ee578063bf333f2c11610097578063d547741f11610071578063d547741f146103f3578063dc9a4ef614610406578063dcf844a71461042d578063e00a83e01461044d57600080fd5b8063bf333f2c146103af578063ca15c873146103b9578063ccc57490146103cc57600080fd5b8063930ac180116100c8578063930ac1801461038a578063a217fddf14610394578063b13aa2d61461039c57600080fd5b80639010d07c1461032a57806391d148541461033d578063922b74871461038157600080fd5b80631ea327c51161015b57806336568abe1161013557806336568abe146102de57806358f85880146102f1578063638a0f09146102fa5780637ebe815c1461030357600080fd5b80631ea327c514610295578063248a9ca3146102a85780632f2ff15d146102cb57600080fd5b806306f333f21161018c57806306f333f2146102375780630f5f6ed71461024c5780630f862f1e1461025557600080fd5b806301ffc9a7146101b357806302d2ff66146101db57806303ed0ee514610210575b600080fd5b6101c66101c13660046110ef565b610474565b60405190151581526020015b60405180910390f35b6102027febfdca8e46c0b8dacf9989ee613e35727eadd20a1d5e5ad01a53968c7e5fe07a81565b6040519081526020016101d2565b6102027f043c983c49d46f0e102151eaf8085d4a2e6571d5df2d47b013f39bddfd4a639d81565b61024a61024536600461115a565b6104d0565b005b61020261271081565b61027073eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee81565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016101d2565b61024a6102a336600461118d565b610611565b6102026102b636600461118d565b60009081526020819052604090206001015490565b61024a6102d93660046111a6565b610648565b61024a6102ec3660046111a6565b61066d565b61020260025481565b61020260045481565b6102027f9a04aea0a349253cc7277afafdf6ead6729a3972a47ffb40eaef2c93d4e1bfea81565b6102706103383660046111c9565b6106c6565b6101c661034b3660046111a6565b60009182526020828152604080842073ffffffffffffffffffffffffffffffffffffffff93909316845291905290205460ff1690565b610202610e1081565b6102026201518081565b610202600081565b61024a6103aa36600461118d565b6106e5565b610202620f424081565b6102026103c736600461118d565b610791565b6102027f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f5581565b61024a6104013660046111a6565b6107a8565b6102027f60044782a422109ac08a415e44260ad5d3bad63d96ebe1fac0363399642ee3f281565b61020261043b3660046111eb565b60036020526000908152604090205481565b6102027f000000000000000000000000000000000000000000000000000000000000000081565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f5a05180f0000000000000000000000000000000000000000000000000000000014806104ca57506104ca826107cd565b92915050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f556104fa81610864565b73ffffffffffffffffffffffffffffffffffffffff83166000908152600360205260408120549081900361052e5750505050565b73ffffffffffffffffffffffffffffffffffffffff8481166000818152600360209081526040808320929092558151928352928616928201929092529081018290527f244e51bc38c1452fa8aaf487bcb4bca36c2baa3a5fbdb776b1eabd8dc6d277cd9060600160405180910390a17fffffffffffffffffffffffff111111111111111111111111111111111111111273ffffffffffffffffffffffffffffffffffffffff8516016105e9576105e48382610871565b61060a565b61060a73ffffffffffffffffffffffffffffffffffffffff8516848361094c565b505b505050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f5561063b81610864565b610644826109d9565b5050565b60008281526020819052604090206001015461066381610864565b61060a8383610a5a565b73ffffffffffffffffffffffffffffffffffffffff811633146106bc576040517f6697b23200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61060c8282610a8f565b60008281526001602052604081206106de9083610abc565b9392505050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f5561070f81610864565b61271082111561074b576040517f9b569b8100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600280549083905560408051828152602081018590527f14914da2bf76024616fbe1859783fcd4dbddcb179b1f3a854949fbf920dcb957910160405180910390a1505050565b60008181526001602052604081206104ca90610ac8565b6000828152602081905260409020600101546107c381610864565b61060a8383610a8f565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f7965db0b0000000000000000000000000000000000000000000000000000000014806104ca57507f01ffc9a7000000000000000000000000000000000000000000000000000000007fffffffff000000000000000000000000000000000000000000000000000000008316146104ca565b61086e8133610ad2565b50565b804710156108b2576040517fcd7860590000000000000000000000000000000000000000000000000000000081523060048201526024015b60405180910390fd5b60008273ffffffffffffffffffffffffffffffffffffffff168260405160006040518083038185875af1925050503d806000811461090c576040519150601f19603f3d011682016040523d82523d6000602084013e610911565b606091505b505090508061060c576040517f1425ea4200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040805173ffffffffffffffffffffffffffffffffffffffff8416602482015260448082018490528251808303909101815260649091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fa9059cbb0000000000000000000000000000000000000000000000000000000017905261060c908490610b58565b610e10811015610a15576040517f0e0ea5c700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600480549082905560408051828152602081018490527f909f9078b2f6eac1d10f2aae793656c5a67511eb627ebd1d2cb1eb9c0ab94c95910160405180910390a15050565b600080610a678484610bee565b905080156106de576000848152600160205260409020610a879084610cea565b509392505050565b600080610a9c8484610d0c565b905080156106de576000848152600160205260409020610a879084610dc7565b60006106de8383610de9565b60006104ca825490565b60008281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915290205460ff16610644576040517fe2517d3f00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff82166004820152602481018390526044016108a9565b6000610b7a73ffffffffffffffffffffffffffffffffffffffff841683610e13565b90508051600014158015610b9f575080806020019051810190610b9d9190611206565b155b1561060c576040517f5274afe700000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff841660048201526024016108a9565b60008281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915281205460ff16610ce25760008381526020818152604080832073ffffffffffffffffffffffffffffffffffffffff86168452909152902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055610c803390565b73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16847f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45060016104ca565b5060006104ca565b60006106de8373ffffffffffffffffffffffffffffffffffffffff8416610e21565b60008281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915281205460ff1615610ce25760008381526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8616808552925280832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016905551339286917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a45060016104ca565b60006106de8373ffffffffffffffffffffffffffffffffffffffff8416610e68565b6000826000018281548110610e0057610e00611228565b9060005260206000200154905092915050565b60606106de83836000610f5b565b6000818152600183016020526040812054610ce2575081546001818101845560008481526020808220909301849055845484825282860190935260409020919091556104ca565b60008181526001830160205260408120548015610f51576000610e8c600183611257565b8554909150600090610ea090600190611257565b9050808214610f05576000866000018281548110610ec057610ec0611228565b9060005260206000200154905080876000018481548110610ee357610ee3611228565b6000918252602080832090910192909255918252600188019052604090208390555b8554869080610f1657610f16611291565b6001900381819060005260206000200160009055905585600101600086815260200190815260200160002060009055600193505050506104ca565b60009150506104ca565b606081471015610f99576040517fcd7860590000000000000000000000000000000000000000000000000000000081523060048201526024016108a9565b6000808573ffffffffffffffffffffffffffffffffffffffff168486604051610fc291906112c0565b60006040518083038185875af1925050503d8060008114610fff576040519150601f19603f3d011682016040523d82523d6000602084013e611004565b606091505b509150915061101486838361101e565b9695505050505050565b6060826110335761102e826110ad565b6106de565b8151158015611057575073ffffffffffffffffffffffffffffffffffffffff84163b155b156110a6576040517f9996b31500000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff851660048201526024016108a9565b50806106de565b8051156110bd5780518082602001fd5b6040517f1425ea4200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006020828403121561110157600080fd5b81357fffffffff00000000000000000000000000000000000000000000000000000000811681146106de57600080fd5b803573ffffffffffffffffffffffffffffffffffffffff8116811461115557600080fd5b919050565b6000806040838503121561116d57600080fd5b61117683611131565b915061118460208401611131565b90509250929050565b60006020828403121561119f57600080fd5b5035919050565b600080604083850312156111b957600080fd5b8235915061118460208401611131565b600080604083850312156111dc57600080fd5b50508035926020909101359150565b6000602082840312156111fd57600080fd5b6106de82611131565b60006020828403121561121857600080fd5b815180151581146106de57600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b818103818111156104ca577f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fd5b6000825160005b818110156112e157602081860181015185830152016112c7565b50600092019182525091905056fea26469706673582212206b451daf2e4e6c560ed06b0aa7925cb50e6aaa8710c48fe024cf23ecbc261d6b64736f6c63430008180033", } // AdminV2ABI is the input ABI used to generate the binding from. @@ -2050,7 +2050,7 @@ var AdminV2FuncSigs = AdminV2MetaData.Sigs var AdminV2Bin = AdminV2MetaData.Bin // DeployAdminV2 deploys a new Ethereum contract, binding an instance of AdminV2 to it. -func DeployAdminV2(auth *bind.TransactOpts, backend bind.ContractBackend, _owner common.Address) (common.Address, *types.Transaction, *AdminV2, error) { +func DeployAdminV2(auth *bind.TransactOpts, backend bind.ContractBackend, defaultAdmin common.Address) (common.Address, *types.Transaction, *AdminV2, error) { parsed, err := AdminV2MetaData.GetAbi() if err != nil { return common.Address{}, nil, nil, err @@ -2059,7 +2059,7 @@ func DeployAdminV2(auth *bind.TransactOpts, backend bind.ContractBackend, _owner return common.Address{}, nil, nil, errors.New("GetABI returned nil") } - address, tx, contract, err := bind.DeployContract(auth, *parsed, common.FromHex(AdminV2Bin), backend, _owner) + address, tx, contract, err := bind.DeployContract(auth, *parsed, common.FromHex(AdminV2Bin), backend, defaultAdmin) if err != nil { return common.Address{}, nil, nil, err } @@ -3849,7 +3849,7 @@ func (_AdminV2 *AdminV2Filterer) ParseRoleRevoked(log types.Log) (*AdminV2RoleRe // BridgeTransactionV2LibMetaData contains all meta data concerning the BridgeTransactionV2Lib contract. var BridgeTransactionV2LibMetaData = &bind.MetaData{ ABI: "[{\"inputs\":[],\"name\":\"BridgeTransactionV2__InvalidEncodedTx\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint16\",\"name\":\"version\",\"type\":\"uint16\"}],\"name\":\"BridgeTransactionV2__UnsupportedVersion\",\"type\":\"error\"}]", - Bin: "0x60566037600b82828239805160001a607314602a57634e487b7160e01b600052600060045260246000fd5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600080fdfea2646970667358221220736bb5e8e495fb3a776c3cad8b30577c46279a088f4f89b0d509badbef3da01f64736f6c63430008180033", + Bin: "0x60566037600b82828239805160001a607314602a57634e487b7160e01b600052600060045260246000fd5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600080fdfea2646970667358221220e0ca35493e1156e7a5feebea2e43b9ef77737179785679c4db599efb0f1e2a0864736f6c63430008180033", } // BridgeTransactionV2LibABI is the input ABI used to generate the binding from. @@ -4362,7 +4362,7 @@ func (_ERC165 *ERC165CallerSession) SupportsInterface(interfaceId [4]byte) (bool // EnumerableSetMetaData contains all meta data concerning the EnumerableSet contract. var EnumerableSetMetaData = &bind.MetaData{ ABI: "[]", - Bin: "0x60566037600b82828239805160001a607314602a57634e487b7160e01b600052600060045260246000fd5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600080fdfea2646970667358221220cb930ba14bc69bdf61a9326099568898423db2bde70050effda1b23aa9e9dc9e64736f6c63430008180033", + Bin: "0x60566037600b82828239805160001a607314602a57634e487b7160e01b600052600060045260246000fd5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600080fdfea2646970667358221220164fbb0c52873ae2972df8055df9a7e90580066b49083b8183327a7192352ac164736f6c63430008180033", } // EnumerableSetABI is the input ABI used to generate the binding from. @@ -4534,7 +4534,7 @@ func (_EnumerableSet *EnumerableSetTransactorRaw) Transact(opts *bind.TransactOp // FastBridgeV2MetaData contains all meta data concerning the FastBridgeV2 contract. var FastBridgeV2MetaData = &bind.MetaData{ - ABI: "[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_owner\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"AccessControlBadConfirmation\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"neededRole\",\"type\":\"bytes32\"}],\"name\":\"AccessControlUnauthorizedAccount\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"}],\"name\":\"AddressEmptyCode\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"AddressInsufficientBalance\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"AmountIncorrect\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"BridgeTransactionV2__InvalidEncodedTx\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint16\",\"name\":\"version\",\"type\":\"uint16\"}],\"name\":\"BridgeTransactionV2__UnsupportedVersion\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"CancelDelayBelowMin\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ChainIncorrect\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DeadlineExceeded\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DeadlineNotExceeded\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DeadlineTooShort\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DisputePeriodNotPassed\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DisputePeriodPassed\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ExclusivityParamsIncorrect\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ExclusivityPeriodNotPassed\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"FailedInnerCall\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"FeeRateAboveMax\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"MsgValueIncorrect\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"MulticallTarget__UndeterminedRevert\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"RecipientIncorrectReturnValue\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"RecipientNoReturnValue\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"}],\"name\":\"SafeERC20FailedOperation\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"SenderIncorrect\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"StatusIncorrect\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"TokenNotContract\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"TransactionRelayed\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ZapDataLengthAboveMax\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ZapNativeNotSupported\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ZeroAddress\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"BridgeDepositClaimed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"BridgeDepositRefunded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"name\":\"BridgeProofDisputed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"transactionHash\",\"type\":\"bytes32\"}],\"name\":\"BridgeProofProvided\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"quoteId\",\"type\":\"bytes\"}],\"name\":\"BridgeQuoteDetails\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"originChainId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"chainGasAmount\",\"type\":\"uint256\"}],\"name\":\"BridgeRelayed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"destChainId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"sendChainGas\",\"type\":\"bool\"}],\"name\":\"BridgeRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"oldCancelDelay\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newCancelDelay\",\"type\":\"uint256\"}],\"name\":\"CancelDelayUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"oldFeeRate\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newFeeRate\",\"type\":\"uint256\"}],\"name\":\"FeeRateUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"FeesSwept\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"previousAdminRole\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"newAdminRole\",\"type\":\"bytes32\"}],\"name\":\"RoleAdminChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleGranted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleRevoked\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"CANCELER_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"DEFAULT_ADMIN_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"DEFAULT_CANCEL_DELAY\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"DISPUTE_PERIOD\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"FEE_BPS\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"FEE_RATE_MAX\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"GOVERNOR_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"GUARD_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"MAX_ZAP_DATA_LENGTH\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"MIN_CANCEL_DELAY\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"MIN_DEADLINE_PERIOD\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"NATIVE_GAS_TOKEN\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"PROVER_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"QUOTER_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"dstChainId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"sendChainGas\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"}],\"internalType\":\"structIFastBridge.BridgeParams\",\"name\":\"params\",\"type\":\"tuple\"}],\"name\":\"bridge\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"dstChainId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"sendChainGas\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"}],\"internalType\":\"structIFastBridge.BridgeParams\",\"name\":\"params\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"quoteRelayer\",\"type\":\"address\"},{\"internalType\":\"int256\",\"name\":\"quoteExclusivitySeconds\",\"type\":\"int256\"},{\"internalType\":\"bytes\",\"name\":\"quoteId\",\"type\":\"bytes\"},{\"internalType\":\"uint256\",\"name\":\"zapNative\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"zapData\",\"type\":\"bytes\"}],\"internalType\":\"structIFastBridgeV2.BridgeParamsV2\",\"name\":\"paramsV2\",\"type\":\"tuple\"}],\"name\":\"bridge\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"}],\"name\":\"bridgeProofs\",\"outputs\":[{\"internalType\":\"uint96\",\"name\":\"timestamp\",\"type\":\"uint96\"},{\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"bridgeRelayDetails\",\"outputs\":[{\"internalType\":\"uint48\",\"name\":\"blockNumber\",\"type\":\"uint48\"},{\"internalType\":\"uint48\",\"name\":\"blockTimestamp\",\"type\":\"uint48\"},{\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"}],\"name\":\"bridgeRelays\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"}],\"name\":\"bridgeStatuses\",\"outputs\":[{\"internalType\":\"enumIFastBridgeV2.BridgeStatus\",\"name\":\"status\",\"type\":\"uint8\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"bridgeTxDetails\",\"outputs\":[{\"internalType\":\"enumIFastBridgeV2.BridgeStatus\",\"name\":\"status\",\"type\":\"uint8\"},{\"internalType\":\"uint32\",\"name\":\"destChainId\",\"type\":\"uint32\"},{\"internalType\":\"uint56\",\"name\":\"proofBlockTimestamp\",\"type\":\"uint56\"},{\"internalType\":\"address\",\"name\":\"proofRelayer\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"name\":\"canClaim\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"cancel\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"cancelDelay\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"chainGasAmount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"claim\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"claim\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"deployBlock\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"}],\"name\":\"dispute\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"getBridgeTransaction\",\"outputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"originChainId\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"destChainId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"originSender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destRecipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"originFeeAmount\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"sendChainGas\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"}],\"internalType\":\"structIFastBridge.BridgeTransaction\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"getBridgeTransactionV2\",\"outputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"originChainId\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"destChainId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"originSender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destRecipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"originFeeAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"exclusivityRelayer\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"exclusivityEndTime\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"zapNative\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"zapData\",\"type\":\"bytes\"}],\"internalType\":\"structIFastBridgeV2.BridgeTransactionV2\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"}],\"name\":\"getRoleAdmin\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"index\",\"type\":\"uint256\"}],\"name\":\"getRoleMember\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"}],\"name\":\"getRoleMemberCount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"grantRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"hasRole\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes[]\",\"name\":\"data\",\"type\":\"bytes[]\"},{\"internalType\":\"bool\",\"name\":\"ignoreReverts\",\"type\":\"bool\"}],\"name\":\"multicallNoResults\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes[]\",\"name\":\"data\",\"type\":\"bytes[]\"},{\"internalType\":\"bool\",\"name\":\"ignoreReverts\",\"type\":\"bool\"}],\"name\":\"multicallWithResults\",\"outputs\":[{\"components\":[{\"internalType\":\"bool\",\"name\":\"success\",\"type\":\"bool\"},{\"internalType\":\"bytes\",\"name\":\"returnData\",\"type\":\"bytes\"}],\"internalType\":\"structIMulticallTarget.Result[]\",\"name\":\"results\",\"type\":\"tuple[]\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"nonce\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"protocolFeeRate\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"protocolFees\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"destTxHash\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"name\":\"prove\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"},{\"internalType\":\"bytes32\",\"name\":\"destTxHash\",\"type\":\"bytes32\"}],\"name\":\"prove\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"refund\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"relay\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"},{\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"name\":\"relay\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"callerConfirmation\",\"type\":\"address\"}],\"name\":\"renounceRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"revokeRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"senderNonces\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"newCancelDelay\",\"type\":\"uint256\"}],\"name\":\"setCancelDelay\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"newFeeRate\",\"type\":\"uint256\"}],\"name\":\"setProtocolFeeRate\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes4\",\"name\":\"interfaceId\",\"type\":\"bytes4\"}],\"name\":\"supportsInterface\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"}],\"name\":\"sweepProtocolFees\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", + ABI: "[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"defaultAdmin\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"AccessControlBadConfirmation\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"neededRole\",\"type\":\"bytes32\"}],\"name\":\"AccessControlUnauthorizedAccount\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"}],\"name\":\"AddressEmptyCode\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"AddressInsufficientBalance\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"AmountIncorrect\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"BridgeTransactionV2__InvalidEncodedTx\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint16\",\"name\":\"version\",\"type\":\"uint16\"}],\"name\":\"BridgeTransactionV2__UnsupportedVersion\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"CancelDelayBelowMin\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ChainIncorrect\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DeadlineExceeded\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DeadlineNotExceeded\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DeadlineTooShort\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DisputePeriodNotPassed\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DisputePeriodPassed\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ExclusivityParamsIncorrect\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ExclusivityPeriodNotPassed\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"FailedInnerCall\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"FeeRateAboveMax\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"MsgValueIncorrect\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"MulticallTarget__UndeterminedRevert\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"RecipientIncorrectReturnValue\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"RecipientNoReturnValue\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"}],\"name\":\"SafeERC20FailedOperation\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"SenderIncorrect\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"StatusIncorrect\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"TokenNotContract\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"TransactionRelayed\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ZapDataLengthAboveMax\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ZapNativeNotSupported\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ZeroAddress\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"BridgeDepositClaimed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"BridgeDepositRefunded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"name\":\"BridgeProofDisputed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"transactionHash\",\"type\":\"bytes32\"}],\"name\":\"BridgeProofProvided\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"quoteId\",\"type\":\"bytes\"}],\"name\":\"BridgeQuoteDetails\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"originChainId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"chainGasAmount\",\"type\":\"uint256\"}],\"name\":\"BridgeRelayed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"destChainId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"sendChainGas\",\"type\":\"bool\"}],\"name\":\"BridgeRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"oldCancelDelay\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newCancelDelay\",\"type\":\"uint256\"}],\"name\":\"CancelDelayUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"oldFeeRate\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newFeeRate\",\"type\":\"uint256\"}],\"name\":\"FeeRateUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"FeesSwept\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"previousAdminRole\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"newAdminRole\",\"type\":\"bytes32\"}],\"name\":\"RoleAdminChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleGranted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleRevoked\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"CANCELER_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"DEFAULT_ADMIN_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"DEFAULT_CANCEL_DELAY\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"DISPUTE_PERIOD\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"FEE_BPS\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"FEE_RATE_MAX\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"GOVERNOR_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"GUARD_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"MAX_ZAP_DATA_LENGTH\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"MIN_CANCEL_DELAY\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"MIN_DEADLINE_PERIOD\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"NATIVE_GAS_TOKEN\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"PROVER_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"QUOTER_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"dstChainId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"sendChainGas\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"}],\"internalType\":\"structIFastBridge.BridgeParams\",\"name\":\"params\",\"type\":\"tuple\"}],\"name\":\"bridge\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"}],\"name\":\"bridgeProofs\",\"outputs\":[{\"internalType\":\"uint96\",\"name\":\"timestamp\",\"type\":\"uint96\"},{\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"bridgeRelayDetails\",\"outputs\":[{\"internalType\":\"uint48\",\"name\":\"blockNumber\",\"type\":\"uint48\"},{\"internalType\":\"uint48\",\"name\":\"blockTimestamp\",\"type\":\"uint48\"},{\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"}],\"name\":\"bridgeRelays\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"}],\"name\":\"bridgeStatuses\",\"outputs\":[{\"internalType\":\"enumIFastBridgeV2.BridgeStatus\",\"name\":\"status\",\"type\":\"uint8\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"bridgeTxDetails\",\"outputs\":[{\"internalType\":\"enumIFastBridgeV2.BridgeStatus\",\"name\":\"status\",\"type\":\"uint8\"},{\"internalType\":\"uint32\",\"name\":\"destChainId\",\"type\":\"uint32\"},{\"internalType\":\"uint56\",\"name\":\"proofBlockTimestamp\",\"type\":\"uint56\"},{\"internalType\":\"address\",\"name\":\"proofRelayer\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"dstChainId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"sendChainGas\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"}],\"internalType\":\"structIFastBridge.BridgeParams\",\"name\":\"params\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"quoteRelayer\",\"type\":\"address\"},{\"internalType\":\"int256\",\"name\":\"quoteExclusivitySeconds\",\"type\":\"int256\"},{\"internalType\":\"bytes\",\"name\":\"quoteId\",\"type\":\"bytes\"},{\"internalType\":\"uint256\",\"name\":\"zapNative\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"zapData\",\"type\":\"bytes\"}],\"internalType\":\"structIFastBridgeV2.BridgeParamsV2\",\"name\":\"paramsV2\",\"type\":\"tuple\"}],\"name\":\"bridgeV2\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"name\":\"canClaim\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"cancelDelay\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"cancelV2\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"chainGasAmount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"claim\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"claimV2\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"deployBlock\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"}],\"name\":\"dispute\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"getBridgeTransaction\",\"outputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"originChainId\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"destChainId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"originSender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destRecipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"originFeeAmount\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"sendChainGas\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"}],\"internalType\":\"structIFastBridge.BridgeTransaction\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"getBridgeTransactionV2\",\"outputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"originChainId\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"destChainId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"originSender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destRecipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"originFeeAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"exclusivityRelayer\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"exclusivityEndTime\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"zapNative\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"zapData\",\"type\":\"bytes\"}],\"internalType\":\"structIFastBridgeV2.BridgeTransactionV2\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"}],\"name\":\"getRoleAdmin\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"index\",\"type\":\"uint256\"}],\"name\":\"getRoleMember\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"}],\"name\":\"getRoleMemberCount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"grantRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"hasRole\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes[]\",\"name\":\"data\",\"type\":\"bytes[]\"},{\"internalType\":\"bool\",\"name\":\"ignoreReverts\",\"type\":\"bool\"}],\"name\":\"multicallNoResults\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes[]\",\"name\":\"data\",\"type\":\"bytes[]\"},{\"internalType\":\"bool\",\"name\":\"ignoreReverts\",\"type\":\"bool\"}],\"name\":\"multicallWithResults\",\"outputs\":[{\"components\":[{\"internalType\":\"bool\",\"name\":\"success\",\"type\":\"bool\"},{\"internalType\":\"bytes\",\"name\":\"returnData\",\"type\":\"bytes\"}],\"internalType\":\"structIMulticallTarget.Result[]\",\"name\":\"results\",\"type\":\"tuple[]\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"nonce\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"protocolFeeRate\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"protocolFees\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"},{\"internalType\":\"bytes32\",\"name\":\"destTxHash\",\"type\":\"bytes32\"}],\"name\":\"prove\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"destTxHash\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"name\":\"proveV2\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"refund\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"relay\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"},{\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"name\":\"relayV2\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"callerConfirmation\",\"type\":\"address\"}],\"name\":\"renounceRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"revokeRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"senderNonces\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"newCancelDelay\",\"type\":\"uint256\"}],\"name\":\"setCancelDelay\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"newFeeRate\",\"type\":\"uint256\"}],\"name\":\"setProtocolFeeRate\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes4\",\"name\":\"interfaceId\",\"type\":\"bytes4\"}],\"name\":\"supportsInterface\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"}],\"name\":\"sweepProtocolFees\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", Sigs: map[string]string{ "02d2ff66": "CANCELER_ROLE()", "a217fddf": "DEFAULT_ADMIN_ROLE()", @@ -4551,18 +4551,18 @@ var FastBridgeV2MetaData = &bind.MetaData{ "dc9a4ef6": "PROVER_ROLE()", "7ebe815c": "QUOTER_ROLE()", "45851694": "bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256))", - "bfc7c607": "bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256),(address,int256,bytes,uint256,bytes))", "91ad5039": "bridgeProofs(bytes32)", "c79371b1": "bridgeRelayDetails(bytes32)", "8379a24f": "bridgeRelays(bytes32)", "051287bc": "bridgeStatuses(bytes32)", "63787e52": "bridgeTxDetails(bytes32)", + "76443085": "bridgeV2((uint32,address,address,address,address,uint256,uint256,bool,uint256),(address,int256,bytes,uint256,bytes))", "aa9641ab": "canClaim(bytes32,address)", - "3c5beeb4": "cancel(bytes)", "638a0f09": "cancelDelay()", + "67e60693": "cancelV2(bytes)", "e00a83e0": "chainGasAmount()", - "c63ff8dd": "claim(bytes)", "41fcb612": "claim(bytes,address)", + "f76d7278": "claimV2(bytes)", "a3ec191a": "deployBlock()", "add98c70": "dispute(bytes32)", "ac11fb1a": "getBridgeTransaction(bytes)", @@ -4578,10 +4578,10 @@ var FastBridgeV2MetaData = &bind.MetaData{ "58f85880": "protocolFeeRate()", "dcf844a7": "protocolFees(address)", "886d36ff": "prove(bytes,bytes32)", - "18e4357d": "prove(bytes32,bytes32,address)", + "41fdec80": "proveV2(bytes32,bytes32,address)", "5eb7d946": "refund(bytes)", "8f0d6f17": "relay(bytes)", - "9c9545f0": "relay(bytes,address)", + "3d71e21f": "relayV2(bytes,address)", "36568abe": "renounceRole(bytes32,address)", "d547741f": "revokeRole(bytes32,address)", "295710ff": "senderNonces(address)", @@ -4590,7 +4590,7 @@ var FastBridgeV2MetaData = &bind.MetaData{ "01ffc9a7": "supportsInterface(bytes4)", "06f333f2": "sweepProtocolFees(address,address)", }, - Bin: "0x60e06040526000608081905260a0523480156200001b57600080fd5b50604051620047ee380380620047ee8339810160408190526200003e9162000215565b806200004c60008262000067565b506200005b62015180620000a4565b50504360c05262000240565b6000806200007684846200010d565b905080156200009b576000848152600160205260409020620000999084620001bb565b505b90505b92915050565b610e10811015620000c857604051630e0ea5c760e01b815260040160405180910390fd5b600480549082905560408051828152602081018490527f909f9078b2f6eac1d10f2aae793656c5a67511eb627ebd1d2cb1eb9c0ab94c95910160405180910390a15050565b6000828152602081815260408083206001600160a01b038516845290915281205460ff16620001b2576000838152602081815260408083206001600160a01b03861684529091529020805460ff19166001179055620001693390565b6001600160a01b0316826001600160a01b0316847f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45060016200009e565b5060006200009e565b60006200009b836001600160a01b0384166000818152600183016020526040812054620001b2575081546001818101845560008481526020808220909301849055845484825282860190935260409020919091556200009e565b6000602082840312156200022857600080fd5b81516001600160a01b03811681146200009b57600080fd5b60805160a05160c05161457e62000270600039600061094b015260006109ec01526000610bec015261457e6000f3fe60806040526004361061034a5760003560e01c80638379a24f116101bb578063ac11fb1a116100f7578063c79371b111610095578063d547741f1161006f578063d547741f14610b59578063dc9a4ef614610b79578063dcf844a714610bad578063e00a83e014610bda57600080fd5b8063c79371b114610a78578063ca15c87314610b05578063ccc5749014610b2557600080fd5b8063b13aa2d6116100d1578063b13aa2d614610a0e578063bf333f2c14610a2e578063bfc7c60714610a45578063c63ff8dd14610a5857600080fd5b8063ac11fb1a1461098d578063add98c70146109ba578063affed0e0146109da57600080fd5b8063922b748711610164578063a217fddf1161013e578063a217fddf14610924578063a3ec191a14610939578063a5bbe22b14610769578063aa9641ab1461096d57600080fd5b8063922b7487146108e4578063930ac180146108fa5780639c9545f01461091157600080fd5b80639010d07c116101955780639010d07c146107fa57806391ad50391461081a57806391d14854146108a057600080fd5b80638379a24f1461077f578063886d36ff146107c75780638f0d6f17146107e757600080fd5b8063385c1d2f1161028a57806358f858801161023357806363787e521161020d57806363787e52146106a5578063638a0f091461071f5780637ebe815c14610735578063820688d51461076957600080fd5b806358f85880146106425780635aa6ccba146106585780635eb7d9461461068557600080fd5b806341fcb6121161026457806341fcb612146105f9578063458516941461061957806354eff0681461062c57600080fd5b8063385c1d2f1461058c5780633c5beeb4146105b95780633f61331d146105d957600080fd5b80630f862f1e116102f7578063248a9ca3116102d1578063248a9ca3146104ef578063295710ff1461051f5780632f2ff15d1461054c57806336568abe1461056c57600080fd5b80630f862f1e1461046f57806318e4357d146104af5780631ea327c5146104cf57600080fd5b8063051287bc11610328578063051287bc146103fa57806306f333f2146104375780630f5f6ed71461045957600080fd5b806301ffc9a71461034f57806302d2ff661461038457806303ed0ee5146103c6575b600080fd5b34801561035b57600080fd5b5061036f61036a36600461352a565b610c0e565b60405190151581526020015b60405180910390f35b34801561039057600080fd5b506103b87febfdca8e46c0b8dacf9989ee613e35727eadd20a1d5e5ad01a53968c7e5fe07a81565b60405190815260200161037b565b3480156103d257600080fd5b506103b87f043c983c49d46f0e102151eaf8085d4a2e6571d5df2d47b013f39bddfd4a639d81565b34801561040657600080fd5b5061042a61041536600461356c565b60009081526005602052604090205460ff1690565b60405161037b91906135ef565b34801561044357600080fd5b50610457610452366004613622565b610c6a565b005b34801561046557600080fd5b506103b861271081565b34801561047b57600080fd5b5061049773eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee81565b6040516001600160a01b03909116815260200161037b565b3480156104bb57600080fd5b506104576104ca36600461365b565b610d77565b3480156104db57600080fd5b506104576104ea36600461356c565b610e8c565b3480156104fb57600080fd5b506103b861050a36600461356c565b60009081526020819052604090206001015490565b34801561052b57600080fd5b506103b861053a366004613694565b60076020526000908152604090205481565b34801561055857600080fd5b506104576105673660046136b1565b610ec3565b34801561057857600080fd5b506104576105873660046136b1565b610ee8565b34801561059857600080fd5b506105ac6105a73660046136ef565b610f34565b60405161037b91906137ba565b3480156105c557600080fd5b506104576105d4366004613899565b6110c2565b3480156105e557600080fd5b506104576105f43660046136ef565b6112c4565b34801561060557600080fd5b506104576106143660046138db565b61136e565b610457610627366004613adc565b6115e0565b34801561063857600080fd5b506103b861ffff81565b34801561064e57600080fd5b506103b860025481565b34801561066457600080fd5b50610678610673366004613899565b61163d565b60405161037b9190613af9565b34801561069157600080fd5b506104576106a0366004613899565b61170a565b3480156106b157600080fd5b5061070f6106c036600461356c565b60056020526000908152604090205460ff811690610100810463ffffffff169065010000000000810466ffffffffffffff16906c0100000000000000000000000090046001600160a01b031684565b60405161037b9493929190613c16565b34801561072b57600080fd5b506103b860045481565b34801561074157600080fd5b506103b87f9a04aea0a349253cc7277afafdf6ead6729a3972a47ffb40eaef2c93d4e1bfea81565b34801561077557600080fd5b506103b861070881565b34801561078b57600080fd5b5061036f61079a36600461356c565b6000908152600660205260409020546c0100000000000000000000000090046001600160a01b0316151590565b3480156107d357600080fd5b506104576107e2366004613c57565b611714565b6104576107f5366004613899565b611740565b34801561080657600080fd5b50610497610815366004613ca3565b61174b565b34801561082657600080fd5b5061087461083536600461356c565b60009081526005602052604090205465010000000000810466ffffffffffffff16916c010000000000000000000000009091046001600160a01b031690565b604080516bffffffffffffffffffffffff90931683526001600160a01b0390911660208301520161037b565b3480156108ac57600080fd5b5061036f6108bb3660046136b1565b6000918252602082815260408084206001600160a01b0393909316845291905290205460ff1690565b3480156108f057600080fd5b506103b8610e1081565b34801561090657600080fd5b506103b86201518081565b61045761091f3660046138db565b611763565b34801561093057600080fd5b506103b8600081565b34801561094557600080fd5b506103b87f000000000000000000000000000000000000000000000000000000000000000081565b34801561097957600080fd5b5061036f6109883660046136b1565b611a1d565b34801561099957600080fd5b506109ad6109a8366004613899565b611af4565b60405161037b9190613cc5565b3480156109c657600080fd5b506104576109d536600461356c565b611ca8565b3480156109e657600080fd5b506103b87f000000000000000000000000000000000000000000000000000000000000000081565b348015610a1a57600080fd5b50610457610a2936600461356c565b611df2565b348015610a3a57600080fd5b506103b8620f424081565b610457610a53366004613e29565b611e9e565b348015610a6457600080fd5b50610457610a73366004613899565b61212d565b348015610a8457600080fd5b50610ad7610a9336600461356c565b60066020526000908152604090205465ffffffffffff8082169166010000000000008104909116906c0100000000000000000000000090046001600160a01b031683565b6040805165ffffffffffff94851681529390921660208401526001600160a01b03169082015260600161037b565b348015610b1157600080fd5b506103b8610b2036600461356c565b612139565b348015610b3157600080fd5b506103b87f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f5581565b348015610b6557600080fd5b50610457610b743660046136b1565b612150565b348015610b8557600080fd5b506103b87f60044782a422109ac08a415e44260ad5d3bad63d96ebe1fac0363399642ee3f281565b348015610bb957600080fd5b506103b8610bc8366004613694565b60036020526000908152604090205481565b348015610be657600080fd5b506103b87f000000000000000000000000000000000000000000000000000000000000000081565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f5a05180f000000000000000000000000000000000000000000000000000000001480610c645750610c6482612175565b92915050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f55610c948161220c565b6001600160a01b03831660009081526003602052604081205490819003610cbb5750505050565b6001600160a01b038481166000818152600360209081526040808320929092558151928352928616928201929092529081018290527f244e51bc38c1452fa8aaf487bcb4bca36c2baa3a5fbdb776b1eabd8dc6d277cd9060600160405180910390a17fffffffffffffffffffffffff11111111111111111111111111111111111111126001600160a01b03851601610d5c57610d578382612216565b610d70565b610d706001600160a01b03851684836122e4565b505b505050565b7f60044782a422109ac08a415e44260ad5d3bad63d96ebe1fac0363399642ee3f2610da18161220c565b60008481526005602052604090206001815460ff166004811115610dc757610dc7613585565b14610dfe576040517f4145817200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80546001600160a01b0384166c0100000000000000000000000081026bffffffffffffffffffffffff66ffffffffffffff421665010000000000021664ffffffff009093169290921791909117600217825560405185815286907f4ac8af8a2cd87193d64dfc7a3b8d9923b714ec528b18725d080aa1299be0c5e49060200160405180910390a35050505050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f55610eb68161220c565b610ebf82612358565b5050565b600082815260208190526040902060010154610ede8161220c565b610d7083836123d9565b6001600160a01b0381163314610f2a576040517f6697b23200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610d728282612406565b60608267ffffffffffffffff811115610f4f57610f4f613927565b604051908082528060200260200182016040528015610f9557816020015b604080518082019091526000815260606020820152815260200190600190039081610f6d5790505b50905060005b838110156110ba5730858583818110610fb657610fb6613ef7565b9050602002810190610fc89190613f26565b604051610fd6929190613f8b565b600060405180830381855af49150503d8060008114611011576040519150601f19603f3d011682016040523d82523d6000602084013e611016565b606091505b5083838151811061102957611029613ef7565b602002602001015160000184848151811061104657611046613ef7565b60200260200101516020018290528215151515815250505081818151811061107057611070613ef7565b602002602001015160000151158015611087575082155b156110b2576110b28282815181106110a1576110a1613ef7565b602002602001015160200151612433565b600101610f9b565b509392505050565b6110cc8282612475565b600082826040516110de929190613f8b565b604080519182900390912060008181526005602052919091209091506001815460ff16600481111561111257611112613585565b14611149576040517f4145817200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b3360009081527f4527d8b28c468984933d33ae052f26b21c15ca0e7fdec762bba08e540e237001602052604090205460ba8501359060ff16611195576004546111929082613fca565b90505b8042116111ce576040517fe15ff9ea00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b81547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166004178255600a850135606090811c906032870135901c600061121d609a890135605a8a0135613fca565b604080516001600160a01b03858116825260208201849052825193945086169289927fb4c55c0c9bc613519b920e88748090150b890a875d307f21bea7d4fb2e8bc958928290030190a37fffffffffffffffffffffffff11111111111111111111111111111111111111126001600160a01b038316016112a6576112a18382612216565b6112ba565b6112ba6001600160a01b03831684836122e4565b5050505050505050565b60005b82811015610d7057600080308686858181106112e5576112e5613ef7565b90506020028101906112f79190613f26565b604051611305929190613f8b565b600060405180830381855af49150503d8060008114611340576040519150601f19603f3d011682016040523d82523d6000602084013e611345565b606091505b509150915081158015611356575083155b156113645761136481612433565b50506001016112c7565b6113788383612475565b6000838360405161138a929190613f8b565b604080519182900390912060008181526005602052919091208054919250906c0100000000000000000000000081046001600160a01b03169060ff81169065010000000000900466ffffffffffffff1660028260048111156113ee576113ee613585565b14611425576040517f4145817200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6107084282900366ffffffffffffff161161146c576040517f1992d0bd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600160a01b038616611482578295506114c4565b6001600160a01b03831633146114c4576040517f4af43a9000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b83547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166003178455603288013560601c605a890135609a8a01358015611533576001600160a01b0383166000908152600360205260408120805483929061152d908490613fca565b90915550505b604080516001600160a01b03858116825260208201859052808c1692908916918b917f582211c35a2139ac3bbaac74663c6a1f56c6cbb658b41fe11fd45a82074ac678910160405180910390a47fffffffffffffffffffffffff11111111111111111111111111111111111111126001600160a01b038416016115bf576115ba8983612216565b6115d3565b6115d36001600160a01b0384168a846122e4565b5050505050505050505050565b61163a816040518060a0016040528060006001600160a01b03168152602001600081526020016040518060200160405280600081525081526020016000815260200160405180602001604052806000815250815250611e9e565b50565b6116ef604051806101e00160405280600063ffffffff168152602001600063ffffffff16815260200160006001600160a01b0316815260200160006001600160a01b0316815260200160006001600160a01b0316815260200160006001600160a01b03168152602001600081526020016000815260200160008152602001600081526020016000815260200160006001600160a01b031681526020016000815260200160008152602001606081525090565b6116f98383612475565b61170383836124f6565b9392505050565b610ebf82826110c2565b61171e8383612475565b610d728383604051611731929190613f8b565b60405180910390208233610d77565b610ebf828233611763565b60008281526001602052604081206117039083612698565b61176d8383612475565b6000838360405161177f929190613f8b565b60405180910390209050611795848483856126a4565b6040805160608101825265ffffffffffff438116825242811660208084019182526001600160a01b038088168587019081526000888152600690935295822094518554935196519091166c01000000000000000000000000026bffffffffffffffffffffffff9685166601000000000000027fffffffffffffffffffffffffffffffffffffffff0000000000000000000000009094169190941617919091179390931617905561184985601e013560601c90565b9050604685013560601c607a86013561012e8701356001600160a01b03808516908716867ff8ae392d784b1ea5e8881bfa586d81abf07ef4f1e2fc75f7fe51c90f05199a5c60028c013560e01c6040805163ffffffff92909216825260328e0135606090811c60208401526001600160a01b038a1683830152605a8f0135908301526080820188905260a08201879052519081900360c00190a47fffffffffffffffffffffffff11111111111111111111111111111111111111126001600160a01b0384160161198957801561194b576040517f846dedc000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b813414611984576040517f81de0bf300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6119d7565b8034146119c2576040517f81de0bf300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6119d76001600160a01b038416338685612839565b3660006119e48a8a612872565b90925090508015611a01576119fc868686858561288e565b611a11565b3415611a1157611a118634612216565b50505050505050505050565b60008281526005602052604081206002815460ff166004811115611a4357611a43613585565b14611a7a576040517f4145817200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80546001600160a01b038481166c010000000000000000000000009092041614611ad0576040517f4af43a9000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b546107086501000000000090910466ffffffffffffff908116420316119392505050565b6040805161018081018252600080825260208201819052818301819052606082018190526080820181905260a0820181905260c0820181905260e0820181905261010082018190526101208201819052610140820181905261016082015290517f5aa6ccba0000000000000000000000000000000000000000000000000000000081523090635aa6ccba90611b8f9086908690600401614008565b600060405180830381865afa925050508015611bcd57506040513d6000823e601f3d908101601f19168201604052611bca9190810190614077565b60015b611be457611bdd828401846141ac565b9050610c64565b604051806101800160405280826000015163ffffffff168152602001826020015163ffffffff16815260200182604001516001600160a01b0316815260200182606001516001600160a01b0316815260200182608001516001600160a01b031681526020018260a001516001600160a01b031681526020018260c0015181526020018260e0015181526020018261010001518152602001826101a0015160001415151581526020018261012001518152602001826101400151815250915050610c64565b7f043c983c49d46f0e102151eaf8085d4a2e6571d5df2d47b013f39bddfd4a639d611cd28161220c565b600082815260056020526040902080546c0100000000000000000000000081046001600160a01b03169060ff81169065010000000000900466ffffffffffffff166002826004811115611d2757611d27613585565b14611d5e576040517f4145817200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6107084282900366ffffffffffffff161115611da6576040517f3e908aac00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b835464ffffffff001660011784556040516001600160a01b0384169087907f0695cf1d39b3055dcd0fe02d8b47eaf0d5a13e1996de925de59d0ef9b7f7fad490600090a3505050505050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f55611e1c8161220c565b612710821115611e58576040517f9b569b8100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600280549083905560408051828152602081018590527f14914da2bf76024616fbe1859783fcd4dbddcb179b1f3a854949fbf920dcb957910160405180910390a1505050565b80516000906001600160a01b031615611ec3576020820151611ec09042614278565b90505b611ece8383836129ea565b6000611ee284606001518560a00151612c6e565b90506000806002541115611f1b57620f424060025483611f0291906142a0565b611f0c91906142b7565b9050611f1881836142f2565b91505b6000612024604051806101e001604052804663ffffffff168152602001886000015163ffffffff16815260200188602001516001600160a01b0316815260200188604001516001600160a01b0316815260200188606001516001600160a01b0316815260200188608001516001600160a01b031681526020018581526020018860c0015181526020018481526020018861010001518152602001600760008a602001516001600160a01b03166001600160a01b031681526020019081526020016000206000815480929190611fef90614305565b90915550815287516001600160a01b031660208201526040810187905260608089015190820152608080890151910152612e81565b805160208083019190912060008181526005835260409081902080548b5163ffffffff8116610100027fffffffffffffffffffffffffffffffffffffffffffffffffffffff000000000090921691909117600117909155928a01516060808c015160808d015160c08e0151928d0151945197985094966001600160a01b039093169587957f120ea0364f36cdac7983bcfdd55270ca09d7f9b314a2ebc425a3b01ab1d6403a956120e0958b959394938e9290919015159061433d565b60405180910390a3807f3120e2bb59c86aca6890191a589a96af3662838efa374fbdcdf4c95bfe4a6c0e876040015160405161211c9190614393565b60405180910390a250505050505050565b610ebf8282600061136e565b6000818152600160205260408120610c6490612fc6565b60008281526020819052604090206001015461216b8161220c565b610d708383612406565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f7965db0b000000000000000000000000000000000000000000000000000000001480610c6457507f01ffc9a7000000000000000000000000000000000000000000000000000000007fffffffff00000000000000000000000000000000000000000000000000000000831614610c64565b61163a8133612fd0565b80471015612257576040517fcd7860590000000000000000000000000000000000000000000000000000000081523060048201526024015b60405180910390fd5b6000826001600160a01b03168260405160006040518083038185875af1925050503d80600081146122a4576040519150601f19603f3d011682016040523d82523d6000602084013e6122a9565b606091505b5050905080610d72576040517f1425ea4200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040516001600160a01b03838116602483015260448201839052610d7291859182169063a9059cbb906064015b604051602081830303815290604052915060e01b6020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff838183161783525050505061303c565b610e10811015612394576040517f0e0ea5c700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600480549082905560408051828152602081018490527f909f9078b2f6eac1d10f2aae793656c5a67511eb627ebd1d2cb1eb9c0ab94c95910160405180910390a15050565b6000806123e684846130b8565b905080156117035760008481526001602052604090206110ba9084613180565b6000806124138484613195565b905080156117035760008481526001602052604090206110ba9084613236565b8051156124435780518082602001fd5b6040517f5ead5a9d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61014e8110156124b1576040517f6ee0e17100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b813560f01c60028114610d72576040517f8bd977e700000000000000000000000000000000000000000000000000000000815261ffff8216600482015260240161224e565b6125a8604051806101e00160405280600063ffffffff168152602001600063ffffffff16815260200160006001600160a01b0316815260200160006001600160a01b0316815260200160006001600160a01b0316815260200160006001600160a01b03168152602001600081526020016000815260200160008152602001600081526020016000815260200160006001600160a01b031681526020016000815260200160008152602001606081525090565b600283013560e090811c82526006840135811c6020830152600a840135606090811c6040840152601e850135811c818401526032850135811c60808401526046850135811c60a0840152605a85013560c0840152607a85013591830191909152609a84013561010083015260ba84013561012083015260da84013561014083015260fa840135901c61016082015261010e83013561018082015261012e8301356101a08201526126588383612872565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152505050506101c082015292915050565b6000611703838361324b565b6001600160a01b0381166126e4576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000828152600660205260409020546c0100000000000000000000000090046001600160a01b031615612743576040517fbef7bb7d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600684013560e01c4614612783576040517f7029fdf900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60ba8401354211156127c1576040517f559895a300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60fa84013560601c80158015906127ea5750816001600160a01b0316816001600160a01b031614155b80156127fb575061010e8501354211155b15612832576040517f14be123200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5050505050565b6040516001600160a01b038481166024830152838116604483015260648201839052610d709186918216906323b872dd90608401612311565b3660006128838361014e81876143a6565b915091509250929050565b600061290986868686866040516024016128ab94939291906143d0565b60408051601f198184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fe85e13dd0000000000000000000000000000000000000000000000000000000017905234613275565b90508051600003612946576040517f1a95ad2600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8051602014612981576040517ff3725cca00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7fe85e13dd000000000000000000000000000000000000000000000000000000006129ab826143f9565b146129e2576040517ff3725cca00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b505050505050565b46836000015163ffffffff1603612a2d576040517f7029fdf900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60a08301511580612a40575060c0830151155b15612a77576040517fe38820c800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60208301516001600160a01b03161580612a9c575060408301516001600160a01b0316155b15612ad3576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60608301516001600160a01b03161580612af8575060808301516001600160a01b0316155b15612b2f576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b612b3b61070842613fca565b8361010001511015612b79576040517f04b7fcc800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61ffff8260800151511115612bba576040517f177a70e100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b606082015115801590612bed575060808301516001600160a01b031673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee145b15612c24576040517f846dedc000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000811280612c37575082610100015181135b15610d72576040517f352807b900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60007fffffffffffffffffffffffff11111111111111111111111111111111111111126001600160a01b03841601612ce057348214612cd9576040517f81de0bf300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5034610c64565b3415612d18576040517f81de0bf300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b826001600160a01b03163b600003612d5c576040517f7f523fe800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201526001600160a01b038416906370a0823190602401602060405180830381865afa158015612db9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612ddd919061443e565b9050612df46001600160a01b038416333085612839565b6040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015281906001600160a01b038516906370a0823190602401602060405180830381865afa158015612e53573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612e77919061443e565b61170391906142f2565b8051602080830151604080850151606086810151608088015160a089015160c08a015195517e02000000000000000000000000000000000000000000000000000000000000988101989098527fffffffff0000000000000000000000000000000000000000000000000000000060e0998a1b811660228a01529690981b90951660268701527fffffffffffffffffffffffffffffffffffffffff00000000000000000000000092821b8316602a870152811b8216603e86015292831b8116605285015293821b9093166066830152607a820192909252600090609a0160408051601f198184030181529082905260e08501516101008601516101208701516101408801516101608901516101808a01516101a08b01516101c08c0151979950612faf988a9890602001614457565b604051602081830303815290604052915050919050565b6000610c64825490565b6000828152602081815260408083206001600160a01b038516845290915290205460ff16610ebf576040517fe2517d3f0000000000000000000000000000000000000000000000000000000081526001600160a01b03821660048201526024810183905260440161224e565b60006130516001600160a01b0384168361332b565b9050805160001415801561307657508080602001905181019061307491906144e0565b155b15610d72576040517f5274afe70000000000000000000000000000000000000000000000000000000081526001600160a01b038416600482015260240161224e565b6000828152602081815260408083206001600160a01b038516845290915281205460ff16613178576000838152602081815260408083206001600160a01b0386168452909152902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790556131303390565b6001600160a01b0316826001600160a01b0316847f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a4506001610c64565b506000610c64565b6000611703836001600160a01b038416613339565b6000828152602081815260408083206001600160a01b038516845290915281205460ff1615613178576000838152602081815260408083206001600160a01b038616808552925280832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016905551339286917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a4506001610c64565b6000611703836001600160a01b038416613380565b600082600001828154811061326257613262613ef7565b9060005260206000200154905092915050565b6060814710156132b3576040517fcd78605900000000000000000000000000000000000000000000000000000000815230600482015260240161224e565b600080856001600160a01b031684866040516132cf91906144fd565b60006040518083038185875af1925050503d806000811461330c576040519150601f19603f3d011682016040523d82523d6000602084013e613311565b606091505b5091509150613321868383613473565b9695505050505050565b606061170383836000613275565b600081815260018301602052604081205461317857508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155610c64565b600081815260018301602052604081205480156134695760006133a46001836142f2565b85549091506000906133b8906001906142f2565b905080821461341d5760008660000182815481106133d8576133d8613ef7565b90600052602060002001549050808760000184815481106133fb576133fb613ef7565b6000918252602080832090910192909255918252600188019052604090208390555b855486908061342e5761342e614519565b600190038181906000526020600020016000905590558560010160008681526020019081526020016000206000905560019350505050610c64565b6000915050610c64565b60608261348857613483826134e8565b611703565b815115801561349f57506001600160a01b0384163b155b156134e1576040517f9996b3150000000000000000000000000000000000000000000000000000000081526001600160a01b038516600482015260240161224e565b5080611703565b8051156134f85780518082602001fd5b6040517f1425ea4200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006020828403121561353c57600080fd5b81357fffffffff000000000000000000000000000000000000000000000000000000008116811461170357600080fd5b60006020828403121561357e57600080fd5b5035919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b600581106135eb577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b9052565b60208101610c6482846135b4565b6001600160a01b038116811461163a57600080fd5b803561361d816135fd565b919050565b6000806040838503121561363557600080fd5b8235613640816135fd565b91506020830135613650816135fd565b809150509250929050565b60008060006060848603121561367057600080fd5b83359250602084013591506040840135613689816135fd565b809150509250925092565b6000602082840312156136a657600080fd5b8135611703816135fd565b600080604083850312156136c457600080fd5b823591506020830135613650816135fd565b801515811461163a57600080fd5b803561361d816136d6565b60008060006040848603121561370457600080fd5b833567ffffffffffffffff8082111561371c57600080fd5b818601915086601f83011261373057600080fd5b81358181111561373f57600080fd5b8760208260051b850101111561375457600080fd5b60209283019550935050840135613689816136d6565b60005b8381101561378557818101518382015260200161376d565b50506000910152565b600081518084526137a681602086016020860161376a565b601f01601f19169290920160200192915050565b600060208083018184528085518083526040925060408601915060408160051b87010184880160005b83811015613842578883037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc0018552815180511515845287015187840187905261382f8785018261378e565b95880195935050908601906001016137e3565b509098975050505050505050565b60008083601f84011261386257600080fd5b50813567ffffffffffffffff81111561387a57600080fd5b60208301915083602082850101111561389257600080fd5b9250929050565b600080602083850312156138ac57600080fd5b823567ffffffffffffffff8111156138c357600080fd5b6138cf85828601613850565b90969095509350505050565b6000806000604084860312156138f057600080fd5b833567ffffffffffffffff81111561390757600080fd5b61391386828701613850565b9094509250506020840135613689816135fd565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051610120810167ffffffffffffffff8111828210171561397a5761397a613927565b60405290565b60405160a0810167ffffffffffffffff8111828210171561397a5761397a613927565b6040516101e0810167ffffffffffffffff8111828210171561397a5761397a613927565b604051610180810167ffffffffffffffff8111828210171561397a5761397a613927565b604051601f8201601f1916810167ffffffffffffffff81118282101715613a1457613a14613927565b604052919050565b63ffffffff8116811461163a57600080fd5b803561361d81613a1c565b60006101208284031215613a4c57600080fd5b613a54613956565b9050613a5f82613a2e565b8152613a6d60208301613612565b6020820152613a7e60408301613612565b6040820152613a8f60608301613612565b6060820152613aa060808301613612565b608082015260a082013560a082015260c082013560c0820152613ac560e083016136e4565b60e082015261010080830135818301525092915050565b60006101208284031215613aef57600080fd5b6117038383613a39565b60208152613b1060208201835163ffffffff169052565b60006020830151613b29604084018263ffffffff169052565b5060408301516001600160a01b03811660608401525060608301516001600160a01b03811660808401525060808301516001600160a01b03811660a08401525060a08301516001600160a01b03811660c08401525060c083015160e08381019190915283015161010080840191909152830151610120808401919091528301516101408084019190915283015161016080840191909152830151610180613bda818501836001600160a01b03169052565b8401516101a0848101919091528401516101c0808501919091528401516101e0808501529050613c0e61020084018261378e565b949350505050565b60808101613c2482876135b4565b63ffffffff8516602083015266ffffffffffffff841660408301526001600160a01b038316606083015295945050505050565b600080600060408486031215613c6c57600080fd5b833567ffffffffffffffff811115613c8357600080fd5b613c8f86828701613850565b909790965060209590950135949350505050565b60008060408385031215613cb657600080fd5b50508035926020909101359150565b815163ffffffff16815261018081016020830151613ceb602084018263ffffffff169052565b506040830151613d0660408401826001600160a01b03169052565b506060830151613d2160608401826001600160a01b03169052565b506080830151613d3c60808401826001600160a01b03169052565b5060a0830151613d5760a08401826001600160a01b03169052565b5060c083015160c083015260e083015160e083015261010080840151818401525061012080840151613d8c8285018215159052565b5050610140838101519083015261016092830151929091019190915290565b600067ffffffffffffffff821115613dc557613dc5613927565b50601f01601f191660200190565b600082601f830112613de457600080fd5b8135613df7613df282613dab565b6139eb565b818152846020838601011115613e0c57600080fd5b816020850160208301376000918101602001919091529392505050565b6000806101408385031215613e3d57600080fd5b613e478484613a39565b915061012083013567ffffffffffffffff80821115613e6557600080fd5b9084019060a08287031215613e7957600080fd5b613e81613980565b8235613e8c816135fd565b815260208381013590820152604083013582811115613eaa57600080fd5b613eb688828601613dd3565b60408301525060608301356060820152608083013582811115613ed857600080fd5b613ee488828601613dd3565b6080830152508093505050509250929050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112613f5b57600080fd5b83018035915067ffffffffffffffff821115613f7657600080fd5b60200191503681900382131561389257600080fd5b8183823760009101908152919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b80820180821115610c6457610c64613f9b565b818352818160208501375060006020828401015260006020601f19601f840116840101905092915050565b602081526000613c0e602083018486613fdd565b805161361d81613a1c565b805161361d816135fd565b600082601f83011261404357600080fd5b8151614051613df282613dab565b81815284602083860101111561406657600080fd5b613c0e82602083016020870161376a565b60006020828403121561408957600080fd5b815167ffffffffffffffff808211156140a157600080fd5b908301906101e082860312156140b657600080fd5b6140be6139a3565b6140c78361401c565b81526140d56020840161401c565b60208201526140e660408401614027565b60408201526140f760608401614027565b606082015261410860808401614027565b608082015261411960a08401614027565b60a082015260c0838101519082015260e08084015190820152610100808401519082015261012080840151908201526101408084015190820152610160614161818501614027565b9082015261018083810151908201526101a080840151908201526101c0808401518381111561418f57600080fd5b61419b88828701614032565b918301919091525095945050505050565b600061018082840312156141bf57600080fd5b6141c76139c7565b6141d083613a2e565b81526141de60208401613a2e565b60208201526141ef60408401613612565b604082015261420060608401613612565b606082015261421160808401613612565b608082015261422260a08401613612565b60a082015260c083013560c082015260e083013560e08201526101008084013581830152506101206142558185016136e4565b908201526101408381013590820152610160928301359281019290925250919050565b808201828112600083128015821682158216171561429857614298613f9b565b505092915050565b8082028115828204841417610c6457610c64613f9b565b6000826142ed577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b81810381811115610c6457610c64613f9b565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820361433657614336613f9b565b5060010190565b60e08152600061435060e083018a61378e565b63ffffffff989098166020830152506001600160a01b039586166040820152939094166060840152608083019190915260a082015290151560c090910152919050565b602081526000611703602083018461378e565b600080858511156143b657600080fd5b838611156143c357600080fd5b5050820193919092039150565b6001600160a01b0385168152836020820152606060408201526000613321606083018486613fdd565b80516020808301519190811015614438577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8160200360031b1b821691505b50919050565b60006020828403121561445057600080fd5b5051919050565b60008a51614469818460208f0161376a565b80830190508a81528960208201528860408201528760608201527fffffffffffffffffffffffffffffffffffffffff0000000000000000000000008760601b1660808201528560948201528460b482015283516144cd8160d484016020880161376a565b0160d4019b9a5050505050505050505050565b6000602082840312156144f257600080fd5b8151611703816136d6565b6000825161450f81846020870161376a565b9190910192915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fdfea2646970667358221220ff0963a32deca1c739f82fff423c2a4ab1b1e197296c902578ae57133c488fd564736f6c63430008180033", + Bin: "0x60e06040526000608081905260a0523480156200001b57600080fd5b50604051620047ba380380620047ba8339810160408190526200003e9162000215565b806200004c60008262000067565b506200005b62015180620000a4565b50504360c05262000240565b6000806200007684846200010d565b905080156200009b576000848152600160205260409020620000999084620001bb565b505b90505b92915050565b610e10811015620000c857604051630e0ea5c760e01b815260040160405180910390fd5b600480549082905560408051828152602081018490527f909f9078b2f6eac1d10f2aae793656c5a67511eb627ebd1d2cb1eb9c0ab94c95910160405180910390a15050565b6000828152602081815260408083206001600160a01b038516845290915281205460ff16620001b2576000838152602081815260408083206001600160a01b03861684529091529020805460ff19166001179055620001693390565b6001600160a01b0316826001600160a01b0316847f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45060016200009e565b5060006200009e565b60006200009b836001600160a01b0384166000818152600183016020526040812054620001b2575081546001818101845560008481526020808220909301849055845484825282860190935260409020919091556200009e565b6000602082840312156200022857600080fd5b81516001600160a01b03811681146200009b57600080fd5b60805160a05160c05161454a62000270600039600061095e015260006109ff01526000610bcc015261454a6000f3fe60806040526004361061034a5760003560e01c80637ebe815c116101bb578063aa9641ab116100f7578063ca15c87311610095578063dc9a4ef61161006f578063dc9a4ef614610b59578063dcf844a714610b8d578063e00a83e014610bba578063f76d727814610bee57600080fd5b8063ca15c87314610ae5578063ccc5749014610b05578063d547741f14610b3957600080fd5b8063affed0e0116100d1578063affed0e0146109ed578063b13aa2d614610a21578063bf333f2c14610a41578063c79371b114610a5857600080fd5b8063aa9641ab14610980578063ac11fb1a146109a0578063add98c70146109cd57600080fd5b806391ad503911610164578063930ac1801161013e578063930ac18014610920578063a217fddf14610937578063a3ec191a1461094c578063a5bbe22b1461078f57600080fd5b806391ad50391461084057806391d14854146108c6578063922b74871461090a57600080fd5b8063886d36ff11610195578063886d36ff146107ed5780638f0d6f171461080d5780639010d07c1461082057600080fd5b80637ebe815c1461075b578063820688d51461078f5780638379a24f146107a557600080fd5b80633d71e21f1161028a57806358f858801161023357806363787e521161020d57806363787e5214610698578063638a0f091461071257806367e6069314610728578063764430851461074857600080fd5b806358f85880146106355780635aa6ccba1461064b5780635eb7d9461461067857600080fd5b806341fdec801161026457806341fdec80146105ec578063458516941461060c57806354eff0681461061f57600080fd5b80633d71e21f146105995780633f61331d146105ac57806341fcb612146105cc57600080fd5b80630f862f1e116102f7578063295710ff116102d1578063295710ff146104ff5780632f2ff15d1461052c57806336568abe1461054c578063385c1d2f1461056c57600080fd5b80630f862f1e1461046f5780631ea327c5146104af578063248a9ca3146104cf57600080fd5b8063051287bc11610328578063051287bc146103fa57806306f333f2146104375780630f5f6ed71461045957600080fd5b806301ffc9a71461034f57806302d2ff661461038457806303ed0ee5146103c6575b600080fd5b34801561035b57600080fd5b5061036f61036a3660046134f6565b610c0e565b60405190151581526020015b60405180910390f35b34801561039057600080fd5b506103b87febfdca8e46c0b8dacf9989ee613e35727eadd20a1d5e5ad01a53968c7e5fe07a81565b60405190815260200161037b565b3480156103d257600080fd5b506103b87f043c983c49d46f0e102151eaf8085d4a2e6571d5df2d47b013f39bddfd4a639d81565b34801561040657600080fd5b5061042a610415366004613538565b60009081526005602052604090205460ff1690565b60405161037b91906135bb565b34801561044357600080fd5b506104576104523660046135ee565b610c6a565b005b34801561046557600080fd5b506103b861271081565b34801561047b57600080fd5b5061049773eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee81565b6040516001600160a01b03909116815260200161037b565b3480156104bb57600080fd5b506104576104ca366004613538565b610d77565b3480156104db57600080fd5b506103b86104ea366004613538565b60009081526020819052604090206001015490565b34801561050b57600080fd5b506103b861051a366004613627565b60076020526000908152604090205481565b34801561053857600080fd5b50610457610547366004613644565b610dae565b34801561055857600080fd5b50610457610567366004613644565b610dd3565b34801561057857600080fd5b5061058c610587366004613682565b610e1f565b60405161037b9190613758565b6104576105a7366004613837565b610fad565b3480156105b857600080fd5b506104576105c7366004613682565b611237565b3480156105d857600080fd5b506104576105e7366004613837565b6112e1565b3480156105f857600080fd5b50610457610607366004613883565b611553565b61045761061a366004613a66565b611668565b34801561062b57600080fd5b506103b861ffff81565b34801561064157600080fd5b506103b860025481565b34801561065757600080fd5b5061066b610666366004613a83565b6116c5565b60405161037b9190613ac5565b34801561068457600080fd5b50610457610693366004613a83565b611792565b3480156106a457600080fd5b506107026106b3366004613538565b60056020526000908152604090205460ff811690610100810463ffffffff169065010000000000810466ffffffffffffff16906c0100000000000000000000000090046001600160a01b031684565b60405161037b9493929190613be2565b34801561071e57600080fd5b506103b860045481565b34801561073457600080fd5b50610457610743366004613a83565b611798565b610457610756366004613ca1565b61199a565b34801561076757600080fd5b506103b87f9a04aea0a349253cc7277afafdf6ead6729a3972a47ffb40eaef2c93d4e1bfea81565b34801561079b57600080fd5b506103b861070881565b3480156107b157600080fd5b5061036f6107c0366004613538565b6000908152600660205260409020546c0100000000000000000000000090046001600160a01b0316151590565b3480156107f957600080fd5b50610457610808366004613d6f565b611c29565b61045761081b366004613a83565b611c55565b34801561082c57600080fd5b5061049761083b366004613dbb565b611c60565b34801561084c57600080fd5b5061089a61085b366004613538565b60009081526005602052604090205465010000000000810466ffffffffffffff16916c010000000000000000000000009091046001600160a01b031690565b604080516bffffffffffffffffffffffff90931683526001600160a01b0390911660208301520161037b565b3480156108d257600080fd5b5061036f6108e1366004613644565b6000918252602082815260408084206001600160a01b0393909316845291905290205460ff1690565b34801561091657600080fd5b506103b8610e1081565b34801561092c57600080fd5b506103b86201518081565b34801561094357600080fd5b506103b8600081565b34801561095857600080fd5b506103b87f000000000000000000000000000000000000000000000000000000000000000081565b34801561098c57600080fd5b5061036f61099b366004613644565b611c78565b3480156109ac57600080fd5b506109c06109bb366004613a83565b611d4f565b60405161037b9190613ddd565b3480156109d957600080fd5b506104576109e8366004613538565b611f03565b3480156109f957600080fd5b506103b87f000000000000000000000000000000000000000000000000000000000000000081565b348015610a2d57600080fd5b50610457610a3c366004613538565b61204d565b348015610a4d57600080fd5b506103b8620f424081565b348015610a6457600080fd5b50610ab7610a73366004613538565b60066020526000908152604090205465ffffffffffff8082169166010000000000008104909116906c0100000000000000000000000090046001600160a01b031683565b6040805165ffffffffffff94851681529390921660208401526001600160a01b03169082015260600161037b565b348015610af157600080fd5b506103b8610b00366004613538565b6120f9565b348015610b1157600080fd5b506103b87f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f5581565b348015610b4557600080fd5b50610457610b54366004613644565b612110565b348015610b6557600080fd5b506103b87f60044782a422109ac08a415e44260ad5d3bad63d96ebe1fac0363399642ee3f281565b348015610b9957600080fd5b506103b8610ba8366004613627565b60036020526000908152604090205481565b348015610bc657600080fd5b506103b87f000000000000000000000000000000000000000000000000000000000000000081565b348015610bfa57600080fd5b50610457610c09366004613a83565b612135565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f5a05180f000000000000000000000000000000000000000000000000000000001480610c645750610c6482612141565b92915050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f55610c94816121d8565b6001600160a01b03831660009081526003602052604081205490819003610cbb5750505050565b6001600160a01b038481166000818152600360209081526040808320929092558151928352928616928201929092529081018290527f244e51bc38c1452fa8aaf487bcb4bca36c2baa3a5fbdb776b1eabd8dc6d277cd9060600160405180910390a17fffffffffffffffffffffffff11111111111111111111111111111111111111126001600160a01b03851601610d5c57610d5783826121e2565b610d70565b610d706001600160a01b03851684836122b0565b505b505050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f55610da1816121d8565b610daa82612324565b5050565b600082815260208190526040902060010154610dc9816121d8565b610d7083836123a5565b6001600160a01b0381163314610e15576040517f6697b23200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610d7282826123d2565b60608267ffffffffffffffff811115610e3a57610e3a6138b1565b604051908082528060200260200182016040528015610e8057816020015b604080518082019091526000815260606020820152815260200190600190039081610e585790505b50905060005b83811015610fa55730858583818110610ea157610ea1613ec3565b9050602002810190610eb39190613ef2565b604051610ec1929190613f57565b600060405180830381855af49150503d8060008114610efc576040519150601f19603f3d011682016040523d82523d6000602084013e610f01565b606091505b50838381518110610f1457610f14613ec3565b6020026020010151600001848481518110610f3157610f31613ec3565b602002602001015160200182905282151515158152505050818181518110610f5b57610f5b613ec3565b602002602001015160000151158015610f72575082155b15610f9d57610f9d828281518110610f8c57610f8c613ec3565b6020026020010151602001516123ff565b600101610e86565b509392505050565b610fb78383612441565b60008383604051610fc9929190613f57565b60405180910390209050610fdf848483856124c2565b600081815260066020526040902080546001600160a01b0384166c0100000000000000000000000081026bffffffffffffffffffffffff4265ffffffffffff9081166601000000000000027fffffffffffffffffffffffffffffffffffffffff000000000000000000000000909516439190911617939093179290921691909117909155601e850135606090811c91604687013590911c90607a8701359061012e880135908490867ff8ae392d784b1ea5e8881bfa586d81abf07ef4f1e2fc75f7fe51c90f05199a5c60028c013560e01c6040805163ffffffff92909216825260328e0135606090811c60208401526001600160a01b038a1683830152605a8f0135908301526080820188905260a08201879052519081900360c00190a47fffffffffffffffffffffffff11111111111111111111111111111111111111126001600160a01b038416016111a3578015611165576040517f846dedc000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b81341461119e576040517f81de0bf300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6111f1565b8034146111dc576040517f81de0bf300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6111f16001600160a01b038416338685612657565b3660006111fe8a8a612690565b9092509050801561121b5761121686868685856126ac565b61122b565b341561122b5761122b86346121e2565b50505050505050505050565b60005b82811015610d70576000803086868581811061125857611258613ec3565b905060200281019061126a9190613ef2565b604051611278929190613f57565b600060405180830381855af49150503d80600081146112b3576040519150601f19603f3d011682016040523d82523d6000602084013e6112b8565b606091505b5091509150811580156112c9575083155b156112d7576112d7816123ff565b505060010161123a565b6112eb8383612441565b600083836040516112fd929190613f57565b604080519182900390912060008181526005602052919091208054919250906c0100000000000000000000000081046001600160a01b03169060ff81169065010000000000900466ffffffffffffff16600282600481111561136157611361613551565b14611398576040517f4145817200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6107084282900366ffffffffffffff16116113df576040517f1992d0bd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600160a01b0386166113f557829550611437565b6001600160a01b0383163314611437576040517f4af43a9000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b83547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166003178455603288013560601c605a890135609a8a013580156114a6576001600160a01b038316600090815260036020526040812080548392906114a0908490613f96565b90915550505b604080516001600160a01b03858116825260208201859052808c1692908916918b917f582211c35a2139ac3bbaac74663c6a1f56c6cbb658b41fe11fd45a82074ac678910160405180910390a47fffffffffffffffffffffffff11111111111111111111111111111111111111126001600160a01b038416016115325761152d89836121e2565b611546565b6115466001600160a01b0384168a846122b0565b5050505050505050505050565b7f60044782a422109ac08a415e44260ad5d3bad63d96ebe1fac0363399642ee3f261157d816121d8565b60008481526005602052604090206001815460ff1660048111156115a3576115a3613551565b146115da576040517f4145817200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80546001600160a01b0384166c0100000000000000000000000081026bffffffffffffffffffffffff66ffffffffffffff421665010000000000021664ffffffff009093169290921791909117600217825560405185815286907f4ac8af8a2cd87193d64dfc7a3b8d9923b714ec528b18725d080aa1299be0c5e49060200160405180910390a35050505050565b6116c2816040518060a0016040528060006001600160a01b0316815260200160008152602001604051806020016040528060008152508152602001600081526020016040518060200160405280600081525081525061199a565b50565b611777604051806101e00160405280600063ffffffff168152602001600063ffffffff16815260200160006001600160a01b0316815260200160006001600160a01b0316815260200160006001600160a01b0316815260200160006001600160a01b03168152602001600081526020016000815260200160008152602001600081526020016000815260200160006001600160a01b031681526020016000815260200160008152602001606081525090565b6117818383612441565b61178b8383612808565b9392505050565b610daa82825b6117a28282612441565b600082826040516117b4929190613f57565b604080519182900390912060008181526005602052919091209091506001815460ff1660048111156117e8576117e8613551565b1461181f576040517f4145817200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b3360009081527f4527d8b28c468984933d33ae052f26b21c15ca0e7fdec762bba08e540e237001602052604090205460ba8501359060ff1661186b576004546118689082613f96565b90505b8042116118a4576040517fe15ff9ea00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b81547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166004178255600a850135606090811c906032870135901c60006118f3609a890135605a8a0135613f96565b604080516001600160a01b03858116825260208201849052825193945086169289927fb4c55c0c9bc613519b920e88748090150b890a875d307f21bea7d4fb2e8bc958928290030190a37fffffffffffffffffffffffff11111111111111111111111111111111111111126001600160a01b0383160161197c5761197783826121e2565b611990565b6119906001600160a01b03831684836122b0565b5050505050505050565b80516000906001600160a01b0316156119bf5760208201516119bc9042613fa9565b90505b6119ca8383836129aa565b60006119de84606001518560a00151612c2e565b90506000806002541115611a1757620f4240600254836119fe9190613fd1565b611a089190613fe8565b9050611a148183614023565b91505b6000611b20604051806101e001604052804663ffffffff168152602001886000015163ffffffff16815260200188602001516001600160a01b0316815260200188604001516001600160a01b0316815260200188606001516001600160a01b0316815260200188608001516001600160a01b031681526020018581526020018860c0015181526020018481526020018861010001518152602001600760008a602001516001600160a01b03166001600160a01b031681526020019081526020016000206000815480929190611aeb90614036565b90915550815287516001600160a01b031660208201526040810187905260608089015190820152608080890151910152612e41565b805160208083019190912060008181526005835260409081902080548b5163ffffffff8116610100027fffffffffffffffffffffffffffffffffffffffffffffffffffffff000000000090921691909117600117909155928a01516060808c015160808d015160c08e0151928d0151945197985094966001600160a01b039093169587957f120ea0364f36cdac7983bcfdd55270ca09d7f9b314a2ebc425a3b01ab1d6403a95611bdc958b959394938e9290919015159061406e565b60405180910390a3807f3120e2bb59c86aca6890191a589a96af3662838efa374fbdcdf4c95bfe4a6c0e8760400151604051611c1891906140c4565b60405180910390a250505050505050565b611c338383612441565b610d728383604051611c46929190613f57565b60405180910390208233611553565b610daa828233610fad565b600082815260016020526040812061178b9083612f86565b60008281526005602052604081206002815460ff166004811115611c9e57611c9e613551565b14611cd5576040517f4145817200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80546001600160a01b038481166c010000000000000000000000009092041614611d2b576040517f4af43a9000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b546107086501000000000090910466ffffffffffffff908116420316119392505050565b6040805161018081018252600080825260208201819052818301819052606082018190526080820181905260a0820181905260c0820181905260e0820181905261010082018190526101208201819052610140820181905261016082015290517f5aa6ccba0000000000000000000000000000000000000000000000000000000081523090635aa6ccba90611dea9086908690600401614102565b600060405180830381865afa925050508015611e2857506040513d6000823e601f3d908101601f19168201604052611e259190810190614171565b60015b611e3f57611e38828401846142a6565b9050610c64565b604051806101800160405280826000015163ffffffff168152602001826020015163ffffffff16815260200182604001516001600160a01b0316815260200182606001516001600160a01b0316815260200182608001516001600160a01b031681526020018260a001516001600160a01b031681526020018260c0015181526020018260e0015181526020018261010001518152602001826101a0015160001415151581526020018261012001518152602001826101400151815250915050610c64565b7f043c983c49d46f0e102151eaf8085d4a2e6571d5df2d47b013f39bddfd4a639d611f2d816121d8565b600082815260056020526040902080546c0100000000000000000000000081046001600160a01b03169060ff81169065010000000000900466ffffffffffffff166002826004811115611f8257611f82613551565b14611fb9576040517f4145817200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6107084282900366ffffffffffffff161115612001576040517f3e908aac00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b835464ffffffff001660011784556040516001600160a01b0384169087907f0695cf1d39b3055dcd0fe02d8b47eaf0d5a13e1996de925de59d0ef9b7f7fad490600090a3505050505050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f55612077816121d8565b6127108211156120b3576040517f9b569b8100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600280549083905560408051828152602081018590527f14914da2bf76024616fbe1859783fcd4dbddcb179b1f3a854949fbf920dcb957910160405180910390a1505050565b6000818152600160205260408120610c6490612f92565b60008281526020819052604090206001015461212b816121d8565b610d7083836123d2565b610daa828260006112e1565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f7965db0b000000000000000000000000000000000000000000000000000000001480610c6457507f01ffc9a7000000000000000000000000000000000000000000000000000000007fffffffff00000000000000000000000000000000000000000000000000000000831614610c64565b6116c28133612f9c565b80471015612223576040517fcd7860590000000000000000000000000000000000000000000000000000000081523060048201526024015b60405180910390fd5b6000826001600160a01b03168260405160006040518083038185875af1925050503d8060008114612270576040519150601f19603f3d011682016040523d82523d6000602084013e612275565b606091505b5050905080610d72576040517f1425ea4200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040516001600160a01b03838116602483015260448201839052610d7291859182169063a9059cbb906064015b604051602081830303815290604052915060e01b6020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8381831617835250505050613008565b610e10811015612360576040517f0e0ea5c700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600480549082905560408051828152602081018490527f909f9078b2f6eac1d10f2aae793656c5a67511eb627ebd1d2cb1eb9c0ab94c95910160405180910390a15050565b6000806123b28484613084565b9050801561178b576000848152600160205260409020610fa5908461314c565b6000806123df8484613161565b9050801561178b576000848152600160205260409020610fa59084613202565b80511561240f5780518082602001fd5b6040517f5ead5a9d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61014e81101561247d576040517f6ee0e17100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b813560f01c60028114610d72576040517f8bd977e700000000000000000000000000000000000000000000000000000000815261ffff8216600482015260240161221a565b6001600160a01b038116612502576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000828152600660205260409020546c0100000000000000000000000090046001600160a01b031615612561576040517fbef7bb7d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600684013560e01c46146125a1576040517f7029fdf900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60ba8401354211156125df576040517f559895a300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60fa84013560601c80158015906126085750816001600160a01b0316816001600160a01b031614155b8015612619575061010e8501354211155b15612650576040517f14be123200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5050505050565b6040516001600160a01b038481166024830152838116604483015260648201839052610d709186918216906323b872dd906084016122dd565b3660006126a18361014e8187614372565b915091509250929050565b600061272786868686866040516024016126c9949392919061439c565b60408051601f198184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fe85e13dd0000000000000000000000000000000000000000000000000000000017905234613217565b90508051600003612764576040517f1a95ad2600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b805160201461279f576040517ff3725cca00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7fe85e13dd000000000000000000000000000000000000000000000000000000006127c9826143c5565b14612800576040517ff3725cca00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b505050505050565b6128ba604051806101e00160405280600063ffffffff168152602001600063ffffffff16815260200160006001600160a01b0316815260200160006001600160a01b0316815260200160006001600160a01b0316815260200160006001600160a01b03168152602001600081526020016000815260200160008152602001600081526020016000815260200160006001600160a01b031681526020016000815260200160008152602001606081525090565b600283013560e090811c82526006840135811c6020830152600a840135606090811c6040840152601e850135811c818401526032850135811c60808401526046850135811c60a0840152605a85013560c0840152607a85013591830191909152609a84013561010083015260ba84013561012083015260da84013561014083015260fa840135901c61016082015261010e83013561018082015261012e8301356101a082015261296a8383612690565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152505050506101c082015292915050565b46836000015163ffffffff16036129ed576040517f7029fdf900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60a08301511580612a00575060c0830151155b15612a37576040517fe38820c800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60208301516001600160a01b03161580612a5c575060408301516001600160a01b0316155b15612a93576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60608301516001600160a01b03161580612ab8575060808301516001600160a01b0316155b15612aef576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b612afb61070842613f96565b8361010001511015612b39576040517f04b7fcc800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61ffff8260800151511115612b7a576040517f177a70e100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b606082015115801590612bad575060808301516001600160a01b031673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee145b15612be4576040517f846dedc000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000811280612bf7575082610100015181135b15610d72576040517f352807b900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60007fffffffffffffffffffffffff11111111111111111111111111111111111111126001600160a01b03841601612ca057348214612c99576040517f81de0bf300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5034610c64565b3415612cd8576040517f81de0bf300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b826001600160a01b03163b600003612d1c576040517f7f523fe800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201526001600160a01b038416906370a0823190602401602060405180830381865afa158015612d79573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612d9d919061440a565b9050612db46001600160a01b038416333085612657565b6040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015281906001600160a01b038516906370a0823190602401602060405180830381865afa158015612e13573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612e37919061440a565b61178b9190614023565b8051602080830151604080850151606086810151608088015160a089015160c08a015195517e02000000000000000000000000000000000000000000000000000000000000988101989098527fffffffff0000000000000000000000000000000000000000000000000000000060e0998a1b811660228a01529690981b90951660268701527fffffffffffffffffffffffffffffffffffffffff00000000000000000000000092821b8316602a870152811b8216603e86015292831b8116605285015293821b9093166066830152607a820192909252600090609a0160408051601f198184030181529082905260e08501516101008601516101208701516101408801516101608901516101808a01516101a08b01516101c08c0151979950612f6f988a9890602001614423565b604051602081830303815290604052915050919050565b600061178b83836132cd565b6000610c64825490565b6000828152602081815260408083206001600160a01b038516845290915290205460ff16610daa576040517fe2517d3f0000000000000000000000000000000000000000000000000000000081526001600160a01b03821660048201526024810183905260440161221a565b600061301d6001600160a01b038416836132f7565b9050805160001415801561304257508080602001905181019061304091906144ac565b155b15610d72576040517f5274afe70000000000000000000000000000000000000000000000000000000081526001600160a01b038416600482015260240161221a565b6000828152602081815260408083206001600160a01b038516845290915281205460ff16613144576000838152602081815260408083206001600160a01b0386168452909152902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790556130fc3390565b6001600160a01b0316826001600160a01b0316847f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a4506001610c64565b506000610c64565b600061178b836001600160a01b038416613305565b6000828152602081815260408083206001600160a01b038516845290915281205460ff1615613144576000838152602081815260408083206001600160a01b038616808552925280832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016905551339286917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a4506001610c64565b600061178b836001600160a01b03841661334c565b606081471015613255576040517fcd78605900000000000000000000000000000000000000000000000000000000815230600482015260240161221a565b600080856001600160a01b0316848660405161327191906144c9565b60006040518083038185875af1925050503d80600081146132ae576040519150601f19603f3d011682016040523d82523d6000602084013e6132b3565b606091505b50915091506132c386838361343f565b9695505050505050565b60008260000182815481106132e4576132e4613ec3565b9060005260206000200154905092915050565b606061178b83836000613217565b600081815260018301602052604081205461314457508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155610c64565b60008181526001830160205260408120548015613435576000613370600183614023565b855490915060009061338490600190614023565b90508082146133e95760008660000182815481106133a4576133a4613ec3565b90600052602060002001549050808760000184815481106133c7576133c7613ec3565b6000918252602080832090910192909255918252600188019052604090208390555b85548690806133fa576133fa6144e5565b600190038181906000526020600020016000905590558560010160008681526020019081526020016000206000905560019350505050610c64565b6000915050610c64565b6060826134545761344f826134b4565b61178b565b815115801561346b57506001600160a01b0384163b155b156134ad576040517f9996b3150000000000000000000000000000000000000000000000000000000081526001600160a01b038516600482015260240161221a565b508061178b565b8051156134c45780518082602001fd5b6040517f1425ea4200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006020828403121561350857600080fd5b81357fffffffff000000000000000000000000000000000000000000000000000000008116811461178b57600080fd5b60006020828403121561354a57600080fd5b5035919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b600581106135b7577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b9052565b60208101610c648284613580565b6001600160a01b03811681146116c257600080fd5b80356135e9816135c9565b919050565b6000806040838503121561360157600080fd5b823561360c816135c9565b9150602083013561361c816135c9565b809150509250929050565b60006020828403121561363957600080fd5b813561178b816135c9565b6000806040838503121561365757600080fd5b82359150602083013561361c816135c9565b80151581146116c257600080fd5b80356135e981613669565b60008060006040848603121561369757600080fd5b833567ffffffffffffffff808211156136af57600080fd5b818601915086601f8301126136c357600080fd5b8135818111156136d257600080fd5b8760208260051b85010111156136e757600080fd5b602092830195509350508401356136fd81613669565b809150509250925092565b60005b8381101561372357818101518382015260200161370b565b50506000910152565b60008151808452613744816020860160208601613708565b601f01601f19169290920160200192915050565b600060208083018184528085518083526040925060408601915060408160051b87010184880160005b838110156137e0578883037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc001855281518051151584528701518784018790526137cd8785018261372c565b9588019593505090860190600101613781565b509098975050505050505050565b60008083601f84011261380057600080fd5b50813567ffffffffffffffff81111561381857600080fd5b60208301915083602082850101111561383057600080fd5b9250929050565b60008060006040848603121561384c57600080fd5b833567ffffffffffffffff81111561386357600080fd5b61386f868287016137ee565b90945092505060208401356136fd816135c9565b60008060006060848603121561389857600080fd5b833592506020840135915060408401356136fd816135c9565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051610120810167ffffffffffffffff81118282101715613904576139046138b1565b60405290565b60405160a0810167ffffffffffffffff81118282101715613904576139046138b1565b6040516101e0810167ffffffffffffffff81118282101715613904576139046138b1565b604051610180810167ffffffffffffffff81118282101715613904576139046138b1565b604051601f8201601f1916810167ffffffffffffffff8111828210171561399e5761399e6138b1565b604052919050565b63ffffffff811681146116c257600080fd5b80356135e9816139a6565b600061012082840312156139d657600080fd5b6139de6138e0565b90506139e9826139b8565b81526139f7602083016135de565b6020820152613a08604083016135de565b6040820152613a19606083016135de565b6060820152613a2a608083016135de565b608082015260a082013560a082015260c082013560c0820152613a4f60e08301613677565b60e082015261010080830135818301525092915050565b60006101208284031215613a7957600080fd5b61178b83836139c3565b60008060208385031215613a9657600080fd5b823567ffffffffffffffff811115613aad57600080fd5b613ab9858286016137ee565b90969095509350505050565b60208152613adc60208201835163ffffffff169052565b60006020830151613af5604084018263ffffffff169052565b5060408301516001600160a01b03811660608401525060608301516001600160a01b03811660808401525060808301516001600160a01b03811660a08401525060a08301516001600160a01b03811660c08401525060c083015160e08381019190915283015161010080840191909152830151610120808401919091528301516101408084019190915283015161016080840191909152830151610180613ba6818501836001600160a01b03169052565b8401516101a0848101919091528401516101c0808501919091528401516101e0808501529050613bda61020084018261372c565b949350505050565b60808101613bf08287613580565b63ffffffff8516602083015266ffffffffffffff841660408301526001600160a01b038316606083015295945050505050565b600067ffffffffffffffff821115613c3d57613c3d6138b1565b50601f01601f191660200190565b600082601f830112613c5c57600080fd5b8135613c6f613c6a82613c23565b613975565b818152846020838601011115613c8457600080fd5b816020850160208301376000918101602001919091529392505050565b6000806101408385031215613cb557600080fd5b613cbf84846139c3565b915061012083013567ffffffffffffffff80821115613cdd57600080fd5b9084019060a08287031215613cf157600080fd5b613cf961390a565b8235613d04816135c9565b815260208381013590820152604083013582811115613d2257600080fd5b613d2e88828601613c4b565b60408301525060608301356060820152608083013582811115613d5057600080fd5b613d5c88828601613c4b565b6080830152508093505050509250929050565b600080600060408486031215613d8457600080fd5b833567ffffffffffffffff811115613d9b57600080fd5b613da7868287016137ee565b909790965060209590950135949350505050565b60008060408385031215613dce57600080fd5b50508035926020909101359150565b815163ffffffff16815261018081016020830151613e03602084018263ffffffff169052565b506040830151613e1e60408401826001600160a01b03169052565b506060830151613e3960608401826001600160a01b03169052565b506080830151613e5460808401826001600160a01b03169052565b5060a0830151613e6f60a08401826001600160a01b03169052565b5060c083015160c083015260e083015160e083015261010080840151818401525061012080840151613ea48285018215159052565b5050610140838101519083015261016092830151929091019190915290565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112613f2757600080fd5b83018035915067ffffffffffffffff821115613f4257600080fd5b60200191503681900382131561383057600080fd5b8183823760009101908152919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b80820180821115610c6457610c64613f67565b8082018281126000831280158216821582161715613fc957613fc9613f67565b505092915050565b8082028115828204841417610c6457610c64613f67565b60008261401e577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b81810381811115610c6457610c64613f67565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820361406757614067613f67565b5060010190565b60e08152600061408160e083018a61372c565b63ffffffff989098166020830152506001600160a01b039586166040820152939094166060840152608083019190915260a082015290151560c090910152919050565b60208152600061178b602083018461372c565b818352818160208501375060006020828401015260006020601f19601f840116840101905092915050565b602081526000613bda6020830184866140d7565b80516135e9816139a6565b80516135e9816135c9565b600082601f83011261413d57600080fd5b815161414b613c6a82613c23565b81815284602083860101111561416057600080fd5b613bda826020830160208701613708565b60006020828403121561418357600080fd5b815167ffffffffffffffff8082111561419b57600080fd5b908301906101e082860312156141b057600080fd5b6141b861392d565b6141c183614116565b81526141cf60208401614116565b60208201526141e060408401614121565b60408201526141f160608401614121565b606082015261420260808401614121565b608082015261421360a08401614121565b60a082015260c0838101519082015260e0808401519082015261010080840151908201526101208084015190820152610140808401519082015261016061425b818501614121565b9082015261018083810151908201526101a080840151908201526101c0808401518381111561428957600080fd5b6142958882870161412c565b918301919091525095945050505050565b600061018082840312156142b957600080fd5b6142c1613951565b6142ca836139b8565b81526142d8602084016139b8565b60208201526142e9604084016135de565b60408201526142fa606084016135de565b606082015261430b608084016135de565b608082015261431c60a084016135de565b60a082015260c083013560c082015260e083013560e082015261010080840135818301525061012061434f818501613677565b908201526101408381013590820152610160928301359281019290925250919050565b6000808585111561438257600080fd5b8386111561438f57600080fd5b5050820193919092039150565b6001600160a01b03851681528360208201526060604082015260006132c36060830184866140d7565b80516020808301519190811015614404577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8160200360031b1b821691505b50919050565b60006020828403121561441c57600080fd5b5051919050565b60008a51614435818460208f01613708565b80830190508a81528960208201528860408201528760608201527fffffffffffffffffffffffffffffffffffffffff0000000000000000000000008760601b1660808201528560948201528460b482015283516144998160d4840160208801613708565b0160d4019b9a5050505050505050505050565b6000602082840312156144be57600080fd5b815161178b81613669565b600082516144db818460208701613708565b9190910192915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fdfea264697066735822122082edd55575a2d7fd882d29c1a5d3a24f84d274aca2cf25f32089fce5162775cc64736f6c63430008180033", } // FastBridgeV2ABI is the input ABI used to generate the binding from. @@ -4606,7 +4606,7 @@ var FastBridgeV2FuncSigs = FastBridgeV2MetaData.Sigs var FastBridgeV2Bin = FastBridgeV2MetaData.Bin // DeployFastBridgeV2 deploys a new Ethereum contract, binding an instance of FastBridgeV2 to it. -func DeployFastBridgeV2(auth *bind.TransactOpts, backend bind.ContractBackend, _owner common.Address) (common.Address, *types.Transaction, *FastBridgeV2, error) { +func DeployFastBridgeV2(auth *bind.TransactOpts, backend bind.ContractBackend, defaultAdmin common.Address) (common.Address, *types.Transaction, *FastBridgeV2, error) { parsed, err := FastBridgeV2MetaData.GetAbi() if err != nil { return common.Address{}, nil, nil, err @@ -4615,7 +4615,7 @@ func DeployFastBridgeV2(auth *bind.TransactOpts, backend bind.ContractBackend, _ return common.Address{}, nil, nil, errors.New("GetABI returned nil") } - address, tx, contract, err := bind.DeployContract(auth, *parsed, common.FromHex(FastBridgeV2Bin), backend, _owner) + address, tx, contract, err := bind.DeployContract(auth, *parsed, common.FromHex(FastBridgeV2Bin), backend, defaultAdmin) if err != nil { return common.Address{}, nil, nil, err } @@ -5896,46 +5896,46 @@ func (_FastBridgeV2 *FastBridgeV2TransactorSession) Bridge(params IFastBridgeBri return _FastBridgeV2.Contract.Bridge(&_FastBridgeV2.TransactOpts, params) } -// Bridge0 is a paid mutator transaction binding the contract method 0xbfc7c607. +// BridgeV2 is a paid mutator transaction binding the contract method 0x76443085. // -// Solidity: function bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256) params, (address,int256,bytes,uint256,bytes) paramsV2) payable returns() -func (_FastBridgeV2 *FastBridgeV2Transactor) Bridge0(opts *bind.TransactOpts, params IFastBridgeBridgeParams, paramsV2 IFastBridgeV2BridgeParamsV2) (*types.Transaction, error) { - return _FastBridgeV2.contract.Transact(opts, "bridge0", params, paramsV2) +// Solidity: function bridgeV2((uint32,address,address,address,address,uint256,uint256,bool,uint256) params, (address,int256,bytes,uint256,bytes) paramsV2) payable returns() +func (_FastBridgeV2 *FastBridgeV2Transactor) BridgeV2(opts *bind.TransactOpts, params IFastBridgeBridgeParams, paramsV2 IFastBridgeV2BridgeParamsV2) (*types.Transaction, error) { + return _FastBridgeV2.contract.Transact(opts, "bridgeV2", params, paramsV2) } -// Bridge0 is a paid mutator transaction binding the contract method 0xbfc7c607. +// BridgeV2 is a paid mutator transaction binding the contract method 0x76443085. // -// Solidity: function bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256) params, (address,int256,bytes,uint256,bytes) paramsV2) payable returns() -func (_FastBridgeV2 *FastBridgeV2Session) Bridge0(params IFastBridgeBridgeParams, paramsV2 IFastBridgeV2BridgeParamsV2) (*types.Transaction, error) { - return _FastBridgeV2.Contract.Bridge0(&_FastBridgeV2.TransactOpts, params, paramsV2) +// Solidity: function bridgeV2((uint32,address,address,address,address,uint256,uint256,bool,uint256) params, (address,int256,bytes,uint256,bytes) paramsV2) payable returns() +func (_FastBridgeV2 *FastBridgeV2Session) BridgeV2(params IFastBridgeBridgeParams, paramsV2 IFastBridgeV2BridgeParamsV2) (*types.Transaction, error) { + return _FastBridgeV2.Contract.BridgeV2(&_FastBridgeV2.TransactOpts, params, paramsV2) } -// Bridge0 is a paid mutator transaction binding the contract method 0xbfc7c607. +// BridgeV2 is a paid mutator transaction binding the contract method 0x76443085. // -// Solidity: function bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256) params, (address,int256,bytes,uint256,bytes) paramsV2) payable returns() -func (_FastBridgeV2 *FastBridgeV2TransactorSession) Bridge0(params IFastBridgeBridgeParams, paramsV2 IFastBridgeV2BridgeParamsV2) (*types.Transaction, error) { - return _FastBridgeV2.Contract.Bridge0(&_FastBridgeV2.TransactOpts, params, paramsV2) +// Solidity: function bridgeV2((uint32,address,address,address,address,uint256,uint256,bool,uint256) params, (address,int256,bytes,uint256,bytes) paramsV2) payable returns() +func (_FastBridgeV2 *FastBridgeV2TransactorSession) BridgeV2(params IFastBridgeBridgeParams, paramsV2 IFastBridgeV2BridgeParamsV2) (*types.Transaction, error) { + return _FastBridgeV2.Contract.BridgeV2(&_FastBridgeV2.TransactOpts, params, paramsV2) } -// Cancel is a paid mutator transaction binding the contract method 0x3c5beeb4. +// CancelV2 is a paid mutator transaction binding the contract method 0x67e60693. // -// Solidity: function cancel(bytes request) returns() -func (_FastBridgeV2 *FastBridgeV2Transactor) Cancel(opts *bind.TransactOpts, request []byte) (*types.Transaction, error) { - return _FastBridgeV2.contract.Transact(opts, "cancel", request) +// Solidity: function cancelV2(bytes request) returns() +func (_FastBridgeV2 *FastBridgeV2Transactor) CancelV2(opts *bind.TransactOpts, request []byte) (*types.Transaction, error) { + return _FastBridgeV2.contract.Transact(opts, "cancelV2", request) } -// Cancel is a paid mutator transaction binding the contract method 0x3c5beeb4. +// CancelV2 is a paid mutator transaction binding the contract method 0x67e60693. // -// Solidity: function cancel(bytes request) returns() -func (_FastBridgeV2 *FastBridgeV2Session) Cancel(request []byte) (*types.Transaction, error) { - return _FastBridgeV2.Contract.Cancel(&_FastBridgeV2.TransactOpts, request) +// Solidity: function cancelV2(bytes request) returns() +func (_FastBridgeV2 *FastBridgeV2Session) CancelV2(request []byte) (*types.Transaction, error) { + return _FastBridgeV2.Contract.CancelV2(&_FastBridgeV2.TransactOpts, request) } -// Cancel is a paid mutator transaction binding the contract method 0x3c5beeb4. +// CancelV2 is a paid mutator transaction binding the contract method 0x67e60693. // -// Solidity: function cancel(bytes request) returns() -func (_FastBridgeV2 *FastBridgeV2TransactorSession) Cancel(request []byte) (*types.Transaction, error) { - return _FastBridgeV2.Contract.Cancel(&_FastBridgeV2.TransactOpts, request) +// Solidity: function cancelV2(bytes request) returns() +func (_FastBridgeV2 *FastBridgeV2TransactorSession) CancelV2(request []byte) (*types.Transaction, error) { + return _FastBridgeV2.Contract.CancelV2(&_FastBridgeV2.TransactOpts, request) } // Claim is a paid mutator transaction binding the contract method 0x41fcb612. @@ -5959,25 +5959,25 @@ func (_FastBridgeV2 *FastBridgeV2TransactorSession) Claim(request []byte, to com return _FastBridgeV2.Contract.Claim(&_FastBridgeV2.TransactOpts, request, to) } -// Claim0 is a paid mutator transaction binding the contract method 0xc63ff8dd. +// ClaimV2 is a paid mutator transaction binding the contract method 0xf76d7278. // -// Solidity: function claim(bytes request) returns() -func (_FastBridgeV2 *FastBridgeV2Transactor) Claim0(opts *bind.TransactOpts, request []byte) (*types.Transaction, error) { - return _FastBridgeV2.contract.Transact(opts, "claim0", request) +// Solidity: function claimV2(bytes request) returns() +func (_FastBridgeV2 *FastBridgeV2Transactor) ClaimV2(opts *bind.TransactOpts, request []byte) (*types.Transaction, error) { + return _FastBridgeV2.contract.Transact(opts, "claimV2", request) } -// Claim0 is a paid mutator transaction binding the contract method 0xc63ff8dd. +// ClaimV2 is a paid mutator transaction binding the contract method 0xf76d7278. // -// Solidity: function claim(bytes request) returns() -func (_FastBridgeV2 *FastBridgeV2Session) Claim0(request []byte) (*types.Transaction, error) { - return _FastBridgeV2.Contract.Claim0(&_FastBridgeV2.TransactOpts, request) +// Solidity: function claimV2(bytes request) returns() +func (_FastBridgeV2 *FastBridgeV2Session) ClaimV2(request []byte) (*types.Transaction, error) { + return _FastBridgeV2.Contract.ClaimV2(&_FastBridgeV2.TransactOpts, request) } -// Claim0 is a paid mutator transaction binding the contract method 0xc63ff8dd. +// ClaimV2 is a paid mutator transaction binding the contract method 0xf76d7278. // -// Solidity: function claim(bytes request) returns() -func (_FastBridgeV2 *FastBridgeV2TransactorSession) Claim0(request []byte) (*types.Transaction, error) { - return _FastBridgeV2.Contract.Claim0(&_FastBridgeV2.TransactOpts, request) +// Solidity: function claimV2(bytes request) returns() +func (_FastBridgeV2 *FastBridgeV2TransactorSession) ClaimV2(request []byte) (*types.Transaction, error) { + return _FastBridgeV2.Contract.ClaimV2(&_FastBridgeV2.TransactOpts, request) } // Dispute is a paid mutator transaction binding the contract method 0xadd98c70. @@ -6064,46 +6064,46 @@ func (_FastBridgeV2 *FastBridgeV2TransactorSession) MulticallWithResults(data [] return _FastBridgeV2.Contract.MulticallWithResults(&_FastBridgeV2.TransactOpts, data, ignoreReverts) } -// Prove is a paid mutator transaction binding the contract method 0x18e4357d. +// Prove is a paid mutator transaction binding the contract method 0x886d36ff. // -// Solidity: function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) returns() -func (_FastBridgeV2 *FastBridgeV2Transactor) Prove(opts *bind.TransactOpts, transactionId [32]byte, destTxHash [32]byte, relayer common.Address) (*types.Transaction, error) { - return _FastBridgeV2.contract.Transact(opts, "prove", transactionId, destTxHash, relayer) +// Solidity: function prove(bytes request, bytes32 destTxHash) returns() +func (_FastBridgeV2 *FastBridgeV2Transactor) Prove(opts *bind.TransactOpts, request []byte, destTxHash [32]byte) (*types.Transaction, error) { + return _FastBridgeV2.contract.Transact(opts, "prove", request, destTxHash) } -// Prove is a paid mutator transaction binding the contract method 0x18e4357d. +// Prove is a paid mutator transaction binding the contract method 0x886d36ff. // -// Solidity: function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) returns() -func (_FastBridgeV2 *FastBridgeV2Session) Prove(transactionId [32]byte, destTxHash [32]byte, relayer common.Address) (*types.Transaction, error) { - return _FastBridgeV2.Contract.Prove(&_FastBridgeV2.TransactOpts, transactionId, destTxHash, relayer) +// Solidity: function prove(bytes request, bytes32 destTxHash) returns() +func (_FastBridgeV2 *FastBridgeV2Session) Prove(request []byte, destTxHash [32]byte) (*types.Transaction, error) { + return _FastBridgeV2.Contract.Prove(&_FastBridgeV2.TransactOpts, request, destTxHash) } -// Prove is a paid mutator transaction binding the contract method 0x18e4357d. +// Prove is a paid mutator transaction binding the contract method 0x886d36ff. // -// Solidity: function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) returns() -func (_FastBridgeV2 *FastBridgeV2TransactorSession) Prove(transactionId [32]byte, destTxHash [32]byte, relayer common.Address) (*types.Transaction, error) { - return _FastBridgeV2.Contract.Prove(&_FastBridgeV2.TransactOpts, transactionId, destTxHash, relayer) +// Solidity: function prove(bytes request, bytes32 destTxHash) returns() +func (_FastBridgeV2 *FastBridgeV2TransactorSession) Prove(request []byte, destTxHash [32]byte) (*types.Transaction, error) { + return _FastBridgeV2.Contract.Prove(&_FastBridgeV2.TransactOpts, request, destTxHash) } -// Prove0 is a paid mutator transaction binding the contract method 0x886d36ff. +// ProveV2 is a paid mutator transaction binding the contract method 0x41fdec80. // -// Solidity: function prove(bytes request, bytes32 destTxHash) returns() -func (_FastBridgeV2 *FastBridgeV2Transactor) Prove0(opts *bind.TransactOpts, request []byte, destTxHash [32]byte) (*types.Transaction, error) { - return _FastBridgeV2.contract.Transact(opts, "prove0", request, destTxHash) +// Solidity: function proveV2(bytes32 transactionId, bytes32 destTxHash, address relayer) returns() +func (_FastBridgeV2 *FastBridgeV2Transactor) ProveV2(opts *bind.TransactOpts, transactionId [32]byte, destTxHash [32]byte, relayer common.Address) (*types.Transaction, error) { + return _FastBridgeV2.contract.Transact(opts, "proveV2", transactionId, destTxHash, relayer) } -// Prove0 is a paid mutator transaction binding the contract method 0x886d36ff. +// ProveV2 is a paid mutator transaction binding the contract method 0x41fdec80. // -// Solidity: function prove(bytes request, bytes32 destTxHash) returns() -func (_FastBridgeV2 *FastBridgeV2Session) Prove0(request []byte, destTxHash [32]byte) (*types.Transaction, error) { - return _FastBridgeV2.Contract.Prove0(&_FastBridgeV2.TransactOpts, request, destTxHash) +// Solidity: function proveV2(bytes32 transactionId, bytes32 destTxHash, address relayer) returns() +func (_FastBridgeV2 *FastBridgeV2Session) ProveV2(transactionId [32]byte, destTxHash [32]byte, relayer common.Address) (*types.Transaction, error) { + return _FastBridgeV2.Contract.ProveV2(&_FastBridgeV2.TransactOpts, transactionId, destTxHash, relayer) } -// Prove0 is a paid mutator transaction binding the contract method 0x886d36ff. +// ProveV2 is a paid mutator transaction binding the contract method 0x41fdec80. // -// Solidity: function prove(bytes request, bytes32 destTxHash) returns() -func (_FastBridgeV2 *FastBridgeV2TransactorSession) Prove0(request []byte, destTxHash [32]byte) (*types.Transaction, error) { - return _FastBridgeV2.Contract.Prove0(&_FastBridgeV2.TransactOpts, request, destTxHash) +// Solidity: function proveV2(bytes32 transactionId, bytes32 destTxHash, address relayer) returns() +func (_FastBridgeV2 *FastBridgeV2TransactorSession) ProveV2(transactionId [32]byte, destTxHash [32]byte, relayer common.Address) (*types.Transaction, error) { + return _FastBridgeV2.Contract.ProveV2(&_FastBridgeV2.TransactOpts, transactionId, destTxHash, relayer) } // Refund is a paid mutator transaction binding the contract method 0x5eb7d946. @@ -6148,25 +6148,25 @@ func (_FastBridgeV2 *FastBridgeV2TransactorSession) Relay(request []byte) (*type return _FastBridgeV2.Contract.Relay(&_FastBridgeV2.TransactOpts, request) } -// Relay0 is a paid mutator transaction binding the contract method 0x9c9545f0. +// RelayV2 is a paid mutator transaction binding the contract method 0x3d71e21f. // -// Solidity: function relay(bytes request, address relayer) payable returns() -func (_FastBridgeV2 *FastBridgeV2Transactor) Relay0(opts *bind.TransactOpts, request []byte, relayer common.Address) (*types.Transaction, error) { - return _FastBridgeV2.contract.Transact(opts, "relay0", request, relayer) +// Solidity: function relayV2(bytes request, address relayer) payable returns() +func (_FastBridgeV2 *FastBridgeV2Transactor) RelayV2(opts *bind.TransactOpts, request []byte, relayer common.Address) (*types.Transaction, error) { + return _FastBridgeV2.contract.Transact(opts, "relayV2", request, relayer) } -// Relay0 is a paid mutator transaction binding the contract method 0x9c9545f0. +// RelayV2 is a paid mutator transaction binding the contract method 0x3d71e21f. // -// Solidity: function relay(bytes request, address relayer) payable returns() -func (_FastBridgeV2 *FastBridgeV2Session) Relay0(request []byte, relayer common.Address) (*types.Transaction, error) { - return _FastBridgeV2.Contract.Relay0(&_FastBridgeV2.TransactOpts, request, relayer) +// Solidity: function relayV2(bytes request, address relayer) payable returns() +func (_FastBridgeV2 *FastBridgeV2Session) RelayV2(request []byte, relayer common.Address) (*types.Transaction, error) { + return _FastBridgeV2.Contract.RelayV2(&_FastBridgeV2.TransactOpts, request, relayer) } -// Relay0 is a paid mutator transaction binding the contract method 0x9c9545f0. +// RelayV2 is a paid mutator transaction binding the contract method 0x3d71e21f. // -// Solidity: function relay(bytes request, address relayer) payable returns() -func (_FastBridgeV2 *FastBridgeV2TransactorSession) Relay0(request []byte, relayer common.Address) (*types.Transaction, error) { - return _FastBridgeV2.Contract.Relay0(&_FastBridgeV2.TransactOpts, request, relayer) +// Solidity: function relayV2(bytes request, address relayer) payable returns() +func (_FastBridgeV2 *FastBridgeV2TransactorSession) RelayV2(request []byte, relayer common.Address) (*types.Transaction, error) { + return _FastBridgeV2.Contract.RelayV2(&_FastBridgeV2.TransactOpts, request, relayer) } // RenounceRole is a paid mutator transaction binding the contract method 0x36568abe. @@ -13023,25 +13023,25 @@ func (_IFastBridge *IFastBridgeFilterer) ParseBridgeRequested(log types.Log) (*I // IFastBridgeV2MetaData contains all meta data concerning the IFastBridgeV2 contract. var IFastBridgeV2MetaData = &bind.MetaData{ - ABI: "[{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"BridgeDepositClaimed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"BridgeDepositRefunded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"name\":\"BridgeProofDisputed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"transactionHash\",\"type\":\"bytes32\"}],\"name\":\"BridgeProofProvided\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"quoteId\",\"type\":\"bytes\"}],\"name\":\"BridgeQuoteDetails\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"originChainId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"chainGasAmount\",\"type\":\"uint256\"}],\"name\":\"BridgeRelayed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"destChainId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"sendChainGas\",\"type\":\"bool\"}],\"name\":\"BridgeRequested\",\"type\":\"event\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"dstChainId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"sendChainGas\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"}],\"internalType\":\"structIFastBridge.BridgeParams\",\"name\":\"params\",\"type\":\"tuple\"}],\"name\":\"bridge\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"dstChainId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"sendChainGas\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"}],\"internalType\":\"structIFastBridge.BridgeParams\",\"name\":\"params\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"quoteRelayer\",\"type\":\"address\"},{\"internalType\":\"int256\",\"name\":\"quoteExclusivitySeconds\",\"type\":\"int256\"},{\"internalType\":\"bytes\",\"name\":\"quoteId\",\"type\":\"bytes\"},{\"internalType\":\"uint256\",\"name\":\"zapNative\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"zapData\",\"type\":\"bytes\"}],\"internalType\":\"structIFastBridgeV2.BridgeParamsV2\",\"name\":\"paramsV2\",\"type\":\"tuple\"}],\"name\":\"bridge\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"}],\"name\":\"bridgeProofs\",\"outputs\":[{\"internalType\":\"uint96\",\"name\":\"timestamp\",\"type\":\"uint96\"},{\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"}],\"name\":\"bridgeRelays\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"}],\"name\":\"bridgeStatuses\",\"outputs\":[{\"internalType\":\"enumIFastBridgeV2.BridgeStatus\",\"name\":\"\",\"type\":\"uint8\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"name\":\"canClaim\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"cancel\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"claim\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"claim\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"}],\"name\":\"dispute\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"getBridgeTransaction\",\"outputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"originChainId\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"destChainId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"originSender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destRecipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"originFeeAmount\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"sendChainGas\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"}],\"internalType\":\"structIFastBridge.BridgeTransaction\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"getBridgeTransactionV2\",\"outputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"originChainId\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"destChainId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"originSender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destRecipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"originFeeAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"exclusivityRelayer\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"exclusivityEndTime\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"zapNative\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"zapData\",\"type\":\"bytes\"}],\"internalType\":\"structIFastBridgeV2.BridgeTransactionV2\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"destTxHash\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"name\":\"prove\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"},{\"internalType\":\"bytes32\",\"name\":\"destTxHash\",\"type\":\"bytes32\"}],\"name\":\"prove\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"refund\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"relay\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"},{\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"name\":\"relay\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"}]", + ABI: "[{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"BridgeDepositClaimed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"BridgeDepositRefunded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"name\":\"BridgeProofDisputed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"transactionHash\",\"type\":\"bytes32\"}],\"name\":\"BridgeProofProvided\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"quoteId\",\"type\":\"bytes\"}],\"name\":\"BridgeQuoteDetails\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"originChainId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"chainGasAmount\",\"type\":\"uint256\"}],\"name\":\"BridgeRelayed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"destChainId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"sendChainGas\",\"type\":\"bool\"}],\"name\":\"BridgeRequested\",\"type\":\"event\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"dstChainId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"sendChainGas\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"}],\"internalType\":\"structIFastBridge.BridgeParams\",\"name\":\"params\",\"type\":\"tuple\"}],\"name\":\"bridge\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"}],\"name\":\"bridgeProofs\",\"outputs\":[{\"internalType\":\"uint96\",\"name\":\"timestamp\",\"type\":\"uint96\"},{\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"}],\"name\":\"bridgeRelays\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"}],\"name\":\"bridgeStatuses\",\"outputs\":[{\"internalType\":\"enumIFastBridgeV2.BridgeStatus\",\"name\":\"\",\"type\":\"uint8\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"dstChainId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"sendChainGas\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"}],\"internalType\":\"structIFastBridge.BridgeParams\",\"name\":\"params\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"quoteRelayer\",\"type\":\"address\"},{\"internalType\":\"int256\",\"name\":\"quoteExclusivitySeconds\",\"type\":\"int256\"},{\"internalType\":\"bytes\",\"name\":\"quoteId\",\"type\":\"bytes\"},{\"internalType\":\"uint256\",\"name\":\"zapNative\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"zapData\",\"type\":\"bytes\"}],\"internalType\":\"structIFastBridgeV2.BridgeParamsV2\",\"name\":\"paramsV2\",\"type\":\"tuple\"}],\"name\":\"bridgeV2\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"name\":\"canClaim\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"cancelV2\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"claim\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"claimV2\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"}],\"name\":\"dispute\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"getBridgeTransaction\",\"outputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"originChainId\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"destChainId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"originSender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destRecipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"originFeeAmount\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"sendChainGas\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"}],\"internalType\":\"structIFastBridge.BridgeTransaction\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"getBridgeTransactionV2\",\"outputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"originChainId\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"destChainId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"originSender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destRecipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"originFeeAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"exclusivityRelayer\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"exclusivityEndTime\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"zapNative\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"zapData\",\"type\":\"bytes\"}],\"internalType\":\"structIFastBridgeV2.BridgeTransactionV2\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"},{\"internalType\":\"bytes32\",\"name\":\"destTxHash\",\"type\":\"bytes32\"}],\"name\":\"prove\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"destTxHash\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"name\":\"proveV2\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"refund\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"relay\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"},{\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"name\":\"relayV2\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"}]", Sigs: map[string]string{ "45851694": "bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256))", - "bfc7c607": "bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256),(address,int256,bytes,uint256,bytes))", "91ad5039": "bridgeProofs(bytes32)", "8379a24f": "bridgeRelays(bytes32)", "051287bc": "bridgeStatuses(bytes32)", + "76443085": "bridgeV2((uint32,address,address,address,address,uint256,uint256,bool,uint256),(address,int256,bytes,uint256,bytes))", "aa9641ab": "canClaim(bytes32,address)", - "3c5beeb4": "cancel(bytes)", - "c63ff8dd": "claim(bytes)", + "67e60693": "cancelV2(bytes)", "41fcb612": "claim(bytes,address)", + "f76d7278": "claimV2(bytes)", "add98c70": "dispute(bytes32)", "ac11fb1a": "getBridgeTransaction(bytes)", "5aa6ccba": "getBridgeTransactionV2(bytes)", "886d36ff": "prove(bytes,bytes32)", - "18e4357d": "prove(bytes32,bytes32,address)", + "41fdec80": "proveV2(bytes32,bytes32,address)", "5eb7d946": "refund(bytes)", "8f0d6f17": "relay(bytes)", - "9c9545f0": "relay(bytes,address)", + "3d71e21f": "relayV2(bytes,address)", }, } @@ -13416,46 +13416,46 @@ func (_IFastBridgeV2 *IFastBridgeV2TransactorSession) Bridge(params IFastBridgeB return _IFastBridgeV2.Contract.Bridge(&_IFastBridgeV2.TransactOpts, params) } -// Bridge0 is a paid mutator transaction binding the contract method 0xbfc7c607. +// BridgeV2 is a paid mutator transaction binding the contract method 0x76443085. // -// Solidity: function bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256) params, (address,int256,bytes,uint256,bytes) paramsV2) payable returns() -func (_IFastBridgeV2 *IFastBridgeV2Transactor) Bridge0(opts *bind.TransactOpts, params IFastBridgeBridgeParams, paramsV2 IFastBridgeV2BridgeParamsV2) (*types.Transaction, error) { - return _IFastBridgeV2.contract.Transact(opts, "bridge0", params, paramsV2) +// Solidity: function bridgeV2((uint32,address,address,address,address,uint256,uint256,bool,uint256) params, (address,int256,bytes,uint256,bytes) paramsV2) payable returns() +func (_IFastBridgeV2 *IFastBridgeV2Transactor) BridgeV2(opts *bind.TransactOpts, params IFastBridgeBridgeParams, paramsV2 IFastBridgeV2BridgeParamsV2) (*types.Transaction, error) { + return _IFastBridgeV2.contract.Transact(opts, "bridgeV2", params, paramsV2) } -// Bridge0 is a paid mutator transaction binding the contract method 0xbfc7c607. +// BridgeV2 is a paid mutator transaction binding the contract method 0x76443085. // -// Solidity: function bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256) params, (address,int256,bytes,uint256,bytes) paramsV2) payable returns() -func (_IFastBridgeV2 *IFastBridgeV2Session) Bridge0(params IFastBridgeBridgeParams, paramsV2 IFastBridgeV2BridgeParamsV2) (*types.Transaction, error) { - return _IFastBridgeV2.Contract.Bridge0(&_IFastBridgeV2.TransactOpts, params, paramsV2) +// Solidity: function bridgeV2((uint32,address,address,address,address,uint256,uint256,bool,uint256) params, (address,int256,bytes,uint256,bytes) paramsV2) payable returns() +func (_IFastBridgeV2 *IFastBridgeV2Session) BridgeV2(params IFastBridgeBridgeParams, paramsV2 IFastBridgeV2BridgeParamsV2) (*types.Transaction, error) { + return _IFastBridgeV2.Contract.BridgeV2(&_IFastBridgeV2.TransactOpts, params, paramsV2) } -// Bridge0 is a paid mutator transaction binding the contract method 0xbfc7c607. +// BridgeV2 is a paid mutator transaction binding the contract method 0x76443085. // -// Solidity: function bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256) params, (address,int256,bytes,uint256,bytes) paramsV2) payable returns() -func (_IFastBridgeV2 *IFastBridgeV2TransactorSession) Bridge0(params IFastBridgeBridgeParams, paramsV2 IFastBridgeV2BridgeParamsV2) (*types.Transaction, error) { - return _IFastBridgeV2.Contract.Bridge0(&_IFastBridgeV2.TransactOpts, params, paramsV2) +// Solidity: function bridgeV2((uint32,address,address,address,address,uint256,uint256,bool,uint256) params, (address,int256,bytes,uint256,bytes) paramsV2) payable returns() +func (_IFastBridgeV2 *IFastBridgeV2TransactorSession) BridgeV2(params IFastBridgeBridgeParams, paramsV2 IFastBridgeV2BridgeParamsV2) (*types.Transaction, error) { + return _IFastBridgeV2.Contract.BridgeV2(&_IFastBridgeV2.TransactOpts, params, paramsV2) } -// Cancel is a paid mutator transaction binding the contract method 0x3c5beeb4. +// CancelV2 is a paid mutator transaction binding the contract method 0x67e60693. // -// Solidity: function cancel(bytes request) returns() -func (_IFastBridgeV2 *IFastBridgeV2Transactor) Cancel(opts *bind.TransactOpts, request []byte) (*types.Transaction, error) { - return _IFastBridgeV2.contract.Transact(opts, "cancel", request) +// Solidity: function cancelV2(bytes request) returns() +func (_IFastBridgeV2 *IFastBridgeV2Transactor) CancelV2(opts *bind.TransactOpts, request []byte) (*types.Transaction, error) { + return _IFastBridgeV2.contract.Transact(opts, "cancelV2", request) } -// Cancel is a paid mutator transaction binding the contract method 0x3c5beeb4. +// CancelV2 is a paid mutator transaction binding the contract method 0x67e60693. // -// Solidity: function cancel(bytes request) returns() -func (_IFastBridgeV2 *IFastBridgeV2Session) Cancel(request []byte) (*types.Transaction, error) { - return _IFastBridgeV2.Contract.Cancel(&_IFastBridgeV2.TransactOpts, request) +// Solidity: function cancelV2(bytes request) returns() +func (_IFastBridgeV2 *IFastBridgeV2Session) CancelV2(request []byte) (*types.Transaction, error) { + return _IFastBridgeV2.Contract.CancelV2(&_IFastBridgeV2.TransactOpts, request) } -// Cancel is a paid mutator transaction binding the contract method 0x3c5beeb4. +// CancelV2 is a paid mutator transaction binding the contract method 0x67e60693. // -// Solidity: function cancel(bytes request) returns() -func (_IFastBridgeV2 *IFastBridgeV2TransactorSession) Cancel(request []byte) (*types.Transaction, error) { - return _IFastBridgeV2.Contract.Cancel(&_IFastBridgeV2.TransactOpts, request) +// Solidity: function cancelV2(bytes request) returns() +func (_IFastBridgeV2 *IFastBridgeV2TransactorSession) CancelV2(request []byte) (*types.Transaction, error) { + return _IFastBridgeV2.Contract.CancelV2(&_IFastBridgeV2.TransactOpts, request) } // Claim is a paid mutator transaction binding the contract method 0x41fcb612. @@ -13479,25 +13479,25 @@ func (_IFastBridgeV2 *IFastBridgeV2TransactorSession) Claim(request []byte, to c return _IFastBridgeV2.Contract.Claim(&_IFastBridgeV2.TransactOpts, request, to) } -// Claim0 is a paid mutator transaction binding the contract method 0xc63ff8dd. +// ClaimV2 is a paid mutator transaction binding the contract method 0xf76d7278. // -// Solidity: function claim(bytes request) returns() -func (_IFastBridgeV2 *IFastBridgeV2Transactor) Claim0(opts *bind.TransactOpts, request []byte) (*types.Transaction, error) { - return _IFastBridgeV2.contract.Transact(opts, "claim0", request) +// Solidity: function claimV2(bytes request) returns() +func (_IFastBridgeV2 *IFastBridgeV2Transactor) ClaimV2(opts *bind.TransactOpts, request []byte) (*types.Transaction, error) { + return _IFastBridgeV2.contract.Transact(opts, "claimV2", request) } -// Claim0 is a paid mutator transaction binding the contract method 0xc63ff8dd. +// ClaimV2 is a paid mutator transaction binding the contract method 0xf76d7278. // -// Solidity: function claim(bytes request) returns() -func (_IFastBridgeV2 *IFastBridgeV2Session) Claim0(request []byte) (*types.Transaction, error) { - return _IFastBridgeV2.Contract.Claim0(&_IFastBridgeV2.TransactOpts, request) +// Solidity: function claimV2(bytes request) returns() +func (_IFastBridgeV2 *IFastBridgeV2Session) ClaimV2(request []byte) (*types.Transaction, error) { + return _IFastBridgeV2.Contract.ClaimV2(&_IFastBridgeV2.TransactOpts, request) } -// Claim0 is a paid mutator transaction binding the contract method 0xc63ff8dd. +// ClaimV2 is a paid mutator transaction binding the contract method 0xf76d7278. // -// Solidity: function claim(bytes request) returns() -func (_IFastBridgeV2 *IFastBridgeV2TransactorSession) Claim0(request []byte) (*types.Transaction, error) { - return _IFastBridgeV2.Contract.Claim0(&_IFastBridgeV2.TransactOpts, request) +// Solidity: function claimV2(bytes request) returns() +func (_IFastBridgeV2 *IFastBridgeV2TransactorSession) ClaimV2(request []byte) (*types.Transaction, error) { + return _IFastBridgeV2.Contract.ClaimV2(&_IFastBridgeV2.TransactOpts, request) } // Dispute is a paid mutator transaction binding the contract method 0xadd98c70. @@ -13521,46 +13521,46 @@ func (_IFastBridgeV2 *IFastBridgeV2TransactorSession) Dispute(transactionId [32] return _IFastBridgeV2.Contract.Dispute(&_IFastBridgeV2.TransactOpts, transactionId) } -// Prove is a paid mutator transaction binding the contract method 0x18e4357d. +// Prove is a paid mutator transaction binding the contract method 0x886d36ff. // -// Solidity: function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) returns() -func (_IFastBridgeV2 *IFastBridgeV2Transactor) Prove(opts *bind.TransactOpts, transactionId [32]byte, destTxHash [32]byte, relayer common.Address) (*types.Transaction, error) { - return _IFastBridgeV2.contract.Transact(opts, "prove", transactionId, destTxHash, relayer) +// Solidity: function prove(bytes request, bytes32 destTxHash) returns() +func (_IFastBridgeV2 *IFastBridgeV2Transactor) Prove(opts *bind.TransactOpts, request []byte, destTxHash [32]byte) (*types.Transaction, error) { + return _IFastBridgeV2.contract.Transact(opts, "prove", request, destTxHash) } -// Prove is a paid mutator transaction binding the contract method 0x18e4357d. +// Prove is a paid mutator transaction binding the contract method 0x886d36ff. // -// Solidity: function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) returns() -func (_IFastBridgeV2 *IFastBridgeV2Session) Prove(transactionId [32]byte, destTxHash [32]byte, relayer common.Address) (*types.Transaction, error) { - return _IFastBridgeV2.Contract.Prove(&_IFastBridgeV2.TransactOpts, transactionId, destTxHash, relayer) +// Solidity: function prove(bytes request, bytes32 destTxHash) returns() +func (_IFastBridgeV2 *IFastBridgeV2Session) Prove(request []byte, destTxHash [32]byte) (*types.Transaction, error) { + return _IFastBridgeV2.Contract.Prove(&_IFastBridgeV2.TransactOpts, request, destTxHash) } -// Prove is a paid mutator transaction binding the contract method 0x18e4357d. +// Prove is a paid mutator transaction binding the contract method 0x886d36ff. // -// Solidity: function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) returns() -func (_IFastBridgeV2 *IFastBridgeV2TransactorSession) Prove(transactionId [32]byte, destTxHash [32]byte, relayer common.Address) (*types.Transaction, error) { - return _IFastBridgeV2.Contract.Prove(&_IFastBridgeV2.TransactOpts, transactionId, destTxHash, relayer) +// Solidity: function prove(bytes request, bytes32 destTxHash) returns() +func (_IFastBridgeV2 *IFastBridgeV2TransactorSession) Prove(request []byte, destTxHash [32]byte) (*types.Transaction, error) { + return _IFastBridgeV2.Contract.Prove(&_IFastBridgeV2.TransactOpts, request, destTxHash) } -// Prove0 is a paid mutator transaction binding the contract method 0x886d36ff. +// ProveV2 is a paid mutator transaction binding the contract method 0x41fdec80. // -// Solidity: function prove(bytes request, bytes32 destTxHash) returns() -func (_IFastBridgeV2 *IFastBridgeV2Transactor) Prove0(opts *bind.TransactOpts, request []byte, destTxHash [32]byte) (*types.Transaction, error) { - return _IFastBridgeV2.contract.Transact(opts, "prove0", request, destTxHash) +// Solidity: function proveV2(bytes32 transactionId, bytes32 destTxHash, address relayer) returns() +func (_IFastBridgeV2 *IFastBridgeV2Transactor) ProveV2(opts *bind.TransactOpts, transactionId [32]byte, destTxHash [32]byte, relayer common.Address) (*types.Transaction, error) { + return _IFastBridgeV2.contract.Transact(opts, "proveV2", transactionId, destTxHash, relayer) } -// Prove0 is a paid mutator transaction binding the contract method 0x886d36ff. +// ProveV2 is a paid mutator transaction binding the contract method 0x41fdec80. // -// Solidity: function prove(bytes request, bytes32 destTxHash) returns() -func (_IFastBridgeV2 *IFastBridgeV2Session) Prove0(request []byte, destTxHash [32]byte) (*types.Transaction, error) { - return _IFastBridgeV2.Contract.Prove0(&_IFastBridgeV2.TransactOpts, request, destTxHash) +// Solidity: function proveV2(bytes32 transactionId, bytes32 destTxHash, address relayer) returns() +func (_IFastBridgeV2 *IFastBridgeV2Session) ProveV2(transactionId [32]byte, destTxHash [32]byte, relayer common.Address) (*types.Transaction, error) { + return _IFastBridgeV2.Contract.ProveV2(&_IFastBridgeV2.TransactOpts, transactionId, destTxHash, relayer) } -// Prove0 is a paid mutator transaction binding the contract method 0x886d36ff. +// ProveV2 is a paid mutator transaction binding the contract method 0x41fdec80. // -// Solidity: function prove(bytes request, bytes32 destTxHash) returns() -func (_IFastBridgeV2 *IFastBridgeV2TransactorSession) Prove0(request []byte, destTxHash [32]byte) (*types.Transaction, error) { - return _IFastBridgeV2.Contract.Prove0(&_IFastBridgeV2.TransactOpts, request, destTxHash) +// Solidity: function proveV2(bytes32 transactionId, bytes32 destTxHash, address relayer) returns() +func (_IFastBridgeV2 *IFastBridgeV2TransactorSession) ProveV2(transactionId [32]byte, destTxHash [32]byte, relayer common.Address) (*types.Transaction, error) { + return _IFastBridgeV2.Contract.ProveV2(&_IFastBridgeV2.TransactOpts, transactionId, destTxHash, relayer) } // Refund is a paid mutator transaction binding the contract method 0x5eb7d946. @@ -13605,25 +13605,25 @@ func (_IFastBridgeV2 *IFastBridgeV2TransactorSession) Relay(request []byte) (*ty return _IFastBridgeV2.Contract.Relay(&_IFastBridgeV2.TransactOpts, request) } -// Relay0 is a paid mutator transaction binding the contract method 0x9c9545f0. +// RelayV2 is a paid mutator transaction binding the contract method 0x3d71e21f. // -// Solidity: function relay(bytes request, address relayer) payable returns() -func (_IFastBridgeV2 *IFastBridgeV2Transactor) Relay0(opts *bind.TransactOpts, request []byte, relayer common.Address) (*types.Transaction, error) { - return _IFastBridgeV2.contract.Transact(opts, "relay0", request, relayer) +// Solidity: function relayV2(bytes request, address relayer) payable returns() +func (_IFastBridgeV2 *IFastBridgeV2Transactor) RelayV2(opts *bind.TransactOpts, request []byte, relayer common.Address) (*types.Transaction, error) { + return _IFastBridgeV2.contract.Transact(opts, "relayV2", request, relayer) } -// Relay0 is a paid mutator transaction binding the contract method 0x9c9545f0. +// RelayV2 is a paid mutator transaction binding the contract method 0x3d71e21f. // -// Solidity: function relay(bytes request, address relayer) payable returns() -func (_IFastBridgeV2 *IFastBridgeV2Session) Relay0(request []byte, relayer common.Address) (*types.Transaction, error) { - return _IFastBridgeV2.Contract.Relay0(&_IFastBridgeV2.TransactOpts, request, relayer) +// Solidity: function relayV2(bytes request, address relayer) payable returns() +func (_IFastBridgeV2 *IFastBridgeV2Session) RelayV2(request []byte, relayer common.Address) (*types.Transaction, error) { + return _IFastBridgeV2.Contract.RelayV2(&_IFastBridgeV2.TransactOpts, request, relayer) } -// Relay0 is a paid mutator transaction binding the contract method 0x9c9545f0. +// RelayV2 is a paid mutator transaction binding the contract method 0x3d71e21f. // -// Solidity: function relay(bytes request, address relayer) payable returns() -func (_IFastBridgeV2 *IFastBridgeV2TransactorSession) Relay0(request []byte, relayer common.Address) (*types.Transaction, error) { - return _IFastBridgeV2.Contract.Relay0(&_IFastBridgeV2.TransactOpts, request, relayer) +// Solidity: function relayV2(bytes request, address relayer) payable returns() +func (_IFastBridgeV2 *IFastBridgeV2TransactorSession) RelayV2(request []byte, relayer common.Address) (*types.Transaction, error) { + return _IFastBridgeV2.Contract.RelayV2(&_IFastBridgeV2.TransactOpts, request, relayer) } // IFastBridgeV2BridgeDepositClaimedIterator is returned from FilterBridgeDepositClaimed and is used to iterate over the raw logs and unpacked data for BridgeDepositClaimed events raised by the IFastBridgeV2 contract. @@ -15460,7 +15460,7 @@ func (_MulticallTarget *MulticallTargetTransactorSession) MulticallWithResults(d // SafeERC20MetaData contains all meta data concerning the SafeERC20 contract. var SafeERC20MetaData = &bind.MetaData{ ABI: "[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"currentAllowance\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"requestedDecrease\",\"type\":\"uint256\"}],\"name\":\"SafeERC20FailedDecreaseAllowance\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"}],\"name\":\"SafeERC20FailedOperation\",\"type\":\"error\"}]", - Bin: "0x60566037600b82828239805160001a607314602a57634e487b7160e01b600052600060045260246000fd5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600080fdfea2646970667358221220fc15551e7cd0cae1476ceeb26ea6d8e21a222c930b99686cddd49777e215b49764736f6c63430008180033", + Bin: "0x60566037600b82828239805160001a607314602a57634e487b7160e01b600052600060045260246000fd5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600080fdfea2646970667358221220efeebe297f7317982e4aa5525f5b73e1604baf8d70a09b9809f700b1855f985d64736f6c63430008180033", } // SafeERC20ABI is the input ABI used to generate the binding from. diff --git a/services/rfq/contracts/fastbridgev2/fastbridgev2.contractinfo.json b/services/rfq/contracts/fastbridgev2/fastbridgev2.contractinfo.json index 5c09314059..ca219e9a57 100644 --- a/services/rfq/contracts/fastbridgev2/fastbridgev2.contractinfo.json +++ b/services/rfq/contracts/fastbridgev2/fastbridgev2.contractinfo.json @@ -1 +1 @@ -{"solidity/FastBridgeV2.sol:AccessControl":{"code":"0x","runtime-code":"0x","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.24 ^0.8.20 ^0.8.4;\n\n// contracts/interfaces/IAdminV2.sol\n\ninterface IAdminV2 {\n event CancelDelayUpdated(uint256 oldCancelDelay, uint256 newCancelDelay);\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n function setCancelDelay(uint256 newCancelDelay) external;\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n}\n\n// contracts/interfaces/IAdminV2Errors.sol\n\ninterface IAdminV2Errors {\n error CancelDelayBelowMin();\n error FeeRateAboveMax();\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IFastBridgeV2Errors.sol\n\ninterface IFastBridgeV2Errors {\n error AmountIncorrect();\n error ChainIncorrect();\n error ExclusivityParamsIncorrect();\n error MsgValueIncorrect();\n error SenderIncorrect();\n error StatusIncorrect();\n error TokenNotContract();\n error ZapDataLengthAboveMax();\n error ZapNativeNotSupported();\n error ZeroAddress();\n\n error RecipientIncorrectReturnValue();\n error RecipientNoReturnValue();\n\n error DeadlineExceeded();\n error DeadlineNotExceeded();\n error DeadlineTooShort();\n error DisputePeriodNotPassed();\n error DisputePeriodPassed();\n error ExclusivityPeriodNotPassed();\n\n error TransactionRelayed();\n}\n\n// contracts/interfaces/IMulticallTarget.sol\n\n/// @notice Interface for a contract that can be called multiple times by the same caller. Inspired by MulticallV3:\n/// https://github.com/mds1/multicall/blob/master/src/Multicall3.sol\ninterface IMulticallTarget {\n struct Result {\n bool success;\n bytes returnData;\n }\n\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external;\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results);\n}\n\n// contracts/interfaces/IZapRecipient.sol\n\ninterface IZapRecipient {\n function zap(address token, uint256 amount, bytes memory zapData) external payable returns (bytes4);\n}\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// contracts/interfaces/IFastBridgeV2.sol\n\ninterface IFastBridgeV2 is IFastBridge {\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n struct BridgeTxDetails {\n BridgeStatus status;\n uint32 destChainId;\n uint56 proofBlockTimestamp;\n address proofRelayer;\n }\n\n struct BridgeRelay {\n uint48 blockNumber;\n uint48 blockTimestamp;\n address relayer;\n }\n\n /// @notice New params introduced in the FastBridgeV2.\n /// We are passing fields from the older BridgeParams struct outside of this struct\n /// for backwards compatibility.\n /// Note: quoteRelayer and quoteExclusivitySeconds are either both zero (indicating no exclusivity)\n /// or both non-zero (indicating exclusivity for the given period).\n /// Note: zapNative \u003e 0 can NOT be used with destToken = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE (native token)\n /// @param quoteRelayer Relayer that provided the quote for the transaction\n /// @param quoteExclusivitySeconds Period of time the quote relayer is guaranteed exclusivity after user's deposit\n /// @param quoteId Unique quote identifier used for tracking the quote\n /// @param zapNative ETH value to send to the recipient (if any)\n /// @param zapData Parameters for the Zap to the destination recipient (if any)\n struct BridgeParamsV2 {\n address quoteRelayer;\n int256 quoteExclusivitySeconds;\n bytes quoteId;\n uint256 zapNative;\n bytes zapData;\n }\n\n /// @notice Updated bridge transaction struct to include parameters introduced in FastBridgeV2.\n /// Note: only `exclusivityRelayer` can fill such a transaction until `exclusivityEndTime`.\n struct BridgeTransactionV2 {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n // Note: sendChainGas flag from V1 is deprecated\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n address exclusivityRelayer;\n uint256 exclusivityEndTime;\n uint256 zapNative; // ETH value to send to the recipient (if any)\n bytes zapData; // data to pass for the Zap action (if any)\n }\n\n event BridgeQuoteDetails(bytes32 indexed transactionId, bytes quoteId);\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability\n /// to provide temporary exclusivity fill rights for the quote relayer.\n /// @param params The parameters required to bridge\n /// @param paramsV2 The parameters for exclusivity fill rights (optional, can be left empty)\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function relay(bytes memory request, address relayer) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param transactionId The transaction id associated with the encoded bridge transaction to prove\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital.\n /// @notice Can only send funds to the relayer address on the proof.\n /// @param request The encoded bridge transaction to claim on origin chain\n function claim(bytes memory request) external;\n\n /// @notice Cancels an outstanding bridge transaction in case optimistic bridging failed and returns the full amount\n /// to the original sender.\n /// @param request The encoded bridge transaction to refund\n function cancel(bytes memory request) external;\n\n /// @notice Checks if a transaction has been relayed\n /// @param transactionId The ID of the transaction to check\n /// @return True if the transaction has been relayed, false otherwise\n function bridgeRelays(bytes32 transactionId) external view returns (bool);\n\n /// @notice Returns the status of a bridge transaction\n /// @param transactionId The ID of the bridge transaction\n /// @return BridgeStatus Status of the bridge transaction\n function bridgeStatuses(bytes32 transactionId) external view returns (BridgeStatus);\n\n /// @notice Returns the timestamp and relayer of a bridge proof\n /// @param transactionId The ID of the bridge transaction\n /// @return timestamp The timestamp of the bridge proof\n /// @return relayer The relayer address of the bridge proof\n function bridgeProofs(bytes32 transactionId) external view returns (uint96 timestamp, address relayer);\n\n /// @notice Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\n /// @param request The bridge request to decode\n function getBridgeTransactionV2(bytes memory request) external view returns (BridgeTransactionV2 memory);\n}\n\n// contracts/utils/MulticallTarget.sol\n\n// solhint-disable avoid-low-level-calls\n/// @notice Template for a contract that supports batched calls (preserving the msg.sender).\n/// Only calls with zero msg.value could be batched.\nabstract contract MulticallTarget is IMulticallTarget {\n error MulticallTarget__UndeterminedRevert();\n\n /// @notice Perform a batched call to this contract, preserving the msg.sender.\n /// The return data from each call is discarded.\n /// @dev The method is non-payable, so only calls with `msg.value == 0` could be batched.\n /// It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag.\n /// Otherwise, the whole batch call will be reverted with the original revert reason.\n /// @param data List of abi-encoded calldata for the calls to perform.\n /// @param ignoreReverts Whether to ignore the revert errors from the calls.\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external {\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\n if (!success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(result);\n }\n }\n }\n\n /// @notice Perform a batched call to this contract, preserving the msg.sender.\n /// The return data from each call is preserved.\n /// @dev The method is non-payable, so only calls with `msg.value == 0` could be batched.\n /// It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag.\n /// Otherwise, the whole batch call will be reverted with the original revert reason.\n /// @param data List of abi-encoded calldata for the calls to perform.\n /// @param ignoreReverts Whether to ignore the revert errors from the calls.\n /// @return results List of results from the calls: `(success, returnData)`.\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results)\n {\n results = new Result[](data.length);\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (results[i].success, results[i].returnData) = address(this).delegatecall(data[i]);\n if (!results[i].success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(results[i].returnData);\n }\n }\n }\n\n /// @dev Bubbles the revert message from the underlying call.\n /// Note: preserves the same custom error or revert string, if one was used.\n /// Source: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v5.0.2/contracts/utils/Address.sol#L143-L158\n function _bubbleRevert(bytes memory returnData) internal pure {\n // Look for revert reason and bubble it up if present\n if (returnData.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n // solhint-disable-next-line no-inline-assembly\n assembly {\n let returndata_size := mload(returnData)\n revert(add(32, returnData), returndata_size)\n }\n } else {\n revert MulticallTarget__UndeterminedRevert();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// contracts/libs/BridgeTransactionV2.sol\n\n// solhint-disable no-inline-assembly\nlibrary BridgeTransactionV2Lib {\n uint16 internal constant VERSION = 2;\n\n // Offsets of the fields in the packed BridgeTransactionV2 struct\n // uint16 version [000 .. 002)\n // uint32 originChainId [002 .. 006)\n // uint32 destChainId [006 .. 010)\n // address originSender [010 .. 030)\n // address destRecipient [030 .. 050)\n // address originToken [050 .. 070)\n // address destToken [070 .. 090)\n // uint256 originAmount [090 .. 122)\n // uint256 destAmount [122 .. 154)\n // uint256 originFeeAmount [154 .. 186)\n // uint256 deadline [186 .. 218)\n // uint256 nonce [218 .. 250)\n // address exclusivityRelayer [250 .. 270)\n // uint256 exclusivityEndTime [270 .. 302)\n // uint256 zapNative [302 .. 334)\n // bytes zapData [334 .. ***)\n\n // forgefmt: disable-start\n uint256 private constant OFFSET_ORIGIN_CHAIN_ID = 2;\n uint256 private constant OFFSET_DEST_CHAIN_ID = 6;\n uint256 private constant OFFSET_ORIGIN_SENDER = 10;\n uint256 private constant OFFSET_DEST_RECIPIENT = 30;\n uint256 private constant OFFSET_ORIGIN_TOKEN = 50;\n uint256 private constant OFFSET_DEST_TOKEN = 70;\n uint256 private constant OFFSET_ORIGIN_AMOUNT = 90;\n uint256 private constant OFFSET_DEST_AMOUNT = 122;\n uint256 private constant OFFSET_ORIGIN_FEE_AMOUNT = 154;\n uint256 private constant OFFSET_DEADLINE = 186;\n uint256 private constant OFFSET_NONCE = 218;\n uint256 private constant OFFSET_EXCLUSIVITY_RELAYER = 250;\n uint256 private constant OFFSET_EXCLUSIVITY_END_TIME = 270;\n uint256 private constant OFFSET_ZAP_NATIVE = 302;\n uint256 private constant OFFSET_ZAP_DATA = 334;\n // forgefmt: disable-end\n\n error BridgeTransactionV2__InvalidEncodedTx();\n error BridgeTransactionV2__UnsupportedVersion(uint16 version);\n\n /// @notice Validates the encoded transaction to be a tightly packed encoded payload for BridgeTransactionV2.\n /// @dev Checks the minimum length and the version, use this function before decoding any of the fields.\n function validateV2(bytes calldata encodedTx) internal pure {\n // Check the minimum length: must at least include all static fields.\n if (encodedTx.length \u003c OFFSET_ZAP_DATA) revert BridgeTransactionV2__InvalidEncodedTx();\n // Once we validated the length, we can be sure that the version field is present.\n uint16 version_ = version(encodedTx);\n if (version_ != VERSION) revert BridgeTransactionV2__UnsupportedVersion(version_);\n }\n\n /// @notice Encodes the BridgeTransactionV2 struct by tightly packing the fields.\n /// @dev `abi.decode` will not work as a result of the tightly packed fields. Use `decodeV2` to decode instead.\n function encodeV2(IFastBridgeV2.BridgeTransactionV2 memory bridgeTx) internal pure returns (bytes memory) {\n // We split the encoding into two parts to avoid stack-too-deep error\n bytes memory firstPart = abi.encodePacked(\n VERSION,\n bridgeTx.originChainId,\n bridgeTx.destChainId,\n bridgeTx.originSender,\n bridgeTx.destRecipient,\n bridgeTx.originToken,\n bridgeTx.destToken,\n bridgeTx.originAmount\n );\n return abi.encodePacked(\n firstPart,\n bridgeTx.destAmount,\n bridgeTx.originFeeAmount,\n // Note: we skip the deprecated `sendChainGas` flag, which was present in BridgeTransaction V1\n bridgeTx.deadline,\n bridgeTx.nonce,\n // New V2 fields: exclusivity\n bridgeTx.exclusivityRelayer,\n bridgeTx.exclusivityEndTime,\n // New V2 fields: Zap\n bridgeTx.zapNative,\n bridgeTx.zapData\n );\n }\n\n /// @notice Decodes the BridgeTransactionV2 struct from the encoded transaction.\n /// @dev Encoded BridgeTransactionV2 struct must be tightly packed.\n /// Use `validateV2` before decoding to ensure the encoded transaction is valid.\n function decodeV2(bytes calldata encodedTx)\n internal\n pure\n returns (IFastBridgeV2.BridgeTransactionV2 memory bridgeTx)\n {\n bridgeTx.originChainId = originChainId(encodedTx);\n bridgeTx.destChainId = destChainId(encodedTx);\n bridgeTx.originSender = originSender(encodedTx);\n bridgeTx.destRecipient = destRecipient(encodedTx);\n bridgeTx.originToken = originToken(encodedTx);\n bridgeTx.destToken = destToken(encodedTx);\n bridgeTx.originAmount = originAmount(encodedTx);\n bridgeTx.destAmount = destAmount(encodedTx);\n bridgeTx.originFeeAmount = originFeeAmount(encodedTx);\n bridgeTx.deadline = deadline(encodedTx);\n bridgeTx.nonce = nonce(encodedTx);\n bridgeTx.exclusivityRelayer = exclusivityRelayer(encodedTx);\n bridgeTx.exclusivityEndTime = exclusivityEndTime(encodedTx);\n bridgeTx.zapNative = zapNative(encodedTx);\n bridgeTx.zapData = zapData(encodedTx);\n }\n\n /// @notice Extracts the version from the encoded transaction.\n function version(bytes calldata encodedTx) internal pure returns (uint16 version_) {\n // Load 32 bytes from the start and shift it 240 bits to the right to get the highest 16 bits.\n assembly {\n version_ := shr(240, calldataload(encodedTx.offset))\n }\n }\n\n /// @notice Extracts the origin chain ID from the encoded transaction.\n function originChainId(bytes calldata encodedTx) internal pure returns (uint32 originChainId_) {\n // Load 32 bytes from the offset and shift it 224 bits to the right to get the highest 32 bits.\n assembly {\n originChainId_ := shr(224, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_CHAIN_ID)))\n }\n }\n\n /// @notice Extracts the destination chain ID from the encoded transaction.\n function destChainId(bytes calldata encodedTx) internal pure returns (uint32 destChainId_) {\n // Load 32 bytes from the offset and shift it 224 bits to the right to get the highest 32 bits.\n assembly {\n destChainId_ := shr(224, calldataload(add(encodedTx.offset, OFFSET_DEST_CHAIN_ID)))\n }\n }\n\n /// @notice Extracts the origin sender from the encoded transaction.\n function originSender(bytes calldata encodedTx) internal pure returns (address originSender_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n originSender_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_SENDER)))\n }\n }\n\n /// @notice Extracts the destination recipient from the encoded transaction.\n function destRecipient(bytes calldata encodedTx) internal pure returns (address destRecipient_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n destRecipient_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_DEST_RECIPIENT)))\n }\n }\n\n /// @notice Extracts the origin token from the encoded transaction.\n function originToken(bytes calldata encodedTx) internal pure returns (address originToken_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n originToken_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_TOKEN)))\n }\n }\n\n /// @notice Extracts the destination token from the encoded transaction.\n function destToken(bytes calldata encodedTx) internal pure returns (address destToken_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n destToken_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_DEST_TOKEN)))\n }\n }\n\n /// @notice Extracts the origin amount from the encoded transaction.\n function originAmount(bytes calldata encodedTx) internal pure returns (uint256 originAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n originAmount_ := calldataload(add(encodedTx.offset, OFFSET_ORIGIN_AMOUNT))\n }\n }\n\n /// @notice Extracts the destination amount from the encoded transaction.\n function destAmount(bytes calldata encodedTx) internal pure returns (uint256 destAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n destAmount_ := calldataload(add(encodedTx.offset, OFFSET_DEST_AMOUNT))\n }\n }\n\n /// @notice Extracts the origin fee amount from the encoded transaction.\n function originFeeAmount(bytes calldata encodedTx) internal pure returns (uint256 originFeeAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n originFeeAmount_ := calldataload(add(encodedTx.offset, OFFSET_ORIGIN_FEE_AMOUNT))\n }\n }\n\n /// @notice Extracts the deadline from the encoded transaction.\n function deadline(bytes calldata encodedTx) internal pure returns (uint256 deadline_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n deadline_ := calldataload(add(encodedTx.offset, OFFSET_DEADLINE))\n }\n }\n\n /// @notice Extracts the nonce from the encoded transaction.\n function nonce(bytes calldata encodedTx) internal pure returns (uint256 nonce_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n nonce_ := calldataload(add(encodedTx.offset, OFFSET_NONCE))\n }\n }\n\n /// @notice Extracts the exclusivity relayer from the encoded transaction.\n function exclusivityRelayer(bytes calldata encodedTx) internal pure returns (address exclusivityRelayer_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n exclusivityRelayer_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_EXCLUSIVITY_RELAYER)))\n }\n }\n\n /// @notice Extracts the exclusivity end time from the encoded transaction.\n function exclusivityEndTime(bytes calldata encodedTx) internal pure returns (uint256 exclusivityEndTime_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n exclusivityEndTime_ := calldataload(add(encodedTx.offset, OFFSET_EXCLUSIVITY_END_TIME))\n }\n }\n\n /// @notice Extracts the Zap's native value from the encoded transaction.\n function zapNative(bytes calldata encodedTx) internal pure returns (uint256 zapNative_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n zapNative_ := calldataload(add(encodedTx.offset, OFFSET_ZAP_NATIVE))\n }\n }\n\n /// @notice Extracts the Zap's data from the encoded transaction.\n function zapData(bytes calldata encodedTx) internal pure returns (bytes calldata zapData_) {\n zapData_ = encodedTx[OFFSET_ZAP_DATA:];\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/AdminV2.sol\n\ncontract AdminV2 is AccessControlEnumerable, IAdminV2, IAdminV2Errors {\n using SafeERC20 for IERC20;\n\n /// @notice Address reserved for native gas token (ETH on Ethereum and most L2s, AVAX on Avalanche, etc)\n address public constant NATIVE_GAS_TOKEN = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Role identifier for Quoter API's off-chain authentication.\n /// @dev Only addresses with this role can post FastBridge quotes to the API.\n bytes32 public constant QUOTER_ROLE = keccak256(\"QUOTER_ROLE\");\n\n /// @notice Role identifier for Prover's on-chain authentication in FastBridge.\n /// @dev Only addresses with this role can provide proofs that a FastBridge request has been relayed.\n bytes32 public constant PROVER_ROLE = keccak256(\"PROVER_ROLE\");\n\n /// @notice Role identifier for Guard's on-chain authentication in FastBridge.\n /// @dev Only addresses with this role can dispute submitted relay proofs during the dispute period.\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n\n /// @notice Role identifier for Canceler's on-chain authentication in FastBridge.\n /// @dev Only addresses with this role can cancel a FastBridge transaction without the cancel delay.\n bytes32 public constant CANCELER_ROLE = keccak256(\"CANCELER_ROLE\");\n\n /// @notice Role identifier for Governor's on-chain administrative authority.\n /// @dev Only addresses with this role can perform administrative tasks within the contract.\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n /// @notice Denominator for fee rates, represents 100%.\n uint256 public constant FEE_BPS = 1e6;\n /// @notice Maximum protocol fee rate: 1% on origin amount.\n uint256 public constant FEE_RATE_MAX = 0.01e6;\n\n /// @notice Minimum cancel delay that can be set by the governor.\n uint256 public constant MIN_CANCEL_DELAY = 1 hours;\n /// @notice Default cancel delay set during the contract deployment.\n uint256 public constant DEFAULT_CANCEL_DELAY = 1 days;\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Delay for a transaction after which it could be permisionlessly cancelled\n uint256 public cancelDelay;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Use ZapNative V2 requests instead.\n uint256 public immutable chainGasAmount = 0;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n _setCancelDelay(DEFAULT_CANCEL_DELAY);\n }\n\n /// @notice Allows the contract governor to set the cancel delay. The cancel delay is the time after the transaction\n /// deadline after which it can be permissionlessly cancelled, if it hasn't been proven by any of the Relayers.\n function setCancelDelay(uint256 newCancelDelay) external onlyRole(GOVERNOR_ROLE) {\n _setCancelDelay(newCancelDelay);\n }\n\n /// @notice Allows the contract governor to set the protocol fee rate. The protocol fee is taken from the origin\n /// amount only for completed and claimed transactions.\n /// @dev The protocol fee is abstracted away from the relayers, they always operate using the amounts after fees:\n /// what they see as the origin amount emitted in the log is what they get credited with.\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n if (newFeeRate \u003e FEE_RATE_MAX) revert FeeRateAboveMax();\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n /// @notice Allows the contract governor to sweep the accumulated protocol fees in the contract.\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n emit FeesSwept(token, recipient, feeAmount);\n /// Sweep the fees as the last transaction action\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(recipient), feeAmount);\n } else {\n IERC20(token).safeTransfer(recipient, feeAmount);\n }\n }\n\n /// @notice Internal function to set the cancel delay. Security checks are performed outside of this function.\n function _setCancelDelay(uint256 newCancelDelay) private {\n if (newCancelDelay \u003c MIN_CANCEL_DELAY) revert CancelDelayBelowMin();\n uint256 oldCancelDelay = cancelDelay;\n cancelDelay = newCancelDelay;\n emit CancelDelayUpdated(oldCancelDelay, newCancelDelay);\n }\n}\n\n// contracts/FastBridgeV2.sol\n\n/// @notice FastBridgeV2 is a contract for bridging tokens across chains.\ncontract FastBridgeV2 is AdminV2, MulticallTarget, IFastBridgeV2, IFastBridgeV2Errors {\n using BridgeTransactionV2Lib for bytes;\n using SafeERC20 for IERC20;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n /// @notice Maximum length of accepted zapData\n uint256 public constant MAX_ZAP_DATA_LENGTH = 2 ** 16 - 1;\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeTxDetails) public bridgeTxDetails;\n /// @notice Relay details on destination chain\n mapping(bytes32 =\u003e BridgeRelay) public bridgeRelayDetails;\n /// @notice Unique bridge nonces tracked per originSender\n mapping(address =\u003e uint256) public senderNonces;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Replaced by senderNonces\n uint256 public immutable nonce = 0;\n /// @notice the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) AdminV2(_owner) {\n deployBlock = block.number;\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n bridge({\n params: params,\n paramsV2: BridgeParamsV2({\n quoteRelayer: address(0),\n quoteExclusivitySeconds: 0,\n quoteId: bytes(\"\"),\n zapNative: 0,\n zapData: bytes(\"\")\n })\n });\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes calldata request) external payable {\n // relay override will validate the request\n relay({request: request, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes calldata request, bytes32 destTxHash) external {\n request.validateV2();\n prove({transactionId: keccak256(request), destTxHash: destTxHash, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridgeV2\n function claim(bytes calldata request) external {\n // claim override will validate the request\n claim({request: request, to: address(0)});\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Aggregate the read operations from the same storage slot\n address disputedRelayer = $.proofRelayer;\n BridgeStatus status = $.status;\n uint56 proofBlockTimestamp = $.proofBlockTimestamp;\n // Can only dispute a RELAYER_PROVED transaction within the dispute period\n if (status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(proofBlockTimestamp) \u003e DISPUTE_PERIOD) {\n revert DisputePeriodPassed();\n }\n // Update status to REQUESTED and delete the disputed proof details\n // Note: these are storage writes\n $.status = BridgeStatus.REQUESTED;\n $.proofRelayer = address(0);\n $.proofBlockTimestamp = 0;\n\n emit BridgeProofDisputed(transactionId, disputedRelayer);\n }\n\n /// Note: this function is deprecated and will be removed in a future version.\n /// @inheritdoc IFastBridge\n function refund(bytes calldata request) external {\n cancel(request);\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // The correct relayer can only claim a RELAYER_PROVED transaction after the dispute period\n if ($.status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if ($.proofRelayer != relayer) revert SenderIncorrect();\n return _timeSince($.proofBlockTimestamp) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n /// @dev This method is added to achieve backwards compatibility with decoding requests into V1 structs:\n /// - `zapNative` is partially reported as a zero/non-zero flag\n /// - `zapData` is ignored\n /// In order to process all kinds of requests use getBridgeTransactionV2 instead.\n function getBridgeTransaction(bytes calldata request) external view returns (BridgeTransaction memory) {\n // Try decoding into V2 struct first. This will revert if V1 struct is passed\n try this.getBridgeTransactionV2(request) returns (BridgeTransactionV2 memory txV2) {\n // Note: we entirely ignore the zapData field, as it was not present in V1\n return BridgeTransaction({\n originChainId: txV2.originChainId,\n destChainId: txV2.destChainId,\n originSender: txV2.originSender,\n destRecipient: txV2.destRecipient,\n originToken: txV2.originToken,\n destToken: txV2.destToken,\n originAmount: txV2.originAmount,\n destAmount: txV2.destAmount,\n originFeeAmount: txV2.originFeeAmount,\n sendChainGas: txV2.zapNative != 0,\n deadline: txV2.deadline,\n nonce: txV2.nonce\n });\n } catch {\n // Fallback to V1 struct\n return abi.decode(request, (BridgeTransaction));\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function getBridgeTransactionV2(bytes calldata request) external pure returns (BridgeTransactionV2 memory) {\n request.validateV2();\n return BridgeTransactionV2Lib.decodeV2(request);\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) public payable {\n int256 exclusivityEndTime = 0;\n // if relayer exclusivity is not intended for this bridge, set exclusivityEndTime to static zero\n // otherwise, set exclusivity to expire at the current block ts offset by quoteExclusivitySeconds\n if (paramsV2.quoteRelayer != address(0)) {\n exclusivityEndTime = int256(block.timestamp) + paramsV2.quoteExclusivitySeconds;\n }\n _validateBridgeParams(params, paramsV2, exclusivityEndTime);\n\n // transfer tokens to bridge contract\n /// @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _takeBridgedUserAsset(params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) {\n originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n }\n\n // set status to requested\n bytes memory request = BridgeTransactionV2Lib.encodeV2(\n BridgeTransactionV2({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n deadline: params.deadline,\n nonce: senderNonces[params.sender]++, // increment nonce on every bridge\n exclusivityRelayer: paramsV2.quoteRelayer,\n // We checked exclusivityEndTime to be in range [0 .. params.deadline] above, so can safely cast\n exclusivityEndTime: uint256(exclusivityEndTime),\n zapNative: paramsV2.zapNative,\n zapData: paramsV2.zapData\n })\n );\n bytes32 transactionId = keccak256(request);\n // Note: the tx status will be updated throughout the tx lifecycle, while destChainId is set once here\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n bridgeTxDetails[transactionId].destChainId = params.dstChainId;\n\n emit BridgeRequested({\n transactionId: transactionId,\n sender: params.sender,\n request: request,\n destChainId: params.dstChainId,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n sendChainGas: paramsV2.zapNative != 0\n });\n emit BridgeQuoteDetails(transactionId, paramsV2.quoteId);\n }\n\n /// @inheritdoc IFastBridgeV2\n function relay(bytes calldata request, address relayer) public payable {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n _validateRelayParams(request, transactionId, relayer);\n // mark bridge transaction as relayed\n bridgeRelayDetails[transactionId] =\n BridgeRelay({blockNumber: uint48(block.number), blockTimestamp: uint48(block.timestamp), relayer: relayer});\n\n // transfer tokens to recipient on destination chain and trigger Zap if requested\n address to = request.destRecipient();\n address token = request.destToken();\n uint256 amount = request.destAmount();\n uint256 zapNative = request.zapNative();\n\n // Emit the event before any external calls\n emit BridgeRelayed({\n transactionId: transactionId,\n relayer: relayer,\n to: to,\n originChainId: request.originChainId(),\n originToken: request.originToken(),\n destToken: token,\n originAmount: request.originAmount(),\n destAmount: amount,\n chainGasAmount: zapNative\n });\n\n // All state changes have been done at this point, can proceed to the external calls.\n // This follows the checks-effects-interactions pattern to mitigate potential reentrancy attacks.\n if (token == NATIVE_GAS_TOKEN) {\n // For the native gas token, additional zapNative is not allowed\n if (zapNative != 0) revert ZapNativeNotSupported();\n // Check that the correct msg.value was sent\n if (msg.value != amount) revert MsgValueIncorrect();\n // Don't do a native transfer yet: we will handle it alongside the Zap below\n } else {\n // For ERC20s, we check that the correct msg.value was sent\n if (msg.value != zapNative) revert MsgValueIncorrect();\n // We need to transfer the tokens from the Relayer to the recipient first before performing an\n // optional post-transfer Zap.\n IERC20(token).safeTransferFrom(msg.sender, to, amount);\n }\n // At this point we have done:\n // - Transferred the requested amount of ERC20 tokens to the recipient.\n // At this point we have confirmed:\n // - For ERC20s: msg.value matches the requested zapNative amount.\n // - For the native gas token: msg.value matches the requested destAmount.\n // Remaining optional things to do:\n // - Forward the full msg.value to the recipient (if non-zero).\n // - Trigger a Zap (if zapData is present).\n bytes calldata zapData = request.zapData();\n if (zapData.length != 0) {\n // Zap Data is present: Zap has been requested by the recipient. Trigger it forwarding the full msg.value.\n\n // Note: if token has a fee on transfers, the recipient will have received less than `amount`.\n // This is a very niche edge case and should be handled by the recipient contract.\n _triggerZapWithChecks({recipient: to, token: token, amount: amount, zapData: zapData});\n } else if (msg.value != 0) {\n // Zap Data is missing, but msg.value was sent. This could happen in two different cases:\n // - Relay with the native gas token is happening.\n // - Relay with ERC20 is happening, with a `zapNative \u003e 0` request.\n // In both cases, we need to transfer the full msg.value to the recipient.\n Address.sendValue(payable(to), msg.value);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) public onlyRole(PROVER_ROLE) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n\n // Can only prove a REQUESTED transaction\n if ($.status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n // Update status to RELAYER_PROVED and store the proof details\n // Note: these are storage writes\n $.status = BridgeStatus.RELAYER_PROVED;\n $.proofBlockTimestamp = uint56(block.timestamp);\n $.proofRelayer = relayer;\n\n emit BridgeProofProvided(transactionId, relayer, destTxHash);\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes calldata request, address to) public {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Aggregate the read operations from the same storage slot\n address proofRelayer = $.proofRelayer;\n BridgeStatus status = $.status;\n uint56 proofBlockTimestamp = $.proofBlockTimestamp;\n\n // Can only claim a RELAYER_PROVED transaction after the dispute period\n if (status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(proofBlockTimestamp) \u003c= DISPUTE_PERIOD) {\n revert DisputePeriodNotPassed();\n }\n\n if (to == address(0)) {\n // Anyone could claim the funds to the proven relayer on their behalf\n to = proofRelayer;\n } else if (proofRelayer != msg.sender) {\n // Only the proven relayer could specify an address to claim the funds to\n revert SenderIncorrect();\n }\n\n // Update status to RELAYER_CLAIMED and transfer the origin collateral to the specified claim address\n // Note: this is a storage write\n $.status = BridgeStatus.RELAYER_CLAIMED;\n\n address token = request.originToken();\n uint256 amount = request.originAmount();\n // Update protocol fees if origin fee amount exists\n uint256 originFeeAmount = request.originFeeAmount();\n if (originFeeAmount \u003e 0) protocolFees[token] += originFeeAmount;\n // Emit the event before any external calls\n emit BridgeDepositClaimed(transactionId, proofRelayer, to, token, amount);\n // Complete the relayer claim as the last transaction action\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(to), amount);\n } else {\n IERC20(token).safeTransfer(to, amount);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function cancel(bytes calldata request) public {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Can only cancel a REQUESTED transaction after its deadline expires\n if ($.status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n uint256 deadline = request.deadline();\n // Permissionless cancel is only allowed after `cancelDelay` on top of the deadline\n if (!hasRole(CANCELER_ROLE, msg.sender)) deadline += cancelDelay;\n if (block.timestamp \u003c= deadline) revert DeadlineNotExceeded();\n // Update status to REFUNDED and return the full amount (collateral + protocol fees) to the original sender.\n // The protocol fees are only updated when the transaction is claimed, so we don't need to update them here.\n // Note: this is a storage write\n $.status = BridgeStatus.REFUNDED;\n\n address to = request.originSender();\n address token = request.originToken();\n uint256 amount = request.originAmount() + request.originFeeAmount();\n // Emit the event before any external calls\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n // Complete the user cancel as the last transaction action\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(to), amount);\n } else {\n IERC20(token).safeTransfer(to, amount);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeStatuses(bytes32 transactionId) public view returns (BridgeStatus status) {\n return bridgeTxDetails[transactionId].status;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeProofs(bytes32 transactionId) public view returns (uint96 timestamp, address relayer) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n\n timestamp = $.proofBlockTimestamp;\n relayer = $.proofRelayer;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeRelays(bytes32 transactionId) public view returns (bool) {\n // has this transactionId been relayed?\n return bridgeRelayDetails[transactionId].relayer != address(0);\n }\n\n /// @notice Takes the bridged asset from the user into FastBridgeV2 custody. It will be later\n /// claimed by the relayer who completed the relay on destination chain, or transferred back to the user\n /// via the cancel function should no one complete the relay.\n function _takeBridgedUserAsset(address token, uint256 amount) internal returns (uint256 amountTaken) {\n if (token == NATIVE_GAS_TOKEN) {\n // For the native gas token, we just need to check that the supplied msg.value is correct.\n // Supplied `msg.value` is already in FastBridgeV2 custody.\n if (amount != msg.value) revert MsgValueIncorrect();\n amountTaken = msg.value;\n } else {\n // For ERC20s, token is explicitly transferred from the user to FastBridgeV2.\n // We don't allow non-zero `msg.value` to avoid extra funds from being stuck in FastBridgeV2.\n if (msg.value != 0) revert MsgValueIncorrect();\n // Throw an explicit error if the provided token address is not a contract\n if (token.code.length == 0) revert TokenNotContract();\n amountTaken = IERC20(token).balanceOf(address(this));\n IERC20(token).safeTransferFrom(msg.sender, address(this), amount);\n // Use the balance difference as the amount taken in case of fee on transfer tokens.\n amountTaken = IERC20(token).balanceOf(address(this)) - amountTaken;\n }\n }\n\n /// @notice Calls the Recipient's hook function with the specified zapData and performs\n /// all the necessary checks for the returned value.\n function _triggerZapWithChecks(address recipient, address token, uint256 amount, bytes calldata zapData) internal {\n // This will bubble any revert messages from the hook function\n bytes memory returnData = Address.functionCallWithValue({\n target: recipient,\n data: abi.encodeCall(IZapRecipient.zap, (token, amount, zapData)),\n // Note: see `relay()` for reasoning behind passing msg.value\n value: msg.value\n });\n // Explicit revert if no return data at all\n if (returnData.length == 0) revert RecipientNoReturnValue();\n // Check that exactly a single return value was returned\n if (returnData.length != 32) revert RecipientIncorrectReturnValue();\n // Return value should be abi-encoded hook function selector\n if (bytes32(returnData) != bytes32(IZapRecipient.zap.selector)) {\n revert RecipientIncorrectReturnValue();\n }\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint56(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint56).max but\n /// proof.timestamp \u003c type(uint56).max via unchecked statement\n /// @param proofBlockTimestamp The bridge proof block timestamp\n /// @return delta Time delta since proof submitted\n function _timeSince(uint56 proofBlockTimestamp) internal view returns (uint256 delta) {\n unchecked {\n delta = uint56(block.timestamp) - proofBlockTimestamp;\n }\n }\n\n /// @notice Performs all the necessary checks for a bridge to happen.\n /// @dev There's no good way to refactor this function to reduce cyclomatic complexity due to\n /// the number of checks that need to be performed, so we skip the code-complexity rule here.\n // solhint-disable-next-line code-complexity\n function _validateBridgeParams(\n BridgeParams memory params,\n BridgeParamsV2 memory paramsV2,\n int256 exclusivityEndTime\n )\n internal\n view\n {\n // Check V1 (legacy) params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.sender == address(0) || params.to == address(0)) revert ZeroAddress();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n // Check V2 params\n if (paramsV2.zapData.length \u003e MAX_ZAP_DATA_LENGTH) revert ZapDataLengthAboveMax();\n if (paramsV2.zapNative != 0 \u0026\u0026 params.destToken == NATIVE_GAS_TOKEN) {\n revert ZapNativeNotSupported();\n }\n // exclusivityEndTime must be in range [0 .. params.deadline]\n if (exclusivityEndTime \u003c 0 || exclusivityEndTime \u003e int256(params.deadline)) {\n revert ExclusivityParamsIncorrect();\n }\n }\n\n /// @notice Performs all the necessary checks for a relay to happen.\n function _validateRelayParams(bytes calldata request, bytes32 transactionId, address relayer) internal view {\n if (relayer == address(0)) revert ZeroAddress();\n // Check if the transaction has already been relayed\n if (bridgeRelays(transactionId)) revert TransactionRelayed();\n if (request.destChainId() != block.chainid) revert ChainIncorrect();\n // Check the deadline for relay to happen\n if (block.timestamp \u003e request.deadline()) revert DeadlineExceeded();\n // Check the exclusivity period, if it is still ongoing\n address exclRelayer = request.exclusivityRelayer();\n if (exclRelayer != address(0) \u0026\u0026 exclRelayer != relayer \u0026\u0026 block.timestamp \u003c= request.exclusivityEndTime()) {\n revert ExclusivityPeriodNotPassed();\n }\n }\n}\n","language":"Solidity","languageVersion":"0.8.24","compilerVersion":"0.8.24","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"","srcMapRuntime":"","abiDefinition":[{"inputs":[],"name":"AccessControlBadConfirmation","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"bytes32","name":"neededRole","type":"bytes32"}],"name":"AccessControlUnauthorizedAccount","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"previousAdminRole","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"newAdminRole","type":"bytes32"}],"name":"RoleAdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleRevoked","type":"event"},{"inputs":[],"name":"DEFAULT_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleAdmin","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"grantRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"hasRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"callerConfirmation","type":"address"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"revokeRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"}],"userDoc":{"kind":"user","methods":{},"version":1},"developerDoc":{"details":"Contract module that allows children to implement role-based access control mechanisms. This is a lightweight version that doesn't allow enumerating role members except through off-chain means by accessing the contract event logs. Some applications may benefit from on-chain enumerability, for those cases see {AccessControlEnumerable}. Roles are referred to by their `bytes32` identifier. These should be exposed in the external API and be unique. The best way to achieve this is by using `public constant` hash digests: ```solidity bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\"); ``` Roles can be used to represent a set of permissions. To restrict access to a function call, use {hasRole}: ```solidity function foo() public { require(hasRole(MY_ROLE, msg.sender)); ... } ``` Roles can be granted and revoked dynamically via the {grantRole} and {revokeRole} functions. Each role has an associated admin role, and only accounts that have a role's admin role can call {grantRole} and {revokeRole}. By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means that only accounts with this role will be able to grant or revoke other roles. More complex role relationships can be created by using {_setRoleAdmin}. WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to grant and revoke this role. Extra precautions should be taken to secure accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules} to enforce additional security measures for this role.","errors":{"AccessControlBadConfirmation()":[{"details":"The caller of a function is not the expected one. NOTE: Don't confuse with {AccessControlUnauthorizedAccount}."}],"AccessControlUnauthorizedAccount(address,bytes32)":[{"details":"The `account` is missing a role."}]},"events":{"RoleAdminChanged(bytes32,bytes32,bytes32)":{"details":"Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole` `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite {RoleAdminChanged} not being emitted signaling this."},"RoleGranted(bytes32,address,address)":{"details":"Emitted when `account` is granted `role`. `sender` is the account that originated the contract call, an admin role bearer except when using {AccessControl-_setupRole}."},"RoleRevoked(bytes32,address,address)":{"details":"Emitted when `account` is revoked `role`. `sender` is the account that originated the contract call: - if using `revokeRole`, it is the admin role bearer - if using `renounceRole`, it is the role bearer (i.e. `account`)"}},"kind":"dev","methods":{"getRoleAdmin(bytes32)":{"details":"Returns the admin role that controls `role`. See {grantRole} and {revokeRole}. To change a role's admin, use {_setRoleAdmin}."},"grantRole(bytes32,address)":{"details":"Grants `role` to `account`. If `account` had not been already granted `role`, emits a {RoleGranted} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleGranted} event."},"hasRole(bytes32,address)":{"details":"Returns `true` if `account` has been granted `role`."},"renounceRole(bytes32,address)":{"details":"Revokes `role` from the calling account. Roles are often managed via {grantRole} and {revokeRole}: this function's purpose is to provide a mechanism for accounts to lose their privileges if they are compromised (such as when a trusted device is misplaced). If the calling account had been revoked `role`, emits a {RoleRevoked} event. Requirements: - the caller must be `callerConfirmation`. May emit a {RoleRevoked} event."},"revokeRole(bytes32,address)":{"details":"Revokes `role` from `account`. If `account` had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleRevoked} event."},"supportsInterface(bytes4)":{"details":"See {IERC165-supportsInterface}."}},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[],\"name\":\"AccessControlBadConfirmation\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"neededRole\",\"type\":\"bytes32\"}],\"name\":\"AccessControlUnauthorizedAccount\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"previousAdminRole\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"newAdminRole\",\"type\":\"bytes32\"}],\"name\":\"RoleAdminChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleGranted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleRevoked\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"DEFAULT_ADMIN_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"}],\"name\":\"getRoleAdmin\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"grantRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"hasRole\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"callerConfirmation\",\"type\":\"address\"}],\"name\":\"renounceRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"revokeRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes4\",\"name\":\"interfaceId\",\"type\":\"bytes4\"}],\"name\":\"supportsInterface\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"}],\"devdoc\":{\"details\":\"Contract module that allows children to implement role-based access control mechanisms. This is a lightweight version that doesn't allow enumerating role members except through off-chain means by accessing the contract event logs. Some applications may benefit from on-chain enumerability, for those cases see {AccessControlEnumerable}. Roles are referred to by their `bytes32` identifier. These should be exposed in the external API and be unique. The best way to achieve this is by using `public constant` hash digests: ```solidity bytes32 public constant MY_ROLE = keccak256(\\\"MY_ROLE\\\"); ``` Roles can be used to represent a set of permissions. To restrict access to a function call, use {hasRole}: ```solidity function foo() public { require(hasRole(MY_ROLE, msg.sender)); ... } ``` Roles can be granted and revoked dynamically via the {grantRole} and {revokeRole} functions. Each role has an associated admin role, and only accounts that have a role's admin role can call {grantRole} and {revokeRole}. By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means that only accounts with this role will be able to grant or revoke other roles. More complex role relationships can be created by using {_setRoleAdmin}. WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to grant and revoke this role. Extra precautions should be taken to secure accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules} to enforce additional security measures for this role.\",\"errors\":{\"AccessControlBadConfirmation()\":[{\"details\":\"The caller of a function is not the expected one. NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\"}],\"AccessControlUnauthorizedAccount(address,bytes32)\":[{\"details\":\"The `account` is missing a role.\"}]},\"events\":{\"RoleAdminChanged(bytes32,bytes32,bytes32)\":{\"details\":\"Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole` `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite {RoleAdminChanged} not being emitted signaling this.\"},\"RoleGranted(bytes32,address,address)\":{\"details\":\"Emitted when `account` is granted `role`. `sender` is the account that originated the contract call, an admin role bearer except when using {AccessControl-_setupRole}.\"},\"RoleRevoked(bytes32,address,address)\":{\"details\":\"Emitted when `account` is revoked `role`. `sender` is the account that originated the contract call: - if using `revokeRole`, it is the admin role bearer - if using `renounceRole`, it is the role bearer (i.e. `account`)\"}},\"kind\":\"dev\",\"methods\":{\"getRoleAdmin(bytes32)\":{\"details\":\"Returns the admin role that controls `role`. See {grantRole} and {revokeRole}. To change a role's admin, use {_setRoleAdmin}.\"},\"grantRole(bytes32,address)\":{\"details\":\"Grants `role` to `account`. If `account` had not been already granted `role`, emits a {RoleGranted} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleGranted} event.\"},\"hasRole(bytes32,address)\":{\"details\":\"Returns `true` if `account` has been granted `role`.\"},\"renounceRole(bytes32,address)\":{\"details\":\"Revokes `role` from the calling account. Roles are often managed via {grantRole} and {revokeRole}: this function's purpose is to provide a mechanism for accounts to lose their privileges if they are compromised (such as when a trusted device is misplaced). If the calling account had been revoked `role`, emits a {RoleRevoked} event. Requirements: - the caller must be `callerConfirmation`. May emit a {RoleRevoked} event.\"},\"revokeRole(bytes32,address)\":{\"details\":\"Revokes `role` from `account`. If `account` had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleRevoked} event.\"},\"supportsInterface(bytes4)\":{\"details\":\"See {IERC165-supportsInterface}.\"}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeV2.sol\":\"AccessControl\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeV2.sol\":{\"keccak256\":\"0xac79c463688a682ca706a4ef95e7817b83548cdfa8182ba0426ac7e5e07613d8\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://b3ecb7097381287cafc3a73f3a2bb03565115ebb682a85064e0b0dc2f7e2919d\",\"dweb:/ipfs/QmatruW3nYZTksf3CeQ8wwiAG4c7xoEJBEp6drHPtFLBRK\"]}},\"version\":1}"},"hashes":{"DEFAULT_ADMIN_ROLE()":"a217fddf","getRoleAdmin(bytes32)":"248a9ca3","grantRole(bytes32,address)":"2f2ff15d","hasRole(bytes32,address)":"91d14854","renounceRole(bytes32,address)":"36568abe","revokeRole(bytes32,address)":"d547741f","supportsInterface(bytes4)":"01ffc9a7"}},"solidity/FastBridgeV2.sol:AccessControlEnumerable":{"code":"0x","runtime-code":"0x","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.24 ^0.8.20 ^0.8.4;\n\n// contracts/interfaces/IAdminV2.sol\n\ninterface IAdminV2 {\n event CancelDelayUpdated(uint256 oldCancelDelay, uint256 newCancelDelay);\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n function setCancelDelay(uint256 newCancelDelay) external;\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n}\n\n// contracts/interfaces/IAdminV2Errors.sol\n\ninterface IAdminV2Errors {\n error CancelDelayBelowMin();\n error FeeRateAboveMax();\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IFastBridgeV2Errors.sol\n\ninterface IFastBridgeV2Errors {\n error AmountIncorrect();\n error ChainIncorrect();\n error ExclusivityParamsIncorrect();\n error MsgValueIncorrect();\n error SenderIncorrect();\n error StatusIncorrect();\n error TokenNotContract();\n error ZapDataLengthAboveMax();\n error ZapNativeNotSupported();\n error ZeroAddress();\n\n error RecipientIncorrectReturnValue();\n error RecipientNoReturnValue();\n\n error DeadlineExceeded();\n error DeadlineNotExceeded();\n error DeadlineTooShort();\n error DisputePeriodNotPassed();\n error DisputePeriodPassed();\n error ExclusivityPeriodNotPassed();\n\n error TransactionRelayed();\n}\n\n// contracts/interfaces/IMulticallTarget.sol\n\n/// @notice Interface for a contract that can be called multiple times by the same caller. Inspired by MulticallV3:\n/// https://github.com/mds1/multicall/blob/master/src/Multicall3.sol\ninterface IMulticallTarget {\n struct Result {\n bool success;\n bytes returnData;\n }\n\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external;\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results);\n}\n\n// contracts/interfaces/IZapRecipient.sol\n\ninterface IZapRecipient {\n function zap(address token, uint256 amount, bytes memory zapData) external payable returns (bytes4);\n}\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// contracts/interfaces/IFastBridgeV2.sol\n\ninterface IFastBridgeV2 is IFastBridge {\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n struct BridgeTxDetails {\n BridgeStatus status;\n uint32 destChainId;\n uint56 proofBlockTimestamp;\n address proofRelayer;\n }\n\n struct BridgeRelay {\n uint48 blockNumber;\n uint48 blockTimestamp;\n address relayer;\n }\n\n /// @notice New params introduced in the FastBridgeV2.\n /// We are passing fields from the older BridgeParams struct outside of this struct\n /// for backwards compatibility.\n /// Note: quoteRelayer and quoteExclusivitySeconds are either both zero (indicating no exclusivity)\n /// or both non-zero (indicating exclusivity for the given period).\n /// Note: zapNative \u003e 0 can NOT be used with destToken = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE (native token)\n /// @param quoteRelayer Relayer that provided the quote for the transaction\n /// @param quoteExclusivitySeconds Period of time the quote relayer is guaranteed exclusivity after user's deposit\n /// @param quoteId Unique quote identifier used for tracking the quote\n /// @param zapNative ETH value to send to the recipient (if any)\n /// @param zapData Parameters for the Zap to the destination recipient (if any)\n struct BridgeParamsV2 {\n address quoteRelayer;\n int256 quoteExclusivitySeconds;\n bytes quoteId;\n uint256 zapNative;\n bytes zapData;\n }\n\n /// @notice Updated bridge transaction struct to include parameters introduced in FastBridgeV2.\n /// Note: only `exclusivityRelayer` can fill such a transaction until `exclusivityEndTime`.\n struct BridgeTransactionV2 {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n // Note: sendChainGas flag from V1 is deprecated\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n address exclusivityRelayer;\n uint256 exclusivityEndTime;\n uint256 zapNative; // ETH value to send to the recipient (if any)\n bytes zapData; // data to pass for the Zap action (if any)\n }\n\n event BridgeQuoteDetails(bytes32 indexed transactionId, bytes quoteId);\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability\n /// to provide temporary exclusivity fill rights for the quote relayer.\n /// @param params The parameters required to bridge\n /// @param paramsV2 The parameters for exclusivity fill rights (optional, can be left empty)\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function relay(bytes memory request, address relayer) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param transactionId The transaction id associated with the encoded bridge transaction to prove\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital.\n /// @notice Can only send funds to the relayer address on the proof.\n /// @param request The encoded bridge transaction to claim on origin chain\n function claim(bytes memory request) external;\n\n /// @notice Cancels an outstanding bridge transaction in case optimistic bridging failed and returns the full amount\n /// to the original sender.\n /// @param request The encoded bridge transaction to refund\n function cancel(bytes memory request) external;\n\n /// @notice Checks if a transaction has been relayed\n /// @param transactionId The ID of the transaction to check\n /// @return True if the transaction has been relayed, false otherwise\n function bridgeRelays(bytes32 transactionId) external view returns (bool);\n\n /// @notice Returns the status of a bridge transaction\n /// @param transactionId The ID of the bridge transaction\n /// @return BridgeStatus Status of the bridge transaction\n function bridgeStatuses(bytes32 transactionId) external view returns (BridgeStatus);\n\n /// @notice Returns the timestamp and relayer of a bridge proof\n /// @param transactionId The ID of the bridge transaction\n /// @return timestamp The timestamp of the bridge proof\n /// @return relayer The relayer address of the bridge proof\n function bridgeProofs(bytes32 transactionId) external view returns (uint96 timestamp, address relayer);\n\n /// @notice Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\n /// @param request The bridge request to decode\n function getBridgeTransactionV2(bytes memory request) external view returns (BridgeTransactionV2 memory);\n}\n\n// contracts/utils/MulticallTarget.sol\n\n// solhint-disable avoid-low-level-calls\n/// @notice Template for a contract that supports batched calls (preserving the msg.sender).\n/// Only calls with zero msg.value could be batched.\nabstract contract MulticallTarget is IMulticallTarget {\n error MulticallTarget__UndeterminedRevert();\n\n /// @notice Perform a batched call to this contract, preserving the msg.sender.\n /// The return data from each call is discarded.\n /// @dev The method is non-payable, so only calls with `msg.value == 0` could be batched.\n /// It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag.\n /// Otherwise, the whole batch call will be reverted with the original revert reason.\n /// @param data List of abi-encoded calldata for the calls to perform.\n /// @param ignoreReverts Whether to ignore the revert errors from the calls.\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external {\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\n if (!success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(result);\n }\n }\n }\n\n /// @notice Perform a batched call to this contract, preserving the msg.sender.\n /// The return data from each call is preserved.\n /// @dev The method is non-payable, so only calls with `msg.value == 0` could be batched.\n /// It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag.\n /// Otherwise, the whole batch call will be reverted with the original revert reason.\n /// @param data List of abi-encoded calldata for the calls to perform.\n /// @param ignoreReverts Whether to ignore the revert errors from the calls.\n /// @return results List of results from the calls: `(success, returnData)`.\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results)\n {\n results = new Result[](data.length);\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (results[i].success, results[i].returnData) = address(this).delegatecall(data[i]);\n if (!results[i].success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(results[i].returnData);\n }\n }\n }\n\n /// @dev Bubbles the revert message from the underlying call.\n /// Note: preserves the same custom error or revert string, if one was used.\n /// Source: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v5.0.2/contracts/utils/Address.sol#L143-L158\n function _bubbleRevert(bytes memory returnData) internal pure {\n // Look for revert reason and bubble it up if present\n if (returnData.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n // solhint-disable-next-line no-inline-assembly\n assembly {\n let returndata_size := mload(returnData)\n revert(add(32, returnData), returndata_size)\n }\n } else {\n revert MulticallTarget__UndeterminedRevert();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// contracts/libs/BridgeTransactionV2.sol\n\n// solhint-disable no-inline-assembly\nlibrary BridgeTransactionV2Lib {\n uint16 internal constant VERSION = 2;\n\n // Offsets of the fields in the packed BridgeTransactionV2 struct\n // uint16 version [000 .. 002)\n // uint32 originChainId [002 .. 006)\n // uint32 destChainId [006 .. 010)\n // address originSender [010 .. 030)\n // address destRecipient [030 .. 050)\n // address originToken [050 .. 070)\n // address destToken [070 .. 090)\n // uint256 originAmount [090 .. 122)\n // uint256 destAmount [122 .. 154)\n // uint256 originFeeAmount [154 .. 186)\n // uint256 deadline [186 .. 218)\n // uint256 nonce [218 .. 250)\n // address exclusivityRelayer [250 .. 270)\n // uint256 exclusivityEndTime [270 .. 302)\n // uint256 zapNative [302 .. 334)\n // bytes zapData [334 .. ***)\n\n // forgefmt: disable-start\n uint256 private constant OFFSET_ORIGIN_CHAIN_ID = 2;\n uint256 private constant OFFSET_DEST_CHAIN_ID = 6;\n uint256 private constant OFFSET_ORIGIN_SENDER = 10;\n uint256 private constant OFFSET_DEST_RECIPIENT = 30;\n uint256 private constant OFFSET_ORIGIN_TOKEN = 50;\n uint256 private constant OFFSET_DEST_TOKEN = 70;\n uint256 private constant OFFSET_ORIGIN_AMOUNT = 90;\n uint256 private constant OFFSET_DEST_AMOUNT = 122;\n uint256 private constant OFFSET_ORIGIN_FEE_AMOUNT = 154;\n uint256 private constant OFFSET_DEADLINE = 186;\n uint256 private constant OFFSET_NONCE = 218;\n uint256 private constant OFFSET_EXCLUSIVITY_RELAYER = 250;\n uint256 private constant OFFSET_EXCLUSIVITY_END_TIME = 270;\n uint256 private constant OFFSET_ZAP_NATIVE = 302;\n uint256 private constant OFFSET_ZAP_DATA = 334;\n // forgefmt: disable-end\n\n error BridgeTransactionV2__InvalidEncodedTx();\n error BridgeTransactionV2__UnsupportedVersion(uint16 version);\n\n /// @notice Validates the encoded transaction to be a tightly packed encoded payload for BridgeTransactionV2.\n /// @dev Checks the minimum length and the version, use this function before decoding any of the fields.\n function validateV2(bytes calldata encodedTx) internal pure {\n // Check the minimum length: must at least include all static fields.\n if (encodedTx.length \u003c OFFSET_ZAP_DATA) revert BridgeTransactionV2__InvalidEncodedTx();\n // Once we validated the length, we can be sure that the version field is present.\n uint16 version_ = version(encodedTx);\n if (version_ != VERSION) revert BridgeTransactionV2__UnsupportedVersion(version_);\n }\n\n /// @notice Encodes the BridgeTransactionV2 struct by tightly packing the fields.\n /// @dev `abi.decode` will not work as a result of the tightly packed fields. Use `decodeV2` to decode instead.\n function encodeV2(IFastBridgeV2.BridgeTransactionV2 memory bridgeTx) internal pure returns (bytes memory) {\n // We split the encoding into two parts to avoid stack-too-deep error\n bytes memory firstPart = abi.encodePacked(\n VERSION,\n bridgeTx.originChainId,\n bridgeTx.destChainId,\n bridgeTx.originSender,\n bridgeTx.destRecipient,\n bridgeTx.originToken,\n bridgeTx.destToken,\n bridgeTx.originAmount\n );\n return abi.encodePacked(\n firstPart,\n bridgeTx.destAmount,\n bridgeTx.originFeeAmount,\n // Note: we skip the deprecated `sendChainGas` flag, which was present in BridgeTransaction V1\n bridgeTx.deadline,\n bridgeTx.nonce,\n // New V2 fields: exclusivity\n bridgeTx.exclusivityRelayer,\n bridgeTx.exclusivityEndTime,\n // New V2 fields: Zap\n bridgeTx.zapNative,\n bridgeTx.zapData\n );\n }\n\n /// @notice Decodes the BridgeTransactionV2 struct from the encoded transaction.\n /// @dev Encoded BridgeTransactionV2 struct must be tightly packed.\n /// Use `validateV2` before decoding to ensure the encoded transaction is valid.\n function decodeV2(bytes calldata encodedTx)\n internal\n pure\n returns (IFastBridgeV2.BridgeTransactionV2 memory bridgeTx)\n {\n bridgeTx.originChainId = originChainId(encodedTx);\n bridgeTx.destChainId = destChainId(encodedTx);\n bridgeTx.originSender = originSender(encodedTx);\n bridgeTx.destRecipient = destRecipient(encodedTx);\n bridgeTx.originToken = originToken(encodedTx);\n bridgeTx.destToken = destToken(encodedTx);\n bridgeTx.originAmount = originAmount(encodedTx);\n bridgeTx.destAmount = destAmount(encodedTx);\n bridgeTx.originFeeAmount = originFeeAmount(encodedTx);\n bridgeTx.deadline = deadline(encodedTx);\n bridgeTx.nonce = nonce(encodedTx);\n bridgeTx.exclusivityRelayer = exclusivityRelayer(encodedTx);\n bridgeTx.exclusivityEndTime = exclusivityEndTime(encodedTx);\n bridgeTx.zapNative = zapNative(encodedTx);\n bridgeTx.zapData = zapData(encodedTx);\n }\n\n /// @notice Extracts the version from the encoded transaction.\n function version(bytes calldata encodedTx) internal pure returns (uint16 version_) {\n // Load 32 bytes from the start and shift it 240 bits to the right to get the highest 16 bits.\n assembly {\n version_ := shr(240, calldataload(encodedTx.offset))\n }\n }\n\n /// @notice Extracts the origin chain ID from the encoded transaction.\n function originChainId(bytes calldata encodedTx) internal pure returns (uint32 originChainId_) {\n // Load 32 bytes from the offset and shift it 224 bits to the right to get the highest 32 bits.\n assembly {\n originChainId_ := shr(224, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_CHAIN_ID)))\n }\n }\n\n /// @notice Extracts the destination chain ID from the encoded transaction.\n function destChainId(bytes calldata encodedTx) internal pure returns (uint32 destChainId_) {\n // Load 32 bytes from the offset and shift it 224 bits to the right to get the highest 32 bits.\n assembly {\n destChainId_ := shr(224, calldataload(add(encodedTx.offset, OFFSET_DEST_CHAIN_ID)))\n }\n }\n\n /// @notice Extracts the origin sender from the encoded transaction.\n function originSender(bytes calldata encodedTx) internal pure returns (address originSender_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n originSender_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_SENDER)))\n }\n }\n\n /// @notice Extracts the destination recipient from the encoded transaction.\n function destRecipient(bytes calldata encodedTx) internal pure returns (address destRecipient_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n destRecipient_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_DEST_RECIPIENT)))\n }\n }\n\n /// @notice Extracts the origin token from the encoded transaction.\n function originToken(bytes calldata encodedTx) internal pure returns (address originToken_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n originToken_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_TOKEN)))\n }\n }\n\n /// @notice Extracts the destination token from the encoded transaction.\n function destToken(bytes calldata encodedTx) internal pure returns (address destToken_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n destToken_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_DEST_TOKEN)))\n }\n }\n\n /// @notice Extracts the origin amount from the encoded transaction.\n function originAmount(bytes calldata encodedTx) internal pure returns (uint256 originAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n originAmount_ := calldataload(add(encodedTx.offset, OFFSET_ORIGIN_AMOUNT))\n }\n }\n\n /// @notice Extracts the destination amount from the encoded transaction.\n function destAmount(bytes calldata encodedTx) internal pure returns (uint256 destAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n destAmount_ := calldataload(add(encodedTx.offset, OFFSET_DEST_AMOUNT))\n }\n }\n\n /// @notice Extracts the origin fee amount from the encoded transaction.\n function originFeeAmount(bytes calldata encodedTx) internal pure returns (uint256 originFeeAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n originFeeAmount_ := calldataload(add(encodedTx.offset, OFFSET_ORIGIN_FEE_AMOUNT))\n }\n }\n\n /// @notice Extracts the deadline from the encoded transaction.\n function deadline(bytes calldata encodedTx) internal pure returns (uint256 deadline_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n deadline_ := calldataload(add(encodedTx.offset, OFFSET_DEADLINE))\n }\n }\n\n /// @notice Extracts the nonce from the encoded transaction.\n function nonce(bytes calldata encodedTx) internal pure returns (uint256 nonce_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n nonce_ := calldataload(add(encodedTx.offset, OFFSET_NONCE))\n }\n }\n\n /// @notice Extracts the exclusivity relayer from the encoded transaction.\n function exclusivityRelayer(bytes calldata encodedTx) internal pure returns (address exclusivityRelayer_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n exclusivityRelayer_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_EXCLUSIVITY_RELAYER)))\n }\n }\n\n /// @notice Extracts the exclusivity end time from the encoded transaction.\n function exclusivityEndTime(bytes calldata encodedTx) internal pure returns (uint256 exclusivityEndTime_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n exclusivityEndTime_ := calldataload(add(encodedTx.offset, OFFSET_EXCLUSIVITY_END_TIME))\n }\n }\n\n /// @notice Extracts the Zap's native value from the encoded transaction.\n function zapNative(bytes calldata encodedTx) internal pure returns (uint256 zapNative_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n zapNative_ := calldataload(add(encodedTx.offset, OFFSET_ZAP_NATIVE))\n }\n }\n\n /// @notice Extracts the Zap's data from the encoded transaction.\n function zapData(bytes calldata encodedTx) internal pure returns (bytes calldata zapData_) {\n zapData_ = encodedTx[OFFSET_ZAP_DATA:];\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/AdminV2.sol\n\ncontract AdminV2 is AccessControlEnumerable, IAdminV2, IAdminV2Errors {\n using SafeERC20 for IERC20;\n\n /// @notice Address reserved for native gas token (ETH on Ethereum and most L2s, AVAX on Avalanche, etc)\n address public constant NATIVE_GAS_TOKEN = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Role identifier for Quoter API's off-chain authentication.\n /// @dev Only addresses with this role can post FastBridge quotes to the API.\n bytes32 public constant QUOTER_ROLE = keccak256(\"QUOTER_ROLE\");\n\n /// @notice Role identifier for Prover's on-chain authentication in FastBridge.\n /// @dev Only addresses with this role can provide proofs that a FastBridge request has been relayed.\n bytes32 public constant PROVER_ROLE = keccak256(\"PROVER_ROLE\");\n\n /// @notice Role identifier for Guard's on-chain authentication in FastBridge.\n /// @dev Only addresses with this role can dispute submitted relay proofs during the dispute period.\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n\n /// @notice Role identifier for Canceler's on-chain authentication in FastBridge.\n /// @dev Only addresses with this role can cancel a FastBridge transaction without the cancel delay.\n bytes32 public constant CANCELER_ROLE = keccak256(\"CANCELER_ROLE\");\n\n /// @notice Role identifier for Governor's on-chain administrative authority.\n /// @dev Only addresses with this role can perform administrative tasks within the contract.\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n /// @notice Denominator for fee rates, represents 100%.\n uint256 public constant FEE_BPS = 1e6;\n /// @notice Maximum protocol fee rate: 1% on origin amount.\n uint256 public constant FEE_RATE_MAX = 0.01e6;\n\n /// @notice Minimum cancel delay that can be set by the governor.\n uint256 public constant MIN_CANCEL_DELAY = 1 hours;\n /// @notice Default cancel delay set during the contract deployment.\n uint256 public constant DEFAULT_CANCEL_DELAY = 1 days;\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Delay for a transaction after which it could be permisionlessly cancelled\n uint256 public cancelDelay;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Use ZapNative V2 requests instead.\n uint256 public immutable chainGasAmount = 0;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n _setCancelDelay(DEFAULT_CANCEL_DELAY);\n }\n\n /// @notice Allows the contract governor to set the cancel delay. The cancel delay is the time after the transaction\n /// deadline after which it can be permissionlessly cancelled, if it hasn't been proven by any of the Relayers.\n function setCancelDelay(uint256 newCancelDelay) external onlyRole(GOVERNOR_ROLE) {\n _setCancelDelay(newCancelDelay);\n }\n\n /// @notice Allows the contract governor to set the protocol fee rate. The protocol fee is taken from the origin\n /// amount only for completed and claimed transactions.\n /// @dev The protocol fee is abstracted away from the relayers, they always operate using the amounts after fees:\n /// what they see as the origin amount emitted in the log is what they get credited with.\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n if (newFeeRate \u003e FEE_RATE_MAX) revert FeeRateAboveMax();\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n /// @notice Allows the contract governor to sweep the accumulated protocol fees in the contract.\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n emit FeesSwept(token, recipient, feeAmount);\n /// Sweep the fees as the last transaction action\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(recipient), feeAmount);\n } else {\n IERC20(token).safeTransfer(recipient, feeAmount);\n }\n }\n\n /// @notice Internal function to set the cancel delay. Security checks are performed outside of this function.\n function _setCancelDelay(uint256 newCancelDelay) private {\n if (newCancelDelay \u003c MIN_CANCEL_DELAY) revert CancelDelayBelowMin();\n uint256 oldCancelDelay = cancelDelay;\n cancelDelay = newCancelDelay;\n emit CancelDelayUpdated(oldCancelDelay, newCancelDelay);\n }\n}\n\n// contracts/FastBridgeV2.sol\n\n/// @notice FastBridgeV2 is a contract for bridging tokens across chains.\ncontract FastBridgeV2 is AdminV2, MulticallTarget, IFastBridgeV2, IFastBridgeV2Errors {\n using BridgeTransactionV2Lib for bytes;\n using SafeERC20 for IERC20;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n /// @notice Maximum length of accepted zapData\n uint256 public constant MAX_ZAP_DATA_LENGTH = 2 ** 16 - 1;\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeTxDetails) public bridgeTxDetails;\n /// @notice Relay details on destination chain\n mapping(bytes32 =\u003e BridgeRelay) public bridgeRelayDetails;\n /// @notice Unique bridge nonces tracked per originSender\n mapping(address =\u003e uint256) public senderNonces;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Replaced by senderNonces\n uint256 public immutable nonce = 0;\n /// @notice the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) AdminV2(_owner) {\n deployBlock = block.number;\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n bridge({\n params: params,\n paramsV2: BridgeParamsV2({\n quoteRelayer: address(0),\n quoteExclusivitySeconds: 0,\n quoteId: bytes(\"\"),\n zapNative: 0,\n zapData: bytes(\"\")\n })\n });\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes calldata request) external payable {\n // relay override will validate the request\n relay({request: request, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes calldata request, bytes32 destTxHash) external {\n request.validateV2();\n prove({transactionId: keccak256(request), destTxHash: destTxHash, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridgeV2\n function claim(bytes calldata request) external {\n // claim override will validate the request\n claim({request: request, to: address(0)});\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Aggregate the read operations from the same storage slot\n address disputedRelayer = $.proofRelayer;\n BridgeStatus status = $.status;\n uint56 proofBlockTimestamp = $.proofBlockTimestamp;\n // Can only dispute a RELAYER_PROVED transaction within the dispute period\n if (status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(proofBlockTimestamp) \u003e DISPUTE_PERIOD) {\n revert DisputePeriodPassed();\n }\n // Update status to REQUESTED and delete the disputed proof details\n // Note: these are storage writes\n $.status = BridgeStatus.REQUESTED;\n $.proofRelayer = address(0);\n $.proofBlockTimestamp = 0;\n\n emit BridgeProofDisputed(transactionId, disputedRelayer);\n }\n\n /// Note: this function is deprecated and will be removed in a future version.\n /// @inheritdoc IFastBridge\n function refund(bytes calldata request) external {\n cancel(request);\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // The correct relayer can only claim a RELAYER_PROVED transaction after the dispute period\n if ($.status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if ($.proofRelayer != relayer) revert SenderIncorrect();\n return _timeSince($.proofBlockTimestamp) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n /// @dev This method is added to achieve backwards compatibility with decoding requests into V1 structs:\n /// - `zapNative` is partially reported as a zero/non-zero flag\n /// - `zapData` is ignored\n /// In order to process all kinds of requests use getBridgeTransactionV2 instead.\n function getBridgeTransaction(bytes calldata request) external view returns (BridgeTransaction memory) {\n // Try decoding into V2 struct first. This will revert if V1 struct is passed\n try this.getBridgeTransactionV2(request) returns (BridgeTransactionV2 memory txV2) {\n // Note: we entirely ignore the zapData field, as it was not present in V1\n return BridgeTransaction({\n originChainId: txV2.originChainId,\n destChainId: txV2.destChainId,\n originSender: txV2.originSender,\n destRecipient: txV2.destRecipient,\n originToken: txV2.originToken,\n destToken: txV2.destToken,\n originAmount: txV2.originAmount,\n destAmount: txV2.destAmount,\n originFeeAmount: txV2.originFeeAmount,\n sendChainGas: txV2.zapNative != 0,\n deadline: txV2.deadline,\n nonce: txV2.nonce\n });\n } catch {\n // Fallback to V1 struct\n return abi.decode(request, (BridgeTransaction));\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function getBridgeTransactionV2(bytes calldata request) external pure returns (BridgeTransactionV2 memory) {\n request.validateV2();\n return BridgeTransactionV2Lib.decodeV2(request);\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) public payable {\n int256 exclusivityEndTime = 0;\n // if relayer exclusivity is not intended for this bridge, set exclusivityEndTime to static zero\n // otherwise, set exclusivity to expire at the current block ts offset by quoteExclusivitySeconds\n if (paramsV2.quoteRelayer != address(0)) {\n exclusivityEndTime = int256(block.timestamp) + paramsV2.quoteExclusivitySeconds;\n }\n _validateBridgeParams(params, paramsV2, exclusivityEndTime);\n\n // transfer tokens to bridge contract\n /// @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _takeBridgedUserAsset(params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) {\n originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n }\n\n // set status to requested\n bytes memory request = BridgeTransactionV2Lib.encodeV2(\n BridgeTransactionV2({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n deadline: params.deadline,\n nonce: senderNonces[params.sender]++, // increment nonce on every bridge\n exclusivityRelayer: paramsV2.quoteRelayer,\n // We checked exclusivityEndTime to be in range [0 .. params.deadline] above, so can safely cast\n exclusivityEndTime: uint256(exclusivityEndTime),\n zapNative: paramsV2.zapNative,\n zapData: paramsV2.zapData\n })\n );\n bytes32 transactionId = keccak256(request);\n // Note: the tx status will be updated throughout the tx lifecycle, while destChainId is set once here\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n bridgeTxDetails[transactionId].destChainId = params.dstChainId;\n\n emit BridgeRequested({\n transactionId: transactionId,\n sender: params.sender,\n request: request,\n destChainId: params.dstChainId,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n sendChainGas: paramsV2.zapNative != 0\n });\n emit BridgeQuoteDetails(transactionId, paramsV2.quoteId);\n }\n\n /// @inheritdoc IFastBridgeV2\n function relay(bytes calldata request, address relayer) public payable {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n _validateRelayParams(request, transactionId, relayer);\n // mark bridge transaction as relayed\n bridgeRelayDetails[transactionId] =\n BridgeRelay({blockNumber: uint48(block.number), blockTimestamp: uint48(block.timestamp), relayer: relayer});\n\n // transfer tokens to recipient on destination chain and trigger Zap if requested\n address to = request.destRecipient();\n address token = request.destToken();\n uint256 amount = request.destAmount();\n uint256 zapNative = request.zapNative();\n\n // Emit the event before any external calls\n emit BridgeRelayed({\n transactionId: transactionId,\n relayer: relayer,\n to: to,\n originChainId: request.originChainId(),\n originToken: request.originToken(),\n destToken: token,\n originAmount: request.originAmount(),\n destAmount: amount,\n chainGasAmount: zapNative\n });\n\n // All state changes have been done at this point, can proceed to the external calls.\n // This follows the checks-effects-interactions pattern to mitigate potential reentrancy attacks.\n if (token == NATIVE_GAS_TOKEN) {\n // For the native gas token, additional zapNative is not allowed\n if (zapNative != 0) revert ZapNativeNotSupported();\n // Check that the correct msg.value was sent\n if (msg.value != amount) revert MsgValueIncorrect();\n // Don't do a native transfer yet: we will handle it alongside the Zap below\n } else {\n // For ERC20s, we check that the correct msg.value was sent\n if (msg.value != zapNative) revert MsgValueIncorrect();\n // We need to transfer the tokens from the Relayer to the recipient first before performing an\n // optional post-transfer Zap.\n IERC20(token).safeTransferFrom(msg.sender, to, amount);\n }\n // At this point we have done:\n // - Transferred the requested amount of ERC20 tokens to the recipient.\n // At this point we have confirmed:\n // - For ERC20s: msg.value matches the requested zapNative amount.\n // - For the native gas token: msg.value matches the requested destAmount.\n // Remaining optional things to do:\n // - Forward the full msg.value to the recipient (if non-zero).\n // - Trigger a Zap (if zapData is present).\n bytes calldata zapData = request.zapData();\n if (zapData.length != 0) {\n // Zap Data is present: Zap has been requested by the recipient. Trigger it forwarding the full msg.value.\n\n // Note: if token has a fee on transfers, the recipient will have received less than `amount`.\n // This is a very niche edge case and should be handled by the recipient contract.\n _triggerZapWithChecks({recipient: to, token: token, amount: amount, zapData: zapData});\n } else if (msg.value != 0) {\n // Zap Data is missing, but msg.value was sent. This could happen in two different cases:\n // - Relay with the native gas token is happening.\n // - Relay with ERC20 is happening, with a `zapNative \u003e 0` request.\n // In both cases, we need to transfer the full msg.value to the recipient.\n Address.sendValue(payable(to), msg.value);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) public onlyRole(PROVER_ROLE) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n\n // Can only prove a REQUESTED transaction\n if ($.status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n // Update status to RELAYER_PROVED and store the proof details\n // Note: these are storage writes\n $.status = BridgeStatus.RELAYER_PROVED;\n $.proofBlockTimestamp = uint56(block.timestamp);\n $.proofRelayer = relayer;\n\n emit BridgeProofProvided(transactionId, relayer, destTxHash);\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes calldata request, address to) public {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Aggregate the read operations from the same storage slot\n address proofRelayer = $.proofRelayer;\n BridgeStatus status = $.status;\n uint56 proofBlockTimestamp = $.proofBlockTimestamp;\n\n // Can only claim a RELAYER_PROVED transaction after the dispute period\n if (status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(proofBlockTimestamp) \u003c= DISPUTE_PERIOD) {\n revert DisputePeriodNotPassed();\n }\n\n if (to == address(0)) {\n // Anyone could claim the funds to the proven relayer on their behalf\n to = proofRelayer;\n } else if (proofRelayer != msg.sender) {\n // Only the proven relayer could specify an address to claim the funds to\n revert SenderIncorrect();\n }\n\n // Update status to RELAYER_CLAIMED and transfer the origin collateral to the specified claim address\n // Note: this is a storage write\n $.status = BridgeStatus.RELAYER_CLAIMED;\n\n address token = request.originToken();\n uint256 amount = request.originAmount();\n // Update protocol fees if origin fee amount exists\n uint256 originFeeAmount = request.originFeeAmount();\n if (originFeeAmount \u003e 0) protocolFees[token] += originFeeAmount;\n // Emit the event before any external calls\n emit BridgeDepositClaimed(transactionId, proofRelayer, to, token, amount);\n // Complete the relayer claim as the last transaction action\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(to), amount);\n } else {\n IERC20(token).safeTransfer(to, amount);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function cancel(bytes calldata request) public {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Can only cancel a REQUESTED transaction after its deadline expires\n if ($.status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n uint256 deadline = request.deadline();\n // Permissionless cancel is only allowed after `cancelDelay` on top of the deadline\n if (!hasRole(CANCELER_ROLE, msg.sender)) deadline += cancelDelay;\n if (block.timestamp \u003c= deadline) revert DeadlineNotExceeded();\n // Update status to REFUNDED and return the full amount (collateral + protocol fees) to the original sender.\n // The protocol fees are only updated when the transaction is claimed, so we don't need to update them here.\n // Note: this is a storage write\n $.status = BridgeStatus.REFUNDED;\n\n address to = request.originSender();\n address token = request.originToken();\n uint256 amount = request.originAmount() + request.originFeeAmount();\n // Emit the event before any external calls\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n // Complete the user cancel as the last transaction action\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(to), amount);\n } else {\n IERC20(token).safeTransfer(to, amount);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeStatuses(bytes32 transactionId) public view returns (BridgeStatus status) {\n return bridgeTxDetails[transactionId].status;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeProofs(bytes32 transactionId) public view returns (uint96 timestamp, address relayer) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n\n timestamp = $.proofBlockTimestamp;\n relayer = $.proofRelayer;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeRelays(bytes32 transactionId) public view returns (bool) {\n // has this transactionId been relayed?\n return bridgeRelayDetails[transactionId].relayer != address(0);\n }\n\n /// @notice Takes the bridged asset from the user into FastBridgeV2 custody. It will be later\n /// claimed by the relayer who completed the relay on destination chain, or transferred back to the user\n /// via the cancel function should no one complete the relay.\n function _takeBridgedUserAsset(address token, uint256 amount) internal returns (uint256 amountTaken) {\n if (token == NATIVE_GAS_TOKEN) {\n // For the native gas token, we just need to check that the supplied msg.value is correct.\n // Supplied `msg.value` is already in FastBridgeV2 custody.\n if (amount != msg.value) revert MsgValueIncorrect();\n amountTaken = msg.value;\n } else {\n // For ERC20s, token is explicitly transferred from the user to FastBridgeV2.\n // We don't allow non-zero `msg.value` to avoid extra funds from being stuck in FastBridgeV2.\n if (msg.value != 0) revert MsgValueIncorrect();\n // Throw an explicit error if the provided token address is not a contract\n if (token.code.length == 0) revert TokenNotContract();\n amountTaken = IERC20(token).balanceOf(address(this));\n IERC20(token).safeTransferFrom(msg.sender, address(this), amount);\n // Use the balance difference as the amount taken in case of fee on transfer tokens.\n amountTaken = IERC20(token).balanceOf(address(this)) - amountTaken;\n }\n }\n\n /// @notice Calls the Recipient's hook function with the specified zapData and performs\n /// all the necessary checks for the returned value.\n function _triggerZapWithChecks(address recipient, address token, uint256 amount, bytes calldata zapData) internal {\n // This will bubble any revert messages from the hook function\n bytes memory returnData = Address.functionCallWithValue({\n target: recipient,\n data: abi.encodeCall(IZapRecipient.zap, (token, amount, zapData)),\n // Note: see `relay()` for reasoning behind passing msg.value\n value: msg.value\n });\n // Explicit revert if no return data at all\n if (returnData.length == 0) revert RecipientNoReturnValue();\n // Check that exactly a single return value was returned\n if (returnData.length != 32) revert RecipientIncorrectReturnValue();\n // Return value should be abi-encoded hook function selector\n if (bytes32(returnData) != bytes32(IZapRecipient.zap.selector)) {\n revert RecipientIncorrectReturnValue();\n }\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint56(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint56).max but\n /// proof.timestamp \u003c type(uint56).max via unchecked statement\n /// @param proofBlockTimestamp The bridge proof block timestamp\n /// @return delta Time delta since proof submitted\n function _timeSince(uint56 proofBlockTimestamp) internal view returns (uint256 delta) {\n unchecked {\n delta = uint56(block.timestamp) - proofBlockTimestamp;\n }\n }\n\n /// @notice Performs all the necessary checks for a bridge to happen.\n /// @dev There's no good way to refactor this function to reduce cyclomatic complexity due to\n /// the number of checks that need to be performed, so we skip the code-complexity rule here.\n // solhint-disable-next-line code-complexity\n function _validateBridgeParams(\n BridgeParams memory params,\n BridgeParamsV2 memory paramsV2,\n int256 exclusivityEndTime\n )\n internal\n view\n {\n // Check V1 (legacy) params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.sender == address(0) || params.to == address(0)) revert ZeroAddress();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n // Check V2 params\n if (paramsV2.zapData.length \u003e MAX_ZAP_DATA_LENGTH) revert ZapDataLengthAboveMax();\n if (paramsV2.zapNative != 0 \u0026\u0026 params.destToken == NATIVE_GAS_TOKEN) {\n revert ZapNativeNotSupported();\n }\n // exclusivityEndTime must be in range [0 .. params.deadline]\n if (exclusivityEndTime \u003c 0 || exclusivityEndTime \u003e int256(params.deadline)) {\n revert ExclusivityParamsIncorrect();\n }\n }\n\n /// @notice Performs all the necessary checks for a relay to happen.\n function _validateRelayParams(bytes calldata request, bytes32 transactionId, address relayer) internal view {\n if (relayer == address(0)) revert ZeroAddress();\n // Check if the transaction has already been relayed\n if (bridgeRelays(transactionId)) revert TransactionRelayed();\n if (request.destChainId() != block.chainid) revert ChainIncorrect();\n // Check the deadline for relay to happen\n if (block.timestamp \u003e request.deadline()) revert DeadlineExceeded();\n // Check the exclusivity period, if it is still ongoing\n address exclRelayer = request.exclusivityRelayer();\n if (exclRelayer != address(0) \u0026\u0026 exclRelayer != relayer \u0026\u0026 block.timestamp \u003c= request.exclusivityEndTime()) {\n revert ExclusivityPeriodNotPassed();\n }\n }\n}\n","language":"Solidity","languageVersion":"0.8.24","compilerVersion":"0.8.24","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"","srcMapRuntime":"","abiDefinition":[{"inputs":[],"name":"AccessControlBadConfirmation","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"bytes32","name":"neededRole","type":"bytes32"}],"name":"AccessControlUnauthorizedAccount","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"previousAdminRole","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"newAdminRole","type":"bytes32"}],"name":"RoleAdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleRevoked","type":"event"},{"inputs":[],"name":"DEFAULT_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleAdmin","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"uint256","name":"index","type":"uint256"}],"name":"getRoleMember","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleMemberCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"grantRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"hasRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"callerConfirmation","type":"address"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"revokeRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"}],"userDoc":{"kind":"user","methods":{},"version":1},"developerDoc":{"details":"Extension of {AccessControl} that allows enumerating the members of each role.","errors":{"AccessControlBadConfirmation()":[{"details":"The caller of a function is not the expected one. NOTE: Don't confuse with {AccessControlUnauthorizedAccount}."}],"AccessControlUnauthorizedAccount(address,bytes32)":[{"details":"The `account` is missing a role."}]},"events":{"RoleAdminChanged(bytes32,bytes32,bytes32)":{"details":"Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole` `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite {RoleAdminChanged} not being emitted signaling this."},"RoleGranted(bytes32,address,address)":{"details":"Emitted when `account` is granted `role`. `sender` is the account that originated the contract call, an admin role bearer except when using {AccessControl-_setupRole}."},"RoleRevoked(bytes32,address,address)":{"details":"Emitted when `account` is revoked `role`. `sender` is the account that originated the contract call: - if using `revokeRole`, it is the admin role bearer - if using `renounceRole`, it is the role bearer (i.e. `account`)"}},"kind":"dev","methods":{"getRoleAdmin(bytes32)":{"details":"Returns the admin role that controls `role`. See {grantRole} and {revokeRole}. To change a role's admin, use {_setRoleAdmin}."},"getRoleMember(bytes32,uint256)":{"details":"Returns one of the accounts that have `role`. `index` must be a value between 0 and {getRoleMemberCount}, non-inclusive. Role bearers are not sorted in any particular way, and their ordering may change at any point. WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure you perform all queries on the same block. See the following https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post] for more information."},"getRoleMemberCount(bytes32)":{"details":"Returns the number of accounts that have `role`. Can be used together with {getRoleMember} to enumerate all bearers of a role."},"grantRole(bytes32,address)":{"details":"Grants `role` to `account`. If `account` had not been already granted `role`, emits a {RoleGranted} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleGranted} event."},"hasRole(bytes32,address)":{"details":"Returns `true` if `account` has been granted `role`."},"renounceRole(bytes32,address)":{"details":"Revokes `role` from the calling account. Roles are often managed via {grantRole} and {revokeRole}: this function's purpose is to provide a mechanism for accounts to lose their privileges if they are compromised (such as when a trusted device is misplaced). If the calling account had been revoked `role`, emits a {RoleRevoked} event. Requirements: - the caller must be `callerConfirmation`. May emit a {RoleRevoked} event."},"revokeRole(bytes32,address)":{"details":"Revokes `role` from `account`. If `account` had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleRevoked} event."},"supportsInterface(bytes4)":{"details":"See {IERC165-supportsInterface}."}},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[],\"name\":\"AccessControlBadConfirmation\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"neededRole\",\"type\":\"bytes32\"}],\"name\":\"AccessControlUnauthorizedAccount\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"previousAdminRole\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"newAdminRole\",\"type\":\"bytes32\"}],\"name\":\"RoleAdminChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleGranted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleRevoked\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"DEFAULT_ADMIN_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"}],\"name\":\"getRoleAdmin\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"index\",\"type\":\"uint256\"}],\"name\":\"getRoleMember\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"}],\"name\":\"getRoleMemberCount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"grantRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"hasRole\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"callerConfirmation\",\"type\":\"address\"}],\"name\":\"renounceRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"revokeRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes4\",\"name\":\"interfaceId\",\"type\":\"bytes4\"}],\"name\":\"supportsInterface\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"}],\"devdoc\":{\"details\":\"Extension of {AccessControl} that allows enumerating the members of each role.\",\"errors\":{\"AccessControlBadConfirmation()\":[{\"details\":\"The caller of a function is not the expected one. NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\"}],\"AccessControlUnauthorizedAccount(address,bytes32)\":[{\"details\":\"The `account` is missing a role.\"}]},\"events\":{\"RoleAdminChanged(bytes32,bytes32,bytes32)\":{\"details\":\"Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole` `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite {RoleAdminChanged} not being emitted signaling this.\"},\"RoleGranted(bytes32,address,address)\":{\"details\":\"Emitted when `account` is granted `role`. `sender` is the account that originated the contract call, an admin role bearer except when using {AccessControl-_setupRole}.\"},\"RoleRevoked(bytes32,address,address)\":{\"details\":\"Emitted when `account` is revoked `role`. `sender` is the account that originated the contract call: - if using `revokeRole`, it is the admin role bearer - if using `renounceRole`, it is the role bearer (i.e. `account`)\"}},\"kind\":\"dev\",\"methods\":{\"getRoleAdmin(bytes32)\":{\"details\":\"Returns the admin role that controls `role`. See {grantRole} and {revokeRole}. To change a role's admin, use {_setRoleAdmin}.\"},\"getRoleMember(bytes32,uint256)\":{\"details\":\"Returns one of the accounts that have `role`. `index` must be a value between 0 and {getRoleMemberCount}, non-inclusive. Role bearers are not sorted in any particular way, and their ordering may change at any point. WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure you perform all queries on the same block. See the following https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post] for more information.\"},\"getRoleMemberCount(bytes32)\":{\"details\":\"Returns the number of accounts that have `role`. Can be used together with {getRoleMember} to enumerate all bearers of a role.\"},\"grantRole(bytes32,address)\":{\"details\":\"Grants `role` to `account`. If `account` had not been already granted `role`, emits a {RoleGranted} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleGranted} event.\"},\"hasRole(bytes32,address)\":{\"details\":\"Returns `true` if `account` has been granted `role`.\"},\"renounceRole(bytes32,address)\":{\"details\":\"Revokes `role` from the calling account. Roles are often managed via {grantRole} and {revokeRole}: this function's purpose is to provide a mechanism for accounts to lose their privileges if they are compromised (such as when a trusted device is misplaced). If the calling account had been revoked `role`, emits a {RoleRevoked} event. Requirements: - the caller must be `callerConfirmation`. May emit a {RoleRevoked} event.\"},\"revokeRole(bytes32,address)\":{\"details\":\"Revokes `role` from `account`. If `account` had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleRevoked} event.\"},\"supportsInterface(bytes4)\":{\"details\":\"See {IERC165-supportsInterface}.\"}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeV2.sol\":\"AccessControlEnumerable\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeV2.sol\":{\"keccak256\":\"0xac79c463688a682ca706a4ef95e7817b83548cdfa8182ba0426ac7e5e07613d8\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://b3ecb7097381287cafc3a73f3a2bb03565115ebb682a85064e0b0dc2f7e2919d\",\"dweb:/ipfs/QmatruW3nYZTksf3CeQ8wwiAG4c7xoEJBEp6drHPtFLBRK\"]}},\"version\":1}"},"hashes":{"DEFAULT_ADMIN_ROLE()":"a217fddf","getRoleAdmin(bytes32)":"248a9ca3","getRoleMember(bytes32,uint256)":"9010d07c","getRoleMemberCount(bytes32)":"ca15c873","grantRole(bytes32,address)":"2f2ff15d","hasRole(bytes32,address)":"91d14854","renounceRole(bytes32,address)":"36568abe","revokeRole(bytes32,address)":"d547741f","supportsInterface(bytes4)":"01ffc9a7"}},"solidity/FastBridgeV2.sol:Address":{"code":"0x60566037600b82828239805160001a607314602a57634e487b7160e01b600052600060045260246000fd5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600080fdfea264697066735822122053e3727ad57bc90f5560dc5a255131033ea91c54c8a147cf6df38af4aac448d564736f6c63430008180033","runtime-code":"0x73000000000000000000000000000000000000000030146080604052600080fdfea264697066735822122053e3727ad57bc90f5560dc5a255131033ea91c54c8a147cf6df38af4aac448d564736f6c63430008180033","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.24 ^0.8.20 ^0.8.4;\n\n// contracts/interfaces/IAdminV2.sol\n\ninterface IAdminV2 {\n event CancelDelayUpdated(uint256 oldCancelDelay, uint256 newCancelDelay);\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n function setCancelDelay(uint256 newCancelDelay) external;\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n}\n\n// contracts/interfaces/IAdminV2Errors.sol\n\ninterface IAdminV2Errors {\n error CancelDelayBelowMin();\n error FeeRateAboveMax();\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IFastBridgeV2Errors.sol\n\ninterface IFastBridgeV2Errors {\n error AmountIncorrect();\n error ChainIncorrect();\n error ExclusivityParamsIncorrect();\n error MsgValueIncorrect();\n error SenderIncorrect();\n error StatusIncorrect();\n error TokenNotContract();\n error ZapDataLengthAboveMax();\n error ZapNativeNotSupported();\n error ZeroAddress();\n\n error RecipientIncorrectReturnValue();\n error RecipientNoReturnValue();\n\n error DeadlineExceeded();\n error DeadlineNotExceeded();\n error DeadlineTooShort();\n error DisputePeriodNotPassed();\n error DisputePeriodPassed();\n error ExclusivityPeriodNotPassed();\n\n error TransactionRelayed();\n}\n\n// contracts/interfaces/IMulticallTarget.sol\n\n/// @notice Interface for a contract that can be called multiple times by the same caller. Inspired by MulticallV3:\n/// https://github.com/mds1/multicall/blob/master/src/Multicall3.sol\ninterface IMulticallTarget {\n struct Result {\n bool success;\n bytes returnData;\n }\n\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external;\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results);\n}\n\n// contracts/interfaces/IZapRecipient.sol\n\ninterface IZapRecipient {\n function zap(address token, uint256 amount, bytes memory zapData) external payable returns (bytes4);\n}\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// contracts/interfaces/IFastBridgeV2.sol\n\ninterface IFastBridgeV2 is IFastBridge {\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n struct BridgeTxDetails {\n BridgeStatus status;\n uint32 destChainId;\n uint56 proofBlockTimestamp;\n address proofRelayer;\n }\n\n struct BridgeRelay {\n uint48 blockNumber;\n uint48 blockTimestamp;\n address relayer;\n }\n\n /// @notice New params introduced in the FastBridgeV2.\n /// We are passing fields from the older BridgeParams struct outside of this struct\n /// for backwards compatibility.\n /// Note: quoteRelayer and quoteExclusivitySeconds are either both zero (indicating no exclusivity)\n /// or both non-zero (indicating exclusivity for the given period).\n /// Note: zapNative \u003e 0 can NOT be used with destToken = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE (native token)\n /// @param quoteRelayer Relayer that provided the quote for the transaction\n /// @param quoteExclusivitySeconds Period of time the quote relayer is guaranteed exclusivity after user's deposit\n /// @param quoteId Unique quote identifier used for tracking the quote\n /// @param zapNative ETH value to send to the recipient (if any)\n /// @param zapData Parameters for the Zap to the destination recipient (if any)\n struct BridgeParamsV2 {\n address quoteRelayer;\n int256 quoteExclusivitySeconds;\n bytes quoteId;\n uint256 zapNative;\n bytes zapData;\n }\n\n /// @notice Updated bridge transaction struct to include parameters introduced in FastBridgeV2.\n /// Note: only `exclusivityRelayer` can fill such a transaction until `exclusivityEndTime`.\n struct BridgeTransactionV2 {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n // Note: sendChainGas flag from V1 is deprecated\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n address exclusivityRelayer;\n uint256 exclusivityEndTime;\n uint256 zapNative; // ETH value to send to the recipient (if any)\n bytes zapData; // data to pass for the Zap action (if any)\n }\n\n event BridgeQuoteDetails(bytes32 indexed transactionId, bytes quoteId);\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability\n /// to provide temporary exclusivity fill rights for the quote relayer.\n /// @param params The parameters required to bridge\n /// @param paramsV2 The parameters for exclusivity fill rights (optional, can be left empty)\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function relay(bytes memory request, address relayer) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param transactionId The transaction id associated with the encoded bridge transaction to prove\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital.\n /// @notice Can only send funds to the relayer address on the proof.\n /// @param request The encoded bridge transaction to claim on origin chain\n function claim(bytes memory request) external;\n\n /// @notice Cancels an outstanding bridge transaction in case optimistic bridging failed and returns the full amount\n /// to the original sender.\n /// @param request The encoded bridge transaction to refund\n function cancel(bytes memory request) external;\n\n /// @notice Checks if a transaction has been relayed\n /// @param transactionId The ID of the transaction to check\n /// @return True if the transaction has been relayed, false otherwise\n function bridgeRelays(bytes32 transactionId) external view returns (bool);\n\n /// @notice Returns the status of a bridge transaction\n /// @param transactionId The ID of the bridge transaction\n /// @return BridgeStatus Status of the bridge transaction\n function bridgeStatuses(bytes32 transactionId) external view returns (BridgeStatus);\n\n /// @notice Returns the timestamp and relayer of a bridge proof\n /// @param transactionId The ID of the bridge transaction\n /// @return timestamp The timestamp of the bridge proof\n /// @return relayer The relayer address of the bridge proof\n function bridgeProofs(bytes32 transactionId) external view returns (uint96 timestamp, address relayer);\n\n /// @notice Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\n /// @param request The bridge request to decode\n function getBridgeTransactionV2(bytes memory request) external view returns (BridgeTransactionV2 memory);\n}\n\n// contracts/utils/MulticallTarget.sol\n\n// solhint-disable avoid-low-level-calls\n/// @notice Template for a contract that supports batched calls (preserving the msg.sender).\n/// Only calls with zero msg.value could be batched.\nabstract contract MulticallTarget is IMulticallTarget {\n error MulticallTarget__UndeterminedRevert();\n\n /// @notice Perform a batched call to this contract, preserving the msg.sender.\n /// The return data from each call is discarded.\n /// @dev The method is non-payable, so only calls with `msg.value == 0` could be batched.\n /// It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag.\n /// Otherwise, the whole batch call will be reverted with the original revert reason.\n /// @param data List of abi-encoded calldata for the calls to perform.\n /// @param ignoreReverts Whether to ignore the revert errors from the calls.\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external {\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\n if (!success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(result);\n }\n }\n }\n\n /// @notice Perform a batched call to this contract, preserving the msg.sender.\n /// The return data from each call is preserved.\n /// @dev The method is non-payable, so only calls with `msg.value == 0` could be batched.\n /// It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag.\n /// Otherwise, the whole batch call will be reverted with the original revert reason.\n /// @param data List of abi-encoded calldata for the calls to perform.\n /// @param ignoreReverts Whether to ignore the revert errors from the calls.\n /// @return results List of results from the calls: `(success, returnData)`.\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results)\n {\n results = new Result[](data.length);\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (results[i].success, results[i].returnData) = address(this).delegatecall(data[i]);\n if (!results[i].success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(results[i].returnData);\n }\n }\n }\n\n /// @dev Bubbles the revert message from the underlying call.\n /// Note: preserves the same custom error or revert string, if one was used.\n /// Source: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v5.0.2/contracts/utils/Address.sol#L143-L158\n function _bubbleRevert(bytes memory returnData) internal pure {\n // Look for revert reason and bubble it up if present\n if (returnData.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n // solhint-disable-next-line no-inline-assembly\n assembly {\n let returndata_size := mload(returnData)\n revert(add(32, returnData), returndata_size)\n }\n } else {\n revert MulticallTarget__UndeterminedRevert();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// contracts/libs/BridgeTransactionV2.sol\n\n// solhint-disable no-inline-assembly\nlibrary BridgeTransactionV2Lib {\n uint16 internal constant VERSION = 2;\n\n // Offsets of the fields in the packed BridgeTransactionV2 struct\n // uint16 version [000 .. 002)\n // uint32 originChainId [002 .. 006)\n // uint32 destChainId [006 .. 010)\n // address originSender [010 .. 030)\n // address destRecipient [030 .. 050)\n // address originToken [050 .. 070)\n // address destToken [070 .. 090)\n // uint256 originAmount [090 .. 122)\n // uint256 destAmount [122 .. 154)\n // uint256 originFeeAmount [154 .. 186)\n // uint256 deadline [186 .. 218)\n // uint256 nonce [218 .. 250)\n // address exclusivityRelayer [250 .. 270)\n // uint256 exclusivityEndTime [270 .. 302)\n // uint256 zapNative [302 .. 334)\n // bytes zapData [334 .. ***)\n\n // forgefmt: disable-start\n uint256 private constant OFFSET_ORIGIN_CHAIN_ID = 2;\n uint256 private constant OFFSET_DEST_CHAIN_ID = 6;\n uint256 private constant OFFSET_ORIGIN_SENDER = 10;\n uint256 private constant OFFSET_DEST_RECIPIENT = 30;\n uint256 private constant OFFSET_ORIGIN_TOKEN = 50;\n uint256 private constant OFFSET_DEST_TOKEN = 70;\n uint256 private constant OFFSET_ORIGIN_AMOUNT = 90;\n uint256 private constant OFFSET_DEST_AMOUNT = 122;\n uint256 private constant OFFSET_ORIGIN_FEE_AMOUNT = 154;\n uint256 private constant OFFSET_DEADLINE = 186;\n uint256 private constant OFFSET_NONCE = 218;\n uint256 private constant OFFSET_EXCLUSIVITY_RELAYER = 250;\n uint256 private constant OFFSET_EXCLUSIVITY_END_TIME = 270;\n uint256 private constant OFFSET_ZAP_NATIVE = 302;\n uint256 private constant OFFSET_ZAP_DATA = 334;\n // forgefmt: disable-end\n\n error BridgeTransactionV2__InvalidEncodedTx();\n error BridgeTransactionV2__UnsupportedVersion(uint16 version);\n\n /// @notice Validates the encoded transaction to be a tightly packed encoded payload for BridgeTransactionV2.\n /// @dev Checks the minimum length and the version, use this function before decoding any of the fields.\n function validateV2(bytes calldata encodedTx) internal pure {\n // Check the minimum length: must at least include all static fields.\n if (encodedTx.length \u003c OFFSET_ZAP_DATA) revert BridgeTransactionV2__InvalidEncodedTx();\n // Once we validated the length, we can be sure that the version field is present.\n uint16 version_ = version(encodedTx);\n if (version_ != VERSION) revert BridgeTransactionV2__UnsupportedVersion(version_);\n }\n\n /// @notice Encodes the BridgeTransactionV2 struct by tightly packing the fields.\n /// @dev `abi.decode` will not work as a result of the tightly packed fields. Use `decodeV2` to decode instead.\n function encodeV2(IFastBridgeV2.BridgeTransactionV2 memory bridgeTx) internal pure returns (bytes memory) {\n // We split the encoding into two parts to avoid stack-too-deep error\n bytes memory firstPart = abi.encodePacked(\n VERSION,\n bridgeTx.originChainId,\n bridgeTx.destChainId,\n bridgeTx.originSender,\n bridgeTx.destRecipient,\n bridgeTx.originToken,\n bridgeTx.destToken,\n bridgeTx.originAmount\n );\n return abi.encodePacked(\n firstPart,\n bridgeTx.destAmount,\n bridgeTx.originFeeAmount,\n // Note: we skip the deprecated `sendChainGas` flag, which was present in BridgeTransaction V1\n bridgeTx.deadline,\n bridgeTx.nonce,\n // New V2 fields: exclusivity\n bridgeTx.exclusivityRelayer,\n bridgeTx.exclusivityEndTime,\n // New V2 fields: Zap\n bridgeTx.zapNative,\n bridgeTx.zapData\n );\n }\n\n /// @notice Decodes the BridgeTransactionV2 struct from the encoded transaction.\n /// @dev Encoded BridgeTransactionV2 struct must be tightly packed.\n /// Use `validateV2` before decoding to ensure the encoded transaction is valid.\n function decodeV2(bytes calldata encodedTx)\n internal\n pure\n returns (IFastBridgeV2.BridgeTransactionV2 memory bridgeTx)\n {\n bridgeTx.originChainId = originChainId(encodedTx);\n bridgeTx.destChainId = destChainId(encodedTx);\n bridgeTx.originSender = originSender(encodedTx);\n bridgeTx.destRecipient = destRecipient(encodedTx);\n bridgeTx.originToken = originToken(encodedTx);\n bridgeTx.destToken = destToken(encodedTx);\n bridgeTx.originAmount = originAmount(encodedTx);\n bridgeTx.destAmount = destAmount(encodedTx);\n bridgeTx.originFeeAmount = originFeeAmount(encodedTx);\n bridgeTx.deadline = deadline(encodedTx);\n bridgeTx.nonce = nonce(encodedTx);\n bridgeTx.exclusivityRelayer = exclusivityRelayer(encodedTx);\n bridgeTx.exclusivityEndTime = exclusivityEndTime(encodedTx);\n bridgeTx.zapNative = zapNative(encodedTx);\n bridgeTx.zapData = zapData(encodedTx);\n }\n\n /// @notice Extracts the version from the encoded transaction.\n function version(bytes calldata encodedTx) internal pure returns (uint16 version_) {\n // Load 32 bytes from the start and shift it 240 bits to the right to get the highest 16 bits.\n assembly {\n version_ := shr(240, calldataload(encodedTx.offset))\n }\n }\n\n /// @notice Extracts the origin chain ID from the encoded transaction.\n function originChainId(bytes calldata encodedTx) internal pure returns (uint32 originChainId_) {\n // Load 32 bytes from the offset and shift it 224 bits to the right to get the highest 32 bits.\n assembly {\n originChainId_ := shr(224, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_CHAIN_ID)))\n }\n }\n\n /// @notice Extracts the destination chain ID from the encoded transaction.\n function destChainId(bytes calldata encodedTx) internal pure returns (uint32 destChainId_) {\n // Load 32 bytes from the offset and shift it 224 bits to the right to get the highest 32 bits.\n assembly {\n destChainId_ := shr(224, calldataload(add(encodedTx.offset, OFFSET_DEST_CHAIN_ID)))\n }\n }\n\n /// @notice Extracts the origin sender from the encoded transaction.\n function originSender(bytes calldata encodedTx) internal pure returns (address originSender_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n originSender_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_SENDER)))\n }\n }\n\n /// @notice Extracts the destination recipient from the encoded transaction.\n function destRecipient(bytes calldata encodedTx) internal pure returns (address destRecipient_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n destRecipient_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_DEST_RECIPIENT)))\n }\n }\n\n /// @notice Extracts the origin token from the encoded transaction.\n function originToken(bytes calldata encodedTx) internal pure returns (address originToken_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n originToken_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_TOKEN)))\n }\n }\n\n /// @notice Extracts the destination token from the encoded transaction.\n function destToken(bytes calldata encodedTx) internal pure returns (address destToken_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n destToken_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_DEST_TOKEN)))\n }\n }\n\n /// @notice Extracts the origin amount from the encoded transaction.\n function originAmount(bytes calldata encodedTx) internal pure returns (uint256 originAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n originAmount_ := calldataload(add(encodedTx.offset, OFFSET_ORIGIN_AMOUNT))\n }\n }\n\n /// @notice Extracts the destination amount from the encoded transaction.\n function destAmount(bytes calldata encodedTx) internal pure returns (uint256 destAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n destAmount_ := calldataload(add(encodedTx.offset, OFFSET_DEST_AMOUNT))\n }\n }\n\n /// @notice Extracts the origin fee amount from the encoded transaction.\n function originFeeAmount(bytes calldata encodedTx) internal pure returns (uint256 originFeeAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n originFeeAmount_ := calldataload(add(encodedTx.offset, OFFSET_ORIGIN_FEE_AMOUNT))\n }\n }\n\n /// @notice Extracts the deadline from the encoded transaction.\n function deadline(bytes calldata encodedTx) internal pure returns (uint256 deadline_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n deadline_ := calldataload(add(encodedTx.offset, OFFSET_DEADLINE))\n }\n }\n\n /// @notice Extracts the nonce from the encoded transaction.\n function nonce(bytes calldata encodedTx) internal pure returns (uint256 nonce_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n nonce_ := calldataload(add(encodedTx.offset, OFFSET_NONCE))\n }\n }\n\n /// @notice Extracts the exclusivity relayer from the encoded transaction.\n function exclusivityRelayer(bytes calldata encodedTx) internal pure returns (address exclusivityRelayer_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n exclusivityRelayer_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_EXCLUSIVITY_RELAYER)))\n }\n }\n\n /// @notice Extracts the exclusivity end time from the encoded transaction.\n function exclusivityEndTime(bytes calldata encodedTx) internal pure returns (uint256 exclusivityEndTime_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n exclusivityEndTime_ := calldataload(add(encodedTx.offset, OFFSET_EXCLUSIVITY_END_TIME))\n }\n }\n\n /// @notice Extracts the Zap's native value from the encoded transaction.\n function zapNative(bytes calldata encodedTx) internal pure returns (uint256 zapNative_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n zapNative_ := calldataload(add(encodedTx.offset, OFFSET_ZAP_NATIVE))\n }\n }\n\n /// @notice Extracts the Zap's data from the encoded transaction.\n function zapData(bytes calldata encodedTx) internal pure returns (bytes calldata zapData_) {\n zapData_ = encodedTx[OFFSET_ZAP_DATA:];\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/AdminV2.sol\n\ncontract AdminV2 is AccessControlEnumerable, IAdminV2, IAdminV2Errors {\n using SafeERC20 for IERC20;\n\n /// @notice Address reserved for native gas token (ETH on Ethereum and most L2s, AVAX on Avalanche, etc)\n address public constant NATIVE_GAS_TOKEN = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Role identifier for Quoter API's off-chain authentication.\n /// @dev Only addresses with this role can post FastBridge quotes to the API.\n bytes32 public constant QUOTER_ROLE = keccak256(\"QUOTER_ROLE\");\n\n /// @notice Role identifier for Prover's on-chain authentication in FastBridge.\n /// @dev Only addresses with this role can provide proofs that a FastBridge request has been relayed.\n bytes32 public constant PROVER_ROLE = keccak256(\"PROVER_ROLE\");\n\n /// @notice Role identifier for Guard's on-chain authentication in FastBridge.\n /// @dev Only addresses with this role can dispute submitted relay proofs during the dispute period.\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n\n /// @notice Role identifier for Canceler's on-chain authentication in FastBridge.\n /// @dev Only addresses with this role can cancel a FastBridge transaction without the cancel delay.\n bytes32 public constant CANCELER_ROLE = keccak256(\"CANCELER_ROLE\");\n\n /// @notice Role identifier for Governor's on-chain administrative authority.\n /// @dev Only addresses with this role can perform administrative tasks within the contract.\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n /// @notice Denominator for fee rates, represents 100%.\n uint256 public constant FEE_BPS = 1e6;\n /// @notice Maximum protocol fee rate: 1% on origin amount.\n uint256 public constant FEE_RATE_MAX = 0.01e6;\n\n /// @notice Minimum cancel delay that can be set by the governor.\n uint256 public constant MIN_CANCEL_DELAY = 1 hours;\n /// @notice Default cancel delay set during the contract deployment.\n uint256 public constant DEFAULT_CANCEL_DELAY = 1 days;\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Delay for a transaction after which it could be permisionlessly cancelled\n uint256 public cancelDelay;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Use ZapNative V2 requests instead.\n uint256 public immutable chainGasAmount = 0;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n _setCancelDelay(DEFAULT_CANCEL_DELAY);\n }\n\n /// @notice Allows the contract governor to set the cancel delay. The cancel delay is the time after the transaction\n /// deadline after which it can be permissionlessly cancelled, if it hasn't been proven by any of the Relayers.\n function setCancelDelay(uint256 newCancelDelay) external onlyRole(GOVERNOR_ROLE) {\n _setCancelDelay(newCancelDelay);\n }\n\n /// @notice Allows the contract governor to set the protocol fee rate. The protocol fee is taken from the origin\n /// amount only for completed and claimed transactions.\n /// @dev The protocol fee is abstracted away from the relayers, they always operate using the amounts after fees:\n /// what they see as the origin amount emitted in the log is what they get credited with.\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n if (newFeeRate \u003e FEE_RATE_MAX) revert FeeRateAboveMax();\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n /// @notice Allows the contract governor to sweep the accumulated protocol fees in the contract.\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n emit FeesSwept(token, recipient, feeAmount);\n /// Sweep the fees as the last transaction action\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(recipient), feeAmount);\n } else {\n IERC20(token).safeTransfer(recipient, feeAmount);\n }\n }\n\n /// @notice Internal function to set the cancel delay. Security checks are performed outside of this function.\n function _setCancelDelay(uint256 newCancelDelay) private {\n if (newCancelDelay \u003c MIN_CANCEL_DELAY) revert CancelDelayBelowMin();\n uint256 oldCancelDelay = cancelDelay;\n cancelDelay = newCancelDelay;\n emit CancelDelayUpdated(oldCancelDelay, newCancelDelay);\n }\n}\n\n// contracts/FastBridgeV2.sol\n\n/// @notice FastBridgeV2 is a contract for bridging tokens across chains.\ncontract FastBridgeV2 is AdminV2, MulticallTarget, IFastBridgeV2, IFastBridgeV2Errors {\n using BridgeTransactionV2Lib for bytes;\n using SafeERC20 for IERC20;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n /// @notice Maximum length of accepted zapData\n uint256 public constant MAX_ZAP_DATA_LENGTH = 2 ** 16 - 1;\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeTxDetails) public bridgeTxDetails;\n /// @notice Relay details on destination chain\n mapping(bytes32 =\u003e BridgeRelay) public bridgeRelayDetails;\n /// @notice Unique bridge nonces tracked per originSender\n mapping(address =\u003e uint256) public senderNonces;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Replaced by senderNonces\n uint256 public immutable nonce = 0;\n /// @notice the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) AdminV2(_owner) {\n deployBlock = block.number;\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n bridge({\n params: params,\n paramsV2: BridgeParamsV2({\n quoteRelayer: address(0),\n quoteExclusivitySeconds: 0,\n quoteId: bytes(\"\"),\n zapNative: 0,\n zapData: bytes(\"\")\n })\n });\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes calldata request) external payable {\n // relay override will validate the request\n relay({request: request, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes calldata request, bytes32 destTxHash) external {\n request.validateV2();\n prove({transactionId: keccak256(request), destTxHash: destTxHash, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridgeV2\n function claim(bytes calldata request) external {\n // claim override will validate the request\n claim({request: request, to: address(0)});\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Aggregate the read operations from the same storage slot\n address disputedRelayer = $.proofRelayer;\n BridgeStatus status = $.status;\n uint56 proofBlockTimestamp = $.proofBlockTimestamp;\n // Can only dispute a RELAYER_PROVED transaction within the dispute period\n if (status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(proofBlockTimestamp) \u003e DISPUTE_PERIOD) {\n revert DisputePeriodPassed();\n }\n // Update status to REQUESTED and delete the disputed proof details\n // Note: these are storage writes\n $.status = BridgeStatus.REQUESTED;\n $.proofRelayer = address(0);\n $.proofBlockTimestamp = 0;\n\n emit BridgeProofDisputed(transactionId, disputedRelayer);\n }\n\n /// Note: this function is deprecated and will be removed in a future version.\n /// @inheritdoc IFastBridge\n function refund(bytes calldata request) external {\n cancel(request);\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // The correct relayer can only claim a RELAYER_PROVED transaction after the dispute period\n if ($.status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if ($.proofRelayer != relayer) revert SenderIncorrect();\n return _timeSince($.proofBlockTimestamp) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n /// @dev This method is added to achieve backwards compatibility with decoding requests into V1 structs:\n /// - `zapNative` is partially reported as a zero/non-zero flag\n /// - `zapData` is ignored\n /// In order to process all kinds of requests use getBridgeTransactionV2 instead.\n function getBridgeTransaction(bytes calldata request) external view returns (BridgeTransaction memory) {\n // Try decoding into V2 struct first. This will revert if V1 struct is passed\n try this.getBridgeTransactionV2(request) returns (BridgeTransactionV2 memory txV2) {\n // Note: we entirely ignore the zapData field, as it was not present in V1\n return BridgeTransaction({\n originChainId: txV2.originChainId,\n destChainId: txV2.destChainId,\n originSender: txV2.originSender,\n destRecipient: txV2.destRecipient,\n originToken: txV2.originToken,\n destToken: txV2.destToken,\n originAmount: txV2.originAmount,\n destAmount: txV2.destAmount,\n originFeeAmount: txV2.originFeeAmount,\n sendChainGas: txV2.zapNative != 0,\n deadline: txV2.deadline,\n nonce: txV2.nonce\n });\n } catch {\n // Fallback to V1 struct\n return abi.decode(request, (BridgeTransaction));\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function getBridgeTransactionV2(bytes calldata request) external pure returns (BridgeTransactionV2 memory) {\n request.validateV2();\n return BridgeTransactionV2Lib.decodeV2(request);\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) public payable {\n int256 exclusivityEndTime = 0;\n // if relayer exclusivity is not intended for this bridge, set exclusivityEndTime to static zero\n // otherwise, set exclusivity to expire at the current block ts offset by quoteExclusivitySeconds\n if (paramsV2.quoteRelayer != address(0)) {\n exclusivityEndTime = int256(block.timestamp) + paramsV2.quoteExclusivitySeconds;\n }\n _validateBridgeParams(params, paramsV2, exclusivityEndTime);\n\n // transfer tokens to bridge contract\n /// @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _takeBridgedUserAsset(params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) {\n originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n }\n\n // set status to requested\n bytes memory request = BridgeTransactionV2Lib.encodeV2(\n BridgeTransactionV2({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n deadline: params.deadline,\n nonce: senderNonces[params.sender]++, // increment nonce on every bridge\n exclusivityRelayer: paramsV2.quoteRelayer,\n // We checked exclusivityEndTime to be in range [0 .. params.deadline] above, so can safely cast\n exclusivityEndTime: uint256(exclusivityEndTime),\n zapNative: paramsV2.zapNative,\n zapData: paramsV2.zapData\n })\n );\n bytes32 transactionId = keccak256(request);\n // Note: the tx status will be updated throughout the tx lifecycle, while destChainId is set once here\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n bridgeTxDetails[transactionId].destChainId = params.dstChainId;\n\n emit BridgeRequested({\n transactionId: transactionId,\n sender: params.sender,\n request: request,\n destChainId: params.dstChainId,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n sendChainGas: paramsV2.zapNative != 0\n });\n emit BridgeQuoteDetails(transactionId, paramsV2.quoteId);\n }\n\n /// @inheritdoc IFastBridgeV2\n function relay(bytes calldata request, address relayer) public payable {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n _validateRelayParams(request, transactionId, relayer);\n // mark bridge transaction as relayed\n bridgeRelayDetails[transactionId] =\n BridgeRelay({blockNumber: uint48(block.number), blockTimestamp: uint48(block.timestamp), relayer: relayer});\n\n // transfer tokens to recipient on destination chain and trigger Zap if requested\n address to = request.destRecipient();\n address token = request.destToken();\n uint256 amount = request.destAmount();\n uint256 zapNative = request.zapNative();\n\n // Emit the event before any external calls\n emit BridgeRelayed({\n transactionId: transactionId,\n relayer: relayer,\n to: to,\n originChainId: request.originChainId(),\n originToken: request.originToken(),\n destToken: token,\n originAmount: request.originAmount(),\n destAmount: amount,\n chainGasAmount: zapNative\n });\n\n // All state changes have been done at this point, can proceed to the external calls.\n // This follows the checks-effects-interactions pattern to mitigate potential reentrancy attacks.\n if (token == NATIVE_GAS_TOKEN) {\n // For the native gas token, additional zapNative is not allowed\n if (zapNative != 0) revert ZapNativeNotSupported();\n // Check that the correct msg.value was sent\n if (msg.value != amount) revert MsgValueIncorrect();\n // Don't do a native transfer yet: we will handle it alongside the Zap below\n } else {\n // For ERC20s, we check that the correct msg.value was sent\n if (msg.value != zapNative) revert MsgValueIncorrect();\n // We need to transfer the tokens from the Relayer to the recipient first before performing an\n // optional post-transfer Zap.\n IERC20(token).safeTransferFrom(msg.sender, to, amount);\n }\n // At this point we have done:\n // - Transferred the requested amount of ERC20 tokens to the recipient.\n // At this point we have confirmed:\n // - For ERC20s: msg.value matches the requested zapNative amount.\n // - For the native gas token: msg.value matches the requested destAmount.\n // Remaining optional things to do:\n // - Forward the full msg.value to the recipient (if non-zero).\n // - Trigger a Zap (if zapData is present).\n bytes calldata zapData = request.zapData();\n if (zapData.length != 0) {\n // Zap Data is present: Zap has been requested by the recipient. Trigger it forwarding the full msg.value.\n\n // Note: if token has a fee on transfers, the recipient will have received less than `amount`.\n // This is a very niche edge case and should be handled by the recipient contract.\n _triggerZapWithChecks({recipient: to, token: token, amount: amount, zapData: zapData});\n } else if (msg.value != 0) {\n // Zap Data is missing, but msg.value was sent. This could happen in two different cases:\n // - Relay with the native gas token is happening.\n // - Relay with ERC20 is happening, with a `zapNative \u003e 0` request.\n // In both cases, we need to transfer the full msg.value to the recipient.\n Address.sendValue(payable(to), msg.value);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) public onlyRole(PROVER_ROLE) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n\n // Can only prove a REQUESTED transaction\n if ($.status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n // Update status to RELAYER_PROVED and store the proof details\n // Note: these are storage writes\n $.status = BridgeStatus.RELAYER_PROVED;\n $.proofBlockTimestamp = uint56(block.timestamp);\n $.proofRelayer = relayer;\n\n emit BridgeProofProvided(transactionId, relayer, destTxHash);\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes calldata request, address to) public {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Aggregate the read operations from the same storage slot\n address proofRelayer = $.proofRelayer;\n BridgeStatus status = $.status;\n uint56 proofBlockTimestamp = $.proofBlockTimestamp;\n\n // Can only claim a RELAYER_PROVED transaction after the dispute period\n if (status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(proofBlockTimestamp) \u003c= DISPUTE_PERIOD) {\n revert DisputePeriodNotPassed();\n }\n\n if (to == address(0)) {\n // Anyone could claim the funds to the proven relayer on their behalf\n to = proofRelayer;\n } else if (proofRelayer != msg.sender) {\n // Only the proven relayer could specify an address to claim the funds to\n revert SenderIncorrect();\n }\n\n // Update status to RELAYER_CLAIMED and transfer the origin collateral to the specified claim address\n // Note: this is a storage write\n $.status = BridgeStatus.RELAYER_CLAIMED;\n\n address token = request.originToken();\n uint256 amount = request.originAmount();\n // Update protocol fees if origin fee amount exists\n uint256 originFeeAmount = request.originFeeAmount();\n if (originFeeAmount \u003e 0) protocolFees[token] += originFeeAmount;\n // Emit the event before any external calls\n emit BridgeDepositClaimed(transactionId, proofRelayer, to, token, amount);\n // Complete the relayer claim as the last transaction action\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(to), amount);\n } else {\n IERC20(token).safeTransfer(to, amount);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function cancel(bytes calldata request) public {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Can only cancel a REQUESTED transaction after its deadline expires\n if ($.status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n uint256 deadline = request.deadline();\n // Permissionless cancel is only allowed after `cancelDelay` on top of the deadline\n if (!hasRole(CANCELER_ROLE, msg.sender)) deadline += cancelDelay;\n if (block.timestamp \u003c= deadline) revert DeadlineNotExceeded();\n // Update status to REFUNDED and return the full amount (collateral + protocol fees) to the original sender.\n // The protocol fees are only updated when the transaction is claimed, so we don't need to update them here.\n // Note: this is a storage write\n $.status = BridgeStatus.REFUNDED;\n\n address to = request.originSender();\n address token = request.originToken();\n uint256 amount = request.originAmount() + request.originFeeAmount();\n // Emit the event before any external calls\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n // Complete the user cancel as the last transaction action\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(to), amount);\n } else {\n IERC20(token).safeTransfer(to, amount);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeStatuses(bytes32 transactionId) public view returns (BridgeStatus status) {\n return bridgeTxDetails[transactionId].status;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeProofs(bytes32 transactionId) public view returns (uint96 timestamp, address relayer) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n\n timestamp = $.proofBlockTimestamp;\n relayer = $.proofRelayer;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeRelays(bytes32 transactionId) public view returns (bool) {\n // has this transactionId been relayed?\n return bridgeRelayDetails[transactionId].relayer != address(0);\n }\n\n /// @notice Takes the bridged asset from the user into FastBridgeV2 custody. It will be later\n /// claimed by the relayer who completed the relay on destination chain, or transferred back to the user\n /// via the cancel function should no one complete the relay.\n function _takeBridgedUserAsset(address token, uint256 amount) internal returns (uint256 amountTaken) {\n if (token == NATIVE_GAS_TOKEN) {\n // For the native gas token, we just need to check that the supplied msg.value is correct.\n // Supplied `msg.value` is already in FastBridgeV2 custody.\n if (amount != msg.value) revert MsgValueIncorrect();\n amountTaken = msg.value;\n } else {\n // For ERC20s, token is explicitly transferred from the user to FastBridgeV2.\n // We don't allow non-zero `msg.value` to avoid extra funds from being stuck in FastBridgeV2.\n if (msg.value != 0) revert MsgValueIncorrect();\n // Throw an explicit error if the provided token address is not a contract\n if (token.code.length == 0) revert TokenNotContract();\n amountTaken = IERC20(token).balanceOf(address(this));\n IERC20(token).safeTransferFrom(msg.sender, address(this), amount);\n // Use the balance difference as the amount taken in case of fee on transfer tokens.\n amountTaken = IERC20(token).balanceOf(address(this)) - amountTaken;\n }\n }\n\n /// @notice Calls the Recipient's hook function with the specified zapData and performs\n /// all the necessary checks for the returned value.\n function _triggerZapWithChecks(address recipient, address token, uint256 amount, bytes calldata zapData) internal {\n // This will bubble any revert messages from the hook function\n bytes memory returnData = Address.functionCallWithValue({\n target: recipient,\n data: abi.encodeCall(IZapRecipient.zap, (token, amount, zapData)),\n // Note: see `relay()` for reasoning behind passing msg.value\n value: msg.value\n });\n // Explicit revert if no return data at all\n if (returnData.length == 0) revert RecipientNoReturnValue();\n // Check that exactly a single return value was returned\n if (returnData.length != 32) revert RecipientIncorrectReturnValue();\n // Return value should be abi-encoded hook function selector\n if (bytes32(returnData) != bytes32(IZapRecipient.zap.selector)) {\n revert RecipientIncorrectReturnValue();\n }\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint56(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint56).max but\n /// proof.timestamp \u003c type(uint56).max via unchecked statement\n /// @param proofBlockTimestamp The bridge proof block timestamp\n /// @return delta Time delta since proof submitted\n function _timeSince(uint56 proofBlockTimestamp) internal view returns (uint256 delta) {\n unchecked {\n delta = uint56(block.timestamp) - proofBlockTimestamp;\n }\n }\n\n /// @notice Performs all the necessary checks for a bridge to happen.\n /// @dev There's no good way to refactor this function to reduce cyclomatic complexity due to\n /// the number of checks that need to be performed, so we skip the code-complexity rule here.\n // solhint-disable-next-line code-complexity\n function _validateBridgeParams(\n BridgeParams memory params,\n BridgeParamsV2 memory paramsV2,\n int256 exclusivityEndTime\n )\n internal\n view\n {\n // Check V1 (legacy) params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.sender == address(0) || params.to == address(0)) revert ZeroAddress();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n // Check V2 params\n if (paramsV2.zapData.length \u003e MAX_ZAP_DATA_LENGTH) revert ZapDataLengthAboveMax();\n if (paramsV2.zapNative != 0 \u0026\u0026 params.destToken == NATIVE_GAS_TOKEN) {\n revert ZapNativeNotSupported();\n }\n // exclusivityEndTime must be in range [0 .. params.deadline]\n if (exclusivityEndTime \u003c 0 || exclusivityEndTime \u003e int256(params.deadline)) {\n revert ExclusivityParamsIncorrect();\n }\n }\n\n /// @notice Performs all the necessary checks for a relay to happen.\n function _validateRelayParams(bytes calldata request, bytes32 transactionId, address relayer) internal view {\n if (relayer == address(0)) revert ZeroAddress();\n // Check if the transaction has already been relayed\n if (bridgeRelays(transactionId)) revert TransactionRelayed();\n if (request.destChainId() != block.chainid) revert ChainIncorrect();\n // Check the deadline for relay to happen\n if (block.timestamp \u003e request.deadline()) revert DeadlineExceeded();\n // Check the exclusivity period, if it is still ongoing\n address exclRelayer = request.exclusivityRelayer();\n if (exclRelayer != address(0) \u0026\u0026 exclRelayer != relayer \u0026\u0026 block.timestamp \u003c= request.exclusivityEndTime()) {\n revert ExclusivityPeriodNotPassed();\n }\n }\n}\n","language":"Solidity","languageVersion":"0.8.24","compilerVersion":"0.8.24","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"16568:6066:0:-:0;;;;;;;;;;;;;;;-1:-1:-1;;;16568:6066:0;;;;;;;;;;;;;;;;;","srcMapRuntime":"16568:6066:0:-:0;;;;;;;;","abiDefinition":[{"inputs":[{"internalType":"address","name":"target","type":"address"}],"name":"AddressEmptyCode","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"AddressInsufficientBalance","type":"error"},{"inputs":[],"name":"FailedInnerCall","type":"error"}],"userDoc":{"kind":"user","methods":{},"version":1},"developerDoc":{"details":"Collection of functions related to the address type","errors":{"AddressEmptyCode(address)":[{"details":"There's no code at `target` (it is not a contract)."}],"AddressInsufficientBalance(address)":[{"details":"The ETH balance of the account is not enough to perform the operation."}],"FailedInnerCall()":[{"details":"A call to an address target failed. The target may have reverted."}]},"kind":"dev","methods":{},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"}],\"name\":\"AddressEmptyCode\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"AddressInsufficientBalance\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"FailedInnerCall\",\"type\":\"error\"}],\"devdoc\":{\"details\":\"Collection of functions related to the address type\",\"errors\":{\"AddressEmptyCode(address)\":[{\"details\":\"There's no code at `target` (it is not a contract).\"}],\"AddressInsufficientBalance(address)\":[{\"details\":\"The ETH balance of the account is not enough to perform the operation.\"}],\"FailedInnerCall()\":[{\"details\":\"A call to an address target failed. The target may have reverted.\"}]},\"kind\":\"dev\",\"methods\":{},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeV2.sol\":\"Address\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeV2.sol\":{\"keccak256\":\"0xac79c463688a682ca706a4ef95e7817b83548cdfa8182ba0426ac7e5e07613d8\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://b3ecb7097381287cafc3a73f3a2bb03565115ebb682a85064e0b0dc2f7e2919d\",\"dweb:/ipfs/QmatruW3nYZTksf3CeQ8wwiAG4c7xoEJBEp6drHPtFLBRK\"]}},\"version\":1}"},"hashes":{}},"solidity/FastBridgeV2.sol:AdminV2":{"code":"0x60a060405260006080523480156200001657600080fd5b50604051620015763803806200157683398101604081905262000039916200020a565b620000466000826200005c565b50620000556201518062000099565b5062000235565b6000806200006b848462000102565b90508015620000905760008481526001602052604090206200008e9084620001b0565b505b90505b92915050565b610e10811015620000bd57604051630e0ea5c760e01b815260040160405180910390fd5b600480549082905560408051828152602081018490527f909f9078b2f6eac1d10f2aae793656c5a67511eb627ebd1d2cb1eb9c0ab94c95910160405180910390a15050565b6000828152602081815260408083206001600160a01b038516845290915281205460ff16620001a7576000838152602081815260408083206001600160a01b03861684529091529020805460ff191660011790556200015e3390565b6001600160a01b0316826001600160a01b0316847f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a450600162000093565b50600062000093565b600062000090836001600160a01b0384166000818152600183016020526040812054620001a75750815460018181018455600084815260208082209093018490558454848252828601909352604090209190915562000093565b6000602082840312156200021d57600080fd5b81516001600160a01b03811681146200009057600080fd5b60805161132562000251600039600061045201526113256000f3fe608060405234801561001057600080fd5b50600436106101ae5760003560e01c80639010d07c116100ee578063bf333f2c11610097578063d547741f11610071578063d547741f146103f3578063dc9a4ef614610406578063dcf844a71461042d578063e00a83e01461044d57600080fd5b8063bf333f2c146103af578063ca15c873146103b9578063ccc57490146103cc57600080fd5b8063930ac180116100c8578063930ac1801461038a578063a217fddf14610394578063b13aa2d61461039c57600080fd5b80639010d07c1461032a57806391d148541461033d578063922b74871461038157600080fd5b80631ea327c51161015b57806336568abe1161013557806336568abe146102de57806358f85880146102f1578063638a0f09146102fa5780637ebe815c1461030357600080fd5b80631ea327c514610295578063248a9ca3146102a85780632f2ff15d146102cb57600080fd5b806306f333f21161018c57806306f333f2146102375780630f5f6ed71461024c5780630f862f1e1461025557600080fd5b806301ffc9a7146101b357806302d2ff66146101db57806303ed0ee514610210575b600080fd5b6101c66101c13660046110ef565b610474565b60405190151581526020015b60405180910390f35b6102027febfdca8e46c0b8dacf9989ee613e35727eadd20a1d5e5ad01a53968c7e5fe07a81565b6040519081526020016101d2565b6102027f043c983c49d46f0e102151eaf8085d4a2e6571d5df2d47b013f39bddfd4a639d81565b61024a61024536600461115a565b6104d0565b005b61020261271081565b61027073eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee81565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016101d2565b61024a6102a336600461118d565b610611565b6102026102b636600461118d565b60009081526020819052604090206001015490565b61024a6102d93660046111a6565b610648565b61024a6102ec3660046111a6565b61066d565b61020260025481565b61020260045481565b6102027f9a04aea0a349253cc7277afafdf6ead6729a3972a47ffb40eaef2c93d4e1bfea81565b6102706103383660046111c9565b6106c6565b6101c661034b3660046111a6565b60009182526020828152604080842073ffffffffffffffffffffffffffffffffffffffff93909316845291905290205460ff1690565b610202610e1081565b6102026201518081565b610202600081565b61024a6103aa36600461118d565b6106e5565b610202620f424081565b6102026103c736600461118d565b610791565b6102027f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f5581565b61024a6104013660046111a6565b6107a8565b6102027f60044782a422109ac08a415e44260ad5d3bad63d96ebe1fac0363399642ee3f281565b61020261043b3660046111eb565b60036020526000908152604090205481565b6102027f000000000000000000000000000000000000000000000000000000000000000081565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f5a05180f0000000000000000000000000000000000000000000000000000000014806104ca57506104ca826107cd565b92915050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f556104fa81610864565b73ffffffffffffffffffffffffffffffffffffffff83166000908152600360205260408120549081900361052e5750505050565b73ffffffffffffffffffffffffffffffffffffffff8481166000818152600360209081526040808320929092558151928352928616928201929092529081018290527f244e51bc38c1452fa8aaf487bcb4bca36c2baa3a5fbdb776b1eabd8dc6d277cd9060600160405180910390a17fffffffffffffffffffffffff111111111111111111111111111111111111111273ffffffffffffffffffffffffffffffffffffffff8516016105e9576105e48382610871565b61060a565b61060a73ffffffffffffffffffffffffffffffffffffffff8516848361094c565b505b505050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f5561063b81610864565b610644826109d9565b5050565b60008281526020819052604090206001015461066381610864565b61060a8383610a5a565b73ffffffffffffffffffffffffffffffffffffffff811633146106bc576040517f6697b23200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61060c8282610a8f565b60008281526001602052604081206106de9083610abc565b9392505050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f5561070f81610864565b61271082111561074b576040517f9b569b8100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600280549083905560408051828152602081018590527f14914da2bf76024616fbe1859783fcd4dbddcb179b1f3a854949fbf920dcb957910160405180910390a1505050565b60008181526001602052604081206104ca90610ac8565b6000828152602081905260409020600101546107c381610864565b61060a8383610a8f565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f7965db0b0000000000000000000000000000000000000000000000000000000014806104ca57507f01ffc9a7000000000000000000000000000000000000000000000000000000007fffffffff000000000000000000000000000000000000000000000000000000008316146104ca565b61086e8133610ad2565b50565b804710156108b2576040517fcd7860590000000000000000000000000000000000000000000000000000000081523060048201526024015b60405180910390fd5b60008273ffffffffffffffffffffffffffffffffffffffff168260405160006040518083038185875af1925050503d806000811461090c576040519150601f19603f3d011682016040523d82523d6000602084013e610911565b606091505b505090508061060c576040517f1425ea4200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040805173ffffffffffffffffffffffffffffffffffffffff8416602482015260448082018490528251808303909101815260649091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fa9059cbb0000000000000000000000000000000000000000000000000000000017905261060c908490610b58565b610e10811015610a15576040517f0e0ea5c700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600480549082905560408051828152602081018490527f909f9078b2f6eac1d10f2aae793656c5a67511eb627ebd1d2cb1eb9c0ab94c95910160405180910390a15050565b600080610a678484610bee565b905080156106de576000848152600160205260409020610a879084610cea565b509392505050565b600080610a9c8484610d0c565b905080156106de576000848152600160205260409020610a879084610dc7565b60006106de8383610de9565b60006104ca825490565b60008281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915290205460ff16610644576040517fe2517d3f00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff82166004820152602481018390526044016108a9565b6000610b7a73ffffffffffffffffffffffffffffffffffffffff841683610e13565b90508051600014158015610b9f575080806020019051810190610b9d9190611206565b155b1561060c576040517f5274afe700000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff841660048201526024016108a9565b60008281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915281205460ff16610ce25760008381526020818152604080832073ffffffffffffffffffffffffffffffffffffffff86168452909152902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055610c803390565b73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16847f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45060016104ca565b5060006104ca565b60006106de8373ffffffffffffffffffffffffffffffffffffffff8416610e21565b60008281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915281205460ff1615610ce25760008381526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8616808552925280832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016905551339286917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a45060016104ca565b60006106de8373ffffffffffffffffffffffffffffffffffffffff8416610e68565b6000826000018281548110610e0057610e00611228565b9060005260206000200154905092915050565b60606106de83836000610f5b565b6000818152600183016020526040812054610ce2575081546001818101845560008481526020808220909301849055845484825282860190935260409020919091556104ca565b60008181526001830160205260408120548015610f51576000610e8c600183611257565b8554909150600090610ea090600190611257565b9050808214610f05576000866000018281548110610ec057610ec0611228565b9060005260206000200154905080876000018481548110610ee357610ee3611228565b6000918252602080832090910192909255918252600188019052604090208390555b8554869080610f1657610f16611291565b6001900381819060005260206000200160009055905585600101600086815260200190815260200160002060009055600193505050506104ca565b60009150506104ca565b606081471015610f99576040517fcd7860590000000000000000000000000000000000000000000000000000000081523060048201526024016108a9565b6000808573ffffffffffffffffffffffffffffffffffffffff168486604051610fc291906112c0565b60006040518083038185875af1925050503d8060008114610fff576040519150601f19603f3d011682016040523d82523d6000602084013e611004565b606091505b509150915061101486838361101e565b9695505050505050565b6060826110335761102e826110ad565b6106de565b8151158015611057575073ffffffffffffffffffffffffffffffffffffffff84163b155b156110a6576040517f9996b31500000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff851660048201526024016108a9565b50806106de565b8051156110bd5780518082602001fd5b6040517f1425ea4200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006020828403121561110157600080fd5b81357fffffffff00000000000000000000000000000000000000000000000000000000811681146106de57600080fd5b803573ffffffffffffffffffffffffffffffffffffffff8116811461115557600080fd5b919050565b6000806040838503121561116d57600080fd5b61117683611131565b915061118460208401611131565b90509250929050565b60006020828403121561119f57600080fd5b5035919050565b600080604083850312156111b957600080fd5b8235915061118460208401611131565b600080604083850312156111dc57600080fd5b50508035926020909101359150565b6000602082840312156111fd57600080fd5b6106de82611131565b60006020828403121561121857600080fd5b815180151581146106de57600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b818103818111156104ca577f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fd5b6000825160005b818110156112e157602081860181015185830152016112c7565b50600092019182525091905056fea264697066735822122079d04eeec7c857b32065468d4b56344ced14fdee358cfecc2cfd327dbced278e64736f6c63430008180033","runtime-code":"0x608060405234801561001057600080fd5b50600436106101ae5760003560e01c80639010d07c116100ee578063bf333f2c11610097578063d547741f11610071578063d547741f146103f3578063dc9a4ef614610406578063dcf844a71461042d578063e00a83e01461044d57600080fd5b8063bf333f2c146103af578063ca15c873146103b9578063ccc57490146103cc57600080fd5b8063930ac180116100c8578063930ac1801461038a578063a217fddf14610394578063b13aa2d61461039c57600080fd5b80639010d07c1461032a57806391d148541461033d578063922b74871461038157600080fd5b80631ea327c51161015b57806336568abe1161013557806336568abe146102de57806358f85880146102f1578063638a0f09146102fa5780637ebe815c1461030357600080fd5b80631ea327c514610295578063248a9ca3146102a85780632f2ff15d146102cb57600080fd5b806306f333f21161018c57806306f333f2146102375780630f5f6ed71461024c5780630f862f1e1461025557600080fd5b806301ffc9a7146101b357806302d2ff66146101db57806303ed0ee514610210575b600080fd5b6101c66101c13660046110ef565b610474565b60405190151581526020015b60405180910390f35b6102027febfdca8e46c0b8dacf9989ee613e35727eadd20a1d5e5ad01a53968c7e5fe07a81565b6040519081526020016101d2565b6102027f043c983c49d46f0e102151eaf8085d4a2e6571d5df2d47b013f39bddfd4a639d81565b61024a61024536600461115a565b6104d0565b005b61020261271081565b61027073eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee81565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016101d2565b61024a6102a336600461118d565b610611565b6102026102b636600461118d565b60009081526020819052604090206001015490565b61024a6102d93660046111a6565b610648565b61024a6102ec3660046111a6565b61066d565b61020260025481565b61020260045481565b6102027f9a04aea0a349253cc7277afafdf6ead6729a3972a47ffb40eaef2c93d4e1bfea81565b6102706103383660046111c9565b6106c6565b6101c661034b3660046111a6565b60009182526020828152604080842073ffffffffffffffffffffffffffffffffffffffff93909316845291905290205460ff1690565b610202610e1081565b6102026201518081565b610202600081565b61024a6103aa36600461118d565b6106e5565b610202620f424081565b6102026103c736600461118d565b610791565b6102027f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f5581565b61024a6104013660046111a6565b6107a8565b6102027f60044782a422109ac08a415e44260ad5d3bad63d96ebe1fac0363399642ee3f281565b61020261043b3660046111eb565b60036020526000908152604090205481565b6102027f000000000000000000000000000000000000000000000000000000000000000081565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f5a05180f0000000000000000000000000000000000000000000000000000000014806104ca57506104ca826107cd565b92915050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f556104fa81610864565b73ffffffffffffffffffffffffffffffffffffffff83166000908152600360205260408120549081900361052e5750505050565b73ffffffffffffffffffffffffffffffffffffffff8481166000818152600360209081526040808320929092558151928352928616928201929092529081018290527f244e51bc38c1452fa8aaf487bcb4bca36c2baa3a5fbdb776b1eabd8dc6d277cd9060600160405180910390a17fffffffffffffffffffffffff111111111111111111111111111111111111111273ffffffffffffffffffffffffffffffffffffffff8516016105e9576105e48382610871565b61060a565b61060a73ffffffffffffffffffffffffffffffffffffffff8516848361094c565b505b505050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f5561063b81610864565b610644826109d9565b5050565b60008281526020819052604090206001015461066381610864565b61060a8383610a5a565b73ffffffffffffffffffffffffffffffffffffffff811633146106bc576040517f6697b23200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61060c8282610a8f565b60008281526001602052604081206106de9083610abc565b9392505050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f5561070f81610864565b61271082111561074b576040517f9b569b8100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600280549083905560408051828152602081018590527f14914da2bf76024616fbe1859783fcd4dbddcb179b1f3a854949fbf920dcb957910160405180910390a1505050565b60008181526001602052604081206104ca90610ac8565b6000828152602081905260409020600101546107c381610864565b61060a8383610a8f565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f7965db0b0000000000000000000000000000000000000000000000000000000014806104ca57507f01ffc9a7000000000000000000000000000000000000000000000000000000007fffffffff000000000000000000000000000000000000000000000000000000008316146104ca565b61086e8133610ad2565b50565b804710156108b2576040517fcd7860590000000000000000000000000000000000000000000000000000000081523060048201526024015b60405180910390fd5b60008273ffffffffffffffffffffffffffffffffffffffff168260405160006040518083038185875af1925050503d806000811461090c576040519150601f19603f3d011682016040523d82523d6000602084013e610911565b606091505b505090508061060c576040517f1425ea4200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040805173ffffffffffffffffffffffffffffffffffffffff8416602482015260448082018490528251808303909101815260649091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fa9059cbb0000000000000000000000000000000000000000000000000000000017905261060c908490610b58565b610e10811015610a15576040517f0e0ea5c700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600480549082905560408051828152602081018490527f909f9078b2f6eac1d10f2aae793656c5a67511eb627ebd1d2cb1eb9c0ab94c95910160405180910390a15050565b600080610a678484610bee565b905080156106de576000848152600160205260409020610a879084610cea565b509392505050565b600080610a9c8484610d0c565b905080156106de576000848152600160205260409020610a879084610dc7565b60006106de8383610de9565b60006104ca825490565b60008281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915290205460ff16610644576040517fe2517d3f00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff82166004820152602481018390526044016108a9565b6000610b7a73ffffffffffffffffffffffffffffffffffffffff841683610e13565b90508051600014158015610b9f575080806020019051810190610b9d9190611206565b155b1561060c576040517f5274afe700000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff841660048201526024016108a9565b60008281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915281205460ff16610ce25760008381526020818152604080832073ffffffffffffffffffffffffffffffffffffffff86168452909152902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055610c803390565b73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16847f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45060016104ca565b5060006104ca565b60006106de8373ffffffffffffffffffffffffffffffffffffffff8416610e21565b60008281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915281205460ff1615610ce25760008381526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8616808552925280832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016905551339286917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a45060016104ca565b60006106de8373ffffffffffffffffffffffffffffffffffffffff8416610e68565b6000826000018281548110610e0057610e00611228565b9060005260206000200154905092915050565b60606106de83836000610f5b565b6000818152600183016020526040812054610ce2575081546001818101845560008481526020808220909301849055845484825282860190935260409020919091556104ca565b60008181526001830160205260408120548015610f51576000610e8c600183611257565b8554909150600090610ea090600190611257565b9050808214610f05576000866000018281548110610ec057610ec0611228565b9060005260206000200154905080876000018481548110610ee357610ee3611228565b6000918252602080832090910192909255918252600188019052604090208390555b8554869080610f1657610f16611291565b6001900381819060005260206000200160009055905585600101600086815260200190815260200160002060009055600193505050506104ca565b60009150506104ca565b606081471015610f99576040517fcd7860590000000000000000000000000000000000000000000000000000000081523060048201526024016108a9565b6000808573ffffffffffffffffffffffffffffffffffffffff168486604051610fc291906112c0565b60006040518083038185875af1925050503d8060008114610fff576040519150601f19603f3d011682016040523d82523d6000602084013e611004565b606091505b509150915061101486838361101e565b9695505050505050565b6060826110335761102e826110ad565b6106de565b8151158015611057575073ffffffffffffffffffffffffffffffffffffffff84163b155b156110a6576040517f9996b31500000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff851660048201526024016108a9565b50806106de565b8051156110bd5780518082602001fd5b6040517f1425ea4200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006020828403121561110157600080fd5b81357fffffffff00000000000000000000000000000000000000000000000000000000811681146106de57600080fd5b803573ffffffffffffffffffffffffffffffffffffffff8116811461115557600080fd5b919050565b6000806040838503121561116d57600080fd5b61117683611131565b915061118460208401611131565b90509250929050565b60006020828403121561119f57600080fd5b5035919050565b600080604083850312156111b957600080fd5b8235915061118460208401611131565b600080604083850312156111dc57600080fd5b50508035926020909101359150565b6000602082840312156111fd57600080fd5b6106de82611131565b60006020828403121561121857600080fd5b815180151581146106de57600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b818103818111156104ca577f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fd5b6000825160005b818110156112e157602081860181015185830152016112c7565b50600092019182525091905056fea264697066735822122079d04eeec7c857b32065468d4b56344ced14fdee358cfecc2cfd327dbced278e64736f6c63430008180033","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.24 ^0.8.20 ^0.8.4;\n\n// contracts/interfaces/IAdminV2.sol\n\ninterface IAdminV2 {\n event CancelDelayUpdated(uint256 oldCancelDelay, uint256 newCancelDelay);\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n function setCancelDelay(uint256 newCancelDelay) external;\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n}\n\n// contracts/interfaces/IAdminV2Errors.sol\n\ninterface IAdminV2Errors {\n error CancelDelayBelowMin();\n error FeeRateAboveMax();\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IFastBridgeV2Errors.sol\n\ninterface IFastBridgeV2Errors {\n error AmountIncorrect();\n error ChainIncorrect();\n error ExclusivityParamsIncorrect();\n error MsgValueIncorrect();\n error SenderIncorrect();\n error StatusIncorrect();\n error TokenNotContract();\n error ZapDataLengthAboveMax();\n error ZapNativeNotSupported();\n error ZeroAddress();\n\n error RecipientIncorrectReturnValue();\n error RecipientNoReturnValue();\n\n error DeadlineExceeded();\n error DeadlineNotExceeded();\n error DeadlineTooShort();\n error DisputePeriodNotPassed();\n error DisputePeriodPassed();\n error ExclusivityPeriodNotPassed();\n\n error TransactionRelayed();\n}\n\n// contracts/interfaces/IMulticallTarget.sol\n\n/// @notice Interface for a contract that can be called multiple times by the same caller. Inspired by MulticallV3:\n/// https://github.com/mds1/multicall/blob/master/src/Multicall3.sol\ninterface IMulticallTarget {\n struct Result {\n bool success;\n bytes returnData;\n }\n\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external;\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results);\n}\n\n// contracts/interfaces/IZapRecipient.sol\n\ninterface IZapRecipient {\n function zap(address token, uint256 amount, bytes memory zapData) external payable returns (bytes4);\n}\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// contracts/interfaces/IFastBridgeV2.sol\n\ninterface IFastBridgeV2 is IFastBridge {\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n struct BridgeTxDetails {\n BridgeStatus status;\n uint32 destChainId;\n uint56 proofBlockTimestamp;\n address proofRelayer;\n }\n\n struct BridgeRelay {\n uint48 blockNumber;\n uint48 blockTimestamp;\n address relayer;\n }\n\n /// @notice New params introduced in the FastBridgeV2.\n /// We are passing fields from the older BridgeParams struct outside of this struct\n /// for backwards compatibility.\n /// Note: quoteRelayer and quoteExclusivitySeconds are either both zero (indicating no exclusivity)\n /// or both non-zero (indicating exclusivity for the given period).\n /// Note: zapNative \u003e 0 can NOT be used with destToken = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE (native token)\n /// @param quoteRelayer Relayer that provided the quote for the transaction\n /// @param quoteExclusivitySeconds Period of time the quote relayer is guaranteed exclusivity after user's deposit\n /// @param quoteId Unique quote identifier used for tracking the quote\n /// @param zapNative ETH value to send to the recipient (if any)\n /// @param zapData Parameters for the Zap to the destination recipient (if any)\n struct BridgeParamsV2 {\n address quoteRelayer;\n int256 quoteExclusivitySeconds;\n bytes quoteId;\n uint256 zapNative;\n bytes zapData;\n }\n\n /// @notice Updated bridge transaction struct to include parameters introduced in FastBridgeV2.\n /// Note: only `exclusivityRelayer` can fill such a transaction until `exclusivityEndTime`.\n struct BridgeTransactionV2 {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n // Note: sendChainGas flag from V1 is deprecated\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n address exclusivityRelayer;\n uint256 exclusivityEndTime;\n uint256 zapNative; // ETH value to send to the recipient (if any)\n bytes zapData; // data to pass for the Zap action (if any)\n }\n\n event BridgeQuoteDetails(bytes32 indexed transactionId, bytes quoteId);\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability\n /// to provide temporary exclusivity fill rights for the quote relayer.\n /// @param params The parameters required to bridge\n /// @param paramsV2 The parameters for exclusivity fill rights (optional, can be left empty)\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function relay(bytes memory request, address relayer) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param transactionId The transaction id associated with the encoded bridge transaction to prove\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital.\n /// @notice Can only send funds to the relayer address on the proof.\n /// @param request The encoded bridge transaction to claim on origin chain\n function claim(bytes memory request) external;\n\n /// @notice Cancels an outstanding bridge transaction in case optimistic bridging failed and returns the full amount\n /// to the original sender.\n /// @param request The encoded bridge transaction to refund\n function cancel(bytes memory request) external;\n\n /// @notice Checks if a transaction has been relayed\n /// @param transactionId The ID of the transaction to check\n /// @return True if the transaction has been relayed, false otherwise\n function bridgeRelays(bytes32 transactionId) external view returns (bool);\n\n /// @notice Returns the status of a bridge transaction\n /// @param transactionId The ID of the bridge transaction\n /// @return BridgeStatus Status of the bridge transaction\n function bridgeStatuses(bytes32 transactionId) external view returns (BridgeStatus);\n\n /// @notice Returns the timestamp and relayer of a bridge proof\n /// @param transactionId The ID of the bridge transaction\n /// @return timestamp The timestamp of the bridge proof\n /// @return relayer The relayer address of the bridge proof\n function bridgeProofs(bytes32 transactionId) external view returns (uint96 timestamp, address relayer);\n\n /// @notice Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\n /// @param request The bridge request to decode\n function getBridgeTransactionV2(bytes memory request) external view returns (BridgeTransactionV2 memory);\n}\n\n// contracts/utils/MulticallTarget.sol\n\n// solhint-disable avoid-low-level-calls\n/// @notice Template for a contract that supports batched calls (preserving the msg.sender).\n/// Only calls with zero msg.value could be batched.\nabstract contract MulticallTarget is IMulticallTarget {\n error MulticallTarget__UndeterminedRevert();\n\n /// @notice Perform a batched call to this contract, preserving the msg.sender.\n /// The return data from each call is discarded.\n /// @dev The method is non-payable, so only calls with `msg.value == 0` could be batched.\n /// It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag.\n /// Otherwise, the whole batch call will be reverted with the original revert reason.\n /// @param data List of abi-encoded calldata for the calls to perform.\n /// @param ignoreReverts Whether to ignore the revert errors from the calls.\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external {\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\n if (!success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(result);\n }\n }\n }\n\n /// @notice Perform a batched call to this contract, preserving the msg.sender.\n /// The return data from each call is preserved.\n /// @dev The method is non-payable, so only calls with `msg.value == 0` could be batched.\n /// It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag.\n /// Otherwise, the whole batch call will be reverted with the original revert reason.\n /// @param data List of abi-encoded calldata for the calls to perform.\n /// @param ignoreReverts Whether to ignore the revert errors from the calls.\n /// @return results List of results from the calls: `(success, returnData)`.\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results)\n {\n results = new Result[](data.length);\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (results[i].success, results[i].returnData) = address(this).delegatecall(data[i]);\n if (!results[i].success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(results[i].returnData);\n }\n }\n }\n\n /// @dev Bubbles the revert message from the underlying call.\n /// Note: preserves the same custom error or revert string, if one was used.\n /// Source: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v5.0.2/contracts/utils/Address.sol#L143-L158\n function _bubbleRevert(bytes memory returnData) internal pure {\n // Look for revert reason and bubble it up if present\n if (returnData.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n // solhint-disable-next-line no-inline-assembly\n assembly {\n let returndata_size := mload(returnData)\n revert(add(32, returnData), returndata_size)\n }\n } else {\n revert MulticallTarget__UndeterminedRevert();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// contracts/libs/BridgeTransactionV2.sol\n\n// solhint-disable no-inline-assembly\nlibrary BridgeTransactionV2Lib {\n uint16 internal constant VERSION = 2;\n\n // Offsets of the fields in the packed BridgeTransactionV2 struct\n // uint16 version [000 .. 002)\n // uint32 originChainId [002 .. 006)\n // uint32 destChainId [006 .. 010)\n // address originSender [010 .. 030)\n // address destRecipient [030 .. 050)\n // address originToken [050 .. 070)\n // address destToken [070 .. 090)\n // uint256 originAmount [090 .. 122)\n // uint256 destAmount [122 .. 154)\n // uint256 originFeeAmount [154 .. 186)\n // uint256 deadline [186 .. 218)\n // uint256 nonce [218 .. 250)\n // address exclusivityRelayer [250 .. 270)\n // uint256 exclusivityEndTime [270 .. 302)\n // uint256 zapNative [302 .. 334)\n // bytes zapData [334 .. ***)\n\n // forgefmt: disable-start\n uint256 private constant OFFSET_ORIGIN_CHAIN_ID = 2;\n uint256 private constant OFFSET_DEST_CHAIN_ID = 6;\n uint256 private constant OFFSET_ORIGIN_SENDER = 10;\n uint256 private constant OFFSET_DEST_RECIPIENT = 30;\n uint256 private constant OFFSET_ORIGIN_TOKEN = 50;\n uint256 private constant OFFSET_DEST_TOKEN = 70;\n uint256 private constant OFFSET_ORIGIN_AMOUNT = 90;\n uint256 private constant OFFSET_DEST_AMOUNT = 122;\n uint256 private constant OFFSET_ORIGIN_FEE_AMOUNT = 154;\n uint256 private constant OFFSET_DEADLINE = 186;\n uint256 private constant OFFSET_NONCE = 218;\n uint256 private constant OFFSET_EXCLUSIVITY_RELAYER = 250;\n uint256 private constant OFFSET_EXCLUSIVITY_END_TIME = 270;\n uint256 private constant OFFSET_ZAP_NATIVE = 302;\n uint256 private constant OFFSET_ZAP_DATA = 334;\n // forgefmt: disable-end\n\n error BridgeTransactionV2__InvalidEncodedTx();\n error BridgeTransactionV2__UnsupportedVersion(uint16 version);\n\n /// @notice Validates the encoded transaction to be a tightly packed encoded payload for BridgeTransactionV2.\n /// @dev Checks the minimum length and the version, use this function before decoding any of the fields.\n function validateV2(bytes calldata encodedTx) internal pure {\n // Check the minimum length: must at least include all static fields.\n if (encodedTx.length \u003c OFFSET_ZAP_DATA) revert BridgeTransactionV2__InvalidEncodedTx();\n // Once we validated the length, we can be sure that the version field is present.\n uint16 version_ = version(encodedTx);\n if (version_ != VERSION) revert BridgeTransactionV2__UnsupportedVersion(version_);\n }\n\n /// @notice Encodes the BridgeTransactionV2 struct by tightly packing the fields.\n /// @dev `abi.decode` will not work as a result of the tightly packed fields. Use `decodeV2` to decode instead.\n function encodeV2(IFastBridgeV2.BridgeTransactionV2 memory bridgeTx) internal pure returns (bytes memory) {\n // We split the encoding into two parts to avoid stack-too-deep error\n bytes memory firstPart = abi.encodePacked(\n VERSION,\n bridgeTx.originChainId,\n bridgeTx.destChainId,\n bridgeTx.originSender,\n bridgeTx.destRecipient,\n bridgeTx.originToken,\n bridgeTx.destToken,\n bridgeTx.originAmount\n );\n return abi.encodePacked(\n firstPart,\n bridgeTx.destAmount,\n bridgeTx.originFeeAmount,\n // Note: we skip the deprecated `sendChainGas` flag, which was present in BridgeTransaction V1\n bridgeTx.deadline,\n bridgeTx.nonce,\n // New V2 fields: exclusivity\n bridgeTx.exclusivityRelayer,\n bridgeTx.exclusivityEndTime,\n // New V2 fields: Zap\n bridgeTx.zapNative,\n bridgeTx.zapData\n );\n }\n\n /// @notice Decodes the BridgeTransactionV2 struct from the encoded transaction.\n /// @dev Encoded BridgeTransactionV2 struct must be tightly packed.\n /// Use `validateV2` before decoding to ensure the encoded transaction is valid.\n function decodeV2(bytes calldata encodedTx)\n internal\n pure\n returns (IFastBridgeV2.BridgeTransactionV2 memory bridgeTx)\n {\n bridgeTx.originChainId = originChainId(encodedTx);\n bridgeTx.destChainId = destChainId(encodedTx);\n bridgeTx.originSender = originSender(encodedTx);\n bridgeTx.destRecipient = destRecipient(encodedTx);\n bridgeTx.originToken = originToken(encodedTx);\n bridgeTx.destToken = destToken(encodedTx);\n bridgeTx.originAmount = originAmount(encodedTx);\n bridgeTx.destAmount = destAmount(encodedTx);\n bridgeTx.originFeeAmount = originFeeAmount(encodedTx);\n bridgeTx.deadline = deadline(encodedTx);\n bridgeTx.nonce = nonce(encodedTx);\n bridgeTx.exclusivityRelayer = exclusivityRelayer(encodedTx);\n bridgeTx.exclusivityEndTime = exclusivityEndTime(encodedTx);\n bridgeTx.zapNative = zapNative(encodedTx);\n bridgeTx.zapData = zapData(encodedTx);\n }\n\n /// @notice Extracts the version from the encoded transaction.\n function version(bytes calldata encodedTx) internal pure returns (uint16 version_) {\n // Load 32 bytes from the start and shift it 240 bits to the right to get the highest 16 bits.\n assembly {\n version_ := shr(240, calldataload(encodedTx.offset))\n }\n }\n\n /// @notice Extracts the origin chain ID from the encoded transaction.\n function originChainId(bytes calldata encodedTx) internal pure returns (uint32 originChainId_) {\n // Load 32 bytes from the offset and shift it 224 bits to the right to get the highest 32 bits.\n assembly {\n originChainId_ := shr(224, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_CHAIN_ID)))\n }\n }\n\n /// @notice Extracts the destination chain ID from the encoded transaction.\n function destChainId(bytes calldata encodedTx) internal pure returns (uint32 destChainId_) {\n // Load 32 bytes from the offset and shift it 224 bits to the right to get the highest 32 bits.\n assembly {\n destChainId_ := shr(224, calldataload(add(encodedTx.offset, OFFSET_DEST_CHAIN_ID)))\n }\n }\n\n /// @notice Extracts the origin sender from the encoded transaction.\n function originSender(bytes calldata encodedTx) internal pure returns (address originSender_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n originSender_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_SENDER)))\n }\n }\n\n /// @notice Extracts the destination recipient from the encoded transaction.\n function destRecipient(bytes calldata encodedTx) internal pure returns (address destRecipient_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n destRecipient_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_DEST_RECIPIENT)))\n }\n }\n\n /// @notice Extracts the origin token from the encoded transaction.\n function originToken(bytes calldata encodedTx) internal pure returns (address originToken_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n originToken_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_TOKEN)))\n }\n }\n\n /// @notice Extracts the destination token from the encoded transaction.\n function destToken(bytes calldata encodedTx) internal pure returns (address destToken_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n destToken_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_DEST_TOKEN)))\n }\n }\n\n /// @notice Extracts the origin amount from the encoded transaction.\n function originAmount(bytes calldata encodedTx) internal pure returns (uint256 originAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n originAmount_ := calldataload(add(encodedTx.offset, OFFSET_ORIGIN_AMOUNT))\n }\n }\n\n /// @notice Extracts the destination amount from the encoded transaction.\n function destAmount(bytes calldata encodedTx) internal pure returns (uint256 destAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n destAmount_ := calldataload(add(encodedTx.offset, OFFSET_DEST_AMOUNT))\n }\n }\n\n /// @notice Extracts the origin fee amount from the encoded transaction.\n function originFeeAmount(bytes calldata encodedTx) internal pure returns (uint256 originFeeAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n originFeeAmount_ := calldataload(add(encodedTx.offset, OFFSET_ORIGIN_FEE_AMOUNT))\n }\n }\n\n /// @notice Extracts the deadline from the encoded transaction.\n function deadline(bytes calldata encodedTx) internal pure returns (uint256 deadline_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n deadline_ := calldataload(add(encodedTx.offset, OFFSET_DEADLINE))\n }\n }\n\n /// @notice Extracts the nonce from the encoded transaction.\n function nonce(bytes calldata encodedTx) internal pure returns (uint256 nonce_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n nonce_ := calldataload(add(encodedTx.offset, OFFSET_NONCE))\n }\n }\n\n /// @notice Extracts the exclusivity relayer from the encoded transaction.\n function exclusivityRelayer(bytes calldata encodedTx) internal pure returns (address exclusivityRelayer_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n exclusivityRelayer_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_EXCLUSIVITY_RELAYER)))\n }\n }\n\n /// @notice Extracts the exclusivity end time from the encoded transaction.\n function exclusivityEndTime(bytes calldata encodedTx) internal pure returns (uint256 exclusivityEndTime_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n exclusivityEndTime_ := calldataload(add(encodedTx.offset, OFFSET_EXCLUSIVITY_END_TIME))\n }\n }\n\n /// @notice Extracts the Zap's native value from the encoded transaction.\n function zapNative(bytes calldata encodedTx) internal pure returns (uint256 zapNative_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n zapNative_ := calldataload(add(encodedTx.offset, OFFSET_ZAP_NATIVE))\n }\n }\n\n /// @notice Extracts the Zap's data from the encoded transaction.\n function zapData(bytes calldata encodedTx) internal pure returns (bytes calldata zapData_) {\n zapData_ = encodedTx[OFFSET_ZAP_DATA:];\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/AdminV2.sol\n\ncontract AdminV2 is AccessControlEnumerable, IAdminV2, IAdminV2Errors {\n using SafeERC20 for IERC20;\n\n /// @notice Address reserved for native gas token (ETH on Ethereum and most L2s, AVAX on Avalanche, etc)\n address public constant NATIVE_GAS_TOKEN = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Role identifier for Quoter API's off-chain authentication.\n /// @dev Only addresses with this role can post FastBridge quotes to the API.\n bytes32 public constant QUOTER_ROLE = keccak256(\"QUOTER_ROLE\");\n\n /// @notice Role identifier for Prover's on-chain authentication in FastBridge.\n /// @dev Only addresses with this role can provide proofs that a FastBridge request has been relayed.\n bytes32 public constant PROVER_ROLE = keccak256(\"PROVER_ROLE\");\n\n /// @notice Role identifier for Guard's on-chain authentication in FastBridge.\n /// @dev Only addresses with this role can dispute submitted relay proofs during the dispute period.\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n\n /// @notice Role identifier for Canceler's on-chain authentication in FastBridge.\n /// @dev Only addresses with this role can cancel a FastBridge transaction without the cancel delay.\n bytes32 public constant CANCELER_ROLE = keccak256(\"CANCELER_ROLE\");\n\n /// @notice Role identifier for Governor's on-chain administrative authority.\n /// @dev Only addresses with this role can perform administrative tasks within the contract.\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n /// @notice Denominator for fee rates, represents 100%.\n uint256 public constant FEE_BPS = 1e6;\n /// @notice Maximum protocol fee rate: 1% on origin amount.\n uint256 public constant FEE_RATE_MAX = 0.01e6;\n\n /// @notice Minimum cancel delay that can be set by the governor.\n uint256 public constant MIN_CANCEL_DELAY = 1 hours;\n /// @notice Default cancel delay set during the contract deployment.\n uint256 public constant DEFAULT_CANCEL_DELAY = 1 days;\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Delay for a transaction after which it could be permisionlessly cancelled\n uint256 public cancelDelay;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Use ZapNative V2 requests instead.\n uint256 public immutable chainGasAmount = 0;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n _setCancelDelay(DEFAULT_CANCEL_DELAY);\n }\n\n /// @notice Allows the contract governor to set the cancel delay. The cancel delay is the time after the transaction\n /// deadline after which it can be permissionlessly cancelled, if it hasn't been proven by any of the Relayers.\n function setCancelDelay(uint256 newCancelDelay) external onlyRole(GOVERNOR_ROLE) {\n _setCancelDelay(newCancelDelay);\n }\n\n /// @notice Allows the contract governor to set the protocol fee rate. The protocol fee is taken from the origin\n /// amount only for completed and claimed transactions.\n /// @dev The protocol fee is abstracted away from the relayers, they always operate using the amounts after fees:\n /// what they see as the origin amount emitted in the log is what they get credited with.\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n if (newFeeRate \u003e FEE_RATE_MAX) revert FeeRateAboveMax();\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n /// @notice Allows the contract governor to sweep the accumulated protocol fees in the contract.\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n emit FeesSwept(token, recipient, feeAmount);\n /// Sweep the fees as the last transaction action\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(recipient), feeAmount);\n } else {\n IERC20(token).safeTransfer(recipient, feeAmount);\n }\n }\n\n /// @notice Internal function to set the cancel delay. Security checks are performed outside of this function.\n function _setCancelDelay(uint256 newCancelDelay) private {\n if (newCancelDelay \u003c MIN_CANCEL_DELAY) revert CancelDelayBelowMin();\n uint256 oldCancelDelay = cancelDelay;\n cancelDelay = newCancelDelay;\n emit CancelDelayUpdated(oldCancelDelay, newCancelDelay);\n }\n}\n\n// contracts/FastBridgeV2.sol\n\n/// @notice FastBridgeV2 is a contract for bridging tokens across chains.\ncontract FastBridgeV2 is AdminV2, MulticallTarget, IFastBridgeV2, IFastBridgeV2Errors {\n using BridgeTransactionV2Lib for bytes;\n using SafeERC20 for IERC20;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n /// @notice Maximum length of accepted zapData\n uint256 public constant MAX_ZAP_DATA_LENGTH = 2 ** 16 - 1;\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeTxDetails) public bridgeTxDetails;\n /// @notice Relay details on destination chain\n mapping(bytes32 =\u003e BridgeRelay) public bridgeRelayDetails;\n /// @notice Unique bridge nonces tracked per originSender\n mapping(address =\u003e uint256) public senderNonces;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Replaced by senderNonces\n uint256 public immutable nonce = 0;\n /// @notice the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) AdminV2(_owner) {\n deployBlock = block.number;\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n bridge({\n params: params,\n paramsV2: BridgeParamsV2({\n quoteRelayer: address(0),\n quoteExclusivitySeconds: 0,\n quoteId: bytes(\"\"),\n zapNative: 0,\n zapData: bytes(\"\")\n })\n });\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes calldata request) external payable {\n // relay override will validate the request\n relay({request: request, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes calldata request, bytes32 destTxHash) external {\n request.validateV2();\n prove({transactionId: keccak256(request), destTxHash: destTxHash, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridgeV2\n function claim(bytes calldata request) external {\n // claim override will validate the request\n claim({request: request, to: address(0)});\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Aggregate the read operations from the same storage slot\n address disputedRelayer = $.proofRelayer;\n BridgeStatus status = $.status;\n uint56 proofBlockTimestamp = $.proofBlockTimestamp;\n // Can only dispute a RELAYER_PROVED transaction within the dispute period\n if (status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(proofBlockTimestamp) \u003e DISPUTE_PERIOD) {\n revert DisputePeriodPassed();\n }\n // Update status to REQUESTED and delete the disputed proof details\n // Note: these are storage writes\n $.status = BridgeStatus.REQUESTED;\n $.proofRelayer = address(0);\n $.proofBlockTimestamp = 0;\n\n emit BridgeProofDisputed(transactionId, disputedRelayer);\n }\n\n /// Note: this function is deprecated and will be removed in a future version.\n /// @inheritdoc IFastBridge\n function refund(bytes calldata request) external {\n cancel(request);\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // The correct relayer can only claim a RELAYER_PROVED transaction after the dispute period\n if ($.status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if ($.proofRelayer != relayer) revert SenderIncorrect();\n return _timeSince($.proofBlockTimestamp) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n /// @dev This method is added to achieve backwards compatibility with decoding requests into V1 structs:\n /// - `zapNative` is partially reported as a zero/non-zero flag\n /// - `zapData` is ignored\n /// In order to process all kinds of requests use getBridgeTransactionV2 instead.\n function getBridgeTransaction(bytes calldata request) external view returns (BridgeTransaction memory) {\n // Try decoding into V2 struct first. This will revert if V1 struct is passed\n try this.getBridgeTransactionV2(request) returns (BridgeTransactionV2 memory txV2) {\n // Note: we entirely ignore the zapData field, as it was not present in V1\n return BridgeTransaction({\n originChainId: txV2.originChainId,\n destChainId: txV2.destChainId,\n originSender: txV2.originSender,\n destRecipient: txV2.destRecipient,\n originToken: txV2.originToken,\n destToken: txV2.destToken,\n originAmount: txV2.originAmount,\n destAmount: txV2.destAmount,\n originFeeAmount: txV2.originFeeAmount,\n sendChainGas: txV2.zapNative != 0,\n deadline: txV2.deadline,\n nonce: txV2.nonce\n });\n } catch {\n // Fallback to V1 struct\n return abi.decode(request, (BridgeTransaction));\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function getBridgeTransactionV2(bytes calldata request) external pure returns (BridgeTransactionV2 memory) {\n request.validateV2();\n return BridgeTransactionV2Lib.decodeV2(request);\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) public payable {\n int256 exclusivityEndTime = 0;\n // if relayer exclusivity is not intended for this bridge, set exclusivityEndTime to static zero\n // otherwise, set exclusivity to expire at the current block ts offset by quoteExclusivitySeconds\n if (paramsV2.quoteRelayer != address(0)) {\n exclusivityEndTime = int256(block.timestamp) + paramsV2.quoteExclusivitySeconds;\n }\n _validateBridgeParams(params, paramsV2, exclusivityEndTime);\n\n // transfer tokens to bridge contract\n /// @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _takeBridgedUserAsset(params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) {\n originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n }\n\n // set status to requested\n bytes memory request = BridgeTransactionV2Lib.encodeV2(\n BridgeTransactionV2({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n deadline: params.deadline,\n nonce: senderNonces[params.sender]++, // increment nonce on every bridge\n exclusivityRelayer: paramsV2.quoteRelayer,\n // We checked exclusivityEndTime to be in range [0 .. params.deadline] above, so can safely cast\n exclusivityEndTime: uint256(exclusivityEndTime),\n zapNative: paramsV2.zapNative,\n zapData: paramsV2.zapData\n })\n );\n bytes32 transactionId = keccak256(request);\n // Note: the tx status will be updated throughout the tx lifecycle, while destChainId is set once here\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n bridgeTxDetails[transactionId].destChainId = params.dstChainId;\n\n emit BridgeRequested({\n transactionId: transactionId,\n sender: params.sender,\n request: request,\n destChainId: params.dstChainId,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n sendChainGas: paramsV2.zapNative != 0\n });\n emit BridgeQuoteDetails(transactionId, paramsV2.quoteId);\n }\n\n /// @inheritdoc IFastBridgeV2\n function relay(bytes calldata request, address relayer) public payable {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n _validateRelayParams(request, transactionId, relayer);\n // mark bridge transaction as relayed\n bridgeRelayDetails[transactionId] =\n BridgeRelay({blockNumber: uint48(block.number), blockTimestamp: uint48(block.timestamp), relayer: relayer});\n\n // transfer tokens to recipient on destination chain and trigger Zap if requested\n address to = request.destRecipient();\n address token = request.destToken();\n uint256 amount = request.destAmount();\n uint256 zapNative = request.zapNative();\n\n // Emit the event before any external calls\n emit BridgeRelayed({\n transactionId: transactionId,\n relayer: relayer,\n to: to,\n originChainId: request.originChainId(),\n originToken: request.originToken(),\n destToken: token,\n originAmount: request.originAmount(),\n destAmount: amount,\n chainGasAmount: zapNative\n });\n\n // All state changes have been done at this point, can proceed to the external calls.\n // This follows the checks-effects-interactions pattern to mitigate potential reentrancy attacks.\n if (token == NATIVE_GAS_TOKEN) {\n // For the native gas token, additional zapNative is not allowed\n if (zapNative != 0) revert ZapNativeNotSupported();\n // Check that the correct msg.value was sent\n if (msg.value != amount) revert MsgValueIncorrect();\n // Don't do a native transfer yet: we will handle it alongside the Zap below\n } else {\n // For ERC20s, we check that the correct msg.value was sent\n if (msg.value != zapNative) revert MsgValueIncorrect();\n // We need to transfer the tokens from the Relayer to the recipient first before performing an\n // optional post-transfer Zap.\n IERC20(token).safeTransferFrom(msg.sender, to, amount);\n }\n // At this point we have done:\n // - Transferred the requested amount of ERC20 tokens to the recipient.\n // At this point we have confirmed:\n // - For ERC20s: msg.value matches the requested zapNative amount.\n // - For the native gas token: msg.value matches the requested destAmount.\n // Remaining optional things to do:\n // - Forward the full msg.value to the recipient (if non-zero).\n // - Trigger a Zap (if zapData is present).\n bytes calldata zapData = request.zapData();\n if (zapData.length != 0) {\n // Zap Data is present: Zap has been requested by the recipient. Trigger it forwarding the full msg.value.\n\n // Note: if token has a fee on transfers, the recipient will have received less than `amount`.\n // This is a very niche edge case and should be handled by the recipient contract.\n _triggerZapWithChecks({recipient: to, token: token, amount: amount, zapData: zapData});\n } else if (msg.value != 0) {\n // Zap Data is missing, but msg.value was sent. This could happen in two different cases:\n // - Relay with the native gas token is happening.\n // - Relay with ERC20 is happening, with a `zapNative \u003e 0` request.\n // In both cases, we need to transfer the full msg.value to the recipient.\n Address.sendValue(payable(to), msg.value);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) public onlyRole(PROVER_ROLE) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n\n // Can only prove a REQUESTED transaction\n if ($.status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n // Update status to RELAYER_PROVED and store the proof details\n // Note: these are storage writes\n $.status = BridgeStatus.RELAYER_PROVED;\n $.proofBlockTimestamp = uint56(block.timestamp);\n $.proofRelayer = relayer;\n\n emit BridgeProofProvided(transactionId, relayer, destTxHash);\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes calldata request, address to) public {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Aggregate the read operations from the same storage slot\n address proofRelayer = $.proofRelayer;\n BridgeStatus status = $.status;\n uint56 proofBlockTimestamp = $.proofBlockTimestamp;\n\n // Can only claim a RELAYER_PROVED transaction after the dispute period\n if (status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(proofBlockTimestamp) \u003c= DISPUTE_PERIOD) {\n revert DisputePeriodNotPassed();\n }\n\n if (to == address(0)) {\n // Anyone could claim the funds to the proven relayer on their behalf\n to = proofRelayer;\n } else if (proofRelayer != msg.sender) {\n // Only the proven relayer could specify an address to claim the funds to\n revert SenderIncorrect();\n }\n\n // Update status to RELAYER_CLAIMED and transfer the origin collateral to the specified claim address\n // Note: this is a storage write\n $.status = BridgeStatus.RELAYER_CLAIMED;\n\n address token = request.originToken();\n uint256 amount = request.originAmount();\n // Update protocol fees if origin fee amount exists\n uint256 originFeeAmount = request.originFeeAmount();\n if (originFeeAmount \u003e 0) protocolFees[token] += originFeeAmount;\n // Emit the event before any external calls\n emit BridgeDepositClaimed(transactionId, proofRelayer, to, token, amount);\n // Complete the relayer claim as the last transaction action\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(to), amount);\n } else {\n IERC20(token).safeTransfer(to, amount);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function cancel(bytes calldata request) public {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Can only cancel a REQUESTED transaction after its deadline expires\n if ($.status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n uint256 deadline = request.deadline();\n // Permissionless cancel is only allowed after `cancelDelay` on top of the deadline\n if (!hasRole(CANCELER_ROLE, msg.sender)) deadline += cancelDelay;\n if (block.timestamp \u003c= deadline) revert DeadlineNotExceeded();\n // Update status to REFUNDED and return the full amount (collateral + protocol fees) to the original sender.\n // The protocol fees are only updated when the transaction is claimed, so we don't need to update them here.\n // Note: this is a storage write\n $.status = BridgeStatus.REFUNDED;\n\n address to = request.originSender();\n address token = request.originToken();\n uint256 amount = request.originAmount() + request.originFeeAmount();\n // Emit the event before any external calls\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n // Complete the user cancel as the last transaction action\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(to), amount);\n } else {\n IERC20(token).safeTransfer(to, amount);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeStatuses(bytes32 transactionId) public view returns (BridgeStatus status) {\n return bridgeTxDetails[transactionId].status;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeProofs(bytes32 transactionId) public view returns (uint96 timestamp, address relayer) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n\n timestamp = $.proofBlockTimestamp;\n relayer = $.proofRelayer;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeRelays(bytes32 transactionId) public view returns (bool) {\n // has this transactionId been relayed?\n return bridgeRelayDetails[transactionId].relayer != address(0);\n }\n\n /// @notice Takes the bridged asset from the user into FastBridgeV2 custody. It will be later\n /// claimed by the relayer who completed the relay on destination chain, or transferred back to the user\n /// via the cancel function should no one complete the relay.\n function _takeBridgedUserAsset(address token, uint256 amount) internal returns (uint256 amountTaken) {\n if (token == NATIVE_GAS_TOKEN) {\n // For the native gas token, we just need to check that the supplied msg.value is correct.\n // Supplied `msg.value` is already in FastBridgeV2 custody.\n if (amount != msg.value) revert MsgValueIncorrect();\n amountTaken = msg.value;\n } else {\n // For ERC20s, token is explicitly transferred from the user to FastBridgeV2.\n // We don't allow non-zero `msg.value` to avoid extra funds from being stuck in FastBridgeV2.\n if (msg.value != 0) revert MsgValueIncorrect();\n // Throw an explicit error if the provided token address is not a contract\n if (token.code.length == 0) revert TokenNotContract();\n amountTaken = IERC20(token).balanceOf(address(this));\n IERC20(token).safeTransferFrom(msg.sender, address(this), amount);\n // Use the balance difference as the amount taken in case of fee on transfer tokens.\n amountTaken = IERC20(token).balanceOf(address(this)) - amountTaken;\n }\n }\n\n /// @notice Calls the Recipient's hook function with the specified zapData and performs\n /// all the necessary checks for the returned value.\n function _triggerZapWithChecks(address recipient, address token, uint256 amount, bytes calldata zapData) internal {\n // This will bubble any revert messages from the hook function\n bytes memory returnData = Address.functionCallWithValue({\n target: recipient,\n data: abi.encodeCall(IZapRecipient.zap, (token, amount, zapData)),\n // Note: see `relay()` for reasoning behind passing msg.value\n value: msg.value\n });\n // Explicit revert if no return data at all\n if (returnData.length == 0) revert RecipientNoReturnValue();\n // Check that exactly a single return value was returned\n if (returnData.length != 32) revert RecipientIncorrectReturnValue();\n // Return value should be abi-encoded hook function selector\n if (bytes32(returnData) != bytes32(IZapRecipient.zap.selector)) {\n revert RecipientIncorrectReturnValue();\n }\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint56(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint56).max but\n /// proof.timestamp \u003c type(uint56).max via unchecked statement\n /// @param proofBlockTimestamp The bridge proof block timestamp\n /// @return delta Time delta since proof submitted\n function _timeSince(uint56 proofBlockTimestamp) internal view returns (uint256 delta) {\n unchecked {\n delta = uint56(block.timestamp) - proofBlockTimestamp;\n }\n }\n\n /// @notice Performs all the necessary checks for a bridge to happen.\n /// @dev There's no good way to refactor this function to reduce cyclomatic complexity due to\n /// the number of checks that need to be performed, so we skip the code-complexity rule here.\n // solhint-disable-next-line code-complexity\n function _validateBridgeParams(\n BridgeParams memory params,\n BridgeParamsV2 memory paramsV2,\n int256 exclusivityEndTime\n )\n internal\n view\n {\n // Check V1 (legacy) params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.sender == address(0) || params.to == address(0)) revert ZeroAddress();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n // Check V2 params\n if (paramsV2.zapData.length \u003e MAX_ZAP_DATA_LENGTH) revert ZapDataLengthAboveMax();\n if (paramsV2.zapNative != 0 \u0026\u0026 params.destToken == NATIVE_GAS_TOKEN) {\n revert ZapNativeNotSupported();\n }\n // exclusivityEndTime must be in range [0 .. params.deadline]\n if (exclusivityEndTime \u003c 0 || exclusivityEndTime \u003e int256(params.deadline)) {\n revert ExclusivityParamsIncorrect();\n }\n }\n\n /// @notice Performs all the necessary checks for a relay to happen.\n function _validateRelayParams(bytes calldata request, bytes32 transactionId, address relayer) internal view {\n if (relayer == address(0)) revert ZeroAddress();\n // Check if the transaction has already been relayed\n if (bridgeRelays(transactionId)) revert TransactionRelayed();\n if (request.destChainId() != block.chainid) revert ChainIncorrect();\n // Check the deadline for relay to happen\n if (block.timestamp \u003e request.deadline()) revert DeadlineExceeded();\n // Check the exclusivity period, if it is still ongoing\n address exclRelayer = request.exclusivityRelayer();\n if (exclRelayer != address(0) \u0026\u0026 exclRelayer != relayer \u0026\u0026 block.timestamp \u003c= request.exclusivityEndTime()) {\n revert ExclusivityPeriodNotPassed();\n }\n }\n}\n","language":"Solidity","languageVersion":"0.8.24","compilerVersion":"0.8.24","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"76061:4808:0:-:0;;;78600:1;78558:43;;78608:130;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;78646:38;68687:4;78677:6;78646:10;:38::i;:::-;-1:-1:-1;78694:37:0;78092:6;78694:15;:37::i;:::-;78608:130;76061:4808;;75409:257;75495:4;;75526:31;75543:4;75549:7;75526:16;:31::i;:::-;75511:46;;75571:7;75567:69;;;75594:18;;;;:12;:18;;;;;:31;;75617:7;75594:22;:31::i;:::-;;75567:69;75652:7;-1:-1:-1;75409:257:0;;;;;:::o;80577:290::-;77959:7;80648:14;:33;80644:67;;;80690:21;;-1:-1:-1;;;80690:21:0;;;;;;;;;;;80644:67;80746:11;;;80767:28;;;;80810:50;;;483:25:1;;;539:2;524:18;;517:34;;;80810:50:0;;456:18:1;80810:50:0;;;;;;;80634:233;80577:290;:::o;72634:316::-;72711:4;69409:12;;;;;;;;;;;-1:-1:-1;;;;;69409:29:0;;;;;;;;;;;;72727:217;;72770:6;:12;;;;;;;;;;;-1:-1:-1;;;;;72770:29:0;;;;;;;;;:36;;-1:-1:-1;;72770:36:0;72802:4;72770:36;;;72852:12;23372:10;;23293:96;72852:12;-1:-1:-1;;;;;72825:40:0;72843:7;-1:-1:-1;;;;;72825:40:0;72837:4;72825:40;;;;;;;;;;-1:-1:-1;72886:4:0;72879:11;;72727:217;-1:-1:-1;72928:5:0;72921:12;;32817:150;32887:4;32910:50;32915:3;-1:-1:-1;;;;;32935:23:0;;26805:4;28861:21;;;:14;;;:21;;;;;;26821:321;;-1:-1:-1;26863:23:0;;;;;;;;:11;:23;;;;;;;;;;;;;27045:18;;27021:21;;;:14;;;:21;;;;;;:42;;;;27077:11;;14:290:1;84:6;137:2;125:9;116:7;112:23;108:32;105:52;;;153:1;150;143:12;105:52;179:16;;-1:-1:-1;;;;;224:31:1;;214:42;;204:70;;270:1;267;260:12;309:248;76061:4808:0;;;;;;;;;;;;","srcMapRuntime":"76061:4808:0:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;74069:212;;;;;;:::i;:::-;;:::i;:::-;;;516:14:1;;509:22;491:41;;479:2;464:18;74069:212:0;;;;;;;;77302:66;;77342:26;77302:66;;;;;689:25:1;;;677:2;662:18;77302:66:0;543:177:1;77044:60:0;;77081:23;77044:60;;79902:554;;;;;;:::i;:::-;;:::i;:::-;;77794:45;;77833:6;77794:45;;76279:85;;76322:42;76279:85;;;;;1549:42:1;1537:55;;;1519:74;;1507:2;1492:18;76279:85:0;1373:226:1;78981:129:0;;;;;;:::i;:::-;;:::i;70265:120::-;;;;;;:::i;:::-;70330:7;70356:12;;;;;;;;;;:22;;;;70265:120;70681:136;;;;;;:::i;:::-;;:::i;71783:245::-;;;;;;:::i;:::-;;:::i;78188:30::-;;;;;;78418:26;;;;;;76528:62;;76566:24;76528:62;;74866:142;;;;;;:::i;:::-;;:::i;69309:136::-;;;;;;:::i;:::-;69386:4;69409:12;;;;;;;;;;;:29;;;;;;;;;;;;;;;;69309:136;77916:50;;77959:7;77916:50;;78045:53;;78092:6;78045:53;;68642:49;;68687:4;68642:49;;79505:290;;;;;;:::i;:::-;;:::i;77687:37::-;;77721:3;77687:37;;75176:131;;;;;;:::i;:::-;;:::i;77554:66::-;;77594:26;77554:66;;71097:138;;;;;;:::i;:::-;;:::i;76787:62::-;;76825:24;76787:62;;78274:47;;;;;;:::i;:::-;;;;;;;;;;;;;;78558:43;;;;;74069:212;74154:4;74177:57;;;74192:42;74177:57;;:97;;;74238:36;74262:11;74238:23;:36::i;:::-;74170:104;74069:212;-1:-1:-1;;74069:212:0:o;79902:554::-;77594:26;68919:16;68930:4;68919:10;:16::i;:::-;80026:19:::1;::::0;::::1;80006:17;80026:19:::0;;;:12:::1;:19;::::0;;;;;;80059:14;;;80055:27:::1;;80075:7;79902:554:::0;;;:::o;80055:27::-:1;80123:19;::::0;;::::1;80145:1;80123:19:::0;;;:12:::1;:19;::::0;;;;;;;:23;;;;80161:38;;2940:34:1;;;3010:15;;;2990:18;;;2983:43;;;;3042:18;;;3035:34;;;80161:38:0::1;::::0;2867:2:1;2852:18;80161:38:0::1;;;;;;;80271:25:::0;::::1;::::0;::::1;::::0;80267:183:::1;;80312:48;80338:9;80350;80312:17;:48::i;:::-;80267:183;;;80391:48;:26;::::0;::::1;80418:9:::0;80429;80391:26:::1;:48::i;:::-;79996:460;68945:1;79902:554:::0;;;:::o;78981:129::-;77594:26;68919:16;68930:4;68919:10;:16::i;:::-;79072:31:::1;79088:14;79072:15;:31::i;:::-;78981:129:::0;;:::o;70681:136::-;70330:7;70356:12;;;;;;;;;;:22;;;68919:16;68930:4;68919:10;:16::i;:::-;70785:25:::1;70796:4;70802:7;70785:10;:25::i;71783:245::-:0;71876:34;;;23372:10;71876:34;71872:102;;71933:30;;;;;;;;;;;;;;71872:102;71984:37;71996:4;72002:18;71984:11;:37::i;74866:142::-;74947:7;74973:18;;;:12;:18;;;;;:28;;74995:5;74973:21;:28::i;:::-;74966:35;74866:142;-1:-1:-1;;;74866:142:0:o;79505:290::-;77594:26;68919:16;68930:4;68919:10;:16::i;:::-;77833:6:::1;79600:10;:25;79596:55;;;79634:17;;;;;;;;;;;;;;79596:55;79682:15;::::0;;79707:28;;;;79750:38:::1;::::0;;3254:25:1;;;3310:2;3295:18;;3288:34;;;79750:38:0::1;::::0;3227:18:1;79750:38:0::1;;;;;;;79586:209;79505:290:::0;;:::o;75176:131::-;75247:7;75273:18;;;:12;:18;;;;;:27;;:25;:27::i;71097:138::-;70330:7;70356:12;;;;;;;;;;:22;;;68919:16;68930:4;68919:10;:16::i;:::-;71202:26:::1;71214:4;71220:7;71202:11;:26::i;69020:202::-:0;69105:4;69128:47;;;69143:32;69128:47;;:87;;-1:-1:-1;49356:25:0;49341:40;;;;69179:36;49242:146;69654:103;69720:30;69731:4;23372:10;69720;:30::i;:::-;69654:103;:::o;17904:331::-;18013:6;17989:21;:30;17985:109;;;18042:41;;;;;18077:4;18042:41;;;1519:74:1;1492:18;;18042:41:0;;;;;;;;17985:109;18105:12;18123:9;:14;;18145:6;18123:33;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;18104:52;;;18171:7;18166:63;;18201:17;;;;;;;;;;;;;;62137:160;62246:43;;;62261:14;3735:55:1;;62246:43:0;;;3717:74:1;3807:18;;;;3800:34;;;62246:43:0;;;;;;;;;;3690:18:1;;;;62246:43:0;;;;;;;;;;;;;;62219:71;;62239:5;;62219:19;:71::i;80577:290::-;77959:7;80648:14;:33;80644:67;;;80690:21;;;;;;;;;;;;;;80644:67;80746:11;;;80767:28;;;;80810:50;;;3254:25:1;;;3310:2;3295:18;;3288:34;;;80810:50:0;;3227:18:1;80810:50:0;;;;;;;80634:233;80577:290;:::o;75409:257::-;75495:4;75511:12;75526:31;75543:4;75549:7;75526:16;:31::i;:::-;75511:46;;75571:7;75567:69;;;75594:18;;;;:12;:18;;;;;:31;;75617:7;75594:22;:31::i;:::-;;75652:7;75409:257;-1:-1:-1;;;75409:257:0:o;75769:262::-;75856:4;75872:12;75887:32;75905:4;75911:7;75887:17;:32::i;:::-;75872:47;;75933:7;75929:72;;;75956:18;;;;:12;:18;;;;;:34;;75982:7;75956:25;:34::i;34075:156::-;34149:7;34199:22;34203:3;34215:5;34199:3;:22::i;33618:115::-;33681:7;33707:19;33715:3;29057:18;;28975:107;69887:197;69386:4;69409:12;;;;;;;;;;;:29;;;;;;;;;;;;;69970:108;;70020:47;;;;;3747:42:1;3735:55;;70020:47:0;;;3717:74:1;3807:18;;;3800:34;;;3690:18;;70020:47:0;3543:297:1;64893:629:0;65312:23;65338:33;:27;;;65366:4;65338:27;:33::i;:::-;65312:59;;65385:10;:17;65406:1;65385:22;;:57;;;;;65423:10;65412:30;;;;;;;;;;;;:::i;:::-;65411:31;65385:57;65381:135;;;65465:40;;;;;1549:42:1;1537:55;;65465:40:0;;;1519:74:1;1492:18;;65465:40:0;1373:226:1;72634:316:0;72711:4;69409:12;;;;;;;;;;;:29;;;;;;;;;;;;;72727:217;;72770:6;:12;;;;;;;;;;;:29;;;;;;;;;;:36;;;;72802:4;72770:36;;;72852:12;23372:10;;23293:96;72852:12;72825:40;;72843:7;72825:40;;72837:4;72825:40;;;;;;;;;;-1:-1:-1;72886:4:0;72879:11;;72727:217;-1:-1:-1;72928:5:0;72921:12;;32817:150;32887:4;32910:50;32915:3;32935:23;;;32910:4;:50::i;73185:317::-;73263:4;69409:12;;;;;;;;;;;:29;;;;;;;;;;;;;73279:217;;;73353:5;73321:12;;;;;;;;;;;:29;;;;;;;;;;;:37;;;;;;73377:40;23372:10;;73321:12;;73377:40;;73353:5;73377:40;-1:-1:-1;73438:4:0;73431:11;;33135:156;33208:4;33231:53;33239:3;33259:23;;;33231:7;:53::i;29424:118::-;29491:7;29517:3;:11;;29529:5;29517:18;;;;;;;;:::i;:::-;;;;;;;;;29510:25;;29424:118;;;;:::o;19078:151::-;19153:12;19184:38;19206:6;19214:4;19220:1;19184:21;:38::i;26742:406::-;26805:4;28861:21;;;:14;;;:21;;;;;;26821:321;;-1:-1:-1;26863:23:0;;;;;;;;:11;:23;;;;;;;;;;;;;27045:18;;27021:21;;;:14;;;:21;;;;;;:42;;;;27077:11;;27316:1368;27382:4;27511:21;;;:14;;;:21;;;;;;27547:13;;27543:1135;;27914:18;27935:12;27946:1;27935:8;:12;:::i;:::-;27981:18;;27914:33;;-1:-1:-1;27961:17:0;;27981:22;;28002:1;;27981:22;:::i;:::-;27961:42;;28036:9;28022:10;:23;28018:378;;28065:17;28085:3;:11;;28097:9;28085:22;;;;;;;;:::i;:::-;;;;;;;;;28065:42;;28232:9;28206:3;:11;;28218:10;28206:23;;;;;;;;:::i;:::-;;;;;;;;;;;;:35;;;;28345:25;;;:14;;;:25;;;;;:36;;;28018:378;28474:17;;:3;;:17;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;28577:3;:14;;:21;28592:5;28577:21;;;;;;;;;;;28570:28;;;28620:4;28613:11;;;;;;;27543:1135;28662:5;28655:12;;;;;19553:392;19652:12;19704:5;19680:21;:29;19676:108;;;19732:41;;;;;19767:4;19732:41;;;1519:74:1;1492:18;;19732:41:0;1373:226:1;19676:108:0;19794:12;19808:23;19835:6;:11;;19854:5;19861:4;19835:31;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;19793:73;;;;19883:55;19910:6;19918:7;19927:10;19883:26;:55::i;:::-;19876:62;19553:392;-1:-1:-1;;;;;;19553:392:0:o;20998:582::-;21142:12;21171:7;21166:408;;21194:19;21202:10;21194:7;:19::i;:::-;21166:408;;;21418:17;;:22;:49;;;;-1:-1:-1;21444:18:0;;;;:23;21418:49;21414:119;;;21494:24;;;;;1549:42:1;1537:55;;21494:24:0;;;1519:74:1;1492:18;;21494:24:0;1373:226:1;21414:119:0;-1:-1:-1;21553:10:0;21546:17;;22116:516;22247:17;;:21;22243:383;;22475:10;22469:17;22531:15;22518:10;22514:2;22510:19;22503:44;22243:383;22598:17;;;;;;;;;;;;;;14:332:1;72:6;125:2;113:9;104:7;100:23;96:32;93:52;;;141:1;138;131:12;93:52;180:9;167:23;230:66;223:5;219:78;212:5;209:89;199:117;;312:1;309;302:12;725:196;793:20;;853:42;842:54;;832:65;;822:93;;911:1;908;901:12;822:93;725:196;;;:::o;926:260::-;994:6;1002;1055:2;1043:9;1034:7;1030:23;1026:32;1023:52;;;1071:1;1068;1061:12;1023:52;1094:29;1113:9;1094:29;:::i;:::-;1084:39;;1142:38;1176:2;1165:9;1161:18;1142:38;:::i;:::-;1132:48;;926:260;;;;;:::o;1604:180::-;1663:6;1716:2;1704:9;1695:7;1691:23;1687:32;1684:52;;;1732:1;1729;1722:12;1684:52;-1:-1:-1;1755:23:1;;1604:180;-1:-1:-1;1604:180:1:o;1974:254::-;2042:6;2050;2103:2;2091:9;2082:7;2078:23;2074:32;2071:52;;;2119:1;2116;2109:12;2071:52;2155:9;2142:23;2132:33;;2184:38;2218:2;2207:9;2203:18;2184:38;:::i;2233:248::-;2301:6;2309;2362:2;2350:9;2341:7;2337:23;2333:32;2330:52;;;2378:1;2375;2368:12;2330:52;-1:-1:-1;;2401:23:1;;;2471:2;2456:18;;;2443:32;;-1:-1:-1;2233:248:1:o;2486:186::-;2545:6;2598:2;2586:9;2577:7;2573:23;2569:32;2566:52;;;2614:1;2611;2604:12;2566:52;2637:29;2656:9;2637:29;:::i;4147:277::-;4214:6;4267:2;4255:9;4246:7;4242:23;4238:32;4235:52;;;4283:1;4280;4273:12;4235:52;4315:9;4309:16;4368:5;4361:13;4354:21;4347:5;4344:32;4334:60;;4390:1;4387;4380:12;4429:184;4481:77;4478:1;4471:88;4578:4;4575:1;4568:15;4602:4;4599:1;4592:15;4618:282;4685:9;;;4706:11;;;4703:191;;;4750:77;4747:1;4740:88;4851:4;4848:1;4841:15;4879:4;4876:1;4869:15;4905:184;4957:77;4954:1;4947:88;5054:4;5051:1;5044:15;5078:4;5075:1;5068:15;5094:412;5223:3;5261:6;5255:13;5286:1;5296:129;5310:6;5307:1;5304:13;5296:129;;;5408:4;5392:14;;;5388:25;;5382:32;5369:11;;;5362:53;5325:12;5296:129;;;-1:-1:-1;5480:1:1;5444:16;;5469:13;;;-1:-1:-1;5444:16:1;5094:412;-1:-1:-1;5094:412:1:o","abiDefinition":[{"inputs":[{"internalType":"address","name":"_owner","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AccessControlBadConfirmation","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"bytes32","name":"neededRole","type":"bytes32"}],"name":"AccessControlUnauthorizedAccount","type":"error"},{"inputs":[{"internalType":"address","name":"target","type":"address"}],"name":"AddressEmptyCode","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"AddressInsufficientBalance","type":"error"},{"inputs":[],"name":"CancelDelayBelowMin","type":"error"},{"inputs":[],"name":"FailedInnerCall","type":"error"},{"inputs":[],"name":"FeeRateAboveMax","type":"error"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"SafeERC20FailedOperation","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldCancelDelay","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newCancelDelay","type":"uint256"}],"name":"CancelDelayUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldFeeRate","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newFeeRate","type":"uint256"}],"name":"FeeRateUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"address","name":"recipient","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"FeesSwept","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"previousAdminRole","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"newAdminRole","type":"bytes32"}],"name":"RoleAdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleRevoked","type":"event"},{"inputs":[],"name":"CANCELER_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"DEFAULT_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"DEFAULT_CANCEL_DELAY","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"FEE_BPS","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"FEE_RATE_MAX","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"GOVERNOR_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"GUARD_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MIN_CANCEL_DELAY","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"NATIVE_GAS_TOKEN","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"PROVER_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"QUOTER_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"cancelDelay","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"chainGasAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleAdmin","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"uint256","name":"index","type":"uint256"}],"name":"getRoleMember","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleMemberCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"grantRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"hasRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"protocolFeeRate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"protocolFees","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"callerConfirmation","type":"address"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"revokeRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"newCancelDelay","type":"uint256"}],"name":"setCancelDelay","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"newFeeRate","type":"uint256"}],"name":"setProtocolFeeRate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"address","name":"recipient","type":"address"}],"name":"sweepProtocolFees","outputs":[],"stateMutability":"nonpayable","type":"function"}],"userDoc":{"kind":"user","methods":{"CANCELER_ROLE()":{"notice":"Role identifier for Canceler's on-chain authentication in FastBridge."},"DEFAULT_CANCEL_DELAY()":{"notice":"Default cancel delay set during the contract deployment."},"FEE_BPS()":{"notice":"Denominator for fee rates, represents 100%."},"FEE_RATE_MAX()":{"notice":"Maximum protocol fee rate: 1% on origin amount."},"GOVERNOR_ROLE()":{"notice":"Role identifier for Governor's on-chain administrative authority."},"GUARD_ROLE()":{"notice":"Role identifier for Guard's on-chain authentication in FastBridge."},"MIN_CANCEL_DELAY()":{"notice":"Minimum cancel delay that can be set by the governor."},"NATIVE_GAS_TOKEN()":{"notice":"Address reserved for native gas token (ETH on Ethereum and most L2s, AVAX on Avalanche, etc)"},"PROVER_ROLE()":{"notice":"Role identifier for Prover's on-chain authentication in FastBridge."},"QUOTER_ROLE()":{"notice":"Role identifier for Quoter API's off-chain authentication."},"cancelDelay()":{"notice":"Delay for a transaction after which it could be permisionlessly cancelled"},"chainGasAmount()":{"notice":"This is deprecated and should not be used."},"protocolFeeRate()":{"notice":"Protocol fee rate taken on origin amount deposited in origin chain"},"protocolFees(address)":{"notice":"Protocol fee amounts accumulated"},"setCancelDelay(uint256)":{"notice":"Allows the contract governor to set the cancel delay. The cancel delay is the time after the transaction deadline after which it can be permissionlessly cancelled, if it hasn't been proven by any of the Relayers."},"setProtocolFeeRate(uint256)":{"notice":"Allows the contract governor to set the protocol fee rate. The protocol fee is taken from the origin amount only for completed and claimed transactions."},"sweepProtocolFees(address,address)":{"notice":"Allows the contract governor to sweep the accumulated protocol fees in the contract."}},"version":1},"developerDoc":{"errors":{"AccessControlBadConfirmation()":[{"details":"The caller of a function is not the expected one. NOTE: Don't confuse with {AccessControlUnauthorizedAccount}."}],"AccessControlUnauthorizedAccount(address,bytes32)":[{"details":"The `account` is missing a role."}],"AddressEmptyCode(address)":[{"details":"There's no code at `target` (it is not a contract)."}],"AddressInsufficientBalance(address)":[{"details":"The ETH balance of the account is not enough to perform the operation."}],"FailedInnerCall()":[{"details":"A call to an address target failed. The target may have reverted."}],"SafeERC20FailedOperation(address)":[{"details":"An operation with an ERC20 token failed."}]},"events":{"RoleAdminChanged(bytes32,bytes32,bytes32)":{"details":"Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole` `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite {RoleAdminChanged} not being emitted signaling this."},"RoleGranted(bytes32,address,address)":{"details":"Emitted when `account` is granted `role`. `sender` is the account that originated the contract call, an admin role bearer except when using {AccessControl-_setupRole}."},"RoleRevoked(bytes32,address,address)":{"details":"Emitted when `account` is revoked `role`. `sender` is the account that originated the contract call: - if using `revokeRole`, it is the admin role bearer - if using `renounceRole`, it is the role bearer (i.e. `account`)"}},"kind":"dev","methods":{"getRoleAdmin(bytes32)":{"details":"Returns the admin role that controls `role`. See {grantRole} and {revokeRole}. To change a role's admin, use {_setRoleAdmin}."},"getRoleMember(bytes32,uint256)":{"details":"Returns one of the accounts that have `role`. `index` must be a value between 0 and {getRoleMemberCount}, non-inclusive. Role bearers are not sorted in any particular way, and their ordering may change at any point. WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure you perform all queries on the same block. See the following https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post] for more information."},"getRoleMemberCount(bytes32)":{"details":"Returns the number of accounts that have `role`. Can be used together with {getRoleMember} to enumerate all bearers of a role."},"grantRole(bytes32,address)":{"details":"Grants `role` to `account`. If `account` had not been already granted `role`, emits a {RoleGranted} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleGranted} event."},"hasRole(bytes32,address)":{"details":"Returns `true` if `account` has been granted `role`."},"renounceRole(bytes32,address)":{"details":"Revokes `role` from the calling account. Roles are often managed via {grantRole} and {revokeRole}: this function's purpose is to provide a mechanism for accounts to lose their privileges if they are compromised (such as when a trusted device is misplaced). If the calling account had been revoked `role`, emits a {RoleRevoked} event. Requirements: - the caller must be `callerConfirmation`. May emit a {RoleRevoked} event."},"revokeRole(bytes32,address)":{"details":"Revokes `role` from `account`. If `account` had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleRevoked} event."},"setProtocolFeeRate(uint256)":{"details":"The protocol fee is abstracted away from the relayers, they always operate using the amounts after fees: what they see as the origin amount emitted in the log is what they get credited with."},"supportsInterface(bytes4)":{"details":"See {IERC165-supportsInterface}."}},"stateVariables":{"CANCELER_ROLE":{"details":"Only addresses with this role can cancel a FastBridge transaction without the cancel delay."},"GOVERNOR_ROLE":{"details":"Only addresses with this role can perform administrative tasks within the contract."},"GUARD_ROLE":{"details":"Only addresses with this role can dispute submitted relay proofs during the dispute period."},"PROVER_ROLE":{"details":"Only addresses with this role can provide proofs that a FastBridge request has been relayed."},"QUOTER_ROLE":{"details":"Only addresses with this role can post FastBridge quotes to the API."},"chainGasAmount":{"details":"Use ZapNative V2 requests instead."}},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_owner\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"AccessControlBadConfirmation\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"neededRole\",\"type\":\"bytes32\"}],\"name\":\"AccessControlUnauthorizedAccount\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"}],\"name\":\"AddressEmptyCode\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"AddressInsufficientBalance\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"CancelDelayBelowMin\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"FailedInnerCall\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"FeeRateAboveMax\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"}],\"name\":\"SafeERC20FailedOperation\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"oldCancelDelay\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newCancelDelay\",\"type\":\"uint256\"}],\"name\":\"CancelDelayUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"oldFeeRate\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newFeeRate\",\"type\":\"uint256\"}],\"name\":\"FeeRateUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"FeesSwept\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"previousAdminRole\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"newAdminRole\",\"type\":\"bytes32\"}],\"name\":\"RoleAdminChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleGranted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleRevoked\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"CANCELER_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"DEFAULT_ADMIN_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"DEFAULT_CANCEL_DELAY\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"FEE_BPS\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"FEE_RATE_MAX\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"GOVERNOR_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"GUARD_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"MIN_CANCEL_DELAY\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"NATIVE_GAS_TOKEN\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"PROVER_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"QUOTER_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"cancelDelay\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"chainGasAmount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"}],\"name\":\"getRoleAdmin\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"index\",\"type\":\"uint256\"}],\"name\":\"getRoleMember\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"}],\"name\":\"getRoleMemberCount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"grantRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"hasRole\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"protocolFeeRate\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"protocolFees\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"callerConfirmation\",\"type\":\"address\"}],\"name\":\"renounceRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"revokeRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"newCancelDelay\",\"type\":\"uint256\"}],\"name\":\"setCancelDelay\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"newFeeRate\",\"type\":\"uint256\"}],\"name\":\"setProtocolFeeRate\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes4\",\"name\":\"interfaceId\",\"type\":\"bytes4\"}],\"name\":\"supportsInterface\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"}],\"name\":\"sweepProtocolFees\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"errors\":{\"AccessControlBadConfirmation()\":[{\"details\":\"The caller of a function is not the expected one. NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\"}],\"AccessControlUnauthorizedAccount(address,bytes32)\":[{\"details\":\"The `account` is missing a role.\"}],\"AddressEmptyCode(address)\":[{\"details\":\"There's no code at `target` (it is not a contract).\"}],\"AddressInsufficientBalance(address)\":[{\"details\":\"The ETH balance of the account is not enough to perform the operation.\"}],\"FailedInnerCall()\":[{\"details\":\"A call to an address target failed. The target may have reverted.\"}],\"SafeERC20FailedOperation(address)\":[{\"details\":\"An operation with an ERC20 token failed.\"}]},\"events\":{\"RoleAdminChanged(bytes32,bytes32,bytes32)\":{\"details\":\"Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole` `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite {RoleAdminChanged} not being emitted signaling this.\"},\"RoleGranted(bytes32,address,address)\":{\"details\":\"Emitted when `account` is granted `role`. `sender` is the account that originated the contract call, an admin role bearer except when using {AccessControl-_setupRole}.\"},\"RoleRevoked(bytes32,address,address)\":{\"details\":\"Emitted when `account` is revoked `role`. `sender` is the account that originated the contract call: - if using `revokeRole`, it is the admin role bearer - if using `renounceRole`, it is the role bearer (i.e. `account`)\"}},\"kind\":\"dev\",\"methods\":{\"getRoleAdmin(bytes32)\":{\"details\":\"Returns the admin role that controls `role`. See {grantRole} and {revokeRole}. To change a role's admin, use {_setRoleAdmin}.\"},\"getRoleMember(bytes32,uint256)\":{\"details\":\"Returns one of the accounts that have `role`. `index` must be a value between 0 and {getRoleMemberCount}, non-inclusive. Role bearers are not sorted in any particular way, and their ordering may change at any point. WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure you perform all queries on the same block. See the following https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post] for more information.\"},\"getRoleMemberCount(bytes32)\":{\"details\":\"Returns the number of accounts that have `role`. Can be used together with {getRoleMember} to enumerate all bearers of a role.\"},\"grantRole(bytes32,address)\":{\"details\":\"Grants `role` to `account`. If `account` had not been already granted `role`, emits a {RoleGranted} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleGranted} event.\"},\"hasRole(bytes32,address)\":{\"details\":\"Returns `true` if `account` has been granted `role`.\"},\"renounceRole(bytes32,address)\":{\"details\":\"Revokes `role` from the calling account. Roles are often managed via {grantRole} and {revokeRole}: this function's purpose is to provide a mechanism for accounts to lose their privileges if they are compromised (such as when a trusted device is misplaced). If the calling account had been revoked `role`, emits a {RoleRevoked} event. Requirements: - the caller must be `callerConfirmation`. May emit a {RoleRevoked} event.\"},\"revokeRole(bytes32,address)\":{\"details\":\"Revokes `role` from `account`. If `account` had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleRevoked} event.\"},\"setProtocolFeeRate(uint256)\":{\"details\":\"The protocol fee is abstracted away from the relayers, they always operate using the amounts after fees: what they see as the origin amount emitted in the log is what they get credited with.\"},\"supportsInterface(bytes4)\":{\"details\":\"See {IERC165-supportsInterface}.\"}},\"stateVariables\":{\"CANCELER_ROLE\":{\"details\":\"Only addresses with this role can cancel a FastBridge transaction without the cancel delay.\"},\"GOVERNOR_ROLE\":{\"details\":\"Only addresses with this role can perform administrative tasks within the contract.\"},\"GUARD_ROLE\":{\"details\":\"Only addresses with this role can dispute submitted relay proofs during the dispute period.\"},\"PROVER_ROLE\":{\"details\":\"Only addresses with this role can provide proofs that a FastBridge request has been relayed.\"},\"QUOTER_ROLE\":{\"details\":\"Only addresses with this role can post FastBridge quotes to the API.\"},\"chainGasAmount\":{\"details\":\"Use ZapNative V2 requests instead.\"}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"CANCELER_ROLE()\":{\"notice\":\"Role identifier for Canceler's on-chain authentication in FastBridge.\"},\"DEFAULT_CANCEL_DELAY()\":{\"notice\":\"Default cancel delay set during the contract deployment.\"},\"FEE_BPS()\":{\"notice\":\"Denominator for fee rates, represents 100%.\"},\"FEE_RATE_MAX()\":{\"notice\":\"Maximum protocol fee rate: 1% on origin amount.\"},\"GOVERNOR_ROLE()\":{\"notice\":\"Role identifier for Governor's on-chain administrative authority.\"},\"GUARD_ROLE()\":{\"notice\":\"Role identifier for Guard's on-chain authentication in FastBridge.\"},\"MIN_CANCEL_DELAY()\":{\"notice\":\"Minimum cancel delay that can be set by the governor.\"},\"NATIVE_GAS_TOKEN()\":{\"notice\":\"Address reserved for native gas token (ETH on Ethereum and most L2s, AVAX on Avalanche, etc)\"},\"PROVER_ROLE()\":{\"notice\":\"Role identifier for Prover's on-chain authentication in FastBridge.\"},\"QUOTER_ROLE()\":{\"notice\":\"Role identifier for Quoter API's off-chain authentication.\"},\"cancelDelay()\":{\"notice\":\"Delay for a transaction after which it could be permisionlessly cancelled\"},\"chainGasAmount()\":{\"notice\":\"This is deprecated and should not be used.\"},\"protocolFeeRate()\":{\"notice\":\"Protocol fee rate taken on origin amount deposited in origin chain\"},\"protocolFees(address)\":{\"notice\":\"Protocol fee amounts accumulated\"},\"setCancelDelay(uint256)\":{\"notice\":\"Allows the contract governor to set the cancel delay. The cancel delay is the time after the transaction deadline after which it can be permissionlessly cancelled, if it hasn't been proven by any of the Relayers.\"},\"setProtocolFeeRate(uint256)\":{\"notice\":\"Allows the contract governor to set the protocol fee rate. The protocol fee is taken from the origin amount only for completed and claimed transactions.\"},\"sweepProtocolFees(address,address)\":{\"notice\":\"Allows the contract governor to sweep the accumulated protocol fees in the contract.\"}},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeV2.sol\":\"AdminV2\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeV2.sol\":{\"keccak256\":\"0xac79c463688a682ca706a4ef95e7817b83548cdfa8182ba0426ac7e5e07613d8\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://b3ecb7097381287cafc3a73f3a2bb03565115ebb682a85064e0b0dc2f7e2919d\",\"dweb:/ipfs/QmatruW3nYZTksf3CeQ8wwiAG4c7xoEJBEp6drHPtFLBRK\"]}},\"version\":1}"},"hashes":{"CANCELER_ROLE()":"02d2ff66","DEFAULT_ADMIN_ROLE()":"a217fddf","DEFAULT_CANCEL_DELAY()":"930ac180","FEE_BPS()":"bf333f2c","FEE_RATE_MAX()":"0f5f6ed7","GOVERNOR_ROLE()":"ccc57490","GUARD_ROLE()":"03ed0ee5","MIN_CANCEL_DELAY()":"922b7487","NATIVE_GAS_TOKEN()":"0f862f1e","PROVER_ROLE()":"dc9a4ef6","QUOTER_ROLE()":"7ebe815c","cancelDelay()":"638a0f09","chainGasAmount()":"e00a83e0","getRoleAdmin(bytes32)":"248a9ca3","getRoleMember(bytes32,uint256)":"9010d07c","getRoleMemberCount(bytes32)":"ca15c873","grantRole(bytes32,address)":"2f2ff15d","hasRole(bytes32,address)":"91d14854","protocolFeeRate()":"58f85880","protocolFees(address)":"dcf844a7","renounceRole(bytes32,address)":"36568abe","revokeRole(bytes32,address)":"d547741f","setCancelDelay(uint256)":"1ea327c5","setProtocolFeeRate(uint256)":"b13aa2d6","supportsInterface(bytes4)":"01ffc9a7","sweepProtocolFees(address,address)":"06f333f2"}},"solidity/FastBridgeV2.sol:BridgeTransactionV2Lib":{"code":"0x60566037600b82828239805160001a607314602a57634e487b7160e01b600052600060045260246000fd5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600080fdfea2646970667358221220736bb5e8e495fb3a776c3cad8b30577c46279a088f4f89b0d509badbef3da01f64736f6c63430008180033","runtime-code":"0x73000000000000000000000000000000000000000030146080604052600080fdfea2646970667358221220736bb5e8e495fb3a776c3cad8b30577c46279a088f4f89b0d509badbef3da01f64736f6c63430008180033","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.24 ^0.8.20 ^0.8.4;\n\n// contracts/interfaces/IAdminV2.sol\n\ninterface IAdminV2 {\n event CancelDelayUpdated(uint256 oldCancelDelay, uint256 newCancelDelay);\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n function setCancelDelay(uint256 newCancelDelay) external;\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n}\n\n// contracts/interfaces/IAdminV2Errors.sol\n\ninterface IAdminV2Errors {\n error CancelDelayBelowMin();\n error FeeRateAboveMax();\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IFastBridgeV2Errors.sol\n\ninterface IFastBridgeV2Errors {\n error AmountIncorrect();\n error ChainIncorrect();\n error ExclusivityParamsIncorrect();\n error MsgValueIncorrect();\n error SenderIncorrect();\n error StatusIncorrect();\n error TokenNotContract();\n error ZapDataLengthAboveMax();\n error ZapNativeNotSupported();\n error ZeroAddress();\n\n error RecipientIncorrectReturnValue();\n error RecipientNoReturnValue();\n\n error DeadlineExceeded();\n error DeadlineNotExceeded();\n error DeadlineTooShort();\n error DisputePeriodNotPassed();\n error DisputePeriodPassed();\n error ExclusivityPeriodNotPassed();\n\n error TransactionRelayed();\n}\n\n// contracts/interfaces/IMulticallTarget.sol\n\n/// @notice Interface for a contract that can be called multiple times by the same caller. Inspired by MulticallV3:\n/// https://github.com/mds1/multicall/blob/master/src/Multicall3.sol\ninterface IMulticallTarget {\n struct Result {\n bool success;\n bytes returnData;\n }\n\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external;\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results);\n}\n\n// contracts/interfaces/IZapRecipient.sol\n\ninterface IZapRecipient {\n function zap(address token, uint256 amount, bytes memory zapData) external payable returns (bytes4);\n}\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// contracts/interfaces/IFastBridgeV2.sol\n\ninterface IFastBridgeV2 is IFastBridge {\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n struct BridgeTxDetails {\n BridgeStatus status;\n uint32 destChainId;\n uint56 proofBlockTimestamp;\n address proofRelayer;\n }\n\n struct BridgeRelay {\n uint48 blockNumber;\n uint48 blockTimestamp;\n address relayer;\n }\n\n /// @notice New params introduced in the FastBridgeV2.\n /// We are passing fields from the older BridgeParams struct outside of this struct\n /// for backwards compatibility.\n /// Note: quoteRelayer and quoteExclusivitySeconds are either both zero (indicating no exclusivity)\n /// or both non-zero (indicating exclusivity for the given period).\n /// Note: zapNative \u003e 0 can NOT be used with destToken = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE (native token)\n /// @param quoteRelayer Relayer that provided the quote for the transaction\n /// @param quoteExclusivitySeconds Period of time the quote relayer is guaranteed exclusivity after user's deposit\n /// @param quoteId Unique quote identifier used for tracking the quote\n /// @param zapNative ETH value to send to the recipient (if any)\n /// @param zapData Parameters for the Zap to the destination recipient (if any)\n struct BridgeParamsV2 {\n address quoteRelayer;\n int256 quoteExclusivitySeconds;\n bytes quoteId;\n uint256 zapNative;\n bytes zapData;\n }\n\n /// @notice Updated bridge transaction struct to include parameters introduced in FastBridgeV2.\n /// Note: only `exclusivityRelayer` can fill such a transaction until `exclusivityEndTime`.\n struct BridgeTransactionV2 {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n // Note: sendChainGas flag from V1 is deprecated\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n address exclusivityRelayer;\n uint256 exclusivityEndTime;\n uint256 zapNative; // ETH value to send to the recipient (if any)\n bytes zapData; // data to pass for the Zap action (if any)\n }\n\n event BridgeQuoteDetails(bytes32 indexed transactionId, bytes quoteId);\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability\n /// to provide temporary exclusivity fill rights for the quote relayer.\n /// @param params The parameters required to bridge\n /// @param paramsV2 The parameters for exclusivity fill rights (optional, can be left empty)\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function relay(bytes memory request, address relayer) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param transactionId The transaction id associated with the encoded bridge transaction to prove\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital.\n /// @notice Can only send funds to the relayer address on the proof.\n /// @param request The encoded bridge transaction to claim on origin chain\n function claim(bytes memory request) external;\n\n /// @notice Cancels an outstanding bridge transaction in case optimistic bridging failed and returns the full amount\n /// to the original sender.\n /// @param request The encoded bridge transaction to refund\n function cancel(bytes memory request) external;\n\n /// @notice Checks if a transaction has been relayed\n /// @param transactionId The ID of the transaction to check\n /// @return True if the transaction has been relayed, false otherwise\n function bridgeRelays(bytes32 transactionId) external view returns (bool);\n\n /// @notice Returns the status of a bridge transaction\n /// @param transactionId The ID of the bridge transaction\n /// @return BridgeStatus Status of the bridge transaction\n function bridgeStatuses(bytes32 transactionId) external view returns (BridgeStatus);\n\n /// @notice Returns the timestamp and relayer of a bridge proof\n /// @param transactionId The ID of the bridge transaction\n /// @return timestamp The timestamp of the bridge proof\n /// @return relayer The relayer address of the bridge proof\n function bridgeProofs(bytes32 transactionId) external view returns (uint96 timestamp, address relayer);\n\n /// @notice Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\n /// @param request The bridge request to decode\n function getBridgeTransactionV2(bytes memory request) external view returns (BridgeTransactionV2 memory);\n}\n\n// contracts/utils/MulticallTarget.sol\n\n// solhint-disable avoid-low-level-calls\n/// @notice Template for a contract that supports batched calls (preserving the msg.sender).\n/// Only calls with zero msg.value could be batched.\nabstract contract MulticallTarget is IMulticallTarget {\n error MulticallTarget__UndeterminedRevert();\n\n /// @notice Perform a batched call to this contract, preserving the msg.sender.\n /// The return data from each call is discarded.\n /// @dev The method is non-payable, so only calls with `msg.value == 0` could be batched.\n /// It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag.\n /// Otherwise, the whole batch call will be reverted with the original revert reason.\n /// @param data List of abi-encoded calldata for the calls to perform.\n /// @param ignoreReverts Whether to ignore the revert errors from the calls.\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external {\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\n if (!success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(result);\n }\n }\n }\n\n /// @notice Perform a batched call to this contract, preserving the msg.sender.\n /// The return data from each call is preserved.\n /// @dev The method is non-payable, so only calls with `msg.value == 0` could be batched.\n /// It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag.\n /// Otherwise, the whole batch call will be reverted with the original revert reason.\n /// @param data List of abi-encoded calldata for the calls to perform.\n /// @param ignoreReverts Whether to ignore the revert errors from the calls.\n /// @return results List of results from the calls: `(success, returnData)`.\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results)\n {\n results = new Result[](data.length);\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (results[i].success, results[i].returnData) = address(this).delegatecall(data[i]);\n if (!results[i].success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(results[i].returnData);\n }\n }\n }\n\n /// @dev Bubbles the revert message from the underlying call.\n /// Note: preserves the same custom error or revert string, if one was used.\n /// Source: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v5.0.2/contracts/utils/Address.sol#L143-L158\n function _bubbleRevert(bytes memory returnData) internal pure {\n // Look for revert reason and bubble it up if present\n if (returnData.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n // solhint-disable-next-line no-inline-assembly\n assembly {\n let returndata_size := mload(returnData)\n revert(add(32, returnData), returndata_size)\n }\n } else {\n revert MulticallTarget__UndeterminedRevert();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// contracts/libs/BridgeTransactionV2.sol\n\n// solhint-disable no-inline-assembly\nlibrary BridgeTransactionV2Lib {\n uint16 internal constant VERSION = 2;\n\n // Offsets of the fields in the packed BridgeTransactionV2 struct\n // uint16 version [000 .. 002)\n // uint32 originChainId [002 .. 006)\n // uint32 destChainId [006 .. 010)\n // address originSender [010 .. 030)\n // address destRecipient [030 .. 050)\n // address originToken [050 .. 070)\n // address destToken [070 .. 090)\n // uint256 originAmount [090 .. 122)\n // uint256 destAmount [122 .. 154)\n // uint256 originFeeAmount [154 .. 186)\n // uint256 deadline [186 .. 218)\n // uint256 nonce [218 .. 250)\n // address exclusivityRelayer [250 .. 270)\n // uint256 exclusivityEndTime [270 .. 302)\n // uint256 zapNative [302 .. 334)\n // bytes zapData [334 .. ***)\n\n // forgefmt: disable-start\n uint256 private constant OFFSET_ORIGIN_CHAIN_ID = 2;\n uint256 private constant OFFSET_DEST_CHAIN_ID = 6;\n uint256 private constant OFFSET_ORIGIN_SENDER = 10;\n uint256 private constant OFFSET_DEST_RECIPIENT = 30;\n uint256 private constant OFFSET_ORIGIN_TOKEN = 50;\n uint256 private constant OFFSET_DEST_TOKEN = 70;\n uint256 private constant OFFSET_ORIGIN_AMOUNT = 90;\n uint256 private constant OFFSET_DEST_AMOUNT = 122;\n uint256 private constant OFFSET_ORIGIN_FEE_AMOUNT = 154;\n uint256 private constant OFFSET_DEADLINE = 186;\n uint256 private constant OFFSET_NONCE = 218;\n uint256 private constant OFFSET_EXCLUSIVITY_RELAYER = 250;\n uint256 private constant OFFSET_EXCLUSIVITY_END_TIME = 270;\n uint256 private constant OFFSET_ZAP_NATIVE = 302;\n uint256 private constant OFFSET_ZAP_DATA = 334;\n // forgefmt: disable-end\n\n error BridgeTransactionV2__InvalidEncodedTx();\n error BridgeTransactionV2__UnsupportedVersion(uint16 version);\n\n /// @notice Validates the encoded transaction to be a tightly packed encoded payload for BridgeTransactionV2.\n /// @dev Checks the minimum length and the version, use this function before decoding any of the fields.\n function validateV2(bytes calldata encodedTx) internal pure {\n // Check the minimum length: must at least include all static fields.\n if (encodedTx.length \u003c OFFSET_ZAP_DATA) revert BridgeTransactionV2__InvalidEncodedTx();\n // Once we validated the length, we can be sure that the version field is present.\n uint16 version_ = version(encodedTx);\n if (version_ != VERSION) revert BridgeTransactionV2__UnsupportedVersion(version_);\n }\n\n /// @notice Encodes the BridgeTransactionV2 struct by tightly packing the fields.\n /// @dev `abi.decode` will not work as a result of the tightly packed fields. Use `decodeV2` to decode instead.\n function encodeV2(IFastBridgeV2.BridgeTransactionV2 memory bridgeTx) internal pure returns (bytes memory) {\n // We split the encoding into two parts to avoid stack-too-deep error\n bytes memory firstPart = abi.encodePacked(\n VERSION,\n bridgeTx.originChainId,\n bridgeTx.destChainId,\n bridgeTx.originSender,\n bridgeTx.destRecipient,\n bridgeTx.originToken,\n bridgeTx.destToken,\n bridgeTx.originAmount\n );\n return abi.encodePacked(\n firstPart,\n bridgeTx.destAmount,\n bridgeTx.originFeeAmount,\n // Note: we skip the deprecated `sendChainGas` flag, which was present in BridgeTransaction V1\n bridgeTx.deadline,\n bridgeTx.nonce,\n // New V2 fields: exclusivity\n bridgeTx.exclusivityRelayer,\n bridgeTx.exclusivityEndTime,\n // New V2 fields: Zap\n bridgeTx.zapNative,\n bridgeTx.zapData\n );\n }\n\n /// @notice Decodes the BridgeTransactionV2 struct from the encoded transaction.\n /// @dev Encoded BridgeTransactionV2 struct must be tightly packed.\n /// Use `validateV2` before decoding to ensure the encoded transaction is valid.\n function decodeV2(bytes calldata encodedTx)\n internal\n pure\n returns (IFastBridgeV2.BridgeTransactionV2 memory bridgeTx)\n {\n bridgeTx.originChainId = originChainId(encodedTx);\n bridgeTx.destChainId = destChainId(encodedTx);\n bridgeTx.originSender = originSender(encodedTx);\n bridgeTx.destRecipient = destRecipient(encodedTx);\n bridgeTx.originToken = originToken(encodedTx);\n bridgeTx.destToken = destToken(encodedTx);\n bridgeTx.originAmount = originAmount(encodedTx);\n bridgeTx.destAmount = destAmount(encodedTx);\n bridgeTx.originFeeAmount = originFeeAmount(encodedTx);\n bridgeTx.deadline = deadline(encodedTx);\n bridgeTx.nonce = nonce(encodedTx);\n bridgeTx.exclusivityRelayer = exclusivityRelayer(encodedTx);\n bridgeTx.exclusivityEndTime = exclusivityEndTime(encodedTx);\n bridgeTx.zapNative = zapNative(encodedTx);\n bridgeTx.zapData = zapData(encodedTx);\n }\n\n /// @notice Extracts the version from the encoded transaction.\n function version(bytes calldata encodedTx) internal pure returns (uint16 version_) {\n // Load 32 bytes from the start and shift it 240 bits to the right to get the highest 16 bits.\n assembly {\n version_ := shr(240, calldataload(encodedTx.offset))\n }\n }\n\n /// @notice Extracts the origin chain ID from the encoded transaction.\n function originChainId(bytes calldata encodedTx) internal pure returns (uint32 originChainId_) {\n // Load 32 bytes from the offset and shift it 224 bits to the right to get the highest 32 bits.\n assembly {\n originChainId_ := shr(224, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_CHAIN_ID)))\n }\n }\n\n /// @notice Extracts the destination chain ID from the encoded transaction.\n function destChainId(bytes calldata encodedTx) internal pure returns (uint32 destChainId_) {\n // Load 32 bytes from the offset and shift it 224 bits to the right to get the highest 32 bits.\n assembly {\n destChainId_ := shr(224, calldataload(add(encodedTx.offset, OFFSET_DEST_CHAIN_ID)))\n }\n }\n\n /// @notice Extracts the origin sender from the encoded transaction.\n function originSender(bytes calldata encodedTx) internal pure returns (address originSender_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n originSender_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_SENDER)))\n }\n }\n\n /// @notice Extracts the destination recipient from the encoded transaction.\n function destRecipient(bytes calldata encodedTx) internal pure returns (address destRecipient_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n destRecipient_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_DEST_RECIPIENT)))\n }\n }\n\n /// @notice Extracts the origin token from the encoded transaction.\n function originToken(bytes calldata encodedTx) internal pure returns (address originToken_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n originToken_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_TOKEN)))\n }\n }\n\n /// @notice Extracts the destination token from the encoded transaction.\n function destToken(bytes calldata encodedTx) internal pure returns (address destToken_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n destToken_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_DEST_TOKEN)))\n }\n }\n\n /// @notice Extracts the origin amount from the encoded transaction.\n function originAmount(bytes calldata encodedTx) internal pure returns (uint256 originAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n originAmount_ := calldataload(add(encodedTx.offset, OFFSET_ORIGIN_AMOUNT))\n }\n }\n\n /// @notice Extracts the destination amount from the encoded transaction.\n function destAmount(bytes calldata encodedTx) internal pure returns (uint256 destAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n destAmount_ := calldataload(add(encodedTx.offset, OFFSET_DEST_AMOUNT))\n }\n }\n\n /// @notice Extracts the origin fee amount from the encoded transaction.\n function originFeeAmount(bytes calldata encodedTx) internal pure returns (uint256 originFeeAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n originFeeAmount_ := calldataload(add(encodedTx.offset, OFFSET_ORIGIN_FEE_AMOUNT))\n }\n }\n\n /// @notice Extracts the deadline from the encoded transaction.\n function deadline(bytes calldata encodedTx) internal pure returns (uint256 deadline_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n deadline_ := calldataload(add(encodedTx.offset, OFFSET_DEADLINE))\n }\n }\n\n /// @notice Extracts the nonce from the encoded transaction.\n function nonce(bytes calldata encodedTx) internal pure returns (uint256 nonce_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n nonce_ := calldataload(add(encodedTx.offset, OFFSET_NONCE))\n }\n }\n\n /// @notice Extracts the exclusivity relayer from the encoded transaction.\n function exclusivityRelayer(bytes calldata encodedTx) internal pure returns (address exclusivityRelayer_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n exclusivityRelayer_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_EXCLUSIVITY_RELAYER)))\n }\n }\n\n /// @notice Extracts the exclusivity end time from the encoded transaction.\n function exclusivityEndTime(bytes calldata encodedTx) internal pure returns (uint256 exclusivityEndTime_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n exclusivityEndTime_ := calldataload(add(encodedTx.offset, OFFSET_EXCLUSIVITY_END_TIME))\n }\n }\n\n /// @notice Extracts the Zap's native value from the encoded transaction.\n function zapNative(bytes calldata encodedTx) internal pure returns (uint256 zapNative_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n zapNative_ := calldataload(add(encodedTx.offset, OFFSET_ZAP_NATIVE))\n }\n }\n\n /// @notice Extracts the Zap's data from the encoded transaction.\n function zapData(bytes calldata encodedTx) internal pure returns (bytes calldata zapData_) {\n zapData_ = encodedTx[OFFSET_ZAP_DATA:];\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/AdminV2.sol\n\ncontract AdminV2 is AccessControlEnumerable, IAdminV2, IAdminV2Errors {\n using SafeERC20 for IERC20;\n\n /// @notice Address reserved for native gas token (ETH on Ethereum and most L2s, AVAX on Avalanche, etc)\n address public constant NATIVE_GAS_TOKEN = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Role identifier for Quoter API's off-chain authentication.\n /// @dev Only addresses with this role can post FastBridge quotes to the API.\n bytes32 public constant QUOTER_ROLE = keccak256(\"QUOTER_ROLE\");\n\n /// @notice Role identifier for Prover's on-chain authentication in FastBridge.\n /// @dev Only addresses with this role can provide proofs that a FastBridge request has been relayed.\n bytes32 public constant PROVER_ROLE = keccak256(\"PROVER_ROLE\");\n\n /// @notice Role identifier for Guard's on-chain authentication in FastBridge.\n /// @dev Only addresses with this role can dispute submitted relay proofs during the dispute period.\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n\n /// @notice Role identifier for Canceler's on-chain authentication in FastBridge.\n /// @dev Only addresses with this role can cancel a FastBridge transaction without the cancel delay.\n bytes32 public constant CANCELER_ROLE = keccak256(\"CANCELER_ROLE\");\n\n /// @notice Role identifier for Governor's on-chain administrative authority.\n /// @dev Only addresses with this role can perform administrative tasks within the contract.\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n /// @notice Denominator for fee rates, represents 100%.\n uint256 public constant FEE_BPS = 1e6;\n /// @notice Maximum protocol fee rate: 1% on origin amount.\n uint256 public constant FEE_RATE_MAX = 0.01e6;\n\n /// @notice Minimum cancel delay that can be set by the governor.\n uint256 public constant MIN_CANCEL_DELAY = 1 hours;\n /// @notice Default cancel delay set during the contract deployment.\n uint256 public constant DEFAULT_CANCEL_DELAY = 1 days;\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Delay for a transaction after which it could be permisionlessly cancelled\n uint256 public cancelDelay;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Use ZapNative V2 requests instead.\n uint256 public immutable chainGasAmount = 0;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n _setCancelDelay(DEFAULT_CANCEL_DELAY);\n }\n\n /// @notice Allows the contract governor to set the cancel delay. The cancel delay is the time after the transaction\n /// deadline after which it can be permissionlessly cancelled, if it hasn't been proven by any of the Relayers.\n function setCancelDelay(uint256 newCancelDelay) external onlyRole(GOVERNOR_ROLE) {\n _setCancelDelay(newCancelDelay);\n }\n\n /// @notice Allows the contract governor to set the protocol fee rate. The protocol fee is taken from the origin\n /// amount only for completed and claimed transactions.\n /// @dev The protocol fee is abstracted away from the relayers, they always operate using the amounts after fees:\n /// what they see as the origin amount emitted in the log is what they get credited with.\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n if (newFeeRate \u003e FEE_RATE_MAX) revert FeeRateAboveMax();\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n /// @notice Allows the contract governor to sweep the accumulated protocol fees in the contract.\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n emit FeesSwept(token, recipient, feeAmount);\n /// Sweep the fees as the last transaction action\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(recipient), feeAmount);\n } else {\n IERC20(token).safeTransfer(recipient, feeAmount);\n }\n }\n\n /// @notice Internal function to set the cancel delay. Security checks are performed outside of this function.\n function _setCancelDelay(uint256 newCancelDelay) private {\n if (newCancelDelay \u003c MIN_CANCEL_DELAY) revert CancelDelayBelowMin();\n uint256 oldCancelDelay = cancelDelay;\n cancelDelay = newCancelDelay;\n emit CancelDelayUpdated(oldCancelDelay, newCancelDelay);\n }\n}\n\n// contracts/FastBridgeV2.sol\n\n/// @notice FastBridgeV2 is a contract for bridging tokens across chains.\ncontract FastBridgeV2 is AdminV2, MulticallTarget, IFastBridgeV2, IFastBridgeV2Errors {\n using BridgeTransactionV2Lib for bytes;\n using SafeERC20 for IERC20;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n /// @notice Maximum length of accepted zapData\n uint256 public constant MAX_ZAP_DATA_LENGTH = 2 ** 16 - 1;\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeTxDetails) public bridgeTxDetails;\n /// @notice Relay details on destination chain\n mapping(bytes32 =\u003e BridgeRelay) public bridgeRelayDetails;\n /// @notice Unique bridge nonces tracked per originSender\n mapping(address =\u003e uint256) public senderNonces;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Replaced by senderNonces\n uint256 public immutable nonce = 0;\n /// @notice the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) AdminV2(_owner) {\n deployBlock = block.number;\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n bridge({\n params: params,\n paramsV2: BridgeParamsV2({\n quoteRelayer: address(0),\n quoteExclusivitySeconds: 0,\n quoteId: bytes(\"\"),\n zapNative: 0,\n zapData: bytes(\"\")\n })\n });\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes calldata request) external payable {\n // relay override will validate the request\n relay({request: request, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes calldata request, bytes32 destTxHash) external {\n request.validateV2();\n prove({transactionId: keccak256(request), destTxHash: destTxHash, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridgeV2\n function claim(bytes calldata request) external {\n // claim override will validate the request\n claim({request: request, to: address(0)});\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Aggregate the read operations from the same storage slot\n address disputedRelayer = $.proofRelayer;\n BridgeStatus status = $.status;\n uint56 proofBlockTimestamp = $.proofBlockTimestamp;\n // Can only dispute a RELAYER_PROVED transaction within the dispute period\n if (status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(proofBlockTimestamp) \u003e DISPUTE_PERIOD) {\n revert DisputePeriodPassed();\n }\n // Update status to REQUESTED and delete the disputed proof details\n // Note: these are storage writes\n $.status = BridgeStatus.REQUESTED;\n $.proofRelayer = address(0);\n $.proofBlockTimestamp = 0;\n\n emit BridgeProofDisputed(transactionId, disputedRelayer);\n }\n\n /// Note: this function is deprecated and will be removed in a future version.\n /// @inheritdoc IFastBridge\n function refund(bytes calldata request) external {\n cancel(request);\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // The correct relayer can only claim a RELAYER_PROVED transaction after the dispute period\n if ($.status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if ($.proofRelayer != relayer) revert SenderIncorrect();\n return _timeSince($.proofBlockTimestamp) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n /// @dev This method is added to achieve backwards compatibility with decoding requests into V1 structs:\n /// - `zapNative` is partially reported as a zero/non-zero flag\n /// - `zapData` is ignored\n /// In order to process all kinds of requests use getBridgeTransactionV2 instead.\n function getBridgeTransaction(bytes calldata request) external view returns (BridgeTransaction memory) {\n // Try decoding into V2 struct first. This will revert if V1 struct is passed\n try this.getBridgeTransactionV2(request) returns (BridgeTransactionV2 memory txV2) {\n // Note: we entirely ignore the zapData field, as it was not present in V1\n return BridgeTransaction({\n originChainId: txV2.originChainId,\n destChainId: txV2.destChainId,\n originSender: txV2.originSender,\n destRecipient: txV2.destRecipient,\n originToken: txV2.originToken,\n destToken: txV2.destToken,\n originAmount: txV2.originAmount,\n destAmount: txV2.destAmount,\n originFeeAmount: txV2.originFeeAmount,\n sendChainGas: txV2.zapNative != 0,\n deadline: txV2.deadline,\n nonce: txV2.nonce\n });\n } catch {\n // Fallback to V1 struct\n return abi.decode(request, (BridgeTransaction));\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function getBridgeTransactionV2(bytes calldata request) external pure returns (BridgeTransactionV2 memory) {\n request.validateV2();\n return BridgeTransactionV2Lib.decodeV2(request);\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) public payable {\n int256 exclusivityEndTime = 0;\n // if relayer exclusivity is not intended for this bridge, set exclusivityEndTime to static zero\n // otherwise, set exclusivity to expire at the current block ts offset by quoteExclusivitySeconds\n if (paramsV2.quoteRelayer != address(0)) {\n exclusivityEndTime = int256(block.timestamp) + paramsV2.quoteExclusivitySeconds;\n }\n _validateBridgeParams(params, paramsV2, exclusivityEndTime);\n\n // transfer tokens to bridge contract\n /// @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _takeBridgedUserAsset(params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) {\n originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n }\n\n // set status to requested\n bytes memory request = BridgeTransactionV2Lib.encodeV2(\n BridgeTransactionV2({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n deadline: params.deadline,\n nonce: senderNonces[params.sender]++, // increment nonce on every bridge\n exclusivityRelayer: paramsV2.quoteRelayer,\n // We checked exclusivityEndTime to be in range [0 .. params.deadline] above, so can safely cast\n exclusivityEndTime: uint256(exclusivityEndTime),\n zapNative: paramsV2.zapNative,\n zapData: paramsV2.zapData\n })\n );\n bytes32 transactionId = keccak256(request);\n // Note: the tx status will be updated throughout the tx lifecycle, while destChainId is set once here\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n bridgeTxDetails[transactionId].destChainId = params.dstChainId;\n\n emit BridgeRequested({\n transactionId: transactionId,\n sender: params.sender,\n request: request,\n destChainId: params.dstChainId,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n sendChainGas: paramsV2.zapNative != 0\n });\n emit BridgeQuoteDetails(transactionId, paramsV2.quoteId);\n }\n\n /// @inheritdoc IFastBridgeV2\n function relay(bytes calldata request, address relayer) public payable {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n _validateRelayParams(request, transactionId, relayer);\n // mark bridge transaction as relayed\n bridgeRelayDetails[transactionId] =\n BridgeRelay({blockNumber: uint48(block.number), blockTimestamp: uint48(block.timestamp), relayer: relayer});\n\n // transfer tokens to recipient on destination chain and trigger Zap if requested\n address to = request.destRecipient();\n address token = request.destToken();\n uint256 amount = request.destAmount();\n uint256 zapNative = request.zapNative();\n\n // Emit the event before any external calls\n emit BridgeRelayed({\n transactionId: transactionId,\n relayer: relayer,\n to: to,\n originChainId: request.originChainId(),\n originToken: request.originToken(),\n destToken: token,\n originAmount: request.originAmount(),\n destAmount: amount,\n chainGasAmount: zapNative\n });\n\n // All state changes have been done at this point, can proceed to the external calls.\n // This follows the checks-effects-interactions pattern to mitigate potential reentrancy attacks.\n if (token == NATIVE_GAS_TOKEN) {\n // For the native gas token, additional zapNative is not allowed\n if (zapNative != 0) revert ZapNativeNotSupported();\n // Check that the correct msg.value was sent\n if (msg.value != amount) revert MsgValueIncorrect();\n // Don't do a native transfer yet: we will handle it alongside the Zap below\n } else {\n // For ERC20s, we check that the correct msg.value was sent\n if (msg.value != zapNative) revert MsgValueIncorrect();\n // We need to transfer the tokens from the Relayer to the recipient first before performing an\n // optional post-transfer Zap.\n IERC20(token).safeTransferFrom(msg.sender, to, amount);\n }\n // At this point we have done:\n // - Transferred the requested amount of ERC20 tokens to the recipient.\n // At this point we have confirmed:\n // - For ERC20s: msg.value matches the requested zapNative amount.\n // - For the native gas token: msg.value matches the requested destAmount.\n // Remaining optional things to do:\n // - Forward the full msg.value to the recipient (if non-zero).\n // - Trigger a Zap (if zapData is present).\n bytes calldata zapData = request.zapData();\n if (zapData.length != 0) {\n // Zap Data is present: Zap has been requested by the recipient. Trigger it forwarding the full msg.value.\n\n // Note: if token has a fee on transfers, the recipient will have received less than `amount`.\n // This is a very niche edge case and should be handled by the recipient contract.\n _triggerZapWithChecks({recipient: to, token: token, amount: amount, zapData: zapData});\n } else if (msg.value != 0) {\n // Zap Data is missing, but msg.value was sent. This could happen in two different cases:\n // - Relay with the native gas token is happening.\n // - Relay with ERC20 is happening, with a `zapNative \u003e 0` request.\n // In both cases, we need to transfer the full msg.value to the recipient.\n Address.sendValue(payable(to), msg.value);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) public onlyRole(PROVER_ROLE) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n\n // Can only prove a REQUESTED transaction\n if ($.status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n // Update status to RELAYER_PROVED and store the proof details\n // Note: these are storage writes\n $.status = BridgeStatus.RELAYER_PROVED;\n $.proofBlockTimestamp = uint56(block.timestamp);\n $.proofRelayer = relayer;\n\n emit BridgeProofProvided(transactionId, relayer, destTxHash);\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes calldata request, address to) public {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Aggregate the read operations from the same storage slot\n address proofRelayer = $.proofRelayer;\n BridgeStatus status = $.status;\n uint56 proofBlockTimestamp = $.proofBlockTimestamp;\n\n // Can only claim a RELAYER_PROVED transaction after the dispute period\n if (status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(proofBlockTimestamp) \u003c= DISPUTE_PERIOD) {\n revert DisputePeriodNotPassed();\n }\n\n if (to == address(0)) {\n // Anyone could claim the funds to the proven relayer on their behalf\n to = proofRelayer;\n } else if (proofRelayer != msg.sender) {\n // Only the proven relayer could specify an address to claim the funds to\n revert SenderIncorrect();\n }\n\n // Update status to RELAYER_CLAIMED and transfer the origin collateral to the specified claim address\n // Note: this is a storage write\n $.status = BridgeStatus.RELAYER_CLAIMED;\n\n address token = request.originToken();\n uint256 amount = request.originAmount();\n // Update protocol fees if origin fee amount exists\n uint256 originFeeAmount = request.originFeeAmount();\n if (originFeeAmount \u003e 0) protocolFees[token] += originFeeAmount;\n // Emit the event before any external calls\n emit BridgeDepositClaimed(transactionId, proofRelayer, to, token, amount);\n // Complete the relayer claim as the last transaction action\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(to), amount);\n } else {\n IERC20(token).safeTransfer(to, amount);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function cancel(bytes calldata request) public {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Can only cancel a REQUESTED transaction after its deadline expires\n if ($.status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n uint256 deadline = request.deadline();\n // Permissionless cancel is only allowed after `cancelDelay` on top of the deadline\n if (!hasRole(CANCELER_ROLE, msg.sender)) deadline += cancelDelay;\n if (block.timestamp \u003c= deadline) revert DeadlineNotExceeded();\n // Update status to REFUNDED and return the full amount (collateral + protocol fees) to the original sender.\n // The protocol fees are only updated when the transaction is claimed, so we don't need to update them here.\n // Note: this is a storage write\n $.status = BridgeStatus.REFUNDED;\n\n address to = request.originSender();\n address token = request.originToken();\n uint256 amount = request.originAmount() + request.originFeeAmount();\n // Emit the event before any external calls\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n // Complete the user cancel as the last transaction action\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(to), amount);\n } else {\n IERC20(token).safeTransfer(to, amount);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeStatuses(bytes32 transactionId) public view returns (BridgeStatus status) {\n return bridgeTxDetails[transactionId].status;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeProofs(bytes32 transactionId) public view returns (uint96 timestamp, address relayer) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n\n timestamp = $.proofBlockTimestamp;\n relayer = $.proofRelayer;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeRelays(bytes32 transactionId) public view returns (bool) {\n // has this transactionId been relayed?\n return bridgeRelayDetails[transactionId].relayer != address(0);\n }\n\n /// @notice Takes the bridged asset from the user into FastBridgeV2 custody. It will be later\n /// claimed by the relayer who completed the relay on destination chain, or transferred back to the user\n /// via the cancel function should no one complete the relay.\n function _takeBridgedUserAsset(address token, uint256 amount) internal returns (uint256 amountTaken) {\n if (token == NATIVE_GAS_TOKEN) {\n // For the native gas token, we just need to check that the supplied msg.value is correct.\n // Supplied `msg.value` is already in FastBridgeV2 custody.\n if (amount != msg.value) revert MsgValueIncorrect();\n amountTaken = msg.value;\n } else {\n // For ERC20s, token is explicitly transferred from the user to FastBridgeV2.\n // We don't allow non-zero `msg.value` to avoid extra funds from being stuck in FastBridgeV2.\n if (msg.value != 0) revert MsgValueIncorrect();\n // Throw an explicit error if the provided token address is not a contract\n if (token.code.length == 0) revert TokenNotContract();\n amountTaken = IERC20(token).balanceOf(address(this));\n IERC20(token).safeTransferFrom(msg.sender, address(this), amount);\n // Use the balance difference as the amount taken in case of fee on transfer tokens.\n amountTaken = IERC20(token).balanceOf(address(this)) - amountTaken;\n }\n }\n\n /// @notice Calls the Recipient's hook function with the specified zapData and performs\n /// all the necessary checks for the returned value.\n function _triggerZapWithChecks(address recipient, address token, uint256 amount, bytes calldata zapData) internal {\n // This will bubble any revert messages from the hook function\n bytes memory returnData = Address.functionCallWithValue({\n target: recipient,\n data: abi.encodeCall(IZapRecipient.zap, (token, amount, zapData)),\n // Note: see `relay()` for reasoning behind passing msg.value\n value: msg.value\n });\n // Explicit revert if no return data at all\n if (returnData.length == 0) revert RecipientNoReturnValue();\n // Check that exactly a single return value was returned\n if (returnData.length != 32) revert RecipientIncorrectReturnValue();\n // Return value should be abi-encoded hook function selector\n if (bytes32(returnData) != bytes32(IZapRecipient.zap.selector)) {\n revert RecipientIncorrectReturnValue();\n }\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint56(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint56).max but\n /// proof.timestamp \u003c type(uint56).max via unchecked statement\n /// @param proofBlockTimestamp The bridge proof block timestamp\n /// @return delta Time delta since proof submitted\n function _timeSince(uint56 proofBlockTimestamp) internal view returns (uint256 delta) {\n unchecked {\n delta = uint56(block.timestamp) - proofBlockTimestamp;\n }\n }\n\n /// @notice Performs all the necessary checks for a bridge to happen.\n /// @dev There's no good way to refactor this function to reduce cyclomatic complexity due to\n /// the number of checks that need to be performed, so we skip the code-complexity rule here.\n // solhint-disable-next-line code-complexity\n function _validateBridgeParams(\n BridgeParams memory params,\n BridgeParamsV2 memory paramsV2,\n int256 exclusivityEndTime\n )\n internal\n view\n {\n // Check V1 (legacy) params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.sender == address(0) || params.to == address(0)) revert ZeroAddress();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n // Check V2 params\n if (paramsV2.zapData.length \u003e MAX_ZAP_DATA_LENGTH) revert ZapDataLengthAboveMax();\n if (paramsV2.zapNative != 0 \u0026\u0026 params.destToken == NATIVE_GAS_TOKEN) {\n revert ZapNativeNotSupported();\n }\n // exclusivityEndTime must be in range [0 .. params.deadline]\n if (exclusivityEndTime \u003c 0 || exclusivityEndTime \u003e int256(params.deadline)) {\n revert ExclusivityParamsIncorrect();\n }\n }\n\n /// @notice Performs all the necessary checks for a relay to happen.\n function _validateRelayParams(bytes calldata request, bytes32 transactionId, address relayer) internal view {\n if (relayer == address(0)) revert ZeroAddress();\n // Check if the transaction has already been relayed\n if (bridgeRelays(transactionId)) revert TransactionRelayed();\n if (request.destChainId() != block.chainid) revert ChainIncorrect();\n // Check the deadline for relay to happen\n if (block.timestamp \u003e request.deadline()) revert DeadlineExceeded();\n // Check the exclusivity period, if it is still ongoing\n address exclRelayer = request.exclusivityRelayer();\n if (exclRelayer != address(0) \u0026\u0026 exclRelayer != relayer \u0026\u0026 block.timestamp \u003c= request.exclusivityEndTime()) {\n revert ExclusivityPeriodNotPassed();\n }\n }\n}\n","language":"Solidity","languageVersion":"0.8.24","compilerVersion":"0.8.24","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"49473:11496:0:-:0;;;;;;;;;;;;;;;-1:-1:-1;;;49473:11496:0;;;;;;;;;;;;;;;;;","srcMapRuntime":"49473:11496:0:-:0;;;;;;;;","abiDefinition":[{"inputs":[],"name":"BridgeTransactionV2__InvalidEncodedTx","type":"error"},{"inputs":[{"internalType":"uint16","name":"version","type":"uint16"}],"name":"BridgeTransactionV2__UnsupportedVersion","type":"error"}],"userDoc":{"kind":"user","methods":{},"version":1},"developerDoc":{"kind":"dev","methods":{},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[],\"name\":\"BridgeTransactionV2__InvalidEncodedTx\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint16\",\"name\":\"version\",\"type\":\"uint16\"}],\"name\":\"BridgeTransactionV2__UnsupportedVersion\",\"type\":\"error\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeV2.sol\":\"BridgeTransactionV2Lib\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeV2.sol\":{\"keccak256\":\"0xac79c463688a682ca706a4ef95e7817b83548cdfa8182ba0426ac7e5e07613d8\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://b3ecb7097381287cafc3a73f3a2bb03565115ebb682a85064e0b0dc2f7e2919d\",\"dweb:/ipfs/QmatruW3nYZTksf3CeQ8wwiAG4c7xoEJBEp6drHPtFLBRK\"]}},\"version\":1}"},"hashes":{}},"solidity/FastBridgeV2.sol:Context":{"code":"0x","runtime-code":"0x","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.24 ^0.8.20 ^0.8.4;\n\n// contracts/interfaces/IAdminV2.sol\n\ninterface IAdminV2 {\n event CancelDelayUpdated(uint256 oldCancelDelay, uint256 newCancelDelay);\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n function setCancelDelay(uint256 newCancelDelay) external;\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n}\n\n// contracts/interfaces/IAdminV2Errors.sol\n\ninterface IAdminV2Errors {\n error CancelDelayBelowMin();\n error FeeRateAboveMax();\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IFastBridgeV2Errors.sol\n\ninterface IFastBridgeV2Errors {\n error AmountIncorrect();\n error ChainIncorrect();\n error ExclusivityParamsIncorrect();\n error MsgValueIncorrect();\n error SenderIncorrect();\n error StatusIncorrect();\n error TokenNotContract();\n error ZapDataLengthAboveMax();\n error ZapNativeNotSupported();\n error ZeroAddress();\n\n error RecipientIncorrectReturnValue();\n error RecipientNoReturnValue();\n\n error DeadlineExceeded();\n error DeadlineNotExceeded();\n error DeadlineTooShort();\n error DisputePeriodNotPassed();\n error DisputePeriodPassed();\n error ExclusivityPeriodNotPassed();\n\n error TransactionRelayed();\n}\n\n// contracts/interfaces/IMulticallTarget.sol\n\n/// @notice Interface for a contract that can be called multiple times by the same caller. Inspired by MulticallV3:\n/// https://github.com/mds1/multicall/blob/master/src/Multicall3.sol\ninterface IMulticallTarget {\n struct Result {\n bool success;\n bytes returnData;\n }\n\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external;\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results);\n}\n\n// contracts/interfaces/IZapRecipient.sol\n\ninterface IZapRecipient {\n function zap(address token, uint256 amount, bytes memory zapData) external payable returns (bytes4);\n}\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// contracts/interfaces/IFastBridgeV2.sol\n\ninterface IFastBridgeV2 is IFastBridge {\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n struct BridgeTxDetails {\n BridgeStatus status;\n uint32 destChainId;\n uint56 proofBlockTimestamp;\n address proofRelayer;\n }\n\n struct BridgeRelay {\n uint48 blockNumber;\n uint48 blockTimestamp;\n address relayer;\n }\n\n /// @notice New params introduced in the FastBridgeV2.\n /// We are passing fields from the older BridgeParams struct outside of this struct\n /// for backwards compatibility.\n /// Note: quoteRelayer and quoteExclusivitySeconds are either both zero (indicating no exclusivity)\n /// or both non-zero (indicating exclusivity for the given period).\n /// Note: zapNative \u003e 0 can NOT be used with destToken = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE (native token)\n /// @param quoteRelayer Relayer that provided the quote for the transaction\n /// @param quoteExclusivitySeconds Period of time the quote relayer is guaranteed exclusivity after user's deposit\n /// @param quoteId Unique quote identifier used for tracking the quote\n /// @param zapNative ETH value to send to the recipient (if any)\n /// @param zapData Parameters for the Zap to the destination recipient (if any)\n struct BridgeParamsV2 {\n address quoteRelayer;\n int256 quoteExclusivitySeconds;\n bytes quoteId;\n uint256 zapNative;\n bytes zapData;\n }\n\n /// @notice Updated bridge transaction struct to include parameters introduced in FastBridgeV2.\n /// Note: only `exclusivityRelayer` can fill such a transaction until `exclusivityEndTime`.\n struct BridgeTransactionV2 {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n // Note: sendChainGas flag from V1 is deprecated\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n address exclusivityRelayer;\n uint256 exclusivityEndTime;\n uint256 zapNative; // ETH value to send to the recipient (if any)\n bytes zapData; // data to pass for the Zap action (if any)\n }\n\n event BridgeQuoteDetails(bytes32 indexed transactionId, bytes quoteId);\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability\n /// to provide temporary exclusivity fill rights for the quote relayer.\n /// @param params The parameters required to bridge\n /// @param paramsV2 The parameters for exclusivity fill rights (optional, can be left empty)\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function relay(bytes memory request, address relayer) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param transactionId The transaction id associated with the encoded bridge transaction to prove\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital.\n /// @notice Can only send funds to the relayer address on the proof.\n /// @param request The encoded bridge transaction to claim on origin chain\n function claim(bytes memory request) external;\n\n /// @notice Cancels an outstanding bridge transaction in case optimistic bridging failed and returns the full amount\n /// to the original sender.\n /// @param request The encoded bridge transaction to refund\n function cancel(bytes memory request) external;\n\n /// @notice Checks if a transaction has been relayed\n /// @param transactionId The ID of the transaction to check\n /// @return True if the transaction has been relayed, false otherwise\n function bridgeRelays(bytes32 transactionId) external view returns (bool);\n\n /// @notice Returns the status of a bridge transaction\n /// @param transactionId The ID of the bridge transaction\n /// @return BridgeStatus Status of the bridge transaction\n function bridgeStatuses(bytes32 transactionId) external view returns (BridgeStatus);\n\n /// @notice Returns the timestamp and relayer of a bridge proof\n /// @param transactionId The ID of the bridge transaction\n /// @return timestamp The timestamp of the bridge proof\n /// @return relayer The relayer address of the bridge proof\n function bridgeProofs(bytes32 transactionId) external view returns (uint96 timestamp, address relayer);\n\n /// @notice Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\n /// @param request The bridge request to decode\n function getBridgeTransactionV2(bytes memory request) external view returns (BridgeTransactionV2 memory);\n}\n\n// contracts/utils/MulticallTarget.sol\n\n// solhint-disable avoid-low-level-calls\n/// @notice Template for a contract that supports batched calls (preserving the msg.sender).\n/// Only calls with zero msg.value could be batched.\nabstract contract MulticallTarget is IMulticallTarget {\n error MulticallTarget__UndeterminedRevert();\n\n /// @notice Perform a batched call to this contract, preserving the msg.sender.\n /// The return data from each call is discarded.\n /// @dev The method is non-payable, so only calls with `msg.value == 0` could be batched.\n /// It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag.\n /// Otherwise, the whole batch call will be reverted with the original revert reason.\n /// @param data List of abi-encoded calldata for the calls to perform.\n /// @param ignoreReverts Whether to ignore the revert errors from the calls.\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external {\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\n if (!success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(result);\n }\n }\n }\n\n /// @notice Perform a batched call to this contract, preserving the msg.sender.\n /// The return data from each call is preserved.\n /// @dev The method is non-payable, so only calls with `msg.value == 0` could be batched.\n /// It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag.\n /// Otherwise, the whole batch call will be reverted with the original revert reason.\n /// @param data List of abi-encoded calldata for the calls to perform.\n /// @param ignoreReverts Whether to ignore the revert errors from the calls.\n /// @return results List of results from the calls: `(success, returnData)`.\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results)\n {\n results = new Result[](data.length);\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (results[i].success, results[i].returnData) = address(this).delegatecall(data[i]);\n if (!results[i].success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(results[i].returnData);\n }\n }\n }\n\n /// @dev Bubbles the revert message from the underlying call.\n /// Note: preserves the same custom error or revert string, if one was used.\n /// Source: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v5.0.2/contracts/utils/Address.sol#L143-L158\n function _bubbleRevert(bytes memory returnData) internal pure {\n // Look for revert reason and bubble it up if present\n if (returnData.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n // solhint-disable-next-line no-inline-assembly\n assembly {\n let returndata_size := mload(returnData)\n revert(add(32, returnData), returndata_size)\n }\n } else {\n revert MulticallTarget__UndeterminedRevert();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// contracts/libs/BridgeTransactionV2.sol\n\n// solhint-disable no-inline-assembly\nlibrary BridgeTransactionV2Lib {\n uint16 internal constant VERSION = 2;\n\n // Offsets of the fields in the packed BridgeTransactionV2 struct\n // uint16 version [000 .. 002)\n // uint32 originChainId [002 .. 006)\n // uint32 destChainId [006 .. 010)\n // address originSender [010 .. 030)\n // address destRecipient [030 .. 050)\n // address originToken [050 .. 070)\n // address destToken [070 .. 090)\n // uint256 originAmount [090 .. 122)\n // uint256 destAmount [122 .. 154)\n // uint256 originFeeAmount [154 .. 186)\n // uint256 deadline [186 .. 218)\n // uint256 nonce [218 .. 250)\n // address exclusivityRelayer [250 .. 270)\n // uint256 exclusivityEndTime [270 .. 302)\n // uint256 zapNative [302 .. 334)\n // bytes zapData [334 .. ***)\n\n // forgefmt: disable-start\n uint256 private constant OFFSET_ORIGIN_CHAIN_ID = 2;\n uint256 private constant OFFSET_DEST_CHAIN_ID = 6;\n uint256 private constant OFFSET_ORIGIN_SENDER = 10;\n uint256 private constant OFFSET_DEST_RECIPIENT = 30;\n uint256 private constant OFFSET_ORIGIN_TOKEN = 50;\n uint256 private constant OFFSET_DEST_TOKEN = 70;\n uint256 private constant OFFSET_ORIGIN_AMOUNT = 90;\n uint256 private constant OFFSET_DEST_AMOUNT = 122;\n uint256 private constant OFFSET_ORIGIN_FEE_AMOUNT = 154;\n uint256 private constant OFFSET_DEADLINE = 186;\n uint256 private constant OFFSET_NONCE = 218;\n uint256 private constant OFFSET_EXCLUSIVITY_RELAYER = 250;\n uint256 private constant OFFSET_EXCLUSIVITY_END_TIME = 270;\n uint256 private constant OFFSET_ZAP_NATIVE = 302;\n uint256 private constant OFFSET_ZAP_DATA = 334;\n // forgefmt: disable-end\n\n error BridgeTransactionV2__InvalidEncodedTx();\n error BridgeTransactionV2__UnsupportedVersion(uint16 version);\n\n /// @notice Validates the encoded transaction to be a tightly packed encoded payload for BridgeTransactionV2.\n /// @dev Checks the minimum length and the version, use this function before decoding any of the fields.\n function validateV2(bytes calldata encodedTx) internal pure {\n // Check the minimum length: must at least include all static fields.\n if (encodedTx.length \u003c OFFSET_ZAP_DATA) revert BridgeTransactionV2__InvalidEncodedTx();\n // Once we validated the length, we can be sure that the version field is present.\n uint16 version_ = version(encodedTx);\n if (version_ != VERSION) revert BridgeTransactionV2__UnsupportedVersion(version_);\n }\n\n /// @notice Encodes the BridgeTransactionV2 struct by tightly packing the fields.\n /// @dev `abi.decode` will not work as a result of the tightly packed fields. Use `decodeV2` to decode instead.\n function encodeV2(IFastBridgeV2.BridgeTransactionV2 memory bridgeTx) internal pure returns (bytes memory) {\n // We split the encoding into two parts to avoid stack-too-deep error\n bytes memory firstPart = abi.encodePacked(\n VERSION,\n bridgeTx.originChainId,\n bridgeTx.destChainId,\n bridgeTx.originSender,\n bridgeTx.destRecipient,\n bridgeTx.originToken,\n bridgeTx.destToken,\n bridgeTx.originAmount\n );\n return abi.encodePacked(\n firstPart,\n bridgeTx.destAmount,\n bridgeTx.originFeeAmount,\n // Note: we skip the deprecated `sendChainGas` flag, which was present in BridgeTransaction V1\n bridgeTx.deadline,\n bridgeTx.nonce,\n // New V2 fields: exclusivity\n bridgeTx.exclusivityRelayer,\n bridgeTx.exclusivityEndTime,\n // New V2 fields: Zap\n bridgeTx.zapNative,\n bridgeTx.zapData\n );\n }\n\n /// @notice Decodes the BridgeTransactionV2 struct from the encoded transaction.\n /// @dev Encoded BridgeTransactionV2 struct must be tightly packed.\n /// Use `validateV2` before decoding to ensure the encoded transaction is valid.\n function decodeV2(bytes calldata encodedTx)\n internal\n pure\n returns (IFastBridgeV2.BridgeTransactionV2 memory bridgeTx)\n {\n bridgeTx.originChainId = originChainId(encodedTx);\n bridgeTx.destChainId = destChainId(encodedTx);\n bridgeTx.originSender = originSender(encodedTx);\n bridgeTx.destRecipient = destRecipient(encodedTx);\n bridgeTx.originToken = originToken(encodedTx);\n bridgeTx.destToken = destToken(encodedTx);\n bridgeTx.originAmount = originAmount(encodedTx);\n bridgeTx.destAmount = destAmount(encodedTx);\n bridgeTx.originFeeAmount = originFeeAmount(encodedTx);\n bridgeTx.deadline = deadline(encodedTx);\n bridgeTx.nonce = nonce(encodedTx);\n bridgeTx.exclusivityRelayer = exclusivityRelayer(encodedTx);\n bridgeTx.exclusivityEndTime = exclusivityEndTime(encodedTx);\n bridgeTx.zapNative = zapNative(encodedTx);\n bridgeTx.zapData = zapData(encodedTx);\n }\n\n /// @notice Extracts the version from the encoded transaction.\n function version(bytes calldata encodedTx) internal pure returns (uint16 version_) {\n // Load 32 bytes from the start and shift it 240 bits to the right to get the highest 16 bits.\n assembly {\n version_ := shr(240, calldataload(encodedTx.offset))\n }\n }\n\n /// @notice Extracts the origin chain ID from the encoded transaction.\n function originChainId(bytes calldata encodedTx) internal pure returns (uint32 originChainId_) {\n // Load 32 bytes from the offset and shift it 224 bits to the right to get the highest 32 bits.\n assembly {\n originChainId_ := shr(224, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_CHAIN_ID)))\n }\n }\n\n /// @notice Extracts the destination chain ID from the encoded transaction.\n function destChainId(bytes calldata encodedTx) internal pure returns (uint32 destChainId_) {\n // Load 32 bytes from the offset and shift it 224 bits to the right to get the highest 32 bits.\n assembly {\n destChainId_ := shr(224, calldataload(add(encodedTx.offset, OFFSET_DEST_CHAIN_ID)))\n }\n }\n\n /// @notice Extracts the origin sender from the encoded transaction.\n function originSender(bytes calldata encodedTx) internal pure returns (address originSender_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n originSender_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_SENDER)))\n }\n }\n\n /// @notice Extracts the destination recipient from the encoded transaction.\n function destRecipient(bytes calldata encodedTx) internal pure returns (address destRecipient_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n destRecipient_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_DEST_RECIPIENT)))\n }\n }\n\n /// @notice Extracts the origin token from the encoded transaction.\n function originToken(bytes calldata encodedTx) internal pure returns (address originToken_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n originToken_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_TOKEN)))\n }\n }\n\n /// @notice Extracts the destination token from the encoded transaction.\n function destToken(bytes calldata encodedTx) internal pure returns (address destToken_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n destToken_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_DEST_TOKEN)))\n }\n }\n\n /// @notice Extracts the origin amount from the encoded transaction.\n function originAmount(bytes calldata encodedTx) internal pure returns (uint256 originAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n originAmount_ := calldataload(add(encodedTx.offset, OFFSET_ORIGIN_AMOUNT))\n }\n }\n\n /// @notice Extracts the destination amount from the encoded transaction.\n function destAmount(bytes calldata encodedTx) internal pure returns (uint256 destAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n destAmount_ := calldataload(add(encodedTx.offset, OFFSET_DEST_AMOUNT))\n }\n }\n\n /// @notice Extracts the origin fee amount from the encoded transaction.\n function originFeeAmount(bytes calldata encodedTx) internal pure returns (uint256 originFeeAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n originFeeAmount_ := calldataload(add(encodedTx.offset, OFFSET_ORIGIN_FEE_AMOUNT))\n }\n }\n\n /// @notice Extracts the deadline from the encoded transaction.\n function deadline(bytes calldata encodedTx) internal pure returns (uint256 deadline_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n deadline_ := calldataload(add(encodedTx.offset, OFFSET_DEADLINE))\n }\n }\n\n /// @notice Extracts the nonce from the encoded transaction.\n function nonce(bytes calldata encodedTx) internal pure returns (uint256 nonce_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n nonce_ := calldataload(add(encodedTx.offset, OFFSET_NONCE))\n }\n }\n\n /// @notice Extracts the exclusivity relayer from the encoded transaction.\n function exclusivityRelayer(bytes calldata encodedTx) internal pure returns (address exclusivityRelayer_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n exclusivityRelayer_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_EXCLUSIVITY_RELAYER)))\n }\n }\n\n /// @notice Extracts the exclusivity end time from the encoded transaction.\n function exclusivityEndTime(bytes calldata encodedTx) internal pure returns (uint256 exclusivityEndTime_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n exclusivityEndTime_ := calldataload(add(encodedTx.offset, OFFSET_EXCLUSIVITY_END_TIME))\n }\n }\n\n /// @notice Extracts the Zap's native value from the encoded transaction.\n function zapNative(bytes calldata encodedTx) internal pure returns (uint256 zapNative_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n zapNative_ := calldataload(add(encodedTx.offset, OFFSET_ZAP_NATIVE))\n }\n }\n\n /// @notice Extracts the Zap's data from the encoded transaction.\n function zapData(bytes calldata encodedTx) internal pure returns (bytes calldata zapData_) {\n zapData_ = encodedTx[OFFSET_ZAP_DATA:];\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/AdminV2.sol\n\ncontract AdminV2 is AccessControlEnumerable, IAdminV2, IAdminV2Errors {\n using SafeERC20 for IERC20;\n\n /// @notice Address reserved for native gas token (ETH on Ethereum and most L2s, AVAX on Avalanche, etc)\n address public constant NATIVE_GAS_TOKEN = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Role identifier for Quoter API's off-chain authentication.\n /// @dev Only addresses with this role can post FastBridge quotes to the API.\n bytes32 public constant QUOTER_ROLE = keccak256(\"QUOTER_ROLE\");\n\n /// @notice Role identifier for Prover's on-chain authentication in FastBridge.\n /// @dev Only addresses with this role can provide proofs that a FastBridge request has been relayed.\n bytes32 public constant PROVER_ROLE = keccak256(\"PROVER_ROLE\");\n\n /// @notice Role identifier for Guard's on-chain authentication in FastBridge.\n /// @dev Only addresses with this role can dispute submitted relay proofs during the dispute period.\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n\n /// @notice Role identifier for Canceler's on-chain authentication in FastBridge.\n /// @dev Only addresses with this role can cancel a FastBridge transaction without the cancel delay.\n bytes32 public constant CANCELER_ROLE = keccak256(\"CANCELER_ROLE\");\n\n /// @notice Role identifier for Governor's on-chain administrative authority.\n /// @dev Only addresses with this role can perform administrative tasks within the contract.\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n /// @notice Denominator for fee rates, represents 100%.\n uint256 public constant FEE_BPS = 1e6;\n /// @notice Maximum protocol fee rate: 1% on origin amount.\n uint256 public constant FEE_RATE_MAX = 0.01e6;\n\n /// @notice Minimum cancel delay that can be set by the governor.\n uint256 public constant MIN_CANCEL_DELAY = 1 hours;\n /// @notice Default cancel delay set during the contract deployment.\n uint256 public constant DEFAULT_CANCEL_DELAY = 1 days;\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Delay for a transaction after which it could be permisionlessly cancelled\n uint256 public cancelDelay;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Use ZapNative V2 requests instead.\n uint256 public immutable chainGasAmount = 0;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n _setCancelDelay(DEFAULT_CANCEL_DELAY);\n }\n\n /// @notice Allows the contract governor to set the cancel delay. The cancel delay is the time after the transaction\n /// deadline after which it can be permissionlessly cancelled, if it hasn't been proven by any of the Relayers.\n function setCancelDelay(uint256 newCancelDelay) external onlyRole(GOVERNOR_ROLE) {\n _setCancelDelay(newCancelDelay);\n }\n\n /// @notice Allows the contract governor to set the protocol fee rate. The protocol fee is taken from the origin\n /// amount only for completed and claimed transactions.\n /// @dev The protocol fee is abstracted away from the relayers, they always operate using the amounts after fees:\n /// what they see as the origin amount emitted in the log is what they get credited with.\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n if (newFeeRate \u003e FEE_RATE_MAX) revert FeeRateAboveMax();\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n /// @notice Allows the contract governor to sweep the accumulated protocol fees in the contract.\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n emit FeesSwept(token, recipient, feeAmount);\n /// Sweep the fees as the last transaction action\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(recipient), feeAmount);\n } else {\n IERC20(token).safeTransfer(recipient, feeAmount);\n }\n }\n\n /// @notice Internal function to set the cancel delay. Security checks are performed outside of this function.\n function _setCancelDelay(uint256 newCancelDelay) private {\n if (newCancelDelay \u003c MIN_CANCEL_DELAY) revert CancelDelayBelowMin();\n uint256 oldCancelDelay = cancelDelay;\n cancelDelay = newCancelDelay;\n emit CancelDelayUpdated(oldCancelDelay, newCancelDelay);\n }\n}\n\n// contracts/FastBridgeV2.sol\n\n/// @notice FastBridgeV2 is a contract for bridging tokens across chains.\ncontract FastBridgeV2 is AdminV2, MulticallTarget, IFastBridgeV2, IFastBridgeV2Errors {\n using BridgeTransactionV2Lib for bytes;\n using SafeERC20 for IERC20;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n /// @notice Maximum length of accepted zapData\n uint256 public constant MAX_ZAP_DATA_LENGTH = 2 ** 16 - 1;\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeTxDetails) public bridgeTxDetails;\n /// @notice Relay details on destination chain\n mapping(bytes32 =\u003e BridgeRelay) public bridgeRelayDetails;\n /// @notice Unique bridge nonces tracked per originSender\n mapping(address =\u003e uint256) public senderNonces;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Replaced by senderNonces\n uint256 public immutable nonce = 0;\n /// @notice the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) AdminV2(_owner) {\n deployBlock = block.number;\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n bridge({\n params: params,\n paramsV2: BridgeParamsV2({\n quoteRelayer: address(0),\n quoteExclusivitySeconds: 0,\n quoteId: bytes(\"\"),\n zapNative: 0,\n zapData: bytes(\"\")\n })\n });\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes calldata request) external payable {\n // relay override will validate the request\n relay({request: request, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes calldata request, bytes32 destTxHash) external {\n request.validateV2();\n prove({transactionId: keccak256(request), destTxHash: destTxHash, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridgeV2\n function claim(bytes calldata request) external {\n // claim override will validate the request\n claim({request: request, to: address(0)});\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Aggregate the read operations from the same storage slot\n address disputedRelayer = $.proofRelayer;\n BridgeStatus status = $.status;\n uint56 proofBlockTimestamp = $.proofBlockTimestamp;\n // Can only dispute a RELAYER_PROVED transaction within the dispute period\n if (status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(proofBlockTimestamp) \u003e DISPUTE_PERIOD) {\n revert DisputePeriodPassed();\n }\n // Update status to REQUESTED and delete the disputed proof details\n // Note: these are storage writes\n $.status = BridgeStatus.REQUESTED;\n $.proofRelayer = address(0);\n $.proofBlockTimestamp = 0;\n\n emit BridgeProofDisputed(transactionId, disputedRelayer);\n }\n\n /// Note: this function is deprecated and will be removed in a future version.\n /// @inheritdoc IFastBridge\n function refund(bytes calldata request) external {\n cancel(request);\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // The correct relayer can only claim a RELAYER_PROVED transaction after the dispute period\n if ($.status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if ($.proofRelayer != relayer) revert SenderIncorrect();\n return _timeSince($.proofBlockTimestamp) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n /// @dev This method is added to achieve backwards compatibility with decoding requests into V1 structs:\n /// - `zapNative` is partially reported as a zero/non-zero flag\n /// - `zapData` is ignored\n /// In order to process all kinds of requests use getBridgeTransactionV2 instead.\n function getBridgeTransaction(bytes calldata request) external view returns (BridgeTransaction memory) {\n // Try decoding into V2 struct first. This will revert if V1 struct is passed\n try this.getBridgeTransactionV2(request) returns (BridgeTransactionV2 memory txV2) {\n // Note: we entirely ignore the zapData field, as it was not present in V1\n return BridgeTransaction({\n originChainId: txV2.originChainId,\n destChainId: txV2.destChainId,\n originSender: txV2.originSender,\n destRecipient: txV2.destRecipient,\n originToken: txV2.originToken,\n destToken: txV2.destToken,\n originAmount: txV2.originAmount,\n destAmount: txV2.destAmount,\n originFeeAmount: txV2.originFeeAmount,\n sendChainGas: txV2.zapNative != 0,\n deadline: txV2.deadline,\n nonce: txV2.nonce\n });\n } catch {\n // Fallback to V1 struct\n return abi.decode(request, (BridgeTransaction));\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function getBridgeTransactionV2(bytes calldata request) external pure returns (BridgeTransactionV2 memory) {\n request.validateV2();\n return BridgeTransactionV2Lib.decodeV2(request);\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) public payable {\n int256 exclusivityEndTime = 0;\n // if relayer exclusivity is not intended for this bridge, set exclusivityEndTime to static zero\n // otherwise, set exclusivity to expire at the current block ts offset by quoteExclusivitySeconds\n if (paramsV2.quoteRelayer != address(0)) {\n exclusivityEndTime = int256(block.timestamp) + paramsV2.quoteExclusivitySeconds;\n }\n _validateBridgeParams(params, paramsV2, exclusivityEndTime);\n\n // transfer tokens to bridge contract\n /// @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _takeBridgedUserAsset(params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) {\n originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n }\n\n // set status to requested\n bytes memory request = BridgeTransactionV2Lib.encodeV2(\n BridgeTransactionV2({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n deadline: params.deadline,\n nonce: senderNonces[params.sender]++, // increment nonce on every bridge\n exclusivityRelayer: paramsV2.quoteRelayer,\n // We checked exclusivityEndTime to be in range [0 .. params.deadline] above, so can safely cast\n exclusivityEndTime: uint256(exclusivityEndTime),\n zapNative: paramsV2.zapNative,\n zapData: paramsV2.zapData\n })\n );\n bytes32 transactionId = keccak256(request);\n // Note: the tx status will be updated throughout the tx lifecycle, while destChainId is set once here\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n bridgeTxDetails[transactionId].destChainId = params.dstChainId;\n\n emit BridgeRequested({\n transactionId: transactionId,\n sender: params.sender,\n request: request,\n destChainId: params.dstChainId,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n sendChainGas: paramsV2.zapNative != 0\n });\n emit BridgeQuoteDetails(transactionId, paramsV2.quoteId);\n }\n\n /// @inheritdoc IFastBridgeV2\n function relay(bytes calldata request, address relayer) public payable {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n _validateRelayParams(request, transactionId, relayer);\n // mark bridge transaction as relayed\n bridgeRelayDetails[transactionId] =\n BridgeRelay({blockNumber: uint48(block.number), blockTimestamp: uint48(block.timestamp), relayer: relayer});\n\n // transfer tokens to recipient on destination chain and trigger Zap if requested\n address to = request.destRecipient();\n address token = request.destToken();\n uint256 amount = request.destAmount();\n uint256 zapNative = request.zapNative();\n\n // Emit the event before any external calls\n emit BridgeRelayed({\n transactionId: transactionId,\n relayer: relayer,\n to: to,\n originChainId: request.originChainId(),\n originToken: request.originToken(),\n destToken: token,\n originAmount: request.originAmount(),\n destAmount: amount,\n chainGasAmount: zapNative\n });\n\n // All state changes have been done at this point, can proceed to the external calls.\n // This follows the checks-effects-interactions pattern to mitigate potential reentrancy attacks.\n if (token == NATIVE_GAS_TOKEN) {\n // For the native gas token, additional zapNative is not allowed\n if (zapNative != 0) revert ZapNativeNotSupported();\n // Check that the correct msg.value was sent\n if (msg.value != amount) revert MsgValueIncorrect();\n // Don't do a native transfer yet: we will handle it alongside the Zap below\n } else {\n // For ERC20s, we check that the correct msg.value was sent\n if (msg.value != zapNative) revert MsgValueIncorrect();\n // We need to transfer the tokens from the Relayer to the recipient first before performing an\n // optional post-transfer Zap.\n IERC20(token).safeTransferFrom(msg.sender, to, amount);\n }\n // At this point we have done:\n // - Transferred the requested amount of ERC20 tokens to the recipient.\n // At this point we have confirmed:\n // - For ERC20s: msg.value matches the requested zapNative amount.\n // - For the native gas token: msg.value matches the requested destAmount.\n // Remaining optional things to do:\n // - Forward the full msg.value to the recipient (if non-zero).\n // - Trigger a Zap (if zapData is present).\n bytes calldata zapData = request.zapData();\n if (zapData.length != 0) {\n // Zap Data is present: Zap has been requested by the recipient. Trigger it forwarding the full msg.value.\n\n // Note: if token has a fee on transfers, the recipient will have received less than `amount`.\n // This is a very niche edge case and should be handled by the recipient contract.\n _triggerZapWithChecks({recipient: to, token: token, amount: amount, zapData: zapData});\n } else if (msg.value != 0) {\n // Zap Data is missing, but msg.value was sent. This could happen in two different cases:\n // - Relay with the native gas token is happening.\n // - Relay with ERC20 is happening, with a `zapNative \u003e 0` request.\n // In both cases, we need to transfer the full msg.value to the recipient.\n Address.sendValue(payable(to), msg.value);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) public onlyRole(PROVER_ROLE) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n\n // Can only prove a REQUESTED transaction\n if ($.status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n // Update status to RELAYER_PROVED and store the proof details\n // Note: these are storage writes\n $.status = BridgeStatus.RELAYER_PROVED;\n $.proofBlockTimestamp = uint56(block.timestamp);\n $.proofRelayer = relayer;\n\n emit BridgeProofProvided(transactionId, relayer, destTxHash);\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes calldata request, address to) public {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Aggregate the read operations from the same storage slot\n address proofRelayer = $.proofRelayer;\n BridgeStatus status = $.status;\n uint56 proofBlockTimestamp = $.proofBlockTimestamp;\n\n // Can only claim a RELAYER_PROVED transaction after the dispute period\n if (status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(proofBlockTimestamp) \u003c= DISPUTE_PERIOD) {\n revert DisputePeriodNotPassed();\n }\n\n if (to == address(0)) {\n // Anyone could claim the funds to the proven relayer on their behalf\n to = proofRelayer;\n } else if (proofRelayer != msg.sender) {\n // Only the proven relayer could specify an address to claim the funds to\n revert SenderIncorrect();\n }\n\n // Update status to RELAYER_CLAIMED and transfer the origin collateral to the specified claim address\n // Note: this is a storage write\n $.status = BridgeStatus.RELAYER_CLAIMED;\n\n address token = request.originToken();\n uint256 amount = request.originAmount();\n // Update protocol fees if origin fee amount exists\n uint256 originFeeAmount = request.originFeeAmount();\n if (originFeeAmount \u003e 0) protocolFees[token] += originFeeAmount;\n // Emit the event before any external calls\n emit BridgeDepositClaimed(transactionId, proofRelayer, to, token, amount);\n // Complete the relayer claim as the last transaction action\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(to), amount);\n } else {\n IERC20(token).safeTransfer(to, amount);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function cancel(bytes calldata request) public {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Can only cancel a REQUESTED transaction after its deadline expires\n if ($.status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n uint256 deadline = request.deadline();\n // Permissionless cancel is only allowed after `cancelDelay` on top of the deadline\n if (!hasRole(CANCELER_ROLE, msg.sender)) deadline += cancelDelay;\n if (block.timestamp \u003c= deadline) revert DeadlineNotExceeded();\n // Update status to REFUNDED and return the full amount (collateral + protocol fees) to the original sender.\n // The protocol fees are only updated when the transaction is claimed, so we don't need to update them here.\n // Note: this is a storage write\n $.status = BridgeStatus.REFUNDED;\n\n address to = request.originSender();\n address token = request.originToken();\n uint256 amount = request.originAmount() + request.originFeeAmount();\n // Emit the event before any external calls\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n // Complete the user cancel as the last transaction action\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(to), amount);\n } else {\n IERC20(token).safeTransfer(to, amount);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeStatuses(bytes32 transactionId) public view returns (BridgeStatus status) {\n return bridgeTxDetails[transactionId].status;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeProofs(bytes32 transactionId) public view returns (uint96 timestamp, address relayer) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n\n timestamp = $.proofBlockTimestamp;\n relayer = $.proofRelayer;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeRelays(bytes32 transactionId) public view returns (bool) {\n // has this transactionId been relayed?\n return bridgeRelayDetails[transactionId].relayer != address(0);\n }\n\n /// @notice Takes the bridged asset from the user into FastBridgeV2 custody. It will be later\n /// claimed by the relayer who completed the relay on destination chain, or transferred back to the user\n /// via the cancel function should no one complete the relay.\n function _takeBridgedUserAsset(address token, uint256 amount) internal returns (uint256 amountTaken) {\n if (token == NATIVE_GAS_TOKEN) {\n // For the native gas token, we just need to check that the supplied msg.value is correct.\n // Supplied `msg.value` is already in FastBridgeV2 custody.\n if (amount != msg.value) revert MsgValueIncorrect();\n amountTaken = msg.value;\n } else {\n // For ERC20s, token is explicitly transferred from the user to FastBridgeV2.\n // We don't allow non-zero `msg.value` to avoid extra funds from being stuck in FastBridgeV2.\n if (msg.value != 0) revert MsgValueIncorrect();\n // Throw an explicit error if the provided token address is not a contract\n if (token.code.length == 0) revert TokenNotContract();\n amountTaken = IERC20(token).balanceOf(address(this));\n IERC20(token).safeTransferFrom(msg.sender, address(this), amount);\n // Use the balance difference as the amount taken in case of fee on transfer tokens.\n amountTaken = IERC20(token).balanceOf(address(this)) - amountTaken;\n }\n }\n\n /// @notice Calls the Recipient's hook function with the specified zapData and performs\n /// all the necessary checks for the returned value.\n function _triggerZapWithChecks(address recipient, address token, uint256 amount, bytes calldata zapData) internal {\n // This will bubble any revert messages from the hook function\n bytes memory returnData = Address.functionCallWithValue({\n target: recipient,\n data: abi.encodeCall(IZapRecipient.zap, (token, amount, zapData)),\n // Note: see `relay()` for reasoning behind passing msg.value\n value: msg.value\n });\n // Explicit revert if no return data at all\n if (returnData.length == 0) revert RecipientNoReturnValue();\n // Check that exactly a single return value was returned\n if (returnData.length != 32) revert RecipientIncorrectReturnValue();\n // Return value should be abi-encoded hook function selector\n if (bytes32(returnData) != bytes32(IZapRecipient.zap.selector)) {\n revert RecipientIncorrectReturnValue();\n }\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint56(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint56).max but\n /// proof.timestamp \u003c type(uint56).max via unchecked statement\n /// @param proofBlockTimestamp The bridge proof block timestamp\n /// @return delta Time delta since proof submitted\n function _timeSince(uint56 proofBlockTimestamp) internal view returns (uint256 delta) {\n unchecked {\n delta = uint56(block.timestamp) - proofBlockTimestamp;\n }\n }\n\n /// @notice Performs all the necessary checks for a bridge to happen.\n /// @dev There's no good way to refactor this function to reduce cyclomatic complexity due to\n /// the number of checks that need to be performed, so we skip the code-complexity rule here.\n // solhint-disable-next-line code-complexity\n function _validateBridgeParams(\n BridgeParams memory params,\n BridgeParamsV2 memory paramsV2,\n int256 exclusivityEndTime\n )\n internal\n view\n {\n // Check V1 (legacy) params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.sender == address(0) || params.to == address(0)) revert ZeroAddress();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n // Check V2 params\n if (paramsV2.zapData.length \u003e MAX_ZAP_DATA_LENGTH) revert ZapDataLengthAboveMax();\n if (paramsV2.zapNative != 0 \u0026\u0026 params.destToken == NATIVE_GAS_TOKEN) {\n revert ZapNativeNotSupported();\n }\n // exclusivityEndTime must be in range [0 .. params.deadline]\n if (exclusivityEndTime \u003c 0 || exclusivityEndTime \u003e int256(params.deadline)) {\n revert ExclusivityParamsIncorrect();\n }\n }\n\n /// @notice Performs all the necessary checks for a relay to happen.\n function _validateRelayParams(bytes calldata request, bytes32 transactionId, address relayer) internal view {\n if (relayer == address(0)) revert ZeroAddress();\n // Check if the transaction has already been relayed\n if (bridgeRelays(transactionId)) revert TransactionRelayed();\n if (request.destChainId() != block.chainid) revert ChainIncorrect();\n // Check the deadline for relay to happen\n if (block.timestamp \u003e request.deadline()) revert DeadlineExceeded();\n // Check the exclusivity period, if it is still ongoing\n address exclRelayer = request.exclusivityRelayer();\n if (exclRelayer != address(0) \u0026\u0026 exclRelayer != relayer \u0026\u0026 block.timestamp \u003c= request.exclusivityEndTime()) {\n revert ExclusivityPeriodNotPassed();\n }\n }\n}\n","language":"Solidity","languageVersion":"0.8.24","compilerVersion":"0.8.24","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"","srcMapRuntime":"","abiDefinition":[],"userDoc":{"kind":"user","methods":{},"version":1},"developerDoc":{"details":"Provides information about the current execution context, including the sender of the transaction and its data. While these are generally available via msg.sender and msg.data, they should not be accessed in such a direct manner, since when dealing with meta-transactions the account sending and paying for execution may not be the actual sender (as far as an application is concerned). This contract is only required for intermediate, library-like contracts.","kind":"dev","methods":{},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[],\"devdoc\":{\"details\":\"Provides information about the current execution context, including the sender of the transaction and its data. While these are generally available via msg.sender and msg.data, they should not be accessed in such a direct manner, since when dealing with meta-transactions the account sending and paying for execution may not be the actual sender (as far as an application is concerned). This contract is only required for intermediate, library-like contracts.\",\"kind\":\"dev\",\"methods\":{},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeV2.sol\":\"Context\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeV2.sol\":{\"keccak256\":\"0xac79c463688a682ca706a4ef95e7817b83548cdfa8182ba0426ac7e5e07613d8\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://b3ecb7097381287cafc3a73f3a2bb03565115ebb682a85064e0b0dc2f7e2919d\",\"dweb:/ipfs/QmatruW3nYZTksf3CeQ8wwiAG4c7xoEJBEp6drHPtFLBRK\"]}},\"version\":1}"},"hashes":{}},"solidity/FastBridgeV2.sol:ERC165":{"code":"0x","runtime-code":"0x","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.24 ^0.8.20 ^0.8.4;\n\n// contracts/interfaces/IAdminV2.sol\n\ninterface IAdminV2 {\n event CancelDelayUpdated(uint256 oldCancelDelay, uint256 newCancelDelay);\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n function setCancelDelay(uint256 newCancelDelay) external;\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n}\n\n// contracts/interfaces/IAdminV2Errors.sol\n\ninterface IAdminV2Errors {\n error CancelDelayBelowMin();\n error FeeRateAboveMax();\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IFastBridgeV2Errors.sol\n\ninterface IFastBridgeV2Errors {\n error AmountIncorrect();\n error ChainIncorrect();\n error ExclusivityParamsIncorrect();\n error MsgValueIncorrect();\n error SenderIncorrect();\n error StatusIncorrect();\n error TokenNotContract();\n error ZapDataLengthAboveMax();\n error ZapNativeNotSupported();\n error ZeroAddress();\n\n error RecipientIncorrectReturnValue();\n error RecipientNoReturnValue();\n\n error DeadlineExceeded();\n error DeadlineNotExceeded();\n error DeadlineTooShort();\n error DisputePeriodNotPassed();\n error DisputePeriodPassed();\n error ExclusivityPeriodNotPassed();\n\n error TransactionRelayed();\n}\n\n// contracts/interfaces/IMulticallTarget.sol\n\n/// @notice Interface for a contract that can be called multiple times by the same caller. Inspired by MulticallV3:\n/// https://github.com/mds1/multicall/blob/master/src/Multicall3.sol\ninterface IMulticallTarget {\n struct Result {\n bool success;\n bytes returnData;\n }\n\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external;\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results);\n}\n\n// contracts/interfaces/IZapRecipient.sol\n\ninterface IZapRecipient {\n function zap(address token, uint256 amount, bytes memory zapData) external payable returns (bytes4);\n}\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// contracts/interfaces/IFastBridgeV2.sol\n\ninterface IFastBridgeV2 is IFastBridge {\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n struct BridgeTxDetails {\n BridgeStatus status;\n uint32 destChainId;\n uint56 proofBlockTimestamp;\n address proofRelayer;\n }\n\n struct BridgeRelay {\n uint48 blockNumber;\n uint48 blockTimestamp;\n address relayer;\n }\n\n /// @notice New params introduced in the FastBridgeV2.\n /// We are passing fields from the older BridgeParams struct outside of this struct\n /// for backwards compatibility.\n /// Note: quoteRelayer and quoteExclusivitySeconds are either both zero (indicating no exclusivity)\n /// or both non-zero (indicating exclusivity for the given period).\n /// Note: zapNative \u003e 0 can NOT be used with destToken = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE (native token)\n /// @param quoteRelayer Relayer that provided the quote for the transaction\n /// @param quoteExclusivitySeconds Period of time the quote relayer is guaranteed exclusivity after user's deposit\n /// @param quoteId Unique quote identifier used for tracking the quote\n /// @param zapNative ETH value to send to the recipient (if any)\n /// @param zapData Parameters for the Zap to the destination recipient (if any)\n struct BridgeParamsV2 {\n address quoteRelayer;\n int256 quoteExclusivitySeconds;\n bytes quoteId;\n uint256 zapNative;\n bytes zapData;\n }\n\n /// @notice Updated bridge transaction struct to include parameters introduced in FastBridgeV2.\n /// Note: only `exclusivityRelayer` can fill such a transaction until `exclusivityEndTime`.\n struct BridgeTransactionV2 {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n // Note: sendChainGas flag from V1 is deprecated\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n address exclusivityRelayer;\n uint256 exclusivityEndTime;\n uint256 zapNative; // ETH value to send to the recipient (if any)\n bytes zapData; // data to pass for the Zap action (if any)\n }\n\n event BridgeQuoteDetails(bytes32 indexed transactionId, bytes quoteId);\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability\n /// to provide temporary exclusivity fill rights for the quote relayer.\n /// @param params The parameters required to bridge\n /// @param paramsV2 The parameters for exclusivity fill rights (optional, can be left empty)\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function relay(bytes memory request, address relayer) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param transactionId The transaction id associated with the encoded bridge transaction to prove\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital.\n /// @notice Can only send funds to the relayer address on the proof.\n /// @param request The encoded bridge transaction to claim on origin chain\n function claim(bytes memory request) external;\n\n /// @notice Cancels an outstanding bridge transaction in case optimistic bridging failed and returns the full amount\n /// to the original sender.\n /// @param request The encoded bridge transaction to refund\n function cancel(bytes memory request) external;\n\n /// @notice Checks if a transaction has been relayed\n /// @param transactionId The ID of the transaction to check\n /// @return True if the transaction has been relayed, false otherwise\n function bridgeRelays(bytes32 transactionId) external view returns (bool);\n\n /// @notice Returns the status of a bridge transaction\n /// @param transactionId The ID of the bridge transaction\n /// @return BridgeStatus Status of the bridge transaction\n function bridgeStatuses(bytes32 transactionId) external view returns (BridgeStatus);\n\n /// @notice Returns the timestamp and relayer of a bridge proof\n /// @param transactionId The ID of the bridge transaction\n /// @return timestamp The timestamp of the bridge proof\n /// @return relayer The relayer address of the bridge proof\n function bridgeProofs(bytes32 transactionId) external view returns (uint96 timestamp, address relayer);\n\n /// @notice Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\n /// @param request The bridge request to decode\n function getBridgeTransactionV2(bytes memory request) external view returns (BridgeTransactionV2 memory);\n}\n\n// contracts/utils/MulticallTarget.sol\n\n// solhint-disable avoid-low-level-calls\n/// @notice Template for a contract that supports batched calls (preserving the msg.sender).\n/// Only calls with zero msg.value could be batched.\nabstract contract MulticallTarget is IMulticallTarget {\n error MulticallTarget__UndeterminedRevert();\n\n /// @notice Perform a batched call to this contract, preserving the msg.sender.\n /// The return data from each call is discarded.\n /// @dev The method is non-payable, so only calls with `msg.value == 0` could be batched.\n /// It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag.\n /// Otherwise, the whole batch call will be reverted with the original revert reason.\n /// @param data List of abi-encoded calldata for the calls to perform.\n /// @param ignoreReverts Whether to ignore the revert errors from the calls.\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external {\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\n if (!success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(result);\n }\n }\n }\n\n /// @notice Perform a batched call to this contract, preserving the msg.sender.\n /// The return data from each call is preserved.\n /// @dev The method is non-payable, so only calls with `msg.value == 0` could be batched.\n /// It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag.\n /// Otherwise, the whole batch call will be reverted with the original revert reason.\n /// @param data List of abi-encoded calldata for the calls to perform.\n /// @param ignoreReverts Whether to ignore the revert errors from the calls.\n /// @return results List of results from the calls: `(success, returnData)`.\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results)\n {\n results = new Result[](data.length);\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (results[i].success, results[i].returnData) = address(this).delegatecall(data[i]);\n if (!results[i].success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(results[i].returnData);\n }\n }\n }\n\n /// @dev Bubbles the revert message from the underlying call.\n /// Note: preserves the same custom error or revert string, if one was used.\n /// Source: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v5.0.2/contracts/utils/Address.sol#L143-L158\n function _bubbleRevert(bytes memory returnData) internal pure {\n // Look for revert reason and bubble it up if present\n if (returnData.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n // solhint-disable-next-line no-inline-assembly\n assembly {\n let returndata_size := mload(returnData)\n revert(add(32, returnData), returndata_size)\n }\n } else {\n revert MulticallTarget__UndeterminedRevert();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// contracts/libs/BridgeTransactionV2.sol\n\n// solhint-disable no-inline-assembly\nlibrary BridgeTransactionV2Lib {\n uint16 internal constant VERSION = 2;\n\n // Offsets of the fields in the packed BridgeTransactionV2 struct\n // uint16 version [000 .. 002)\n // uint32 originChainId [002 .. 006)\n // uint32 destChainId [006 .. 010)\n // address originSender [010 .. 030)\n // address destRecipient [030 .. 050)\n // address originToken [050 .. 070)\n // address destToken [070 .. 090)\n // uint256 originAmount [090 .. 122)\n // uint256 destAmount [122 .. 154)\n // uint256 originFeeAmount [154 .. 186)\n // uint256 deadline [186 .. 218)\n // uint256 nonce [218 .. 250)\n // address exclusivityRelayer [250 .. 270)\n // uint256 exclusivityEndTime [270 .. 302)\n // uint256 zapNative [302 .. 334)\n // bytes zapData [334 .. ***)\n\n // forgefmt: disable-start\n uint256 private constant OFFSET_ORIGIN_CHAIN_ID = 2;\n uint256 private constant OFFSET_DEST_CHAIN_ID = 6;\n uint256 private constant OFFSET_ORIGIN_SENDER = 10;\n uint256 private constant OFFSET_DEST_RECIPIENT = 30;\n uint256 private constant OFFSET_ORIGIN_TOKEN = 50;\n uint256 private constant OFFSET_DEST_TOKEN = 70;\n uint256 private constant OFFSET_ORIGIN_AMOUNT = 90;\n uint256 private constant OFFSET_DEST_AMOUNT = 122;\n uint256 private constant OFFSET_ORIGIN_FEE_AMOUNT = 154;\n uint256 private constant OFFSET_DEADLINE = 186;\n uint256 private constant OFFSET_NONCE = 218;\n uint256 private constant OFFSET_EXCLUSIVITY_RELAYER = 250;\n uint256 private constant OFFSET_EXCLUSIVITY_END_TIME = 270;\n uint256 private constant OFFSET_ZAP_NATIVE = 302;\n uint256 private constant OFFSET_ZAP_DATA = 334;\n // forgefmt: disable-end\n\n error BridgeTransactionV2__InvalidEncodedTx();\n error BridgeTransactionV2__UnsupportedVersion(uint16 version);\n\n /// @notice Validates the encoded transaction to be a tightly packed encoded payload for BridgeTransactionV2.\n /// @dev Checks the minimum length and the version, use this function before decoding any of the fields.\n function validateV2(bytes calldata encodedTx) internal pure {\n // Check the minimum length: must at least include all static fields.\n if (encodedTx.length \u003c OFFSET_ZAP_DATA) revert BridgeTransactionV2__InvalidEncodedTx();\n // Once we validated the length, we can be sure that the version field is present.\n uint16 version_ = version(encodedTx);\n if (version_ != VERSION) revert BridgeTransactionV2__UnsupportedVersion(version_);\n }\n\n /// @notice Encodes the BridgeTransactionV2 struct by tightly packing the fields.\n /// @dev `abi.decode` will not work as a result of the tightly packed fields. Use `decodeV2` to decode instead.\n function encodeV2(IFastBridgeV2.BridgeTransactionV2 memory bridgeTx) internal pure returns (bytes memory) {\n // We split the encoding into two parts to avoid stack-too-deep error\n bytes memory firstPart = abi.encodePacked(\n VERSION,\n bridgeTx.originChainId,\n bridgeTx.destChainId,\n bridgeTx.originSender,\n bridgeTx.destRecipient,\n bridgeTx.originToken,\n bridgeTx.destToken,\n bridgeTx.originAmount\n );\n return abi.encodePacked(\n firstPart,\n bridgeTx.destAmount,\n bridgeTx.originFeeAmount,\n // Note: we skip the deprecated `sendChainGas` flag, which was present in BridgeTransaction V1\n bridgeTx.deadline,\n bridgeTx.nonce,\n // New V2 fields: exclusivity\n bridgeTx.exclusivityRelayer,\n bridgeTx.exclusivityEndTime,\n // New V2 fields: Zap\n bridgeTx.zapNative,\n bridgeTx.zapData\n );\n }\n\n /// @notice Decodes the BridgeTransactionV2 struct from the encoded transaction.\n /// @dev Encoded BridgeTransactionV2 struct must be tightly packed.\n /// Use `validateV2` before decoding to ensure the encoded transaction is valid.\n function decodeV2(bytes calldata encodedTx)\n internal\n pure\n returns (IFastBridgeV2.BridgeTransactionV2 memory bridgeTx)\n {\n bridgeTx.originChainId = originChainId(encodedTx);\n bridgeTx.destChainId = destChainId(encodedTx);\n bridgeTx.originSender = originSender(encodedTx);\n bridgeTx.destRecipient = destRecipient(encodedTx);\n bridgeTx.originToken = originToken(encodedTx);\n bridgeTx.destToken = destToken(encodedTx);\n bridgeTx.originAmount = originAmount(encodedTx);\n bridgeTx.destAmount = destAmount(encodedTx);\n bridgeTx.originFeeAmount = originFeeAmount(encodedTx);\n bridgeTx.deadline = deadline(encodedTx);\n bridgeTx.nonce = nonce(encodedTx);\n bridgeTx.exclusivityRelayer = exclusivityRelayer(encodedTx);\n bridgeTx.exclusivityEndTime = exclusivityEndTime(encodedTx);\n bridgeTx.zapNative = zapNative(encodedTx);\n bridgeTx.zapData = zapData(encodedTx);\n }\n\n /// @notice Extracts the version from the encoded transaction.\n function version(bytes calldata encodedTx) internal pure returns (uint16 version_) {\n // Load 32 bytes from the start and shift it 240 bits to the right to get the highest 16 bits.\n assembly {\n version_ := shr(240, calldataload(encodedTx.offset))\n }\n }\n\n /// @notice Extracts the origin chain ID from the encoded transaction.\n function originChainId(bytes calldata encodedTx) internal pure returns (uint32 originChainId_) {\n // Load 32 bytes from the offset and shift it 224 bits to the right to get the highest 32 bits.\n assembly {\n originChainId_ := shr(224, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_CHAIN_ID)))\n }\n }\n\n /// @notice Extracts the destination chain ID from the encoded transaction.\n function destChainId(bytes calldata encodedTx) internal pure returns (uint32 destChainId_) {\n // Load 32 bytes from the offset and shift it 224 bits to the right to get the highest 32 bits.\n assembly {\n destChainId_ := shr(224, calldataload(add(encodedTx.offset, OFFSET_DEST_CHAIN_ID)))\n }\n }\n\n /// @notice Extracts the origin sender from the encoded transaction.\n function originSender(bytes calldata encodedTx) internal pure returns (address originSender_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n originSender_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_SENDER)))\n }\n }\n\n /// @notice Extracts the destination recipient from the encoded transaction.\n function destRecipient(bytes calldata encodedTx) internal pure returns (address destRecipient_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n destRecipient_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_DEST_RECIPIENT)))\n }\n }\n\n /// @notice Extracts the origin token from the encoded transaction.\n function originToken(bytes calldata encodedTx) internal pure returns (address originToken_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n originToken_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_TOKEN)))\n }\n }\n\n /// @notice Extracts the destination token from the encoded transaction.\n function destToken(bytes calldata encodedTx) internal pure returns (address destToken_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n destToken_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_DEST_TOKEN)))\n }\n }\n\n /// @notice Extracts the origin amount from the encoded transaction.\n function originAmount(bytes calldata encodedTx) internal pure returns (uint256 originAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n originAmount_ := calldataload(add(encodedTx.offset, OFFSET_ORIGIN_AMOUNT))\n }\n }\n\n /// @notice Extracts the destination amount from the encoded transaction.\n function destAmount(bytes calldata encodedTx) internal pure returns (uint256 destAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n destAmount_ := calldataload(add(encodedTx.offset, OFFSET_DEST_AMOUNT))\n }\n }\n\n /// @notice Extracts the origin fee amount from the encoded transaction.\n function originFeeAmount(bytes calldata encodedTx) internal pure returns (uint256 originFeeAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n originFeeAmount_ := calldataload(add(encodedTx.offset, OFFSET_ORIGIN_FEE_AMOUNT))\n }\n }\n\n /// @notice Extracts the deadline from the encoded transaction.\n function deadline(bytes calldata encodedTx) internal pure returns (uint256 deadline_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n deadline_ := calldataload(add(encodedTx.offset, OFFSET_DEADLINE))\n }\n }\n\n /// @notice Extracts the nonce from the encoded transaction.\n function nonce(bytes calldata encodedTx) internal pure returns (uint256 nonce_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n nonce_ := calldataload(add(encodedTx.offset, OFFSET_NONCE))\n }\n }\n\n /// @notice Extracts the exclusivity relayer from the encoded transaction.\n function exclusivityRelayer(bytes calldata encodedTx) internal pure returns (address exclusivityRelayer_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n exclusivityRelayer_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_EXCLUSIVITY_RELAYER)))\n }\n }\n\n /// @notice Extracts the exclusivity end time from the encoded transaction.\n function exclusivityEndTime(bytes calldata encodedTx) internal pure returns (uint256 exclusivityEndTime_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n exclusivityEndTime_ := calldataload(add(encodedTx.offset, OFFSET_EXCLUSIVITY_END_TIME))\n }\n }\n\n /// @notice Extracts the Zap's native value from the encoded transaction.\n function zapNative(bytes calldata encodedTx) internal pure returns (uint256 zapNative_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n zapNative_ := calldataload(add(encodedTx.offset, OFFSET_ZAP_NATIVE))\n }\n }\n\n /// @notice Extracts the Zap's data from the encoded transaction.\n function zapData(bytes calldata encodedTx) internal pure returns (bytes calldata zapData_) {\n zapData_ = encodedTx[OFFSET_ZAP_DATA:];\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/AdminV2.sol\n\ncontract AdminV2 is AccessControlEnumerable, IAdminV2, IAdminV2Errors {\n using SafeERC20 for IERC20;\n\n /// @notice Address reserved for native gas token (ETH on Ethereum and most L2s, AVAX on Avalanche, etc)\n address public constant NATIVE_GAS_TOKEN = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Role identifier for Quoter API's off-chain authentication.\n /// @dev Only addresses with this role can post FastBridge quotes to the API.\n bytes32 public constant QUOTER_ROLE = keccak256(\"QUOTER_ROLE\");\n\n /// @notice Role identifier for Prover's on-chain authentication in FastBridge.\n /// @dev Only addresses with this role can provide proofs that a FastBridge request has been relayed.\n bytes32 public constant PROVER_ROLE = keccak256(\"PROVER_ROLE\");\n\n /// @notice Role identifier for Guard's on-chain authentication in FastBridge.\n /// @dev Only addresses with this role can dispute submitted relay proofs during the dispute period.\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n\n /// @notice Role identifier for Canceler's on-chain authentication in FastBridge.\n /// @dev Only addresses with this role can cancel a FastBridge transaction without the cancel delay.\n bytes32 public constant CANCELER_ROLE = keccak256(\"CANCELER_ROLE\");\n\n /// @notice Role identifier for Governor's on-chain administrative authority.\n /// @dev Only addresses with this role can perform administrative tasks within the contract.\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n /// @notice Denominator for fee rates, represents 100%.\n uint256 public constant FEE_BPS = 1e6;\n /// @notice Maximum protocol fee rate: 1% on origin amount.\n uint256 public constant FEE_RATE_MAX = 0.01e6;\n\n /// @notice Minimum cancel delay that can be set by the governor.\n uint256 public constant MIN_CANCEL_DELAY = 1 hours;\n /// @notice Default cancel delay set during the contract deployment.\n uint256 public constant DEFAULT_CANCEL_DELAY = 1 days;\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Delay for a transaction after which it could be permisionlessly cancelled\n uint256 public cancelDelay;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Use ZapNative V2 requests instead.\n uint256 public immutable chainGasAmount = 0;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n _setCancelDelay(DEFAULT_CANCEL_DELAY);\n }\n\n /// @notice Allows the contract governor to set the cancel delay. The cancel delay is the time after the transaction\n /// deadline after which it can be permissionlessly cancelled, if it hasn't been proven by any of the Relayers.\n function setCancelDelay(uint256 newCancelDelay) external onlyRole(GOVERNOR_ROLE) {\n _setCancelDelay(newCancelDelay);\n }\n\n /// @notice Allows the contract governor to set the protocol fee rate. The protocol fee is taken from the origin\n /// amount only for completed and claimed transactions.\n /// @dev The protocol fee is abstracted away from the relayers, they always operate using the amounts after fees:\n /// what they see as the origin amount emitted in the log is what they get credited with.\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n if (newFeeRate \u003e FEE_RATE_MAX) revert FeeRateAboveMax();\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n /// @notice Allows the contract governor to sweep the accumulated protocol fees in the contract.\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n emit FeesSwept(token, recipient, feeAmount);\n /// Sweep the fees as the last transaction action\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(recipient), feeAmount);\n } else {\n IERC20(token).safeTransfer(recipient, feeAmount);\n }\n }\n\n /// @notice Internal function to set the cancel delay. Security checks are performed outside of this function.\n function _setCancelDelay(uint256 newCancelDelay) private {\n if (newCancelDelay \u003c MIN_CANCEL_DELAY) revert CancelDelayBelowMin();\n uint256 oldCancelDelay = cancelDelay;\n cancelDelay = newCancelDelay;\n emit CancelDelayUpdated(oldCancelDelay, newCancelDelay);\n }\n}\n\n// contracts/FastBridgeV2.sol\n\n/// @notice FastBridgeV2 is a contract for bridging tokens across chains.\ncontract FastBridgeV2 is AdminV2, MulticallTarget, IFastBridgeV2, IFastBridgeV2Errors {\n using BridgeTransactionV2Lib for bytes;\n using SafeERC20 for IERC20;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n /// @notice Maximum length of accepted zapData\n uint256 public constant MAX_ZAP_DATA_LENGTH = 2 ** 16 - 1;\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeTxDetails) public bridgeTxDetails;\n /// @notice Relay details on destination chain\n mapping(bytes32 =\u003e BridgeRelay) public bridgeRelayDetails;\n /// @notice Unique bridge nonces tracked per originSender\n mapping(address =\u003e uint256) public senderNonces;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Replaced by senderNonces\n uint256 public immutable nonce = 0;\n /// @notice the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) AdminV2(_owner) {\n deployBlock = block.number;\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n bridge({\n params: params,\n paramsV2: BridgeParamsV2({\n quoteRelayer: address(0),\n quoteExclusivitySeconds: 0,\n quoteId: bytes(\"\"),\n zapNative: 0,\n zapData: bytes(\"\")\n })\n });\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes calldata request) external payable {\n // relay override will validate the request\n relay({request: request, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes calldata request, bytes32 destTxHash) external {\n request.validateV2();\n prove({transactionId: keccak256(request), destTxHash: destTxHash, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridgeV2\n function claim(bytes calldata request) external {\n // claim override will validate the request\n claim({request: request, to: address(0)});\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Aggregate the read operations from the same storage slot\n address disputedRelayer = $.proofRelayer;\n BridgeStatus status = $.status;\n uint56 proofBlockTimestamp = $.proofBlockTimestamp;\n // Can only dispute a RELAYER_PROVED transaction within the dispute period\n if (status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(proofBlockTimestamp) \u003e DISPUTE_PERIOD) {\n revert DisputePeriodPassed();\n }\n // Update status to REQUESTED and delete the disputed proof details\n // Note: these are storage writes\n $.status = BridgeStatus.REQUESTED;\n $.proofRelayer = address(0);\n $.proofBlockTimestamp = 0;\n\n emit BridgeProofDisputed(transactionId, disputedRelayer);\n }\n\n /// Note: this function is deprecated and will be removed in a future version.\n /// @inheritdoc IFastBridge\n function refund(bytes calldata request) external {\n cancel(request);\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // The correct relayer can only claim a RELAYER_PROVED transaction after the dispute period\n if ($.status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if ($.proofRelayer != relayer) revert SenderIncorrect();\n return _timeSince($.proofBlockTimestamp) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n /// @dev This method is added to achieve backwards compatibility with decoding requests into V1 structs:\n /// - `zapNative` is partially reported as a zero/non-zero flag\n /// - `zapData` is ignored\n /// In order to process all kinds of requests use getBridgeTransactionV2 instead.\n function getBridgeTransaction(bytes calldata request) external view returns (BridgeTransaction memory) {\n // Try decoding into V2 struct first. This will revert if V1 struct is passed\n try this.getBridgeTransactionV2(request) returns (BridgeTransactionV2 memory txV2) {\n // Note: we entirely ignore the zapData field, as it was not present in V1\n return BridgeTransaction({\n originChainId: txV2.originChainId,\n destChainId: txV2.destChainId,\n originSender: txV2.originSender,\n destRecipient: txV2.destRecipient,\n originToken: txV2.originToken,\n destToken: txV2.destToken,\n originAmount: txV2.originAmount,\n destAmount: txV2.destAmount,\n originFeeAmount: txV2.originFeeAmount,\n sendChainGas: txV2.zapNative != 0,\n deadline: txV2.deadline,\n nonce: txV2.nonce\n });\n } catch {\n // Fallback to V1 struct\n return abi.decode(request, (BridgeTransaction));\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function getBridgeTransactionV2(bytes calldata request) external pure returns (BridgeTransactionV2 memory) {\n request.validateV2();\n return BridgeTransactionV2Lib.decodeV2(request);\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) public payable {\n int256 exclusivityEndTime = 0;\n // if relayer exclusivity is not intended for this bridge, set exclusivityEndTime to static zero\n // otherwise, set exclusivity to expire at the current block ts offset by quoteExclusivitySeconds\n if (paramsV2.quoteRelayer != address(0)) {\n exclusivityEndTime = int256(block.timestamp) + paramsV2.quoteExclusivitySeconds;\n }\n _validateBridgeParams(params, paramsV2, exclusivityEndTime);\n\n // transfer tokens to bridge contract\n /// @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _takeBridgedUserAsset(params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) {\n originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n }\n\n // set status to requested\n bytes memory request = BridgeTransactionV2Lib.encodeV2(\n BridgeTransactionV2({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n deadline: params.deadline,\n nonce: senderNonces[params.sender]++, // increment nonce on every bridge\n exclusivityRelayer: paramsV2.quoteRelayer,\n // We checked exclusivityEndTime to be in range [0 .. params.deadline] above, so can safely cast\n exclusivityEndTime: uint256(exclusivityEndTime),\n zapNative: paramsV2.zapNative,\n zapData: paramsV2.zapData\n })\n );\n bytes32 transactionId = keccak256(request);\n // Note: the tx status will be updated throughout the tx lifecycle, while destChainId is set once here\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n bridgeTxDetails[transactionId].destChainId = params.dstChainId;\n\n emit BridgeRequested({\n transactionId: transactionId,\n sender: params.sender,\n request: request,\n destChainId: params.dstChainId,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n sendChainGas: paramsV2.zapNative != 0\n });\n emit BridgeQuoteDetails(transactionId, paramsV2.quoteId);\n }\n\n /// @inheritdoc IFastBridgeV2\n function relay(bytes calldata request, address relayer) public payable {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n _validateRelayParams(request, transactionId, relayer);\n // mark bridge transaction as relayed\n bridgeRelayDetails[transactionId] =\n BridgeRelay({blockNumber: uint48(block.number), blockTimestamp: uint48(block.timestamp), relayer: relayer});\n\n // transfer tokens to recipient on destination chain and trigger Zap if requested\n address to = request.destRecipient();\n address token = request.destToken();\n uint256 amount = request.destAmount();\n uint256 zapNative = request.zapNative();\n\n // Emit the event before any external calls\n emit BridgeRelayed({\n transactionId: transactionId,\n relayer: relayer,\n to: to,\n originChainId: request.originChainId(),\n originToken: request.originToken(),\n destToken: token,\n originAmount: request.originAmount(),\n destAmount: amount,\n chainGasAmount: zapNative\n });\n\n // All state changes have been done at this point, can proceed to the external calls.\n // This follows the checks-effects-interactions pattern to mitigate potential reentrancy attacks.\n if (token == NATIVE_GAS_TOKEN) {\n // For the native gas token, additional zapNative is not allowed\n if (zapNative != 0) revert ZapNativeNotSupported();\n // Check that the correct msg.value was sent\n if (msg.value != amount) revert MsgValueIncorrect();\n // Don't do a native transfer yet: we will handle it alongside the Zap below\n } else {\n // For ERC20s, we check that the correct msg.value was sent\n if (msg.value != zapNative) revert MsgValueIncorrect();\n // We need to transfer the tokens from the Relayer to the recipient first before performing an\n // optional post-transfer Zap.\n IERC20(token).safeTransferFrom(msg.sender, to, amount);\n }\n // At this point we have done:\n // - Transferred the requested amount of ERC20 tokens to the recipient.\n // At this point we have confirmed:\n // - For ERC20s: msg.value matches the requested zapNative amount.\n // - For the native gas token: msg.value matches the requested destAmount.\n // Remaining optional things to do:\n // - Forward the full msg.value to the recipient (if non-zero).\n // - Trigger a Zap (if zapData is present).\n bytes calldata zapData = request.zapData();\n if (zapData.length != 0) {\n // Zap Data is present: Zap has been requested by the recipient. Trigger it forwarding the full msg.value.\n\n // Note: if token has a fee on transfers, the recipient will have received less than `amount`.\n // This is a very niche edge case and should be handled by the recipient contract.\n _triggerZapWithChecks({recipient: to, token: token, amount: amount, zapData: zapData});\n } else if (msg.value != 0) {\n // Zap Data is missing, but msg.value was sent. This could happen in two different cases:\n // - Relay with the native gas token is happening.\n // - Relay with ERC20 is happening, with a `zapNative \u003e 0` request.\n // In both cases, we need to transfer the full msg.value to the recipient.\n Address.sendValue(payable(to), msg.value);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) public onlyRole(PROVER_ROLE) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n\n // Can only prove a REQUESTED transaction\n if ($.status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n // Update status to RELAYER_PROVED and store the proof details\n // Note: these are storage writes\n $.status = BridgeStatus.RELAYER_PROVED;\n $.proofBlockTimestamp = uint56(block.timestamp);\n $.proofRelayer = relayer;\n\n emit BridgeProofProvided(transactionId, relayer, destTxHash);\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes calldata request, address to) public {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Aggregate the read operations from the same storage slot\n address proofRelayer = $.proofRelayer;\n BridgeStatus status = $.status;\n uint56 proofBlockTimestamp = $.proofBlockTimestamp;\n\n // Can only claim a RELAYER_PROVED transaction after the dispute period\n if (status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(proofBlockTimestamp) \u003c= DISPUTE_PERIOD) {\n revert DisputePeriodNotPassed();\n }\n\n if (to == address(0)) {\n // Anyone could claim the funds to the proven relayer on their behalf\n to = proofRelayer;\n } else if (proofRelayer != msg.sender) {\n // Only the proven relayer could specify an address to claim the funds to\n revert SenderIncorrect();\n }\n\n // Update status to RELAYER_CLAIMED and transfer the origin collateral to the specified claim address\n // Note: this is a storage write\n $.status = BridgeStatus.RELAYER_CLAIMED;\n\n address token = request.originToken();\n uint256 amount = request.originAmount();\n // Update protocol fees if origin fee amount exists\n uint256 originFeeAmount = request.originFeeAmount();\n if (originFeeAmount \u003e 0) protocolFees[token] += originFeeAmount;\n // Emit the event before any external calls\n emit BridgeDepositClaimed(transactionId, proofRelayer, to, token, amount);\n // Complete the relayer claim as the last transaction action\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(to), amount);\n } else {\n IERC20(token).safeTransfer(to, amount);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function cancel(bytes calldata request) public {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Can only cancel a REQUESTED transaction after its deadline expires\n if ($.status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n uint256 deadline = request.deadline();\n // Permissionless cancel is only allowed after `cancelDelay` on top of the deadline\n if (!hasRole(CANCELER_ROLE, msg.sender)) deadline += cancelDelay;\n if (block.timestamp \u003c= deadline) revert DeadlineNotExceeded();\n // Update status to REFUNDED and return the full amount (collateral + protocol fees) to the original sender.\n // The protocol fees are only updated when the transaction is claimed, so we don't need to update them here.\n // Note: this is a storage write\n $.status = BridgeStatus.REFUNDED;\n\n address to = request.originSender();\n address token = request.originToken();\n uint256 amount = request.originAmount() + request.originFeeAmount();\n // Emit the event before any external calls\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n // Complete the user cancel as the last transaction action\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(to), amount);\n } else {\n IERC20(token).safeTransfer(to, amount);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeStatuses(bytes32 transactionId) public view returns (BridgeStatus status) {\n return bridgeTxDetails[transactionId].status;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeProofs(bytes32 transactionId) public view returns (uint96 timestamp, address relayer) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n\n timestamp = $.proofBlockTimestamp;\n relayer = $.proofRelayer;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeRelays(bytes32 transactionId) public view returns (bool) {\n // has this transactionId been relayed?\n return bridgeRelayDetails[transactionId].relayer != address(0);\n }\n\n /// @notice Takes the bridged asset from the user into FastBridgeV2 custody. It will be later\n /// claimed by the relayer who completed the relay on destination chain, or transferred back to the user\n /// via the cancel function should no one complete the relay.\n function _takeBridgedUserAsset(address token, uint256 amount) internal returns (uint256 amountTaken) {\n if (token == NATIVE_GAS_TOKEN) {\n // For the native gas token, we just need to check that the supplied msg.value is correct.\n // Supplied `msg.value` is already in FastBridgeV2 custody.\n if (amount != msg.value) revert MsgValueIncorrect();\n amountTaken = msg.value;\n } else {\n // For ERC20s, token is explicitly transferred from the user to FastBridgeV2.\n // We don't allow non-zero `msg.value` to avoid extra funds from being stuck in FastBridgeV2.\n if (msg.value != 0) revert MsgValueIncorrect();\n // Throw an explicit error if the provided token address is not a contract\n if (token.code.length == 0) revert TokenNotContract();\n amountTaken = IERC20(token).balanceOf(address(this));\n IERC20(token).safeTransferFrom(msg.sender, address(this), amount);\n // Use the balance difference as the amount taken in case of fee on transfer tokens.\n amountTaken = IERC20(token).balanceOf(address(this)) - amountTaken;\n }\n }\n\n /// @notice Calls the Recipient's hook function with the specified zapData and performs\n /// all the necessary checks for the returned value.\n function _triggerZapWithChecks(address recipient, address token, uint256 amount, bytes calldata zapData) internal {\n // This will bubble any revert messages from the hook function\n bytes memory returnData = Address.functionCallWithValue({\n target: recipient,\n data: abi.encodeCall(IZapRecipient.zap, (token, amount, zapData)),\n // Note: see `relay()` for reasoning behind passing msg.value\n value: msg.value\n });\n // Explicit revert if no return data at all\n if (returnData.length == 0) revert RecipientNoReturnValue();\n // Check that exactly a single return value was returned\n if (returnData.length != 32) revert RecipientIncorrectReturnValue();\n // Return value should be abi-encoded hook function selector\n if (bytes32(returnData) != bytes32(IZapRecipient.zap.selector)) {\n revert RecipientIncorrectReturnValue();\n }\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint56(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint56).max but\n /// proof.timestamp \u003c type(uint56).max via unchecked statement\n /// @param proofBlockTimestamp The bridge proof block timestamp\n /// @return delta Time delta since proof submitted\n function _timeSince(uint56 proofBlockTimestamp) internal view returns (uint256 delta) {\n unchecked {\n delta = uint56(block.timestamp) - proofBlockTimestamp;\n }\n }\n\n /// @notice Performs all the necessary checks for a bridge to happen.\n /// @dev There's no good way to refactor this function to reduce cyclomatic complexity due to\n /// the number of checks that need to be performed, so we skip the code-complexity rule here.\n // solhint-disable-next-line code-complexity\n function _validateBridgeParams(\n BridgeParams memory params,\n BridgeParamsV2 memory paramsV2,\n int256 exclusivityEndTime\n )\n internal\n view\n {\n // Check V1 (legacy) params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.sender == address(0) || params.to == address(0)) revert ZeroAddress();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n // Check V2 params\n if (paramsV2.zapData.length \u003e MAX_ZAP_DATA_LENGTH) revert ZapDataLengthAboveMax();\n if (paramsV2.zapNative != 0 \u0026\u0026 params.destToken == NATIVE_GAS_TOKEN) {\n revert ZapNativeNotSupported();\n }\n // exclusivityEndTime must be in range [0 .. params.deadline]\n if (exclusivityEndTime \u003c 0 || exclusivityEndTime \u003e int256(params.deadline)) {\n revert ExclusivityParamsIncorrect();\n }\n }\n\n /// @notice Performs all the necessary checks for a relay to happen.\n function _validateRelayParams(bytes calldata request, bytes32 transactionId, address relayer) internal view {\n if (relayer == address(0)) revert ZeroAddress();\n // Check if the transaction has already been relayed\n if (bridgeRelays(transactionId)) revert TransactionRelayed();\n if (request.destChainId() != block.chainid) revert ChainIncorrect();\n // Check the deadline for relay to happen\n if (block.timestamp \u003e request.deadline()) revert DeadlineExceeded();\n // Check the exclusivity period, if it is still ongoing\n address exclRelayer = request.exclusivityRelayer();\n if (exclRelayer != address(0) \u0026\u0026 exclRelayer != relayer \u0026\u0026 block.timestamp \u003c= request.exclusivityEndTime()) {\n revert ExclusivityPeriodNotPassed();\n }\n }\n}\n","language":"Solidity","languageVersion":"0.8.24","compilerVersion":"0.8.24","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"","srcMapRuntime":"","abiDefinition":[{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"}],"userDoc":{"kind":"user","methods":{},"version":1},"developerDoc":{"details":"Implementation of the {IERC165} interface. Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check for the additional interface id that will be supported. For example: ```solidity function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId); } ```","kind":"dev","methods":{"supportsInterface(bytes4)":{"details":"See {IERC165-supportsInterface}."}},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"bytes4\",\"name\":\"interfaceId\",\"type\":\"bytes4\"}],\"name\":\"supportsInterface\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"}],\"devdoc\":{\"details\":\"Implementation of the {IERC165} interface. Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check for the additional interface id that will be supported. For example: ```solidity function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId); } ```\",\"kind\":\"dev\",\"methods\":{\"supportsInterface(bytes4)\":{\"details\":\"See {IERC165-supportsInterface}.\"}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeV2.sol\":\"ERC165\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeV2.sol\":{\"keccak256\":\"0xac79c463688a682ca706a4ef95e7817b83548cdfa8182ba0426ac7e5e07613d8\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://b3ecb7097381287cafc3a73f3a2bb03565115ebb682a85064e0b0dc2f7e2919d\",\"dweb:/ipfs/QmatruW3nYZTksf3CeQ8wwiAG4c7xoEJBEp6drHPtFLBRK\"]}},\"version\":1}"},"hashes":{"supportsInterface(bytes4)":"01ffc9a7"}},"solidity/FastBridgeV2.sol:EnumerableSet":{"code":"0x60566037600b82828239805160001a607314602a57634e487b7160e01b600052600060045260246000fd5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600080fdfea2646970667358221220cb930ba14bc69bdf61a9326099568898423db2bde70050effda1b23aa9e9dc9e64736f6c63430008180033","runtime-code":"0x73000000000000000000000000000000000000000030146080604052600080fdfea2646970667358221220cb930ba14bc69bdf61a9326099568898423db2bde70050effda1b23aa9e9dc9e64736f6c63430008180033","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.24 ^0.8.20 ^0.8.4;\n\n// contracts/interfaces/IAdminV2.sol\n\ninterface IAdminV2 {\n event CancelDelayUpdated(uint256 oldCancelDelay, uint256 newCancelDelay);\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n function setCancelDelay(uint256 newCancelDelay) external;\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n}\n\n// contracts/interfaces/IAdminV2Errors.sol\n\ninterface IAdminV2Errors {\n error CancelDelayBelowMin();\n error FeeRateAboveMax();\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IFastBridgeV2Errors.sol\n\ninterface IFastBridgeV2Errors {\n error AmountIncorrect();\n error ChainIncorrect();\n error ExclusivityParamsIncorrect();\n error MsgValueIncorrect();\n error SenderIncorrect();\n error StatusIncorrect();\n error TokenNotContract();\n error ZapDataLengthAboveMax();\n error ZapNativeNotSupported();\n error ZeroAddress();\n\n error RecipientIncorrectReturnValue();\n error RecipientNoReturnValue();\n\n error DeadlineExceeded();\n error DeadlineNotExceeded();\n error DeadlineTooShort();\n error DisputePeriodNotPassed();\n error DisputePeriodPassed();\n error ExclusivityPeriodNotPassed();\n\n error TransactionRelayed();\n}\n\n// contracts/interfaces/IMulticallTarget.sol\n\n/// @notice Interface for a contract that can be called multiple times by the same caller. Inspired by MulticallV3:\n/// https://github.com/mds1/multicall/blob/master/src/Multicall3.sol\ninterface IMulticallTarget {\n struct Result {\n bool success;\n bytes returnData;\n }\n\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external;\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results);\n}\n\n// contracts/interfaces/IZapRecipient.sol\n\ninterface IZapRecipient {\n function zap(address token, uint256 amount, bytes memory zapData) external payable returns (bytes4);\n}\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// contracts/interfaces/IFastBridgeV2.sol\n\ninterface IFastBridgeV2 is IFastBridge {\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n struct BridgeTxDetails {\n BridgeStatus status;\n uint32 destChainId;\n uint56 proofBlockTimestamp;\n address proofRelayer;\n }\n\n struct BridgeRelay {\n uint48 blockNumber;\n uint48 blockTimestamp;\n address relayer;\n }\n\n /// @notice New params introduced in the FastBridgeV2.\n /// We are passing fields from the older BridgeParams struct outside of this struct\n /// for backwards compatibility.\n /// Note: quoteRelayer and quoteExclusivitySeconds are either both zero (indicating no exclusivity)\n /// or both non-zero (indicating exclusivity for the given period).\n /// Note: zapNative \u003e 0 can NOT be used with destToken = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE (native token)\n /// @param quoteRelayer Relayer that provided the quote for the transaction\n /// @param quoteExclusivitySeconds Period of time the quote relayer is guaranteed exclusivity after user's deposit\n /// @param quoteId Unique quote identifier used for tracking the quote\n /// @param zapNative ETH value to send to the recipient (if any)\n /// @param zapData Parameters for the Zap to the destination recipient (if any)\n struct BridgeParamsV2 {\n address quoteRelayer;\n int256 quoteExclusivitySeconds;\n bytes quoteId;\n uint256 zapNative;\n bytes zapData;\n }\n\n /// @notice Updated bridge transaction struct to include parameters introduced in FastBridgeV2.\n /// Note: only `exclusivityRelayer` can fill such a transaction until `exclusivityEndTime`.\n struct BridgeTransactionV2 {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n // Note: sendChainGas flag from V1 is deprecated\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n address exclusivityRelayer;\n uint256 exclusivityEndTime;\n uint256 zapNative; // ETH value to send to the recipient (if any)\n bytes zapData; // data to pass for the Zap action (if any)\n }\n\n event BridgeQuoteDetails(bytes32 indexed transactionId, bytes quoteId);\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability\n /// to provide temporary exclusivity fill rights for the quote relayer.\n /// @param params The parameters required to bridge\n /// @param paramsV2 The parameters for exclusivity fill rights (optional, can be left empty)\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function relay(bytes memory request, address relayer) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param transactionId The transaction id associated with the encoded bridge transaction to prove\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital.\n /// @notice Can only send funds to the relayer address on the proof.\n /// @param request The encoded bridge transaction to claim on origin chain\n function claim(bytes memory request) external;\n\n /// @notice Cancels an outstanding bridge transaction in case optimistic bridging failed and returns the full amount\n /// to the original sender.\n /// @param request The encoded bridge transaction to refund\n function cancel(bytes memory request) external;\n\n /// @notice Checks if a transaction has been relayed\n /// @param transactionId The ID of the transaction to check\n /// @return True if the transaction has been relayed, false otherwise\n function bridgeRelays(bytes32 transactionId) external view returns (bool);\n\n /// @notice Returns the status of a bridge transaction\n /// @param transactionId The ID of the bridge transaction\n /// @return BridgeStatus Status of the bridge transaction\n function bridgeStatuses(bytes32 transactionId) external view returns (BridgeStatus);\n\n /// @notice Returns the timestamp and relayer of a bridge proof\n /// @param transactionId The ID of the bridge transaction\n /// @return timestamp The timestamp of the bridge proof\n /// @return relayer The relayer address of the bridge proof\n function bridgeProofs(bytes32 transactionId) external view returns (uint96 timestamp, address relayer);\n\n /// @notice Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\n /// @param request The bridge request to decode\n function getBridgeTransactionV2(bytes memory request) external view returns (BridgeTransactionV2 memory);\n}\n\n// contracts/utils/MulticallTarget.sol\n\n// solhint-disable avoid-low-level-calls\n/// @notice Template for a contract that supports batched calls (preserving the msg.sender).\n/// Only calls with zero msg.value could be batched.\nabstract contract MulticallTarget is IMulticallTarget {\n error MulticallTarget__UndeterminedRevert();\n\n /// @notice Perform a batched call to this contract, preserving the msg.sender.\n /// The return data from each call is discarded.\n /// @dev The method is non-payable, so only calls with `msg.value == 0` could be batched.\n /// It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag.\n /// Otherwise, the whole batch call will be reverted with the original revert reason.\n /// @param data List of abi-encoded calldata for the calls to perform.\n /// @param ignoreReverts Whether to ignore the revert errors from the calls.\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external {\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\n if (!success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(result);\n }\n }\n }\n\n /// @notice Perform a batched call to this contract, preserving the msg.sender.\n /// The return data from each call is preserved.\n /// @dev The method is non-payable, so only calls with `msg.value == 0` could be batched.\n /// It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag.\n /// Otherwise, the whole batch call will be reverted with the original revert reason.\n /// @param data List of abi-encoded calldata for the calls to perform.\n /// @param ignoreReverts Whether to ignore the revert errors from the calls.\n /// @return results List of results from the calls: `(success, returnData)`.\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results)\n {\n results = new Result[](data.length);\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (results[i].success, results[i].returnData) = address(this).delegatecall(data[i]);\n if (!results[i].success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(results[i].returnData);\n }\n }\n }\n\n /// @dev Bubbles the revert message from the underlying call.\n /// Note: preserves the same custom error or revert string, if one was used.\n /// Source: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v5.0.2/contracts/utils/Address.sol#L143-L158\n function _bubbleRevert(bytes memory returnData) internal pure {\n // Look for revert reason and bubble it up if present\n if (returnData.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n // solhint-disable-next-line no-inline-assembly\n assembly {\n let returndata_size := mload(returnData)\n revert(add(32, returnData), returndata_size)\n }\n } else {\n revert MulticallTarget__UndeterminedRevert();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// contracts/libs/BridgeTransactionV2.sol\n\n// solhint-disable no-inline-assembly\nlibrary BridgeTransactionV2Lib {\n uint16 internal constant VERSION = 2;\n\n // Offsets of the fields in the packed BridgeTransactionV2 struct\n // uint16 version [000 .. 002)\n // uint32 originChainId [002 .. 006)\n // uint32 destChainId [006 .. 010)\n // address originSender [010 .. 030)\n // address destRecipient [030 .. 050)\n // address originToken [050 .. 070)\n // address destToken [070 .. 090)\n // uint256 originAmount [090 .. 122)\n // uint256 destAmount [122 .. 154)\n // uint256 originFeeAmount [154 .. 186)\n // uint256 deadline [186 .. 218)\n // uint256 nonce [218 .. 250)\n // address exclusivityRelayer [250 .. 270)\n // uint256 exclusivityEndTime [270 .. 302)\n // uint256 zapNative [302 .. 334)\n // bytes zapData [334 .. ***)\n\n // forgefmt: disable-start\n uint256 private constant OFFSET_ORIGIN_CHAIN_ID = 2;\n uint256 private constant OFFSET_DEST_CHAIN_ID = 6;\n uint256 private constant OFFSET_ORIGIN_SENDER = 10;\n uint256 private constant OFFSET_DEST_RECIPIENT = 30;\n uint256 private constant OFFSET_ORIGIN_TOKEN = 50;\n uint256 private constant OFFSET_DEST_TOKEN = 70;\n uint256 private constant OFFSET_ORIGIN_AMOUNT = 90;\n uint256 private constant OFFSET_DEST_AMOUNT = 122;\n uint256 private constant OFFSET_ORIGIN_FEE_AMOUNT = 154;\n uint256 private constant OFFSET_DEADLINE = 186;\n uint256 private constant OFFSET_NONCE = 218;\n uint256 private constant OFFSET_EXCLUSIVITY_RELAYER = 250;\n uint256 private constant OFFSET_EXCLUSIVITY_END_TIME = 270;\n uint256 private constant OFFSET_ZAP_NATIVE = 302;\n uint256 private constant OFFSET_ZAP_DATA = 334;\n // forgefmt: disable-end\n\n error BridgeTransactionV2__InvalidEncodedTx();\n error BridgeTransactionV2__UnsupportedVersion(uint16 version);\n\n /// @notice Validates the encoded transaction to be a tightly packed encoded payload for BridgeTransactionV2.\n /// @dev Checks the minimum length and the version, use this function before decoding any of the fields.\n function validateV2(bytes calldata encodedTx) internal pure {\n // Check the minimum length: must at least include all static fields.\n if (encodedTx.length \u003c OFFSET_ZAP_DATA) revert BridgeTransactionV2__InvalidEncodedTx();\n // Once we validated the length, we can be sure that the version field is present.\n uint16 version_ = version(encodedTx);\n if (version_ != VERSION) revert BridgeTransactionV2__UnsupportedVersion(version_);\n }\n\n /// @notice Encodes the BridgeTransactionV2 struct by tightly packing the fields.\n /// @dev `abi.decode` will not work as a result of the tightly packed fields. Use `decodeV2` to decode instead.\n function encodeV2(IFastBridgeV2.BridgeTransactionV2 memory bridgeTx) internal pure returns (bytes memory) {\n // We split the encoding into two parts to avoid stack-too-deep error\n bytes memory firstPart = abi.encodePacked(\n VERSION,\n bridgeTx.originChainId,\n bridgeTx.destChainId,\n bridgeTx.originSender,\n bridgeTx.destRecipient,\n bridgeTx.originToken,\n bridgeTx.destToken,\n bridgeTx.originAmount\n );\n return abi.encodePacked(\n firstPart,\n bridgeTx.destAmount,\n bridgeTx.originFeeAmount,\n // Note: we skip the deprecated `sendChainGas` flag, which was present in BridgeTransaction V1\n bridgeTx.deadline,\n bridgeTx.nonce,\n // New V2 fields: exclusivity\n bridgeTx.exclusivityRelayer,\n bridgeTx.exclusivityEndTime,\n // New V2 fields: Zap\n bridgeTx.zapNative,\n bridgeTx.zapData\n );\n }\n\n /// @notice Decodes the BridgeTransactionV2 struct from the encoded transaction.\n /// @dev Encoded BridgeTransactionV2 struct must be tightly packed.\n /// Use `validateV2` before decoding to ensure the encoded transaction is valid.\n function decodeV2(bytes calldata encodedTx)\n internal\n pure\n returns (IFastBridgeV2.BridgeTransactionV2 memory bridgeTx)\n {\n bridgeTx.originChainId = originChainId(encodedTx);\n bridgeTx.destChainId = destChainId(encodedTx);\n bridgeTx.originSender = originSender(encodedTx);\n bridgeTx.destRecipient = destRecipient(encodedTx);\n bridgeTx.originToken = originToken(encodedTx);\n bridgeTx.destToken = destToken(encodedTx);\n bridgeTx.originAmount = originAmount(encodedTx);\n bridgeTx.destAmount = destAmount(encodedTx);\n bridgeTx.originFeeAmount = originFeeAmount(encodedTx);\n bridgeTx.deadline = deadline(encodedTx);\n bridgeTx.nonce = nonce(encodedTx);\n bridgeTx.exclusivityRelayer = exclusivityRelayer(encodedTx);\n bridgeTx.exclusivityEndTime = exclusivityEndTime(encodedTx);\n bridgeTx.zapNative = zapNative(encodedTx);\n bridgeTx.zapData = zapData(encodedTx);\n }\n\n /// @notice Extracts the version from the encoded transaction.\n function version(bytes calldata encodedTx) internal pure returns (uint16 version_) {\n // Load 32 bytes from the start and shift it 240 bits to the right to get the highest 16 bits.\n assembly {\n version_ := shr(240, calldataload(encodedTx.offset))\n }\n }\n\n /// @notice Extracts the origin chain ID from the encoded transaction.\n function originChainId(bytes calldata encodedTx) internal pure returns (uint32 originChainId_) {\n // Load 32 bytes from the offset and shift it 224 bits to the right to get the highest 32 bits.\n assembly {\n originChainId_ := shr(224, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_CHAIN_ID)))\n }\n }\n\n /// @notice Extracts the destination chain ID from the encoded transaction.\n function destChainId(bytes calldata encodedTx) internal pure returns (uint32 destChainId_) {\n // Load 32 bytes from the offset and shift it 224 bits to the right to get the highest 32 bits.\n assembly {\n destChainId_ := shr(224, calldataload(add(encodedTx.offset, OFFSET_DEST_CHAIN_ID)))\n }\n }\n\n /// @notice Extracts the origin sender from the encoded transaction.\n function originSender(bytes calldata encodedTx) internal pure returns (address originSender_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n originSender_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_SENDER)))\n }\n }\n\n /// @notice Extracts the destination recipient from the encoded transaction.\n function destRecipient(bytes calldata encodedTx) internal pure returns (address destRecipient_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n destRecipient_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_DEST_RECIPIENT)))\n }\n }\n\n /// @notice Extracts the origin token from the encoded transaction.\n function originToken(bytes calldata encodedTx) internal pure returns (address originToken_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n originToken_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_TOKEN)))\n }\n }\n\n /// @notice Extracts the destination token from the encoded transaction.\n function destToken(bytes calldata encodedTx) internal pure returns (address destToken_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n destToken_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_DEST_TOKEN)))\n }\n }\n\n /// @notice Extracts the origin amount from the encoded transaction.\n function originAmount(bytes calldata encodedTx) internal pure returns (uint256 originAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n originAmount_ := calldataload(add(encodedTx.offset, OFFSET_ORIGIN_AMOUNT))\n }\n }\n\n /// @notice Extracts the destination amount from the encoded transaction.\n function destAmount(bytes calldata encodedTx) internal pure returns (uint256 destAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n destAmount_ := calldataload(add(encodedTx.offset, OFFSET_DEST_AMOUNT))\n }\n }\n\n /// @notice Extracts the origin fee amount from the encoded transaction.\n function originFeeAmount(bytes calldata encodedTx) internal pure returns (uint256 originFeeAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n originFeeAmount_ := calldataload(add(encodedTx.offset, OFFSET_ORIGIN_FEE_AMOUNT))\n }\n }\n\n /// @notice Extracts the deadline from the encoded transaction.\n function deadline(bytes calldata encodedTx) internal pure returns (uint256 deadline_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n deadline_ := calldataload(add(encodedTx.offset, OFFSET_DEADLINE))\n }\n }\n\n /// @notice Extracts the nonce from the encoded transaction.\n function nonce(bytes calldata encodedTx) internal pure returns (uint256 nonce_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n nonce_ := calldataload(add(encodedTx.offset, OFFSET_NONCE))\n }\n }\n\n /// @notice Extracts the exclusivity relayer from the encoded transaction.\n function exclusivityRelayer(bytes calldata encodedTx) internal pure returns (address exclusivityRelayer_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n exclusivityRelayer_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_EXCLUSIVITY_RELAYER)))\n }\n }\n\n /// @notice Extracts the exclusivity end time from the encoded transaction.\n function exclusivityEndTime(bytes calldata encodedTx) internal pure returns (uint256 exclusivityEndTime_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n exclusivityEndTime_ := calldataload(add(encodedTx.offset, OFFSET_EXCLUSIVITY_END_TIME))\n }\n }\n\n /// @notice Extracts the Zap's native value from the encoded transaction.\n function zapNative(bytes calldata encodedTx) internal pure returns (uint256 zapNative_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n zapNative_ := calldataload(add(encodedTx.offset, OFFSET_ZAP_NATIVE))\n }\n }\n\n /// @notice Extracts the Zap's data from the encoded transaction.\n function zapData(bytes calldata encodedTx) internal pure returns (bytes calldata zapData_) {\n zapData_ = encodedTx[OFFSET_ZAP_DATA:];\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/AdminV2.sol\n\ncontract AdminV2 is AccessControlEnumerable, IAdminV2, IAdminV2Errors {\n using SafeERC20 for IERC20;\n\n /// @notice Address reserved for native gas token (ETH on Ethereum and most L2s, AVAX on Avalanche, etc)\n address public constant NATIVE_GAS_TOKEN = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Role identifier for Quoter API's off-chain authentication.\n /// @dev Only addresses with this role can post FastBridge quotes to the API.\n bytes32 public constant QUOTER_ROLE = keccak256(\"QUOTER_ROLE\");\n\n /// @notice Role identifier for Prover's on-chain authentication in FastBridge.\n /// @dev Only addresses with this role can provide proofs that a FastBridge request has been relayed.\n bytes32 public constant PROVER_ROLE = keccak256(\"PROVER_ROLE\");\n\n /// @notice Role identifier for Guard's on-chain authentication in FastBridge.\n /// @dev Only addresses with this role can dispute submitted relay proofs during the dispute period.\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n\n /// @notice Role identifier for Canceler's on-chain authentication in FastBridge.\n /// @dev Only addresses with this role can cancel a FastBridge transaction without the cancel delay.\n bytes32 public constant CANCELER_ROLE = keccak256(\"CANCELER_ROLE\");\n\n /// @notice Role identifier for Governor's on-chain administrative authority.\n /// @dev Only addresses with this role can perform administrative tasks within the contract.\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n /// @notice Denominator for fee rates, represents 100%.\n uint256 public constant FEE_BPS = 1e6;\n /// @notice Maximum protocol fee rate: 1% on origin amount.\n uint256 public constant FEE_RATE_MAX = 0.01e6;\n\n /// @notice Minimum cancel delay that can be set by the governor.\n uint256 public constant MIN_CANCEL_DELAY = 1 hours;\n /// @notice Default cancel delay set during the contract deployment.\n uint256 public constant DEFAULT_CANCEL_DELAY = 1 days;\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Delay for a transaction after which it could be permisionlessly cancelled\n uint256 public cancelDelay;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Use ZapNative V2 requests instead.\n uint256 public immutable chainGasAmount = 0;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n _setCancelDelay(DEFAULT_CANCEL_DELAY);\n }\n\n /// @notice Allows the contract governor to set the cancel delay. The cancel delay is the time after the transaction\n /// deadline after which it can be permissionlessly cancelled, if it hasn't been proven by any of the Relayers.\n function setCancelDelay(uint256 newCancelDelay) external onlyRole(GOVERNOR_ROLE) {\n _setCancelDelay(newCancelDelay);\n }\n\n /// @notice Allows the contract governor to set the protocol fee rate. The protocol fee is taken from the origin\n /// amount only for completed and claimed transactions.\n /// @dev The protocol fee is abstracted away from the relayers, they always operate using the amounts after fees:\n /// what they see as the origin amount emitted in the log is what they get credited with.\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n if (newFeeRate \u003e FEE_RATE_MAX) revert FeeRateAboveMax();\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n /// @notice Allows the contract governor to sweep the accumulated protocol fees in the contract.\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n emit FeesSwept(token, recipient, feeAmount);\n /// Sweep the fees as the last transaction action\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(recipient), feeAmount);\n } else {\n IERC20(token).safeTransfer(recipient, feeAmount);\n }\n }\n\n /// @notice Internal function to set the cancel delay. Security checks are performed outside of this function.\n function _setCancelDelay(uint256 newCancelDelay) private {\n if (newCancelDelay \u003c MIN_CANCEL_DELAY) revert CancelDelayBelowMin();\n uint256 oldCancelDelay = cancelDelay;\n cancelDelay = newCancelDelay;\n emit CancelDelayUpdated(oldCancelDelay, newCancelDelay);\n }\n}\n\n// contracts/FastBridgeV2.sol\n\n/// @notice FastBridgeV2 is a contract for bridging tokens across chains.\ncontract FastBridgeV2 is AdminV2, MulticallTarget, IFastBridgeV2, IFastBridgeV2Errors {\n using BridgeTransactionV2Lib for bytes;\n using SafeERC20 for IERC20;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n /// @notice Maximum length of accepted zapData\n uint256 public constant MAX_ZAP_DATA_LENGTH = 2 ** 16 - 1;\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeTxDetails) public bridgeTxDetails;\n /// @notice Relay details on destination chain\n mapping(bytes32 =\u003e BridgeRelay) public bridgeRelayDetails;\n /// @notice Unique bridge nonces tracked per originSender\n mapping(address =\u003e uint256) public senderNonces;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Replaced by senderNonces\n uint256 public immutable nonce = 0;\n /// @notice the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) AdminV2(_owner) {\n deployBlock = block.number;\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n bridge({\n params: params,\n paramsV2: BridgeParamsV2({\n quoteRelayer: address(0),\n quoteExclusivitySeconds: 0,\n quoteId: bytes(\"\"),\n zapNative: 0,\n zapData: bytes(\"\")\n })\n });\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes calldata request) external payable {\n // relay override will validate the request\n relay({request: request, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes calldata request, bytes32 destTxHash) external {\n request.validateV2();\n prove({transactionId: keccak256(request), destTxHash: destTxHash, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridgeV2\n function claim(bytes calldata request) external {\n // claim override will validate the request\n claim({request: request, to: address(0)});\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Aggregate the read operations from the same storage slot\n address disputedRelayer = $.proofRelayer;\n BridgeStatus status = $.status;\n uint56 proofBlockTimestamp = $.proofBlockTimestamp;\n // Can only dispute a RELAYER_PROVED transaction within the dispute period\n if (status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(proofBlockTimestamp) \u003e DISPUTE_PERIOD) {\n revert DisputePeriodPassed();\n }\n // Update status to REQUESTED and delete the disputed proof details\n // Note: these are storage writes\n $.status = BridgeStatus.REQUESTED;\n $.proofRelayer = address(0);\n $.proofBlockTimestamp = 0;\n\n emit BridgeProofDisputed(transactionId, disputedRelayer);\n }\n\n /// Note: this function is deprecated and will be removed in a future version.\n /// @inheritdoc IFastBridge\n function refund(bytes calldata request) external {\n cancel(request);\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // The correct relayer can only claim a RELAYER_PROVED transaction after the dispute period\n if ($.status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if ($.proofRelayer != relayer) revert SenderIncorrect();\n return _timeSince($.proofBlockTimestamp) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n /// @dev This method is added to achieve backwards compatibility with decoding requests into V1 structs:\n /// - `zapNative` is partially reported as a zero/non-zero flag\n /// - `zapData` is ignored\n /// In order to process all kinds of requests use getBridgeTransactionV2 instead.\n function getBridgeTransaction(bytes calldata request) external view returns (BridgeTransaction memory) {\n // Try decoding into V2 struct first. This will revert if V1 struct is passed\n try this.getBridgeTransactionV2(request) returns (BridgeTransactionV2 memory txV2) {\n // Note: we entirely ignore the zapData field, as it was not present in V1\n return BridgeTransaction({\n originChainId: txV2.originChainId,\n destChainId: txV2.destChainId,\n originSender: txV2.originSender,\n destRecipient: txV2.destRecipient,\n originToken: txV2.originToken,\n destToken: txV2.destToken,\n originAmount: txV2.originAmount,\n destAmount: txV2.destAmount,\n originFeeAmount: txV2.originFeeAmount,\n sendChainGas: txV2.zapNative != 0,\n deadline: txV2.deadline,\n nonce: txV2.nonce\n });\n } catch {\n // Fallback to V1 struct\n return abi.decode(request, (BridgeTransaction));\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function getBridgeTransactionV2(bytes calldata request) external pure returns (BridgeTransactionV2 memory) {\n request.validateV2();\n return BridgeTransactionV2Lib.decodeV2(request);\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) public payable {\n int256 exclusivityEndTime = 0;\n // if relayer exclusivity is not intended for this bridge, set exclusivityEndTime to static zero\n // otherwise, set exclusivity to expire at the current block ts offset by quoteExclusivitySeconds\n if (paramsV2.quoteRelayer != address(0)) {\n exclusivityEndTime = int256(block.timestamp) + paramsV2.quoteExclusivitySeconds;\n }\n _validateBridgeParams(params, paramsV2, exclusivityEndTime);\n\n // transfer tokens to bridge contract\n /// @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _takeBridgedUserAsset(params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) {\n originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n }\n\n // set status to requested\n bytes memory request = BridgeTransactionV2Lib.encodeV2(\n BridgeTransactionV2({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n deadline: params.deadline,\n nonce: senderNonces[params.sender]++, // increment nonce on every bridge\n exclusivityRelayer: paramsV2.quoteRelayer,\n // We checked exclusivityEndTime to be in range [0 .. params.deadline] above, so can safely cast\n exclusivityEndTime: uint256(exclusivityEndTime),\n zapNative: paramsV2.zapNative,\n zapData: paramsV2.zapData\n })\n );\n bytes32 transactionId = keccak256(request);\n // Note: the tx status will be updated throughout the tx lifecycle, while destChainId is set once here\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n bridgeTxDetails[transactionId].destChainId = params.dstChainId;\n\n emit BridgeRequested({\n transactionId: transactionId,\n sender: params.sender,\n request: request,\n destChainId: params.dstChainId,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n sendChainGas: paramsV2.zapNative != 0\n });\n emit BridgeQuoteDetails(transactionId, paramsV2.quoteId);\n }\n\n /// @inheritdoc IFastBridgeV2\n function relay(bytes calldata request, address relayer) public payable {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n _validateRelayParams(request, transactionId, relayer);\n // mark bridge transaction as relayed\n bridgeRelayDetails[transactionId] =\n BridgeRelay({blockNumber: uint48(block.number), blockTimestamp: uint48(block.timestamp), relayer: relayer});\n\n // transfer tokens to recipient on destination chain and trigger Zap if requested\n address to = request.destRecipient();\n address token = request.destToken();\n uint256 amount = request.destAmount();\n uint256 zapNative = request.zapNative();\n\n // Emit the event before any external calls\n emit BridgeRelayed({\n transactionId: transactionId,\n relayer: relayer,\n to: to,\n originChainId: request.originChainId(),\n originToken: request.originToken(),\n destToken: token,\n originAmount: request.originAmount(),\n destAmount: amount,\n chainGasAmount: zapNative\n });\n\n // All state changes have been done at this point, can proceed to the external calls.\n // This follows the checks-effects-interactions pattern to mitigate potential reentrancy attacks.\n if (token == NATIVE_GAS_TOKEN) {\n // For the native gas token, additional zapNative is not allowed\n if (zapNative != 0) revert ZapNativeNotSupported();\n // Check that the correct msg.value was sent\n if (msg.value != amount) revert MsgValueIncorrect();\n // Don't do a native transfer yet: we will handle it alongside the Zap below\n } else {\n // For ERC20s, we check that the correct msg.value was sent\n if (msg.value != zapNative) revert MsgValueIncorrect();\n // We need to transfer the tokens from the Relayer to the recipient first before performing an\n // optional post-transfer Zap.\n IERC20(token).safeTransferFrom(msg.sender, to, amount);\n }\n // At this point we have done:\n // - Transferred the requested amount of ERC20 tokens to the recipient.\n // At this point we have confirmed:\n // - For ERC20s: msg.value matches the requested zapNative amount.\n // - For the native gas token: msg.value matches the requested destAmount.\n // Remaining optional things to do:\n // - Forward the full msg.value to the recipient (if non-zero).\n // - Trigger a Zap (if zapData is present).\n bytes calldata zapData = request.zapData();\n if (zapData.length != 0) {\n // Zap Data is present: Zap has been requested by the recipient. Trigger it forwarding the full msg.value.\n\n // Note: if token has a fee on transfers, the recipient will have received less than `amount`.\n // This is a very niche edge case and should be handled by the recipient contract.\n _triggerZapWithChecks({recipient: to, token: token, amount: amount, zapData: zapData});\n } else if (msg.value != 0) {\n // Zap Data is missing, but msg.value was sent. This could happen in two different cases:\n // - Relay with the native gas token is happening.\n // - Relay with ERC20 is happening, with a `zapNative \u003e 0` request.\n // In both cases, we need to transfer the full msg.value to the recipient.\n Address.sendValue(payable(to), msg.value);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) public onlyRole(PROVER_ROLE) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n\n // Can only prove a REQUESTED transaction\n if ($.status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n // Update status to RELAYER_PROVED and store the proof details\n // Note: these are storage writes\n $.status = BridgeStatus.RELAYER_PROVED;\n $.proofBlockTimestamp = uint56(block.timestamp);\n $.proofRelayer = relayer;\n\n emit BridgeProofProvided(transactionId, relayer, destTxHash);\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes calldata request, address to) public {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Aggregate the read operations from the same storage slot\n address proofRelayer = $.proofRelayer;\n BridgeStatus status = $.status;\n uint56 proofBlockTimestamp = $.proofBlockTimestamp;\n\n // Can only claim a RELAYER_PROVED transaction after the dispute period\n if (status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(proofBlockTimestamp) \u003c= DISPUTE_PERIOD) {\n revert DisputePeriodNotPassed();\n }\n\n if (to == address(0)) {\n // Anyone could claim the funds to the proven relayer on their behalf\n to = proofRelayer;\n } else if (proofRelayer != msg.sender) {\n // Only the proven relayer could specify an address to claim the funds to\n revert SenderIncorrect();\n }\n\n // Update status to RELAYER_CLAIMED and transfer the origin collateral to the specified claim address\n // Note: this is a storage write\n $.status = BridgeStatus.RELAYER_CLAIMED;\n\n address token = request.originToken();\n uint256 amount = request.originAmount();\n // Update protocol fees if origin fee amount exists\n uint256 originFeeAmount = request.originFeeAmount();\n if (originFeeAmount \u003e 0) protocolFees[token] += originFeeAmount;\n // Emit the event before any external calls\n emit BridgeDepositClaimed(transactionId, proofRelayer, to, token, amount);\n // Complete the relayer claim as the last transaction action\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(to), amount);\n } else {\n IERC20(token).safeTransfer(to, amount);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function cancel(bytes calldata request) public {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Can only cancel a REQUESTED transaction after its deadline expires\n if ($.status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n uint256 deadline = request.deadline();\n // Permissionless cancel is only allowed after `cancelDelay` on top of the deadline\n if (!hasRole(CANCELER_ROLE, msg.sender)) deadline += cancelDelay;\n if (block.timestamp \u003c= deadline) revert DeadlineNotExceeded();\n // Update status to REFUNDED and return the full amount (collateral + protocol fees) to the original sender.\n // The protocol fees are only updated when the transaction is claimed, so we don't need to update them here.\n // Note: this is a storage write\n $.status = BridgeStatus.REFUNDED;\n\n address to = request.originSender();\n address token = request.originToken();\n uint256 amount = request.originAmount() + request.originFeeAmount();\n // Emit the event before any external calls\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n // Complete the user cancel as the last transaction action\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(to), amount);\n } else {\n IERC20(token).safeTransfer(to, amount);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeStatuses(bytes32 transactionId) public view returns (BridgeStatus status) {\n return bridgeTxDetails[transactionId].status;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeProofs(bytes32 transactionId) public view returns (uint96 timestamp, address relayer) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n\n timestamp = $.proofBlockTimestamp;\n relayer = $.proofRelayer;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeRelays(bytes32 transactionId) public view returns (bool) {\n // has this transactionId been relayed?\n return bridgeRelayDetails[transactionId].relayer != address(0);\n }\n\n /// @notice Takes the bridged asset from the user into FastBridgeV2 custody. It will be later\n /// claimed by the relayer who completed the relay on destination chain, or transferred back to the user\n /// via the cancel function should no one complete the relay.\n function _takeBridgedUserAsset(address token, uint256 amount) internal returns (uint256 amountTaken) {\n if (token == NATIVE_GAS_TOKEN) {\n // For the native gas token, we just need to check that the supplied msg.value is correct.\n // Supplied `msg.value` is already in FastBridgeV2 custody.\n if (amount != msg.value) revert MsgValueIncorrect();\n amountTaken = msg.value;\n } else {\n // For ERC20s, token is explicitly transferred from the user to FastBridgeV2.\n // We don't allow non-zero `msg.value` to avoid extra funds from being stuck in FastBridgeV2.\n if (msg.value != 0) revert MsgValueIncorrect();\n // Throw an explicit error if the provided token address is not a contract\n if (token.code.length == 0) revert TokenNotContract();\n amountTaken = IERC20(token).balanceOf(address(this));\n IERC20(token).safeTransferFrom(msg.sender, address(this), amount);\n // Use the balance difference as the amount taken in case of fee on transfer tokens.\n amountTaken = IERC20(token).balanceOf(address(this)) - amountTaken;\n }\n }\n\n /// @notice Calls the Recipient's hook function with the specified zapData and performs\n /// all the necessary checks for the returned value.\n function _triggerZapWithChecks(address recipient, address token, uint256 amount, bytes calldata zapData) internal {\n // This will bubble any revert messages from the hook function\n bytes memory returnData = Address.functionCallWithValue({\n target: recipient,\n data: abi.encodeCall(IZapRecipient.zap, (token, amount, zapData)),\n // Note: see `relay()` for reasoning behind passing msg.value\n value: msg.value\n });\n // Explicit revert if no return data at all\n if (returnData.length == 0) revert RecipientNoReturnValue();\n // Check that exactly a single return value was returned\n if (returnData.length != 32) revert RecipientIncorrectReturnValue();\n // Return value should be abi-encoded hook function selector\n if (bytes32(returnData) != bytes32(IZapRecipient.zap.selector)) {\n revert RecipientIncorrectReturnValue();\n }\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint56(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint56).max but\n /// proof.timestamp \u003c type(uint56).max via unchecked statement\n /// @param proofBlockTimestamp The bridge proof block timestamp\n /// @return delta Time delta since proof submitted\n function _timeSince(uint56 proofBlockTimestamp) internal view returns (uint256 delta) {\n unchecked {\n delta = uint56(block.timestamp) - proofBlockTimestamp;\n }\n }\n\n /// @notice Performs all the necessary checks for a bridge to happen.\n /// @dev There's no good way to refactor this function to reduce cyclomatic complexity due to\n /// the number of checks that need to be performed, so we skip the code-complexity rule here.\n // solhint-disable-next-line code-complexity\n function _validateBridgeParams(\n BridgeParams memory params,\n BridgeParamsV2 memory paramsV2,\n int256 exclusivityEndTime\n )\n internal\n view\n {\n // Check V1 (legacy) params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.sender == address(0) || params.to == address(0)) revert ZeroAddress();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n // Check V2 params\n if (paramsV2.zapData.length \u003e MAX_ZAP_DATA_LENGTH) revert ZapDataLengthAboveMax();\n if (paramsV2.zapNative != 0 \u0026\u0026 params.destToken == NATIVE_GAS_TOKEN) {\n revert ZapNativeNotSupported();\n }\n // exclusivityEndTime must be in range [0 .. params.deadline]\n if (exclusivityEndTime \u003c 0 || exclusivityEndTime \u003e int256(params.deadline)) {\n revert ExclusivityParamsIncorrect();\n }\n }\n\n /// @notice Performs all the necessary checks for a relay to happen.\n function _validateRelayParams(bytes calldata request, bytes32 transactionId, address relayer) internal view {\n if (relayer == address(0)) revert ZeroAddress();\n // Check if the transaction has already been relayed\n if (bridgeRelays(transactionId)) revert TransactionRelayed();\n if (request.destChainId() != block.chainid) revert ChainIncorrect();\n // Check the deadline for relay to happen\n if (block.timestamp \u003e request.deadline()) revert DeadlineExceeded();\n // Check the exclusivity period, if it is still ongoing\n address exclRelayer = request.exclusivityRelayer();\n if (exclRelayer != address(0) \u0026\u0026 exclRelayer != relayer \u0026\u0026 block.timestamp \u003c= request.exclusivityEndTime()) {\n revert ExclusivityPeriodNotPassed();\n }\n }\n}\n","language":"Solidity","languageVersion":"0.8.24","compilerVersion":"0.8.24","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"25831:11640:0:-:0;;;;;;;;;;;;;;;-1:-1:-1;;;25831:11640:0;;;;;;;;;;;;;;;;;","srcMapRuntime":"25831:11640:0:-:0;;;;;;;;","abiDefinition":[],"userDoc":{"kind":"user","methods":{},"version":1},"developerDoc":{"details":"Library for managing https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive types. Sets have the following properties: - Elements are added, removed, and checked for existence in constant time (O(1)). - Elements are enumerated in O(n). No guarantees are made on the ordering. ```solidity contract Example { // Add the library methods using EnumerableSet for EnumerableSet.AddressSet; // Declare a set state variable EnumerableSet.AddressSet private mySet; } ``` As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`) and `uint256` (`UintSet`) are supported. [WARNING] ==== Trying to delete such a structure from storage will likely result in data corruption, rendering the structure unusable. See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info. In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an array of EnumerableSet. ====","kind":"dev","methods":{},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[],\"devdoc\":{\"details\":\"Library for managing https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive types. Sets have the following properties: - Elements are added, removed, and checked for existence in constant time (O(1)). - Elements are enumerated in O(n). No guarantees are made on the ordering. ```solidity contract Example { // Add the library methods using EnumerableSet for EnumerableSet.AddressSet; // Declare a set state variable EnumerableSet.AddressSet private mySet; } ``` As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`) and `uint256` (`UintSet`) are supported. [WARNING] ==== Trying to delete such a structure from storage will likely result in data corruption, rendering the structure unusable. See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info. In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an array of EnumerableSet. ====\",\"kind\":\"dev\",\"methods\":{},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeV2.sol\":\"EnumerableSet\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeV2.sol\":{\"keccak256\":\"0xac79c463688a682ca706a4ef95e7817b83548cdfa8182ba0426ac7e5e07613d8\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://b3ecb7097381287cafc3a73f3a2bb03565115ebb682a85064e0b0dc2f7e2919d\",\"dweb:/ipfs/QmatruW3nYZTksf3CeQ8wwiAG4c7xoEJBEp6drHPtFLBRK\"]}},\"version\":1}"},"hashes":{}},"solidity/FastBridgeV2.sol:FastBridgeV2":{"code":"0x60e06040526000608081905260a0523480156200001b57600080fd5b50604051620047ee380380620047ee8339810160408190526200003e9162000215565b806200004c60008262000067565b506200005b62015180620000a4565b50504360c05262000240565b6000806200007684846200010d565b905080156200009b576000848152600160205260409020620000999084620001bb565b505b90505b92915050565b610e10811015620000c857604051630e0ea5c760e01b815260040160405180910390fd5b600480549082905560408051828152602081018490527f909f9078b2f6eac1d10f2aae793656c5a67511eb627ebd1d2cb1eb9c0ab94c95910160405180910390a15050565b6000828152602081815260408083206001600160a01b038516845290915281205460ff16620001b2576000838152602081815260408083206001600160a01b03861684529091529020805460ff19166001179055620001693390565b6001600160a01b0316826001600160a01b0316847f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45060016200009e565b5060006200009e565b60006200009b836001600160a01b0384166000818152600183016020526040812054620001b2575081546001818101845560008481526020808220909301849055845484825282860190935260409020919091556200009e565b6000602082840312156200022857600080fd5b81516001600160a01b03811681146200009b57600080fd5b60805160a05160c05161457e62000270600039600061094b015260006109ec01526000610bec015261457e6000f3fe60806040526004361061034a5760003560e01c80638379a24f116101bb578063ac11fb1a116100f7578063c79371b111610095578063d547741f1161006f578063d547741f14610b59578063dc9a4ef614610b79578063dcf844a714610bad578063e00a83e014610bda57600080fd5b8063c79371b114610a78578063ca15c87314610b05578063ccc5749014610b2557600080fd5b8063b13aa2d6116100d1578063b13aa2d614610a0e578063bf333f2c14610a2e578063bfc7c60714610a45578063c63ff8dd14610a5857600080fd5b8063ac11fb1a1461098d578063add98c70146109ba578063affed0e0146109da57600080fd5b8063922b748711610164578063a217fddf1161013e578063a217fddf14610924578063a3ec191a14610939578063a5bbe22b14610769578063aa9641ab1461096d57600080fd5b8063922b7487146108e4578063930ac180146108fa5780639c9545f01461091157600080fd5b80639010d07c116101955780639010d07c146107fa57806391ad50391461081a57806391d14854146108a057600080fd5b80638379a24f1461077f578063886d36ff146107c75780638f0d6f17146107e757600080fd5b8063385c1d2f1161028a57806358f858801161023357806363787e521161020d57806363787e52146106a5578063638a0f091461071f5780637ebe815c14610735578063820688d51461076957600080fd5b806358f85880146106425780635aa6ccba146106585780635eb7d9461461068557600080fd5b806341fcb6121161026457806341fcb612146105f9578063458516941461061957806354eff0681461062c57600080fd5b8063385c1d2f1461058c5780633c5beeb4146105b95780633f61331d146105d957600080fd5b80630f862f1e116102f7578063248a9ca3116102d1578063248a9ca3146104ef578063295710ff1461051f5780632f2ff15d1461054c57806336568abe1461056c57600080fd5b80630f862f1e1461046f57806318e4357d146104af5780631ea327c5146104cf57600080fd5b8063051287bc11610328578063051287bc146103fa57806306f333f2146104375780630f5f6ed71461045957600080fd5b806301ffc9a71461034f57806302d2ff661461038457806303ed0ee5146103c6575b600080fd5b34801561035b57600080fd5b5061036f61036a36600461352a565b610c0e565b60405190151581526020015b60405180910390f35b34801561039057600080fd5b506103b87febfdca8e46c0b8dacf9989ee613e35727eadd20a1d5e5ad01a53968c7e5fe07a81565b60405190815260200161037b565b3480156103d257600080fd5b506103b87f043c983c49d46f0e102151eaf8085d4a2e6571d5df2d47b013f39bddfd4a639d81565b34801561040657600080fd5b5061042a61041536600461356c565b60009081526005602052604090205460ff1690565b60405161037b91906135ef565b34801561044357600080fd5b50610457610452366004613622565b610c6a565b005b34801561046557600080fd5b506103b861271081565b34801561047b57600080fd5b5061049773eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee81565b6040516001600160a01b03909116815260200161037b565b3480156104bb57600080fd5b506104576104ca36600461365b565b610d77565b3480156104db57600080fd5b506104576104ea36600461356c565b610e8c565b3480156104fb57600080fd5b506103b861050a36600461356c565b60009081526020819052604090206001015490565b34801561052b57600080fd5b506103b861053a366004613694565b60076020526000908152604090205481565b34801561055857600080fd5b506104576105673660046136b1565b610ec3565b34801561057857600080fd5b506104576105873660046136b1565b610ee8565b34801561059857600080fd5b506105ac6105a73660046136ef565b610f34565b60405161037b91906137ba565b3480156105c557600080fd5b506104576105d4366004613899565b6110c2565b3480156105e557600080fd5b506104576105f43660046136ef565b6112c4565b34801561060557600080fd5b506104576106143660046138db565b61136e565b610457610627366004613adc565b6115e0565b34801561063857600080fd5b506103b861ffff81565b34801561064e57600080fd5b506103b860025481565b34801561066457600080fd5b50610678610673366004613899565b61163d565b60405161037b9190613af9565b34801561069157600080fd5b506104576106a0366004613899565b61170a565b3480156106b157600080fd5b5061070f6106c036600461356c565b60056020526000908152604090205460ff811690610100810463ffffffff169065010000000000810466ffffffffffffff16906c0100000000000000000000000090046001600160a01b031684565b60405161037b9493929190613c16565b34801561072b57600080fd5b506103b860045481565b34801561074157600080fd5b506103b87f9a04aea0a349253cc7277afafdf6ead6729a3972a47ffb40eaef2c93d4e1bfea81565b34801561077557600080fd5b506103b861070881565b34801561078b57600080fd5b5061036f61079a36600461356c565b6000908152600660205260409020546c0100000000000000000000000090046001600160a01b0316151590565b3480156107d357600080fd5b506104576107e2366004613c57565b611714565b6104576107f5366004613899565b611740565b34801561080657600080fd5b50610497610815366004613ca3565b61174b565b34801561082657600080fd5b5061087461083536600461356c565b60009081526005602052604090205465010000000000810466ffffffffffffff16916c010000000000000000000000009091046001600160a01b031690565b604080516bffffffffffffffffffffffff90931683526001600160a01b0390911660208301520161037b565b3480156108ac57600080fd5b5061036f6108bb3660046136b1565b6000918252602082815260408084206001600160a01b0393909316845291905290205460ff1690565b3480156108f057600080fd5b506103b8610e1081565b34801561090657600080fd5b506103b86201518081565b61045761091f3660046138db565b611763565b34801561093057600080fd5b506103b8600081565b34801561094557600080fd5b506103b87f000000000000000000000000000000000000000000000000000000000000000081565b34801561097957600080fd5b5061036f6109883660046136b1565b611a1d565b34801561099957600080fd5b506109ad6109a8366004613899565b611af4565b60405161037b9190613cc5565b3480156109c657600080fd5b506104576109d536600461356c565b611ca8565b3480156109e657600080fd5b506103b87f000000000000000000000000000000000000000000000000000000000000000081565b348015610a1a57600080fd5b50610457610a2936600461356c565b611df2565b348015610a3a57600080fd5b506103b8620f424081565b610457610a53366004613e29565b611e9e565b348015610a6457600080fd5b50610457610a73366004613899565b61212d565b348015610a8457600080fd5b50610ad7610a9336600461356c565b60066020526000908152604090205465ffffffffffff8082169166010000000000008104909116906c0100000000000000000000000090046001600160a01b031683565b6040805165ffffffffffff94851681529390921660208401526001600160a01b03169082015260600161037b565b348015610b1157600080fd5b506103b8610b2036600461356c565b612139565b348015610b3157600080fd5b506103b87f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f5581565b348015610b6557600080fd5b50610457610b743660046136b1565b612150565b348015610b8557600080fd5b506103b87f60044782a422109ac08a415e44260ad5d3bad63d96ebe1fac0363399642ee3f281565b348015610bb957600080fd5b506103b8610bc8366004613694565b60036020526000908152604090205481565b348015610be657600080fd5b506103b87f000000000000000000000000000000000000000000000000000000000000000081565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f5a05180f000000000000000000000000000000000000000000000000000000001480610c645750610c6482612175565b92915050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f55610c948161220c565b6001600160a01b03831660009081526003602052604081205490819003610cbb5750505050565b6001600160a01b038481166000818152600360209081526040808320929092558151928352928616928201929092529081018290527f244e51bc38c1452fa8aaf487bcb4bca36c2baa3a5fbdb776b1eabd8dc6d277cd9060600160405180910390a17fffffffffffffffffffffffff11111111111111111111111111111111111111126001600160a01b03851601610d5c57610d578382612216565b610d70565b610d706001600160a01b03851684836122e4565b505b505050565b7f60044782a422109ac08a415e44260ad5d3bad63d96ebe1fac0363399642ee3f2610da18161220c565b60008481526005602052604090206001815460ff166004811115610dc757610dc7613585565b14610dfe576040517f4145817200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80546001600160a01b0384166c0100000000000000000000000081026bffffffffffffffffffffffff66ffffffffffffff421665010000000000021664ffffffff009093169290921791909117600217825560405185815286907f4ac8af8a2cd87193d64dfc7a3b8d9923b714ec528b18725d080aa1299be0c5e49060200160405180910390a35050505050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f55610eb68161220c565b610ebf82612358565b5050565b600082815260208190526040902060010154610ede8161220c565b610d7083836123d9565b6001600160a01b0381163314610f2a576040517f6697b23200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610d728282612406565b60608267ffffffffffffffff811115610f4f57610f4f613927565b604051908082528060200260200182016040528015610f9557816020015b604080518082019091526000815260606020820152815260200190600190039081610f6d5790505b50905060005b838110156110ba5730858583818110610fb657610fb6613ef7565b9050602002810190610fc89190613f26565b604051610fd6929190613f8b565b600060405180830381855af49150503d8060008114611011576040519150601f19603f3d011682016040523d82523d6000602084013e611016565b606091505b5083838151811061102957611029613ef7565b602002602001015160000184848151811061104657611046613ef7565b60200260200101516020018290528215151515815250505081818151811061107057611070613ef7565b602002602001015160000151158015611087575082155b156110b2576110b28282815181106110a1576110a1613ef7565b602002602001015160200151612433565b600101610f9b565b509392505050565b6110cc8282612475565b600082826040516110de929190613f8b565b604080519182900390912060008181526005602052919091209091506001815460ff16600481111561111257611112613585565b14611149576040517f4145817200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b3360009081527f4527d8b28c468984933d33ae052f26b21c15ca0e7fdec762bba08e540e237001602052604090205460ba8501359060ff16611195576004546111929082613fca565b90505b8042116111ce576040517fe15ff9ea00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b81547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166004178255600a850135606090811c906032870135901c600061121d609a890135605a8a0135613fca565b604080516001600160a01b03858116825260208201849052825193945086169289927fb4c55c0c9bc613519b920e88748090150b890a875d307f21bea7d4fb2e8bc958928290030190a37fffffffffffffffffffffffff11111111111111111111111111111111111111126001600160a01b038316016112a6576112a18382612216565b6112ba565b6112ba6001600160a01b03831684836122e4565b5050505050505050565b60005b82811015610d7057600080308686858181106112e5576112e5613ef7565b90506020028101906112f79190613f26565b604051611305929190613f8b565b600060405180830381855af49150503d8060008114611340576040519150601f19603f3d011682016040523d82523d6000602084013e611345565b606091505b509150915081158015611356575083155b156113645761136481612433565b50506001016112c7565b6113788383612475565b6000838360405161138a929190613f8b565b604080519182900390912060008181526005602052919091208054919250906c0100000000000000000000000081046001600160a01b03169060ff81169065010000000000900466ffffffffffffff1660028260048111156113ee576113ee613585565b14611425576040517f4145817200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6107084282900366ffffffffffffff161161146c576040517f1992d0bd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600160a01b038616611482578295506114c4565b6001600160a01b03831633146114c4576040517f4af43a9000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b83547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166003178455603288013560601c605a890135609a8a01358015611533576001600160a01b0383166000908152600360205260408120805483929061152d908490613fca565b90915550505b604080516001600160a01b03858116825260208201859052808c1692908916918b917f582211c35a2139ac3bbaac74663c6a1f56c6cbb658b41fe11fd45a82074ac678910160405180910390a47fffffffffffffffffffffffff11111111111111111111111111111111111111126001600160a01b038416016115bf576115ba8983612216565b6115d3565b6115d36001600160a01b0384168a846122e4565b5050505050505050505050565b61163a816040518060a0016040528060006001600160a01b03168152602001600081526020016040518060200160405280600081525081526020016000815260200160405180602001604052806000815250815250611e9e565b50565b6116ef604051806101e00160405280600063ffffffff168152602001600063ffffffff16815260200160006001600160a01b0316815260200160006001600160a01b0316815260200160006001600160a01b0316815260200160006001600160a01b03168152602001600081526020016000815260200160008152602001600081526020016000815260200160006001600160a01b031681526020016000815260200160008152602001606081525090565b6116f98383612475565b61170383836124f6565b9392505050565b610ebf82826110c2565b61171e8383612475565b610d728383604051611731929190613f8b565b60405180910390208233610d77565b610ebf828233611763565b60008281526001602052604081206117039083612698565b61176d8383612475565b6000838360405161177f929190613f8b565b60405180910390209050611795848483856126a4565b6040805160608101825265ffffffffffff438116825242811660208084019182526001600160a01b038088168587019081526000888152600690935295822094518554935196519091166c01000000000000000000000000026bffffffffffffffffffffffff9685166601000000000000027fffffffffffffffffffffffffffffffffffffffff0000000000000000000000009094169190941617919091179390931617905561184985601e013560601c90565b9050604685013560601c607a86013561012e8701356001600160a01b03808516908716867ff8ae392d784b1ea5e8881bfa586d81abf07ef4f1e2fc75f7fe51c90f05199a5c60028c013560e01c6040805163ffffffff92909216825260328e0135606090811c60208401526001600160a01b038a1683830152605a8f0135908301526080820188905260a08201879052519081900360c00190a47fffffffffffffffffffffffff11111111111111111111111111111111111111126001600160a01b0384160161198957801561194b576040517f846dedc000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b813414611984576040517f81de0bf300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6119d7565b8034146119c2576040517f81de0bf300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6119d76001600160a01b038416338685612839565b3660006119e48a8a612872565b90925090508015611a01576119fc868686858561288e565b611a11565b3415611a1157611a118634612216565b50505050505050505050565b60008281526005602052604081206002815460ff166004811115611a4357611a43613585565b14611a7a576040517f4145817200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80546001600160a01b038481166c010000000000000000000000009092041614611ad0576040517f4af43a9000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b546107086501000000000090910466ffffffffffffff908116420316119392505050565b6040805161018081018252600080825260208201819052818301819052606082018190526080820181905260a0820181905260c0820181905260e0820181905261010082018190526101208201819052610140820181905261016082015290517f5aa6ccba0000000000000000000000000000000000000000000000000000000081523090635aa6ccba90611b8f9086908690600401614008565b600060405180830381865afa925050508015611bcd57506040513d6000823e601f3d908101601f19168201604052611bca9190810190614077565b60015b611be457611bdd828401846141ac565b9050610c64565b604051806101800160405280826000015163ffffffff168152602001826020015163ffffffff16815260200182604001516001600160a01b0316815260200182606001516001600160a01b0316815260200182608001516001600160a01b031681526020018260a001516001600160a01b031681526020018260c0015181526020018260e0015181526020018261010001518152602001826101a0015160001415151581526020018261012001518152602001826101400151815250915050610c64565b7f043c983c49d46f0e102151eaf8085d4a2e6571d5df2d47b013f39bddfd4a639d611cd28161220c565b600082815260056020526040902080546c0100000000000000000000000081046001600160a01b03169060ff81169065010000000000900466ffffffffffffff166002826004811115611d2757611d27613585565b14611d5e576040517f4145817200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6107084282900366ffffffffffffff161115611da6576040517f3e908aac00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b835464ffffffff001660011784556040516001600160a01b0384169087907f0695cf1d39b3055dcd0fe02d8b47eaf0d5a13e1996de925de59d0ef9b7f7fad490600090a3505050505050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f55611e1c8161220c565b612710821115611e58576040517f9b569b8100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600280549083905560408051828152602081018590527f14914da2bf76024616fbe1859783fcd4dbddcb179b1f3a854949fbf920dcb957910160405180910390a1505050565b80516000906001600160a01b031615611ec3576020820151611ec09042614278565b90505b611ece8383836129ea565b6000611ee284606001518560a00151612c6e565b90506000806002541115611f1b57620f424060025483611f0291906142a0565b611f0c91906142b7565b9050611f1881836142f2565b91505b6000612024604051806101e001604052804663ffffffff168152602001886000015163ffffffff16815260200188602001516001600160a01b0316815260200188604001516001600160a01b0316815260200188606001516001600160a01b0316815260200188608001516001600160a01b031681526020018581526020018860c0015181526020018481526020018861010001518152602001600760008a602001516001600160a01b03166001600160a01b031681526020019081526020016000206000815480929190611fef90614305565b90915550815287516001600160a01b031660208201526040810187905260608089015190820152608080890151910152612e81565b805160208083019190912060008181526005835260409081902080548b5163ffffffff8116610100027fffffffffffffffffffffffffffffffffffffffffffffffffffffff000000000090921691909117600117909155928a01516060808c015160808d015160c08e0151928d0151945197985094966001600160a01b039093169587957f120ea0364f36cdac7983bcfdd55270ca09d7f9b314a2ebc425a3b01ab1d6403a956120e0958b959394938e9290919015159061433d565b60405180910390a3807f3120e2bb59c86aca6890191a589a96af3662838efa374fbdcdf4c95bfe4a6c0e876040015160405161211c9190614393565b60405180910390a250505050505050565b610ebf8282600061136e565b6000818152600160205260408120610c6490612fc6565b60008281526020819052604090206001015461216b8161220c565b610d708383612406565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f7965db0b000000000000000000000000000000000000000000000000000000001480610c6457507f01ffc9a7000000000000000000000000000000000000000000000000000000007fffffffff00000000000000000000000000000000000000000000000000000000831614610c64565b61163a8133612fd0565b80471015612257576040517fcd7860590000000000000000000000000000000000000000000000000000000081523060048201526024015b60405180910390fd5b6000826001600160a01b03168260405160006040518083038185875af1925050503d80600081146122a4576040519150601f19603f3d011682016040523d82523d6000602084013e6122a9565b606091505b5050905080610d72576040517f1425ea4200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040516001600160a01b03838116602483015260448201839052610d7291859182169063a9059cbb906064015b604051602081830303815290604052915060e01b6020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff838183161783525050505061303c565b610e10811015612394576040517f0e0ea5c700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600480549082905560408051828152602081018490527f909f9078b2f6eac1d10f2aae793656c5a67511eb627ebd1d2cb1eb9c0ab94c95910160405180910390a15050565b6000806123e684846130b8565b905080156117035760008481526001602052604090206110ba9084613180565b6000806124138484613195565b905080156117035760008481526001602052604090206110ba9084613236565b8051156124435780518082602001fd5b6040517f5ead5a9d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61014e8110156124b1576040517f6ee0e17100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b813560f01c60028114610d72576040517f8bd977e700000000000000000000000000000000000000000000000000000000815261ffff8216600482015260240161224e565b6125a8604051806101e00160405280600063ffffffff168152602001600063ffffffff16815260200160006001600160a01b0316815260200160006001600160a01b0316815260200160006001600160a01b0316815260200160006001600160a01b03168152602001600081526020016000815260200160008152602001600081526020016000815260200160006001600160a01b031681526020016000815260200160008152602001606081525090565b600283013560e090811c82526006840135811c6020830152600a840135606090811c6040840152601e850135811c818401526032850135811c60808401526046850135811c60a0840152605a85013560c0840152607a85013591830191909152609a84013561010083015260ba84013561012083015260da84013561014083015260fa840135901c61016082015261010e83013561018082015261012e8301356101a08201526126588383612872565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152505050506101c082015292915050565b6000611703838361324b565b6001600160a01b0381166126e4576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000828152600660205260409020546c0100000000000000000000000090046001600160a01b031615612743576040517fbef7bb7d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600684013560e01c4614612783576040517f7029fdf900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60ba8401354211156127c1576040517f559895a300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60fa84013560601c80158015906127ea5750816001600160a01b0316816001600160a01b031614155b80156127fb575061010e8501354211155b15612832576040517f14be123200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5050505050565b6040516001600160a01b038481166024830152838116604483015260648201839052610d709186918216906323b872dd90608401612311565b3660006128838361014e81876143a6565b915091509250929050565b600061290986868686866040516024016128ab94939291906143d0565b60408051601f198184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fe85e13dd0000000000000000000000000000000000000000000000000000000017905234613275565b90508051600003612946576040517f1a95ad2600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8051602014612981576040517ff3725cca00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7fe85e13dd000000000000000000000000000000000000000000000000000000006129ab826143f9565b146129e2576040517ff3725cca00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b505050505050565b46836000015163ffffffff1603612a2d576040517f7029fdf900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60a08301511580612a40575060c0830151155b15612a77576040517fe38820c800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60208301516001600160a01b03161580612a9c575060408301516001600160a01b0316155b15612ad3576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60608301516001600160a01b03161580612af8575060808301516001600160a01b0316155b15612b2f576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b612b3b61070842613fca565b8361010001511015612b79576040517f04b7fcc800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61ffff8260800151511115612bba576040517f177a70e100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b606082015115801590612bed575060808301516001600160a01b031673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee145b15612c24576040517f846dedc000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000811280612c37575082610100015181135b15610d72576040517f352807b900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60007fffffffffffffffffffffffff11111111111111111111111111111111111111126001600160a01b03841601612ce057348214612cd9576040517f81de0bf300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5034610c64565b3415612d18576040517f81de0bf300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b826001600160a01b03163b600003612d5c576040517f7f523fe800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201526001600160a01b038416906370a0823190602401602060405180830381865afa158015612db9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612ddd919061443e565b9050612df46001600160a01b038416333085612839565b6040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015281906001600160a01b038516906370a0823190602401602060405180830381865afa158015612e53573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612e77919061443e565b61170391906142f2565b8051602080830151604080850151606086810151608088015160a089015160c08a015195517e02000000000000000000000000000000000000000000000000000000000000988101989098527fffffffff0000000000000000000000000000000000000000000000000000000060e0998a1b811660228a01529690981b90951660268701527fffffffffffffffffffffffffffffffffffffffff00000000000000000000000092821b8316602a870152811b8216603e86015292831b8116605285015293821b9093166066830152607a820192909252600090609a0160408051601f198184030181529082905260e08501516101008601516101208701516101408801516101608901516101808a01516101a08b01516101c08c0151979950612faf988a9890602001614457565b604051602081830303815290604052915050919050565b6000610c64825490565b6000828152602081815260408083206001600160a01b038516845290915290205460ff16610ebf576040517fe2517d3f0000000000000000000000000000000000000000000000000000000081526001600160a01b03821660048201526024810183905260440161224e565b60006130516001600160a01b0384168361332b565b9050805160001415801561307657508080602001905181019061307491906144e0565b155b15610d72576040517f5274afe70000000000000000000000000000000000000000000000000000000081526001600160a01b038416600482015260240161224e565b6000828152602081815260408083206001600160a01b038516845290915281205460ff16613178576000838152602081815260408083206001600160a01b0386168452909152902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790556131303390565b6001600160a01b0316826001600160a01b0316847f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a4506001610c64565b506000610c64565b6000611703836001600160a01b038416613339565b6000828152602081815260408083206001600160a01b038516845290915281205460ff1615613178576000838152602081815260408083206001600160a01b038616808552925280832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016905551339286917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a4506001610c64565b6000611703836001600160a01b038416613380565b600082600001828154811061326257613262613ef7565b9060005260206000200154905092915050565b6060814710156132b3576040517fcd78605900000000000000000000000000000000000000000000000000000000815230600482015260240161224e565b600080856001600160a01b031684866040516132cf91906144fd565b60006040518083038185875af1925050503d806000811461330c576040519150601f19603f3d011682016040523d82523d6000602084013e613311565b606091505b5091509150613321868383613473565b9695505050505050565b606061170383836000613275565b600081815260018301602052604081205461317857508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155610c64565b600081815260018301602052604081205480156134695760006133a46001836142f2565b85549091506000906133b8906001906142f2565b905080821461341d5760008660000182815481106133d8576133d8613ef7565b90600052602060002001549050808760000184815481106133fb576133fb613ef7565b6000918252602080832090910192909255918252600188019052604090208390555b855486908061342e5761342e614519565b600190038181906000526020600020016000905590558560010160008681526020019081526020016000206000905560019350505050610c64565b6000915050610c64565b60608261348857613483826134e8565b611703565b815115801561349f57506001600160a01b0384163b155b156134e1576040517f9996b3150000000000000000000000000000000000000000000000000000000081526001600160a01b038516600482015260240161224e565b5080611703565b8051156134f85780518082602001fd5b6040517f1425ea4200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006020828403121561353c57600080fd5b81357fffffffff000000000000000000000000000000000000000000000000000000008116811461170357600080fd5b60006020828403121561357e57600080fd5b5035919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b600581106135eb577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b9052565b60208101610c6482846135b4565b6001600160a01b038116811461163a57600080fd5b803561361d816135fd565b919050565b6000806040838503121561363557600080fd5b8235613640816135fd565b91506020830135613650816135fd565b809150509250929050565b60008060006060848603121561367057600080fd5b83359250602084013591506040840135613689816135fd565b809150509250925092565b6000602082840312156136a657600080fd5b8135611703816135fd565b600080604083850312156136c457600080fd5b823591506020830135613650816135fd565b801515811461163a57600080fd5b803561361d816136d6565b60008060006040848603121561370457600080fd5b833567ffffffffffffffff8082111561371c57600080fd5b818601915086601f83011261373057600080fd5b81358181111561373f57600080fd5b8760208260051b850101111561375457600080fd5b60209283019550935050840135613689816136d6565b60005b8381101561378557818101518382015260200161376d565b50506000910152565b600081518084526137a681602086016020860161376a565b601f01601f19169290920160200192915050565b600060208083018184528085518083526040925060408601915060408160051b87010184880160005b83811015613842578883037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc0018552815180511515845287015187840187905261382f8785018261378e565b95880195935050908601906001016137e3565b509098975050505050505050565b60008083601f84011261386257600080fd5b50813567ffffffffffffffff81111561387a57600080fd5b60208301915083602082850101111561389257600080fd5b9250929050565b600080602083850312156138ac57600080fd5b823567ffffffffffffffff8111156138c357600080fd5b6138cf85828601613850565b90969095509350505050565b6000806000604084860312156138f057600080fd5b833567ffffffffffffffff81111561390757600080fd5b61391386828701613850565b9094509250506020840135613689816135fd565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051610120810167ffffffffffffffff8111828210171561397a5761397a613927565b60405290565b60405160a0810167ffffffffffffffff8111828210171561397a5761397a613927565b6040516101e0810167ffffffffffffffff8111828210171561397a5761397a613927565b604051610180810167ffffffffffffffff8111828210171561397a5761397a613927565b604051601f8201601f1916810167ffffffffffffffff81118282101715613a1457613a14613927565b604052919050565b63ffffffff8116811461163a57600080fd5b803561361d81613a1c565b60006101208284031215613a4c57600080fd5b613a54613956565b9050613a5f82613a2e565b8152613a6d60208301613612565b6020820152613a7e60408301613612565b6040820152613a8f60608301613612565b6060820152613aa060808301613612565b608082015260a082013560a082015260c082013560c0820152613ac560e083016136e4565b60e082015261010080830135818301525092915050565b60006101208284031215613aef57600080fd5b6117038383613a39565b60208152613b1060208201835163ffffffff169052565b60006020830151613b29604084018263ffffffff169052565b5060408301516001600160a01b03811660608401525060608301516001600160a01b03811660808401525060808301516001600160a01b03811660a08401525060a08301516001600160a01b03811660c08401525060c083015160e08381019190915283015161010080840191909152830151610120808401919091528301516101408084019190915283015161016080840191909152830151610180613bda818501836001600160a01b03169052565b8401516101a0848101919091528401516101c0808501919091528401516101e0808501529050613c0e61020084018261378e565b949350505050565b60808101613c2482876135b4565b63ffffffff8516602083015266ffffffffffffff841660408301526001600160a01b038316606083015295945050505050565b600080600060408486031215613c6c57600080fd5b833567ffffffffffffffff811115613c8357600080fd5b613c8f86828701613850565b909790965060209590950135949350505050565b60008060408385031215613cb657600080fd5b50508035926020909101359150565b815163ffffffff16815261018081016020830151613ceb602084018263ffffffff169052565b506040830151613d0660408401826001600160a01b03169052565b506060830151613d2160608401826001600160a01b03169052565b506080830151613d3c60808401826001600160a01b03169052565b5060a0830151613d5760a08401826001600160a01b03169052565b5060c083015160c083015260e083015160e083015261010080840151818401525061012080840151613d8c8285018215159052565b5050610140838101519083015261016092830151929091019190915290565b600067ffffffffffffffff821115613dc557613dc5613927565b50601f01601f191660200190565b600082601f830112613de457600080fd5b8135613df7613df282613dab565b6139eb565b818152846020838601011115613e0c57600080fd5b816020850160208301376000918101602001919091529392505050565b6000806101408385031215613e3d57600080fd5b613e478484613a39565b915061012083013567ffffffffffffffff80821115613e6557600080fd5b9084019060a08287031215613e7957600080fd5b613e81613980565b8235613e8c816135fd565b815260208381013590820152604083013582811115613eaa57600080fd5b613eb688828601613dd3565b60408301525060608301356060820152608083013582811115613ed857600080fd5b613ee488828601613dd3565b6080830152508093505050509250929050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112613f5b57600080fd5b83018035915067ffffffffffffffff821115613f7657600080fd5b60200191503681900382131561389257600080fd5b8183823760009101908152919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b80820180821115610c6457610c64613f9b565b818352818160208501375060006020828401015260006020601f19601f840116840101905092915050565b602081526000613c0e602083018486613fdd565b805161361d81613a1c565b805161361d816135fd565b600082601f83011261404357600080fd5b8151614051613df282613dab565b81815284602083860101111561406657600080fd5b613c0e82602083016020870161376a565b60006020828403121561408957600080fd5b815167ffffffffffffffff808211156140a157600080fd5b908301906101e082860312156140b657600080fd5b6140be6139a3565b6140c78361401c565b81526140d56020840161401c565b60208201526140e660408401614027565b60408201526140f760608401614027565b606082015261410860808401614027565b608082015261411960a08401614027565b60a082015260c0838101519082015260e08084015190820152610100808401519082015261012080840151908201526101408084015190820152610160614161818501614027565b9082015261018083810151908201526101a080840151908201526101c0808401518381111561418f57600080fd5b61419b88828701614032565b918301919091525095945050505050565b600061018082840312156141bf57600080fd5b6141c76139c7565b6141d083613a2e565b81526141de60208401613a2e565b60208201526141ef60408401613612565b604082015261420060608401613612565b606082015261421160808401613612565b608082015261422260a08401613612565b60a082015260c083013560c082015260e083013560e08201526101008084013581830152506101206142558185016136e4565b908201526101408381013590820152610160928301359281019290925250919050565b808201828112600083128015821682158216171561429857614298613f9b565b505092915050565b8082028115828204841417610c6457610c64613f9b565b6000826142ed577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b81810381811115610c6457610c64613f9b565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820361433657614336613f9b565b5060010190565b60e08152600061435060e083018a61378e565b63ffffffff989098166020830152506001600160a01b039586166040820152939094166060840152608083019190915260a082015290151560c090910152919050565b602081526000611703602083018461378e565b600080858511156143b657600080fd5b838611156143c357600080fd5b5050820193919092039150565b6001600160a01b0385168152836020820152606060408201526000613321606083018486613fdd565b80516020808301519190811015614438577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8160200360031b1b821691505b50919050565b60006020828403121561445057600080fd5b5051919050565b60008a51614469818460208f0161376a565b80830190508a81528960208201528860408201528760608201527fffffffffffffffffffffffffffffffffffffffff0000000000000000000000008760601b1660808201528560948201528460b482015283516144cd8160d484016020880161376a565b0160d4019b9a5050505050505050505050565b6000602082840312156144f257600080fd5b8151611703816136d6565b6000825161450f81846020870161376a565b9190910192915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fdfea2646970667358221220ff0963a32deca1c739f82fff423c2a4ab1b1e197296c902578ae57133c488fd564736f6c63430008180033","runtime-code":"0x60806040526004361061034a5760003560e01c80638379a24f116101bb578063ac11fb1a116100f7578063c79371b111610095578063d547741f1161006f578063d547741f14610b59578063dc9a4ef614610b79578063dcf844a714610bad578063e00a83e014610bda57600080fd5b8063c79371b114610a78578063ca15c87314610b05578063ccc5749014610b2557600080fd5b8063b13aa2d6116100d1578063b13aa2d614610a0e578063bf333f2c14610a2e578063bfc7c60714610a45578063c63ff8dd14610a5857600080fd5b8063ac11fb1a1461098d578063add98c70146109ba578063affed0e0146109da57600080fd5b8063922b748711610164578063a217fddf1161013e578063a217fddf14610924578063a3ec191a14610939578063a5bbe22b14610769578063aa9641ab1461096d57600080fd5b8063922b7487146108e4578063930ac180146108fa5780639c9545f01461091157600080fd5b80639010d07c116101955780639010d07c146107fa57806391ad50391461081a57806391d14854146108a057600080fd5b80638379a24f1461077f578063886d36ff146107c75780638f0d6f17146107e757600080fd5b8063385c1d2f1161028a57806358f858801161023357806363787e521161020d57806363787e52146106a5578063638a0f091461071f5780637ebe815c14610735578063820688d51461076957600080fd5b806358f85880146106425780635aa6ccba146106585780635eb7d9461461068557600080fd5b806341fcb6121161026457806341fcb612146105f9578063458516941461061957806354eff0681461062c57600080fd5b8063385c1d2f1461058c5780633c5beeb4146105b95780633f61331d146105d957600080fd5b80630f862f1e116102f7578063248a9ca3116102d1578063248a9ca3146104ef578063295710ff1461051f5780632f2ff15d1461054c57806336568abe1461056c57600080fd5b80630f862f1e1461046f57806318e4357d146104af5780631ea327c5146104cf57600080fd5b8063051287bc11610328578063051287bc146103fa57806306f333f2146104375780630f5f6ed71461045957600080fd5b806301ffc9a71461034f57806302d2ff661461038457806303ed0ee5146103c6575b600080fd5b34801561035b57600080fd5b5061036f61036a36600461352a565b610c0e565b60405190151581526020015b60405180910390f35b34801561039057600080fd5b506103b87febfdca8e46c0b8dacf9989ee613e35727eadd20a1d5e5ad01a53968c7e5fe07a81565b60405190815260200161037b565b3480156103d257600080fd5b506103b87f043c983c49d46f0e102151eaf8085d4a2e6571d5df2d47b013f39bddfd4a639d81565b34801561040657600080fd5b5061042a61041536600461356c565b60009081526005602052604090205460ff1690565b60405161037b91906135ef565b34801561044357600080fd5b50610457610452366004613622565b610c6a565b005b34801561046557600080fd5b506103b861271081565b34801561047b57600080fd5b5061049773eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee81565b6040516001600160a01b03909116815260200161037b565b3480156104bb57600080fd5b506104576104ca36600461365b565b610d77565b3480156104db57600080fd5b506104576104ea36600461356c565b610e8c565b3480156104fb57600080fd5b506103b861050a36600461356c565b60009081526020819052604090206001015490565b34801561052b57600080fd5b506103b861053a366004613694565b60076020526000908152604090205481565b34801561055857600080fd5b506104576105673660046136b1565b610ec3565b34801561057857600080fd5b506104576105873660046136b1565b610ee8565b34801561059857600080fd5b506105ac6105a73660046136ef565b610f34565b60405161037b91906137ba565b3480156105c557600080fd5b506104576105d4366004613899565b6110c2565b3480156105e557600080fd5b506104576105f43660046136ef565b6112c4565b34801561060557600080fd5b506104576106143660046138db565b61136e565b610457610627366004613adc565b6115e0565b34801561063857600080fd5b506103b861ffff81565b34801561064e57600080fd5b506103b860025481565b34801561066457600080fd5b50610678610673366004613899565b61163d565b60405161037b9190613af9565b34801561069157600080fd5b506104576106a0366004613899565b61170a565b3480156106b157600080fd5b5061070f6106c036600461356c565b60056020526000908152604090205460ff811690610100810463ffffffff169065010000000000810466ffffffffffffff16906c0100000000000000000000000090046001600160a01b031684565b60405161037b9493929190613c16565b34801561072b57600080fd5b506103b860045481565b34801561074157600080fd5b506103b87f9a04aea0a349253cc7277afafdf6ead6729a3972a47ffb40eaef2c93d4e1bfea81565b34801561077557600080fd5b506103b861070881565b34801561078b57600080fd5b5061036f61079a36600461356c565b6000908152600660205260409020546c0100000000000000000000000090046001600160a01b0316151590565b3480156107d357600080fd5b506104576107e2366004613c57565b611714565b6104576107f5366004613899565b611740565b34801561080657600080fd5b50610497610815366004613ca3565b61174b565b34801561082657600080fd5b5061087461083536600461356c565b60009081526005602052604090205465010000000000810466ffffffffffffff16916c010000000000000000000000009091046001600160a01b031690565b604080516bffffffffffffffffffffffff90931683526001600160a01b0390911660208301520161037b565b3480156108ac57600080fd5b5061036f6108bb3660046136b1565b6000918252602082815260408084206001600160a01b0393909316845291905290205460ff1690565b3480156108f057600080fd5b506103b8610e1081565b34801561090657600080fd5b506103b86201518081565b61045761091f3660046138db565b611763565b34801561093057600080fd5b506103b8600081565b34801561094557600080fd5b506103b87f000000000000000000000000000000000000000000000000000000000000000081565b34801561097957600080fd5b5061036f6109883660046136b1565b611a1d565b34801561099957600080fd5b506109ad6109a8366004613899565b611af4565b60405161037b9190613cc5565b3480156109c657600080fd5b506104576109d536600461356c565b611ca8565b3480156109e657600080fd5b506103b87f000000000000000000000000000000000000000000000000000000000000000081565b348015610a1a57600080fd5b50610457610a2936600461356c565b611df2565b348015610a3a57600080fd5b506103b8620f424081565b610457610a53366004613e29565b611e9e565b348015610a6457600080fd5b50610457610a73366004613899565b61212d565b348015610a8457600080fd5b50610ad7610a9336600461356c565b60066020526000908152604090205465ffffffffffff8082169166010000000000008104909116906c0100000000000000000000000090046001600160a01b031683565b6040805165ffffffffffff94851681529390921660208401526001600160a01b03169082015260600161037b565b348015610b1157600080fd5b506103b8610b2036600461356c565b612139565b348015610b3157600080fd5b506103b87f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f5581565b348015610b6557600080fd5b50610457610b743660046136b1565b612150565b348015610b8557600080fd5b506103b87f60044782a422109ac08a415e44260ad5d3bad63d96ebe1fac0363399642ee3f281565b348015610bb957600080fd5b506103b8610bc8366004613694565b60036020526000908152604090205481565b348015610be657600080fd5b506103b87f000000000000000000000000000000000000000000000000000000000000000081565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f5a05180f000000000000000000000000000000000000000000000000000000001480610c645750610c6482612175565b92915050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f55610c948161220c565b6001600160a01b03831660009081526003602052604081205490819003610cbb5750505050565b6001600160a01b038481166000818152600360209081526040808320929092558151928352928616928201929092529081018290527f244e51bc38c1452fa8aaf487bcb4bca36c2baa3a5fbdb776b1eabd8dc6d277cd9060600160405180910390a17fffffffffffffffffffffffff11111111111111111111111111111111111111126001600160a01b03851601610d5c57610d578382612216565b610d70565b610d706001600160a01b03851684836122e4565b505b505050565b7f60044782a422109ac08a415e44260ad5d3bad63d96ebe1fac0363399642ee3f2610da18161220c565b60008481526005602052604090206001815460ff166004811115610dc757610dc7613585565b14610dfe576040517f4145817200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80546001600160a01b0384166c0100000000000000000000000081026bffffffffffffffffffffffff66ffffffffffffff421665010000000000021664ffffffff009093169290921791909117600217825560405185815286907f4ac8af8a2cd87193d64dfc7a3b8d9923b714ec528b18725d080aa1299be0c5e49060200160405180910390a35050505050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f55610eb68161220c565b610ebf82612358565b5050565b600082815260208190526040902060010154610ede8161220c565b610d7083836123d9565b6001600160a01b0381163314610f2a576040517f6697b23200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610d728282612406565b60608267ffffffffffffffff811115610f4f57610f4f613927565b604051908082528060200260200182016040528015610f9557816020015b604080518082019091526000815260606020820152815260200190600190039081610f6d5790505b50905060005b838110156110ba5730858583818110610fb657610fb6613ef7565b9050602002810190610fc89190613f26565b604051610fd6929190613f8b565b600060405180830381855af49150503d8060008114611011576040519150601f19603f3d011682016040523d82523d6000602084013e611016565b606091505b5083838151811061102957611029613ef7565b602002602001015160000184848151811061104657611046613ef7565b60200260200101516020018290528215151515815250505081818151811061107057611070613ef7565b602002602001015160000151158015611087575082155b156110b2576110b28282815181106110a1576110a1613ef7565b602002602001015160200151612433565b600101610f9b565b509392505050565b6110cc8282612475565b600082826040516110de929190613f8b565b604080519182900390912060008181526005602052919091209091506001815460ff16600481111561111257611112613585565b14611149576040517f4145817200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b3360009081527f4527d8b28c468984933d33ae052f26b21c15ca0e7fdec762bba08e540e237001602052604090205460ba8501359060ff16611195576004546111929082613fca565b90505b8042116111ce576040517fe15ff9ea00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b81547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166004178255600a850135606090811c906032870135901c600061121d609a890135605a8a0135613fca565b604080516001600160a01b03858116825260208201849052825193945086169289927fb4c55c0c9bc613519b920e88748090150b890a875d307f21bea7d4fb2e8bc958928290030190a37fffffffffffffffffffffffff11111111111111111111111111111111111111126001600160a01b038316016112a6576112a18382612216565b6112ba565b6112ba6001600160a01b03831684836122e4565b5050505050505050565b60005b82811015610d7057600080308686858181106112e5576112e5613ef7565b90506020028101906112f79190613f26565b604051611305929190613f8b565b600060405180830381855af49150503d8060008114611340576040519150601f19603f3d011682016040523d82523d6000602084013e611345565b606091505b509150915081158015611356575083155b156113645761136481612433565b50506001016112c7565b6113788383612475565b6000838360405161138a929190613f8b565b604080519182900390912060008181526005602052919091208054919250906c0100000000000000000000000081046001600160a01b03169060ff81169065010000000000900466ffffffffffffff1660028260048111156113ee576113ee613585565b14611425576040517f4145817200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6107084282900366ffffffffffffff161161146c576040517f1992d0bd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600160a01b038616611482578295506114c4565b6001600160a01b03831633146114c4576040517f4af43a9000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b83547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166003178455603288013560601c605a890135609a8a01358015611533576001600160a01b0383166000908152600360205260408120805483929061152d908490613fca565b90915550505b604080516001600160a01b03858116825260208201859052808c1692908916918b917f582211c35a2139ac3bbaac74663c6a1f56c6cbb658b41fe11fd45a82074ac678910160405180910390a47fffffffffffffffffffffffff11111111111111111111111111111111111111126001600160a01b038416016115bf576115ba8983612216565b6115d3565b6115d36001600160a01b0384168a846122e4565b5050505050505050505050565b61163a816040518060a0016040528060006001600160a01b03168152602001600081526020016040518060200160405280600081525081526020016000815260200160405180602001604052806000815250815250611e9e565b50565b6116ef604051806101e00160405280600063ffffffff168152602001600063ffffffff16815260200160006001600160a01b0316815260200160006001600160a01b0316815260200160006001600160a01b0316815260200160006001600160a01b03168152602001600081526020016000815260200160008152602001600081526020016000815260200160006001600160a01b031681526020016000815260200160008152602001606081525090565b6116f98383612475565b61170383836124f6565b9392505050565b610ebf82826110c2565b61171e8383612475565b610d728383604051611731929190613f8b565b60405180910390208233610d77565b610ebf828233611763565b60008281526001602052604081206117039083612698565b61176d8383612475565b6000838360405161177f929190613f8b565b60405180910390209050611795848483856126a4565b6040805160608101825265ffffffffffff438116825242811660208084019182526001600160a01b038088168587019081526000888152600690935295822094518554935196519091166c01000000000000000000000000026bffffffffffffffffffffffff9685166601000000000000027fffffffffffffffffffffffffffffffffffffffff0000000000000000000000009094169190941617919091179390931617905561184985601e013560601c90565b9050604685013560601c607a86013561012e8701356001600160a01b03808516908716867ff8ae392d784b1ea5e8881bfa586d81abf07ef4f1e2fc75f7fe51c90f05199a5c60028c013560e01c6040805163ffffffff92909216825260328e0135606090811c60208401526001600160a01b038a1683830152605a8f0135908301526080820188905260a08201879052519081900360c00190a47fffffffffffffffffffffffff11111111111111111111111111111111111111126001600160a01b0384160161198957801561194b576040517f846dedc000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b813414611984576040517f81de0bf300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6119d7565b8034146119c2576040517f81de0bf300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6119d76001600160a01b038416338685612839565b3660006119e48a8a612872565b90925090508015611a01576119fc868686858561288e565b611a11565b3415611a1157611a118634612216565b50505050505050505050565b60008281526005602052604081206002815460ff166004811115611a4357611a43613585565b14611a7a576040517f4145817200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80546001600160a01b038481166c010000000000000000000000009092041614611ad0576040517f4af43a9000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b546107086501000000000090910466ffffffffffffff908116420316119392505050565b6040805161018081018252600080825260208201819052818301819052606082018190526080820181905260a0820181905260c0820181905260e0820181905261010082018190526101208201819052610140820181905261016082015290517f5aa6ccba0000000000000000000000000000000000000000000000000000000081523090635aa6ccba90611b8f9086908690600401614008565b600060405180830381865afa925050508015611bcd57506040513d6000823e601f3d908101601f19168201604052611bca9190810190614077565b60015b611be457611bdd828401846141ac565b9050610c64565b604051806101800160405280826000015163ffffffff168152602001826020015163ffffffff16815260200182604001516001600160a01b0316815260200182606001516001600160a01b0316815260200182608001516001600160a01b031681526020018260a001516001600160a01b031681526020018260c0015181526020018260e0015181526020018261010001518152602001826101a0015160001415151581526020018261012001518152602001826101400151815250915050610c64565b7f043c983c49d46f0e102151eaf8085d4a2e6571d5df2d47b013f39bddfd4a639d611cd28161220c565b600082815260056020526040902080546c0100000000000000000000000081046001600160a01b03169060ff81169065010000000000900466ffffffffffffff166002826004811115611d2757611d27613585565b14611d5e576040517f4145817200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6107084282900366ffffffffffffff161115611da6576040517f3e908aac00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b835464ffffffff001660011784556040516001600160a01b0384169087907f0695cf1d39b3055dcd0fe02d8b47eaf0d5a13e1996de925de59d0ef9b7f7fad490600090a3505050505050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f55611e1c8161220c565b612710821115611e58576040517f9b569b8100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600280549083905560408051828152602081018590527f14914da2bf76024616fbe1859783fcd4dbddcb179b1f3a854949fbf920dcb957910160405180910390a1505050565b80516000906001600160a01b031615611ec3576020820151611ec09042614278565b90505b611ece8383836129ea565b6000611ee284606001518560a00151612c6e565b90506000806002541115611f1b57620f424060025483611f0291906142a0565b611f0c91906142b7565b9050611f1881836142f2565b91505b6000612024604051806101e001604052804663ffffffff168152602001886000015163ffffffff16815260200188602001516001600160a01b0316815260200188604001516001600160a01b0316815260200188606001516001600160a01b0316815260200188608001516001600160a01b031681526020018581526020018860c0015181526020018481526020018861010001518152602001600760008a602001516001600160a01b03166001600160a01b031681526020019081526020016000206000815480929190611fef90614305565b90915550815287516001600160a01b031660208201526040810187905260608089015190820152608080890151910152612e81565b805160208083019190912060008181526005835260409081902080548b5163ffffffff8116610100027fffffffffffffffffffffffffffffffffffffffffffffffffffffff000000000090921691909117600117909155928a01516060808c015160808d015160c08e0151928d0151945197985094966001600160a01b039093169587957f120ea0364f36cdac7983bcfdd55270ca09d7f9b314a2ebc425a3b01ab1d6403a956120e0958b959394938e9290919015159061433d565b60405180910390a3807f3120e2bb59c86aca6890191a589a96af3662838efa374fbdcdf4c95bfe4a6c0e876040015160405161211c9190614393565b60405180910390a250505050505050565b610ebf8282600061136e565b6000818152600160205260408120610c6490612fc6565b60008281526020819052604090206001015461216b8161220c565b610d708383612406565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f7965db0b000000000000000000000000000000000000000000000000000000001480610c6457507f01ffc9a7000000000000000000000000000000000000000000000000000000007fffffffff00000000000000000000000000000000000000000000000000000000831614610c64565b61163a8133612fd0565b80471015612257576040517fcd7860590000000000000000000000000000000000000000000000000000000081523060048201526024015b60405180910390fd5b6000826001600160a01b03168260405160006040518083038185875af1925050503d80600081146122a4576040519150601f19603f3d011682016040523d82523d6000602084013e6122a9565b606091505b5050905080610d72576040517f1425ea4200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040516001600160a01b03838116602483015260448201839052610d7291859182169063a9059cbb906064015b604051602081830303815290604052915060e01b6020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff838183161783525050505061303c565b610e10811015612394576040517f0e0ea5c700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600480549082905560408051828152602081018490527f909f9078b2f6eac1d10f2aae793656c5a67511eb627ebd1d2cb1eb9c0ab94c95910160405180910390a15050565b6000806123e684846130b8565b905080156117035760008481526001602052604090206110ba9084613180565b6000806124138484613195565b905080156117035760008481526001602052604090206110ba9084613236565b8051156124435780518082602001fd5b6040517f5ead5a9d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61014e8110156124b1576040517f6ee0e17100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b813560f01c60028114610d72576040517f8bd977e700000000000000000000000000000000000000000000000000000000815261ffff8216600482015260240161224e565b6125a8604051806101e00160405280600063ffffffff168152602001600063ffffffff16815260200160006001600160a01b0316815260200160006001600160a01b0316815260200160006001600160a01b0316815260200160006001600160a01b03168152602001600081526020016000815260200160008152602001600081526020016000815260200160006001600160a01b031681526020016000815260200160008152602001606081525090565b600283013560e090811c82526006840135811c6020830152600a840135606090811c6040840152601e850135811c818401526032850135811c60808401526046850135811c60a0840152605a85013560c0840152607a85013591830191909152609a84013561010083015260ba84013561012083015260da84013561014083015260fa840135901c61016082015261010e83013561018082015261012e8301356101a08201526126588383612872565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152505050506101c082015292915050565b6000611703838361324b565b6001600160a01b0381166126e4576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000828152600660205260409020546c0100000000000000000000000090046001600160a01b031615612743576040517fbef7bb7d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600684013560e01c4614612783576040517f7029fdf900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60ba8401354211156127c1576040517f559895a300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60fa84013560601c80158015906127ea5750816001600160a01b0316816001600160a01b031614155b80156127fb575061010e8501354211155b15612832576040517f14be123200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5050505050565b6040516001600160a01b038481166024830152838116604483015260648201839052610d709186918216906323b872dd90608401612311565b3660006128838361014e81876143a6565b915091509250929050565b600061290986868686866040516024016128ab94939291906143d0565b60408051601f198184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fe85e13dd0000000000000000000000000000000000000000000000000000000017905234613275565b90508051600003612946576040517f1a95ad2600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8051602014612981576040517ff3725cca00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7fe85e13dd000000000000000000000000000000000000000000000000000000006129ab826143f9565b146129e2576040517ff3725cca00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b505050505050565b46836000015163ffffffff1603612a2d576040517f7029fdf900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60a08301511580612a40575060c0830151155b15612a77576040517fe38820c800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60208301516001600160a01b03161580612a9c575060408301516001600160a01b0316155b15612ad3576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60608301516001600160a01b03161580612af8575060808301516001600160a01b0316155b15612b2f576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b612b3b61070842613fca565b8361010001511015612b79576040517f04b7fcc800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61ffff8260800151511115612bba576040517f177a70e100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b606082015115801590612bed575060808301516001600160a01b031673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee145b15612c24576040517f846dedc000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000811280612c37575082610100015181135b15610d72576040517f352807b900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60007fffffffffffffffffffffffff11111111111111111111111111111111111111126001600160a01b03841601612ce057348214612cd9576040517f81de0bf300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5034610c64565b3415612d18576040517f81de0bf300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b826001600160a01b03163b600003612d5c576040517f7f523fe800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201526001600160a01b038416906370a0823190602401602060405180830381865afa158015612db9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612ddd919061443e565b9050612df46001600160a01b038416333085612839565b6040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015281906001600160a01b038516906370a0823190602401602060405180830381865afa158015612e53573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612e77919061443e565b61170391906142f2565b8051602080830151604080850151606086810151608088015160a089015160c08a015195517e02000000000000000000000000000000000000000000000000000000000000988101989098527fffffffff0000000000000000000000000000000000000000000000000000000060e0998a1b811660228a01529690981b90951660268701527fffffffffffffffffffffffffffffffffffffffff00000000000000000000000092821b8316602a870152811b8216603e86015292831b8116605285015293821b9093166066830152607a820192909252600090609a0160408051601f198184030181529082905260e08501516101008601516101208701516101408801516101608901516101808a01516101a08b01516101c08c0151979950612faf988a9890602001614457565b604051602081830303815290604052915050919050565b6000610c64825490565b6000828152602081815260408083206001600160a01b038516845290915290205460ff16610ebf576040517fe2517d3f0000000000000000000000000000000000000000000000000000000081526001600160a01b03821660048201526024810183905260440161224e565b60006130516001600160a01b0384168361332b565b9050805160001415801561307657508080602001905181019061307491906144e0565b155b15610d72576040517f5274afe70000000000000000000000000000000000000000000000000000000081526001600160a01b038416600482015260240161224e565b6000828152602081815260408083206001600160a01b038516845290915281205460ff16613178576000838152602081815260408083206001600160a01b0386168452909152902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790556131303390565b6001600160a01b0316826001600160a01b0316847f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a4506001610c64565b506000610c64565b6000611703836001600160a01b038416613339565b6000828152602081815260408083206001600160a01b038516845290915281205460ff1615613178576000838152602081815260408083206001600160a01b038616808552925280832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016905551339286917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a4506001610c64565b6000611703836001600160a01b038416613380565b600082600001828154811061326257613262613ef7565b9060005260206000200154905092915050565b6060814710156132b3576040517fcd78605900000000000000000000000000000000000000000000000000000000815230600482015260240161224e565b600080856001600160a01b031684866040516132cf91906144fd565b60006040518083038185875af1925050503d806000811461330c576040519150601f19603f3d011682016040523d82523d6000602084013e613311565b606091505b5091509150613321868383613473565b9695505050505050565b606061170383836000613275565b600081815260018301602052604081205461317857508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155610c64565b600081815260018301602052604081205480156134695760006133a46001836142f2565b85549091506000906133b8906001906142f2565b905080821461341d5760008660000182815481106133d8576133d8613ef7565b90600052602060002001549050808760000184815481106133fb576133fb613ef7565b6000918252602080832090910192909255918252600188019052604090208390555b855486908061342e5761342e614519565b600190038181906000526020600020016000905590558560010160008681526020019081526020016000206000905560019350505050610c64565b6000915050610c64565b60608261348857613483826134e8565b611703565b815115801561349f57506001600160a01b0384163b155b156134e1576040517f9996b3150000000000000000000000000000000000000000000000000000000081526001600160a01b038516600482015260240161224e565b5080611703565b8051156134f85780518082602001fd5b6040517f1425ea4200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006020828403121561353c57600080fd5b81357fffffffff000000000000000000000000000000000000000000000000000000008116811461170357600080fd5b60006020828403121561357e57600080fd5b5035919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b600581106135eb577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b9052565b60208101610c6482846135b4565b6001600160a01b038116811461163a57600080fd5b803561361d816135fd565b919050565b6000806040838503121561363557600080fd5b8235613640816135fd565b91506020830135613650816135fd565b809150509250929050565b60008060006060848603121561367057600080fd5b83359250602084013591506040840135613689816135fd565b809150509250925092565b6000602082840312156136a657600080fd5b8135611703816135fd565b600080604083850312156136c457600080fd5b823591506020830135613650816135fd565b801515811461163a57600080fd5b803561361d816136d6565b60008060006040848603121561370457600080fd5b833567ffffffffffffffff8082111561371c57600080fd5b818601915086601f83011261373057600080fd5b81358181111561373f57600080fd5b8760208260051b850101111561375457600080fd5b60209283019550935050840135613689816136d6565b60005b8381101561378557818101518382015260200161376d565b50506000910152565b600081518084526137a681602086016020860161376a565b601f01601f19169290920160200192915050565b600060208083018184528085518083526040925060408601915060408160051b87010184880160005b83811015613842578883037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc0018552815180511515845287015187840187905261382f8785018261378e565b95880195935050908601906001016137e3565b509098975050505050505050565b60008083601f84011261386257600080fd5b50813567ffffffffffffffff81111561387a57600080fd5b60208301915083602082850101111561389257600080fd5b9250929050565b600080602083850312156138ac57600080fd5b823567ffffffffffffffff8111156138c357600080fd5b6138cf85828601613850565b90969095509350505050565b6000806000604084860312156138f057600080fd5b833567ffffffffffffffff81111561390757600080fd5b61391386828701613850565b9094509250506020840135613689816135fd565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051610120810167ffffffffffffffff8111828210171561397a5761397a613927565b60405290565b60405160a0810167ffffffffffffffff8111828210171561397a5761397a613927565b6040516101e0810167ffffffffffffffff8111828210171561397a5761397a613927565b604051610180810167ffffffffffffffff8111828210171561397a5761397a613927565b604051601f8201601f1916810167ffffffffffffffff81118282101715613a1457613a14613927565b604052919050565b63ffffffff8116811461163a57600080fd5b803561361d81613a1c565b60006101208284031215613a4c57600080fd5b613a54613956565b9050613a5f82613a2e565b8152613a6d60208301613612565b6020820152613a7e60408301613612565b6040820152613a8f60608301613612565b6060820152613aa060808301613612565b608082015260a082013560a082015260c082013560c0820152613ac560e083016136e4565b60e082015261010080830135818301525092915050565b60006101208284031215613aef57600080fd5b6117038383613a39565b60208152613b1060208201835163ffffffff169052565b60006020830151613b29604084018263ffffffff169052565b5060408301516001600160a01b03811660608401525060608301516001600160a01b03811660808401525060808301516001600160a01b03811660a08401525060a08301516001600160a01b03811660c08401525060c083015160e08381019190915283015161010080840191909152830151610120808401919091528301516101408084019190915283015161016080840191909152830151610180613bda818501836001600160a01b03169052565b8401516101a0848101919091528401516101c0808501919091528401516101e0808501529050613c0e61020084018261378e565b949350505050565b60808101613c2482876135b4565b63ffffffff8516602083015266ffffffffffffff841660408301526001600160a01b038316606083015295945050505050565b600080600060408486031215613c6c57600080fd5b833567ffffffffffffffff811115613c8357600080fd5b613c8f86828701613850565b909790965060209590950135949350505050565b60008060408385031215613cb657600080fd5b50508035926020909101359150565b815163ffffffff16815261018081016020830151613ceb602084018263ffffffff169052565b506040830151613d0660408401826001600160a01b03169052565b506060830151613d2160608401826001600160a01b03169052565b506080830151613d3c60808401826001600160a01b03169052565b5060a0830151613d5760a08401826001600160a01b03169052565b5060c083015160c083015260e083015160e083015261010080840151818401525061012080840151613d8c8285018215159052565b5050610140838101519083015261016092830151929091019190915290565b600067ffffffffffffffff821115613dc557613dc5613927565b50601f01601f191660200190565b600082601f830112613de457600080fd5b8135613df7613df282613dab565b6139eb565b818152846020838601011115613e0c57600080fd5b816020850160208301376000918101602001919091529392505050565b6000806101408385031215613e3d57600080fd5b613e478484613a39565b915061012083013567ffffffffffffffff80821115613e6557600080fd5b9084019060a08287031215613e7957600080fd5b613e81613980565b8235613e8c816135fd565b815260208381013590820152604083013582811115613eaa57600080fd5b613eb688828601613dd3565b60408301525060608301356060820152608083013582811115613ed857600080fd5b613ee488828601613dd3565b6080830152508093505050509250929050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112613f5b57600080fd5b83018035915067ffffffffffffffff821115613f7657600080fd5b60200191503681900382131561389257600080fd5b8183823760009101908152919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b80820180821115610c6457610c64613f9b565b818352818160208501375060006020828401015260006020601f19601f840116840101905092915050565b602081526000613c0e602083018486613fdd565b805161361d81613a1c565b805161361d816135fd565b600082601f83011261404357600080fd5b8151614051613df282613dab565b81815284602083860101111561406657600080fd5b613c0e82602083016020870161376a565b60006020828403121561408957600080fd5b815167ffffffffffffffff808211156140a157600080fd5b908301906101e082860312156140b657600080fd5b6140be6139a3565b6140c78361401c565b81526140d56020840161401c565b60208201526140e660408401614027565b60408201526140f760608401614027565b606082015261410860808401614027565b608082015261411960a08401614027565b60a082015260c0838101519082015260e08084015190820152610100808401519082015261012080840151908201526101408084015190820152610160614161818501614027565b9082015261018083810151908201526101a080840151908201526101c0808401518381111561418f57600080fd5b61419b88828701614032565b918301919091525095945050505050565b600061018082840312156141bf57600080fd5b6141c76139c7565b6141d083613a2e565b81526141de60208401613a2e565b60208201526141ef60408401613612565b604082015261420060608401613612565b606082015261421160808401613612565b608082015261422260a08401613612565b60a082015260c083013560c082015260e083013560e08201526101008084013581830152506101206142558185016136e4565b908201526101408381013590820152610160928301359281019290925250919050565b808201828112600083128015821682158216171561429857614298613f9b565b505092915050565b8082028115828204841417610c6457610c64613f9b565b6000826142ed577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b81810381811115610c6457610c64613f9b565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820361433657614336613f9b565b5060010190565b60e08152600061435060e083018a61378e565b63ffffffff989098166020830152506001600160a01b039586166040820152939094166060840152608083019190915260a082015290151560c090910152919050565b602081526000611703602083018461378e565b600080858511156143b657600080fd5b838611156143c357600080fd5b5050820193919092039150565b6001600160a01b0385168152836020820152606060408201526000613321606083018486613fdd565b80516020808301519190811015614438577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8160200360031b1b821691505b50919050565b60006020828403121561445057600080fd5b5051919050565b60008a51614469818460208f0161376a565b80830190508a81528960208201528860408201528760608201527fffffffffffffffffffffffffffffffffffffffff0000000000000000000000008760601b1660808201528560948201528460b482015283516144cd8160d484016020880161376a565b0160d4019b9a5050505050505050505050565b6000602082840312156144f257600080fd5b8151611703816136d6565b6000825161450f81846020870161376a565b9190910192915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fdfea2646970667358221220ff0963a32deca1c739f82fff423c2a4ab1b1e197296c902578ae57133c488fd564736f6c63430008180033","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.24 ^0.8.20 ^0.8.4;\n\n// contracts/interfaces/IAdminV2.sol\n\ninterface IAdminV2 {\n event CancelDelayUpdated(uint256 oldCancelDelay, uint256 newCancelDelay);\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n function setCancelDelay(uint256 newCancelDelay) external;\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n}\n\n// contracts/interfaces/IAdminV2Errors.sol\n\ninterface IAdminV2Errors {\n error CancelDelayBelowMin();\n error FeeRateAboveMax();\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IFastBridgeV2Errors.sol\n\ninterface IFastBridgeV2Errors {\n error AmountIncorrect();\n error ChainIncorrect();\n error ExclusivityParamsIncorrect();\n error MsgValueIncorrect();\n error SenderIncorrect();\n error StatusIncorrect();\n error TokenNotContract();\n error ZapDataLengthAboveMax();\n error ZapNativeNotSupported();\n error ZeroAddress();\n\n error RecipientIncorrectReturnValue();\n error RecipientNoReturnValue();\n\n error DeadlineExceeded();\n error DeadlineNotExceeded();\n error DeadlineTooShort();\n error DisputePeriodNotPassed();\n error DisputePeriodPassed();\n error ExclusivityPeriodNotPassed();\n\n error TransactionRelayed();\n}\n\n// contracts/interfaces/IMulticallTarget.sol\n\n/// @notice Interface for a contract that can be called multiple times by the same caller. Inspired by MulticallV3:\n/// https://github.com/mds1/multicall/blob/master/src/Multicall3.sol\ninterface IMulticallTarget {\n struct Result {\n bool success;\n bytes returnData;\n }\n\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external;\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results);\n}\n\n// contracts/interfaces/IZapRecipient.sol\n\ninterface IZapRecipient {\n function zap(address token, uint256 amount, bytes memory zapData) external payable returns (bytes4);\n}\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// contracts/interfaces/IFastBridgeV2.sol\n\ninterface IFastBridgeV2 is IFastBridge {\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n struct BridgeTxDetails {\n BridgeStatus status;\n uint32 destChainId;\n uint56 proofBlockTimestamp;\n address proofRelayer;\n }\n\n struct BridgeRelay {\n uint48 blockNumber;\n uint48 blockTimestamp;\n address relayer;\n }\n\n /// @notice New params introduced in the FastBridgeV2.\n /// We are passing fields from the older BridgeParams struct outside of this struct\n /// for backwards compatibility.\n /// Note: quoteRelayer and quoteExclusivitySeconds are either both zero (indicating no exclusivity)\n /// or both non-zero (indicating exclusivity for the given period).\n /// Note: zapNative \u003e 0 can NOT be used with destToken = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE (native token)\n /// @param quoteRelayer Relayer that provided the quote for the transaction\n /// @param quoteExclusivitySeconds Period of time the quote relayer is guaranteed exclusivity after user's deposit\n /// @param quoteId Unique quote identifier used for tracking the quote\n /// @param zapNative ETH value to send to the recipient (if any)\n /// @param zapData Parameters for the Zap to the destination recipient (if any)\n struct BridgeParamsV2 {\n address quoteRelayer;\n int256 quoteExclusivitySeconds;\n bytes quoteId;\n uint256 zapNative;\n bytes zapData;\n }\n\n /// @notice Updated bridge transaction struct to include parameters introduced in FastBridgeV2.\n /// Note: only `exclusivityRelayer` can fill such a transaction until `exclusivityEndTime`.\n struct BridgeTransactionV2 {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n // Note: sendChainGas flag from V1 is deprecated\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n address exclusivityRelayer;\n uint256 exclusivityEndTime;\n uint256 zapNative; // ETH value to send to the recipient (if any)\n bytes zapData; // data to pass for the Zap action (if any)\n }\n\n event BridgeQuoteDetails(bytes32 indexed transactionId, bytes quoteId);\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability\n /// to provide temporary exclusivity fill rights for the quote relayer.\n /// @param params The parameters required to bridge\n /// @param paramsV2 The parameters for exclusivity fill rights (optional, can be left empty)\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function relay(bytes memory request, address relayer) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param transactionId The transaction id associated with the encoded bridge transaction to prove\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital.\n /// @notice Can only send funds to the relayer address on the proof.\n /// @param request The encoded bridge transaction to claim on origin chain\n function claim(bytes memory request) external;\n\n /// @notice Cancels an outstanding bridge transaction in case optimistic bridging failed and returns the full amount\n /// to the original sender.\n /// @param request The encoded bridge transaction to refund\n function cancel(bytes memory request) external;\n\n /// @notice Checks if a transaction has been relayed\n /// @param transactionId The ID of the transaction to check\n /// @return True if the transaction has been relayed, false otherwise\n function bridgeRelays(bytes32 transactionId) external view returns (bool);\n\n /// @notice Returns the status of a bridge transaction\n /// @param transactionId The ID of the bridge transaction\n /// @return BridgeStatus Status of the bridge transaction\n function bridgeStatuses(bytes32 transactionId) external view returns (BridgeStatus);\n\n /// @notice Returns the timestamp and relayer of a bridge proof\n /// @param transactionId The ID of the bridge transaction\n /// @return timestamp The timestamp of the bridge proof\n /// @return relayer The relayer address of the bridge proof\n function bridgeProofs(bytes32 transactionId) external view returns (uint96 timestamp, address relayer);\n\n /// @notice Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\n /// @param request The bridge request to decode\n function getBridgeTransactionV2(bytes memory request) external view returns (BridgeTransactionV2 memory);\n}\n\n// contracts/utils/MulticallTarget.sol\n\n// solhint-disable avoid-low-level-calls\n/// @notice Template for a contract that supports batched calls (preserving the msg.sender).\n/// Only calls with zero msg.value could be batched.\nabstract contract MulticallTarget is IMulticallTarget {\n error MulticallTarget__UndeterminedRevert();\n\n /// @notice Perform a batched call to this contract, preserving the msg.sender.\n /// The return data from each call is discarded.\n /// @dev The method is non-payable, so only calls with `msg.value == 0` could be batched.\n /// It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag.\n /// Otherwise, the whole batch call will be reverted with the original revert reason.\n /// @param data List of abi-encoded calldata for the calls to perform.\n /// @param ignoreReverts Whether to ignore the revert errors from the calls.\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external {\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\n if (!success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(result);\n }\n }\n }\n\n /// @notice Perform a batched call to this contract, preserving the msg.sender.\n /// The return data from each call is preserved.\n /// @dev The method is non-payable, so only calls with `msg.value == 0` could be batched.\n /// It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag.\n /// Otherwise, the whole batch call will be reverted with the original revert reason.\n /// @param data List of abi-encoded calldata for the calls to perform.\n /// @param ignoreReverts Whether to ignore the revert errors from the calls.\n /// @return results List of results from the calls: `(success, returnData)`.\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results)\n {\n results = new Result[](data.length);\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (results[i].success, results[i].returnData) = address(this).delegatecall(data[i]);\n if (!results[i].success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(results[i].returnData);\n }\n }\n }\n\n /// @dev Bubbles the revert message from the underlying call.\n /// Note: preserves the same custom error or revert string, if one was used.\n /// Source: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v5.0.2/contracts/utils/Address.sol#L143-L158\n function _bubbleRevert(bytes memory returnData) internal pure {\n // Look for revert reason and bubble it up if present\n if (returnData.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n // solhint-disable-next-line no-inline-assembly\n assembly {\n let returndata_size := mload(returnData)\n revert(add(32, returnData), returndata_size)\n }\n } else {\n revert MulticallTarget__UndeterminedRevert();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// contracts/libs/BridgeTransactionV2.sol\n\n// solhint-disable no-inline-assembly\nlibrary BridgeTransactionV2Lib {\n uint16 internal constant VERSION = 2;\n\n // Offsets of the fields in the packed BridgeTransactionV2 struct\n // uint16 version [000 .. 002)\n // uint32 originChainId [002 .. 006)\n // uint32 destChainId [006 .. 010)\n // address originSender [010 .. 030)\n // address destRecipient [030 .. 050)\n // address originToken [050 .. 070)\n // address destToken [070 .. 090)\n // uint256 originAmount [090 .. 122)\n // uint256 destAmount [122 .. 154)\n // uint256 originFeeAmount [154 .. 186)\n // uint256 deadline [186 .. 218)\n // uint256 nonce [218 .. 250)\n // address exclusivityRelayer [250 .. 270)\n // uint256 exclusivityEndTime [270 .. 302)\n // uint256 zapNative [302 .. 334)\n // bytes zapData [334 .. ***)\n\n // forgefmt: disable-start\n uint256 private constant OFFSET_ORIGIN_CHAIN_ID = 2;\n uint256 private constant OFFSET_DEST_CHAIN_ID = 6;\n uint256 private constant OFFSET_ORIGIN_SENDER = 10;\n uint256 private constant OFFSET_DEST_RECIPIENT = 30;\n uint256 private constant OFFSET_ORIGIN_TOKEN = 50;\n uint256 private constant OFFSET_DEST_TOKEN = 70;\n uint256 private constant OFFSET_ORIGIN_AMOUNT = 90;\n uint256 private constant OFFSET_DEST_AMOUNT = 122;\n uint256 private constant OFFSET_ORIGIN_FEE_AMOUNT = 154;\n uint256 private constant OFFSET_DEADLINE = 186;\n uint256 private constant OFFSET_NONCE = 218;\n uint256 private constant OFFSET_EXCLUSIVITY_RELAYER = 250;\n uint256 private constant OFFSET_EXCLUSIVITY_END_TIME = 270;\n uint256 private constant OFFSET_ZAP_NATIVE = 302;\n uint256 private constant OFFSET_ZAP_DATA = 334;\n // forgefmt: disable-end\n\n error BridgeTransactionV2__InvalidEncodedTx();\n error BridgeTransactionV2__UnsupportedVersion(uint16 version);\n\n /// @notice Validates the encoded transaction to be a tightly packed encoded payload for BridgeTransactionV2.\n /// @dev Checks the minimum length and the version, use this function before decoding any of the fields.\n function validateV2(bytes calldata encodedTx) internal pure {\n // Check the minimum length: must at least include all static fields.\n if (encodedTx.length \u003c OFFSET_ZAP_DATA) revert BridgeTransactionV2__InvalidEncodedTx();\n // Once we validated the length, we can be sure that the version field is present.\n uint16 version_ = version(encodedTx);\n if (version_ != VERSION) revert BridgeTransactionV2__UnsupportedVersion(version_);\n }\n\n /// @notice Encodes the BridgeTransactionV2 struct by tightly packing the fields.\n /// @dev `abi.decode` will not work as a result of the tightly packed fields. Use `decodeV2` to decode instead.\n function encodeV2(IFastBridgeV2.BridgeTransactionV2 memory bridgeTx) internal pure returns (bytes memory) {\n // We split the encoding into two parts to avoid stack-too-deep error\n bytes memory firstPart = abi.encodePacked(\n VERSION,\n bridgeTx.originChainId,\n bridgeTx.destChainId,\n bridgeTx.originSender,\n bridgeTx.destRecipient,\n bridgeTx.originToken,\n bridgeTx.destToken,\n bridgeTx.originAmount\n );\n return abi.encodePacked(\n firstPart,\n bridgeTx.destAmount,\n bridgeTx.originFeeAmount,\n // Note: we skip the deprecated `sendChainGas` flag, which was present in BridgeTransaction V1\n bridgeTx.deadline,\n bridgeTx.nonce,\n // New V2 fields: exclusivity\n bridgeTx.exclusivityRelayer,\n bridgeTx.exclusivityEndTime,\n // New V2 fields: Zap\n bridgeTx.zapNative,\n bridgeTx.zapData\n );\n }\n\n /// @notice Decodes the BridgeTransactionV2 struct from the encoded transaction.\n /// @dev Encoded BridgeTransactionV2 struct must be tightly packed.\n /// Use `validateV2` before decoding to ensure the encoded transaction is valid.\n function decodeV2(bytes calldata encodedTx)\n internal\n pure\n returns (IFastBridgeV2.BridgeTransactionV2 memory bridgeTx)\n {\n bridgeTx.originChainId = originChainId(encodedTx);\n bridgeTx.destChainId = destChainId(encodedTx);\n bridgeTx.originSender = originSender(encodedTx);\n bridgeTx.destRecipient = destRecipient(encodedTx);\n bridgeTx.originToken = originToken(encodedTx);\n bridgeTx.destToken = destToken(encodedTx);\n bridgeTx.originAmount = originAmount(encodedTx);\n bridgeTx.destAmount = destAmount(encodedTx);\n bridgeTx.originFeeAmount = originFeeAmount(encodedTx);\n bridgeTx.deadline = deadline(encodedTx);\n bridgeTx.nonce = nonce(encodedTx);\n bridgeTx.exclusivityRelayer = exclusivityRelayer(encodedTx);\n bridgeTx.exclusivityEndTime = exclusivityEndTime(encodedTx);\n bridgeTx.zapNative = zapNative(encodedTx);\n bridgeTx.zapData = zapData(encodedTx);\n }\n\n /// @notice Extracts the version from the encoded transaction.\n function version(bytes calldata encodedTx) internal pure returns (uint16 version_) {\n // Load 32 bytes from the start and shift it 240 bits to the right to get the highest 16 bits.\n assembly {\n version_ := shr(240, calldataload(encodedTx.offset))\n }\n }\n\n /// @notice Extracts the origin chain ID from the encoded transaction.\n function originChainId(bytes calldata encodedTx) internal pure returns (uint32 originChainId_) {\n // Load 32 bytes from the offset and shift it 224 bits to the right to get the highest 32 bits.\n assembly {\n originChainId_ := shr(224, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_CHAIN_ID)))\n }\n }\n\n /// @notice Extracts the destination chain ID from the encoded transaction.\n function destChainId(bytes calldata encodedTx) internal pure returns (uint32 destChainId_) {\n // Load 32 bytes from the offset and shift it 224 bits to the right to get the highest 32 bits.\n assembly {\n destChainId_ := shr(224, calldataload(add(encodedTx.offset, OFFSET_DEST_CHAIN_ID)))\n }\n }\n\n /// @notice Extracts the origin sender from the encoded transaction.\n function originSender(bytes calldata encodedTx) internal pure returns (address originSender_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n originSender_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_SENDER)))\n }\n }\n\n /// @notice Extracts the destination recipient from the encoded transaction.\n function destRecipient(bytes calldata encodedTx) internal pure returns (address destRecipient_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n destRecipient_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_DEST_RECIPIENT)))\n }\n }\n\n /// @notice Extracts the origin token from the encoded transaction.\n function originToken(bytes calldata encodedTx) internal pure returns (address originToken_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n originToken_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_TOKEN)))\n }\n }\n\n /// @notice Extracts the destination token from the encoded transaction.\n function destToken(bytes calldata encodedTx) internal pure returns (address destToken_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n destToken_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_DEST_TOKEN)))\n }\n }\n\n /// @notice Extracts the origin amount from the encoded transaction.\n function originAmount(bytes calldata encodedTx) internal pure returns (uint256 originAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n originAmount_ := calldataload(add(encodedTx.offset, OFFSET_ORIGIN_AMOUNT))\n }\n }\n\n /// @notice Extracts the destination amount from the encoded transaction.\n function destAmount(bytes calldata encodedTx) internal pure returns (uint256 destAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n destAmount_ := calldataload(add(encodedTx.offset, OFFSET_DEST_AMOUNT))\n }\n }\n\n /// @notice Extracts the origin fee amount from the encoded transaction.\n function originFeeAmount(bytes calldata encodedTx) internal pure returns (uint256 originFeeAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n originFeeAmount_ := calldataload(add(encodedTx.offset, OFFSET_ORIGIN_FEE_AMOUNT))\n }\n }\n\n /// @notice Extracts the deadline from the encoded transaction.\n function deadline(bytes calldata encodedTx) internal pure returns (uint256 deadline_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n deadline_ := calldataload(add(encodedTx.offset, OFFSET_DEADLINE))\n }\n }\n\n /// @notice Extracts the nonce from the encoded transaction.\n function nonce(bytes calldata encodedTx) internal pure returns (uint256 nonce_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n nonce_ := calldataload(add(encodedTx.offset, OFFSET_NONCE))\n }\n }\n\n /// @notice Extracts the exclusivity relayer from the encoded transaction.\n function exclusivityRelayer(bytes calldata encodedTx) internal pure returns (address exclusivityRelayer_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n exclusivityRelayer_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_EXCLUSIVITY_RELAYER)))\n }\n }\n\n /// @notice Extracts the exclusivity end time from the encoded transaction.\n function exclusivityEndTime(bytes calldata encodedTx) internal pure returns (uint256 exclusivityEndTime_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n exclusivityEndTime_ := calldataload(add(encodedTx.offset, OFFSET_EXCLUSIVITY_END_TIME))\n }\n }\n\n /// @notice Extracts the Zap's native value from the encoded transaction.\n function zapNative(bytes calldata encodedTx) internal pure returns (uint256 zapNative_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n zapNative_ := calldataload(add(encodedTx.offset, OFFSET_ZAP_NATIVE))\n }\n }\n\n /// @notice Extracts the Zap's data from the encoded transaction.\n function zapData(bytes calldata encodedTx) internal pure returns (bytes calldata zapData_) {\n zapData_ = encodedTx[OFFSET_ZAP_DATA:];\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/AdminV2.sol\n\ncontract AdminV2 is AccessControlEnumerable, IAdminV2, IAdminV2Errors {\n using SafeERC20 for IERC20;\n\n /// @notice Address reserved for native gas token (ETH on Ethereum and most L2s, AVAX on Avalanche, etc)\n address public constant NATIVE_GAS_TOKEN = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Role identifier for Quoter API's off-chain authentication.\n /// @dev Only addresses with this role can post FastBridge quotes to the API.\n bytes32 public constant QUOTER_ROLE = keccak256(\"QUOTER_ROLE\");\n\n /// @notice Role identifier for Prover's on-chain authentication in FastBridge.\n /// @dev Only addresses with this role can provide proofs that a FastBridge request has been relayed.\n bytes32 public constant PROVER_ROLE = keccak256(\"PROVER_ROLE\");\n\n /// @notice Role identifier for Guard's on-chain authentication in FastBridge.\n /// @dev Only addresses with this role can dispute submitted relay proofs during the dispute period.\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n\n /// @notice Role identifier for Canceler's on-chain authentication in FastBridge.\n /// @dev Only addresses with this role can cancel a FastBridge transaction without the cancel delay.\n bytes32 public constant CANCELER_ROLE = keccak256(\"CANCELER_ROLE\");\n\n /// @notice Role identifier for Governor's on-chain administrative authority.\n /// @dev Only addresses with this role can perform administrative tasks within the contract.\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n /// @notice Denominator for fee rates, represents 100%.\n uint256 public constant FEE_BPS = 1e6;\n /// @notice Maximum protocol fee rate: 1% on origin amount.\n uint256 public constant FEE_RATE_MAX = 0.01e6;\n\n /// @notice Minimum cancel delay that can be set by the governor.\n uint256 public constant MIN_CANCEL_DELAY = 1 hours;\n /// @notice Default cancel delay set during the contract deployment.\n uint256 public constant DEFAULT_CANCEL_DELAY = 1 days;\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Delay for a transaction after which it could be permisionlessly cancelled\n uint256 public cancelDelay;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Use ZapNative V2 requests instead.\n uint256 public immutable chainGasAmount = 0;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n _setCancelDelay(DEFAULT_CANCEL_DELAY);\n }\n\n /// @notice Allows the contract governor to set the cancel delay. The cancel delay is the time after the transaction\n /// deadline after which it can be permissionlessly cancelled, if it hasn't been proven by any of the Relayers.\n function setCancelDelay(uint256 newCancelDelay) external onlyRole(GOVERNOR_ROLE) {\n _setCancelDelay(newCancelDelay);\n }\n\n /// @notice Allows the contract governor to set the protocol fee rate. The protocol fee is taken from the origin\n /// amount only for completed and claimed transactions.\n /// @dev The protocol fee is abstracted away from the relayers, they always operate using the amounts after fees:\n /// what they see as the origin amount emitted in the log is what they get credited with.\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n if (newFeeRate \u003e FEE_RATE_MAX) revert FeeRateAboveMax();\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n /// @notice Allows the contract governor to sweep the accumulated protocol fees in the contract.\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n emit FeesSwept(token, recipient, feeAmount);\n /// Sweep the fees as the last transaction action\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(recipient), feeAmount);\n } else {\n IERC20(token).safeTransfer(recipient, feeAmount);\n }\n }\n\n /// @notice Internal function to set the cancel delay. Security checks are performed outside of this function.\n function _setCancelDelay(uint256 newCancelDelay) private {\n if (newCancelDelay \u003c MIN_CANCEL_DELAY) revert CancelDelayBelowMin();\n uint256 oldCancelDelay = cancelDelay;\n cancelDelay = newCancelDelay;\n emit CancelDelayUpdated(oldCancelDelay, newCancelDelay);\n }\n}\n\n// contracts/FastBridgeV2.sol\n\n/// @notice FastBridgeV2 is a contract for bridging tokens across chains.\ncontract FastBridgeV2 is AdminV2, MulticallTarget, IFastBridgeV2, IFastBridgeV2Errors {\n using BridgeTransactionV2Lib for bytes;\n using SafeERC20 for IERC20;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n /// @notice Maximum length of accepted zapData\n uint256 public constant MAX_ZAP_DATA_LENGTH = 2 ** 16 - 1;\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeTxDetails) public bridgeTxDetails;\n /// @notice Relay details on destination chain\n mapping(bytes32 =\u003e BridgeRelay) public bridgeRelayDetails;\n /// @notice Unique bridge nonces tracked per originSender\n mapping(address =\u003e uint256) public senderNonces;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Replaced by senderNonces\n uint256 public immutable nonce = 0;\n /// @notice the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) AdminV2(_owner) {\n deployBlock = block.number;\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n bridge({\n params: params,\n paramsV2: BridgeParamsV2({\n quoteRelayer: address(0),\n quoteExclusivitySeconds: 0,\n quoteId: bytes(\"\"),\n zapNative: 0,\n zapData: bytes(\"\")\n })\n });\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes calldata request) external payable {\n // relay override will validate the request\n relay({request: request, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes calldata request, bytes32 destTxHash) external {\n request.validateV2();\n prove({transactionId: keccak256(request), destTxHash: destTxHash, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridgeV2\n function claim(bytes calldata request) external {\n // claim override will validate the request\n claim({request: request, to: address(0)});\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Aggregate the read operations from the same storage slot\n address disputedRelayer = $.proofRelayer;\n BridgeStatus status = $.status;\n uint56 proofBlockTimestamp = $.proofBlockTimestamp;\n // Can only dispute a RELAYER_PROVED transaction within the dispute period\n if (status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(proofBlockTimestamp) \u003e DISPUTE_PERIOD) {\n revert DisputePeriodPassed();\n }\n // Update status to REQUESTED and delete the disputed proof details\n // Note: these are storage writes\n $.status = BridgeStatus.REQUESTED;\n $.proofRelayer = address(0);\n $.proofBlockTimestamp = 0;\n\n emit BridgeProofDisputed(transactionId, disputedRelayer);\n }\n\n /// Note: this function is deprecated and will be removed in a future version.\n /// @inheritdoc IFastBridge\n function refund(bytes calldata request) external {\n cancel(request);\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // The correct relayer can only claim a RELAYER_PROVED transaction after the dispute period\n if ($.status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if ($.proofRelayer != relayer) revert SenderIncorrect();\n return _timeSince($.proofBlockTimestamp) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n /// @dev This method is added to achieve backwards compatibility with decoding requests into V1 structs:\n /// - `zapNative` is partially reported as a zero/non-zero flag\n /// - `zapData` is ignored\n /// In order to process all kinds of requests use getBridgeTransactionV2 instead.\n function getBridgeTransaction(bytes calldata request) external view returns (BridgeTransaction memory) {\n // Try decoding into V2 struct first. This will revert if V1 struct is passed\n try this.getBridgeTransactionV2(request) returns (BridgeTransactionV2 memory txV2) {\n // Note: we entirely ignore the zapData field, as it was not present in V1\n return BridgeTransaction({\n originChainId: txV2.originChainId,\n destChainId: txV2.destChainId,\n originSender: txV2.originSender,\n destRecipient: txV2.destRecipient,\n originToken: txV2.originToken,\n destToken: txV2.destToken,\n originAmount: txV2.originAmount,\n destAmount: txV2.destAmount,\n originFeeAmount: txV2.originFeeAmount,\n sendChainGas: txV2.zapNative != 0,\n deadline: txV2.deadline,\n nonce: txV2.nonce\n });\n } catch {\n // Fallback to V1 struct\n return abi.decode(request, (BridgeTransaction));\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function getBridgeTransactionV2(bytes calldata request) external pure returns (BridgeTransactionV2 memory) {\n request.validateV2();\n return BridgeTransactionV2Lib.decodeV2(request);\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) public payable {\n int256 exclusivityEndTime = 0;\n // if relayer exclusivity is not intended for this bridge, set exclusivityEndTime to static zero\n // otherwise, set exclusivity to expire at the current block ts offset by quoteExclusivitySeconds\n if (paramsV2.quoteRelayer != address(0)) {\n exclusivityEndTime = int256(block.timestamp) + paramsV2.quoteExclusivitySeconds;\n }\n _validateBridgeParams(params, paramsV2, exclusivityEndTime);\n\n // transfer tokens to bridge contract\n /// @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _takeBridgedUserAsset(params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) {\n originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n }\n\n // set status to requested\n bytes memory request = BridgeTransactionV2Lib.encodeV2(\n BridgeTransactionV2({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n deadline: params.deadline,\n nonce: senderNonces[params.sender]++, // increment nonce on every bridge\n exclusivityRelayer: paramsV2.quoteRelayer,\n // We checked exclusivityEndTime to be in range [0 .. params.deadline] above, so can safely cast\n exclusivityEndTime: uint256(exclusivityEndTime),\n zapNative: paramsV2.zapNative,\n zapData: paramsV2.zapData\n })\n );\n bytes32 transactionId = keccak256(request);\n // Note: the tx status will be updated throughout the tx lifecycle, while destChainId is set once here\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n bridgeTxDetails[transactionId].destChainId = params.dstChainId;\n\n emit BridgeRequested({\n transactionId: transactionId,\n sender: params.sender,\n request: request,\n destChainId: params.dstChainId,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n sendChainGas: paramsV2.zapNative != 0\n });\n emit BridgeQuoteDetails(transactionId, paramsV2.quoteId);\n }\n\n /// @inheritdoc IFastBridgeV2\n function relay(bytes calldata request, address relayer) public payable {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n _validateRelayParams(request, transactionId, relayer);\n // mark bridge transaction as relayed\n bridgeRelayDetails[transactionId] =\n BridgeRelay({blockNumber: uint48(block.number), blockTimestamp: uint48(block.timestamp), relayer: relayer});\n\n // transfer tokens to recipient on destination chain and trigger Zap if requested\n address to = request.destRecipient();\n address token = request.destToken();\n uint256 amount = request.destAmount();\n uint256 zapNative = request.zapNative();\n\n // Emit the event before any external calls\n emit BridgeRelayed({\n transactionId: transactionId,\n relayer: relayer,\n to: to,\n originChainId: request.originChainId(),\n originToken: request.originToken(),\n destToken: token,\n originAmount: request.originAmount(),\n destAmount: amount,\n chainGasAmount: zapNative\n });\n\n // All state changes have been done at this point, can proceed to the external calls.\n // This follows the checks-effects-interactions pattern to mitigate potential reentrancy attacks.\n if (token == NATIVE_GAS_TOKEN) {\n // For the native gas token, additional zapNative is not allowed\n if (zapNative != 0) revert ZapNativeNotSupported();\n // Check that the correct msg.value was sent\n if (msg.value != amount) revert MsgValueIncorrect();\n // Don't do a native transfer yet: we will handle it alongside the Zap below\n } else {\n // For ERC20s, we check that the correct msg.value was sent\n if (msg.value != zapNative) revert MsgValueIncorrect();\n // We need to transfer the tokens from the Relayer to the recipient first before performing an\n // optional post-transfer Zap.\n IERC20(token).safeTransferFrom(msg.sender, to, amount);\n }\n // At this point we have done:\n // - Transferred the requested amount of ERC20 tokens to the recipient.\n // At this point we have confirmed:\n // - For ERC20s: msg.value matches the requested zapNative amount.\n // - For the native gas token: msg.value matches the requested destAmount.\n // Remaining optional things to do:\n // - Forward the full msg.value to the recipient (if non-zero).\n // - Trigger a Zap (if zapData is present).\n bytes calldata zapData = request.zapData();\n if (zapData.length != 0) {\n // Zap Data is present: Zap has been requested by the recipient. Trigger it forwarding the full msg.value.\n\n // Note: if token has a fee on transfers, the recipient will have received less than `amount`.\n // This is a very niche edge case and should be handled by the recipient contract.\n _triggerZapWithChecks({recipient: to, token: token, amount: amount, zapData: zapData});\n } else if (msg.value != 0) {\n // Zap Data is missing, but msg.value was sent. This could happen in two different cases:\n // - Relay with the native gas token is happening.\n // - Relay with ERC20 is happening, with a `zapNative \u003e 0` request.\n // In both cases, we need to transfer the full msg.value to the recipient.\n Address.sendValue(payable(to), msg.value);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) public onlyRole(PROVER_ROLE) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n\n // Can only prove a REQUESTED transaction\n if ($.status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n // Update status to RELAYER_PROVED and store the proof details\n // Note: these are storage writes\n $.status = BridgeStatus.RELAYER_PROVED;\n $.proofBlockTimestamp = uint56(block.timestamp);\n $.proofRelayer = relayer;\n\n emit BridgeProofProvided(transactionId, relayer, destTxHash);\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes calldata request, address to) public {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Aggregate the read operations from the same storage slot\n address proofRelayer = $.proofRelayer;\n BridgeStatus status = $.status;\n uint56 proofBlockTimestamp = $.proofBlockTimestamp;\n\n // Can only claim a RELAYER_PROVED transaction after the dispute period\n if (status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(proofBlockTimestamp) \u003c= DISPUTE_PERIOD) {\n revert DisputePeriodNotPassed();\n }\n\n if (to == address(0)) {\n // Anyone could claim the funds to the proven relayer on their behalf\n to = proofRelayer;\n } else if (proofRelayer != msg.sender) {\n // Only the proven relayer could specify an address to claim the funds to\n revert SenderIncorrect();\n }\n\n // Update status to RELAYER_CLAIMED and transfer the origin collateral to the specified claim address\n // Note: this is a storage write\n $.status = BridgeStatus.RELAYER_CLAIMED;\n\n address token = request.originToken();\n uint256 amount = request.originAmount();\n // Update protocol fees if origin fee amount exists\n uint256 originFeeAmount = request.originFeeAmount();\n if (originFeeAmount \u003e 0) protocolFees[token] += originFeeAmount;\n // Emit the event before any external calls\n emit BridgeDepositClaimed(transactionId, proofRelayer, to, token, amount);\n // Complete the relayer claim as the last transaction action\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(to), amount);\n } else {\n IERC20(token).safeTransfer(to, amount);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function cancel(bytes calldata request) public {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Can only cancel a REQUESTED transaction after its deadline expires\n if ($.status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n uint256 deadline = request.deadline();\n // Permissionless cancel is only allowed after `cancelDelay` on top of the deadline\n if (!hasRole(CANCELER_ROLE, msg.sender)) deadline += cancelDelay;\n if (block.timestamp \u003c= deadline) revert DeadlineNotExceeded();\n // Update status to REFUNDED and return the full amount (collateral + protocol fees) to the original sender.\n // The protocol fees are only updated when the transaction is claimed, so we don't need to update them here.\n // Note: this is a storage write\n $.status = BridgeStatus.REFUNDED;\n\n address to = request.originSender();\n address token = request.originToken();\n uint256 amount = request.originAmount() + request.originFeeAmount();\n // Emit the event before any external calls\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n // Complete the user cancel as the last transaction action\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(to), amount);\n } else {\n IERC20(token).safeTransfer(to, amount);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeStatuses(bytes32 transactionId) public view returns (BridgeStatus status) {\n return bridgeTxDetails[transactionId].status;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeProofs(bytes32 transactionId) public view returns (uint96 timestamp, address relayer) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n\n timestamp = $.proofBlockTimestamp;\n relayer = $.proofRelayer;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeRelays(bytes32 transactionId) public view returns (bool) {\n // has this transactionId been relayed?\n return bridgeRelayDetails[transactionId].relayer != address(0);\n }\n\n /// @notice Takes the bridged asset from the user into FastBridgeV2 custody. It will be later\n /// claimed by the relayer who completed the relay on destination chain, or transferred back to the user\n /// via the cancel function should no one complete the relay.\n function _takeBridgedUserAsset(address token, uint256 amount) internal returns (uint256 amountTaken) {\n if (token == NATIVE_GAS_TOKEN) {\n // For the native gas token, we just need to check that the supplied msg.value is correct.\n // Supplied `msg.value` is already in FastBridgeV2 custody.\n if (amount != msg.value) revert MsgValueIncorrect();\n amountTaken = msg.value;\n } else {\n // For ERC20s, token is explicitly transferred from the user to FastBridgeV2.\n // We don't allow non-zero `msg.value` to avoid extra funds from being stuck in FastBridgeV2.\n if (msg.value != 0) revert MsgValueIncorrect();\n // Throw an explicit error if the provided token address is not a contract\n if (token.code.length == 0) revert TokenNotContract();\n amountTaken = IERC20(token).balanceOf(address(this));\n IERC20(token).safeTransferFrom(msg.sender, address(this), amount);\n // Use the balance difference as the amount taken in case of fee on transfer tokens.\n amountTaken = IERC20(token).balanceOf(address(this)) - amountTaken;\n }\n }\n\n /// @notice Calls the Recipient's hook function with the specified zapData and performs\n /// all the necessary checks for the returned value.\n function _triggerZapWithChecks(address recipient, address token, uint256 amount, bytes calldata zapData) internal {\n // This will bubble any revert messages from the hook function\n bytes memory returnData = Address.functionCallWithValue({\n target: recipient,\n data: abi.encodeCall(IZapRecipient.zap, (token, amount, zapData)),\n // Note: see `relay()` for reasoning behind passing msg.value\n value: msg.value\n });\n // Explicit revert if no return data at all\n if (returnData.length == 0) revert RecipientNoReturnValue();\n // Check that exactly a single return value was returned\n if (returnData.length != 32) revert RecipientIncorrectReturnValue();\n // Return value should be abi-encoded hook function selector\n if (bytes32(returnData) != bytes32(IZapRecipient.zap.selector)) {\n revert RecipientIncorrectReturnValue();\n }\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint56(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint56).max but\n /// proof.timestamp \u003c type(uint56).max via unchecked statement\n /// @param proofBlockTimestamp The bridge proof block timestamp\n /// @return delta Time delta since proof submitted\n function _timeSince(uint56 proofBlockTimestamp) internal view returns (uint256 delta) {\n unchecked {\n delta = uint56(block.timestamp) - proofBlockTimestamp;\n }\n }\n\n /// @notice Performs all the necessary checks for a bridge to happen.\n /// @dev There's no good way to refactor this function to reduce cyclomatic complexity due to\n /// the number of checks that need to be performed, so we skip the code-complexity rule here.\n // solhint-disable-next-line code-complexity\n function _validateBridgeParams(\n BridgeParams memory params,\n BridgeParamsV2 memory paramsV2,\n int256 exclusivityEndTime\n )\n internal\n view\n {\n // Check V1 (legacy) params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.sender == address(0) || params.to == address(0)) revert ZeroAddress();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n // Check V2 params\n if (paramsV2.zapData.length \u003e MAX_ZAP_DATA_LENGTH) revert ZapDataLengthAboveMax();\n if (paramsV2.zapNative != 0 \u0026\u0026 params.destToken == NATIVE_GAS_TOKEN) {\n revert ZapNativeNotSupported();\n }\n // exclusivityEndTime must be in range [0 .. params.deadline]\n if (exclusivityEndTime \u003c 0 || exclusivityEndTime \u003e int256(params.deadline)) {\n revert ExclusivityParamsIncorrect();\n }\n }\n\n /// @notice Performs all the necessary checks for a relay to happen.\n function _validateRelayParams(bytes calldata request, bytes32 transactionId, address relayer) internal view {\n if (relayer == address(0)) revert ZeroAddress();\n // Check if the transaction has already been relayed\n if (bridgeRelays(transactionId)) revert TransactionRelayed();\n if (request.destChainId() != block.chainid) revert ChainIncorrect();\n // Check the deadline for relay to happen\n if (block.timestamp \u003e request.deadline()) revert DeadlineExceeded();\n // Check the exclusivity period, if it is still ongoing\n address exclRelayer = request.exclusivityRelayer();\n if (exclRelayer != address(0) \u0026\u0026 exclRelayer != relayer \u0026\u0026 block.timestamp \u003c= request.exclusivityEndTime()) {\n revert ExclusivityPeriodNotPassed();\n }\n }\n}\n","language":"Solidity","languageVersion":"0.8.24","compilerVersion":"0.8.24","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"80976:22670:0:-:0;;;78600:1;78558:43;;;;81964:34;;82102:87;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;82138:6;78646:38;68687:4;82138:6;78646:10;:38::i;:::-;-1:-1:-1;78694:37:0;78092:6;78694:15;:37::i;:::-;-1:-1:-1;;82170:12:0::1;82156:26;::::0;80976:22670;;75409:257;75495:4;;75526:31;75543:4;75549:7;75526:16;:31::i;:::-;75511:46;;75571:7;75567:69;;;75594:18;;;;:12;:18;;;;;:31;;75617:7;75594:22;:31::i;:::-;;75567:69;75652:7;-1:-1:-1;75409:257:0;;;;;:::o;80577:290::-;77959:7;80648:14;:33;80644:67;;;80690:21;;-1:-1:-1;;;80690:21:0;;;;;;;;;;;80644:67;80746:11;;;80767:28;;;;80810:50;;;483:25:1;;;539:2;524:18;;517:34;;;80810:50:0;;456:18:1;80810:50:0;;;;;;;80634:233;80577:290;:::o;72634:316::-;72711:4;69409:12;;;;;;;;;;;-1:-1:-1;;;;;69409:29:0;;;;;;;;;;;;72727:217;;72770:6;:12;;;;;;;;;;;-1:-1:-1;;;;;72770:29:0;;;;;;;;;:36;;-1:-1:-1;;72770:36:0;72802:4;72770:36;;;72852:12;23372:10;;23293:96;72852:12;-1:-1:-1;;;;;72825:40:0;72843:7;-1:-1:-1;;;;;72825:40:0;72837:4;72825:40;;;;;;;;;;-1:-1:-1;72886:4:0;72879:11;;72727:217;-1:-1:-1;72928:5:0;72921:12;;32817:150;32887:4;32910:50;32915:3;-1:-1:-1;;;;;32935:23:0;;26805:4;28861:21;;;:14;;;:21;;;;;;26821:321;;-1:-1:-1;26863:23:0;;;;;;;;:11;:23;;;;;;;;;;;;;27045:18;;27021:21;;;:14;;;:21;;;;;;:42;;;;27077:11;;14:290:1;84:6;137:2;125:9;116:7;112:23;108:32;105:52;;;153:1;150;143:12;105:52;179:16;;-1:-1:-1;;;;;224:31:1;;214:42;;204:70;;270:1;267;260:12;309:248;80976:22670:0;;;;;;;;;;;;;;;;;;;;;;;;","srcMapRuntime":"80976:22670:0:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;74069:212;;;;;;;;;;-1:-1:-1;74069:212:0;;;;;:::i;:::-;;:::i;:::-;;;612:14:1;;605:22;587:41;;575:2;560:18;74069:212:0;;;;;;;;77302:66;;;;;;;;;;;;77342:26;77302:66;;;;;785:25:1;;;773:2;758:18;77302:66:0;639:177:1;77044:60:0;;;;;;;;;;;;77081:23;77044:60;;97383:150;;;;;;;;;;-1:-1:-1;97383:150:0;;;;;:::i;:::-;97451:19;97489:30;;;:15;:30;;;;;:37;;;;97383:150;;;;;;;;:::i;79902:554::-;;;;;;;;;;-1:-1:-1;79902:554:0;;;;;:::i;:::-;;:::i;:::-;;77794:45;;;;;;;;;;;;77833:6;77794:45;;76279:85;;;;;;;;;;;;76322:42;76279:85;;;;;-1:-1:-1;;;;;2885:55:1;;;2867:74;;2855:2;2840:18;76279:85:0;2721:226:1;93245:627:0;;;;;;;;;;-1:-1:-1;93245:627:0;;;;;:::i;:::-;;:::i;78981:129::-;;;;;;;;;;-1:-1:-1;78981:129:0;;;;;:::i;:::-;;:::i;70265:120::-;;;;;;;;;;-1:-1:-1;70265:120:0;;;;;:::i;:::-;70330:7;70356:12;;;;;;;;;;:22;;;;70265:120;81813:47;;;;;;;;;;-1:-1:-1;81813:47:0;;;;;:::i;:::-;;;;;;;;;;;;;;70681:136;;;;;;;;;;-1:-1:-1;70681:136:0;;;;;:::i;:::-;;:::i;71783:245::-;;;;;;;;;;-1:-1:-1;71783:245:0;;;;;:::i;:::-;;:::i;45543:875::-;;;;;;;;;;-1:-1:-1;45543:875:0;;;;;:::i;:::-;;:::i;:::-;;;;;;;:::i;95855:1488::-;;;;;;;;;;-1:-1:-1;95855:1488:0;;;;;:::i;:::-;;:::i;44142:718::-;;;;;;;;;;-1:-1:-1;44142:718:0;;;;;:::i;:::-;;:::i;93910:1905::-;;;;;;;;;;-1:-1:-1;93910:1905:0;;;;;:::i;:::-;;:::i;82227:366::-;;;;;;:::i;:::-;;:::i;81453:57::-;;;;;;;;;;;;81499:11;81453:57;;78188:30;;;;;;;;;;;;;;;;86422:201;;;;;;;;;;-1:-1:-1;86422:201:0;;;;;:::i;:::-;;:::i;:::-;;;;;;;:::i;84338:81::-;;;;;;;;;;-1:-1:-1;84338:81:0;;;;;:::i;:::-;;:::i;81573:58::-;;;;;;;;;;-1:-1:-1;81573:58:0;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;81573:58:0;;;;;;;;;;;;;:::i;78418:26::-;;;;;;;;;;;;;;;;76528:62;;;;;;;;;;;;76566:24;76528:62;;81339:56;;;;;;;;;;;;81385:10;81339:56;;97867:199;;;;;;;;;;-1:-1:-1;97867:199:0;;;;;:::i;:::-;97933:4;98004:33;;;:18;:33;;;;;:41;;;;-1:-1:-1;;;;;98004:41:0;:55;;;97867:199;82840:202;;;;;;;;;;-1:-1:-1;82840:202:0;;;;;:::i;:::-;;:::i;82631:171::-;;;;;;:::i;:::-;;:::i;74866:142::-;;;;;;;;;;-1:-1:-1;74866:142:0;;;;;:::i;:::-;;:::i;97573:254::-;;;;;;;;;;-1:-1:-1;97573:254:0;;;;;:::i;:::-;97639:16;97712:30;;;:15;:30;;;;;97765:21;;;;;;;97806:14;;;;-1:-1:-1;;;;;97806:14:0;;97573:254;;;;;14428:26:1;14416:39;;;14398:58;;-1:-1:-1;;;;;14492:55:1;;;14487:2;14472:18;;14465:83;14371:18;97573:254:0;14226:328:1;69309:136:0;;;;;;;;;;-1:-1:-1;69309:136:0;;;;;:::i;:::-;69386:4;69409:12;;;;;;;;;;;-1:-1:-1;;;;;69409:29:0;;;;;;;;;;;;;;;69309:136;77916:50;;;;;;;;;;;;77959:7;77916:50;;78045:53;;;;;;;;;;;;78092:6;78045:53;;89646:3559;;;;;;:::i;:::-;;:::i;68642:49::-;;;;;;;;;;-1:-1:-1;68642:49:0;68687:4;68642:49;;82059:36;;;;;;;;;;;;;;;84457:473;;;;;;;;;;-1:-1:-1;84457:473:0;;;;;:::i;:::-;;:::i;85262:1120::-;;;;;;;;;;-1:-1:-1;85262:1120:0;;;;;:::i;:::-;;:::i;:::-;;;;;;;:::i;83278:939::-;;;;;;;;;;-1:-1:-1;83278:939:0;;;;;:::i;:::-;;:::i;81964:34::-;;;;;;;;;;;;;;;79505:290;;;;;;;;;;-1:-1:-1;79505:290:0;;;;;:::i;:::-;;:::i;77687:37::-;;;;;;;;;;;;77721:3;77687:37;;86663:2943;;;;;;:::i;:::-;;:::i;83082:158::-;;;;;;;;;;-1:-1:-1;83082:158:0;;;;;:::i;:::-;;:::i;81688:57::-;;;;;;;;;;-1:-1:-1;81688:57:0;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;81688:57:0;;;;;;;18029:14:1;18070:15;;;18052:34;;18122:15;;;;18117:2;18102:18;;18095:43;-1:-1:-1;;;;;18174:55:1;18154:18;;;18147:83;18007:2;17992:18;81688:57:0;17821:415:1;75176:131:0;;;;;;;;;;-1:-1:-1;75176:131:0;;;;;:::i;:::-;;:::i;77554:66::-;;;;;;;;;;;;77594:26;77554:66;;71097:138;;;;;;;;;;-1:-1:-1;71097:138:0;;;;;:::i;:::-;;:::i;76787:62::-;;;;;;;;;;;;76825:24;76787:62;;78274:47;;;;;;;;;;-1:-1:-1;78274:47:0;;;;;:::i;:::-;;;;;;;;;;;;;;78558:43;;;;;;;;;;;;;;;74069:212;74154:4;74177:57;;;74192:42;74177:57;;:97;;;74238:36;74262:11;74238:23;:36::i;:::-;74170:104;74069:212;-1:-1:-1;;74069:212:0:o;79902:554::-;77594:26;68919:16;68930:4;68919:10;:16::i;:::-;-1:-1:-1;;;;;80026:19:0;::::1;80006:17;80026:19:::0;;;:12:::1;:19;::::0;;;;;;80059:14;;;80055:27:::1;;80075:7;79902:554:::0;;;:::o;80055:27::-:1;-1:-1:-1::0;;;;;80123:19:0;;::::1;80145:1;80123:19:::0;;;:12:::1;:19;::::0;;;;;;;:23;;;;80161:38;;18504:34:1;;;18574:15;;;18554:18;;;18547:43;;;;18606:18;;;18599:34;;;80161:38:0::1;::::0;18431:2:1;18416:18;80161:38:0::1;;;;;;;80271:25:::0;-1:-1:-1;;;;;80271:25:0;::::1;::::0;80267:183:::1;;80312:48;80338:9;80350;80312:17;:48::i;:::-;80267:183;;;80391:48;-1:-1:-1::0;;;;;80391:26:0;::::1;80418:9:::0;80429;80391:26:::1;:48::i;:::-;79996:460;68945:1;79902:554:::0;;;:::o;93245:627::-;76825:24;68919:16;68930:4;68919:10;:16::i;:::-;93359:25:::1;93387:30:::0;;;:15:::1;:30;::::0;;;;93494:22:::1;93482:8:::0;;::::1;;:34;::::0;::::1;;;;;;:::i;:::-;;93478:64;;93525:17;;;;;;;;;;;;;;93478:64;93665:38:::0;;-1:-1:-1;;;;;93770:24:0;::::1;::::0;;::::1;::::0;93713:47:::1;93744:15;93713:47;::::0;::::1;93770:24:::0;;;;;;;;;;;;;93676:27:::1;93770:24:::0;;;93810:55:::1;::::0;785:25:1;;;93830:13:0;;93810:55:::1;::::0;773:2:1;758:18;93810:55:0::1;;;;;;;93349:523;93245:627:::0;;;;:::o;78981:129::-;77594:26;68919:16;68930:4;68919:10;:16::i;:::-;79072:31:::1;79088:14;79072:15;:31::i;:::-;78981:129:::0;;:::o;70681:136::-;70330:7;70356:12;;;;;;;;;;:22;;;68919:16;68930:4;68919:10;:16::i;:::-;70785:25:::1;70796:4;70802:7;70785:10;:25::i;71783:245::-:0;-1:-1:-1;;;;;71876:34:0;;23372:10;71876:34;71872:102;;71933:30;;;;;;;;;;;;;;71872:102;71984:37;71996:4;72002:18;71984:11;:37::i;45543:875::-;45672:23;45734:4;45721:25;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;;;;;;;;;;;;;45721:25:0;;;;;;;;;;;;;;;;45711:35;;45761:9;45756:656;45776:15;;;45756:656;;;46249:4;46268;;46273:1;46268:7;;;;;;;:::i;:::-;;;;;;;;;;;;:::i;:::-;46241:35;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;46196:7;46204:1;46196:10;;;;;;;;:::i;:::-;;;;;;;:18;;46216:7;46224:1;46216:10;;;;;;;;:::i;:::-;;;;;;;:21;;46195:81;;;;;;;;;;;;;46295:7;46303:1;46295:10;;;;;;;;:::i;:::-;;;;;;;:18;;;46294:19;:37;;;;;46318:13;46317:14;46294:37;46290:112;;;46351:36;46365:7;46373:1;46365:10;;;;;;;;:::i;:::-;;;;;;;:21;;;46351:13;:36::i;:::-;45793:3;;45756:656;;;;45543:875;;;;;:::o;95855:1488::-;95912:20;:7;;:18;:20::i;:::-;95942:21;95976:7;;95966:18;;;;;;;:::i;:::-;;;;;;;;;;;95994:25;96022:30;;;:15;:30;;;;;;95966:18;;-1:-1:-1;96156:22:0;96144:8;;;;:34;;;;;;;;:::i;:::-;;96140:64;;96187:17;;;;;;;;;;;;;;96140:64;96381:10;96214:16;69409:29;;;:12;;:29;:12;:29;;;59118:15;59096:38;;59083:52;;69409:29;;96353:64;;96406:11;;96394:23;;;;:::i;:::-;;;96353:64;96450:8;96431:15;:27;96427:61;;96467:21;;;;;;;;;;;;;;96427:61;96773:32;;;;96784:21;96773:32;;;56338:20;56316:43;;56303:57;56299:2;56295:66;;;;57164:19;57142:42;;57129:56;57121:65;;-1:-1:-1;96925:50:0;58742:24;58720:47;;58707:61;57954:20;57932:43;;57919:57;96925:50;:::i;:::-;97042:55;;;-1:-1:-1;;;;;20205:55:1;;;20187:74;;20292:2;20277:18;;20270:34;;;97042:55:0;;20270:34:1;;-1:-1:-1;97042:55:0;;;97064:13;;97042:55;;;;;;;;97178:25;-1:-1:-1;;;;;97178:25:0;;;97174:163;;97219:38;97245:2;97250:6;97219:17;:38::i;:::-;97174:163;;;97288:38;-1:-1:-1;;;;;97288:26:0;;97315:2;97319:6;97288:26;:38::i;:::-;95902:1441;;;;;;95855:1488;;:::o;44142:718::-;44237:9;44232:622;44252:15;;;44232:622;;;44672:12;;44717:4;44736;;44741:1;44736:7;;;;;;;:::i;:::-;;;;;;;;;;;;:::i;:::-;44709:35;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;44671:73;;;;44763:7;44762:8;:26;;;;;44775:13;44774:14;44762:26;44758:86;;;44808:21;44822:6;44808:13;:21::i;:::-;-1:-1:-1;;44269:3:0;;44232:622;;93910:1905;93978:20;:7;;:18;:20::i;:::-;94008:21;94042:7;;94032:18;;;;;;;:::i;:::-;;;;;;;;;;;94060:25;94088:30;;;:15;:30;;;;;;94219:14;;94032:18;;-1:-1:-1;94088:30:0;94219:14;;;-1:-1:-1;;;;;94219:14:0;;94265:8;;;;94312:21;;;;;94438:27;94428:6;:37;;;;;;;;:::i;:::-;;94424:67;;94474:17;;;;;;;;;;;;;;94424:67;81242:10;101235:15;101228:45;;;101220:53;;94505:49;94501:111;;94577:24;;;;;;;;;;;;;;94501:111;-1:-1:-1;;;;;94626:16:0;;94622:319;;94745:12;94740:17;;94622:319;;;-1:-1:-1;;;;;94778:26:0;;94794:10;94778:26;94774:167;;94913:17;;;;;;;;;;;;;;94774:167;95102:39;;;;95113:28;95102:39;;;57164:19;57142:42;;57129:56;57125:2;57121:65;57954:20;57932:43;;57919:57;58742:24;58720:47;;58707:61;95373:19;;95369:63;;-1:-1:-1;;;;;95394:19:0;;;;;;:12;:19;;;;;:38;;95417:15;;95394:19;:38;;95417:15;;95394:38;:::i;:::-;;;;-1:-1:-1;;95369:63:0;95499:68;;;-1:-1:-1;;;;;20205:55:1;;;20187:74;;20292:2;20277:18;;20270:34;;;95499:68:0;;;;;;;;95520:13;;95499:68;;20160:18:1;95499:68:0;;;;;;;95650:25;-1:-1:-1;;;;;95650:25:0;;;95646:163;;95691:38;95717:2;95722:6;95691:17;:38::i;:::-;95646:163;;;95760:38;-1:-1:-1;;;;;95760:26:0;;95787:2;95791:6;95760:26;:38::i;:::-;93968:1847;;;;;;;;93910:1905;;;:::o;82227:366::-;82298:288;82327:6;82357:218;;;;;;;;82412:1;-1:-1:-1;;;;;82357:218:0;;;;;82457:1;82357:218;;;;82485:9;;;;;;;;;;;;82357:218;;;;82523:1;82357:218;;;;82551:9;;;;;;;;;;;;82357:218;;;82298:6;:288::i;:::-;82227:366;:::o;86422:201::-;86501:26;-1:-1:-1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;86501:26:0;86539:20;:7;;:18;:20::i;:::-;86576:40;86608:7;;86576:31;:40::i;:::-;86569:47;86422:201;-1:-1:-1;;;86422:201:0:o;84338:81::-;84397:15;84404:7;;84397:6;:15::i;82840:202::-;82918:20;:7;;:18;:20::i;:::-;82948:87;82980:7;;82970:18;;;;;;;:::i;:::-;;;;;;;;83002:10;83023;82948:5;:87::i;82631:171::-;82749:46;82765:7;;82783:10;82749:5;:46::i;74866:142::-;74947:7;74973:18;;;:12;:18;;;;;:28;;74995:5;74973:21;:28::i;89646:3559::-;89727:20;:7;;:18;:20::i;:::-;89757:21;89791:7;;89781:18;;;;;;;:::i;:::-;;;;;;;;89757:42;;89809:53;89830:7;;89839:13;89854:7;89809:20;:53::i;:::-;89966:107;;;;;;;;;89999:12;89966:107;;;;90037:15;89966:107;;;;;;;;;-1:-1:-1;;;;;89966:107:0;;;;;;;;;-1:-1:-1;89918:33:0;;;:18;:33;;;;;;:155;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;90187:23;:7;56758:21;56736:44;56723:58;56719:2;56715:67;;56464:334;90187:23;90174:36;-1:-1:-1;57567:17:0;57545:40;;57532:54;57528:2;57524:63;58342:18;58320:41;;58307:55;60710:17;60688:40;;60675:54;-1:-1:-1;;;;;90419:368:0;;;;;;90462:13;90419:368;55514:22;55492:45;;55479:59;55474:3;55470:69;90419:368;;;20630:10:1;20618:23;;;;20600:42;;57164:19:0;57142:42;;57129:56;57125:2;57121:65;;;20734:2:1;20719:18;;20712:43;-1:-1:-1;;;;;20791:15:1;;20771:18;;;20764:43;57954:20:0;57932:43;;57919:57;20823:18:1;;;20816:34;20881:3;20866:19;;20859:35;;;20925:3;20910:19;;20903:35;;;90419:368:0;;;;;20587:3:1;90419:368:0;;;91002:25;-1:-1:-1;;;;;91002:25:0;;;90998:769;;91124:14;;91120:50;;91147:23;;;;;;;;;;;;;;91120:50;91258:6;91245:9;:19;91241:51;;91273:19;;;;;;;;;;;;;;91241:51;90998:769;;;91501:9;91488;:22;91484:54;;91519:19;;;;;;;;;;;;;;91484:54;91702;-1:-1:-1;;;;;91702:30:0;;91733:10;91745:2;91749:6;91702:30;:54::i;:::-;92265:22;;92290:17;:7;;:15;:17::i;:::-;92265:42;;-1:-1:-1;92265:42:0;-1:-1:-1;92321:19:0;;92317:882;;92678:86;92712:2;92723:5;92738:6;92755:7;;92678:21;:86::i;:::-;92317:882;;;92785:9;:14;92781:418;;93147:41;93173:2;93178:9;93147:17;:41::i;:::-;89717:3488;;;;;;;89646:3559;;;:::o;84457:473::-;84538:4;84582:30;;;:15;:30;;;;;84738:27;84726:8;;;;:39;;;;;;;;:::i;:::-;;84722:69;;84774:17;;;;;;;;;;;;;;84722:69;84805:14;;-1:-1:-1;;;;;84805:25:0;;;:14;;;;;:25;84801:55;;84839:17;;;;;;;;;;;;;;84801:55;84884:21;81242:10;84884:21;;;;;;;;101235:15;101228:45;101220:53;84873:50;;;-1:-1:-1;;;84457:473:0:o;85262:1120::-;-1:-1:-1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;85465:36:0;;;;;:4;;:27;;:36;;85493:7;;;;85465:36;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;85465:36:0;;;;;;;;;;;;:::i;:::-;;;85461:915;;86325:40;;;;86336:7;86325:40;:::i;:::-;86318:47;;;;85461:915;85652:597;;;;;;;;85703:4;:18;;;85652:597;;;;;;85752:4;:16;;;85652:597;;;;;;85800:4;:17;;;-1:-1:-1;;;;;85652:597:0;;;;;85850:4;:18;;;-1:-1:-1;;;;;85652:597:0;;;;;85899:4;:16;;;-1:-1:-1;;;;;85652:597:0;;;;;85944:4;:14;;;-1:-1:-1;;;;;85652:597:0;;;;;85990:4;:17;;;85652:597;;;;86037:4;:15;;;85652:597;;;;86087:4;:20;;;85652:597;;;;86139:4;:14;;;86157:1;86139:19;;85652:597;;;;;;86186:4;:13;;;85652:597;;;;86224:4;:10;;;85652:597;;;85645:604;;;;;83278:939;77081:23;68919:16;68930:4;68919:10;:16::i;:::-;83358:25:::1;83386:30:::0;;;:15:::1;:30;::::0;;;;83520:14;;;;::::1;-1:-1:-1::0;;;;;83520:14:0::1;::::0;83566:8:::1;::::0;::::1;::::0;83613:21;;::::1;;;83741:27;83731:6;:37;;;;;;;;:::i;:::-;;83727:67;;83777:17;;;;;;;;;;;;;;83727:67;81242:10;101235:15:::0;101228:45;;;101220:53;;83808:48:::1;83804:107;;;83879:21;;;;;;;;;;;;;;83804:107;84038:33:::0;;84118:25;;84049:22:::1;84118:25:::0;;;84159:51:::1;::::0;-1:-1:-1;;;;;84159:51:0;::::1;::::0;84179:13;;84159:51:::1;::::0;-1:-1:-1;;84159:51:0::1;83348:869;;;;83278:939:::0;;:::o;79505:290::-;77594:26;68919:16;68930:4;68919:10;:16::i;:::-;77833:6:::1;79600:10;:25;79596:55;;;79634:17;;;;;;;;;;;;;;79596:55;79682:15;::::0;;79707:28;;;;79750:38:::1;::::0;;25249:25:1;;;25305:2;25290:18;;25283:34;;;79750:38:0::1;::::0;25222:18:1;79750:38:0::1;;;;;;;79586:209;79505:290:::0;;:::o;86663:2943::-;87018:21;;86764:25;;-1:-1:-1;;;;;87018:35:0;;87014:145;;87116:32;;;;87090:58;;87097:15;87090:58;:::i;:::-;87069:79;;87014:145;87168:59;87190:6;87198:8;87208:18;87168:21;:59::i;:::-;87363:20;87386:62;87408:6;:18;;;87428:6;:19;;;87386:21;:62::i;:::-;87363:85;;87516:23;87571:1;87553:15;;:19;87549:222;;;77721:3;87622:15;;87607:12;:30;;;;:::i;:::-;87606:42;;;;:::i;:::-;87588:60;-1:-1:-1;87662:31:0;87588:60;87662:31;;:::i;:::-;;;87549:222;87816:20;87839:973;87884:918;;;;;;;;87944:13;87884:918;;;;;;87989:6;:17;;;87884:918;;;;;;88038:6;:13;;;-1:-1:-1;;;;;87884:918:0;;;;;88084:6;:9;;;-1:-1:-1;;;;;87884:918:0;;;;;88124:6;:18;;;-1:-1:-1;;;;;87884:918:0;;;;;88171:6;:16;;;-1:-1:-1;;;;;87884:918:0;;;;;88219:12;87884:918;;;;88261:6;:17;;;87884:918;;;;88313:15;87884:918;;;;88356:6;:15;;;87884:918;;;;88396:12;:27;88409:6;:13;;;-1:-1:-1;;;;;88396:27:0;-1:-1:-1;;;;;88396:27:0;;;;;;;;;;;;;:29;;;;;;;;;:::i;:::-;;;;-1:-1:-1;87884:918:0;;88498:21;;-1:-1:-1;;;;;87884:918:0;;;;;;;;;;;;88726:18;;;;87884:918;;;;;88771:16;;;;87884:918;;;87839:31;:973::i;:::-;88846:18;;;;;;;;;;88822:21;88985:30;;;:15;:30;;;;;;;:62;;89102:17;;89057:62;;;;;;;;;;;;;89025:22;89057:62;;;;89215:13;;;;89329:18;;;;;89372:16;;;;89454:17;;;;89499:18;;;;89135:398;;88846:18;;-1:-1:-1;88846:18:0;;-1:-1:-1;;;;;89135:398:0;;;;88846:18;;89135:398;;;;88846:18;;89102:17;;89329:18;89416:12;;89454:17;;89499:23;;;;89135:398;:::i;:::-;;;;;;;;89567:13;89548:51;89582:8;:16;;;89548:51;;;;;;:::i;:::-;;;;;;;;86754:2852;;;;;86663:2943;;:::o;83082:158::-;83192:41;83208:7;;83229:1;83192:5;:41::i;75176:131::-;75247:7;75273:18;;;:12;:18;;;;;:27;;:25;:27::i;71097:138::-;70330:7;70356:12;;;;;;;;;;:22;;;68919:16;68930:4;68919:10;:16::i;:::-;71202:26:::1;71214:4;71220:7;71202:11;:26::i;69020:202::-:0;69105:4;69128:47;;;69143:32;69128:47;;:87;;-1:-1:-1;49356:25:0;49341:40;;;;69179:36;49242:146;69654:103;69720:30;69731:4;23372:10;69720;:30::i;17904:331::-;18013:6;17989:21;:30;17985:109;;;18042:41;;;;;18077:4;18042:41;;;2867:74:1;2840:18;;18042:41:0;;;;;;;;17985:109;18105:12;18123:9;-1:-1:-1;;;;;18123:14:0;18145:6;18123:33;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;18104:52;;;18171:7;18166:63;;18201:17;;;;;;;;;;;;;;62137:160;62246:43;;-1:-1:-1;;;;;20205:55:1;;;62246:43:0;;;20187:74:1;20277:18;;;20270:34;;;62219:71:0;;62239:5;;62261:14;;;;;20160:18:1;;62246:43:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;62219:19;:71::i;80577:290::-;77959:7;80648:14;:33;80644:67;;;80690:21;;;;;;;;;;;;;;80644:67;80746:11;;;80767:28;;;;80810:50;;;25249:25:1;;;25305:2;25290:18;;25283:34;;;80810:50:0;;25222:18:1;80810:50:0;;;;;;;80634:233;80577:290;:::o;75409:257::-;75495:4;75511:12;75526:31;75543:4;75549:7;75526:16;:31::i;:::-;75511:46;;75571:7;75567:69;;;75594:18;;;;:12;:18;;;;;:31;;75617:7;75594:22;:31::i;75769:262::-;75856:4;75872:12;75887:32;75905:4;75911:7;75887:17;:32::i;:::-;75872:47;;75933:7;75929:72;;;75956:18;;;;:12;:18;;;;;:34;;75982:7;75956:25;:34::i;46692:556::-;46830:17;;:21;46826:416;;47071:10;47065:17;47127:15;47114:10;47110:2;47106:19;47099:44;46826:416;47194:37;;;;;;;;;;;;;;51826:469;51445:3;51978:34;;51974:86;;;52021:39;;;;;;;;;;;;;;51974:86;55092:30;;55087:3;55083:40;49545:1;52211:19;;52207:81;;52239:49;;;;;27697:6:1;27685:19;;52239:49:0;;;27667:38:1;27640:18;;52239:49:0;27523:188:1;53789:990:0;53880:49;-1:-1:-1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;53880:49:0;55514:22;55492:45;;55479:59;55474:3;55470:69;;;53945:49;;55929:20;55907:43;;55894:57;55885:67;;54004:20;;;:45;56338:20;56316:43;;56303:57;56299:2;56295:66;;;54059:21;;;:47;56758:21;56736:44;;56723:58;56715:67;;54116:22;;;:49;57164:19;57142:42;;57129:56;57121:65;;54175:20;;;:45;57567:17;57545:40;;57532:54;57524:63;;54230:18;;;:41;57954:20;57932:43;;57919:57;54281:21;;;:47;58342:18;58320:41;;58307:55;54338:19;;;:43;;;;58742:24;58720:47;;58707:61;54391:24;;;:53;59118:15;59096:38;;59083:52;54454:17;;;:39;59473:12;59451:35;;59438:49;54503:14;;;:33;59897:26;59875:49;;59862:63;59854:72;;54546:27;;;:59;60318:27;60296:50;;60283:64;54615:27;;;:59;60710:17;60688:40;;60675:54;54684:18;;;:41;54754:18;55492:45;54762:9;54754:7;:18::i;:::-;54735:37;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;54735:16:0;;;:37;:8;53789:990;-1:-1:-1;;53789:990:0:o;34075:156::-;34149:7;34199:22;34203:3;34215:5;34199:3;:22::i;102836:808::-;-1:-1:-1;;;;;102958:21:0;;102954:47;;102988:13;;;;;;;;;;;;;;102954:47;97933:4;98004:33;;;:18;:33;;;;;:41;;;;-1:-1:-1;;;;;98004:41:0;:55;103072:60;;103112:20;;;;;;;;;;;;;;103072:60;55929:20;55907:43;;55894:57;55889:3;55885:67;103171:13;103146:38;103142:67;;103193:16;;;;;;;;;;;;;;103142:67;59118:15;59096:38;;59083:52;103273:15;:36;103269:67;;;103318:18;;;;;;;;;;;;;;103269:67;59897:26;59875:49;;59862:63;59858:2;59854:72;103474:25;;;;;:51;;;103518:7;-1:-1:-1;;;;;103503:22:0;:11;-1:-1:-1;;;;;103503:22:0;;;103474:51;:102;;;;-1:-1:-1;60318:27:0;60296:50;;60283:64;103529:15;:47;;103474:102;103470:168;;;103599:28;;;;;;;;;;;;;;103470:168;102944:700;102836:808;;;;:::o;62536:188::-;62663:53;;-1:-1:-1;;;;;18522:15:1;;;62663:53:0;;;18504:34:1;18574:15;;;18554:18;;;18547:43;18606:18;;;18599:34;;;62636:81:0;;62656:5;;62678:18;;;;;18416::1;;62663:53:0;18241:398:1;60821:146:0;60887:23;;60933:27;:9;51445:3;60933:9;;:27;:::i;:::-;60922:38;;;;60821:146;;;;;:::o;99685:951::-;99880:23;99906:255;99958:9;100022:5;100029:6;100037:7;;99987:59;;;;;;;;;;;:::i;:::-;;;;-1:-1:-1;;99987:59:0;;;;;;;;;;;;;;;;;;;;100141:9;99906:29;:255::i;:::-;99880:281;;100227:10;:17;100248:1;100227:22;100223:59;;100258:24;;;;;;;;;;;;;;100223:59;100361:10;:17;100382:2;100361:23;100357:67;;100393:31;;;;;;;;;;;;;;100357:67;100538:26;100507:19;100515:10;100507:19;:::i;:::-;:58;100503:127;;100588:31;;;;;;;;;;;;;;100503:127;99799:837;99685:951;;;;;:::o;101615:1142::-;101868:13;101847:6;:17;;;:34;;;101843:63;;101890:16;;;;;;;;;;;;;;101843:63;101920:19;;;;:24;;:50;;-1:-1:-1;101948:17:0;;;;:22;101920:50;101916:80;;;101979:17;;;;;;;;;;;;;;101916:80;102010:13;;;;-1:-1:-1;;;;;102010:27:0;;;:54;;-1:-1:-1;102041:9:0;;;;-1:-1:-1;;;;;102041:23:0;;102010:54;102006:80;;;102073:13;;;;;;;;;;;;;;102006:80;102100:18;;;;-1:-1:-1;;;;;102100:32:0;;;:66;;-1:-1:-1;102136:16:0;;;;-1:-1:-1;;;;;102136:30:0;;102100:66;102096:92;;;102175:13;;;;;;;;;;;;;;102096:92;102220:37;81385:10;102220:15;:37;:::i;:::-;102202:6;:15;;;:55;102198:86;;;102266:18;;;;;;;;;;;;;;102198:86;81499:11;102325:8;:16;;;:23;:45;102321:81;;;102379:23;;;;;;;;;;;;;;102321:81;102416:18;;;;:23;;;;:63;;-1:-1:-1;102443:16:0;;;;-1:-1:-1;;;;;102443:36:0;76322:42;102443:36;102416:63;102412:124;;;102502:23;;;;;;;;;;;;;;102412:124;102640:1;102619:18;:22;:70;;;;102673:6;:15;;;102645:18;:44;102619:70;102615:136;;;102712:28;;;;;;;;;;;;;;98345:1185;98425:19;98460:25;-1:-1:-1;;;;;98460:25:0;;;98456:1068;;98690:9;98680:6;:19;98676:51;;98708:19;;;;;;;;;;;;;;98676:51;-1:-1:-1;98755:9:0;98456:1068;;;98995:9;:14;98991:46;;99018:19;;;;;;;;;;;;;;98991:46;99142:5;-1:-1:-1;;;;;99142:17:0;;99163:1;99142:22;99138:53;;99173:18;;;;;;;;;;;;;;99138:53;99219:38;;;;;99251:4;99219:38;;;2867:74:1;-1:-1:-1;;;;;99219:23:0;;;;;2840:18:1;;99219:38:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;99205:52;-1:-1:-1;99271:65:0;-1:-1:-1;;;;;99271:30:0;;99302:10;99322:4;99329:6;99271:30;:65::i;:::-;99461:38;;;;;99493:4;99461:38;;;2867:74:1;99502:11:0;;-1:-1:-1;;;;;99461:23:0;;;;;2840:18:1;;99461:38:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;:52;;;;:::i;52503:1038::-;52773:22;;52809:20;;;;;52843:21;;;;;52595:12;52878:22;;;;52914:20;;;;52948:18;;;;52980:21;;;;52722:289;;29378:16:1;52722:289:0;;;29362:102:1;;;;29483:66;29586:3;29582:16;;;29578:25;;29565:11;;;29558:46;29637:16;;;;29633:25;;;29620:11;;;29613:46;29678:66;29778:15;;;29774:24;;29760:12;;;29753:46;29833:15;;29829:24;;29815:12;;;29808:46;29888:15;;;29884:24;;29870:12;;;29863:46;29943:15;;;29939:24;;;29925:12;;;29918:46;29980:12;;;29973:28;;;;52697:22:0;;30017:13:1;;52722:289:0;;;-1:-1:-1;;52722:289:0;;;;;;;;;;53081:19;;;;53114:24;;;;53259:17;;;;53290:14;;;;53360:27;;;;53401;;;;53476:18;;;;53508:16;;;;52722:289;;-1:-1:-1;53028:506:0;;52722:289;;53508:16;52722:289;53028:506;;:::i;:::-;;;;;;;;;;;;;53021:513;;;52503:1038;;;:::o;33618:115::-;33681:7;33707:19;33715:3;29057:18;;28975:107;69887:197;69386:4;69409:12;;;;;;;;;;;-1:-1:-1;;;;;69409:29:0;;;;;;;;;;;;69970:108;;70020:47;;;;;-1:-1:-1;;;;;20205:55:1;;70020:47:0;;;20187:74:1;20277:18;;;20270:34;;;20160:18;;70020:47:0;20013:297:1;64893:629:0;65312:23;65338:33;-1:-1:-1;;;;;65338:27:0;;65366:4;65338:27;:33::i;:::-;65312:59;;65385:10;:17;65406:1;65385:22;;:57;;;;;65423:10;65412:30;;;;;;;;;;;;:::i;:::-;65411:31;65385:57;65381:135;;;65465:40;;;;;-1:-1:-1;;;;;2885:55:1;;65465:40:0;;;2867:74:1;2840:18;;65465:40:0;2721:226:1;72634:316:0;72711:4;69409:12;;;;;;;;;;;-1:-1:-1;;;;;69409:29:0;;;;;;;;;;;;72727:217;;72770:6;:12;;;;;;;;;;;-1:-1:-1;;;;;72770:29:0;;;;;;;;;:36;;;;72802:4;72770:36;;;72852:12;23372:10;;23293:96;72852:12;-1:-1:-1;;;;;72825:40:0;72843:7;-1:-1:-1;;;;;72825:40:0;72837:4;72825:40;;;;;;;;;;-1:-1:-1;72886:4:0;72879:11;;72727:217;-1:-1:-1;72928:5:0;72921:12;;32817:150;32887:4;32910:50;32915:3;-1:-1:-1;;;;;32935:23:0;;32910:4;:50::i;73185:317::-;73263:4;69409:12;;;;;;;;;;;-1:-1:-1;;;;;69409:29:0;;;;;;;;;;;;73279:217;;;73353:5;73321:12;;;;;;;;;;;-1:-1:-1;;;;;73321:29:0;;;;;;;;;;:37;;;;;;73377:40;23372:10;;73321:12;;73377:40;;73353:5;73377:40;-1:-1:-1;73438:4:0;73431:11;;33135:156;33208:4;33231:53;33239:3;-1:-1:-1;;;;;33259:23:0;;33231:7;:53::i;29424:118::-;29491:7;29517:3;:11;;29529:5;29517:18;;;;;;;;:::i;:::-;;;;;;;;;29510:25;;29424:118;;;;:::o;19553:392::-;19652:12;19704:5;19680:21;:29;19676:108;;;19732:41;;;;;19767:4;19732:41;;;2867:74:1;2840:18;;19732:41:0;2721:226:1;19676:108:0;19794:12;19808:23;19835:6;-1:-1:-1;;;;;19835:11:0;19854:5;19861:4;19835:31;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;19793:73;;;;19883:55;19910:6;19918:7;19927:10;19883:26;:55::i;:::-;19876:62;19553:392;-1:-1:-1;;;;;;19553:392:0:o;19078:151::-;19153:12;19184:38;19206:6;19214:4;19220:1;19184:21;:38::i;26742:406::-;26805:4;28861:21;;;:14;;;:21;;;;;;26821:321;;-1:-1:-1;26863:23:0;;;;;;;;:11;:23;;;;;;;;;;;;;27045:18;;27021:21;;;:14;;;:21;;;;;;:42;;;;27077:11;;27316:1368;27382:4;27511:21;;;:14;;;:21;;;;;;27547:13;;27543:1135;;27914:18;27935:12;27946:1;27935:8;:12;:::i;:::-;27981:18;;27914:33;;-1:-1:-1;27961:17:0;;27981:22;;28002:1;;27981:22;:::i;:::-;27961:42;;28036:9;28022:10;:23;28018:378;;28065:17;28085:3;:11;;28097:9;28085:22;;;;;;;;:::i;:::-;;;;;;;;;28065:42;;28232:9;28206:3;:11;;28218:10;28206:23;;;;;;;;:::i;:::-;;;;;;;;;;;;:35;;;;28345:25;;;:14;;;:25;;;;;:36;;;28018:378;28474:17;;:3;;:17;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;28577:3;:14;;:21;28592:5;28577:21;;;;;;;;;;;28570:28;;;28620:4;28613:11;;;;;;;27543:1135;28662:5;28655:12;;;;;20998:582;21142:12;21171:7;21166:408;;21194:19;21202:10;21194:7;:19::i;:::-;21166:408;;;21418:17;;:22;:49;;;;-1:-1:-1;;;;;;21444:18:0;;;:23;21418:49;21414:119;;;21494:24;;;;;-1:-1:-1;;;;;2885:55:1;;21494:24:0;;;2867:74:1;2840:18;;21494:24:0;2721:226:1;21414:119:0;-1:-1:-1;21553:10:0;21546:17;;22116:516;22247:17;;:21;22243:383;;22475:10;22469:17;22531:15;22518:10;22514:2;22510:19;22503:44;22243:383;22598:17;;;;;;;;;;;;;;14:332:1;72:6;125:2;113:9;104:7;100:23;96:32;93:52;;;141:1;138;131:12;93:52;180:9;167:23;230:66;223:5;219:78;212:5;209:89;199:117;;312:1;309;302:12;821:180;880:6;933:2;921:9;912:7;908:23;904:32;901:52;;;949:1;946;939:12;901:52;-1:-1:-1;972:23:1;;821:180;-1:-1:-1;821:180:1:o;1006:184::-;1058:77;1055:1;1048:88;1155:4;1152:1;1145:15;1179:4;1176:1;1169:15;1195:297;1279:1;1272:5;1269:12;1259:200;;1315:77;1312:1;1305:88;1416:4;1413:1;1406:15;1444:4;1441:1;1434:15;1259:200;1468:18;;1195:297::o;1497:214::-;1646:2;1631:18;;1658:47;1635:9;1687:6;1658:47;:::i;1716:154::-;-1:-1:-1;;;;;1795:5:1;1791:54;1784:5;1781:65;1771:93;;1860:1;1857;1850:12;1875:134;1943:20;;1972:31;1943:20;1972:31;:::i;:::-;1875:134;;;:::o;2014:388::-;2082:6;2090;2143:2;2131:9;2122:7;2118:23;2114:32;2111:52;;;2159:1;2156;2149:12;2111:52;2198:9;2185:23;2217:31;2242:5;2217:31;:::i;:::-;2267:5;-1:-1:-1;2324:2:1;2309:18;;2296:32;2337:33;2296:32;2337:33;:::i;:::-;2389:7;2379:17;;;2014:388;;;;;:::o;2952:383::-;3029:6;3037;3045;3098:2;3086:9;3077:7;3073:23;3069:32;3066:52;;;3114:1;3111;3104:12;3066:52;3150:9;3137:23;3127:33;;3207:2;3196:9;3192:18;3179:32;3169:42;;3261:2;3250:9;3246:18;3233:32;3274:31;3299:5;3274:31;:::i;:::-;3324:5;3314:15;;;2952:383;;;;;:::o;3525:247::-;3584:6;3637:2;3625:9;3616:7;3612:23;3608:32;3605:52;;;3653:1;3650;3643:12;3605:52;3692:9;3679:23;3711:31;3736:5;3711:31;:::i;3777:315::-;3845:6;3853;3906:2;3894:9;3885:7;3881:23;3877:32;3874:52;;;3922:1;3919;3912:12;3874:52;3958:9;3945:23;3935:33;;4018:2;4007:9;4003:18;3990:32;4031:31;4056:5;4031:31;:::i;4097:118::-;4183:5;4176:13;4169:21;4162:5;4159:32;4149:60;;4205:1;4202;4195:12;4220:128;4285:20;;4314:28;4285:20;4314:28;:::i;4353:761::-;4456:6;4464;4472;4525:2;4513:9;4504:7;4500:23;4496:32;4493:52;;;4541:1;4538;4531:12;4493:52;4581:9;4568:23;4610:18;4651:2;4643:6;4640:14;4637:34;;;4667:1;4664;4657:12;4637:34;4705:6;4694:9;4690:22;4680:32;;4750:7;4743:4;4739:2;4735:13;4731:27;4721:55;;4772:1;4769;4762:12;4721:55;4812:2;4799:16;4838:2;4830:6;4827:14;4824:34;;;4854:1;4851;4844:12;4824:34;4909:7;4902:4;4892:6;4889:1;4885:14;4881:2;4877:23;4873:34;4870:47;4867:67;;;4930:1;4927;4920:12;4867:67;4961:4;4953:13;;;;-1:-1:-1;4985:6:1;-1:-1:-1;;5026:20:1;;5013:34;5056:28;5013:34;5056:28;:::i;5119:250::-;5204:1;5214:113;5228:6;5225:1;5222:13;5214:113;;;5304:11;;;5298:18;5285:11;;;5278:39;5250:2;5243:10;5214:113;;;-1:-1:-1;;5361:1:1;5343:16;;5336:27;5119:250::o;5374:329::-;5415:3;5453:5;5447:12;5480:6;5475:3;5468:19;5496:76;5565:6;5558:4;5553:3;5549:14;5542:4;5535:5;5531:16;5496:76;:::i;:::-;5617:2;5605:15;-1:-1:-1;;5601:88:1;5592:98;;;;5692:4;5588:109;;5374:329;-1:-1:-1;;5374:329:1:o;5708:1097::-;5896:4;5925:2;5965;5954:9;5950:18;5995:2;5984:9;5977:21;6018:6;6053;6047:13;6084:6;6076;6069:22;6110:2;6100:12;;6143:2;6132:9;6128:18;6121:25;;6205:2;6195:6;6192:1;6188:14;6177:9;6173:30;6169:39;6243:2;6235:6;6231:15;6264:1;6274:502;6288:6;6285:1;6282:13;6274:502;;;6353:22;;;6377:66;6349:95;6337:108;;6468:13;;6523:9;;6516:17;6509:25;6494:41;;6574:11;;6568:18;6606:15;;;6599:27;;;6649:47;6680:15;;;6568:18;6649:47;:::i;:::-;6754:12;;;;6639:57;-1:-1:-1;;6719:15:1;;;;6310:1;6303:9;6274:502;;;-1:-1:-1;6793:6:1;;5708:1097;-1:-1:-1;;;;;;;;5708:1097:1:o;6810:347::-;6861:8;6871:6;6925:3;6918:4;6910:6;6906:17;6902:27;6892:55;;6943:1;6940;6933:12;6892:55;-1:-1:-1;6966:20:1;;7009:18;6998:30;;6995:50;;;7041:1;7038;7031:12;6995:50;7078:4;7070:6;7066:17;7054:29;;7130:3;7123:4;7114:6;7106;7102:19;7098:30;7095:39;7092:59;;;7147:1;7144;7137:12;7092:59;6810:347;;;;;:::o;7162:409::-;7232:6;7240;7293:2;7281:9;7272:7;7268:23;7264:32;7261:52;;;7309:1;7306;7299:12;7261:52;7349:9;7336:23;7382:18;7374:6;7371:30;7368:50;;;7414:1;7411;7404:12;7368:50;7453:58;7503:7;7494:6;7483:9;7479:22;7453:58;:::i;:::-;7530:8;;7427:84;;-1:-1:-1;7162:409:1;-1:-1:-1;;;;7162:409:1:o;7576:544::-;7655:6;7663;7671;7724:2;7712:9;7703:7;7699:23;7695:32;7692:52;;;7740:1;7737;7730:12;7692:52;7780:9;7767:23;7813:18;7805:6;7802:30;7799:50;;;7845:1;7842;7835:12;7799:50;7884:58;7934:7;7925:6;7914:9;7910:22;7884:58;:::i;:::-;7961:8;;-1:-1:-1;7858:84:1;-1:-1:-1;;8046:2:1;8031:18;;8018:32;8059:31;8018:32;8059:31;:::i;8125:184::-;8177:77;8174:1;8167:88;8274:4;8271:1;8264:15;8298:4;8295:1;8288:15;8314:255;8386:2;8380:9;8428:6;8416:19;;8465:18;8450:34;;8486:22;;;8447:62;8444:88;;;8512:18;;:::i;:::-;8548:2;8541:22;8314:255;:::o;8574:253::-;8646:2;8640:9;8688:4;8676:17;;8723:18;8708:34;;8744:22;;;8705:62;8702:88;;;8770:18;;:::i;8832:255::-;8904:2;8898:9;8946:6;8934:19;;8983:18;8968:34;;9004:22;;;8965:62;8962:88;;;9030:18;;:::i;9092:252::-;9164:2;9158:9;9206:3;9194:16;;9240:18;9225:34;;9261:22;;;9222:62;9219:88;;;9287:18;;:::i;9349:334::-;9420:2;9414:9;9476:2;9466:13;;-1:-1:-1;;9462:86:1;9450:99;;9579:18;9564:34;;9600:22;;;9561:62;9558:88;;;9626:18;;:::i;:::-;9662:2;9655:22;9349:334;;-1:-1:-1;9349:334:1:o;9688:121::-;9773:10;9766:5;9762:22;9755:5;9752:33;9742:61;;9799:1;9796;9789:12;9814:132;9881:20;;9910:30;9881:20;9910:30;:::i;9951:806::-;10010:5;10058:6;10046:9;10041:3;10037:19;10033:32;10030:52;;;10078:1;10075;10068:12;10030:52;10100:22;;:::i;:::-;10091:31;;10145:28;10163:9;10145:28;:::i;:::-;10138:5;10131:43;10206:38;10240:2;10229:9;10225:18;10206:38;:::i;:::-;10201:2;10194:5;10190:14;10183:62;10277:38;10311:2;10300:9;10296:18;10277:38;:::i;:::-;10272:2;10265:5;10261:14;10254:62;10348:38;10382:2;10371:9;10367:18;10348:38;:::i;:::-;10343:2;10336:5;10332:14;10325:62;10420:39;10454:3;10443:9;10439:19;10420:39;:::i;:::-;10414:3;10407:5;10403:15;10396:64;10521:3;10510:9;10506:19;10493:33;10487:3;10480:5;10476:15;10469:58;10588:3;10577:9;10573:19;10560:33;10554:3;10547:5;10543:15;10536:58;10627:36;10658:3;10647:9;10643:19;10627:36;:::i;:::-;10621:3;10614:5;10610:15;10603:61;10683:3;10746:2;10735:9;10731:18;10718:32;10713:2;10706:5;10702:14;10695:56;;9951:806;;;;:::o;10762:237::-;10850:6;10903:3;10891:9;10882:7;10878:23;10874:33;10871:53;;;10920:1;10917;10910:12;10871:53;10943:50;10985:7;10974:9;10943:50;:::i;11103:1865::-;11306:2;11295:9;11288:21;11318:52;11366:2;11355:9;11351:18;11342:6;11336:13;11080:10;11069:22;11057:35;;11004:94;11318:52;11269:4;11417:2;11409:6;11405:15;11399:22;11430:51;11477:2;11466:9;11462:18;11448:12;11080:10;11069:22;11057:35;;11004:94;11430:51;-1:-1:-1;11530:2:1;11518:15;;11512:22;-1:-1:-1;;;;;2655:54:1;;11593:2;11578:18;;2643:67;-1:-1:-1;11646:2:1;11634:15;;11628:22;-1:-1:-1;;;;;2655:54:1;;11709:3;11694:19;;2643:67;-1:-1:-1;11763:3:1;11751:16;;11745:23;-1:-1:-1;;;;;2655:54:1;;11827:3;11812:19;;2643:67;-1:-1:-1;11881:3:1;11869:16;;11863:23;-1:-1:-1;;;;;2655:54:1;;11945:3;11930:19;;2643:67;-1:-1:-1;12005:3:1;11993:16;;11987:23;11981:3;11966:19;;;11959:52;;;;12036:16;;12030:23;12072:3;12091:18;;;12084:30;;;;12139:15;;12133:22;12174:3;12193:18;;;12186:30;;;;12241:15;;12235:22;12276:3;12295:18;;;12288:30;;;;12343:15;;12337:22;12378:3;12397:18;;;12390:30;;;;12457:15;;12451:22;12492:3;12504:54;12539:18;;;12451:22;-1:-1:-1;;;;;2655:54:1;2643:67;;2589:127;12504:54;12584:15;;12578:22;12620:3;12639:19;;;12632:32;;;;12690:16;;12684:23;12727:3;12746:19;;;12739:32;;;;12808:16;;12802:23;12845:6;12867:19;;;12860:32;12802:23;-1:-1:-1;12909:53:1;12957:3;12942:19;;12802:23;12909:53;:::i;:::-;12901:61;11103:1865;-1:-1:-1;;;;11103:1865:1:o;12973:513::-;13202:3;13187:19;;13215:47;13191:9;13244:6;13215:47;:::i;:::-;13310:10;13302:6;13298:23;13293:2;13282:9;13278:18;13271:51;13370:16;13362:6;13358:29;13353:2;13342:9;13338:18;13331:57;-1:-1:-1;;;;;13428:6:1;13424:55;13419:2;13408:9;13404:18;13397:83;12973:513;;;;;;;:::o;13491:477::-;13570:6;13578;13586;13639:2;13627:9;13618:7;13614:23;13610:32;13607:52;;;13655:1;13652;13645:12;13607:52;13695:9;13682:23;13728:18;13720:6;13717:30;13714:50;;;13760:1;13757;13750:12;13714:50;13799:58;13849:7;13840:6;13829:9;13825:22;13799:58;:::i;:::-;13876:8;;13773:84;;-1:-1:-1;13958:2:1;13943:18;;;;13930:32;;13491:477;-1:-1:-1;;;;13491:477:1:o;13973:248::-;14041:6;14049;14102:2;14090:9;14081:7;14077:23;14073:32;14070:52;;;14118:1;14115;14108:12;14070:52;-1:-1:-1;;14141:23:1;;;14211:2;14196:18;;;14183:32;;-1:-1:-1;13973:248:1:o;14559:1373::-;14790:13;;11080:10;11069:22;11057:35;;14759:3;14744:19;;14862:4;14854:6;14850:17;14844:24;14877:53;14924:4;14913:9;14909:20;14895:12;11080:10;11069:22;11057:35;;11004:94;14877:53;;14979:4;14971:6;14967:17;14961:24;14994:56;15044:4;15033:9;15029:20;15013:14;-1:-1:-1;;;;;2655:54:1;2643:67;;2589:127;14994:56;;15099:4;15091:6;15087:17;15081:24;15114:56;15164:4;15153:9;15149:20;15133:14;-1:-1:-1;;;;;2655:54:1;2643:67;;2589:127;15114:56;;15219:4;15211:6;15207:17;15201:24;15234:56;15284:4;15273:9;15269:20;15253:14;-1:-1:-1;;;;;2655:54:1;2643:67;;2589:127;15234:56;;15339:4;15331:6;15327:17;15321:24;15354:56;15404:4;15393:9;15389:20;15373:14;-1:-1:-1;;;;;2655:54:1;2643:67;;2589:127;15354:56;;15466:4;15458:6;15454:17;15448:24;15441:4;15430:9;15426:20;15419:54;15529:4;15521:6;15517:17;15511:24;15504:4;15493:9;15489:20;15482:54;15555:6;15615:2;15607:6;15603:15;15597:22;15592:2;15581:9;15577:18;15570:50;;15639:6;15694:2;15686:6;15682:15;15676:22;15707:51;15754:2;15743:9;15739:18;15723:14;421:13;414:21;402:34;;351:91;15707:51;-1:-1:-1;;15777:6:1;15825:15;;;15819:22;15799:18;;;15792:50;15861:6;15909:15;;;15903:22;15883:18;;;;15876:50;;;;14559:1373;:::o;15937:245::-;15985:4;16018:18;16010:6;16007:30;16004:56;;;16040:18;;:::i;:::-;-1:-1:-1;16097:2:1;16085:15;-1:-1:-1;;16081:88:1;16171:4;16077:99;;15937:245::o;16187:462::-;16229:5;16282:3;16275:4;16267:6;16263:17;16259:27;16249:55;;16300:1;16297;16290:12;16249:55;16336:6;16323:20;16367:48;16383:31;16411:2;16383:31;:::i;:::-;16367:48;:::i;:::-;16440:2;16431:7;16424:19;16486:3;16479:4;16474:2;16466:6;16462:15;16458:26;16455:35;16452:55;;;16503:1;16500;16493:12;16452:55;16568:2;16561:4;16553:6;16549:17;16542:4;16533:7;16529:18;16516:55;16616:1;16591:16;;;16609:4;16587:27;16580:38;;;;16595:7;16187:462;-1:-1:-1;;;16187:462:1:o;16654:1162::-;16783:6;16791;16844:3;16832:9;16823:7;16819:23;16815:33;16812:53;;;16861:1;16858;16851:12;16812:53;16884:50;16926:7;16915:9;16884:50;:::i;:::-;16874:60;;16985:3;16974:9;16970:19;16957:33;17009:18;17050:2;17042:6;17039:14;17036:34;;;17066:1;17063;17056:12;17036:34;17089:22;;;;17145:4;17127:16;;;17123:27;17120:47;;;17163:1;17160;17153:12;17120:47;17189:22;;:::i;:::-;17248:2;17235:16;17260:33;17285:7;17260:33;:::i;:::-;17302:22;;17377:2;17369:11;;;17356:25;17340:14;;;17333:49;17428:2;17420:11;;17407:25;17444:16;;;17441:36;;;17473:1;17470;17463:12;17441:36;17509:44;17545:7;17534:8;17530:2;17526:17;17509:44;:::i;:::-;17504:2;17497:5;17493:14;17486:68;;17607:2;17603;17599:11;17586:25;17581:2;17574:5;17570:14;17563:49;17658:3;17654:2;17650:12;17637:26;17688:2;17678:8;17675:16;17672:36;;;17704:1;17701;17694:12;17672:36;17741:44;17777:7;17766:8;17762:2;17758:17;17741:44;:::i;:::-;17735:3;17728:5;17724:15;17717:69;;17805:5;17795:15;;;;;16654:1162;;;;;:::o;18644:184::-;18696:77;18693:1;18686:88;18793:4;18790:1;18783:15;18817:4;18814:1;18807:15;18833:580;18910:4;18916:6;18976:11;18963:25;19066:66;19055:8;19039:14;19035:29;19031:102;19011:18;19007:127;18997:155;;19148:1;19145;19138:12;18997:155;19175:33;;19227:20;;;-1:-1:-1;19270:18:1;19259:30;;19256:50;;;19302:1;19299;19292:12;19256:50;19335:4;19323:17;;-1:-1:-1;19366:14:1;19362:27;;;19352:38;;19349:58;;;19403:1;19400;19393:12;19418:271;19601:6;19593;19588:3;19575:33;19557:3;19627:16;;19652:13;;;19627:16;19418:271;-1:-1:-1;19418:271:1:o;19694:184::-;19746:77;19743:1;19736:88;19843:4;19840:1;19833:15;19867:4;19864:1;19857:15;19883:125;19948:9;;;19969:10;;;19966:36;;;19982:18;;:::i;20949:325::-;21037:6;21032:3;21025:19;21089:6;21082:5;21075:4;21070:3;21066:14;21053:43;;21141:1;21134:4;21125:6;21120:3;21116:16;21112:27;21105:38;21007:3;21263:4;-1:-1:-1;;21188:2:1;21180:6;21176:15;21172:88;21167:3;21163:98;21159:109;21152:116;;20949:325;;;;:::o;21279:244::-;21436:2;21425:9;21418:21;21399:4;21456:61;21513:2;21502:9;21498:18;21490:6;21482;21456:61;:::i;21528:136::-;21606:13;;21628:30;21606:13;21628:30;:::i;21669:138::-;21748:13;;21770:31;21748:13;21770:31;:::i;21812:441::-;21865:5;21918:3;21911:4;21903:6;21899:17;21895:27;21885:55;;21936:1;21933;21926:12;21885:55;21965:6;21959:13;21996:48;22012:31;22040:2;22012:31;:::i;21996:48::-;22069:2;22060:7;22053:19;22115:3;22108:4;22103:2;22095:6;22091:15;22087:26;22084:35;22081:55;;;22132:1;22129;22122:12;22081:55;22145:77;22219:2;22212:4;22203:7;22199:18;22192:4;22184:6;22180:17;22145:77;:::i;22258:1672::-;22365:6;22418:2;22406:9;22397:7;22393:23;22389:32;22386:52;;;22434:1;22431;22424:12;22386:52;22467:9;22461:16;22496:18;22537:2;22529:6;22526:14;22523:34;;;22553:1;22550;22543:12;22523:34;22576:22;;;;22632:6;22614:16;;;22610:29;22607:49;;;22652:1;22649;22642:12;22607:49;22678:22;;:::i;:::-;22723:32;22752:2;22723:32;:::i;:::-;22716:5;22709:47;22788:41;22825:2;22821;22817:11;22788:41;:::i;:::-;22783:2;22776:5;22772:14;22765:65;22862:42;22900:2;22896;22892:11;22862:42;:::i;:::-;22857:2;22850:5;22846:14;22839:66;22937:42;22975:2;22971;22967:11;22937:42;:::i;:::-;22932:2;22925:5;22921:14;22914:66;23013:43;23051:3;23047:2;23043:12;23013:43;:::i;:::-;23007:3;23000:5;22996:15;22989:68;23090:43;23128:3;23124:2;23120:12;23090:43;:::i;:::-;23084:3;23073:15;;23066:68;23181:3;23173:12;;;23167:19;23150:15;;;23143:44;23234:3;23226:12;;;23220:19;23203:15;;;23196:44;23259:3;23300:11;;;23294:18;23278:14;;;23271:42;23332:3;23373:11;;;23367:18;23351:14;;;23344:42;23405:3;23446:11;;;23440:18;23424:14;;;23417:42;23478:3;23513:42;23543:11;;;23513:42;:::i;:::-;23497:14;;;23490:66;23575:3;23616:11;;;23610:18;23594:14;;;23587:42;23648:3;23689:11;;;23683:18;23667:14;;;23660:42;23721:3;23755:11;;;23749:18;23779:16;;;23776:36;;;23808:1;23805;23798:12;23776:36;23844:55;23891:7;23880:8;23876:2;23872:17;23844:55;:::i;:::-;23828:14;;;23821:79;;;;-1:-1:-1;23832:5:1;22258:1672;-1:-1:-1;;;;;22258:1672:1:o;23935:1135::-;24027:6;24080:3;24068:9;24059:7;24055:23;24051:33;24048:53;;;24097:1;24094;24087:12;24048:53;24123:22;;:::i;:::-;24168:28;24186:9;24168:28;:::i;:::-;24161:5;24154:43;24229:37;24262:2;24251:9;24247:18;24229:37;:::i;:::-;24224:2;24217:5;24213:14;24206:61;24299:38;24333:2;24322:9;24318:18;24299:38;:::i;:::-;24294:2;24287:5;24283:14;24276:62;24370:38;24404:2;24393:9;24389:18;24370:38;:::i;:::-;24365:2;24358:5;24354:14;24347:62;24442:39;24476:3;24465:9;24461:19;24442:39;:::i;:::-;24436:3;24429:5;24425:15;24418:64;24515:39;24549:3;24538:9;24534:19;24515:39;:::i;:::-;24509:3;24502:5;24498:15;24491:64;24616:3;24605:9;24601:19;24588:33;24582:3;24575:5;24571:15;24564:58;24683:3;24672:9;24668:19;24655:33;24649:3;24642:5;24638:15;24631:58;24708:3;24771:2;24760:9;24756:18;24743:32;24738:2;24731:5;24727:14;24720:56;;24795:3;24830:35;24861:2;24850:9;24846:18;24830:35;:::i;:::-;24814:14;;;24807:59;24885:3;24933:18;;;24920:32;24904:14;;;24897:56;24972:3;25020:18;;;25007:32;24991:14;;;24984:56;;;;-1:-1:-1;24818:5:1;23935:1135;-1:-1:-1;23935:1135:1:o;25328:216::-;25392:9;;;25420:11;;;25367:3;25450:9;;25478:10;;25474:19;;25503:10;;25495:19;;25471:44;25468:70;;;25518:18;;:::i;:::-;25468:70;;25328:216;;;;:::o;25549:168::-;25622:9;;;25653;;25670:15;;;25664:22;;25650:37;25640:71;;25691:18;;:::i;25722:274::-;25762:1;25788;25778:189;;25823:77;25820:1;25813:88;25924:4;25921:1;25914:15;25952:4;25949:1;25942:15;25778:189;-1:-1:-1;25981:9:1;;25722:274::o;26001:128::-;26068:9;;;26089:11;;;26086:37;;;26103:18;;:::i;26134:195::-;26173:3;26204:66;26197:5;26194:77;26191:103;;26274:18;;:::i;:::-;-1:-1:-1;26321:1:1;26310:13;;26134:195::o;26334:752::-;26641:3;26630:9;26623:22;26604:4;26662:45;26702:3;26691:9;26687:19;26679:6;26662:45;:::i;:::-;26755:10;26743:23;;;;26738:2;26723:18;;26716:51;-1:-1:-1;;;;;;26864:15:1;;;26859:2;26844:18;;26837:43;26916:15;;;;26911:2;26896:18;;26889:43;26963:3;26948:19;;26941:35;;;;27007:3;26992:19;;26985:35;27064:14;;27057:22;27051:3;27036:19;;;27029:51;26654:53;26334:752;-1:-1:-1;26334:752:1:o;27091:217::-;27238:2;27227:9;27220:21;27201:4;27258:44;27298:2;27287:9;27283:18;27275:6;27258:44;:::i;27716:331::-;27821:9;27832;27874:8;27862:10;27859:24;27856:44;;;27896:1;27893;27886:12;27856:44;27925:6;27915:8;27912:20;27909:40;;;27945:1;27942;27935:12;27909:40;-1:-1:-1;;27971:23:1;;;28016:25;;;;;-1:-1:-1;27716:331:1:o;28052:435::-;-1:-1:-1;;;;;28269:6:1;28265:55;28254:9;28247:74;28357:6;28352:2;28341:9;28337:18;28330:34;28400:2;28395;28384:9;28380:18;28373:30;28228:4;28420:61;28477:2;28466:9;28462:18;28454:6;28446;28420:61;:::i;28492:357::-;28610:12;;28657:4;28646:16;;;28640:23;;28610:12;28675:16;;28672:171;;;28765:66;28755:6;28749:4;28745:17;28742:1;28738:25;28734:98;28727:5;28723:110;28714:119;;28672:171;;28492:357;;;:::o;28854:184::-;28924:6;28977:2;28965:9;28956:7;28952:23;28948:32;28945:52;;;28993:1;28990;28983:12;28945:52;-1:-1:-1;29016:16:1;;28854:184;-1:-1:-1;28854:184:1:o;30041:1059::-;30412:3;30450:6;30444:13;30466:66;30525:6;30520:3;30513:4;30505:6;30501:17;30466:66;:::i;:::-;30563:6;30558:3;30554:16;30541:29;;30593:6;30586:5;30579:21;30634:6;30627:4;30620:5;30616:16;30609:32;30673:6;30668:2;30661:5;30657:14;30650:30;30712:6;30707:2;30700:5;30696:14;30689:30;30773:66;30764:6;30760:2;30756:15;30752:88;30746:3;30739:5;30735:15;30728:113;30874:6;30868:3;30861:5;30857:15;30850:31;30914:6;30908:3;30901:5;30897:15;30890:31;30952:6;30946:13;30968:80;31039:8;31033:3;31026:5;31022:15;31015:4;31007:6;31003:17;30968:80;:::i;:::-;31068:20;31090:3;31064:30;;30041:1059;-1:-1:-1;;;;;;;;;;;30041:1059:1:o;31407:245::-;31474:6;31527:2;31515:9;31506:7;31502:23;31498:32;31495:52;;;31543:1;31540;31533:12;31495:52;31575:9;31569:16;31594:28;31616:5;31594:28;:::i;31657:287::-;31786:3;31824:6;31818:13;31840:66;31899:6;31894:3;31887:4;31879:6;31875:17;31840:66;:::i;:::-;31922:16;;;;;31657:287;-1:-1:-1;;31657:287:1:o;31949:184::-;32001:77;31998:1;31991:88;32098:4;32095:1;32088:15;32122:4;32119:1;32112:15","abiDefinition":[{"inputs":[{"internalType":"address","name":"_owner","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AccessControlBadConfirmation","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"bytes32","name":"neededRole","type":"bytes32"}],"name":"AccessControlUnauthorizedAccount","type":"error"},{"inputs":[{"internalType":"address","name":"target","type":"address"}],"name":"AddressEmptyCode","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"AddressInsufficientBalance","type":"error"},{"inputs":[],"name":"AmountIncorrect","type":"error"},{"inputs":[],"name":"BridgeTransactionV2__InvalidEncodedTx","type":"error"},{"inputs":[{"internalType":"uint16","name":"version","type":"uint16"}],"name":"BridgeTransactionV2__UnsupportedVersion","type":"error"},{"inputs":[],"name":"CancelDelayBelowMin","type":"error"},{"inputs":[],"name":"ChainIncorrect","type":"error"},{"inputs":[],"name":"DeadlineExceeded","type":"error"},{"inputs":[],"name":"DeadlineNotExceeded","type":"error"},{"inputs":[],"name":"DeadlineTooShort","type":"error"},{"inputs":[],"name":"DisputePeriodNotPassed","type":"error"},{"inputs":[],"name":"DisputePeriodPassed","type":"error"},{"inputs":[],"name":"ExclusivityParamsIncorrect","type":"error"},{"inputs":[],"name":"ExclusivityPeriodNotPassed","type":"error"},{"inputs":[],"name":"FailedInnerCall","type":"error"},{"inputs":[],"name":"FeeRateAboveMax","type":"error"},{"inputs":[],"name":"MsgValueIncorrect","type":"error"},{"inputs":[],"name":"MulticallTarget__UndeterminedRevert","type":"error"},{"inputs":[],"name":"RecipientIncorrectReturnValue","type":"error"},{"inputs":[],"name":"RecipientNoReturnValue","type":"error"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"SafeERC20FailedOperation","type":"error"},{"inputs":[],"name":"SenderIncorrect","type":"error"},{"inputs":[],"name":"StatusIncorrect","type":"error"},{"inputs":[],"name":"TokenNotContract","type":"error"},{"inputs":[],"name":"TransactionRelayed","type":"error"},{"inputs":[],"name":"ZapDataLengthAboveMax","type":"error"},{"inputs":[],"name":"ZapNativeNotSupported","type":"error"},{"inputs":[],"name":"ZeroAddress","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"relayer","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"BridgeDepositClaimed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"BridgeDepositRefunded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"relayer","type":"address"}],"name":"BridgeProofDisputed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"relayer","type":"address"},{"indexed":false,"internalType":"bytes32","name":"transactionHash","type":"bytes32"}],"name":"BridgeProofProvided","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":false,"internalType":"bytes","name":"quoteId","type":"bytes"}],"name":"BridgeQuoteDetails","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"relayer","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint32","name":"originChainId","type":"uint32"},{"indexed":false,"internalType":"address","name":"originToken","type":"address"},{"indexed":false,"internalType":"address","name":"destToken","type":"address"},{"indexed":false,"internalType":"uint256","name":"originAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"destAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"chainGasAmount","type":"uint256"}],"name":"BridgeRelayed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"bytes","name":"request","type":"bytes"},{"indexed":false,"internalType":"uint32","name":"destChainId","type":"uint32"},{"indexed":false,"internalType":"address","name":"originToken","type":"address"},{"indexed":false,"internalType":"address","name":"destToken","type":"address"},{"indexed":false,"internalType":"uint256","name":"originAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"destAmount","type":"uint256"},{"indexed":false,"internalType":"bool","name":"sendChainGas","type":"bool"}],"name":"BridgeRequested","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldCancelDelay","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newCancelDelay","type":"uint256"}],"name":"CancelDelayUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldFeeRate","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newFeeRate","type":"uint256"}],"name":"FeeRateUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"address","name":"recipient","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"FeesSwept","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"previousAdminRole","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"newAdminRole","type":"bytes32"}],"name":"RoleAdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleRevoked","type":"event"},{"inputs":[],"name":"CANCELER_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"DEFAULT_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"DEFAULT_CANCEL_DELAY","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"DISPUTE_PERIOD","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"FEE_BPS","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"FEE_RATE_MAX","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"GOVERNOR_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"GUARD_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_ZAP_DATA_LENGTH","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MIN_CANCEL_DELAY","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MIN_DEADLINE_PERIOD","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"NATIVE_GAS_TOKEN","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"PROVER_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"QUOTER_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"uint32","name":"dstChainId","type":"uint32"},{"internalType":"address","name":"sender","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"address","name":"originToken","type":"address"},{"internalType":"address","name":"destToken","type":"address"},{"internalType":"uint256","name":"originAmount","type":"uint256"},{"internalType":"uint256","name":"destAmount","type":"uint256"},{"internalType":"bool","name":"sendChainGas","type":"bool"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"internalType":"struct IFastBridge.BridgeParams","name":"params","type":"tuple"}],"name":"bridge","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"uint32","name":"dstChainId","type":"uint32"},{"internalType":"address","name":"sender","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"address","name":"originToken","type":"address"},{"internalType":"address","name":"destToken","type":"address"},{"internalType":"uint256","name":"originAmount","type":"uint256"},{"internalType":"uint256","name":"destAmount","type":"uint256"},{"internalType":"bool","name":"sendChainGas","type":"bool"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"internalType":"struct IFastBridge.BridgeParams","name":"params","type":"tuple"},{"components":[{"internalType":"address","name":"quoteRelayer","type":"address"},{"internalType":"int256","name":"quoteExclusivitySeconds","type":"int256"},{"internalType":"bytes","name":"quoteId","type":"bytes"},{"internalType":"uint256","name":"zapNative","type":"uint256"},{"internalType":"bytes","name":"zapData","type":"bytes"}],"internalType":"struct IFastBridgeV2.BridgeParamsV2","name":"paramsV2","type":"tuple"}],"name":"bridge","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"transactionId","type":"bytes32"}],"name":"bridgeProofs","outputs":[{"internalType":"uint96","name":"timestamp","type":"uint96"},{"internalType":"address","name":"relayer","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"bridgeRelayDetails","outputs":[{"internalType":"uint48","name":"blockNumber","type":"uint48"},{"internalType":"uint48","name":"blockTimestamp","type":"uint48"},{"internalType":"address","name":"relayer","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"transactionId","type":"bytes32"}],"name":"bridgeRelays","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"transactionId","type":"bytes32"}],"name":"bridgeStatuses","outputs":[{"internalType":"enum IFastBridgeV2.BridgeStatus","name":"status","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"bridgeTxDetails","outputs":[{"internalType":"enum IFastBridgeV2.BridgeStatus","name":"status","type":"uint8"},{"internalType":"uint32","name":"destChainId","type":"uint32"},{"internalType":"uint56","name":"proofBlockTimestamp","type":"uint56"},{"internalType":"address","name":"proofRelayer","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"internalType":"address","name":"relayer","type":"address"}],"name":"canClaim","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"}],"name":"cancel","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"cancelDelay","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"chainGasAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"},{"internalType":"address","name":"to","type":"address"}],"name":"claim","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"}],"name":"claim","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"deployBlock","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"transactionId","type":"bytes32"}],"name":"dispute","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"}],"name":"getBridgeTransaction","outputs":[{"components":[{"internalType":"uint32","name":"originChainId","type":"uint32"},{"internalType":"uint32","name":"destChainId","type":"uint32"},{"internalType":"address","name":"originSender","type":"address"},{"internalType":"address","name":"destRecipient","type":"address"},{"internalType":"address","name":"originToken","type":"address"},{"internalType":"address","name":"destToken","type":"address"},{"internalType":"uint256","name":"originAmount","type":"uint256"},{"internalType":"uint256","name":"destAmount","type":"uint256"},{"internalType":"uint256","name":"originFeeAmount","type":"uint256"},{"internalType":"bool","name":"sendChainGas","type":"bool"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint256","name":"nonce","type":"uint256"}],"internalType":"struct IFastBridge.BridgeTransaction","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"}],"name":"getBridgeTransactionV2","outputs":[{"components":[{"internalType":"uint32","name":"originChainId","type":"uint32"},{"internalType":"uint32","name":"destChainId","type":"uint32"},{"internalType":"address","name":"originSender","type":"address"},{"internalType":"address","name":"destRecipient","type":"address"},{"internalType":"address","name":"originToken","type":"address"},{"internalType":"address","name":"destToken","type":"address"},{"internalType":"uint256","name":"originAmount","type":"uint256"},{"internalType":"uint256","name":"destAmount","type":"uint256"},{"internalType":"uint256","name":"originFeeAmount","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"address","name":"exclusivityRelayer","type":"address"},{"internalType":"uint256","name":"exclusivityEndTime","type":"uint256"},{"internalType":"uint256","name":"zapNative","type":"uint256"},{"internalType":"bytes","name":"zapData","type":"bytes"}],"internalType":"struct IFastBridgeV2.BridgeTransactionV2","name":"","type":"tuple"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleAdmin","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"uint256","name":"index","type":"uint256"}],"name":"getRoleMember","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleMemberCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"grantRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"hasRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes[]","name":"data","type":"bytes[]"},{"internalType":"bool","name":"ignoreReverts","type":"bool"}],"name":"multicallNoResults","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes[]","name":"data","type":"bytes[]"},{"internalType":"bool","name":"ignoreReverts","type":"bool"}],"name":"multicallWithResults","outputs":[{"components":[{"internalType":"bool","name":"success","type":"bool"},{"internalType":"bytes","name":"returnData","type":"bytes"}],"internalType":"struct IMulticallTarget.Result[]","name":"results","type":"tuple[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"nonce","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"protocolFeeRate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"protocolFees","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"internalType":"bytes32","name":"destTxHash","type":"bytes32"},{"internalType":"address","name":"relayer","type":"address"}],"name":"prove","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"},{"internalType":"bytes32","name":"destTxHash","type":"bytes32"}],"name":"prove","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"}],"name":"refund","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"}],"name":"relay","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"},{"internalType":"address","name":"relayer","type":"address"}],"name":"relay","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"callerConfirmation","type":"address"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"revokeRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"senderNonces","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"newCancelDelay","type":"uint256"}],"name":"setCancelDelay","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"newFeeRate","type":"uint256"}],"name":"setProtocolFeeRate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"address","name":"recipient","type":"address"}],"name":"sweepProtocolFees","outputs":[],"stateMutability":"nonpayable","type":"function"}],"userDoc":{"kind":"user","methods":{"CANCELER_ROLE()":{"notice":"Role identifier for Canceler's on-chain authentication in FastBridge."},"DEFAULT_CANCEL_DELAY()":{"notice":"Default cancel delay set during the contract deployment."},"DISPUTE_PERIOD()":{"notice":"Dispute period for relayed transactions"},"FEE_BPS()":{"notice":"Denominator for fee rates, represents 100%."},"FEE_RATE_MAX()":{"notice":"Maximum protocol fee rate: 1% on origin amount."},"GOVERNOR_ROLE()":{"notice":"Role identifier for Governor's on-chain administrative authority."},"GUARD_ROLE()":{"notice":"Role identifier for Guard's on-chain authentication in FastBridge."},"MAX_ZAP_DATA_LENGTH()":{"notice":"Maximum length of accepted zapData"},"MIN_CANCEL_DELAY()":{"notice":"Minimum cancel delay that can be set by the governor."},"MIN_DEADLINE_PERIOD()":{"notice":"Minimum deadline period to relay a requested bridge transaction"},"NATIVE_GAS_TOKEN()":{"notice":"Address reserved for native gas token (ETH on Ethereum and most L2s, AVAX on Avalanche, etc)"},"PROVER_ROLE()":{"notice":"Role identifier for Prover's on-chain authentication in FastBridge."},"QUOTER_ROLE()":{"notice":"Role identifier for Quoter API's off-chain authentication."},"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256))":{"notice":"Initiates bridge on origin chain to be relayed by off-chain relayer"},"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256),(address,int256,bytes,uint256,bytes))":{"notice":"Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability to provide temporary exclusivity fill rights for the quote relayer."},"bridgeProofs(bytes32)":{"notice":"Returns the timestamp and relayer of a bridge proof"},"bridgeRelayDetails(bytes32)":{"notice":"Relay details on destination chain"},"bridgeRelays(bytes32)":{"notice":"Checks if a transaction has been relayed"},"bridgeStatuses(bytes32)":{"notice":"Returns the status of a bridge transaction"},"bridgeTxDetails(bytes32)":{"notice":"Status of the bridge tx on origin chain"},"canClaim(bytes32,address)":{"notice":"Checks if the dispute period has passed so bridge deposit can be claimed"},"cancel(bytes)":{"notice":"Cancels an outstanding bridge transaction in case optimistic bridging failed and returns the full amount to the original sender."},"cancelDelay()":{"notice":"Delay for a transaction after which it could be permisionlessly cancelled"},"chainGasAmount()":{"notice":"This is deprecated and should not be used."},"claim(bytes)":{"notice":"Completes bridge transaction on origin chain by claiming originally deposited capital.Can only send funds to the relayer address on the proof."},"claim(bytes,address)":{"notice":"Completes bridge transaction on origin chain by claiming originally deposited capital"},"deployBlock()":{"notice":"the block the contract was deployed at"},"dispute(bytes32)":{"notice":"Disputes an outstanding proof in case relayer provided dest chain tx is invalid"},"getBridgeTransaction(bytes)":{"notice":"Decodes bridge request into a bridge transaction"},"getBridgeTransactionV2(bytes)":{"notice":"Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2"},"multicallNoResults(bytes[],bool)":{"notice":"Perform a batched call to this contract, preserving the msg.sender. The return data from each call is discarded."},"multicallWithResults(bytes[],bool)":{"notice":"Perform a batched call to this contract, preserving the msg.sender. The return data from each call is preserved."},"nonce()":{"notice":"This is deprecated and should not be used."},"protocolFeeRate()":{"notice":"Protocol fee rate taken on origin amount deposited in origin chain"},"protocolFees(address)":{"notice":"Protocol fee amounts accumulated"},"prove(bytes,bytes32)":{"notice":"Provides proof on origin side that relayer provided funds on destination side of bridge transaction"},"prove(bytes32,bytes32,address)":{"notice":"Provides proof on origin side that relayer provided funds on destination side of bridge transaction"},"refund(bytes)":{"notice":"Note: this function is deprecated and will be removed in a future version."},"relay(bytes)":{"notice":"Relays destination side of bridge transaction by off-chain relayer"},"relay(bytes,address)":{"notice":"Relays destination side of bridge transaction by off-chain relayer"},"senderNonces(address)":{"notice":"Unique bridge nonces tracked per originSender"},"setCancelDelay(uint256)":{"notice":"Allows the contract governor to set the cancel delay. The cancel delay is the time after the transaction deadline after which it can be permissionlessly cancelled, if it hasn't been proven by any of the Relayers."},"setProtocolFeeRate(uint256)":{"notice":"Allows the contract governor to set the protocol fee rate. The protocol fee is taken from the origin amount only for completed and claimed transactions."},"sweepProtocolFees(address,address)":{"notice":"Allows the contract governor to sweep the accumulated protocol fees in the contract."}},"notice":"FastBridgeV2 is a contract for bridging tokens across chains.","version":1},"developerDoc":{"errors":{"AccessControlBadConfirmation()":[{"details":"The caller of a function is not the expected one. NOTE: Don't confuse with {AccessControlUnauthorizedAccount}."}],"AccessControlUnauthorizedAccount(address,bytes32)":[{"details":"The `account` is missing a role."}],"AddressEmptyCode(address)":[{"details":"There's no code at `target` (it is not a contract)."}],"AddressInsufficientBalance(address)":[{"details":"The ETH balance of the account is not enough to perform the operation."}],"FailedInnerCall()":[{"details":"A call to an address target failed. The target may have reverted."}],"SafeERC20FailedOperation(address)":[{"details":"An operation with an ERC20 token failed."}]},"events":{"RoleAdminChanged(bytes32,bytes32,bytes32)":{"details":"Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole` `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite {RoleAdminChanged} not being emitted signaling this."},"RoleGranted(bytes32,address,address)":{"details":"Emitted when `account` is granted `role`. `sender` is the account that originated the contract call, an admin role bearer except when using {AccessControl-_setupRole}."},"RoleRevoked(bytes32,address,address)":{"details":"Emitted when `account` is revoked `role`. `sender` is the account that originated the contract call: - if using `revokeRole`, it is the admin role bearer - if using `renounceRole`, it is the role bearer (i.e. `account`)"}},"kind":"dev","methods":{"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256))":{"params":{"params":"The parameters required to bridge"}},"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256),(address,int256,bytes,uint256,bytes))":{"params":{"params":"The parameters required to bridge","paramsV2":"The parameters for exclusivity fill rights (optional, can be left empty)"}},"bridgeProofs(bytes32)":{"params":{"transactionId":"The ID of the bridge transaction"},"returns":{"relayer":"The relayer address of the bridge proof","timestamp":"The timestamp of the bridge proof"}},"bridgeRelays(bytes32)":{"params":{"transactionId":"The ID of the transaction to check"},"returns":{"_0":"True if the transaction has been relayed, false otherwise"}},"bridgeStatuses(bytes32)":{"params":{"transactionId":"The ID of the bridge transaction"},"returns":{"status":"BridgeStatus Status of the bridge transaction"}},"canClaim(bytes32,address)":{"params":{"relayer":"The address of the relayer attempting to claim","transactionId":"The transaction id associated with the encoded bridge transaction to check"}},"cancel(bytes)":{"params":{"request":"The encoded bridge transaction to refund"}},"claim(bytes)":{"params":{"request":"The encoded bridge transaction to claim on origin chain"}},"claim(bytes,address)":{"params":{"request":"The encoded bridge transaction to claim on origin chain","to":"The recipient address of the funds"}},"dispute(bytes32)":{"params":{"transactionId":"The transaction id associated with the encoded bridge transaction to dispute"}},"getBridgeTransaction(bytes)":{"details":"This method is added to achieve backwards compatibility with decoding requests into V1 structs: - `zapNative` is partially reported as a zero/non-zero flag - `zapData` is ignored In order to process all kinds of requests use getBridgeTransactionV2 instead.","params":{"request":"The bridge request to decode"}},"getBridgeTransactionV2(bytes)":{"params":{"request":"The bridge request to decode"}},"getRoleAdmin(bytes32)":{"details":"Returns the admin role that controls `role`. See {grantRole} and {revokeRole}. To change a role's admin, use {_setRoleAdmin}."},"getRoleMember(bytes32,uint256)":{"details":"Returns one of the accounts that have `role`. `index` must be a value between 0 and {getRoleMemberCount}, non-inclusive. Role bearers are not sorted in any particular way, and their ordering may change at any point. WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure you perform all queries on the same block. See the following https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post] for more information."},"getRoleMemberCount(bytes32)":{"details":"Returns the number of accounts that have `role`. Can be used together with {getRoleMember} to enumerate all bearers of a role."},"grantRole(bytes32,address)":{"details":"Grants `role` to `account`. If `account` had not been already granted `role`, emits a {RoleGranted} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleGranted} event."},"hasRole(bytes32,address)":{"details":"Returns `true` if `account` has been granted `role`."},"multicallNoResults(bytes[],bool)":{"details":"The method is non-payable, so only calls with `msg.value == 0` could be batched. It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag. Otherwise, the whole batch call will be reverted with the original revert reason.","params":{"data":"List of abi-encoded calldata for the calls to perform.","ignoreReverts":"Whether to ignore the revert errors from the calls."}},"multicallWithResults(bytes[],bool)":{"details":"The method is non-payable, so only calls with `msg.value == 0` could be batched. It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag. Otherwise, the whole batch call will be reverted with the original revert reason.","params":{"data":"List of abi-encoded calldata for the calls to perform.","ignoreReverts":"Whether to ignore the revert errors from the calls."},"returns":{"results":" List of results from the calls: `(success, returnData)`."}},"prove(bytes,bytes32)":{"params":{"destTxHash":"The destination tx hash proving bridge transaction was relayed","request":"The encoded bridge transaction to prove on origin chain"}},"prove(bytes32,bytes32,address)":{"params":{"destTxHash":"The destination tx hash proving bridge transaction was relayed","relayer":"The address of the relaying entity which should have control of the origin funds when claimed","transactionId":"The transaction id associated with the encoded bridge transaction to prove"}},"refund(bytes)":{"params":{"request":"The encoded bridge transaction to refund"}},"relay(bytes)":{"params":{"request":"The encoded bridge transaction to relay on destination chain"}},"relay(bytes,address)":{"params":{"relayer":"The address of the relaying entity which should have control of the origin funds when claimed","request":"The encoded bridge transaction to relay on destination chain"}},"renounceRole(bytes32,address)":{"details":"Revokes `role` from the calling account. Roles are often managed via {grantRole} and {revokeRole}: this function's purpose is to provide a mechanism for accounts to lose their privileges if they are compromised (such as when a trusted device is misplaced). If the calling account had been revoked `role`, emits a {RoleRevoked} event. Requirements: - the caller must be `callerConfirmation`. May emit a {RoleRevoked} event."},"revokeRole(bytes32,address)":{"details":"Revokes `role` from `account`. If `account` had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleRevoked} event."},"setProtocolFeeRate(uint256)":{"details":"The protocol fee is abstracted away from the relayers, they always operate using the amounts after fees: what they see as the origin amount emitted in the log is what they get credited with."},"supportsInterface(bytes4)":{"details":"See {IERC165-supportsInterface}."}},"stateVariables":{"nonce":{"details":"Replaced by senderNonces"}},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_owner\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"AccessControlBadConfirmation\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"neededRole\",\"type\":\"bytes32\"}],\"name\":\"AccessControlUnauthorizedAccount\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"}],\"name\":\"AddressEmptyCode\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"AddressInsufficientBalance\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"AmountIncorrect\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"BridgeTransactionV2__InvalidEncodedTx\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint16\",\"name\":\"version\",\"type\":\"uint16\"}],\"name\":\"BridgeTransactionV2__UnsupportedVersion\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"CancelDelayBelowMin\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ChainIncorrect\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DeadlineExceeded\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DeadlineNotExceeded\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DeadlineTooShort\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DisputePeriodNotPassed\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DisputePeriodPassed\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ExclusivityParamsIncorrect\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ExclusivityPeriodNotPassed\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"FailedInnerCall\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"FeeRateAboveMax\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"MsgValueIncorrect\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"MulticallTarget__UndeterminedRevert\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"RecipientIncorrectReturnValue\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"RecipientNoReturnValue\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"}],\"name\":\"SafeERC20FailedOperation\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"SenderIncorrect\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"StatusIncorrect\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"TokenNotContract\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"TransactionRelayed\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ZapDataLengthAboveMax\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ZapNativeNotSupported\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ZeroAddress\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"BridgeDepositClaimed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"BridgeDepositRefunded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"name\":\"BridgeProofDisputed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"transactionHash\",\"type\":\"bytes32\"}],\"name\":\"BridgeProofProvided\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"quoteId\",\"type\":\"bytes\"}],\"name\":\"BridgeQuoteDetails\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"originChainId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"chainGasAmount\",\"type\":\"uint256\"}],\"name\":\"BridgeRelayed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"destChainId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"sendChainGas\",\"type\":\"bool\"}],\"name\":\"BridgeRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"oldCancelDelay\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newCancelDelay\",\"type\":\"uint256\"}],\"name\":\"CancelDelayUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"oldFeeRate\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newFeeRate\",\"type\":\"uint256\"}],\"name\":\"FeeRateUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"FeesSwept\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"previousAdminRole\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"newAdminRole\",\"type\":\"bytes32\"}],\"name\":\"RoleAdminChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleGranted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleRevoked\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"CANCELER_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"DEFAULT_ADMIN_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"DEFAULT_CANCEL_DELAY\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"DISPUTE_PERIOD\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"FEE_BPS\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"FEE_RATE_MAX\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"GOVERNOR_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"GUARD_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"MAX_ZAP_DATA_LENGTH\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"MIN_CANCEL_DELAY\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"MIN_DEADLINE_PERIOD\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"NATIVE_GAS_TOKEN\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"PROVER_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"QUOTER_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"dstChainId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"sendChainGas\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"}],\"internalType\":\"struct IFastBridge.BridgeParams\",\"name\":\"params\",\"type\":\"tuple\"}],\"name\":\"bridge\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"dstChainId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"sendChainGas\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"}],\"internalType\":\"struct IFastBridge.BridgeParams\",\"name\":\"params\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"quoteRelayer\",\"type\":\"address\"},{\"internalType\":\"int256\",\"name\":\"quoteExclusivitySeconds\",\"type\":\"int256\"},{\"internalType\":\"bytes\",\"name\":\"quoteId\",\"type\":\"bytes\"},{\"internalType\":\"uint256\",\"name\":\"zapNative\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"zapData\",\"type\":\"bytes\"}],\"internalType\":\"struct IFastBridgeV2.BridgeParamsV2\",\"name\":\"paramsV2\",\"type\":\"tuple\"}],\"name\":\"bridge\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"}],\"name\":\"bridgeProofs\",\"outputs\":[{\"internalType\":\"uint96\",\"name\":\"timestamp\",\"type\":\"uint96\"},{\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"bridgeRelayDetails\",\"outputs\":[{\"internalType\":\"uint48\",\"name\":\"blockNumber\",\"type\":\"uint48\"},{\"internalType\":\"uint48\",\"name\":\"blockTimestamp\",\"type\":\"uint48\"},{\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"}],\"name\":\"bridgeRelays\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"}],\"name\":\"bridgeStatuses\",\"outputs\":[{\"internalType\":\"enum IFastBridgeV2.BridgeStatus\",\"name\":\"status\",\"type\":\"uint8\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"bridgeTxDetails\",\"outputs\":[{\"internalType\":\"enum IFastBridgeV2.BridgeStatus\",\"name\":\"status\",\"type\":\"uint8\"},{\"internalType\":\"uint32\",\"name\":\"destChainId\",\"type\":\"uint32\"},{\"internalType\":\"uint56\",\"name\":\"proofBlockTimestamp\",\"type\":\"uint56\"},{\"internalType\":\"address\",\"name\":\"proofRelayer\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"name\":\"canClaim\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"cancel\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"cancelDelay\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"chainGasAmount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"claim\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"claim\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"deployBlock\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"}],\"name\":\"dispute\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"getBridgeTransaction\",\"outputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"originChainId\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"destChainId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"originSender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destRecipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"originFeeAmount\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"sendChainGas\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"}],\"internalType\":\"struct IFastBridge.BridgeTransaction\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"getBridgeTransactionV2\",\"outputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"originChainId\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"destChainId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"originSender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destRecipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"originFeeAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"exclusivityRelayer\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"exclusivityEndTime\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"zapNative\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"zapData\",\"type\":\"bytes\"}],\"internalType\":\"struct IFastBridgeV2.BridgeTransactionV2\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"}],\"name\":\"getRoleAdmin\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"index\",\"type\":\"uint256\"}],\"name\":\"getRoleMember\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"}],\"name\":\"getRoleMemberCount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"grantRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"hasRole\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes[]\",\"name\":\"data\",\"type\":\"bytes[]\"},{\"internalType\":\"bool\",\"name\":\"ignoreReverts\",\"type\":\"bool\"}],\"name\":\"multicallNoResults\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes[]\",\"name\":\"data\",\"type\":\"bytes[]\"},{\"internalType\":\"bool\",\"name\":\"ignoreReverts\",\"type\":\"bool\"}],\"name\":\"multicallWithResults\",\"outputs\":[{\"components\":[{\"internalType\":\"bool\",\"name\":\"success\",\"type\":\"bool\"},{\"internalType\":\"bytes\",\"name\":\"returnData\",\"type\":\"bytes\"}],\"internalType\":\"struct IMulticallTarget.Result[]\",\"name\":\"results\",\"type\":\"tuple[]\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"nonce\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"protocolFeeRate\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"protocolFees\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"destTxHash\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"name\":\"prove\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"},{\"internalType\":\"bytes32\",\"name\":\"destTxHash\",\"type\":\"bytes32\"}],\"name\":\"prove\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"refund\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"relay\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"},{\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"name\":\"relay\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"callerConfirmation\",\"type\":\"address\"}],\"name\":\"renounceRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"revokeRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"senderNonces\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"newCancelDelay\",\"type\":\"uint256\"}],\"name\":\"setCancelDelay\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"newFeeRate\",\"type\":\"uint256\"}],\"name\":\"setProtocolFeeRate\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes4\",\"name\":\"interfaceId\",\"type\":\"bytes4\"}],\"name\":\"supportsInterface\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"}],\"name\":\"sweepProtocolFees\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"errors\":{\"AccessControlBadConfirmation()\":[{\"details\":\"The caller of a function is not the expected one. NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\"}],\"AccessControlUnauthorizedAccount(address,bytes32)\":[{\"details\":\"The `account` is missing a role.\"}],\"AddressEmptyCode(address)\":[{\"details\":\"There's no code at `target` (it is not a contract).\"}],\"AddressInsufficientBalance(address)\":[{\"details\":\"The ETH balance of the account is not enough to perform the operation.\"}],\"FailedInnerCall()\":[{\"details\":\"A call to an address target failed. The target may have reverted.\"}],\"SafeERC20FailedOperation(address)\":[{\"details\":\"An operation with an ERC20 token failed.\"}]},\"events\":{\"RoleAdminChanged(bytes32,bytes32,bytes32)\":{\"details\":\"Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole` `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite {RoleAdminChanged} not being emitted signaling this.\"},\"RoleGranted(bytes32,address,address)\":{\"details\":\"Emitted when `account` is granted `role`. `sender` is the account that originated the contract call, an admin role bearer except when using {AccessControl-_setupRole}.\"},\"RoleRevoked(bytes32,address,address)\":{\"details\":\"Emitted when `account` is revoked `role`. `sender` is the account that originated the contract call: - if using `revokeRole`, it is the admin role bearer - if using `renounceRole`, it is the role bearer (i.e. `account`)\"}},\"kind\":\"dev\",\"methods\":{\"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256))\":{\"params\":{\"params\":\"The parameters required to bridge\"}},\"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256),(address,int256,bytes,uint256,bytes))\":{\"params\":{\"params\":\"The parameters required to bridge\",\"paramsV2\":\"The parameters for exclusivity fill rights (optional, can be left empty)\"}},\"bridgeProofs(bytes32)\":{\"params\":{\"transactionId\":\"The ID of the bridge transaction\"},\"returns\":{\"relayer\":\"The relayer address of the bridge proof\",\"timestamp\":\"The timestamp of the bridge proof\"}},\"bridgeRelays(bytes32)\":{\"params\":{\"transactionId\":\"The ID of the transaction to check\"},\"returns\":{\"_0\":\"True if the transaction has been relayed, false otherwise\"}},\"bridgeStatuses(bytes32)\":{\"params\":{\"transactionId\":\"The ID of the bridge transaction\"},\"returns\":{\"status\":\"BridgeStatus Status of the bridge transaction\"}},\"canClaim(bytes32,address)\":{\"params\":{\"relayer\":\"The address of the relayer attempting to claim\",\"transactionId\":\"The transaction id associated with the encoded bridge transaction to check\"}},\"cancel(bytes)\":{\"params\":{\"request\":\"The encoded bridge transaction to refund\"}},\"claim(bytes)\":{\"params\":{\"request\":\"The encoded bridge transaction to claim on origin chain\"}},\"claim(bytes,address)\":{\"params\":{\"request\":\"The encoded bridge transaction to claim on origin chain\",\"to\":\"The recipient address of the funds\"}},\"dispute(bytes32)\":{\"params\":{\"transactionId\":\"The transaction id associated with the encoded bridge transaction to dispute\"}},\"getBridgeTransaction(bytes)\":{\"details\":\"This method is added to achieve backwards compatibility with decoding requests into V1 structs: - `zapNative` is partially reported as a zero/non-zero flag - `zapData` is ignored In order to process all kinds of requests use getBridgeTransactionV2 instead.\",\"params\":{\"request\":\"The bridge request to decode\"}},\"getBridgeTransactionV2(bytes)\":{\"params\":{\"request\":\"The bridge request to decode\"}},\"getRoleAdmin(bytes32)\":{\"details\":\"Returns the admin role that controls `role`. See {grantRole} and {revokeRole}. To change a role's admin, use {_setRoleAdmin}.\"},\"getRoleMember(bytes32,uint256)\":{\"details\":\"Returns one of the accounts that have `role`. `index` must be a value between 0 and {getRoleMemberCount}, non-inclusive. Role bearers are not sorted in any particular way, and their ordering may change at any point. WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure you perform all queries on the same block. See the following https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post] for more information.\"},\"getRoleMemberCount(bytes32)\":{\"details\":\"Returns the number of accounts that have `role`. Can be used together with {getRoleMember} to enumerate all bearers of a role.\"},\"grantRole(bytes32,address)\":{\"details\":\"Grants `role` to `account`. If `account` had not been already granted `role`, emits a {RoleGranted} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleGranted} event.\"},\"hasRole(bytes32,address)\":{\"details\":\"Returns `true` if `account` has been granted `role`.\"},\"multicallNoResults(bytes[],bool)\":{\"details\":\"The method is non-payable, so only calls with `msg.value == 0` could be batched. It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag. Otherwise, the whole batch call will be reverted with the original revert reason.\",\"params\":{\"data\":\"List of abi-encoded calldata for the calls to perform.\",\"ignoreReverts\":\"Whether to ignore the revert errors from the calls.\"}},\"multicallWithResults(bytes[],bool)\":{\"details\":\"The method is non-payable, so only calls with `msg.value == 0` could be batched. It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag. Otherwise, the whole batch call will be reverted with the original revert reason.\",\"params\":{\"data\":\"List of abi-encoded calldata for the calls to perform.\",\"ignoreReverts\":\"Whether to ignore the revert errors from the calls.\"},\"returns\":{\"results\":\" List of results from the calls: `(success, returnData)`.\"}},\"prove(bytes,bytes32)\":{\"params\":{\"destTxHash\":\"The destination tx hash proving bridge transaction was relayed\",\"request\":\"The encoded bridge transaction to prove on origin chain\"}},\"prove(bytes32,bytes32,address)\":{\"params\":{\"destTxHash\":\"The destination tx hash proving bridge transaction was relayed\",\"relayer\":\"The address of the relaying entity which should have control of the origin funds when claimed\",\"transactionId\":\"The transaction id associated with the encoded bridge transaction to prove\"}},\"refund(bytes)\":{\"params\":{\"request\":\"The encoded bridge transaction to refund\"}},\"relay(bytes)\":{\"params\":{\"request\":\"The encoded bridge transaction to relay on destination chain\"}},\"relay(bytes,address)\":{\"params\":{\"relayer\":\"The address of the relaying entity which should have control of the origin funds when claimed\",\"request\":\"The encoded bridge transaction to relay on destination chain\"}},\"renounceRole(bytes32,address)\":{\"details\":\"Revokes `role` from the calling account. Roles are often managed via {grantRole} and {revokeRole}: this function's purpose is to provide a mechanism for accounts to lose their privileges if they are compromised (such as when a trusted device is misplaced). If the calling account had been revoked `role`, emits a {RoleRevoked} event. Requirements: - the caller must be `callerConfirmation`. May emit a {RoleRevoked} event.\"},\"revokeRole(bytes32,address)\":{\"details\":\"Revokes `role` from `account`. If `account` had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleRevoked} event.\"},\"setProtocolFeeRate(uint256)\":{\"details\":\"The protocol fee is abstracted away from the relayers, they always operate using the amounts after fees: what they see as the origin amount emitted in the log is what they get credited with.\"},\"supportsInterface(bytes4)\":{\"details\":\"See {IERC165-supportsInterface}.\"}},\"stateVariables\":{\"nonce\":{\"details\":\"Replaced by senderNonces\"}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"CANCELER_ROLE()\":{\"notice\":\"Role identifier for Canceler's on-chain authentication in FastBridge.\"},\"DEFAULT_CANCEL_DELAY()\":{\"notice\":\"Default cancel delay set during the contract deployment.\"},\"DISPUTE_PERIOD()\":{\"notice\":\"Dispute period for relayed transactions\"},\"FEE_BPS()\":{\"notice\":\"Denominator for fee rates, represents 100%.\"},\"FEE_RATE_MAX()\":{\"notice\":\"Maximum protocol fee rate: 1% on origin amount.\"},\"GOVERNOR_ROLE()\":{\"notice\":\"Role identifier for Governor's on-chain administrative authority.\"},\"GUARD_ROLE()\":{\"notice\":\"Role identifier for Guard's on-chain authentication in FastBridge.\"},\"MAX_ZAP_DATA_LENGTH()\":{\"notice\":\"Maximum length of accepted zapData\"},\"MIN_CANCEL_DELAY()\":{\"notice\":\"Minimum cancel delay that can be set by the governor.\"},\"MIN_DEADLINE_PERIOD()\":{\"notice\":\"Minimum deadline period to relay a requested bridge transaction\"},\"NATIVE_GAS_TOKEN()\":{\"notice\":\"Address reserved for native gas token (ETH on Ethereum and most L2s, AVAX on Avalanche, etc)\"},\"PROVER_ROLE()\":{\"notice\":\"Role identifier for Prover's on-chain authentication in FastBridge.\"},\"QUOTER_ROLE()\":{\"notice\":\"Role identifier for Quoter API's off-chain authentication.\"},\"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256))\":{\"notice\":\"Initiates bridge on origin chain to be relayed by off-chain relayer\"},\"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256),(address,int256,bytes,uint256,bytes))\":{\"notice\":\"Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability to provide temporary exclusivity fill rights for the quote relayer.\"},\"bridgeProofs(bytes32)\":{\"notice\":\"Returns the timestamp and relayer of a bridge proof\"},\"bridgeRelayDetails(bytes32)\":{\"notice\":\"Relay details on destination chain\"},\"bridgeRelays(bytes32)\":{\"notice\":\"Checks if a transaction has been relayed\"},\"bridgeStatuses(bytes32)\":{\"notice\":\"Returns the status of a bridge transaction\"},\"bridgeTxDetails(bytes32)\":{\"notice\":\"Status of the bridge tx on origin chain\"},\"canClaim(bytes32,address)\":{\"notice\":\"Checks if the dispute period has passed so bridge deposit can be claimed\"},\"cancel(bytes)\":{\"notice\":\"Cancels an outstanding bridge transaction in case optimistic bridging failed and returns the full amount to the original sender.\"},\"cancelDelay()\":{\"notice\":\"Delay for a transaction after which it could be permisionlessly cancelled\"},\"chainGasAmount()\":{\"notice\":\"This is deprecated and should not be used.\"},\"claim(bytes)\":{\"notice\":\"Completes bridge transaction on origin chain by claiming originally deposited capital.Can only send funds to the relayer address on the proof.\"},\"claim(bytes,address)\":{\"notice\":\"Completes bridge transaction on origin chain by claiming originally deposited capital\"},\"deployBlock()\":{\"notice\":\"the block the contract was deployed at\"},\"dispute(bytes32)\":{\"notice\":\"Disputes an outstanding proof in case relayer provided dest chain tx is invalid\"},\"getBridgeTransaction(bytes)\":{\"notice\":\"Decodes bridge request into a bridge transaction\"},\"getBridgeTransactionV2(bytes)\":{\"notice\":\"Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\"},\"multicallNoResults(bytes[],bool)\":{\"notice\":\"Perform a batched call to this contract, preserving the msg.sender. The return data from each call is discarded.\"},\"multicallWithResults(bytes[],bool)\":{\"notice\":\"Perform a batched call to this contract, preserving the msg.sender. The return data from each call is preserved.\"},\"nonce()\":{\"notice\":\"This is deprecated and should not be used.\"},\"protocolFeeRate()\":{\"notice\":\"Protocol fee rate taken on origin amount deposited in origin chain\"},\"protocolFees(address)\":{\"notice\":\"Protocol fee amounts accumulated\"},\"prove(bytes,bytes32)\":{\"notice\":\"Provides proof on origin side that relayer provided funds on destination side of bridge transaction\"},\"prove(bytes32,bytes32,address)\":{\"notice\":\"Provides proof on origin side that relayer provided funds on destination side of bridge transaction\"},\"refund(bytes)\":{\"notice\":\"Note: this function is deprecated and will be removed in a future version.\"},\"relay(bytes)\":{\"notice\":\"Relays destination side of bridge transaction by off-chain relayer\"},\"relay(bytes,address)\":{\"notice\":\"Relays destination side of bridge transaction by off-chain relayer\"},\"senderNonces(address)\":{\"notice\":\"Unique bridge nonces tracked per originSender\"},\"setCancelDelay(uint256)\":{\"notice\":\"Allows the contract governor to set the cancel delay. The cancel delay is the time after the transaction deadline after which it can be permissionlessly cancelled, if it hasn't been proven by any of the Relayers.\"},\"setProtocolFeeRate(uint256)\":{\"notice\":\"Allows the contract governor to set the protocol fee rate. The protocol fee is taken from the origin amount only for completed and claimed transactions.\"},\"sweepProtocolFees(address,address)\":{\"notice\":\"Allows the contract governor to sweep the accumulated protocol fees in the contract.\"}},\"notice\":\"FastBridgeV2 is a contract for bridging tokens across chains.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeV2.sol\":\"FastBridgeV2\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeV2.sol\":{\"keccak256\":\"0xac79c463688a682ca706a4ef95e7817b83548cdfa8182ba0426ac7e5e07613d8\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://b3ecb7097381287cafc3a73f3a2bb03565115ebb682a85064e0b0dc2f7e2919d\",\"dweb:/ipfs/QmatruW3nYZTksf3CeQ8wwiAG4c7xoEJBEp6drHPtFLBRK\"]}},\"version\":1}"},"hashes":{"CANCELER_ROLE()":"02d2ff66","DEFAULT_ADMIN_ROLE()":"a217fddf","DEFAULT_CANCEL_DELAY()":"930ac180","DISPUTE_PERIOD()":"a5bbe22b","FEE_BPS()":"bf333f2c","FEE_RATE_MAX()":"0f5f6ed7","GOVERNOR_ROLE()":"ccc57490","GUARD_ROLE()":"03ed0ee5","MAX_ZAP_DATA_LENGTH()":"54eff068","MIN_CANCEL_DELAY()":"922b7487","MIN_DEADLINE_PERIOD()":"820688d5","NATIVE_GAS_TOKEN()":"0f862f1e","PROVER_ROLE()":"dc9a4ef6","QUOTER_ROLE()":"7ebe815c","bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256))":"45851694","bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256),(address,int256,bytes,uint256,bytes))":"bfc7c607","bridgeProofs(bytes32)":"91ad5039","bridgeRelayDetails(bytes32)":"c79371b1","bridgeRelays(bytes32)":"8379a24f","bridgeStatuses(bytes32)":"051287bc","bridgeTxDetails(bytes32)":"63787e52","canClaim(bytes32,address)":"aa9641ab","cancel(bytes)":"3c5beeb4","cancelDelay()":"638a0f09","chainGasAmount()":"e00a83e0","claim(bytes)":"c63ff8dd","claim(bytes,address)":"41fcb612","deployBlock()":"a3ec191a","dispute(bytes32)":"add98c70","getBridgeTransaction(bytes)":"ac11fb1a","getBridgeTransactionV2(bytes)":"5aa6ccba","getRoleAdmin(bytes32)":"248a9ca3","getRoleMember(bytes32,uint256)":"9010d07c","getRoleMemberCount(bytes32)":"ca15c873","grantRole(bytes32,address)":"2f2ff15d","hasRole(bytes32,address)":"91d14854","multicallNoResults(bytes[],bool)":"3f61331d","multicallWithResults(bytes[],bool)":"385c1d2f","nonce()":"affed0e0","protocolFeeRate()":"58f85880","protocolFees(address)":"dcf844a7","prove(bytes,bytes32)":"886d36ff","prove(bytes32,bytes32,address)":"18e4357d","refund(bytes)":"5eb7d946","relay(bytes)":"8f0d6f17","relay(bytes,address)":"9c9545f0","renounceRole(bytes32,address)":"36568abe","revokeRole(bytes32,address)":"d547741f","senderNonces(address)":"295710ff","setCancelDelay(uint256)":"1ea327c5","setProtocolFeeRate(uint256)":"b13aa2d6","supportsInterface(bytes4)":"01ffc9a7","sweepProtocolFees(address,address)":"06f333f2"}},"solidity/FastBridgeV2.sol:IAccessControl":{"code":"0x","runtime-code":"0x","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.24 ^0.8.20 ^0.8.4;\n\n// contracts/interfaces/IAdminV2.sol\n\ninterface IAdminV2 {\n event CancelDelayUpdated(uint256 oldCancelDelay, uint256 newCancelDelay);\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n function setCancelDelay(uint256 newCancelDelay) external;\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n}\n\n// contracts/interfaces/IAdminV2Errors.sol\n\ninterface IAdminV2Errors {\n error CancelDelayBelowMin();\n error FeeRateAboveMax();\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IFastBridgeV2Errors.sol\n\ninterface IFastBridgeV2Errors {\n error AmountIncorrect();\n error ChainIncorrect();\n error ExclusivityParamsIncorrect();\n error MsgValueIncorrect();\n error SenderIncorrect();\n error StatusIncorrect();\n error TokenNotContract();\n error ZapDataLengthAboveMax();\n error ZapNativeNotSupported();\n error ZeroAddress();\n\n error RecipientIncorrectReturnValue();\n error RecipientNoReturnValue();\n\n error DeadlineExceeded();\n error DeadlineNotExceeded();\n error DeadlineTooShort();\n error DisputePeriodNotPassed();\n error DisputePeriodPassed();\n error ExclusivityPeriodNotPassed();\n\n error TransactionRelayed();\n}\n\n// contracts/interfaces/IMulticallTarget.sol\n\n/// @notice Interface for a contract that can be called multiple times by the same caller. Inspired by MulticallV3:\n/// https://github.com/mds1/multicall/blob/master/src/Multicall3.sol\ninterface IMulticallTarget {\n struct Result {\n bool success;\n bytes returnData;\n }\n\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external;\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results);\n}\n\n// contracts/interfaces/IZapRecipient.sol\n\ninterface IZapRecipient {\n function zap(address token, uint256 amount, bytes memory zapData) external payable returns (bytes4);\n}\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// contracts/interfaces/IFastBridgeV2.sol\n\ninterface IFastBridgeV2 is IFastBridge {\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n struct BridgeTxDetails {\n BridgeStatus status;\n uint32 destChainId;\n uint56 proofBlockTimestamp;\n address proofRelayer;\n }\n\n struct BridgeRelay {\n uint48 blockNumber;\n uint48 blockTimestamp;\n address relayer;\n }\n\n /// @notice New params introduced in the FastBridgeV2.\n /// We are passing fields from the older BridgeParams struct outside of this struct\n /// for backwards compatibility.\n /// Note: quoteRelayer and quoteExclusivitySeconds are either both zero (indicating no exclusivity)\n /// or both non-zero (indicating exclusivity for the given period).\n /// Note: zapNative \u003e 0 can NOT be used with destToken = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE (native token)\n /// @param quoteRelayer Relayer that provided the quote for the transaction\n /// @param quoteExclusivitySeconds Period of time the quote relayer is guaranteed exclusivity after user's deposit\n /// @param quoteId Unique quote identifier used for tracking the quote\n /// @param zapNative ETH value to send to the recipient (if any)\n /// @param zapData Parameters for the Zap to the destination recipient (if any)\n struct BridgeParamsV2 {\n address quoteRelayer;\n int256 quoteExclusivitySeconds;\n bytes quoteId;\n uint256 zapNative;\n bytes zapData;\n }\n\n /// @notice Updated bridge transaction struct to include parameters introduced in FastBridgeV2.\n /// Note: only `exclusivityRelayer` can fill such a transaction until `exclusivityEndTime`.\n struct BridgeTransactionV2 {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n // Note: sendChainGas flag from V1 is deprecated\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n address exclusivityRelayer;\n uint256 exclusivityEndTime;\n uint256 zapNative; // ETH value to send to the recipient (if any)\n bytes zapData; // data to pass for the Zap action (if any)\n }\n\n event BridgeQuoteDetails(bytes32 indexed transactionId, bytes quoteId);\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability\n /// to provide temporary exclusivity fill rights for the quote relayer.\n /// @param params The parameters required to bridge\n /// @param paramsV2 The parameters for exclusivity fill rights (optional, can be left empty)\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function relay(bytes memory request, address relayer) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param transactionId The transaction id associated with the encoded bridge transaction to prove\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital.\n /// @notice Can only send funds to the relayer address on the proof.\n /// @param request The encoded bridge transaction to claim on origin chain\n function claim(bytes memory request) external;\n\n /// @notice Cancels an outstanding bridge transaction in case optimistic bridging failed and returns the full amount\n /// to the original sender.\n /// @param request The encoded bridge transaction to refund\n function cancel(bytes memory request) external;\n\n /// @notice Checks if a transaction has been relayed\n /// @param transactionId The ID of the transaction to check\n /// @return True if the transaction has been relayed, false otherwise\n function bridgeRelays(bytes32 transactionId) external view returns (bool);\n\n /// @notice Returns the status of a bridge transaction\n /// @param transactionId The ID of the bridge transaction\n /// @return BridgeStatus Status of the bridge transaction\n function bridgeStatuses(bytes32 transactionId) external view returns (BridgeStatus);\n\n /// @notice Returns the timestamp and relayer of a bridge proof\n /// @param transactionId The ID of the bridge transaction\n /// @return timestamp The timestamp of the bridge proof\n /// @return relayer The relayer address of the bridge proof\n function bridgeProofs(bytes32 transactionId) external view returns (uint96 timestamp, address relayer);\n\n /// @notice Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\n /// @param request The bridge request to decode\n function getBridgeTransactionV2(bytes memory request) external view returns (BridgeTransactionV2 memory);\n}\n\n// contracts/utils/MulticallTarget.sol\n\n// solhint-disable avoid-low-level-calls\n/// @notice Template for a contract that supports batched calls (preserving the msg.sender).\n/// Only calls with zero msg.value could be batched.\nabstract contract MulticallTarget is IMulticallTarget {\n error MulticallTarget__UndeterminedRevert();\n\n /// @notice Perform a batched call to this contract, preserving the msg.sender.\n /// The return data from each call is discarded.\n /// @dev The method is non-payable, so only calls with `msg.value == 0` could be batched.\n /// It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag.\n /// Otherwise, the whole batch call will be reverted with the original revert reason.\n /// @param data List of abi-encoded calldata for the calls to perform.\n /// @param ignoreReverts Whether to ignore the revert errors from the calls.\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external {\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\n if (!success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(result);\n }\n }\n }\n\n /// @notice Perform a batched call to this contract, preserving the msg.sender.\n /// The return data from each call is preserved.\n /// @dev The method is non-payable, so only calls with `msg.value == 0` could be batched.\n /// It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag.\n /// Otherwise, the whole batch call will be reverted with the original revert reason.\n /// @param data List of abi-encoded calldata for the calls to perform.\n /// @param ignoreReverts Whether to ignore the revert errors from the calls.\n /// @return results List of results from the calls: `(success, returnData)`.\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results)\n {\n results = new Result[](data.length);\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (results[i].success, results[i].returnData) = address(this).delegatecall(data[i]);\n if (!results[i].success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(results[i].returnData);\n }\n }\n }\n\n /// @dev Bubbles the revert message from the underlying call.\n /// Note: preserves the same custom error or revert string, if one was used.\n /// Source: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v5.0.2/contracts/utils/Address.sol#L143-L158\n function _bubbleRevert(bytes memory returnData) internal pure {\n // Look for revert reason and bubble it up if present\n if (returnData.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n // solhint-disable-next-line no-inline-assembly\n assembly {\n let returndata_size := mload(returnData)\n revert(add(32, returnData), returndata_size)\n }\n } else {\n revert MulticallTarget__UndeterminedRevert();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// contracts/libs/BridgeTransactionV2.sol\n\n// solhint-disable no-inline-assembly\nlibrary BridgeTransactionV2Lib {\n uint16 internal constant VERSION = 2;\n\n // Offsets of the fields in the packed BridgeTransactionV2 struct\n // uint16 version [000 .. 002)\n // uint32 originChainId [002 .. 006)\n // uint32 destChainId [006 .. 010)\n // address originSender [010 .. 030)\n // address destRecipient [030 .. 050)\n // address originToken [050 .. 070)\n // address destToken [070 .. 090)\n // uint256 originAmount [090 .. 122)\n // uint256 destAmount [122 .. 154)\n // uint256 originFeeAmount [154 .. 186)\n // uint256 deadline [186 .. 218)\n // uint256 nonce [218 .. 250)\n // address exclusivityRelayer [250 .. 270)\n // uint256 exclusivityEndTime [270 .. 302)\n // uint256 zapNative [302 .. 334)\n // bytes zapData [334 .. ***)\n\n // forgefmt: disable-start\n uint256 private constant OFFSET_ORIGIN_CHAIN_ID = 2;\n uint256 private constant OFFSET_DEST_CHAIN_ID = 6;\n uint256 private constant OFFSET_ORIGIN_SENDER = 10;\n uint256 private constant OFFSET_DEST_RECIPIENT = 30;\n uint256 private constant OFFSET_ORIGIN_TOKEN = 50;\n uint256 private constant OFFSET_DEST_TOKEN = 70;\n uint256 private constant OFFSET_ORIGIN_AMOUNT = 90;\n uint256 private constant OFFSET_DEST_AMOUNT = 122;\n uint256 private constant OFFSET_ORIGIN_FEE_AMOUNT = 154;\n uint256 private constant OFFSET_DEADLINE = 186;\n uint256 private constant OFFSET_NONCE = 218;\n uint256 private constant OFFSET_EXCLUSIVITY_RELAYER = 250;\n uint256 private constant OFFSET_EXCLUSIVITY_END_TIME = 270;\n uint256 private constant OFFSET_ZAP_NATIVE = 302;\n uint256 private constant OFFSET_ZAP_DATA = 334;\n // forgefmt: disable-end\n\n error BridgeTransactionV2__InvalidEncodedTx();\n error BridgeTransactionV2__UnsupportedVersion(uint16 version);\n\n /// @notice Validates the encoded transaction to be a tightly packed encoded payload for BridgeTransactionV2.\n /// @dev Checks the minimum length and the version, use this function before decoding any of the fields.\n function validateV2(bytes calldata encodedTx) internal pure {\n // Check the minimum length: must at least include all static fields.\n if (encodedTx.length \u003c OFFSET_ZAP_DATA) revert BridgeTransactionV2__InvalidEncodedTx();\n // Once we validated the length, we can be sure that the version field is present.\n uint16 version_ = version(encodedTx);\n if (version_ != VERSION) revert BridgeTransactionV2__UnsupportedVersion(version_);\n }\n\n /// @notice Encodes the BridgeTransactionV2 struct by tightly packing the fields.\n /// @dev `abi.decode` will not work as a result of the tightly packed fields. Use `decodeV2` to decode instead.\n function encodeV2(IFastBridgeV2.BridgeTransactionV2 memory bridgeTx) internal pure returns (bytes memory) {\n // We split the encoding into two parts to avoid stack-too-deep error\n bytes memory firstPart = abi.encodePacked(\n VERSION,\n bridgeTx.originChainId,\n bridgeTx.destChainId,\n bridgeTx.originSender,\n bridgeTx.destRecipient,\n bridgeTx.originToken,\n bridgeTx.destToken,\n bridgeTx.originAmount\n );\n return abi.encodePacked(\n firstPart,\n bridgeTx.destAmount,\n bridgeTx.originFeeAmount,\n // Note: we skip the deprecated `sendChainGas` flag, which was present in BridgeTransaction V1\n bridgeTx.deadline,\n bridgeTx.nonce,\n // New V2 fields: exclusivity\n bridgeTx.exclusivityRelayer,\n bridgeTx.exclusivityEndTime,\n // New V2 fields: Zap\n bridgeTx.zapNative,\n bridgeTx.zapData\n );\n }\n\n /// @notice Decodes the BridgeTransactionV2 struct from the encoded transaction.\n /// @dev Encoded BridgeTransactionV2 struct must be tightly packed.\n /// Use `validateV2` before decoding to ensure the encoded transaction is valid.\n function decodeV2(bytes calldata encodedTx)\n internal\n pure\n returns (IFastBridgeV2.BridgeTransactionV2 memory bridgeTx)\n {\n bridgeTx.originChainId = originChainId(encodedTx);\n bridgeTx.destChainId = destChainId(encodedTx);\n bridgeTx.originSender = originSender(encodedTx);\n bridgeTx.destRecipient = destRecipient(encodedTx);\n bridgeTx.originToken = originToken(encodedTx);\n bridgeTx.destToken = destToken(encodedTx);\n bridgeTx.originAmount = originAmount(encodedTx);\n bridgeTx.destAmount = destAmount(encodedTx);\n bridgeTx.originFeeAmount = originFeeAmount(encodedTx);\n bridgeTx.deadline = deadline(encodedTx);\n bridgeTx.nonce = nonce(encodedTx);\n bridgeTx.exclusivityRelayer = exclusivityRelayer(encodedTx);\n bridgeTx.exclusivityEndTime = exclusivityEndTime(encodedTx);\n bridgeTx.zapNative = zapNative(encodedTx);\n bridgeTx.zapData = zapData(encodedTx);\n }\n\n /// @notice Extracts the version from the encoded transaction.\n function version(bytes calldata encodedTx) internal pure returns (uint16 version_) {\n // Load 32 bytes from the start and shift it 240 bits to the right to get the highest 16 bits.\n assembly {\n version_ := shr(240, calldataload(encodedTx.offset))\n }\n }\n\n /// @notice Extracts the origin chain ID from the encoded transaction.\n function originChainId(bytes calldata encodedTx) internal pure returns (uint32 originChainId_) {\n // Load 32 bytes from the offset and shift it 224 bits to the right to get the highest 32 bits.\n assembly {\n originChainId_ := shr(224, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_CHAIN_ID)))\n }\n }\n\n /// @notice Extracts the destination chain ID from the encoded transaction.\n function destChainId(bytes calldata encodedTx) internal pure returns (uint32 destChainId_) {\n // Load 32 bytes from the offset and shift it 224 bits to the right to get the highest 32 bits.\n assembly {\n destChainId_ := shr(224, calldataload(add(encodedTx.offset, OFFSET_DEST_CHAIN_ID)))\n }\n }\n\n /// @notice Extracts the origin sender from the encoded transaction.\n function originSender(bytes calldata encodedTx) internal pure returns (address originSender_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n originSender_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_SENDER)))\n }\n }\n\n /// @notice Extracts the destination recipient from the encoded transaction.\n function destRecipient(bytes calldata encodedTx) internal pure returns (address destRecipient_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n destRecipient_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_DEST_RECIPIENT)))\n }\n }\n\n /// @notice Extracts the origin token from the encoded transaction.\n function originToken(bytes calldata encodedTx) internal pure returns (address originToken_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n originToken_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_TOKEN)))\n }\n }\n\n /// @notice Extracts the destination token from the encoded transaction.\n function destToken(bytes calldata encodedTx) internal pure returns (address destToken_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n destToken_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_DEST_TOKEN)))\n }\n }\n\n /// @notice Extracts the origin amount from the encoded transaction.\n function originAmount(bytes calldata encodedTx) internal pure returns (uint256 originAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n originAmount_ := calldataload(add(encodedTx.offset, OFFSET_ORIGIN_AMOUNT))\n }\n }\n\n /// @notice Extracts the destination amount from the encoded transaction.\n function destAmount(bytes calldata encodedTx) internal pure returns (uint256 destAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n destAmount_ := calldataload(add(encodedTx.offset, OFFSET_DEST_AMOUNT))\n }\n }\n\n /// @notice Extracts the origin fee amount from the encoded transaction.\n function originFeeAmount(bytes calldata encodedTx) internal pure returns (uint256 originFeeAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n originFeeAmount_ := calldataload(add(encodedTx.offset, OFFSET_ORIGIN_FEE_AMOUNT))\n }\n }\n\n /// @notice Extracts the deadline from the encoded transaction.\n function deadline(bytes calldata encodedTx) internal pure returns (uint256 deadline_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n deadline_ := calldataload(add(encodedTx.offset, OFFSET_DEADLINE))\n }\n }\n\n /// @notice Extracts the nonce from the encoded transaction.\n function nonce(bytes calldata encodedTx) internal pure returns (uint256 nonce_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n nonce_ := calldataload(add(encodedTx.offset, OFFSET_NONCE))\n }\n }\n\n /// @notice Extracts the exclusivity relayer from the encoded transaction.\n function exclusivityRelayer(bytes calldata encodedTx) internal pure returns (address exclusivityRelayer_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n exclusivityRelayer_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_EXCLUSIVITY_RELAYER)))\n }\n }\n\n /// @notice Extracts the exclusivity end time from the encoded transaction.\n function exclusivityEndTime(bytes calldata encodedTx) internal pure returns (uint256 exclusivityEndTime_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n exclusivityEndTime_ := calldataload(add(encodedTx.offset, OFFSET_EXCLUSIVITY_END_TIME))\n }\n }\n\n /// @notice Extracts the Zap's native value from the encoded transaction.\n function zapNative(bytes calldata encodedTx) internal pure returns (uint256 zapNative_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n zapNative_ := calldataload(add(encodedTx.offset, OFFSET_ZAP_NATIVE))\n }\n }\n\n /// @notice Extracts the Zap's data from the encoded transaction.\n function zapData(bytes calldata encodedTx) internal pure returns (bytes calldata zapData_) {\n zapData_ = encodedTx[OFFSET_ZAP_DATA:];\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/AdminV2.sol\n\ncontract AdminV2 is AccessControlEnumerable, IAdminV2, IAdminV2Errors {\n using SafeERC20 for IERC20;\n\n /// @notice Address reserved for native gas token (ETH on Ethereum and most L2s, AVAX on Avalanche, etc)\n address public constant NATIVE_GAS_TOKEN = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Role identifier for Quoter API's off-chain authentication.\n /// @dev Only addresses with this role can post FastBridge quotes to the API.\n bytes32 public constant QUOTER_ROLE = keccak256(\"QUOTER_ROLE\");\n\n /// @notice Role identifier for Prover's on-chain authentication in FastBridge.\n /// @dev Only addresses with this role can provide proofs that a FastBridge request has been relayed.\n bytes32 public constant PROVER_ROLE = keccak256(\"PROVER_ROLE\");\n\n /// @notice Role identifier for Guard's on-chain authentication in FastBridge.\n /// @dev Only addresses with this role can dispute submitted relay proofs during the dispute period.\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n\n /// @notice Role identifier for Canceler's on-chain authentication in FastBridge.\n /// @dev Only addresses with this role can cancel a FastBridge transaction without the cancel delay.\n bytes32 public constant CANCELER_ROLE = keccak256(\"CANCELER_ROLE\");\n\n /// @notice Role identifier for Governor's on-chain administrative authority.\n /// @dev Only addresses with this role can perform administrative tasks within the contract.\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n /// @notice Denominator for fee rates, represents 100%.\n uint256 public constant FEE_BPS = 1e6;\n /// @notice Maximum protocol fee rate: 1% on origin amount.\n uint256 public constant FEE_RATE_MAX = 0.01e6;\n\n /// @notice Minimum cancel delay that can be set by the governor.\n uint256 public constant MIN_CANCEL_DELAY = 1 hours;\n /// @notice Default cancel delay set during the contract deployment.\n uint256 public constant DEFAULT_CANCEL_DELAY = 1 days;\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Delay for a transaction after which it could be permisionlessly cancelled\n uint256 public cancelDelay;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Use ZapNative V2 requests instead.\n uint256 public immutable chainGasAmount = 0;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n _setCancelDelay(DEFAULT_CANCEL_DELAY);\n }\n\n /// @notice Allows the contract governor to set the cancel delay. The cancel delay is the time after the transaction\n /// deadline after which it can be permissionlessly cancelled, if it hasn't been proven by any of the Relayers.\n function setCancelDelay(uint256 newCancelDelay) external onlyRole(GOVERNOR_ROLE) {\n _setCancelDelay(newCancelDelay);\n }\n\n /// @notice Allows the contract governor to set the protocol fee rate. The protocol fee is taken from the origin\n /// amount only for completed and claimed transactions.\n /// @dev The protocol fee is abstracted away from the relayers, they always operate using the amounts after fees:\n /// what they see as the origin amount emitted in the log is what they get credited with.\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n if (newFeeRate \u003e FEE_RATE_MAX) revert FeeRateAboveMax();\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n /// @notice Allows the contract governor to sweep the accumulated protocol fees in the contract.\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n emit FeesSwept(token, recipient, feeAmount);\n /// Sweep the fees as the last transaction action\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(recipient), feeAmount);\n } else {\n IERC20(token).safeTransfer(recipient, feeAmount);\n }\n }\n\n /// @notice Internal function to set the cancel delay. Security checks are performed outside of this function.\n function _setCancelDelay(uint256 newCancelDelay) private {\n if (newCancelDelay \u003c MIN_CANCEL_DELAY) revert CancelDelayBelowMin();\n uint256 oldCancelDelay = cancelDelay;\n cancelDelay = newCancelDelay;\n emit CancelDelayUpdated(oldCancelDelay, newCancelDelay);\n }\n}\n\n// contracts/FastBridgeV2.sol\n\n/// @notice FastBridgeV2 is a contract for bridging tokens across chains.\ncontract FastBridgeV2 is AdminV2, MulticallTarget, IFastBridgeV2, IFastBridgeV2Errors {\n using BridgeTransactionV2Lib for bytes;\n using SafeERC20 for IERC20;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n /// @notice Maximum length of accepted zapData\n uint256 public constant MAX_ZAP_DATA_LENGTH = 2 ** 16 - 1;\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeTxDetails) public bridgeTxDetails;\n /// @notice Relay details on destination chain\n mapping(bytes32 =\u003e BridgeRelay) public bridgeRelayDetails;\n /// @notice Unique bridge nonces tracked per originSender\n mapping(address =\u003e uint256) public senderNonces;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Replaced by senderNonces\n uint256 public immutable nonce = 0;\n /// @notice the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) AdminV2(_owner) {\n deployBlock = block.number;\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n bridge({\n params: params,\n paramsV2: BridgeParamsV2({\n quoteRelayer: address(0),\n quoteExclusivitySeconds: 0,\n quoteId: bytes(\"\"),\n zapNative: 0,\n zapData: bytes(\"\")\n })\n });\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes calldata request) external payable {\n // relay override will validate the request\n relay({request: request, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes calldata request, bytes32 destTxHash) external {\n request.validateV2();\n prove({transactionId: keccak256(request), destTxHash: destTxHash, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridgeV2\n function claim(bytes calldata request) external {\n // claim override will validate the request\n claim({request: request, to: address(0)});\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Aggregate the read operations from the same storage slot\n address disputedRelayer = $.proofRelayer;\n BridgeStatus status = $.status;\n uint56 proofBlockTimestamp = $.proofBlockTimestamp;\n // Can only dispute a RELAYER_PROVED transaction within the dispute period\n if (status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(proofBlockTimestamp) \u003e DISPUTE_PERIOD) {\n revert DisputePeriodPassed();\n }\n // Update status to REQUESTED and delete the disputed proof details\n // Note: these are storage writes\n $.status = BridgeStatus.REQUESTED;\n $.proofRelayer = address(0);\n $.proofBlockTimestamp = 0;\n\n emit BridgeProofDisputed(transactionId, disputedRelayer);\n }\n\n /// Note: this function is deprecated and will be removed in a future version.\n /// @inheritdoc IFastBridge\n function refund(bytes calldata request) external {\n cancel(request);\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // The correct relayer can only claim a RELAYER_PROVED transaction after the dispute period\n if ($.status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if ($.proofRelayer != relayer) revert SenderIncorrect();\n return _timeSince($.proofBlockTimestamp) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n /// @dev This method is added to achieve backwards compatibility with decoding requests into V1 structs:\n /// - `zapNative` is partially reported as a zero/non-zero flag\n /// - `zapData` is ignored\n /// In order to process all kinds of requests use getBridgeTransactionV2 instead.\n function getBridgeTransaction(bytes calldata request) external view returns (BridgeTransaction memory) {\n // Try decoding into V2 struct first. This will revert if V1 struct is passed\n try this.getBridgeTransactionV2(request) returns (BridgeTransactionV2 memory txV2) {\n // Note: we entirely ignore the zapData field, as it was not present in V1\n return BridgeTransaction({\n originChainId: txV2.originChainId,\n destChainId: txV2.destChainId,\n originSender: txV2.originSender,\n destRecipient: txV2.destRecipient,\n originToken: txV2.originToken,\n destToken: txV2.destToken,\n originAmount: txV2.originAmount,\n destAmount: txV2.destAmount,\n originFeeAmount: txV2.originFeeAmount,\n sendChainGas: txV2.zapNative != 0,\n deadline: txV2.deadline,\n nonce: txV2.nonce\n });\n } catch {\n // Fallback to V1 struct\n return abi.decode(request, (BridgeTransaction));\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function getBridgeTransactionV2(bytes calldata request) external pure returns (BridgeTransactionV2 memory) {\n request.validateV2();\n return BridgeTransactionV2Lib.decodeV2(request);\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) public payable {\n int256 exclusivityEndTime = 0;\n // if relayer exclusivity is not intended for this bridge, set exclusivityEndTime to static zero\n // otherwise, set exclusivity to expire at the current block ts offset by quoteExclusivitySeconds\n if (paramsV2.quoteRelayer != address(0)) {\n exclusivityEndTime = int256(block.timestamp) + paramsV2.quoteExclusivitySeconds;\n }\n _validateBridgeParams(params, paramsV2, exclusivityEndTime);\n\n // transfer tokens to bridge contract\n /// @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _takeBridgedUserAsset(params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) {\n originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n }\n\n // set status to requested\n bytes memory request = BridgeTransactionV2Lib.encodeV2(\n BridgeTransactionV2({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n deadline: params.deadline,\n nonce: senderNonces[params.sender]++, // increment nonce on every bridge\n exclusivityRelayer: paramsV2.quoteRelayer,\n // We checked exclusivityEndTime to be in range [0 .. params.deadline] above, so can safely cast\n exclusivityEndTime: uint256(exclusivityEndTime),\n zapNative: paramsV2.zapNative,\n zapData: paramsV2.zapData\n })\n );\n bytes32 transactionId = keccak256(request);\n // Note: the tx status will be updated throughout the tx lifecycle, while destChainId is set once here\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n bridgeTxDetails[transactionId].destChainId = params.dstChainId;\n\n emit BridgeRequested({\n transactionId: transactionId,\n sender: params.sender,\n request: request,\n destChainId: params.dstChainId,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n sendChainGas: paramsV2.zapNative != 0\n });\n emit BridgeQuoteDetails(transactionId, paramsV2.quoteId);\n }\n\n /// @inheritdoc IFastBridgeV2\n function relay(bytes calldata request, address relayer) public payable {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n _validateRelayParams(request, transactionId, relayer);\n // mark bridge transaction as relayed\n bridgeRelayDetails[transactionId] =\n BridgeRelay({blockNumber: uint48(block.number), blockTimestamp: uint48(block.timestamp), relayer: relayer});\n\n // transfer tokens to recipient on destination chain and trigger Zap if requested\n address to = request.destRecipient();\n address token = request.destToken();\n uint256 amount = request.destAmount();\n uint256 zapNative = request.zapNative();\n\n // Emit the event before any external calls\n emit BridgeRelayed({\n transactionId: transactionId,\n relayer: relayer,\n to: to,\n originChainId: request.originChainId(),\n originToken: request.originToken(),\n destToken: token,\n originAmount: request.originAmount(),\n destAmount: amount,\n chainGasAmount: zapNative\n });\n\n // All state changes have been done at this point, can proceed to the external calls.\n // This follows the checks-effects-interactions pattern to mitigate potential reentrancy attacks.\n if (token == NATIVE_GAS_TOKEN) {\n // For the native gas token, additional zapNative is not allowed\n if (zapNative != 0) revert ZapNativeNotSupported();\n // Check that the correct msg.value was sent\n if (msg.value != amount) revert MsgValueIncorrect();\n // Don't do a native transfer yet: we will handle it alongside the Zap below\n } else {\n // For ERC20s, we check that the correct msg.value was sent\n if (msg.value != zapNative) revert MsgValueIncorrect();\n // We need to transfer the tokens from the Relayer to the recipient first before performing an\n // optional post-transfer Zap.\n IERC20(token).safeTransferFrom(msg.sender, to, amount);\n }\n // At this point we have done:\n // - Transferred the requested amount of ERC20 tokens to the recipient.\n // At this point we have confirmed:\n // - For ERC20s: msg.value matches the requested zapNative amount.\n // - For the native gas token: msg.value matches the requested destAmount.\n // Remaining optional things to do:\n // - Forward the full msg.value to the recipient (if non-zero).\n // - Trigger a Zap (if zapData is present).\n bytes calldata zapData = request.zapData();\n if (zapData.length != 0) {\n // Zap Data is present: Zap has been requested by the recipient. Trigger it forwarding the full msg.value.\n\n // Note: if token has a fee on transfers, the recipient will have received less than `amount`.\n // This is a very niche edge case and should be handled by the recipient contract.\n _triggerZapWithChecks({recipient: to, token: token, amount: amount, zapData: zapData});\n } else if (msg.value != 0) {\n // Zap Data is missing, but msg.value was sent. This could happen in two different cases:\n // - Relay with the native gas token is happening.\n // - Relay with ERC20 is happening, with a `zapNative \u003e 0` request.\n // In both cases, we need to transfer the full msg.value to the recipient.\n Address.sendValue(payable(to), msg.value);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) public onlyRole(PROVER_ROLE) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n\n // Can only prove a REQUESTED transaction\n if ($.status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n // Update status to RELAYER_PROVED and store the proof details\n // Note: these are storage writes\n $.status = BridgeStatus.RELAYER_PROVED;\n $.proofBlockTimestamp = uint56(block.timestamp);\n $.proofRelayer = relayer;\n\n emit BridgeProofProvided(transactionId, relayer, destTxHash);\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes calldata request, address to) public {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Aggregate the read operations from the same storage slot\n address proofRelayer = $.proofRelayer;\n BridgeStatus status = $.status;\n uint56 proofBlockTimestamp = $.proofBlockTimestamp;\n\n // Can only claim a RELAYER_PROVED transaction after the dispute period\n if (status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(proofBlockTimestamp) \u003c= DISPUTE_PERIOD) {\n revert DisputePeriodNotPassed();\n }\n\n if (to == address(0)) {\n // Anyone could claim the funds to the proven relayer on their behalf\n to = proofRelayer;\n } else if (proofRelayer != msg.sender) {\n // Only the proven relayer could specify an address to claim the funds to\n revert SenderIncorrect();\n }\n\n // Update status to RELAYER_CLAIMED and transfer the origin collateral to the specified claim address\n // Note: this is a storage write\n $.status = BridgeStatus.RELAYER_CLAIMED;\n\n address token = request.originToken();\n uint256 amount = request.originAmount();\n // Update protocol fees if origin fee amount exists\n uint256 originFeeAmount = request.originFeeAmount();\n if (originFeeAmount \u003e 0) protocolFees[token] += originFeeAmount;\n // Emit the event before any external calls\n emit BridgeDepositClaimed(transactionId, proofRelayer, to, token, amount);\n // Complete the relayer claim as the last transaction action\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(to), amount);\n } else {\n IERC20(token).safeTransfer(to, amount);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function cancel(bytes calldata request) public {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Can only cancel a REQUESTED transaction after its deadline expires\n if ($.status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n uint256 deadline = request.deadline();\n // Permissionless cancel is only allowed after `cancelDelay` on top of the deadline\n if (!hasRole(CANCELER_ROLE, msg.sender)) deadline += cancelDelay;\n if (block.timestamp \u003c= deadline) revert DeadlineNotExceeded();\n // Update status to REFUNDED and return the full amount (collateral + protocol fees) to the original sender.\n // The protocol fees are only updated when the transaction is claimed, so we don't need to update them here.\n // Note: this is a storage write\n $.status = BridgeStatus.REFUNDED;\n\n address to = request.originSender();\n address token = request.originToken();\n uint256 amount = request.originAmount() + request.originFeeAmount();\n // Emit the event before any external calls\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n // Complete the user cancel as the last transaction action\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(to), amount);\n } else {\n IERC20(token).safeTransfer(to, amount);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeStatuses(bytes32 transactionId) public view returns (BridgeStatus status) {\n return bridgeTxDetails[transactionId].status;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeProofs(bytes32 transactionId) public view returns (uint96 timestamp, address relayer) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n\n timestamp = $.proofBlockTimestamp;\n relayer = $.proofRelayer;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeRelays(bytes32 transactionId) public view returns (bool) {\n // has this transactionId been relayed?\n return bridgeRelayDetails[transactionId].relayer != address(0);\n }\n\n /// @notice Takes the bridged asset from the user into FastBridgeV2 custody. It will be later\n /// claimed by the relayer who completed the relay on destination chain, or transferred back to the user\n /// via the cancel function should no one complete the relay.\n function _takeBridgedUserAsset(address token, uint256 amount) internal returns (uint256 amountTaken) {\n if (token == NATIVE_GAS_TOKEN) {\n // For the native gas token, we just need to check that the supplied msg.value is correct.\n // Supplied `msg.value` is already in FastBridgeV2 custody.\n if (amount != msg.value) revert MsgValueIncorrect();\n amountTaken = msg.value;\n } else {\n // For ERC20s, token is explicitly transferred from the user to FastBridgeV2.\n // We don't allow non-zero `msg.value` to avoid extra funds from being stuck in FastBridgeV2.\n if (msg.value != 0) revert MsgValueIncorrect();\n // Throw an explicit error if the provided token address is not a contract\n if (token.code.length == 0) revert TokenNotContract();\n amountTaken = IERC20(token).balanceOf(address(this));\n IERC20(token).safeTransferFrom(msg.sender, address(this), amount);\n // Use the balance difference as the amount taken in case of fee on transfer tokens.\n amountTaken = IERC20(token).balanceOf(address(this)) - amountTaken;\n }\n }\n\n /// @notice Calls the Recipient's hook function with the specified zapData and performs\n /// all the necessary checks for the returned value.\n function _triggerZapWithChecks(address recipient, address token, uint256 amount, bytes calldata zapData) internal {\n // This will bubble any revert messages from the hook function\n bytes memory returnData = Address.functionCallWithValue({\n target: recipient,\n data: abi.encodeCall(IZapRecipient.zap, (token, amount, zapData)),\n // Note: see `relay()` for reasoning behind passing msg.value\n value: msg.value\n });\n // Explicit revert if no return data at all\n if (returnData.length == 0) revert RecipientNoReturnValue();\n // Check that exactly a single return value was returned\n if (returnData.length != 32) revert RecipientIncorrectReturnValue();\n // Return value should be abi-encoded hook function selector\n if (bytes32(returnData) != bytes32(IZapRecipient.zap.selector)) {\n revert RecipientIncorrectReturnValue();\n }\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint56(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint56).max but\n /// proof.timestamp \u003c type(uint56).max via unchecked statement\n /// @param proofBlockTimestamp The bridge proof block timestamp\n /// @return delta Time delta since proof submitted\n function _timeSince(uint56 proofBlockTimestamp) internal view returns (uint256 delta) {\n unchecked {\n delta = uint56(block.timestamp) - proofBlockTimestamp;\n }\n }\n\n /// @notice Performs all the necessary checks for a bridge to happen.\n /// @dev There's no good way to refactor this function to reduce cyclomatic complexity due to\n /// the number of checks that need to be performed, so we skip the code-complexity rule here.\n // solhint-disable-next-line code-complexity\n function _validateBridgeParams(\n BridgeParams memory params,\n BridgeParamsV2 memory paramsV2,\n int256 exclusivityEndTime\n )\n internal\n view\n {\n // Check V1 (legacy) params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.sender == address(0) || params.to == address(0)) revert ZeroAddress();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n // Check V2 params\n if (paramsV2.zapData.length \u003e MAX_ZAP_DATA_LENGTH) revert ZapDataLengthAboveMax();\n if (paramsV2.zapNative != 0 \u0026\u0026 params.destToken == NATIVE_GAS_TOKEN) {\n revert ZapNativeNotSupported();\n }\n // exclusivityEndTime must be in range [0 .. params.deadline]\n if (exclusivityEndTime \u003c 0 || exclusivityEndTime \u003e int256(params.deadline)) {\n revert ExclusivityParamsIncorrect();\n }\n }\n\n /// @notice Performs all the necessary checks for a relay to happen.\n function _validateRelayParams(bytes calldata request, bytes32 transactionId, address relayer) internal view {\n if (relayer == address(0)) revert ZeroAddress();\n // Check if the transaction has already been relayed\n if (bridgeRelays(transactionId)) revert TransactionRelayed();\n if (request.destChainId() != block.chainid) revert ChainIncorrect();\n // Check the deadline for relay to happen\n if (block.timestamp \u003e request.deadline()) revert DeadlineExceeded();\n // Check the exclusivity period, if it is still ongoing\n address exclRelayer = request.exclusivityRelayer();\n if (exclRelayer != address(0) \u0026\u0026 exclRelayer != relayer \u0026\u0026 block.timestamp \u003c= request.exclusivityEndTime()) {\n revert ExclusivityPeriodNotPassed();\n }\n }\n}\n","language":"Solidity","languageVersion":"0.8.24","compilerVersion":"0.8.24","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"","srcMapRuntime":"","abiDefinition":[{"inputs":[],"name":"AccessControlBadConfirmation","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"bytes32","name":"neededRole","type":"bytes32"}],"name":"AccessControlUnauthorizedAccount","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"previousAdminRole","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"newAdminRole","type":"bytes32"}],"name":"RoleAdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleRevoked","type":"event"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleAdmin","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"grantRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"hasRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"callerConfirmation","type":"address"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"revokeRole","outputs":[],"stateMutability":"nonpayable","type":"function"}],"userDoc":{"kind":"user","methods":{},"version":1},"developerDoc":{"details":"External interface of AccessControl declared to support ERC165 detection.","errors":{"AccessControlBadConfirmation()":[{"details":"The caller of a function is not the expected one. NOTE: Don't confuse with {AccessControlUnauthorizedAccount}."}],"AccessControlUnauthorizedAccount(address,bytes32)":[{"details":"The `account` is missing a role."}]},"events":{"RoleAdminChanged(bytes32,bytes32,bytes32)":{"details":"Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole` `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite {RoleAdminChanged} not being emitted signaling this."},"RoleGranted(bytes32,address,address)":{"details":"Emitted when `account` is granted `role`. `sender` is the account that originated the contract call, an admin role bearer except when using {AccessControl-_setupRole}."},"RoleRevoked(bytes32,address,address)":{"details":"Emitted when `account` is revoked `role`. `sender` is the account that originated the contract call: - if using `revokeRole`, it is the admin role bearer - if using `renounceRole`, it is the role bearer (i.e. `account`)"}},"kind":"dev","methods":{"getRoleAdmin(bytes32)":{"details":"Returns the admin role that controls `role`. See {grantRole} and {revokeRole}. To change a role's admin, use {AccessControl-_setRoleAdmin}."},"grantRole(bytes32,address)":{"details":"Grants `role` to `account`. If `account` had not been already granted `role`, emits a {RoleGranted} event. Requirements: - the caller must have ``role``'s admin role."},"hasRole(bytes32,address)":{"details":"Returns `true` if `account` has been granted `role`."},"renounceRole(bytes32,address)":{"details":"Revokes `role` from the calling account. Roles are often managed via {grantRole} and {revokeRole}: this function's purpose is to provide a mechanism for accounts to lose their privileges if they are compromised (such as when a trusted device is misplaced). If the calling account had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must be `callerConfirmation`."},"revokeRole(bytes32,address)":{"details":"Revokes `role` from `account`. If `account` had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must have ``role``'s admin role."}},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[],\"name\":\"AccessControlBadConfirmation\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"neededRole\",\"type\":\"bytes32\"}],\"name\":\"AccessControlUnauthorizedAccount\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"previousAdminRole\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"newAdminRole\",\"type\":\"bytes32\"}],\"name\":\"RoleAdminChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleGranted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleRevoked\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"}],\"name\":\"getRoleAdmin\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"grantRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"hasRole\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"callerConfirmation\",\"type\":\"address\"}],\"name\":\"renounceRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"revokeRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"details\":\"External interface of AccessControl declared to support ERC165 detection.\",\"errors\":{\"AccessControlBadConfirmation()\":[{\"details\":\"The caller of a function is not the expected one. NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\"}],\"AccessControlUnauthorizedAccount(address,bytes32)\":[{\"details\":\"The `account` is missing a role.\"}]},\"events\":{\"RoleAdminChanged(bytes32,bytes32,bytes32)\":{\"details\":\"Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole` `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite {RoleAdminChanged} not being emitted signaling this.\"},\"RoleGranted(bytes32,address,address)\":{\"details\":\"Emitted when `account` is granted `role`. `sender` is the account that originated the contract call, an admin role bearer except when using {AccessControl-_setupRole}.\"},\"RoleRevoked(bytes32,address,address)\":{\"details\":\"Emitted when `account` is revoked `role`. `sender` is the account that originated the contract call: - if using `revokeRole`, it is the admin role bearer - if using `renounceRole`, it is the role bearer (i.e. `account`)\"}},\"kind\":\"dev\",\"methods\":{\"getRoleAdmin(bytes32)\":{\"details\":\"Returns the admin role that controls `role`. See {grantRole} and {revokeRole}. To change a role's admin, use {AccessControl-_setRoleAdmin}.\"},\"grantRole(bytes32,address)\":{\"details\":\"Grants `role` to `account`. If `account` had not been already granted `role`, emits a {RoleGranted} event. Requirements: - the caller must have ``role``'s admin role.\"},\"hasRole(bytes32,address)\":{\"details\":\"Returns `true` if `account` has been granted `role`.\"},\"renounceRole(bytes32,address)\":{\"details\":\"Revokes `role` from the calling account. Roles are often managed via {grantRole} and {revokeRole}: this function's purpose is to provide a mechanism for accounts to lose their privileges if they are compromised (such as when a trusted device is misplaced). If the calling account had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must be `callerConfirmation`.\"},\"revokeRole(bytes32,address)\":{\"details\":\"Revokes `role` from `account`. If `account` had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must have ``role``'s admin role.\"}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeV2.sol\":\"IAccessControl\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeV2.sol\":{\"keccak256\":\"0xac79c463688a682ca706a4ef95e7817b83548cdfa8182ba0426ac7e5e07613d8\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://b3ecb7097381287cafc3a73f3a2bb03565115ebb682a85064e0b0dc2f7e2919d\",\"dweb:/ipfs/QmatruW3nYZTksf3CeQ8wwiAG4c7xoEJBEp6drHPtFLBRK\"]}},\"version\":1}"},"hashes":{"getRoleAdmin(bytes32)":"248a9ca3","grantRole(bytes32,address)":"2f2ff15d","hasRole(bytes32,address)":"91d14854","renounceRole(bytes32,address)":"36568abe","revokeRole(bytes32,address)":"d547741f"}},"solidity/FastBridgeV2.sol:IAccessControlEnumerable":{"code":"0x","runtime-code":"0x","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.24 ^0.8.20 ^0.8.4;\n\n// contracts/interfaces/IAdminV2.sol\n\ninterface IAdminV2 {\n event CancelDelayUpdated(uint256 oldCancelDelay, uint256 newCancelDelay);\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n function setCancelDelay(uint256 newCancelDelay) external;\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n}\n\n// contracts/interfaces/IAdminV2Errors.sol\n\ninterface IAdminV2Errors {\n error CancelDelayBelowMin();\n error FeeRateAboveMax();\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IFastBridgeV2Errors.sol\n\ninterface IFastBridgeV2Errors {\n error AmountIncorrect();\n error ChainIncorrect();\n error ExclusivityParamsIncorrect();\n error MsgValueIncorrect();\n error SenderIncorrect();\n error StatusIncorrect();\n error TokenNotContract();\n error ZapDataLengthAboveMax();\n error ZapNativeNotSupported();\n error ZeroAddress();\n\n error RecipientIncorrectReturnValue();\n error RecipientNoReturnValue();\n\n error DeadlineExceeded();\n error DeadlineNotExceeded();\n error DeadlineTooShort();\n error DisputePeriodNotPassed();\n error DisputePeriodPassed();\n error ExclusivityPeriodNotPassed();\n\n error TransactionRelayed();\n}\n\n// contracts/interfaces/IMulticallTarget.sol\n\n/// @notice Interface for a contract that can be called multiple times by the same caller. Inspired by MulticallV3:\n/// https://github.com/mds1/multicall/blob/master/src/Multicall3.sol\ninterface IMulticallTarget {\n struct Result {\n bool success;\n bytes returnData;\n }\n\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external;\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results);\n}\n\n// contracts/interfaces/IZapRecipient.sol\n\ninterface IZapRecipient {\n function zap(address token, uint256 amount, bytes memory zapData) external payable returns (bytes4);\n}\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// contracts/interfaces/IFastBridgeV2.sol\n\ninterface IFastBridgeV2 is IFastBridge {\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n struct BridgeTxDetails {\n BridgeStatus status;\n uint32 destChainId;\n uint56 proofBlockTimestamp;\n address proofRelayer;\n }\n\n struct BridgeRelay {\n uint48 blockNumber;\n uint48 blockTimestamp;\n address relayer;\n }\n\n /// @notice New params introduced in the FastBridgeV2.\n /// We are passing fields from the older BridgeParams struct outside of this struct\n /// for backwards compatibility.\n /// Note: quoteRelayer and quoteExclusivitySeconds are either both zero (indicating no exclusivity)\n /// or both non-zero (indicating exclusivity for the given period).\n /// Note: zapNative \u003e 0 can NOT be used with destToken = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE (native token)\n /// @param quoteRelayer Relayer that provided the quote for the transaction\n /// @param quoteExclusivitySeconds Period of time the quote relayer is guaranteed exclusivity after user's deposit\n /// @param quoteId Unique quote identifier used for tracking the quote\n /// @param zapNative ETH value to send to the recipient (if any)\n /// @param zapData Parameters for the Zap to the destination recipient (if any)\n struct BridgeParamsV2 {\n address quoteRelayer;\n int256 quoteExclusivitySeconds;\n bytes quoteId;\n uint256 zapNative;\n bytes zapData;\n }\n\n /// @notice Updated bridge transaction struct to include parameters introduced in FastBridgeV2.\n /// Note: only `exclusivityRelayer` can fill such a transaction until `exclusivityEndTime`.\n struct BridgeTransactionV2 {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n // Note: sendChainGas flag from V1 is deprecated\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n address exclusivityRelayer;\n uint256 exclusivityEndTime;\n uint256 zapNative; // ETH value to send to the recipient (if any)\n bytes zapData; // data to pass for the Zap action (if any)\n }\n\n event BridgeQuoteDetails(bytes32 indexed transactionId, bytes quoteId);\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability\n /// to provide temporary exclusivity fill rights for the quote relayer.\n /// @param params The parameters required to bridge\n /// @param paramsV2 The parameters for exclusivity fill rights (optional, can be left empty)\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function relay(bytes memory request, address relayer) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param transactionId The transaction id associated with the encoded bridge transaction to prove\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital.\n /// @notice Can only send funds to the relayer address on the proof.\n /// @param request The encoded bridge transaction to claim on origin chain\n function claim(bytes memory request) external;\n\n /// @notice Cancels an outstanding bridge transaction in case optimistic bridging failed and returns the full amount\n /// to the original sender.\n /// @param request The encoded bridge transaction to refund\n function cancel(bytes memory request) external;\n\n /// @notice Checks if a transaction has been relayed\n /// @param transactionId The ID of the transaction to check\n /// @return True if the transaction has been relayed, false otherwise\n function bridgeRelays(bytes32 transactionId) external view returns (bool);\n\n /// @notice Returns the status of a bridge transaction\n /// @param transactionId The ID of the bridge transaction\n /// @return BridgeStatus Status of the bridge transaction\n function bridgeStatuses(bytes32 transactionId) external view returns (BridgeStatus);\n\n /// @notice Returns the timestamp and relayer of a bridge proof\n /// @param transactionId The ID of the bridge transaction\n /// @return timestamp The timestamp of the bridge proof\n /// @return relayer The relayer address of the bridge proof\n function bridgeProofs(bytes32 transactionId) external view returns (uint96 timestamp, address relayer);\n\n /// @notice Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\n /// @param request The bridge request to decode\n function getBridgeTransactionV2(bytes memory request) external view returns (BridgeTransactionV2 memory);\n}\n\n// contracts/utils/MulticallTarget.sol\n\n// solhint-disable avoid-low-level-calls\n/// @notice Template for a contract that supports batched calls (preserving the msg.sender).\n/// Only calls with zero msg.value could be batched.\nabstract contract MulticallTarget is IMulticallTarget {\n error MulticallTarget__UndeterminedRevert();\n\n /// @notice Perform a batched call to this contract, preserving the msg.sender.\n /// The return data from each call is discarded.\n /// @dev The method is non-payable, so only calls with `msg.value == 0` could be batched.\n /// It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag.\n /// Otherwise, the whole batch call will be reverted with the original revert reason.\n /// @param data List of abi-encoded calldata for the calls to perform.\n /// @param ignoreReverts Whether to ignore the revert errors from the calls.\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external {\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\n if (!success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(result);\n }\n }\n }\n\n /// @notice Perform a batched call to this contract, preserving the msg.sender.\n /// The return data from each call is preserved.\n /// @dev The method is non-payable, so only calls with `msg.value == 0` could be batched.\n /// It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag.\n /// Otherwise, the whole batch call will be reverted with the original revert reason.\n /// @param data List of abi-encoded calldata for the calls to perform.\n /// @param ignoreReverts Whether to ignore the revert errors from the calls.\n /// @return results List of results from the calls: `(success, returnData)`.\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results)\n {\n results = new Result[](data.length);\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (results[i].success, results[i].returnData) = address(this).delegatecall(data[i]);\n if (!results[i].success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(results[i].returnData);\n }\n }\n }\n\n /// @dev Bubbles the revert message from the underlying call.\n /// Note: preserves the same custom error or revert string, if one was used.\n /// Source: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v5.0.2/contracts/utils/Address.sol#L143-L158\n function _bubbleRevert(bytes memory returnData) internal pure {\n // Look for revert reason and bubble it up if present\n if (returnData.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n // solhint-disable-next-line no-inline-assembly\n assembly {\n let returndata_size := mload(returnData)\n revert(add(32, returnData), returndata_size)\n }\n } else {\n revert MulticallTarget__UndeterminedRevert();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// contracts/libs/BridgeTransactionV2.sol\n\n// solhint-disable no-inline-assembly\nlibrary BridgeTransactionV2Lib {\n uint16 internal constant VERSION = 2;\n\n // Offsets of the fields in the packed BridgeTransactionV2 struct\n // uint16 version [000 .. 002)\n // uint32 originChainId [002 .. 006)\n // uint32 destChainId [006 .. 010)\n // address originSender [010 .. 030)\n // address destRecipient [030 .. 050)\n // address originToken [050 .. 070)\n // address destToken [070 .. 090)\n // uint256 originAmount [090 .. 122)\n // uint256 destAmount [122 .. 154)\n // uint256 originFeeAmount [154 .. 186)\n // uint256 deadline [186 .. 218)\n // uint256 nonce [218 .. 250)\n // address exclusivityRelayer [250 .. 270)\n // uint256 exclusivityEndTime [270 .. 302)\n // uint256 zapNative [302 .. 334)\n // bytes zapData [334 .. ***)\n\n // forgefmt: disable-start\n uint256 private constant OFFSET_ORIGIN_CHAIN_ID = 2;\n uint256 private constant OFFSET_DEST_CHAIN_ID = 6;\n uint256 private constant OFFSET_ORIGIN_SENDER = 10;\n uint256 private constant OFFSET_DEST_RECIPIENT = 30;\n uint256 private constant OFFSET_ORIGIN_TOKEN = 50;\n uint256 private constant OFFSET_DEST_TOKEN = 70;\n uint256 private constant OFFSET_ORIGIN_AMOUNT = 90;\n uint256 private constant OFFSET_DEST_AMOUNT = 122;\n uint256 private constant OFFSET_ORIGIN_FEE_AMOUNT = 154;\n uint256 private constant OFFSET_DEADLINE = 186;\n uint256 private constant OFFSET_NONCE = 218;\n uint256 private constant OFFSET_EXCLUSIVITY_RELAYER = 250;\n uint256 private constant OFFSET_EXCLUSIVITY_END_TIME = 270;\n uint256 private constant OFFSET_ZAP_NATIVE = 302;\n uint256 private constant OFFSET_ZAP_DATA = 334;\n // forgefmt: disable-end\n\n error BridgeTransactionV2__InvalidEncodedTx();\n error BridgeTransactionV2__UnsupportedVersion(uint16 version);\n\n /// @notice Validates the encoded transaction to be a tightly packed encoded payload for BridgeTransactionV2.\n /// @dev Checks the minimum length and the version, use this function before decoding any of the fields.\n function validateV2(bytes calldata encodedTx) internal pure {\n // Check the minimum length: must at least include all static fields.\n if (encodedTx.length \u003c OFFSET_ZAP_DATA) revert BridgeTransactionV2__InvalidEncodedTx();\n // Once we validated the length, we can be sure that the version field is present.\n uint16 version_ = version(encodedTx);\n if (version_ != VERSION) revert BridgeTransactionV2__UnsupportedVersion(version_);\n }\n\n /// @notice Encodes the BridgeTransactionV2 struct by tightly packing the fields.\n /// @dev `abi.decode` will not work as a result of the tightly packed fields. Use `decodeV2` to decode instead.\n function encodeV2(IFastBridgeV2.BridgeTransactionV2 memory bridgeTx) internal pure returns (bytes memory) {\n // We split the encoding into two parts to avoid stack-too-deep error\n bytes memory firstPart = abi.encodePacked(\n VERSION,\n bridgeTx.originChainId,\n bridgeTx.destChainId,\n bridgeTx.originSender,\n bridgeTx.destRecipient,\n bridgeTx.originToken,\n bridgeTx.destToken,\n bridgeTx.originAmount\n );\n return abi.encodePacked(\n firstPart,\n bridgeTx.destAmount,\n bridgeTx.originFeeAmount,\n // Note: we skip the deprecated `sendChainGas` flag, which was present in BridgeTransaction V1\n bridgeTx.deadline,\n bridgeTx.nonce,\n // New V2 fields: exclusivity\n bridgeTx.exclusivityRelayer,\n bridgeTx.exclusivityEndTime,\n // New V2 fields: Zap\n bridgeTx.zapNative,\n bridgeTx.zapData\n );\n }\n\n /// @notice Decodes the BridgeTransactionV2 struct from the encoded transaction.\n /// @dev Encoded BridgeTransactionV2 struct must be tightly packed.\n /// Use `validateV2` before decoding to ensure the encoded transaction is valid.\n function decodeV2(bytes calldata encodedTx)\n internal\n pure\n returns (IFastBridgeV2.BridgeTransactionV2 memory bridgeTx)\n {\n bridgeTx.originChainId = originChainId(encodedTx);\n bridgeTx.destChainId = destChainId(encodedTx);\n bridgeTx.originSender = originSender(encodedTx);\n bridgeTx.destRecipient = destRecipient(encodedTx);\n bridgeTx.originToken = originToken(encodedTx);\n bridgeTx.destToken = destToken(encodedTx);\n bridgeTx.originAmount = originAmount(encodedTx);\n bridgeTx.destAmount = destAmount(encodedTx);\n bridgeTx.originFeeAmount = originFeeAmount(encodedTx);\n bridgeTx.deadline = deadline(encodedTx);\n bridgeTx.nonce = nonce(encodedTx);\n bridgeTx.exclusivityRelayer = exclusivityRelayer(encodedTx);\n bridgeTx.exclusivityEndTime = exclusivityEndTime(encodedTx);\n bridgeTx.zapNative = zapNative(encodedTx);\n bridgeTx.zapData = zapData(encodedTx);\n }\n\n /// @notice Extracts the version from the encoded transaction.\n function version(bytes calldata encodedTx) internal pure returns (uint16 version_) {\n // Load 32 bytes from the start and shift it 240 bits to the right to get the highest 16 bits.\n assembly {\n version_ := shr(240, calldataload(encodedTx.offset))\n }\n }\n\n /// @notice Extracts the origin chain ID from the encoded transaction.\n function originChainId(bytes calldata encodedTx) internal pure returns (uint32 originChainId_) {\n // Load 32 bytes from the offset and shift it 224 bits to the right to get the highest 32 bits.\n assembly {\n originChainId_ := shr(224, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_CHAIN_ID)))\n }\n }\n\n /// @notice Extracts the destination chain ID from the encoded transaction.\n function destChainId(bytes calldata encodedTx) internal pure returns (uint32 destChainId_) {\n // Load 32 bytes from the offset and shift it 224 bits to the right to get the highest 32 bits.\n assembly {\n destChainId_ := shr(224, calldataload(add(encodedTx.offset, OFFSET_DEST_CHAIN_ID)))\n }\n }\n\n /// @notice Extracts the origin sender from the encoded transaction.\n function originSender(bytes calldata encodedTx) internal pure returns (address originSender_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n originSender_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_SENDER)))\n }\n }\n\n /// @notice Extracts the destination recipient from the encoded transaction.\n function destRecipient(bytes calldata encodedTx) internal pure returns (address destRecipient_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n destRecipient_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_DEST_RECIPIENT)))\n }\n }\n\n /// @notice Extracts the origin token from the encoded transaction.\n function originToken(bytes calldata encodedTx) internal pure returns (address originToken_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n originToken_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_TOKEN)))\n }\n }\n\n /// @notice Extracts the destination token from the encoded transaction.\n function destToken(bytes calldata encodedTx) internal pure returns (address destToken_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n destToken_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_DEST_TOKEN)))\n }\n }\n\n /// @notice Extracts the origin amount from the encoded transaction.\n function originAmount(bytes calldata encodedTx) internal pure returns (uint256 originAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n originAmount_ := calldataload(add(encodedTx.offset, OFFSET_ORIGIN_AMOUNT))\n }\n }\n\n /// @notice Extracts the destination amount from the encoded transaction.\n function destAmount(bytes calldata encodedTx) internal pure returns (uint256 destAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n destAmount_ := calldataload(add(encodedTx.offset, OFFSET_DEST_AMOUNT))\n }\n }\n\n /// @notice Extracts the origin fee amount from the encoded transaction.\n function originFeeAmount(bytes calldata encodedTx) internal pure returns (uint256 originFeeAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n originFeeAmount_ := calldataload(add(encodedTx.offset, OFFSET_ORIGIN_FEE_AMOUNT))\n }\n }\n\n /// @notice Extracts the deadline from the encoded transaction.\n function deadline(bytes calldata encodedTx) internal pure returns (uint256 deadline_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n deadline_ := calldataload(add(encodedTx.offset, OFFSET_DEADLINE))\n }\n }\n\n /// @notice Extracts the nonce from the encoded transaction.\n function nonce(bytes calldata encodedTx) internal pure returns (uint256 nonce_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n nonce_ := calldataload(add(encodedTx.offset, OFFSET_NONCE))\n }\n }\n\n /// @notice Extracts the exclusivity relayer from the encoded transaction.\n function exclusivityRelayer(bytes calldata encodedTx) internal pure returns (address exclusivityRelayer_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n exclusivityRelayer_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_EXCLUSIVITY_RELAYER)))\n }\n }\n\n /// @notice Extracts the exclusivity end time from the encoded transaction.\n function exclusivityEndTime(bytes calldata encodedTx) internal pure returns (uint256 exclusivityEndTime_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n exclusivityEndTime_ := calldataload(add(encodedTx.offset, OFFSET_EXCLUSIVITY_END_TIME))\n }\n }\n\n /// @notice Extracts the Zap's native value from the encoded transaction.\n function zapNative(bytes calldata encodedTx) internal pure returns (uint256 zapNative_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n zapNative_ := calldataload(add(encodedTx.offset, OFFSET_ZAP_NATIVE))\n }\n }\n\n /// @notice Extracts the Zap's data from the encoded transaction.\n function zapData(bytes calldata encodedTx) internal pure returns (bytes calldata zapData_) {\n zapData_ = encodedTx[OFFSET_ZAP_DATA:];\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/AdminV2.sol\n\ncontract AdminV2 is AccessControlEnumerable, IAdminV2, IAdminV2Errors {\n using SafeERC20 for IERC20;\n\n /// @notice Address reserved for native gas token (ETH on Ethereum and most L2s, AVAX on Avalanche, etc)\n address public constant NATIVE_GAS_TOKEN = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Role identifier for Quoter API's off-chain authentication.\n /// @dev Only addresses with this role can post FastBridge quotes to the API.\n bytes32 public constant QUOTER_ROLE = keccak256(\"QUOTER_ROLE\");\n\n /// @notice Role identifier for Prover's on-chain authentication in FastBridge.\n /// @dev Only addresses with this role can provide proofs that a FastBridge request has been relayed.\n bytes32 public constant PROVER_ROLE = keccak256(\"PROVER_ROLE\");\n\n /// @notice Role identifier for Guard's on-chain authentication in FastBridge.\n /// @dev Only addresses with this role can dispute submitted relay proofs during the dispute period.\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n\n /// @notice Role identifier for Canceler's on-chain authentication in FastBridge.\n /// @dev Only addresses with this role can cancel a FastBridge transaction without the cancel delay.\n bytes32 public constant CANCELER_ROLE = keccak256(\"CANCELER_ROLE\");\n\n /// @notice Role identifier for Governor's on-chain administrative authority.\n /// @dev Only addresses with this role can perform administrative tasks within the contract.\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n /// @notice Denominator for fee rates, represents 100%.\n uint256 public constant FEE_BPS = 1e6;\n /// @notice Maximum protocol fee rate: 1% on origin amount.\n uint256 public constant FEE_RATE_MAX = 0.01e6;\n\n /// @notice Minimum cancel delay that can be set by the governor.\n uint256 public constant MIN_CANCEL_DELAY = 1 hours;\n /// @notice Default cancel delay set during the contract deployment.\n uint256 public constant DEFAULT_CANCEL_DELAY = 1 days;\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Delay for a transaction after which it could be permisionlessly cancelled\n uint256 public cancelDelay;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Use ZapNative V2 requests instead.\n uint256 public immutable chainGasAmount = 0;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n _setCancelDelay(DEFAULT_CANCEL_DELAY);\n }\n\n /// @notice Allows the contract governor to set the cancel delay. The cancel delay is the time after the transaction\n /// deadline after which it can be permissionlessly cancelled, if it hasn't been proven by any of the Relayers.\n function setCancelDelay(uint256 newCancelDelay) external onlyRole(GOVERNOR_ROLE) {\n _setCancelDelay(newCancelDelay);\n }\n\n /// @notice Allows the contract governor to set the protocol fee rate. The protocol fee is taken from the origin\n /// amount only for completed and claimed transactions.\n /// @dev The protocol fee is abstracted away from the relayers, they always operate using the amounts after fees:\n /// what they see as the origin amount emitted in the log is what they get credited with.\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n if (newFeeRate \u003e FEE_RATE_MAX) revert FeeRateAboveMax();\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n /// @notice Allows the contract governor to sweep the accumulated protocol fees in the contract.\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n emit FeesSwept(token, recipient, feeAmount);\n /// Sweep the fees as the last transaction action\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(recipient), feeAmount);\n } else {\n IERC20(token).safeTransfer(recipient, feeAmount);\n }\n }\n\n /// @notice Internal function to set the cancel delay. Security checks are performed outside of this function.\n function _setCancelDelay(uint256 newCancelDelay) private {\n if (newCancelDelay \u003c MIN_CANCEL_DELAY) revert CancelDelayBelowMin();\n uint256 oldCancelDelay = cancelDelay;\n cancelDelay = newCancelDelay;\n emit CancelDelayUpdated(oldCancelDelay, newCancelDelay);\n }\n}\n\n// contracts/FastBridgeV2.sol\n\n/// @notice FastBridgeV2 is a contract for bridging tokens across chains.\ncontract FastBridgeV2 is AdminV2, MulticallTarget, IFastBridgeV2, IFastBridgeV2Errors {\n using BridgeTransactionV2Lib for bytes;\n using SafeERC20 for IERC20;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n /// @notice Maximum length of accepted zapData\n uint256 public constant MAX_ZAP_DATA_LENGTH = 2 ** 16 - 1;\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeTxDetails) public bridgeTxDetails;\n /// @notice Relay details on destination chain\n mapping(bytes32 =\u003e BridgeRelay) public bridgeRelayDetails;\n /// @notice Unique bridge nonces tracked per originSender\n mapping(address =\u003e uint256) public senderNonces;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Replaced by senderNonces\n uint256 public immutable nonce = 0;\n /// @notice the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) AdminV2(_owner) {\n deployBlock = block.number;\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n bridge({\n params: params,\n paramsV2: BridgeParamsV2({\n quoteRelayer: address(0),\n quoteExclusivitySeconds: 0,\n quoteId: bytes(\"\"),\n zapNative: 0,\n zapData: bytes(\"\")\n })\n });\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes calldata request) external payable {\n // relay override will validate the request\n relay({request: request, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes calldata request, bytes32 destTxHash) external {\n request.validateV2();\n prove({transactionId: keccak256(request), destTxHash: destTxHash, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridgeV2\n function claim(bytes calldata request) external {\n // claim override will validate the request\n claim({request: request, to: address(0)});\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Aggregate the read operations from the same storage slot\n address disputedRelayer = $.proofRelayer;\n BridgeStatus status = $.status;\n uint56 proofBlockTimestamp = $.proofBlockTimestamp;\n // Can only dispute a RELAYER_PROVED transaction within the dispute period\n if (status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(proofBlockTimestamp) \u003e DISPUTE_PERIOD) {\n revert DisputePeriodPassed();\n }\n // Update status to REQUESTED and delete the disputed proof details\n // Note: these are storage writes\n $.status = BridgeStatus.REQUESTED;\n $.proofRelayer = address(0);\n $.proofBlockTimestamp = 0;\n\n emit BridgeProofDisputed(transactionId, disputedRelayer);\n }\n\n /// Note: this function is deprecated and will be removed in a future version.\n /// @inheritdoc IFastBridge\n function refund(bytes calldata request) external {\n cancel(request);\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // The correct relayer can only claim a RELAYER_PROVED transaction after the dispute period\n if ($.status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if ($.proofRelayer != relayer) revert SenderIncorrect();\n return _timeSince($.proofBlockTimestamp) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n /// @dev This method is added to achieve backwards compatibility with decoding requests into V1 structs:\n /// - `zapNative` is partially reported as a zero/non-zero flag\n /// - `zapData` is ignored\n /// In order to process all kinds of requests use getBridgeTransactionV2 instead.\n function getBridgeTransaction(bytes calldata request) external view returns (BridgeTransaction memory) {\n // Try decoding into V2 struct first. This will revert if V1 struct is passed\n try this.getBridgeTransactionV2(request) returns (BridgeTransactionV2 memory txV2) {\n // Note: we entirely ignore the zapData field, as it was not present in V1\n return BridgeTransaction({\n originChainId: txV2.originChainId,\n destChainId: txV2.destChainId,\n originSender: txV2.originSender,\n destRecipient: txV2.destRecipient,\n originToken: txV2.originToken,\n destToken: txV2.destToken,\n originAmount: txV2.originAmount,\n destAmount: txV2.destAmount,\n originFeeAmount: txV2.originFeeAmount,\n sendChainGas: txV2.zapNative != 0,\n deadline: txV2.deadline,\n nonce: txV2.nonce\n });\n } catch {\n // Fallback to V1 struct\n return abi.decode(request, (BridgeTransaction));\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function getBridgeTransactionV2(bytes calldata request) external pure returns (BridgeTransactionV2 memory) {\n request.validateV2();\n return BridgeTransactionV2Lib.decodeV2(request);\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) public payable {\n int256 exclusivityEndTime = 0;\n // if relayer exclusivity is not intended for this bridge, set exclusivityEndTime to static zero\n // otherwise, set exclusivity to expire at the current block ts offset by quoteExclusivitySeconds\n if (paramsV2.quoteRelayer != address(0)) {\n exclusivityEndTime = int256(block.timestamp) + paramsV2.quoteExclusivitySeconds;\n }\n _validateBridgeParams(params, paramsV2, exclusivityEndTime);\n\n // transfer tokens to bridge contract\n /// @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _takeBridgedUserAsset(params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) {\n originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n }\n\n // set status to requested\n bytes memory request = BridgeTransactionV2Lib.encodeV2(\n BridgeTransactionV2({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n deadline: params.deadline,\n nonce: senderNonces[params.sender]++, // increment nonce on every bridge\n exclusivityRelayer: paramsV2.quoteRelayer,\n // We checked exclusivityEndTime to be in range [0 .. params.deadline] above, so can safely cast\n exclusivityEndTime: uint256(exclusivityEndTime),\n zapNative: paramsV2.zapNative,\n zapData: paramsV2.zapData\n })\n );\n bytes32 transactionId = keccak256(request);\n // Note: the tx status will be updated throughout the tx lifecycle, while destChainId is set once here\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n bridgeTxDetails[transactionId].destChainId = params.dstChainId;\n\n emit BridgeRequested({\n transactionId: transactionId,\n sender: params.sender,\n request: request,\n destChainId: params.dstChainId,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n sendChainGas: paramsV2.zapNative != 0\n });\n emit BridgeQuoteDetails(transactionId, paramsV2.quoteId);\n }\n\n /// @inheritdoc IFastBridgeV2\n function relay(bytes calldata request, address relayer) public payable {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n _validateRelayParams(request, transactionId, relayer);\n // mark bridge transaction as relayed\n bridgeRelayDetails[transactionId] =\n BridgeRelay({blockNumber: uint48(block.number), blockTimestamp: uint48(block.timestamp), relayer: relayer});\n\n // transfer tokens to recipient on destination chain and trigger Zap if requested\n address to = request.destRecipient();\n address token = request.destToken();\n uint256 amount = request.destAmount();\n uint256 zapNative = request.zapNative();\n\n // Emit the event before any external calls\n emit BridgeRelayed({\n transactionId: transactionId,\n relayer: relayer,\n to: to,\n originChainId: request.originChainId(),\n originToken: request.originToken(),\n destToken: token,\n originAmount: request.originAmount(),\n destAmount: amount,\n chainGasAmount: zapNative\n });\n\n // All state changes have been done at this point, can proceed to the external calls.\n // This follows the checks-effects-interactions pattern to mitigate potential reentrancy attacks.\n if (token == NATIVE_GAS_TOKEN) {\n // For the native gas token, additional zapNative is not allowed\n if (zapNative != 0) revert ZapNativeNotSupported();\n // Check that the correct msg.value was sent\n if (msg.value != amount) revert MsgValueIncorrect();\n // Don't do a native transfer yet: we will handle it alongside the Zap below\n } else {\n // For ERC20s, we check that the correct msg.value was sent\n if (msg.value != zapNative) revert MsgValueIncorrect();\n // We need to transfer the tokens from the Relayer to the recipient first before performing an\n // optional post-transfer Zap.\n IERC20(token).safeTransferFrom(msg.sender, to, amount);\n }\n // At this point we have done:\n // - Transferred the requested amount of ERC20 tokens to the recipient.\n // At this point we have confirmed:\n // - For ERC20s: msg.value matches the requested zapNative amount.\n // - For the native gas token: msg.value matches the requested destAmount.\n // Remaining optional things to do:\n // - Forward the full msg.value to the recipient (if non-zero).\n // - Trigger a Zap (if zapData is present).\n bytes calldata zapData = request.zapData();\n if (zapData.length != 0) {\n // Zap Data is present: Zap has been requested by the recipient. Trigger it forwarding the full msg.value.\n\n // Note: if token has a fee on transfers, the recipient will have received less than `amount`.\n // This is a very niche edge case and should be handled by the recipient contract.\n _triggerZapWithChecks({recipient: to, token: token, amount: amount, zapData: zapData});\n } else if (msg.value != 0) {\n // Zap Data is missing, but msg.value was sent. This could happen in two different cases:\n // - Relay with the native gas token is happening.\n // - Relay with ERC20 is happening, with a `zapNative \u003e 0` request.\n // In both cases, we need to transfer the full msg.value to the recipient.\n Address.sendValue(payable(to), msg.value);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) public onlyRole(PROVER_ROLE) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n\n // Can only prove a REQUESTED transaction\n if ($.status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n // Update status to RELAYER_PROVED and store the proof details\n // Note: these are storage writes\n $.status = BridgeStatus.RELAYER_PROVED;\n $.proofBlockTimestamp = uint56(block.timestamp);\n $.proofRelayer = relayer;\n\n emit BridgeProofProvided(transactionId, relayer, destTxHash);\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes calldata request, address to) public {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Aggregate the read operations from the same storage slot\n address proofRelayer = $.proofRelayer;\n BridgeStatus status = $.status;\n uint56 proofBlockTimestamp = $.proofBlockTimestamp;\n\n // Can only claim a RELAYER_PROVED transaction after the dispute period\n if (status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(proofBlockTimestamp) \u003c= DISPUTE_PERIOD) {\n revert DisputePeriodNotPassed();\n }\n\n if (to == address(0)) {\n // Anyone could claim the funds to the proven relayer on their behalf\n to = proofRelayer;\n } else if (proofRelayer != msg.sender) {\n // Only the proven relayer could specify an address to claim the funds to\n revert SenderIncorrect();\n }\n\n // Update status to RELAYER_CLAIMED and transfer the origin collateral to the specified claim address\n // Note: this is a storage write\n $.status = BridgeStatus.RELAYER_CLAIMED;\n\n address token = request.originToken();\n uint256 amount = request.originAmount();\n // Update protocol fees if origin fee amount exists\n uint256 originFeeAmount = request.originFeeAmount();\n if (originFeeAmount \u003e 0) protocolFees[token] += originFeeAmount;\n // Emit the event before any external calls\n emit BridgeDepositClaimed(transactionId, proofRelayer, to, token, amount);\n // Complete the relayer claim as the last transaction action\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(to), amount);\n } else {\n IERC20(token).safeTransfer(to, amount);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function cancel(bytes calldata request) public {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Can only cancel a REQUESTED transaction after its deadline expires\n if ($.status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n uint256 deadline = request.deadline();\n // Permissionless cancel is only allowed after `cancelDelay` on top of the deadline\n if (!hasRole(CANCELER_ROLE, msg.sender)) deadline += cancelDelay;\n if (block.timestamp \u003c= deadline) revert DeadlineNotExceeded();\n // Update status to REFUNDED and return the full amount (collateral + protocol fees) to the original sender.\n // The protocol fees are only updated when the transaction is claimed, so we don't need to update them here.\n // Note: this is a storage write\n $.status = BridgeStatus.REFUNDED;\n\n address to = request.originSender();\n address token = request.originToken();\n uint256 amount = request.originAmount() + request.originFeeAmount();\n // Emit the event before any external calls\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n // Complete the user cancel as the last transaction action\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(to), amount);\n } else {\n IERC20(token).safeTransfer(to, amount);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeStatuses(bytes32 transactionId) public view returns (BridgeStatus status) {\n return bridgeTxDetails[transactionId].status;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeProofs(bytes32 transactionId) public view returns (uint96 timestamp, address relayer) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n\n timestamp = $.proofBlockTimestamp;\n relayer = $.proofRelayer;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeRelays(bytes32 transactionId) public view returns (bool) {\n // has this transactionId been relayed?\n return bridgeRelayDetails[transactionId].relayer != address(0);\n }\n\n /// @notice Takes the bridged asset from the user into FastBridgeV2 custody. It will be later\n /// claimed by the relayer who completed the relay on destination chain, or transferred back to the user\n /// via the cancel function should no one complete the relay.\n function _takeBridgedUserAsset(address token, uint256 amount) internal returns (uint256 amountTaken) {\n if (token == NATIVE_GAS_TOKEN) {\n // For the native gas token, we just need to check that the supplied msg.value is correct.\n // Supplied `msg.value` is already in FastBridgeV2 custody.\n if (amount != msg.value) revert MsgValueIncorrect();\n amountTaken = msg.value;\n } else {\n // For ERC20s, token is explicitly transferred from the user to FastBridgeV2.\n // We don't allow non-zero `msg.value` to avoid extra funds from being stuck in FastBridgeV2.\n if (msg.value != 0) revert MsgValueIncorrect();\n // Throw an explicit error if the provided token address is not a contract\n if (token.code.length == 0) revert TokenNotContract();\n amountTaken = IERC20(token).balanceOf(address(this));\n IERC20(token).safeTransferFrom(msg.sender, address(this), amount);\n // Use the balance difference as the amount taken in case of fee on transfer tokens.\n amountTaken = IERC20(token).balanceOf(address(this)) - amountTaken;\n }\n }\n\n /// @notice Calls the Recipient's hook function with the specified zapData and performs\n /// all the necessary checks for the returned value.\n function _triggerZapWithChecks(address recipient, address token, uint256 amount, bytes calldata zapData) internal {\n // This will bubble any revert messages from the hook function\n bytes memory returnData = Address.functionCallWithValue({\n target: recipient,\n data: abi.encodeCall(IZapRecipient.zap, (token, amount, zapData)),\n // Note: see `relay()` for reasoning behind passing msg.value\n value: msg.value\n });\n // Explicit revert if no return data at all\n if (returnData.length == 0) revert RecipientNoReturnValue();\n // Check that exactly a single return value was returned\n if (returnData.length != 32) revert RecipientIncorrectReturnValue();\n // Return value should be abi-encoded hook function selector\n if (bytes32(returnData) != bytes32(IZapRecipient.zap.selector)) {\n revert RecipientIncorrectReturnValue();\n }\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint56(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint56).max but\n /// proof.timestamp \u003c type(uint56).max via unchecked statement\n /// @param proofBlockTimestamp The bridge proof block timestamp\n /// @return delta Time delta since proof submitted\n function _timeSince(uint56 proofBlockTimestamp) internal view returns (uint256 delta) {\n unchecked {\n delta = uint56(block.timestamp) - proofBlockTimestamp;\n }\n }\n\n /// @notice Performs all the necessary checks for a bridge to happen.\n /// @dev There's no good way to refactor this function to reduce cyclomatic complexity due to\n /// the number of checks that need to be performed, so we skip the code-complexity rule here.\n // solhint-disable-next-line code-complexity\n function _validateBridgeParams(\n BridgeParams memory params,\n BridgeParamsV2 memory paramsV2,\n int256 exclusivityEndTime\n )\n internal\n view\n {\n // Check V1 (legacy) params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.sender == address(0) || params.to == address(0)) revert ZeroAddress();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n // Check V2 params\n if (paramsV2.zapData.length \u003e MAX_ZAP_DATA_LENGTH) revert ZapDataLengthAboveMax();\n if (paramsV2.zapNative != 0 \u0026\u0026 params.destToken == NATIVE_GAS_TOKEN) {\n revert ZapNativeNotSupported();\n }\n // exclusivityEndTime must be in range [0 .. params.deadline]\n if (exclusivityEndTime \u003c 0 || exclusivityEndTime \u003e int256(params.deadline)) {\n revert ExclusivityParamsIncorrect();\n }\n }\n\n /// @notice Performs all the necessary checks for a relay to happen.\n function _validateRelayParams(bytes calldata request, bytes32 transactionId, address relayer) internal view {\n if (relayer == address(0)) revert ZeroAddress();\n // Check if the transaction has already been relayed\n if (bridgeRelays(transactionId)) revert TransactionRelayed();\n if (request.destChainId() != block.chainid) revert ChainIncorrect();\n // Check the deadline for relay to happen\n if (block.timestamp \u003e request.deadline()) revert DeadlineExceeded();\n // Check the exclusivity period, if it is still ongoing\n address exclRelayer = request.exclusivityRelayer();\n if (exclRelayer != address(0) \u0026\u0026 exclRelayer != relayer \u0026\u0026 block.timestamp \u003c= request.exclusivityEndTime()) {\n revert ExclusivityPeriodNotPassed();\n }\n }\n}\n","language":"Solidity","languageVersion":"0.8.24","compilerVersion":"0.8.24","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"","srcMapRuntime":"","abiDefinition":[{"inputs":[],"name":"AccessControlBadConfirmation","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"bytes32","name":"neededRole","type":"bytes32"}],"name":"AccessControlUnauthorizedAccount","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"previousAdminRole","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"newAdminRole","type":"bytes32"}],"name":"RoleAdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleRevoked","type":"event"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleAdmin","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"uint256","name":"index","type":"uint256"}],"name":"getRoleMember","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleMemberCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"grantRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"hasRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"callerConfirmation","type":"address"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"revokeRole","outputs":[],"stateMutability":"nonpayable","type":"function"}],"userDoc":{"kind":"user","methods":{},"version":1},"developerDoc":{"details":"External interface of AccessControlEnumerable declared to support ERC165 detection.","errors":{"AccessControlBadConfirmation()":[{"details":"The caller of a function is not the expected one. NOTE: Don't confuse with {AccessControlUnauthorizedAccount}."}],"AccessControlUnauthorizedAccount(address,bytes32)":[{"details":"The `account` is missing a role."}]},"events":{"RoleAdminChanged(bytes32,bytes32,bytes32)":{"details":"Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole` `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite {RoleAdminChanged} not being emitted signaling this."},"RoleGranted(bytes32,address,address)":{"details":"Emitted when `account` is granted `role`. `sender` is the account that originated the contract call, an admin role bearer except when using {AccessControl-_setupRole}."},"RoleRevoked(bytes32,address,address)":{"details":"Emitted when `account` is revoked `role`. `sender` is the account that originated the contract call: - if using `revokeRole`, it is the admin role bearer - if using `renounceRole`, it is the role bearer (i.e. `account`)"}},"kind":"dev","methods":{"getRoleAdmin(bytes32)":{"details":"Returns the admin role that controls `role`. See {grantRole} and {revokeRole}. To change a role's admin, use {AccessControl-_setRoleAdmin}."},"getRoleMember(bytes32,uint256)":{"details":"Returns one of the accounts that have `role`. `index` must be a value between 0 and {getRoleMemberCount}, non-inclusive. Role bearers are not sorted in any particular way, and their ordering may change at any point. WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure you perform all queries on the same block. See the following https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post] for more information."},"getRoleMemberCount(bytes32)":{"details":"Returns the number of accounts that have `role`. Can be used together with {getRoleMember} to enumerate all bearers of a role."},"grantRole(bytes32,address)":{"details":"Grants `role` to `account`. If `account` had not been already granted `role`, emits a {RoleGranted} event. Requirements: - the caller must have ``role``'s admin role."},"hasRole(bytes32,address)":{"details":"Returns `true` if `account` has been granted `role`."},"renounceRole(bytes32,address)":{"details":"Revokes `role` from the calling account. Roles are often managed via {grantRole} and {revokeRole}: this function's purpose is to provide a mechanism for accounts to lose their privileges if they are compromised (such as when a trusted device is misplaced). If the calling account had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must be `callerConfirmation`."},"revokeRole(bytes32,address)":{"details":"Revokes `role` from `account`. If `account` had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must have ``role``'s admin role."}},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[],\"name\":\"AccessControlBadConfirmation\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"neededRole\",\"type\":\"bytes32\"}],\"name\":\"AccessControlUnauthorizedAccount\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"previousAdminRole\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"newAdminRole\",\"type\":\"bytes32\"}],\"name\":\"RoleAdminChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleGranted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleRevoked\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"}],\"name\":\"getRoleAdmin\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"index\",\"type\":\"uint256\"}],\"name\":\"getRoleMember\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"}],\"name\":\"getRoleMemberCount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"grantRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"hasRole\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"callerConfirmation\",\"type\":\"address\"}],\"name\":\"renounceRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"revokeRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"details\":\"External interface of AccessControlEnumerable declared to support ERC165 detection.\",\"errors\":{\"AccessControlBadConfirmation()\":[{\"details\":\"The caller of a function is not the expected one. NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\"}],\"AccessControlUnauthorizedAccount(address,bytes32)\":[{\"details\":\"The `account` is missing a role.\"}]},\"events\":{\"RoleAdminChanged(bytes32,bytes32,bytes32)\":{\"details\":\"Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole` `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite {RoleAdminChanged} not being emitted signaling this.\"},\"RoleGranted(bytes32,address,address)\":{\"details\":\"Emitted when `account` is granted `role`. `sender` is the account that originated the contract call, an admin role bearer except when using {AccessControl-_setupRole}.\"},\"RoleRevoked(bytes32,address,address)\":{\"details\":\"Emitted when `account` is revoked `role`. `sender` is the account that originated the contract call: - if using `revokeRole`, it is the admin role bearer - if using `renounceRole`, it is the role bearer (i.e. `account`)\"}},\"kind\":\"dev\",\"methods\":{\"getRoleAdmin(bytes32)\":{\"details\":\"Returns the admin role that controls `role`. See {grantRole} and {revokeRole}. To change a role's admin, use {AccessControl-_setRoleAdmin}.\"},\"getRoleMember(bytes32,uint256)\":{\"details\":\"Returns one of the accounts that have `role`. `index` must be a value between 0 and {getRoleMemberCount}, non-inclusive. Role bearers are not sorted in any particular way, and their ordering may change at any point. WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure you perform all queries on the same block. See the following https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post] for more information.\"},\"getRoleMemberCount(bytes32)\":{\"details\":\"Returns the number of accounts that have `role`. Can be used together with {getRoleMember} to enumerate all bearers of a role.\"},\"grantRole(bytes32,address)\":{\"details\":\"Grants `role` to `account`. If `account` had not been already granted `role`, emits a {RoleGranted} event. Requirements: - the caller must have ``role``'s admin role.\"},\"hasRole(bytes32,address)\":{\"details\":\"Returns `true` if `account` has been granted `role`.\"},\"renounceRole(bytes32,address)\":{\"details\":\"Revokes `role` from the calling account. Roles are often managed via {grantRole} and {revokeRole}: this function's purpose is to provide a mechanism for accounts to lose their privileges if they are compromised (such as when a trusted device is misplaced). If the calling account had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must be `callerConfirmation`.\"},\"revokeRole(bytes32,address)\":{\"details\":\"Revokes `role` from `account`. If `account` had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must have ``role``'s admin role.\"}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeV2.sol\":\"IAccessControlEnumerable\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeV2.sol\":{\"keccak256\":\"0xac79c463688a682ca706a4ef95e7817b83548cdfa8182ba0426ac7e5e07613d8\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://b3ecb7097381287cafc3a73f3a2bb03565115ebb682a85064e0b0dc2f7e2919d\",\"dweb:/ipfs/QmatruW3nYZTksf3CeQ8wwiAG4c7xoEJBEp6drHPtFLBRK\"]}},\"version\":1}"},"hashes":{"getRoleAdmin(bytes32)":"248a9ca3","getRoleMember(bytes32,uint256)":"9010d07c","getRoleMemberCount(bytes32)":"ca15c873","grantRole(bytes32,address)":"2f2ff15d","hasRole(bytes32,address)":"91d14854","renounceRole(bytes32,address)":"36568abe","revokeRole(bytes32,address)":"d547741f"}},"solidity/FastBridgeV2.sol:IAdminV2":{"code":"0x","runtime-code":"0x","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.24 ^0.8.20 ^0.8.4;\n\n// contracts/interfaces/IAdminV2.sol\n\ninterface IAdminV2 {\n event CancelDelayUpdated(uint256 oldCancelDelay, uint256 newCancelDelay);\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n function setCancelDelay(uint256 newCancelDelay) external;\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n}\n\n// contracts/interfaces/IAdminV2Errors.sol\n\ninterface IAdminV2Errors {\n error CancelDelayBelowMin();\n error FeeRateAboveMax();\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IFastBridgeV2Errors.sol\n\ninterface IFastBridgeV2Errors {\n error AmountIncorrect();\n error ChainIncorrect();\n error ExclusivityParamsIncorrect();\n error MsgValueIncorrect();\n error SenderIncorrect();\n error StatusIncorrect();\n error TokenNotContract();\n error ZapDataLengthAboveMax();\n error ZapNativeNotSupported();\n error ZeroAddress();\n\n error RecipientIncorrectReturnValue();\n error RecipientNoReturnValue();\n\n error DeadlineExceeded();\n error DeadlineNotExceeded();\n error DeadlineTooShort();\n error DisputePeriodNotPassed();\n error DisputePeriodPassed();\n error ExclusivityPeriodNotPassed();\n\n error TransactionRelayed();\n}\n\n// contracts/interfaces/IMulticallTarget.sol\n\n/// @notice Interface for a contract that can be called multiple times by the same caller. Inspired by MulticallV3:\n/// https://github.com/mds1/multicall/blob/master/src/Multicall3.sol\ninterface IMulticallTarget {\n struct Result {\n bool success;\n bytes returnData;\n }\n\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external;\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results);\n}\n\n// contracts/interfaces/IZapRecipient.sol\n\ninterface IZapRecipient {\n function zap(address token, uint256 amount, bytes memory zapData) external payable returns (bytes4);\n}\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// contracts/interfaces/IFastBridgeV2.sol\n\ninterface IFastBridgeV2 is IFastBridge {\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n struct BridgeTxDetails {\n BridgeStatus status;\n uint32 destChainId;\n uint56 proofBlockTimestamp;\n address proofRelayer;\n }\n\n struct BridgeRelay {\n uint48 blockNumber;\n uint48 blockTimestamp;\n address relayer;\n }\n\n /// @notice New params introduced in the FastBridgeV2.\n /// We are passing fields from the older BridgeParams struct outside of this struct\n /// for backwards compatibility.\n /// Note: quoteRelayer and quoteExclusivitySeconds are either both zero (indicating no exclusivity)\n /// or both non-zero (indicating exclusivity for the given period).\n /// Note: zapNative \u003e 0 can NOT be used with destToken = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE (native token)\n /// @param quoteRelayer Relayer that provided the quote for the transaction\n /// @param quoteExclusivitySeconds Period of time the quote relayer is guaranteed exclusivity after user's deposit\n /// @param quoteId Unique quote identifier used for tracking the quote\n /// @param zapNative ETH value to send to the recipient (if any)\n /// @param zapData Parameters for the Zap to the destination recipient (if any)\n struct BridgeParamsV2 {\n address quoteRelayer;\n int256 quoteExclusivitySeconds;\n bytes quoteId;\n uint256 zapNative;\n bytes zapData;\n }\n\n /// @notice Updated bridge transaction struct to include parameters introduced in FastBridgeV2.\n /// Note: only `exclusivityRelayer` can fill such a transaction until `exclusivityEndTime`.\n struct BridgeTransactionV2 {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n // Note: sendChainGas flag from V1 is deprecated\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n address exclusivityRelayer;\n uint256 exclusivityEndTime;\n uint256 zapNative; // ETH value to send to the recipient (if any)\n bytes zapData; // data to pass for the Zap action (if any)\n }\n\n event BridgeQuoteDetails(bytes32 indexed transactionId, bytes quoteId);\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability\n /// to provide temporary exclusivity fill rights for the quote relayer.\n /// @param params The parameters required to bridge\n /// @param paramsV2 The parameters for exclusivity fill rights (optional, can be left empty)\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function relay(bytes memory request, address relayer) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param transactionId The transaction id associated with the encoded bridge transaction to prove\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital.\n /// @notice Can only send funds to the relayer address on the proof.\n /// @param request The encoded bridge transaction to claim on origin chain\n function claim(bytes memory request) external;\n\n /// @notice Cancels an outstanding bridge transaction in case optimistic bridging failed and returns the full amount\n /// to the original sender.\n /// @param request The encoded bridge transaction to refund\n function cancel(bytes memory request) external;\n\n /// @notice Checks if a transaction has been relayed\n /// @param transactionId The ID of the transaction to check\n /// @return True if the transaction has been relayed, false otherwise\n function bridgeRelays(bytes32 transactionId) external view returns (bool);\n\n /// @notice Returns the status of a bridge transaction\n /// @param transactionId The ID of the bridge transaction\n /// @return BridgeStatus Status of the bridge transaction\n function bridgeStatuses(bytes32 transactionId) external view returns (BridgeStatus);\n\n /// @notice Returns the timestamp and relayer of a bridge proof\n /// @param transactionId The ID of the bridge transaction\n /// @return timestamp The timestamp of the bridge proof\n /// @return relayer The relayer address of the bridge proof\n function bridgeProofs(bytes32 transactionId) external view returns (uint96 timestamp, address relayer);\n\n /// @notice Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\n /// @param request The bridge request to decode\n function getBridgeTransactionV2(bytes memory request) external view returns (BridgeTransactionV2 memory);\n}\n\n// contracts/utils/MulticallTarget.sol\n\n// solhint-disable avoid-low-level-calls\n/// @notice Template for a contract that supports batched calls (preserving the msg.sender).\n/// Only calls with zero msg.value could be batched.\nabstract contract MulticallTarget is IMulticallTarget {\n error MulticallTarget__UndeterminedRevert();\n\n /// @notice Perform a batched call to this contract, preserving the msg.sender.\n /// The return data from each call is discarded.\n /// @dev The method is non-payable, so only calls with `msg.value == 0` could be batched.\n /// It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag.\n /// Otherwise, the whole batch call will be reverted with the original revert reason.\n /// @param data List of abi-encoded calldata for the calls to perform.\n /// @param ignoreReverts Whether to ignore the revert errors from the calls.\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external {\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\n if (!success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(result);\n }\n }\n }\n\n /// @notice Perform a batched call to this contract, preserving the msg.sender.\n /// The return data from each call is preserved.\n /// @dev The method is non-payable, so only calls with `msg.value == 0` could be batched.\n /// It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag.\n /// Otherwise, the whole batch call will be reverted with the original revert reason.\n /// @param data List of abi-encoded calldata for the calls to perform.\n /// @param ignoreReverts Whether to ignore the revert errors from the calls.\n /// @return results List of results from the calls: `(success, returnData)`.\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results)\n {\n results = new Result[](data.length);\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (results[i].success, results[i].returnData) = address(this).delegatecall(data[i]);\n if (!results[i].success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(results[i].returnData);\n }\n }\n }\n\n /// @dev Bubbles the revert message from the underlying call.\n /// Note: preserves the same custom error or revert string, if one was used.\n /// Source: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v5.0.2/contracts/utils/Address.sol#L143-L158\n function _bubbleRevert(bytes memory returnData) internal pure {\n // Look for revert reason and bubble it up if present\n if (returnData.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n // solhint-disable-next-line no-inline-assembly\n assembly {\n let returndata_size := mload(returnData)\n revert(add(32, returnData), returndata_size)\n }\n } else {\n revert MulticallTarget__UndeterminedRevert();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// contracts/libs/BridgeTransactionV2.sol\n\n// solhint-disable no-inline-assembly\nlibrary BridgeTransactionV2Lib {\n uint16 internal constant VERSION = 2;\n\n // Offsets of the fields in the packed BridgeTransactionV2 struct\n // uint16 version [000 .. 002)\n // uint32 originChainId [002 .. 006)\n // uint32 destChainId [006 .. 010)\n // address originSender [010 .. 030)\n // address destRecipient [030 .. 050)\n // address originToken [050 .. 070)\n // address destToken [070 .. 090)\n // uint256 originAmount [090 .. 122)\n // uint256 destAmount [122 .. 154)\n // uint256 originFeeAmount [154 .. 186)\n // uint256 deadline [186 .. 218)\n // uint256 nonce [218 .. 250)\n // address exclusivityRelayer [250 .. 270)\n // uint256 exclusivityEndTime [270 .. 302)\n // uint256 zapNative [302 .. 334)\n // bytes zapData [334 .. ***)\n\n // forgefmt: disable-start\n uint256 private constant OFFSET_ORIGIN_CHAIN_ID = 2;\n uint256 private constant OFFSET_DEST_CHAIN_ID = 6;\n uint256 private constant OFFSET_ORIGIN_SENDER = 10;\n uint256 private constant OFFSET_DEST_RECIPIENT = 30;\n uint256 private constant OFFSET_ORIGIN_TOKEN = 50;\n uint256 private constant OFFSET_DEST_TOKEN = 70;\n uint256 private constant OFFSET_ORIGIN_AMOUNT = 90;\n uint256 private constant OFFSET_DEST_AMOUNT = 122;\n uint256 private constant OFFSET_ORIGIN_FEE_AMOUNT = 154;\n uint256 private constant OFFSET_DEADLINE = 186;\n uint256 private constant OFFSET_NONCE = 218;\n uint256 private constant OFFSET_EXCLUSIVITY_RELAYER = 250;\n uint256 private constant OFFSET_EXCLUSIVITY_END_TIME = 270;\n uint256 private constant OFFSET_ZAP_NATIVE = 302;\n uint256 private constant OFFSET_ZAP_DATA = 334;\n // forgefmt: disable-end\n\n error BridgeTransactionV2__InvalidEncodedTx();\n error BridgeTransactionV2__UnsupportedVersion(uint16 version);\n\n /// @notice Validates the encoded transaction to be a tightly packed encoded payload for BridgeTransactionV2.\n /// @dev Checks the minimum length and the version, use this function before decoding any of the fields.\n function validateV2(bytes calldata encodedTx) internal pure {\n // Check the minimum length: must at least include all static fields.\n if (encodedTx.length \u003c OFFSET_ZAP_DATA) revert BridgeTransactionV2__InvalidEncodedTx();\n // Once we validated the length, we can be sure that the version field is present.\n uint16 version_ = version(encodedTx);\n if (version_ != VERSION) revert BridgeTransactionV2__UnsupportedVersion(version_);\n }\n\n /// @notice Encodes the BridgeTransactionV2 struct by tightly packing the fields.\n /// @dev `abi.decode` will not work as a result of the tightly packed fields. Use `decodeV2` to decode instead.\n function encodeV2(IFastBridgeV2.BridgeTransactionV2 memory bridgeTx) internal pure returns (bytes memory) {\n // We split the encoding into two parts to avoid stack-too-deep error\n bytes memory firstPart = abi.encodePacked(\n VERSION,\n bridgeTx.originChainId,\n bridgeTx.destChainId,\n bridgeTx.originSender,\n bridgeTx.destRecipient,\n bridgeTx.originToken,\n bridgeTx.destToken,\n bridgeTx.originAmount\n );\n return abi.encodePacked(\n firstPart,\n bridgeTx.destAmount,\n bridgeTx.originFeeAmount,\n // Note: we skip the deprecated `sendChainGas` flag, which was present in BridgeTransaction V1\n bridgeTx.deadline,\n bridgeTx.nonce,\n // New V2 fields: exclusivity\n bridgeTx.exclusivityRelayer,\n bridgeTx.exclusivityEndTime,\n // New V2 fields: Zap\n bridgeTx.zapNative,\n bridgeTx.zapData\n );\n }\n\n /// @notice Decodes the BridgeTransactionV2 struct from the encoded transaction.\n /// @dev Encoded BridgeTransactionV2 struct must be tightly packed.\n /// Use `validateV2` before decoding to ensure the encoded transaction is valid.\n function decodeV2(bytes calldata encodedTx)\n internal\n pure\n returns (IFastBridgeV2.BridgeTransactionV2 memory bridgeTx)\n {\n bridgeTx.originChainId = originChainId(encodedTx);\n bridgeTx.destChainId = destChainId(encodedTx);\n bridgeTx.originSender = originSender(encodedTx);\n bridgeTx.destRecipient = destRecipient(encodedTx);\n bridgeTx.originToken = originToken(encodedTx);\n bridgeTx.destToken = destToken(encodedTx);\n bridgeTx.originAmount = originAmount(encodedTx);\n bridgeTx.destAmount = destAmount(encodedTx);\n bridgeTx.originFeeAmount = originFeeAmount(encodedTx);\n bridgeTx.deadline = deadline(encodedTx);\n bridgeTx.nonce = nonce(encodedTx);\n bridgeTx.exclusivityRelayer = exclusivityRelayer(encodedTx);\n bridgeTx.exclusivityEndTime = exclusivityEndTime(encodedTx);\n bridgeTx.zapNative = zapNative(encodedTx);\n bridgeTx.zapData = zapData(encodedTx);\n }\n\n /// @notice Extracts the version from the encoded transaction.\n function version(bytes calldata encodedTx) internal pure returns (uint16 version_) {\n // Load 32 bytes from the start and shift it 240 bits to the right to get the highest 16 bits.\n assembly {\n version_ := shr(240, calldataload(encodedTx.offset))\n }\n }\n\n /// @notice Extracts the origin chain ID from the encoded transaction.\n function originChainId(bytes calldata encodedTx) internal pure returns (uint32 originChainId_) {\n // Load 32 bytes from the offset and shift it 224 bits to the right to get the highest 32 bits.\n assembly {\n originChainId_ := shr(224, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_CHAIN_ID)))\n }\n }\n\n /// @notice Extracts the destination chain ID from the encoded transaction.\n function destChainId(bytes calldata encodedTx) internal pure returns (uint32 destChainId_) {\n // Load 32 bytes from the offset and shift it 224 bits to the right to get the highest 32 bits.\n assembly {\n destChainId_ := shr(224, calldataload(add(encodedTx.offset, OFFSET_DEST_CHAIN_ID)))\n }\n }\n\n /// @notice Extracts the origin sender from the encoded transaction.\n function originSender(bytes calldata encodedTx) internal pure returns (address originSender_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n originSender_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_SENDER)))\n }\n }\n\n /// @notice Extracts the destination recipient from the encoded transaction.\n function destRecipient(bytes calldata encodedTx) internal pure returns (address destRecipient_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n destRecipient_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_DEST_RECIPIENT)))\n }\n }\n\n /// @notice Extracts the origin token from the encoded transaction.\n function originToken(bytes calldata encodedTx) internal pure returns (address originToken_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n originToken_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_TOKEN)))\n }\n }\n\n /// @notice Extracts the destination token from the encoded transaction.\n function destToken(bytes calldata encodedTx) internal pure returns (address destToken_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n destToken_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_DEST_TOKEN)))\n }\n }\n\n /// @notice Extracts the origin amount from the encoded transaction.\n function originAmount(bytes calldata encodedTx) internal pure returns (uint256 originAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n originAmount_ := calldataload(add(encodedTx.offset, OFFSET_ORIGIN_AMOUNT))\n }\n }\n\n /// @notice Extracts the destination amount from the encoded transaction.\n function destAmount(bytes calldata encodedTx) internal pure returns (uint256 destAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n destAmount_ := calldataload(add(encodedTx.offset, OFFSET_DEST_AMOUNT))\n }\n }\n\n /// @notice Extracts the origin fee amount from the encoded transaction.\n function originFeeAmount(bytes calldata encodedTx) internal pure returns (uint256 originFeeAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n originFeeAmount_ := calldataload(add(encodedTx.offset, OFFSET_ORIGIN_FEE_AMOUNT))\n }\n }\n\n /// @notice Extracts the deadline from the encoded transaction.\n function deadline(bytes calldata encodedTx) internal pure returns (uint256 deadline_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n deadline_ := calldataload(add(encodedTx.offset, OFFSET_DEADLINE))\n }\n }\n\n /// @notice Extracts the nonce from the encoded transaction.\n function nonce(bytes calldata encodedTx) internal pure returns (uint256 nonce_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n nonce_ := calldataload(add(encodedTx.offset, OFFSET_NONCE))\n }\n }\n\n /// @notice Extracts the exclusivity relayer from the encoded transaction.\n function exclusivityRelayer(bytes calldata encodedTx) internal pure returns (address exclusivityRelayer_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n exclusivityRelayer_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_EXCLUSIVITY_RELAYER)))\n }\n }\n\n /// @notice Extracts the exclusivity end time from the encoded transaction.\n function exclusivityEndTime(bytes calldata encodedTx) internal pure returns (uint256 exclusivityEndTime_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n exclusivityEndTime_ := calldataload(add(encodedTx.offset, OFFSET_EXCLUSIVITY_END_TIME))\n }\n }\n\n /// @notice Extracts the Zap's native value from the encoded transaction.\n function zapNative(bytes calldata encodedTx) internal pure returns (uint256 zapNative_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n zapNative_ := calldataload(add(encodedTx.offset, OFFSET_ZAP_NATIVE))\n }\n }\n\n /// @notice Extracts the Zap's data from the encoded transaction.\n function zapData(bytes calldata encodedTx) internal pure returns (bytes calldata zapData_) {\n zapData_ = encodedTx[OFFSET_ZAP_DATA:];\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/AdminV2.sol\n\ncontract AdminV2 is AccessControlEnumerable, IAdminV2, IAdminV2Errors {\n using SafeERC20 for IERC20;\n\n /// @notice Address reserved for native gas token (ETH on Ethereum and most L2s, AVAX on Avalanche, etc)\n address public constant NATIVE_GAS_TOKEN = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Role identifier for Quoter API's off-chain authentication.\n /// @dev Only addresses with this role can post FastBridge quotes to the API.\n bytes32 public constant QUOTER_ROLE = keccak256(\"QUOTER_ROLE\");\n\n /// @notice Role identifier for Prover's on-chain authentication in FastBridge.\n /// @dev Only addresses with this role can provide proofs that a FastBridge request has been relayed.\n bytes32 public constant PROVER_ROLE = keccak256(\"PROVER_ROLE\");\n\n /// @notice Role identifier for Guard's on-chain authentication in FastBridge.\n /// @dev Only addresses with this role can dispute submitted relay proofs during the dispute period.\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n\n /// @notice Role identifier for Canceler's on-chain authentication in FastBridge.\n /// @dev Only addresses with this role can cancel a FastBridge transaction without the cancel delay.\n bytes32 public constant CANCELER_ROLE = keccak256(\"CANCELER_ROLE\");\n\n /// @notice Role identifier for Governor's on-chain administrative authority.\n /// @dev Only addresses with this role can perform administrative tasks within the contract.\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n /// @notice Denominator for fee rates, represents 100%.\n uint256 public constant FEE_BPS = 1e6;\n /// @notice Maximum protocol fee rate: 1% on origin amount.\n uint256 public constant FEE_RATE_MAX = 0.01e6;\n\n /// @notice Minimum cancel delay that can be set by the governor.\n uint256 public constant MIN_CANCEL_DELAY = 1 hours;\n /// @notice Default cancel delay set during the contract deployment.\n uint256 public constant DEFAULT_CANCEL_DELAY = 1 days;\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Delay for a transaction after which it could be permisionlessly cancelled\n uint256 public cancelDelay;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Use ZapNative V2 requests instead.\n uint256 public immutable chainGasAmount = 0;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n _setCancelDelay(DEFAULT_CANCEL_DELAY);\n }\n\n /// @notice Allows the contract governor to set the cancel delay. The cancel delay is the time after the transaction\n /// deadline after which it can be permissionlessly cancelled, if it hasn't been proven by any of the Relayers.\n function setCancelDelay(uint256 newCancelDelay) external onlyRole(GOVERNOR_ROLE) {\n _setCancelDelay(newCancelDelay);\n }\n\n /// @notice Allows the contract governor to set the protocol fee rate. The protocol fee is taken from the origin\n /// amount only for completed and claimed transactions.\n /// @dev The protocol fee is abstracted away from the relayers, they always operate using the amounts after fees:\n /// what they see as the origin amount emitted in the log is what they get credited with.\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n if (newFeeRate \u003e FEE_RATE_MAX) revert FeeRateAboveMax();\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n /// @notice Allows the contract governor to sweep the accumulated protocol fees in the contract.\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n emit FeesSwept(token, recipient, feeAmount);\n /// Sweep the fees as the last transaction action\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(recipient), feeAmount);\n } else {\n IERC20(token).safeTransfer(recipient, feeAmount);\n }\n }\n\n /// @notice Internal function to set the cancel delay. Security checks are performed outside of this function.\n function _setCancelDelay(uint256 newCancelDelay) private {\n if (newCancelDelay \u003c MIN_CANCEL_DELAY) revert CancelDelayBelowMin();\n uint256 oldCancelDelay = cancelDelay;\n cancelDelay = newCancelDelay;\n emit CancelDelayUpdated(oldCancelDelay, newCancelDelay);\n }\n}\n\n// contracts/FastBridgeV2.sol\n\n/// @notice FastBridgeV2 is a contract for bridging tokens across chains.\ncontract FastBridgeV2 is AdminV2, MulticallTarget, IFastBridgeV2, IFastBridgeV2Errors {\n using BridgeTransactionV2Lib for bytes;\n using SafeERC20 for IERC20;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n /// @notice Maximum length of accepted zapData\n uint256 public constant MAX_ZAP_DATA_LENGTH = 2 ** 16 - 1;\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeTxDetails) public bridgeTxDetails;\n /// @notice Relay details on destination chain\n mapping(bytes32 =\u003e BridgeRelay) public bridgeRelayDetails;\n /// @notice Unique bridge nonces tracked per originSender\n mapping(address =\u003e uint256) public senderNonces;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Replaced by senderNonces\n uint256 public immutable nonce = 0;\n /// @notice the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) AdminV2(_owner) {\n deployBlock = block.number;\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n bridge({\n params: params,\n paramsV2: BridgeParamsV2({\n quoteRelayer: address(0),\n quoteExclusivitySeconds: 0,\n quoteId: bytes(\"\"),\n zapNative: 0,\n zapData: bytes(\"\")\n })\n });\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes calldata request) external payable {\n // relay override will validate the request\n relay({request: request, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes calldata request, bytes32 destTxHash) external {\n request.validateV2();\n prove({transactionId: keccak256(request), destTxHash: destTxHash, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridgeV2\n function claim(bytes calldata request) external {\n // claim override will validate the request\n claim({request: request, to: address(0)});\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Aggregate the read operations from the same storage slot\n address disputedRelayer = $.proofRelayer;\n BridgeStatus status = $.status;\n uint56 proofBlockTimestamp = $.proofBlockTimestamp;\n // Can only dispute a RELAYER_PROVED transaction within the dispute period\n if (status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(proofBlockTimestamp) \u003e DISPUTE_PERIOD) {\n revert DisputePeriodPassed();\n }\n // Update status to REQUESTED and delete the disputed proof details\n // Note: these are storage writes\n $.status = BridgeStatus.REQUESTED;\n $.proofRelayer = address(0);\n $.proofBlockTimestamp = 0;\n\n emit BridgeProofDisputed(transactionId, disputedRelayer);\n }\n\n /// Note: this function is deprecated and will be removed in a future version.\n /// @inheritdoc IFastBridge\n function refund(bytes calldata request) external {\n cancel(request);\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // The correct relayer can only claim a RELAYER_PROVED transaction after the dispute period\n if ($.status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if ($.proofRelayer != relayer) revert SenderIncorrect();\n return _timeSince($.proofBlockTimestamp) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n /// @dev This method is added to achieve backwards compatibility with decoding requests into V1 structs:\n /// - `zapNative` is partially reported as a zero/non-zero flag\n /// - `zapData` is ignored\n /// In order to process all kinds of requests use getBridgeTransactionV2 instead.\n function getBridgeTransaction(bytes calldata request) external view returns (BridgeTransaction memory) {\n // Try decoding into V2 struct first. This will revert if V1 struct is passed\n try this.getBridgeTransactionV2(request) returns (BridgeTransactionV2 memory txV2) {\n // Note: we entirely ignore the zapData field, as it was not present in V1\n return BridgeTransaction({\n originChainId: txV2.originChainId,\n destChainId: txV2.destChainId,\n originSender: txV2.originSender,\n destRecipient: txV2.destRecipient,\n originToken: txV2.originToken,\n destToken: txV2.destToken,\n originAmount: txV2.originAmount,\n destAmount: txV2.destAmount,\n originFeeAmount: txV2.originFeeAmount,\n sendChainGas: txV2.zapNative != 0,\n deadline: txV2.deadline,\n nonce: txV2.nonce\n });\n } catch {\n // Fallback to V1 struct\n return abi.decode(request, (BridgeTransaction));\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function getBridgeTransactionV2(bytes calldata request) external pure returns (BridgeTransactionV2 memory) {\n request.validateV2();\n return BridgeTransactionV2Lib.decodeV2(request);\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) public payable {\n int256 exclusivityEndTime = 0;\n // if relayer exclusivity is not intended for this bridge, set exclusivityEndTime to static zero\n // otherwise, set exclusivity to expire at the current block ts offset by quoteExclusivitySeconds\n if (paramsV2.quoteRelayer != address(0)) {\n exclusivityEndTime = int256(block.timestamp) + paramsV2.quoteExclusivitySeconds;\n }\n _validateBridgeParams(params, paramsV2, exclusivityEndTime);\n\n // transfer tokens to bridge contract\n /// @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _takeBridgedUserAsset(params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) {\n originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n }\n\n // set status to requested\n bytes memory request = BridgeTransactionV2Lib.encodeV2(\n BridgeTransactionV2({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n deadline: params.deadline,\n nonce: senderNonces[params.sender]++, // increment nonce on every bridge\n exclusivityRelayer: paramsV2.quoteRelayer,\n // We checked exclusivityEndTime to be in range [0 .. params.deadline] above, so can safely cast\n exclusivityEndTime: uint256(exclusivityEndTime),\n zapNative: paramsV2.zapNative,\n zapData: paramsV2.zapData\n })\n );\n bytes32 transactionId = keccak256(request);\n // Note: the tx status will be updated throughout the tx lifecycle, while destChainId is set once here\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n bridgeTxDetails[transactionId].destChainId = params.dstChainId;\n\n emit BridgeRequested({\n transactionId: transactionId,\n sender: params.sender,\n request: request,\n destChainId: params.dstChainId,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n sendChainGas: paramsV2.zapNative != 0\n });\n emit BridgeQuoteDetails(transactionId, paramsV2.quoteId);\n }\n\n /// @inheritdoc IFastBridgeV2\n function relay(bytes calldata request, address relayer) public payable {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n _validateRelayParams(request, transactionId, relayer);\n // mark bridge transaction as relayed\n bridgeRelayDetails[transactionId] =\n BridgeRelay({blockNumber: uint48(block.number), blockTimestamp: uint48(block.timestamp), relayer: relayer});\n\n // transfer tokens to recipient on destination chain and trigger Zap if requested\n address to = request.destRecipient();\n address token = request.destToken();\n uint256 amount = request.destAmount();\n uint256 zapNative = request.zapNative();\n\n // Emit the event before any external calls\n emit BridgeRelayed({\n transactionId: transactionId,\n relayer: relayer,\n to: to,\n originChainId: request.originChainId(),\n originToken: request.originToken(),\n destToken: token,\n originAmount: request.originAmount(),\n destAmount: amount,\n chainGasAmount: zapNative\n });\n\n // All state changes have been done at this point, can proceed to the external calls.\n // This follows the checks-effects-interactions pattern to mitigate potential reentrancy attacks.\n if (token == NATIVE_GAS_TOKEN) {\n // For the native gas token, additional zapNative is not allowed\n if (zapNative != 0) revert ZapNativeNotSupported();\n // Check that the correct msg.value was sent\n if (msg.value != amount) revert MsgValueIncorrect();\n // Don't do a native transfer yet: we will handle it alongside the Zap below\n } else {\n // For ERC20s, we check that the correct msg.value was sent\n if (msg.value != zapNative) revert MsgValueIncorrect();\n // We need to transfer the tokens from the Relayer to the recipient first before performing an\n // optional post-transfer Zap.\n IERC20(token).safeTransferFrom(msg.sender, to, amount);\n }\n // At this point we have done:\n // - Transferred the requested amount of ERC20 tokens to the recipient.\n // At this point we have confirmed:\n // - For ERC20s: msg.value matches the requested zapNative amount.\n // - For the native gas token: msg.value matches the requested destAmount.\n // Remaining optional things to do:\n // - Forward the full msg.value to the recipient (if non-zero).\n // - Trigger a Zap (if zapData is present).\n bytes calldata zapData = request.zapData();\n if (zapData.length != 0) {\n // Zap Data is present: Zap has been requested by the recipient. Trigger it forwarding the full msg.value.\n\n // Note: if token has a fee on transfers, the recipient will have received less than `amount`.\n // This is a very niche edge case and should be handled by the recipient contract.\n _triggerZapWithChecks({recipient: to, token: token, amount: amount, zapData: zapData});\n } else if (msg.value != 0) {\n // Zap Data is missing, but msg.value was sent. This could happen in two different cases:\n // - Relay with the native gas token is happening.\n // - Relay with ERC20 is happening, with a `zapNative \u003e 0` request.\n // In both cases, we need to transfer the full msg.value to the recipient.\n Address.sendValue(payable(to), msg.value);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) public onlyRole(PROVER_ROLE) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n\n // Can only prove a REQUESTED transaction\n if ($.status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n // Update status to RELAYER_PROVED and store the proof details\n // Note: these are storage writes\n $.status = BridgeStatus.RELAYER_PROVED;\n $.proofBlockTimestamp = uint56(block.timestamp);\n $.proofRelayer = relayer;\n\n emit BridgeProofProvided(transactionId, relayer, destTxHash);\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes calldata request, address to) public {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Aggregate the read operations from the same storage slot\n address proofRelayer = $.proofRelayer;\n BridgeStatus status = $.status;\n uint56 proofBlockTimestamp = $.proofBlockTimestamp;\n\n // Can only claim a RELAYER_PROVED transaction after the dispute period\n if (status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(proofBlockTimestamp) \u003c= DISPUTE_PERIOD) {\n revert DisputePeriodNotPassed();\n }\n\n if (to == address(0)) {\n // Anyone could claim the funds to the proven relayer on their behalf\n to = proofRelayer;\n } else if (proofRelayer != msg.sender) {\n // Only the proven relayer could specify an address to claim the funds to\n revert SenderIncorrect();\n }\n\n // Update status to RELAYER_CLAIMED and transfer the origin collateral to the specified claim address\n // Note: this is a storage write\n $.status = BridgeStatus.RELAYER_CLAIMED;\n\n address token = request.originToken();\n uint256 amount = request.originAmount();\n // Update protocol fees if origin fee amount exists\n uint256 originFeeAmount = request.originFeeAmount();\n if (originFeeAmount \u003e 0) protocolFees[token] += originFeeAmount;\n // Emit the event before any external calls\n emit BridgeDepositClaimed(transactionId, proofRelayer, to, token, amount);\n // Complete the relayer claim as the last transaction action\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(to), amount);\n } else {\n IERC20(token).safeTransfer(to, amount);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function cancel(bytes calldata request) public {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Can only cancel a REQUESTED transaction after its deadline expires\n if ($.status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n uint256 deadline = request.deadline();\n // Permissionless cancel is only allowed after `cancelDelay` on top of the deadline\n if (!hasRole(CANCELER_ROLE, msg.sender)) deadline += cancelDelay;\n if (block.timestamp \u003c= deadline) revert DeadlineNotExceeded();\n // Update status to REFUNDED and return the full amount (collateral + protocol fees) to the original sender.\n // The protocol fees are only updated when the transaction is claimed, so we don't need to update them here.\n // Note: this is a storage write\n $.status = BridgeStatus.REFUNDED;\n\n address to = request.originSender();\n address token = request.originToken();\n uint256 amount = request.originAmount() + request.originFeeAmount();\n // Emit the event before any external calls\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n // Complete the user cancel as the last transaction action\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(to), amount);\n } else {\n IERC20(token).safeTransfer(to, amount);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeStatuses(bytes32 transactionId) public view returns (BridgeStatus status) {\n return bridgeTxDetails[transactionId].status;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeProofs(bytes32 transactionId) public view returns (uint96 timestamp, address relayer) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n\n timestamp = $.proofBlockTimestamp;\n relayer = $.proofRelayer;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeRelays(bytes32 transactionId) public view returns (bool) {\n // has this transactionId been relayed?\n return bridgeRelayDetails[transactionId].relayer != address(0);\n }\n\n /// @notice Takes the bridged asset from the user into FastBridgeV2 custody. It will be later\n /// claimed by the relayer who completed the relay on destination chain, or transferred back to the user\n /// via the cancel function should no one complete the relay.\n function _takeBridgedUserAsset(address token, uint256 amount) internal returns (uint256 amountTaken) {\n if (token == NATIVE_GAS_TOKEN) {\n // For the native gas token, we just need to check that the supplied msg.value is correct.\n // Supplied `msg.value` is already in FastBridgeV2 custody.\n if (amount != msg.value) revert MsgValueIncorrect();\n amountTaken = msg.value;\n } else {\n // For ERC20s, token is explicitly transferred from the user to FastBridgeV2.\n // We don't allow non-zero `msg.value` to avoid extra funds from being stuck in FastBridgeV2.\n if (msg.value != 0) revert MsgValueIncorrect();\n // Throw an explicit error if the provided token address is not a contract\n if (token.code.length == 0) revert TokenNotContract();\n amountTaken = IERC20(token).balanceOf(address(this));\n IERC20(token).safeTransferFrom(msg.sender, address(this), amount);\n // Use the balance difference as the amount taken in case of fee on transfer tokens.\n amountTaken = IERC20(token).balanceOf(address(this)) - amountTaken;\n }\n }\n\n /// @notice Calls the Recipient's hook function with the specified zapData and performs\n /// all the necessary checks for the returned value.\n function _triggerZapWithChecks(address recipient, address token, uint256 amount, bytes calldata zapData) internal {\n // This will bubble any revert messages from the hook function\n bytes memory returnData = Address.functionCallWithValue({\n target: recipient,\n data: abi.encodeCall(IZapRecipient.zap, (token, amount, zapData)),\n // Note: see `relay()` for reasoning behind passing msg.value\n value: msg.value\n });\n // Explicit revert if no return data at all\n if (returnData.length == 0) revert RecipientNoReturnValue();\n // Check that exactly a single return value was returned\n if (returnData.length != 32) revert RecipientIncorrectReturnValue();\n // Return value should be abi-encoded hook function selector\n if (bytes32(returnData) != bytes32(IZapRecipient.zap.selector)) {\n revert RecipientIncorrectReturnValue();\n }\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint56(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint56).max but\n /// proof.timestamp \u003c type(uint56).max via unchecked statement\n /// @param proofBlockTimestamp The bridge proof block timestamp\n /// @return delta Time delta since proof submitted\n function _timeSince(uint56 proofBlockTimestamp) internal view returns (uint256 delta) {\n unchecked {\n delta = uint56(block.timestamp) - proofBlockTimestamp;\n }\n }\n\n /// @notice Performs all the necessary checks for a bridge to happen.\n /// @dev There's no good way to refactor this function to reduce cyclomatic complexity due to\n /// the number of checks that need to be performed, so we skip the code-complexity rule here.\n // solhint-disable-next-line code-complexity\n function _validateBridgeParams(\n BridgeParams memory params,\n BridgeParamsV2 memory paramsV2,\n int256 exclusivityEndTime\n )\n internal\n view\n {\n // Check V1 (legacy) params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.sender == address(0) || params.to == address(0)) revert ZeroAddress();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n // Check V2 params\n if (paramsV2.zapData.length \u003e MAX_ZAP_DATA_LENGTH) revert ZapDataLengthAboveMax();\n if (paramsV2.zapNative != 0 \u0026\u0026 params.destToken == NATIVE_GAS_TOKEN) {\n revert ZapNativeNotSupported();\n }\n // exclusivityEndTime must be in range [0 .. params.deadline]\n if (exclusivityEndTime \u003c 0 || exclusivityEndTime \u003e int256(params.deadline)) {\n revert ExclusivityParamsIncorrect();\n }\n }\n\n /// @notice Performs all the necessary checks for a relay to happen.\n function _validateRelayParams(bytes calldata request, bytes32 transactionId, address relayer) internal view {\n if (relayer == address(0)) revert ZeroAddress();\n // Check if the transaction has already been relayed\n if (bridgeRelays(transactionId)) revert TransactionRelayed();\n if (request.destChainId() != block.chainid) revert ChainIncorrect();\n // Check the deadline for relay to happen\n if (block.timestamp \u003e request.deadline()) revert DeadlineExceeded();\n // Check the exclusivity period, if it is still ongoing\n address exclRelayer = request.exclusivityRelayer();\n if (exclRelayer != address(0) \u0026\u0026 exclRelayer != relayer \u0026\u0026 block.timestamp \u003c= request.exclusivityEndTime()) {\n revert ExclusivityPeriodNotPassed();\n }\n }\n}\n","language":"Solidity","languageVersion":"0.8.24","compilerVersion":"0.8.24","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"","srcMapRuntime":"","abiDefinition":[{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldCancelDelay","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newCancelDelay","type":"uint256"}],"name":"CancelDelayUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldFeeRate","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newFeeRate","type":"uint256"}],"name":"FeeRateUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"address","name":"recipient","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"FeesSwept","type":"event"},{"inputs":[{"internalType":"uint256","name":"newCancelDelay","type":"uint256"}],"name":"setCancelDelay","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"newFeeRate","type":"uint256"}],"name":"setProtocolFeeRate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"address","name":"recipient","type":"address"}],"name":"sweepProtocolFees","outputs":[],"stateMutability":"nonpayable","type":"function"}],"userDoc":{"kind":"user","methods":{},"version":1},"developerDoc":{"kind":"dev","methods":{},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"oldCancelDelay\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newCancelDelay\",\"type\":\"uint256\"}],\"name\":\"CancelDelayUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"oldFeeRate\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newFeeRate\",\"type\":\"uint256\"}],\"name\":\"FeeRateUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"FeesSwept\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"newCancelDelay\",\"type\":\"uint256\"}],\"name\":\"setCancelDelay\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"newFeeRate\",\"type\":\"uint256\"}],\"name\":\"setProtocolFeeRate\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"}],\"name\":\"sweepProtocolFees\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeV2.sol\":\"IAdminV2\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeV2.sol\":{\"keccak256\":\"0xac79c463688a682ca706a4ef95e7817b83548cdfa8182ba0426ac7e5e07613d8\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://b3ecb7097381287cafc3a73f3a2bb03565115ebb682a85064e0b0dc2f7e2919d\",\"dweb:/ipfs/QmatruW3nYZTksf3CeQ8wwiAG4c7xoEJBEp6drHPtFLBRK\"]}},\"version\":1}"},"hashes":{"setCancelDelay(uint256)":"1ea327c5","setProtocolFeeRate(uint256)":"b13aa2d6","sweepProtocolFees(address,address)":"06f333f2"}},"solidity/FastBridgeV2.sol:IAdminV2Errors":{"code":"0x","runtime-code":"0x","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.24 ^0.8.20 ^0.8.4;\n\n// contracts/interfaces/IAdminV2.sol\n\ninterface IAdminV2 {\n event CancelDelayUpdated(uint256 oldCancelDelay, uint256 newCancelDelay);\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n function setCancelDelay(uint256 newCancelDelay) external;\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n}\n\n// contracts/interfaces/IAdminV2Errors.sol\n\ninterface IAdminV2Errors {\n error CancelDelayBelowMin();\n error FeeRateAboveMax();\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IFastBridgeV2Errors.sol\n\ninterface IFastBridgeV2Errors {\n error AmountIncorrect();\n error ChainIncorrect();\n error ExclusivityParamsIncorrect();\n error MsgValueIncorrect();\n error SenderIncorrect();\n error StatusIncorrect();\n error TokenNotContract();\n error ZapDataLengthAboveMax();\n error ZapNativeNotSupported();\n error ZeroAddress();\n\n error RecipientIncorrectReturnValue();\n error RecipientNoReturnValue();\n\n error DeadlineExceeded();\n error DeadlineNotExceeded();\n error DeadlineTooShort();\n error DisputePeriodNotPassed();\n error DisputePeriodPassed();\n error ExclusivityPeriodNotPassed();\n\n error TransactionRelayed();\n}\n\n// contracts/interfaces/IMulticallTarget.sol\n\n/// @notice Interface for a contract that can be called multiple times by the same caller. Inspired by MulticallV3:\n/// https://github.com/mds1/multicall/blob/master/src/Multicall3.sol\ninterface IMulticallTarget {\n struct Result {\n bool success;\n bytes returnData;\n }\n\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external;\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results);\n}\n\n// contracts/interfaces/IZapRecipient.sol\n\ninterface IZapRecipient {\n function zap(address token, uint256 amount, bytes memory zapData) external payable returns (bytes4);\n}\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// contracts/interfaces/IFastBridgeV2.sol\n\ninterface IFastBridgeV2 is IFastBridge {\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n struct BridgeTxDetails {\n BridgeStatus status;\n uint32 destChainId;\n uint56 proofBlockTimestamp;\n address proofRelayer;\n }\n\n struct BridgeRelay {\n uint48 blockNumber;\n uint48 blockTimestamp;\n address relayer;\n }\n\n /// @notice New params introduced in the FastBridgeV2.\n /// We are passing fields from the older BridgeParams struct outside of this struct\n /// for backwards compatibility.\n /// Note: quoteRelayer and quoteExclusivitySeconds are either both zero (indicating no exclusivity)\n /// or both non-zero (indicating exclusivity for the given period).\n /// Note: zapNative \u003e 0 can NOT be used with destToken = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE (native token)\n /// @param quoteRelayer Relayer that provided the quote for the transaction\n /// @param quoteExclusivitySeconds Period of time the quote relayer is guaranteed exclusivity after user's deposit\n /// @param quoteId Unique quote identifier used for tracking the quote\n /// @param zapNative ETH value to send to the recipient (if any)\n /// @param zapData Parameters for the Zap to the destination recipient (if any)\n struct BridgeParamsV2 {\n address quoteRelayer;\n int256 quoteExclusivitySeconds;\n bytes quoteId;\n uint256 zapNative;\n bytes zapData;\n }\n\n /// @notice Updated bridge transaction struct to include parameters introduced in FastBridgeV2.\n /// Note: only `exclusivityRelayer` can fill such a transaction until `exclusivityEndTime`.\n struct BridgeTransactionV2 {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n // Note: sendChainGas flag from V1 is deprecated\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n address exclusivityRelayer;\n uint256 exclusivityEndTime;\n uint256 zapNative; // ETH value to send to the recipient (if any)\n bytes zapData; // data to pass for the Zap action (if any)\n }\n\n event BridgeQuoteDetails(bytes32 indexed transactionId, bytes quoteId);\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability\n /// to provide temporary exclusivity fill rights for the quote relayer.\n /// @param params The parameters required to bridge\n /// @param paramsV2 The parameters for exclusivity fill rights (optional, can be left empty)\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function relay(bytes memory request, address relayer) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param transactionId The transaction id associated with the encoded bridge transaction to prove\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital.\n /// @notice Can only send funds to the relayer address on the proof.\n /// @param request The encoded bridge transaction to claim on origin chain\n function claim(bytes memory request) external;\n\n /// @notice Cancels an outstanding bridge transaction in case optimistic bridging failed and returns the full amount\n /// to the original sender.\n /// @param request The encoded bridge transaction to refund\n function cancel(bytes memory request) external;\n\n /// @notice Checks if a transaction has been relayed\n /// @param transactionId The ID of the transaction to check\n /// @return True if the transaction has been relayed, false otherwise\n function bridgeRelays(bytes32 transactionId) external view returns (bool);\n\n /// @notice Returns the status of a bridge transaction\n /// @param transactionId The ID of the bridge transaction\n /// @return BridgeStatus Status of the bridge transaction\n function bridgeStatuses(bytes32 transactionId) external view returns (BridgeStatus);\n\n /// @notice Returns the timestamp and relayer of a bridge proof\n /// @param transactionId The ID of the bridge transaction\n /// @return timestamp The timestamp of the bridge proof\n /// @return relayer The relayer address of the bridge proof\n function bridgeProofs(bytes32 transactionId) external view returns (uint96 timestamp, address relayer);\n\n /// @notice Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\n /// @param request The bridge request to decode\n function getBridgeTransactionV2(bytes memory request) external view returns (BridgeTransactionV2 memory);\n}\n\n// contracts/utils/MulticallTarget.sol\n\n// solhint-disable avoid-low-level-calls\n/// @notice Template for a contract that supports batched calls (preserving the msg.sender).\n/// Only calls with zero msg.value could be batched.\nabstract contract MulticallTarget is IMulticallTarget {\n error MulticallTarget__UndeterminedRevert();\n\n /// @notice Perform a batched call to this contract, preserving the msg.sender.\n /// The return data from each call is discarded.\n /// @dev The method is non-payable, so only calls with `msg.value == 0` could be batched.\n /// It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag.\n /// Otherwise, the whole batch call will be reverted with the original revert reason.\n /// @param data List of abi-encoded calldata for the calls to perform.\n /// @param ignoreReverts Whether to ignore the revert errors from the calls.\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external {\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\n if (!success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(result);\n }\n }\n }\n\n /// @notice Perform a batched call to this contract, preserving the msg.sender.\n /// The return data from each call is preserved.\n /// @dev The method is non-payable, so only calls with `msg.value == 0` could be batched.\n /// It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag.\n /// Otherwise, the whole batch call will be reverted with the original revert reason.\n /// @param data List of abi-encoded calldata for the calls to perform.\n /// @param ignoreReverts Whether to ignore the revert errors from the calls.\n /// @return results List of results from the calls: `(success, returnData)`.\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results)\n {\n results = new Result[](data.length);\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (results[i].success, results[i].returnData) = address(this).delegatecall(data[i]);\n if (!results[i].success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(results[i].returnData);\n }\n }\n }\n\n /// @dev Bubbles the revert message from the underlying call.\n /// Note: preserves the same custom error or revert string, if one was used.\n /// Source: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v5.0.2/contracts/utils/Address.sol#L143-L158\n function _bubbleRevert(bytes memory returnData) internal pure {\n // Look for revert reason and bubble it up if present\n if (returnData.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n // solhint-disable-next-line no-inline-assembly\n assembly {\n let returndata_size := mload(returnData)\n revert(add(32, returnData), returndata_size)\n }\n } else {\n revert MulticallTarget__UndeterminedRevert();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// contracts/libs/BridgeTransactionV2.sol\n\n// solhint-disable no-inline-assembly\nlibrary BridgeTransactionV2Lib {\n uint16 internal constant VERSION = 2;\n\n // Offsets of the fields in the packed BridgeTransactionV2 struct\n // uint16 version [000 .. 002)\n // uint32 originChainId [002 .. 006)\n // uint32 destChainId [006 .. 010)\n // address originSender [010 .. 030)\n // address destRecipient [030 .. 050)\n // address originToken [050 .. 070)\n // address destToken [070 .. 090)\n // uint256 originAmount [090 .. 122)\n // uint256 destAmount [122 .. 154)\n // uint256 originFeeAmount [154 .. 186)\n // uint256 deadline [186 .. 218)\n // uint256 nonce [218 .. 250)\n // address exclusivityRelayer [250 .. 270)\n // uint256 exclusivityEndTime [270 .. 302)\n // uint256 zapNative [302 .. 334)\n // bytes zapData [334 .. ***)\n\n // forgefmt: disable-start\n uint256 private constant OFFSET_ORIGIN_CHAIN_ID = 2;\n uint256 private constant OFFSET_DEST_CHAIN_ID = 6;\n uint256 private constant OFFSET_ORIGIN_SENDER = 10;\n uint256 private constant OFFSET_DEST_RECIPIENT = 30;\n uint256 private constant OFFSET_ORIGIN_TOKEN = 50;\n uint256 private constant OFFSET_DEST_TOKEN = 70;\n uint256 private constant OFFSET_ORIGIN_AMOUNT = 90;\n uint256 private constant OFFSET_DEST_AMOUNT = 122;\n uint256 private constant OFFSET_ORIGIN_FEE_AMOUNT = 154;\n uint256 private constant OFFSET_DEADLINE = 186;\n uint256 private constant OFFSET_NONCE = 218;\n uint256 private constant OFFSET_EXCLUSIVITY_RELAYER = 250;\n uint256 private constant OFFSET_EXCLUSIVITY_END_TIME = 270;\n uint256 private constant OFFSET_ZAP_NATIVE = 302;\n uint256 private constant OFFSET_ZAP_DATA = 334;\n // forgefmt: disable-end\n\n error BridgeTransactionV2__InvalidEncodedTx();\n error BridgeTransactionV2__UnsupportedVersion(uint16 version);\n\n /// @notice Validates the encoded transaction to be a tightly packed encoded payload for BridgeTransactionV2.\n /// @dev Checks the minimum length and the version, use this function before decoding any of the fields.\n function validateV2(bytes calldata encodedTx) internal pure {\n // Check the minimum length: must at least include all static fields.\n if (encodedTx.length \u003c OFFSET_ZAP_DATA) revert BridgeTransactionV2__InvalidEncodedTx();\n // Once we validated the length, we can be sure that the version field is present.\n uint16 version_ = version(encodedTx);\n if (version_ != VERSION) revert BridgeTransactionV2__UnsupportedVersion(version_);\n }\n\n /// @notice Encodes the BridgeTransactionV2 struct by tightly packing the fields.\n /// @dev `abi.decode` will not work as a result of the tightly packed fields. Use `decodeV2` to decode instead.\n function encodeV2(IFastBridgeV2.BridgeTransactionV2 memory bridgeTx) internal pure returns (bytes memory) {\n // We split the encoding into two parts to avoid stack-too-deep error\n bytes memory firstPart = abi.encodePacked(\n VERSION,\n bridgeTx.originChainId,\n bridgeTx.destChainId,\n bridgeTx.originSender,\n bridgeTx.destRecipient,\n bridgeTx.originToken,\n bridgeTx.destToken,\n bridgeTx.originAmount\n );\n return abi.encodePacked(\n firstPart,\n bridgeTx.destAmount,\n bridgeTx.originFeeAmount,\n // Note: we skip the deprecated `sendChainGas` flag, which was present in BridgeTransaction V1\n bridgeTx.deadline,\n bridgeTx.nonce,\n // New V2 fields: exclusivity\n bridgeTx.exclusivityRelayer,\n bridgeTx.exclusivityEndTime,\n // New V2 fields: Zap\n bridgeTx.zapNative,\n bridgeTx.zapData\n );\n }\n\n /// @notice Decodes the BridgeTransactionV2 struct from the encoded transaction.\n /// @dev Encoded BridgeTransactionV2 struct must be tightly packed.\n /// Use `validateV2` before decoding to ensure the encoded transaction is valid.\n function decodeV2(bytes calldata encodedTx)\n internal\n pure\n returns (IFastBridgeV2.BridgeTransactionV2 memory bridgeTx)\n {\n bridgeTx.originChainId = originChainId(encodedTx);\n bridgeTx.destChainId = destChainId(encodedTx);\n bridgeTx.originSender = originSender(encodedTx);\n bridgeTx.destRecipient = destRecipient(encodedTx);\n bridgeTx.originToken = originToken(encodedTx);\n bridgeTx.destToken = destToken(encodedTx);\n bridgeTx.originAmount = originAmount(encodedTx);\n bridgeTx.destAmount = destAmount(encodedTx);\n bridgeTx.originFeeAmount = originFeeAmount(encodedTx);\n bridgeTx.deadline = deadline(encodedTx);\n bridgeTx.nonce = nonce(encodedTx);\n bridgeTx.exclusivityRelayer = exclusivityRelayer(encodedTx);\n bridgeTx.exclusivityEndTime = exclusivityEndTime(encodedTx);\n bridgeTx.zapNative = zapNative(encodedTx);\n bridgeTx.zapData = zapData(encodedTx);\n }\n\n /// @notice Extracts the version from the encoded transaction.\n function version(bytes calldata encodedTx) internal pure returns (uint16 version_) {\n // Load 32 bytes from the start and shift it 240 bits to the right to get the highest 16 bits.\n assembly {\n version_ := shr(240, calldataload(encodedTx.offset))\n }\n }\n\n /// @notice Extracts the origin chain ID from the encoded transaction.\n function originChainId(bytes calldata encodedTx) internal pure returns (uint32 originChainId_) {\n // Load 32 bytes from the offset and shift it 224 bits to the right to get the highest 32 bits.\n assembly {\n originChainId_ := shr(224, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_CHAIN_ID)))\n }\n }\n\n /// @notice Extracts the destination chain ID from the encoded transaction.\n function destChainId(bytes calldata encodedTx) internal pure returns (uint32 destChainId_) {\n // Load 32 bytes from the offset and shift it 224 bits to the right to get the highest 32 bits.\n assembly {\n destChainId_ := shr(224, calldataload(add(encodedTx.offset, OFFSET_DEST_CHAIN_ID)))\n }\n }\n\n /// @notice Extracts the origin sender from the encoded transaction.\n function originSender(bytes calldata encodedTx) internal pure returns (address originSender_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n originSender_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_SENDER)))\n }\n }\n\n /// @notice Extracts the destination recipient from the encoded transaction.\n function destRecipient(bytes calldata encodedTx) internal pure returns (address destRecipient_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n destRecipient_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_DEST_RECIPIENT)))\n }\n }\n\n /// @notice Extracts the origin token from the encoded transaction.\n function originToken(bytes calldata encodedTx) internal pure returns (address originToken_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n originToken_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_TOKEN)))\n }\n }\n\n /// @notice Extracts the destination token from the encoded transaction.\n function destToken(bytes calldata encodedTx) internal pure returns (address destToken_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n destToken_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_DEST_TOKEN)))\n }\n }\n\n /// @notice Extracts the origin amount from the encoded transaction.\n function originAmount(bytes calldata encodedTx) internal pure returns (uint256 originAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n originAmount_ := calldataload(add(encodedTx.offset, OFFSET_ORIGIN_AMOUNT))\n }\n }\n\n /// @notice Extracts the destination amount from the encoded transaction.\n function destAmount(bytes calldata encodedTx) internal pure returns (uint256 destAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n destAmount_ := calldataload(add(encodedTx.offset, OFFSET_DEST_AMOUNT))\n }\n }\n\n /// @notice Extracts the origin fee amount from the encoded transaction.\n function originFeeAmount(bytes calldata encodedTx) internal pure returns (uint256 originFeeAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n originFeeAmount_ := calldataload(add(encodedTx.offset, OFFSET_ORIGIN_FEE_AMOUNT))\n }\n }\n\n /// @notice Extracts the deadline from the encoded transaction.\n function deadline(bytes calldata encodedTx) internal pure returns (uint256 deadline_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n deadline_ := calldataload(add(encodedTx.offset, OFFSET_DEADLINE))\n }\n }\n\n /// @notice Extracts the nonce from the encoded transaction.\n function nonce(bytes calldata encodedTx) internal pure returns (uint256 nonce_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n nonce_ := calldataload(add(encodedTx.offset, OFFSET_NONCE))\n }\n }\n\n /// @notice Extracts the exclusivity relayer from the encoded transaction.\n function exclusivityRelayer(bytes calldata encodedTx) internal pure returns (address exclusivityRelayer_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n exclusivityRelayer_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_EXCLUSIVITY_RELAYER)))\n }\n }\n\n /// @notice Extracts the exclusivity end time from the encoded transaction.\n function exclusivityEndTime(bytes calldata encodedTx) internal pure returns (uint256 exclusivityEndTime_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n exclusivityEndTime_ := calldataload(add(encodedTx.offset, OFFSET_EXCLUSIVITY_END_TIME))\n }\n }\n\n /// @notice Extracts the Zap's native value from the encoded transaction.\n function zapNative(bytes calldata encodedTx) internal pure returns (uint256 zapNative_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n zapNative_ := calldataload(add(encodedTx.offset, OFFSET_ZAP_NATIVE))\n }\n }\n\n /// @notice Extracts the Zap's data from the encoded transaction.\n function zapData(bytes calldata encodedTx) internal pure returns (bytes calldata zapData_) {\n zapData_ = encodedTx[OFFSET_ZAP_DATA:];\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/AdminV2.sol\n\ncontract AdminV2 is AccessControlEnumerable, IAdminV2, IAdminV2Errors {\n using SafeERC20 for IERC20;\n\n /// @notice Address reserved for native gas token (ETH on Ethereum and most L2s, AVAX on Avalanche, etc)\n address public constant NATIVE_GAS_TOKEN = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Role identifier for Quoter API's off-chain authentication.\n /// @dev Only addresses with this role can post FastBridge quotes to the API.\n bytes32 public constant QUOTER_ROLE = keccak256(\"QUOTER_ROLE\");\n\n /// @notice Role identifier for Prover's on-chain authentication in FastBridge.\n /// @dev Only addresses with this role can provide proofs that a FastBridge request has been relayed.\n bytes32 public constant PROVER_ROLE = keccak256(\"PROVER_ROLE\");\n\n /// @notice Role identifier for Guard's on-chain authentication in FastBridge.\n /// @dev Only addresses with this role can dispute submitted relay proofs during the dispute period.\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n\n /// @notice Role identifier for Canceler's on-chain authentication in FastBridge.\n /// @dev Only addresses with this role can cancel a FastBridge transaction without the cancel delay.\n bytes32 public constant CANCELER_ROLE = keccak256(\"CANCELER_ROLE\");\n\n /// @notice Role identifier for Governor's on-chain administrative authority.\n /// @dev Only addresses with this role can perform administrative tasks within the contract.\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n /// @notice Denominator for fee rates, represents 100%.\n uint256 public constant FEE_BPS = 1e6;\n /// @notice Maximum protocol fee rate: 1% on origin amount.\n uint256 public constant FEE_RATE_MAX = 0.01e6;\n\n /// @notice Minimum cancel delay that can be set by the governor.\n uint256 public constant MIN_CANCEL_DELAY = 1 hours;\n /// @notice Default cancel delay set during the contract deployment.\n uint256 public constant DEFAULT_CANCEL_DELAY = 1 days;\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Delay for a transaction after which it could be permisionlessly cancelled\n uint256 public cancelDelay;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Use ZapNative V2 requests instead.\n uint256 public immutable chainGasAmount = 0;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n _setCancelDelay(DEFAULT_CANCEL_DELAY);\n }\n\n /// @notice Allows the contract governor to set the cancel delay. The cancel delay is the time after the transaction\n /// deadline after which it can be permissionlessly cancelled, if it hasn't been proven by any of the Relayers.\n function setCancelDelay(uint256 newCancelDelay) external onlyRole(GOVERNOR_ROLE) {\n _setCancelDelay(newCancelDelay);\n }\n\n /// @notice Allows the contract governor to set the protocol fee rate. The protocol fee is taken from the origin\n /// amount only for completed and claimed transactions.\n /// @dev The protocol fee is abstracted away from the relayers, they always operate using the amounts after fees:\n /// what they see as the origin amount emitted in the log is what they get credited with.\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n if (newFeeRate \u003e FEE_RATE_MAX) revert FeeRateAboveMax();\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n /// @notice Allows the contract governor to sweep the accumulated protocol fees in the contract.\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n emit FeesSwept(token, recipient, feeAmount);\n /// Sweep the fees as the last transaction action\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(recipient), feeAmount);\n } else {\n IERC20(token).safeTransfer(recipient, feeAmount);\n }\n }\n\n /// @notice Internal function to set the cancel delay. Security checks are performed outside of this function.\n function _setCancelDelay(uint256 newCancelDelay) private {\n if (newCancelDelay \u003c MIN_CANCEL_DELAY) revert CancelDelayBelowMin();\n uint256 oldCancelDelay = cancelDelay;\n cancelDelay = newCancelDelay;\n emit CancelDelayUpdated(oldCancelDelay, newCancelDelay);\n }\n}\n\n// contracts/FastBridgeV2.sol\n\n/// @notice FastBridgeV2 is a contract for bridging tokens across chains.\ncontract FastBridgeV2 is AdminV2, MulticallTarget, IFastBridgeV2, IFastBridgeV2Errors {\n using BridgeTransactionV2Lib for bytes;\n using SafeERC20 for IERC20;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n /// @notice Maximum length of accepted zapData\n uint256 public constant MAX_ZAP_DATA_LENGTH = 2 ** 16 - 1;\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeTxDetails) public bridgeTxDetails;\n /// @notice Relay details on destination chain\n mapping(bytes32 =\u003e BridgeRelay) public bridgeRelayDetails;\n /// @notice Unique bridge nonces tracked per originSender\n mapping(address =\u003e uint256) public senderNonces;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Replaced by senderNonces\n uint256 public immutable nonce = 0;\n /// @notice the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) AdminV2(_owner) {\n deployBlock = block.number;\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n bridge({\n params: params,\n paramsV2: BridgeParamsV2({\n quoteRelayer: address(0),\n quoteExclusivitySeconds: 0,\n quoteId: bytes(\"\"),\n zapNative: 0,\n zapData: bytes(\"\")\n })\n });\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes calldata request) external payable {\n // relay override will validate the request\n relay({request: request, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes calldata request, bytes32 destTxHash) external {\n request.validateV2();\n prove({transactionId: keccak256(request), destTxHash: destTxHash, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridgeV2\n function claim(bytes calldata request) external {\n // claim override will validate the request\n claim({request: request, to: address(0)});\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Aggregate the read operations from the same storage slot\n address disputedRelayer = $.proofRelayer;\n BridgeStatus status = $.status;\n uint56 proofBlockTimestamp = $.proofBlockTimestamp;\n // Can only dispute a RELAYER_PROVED transaction within the dispute period\n if (status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(proofBlockTimestamp) \u003e DISPUTE_PERIOD) {\n revert DisputePeriodPassed();\n }\n // Update status to REQUESTED and delete the disputed proof details\n // Note: these are storage writes\n $.status = BridgeStatus.REQUESTED;\n $.proofRelayer = address(0);\n $.proofBlockTimestamp = 0;\n\n emit BridgeProofDisputed(transactionId, disputedRelayer);\n }\n\n /// Note: this function is deprecated and will be removed in a future version.\n /// @inheritdoc IFastBridge\n function refund(bytes calldata request) external {\n cancel(request);\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // The correct relayer can only claim a RELAYER_PROVED transaction after the dispute period\n if ($.status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if ($.proofRelayer != relayer) revert SenderIncorrect();\n return _timeSince($.proofBlockTimestamp) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n /// @dev This method is added to achieve backwards compatibility with decoding requests into V1 structs:\n /// - `zapNative` is partially reported as a zero/non-zero flag\n /// - `zapData` is ignored\n /// In order to process all kinds of requests use getBridgeTransactionV2 instead.\n function getBridgeTransaction(bytes calldata request) external view returns (BridgeTransaction memory) {\n // Try decoding into V2 struct first. This will revert if V1 struct is passed\n try this.getBridgeTransactionV2(request) returns (BridgeTransactionV2 memory txV2) {\n // Note: we entirely ignore the zapData field, as it was not present in V1\n return BridgeTransaction({\n originChainId: txV2.originChainId,\n destChainId: txV2.destChainId,\n originSender: txV2.originSender,\n destRecipient: txV2.destRecipient,\n originToken: txV2.originToken,\n destToken: txV2.destToken,\n originAmount: txV2.originAmount,\n destAmount: txV2.destAmount,\n originFeeAmount: txV2.originFeeAmount,\n sendChainGas: txV2.zapNative != 0,\n deadline: txV2.deadline,\n nonce: txV2.nonce\n });\n } catch {\n // Fallback to V1 struct\n return abi.decode(request, (BridgeTransaction));\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function getBridgeTransactionV2(bytes calldata request) external pure returns (BridgeTransactionV2 memory) {\n request.validateV2();\n return BridgeTransactionV2Lib.decodeV2(request);\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) public payable {\n int256 exclusivityEndTime = 0;\n // if relayer exclusivity is not intended for this bridge, set exclusivityEndTime to static zero\n // otherwise, set exclusivity to expire at the current block ts offset by quoteExclusivitySeconds\n if (paramsV2.quoteRelayer != address(0)) {\n exclusivityEndTime = int256(block.timestamp) + paramsV2.quoteExclusivitySeconds;\n }\n _validateBridgeParams(params, paramsV2, exclusivityEndTime);\n\n // transfer tokens to bridge contract\n /// @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _takeBridgedUserAsset(params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) {\n originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n }\n\n // set status to requested\n bytes memory request = BridgeTransactionV2Lib.encodeV2(\n BridgeTransactionV2({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n deadline: params.deadline,\n nonce: senderNonces[params.sender]++, // increment nonce on every bridge\n exclusivityRelayer: paramsV2.quoteRelayer,\n // We checked exclusivityEndTime to be in range [0 .. params.deadline] above, so can safely cast\n exclusivityEndTime: uint256(exclusivityEndTime),\n zapNative: paramsV2.zapNative,\n zapData: paramsV2.zapData\n })\n );\n bytes32 transactionId = keccak256(request);\n // Note: the tx status will be updated throughout the tx lifecycle, while destChainId is set once here\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n bridgeTxDetails[transactionId].destChainId = params.dstChainId;\n\n emit BridgeRequested({\n transactionId: transactionId,\n sender: params.sender,\n request: request,\n destChainId: params.dstChainId,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n sendChainGas: paramsV2.zapNative != 0\n });\n emit BridgeQuoteDetails(transactionId, paramsV2.quoteId);\n }\n\n /// @inheritdoc IFastBridgeV2\n function relay(bytes calldata request, address relayer) public payable {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n _validateRelayParams(request, transactionId, relayer);\n // mark bridge transaction as relayed\n bridgeRelayDetails[transactionId] =\n BridgeRelay({blockNumber: uint48(block.number), blockTimestamp: uint48(block.timestamp), relayer: relayer});\n\n // transfer tokens to recipient on destination chain and trigger Zap if requested\n address to = request.destRecipient();\n address token = request.destToken();\n uint256 amount = request.destAmount();\n uint256 zapNative = request.zapNative();\n\n // Emit the event before any external calls\n emit BridgeRelayed({\n transactionId: transactionId,\n relayer: relayer,\n to: to,\n originChainId: request.originChainId(),\n originToken: request.originToken(),\n destToken: token,\n originAmount: request.originAmount(),\n destAmount: amount,\n chainGasAmount: zapNative\n });\n\n // All state changes have been done at this point, can proceed to the external calls.\n // This follows the checks-effects-interactions pattern to mitigate potential reentrancy attacks.\n if (token == NATIVE_GAS_TOKEN) {\n // For the native gas token, additional zapNative is not allowed\n if (zapNative != 0) revert ZapNativeNotSupported();\n // Check that the correct msg.value was sent\n if (msg.value != amount) revert MsgValueIncorrect();\n // Don't do a native transfer yet: we will handle it alongside the Zap below\n } else {\n // For ERC20s, we check that the correct msg.value was sent\n if (msg.value != zapNative) revert MsgValueIncorrect();\n // We need to transfer the tokens from the Relayer to the recipient first before performing an\n // optional post-transfer Zap.\n IERC20(token).safeTransferFrom(msg.sender, to, amount);\n }\n // At this point we have done:\n // - Transferred the requested amount of ERC20 tokens to the recipient.\n // At this point we have confirmed:\n // - For ERC20s: msg.value matches the requested zapNative amount.\n // - For the native gas token: msg.value matches the requested destAmount.\n // Remaining optional things to do:\n // - Forward the full msg.value to the recipient (if non-zero).\n // - Trigger a Zap (if zapData is present).\n bytes calldata zapData = request.zapData();\n if (zapData.length != 0) {\n // Zap Data is present: Zap has been requested by the recipient. Trigger it forwarding the full msg.value.\n\n // Note: if token has a fee on transfers, the recipient will have received less than `amount`.\n // This is a very niche edge case and should be handled by the recipient contract.\n _triggerZapWithChecks({recipient: to, token: token, amount: amount, zapData: zapData});\n } else if (msg.value != 0) {\n // Zap Data is missing, but msg.value was sent. This could happen in two different cases:\n // - Relay with the native gas token is happening.\n // - Relay with ERC20 is happening, with a `zapNative \u003e 0` request.\n // In both cases, we need to transfer the full msg.value to the recipient.\n Address.sendValue(payable(to), msg.value);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) public onlyRole(PROVER_ROLE) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n\n // Can only prove a REQUESTED transaction\n if ($.status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n // Update status to RELAYER_PROVED and store the proof details\n // Note: these are storage writes\n $.status = BridgeStatus.RELAYER_PROVED;\n $.proofBlockTimestamp = uint56(block.timestamp);\n $.proofRelayer = relayer;\n\n emit BridgeProofProvided(transactionId, relayer, destTxHash);\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes calldata request, address to) public {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Aggregate the read operations from the same storage slot\n address proofRelayer = $.proofRelayer;\n BridgeStatus status = $.status;\n uint56 proofBlockTimestamp = $.proofBlockTimestamp;\n\n // Can only claim a RELAYER_PROVED transaction after the dispute period\n if (status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(proofBlockTimestamp) \u003c= DISPUTE_PERIOD) {\n revert DisputePeriodNotPassed();\n }\n\n if (to == address(0)) {\n // Anyone could claim the funds to the proven relayer on their behalf\n to = proofRelayer;\n } else if (proofRelayer != msg.sender) {\n // Only the proven relayer could specify an address to claim the funds to\n revert SenderIncorrect();\n }\n\n // Update status to RELAYER_CLAIMED and transfer the origin collateral to the specified claim address\n // Note: this is a storage write\n $.status = BridgeStatus.RELAYER_CLAIMED;\n\n address token = request.originToken();\n uint256 amount = request.originAmount();\n // Update protocol fees if origin fee amount exists\n uint256 originFeeAmount = request.originFeeAmount();\n if (originFeeAmount \u003e 0) protocolFees[token] += originFeeAmount;\n // Emit the event before any external calls\n emit BridgeDepositClaimed(transactionId, proofRelayer, to, token, amount);\n // Complete the relayer claim as the last transaction action\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(to), amount);\n } else {\n IERC20(token).safeTransfer(to, amount);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function cancel(bytes calldata request) public {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Can only cancel a REQUESTED transaction after its deadline expires\n if ($.status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n uint256 deadline = request.deadline();\n // Permissionless cancel is only allowed after `cancelDelay` on top of the deadline\n if (!hasRole(CANCELER_ROLE, msg.sender)) deadline += cancelDelay;\n if (block.timestamp \u003c= deadline) revert DeadlineNotExceeded();\n // Update status to REFUNDED and return the full amount (collateral + protocol fees) to the original sender.\n // The protocol fees are only updated when the transaction is claimed, so we don't need to update them here.\n // Note: this is a storage write\n $.status = BridgeStatus.REFUNDED;\n\n address to = request.originSender();\n address token = request.originToken();\n uint256 amount = request.originAmount() + request.originFeeAmount();\n // Emit the event before any external calls\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n // Complete the user cancel as the last transaction action\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(to), amount);\n } else {\n IERC20(token).safeTransfer(to, amount);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeStatuses(bytes32 transactionId) public view returns (BridgeStatus status) {\n return bridgeTxDetails[transactionId].status;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeProofs(bytes32 transactionId) public view returns (uint96 timestamp, address relayer) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n\n timestamp = $.proofBlockTimestamp;\n relayer = $.proofRelayer;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeRelays(bytes32 transactionId) public view returns (bool) {\n // has this transactionId been relayed?\n return bridgeRelayDetails[transactionId].relayer != address(0);\n }\n\n /// @notice Takes the bridged asset from the user into FastBridgeV2 custody. It will be later\n /// claimed by the relayer who completed the relay on destination chain, or transferred back to the user\n /// via the cancel function should no one complete the relay.\n function _takeBridgedUserAsset(address token, uint256 amount) internal returns (uint256 amountTaken) {\n if (token == NATIVE_GAS_TOKEN) {\n // For the native gas token, we just need to check that the supplied msg.value is correct.\n // Supplied `msg.value` is already in FastBridgeV2 custody.\n if (amount != msg.value) revert MsgValueIncorrect();\n amountTaken = msg.value;\n } else {\n // For ERC20s, token is explicitly transferred from the user to FastBridgeV2.\n // We don't allow non-zero `msg.value` to avoid extra funds from being stuck in FastBridgeV2.\n if (msg.value != 0) revert MsgValueIncorrect();\n // Throw an explicit error if the provided token address is not a contract\n if (token.code.length == 0) revert TokenNotContract();\n amountTaken = IERC20(token).balanceOf(address(this));\n IERC20(token).safeTransferFrom(msg.sender, address(this), amount);\n // Use the balance difference as the amount taken in case of fee on transfer tokens.\n amountTaken = IERC20(token).balanceOf(address(this)) - amountTaken;\n }\n }\n\n /// @notice Calls the Recipient's hook function with the specified zapData and performs\n /// all the necessary checks for the returned value.\n function _triggerZapWithChecks(address recipient, address token, uint256 amount, bytes calldata zapData) internal {\n // This will bubble any revert messages from the hook function\n bytes memory returnData = Address.functionCallWithValue({\n target: recipient,\n data: abi.encodeCall(IZapRecipient.zap, (token, amount, zapData)),\n // Note: see `relay()` for reasoning behind passing msg.value\n value: msg.value\n });\n // Explicit revert if no return data at all\n if (returnData.length == 0) revert RecipientNoReturnValue();\n // Check that exactly a single return value was returned\n if (returnData.length != 32) revert RecipientIncorrectReturnValue();\n // Return value should be abi-encoded hook function selector\n if (bytes32(returnData) != bytes32(IZapRecipient.zap.selector)) {\n revert RecipientIncorrectReturnValue();\n }\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint56(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint56).max but\n /// proof.timestamp \u003c type(uint56).max via unchecked statement\n /// @param proofBlockTimestamp The bridge proof block timestamp\n /// @return delta Time delta since proof submitted\n function _timeSince(uint56 proofBlockTimestamp) internal view returns (uint256 delta) {\n unchecked {\n delta = uint56(block.timestamp) - proofBlockTimestamp;\n }\n }\n\n /// @notice Performs all the necessary checks for a bridge to happen.\n /// @dev There's no good way to refactor this function to reduce cyclomatic complexity due to\n /// the number of checks that need to be performed, so we skip the code-complexity rule here.\n // solhint-disable-next-line code-complexity\n function _validateBridgeParams(\n BridgeParams memory params,\n BridgeParamsV2 memory paramsV2,\n int256 exclusivityEndTime\n )\n internal\n view\n {\n // Check V1 (legacy) params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.sender == address(0) || params.to == address(0)) revert ZeroAddress();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n // Check V2 params\n if (paramsV2.zapData.length \u003e MAX_ZAP_DATA_LENGTH) revert ZapDataLengthAboveMax();\n if (paramsV2.zapNative != 0 \u0026\u0026 params.destToken == NATIVE_GAS_TOKEN) {\n revert ZapNativeNotSupported();\n }\n // exclusivityEndTime must be in range [0 .. params.deadline]\n if (exclusivityEndTime \u003c 0 || exclusivityEndTime \u003e int256(params.deadline)) {\n revert ExclusivityParamsIncorrect();\n }\n }\n\n /// @notice Performs all the necessary checks for a relay to happen.\n function _validateRelayParams(bytes calldata request, bytes32 transactionId, address relayer) internal view {\n if (relayer == address(0)) revert ZeroAddress();\n // Check if the transaction has already been relayed\n if (bridgeRelays(transactionId)) revert TransactionRelayed();\n if (request.destChainId() != block.chainid) revert ChainIncorrect();\n // Check the deadline for relay to happen\n if (block.timestamp \u003e request.deadline()) revert DeadlineExceeded();\n // Check the exclusivity period, if it is still ongoing\n address exclRelayer = request.exclusivityRelayer();\n if (exclRelayer != address(0) \u0026\u0026 exclRelayer != relayer \u0026\u0026 block.timestamp \u003c= request.exclusivityEndTime()) {\n revert ExclusivityPeriodNotPassed();\n }\n }\n}\n","language":"Solidity","languageVersion":"0.8.24","compilerVersion":"0.8.24","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"","srcMapRuntime":"","abiDefinition":[{"inputs":[],"name":"CancelDelayBelowMin","type":"error"},{"inputs":[],"name":"FeeRateAboveMax","type":"error"}],"userDoc":{"kind":"user","methods":{},"version":1},"developerDoc":{"kind":"dev","methods":{},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[],\"name\":\"CancelDelayBelowMin\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"FeeRateAboveMax\",\"type\":\"error\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeV2.sol\":\"IAdminV2Errors\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeV2.sol\":{\"keccak256\":\"0xac79c463688a682ca706a4ef95e7817b83548cdfa8182ba0426ac7e5e07613d8\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://b3ecb7097381287cafc3a73f3a2bb03565115ebb682a85064e0b0dc2f7e2919d\",\"dweb:/ipfs/QmatruW3nYZTksf3CeQ8wwiAG4c7xoEJBEp6drHPtFLBRK\"]}},\"version\":1}"},"hashes":{}},"solidity/FastBridgeV2.sol:IERC165":{"code":"0x","runtime-code":"0x","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.24 ^0.8.20 ^0.8.4;\n\n// contracts/interfaces/IAdminV2.sol\n\ninterface IAdminV2 {\n event CancelDelayUpdated(uint256 oldCancelDelay, uint256 newCancelDelay);\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n function setCancelDelay(uint256 newCancelDelay) external;\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n}\n\n// contracts/interfaces/IAdminV2Errors.sol\n\ninterface IAdminV2Errors {\n error CancelDelayBelowMin();\n error FeeRateAboveMax();\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IFastBridgeV2Errors.sol\n\ninterface IFastBridgeV2Errors {\n error AmountIncorrect();\n error ChainIncorrect();\n error ExclusivityParamsIncorrect();\n error MsgValueIncorrect();\n error SenderIncorrect();\n error StatusIncorrect();\n error TokenNotContract();\n error ZapDataLengthAboveMax();\n error ZapNativeNotSupported();\n error ZeroAddress();\n\n error RecipientIncorrectReturnValue();\n error RecipientNoReturnValue();\n\n error DeadlineExceeded();\n error DeadlineNotExceeded();\n error DeadlineTooShort();\n error DisputePeriodNotPassed();\n error DisputePeriodPassed();\n error ExclusivityPeriodNotPassed();\n\n error TransactionRelayed();\n}\n\n// contracts/interfaces/IMulticallTarget.sol\n\n/// @notice Interface for a contract that can be called multiple times by the same caller. Inspired by MulticallV3:\n/// https://github.com/mds1/multicall/blob/master/src/Multicall3.sol\ninterface IMulticallTarget {\n struct Result {\n bool success;\n bytes returnData;\n }\n\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external;\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results);\n}\n\n// contracts/interfaces/IZapRecipient.sol\n\ninterface IZapRecipient {\n function zap(address token, uint256 amount, bytes memory zapData) external payable returns (bytes4);\n}\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// contracts/interfaces/IFastBridgeV2.sol\n\ninterface IFastBridgeV2 is IFastBridge {\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n struct BridgeTxDetails {\n BridgeStatus status;\n uint32 destChainId;\n uint56 proofBlockTimestamp;\n address proofRelayer;\n }\n\n struct BridgeRelay {\n uint48 blockNumber;\n uint48 blockTimestamp;\n address relayer;\n }\n\n /// @notice New params introduced in the FastBridgeV2.\n /// We are passing fields from the older BridgeParams struct outside of this struct\n /// for backwards compatibility.\n /// Note: quoteRelayer and quoteExclusivitySeconds are either both zero (indicating no exclusivity)\n /// or both non-zero (indicating exclusivity for the given period).\n /// Note: zapNative \u003e 0 can NOT be used with destToken = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE (native token)\n /// @param quoteRelayer Relayer that provided the quote for the transaction\n /// @param quoteExclusivitySeconds Period of time the quote relayer is guaranteed exclusivity after user's deposit\n /// @param quoteId Unique quote identifier used for tracking the quote\n /// @param zapNative ETH value to send to the recipient (if any)\n /// @param zapData Parameters for the Zap to the destination recipient (if any)\n struct BridgeParamsV2 {\n address quoteRelayer;\n int256 quoteExclusivitySeconds;\n bytes quoteId;\n uint256 zapNative;\n bytes zapData;\n }\n\n /// @notice Updated bridge transaction struct to include parameters introduced in FastBridgeV2.\n /// Note: only `exclusivityRelayer` can fill such a transaction until `exclusivityEndTime`.\n struct BridgeTransactionV2 {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n // Note: sendChainGas flag from V1 is deprecated\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n address exclusivityRelayer;\n uint256 exclusivityEndTime;\n uint256 zapNative; // ETH value to send to the recipient (if any)\n bytes zapData; // data to pass for the Zap action (if any)\n }\n\n event BridgeQuoteDetails(bytes32 indexed transactionId, bytes quoteId);\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability\n /// to provide temporary exclusivity fill rights for the quote relayer.\n /// @param params The parameters required to bridge\n /// @param paramsV2 The parameters for exclusivity fill rights (optional, can be left empty)\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function relay(bytes memory request, address relayer) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param transactionId The transaction id associated with the encoded bridge transaction to prove\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital.\n /// @notice Can only send funds to the relayer address on the proof.\n /// @param request The encoded bridge transaction to claim on origin chain\n function claim(bytes memory request) external;\n\n /// @notice Cancels an outstanding bridge transaction in case optimistic bridging failed and returns the full amount\n /// to the original sender.\n /// @param request The encoded bridge transaction to refund\n function cancel(bytes memory request) external;\n\n /// @notice Checks if a transaction has been relayed\n /// @param transactionId The ID of the transaction to check\n /// @return True if the transaction has been relayed, false otherwise\n function bridgeRelays(bytes32 transactionId) external view returns (bool);\n\n /// @notice Returns the status of a bridge transaction\n /// @param transactionId The ID of the bridge transaction\n /// @return BridgeStatus Status of the bridge transaction\n function bridgeStatuses(bytes32 transactionId) external view returns (BridgeStatus);\n\n /// @notice Returns the timestamp and relayer of a bridge proof\n /// @param transactionId The ID of the bridge transaction\n /// @return timestamp The timestamp of the bridge proof\n /// @return relayer The relayer address of the bridge proof\n function bridgeProofs(bytes32 transactionId) external view returns (uint96 timestamp, address relayer);\n\n /// @notice Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\n /// @param request The bridge request to decode\n function getBridgeTransactionV2(bytes memory request) external view returns (BridgeTransactionV2 memory);\n}\n\n// contracts/utils/MulticallTarget.sol\n\n// solhint-disable avoid-low-level-calls\n/// @notice Template for a contract that supports batched calls (preserving the msg.sender).\n/// Only calls with zero msg.value could be batched.\nabstract contract MulticallTarget is IMulticallTarget {\n error MulticallTarget__UndeterminedRevert();\n\n /// @notice Perform a batched call to this contract, preserving the msg.sender.\n /// The return data from each call is discarded.\n /// @dev The method is non-payable, so only calls with `msg.value == 0` could be batched.\n /// It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag.\n /// Otherwise, the whole batch call will be reverted with the original revert reason.\n /// @param data List of abi-encoded calldata for the calls to perform.\n /// @param ignoreReverts Whether to ignore the revert errors from the calls.\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external {\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\n if (!success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(result);\n }\n }\n }\n\n /// @notice Perform a batched call to this contract, preserving the msg.sender.\n /// The return data from each call is preserved.\n /// @dev The method is non-payable, so only calls with `msg.value == 0` could be batched.\n /// It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag.\n /// Otherwise, the whole batch call will be reverted with the original revert reason.\n /// @param data List of abi-encoded calldata for the calls to perform.\n /// @param ignoreReverts Whether to ignore the revert errors from the calls.\n /// @return results List of results from the calls: `(success, returnData)`.\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results)\n {\n results = new Result[](data.length);\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (results[i].success, results[i].returnData) = address(this).delegatecall(data[i]);\n if (!results[i].success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(results[i].returnData);\n }\n }\n }\n\n /// @dev Bubbles the revert message from the underlying call.\n /// Note: preserves the same custom error or revert string, if one was used.\n /// Source: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v5.0.2/contracts/utils/Address.sol#L143-L158\n function _bubbleRevert(bytes memory returnData) internal pure {\n // Look for revert reason and bubble it up if present\n if (returnData.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n // solhint-disable-next-line no-inline-assembly\n assembly {\n let returndata_size := mload(returnData)\n revert(add(32, returnData), returndata_size)\n }\n } else {\n revert MulticallTarget__UndeterminedRevert();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// contracts/libs/BridgeTransactionV2.sol\n\n// solhint-disable no-inline-assembly\nlibrary BridgeTransactionV2Lib {\n uint16 internal constant VERSION = 2;\n\n // Offsets of the fields in the packed BridgeTransactionV2 struct\n // uint16 version [000 .. 002)\n // uint32 originChainId [002 .. 006)\n // uint32 destChainId [006 .. 010)\n // address originSender [010 .. 030)\n // address destRecipient [030 .. 050)\n // address originToken [050 .. 070)\n // address destToken [070 .. 090)\n // uint256 originAmount [090 .. 122)\n // uint256 destAmount [122 .. 154)\n // uint256 originFeeAmount [154 .. 186)\n // uint256 deadline [186 .. 218)\n // uint256 nonce [218 .. 250)\n // address exclusivityRelayer [250 .. 270)\n // uint256 exclusivityEndTime [270 .. 302)\n // uint256 zapNative [302 .. 334)\n // bytes zapData [334 .. ***)\n\n // forgefmt: disable-start\n uint256 private constant OFFSET_ORIGIN_CHAIN_ID = 2;\n uint256 private constant OFFSET_DEST_CHAIN_ID = 6;\n uint256 private constant OFFSET_ORIGIN_SENDER = 10;\n uint256 private constant OFFSET_DEST_RECIPIENT = 30;\n uint256 private constant OFFSET_ORIGIN_TOKEN = 50;\n uint256 private constant OFFSET_DEST_TOKEN = 70;\n uint256 private constant OFFSET_ORIGIN_AMOUNT = 90;\n uint256 private constant OFFSET_DEST_AMOUNT = 122;\n uint256 private constant OFFSET_ORIGIN_FEE_AMOUNT = 154;\n uint256 private constant OFFSET_DEADLINE = 186;\n uint256 private constant OFFSET_NONCE = 218;\n uint256 private constant OFFSET_EXCLUSIVITY_RELAYER = 250;\n uint256 private constant OFFSET_EXCLUSIVITY_END_TIME = 270;\n uint256 private constant OFFSET_ZAP_NATIVE = 302;\n uint256 private constant OFFSET_ZAP_DATA = 334;\n // forgefmt: disable-end\n\n error BridgeTransactionV2__InvalidEncodedTx();\n error BridgeTransactionV2__UnsupportedVersion(uint16 version);\n\n /// @notice Validates the encoded transaction to be a tightly packed encoded payload for BridgeTransactionV2.\n /// @dev Checks the minimum length and the version, use this function before decoding any of the fields.\n function validateV2(bytes calldata encodedTx) internal pure {\n // Check the minimum length: must at least include all static fields.\n if (encodedTx.length \u003c OFFSET_ZAP_DATA) revert BridgeTransactionV2__InvalidEncodedTx();\n // Once we validated the length, we can be sure that the version field is present.\n uint16 version_ = version(encodedTx);\n if (version_ != VERSION) revert BridgeTransactionV2__UnsupportedVersion(version_);\n }\n\n /// @notice Encodes the BridgeTransactionV2 struct by tightly packing the fields.\n /// @dev `abi.decode` will not work as a result of the tightly packed fields. Use `decodeV2` to decode instead.\n function encodeV2(IFastBridgeV2.BridgeTransactionV2 memory bridgeTx) internal pure returns (bytes memory) {\n // We split the encoding into two parts to avoid stack-too-deep error\n bytes memory firstPart = abi.encodePacked(\n VERSION,\n bridgeTx.originChainId,\n bridgeTx.destChainId,\n bridgeTx.originSender,\n bridgeTx.destRecipient,\n bridgeTx.originToken,\n bridgeTx.destToken,\n bridgeTx.originAmount\n );\n return abi.encodePacked(\n firstPart,\n bridgeTx.destAmount,\n bridgeTx.originFeeAmount,\n // Note: we skip the deprecated `sendChainGas` flag, which was present in BridgeTransaction V1\n bridgeTx.deadline,\n bridgeTx.nonce,\n // New V2 fields: exclusivity\n bridgeTx.exclusivityRelayer,\n bridgeTx.exclusivityEndTime,\n // New V2 fields: Zap\n bridgeTx.zapNative,\n bridgeTx.zapData\n );\n }\n\n /// @notice Decodes the BridgeTransactionV2 struct from the encoded transaction.\n /// @dev Encoded BridgeTransactionV2 struct must be tightly packed.\n /// Use `validateV2` before decoding to ensure the encoded transaction is valid.\n function decodeV2(bytes calldata encodedTx)\n internal\n pure\n returns (IFastBridgeV2.BridgeTransactionV2 memory bridgeTx)\n {\n bridgeTx.originChainId = originChainId(encodedTx);\n bridgeTx.destChainId = destChainId(encodedTx);\n bridgeTx.originSender = originSender(encodedTx);\n bridgeTx.destRecipient = destRecipient(encodedTx);\n bridgeTx.originToken = originToken(encodedTx);\n bridgeTx.destToken = destToken(encodedTx);\n bridgeTx.originAmount = originAmount(encodedTx);\n bridgeTx.destAmount = destAmount(encodedTx);\n bridgeTx.originFeeAmount = originFeeAmount(encodedTx);\n bridgeTx.deadline = deadline(encodedTx);\n bridgeTx.nonce = nonce(encodedTx);\n bridgeTx.exclusivityRelayer = exclusivityRelayer(encodedTx);\n bridgeTx.exclusivityEndTime = exclusivityEndTime(encodedTx);\n bridgeTx.zapNative = zapNative(encodedTx);\n bridgeTx.zapData = zapData(encodedTx);\n }\n\n /// @notice Extracts the version from the encoded transaction.\n function version(bytes calldata encodedTx) internal pure returns (uint16 version_) {\n // Load 32 bytes from the start and shift it 240 bits to the right to get the highest 16 bits.\n assembly {\n version_ := shr(240, calldataload(encodedTx.offset))\n }\n }\n\n /// @notice Extracts the origin chain ID from the encoded transaction.\n function originChainId(bytes calldata encodedTx) internal pure returns (uint32 originChainId_) {\n // Load 32 bytes from the offset and shift it 224 bits to the right to get the highest 32 bits.\n assembly {\n originChainId_ := shr(224, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_CHAIN_ID)))\n }\n }\n\n /// @notice Extracts the destination chain ID from the encoded transaction.\n function destChainId(bytes calldata encodedTx) internal pure returns (uint32 destChainId_) {\n // Load 32 bytes from the offset and shift it 224 bits to the right to get the highest 32 bits.\n assembly {\n destChainId_ := shr(224, calldataload(add(encodedTx.offset, OFFSET_DEST_CHAIN_ID)))\n }\n }\n\n /// @notice Extracts the origin sender from the encoded transaction.\n function originSender(bytes calldata encodedTx) internal pure returns (address originSender_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n originSender_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_SENDER)))\n }\n }\n\n /// @notice Extracts the destination recipient from the encoded transaction.\n function destRecipient(bytes calldata encodedTx) internal pure returns (address destRecipient_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n destRecipient_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_DEST_RECIPIENT)))\n }\n }\n\n /// @notice Extracts the origin token from the encoded transaction.\n function originToken(bytes calldata encodedTx) internal pure returns (address originToken_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n originToken_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_TOKEN)))\n }\n }\n\n /// @notice Extracts the destination token from the encoded transaction.\n function destToken(bytes calldata encodedTx) internal pure returns (address destToken_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n destToken_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_DEST_TOKEN)))\n }\n }\n\n /// @notice Extracts the origin amount from the encoded transaction.\n function originAmount(bytes calldata encodedTx) internal pure returns (uint256 originAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n originAmount_ := calldataload(add(encodedTx.offset, OFFSET_ORIGIN_AMOUNT))\n }\n }\n\n /// @notice Extracts the destination amount from the encoded transaction.\n function destAmount(bytes calldata encodedTx) internal pure returns (uint256 destAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n destAmount_ := calldataload(add(encodedTx.offset, OFFSET_DEST_AMOUNT))\n }\n }\n\n /// @notice Extracts the origin fee amount from the encoded transaction.\n function originFeeAmount(bytes calldata encodedTx) internal pure returns (uint256 originFeeAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n originFeeAmount_ := calldataload(add(encodedTx.offset, OFFSET_ORIGIN_FEE_AMOUNT))\n }\n }\n\n /// @notice Extracts the deadline from the encoded transaction.\n function deadline(bytes calldata encodedTx) internal pure returns (uint256 deadline_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n deadline_ := calldataload(add(encodedTx.offset, OFFSET_DEADLINE))\n }\n }\n\n /// @notice Extracts the nonce from the encoded transaction.\n function nonce(bytes calldata encodedTx) internal pure returns (uint256 nonce_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n nonce_ := calldataload(add(encodedTx.offset, OFFSET_NONCE))\n }\n }\n\n /// @notice Extracts the exclusivity relayer from the encoded transaction.\n function exclusivityRelayer(bytes calldata encodedTx) internal pure returns (address exclusivityRelayer_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n exclusivityRelayer_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_EXCLUSIVITY_RELAYER)))\n }\n }\n\n /// @notice Extracts the exclusivity end time from the encoded transaction.\n function exclusivityEndTime(bytes calldata encodedTx) internal pure returns (uint256 exclusivityEndTime_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n exclusivityEndTime_ := calldataload(add(encodedTx.offset, OFFSET_EXCLUSIVITY_END_TIME))\n }\n }\n\n /// @notice Extracts the Zap's native value from the encoded transaction.\n function zapNative(bytes calldata encodedTx) internal pure returns (uint256 zapNative_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n zapNative_ := calldataload(add(encodedTx.offset, OFFSET_ZAP_NATIVE))\n }\n }\n\n /// @notice Extracts the Zap's data from the encoded transaction.\n function zapData(bytes calldata encodedTx) internal pure returns (bytes calldata zapData_) {\n zapData_ = encodedTx[OFFSET_ZAP_DATA:];\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/AdminV2.sol\n\ncontract AdminV2 is AccessControlEnumerable, IAdminV2, IAdminV2Errors {\n using SafeERC20 for IERC20;\n\n /// @notice Address reserved for native gas token (ETH on Ethereum and most L2s, AVAX on Avalanche, etc)\n address public constant NATIVE_GAS_TOKEN = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Role identifier for Quoter API's off-chain authentication.\n /// @dev Only addresses with this role can post FastBridge quotes to the API.\n bytes32 public constant QUOTER_ROLE = keccak256(\"QUOTER_ROLE\");\n\n /// @notice Role identifier for Prover's on-chain authentication in FastBridge.\n /// @dev Only addresses with this role can provide proofs that a FastBridge request has been relayed.\n bytes32 public constant PROVER_ROLE = keccak256(\"PROVER_ROLE\");\n\n /// @notice Role identifier for Guard's on-chain authentication in FastBridge.\n /// @dev Only addresses with this role can dispute submitted relay proofs during the dispute period.\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n\n /// @notice Role identifier for Canceler's on-chain authentication in FastBridge.\n /// @dev Only addresses with this role can cancel a FastBridge transaction without the cancel delay.\n bytes32 public constant CANCELER_ROLE = keccak256(\"CANCELER_ROLE\");\n\n /// @notice Role identifier for Governor's on-chain administrative authority.\n /// @dev Only addresses with this role can perform administrative tasks within the contract.\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n /// @notice Denominator for fee rates, represents 100%.\n uint256 public constant FEE_BPS = 1e6;\n /// @notice Maximum protocol fee rate: 1% on origin amount.\n uint256 public constant FEE_RATE_MAX = 0.01e6;\n\n /// @notice Minimum cancel delay that can be set by the governor.\n uint256 public constant MIN_CANCEL_DELAY = 1 hours;\n /// @notice Default cancel delay set during the contract deployment.\n uint256 public constant DEFAULT_CANCEL_DELAY = 1 days;\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Delay for a transaction after which it could be permisionlessly cancelled\n uint256 public cancelDelay;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Use ZapNative V2 requests instead.\n uint256 public immutable chainGasAmount = 0;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n _setCancelDelay(DEFAULT_CANCEL_DELAY);\n }\n\n /// @notice Allows the contract governor to set the cancel delay. The cancel delay is the time after the transaction\n /// deadline after which it can be permissionlessly cancelled, if it hasn't been proven by any of the Relayers.\n function setCancelDelay(uint256 newCancelDelay) external onlyRole(GOVERNOR_ROLE) {\n _setCancelDelay(newCancelDelay);\n }\n\n /// @notice Allows the contract governor to set the protocol fee rate. The protocol fee is taken from the origin\n /// amount only for completed and claimed transactions.\n /// @dev The protocol fee is abstracted away from the relayers, they always operate using the amounts after fees:\n /// what they see as the origin amount emitted in the log is what they get credited with.\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n if (newFeeRate \u003e FEE_RATE_MAX) revert FeeRateAboveMax();\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n /// @notice Allows the contract governor to sweep the accumulated protocol fees in the contract.\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n emit FeesSwept(token, recipient, feeAmount);\n /// Sweep the fees as the last transaction action\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(recipient), feeAmount);\n } else {\n IERC20(token).safeTransfer(recipient, feeAmount);\n }\n }\n\n /// @notice Internal function to set the cancel delay. Security checks are performed outside of this function.\n function _setCancelDelay(uint256 newCancelDelay) private {\n if (newCancelDelay \u003c MIN_CANCEL_DELAY) revert CancelDelayBelowMin();\n uint256 oldCancelDelay = cancelDelay;\n cancelDelay = newCancelDelay;\n emit CancelDelayUpdated(oldCancelDelay, newCancelDelay);\n }\n}\n\n// contracts/FastBridgeV2.sol\n\n/// @notice FastBridgeV2 is a contract for bridging tokens across chains.\ncontract FastBridgeV2 is AdminV2, MulticallTarget, IFastBridgeV2, IFastBridgeV2Errors {\n using BridgeTransactionV2Lib for bytes;\n using SafeERC20 for IERC20;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n /// @notice Maximum length of accepted zapData\n uint256 public constant MAX_ZAP_DATA_LENGTH = 2 ** 16 - 1;\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeTxDetails) public bridgeTxDetails;\n /// @notice Relay details on destination chain\n mapping(bytes32 =\u003e BridgeRelay) public bridgeRelayDetails;\n /// @notice Unique bridge nonces tracked per originSender\n mapping(address =\u003e uint256) public senderNonces;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Replaced by senderNonces\n uint256 public immutable nonce = 0;\n /// @notice the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) AdminV2(_owner) {\n deployBlock = block.number;\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n bridge({\n params: params,\n paramsV2: BridgeParamsV2({\n quoteRelayer: address(0),\n quoteExclusivitySeconds: 0,\n quoteId: bytes(\"\"),\n zapNative: 0,\n zapData: bytes(\"\")\n })\n });\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes calldata request) external payable {\n // relay override will validate the request\n relay({request: request, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes calldata request, bytes32 destTxHash) external {\n request.validateV2();\n prove({transactionId: keccak256(request), destTxHash: destTxHash, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridgeV2\n function claim(bytes calldata request) external {\n // claim override will validate the request\n claim({request: request, to: address(0)});\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Aggregate the read operations from the same storage slot\n address disputedRelayer = $.proofRelayer;\n BridgeStatus status = $.status;\n uint56 proofBlockTimestamp = $.proofBlockTimestamp;\n // Can only dispute a RELAYER_PROVED transaction within the dispute period\n if (status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(proofBlockTimestamp) \u003e DISPUTE_PERIOD) {\n revert DisputePeriodPassed();\n }\n // Update status to REQUESTED and delete the disputed proof details\n // Note: these are storage writes\n $.status = BridgeStatus.REQUESTED;\n $.proofRelayer = address(0);\n $.proofBlockTimestamp = 0;\n\n emit BridgeProofDisputed(transactionId, disputedRelayer);\n }\n\n /// Note: this function is deprecated and will be removed in a future version.\n /// @inheritdoc IFastBridge\n function refund(bytes calldata request) external {\n cancel(request);\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // The correct relayer can only claim a RELAYER_PROVED transaction after the dispute period\n if ($.status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if ($.proofRelayer != relayer) revert SenderIncorrect();\n return _timeSince($.proofBlockTimestamp) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n /// @dev This method is added to achieve backwards compatibility with decoding requests into V1 structs:\n /// - `zapNative` is partially reported as a zero/non-zero flag\n /// - `zapData` is ignored\n /// In order to process all kinds of requests use getBridgeTransactionV2 instead.\n function getBridgeTransaction(bytes calldata request) external view returns (BridgeTransaction memory) {\n // Try decoding into V2 struct first. This will revert if V1 struct is passed\n try this.getBridgeTransactionV2(request) returns (BridgeTransactionV2 memory txV2) {\n // Note: we entirely ignore the zapData field, as it was not present in V1\n return BridgeTransaction({\n originChainId: txV2.originChainId,\n destChainId: txV2.destChainId,\n originSender: txV2.originSender,\n destRecipient: txV2.destRecipient,\n originToken: txV2.originToken,\n destToken: txV2.destToken,\n originAmount: txV2.originAmount,\n destAmount: txV2.destAmount,\n originFeeAmount: txV2.originFeeAmount,\n sendChainGas: txV2.zapNative != 0,\n deadline: txV2.deadline,\n nonce: txV2.nonce\n });\n } catch {\n // Fallback to V1 struct\n return abi.decode(request, (BridgeTransaction));\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function getBridgeTransactionV2(bytes calldata request) external pure returns (BridgeTransactionV2 memory) {\n request.validateV2();\n return BridgeTransactionV2Lib.decodeV2(request);\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) public payable {\n int256 exclusivityEndTime = 0;\n // if relayer exclusivity is not intended for this bridge, set exclusivityEndTime to static zero\n // otherwise, set exclusivity to expire at the current block ts offset by quoteExclusivitySeconds\n if (paramsV2.quoteRelayer != address(0)) {\n exclusivityEndTime = int256(block.timestamp) + paramsV2.quoteExclusivitySeconds;\n }\n _validateBridgeParams(params, paramsV2, exclusivityEndTime);\n\n // transfer tokens to bridge contract\n /// @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _takeBridgedUserAsset(params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) {\n originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n }\n\n // set status to requested\n bytes memory request = BridgeTransactionV2Lib.encodeV2(\n BridgeTransactionV2({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n deadline: params.deadline,\n nonce: senderNonces[params.sender]++, // increment nonce on every bridge\n exclusivityRelayer: paramsV2.quoteRelayer,\n // We checked exclusivityEndTime to be in range [0 .. params.deadline] above, so can safely cast\n exclusivityEndTime: uint256(exclusivityEndTime),\n zapNative: paramsV2.zapNative,\n zapData: paramsV2.zapData\n })\n );\n bytes32 transactionId = keccak256(request);\n // Note: the tx status will be updated throughout the tx lifecycle, while destChainId is set once here\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n bridgeTxDetails[transactionId].destChainId = params.dstChainId;\n\n emit BridgeRequested({\n transactionId: transactionId,\n sender: params.sender,\n request: request,\n destChainId: params.dstChainId,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n sendChainGas: paramsV2.zapNative != 0\n });\n emit BridgeQuoteDetails(transactionId, paramsV2.quoteId);\n }\n\n /// @inheritdoc IFastBridgeV2\n function relay(bytes calldata request, address relayer) public payable {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n _validateRelayParams(request, transactionId, relayer);\n // mark bridge transaction as relayed\n bridgeRelayDetails[transactionId] =\n BridgeRelay({blockNumber: uint48(block.number), blockTimestamp: uint48(block.timestamp), relayer: relayer});\n\n // transfer tokens to recipient on destination chain and trigger Zap if requested\n address to = request.destRecipient();\n address token = request.destToken();\n uint256 amount = request.destAmount();\n uint256 zapNative = request.zapNative();\n\n // Emit the event before any external calls\n emit BridgeRelayed({\n transactionId: transactionId,\n relayer: relayer,\n to: to,\n originChainId: request.originChainId(),\n originToken: request.originToken(),\n destToken: token,\n originAmount: request.originAmount(),\n destAmount: amount,\n chainGasAmount: zapNative\n });\n\n // All state changes have been done at this point, can proceed to the external calls.\n // This follows the checks-effects-interactions pattern to mitigate potential reentrancy attacks.\n if (token == NATIVE_GAS_TOKEN) {\n // For the native gas token, additional zapNative is not allowed\n if (zapNative != 0) revert ZapNativeNotSupported();\n // Check that the correct msg.value was sent\n if (msg.value != amount) revert MsgValueIncorrect();\n // Don't do a native transfer yet: we will handle it alongside the Zap below\n } else {\n // For ERC20s, we check that the correct msg.value was sent\n if (msg.value != zapNative) revert MsgValueIncorrect();\n // We need to transfer the tokens from the Relayer to the recipient first before performing an\n // optional post-transfer Zap.\n IERC20(token).safeTransferFrom(msg.sender, to, amount);\n }\n // At this point we have done:\n // - Transferred the requested amount of ERC20 tokens to the recipient.\n // At this point we have confirmed:\n // - For ERC20s: msg.value matches the requested zapNative amount.\n // - For the native gas token: msg.value matches the requested destAmount.\n // Remaining optional things to do:\n // - Forward the full msg.value to the recipient (if non-zero).\n // - Trigger a Zap (if zapData is present).\n bytes calldata zapData = request.zapData();\n if (zapData.length != 0) {\n // Zap Data is present: Zap has been requested by the recipient. Trigger it forwarding the full msg.value.\n\n // Note: if token has a fee on transfers, the recipient will have received less than `amount`.\n // This is a very niche edge case and should be handled by the recipient contract.\n _triggerZapWithChecks({recipient: to, token: token, amount: amount, zapData: zapData});\n } else if (msg.value != 0) {\n // Zap Data is missing, but msg.value was sent. This could happen in two different cases:\n // - Relay with the native gas token is happening.\n // - Relay with ERC20 is happening, with a `zapNative \u003e 0` request.\n // In both cases, we need to transfer the full msg.value to the recipient.\n Address.sendValue(payable(to), msg.value);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) public onlyRole(PROVER_ROLE) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n\n // Can only prove a REQUESTED transaction\n if ($.status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n // Update status to RELAYER_PROVED and store the proof details\n // Note: these are storage writes\n $.status = BridgeStatus.RELAYER_PROVED;\n $.proofBlockTimestamp = uint56(block.timestamp);\n $.proofRelayer = relayer;\n\n emit BridgeProofProvided(transactionId, relayer, destTxHash);\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes calldata request, address to) public {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Aggregate the read operations from the same storage slot\n address proofRelayer = $.proofRelayer;\n BridgeStatus status = $.status;\n uint56 proofBlockTimestamp = $.proofBlockTimestamp;\n\n // Can only claim a RELAYER_PROVED transaction after the dispute period\n if (status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(proofBlockTimestamp) \u003c= DISPUTE_PERIOD) {\n revert DisputePeriodNotPassed();\n }\n\n if (to == address(0)) {\n // Anyone could claim the funds to the proven relayer on their behalf\n to = proofRelayer;\n } else if (proofRelayer != msg.sender) {\n // Only the proven relayer could specify an address to claim the funds to\n revert SenderIncorrect();\n }\n\n // Update status to RELAYER_CLAIMED and transfer the origin collateral to the specified claim address\n // Note: this is a storage write\n $.status = BridgeStatus.RELAYER_CLAIMED;\n\n address token = request.originToken();\n uint256 amount = request.originAmount();\n // Update protocol fees if origin fee amount exists\n uint256 originFeeAmount = request.originFeeAmount();\n if (originFeeAmount \u003e 0) protocolFees[token] += originFeeAmount;\n // Emit the event before any external calls\n emit BridgeDepositClaimed(transactionId, proofRelayer, to, token, amount);\n // Complete the relayer claim as the last transaction action\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(to), amount);\n } else {\n IERC20(token).safeTransfer(to, amount);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function cancel(bytes calldata request) public {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Can only cancel a REQUESTED transaction after its deadline expires\n if ($.status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n uint256 deadline = request.deadline();\n // Permissionless cancel is only allowed after `cancelDelay` on top of the deadline\n if (!hasRole(CANCELER_ROLE, msg.sender)) deadline += cancelDelay;\n if (block.timestamp \u003c= deadline) revert DeadlineNotExceeded();\n // Update status to REFUNDED and return the full amount (collateral + protocol fees) to the original sender.\n // The protocol fees are only updated when the transaction is claimed, so we don't need to update them here.\n // Note: this is a storage write\n $.status = BridgeStatus.REFUNDED;\n\n address to = request.originSender();\n address token = request.originToken();\n uint256 amount = request.originAmount() + request.originFeeAmount();\n // Emit the event before any external calls\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n // Complete the user cancel as the last transaction action\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(to), amount);\n } else {\n IERC20(token).safeTransfer(to, amount);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeStatuses(bytes32 transactionId) public view returns (BridgeStatus status) {\n return bridgeTxDetails[transactionId].status;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeProofs(bytes32 transactionId) public view returns (uint96 timestamp, address relayer) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n\n timestamp = $.proofBlockTimestamp;\n relayer = $.proofRelayer;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeRelays(bytes32 transactionId) public view returns (bool) {\n // has this transactionId been relayed?\n return bridgeRelayDetails[transactionId].relayer != address(0);\n }\n\n /// @notice Takes the bridged asset from the user into FastBridgeV2 custody. It will be later\n /// claimed by the relayer who completed the relay on destination chain, or transferred back to the user\n /// via the cancel function should no one complete the relay.\n function _takeBridgedUserAsset(address token, uint256 amount) internal returns (uint256 amountTaken) {\n if (token == NATIVE_GAS_TOKEN) {\n // For the native gas token, we just need to check that the supplied msg.value is correct.\n // Supplied `msg.value` is already in FastBridgeV2 custody.\n if (amount != msg.value) revert MsgValueIncorrect();\n amountTaken = msg.value;\n } else {\n // For ERC20s, token is explicitly transferred from the user to FastBridgeV2.\n // We don't allow non-zero `msg.value` to avoid extra funds from being stuck in FastBridgeV2.\n if (msg.value != 0) revert MsgValueIncorrect();\n // Throw an explicit error if the provided token address is not a contract\n if (token.code.length == 0) revert TokenNotContract();\n amountTaken = IERC20(token).balanceOf(address(this));\n IERC20(token).safeTransferFrom(msg.sender, address(this), amount);\n // Use the balance difference as the amount taken in case of fee on transfer tokens.\n amountTaken = IERC20(token).balanceOf(address(this)) - amountTaken;\n }\n }\n\n /// @notice Calls the Recipient's hook function with the specified zapData and performs\n /// all the necessary checks for the returned value.\n function _triggerZapWithChecks(address recipient, address token, uint256 amount, bytes calldata zapData) internal {\n // This will bubble any revert messages from the hook function\n bytes memory returnData = Address.functionCallWithValue({\n target: recipient,\n data: abi.encodeCall(IZapRecipient.zap, (token, amount, zapData)),\n // Note: see `relay()` for reasoning behind passing msg.value\n value: msg.value\n });\n // Explicit revert if no return data at all\n if (returnData.length == 0) revert RecipientNoReturnValue();\n // Check that exactly a single return value was returned\n if (returnData.length != 32) revert RecipientIncorrectReturnValue();\n // Return value should be abi-encoded hook function selector\n if (bytes32(returnData) != bytes32(IZapRecipient.zap.selector)) {\n revert RecipientIncorrectReturnValue();\n }\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint56(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint56).max but\n /// proof.timestamp \u003c type(uint56).max via unchecked statement\n /// @param proofBlockTimestamp The bridge proof block timestamp\n /// @return delta Time delta since proof submitted\n function _timeSince(uint56 proofBlockTimestamp) internal view returns (uint256 delta) {\n unchecked {\n delta = uint56(block.timestamp) - proofBlockTimestamp;\n }\n }\n\n /// @notice Performs all the necessary checks for a bridge to happen.\n /// @dev There's no good way to refactor this function to reduce cyclomatic complexity due to\n /// the number of checks that need to be performed, so we skip the code-complexity rule here.\n // solhint-disable-next-line code-complexity\n function _validateBridgeParams(\n BridgeParams memory params,\n BridgeParamsV2 memory paramsV2,\n int256 exclusivityEndTime\n )\n internal\n view\n {\n // Check V1 (legacy) params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.sender == address(0) || params.to == address(0)) revert ZeroAddress();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n // Check V2 params\n if (paramsV2.zapData.length \u003e MAX_ZAP_DATA_LENGTH) revert ZapDataLengthAboveMax();\n if (paramsV2.zapNative != 0 \u0026\u0026 params.destToken == NATIVE_GAS_TOKEN) {\n revert ZapNativeNotSupported();\n }\n // exclusivityEndTime must be in range [0 .. params.deadline]\n if (exclusivityEndTime \u003c 0 || exclusivityEndTime \u003e int256(params.deadline)) {\n revert ExclusivityParamsIncorrect();\n }\n }\n\n /// @notice Performs all the necessary checks for a relay to happen.\n function _validateRelayParams(bytes calldata request, bytes32 transactionId, address relayer) internal view {\n if (relayer == address(0)) revert ZeroAddress();\n // Check if the transaction has already been relayed\n if (bridgeRelays(transactionId)) revert TransactionRelayed();\n if (request.destChainId() != block.chainid) revert ChainIncorrect();\n // Check the deadline for relay to happen\n if (block.timestamp \u003e request.deadline()) revert DeadlineExceeded();\n // Check the exclusivity period, if it is still ongoing\n address exclRelayer = request.exclusivityRelayer();\n if (exclRelayer != address(0) \u0026\u0026 exclRelayer != relayer \u0026\u0026 block.timestamp \u003c= request.exclusivityEndTime()) {\n revert ExclusivityPeriodNotPassed();\n }\n }\n}\n","language":"Solidity","languageVersion":"0.8.24","compilerVersion":"0.8.24","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"","srcMapRuntime":"","abiDefinition":[{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"}],"userDoc":{"kind":"user","methods":{},"version":1},"developerDoc":{"details":"Interface of the ERC165 standard, as defined in the https://eips.ethereum.org/EIPS/eip-165[EIP]. Implementers can declare support of contract interfaces, which can then be queried by others ({ERC165Checker}). For an implementation, see {ERC165}.","kind":"dev","methods":{"supportsInterface(bytes4)":{"details":"Returns true if this contract implements the interface defined by `interfaceId`. See the corresponding https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section] to learn more about how these ids are created. This function call must use less than 30 000 gas."}},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"bytes4\",\"name\":\"interfaceId\",\"type\":\"bytes4\"}],\"name\":\"supportsInterface\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"}],\"devdoc\":{\"details\":\"Interface of the ERC165 standard, as defined in the https://eips.ethereum.org/EIPS/eip-165[EIP]. Implementers can declare support of contract interfaces, which can then be queried by others ({ERC165Checker}). For an implementation, see {ERC165}.\",\"kind\":\"dev\",\"methods\":{\"supportsInterface(bytes4)\":{\"details\":\"Returns true if this contract implements the interface defined by `interfaceId`. See the corresponding https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section] to learn more about how these ids are created. This function call must use less than 30 000 gas.\"}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeV2.sol\":\"IERC165\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeV2.sol\":{\"keccak256\":\"0xac79c463688a682ca706a4ef95e7817b83548cdfa8182ba0426ac7e5e07613d8\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://b3ecb7097381287cafc3a73f3a2bb03565115ebb682a85064e0b0dc2f7e2919d\",\"dweb:/ipfs/QmatruW3nYZTksf3CeQ8wwiAG4c7xoEJBEp6drHPtFLBRK\"]}},\"version\":1}"},"hashes":{"supportsInterface(bytes4)":"01ffc9a7"}},"solidity/FastBridgeV2.sol:IERC20":{"code":"0x","runtime-code":"0x","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.24 ^0.8.20 ^0.8.4;\n\n// contracts/interfaces/IAdminV2.sol\n\ninterface IAdminV2 {\n event CancelDelayUpdated(uint256 oldCancelDelay, uint256 newCancelDelay);\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n function setCancelDelay(uint256 newCancelDelay) external;\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n}\n\n// contracts/interfaces/IAdminV2Errors.sol\n\ninterface IAdminV2Errors {\n error CancelDelayBelowMin();\n error FeeRateAboveMax();\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IFastBridgeV2Errors.sol\n\ninterface IFastBridgeV2Errors {\n error AmountIncorrect();\n error ChainIncorrect();\n error ExclusivityParamsIncorrect();\n error MsgValueIncorrect();\n error SenderIncorrect();\n error StatusIncorrect();\n error TokenNotContract();\n error ZapDataLengthAboveMax();\n error ZapNativeNotSupported();\n error ZeroAddress();\n\n error RecipientIncorrectReturnValue();\n error RecipientNoReturnValue();\n\n error DeadlineExceeded();\n error DeadlineNotExceeded();\n error DeadlineTooShort();\n error DisputePeriodNotPassed();\n error DisputePeriodPassed();\n error ExclusivityPeriodNotPassed();\n\n error TransactionRelayed();\n}\n\n// contracts/interfaces/IMulticallTarget.sol\n\n/// @notice Interface for a contract that can be called multiple times by the same caller. Inspired by MulticallV3:\n/// https://github.com/mds1/multicall/blob/master/src/Multicall3.sol\ninterface IMulticallTarget {\n struct Result {\n bool success;\n bytes returnData;\n }\n\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external;\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results);\n}\n\n// contracts/interfaces/IZapRecipient.sol\n\ninterface IZapRecipient {\n function zap(address token, uint256 amount, bytes memory zapData) external payable returns (bytes4);\n}\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// contracts/interfaces/IFastBridgeV2.sol\n\ninterface IFastBridgeV2 is IFastBridge {\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n struct BridgeTxDetails {\n BridgeStatus status;\n uint32 destChainId;\n uint56 proofBlockTimestamp;\n address proofRelayer;\n }\n\n struct BridgeRelay {\n uint48 blockNumber;\n uint48 blockTimestamp;\n address relayer;\n }\n\n /// @notice New params introduced in the FastBridgeV2.\n /// We are passing fields from the older BridgeParams struct outside of this struct\n /// for backwards compatibility.\n /// Note: quoteRelayer and quoteExclusivitySeconds are either both zero (indicating no exclusivity)\n /// or both non-zero (indicating exclusivity for the given period).\n /// Note: zapNative \u003e 0 can NOT be used with destToken = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE (native token)\n /// @param quoteRelayer Relayer that provided the quote for the transaction\n /// @param quoteExclusivitySeconds Period of time the quote relayer is guaranteed exclusivity after user's deposit\n /// @param quoteId Unique quote identifier used for tracking the quote\n /// @param zapNative ETH value to send to the recipient (if any)\n /// @param zapData Parameters for the Zap to the destination recipient (if any)\n struct BridgeParamsV2 {\n address quoteRelayer;\n int256 quoteExclusivitySeconds;\n bytes quoteId;\n uint256 zapNative;\n bytes zapData;\n }\n\n /// @notice Updated bridge transaction struct to include parameters introduced in FastBridgeV2.\n /// Note: only `exclusivityRelayer` can fill such a transaction until `exclusivityEndTime`.\n struct BridgeTransactionV2 {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n // Note: sendChainGas flag from V1 is deprecated\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n address exclusivityRelayer;\n uint256 exclusivityEndTime;\n uint256 zapNative; // ETH value to send to the recipient (if any)\n bytes zapData; // data to pass for the Zap action (if any)\n }\n\n event BridgeQuoteDetails(bytes32 indexed transactionId, bytes quoteId);\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability\n /// to provide temporary exclusivity fill rights for the quote relayer.\n /// @param params The parameters required to bridge\n /// @param paramsV2 The parameters for exclusivity fill rights (optional, can be left empty)\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function relay(bytes memory request, address relayer) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param transactionId The transaction id associated with the encoded bridge transaction to prove\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital.\n /// @notice Can only send funds to the relayer address on the proof.\n /// @param request The encoded bridge transaction to claim on origin chain\n function claim(bytes memory request) external;\n\n /// @notice Cancels an outstanding bridge transaction in case optimistic bridging failed and returns the full amount\n /// to the original sender.\n /// @param request The encoded bridge transaction to refund\n function cancel(bytes memory request) external;\n\n /// @notice Checks if a transaction has been relayed\n /// @param transactionId The ID of the transaction to check\n /// @return True if the transaction has been relayed, false otherwise\n function bridgeRelays(bytes32 transactionId) external view returns (bool);\n\n /// @notice Returns the status of a bridge transaction\n /// @param transactionId The ID of the bridge transaction\n /// @return BridgeStatus Status of the bridge transaction\n function bridgeStatuses(bytes32 transactionId) external view returns (BridgeStatus);\n\n /// @notice Returns the timestamp and relayer of a bridge proof\n /// @param transactionId The ID of the bridge transaction\n /// @return timestamp The timestamp of the bridge proof\n /// @return relayer The relayer address of the bridge proof\n function bridgeProofs(bytes32 transactionId) external view returns (uint96 timestamp, address relayer);\n\n /// @notice Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\n /// @param request The bridge request to decode\n function getBridgeTransactionV2(bytes memory request) external view returns (BridgeTransactionV2 memory);\n}\n\n// contracts/utils/MulticallTarget.sol\n\n// solhint-disable avoid-low-level-calls\n/// @notice Template for a contract that supports batched calls (preserving the msg.sender).\n/// Only calls with zero msg.value could be batched.\nabstract contract MulticallTarget is IMulticallTarget {\n error MulticallTarget__UndeterminedRevert();\n\n /// @notice Perform a batched call to this contract, preserving the msg.sender.\n /// The return data from each call is discarded.\n /// @dev The method is non-payable, so only calls with `msg.value == 0` could be batched.\n /// It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag.\n /// Otherwise, the whole batch call will be reverted with the original revert reason.\n /// @param data List of abi-encoded calldata for the calls to perform.\n /// @param ignoreReverts Whether to ignore the revert errors from the calls.\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external {\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\n if (!success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(result);\n }\n }\n }\n\n /// @notice Perform a batched call to this contract, preserving the msg.sender.\n /// The return data from each call is preserved.\n /// @dev The method is non-payable, so only calls with `msg.value == 0` could be batched.\n /// It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag.\n /// Otherwise, the whole batch call will be reverted with the original revert reason.\n /// @param data List of abi-encoded calldata for the calls to perform.\n /// @param ignoreReverts Whether to ignore the revert errors from the calls.\n /// @return results List of results from the calls: `(success, returnData)`.\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results)\n {\n results = new Result[](data.length);\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (results[i].success, results[i].returnData) = address(this).delegatecall(data[i]);\n if (!results[i].success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(results[i].returnData);\n }\n }\n }\n\n /// @dev Bubbles the revert message from the underlying call.\n /// Note: preserves the same custom error or revert string, if one was used.\n /// Source: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v5.0.2/contracts/utils/Address.sol#L143-L158\n function _bubbleRevert(bytes memory returnData) internal pure {\n // Look for revert reason and bubble it up if present\n if (returnData.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n // solhint-disable-next-line no-inline-assembly\n assembly {\n let returndata_size := mload(returnData)\n revert(add(32, returnData), returndata_size)\n }\n } else {\n revert MulticallTarget__UndeterminedRevert();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// contracts/libs/BridgeTransactionV2.sol\n\n// solhint-disable no-inline-assembly\nlibrary BridgeTransactionV2Lib {\n uint16 internal constant VERSION = 2;\n\n // Offsets of the fields in the packed BridgeTransactionV2 struct\n // uint16 version [000 .. 002)\n // uint32 originChainId [002 .. 006)\n // uint32 destChainId [006 .. 010)\n // address originSender [010 .. 030)\n // address destRecipient [030 .. 050)\n // address originToken [050 .. 070)\n // address destToken [070 .. 090)\n // uint256 originAmount [090 .. 122)\n // uint256 destAmount [122 .. 154)\n // uint256 originFeeAmount [154 .. 186)\n // uint256 deadline [186 .. 218)\n // uint256 nonce [218 .. 250)\n // address exclusivityRelayer [250 .. 270)\n // uint256 exclusivityEndTime [270 .. 302)\n // uint256 zapNative [302 .. 334)\n // bytes zapData [334 .. ***)\n\n // forgefmt: disable-start\n uint256 private constant OFFSET_ORIGIN_CHAIN_ID = 2;\n uint256 private constant OFFSET_DEST_CHAIN_ID = 6;\n uint256 private constant OFFSET_ORIGIN_SENDER = 10;\n uint256 private constant OFFSET_DEST_RECIPIENT = 30;\n uint256 private constant OFFSET_ORIGIN_TOKEN = 50;\n uint256 private constant OFFSET_DEST_TOKEN = 70;\n uint256 private constant OFFSET_ORIGIN_AMOUNT = 90;\n uint256 private constant OFFSET_DEST_AMOUNT = 122;\n uint256 private constant OFFSET_ORIGIN_FEE_AMOUNT = 154;\n uint256 private constant OFFSET_DEADLINE = 186;\n uint256 private constant OFFSET_NONCE = 218;\n uint256 private constant OFFSET_EXCLUSIVITY_RELAYER = 250;\n uint256 private constant OFFSET_EXCLUSIVITY_END_TIME = 270;\n uint256 private constant OFFSET_ZAP_NATIVE = 302;\n uint256 private constant OFFSET_ZAP_DATA = 334;\n // forgefmt: disable-end\n\n error BridgeTransactionV2__InvalidEncodedTx();\n error BridgeTransactionV2__UnsupportedVersion(uint16 version);\n\n /// @notice Validates the encoded transaction to be a tightly packed encoded payload for BridgeTransactionV2.\n /// @dev Checks the minimum length and the version, use this function before decoding any of the fields.\n function validateV2(bytes calldata encodedTx) internal pure {\n // Check the minimum length: must at least include all static fields.\n if (encodedTx.length \u003c OFFSET_ZAP_DATA) revert BridgeTransactionV2__InvalidEncodedTx();\n // Once we validated the length, we can be sure that the version field is present.\n uint16 version_ = version(encodedTx);\n if (version_ != VERSION) revert BridgeTransactionV2__UnsupportedVersion(version_);\n }\n\n /// @notice Encodes the BridgeTransactionV2 struct by tightly packing the fields.\n /// @dev `abi.decode` will not work as a result of the tightly packed fields. Use `decodeV2` to decode instead.\n function encodeV2(IFastBridgeV2.BridgeTransactionV2 memory bridgeTx) internal pure returns (bytes memory) {\n // We split the encoding into two parts to avoid stack-too-deep error\n bytes memory firstPart = abi.encodePacked(\n VERSION,\n bridgeTx.originChainId,\n bridgeTx.destChainId,\n bridgeTx.originSender,\n bridgeTx.destRecipient,\n bridgeTx.originToken,\n bridgeTx.destToken,\n bridgeTx.originAmount\n );\n return abi.encodePacked(\n firstPart,\n bridgeTx.destAmount,\n bridgeTx.originFeeAmount,\n // Note: we skip the deprecated `sendChainGas` flag, which was present in BridgeTransaction V1\n bridgeTx.deadline,\n bridgeTx.nonce,\n // New V2 fields: exclusivity\n bridgeTx.exclusivityRelayer,\n bridgeTx.exclusivityEndTime,\n // New V2 fields: Zap\n bridgeTx.zapNative,\n bridgeTx.zapData\n );\n }\n\n /// @notice Decodes the BridgeTransactionV2 struct from the encoded transaction.\n /// @dev Encoded BridgeTransactionV2 struct must be tightly packed.\n /// Use `validateV2` before decoding to ensure the encoded transaction is valid.\n function decodeV2(bytes calldata encodedTx)\n internal\n pure\n returns (IFastBridgeV2.BridgeTransactionV2 memory bridgeTx)\n {\n bridgeTx.originChainId = originChainId(encodedTx);\n bridgeTx.destChainId = destChainId(encodedTx);\n bridgeTx.originSender = originSender(encodedTx);\n bridgeTx.destRecipient = destRecipient(encodedTx);\n bridgeTx.originToken = originToken(encodedTx);\n bridgeTx.destToken = destToken(encodedTx);\n bridgeTx.originAmount = originAmount(encodedTx);\n bridgeTx.destAmount = destAmount(encodedTx);\n bridgeTx.originFeeAmount = originFeeAmount(encodedTx);\n bridgeTx.deadline = deadline(encodedTx);\n bridgeTx.nonce = nonce(encodedTx);\n bridgeTx.exclusivityRelayer = exclusivityRelayer(encodedTx);\n bridgeTx.exclusivityEndTime = exclusivityEndTime(encodedTx);\n bridgeTx.zapNative = zapNative(encodedTx);\n bridgeTx.zapData = zapData(encodedTx);\n }\n\n /// @notice Extracts the version from the encoded transaction.\n function version(bytes calldata encodedTx) internal pure returns (uint16 version_) {\n // Load 32 bytes from the start and shift it 240 bits to the right to get the highest 16 bits.\n assembly {\n version_ := shr(240, calldataload(encodedTx.offset))\n }\n }\n\n /// @notice Extracts the origin chain ID from the encoded transaction.\n function originChainId(bytes calldata encodedTx) internal pure returns (uint32 originChainId_) {\n // Load 32 bytes from the offset and shift it 224 bits to the right to get the highest 32 bits.\n assembly {\n originChainId_ := shr(224, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_CHAIN_ID)))\n }\n }\n\n /// @notice Extracts the destination chain ID from the encoded transaction.\n function destChainId(bytes calldata encodedTx) internal pure returns (uint32 destChainId_) {\n // Load 32 bytes from the offset and shift it 224 bits to the right to get the highest 32 bits.\n assembly {\n destChainId_ := shr(224, calldataload(add(encodedTx.offset, OFFSET_DEST_CHAIN_ID)))\n }\n }\n\n /// @notice Extracts the origin sender from the encoded transaction.\n function originSender(bytes calldata encodedTx) internal pure returns (address originSender_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n originSender_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_SENDER)))\n }\n }\n\n /// @notice Extracts the destination recipient from the encoded transaction.\n function destRecipient(bytes calldata encodedTx) internal pure returns (address destRecipient_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n destRecipient_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_DEST_RECIPIENT)))\n }\n }\n\n /// @notice Extracts the origin token from the encoded transaction.\n function originToken(bytes calldata encodedTx) internal pure returns (address originToken_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n originToken_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_TOKEN)))\n }\n }\n\n /// @notice Extracts the destination token from the encoded transaction.\n function destToken(bytes calldata encodedTx) internal pure returns (address destToken_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n destToken_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_DEST_TOKEN)))\n }\n }\n\n /// @notice Extracts the origin amount from the encoded transaction.\n function originAmount(bytes calldata encodedTx) internal pure returns (uint256 originAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n originAmount_ := calldataload(add(encodedTx.offset, OFFSET_ORIGIN_AMOUNT))\n }\n }\n\n /// @notice Extracts the destination amount from the encoded transaction.\n function destAmount(bytes calldata encodedTx) internal pure returns (uint256 destAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n destAmount_ := calldataload(add(encodedTx.offset, OFFSET_DEST_AMOUNT))\n }\n }\n\n /// @notice Extracts the origin fee amount from the encoded transaction.\n function originFeeAmount(bytes calldata encodedTx) internal pure returns (uint256 originFeeAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n originFeeAmount_ := calldataload(add(encodedTx.offset, OFFSET_ORIGIN_FEE_AMOUNT))\n }\n }\n\n /// @notice Extracts the deadline from the encoded transaction.\n function deadline(bytes calldata encodedTx) internal pure returns (uint256 deadline_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n deadline_ := calldataload(add(encodedTx.offset, OFFSET_DEADLINE))\n }\n }\n\n /// @notice Extracts the nonce from the encoded transaction.\n function nonce(bytes calldata encodedTx) internal pure returns (uint256 nonce_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n nonce_ := calldataload(add(encodedTx.offset, OFFSET_NONCE))\n }\n }\n\n /// @notice Extracts the exclusivity relayer from the encoded transaction.\n function exclusivityRelayer(bytes calldata encodedTx) internal pure returns (address exclusivityRelayer_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n exclusivityRelayer_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_EXCLUSIVITY_RELAYER)))\n }\n }\n\n /// @notice Extracts the exclusivity end time from the encoded transaction.\n function exclusivityEndTime(bytes calldata encodedTx) internal pure returns (uint256 exclusivityEndTime_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n exclusivityEndTime_ := calldataload(add(encodedTx.offset, OFFSET_EXCLUSIVITY_END_TIME))\n }\n }\n\n /// @notice Extracts the Zap's native value from the encoded transaction.\n function zapNative(bytes calldata encodedTx) internal pure returns (uint256 zapNative_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n zapNative_ := calldataload(add(encodedTx.offset, OFFSET_ZAP_NATIVE))\n }\n }\n\n /// @notice Extracts the Zap's data from the encoded transaction.\n function zapData(bytes calldata encodedTx) internal pure returns (bytes calldata zapData_) {\n zapData_ = encodedTx[OFFSET_ZAP_DATA:];\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/AdminV2.sol\n\ncontract AdminV2 is AccessControlEnumerable, IAdminV2, IAdminV2Errors {\n using SafeERC20 for IERC20;\n\n /// @notice Address reserved for native gas token (ETH on Ethereum and most L2s, AVAX on Avalanche, etc)\n address public constant NATIVE_GAS_TOKEN = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Role identifier for Quoter API's off-chain authentication.\n /// @dev Only addresses with this role can post FastBridge quotes to the API.\n bytes32 public constant QUOTER_ROLE = keccak256(\"QUOTER_ROLE\");\n\n /// @notice Role identifier for Prover's on-chain authentication in FastBridge.\n /// @dev Only addresses with this role can provide proofs that a FastBridge request has been relayed.\n bytes32 public constant PROVER_ROLE = keccak256(\"PROVER_ROLE\");\n\n /// @notice Role identifier for Guard's on-chain authentication in FastBridge.\n /// @dev Only addresses with this role can dispute submitted relay proofs during the dispute period.\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n\n /// @notice Role identifier for Canceler's on-chain authentication in FastBridge.\n /// @dev Only addresses with this role can cancel a FastBridge transaction without the cancel delay.\n bytes32 public constant CANCELER_ROLE = keccak256(\"CANCELER_ROLE\");\n\n /// @notice Role identifier for Governor's on-chain administrative authority.\n /// @dev Only addresses with this role can perform administrative tasks within the contract.\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n /// @notice Denominator for fee rates, represents 100%.\n uint256 public constant FEE_BPS = 1e6;\n /// @notice Maximum protocol fee rate: 1% on origin amount.\n uint256 public constant FEE_RATE_MAX = 0.01e6;\n\n /// @notice Minimum cancel delay that can be set by the governor.\n uint256 public constant MIN_CANCEL_DELAY = 1 hours;\n /// @notice Default cancel delay set during the contract deployment.\n uint256 public constant DEFAULT_CANCEL_DELAY = 1 days;\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Delay for a transaction after which it could be permisionlessly cancelled\n uint256 public cancelDelay;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Use ZapNative V2 requests instead.\n uint256 public immutable chainGasAmount = 0;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n _setCancelDelay(DEFAULT_CANCEL_DELAY);\n }\n\n /// @notice Allows the contract governor to set the cancel delay. The cancel delay is the time after the transaction\n /// deadline after which it can be permissionlessly cancelled, if it hasn't been proven by any of the Relayers.\n function setCancelDelay(uint256 newCancelDelay) external onlyRole(GOVERNOR_ROLE) {\n _setCancelDelay(newCancelDelay);\n }\n\n /// @notice Allows the contract governor to set the protocol fee rate. The protocol fee is taken from the origin\n /// amount only for completed and claimed transactions.\n /// @dev The protocol fee is abstracted away from the relayers, they always operate using the amounts after fees:\n /// what they see as the origin amount emitted in the log is what they get credited with.\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n if (newFeeRate \u003e FEE_RATE_MAX) revert FeeRateAboveMax();\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n /// @notice Allows the contract governor to sweep the accumulated protocol fees in the contract.\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n emit FeesSwept(token, recipient, feeAmount);\n /// Sweep the fees as the last transaction action\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(recipient), feeAmount);\n } else {\n IERC20(token).safeTransfer(recipient, feeAmount);\n }\n }\n\n /// @notice Internal function to set the cancel delay. Security checks are performed outside of this function.\n function _setCancelDelay(uint256 newCancelDelay) private {\n if (newCancelDelay \u003c MIN_CANCEL_DELAY) revert CancelDelayBelowMin();\n uint256 oldCancelDelay = cancelDelay;\n cancelDelay = newCancelDelay;\n emit CancelDelayUpdated(oldCancelDelay, newCancelDelay);\n }\n}\n\n// contracts/FastBridgeV2.sol\n\n/// @notice FastBridgeV2 is a contract for bridging tokens across chains.\ncontract FastBridgeV2 is AdminV2, MulticallTarget, IFastBridgeV2, IFastBridgeV2Errors {\n using BridgeTransactionV2Lib for bytes;\n using SafeERC20 for IERC20;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n /// @notice Maximum length of accepted zapData\n uint256 public constant MAX_ZAP_DATA_LENGTH = 2 ** 16 - 1;\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeTxDetails) public bridgeTxDetails;\n /// @notice Relay details on destination chain\n mapping(bytes32 =\u003e BridgeRelay) public bridgeRelayDetails;\n /// @notice Unique bridge nonces tracked per originSender\n mapping(address =\u003e uint256) public senderNonces;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Replaced by senderNonces\n uint256 public immutable nonce = 0;\n /// @notice the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) AdminV2(_owner) {\n deployBlock = block.number;\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n bridge({\n params: params,\n paramsV2: BridgeParamsV2({\n quoteRelayer: address(0),\n quoteExclusivitySeconds: 0,\n quoteId: bytes(\"\"),\n zapNative: 0,\n zapData: bytes(\"\")\n })\n });\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes calldata request) external payable {\n // relay override will validate the request\n relay({request: request, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes calldata request, bytes32 destTxHash) external {\n request.validateV2();\n prove({transactionId: keccak256(request), destTxHash: destTxHash, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridgeV2\n function claim(bytes calldata request) external {\n // claim override will validate the request\n claim({request: request, to: address(0)});\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Aggregate the read operations from the same storage slot\n address disputedRelayer = $.proofRelayer;\n BridgeStatus status = $.status;\n uint56 proofBlockTimestamp = $.proofBlockTimestamp;\n // Can only dispute a RELAYER_PROVED transaction within the dispute period\n if (status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(proofBlockTimestamp) \u003e DISPUTE_PERIOD) {\n revert DisputePeriodPassed();\n }\n // Update status to REQUESTED and delete the disputed proof details\n // Note: these are storage writes\n $.status = BridgeStatus.REQUESTED;\n $.proofRelayer = address(0);\n $.proofBlockTimestamp = 0;\n\n emit BridgeProofDisputed(transactionId, disputedRelayer);\n }\n\n /// Note: this function is deprecated and will be removed in a future version.\n /// @inheritdoc IFastBridge\n function refund(bytes calldata request) external {\n cancel(request);\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // The correct relayer can only claim a RELAYER_PROVED transaction after the dispute period\n if ($.status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if ($.proofRelayer != relayer) revert SenderIncorrect();\n return _timeSince($.proofBlockTimestamp) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n /// @dev This method is added to achieve backwards compatibility with decoding requests into V1 structs:\n /// - `zapNative` is partially reported as a zero/non-zero flag\n /// - `zapData` is ignored\n /// In order to process all kinds of requests use getBridgeTransactionV2 instead.\n function getBridgeTransaction(bytes calldata request) external view returns (BridgeTransaction memory) {\n // Try decoding into V2 struct first. This will revert if V1 struct is passed\n try this.getBridgeTransactionV2(request) returns (BridgeTransactionV2 memory txV2) {\n // Note: we entirely ignore the zapData field, as it was not present in V1\n return BridgeTransaction({\n originChainId: txV2.originChainId,\n destChainId: txV2.destChainId,\n originSender: txV2.originSender,\n destRecipient: txV2.destRecipient,\n originToken: txV2.originToken,\n destToken: txV2.destToken,\n originAmount: txV2.originAmount,\n destAmount: txV2.destAmount,\n originFeeAmount: txV2.originFeeAmount,\n sendChainGas: txV2.zapNative != 0,\n deadline: txV2.deadline,\n nonce: txV2.nonce\n });\n } catch {\n // Fallback to V1 struct\n return abi.decode(request, (BridgeTransaction));\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function getBridgeTransactionV2(bytes calldata request) external pure returns (BridgeTransactionV2 memory) {\n request.validateV2();\n return BridgeTransactionV2Lib.decodeV2(request);\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) public payable {\n int256 exclusivityEndTime = 0;\n // if relayer exclusivity is not intended for this bridge, set exclusivityEndTime to static zero\n // otherwise, set exclusivity to expire at the current block ts offset by quoteExclusivitySeconds\n if (paramsV2.quoteRelayer != address(0)) {\n exclusivityEndTime = int256(block.timestamp) + paramsV2.quoteExclusivitySeconds;\n }\n _validateBridgeParams(params, paramsV2, exclusivityEndTime);\n\n // transfer tokens to bridge contract\n /// @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _takeBridgedUserAsset(params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) {\n originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n }\n\n // set status to requested\n bytes memory request = BridgeTransactionV2Lib.encodeV2(\n BridgeTransactionV2({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n deadline: params.deadline,\n nonce: senderNonces[params.sender]++, // increment nonce on every bridge\n exclusivityRelayer: paramsV2.quoteRelayer,\n // We checked exclusivityEndTime to be in range [0 .. params.deadline] above, so can safely cast\n exclusivityEndTime: uint256(exclusivityEndTime),\n zapNative: paramsV2.zapNative,\n zapData: paramsV2.zapData\n })\n );\n bytes32 transactionId = keccak256(request);\n // Note: the tx status will be updated throughout the tx lifecycle, while destChainId is set once here\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n bridgeTxDetails[transactionId].destChainId = params.dstChainId;\n\n emit BridgeRequested({\n transactionId: transactionId,\n sender: params.sender,\n request: request,\n destChainId: params.dstChainId,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n sendChainGas: paramsV2.zapNative != 0\n });\n emit BridgeQuoteDetails(transactionId, paramsV2.quoteId);\n }\n\n /// @inheritdoc IFastBridgeV2\n function relay(bytes calldata request, address relayer) public payable {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n _validateRelayParams(request, transactionId, relayer);\n // mark bridge transaction as relayed\n bridgeRelayDetails[transactionId] =\n BridgeRelay({blockNumber: uint48(block.number), blockTimestamp: uint48(block.timestamp), relayer: relayer});\n\n // transfer tokens to recipient on destination chain and trigger Zap if requested\n address to = request.destRecipient();\n address token = request.destToken();\n uint256 amount = request.destAmount();\n uint256 zapNative = request.zapNative();\n\n // Emit the event before any external calls\n emit BridgeRelayed({\n transactionId: transactionId,\n relayer: relayer,\n to: to,\n originChainId: request.originChainId(),\n originToken: request.originToken(),\n destToken: token,\n originAmount: request.originAmount(),\n destAmount: amount,\n chainGasAmount: zapNative\n });\n\n // All state changes have been done at this point, can proceed to the external calls.\n // This follows the checks-effects-interactions pattern to mitigate potential reentrancy attacks.\n if (token == NATIVE_GAS_TOKEN) {\n // For the native gas token, additional zapNative is not allowed\n if (zapNative != 0) revert ZapNativeNotSupported();\n // Check that the correct msg.value was sent\n if (msg.value != amount) revert MsgValueIncorrect();\n // Don't do a native transfer yet: we will handle it alongside the Zap below\n } else {\n // For ERC20s, we check that the correct msg.value was sent\n if (msg.value != zapNative) revert MsgValueIncorrect();\n // We need to transfer the tokens from the Relayer to the recipient first before performing an\n // optional post-transfer Zap.\n IERC20(token).safeTransferFrom(msg.sender, to, amount);\n }\n // At this point we have done:\n // - Transferred the requested amount of ERC20 tokens to the recipient.\n // At this point we have confirmed:\n // - For ERC20s: msg.value matches the requested zapNative amount.\n // - For the native gas token: msg.value matches the requested destAmount.\n // Remaining optional things to do:\n // - Forward the full msg.value to the recipient (if non-zero).\n // - Trigger a Zap (if zapData is present).\n bytes calldata zapData = request.zapData();\n if (zapData.length != 0) {\n // Zap Data is present: Zap has been requested by the recipient. Trigger it forwarding the full msg.value.\n\n // Note: if token has a fee on transfers, the recipient will have received less than `amount`.\n // This is a very niche edge case and should be handled by the recipient contract.\n _triggerZapWithChecks({recipient: to, token: token, amount: amount, zapData: zapData});\n } else if (msg.value != 0) {\n // Zap Data is missing, but msg.value was sent. This could happen in two different cases:\n // - Relay with the native gas token is happening.\n // - Relay with ERC20 is happening, with a `zapNative \u003e 0` request.\n // In both cases, we need to transfer the full msg.value to the recipient.\n Address.sendValue(payable(to), msg.value);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) public onlyRole(PROVER_ROLE) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n\n // Can only prove a REQUESTED transaction\n if ($.status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n // Update status to RELAYER_PROVED and store the proof details\n // Note: these are storage writes\n $.status = BridgeStatus.RELAYER_PROVED;\n $.proofBlockTimestamp = uint56(block.timestamp);\n $.proofRelayer = relayer;\n\n emit BridgeProofProvided(transactionId, relayer, destTxHash);\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes calldata request, address to) public {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Aggregate the read operations from the same storage slot\n address proofRelayer = $.proofRelayer;\n BridgeStatus status = $.status;\n uint56 proofBlockTimestamp = $.proofBlockTimestamp;\n\n // Can only claim a RELAYER_PROVED transaction after the dispute period\n if (status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(proofBlockTimestamp) \u003c= DISPUTE_PERIOD) {\n revert DisputePeriodNotPassed();\n }\n\n if (to == address(0)) {\n // Anyone could claim the funds to the proven relayer on their behalf\n to = proofRelayer;\n } else if (proofRelayer != msg.sender) {\n // Only the proven relayer could specify an address to claim the funds to\n revert SenderIncorrect();\n }\n\n // Update status to RELAYER_CLAIMED and transfer the origin collateral to the specified claim address\n // Note: this is a storage write\n $.status = BridgeStatus.RELAYER_CLAIMED;\n\n address token = request.originToken();\n uint256 amount = request.originAmount();\n // Update protocol fees if origin fee amount exists\n uint256 originFeeAmount = request.originFeeAmount();\n if (originFeeAmount \u003e 0) protocolFees[token] += originFeeAmount;\n // Emit the event before any external calls\n emit BridgeDepositClaimed(transactionId, proofRelayer, to, token, amount);\n // Complete the relayer claim as the last transaction action\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(to), amount);\n } else {\n IERC20(token).safeTransfer(to, amount);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function cancel(bytes calldata request) public {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Can only cancel a REQUESTED transaction after its deadline expires\n if ($.status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n uint256 deadline = request.deadline();\n // Permissionless cancel is only allowed after `cancelDelay` on top of the deadline\n if (!hasRole(CANCELER_ROLE, msg.sender)) deadline += cancelDelay;\n if (block.timestamp \u003c= deadline) revert DeadlineNotExceeded();\n // Update status to REFUNDED and return the full amount (collateral + protocol fees) to the original sender.\n // The protocol fees are only updated when the transaction is claimed, so we don't need to update them here.\n // Note: this is a storage write\n $.status = BridgeStatus.REFUNDED;\n\n address to = request.originSender();\n address token = request.originToken();\n uint256 amount = request.originAmount() + request.originFeeAmount();\n // Emit the event before any external calls\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n // Complete the user cancel as the last transaction action\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(to), amount);\n } else {\n IERC20(token).safeTransfer(to, amount);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeStatuses(bytes32 transactionId) public view returns (BridgeStatus status) {\n return bridgeTxDetails[transactionId].status;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeProofs(bytes32 transactionId) public view returns (uint96 timestamp, address relayer) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n\n timestamp = $.proofBlockTimestamp;\n relayer = $.proofRelayer;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeRelays(bytes32 transactionId) public view returns (bool) {\n // has this transactionId been relayed?\n return bridgeRelayDetails[transactionId].relayer != address(0);\n }\n\n /// @notice Takes the bridged asset from the user into FastBridgeV2 custody. It will be later\n /// claimed by the relayer who completed the relay on destination chain, or transferred back to the user\n /// via the cancel function should no one complete the relay.\n function _takeBridgedUserAsset(address token, uint256 amount) internal returns (uint256 amountTaken) {\n if (token == NATIVE_GAS_TOKEN) {\n // For the native gas token, we just need to check that the supplied msg.value is correct.\n // Supplied `msg.value` is already in FastBridgeV2 custody.\n if (amount != msg.value) revert MsgValueIncorrect();\n amountTaken = msg.value;\n } else {\n // For ERC20s, token is explicitly transferred from the user to FastBridgeV2.\n // We don't allow non-zero `msg.value` to avoid extra funds from being stuck in FastBridgeV2.\n if (msg.value != 0) revert MsgValueIncorrect();\n // Throw an explicit error if the provided token address is not a contract\n if (token.code.length == 0) revert TokenNotContract();\n amountTaken = IERC20(token).balanceOf(address(this));\n IERC20(token).safeTransferFrom(msg.sender, address(this), amount);\n // Use the balance difference as the amount taken in case of fee on transfer tokens.\n amountTaken = IERC20(token).balanceOf(address(this)) - amountTaken;\n }\n }\n\n /// @notice Calls the Recipient's hook function with the specified zapData and performs\n /// all the necessary checks for the returned value.\n function _triggerZapWithChecks(address recipient, address token, uint256 amount, bytes calldata zapData) internal {\n // This will bubble any revert messages from the hook function\n bytes memory returnData = Address.functionCallWithValue({\n target: recipient,\n data: abi.encodeCall(IZapRecipient.zap, (token, amount, zapData)),\n // Note: see `relay()` for reasoning behind passing msg.value\n value: msg.value\n });\n // Explicit revert if no return data at all\n if (returnData.length == 0) revert RecipientNoReturnValue();\n // Check that exactly a single return value was returned\n if (returnData.length != 32) revert RecipientIncorrectReturnValue();\n // Return value should be abi-encoded hook function selector\n if (bytes32(returnData) != bytes32(IZapRecipient.zap.selector)) {\n revert RecipientIncorrectReturnValue();\n }\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint56(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint56).max but\n /// proof.timestamp \u003c type(uint56).max via unchecked statement\n /// @param proofBlockTimestamp The bridge proof block timestamp\n /// @return delta Time delta since proof submitted\n function _timeSince(uint56 proofBlockTimestamp) internal view returns (uint256 delta) {\n unchecked {\n delta = uint56(block.timestamp) - proofBlockTimestamp;\n }\n }\n\n /// @notice Performs all the necessary checks for a bridge to happen.\n /// @dev There's no good way to refactor this function to reduce cyclomatic complexity due to\n /// the number of checks that need to be performed, so we skip the code-complexity rule here.\n // solhint-disable-next-line code-complexity\n function _validateBridgeParams(\n BridgeParams memory params,\n BridgeParamsV2 memory paramsV2,\n int256 exclusivityEndTime\n )\n internal\n view\n {\n // Check V1 (legacy) params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.sender == address(0) || params.to == address(0)) revert ZeroAddress();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n // Check V2 params\n if (paramsV2.zapData.length \u003e MAX_ZAP_DATA_LENGTH) revert ZapDataLengthAboveMax();\n if (paramsV2.zapNative != 0 \u0026\u0026 params.destToken == NATIVE_GAS_TOKEN) {\n revert ZapNativeNotSupported();\n }\n // exclusivityEndTime must be in range [0 .. params.deadline]\n if (exclusivityEndTime \u003c 0 || exclusivityEndTime \u003e int256(params.deadline)) {\n revert ExclusivityParamsIncorrect();\n }\n }\n\n /// @notice Performs all the necessary checks for a relay to happen.\n function _validateRelayParams(bytes calldata request, bytes32 transactionId, address relayer) internal view {\n if (relayer == address(0)) revert ZeroAddress();\n // Check if the transaction has already been relayed\n if (bridgeRelays(transactionId)) revert TransactionRelayed();\n if (request.destChainId() != block.chainid) revert ChainIncorrect();\n // Check the deadline for relay to happen\n if (block.timestamp \u003e request.deadline()) revert DeadlineExceeded();\n // Check the exclusivity period, if it is still ongoing\n address exclRelayer = request.exclusivityRelayer();\n if (exclRelayer != address(0) \u0026\u0026 exclRelayer != relayer \u0026\u0026 block.timestamp \u003c= request.exclusivityEndTime()) {\n revert ExclusivityPeriodNotPassed();\n }\n }\n}\n","language":"Solidity","languageVersion":"0.8.24","compilerVersion":"0.8.24","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"","srcMapRuntime":"","abiDefinition":[{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Transfer","type":"event"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"}],"userDoc":{"kind":"user","methods":{},"version":1},"developerDoc":{"details":"Interface of the ERC20 standard as defined in the EIP.","events":{"Approval(address,address,uint256)":{"details":"Emitted when the allowance of a `spender` for an `owner` is set by a call to {approve}. `value` is the new allowance."},"Transfer(address,address,uint256)":{"details":"Emitted when `value` tokens are moved from one account (`from`) to another (`to`). Note that `value` may be zero."}},"kind":"dev","methods":{"allowance(address,address)":{"details":"Returns the remaining number of tokens that `spender` will be allowed to spend on behalf of `owner` through {transferFrom}. This is zero by default. This value changes when {approve} or {transferFrom} are called."},"approve(address,uint256)":{"details":"Sets a `value` amount of tokens as the allowance of `spender` over the caller's tokens. Returns a boolean value indicating whether the operation succeeded. IMPORTANT: Beware that changing an allowance with this method brings the risk that someone may use both the old and the new allowance by unfortunate transaction ordering. One possible solution to mitigate this race condition is to first reduce the spender's allowance to 0 and set the desired value afterwards: https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 Emits an {Approval} event."},"balanceOf(address)":{"details":"Returns the value of tokens owned by `account`."},"totalSupply()":{"details":"Returns the value of tokens in existence."},"transfer(address,uint256)":{"details":"Moves a `value` amount of tokens from the caller's account to `to`. Returns a boolean value indicating whether the operation succeeded. Emits a {Transfer} event."},"transferFrom(address,address,uint256)":{"details":"Moves a `value` amount of tokens from `from` to `to` using the allowance mechanism. `value` is then deducted from the caller's allowance. Returns a boolean value indicating whether the operation succeeded. Emits a {Transfer} event."}},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"Approval\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"Transfer\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"}],\"name\":\"allowance\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"approve\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"balanceOf\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"totalSupply\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"transfer\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"transferFrom\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"details\":\"Interface of the ERC20 standard as defined in the EIP.\",\"events\":{\"Approval(address,address,uint256)\":{\"details\":\"Emitted when the allowance of a `spender` for an `owner` is set by a call to {approve}. `value` is the new allowance.\"},\"Transfer(address,address,uint256)\":{\"details\":\"Emitted when `value` tokens are moved from one account (`from`) to another (`to`). Note that `value` may be zero.\"}},\"kind\":\"dev\",\"methods\":{\"allowance(address,address)\":{\"details\":\"Returns the remaining number of tokens that `spender` will be allowed to spend on behalf of `owner` through {transferFrom}. This is zero by default. This value changes when {approve} or {transferFrom} are called.\"},\"approve(address,uint256)\":{\"details\":\"Sets a `value` amount of tokens as the allowance of `spender` over the caller's tokens. Returns a boolean value indicating whether the operation succeeded. IMPORTANT: Beware that changing an allowance with this method brings the risk that someone may use both the old and the new allowance by unfortunate transaction ordering. One possible solution to mitigate this race condition is to first reduce the spender's allowance to 0 and set the desired value afterwards: https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 Emits an {Approval} event.\"},\"balanceOf(address)\":{\"details\":\"Returns the value of tokens owned by `account`.\"},\"totalSupply()\":{\"details\":\"Returns the value of tokens in existence.\"},\"transfer(address,uint256)\":{\"details\":\"Moves a `value` amount of tokens from the caller's account to `to`. Returns a boolean value indicating whether the operation succeeded. Emits a {Transfer} event.\"},\"transferFrom(address,address,uint256)\":{\"details\":\"Moves a `value` amount of tokens from `from` to `to` using the allowance mechanism. `value` is then deducted from the caller's allowance. Returns a boolean value indicating whether the operation succeeded. Emits a {Transfer} event.\"}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeV2.sol\":\"IERC20\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeV2.sol\":{\"keccak256\":\"0xac79c463688a682ca706a4ef95e7817b83548cdfa8182ba0426ac7e5e07613d8\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://b3ecb7097381287cafc3a73f3a2bb03565115ebb682a85064e0b0dc2f7e2919d\",\"dweb:/ipfs/QmatruW3nYZTksf3CeQ8wwiAG4c7xoEJBEp6drHPtFLBRK\"]}},\"version\":1}"},"hashes":{"allowance(address,address)":"dd62ed3e","approve(address,uint256)":"095ea7b3","balanceOf(address)":"70a08231","totalSupply()":"18160ddd","transfer(address,uint256)":"a9059cbb","transferFrom(address,address,uint256)":"23b872dd"}},"solidity/FastBridgeV2.sol:IERC20Permit":{"code":"0x","runtime-code":"0x","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.24 ^0.8.20 ^0.8.4;\n\n// contracts/interfaces/IAdminV2.sol\n\ninterface IAdminV2 {\n event CancelDelayUpdated(uint256 oldCancelDelay, uint256 newCancelDelay);\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n function setCancelDelay(uint256 newCancelDelay) external;\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n}\n\n// contracts/interfaces/IAdminV2Errors.sol\n\ninterface IAdminV2Errors {\n error CancelDelayBelowMin();\n error FeeRateAboveMax();\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IFastBridgeV2Errors.sol\n\ninterface IFastBridgeV2Errors {\n error AmountIncorrect();\n error ChainIncorrect();\n error ExclusivityParamsIncorrect();\n error MsgValueIncorrect();\n error SenderIncorrect();\n error StatusIncorrect();\n error TokenNotContract();\n error ZapDataLengthAboveMax();\n error ZapNativeNotSupported();\n error ZeroAddress();\n\n error RecipientIncorrectReturnValue();\n error RecipientNoReturnValue();\n\n error DeadlineExceeded();\n error DeadlineNotExceeded();\n error DeadlineTooShort();\n error DisputePeriodNotPassed();\n error DisputePeriodPassed();\n error ExclusivityPeriodNotPassed();\n\n error TransactionRelayed();\n}\n\n// contracts/interfaces/IMulticallTarget.sol\n\n/// @notice Interface for a contract that can be called multiple times by the same caller. Inspired by MulticallV3:\n/// https://github.com/mds1/multicall/blob/master/src/Multicall3.sol\ninterface IMulticallTarget {\n struct Result {\n bool success;\n bytes returnData;\n }\n\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external;\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results);\n}\n\n// contracts/interfaces/IZapRecipient.sol\n\ninterface IZapRecipient {\n function zap(address token, uint256 amount, bytes memory zapData) external payable returns (bytes4);\n}\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// contracts/interfaces/IFastBridgeV2.sol\n\ninterface IFastBridgeV2 is IFastBridge {\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n struct BridgeTxDetails {\n BridgeStatus status;\n uint32 destChainId;\n uint56 proofBlockTimestamp;\n address proofRelayer;\n }\n\n struct BridgeRelay {\n uint48 blockNumber;\n uint48 blockTimestamp;\n address relayer;\n }\n\n /// @notice New params introduced in the FastBridgeV2.\n /// We are passing fields from the older BridgeParams struct outside of this struct\n /// for backwards compatibility.\n /// Note: quoteRelayer and quoteExclusivitySeconds are either both zero (indicating no exclusivity)\n /// or both non-zero (indicating exclusivity for the given period).\n /// Note: zapNative \u003e 0 can NOT be used with destToken = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE (native token)\n /// @param quoteRelayer Relayer that provided the quote for the transaction\n /// @param quoteExclusivitySeconds Period of time the quote relayer is guaranteed exclusivity after user's deposit\n /// @param quoteId Unique quote identifier used for tracking the quote\n /// @param zapNative ETH value to send to the recipient (if any)\n /// @param zapData Parameters for the Zap to the destination recipient (if any)\n struct BridgeParamsV2 {\n address quoteRelayer;\n int256 quoteExclusivitySeconds;\n bytes quoteId;\n uint256 zapNative;\n bytes zapData;\n }\n\n /// @notice Updated bridge transaction struct to include parameters introduced in FastBridgeV2.\n /// Note: only `exclusivityRelayer` can fill such a transaction until `exclusivityEndTime`.\n struct BridgeTransactionV2 {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n // Note: sendChainGas flag from V1 is deprecated\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n address exclusivityRelayer;\n uint256 exclusivityEndTime;\n uint256 zapNative; // ETH value to send to the recipient (if any)\n bytes zapData; // data to pass for the Zap action (if any)\n }\n\n event BridgeQuoteDetails(bytes32 indexed transactionId, bytes quoteId);\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability\n /// to provide temporary exclusivity fill rights for the quote relayer.\n /// @param params The parameters required to bridge\n /// @param paramsV2 The parameters for exclusivity fill rights (optional, can be left empty)\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function relay(bytes memory request, address relayer) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param transactionId The transaction id associated with the encoded bridge transaction to prove\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital.\n /// @notice Can only send funds to the relayer address on the proof.\n /// @param request The encoded bridge transaction to claim on origin chain\n function claim(bytes memory request) external;\n\n /// @notice Cancels an outstanding bridge transaction in case optimistic bridging failed and returns the full amount\n /// to the original sender.\n /// @param request The encoded bridge transaction to refund\n function cancel(bytes memory request) external;\n\n /// @notice Checks if a transaction has been relayed\n /// @param transactionId The ID of the transaction to check\n /// @return True if the transaction has been relayed, false otherwise\n function bridgeRelays(bytes32 transactionId) external view returns (bool);\n\n /// @notice Returns the status of a bridge transaction\n /// @param transactionId The ID of the bridge transaction\n /// @return BridgeStatus Status of the bridge transaction\n function bridgeStatuses(bytes32 transactionId) external view returns (BridgeStatus);\n\n /// @notice Returns the timestamp and relayer of a bridge proof\n /// @param transactionId The ID of the bridge transaction\n /// @return timestamp The timestamp of the bridge proof\n /// @return relayer The relayer address of the bridge proof\n function bridgeProofs(bytes32 transactionId) external view returns (uint96 timestamp, address relayer);\n\n /// @notice Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\n /// @param request The bridge request to decode\n function getBridgeTransactionV2(bytes memory request) external view returns (BridgeTransactionV2 memory);\n}\n\n// contracts/utils/MulticallTarget.sol\n\n// solhint-disable avoid-low-level-calls\n/// @notice Template for a contract that supports batched calls (preserving the msg.sender).\n/// Only calls with zero msg.value could be batched.\nabstract contract MulticallTarget is IMulticallTarget {\n error MulticallTarget__UndeterminedRevert();\n\n /// @notice Perform a batched call to this contract, preserving the msg.sender.\n /// The return data from each call is discarded.\n /// @dev The method is non-payable, so only calls with `msg.value == 0` could be batched.\n /// It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag.\n /// Otherwise, the whole batch call will be reverted with the original revert reason.\n /// @param data List of abi-encoded calldata for the calls to perform.\n /// @param ignoreReverts Whether to ignore the revert errors from the calls.\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external {\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\n if (!success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(result);\n }\n }\n }\n\n /// @notice Perform a batched call to this contract, preserving the msg.sender.\n /// The return data from each call is preserved.\n /// @dev The method is non-payable, so only calls with `msg.value == 0` could be batched.\n /// It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag.\n /// Otherwise, the whole batch call will be reverted with the original revert reason.\n /// @param data List of abi-encoded calldata for the calls to perform.\n /// @param ignoreReverts Whether to ignore the revert errors from the calls.\n /// @return results List of results from the calls: `(success, returnData)`.\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results)\n {\n results = new Result[](data.length);\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (results[i].success, results[i].returnData) = address(this).delegatecall(data[i]);\n if (!results[i].success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(results[i].returnData);\n }\n }\n }\n\n /// @dev Bubbles the revert message from the underlying call.\n /// Note: preserves the same custom error or revert string, if one was used.\n /// Source: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v5.0.2/contracts/utils/Address.sol#L143-L158\n function _bubbleRevert(bytes memory returnData) internal pure {\n // Look for revert reason and bubble it up if present\n if (returnData.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n // solhint-disable-next-line no-inline-assembly\n assembly {\n let returndata_size := mload(returnData)\n revert(add(32, returnData), returndata_size)\n }\n } else {\n revert MulticallTarget__UndeterminedRevert();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// contracts/libs/BridgeTransactionV2.sol\n\n// solhint-disable no-inline-assembly\nlibrary BridgeTransactionV2Lib {\n uint16 internal constant VERSION = 2;\n\n // Offsets of the fields in the packed BridgeTransactionV2 struct\n // uint16 version [000 .. 002)\n // uint32 originChainId [002 .. 006)\n // uint32 destChainId [006 .. 010)\n // address originSender [010 .. 030)\n // address destRecipient [030 .. 050)\n // address originToken [050 .. 070)\n // address destToken [070 .. 090)\n // uint256 originAmount [090 .. 122)\n // uint256 destAmount [122 .. 154)\n // uint256 originFeeAmount [154 .. 186)\n // uint256 deadline [186 .. 218)\n // uint256 nonce [218 .. 250)\n // address exclusivityRelayer [250 .. 270)\n // uint256 exclusivityEndTime [270 .. 302)\n // uint256 zapNative [302 .. 334)\n // bytes zapData [334 .. ***)\n\n // forgefmt: disable-start\n uint256 private constant OFFSET_ORIGIN_CHAIN_ID = 2;\n uint256 private constant OFFSET_DEST_CHAIN_ID = 6;\n uint256 private constant OFFSET_ORIGIN_SENDER = 10;\n uint256 private constant OFFSET_DEST_RECIPIENT = 30;\n uint256 private constant OFFSET_ORIGIN_TOKEN = 50;\n uint256 private constant OFFSET_DEST_TOKEN = 70;\n uint256 private constant OFFSET_ORIGIN_AMOUNT = 90;\n uint256 private constant OFFSET_DEST_AMOUNT = 122;\n uint256 private constant OFFSET_ORIGIN_FEE_AMOUNT = 154;\n uint256 private constant OFFSET_DEADLINE = 186;\n uint256 private constant OFFSET_NONCE = 218;\n uint256 private constant OFFSET_EXCLUSIVITY_RELAYER = 250;\n uint256 private constant OFFSET_EXCLUSIVITY_END_TIME = 270;\n uint256 private constant OFFSET_ZAP_NATIVE = 302;\n uint256 private constant OFFSET_ZAP_DATA = 334;\n // forgefmt: disable-end\n\n error BridgeTransactionV2__InvalidEncodedTx();\n error BridgeTransactionV2__UnsupportedVersion(uint16 version);\n\n /// @notice Validates the encoded transaction to be a tightly packed encoded payload for BridgeTransactionV2.\n /// @dev Checks the minimum length and the version, use this function before decoding any of the fields.\n function validateV2(bytes calldata encodedTx) internal pure {\n // Check the minimum length: must at least include all static fields.\n if (encodedTx.length \u003c OFFSET_ZAP_DATA) revert BridgeTransactionV2__InvalidEncodedTx();\n // Once we validated the length, we can be sure that the version field is present.\n uint16 version_ = version(encodedTx);\n if (version_ != VERSION) revert BridgeTransactionV2__UnsupportedVersion(version_);\n }\n\n /// @notice Encodes the BridgeTransactionV2 struct by tightly packing the fields.\n /// @dev `abi.decode` will not work as a result of the tightly packed fields. Use `decodeV2` to decode instead.\n function encodeV2(IFastBridgeV2.BridgeTransactionV2 memory bridgeTx) internal pure returns (bytes memory) {\n // We split the encoding into two parts to avoid stack-too-deep error\n bytes memory firstPart = abi.encodePacked(\n VERSION,\n bridgeTx.originChainId,\n bridgeTx.destChainId,\n bridgeTx.originSender,\n bridgeTx.destRecipient,\n bridgeTx.originToken,\n bridgeTx.destToken,\n bridgeTx.originAmount\n );\n return abi.encodePacked(\n firstPart,\n bridgeTx.destAmount,\n bridgeTx.originFeeAmount,\n // Note: we skip the deprecated `sendChainGas` flag, which was present in BridgeTransaction V1\n bridgeTx.deadline,\n bridgeTx.nonce,\n // New V2 fields: exclusivity\n bridgeTx.exclusivityRelayer,\n bridgeTx.exclusivityEndTime,\n // New V2 fields: Zap\n bridgeTx.zapNative,\n bridgeTx.zapData\n );\n }\n\n /// @notice Decodes the BridgeTransactionV2 struct from the encoded transaction.\n /// @dev Encoded BridgeTransactionV2 struct must be tightly packed.\n /// Use `validateV2` before decoding to ensure the encoded transaction is valid.\n function decodeV2(bytes calldata encodedTx)\n internal\n pure\n returns (IFastBridgeV2.BridgeTransactionV2 memory bridgeTx)\n {\n bridgeTx.originChainId = originChainId(encodedTx);\n bridgeTx.destChainId = destChainId(encodedTx);\n bridgeTx.originSender = originSender(encodedTx);\n bridgeTx.destRecipient = destRecipient(encodedTx);\n bridgeTx.originToken = originToken(encodedTx);\n bridgeTx.destToken = destToken(encodedTx);\n bridgeTx.originAmount = originAmount(encodedTx);\n bridgeTx.destAmount = destAmount(encodedTx);\n bridgeTx.originFeeAmount = originFeeAmount(encodedTx);\n bridgeTx.deadline = deadline(encodedTx);\n bridgeTx.nonce = nonce(encodedTx);\n bridgeTx.exclusivityRelayer = exclusivityRelayer(encodedTx);\n bridgeTx.exclusivityEndTime = exclusivityEndTime(encodedTx);\n bridgeTx.zapNative = zapNative(encodedTx);\n bridgeTx.zapData = zapData(encodedTx);\n }\n\n /// @notice Extracts the version from the encoded transaction.\n function version(bytes calldata encodedTx) internal pure returns (uint16 version_) {\n // Load 32 bytes from the start and shift it 240 bits to the right to get the highest 16 bits.\n assembly {\n version_ := shr(240, calldataload(encodedTx.offset))\n }\n }\n\n /// @notice Extracts the origin chain ID from the encoded transaction.\n function originChainId(bytes calldata encodedTx) internal pure returns (uint32 originChainId_) {\n // Load 32 bytes from the offset and shift it 224 bits to the right to get the highest 32 bits.\n assembly {\n originChainId_ := shr(224, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_CHAIN_ID)))\n }\n }\n\n /// @notice Extracts the destination chain ID from the encoded transaction.\n function destChainId(bytes calldata encodedTx) internal pure returns (uint32 destChainId_) {\n // Load 32 bytes from the offset and shift it 224 bits to the right to get the highest 32 bits.\n assembly {\n destChainId_ := shr(224, calldataload(add(encodedTx.offset, OFFSET_DEST_CHAIN_ID)))\n }\n }\n\n /// @notice Extracts the origin sender from the encoded transaction.\n function originSender(bytes calldata encodedTx) internal pure returns (address originSender_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n originSender_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_SENDER)))\n }\n }\n\n /// @notice Extracts the destination recipient from the encoded transaction.\n function destRecipient(bytes calldata encodedTx) internal pure returns (address destRecipient_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n destRecipient_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_DEST_RECIPIENT)))\n }\n }\n\n /// @notice Extracts the origin token from the encoded transaction.\n function originToken(bytes calldata encodedTx) internal pure returns (address originToken_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n originToken_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_TOKEN)))\n }\n }\n\n /// @notice Extracts the destination token from the encoded transaction.\n function destToken(bytes calldata encodedTx) internal pure returns (address destToken_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n destToken_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_DEST_TOKEN)))\n }\n }\n\n /// @notice Extracts the origin amount from the encoded transaction.\n function originAmount(bytes calldata encodedTx) internal pure returns (uint256 originAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n originAmount_ := calldataload(add(encodedTx.offset, OFFSET_ORIGIN_AMOUNT))\n }\n }\n\n /// @notice Extracts the destination amount from the encoded transaction.\n function destAmount(bytes calldata encodedTx) internal pure returns (uint256 destAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n destAmount_ := calldataload(add(encodedTx.offset, OFFSET_DEST_AMOUNT))\n }\n }\n\n /// @notice Extracts the origin fee amount from the encoded transaction.\n function originFeeAmount(bytes calldata encodedTx) internal pure returns (uint256 originFeeAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n originFeeAmount_ := calldataload(add(encodedTx.offset, OFFSET_ORIGIN_FEE_AMOUNT))\n }\n }\n\n /// @notice Extracts the deadline from the encoded transaction.\n function deadline(bytes calldata encodedTx) internal pure returns (uint256 deadline_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n deadline_ := calldataload(add(encodedTx.offset, OFFSET_DEADLINE))\n }\n }\n\n /// @notice Extracts the nonce from the encoded transaction.\n function nonce(bytes calldata encodedTx) internal pure returns (uint256 nonce_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n nonce_ := calldataload(add(encodedTx.offset, OFFSET_NONCE))\n }\n }\n\n /// @notice Extracts the exclusivity relayer from the encoded transaction.\n function exclusivityRelayer(bytes calldata encodedTx) internal pure returns (address exclusivityRelayer_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n exclusivityRelayer_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_EXCLUSIVITY_RELAYER)))\n }\n }\n\n /// @notice Extracts the exclusivity end time from the encoded transaction.\n function exclusivityEndTime(bytes calldata encodedTx) internal pure returns (uint256 exclusivityEndTime_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n exclusivityEndTime_ := calldataload(add(encodedTx.offset, OFFSET_EXCLUSIVITY_END_TIME))\n }\n }\n\n /// @notice Extracts the Zap's native value from the encoded transaction.\n function zapNative(bytes calldata encodedTx) internal pure returns (uint256 zapNative_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n zapNative_ := calldataload(add(encodedTx.offset, OFFSET_ZAP_NATIVE))\n }\n }\n\n /// @notice Extracts the Zap's data from the encoded transaction.\n function zapData(bytes calldata encodedTx) internal pure returns (bytes calldata zapData_) {\n zapData_ = encodedTx[OFFSET_ZAP_DATA:];\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/AdminV2.sol\n\ncontract AdminV2 is AccessControlEnumerable, IAdminV2, IAdminV2Errors {\n using SafeERC20 for IERC20;\n\n /// @notice Address reserved for native gas token (ETH on Ethereum and most L2s, AVAX on Avalanche, etc)\n address public constant NATIVE_GAS_TOKEN = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Role identifier for Quoter API's off-chain authentication.\n /// @dev Only addresses with this role can post FastBridge quotes to the API.\n bytes32 public constant QUOTER_ROLE = keccak256(\"QUOTER_ROLE\");\n\n /// @notice Role identifier for Prover's on-chain authentication in FastBridge.\n /// @dev Only addresses with this role can provide proofs that a FastBridge request has been relayed.\n bytes32 public constant PROVER_ROLE = keccak256(\"PROVER_ROLE\");\n\n /// @notice Role identifier for Guard's on-chain authentication in FastBridge.\n /// @dev Only addresses with this role can dispute submitted relay proofs during the dispute period.\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n\n /// @notice Role identifier for Canceler's on-chain authentication in FastBridge.\n /// @dev Only addresses with this role can cancel a FastBridge transaction without the cancel delay.\n bytes32 public constant CANCELER_ROLE = keccak256(\"CANCELER_ROLE\");\n\n /// @notice Role identifier for Governor's on-chain administrative authority.\n /// @dev Only addresses with this role can perform administrative tasks within the contract.\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n /// @notice Denominator for fee rates, represents 100%.\n uint256 public constant FEE_BPS = 1e6;\n /// @notice Maximum protocol fee rate: 1% on origin amount.\n uint256 public constant FEE_RATE_MAX = 0.01e6;\n\n /// @notice Minimum cancel delay that can be set by the governor.\n uint256 public constant MIN_CANCEL_DELAY = 1 hours;\n /// @notice Default cancel delay set during the contract deployment.\n uint256 public constant DEFAULT_CANCEL_DELAY = 1 days;\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Delay for a transaction after which it could be permisionlessly cancelled\n uint256 public cancelDelay;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Use ZapNative V2 requests instead.\n uint256 public immutable chainGasAmount = 0;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n _setCancelDelay(DEFAULT_CANCEL_DELAY);\n }\n\n /// @notice Allows the contract governor to set the cancel delay. The cancel delay is the time after the transaction\n /// deadline after which it can be permissionlessly cancelled, if it hasn't been proven by any of the Relayers.\n function setCancelDelay(uint256 newCancelDelay) external onlyRole(GOVERNOR_ROLE) {\n _setCancelDelay(newCancelDelay);\n }\n\n /// @notice Allows the contract governor to set the protocol fee rate. The protocol fee is taken from the origin\n /// amount only for completed and claimed transactions.\n /// @dev The protocol fee is abstracted away from the relayers, they always operate using the amounts after fees:\n /// what they see as the origin amount emitted in the log is what they get credited with.\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n if (newFeeRate \u003e FEE_RATE_MAX) revert FeeRateAboveMax();\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n /// @notice Allows the contract governor to sweep the accumulated protocol fees in the contract.\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n emit FeesSwept(token, recipient, feeAmount);\n /// Sweep the fees as the last transaction action\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(recipient), feeAmount);\n } else {\n IERC20(token).safeTransfer(recipient, feeAmount);\n }\n }\n\n /// @notice Internal function to set the cancel delay. Security checks are performed outside of this function.\n function _setCancelDelay(uint256 newCancelDelay) private {\n if (newCancelDelay \u003c MIN_CANCEL_DELAY) revert CancelDelayBelowMin();\n uint256 oldCancelDelay = cancelDelay;\n cancelDelay = newCancelDelay;\n emit CancelDelayUpdated(oldCancelDelay, newCancelDelay);\n }\n}\n\n// contracts/FastBridgeV2.sol\n\n/// @notice FastBridgeV2 is a contract for bridging tokens across chains.\ncontract FastBridgeV2 is AdminV2, MulticallTarget, IFastBridgeV2, IFastBridgeV2Errors {\n using BridgeTransactionV2Lib for bytes;\n using SafeERC20 for IERC20;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n /// @notice Maximum length of accepted zapData\n uint256 public constant MAX_ZAP_DATA_LENGTH = 2 ** 16 - 1;\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeTxDetails) public bridgeTxDetails;\n /// @notice Relay details on destination chain\n mapping(bytes32 =\u003e BridgeRelay) public bridgeRelayDetails;\n /// @notice Unique bridge nonces tracked per originSender\n mapping(address =\u003e uint256) public senderNonces;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Replaced by senderNonces\n uint256 public immutable nonce = 0;\n /// @notice the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) AdminV2(_owner) {\n deployBlock = block.number;\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n bridge({\n params: params,\n paramsV2: BridgeParamsV2({\n quoteRelayer: address(0),\n quoteExclusivitySeconds: 0,\n quoteId: bytes(\"\"),\n zapNative: 0,\n zapData: bytes(\"\")\n })\n });\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes calldata request) external payable {\n // relay override will validate the request\n relay({request: request, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes calldata request, bytes32 destTxHash) external {\n request.validateV2();\n prove({transactionId: keccak256(request), destTxHash: destTxHash, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridgeV2\n function claim(bytes calldata request) external {\n // claim override will validate the request\n claim({request: request, to: address(0)});\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Aggregate the read operations from the same storage slot\n address disputedRelayer = $.proofRelayer;\n BridgeStatus status = $.status;\n uint56 proofBlockTimestamp = $.proofBlockTimestamp;\n // Can only dispute a RELAYER_PROVED transaction within the dispute period\n if (status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(proofBlockTimestamp) \u003e DISPUTE_PERIOD) {\n revert DisputePeriodPassed();\n }\n // Update status to REQUESTED and delete the disputed proof details\n // Note: these are storage writes\n $.status = BridgeStatus.REQUESTED;\n $.proofRelayer = address(0);\n $.proofBlockTimestamp = 0;\n\n emit BridgeProofDisputed(transactionId, disputedRelayer);\n }\n\n /// Note: this function is deprecated and will be removed in a future version.\n /// @inheritdoc IFastBridge\n function refund(bytes calldata request) external {\n cancel(request);\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // The correct relayer can only claim a RELAYER_PROVED transaction after the dispute period\n if ($.status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if ($.proofRelayer != relayer) revert SenderIncorrect();\n return _timeSince($.proofBlockTimestamp) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n /// @dev This method is added to achieve backwards compatibility with decoding requests into V1 structs:\n /// - `zapNative` is partially reported as a zero/non-zero flag\n /// - `zapData` is ignored\n /// In order to process all kinds of requests use getBridgeTransactionV2 instead.\n function getBridgeTransaction(bytes calldata request) external view returns (BridgeTransaction memory) {\n // Try decoding into V2 struct first. This will revert if V1 struct is passed\n try this.getBridgeTransactionV2(request) returns (BridgeTransactionV2 memory txV2) {\n // Note: we entirely ignore the zapData field, as it was not present in V1\n return BridgeTransaction({\n originChainId: txV2.originChainId,\n destChainId: txV2.destChainId,\n originSender: txV2.originSender,\n destRecipient: txV2.destRecipient,\n originToken: txV2.originToken,\n destToken: txV2.destToken,\n originAmount: txV2.originAmount,\n destAmount: txV2.destAmount,\n originFeeAmount: txV2.originFeeAmount,\n sendChainGas: txV2.zapNative != 0,\n deadline: txV2.deadline,\n nonce: txV2.nonce\n });\n } catch {\n // Fallback to V1 struct\n return abi.decode(request, (BridgeTransaction));\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function getBridgeTransactionV2(bytes calldata request) external pure returns (BridgeTransactionV2 memory) {\n request.validateV2();\n return BridgeTransactionV2Lib.decodeV2(request);\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) public payable {\n int256 exclusivityEndTime = 0;\n // if relayer exclusivity is not intended for this bridge, set exclusivityEndTime to static zero\n // otherwise, set exclusivity to expire at the current block ts offset by quoteExclusivitySeconds\n if (paramsV2.quoteRelayer != address(0)) {\n exclusivityEndTime = int256(block.timestamp) + paramsV2.quoteExclusivitySeconds;\n }\n _validateBridgeParams(params, paramsV2, exclusivityEndTime);\n\n // transfer tokens to bridge contract\n /// @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _takeBridgedUserAsset(params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) {\n originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n }\n\n // set status to requested\n bytes memory request = BridgeTransactionV2Lib.encodeV2(\n BridgeTransactionV2({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n deadline: params.deadline,\n nonce: senderNonces[params.sender]++, // increment nonce on every bridge\n exclusivityRelayer: paramsV2.quoteRelayer,\n // We checked exclusivityEndTime to be in range [0 .. params.deadline] above, so can safely cast\n exclusivityEndTime: uint256(exclusivityEndTime),\n zapNative: paramsV2.zapNative,\n zapData: paramsV2.zapData\n })\n );\n bytes32 transactionId = keccak256(request);\n // Note: the tx status will be updated throughout the tx lifecycle, while destChainId is set once here\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n bridgeTxDetails[transactionId].destChainId = params.dstChainId;\n\n emit BridgeRequested({\n transactionId: transactionId,\n sender: params.sender,\n request: request,\n destChainId: params.dstChainId,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n sendChainGas: paramsV2.zapNative != 0\n });\n emit BridgeQuoteDetails(transactionId, paramsV2.quoteId);\n }\n\n /// @inheritdoc IFastBridgeV2\n function relay(bytes calldata request, address relayer) public payable {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n _validateRelayParams(request, transactionId, relayer);\n // mark bridge transaction as relayed\n bridgeRelayDetails[transactionId] =\n BridgeRelay({blockNumber: uint48(block.number), blockTimestamp: uint48(block.timestamp), relayer: relayer});\n\n // transfer tokens to recipient on destination chain and trigger Zap if requested\n address to = request.destRecipient();\n address token = request.destToken();\n uint256 amount = request.destAmount();\n uint256 zapNative = request.zapNative();\n\n // Emit the event before any external calls\n emit BridgeRelayed({\n transactionId: transactionId,\n relayer: relayer,\n to: to,\n originChainId: request.originChainId(),\n originToken: request.originToken(),\n destToken: token,\n originAmount: request.originAmount(),\n destAmount: amount,\n chainGasAmount: zapNative\n });\n\n // All state changes have been done at this point, can proceed to the external calls.\n // This follows the checks-effects-interactions pattern to mitigate potential reentrancy attacks.\n if (token == NATIVE_GAS_TOKEN) {\n // For the native gas token, additional zapNative is not allowed\n if (zapNative != 0) revert ZapNativeNotSupported();\n // Check that the correct msg.value was sent\n if (msg.value != amount) revert MsgValueIncorrect();\n // Don't do a native transfer yet: we will handle it alongside the Zap below\n } else {\n // For ERC20s, we check that the correct msg.value was sent\n if (msg.value != zapNative) revert MsgValueIncorrect();\n // We need to transfer the tokens from the Relayer to the recipient first before performing an\n // optional post-transfer Zap.\n IERC20(token).safeTransferFrom(msg.sender, to, amount);\n }\n // At this point we have done:\n // - Transferred the requested amount of ERC20 tokens to the recipient.\n // At this point we have confirmed:\n // - For ERC20s: msg.value matches the requested zapNative amount.\n // - For the native gas token: msg.value matches the requested destAmount.\n // Remaining optional things to do:\n // - Forward the full msg.value to the recipient (if non-zero).\n // - Trigger a Zap (if zapData is present).\n bytes calldata zapData = request.zapData();\n if (zapData.length != 0) {\n // Zap Data is present: Zap has been requested by the recipient. Trigger it forwarding the full msg.value.\n\n // Note: if token has a fee on transfers, the recipient will have received less than `amount`.\n // This is a very niche edge case and should be handled by the recipient contract.\n _triggerZapWithChecks({recipient: to, token: token, amount: amount, zapData: zapData});\n } else if (msg.value != 0) {\n // Zap Data is missing, but msg.value was sent. This could happen in two different cases:\n // - Relay with the native gas token is happening.\n // - Relay with ERC20 is happening, with a `zapNative \u003e 0` request.\n // In both cases, we need to transfer the full msg.value to the recipient.\n Address.sendValue(payable(to), msg.value);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) public onlyRole(PROVER_ROLE) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n\n // Can only prove a REQUESTED transaction\n if ($.status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n // Update status to RELAYER_PROVED and store the proof details\n // Note: these are storage writes\n $.status = BridgeStatus.RELAYER_PROVED;\n $.proofBlockTimestamp = uint56(block.timestamp);\n $.proofRelayer = relayer;\n\n emit BridgeProofProvided(transactionId, relayer, destTxHash);\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes calldata request, address to) public {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Aggregate the read operations from the same storage slot\n address proofRelayer = $.proofRelayer;\n BridgeStatus status = $.status;\n uint56 proofBlockTimestamp = $.proofBlockTimestamp;\n\n // Can only claim a RELAYER_PROVED transaction after the dispute period\n if (status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(proofBlockTimestamp) \u003c= DISPUTE_PERIOD) {\n revert DisputePeriodNotPassed();\n }\n\n if (to == address(0)) {\n // Anyone could claim the funds to the proven relayer on their behalf\n to = proofRelayer;\n } else if (proofRelayer != msg.sender) {\n // Only the proven relayer could specify an address to claim the funds to\n revert SenderIncorrect();\n }\n\n // Update status to RELAYER_CLAIMED and transfer the origin collateral to the specified claim address\n // Note: this is a storage write\n $.status = BridgeStatus.RELAYER_CLAIMED;\n\n address token = request.originToken();\n uint256 amount = request.originAmount();\n // Update protocol fees if origin fee amount exists\n uint256 originFeeAmount = request.originFeeAmount();\n if (originFeeAmount \u003e 0) protocolFees[token] += originFeeAmount;\n // Emit the event before any external calls\n emit BridgeDepositClaimed(transactionId, proofRelayer, to, token, amount);\n // Complete the relayer claim as the last transaction action\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(to), amount);\n } else {\n IERC20(token).safeTransfer(to, amount);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function cancel(bytes calldata request) public {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Can only cancel a REQUESTED transaction after its deadline expires\n if ($.status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n uint256 deadline = request.deadline();\n // Permissionless cancel is only allowed after `cancelDelay` on top of the deadline\n if (!hasRole(CANCELER_ROLE, msg.sender)) deadline += cancelDelay;\n if (block.timestamp \u003c= deadline) revert DeadlineNotExceeded();\n // Update status to REFUNDED and return the full amount (collateral + protocol fees) to the original sender.\n // The protocol fees are only updated when the transaction is claimed, so we don't need to update them here.\n // Note: this is a storage write\n $.status = BridgeStatus.REFUNDED;\n\n address to = request.originSender();\n address token = request.originToken();\n uint256 amount = request.originAmount() + request.originFeeAmount();\n // Emit the event before any external calls\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n // Complete the user cancel as the last transaction action\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(to), amount);\n } else {\n IERC20(token).safeTransfer(to, amount);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeStatuses(bytes32 transactionId) public view returns (BridgeStatus status) {\n return bridgeTxDetails[transactionId].status;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeProofs(bytes32 transactionId) public view returns (uint96 timestamp, address relayer) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n\n timestamp = $.proofBlockTimestamp;\n relayer = $.proofRelayer;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeRelays(bytes32 transactionId) public view returns (bool) {\n // has this transactionId been relayed?\n return bridgeRelayDetails[transactionId].relayer != address(0);\n }\n\n /// @notice Takes the bridged asset from the user into FastBridgeV2 custody. It will be later\n /// claimed by the relayer who completed the relay on destination chain, or transferred back to the user\n /// via the cancel function should no one complete the relay.\n function _takeBridgedUserAsset(address token, uint256 amount) internal returns (uint256 amountTaken) {\n if (token == NATIVE_GAS_TOKEN) {\n // For the native gas token, we just need to check that the supplied msg.value is correct.\n // Supplied `msg.value` is already in FastBridgeV2 custody.\n if (amount != msg.value) revert MsgValueIncorrect();\n amountTaken = msg.value;\n } else {\n // For ERC20s, token is explicitly transferred from the user to FastBridgeV2.\n // We don't allow non-zero `msg.value` to avoid extra funds from being stuck in FastBridgeV2.\n if (msg.value != 0) revert MsgValueIncorrect();\n // Throw an explicit error if the provided token address is not a contract\n if (token.code.length == 0) revert TokenNotContract();\n amountTaken = IERC20(token).balanceOf(address(this));\n IERC20(token).safeTransferFrom(msg.sender, address(this), amount);\n // Use the balance difference as the amount taken in case of fee on transfer tokens.\n amountTaken = IERC20(token).balanceOf(address(this)) - amountTaken;\n }\n }\n\n /// @notice Calls the Recipient's hook function with the specified zapData and performs\n /// all the necessary checks for the returned value.\n function _triggerZapWithChecks(address recipient, address token, uint256 amount, bytes calldata zapData) internal {\n // This will bubble any revert messages from the hook function\n bytes memory returnData = Address.functionCallWithValue({\n target: recipient,\n data: abi.encodeCall(IZapRecipient.zap, (token, amount, zapData)),\n // Note: see `relay()` for reasoning behind passing msg.value\n value: msg.value\n });\n // Explicit revert if no return data at all\n if (returnData.length == 0) revert RecipientNoReturnValue();\n // Check that exactly a single return value was returned\n if (returnData.length != 32) revert RecipientIncorrectReturnValue();\n // Return value should be abi-encoded hook function selector\n if (bytes32(returnData) != bytes32(IZapRecipient.zap.selector)) {\n revert RecipientIncorrectReturnValue();\n }\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint56(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint56).max but\n /// proof.timestamp \u003c type(uint56).max via unchecked statement\n /// @param proofBlockTimestamp The bridge proof block timestamp\n /// @return delta Time delta since proof submitted\n function _timeSince(uint56 proofBlockTimestamp) internal view returns (uint256 delta) {\n unchecked {\n delta = uint56(block.timestamp) - proofBlockTimestamp;\n }\n }\n\n /// @notice Performs all the necessary checks for a bridge to happen.\n /// @dev There's no good way to refactor this function to reduce cyclomatic complexity due to\n /// the number of checks that need to be performed, so we skip the code-complexity rule here.\n // solhint-disable-next-line code-complexity\n function _validateBridgeParams(\n BridgeParams memory params,\n BridgeParamsV2 memory paramsV2,\n int256 exclusivityEndTime\n )\n internal\n view\n {\n // Check V1 (legacy) params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.sender == address(0) || params.to == address(0)) revert ZeroAddress();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n // Check V2 params\n if (paramsV2.zapData.length \u003e MAX_ZAP_DATA_LENGTH) revert ZapDataLengthAboveMax();\n if (paramsV2.zapNative != 0 \u0026\u0026 params.destToken == NATIVE_GAS_TOKEN) {\n revert ZapNativeNotSupported();\n }\n // exclusivityEndTime must be in range [0 .. params.deadline]\n if (exclusivityEndTime \u003c 0 || exclusivityEndTime \u003e int256(params.deadline)) {\n revert ExclusivityParamsIncorrect();\n }\n }\n\n /// @notice Performs all the necessary checks for a relay to happen.\n function _validateRelayParams(bytes calldata request, bytes32 transactionId, address relayer) internal view {\n if (relayer == address(0)) revert ZeroAddress();\n // Check if the transaction has already been relayed\n if (bridgeRelays(transactionId)) revert TransactionRelayed();\n if (request.destChainId() != block.chainid) revert ChainIncorrect();\n // Check the deadline for relay to happen\n if (block.timestamp \u003e request.deadline()) revert DeadlineExceeded();\n // Check the exclusivity period, if it is still ongoing\n address exclRelayer = request.exclusivityRelayer();\n if (exclRelayer != address(0) \u0026\u0026 exclRelayer != relayer \u0026\u0026 block.timestamp \u003c= request.exclusivityEndTime()) {\n revert ExclusivityPeriodNotPassed();\n }\n }\n}\n","language":"Solidity","languageVersion":"0.8.24","compilerVersion":"0.8.24","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"","srcMapRuntime":"","abiDefinition":[{"inputs":[],"name":"DOMAIN_SEPARATOR","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"nonces","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"permit","outputs":[],"stateMutability":"nonpayable","type":"function"}],"userDoc":{"kind":"user","methods":{},"version":1},"developerDoc":{"details":"Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in https://eips.ethereum.org/EIPS/eip-2612[EIP-2612]. Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't need to send a transaction, and thus is not required to hold Ether at all. ==== Security Considerations There are two important considerations concerning the use of `permit`. The first is that a valid permit signature expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be considered as an intention to spend the allowance in any specific way. The second is that because permits have built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be generally recommended is: ```solidity function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public { try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {} doThing(..., value); } function doThing(..., uint256 value) public { token.safeTransferFrom(msg.sender, address(this), value); ... } ``` Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also {SafeERC20-safeTransferFrom}). Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so contracts should have entry points that don't rely on permit.","kind":"dev","methods":{"DOMAIN_SEPARATOR()":{"details":"Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}."},"nonces(address)":{"details":"Returns the current nonce for `owner`. This value must be included whenever a signature is generated for {permit}. Every successful call to {permit} increases ``owner``'s nonce by one. This prevents a signature from being used multiple times."},"permit(address,address,uint256,uint256,uint8,bytes32,bytes32)":{"details":"Sets `value` as the allowance of `spender` over ``owner``'s tokens, given ``owner``'s signed approval. IMPORTANT: The same issues {IERC20-approve} has related to transaction ordering also apply here. Emits an {Approval} event. Requirements: - `spender` cannot be the zero address. - `deadline` must be a timestamp in the future. - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner` over the EIP712-formatted function arguments. - the signature must use ``owner``'s current nonce (see {nonces}). For more information on the signature format, see the https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP section]. CAUTION: See Security Considerations above."}},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[],\"name\":\"DOMAIN_SEPARATOR\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"}],\"name\":\"nonces\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"},{\"internalType\":\"uint8\",\"name\":\"v\",\"type\":\"uint8\"},{\"internalType\":\"bytes32\",\"name\":\"r\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"s\",\"type\":\"bytes32\"}],\"name\":\"permit\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"details\":\"Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in https://eips.ethereum.org/EIPS/eip-2612[EIP-2612]. Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't need to send a transaction, and thus is not required to hold Ether at all. ==== Security Considerations There are two important considerations concerning the use of `permit`. The first is that a valid permit signature expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be considered as an intention to spend the allowance in any specific way. The second is that because permits have built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be generally recommended is: ```solidity function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public { try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {} doThing(..., value); } function doThing(..., uint256 value) public { token.safeTransferFrom(msg.sender, address(this), value); ... } ``` Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also {SafeERC20-safeTransferFrom}). Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so contracts should have entry points that don't rely on permit.\",\"kind\":\"dev\",\"methods\":{\"DOMAIN_SEPARATOR()\":{\"details\":\"Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\"},\"nonces(address)\":{\"details\":\"Returns the current nonce for `owner`. This value must be included whenever a signature is generated for {permit}. Every successful call to {permit} increases ``owner``'s nonce by one. This prevents a signature from being used multiple times.\"},\"permit(address,address,uint256,uint256,uint8,bytes32,bytes32)\":{\"details\":\"Sets `value` as the allowance of `spender` over ``owner``'s tokens, given ``owner``'s signed approval. IMPORTANT: The same issues {IERC20-approve} has related to transaction ordering also apply here. Emits an {Approval} event. Requirements: - `spender` cannot be the zero address. - `deadline` must be a timestamp in the future. - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner` over the EIP712-formatted function arguments. - the signature must use ``owner``'s current nonce (see {nonces}). For more information on the signature format, see the https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP section]. CAUTION: See Security Considerations above.\"}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeV2.sol\":\"IERC20Permit\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeV2.sol\":{\"keccak256\":\"0xac79c463688a682ca706a4ef95e7817b83548cdfa8182ba0426ac7e5e07613d8\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://b3ecb7097381287cafc3a73f3a2bb03565115ebb682a85064e0b0dc2f7e2919d\",\"dweb:/ipfs/QmatruW3nYZTksf3CeQ8wwiAG4c7xoEJBEp6drHPtFLBRK\"]}},\"version\":1}"},"hashes":{"DOMAIN_SEPARATOR()":"3644e515","nonces(address)":"7ecebe00","permit(address,address,uint256,uint256,uint8,bytes32,bytes32)":"d505accf"}},"solidity/FastBridgeV2.sol:IFastBridge":{"code":"0x","runtime-code":"0x","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.24 ^0.8.20 ^0.8.4;\n\n// contracts/interfaces/IAdminV2.sol\n\ninterface IAdminV2 {\n event CancelDelayUpdated(uint256 oldCancelDelay, uint256 newCancelDelay);\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n function setCancelDelay(uint256 newCancelDelay) external;\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n}\n\n// contracts/interfaces/IAdminV2Errors.sol\n\ninterface IAdminV2Errors {\n error CancelDelayBelowMin();\n error FeeRateAboveMax();\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IFastBridgeV2Errors.sol\n\ninterface IFastBridgeV2Errors {\n error AmountIncorrect();\n error ChainIncorrect();\n error ExclusivityParamsIncorrect();\n error MsgValueIncorrect();\n error SenderIncorrect();\n error StatusIncorrect();\n error TokenNotContract();\n error ZapDataLengthAboveMax();\n error ZapNativeNotSupported();\n error ZeroAddress();\n\n error RecipientIncorrectReturnValue();\n error RecipientNoReturnValue();\n\n error DeadlineExceeded();\n error DeadlineNotExceeded();\n error DeadlineTooShort();\n error DisputePeriodNotPassed();\n error DisputePeriodPassed();\n error ExclusivityPeriodNotPassed();\n\n error TransactionRelayed();\n}\n\n// contracts/interfaces/IMulticallTarget.sol\n\n/// @notice Interface for a contract that can be called multiple times by the same caller. Inspired by MulticallV3:\n/// https://github.com/mds1/multicall/blob/master/src/Multicall3.sol\ninterface IMulticallTarget {\n struct Result {\n bool success;\n bytes returnData;\n }\n\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external;\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results);\n}\n\n// contracts/interfaces/IZapRecipient.sol\n\ninterface IZapRecipient {\n function zap(address token, uint256 amount, bytes memory zapData) external payable returns (bytes4);\n}\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// contracts/interfaces/IFastBridgeV2.sol\n\ninterface IFastBridgeV2 is IFastBridge {\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n struct BridgeTxDetails {\n BridgeStatus status;\n uint32 destChainId;\n uint56 proofBlockTimestamp;\n address proofRelayer;\n }\n\n struct BridgeRelay {\n uint48 blockNumber;\n uint48 blockTimestamp;\n address relayer;\n }\n\n /// @notice New params introduced in the FastBridgeV2.\n /// We are passing fields from the older BridgeParams struct outside of this struct\n /// for backwards compatibility.\n /// Note: quoteRelayer and quoteExclusivitySeconds are either both zero (indicating no exclusivity)\n /// or both non-zero (indicating exclusivity for the given period).\n /// Note: zapNative \u003e 0 can NOT be used with destToken = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE (native token)\n /// @param quoteRelayer Relayer that provided the quote for the transaction\n /// @param quoteExclusivitySeconds Period of time the quote relayer is guaranteed exclusivity after user's deposit\n /// @param quoteId Unique quote identifier used for tracking the quote\n /// @param zapNative ETH value to send to the recipient (if any)\n /// @param zapData Parameters for the Zap to the destination recipient (if any)\n struct BridgeParamsV2 {\n address quoteRelayer;\n int256 quoteExclusivitySeconds;\n bytes quoteId;\n uint256 zapNative;\n bytes zapData;\n }\n\n /// @notice Updated bridge transaction struct to include parameters introduced in FastBridgeV2.\n /// Note: only `exclusivityRelayer` can fill such a transaction until `exclusivityEndTime`.\n struct BridgeTransactionV2 {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n // Note: sendChainGas flag from V1 is deprecated\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n address exclusivityRelayer;\n uint256 exclusivityEndTime;\n uint256 zapNative; // ETH value to send to the recipient (if any)\n bytes zapData; // data to pass for the Zap action (if any)\n }\n\n event BridgeQuoteDetails(bytes32 indexed transactionId, bytes quoteId);\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability\n /// to provide temporary exclusivity fill rights for the quote relayer.\n /// @param params The parameters required to bridge\n /// @param paramsV2 The parameters for exclusivity fill rights (optional, can be left empty)\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function relay(bytes memory request, address relayer) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param transactionId The transaction id associated with the encoded bridge transaction to prove\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital.\n /// @notice Can only send funds to the relayer address on the proof.\n /// @param request The encoded bridge transaction to claim on origin chain\n function claim(bytes memory request) external;\n\n /// @notice Cancels an outstanding bridge transaction in case optimistic bridging failed and returns the full amount\n /// to the original sender.\n /// @param request The encoded bridge transaction to refund\n function cancel(bytes memory request) external;\n\n /// @notice Checks if a transaction has been relayed\n /// @param transactionId The ID of the transaction to check\n /// @return True if the transaction has been relayed, false otherwise\n function bridgeRelays(bytes32 transactionId) external view returns (bool);\n\n /// @notice Returns the status of a bridge transaction\n /// @param transactionId The ID of the bridge transaction\n /// @return BridgeStatus Status of the bridge transaction\n function bridgeStatuses(bytes32 transactionId) external view returns (BridgeStatus);\n\n /// @notice Returns the timestamp and relayer of a bridge proof\n /// @param transactionId The ID of the bridge transaction\n /// @return timestamp The timestamp of the bridge proof\n /// @return relayer The relayer address of the bridge proof\n function bridgeProofs(bytes32 transactionId) external view returns (uint96 timestamp, address relayer);\n\n /// @notice Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\n /// @param request The bridge request to decode\n function getBridgeTransactionV2(bytes memory request) external view returns (BridgeTransactionV2 memory);\n}\n\n// contracts/utils/MulticallTarget.sol\n\n// solhint-disable avoid-low-level-calls\n/// @notice Template for a contract that supports batched calls (preserving the msg.sender).\n/// Only calls with zero msg.value could be batched.\nabstract contract MulticallTarget is IMulticallTarget {\n error MulticallTarget__UndeterminedRevert();\n\n /// @notice Perform a batched call to this contract, preserving the msg.sender.\n /// The return data from each call is discarded.\n /// @dev The method is non-payable, so only calls with `msg.value == 0` could be batched.\n /// It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag.\n /// Otherwise, the whole batch call will be reverted with the original revert reason.\n /// @param data List of abi-encoded calldata for the calls to perform.\n /// @param ignoreReverts Whether to ignore the revert errors from the calls.\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external {\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\n if (!success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(result);\n }\n }\n }\n\n /// @notice Perform a batched call to this contract, preserving the msg.sender.\n /// The return data from each call is preserved.\n /// @dev The method is non-payable, so only calls with `msg.value == 0` could be batched.\n /// It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag.\n /// Otherwise, the whole batch call will be reverted with the original revert reason.\n /// @param data List of abi-encoded calldata for the calls to perform.\n /// @param ignoreReverts Whether to ignore the revert errors from the calls.\n /// @return results List of results from the calls: `(success, returnData)`.\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results)\n {\n results = new Result[](data.length);\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (results[i].success, results[i].returnData) = address(this).delegatecall(data[i]);\n if (!results[i].success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(results[i].returnData);\n }\n }\n }\n\n /// @dev Bubbles the revert message from the underlying call.\n /// Note: preserves the same custom error or revert string, if one was used.\n /// Source: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v5.0.2/contracts/utils/Address.sol#L143-L158\n function _bubbleRevert(bytes memory returnData) internal pure {\n // Look for revert reason and bubble it up if present\n if (returnData.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n // solhint-disable-next-line no-inline-assembly\n assembly {\n let returndata_size := mload(returnData)\n revert(add(32, returnData), returndata_size)\n }\n } else {\n revert MulticallTarget__UndeterminedRevert();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// contracts/libs/BridgeTransactionV2.sol\n\n// solhint-disable no-inline-assembly\nlibrary BridgeTransactionV2Lib {\n uint16 internal constant VERSION = 2;\n\n // Offsets of the fields in the packed BridgeTransactionV2 struct\n // uint16 version [000 .. 002)\n // uint32 originChainId [002 .. 006)\n // uint32 destChainId [006 .. 010)\n // address originSender [010 .. 030)\n // address destRecipient [030 .. 050)\n // address originToken [050 .. 070)\n // address destToken [070 .. 090)\n // uint256 originAmount [090 .. 122)\n // uint256 destAmount [122 .. 154)\n // uint256 originFeeAmount [154 .. 186)\n // uint256 deadline [186 .. 218)\n // uint256 nonce [218 .. 250)\n // address exclusivityRelayer [250 .. 270)\n // uint256 exclusivityEndTime [270 .. 302)\n // uint256 zapNative [302 .. 334)\n // bytes zapData [334 .. ***)\n\n // forgefmt: disable-start\n uint256 private constant OFFSET_ORIGIN_CHAIN_ID = 2;\n uint256 private constant OFFSET_DEST_CHAIN_ID = 6;\n uint256 private constant OFFSET_ORIGIN_SENDER = 10;\n uint256 private constant OFFSET_DEST_RECIPIENT = 30;\n uint256 private constant OFFSET_ORIGIN_TOKEN = 50;\n uint256 private constant OFFSET_DEST_TOKEN = 70;\n uint256 private constant OFFSET_ORIGIN_AMOUNT = 90;\n uint256 private constant OFFSET_DEST_AMOUNT = 122;\n uint256 private constant OFFSET_ORIGIN_FEE_AMOUNT = 154;\n uint256 private constant OFFSET_DEADLINE = 186;\n uint256 private constant OFFSET_NONCE = 218;\n uint256 private constant OFFSET_EXCLUSIVITY_RELAYER = 250;\n uint256 private constant OFFSET_EXCLUSIVITY_END_TIME = 270;\n uint256 private constant OFFSET_ZAP_NATIVE = 302;\n uint256 private constant OFFSET_ZAP_DATA = 334;\n // forgefmt: disable-end\n\n error BridgeTransactionV2__InvalidEncodedTx();\n error BridgeTransactionV2__UnsupportedVersion(uint16 version);\n\n /// @notice Validates the encoded transaction to be a tightly packed encoded payload for BridgeTransactionV2.\n /// @dev Checks the minimum length and the version, use this function before decoding any of the fields.\n function validateV2(bytes calldata encodedTx) internal pure {\n // Check the minimum length: must at least include all static fields.\n if (encodedTx.length \u003c OFFSET_ZAP_DATA) revert BridgeTransactionV2__InvalidEncodedTx();\n // Once we validated the length, we can be sure that the version field is present.\n uint16 version_ = version(encodedTx);\n if (version_ != VERSION) revert BridgeTransactionV2__UnsupportedVersion(version_);\n }\n\n /// @notice Encodes the BridgeTransactionV2 struct by tightly packing the fields.\n /// @dev `abi.decode` will not work as a result of the tightly packed fields. Use `decodeV2` to decode instead.\n function encodeV2(IFastBridgeV2.BridgeTransactionV2 memory bridgeTx) internal pure returns (bytes memory) {\n // We split the encoding into two parts to avoid stack-too-deep error\n bytes memory firstPart = abi.encodePacked(\n VERSION,\n bridgeTx.originChainId,\n bridgeTx.destChainId,\n bridgeTx.originSender,\n bridgeTx.destRecipient,\n bridgeTx.originToken,\n bridgeTx.destToken,\n bridgeTx.originAmount\n );\n return abi.encodePacked(\n firstPart,\n bridgeTx.destAmount,\n bridgeTx.originFeeAmount,\n // Note: we skip the deprecated `sendChainGas` flag, which was present in BridgeTransaction V1\n bridgeTx.deadline,\n bridgeTx.nonce,\n // New V2 fields: exclusivity\n bridgeTx.exclusivityRelayer,\n bridgeTx.exclusivityEndTime,\n // New V2 fields: Zap\n bridgeTx.zapNative,\n bridgeTx.zapData\n );\n }\n\n /// @notice Decodes the BridgeTransactionV2 struct from the encoded transaction.\n /// @dev Encoded BridgeTransactionV2 struct must be tightly packed.\n /// Use `validateV2` before decoding to ensure the encoded transaction is valid.\n function decodeV2(bytes calldata encodedTx)\n internal\n pure\n returns (IFastBridgeV2.BridgeTransactionV2 memory bridgeTx)\n {\n bridgeTx.originChainId = originChainId(encodedTx);\n bridgeTx.destChainId = destChainId(encodedTx);\n bridgeTx.originSender = originSender(encodedTx);\n bridgeTx.destRecipient = destRecipient(encodedTx);\n bridgeTx.originToken = originToken(encodedTx);\n bridgeTx.destToken = destToken(encodedTx);\n bridgeTx.originAmount = originAmount(encodedTx);\n bridgeTx.destAmount = destAmount(encodedTx);\n bridgeTx.originFeeAmount = originFeeAmount(encodedTx);\n bridgeTx.deadline = deadline(encodedTx);\n bridgeTx.nonce = nonce(encodedTx);\n bridgeTx.exclusivityRelayer = exclusivityRelayer(encodedTx);\n bridgeTx.exclusivityEndTime = exclusivityEndTime(encodedTx);\n bridgeTx.zapNative = zapNative(encodedTx);\n bridgeTx.zapData = zapData(encodedTx);\n }\n\n /// @notice Extracts the version from the encoded transaction.\n function version(bytes calldata encodedTx) internal pure returns (uint16 version_) {\n // Load 32 bytes from the start and shift it 240 bits to the right to get the highest 16 bits.\n assembly {\n version_ := shr(240, calldataload(encodedTx.offset))\n }\n }\n\n /// @notice Extracts the origin chain ID from the encoded transaction.\n function originChainId(bytes calldata encodedTx) internal pure returns (uint32 originChainId_) {\n // Load 32 bytes from the offset and shift it 224 bits to the right to get the highest 32 bits.\n assembly {\n originChainId_ := shr(224, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_CHAIN_ID)))\n }\n }\n\n /// @notice Extracts the destination chain ID from the encoded transaction.\n function destChainId(bytes calldata encodedTx) internal pure returns (uint32 destChainId_) {\n // Load 32 bytes from the offset and shift it 224 bits to the right to get the highest 32 bits.\n assembly {\n destChainId_ := shr(224, calldataload(add(encodedTx.offset, OFFSET_DEST_CHAIN_ID)))\n }\n }\n\n /// @notice Extracts the origin sender from the encoded transaction.\n function originSender(bytes calldata encodedTx) internal pure returns (address originSender_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n originSender_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_SENDER)))\n }\n }\n\n /// @notice Extracts the destination recipient from the encoded transaction.\n function destRecipient(bytes calldata encodedTx) internal pure returns (address destRecipient_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n destRecipient_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_DEST_RECIPIENT)))\n }\n }\n\n /// @notice Extracts the origin token from the encoded transaction.\n function originToken(bytes calldata encodedTx) internal pure returns (address originToken_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n originToken_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_TOKEN)))\n }\n }\n\n /// @notice Extracts the destination token from the encoded transaction.\n function destToken(bytes calldata encodedTx) internal pure returns (address destToken_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n destToken_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_DEST_TOKEN)))\n }\n }\n\n /// @notice Extracts the origin amount from the encoded transaction.\n function originAmount(bytes calldata encodedTx) internal pure returns (uint256 originAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n originAmount_ := calldataload(add(encodedTx.offset, OFFSET_ORIGIN_AMOUNT))\n }\n }\n\n /// @notice Extracts the destination amount from the encoded transaction.\n function destAmount(bytes calldata encodedTx) internal pure returns (uint256 destAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n destAmount_ := calldataload(add(encodedTx.offset, OFFSET_DEST_AMOUNT))\n }\n }\n\n /// @notice Extracts the origin fee amount from the encoded transaction.\n function originFeeAmount(bytes calldata encodedTx) internal pure returns (uint256 originFeeAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n originFeeAmount_ := calldataload(add(encodedTx.offset, OFFSET_ORIGIN_FEE_AMOUNT))\n }\n }\n\n /// @notice Extracts the deadline from the encoded transaction.\n function deadline(bytes calldata encodedTx) internal pure returns (uint256 deadline_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n deadline_ := calldataload(add(encodedTx.offset, OFFSET_DEADLINE))\n }\n }\n\n /// @notice Extracts the nonce from the encoded transaction.\n function nonce(bytes calldata encodedTx) internal pure returns (uint256 nonce_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n nonce_ := calldataload(add(encodedTx.offset, OFFSET_NONCE))\n }\n }\n\n /// @notice Extracts the exclusivity relayer from the encoded transaction.\n function exclusivityRelayer(bytes calldata encodedTx) internal pure returns (address exclusivityRelayer_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n exclusivityRelayer_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_EXCLUSIVITY_RELAYER)))\n }\n }\n\n /// @notice Extracts the exclusivity end time from the encoded transaction.\n function exclusivityEndTime(bytes calldata encodedTx) internal pure returns (uint256 exclusivityEndTime_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n exclusivityEndTime_ := calldataload(add(encodedTx.offset, OFFSET_EXCLUSIVITY_END_TIME))\n }\n }\n\n /// @notice Extracts the Zap's native value from the encoded transaction.\n function zapNative(bytes calldata encodedTx) internal pure returns (uint256 zapNative_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n zapNative_ := calldataload(add(encodedTx.offset, OFFSET_ZAP_NATIVE))\n }\n }\n\n /// @notice Extracts the Zap's data from the encoded transaction.\n function zapData(bytes calldata encodedTx) internal pure returns (bytes calldata zapData_) {\n zapData_ = encodedTx[OFFSET_ZAP_DATA:];\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/AdminV2.sol\n\ncontract AdminV2 is AccessControlEnumerable, IAdminV2, IAdminV2Errors {\n using SafeERC20 for IERC20;\n\n /// @notice Address reserved for native gas token (ETH on Ethereum and most L2s, AVAX on Avalanche, etc)\n address public constant NATIVE_GAS_TOKEN = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Role identifier for Quoter API's off-chain authentication.\n /// @dev Only addresses with this role can post FastBridge quotes to the API.\n bytes32 public constant QUOTER_ROLE = keccak256(\"QUOTER_ROLE\");\n\n /// @notice Role identifier for Prover's on-chain authentication in FastBridge.\n /// @dev Only addresses with this role can provide proofs that a FastBridge request has been relayed.\n bytes32 public constant PROVER_ROLE = keccak256(\"PROVER_ROLE\");\n\n /// @notice Role identifier for Guard's on-chain authentication in FastBridge.\n /// @dev Only addresses with this role can dispute submitted relay proofs during the dispute period.\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n\n /// @notice Role identifier for Canceler's on-chain authentication in FastBridge.\n /// @dev Only addresses with this role can cancel a FastBridge transaction without the cancel delay.\n bytes32 public constant CANCELER_ROLE = keccak256(\"CANCELER_ROLE\");\n\n /// @notice Role identifier for Governor's on-chain administrative authority.\n /// @dev Only addresses with this role can perform administrative tasks within the contract.\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n /// @notice Denominator for fee rates, represents 100%.\n uint256 public constant FEE_BPS = 1e6;\n /// @notice Maximum protocol fee rate: 1% on origin amount.\n uint256 public constant FEE_RATE_MAX = 0.01e6;\n\n /// @notice Minimum cancel delay that can be set by the governor.\n uint256 public constant MIN_CANCEL_DELAY = 1 hours;\n /// @notice Default cancel delay set during the contract deployment.\n uint256 public constant DEFAULT_CANCEL_DELAY = 1 days;\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Delay for a transaction after which it could be permisionlessly cancelled\n uint256 public cancelDelay;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Use ZapNative V2 requests instead.\n uint256 public immutable chainGasAmount = 0;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n _setCancelDelay(DEFAULT_CANCEL_DELAY);\n }\n\n /// @notice Allows the contract governor to set the cancel delay. The cancel delay is the time after the transaction\n /// deadline after which it can be permissionlessly cancelled, if it hasn't been proven by any of the Relayers.\n function setCancelDelay(uint256 newCancelDelay) external onlyRole(GOVERNOR_ROLE) {\n _setCancelDelay(newCancelDelay);\n }\n\n /// @notice Allows the contract governor to set the protocol fee rate. The protocol fee is taken from the origin\n /// amount only for completed and claimed transactions.\n /// @dev The protocol fee is abstracted away from the relayers, they always operate using the amounts after fees:\n /// what they see as the origin amount emitted in the log is what they get credited with.\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n if (newFeeRate \u003e FEE_RATE_MAX) revert FeeRateAboveMax();\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n /// @notice Allows the contract governor to sweep the accumulated protocol fees in the contract.\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n emit FeesSwept(token, recipient, feeAmount);\n /// Sweep the fees as the last transaction action\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(recipient), feeAmount);\n } else {\n IERC20(token).safeTransfer(recipient, feeAmount);\n }\n }\n\n /// @notice Internal function to set the cancel delay. Security checks are performed outside of this function.\n function _setCancelDelay(uint256 newCancelDelay) private {\n if (newCancelDelay \u003c MIN_CANCEL_DELAY) revert CancelDelayBelowMin();\n uint256 oldCancelDelay = cancelDelay;\n cancelDelay = newCancelDelay;\n emit CancelDelayUpdated(oldCancelDelay, newCancelDelay);\n }\n}\n\n// contracts/FastBridgeV2.sol\n\n/// @notice FastBridgeV2 is a contract for bridging tokens across chains.\ncontract FastBridgeV2 is AdminV2, MulticallTarget, IFastBridgeV2, IFastBridgeV2Errors {\n using BridgeTransactionV2Lib for bytes;\n using SafeERC20 for IERC20;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n /// @notice Maximum length of accepted zapData\n uint256 public constant MAX_ZAP_DATA_LENGTH = 2 ** 16 - 1;\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeTxDetails) public bridgeTxDetails;\n /// @notice Relay details on destination chain\n mapping(bytes32 =\u003e BridgeRelay) public bridgeRelayDetails;\n /// @notice Unique bridge nonces tracked per originSender\n mapping(address =\u003e uint256) public senderNonces;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Replaced by senderNonces\n uint256 public immutable nonce = 0;\n /// @notice the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) AdminV2(_owner) {\n deployBlock = block.number;\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n bridge({\n params: params,\n paramsV2: BridgeParamsV2({\n quoteRelayer: address(0),\n quoteExclusivitySeconds: 0,\n quoteId: bytes(\"\"),\n zapNative: 0,\n zapData: bytes(\"\")\n })\n });\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes calldata request) external payable {\n // relay override will validate the request\n relay({request: request, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes calldata request, bytes32 destTxHash) external {\n request.validateV2();\n prove({transactionId: keccak256(request), destTxHash: destTxHash, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridgeV2\n function claim(bytes calldata request) external {\n // claim override will validate the request\n claim({request: request, to: address(0)});\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Aggregate the read operations from the same storage slot\n address disputedRelayer = $.proofRelayer;\n BridgeStatus status = $.status;\n uint56 proofBlockTimestamp = $.proofBlockTimestamp;\n // Can only dispute a RELAYER_PROVED transaction within the dispute period\n if (status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(proofBlockTimestamp) \u003e DISPUTE_PERIOD) {\n revert DisputePeriodPassed();\n }\n // Update status to REQUESTED and delete the disputed proof details\n // Note: these are storage writes\n $.status = BridgeStatus.REQUESTED;\n $.proofRelayer = address(0);\n $.proofBlockTimestamp = 0;\n\n emit BridgeProofDisputed(transactionId, disputedRelayer);\n }\n\n /// Note: this function is deprecated and will be removed in a future version.\n /// @inheritdoc IFastBridge\n function refund(bytes calldata request) external {\n cancel(request);\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // The correct relayer can only claim a RELAYER_PROVED transaction after the dispute period\n if ($.status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if ($.proofRelayer != relayer) revert SenderIncorrect();\n return _timeSince($.proofBlockTimestamp) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n /// @dev This method is added to achieve backwards compatibility with decoding requests into V1 structs:\n /// - `zapNative` is partially reported as a zero/non-zero flag\n /// - `zapData` is ignored\n /// In order to process all kinds of requests use getBridgeTransactionV2 instead.\n function getBridgeTransaction(bytes calldata request) external view returns (BridgeTransaction memory) {\n // Try decoding into V2 struct first. This will revert if V1 struct is passed\n try this.getBridgeTransactionV2(request) returns (BridgeTransactionV2 memory txV2) {\n // Note: we entirely ignore the zapData field, as it was not present in V1\n return BridgeTransaction({\n originChainId: txV2.originChainId,\n destChainId: txV2.destChainId,\n originSender: txV2.originSender,\n destRecipient: txV2.destRecipient,\n originToken: txV2.originToken,\n destToken: txV2.destToken,\n originAmount: txV2.originAmount,\n destAmount: txV2.destAmount,\n originFeeAmount: txV2.originFeeAmount,\n sendChainGas: txV2.zapNative != 0,\n deadline: txV2.deadline,\n nonce: txV2.nonce\n });\n } catch {\n // Fallback to V1 struct\n return abi.decode(request, (BridgeTransaction));\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function getBridgeTransactionV2(bytes calldata request) external pure returns (BridgeTransactionV2 memory) {\n request.validateV2();\n return BridgeTransactionV2Lib.decodeV2(request);\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) public payable {\n int256 exclusivityEndTime = 0;\n // if relayer exclusivity is not intended for this bridge, set exclusivityEndTime to static zero\n // otherwise, set exclusivity to expire at the current block ts offset by quoteExclusivitySeconds\n if (paramsV2.quoteRelayer != address(0)) {\n exclusivityEndTime = int256(block.timestamp) + paramsV2.quoteExclusivitySeconds;\n }\n _validateBridgeParams(params, paramsV2, exclusivityEndTime);\n\n // transfer tokens to bridge contract\n /// @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _takeBridgedUserAsset(params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) {\n originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n }\n\n // set status to requested\n bytes memory request = BridgeTransactionV2Lib.encodeV2(\n BridgeTransactionV2({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n deadline: params.deadline,\n nonce: senderNonces[params.sender]++, // increment nonce on every bridge\n exclusivityRelayer: paramsV2.quoteRelayer,\n // We checked exclusivityEndTime to be in range [0 .. params.deadline] above, so can safely cast\n exclusivityEndTime: uint256(exclusivityEndTime),\n zapNative: paramsV2.zapNative,\n zapData: paramsV2.zapData\n })\n );\n bytes32 transactionId = keccak256(request);\n // Note: the tx status will be updated throughout the tx lifecycle, while destChainId is set once here\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n bridgeTxDetails[transactionId].destChainId = params.dstChainId;\n\n emit BridgeRequested({\n transactionId: transactionId,\n sender: params.sender,\n request: request,\n destChainId: params.dstChainId,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n sendChainGas: paramsV2.zapNative != 0\n });\n emit BridgeQuoteDetails(transactionId, paramsV2.quoteId);\n }\n\n /// @inheritdoc IFastBridgeV2\n function relay(bytes calldata request, address relayer) public payable {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n _validateRelayParams(request, transactionId, relayer);\n // mark bridge transaction as relayed\n bridgeRelayDetails[transactionId] =\n BridgeRelay({blockNumber: uint48(block.number), blockTimestamp: uint48(block.timestamp), relayer: relayer});\n\n // transfer tokens to recipient on destination chain and trigger Zap if requested\n address to = request.destRecipient();\n address token = request.destToken();\n uint256 amount = request.destAmount();\n uint256 zapNative = request.zapNative();\n\n // Emit the event before any external calls\n emit BridgeRelayed({\n transactionId: transactionId,\n relayer: relayer,\n to: to,\n originChainId: request.originChainId(),\n originToken: request.originToken(),\n destToken: token,\n originAmount: request.originAmount(),\n destAmount: amount,\n chainGasAmount: zapNative\n });\n\n // All state changes have been done at this point, can proceed to the external calls.\n // This follows the checks-effects-interactions pattern to mitigate potential reentrancy attacks.\n if (token == NATIVE_GAS_TOKEN) {\n // For the native gas token, additional zapNative is not allowed\n if (zapNative != 0) revert ZapNativeNotSupported();\n // Check that the correct msg.value was sent\n if (msg.value != amount) revert MsgValueIncorrect();\n // Don't do a native transfer yet: we will handle it alongside the Zap below\n } else {\n // For ERC20s, we check that the correct msg.value was sent\n if (msg.value != zapNative) revert MsgValueIncorrect();\n // We need to transfer the tokens from the Relayer to the recipient first before performing an\n // optional post-transfer Zap.\n IERC20(token).safeTransferFrom(msg.sender, to, amount);\n }\n // At this point we have done:\n // - Transferred the requested amount of ERC20 tokens to the recipient.\n // At this point we have confirmed:\n // - For ERC20s: msg.value matches the requested zapNative amount.\n // - For the native gas token: msg.value matches the requested destAmount.\n // Remaining optional things to do:\n // - Forward the full msg.value to the recipient (if non-zero).\n // - Trigger a Zap (if zapData is present).\n bytes calldata zapData = request.zapData();\n if (zapData.length != 0) {\n // Zap Data is present: Zap has been requested by the recipient. Trigger it forwarding the full msg.value.\n\n // Note: if token has a fee on transfers, the recipient will have received less than `amount`.\n // This is a very niche edge case and should be handled by the recipient contract.\n _triggerZapWithChecks({recipient: to, token: token, amount: amount, zapData: zapData});\n } else if (msg.value != 0) {\n // Zap Data is missing, but msg.value was sent. This could happen in two different cases:\n // - Relay with the native gas token is happening.\n // - Relay with ERC20 is happening, with a `zapNative \u003e 0` request.\n // In both cases, we need to transfer the full msg.value to the recipient.\n Address.sendValue(payable(to), msg.value);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) public onlyRole(PROVER_ROLE) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n\n // Can only prove a REQUESTED transaction\n if ($.status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n // Update status to RELAYER_PROVED and store the proof details\n // Note: these are storage writes\n $.status = BridgeStatus.RELAYER_PROVED;\n $.proofBlockTimestamp = uint56(block.timestamp);\n $.proofRelayer = relayer;\n\n emit BridgeProofProvided(transactionId, relayer, destTxHash);\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes calldata request, address to) public {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Aggregate the read operations from the same storage slot\n address proofRelayer = $.proofRelayer;\n BridgeStatus status = $.status;\n uint56 proofBlockTimestamp = $.proofBlockTimestamp;\n\n // Can only claim a RELAYER_PROVED transaction after the dispute period\n if (status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(proofBlockTimestamp) \u003c= DISPUTE_PERIOD) {\n revert DisputePeriodNotPassed();\n }\n\n if (to == address(0)) {\n // Anyone could claim the funds to the proven relayer on their behalf\n to = proofRelayer;\n } else if (proofRelayer != msg.sender) {\n // Only the proven relayer could specify an address to claim the funds to\n revert SenderIncorrect();\n }\n\n // Update status to RELAYER_CLAIMED and transfer the origin collateral to the specified claim address\n // Note: this is a storage write\n $.status = BridgeStatus.RELAYER_CLAIMED;\n\n address token = request.originToken();\n uint256 amount = request.originAmount();\n // Update protocol fees if origin fee amount exists\n uint256 originFeeAmount = request.originFeeAmount();\n if (originFeeAmount \u003e 0) protocolFees[token] += originFeeAmount;\n // Emit the event before any external calls\n emit BridgeDepositClaimed(transactionId, proofRelayer, to, token, amount);\n // Complete the relayer claim as the last transaction action\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(to), amount);\n } else {\n IERC20(token).safeTransfer(to, amount);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function cancel(bytes calldata request) public {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Can only cancel a REQUESTED transaction after its deadline expires\n if ($.status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n uint256 deadline = request.deadline();\n // Permissionless cancel is only allowed after `cancelDelay` on top of the deadline\n if (!hasRole(CANCELER_ROLE, msg.sender)) deadline += cancelDelay;\n if (block.timestamp \u003c= deadline) revert DeadlineNotExceeded();\n // Update status to REFUNDED and return the full amount (collateral + protocol fees) to the original sender.\n // The protocol fees are only updated when the transaction is claimed, so we don't need to update them here.\n // Note: this is a storage write\n $.status = BridgeStatus.REFUNDED;\n\n address to = request.originSender();\n address token = request.originToken();\n uint256 amount = request.originAmount() + request.originFeeAmount();\n // Emit the event before any external calls\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n // Complete the user cancel as the last transaction action\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(to), amount);\n } else {\n IERC20(token).safeTransfer(to, amount);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeStatuses(bytes32 transactionId) public view returns (BridgeStatus status) {\n return bridgeTxDetails[transactionId].status;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeProofs(bytes32 transactionId) public view returns (uint96 timestamp, address relayer) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n\n timestamp = $.proofBlockTimestamp;\n relayer = $.proofRelayer;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeRelays(bytes32 transactionId) public view returns (bool) {\n // has this transactionId been relayed?\n return bridgeRelayDetails[transactionId].relayer != address(0);\n }\n\n /// @notice Takes the bridged asset from the user into FastBridgeV2 custody. It will be later\n /// claimed by the relayer who completed the relay on destination chain, or transferred back to the user\n /// via the cancel function should no one complete the relay.\n function _takeBridgedUserAsset(address token, uint256 amount) internal returns (uint256 amountTaken) {\n if (token == NATIVE_GAS_TOKEN) {\n // For the native gas token, we just need to check that the supplied msg.value is correct.\n // Supplied `msg.value` is already in FastBridgeV2 custody.\n if (amount != msg.value) revert MsgValueIncorrect();\n amountTaken = msg.value;\n } else {\n // For ERC20s, token is explicitly transferred from the user to FastBridgeV2.\n // We don't allow non-zero `msg.value` to avoid extra funds from being stuck in FastBridgeV2.\n if (msg.value != 0) revert MsgValueIncorrect();\n // Throw an explicit error if the provided token address is not a contract\n if (token.code.length == 0) revert TokenNotContract();\n amountTaken = IERC20(token).balanceOf(address(this));\n IERC20(token).safeTransferFrom(msg.sender, address(this), amount);\n // Use the balance difference as the amount taken in case of fee on transfer tokens.\n amountTaken = IERC20(token).balanceOf(address(this)) - amountTaken;\n }\n }\n\n /// @notice Calls the Recipient's hook function with the specified zapData and performs\n /// all the necessary checks for the returned value.\n function _triggerZapWithChecks(address recipient, address token, uint256 amount, bytes calldata zapData) internal {\n // This will bubble any revert messages from the hook function\n bytes memory returnData = Address.functionCallWithValue({\n target: recipient,\n data: abi.encodeCall(IZapRecipient.zap, (token, amount, zapData)),\n // Note: see `relay()` for reasoning behind passing msg.value\n value: msg.value\n });\n // Explicit revert if no return data at all\n if (returnData.length == 0) revert RecipientNoReturnValue();\n // Check that exactly a single return value was returned\n if (returnData.length != 32) revert RecipientIncorrectReturnValue();\n // Return value should be abi-encoded hook function selector\n if (bytes32(returnData) != bytes32(IZapRecipient.zap.selector)) {\n revert RecipientIncorrectReturnValue();\n }\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint56(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint56).max but\n /// proof.timestamp \u003c type(uint56).max via unchecked statement\n /// @param proofBlockTimestamp The bridge proof block timestamp\n /// @return delta Time delta since proof submitted\n function _timeSince(uint56 proofBlockTimestamp) internal view returns (uint256 delta) {\n unchecked {\n delta = uint56(block.timestamp) - proofBlockTimestamp;\n }\n }\n\n /// @notice Performs all the necessary checks for a bridge to happen.\n /// @dev There's no good way to refactor this function to reduce cyclomatic complexity due to\n /// the number of checks that need to be performed, so we skip the code-complexity rule here.\n // solhint-disable-next-line code-complexity\n function _validateBridgeParams(\n BridgeParams memory params,\n BridgeParamsV2 memory paramsV2,\n int256 exclusivityEndTime\n )\n internal\n view\n {\n // Check V1 (legacy) params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.sender == address(0) || params.to == address(0)) revert ZeroAddress();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n // Check V2 params\n if (paramsV2.zapData.length \u003e MAX_ZAP_DATA_LENGTH) revert ZapDataLengthAboveMax();\n if (paramsV2.zapNative != 0 \u0026\u0026 params.destToken == NATIVE_GAS_TOKEN) {\n revert ZapNativeNotSupported();\n }\n // exclusivityEndTime must be in range [0 .. params.deadline]\n if (exclusivityEndTime \u003c 0 || exclusivityEndTime \u003e int256(params.deadline)) {\n revert ExclusivityParamsIncorrect();\n }\n }\n\n /// @notice Performs all the necessary checks for a relay to happen.\n function _validateRelayParams(bytes calldata request, bytes32 transactionId, address relayer) internal view {\n if (relayer == address(0)) revert ZeroAddress();\n // Check if the transaction has already been relayed\n if (bridgeRelays(transactionId)) revert TransactionRelayed();\n if (request.destChainId() != block.chainid) revert ChainIncorrect();\n // Check the deadline for relay to happen\n if (block.timestamp \u003e request.deadline()) revert DeadlineExceeded();\n // Check the exclusivity period, if it is still ongoing\n address exclRelayer = request.exclusivityRelayer();\n if (exclRelayer != address(0) \u0026\u0026 exclRelayer != relayer \u0026\u0026 block.timestamp \u003c= request.exclusivityEndTime()) {\n revert ExclusivityPeriodNotPassed();\n }\n }\n}\n","language":"Solidity","languageVersion":"0.8.24","compilerVersion":"0.8.24","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"","srcMapRuntime":"","abiDefinition":[{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"relayer","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"BridgeDepositClaimed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"BridgeDepositRefunded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"relayer","type":"address"}],"name":"BridgeProofDisputed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"relayer","type":"address"},{"indexed":false,"internalType":"bytes32","name":"transactionHash","type":"bytes32"}],"name":"BridgeProofProvided","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"relayer","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint32","name":"originChainId","type":"uint32"},{"indexed":false,"internalType":"address","name":"originToken","type":"address"},{"indexed":false,"internalType":"address","name":"destToken","type":"address"},{"indexed":false,"internalType":"uint256","name":"originAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"destAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"chainGasAmount","type":"uint256"}],"name":"BridgeRelayed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"bytes","name":"request","type":"bytes"},{"indexed":false,"internalType":"uint32","name":"destChainId","type":"uint32"},{"indexed":false,"internalType":"address","name":"originToken","type":"address"},{"indexed":false,"internalType":"address","name":"destToken","type":"address"},{"indexed":false,"internalType":"uint256","name":"originAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"destAmount","type":"uint256"},{"indexed":false,"internalType":"bool","name":"sendChainGas","type":"bool"}],"name":"BridgeRequested","type":"event"},{"inputs":[{"components":[{"internalType":"uint32","name":"dstChainId","type":"uint32"},{"internalType":"address","name":"sender","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"address","name":"originToken","type":"address"},{"internalType":"address","name":"destToken","type":"address"},{"internalType":"uint256","name":"originAmount","type":"uint256"},{"internalType":"uint256","name":"destAmount","type":"uint256"},{"internalType":"bool","name":"sendChainGas","type":"bool"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"internalType":"struct IFastBridge.BridgeParams","name":"params","type":"tuple"}],"name":"bridge","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"internalType":"address","name":"relayer","type":"address"}],"name":"canClaim","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"},{"internalType":"address","name":"to","type":"address"}],"name":"claim","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"transactionId","type":"bytes32"}],"name":"dispute","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"}],"name":"getBridgeTransaction","outputs":[{"components":[{"internalType":"uint32","name":"originChainId","type":"uint32"},{"internalType":"uint32","name":"destChainId","type":"uint32"},{"internalType":"address","name":"originSender","type":"address"},{"internalType":"address","name":"destRecipient","type":"address"},{"internalType":"address","name":"originToken","type":"address"},{"internalType":"address","name":"destToken","type":"address"},{"internalType":"uint256","name":"originAmount","type":"uint256"},{"internalType":"uint256","name":"destAmount","type":"uint256"},{"internalType":"uint256","name":"originFeeAmount","type":"uint256"},{"internalType":"bool","name":"sendChainGas","type":"bool"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint256","name":"nonce","type":"uint256"}],"internalType":"struct IFastBridge.BridgeTransaction","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"},{"internalType":"bytes32","name":"destTxHash","type":"bytes32"}],"name":"prove","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"}],"name":"refund","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"}],"name":"relay","outputs":[],"stateMutability":"payable","type":"function"}],"userDoc":{"kind":"user","methods":{"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256))":{"notice":"Initiates bridge on origin chain to be relayed by off-chain relayer"},"canClaim(bytes32,address)":{"notice":"Checks if the dispute period has passed so bridge deposit can be claimed"},"claim(bytes,address)":{"notice":"Completes bridge transaction on origin chain by claiming originally deposited capital"},"dispute(bytes32)":{"notice":"Disputes an outstanding proof in case relayer provided dest chain tx is invalid"},"getBridgeTransaction(bytes)":{"notice":"Decodes bridge request into a bridge transaction"},"prove(bytes,bytes32)":{"notice":"Provides proof on origin side that relayer provided funds on destination side of bridge transaction"},"refund(bytes)":{"notice":"Refunds an outstanding bridge transaction in case optimistic bridging failed"},"relay(bytes)":{"notice":"Relays destination side of bridge transaction by off-chain relayer"}},"version":1},"developerDoc":{"kind":"dev","methods":{"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256))":{"params":{"params":"The parameters required to bridge"}},"canClaim(bytes32,address)":{"params":{"relayer":"The address of the relayer attempting to claim","transactionId":"The transaction id associated with the encoded bridge transaction to check"}},"claim(bytes,address)":{"params":{"request":"The encoded bridge transaction to claim on origin chain","to":"The recipient address of the funds"}},"dispute(bytes32)":{"params":{"transactionId":"The transaction id associated with the encoded bridge transaction to dispute"}},"getBridgeTransaction(bytes)":{"params":{"request":"The bridge request to decode"}},"prove(bytes,bytes32)":{"params":{"destTxHash":"The destination tx hash proving bridge transaction was relayed","request":"The encoded bridge transaction to prove on origin chain"}},"refund(bytes)":{"params":{"request":"The encoded bridge transaction to refund"}},"relay(bytes)":{"params":{"request":"The encoded bridge transaction to relay on destination chain"}}},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"BridgeDepositClaimed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"BridgeDepositRefunded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"name\":\"BridgeProofDisputed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"transactionHash\",\"type\":\"bytes32\"}],\"name\":\"BridgeProofProvided\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"originChainId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"chainGasAmount\",\"type\":\"uint256\"}],\"name\":\"BridgeRelayed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"destChainId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"sendChainGas\",\"type\":\"bool\"}],\"name\":\"BridgeRequested\",\"type\":\"event\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"dstChainId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"sendChainGas\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"}],\"internalType\":\"struct IFastBridge.BridgeParams\",\"name\":\"params\",\"type\":\"tuple\"}],\"name\":\"bridge\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"name\":\"canClaim\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"claim\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"}],\"name\":\"dispute\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"getBridgeTransaction\",\"outputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"originChainId\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"destChainId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"originSender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destRecipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"originFeeAmount\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"sendChainGas\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"}],\"internalType\":\"struct IFastBridge.BridgeTransaction\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"},{\"internalType\":\"bytes32\",\"name\":\"destTxHash\",\"type\":\"bytes32\"}],\"name\":\"prove\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"refund\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"relay\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{\"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256))\":{\"params\":{\"params\":\"The parameters required to bridge\"}},\"canClaim(bytes32,address)\":{\"params\":{\"relayer\":\"The address of the relayer attempting to claim\",\"transactionId\":\"The transaction id associated with the encoded bridge transaction to check\"}},\"claim(bytes,address)\":{\"params\":{\"request\":\"The encoded bridge transaction to claim on origin chain\",\"to\":\"The recipient address of the funds\"}},\"dispute(bytes32)\":{\"params\":{\"transactionId\":\"The transaction id associated with the encoded bridge transaction to dispute\"}},\"getBridgeTransaction(bytes)\":{\"params\":{\"request\":\"The bridge request to decode\"}},\"prove(bytes,bytes32)\":{\"params\":{\"destTxHash\":\"The destination tx hash proving bridge transaction was relayed\",\"request\":\"The encoded bridge transaction to prove on origin chain\"}},\"refund(bytes)\":{\"params\":{\"request\":\"The encoded bridge transaction to refund\"}},\"relay(bytes)\":{\"params\":{\"request\":\"The encoded bridge transaction to relay on destination chain\"}}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256))\":{\"notice\":\"Initiates bridge on origin chain to be relayed by off-chain relayer\"},\"canClaim(bytes32,address)\":{\"notice\":\"Checks if the dispute period has passed so bridge deposit can be claimed\"},\"claim(bytes,address)\":{\"notice\":\"Completes bridge transaction on origin chain by claiming originally deposited capital\"},\"dispute(bytes32)\":{\"notice\":\"Disputes an outstanding proof in case relayer provided dest chain tx is invalid\"},\"getBridgeTransaction(bytes)\":{\"notice\":\"Decodes bridge request into a bridge transaction\"},\"prove(bytes,bytes32)\":{\"notice\":\"Provides proof on origin side that relayer provided funds on destination side of bridge transaction\"},\"refund(bytes)\":{\"notice\":\"Refunds an outstanding bridge transaction in case optimistic bridging failed\"},\"relay(bytes)\":{\"notice\":\"Relays destination side of bridge transaction by off-chain relayer\"}},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeV2.sol\":\"IFastBridge\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeV2.sol\":{\"keccak256\":\"0xac79c463688a682ca706a4ef95e7817b83548cdfa8182ba0426ac7e5e07613d8\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://b3ecb7097381287cafc3a73f3a2bb03565115ebb682a85064e0b0dc2f7e2919d\",\"dweb:/ipfs/QmatruW3nYZTksf3CeQ8wwiAG4c7xoEJBEp6drHPtFLBRK\"]}},\"version\":1}"},"hashes":{"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256))":"45851694","canClaim(bytes32,address)":"aa9641ab","claim(bytes,address)":"41fcb612","dispute(bytes32)":"add98c70","getBridgeTransaction(bytes)":"ac11fb1a","prove(bytes,bytes32)":"886d36ff","refund(bytes)":"5eb7d946","relay(bytes)":"8f0d6f17"}},"solidity/FastBridgeV2.sol:IFastBridgeV2":{"code":"0x","runtime-code":"0x","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.24 ^0.8.20 ^0.8.4;\n\n// contracts/interfaces/IAdminV2.sol\n\ninterface IAdminV2 {\n event CancelDelayUpdated(uint256 oldCancelDelay, uint256 newCancelDelay);\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n function setCancelDelay(uint256 newCancelDelay) external;\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n}\n\n// contracts/interfaces/IAdminV2Errors.sol\n\ninterface IAdminV2Errors {\n error CancelDelayBelowMin();\n error FeeRateAboveMax();\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IFastBridgeV2Errors.sol\n\ninterface IFastBridgeV2Errors {\n error AmountIncorrect();\n error ChainIncorrect();\n error ExclusivityParamsIncorrect();\n error MsgValueIncorrect();\n error SenderIncorrect();\n error StatusIncorrect();\n error TokenNotContract();\n error ZapDataLengthAboveMax();\n error ZapNativeNotSupported();\n error ZeroAddress();\n\n error RecipientIncorrectReturnValue();\n error RecipientNoReturnValue();\n\n error DeadlineExceeded();\n error DeadlineNotExceeded();\n error DeadlineTooShort();\n error DisputePeriodNotPassed();\n error DisputePeriodPassed();\n error ExclusivityPeriodNotPassed();\n\n error TransactionRelayed();\n}\n\n// contracts/interfaces/IMulticallTarget.sol\n\n/// @notice Interface for a contract that can be called multiple times by the same caller. Inspired by MulticallV3:\n/// https://github.com/mds1/multicall/blob/master/src/Multicall3.sol\ninterface IMulticallTarget {\n struct Result {\n bool success;\n bytes returnData;\n }\n\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external;\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results);\n}\n\n// contracts/interfaces/IZapRecipient.sol\n\ninterface IZapRecipient {\n function zap(address token, uint256 amount, bytes memory zapData) external payable returns (bytes4);\n}\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// contracts/interfaces/IFastBridgeV2.sol\n\ninterface IFastBridgeV2 is IFastBridge {\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n struct BridgeTxDetails {\n BridgeStatus status;\n uint32 destChainId;\n uint56 proofBlockTimestamp;\n address proofRelayer;\n }\n\n struct BridgeRelay {\n uint48 blockNumber;\n uint48 blockTimestamp;\n address relayer;\n }\n\n /// @notice New params introduced in the FastBridgeV2.\n /// We are passing fields from the older BridgeParams struct outside of this struct\n /// for backwards compatibility.\n /// Note: quoteRelayer and quoteExclusivitySeconds are either both zero (indicating no exclusivity)\n /// or both non-zero (indicating exclusivity for the given period).\n /// Note: zapNative \u003e 0 can NOT be used with destToken = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE (native token)\n /// @param quoteRelayer Relayer that provided the quote for the transaction\n /// @param quoteExclusivitySeconds Period of time the quote relayer is guaranteed exclusivity after user's deposit\n /// @param quoteId Unique quote identifier used for tracking the quote\n /// @param zapNative ETH value to send to the recipient (if any)\n /// @param zapData Parameters for the Zap to the destination recipient (if any)\n struct BridgeParamsV2 {\n address quoteRelayer;\n int256 quoteExclusivitySeconds;\n bytes quoteId;\n uint256 zapNative;\n bytes zapData;\n }\n\n /// @notice Updated bridge transaction struct to include parameters introduced in FastBridgeV2.\n /// Note: only `exclusivityRelayer` can fill such a transaction until `exclusivityEndTime`.\n struct BridgeTransactionV2 {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n // Note: sendChainGas flag from V1 is deprecated\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n address exclusivityRelayer;\n uint256 exclusivityEndTime;\n uint256 zapNative; // ETH value to send to the recipient (if any)\n bytes zapData; // data to pass for the Zap action (if any)\n }\n\n event BridgeQuoteDetails(bytes32 indexed transactionId, bytes quoteId);\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability\n /// to provide temporary exclusivity fill rights for the quote relayer.\n /// @param params The parameters required to bridge\n /// @param paramsV2 The parameters for exclusivity fill rights (optional, can be left empty)\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function relay(bytes memory request, address relayer) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param transactionId The transaction id associated with the encoded bridge transaction to prove\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital.\n /// @notice Can only send funds to the relayer address on the proof.\n /// @param request The encoded bridge transaction to claim on origin chain\n function claim(bytes memory request) external;\n\n /// @notice Cancels an outstanding bridge transaction in case optimistic bridging failed and returns the full amount\n /// to the original sender.\n /// @param request The encoded bridge transaction to refund\n function cancel(bytes memory request) external;\n\n /// @notice Checks if a transaction has been relayed\n /// @param transactionId The ID of the transaction to check\n /// @return True if the transaction has been relayed, false otherwise\n function bridgeRelays(bytes32 transactionId) external view returns (bool);\n\n /// @notice Returns the status of a bridge transaction\n /// @param transactionId The ID of the bridge transaction\n /// @return BridgeStatus Status of the bridge transaction\n function bridgeStatuses(bytes32 transactionId) external view returns (BridgeStatus);\n\n /// @notice Returns the timestamp and relayer of a bridge proof\n /// @param transactionId The ID of the bridge transaction\n /// @return timestamp The timestamp of the bridge proof\n /// @return relayer The relayer address of the bridge proof\n function bridgeProofs(bytes32 transactionId) external view returns (uint96 timestamp, address relayer);\n\n /// @notice Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\n /// @param request The bridge request to decode\n function getBridgeTransactionV2(bytes memory request) external view returns (BridgeTransactionV2 memory);\n}\n\n// contracts/utils/MulticallTarget.sol\n\n// solhint-disable avoid-low-level-calls\n/// @notice Template for a contract that supports batched calls (preserving the msg.sender).\n/// Only calls with zero msg.value could be batched.\nabstract contract MulticallTarget is IMulticallTarget {\n error MulticallTarget__UndeterminedRevert();\n\n /// @notice Perform a batched call to this contract, preserving the msg.sender.\n /// The return data from each call is discarded.\n /// @dev The method is non-payable, so only calls with `msg.value == 0` could be batched.\n /// It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag.\n /// Otherwise, the whole batch call will be reverted with the original revert reason.\n /// @param data List of abi-encoded calldata for the calls to perform.\n /// @param ignoreReverts Whether to ignore the revert errors from the calls.\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external {\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\n if (!success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(result);\n }\n }\n }\n\n /// @notice Perform a batched call to this contract, preserving the msg.sender.\n /// The return data from each call is preserved.\n /// @dev The method is non-payable, so only calls with `msg.value == 0` could be batched.\n /// It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag.\n /// Otherwise, the whole batch call will be reverted with the original revert reason.\n /// @param data List of abi-encoded calldata for the calls to perform.\n /// @param ignoreReverts Whether to ignore the revert errors from the calls.\n /// @return results List of results from the calls: `(success, returnData)`.\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results)\n {\n results = new Result[](data.length);\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (results[i].success, results[i].returnData) = address(this).delegatecall(data[i]);\n if (!results[i].success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(results[i].returnData);\n }\n }\n }\n\n /// @dev Bubbles the revert message from the underlying call.\n /// Note: preserves the same custom error or revert string, if one was used.\n /// Source: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v5.0.2/contracts/utils/Address.sol#L143-L158\n function _bubbleRevert(bytes memory returnData) internal pure {\n // Look for revert reason and bubble it up if present\n if (returnData.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n // solhint-disable-next-line no-inline-assembly\n assembly {\n let returndata_size := mload(returnData)\n revert(add(32, returnData), returndata_size)\n }\n } else {\n revert MulticallTarget__UndeterminedRevert();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// contracts/libs/BridgeTransactionV2.sol\n\n// solhint-disable no-inline-assembly\nlibrary BridgeTransactionV2Lib {\n uint16 internal constant VERSION = 2;\n\n // Offsets of the fields in the packed BridgeTransactionV2 struct\n // uint16 version [000 .. 002)\n // uint32 originChainId [002 .. 006)\n // uint32 destChainId [006 .. 010)\n // address originSender [010 .. 030)\n // address destRecipient [030 .. 050)\n // address originToken [050 .. 070)\n // address destToken [070 .. 090)\n // uint256 originAmount [090 .. 122)\n // uint256 destAmount [122 .. 154)\n // uint256 originFeeAmount [154 .. 186)\n // uint256 deadline [186 .. 218)\n // uint256 nonce [218 .. 250)\n // address exclusivityRelayer [250 .. 270)\n // uint256 exclusivityEndTime [270 .. 302)\n // uint256 zapNative [302 .. 334)\n // bytes zapData [334 .. ***)\n\n // forgefmt: disable-start\n uint256 private constant OFFSET_ORIGIN_CHAIN_ID = 2;\n uint256 private constant OFFSET_DEST_CHAIN_ID = 6;\n uint256 private constant OFFSET_ORIGIN_SENDER = 10;\n uint256 private constant OFFSET_DEST_RECIPIENT = 30;\n uint256 private constant OFFSET_ORIGIN_TOKEN = 50;\n uint256 private constant OFFSET_DEST_TOKEN = 70;\n uint256 private constant OFFSET_ORIGIN_AMOUNT = 90;\n uint256 private constant OFFSET_DEST_AMOUNT = 122;\n uint256 private constant OFFSET_ORIGIN_FEE_AMOUNT = 154;\n uint256 private constant OFFSET_DEADLINE = 186;\n uint256 private constant OFFSET_NONCE = 218;\n uint256 private constant OFFSET_EXCLUSIVITY_RELAYER = 250;\n uint256 private constant OFFSET_EXCLUSIVITY_END_TIME = 270;\n uint256 private constant OFFSET_ZAP_NATIVE = 302;\n uint256 private constant OFFSET_ZAP_DATA = 334;\n // forgefmt: disable-end\n\n error BridgeTransactionV2__InvalidEncodedTx();\n error BridgeTransactionV2__UnsupportedVersion(uint16 version);\n\n /// @notice Validates the encoded transaction to be a tightly packed encoded payload for BridgeTransactionV2.\n /// @dev Checks the minimum length and the version, use this function before decoding any of the fields.\n function validateV2(bytes calldata encodedTx) internal pure {\n // Check the minimum length: must at least include all static fields.\n if (encodedTx.length \u003c OFFSET_ZAP_DATA) revert BridgeTransactionV2__InvalidEncodedTx();\n // Once we validated the length, we can be sure that the version field is present.\n uint16 version_ = version(encodedTx);\n if (version_ != VERSION) revert BridgeTransactionV2__UnsupportedVersion(version_);\n }\n\n /// @notice Encodes the BridgeTransactionV2 struct by tightly packing the fields.\n /// @dev `abi.decode` will not work as a result of the tightly packed fields. Use `decodeV2` to decode instead.\n function encodeV2(IFastBridgeV2.BridgeTransactionV2 memory bridgeTx) internal pure returns (bytes memory) {\n // We split the encoding into two parts to avoid stack-too-deep error\n bytes memory firstPart = abi.encodePacked(\n VERSION,\n bridgeTx.originChainId,\n bridgeTx.destChainId,\n bridgeTx.originSender,\n bridgeTx.destRecipient,\n bridgeTx.originToken,\n bridgeTx.destToken,\n bridgeTx.originAmount\n );\n return abi.encodePacked(\n firstPart,\n bridgeTx.destAmount,\n bridgeTx.originFeeAmount,\n // Note: we skip the deprecated `sendChainGas` flag, which was present in BridgeTransaction V1\n bridgeTx.deadline,\n bridgeTx.nonce,\n // New V2 fields: exclusivity\n bridgeTx.exclusivityRelayer,\n bridgeTx.exclusivityEndTime,\n // New V2 fields: Zap\n bridgeTx.zapNative,\n bridgeTx.zapData\n );\n }\n\n /// @notice Decodes the BridgeTransactionV2 struct from the encoded transaction.\n /// @dev Encoded BridgeTransactionV2 struct must be tightly packed.\n /// Use `validateV2` before decoding to ensure the encoded transaction is valid.\n function decodeV2(bytes calldata encodedTx)\n internal\n pure\n returns (IFastBridgeV2.BridgeTransactionV2 memory bridgeTx)\n {\n bridgeTx.originChainId = originChainId(encodedTx);\n bridgeTx.destChainId = destChainId(encodedTx);\n bridgeTx.originSender = originSender(encodedTx);\n bridgeTx.destRecipient = destRecipient(encodedTx);\n bridgeTx.originToken = originToken(encodedTx);\n bridgeTx.destToken = destToken(encodedTx);\n bridgeTx.originAmount = originAmount(encodedTx);\n bridgeTx.destAmount = destAmount(encodedTx);\n bridgeTx.originFeeAmount = originFeeAmount(encodedTx);\n bridgeTx.deadline = deadline(encodedTx);\n bridgeTx.nonce = nonce(encodedTx);\n bridgeTx.exclusivityRelayer = exclusivityRelayer(encodedTx);\n bridgeTx.exclusivityEndTime = exclusivityEndTime(encodedTx);\n bridgeTx.zapNative = zapNative(encodedTx);\n bridgeTx.zapData = zapData(encodedTx);\n }\n\n /// @notice Extracts the version from the encoded transaction.\n function version(bytes calldata encodedTx) internal pure returns (uint16 version_) {\n // Load 32 bytes from the start and shift it 240 bits to the right to get the highest 16 bits.\n assembly {\n version_ := shr(240, calldataload(encodedTx.offset))\n }\n }\n\n /// @notice Extracts the origin chain ID from the encoded transaction.\n function originChainId(bytes calldata encodedTx) internal pure returns (uint32 originChainId_) {\n // Load 32 bytes from the offset and shift it 224 bits to the right to get the highest 32 bits.\n assembly {\n originChainId_ := shr(224, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_CHAIN_ID)))\n }\n }\n\n /// @notice Extracts the destination chain ID from the encoded transaction.\n function destChainId(bytes calldata encodedTx) internal pure returns (uint32 destChainId_) {\n // Load 32 bytes from the offset and shift it 224 bits to the right to get the highest 32 bits.\n assembly {\n destChainId_ := shr(224, calldataload(add(encodedTx.offset, OFFSET_DEST_CHAIN_ID)))\n }\n }\n\n /// @notice Extracts the origin sender from the encoded transaction.\n function originSender(bytes calldata encodedTx) internal pure returns (address originSender_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n originSender_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_SENDER)))\n }\n }\n\n /// @notice Extracts the destination recipient from the encoded transaction.\n function destRecipient(bytes calldata encodedTx) internal pure returns (address destRecipient_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n destRecipient_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_DEST_RECIPIENT)))\n }\n }\n\n /// @notice Extracts the origin token from the encoded transaction.\n function originToken(bytes calldata encodedTx) internal pure returns (address originToken_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n originToken_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_TOKEN)))\n }\n }\n\n /// @notice Extracts the destination token from the encoded transaction.\n function destToken(bytes calldata encodedTx) internal pure returns (address destToken_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n destToken_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_DEST_TOKEN)))\n }\n }\n\n /// @notice Extracts the origin amount from the encoded transaction.\n function originAmount(bytes calldata encodedTx) internal pure returns (uint256 originAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n originAmount_ := calldataload(add(encodedTx.offset, OFFSET_ORIGIN_AMOUNT))\n }\n }\n\n /// @notice Extracts the destination amount from the encoded transaction.\n function destAmount(bytes calldata encodedTx) internal pure returns (uint256 destAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n destAmount_ := calldataload(add(encodedTx.offset, OFFSET_DEST_AMOUNT))\n }\n }\n\n /// @notice Extracts the origin fee amount from the encoded transaction.\n function originFeeAmount(bytes calldata encodedTx) internal pure returns (uint256 originFeeAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n originFeeAmount_ := calldataload(add(encodedTx.offset, OFFSET_ORIGIN_FEE_AMOUNT))\n }\n }\n\n /// @notice Extracts the deadline from the encoded transaction.\n function deadline(bytes calldata encodedTx) internal pure returns (uint256 deadline_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n deadline_ := calldataload(add(encodedTx.offset, OFFSET_DEADLINE))\n }\n }\n\n /// @notice Extracts the nonce from the encoded transaction.\n function nonce(bytes calldata encodedTx) internal pure returns (uint256 nonce_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n nonce_ := calldataload(add(encodedTx.offset, OFFSET_NONCE))\n }\n }\n\n /// @notice Extracts the exclusivity relayer from the encoded transaction.\n function exclusivityRelayer(bytes calldata encodedTx) internal pure returns (address exclusivityRelayer_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n exclusivityRelayer_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_EXCLUSIVITY_RELAYER)))\n }\n }\n\n /// @notice Extracts the exclusivity end time from the encoded transaction.\n function exclusivityEndTime(bytes calldata encodedTx) internal pure returns (uint256 exclusivityEndTime_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n exclusivityEndTime_ := calldataload(add(encodedTx.offset, OFFSET_EXCLUSIVITY_END_TIME))\n }\n }\n\n /// @notice Extracts the Zap's native value from the encoded transaction.\n function zapNative(bytes calldata encodedTx) internal pure returns (uint256 zapNative_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n zapNative_ := calldataload(add(encodedTx.offset, OFFSET_ZAP_NATIVE))\n }\n }\n\n /// @notice Extracts the Zap's data from the encoded transaction.\n function zapData(bytes calldata encodedTx) internal pure returns (bytes calldata zapData_) {\n zapData_ = encodedTx[OFFSET_ZAP_DATA:];\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/AdminV2.sol\n\ncontract AdminV2 is AccessControlEnumerable, IAdminV2, IAdminV2Errors {\n using SafeERC20 for IERC20;\n\n /// @notice Address reserved for native gas token (ETH on Ethereum and most L2s, AVAX on Avalanche, etc)\n address public constant NATIVE_GAS_TOKEN = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Role identifier for Quoter API's off-chain authentication.\n /// @dev Only addresses with this role can post FastBridge quotes to the API.\n bytes32 public constant QUOTER_ROLE = keccak256(\"QUOTER_ROLE\");\n\n /// @notice Role identifier for Prover's on-chain authentication in FastBridge.\n /// @dev Only addresses with this role can provide proofs that a FastBridge request has been relayed.\n bytes32 public constant PROVER_ROLE = keccak256(\"PROVER_ROLE\");\n\n /// @notice Role identifier for Guard's on-chain authentication in FastBridge.\n /// @dev Only addresses with this role can dispute submitted relay proofs during the dispute period.\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n\n /// @notice Role identifier for Canceler's on-chain authentication in FastBridge.\n /// @dev Only addresses with this role can cancel a FastBridge transaction without the cancel delay.\n bytes32 public constant CANCELER_ROLE = keccak256(\"CANCELER_ROLE\");\n\n /// @notice Role identifier for Governor's on-chain administrative authority.\n /// @dev Only addresses with this role can perform administrative tasks within the contract.\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n /// @notice Denominator for fee rates, represents 100%.\n uint256 public constant FEE_BPS = 1e6;\n /// @notice Maximum protocol fee rate: 1% on origin amount.\n uint256 public constant FEE_RATE_MAX = 0.01e6;\n\n /// @notice Minimum cancel delay that can be set by the governor.\n uint256 public constant MIN_CANCEL_DELAY = 1 hours;\n /// @notice Default cancel delay set during the contract deployment.\n uint256 public constant DEFAULT_CANCEL_DELAY = 1 days;\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Delay for a transaction after which it could be permisionlessly cancelled\n uint256 public cancelDelay;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Use ZapNative V2 requests instead.\n uint256 public immutable chainGasAmount = 0;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n _setCancelDelay(DEFAULT_CANCEL_DELAY);\n }\n\n /// @notice Allows the contract governor to set the cancel delay. The cancel delay is the time after the transaction\n /// deadline after which it can be permissionlessly cancelled, if it hasn't been proven by any of the Relayers.\n function setCancelDelay(uint256 newCancelDelay) external onlyRole(GOVERNOR_ROLE) {\n _setCancelDelay(newCancelDelay);\n }\n\n /// @notice Allows the contract governor to set the protocol fee rate. The protocol fee is taken from the origin\n /// amount only for completed and claimed transactions.\n /// @dev The protocol fee is abstracted away from the relayers, they always operate using the amounts after fees:\n /// what they see as the origin amount emitted in the log is what they get credited with.\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n if (newFeeRate \u003e FEE_RATE_MAX) revert FeeRateAboveMax();\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n /// @notice Allows the contract governor to sweep the accumulated protocol fees in the contract.\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n emit FeesSwept(token, recipient, feeAmount);\n /// Sweep the fees as the last transaction action\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(recipient), feeAmount);\n } else {\n IERC20(token).safeTransfer(recipient, feeAmount);\n }\n }\n\n /// @notice Internal function to set the cancel delay. Security checks are performed outside of this function.\n function _setCancelDelay(uint256 newCancelDelay) private {\n if (newCancelDelay \u003c MIN_CANCEL_DELAY) revert CancelDelayBelowMin();\n uint256 oldCancelDelay = cancelDelay;\n cancelDelay = newCancelDelay;\n emit CancelDelayUpdated(oldCancelDelay, newCancelDelay);\n }\n}\n\n// contracts/FastBridgeV2.sol\n\n/// @notice FastBridgeV2 is a contract for bridging tokens across chains.\ncontract FastBridgeV2 is AdminV2, MulticallTarget, IFastBridgeV2, IFastBridgeV2Errors {\n using BridgeTransactionV2Lib for bytes;\n using SafeERC20 for IERC20;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n /// @notice Maximum length of accepted zapData\n uint256 public constant MAX_ZAP_DATA_LENGTH = 2 ** 16 - 1;\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeTxDetails) public bridgeTxDetails;\n /// @notice Relay details on destination chain\n mapping(bytes32 =\u003e BridgeRelay) public bridgeRelayDetails;\n /// @notice Unique bridge nonces tracked per originSender\n mapping(address =\u003e uint256) public senderNonces;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Replaced by senderNonces\n uint256 public immutable nonce = 0;\n /// @notice the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) AdminV2(_owner) {\n deployBlock = block.number;\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n bridge({\n params: params,\n paramsV2: BridgeParamsV2({\n quoteRelayer: address(0),\n quoteExclusivitySeconds: 0,\n quoteId: bytes(\"\"),\n zapNative: 0,\n zapData: bytes(\"\")\n })\n });\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes calldata request) external payable {\n // relay override will validate the request\n relay({request: request, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes calldata request, bytes32 destTxHash) external {\n request.validateV2();\n prove({transactionId: keccak256(request), destTxHash: destTxHash, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridgeV2\n function claim(bytes calldata request) external {\n // claim override will validate the request\n claim({request: request, to: address(0)});\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Aggregate the read operations from the same storage slot\n address disputedRelayer = $.proofRelayer;\n BridgeStatus status = $.status;\n uint56 proofBlockTimestamp = $.proofBlockTimestamp;\n // Can only dispute a RELAYER_PROVED transaction within the dispute period\n if (status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(proofBlockTimestamp) \u003e DISPUTE_PERIOD) {\n revert DisputePeriodPassed();\n }\n // Update status to REQUESTED and delete the disputed proof details\n // Note: these are storage writes\n $.status = BridgeStatus.REQUESTED;\n $.proofRelayer = address(0);\n $.proofBlockTimestamp = 0;\n\n emit BridgeProofDisputed(transactionId, disputedRelayer);\n }\n\n /// Note: this function is deprecated and will be removed in a future version.\n /// @inheritdoc IFastBridge\n function refund(bytes calldata request) external {\n cancel(request);\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // The correct relayer can only claim a RELAYER_PROVED transaction after the dispute period\n if ($.status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if ($.proofRelayer != relayer) revert SenderIncorrect();\n return _timeSince($.proofBlockTimestamp) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n /// @dev This method is added to achieve backwards compatibility with decoding requests into V1 structs:\n /// - `zapNative` is partially reported as a zero/non-zero flag\n /// - `zapData` is ignored\n /// In order to process all kinds of requests use getBridgeTransactionV2 instead.\n function getBridgeTransaction(bytes calldata request) external view returns (BridgeTransaction memory) {\n // Try decoding into V2 struct first. This will revert if V1 struct is passed\n try this.getBridgeTransactionV2(request) returns (BridgeTransactionV2 memory txV2) {\n // Note: we entirely ignore the zapData field, as it was not present in V1\n return BridgeTransaction({\n originChainId: txV2.originChainId,\n destChainId: txV2.destChainId,\n originSender: txV2.originSender,\n destRecipient: txV2.destRecipient,\n originToken: txV2.originToken,\n destToken: txV2.destToken,\n originAmount: txV2.originAmount,\n destAmount: txV2.destAmount,\n originFeeAmount: txV2.originFeeAmount,\n sendChainGas: txV2.zapNative != 0,\n deadline: txV2.deadline,\n nonce: txV2.nonce\n });\n } catch {\n // Fallback to V1 struct\n return abi.decode(request, (BridgeTransaction));\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function getBridgeTransactionV2(bytes calldata request) external pure returns (BridgeTransactionV2 memory) {\n request.validateV2();\n return BridgeTransactionV2Lib.decodeV2(request);\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) public payable {\n int256 exclusivityEndTime = 0;\n // if relayer exclusivity is not intended for this bridge, set exclusivityEndTime to static zero\n // otherwise, set exclusivity to expire at the current block ts offset by quoteExclusivitySeconds\n if (paramsV2.quoteRelayer != address(0)) {\n exclusivityEndTime = int256(block.timestamp) + paramsV2.quoteExclusivitySeconds;\n }\n _validateBridgeParams(params, paramsV2, exclusivityEndTime);\n\n // transfer tokens to bridge contract\n /// @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _takeBridgedUserAsset(params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) {\n originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n }\n\n // set status to requested\n bytes memory request = BridgeTransactionV2Lib.encodeV2(\n BridgeTransactionV2({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n deadline: params.deadline,\n nonce: senderNonces[params.sender]++, // increment nonce on every bridge\n exclusivityRelayer: paramsV2.quoteRelayer,\n // We checked exclusivityEndTime to be in range [0 .. params.deadline] above, so can safely cast\n exclusivityEndTime: uint256(exclusivityEndTime),\n zapNative: paramsV2.zapNative,\n zapData: paramsV2.zapData\n })\n );\n bytes32 transactionId = keccak256(request);\n // Note: the tx status will be updated throughout the tx lifecycle, while destChainId is set once here\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n bridgeTxDetails[transactionId].destChainId = params.dstChainId;\n\n emit BridgeRequested({\n transactionId: transactionId,\n sender: params.sender,\n request: request,\n destChainId: params.dstChainId,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n sendChainGas: paramsV2.zapNative != 0\n });\n emit BridgeQuoteDetails(transactionId, paramsV2.quoteId);\n }\n\n /// @inheritdoc IFastBridgeV2\n function relay(bytes calldata request, address relayer) public payable {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n _validateRelayParams(request, transactionId, relayer);\n // mark bridge transaction as relayed\n bridgeRelayDetails[transactionId] =\n BridgeRelay({blockNumber: uint48(block.number), blockTimestamp: uint48(block.timestamp), relayer: relayer});\n\n // transfer tokens to recipient on destination chain and trigger Zap if requested\n address to = request.destRecipient();\n address token = request.destToken();\n uint256 amount = request.destAmount();\n uint256 zapNative = request.zapNative();\n\n // Emit the event before any external calls\n emit BridgeRelayed({\n transactionId: transactionId,\n relayer: relayer,\n to: to,\n originChainId: request.originChainId(),\n originToken: request.originToken(),\n destToken: token,\n originAmount: request.originAmount(),\n destAmount: amount,\n chainGasAmount: zapNative\n });\n\n // All state changes have been done at this point, can proceed to the external calls.\n // This follows the checks-effects-interactions pattern to mitigate potential reentrancy attacks.\n if (token == NATIVE_GAS_TOKEN) {\n // For the native gas token, additional zapNative is not allowed\n if (zapNative != 0) revert ZapNativeNotSupported();\n // Check that the correct msg.value was sent\n if (msg.value != amount) revert MsgValueIncorrect();\n // Don't do a native transfer yet: we will handle it alongside the Zap below\n } else {\n // For ERC20s, we check that the correct msg.value was sent\n if (msg.value != zapNative) revert MsgValueIncorrect();\n // We need to transfer the tokens from the Relayer to the recipient first before performing an\n // optional post-transfer Zap.\n IERC20(token).safeTransferFrom(msg.sender, to, amount);\n }\n // At this point we have done:\n // - Transferred the requested amount of ERC20 tokens to the recipient.\n // At this point we have confirmed:\n // - For ERC20s: msg.value matches the requested zapNative amount.\n // - For the native gas token: msg.value matches the requested destAmount.\n // Remaining optional things to do:\n // - Forward the full msg.value to the recipient (if non-zero).\n // - Trigger a Zap (if zapData is present).\n bytes calldata zapData = request.zapData();\n if (zapData.length != 0) {\n // Zap Data is present: Zap has been requested by the recipient. Trigger it forwarding the full msg.value.\n\n // Note: if token has a fee on transfers, the recipient will have received less than `amount`.\n // This is a very niche edge case and should be handled by the recipient contract.\n _triggerZapWithChecks({recipient: to, token: token, amount: amount, zapData: zapData});\n } else if (msg.value != 0) {\n // Zap Data is missing, but msg.value was sent. This could happen in two different cases:\n // - Relay with the native gas token is happening.\n // - Relay with ERC20 is happening, with a `zapNative \u003e 0` request.\n // In both cases, we need to transfer the full msg.value to the recipient.\n Address.sendValue(payable(to), msg.value);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) public onlyRole(PROVER_ROLE) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n\n // Can only prove a REQUESTED transaction\n if ($.status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n // Update status to RELAYER_PROVED and store the proof details\n // Note: these are storage writes\n $.status = BridgeStatus.RELAYER_PROVED;\n $.proofBlockTimestamp = uint56(block.timestamp);\n $.proofRelayer = relayer;\n\n emit BridgeProofProvided(transactionId, relayer, destTxHash);\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes calldata request, address to) public {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Aggregate the read operations from the same storage slot\n address proofRelayer = $.proofRelayer;\n BridgeStatus status = $.status;\n uint56 proofBlockTimestamp = $.proofBlockTimestamp;\n\n // Can only claim a RELAYER_PROVED transaction after the dispute period\n if (status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(proofBlockTimestamp) \u003c= DISPUTE_PERIOD) {\n revert DisputePeriodNotPassed();\n }\n\n if (to == address(0)) {\n // Anyone could claim the funds to the proven relayer on their behalf\n to = proofRelayer;\n } else if (proofRelayer != msg.sender) {\n // Only the proven relayer could specify an address to claim the funds to\n revert SenderIncorrect();\n }\n\n // Update status to RELAYER_CLAIMED and transfer the origin collateral to the specified claim address\n // Note: this is a storage write\n $.status = BridgeStatus.RELAYER_CLAIMED;\n\n address token = request.originToken();\n uint256 amount = request.originAmount();\n // Update protocol fees if origin fee amount exists\n uint256 originFeeAmount = request.originFeeAmount();\n if (originFeeAmount \u003e 0) protocolFees[token] += originFeeAmount;\n // Emit the event before any external calls\n emit BridgeDepositClaimed(transactionId, proofRelayer, to, token, amount);\n // Complete the relayer claim as the last transaction action\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(to), amount);\n } else {\n IERC20(token).safeTransfer(to, amount);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function cancel(bytes calldata request) public {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Can only cancel a REQUESTED transaction after its deadline expires\n if ($.status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n uint256 deadline = request.deadline();\n // Permissionless cancel is only allowed after `cancelDelay` on top of the deadline\n if (!hasRole(CANCELER_ROLE, msg.sender)) deadline += cancelDelay;\n if (block.timestamp \u003c= deadline) revert DeadlineNotExceeded();\n // Update status to REFUNDED and return the full amount (collateral + protocol fees) to the original sender.\n // The protocol fees are only updated when the transaction is claimed, so we don't need to update them here.\n // Note: this is a storage write\n $.status = BridgeStatus.REFUNDED;\n\n address to = request.originSender();\n address token = request.originToken();\n uint256 amount = request.originAmount() + request.originFeeAmount();\n // Emit the event before any external calls\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n // Complete the user cancel as the last transaction action\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(to), amount);\n } else {\n IERC20(token).safeTransfer(to, amount);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeStatuses(bytes32 transactionId) public view returns (BridgeStatus status) {\n return bridgeTxDetails[transactionId].status;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeProofs(bytes32 transactionId) public view returns (uint96 timestamp, address relayer) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n\n timestamp = $.proofBlockTimestamp;\n relayer = $.proofRelayer;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeRelays(bytes32 transactionId) public view returns (bool) {\n // has this transactionId been relayed?\n return bridgeRelayDetails[transactionId].relayer != address(0);\n }\n\n /// @notice Takes the bridged asset from the user into FastBridgeV2 custody. It will be later\n /// claimed by the relayer who completed the relay on destination chain, or transferred back to the user\n /// via the cancel function should no one complete the relay.\n function _takeBridgedUserAsset(address token, uint256 amount) internal returns (uint256 amountTaken) {\n if (token == NATIVE_GAS_TOKEN) {\n // For the native gas token, we just need to check that the supplied msg.value is correct.\n // Supplied `msg.value` is already in FastBridgeV2 custody.\n if (amount != msg.value) revert MsgValueIncorrect();\n amountTaken = msg.value;\n } else {\n // For ERC20s, token is explicitly transferred from the user to FastBridgeV2.\n // We don't allow non-zero `msg.value` to avoid extra funds from being stuck in FastBridgeV2.\n if (msg.value != 0) revert MsgValueIncorrect();\n // Throw an explicit error if the provided token address is not a contract\n if (token.code.length == 0) revert TokenNotContract();\n amountTaken = IERC20(token).balanceOf(address(this));\n IERC20(token).safeTransferFrom(msg.sender, address(this), amount);\n // Use the balance difference as the amount taken in case of fee on transfer tokens.\n amountTaken = IERC20(token).balanceOf(address(this)) - amountTaken;\n }\n }\n\n /// @notice Calls the Recipient's hook function with the specified zapData and performs\n /// all the necessary checks for the returned value.\n function _triggerZapWithChecks(address recipient, address token, uint256 amount, bytes calldata zapData) internal {\n // This will bubble any revert messages from the hook function\n bytes memory returnData = Address.functionCallWithValue({\n target: recipient,\n data: abi.encodeCall(IZapRecipient.zap, (token, amount, zapData)),\n // Note: see `relay()` for reasoning behind passing msg.value\n value: msg.value\n });\n // Explicit revert if no return data at all\n if (returnData.length == 0) revert RecipientNoReturnValue();\n // Check that exactly a single return value was returned\n if (returnData.length != 32) revert RecipientIncorrectReturnValue();\n // Return value should be abi-encoded hook function selector\n if (bytes32(returnData) != bytes32(IZapRecipient.zap.selector)) {\n revert RecipientIncorrectReturnValue();\n }\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint56(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint56).max but\n /// proof.timestamp \u003c type(uint56).max via unchecked statement\n /// @param proofBlockTimestamp The bridge proof block timestamp\n /// @return delta Time delta since proof submitted\n function _timeSince(uint56 proofBlockTimestamp) internal view returns (uint256 delta) {\n unchecked {\n delta = uint56(block.timestamp) - proofBlockTimestamp;\n }\n }\n\n /// @notice Performs all the necessary checks for a bridge to happen.\n /// @dev There's no good way to refactor this function to reduce cyclomatic complexity due to\n /// the number of checks that need to be performed, so we skip the code-complexity rule here.\n // solhint-disable-next-line code-complexity\n function _validateBridgeParams(\n BridgeParams memory params,\n BridgeParamsV2 memory paramsV2,\n int256 exclusivityEndTime\n )\n internal\n view\n {\n // Check V1 (legacy) params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.sender == address(0) || params.to == address(0)) revert ZeroAddress();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n // Check V2 params\n if (paramsV2.zapData.length \u003e MAX_ZAP_DATA_LENGTH) revert ZapDataLengthAboveMax();\n if (paramsV2.zapNative != 0 \u0026\u0026 params.destToken == NATIVE_GAS_TOKEN) {\n revert ZapNativeNotSupported();\n }\n // exclusivityEndTime must be in range [0 .. params.deadline]\n if (exclusivityEndTime \u003c 0 || exclusivityEndTime \u003e int256(params.deadline)) {\n revert ExclusivityParamsIncorrect();\n }\n }\n\n /// @notice Performs all the necessary checks for a relay to happen.\n function _validateRelayParams(bytes calldata request, bytes32 transactionId, address relayer) internal view {\n if (relayer == address(0)) revert ZeroAddress();\n // Check if the transaction has already been relayed\n if (bridgeRelays(transactionId)) revert TransactionRelayed();\n if (request.destChainId() != block.chainid) revert ChainIncorrect();\n // Check the deadline for relay to happen\n if (block.timestamp \u003e request.deadline()) revert DeadlineExceeded();\n // Check the exclusivity period, if it is still ongoing\n address exclRelayer = request.exclusivityRelayer();\n if (exclRelayer != address(0) \u0026\u0026 exclRelayer != relayer \u0026\u0026 block.timestamp \u003c= request.exclusivityEndTime()) {\n revert ExclusivityPeriodNotPassed();\n }\n }\n}\n","language":"Solidity","languageVersion":"0.8.24","compilerVersion":"0.8.24","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"","srcMapRuntime":"","abiDefinition":[{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"relayer","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"BridgeDepositClaimed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"BridgeDepositRefunded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"relayer","type":"address"}],"name":"BridgeProofDisputed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"relayer","type":"address"},{"indexed":false,"internalType":"bytes32","name":"transactionHash","type":"bytes32"}],"name":"BridgeProofProvided","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":false,"internalType":"bytes","name":"quoteId","type":"bytes"}],"name":"BridgeQuoteDetails","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"relayer","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint32","name":"originChainId","type":"uint32"},{"indexed":false,"internalType":"address","name":"originToken","type":"address"},{"indexed":false,"internalType":"address","name":"destToken","type":"address"},{"indexed":false,"internalType":"uint256","name":"originAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"destAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"chainGasAmount","type":"uint256"}],"name":"BridgeRelayed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"bytes","name":"request","type":"bytes"},{"indexed":false,"internalType":"uint32","name":"destChainId","type":"uint32"},{"indexed":false,"internalType":"address","name":"originToken","type":"address"},{"indexed":false,"internalType":"address","name":"destToken","type":"address"},{"indexed":false,"internalType":"uint256","name":"originAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"destAmount","type":"uint256"},{"indexed":false,"internalType":"bool","name":"sendChainGas","type":"bool"}],"name":"BridgeRequested","type":"event"},{"inputs":[{"components":[{"internalType":"uint32","name":"dstChainId","type":"uint32"},{"internalType":"address","name":"sender","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"address","name":"originToken","type":"address"},{"internalType":"address","name":"destToken","type":"address"},{"internalType":"uint256","name":"originAmount","type":"uint256"},{"internalType":"uint256","name":"destAmount","type":"uint256"},{"internalType":"bool","name":"sendChainGas","type":"bool"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"internalType":"struct IFastBridge.BridgeParams","name":"params","type":"tuple"}],"name":"bridge","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"uint32","name":"dstChainId","type":"uint32"},{"internalType":"address","name":"sender","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"address","name":"originToken","type":"address"},{"internalType":"address","name":"destToken","type":"address"},{"internalType":"uint256","name":"originAmount","type":"uint256"},{"internalType":"uint256","name":"destAmount","type":"uint256"},{"internalType":"bool","name":"sendChainGas","type":"bool"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"internalType":"struct IFastBridge.BridgeParams","name":"params","type":"tuple"},{"components":[{"internalType":"address","name":"quoteRelayer","type":"address"},{"internalType":"int256","name":"quoteExclusivitySeconds","type":"int256"},{"internalType":"bytes","name":"quoteId","type":"bytes"},{"internalType":"uint256","name":"zapNative","type":"uint256"},{"internalType":"bytes","name":"zapData","type":"bytes"}],"internalType":"struct IFastBridgeV2.BridgeParamsV2","name":"paramsV2","type":"tuple"}],"name":"bridge","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"transactionId","type":"bytes32"}],"name":"bridgeProofs","outputs":[{"internalType":"uint96","name":"timestamp","type":"uint96"},{"internalType":"address","name":"relayer","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"transactionId","type":"bytes32"}],"name":"bridgeRelays","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"transactionId","type":"bytes32"}],"name":"bridgeStatuses","outputs":[{"internalType":"enum IFastBridgeV2.BridgeStatus","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"internalType":"address","name":"relayer","type":"address"}],"name":"canClaim","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"}],"name":"cancel","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"},{"internalType":"address","name":"to","type":"address"}],"name":"claim","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"}],"name":"claim","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"transactionId","type":"bytes32"}],"name":"dispute","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"}],"name":"getBridgeTransaction","outputs":[{"components":[{"internalType":"uint32","name":"originChainId","type":"uint32"},{"internalType":"uint32","name":"destChainId","type":"uint32"},{"internalType":"address","name":"originSender","type":"address"},{"internalType":"address","name":"destRecipient","type":"address"},{"internalType":"address","name":"originToken","type":"address"},{"internalType":"address","name":"destToken","type":"address"},{"internalType":"uint256","name":"originAmount","type":"uint256"},{"internalType":"uint256","name":"destAmount","type":"uint256"},{"internalType":"uint256","name":"originFeeAmount","type":"uint256"},{"internalType":"bool","name":"sendChainGas","type":"bool"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint256","name":"nonce","type":"uint256"}],"internalType":"struct IFastBridge.BridgeTransaction","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"}],"name":"getBridgeTransactionV2","outputs":[{"components":[{"internalType":"uint32","name":"originChainId","type":"uint32"},{"internalType":"uint32","name":"destChainId","type":"uint32"},{"internalType":"address","name":"originSender","type":"address"},{"internalType":"address","name":"destRecipient","type":"address"},{"internalType":"address","name":"originToken","type":"address"},{"internalType":"address","name":"destToken","type":"address"},{"internalType":"uint256","name":"originAmount","type":"uint256"},{"internalType":"uint256","name":"destAmount","type":"uint256"},{"internalType":"uint256","name":"originFeeAmount","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"address","name":"exclusivityRelayer","type":"address"},{"internalType":"uint256","name":"exclusivityEndTime","type":"uint256"},{"internalType":"uint256","name":"zapNative","type":"uint256"},{"internalType":"bytes","name":"zapData","type":"bytes"}],"internalType":"struct IFastBridgeV2.BridgeTransactionV2","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"internalType":"bytes32","name":"destTxHash","type":"bytes32"},{"internalType":"address","name":"relayer","type":"address"}],"name":"prove","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"},{"internalType":"bytes32","name":"destTxHash","type":"bytes32"}],"name":"prove","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"}],"name":"refund","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"}],"name":"relay","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"},{"internalType":"address","name":"relayer","type":"address"}],"name":"relay","outputs":[],"stateMutability":"payable","type":"function"}],"userDoc":{"kind":"user","methods":{"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256))":{"notice":"Initiates bridge on origin chain to be relayed by off-chain relayer"},"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256),(address,int256,bytes,uint256,bytes))":{"notice":"Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability to provide temporary exclusivity fill rights for the quote relayer."},"bridgeProofs(bytes32)":{"notice":"Returns the timestamp and relayer of a bridge proof"},"bridgeRelays(bytes32)":{"notice":"Checks if a transaction has been relayed"},"bridgeStatuses(bytes32)":{"notice":"Returns the status of a bridge transaction"},"canClaim(bytes32,address)":{"notice":"Checks if the dispute period has passed so bridge deposit can be claimed"},"cancel(bytes)":{"notice":"Cancels an outstanding bridge transaction in case optimistic bridging failed and returns the full amount to the original sender."},"claim(bytes)":{"notice":"Completes bridge transaction on origin chain by claiming originally deposited capital.Can only send funds to the relayer address on the proof."},"claim(bytes,address)":{"notice":"Completes bridge transaction on origin chain by claiming originally deposited capital"},"dispute(bytes32)":{"notice":"Disputes an outstanding proof in case relayer provided dest chain tx is invalid"},"getBridgeTransaction(bytes)":{"notice":"Decodes bridge request into a bridge transaction"},"getBridgeTransactionV2(bytes)":{"notice":"Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2"},"prove(bytes,bytes32)":{"notice":"Provides proof on origin side that relayer provided funds on destination side of bridge transaction"},"prove(bytes32,bytes32,address)":{"notice":"Provides proof on origin side that relayer provided funds on destination side of bridge transaction"},"refund(bytes)":{"notice":"Refunds an outstanding bridge transaction in case optimistic bridging failed"},"relay(bytes)":{"notice":"Relays destination side of bridge transaction by off-chain relayer"},"relay(bytes,address)":{"notice":"Relays destination side of bridge transaction by off-chain relayer"}},"version":1},"developerDoc":{"kind":"dev","methods":{"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256))":{"params":{"params":"The parameters required to bridge"}},"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256),(address,int256,bytes,uint256,bytes))":{"params":{"params":"The parameters required to bridge","paramsV2":"The parameters for exclusivity fill rights (optional, can be left empty)"}},"bridgeProofs(bytes32)":{"params":{"transactionId":"The ID of the bridge transaction"},"returns":{"relayer":"The relayer address of the bridge proof","timestamp":"The timestamp of the bridge proof"}},"bridgeRelays(bytes32)":{"params":{"transactionId":"The ID of the transaction to check"},"returns":{"_0":"True if the transaction has been relayed, false otherwise"}},"bridgeStatuses(bytes32)":{"params":{"transactionId":"The ID of the bridge transaction"},"returns":{"_0":"BridgeStatus Status of the bridge transaction"}},"canClaim(bytes32,address)":{"params":{"relayer":"The address of the relayer attempting to claim","transactionId":"The transaction id associated with the encoded bridge transaction to check"}},"cancel(bytes)":{"params":{"request":"The encoded bridge transaction to refund"}},"claim(bytes)":{"params":{"request":"The encoded bridge transaction to claim on origin chain"}},"claim(bytes,address)":{"params":{"request":"The encoded bridge transaction to claim on origin chain","to":"The recipient address of the funds"}},"dispute(bytes32)":{"params":{"transactionId":"The transaction id associated with the encoded bridge transaction to dispute"}},"getBridgeTransaction(bytes)":{"params":{"request":"The bridge request to decode"}},"getBridgeTransactionV2(bytes)":{"params":{"request":"The bridge request to decode"}},"prove(bytes,bytes32)":{"params":{"destTxHash":"The destination tx hash proving bridge transaction was relayed","request":"The encoded bridge transaction to prove on origin chain"}},"prove(bytes32,bytes32,address)":{"params":{"destTxHash":"The destination tx hash proving bridge transaction was relayed","relayer":"The address of the relaying entity which should have control of the origin funds when claimed","transactionId":"The transaction id associated with the encoded bridge transaction to prove"}},"refund(bytes)":{"params":{"request":"The encoded bridge transaction to refund"}},"relay(bytes)":{"params":{"request":"The encoded bridge transaction to relay on destination chain"}},"relay(bytes,address)":{"params":{"relayer":"The address of the relaying entity which should have control of the origin funds when claimed","request":"The encoded bridge transaction to relay on destination chain"}}},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"BridgeDepositClaimed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"BridgeDepositRefunded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"name\":\"BridgeProofDisputed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"transactionHash\",\"type\":\"bytes32\"}],\"name\":\"BridgeProofProvided\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"quoteId\",\"type\":\"bytes\"}],\"name\":\"BridgeQuoteDetails\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"originChainId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"chainGasAmount\",\"type\":\"uint256\"}],\"name\":\"BridgeRelayed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"destChainId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"sendChainGas\",\"type\":\"bool\"}],\"name\":\"BridgeRequested\",\"type\":\"event\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"dstChainId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"sendChainGas\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"}],\"internalType\":\"struct IFastBridge.BridgeParams\",\"name\":\"params\",\"type\":\"tuple\"}],\"name\":\"bridge\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"dstChainId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"sendChainGas\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"}],\"internalType\":\"struct IFastBridge.BridgeParams\",\"name\":\"params\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"quoteRelayer\",\"type\":\"address\"},{\"internalType\":\"int256\",\"name\":\"quoteExclusivitySeconds\",\"type\":\"int256\"},{\"internalType\":\"bytes\",\"name\":\"quoteId\",\"type\":\"bytes\"},{\"internalType\":\"uint256\",\"name\":\"zapNative\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"zapData\",\"type\":\"bytes\"}],\"internalType\":\"struct IFastBridgeV2.BridgeParamsV2\",\"name\":\"paramsV2\",\"type\":\"tuple\"}],\"name\":\"bridge\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"}],\"name\":\"bridgeProofs\",\"outputs\":[{\"internalType\":\"uint96\",\"name\":\"timestamp\",\"type\":\"uint96\"},{\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"}],\"name\":\"bridgeRelays\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"}],\"name\":\"bridgeStatuses\",\"outputs\":[{\"internalType\":\"enum IFastBridgeV2.BridgeStatus\",\"name\":\"\",\"type\":\"uint8\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"name\":\"canClaim\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"cancel\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"claim\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"claim\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"}],\"name\":\"dispute\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"getBridgeTransaction\",\"outputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"originChainId\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"destChainId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"originSender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destRecipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"originFeeAmount\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"sendChainGas\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"}],\"internalType\":\"struct IFastBridge.BridgeTransaction\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"getBridgeTransactionV2\",\"outputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"originChainId\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"destChainId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"originSender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destRecipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"originFeeAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"exclusivityRelayer\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"exclusivityEndTime\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"zapNative\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"zapData\",\"type\":\"bytes\"}],\"internalType\":\"struct IFastBridgeV2.BridgeTransactionV2\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"destTxHash\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"name\":\"prove\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"},{\"internalType\":\"bytes32\",\"name\":\"destTxHash\",\"type\":\"bytes32\"}],\"name\":\"prove\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"refund\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"relay\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"},{\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"name\":\"relay\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{\"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256))\":{\"params\":{\"params\":\"The parameters required to bridge\"}},\"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256),(address,int256,bytes,uint256,bytes))\":{\"params\":{\"params\":\"The parameters required to bridge\",\"paramsV2\":\"The parameters for exclusivity fill rights (optional, can be left empty)\"}},\"bridgeProofs(bytes32)\":{\"params\":{\"transactionId\":\"The ID of the bridge transaction\"},\"returns\":{\"relayer\":\"The relayer address of the bridge proof\",\"timestamp\":\"The timestamp of the bridge proof\"}},\"bridgeRelays(bytes32)\":{\"params\":{\"transactionId\":\"The ID of the transaction to check\"},\"returns\":{\"_0\":\"True if the transaction has been relayed, false otherwise\"}},\"bridgeStatuses(bytes32)\":{\"params\":{\"transactionId\":\"The ID of the bridge transaction\"},\"returns\":{\"_0\":\"BridgeStatus Status of the bridge transaction\"}},\"canClaim(bytes32,address)\":{\"params\":{\"relayer\":\"The address of the relayer attempting to claim\",\"transactionId\":\"The transaction id associated with the encoded bridge transaction to check\"}},\"cancel(bytes)\":{\"params\":{\"request\":\"The encoded bridge transaction to refund\"}},\"claim(bytes)\":{\"params\":{\"request\":\"The encoded bridge transaction to claim on origin chain\"}},\"claim(bytes,address)\":{\"params\":{\"request\":\"The encoded bridge transaction to claim on origin chain\",\"to\":\"The recipient address of the funds\"}},\"dispute(bytes32)\":{\"params\":{\"transactionId\":\"The transaction id associated with the encoded bridge transaction to dispute\"}},\"getBridgeTransaction(bytes)\":{\"params\":{\"request\":\"The bridge request to decode\"}},\"getBridgeTransactionV2(bytes)\":{\"params\":{\"request\":\"The bridge request to decode\"}},\"prove(bytes,bytes32)\":{\"params\":{\"destTxHash\":\"The destination tx hash proving bridge transaction was relayed\",\"request\":\"The encoded bridge transaction to prove on origin chain\"}},\"prove(bytes32,bytes32,address)\":{\"params\":{\"destTxHash\":\"The destination tx hash proving bridge transaction was relayed\",\"relayer\":\"The address of the relaying entity which should have control of the origin funds when claimed\",\"transactionId\":\"The transaction id associated with the encoded bridge transaction to prove\"}},\"refund(bytes)\":{\"params\":{\"request\":\"The encoded bridge transaction to refund\"}},\"relay(bytes)\":{\"params\":{\"request\":\"The encoded bridge transaction to relay on destination chain\"}},\"relay(bytes,address)\":{\"params\":{\"relayer\":\"The address of the relaying entity which should have control of the origin funds when claimed\",\"request\":\"The encoded bridge transaction to relay on destination chain\"}}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256))\":{\"notice\":\"Initiates bridge on origin chain to be relayed by off-chain relayer\"},\"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256),(address,int256,bytes,uint256,bytes))\":{\"notice\":\"Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability to provide temporary exclusivity fill rights for the quote relayer.\"},\"bridgeProofs(bytes32)\":{\"notice\":\"Returns the timestamp and relayer of a bridge proof\"},\"bridgeRelays(bytes32)\":{\"notice\":\"Checks if a transaction has been relayed\"},\"bridgeStatuses(bytes32)\":{\"notice\":\"Returns the status of a bridge transaction\"},\"canClaim(bytes32,address)\":{\"notice\":\"Checks if the dispute period has passed so bridge deposit can be claimed\"},\"cancel(bytes)\":{\"notice\":\"Cancels an outstanding bridge transaction in case optimistic bridging failed and returns the full amount to the original sender.\"},\"claim(bytes)\":{\"notice\":\"Completes bridge transaction on origin chain by claiming originally deposited capital.Can only send funds to the relayer address on the proof.\"},\"claim(bytes,address)\":{\"notice\":\"Completes bridge transaction on origin chain by claiming originally deposited capital\"},\"dispute(bytes32)\":{\"notice\":\"Disputes an outstanding proof in case relayer provided dest chain tx is invalid\"},\"getBridgeTransaction(bytes)\":{\"notice\":\"Decodes bridge request into a bridge transaction\"},\"getBridgeTransactionV2(bytes)\":{\"notice\":\"Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\"},\"prove(bytes,bytes32)\":{\"notice\":\"Provides proof on origin side that relayer provided funds on destination side of bridge transaction\"},\"prove(bytes32,bytes32,address)\":{\"notice\":\"Provides proof on origin side that relayer provided funds on destination side of bridge transaction\"},\"refund(bytes)\":{\"notice\":\"Refunds an outstanding bridge transaction in case optimistic bridging failed\"},\"relay(bytes)\":{\"notice\":\"Relays destination side of bridge transaction by off-chain relayer\"},\"relay(bytes,address)\":{\"notice\":\"Relays destination side of bridge transaction by off-chain relayer\"}},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeV2.sol\":\"IFastBridgeV2\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeV2.sol\":{\"keccak256\":\"0xac79c463688a682ca706a4ef95e7817b83548cdfa8182ba0426ac7e5e07613d8\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://b3ecb7097381287cafc3a73f3a2bb03565115ebb682a85064e0b0dc2f7e2919d\",\"dweb:/ipfs/QmatruW3nYZTksf3CeQ8wwiAG4c7xoEJBEp6drHPtFLBRK\"]}},\"version\":1}"},"hashes":{"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256))":"45851694","bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256),(address,int256,bytes,uint256,bytes))":"bfc7c607","bridgeProofs(bytes32)":"91ad5039","bridgeRelays(bytes32)":"8379a24f","bridgeStatuses(bytes32)":"051287bc","canClaim(bytes32,address)":"aa9641ab","cancel(bytes)":"3c5beeb4","claim(bytes)":"c63ff8dd","claim(bytes,address)":"41fcb612","dispute(bytes32)":"add98c70","getBridgeTransaction(bytes)":"ac11fb1a","getBridgeTransactionV2(bytes)":"5aa6ccba","prove(bytes,bytes32)":"886d36ff","prove(bytes32,bytes32,address)":"18e4357d","refund(bytes)":"5eb7d946","relay(bytes)":"8f0d6f17","relay(bytes,address)":"9c9545f0"}},"solidity/FastBridgeV2.sol:IFastBridgeV2Errors":{"code":"0x","runtime-code":"0x","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.24 ^0.8.20 ^0.8.4;\n\n// contracts/interfaces/IAdminV2.sol\n\ninterface IAdminV2 {\n event CancelDelayUpdated(uint256 oldCancelDelay, uint256 newCancelDelay);\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n function setCancelDelay(uint256 newCancelDelay) external;\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n}\n\n// contracts/interfaces/IAdminV2Errors.sol\n\ninterface IAdminV2Errors {\n error CancelDelayBelowMin();\n error FeeRateAboveMax();\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IFastBridgeV2Errors.sol\n\ninterface IFastBridgeV2Errors {\n error AmountIncorrect();\n error ChainIncorrect();\n error ExclusivityParamsIncorrect();\n error MsgValueIncorrect();\n error SenderIncorrect();\n error StatusIncorrect();\n error TokenNotContract();\n error ZapDataLengthAboveMax();\n error ZapNativeNotSupported();\n error ZeroAddress();\n\n error RecipientIncorrectReturnValue();\n error RecipientNoReturnValue();\n\n error DeadlineExceeded();\n error DeadlineNotExceeded();\n error DeadlineTooShort();\n error DisputePeriodNotPassed();\n error DisputePeriodPassed();\n error ExclusivityPeriodNotPassed();\n\n error TransactionRelayed();\n}\n\n// contracts/interfaces/IMulticallTarget.sol\n\n/// @notice Interface for a contract that can be called multiple times by the same caller. Inspired by MulticallV3:\n/// https://github.com/mds1/multicall/blob/master/src/Multicall3.sol\ninterface IMulticallTarget {\n struct Result {\n bool success;\n bytes returnData;\n }\n\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external;\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results);\n}\n\n// contracts/interfaces/IZapRecipient.sol\n\ninterface IZapRecipient {\n function zap(address token, uint256 amount, bytes memory zapData) external payable returns (bytes4);\n}\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// contracts/interfaces/IFastBridgeV2.sol\n\ninterface IFastBridgeV2 is IFastBridge {\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n struct BridgeTxDetails {\n BridgeStatus status;\n uint32 destChainId;\n uint56 proofBlockTimestamp;\n address proofRelayer;\n }\n\n struct BridgeRelay {\n uint48 blockNumber;\n uint48 blockTimestamp;\n address relayer;\n }\n\n /// @notice New params introduced in the FastBridgeV2.\n /// We are passing fields from the older BridgeParams struct outside of this struct\n /// for backwards compatibility.\n /// Note: quoteRelayer and quoteExclusivitySeconds are either both zero (indicating no exclusivity)\n /// or both non-zero (indicating exclusivity for the given period).\n /// Note: zapNative \u003e 0 can NOT be used with destToken = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE (native token)\n /// @param quoteRelayer Relayer that provided the quote for the transaction\n /// @param quoteExclusivitySeconds Period of time the quote relayer is guaranteed exclusivity after user's deposit\n /// @param quoteId Unique quote identifier used for tracking the quote\n /// @param zapNative ETH value to send to the recipient (if any)\n /// @param zapData Parameters for the Zap to the destination recipient (if any)\n struct BridgeParamsV2 {\n address quoteRelayer;\n int256 quoteExclusivitySeconds;\n bytes quoteId;\n uint256 zapNative;\n bytes zapData;\n }\n\n /// @notice Updated bridge transaction struct to include parameters introduced in FastBridgeV2.\n /// Note: only `exclusivityRelayer` can fill such a transaction until `exclusivityEndTime`.\n struct BridgeTransactionV2 {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n // Note: sendChainGas flag from V1 is deprecated\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n address exclusivityRelayer;\n uint256 exclusivityEndTime;\n uint256 zapNative; // ETH value to send to the recipient (if any)\n bytes zapData; // data to pass for the Zap action (if any)\n }\n\n event BridgeQuoteDetails(bytes32 indexed transactionId, bytes quoteId);\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability\n /// to provide temporary exclusivity fill rights for the quote relayer.\n /// @param params The parameters required to bridge\n /// @param paramsV2 The parameters for exclusivity fill rights (optional, can be left empty)\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function relay(bytes memory request, address relayer) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param transactionId The transaction id associated with the encoded bridge transaction to prove\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital.\n /// @notice Can only send funds to the relayer address on the proof.\n /// @param request The encoded bridge transaction to claim on origin chain\n function claim(bytes memory request) external;\n\n /// @notice Cancels an outstanding bridge transaction in case optimistic bridging failed and returns the full amount\n /// to the original sender.\n /// @param request The encoded bridge transaction to refund\n function cancel(bytes memory request) external;\n\n /// @notice Checks if a transaction has been relayed\n /// @param transactionId The ID of the transaction to check\n /// @return True if the transaction has been relayed, false otherwise\n function bridgeRelays(bytes32 transactionId) external view returns (bool);\n\n /// @notice Returns the status of a bridge transaction\n /// @param transactionId The ID of the bridge transaction\n /// @return BridgeStatus Status of the bridge transaction\n function bridgeStatuses(bytes32 transactionId) external view returns (BridgeStatus);\n\n /// @notice Returns the timestamp and relayer of a bridge proof\n /// @param transactionId The ID of the bridge transaction\n /// @return timestamp The timestamp of the bridge proof\n /// @return relayer The relayer address of the bridge proof\n function bridgeProofs(bytes32 transactionId) external view returns (uint96 timestamp, address relayer);\n\n /// @notice Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\n /// @param request The bridge request to decode\n function getBridgeTransactionV2(bytes memory request) external view returns (BridgeTransactionV2 memory);\n}\n\n// contracts/utils/MulticallTarget.sol\n\n// solhint-disable avoid-low-level-calls\n/// @notice Template for a contract that supports batched calls (preserving the msg.sender).\n/// Only calls with zero msg.value could be batched.\nabstract contract MulticallTarget is IMulticallTarget {\n error MulticallTarget__UndeterminedRevert();\n\n /// @notice Perform a batched call to this contract, preserving the msg.sender.\n /// The return data from each call is discarded.\n /// @dev The method is non-payable, so only calls with `msg.value == 0` could be batched.\n /// It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag.\n /// Otherwise, the whole batch call will be reverted with the original revert reason.\n /// @param data List of abi-encoded calldata for the calls to perform.\n /// @param ignoreReverts Whether to ignore the revert errors from the calls.\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external {\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\n if (!success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(result);\n }\n }\n }\n\n /// @notice Perform a batched call to this contract, preserving the msg.sender.\n /// The return data from each call is preserved.\n /// @dev The method is non-payable, so only calls with `msg.value == 0` could be batched.\n /// It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag.\n /// Otherwise, the whole batch call will be reverted with the original revert reason.\n /// @param data List of abi-encoded calldata for the calls to perform.\n /// @param ignoreReverts Whether to ignore the revert errors from the calls.\n /// @return results List of results from the calls: `(success, returnData)`.\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results)\n {\n results = new Result[](data.length);\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (results[i].success, results[i].returnData) = address(this).delegatecall(data[i]);\n if (!results[i].success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(results[i].returnData);\n }\n }\n }\n\n /// @dev Bubbles the revert message from the underlying call.\n /// Note: preserves the same custom error or revert string, if one was used.\n /// Source: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v5.0.2/contracts/utils/Address.sol#L143-L158\n function _bubbleRevert(bytes memory returnData) internal pure {\n // Look for revert reason and bubble it up if present\n if (returnData.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n // solhint-disable-next-line no-inline-assembly\n assembly {\n let returndata_size := mload(returnData)\n revert(add(32, returnData), returndata_size)\n }\n } else {\n revert MulticallTarget__UndeterminedRevert();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// contracts/libs/BridgeTransactionV2.sol\n\n// solhint-disable no-inline-assembly\nlibrary BridgeTransactionV2Lib {\n uint16 internal constant VERSION = 2;\n\n // Offsets of the fields in the packed BridgeTransactionV2 struct\n // uint16 version [000 .. 002)\n // uint32 originChainId [002 .. 006)\n // uint32 destChainId [006 .. 010)\n // address originSender [010 .. 030)\n // address destRecipient [030 .. 050)\n // address originToken [050 .. 070)\n // address destToken [070 .. 090)\n // uint256 originAmount [090 .. 122)\n // uint256 destAmount [122 .. 154)\n // uint256 originFeeAmount [154 .. 186)\n // uint256 deadline [186 .. 218)\n // uint256 nonce [218 .. 250)\n // address exclusivityRelayer [250 .. 270)\n // uint256 exclusivityEndTime [270 .. 302)\n // uint256 zapNative [302 .. 334)\n // bytes zapData [334 .. ***)\n\n // forgefmt: disable-start\n uint256 private constant OFFSET_ORIGIN_CHAIN_ID = 2;\n uint256 private constant OFFSET_DEST_CHAIN_ID = 6;\n uint256 private constant OFFSET_ORIGIN_SENDER = 10;\n uint256 private constant OFFSET_DEST_RECIPIENT = 30;\n uint256 private constant OFFSET_ORIGIN_TOKEN = 50;\n uint256 private constant OFFSET_DEST_TOKEN = 70;\n uint256 private constant OFFSET_ORIGIN_AMOUNT = 90;\n uint256 private constant OFFSET_DEST_AMOUNT = 122;\n uint256 private constant OFFSET_ORIGIN_FEE_AMOUNT = 154;\n uint256 private constant OFFSET_DEADLINE = 186;\n uint256 private constant OFFSET_NONCE = 218;\n uint256 private constant OFFSET_EXCLUSIVITY_RELAYER = 250;\n uint256 private constant OFFSET_EXCLUSIVITY_END_TIME = 270;\n uint256 private constant OFFSET_ZAP_NATIVE = 302;\n uint256 private constant OFFSET_ZAP_DATA = 334;\n // forgefmt: disable-end\n\n error BridgeTransactionV2__InvalidEncodedTx();\n error BridgeTransactionV2__UnsupportedVersion(uint16 version);\n\n /// @notice Validates the encoded transaction to be a tightly packed encoded payload for BridgeTransactionV2.\n /// @dev Checks the minimum length and the version, use this function before decoding any of the fields.\n function validateV2(bytes calldata encodedTx) internal pure {\n // Check the minimum length: must at least include all static fields.\n if (encodedTx.length \u003c OFFSET_ZAP_DATA) revert BridgeTransactionV2__InvalidEncodedTx();\n // Once we validated the length, we can be sure that the version field is present.\n uint16 version_ = version(encodedTx);\n if (version_ != VERSION) revert BridgeTransactionV2__UnsupportedVersion(version_);\n }\n\n /// @notice Encodes the BridgeTransactionV2 struct by tightly packing the fields.\n /// @dev `abi.decode` will not work as a result of the tightly packed fields. Use `decodeV2` to decode instead.\n function encodeV2(IFastBridgeV2.BridgeTransactionV2 memory bridgeTx) internal pure returns (bytes memory) {\n // We split the encoding into two parts to avoid stack-too-deep error\n bytes memory firstPart = abi.encodePacked(\n VERSION,\n bridgeTx.originChainId,\n bridgeTx.destChainId,\n bridgeTx.originSender,\n bridgeTx.destRecipient,\n bridgeTx.originToken,\n bridgeTx.destToken,\n bridgeTx.originAmount\n );\n return abi.encodePacked(\n firstPart,\n bridgeTx.destAmount,\n bridgeTx.originFeeAmount,\n // Note: we skip the deprecated `sendChainGas` flag, which was present in BridgeTransaction V1\n bridgeTx.deadline,\n bridgeTx.nonce,\n // New V2 fields: exclusivity\n bridgeTx.exclusivityRelayer,\n bridgeTx.exclusivityEndTime,\n // New V2 fields: Zap\n bridgeTx.zapNative,\n bridgeTx.zapData\n );\n }\n\n /// @notice Decodes the BridgeTransactionV2 struct from the encoded transaction.\n /// @dev Encoded BridgeTransactionV2 struct must be tightly packed.\n /// Use `validateV2` before decoding to ensure the encoded transaction is valid.\n function decodeV2(bytes calldata encodedTx)\n internal\n pure\n returns (IFastBridgeV2.BridgeTransactionV2 memory bridgeTx)\n {\n bridgeTx.originChainId = originChainId(encodedTx);\n bridgeTx.destChainId = destChainId(encodedTx);\n bridgeTx.originSender = originSender(encodedTx);\n bridgeTx.destRecipient = destRecipient(encodedTx);\n bridgeTx.originToken = originToken(encodedTx);\n bridgeTx.destToken = destToken(encodedTx);\n bridgeTx.originAmount = originAmount(encodedTx);\n bridgeTx.destAmount = destAmount(encodedTx);\n bridgeTx.originFeeAmount = originFeeAmount(encodedTx);\n bridgeTx.deadline = deadline(encodedTx);\n bridgeTx.nonce = nonce(encodedTx);\n bridgeTx.exclusivityRelayer = exclusivityRelayer(encodedTx);\n bridgeTx.exclusivityEndTime = exclusivityEndTime(encodedTx);\n bridgeTx.zapNative = zapNative(encodedTx);\n bridgeTx.zapData = zapData(encodedTx);\n }\n\n /// @notice Extracts the version from the encoded transaction.\n function version(bytes calldata encodedTx) internal pure returns (uint16 version_) {\n // Load 32 bytes from the start and shift it 240 bits to the right to get the highest 16 bits.\n assembly {\n version_ := shr(240, calldataload(encodedTx.offset))\n }\n }\n\n /// @notice Extracts the origin chain ID from the encoded transaction.\n function originChainId(bytes calldata encodedTx) internal pure returns (uint32 originChainId_) {\n // Load 32 bytes from the offset and shift it 224 bits to the right to get the highest 32 bits.\n assembly {\n originChainId_ := shr(224, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_CHAIN_ID)))\n }\n }\n\n /// @notice Extracts the destination chain ID from the encoded transaction.\n function destChainId(bytes calldata encodedTx) internal pure returns (uint32 destChainId_) {\n // Load 32 bytes from the offset and shift it 224 bits to the right to get the highest 32 bits.\n assembly {\n destChainId_ := shr(224, calldataload(add(encodedTx.offset, OFFSET_DEST_CHAIN_ID)))\n }\n }\n\n /// @notice Extracts the origin sender from the encoded transaction.\n function originSender(bytes calldata encodedTx) internal pure returns (address originSender_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n originSender_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_SENDER)))\n }\n }\n\n /// @notice Extracts the destination recipient from the encoded transaction.\n function destRecipient(bytes calldata encodedTx) internal pure returns (address destRecipient_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n destRecipient_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_DEST_RECIPIENT)))\n }\n }\n\n /// @notice Extracts the origin token from the encoded transaction.\n function originToken(bytes calldata encodedTx) internal pure returns (address originToken_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n originToken_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_TOKEN)))\n }\n }\n\n /// @notice Extracts the destination token from the encoded transaction.\n function destToken(bytes calldata encodedTx) internal pure returns (address destToken_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n destToken_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_DEST_TOKEN)))\n }\n }\n\n /// @notice Extracts the origin amount from the encoded transaction.\n function originAmount(bytes calldata encodedTx) internal pure returns (uint256 originAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n originAmount_ := calldataload(add(encodedTx.offset, OFFSET_ORIGIN_AMOUNT))\n }\n }\n\n /// @notice Extracts the destination amount from the encoded transaction.\n function destAmount(bytes calldata encodedTx) internal pure returns (uint256 destAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n destAmount_ := calldataload(add(encodedTx.offset, OFFSET_DEST_AMOUNT))\n }\n }\n\n /// @notice Extracts the origin fee amount from the encoded transaction.\n function originFeeAmount(bytes calldata encodedTx) internal pure returns (uint256 originFeeAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n originFeeAmount_ := calldataload(add(encodedTx.offset, OFFSET_ORIGIN_FEE_AMOUNT))\n }\n }\n\n /// @notice Extracts the deadline from the encoded transaction.\n function deadline(bytes calldata encodedTx) internal pure returns (uint256 deadline_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n deadline_ := calldataload(add(encodedTx.offset, OFFSET_DEADLINE))\n }\n }\n\n /// @notice Extracts the nonce from the encoded transaction.\n function nonce(bytes calldata encodedTx) internal pure returns (uint256 nonce_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n nonce_ := calldataload(add(encodedTx.offset, OFFSET_NONCE))\n }\n }\n\n /// @notice Extracts the exclusivity relayer from the encoded transaction.\n function exclusivityRelayer(bytes calldata encodedTx) internal pure returns (address exclusivityRelayer_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n exclusivityRelayer_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_EXCLUSIVITY_RELAYER)))\n }\n }\n\n /// @notice Extracts the exclusivity end time from the encoded transaction.\n function exclusivityEndTime(bytes calldata encodedTx) internal pure returns (uint256 exclusivityEndTime_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n exclusivityEndTime_ := calldataload(add(encodedTx.offset, OFFSET_EXCLUSIVITY_END_TIME))\n }\n }\n\n /// @notice Extracts the Zap's native value from the encoded transaction.\n function zapNative(bytes calldata encodedTx) internal pure returns (uint256 zapNative_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n zapNative_ := calldataload(add(encodedTx.offset, OFFSET_ZAP_NATIVE))\n }\n }\n\n /// @notice Extracts the Zap's data from the encoded transaction.\n function zapData(bytes calldata encodedTx) internal pure returns (bytes calldata zapData_) {\n zapData_ = encodedTx[OFFSET_ZAP_DATA:];\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/AdminV2.sol\n\ncontract AdminV2 is AccessControlEnumerable, IAdminV2, IAdminV2Errors {\n using SafeERC20 for IERC20;\n\n /// @notice Address reserved for native gas token (ETH on Ethereum and most L2s, AVAX on Avalanche, etc)\n address public constant NATIVE_GAS_TOKEN = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Role identifier for Quoter API's off-chain authentication.\n /// @dev Only addresses with this role can post FastBridge quotes to the API.\n bytes32 public constant QUOTER_ROLE = keccak256(\"QUOTER_ROLE\");\n\n /// @notice Role identifier for Prover's on-chain authentication in FastBridge.\n /// @dev Only addresses with this role can provide proofs that a FastBridge request has been relayed.\n bytes32 public constant PROVER_ROLE = keccak256(\"PROVER_ROLE\");\n\n /// @notice Role identifier for Guard's on-chain authentication in FastBridge.\n /// @dev Only addresses with this role can dispute submitted relay proofs during the dispute period.\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n\n /// @notice Role identifier for Canceler's on-chain authentication in FastBridge.\n /// @dev Only addresses with this role can cancel a FastBridge transaction without the cancel delay.\n bytes32 public constant CANCELER_ROLE = keccak256(\"CANCELER_ROLE\");\n\n /// @notice Role identifier for Governor's on-chain administrative authority.\n /// @dev Only addresses with this role can perform administrative tasks within the contract.\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n /// @notice Denominator for fee rates, represents 100%.\n uint256 public constant FEE_BPS = 1e6;\n /// @notice Maximum protocol fee rate: 1% on origin amount.\n uint256 public constant FEE_RATE_MAX = 0.01e6;\n\n /// @notice Minimum cancel delay that can be set by the governor.\n uint256 public constant MIN_CANCEL_DELAY = 1 hours;\n /// @notice Default cancel delay set during the contract deployment.\n uint256 public constant DEFAULT_CANCEL_DELAY = 1 days;\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Delay for a transaction after which it could be permisionlessly cancelled\n uint256 public cancelDelay;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Use ZapNative V2 requests instead.\n uint256 public immutable chainGasAmount = 0;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n _setCancelDelay(DEFAULT_CANCEL_DELAY);\n }\n\n /// @notice Allows the contract governor to set the cancel delay. The cancel delay is the time after the transaction\n /// deadline after which it can be permissionlessly cancelled, if it hasn't been proven by any of the Relayers.\n function setCancelDelay(uint256 newCancelDelay) external onlyRole(GOVERNOR_ROLE) {\n _setCancelDelay(newCancelDelay);\n }\n\n /// @notice Allows the contract governor to set the protocol fee rate. The protocol fee is taken from the origin\n /// amount only for completed and claimed transactions.\n /// @dev The protocol fee is abstracted away from the relayers, they always operate using the amounts after fees:\n /// what they see as the origin amount emitted in the log is what they get credited with.\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n if (newFeeRate \u003e FEE_RATE_MAX) revert FeeRateAboveMax();\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n /// @notice Allows the contract governor to sweep the accumulated protocol fees in the contract.\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n emit FeesSwept(token, recipient, feeAmount);\n /// Sweep the fees as the last transaction action\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(recipient), feeAmount);\n } else {\n IERC20(token).safeTransfer(recipient, feeAmount);\n }\n }\n\n /// @notice Internal function to set the cancel delay. Security checks are performed outside of this function.\n function _setCancelDelay(uint256 newCancelDelay) private {\n if (newCancelDelay \u003c MIN_CANCEL_DELAY) revert CancelDelayBelowMin();\n uint256 oldCancelDelay = cancelDelay;\n cancelDelay = newCancelDelay;\n emit CancelDelayUpdated(oldCancelDelay, newCancelDelay);\n }\n}\n\n// contracts/FastBridgeV2.sol\n\n/// @notice FastBridgeV2 is a contract for bridging tokens across chains.\ncontract FastBridgeV2 is AdminV2, MulticallTarget, IFastBridgeV2, IFastBridgeV2Errors {\n using BridgeTransactionV2Lib for bytes;\n using SafeERC20 for IERC20;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n /// @notice Maximum length of accepted zapData\n uint256 public constant MAX_ZAP_DATA_LENGTH = 2 ** 16 - 1;\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeTxDetails) public bridgeTxDetails;\n /// @notice Relay details on destination chain\n mapping(bytes32 =\u003e BridgeRelay) public bridgeRelayDetails;\n /// @notice Unique bridge nonces tracked per originSender\n mapping(address =\u003e uint256) public senderNonces;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Replaced by senderNonces\n uint256 public immutable nonce = 0;\n /// @notice the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) AdminV2(_owner) {\n deployBlock = block.number;\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n bridge({\n params: params,\n paramsV2: BridgeParamsV2({\n quoteRelayer: address(0),\n quoteExclusivitySeconds: 0,\n quoteId: bytes(\"\"),\n zapNative: 0,\n zapData: bytes(\"\")\n })\n });\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes calldata request) external payable {\n // relay override will validate the request\n relay({request: request, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes calldata request, bytes32 destTxHash) external {\n request.validateV2();\n prove({transactionId: keccak256(request), destTxHash: destTxHash, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridgeV2\n function claim(bytes calldata request) external {\n // claim override will validate the request\n claim({request: request, to: address(0)});\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Aggregate the read operations from the same storage slot\n address disputedRelayer = $.proofRelayer;\n BridgeStatus status = $.status;\n uint56 proofBlockTimestamp = $.proofBlockTimestamp;\n // Can only dispute a RELAYER_PROVED transaction within the dispute period\n if (status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(proofBlockTimestamp) \u003e DISPUTE_PERIOD) {\n revert DisputePeriodPassed();\n }\n // Update status to REQUESTED and delete the disputed proof details\n // Note: these are storage writes\n $.status = BridgeStatus.REQUESTED;\n $.proofRelayer = address(0);\n $.proofBlockTimestamp = 0;\n\n emit BridgeProofDisputed(transactionId, disputedRelayer);\n }\n\n /// Note: this function is deprecated and will be removed in a future version.\n /// @inheritdoc IFastBridge\n function refund(bytes calldata request) external {\n cancel(request);\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // The correct relayer can only claim a RELAYER_PROVED transaction after the dispute period\n if ($.status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if ($.proofRelayer != relayer) revert SenderIncorrect();\n return _timeSince($.proofBlockTimestamp) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n /// @dev This method is added to achieve backwards compatibility with decoding requests into V1 structs:\n /// - `zapNative` is partially reported as a zero/non-zero flag\n /// - `zapData` is ignored\n /// In order to process all kinds of requests use getBridgeTransactionV2 instead.\n function getBridgeTransaction(bytes calldata request) external view returns (BridgeTransaction memory) {\n // Try decoding into V2 struct first. This will revert if V1 struct is passed\n try this.getBridgeTransactionV2(request) returns (BridgeTransactionV2 memory txV2) {\n // Note: we entirely ignore the zapData field, as it was not present in V1\n return BridgeTransaction({\n originChainId: txV2.originChainId,\n destChainId: txV2.destChainId,\n originSender: txV2.originSender,\n destRecipient: txV2.destRecipient,\n originToken: txV2.originToken,\n destToken: txV2.destToken,\n originAmount: txV2.originAmount,\n destAmount: txV2.destAmount,\n originFeeAmount: txV2.originFeeAmount,\n sendChainGas: txV2.zapNative != 0,\n deadline: txV2.deadline,\n nonce: txV2.nonce\n });\n } catch {\n // Fallback to V1 struct\n return abi.decode(request, (BridgeTransaction));\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function getBridgeTransactionV2(bytes calldata request) external pure returns (BridgeTransactionV2 memory) {\n request.validateV2();\n return BridgeTransactionV2Lib.decodeV2(request);\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) public payable {\n int256 exclusivityEndTime = 0;\n // if relayer exclusivity is not intended for this bridge, set exclusivityEndTime to static zero\n // otherwise, set exclusivity to expire at the current block ts offset by quoteExclusivitySeconds\n if (paramsV2.quoteRelayer != address(0)) {\n exclusivityEndTime = int256(block.timestamp) + paramsV2.quoteExclusivitySeconds;\n }\n _validateBridgeParams(params, paramsV2, exclusivityEndTime);\n\n // transfer tokens to bridge contract\n /// @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _takeBridgedUserAsset(params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) {\n originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n }\n\n // set status to requested\n bytes memory request = BridgeTransactionV2Lib.encodeV2(\n BridgeTransactionV2({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n deadline: params.deadline,\n nonce: senderNonces[params.sender]++, // increment nonce on every bridge\n exclusivityRelayer: paramsV2.quoteRelayer,\n // We checked exclusivityEndTime to be in range [0 .. params.deadline] above, so can safely cast\n exclusivityEndTime: uint256(exclusivityEndTime),\n zapNative: paramsV2.zapNative,\n zapData: paramsV2.zapData\n })\n );\n bytes32 transactionId = keccak256(request);\n // Note: the tx status will be updated throughout the tx lifecycle, while destChainId is set once here\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n bridgeTxDetails[transactionId].destChainId = params.dstChainId;\n\n emit BridgeRequested({\n transactionId: transactionId,\n sender: params.sender,\n request: request,\n destChainId: params.dstChainId,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n sendChainGas: paramsV2.zapNative != 0\n });\n emit BridgeQuoteDetails(transactionId, paramsV2.quoteId);\n }\n\n /// @inheritdoc IFastBridgeV2\n function relay(bytes calldata request, address relayer) public payable {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n _validateRelayParams(request, transactionId, relayer);\n // mark bridge transaction as relayed\n bridgeRelayDetails[transactionId] =\n BridgeRelay({blockNumber: uint48(block.number), blockTimestamp: uint48(block.timestamp), relayer: relayer});\n\n // transfer tokens to recipient on destination chain and trigger Zap if requested\n address to = request.destRecipient();\n address token = request.destToken();\n uint256 amount = request.destAmount();\n uint256 zapNative = request.zapNative();\n\n // Emit the event before any external calls\n emit BridgeRelayed({\n transactionId: transactionId,\n relayer: relayer,\n to: to,\n originChainId: request.originChainId(),\n originToken: request.originToken(),\n destToken: token,\n originAmount: request.originAmount(),\n destAmount: amount,\n chainGasAmount: zapNative\n });\n\n // All state changes have been done at this point, can proceed to the external calls.\n // This follows the checks-effects-interactions pattern to mitigate potential reentrancy attacks.\n if (token == NATIVE_GAS_TOKEN) {\n // For the native gas token, additional zapNative is not allowed\n if (zapNative != 0) revert ZapNativeNotSupported();\n // Check that the correct msg.value was sent\n if (msg.value != amount) revert MsgValueIncorrect();\n // Don't do a native transfer yet: we will handle it alongside the Zap below\n } else {\n // For ERC20s, we check that the correct msg.value was sent\n if (msg.value != zapNative) revert MsgValueIncorrect();\n // We need to transfer the tokens from the Relayer to the recipient first before performing an\n // optional post-transfer Zap.\n IERC20(token).safeTransferFrom(msg.sender, to, amount);\n }\n // At this point we have done:\n // - Transferred the requested amount of ERC20 tokens to the recipient.\n // At this point we have confirmed:\n // - For ERC20s: msg.value matches the requested zapNative amount.\n // - For the native gas token: msg.value matches the requested destAmount.\n // Remaining optional things to do:\n // - Forward the full msg.value to the recipient (if non-zero).\n // - Trigger a Zap (if zapData is present).\n bytes calldata zapData = request.zapData();\n if (zapData.length != 0) {\n // Zap Data is present: Zap has been requested by the recipient. Trigger it forwarding the full msg.value.\n\n // Note: if token has a fee on transfers, the recipient will have received less than `amount`.\n // This is a very niche edge case and should be handled by the recipient contract.\n _triggerZapWithChecks({recipient: to, token: token, amount: amount, zapData: zapData});\n } else if (msg.value != 0) {\n // Zap Data is missing, but msg.value was sent. This could happen in two different cases:\n // - Relay with the native gas token is happening.\n // - Relay with ERC20 is happening, with a `zapNative \u003e 0` request.\n // In both cases, we need to transfer the full msg.value to the recipient.\n Address.sendValue(payable(to), msg.value);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) public onlyRole(PROVER_ROLE) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n\n // Can only prove a REQUESTED transaction\n if ($.status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n // Update status to RELAYER_PROVED and store the proof details\n // Note: these are storage writes\n $.status = BridgeStatus.RELAYER_PROVED;\n $.proofBlockTimestamp = uint56(block.timestamp);\n $.proofRelayer = relayer;\n\n emit BridgeProofProvided(transactionId, relayer, destTxHash);\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes calldata request, address to) public {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Aggregate the read operations from the same storage slot\n address proofRelayer = $.proofRelayer;\n BridgeStatus status = $.status;\n uint56 proofBlockTimestamp = $.proofBlockTimestamp;\n\n // Can only claim a RELAYER_PROVED transaction after the dispute period\n if (status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(proofBlockTimestamp) \u003c= DISPUTE_PERIOD) {\n revert DisputePeriodNotPassed();\n }\n\n if (to == address(0)) {\n // Anyone could claim the funds to the proven relayer on their behalf\n to = proofRelayer;\n } else if (proofRelayer != msg.sender) {\n // Only the proven relayer could specify an address to claim the funds to\n revert SenderIncorrect();\n }\n\n // Update status to RELAYER_CLAIMED and transfer the origin collateral to the specified claim address\n // Note: this is a storage write\n $.status = BridgeStatus.RELAYER_CLAIMED;\n\n address token = request.originToken();\n uint256 amount = request.originAmount();\n // Update protocol fees if origin fee amount exists\n uint256 originFeeAmount = request.originFeeAmount();\n if (originFeeAmount \u003e 0) protocolFees[token] += originFeeAmount;\n // Emit the event before any external calls\n emit BridgeDepositClaimed(transactionId, proofRelayer, to, token, amount);\n // Complete the relayer claim as the last transaction action\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(to), amount);\n } else {\n IERC20(token).safeTransfer(to, amount);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function cancel(bytes calldata request) public {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Can only cancel a REQUESTED transaction after its deadline expires\n if ($.status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n uint256 deadline = request.deadline();\n // Permissionless cancel is only allowed after `cancelDelay` on top of the deadline\n if (!hasRole(CANCELER_ROLE, msg.sender)) deadline += cancelDelay;\n if (block.timestamp \u003c= deadline) revert DeadlineNotExceeded();\n // Update status to REFUNDED and return the full amount (collateral + protocol fees) to the original sender.\n // The protocol fees are only updated when the transaction is claimed, so we don't need to update them here.\n // Note: this is a storage write\n $.status = BridgeStatus.REFUNDED;\n\n address to = request.originSender();\n address token = request.originToken();\n uint256 amount = request.originAmount() + request.originFeeAmount();\n // Emit the event before any external calls\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n // Complete the user cancel as the last transaction action\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(to), amount);\n } else {\n IERC20(token).safeTransfer(to, amount);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeStatuses(bytes32 transactionId) public view returns (BridgeStatus status) {\n return bridgeTxDetails[transactionId].status;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeProofs(bytes32 transactionId) public view returns (uint96 timestamp, address relayer) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n\n timestamp = $.proofBlockTimestamp;\n relayer = $.proofRelayer;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeRelays(bytes32 transactionId) public view returns (bool) {\n // has this transactionId been relayed?\n return bridgeRelayDetails[transactionId].relayer != address(0);\n }\n\n /// @notice Takes the bridged asset from the user into FastBridgeV2 custody. It will be later\n /// claimed by the relayer who completed the relay on destination chain, or transferred back to the user\n /// via the cancel function should no one complete the relay.\n function _takeBridgedUserAsset(address token, uint256 amount) internal returns (uint256 amountTaken) {\n if (token == NATIVE_GAS_TOKEN) {\n // For the native gas token, we just need to check that the supplied msg.value is correct.\n // Supplied `msg.value` is already in FastBridgeV2 custody.\n if (amount != msg.value) revert MsgValueIncorrect();\n amountTaken = msg.value;\n } else {\n // For ERC20s, token is explicitly transferred from the user to FastBridgeV2.\n // We don't allow non-zero `msg.value` to avoid extra funds from being stuck in FastBridgeV2.\n if (msg.value != 0) revert MsgValueIncorrect();\n // Throw an explicit error if the provided token address is not a contract\n if (token.code.length == 0) revert TokenNotContract();\n amountTaken = IERC20(token).balanceOf(address(this));\n IERC20(token).safeTransferFrom(msg.sender, address(this), amount);\n // Use the balance difference as the amount taken in case of fee on transfer tokens.\n amountTaken = IERC20(token).balanceOf(address(this)) - amountTaken;\n }\n }\n\n /// @notice Calls the Recipient's hook function with the specified zapData and performs\n /// all the necessary checks for the returned value.\n function _triggerZapWithChecks(address recipient, address token, uint256 amount, bytes calldata zapData) internal {\n // This will bubble any revert messages from the hook function\n bytes memory returnData = Address.functionCallWithValue({\n target: recipient,\n data: abi.encodeCall(IZapRecipient.zap, (token, amount, zapData)),\n // Note: see `relay()` for reasoning behind passing msg.value\n value: msg.value\n });\n // Explicit revert if no return data at all\n if (returnData.length == 0) revert RecipientNoReturnValue();\n // Check that exactly a single return value was returned\n if (returnData.length != 32) revert RecipientIncorrectReturnValue();\n // Return value should be abi-encoded hook function selector\n if (bytes32(returnData) != bytes32(IZapRecipient.zap.selector)) {\n revert RecipientIncorrectReturnValue();\n }\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint56(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint56).max but\n /// proof.timestamp \u003c type(uint56).max via unchecked statement\n /// @param proofBlockTimestamp The bridge proof block timestamp\n /// @return delta Time delta since proof submitted\n function _timeSince(uint56 proofBlockTimestamp) internal view returns (uint256 delta) {\n unchecked {\n delta = uint56(block.timestamp) - proofBlockTimestamp;\n }\n }\n\n /// @notice Performs all the necessary checks for a bridge to happen.\n /// @dev There's no good way to refactor this function to reduce cyclomatic complexity due to\n /// the number of checks that need to be performed, so we skip the code-complexity rule here.\n // solhint-disable-next-line code-complexity\n function _validateBridgeParams(\n BridgeParams memory params,\n BridgeParamsV2 memory paramsV2,\n int256 exclusivityEndTime\n )\n internal\n view\n {\n // Check V1 (legacy) params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.sender == address(0) || params.to == address(0)) revert ZeroAddress();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n // Check V2 params\n if (paramsV2.zapData.length \u003e MAX_ZAP_DATA_LENGTH) revert ZapDataLengthAboveMax();\n if (paramsV2.zapNative != 0 \u0026\u0026 params.destToken == NATIVE_GAS_TOKEN) {\n revert ZapNativeNotSupported();\n }\n // exclusivityEndTime must be in range [0 .. params.deadline]\n if (exclusivityEndTime \u003c 0 || exclusivityEndTime \u003e int256(params.deadline)) {\n revert ExclusivityParamsIncorrect();\n }\n }\n\n /// @notice Performs all the necessary checks for a relay to happen.\n function _validateRelayParams(bytes calldata request, bytes32 transactionId, address relayer) internal view {\n if (relayer == address(0)) revert ZeroAddress();\n // Check if the transaction has already been relayed\n if (bridgeRelays(transactionId)) revert TransactionRelayed();\n if (request.destChainId() != block.chainid) revert ChainIncorrect();\n // Check the deadline for relay to happen\n if (block.timestamp \u003e request.deadline()) revert DeadlineExceeded();\n // Check the exclusivity period, if it is still ongoing\n address exclRelayer = request.exclusivityRelayer();\n if (exclRelayer != address(0) \u0026\u0026 exclRelayer != relayer \u0026\u0026 block.timestamp \u003c= request.exclusivityEndTime()) {\n revert ExclusivityPeriodNotPassed();\n }\n }\n}\n","language":"Solidity","languageVersion":"0.8.24","compilerVersion":"0.8.24","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"","srcMapRuntime":"","abiDefinition":[{"inputs":[],"name":"AmountIncorrect","type":"error"},{"inputs":[],"name":"ChainIncorrect","type":"error"},{"inputs":[],"name":"DeadlineExceeded","type":"error"},{"inputs":[],"name":"DeadlineNotExceeded","type":"error"},{"inputs":[],"name":"DeadlineTooShort","type":"error"},{"inputs":[],"name":"DisputePeriodNotPassed","type":"error"},{"inputs":[],"name":"DisputePeriodPassed","type":"error"},{"inputs":[],"name":"ExclusivityParamsIncorrect","type":"error"},{"inputs":[],"name":"ExclusivityPeriodNotPassed","type":"error"},{"inputs":[],"name":"MsgValueIncorrect","type":"error"},{"inputs":[],"name":"RecipientIncorrectReturnValue","type":"error"},{"inputs":[],"name":"RecipientNoReturnValue","type":"error"},{"inputs":[],"name":"SenderIncorrect","type":"error"},{"inputs":[],"name":"StatusIncorrect","type":"error"},{"inputs":[],"name":"TokenNotContract","type":"error"},{"inputs":[],"name":"TransactionRelayed","type":"error"},{"inputs":[],"name":"ZapDataLengthAboveMax","type":"error"},{"inputs":[],"name":"ZapNativeNotSupported","type":"error"},{"inputs":[],"name":"ZeroAddress","type":"error"}],"userDoc":{"kind":"user","methods":{},"version":1},"developerDoc":{"kind":"dev","methods":{},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[],\"name\":\"AmountIncorrect\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ChainIncorrect\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DeadlineExceeded\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DeadlineNotExceeded\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DeadlineTooShort\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DisputePeriodNotPassed\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DisputePeriodPassed\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ExclusivityParamsIncorrect\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ExclusivityPeriodNotPassed\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"MsgValueIncorrect\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"RecipientIncorrectReturnValue\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"RecipientNoReturnValue\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"SenderIncorrect\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"StatusIncorrect\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"TokenNotContract\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"TransactionRelayed\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ZapDataLengthAboveMax\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ZapNativeNotSupported\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ZeroAddress\",\"type\":\"error\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeV2.sol\":\"IFastBridgeV2Errors\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeV2.sol\":{\"keccak256\":\"0xac79c463688a682ca706a4ef95e7817b83548cdfa8182ba0426ac7e5e07613d8\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://b3ecb7097381287cafc3a73f3a2bb03565115ebb682a85064e0b0dc2f7e2919d\",\"dweb:/ipfs/QmatruW3nYZTksf3CeQ8wwiAG4c7xoEJBEp6drHPtFLBRK\"]}},\"version\":1}"},"hashes":{}},"solidity/FastBridgeV2.sol:IMulticallTarget":{"code":"0x","runtime-code":"0x","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.24 ^0.8.20 ^0.8.4;\n\n// contracts/interfaces/IAdminV2.sol\n\ninterface IAdminV2 {\n event CancelDelayUpdated(uint256 oldCancelDelay, uint256 newCancelDelay);\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n function setCancelDelay(uint256 newCancelDelay) external;\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n}\n\n// contracts/interfaces/IAdminV2Errors.sol\n\ninterface IAdminV2Errors {\n error CancelDelayBelowMin();\n error FeeRateAboveMax();\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IFastBridgeV2Errors.sol\n\ninterface IFastBridgeV2Errors {\n error AmountIncorrect();\n error ChainIncorrect();\n error ExclusivityParamsIncorrect();\n error MsgValueIncorrect();\n error SenderIncorrect();\n error StatusIncorrect();\n error TokenNotContract();\n error ZapDataLengthAboveMax();\n error ZapNativeNotSupported();\n error ZeroAddress();\n\n error RecipientIncorrectReturnValue();\n error RecipientNoReturnValue();\n\n error DeadlineExceeded();\n error DeadlineNotExceeded();\n error DeadlineTooShort();\n error DisputePeriodNotPassed();\n error DisputePeriodPassed();\n error ExclusivityPeriodNotPassed();\n\n error TransactionRelayed();\n}\n\n// contracts/interfaces/IMulticallTarget.sol\n\n/// @notice Interface for a contract that can be called multiple times by the same caller. Inspired by MulticallV3:\n/// https://github.com/mds1/multicall/blob/master/src/Multicall3.sol\ninterface IMulticallTarget {\n struct Result {\n bool success;\n bytes returnData;\n }\n\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external;\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results);\n}\n\n// contracts/interfaces/IZapRecipient.sol\n\ninterface IZapRecipient {\n function zap(address token, uint256 amount, bytes memory zapData) external payable returns (bytes4);\n}\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// contracts/interfaces/IFastBridgeV2.sol\n\ninterface IFastBridgeV2 is IFastBridge {\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n struct BridgeTxDetails {\n BridgeStatus status;\n uint32 destChainId;\n uint56 proofBlockTimestamp;\n address proofRelayer;\n }\n\n struct BridgeRelay {\n uint48 blockNumber;\n uint48 blockTimestamp;\n address relayer;\n }\n\n /// @notice New params introduced in the FastBridgeV2.\n /// We are passing fields from the older BridgeParams struct outside of this struct\n /// for backwards compatibility.\n /// Note: quoteRelayer and quoteExclusivitySeconds are either both zero (indicating no exclusivity)\n /// or both non-zero (indicating exclusivity for the given period).\n /// Note: zapNative \u003e 0 can NOT be used with destToken = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE (native token)\n /// @param quoteRelayer Relayer that provided the quote for the transaction\n /// @param quoteExclusivitySeconds Period of time the quote relayer is guaranteed exclusivity after user's deposit\n /// @param quoteId Unique quote identifier used for tracking the quote\n /// @param zapNative ETH value to send to the recipient (if any)\n /// @param zapData Parameters for the Zap to the destination recipient (if any)\n struct BridgeParamsV2 {\n address quoteRelayer;\n int256 quoteExclusivitySeconds;\n bytes quoteId;\n uint256 zapNative;\n bytes zapData;\n }\n\n /// @notice Updated bridge transaction struct to include parameters introduced in FastBridgeV2.\n /// Note: only `exclusivityRelayer` can fill such a transaction until `exclusivityEndTime`.\n struct BridgeTransactionV2 {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n // Note: sendChainGas flag from V1 is deprecated\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n address exclusivityRelayer;\n uint256 exclusivityEndTime;\n uint256 zapNative; // ETH value to send to the recipient (if any)\n bytes zapData; // data to pass for the Zap action (if any)\n }\n\n event BridgeQuoteDetails(bytes32 indexed transactionId, bytes quoteId);\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability\n /// to provide temporary exclusivity fill rights for the quote relayer.\n /// @param params The parameters required to bridge\n /// @param paramsV2 The parameters for exclusivity fill rights (optional, can be left empty)\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function relay(bytes memory request, address relayer) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param transactionId The transaction id associated with the encoded bridge transaction to prove\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital.\n /// @notice Can only send funds to the relayer address on the proof.\n /// @param request The encoded bridge transaction to claim on origin chain\n function claim(bytes memory request) external;\n\n /// @notice Cancels an outstanding bridge transaction in case optimistic bridging failed and returns the full amount\n /// to the original sender.\n /// @param request The encoded bridge transaction to refund\n function cancel(bytes memory request) external;\n\n /// @notice Checks if a transaction has been relayed\n /// @param transactionId The ID of the transaction to check\n /// @return True if the transaction has been relayed, false otherwise\n function bridgeRelays(bytes32 transactionId) external view returns (bool);\n\n /// @notice Returns the status of a bridge transaction\n /// @param transactionId The ID of the bridge transaction\n /// @return BridgeStatus Status of the bridge transaction\n function bridgeStatuses(bytes32 transactionId) external view returns (BridgeStatus);\n\n /// @notice Returns the timestamp and relayer of a bridge proof\n /// @param transactionId The ID of the bridge transaction\n /// @return timestamp The timestamp of the bridge proof\n /// @return relayer The relayer address of the bridge proof\n function bridgeProofs(bytes32 transactionId) external view returns (uint96 timestamp, address relayer);\n\n /// @notice Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\n /// @param request The bridge request to decode\n function getBridgeTransactionV2(bytes memory request) external view returns (BridgeTransactionV2 memory);\n}\n\n// contracts/utils/MulticallTarget.sol\n\n// solhint-disable avoid-low-level-calls\n/// @notice Template for a contract that supports batched calls (preserving the msg.sender).\n/// Only calls with zero msg.value could be batched.\nabstract contract MulticallTarget is IMulticallTarget {\n error MulticallTarget__UndeterminedRevert();\n\n /// @notice Perform a batched call to this contract, preserving the msg.sender.\n /// The return data from each call is discarded.\n /// @dev The method is non-payable, so only calls with `msg.value == 0` could be batched.\n /// It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag.\n /// Otherwise, the whole batch call will be reverted with the original revert reason.\n /// @param data List of abi-encoded calldata for the calls to perform.\n /// @param ignoreReverts Whether to ignore the revert errors from the calls.\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external {\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\n if (!success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(result);\n }\n }\n }\n\n /// @notice Perform a batched call to this contract, preserving the msg.sender.\n /// The return data from each call is preserved.\n /// @dev The method is non-payable, so only calls with `msg.value == 0` could be batched.\n /// It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag.\n /// Otherwise, the whole batch call will be reverted with the original revert reason.\n /// @param data List of abi-encoded calldata for the calls to perform.\n /// @param ignoreReverts Whether to ignore the revert errors from the calls.\n /// @return results List of results from the calls: `(success, returnData)`.\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results)\n {\n results = new Result[](data.length);\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (results[i].success, results[i].returnData) = address(this).delegatecall(data[i]);\n if (!results[i].success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(results[i].returnData);\n }\n }\n }\n\n /// @dev Bubbles the revert message from the underlying call.\n /// Note: preserves the same custom error or revert string, if one was used.\n /// Source: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v5.0.2/contracts/utils/Address.sol#L143-L158\n function _bubbleRevert(bytes memory returnData) internal pure {\n // Look for revert reason and bubble it up if present\n if (returnData.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n // solhint-disable-next-line no-inline-assembly\n assembly {\n let returndata_size := mload(returnData)\n revert(add(32, returnData), returndata_size)\n }\n } else {\n revert MulticallTarget__UndeterminedRevert();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// contracts/libs/BridgeTransactionV2.sol\n\n// solhint-disable no-inline-assembly\nlibrary BridgeTransactionV2Lib {\n uint16 internal constant VERSION = 2;\n\n // Offsets of the fields in the packed BridgeTransactionV2 struct\n // uint16 version [000 .. 002)\n // uint32 originChainId [002 .. 006)\n // uint32 destChainId [006 .. 010)\n // address originSender [010 .. 030)\n // address destRecipient [030 .. 050)\n // address originToken [050 .. 070)\n // address destToken [070 .. 090)\n // uint256 originAmount [090 .. 122)\n // uint256 destAmount [122 .. 154)\n // uint256 originFeeAmount [154 .. 186)\n // uint256 deadline [186 .. 218)\n // uint256 nonce [218 .. 250)\n // address exclusivityRelayer [250 .. 270)\n // uint256 exclusivityEndTime [270 .. 302)\n // uint256 zapNative [302 .. 334)\n // bytes zapData [334 .. ***)\n\n // forgefmt: disable-start\n uint256 private constant OFFSET_ORIGIN_CHAIN_ID = 2;\n uint256 private constant OFFSET_DEST_CHAIN_ID = 6;\n uint256 private constant OFFSET_ORIGIN_SENDER = 10;\n uint256 private constant OFFSET_DEST_RECIPIENT = 30;\n uint256 private constant OFFSET_ORIGIN_TOKEN = 50;\n uint256 private constant OFFSET_DEST_TOKEN = 70;\n uint256 private constant OFFSET_ORIGIN_AMOUNT = 90;\n uint256 private constant OFFSET_DEST_AMOUNT = 122;\n uint256 private constant OFFSET_ORIGIN_FEE_AMOUNT = 154;\n uint256 private constant OFFSET_DEADLINE = 186;\n uint256 private constant OFFSET_NONCE = 218;\n uint256 private constant OFFSET_EXCLUSIVITY_RELAYER = 250;\n uint256 private constant OFFSET_EXCLUSIVITY_END_TIME = 270;\n uint256 private constant OFFSET_ZAP_NATIVE = 302;\n uint256 private constant OFFSET_ZAP_DATA = 334;\n // forgefmt: disable-end\n\n error BridgeTransactionV2__InvalidEncodedTx();\n error BridgeTransactionV2__UnsupportedVersion(uint16 version);\n\n /// @notice Validates the encoded transaction to be a tightly packed encoded payload for BridgeTransactionV2.\n /// @dev Checks the minimum length and the version, use this function before decoding any of the fields.\n function validateV2(bytes calldata encodedTx) internal pure {\n // Check the minimum length: must at least include all static fields.\n if (encodedTx.length \u003c OFFSET_ZAP_DATA) revert BridgeTransactionV2__InvalidEncodedTx();\n // Once we validated the length, we can be sure that the version field is present.\n uint16 version_ = version(encodedTx);\n if (version_ != VERSION) revert BridgeTransactionV2__UnsupportedVersion(version_);\n }\n\n /// @notice Encodes the BridgeTransactionV2 struct by tightly packing the fields.\n /// @dev `abi.decode` will not work as a result of the tightly packed fields. Use `decodeV2` to decode instead.\n function encodeV2(IFastBridgeV2.BridgeTransactionV2 memory bridgeTx) internal pure returns (bytes memory) {\n // We split the encoding into two parts to avoid stack-too-deep error\n bytes memory firstPart = abi.encodePacked(\n VERSION,\n bridgeTx.originChainId,\n bridgeTx.destChainId,\n bridgeTx.originSender,\n bridgeTx.destRecipient,\n bridgeTx.originToken,\n bridgeTx.destToken,\n bridgeTx.originAmount\n );\n return abi.encodePacked(\n firstPart,\n bridgeTx.destAmount,\n bridgeTx.originFeeAmount,\n // Note: we skip the deprecated `sendChainGas` flag, which was present in BridgeTransaction V1\n bridgeTx.deadline,\n bridgeTx.nonce,\n // New V2 fields: exclusivity\n bridgeTx.exclusivityRelayer,\n bridgeTx.exclusivityEndTime,\n // New V2 fields: Zap\n bridgeTx.zapNative,\n bridgeTx.zapData\n );\n }\n\n /// @notice Decodes the BridgeTransactionV2 struct from the encoded transaction.\n /// @dev Encoded BridgeTransactionV2 struct must be tightly packed.\n /// Use `validateV2` before decoding to ensure the encoded transaction is valid.\n function decodeV2(bytes calldata encodedTx)\n internal\n pure\n returns (IFastBridgeV2.BridgeTransactionV2 memory bridgeTx)\n {\n bridgeTx.originChainId = originChainId(encodedTx);\n bridgeTx.destChainId = destChainId(encodedTx);\n bridgeTx.originSender = originSender(encodedTx);\n bridgeTx.destRecipient = destRecipient(encodedTx);\n bridgeTx.originToken = originToken(encodedTx);\n bridgeTx.destToken = destToken(encodedTx);\n bridgeTx.originAmount = originAmount(encodedTx);\n bridgeTx.destAmount = destAmount(encodedTx);\n bridgeTx.originFeeAmount = originFeeAmount(encodedTx);\n bridgeTx.deadline = deadline(encodedTx);\n bridgeTx.nonce = nonce(encodedTx);\n bridgeTx.exclusivityRelayer = exclusivityRelayer(encodedTx);\n bridgeTx.exclusivityEndTime = exclusivityEndTime(encodedTx);\n bridgeTx.zapNative = zapNative(encodedTx);\n bridgeTx.zapData = zapData(encodedTx);\n }\n\n /// @notice Extracts the version from the encoded transaction.\n function version(bytes calldata encodedTx) internal pure returns (uint16 version_) {\n // Load 32 bytes from the start and shift it 240 bits to the right to get the highest 16 bits.\n assembly {\n version_ := shr(240, calldataload(encodedTx.offset))\n }\n }\n\n /// @notice Extracts the origin chain ID from the encoded transaction.\n function originChainId(bytes calldata encodedTx) internal pure returns (uint32 originChainId_) {\n // Load 32 bytes from the offset and shift it 224 bits to the right to get the highest 32 bits.\n assembly {\n originChainId_ := shr(224, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_CHAIN_ID)))\n }\n }\n\n /// @notice Extracts the destination chain ID from the encoded transaction.\n function destChainId(bytes calldata encodedTx) internal pure returns (uint32 destChainId_) {\n // Load 32 bytes from the offset and shift it 224 bits to the right to get the highest 32 bits.\n assembly {\n destChainId_ := shr(224, calldataload(add(encodedTx.offset, OFFSET_DEST_CHAIN_ID)))\n }\n }\n\n /// @notice Extracts the origin sender from the encoded transaction.\n function originSender(bytes calldata encodedTx) internal pure returns (address originSender_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n originSender_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_SENDER)))\n }\n }\n\n /// @notice Extracts the destination recipient from the encoded transaction.\n function destRecipient(bytes calldata encodedTx) internal pure returns (address destRecipient_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n destRecipient_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_DEST_RECIPIENT)))\n }\n }\n\n /// @notice Extracts the origin token from the encoded transaction.\n function originToken(bytes calldata encodedTx) internal pure returns (address originToken_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n originToken_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_TOKEN)))\n }\n }\n\n /// @notice Extracts the destination token from the encoded transaction.\n function destToken(bytes calldata encodedTx) internal pure returns (address destToken_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n destToken_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_DEST_TOKEN)))\n }\n }\n\n /// @notice Extracts the origin amount from the encoded transaction.\n function originAmount(bytes calldata encodedTx) internal pure returns (uint256 originAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n originAmount_ := calldataload(add(encodedTx.offset, OFFSET_ORIGIN_AMOUNT))\n }\n }\n\n /// @notice Extracts the destination amount from the encoded transaction.\n function destAmount(bytes calldata encodedTx) internal pure returns (uint256 destAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n destAmount_ := calldataload(add(encodedTx.offset, OFFSET_DEST_AMOUNT))\n }\n }\n\n /// @notice Extracts the origin fee amount from the encoded transaction.\n function originFeeAmount(bytes calldata encodedTx) internal pure returns (uint256 originFeeAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n originFeeAmount_ := calldataload(add(encodedTx.offset, OFFSET_ORIGIN_FEE_AMOUNT))\n }\n }\n\n /// @notice Extracts the deadline from the encoded transaction.\n function deadline(bytes calldata encodedTx) internal pure returns (uint256 deadline_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n deadline_ := calldataload(add(encodedTx.offset, OFFSET_DEADLINE))\n }\n }\n\n /// @notice Extracts the nonce from the encoded transaction.\n function nonce(bytes calldata encodedTx) internal pure returns (uint256 nonce_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n nonce_ := calldataload(add(encodedTx.offset, OFFSET_NONCE))\n }\n }\n\n /// @notice Extracts the exclusivity relayer from the encoded transaction.\n function exclusivityRelayer(bytes calldata encodedTx) internal pure returns (address exclusivityRelayer_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n exclusivityRelayer_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_EXCLUSIVITY_RELAYER)))\n }\n }\n\n /// @notice Extracts the exclusivity end time from the encoded transaction.\n function exclusivityEndTime(bytes calldata encodedTx) internal pure returns (uint256 exclusivityEndTime_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n exclusivityEndTime_ := calldataload(add(encodedTx.offset, OFFSET_EXCLUSIVITY_END_TIME))\n }\n }\n\n /// @notice Extracts the Zap's native value from the encoded transaction.\n function zapNative(bytes calldata encodedTx) internal pure returns (uint256 zapNative_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n zapNative_ := calldataload(add(encodedTx.offset, OFFSET_ZAP_NATIVE))\n }\n }\n\n /// @notice Extracts the Zap's data from the encoded transaction.\n function zapData(bytes calldata encodedTx) internal pure returns (bytes calldata zapData_) {\n zapData_ = encodedTx[OFFSET_ZAP_DATA:];\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/AdminV2.sol\n\ncontract AdminV2 is AccessControlEnumerable, IAdminV2, IAdminV2Errors {\n using SafeERC20 for IERC20;\n\n /// @notice Address reserved for native gas token (ETH on Ethereum and most L2s, AVAX on Avalanche, etc)\n address public constant NATIVE_GAS_TOKEN = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Role identifier for Quoter API's off-chain authentication.\n /// @dev Only addresses with this role can post FastBridge quotes to the API.\n bytes32 public constant QUOTER_ROLE = keccak256(\"QUOTER_ROLE\");\n\n /// @notice Role identifier for Prover's on-chain authentication in FastBridge.\n /// @dev Only addresses with this role can provide proofs that a FastBridge request has been relayed.\n bytes32 public constant PROVER_ROLE = keccak256(\"PROVER_ROLE\");\n\n /// @notice Role identifier for Guard's on-chain authentication in FastBridge.\n /// @dev Only addresses with this role can dispute submitted relay proofs during the dispute period.\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n\n /// @notice Role identifier for Canceler's on-chain authentication in FastBridge.\n /// @dev Only addresses with this role can cancel a FastBridge transaction without the cancel delay.\n bytes32 public constant CANCELER_ROLE = keccak256(\"CANCELER_ROLE\");\n\n /// @notice Role identifier for Governor's on-chain administrative authority.\n /// @dev Only addresses with this role can perform administrative tasks within the contract.\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n /// @notice Denominator for fee rates, represents 100%.\n uint256 public constant FEE_BPS = 1e6;\n /// @notice Maximum protocol fee rate: 1% on origin amount.\n uint256 public constant FEE_RATE_MAX = 0.01e6;\n\n /// @notice Minimum cancel delay that can be set by the governor.\n uint256 public constant MIN_CANCEL_DELAY = 1 hours;\n /// @notice Default cancel delay set during the contract deployment.\n uint256 public constant DEFAULT_CANCEL_DELAY = 1 days;\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Delay for a transaction after which it could be permisionlessly cancelled\n uint256 public cancelDelay;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Use ZapNative V2 requests instead.\n uint256 public immutable chainGasAmount = 0;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n _setCancelDelay(DEFAULT_CANCEL_DELAY);\n }\n\n /// @notice Allows the contract governor to set the cancel delay. The cancel delay is the time after the transaction\n /// deadline after which it can be permissionlessly cancelled, if it hasn't been proven by any of the Relayers.\n function setCancelDelay(uint256 newCancelDelay) external onlyRole(GOVERNOR_ROLE) {\n _setCancelDelay(newCancelDelay);\n }\n\n /// @notice Allows the contract governor to set the protocol fee rate. The protocol fee is taken from the origin\n /// amount only for completed and claimed transactions.\n /// @dev The protocol fee is abstracted away from the relayers, they always operate using the amounts after fees:\n /// what they see as the origin amount emitted in the log is what they get credited with.\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n if (newFeeRate \u003e FEE_RATE_MAX) revert FeeRateAboveMax();\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n /// @notice Allows the contract governor to sweep the accumulated protocol fees in the contract.\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n emit FeesSwept(token, recipient, feeAmount);\n /// Sweep the fees as the last transaction action\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(recipient), feeAmount);\n } else {\n IERC20(token).safeTransfer(recipient, feeAmount);\n }\n }\n\n /// @notice Internal function to set the cancel delay. Security checks are performed outside of this function.\n function _setCancelDelay(uint256 newCancelDelay) private {\n if (newCancelDelay \u003c MIN_CANCEL_DELAY) revert CancelDelayBelowMin();\n uint256 oldCancelDelay = cancelDelay;\n cancelDelay = newCancelDelay;\n emit CancelDelayUpdated(oldCancelDelay, newCancelDelay);\n }\n}\n\n// contracts/FastBridgeV2.sol\n\n/// @notice FastBridgeV2 is a contract for bridging tokens across chains.\ncontract FastBridgeV2 is AdminV2, MulticallTarget, IFastBridgeV2, IFastBridgeV2Errors {\n using BridgeTransactionV2Lib for bytes;\n using SafeERC20 for IERC20;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n /// @notice Maximum length of accepted zapData\n uint256 public constant MAX_ZAP_DATA_LENGTH = 2 ** 16 - 1;\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeTxDetails) public bridgeTxDetails;\n /// @notice Relay details on destination chain\n mapping(bytes32 =\u003e BridgeRelay) public bridgeRelayDetails;\n /// @notice Unique bridge nonces tracked per originSender\n mapping(address =\u003e uint256) public senderNonces;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Replaced by senderNonces\n uint256 public immutable nonce = 0;\n /// @notice the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) AdminV2(_owner) {\n deployBlock = block.number;\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n bridge({\n params: params,\n paramsV2: BridgeParamsV2({\n quoteRelayer: address(0),\n quoteExclusivitySeconds: 0,\n quoteId: bytes(\"\"),\n zapNative: 0,\n zapData: bytes(\"\")\n })\n });\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes calldata request) external payable {\n // relay override will validate the request\n relay({request: request, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes calldata request, bytes32 destTxHash) external {\n request.validateV2();\n prove({transactionId: keccak256(request), destTxHash: destTxHash, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridgeV2\n function claim(bytes calldata request) external {\n // claim override will validate the request\n claim({request: request, to: address(0)});\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Aggregate the read operations from the same storage slot\n address disputedRelayer = $.proofRelayer;\n BridgeStatus status = $.status;\n uint56 proofBlockTimestamp = $.proofBlockTimestamp;\n // Can only dispute a RELAYER_PROVED transaction within the dispute period\n if (status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(proofBlockTimestamp) \u003e DISPUTE_PERIOD) {\n revert DisputePeriodPassed();\n }\n // Update status to REQUESTED and delete the disputed proof details\n // Note: these are storage writes\n $.status = BridgeStatus.REQUESTED;\n $.proofRelayer = address(0);\n $.proofBlockTimestamp = 0;\n\n emit BridgeProofDisputed(transactionId, disputedRelayer);\n }\n\n /// Note: this function is deprecated and will be removed in a future version.\n /// @inheritdoc IFastBridge\n function refund(bytes calldata request) external {\n cancel(request);\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // The correct relayer can only claim a RELAYER_PROVED transaction after the dispute period\n if ($.status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if ($.proofRelayer != relayer) revert SenderIncorrect();\n return _timeSince($.proofBlockTimestamp) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n /// @dev This method is added to achieve backwards compatibility with decoding requests into V1 structs:\n /// - `zapNative` is partially reported as a zero/non-zero flag\n /// - `zapData` is ignored\n /// In order to process all kinds of requests use getBridgeTransactionV2 instead.\n function getBridgeTransaction(bytes calldata request) external view returns (BridgeTransaction memory) {\n // Try decoding into V2 struct first. This will revert if V1 struct is passed\n try this.getBridgeTransactionV2(request) returns (BridgeTransactionV2 memory txV2) {\n // Note: we entirely ignore the zapData field, as it was not present in V1\n return BridgeTransaction({\n originChainId: txV2.originChainId,\n destChainId: txV2.destChainId,\n originSender: txV2.originSender,\n destRecipient: txV2.destRecipient,\n originToken: txV2.originToken,\n destToken: txV2.destToken,\n originAmount: txV2.originAmount,\n destAmount: txV2.destAmount,\n originFeeAmount: txV2.originFeeAmount,\n sendChainGas: txV2.zapNative != 0,\n deadline: txV2.deadline,\n nonce: txV2.nonce\n });\n } catch {\n // Fallback to V1 struct\n return abi.decode(request, (BridgeTransaction));\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function getBridgeTransactionV2(bytes calldata request) external pure returns (BridgeTransactionV2 memory) {\n request.validateV2();\n return BridgeTransactionV2Lib.decodeV2(request);\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) public payable {\n int256 exclusivityEndTime = 0;\n // if relayer exclusivity is not intended for this bridge, set exclusivityEndTime to static zero\n // otherwise, set exclusivity to expire at the current block ts offset by quoteExclusivitySeconds\n if (paramsV2.quoteRelayer != address(0)) {\n exclusivityEndTime = int256(block.timestamp) + paramsV2.quoteExclusivitySeconds;\n }\n _validateBridgeParams(params, paramsV2, exclusivityEndTime);\n\n // transfer tokens to bridge contract\n /// @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _takeBridgedUserAsset(params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) {\n originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n }\n\n // set status to requested\n bytes memory request = BridgeTransactionV2Lib.encodeV2(\n BridgeTransactionV2({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n deadline: params.deadline,\n nonce: senderNonces[params.sender]++, // increment nonce on every bridge\n exclusivityRelayer: paramsV2.quoteRelayer,\n // We checked exclusivityEndTime to be in range [0 .. params.deadline] above, so can safely cast\n exclusivityEndTime: uint256(exclusivityEndTime),\n zapNative: paramsV2.zapNative,\n zapData: paramsV2.zapData\n })\n );\n bytes32 transactionId = keccak256(request);\n // Note: the tx status will be updated throughout the tx lifecycle, while destChainId is set once here\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n bridgeTxDetails[transactionId].destChainId = params.dstChainId;\n\n emit BridgeRequested({\n transactionId: transactionId,\n sender: params.sender,\n request: request,\n destChainId: params.dstChainId,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n sendChainGas: paramsV2.zapNative != 0\n });\n emit BridgeQuoteDetails(transactionId, paramsV2.quoteId);\n }\n\n /// @inheritdoc IFastBridgeV2\n function relay(bytes calldata request, address relayer) public payable {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n _validateRelayParams(request, transactionId, relayer);\n // mark bridge transaction as relayed\n bridgeRelayDetails[transactionId] =\n BridgeRelay({blockNumber: uint48(block.number), blockTimestamp: uint48(block.timestamp), relayer: relayer});\n\n // transfer tokens to recipient on destination chain and trigger Zap if requested\n address to = request.destRecipient();\n address token = request.destToken();\n uint256 amount = request.destAmount();\n uint256 zapNative = request.zapNative();\n\n // Emit the event before any external calls\n emit BridgeRelayed({\n transactionId: transactionId,\n relayer: relayer,\n to: to,\n originChainId: request.originChainId(),\n originToken: request.originToken(),\n destToken: token,\n originAmount: request.originAmount(),\n destAmount: amount,\n chainGasAmount: zapNative\n });\n\n // All state changes have been done at this point, can proceed to the external calls.\n // This follows the checks-effects-interactions pattern to mitigate potential reentrancy attacks.\n if (token == NATIVE_GAS_TOKEN) {\n // For the native gas token, additional zapNative is not allowed\n if (zapNative != 0) revert ZapNativeNotSupported();\n // Check that the correct msg.value was sent\n if (msg.value != amount) revert MsgValueIncorrect();\n // Don't do a native transfer yet: we will handle it alongside the Zap below\n } else {\n // For ERC20s, we check that the correct msg.value was sent\n if (msg.value != zapNative) revert MsgValueIncorrect();\n // We need to transfer the tokens from the Relayer to the recipient first before performing an\n // optional post-transfer Zap.\n IERC20(token).safeTransferFrom(msg.sender, to, amount);\n }\n // At this point we have done:\n // - Transferred the requested amount of ERC20 tokens to the recipient.\n // At this point we have confirmed:\n // - For ERC20s: msg.value matches the requested zapNative amount.\n // - For the native gas token: msg.value matches the requested destAmount.\n // Remaining optional things to do:\n // - Forward the full msg.value to the recipient (if non-zero).\n // - Trigger a Zap (if zapData is present).\n bytes calldata zapData = request.zapData();\n if (zapData.length != 0) {\n // Zap Data is present: Zap has been requested by the recipient. Trigger it forwarding the full msg.value.\n\n // Note: if token has a fee on transfers, the recipient will have received less than `amount`.\n // This is a very niche edge case and should be handled by the recipient contract.\n _triggerZapWithChecks({recipient: to, token: token, amount: amount, zapData: zapData});\n } else if (msg.value != 0) {\n // Zap Data is missing, but msg.value was sent. This could happen in two different cases:\n // - Relay with the native gas token is happening.\n // - Relay with ERC20 is happening, with a `zapNative \u003e 0` request.\n // In both cases, we need to transfer the full msg.value to the recipient.\n Address.sendValue(payable(to), msg.value);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) public onlyRole(PROVER_ROLE) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n\n // Can only prove a REQUESTED transaction\n if ($.status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n // Update status to RELAYER_PROVED and store the proof details\n // Note: these are storage writes\n $.status = BridgeStatus.RELAYER_PROVED;\n $.proofBlockTimestamp = uint56(block.timestamp);\n $.proofRelayer = relayer;\n\n emit BridgeProofProvided(transactionId, relayer, destTxHash);\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes calldata request, address to) public {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Aggregate the read operations from the same storage slot\n address proofRelayer = $.proofRelayer;\n BridgeStatus status = $.status;\n uint56 proofBlockTimestamp = $.proofBlockTimestamp;\n\n // Can only claim a RELAYER_PROVED transaction after the dispute period\n if (status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(proofBlockTimestamp) \u003c= DISPUTE_PERIOD) {\n revert DisputePeriodNotPassed();\n }\n\n if (to == address(0)) {\n // Anyone could claim the funds to the proven relayer on their behalf\n to = proofRelayer;\n } else if (proofRelayer != msg.sender) {\n // Only the proven relayer could specify an address to claim the funds to\n revert SenderIncorrect();\n }\n\n // Update status to RELAYER_CLAIMED and transfer the origin collateral to the specified claim address\n // Note: this is a storage write\n $.status = BridgeStatus.RELAYER_CLAIMED;\n\n address token = request.originToken();\n uint256 amount = request.originAmount();\n // Update protocol fees if origin fee amount exists\n uint256 originFeeAmount = request.originFeeAmount();\n if (originFeeAmount \u003e 0) protocolFees[token] += originFeeAmount;\n // Emit the event before any external calls\n emit BridgeDepositClaimed(transactionId, proofRelayer, to, token, amount);\n // Complete the relayer claim as the last transaction action\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(to), amount);\n } else {\n IERC20(token).safeTransfer(to, amount);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function cancel(bytes calldata request) public {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Can only cancel a REQUESTED transaction after its deadline expires\n if ($.status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n uint256 deadline = request.deadline();\n // Permissionless cancel is only allowed after `cancelDelay` on top of the deadline\n if (!hasRole(CANCELER_ROLE, msg.sender)) deadline += cancelDelay;\n if (block.timestamp \u003c= deadline) revert DeadlineNotExceeded();\n // Update status to REFUNDED and return the full amount (collateral + protocol fees) to the original sender.\n // The protocol fees are only updated when the transaction is claimed, so we don't need to update them here.\n // Note: this is a storage write\n $.status = BridgeStatus.REFUNDED;\n\n address to = request.originSender();\n address token = request.originToken();\n uint256 amount = request.originAmount() + request.originFeeAmount();\n // Emit the event before any external calls\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n // Complete the user cancel as the last transaction action\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(to), amount);\n } else {\n IERC20(token).safeTransfer(to, amount);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeStatuses(bytes32 transactionId) public view returns (BridgeStatus status) {\n return bridgeTxDetails[transactionId].status;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeProofs(bytes32 transactionId) public view returns (uint96 timestamp, address relayer) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n\n timestamp = $.proofBlockTimestamp;\n relayer = $.proofRelayer;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeRelays(bytes32 transactionId) public view returns (bool) {\n // has this transactionId been relayed?\n return bridgeRelayDetails[transactionId].relayer != address(0);\n }\n\n /// @notice Takes the bridged asset from the user into FastBridgeV2 custody. It will be later\n /// claimed by the relayer who completed the relay on destination chain, or transferred back to the user\n /// via the cancel function should no one complete the relay.\n function _takeBridgedUserAsset(address token, uint256 amount) internal returns (uint256 amountTaken) {\n if (token == NATIVE_GAS_TOKEN) {\n // For the native gas token, we just need to check that the supplied msg.value is correct.\n // Supplied `msg.value` is already in FastBridgeV2 custody.\n if (amount != msg.value) revert MsgValueIncorrect();\n amountTaken = msg.value;\n } else {\n // For ERC20s, token is explicitly transferred from the user to FastBridgeV2.\n // We don't allow non-zero `msg.value` to avoid extra funds from being stuck in FastBridgeV2.\n if (msg.value != 0) revert MsgValueIncorrect();\n // Throw an explicit error if the provided token address is not a contract\n if (token.code.length == 0) revert TokenNotContract();\n amountTaken = IERC20(token).balanceOf(address(this));\n IERC20(token).safeTransferFrom(msg.sender, address(this), amount);\n // Use the balance difference as the amount taken in case of fee on transfer tokens.\n amountTaken = IERC20(token).balanceOf(address(this)) - amountTaken;\n }\n }\n\n /// @notice Calls the Recipient's hook function with the specified zapData and performs\n /// all the necessary checks for the returned value.\n function _triggerZapWithChecks(address recipient, address token, uint256 amount, bytes calldata zapData) internal {\n // This will bubble any revert messages from the hook function\n bytes memory returnData = Address.functionCallWithValue({\n target: recipient,\n data: abi.encodeCall(IZapRecipient.zap, (token, amount, zapData)),\n // Note: see `relay()` for reasoning behind passing msg.value\n value: msg.value\n });\n // Explicit revert if no return data at all\n if (returnData.length == 0) revert RecipientNoReturnValue();\n // Check that exactly a single return value was returned\n if (returnData.length != 32) revert RecipientIncorrectReturnValue();\n // Return value should be abi-encoded hook function selector\n if (bytes32(returnData) != bytes32(IZapRecipient.zap.selector)) {\n revert RecipientIncorrectReturnValue();\n }\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint56(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint56).max but\n /// proof.timestamp \u003c type(uint56).max via unchecked statement\n /// @param proofBlockTimestamp The bridge proof block timestamp\n /// @return delta Time delta since proof submitted\n function _timeSince(uint56 proofBlockTimestamp) internal view returns (uint256 delta) {\n unchecked {\n delta = uint56(block.timestamp) - proofBlockTimestamp;\n }\n }\n\n /// @notice Performs all the necessary checks for a bridge to happen.\n /// @dev There's no good way to refactor this function to reduce cyclomatic complexity due to\n /// the number of checks that need to be performed, so we skip the code-complexity rule here.\n // solhint-disable-next-line code-complexity\n function _validateBridgeParams(\n BridgeParams memory params,\n BridgeParamsV2 memory paramsV2,\n int256 exclusivityEndTime\n )\n internal\n view\n {\n // Check V1 (legacy) params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.sender == address(0) || params.to == address(0)) revert ZeroAddress();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n // Check V2 params\n if (paramsV2.zapData.length \u003e MAX_ZAP_DATA_LENGTH) revert ZapDataLengthAboveMax();\n if (paramsV2.zapNative != 0 \u0026\u0026 params.destToken == NATIVE_GAS_TOKEN) {\n revert ZapNativeNotSupported();\n }\n // exclusivityEndTime must be in range [0 .. params.deadline]\n if (exclusivityEndTime \u003c 0 || exclusivityEndTime \u003e int256(params.deadline)) {\n revert ExclusivityParamsIncorrect();\n }\n }\n\n /// @notice Performs all the necessary checks for a relay to happen.\n function _validateRelayParams(bytes calldata request, bytes32 transactionId, address relayer) internal view {\n if (relayer == address(0)) revert ZeroAddress();\n // Check if the transaction has already been relayed\n if (bridgeRelays(transactionId)) revert TransactionRelayed();\n if (request.destChainId() != block.chainid) revert ChainIncorrect();\n // Check the deadline for relay to happen\n if (block.timestamp \u003e request.deadline()) revert DeadlineExceeded();\n // Check the exclusivity period, if it is still ongoing\n address exclRelayer = request.exclusivityRelayer();\n if (exclRelayer != address(0) \u0026\u0026 exclRelayer != relayer \u0026\u0026 block.timestamp \u003c= request.exclusivityEndTime()) {\n revert ExclusivityPeriodNotPassed();\n }\n }\n}\n","language":"Solidity","languageVersion":"0.8.24","compilerVersion":"0.8.24","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"","srcMapRuntime":"","abiDefinition":[{"inputs":[{"internalType":"bytes[]","name":"data","type":"bytes[]"},{"internalType":"bool","name":"ignoreReverts","type":"bool"}],"name":"multicallNoResults","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes[]","name":"data","type":"bytes[]"},{"internalType":"bool","name":"ignoreReverts","type":"bool"}],"name":"multicallWithResults","outputs":[{"components":[{"internalType":"bool","name":"success","type":"bool"},{"internalType":"bytes","name":"returnData","type":"bytes"}],"internalType":"struct IMulticallTarget.Result[]","name":"results","type":"tuple[]"}],"stateMutability":"nonpayable","type":"function"}],"userDoc":{"kind":"user","methods":{},"notice":"Interface for a contract that can be called multiple times by the same caller. Inspired by MulticallV3: https://github.com/mds1/multicall/blob/master/src/Multicall3.sol","version":1},"developerDoc":{"kind":"dev","methods":{},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"bytes[]\",\"name\":\"data\",\"type\":\"bytes[]\"},{\"internalType\":\"bool\",\"name\":\"ignoreReverts\",\"type\":\"bool\"}],\"name\":\"multicallNoResults\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes[]\",\"name\":\"data\",\"type\":\"bytes[]\"},{\"internalType\":\"bool\",\"name\":\"ignoreReverts\",\"type\":\"bool\"}],\"name\":\"multicallWithResults\",\"outputs\":[{\"components\":[{\"internalType\":\"bool\",\"name\":\"success\",\"type\":\"bool\"},{\"internalType\":\"bytes\",\"name\":\"returnData\",\"type\":\"bytes\"}],\"internalType\":\"struct IMulticallTarget.Result[]\",\"name\":\"results\",\"type\":\"tuple[]\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"notice\":\"Interface for a contract that can be called multiple times by the same caller. Inspired by MulticallV3: https://github.com/mds1/multicall/blob/master/src/Multicall3.sol\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeV2.sol\":\"IMulticallTarget\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeV2.sol\":{\"keccak256\":\"0xac79c463688a682ca706a4ef95e7817b83548cdfa8182ba0426ac7e5e07613d8\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://b3ecb7097381287cafc3a73f3a2bb03565115ebb682a85064e0b0dc2f7e2919d\",\"dweb:/ipfs/QmatruW3nYZTksf3CeQ8wwiAG4c7xoEJBEp6drHPtFLBRK\"]}},\"version\":1}"},"hashes":{"multicallNoResults(bytes[],bool)":"3f61331d","multicallWithResults(bytes[],bool)":"385c1d2f"}},"solidity/FastBridgeV2.sol:IZapRecipient":{"code":"0x","runtime-code":"0x","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.24 ^0.8.20 ^0.8.4;\n\n// contracts/interfaces/IAdminV2.sol\n\ninterface IAdminV2 {\n event CancelDelayUpdated(uint256 oldCancelDelay, uint256 newCancelDelay);\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n function setCancelDelay(uint256 newCancelDelay) external;\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n}\n\n// contracts/interfaces/IAdminV2Errors.sol\n\ninterface IAdminV2Errors {\n error CancelDelayBelowMin();\n error FeeRateAboveMax();\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IFastBridgeV2Errors.sol\n\ninterface IFastBridgeV2Errors {\n error AmountIncorrect();\n error ChainIncorrect();\n error ExclusivityParamsIncorrect();\n error MsgValueIncorrect();\n error SenderIncorrect();\n error StatusIncorrect();\n error TokenNotContract();\n error ZapDataLengthAboveMax();\n error ZapNativeNotSupported();\n error ZeroAddress();\n\n error RecipientIncorrectReturnValue();\n error RecipientNoReturnValue();\n\n error DeadlineExceeded();\n error DeadlineNotExceeded();\n error DeadlineTooShort();\n error DisputePeriodNotPassed();\n error DisputePeriodPassed();\n error ExclusivityPeriodNotPassed();\n\n error TransactionRelayed();\n}\n\n// contracts/interfaces/IMulticallTarget.sol\n\n/// @notice Interface for a contract that can be called multiple times by the same caller. Inspired by MulticallV3:\n/// https://github.com/mds1/multicall/blob/master/src/Multicall3.sol\ninterface IMulticallTarget {\n struct Result {\n bool success;\n bytes returnData;\n }\n\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external;\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results);\n}\n\n// contracts/interfaces/IZapRecipient.sol\n\ninterface IZapRecipient {\n function zap(address token, uint256 amount, bytes memory zapData) external payable returns (bytes4);\n}\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// contracts/interfaces/IFastBridgeV2.sol\n\ninterface IFastBridgeV2 is IFastBridge {\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n struct BridgeTxDetails {\n BridgeStatus status;\n uint32 destChainId;\n uint56 proofBlockTimestamp;\n address proofRelayer;\n }\n\n struct BridgeRelay {\n uint48 blockNumber;\n uint48 blockTimestamp;\n address relayer;\n }\n\n /// @notice New params introduced in the FastBridgeV2.\n /// We are passing fields from the older BridgeParams struct outside of this struct\n /// for backwards compatibility.\n /// Note: quoteRelayer and quoteExclusivitySeconds are either both zero (indicating no exclusivity)\n /// or both non-zero (indicating exclusivity for the given period).\n /// Note: zapNative \u003e 0 can NOT be used with destToken = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE (native token)\n /// @param quoteRelayer Relayer that provided the quote for the transaction\n /// @param quoteExclusivitySeconds Period of time the quote relayer is guaranteed exclusivity after user's deposit\n /// @param quoteId Unique quote identifier used for tracking the quote\n /// @param zapNative ETH value to send to the recipient (if any)\n /// @param zapData Parameters for the Zap to the destination recipient (if any)\n struct BridgeParamsV2 {\n address quoteRelayer;\n int256 quoteExclusivitySeconds;\n bytes quoteId;\n uint256 zapNative;\n bytes zapData;\n }\n\n /// @notice Updated bridge transaction struct to include parameters introduced in FastBridgeV2.\n /// Note: only `exclusivityRelayer` can fill such a transaction until `exclusivityEndTime`.\n struct BridgeTransactionV2 {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n // Note: sendChainGas flag from V1 is deprecated\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n address exclusivityRelayer;\n uint256 exclusivityEndTime;\n uint256 zapNative; // ETH value to send to the recipient (if any)\n bytes zapData; // data to pass for the Zap action (if any)\n }\n\n event BridgeQuoteDetails(bytes32 indexed transactionId, bytes quoteId);\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability\n /// to provide temporary exclusivity fill rights for the quote relayer.\n /// @param params The parameters required to bridge\n /// @param paramsV2 The parameters for exclusivity fill rights (optional, can be left empty)\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function relay(bytes memory request, address relayer) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param transactionId The transaction id associated with the encoded bridge transaction to prove\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital.\n /// @notice Can only send funds to the relayer address on the proof.\n /// @param request The encoded bridge transaction to claim on origin chain\n function claim(bytes memory request) external;\n\n /// @notice Cancels an outstanding bridge transaction in case optimistic bridging failed and returns the full amount\n /// to the original sender.\n /// @param request The encoded bridge transaction to refund\n function cancel(bytes memory request) external;\n\n /// @notice Checks if a transaction has been relayed\n /// @param transactionId The ID of the transaction to check\n /// @return True if the transaction has been relayed, false otherwise\n function bridgeRelays(bytes32 transactionId) external view returns (bool);\n\n /// @notice Returns the status of a bridge transaction\n /// @param transactionId The ID of the bridge transaction\n /// @return BridgeStatus Status of the bridge transaction\n function bridgeStatuses(bytes32 transactionId) external view returns (BridgeStatus);\n\n /// @notice Returns the timestamp and relayer of a bridge proof\n /// @param transactionId The ID of the bridge transaction\n /// @return timestamp The timestamp of the bridge proof\n /// @return relayer The relayer address of the bridge proof\n function bridgeProofs(bytes32 transactionId) external view returns (uint96 timestamp, address relayer);\n\n /// @notice Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\n /// @param request The bridge request to decode\n function getBridgeTransactionV2(bytes memory request) external view returns (BridgeTransactionV2 memory);\n}\n\n// contracts/utils/MulticallTarget.sol\n\n// solhint-disable avoid-low-level-calls\n/// @notice Template for a contract that supports batched calls (preserving the msg.sender).\n/// Only calls with zero msg.value could be batched.\nabstract contract MulticallTarget is IMulticallTarget {\n error MulticallTarget__UndeterminedRevert();\n\n /// @notice Perform a batched call to this contract, preserving the msg.sender.\n /// The return data from each call is discarded.\n /// @dev The method is non-payable, so only calls with `msg.value == 0` could be batched.\n /// It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag.\n /// Otherwise, the whole batch call will be reverted with the original revert reason.\n /// @param data List of abi-encoded calldata for the calls to perform.\n /// @param ignoreReverts Whether to ignore the revert errors from the calls.\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external {\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\n if (!success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(result);\n }\n }\n }\n\n /// @notice Perform a batched call to this contract, preserving the msg.sender.\n /// The return data from each call is preserved.\n /// @dev The method is non-payable, so only calls with `msg.value == 0` could be batched.\n /// It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag.\n /// Otherwise, the whole batch call will be reverted with the original revert reason.\n /// @param data List of abi-encoded calldata for the calls to perform.\n /// @param ignoreReverts Whether to ignore the revert errors from the calls.\n /// @return results List of results from the calls: `(success, returnData)`.\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results)\n {\n results = new Result[](data.length);\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (results[i].success, results[i].returnData) = address(this).delegatecall(data[i]);\n if (!results[i].success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(results[i].returnData);\n }\n }\n }\n\n /// @dev Bubbles the revert message from the underlying call.\n /// Note: preserves the same custom error or revert string, if one was used.\n /// Source: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v5.0.2/contracts/utils/Address.sol#L143-L158\n function _bubbleRevert(bytes memory returnData) internal pure {\n // Look for revert reason and bubble it up if present\n if (returnData.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n // solhint-disable-next-line no-inline-assembly\n assembly {\n let returndata_size := mload(returnData)\n revert(add(32, returnData), returndata_size)\n }\n } else {\n revert MulticallTarget__UndeterminedRevert();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// contracts/libs/BridgeTransactionV2.sol\n\n// solhint-disable no-inline-assembly\nlibrary BridgeTransactionV2Lib {\n uint16 internal constant VERSION = 2;\n\n // Offsets of the fields in the packed BridgeTransactionV2 struct\n // uint16 version [000 .. 002)\n // uint32 originChainId [002 .. 006)\n // uint32 destChainId [006 .. 010)\n // address originSender [010 .. 030)\n // address destRecipient [030 .. 050)\n // address originToken [050 .. 070)\n // address destToken [070 .. 090)\n // uint256 originAmount [090 .. 122)\n // uint256 destAmount [122 .. 154)\n // uint256 originFeeAmount [154 .. 186)\n // uint256 deadline [186 .. 218)\n // uint256 nonce [218 .. 250)\n // address exclusivityRelayer [250 .. 270)\n // uint256 exclusivityEndTime [270 .. 302)\n // uint256 zapNative [302 .. 334)\n // bytes zapData [334 .. ***)\n\n // forgefmt: disable-start\n uint256 private constant OFFSET_ORIGIN_CHAIN_ID = 2;\n uint256 private constant OFFSET_DEST_CHAIN_ID = 6;\n uint256 private constant OFFSET_ORIGIN_SENDER = 10;\n uint256 private constant OFFSET_DEST_RECIPIENT = 30;\n uint256 private constant OFFSET_ORIGIN_TOKEN = 50;\n uint256 private constant OFFSET_DEST_TOKEN = 70;\n uint256 private constant OFFSET_ORIGIN_AMOUNT = 90;\n uint256 private constant OFFSET_DEST_AMOUNT = 122;\n uint256 private constant OFFSET_ORIGIN_FEE_AMOUNT = 154;\n uint256 private constant OFFSET_DEADLINE = 186;\n uint256 private constant OFFSET_NONCE = 218;\n uint256 private constant OFFSET_EXCLUSIVITY_RELAYER = 250;\n uint256 private constant OFFSET_EXCLUSIVITY_END_TIME = 270;\n uint256 private constant OFFSET_ZAP_NATIVE = 302;\n uint256 private constant OFFSET_ZAP_DATA = 334;\n // forgefmt: disable-end\n\n error BridgeTransactionV2__InvalidEncodedTx();\n error BridgeTransactionV2__UnsupportedVersion(uint16 version);\n\n /// @notice Validates the encoded transaction to be a tightly packed encoded payload for BridgeTransactionV2.\n /// @dev Checks the minimum length and the version, use this function before decoding any of the fields.\n function validateV2(bytes calldata encodedTx) internal pure {\n // Check the minimum length: must at least include all static fields.\n if (encodedTx.length \u003c OFFSET_ZAP_DATA) revert BridgeTransactionV2__InvalidEncodedTx();\n // Once we validated the length, we can be sure that the version field is present.\n uint16 version_ = version(encodedTx);\n if (version_ != VERSION) revert BridgeTransactionV2__UnsupportedVersion(version_);\n }\n\n /// @notice Encodes the BridgeTransactionV2 struct by tightly packing the fields.\n /// @dev `abi.decode` will not work as a result of the tightly packed fields. Use `decodeV2` to decode instead.\n function encodeV2(IFastBridgeV2.BridgeTransactionV2 memory bridgeTx) internal pure returns (bytes memory) {\n // We split the encoding into two parts to avoid stack-too-deep error\n bytes memory firstPart = abi.encodePacked(\n VERSION,\n bridgeTx.originChainId,\n bridgeTx.destChainId,\n bridgeTx.originSender,\n bridgeTx.destRecipient,\n bridgeTx.originToken,\n bridgeTx.destToken,\n bridgeTx.originAmount\n );\n return abi.encodePacked(\n firstPart,\n bridgeTx.destAmount,\n bridgeTx.originFeeAmount,\n // Note: we skip the deprecated `sendChainGas` flag, which was present in BridgeTransaction V1\n bridgeTx.deadline,\n bridgeTx.nonce,\n // New V2 fields: exclusivity\n bridgeTx.exclusivityRelayer,\n bridgeTx.exclusivityEndTime,\n // New V2 fields: Zap\n bridgeTx.zapNative,\n bridgeTx.zapData\n );\n }\n\n /// @notice Decodes the BridgeTransactionV2 struct from the encoded transaction.\n /// @dev Encoded BridgeTransactionV2 struct must be tightly packed.\n /// Use `validateV2` before decoding to ensure the encoded transaction is valid.\n function decodeV2(bytes calldata encodedTx)\n internal\n pure\n returns (IFastBridgeV2.BridgeTransactionV2 memory bridgeTx)\n {\n bridgeTx.originChainId = originChainId(encodedTx);\n bridgeTx.destChainId = destChainId(encodedTx);\n bridgeTx.originSender = originSender(encodedTx);\n bridgeTx.destRecipient = destRecipient(encodedTx);\n bridgeTx.originToken = originToken(encodedTx);\n bridgeTx.destToken = destToken(encodedTx);\n bridgeTx.originAmount = originAmount(encodedTx);\n bridgeTx.destAmount = destAmount(encodedTx);\n bridgeTx.originFeeAmount = originFeeAmount(encodedTx);\n bridgeTx.deadline = deadline(encodedTx);\n bridgeTx.nonce = nonce(encodedTx);\n bridgeTx.exclusivityRelayer = exclusivityRelayer(encodedTx);\n bridgeTx.exclusivityEndTime = exclusivityEndTime(encodedTx);\n bridgeTx.zapNative = zapNative(encodedTx);\n bridgeTx.zapData = zapData(encodedTx);\n }\n\n /// @notice Extracts the version from the encoded transaction.\n function version(bytes calldata encodedTx) internal pure returns (uint16 version_) {\n // Load 32 bytes from the start and shift it 240 bits to the right to get the highest 16 bits.\n assembly {\n version_ := shr(240, calldataload(encodedTx.offset))\n }\n }\n\n /// @notice Extracts the origin chain ID from the encoded transaction.\n function originChainId(bytes calldata encodedTx) internal pure returns (uint32 originChainId_) {\n // Load 32 bytes from the offset and shift it 224 bits to the right to get the highest 32 bits.\n assembly {\n originChainId_ := shr(224, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_CHAIN_ID)))\n }\n }\n\n /// @notice Extracts the destination chain ID from the encoded transaction.\n function destChainId(bytes calldata encodedTx) internal pure returns (uint32 destChainId_) {\n // Load 32 bytes from the offset and shift it 224 bits to the right to get the highest 32 bits.\n assembly {\n destChainId_ := shr(224, calldataload(add(encodedTx.offset, OFFSET_DEST_CHAIN_ID)))\n }\n }\n\n /// @notice Extracts the origin sender from the encoded transaction.\n function originSender(bytes calldata encodedTx) internal pure returns (address originSender_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n originSender_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_SENDER)))\n }\n }\n\n /// @notice Extracts the destination recipient from the encoded transaction.\n function destRecipient(bytes calldata encodedTx) internal pure returns (address destRecipient_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n destRecipient_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_DEST_RECIPIENT)))\n }\n }\n\n /// @notice Extracts the origin token from the encoded transaction.\n function originToken(bytes calldata encodedTx) internal pure returns (address originToken_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n originToken_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_TOKEN)))\n }\n }\n\n /// @notice Extracts the destination token from the encoded transaction.\n function destToken(bytes calldata encodedTx) internal pure returns (address destToken_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n destToken_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_DEST_TOKEN)))\n }\n }\n\n /// @notice Extracts the origin amount from the encoded transaction.\n function originAmount(bytes calldata encodedTx) internal pure returns (uint256 originAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n originAmount_ := calldataload(add(encodedTx.offset, OFFSET_ORIGIN_AMOUNT))\n }\n }\n\n /// @notice Extracts the destination amount from the encoded transaction.\n function destAmount(bytes calldata encodedTx) internal pure returns (uint256 destAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n destAmount_ := calldataload(add(encodedTx.offset, OFFSET_DEST_AMOUNT))\n }\n }\n\n /// @notice Extracts the origin fee amount from the encoded transaction.\n function originFeeAmount(bytes calldata encodedTx) internal pure returns (uint256 originFeeAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n originFeeAmount_ := calldataload(add(encodedTx.offset, OFFSET_ORIGIN_FEE_AMOUNT))\n }\n }\n\n /// @notice Extracts the deadline from the encoded transaction.\n function deadline(bytes calldata encodedTx) internal pure returns (uint256 deadline_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n deadline_ := calldataload(add(encodedTx.offset, OFFSET_DEADLINE))\n }\n }\n\n /// @notice Extracts the nonce from the encoded transaction.\n function nonce(bytes calldata encodedTx) internal pure returns (uint256 nonce_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n nonce_ := calldataload(add(encodedTx.offset, OFFSET_NONCE))\n }\n }\n\n /// @notice Extracts the exclusivity relayer from the encoded transaction.\n function exclusivityRelayer(bytes calldata encodedTx) internal pure returns (address exclusivityRelayer_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n exclusivityRelayer_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_EXCLUSIVITY_RELAYER)))\n }\n }\n\n /// @notice Extracts the exclusivity end time from the encoded transaction.\n function exclusivityEndTime(bytes calldata encodedTx) internal pure returns (uint256 exclusivityEndTime_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n exclusivityEndTime_ := calldataload(add(encodedTx.offset, OFFSET_EXCLUSIVITY_END_TIME))\n }\n }\n\n /// @notice Extracts the Zap's native value from the encoded transaction.\n function zapNative(bytes calldata encodedTx) internal pure returns (uint256 zapNative_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n zapNative_ := calldataload(add(encodedTx.offset, OFFSET_ZAP_NATIVE))\n }\n }\n\n /// @notice Extracts the Zap's data from the encoded transaction.\n function zapData(bytes calldata encodedTx) internal pure returns (bytes calldata zapData_) {\n zapData_ = encodedTx[OFFSET_ZAP_DATA:];\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/AdminV2.sol\n\ncontract AdminV2 is AccessControlEnumerable, IAdminV2, IAdminV2Errors {\n using SafeERC20 for IERC20;\n\n /// @notice Address reserved for native gas token (ETH on Ethereum and most L2s, AVAX on Avalanche, etc)\n address public constant NATIVE_GAS_TOKEN = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Role identifier for Quoter API's off-chain authentication.\n /// @dev Only addresses with this role can post FastBridge quotes to the API.\n bytes32 public constant QUOTER_ROLE = keccak256(\"QUOTER_ROLE\");\n\n /// @notice Role identifier for Prover's on-chain authentication in FastBridge.\n /// @dev Only addresses with this role can provide proofs that a FastBridge request has been relayed.\n bytes32 public constant PROVER_ROLE = keccak256(\"PROVER_ROLE\");\n\n /// @notice Role identifier for Guard's on-chain authentication in FastBridge.\n /// @dev Only addresses with this role can dispute submitted relay proofs during the dispute period.\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n\n /// @notice Role identifier for Canceler's on-chain authentication in FastBridge.\n /// @dev Only addresses with this role can cancel a FastBridge transaction without the cancel delay.\n bytes32 public constant CANCELER_ROLE = keccak256(\"CANCELER_ROLE\");\n\n /// @notice Role identifier for Governor's on-chain administrative authority.\n /// @dev Only addresses with this role can perform administrative tasks within the contract.\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n /// @notice Denominator for fee rates, represents 100%.\n uint256 public constant FEE_BPS = 1e6;\n /// @notice Maximum protocol fee rate: 1% on origin amount.\n uint256 public constant FEE_RATE_MAX = 0.01e6;\n\n /// @notice Minimum cancel delay that can be set by the governor.\n uint256 public constant MIN_CANCEL_DELAY = 1 hours;\n /// @notice Default cancel delay set during the contract deployment.\n uint256 public constant DEFAULT_CANCEL_DELAY = 1 days;\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Delay for a transaction after which it could be permisionlessly cancelled\n uint256 public cancelDelay;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Use ZapNative V2 requests instead.\n uint256 public immutable chainGasAmount = 0;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n _setCancelDelay(DEFAULT_CANCEL_DELAY);\n }\n\n /// @notice Allows the contract governor to set the cancel delay. The cancel delay is the time after the transaction\n /// deadline after which it can be permissionlessly cancelled, if it hasn't been proven by any of the Relayers.\n function setCancelDelay(uint256 newCancelDelay) external onlyRole(GOVERNOR_ROLE) {\n _setCancelDelay(newCancelDelay);\n }\n\n /// @notice Allows the contract governor to set the protocol fee rate. The protocol fee is taken from the origin\n /// amount only for completed and claimed transactions.\n /// @dev The protocol fee is abstracted away from the relayers, they always operate using the amounts after fees:\n /// what they see as the origin amount emitted in the log is what they get credited with.\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n if (newFeeRate \u003e FEE_RATE_MAX) revert FeeRateAboveMax();\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n /// @notice Allows the contract governor to sweep the accumulated protocol fees in the contract.\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n emit FeesSwept(token, recipient, feeAmount);\n /// Sweep the fees as the last transaction action\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(recipient), feeAmount);\n } else {\n IERC20(token).safeTransfer(recipient, feeAmount);\n }\n }\n\n /// @notice Internal function to set the cancel delay. Security checks are performed outside of this function.\n function _setCancelDelay(uint256 newCancelDelay) private {\n if (newCancelDelay \u003c MIN_CANCEL_DELAY) revert CancelDelayBelowMin();\n uint256 oldCancelDelay = cancelDelay;\n cancelDelay = newCancelDelay;\n emit CancelDelayUpdated(oldCancelDelay, newCancelDelay);\n }\n}\n\n// contracts/FastBridgeV2.sol\n\n/// @notice FastBridgeV2 is a contract for bridging tokens across chains.\ncontract FastBridgeV2 is AdminV2, MulticallTarget, IFastBridgeV2, IFastBridgeV2Errors {\n using BridgeTransactionV2Lib for bytes;\n using SafeERC20 for IERC20;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n /// @notice Maximum length of accepted zapData\n uint256 public constant MAX_ZAP_DATA_LENGTH = 2 ** 16 - 1;\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeTxDetails) public bridgeTxDetails;\n /// @notice Relay details on destination chain\n mapping(bytes32 =\u003e BridgeRelay) public bridgeRelayDetails;\n /// @notice Unique bridge nonces tracked per originSender\n mapping(address =\u003e uint256) public senderNonces;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Replaced by senderNonces\n uint256 public immutable nonce = 0;\n /// @notice the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) AdminV2(_owner) {\n deployBlock = block.number;\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n bridge({\n params: params,\n paramsV2: BridgeParamsV2({\n quoteRelayer: address(0),\n quoteExclusivitySeconds: 0,\n quoteId: bytes(\"\"),\n zapNative: 0,\n zapData: bytes(\"\")\n })\n });\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes calldata request) external payable {\n // relay override will validate the request\n relay({request: request, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes calldata request, bytes32 destTxHash) external {\n request.validateV2();\n prove({transactionId: keccak256(request), destTxHash: destTxHash, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridgeV2\n function claim(bytes calldata request) external {\n // claim override will validate the request\n claim({request: request, to: address(0)});\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Aggregate the read operations from the same storage slot\n address disputedRelayer = $.proofRelayer;\n BridgeStatus status = $.status;\n uint56 proofBlockTimestamp = $.proofBlockTimestamp;\n // Can only dispute a RELAYER_PROVED transaction within the dispute period\n if (status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(proofBlockTimestamp) \u003e DISPUTE_PERIOD) {\n revert DisputePeriodPassed();\n }\n // Update status to REQUESTED and delete the disputed proof details\n // Note: these are storage writes\n $.status = BridgeStatus.REQUESTED;\n $.proofRelayer = address(0);\n $.proofBlockTimestamp = 0;\n\n emit BridgeProofDisputed(transactionId, disputedRelayer);\n }\n\n /// Note: this function is deprecated and will be removed in a future version.\n /// @inheritdoc IFastBridge\n function refund(bytes calldata request) external {\n cancel(request);\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // The correct relayer can only claim a RELAYER_PROVED transaction after the dispute period\n if ($.status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if ($.proofRelayer != relayer) revert SenderIncorrect();\n return _timeSince($.proofBlockTimestamp) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n /// @dev This method is added to achieve backwards compatibility with decoding requests into V1 structs:\n /// - `zapNative` is partially reported as a zero/non-zero flag\n /// - `zapData` is ignored\n /// In order to process all kinds of requests use getBridgeTransactionV2 instead.\n function getBridgeTransaction(bytes calldata request) external view returns (BridgeTransaction memory) {\n // Try decoding into V2 struct first. This will revert if V1 struct is passed\n try this.getBridgeTransactionV2(request) returns (BridgeTransactionV2 memory txV2) {\n // Note: we entirely ignore the zapData field, as it was not present in V1\n return BridgeTransaction({\n originChainId: txV2.originChainId,\n destChainId: txV2.destChainId,\n originSender: txV2.originSender,\n destRecipient: txV2.destRecipient,\n originToken: txV2.originToken,\n destToken: txV2.destToken,\n originAmount: txV2.originAmount,\n destAmount: txV2.destAmount,\n originFeeAmount: txV2.originFeeAmount,\n sendChainGas: txV2.zapNative != 0,\n deadline: txV2.deadline,\n nonce: txV2.nonce\n });\n } catch {\n // Fallback to V1 struct\n return abi.decode(request, (BridgeTransaction));\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function getBridgeTransactionV2(bytes calldata request) external pure returns (BridgeTransactionV2 memory) {\n request.validateV2();\n return BridgeTransactionV2Lib.decodeV2(request);\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) public payable {\n int256 exclusivityEndTime = 0;\n // if relayer exclusivity is not intended for this bridge, set exclusivityEndTime to static zero\n // otherwise, set exclusivity to expire at the current block ts offset by quoteExclusivitySeconds\n if (paramsV2.quoteRelayer != address(0)) {\n exclusivityEndTime = int256(block.timestamp) + paramsV2.quoteExclusivitySeconds;\n }\n _validateBridgeParams(params, paramsV2, exclusivityEndTime);\n\n // transfer tokens to bridge contract\n /// @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _takeBridgedUserAsset(params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) {\n originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n }\n\n // set status to requested\n bytes memory request = BridgeTransactionV2Lib.encodeV2(\n BridgeTransactionV2({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n deadline: params.deadline,\n nonce: senderNonces[params.sender]++, // increment nonce on every bridge\n exclusivityRelayer: paramsV2.quoteRelayer,\n // We checked exclusivityEndTime to be in range [0 .. params.deadline] above, so can safely cast\n exclusivityEndTime: uint256(exclusivityEndTime),\n zapNative: paramsV2.zapNative,\n zapData: paramsV2.zapData\n })\n );\n bytes32 transactionId = keccak256(request);\n // Note: the tx status will be updated throughout the tx lifecycle, while destChainId is set once here\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n bridgeTxDetails[transactionId].destChainId = params.dstChainId;\n\n emit BridgeRequested({\n transactionId: transactionId,\n sender: params.sender,\n request: request,\n destChainId: params.dstChainId,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n sendChainGas: paramsV2.zapNative != 0\n });\n emit BridgeQuoteDetails(transactionId, paramsV2.quoteId);\n }\n\n /// @inheritdoc IFastBridgeV2\n function relay(bytes calldata request, address relayer) public payable {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n _validateRelayParams(request, transactionId, relayer);\n // mark bridge transaction as relayed\n bridgeRelayDetails[transactionId] =\n BridgeRelay({blockNumber: uint48(block.number), blockTimestamp: uint48(block.timestamp), relayer: relayer});\n\n // transfer tokens to recipient on destination chain and trigger Zap if requested\n address to = request.destRecipient();\n address token = request.destToken();\n uint256 amount = request.destAmount();\n uint256 zapNative = request.zapNative();\n\n // Emit the event before any external calls\n emit BridgeRelayed({\n transactionId: transactionId,\n relayer: relayer,\n to: to,\n originChainId: request.originChainId(),\n originToken: request.originToken(),\n destToken: token,\n originAmount: request.originAmount(),\n destAmount: amount,\n chainGasAmount: zapNative\n });\n\n // All state changes have been done at this point, can proceed to the external calls.\n // This follows the checks-effects-interactions pattern to mitigate potential reentrancy attacks.\n if (token == NATIVE_GAS_TOKEN) {\n // For the native gas token, additional zapNative is not allowed\n if (zapNative != 0) revert ZapNativeNotSupported();\n // Check that the correct msg.value was sent\n if (msg.value != amount) revert MsgValueIncorrect();\n // Don't do a native transfer yet: we will handle it alongside the Zap below\n } else {\n // For ERC20s, we check that the correct msg.value was sent\n if (msg.value != zapNative) revert MsgValueIncorrect();\n // We need to transfer the tokens from the Relayer to the recipient first before performing an\n // optional post-transfer Zap.\n IERC20(token).safeTransferFrom(msg.sender, to, amount);\n }\n // At this point we have done:\n // - Transferred the requested amount of ERC20 tokens to the recipient.\n // At this point we have confirmed:\n // - For ERC20s: msg.value matches the requested zapNative amount.\n // - For the native gas token: msg.value matches the requested destAmount.\n // Remaining optional things to do:\n // - Forward the full msg.value to the recipient (if non-zero).\n // - Trigger a Zap (if zapData is present).\n bytes calldata zapData = request.zapData();\n if (zapData.length != 0) {\n // Zap Data is present: Zap has been requested by the recipient. Trigger it forwarding the full msg.value.\n\n // Note: if token has a fee on transfers, the recipient will have received less than `amount`.\n // This is a very niche edge case and should be handled by the recipient contract.\n _triggerZapWithChecks({recipient: to, token: token, amount: amount, zapData: zapData});\n } else if (msg.value != 0) {\n // Zap Data is missing, but msg.value was sent. This could happen in two different cases:\n // - Relay with the native gas token is happening.\n // - Relay with ERC20 is happening, with a `zapNative \u003e 0` request.\n // In both cases, we need to transfer the full msg.value to the recipient.\n Address.sendValue(payable(to), msg.value);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) public onlyRole(PROVER_ROLE) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n\n // Can only prove a REQUESTED transaction\n if ($.status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n // Update status to RELAYER_PROVED and store the proof details\n // Note: these are storage writes\n $.status = BridgeStatus.RELAYER_PROVED;\n $.proofBlockTimestamp = uint56(block.timestamp);\n $.proofRelayer = relayer;\n\n emit BridgeProofProvided(transactionId, relayer, destTxHash);\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes calldata request, address to) public {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Aggregate the read operations from the same storage slot\n address proofRelayer = $.proofRelayer;\n BridgeStatus status = $.status;\n uint56 proofBlockTimestamp = $.proofBlockTimestamp;\n\n // Can only claim a RELAYER_PROVED transaction after the dispute period\n if (status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(proofBlockTimestamp) \u003c= DISPUTE_PERIOD) {\n revert DisputePeriodNotPassed();\n }\n\n if (to == address(0)) {\n // Anyone could claim the funds to the proven relayer on their behalf\n to = proofRelayer;\n } else if (proofRelayer != msg.sender) {\n // Only the proven relayer could specify an address to claim the funds to\n revert SenderIncorrect();\n }\n\n // Update status to RELAYER_CLAIMED and transfer the origin collateral to the specified claim address\n // Note: this is a storage write\n $.status = BridgeStatus.RELAYER_CLAIMED;\n\n address token = request.originToken();\n uint256 amount = request.originAmount();\n // Update protocol fees if origin fee amount exists\n uint256 originFeeAmount = request.originFeeAmount();\n if (originFeeAmount \u003e 0) protocolFees[token] += originFeeAmount;\n // Emit the event before any external calls\n emit BridgeDepositClaimed(transactionId, proofRelayer, to, token, amount);\n // Complete the relayer claim as the last transaction action\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(to), amount);\n } else {\n IERC20(token).safeTransfer(to, amount);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function cancel(bytes calldata request) public {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Can only cancel a REQUESTED transaction after its deadline expires\n if ($.status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n uint256 deadline = request.deadline();\n // Permissionless cancel is only allowed after `cancelDelay` on top of the deadline\n if (!hasRole(CANCELER_ROLE, msg.sender)) deadline += cancelDelay;\n if (block.timestamp \u003c= deadline) revert DeadlineNotExceeded();\n // Update status to REFUNDED and return the full amount (collateral + protocol fees) to the original sender.\n // The protocol fees are only updated when the transaction is claimed, so we don't need to update them here.\n // Note: this is a storage write\n $.status = BridgeStatus.REFUNDED;\n\n address to = request.originSender();\n address token = request.originToken();\n uint256 amount = request.originAmount() + request.originFeeAmount();\n // Emit the event before any external calls\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n // Complete the user cancel as the last transaction action\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(to), amount);\n } else {\n IERC20(token).safeTransfer(to, amount);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeStatuses(bytes32 transactionId) public view returns (BridgeStatus status) {\n return bridgeTxDetails[transactionId].status;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeProofs(bytes32 transactionId) public view returns (uint96 timestamp, address relayer) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n\n timestamp = $.proofBlockTimestamp;\n relayer = $.proofRelayer;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeRelays(bytes32 transactionId) public view returns (bool) {\n // has this transactionId been relayed?\n return bridgeRelayDetails[transactionId].relayer != address(0);\n }\n\n /// @notice Takes the bridged asset from the user into FastBridgeV2 custody. It will be later\n /// claimed by the relayer who completed the relay on destination chain, or transferred back to the user\n /// via the cancel function should no one complete the relay.\n function _takeBridgedUserAsset(address token, uint256 amount) internal returns (uint256 amountTaken) {\n if (token == NATIVE_GAS_TOKEN) {\n // For the native gas token, we just need to check that the supplied msg.value is correct.\n // Supplied `msg.value` is already in FastBridgeV2 custody.\n if (amount != msg.value) revert MsgValueIncorrect();\n amountTaken = msg.value;\n } else {\n // For ERC20s, token is explicitly transferred from the user to FastBridgeV2.\n // We don't allow non-zero `msg.value` to avoid extra funds from being stuck in FastBridgeV2.\n if (msg.value != 0) revert MsgValueIncorrect();\n // Throw an explicit error if the provided token address is not a contract\n if (token.code.length == 0) revert TokenNotContract();\n amountTaken = IERC20(token).balanceOf(address(this));\n IERC20(token).safeTransferFrom(msg.sender, address(this), amount);\n // Use the balance difference as the amount taken in case of fee on transfer tokens.\n amountTaken = IERC20(token).balanceOf(address(this)) - amountTaken;\n }\n }\n\n /// @notice Calls the Recipient's hook function with the specified zapData and performs\n /// all the necessary checks for the returned value.\n function _triggerZapWithChecks(address recipient, address token, uint256 amount, bytes calldata zapData) internal {\n // This will bubble any revert messages from the hook function\n bytes memory returnData = Address.functionCallWithValue({\n target: recipient,\n data: abi.encodeCall(IZapRecipient.zap, (token, amount, zapData)),\n // Note: see `relay()` for reasoning behind passing msg.value\n value: msg.value\n });\n // Explicit revert if no return data at all\n if (returnData.length == 0) revert RecipientNoReturnValue();\n // Check that exactly a single return value was returned\n if (returnData.length != 32) revert RecipientIncorrectReturnValue();\n // Return value should be abi-encoded hook function selector\n if (bytes32(returnData) != bytes32(IZapRecipient.zap.selector)) {\n revert RecipientIncorrectReturnValue();\n }\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint56(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint56).max but\n /// proof.timestamp \u003c type(uint56).max via unchecked statement\n /// @param proofBlockTimestamp The bridge proof block timestamp\n /// @return delta Time delta since proof submitted\n function _timeSince(uint56 proofBlockTimestamp) internal view returns (uint256 delta) {\n unchecked {\n delta = uint56(block.timestamp) - proofBlockTimestamp;\n }\n }\n\n /// @notice Performs all the necessary checks for a bridge to happen.\n /// @dev There's no good way to refactor this function to reduce cyclomatic complexity due to\n /// the number of checks that need to be performed, so we skip the code-complexity rule here.\n // solhint-disable-next-line code-complexity\n function _validateBridgeParams(\n BridgeParams memory params,\n BridgeParamsV2 memory paramsV2,\n int256 exclusivityEndTime\n )\n internal\n view\n {\n // Check V1 (legacy) params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.sender == address(0) || params.to == address(0)) revert ZeroAddress();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n // Check V2 params\n if (paramsV2.zapData.length \u003e MAX_ZAP_DATA_LENGTH) revert ZapDataLengthAboveMax();\n if (paramsV2.zapNative != 0 \u0026\u0026 params.destToken == NATIVE_GAS_TOKEN) {\n revert ZapNativeNotSupported();\n }\n // exclusivityEndTime must be in range [0 .. params.deadline]\n if (exclusivityEndTime \u003c 0 || exclusivityEndTime \u003e int256(params.deadline)) {\n revert ExclusivityParamsIncorrect();\n }\n }\n\n /// @notice Performs all the necessary checks for a relay to happen.\n function _validateRelayParams(bytes calldata request, bytes32 transactionId, address relayer) internal view {\n if (relayer == address(0)) revert ZeroAddress();\n // Check if the transaction has already been relayed\n if (bridgeRelays(transactionId)) revert TransactionRelayed();\n if (request.destChainId() != block.chainid) revert ChainIncorrect();\n // Check the deadline for relay to happen\n if (block.timestamp \u003e request.deadline()) revert DeadlineExceeded();\n // Check the exclusivity period, if it is still ongoing\n address exclRelayer = request.exclusivityRelayer();\n if (exclRelayer != address(0) \u0026\u0026 exclRelayer != relayer \u0026\u0026 block.timestamp \u003c= request.exclusivityEndTime()) {\n revert ExclusivityPeriodNotPassed();\n }\n }\n}\n","language":"Solidity","languageVersion":"0.8.24","compilerVersion":"0.8.24","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"","srcMapRuntime":"","abiDefinition":[{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"bytes","name":"zapData","type":"bytes"}],"name":"zap","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"payable","type":"function"}],"userDoc":{"kind":"user","methods":{},"version":1},"developerDoc":{"kind":"dev","methods":{},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"zapData\",\"type\":\"bytes\"}],\"name\":\"zap\",\"outputs\":[{\"internalType\":\"bytes4\",\"name\":\"\",\"type\":\"bytes4\"}],\"stateMutability\":\"payable\",\"type\":\"function\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeV2.sol\":\"IZapRecipient\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeV2.sol\":{\"keccak256\":\"0xac79c463688a682ca706a4ef95e7817b83548cdfa8182ba0426ac7e5e07613d8\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://b3ecb7097381287cafc3a73f3a2bb03565115ebb682a85064e0b0dc2f7e2919d\",\"dweb:/ipfs/QmatruW3nYZTksf3CeQ8wwiAG4c7xoEJBEp6drHPtFLBRK\"]}},\"version\":1}"},"hashes":{"zap(address,uint256,bytes)":"e85e13dd"}},"solidity/FastBridgeV2.sol:MulticallTarget":{"code":"0x","runtime-code":"0x","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.24 ^0.8.20 ^0.8.4;\n\n// contracts/interfaces/IAdminV2.sol\n\ninterface IAdminV2 {\n event CancelDelayUpdated(uint256 oldCancelDelay, uint256 newCancelDelay);\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n function setCancelDelay(uint256 newCancelDelay) external;\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n}\n\n// contracts/interfaces/IAdminV2Errors.sol\n\ninterface IAdminV2Errors {\n error CancelDelayBelowMin();\n error FeeRateAboveMax();\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IFastBridgeV2Errors.sol\n\ninterface IFastBridgeV2Errors {\n error AmountIncorrect();\n error ChainIncorrect();\n error ExclusivityParamsIncorrect();\n error MsgValueIncorrect();\n error SenderIncorrect();\n error StatusIncorrect();\n error TokenNotContract();\n error ZapDataLengthAboveMax();\n error ZapNativeNotSupported();\n error ZeroAddress();\n\n error RecipientIncorrectReturnValue();\n error RecipientNoReturnValue();\n\n error DeadlineExceeded();\n error DeadlineNotExceeded();\n error DeadlineTooShort();\n error DisputePeriodNotPassed();\n error DisputePeriodPassed();\n error ExclusivityPeriodNotPassed();\n\n error TransactionRelayed();\n}\n\n// contracts/interfaces/IMulticallTarget.sol\n\n/// @notice Interface for a contract that can be called multiple times by the same caller. Inspired by MulticallV3:\n/// https://github.com/mds1/multicall/blob/master/src/Multicall3.sol\ninterface IMulticallTarget {\n struct Result {\n bool success;\n bytes returnData;\n }\n\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external;\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results);\n}\n\n// contracts/interfaces/IZapRecipient.sol\n\ninterface IZapRecipient {\n function zap(address token, uint256 amount, bytes memory zapData) external payable returns (bytes4);\n}\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// contracts/interfaces/IFastBridgeV2.sol\n\ninterface IFastBridgeV2 is IFastBridge {\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n struct BridgeTxDetails {\n BridgeStatus status;\n uint32 destChainId;\n uint56 proofBlockTimestamp;\n address proofRelayer;\n }\n\n struct BridgeRelay {\n uint48 blockNumber;\n uint48 blockTimestamp;\n address relayer;\n }\n\n /// @notice New params introduced in the FastBridgeV2.\n /// We are passing fields from the older BridgeParams struct outside of this struct\n /// for backwards compatibility.\n /// Note: quoteRelayer and quoteExclusivitySeconds are either both zero (indicating no exclusivity)\n /// or both non-zero (indicating exclusivity for the given period).\n /// Note: zapNative \u003e 0 can NOT be used with destToken = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE (native token)\n /// @param quoteRelayer Relayer that provided the quote for the transaction\n /// @param quoteExclusivitySeconds Period of time the quote relayer is guaranteed exclusivity after user's deposit\n /// @param quoteId Unique quote identifier used for tracking the quote\n /// @param zapNative ETH value to send to the recipient (if any)\n /// @param zapData Parameters for the Zap to the destination recipient (if any)\n struct BridgeParamsV2 {\n address quoteRelayer;\n int256 quoteExclusivitySeconds;\n bytes quoteId;\n uint256 zapNative;\n bytes zapData;\n }\n\n /// @notice Updated bridge transaction struct to include parameters introduced in FastBridgeV2.\n /// Note: only `exclusivityRelayer` can fill such a transaction until `exclusivityEndTime`.\n struct BridgeTransactionV2 {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n // Note: sendChainGas flag from V1 is deprecated\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n address exclusivityRelayer;\n uint256 exclusivityEndTime;\n uint256 zapNative; // ETH value to send to the recipient (if any)\n bytes zapData; // data to pass for the Zap action (if any)\n }\n\n event BridgeQuoteDetails(bytes32 indexed transactionId, bytes quoteId);\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability\n /// to provide temporary exclusivity fill rights for the quote relayer.\n /// @param params The parameters required to bridge\n /// @param paramsV2 The parameters for exclusivity fill rights (optional, can be left empty)\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function relay(bytes memory request, address relayer) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param transactionId The transaction id associated with the encoded bridge transaction to prove\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital.\n /// @notice Can only send funds to the relayer address on the proof.\n /// @param request The encoded bridge transaction to claim on origin chain\n function claim(bytes memory request) external;\n\n /// @notice Cancels an outstanding bridge transaction in case optimistic bridging failed and returns the full amount\n /// to the original sender.\n /// @param request The encoded bridge transaction to refund\n function cancel(bytes memory request) external;\n\n /// @notice Checks if a transaction has been relayed\n /// @param transactionId The ID of the transaction to check\n /// @return True if the transaction has been relayed, false otherwise\n function bridgeRelays(bytes32 transactionId) external view returns (bool);\n\n /// @notice Returns the status of a bridge transaction\n /// @param transactionId The ID of the bridge transaction\n /// @return BridgeStatus Status of the bridge transaction\n function bridgeStatuses(bytes32 transactionId) external view returns (BridgeStatus);\n\n /// @notice Returns the timestamp and relayer of a bridge proof\n /// @param transactionId The ID of the bridge transaction\n /// @return timestamp The timestamp of the bridge proof\n /// @return relayer The relayer address of the bridge proof\n function bridgeProofs(bytes32 transactionId) external view returns (uint96 timestamp, address relayer);\n\n /// @notice Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\n /// @param request The bridge request to decode\n function getBridgeTransactionV2(bytes memory request) external view returns (BridgeTransactionV2 memory);\n}\n\n// contracts/utils/MulticallTarget.sol\n\n// solhint-disable avoid-low-level-calls\n/// @notice Template for a contract that supports batched calls (preserving the msg.sender).\n/// Only calls with zero msg.value could be batched.\nabstract contract MulticallTarget is IMulticallTarget {\n error MulticallTarget__UndeterminedRevert();\n\n /// @notice Perform a batched call to this contract, preserving the msg.sender.\n /// The return data from each call is discarded.\n /// @dev The method is non-payable, so only calls with `msg.value == 0` could be batched.\n /// It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag.\n /// Otherwise, the whole batch call will be reverted with the original revert reason.\n /// @param data List of abi-encoded calldata for the calls to perform.\n /// @param ignoreReverts Whether to ignore the revert errors from the calls.\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external {\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\n if (!success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(result);\n }\n }\n }\n\n /// @notice Perform a batched call to this contract, preserving the msg.sender.\n /// The return data from each call is preserved.\n /// @dev The method is non-payable, so only calls with `msg.value == 0` could be batched.\n /// It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag.\n /// Otherwise, the whole batch call will be reverted with the original revert reason.\n /// @param data List of abi-encoded calldata for the calls to perform.\n /// @param ignoreReverts Whether to ignore the revert errors from the calls.\n /// @return results List of results from the calls: `(success, returnData)`.\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results)\n {\n results = new Result[](data.length);\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (results[i].success, results[i].returnData) = address(this).delegatecall(data[i]);\n if (!results[i].success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(results[i].returnData);\n }\n }\n }\n\n /// @dev Bubbles the revert message from the underlying call.\n /// Note: preserves the same custom error or revert string, if one was used.\n /// Source: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v5.0.2/contracts/utils/Address.sol#L143-L158\n function _bubbleRevert(bytes memory returnData) internal pure {\n // Look for revert reason and bubble it up if present\n if (returnData.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n // solhint-disable-next-line no-inline-assembly\n assembly {\n let returndata_size := mload(returnData)\n revert(add(32, returnData), returndata_size)\n }\n } else {\n revert MulticallTarget__UndeterminedRevert();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// contracts/libs/BridgeTransactionV2.sol\n\n// solhint-disable no-inline-assembly\nlibrary BridgeTransactionV2Lib {\n uint16 internal constant VERSION = 2;\n\n // Offsets of the fields in the packed BridgeTransactionV2 struct\n // uint16 version [000 .. 002)\n // uint32 originChainId [002 .. 006)\n // uint32 destChainId [006 .. 010)\n // address originSender [010 .. 030)\n // address destRecipient [030 .. 050)\n // address originToken [050 .. 070)\n // address destToken [070 .. 090)\n // uint256 originAmount [090 .. 122)\n // uint256 destAmount [122 .. 154)\n // uint256 originFeeAmount [154 .. 186)\n // uint256 deadline [186 .. 218)\n // uint256 nonce [218 .. 250)\n // address exclusivityRelayer [250 .. 270)\n // uint256 exclusivityEndTime [270 .. 302)\n // uint256 zapNative [302 .. 334)\n // bytes zapData [334 .. ***)\n\n // forgefmt: disable-start\n uint256 private constant OFFSET_ORIGIN_CHAIN_ID = 2;\n uint256 private constant OFFSET_DEST_CHAIN_ID = 6;\n uint256 private constant OFFSET_ORIGIN_SENDER = 10;\n uint256 private constant OFFSET_DEST_RECIPIENT = 30;\n uint256 private constant OFFSET_ORIGIN_TOKEN = 50;\n uint256 private constant OFFSET_DEST_TOKEN = 70;\n uint256 private constant OFFSET_ORIGIN_AMOUNT = 90;\n uint256 private constant OFFSET_DEST_AMOUNT = 122;\n uint256 private constant OFFSET_ORIGIN_FEE_AMOUNT = 154;\n uint256 private constant OFFSET_DEADLINE = 186;\n uint256 private constant OFFSET_NONCE = 218;\n uint256 private constant OFFSET_EXCLUSIVITY_RELAYER = 250;\n uint256 private constant OFFSET_EXCLUSIVITY_END_TIME = 270;\n uint256 private constant OFFSET_ZAP_NATIVE = 302;\n uint256 private constant OFFSET_ZAP_DATA = 334;\n // forgefmt: disable-end\n\n error BridgeTransactionV2__InvalidEncodedTx();\n error BridgeTransactionV2__UnsupportedVersion(uint16 version);\n\n /// @notice Validates the encoded transaction to be a tightly packed encoded payload for BridgeTransactionV2.\n /// @dev Checks the minimum length and the version, use this function before decoding any of the fields.\n function validateV2(bytes calldata encodedTx) internal pure {\n // Check the minimum length: must at least include all static fields.\n if (encodedTx.length \u003c OFFSET_ZAP_DATA) revert BridgeTransactionV2__InvalidEncodedTx();\n // Once we validated the length, we can be sure that the version field is present.\n uint16 version_ = version(encodedTx);\n if (version_ != VERSION) revert BridgeTransactionV2__UnsupportedVersion(version_);\n }\n\n /// @notice Encodes the BridgeTransactionV2 struct by tightly packing the fields.\n /// @dev `abi.decode` will not work as a result of the tightly packed fields. Use `decodeV2` to decode instead.\n function encodeV2(IFastBridgeV2.BridgeTransactionV2 memory bridgeTx) internal pure returns (bytes memory) {\n // We split the encoding into two parts to avoid stack-too-deep error\n bytes memory firstPart = abi.encodePacked(\n VERSION,\n bridgeTx.originChainId,\n bridgeTx.destChainId,\n bridgeTx.originSender,\n bridgeTx.destRecipient,\n bridgeTx.originToken,\n bridgeTx.destToken,\n bridgeTx.originAmount\n );\n return abi.encodePacked(\n firstPart,\n bridgeTx.destAmount,\n bridgeTx.originFeeAmount,\n // Note: we skip the deprecated `sendChainGas` flag, which was present in BridgeTransaction V1\n bridgeTx.deadline,\n bridgeTx.nonce,\n // New V2 fields: exclusivity\n bridgeTx.exclusivityRelayer,\n bridgeTx.exclusivityEndTime,\n // New V2 fields: Zap\n bridgeTx.zapNative,\n bridgeTx.zapData\n );\n }\n\n /// @notice Decodes the BridgeTransactionV2 struct from the encoded transaction.\n /// @dev Encoded BridgeTransactionV2 struct must be tightly packed.\n /// Use `validateV2` before decoding to ensure the encoded transaction is valid.\n function decodeV2(bytes calldata encodedTx)\n internal\n pure\n returns (IFastBridgeV2.BridgeTransactionV2 memory bridgeTx)\n {\n bridgeTx.originChainId = originChainId(encodedTx);\n bridgeTx.destChainId = destChainId(encodedTx);\n bridgeTx.originSender = originSender(encodedTx);\n bridgeTx.destRecipient = destRecipient(encodedTx);\n bridgeTx.originToken = originToken(encodedTx);\n bridgeTx.destToken = destToken(encodedTx);\n bridgeTx.originAmount = originAmount(encodedTx);\n bridgeTx.destAmount = destAmount(encodedTx);\n bridgeTx.originFeeAmount = originFeeAmount(encodedTx);\n bridgeTx.deadline = deadline(encodedTx);\n bridgeTx.nonce = nonce(encodedTx);\n bridgeTx.exclusivityRelayer = exclusivityRelayer(encodedTx);\n bridgeTx.exclusivityEndTime = exclusivityEndTime(encodedTx);\n bridgeTx.zapNative = zapNative(encodedTx);\n bridgeTx.zapData = zapData(encodedTx);\n }\n\n /// @notice Extracts the version from the encoded transaction.\n function version(bytes calldata encodedTx) internal pure returns (uint16 version_) {\n // Load 32 bytes from the start and shift it 240 bits to the right to get the highest 16 bits.\n assembly {\n version_ := shr(240, calldataload(encodedTx.offset))\n }\n }\n\n /// @notice Extracts the origin chain ID from the encoded transaction.\n function originChainId(bytes calldata encodedTx) internal pure returns (uint32 originChainId_) {\n // Load 32 bytes from the offset and shift it 224 bits to the right to get the highest 32 bits.\n assembly {\n originChainId_ := shr(224, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_CHAIN_ID)))\n }\n }\n\n /// @notice Extracts the destination chain ID from the encoded transaction.\n function destChainId(bytes calldata encodedTx) internal pure returns (uint32 destChainId_) {\n // Load 32 bytes from the offset and shift it 224 bits to the right to get the highest 32 bits.\n assembly {\n destChainId_ := shr(224, calldataload(add(encodedTx.offset, OFFSET_DEST_CHAIN_ID)))\n }\n }\n\n /// @notice Extracts the origin sender from the encoded transaction.\n function originSender(bytes calldata encodedTx) internal pure returns (address originSender_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n originSender_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_SENDER)))\n }\n }\n\n /// @notice Extracts the destination recipient from the encoded transaction.\n function destRecipient(bytes calldata encodedTx) internal pure returns (address destRecipient_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n destRecipient_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_DEST_RECIPIENT)))\n }\n }\n\n /// @notice Extracts the origin token from the encoded transaction.\n function originToken(bytes calldata encodedTx) internal pure returns (address originToken_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n originToken_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_TOKEN)))\n }\n }\n\n /// @notice Extracts the destination token from the encoded transaction.\n function destToken(bytes calldata encodedTx) internal pure returns (address destToken_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n destToken_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_DEST_TOKEN)))\n }\n }\n\n /// @notice Extracts the origin amount from the encoded transaction.\n function originAmount(bytes calldata encodedTx) internal pure returns (uint256 originAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n originAmount_ := calldataload(add(encodedTx.offset, OFFSET_ORIGIN_AMOUNT))\n }\n }\n\n /// @notice Extracts the destination amount from the encoded transaction.\n function destAmount(bytes calldata encodedTx) internal pure returns (uint256 destAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n destAmount_ := calldataload(add(encodedTx.offset, OFFSET_DEST_AMOUNT))\n }\n }\n\n /// @notice Extracts the origin fee amount from the encoded transaction.\n function originFeeAmount(bytes calldata encodedTx) internal pure returns (uint256 originFeeAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n originFeeAmount_ := calldataload(add(encodedTx.offset, OFFSET_ORIGIN_FEE_AMOUNT))\n }\n }\n\n /// @notice Extracts the deadline from the encoded transaction.\n function deadline(bytes calldata encodedTx) internal pure returns (uint256 deadline_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n deadline_ := calldataload(add(encodedTx.offset, OFFSET_DEADLINE))\n }\n }\n\n /// @notice Extracts the nonce from the encoded transaction.\n function nonce(bytes calldata encodedTx) internal pure returns (uint256 nonce_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n nonce_ := calldataload(add(encodedTx.offset, OFFSET_NONCE))\n }\n }\n\n /// @notice Extracts the exclusivity relayer from the encoded transaction.\n function exclusivityRelayer(bytes calldata encodedTx) internal pure returns (address exclusivityRelayer_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n exclusivityRelayer_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_EXCLUSIVITY_RELAYER)))\n }\n }\n\n /// @notice Extracts the exclusivity end time from the encoded transaction.\n function exclusivityEndTime(bytes calldata encodedTx) internal pure returns (uint256 exclusivityEndTime_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n exclusivityEndTime_ := calldataload(add(encodedTx.offset, OFFSET_EXCLUSIVITY_END_TIME))\n }\n }\n\n /// @notice Extracts the Zap's native value from the encoded transaction.\n function zapNative(bytes calldata encodedTx) internal pure returns (uint256 zapNative_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n zapNative_ := calldataload(add(encodedTx.offset, OFFSET_ZAP_NATIVE))\n }\n }\n\n /// @notice Extracts the Zap's data from the encoded transaction.\n function zapData(bytes calldata encodedTx) internal pure returns (bytes calldata zapData_) {\n zapData_ = encodedTx[OFFSET_ZAP_DATA:];\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/AdminV2.sol\n\ncontract AdminV2 is AccessControlEnumerable, IAdminV2, IAdminV2Errors {\n using SafeERC20 for IERC20;\n\n /// @notice Address reserved for native gas token (ETH on Ethereum and most L2s, AVAX on Avalanche, etc)\n address public constant NATIVE_GAS_TOKEN = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Role identifier for Quoter API's off-chain authentication.\n /// @dev Only addresses with this role can post FastBridge quotes to the API.\n bytes32 public constant QUOTER_ROLE = keccak256(\"QUOTER_ROLE\");\n\n /// @notice Role identifier for Prover's on-chain authentication in FastBridge.\n /// @dev Only addresses with this role can provide proofs that a FastBridge request has been relayed.\n bytes32 public constant PROVER_ROLE = keccak256(\"PROVER_ROLE\");\n\n /// @notice Role identifier for Guard's on-chain authentication in FastBridge.\n /// @dev Only addresses with this role can dispute submitted relay proofs during the dispute period.\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n\n /// @notice Role identifier for Canceler's on-chain authentication in FastBridge.\n /// @dev Only addresses with this role can cancel a FastBridge transaction without the cancel delay.\n bytes32 public constant CANCELER_ROLE = keccak256(\"CANCELER_ROLE\");\n\n /// @notice Role identifier for Governor's on-chain administrative authority.\n /// @dev Only addresses with this role can perform administrative tasks within the contract.\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n /// @notice Denominator for fee rates, represents 100%.\n uint256 public constant FEE_BPS = 1e6;\n /// @notice Maximum protocol fee rate: 1% on origin amount.\n uint256 public constant FEE_RATE_MAX = 0.01e6;\n\n /// @notice Minimum cancel delay that can be set by the governor.\n uint256 public constant MIN_CANCEL_DELAY = 1 hours;\n /// @notice Default cancel delay set during the contract deployment.\n uint256 public constant DEFAULT_CANCEL_DELAY = 1 days;\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Delay for a transaction after which it could be permisionlessly cancelled\n uint256 public cancelDelay;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Use ZapNative V2 requests instead.\n uint256 public immutable chainGasAmount = 0;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n _setCancelDelay(DEFAULT_CANCEL_DELAY);\n }\n\n /// @notice Allows the contract governor to set the cancel delay. The cancel delay is the time after the transaction\n /// deadline after which it can be permissionlessly cancelled, if it hasn't been proven by any of the Relayers.\n function setCancelDelay(uint256 newCancelDelay) external onlyRole(GOVERNOR_ROLE) {\n _setCancelDelay(newCancelDelay);\n }\n\n /// @notice Allows the contract governor to set the protocol fee rate. The protocol fee is taken from the origin\n /// amount only for completed and claimed transactions.\n /// @dev The protocol fee is abstracted away from the relayers, they always operate using the amounts after fees:\n /// what they see as the origin amount emitted in the log is what they get credited with.\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n if (newFeeRate \u003e FEE_RATE_MAX) revert FeeRateAboveMax();\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n /// @notice Allows the contract governor to sweep the accumulated protocol fees in the contract.\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n emit FeesSwept(token, recipient, feeAmount);\n /// Sweep the fees as the last transaction action\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(recipient), feeAmount);\n } else {\n IERC20(token).safeTransfer(recipient, feeAmount);\n }\n }\n\n /// @notice Internal function to set the cancel delay. Security checks are performed outside of this function.\n function _setCancelDelay(uint256 newCancelDelay) private {\n if (newCancelDelay \u003c MIN_CANCEL_DELAY) revert CancelDelayBelowMin();\n uint256 oldCancelDelay = cancelDelay;\n cancelDelay = newCancelDelay;\n emit CancelDelayUpdated(oldCancelDelay, newCancelDelay);\n }\n}\n\n// contracts/FastBridgeV2.sol\n\n/// @notice FastBridgeV2 is a contract for bridging tokens across chains.\ncontract FastBridgeV2 is AdminV2, MulticallTarget, IFastBridgeV2, IFastBridgeV2Errors {\n using BridgeTransactionV2Lib for bytes;\n using SafeERC20 for IERC20;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n /// @notice Maximum length of accepted zapData\n uint256 public constant MAX_ZAP_DATA_LENGTH = 2 ** 16 - 1;\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeTxDetails) public bridgeTxDetails;\n /// @notice Relay details on destination chain\n mapping(bytes32 =\u003e BridgeRelay) public bridgeRelayDetails;\n /// @notice Unique bridge nonces tracked per originSender\n mapping(address =\u003e uint256) public senderNonces;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Replaced by senderNonces\n uint256 public immutable nonce = 0;\n /// @notice the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) AdminV2(_owner) {\n deployBlock = block.number;\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n bridge({\n params: params,\n paramsV2: BridgeParamsV2({\n quoteRelayer: address(0),\n quoteExclusivitySeconds: 0,\n quoteId: bytes(\"\"),\n zapNative: 0,\n zapData: bytes(\"\")\n })\n });\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes calldata request) external payable {\n // relay override will validate the request\n relay({request: request, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes calldata request, bytes32 destTxHash) external {\n request.validateV2();\n prove({transactionId: keccak256(request), destTxHash: destTxHash, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridgeV2\n function claim(bytes calldata request) external {\n // claim override will validate the request\n claim({request: request, to: address(0)});\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Aggregate the read operations from the same storage slot\n address disputedRelayer = $.proofRelayer;\n BridgeStatus status = $.status;\n uint56 proofBlockTimestamp = $.proofBlockTimestamp;\n // Can only dispute a RELAYER_PROVED transaction within the dispute period\n if (status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(proofBlockTimestamp) \u003e DISPUTE_PERIOD) {\n revert DisputePeriodPassed();\n }\n // Update status to REQUESTED and delete the disputed proof details\n // Note: these are storage writes\n $.status = BridgeStatus.REQUESTED;\n $.proofRelayer = address(0);\n $.proofBlockTimestamp = 0;\n\n emit BridgeProofDisputed(transactionId, disputedRelayer);\n }\n\n /// Note: this function is deprecated and will be removed in a future version.\n /// @inheritdoc IFastBridge\n function refund(bytes calldata request) external {\n cancel(request);\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // The correct relayer can only claim a RELAYER_PROVED transaction after the dispute period\n if ($.status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if ($.proofRelayer != relayer) revert SenderIncorrect();\n return _timeSince($.proofBlockTimestamp) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n /// @dev This method is added to achieve backwards compatibility with decoding requests into V1 structs:\n /// - `zapNative` is partially reported as a zero/non-zero flag\n /// - `zapData` is ignored\n /// In order to process all kinds of requests use getBridgeTransactionV2 instead.\n function getBridgeTransaction(bytes calldata request) external view returns (BridgeTransaction memory) {\n // Try decoding into V2 struct first. This will revert if V1 struct is passed\n try this.getBridgeTransactionV2(request) returns (BridgeTransactionV2 memory txV2) {\n // Note: we entirely ignore the zapData field, as it was not present in V1\n return BridgeTransaction({\n originChainId: txV2.originChainId,\n destChainId: txV2.destChainId,\n originSender: txV2.originSender,\n destRecipient: txV2.destRecipient,\n originToken: txV2.originToken,\n destToken: txV2.destToken,\n originAmount: txV2.originAmount,\n destAmount: txV2.destAmount,\n originFeeAmount: txV2.originFeeAmount,\n sendChainGas: txV2.zapNative != 0,\n deadline: txV2.deadline,\n nonce: txV2.nonce\n });\n } catch {\n // Fallback to V1 struct\n return abi.decode(request, (BridgeTransaction));\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function getBridgeTransactionV2(bytes calldata request) external pure returns (BridgeTransactionV2 memory) {\n request.validateV2();\n return BridgeTransactionV2Lib.decodeV2(request);\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) public payable {\n int256 exclusivityEndTime = 0;\n // if relayer exclusivity is not intended for this bridge, set exclusivityEndTime to static zero\n // otherwise, set exclusivity to expire at the current block ts offset by quoteExclusivitySeconds\n if (paramsV2.quoteRelayer != address(0)) {\n exclusivityEndTime = int256(block.timestamp) + paramsV2.quoteExclusivitySeconds;\n }\n _validateBridgeParams(params, paramsV2, exclusivityEndTime);\n\n // transfer tokens to bridge contract\n /// @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _takeBridgedUserAsset(params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) {\n originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n }\n\n // set status to requested\n bytes memory request = BridgeTransactionV2Lib.encodeV2(\n BridgeTransactionV2({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n deadline: params.deadline,\n nonce: senderNonces[params.sender]++, // increment nonce on every bridge\n exclusivityRelayer: paramsV2.quoteRelayer,\n // We checked exclusivityEndTime to be in range [0 .. params.deadline] above, so can safely cast\n exclusivityEndTime: uint256(exclusivityEndTime),\n zapNative: paramsV2.zapNative,\n zapData: paramsV2.zapData\n })\n );\n bytes32 transactionId = keccak256(request);\n // Note: the tx status will be updated throughout the tx lifecycle, while destChainId is set once here\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n bridgeTxDetails[transactionId].destChainId = params.dstChainId;\n\n emit BridgeRequested({\n transactionId: transactionId,\n sender: params.sender,\n request: request,\n destChainId: params.dstChainId,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n sendChainGas: paramsV2.zapNative != 0\n });\n emit BridgeQuoteDetails(transactionId, paramsV2.quoteId);\n }\n\n /// @inheritdoc IFastBridgeV2\n function relay(bytes calldata request, address relayer) public payable {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n _validateRelayParams(request, transactionId, relayer);\n // mark bridge transaction as relayed\n bridgeRelayDetails[transactionId] =\n BridgeRelay({blockNumber: uint48(block.number), blockTimestamp: uint48(block.timestamp), relayer: relayer});\n\n // transfer tokens to recipient on destination chain and trigger Zap if requested\n address to = request.destRecipient();\n address token = request.destToken();\n uint256 amount = request.destAmount();\n uint256 zapNative = request.zapNative();\n\n // Emit the event before any external calls\n emit BridgeRelayed({\n transactionId: transactionId,\n relayer: relayer,\n to: to,\n originChainId: request.originChainId(),\n originToken: request.originToken(),\n destToken: token,\n originAmount: request.originAmount(),\n destAmount: amount,\n chainGasAmount: zapNative\n });\n\n // All state changes have been done at this point, can proceed to the external calls.\n // This follows the checks-effects-interactions pattern to mitigate potential reentrancy attacks.\n if (token == NATIVE_GAS_TOKEN) {\n // For the native gas token, additional zapNative is not allowed\n if (zapNative != 0) revert ZapNativeNotSupported();\n // Check that the correct msg.value was sent\n if (msg.value != amount) revert MsgValueIncorrect();\n // Don't do a native transfer yet: we will handle it alongside the Zap below\n } else {\n // For ERC20s, we check that the correct msg.value was sent\n if (msg.value != zapNative) revert MsgValueIncorrect();\n // We need to transfer the tokens from the Relayer to the recipient first before performing an\n // optional post-transfer Zap.\n IERC20(token).safeTransferFrom(msg.sender, to, amount);\n }\n // At this point we have done:\n // - Transferred the requested amount of ERC20 tokens to the recipient.\n // At this point we have confirmed:\n // - For ERC20s: msg.value matches the requested zapNative amount.\n // - For the native gas token: msg.value matches the requested destAmount.\n // Remaining optional things to do:\n // - Forward the full msg.value to the recipient (if non-zero).\n // - Trigger a Zap (if zapData is present).\n bytes calldata zapData = request.zapData();\n if (zapData.length != 0) {\n // Zap Data is present: Zap has been requested by the recipient. Trigger it forwarding the full msg.value.\n\n // Note: if token has a fee on transfers, the recipient will have received less than `amount`.\n // This is a very niche edge case and should be handled by the recipient contract.\n _triggerZapWithChecks({recipient: to, token: token, amount: amount, zapData: zapData});\n } else if (msg.value != 0) {\n // Zap Data is missing, but msg.value was sent. This could happen in two different cases:\n // - Relay with the native gas token is happening.\n // - Relay with ERC20 is happening, with a `zapNative \u003e 0` request.\n // In both cases, we need to transfer the full msg.value to the recipient.\n Address.sendValue(payable(to), msg.value);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) public onlyRole(PROVER_ROLE) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n\n // Can only prove a REQUESTED transaction\n if ($.status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n // Update status to RELAYER_PROVED and store the proof details\n // Note: these are storage writes\n $.status = BridgeStatus.RELAYER_PROVED;\n $.proofBlockTimestamp = uint56(block.timestamp);\n $.proofRelayer = relayer;\n\n emit BridgeProofProvided(transactionId, relayer, destTxHash);\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes calldata request, address to) public {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Aggregate the read operations from the same storage slot\n address proofRelayer = $.proofRelayer;\n BridgeStatus status = $.status;\n uint56 proofBlockTimestamp = $.proofBlockTimestamp;\n\n // Can only claim a RELAYER_PROVED transaction after the dispute period\n if (status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(proofBlockTimestamp) \u003c= DISPUTE_PERIOD) {\n revert DisputePeriodNotPassed();\n }\n\n if (to == address(0)) {\n // Anyone could claim the funds to the proven relayer on their behalf\n to = proofRelayer;\n } else if (proofRelayer != msg.sender) {\n // Only the proven relayer could specify an address to claim the funds to\n revert SenderIncorrect();\n }\n\n // Update status to RELAYER_CLAIMED and transfer the origin collateral to the specified claim address\n // Note: this is a storage write\n $.status = BridgeStatus.RELAYER_CLAIMED;\n\n address token = request.originToken();\n uint256 amount = request.originAmount();\n // Update protocol fees if origin fee amount exists\n uint256 originFeeAmount = request.originFeeAmount();\n if (originFeeAmount \u003e 0) protocolFees[token] += originFeeAmount;\n // Emit the event before any external calls\n emit BridgeDepositClaimed(transactionId, proofRelayer, to, token, amount);\n // Complete the relayer claim as the last transaction action\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(to), amount);\n } else {\n IERC20(token).safeTransfer(to, amount);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function cancel(bytes calldata request) public {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Can only cancel a REQUESTED transaction after its deadline expires\n if ($.status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n uint256 deadline = request.deadline();\n // Permissionless cancel is only allowed after `cancelDelay` on top of the deadline\n if (!hasRole(CANCELER_ROLE, msg.sender)) deadline += cancelDelay;\n if (block.timestamp \u003c= deadline) revert DeadlineNotExceeded();\n // Update status to REFUNDED and return the full amount (collateral + protocol fees) to the original sender.\n // The protocol fees are only updated when the transaction is claimed, so we don't need to update them here.\n // Note: this is a storage write\n $.status = BridgeStatus.REFUNDED;\n\n address to = request.originSender();\n address token = request.originToken();\n uint256 amount = request.originAmount() + request.originFeeAmount();\n // Emit the event before any external calls\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n // Complete the user cancel as the last transaction action\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(to), amount);\n } else {\n IERC20(token).safeTransfer(to, amount);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeStatuses(bytes32 transactionId) public view returns (BridgeStatus status) {\n return bridgeTxDetails[transactionId].status;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeProofs(bytes32 transactionId) public view returns (uint96 timestamp, address relayer) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n\n timestamp = $.proofBlockTimestamp;\n relayer = $.proofRelayer;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeRelays(bytes32 transactionId) public view returns (bool) {\n // has this transactionId been relayed?\n return bridgeRelayDetails[transactionId].relayer != address(0);\n }\n\n /// @notice Takes the bridged asset from the user into FastBridgeV2 custody. It will be later\n /// claimed by the relayer who completed the relay on destination chain, or transferred back to the user\n /// via the cancel function should no one complete the relay.\n function _takeBridgedUserAsset(address token, uint256 amount) internal returns (uint256 amountTaken) {\n if (token == NATIVE_GAS_TOKEN) {\n // For the native gas token, we just need to check that the supplied msg.value is correct.\n // Supplied `msg.value` is already in FastBridgeV2 custody.\n if (amount != msg.value) revert MsgValueIncorrect();\n amountTaken = msg.value;\n } else {\n // For ERC20s, token is explicitly transferred from the user to FastBridgeV2.\n // We don't allow non-zero `msg.value` to avoid extra funds from being stuck in FastBridgeV2.\n if (msg.value != 0) revert MsgValueIncorrect();\n // Throw an explicit error if the provided token address is not a contract\n if (token.code.length == 0) revert TokenNotContract();\n amountTaken = IERC20(token).balanceOf(address(this));\n IERC20(token).safeTransferFrom(msg.sender, address(this), amount);\n // Use the balance difference as the amount taken in case of fee on transfer tokens.\n amountTaken = IERC20(token).balanceOf(address(this)) - amountTaken;\n }\n }\n\n /// @notice Calls the Recipient's hook function with the specified zapData and performs\n /// all the necessary checks for the returned value.\n function _triggerZapWithChecks(address recipient, address token, uint256 amount, bytes calldata zapData) internal {\n // This will bubble any revert messages from the hook function\n bytes memory returnData = Address.functionCallWithValue({\n target: recipient,\n data: abi.encodeCall(IZapRecipient.zap, (token, amount, zapData)),\n // Note: see `relay()` for reasoning behind passing msg.value\n value: msg.value\n });\n // Explicit revert if no return data at all\n if (returnData.length == 0) revert RecipientNoReturnValue();\n // Check that exactly a single return value was returned\n if (returnData.length != 32) revert RecipientIncorrectReturnValue();\n // Return value should be abi-encoded hook function selector\n if (bytes32(returnData) != bytes32(IZapRecipient.zap.selector)) {\n revert RecipientIncorrectReturnValue();\n }\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint56(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint56).max but\n /// proof.timestamp \u003c type(uint56).max via unchecked statement\n /// @param proofBlockTimestamp The bridge proof block timestamp\n /// @return delta Time delta since proof submitted\n function _timeSince(uint56 proofBlockTimestamp) internal view returns (uint256 delta) {\n unchecked {\n delta = uint56(block.timestamp) - proofBlockTimestamp;\n }\n }\n\n /// @notice Performs all the necessary checks for a bridge to happen.\n /// @dev There's no good way to refactor this function to reduce cyclomatic complexity due to\n /// the number of checks that need to be performed, so we skip the code-complexity rule here.\n // solhint-disable-next-line code-complexity\n function _validateBridgeParams(\n BridgeParams memory params,\n BridgeParamsV2 memory paramsV2,\n int256 exclusivityEndTime\n )\n internal\n view\n {\n // Check V1 (legacy) params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.sender == address(0) || params.to == address(0)) revert ZeroAddress();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n // Check V2 params\n if (paramsV2.zapData.length \u003e MAX_ZAP_DATA_LENGTH) revert ZapDataLengthAboveMax();\n if (paramsV2.zapNative != 0 \u0026\u0026 params.destToken == NATIVE_GAS_TOKEN) {\n revert ZapNativeNotSupported();\n }\n // exclusivityEndTime must be in range [0 .. params.deadline]\n if (exclusivityEndTime \u003c 0 || exclusivityEndTime \u003e int256(params.deadline)) {\n revert ExclusivityParamsIncorrect();\n }\n }\n\n /// @notice Performs all the necessary checks for a relay to happen.\n function _validateRelayParams(bytes calldata request, bytes32 transactionId, address relayer) internal view {\n if (relayer == address(0)) revert ZeroAddress();\n // Check if the transaction has already been relayed\n if (bridgeRelays(transactionId)) revert TransactionRelayed();\n if (request.destChainId() != block.chainid) revert ChainIncorrect();\n // Check the deadline for relay to happen\n if (block.timestamp \u003e request.deadline()) revert DeadlineExceeded();\n // Check the exclusivity period, if it is still ongoing\n address exclRelayer = request.exclusivityRelayer();\n if (exclRelayer != address(0) \u0026\u0026 exclRelayer != relayer \u0026\u0026 block.timestamp \u003c= request.exclusivityEndTime()) {\n revert ExclusivityPeriodNotPassed();\n }\n }\n}\n","language":"Solidity","languageVersion":"0.8.24","compilerVersion":"0.8.24","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"","srcMapRuntime":"","abiDefinition":[{"inputs":[],"name":"MulticallTarget__UndeterminedRevert","type":"error"},{"inputs":[{"internalType":"bytes[]","name":"data","type":"bytes[]"},{"internalType":"bool","name":"ignoreReverts","type":"bool"}],"name":"multicallNoResults","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes[]","name":"data","type":"bytes[]"},{"internalType":"bool","name":"ignoreReverts","type":"bool"}],"name":"multicallWithResults","outputs":[{"components":[{"internalType":"bool","name":"success","type":"bool"},{"internalType":"bytes","name":"returnData","type":"bytes"}],"internalType":"struct IMulticallTarget.Result[]","name":"results","type":"tuple[]"}],"stateMutability":"nonpayable","type":"function"}],"userDoc":{"kind":"user","methods":{"multicallNoResults(bytes[],bool)":{"notice":"Perform a batched call to this contract, preserving the msg.sender. The return data from each call is discarded."},"multicallWithResults(bytes[],bool)":{"notice":"Perform a batched call to this contract, preserving the msg.sender. The return data from each call is preserved."}},"notice":"Template for a contract that supports batched calls (preserving the msg.sender). Only calls with zero msg.value could be batched.","version":1},"developerDoc":{"kind":"dev","methods":{"multicallNoResults(bytes[],bool)":{"details":"The method is non-payable, so only calls with `msg.value == 0` could be batched. It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag. Otherwise, the whole batch call will be reverted with the original revert reason.","params":{"data":"List of abi-encoded calldata for the calls to perform.","ignoreReverts":"Whether to ignore the revert errors from the calls."}},"multicallWithResults(bytes[],bool)":{"details":"The method is non-payable, so only calls with `msg.value == 0` could be batched. It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag. Otherwise, the whole batch call will be reverted with the original revert reason.","params":{"data":"List of abi-encoded calldata for the calls to perform.","ignoreReverts":"Whether to ignore the revert errors from the calls."},"returns":{"results":" List of results from the calls: `(success, returnData)`."}}},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[],\"name\":\"MulticallTarget__UndeterminedRevert\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"bytes[]\",\"name\":\"data\",\"type\":\"bytes[]\"},{\"internalType\":\"bool\",\"name\":\"ignoreReverts\",\"type\":\"bool\"}],\"name\":\"multicallNoResults\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes[]\",\"name\":\"data\",\"type\":\"bytes[]\"},{\"internalType\":\"bool\",\"name\":\"ignoreReverts\",\"type\":\"bool\"}],\"name\":\"multicallWithResults\",\"outputs\":[{\"components\":[{\"internalType\":\"bool\",\"name\":\"success\",\"type\":\"bool\"},{\"internalType\":\"bytes\",\"name\":\"returnData\",\"type\":\"bytes\"}],\"internalType\":\"struct IMulticallTarget.Result[]\",\"name\":\"results\",\"type\":\"tuple[]\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{\"multicallNoResults(bytes[],bool)\":{\"details\":\"The method is non-payable, so only calls with `msg.value == 0` could be batched. It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag. Otherwise, the whole batch call will be reverted with the original revert reason.\",\"params\":{\"data\":\"List of abi-encoded calldata for the calls to perform.\",\"ignoreReverts\":\"Whether to ignore the revert errors from the calls.\"}},\"multicallWithResults(bytes[],bool)\":{\"details\":\"The method is non-payable, so only calls with `msg.value == 0` could be batched. It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag. Otherwise, the whole batch call will be reverted with the original revert reason.\",\"params\":{\"data\":\"List of abi-encoded calldata for the calls to perform.\",\"ignoreReverts\":\"Whether to ignore the revert errors from the calls.\"},\"returns\":{\"results\":\" List of results from the calls: `(success, returnData)`.\"}}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"multicallNoResults(bytes[],bool)\":{\"notice\":\"Perform a batched call to this contract, preserving the msg.sender. The return data from each call is discarded.\"},\"multicallWithResults(bytes[],bool)\":{\"notice\":\"Perform a batched call to this contract, preserving the msg.sender. The return data from each call is preserved.\"}},\"notice\":\"Template for a contract that supports batched calls (preserving the msg.sender). Only calls with zero msg.value could be batched.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeV2.sol\":\"MulticallTarget\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeV2.sol\":{\"keccak256\":\"0xac79c463688a682ca706a4ef95e7817b83548cdfa8182ba0426ac7e5e07613d8\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://b3ecb7097381287cafc3a73f3a2bb03565115ebb682a85064e0b0dc2f7e2919d\",\"dweb:/ipfs/QmatruW3nYZTksf3CeQ8wwiAG4c7xoEJBEp6drHPtFLBRK\"]}},\"version\":1}"},"hashes":{"multicallNoResults(bytes[],bool)":"3f61331d","multicallWithResults(bytes[],bool)":"385c1d2f"}},"solidity/FastBridgeV2.sol:SafeERC20":{"code":"0x60566037600b82828239805160001a607314602a57634e487b7160e01b600052600060045260246000fd5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600080fdfea2646970667358221220fc15551e7cd0cae1476ceeb26ea6d8e21a222c930b99686cddd49777e215b49764736f6c63430008180033","runtime-code":"0x73000000000000000000000000000000000000000030146080604052600080fdfea2646970667358221220fc15551e7cd0cae1476ceeb26ea6d8e21a222c930b99686cddd49777e215b49764736f6c63430008180033","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.24 ^0.8.20 ^0.8.4;\n\n// contracts/interfaces/IAdminV2.sol\n\ninterface IAdminV2 {\n event CancelDelayUpdated(uint256 oldCancelDelay, uint256 newCancelDelay);\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n function setCancelDelay(uint256 newCancelDelay) external;\n\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n function sweepProtocolFees(address token, address recipient) external;\n}\n\n// contracts/interfaces/IAdminV2Errors.sol\n\ninterface IAdminV2Errors {\n error CancelDelayBelowMin();\n error FeeRateAboveMax();\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IFastBridgeV2Errors.sol\n\ninterface IFastBridgeV2Errors {\n error AmountIncorrect();\n error ChainIncorrect();\n error ExclusivityParamsIncorrect();\n error MsgValueIncorrect();\n error SenderIncorrect();\n error StatusIncorrect();\n error TokenNotContract();\n error ZapDataLengthAboveMax();\n error ZapNativeNotSupported();\n error ZeroAddress();\n\n error RecipientIncorrectReturnValue();\n error RecipientNoReturnValue();\n\n error DeadlineExceeded();\n error DeadlineNotExceeded();\n error DeadlineTooShort();\n error DisputePeriodNotPassed();\n error DisputePeriodPassed();\n error ExclusivityPeriodNotPassed();\n\n error TransactionRelayed();\n}\n\n// contracts/interfaces/IMulticallTarget.sol\n\n/// @notice Interface for a contract that can be called multiple times by the same caller. Inspired by MulticallV3:\n/// https://github.com/mds1/multicall/blob/master/src/Multicall3.sol\ninterface IMulticallTarget {\n struct Result {\n bool success;\n bytes returnData;\n }\n\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external;\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results);\n}\n\n// contracts/interfaces/IZapRecipient.sol\n\ninterface IZapRecipient {\n function zap(address token, uint256 amount, bytes memory zapData) external payable returns (bytes4);\n}\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// contracts/interfaces/IFastBridgeV2.sol\n\ninterface IFastBridgeV2 is IFastBridge {\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n struct BridgeTxDetails {\n BridgeStatus status;\n uint32 destChainId;\n uint56 proofBlockTimestamp;\n address proofRelayer;\n }\n\n struct BridgeRelay {\n uint48 blockNumber;\n uint48 blockTimestamp;\n address relayer;\n }\n\n /// @notice New params introduced in the FastBridgeV2.\n /// We are passing fields from the older BridgeParams struct outside of this struct\n /// for backwards compatibility.\n /// Note: quoteRelayer and quoteExclusivitySeconds are either both zero (indicating no exclusivity)\n /// or both non-zero (indicating exclusivity for the given period).\n /// Note: zapNative \u003e 0 can NOT be used with destToken = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE (native token)\n /// @param quoteRelayer Relayer that provided the quote for the transaction\n /// @param quoteExclusivitySeconds Period of time the quote relayer is guaranteed exclusivity after user's deposit\n /// @param quoteId Unique quote identifier used for tracking the quote\n /// @param zapNative ETH value to send to the recipient (if any)\n /// @param zapData Parameters for the Zap to the destination recipient (if any)\n struct BridgeParamsV2 {\n address quoteRelayer;\n int256 quoteExclusivitySeconds;\n bytes quoteId;\n uint256 zapNative;\n bytes zapData;\n }\n\n /// @notice Updated bridge transaction struct to include parameters introduced in FastBridgeV2.\n /// Note: only `exclusivityRelayer` can fill such a transaction until `exclusivityEndTime`.\n struct BridgeTransactionV2 {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n // Note: sendChainGas flag from V1 is deprecated\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n address exclusivityRelayer;\n uint256 exclusivityEndTime;\n uint256 zapNative; // ETH value to send to the recipient (if any)\n bytes zapData; // data to pass for the Zap action (if any)\n }\n\n event BridgeQuoteDetails(bytes32 indexed transactionId, bytes quoteId);\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability\n /// to provide temporary exclusivity fill rights for the quote relayer.\n /// @param params The parameters required to bridge\n /// @param paramsV2 The parameters for exclusivity fill rights (optional, can be left empty)\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function relay(bytes memory request, address relayer) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param transactionId The transaction id associated with the encoded bridge transaction to prove\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital.\n /// @notice Can only send funds to the relayer address on the proof.\n /// @param request The encoded bridge transaction to claim on origin chain\n function claim(bytes memory request) external;\n\n /// @notice Cancels an outstanding bridge transaction in case optimistic bridging failed and returns the full amount\n /// to the original sender.\n /// @param request The encoded bridge transaction to refund\n function cancel(bytes memory request) external;\n\n /// @notice Checks if a transaction has been relayed\n /// @param transactionId The ID of the transaction to check\n /// @return True if the transaction has been relayed, false otherwise\n function bridgeRelays(bytes32 transactionId) external view returns (bool);\n\n /// @notice Returns the status of a bridge transaction\n /// @param transactionId The ID of the bridge transaction\n /// @return BridgeStatus Status of the bridge transaction\n function bridgeStatuses(bytes32 transactionId) external view returns (BridgeStatus);\n\n /// @notice Returns the timestamp and relayer of a bridge proof\n /// @param transactionId The ID of the bridge transaction\n /// @return timestamp The timestamp of the bridge proof\n /// @return relayer The relayer address of the bridge proof\n function bridgeProofs(bytes32 transactionId) external view returns (uint96 timestamp, address relayer);\n\n /// @notice Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\n /// @param request The bridge request to decode\n function getBridgeTransactionV2(bytes memory request) external view returns (BridgeTransactionV2 memory);\n}\n\n// contracts/utils/MulticallTarget.sol\n\n// solhint-disable avoid-low-level-calls\n/// @notice Template for a contract that supports batched calls (preserving the msg.sender).\n/// Only calls with zero msg.value could be batched.\nabstract contract MulticallTarget is IMulticallTarget {\n error MulticallTarget__UndeterminedRevert();\n\n /// @notice Perform a batched call to this contract, preserving the msg.sender.\n /// The return data from each call is discarded.\n /// @dev The method is non-payable, so only calls with `msg.value == 0` could be batched.\n /// It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag.\n /// Otherwise, the whole batch call will be reverted with the original revert reason.\n /// @param data List of abi-encoded calldata for the calls to perform.\n /// @param ignoreReverts Whether to ignore the revert errors from the calls.\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external {\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\n if (!success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(result);\n }\n }\n }\n\n /// @notice Perform a batched call to this contract, preserving the msg.sender.\n /// The return data from each call is preserved.\n /// @dev The method is non-payable, so only calls with `msg.value == 0` could be batched.\n /// It's possible to ignore the reverts from the calls by setting the `ignoreReverts` flag.\n /// Otherwise, the whole batch call will be reverted with the original revert reason.\n /// @param data List of abi-encoded calldata for the calls to perform.\n /// @param ignoreReverts Whether to ignore the revert errors from the calls.\n /// @return results List of results from the calls: `(success, returnData)`.\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results)\n {\n results = new Result[](data.length);\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (results[i].success, results[i].returnData) = address(this).delegatecall(data[i]);\n if (!results[i].success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(results[i].returnData);\n }\n }\n }\n\n /// @dev Bubbles the revert message from the underlying call.\n /// Note: preserves the same custom error or revert string, if one was used.\n /// Source: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v5.0.2/contracts/utils/Address.sol#L143-L158\n function _bubbleRevert(bytes memory returnData) internal pure {\n // Look for revert reason and bubble it up if present\n if (returnData.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n // solhint-disable-next-line no-inline-assembly\n assembly {\n let returndata_size := mload(returnData)\n revert(add(32, returnData), returndata_size)\n }\n } else {\n revert MulticallTarget__UndeterminedRevert();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// contracts/libs/BridgeTransactionV2.sol\n\n// solhint-disable no-inline-assembly\nlibrary BridgeTransactionV2Lib {\n uint16 internal constant VERSION = 2;\n\n // Offsets of the fields in the packed BridgeTransactionV2 struct\n // uint16 version [000 .. 002)\n // uint32 originChainId [002 .. 006)\n // uint32 destChainId [006 .. 010)\n // address originSender [010 .. 030)\n // address destRecipient [030 .. 050)\n // address originToken [050 .. 070)\n // address destToken [070 .. 090)\n // uint256 originAmount [090 .. 122)\n // uint256 destAmount [122 .. 154)\n // uint256 originFeeAmount [154 .. 186)\n // uint256 deadline [186 .. 218)\n // uint256 nonce [218 .. 250)\n // address exclusivityRelayer [250 .. 270)\n // uint256 exclusivityEndTime [270 .. 302)\n // uint256 zapNative [302 .. 334)\n // bytes zapData [334 .. ***)\n\n // forgefmt: disable-start\n uint256 private constant OFFSET_ORIGIN_CHAIN_ID = 2;\n uint256 private constant OFFSET_DEST_CHAIN_ID = 6;\n uint256 private constant OFFSET_ORIGIN_SENDER = 10;\n uint256 private constant OFFSET_DEST_RECIPIENT = 30;\n uint256 private constant OFFSET_ORIGIN_TOKEN = 50;\n uint256 private constant OFFSET_DEST_TOKEN = 70;\n uint256 private constant OFFSET_ORIGIN_AMOUNT = 90;\n uint256 private constant OFFSET_DEST_AMOUNT = 122;\n uint256 private constant OFFSET_ORIGIN_FEE_AMOUNT = 154;\n uint256 private constant OFFSET_DEADLINE = 186;\n uint256 private constant OFFSET_NONCE = 218;\n uint256 private constant OFFSET_EXCLUSIVITY_RELAYER = 250;\n uint256 private constant OFFSET_EXCLUSIVITY_END_TIME = 270;\n uint256 private constant OFFSET_ZAP_NATIVE = 302;\n uint256 private constant OFFSET_ZAP_DATA = 334;\n // forgefmt: disable-end\n\n error BridgeTransactionV2__InvalidEncodedTx();\n error BridgeTransactionV2__UnsupportedVersion(uint16 version);\n\n /// @notice Validates the encoded transaction to be a tightly packed encoded payload for BridgeTransactionV2.\n /// @dev Checks the minimum length and the version, use this function before decoding any of the fields.\n function validateV2(bytes calldata encodedTx) internal pure {\n // Check the minimum length: must at least include all static fields.\n if (encodedTx.length \u003c OFFSET_ZAP_DATA) revert BridgeTransactionV2__InvalidEncodedTx();\n // Once we validated the length, we can be sure that the version field is present.\n uint16 version_ = version(encodedTx);\n if (version_ != VERSION) revert BridgeTransactionV2__UnsupportedVersion(version_);\n }\n\n /// @notice Encodes the BridgeTransactionV2 struct by tightly packing the fields.\n /// @dev `abi.decode` will not work as a result of the tightly packed fields. Use `decodeV2` to decode instead.\n function encodeV2(IFastBridgeV2.BridgeTransactionV2 memory bridgeTx) internal pure returns (bytes memory) {\n // We split the encoding into two parts to avoid stack-too-deep error\n bytes memory firstPart = abi.encodePacked(\n VERSION,\n bridgeTx.originChainId,\n bridgeTx.destChainId,\n bridgeTx.originSender,\n bridgeTx.destRecipient,\n bridgeTx.originToken,\n bridgeTx.destToken,\n bridgeTx.originAmount\n );\n return abi.encodePacked(\n firstPart,\n bridgeTx.destAmount,\n bridgeTx.originFeeAmount,\n // Note: we skip the deprecated `sendChainGas` flag, which was present in BridgeTransaction V1\n bridgeTx.deadline,\n bridgeTx.nonce,\n // New V2 fields: exclusivity\n bridgeTx.exclusivityRelayer,\n bridgeTx.exclusivityEndTime,\n // New V2 fields: Zap\n bridgeTx.zapNative,\n bridgeTx.zapData\n );\n }\n\n /// @notice Decodes the BridgeTransactionV2 struct from the encoded transaction.\n /// @dev Encoded BridgeTransactionV2 struct must be tightly packed.\n /// Use `validateV2` before decoding to ensure the encoded transaction is valid.\n function decodeV2(bytes calldata encodedTx)\n internal\n pure\n returns (IFastBridgeV2.BridgeTransactionV2 memory bridgeTx)\n {\n bridgeTx.originChainId = originChainId(encodedTx);\n bridgeTx.destChainId = destChainId(encodedTx);\n bridgeTx.originSender = originSender(encodedTx);\n bridgeTx.destRecipient = destRecipient(encodedTx);\n bridgeTx.originToken = originToken(encodedTx);\n bridgeTx.destToken = destToken(encodedTx);\n bridgeTx.originAmount = originAmount(encodedTx);\n bridgeTx.destAmount = destAmount(encodedTx);\n bridgeTx.originFeeAmount = originFeeAmount(encodedTx);\n bridgeTx.deadline = deadline(encodedTx);\n bridgeTx.nonce = nonce(encodedTx);\n bridgeTx.exclusivityRelayer = exclusivityRelayer(encodedTx);\n bridgeTx.exclusivityEndTime = exclusivityEndTime(encodedTx);\n bridgeTx.zapNative = zapNative(encodedTx);\n bridgeTx.zapData = zapData(encodedTx);\n }\n\n /// @notice Extracts the version from the encoded transaction.\n function version(bytes calldata encodedTx) internal pure returns (uint16 version_) {\n // Load 32 bytes from the start and shift it 240 bits to the right to get the highest 16 bits.\n assembly {\n version_ := shr(240, calldataload(encodedTx.offset))\n }\n }\n\n /// @notice Extracts the origin chain ID from the encoded transaction.\n function originChainId(bytes calldata encodedTx) internal pure returns (uint32 originChainId_) {\n // Load 32 bytes from the offset and shift it 224 bits to the right to get the highest 32 bits.\n assembly {\n originChainId_ := shr(224, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_CHAIN_ID)))\n }\n }\n\n /// @notice Extracts the destination chain ID from the encoded transaction.\n function destChainId(bytes calldata encodedTx) internal pure returns (uint32 destChainId_) {\n // Load 32 bytes from the offset and shift it 224 bits to the right to get the highest 32 bits.\n assembly {\n destChainId_ := shr(224, calldataload(add(encodedTx.offset, OFFSET_DEST_CHAIN_ID)))\n }\n }\n\n /// @notice Extracts the origin sender from the encoded transaction.\n function originSender(bytes calldata encodedTx) internal pure returns (address originSender_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n originSender_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_SENDER)))\n }\n }\n\n /// @notice Extracts the destination recipient from the encoded transaction.\n function destRecipient(bytes calldata encodedTx) internal pure returns (address destRecipient_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n destRecipient_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_DEST_RECIPIENT)))\n }\n }\n\n /// @notice Extracts the origin token from the encoded transaction.\n function originToken(bytes calldata encodedTx) internal pure returns (address originToken_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n originToken_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_TOKEN)))\n }\n }\n\n /// @notice Extracts the destination token from the encoded transaction.\n function destToken(bytes calldata encodedTx) internal pure returns (address destToken_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n destToken_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_DEST_TOKEN)))\n }\n }\n\n /// @notice Extracts the origin amount from the encoded transaction.\n function originAmount(bytes calldata encodedTx) internal pure returns (uint256 originAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n originAmount_ := calldataload(add(encodedTx.offset, OFFSET_ORIGIN_AMOUNT))\n }\n }\n\n /// @notice Extracts the destination amount from the encoded transaction.\n function destAmount(bytes calldata encodedTx) internal pure returns (uint256 destAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n destAmount_ := calldataload(add(encodedTx.offset, OFFSET_DEST_AMOUNT))\n }\n }\n\n /// @notice Extracts the origin fee amount from the encoded transaction.\n function originFeeAmount(bytes calldata encodedTx) internal pure returns (uint256 originFeeAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n originFeeAmount_ := calldataload(add(encodedTx.offset, OFFSET_ORIGIN_FEE_AMOUNT))\n }\n }\n\n /// @notice Extracts the deadline from the encoded transaction.\n function deadline(bytes calldata encodedTx) internal pure returns (uint256 deadline_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n deadline_ := calldataload(add(encodedTx.offset, OFFSET_DEADLINE))\n }\n }\n\n /// @notice Extracts the nonce from the encoded transaction.\n function nonce(bytes calldata encodedTx) internal pure returns (uint256 nonce_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n nonce_ := calldataload(add(encodedTx.offset, OFFSET_NONCE))\n }\n }\n\n /// @notice Extracts the exclusivity relayer from the encoded transaction.\n function exclusivityRelayer(bytes calldata encodedTx) internal pure returns (address exclusivityRelayer_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n exclusivityRelayer_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_EXCLUSIVITY_RELAYER)))\n }\n }\n\n /// @notice Extracts the exclusivity end time from the encoded transaction.\n function exclusivityEndTime(bytes calldata encodedTx) internal pure returns (uint256 exclusivityEndTime_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n exclusivityEndTime_ := calldataload(add(encodedTx.offset, OFFSET_EXCLUSIVITY_END_TIME))\n }\n }\n\n /// @notice Extracts the Zap's native value from the encoded transaction.\n function zapNative(bytes calldata encodedTx) internal pure returns (uint256 zapNative_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n zapNative_ := calldataload(add(encodedTx.offset, OFFSET_ZAP_NATIVE))\n }\n }\n\n /// @notice Extracts the Zap's data from the encoded transaction.\n function zapData(bytes calldata encodedTx) internal pure returns (bytes calldata zapData_) {\n zapData_ = encodedTx[OFFSET_ZAP_DATA:];\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/AdminV2.sol\n\ncontract AdminV2 is AccessControlEnumerable, IAdminV2, IAdminV2Errors {\n using SafeERC20 for IERC20;\n\n /// @notice Address reserved for native gas token (ETH on Ethereum and most L2s, AVAX on Avalanche, etc)\n address public constant NATIVE_GAS_TOKEN = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice Role identifier for Quoter API's off-chain authentication.\n /// @dev Only addresses with this role can post FastBridge quotes to the API.\n bytes32 public constant QUOTER_ROLE = keccak256(\"QUOTER_ROLE\");\n\n /// @notice Role identifier for Prover's on-chain authentication in FastBridge.\n /// @dev Only addresses with this role can provide proofs that a FastBridge request has been relayed.\n bytes32 public constant PROVER_ROLE = keccak256(\"PROVER_ROLE\");\n\n /// @notice Role identifier for Guard's on-chain authentication in FastBridge.\n /// @dev Only addresses with this role can dispute submitted relay proofs during the dispute period.\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n\n /// @notice Role identifier for Canceler's on-chain authentication in FastBridge.\n /// @dev Only addresses with this role can cancel a FastBridge transaction without the cancel delay.\n bytes32 public constant CANCELER_ROLE = keccak256(\"CANCELER_ROLE\");\n\n /// @notice Role identifier for Governor's on-chain administrative authority.\n /// @dev Only addresses with this role can perform administrative tasks within the contract.\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n /// @notice Denominator for fee rates, represents 100%.\n uint256 public constant FEE_BPS = 1e6;\n /// @notice Maximum protocol fee rate: 1% on origin amount.\n uint256 public constant FEE_RATE_MAX = 0.01e6;\n\n /// @notice Minimum cancel delay that can be set by the governor.\n uint256 public constant MIN_CANCEL_DELAY = 1 hours;\n /// @notice Default cancel delay set during the contract deployment.\n uint256 public constant DEFAULT_CANCEL_DELAY = 1 days;\n\n /// @notice Protocol fee rate taken on origin amount deposited in origin chain\n uint256 public protocolFeeRate;\n\n /// @notice Protocol fee amounts accumulated\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice Delay for a transaction after which it could be permisionlessly cancelled\n uint256 public cancelDelay;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Use ZapNative V2 requests instead.\n uint256 public immutable chainGasAmount = 0;\n\n constructor(address _owner) {\n _grantRole(DEFAULT_ADMIN_ROLE, _owner);\n _setCancelDelay(DEFAULT_CANCEL_DELAY);\n }\n\n /// @notice Allows the contract governor to set the cancel delay. The cancel delay is the time after the transaction\n /// deadline after which it can be permissionlessly cancelled, if it hasn't been proven by any of the Relayers.\n function setCancelDelay(uint256 newCancelDelay) external onlyRole(GOVERNOR_ROLE) {\n _setCancelDelay(newCancelDelay);\n }\n\n /// @notice Allows the contract governor to set the protocol fee rate. The protocol fee is taken from the origin\n /// amount only for completed and claimed transactions.\n /// @dev The protocol fee is abstracted away from the relayers, they always operate using the amounts after fees:\n /// what they see as the origin amount emitted in the log is what they get credited with.\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n if (newFeeRate \u003e FEE_RATE_MAX) revert FeeRateAboveMax();\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n /// @notice Allows the contract governor to sweep the accumulated protocol fees in the contract.\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return; // skip if no accumulated fees\n\n protocolFees[token] = 0;\n emit FeesSwept(token, recipient, feeAmount);\n /// Sweep the fees as the last transaction action\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(recipient), feeAmount);\n } else {\n IERC20(token).safeTransfer(recipient, feeAmount);\n }\n }\n\n /// @notice Internal function to set the cancel delay. Security checks are performed outside of this function.\n function _setCancelDelay(uint256 newCancelDelay) private {\n if (newCancelDelay \u003c MIN_CANCEL_DELAY) revert CancelDelayBelowMin();\n uint256 oldCancelDelay = cancelDelay;\n cancelDelay = newCancelDelay;\n emit CancelDelayUpdated(oldCancelDelay, newCancelDelay);\n }\n}\n\n// contracts/FastBridgeV2.sol\n\n/// @notice FastBridgeV2 is a contract for bridging tokens across chains.\ncontract FastBridgeV2 is AdminV2, MulticallTarget, IFastBridgeV2, IFastBridgeV2Errors {\n using BridgeTransactionV2Lib for bytes;\n using SafeERC20 for IERC20;\n\n /// @notice Dispute period for relayed transactions\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice Minimum deadline period to relay a requested bridge transaction\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n /// @notice Maximum length of accepted zapData\n uint256 public constant MAX_ZAP_DATA_LENGTH = 2 ** 16 - 1;\n\n /// @notice Status of the bridge tx on origin chain\n mapping(bytes32 =\u003e BridgeTxDetails) public bridgeTxDetails;\n /// @notice Relay details on destination chain\n mapping(bytes32 =\u003e BridgeRelay) public bridgeRelayDetails;\n /// @notice Unique bridge nonces tracked per originSender\n mapping(address =\u003e uint256) public senderNonces;\n\n /// @notice This is deprecated and should not be used.\n /// @dev Replaced by senderNonces\n uint256 public immutable nonce = 0;\n /// @notice the block the contract was deployed at\n uint256 public immutable deployBlock;\n\n constructor(address _owner) AdminV2(_owner) {\n deployBlock = block.number;\n }\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n bridge({\n params: params,\n paramsV2: BridgeParamsV2({\n quoteRelayer: address(0),\n quoteExclusivitySeconds: 0,\n quoteId: bytes(\"\"),\n zapNative: 0,\n zapData: bytes(\"\")\n })\n });\n }\n\n /// @inheritdoc IFastBridge\n function relay(bytes calldata request) external payable {\n // relay override will validate the request\n relay({request: request, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes calldata request, bytes32 destTxHash) external {\n request.validateV2();\n prove({transactionId: keccak256(request), destTxHash: destTxHash, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridgeV2\n function claim(bytes calldata request) external {\n // claim override will validate the request\n claim({request: request, to: address(0)});\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Aggregate the read operations from the same storage slot\n address disputedRelayer = $.proofRelayer;\n BridgeStatus status = $.status;\n uint56 proofBlockTimestamp = $.proofBlockTimestamp;\n // Can only dispute a RELAYER_PROVED transaction within the dispute period\n if (status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(proofBlockTimestamp) \u003e DISPUTE_PERIOD) {\n revert DisputePeriodPassed();\n }\n // Update status to REQUESTED and delete the disputed proof details\n // Note: these are storage writes\n $.status = BridgeStatus.REQUESTED;\n $.proofRelayer = address(0);\n $.proofBlockTimestamp = 0;\n\n emit BridgeProofDisputed(transactionId, disputedRelayer);\n }\n\n /// Note: this function is deprecated and will be removed in a future version.\n /// @inheritdoc IFastBridge\n function refund(bytes calldata request) external {\n cancel(request);\n }\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // The correct relayer can only claim a RELAYER_PROVED transaction after the dispute period\n if ($.status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if ($.proofRelayer != relayer) revert SenderIncorrect();\n return _timeSince($.proofBlockTimestamp) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n /// @dev This method is added to achieve backwards compatibility with decoding requests into V1 structs:\n /// - `zapNative` is partially reported as a zero/non-zero flag\n /// - `zapData` is ignored\n /// In order to process all kinds of requests use getBridgeTransactionV2 instead.\n function getBridgeTransaction(bytes calldata request) external view returns (BridgeTransaction memory) {\n // Try decoding into V2 struct first. This will revert if V1 struct is passed\n try this.getBridgeTransactionV2(request) returns (BridgeTransactionV2 memory txV2) {\n // Note: we entirely ignore the zapData field, as it was not present in V1\n return BridgeTransaction({\n originChainId: txV2.originChainId,\n destChainId: txV2.destChainId,\n originSender: txV2.originSender,\n destRecipient: txV2.destRecipient,\n originToken: txV2.originToken,\n destToken: txV2.destToken,\n originAmount: txV2.originAmount,\n destAmount: txV2.destAmount,\n originFeeAmount: txV2.originFeeAmount,\n sendChainGas: txV2.zapNative != 0,\n deadline: txV2.deadline,\n nonce: txV2.nonce\n });\n } catch {\n // Fallback to V1 struct\n return abi.decode(request, (BridgeTransaction));\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function getBridgeTransactionV2(bytes calldata request) external pure returns (BridgeTransactionV2 memory) {\n request.validateV2();\n return BridgeTransactionV2Lib.decodeV2(request);\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) public payable {\n int256 exclusivityEndTime = 0;\n // if relayer exclusivity is not intended for this bridge, set exclusivityEndTime to static zero\n // otherwise, set exclusivity to expire at the current block ts offset by quoteExclusivitySeconds\n if (paramsV2.quoteRelayer != address(0)) {\n exclusivityEndTime = int256(block.timestamp) + paramsV2.quoteExclusivitySeconds;\n }\n _validateBridgeParams(params, paramsV2, exclusivityEndTime);\n\n // transfer tokens to bridge contract\n /// @dev use returned originAmount in request in case of transfer fees\n uint256 originAmount = _takeBridgedUserAsset(params.originToken, params.originAmount);\n\n // track amount of origin token owed to protocol\n uint256 originFeeAmount;\n if (protocolFeeRate \u003e 0) {\n originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers\n }\n\n // set status to requested\n bytes memory request = BridgeTransactionV2Lib.encodeV2(\n BridgeTransactionV2({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n deadline: params.deadline,\n nonce: senderNonces[params.sender]++, // increment nonce on every bridge\n exclusivityRelayer: paramsV2.quoteRelayer,\n // We checked exclusivityEndTime to be in range [0 .. params.deadline] above, so can safely cast\n exclusivityEndTime: uint256(exclusivityEndTime),\n zapNative: paramsV2.zapNative,\n zapData: paramsV2.zapData\n })\n );\n bytes32 transactionId = keccak256(request);\n // Note: the tx status will be updated throughout the tx lifecycle, while destChainId is set once here\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n bridgeTxDetails[transactionId].destChainId = params.dstChainId;\n\n emit BridgeRequested({\n transactionId: transactionId,\n sender: params.sender,\n request: request,\n destChainId: params.dstChainId,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n sendChainGas: paramsV2.zapNative != 0\n });\n emit BridgeQuoteDetails(transactionId, paramsV2.quoteId);\n }\n\n /// @inheritdoc IFastBridgeV2\n function relay(bytes calldata request, address relayer) public payable {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n _validateRelayParams(request, transactionId, relayer);\n // mark bridge transaction as relayed\n bridgeRelayDetails[transactionId] =\n BridgeRelay({blockNumber: uint48(block.number), blockTimestamp: uint48(block.timestamp), relayer: relayer});\n\n // transfer tokens to recipient on destination chain and trigger Zap if requested\n address to = request.destRecipient();\n address token = request.destToken();\n uint256 amount = request.destAmount();\n uint256 zapNative = request.zapNative();\n\n // Emit the event before any external calls\n emit BridgeRelayed({\n transactionId: transactionId,\n relayer: relayer,\n to: to,\n originChainId: request.originChainId(),\n originToken: request.originToken(),\n destToken: token,\n originAmount: request.originAmount(),\n destAmount: amount,\n chainGasAmount: zapNative\n });\n\n // All state changes have been done at this point, can proceed to the external calls.\n // This follows the checks-effects-interactions pattern to mitigate potential reentrancy attacks.\n if (token == NATIVE_GAS_TOKEN) {\n // For the native gas token, additional zapNative is not allowed\n if (zapNative != 0) revert ZapNativeNotSupported();\n // Check that the correct msg.value was sent\n if (msg.value != amount) revert MsgValueIncorrect();\n // Don't do a native transfer yet: we will handle it alongside the Zap below\n } else {\n // For ERC20s, we check that the correct msg.value was sent\n if (msg.value != zapNative) revert MsgValueIncorrect();\n // We need to transfer the tokens from the Relayer to the recipient first before performing an\n // optional post-transfer Zap.\n IERC20(token).safeTransferFrom(msg.sender, to, amount);\n }\n // At this point we have done:\n // - Transferred the requested amount of ERC20 tokens to the recipient.\n // At this point we have confirmed:\n // - For ERC20s: msg.value matches the requested zapNative amount.\n // - For the native gas token: msg.value matches the requested destAmount.\n // Remaining optional things to do:\n // - Forward the full msg.value to the recipient (if non-zero).\n // - Trigger a Zap (if zapData is present).\n bytes calldata zapData = request.zapData();\n if (zapData.length != 0) {\n // Zap Data is present: Zap has been requested by the recipient. Trigger it forwarding the full msg.value.\n\n // Note: if token has a fee on transfers, the recipient will have received less than `amount`.\n // This is a very niche edge case and should be handled by the recipient contract.\n _triggerZapWithChecks({recipient: to, token: token, amount: amount, zapData: zapData});\n } else if (msg.value != 0) {\n // Zap Data is missing, but msg.value was sent. This could happen in two different cases:\n // - Relay with the native gas token is happening.\n // - Relay with ERC20 is happening, with a `zapNative \u003e 0` request.\n // In both cases, we need to transfer the full msg.value to the recipient.\n Address.sendValue(payable(to), msg.value);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) public onlyRole(PROVER_ROLE) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n\n // Can only prove a REQUESTED transaction\n if ($.status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n // Update status to RELAYER_PROVED and store the proof details\n // Note: these are storage writes\n $.status = BridgeStatus.RELAYER_PROVED;\n $.proofBlockTimestamp = uint56(block.timestamp);\n $.proofRelayer = relayer;\n\n emit BridgeProofProvided(transactionId, relayer, destTxHash);\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes calldata request, address to) public {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Aggregate the read operations from the same storage slot\n address proofRelayer = $.proofRelayer;\n BridgeStatus status = $.status;\n uint56 proofBlockTimestamp = $.proofBlockTimestamp;\n\n // Can only claim a RELAYER_PROVED transaction after the dispute period\n if (status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(proofBlockTimestamp) \u003c= DISPUTE_PERIOD) {\n revert DisputePeriodNotPassed();\n }\n\n if (to == address(0)) {\n // Anyone could claim the funds to the proven relayer on their behalf\n to = proofRelayer;\n } else if (proofRelayer != msg.sender) {\n // Only the proven relayer could specify an address to claim the funds to\n revert SenderIncorrect();\n }\n\n // Update status to RELAYER_CLAIMED and transfer the origin collateral to the specified claim address\n // Note: this is a storage write\n $.status = BridgeStatus.RELAYER_CLAIMED;\n\n address token = request.originToken();\n uint256 amount = request.originAmount();\n // Update protocol fees if origin fee amount exists\n uint256 originFeeAmount = request.originFeeAmount();\n if (originFeeAmount \u003e 0) protocolFees[token] += originFeeAmount;\n // Emit the event before any external calls\n emit BridgeDepositClaimed(transactionId, proofRelayer, to, token, amount);\n // Complete the relayer claim as the last transaction action\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(to), amount);\n } else {\n IERC20(token).safeTransfer(to, amount);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function cancel(bytes calldata request) public {\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n // Can only cancel a REQUESTED transaction after its deadline expires\n if ($.status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n uint256 deadline = request.deadline();\n // Permissionless cancel is only allowed after `cancelDelay` on top of the deadline\n if (!hasRole(CANCELER_ROLE, msg.sender)) deadline += cancelDelay;\n if (block.timestamp \u003c= deadline) revert DeadlineNotExceeded();\n // Update status to REFUNDED and return the full amount (collateral + protocol fees) to the original sender.\n // The protocol fees are only updated when the transaction is claimed, so we don't need to update them here.\n // Note: this is a storage write\n $.status = BridgeStatus.REFUNDED;\n\n address to = request.originSender();\n address token = request.originToken();\n uint256 amount = request.originAmount() + request.originFeeAmount();\n // Emit the event before any external calls\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n // Complete the user cancel as the last transaction action\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(to), amount);\n } else {\n IERC20(token).safeTransfer(to, amount);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeStatuses(bytes32 transactionId) public view returns (BridgeStatus status) {\n return bridgeTxDetails[transactionId].status;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeProofs(bytes32 transactionId) public view returns (uint96 timestamp, address relayer) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n\n timestamp = $.proofBlockTimestamp;\n relayer = $.proofRelayer;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeRelays(bytes32 transactionId) public view returns (bool) {\n // has this transactionId been relayed?\n return bridgeRelayDetails[transactionId].relayer != address(0);\n }\n\n /// @notice Takes the bridged asset from the user into FastBridgeV2 custody. It will be later\n /// claimed by the relayer who completed the relay on destination chain, or transferred back to the user\n /// via the cancel function should no one complete the relay.\n function _takeBridgedUserAsset(address token, uint256 amount) internal returns (uint256 amountTaken) {\n if (token == NATIVE_GAS_TOKEN) {\n // For the native gas token, we just need to check that the supplied msg.value is correct.\n // Supplied `msg.value` is already in FastBridgeV2 custody.\n if (amount != msg.value) revert MsgValueIncorrect();\n amountTaken = msg.value;\n } else {\n // For ERC20s, token is explicitly transferred from the user to FastBridgeV2.\n // We don't allow non-zero `msg.value` to avoid extra funds from being stuck in FastBridgeV2.\n if (msg.value != 0) revert MsgValueIncorrect();\n // Throw an explicit error if the provided token address is not a contract\n if (token.code.length == 0) revert TokenNotContract();\n amountTaken = IERC20(token).balanceOf(address(this));\n IERC20(token).safeTransferFrom(msg.sender, address(this), amount);\n // Use the balance difference as the amount taken in case of fee on transfer tokens.\n amountTaken = IERC20(token).balanceOf(address(this)) - amountTaken;\n }\n }\n\n /// @notice Calls the Recipient's hook function with the specified zapData and performs\n /// all the necessary checks for the returned value.\n function _triggerZapWithChecks(address recipient, address token, uint256 amount, bytes calldata zapData) internal {\n // This will bubble any revert messages from the hook function\n bytes memory returnData = Address.functionCallWithValue({\n target: recipient,\n data: abi.encodeCall(IZapRecipient.zap, (token, amount, zapData)),\n // Note: see `relay()` for reasoning behind passing msg.value\n value: msg.value\n });\n // Explicit revert if no return data at all\n if (returnData.length == 0) revert RecipientNoReturnValue();\n // Check that exactly a single return value was returned\n if (returnData.length != 32) revert RecipientIncorrectReturnValue();\n // Return value should be abi-encoded hook function selector\n if (bytes32(returnData) != bytes32(IZapRecipient.zap.selector)) {\n revert RecipientIncorrectReturnValue();\n }\n }\n\n /// @notice Calculates time since proof submitted\n /// @dev proof.timestamp stores casted uint56(block.timestamp) block timestamps for gas optimization\n /// _timeSince(proof) can accomodate rollover case when block.timestamp \u003e type(uint56).max but\n /// proof.timestamp \u003c type(uint56).max via unchecked statement\n /// @param proofBlockTimestamp The bridge proof block timestamp\n /// @return delta Time delta since proof submitted\n function _timeSince(uint56 proofBlockTimestamp) internal view returns (uint256 delta) {\n unchecked {\n delta = uint56(block.timestamp) - proofBlockTimestamp;\n }\n }\n\n /// @notice Performs all the necessary checks for a bridge to happen.\n /// @dev There's no good way to refactor this function to reduce cyclomatic complexity due to\n /// the number of checks that need to be performed, so we skip the code-complexity rule here.\n // solhint-disable-next-line code-complexity\n function _validateBridgeParams(\n BridgeParams memory params,\n BridgeParamsV2 memory paramsV2,\n int256 exclusivityEndTime\n )\n internal\n view\n {\n // Check V1 (legacy) params\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.sender == address(0) || params.to == address(0)) revert ZeroAddress();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n // Check V2 params\n if (paramsV2.zapData.length \u003e MAX_ZAP_DATA_LENGTH) revert ZapDataLengthAboveMax();\n if (paramsV2.zapNative != 0 \u0026\u0026 params.destToken == NATIVE_GAS_TOKEN) {\n revert ZapNativeNotSupported();\n }\n // exclusivityEndTime must be in range [0 .. params.deadline]\n if (exclusivityEndTime \u003c 0 || exclusivityEndTime \u003e int256(params.deadline)) {\n revert ExclusivityParamsIncorrect();\n }\n }\n\n /// @notice Performs all the necessary checks for a relay to happen.\n function _validateRelayParams(bytes calldata request, bytes32 transactionId, address relayer) internal view {\n if (relayer == address(0)) revert ZeroAddress();\n // Check if the transaction has already been relayed\n if (bridgeRelays(transactionId)) revert TransactionRelayed();\n if (request.destChainId() != block.chainid) revert ChainIncorrect();\n // Check the deadline for relay to happen\n if (block.timestamp \u003e request.deadline()) revert DeadlineExceeded();\n // Check the exclusivity period, if it is still ongoing\n address exclRelayer = request.exclusivityRelayer();\n if (exclRelayer != address(0) \u0026\u0026 exclRelayer != relayer \u0026\u0026 block.timestamp \u003c= request.exclusivityEndTime()) {\n revert ExclusivityPeriodNotPassed();\n }\n }\n}\n","language":"Solidity","languageVersion":"0.8.24","compilerVersion":"0.8.24","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"61585:5018:0:-:0;;;;;;;;;;;;;;;-1:-1:-1;;;61585:5018:0;;;;;;;;;;;;;;;;;","srcMapRuntime":"61585:5018:0:-:0;;;;;;;;","abiDefinition":[{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"currentAllowance","type":"uint256"},{"internalType":"uint256","name":"requestedDecrease","type":"uint256"}],"name":"SafeERC20FailedDecreaseAllowance","type":"error"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"SafeERC20FailedOperation","type":"error"}],"userDoc":{"kind":"user","methods":{},"version":1},"developerDoc":{"details":"Wrappers around ERC20 operations that throw on failure (when the token contract returns false). Tokens that return no value (and instead revert or throw on failure) are also supported, non-reverting calls are assumed to be successful. To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract, which allows you to call the safe operations as `token.safeTransfer(...)`, etc.","errors":{"SafeERC20FailedDecreaseAllowance(address,uint256,uint256)":[{"details":"Indicates a failed `decreaseAllowance` request."}],"SafeERC20FailedOperation(address)":[{"details":"An operation with an ERC20 token failed."}]},"kind":"dev","methods":{},"title":"SafeERC20","version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"currentAllowance\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"requestedDecrease\",\"type\":\"uint256\"}],\"name\":\"SafeERC20FailedDecreaseAllowance\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"}],\"name\":\"SafeERC20FailedOperation\",\"type\":\"error\"}],\"devdoc\":{\"details\":\"Wrappers around ERC20 operations that throw on failure (when the token contract returns false). Tokens that return no value (and instead revert or throw on failure) are also supported, non-reverting calls are assumed to be successful. To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract, which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\",\"errors\":{\"SafeERC20FailedDecreaseAllowance(address,uint256,uint256)\":[{\"details\":\"Indicates a failed `decreaseAllowance` request.\"}],\"SafeERC20FailedOperation(address)\":[{\"details\":\"An operation with an ERC20 token failed.\"}]},\"kind\":\"dev\",\"methods\":{},\"title\":\"SafeERC20\",\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeV2.sol\":\"SafeERC20\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeV2.sol\":{\"keccak256\":\"0xac79c463688a682ca706a4ef95e7817b83548cdfa8182ba0426ac7e5e07613d8\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://b3ecb7097381287cafc3a73f3a2bb03565115ebb682a85064e0b0dc2f7e2919d\",\"dweb:/ipfs/QmatruW3nYZTksf3CeQ8wwiAG4c7xoEJBEp6drHPtFLBRK\"]}},\"version\":1}"},"hashes":{}}} \ No newline at end of file +{"solidity/FastBridgeV2.sol:AccessControl":{"code":"0x","runtime-code":"0x","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.24 ^0.8.20 ^0.8.4;\n\n// contracts/interfaces/IAdminV2.sol\n\ninterface IAdminV2 {\n event CancelDelayUpdated(uint256 oldCancelDelay, uint256 newCancelDelay);\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n /// @notice Allows the governor to set the cancel delay. The cancel delay is the time period after the transaction\n /// deadline during which a transaction can be permissionlessly cancelled if it hasn't been proven by any Relayer.\n function setCancelDelay(uint256 newCancelDelay) external;\n\n /// @notice Allows the governor to set the protocol fee rate. The protocol fee is taken from the origin\n /// amount and is only applied to completed and claimed transactions.\n /// @dev The protocol fee is abstracted away from the relayers; they always operate using the amounts after fees.\n /// The origin amount they see in the emitted log is what they get credited with.\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n /// @notice Allows the governor to withdraw the accumulated protocol fees from the contract.\n function sweepProtocolFees(address token, address recipient) external;\n}\n\n// contracts/interfaces/IAdminV2Errors.sol\n\ninterface IAdminV2Errors {\n error CancelDelayBelowMin();\n error FeeRateAboveMax();\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IFastBridgeV2Errors.sol\n\ninterface IFastBridgeV2Errors {\n error AmountIncorrect();\n error ChainIncorrect();\n error ExclusivityParamsIncorrect();\n error MsgValueIncorrect();\n error SenderIncorrect();\n error StatusIncorrect();\n error TokenNotContract();\n error ZapDataLengthAboveMax();\n error ZapNativeNotSupported();\n error ZeroAddress();\n\n error RecipientIncorrectReturnValue();\n error RecipientNoReturnValue();\n\n error DeadlineExceeded();\n error DeadlineNotExceeded();\n error DeadlineTooShort();\n error DisputePeriodNotPassed();\n error DisputePeriodPassed();\n error ExclusivityPeriodNotPassed();\n\n error TransactionRelayed();\n}\n\n// contracts/interfaces/IMulticallTarget.sol\n\n/// @notice Interface for a contract that supports multiple calls from the same caller. Inspired by MulticallV3:\n/// https://github.com/mds1/multicall/blob/master/src/Multicall3.sol\ninterface IMulticallTarget {\n struct Result {\n bool success;\n bytes returnData;\n }\n\n /// @notice Executes multiple calls to this contract in a single transaction while preserving msg.sender.\n /// Return data from the calls is discarded.\n /// @dev This method is non-payable, so only calls with msg.value of 0 can be batched.\n /// If ignoreReverts is set to true, reverted calls will be skipped.\n /// Otherwise, the entire batch will revert with the original revert reason.\n /// @param data List of ABI-encoded calldata for the calls to execute\n /// @param ignoreReverts Whether to skip calls that revert\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external;\n\n /// @notice Executes multiple calls to this contract in a single transaction while preserving msg.sender.\n /// Return data from each call is preserved.\n /// @dev This method is non-payable, so only calls with msg.value of 0 can be batched.\n /// If ignoreReverts is set to true, reverted calls will be skipped.\n /// Otherwise, the entire batch will revert with the original revert reason.\n /// @param data List of ABI-encoded calldata for the calls to execute\n /// @param ignoreReverts Whether to skip calls that revert\n /// @return results List of results from the calls, each containing (success, returnData)\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results);\n}\n\n// contracts/interfaces/IZapRecipient.sol\n\n/// @notice Interface for contracts that can perform Zap operations. Such contracts could be used as Recipients\n/// in a FastBridge transaction that includes a Zap operation. The Zap Data should include instructions on how\n/// exactly the Zap operation should be executed, which would typically include the target address and calldata\n/// to use. The exact implementation of the Zap Data encoding is up to the Recipient contract.\ninterface IZapRecipient {\n /// @notice Performs a Zap operation with the given token and amount according to the provided Zap data.\n /// @param token The address of the token being used for the Zap operation.\n /// @param amount The amount of tokens to be used.\n /// @param zapData The encoded data specifying how the Zap operation should be executed.\n /// @return The function selector to indicate successful execution.\n function zap(address token, uint256 amount, bytes memory zapData) external payable returns (bytes4);\n}\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// contracts/interfaces/IFastBridgeV2.sol\n\ninterface IFastBridgeV2 is IFastBridge {\n enum BridgeStatus {\n NULL, // Doesn't exist yet.\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n struct BridgeTxDetails {\n BridgeStatus status;\n uint32 destChainId;\n uint56 proofBlockTimestamp;\n address proofRelayer;\n }\n\n struct BridgeRelay {\n uint48 blockNumber;\n uint48 blockTimestamp;\n address relayer;\n }\n\n /// @notice New params introduced in the FastBridgeV2.\n /// We are passing fields from the older BridgeParams struct outside of this struct for backwards compatibility.\n /// Note: quoteRelayer and quoteExclusivitySeconds are either both zero (indicating no exclusivity)\n /// or both non-zero (indicating exclusivity for the given period).\n /// Note: zapNative \u003e 0 can NOT be used with destToken = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE (native token)\n /// @param quoteRelayer Relayer that provided the quote for the transaction\n /// @param quoteExclusivitySeconds Period of time the quote relayer is guaranteed exclusivity after user's deposit\n /// @param quoteId Unique quote identifier used for tracking the quote\n /// @param zapNative ETH value to send to the recipient (if any)\n /// @param zapData Parameters for the Zap to the destination recipient (if any)\n struct BridgeParamsV2 {\n address quoteRelayer;\n int256 quoteExclusivitySeconds;\n bytes quoteId;\n uint256 zapNative;\n bytes zapData;\n }\n\n /// @notice Updated bridge transaction struct to include parameters introduced in FastBridgeV2.\n /// Note: only `exclusivityRelayer` can fill such a transaction until `exclusivityEndTime`.\n struct BridgeTransactionV2 {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n // Note: sendChainGas flag from V1 is deprecated\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n address exclusivityRelayer;\n uint256 exclusivityEndTime;\n uint256 zapNative; // ETH value to send to the recipient (if any)\n bytes zapData; // data to pass for the Zap action (if any)\n }\n\n event BridgeQuoteDetails(bytes32 indexed transactionId, bytes quoteId);\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability\n /// to provide temporary exclusivity fill rights for the quote relayer.\n /// @param params The parameters required to bridge\n /// @param paramsV2 The parameters for exclusivity fill rights (optional, can be left empty)\n function bridgeV2(BridgeParams memory params, BridgeParamsV2 memory paramsV2) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function relayV2(bytes memory request, address relayer) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param transactionId The transaction id associated with the encoded bridge transaction to prove\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function proveV2(bytes32 transactionId, bytes32 destTxHash, address relayer) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital.\n /// @notice Can only send funds to the relayer address on the proof.\n /// @param request The encoded bridge transaction to claim on origin chain\n function claimV2(bytes memory request) external;\n\n /// @notice Cancels an outstanding bridge transaction in case optimistic bridging failed and returns the full amount\n /// to the original sender.\n /// @param request The encoded bridge transaction to refund\n function cancelV2(bytes memory request) external;\n\n /// @notice Checks if a transaction has been relayed\n /// @param transactionId The ID of the transaction to check\n /// @return True if the transaction has been relayed, false otherwise\n function bridgeRelays(bytes32 transactionId) external view returns (bool);\n\n /// @notice Returns the status of a bridge transaction\n /// @param transactionId The ID of the bridge transaction\n /// @return BridgeStatus Status of the bridge transaction\n function bridgeStatuses(bytes32 transactionId) external view returns (BridgeStatus);\n\n /// @notice Returns the timestamp and relayer of a bridge proof\n /// @param transactionId The ID of the bridge transaction\n /// @return timestamp The timestamp of the bridge proof\n /// @return relayer The relayer address of the bridge proof\n function bridgeProofs(bytes32 transactionId) external view returns (uint96 timestamp, address relayer);\n\n /// @notice Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\n /// @param request The bridge request to decode\n function getBridgeTransactionV2(bytes memory request) external view returns (BridgeTransactionV2 memory);\n}\n\n// contracts/utils/MulticallTarget.sol\n\n// solhint-disable avoid-low-level-calls\n/// @notice Abstract contract template that supports batched calls while preserving msg.sender.\n/// Only calls with msg.value of 0 can be batched.\nabstract contract MulticallTarget is IMulticallTarget {\n error MulticallTarget__UndeterminedRevert();\n\n /// @inheritdoc IMulticallTarget\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external {\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\n if (!success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(result);\n }\n }\n }\n\n /// @inheritdoc IMulticallTarget\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results)\n {\n results = new Result[](data.length);\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (results[i].success, results[i].returnData) = address(this).delegatecall(data[i]);\n if (!results[i].success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(results[i].returnData);\n }\n }\n }\n\n /// @dev Bubbles the revert message from the underlying call.\n /// Note: preserves the same custom error or revert string, if one was used.\n /// Source: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v5.0.2/contracts/utils/Address.sol#L143-L158\n function _bubbleRevert(bytes memory returnData) internal pure {\n // Look for revert reason and bubble it up if present\n if (returnData.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n // solhint-disable-next-line no-inline-assembly\n assembly {\n let returndata_size := mload(returnData)\n revert(add(32, returnData), returndata_size)\n }\n } else {\n revert MulticallTarget__UndeterminedRevert();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// contracts/libs/BridgeTransactionV2.sol\n\n// solhint-disable no-inline-assembly\nlibrary BridgeTransactionV2Lib {\n uint16 internal constant VERSION = 2;\n\n // Offsets of the fields in the packed BridgeTransactionV2 struct\n // uint16 version [000 .. 002)\n // uint32 originChainId [002 .. 006)\n // uint32 destChainId [006 .. 010)\n // address originSender [010 .. 030)\n // address destRecipient [030 .. 050)\n // address originToken [050 .. 070)\n // address destToken [070 .. 090)\n // uint256 originAmount [090 .. 122)\n // uint256 destAmount [122 .. 154)\n // uint256 originFeeAmount [154 .. 186)\n // uint256 deadline [186 .. 218)\n // uint256 nonce [218 .. 250)\n // address exclusivityRelayer [250 .. 270)\n // uint256 exclusivityEndTime [270 .. 302)\n // uint256 zapNative [302 .. 334)\n // bytes zapData [334 .. ***)\n\n // forgefmt: disable-start\n uint256 private constant OFFSET_ORIGIN_CHAIN_ID = 2;\n uint256 private constant OFFSET_DEST_CHAIN_ID = 6;\n uint256 private constant OFFSET_ORIGIN_SENDER = 10;\n uint256 private constant OFFSET_DEST_RECIPIENT = 30;\n uint256 private constant OFFSET_ORIGIN_TOKEN = 50;\n uint256 private constant OFFSET_DEST_TOKEN = 70;\n uint256 private constant OFFSET_ORIGIN_AMOUNT = 90;\n uint256 private constant OFFSET_DEST_AMOUNT = 122;\n uint256 private constant OFFSET_ORIGIN_FEE_AMOUNT = 154;\n uint256 private constant OFFSET_DEADLINE = 186;\n uint256 private constant OFFSET_NONCE = 218;\n uint256 private constant OFFSET_EXCLUSIVITY_RELAYER = 250;\n uint256 private constant OFFSET_EXCLUSIVITY_END_TIME = 270;\n uint256 private constant OFFSET_ZAP_NATIVE = 302;\n uint256 private constant OFFSET_ZAP_DATA = 334;\n // forgefmt: disable-end\n\n error BridgeTransactionV2__InvalidEncodedTx();\n error BridgeTransactionV2__UnsupportedVersion(uint16 version);\n\n /// @notice Validates that the encoded transaction is a tightly packed encoded payload for BridgeTransactionV2.\n /// @dev Checks the minimum length and the version, use this function before decoding any of the fields.\n function validateV2(bytes calldata encodedTx) internal pure {\n // Check the minimum length: must at least include all static fields.\n if (encodedTx.length \u003c OFFSET_ZAP_DATA) revert BridgeTransactionV2__InvalidEncodedTx();\n // Once we validated the length, we can be sure that the version field is present.\n uint16 version_ = version(encodedTx);\n if (version_ != VERSION) revert BridgeTransactionV2__UnsupportedVersion(version_);\n }\n\n /// @notice Encodes the BridgeTransactionV2 struct by tightly packing the fields.\n /// @dev `abi.decode` will not work as a result of the tightly packed fields. Use `decodeV2` to decode instead.\n function encodeV2(IFastBridgeV2.BridgeTransactionV2 memory bridgeTx) internal pure returns (bytes memory) {\n // We split the encoding into two parts to avoid stack-too-deep error\n bytes memory firstPart = abi.encodePacked(\n VERSION,\n bridgeTx.originChainId,\n bridgeTx.destChainId,\n bridgeTx.originSender,\n bridgeTx.destRecipient,\n bridgeTx.originToken,\n bridgeTx.destToken,\n bridgeTx.originAmount\n );\n return abi.encodePacked(\n firstPart,\n bridgeTx.destAmount,\n bridgeTx.originFeeAmount,\n // Note: we skip the deprecated `sendChainGas` flag, which was present in BridgeTransaction V1\n bridgeTx.deadline,\n bridgeTx.nonce,\n // New V2 fields: exclusivity\n bridgeTx.exclusivityRelayer,\n bridgeTx.exclusivityEndTime,\n // New V2 fields: Zap\n bridgeTx.zapNative,\n bridgeTx.zapData\n );\n }\n\n /// @notice Decodes the BridgeTransactionV2 struct from the encoded transaction.\n /// @dev Encoded BridgeTransactionV2 struct must be tightly packed.\n /// Use `validateV2` before decoding to ensure the encoded transaction is valid.\n function decodeV2(bytes calldata encodedTx)\n internal\n pure\n returns (IFastBridgeV2.BridgeTransactionV2 memory bridgeTx)\n {\n bridgeTx.originChainId = originChainId(encodedTx);\n bridgeTx.destChainId = destChainId(encodedTx);\n bridgeTx.originSender = originSender(encodedTx);\n bridgeTx.destRecipient = destRecipient(encodedTx);\n bridgeTx.originToken = originToken(encodedTx);\n bridgeTx.destToken = destToken(encodedTx);\n bridgeTx.originAmount = originAmount(encodedTx);\n bridgeTx.destAmount = destAmount(encodedTx);\n bridgeTx.originFeeAmount = originFeeAmount(encodedTx);\n bridgeTx.deadline = deadline(encodedTx);\n bridgeTx.nonce = nonce(encodedTx);\n bridgeTx.exclusivityRelayer = exclusivityRelayer(encodedTx);\n bridgeTx.exclusivityEndTime = exclusivityEndTime(encodedTx);\n bridgeTx.zapNative = zapNative(encodedTx);\n bridgeTx.zapData = zapData(encodedTx);\n }\n\n /// @notice Extracts the version from the encoded transaction.\n function version(bytes calldata encodedTx) internal pure returns (uint16 version_) {\n // Load 32 bytes from the start and shift it 240 bits to the right to get the highest 16 bits.\n assembly {\n version_ := shr(240, calldataload(encodedTx.offset))\n }\n }\n\n /// @notice Extracts the origin chain ID from the encoded transaction.\n function originChainId(bytes calldata encodedTx) internal pure returns (uint32 originChainId_) {\n // Load 32 bytes from the offset and shift it 224 bits to the right to get the highest 32 bits.\n assembly {\n originChainId_ := shr(224, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_CHAIN_ID)))\n }\n }\n\n /// @notice Extracts the destination chain ID from the encoded transaction.\n function destChainId(bytes calldata encodedTx) internal pure returns (uint32 destChainId_) {\n // Load 32 bytes from the offset and shift it 224 bits to the right to get the highest 32 bits.\n assembly {\n destChainId_ := shr(224, calldataload(add(encodedTx.offset, OFFSET_DEST_CHAIN_ID)))\n }\n }\n\n /// @notice Extracts the origin sender from the encoded transaction.\n function originSender(bytes calldata encodedTx) internal pure returns (address originSender_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n originSender_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_SENDER)))\n }\n }\n\n /// @notice Extracts the destination recipient from the encoded transaction.\n function destRecipient(bytes calldata encodedTx) internal pure returns (address destRecipient_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n destRecipient_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_DEST_RECIPIENT)))\n }\n }\n\n /// @notice Extracts the origin token from the encoded transaction.\n function originToken(bytes calldata encodedTx) internal pure returns (address originToken_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n originToken_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_TOKEN)))\n }\n }\n\n /// @notice Extracts the destination token from the encoded transaction.\n function destToken(bytes calldata encodedTx) internal pure returns (address destToken_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n destToken_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_DEST_TOKEN)))\n }\n }\n\n /// @notice Extracts the origin amount from the encoded transaction.\n function originAmount(bytes calldata encodedTx) internal pure returns (uint256 originAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n originAmount_ := calldataload(add(encodedTx.offset, OFFSET_ORIGIN_AMOUNT))\n }\n }\n\n /// @notice Extracts the destination amount from the encoded transaction.\n function destAmount(bytes calldata encodedTx) internal pure returns (uint256 destAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n destAmount_ := calldataload(add(encodedTx.offset, OFFSET_DEST_AMOUNT))\n }\n }\n\n /// @notice Extracts the origin fee amount from the encoded transaction.\n function originFeeAmount(bytes calldata encodedTx) internal pure returns (uint256 originFeeAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n originFeeAmount_ := calldataload(add(encodedTx.offset, OFFSET_ORIGIN_FEE_AMOUNT))\n }\n }\n\n /// @notice Extracts the deadline from the encoded transaction.\n function deadline(bytes calldata encodedTx) internal pure returns (uint256 deadline_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n deadline_ := calldataload(add(encodedTx.offset, OFFSET_DEADLINE))\n }\n }\n\n /// @notice Extracts the nonce from the encoded transaction.\n function nonce(bytes calldata encodedTx) internal pure returns (uint256 nonce_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n nonce_ := calldataload(add(encodedTx.offset, OFFSET_NONCE))\n }\n }\n\n /// @notice Extracts the exclusivity relayer from the encoded transaction.\n function exclusivityRelayer(bytes calldata encodedTx) internal pure returns (address exclusivityRelayer_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n exclusivityRelayer_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_EXCLUSIVITY_RELAYER)))\n }\n }\n\n /// @notice Extracts the exclusivity end time from the encoded transaction.\n function exclusivityEndTime(bytes calldata encodedTx) internal pure returns (uint256 exclusivityEndTime_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n exclusivityEndTime_ := calldataload(add(encodedTx.offset, OFFSET_EXCLUSIVITY_END_TIME))\n }\n }\n\n /// @notice Extracts the Zap's native value from the encoded transaction.\n function zapNative(bytes calldata encodedTx) internal pure returns (uint256 zapNative_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n zapNative_ := calldataload(add(encodedTx.offset, OFFSET_ZAP_NATIVE))\n }\n }\n\n /// @notice Extracts the Zap's data from the encoded transaction.\n function zapData(bytes calldata encodedTx) internal pure returns (bytes calldata zapData_) {\n zapData_ = encodedTx[OFFSET_ZAP_DATA:];\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/AdminV2.sol\n\n// ════════════════════════════════════════════════ INTERFACES ═════════════════════════════════════════════════════\n\n// ═════════════════════════════════════════════ EXTERNAL IMPORTS ══════════════════════════════════════════════════\n\n/// @title AdminV2\n/// @notice Provides administrative functions and controls for managing the FastBridgeV2 contract,\n/// including access control and configuration settings.\ncontract AdminV2 is AccessControlEnumerable, IAdminV2, IAdminV2Errors {\n using SafeERC20 for IERC20;\n\n /// @notice The address reserved for the native gas token (ETH on Ethereum and most L2s, AVAX on Avalanche, etc.).\n address public constant NATIVE_GAS_TOKEN = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice The role identifier for the Quoter API's off-chain authentication.\n /// @dev Only addresses with this role can post FastBridge quotes to the API.\n bytes32 public constant QUOTER_ROLE = keccak256(\"QUOTER_ROLE\");\n\n /// @notice The role identifier for the Prover's on-chain authentication in FastBridge.\n /// @dev Only addresses with this role can provide proofs that a FastBridge request has been relayed.\n bytes32 public constant PROVER_ROLE = keccak256(\"PROVER_ROLE\");\n\n /// @notice The role identifier for the Guard's on-chain authentication in FastBridge.\n /// @dev Only addresses with this role can dispute submitted relay proofs during the dispute period.\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n\n /// @notice The role identifier for the Canceler's on-chain authentication in FastBridge.\n /// @dev Only addresses with this role can cancel a FastBridge transaction without the cancel delay.\n bytes32 public constant CANCELER_ROLE = keccak256(\"CANCELER_ROLE\");\n\n /// @notice The role identifier for the Governor's on-chain administrative authority.\n /// @dev Only addresses with this role can perform administrative tasks within the contract.\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n /// @notice The denominator for fee rates, representing 100%.\n uint256 public constant FEE_BPS = 1e6;\n /// @notice The maximum protocol fee rate: 1% of the origin amount.\n uint256 public constant FEE_RATE_MAX = 0.01e6;\n\n /// @notice The minimum cancel delay that can be set by the governor.\n uint256 public constant MIN_CANCEL_DELAY = 1 hours;\n /// @notice The default cancel delay set during contract deployment.\n uint256 public constant DEFAULT_CANCEL_DELAY = 1 days;\n\n /// @notice The protocol fee rate taken on the origin amount deposited in the origin chain.\n uint256 public protocolFeeRate;\n\n /// @notice The accumulated protocol fee amounts.\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice The delay period after which a transaction can be permissionlessly cancelled.\n uint256 public cancelDelay;\n\n /// @notice This variable is deprecated and should not be used.\n /// @dev Use ZapNative V2 requests instead.\n uint256 public immutable chainGasAmount = 0;\n\n constructor(address defaultAdmin) {\n _grantRole(DEFAULT_ADMIN_ROLE, defaultAdmin);\n _setCancelDelay(DEFAULT_CANCEL_DELAY);\n }\n\n /// @inheritdoc IAdminV2\n function setCancelDelay(uint256 newCancelDelay) external onlyRole(GOVERNOR_ROLE) {\n _setCancelDelay(newCancelDelay);\n }\n\n /// @inheritdoc IAdminV2\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n if (newFeeRate \u003e FEE_RATE_MAX) revert FeeRateAboveMax();\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n /// @inheritdoc IAdminV2\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n // Early exit if no accumulated fees.\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return;\n // Reset the accumulated fees first.\n protocolFees[token] = 0;\n emit FeesSwept(token, recipient, feeAmount);\n // Sweep the fees as the last transaction action.\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(recipient), feeAmount);\n } else {\n IERC20(token).safeTransfer(recipient, feeAmount);\n }\n }\n\n /// @notice Internal logic to set the cancel delay. Security checks are performed outside of this function.\n /// @dev This function is marked as private to prevent child contracts from calling it directly.\n function _setCancelDelay(uint256 newCancelDelay) private {\n if (newCancelDelay \u003c MIN_CANCEL_DELAY) revert CancelDelayBelowMin();\n uint256 oldCancelDelay = cancelDelay;\n cancelDelay = newCancelDelay;\n emit CancelDelayUpdated(oldCancelDelay, newCancelDelay);\n }\n}\n\n// contracts/FastBridgeV2.sol\n\n// ════════════════════════════════════════════════ INTERFACES ═════════════════════════════════════════════════════\n\n// ═════════════════════════════════════════════ INTERNAL IMPORTS ══════════════════════════════════════════════════\n\n// ═════════════════════════════════════════════ EXTERNAL IMPORTS ══════════════════════════════════════════════════\n\n/// @title FastBridgeV2\n/// @notice Core component of the SynapseRFQ protocol, enabling Relayers (Solvers) to fulfill bridge requests.\n/// Supports ERC20 and native gas tokens, along with the Zap feature for executing actions on the destination chain.\n/// Users interact with the off-chain Quoter API to obtain a current quote for a bridge transaction.\n/// They then submit the bridge request with the quote to this contract, depositing their assets in escrow.\n/// Relayers can fulfill requests by relaying them to the destination chain and must prove fulfillment to claim funds.\n/// Guards monitor proofs and can dispute discrepancies.\n/// Users can reclaim funds by cancelling their requests if it has not been fulfilled within the specified deadline.\ncontract FastBridgeV2 is AdminV2, MulticallTarget, IFastBridgeV2, IFastBridgeV2Errors {\n using BridgeTransactionV2Lib for bytes;\n using SafeERC20 for IERC20;\n\n /// @notice The duration of the dispute period for relayed transactions.\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice The minimum required time between transaction request and deadline.\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n /// @notice The maximum allowed length for zapData.\n uint256 public constant MAX_ZAP_DATA_LENGTH = 2 ** 16 - 1;\n\n /// @notice Maps transaction IDs to bridge details (status, destination chain ID, proof timestamp, and relayer).\n /// Note: this is only stored for transactions having local chain as the origin chain.\n mapping(bytes32 =\u003e BridgeTxDetails) public bridgeTxDetails;\n /// @notice Maps transaction IDs to relay details (block number, block timestamp, and relayer).\n /// Note: this is only stored for transactions having local chain as the destination chain.\n mapping(bytes32 =\u003e BridgeRelay) public bridgeRelayDetails;\n /// @notice Maps sender addresses to their unique bridge nonce.\n mapping(address =\u003e uint256) public senderNonces;\n\n /// @notice This variable is deprecated and should not be used.\n /// @dev Replaced by senderNonces.\n uint256 public immutable nonce = 0;\n /// @notice The block number at which this contract was deployed.\n uint256 public immutable deployBlock;\n\n /// @notice Initializes the FastBridgeV2 contract with the provided default admin,\n /// sets the default cancel delay, and records the deploy block number.\n constructor(address defaultAdmin) AdminV2(defaultAdmin) {\n deployBlock = block.number;\n }\n\n // ══════════════════════════════════════ EXTERNAL MUTABLE (USER FACING) ═══════════════════════════════════════════\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n bridgeV2({\n params: params,\n paramsV2: BridgeParamsV2({\n quoteRelayer: address(0),\n quoteExclusivitySeconds: 0,\n quoteId: bytes(\"\"),\n zapNative: 0,\n zapData: bytes(\"\")\n })\n });\n }\n\n /// Note: this function is deprecated and will be removed in a future version.\n /// @dev Replaced by `cancel`.\n /// @inheritdoc IFastBridge\n function refund(bytes calldata request) external {\n cancelV2(request);\n }\n\n // ══════════════════════════════════════ EXTERNAL MUTABLE (AGENT FACING) ══════════════════════════════════════════\n\n /// @inheritdoc IFastBridge\n function relay(bytes calldata request) external payable {\n // `relay` override will validate the request.\n relayV2({request: request, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes calldata request, bytes32 destTxHash) external {\n request.validateV2();\n proveV2({transactionId: keccak256(request), destTxHash: destTxHash, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridgeV2\n function claimV2(bytes calldata request) external {\n // `claim` override will validate the request.\n claim({request: request, to: address(0)});\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n // Aggregate the read operations from the same storage slot.\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n address disputedRelayer = $.proofRelayer;\n BridgeStatus status = $.status;\n uint56 proofBlockTimestamp = $.proofBlockTimestamp;\n\n // Can only dispute a RELAYER_PROVED transaction within the dispute period.\n if (status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(proofBlockTimestamp) \u003e DISPUTE_PERIOD) {\n revert DisputePeriodPassed();\n }\n\n // Update status to REQUESTED and delete the disputed proof details.\n // Note: these are storage writes.\n $.status = BridgeStatus.REQUESTED;\n $.proofRelayer = address(0);\n $.proofBlockTimestamp = 0;\n\n emit BridgeProofDisputed(transactionId, disputedRelayer);\n }\n\n // ══════════════════════════════════════════════ EXTERNAL VIEWS ═══════════════════════════════════════════════════\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n // The correct relayer can only claim a RELAYER_PROVED transaction after the dispute period.\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n if ($.status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if ($.proofRelayer != relayer) revert SenderIncorrect();\n\n return _timeSince($.proofBlockTimestamp) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n /// @dev This method is added to achieve backwards compatibility with decoding requests into V1 structs:\n /// - `zapNative` is partially reported as a zero/non-zero flag\n /// - `zapData` is ignored\n /// In order to process all kinds of requests use getBridgeTransactionV2 instead.\n function getBridgeTransaction(bytes calldata request) external view returns (BridgeTransaction memory) {\n // Try decoding into V2 struct first. This will revert if V1 struct is passed.\n try this.getBridgeTransactionV2(request) returns (BridgeTransactionV2 memory txV2) {\n // Note: we entirely ignore the zapData field, as it was not present in V1.\n return BridgeTransaction({\n originChainId: txV2.originChainId,\n destChainId: txV2.destChainId,\n originSender: txV2.originSender,\n destRecipient: txV2.destRecipient,\n originToken: txV2.originToken,\n destToken: txV2.destToken,\n originAmount: txV2.originAmount,\n destAmount: txV2.destAmount,\n originFeeAmount: txV2.originFeeAmount,\n sendChainGas: txV2.zapNative != 0,\n deadline: txV2.deadline,\n nonce: txV2.nonce\n });\n } catch {\n // Fallback to V1 struct.\n return abi.decode(request, (BridgeTransaction));\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function getBridgeTransactionV2(bytes calldata request) external pure returns (BridgeTransactionV2 memory) {\n request.validateV2();\n return BridgeTransactionV2Lib.decodeV2(request);\n }\n\n // ═══════════════════════════════════════ PUBLIC MUTABLE (USER FACING) ════════════════════════════════════════════\n\n /// @inheritdoc IFastBridgeV2\n function bridgeV2(BridgeParams memory params, BridgeParamsV2 memory paramsV2) public payable {\n // If relayer exclusivity is not intended for this bridge, set exclusivityEndTime to static zero.\n // Otherwise, set exclusivity to expire at the current block ts offset by quoteExclusivitySeconds.\n int256 exclusivityEndTime = 0;\n if (paramsV2.quoteRelayer != address(0)) {\n exclusivityEndTime = int256(block.timestamp) + paramsV2.quoteExclusivitySeconds;\n }\n _validateBridgeParams(params, paramsV2, exclusivityEndTime);\n\n // Transfer tokens to bridge contract. We use the actual transferred amount in case of transfer fees.\n uint256 originAmount = _takeBridgedUserAsset(params.originToken, params.originAmount);\n\n // Track the amount of origin token owed to protocol.\n uint256 originFeeAmount = 0;\n if (protocolFeeRate \u003e 0) {\n originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n // The Relayer filling this request will be paid the originAmount after fees.\n // Note: the protocol fees will be accumulated only when the Relayer claims the origin collateral.\n originAmount -= originFeeAmount;\n }\n\n // Hash the bridge request and set the initial status to REQUESTED.\n bytes memory request = BridgeTransactionV2Lib.encodeV2(\n BridgeTransactionV2({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n deadline: params.deadline,\n // Increment the sender's nonce on every bridge.\n nonce: senderNonces[params.sender]++,\n exclusivityRelayer: paramsV2.quoteRelayer,\n // We checked exclusivityEndTime to be in range [0 .. params.deadline] above, so can safely cast.\n exclusivityEndTime: uint256(exclusivityEndTime),\n zapNative: paramsV2.zapNative,\n zapData: paramsV2.zapData\n })\n );\n bytes32 transactionId = keccak256(request);\n // Note: the tx status will be updated throughout the tx lifecycle, while destChainId is set once here.\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n bridgeTxDetails[transactionId].destChainId = params.dstChainId;\n\n emit BridgeRequested({\n transactionId: transactionId,\n sender: params.sender,\n request: request,\n destChainId: params.dstChainId,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n sendChainGas: paramsV2.zapNative != 0\n });\n emit BridgeQuoteDetails(transactionId, paramsV2.quoteId);\n }\n\n /// @inheritdoc IFastBridgeV2\n function cancelV2(bytes calldata request) public {\n // Decode the request and check that it could be cancelled.\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n\n // Can only cancel a REQUESTED transaction after its deadline expires.\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n if ($.status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n\n // Permissionless cancel is only allowed after `cancelDelay` on top of the deadline.\n uint256 deadline = request.deadline();\n if (!hasRole(CANCELER_ROLE, msg.sender)) deadline += cancelDelay;\n if (block.timestamp \u003c= deadline) revert DeadlineNotExceeded();\n\n // Update status to REFUNDED.\n // Note: this is a storage write.\n $.status = BridgeStatus.REFUNDED;\n\n // Return the full amount (collateral + protocol fees) to the original sender.\n // The protocol fees are only accumulated when the transaction is claimed, so we don't need to update them here.\n address to = request.originSender();\n address token = request.originToken();\n uint256 amount = request.originAmount() + request.originFeeAmount();\n\n // Emit the event before any external calls.\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n\n // Return the funds to the original sender as last transaction action.\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(to), amount);\n } else {\n IERC20(token).safeTransfer(to, amount);\n }\n }\n\n // ═══════════════════════════════════════ PUBLIC MUTABLE (AGENT FACING) ═══════════════════════════════════════════\n\n /// @inheritdoc IFastBridgeV2\n function relayV2(bytes calldata request, address relayer) public payable {\n // Decode the request and check that it could be relayed.\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n _validateRelayParams(request, transactionId, relayer);\n\n // Mark the bridge request as relayed by saving the relayer and the block details.\n bridgeRelayDetails[transactionId].blockNumber = uint48(block.number);\n bridgeRelayDetails[transactionId].blockTimestamp = uint48(block.timestamp);\n bridgeRelayDetails[transactionId].relayer = relayer;\n\n // Transfer tokens to recipient on destination chain and trigger Zap if requested.\n address to = request.destRecipient();\n address token = request.destToken();\n uint256 amount = request.destAmount();\n uint256 zapNative = request.zapNative();\n\n // Emit the event before any external calls.\n emit BridgeRelayed({\n transactionId: transactionId,\n relayer: relayer,\n to: to,\n originChainId: request.originChainId(),\n originToken: request.originToken(),\n destToken: token,\n originAmount: request.originAmount(),\n destAmount: amount,\n chainGasAmount: zapNative\n });\n\n // All state changes have been done at this point, can proceed to the external calls.\n // This follows the checks-effects-interactions pattern to mitigate potential reentrancy attacks.\n if (token == NATIVE_GAS_TOKEN) {\n // For the native gas token, additional zapNative is not allowed.\n if (zapNative != 0) revert ZapNativeNotSupported();\n // Check that the correct msg.value was sent.\n if (msg.value != amount) revert MsgValueIncorrect();\n // Don't do a native transfer yet: we will handle it alongside the Zap below.\n } else {\n // For ERC20s, we check that the correct msg.value was sent.\n if (msg.value != zapNative) revert MsgValueIncorrect();\n // We need to transfer the tokens from the Relayer to the recipient first before performing an\n // optional post-transfer Zap.\n IERC20(token).safeTransferFrom(msg.sender, to, amount);\n }\n // At this point we have done:\n // - Transferred the requested amount of ERC20 tokens to the recipient.\n // At this point we have confirmed:\n // - For ERC20s: msg.value matches the requested zapNative amount.\n // - For the native gas token: msg.value matches the requested destAmount.\n // Remaining optional things to do:\n // - Forward the full msg.value to the recipient (if non-zero).\n // - Trigger a Zap (if zapData is present).\n bytes calldata zapData = request.zapData();\n if (zapData.length != 0) {\n // Zap Data is present: Zap has been requested by the recipient. Trigger it forwarding the full msg.value.\n _triggerZapWithChecks({recipient: to, token: token, amount: amount, zapData: zapData});\n // Note: if token has a fee on transfers, the recipient will have received less than `amount`.\n // This is a very niche edge case and should be handled by the recipient contract.\n } else if (msg.value != 0) {\n // Zap Data is missing, but msg.value was sent. This could happen in two different cases:\n // - Relay with the native gas token is happening.\n // - Relay with ERC20 is happening, with a `zapNative \u003e 0` request.\n // In both cases, we need to transfer the full msg.value to the recipient.\n Address.sendValue(payable(to), msg.value);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function proveV2(bytes32 transactionId, bytes32 destTxHash, address relayer) public onlyRole(PROVER_ROLE) {\n // Can only prove a REQUESTED transaction.\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n if ($.status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n\n // Update status to RELAYER_PROVED and store the proof details.\n // Note: these are storage writes.\n $.status = BridgeStatus.RELAYER_PROVED;\n $.proofBlockTimestamp = uint56(block.timestamp);\n $.proofRelayer = relayer;\n\n emit BridgeProofProvided(transactionId, relayer, destTxHash);\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes calldata request, address to) public {\n // Decode the request and check that it could be claimed.\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n\n // Aggregate the read operations from the same storage slot.\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n address proofRelayer = $.proofRelayer;\n BridgeStatus status = $.status;\n uint56 proofBlockTimestamp = $.proofBlockTimestamp;\n\n // Can only claim a RELAYER_PROVED transaction after the dispute period.\n if (status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(proofBlockTimestamp) \u003c= DISPUTE_PERIOD) revert DisputePeriodNotPassed();\n if (to == address(0)) {\n // Anyone could claim the funds to the proven relayer on their behalf.\n to = proofRelayer;\n } else if (proofRelayer != msg.sender) {\n // Only the proven relayer could specify an address to claim the funds to.\n revert SenderIncorrect();\n }\n\n // Update status to RELAYER_CLAIMED and transfer the origin collateral to the specified claim address.\n // Note: this is a storage write.\n $.status = BridgeStatus.RELAYER_CLAIMED;\n\n // Accumulate protocol fees if origin fee amount exists.\n address token = request.originToken();\n uint256 amount = request.originAmount();\n uint256 originFeeAmount = request.originFeeAmount();\n if (originFeeAmount \u003e 0) protocolFees[token] += originFeeAmount;\n\n // Emit the event before any external calls.\n emit BridgeDepositClaimed(transactionId, proofRelayer, to, token, amount);\n\n // Complete the relayer claim as the last transaction action.\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(to), amount);\n } else {\n IERC20(token).safeTransfer(to, amount);\n }\n }\n\n // ═══════════════════════════════════════════════ PUBLIC VIEWS ════════════════════════════════════════════════════\n\n /// @inheritdoc IFastBridgeV2\n function bridgeStatuses(bytes32 transactionId) public view returns (BridgeStatus status) {\n return bridgeTxDetails[transactionId].status;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeProofs(bytes32 transactionId) public view returns (uint96 timestamp, address relayer) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n timestamp = $.proofBlockTimestamp;\n relayer = $.proofRelayer;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeRelays(bytes32 transactionId) public view returns (bool) {\n // This transaction has been relayed if the relayer address is recorded.\n return bridgeRelayDetails[transactionId].relayer != address(0);\n }\n\n // ═════════════════════════════════════════════ INTERNAL METHODS ══════════════════════════════════════════════════\n\n /// @notice Takes the bridged asset from the user into FastBridgeV2 custody. The asset will later be\n /// claimed by the relayer who completed the relay on the destination chain, or returned to the user\n /// via the cancel function if no relay is completed.\n function _takeBridgedUserAsset(address token, uint256 amount) internal returns (uint256 amountTaken) {\n if (token == NATIVE_GAS_TOKEN) {\n // For the native gas token, we just need to check that the supplied msg.value is correct.\n // Supplied `msg.value` is already in FastBridgeV2 custody.\n if (amount != msg.value) revert MsgValueIncorrect();\n amountTaken = msg.value;\n } else {\n // For ERC20s, token is explicitly transferred from the user to FastBridgeV2.\n // We don't allow non-zero `msg.value` to avoid extra funds from being stuck in FastBridgeV2.\n if (msg.value != 0) revert MsgValueIncorrect();\n // Throw an explicit error if the provided token address is not a contract.\n if (token.code.length == 0) revert TokenNotContract();\n\n // Use the balance difference as the amount taken in case of fee on transfer tokens.\n amountTaken = IERC20(token).balanceOf(address(this));\n IERC20(token).safeTransferFrom(msg.sender, address(this), amount);\n amountTaken = IERC20(token).balanceOf(address(this)) - amountTaken;\n }\n }\n\n /// @notice Calls the recipient's hook function with the specified zapData and validates\n /// the returned value.\n function _triggerZapWithChecks(address recipient, address token, uint256 amount, bytes calldata zapData) internal {\n // Call the recipient's hook function with the specified zapData, bubbling any revert messages.\n bytes memory returnData = Address.functionCallWithValue({\n target: recipient,\n data: abi.encodeCall(IZapRecipient.zap, (token, amount, zapData)),\n // Note: see `relay()` for reasoning behind passing msg.value.\n value: msg.value\n });\n\n // Explicit revert if no return data at all.\n if (returnData.length == 0) revert RecipientNoReturnValue();\n // Check that exactly a single return value was returned.\n if (returnData.length != 32) revert RecipientIncorrectReturnValue();\n // Return value should be abi-encoded hook function selector.\n if (bytes32(returnData) != bytes32(IZapRecipient.zap.selector)) {\n revert RecipientIncorrectReturnValue();\n }\n }\n\n /// @notice Calculates the time elapsed since a proof was submitted.\n /// @dev The proof.timestamp stores block timestamps as uint56 for gas optimization.\n /// _timeSince(proof) handles timestamp rollover when block.timestamp \u003e type(uint56).max but\n /// proof.timestamp \u003c type(uint56).max via an unchecked statement.\n /// @param proofBlockTimestamp The block timestamp when the proof was submitted.\n /// @return delta The time elapsed since proof submission.\n function _timeSince(uint56 proofBlockTimestamp) internal view returns (uint256 delta) {\n unchecked {\n delta = uint56(block.timestamp) - proofBlockTimestamp;\n }\n }\n\n /// @notice Validates all parameters required for a bridge transaction.\n /// @dev This function's complexity cannot be reduced due to the number of required checks,\n /// so we disable the code-complexity rule.\n // solhint-disable-next-line code-complexity\n function _validateBridgeParams(\n BridgeParams memory params,\n BridgeParamsV2 memory paramsV2,\n int256 exclusivityEndTime\n )\n internal\n view\n {\n // Check V1 (legacy) params.\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.sender == address(0) || params.to == address(0)) revert ZeroAddress();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n\n // Check V2 params.\n if (paramsV2.zapData.length \u003e MAX_ZAP_DATA_LENGTH) revert ZapDataLengthAboveMax();\n if (paramsV2.zapNative != 0 \u0026\u0026 params.destToken == NATIVE_GAS_TOKEN) {\n revert ZapNativeNotSupported();\n }\n\n // exclusivityEndTime must be in range [0 .. params.deadline].\n if (exclusivityEndTime \u003c 0 || exclusivityEndTime \u003e int256(params.deadline)) {\n revert ExclusivityParamsIncorrect();\n }\n }\n\n /// @notice Validates all parameters required for a relay transaction.\n function _validateRelayParams(bytes calldata request, bytes32 transactionId, address relayer) internal view {\n if (relayer == address(0)) revert ZeroAddress();\n // Check that the transaction has not been relayed yet and is for the current chain.\n if (bridgeRelays(transactionId)) revert TransactionRelayed();\n if (request.destChainId() != block.chainid) revert ChainIncorrect();\n // Check that the deadline for relay to happen has not passed yet.\n if (block.timestamp \u003e request.deadline()) revert DeadlineExceeded();\n // Check the exclusivity period, if it was specified and is still ongoing.\n address exclRelayer = request.exclusivityRelayer();\n if (exclRelayer != address(0) \u0026\u0026 exclRelayer != relayer \u0026\u0026 block.timestamp \u003c= request.exclusivityEndTime()) {\n revert ExclusivityPeriodNotPassed();\n }\n }\n}\n","language":"Solidity","languageVersion":"0.8.24","compilerVersion":"0.8.24","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"","srcMapRuntime":"","abiDefinition":[{"inputs":[],"name":"AccessControlBadConfirmation","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"bytes32","name":"neededRole","type":"bytes32"}],"name":"AccessControlUnauthorizedAccount","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"previousAdminRole","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"newAdminRole","type":"bytes32"}],"name":"RoleAdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleRevoked","type":"event"},{"inputs":[],"name":"DEFAULT_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleAdmin","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"grantRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"hasRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"callerConfirmation","type":"address"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"revokeRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"}],"userDoc":{"kind":"user","methods":{},"version":1},"developerDoc":{"details":"Contract module that allows children to implement role-based access control mechanisms. This is a lightweight version that doesn't allow enumerating role members except through off-chain means by accessing the contract event logs. Some applications may benefit from on-chain enumerability, for those cases see {AccessControlEnumerable}. Roles are referred to by their `bytes32` identifier. These should be exposed in the external API and be unique. The best way to achieve this is by using `public constant` hash digests: ```solidity bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\"); ``` Roles can be used to represent a set of permissions. To restrict access to a function call, use {hasRole}: ```solidity function foo() public { require(hasRole(MY_ROLE, msg.sender)); ... } ``` Roles can be granted and revoked dynamically via the {grantRole} and {revokeRole} functions. Each role has an associated admin role, and only accounts that have a role's admin role can call {grantRole} and {revokeRole}. By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means that only accounts with this role will be able to grant or revoke other roles. More complex role relationships can be created by using {_setRoleAdmin}. WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to grant and revoke this role. Extra precautions should be taken to secure accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules} to enforce additional security measures for this role.","errors":{"AccessControlBadConfirmation()":[{"details":"The caller of a function is not the expected one. NOTE: Don't confuse with {AccessControlUnauthorizedAccount}."}],"AccessControlUnauthorizedAccount(address,bytes32)":[{"details":"The `account` is missing a role."}]},"events":{"RoleAdminChanged(bytes32,bytes32,bytes32)":{"details":"Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole` `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite {RoleAdminChanged} not being emitted signaling this."},"RoleGranted(bytes32,address,address)":{"details":"Emitted when `account` is granted `role`. `sender` is the account that originated the contract call, an admin role bearer except when using {AccessControl-_setupRole}."},"RoleRevoked(bytes32,address,address)":{"details":"Emitted when `account` is revoked `role`. `sender` is the account that originated the contract call: - if using `revokeRole`, it is the admin role bearer - if using `renounceRole`, it is the role bearer (i.e. `account`)"}},"kind":"dev","methods":{"getRoleAdmin(bytes32)":{"details":"Returns the admin role that controls `role`. See {grantRole} and {revokeRole}. To change a role's admin, use {_setRoleAdmin}."},"grantRole(bytes32,address)":{"details":"Grants `role` to `account`. If `account` had not been already granted `role`, emits a {RoleGranted} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleGranted} event."},"hasRole(bytes32,address)":{"details":"Returns `true` if `account` has been granted `role`."},"renounceRole(bytes32,address)":{"details":"Revokes `role` from the calling account. Roles are often managed via {grantRole} and {revokeRole}: this function's purpose is to provide a mechanism for accounts to lose their privileges if they are compromised (such as when a trusted device is misplaced). If the calling account had been revoked `role`, emits a {RoleRevoked} event. Requirements: - the caller must be `callerConfirmation`. May emit a {RoleRevoked} event."},"revokeRole(bytes32,address)":{"details":"Revokes `role` from `account`. If `account` had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleRevoked} event."},"supportsInterface(bytes4)":{"details":"See {IERC165-supportsInterface}."}},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[],\"name\":\"AccessControlBadConfirmation\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"neededRole\",\"type\":\"bytes32\"}],\"name\":\"AccessControlUnauthorizedAccount\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"previousAdminRole\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"newAdminRole\",\"type\":\"bytes32\"}],\"name\":\"RoleAdminChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleGranted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleRevoked\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"DEFAULT_ADMIN_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"}],\"name\":\"getRoleAdmin\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"grantRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"hasRole\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"callerConfirmation\",\"type\":\"address\"}],\"name\":\"renounceRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"revokeRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes4\",\"name\":\"interfaceId\",\"type\":\"bytes4\"}],\"name\":\"supportsInterface\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"}],\"devdoc\":{\"details\":\"Contract module that allows children to implement role-based access control mechanisms. This is a lightweight version that doesn't allow enumerating role members except through off-chain means by accessing the contract event logs. Some applications may benefit from on-chain enumerability, for those cases see {AccessControlEnumerable}. Roles are referred to by their `bytes32` identifier. These should be exposed in the external API and be unique. The best way to achieve this is by using `public constant` hash digests: ```solidity bytes32 public constant MY_ROLE = keccak256(\\\"MY_ROLE\\\"); ``` Roles can be used to represent a set of permissions. To restrict access to a function call, use {hasRole}: ```solidity function foo() public { require(hasRole(MY_ROLE, msg.sender)); ... } ``` Roles can be granted and revoked dynamically via the {grantRole} and {revokeRole} functions. Each role has an associated admin role, and only accounts that have a role's admin role can call {grantRole} and {revokeRole}. By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means that only accounts with this role will be able to grant or revoke other roles. More complex role relationships can be created by using {_setRoleAdmin}. WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to grant and revoke this role. Extra precautions should be taken to secure accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules} to enforce additional security measures for this role.\",\"errors\":{\"AccessControlBadConfirmation()\":[{\"details\":\"The caller of a function is not the expected one. NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\"}],\"AccessControlUnauthorizedAccount(address,bytes32)\":[{\"details\":\"The `account` is missing a role.\"}]},\"events\":{\"RoleAdminChanged(bytes32,bytes32,bytes32)\":{\"details\":\"Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole` `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite {RoleAdminChanged} not being emitted signaling this.\"},\"RoleGranted(bytes32,address,address)\":{\"details\":\"Emitted when `account` is granted `role`. `sender` is the account that originated the contract call, an admin role bearer except when using {AccessControl-_setupRole}.\"},\"RoleRevoked(bytes32,address,address)\":{\"details\":\"Emitted when `account` is revoked `role`. `sender` is the account that originated the contract call: - if using `revokeRole`, it is the admin role bearer - if using `renounceRole`, it is the role bearer (i.e. `account`)\"}},\"kind\":\"dev\",\"methods\":{\"getRoleAdmin(bytes32)\":{\"details\":\"Returns the admin role that controls `role`. See {grantRole} and {revokeRole}. To change a role's admin, use {_setRoleAdmin}.\"},\"grantRole(bytes32,address)\":{\"details\":\"Grants `role` to `account`. If `account` had not been already granted `role`, emits a {RoleGranted} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleGranted} event.\"},\"hasRole(bytes32,address)\":{\"details\":\"Returns `true` if `account` has been granted `role`.\"},\"renounceRole(bytes32,address)\":{\"details\":\"Revokes `role` from the calling account. Roles are often managed via {grantRole} and {revokeRole}: this function's purpose is to provide a mechanism for accounts to lose their privileges if they are compromised (such as when a trusted device is misplaced). If the calling account had been revoked `role`, emits a {RoleRevoked} event. Requirements: - the caller must be `callerConfirmation`. May emit a {RoleRevoked} event.\"},\"revokeRole(bytes32,address)\":{\"details\":\"Revokes `role` from `account`. If `account` had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleRevoked} event.\"},\"supportsInterface(bytes4)\":{\"details\":\"See {IERC165-supportsInterface}.\"}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeV2.sol\":\"AccessControl\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeV2.sol\":{\"keccak256\":\"0xaab2ee7357681726f0faf799a48ddfbf45fb4da93b69abf61c33dde92b29b74d\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://673391bff9569efc0f9bd99e0e6fece0bc8e8af1f052bb071b407b267a17b3b5\",\"dweb:/ipfs/QmdQQZ6DxpJYhfpinwU5WjLugr2f6qP8h68b5GerhSMQ4j\"]}},\"version\":1}"},"hashes":{"DEFAULT_ADMIN_ROLE()":"a217fddf","getRoleAdmin(bytes32)":"248a9ca3","grantRole(bytes32,address)":"2f2ff15d","hasRole(bytes32,address)":"91d14854","renounceRole(bytes32,address)":"36568abe","revokeRole(bytes32,address)":"d547741f","supportsInterface(bytes4)":"01ffc9a7"}},"solidity/FastBridgeV2.sol:AccessControlEnumerable":{"code":"0x","runtime-code":"0x","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.24 ^0.8.20 ^0.8.4;\n\n// contracts/interfaces/IAdminV2.sol\n\ninterface IAdminV2 {\n event CancelDelayUpdated(uint256 oldCancelDelay, uint256 newCancelDelay);\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n /// @notice Allows the governor to set the cancel delay. The cancel delay is the time period after the transaction\n /// deadline during which a transaction can be permissionlessly cancelled if it hasn't been proven by any Relayer.\n function setCancelDelay(uint256 newCancelDelay) external;\n\n /// @notice Allows the governor to set the protocol fee rate. The protocol fee is taken from the origin\n /// amount and is only applied to completed and claimed transactions.\n /// @dev The protocol fee is abstracted away from the relayers; they always operate using the amounts after fees.\n /// The origin amount they see in the emitted log is what they get credited with.\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n /// @notice Allows the governor to withdraw the accumulated protocol fees from the contract.\n function sweepProtocolFees(address token, address recipient) external;\n}\n\n// contracts/interfaces/IAdminV2Errors.sol\n\ninterface IAdminV2Errors {\n error CancelDelayBelowMin();\n error FeeRateAboveMax();\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IFastBridgeV2Errors.sol\n\ninterface IFastBridgeV2Errors {\n error AmountIncorrect();\n error ChainIncorrect();\n error ExclusivityParamsIncorrect();\n error MsgValueIncorrect();\n error SenderIncorrect();\n error StatusIncorrect();\n error TokenNotContract();\n error ZapDataLengthAboveMax();\n error ZapNativeNotSupported();\n error ZeroAddress();\n\n error RecipientIncorrectReturnValue();\n error RecipientNoReturnValue();\n\n error DeadlineExceeded();\n error DeadlineNotExceeded();\n error DeadlineTooShort();\n error DisputePeriodNotPassed();\n error DisputePeriodPassed();\n error ExclusivityPeriodNotPassed();\n\n error TransactionRelayed();\n}\n\n// contracts/interfaces/IMulticallTarget.sol\n\n/// @notice Interface for a contract that supports multiple calls from the same caller. Inspired by MulticallV3:\n/// https://github.com/mds1/multicall/blob/master/src/Multicall3.sol\ninterface IMulticallTarget {\n struct Result {\n bool success;\n bytes returnData;\n }\n\n /// @notice Executes multiple calls to this contract in a single transaction while preserving msg.sender.\n /// Return data from the calls is discarded.\n /// @dev This method is non-payable, so only calls with msg.value of 0 can be batched.\n /// If ignoreReverts is set to true, reverted calls will be skipped.\n /// Otherwise, the entire batch will revert with the original revert reason.\n /// @param data List of ABI-encoded calldata for the calls to execute\n /// @param ignoreReverts Whether to skip calls that revert\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external;\n\n /// @notice Executes multiple calls to this contract in a single transaction while preserving msg.sender.\n /// Return data from each call is preserved.\n /// @dev This method is non-payable, so only calls with msg.value of 0 can be batched.\n /// If ignoreReverts is set to true, reverted calls will be skipped.\n /// Otherwise, the entire batch will revert with the original revert reason.\n /// @param data List of ABI-encoded calldata for the calls to execute\n /// @param ignoreReverts Whether to skip calls that revert\n /// @return results List of results from the calls, each containing (success, returnData)\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results);\n}\n\n// contracts/interfaces/IZapRecipient.sol\n\n/// @notice Interface for contracts that can perform Zap operations. Such contracts could be used as Recipients\n/// in a FastBridge transaction that includes a Zap operation. The Zap Data should include instructions on how\n/// exactly the Zap operation should be executed, which would typically include the target address and calldata\n/// to use. The exact implementation of the Zap Data encoding is up to the Recipient contract.\ninterface IZapRecipient {\n /// @notice Performs a Zap operation with the given token and amount according to the provided Zap data.\n /// @param token The address of the token being used for the Zap operation.\n /// @param amount The amount of tokens to be used.\n /// @param zapData The encoded data specifying how the Zap operation should be executed.\n /// @return The function selector to indicate successful execution.\n function zap(address token, uint256 amount, bytes memory zapData) external payable returns (bytes4);\n}\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// contracts/interfaces/IFastBridgeV2.sol\n\ninterface IFastBridgeV2 is IFastBridge {\n enum BridgeStatus {\n NULL, // Doesn't exist yet.\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n struct BridgeTxDetails {\n BridgeStatus status;\n uint32 destChainId;\n uint56 proofBlockTimestamp;\n address proofRelayer;\n }\n\n struct BridgeRelay {\n uint48 blockNumber;\n uint48 blockTimestamp;\n address relayer;\n }\n\n /// @notice New params introduced in the FastBridgeV2.\n /// We are passing fields from the older BridgeParams struct outside of this struct for backwards compatibility.\n /// Note: quoteRelayer and quoteExclusivitySeconds are either both zero (indicating no exclusivity)\n /// or both non-zero (indicating exclusivity for the given period).\n /// Note: zapNative \u003e 0 can NOT be used with destToken = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE (native token)\n /// @param quoteRelayer Relayer that provided the quote for the transaction\n /// @param quoteExclusivitySeconds Period of time the quote relayer is guaranteed exclusivity after user's deposit\n /// @param quoteId Unique quote identifier used for tracking the quote\n /// @param zapNative ETH value to send to the recipient (if any)\n /// @param zapData Parameters for the Zap to the destination recipient (if any)\n struct BridgeParamsV2 {\n address quoteRelayer;\n int256 quoteExclusivitySeconds;\n bytes quoteId;\n uint256 zapNative;\n bytes zapData;\n }\n\n /// @notice Updated bridge transaction struct to include parameters introduced in FastBridgeV2.\n /// Note: only `exclusivityRelayer` can fill such a transaction until `exclusivityEndTime`.\n struct BridgeTransactionV2 {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n // Note: sendChainGas flag from V1 is deprecated\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n address exclusivityRelayer;\n uint256 exclusivityEndTime;\n uint256 zapNative; // ETH value to send to the recipient (if any)\n bytes zapData; // data to pass for the Zap action (if any)\n }\n\n event BridgeQuoteDetails(bytes32 indexed transactionId, bytes quoteId);\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability\n /// to provide temporary exclusivity fill rights for the quote relayer.\n /// @param params The parameters required to bridge\n /// @param paramsV2 The parameters for exclusivity fill rights (optional, can be left empty)\n function bridgeV2(BridgeParams memory params, BridgeParamsV2 memory paramsV2) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function relayV2(bytes memory request, address relayer) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param transactionId The transaction id associated with the encoded bridge transaction to prove\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function proveV2(bytes32 transactionId, bytes32 destTxHash, address relayer) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital.\n /// @notice Can only send funds to the relayer address on the proof.\n /// @param request The encoded bridge transaction to claim on origin chain\n function claimV2(bytes memory request) external;\n\n /// @notice Cancels an outstanding bridge transaction in case optimistic bridging failed and returns the full amount\n /// to the original sender.\n /// @param request The encoded bridge transaction to refund\n function cancelV2(bytes memory request) external;\n\n /// @notice Checks if a transaction has been relayed\n /// @param transactionId The ID of the transaction to check\n /// @return True if the transaction has been relayed, false otherwise\n function bridgeRelays(bytes32 transactionId) external view returns (bool);\n\n /// @notice Returns the status of a bridge transaction\n /// @param transactionId The ID of the bridge transaction\n /// @return BridgeStatus Status of the bridge transaction\n function bridgeStatuses(bytes32 transactionId) external view returns (BridgeStatus);\n\n /// @notice Returns the timestamp and relayer of a bridge proof\n /// @param transactionId The ID of the bridge transaction\n /// @return timestamp The timestamp of the bridge proof\n /// @return relayer The relayer address of the bridge proof\n function bridgeProofs(bytes32 transactionId) external view returns (uint96 timestamp, address relayer);\n\n /// @notice Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\n /// @param request The bridge request to decode\n function getBridgeTransactionV2(bytes memory request) external view returns (BridgeTransactionV2 memory);\n}\n\n// contracts/utils/MulticallTarget.sol\n\n// solhint-disable avoid-low-level-calls\n/// @notice Abstract contract template that supports batched calls while preserving msg.sender.\n/// Only calls with msg.value of 0 can be batched.\nabstract contract MulticallTarget is IMulticallTarget {\n error MulticallTarget__UndeterminedRevert();\n\n /// @inheritdoc IMulticallTarget\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external {\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\n if (!success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(result);\n }\n }\n }\n\n /// @inheritdoc IMulticallTarget\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results)\n {\n results = new Result[](data.length);\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (results[i].success, results[i].returnData) = address(this).delegatecall(data[i]);\n if (!results[i].success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(results[i].returnData);\n }\n }\n }\n\n /// @dev Bubbles the revert message from the underlying call.\n /// Note: preserves the same custom error or revert string, if one was used.\n /// Source: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v5.0.2/contracts/utils/Address.sol#L143-L158\n function _bubbleRevert(bytes memory returnData) internal pure {\n // Look for revert reason and bubble it up if present\n if (returnData.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n // solhint-disable-next-line no-inline-assembly\n assembly {\n let returndata_size := mload(returnData)\n revert(add(32, returnData), returndata_size)\n }\n } else {\n revert MulticallTarget__UndeterminedRevert();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// contracts/libs/BridgeTransactionV2.sol\n\n// solhint-disable no-inline-assembly\nlibrary BridgeTransactionV2Lib {\n uint16 internal constant VERSION = 2;\n\n // Offsets of the fields in the packed BridgeTransactionV2 struct\n // uint16 version [000 .. 002)\n // uint32 originChainId [002 .. 006)\n // uint32 destChainId [006 .. 010)\n // address originSender [010 .. 030)\n // address destRecipient [030 .. 050)\n // address originToken [050 .. 070)\n // address destToken [070 .. 090)\n // uint256 originAmount [090 .. 122)\n // uint256 destAmount [122 .. 154)\n // uint256 originFeeAmount [154 .. 186)\n // uint256 deadline [186 .. 218)\n // uint256 nonce [218 .. 250)\n // address exclusivityRelayer [250 .. 270)\n // uint256 exclusivityEndTime [270 .. 302)\n // uint256 zapNative [302 .. 334)\n // bytes zapData [334 .. ***)\n\n // forgefmt: disable-start\n uint256 private constant OFFSET_ORIGIN_CHAIN_ID = 2;\n uint256 private constant OFFSET_DEST_CHAIN_ID = 6;\n uint256 private constant OFFSET_ORIGIN_SENDER = 10;\n uint256 private constant OFFSET_DEST_RECIPIENT = 30;\n uint256 private constant OFFSET_ORIGIN_TOKEN = 50;\n uint256 private constant OFFSET_DEST_TOKEN = 70;\n uint256 private constant OFFSET_ORIGIN_AMOUNT = 90;\n uint256 private constant OFFSET_DEST_AMOUNT = 122;\n uint256 private constant OFFSET_ORIGIN_FEE_AMOUNT = 154;\n uint256 private constant OFFSET_DEADLINE = 186;\n uint256 private constant OFFSET_NONCE = 218;\n uint256 private constant OFFSET_EXCLUSIVITY_RELAYER = 250;\n uint256 private constant OFFSET_EXCLUSIVITY_END_TIME = 270;\n uint256 private constant OFFSET_ZAP_NATIVE = 302;\n uint256 private constant OFFSET_ZAP_DATA = 334;\n // forgefmt: disable-end\n\n error BridgeTransactionV2__InvalidEncodedTx();\n error BridgeTransactionV2__UnsupportedVersion(uint16 version);\n\n /// @notice Validates that the encoded transaction is a tightly packed encoded payload for BridgeTransactionV2.\n /// @dev Checks the minimum length and the version, use this function before decoding any of the fields.\n function validateV2(bytes calldata encodedTx) internal pure {\n // Check the minimum length: must at least include all static fields.\n if (encodedTx.length \u003c OFFSET_ZAP_DATA) revert BridgeTransactionV2__InvalidEncodedTx();\n // Once we validated the length, we can be sure that the version field is present.\n uint16 version_ = version(encodedTx);\n if (version_ != VERSION) revert BridgeTransactionV2__UnsupportedVersion(version_);\n }\n\n /// @notice Encodes the BridgeTransactionV2 struct by tightly packing the fields.\n /// @dev `abi.decode` will not work as a result of the tightly packed fields. Use `decodeV2` to decode instead.\n function encodeV2(IFastBridgeV2.BridgeTransactionV2 memory bridgeTx) internal pure returns (bytes memory) {\n // We split the encoding into two parts to avoid stack-too-deep error\n bytes memory firstPart = abi.encodePacked(\n VERSION,\n bridgeTx.originChainId,\n bridgeTx.destChainId,\n bridgeTx.originSender,\n bridgeTx.destRecipient,\n bridgeTx.originToken,\n bridgeTx.destToken,\n bridgeTx.originAmount\n );\n return abi.encodePacked(\n firstPart,\n bridgeTx.destAmount,\n bridgeTx.originFeeAmount,\n // Note: we skip the deprecated `sendChainGas` flag, which was present in BridgeTransaction V1\n bridgeTx.deadline,\n bridgeTx.nonce,\n // New V2 fields: exclusivity\n bridgeTx.exclusivityRelayer,\n bridgeTx.exclusivityEndTime,\n // New V2 fields: Zap\n bridgeTx.zapNative,\n bridgeTx.zapData\n );\n }\n\n /// @notice Decodes the BridgeTransactionV2 struct from the encoded transaction.\n /// @dev Encoded BridgeTransactionV2 struct must be tightly packed.\n /// Use `validateV2` before decoding to ensure the encoded transaction is valid.\n function decodeV2(bytes calldata encodedTx)\n internal\n pure\n returns (IFastBridgeV2.BridgeTransactionV2 memory bridgeTx)\n {\n bridgeTx.originChainId = originChainId(encodedTx);\n bridgeTx.destChainId = destChainId(encodedTx);\n bridgeTx.originSender = originSender(encodedTx);\n bridgeTx.destRecipient = destRecipient(encodedTx);\n bridgeTx.originToken = originToken(encodedTx);\n bridgeTx.destToken = destToken(encodedTx);\n bridgeTx.originAmount = originAmount(encodedTx);\n bridgeTx.destAmount = destAmount(encodedTx);\n bridgeTx.originFeeAmount = originFeeAmount(encodedTx);\n bridgeTx.deadline = deadline(encodedTx);\n bridgeTx.nonce = nonce(encodedTx);\n bridgeTx.exclusivityRelayer = exclusivityRelayer(encodedTx);\n bridgeTx.exclusivityEndTime = exclusivityEndTime(encodedTx);\n bridgeTx.zapNative = zapNative(encodedTx);\n bridgeTx.zapData = zapData(encodedTx);\n }\n\n /// @notice Extracts the version from the encoded transaction.\n function version(bytes calldata encodedTx) internal pure returns (uint16 version_) {\n // Load 32 bytes from the start and shift it 240 bits to the right to get the highest 16 bits.\n assembly {\n version_ := shr(240, calldataload(encodedTx.offset))\n }\n }\n\n /// @notice Extracts the origin chain ID from the encoded transaction.\n function originChainId(bytes calldata encodedTx) internal pure returns (uint32 originChainId_) {\n // Load 32 bytes from the offset and shift it 224 bits to the right to get the highest 32 bits.\n assembly {\n originChainId_ := shr(224, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_CHAIN_ID)))\n }\n }\n\n /// @notice Extracts the destination chain ID from the encoded transaction.\n function destChainId(bytes calldata encodedTx) internal pure returns (uint32 destChainId_) {\n // Load 32 bytes from the offset and shift it 224 bits to the right to get the highest 32 bits.\n assembly {\n destChainId_ := shr(224, calldataload(add(encodedTx.offset, OFFSET_DEST_CHAIN_ID)))\n }\n }\n\n /// @notice Extracts the origin sender from the encoded transaction.\n function originSender(bytes calldata encodedTx) internal pure returns (address originSender_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n originSender_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_SENDER)))\n }\n }\n\n /// @notice Extracts the destination recipient from the encoded transaction.\n function destRecipient(bytes calldata encodedTx) internal pure returns (address destRecipient_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n destRecipient_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_DEST_RECIPIENT)))\n }\n }\n\n /// @notice Extracts the origin token from the encoded transaction.\n function originToken(bytes calldata encodedTx) internal pure returns (address originToken_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n originToken_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_TOKEN)))\n }\n }\n\n /// @notice Extracts the destination token from the encoded transaction.\n function destToken(bytes calldata encodedTx) internal pure returns (address destToken_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n destToken_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_DEST_TOKEN)))\n }\n }\n\n /// @notice Extracts the origin amount from the encoded transaction.\n function originAmount(bytes calldata encodedTx) internal pure returns (uint256 originAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n originAmount_ := calldataload(add(encodedTx.offset, OFFSET_ORIGIN_AMOUNT))\n }\n }\n\n /// @notice Extracts the destination amount from the encoded transaction.\n function destAmount(bytes calldata encodedTx) internal pure returns (uint256 destAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n destAmount_ := calldataload(add(encodedTx.offset, OFFSET_DEST_AMOUNT))\n }\n }\n\n /// @notice Extracts the origin fee amount from the encoded transaction.\n function originFeeAmount(bytes calldata encodedTx) internal pure returns (uint256 originFeeAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n originFeeAmount_ := calldataload(add(encodedTx.offset, OFFSET_ORIGIN_FEE_AMOUNT))\n }\n }\n\n /// @notice Extracts the deadline from the encoded transaction.\n function deadline(bytes calldata encodedTx) internal pure returns (uint256 deadline_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n deadline_ := calldataload(add(encodedTx.offset, OFFSET_DEADLINE))\n }\n }\n\n /// @notice Extracts the nonce from the encoded transaction.\n function nonce(bytes calldata encodedTx) internal pure returns (uint256 nonce_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n nonce_ := calldataload(add(encodedTx.offset, OFFSET_NONCE))\n }\n }\n\n /// @notice Extracts the exclusivity relayer from the encoded transaction.\n function exclusivityRelayer(bytes calldata encodedTx) internal pure returns (address exclusivityRelayer_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n exclusivityRelayer_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_EXCLUSIVITY_RELAYER)))\n }\n }\n\n /// @notice Extracts the exclusivity end time from the encoded transaction.\n function exclusivityEndTime(bytes calldata encodedTx) internal pure returns (uint256 exclusivityEndTime_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n exclusivityEndTime_ := calldataload(add(encodedTx.offset, OFFSET_EXCLUSIVITY_END_TIME))\n }\n }\n\n /// @notice Extracts the Zap's native value from the encoded transaction.\n function zapNative(bytes calldata encodedTx) internal pure returns (uint256 zapNative_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n zapNative_ := calldataload(add(encodedTx.offset, OFFSET_ZAP_NATIVE))\n }\n }\n\n /// @notice Extracts the Zap's data from the encoded transaction.\n function zapData(bytes calldata encodedTx) internal pure returns (bytes calldata zapData_) {\n zapData_ = encodedTx[OFFSET_ZAP_DATA:];\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/AdminV2.sol\n\n// ════════════════════════════════════════════════ INTERFACES ═════════════════════════════════════════════════════\n\n// ═════════════════════════════════════════════ EXTERNAL IMPORTS ══════════════════════════════════════════════════\n\n/// @title AdminV2\n/// @notice Provides administrative functions and controls for managing the FastBridgeV2 contract,\n/// including access control and configuration settings.\ncontract AdminV2 is AccessControlEnumerable, IAdminV2, IAdminV2Errors {\n using SafeERC20 for IERC20;\n\n /// @notice The address reserved for the native gas token (ETH on Ethereum and most L2s, AVAX on Avalanche, etc.).\n address public constant NATIVE_GAS_TOKEN = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice The role identifier for the Quoter API's off-chain authentication.\n /// @dev Only addresses with this role can post FastBridge quotes to the API.\n bytes32 public constant QUOTER_ROLE = keccak256(\"QUOTER_ROLE\");\n\n /// @notice The role identifier for the Prover's on-chain authentication in FastBridge.\n /// @dev Only addresses with this role can provide proofs that a FastBridge request has been relayed.\n bytes32 public constant PROVER_ROLE = keccak256(\"PROVER_ROLE\");\n\n /// @notice The role identifier for the Guard's on-chain authentication in FastBridge.\n /// @dev Only addresses with this role can dispute submitted relay proofs during the dispute period.\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n\n /// @notice The role identifier for the Canceler's on-chain authentication in FastBridge.\n /// @dev Only addresses with this role can cancel a FastBridge transaction without the cancel delay.\n bytes32 public constant CANCELER_ROLE = keccak256(\"CANCELER_ROLE\");\n\n /// @notice The role identifier for the Governor's on-chain administrative authority.\n /// @dev Only addresses with this role can perform administrative tasks within the contract.\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n /// @notice The denominator for fee rates, representing 100%.\n uint256 public constant FEE_BPS = 1e6;\n /// @notice The maximum protocol fee rate: 1% of the origin amount.\n uint256 public constant FEE_RATE_MAX = 0.01e6;\n\n /// @notice The minimum cancel delay that can be set by the governor.\n uint256 public constant MIN_CANCEL_DELAY = 1 hours;\n /// @notice The default cancel delay set during contract deployment.\n uint256 public constant DEFAULT_CANCEL_DELAY = 1 days;\n\n /// @notice The protocol fee rate taken on the origin amount deposited in the origin chain.\n uint256 public protocolFeeRate;\n\n /// @notice The accumulated protocol fee amounts.\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice The delay period after which a transaction can be permissionlessly cancelled.\n uint256 public cancelDelay;\n\n /// @notice This variable is deprecated and should not be used.\n /// @dev Use ZapNative V2 requests instead.\n uint256 public immutable chainGasAmount = 0;\n\n constructor(address defaultAdmin) {\n _grantRole(DEFAULT_ADMIN_ROLE, defaultAdmin);\n _setCancelDelay(DEFAULT_CANCEL_DELAY);\n }\n\n /// @inheritdoc IAdminV2\n function setCancelDelay(uint256 newCancelDelay) external onlyRole(GOVERNOR_ROLE) {\n _setCancelDelay(newCancelDelay);\n }\n\n /// @inheritdoc IAdminV2\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n if (newFeeRate \u003e FEE_RATE_MAX) revert FeeRateAboveMax();\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n /// @inheritdoc IAdminV2\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n // Early exit if no accumulated fees.\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return;\n // Reset the accumulated fees first.\n protocolFees[token] = 0;\n emit FeesSwept(token, recipient, feeAmount);\n // Sweep the fees as the last transaction action.\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(recipient), feeAmount);\n } else {\n IERC20(token).safeTransfer(recipient, feeAmount);\n }\n }\n\n /// @notice Internal logic to set the cancel delay. Security checks are performed outside of this function.\n /// @dev This function is marked as private to prevent child contracts from calling it directly.\n function _setCancelDelay(uint256 newCancelDelay) private {\n if (newCancelDelay \u003c MIN_CANCEL_DELAY) revert CancelDelayBelowMin();\n uint256 oldCancelDelay = cancelDelay;\n cancelDelay = newCancelDelay;\n emit CancelDelayUpdated(oldCancelDelay, newCancelDelay);\n }\n}\n\n// contracts/FastBridgeV2.sol\n\n// ════════════════════════════════════════════════ INTERFACES ═════════════════════════════════════════════════════\n\n// ═════════════════════════════════════════════ INTERNAL IMPORTS ══════════════════════════════════════════════════\n\n// ═════════════════════════════════════════════ EXTERNAL IMPORTS ══════════════════════════════════════════════════\n\n/// @title FastBridgeV2\n/// @notice Core component of the SynapseRFQ protocol, enabling Relayers (Solvers) to fulfill bridge requests.\n/// Supports ERC20 and native gas tokens, along with the Zap feature for executing actions on the destination chain.\n/// Users interact with the off-chain Quoter API to obtain a current quote for a bridge transaction.\n/// They then submit the bridge request with the quote to this contract, depositing their assets in escrow.\n/// Relayers can fulfill requests by relaying them to the destination chain and must prove fulfillment to claim funds.\n/// Guards monitor proofs and can dispute discrepancies.\n/// Users can reclaim funds by cancelling their requests if it has not been fulfilled within the specified deadline.\ncontract FastBridgeV2 is AdminV2, MulticallTarget, IFastBridgeV2, IFastBridgeV2Errors {\n using BridgeTransactionV2Lib for bytes;\n using SafeERC20 for IERC20;\n\n /// @notice The duration of the dispute period for relayed transactions.\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice The minimum required time between transaction request and deadline.\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n /// @notice The maximum allowed length for zapData.\n uint256 public constant MAX_ZAP_DATA_LENGTH = 2 ** 16 - 1;\n\n /// @notice Maps transaction IDs to bridge details (status, destination chain ID, proof timestamp, and relayer).\n /// Note: this is only stored for transactions having local chain as the origin chain.\n mapping(bytes32 =\u003e BridgeTxDetails) public bridgeTxDetails;\n /// @notice Maps transaction IDs to relay details (block number, block timestamp, and relayer).\n /// Note: this is only stored for transactions having local chain as the destination chain.\n mapping(bytes32 =\u003e BridgeRelay) public bridgeRelayDetails;\n /// @notice Maps sender addresses to their unique bridge nonce.\n mapping(address =\u003e uint256) public senderNonces;\n\n /// @notice This variable is deprecated and should not be used.\n /// @dev Replaced by senderNonces.\n uint256 public immutable nonce = 0;\n /// @notice The block number at which this contract was deployed.\n uint256 public immutable deployBlock;\n\n /// @notice Initializes the FastBridgeV2 contract with the provided default admin,\n /// sets the default cancel delay, and records the deploy block number.\n constructor(address defaultAdmin) AdminV2(defaultAdmin) {\n deployBlock = block.number;\n }\n\n // ══════════════════════════════════════ EXTERNAL MUTABLE (USER FACING) ═══════════════════════════════════════════\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n bridgeV2({\n params: params,\n paramsV2: BridgeParamsV2({\n quoteRelayer: address(0),\n quoteExclusivitySeconds: 0,\n quoteId: bytes(\"\"),\n zapNative: 0,\n zapData: bytes(\"\")\n })\n });\n }\n\n /// Note: this function is deprecated and will be removed in a future version.\n /// @dev Replaced by `cancel`.\n /// @inheritdoc IFastBridge\n function refund(bytes calldata request) external {\n cancelV2(request);\n }\n\n // ══════════════════════════════════════ EXTERNAL MUTABLE (AGENT FACING) ══════════════════════════════════════════\n\n /// @inheritdoc IFastBridge\n function relay(bytes calldata request) external payable {\n // `relay` override will validate the request.\n relayV2({request: request, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes calldata request, bytes32 destTxHash) external {\n request.validateV2();\n proveV2({transactionId: keccak256(request), destTxHash: destTxHash, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridgeV2\n function claimV2(bytes calldata request) external {\n // `claim` override will validate the request.\n claim({request: request, to: address(0)});\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n // Aggregate the read operations from the same storage slot.\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n address disputedRelayer = $.proofRelayer;\n BridgeStatus status = $.status;\n uint56 proofBlockTimestamp = $.proofBlockTimestamp;\n\n // Can only dispute a RELAYER_PROVED transaction within the dispute period.\n if (status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(proofBlockTimestamp) \u003e DISPUTE_PERIOD) {\n revert DisputePeriodPassed();\n }\n\n // Update status to REQUESTED and delete the disputed proof details.\n // Note: these are storage writes.\n $.status = BridgeStatus.REQUESTED;\n $.proofRelayer = address(0);\n $.proofBlockTimestamp = 0;\n\n emit BridgeProofDisputed(transactionId, disputedRelayer);\n }\n\n // ══════════════════════════════════════════════ EXTERNAL VIEWS ═══════════════════════════════════════════════════\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n // The correct relayer can only claim a RELAYER_PROVED transaction after the dispute period.\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n if ($.status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if ($.proofRelayer != relayer) revert SenderIncorrect();\n\n return _timeSince($.proofBlockTimestamp) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n /// @dev This method is added to achieve backwards compatibility with decoding requests into V1 structs:\n /// - `zapNative` is partially reported as a zero/non-zero flag\n /// - `zapData` is ignored\n /// In order to process all kinds of requests use getBridgeTransactionV2 instead.\n function getBridgeTransaction(bytes calldata request) external view returns (BridgeTransaction memory) {\n // Try decoding into V2 struct first. This will revert if V1 struct is passed.\n try this.getBridgeTransactionV2(request) returns (BridgeTransactionV2 memory txV2) {\n // Note: we entirely ignore the zapData field, as it was not present in V1.\n return BridgeTransaction({\n originChainId: txV2.originChainId,\n destChainId: txV2.destChainId,\n originSender: txV2.originSender,\n destRecipient: txV2.destRecipient,\n originToken: txV2.originToken,\n destToken: txV2.destToken,\n originAmount: txV2.originAmount,\n destAmount: txV2.destAmount,\n originFeeAmount: txV2.originFeeAmount,\n sendChainGas: txV2.zapNative != 0,\n deadline: txV2.deadline,\n nonce: txV2.nonce\n });\n } catch {\n // Fallback to V1 struct.\n return abi.decode(request, (BridgeTransaction));\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function getBridgeTransactionV2(bytes calldata request) external pure returns (BridgeTransactionV2 memory) {\n request.validateV2();\n return BridgeTransactionV2Lib.decodeV2(request);\n }\n\n // ═══════════════════════════════════════ PUBLIC MUTABLE (USER FACING) ════════════════════════════════════════════\n\n /// @inheritdoc IFastBridgeV2\n function bridgeV2(BridgeParams memory params, BridgeParamsV2 memory paramsV2) public payable {\n // If relayer exclusivity is not intended for this bridge, set exclusivityEndTime to static zero.\n // Otherwise, set exclusivity to expire at the current block ts offset by quoteExclusivitySeconds.\n int256 exclusivityEndTime = 0;\n if (paramsV2.quoteRelayer != address(0)) {\n exclusivityEndTime = int256(block.timestamp) + paramsV2.quoteExclusivitySeconds;\n }\n _validateBridgeParams(params, paramsV2, exclusivityEndTime);\n\n // Transfer tokens to bridge contract. We use the actual transferred amount in case of transfer fees.\n uint256 originAmount = _takeBridgedUserAsset(params.originToken, params.originAmount);\n\n // Track the amount of origin token owed to protocol.\n uint256 originFeeAmount = 0;\n if (protocolFeeRate \u003e 0) {\n originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n // The Relayer filling this request will be paid the originAmount after fees.\n // Note: the protocol fees will be accumulated only when the Relayer claims the origin collateral.\n originAmount -= originFeeAmount;\n }\n\n // Hash the bridge request and set the initial status to REQUESTED.\n bytes memory request = BridgeTransactionV2Lib.encodeV2(\n BridgeTransactionV2({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n deadline: params.deadline,\n // Increment the sender's nonce on every bridge.\n nonce: senderNonces[params.sender]++,\n exclusivityRelayer: paramsV2.quoteRelayer,\n // We checked exclusivityEndTime to be in range [0 .. params.deadline] above, so can safely cast.\n exclusivityEndTime: uint256(exclusivityEndTime),\n zapNative: paramsV2.zapNative,\n zapData: paramsV2.zapData\n })\n );\n bytes32 transactionId = keccak256(request);\n // Note: the tx status will be updated throughout the tx lifecycle, while destChainId is set once here.\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n bridgeTxDetails[transactionId].destChainId = params.dstChainId;\n\n emit BridgeRequested({\n transactionId: transactionId,\n sender: params.sender,\n request: request,\n destChainId: params.dstChainId,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n sendChainGas: paramsV2.zapNative != 0\n });\n emit BridgeQuoteDetails(transactionId, paramsV2.quoteId);\n }\n\n /// @inheritdoc IFastBridgeV2\n function cancelV2(bytes calldata request) public {\n // Decode the request and check that it could be cancelled.\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n\n // Can only cancel a REQUESTED transaction after its deadline expires.\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n if ($.status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n\n // Permissionless cancel is only allowed after `cancelDelay` on top of the deadline.\n uint256 deadline = request.deadline();\n if (!hasRole(CANCELER_ROLE, msg.sender)) deadline += cancelDelay;\n if (block.timestamp \u003c= deadline) revert DeadlineNotExceeded();\n\n // Update status to REFUNDED.\n // Note: this is a storage write.\n $.status = BridgeStatus.REFUNDED;\n\n // Return the full amount (collateral + protocol fees) to the original sender.\n // The protocol fees are only accumulated when the transaction is claimed, so we don't need to update them here.\n address to = request.originSender();\n address token = request.originToken();\n uint256 amount = request.originAmount() + request.originFeeAmount();\n\n // Emit the event before any external calls.\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n\n // Return the funds to the original sender as last transaction action.\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(to), amount);\n } else {\n IERC20(token).safeTransfer(to, amount);\n }\n }\n\n // ═══════════════════════════════════════ PUBLIC MUTABLE (AGENT FACING) ═══════════════════════════════════════════\n\n /// @inheritdoc IFastBridgeV2\n function relayV2(bytes calldata request, address relayer) public payable {\n // Decode the request and check that it could be relayed.\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n _validateRelayParams(request, transactionId, relayer);\n\n // Mark the bridge request as relayed by saving the relayer and the block details.\n bridgeRelayDetails[transactionId].blockNumber = uint48(block.number);\n bridgeRelayDetails[transactionId].blockTimestamp = uint48(block.timestamp);\n bridgeRelayDetails[transactionId].relayer = relayer;\n\n // Transfer tokens to recipient on destination chain and trigger Zap if requested.\n address to = request.destRecipient();\n address token = request.destToken();\n uint256 amount = request.destAmount();\n uint256 zapNative = request.zapNative();\n\n // Emit the event before any external calls.\n emit BridgeRelayed({\n transactionId: transactionId,\n relayer: relayer,\n to: to,\n originChainId: request.originChainId(),\n originToken: request.originToken(),\n destToken: token,\n originAmount: request.originAmount(),\n destAmount: amount,\n chainGasAmount: zapNative\n });\n\n // All state changes have been done at this point, can proceed to the external calls.\n // This follows the checks-effects-interactions pattern to mitigate potential reentrancy attacks.\n if (token == NATIVE_GAS_TOKEN) {\n // For the native gas token, additional zapNative is not allowed.\n if (zapNative != 0) revert ZapNativeNotSupported();\n // Check that the correct msg.value was sent.\n if (msg.value != amount) revert MsgValueIncorrect();\n // Don't do a native transfer yet: we will handle it alongside the Zap below.\n } else {\n // For ERC20s, we check that the correct msg.value was sent.\n if (msg.value != zapNative) revert MsgValueIncorrect();\n // We need to transfer the tokens from the Relayer to the recipient first before performing an\n // optional post-transfer Zap.\n IERC20(token).safeTransferFrom(msg.sender, to, amount);\n }\n // At this point we have done:\n // - Transferred the requested amount of ERC20 tokens to the recipient.\n // At this point we have confirmed:\n // - For ERC20s: msg.value matches the requested zapNative amount.\n // - For the native gas token: msg.value matches the requested destAmount.\n // Remaining optional things to do:\n // - Forward the full msg.value to the recipient (if non-zero).\n // - Trigger a Zap (if zapData is present).\n bytes calldata zapData = request.zapData();\n if (zapData.length != 0) {\n // Zap Data is present: Zap has been requested by the recipient. Trigger it forwarding the full msg.value.\n _triggerZapWithChecks({recipient: to, token: token, amount: amount, zapData: zapData});\n // Note: if token has a fee on transfers, the recipient will have received less than `amount`.\n // This is a very niche edge case and should be handled by the recipient contract.\n } else if (msg.value != 0) {\n // Zap Data is missing, but msg.value was sent. This could happen in two different cases:\n // - Relay with the native gas token is happening.\n // - Relay with ERC20 is happening, with a `zapNative \u003e 0` request.\n // In both cases, we need to transfer the full msg.value to the recipient.\n Address.sendValue(payable(to), msg.value);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function proveV2(bytes32 transactionId, bytes32 destTxHash, address relayer) public onlyRole(PROVER_ROLE) {\n // Can only prove a REQUESTED transaction.\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n if ($.status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n\n // Update status to RELAYER_PROVED and store the proof details.\n // Note: these are storage writes.\n $.status = BridgeStatus.RELAYER_PROVED;\n $.proofBlockTimestamp = uint56(block.timestamp);\n $.proofRelayer = relayer;\n\n emit BridgeProofProvided(transactionId, relayer, destTxHash);\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes calldata request, address to) public {\n // Decode the request and check that it could be claimed.\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n\n // Aggregate the read operations from the same storage slot.\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n address proofRelayer = $.proofRelayer;\n BridgeStatus status = $.status;\n uint56 proofBlockTimestamp = $.proofBlockTimestamp;\n\n // Can only claim a RELAYER_PROVED transaction after the dispute period.\n if (status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(proofBlockTimestamp) \u003c= DISPUTE_PERIOD) revert DisputePeriodNotPassed();\n if (to == address(0)) {\n // Anyone could claim the funds to the proven relayer on their behalf.\n to = proofRelayer;\n } else if (proofRelayer != msg.sender) {\n // Only the proven relayer could specify an address to claim the funds to.\n revert SenderIncorrect();\n }\n\n // Update status to RELAYER_CLAIMED and transfer the origin collateral to the specified claim address.\n // Note: this is a storage write.\n $.status = BridgeStatus.RELAYER_CLAIMED;\n\n // Accumulate protocol fees if origin fee amount exists.\n address token = request.originToken();\n uint256 amount = request.originAmount();\n uint256 originFeeAmount = request.originFeeAmount();\n if (originFeeAmount \u003e 0) protocolFees[token] += originFeeAmount;\n\n // Emit the event before any external calls.\n emit BridgeDepositClaimed(transactionId, proofRelayer, to, token, amount);\n\n // Complete the relayer claim as the last transaction action.\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(to), amount);\n } else {\n IERC20(token).safeTransfer(to, amount);\n }\n }\n\n // ═══════════════════════════════════════════════ PUBLIC VIEWS ════════════════════════════════════════════════════\n\n /// @inheritdoc IFastBridgeV2\n function bridgeStatuses(bytes32 transactionId) public view returns (BridgeStatus status) {\n return bridgeTxDetails[transactionId].status;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeProofs(bytes32 transactionId) public view returns (uint96 timestamp, address relayer) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n timestamp = $.proofBlockTimestamp;\n relayer = $.proofRelayer;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeRelays(bytes32 transactionId) public view returns (bool) {\n // This transaction has been relayed if the relayer address is recorded.\n return bridgeRelayDetails[transactionId].relayer != address(0);\n }\n\n // ═════════════════════════════════════════════ INTERNAL METHODS ══════════════════════════════════════════════════\n\n /// @notice Takes the bridged asset from the user into FastBridgeV2 custody. The asset will later be\n /// claimed by the relayer who completed the relay on the destination chain, or returned to the user\n /// via the cancel function if no relay is completed.\n function _takeBridgedUserAsset(address token, uint256 amount) internal returns (uint256 amountTaken) {\n if (token == NATIVE_GAS_TOKEN) {\n // For the native gas token, we just need to check that the supplied msg.value is correct.\n // Supplied `msg.value` is already in FastBridgeV2 custody.\n if (amount != msg.value) revert MsgValueIncorrect();\n amountTaken = msg.value;\n } else {\n // For ERC20s, token is explicitly transferred from the user to FastBridgeV2.\n // We don't allow non-zero `msg.value` to avoid extra funds from being stuck in FastBridgeV2.\n if (msg.value != 0) revert MsgValueIncorrect();\n // Throw an explicit error if the provided token address is not a contract.\n if (token.code.length == 0) revert TokenNotContract();\n\n // Use the balance difference as the amount taken in case of fee on transfer tokens.\n amountTaken = IERC20(token).balanceOf(address(this));\n IERC20(token).safeTransferFrom(msg.sender, address(this), amount);\n amountTaken = IERC20(token).balanceOf(address(this)) - amountTaken;\n }\n }\n\n /// @notice Calls the recipient's hook function with the specified zapData and validates\n /// the returned value.\n function _triggerZapWithChecks(address recipient, address token, uint256 amount, bytes calldata zapData) internal {\n // Call the recipient's hook function with the specified zapData, bubbling any revert messages.\n bytes memory returnData = Address.functionCallWithValue({\n target: recipient,\n data: abi.encodeCall(IZapRecipient.zap, (token, amount, zapData)),\n // Note: see `relay()` for reasoning behind passing msg.value.\n value: msg.value\n });\n\n // Explicit revert if no return data at all.\n if (returnData.length == 0) revert RecipientNoReturnValue();\n // Check that exactly a single return value was returned.\n if (returnData.length != 32) revert RecipientIncorrectReturnValue();\n // Return value should be abi-encoded hook function selector.\n if (bytes32(returnData) != bytes32(IZapRecipient.zap.selector)) {\n revert RecipientIncorrectReturnValue();\n }\n }\n\n /// @notice Calculates the time elapsed since a proof was submitted.\n /// @dev The proof.timestamp stores block timestamps as uint56 for gas optimization.\n /// _timeSince(proof) handles timestamp rollover when block.timestamp \u003e type(uint56).max but\n /// proof.timestamp \u003c type(uint56).max via an unchecked statement.\n /// @param proofBlockTimestamp The block timestamp when the proof was submitted.\n /// @return delta The time elapsed since proof submission.\n function _timeSince(uint56 proofBlockTimestamp) internal view returns (uint256 delta) {\n unchecked {\n delta = uint56(block.timestamp) - proofBlockTimestamp;\n }\n }\n\n /// @notice Validates all parameters required for a bridge transaction.\n /// @dev This function's complexity cannot be reduced due to the number of required checks,\n /// so we disable the code-complexity rule.\n // solhint-disable-next-line code-complexity\n function _validateBridgeParams(\n BridgeParams memory params,\n BridgeParamsV2 memory paramsV2,\n int256 exclusivityEndTime\n )\n internal\n view\n {\n // Check V1 (legacy) params.\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.sender == address(0) || params.to == address(0)) revert ZeroAddress();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n\n // Check V2 params.\n if (paramsV2.zapData.length \u003e MAX_ZAP_DATA_LENGTH) revert ZapDataLengthAboveMax();\n if (paramsV2.zapNative != 0 \u0026\u0026 params.destToken == NATIVE_GAS_TOKEN) {\n revert ZapNativeNotSupported();\n }\n\n // exclusivityEndTime must be in range [0 .. params.deadline].\n if (exclusivityEndTime \u003c 0 || exclusivityEndTime \u003e int256(params.deadline)) {\n revert ExclusivityParamsIncorrect();\n }\n }\n\n /// @notice Validates all parameters required for a relay transaction.\n function _validateRelayParams(bytes calldata request, bytes32 transactionId, address relayer) internal view {\n if (relayer == address(0)) revert ZeroAddress();\n // Check that the transaction has not been relayed yet and is for the current chain.\n if (bridgeRelays(transactionId)) revert TransactionRelayed();\n if (request.destChainId() != block.chainid) revert ChainIncorrect();\n // Check that the deadline for relay to happen has not passed yet.\n if (block.timestamp \u003e request.deadline()) revert DeadlineExceeded();\n // Check the exclusivity period, if it was specified and is still ongoing.\n address exclRelayer = request.exclusivityRelayer();\n if (exclRelayer != address(0) \u0026\u0026 exclRelayer != relayer \u0026\u0026 block.timestamp \u003c= request.exclusivityEndTime()) {\n revert ExclusivityPeriodNotPassed();\n }\n }\n}\n","language":"Solidity","languageVersion":"0.8.24","compilerVersion":"0.8.24","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"","srcMapRuntime":"","abiDefinition":[{"inputs":[],"name":"AccessControlBadConfirmation","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"bytes32","name":"neededRole","type":"bytes32"}],"name":"AccessControlUnauthorizedAccount","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"previousAdminRole","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"newAdminRole","type":"bytes32"}],"name":"RoleAdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleRevoked","type":"event"},{"inputs":[],"name":"DEFAULT_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleAdmin","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"uint256","name":"index","type":"uint256"}],"name":"getRoleMember","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleMemberCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"grantRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"hasRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"callerConfirmation","type":"address"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"revokeRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"}],"userDoc":{"kind":"user","methods":{},"version":1},"developerDoc":{"details":"Extension of {AccessControl} that allows enumerating the members of each role.","errors":{"AccessControlBadConfirmation()":[{"details":"The caller of a function is not the expected one. NOTE: Don't confuse with {AccessControlUnauthorizedAccount}."}],"AccessControlUnauthorizedAccount(address,bytes32)":[{"details":"The `account` is missing a role."}]},"events":{"RoleAdminChanged(bytes32,bytes32,bytes32)":{"details":"Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole` `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite {RoleAdminChanged} not being emitted signaling this."},"RoleGranted(bytes32,address,address)":{"details":"Emitted when `account` is granted `role`. `sender` is the account that originated the contract call, an admin role bearer except when using {AccessControl-_setupRole}."},"RoleRevoked(bytes32,address,address)":{"details":"Emitted when `account` is revoked `role`. `sender` is the account that originated the contract call: - if using `revokeRole`, it is the admin role bearer - if using `renounceRole`, it is the role bearer (i.e. `account`)"}},"kind":"dev","methods":{"getRoleAdmin(bytes32)":{"details":"Returns the admin role that controls `role`. See {grantRole} and {revokeRole}. To change a role's admin, use {_setRoleAdmin}."},"getRoleMember(bytes32,uint256)":{"details":"Returns one of the accounts that have `role`. `index` must be a value between 0 and {getRoleMemberCount}, non-inclusive. Role bearers are not sorted in any particular way, and their ordering may change at any point. WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure you perform all queries on the same block. See the following https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post] for more information."},"getRoleMemberCount(bytes32)":{"details":"Returns the number of accounts that have `role`. Can be used together with {getRoleMember} to enumerate all bearers of a role."},"grantRole(bytes32,address)":{"details":"Grants `role` to `account`. If `account` had not been already granted `role`, emits a {RoleGranted} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleGranted} event."},"hasRole(bytes32,address)":{"details":"Returns `true` if `account` has been granted `role`."},"renounceRole(bytes32,address)":{"details":"Revokes `role` from the calling account. Roles are often managed via {grantRole} and {revokeRole}: this function's purpose is to provide a mechanism for accounts to lose their privileges if they are compromised (such as when a trusted device is misplaced). If the calling account had been revoked `role`, emits a {RoleRevoked} event. Requirements: - the caller must be `callerConfirmation`. May emit a {RoleRevoked} event."},"revokeRole(bytes32,address)":{"details":"Revokes `role` from `account`. If `account` had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleRevoked} event."},"supportsInterface(bytes4)":{"details":"See {IERC165-supportsInterface}."}},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[],\"name\":\"AccessControlBadConfirmation\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"neededRole\",\"type\":\"bytes32\"}],\"name\":\"AccessControlUnauthorizedAccount\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"previousAdminRole\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"newAdminRole\",\"type\":\"bytes32\"}],\"name\":\"RoleAdminChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleGranted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleRevoked\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"DEFAULT_ADMIN_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"}],\"name\":\"getRoleAdmin\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"index\",\"type\":\"uint256\"}],\"name\":\"getRoleMember\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"}],\"name\":\"getRoleMemberCount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"grantRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"hasRole\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"callerConfirmation\",\"type\":\"address\"}],\"name\":\"renounceRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"revokeRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes4\",\"name\":\"interfaceId\",\"type\":\"bytes4\"}],\"name\":\"supportsInterface\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"}],\"devdoc\":{\"details\":\"Extension of {AccessControl} that allows enumerating the members of each role.\",\"errors\":{\"AccessControlBadConfirmation()\":[{\"details\":\"The caller of a function is not the expected one. NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\"}],\"AccessControlUnauthorizedAccount(address,bytes32)\":[{\"details\":\"The `account` is missing a role.\"}]},\"events\":{\"RoleAdminChanged(bytes32,bytes32,bytes32)\":{\"details\":\"Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole` `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite {RoleAdminChanged} not being emitted signaling this.\"},\"RoleGranted(bytes32,address,address)\":{\"details\":\"Emitted when `account` is granted `role`. `sender` is the account that originated the contract call, an admin role bearer except when using {AccessControl-_setupRole}.\"},\"RoleRevoked(bytes32,address,address)\":{\"details\":\"Emitted when `account` is revoked `role`. `sender` is the account that originated the contract call: - if using `revokeRole`, it is the admin role bearer - if using `renounceRole`, it is the role bearer (i.e. `account`)\"}},\"kind\":\"dev\",\"methods\":{\"getRoleAdmin(bytes32)\":{\"details\":\"Returns the admin role that controls `role`. See {grantRole} and {revokeRole}. To change a role's admin, use {_setRoleAdmin}.\"},\"getRoleMember(bytes32,uint256)\":{\"details\":\"Returns one of the accounts that have `role`. `index` must be a value between 0 and {getRoleMemberCount}, non-inclusive. Role bearers are not sorted in any particular way, and their ordering may change at any point. WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure you perform all queries on the same block. See the following https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post] for more information.\"},\"getRoleMemberCount(bytes32)\":{\"details\":\"Returns the number of accounts that have `role`. Can be used together with {getRoleMember} to enumerate all bearers of a role.\"},\"grantRole(bytes32,address)\":{\"details\":\"Grants `role` to `account`. If `account` had not been already granted `role`, emits a {RoleGranted} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleGranted} event.\"},\"hasRole(bytes32,address)\":{\"details\":\"Returns `true` if `account` has been granted `role`.\"},\"renounceRole(bytes32,address)\":{\"details\":\"Revokes `role` from the calling account. Roles are often managed via {grantRole} and {revokeRole}: this function's purpose is to provide a mechanism for accounts to lose their privileges if they are compromised (such as when a trusted device is misplaced). If the calling account had been revoked `role`, emits a {RoleRevoked} event. Requirements: - the caller must be `callerConfirmation`. May emit a {RoleRevoked} event.\"},\"revokeRole(bytes32,address)\":{\"details\":\"Revokes `role` from `account`. If `account` had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleRevoked} event.\"},\"supportsInterface(bytes4)\":{\"details\":\"See {IERC165-supportsInterface}.\"}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeV2.sol\":\"AccessControlEnumerable\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeV2.sol\":{\"keccak256\":\"0xaab2ee7357681726f0faf799a48ddfbf45fb4da93b69abf61c33dde92b29b74d\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://673391bff9569efc0f9bd99e0e6fece0bc8e8af1f052bb071b407b267a17b3b5\",\"dweb:/ipfs/QmdQQZ6DxpJYhfpinwU5WjLugr2f6qP8h68b5GerhSMQ4j\"]}},\"version\":1}"},"hashes":{"DEFAULT_ADMIN_ROLE()":"a217fddf","getRoleAdmin(bytes32)":"248a9ca3","getRoleMember(bytes32,uint256)":"9010d07c","getRoleMemberCount(bytes32)":"ca15c873","grantRole(bytes32,address)":"2f2ff15d","hasRole(bytes32,address)":"91d14854","renounceRole(bytes32,address)":"36568abe","revokeRole(bytes32,address)":"d547741f","supportsInterface(bytes4)":"01ffc9a7"}},"solidity/FastBridgeV2.sol:Address":{"code":"0x60566037600b82828239805160001a607314602a57634e487b7160e01b600052600060045260246000fd5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600080fdfea26469706673582212209a0af1109cd6979a77a02bde578408e1ed84d2bdf8d75fee43ff2aec21f2c23564736f6c63430008180033","runtime-code":"0x73000000000000000000000000000000000000000030146080604052600080fdfea26469706673582212209a0af1109cd6979a77a02bde578408e1ed84d2bdf8d75fee43ff2aec21f2c23564736f6c63430008180033","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.24 ^0.8.20 ^0.8.4;\n\n// contracts/interfaces/IAdminV2.sol\n\ninterface IAdminV2 {\n event CancelDelayUpdated(uint256 oldCancelDelay, uint256 newCancelDelay);\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n /// @notice Allows the governor to set the cancel delay. The cancel delay is the time period after the transaction\n /// deadline during which a transaction can be permissionlessly cancelled if it hasn't been proven by any Relayer.\n function setCancelDelay(uint256 newCancelDelay) external;\n\n /// @notice Allows the governor to set the protocol fee rate. The protocol fee is taken from the origin\n /// amount and is only applied to completed and claimed transactions.\n /// @dev The protocol fee is abstracted away from the relayers; they always operate using the amounts after fees.\n /// The origin amount they see in the emitted log is what they get credited with.\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n /// @notice Allows the governor to withdraw the accumulated protocol fees from the contract.\n function sweepProtocolFees(address token, address recipient) external;\n}\n\n// contracts/interfaces/IAdminV2Errors.sol\n\ninterface IAdminV2Errors {\n error CancelDelayBelowMin();\n error FeeRateAboveMax();\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IFastBridgeV2Errors.sol\n\ninterface IFastBridgeV2Errors {\n error AmountIncorrect();\n error ChainIncorrect();\n error ExclusivityParamsIncorrect();\n error MsgValueIncorrect();\n error SenderIncorrect();\n error StatusIncorrect();\n error TokenNotContract();\n error ZapDataLengthAboveMax();\n error ZapNativeNotSupported();\n error ZeroAddress();\n\n error RecipientIncorrectReturnValue();\n error RecipientNoReturnValue();\n\n error DeadlineExceeded();\n error DeadlineNotExceeded();\n error DeadlineTooShort();\n error DisputePeriodNotPassed();\n error DisputePeriodPassed();\n error ExclusivityPeriodNotPassed();\n\n error TransactionRelayed();\n}\n\n// contracts/interfaces/IMulticallTarget.sol\n\n/// @notice Interface for a contract that supports multiple calls from the same caller. Inspired by MulticallV3:\n/// https://github.com/mds1/multicall/blob/master/src/Multicall3.sol\ninterface IMulticallTarget {\n struct Result {\n bool success;\n bytes returnData;\n }\n\n /// @notice Executes multiple calls to this contract in a single transaction while preserving msg.sender.\n /// Return data from the calls is discarded.\n /// @dev This method is non-payable, so only calls with msg.value of 0 can be batched.\n /// If ignoreReverts is set to true, reverted calls will be skipped.\n /// Otherwise, the entire batch will revert with the original revert reason.\n /// @param data List of ABI-encoded calldata for the calls to execute\n /// @param ignoreReverts Whether to skip calls that revert\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external;\n\n /// @notice Executes multiple calls to this contract in a single transaction while preserving msg.sender.\n /// Return data from each call is preserved.\n /// @dev This method is non-payable, so only calls with msg.value of 0 can be batched.\n /// If ignoreReverts is set to true, reverted calls will be skipped.\n /// Otherwise, the entire batch will revert with the original revert reason.\n /// @param data List of ABI-encoded calldata for the calls to execute\n /// @param ignoreReverts Whether to skip calls that revert\n /// @return results List of results from the calls, each containing (success, returnData)\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results);\n}\n\n// contracts/interfaces/IZapRecipient.sol\n\n/// @notice Interface for contracts that can perform Zap operations. Such contracts could be used as Recipients\n/// in a FastBridge transaction that includes a Zap operation. The Zap Data should include instructions on how\n/// exactly the Zap operation should be executed, which would typically include the target address and calldata\n/// to use. The exact implementation of the Zap Data encoding is up to the Recipient contract.\ninterface IZapRecipient {\n /// @notice Performs a Zap operation with the given token and amount according to the provided Zap data.\n /// @param token The address of the token being used for the Zap operation.\n /// @param amount The amount of tokens to be used.\n /// @param zapData The encoded data specifying how the Zap operation should be executed.\n /// @return The function selector to indicate successful execution.\n function zap(address token, uint256 amount, bytes memory zapData) external payable returns (bytes4);\n}\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// contracts/interfaces/IFastBridgeV2.sol\n\ninterface IFastBridgeV2 is IFastBridge {\n enum BridgeStatus {\n NULL, // Doesn't exist yet.\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n struct BridgeTxDetails {\n BridgeStatus status;\n uint32 destChainId;\n uint56 proofBlockTimestamp;\n address proofRelayer;\n }\n\n struct BridgeRelay {\n uint48 blockNumber;\n uint48 blockTimestamp;\n address relayer;\n }\n\n /// @notice New params introduced in the FastBridgeV2.\n /// We are passing fields from the older BridgeParams struct outside of this struct for backwards compatibility.\n /// Note: quoteRelayer and quoteExclusivitySeconds are either both zero (indicating no exclusivity)\n /// or both non-zero (indicating exclusivity for the given period).\n /// Note: zapNative \u003e 0 can NOT be used with destToken = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE (native token)\n /// @param quoteRelayer Relayer that provided the quote for the transaction\n /// @param quoteExclusivitySeconds Period of time the quote relayer is guaranteed exclusivity after user's deposit\n /// @param quoteId Unique quote identifier used for tracking the quote\n /// @param zapNative ETH value to send to the recipient (if any)\n /// @param zapData Parameters for the Zap to the destination recipient (if any)\n struct BridgeParamsV2 {\n address quoteRelayer;\n int256 quoteExclusivitySeconds;\n bytes quoteId;\n uint256 zapNative;\n bytes zapData;\n }\n\n /// @notice Updated bridge transaction struct to include parameters introduced in FastBridgeV2.\n /// Note: only `exclusivityRelayer` can fill such a transaction until `exclusivityEndTime`.\n struct BridgeTransactionV2 {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n // Note: sendChainGas flag from V1 is deprecated\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n address exclusivityRelayer;\n uint256 exclusivityEndTime;\n uint256 zapNative; // ETH value to send to the recipient (if any)\n bytes zapData; // data to pass for the Zap action (if any)\n }\n\n event BridgeQuoteDetails(bytes32 indexed transactionId, bytes quoteId);\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability\n /// to provide temporary exclusivity fill rights for the quote relayer.\n /// @param params The parameters required to bridge\n /// @param paramsV2 The parameters for exclusivity fill rights (optional, can be left empty)\n function bridgeV2(BridgeParams memory params, BridgeParamsV2 memory paramsV2) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function relayV2(bytes memory request, address relayer) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param transactionId The transaction id associated with the encoded bridge transaction to prove\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function proveV2(bytes32 transactionId, bytes32 destTxHash, address relayer) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital.\n /// @notice Can only send funds to the relayer address on the proof.\n /// @param request The encoded bridge transaction to claim on origin chain\n function claimV2(bytes memory request) external;\n\n /// @notice Cancels an outstanding bridge transaction in case optimistic bridging failed and returns the full amount\n /// to the original sender.\n /// @param request The encoded bridge transaction to refund\n function cancelV2(bytes memory request) external;\n\n /// @notice Checks if a transaction has been relayed\n /// @param transactionId The ID of the transaction to check\n /// @return True if the transaction has been relayed, false otherwise\n function bridgeRelays(bytes32 transactionId) external view returns (bool);\n\n /// @notice Returns the status of a bridge transaction\n /// @param transactionId The ID of the bridge transaction\n /// @return BridgeStatus Status of the bridge transaction\n function bridgeStatuses(bytes32 transactionId) external view returns (BridgeStatus);\n\n /// @notice Returns the timestamp and relayer of a bridge proof\n /// @param transactionId The ID of the bridge transaction\n /// @return timestamp The timestamp of the bridge proof\n /// @return relayer The relayer address of the bridge proof\n function bridgeProofs(bytes32 transactionId) external view returns (uint96 timestamp, address relayer);\n\n /// @notice Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\n /// @param request The bridge request to decode\n function getBridgeTransactionV2(bytes memory request) external view returns (BridgeTransactionV2 memory);\n}\n\n// contracts/utils/MulticallTarget.sol\n\n// solhint-disable avoid-low-level-calls\n/// @notice Abstract contract template that supports batched calls while preserving msg.sender.\n/// Only calls with msg.value of 0 can be batched.\nabstract contract MulticallTarget is IMulticallTarget {\n error MulticallTarget__UndeterminedRevert();\n\n /// @inheritdoc IMulticallTarget\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external {\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\n if (!success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(result);\n }\n }\n }\n\n /// @inheritdoc IMulticallTarget\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results)\n {\n results = new Result[](data.length);\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (results[i].success, results[i].returnData) = address(this).delegatecall(data[i]);\n if (!results[i].success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(results[i].returnData);\n }\n }\n }\n\n /// @dev Bubbles the revert message from the underlying call.\n /// Note: preserves the same custom error or revert string, if one was used.\n /// Source: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v5.0.2/contracts/utils/Address.sol#L143-L158\n function _bubbleRevert(bytes memory returnData) internal pure {\n // Look for revert reason and bubble it up if present\n if (returnData.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n // solhint-disable-next-line no-inline-assembly\n assembly {\n let returndata_size := mload(returnData)\n revert(add(32, returnData), returndata_size)\n }\n } else {\n revert MulticallTarget__UndeterminedRevert();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// contracts/libs/BridgeTransactionV2.sol\n\n// solhint-disable no-inline-assembly\nlibrary BridgeTransactionV2Lib {\n uint16 internal constant VERSION = 2;\n\n // Offsets of the fields in the packed BridgeTransactionV2 struct\n // uint16 version [000 .. 002)\n // uint32 originChainId [002 .. 006)\n // uint32 destChainId [006 .. 010)\n // address originSender [010 .. 030)\n // address destRecipient [030 .. 050)\n // address originToken [050 .. 070)\n // address destToken [070 .. 090)\n // uint256 originAmount [090 .. 122)\n // uint256 destAmount [122 .. 154)\n // uint256 originFeeAmount [154 .. 186)\n // uint256 deadline [186 .. 218)\n // uint256 nonce [218 .. 250)\n // address exclusivityRelayer [250 .. 270)\n // uint256 exclusivityEndTime [270 .. 302)\n // uint256 zapNative [302 .. 334)\n // bytes zapData [334 .. ***)\n\n // forgefmt: disable-start\n uint256 private constant OFFSET_ORIGIN_CHAIN_ID = 2;\n uint256 private constant OFFSET_DEST_CHAIN_ID = 6;\n uint256 private constant OFFSET_ORIGIN_SENDER = 10;\n uint256 private constant OFFSET_DEST_RECIPIENT = 30;\n uint256 private constant OFFSET_ORIGIN_TOKEN = 50;\n uint256 private constant OFFSET_DEST_TOKEN = 70;\n uint256 private constant OFFSET_ORIGIN_AMOUNT = 90;\n uint256 private constant OFFSET_DEST_AMOUNT = 122;\n uint256 private constant OFFSET_ORIGIN_FEE_AMOUNT = 154;\n uint256 private constant OFFSET_DEADLINE = 186;\n uint256 private constant OFFSET_NONCE = 218;\n uint256 private constant OFFSET_EXCLUSIVITY_RELAYER = 250;\n uint256 private constant OFFSET_EXCLUSIVITY_END_TIME = 270;\n uint256 private constant OFFSET_ZAP_NATIVE = 302;\n uint256 private constant OFFSET_ZAP_DATA = 334;\n // forgefmt: disable-end\n\n error BridgeTransactionV2__InvalidEncodedTx();\n error BridgeTransactionV2__UnsupportedVersion(uint16 version);\n\n /// @notice Validates that the encoded transaction is a tightly packed encoded payload for BridgeTransactionV2.\n /// @dev Checks the minimum length and the version, use this function before decoding any of the fields.\n function validateV2(bytes calldata encodedTx) internal pure {\n // Check the minimum length: must at least include all static fields.\n if (encodedTx.length \u003c OFFSET_ZAP_DATA) revert BridgeTransactionV2__InvalidEncodedTx();\n // Once we validated the length, we can be sure that the version field is present.\n uint16 version_ = version(encodedTx);\n if (version_ != VERSION) revert BridgeTransactionV2__UnsupportedVersion(version_);\n }\n\n /// @notice Encodes the BridgeTransactionV2 struct by tightly packing the fields.\n /// @dev `abi.decode` will not work as a result of the tightly packed fields. Use `decodeV2` to decode instead.\n function encodeV2(IFastBridgeV2.BridgeTransactionV2 memory bridgeTx) internal pure returns (bytes memory) {\n // We split the encoding into two parts to avoid stack-too-deep error\n bytes memory firstPart = abi.encodePacked(\n VERSION,\n bridgeTx.originChainId,\n bridgeTx.destChainId,\n bridgeTx.originSender,\n bridgeTx.destRecipient,\n bridgeTx.originToken,\n bridgeTx.destToken,\n bridgeTx.originAmount\n );\n return abi.encodePacked(\n firstPart,\n bridgeTx.destAmount,\n bridgeTx.originFeeAmount,\n // Note: we skip the deprecated `sendChainGas` flag, which was present in BridgeTransaction V1\n bridgeTx.deadline,\n bridgeTx.nonce,\n // New V2 fields: exclusivity\n bridgeTx.exclusivityRelayer,\n bridgeTx.exclusivityEndTime,\n // New V2 fields: Zap\n bridgeTx.zapNative,\n bridgeTx.zapData\n );\n }\n\n /// @notice Decodes the BridgeTransactionV2 struct from the encoded transaction.\n /// @dev Encoded BridgeTransactionV2 struct must be tightly packed.\n /// Use `validateV2` before decoding to ensure the encoded transaction is valid.\n function decodeV2(bytes calldata encodedTx)\n internal\n pure\n returns (IFastBridgeV2.BridgeTransactionV2 memory bridgeTx)\n {\n bridgeTx.originChainId = originChainId(encodedTx);\n bridgeTx.destChainId = destChainId(encodedTx);\n bridgeTx.originSender = originSender(encodedTx);\n bridgeTx.destRecipient = destRecipient(encodedTx);\n bridgeTx.originToken = originToken(encodedTx);\n bridgeTx.destToken = destToken(encodedTx);\n bridgeTx.originAmount = originAmount(encodedTx);\n bridgeTx.destAmount = destAmount(encodedTx);\n bridgeTx.originFeeAmount = originFeeAmount(encodedTx);\n bridgeTx.deadline = deadline(encodedTx);\n bridgeTx.nonce = nonce(encodedTx);\n bridgeTx.exclusivityRelayer = exclusivityRelayer(encodedTx);\n bridgeTx.exclusivityEndTime = exclusivityEndTime(encodedTx);\n bridgeTx.zapNative = zapNative(encodedTx);\n bridgeTx.zapData = zapData(encodedTx);\n }\n\n /// @notice Extracts the version from the encoded transaction.\n function version(bytes calldata encodedTx) internal pure returns (uint16 version_) {\n // Load 32 bytes from the start and shift it 240 bits to the right to get the highest 16 bits.\n assembly {\n version_ := shr(240, calldataload(encodedTx.offset))\n }\n }\n\n /// @notice Extracts the origin chain ID from the encoded transaction.\n function originChainId(bytes calldata encodedTx) internal pure returns (uint32 originChainId_) {\n // Load 32 bytes from the offset and shift it 224 bits to the right to get the highest 32 bits.\n assembly {\n originChainId_ := shr(224, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_CHAIN_ID)))\n }\n }\n\n /// @notice Extracts the destination chain ID from the encoded transaction.\n function destChainId(bytes calldata encodedTx) internal pure returns (uint32 destChainId_) {\n // Load 32 bytes from the offset and shift it 224 bits to the right to get the highest 32 bits.\n assembly {\n destChainId_ := shr(224, calldataload(add(encodedTx.offset, OFFSET_DEST_CHAIN_ID)))\n }\n }\n\n /// @notice Extracts the origin sender from the encoded transaction.\n function originSender(bytes calldata encodedTx) internal pure returns (address originSender_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n originSender_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_SENDER)))\n }\n }\n\n /// @notice Extracts the destination recipient from the encoded transaction.\n function destRecipient(bytes calldata encodedTx) internal pure returns (address destRecipient_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n destRecipient_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_DEST_RECIPIENT)))\n }\n }\n\n /// @notice Extracts the origin token from the encoded transaction.\n function originToken(bytes calldata encodedTx) internal pure returns (address originToken_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n originToken_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_TOKEN)))\n }\n }\n\n /// @notice Extracts the destination token from the encoded transaction.\n function destToken(bytes calldata encodedTx) internal pure returns (address destToken_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n destToken_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_DEST_TOKEN)))\n }\n }\n\n /// @notice Extracts the origin amount from the encoded transaction.\n function originAmount(bytes calldata encodedTx) internal pure returns (uint256 originAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n originAmount_ := calldataload(add(encodedTx.offset, OFFSET_ORIGIN_AMOUNT))\n }\n }\n\n /// @notice Extracts the destination amount from the encoded transaction.\n function destAmount(bytes calldata encodedTx) internal pure returns (uint256 destAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n destAmount_ := calldataload(add(encodedTx.offset, OFFSET_DEST_AMOUNT))\n }\n }\n\n /// @notice Extracts the origin fee amount from the encoded transaction.\n function originFeeAmount(bytes calldata encodedTx) internal pure returns (uint256 originFeeAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n originFeeAmount_ := calldataload(add(encodedTx.offset, OFFSET_ORIGIN_FEE_AMOUNT))\n }\n }\n\n /// @notice Extracts the deadline from the encoded transaction.\n function deadline(bytes calldata encodedTx) internal pure returns (uint256 deadline_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n deadline_ := calldataload(add(encodedTx.offset, OFFSET_DEADLINE))\n }\n }\n\n /// @notice Extracts the nonce from the encoded transaction.\n function nonce(bytes calldata encodedTx) internal pure returns (uint256 nonce_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n nonce_ := calldataload(add(encodedTx.offset, OFFSET_NONCE))\n }\n }\n\n /// @notice Extracts the exclusivity relayer from the encoded transaction.\n function exclusivityRelayer(bytes calldata encodedTx) internal pure returns (address exclusivityRelayer_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n exclusivityRelayer_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_EXCLUSIVITY_RELAYER)))\n }\n }\n\n /// @notice Extracts the exclusivity end time from the encoded transaction.\n function exclusivityEndTime(bytes calldata encodedTx) internal pure returns (uint256 exclusivityEndTime_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n exclusivityEndTime_ := calldataload(add(encodedTx.offset, OFFSET_EXCLUSIVITY_END_TIME))\n }\n }\n\n /// @notice Extracts the Zap's native value from the encoded transaction.\n function zapNative(bytes calldata encodedTx) internal pure returns (uint256 zapNative_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n zapNative_ := calldataload(add(encodedTx.offset, OFFSET_ZAP_NATIVE))\n }\n }\n\n /// @notice Extracts the Zap's data from the encoded transaction.\n function zapData(bytes calldata encodedTx) internal pure returns (bytes calldata zapData_) {\n zapData_ = encodedTx[OFFSET_ZAP_DATA:];\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/AdminV2.sol\n\n// ════════════════════════════════════════════════ INTERFACES ═════════════════════════════════════════════════════\n\n// ═════════════════════════════════════════════ EXTERNAL IMPORTS ══════════════════════════════════════════════════\n\n/// @title AdminV2\n/// @notice Provides administrative functions and controls for managing the FastBridgeV2 contract,\n/// including access control and configuration settings.\ncontract AdminV2 is AccessControlEnumerable, IAdminV2, IAdminV2Errors {\n using SafeERC20 for IERC20;\n\n /// @notice The address reserved for the native gas token (ETH on Ethereum and most L2s, AVAX on Avalanche, etc.).\n address public constant NATIVE_GAS_TOKEN = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice The role identifier for the Quoter API's off-chain authentication.\n /// @dev Only addresses with this role can post FastBridge quotes to the API.\n bytes32 public constant QUOTER_ROLE = keccak256(\"QUOTER_ROLE\");\n\n /// @notice The role identifier for the Prover's on-chain authentication in FastBridge.\n /// @dev Only addresses with this role can provide proofs that a FastBridge request has been relayed.\n bytes32 public constant PROVER_ROLE = keccak256(\"PROVER_ROLE\");\n\n /// @notice The role identifier for the Guard's on-chain authentication in FastBridge.\n /// @dev Only addresses with this role can dispute submitted relay proofs during the dispute period.\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n\n /// @notice The role identifier for the Canceler's on-chain authentication in FastBridge.\n /// @dev Only addresses with this role can cancel a FastBridge transaction without the cancel delay.\n bytes32 public constant CANCELER_ROLE = keccak256(\"CANCELER_ROLE\");\n\n /// @notice The role identifier for the Governor's on-chain administrative authority.\n /// @dev Only addresses with this role can perform administrative tasks within the contract.\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n /// @notice The denominator for fee rates, representing 100%.\n uint256 public constant FEE_BPS = 1e6;\n /// @notice The maximum protocol fee rate: 1% of the origin amount.\n uint256 public constant FEE_RATE_MAX = 0.01e6;\n\n /// @notice The minimum cancel delay that can be set by the governor.\n uint256 public constant MIN_CANCEL_DELAY = 1 hours;\n /// @notice The default cancel delay set during contract deployment.\n uint256 public constant DEFAULT_CANCEL_DELAY = 1 days;\n\n /// @notice The protocol fee rate taken on the origin amount deposited in the origin chain.\n uint256 public protocolFeeRate;\n\n /// @notice The accumulated protocol fee amounts.\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice The delay period after which a transaction can be permissionlessly cancelled.\n uint256 public cancelDelay;\n\n /// @notice This variable is deprecated and should not be used.\n /// @dev Use ZapNative V2 requests instead.\n uint256 public immutable chainGasAmount = 0;\n\n constructor(address defaultAdmin) {\n _grantRole(DEFAULT_ADMIN_ROLE, defaultAdmin);\n _setCancelDelay(DEFAULT_CANCEL_DELAY);\n }\n\n /// @inheritdoc IAdminV2\n function setCancelDelay(uint256 newCancelDelay) external onlyRole(GOVERNOR_ROLE) {\n _setCancelDelay(newCancelDelay);\n }\n\n /// @inheritdoc IAdminV2\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n if (newFeeRate \u003e FEE_RATE_MAX) revert FeeRateAboveMax();\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n /// @inheritdoc IAdminV2\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n // Early exit if no accumulated fees.\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return;\n // Reset the accumulated fees first.\n protocolFees[token] = 0;\n emit FeesSwept(token, recipient, feeAmount);\n // Sweep the fees as the last transaction action.\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(recipient), feeAmount);\n } else {\n IERC20(token).safeTransfer(recipient, feeAmount);\n }\n }\n\n /// @notice Internal logic to set the cancel delay. Security checks are performed outside of this function.\n /// @dev This function is marked as private to prevent child contracts from calling it directly.\n function _setCancelDelay(uint256 newCancelDelay) private {\n if (newCancelDelay \u003c MIN_CANCEL_DELAY) revert CancelDelayBelowMin();\n uint256 oldCancelDelay = cancelDelay;\n cancelDelay = newCancelDelay;\n emit CancelDelayUpdated(oldCancelDelay, newCancelDelay);\n }\n}\n\n// contracts/FastBridgeV2.sol\n\n// ════════════════════════════════════════════════ INTERFACES ═════════════════════════════════════════════════════\n\n// ═════════════════════════════════════════════ INTERNAL IMPORTS ══════════════════════════════════════════════════\n\n// ═════════════════════════════════════════════ EXTERNAL IMPORTS ══════════════════════════════════════════════════\n\n/// @title FastBridgeV2\n/// @notice Core component of the SynapseRFQ protocol, enabling Relayers (Solvers) to fulfill bridge requests.\n/// Supports ERC20 and native gas tokens, along with the Zap feature for executing actions on the destination chain.\n/// Users interact with the off-chain Quoter API to obtain a current quote for a bridge transaction.\n/// They then submit the bridge request with the quote to this contract, depositing their assets in escrow.\n/// Relayers can fulfill requests by relaying them to the destination chain and must prove fulfillment to claim funds.\n/// Guards monitor proofs and can dispute discrepancies.\n/// Users can reclaim funds by cancelling their requests if it has not been fulfilled within the specified deadline.\ncontract FastBridgeV2 is AdminV2, MulticallTarget, IFastBridgeV2, IFastBridgeV2Errors {\n using BridgeTransactionV2Lib for bytes;\n using SafeERC20 for IERC20;\n\n /// @notice The duration of the dispute period for relayed transactions.\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice The minimum required time between transaction request and deadline.\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n /// @notice The maximum allowed length for zapData.\n uint256 public constant MAX_ZAP_DATA_LENGTH = 2 ** 16 - 1;\n\n /// @notice Maps transaction IDs to bridge details (status, destination chain ID, proof timestamp, and relayer).\n /// Note: this is only stored for transactions having local chain as the origin chain.\n mapping(bytes32 =\u003e BridgeTxDetails) public bridgeTxDetails;\n /// @notice Maps transaction IDs to relay details (block number, block timestamp, and relayer).\n /// Note: this is only stored for transactions having local chain as the destination chain.\n mapping(bytes32 =\u003e BridgeRelay) public bridgeRelayDetails;\n /// @notice Maps sender addresses to their unique bridge nonce.\n mapping(address =\u003e uint256) public senderNonces;\n\n /// @notice This variable is deprecated and should not be used.\n /// @dev Replaced by senderNonces.\n uint256 public immutable nonce = 0;\n /// @notice The block number at which this contract was deployed.\n uint256 public immutable deployBlock;\n\n /// @notice Initializes the FastBridgeV2 contract with the provided default admin,\n /// sets the default cancel delay, and records the deploy block number.\n constructor(address defaultAdmin) AdminV2(defaultAdmin) {\n deployBlock = block.number;\n }\n\n // ══════════════════════════════════════ EXTERNAL MUTABLE (USER FACING) ═══════════════════════════════════════════\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n bridgeV2({\n params: params,\n paramsV2: BridgeParamsV2({\n quoteRelayer: address(0),\n quoteExclusivitySeconds: 0,\n quoteId: bytes(\"\"),\n zapNative: 0,\n zapData: bytes(\"\")\n })\n });\n }\n\n /// Note: this function is deprecated and will be removed in a future version.\n /// @dev Replaced by `cancel`.\n /// @inheritdoc IFastBridge\n function refund(bytes calldata request) external {\n cancelV2(request);\n }\n\n // ══════════════════════════════════════ EXTERNAL MUTABLE (AGENT FACING) ══════════════════════════════════════════\n\n /// @inheritdoc IFastBridge\n function relay(bytes calldata request) external payable {\n // `relay` override will validate the request.\n relayV2({request: request, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes calldata request, bytes32 destTxHash) external {\n request.validateV2();\n proveV2({transactionId: keccak256(request), destTxHash: destTxHash, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridgeV2\n function claimV2(bytes calldata request) external {\n // `claim` override will validate the request.\n claim({request: request, to: address(0)});\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n // Aggregate the read operations from the same storage slot.\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n address disputedRelayer = $.proofRelayer;\n BridgeStatus status = $.status;\n uint56 proofBlockTimestamp = $.proofBlockTimestamp;\n\n // Can only dispute a RELAYER_PROVED transaction within the dispute period.\n if (status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(proofBlockTimestamp) \u003e DISPUTE_PERIOD) {\n revert DisputePeriodPassed();\n }\n\n // Update status to REQUESTED and delete the disputed proof details.\n // Note: these are storage writes.\n $.status = BridgeStatus.REQUESTED;\n $.proofRelayer = address(0);\n $.proofBlockTimestamp = 0;\n\n emit BridgeProofDisputed(transactionId, disputedRelayer);\n }\n\n // ══════════════════════════════════════════════ EXTERNAL VIEWS ═══════════════════════════════════════════════════\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n // The correct relayer can only claim a RELAYER_PROVED transaction after the dispute period.\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n if ($.status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if ($.proofRelayer != relayer) revert SenderIncorrect();\n\n return _timeSince($.proofBlockTimestamp) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n /// @dev This method is added to achieve backwards compatibility with decoding requests into V1 structs:\n /// - `zapNative` is partially reported as a zero/non-zero flag\n /// - `zapData` is ignored\n /// In order to process all kinds of requests use getBridgeTransactionV2 instead.\n function getBridgeTransaction(bytes calldata request) external view returns (BridgeTransaction memory) {\n // Try decoding into V2 struct first. This will revert if V1 struct is passed.\n try this.getBridgeTransactionV2(request) returns (BridgeTransactionV2 memory txV2) {\n // Note: we entirely ignore the zapData field, as it was not present in V1.\n return BridgeTransaction({\n originChainId: txV2.originChainId,\n destChainId: txV2.destChainId,\n originSender: txV2.originSender,\n destRecipient: txV2.destRecipient,\n originToken: txV2.originToken,\n destToken: txV2.destToken,\n originAmount: txV2.originAmount,\n destAmount: txV2.destAmount,\n originFeeAmount: txV2.originFeeAmount,\n sendChainGas: txV2.zapNative != 0,\n deadline: txV2.deadline,\n nonce: txV2.nonce\n });\n } catch {\n // Fallback to V1 struct.\n return abi.decode(request, (BridgeTransaction));\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function getBridgeTransactionV2(bytes calldata request) external pure returns (BridgeTransactionV2 memory) {\n request.validateV2();\n return BridgeTransactionV2Lib.decodeV2(request);\n }\n\n // ═══════════════════════════════════════ PUBLIC MUTABLE (USER FACING) ════════════════════════════════════════════\n\n /// @inheritdoc IFastBridgeV2\n function bridgeV2(BridgeParams memory params, BridgeParamsV2 memory paramsV2) public payable {\n // If relayer exclusivity is not intended for this bridge, set exclusivityEndTime to static zero.\n // Otherwise, set exclusivity to expire at the current block ts offset by quoteExclusivitySeconds.\n int256 exclusivityEndTime = 0;\n if (paramsV2.quoteRelayer != address(0)) {\n exclusivityEndTime = int256(block.timestamp) + paramsV2.quoteExclusivitySeconds;\n }\n _validateBridgeParams(params, paramsV2, exclusivityEndTime);\n\n // Transfer tokens to bridge contract. We use the actual transferred amount in case of transfer fees.\n uint256 originAmount = _takeBridgedUserAsset(params.originToken, params.originAmount);\n\n // Track the amount of origin token owed to protocol.\n uint256 originFeeAmount = 0;\n if (protocolFeeRate \u003e 0) {\n originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n // The Relayer filling this request will be paid the originAmount after fees.\n // Note: the protocol fees will be accumulated only when the Relayer claims the origin collateral.\n originAmount -= originFeeAmount;\n }\n\n // Hash the bridge request and set the initial status to REQUESTED.\n bytes memory request = BridgeTransactionV2Lib.encodeV2(\n BridgeTransactionV2({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n deadline: params.deadline,\n // Increment the sender's nonce on every bridge.\n nonce: senderNonces[params.sender]++,\n exclusivityRelayer: paramsV2.quoteRelayer,\n // We checked exclusivityEndTime to be in range [0 .. params.deadline] above, so can safely cast.\n exclusivityEndTime: uint256(exclusivityEndTime),\n zapNative: paramsV2.zapNative,\n zapData: paramsV2.zapData\n })\n );\n bytes32 transactionId = keccak256(request);\n // Note: the tx status will be updated throughout the tx lifecycle, while destChainId is set once here.\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n bridgeTxDetails[transactionId].destChainId = params.dstChainId;\n\n emit BridgeRequested({\n transactionId: transactionId,\n sender: params.sender,\n request: request,\n destChainId: params.dstChainId,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n sendChainGas: paramsV2.zapNative != 0\n });\n emit BridgeQuoteDetails(transactionId, paramsV2.quoteId);\n }\n\n /// @inheritdoc IFastBridgeV2\n function cancelV2(bytes calldata request) public {\n // Decode the request and check that it could be cancelled.\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n\n // Can only cancel a REQUESTED transaction after its deadline expires.\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n if ($.status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n\n // Permissionless cancel is only allowed after `cancelDelay` on top of the deadline.\n uint256 deadline = request.deadline();\n if (!hasRole(CANCELER_ROLE, msg.sender)) deadline += cancelDelay;\n if (block.timestamp \u003c= deadline) revert DeadlineNotExceeded();\n\n // Update status to REFUNDED.\n // Note: this is a storage write.\n $.status = BridgeStatus.REFUNDED;\n\n // Return the full amount (collateral + protocol fees) to the original sender.\n // The protocol fees are only accumulated when the transaction is claimed, so we don't need to update them here.\n address to = request.originSender();\n address token = request.originToken();\n uint256 amount = request.originAmount() + request.originFeeAmount();\n\n // Emit the event before any external calls.\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n\n // Return the funds to the original sender as last transaction action.\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(to), amount);\n } else {\n IERC20(token).safeTransfer(to, amount);\n }\n }\n\n // ═══════════════════════════════════════ PUBLIC MUTABLE (AGENT FACING) ═══════════════════════════════════════════\n\n /// @inheritdoc IFastBridgeV2\n function relayV2(bytes calldata request, address relayer) public payable {\n // Decode the request and check that it could be relayed.\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n _validateRelayParams(request, transactionId, relayer);\n\n // Mark the bridge request as relayed by saving the relayer and the block details.\n bridgeRelayDetails[transactionId].blockNumber = uint48(block.number);\n bridgeRelayDetails[transactionId].blockTimestamp = uint48(block.timestamp);\n bridgeRelayDetails[transactionId].relayer = relayer;\n\n // Transfer tokens to recipient on destination chain and trigger Zap if requested.\n address to = request.destRecipient();\n address token = request.destToken();\n uint256 amount = request.destAmount();\n uint256 zapNative = request.zapNative();\n\n // Emit the event before any external calls.\n emit BridgeRelayed({\n transactionId: transactionId,\n relayer: relayer,\n to: to,\n originChainId: request.originChainId(),\n originToken: request.originToken(),\n destToken: token,\n originAmount: request.originAmount(),\n destAmount: amount,\n chainGasAmount: zapNative\n });\n\n // All state changes have been done at this point, can proceed to the external calls.\n // This follows the checks-effects-interactions pattern to mitigate potential reentrancy attacks.\n if (token == NATIVE_GAS_TOKEN) {\n // For the native gas token, additional zapNative is not allowed.\n if (zapNative != 0) revert ZapNativeNotSupported();\n // Check that the correct msg.value was sent.\n if (msg.value != amount) revert MsgValueIncorrect();\n // Don't do a native transfer yet: we will handle it alongside the Zap below.\n } else {\n // For ERC20s, we check that the correct msg.value was sent.\n if (msg.value != zapNative) revert MsgValueIncorrect();\n // We need to transfer the tokens from the Relayer to the recipient first before performing an\n // optional post-transfer Zap.\n IERC20(token).safeTransferFrom(msg.sender, to, amount);\n }\n // At this point we have done:\n // - Transferred the requested amount of ERC20 tokens to the recipient.\n // At this point we have confirmed:\n // - For ERC20s: msg.value matches the requested zapNative amount.\n // - For the native gas token: msg.value matches the requested destAmount.\n // Remaining optional things to do:\n // - Forward the full msg.value to the recipient (if non-zero).\n // - Trigger a Zap (if zapData is present).\n bytes calldata zapData = request.zapData();\n if (zapData.length != 0) {\n // Zap Data is present: Zap has been requested by the recipient. Trigger it forwarding the full msg.value.\n _triggerZapWithChecks({recipient: to, token: token, amount: amount, zapData: zapData});\n // Note: if token has a fee on transfers, the recipient will have received less than `amount`.\n // This is a very niche edge case and should be handled by the recipient contract.\n } else if (msg.value != 0) {\n // Zap Data is missing, but msg.value was sent. This could happen in two different cases:\n // - Relay with the native gas token is happening.\n // - Relay with ERC20 is happening, with a `zapNative \u003e 0` request.\n // In both cases, we need to transfer the full msg.value to the recipient.\n Address.sendValue(payable(to), msg.value);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function proveV2(bytes32 transactionId, bytes32 destTxHash, address relayer) public onlyRole(PROVER_ROLE) {\n // Can only prove a REQUESTED transaction.\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n if ($.status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n\n // Update status to RELAYER_PROVED and store the proof details.\n // Note: these are storage writes.\n $.status = BridgeStatus.RELAYER_PROVED;\n $.proofBlockTimestamp = uint56(block.timestamp);\n $.proofRelayer = relayer;\n\n emit BridgeProofProvided(transactionId, relayer, destTxHash);\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes calldata request, address to) public {\n // Decode the request and check that it could be claimed.\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n\n // Aggregate the read operations from the same storage slot.\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n address proofRelayer = $.proofRelayer;\n BridgeStatus status = $.status;\n uint56 proofBlockTimestamp = $.proofBlockTimestamp;\n\n // Can only claim a RELAYER_PROVED transaction after the dispute period.\n if (status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(proofBlockTimestamp) \u003c= DISPUTE_PERIOD) revert DisputePeriodNotPassed();\n if (to == address(0)) {\n // Anyone could claim the funds to the proven relayer on their behalf.\n to = proofRelayer;\n } else if (proofRelayer != msg.sender) {\n // Only the proven relayer could specify an address to claim the funds to.\n revert SenderIncorrect();\n }\n\n // Update status to RELAYER_CLAIMED and transfer the origin collateral to the specified claim address.\n // Note: this is a storage write.\n $.status = BridgeStatus.RELAYER_CLAIMED;\n\n // Accumulate protocol fees if origin fee amount exists.\n address token = request.originToken();\n uint256 amount = request.originAmount();\n uint256 originFeeAmount = request.originFeeAmount();\n if (originFeeAmount \u003e 0) protocolFees[token] += originFeeAmount;\n\n // Emit the event before any external calls.\n emit BridgeDepositClaimed(transactionId, proofRelayer, to, token, amount);\n\n // Complete the relayer claim as the last transaction action.\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(to), amount);\n } else {\n IERC20(token).safeTransfer(to, amount);\n }\n }\n\n // ═══════════════════════════════════════════════ PUBLIC VIEWS ════════════════════════════════════════════════════\n\n /// @inheritdoc IFastBridgeV2\n function bridgeStatuses(bytes32 transactionId) public view returns (BridgeStatus status) {\n return bridgeTxDetails[transactionId].status;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeProofs(bytes32 transactionId) public view returns (uint96 timestamp, address relayer) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n timestamp = $.proofBlockTimestamp;\n relayer = $.proofRelayer;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeRelays(bytes32 transactionId) public view returns (bool) {\n // This transaction has been relayed if the relayer address is recorded.\n return bridgeRelayDetails[transactionId].relayer != address(0);\n }\n\n // ═════════════════════════════════════════════ INTERNAL METHODS ══════════════════════════════════════════════════\n\n /// @notice Takes the bridged asset from the user into FastBridgeV2 custody. The asset will later be\n /// claimed by the relayer who completed the relay on the destination chain, or returned to the user\n /// via the cancel function if no relay is completed.\n function _takeBridgedUserAsset(address token, uint256 amount) internal returns (uint256 amountTaken) {\n if (token == NATIVE_GAS_TOKEN) {\n // For the native gas token, we just need to check that the supplied msg.value is correct.\n // Supplied `msg.value` is already in FastBridgeV2 custody.\n if (amount != msg.value) revert MsgValueIncorrect();\n amountTaken = msg.value;\n } else {\n // For ERC20s, token is explicitly transferred from the user to FastBridgeV2.\n // We don't allow non-zero `msg.value` to avoid extra funds from being stuck in FastBridgeV2.\n if (msg.value != 0) revert MsgValueIncorrect();\n // Throw an explicit error if the provided token address is not a contract.\n if (token.code.length == 0) revert TokenNotContract();\n\n // Use the balance difference as the amount taken in case of fee on transfer tokens.\n amountTaken = IERC20(token).balanceOf(address(this));\n IERC20(token).safeTransferFrom(msg.sender, address(this), amount);\n amountTaken = IERC20(token).balanceOf(address(this)) - amountTaken;\n }\n }\n\n /// @notice Calls the recipient's hook function with the specified zapData and validates\n /// the returned value.\n function _triggerZapWithChecks(address recipient, address token, uint256 amount, bytes calldata zapData) internal {\n // Call the recipient's hook function with the specified zapData, bubbling any revert messages.\n bytes memory returnData = Address.functionCallWithValue({\n target: recipient,\n data: abi.encodeCall(IZapRecipient.zap, (token, amount, zapData)),\n // Note: see `relay()` for reasoning behind passing msg.value.\n value: msg.value\n });\n\n // Explicit revert if no return data at all.\n if (returnData.length == 0) revert RecipientNoReturnValue();\n // Check that exactly a single return value was returned.\n if (returnData.length != 32) revert RecipientIncorrectReturnValue();\n // Return value should be abi-encoded hook function selector.\n if (bytes32(returnData) != bytes32(IZapRecipient.zap.selector)) {\n revert RecipientIncorrectReturnValue();\n }\n }\n\n /// @notice Calculates the time elapsed since a proof was submitted.\n /// @dev The proof.timestamp stores block timestamps as uint56 for gas optimization.\n /// _timeSince(proof) handles timestamp rollover when block.timestamp \u003e type(uint56).max but\n /// proof.timestamp \u003c type(uint56).max via an unchecked statement.\n /// @param proofBlockTimestamp The block timestamp when the proof was submitted.\n /// @return delta The time elapsed since proof submission.\n function _timeSince(uint56 proofBlockTimestamp) internal view returns (uint256 delta) {\n unchecked {\n delta = uint56(block.timestamp) - proofBlockTimestamp;\n }\n }\n\n /// @notice Validates all parameters required for a bridge transaction.\n /// @dev This function's complexity cannot be reduced due to the number of required checks,\n /// so we disable the code-complexity rule.\n // solhint-disable-next-line code-complexity\n function _validateBridgeParams(\n BridgeParams memory params,\n BridgeParamsV2 memory paramsV2,\n int256 exclusivityEndTime\n )\n internal\n view\n {\n // Check V1 (legacy) params.\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.sender == address(0) || params.to == address(0)) revert ZeroAddress();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n\n // Check V2 params.\n if (paramsV2.zapData.length \u003e MAX_ZAP_DATA_LENGTH) revert ZapDataLengthAboveMax();\n if (paramsV2.zapNative != 0 \u0026\u0026 params.destToken == NATIVE_GAS_TOKEN) {\n revert ZapNativeNotSupported();\n }\n\n // exclusivityEndTime must be in range [0 .. params.deadline].\n if (exclusivityEndTime \u003c 0 || exclusivityEndTime \u003e int256(params.deadline)) {\n revert ExclusivityParamsIncorrect();\n }\n }\n\n /// @notice Validates all parameters required for a relay transaction.\n function _validateRelayParams(bytes calldata request, bytes32 transactionId, address relayer) internal view {\n if (relayer == address(0)) revert ZeroAddress();\n // Check that the transaction has not been relayed yet and is for the current chain.\n if (bridgeRelays(transactionId)) revert TransactionRelayed();\n if (request.destChainId() != block.chainid) revert ChainIncorrect();\n // Check that the deadline for relay to happen has not passed yet.\n if (block.timestamp \u003e request.deadline()) revert DeadlineExceeded();\n // Check the exclusivity period, if it was specified and is still ongoing.\n address exclRelayer = request.exclusivityRelayer();\n if (exclRelayer != address(0) \u0026\u0026 exclRelayer != relayer \u0026\u0026 block.timestamp \u003c= request.exclusivityEndTime()) {\n revert ExclusivityPeriodNotPassed();\n }\n }\n}\n","language":"Solidity","languageVersion":"0.8.24","compilerVersion":"0.8.24","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"19354:6066:0:-:0;;;;;;;;;;;;;;;-1:-1:-1;;;19354:6066:0;;;;;;;;;;;;;;;;;","srcMapRuntime":"19354:6066:0:-:0;;;;;;;;","abiDefinition":[{"inputs":[{"internalType":"address","name":"target","type":"address"}],"name":"AddressEmptyCode","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"AddressInsufficientBalance","type":"error"},{"inputs":[],"name":"FailedInnerCall","type":"error"}],"userDoc":{"kind":"user","methods":{},"version":1},"developerDoc":{"details":"Collection of functions related to the address type","errors":{"AddressEmptyCode(address)":[{"details":"There's no code at `target` (it is not a contract)."}],"AddressInsufficientBalance(address)":[{"details":"The ETH balance of the account is not enough to perform the operation."}],"FailedInnerCall()":[{"details":"A call to an address target failed. The target may have reverted."}]},"kind":"dev","methods":{},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"}],\"name\":\"AddressEmptyCode\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"AddressInsufficientBalance\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"FailedInnerCall\",\"type\":\"error\"}],\"devdoc\":{\"details\":\"Collection of functions related to the address type\",\"errors\":{\"AddressEmptyCode(address)\":[{\"details\":\"There's no code at `target` (it is not a contract).\"}],\"AddressInsufficientBalance(address)\":[{\"details\":\"The ETH balance of the account is not enough to perform the operation.\"}],\"FailedInnerCall()\":[{\"details\":\"A call to an address target failed. The target may have reverted.\"}]},\"kind\":\"dev\",\"methods\":{},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeV2.sol\":\"Address\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeV2.sol\":{\"keccak256\":\"0xaab2ee7357681726f0faf799a48ddfbf45fb4da93b69abf61c33dde92b29b74d\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://673391bff9569efc0f9bd99e0e6fece0bc8e8af1f052bb071b407b267a17b3b5\",\"dweb:/ipfs/QmdQQZ6DxpJYhfpinwU5WjLugr2f6qP8h68b5GerhSMQ4j\"]}},\"version\":1}"},"hashes":{}},"solidity/FastBridgeV2.sol:AdminV2":{"code":"0x60a060405260006080523480156200001657600080fd5b50604051620015763803806200157683398101604081905262000039916200020a565b620000466000826200005c565b50620000556201518062000099565b5062000235565b6000806200006b848462000102565b90508015620000905760008481526001602052604090206200008e9084620001b0565b505b90505b92915050565b610e10811015620000bd57604051630e0ea5c760e01b815260040160405180910390fd5b600480549082905560408051828152602081018490527f909f9078b2f6eac1d10f2aae793656c5a67511eb627ebd1d2cb1eb9c0ab94c95910160405180910390a15050565b6000828152602081815260408083206001600160a01b038516845290915281205460ff16620001a7576000838152602081815260408083206001600160a01b03861684529091529020805460ff191660011790556200015e3390565b6001600160a01b0316826001600160a01b0316847f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a450600162000093565b50600062000093565b600062000090836001600160a01b0384166000818152600183016020526040812054620001a75750815460018181018455600084815260208082209093018490558454848252828601909352604090209190915562000093565b6000602082840312156200021d57600080fd5b81516001600160a01b03811681146200009057600080fd5b60805161132562000251600039600061045201526113256000f3fe608060405234801561001057600080fd5b50600436106101ae5760003560e01c80639010d07c116100ee578063bf333f2c11610097578063d547741f11610071578063d547741f146103f3578063dc9a4ef614610406578063dcf844a71461042d578063e00a83e01461044d57600080fd5b8063bf333f2c146103af578063ca15c873146103b9578063ccc57490146103cc57600080fd5b8063930ac180116100c8578063930ac1801461038a578063a217fddf14610394578063b13aa2d61461039c57600080fd5b80639010d07c1461032a57806391d148541461033d578063922b74871461038157600080fd5b80631ea327c51161015b57806336568abe1161013557806336568abe146102de57806358f85880146102f1578063638a0f09146102fa5780637ebe815c1461030357600080fd5b80631ea327c514610295578063248a9ca3146102a85780632f2ff15d146102cb57600080fd5b806306f333f21161018c57806306f333f2146102375780630f5f6ed71461024c5780630f862f1e1461025557600080fd5b806301ffc9a7146101b357806302d2ff66146101db57806303ed0ee514610210575b600080fd5b6101c66101c13660046110ef565b610474565b60405190151581526020015b60405180910390f35b6102027febfdca8e46c0b8dacf9989ee613e35727eadd20a1d5e5ad01a53968c7e5fe07a81565b6040519081526020016101d2565b6102027f043c983c49d46f0e102151eaf8085d4a2e6571d5df2d47b013f39bddfd4a639d81565b61024a61024536600461115a565b6104d0565b005b61020261271081565b61027073eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee81565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016101d2565b61024a6102a336600461118d565b610611565b6102026102b636600461118d565b60009081526020819052604090206001015490565b61024a6102d93660046111a6565b610648565b61024a6102ec3660046111a6565b61066d565b61020260025481565b61020260045481565b6102027f9a04aea0a349253cc7277afafdf6ead6729a3972a47ffb40eaef2c93d4e1bfea81565b6102706103383660046111c9565b6106c6565b6101c661034b3660046111a6565b60009182526020828152604080842073ffffffffffffffffffffffffffffffffffffffff93909316845291905290205460ff1690565b610202610e1081565b6102026201518081565b610202600081565b61024a6103aa36600461118d565b6106e5565b610202620f424081565b6102026103c736600461118d565b610791565b6102027f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f5581565b61024a6104013660046111a6565b6107a8565b6102027f60044782a422109ac08a415e44260ad5d3bad63d96ebe1fac0363399642ee3f281565b61020261043b3660046111eb565b60036020526000908152604090205481565b6102027f000000000000000000000000000000000000000000000000000000000000000081565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f5a05180f0000000000000000000000000000000000000000000000000000000014806104ca57506104ca826107cd565b92915050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f556104fa81610864565b73ffffffffffffffffffffffffffffffffffffffff83166000908152600360205260408120549081900361052e5750505050565b73ffffffffffffffffffffffffffffffffffffffff8481166000818152600360209081526040808320929092558151928352928616928201929092529081018290527f244e51bc38c1452fa8aaf487bcb4bca36c2baa3a5fbdb776b1eabd8dc6d277cd9060600160405180910390a17fffffffffffffffffffffffff111111111111111111111111111111111111111273ffffffffffffffffffffffffffffffffffffffff8516016105e9576105e48382610871565b61060a565b61060a73ffffffffffffffffffffffffffffffffffffffff8516848361094c565b505b505050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f5561063b81610864565b610644826109d9565b5050565b60008281526020819052604090206001015461066381610864565b61060a8383610a5a565b73ffffffffffffffffffffffffffffffffffffffff811633146106bc576040517f6697b23200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61060c8282610a8f565b60008281526001602052604081206106de9083610abc565b9392505050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f5561070f81610864565b61271082111561074b576040517f9b569b8100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600280549083905560408051828152602081018590527f14914da2bf76024616fbe1859783fcd4dbddcb179b1f3a854949fbf920dcb957910160405180910390a1505050565b60008181526001602052604081206104ca90610ac8565b6000828152602081905260409020600101546107c381610864565b61060a8383610a8f565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f7965db0b0000000000000000000000000000000000000000000000000000000014806104ca57507f01ffc9a7000000000000000000000000000000000000000000000000000000007fffffffff000000000000000000000000000000000000000000000000000000008316146104ca565b61086e8133610ad2565b50565b804710156108b2576040517fcd7860590000000000000000000000000000000000000000000000000000000081523060048201526024015b60405180910390fd5b60008273ffffffffffffffffffffffffffffffffffffffff168260405160006040518083038185875af1925050503d806000811461090c576040519150601f19603f3d011682016040523d82523d6000602084013e610911565b606091505b505090508061060c576040517f1425ea4200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040805173ffffffffffffffffffffffffffffffffffffffff8416602482015260448082018490528251808303909101815260649091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fa9059cbb0000000000000000000000000000000000000000000000000000000017905261060c908490610b58565b610e10811015610a15576040517f0e0ea5c700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600480549082905560408051828152602081018490527f909f9078b2f6eac1d10f2aae793656c5a67511eb627ebd1d2cb1eb9c0ab94c95910160405180910390a15050565b600080610a678484610bee565b905080156106de576000848152600160205260409020610a879084610cea565b509392505050565b600080610a9c8484610d0c565b905080156106de576000848152600160205260409020610a879084610dc7565b60006106de8383610de9565b60006104ca825490565b60008281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915290205460ff16610644576040517fe2517d3f00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff82166004820152602481018390526044016108a9565b6000610b7a73ffffffffffffffffffffffffffffffffffffffff841683610e13565b90508051600014158015610b9f575080806020019051810190610b9d9190611206565b155b1561060c576040517f5274afe700000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff841660048201526024016108a9565b60008281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915281205460ff16610ce25760008381526020818152604080832073ffffffffffffffffffffffffffffffffffffffff86168452909152902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055610c803390565b73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16847f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45060016104ca565b5060006104ca565b60006106de8373ffffffffffffffffffffffffffffffffffffffff8416610e21565b60008281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915281205460ff1615610ce25760008381526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8616808552925280832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016905551339286917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a45060016104ca565b60006106de8373ffffffffffffffffffffffffffffffffffffffff8416610e68565b6000826000018281548110610e0057610e00611228565b9060005260206000200154905092915050565b60606106de83836000610f5b565b6000818152600183016020526040812054610ce2575081546001818101845560008481526020808220909301849055845484825282860190935260409020919091556104ca565b60008181526001830160205260408120548015610f51576000610e8c600183611257565b8554909150600090610ea090600190611257565b9050808214610f05576000866000018281548110610ec057610ec0611228565b9060005260206000200154905080876000018481548110610ee357610ee3611228565b6000918252602080832090910192909255918252600188019052604090208390555b8554869080610f1657610f16611291565b6001900381819060005260206000200160009055905585600101600086815260200190815260200160002060009055600193505050506104ca565b60009150506104ca565b606081471015610f99576040517fcd7860590000000000000000000000000000000000000000000000000000000081523060048201526024016108a9565b6000808573ffffffffffffffffffffffffffffffffffffffff168486604051610fc291906112c0565b60006040518083038185875af1925050503d8060008114610fff576040519150601f19603f3d011682016040523d82523d6000602084013e611004565b606091505b509150915061101486838361101e565b9695505050505050565b6060826110335761102e826110ad565b6106de565b8151158015611057575073ffffffffffffffffffffffffffffffffffffffff84163b155b156110a6576040517f9996b31500000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff851660048201526024016108a9565b50806106de565b8051156110bd5780518082602001fd5b6040517f1425ea4200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006020828403121561110157600080fd5b81357fffffffff00000000000000000000000000000000000000000000000000000000811681146106de57600080fd5b803573ffffffffffffffffffffffffffffffffffffffff8116811461115557600080fd5b919050565b6000806040838503121561116d57600080fd5b61117683611131565b915061118460208401611131565b90509250929050565b60006020828403121561119f57600080fd5b5035919050565b600080604083850312156111b957600080fd5b8235915061118460208401611131565b600080604083850312156111dc57600080fd5b50508035926020909101359150565b6000602082840312156111fd57600080fd5b6106de82611131565b60006020828403121561121857600080fd5b815180151581146106de57600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b818103818111156104ca577f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fd5b6000825160005b818110156112e157602081860181015185830152016112c7565b50600092019182525091905056fea26469706673582212206b451daf2e4e6c560ed06b0aa7925cb50e6aaa8710c48fe024cf23ecbc261d6b64736f6c63430008180033","runtime-code":"0x608060405234801561001057600080fd5b50600436106101ae5760003560e01c80639010d07c116100ee578063bf333f2c11610097578063d547741f11610071578063d547741f146103f3578063dc9a4ef614610406578063dcf844a71461042d578063e00a83e01461044d57600080fd5b8063bf333f2c146103af578063ca15c873146103b9578063ccc57490146103cc57600080fd5b8063930ac180116100c8578063930ac1801461038a578063a217fddf14610394578063b13aa2d61461039c57600080fd5b80639010d07c1461032a57806391d148541461033d578063922b74871461038157600080fd5b80631ea327c51161015b57806336568abe1161013557806336568abe146102de57806358f85880146102f1578063638a0f09146102fa5780637ebe815c1461030357600080fd5b80631ea327c514610295578063248a9ca3146102a85780632f2ff15d146102cb57600080fd5b806306f333f21161018c57806306f333f2146102375780630f5f6ed71461024c5780630f862f1e1461025557600080fd5b806301ffc9a7146101b357806302d2ff66146101db57806303ed0ee514610210575b600080fd5b6101c66101c13660046110ef565b610474565b60405190151581526020015b60405180910390f35b6102027febfdca8e46c0b8dacf9989ee613e35727eadd20a1d5e5ad01a53968c7e5fe07a81565b6040519081526020016101d2565b6102027f043c983c49d46f0e102151eaf8085d4a2e6571d5df2d47b013f39bddfd4a639d81565b61024a61024536600461115a565b6104d0565b005b61020261271081565b61027073eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee81565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016101d2565b61024a6102a336600461118d565b610611565b6102026102b636600461118d565b60009081526020819052604090206001015490565b61024a6102d93660046111a6565b610648565b61024a6102ec3660046111a6565b61066d565b61020260025481565b61020260045481565b6102027f9a04aea0a349253cc7277afafdf6ead6729a3972a47ffb40eaef2c93d4e1bfea81565b6102706103383660046111c9565b6106c6565b6101c661034b3660046111a6565b60009182526020828152604080842073ffffffffffffffffffffffffffffffffffffffff93909316845291905290205460ff1690565b610202610e1081565b6102026201518081565b610202600081565b61024a6103aa36600461118d565b6106e5565b610202620f424081565b6102026103c736600461118d565b610791565b6102027f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f5581565b61024a6104013660046111a6565b6107a8565b6102027f60044782a422109ac08a415e44260ad5d3bad63d96ebe1fac0363399642ee3f281565b61020261043b3660046111eb565b60036020526000908152604090205481565b6102027f000000000000000000000000000000000000000000000000000000000000000081565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f5a05180f0000000000000000000000000000000000000000000000000000000014806104ca57506104ca826107cd565b92915050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f556104fa81610864565b73ffffffffffffffffffffffffffffffffffffffff83166000908152600360205260408120549081900361052e5750505050565b73ffffffffffffffffffffffffffffffffffffffff8481166000818152600360209081526040808320929092558151928352928616928201929092529081018290527f244e51bc38c1452fa8aaf487bcb4bca36c2baa3a5fbdb776b1eabd8dc6d277cd9060600160405180910390a17fffffffffffffffffffffffff111111111111111111111111111111111111111273ffffffffffffffffffffffffffffffffffffffff8516016105e9576105e48382610871565b61060a565b61060a73ffffffffffffffffffffffffffffffffffffffff8516848361094c565b505b505050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f5561063b81610864565b610644826109d9565b5050565b60008281526020819052604090206001015461066381610864565b61060a8383610a5a565b73ffffffffffffffffffffffffffffffffffffffff811633146106bc576040517f6697b23200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61060c8282610a8f565b60008281526001602052604081206106de9083610abc565b9392505050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f5561070f81610864565b61271082111561074b576040517f9b569b8100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600280549083905560408051828152602081018590527f14914da2bf76024616fbe1859783fcd4dbddcb179b1f3a854949fbf920dcb957910160405180910390a1505050565b60008181526001602052604081206104ca90610ac8565b6000828152602081905260409020600101546107c381610864565b61060a8383610a8f565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f7965db0b0000000000000000000000000000000000000000000000000000000014806104ca57507f01ffc9a7000000000000000000000000000000000000000000000000000000007fffffffff000000000000000000000000000000000000000000000000000000008316146104ca565b61086e8133610ad2565b50565b804710156108b2576040517fcd7860590000000000000000000000000000000000000000000000000000000081523060048201526024015b60405180910390fd5b60008273ffffffffffffffffffffffffffffffffffffffff168260405160006040518083038185875af1925050503d806000811461090c576040519150601f19603f3d011682016040523d82523d6000602084013e610911565b606091505b505090508061060c576040517f1425ea4200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040805173ffffffffffffffffffffffffffffffffffffffff8416602482015260448082018490528251808303909101815260649091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fa9059cbb0000000000000000000000000000000000000000000000000000000017905261060c908490610b58565b610e10811015610a15576040517f0e0ea5c700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600480549082905560408051828152602081018490527f909f9078b2f6eac1d10f2aae793656c5a67511eb627ebd1d2cb1eb9c0ab94c95910160405180910390a15050565b600080610a678484610bee565b905080156106de576000848152600160205260409020610a879084610cea565b509392505050565b600080610a9c8484610d0c565b905080156106de576000848152600160205260409020610a879084610dc7565b60006106de8383610de9565b60006104ca825490565b60008281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915290205460ff16610644576040517fe2517d3f00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff82166004820152602481018390526044016108a9565b6000610b7a73ffffffffffffffffffffffffffffffffffffffff841683610e13565b90508051600014158015610b9f575080806020019051810190610b9d9190611206565b155b1561060c576040517f5274afe700000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff841660048201526024016108a9565b60008281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915281205460ff16610ce25760008381526020818152604080832073ffffffffffffffffffffffffffffffffffffffff86168452909152902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055610c803390565b73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16847f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45060016104ca565b5060006104ca565b60006106de8373ffffffffffffffffffffffffffffffffffffffff8416610e21565b60008281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915281205460ff1615610ce25760008381526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8616808552925280832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016905551339286917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a45060016104ca565b60006106de8373ffffffffffffffffffffffffffffffffffffffff8416610e68565b6000826000018281548110610e0057610e00611228565b9060005260206000200154905092915050565b60606106de83836000610f5b565b6000818152600183016020526040812054610ce2575081546001818101845560008481526020808220909301849055845484825282860190935260409020919091556104ca565b60008181526001830160205260408120548015610f51576000610e8c600183611257565b8554909150600090610ea090600190611257565b9050808214610f05576000866000018281548110610ec057610ec0611228565b9060005260206000200154905080876000018481548110610ee357610ee3611228565b6000918252602080832090910192909255918252600188019052604090208390555b8554869080610f1657610f16611291565b6001900381819060005260206000200160009055905585600101600086815260200190815260200160002060009055600193505050506104ca565b60009150506104ca565b606081471015610f99576040517fcd7860590000000000000000000000000000000000000000000000000000000081523060048201526024016108a9565b6000808573ffffffffffffffffffffffffffffffffffffffff168486604051610fc291906112c0565b60006040518083038185875af1925050503d8060008114610fff576040519150601f19603f3d011682016040523d82523d6000602084013e611004565b606091505b509150915061101486838361101e565b9695505050505050565b6060826110335761102e826110ad565b6106de565b8151158015611057575073ffffffffffffffffffffffffffffffffffffffff84163b155b156110a6576040517f9996b31500000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff851660048201526024016108a9565b50806106de565b8051156110bd5780518082602001fd5b6040517f1425ea4200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006020828403121561110157600080fd5b81357fffffffff00000000000000000000000000000000000000000000000000000000811681146106de57600080fd5b803573ffffffffffffffffffffffffffffffffffffffff8116811461115557600080fd5b919050565b6000806040838503121561116d57600080fd5b61117683611131565b915061118460208401611131565b90509250929050565b60006020828403121561119f57600080fd5b5035919050565b600080604083850312156111b957600080fd5b8235915061118460208401611131565b600080604083850312156111dc57600080fd5b50508035926020909101359150565b6000602082840312156111fd57600080fd5b6106de82611131565b60006020828403121561121857600080fd5b815180151581146106de57600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b818103818111156104ca577f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fd5b6000825160005b818110156112e157602081860181015185830152016112c7565b50600092019182525091905056fea26469706673582212206b451daf2e4e6c560ed06b0aa7925cb50e6aaa8710c48fe024cf23ecbc261d6b64736f6c63430008180033","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.24 ^0.8.20 ^0.8.4;\n\n// contracts/interfaces/IAdminV2.sol\n\ninterface IAdminV2 {\n event CancelDelayUpdated(uint256 oldCancelDelay, uint256 newCancelDelay);\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n /// @notice Allows the governor to set the cancel delay. The cancel delay is the time period after the transaction\n /// deadline during which a transaction can be permissionlessly cancelled if it hasn't been proven by any Relayer.\n function setCancelDelay(uint256 newCancelDelay) external;\n\n /// @notice Allows the governor to set the protocol fee rate. The protocol fee is taken from the origin\n /// amount and is only applied to completed and claimed transactions.\n /// @dev The protocol fee is abstracted away from the relayers; they always operate using the amounts after fees.\n /// The origin amount they see in the emitted log is what they get credited with.\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n /// @notice Allows the governor to withdraw the accumulated protocol fees from the contract.\n function sweepProtocolFees(address token, address recipient) external;\n}\n\n// contracts/interfaces/IAdminV2Errors.sol\n\ninterface IAdminV2Errors {\n error CancelDelayBelowMin();\n error FeeRateAboveMax();\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IFastBridgeV2Errors.sol\n\ninterface IFastBridgeV2Errors {\n error AmountIncorrect();\n error ChainIncorrect();\n error ExclusivityParamsIncorrect();\n error MsgValueIncorrect();\n error SenderIncorrect();\n error StatusIncorrect();\n error TokenNotContract();\n error ZapDataLengthAboveMax();\n error ZapNativeNotSupported();\n error ZeroAddress();\n\n error RecipientIncorrectReturnValue();\n error RecipientNoReturnValue();\n\n error DeadlineExceeded();\n error DeadlineNotExceeded();\n error DeadlineTooShort();\n error DisputePeriodNotPassed();\n error DisputePeriodPassed();\n error ExclusivityPeriodNotPassed();\n\n error TransactionRelayed();\n}\n\n// contracts/interfaces/IMulticallTarget.sol\n\n/// @notice Interface for a contract that supports multiple calls from the same caller. Inspired by MulticallV3:\n/// https://github.com/mds1/multicall/blob/master/src/Multicall3.sol\ninterface IMulticallTarget {\n struct Result {\n bool success;\n bytes returnData;\n }\n\n /// @notice Executes multiple calls to this contract in a single transaction while preserving msg.sender.\n /// Return data from the calls is discarded.\n /// @dev This method is non-payable, so only calls with msg.value of 0 can be batched.\n /// If ignoreReverts is set to true, reverted calls will be skipped.\n /// Otherwise, the entire batch will revert with the original revert reason.\n /// @param data List of ABI-encoded calldata for the calls to execute\n /// @param ignoreReverts Whether to skip calls that revert\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external;\n\n /// @notice Executes multiple calls to this contract in a single transaction while preserving msg.sender.\n /// Return data from each call is preserved.\n /// @dev This method is non-payable, so only calls with msg.value of 0 can be batched.\n /// If ignoreReverts is set to true, reverted calls will be skipped.\n /// Otherwise, the entire batch will revert with the original revert reason.\n /// @param data List of ABI-encoded calldata for the calls to execute\n /// @param ignoreReverts Whether to skip calls that revert\n /// @return results List of results from the calls, each containing (success, returnData)\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results);\n}\n\n// contracts/interfaces/IZapRecipient.sol\n\n/// @notice Interface for contracts that can perform Zap operations. Such contracts could be used as Recipients\n/// in a FastBridge transaction that includes a Zap operation. The Zap Data should include instructions on how\n/// exactly the Zap operation should be executed, which would typically include the target address and calldata\n/// to use. The exact implementation of the Zap Data encoding is up to the Recipient contract.\ninterface IZapRecipient {\n /// @notice Performs a Zap operation with the given token and amount according to the provided Zap data.\n /// @param token The address of the token being used for the Zap operation.\n /// @param amount The amount of tokens to be used.\n /// @param zapData The encoded data specifying how the Zap operation should be executed.\n /// @return The function selector to indicate successful execution.\n function zap(address token, uint256 amount, bytes memory zapData) external payable returns (bytes4);\n}\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// contracts/interfaces/IFastBridgeV2.sol\n\ninterface IFastBridgeV2 is IFastBridge {\n enum BridgeStatus {\n NULL, // Doesn't exist yet.\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n struct BridgeTxDetails {\n BridgeStatus status;\n uint32 destChainId;\n uint56 proofBlockTimestamp;\n address proofRelayer;\n }\n\n struct BridgeRelay {\n uint48 blockNumber;\n uint48 blockTimestamp;\n address relayer;\n }\n\n /// @notice New params introduced in the FastBridgeV2.\n /// We are passing fields from the older BridgeParams struct outside of this struct for backwards compatibility.\n /// Note: quoteRelayer and quoteExclusivitySeconds are either both zero (indicating no exclusivity)\n /// or both non-zero (indicating exclusivity for the given period).\n /// Note: zapNative \u003e 0 can NOT be used with destToken = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE (native token)\n /// @param quoteRelayer Relayer that provided the quote for the transaction\n /// @param quoteExclusivitySeconds Period of time the quote relayer is guaranteed exclusivity after user's deposit\n /// @param quoteId Unique quote identifier used for tracking the quote\n /// @param zapNative ETH value to send to the recipient (if any)\n /// @param zapData Parameters for the Zap to the destination recipient (if any)\n struct BridgeParamsV2 {\n address quoteRelayer;\n int256 quoteExclusivitySeconds;\n bytes quoteId;\n uint256 zapNative;\n bytes zapData;\n }\n\n /// @notice Updated bridge transaction struct to include parameters introduced in FastBridgeV2.\n /// Note: only `exclusivityRelayer` can fill such a transaction until `exclusivityEndTime`.\n struct BridgeTransactionV2 {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n // Note: sendChainGas flag from V1 is deprecated\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n address exclusivityRelayer;\n uint256 exclusivityEndTime;\n uint256 zapNative; // ETH value to send to the recipient (if any)\n bytes zapData; // data to pass for the Zap action (if any)\n }\n\n event BridgeQuoteDetails(bytes32 indexed transactionId, bytes quoteId);\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability\n /// to provide temporary exclusivity fill rights for the quote relayer.\n /// @param params The parameters required to bridge\n /// @param paramsV2 The parameters for exclusivity fill rights (optional, can be left empty)\n function bridgeV2(BridgeParams memory params, BridgeParamsV2 memory paramsV2) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function relayV2(bytes memory request, address relayer) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param transactionId The transaction id associated with the encoded bridge transaction to prove\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function proveV2(bytes32 transactionId, bytes32 destTxHash, address relayer) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital.\n /// @notice Can only send funds to the relayer address on the proof.\n /// @param request The encoded bridge transaction to claim on origin chain\n function claimV2(bytes memory request) external;\n\n /// @notice Cancels an outstanding bridge transaction in case optimistic bridging failed and returns the full amount\n /// to the original sender.\n /// @param request The encoded bridge transaction to refund\n function cancelV2(bytes memory request) external;\n\n /// @notice Checks if a transaction has been relayed\n /// @param transactionId The ID of the transaction to check\n /// @return True if the transaction has been relayed, false otherwise\n function bridgeRelays(bytes32 transactionId) external view returns (bool);\n\n /// @notice Returns the status of a bridge transaction\n /// @param transactionId The ID of the bridge transaction\n /// @return BridgeStatus Status of the bridge transaction\n function bridgeStatuses(bytes32 transactionId) external view returns (BridgeStatus);\n\n /// @notice Returns the timestamp and relayer of a bridge proof\n /// @param transactionId The ID of the bridge transaction\n /// @return timestamp The timestamp of the bridge proof\n /// @return relayer The relayer address of the bridge proof\n function bridgeProofs(bytes32 transactionId) external view returns (uint96 timestamp, address relayer);\n\n /// @notice Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\n /// @param request The bridge request to decode\n function getBridgeTransactionV2(bytes memory request) external view returns (BridgeTransactionV2 memory);\n}\n\n// contracts/utils/MulticallTarget.sol\n\n// solhint-disable avoid-low-level-calls\n/// @notice Abstract contract template that supports batched calls while preserving msg.sender.\n/// Only calls with msg.value of 0 can be batched.\nabstract contract MulticallTarget is IMulticallTarget {\n error MulticallTarget__UndeterminedRevert();\n\n /// @inheritdoc IMulticallTarget\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external {\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\n if (!success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(result);\n }\n }\n }\n\n /// @inheritdoc IMulticallTarget\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results)\n {\n results = new Result[](data.length);\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (results[i].success, results[i].returnData) = address(this).delegatecall(data[i]);\n if (!results[i].success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(results[i].returnData);\n }\n }\n }\n\n /// @dev Bubbles the revert message from the underlying call.\n /// Note: preserves the same custom error or revert string, if one was used.\n /// Source: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v5.0.2/contracts/utils/Address.sol#L143-L158\n function _bubbleRevert(bytes memory returnData) internal pure {\n // Look for revert reason and bubble it up if present\n if (returnData.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n // solhint-disable-next-line no-inline-assembly\n assembly {\n let returndata_size := mload(returnData)\n revert(add(32, returnData), returndata_size)\n }\n } else {\n revert MulticallTarget__UndeterminedRevert();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// contracts/libs/BridgeTransactionV2.sol\n\n// solhint-disable no-inline-assembly\nlibrary BridgeTransactionV2Lib {\n uint16 internal constant VERSION = 2;\n\n // Offsets of the fields in the packed BridgeTransactionV2 struct\n // uint16 version [000 .. 002)\n // uint32 originChainId [002 .. 006)\n // uint32 destChainId [006 .. 010)\n // address originSender [010 .. 030)\n // address destRecipient [030 .. 050)\n // address originToken [050 .. 070)\n // address destToken [070 .. 090)\n // uint256 originAmount [090 .. 122)\n // uint256 destAmount [122 .. 154)\n // uint256 originFeeAmount [154 .. 186)\n // uint256 deadline [186 .. 218)\n // uint256 nonce [218 .. 250)\n // address exclusivityRelayer [250 .. 270)\n // uint256 exclusivityEndTime [270 .. 302)\n // uint256 zapNative [302 .. 334)\n // bytes zapData [334 .. ***)\n\n // forgefmt: disable-start\n uint256 private constant OFFSET_ORIGIN_CHAIN_ID = 2;\n uint256 private constant OFFSET_DEST_CHAIN_ID = 6;\n uint256 private constant OFFSET_ORIGIN_SENDER = 10;\n uint256 private constant OFFSET_DEST_RECIPIENT = 30;\n uint256 private constant OFFSET_ORIGIN_TOKEN = 50;\n uint256 private constant OFFSET_DEST_TOKEN = 70;\n uint256 private constant OFFSET_ORIGIN_AMOUNT = 90;\n uint256 private constant OFFSET_DEST_AMOUNT = 122;\n uint256 private constant OFFSET_ORIGIN_FEE_AMOUNT = 154;\n uint256 private constant OFFSET_DEADLINE = 186;\n uint256 private constant OFFSET_NONCE = 218;\n uint256 private constant OFFSET_EXCLUSIVITY_RELAYER = 250;\n uint256 private constant OFFSET_EXCLUSIVITY_END_TIME = 270;\n uint256 private constant OFFSET_ZAP_NATIVE = 302;\n uint256 private constant OFFSET_ZAP_DATA = 334;\n // forgefmt: disable-end\n\n error BridgeTransactionV2__InvalidEncodedTx();\n error BridgeTransactionV2__UnsupportedVersion(uint16 version);\n\n /// @notice Validates that the encoded transaction is a tightly packed encoded payload for BridgeTransactionV2.\n /// @dev Checks the minimum length and the version, use this function before decoding any of the fields.\n function validateV2(bytes calldata encodedTx) internal pure {\n // Check the minimum length: must at least include all static fields.\n if (encodedTx.length \u003c OFFSET_ZAP_DATA) revert BridgeTransactionV2__InvalidEncodedTx();\n // Once we validated the length, we can be sure that the version field is present.\n uint16 version_ = version(encodedTx);\n if (version_ != VERSION) revert BridgeTransactionV2__UnsupportedVersion(version_);\n }\n\n /// @notice Encodes the BridgeTransactionV2 struct by tightly packing the fields.\n /// @dev `abi.decode` will not work as a result of the tightly packed fields. Use `decodeV2` to decode instead.\n function encodeV2(IFastBridgeV2.BridgeTransactionV2 memory bridgeTx) internal pure returns (bytes memory) {\n // We split the encoding into two parts to avoid stack-too-deep error\n bytes memory firstPart = abi.encodePacked(\n VERSION,\n bridgeTx.originChainId,\n bridgeTx.destChainId,\n bridgeTx.originSender,\n bridgeTx.destRecipient,\n bridgeTx.originToken,\n bridgeTx.destToken,\n bridgeTx.originAmount\n );\n return abi.encodePacked(\n firstPart,\n bridgeTx.destAmount,\n bridgeTx.originFeeAmount,\n // Note: we skip the deprecated `sendChainGas` flag, which was present in BridgeTransaction V1\n bridgeTx.deadline,\n bridgeTx.nonce,\n // New V2 fields: exclusivity\n bridgeTx.exclusivityRelayer,\n bridgeTx.exclusivityEndTime,\n // New V2 fields: Zap\n bridgeTx.zapNative,\n bridgeTx.zapData\n );\n }\n\n /// @notice Decodes the BridgeTransactionV2 struct from the encoded transaction.\n /// @dev Encoded BridgeTransactionV2 struct must be tightly packed.\n /// Use `validateV2` before decoding to ensure the encoded transaction is valid.\n function decodeV2(bytes calldata encodedTx)\n internal\n pure\n returns (IFastBridgeV2.BridgeTransactionV2 memory bridgeTx)\n {\n bridgeTx.originChainId = originChainId(encodedTx);\n bridgeTx.destChainId = destChainId(encodedTx);\n bridgeTx.originSender = originSender(encodedTx);\n bridgeTx.destRecipient = destRecipient(encodedTx);\n bridgeTx.originToken = originToken(encodedTx);\n bridgeTx.destToken = destToken(encodedTx);\n bridgeTx.originAmount = originAmount(encodedTx);\n bridgeTx.destAmount = destAmount(encodedTx);\n bridgeTx.originFeeAmount = originFeeAmount(encodedTx);\n bridgeTx.deadline = deadline(encodedTx);\n bridgeTx.nonce = nonce(encodedTx);\n bridgeTx.exclusivityRelayer = exclusivityRelayer(encodedTx);\n bridgeTx.exclusivityEndTime = exclusivityEndTime(encodedTx);\n bridgeTx.zapNative = zapNative(encodedTx);\n bridgeTx.zapData = zapData(encodedTx);\n }\n\n /// @notice Extracts the version from the encoded transaction.\n function version(bytes calldata encodedTx) internal pure returns (uint16 version_) {\n // Load 32 bytes from the start and shift it 240 bits to the right to get the highest 16 bits.\n assembly {\n version_ := shr(240, calldataload(encodedTx.offset))\n }\n }\n\n /// @notice Extracts the origin chain ID from the encoded transaction.\n function originChainId(bytes calldata encodedTx) internal pure returns (uint32 originChainId_) {\n // Load 32 bytes from the offset and shift it 224 bits to the right to get the highest 32 bits.\n assembly {\n originChainId_ := shr(224, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_CHAIN_ID)))\n }\n }\n\n /// @notice Extracts the destination chain ID from the encoded transaction.\n function destChainId(bytes calldata encodedTx) internal pure returns (uint32 destChainId_) {\n // Load 32 bytes from the offset and shift it 224 bits to the right to get the highest 32 bits.\n assembly {\n destChainId_ := shr(224, calldataload(add(encodedTx.offset, OFFSET_DEST_CHAIN_ID)))\n }\n }\n\n /// @notice Extracts the origin sender from the encoded transaction.\n function originSender(bytes calldata encodedTx) internal pure returns (address originSender_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n originSender_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_SENDER)))\n }\n }\n\n /// @notice Extracts the destination recipient from the encoded transaction.\n function destRecipient(bytes calldata encodedTx) internal pure returns (address destRecipient_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n destRecipient_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_DEST_RECIPIENT)))\n }\n }\n\n /// @notice Extracts the origin token from the encoded transaction.\n function originToken(bytes calldata encodedTx) internal pure returns (address originToken_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n originToken_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_TOKEN)))\n }\n }\n\n /// @notice Extracts the destination token from the encoded transaction.\n function destToken(bytes calldata encodedTx) internal pure returns (address destToken_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n destToken_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_DEST_TOKEN)))\n }\n }\n\n /// @notice Extracts the origin amount from the encoded transaction.\n function originAmount(bytes calldata encodedTx) internal pure returns (uint256 originAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n originAmount_ := calldataload(add(encodedTx.offset, OFFSET_ORIGIN_AMOUNT))\n }\n }\n\n /// @notice Extracts the destination amount from the encoded transaction.\n function destAmount(bytes calldata encodedTx) internal pure returns (uint256 destAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n destAmount_ := calldataload(add(encodedTx.offset, OFFSET_DEST_AMOUNT))\n }\n }\n\n /// @notice Extracts the origin fee amount from the encoded transaction.\n function originFeeAmount(bytes calldata encodedTx) internal pure returns (uint256 originFeeAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n originFeeAmount_ := calldataload(add(encodedTx.offset, OFFSET_ORIGIN_FEE_AMOUNT))\n }\n }\n\n /// @notice Extracts the deadline from the encoded transaction.\n function deadline(bytes calldata encodedTx) internal pure returns (uint256 deadline_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n deadline_ := calldataload(add(encodedTx.offset, OFFSET_DEADLINE))\n }\n }\n\n /// @notice Extracts the nonce from the encoded transaction.\n function nonce(bytes calldata encodedTx) internal pure returns (uint256 nonce_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n nonce_ := calldataload(add(encodedTx.offset, OFFSET_NONCE))\n }\n }\n\n /// @notice Extracts the exclusivity relayer from the encoded transaction.\n function exclusivityRelayer(bytes calldata encodedTx) internal pure returns (address exclusivityRelayer_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n exclusivityRelayer_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_EXCLUSIVITY_RELAYER)))\n }\n }\n\n /// @notice Extracts the exclusivity end time from the encoded transaction.\n function exclusivityEndTime(bytes calldata encodedTx) internal pure returns (uint256 exclusivityEndTime_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n exclusivityEndTime_ := calldataload(add(encodedTx.offset, OFFSET_EXCLUSIVITY_END_TIME))\n }\n }\n\n /// @notice Extracts the Zap's native value from the encoded transaction.\n function zapNative(bytes calldata encodedTx) internal pure returns (uint256 zapNative_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n zapNative_ := calldataload(add(encodedTx.offset, OFFSET_ZAP_NATIVE))\n }\n }\n\n /// @notice Extracts the Zap's data from the encoded transaction.\n function zapData(bytes calldata encodedTx) internal pure returns (bytes calldata zapData_) {\n zapData_ = encodedTx[OFFSET_ZAP_DATA:];\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/AdminV2.sol\n\n// ════════════════════════════════════════════════ INTERFACES ═════════════════════════════════════════════════════\n\n// ═════════════════════════════════════════════ EXTERNAL IMPORTS ══════════════════════════════════════════════════\n\n/// @title AdminV2\n/// @notice Provides administrative functions and controls for managing the FastBridgeV2 contract,\n/// including access control and configuration settings.\ncontract AdminV2 is AccessControlEnumerable, IAdminV2, IAdminV2Errors {\n using SafeERC20 for IERC20;\n\n /// @notice The address reserved for the native gas token (ETH on Ethereum and most L2s, AVAX on Avalanche, etc.).\n address public constant NATIVE_GAS_TOKEN = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice The role identifier for the Quoter API's off-chain authentication.\n /// @dev Only addresses with this role can post FastBridge quotes to the API.\n bytes32 public constant QUOTER_ROLE = keccak256(\"QUOTER_ROLE\");\n\n /// @notice The role identifier for the Prover's on-chain authentication in FastBridge.\n /// @dev Only addresses with this role can provide proofs that a FastBridge request has been relayed.\n bytes32 public constant PROVER_ROLE = keccak256(\"PROVER_ROLE\");\n\n /// @notice The role identifier for the Guard's on-chain authentication in FastBridge.\n /// @dev Only addresses with this role can dispute submitted relay proofs during the dispute period.\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n\n /// @notice The role identifier for the Canceler's on-chain authentication in FastBridge.\n /// @dev Only addresses with this role can cancel a FastBridge transaction without the cancel delay.\n bytes32 public constant CANCELER_ROLE = keccak256(\"CANCELER_ROLE\");\n\n /// @notice The role identifier for the Governor's on-chain administrative authority.\n /// @dev Only addresses with this role can perform administrative tasks within the contract.\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n /// @notice The denominator for fee rates, representing 100%.\n uint256 public constant FEE_BPS = 1e6;\n /// @notice The maximum protocol fee rate: 1% of the origin amount.\n uint256 public constant FEE_RATE_MAX = 0.01e6;\n\n /// @notice The minimum cancel delay that can be set by the governor.\n uint256 public constant MIN_CANCEL_DELAY = 1 hours;\n /// @notice The default cancel delay set during contract deployment.\n uint256 public constant DEFAULT_CANCEL_DELAY = 1 days;\n\n /// @notice The protocol fee rate taken on the origin amount deposited in the origin chain.\n uint256 public protocolFeeRate;\n\n /// @notice The accumulated protocol fee amounts.\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice The delay period after which a transaction can be permissionlessly cancelled.\n uint256 public cancelDelay;\n\n /// @notice This variable is deprecated and should not be used.\n /// @dev Use ZapNative V2 requests instead.\n uint256 public immutable chainGasAmount = 0;\n\n constructor(address defaultAdmin) {\n _grantRole(DEFAULT_ADMIN_ROLE, defaultAdmin);\n _setCancelDelay(DEFAULT_CANCEL_DELAY);\n }\n\n /// @inheritdoc IAdminV2\n function setCancelDelay(uint256 newCancelDelay) external onlyRole(GOVERNOR_ROLE) {\n _setCancelDelay(newCancelDelay);\n }\n\n /// @inheritdoc IAdminV2\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n if (newFeeRate \u003e FEE_RATE_MAX) revert FeeRateAboveMax();\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n /// @inheritdoc IAdminV2\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n // Early exit if no accumulated fees.\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return;\n // Reset the accumulated fees first.\n protocolFees[token] = 0;\n emit FeesSwept(token, recipient, feeAmount);\n // Sweep the fees as the last transaction action.\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(recipient), feeAmount);\n } else {\n IERC20(token).safeTransfer(recipient, feeAmount);\n }\n }\n\n /// @notice Internal logic to set the cancel delay. Security checks are performed outside of this function.\n /// @dev This function is marked as private to prevent child contracts from calling it directly.\n function _setCancelDelay(uint256 newCancelDelay) private {\n if (newCancelDelay \u003c MIN_CANCEL_DELAY) revert CancelDelayBelowMin();\n uint256 oldCancelDelay = cancelDelay;\n cancelDelay = newCancelDelay;\n emit CancelDelayUpdated(oldCancelDelay, newCancelDelay);\n }\n}\n\n// contracts/FastBridgeV2.sol\n\n// ════════════════════════════════════════════════ INTERFACES ═════════════════════════════════════════════════════\n\n// ═════════════════════════════════════════════ INTERNAL IMPORTS ══════════════════════════════════════════════════\n\n// ═════════════════════════════════════════════ EXTERNAL IMPORTS ══════════════════════════════════════════════════\n\n/// @title FastBridgeV2\n/// @notice Core component of the SynapseRFQ protocol, enabling Relayers (Solvers) to fulfill bridge requests.\n/// Supports ERC20 and native gas tokens, along with the Zap feature for executing actions on the destination chain.\n/// Users interact with the off-chain Quoter API to obtain a current quote for a bridge transaction.\n/// They then submit the bridge request with the quote to this contract, depositing their assets in escrow.\n/// Relayers can fulfill requests by relaying them to the destination chain and must prove fulfillment to claim funds.\n/// Guards monitor proofs and can dispute discrepancies.\n/// Users can reclaim funds by cancelling their requests if it has not been fulfilled within the specified deadline.\ncontract FastBridgeV2 is AdminV2, MulticallTarget, IFastBridgeV2, IFastBridgeV2Errors {\n using BridgeTransactionV2Lib for bytes;\n using SafeERC20 for IERC20;\n\n /// @notice The duration of the dispute period for relayed transactions.\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice The minimum required time between transaction request and deadline.\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n /// @notice The maximum allowed length for zapData.\n uint256 public constant MAX_ZAP_DATA_LENGTH = 2 ** 16 - 1;\n\n /// @notice Maps transaction IDs to bridge details (status, destination chain ID, proof timestamp, and relayer).\n /// Note: this is only stored for transactions having local chain as the origin chain.\n mapping(bytes32 =\u003e BridgeTxDetails) public bridgeTxDetails;\n /// @notice Maps transaction IDs to relay details (block number, block timestamp, and relayer).\n /// Note: this is only stored for transactions having local chain as the destination chain.\n mapping(bytes32 =\u003e BridgeRelay) public bridgeRelayDetails;\n /// @notice Maps sender addresses to their unique bridge nonce.\n mapping(address =\u003e uint256) public senderNonces;\n\n /// @notice This variable is deprecated and should not be used.\n /// @dev Replaced by senderNonces.\n uint256 public immutable nonce = 0;\n /// @notice The block number at which this contract was deployed.\n uint256 public immutable deployBlock;\n\n /// @notice Initializes the FastBridgeV2 contract with the provided default admin,\n /// sets the default cancel delay, and records the deploy block number.\n constructor(address defaultAdmin) AdminV2(defaultAdmin) {\n deployBlock = block.number;\n }\n\n // ══════════════════════════════════════ EXTERNAL MUTABLE (USER FACING) ═══════════════════════════════════════════\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n bridgeV2({\n params: params,\n paramsV2: BridgeParamsV2({\n quoteRelayer: address(0),\n quoteExclusivitySeconds: 0,\n quoteId: bytes(\"\"),\n zapNative: 0,\n zapData: bytes(\"\")\n })\n });\n }\n\n /// Note: this function is deprecated and will be removed in a future version.\n /// @dev Replaced by `cancel`.\n /// @inheritdoc IFastBridge\n function refund(bytes calldata request) external {\n cancelV2(request);\n }\n\n // ══════════════════════════════════════ EXTERNAL MUTABLE (AGENT FACING) ══════════════════════════════════════════\n\n /// @inheritdoc IFastBridge\n function relay(bytes calldata request) external payable {\n // `relay` override will validate the request.\n relayV2({request: request, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes calldata request, bytes32 destTxHash) external {\n request.validateV2();\n proveV2({transactionId: keccak256(request), destTxHash: destTxHash, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridgeV2\n function claimV2(bytes calldata request) external {\n // `claim` override will validate the request.\n claim({request: request, to: address(0)});\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n // Aggregate the read operations from the same storage slot.\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n address disputedRelayer = $.proofRelayer;\n BridgeStatus status = $.status;\n uint56 proofBlockTimestamp = $.proofBlockTimestamp;\n\n // Can only dispute a RELAYER_PROVED transaction within the dispute period.\n if (status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(proofBlockTimestamp) \u003e DISPUTE_PERIOD) {\n revert DisputePeriodPassed();\n }\n\n // Update status to REQUESTED and delete the disputed proof details.\n // Note: these are storage writes.\n $.status = BridgeStatus.REQUESTED;\n $.proofRelayer = address(0);\n $.proofBlockTimestamp = 0;\n\n emit BridgeProofDisputed(transactionId, disputedRelayer);\n }\n\n // ══════════════════════════════════════════════ EXTERNAL VIEWS ═══════════════════════════════════════════════════\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n // The correct relayer can only claim a RELAYER_PROVED transaction after the dispute period.\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n if ($.status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if ($.proofRelayer != relayer) revert SenderIncorrect();\n\n return _timeSince($.proofBlockTimestamp) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n /// @dev This method is added to achieve backwards compatibility with decoding requests into V1 structs:\n /// - `zapNative` is partially reported as a zero/non-zero flag\n /// - `zapData` is ignored\n /// In order to process all kinds of requests use getBridgeTransactionV2 instead.\n function getBridgeTransaction(bytes calldata request) external view returns (BridgeTransaction memory) {\n // Try decoding into V2 struct first. This will revert if V1 struct is passed.\n try this.getBridgeTransactionV2(request) returns (BridgeTransactionV2 memory txV2) {\n // Note: we entirely ignore the zapData field, as it was not present in V1.\n return BridgeTransaction({\n originChainId: txV2.originChainId,\n destChainId: txV2.destChainId,\n originSender: txV2.originSender,\n destRecipient: txV2.destRecipient,\n originToken: txV2.originToken,\n destToken: txV2.destToken,\n originAmount: txV2.originAmount,\n destAmount: txV2.destAmount,\n originFeeAmount: txV2.originFeeAmount,\n sendChainGas: txV2.zapNative != 0,\n deadline: txV2.deadline,\n nonce: txV2.nonce\n });\n } catch {\n // Fallback to V1 struct.\n return abi.decode(request, (BridgeTransaction));\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function getBridgeTransactionV2(bytes calldata request) external pure returns (BridgeTransactionV2 memory) {\n request.validateV2();\n return BridgeTransactionV2Lib.decodeV2(request);\n }\n\n // ═══════════════════════════════════════ PUBLIC MUTABLE (USER FACING) ════════════════════════════════════════════\n\n /// @inheritdoc IFastBridgeV2\n function bridgeV2(BridgeParams memory params, BridgeParamsV2 memory paramsV2) public payable {\n // If relayer exclusivity is not intended for this bridge, set exclusivityEndTime to static zero.\n // Otherwise, set exclusivity to expire at the current block ts offset by quoteExclusivitySeconds.\n int256 exclusivityEndTime = 0;\n if (paramsV2.quoteRelayer != address(0)) {\n exclusivityEndTime = int256(block.timestamp) + paramsV2.quoteExclusivitySeconds;\n }\n _validateBridgeParams(params, paramsV2, exclusivityEndTime);\n\n // Transfer tokens to bridge contract. We use the actual transferred amount in case of transfer fees.\n uint256 originAmount = _takeBridgedUserAsset(params.originToken, params.originAmount);\n\n // Track the amount of origin token owed to protocol.\n uint256 originFeeAmount = 0;\n if (protocolFeeRate \u003e 0) {\n originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n // The Relayer filling this request will be paid the originAmount after fees.\n // Note: the protocol fees will be accumulated only when the Relayer claims the origin collateral.\n originAmount -= originFeeAmount;\n }\n\n // Hash the bridge request and set the initial status to REQUESTED.\n bytes memory request = BridgeTransactionV2Lib.encodeV2(\n BridgeTransactionV2({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n deadline: params.deadline,\n // Increment the sender's nonce on every bridge.\n nonce: senderNonces[params.sender]++,\n exclusivityRelayer: paramsV2.quoteRelayer,\n // We checked exclusivityEndTime to be in range [0 .. params.deadline] above, so can safely cast.\n exclusivityEndTime: uint256(exclusivityEndTime),\n zapNative: paramsV2.zapNative,\n zapData: paramsV2.zapData\n })\n );\n bytes32 transactionId = keccak256(request);\n // Note: the tx status will be updated throughout the tx lifecycle, while destChainId is set once here.\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n bridgeTxDetails[transactionId].destChainId = params.dstChainId;\n\n emit BridgeRequested({\n transactionId: transactionId,\n sender: params.sender,\n request: request,\n destChainId: params.dstChainId,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n sendChainGas: paramsV2.zapNative != 0\n });\n emit BridgeQuoteDetails(transactionId, paramsV2.quoteId);\n }\n\n /// @inheritdoc IFastBridgeV2\n function cancelV2(bytes calldata request) public {\n // Decode the request and check that it could be cancelled.\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n\n // Can only cancel a REQUESTED transaction after its deadline expires.\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n if ($.status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n\n // Permissionless cancel is only allowed after `cancelDelay` on top of the deadline.\n uint256 deadline = request.deadline();\n if (!hasRole(CANCELER_ROLE, msg.sender)) deadline += cancelDelay;\n if (block.timestamp \u003c= deadline) revert DeadlineNotExceeded();\n\n // Update status to REFUNDED.\n // Note: this is a storage write.\n $.status = BridgeStatus.REFUNDED;\n\n // Return the full amount (collateral + protocol fees) to the original sender.\n // The protocol fees are only accumulated when the transaction is claimed, so we don't need to update them here.\n address to = request.originSender();\n address token = request.originToken();\n uint256 amount = request.originAmount() + request.originFeeAmount();\n\n // Emit the event before any external calls.\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n\n // Return the funds to the original sender as last transaction action.\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(to), amount);\n } else {\n IERC20(token).safeTransfer(to, amount);\n }\n }\n\n // ═══════════════════════════════════════ PUBLIC MUTABLE (AGENT FACING) ═══════════════════════════════════════════\n\n /// @inheritdoc IFastBridgeV2\n function relayV2(bytes calldata request, address relayer) public payable {\n // Decode the request and check that it could be relayed.\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n _validateRelayParams(request, transactionId, relayer);\n\n // Mark the bridge request as relayed by saving the relayer and the block details.\n bridgeRelayDetails[transactionId].blockNumber = uint48(block.number);\n bridgeRelayDetails[transactionId].blockTimestamp = uint48(block.timestamp);\n bridgeRelayDetails[transactionId].relayer = relayer;\n\n // Transfer tokens to recipient on destination chain and trigger Zap if requested.\n address to = request.destRecipient();\n address token = request.destToken();\n uint256 amount = request.destAmount();\n uint256 zapNative = request.zapNative();\n\n // Emit the event before any external calls.\n emit BridgeRelayed({\n transactionId: transactionId,\n relayer: relayer,\n to: to,\n originChainId: request.originChainId(),\n originToken: request.originToken(),\n destToken: token,\n originAmount: request.originAmount(),\n destAmount: amount,\n chainGasAmount: zapNative\n });\n\n // All state changes have been done at this point, can proceed to the external calls.\n // This follows the checks-effects-interactions pattern to mitigate potential reentrancy attacks.\n if (token == NATIVE_GAS_TOKEN) {\n // For the native gas token, additional zapNative is not allowed.\n if (zapNative != 0) revert ZapNativeNotSupported();\n // Check that the correct msg.value was sent.\n if (msg.value != amount) revert MsgValueIncorrect();\n // Don't do a native transfer yet: we will handle it alongside the Zap below.\n } else {\n // For ERC20s, we check that the correct msg.value was sent.\n if (msg.value != zapNative) revert MsgValueIncorrect();\n // We need to transfer the tokens from the Relayer to the recipient first before performing an\n // optional post-transfer Zap.\n IERC20(token).safeTransferFrom(msg.sender, to, amount);\n }\n // At this point we have done:\n // - Transferred the requested amount of ERC20 tokens to the recipient.\n // At this point we have confirmed:\n // - For ERC20s: msg.value matches the requested zapNative amount.\n // - For the native gas token: msg.value matches the requested destAmount.\n // Remaining optional things to do:\n // - Forward the full msg.value to the recipient (if non-zero).\n // - Trigger a Zap (if zapData is present).\n bytes calldata zapData = request.zapData();\n if (zapData.length != 0) {\n // Zap Data is present: Zap has been requested by the recipient. Trigger it forwarding the full msg.value.\n _triggerZapWithChecks({recipient: to, token: token, amount: amount, zapData: zapData});\n // Note: if token has a fee on transfers, the recipient will have received less than `amount`.\n // This is a very niche edge case and should be handled by the recipient contract.\n } else if (msg.value != 0) {\n // Zap Data is missing, but msg.value was sent. This could happen in two different cases:\n // - Relay with the native gas token is happening.\n // - Relay with ERC20 is happening, with a `zapNative \u003e 0` request.\n // In both cases, we need to transfer the full msg.value to the recipient.\n Address.sendValue(payable(to), msg.value);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function proveV2(bytes32 transactionId, bytes32 destTxHash, address relayer) public onlyRole(PROVER_ROLE) {\n // Can only prove a REQUESTED transaction.\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n if ($.status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n\n // Update status to RELAYER_PROVED and store the proof details.\n // Note: these are storage writes.\n $.status = BridgeStatus.RELAYER_PROVED;\n $.proofBlockTimestamp = uint56(block.timestamp);\n $.proofRelayer = relayer;\n\n emit BridgeProofProvided(transactionId, relayer, destTxHash);\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes calldata request, address to) public {\n // Decode the request and check that it could be claimed.\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n\n // Aggregate the read operations from the same storage slot.\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n address proofRelayer = $.proofRelayer;\n BridgeStatus status = $.status;\n uint56 proofBlockTimestamp = $.proofBlockTimestamp;\n\n // Can only claim a RELAYER_PROVED transaction after the dispute period.\n if (status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(proofBlockTimestamp) \u003c= DISPUTE_PERIOD) revert DisputePeriodNotPassed();\n if (to == address(0)) {\n // Anyone could claim the funds to the proven relayer on their behalf.\n to = proofRelayer;\n } else if (proofRelayer != msg.sender) {\n // Only the proven relayer could specify an address to claim the funds to.\n revert SenderIncorrect();\n }\n\n // Update status to RELAYER_CLAIMED and transfer the origin collateral to the specified claim address.\n // Note: this is a storage write.\n $.status = BridgeStatus.RELAYER_CLAIMED;\n\n // Accumulate protocol fees if origin fee amount exists.\n address token = request.originToken();\n uint256 amount = request.originAmount();\n uint256 originFeeAmount = request.originFeeAmount();\n if (originFeeAmount \u003e 0) protocolFees[token] += originFeeAmount;\n\n // Emit the event before any external calls.\n emit BridgeDepositClaimed(transactionId, proofRelayer, to, token, amount);\n\n // Complete the relayer claim as the last transaction action.\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(to), amount);\n } else {\n IERC20(token).safeTransfer(to, amount);\n }\n }\n\n // ═══════════════════════════════════════════════ PUBLIC VIEWS ════════════════════════════════════════════════════\n\n /// @inheritdoc IFastBridgeV2\n function bridgeStatuses(bytes32 transactionId) public view returns (BridgeStatus status) {\n return bridgeTxDetails[transactionId].status;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeProofs(bytes32 transactionId) public view returns (uint96 timestamp, address relayer) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n timestamp = $.proofBlockTimestamp;\n relayer = $.proofRelayer;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeRelays(bytes32 transactionId) public view returns (bool) {\n // This transaction has been relayed if the relayer address is recorded.\n return bridgeRelayDetails[transactionId].relayer != address(0);\n }\n\n // ═════════════════════════════════════════════ INTERNAL METHODS ══════════════════════════════════════════════════\n\n /// @notice Takes the bridged asset from the user into FastBridgeV2 custody. The asset will later be\n /// claimed by the relayer who completed the relay on the destination chain, or returned to the user\n /// via the cancel function if no relay is completed.\n function _takeBridgedUserAsset(address token, uint256 amount) internal returns (uint256 amountTaken) {\n if (token == NATIVE_GAS_TOKEN) {\n // For the native gas token, we just need to check that the supplied msg.value is correct.\n // Supplied `msg.value` is already in FastBridgeV2 custody.\n if (amount != msg.value) revert MsgValueIncorrect();\n amountTaken = msg.value;\n } else {\n // For ERC20s, token is explicitly transferred from the user to FastBridgeV2.\n // We don't allow non-zero `msg.value` to avoid extra funds from being stuck in FastBridgeV2.\n if (msg.value != 0) revert MsgValueIncorrect();\n // Throw an explicit error if the provided token address is not a contract.\n if (token.code.length == 0) revert TokenNotContract();\n\n // Use the balance difference as the amount taken in case of fee on transfer tokens.\n amountTaken = IERC20(token).balanceOf(address(this));\n IERC20(token).safeTransferFrom(msg.sender, address(this), amount);\n amountTaken = IERC20(token).balanceOf(address(this)) - amountTaken;\n }\n }\n\n /// @notice Calls the recipient's hook function with the specified zapData and validates\n /// the returned value.\n function _triggerZapWithChecks(address recipient, address token, uint256 amount, bytes calldata zapData) internal {\n // Call the recipient's hook function with the specified zapData, bubbling any revert messages.\n bytes memory returnData = Address.functionCallWithValue({\n target: recipient,\n data: abi.encodeCall(IZapRecipient.zap, (token, amount, zapData)),\n // Note: see `relay()` for reasoning behind passing msg.value.\n value: msg.value\n });\n\n // Explicit revert if no return data at all.\n if (returnData.length == 0) revert RecipientNoReturnValue();\n // Check that exactly a single return value was returned.\n if (returnData.length != 32) revert RecipientIncorrectReturnValue();\n // Return value should be abi-encoded hook function selector.\n if (bytes32(returnData) != bytes32(IZapRecipient.zap.selector)) {\n revert RecipientIncorrectReturnValue();\n }\n }\n\n /// @notice Calculates the time elapsed since a proof was submitted.\n /// @dev The proof.timestamp stores block timestamps as uint56 for gas optimization.\n /// _timeSince(proof) handles timestamp rollover when block.timestamp \u003e type(uint56).max but\n /// proof.timestamp \u003c type(uint56).max via an unchecked statement.\n /// @param proofBlockTimestamp The block timestamp when the proof was submitted.\n /// @return delta The time elapsed since proof submission.\n function _timeSince(uint56 proofBlockTimestamp) internal view returns (uint256 delta) {\n unchecked {\n delta = uint56(block.timestamp) - proofBlockTimestamp;\n }\n }\n\n /// @notice Validates all parameters required for a bridge transaction.\n /// @dev This function's complexity cannot be reduced due to the number of required checks,\n /// so we disable the code-complexity rule.\n // solhint-disable-next-line code-complexity\n function _validateBridgeParams(\n BridgeParams memory params,\n BridgeParamsV2 memory paramsV2,\n int256 exclusivityEndTime\n )\n internal\n view\n {\n // Check V1 (legacy) params.\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.sender == address(0) || params.to == address(0)) revert ZeroAddress();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n\n // Check V2 params.\n if (paramsV2.zapData.length \u003e MAX_ZAP_DATA_LENGTH) revert ZapDataLengthAboveMax();\n if (paramsV2.zapNative != 0 \u0026\u0026 params.destToken == NATIVE_GAS_TOKEN) {\n revert ZapNativeNotSupported();\n }\n\n // exclusivityEndTime must be in range [0 .. params.deadline].\n if (exclusivityEndTime \u003c 0 || exclusivityEndTime \u003e int256(params.deadline)) {\n revert ExclusivityParamsIncorrect();\n }\n }\n\n /// @notice Validates all parameters required for a relay transaction.\n function _validateRelayParams(bytes calldata request, bytes32 transactionId, address relayer) internal view {\n if (relayer == address(0)) revert ZeroAddress();\n // Check that the transaction has not been relayed yet and is for the current chain.\n if (bridgeRelays(transactionId)) revert TransactionRelayed();\n if (request.destChainId() != block.chainid) revert ChainIncorrect();\n // Check that the deadline for relay to happen has not passed yet.\n if (block.timestamp \u003e request.deadline()) revert DeadlineExceeded();\n // Check the exclusivity period, if it was specified and is still ongoing.\n address exclRelayer = request.exclusivityRelayer();\n if (exclRelayer != address(0) \u0026\u0026 exclRelayer != relayer \u0026\u0026 block.timestamp \u003c= request.exclusivityEndTime()) {\n revert ExclusivityPeriodNotPassed();\n }\n }\n}\n","language":"Solidity","languageVersion":"0.8.24","compilerVersion":"0.8.24","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"78465:4436:0:-:0;;;81103:1;81061:43;;81111:142;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;81155:44;70288:4;81186:12;81155:10;:44::i;:::-;-1:-1:-1;81209:37:0;80564:6;81209:15;:37::i;:::-;81111:142;78465:4436;;77010:257;77096:4;;77127:31;77144:4;77150:7;77127:16;:31::i;:::-;77112:46;;77172:7;77168:69;;;77195:18;;;;:12;:18;;;;;:31;;77218:7;77195:22;:31::i;:::-;;77168:69;77253:7;-1:-1:-1;77010:257:0;;;;;:::o;82609:290::-;80431:7;82680:14;:33;82676:67;;;82722:21;;-1:-1:-1;;;82722:21:0;;;;;;;;;;;82676:67;82778:11;;;82799:28;;;;82842:50;;;483:25:1;;;539:2;524:18;;517:34;;;82842:50:0;;456:18:1;82842:50:0;;;;;;;82666:233;82609:290;:::o;74235:316::-;74312:4;71010:12;;;;;;;;;;;-1:-1:-1;;;;;71010:29:0;;;;;;;;;;;;74328:217;;74371:6;:12;;;;;;;;;;;-1:-1:-1;;;;;74371:29:0;;;;;;;;;:36;;-1:-1:-1;;74371:36:0;74403:4;74371:36;;;74453:12;26158:10;;26079:96;74453:12;-1:-1:-1;;;;;74426:40:0;74444:7;-1:-1:-1;;;;;74426:40:0;74438:4;74426:40;;;;;;;;;;-1:-1:-1;74487:4:0;74480:11;;74328:217;-1:-1:-1;74529:5:0;74522:12;;35603:150;35673:4;35696:50;35701:3;-1:-1:-1;;;;;35721:23:0;;29591:4;31647:21;;;:14;;;:21;;;;;;29607:321;;-1:-1:-1;29649:23:0;;;;;;;;:11;:23;;;;;;;;;;;;;29831:18;;29807:21;;;:14;;;:21;;;;;;:42;;;;29863:11;;14:290:1;84:6;137:2;125:9;116:7;112:23;108:32;105:52;;;153:1;150;143:12;105:52;179:16;;-1:-1:-1;;;;;224:31:1;;214:42;;204:70;;270:1;267;260:12;309:248;78465:4436:0;;;;;;;;;;;;","srcMapRuntime":"78465:4436:0:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;75670:212;;;;;;:::i;:::-;;:::i;:::-;;;516:14:1;;509:22;491:41;;479:2;464:18;75670:212:0;;;;;;;;79748:66;;79788:26;79748:66;;;;;689:25:1;;;677:2;662:18;79748:66:0;543:177:1;79482:60:0;;79519:23;79482:60;;81777:613;;;;;;:::i;:::-;;:::i;:::-;;80262:45;;80301:6;80262:45;;78693:85;;78736:42;78693:85;;;;;1549:42:1;1537:55;;;1519:74;;1507:2;1492:18;78693:85:0;1373:226:1;81288:129:0;;;;;;:::i;:::-;;:::i;71866:120::-;;;;;;:::i;:::-;71931:7;71957:12;;;;;;;;;;:22;;;;71866:120;72282:136;;;;;;:::i;:::-;;:::i;73384:245::-;;;;;;:::i;:::-;;:::i;80673:30::-;;;;;;80912:26;;;;;;78950:62;;78988:24;78950:62;;76467:142;;;;;;:::i;:::-;;:::i;70910:136::-;;;;;;:::i;:::-;70987:4;71010:12;;;;;;;;;;;:29;;;;;;;;;;;;;;;;70910:136;80388:50;;80431:7;80388:50;;80517:53;;80564:6;80517:53;;70243:49;;70288:4;70243:49;;81452:290;;;;;;:::i;:::-;;:::i;80147:37::-;;80181:3;80147:37;;76777:131;;;;;;:::i;:::-;;:::i;80008:66::-;;80048:26;80008:66;;72698:138;;;;;;:::i;:::-;;:::i;79217:62::-;;79255:24;79217:62;;80764:47;;;;;;:::i;:::-;;;;;;;;;;;;;;81061:43;;;;;75670:212;75755:4;75778:57;;;75793:42;75778:57;;:97;;;75839:36;75863:11;75839:23;:36::i;:::-;75771:104;75670:212;-1:-1:-1;;75670:212:0:o;81777:613::-;80048:26;70520:16;70531:4;70520:10;:16::i;:::-;81947:19:::1;::::0;::::1;81927:17;81947:19:::0;;;:12:::1;:19;::::0;;;;;;81980:14;;;81976:27:::1;;81996:7;81777:613:::0;;;:::o;81976:27::-:1;82057:19;::::0;;::::1;82079:1;82057:19:::0;;;:12:::1;:19;::::0;;;;;;;:23;;;;82095:38;;2940:34:1;;;3010:15;;;2990:18;;;2983:43;;;;3042:18;;;3035:34;;;82095:38:0::1;::::0;2867:2:1;2852:18;82095:38:0::1;;;;;;;82205:25:::0;::::1;::::0;::::1;::::0;82201:183:::1;;82246:48;82272:9;82284;82246:17;:48::i;:::-;82201:183;;;82325:48;:26;::::0;::::1;82352:9:::0;82363;82325:26:::1;:48::i;:::-;81871:519;70546:1;81777:613:::0;;;:::o;81288:129::-;80048:26;70520:16;70531:4;70520:10;:16::i;:::-;81379:31:::1;81395:14;81379:15;:31::i;:::-;81288:129:::0;;:::o;72282:136::-;71931:7;71957:12;;;;;;;;;;:22;;;70520:16;70531:4;70520:10;:16::i;:::-;72386:25:::1;72397:4;72403:7;72386:10;:25::i;73384:245::-:0;73477:34;;;26158:10;73477:34;73473:102;;73534:30;;;;;;;;;;;;;;73473:102;73585:37;73597:4;73603:18;73585:11;:37::i;76467:142::-;76548:7;76574:18;;;:12;:18;;;;;:28;;76596:5;76574:21;:28::i;:::-;76567:35;76467:142;-1:-1:-1;;;76467:142:0:o;81452:290::-;80048:26;70520:16;70531:4;70520:10;:16::i;:::-;80301:6:::1;81547:10;:25;81543:55;;;81581:17;;;;;;;;;;;;;;81543:55;81629:15;::::0;;81654:28;;;;81697:38:::1;::::0;;3254:25:1;;;3310:2;3295:18;;3288:34;;;81697:38:0::1;::::0;3227:18:1;81697:38:0::1;;;;;;;81533:209;81452:290:::0;;:::o;76777:131::-;76848:7;76874:18;;;:12;:18;;;;;:27;;:25;:27::i;72698:138::-;71931:7;71957:12;;;;;;;;;;:22;;;70520:16;70531:4;70520:10;:16::i;:::-;72803:26:::1;72815:4;72821:7;72803:11;:26::i;70621:202::-:0;70706:4;70729:47;;;70744:32;70729:47;;:87;;-1:-1:-1;50955:25:0;50940:40;;;;70780:36;50841:146;71255:103;71321:30;71332:4;26158:10;71321;:30::i;:::-;71255:103;:::o;20690:331::-;20799:6;20775:21;:30;20771:109;;;20828:41;;;;;20863:4;20828:41;;;1519:74:1;1492:18;;20828:41:0;;;;;;;;20771:109;20891:12;20909:9;:14;;20931:6;20909:33;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;20890:52;;;20957:7;20952:63;;20987:17;;;;;;;;;;;;;;63738:160;63847:43;;;63862:14;3735:55:1;;63847:43:0;;;3717:74:1;3807:18;;;;3800:34;;;63847:43:0;;;;;;;;;;3690:18:1;;;;63847:43:0;;;;;;;;;;;;;;63820:71;;63840:5;;63820:19;:71::i;82609:290::-;80431:7;82680:14;:33;82676:67;;;82722:21;;;;;;;;;;;;;;82676:67;82778:11;;;82799:28;;;;82842:50;;;3254:25:1;;;3310:2;3295:18;;3288:34;;;82842:50:0;;3227:18:1;82842:50:0;;;;;;;82666:233;82609:290;:::o;77010:257::-;77096:4;77112:12;77127:31;77144:4;77150:7;77127:16;:31::i;:::-;77112:46;;77172:7;77168:69;;;77195:18;;;;:12;:18;;;;;:31;;77218:7;77195:22;:31::i;:::-;;77253:7;77010:257;-1:-1:-1;;;77010:257:0:o;77370:262::-;77457:4;77473:12;77488:32;77506:4;77512:7;77488:17;:32::i;:::-;77473:47;;77534:7;77530:72;;;77557:18;;;;:12;:18;;;;;:34;;77583:7;77557:25;:34::i;36861:156::-;36935:7;36985:22;36989:3;37001:5;36985:3;:22::i;36404:115::-;36467:7;36493:19;36501:3;31843:18;;31761:107;71488:197;70987:4;71010:12;;;;;;;;;;;:29;;;;;;;;;;;;;71571:108;;71621:47;;;;;3747:42:1;3735:55;;71621:47:0;;;3717:74:1;3807:18;;;3800:34;;;3690:18;;71621:47:0;3543:297:1;66494:629:0;66913:23;66939:33;:27;;;66967:4;66939:27;:33::i;:::-;66913:59;;66986:10;:17;67007:1;66986:22;;:57;;;;;67024:10;67013:30;;;;;;;;;;;;:::i;:::-;67012:31;66986:57;66982:135;;;67066:40;;;;;1549:42:1;1537:55;;67066:40:0;;;1519:74:1;1492:18;;67066:40:0;1373:226:1;74235:316:0;74312:4;71010:12;;;;;;;;;;;:29;;;;;;;;;;;;;74328:217;;74371:6;:12;;;;;;;;;;;:29;;;;;;;;;;:36;;;;74403:4;74371:36;;;74453:12;26158:10;;26079:96;74453:12;74426:40;;74444:7;74426:40;;74438:4;74426:40;;;;;;;;;;-1:-1:-1;74487:4:0;74480:11;;74328:217;-1:-1:-1;74529:5:0;74522:12;;35603:150;35673:4;35696:50;35701:3;35721:23;;;35696:4;:50::i;74786:317::-;74864:4;71010:12;;;;;;;;;;;:29;;;;;;;;;;;;;74880:217;;;74954:5;74922:12;;;;;;;;;;;:29;;;;;;;;;;;:37;;;;;;74978:40;26158:10;;74922:12;;74978:40;;74954:5;74978:40;-1:-1:-1;75039:4:0;75032:11;;35921:156;35994:4;36017:53;36025:3;36045:23;;;36017:7;:53::i;32210:118::-;32277:7;32303:3;:11;;32315:5;32303:18;;;;;;;;:::i;:::-;;;;;;;;;32296:25;;32210:118;;;;:::o;21864:151::-;21939:12;21970:38;21992:6;22000:4;22006:1;21970:21;:38::i;29528:406::-;29591:4;31647:21;;;:14;;;:21;;;;;;29607:321;;-1:-1:-1;29649:23:0;;;;;;;;:11;:23;;;;;;;;;;;;;29831:18;;29807:21;;;:14;;;:21;;;;;;:42;;;;29863:11;;30102:1368;30168:4;30297:21;;;:14;;;:21;;;;;;30333:13;;30329:1135;;30700:18;30721:12;30732:1;30721:8;:12;:::i;:::-;30767:18;;30700:33;;-1:-1:-1;30747:17:0;;30767:22;;30788:1;;30767:22;:::i;:::-;30747:42;;30822:9;30808:10;:23;30804:378;;30851:17;30871:3;:11;;30883:9;30871:22;;;;;;;;:::i;:::-;;;;;;;;;30851:42;;31018:9;30992:3;:11;;31004:10;30992:23;;;;;;;;:::i;:::-;;;;;;;;;;;;:35;;;;31131:25;;;:14;;;:25;;;;;:36;;;30804:378;31260:17;;:3;;:17;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;31363:3;:14;;:21;31378:5;31363:21;;;;;;;;;;;31356:28;;;31406:4;31399:11;;;;;;;30329:1135;31448:5;31441:12;;;;;22339:392;22438:12;22490:5;22466:21;:29;22462:108;;;22518:41;;;;;22553:4;22518:41;;;1519:74:1;1492:18;;22518:41:0;1373:226:1;22462:108:0;22580:12;22594:23;22621:6;:11;;22640:5;22647:4;22621:31;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;22579:73;;;;22669:55;22696:6;22704:7;22713:10;22669:26;:55::i;:::-;22662:62;22339:392;-1:-1:-1;;;;;;22339:392:0:o;23784:582::-;23928:12;23957:7;23952:408;;23980:19;23988:10;23980:7;:19::i;:::-;23952:408;;;24204:17;;:22;:49;;;;-1:-1:-1;24230:18:0;;;;:23;24204:49;24200:119;;;24280:24;;;;;1549:42:1;1537:55;;24280:24:0;;;1519:74:1;1492:18;;24280:24:0;1373:226:1;24200:119:0;-1:-1:-1;24339:10:0;24332:17;;24902:516;25033:17;;:21;25029:383;;25261:10;25255:17;25317:15;25304:10;25300:2;25296:19;25289:44;25029:383;25384:17;;;;;;;;;;;;;;14:332:1;72:6;125:2;113:9;104:7;100:23;96:32;93:52;;;141:1;138;131:12;93:52;180:9;167:23;230:66;223:5;219:78;212:5;209:89;199:117;;312:1;309;302:12;725:196;793:20;;853:42;842:54;;832:65;;822:93;;911:1;908;901:12;822:93;725:196;;;:::o;926:260::-;994:6;1002;1055:2;1043:9;1034:7;1030:23;1026:32;1023:52;;;1071:1;1068;1061:12;1023:52;1094:29;1113:9;1094:29;:::i;:::-;1084:39;;1142:38;1176:2;1165:9;1161:18;1142:38;:::i;:::-;1132:48;;926:260;;;;;:::o;1604:180::-;1663:6;1716:2;1704:9;1695:7;1691:23;1687:32;1684:52;;;1732:1;1729;1722:12;1684:52;-1:-1:-1;1755:23:1;;1604:180;-1:-1:-1;1604:180:1:o;1974:254::-;2042:6;2050;2103:2;2091:9;2082:7;2078:23;2074:32;2071:52;;;2119:1;2116;2109:12;2071:52;2155:9;2142:23;2132:33;;2184:38;2218:2;2207:9;2203:18;2184:38;:::i;2233:248::-;2301:6;2309;2362:2;2350:9;2341:7;2337:23;2333:32;2330:52;;;2378:1;2375;2368:12;2330:52;-1:-1:-1;;2401:23:1;;;2471:2;2456:18;;;2443:32;;-1:-1:-1;2233:248:1:o;2486:186::-;2545:6;2598:2;2586:9;2577:7;2573:23;2569:32;2566:52;;;2614:1;2611;2604:12;2566:52;2637:29;2656:9;2637:29;:::i;4147:277::-;4214:6;4267:2;4255:9;4246:7;4242:23;4238:32;4235:52;;;4283:1;4280;4273:12;4235:52;4315:9;4309:16;4368:5;4361:13;4354:21;4347:5;4344:32;4334:60;;4390:1;4387;4380:12;4429:184;4481:77;4478:1;4471:88;4578:4;4575:1;4568:15;4602:4;4599:1;4592:15;4618:282;4685:9;;;4706:11;;;4703:191;;;4750:77;4747:1;4740:88;4851:4;4848:1;4841:15;4879:4;4876:1;4869:15;4905:184;4957:77;4954:1;4947:88;5054:4;5051:1;5044:15;5078:4;5075:1;5068:15;5094:412;5223:3;5261:6;5255:13;5286:1;5296:129;5310:6;5307:1;5304:13;5296:129;;;5408:4;5392:14;;;5388:25;;5382:32;5369:11;;;5362:53;5325:12;5296:129;;;-1:-1:-1;5480:1:1;5444:16;;5469:13;;;-1:-1:-1;5444:16:1;5094:412;-1:-1:-1;5094:412:1:o","abiDefinition":[{"inputs":[{"internalType":"address","name":"defaultAdmin","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AccessControlBadConfirmation","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"bytes32","name":"neededRole","type":"bytes32"}],"name":"AccessControlUnauthorizedAccount","type":"error"},{"inputs":[{"internalType":"address","name":"target","type":"address"}],"name":"AddressEmptyCode","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"AddressInsufficientBalance","type":"error"},{"inputs":[],"name":"CancelDelayBelowMin","type":"error"},{"inputs":[],"name":"FailedInnerCall","type":"error"},{"inputs":[],"name":"FeeRateAboveMax","type":"error"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"SafeERC20FailedOperation","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldCancelDelay","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newCancelDelay","type":"uint256"}],"name":"CancelDelayUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldFeeRate","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newFeeRate","type":"uint256"}],"name":"FeeRateUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"address","name":"recipient","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"FeesSwept","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"previousAdminRole","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"newAdminRole","type":"bytes32"}],"name":"RoleAdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleRevoked","type":"event"},{"inputs":[],"name":"CANCELER_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"DEFAULT_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"DEFAULT_CANCEL_DELAY","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"FEE_BPS","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"FEE_RATE_MAX","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"GOVERNOR_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"GUARD_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MIN_CANCEL_DELAY","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"NATIVE_GAS_TOKEN","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"PROVER_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"QUOTER_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"cancelDelay","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"chainGasAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleAdmin","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"uint256","name":"index","type":"uint256"}],"name":"getRoleMember","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleMemberCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"grantRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"hasRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"protocolFeeRate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"protocolFees","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"callerConfirmation","type":"address"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"revokeRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"newCancelDelay","type":"uint256"}],"name":"setCancelDelay","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"newFeeRate","type":"uint256"}],"name":"setProtocolFeeRate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"address","name":"recipient","type":"address"}],"name":"sweepProtocolFees","outputs":[],"stateMutability":"nonpayable","type":"function"}],"userDoc":{"kind":"user","methods":{"CANCELER_ROLE()":{"notice":"The role identifier for the Canceler's on-chain authentication in FastBridge."},"DEFAULT_CANCEL_DELAY()":{"notice":"The default cancel delay set during contract deployment."},"FEE_BPS()":{"notice":"The denominator for fee rates, representing 100%."},"FEE_RATE_MAX()":{"notice":"The maximum protocol fee rate: 1% of the origin amount."},"GOVERNOR_ROLE()":{"notice":"The role identifier for the Governor's on-chain administrative authority."},"GUARD_ROLE()":{"notice":"The role identifier for the Guard's on-chain authentication in FastBridge."},"MIN_CANCEL_DELAY()":{"notice":"The minimum cancel delay that can be set by the governor."},"NATIVE_GAS_TOKEN()":{"notice":"The address reserved for the native gas token (ETH on Ethereum and most L2s, AVAX on Avalanche, etc.)."},"PROVER_ROLE()":{"notice":"The role identifier for the Prover's on-chain authentication in FastBridge."},"QUOTER_ROLE()":{"notice":"The role identifier for the Quoter API's off-chain authentication."},"cancelDelay()":{"notice":"The delay period after which a transaction can be permissionlessly cancelled."},"chainGasAmount()":{"notice":"This variable is deprecated and should not be used."},"protocolFeeRate()":{"notice":"The protocol fee rate taken on the origin amount deposited in the origin chain."},"protocolFees(address)":{"notice":"The accumulated protocol fee amounts."},"setCancelDelay(uint256)":{"notice":"Allows the governor to set the cancel delay. The cancel delay is the time period after the transaction deadline during which a transaction can be permissionlessly cancelled if it hasn't been proven by any Relayer."},"setProtocolFeeRate(uint256)":{"notice":"Allows the governor to set the protocol fee rate. The protocol fee is taken from the origin amount and is only applied to completed and claimed transactions."},"sweepProtocolFees(address,address)":{"notice":"Allows the governor to withdraw the accumulated protocol fees from the contract."}},"notice":"Provides administrative functions and controls for managing the FastBridgeV2 contract, including access control and configuration settings.","version":1},"developerDoc":{"errors":{"AccessControlBadConfirmation()":[{"details":"The caller of a function is not the expected one. NOTE: Don't confuse with {AccessControlUnauthorizedAccount}."}],"AccessControlUnauthorizedAccount(address,bytes32)":[{"details":"The `account` is missing a role."}],"AddressEmptyCode(address)":[{"details":"There's no code at `target` (it is not a contract)."}],"AddressInsufficientBalance(address)":[{"details":"The ETH balance of the account is not enough to perform the operation."}],"FailedInnerCall()":[{"details":"A call to an address target failed. The target may have reverted."}],"SafeERC20FailedOperation(address)":[{"details":"An operation with an ERC20 token failed."}]},"events":{"RoleAdminChanged(bytes32,bytes32,bytes32)":{"details":"Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole` `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite {RoleAdminChanged} not being emitted signaling this."},"RoleGranted(bytes32,address,address)":{"details":"Emitted when `account` is granted `role`. `sender` is the account that originated the contract call, an admin role bearer except when using {AccessControl-_setupRole}."},"RoleRevoked(bytes32,address,address)":{"details":"Emitted when `account` is revoked `role`. `sender` is the account that originated the contract call: - if using `revokeRole`, it is the admin role bearer - if using `renounceRole`, it is the role bearer (i.e. `account`)"}},"kind":"dev","methods":{"getRoleAdmin(bytes32)":{"details":"Returns the admin role that controls `role`. See {grantRole} and {revokeRole}. To change a role's admin, use {_setRoleAdmin}."},"getRoleMember(bytes32,uint256)":{"details":"Returns one of the accounts that have `role`. `index` must be a value between 0 and {getRoleMemberCount}, non-inclusive. Role bearers are not sorted in any particular way, and their ordering may change at any point. WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure you perform all queries on the same block. See the following https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post] for more information."},"getRoleMemberCount(bytes32)":{"details":"Returns the number of accounts that have `role`. Can be used together with {getRoleMember} to enumerate all bearers of a role."},"grantRole(bytes32,address)":{"details":"Grants `role` to `account`. If `account` had not been already granted `role`, emits a {RoleGranted} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleGranted} event."},"hasRole(bytes32,address)":{"details":"Returns `true` if `account` has been granted `role`."},"renounceRole(bytes32,address)":{"details":"Revokes `role` from the calling account. Roles are often managed via {grantRole} and {revokeRole}: this function's purpose is to provide a mechanism for accounts to lose their privileges if they are compromised (such as when a trusted device is misplaced). If the calling account had been revoked `role`, emits a {RoleRevoked} event. Requirements: - the caller must be `callerConfirmation`. May emit a {RoleRevoked} event."},"revokeRole(bytes32,address)":{"details":"Revokes `role` from `account`. If `account` had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleRevoked} event."},"setProtocolFeeRate(uint256)":{"details":"The protocol fee is abstracted away from the relayers; they always operate using the amounts after fees. The origin amount they see in the emitted log is what they get credited with."},"supportsInterface(bytes4)":{"details":"See {IERC165-supportsInterface}."}},"stateVariables":{"CANCELER_ROLE":{"details":"Only addresses with this role can cancel a FastBridge transaction without the cancel delay."},"GOVERNOR_ROLE":{"details":"Only addresses with this role can perform administrative tasks within the contract."},"GUARD_ROLE":{"details":"Only addresses with this role can dispute submitted relay proofs during the dispute period."},"PROVER_ROLE":{"details":"Only addresses with this role can provide proofs that a FastBridge request has been relayed."},"QUOTER_ROLE":{"details":"Only addresses with this role can post FastBridge quotes to the API."},"chainGasAmount":{"details":"Use ZapNative V2 requests instead."}},"title":"AdminV2","version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"defaultAdmin\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"AccessControlBadConfirmation\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"neededRole\",\"type\":\"bytes32\"}],\"name\":\"AccessControlUnauthorizedAccount\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"}],\"name\":\"AddressEmptyCode\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"AddressInsufficientBalance\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"CancelDelayBelowMin\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"FailedInnerCall\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"FeeRateAboveMax\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"}],\"name\":\"SafeERC20FailedOperation\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"oldCancelDelay\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newCancelDelay\",\"type\":\"uint256\"}],\"name\":\"CancelDelayUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"oldFeeRate\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newFeeRate\",\"type\":\"uint256\"}],\"name\":\"FeeRateUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"FeesSwept\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"previousAdminRole\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"newAdminRole\",\"type\":\"bytes32\"}],\"name\":\"RoleAdminChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleGranted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleRevoked\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"CANCELER_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"DEFAULT_ADMIN_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"DEFAULT_CANCEL_DELAY\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"FEE_BPS\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"FEE_RATE_MAX\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"GOVERNOR_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"GUARD_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"MIN_CANCEL_DELAY\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"NATIVE_GAS_TOKEN\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"PROVER_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"QUOTER_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"cancelDelay\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"chainGasAmount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"}],\"name\":\"getRoleAdmin\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"index\",\"type\":\"uint256\"}],\"name\":\"getRoleMember\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"}],\"name\":\"getRoleMemberCount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"grantRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"hasRole\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"protocolFeeRate\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"protocolFees\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"callerConfirmation\",\"type\":\"address\"}],\"name\":\"renounceRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"revokeRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"newCancelDelay\",\"type\":\"uint256\"}],\"name\":\"setCancelDelay\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"newFeeRate\",\"type\":\"uint256\"}],\"name\":\"setProtocolFeeRate\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes4\",\"name\":\"interfaceId\",\"type\":\"bytes4\"}],\"name\":\"supportsInterface\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"}],\"name\":\"sweepProtocolFees\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"errors\":{\"AccessControlBadConfirmation()\":[{\"details\":\"The caller of a function is not the expected one. NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\"}],\"AccessControlUnauthorizedAccount(address,bytes32)\":[{\"details\":\"The `account` is missing a role.\"}],\"AddressEmptyCode(address)\":[{\"details\":\"There's no code at `target` (it is not a contract).\"}],\"AddressInsufficientBalance(address)\":[{\"details\":\"The ETH balance of the account is not enough to perform the operation.\"}],\"FailedInnerCall()\":[{\"details\":\"A call to an address target failed. The target may have reverted.\"}],\"SafeERC20FailedOperation(address)\":[{\"details\":\"An operation with an ERC20 token failed.\"}]},\"events\":{\"RoleAdminChanged(bytes32,bytes32,bytes32)\":{\"details\":\"Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole` `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite {RoleAdminChanged} not being emitted signaling this.\"},\"RoleGranted(bytes32,address,address)\":{\"details\":\"Emitted when `account` is granted `role`. `sender` is the account that originated the contract call, an admin role bearer except when using {AccessControl-_setupRole}.\"},\"RoleRevoked(bytes32,address,address)\":{\"details\":\"Emitted when `account` is revoked `role`. `sender` is the account that originated the contract call: - if using `revokeRole`, it is the admin role bearer - if using `renounceRole`, it is the role bearer (i.e. `account`)\"}},\"kind\":\"dev\",\"methods\":{\"getRoleAdmin(bytes32)\":{\"details\":\"Returns the admin role that controls `role`. See {grantRole} and {revokeRole}. To change a role's admin, use {_setRoleAdmin}.\"},\"getRoleMember(bytes32,uint256)\":{\"details\":\"Returns one of the accounts that have `role`. `index` must be a value between 0 and {getRoleMemberCount}, non-inclusive. Role bearers are not sorted in any particular way, and their ordering may change at any point. WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure you perform all queries on the same block. See the following https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post] for more information.\"},\"getRoleMemberCount(bytes32)\":{\"details\":\"Returns the number of accounts that have `role`. Can be used together with {getRoleMember} to enumerate all bearers of a role.\"},\"grantRole(bytes32,address)\":{\"details\":\"Grants `role` to `account`. If `account` had not been already granted `role`, emits a {RoleGranted} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleGranted} event.\"},\"hasRole(bytes32,address)\":{\"details\":\"Returns `true` if `account` has been granted `role`.\"},\"renounceRole(bytes32,address)\":{\"details\":\"Revokes `role` from the calling account. Roles are often managed via {grantRole} and {revokeRole}: this function's purpose is to provide a mechanism for accounts to lose their privileges if they are compromised (such as when a trusted device is misplaced). If the calling account had been revoked `role`, emits a {RoleRevoked} event. Requirements: - the caller must be `callerConfirmation`. May emit a {RoleRevoked} event.\"},\"revokeRole(bytes32,address)\":{\"details\":\"Revokes `role` from `account`. If `account` had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleRevoked} event.\"},\"setProtocolFeeRate(uint256)\":{\"details\":\"The protocol fee is abstracted away from the relayers; they always operate using the amounts after fees. The origin amount they see in the emitted log is what they get credited with.\"},\"supportsInterface(bytes4)\":{\"details\":\"See {IERC165-supportsInterface}.\"}},\"stateVariables\":{\"CANCELER_ROLE\":{\"details\":\"Only addresses with this role can cancel a FastBridge transaction without the cancel delay.\"},\"GOVERNOR_ROLE\":{\"details\":\"Only addresses with this role can perform administrative tasks within the contract.\"},\"GUARD_ROLE\":{\"details\":\"Only addresses with this role can dispute submitted relay proofs during the dispute period.\"},\"PROVER_ROLE\":{\"details\":\"Only addresses with this role can provide proofs that a FastBridge request has been relayed.\"},\"QUOTER_ROLE\":{\"details\":\"Only addresses with this role can post FastBridge quotes to the API.\"},\"chainGasAmount\":{\"details\":\"Use ZapNative V2 requests instead.\"}},\"title\":\"AdminV2\",\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"CANCELER_ROLE()\":{\"notice\":\"The role identifier for the Canceler's on-chain authentication in FastBridge.\"},\"DEFAULT_CANCEL_DELAY()\":{\"notice\":\"The default cancel delay set during contract deployment.\"},\"FEE_BPS()\":{\"notice\":\"The denominator for fee rates, representing 100%.\"},\"FEE_RATE_MAX()\":{\"notice\":\"The maximum protocol fee rate: 1% of the origin amount.\"},\"GOVERNOR_ROLE()\":{\"notice\":\"The role identifier for the Governor's on-chain administrative authority.\"},\"GUARD_ROLE()\":{\"notice\":\"The role identifier for the Guard's on-chain authentication in FastBridge.\"},\"MIN_CANCEL_DELAY()\":{\"notice\":\"The minimum cancel delay that can be set by the governor.\"},\"NATIVE_GAS_TOKEN()\":{\"notice\":\"The address reserved for the native gas token (ETH on Ethereum and most L2s, AVAX on Avalanche, etc.).\"},\"PROVER_ROLE()\":{\"notice\":\"The role identifier for the Prover's on-chain authentication in FastBridge.\"},\"QUOTER_ROLE()\":{\"notice\":\"The role identifier for the Quoter API's off-chain authentication.\"},\"cancelDelay()\":{\"notice\":\"The delay period after which a transaction can be permissionlessly cancelled.\"},\"chainGasAmount()\":{\"notice\":\"This variable is deprecated and should not be used.\"},\"protocolFeeRate()\":{\"notice\":\"The protocol fee rate taken on the origin amount deposited in the origin chain.\"},\"protocolFees(address)\":{\"notice\":\"The accumulated protocol fee amounts.\"},\"setCancelDelay(uint256)\":{\"notice\":\"Allows the governor to set the cancel delay. The cancel delay is the time period after the transaction deadline during which a transaction can be permissionlessly cancelled if it hasn't been proven by any Relayer.\"},\"setProtocolFeeRate(uint256)\":{\"notice\":\"Allows the governor to set the protocol fee rate. The protocol fee is taken from the origin amount and is only applied to completed and claimed transactions.\"},\"sweepProtocolFees(address,address)\":{\"notice\":\"Allows the governor to withdraw the accumulated protocol fees from the contract.\"}},\"notice\":\"Provides administrative functions and controls for managing the FastBridgeV2 contract, including access control and configuration settings.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeV2.sol\":\"AdminV2\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeV2.sol\":{\"keccak256\":\"0xaab2ee7357681726f0faf799a48ddfbf45fb4da93b69abf61c33dde92b29b74d\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://673391bff9569efc0f9bd99e0e6fece0bc8e8af1f052bb071b407b267a17b3b5\",\"dweb:/ipfs/QmdQQZ6DxpJYhfpinwU5WjLugr2f6qP8h68b5GerhSMQ4j\"]}},\"version\":1}"},"hashes":{"CANCELER_ROLE()":"02d2ff66","DEFAULT_ADMIN_ROLE()":"a217fddf","DEFAULT_CANCEL_DELAY()":"930ac180","FEE_BPS()":"bf333f2c","FEE_RATE_MAX()":"0f5f6ed7","GOVERNOR_ROLE()":"ccc57490","GUARD_ROLE()":"03ed0ee5","MIN_CANCEL_DELAY()":"922b7487","NATIVE_GAS_TOKEN()":"0f862f1e","PROVER_ROLE()":"dc9a4ef6","QUOTER_ROLE()":"7ebe815c","cancelDelay()":"638a0f09","chainGasAmount()":"e00a83e0","getRoleAdmin(bytes32)":"248a9ca3","getRoleMember(bytes32,uint256)":"9010d07c","getRoleMemberCount(bytes32)":"ca15c873","grantRole(bytes32,address)":"2f2ff15d","hasRole(bytes32,address)":"91d14854","protocolFeeRate()":"58f85880","protocolFees(address)":"dcf844a7","renounceRole(bytes32,address)":"36568abe","revokeRole(bytes32,address)":"d547741f","setCancelDelay(uint256)":"1ea327c5","setProtocolFeeRate(uint256)":"b13aa2d6","supportsInterface(bytes4)":"01ffc9a7","sweepProtocolFees(address,address)":"06f333f2"}},"solidity/FastBridgeV2.sol:BridgeTransactionV2Lib":{"code":"0x60566037600b82828239805160001a607314602a57634e487b7160e01b600052600060045260246000fd5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600080fdfea2646970667358221220e0ca35493e1156e7a5feebea2e43b9ef77737179785679c4db599efb0f1e2a0864736f6c63430008180033","runtime-code":"0x73000000000000000000000000000000000000000030146080604052600080fdfea2646970667358221220e0ca35493e1156e7a5feebea2e43b9ef77737179785679c4db599efb0f1e2a0864736f6c63430008180033","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.24 ^0.8.20 ^0.8.4;\n\n// contracts/interfaces/IAdminV2.sol\n\ninterface IAdminV2 {\n event CancelDelayUpdated(uint256 oldCancelDelay, uint256 newCancelDelay);\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n /// @notice Allows the governor to set the cancel delay. The cancel delay is the time period after the transaction\n /// deadline during which a transaction can be permissionlessly cancelled if it hasn't been proven by any Relayer.\n function setCancelDelay(uint256 newCancelDelay) external;\n\n /// @notice Allows the governor to set the protocol fee rate. The protocol fee is taken from the origin\n /// amount and is only applied to completed and claimed transactions.\n /// @dev The protocol fee is abstracted away from the relayers; they always operate using the amounts after fees.\n /// The origin amount they see in the emitted log is what they get credited with.\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n /// @notice Allows the governor to withdraw the accumulated protocol fees from the contract.\n function sweepProtocolFees(address token, address recipient) external;\n}\n\n// contracts/interfaces/IAdminV2Errors.sol\n\ninterface IAdminV2Errors {\n error CancelDelayBelowMin();\n error FeeRateAboveMax();\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IFastBridgeV2Errors.sol\n\ninterface IFastBridgeV2Errors {\n error AmountIncorrect();\n error ChainIncorrect();\n error ExclusivityParamsIncorrect();\n error MsgValueIncorrect();\n error SenderIncorrect();\n error StatusIncorrect();\n error TokenNotContract();\n error ZapDataLengthAboveMax();\n error ZapNativeNotSupported();\n error ZeroAddress();\n\n error RecipientIncorrectReturnValue();\n error RecipientNoReturnValue();\n\n error DeadlineExceeded();\n error DeadlineNotExceeded();\n error DeadlineTooShort();\n error DisputePeriodNotPassed();\n error DisputePeriodPassed();\n error ExclusivityPeriodNotPassed();\n\n error TransactionRelayed();\n}\n\n// contracts/interfaces/IMulticallTarget.sol\n\n/// @notice Interface for a contract that supports multiple calls from the same caller. Inspired by MulticallV3:\n/// https://github.com/mds1/multicall/blob/master/src/Multicall3.sol\ninterface IMulticallTarget {\n struct Result {\n bool success;\n bytes returnData;\n }\n\n /// @notice Executes multiple calls to this contract in a single transaction while preserving msg.sender.\n /// Return data from the calls is discarded.\n /// @dev This method is non-payable, so only calls with msg.value of 0 can be batched.\n /// If ignoreReverts is set to true, reverted calls will be skipped.\n /// Otherwise, the entire batch will revert with the original revert reason.\n /// @param data List of ABI-encoded calldata for the calls to execute\n /// @param ignoreReverts Whether to skip calls that revert\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external;\n\n /// @notice Executes multiple calls to this contract in a single transaction while preserving msg.sender.\n /// Return data from each call is preserved.\n /// @dev This method is non-payable, so only calls with msg.value of 0 can be batched.\n /// If ignoreReverts is set to true, reverted calls will be skipped.\n /// Otherwise, the entire batch will revert with the original revert reason.\n /// @param data List of ABI-encoded calldata for the calls to execute\n /// @param ignoreReverts Whether to skip calls that revert\n /// @return results List of results from the calls, each containing (success, returnData)\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results);\n}\n\n// contracts/interfaces/IZapRecipient.sol\n\n/// @notice Interface for contracts that can perform Zap operations. Such contracts could be used as Recipients\n/// in a FastBridge transaction that includes a Zap operation. The Zap Data should include instructions on how\n/// exactly the Zap operation should be executed, which would typically include the target address and calldata\n/// to use. The exact implementation of the Zap Data encoding is up to the Recipient contract.\ninterface IZapRecipient {\n /// @notice Performs a Zap operation with the given token and amount according to the provided Zap data.\n /// @param token The address of the token being used for the Zap operation.\n /// @param amount The amount of tokens to be used.\n /// @param zapData The encoded data specifying how the Zap operation should be executed.\n /// @return The function selector to indicate successful execution.\n function zap(address token, uint256 amount, bytes memory zapData) external payable returns (bytes4);\n}\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// contracts/interfaces/IFastBridgeV2.sol\n\ninterface IFastBridgeV2 is IFastBridge {\n enum BridgeStatus {\n NULL, // Doesn't exist yet.\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n struct BridgeTxDetails {\n BridgeStatus status;\n uint32 destChainId;\n uint56 proofBlockTimestamp;\n address proofRelayer;\n }\n\n struct BridgeRelay {\n uint48 blockNumber;\n uint48 blockTimestamp;\n address relayer;\n }\n\n /// @notice New params introduced in the FastBridgeV2.\n /// We are passing fields from the older BridgeParams struct outside of this struct for backwards compatibility.\n /// Note: quoteRelayer and quoteExclusivitySeconds are either both zero (indicating no exclusivity)\n /// or both non-zero (indicating exclusivity for the given period).\n /// Note: zapNative \u003e 0 can NOT be used with destToken = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE (native token)\n /// @param quoteRelayer Relayer that provided the quote for the transaction\n /// @param quoteExclusivitySeconds Period of time the quote relayer is guaranteed exclusivity after user's deposit\n /// @param quoteId Unique quote identifier used for tracking the quote\n /// @param zapNative ETH value to send to the recipient (if any)\n /// @param zapData Parameters for the Zap to the destination recipient (if any)\n struct BridgeParamsV2 {\n address quoteRelayer;\n int256 quoteExclusivitySeconds;\n bytes quoteId;\n uint256 zapNative;\n bytes zapData;\n }\n\n /// @notice Updated bridge transaction struct to include parameters introduced in FastBridgeV2.\n /// Note: only `exclusivityRelayer` can fill such a transaction until `exclusivityEndTime`.\n struct BridgeTransactionV2 {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n // Note: sendChainGas flag from V1 is deprecated\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n address exclusivityRelayer;\n uint256 exclusivityEndTime;\n uint256 zapNative; // ETH value to send to the recipient (if any)\n bytes zapData; // data to pass for the Zap action (if any)\n }\n\n event BridgeQuoteDetails(bytes32 indexed transactionId, bytes quoteId);\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability\n /// to provide temporary exclusivity fill rights for the quote relayer.\n /// @param params The parameters required to bridge\n /// @param paramsV2 The parameters for exclusivity fill rights (optional, can be left empty)\n function bridgeV2(BridgeParams memory params, BridgeParamsV2 memory paramsV2) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function relayV2(bytes memory request, address relayer) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param transactionId The transaction id associated with the encoded bridge transaction to prove\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function proveV2(bytes32 transactionId, bytes32 destTxHash, address relayer) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital.\n /// @notice Can only send funds to the relayer address on the proof.\n /// @param request The encoded bridge transaction to claim on origin chain\n function claimV2(bytes memory request) external;\n\n /// @notice Cancels an outstanding bridge transaction in case optimistic bridging failed and returns the full amount\n /// to the original sender.\n /// @param request The encoded bridge transaction to refund\n function cancelV2(bytes memory request) external;\n\n /// @notice Checks if a transaction has been relayed\n /// @param transactionId The ID of the transaction to check\n /// @return True if the transaction has been relayed, false otherwise\n function bridgeRelays(bytes32 transactionId) external view returns (bool);\n\n /// @notice Returns the status of a bridge transaction\n /// @param transactionId The ID of the bridge transaction\n /// @return BridgeStatus Status of the bridge transaction\n function bridgeStatuses(bytes32 transactionId) external view returns (BridgeStatus);\n\n /// @notice Returns the timestamp and relayer of a bridge proof\n /// @param transactionId The ID of the bridge transaction\n /// @return timestamp The timestamp of the bridge proof\n /// @return relayer The relayer address of the bridge proof\n function bridgeProofs(bytes32 transactionId) external view returns (uint96 timestamp, address relayer);\n\n /// @notice Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\n /// @param request The bridge request to decode\n function getBridgeTransactionV2(bytes memory request) external view returns (BridgeTransactionV2 memory);\n}\n\n// contracts/utils/MulticallTarget.sol\n\n// solhint-disable avoid-low-level-calls\n/// @notice Abstract contract template that supports batched calls while preserving msg.sender.\n/// Only calls with msg.value of 0 can be batched.\nabstract contract MulticallTarget is IMulticallTarget {\n error MulticallTarget__UndeterminedRevert();\n\n /// @inheritdoc IMulticallTarget\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external {\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\n if (!success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(result);\n }\n }\n }\n\n /// @inheritdoc IMulticallTarget\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results)\n {\n results = new Result[](data.length);\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (results[i].success, results[i].returnData) = address(this).delegatecall(data[i]);\n if (!results[i].success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(results[i].returnData);\n }\n }\n }\n\n /// @dev Bubbles the revert message from the underlying call.\n /// Note: preserves the same custom error or revert string, if one was used.\n /// Source: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v5.0.2/contracts/utils/Address.sol#L143-L158\n function _bubbleRevert(bytes memory returnData) internal pure {\n // Look for revert reason and bubble it up if present\n if (returnData.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n // solhint-disable-next-line no-inline-assembly\n assembly {\n let returndata_size := mload(returnData)\n revert(add(32, returnData), returndata_size)\n }\n } else {\n revert MulticallTarget__UndeterminedRevert();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// contracts/libs/BridgeTransactionV2.sol\n\n// solhint-disable no-inline-assembly\nlibrary BridgeTransactionV2Lib {\n uint16 internal constant VERSION = 2;\n\n // Offsets of the fields in the packed BridgeTransactionV2 struct\n // uint16 version [000 .. 002)\n // uint32 originChainId [002 .. 006)\n // uint32 destChainId [006 .. 010)\n // address originSender [010 .. 030)\n // address destRecipient [030 .. 050)\n // address originToken [050 .. 070)\n // address destToken [070 .. 090)\n // uint256 originAmount [090 .. 122)\n // uint256 destAmount [122 .. 154)\n // uint256 originFeeAmount [154 .. 186)\n // uint256 deadline [186 .. 218)\n // uint256 nonce [218 .. 250)\n // address exclusivityRelayer [250 .. 270)\n // uint256 exclusivityEndTime [270 .. 302)\n // uint256 zapNative [302 .. 334)\n // bytes zapData [334 .. ***)\n\n // forgefmt: disable-start\n uint256 private constant OFFSET_ORIGIN_CHAIN_ID = 2;\n uint256 private constant OFFSET_DEST_CHAIN_ID = 6;\n uint256 private constant OFFSET_ORIGIN_SENDER = 10;\n uint256 private constant OFFSET_DEST_RECIPIENT = 30;\n uint256 private constant OFFSET_ORIGIN_TOKEN = 50;\n uint256 private constant OFFSET_DEST_TOKEN = 70;\n uint256 private constant OFFSET_ORIGIN_AMOUNT = 90;\n uint256 private constant OFFSET_DEST_AMOUNT = 122;\n uint256 private constant OFFSET_ORIGIN_FEE_AMOUNT = 154;\n uint256 private constant OFFSET_DEADLINE = 186;\n uint256 private constant OFFSET_NONCE = 218;\n uint256 private constant OFFSET_EXCLUSIVITY_RELAYER = 250;\n uint256 private constant OFFSET_EXCLUSIVITY_END_TIME = 270;\n uint256 private constant OFFSET_ZAP_NATIVE = 302;\n uint256 private constant OFFSET_ZAP_DATA = 334;\n // forgefmt: disable-end\n\n error BridgeTransactionV2__InvalidEncodedTx();\n error BridgeTransactionV2__UnsupportedVersion(uint16 version);\n\n /// @notice Validates that the encoded transaction is a tightly packed encoded payload for BridgeTransactionV2.\n /// @dev Checks the minimum length and the version, use this function before decoding any of the fields.\n function validateV2(bytes calldata encodedTx) internal pure {\n // Check the minimum length: must at least include all static fields.\n if (encodedTx.length \u003c OFFSET_ZAP_DATA) revert BridgeTransactionV2__InvalidEncodedTx();\n // Once we validated the length, we can be sure that the version field is present.\n uint16 version_ = version(encodedTx);\n if (version_ != VERSION) revert BridgeTransactionV2__UnsupportedVersion(version_);\n }\n\n /// @notice Encodes the BridgeTransactionV2 struct by tightly packing the fields.\n /// @dev `abi.decode` will not work as a result of the tightly packed fields. Use `decodeV2` to decode instead.\n function encodeV2(IFastBridgeV2.BridgeTransactionV2 memory bridgeTx) internal pure returns (bytes memory) {\n // We split the encoding into two parts to avoid stack-too-deep error\n bytes memory firstPart = abi.encodePacked(\n VERSION,\n bridgeTx.originChainId,\n bridgeTx.destChainId,\n bridgeTx.originSender,\n bridgeTx.destRecipient,\n bridgeTx.originToken,\n bridgeTx.destToken,\n bridgeTx.originAmount\n );\n return abi.encodePacked(\n firstPart,\n bridgeTx.destAmount,\n bridgeTx.originFeeAmount,\n // Note: we skip the deprecated `sendChainGas` flag, which was present in BridgeTransaction V1\n bridgeTx.deadline,\n bridgeTx.nonce,\n // New V2 fields: exclusivity\n bridgeTx.exclusivityRelayer,\n bridgeTx.exclusivityEndTime,\n // New V2 fields: Zap\n bridgeTx.zapNative,\n bridgeTx.zapData\n );\n }\n\n /// @notice Decodes the BridgeTransactionV2 struct from the encoded transaction.\n /// @dev Encoded BridgeTransactionV2 struct must be tightly packed.\n /// Use `validateV2` before decoding to ensure the encoded transaction is valid.\n function decodeV2(bytes calldata encodedTx)\n internal\n pure\n returns (IFastBridgeV2.BridgeTransactionV2 memory bridgeTx)\n {\n bridgeTx.originChainId = originChainId(encodedTx);\n bridgeTx.destChainId = destChainId(encodedTx);\n bridgeTx.originSender = originSender(encodedTx);\n bridgeTx.destRecipient = destRecipient(encodedTx);\n bridgeTx.originToken = originToken(encodedTx);\n bridgeTx.destToken = destToken(encodedTx);\n bridgeTx.originAmount = originAmount(encodedTx);\n bridgeTx.destAmount = destAmount(encodedTx);\n bridgeTx.originFeeAmount = originFeeAmount(encodedTx);\n bridgeTx.deadline = deadline(encodedTx);\n bridgeTx.nonce = nonce(encodedTx);\n bridgeTx.exclusivityRelayer = exclusivityRelayer(encodedTx);\n bridgeTx.exclusivityEndTime = exclusivityEndTime(encodedTx);\n bridgeTx.zapNative = zapNative(encodedTx);\n bridgeTx.zapData = zapData(encodedTx);\n }\n\n /// @notice Extracts the version from the encoded transaction.\n function version(bytes calldata encodedTx) internal pure returns (uint16 version_) {\n // Load 32 bytes from the start and shift it 240 bits to the right to get the highest 16 bits.\n assembly {\n version_ := shr(240, calldataload(encodedTx.offset))\n }\n }\n\n /// @notice Extracts the origin chain ID from the encoded transaction.\n function originChainId(bytes calldata encodedTx) internal pure returns (uint32 originChainId_) {\n // Load 32 bytes from the offset and shift it 224 bits to the right to get the highest 32 bits.\n assembly {\n originChainId_ := shr(224, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_CHAIN_ID)))\n }\n }\n\n /// @notice Extracts the destination chain ID from the encoded transaction.\n function destChainId(bytes calldata encodedTx) internal pure returns (uint32 destChainId_) {\n // Load 32 bytes from the offset and shift it 224 bits to the right to get the highest 32 bits.\n assembly {\n destChainId_ := shr(224, calldataload(add(encodedTx.offset, OFFSET_DEST_CHAIN_ID)))\n }\n }\n\n /// @notice Extracts the origin sender from the encoded transaction.\n function originSender(bytes calldata encodedTx) internal pure returns (address originSender_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n originSender_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_SENDER)))\n }\n }\n\n /// @notice Extracts the destination recipient from the encoded transaction.\n function destRecipient(bytes calldata encodedTx) internal pure returns (address destRecipient_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n destRecipient_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_DEST_RECIPIENT)))\n }\n }\n\n /// @notice Extracts the origin token from the encoded transaction.\n function originToken(bytes calldata encodedTx) internal pure returns (address originToken_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n originToken_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_TOKEN)))\n }\n }\n\n /// @notice Extracts the destination token from the encoded transaction.\n function destToken(bytes calldata encodedTx) internal pure returns (address destToken_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n destToken_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_DEST_TOKEN)))\n }\n }\n\n /// @notice Extracts the origin amount from the encoded transaction.\n function originAmount(bytes calldata encodedTx) internal pure returns (uint256 originAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n originAmount_ := calldataload(add(encodedTx.offset, OFFSET_ORIGIN_AMOUNT))\n }\n }\n\n /// @notice Extracts the destination amount from the encoded transaction.\n function destAmount(bytes calldata encodedTx) internal pure returns (uint256 destAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n destAmount_ := calldataload(add(encodedTx.offset, OFFSET_DEST_AMOUNT))\n }\n }\n\n /// @notice Extracts the origin fee amount from the encoded transaction.\n function originFeeAmount(bytes calldata encodedTx) internal pure returns (uint256 originFeeAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n originFeeAmount_ := calldataload(add(encodedTx.offset, OFFSET_ORIGIN_FEE_AMOUNT))\n }\n }\n\n /// @notice Extracts the deadline from the encoded transaction.\n function deadline(bytes calldata encodedTx) internal pure returns (uint256 deadline_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n deadline_ := calldataload(add(encodedTx.offset, OFFSET_DEADLINE))\n }\n }\n\n /// @notice Extracts the nonce from the encoded transaction.\n function nonce(bytes calldata encodedTx) internal pure returns (uint256 nonce_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n nonce_ := calldataload(add(encodedTx.offset, OFFSET_NONCE))\n }\n }\n\n /// @notice Extracts the exclusivity relayer from the encoded transaction.\n function exclusivityRelayer(bytes calldata encodedTx) internal pure returns (address exclusivityRelayer_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n exclusivityRelayer_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_EXCLUSIVITY_RELAYER)))\n }\n }\n\n /// @notice Extracts the exclusivity end time from the encoded transaction.\n function exclusivityEndTime(bytes calldata encodedTx) internal pure returns (uint256 exclusivityEndTime_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n exclusivityEndTime_ := calldataload(add(encodedTx.offset, OFFSET_EXCLUSIVITY_END_TIME))\n }\n }\n\n /// @notice Extracts the Zap's native value from the encoded transaction.\n function zapNative(bytes calldata encodedTx) internal pure returns (uint256 zapNative_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n zapNative_ := calldataload(add(encodedTx.offset, OFFSET_ZAP_NATIVE))\n }\n }\n\n /// @notice Extracts the Zap's data from the encoded transaction.\n function zapData(bytes calldata encodedTx) internal pure returns (bytes calldata zapData_) {\n zapData_ = encodedTx[OFFSET_ZAP_DATA:];\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/AdminV2.sol\n\n// ════════════════════════════════════════════════ INTERFACES ═════════════════════════════════════════════════════\n\n// ═════════════════════════════════════════════ EXTERNAL IMPORTS ══════════════════════════════════════════════════\n\n/// @title AdminV2\n/// @notice Provides administrative functions and controls for managing the FastBridgeV2 contract,\n/// including access control and configuration settings.\ncontract AdminV2 is AccessControlEnumerable, IAdminV2, IAdminV2Errors {\n using SafeERC20 for IERC20;\n\n /// @notice The address reserved for the native gas token (ETH on Ethereum and most L2s, AVAX on Avalanche, etc.).\n address public constant NATIVE_GAS_TOKEN = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice The role identifier for the Quoter API's off-chain authentication.\n /// @dev Only addresses with this role can post FastBridge quotes to the API.\n bytes32 public constant QUOTER_ROLE = keccak256(\"QUOTER_ROLE\");\n\n /// @notice The role identifier for the Prover's on-chain authentication in FastBridge.\n /// @dev Only addresses with this role can provide proofs that a FastBridge request has been relayed.\n bytes32 public constant PROVER_ROLE = keccak256(\"PROVER_ROLE\");\n\n /// @notice The role identifier for the Guard's on-chain authentication in FastBridge.\n /// @dev Only addresses with this role can dispute submitted relay proofs during the dispute period.\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n\n /// @notice The role identifier for the Canceler's on-chain authentication in FastBridge.\n /// @dev Only addresses with this role can cancel a FastBridge transaction without the cancel delay.\n bytes32 public constant CANCELER_ROLE = keccak256(\"CANCELER_ROLE\");\n\n /// @notice The role identifier for the Governor's on-chain administrative authority.\n /// @dev Only addresses with this role can perform administrative tasks within the contract.\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n /// @notice The denominator for fee rates, representing 100%.\n uint256 public constant FEE_BPS = 1e6;\n /// @notice The maximum protocol fee rate: 1% of the origin amount.\n uint256 public constant FEE_RATE_MAX = 0.01e6;\n\n /// @notice The minimum cancel delay that can be set by the governor.\n uint256 public constant MIN_CANCEL_DELAY = 1 hours;\n /// @notice The default cancel delay set during contract deployment.\n uint256 public constant DEFAULT_CANCEL_DELAY = 1 days;\n\n /// @notice The protocol fee rate taken on the origin amount deposited in the origin chain.\n uint256 public protocolFeeRate;\n\n /// @notice The accumulated protocol fee amounts.\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice The delay period after which a transaction can be permissionlessly cancelled.\n uint256 public cancelDelay;\n\n /// @notice This variable is deprecated and should not be used.\n /// @dev Use ZapNative V2 requests instead.\n uint256 public immutable chainGasAmount = 0;\n\n constructor(address defaultAdmin) {\n _grantRole(DEFAULT_ADMIN_ROLE, defaultAdmin);\n _setCancelDelay(DEFAULT_CANCEL_DELAY);\n }\n\n /// @inheritdoc IAdminV2\n function setCancelDelay(uint256 newCancelDelay) external onlyRole(GOVERNOR_ROLE) {\n _setCancelDelay(newCancelDelay);\n }\n\n /// @inheritdoc IAdminV2\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n if (newFeeRate \u003e FEE_RATE_MAX) revert FeeRateAboveMax();\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n /// @inheritdoc IAdminV2\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n // Early exit if no accumulated fees.\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return;\n // Reset the accumulated fees first.\n protocolFees[token] = 0;\n emit FeesSwept(token, recipient, feeAmount);\n // Sweep the fees as the last transaction action.\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(recipient), feeAmount);\n } else {\n IERC20(token).safeTransfer(recipient, feeAmount);\n }\n }\n\n /// @notice Internal logic to set the cancel delay. Security checks are performed outside of this function.\n /// @dev This function is marked as private to prevent child contracts from calling it directly.\n function _setCancelDelay(uint256 newCancelDelay) private {\n if (newCancelDelay \u003c MIN_CANCEL_DELAY) revert CancelDelayBelowMin();\n uint256 oldCancelDelay = cancelDelay;\n cancelDelay = newCancelDelay;\n emit CancelDelayUpdated(oldCancelDelay, newCancelDelay);\n }\n}\n\n// contracts/FastBridgeV2.sol\n\n// ════════════════════════════════════════════════ INTERFACES ═════════════════════════════════════════════════════\n\n// ═════════════════════════════════════════════ INTERNAL IMPORTS ══════════════════════════════════════════════════\n\n// ═════════════════════════════════════════════ EXTERNAL IMPORTS ══════════════════════════════════════════════════\n\n/// @title FastBridgeV2\n/// @notice Core component of the SynapseRFQ protocol, enabling Relayers (Solvers) to fulfill bridge requests.\n/// Supports ERC20 and native gas tokens, along with the Zap feature for executing actions on the destination chain.\n/// Users interact with the off-chain Quoter API to obtain a current quote for a bridge transaction.\n/// They then submit the bridge request with the quote to this contract, depositing their assets in escrow.\n/// Relayers can fulfill requests by relaying them to the destination chain and must prove fulfillment to claim funds.\n/// Guards monitor proofs and can dispute discrepancies.\n/// Users can reclaim funds by cancelling their requests if it has not been fulfilled within the specified deadline.\ncontract FastBridgeV2 is AdminV2, MulticallTarget, IFastBridgeV2, IFastBridgeV2Errors {\n using BridgeTransactionV2Lib for bytes;\n using SafeERC20 for IERC20;\n\n /// @notice The duration of the dispute period for relayed transactions.\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice The minimum required time between transaction request and deadline.\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n /// @notice The maximum allowed length for zapData.\n uint256 public constant MAX_ZAP_DATA_LENGTH = 2 ** 16 - 1;\n\n /// @notice Maps transaction IDs to bridge details (status, destination chain ID, proof timestamp, and relayer).\n /// Note: this is only stored for transactions having local chain as the origin chain.\n mapping(bytes32 =\u003e BridgeTxDetails) public bridgeTxDetails;\n /// @notice Maps transaction IDs to relay details (block number, block timestamp, and relayer).\n /// Note: this is only stored for transactions having local chain as the destination chain.\n mapping(bytes32 =\u003e BridgeRelay) public bridgeRelayDetails;\n /// @notice Maps sender addresses to their unique bridge nonce.\n mapping(address =\u003e uint256) public senderNonces;\n\n /// @notice This variable is deprecated and should not be used.\n /// @dev Replaced by senderNonces.\n uint256 public immutable nonce = 0;\n /// @notice The block number at which this contract was deployed.\n uint256 public immutable deployBlock;\n\n /// @notice Initializes the FastBridgeV2 contract with the provided default admin,\n /// sets the default cancel delay, and records the deploy block number.\n constructor(address defaultAdmin) AdminV2(defaultAdmin) {\n deployBlock = block.number;\n }\n\n // ══════════════════════════════════════ EXTERNAL MUTABLE (USER FACING) ═══════════════════════════════════════════\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n bridgeV2({\n params: params,\n paramsV2: BridgeParamsV2({\n quoteRelayer: address(0),\n quoteExclusivitySeconds: 0,\n quoteId: bytes(\"\"),\n zapNative: 0,\n zapData: bytes(\"\")\n })\n });\n }\n\n /// Note: this function is deprecated and will be removed in a future version.\n /// @dev Replaced by `cancel`.\n /// @inheritdoc IFastBridge\n function refund(bytes calldata request) external {\n cancelV2(request);\n }\n\n // ══════════════════════════════════════ EXTERNAL MUTABLE (AGENT FACING) ══════════════════════════════════════════\n\n /// @inheritdoc IFastBridge\n function relay(bytes calldata request) external payable {\n // `relay` override will validate the request.\n relayV2({request: request, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes calldata request, bytes32 destTxHash) external {\n request.validateV2();\n proveV2({transactionId: keccak256(request), destTxHash: destTxHash, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridgeV2\n function claimV2(bytes calldata request) external {\n // `claim` override will validate the request.\n claim({request: request, to: address(0)});\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n // Aggregate the read operations from the same storage slot.\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n address disputedRelayer = $.proofRelayer;\n BridgeStatus status = $.status;\n uint56 proofBlockTimestamp = $.proofBlockTimestamp;\n\n // Can only dispute a RELAYER_PROVED transaction within the dispute period.\n if (status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(proofBlockTimestamp) \u003e DISPUTE_PERIOD) {\n revert DisputePeriodPassed();\n }\n\n // Update status to REQUESTED and delete the disputed proof details.\n // Note: these are storage writes.\n $.status = BridgeStatus.REQUESTED;\n $.proofRelayer = address(0);\n $.proofBlockTimestamp = 0;\n\n emit BridgeProofDisputed(transactionId, disputedRelayer);\n }\n\n // ══════════════════════════════════════════════ EXTERNAL VIEWS ═══════════════════════════════════════════════════\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n // The correct relayer can only claim a RELAYER_PROVED transaction after the dispute period.\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n if ($.status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if ($.proofRelayer != relayer) revert SenderIncorrect();\n\n return _timeSince($.proofBlockTimestamp) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n /// @dev This method is added to achieve backwards compatibility with decoding requests into V1 structs:\n /// - `zapNative` is partially reported as a zero/non-zero flag\n /// - `zapData` is ignored\n /// In order to process all kinds of requests use getBridgeTransactionV2 instead.\n function getBridgeTransaction(bytes calldata request) external view returns (BridgeTransaction memory) {\n // Try decoding into V2 struct first. This will revert if V1 struct is passed.\n try this.getBridgeTransactionV2(request) returns (BridgeTransactionV2 memory txV2) {\n // Note: we entirely ignore the zapData field, as it was not present in V1.\n return BridgeTransaction({\n originChainId: txV2.originChainId,\n destChainId: txV2.destChainId,\n originSender: txV2.originSender,\n destRecipient: txV2.destRecipient,\n originToken: txV2.originToken,\n destToken: txV2.destToken,\n originAmount: txV2.originAmount,\n destAmount: txV2.destAmount,\n originFeeAmount: txV2.originFeeAmount,\n sendChainGas: txV2.zapNative != 0,\n deadline: txV2.deadline,\n nonce: txV2.nonce\n });\n } catch {\n // Fallback to V1 struct.\n return abi.decode(request, (BridgeTransaction));\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function getBridgeTransactionV2(bytes calldata request) external pure returns (BridgeTransactionV2 memory) {\n request.validateV2();\n return BridgeTransactionV2Lib.decodeV2(request);\n }\n\n // ═══════════════════════════════════════ PUBLIC MUTABLE (USER FACING) ════════════════════════════════════════════\n\n /// @inheritdoc IFastBridgeV2\n function bridgeV2(BridgeParams memory params, BridgeParamsV2 memory paramsV2) public payable {\n // If relayer exclusivity is not intended for this bridge, set exclusivityEndTime to static zero.\n // Otherwise, set exclusivity to expire at the current block ts offset by quoteExclusivitySeconds.\n int256 exclusivityEndTime = 0;\n if (paramsV2.quoteRelayer != address(0)) {\n exclusivityEndTime = int256(block.timestamp) + paramsV2.quoteExclusivitySeconds;\n }\n _validateBridgeParams(params, paramsV2, exclusivityEndTime);\n\n // Transfer tokens to bridge contract. We use the actual transferred amount in case of transfer fees.\n uint256 originAmount = _takeBridgedUserAsset(params.originToken, params.originAmount);\n\n // Track the amount of origin token owed to protocol.\n uint256 originFeeAmount = 0;\n if (protocolFeeRate \u003e 0) {\n originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n // The Relayer filling this request will be paid the originAmount after fees.\n // Note: the protocol fees will be accumulated only when the Relayer claims the origin collateral.\n originAmount -= originFeeAmount;\n }\n\n // Hash the bridge request and set the initial status to REQUESTED.\n bytes memory request = BridgeTransactionV2Lib.encodeV2(\n BridgeTransactionV2({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n deadline: params.deadline,\n // Increment the sender's nonce on every bridge.\n nonce: senderNonces[params.sender]++,\n exclusivityRelayer: paramsV2.quoteRelayer,\n // We checked exclusivityEndTime to be in range [0 .. params.deadline] above, so can safely cast.\n exclusivityEndTime: uint256(exclusivityEndTime),\n zapNative: paramsV2.zapNative,\n zapData: paramsV2.zapData\n })\n );\n bytes32 transactionId = keccak256(request);\n // Note: the tx status will be updated throughout the tx lifecycle, while destChainId is set once here.\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n bridgeTxDetails[transactionId].destChainId = params.dstChainId;\n\n emit BridgeRequested({\n transactionId: transactionId,\n sender: params.sender,\n request: request,\n destChainId: params.dstChainId,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n sendChainGas: paramsV2.zapNative != 0\n });\n emit BridgeQuoteDetails(transactionId, paramsV2.quoteId);\n }\n\n /// @inheritdoc IFastBridgeV2\n function cancelV2(bytes calldata request) public {\n // Decode the request and check that it could be cancelled.\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n\n // Can only cancel a REQUESTED transaction after its deadline expires.\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n if ($.status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n\n // Permissionless cancel is only allowed after `cancelDelay` on top of the deadline.\n uint256 deadline = request.deadline();\n if (!hasRole(CANCELER_ROLE, msg.sender)) deadline += cancelDelay;\n if (block.timestamp \u003c= deadline) revert DeadlineNotExceeded();\n\n // Update status to REFUNDED.\n // Note: this is a storage write.\n $.status = BridgeStatus.REFUNDED;\n\n // Return the full amount (collateral + protocol fees) to the original sender.\n // The protocol fees are only accumulated when the transaction is claimed, so we don't need to update them here.\n address to = request.originSender();\n address token = request.originToken();\n uint256 amount = request.originAmount() + request.originFeeAmount();\n\n // Emit the event before any external calls.\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n\n // Return the funds to the original sender as last transaction action.\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(to), amount);\n } else {\n IERC20(token).safeTransfer(to, amount);\n }\n }\n\n // ═══════════════════════════════════════ PUBLIC MUTABLE (AGENT FACING) ═══════════════════════════════════════════\n\n /// @inheritdoc IFastBridgeV2\n function relayV2(bytes calldata request, address relayer) public payable {\n // Decode the request and check that it could be relayed.\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n _validateRelayParams(request, transactionId, relayer);\n\n // Mark the bridge request as relayed by saving the relayer and the block details.\n bridgeRelayDetails[transactionId].blockNumber = uint48(block.number);\n bridgeRelayDetails[transactionId].blockTimestamp = uint48(block.timestamp);\n bridgeRelayDetails[transactionId].relayer = relayer;\n\n // Transfer tokens to recipient on destination chain and trigger Zap if requested.\n address to = request.destRecipient();\n address token = request.destToken();\n uint256 amount = request.destAmount();\n uint256 zapNative = request.zapNative();\n\n // Emit the event before any external calls.\n emit BridgeRelayed({\n transactionId: transactionId,\n relayer: relayer,\n to: to,\n originChainId: request.originChainId(),\n originToken: request.originToken(),\n destToken: token,\n originAmount: request.originAmount(),\n destAmount: amount,\n chainGasAmount: zapNative\n });\n\n // All state changes have been done at this point, can proceed to the external calls.\n // This follows the checks-effects-interactions pattern to mitigate potential reentrancy attacks.\n if (token == NATIVE_GAS_TOKEN) {\n // For the native gas token, additional zapNative is not allowed.\n if (zapNative != 0) revert ZapNativeNotSupported();\n // Check that the correct msg.value was sent.\n if (msg.value != amount) revert MsgValueIncorrect();\n // Don't do a native transfer yet: we will handle it alongside the Zap below.\n } else {\n // For ERC20s, we check that the correct msg.value was sent.\n if (msg.value != zapNative) revert MsgValueIncorrect();\n // We need to transfer the tokens from the Relayer to the recipient first before performing an\n // optional post-transfer Zap.\n IERC20(token).safeTransferFrom(msg.sender, to, amount);\n }\n // At this point we have done:\n // - Transferred the requested amount of ERC20 tokens to the recipient.\n // At this point we have confirmed:\n // - For ERC20s: msg.value matches the requested zapNative amount.\n // - For the native gas token: msg.value matches the requested destAmount.\n // Remaining optional things to do:\n // - Forward the full msg.value to the recipient (if non-zero).\n // - Trigger a Zap (if zapData is present).\n bytes calldata zapData = request.zapData();\n if (zapData.length != 0) {\n // Zap Data is present: Zap has been requested by the recipient. Trigger it forwarding the full msg.value.\n _triggerZapWithChecks({recipient: to, token: token, amount: amount, zapData: zapData});\n // Note: if token has a fee on transfers, the recipient will have received less than `amount`.\n // This is a very niche edge case and should be handled by the recipient contract.\n } else if (msg.value != 0) {\n // Zap Data is missing, but msg.value was sent. This could happen in two different cases:\n // - Relay with the native gas token is happening.\n // - Relay with ERC20 is happening, with a `zapNative \u003e 0` request.\n // In both cases, we need to transfer the full msg.value to the recipient.\n Address.sendValue(payable(to), msg.value);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function proveV2(bytes32 transactionId, bytes32 destTxHash, address relayer) public onlyRole(PROVER_ROLE) {\n // Can only prove a REQUESTED transaction.\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n if ($.status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n\n // Update status to RELAYER_PROVED and store the proof details.\n // Note: these are storage writes.\n $.status = BridgeStatus.RELAYER_PROVED;\n $.proofBlockTimestamp = uint56(block.timestamp);\n $.proofRelayer = relayer;\n\n emit BridgeProofProvided(transactionId, relayer, destTxHash);\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes calldata request, address to) public {\n // Decode the request and check that it could be claimed.\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n\n // Aggregate the read operations from the same storage slot.\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n address proofRelayer = $.proofRelayer;\n BridgeStatus status = $.status;\n uint56 proofBlockTimestamp = $.proofBlockTimestamp;\n\n // Can only claim a RELAYER_PROVED transaction after the dispute period.\n if (status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(proofBlockTimestamp) \u003c= DISPUTE_PERIOD) revert DisputePeriodNotPassed();\n if (to == address(0)) {\n // Anyone could claim the funds to the proven relayer on their behalf.\n to = proofRelayer;\n } else if (proofRelayer != msg.sender) {\n // Only the proven relayer could specify an address to claim the funds to.\n revert SenderIncorrect();\n }\n\n // Update status to RELAYER_CLAIMED and transfer the origin collateral to the specified claim address.\n // Note: this is a storage write.\n $.status = BridgeStatus.RELAYER_CLAIMED;\n\n // Accumulate protocol fees if origin fee amount exists.\n address token = request.originToken();\n uint256 amount = request.originAmount();\n uint256 originFeeAmount = request.originFeeAmount();\n if (originFeeAmount \u003e 0) protocolFees[token] += originFeeAmount;\n\n // Emit the event before any external calls.\n emit BridgeDepositClaimed(transactionId, proofRelayer, to, token, amount);\n\n // Complete the relayer claim as the last transaction action.\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(to), amount);\n } else {\n IERC20(token).safeTransfer(to, amount);\n }\n }\n\n // ═══════════════════════════════════════════════ PUBLIC VIEWS ════════════════════════════════════════════════════\n\n /// @inheritdoc IFastBridgeV2\n function bridgeStatuses(bytes32 transactionId) public view returns (BridgeStatus status) {\n return bridgeTxDetails[transactionId].status;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeProofs(bytes32 transactionId) public view returns (uint96 timestamp, address relayer) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n timestamp = $.proofBlockTimestamp;\n relayer = $.proofRelayer;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeRelays(bytes32 transactionId) public view returns (bool) {\n // This transaction has been relayed if the relayer address is recorded.\n return bridgeRelayDetails[transactionId].relayer != address(0);\n }\n\n // ═════════════════════════════════════════════ INTERNAL METHODS ══════════════════════════════════════════════════\n\n /// @notice Takes the bridged asset from the user into FastBridgeV2 custody. The asset will later be\n /// claimed by the relayer who completed the relay on the destination chain, or returned to the user\n /// via the cancel function if no relay is completed.\n function _takeBridgedUserAsset(address token, uint256 amount) internal returns (uint256 amountTaken) {\n if (token == NATIVE_GAS_TOKEN) {\n // For the native gas token, we just need to check that the supplied msg.value is correct.\n // Supplied `msg.value` is already in FastBridgeV2 custody.\n if (amount != msg.value) revert MsgValueIncorrect();\n amountTaken = msg.value;\n } else {\n // For ERC20s, token is explicitly transferred from the user to FastBridgeV2.\n // We don't allow non-zero `msg.value` to avoid extra funds from being stuck in FastBridgeV2.\n if (msg.value != 0) revert MsgValueIncorrect();\n // Throw an explicit error if the provided token address is not a contract.\n if (token.code.length == 0) revert TokenNotContract();\n\n // Use the balance difference as the amount taken in case of fee on transfer tokens.\n amountTaken = IERC20(token).balanceOf(address(this));\n IERC20(token).safeTransferFrom(msg.sender, address(this), amount);\n amountTaken = IERC20(token).balanceOf(address(this)) - amountTaken;\n }\n }\n\n /// @notice Calls the recipient's hook function with the specified zapData and validates\n /// the returned value.\n function _triggerZapWithChecks(address recipient, address token, uint256 amount, bytes calldata zapData) internal {\n // Call the recipient's hook function with the specified zapData, bubbling any revert messages.\n bytes memory returnData = Address.functionCallWithValue({\n target: recipient,\n data: abi.encodeCall(IZapRecipient.zap, (token, amount, zapData)),\n // Note: see `relay()` for reasoning behind passing msg.value.\n value: msg.value\n });\n\n // Explicit revert if no return data at all.\n if (returnData.length == 0) revert RecipientNoReturnValue();\n // Check that exactly a single return value was returned.\n if (returnData.length != 32) revert RecipientIncorrectReturnValue();\n // Return value should be abi-encoded hook function selector.\n if (bytes32(returnData) != bytes32(IZapRecipient.zap.selector)) {\n revert RecipientIncorrectReturnValue();\n }\n }\n\n /// @notice Calculates the time elapsed since a proof was submitted.\n /// @dev The proof.timestamp stores block timestamps as uint56 for gas optimization.\n /// _timeSince(proof) handles timestamp rollover when block.timestamp \u003e type(uint56).max but\n /// proof.timestamp \u003c type(uint56).max via an unchecked statement.\n /// @param proofBlockTimestamp The block timestamp when the proof was submitted.\n /// @return delta The time elapsed since proof submission.\n function _timeSince(uint56 proofBlockTimestamp) internal view returns (uint256 delta) {\n unchecked {\n delta = uint56(block.timestamp) - proofBlockTimestamp;\n }\n }\n\n /// @notice Validates all parameters required for a bridge transaction.\n /// @dev This function's complexity cannot be reduced due to the number of required checks,\n /// so we disable the code-complexity rule.\n // solhint-disable-next-line code-complexity\n function _validateBridgeParams(\n BridgeParams memory params,\n BridgeParamsV2 memory paramsV2,\n int256 exclusivityEndTime\n )\n internal\n view\n {\n // Check V1 (legacy) params.\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.sender == address(0) || params.to == address(0)) revert ZeroAddress();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n\n // Check V2 params.\n if (paramsV2.zapData.length \u003e MAX_ZAP_DATA_LENGTH) revert ZapDataLengthAboveMax();\n if (paramsV2.zapNative != 0 \u0026\u0026 params.destToken == NATIVE_GAS_TOKEN) {\n revert ZapNativeNotSupported();\n }\n\n // exclusivityEndTime must be in range [0 .. params.deadline].\n if (exclusivityEndTime \u003c 0 || exclusivityEndTime \u003e int256(params.deadline)) {\n revert ExclusivityParamsIncorrect();\n }\n }\n\n /// @notice Validates all parameters required for a relay transaction.\n function _validateRelayParams(bytes calldata request, bytes32 transactionId, address relayer) internal view {\n if (relayer == address(0)) revert ZeroAddress();\n // Check that the transaction has not been relayed yet and is for the current chain.\n if (bridgeRelays(transactionId)) revert TransactionRelayed();\n if (request.destChainId() != block.chainid) revert ChainIncorrect();\n // Check that the deadline for relay to happen has not passed yet.\n if (block.timestamp \u003e request.deadline()) revert DeadlineExceeded();\n // Check the exclusivity period, if it was specified and is still ongoing.\n address exclRelayer = request.exclusivityRelayer();\n if (exclRelayer != address(0) \u0026\u0026 exclRelayer != relayer \u0026\u0026 block.timestamp \u003c= request.exclusivityEndTime()) {\n revert ExclusivityPeriodNotPassed();\n }\n }\n}\n","language":"Solidity","languageVersion":"0.8.24","compilerVersion":"0.8.24","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"51072:11498:0:-:0;;;;;;;;;;;;;;;-1:-1:-1;;;51072:11498:0;;;;;;;;;;;;;;;;;","srcMapRuntime":"51072:11498:0:-:0;;;;;;;;","abiDefinition":[{"inputs":[],"name":"BridgeTransactionV2__InvalidEncodedTx","type":"error"},{"inputs":[{"internalType":"uint16","name":"version","type":"uint16"}],"name":"BridgeTransactionV2__UnsupportedVersion","type":"error"}],"userDoc":{"kind":"user","methods":{},"version":1},"developerDoc":{"kind":"dev","methods":{},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[],\"name\":\"BridgeTransactionV2__InvalidEncodedTx\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint16\",\"name\":\"version\",\"type\":\"uint16\"}],\"name\":\"BridgeTransactionV2__UnsupportedVersion\",\"type\":\"error\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeV2.sol\":\"BridgeTransactionV2Lib\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeV2.sol\":{\"keccak256\":\"0xaab2ee7357681726f0faf799a48ddfbf45fb4da93b69abf61c33dde92b29b74d\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://673391bff9569efc0f9bd99e0e6fece0bc8e8af1f052bb071b407b267a17b3b5\",\"dweb:/ipfs/QmdQQZ6DxpJYhfpinwU5WjLugr2f6qP8h68b5GerhSMQ4j\"]}},\"version\":1}"},"hashes":{}},"solidity/FastBridgeV2.sol:Context":{"code":"0x","runtime-code":"0x","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.24 ^0.8.20 ^0.8.4;\n\n// contracts/interfaces/IAdminV2.sol\n\ninterface IAdminV2 {\n event CancelDelayUpdated(uint256 oldCancelDelay, uint256 newCancelDelay);\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n /// @notice Allows the governor to set the cancel delay. The cancel delay is the time period after the transaction\n /// deadline during which a transaction can be permissionlessly cancelled if it hasn't been proven by any Relayer.\n function setCancelDelay(uint256 newCancelDelay) external;\n\n /// @notice Allows the governor to set the protocol fee rate. The protocol fee is taken from the origin\n /// amount and is only applied to completed and claimed transactions.\n /// @dev The protocol fee is abstracted away from the relayers; they always operate using the amounts after fees.\n /// The origin amount they see in the emitted log is what they get credited with.\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n /// @notice Allows the governor to withdraw the accumulated protocol fees from the contract.\n function sweepProtocolFees(address token, address recipient) external;\n}\n\n// contracts/interfaces/IAdminV2Errors.sol\n\ninterface IAdminV2Errors {\n error CancelDelayBelowMin();\n error FeeRateAboveMax();\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IFastBridgeV2Errors.sol\n\ninterface IFastBridgeV2Errors {\n error AmountIncorrect();\n error ChainIncorrect();\n error ExclusivityParamsIncorrect();\n error MsgValueIncorrect();\n error SenderIncorrect();\n error StatusIncorrect();\n error TokenNotContract();\n error ZapDataLengthAboveMax();\n error ZapNativeNotSupported();\n error ZeroAddress();\n\n error RecipientIncorrectReturnValue();\n error RecipientNoReturnValue();\n\n error DeadlineExceeded();\n error DeadlineNotExceeded();\n error DeadlineTooShort();\n error DisputePeriodNotPassed();\n error DisputePeriodPassed();\n error ExclusivityPeriodNotPassed();\n\n error TransactionRelayed();\n}\n\n// contracts/interfaces/IMulticallTarget.sol\n\n/// @notice Interface for a contract that supports multiple calls from the same caller. Inspired by MulticallV3:\n/// https://github.com/mds1/multicall/blob/master/src/Multicall3.sol\ninterface IMulticallTarget {\n struct Result {\n bool success;\n bytes returnData;\n }\n\n /// @notice Executes multiple calls to this contract in a single transaction while preserving msg.sender.\n /// Return data from the calls is discarded.\n /// @dev This method is non-payable, so only calls with msg.value of 0 can be batched.\n /// If ignoreReverts is set to true, reverted calls will be skipped.\n /// Otherwise, the entire batch will revert with the original revert reason.\n /// @param data List of ABI-encoded calldata for the calls to execute\n /// @param ignoreReverts Whether to skip calls that revert\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external;\n\n /// @notice Executes multiple calls to this contract in a single transaction while preserving msg.sender.\n /// Return data from each call is preserved.\n /// @dev This method is non-payable, so only calls with msg.value of 0 can be batched.\n /// If ignoreReverts is set to true, reverted calls will be skipped.\n /// Otherwise, the entire batch will revert with the original revert reason.\n /// @param data List of ABI-encoded calldata for the calls to execute\n /// @param ignoreReverts Whether to skip calls that revert\n /// @return results List of results from the calls, each containing (success, returnData)\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results);\n}\n\n// contracts/interfaces/IZapRecipient.sol\n\n/// @notice Interface for contracts that can perform Zap operations. Such contracts could be used as Recipients\n/// in a FastBridge transaction that includes a Zap operation. The Zap Data should include instructions on how\n/// exactly the Zap operation should be executed, which would typically include the target address and calldata\n/// to use. The exact implementation of the Zap Data encoding is up to the Recipient contract.\ninterface IZapRecipient {\n /// @notice Performs a Zap operation with the given token and amount according to the provided Zap data.\n /// @param token The address of the token being used for the Zap operation.\n /// @param amount The amount of tokens to be used.\n /// @param zapData The encoded data specifying how the Zap operation should be executed.\n /// @return The function selector to indicate successful execution.\n function zap(address token, uint256 amount, bytes memory zapData) external payable returns (bytes4);\n}\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// contracts/interfaces/IFastBridgeV2.sol\n\ninterface IFastBridgeV2 is IFastBridge {\n enum BridgeStatus {\n NULL, // Doesn't exist yet.\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n struct BridgeTxDetails {\n BridgeStatus status;\n uint32 destChainId;\n uint56 proofBlockTimestamp;\n address proofRelayer;\n }\n\n struct BridgeRelay {\n uint48 blockNumber;\n uint48 blockTimestamp;\n address relayer;\n }\n\n /// @notice New params introduced in the FastBridgeV2.\n /// We are passing fields from the older BridgeParams struct outside of this struct for backwards compatibility.\n /// Note: quoteRelayer and quoteExclusivitySeconds are either both zero (indicating no exclusivity)\n /// or both non-zero (indicating exclusivity for the given period).\n /// Note: zapNative \u003e 0 can NOT be used with destToken = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE (native token)\n /// @param quoteRelayer Relayer that provided the quote for the transaction\n /// @param quoteExclusivitySeconds Period of time the quote relayer is guaranteed exclusivity after user's deposit\n /// @param quoteId Unique quote identifier used for tracking the quote\n /// @param zapNative ETH value to send to the recipient (if any)\n /// @param zapData Parameters for the Zap to the destination recipient (if any)\n struct BridgeParamsV2 {\n address quoteRelayer;\n int256 quoteExclusivitySeconds;\n bytes quoteId;\n uint256 zapNative;\n bytes zapData;\n }\n\n /// @notice Updated bridge transaction struct to include parameters introduced in FastBridgeV2.\n /// Note: only `exclusivityRelayer` can fill such a transaction until `exclusivityEndTime`.\n struct BridgeTransactionV2 {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n // Note: sendChainGas flag from V1 is deprecated\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n address exclusivityRelayer;\n uint256 exclusivityEndTime;\n uint256 zapNative; // ETH value to send to the recipient (if any)\n bytes zapData; // data to pass for the Zap action (if any)\n }\n\n event BridgeQuoteDetails(bytes32 indexed transactionId, bytes quoteId);\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability\n /// to provide temporary exclusivity fill rights for the quote relayer.\n /// @param params The parameters required to bridge\n /// @param paramsV2 The parameters for exclusivity fill rights (optional, can be left empty)\n function bridgeV2(BridgeParams memory params, BridgeParamsV2 memory paramsV2) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function relayV2(bytes memory request, address relayer) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param transactionId The transaction id associated with the encoded bridge transaction to prove\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function proveV2(bytes32 transactionId, bytes32 destTxHash, address relayer) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital.\n /// @notice Can only send funds to the relayer address on the proof.\n /// @param request The encoded bridge transaction to claim on origin chain\n function claimV2(bytes memory request) external;\n\n /// @notice Cancels an outstanding bridge transaction in case optimistic bridging failed and returns the full amount\n /// to the original sender.\n /// @param request The encoded bridge transaction to refund\n function cancelV2(bytes memory request) external;\n\n /// @notice Checks if a transaction has been relayed\n /// @param transactionId The ID of the transaction to check\n /// @return True if the transaction has been relayed, false otherwise\n function bridgeRelays(bytes32 transactionId) external view returns (bool);\n\n /// @notice Returns the status of a bridge transaction\n /// @param transactionId The ID of the bridge transaction\n /// @return BridgeStatus Status of the bridge transaction\n function bridgeStatuses(bytes32 transactionId) external view returns (BridgeStatus);\n\n /// @notice Returns the timestamp and relayer of a bridge proof\n /// @param transactionId The ID of the bridge transaction\n /// @return timestamp The timestamp of the bridge proof\n /// @return relayer The relayer address of the bridge proof\n function bridgeProofs(bytes32 transactionId) external view returns (uint96 timestamp, address relayer);\n\n /// @notice Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\n /// @param request The bridge request to decode\n function getBridgeTransactionV2(bytes memory request) external view returns (BridgeTransactionV2 memory);\n}\n\n// contracts/utils/MulticallTarget.sol\n\n// solhint-disable avoid-low-level-calls\n/// @notice Abstract contract template that supports batched calls while preserving msg.sender.\n/// Only calls with msg.value of 0 can be batched.\nabstract contract MulticallTarget is IMulticallTarget {\n error MulticallTarget__UndeterminedRevert();\n\n /// @inheritdoc IMulticallTarget\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external {\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\n if (!success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(result);\n }\n }\n }\n\n /// @inheritdoc IMulticallTarget\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results)\n {\n results = new Result[](data.length);\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (results[i].success, results[i].returnData) = address(this).delegatecall(data[i]);\n if (!results[i].success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(results[i].returnData);\n }\n }\n }\n\n /// @dev Bubbles the revert message from the underlying call.\n /// Note: preserves the same custom error or revert string, if one was used.\n /// Source: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v5.0.2/contracts/utils/Address.sol#L143-L158\n function _bubbleRevert(bytes memory returnData) internal pure {\n // Look for revert reason and bubble it up if present\n if (returnData.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n // solhint-disable-next-line no-inline-assembly\n assembly {\n let returndata_size := mload(returnData)\n revert(add(32, returnData), returndata_size)\n }\n } else {\n revert MulticallTarget__UndeterminedRevert();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// contracts/libs/BridgeTransactionV2.sol\n\n// solhint-disable no-inline-assembly\nlibrary BridgeTransactionV2Lib {\n uint16 internal constant VERSION = 2;\n\n // Offsets of the fields in the packed BridgeTransactionV2 struct\n // uint16 version [000 .. 002)\n // uint32 originChainId [002 .. 006)\n // uint32 destChainId [006 .. 010)\n // address originSender [010 .. 030)\n // address destRecipient [030 .. 050)\n // address originToken [050 .. 070)\n // address destToken [070 .. 090)\n // uint256 originAmount [090 .. 122)\n // uint256 destAmount [122 .. 154)\n // uint256 originFeeAmount [154 .. 186)\n // uint256 deadline [186 .. 218)\n // uint256 nonce [218 .. 250)\n // address exclusivityRelayer [250 .. 270)\n // uint256 exclusivityEndTime [270 .. 302)\n // uint256 zapNative [302 .. 334)\n // bytes zapData [334 .. ***)\n\n // forgefmt: disable-start\n uint256 private constant OFFSET_ORIGIN_CHAIN_ID = 2;\n uint256 private constant OFFSET_DEST_CHAIN_ID = 6;\n uint256 private constant OFFSET_ORIGIN_SENDER = 10;\n uint256 private constant OFFSET_DEST_RECIPIENT = 30;\n uint256 private constant OFFSET_ORIGIN_TOKEN = 50;\n uint256 private constant OFFSET_DEST_TOKEN = 70;\n uint256 private constant OFFSET_ORIGIN_AMOUNT = 90;\n uint256 private constant OFFSET_DEST_AMOUNT = 122;\n uint256 private constant OFFSET_ORIGIN_FEE_AMOUNT = 154;\n uint256 private constant OFFSET_DEADLINE = 186;\n uint256 private constant OFFSET_NONCE = 218;\n uint256 private constant OFFSET_EXCLUSIVITY_RELAYER = 250;\n uint256 private constant OFFSET_EXCLUSIVITY_END_TIME = 270;\n uint256 private constant OFFSET_ZAP_NATIVE = 302;\n uint256 private constant OFFSET_ZAP_DATA = 334;\n // forgefmt: disable-end\n\n error BridgeTransactionV2__InvalidEncodedTx();\n error BridgeTransactionV2__UnsupportedVersion(uint16 version);\n\n /// @notice Validates that the encoded transaction is a tightly packed encoded payload for BridgeTransactionV2.\n /// @dev Checks the minimum length and the version, use this function before decoding any of the fields.\n function validateV2(bytes calldata encodedTx) internal pure {\n // Check the minimum length: must at least include all static fields.\n if (encodedTx.length \u003c OFFSET_ZAP_DATA) revert BridgeTransactionV2__InvalidEncodedTx();\n // Once we validated the length, we can be sure that the version field is present.\n uint16 version_ = version(encodedTx);\n if (version_ != VERSION) revert BridgeTransactionV2__UnsupportedVersion(version_);\n }\n\n /// @notice Encodes the BridgeTransactionV2 struct by tightly packing the fields.\n /// @dev `abi.decode` will not work as a result of the tightly packed fields. Use `decodeV2` to decode instead.\n function encodeV2(IFastBridgeV2.BridgeTransactionV2 memory bridgeTx) internal pure returns (bytes memory) {\n // We split the encoding into two parts to avoid stack-too-deep error\n bytes memory firstPart = abi.encodePacked(\n VERSION,\n bridgeTx.originChainId,\n bridgeTx.destChainId,\n bridgeTx.originSender,\n bridgeTx.destRecipient,\n bridgeTx.originToken,\n bridgeTx.destToken,\n bridgeTx.originAmount\n );\n return abi.encodePacked(\n firstPart,\n bridgeTx.destAmount,\n bridgeTx.originFeeAmount,\n // Note: we skip the deprecated `sendChainGas` flag, which was present in BridgeTransaction V1\n bridgeTx.deadline,\n bridgeTx.nonce,\n // New V2 fields: exclusivity\n bridgeTx.exclusivityRelayer,\n bridgeTx.exclusivityEndTime,\n // New V2 fields: Zap\n bridgeTx.zapNative,\n bridgeTx.zapData\n );\n }\n\n /// @notice Decodes the BridgeTransactionV2 struct from the encoded transaction.\n /// @dev Encoded BridgeTransactionV2 struct must be tightly packed.\n /// Use `validateV2` before decoding to ensure the encoded transaction is valid.\n function decodeV2(bytes calldata encodedTx)\n internal\n pure\n returns (IFastBridgeV2.BridgeTransactionV2 memory bridgeTx)\n {\n bridgeTx.originChainId = originChainId(encodedTx);\n bridgeTx.destChainId = destChainId(encodedTx);\n bridgeTx.originSender = originSender(encodedTx);\n bridgeTx.destRecipient = destRecipient(encodedTx);\n bridgeTx.originToken = originToken(encodedTx);\n bridgeTx.destToken = destToken(encodedTx);\n bridgeTx.originAmount = originAmount(encodedTx);\n bridgeTx.destAmount = destAmount(encodedTx);\n bridgeTx.originFeeAmount = originFeeAmount(encodedTx);\n bridgeTx.deadline = deadline(encodedTx);\n bridgeTx.nonce = nonce(encodedTx);\n bridgeTx.exclusivityRelayer = exclusivityRelayer(encodedTx);\n bridgeTx.exclusivityEndTime = exclusivityEndTime(encodedTx);\n bridgeTx.zapNative = zapNative(encodedTx);\n bridgeTx.zapData = zapData(encodedTx);\n }\n\n /// @notice Extracts the version from the encoded transaction.\n function version(bytes calldata encodedTx) internal pure returns (uint16 version_) {\n // Load 32 bytes from the start and shift it 240 bits to the right to get the highest 16 bits.\n assembly {\n version_ := shr(240, calldataload(encodedTx.offset))\n }\n }\n\n /// @notice Extracts the origin chain ID from the encoded transaction.\n function originChainId(bytes calldata encodedTx) internal pure returns (uint32 originChainId_) {\n // Load 32 bytes from the offset and shift it 224 bits to the right to get the highest 32 bits.\n assembly {\n originChainId_ := shr(224, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_CHAIN_ID)))\n }\n }\n\n /// @notice Extracts the destination chain ID from the encoded transaction.\n function destChainId(bytes calldata encodedTx) internal pure returns (uint32 destChainId_) {\n // Load 32 bytes from the offset and shift it 224 bits to the right to get the highest 32 bits.\n assembly {\n destChainId_ := shr(224, calldataload(add(encodedTx.offset, OFFSET_DEST_CHAIN_ID)))\n }\n }\n\n /// @notice Extracts the origin sender from the encoded transaction.\n function originSender(bytes calldata encodedTx) internal pure returns (address originSender_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n originSender_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_SENDER)))\n }\n }\n\n /// @notice Extracts the destination recipient from the encoded transaction.\n function destRecipient(bytes calldata encodedTx) internal pure returns (address destRecipient_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n destRecipient_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_DEST_RECIPIENT)))\n }\n }\n\n /// @notice Extracts the origin token from the encoded transaction.\n function originToken(bytes calldata encodedTx) internal pure returns (address originToken_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n originToken_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_TOKEN)))\n }\n }\n\n /// @notice Extracts the destination token from the encoded transaction.\n function destToken(bytes calldata encodedTx) internal pure returns (address destToken_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n destToken_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_DEST_TOKEN)))\n }\n }\n\n /// @notice Extracts the origin amount from the encoded transaction.\n function originAmount(bytes calldata encodedTx) internal pure returns (uint256 originAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n originAmount_ := calldataload(add(encodedTx.offset, OFFSET_ORIGIN_AMOUNT))\n }\n }\n\n /// @notice Extracts the destination amount from the encoded transaction.\n function destAmount(bytes calldata encodedTx) internal pure returns (uint256 destAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n destAmount_ := calldataload(add(encodedTx.offset, OFFSET_DEST_AMOUNT))\n }\n }\n\n /// @notice Extracts the origin fee amount from the encoded transaction.\n function originFeeAmount(bytes calldata encodedTx) internal pure returns (uint256 originFeeAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n originFeeAmount_ := calldataload(add(encodedTx.offset, OFFSET_ORIGIN_FEE_AMOUNT))\n }\n }\n\n /// @notice Extracts the deadline from the encoded transaction.\n function deadline(bytes calldata encodedTx) internal pure returns (uint256 deadline_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n deadline_ := calldataload(add(encodedTx.offset, OFFSET_DEADLINE))\n }\n }\n\n /// @notice Extracts the nonce from the encoded transaction.\n function nonce(bytes calldata encodedTx) internal pure returns (uint256 nonce_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n nonce_ := calldataload(add(encodedTx.offset, OFFSET_NONCE))\n }\n }\n\n /// @notice Extracts the exclusivity relayer from the encoded transaction.\n function exclusivityRelayer(bytes calldata encodedTx) internal pure returns (address exclusivityRelayer_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n exclusivityRelayer_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_EXCLUSIVITY_RELAYER)))\n }\n }\n\n /// @notice Extracts the exclusivity end time from the encoded transaction.\n function exclusivityEndTime(bytes calldata encodedTx) internal pure returns (uint256 exclusivityEndTime_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n exclusivityEndTime_ := calldataload(add(encodedTx.offset, OFFSET_EXCLUSIVITY_END_TIME))\n }\n }\n\n /// @notice Extracts the Zap's native value from the encoded transaction.\n function zapNative(bytes calldata encodedTx) internal pure returns (uint256 zapNative_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n zapNative_ := calldataload(add(encodedTx.offset, OFFSET_ZAP_NATIVE))\n }\n }\n\n /// @notice Extracts the Zap's data from the encoded transaction.\n function zapData(bytes calldata encodedTx) internal pure returns (bytes calldata zapData_) {\n zapData_ = encodedTx[OFFSET_ZAP_DATA:];\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/AdminV2.sol\n\n// ════════════════════════════════════════════════ INTERFACES ═════════════════════════════════════════════════════\n\n// ═════════════════════════════════════════════ EXTERNAL IMPORTS ══════════════════════════════════════════════════\n\n/// @title AdminV2\n/// @notice Provides administrative functions and controls for managing the FastBridgeV2 contract,\n/// including access control and configuration settings.\ncontract AdminV2 is AccessControlEnumerable, IAdminV2, IAdminV2Errors {\n using SafeERC20 for IERC20;\n\n /// @notice The address reserved for the native gas token (ETH on Ethereum and most L2s, AVAX on Avalanche, etc.).\n address public constant NATIVE_GAS_TOKEN = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice The role identifier for the Quoter API's off-chain authentication.\n /// @dev Only addresses with this role can post FastBridge quotes to the API.\n bytes32 public constant QUOTER_ROLE = keccak256(\"QUOTER_ROLE\");\n\n /// @notice The role identifier for the Prover's on-chain authentication in FastBridge.\n /// @dev Only addresses with this role can provide proofs that a FastBridge request has been relayed.\n bytes32 public constant PROVER_ROLE = keccak256(\"PROVER_ROLE\");\n\n /// @notice The role identifier for the Guard's on-chain authentication in FastBridge.\n /// @dev Only addresses with this role can dispute submitted relay proofs during the dispute period.\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n\n /// @notice The role identifier for the Canceler's on-chain authentication in FastBridge.\n /// @dev Only addresses with this role can cancel a FastBridge transaction without the cancel delay.\n bytes32 public constant CANCELER_ROLE = keccak256(\"CANCELER_ROLE\");\n\n /// @notice The role identifier for the Governor's on-chain administrative authority.\n /// @dev Only addresses with this role can perform administrative tasks within the contract.\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n /// @notice The denominator for fee rates, representing 100%.\n uint256 public constant FEE_BPS = 1e6;\n /// @notice The maximum protocol fee rate: 1% of the origin amount.\n uint256 public constant FEE_RATE_MAX = 0.01e6;\n\n /// @notice The minimum cancel delay that can be set by the governor.\n uint256 public constant MIN_CANCEL_DELAY = 1 hours;\n /// @notice The default cancel delay set during contract deployment.\n uint256 public constant DEFAULT_CANCEL_DELAY = 1 days;\n\n /// @notice The protocol fee rate taken on the origin amount deposited in the origin chain.\n uint256 public protocolFeeRate;\n\n /// @notice The accumulated protocol fee amounts.\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice The delay period after which a transaction can be permissionlessly cancelled.\n uint256 public cancelDelay;\n\n /// @notice This variable is deprecated and should not be used.\n /// @dev Use ZapNative V2 requests instead.\n uint256 public immutable chainGasAmount = 0;\n\n constructor(address defaultAdmin) {\n _grantRole(DEFAULT_ADMIN_ROLE, defaultAdmin);\n _setCancelDelay(DEFAULT_CANCEL_DELAY);\n }\n\n /// @inheritdoc IAdminV2\n function setCancelDelay(uint256 newCancelDelay) external onlyRole(GOVERNOR_ROLE) {\n _setCancelDelay(newCancelDelay);\n }\n\n /// @inheritdoc IAdminV2\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n if (newFeeRate \u003e FEE_RATE_MAX) revert FeeRateAboveMax();\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n /// @inheritdoc IAdminV2\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n // Early exit if no accumulated fees.\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return;\n // Reset the accumulated fees first.\n protocolFees[token] = 0;\n emit FeesSwept(token, recipient, feeAmount);\n // Sweep the fees as the last transaction action.\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(recipient), feeAmount);\n } else {\n IERC20(token).safeTransfer(recipient, feeAmount);\n }\n }\n\n /// @notice Internal logic to set the cancel delay. Security checks are performed outside of this function.\n /// @dev This function is marked as private to prevent child contracts from calling it directly.\n function _setCancelDelay(uint256 newCancelDelay) private {\n if (newCancelDelay \u003c MIN_CANCEL_DELAY) revert CancelDelayBelowMin();\n uint256 oldCancelDelay = cancelDelay;\n cancelDelay = newCancelDelay;\n emit CancelDelayUpdated(oldCancelDelay, newCancelDelay);\n }\n}\n\n// contracts/FastBridgeV2.sol\n\n// ════════════════════════════════════════════════ INTERFACES ═════════════════════════════════════════════════════\n\n// ═════════════════════════════════════════════ INTERNAL IMPORTS ══════════════════════════════════════════════════\n\n// ═════════════════════════════════════════════ EXTERNAL IMPORTS ══════════════════════════════════════════════════\n\n/// @title FastBridgeV2\n/// @notice Core component of the SynapseRFQ protocol, enabling Relayers (Solvers) to fulfill bridge requests.\n/// Supports ERC20 and native gas tokens, along with the Zap feature for executing actions on the destination chain.\n/// Users interact with the off-chain Quoter API to obtain a current quote for a bridge transaction.\n/// They then submit the bridge request with the quote to this contract, depositing their assets in escrow.\n/// Relayers can fulfill requests by relaying them to the destination chain and must prove fulfillment to claim funds.\n/// Guards monitor proofs and can dispute discrepancies.\n/// Users can reclaim funds by cancelling their requests if it has not been fulfilled within the specified deadline.\ncontract FastBridgeV2 is AdminV2, MulticallTarget, IFastBridgeV2, IFastBridgeV2Errors {\n using BridgeTransactionV2Lib for bytes;\n using SafeERC20 for IERC20;\n\n /// @notice The duration of the dispute period for relayed transactions.\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice The minimum required time between transaction request and deadline.\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n /// @notice The maximum allowed length for zapData.\n uint256 public constant MAX_ZAP_DATA_LENGTH = 2 ** 16 - 1;\n\n /// @notice Maps transaction IDs to bridge details (status, destination chain ID, proof timestamp, and relayer).\n /// Note: this is only stored for transactions having local chain as the origin chain.\n mapping(bytes32 =\u003e BridgeTxDetails) public bridgeTxDetails;\n /// @notice Maps transaction IDs to relay details (block number, block timestamp, and relayer).\n /// Note: this is only stored for transactions having local chain as the destination chain.\n mapping(bytes32 =\u003e BridgeRelay) public bridgeRelayDetails;\n /// @notice Maps sender addresses to their unique bridge nonce.\n mapping(address =\u003e uint256) public senderNonces;\n\n /// @notice This variable is deprecated and should not be used.\n /// @dev Replaced by senderNonces.\n uint256 public immutable nonce = 0;\n /// @notice The block number at which this contract was deployed.\n uint256 public immutable deployBlock;\n\n /// @notice Initializes the FastBridgeV2 contract with the provided default admin,\n /// sets the default cancel delay, and records the deploy block number.\n constructor(address defaultAdmin) AdminV2(defaultAdmin) {\n deployBlock = block.number;\n }\n\n // ══════════════════════════════════════ EXTERNAL MUTABLE (USER FACING) ═══════════════════════════════════════════\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n bridgeV2({\n params: params,\n paramsV2: BridgeParamsV2({\n quoteRelayer: address(0),\n quoteExclusivitySeconds: 0,\n quoteId: bytes(\"\"),\n zapNative: 0,\n zapData: bytes(\"\")\n })\n });\n }\n\n /// Note: this function is deprecated and will be removed in a future version.\n /// @dev Replaced by `cancel`.\n /// @inheritdoc IFastBridge\n function refund(bytes calldata request) external {\n cancelV2(request);\n }\n\n // ══════════════════════════════════════ EXTERNAL MUTABLE (AGENT FACING) ══════════════════════════════════════════\n\n /// @inheritdoc IFastBridge\n function relay(bytes calldata request) external payable {\n // `relay` override will validate the request.\n relayV2({request: request, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes calldata request, bytes32 destTxHash) external {\n request.validateV2();\n proveV2({transactionId: keccak256(request), destTxHash: destTxHash, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridgeV2\n function claimV2(bytes calldata request) external {\n // `claim` override will validate the request.\n claim({request: request, to: address(0)});\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n // Aggregate the read operations from the same storage slot.\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n address disputedRelayer = $.proofRelayer;\n BridgeStatus status = $.status;\n uint56 proofBlockTimestamp = $.proofBlockTimestamp;\n\n // Can only dispute a RELAYER_PROVED transaction within the dispute period.\n if (status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(proofBlockTimestamp) \u003e DISPUTE_PERIOD) {\n revert DisputePeriodPassed();\n }\n\n // Update status to REQUESTED and delete the disputed proof details.\n // Note: these are storage writes.\n $.status = BridgeStatus.REQUESTED;\n $.proofRelayer = address(0);\n $.proofBlockTimestamp = 0;\n\n emit BridgeProofDisputed(transactionId, disputedRelayer);\n }\n\n // ══════════════════════════════════════════════ EXTERNAL VIEWS ═══════════════════════════════════════════════════\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n // The correct relayer can only claim a RELAYER_PROVED transaction after the dispute period.\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n if ($.status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if ($.proofRelayer != relayer) revert SenderIncorrect();\n\n return _timeSince($.proofBlockTimestamp) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n /// @dev This method is added to achieve backwards compatibility with decoding requests into V1 structs:\n /// - `zapNative` is partially reported as a zero/non-zero flag\n /// - `zapData` is ignored\n /// In order to process all kinds of requests use getBridgeTransactionV2 instead.\n function getBridgeTransaction(bytes calldata request) external view returns (BridgeTransaction memory) {\n // Try decoding into V2 struct first. This will revert if V1 struct is passed.\n try this.getBridgeTransactionV2(request) returns (BridgeTransactionV2 memory txV2) {\n // Note: we entirely ignore the zapData field, as it was not present in V1.\n return BridgeTransaction({\n originChainId: txV2.originChainId,\n destChainId: txV2.destChainId,\n originSender: txV2.originSender,\n destRecipient: txV2.destRecipient,\n originToken: txV2.originToken,\n destToken: txV2.destToken,\n originAmount: txV2.originAmount,\n destAmount: txV2.destAmount,\n originFeeAmount: txV2.originFeeAmount,\n sendChainGas: txV2.zapNative != 0,\n deadline: txV2.deadline,\n nonce: txV2.nonce\n });\n } catch {\n // Fallback to V1 struct.\n return abi.decode(request, (BridgeTransaction));\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function getBridgeTransactionV2(bytes calldata request) external pure returns (BridgeTransactionV2 memory) {\n request.validateV2();\n return BridgeTransactionV2Lib.decodeV2(request);\n }\n\n // ═══════════════════════════════════════ PUBLIC MUTABLE (USER FACING) ════════════════════════════════════════════\n\n /// @inheritdoc IFastBridgeV2\n function bridgeV2(BridgeParams memory params, BridgeParamsV2 memory paramsV2) public payable {\n // If relayer exclusivity is not intended for this bridge, set exclusivityEndTime to static zero.\n // Otherwise, set exclusivity to expire at the current block ts offset by quoteExclusivitySeconds.\n int256 exclusivityEndTime = 0;\n if (paramsV2.quoteRelayer != address(0)) {\n exclusivityEndTime = int256(block.timestamp) + paramsV2.quoteExclusivitySeconds;\n }\n _validateBridgeParams(params, paramsV2, exclusivityEndTime);\n\n // Transfer tokens to bridge contract. We use the actual transferred amount in case of transfer fees.\n uint256 originAmount = _takeBridgedUserAsset(params.originToken, params.originAmount);\n\n // Track the amount of origin token owed to protocol.\n uint256 originFeeAmount = 0;\n if (protocolFeeRate \u003e 0) {\n originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n // The Relayer filling this request will be paid the originAmount after fees.\n // Note: the protocol fees will be accumulated only when the Relayer claims the origin collateral.\n originAmount -= originFeeAmount;\n }\n\n // Hash the bridge request and set the initial status to REQUESTED.\n bytes memory request = BridgeTransactionV2Lib.encodeV2(\n BridgeTransactionV2({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n deadline: params.deadline,\n // Increment the sender's nonce on every bridge.\n nonce: senderNonces[params.sender]++,\n exclusivityRelayer: paramsV2.quoteRelayer,\n // We checked exclusivityEndTime to be in range [0 .. params.deadline] above, so can safely cast.\n exclusivityEndTime: uint256(exclusivityEndTime),\n zapNative: paramsV2.zapNative,\n zapData: paramsV2.zapData\n })\n );\n bytes32 transactionId = keccak256(request);\n // Note: the tx status will be updated throughout the tx lifecycle, while destChainId is set once here.\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n bridgeTxDetails[transactionId].destChainId = params.dstChainId;\n\n emit BridgeRequested({\n transactionId: transactionId,\n sender: params.sender,\n request: request,\n destChainId: params.dstChainId,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n sendChainGas: paramsV2.zapNative != 0\n });\n emit BridgeQuoteDetails(transactionId, paramsV2.quoteId);\n }\n\n /// @inheritdoc IFastBridgeV2\n function cancelV2(bytes calldata request) public {\n // Decode the request and check that it could be cancelled.\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n\n // Can only cancel a REQUESTED transaction after its deadline expires.\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n if ($.status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n\n // Permissionless cancel is only allowed after `cancelDelay` on top of the deadline.\n uint256 deadline = request.deadline();\n if (!hasRole(CANCELER_ROLE, msg.sender)) deadline += cancelDelay;\n if (block.timestamp \u003c= deadline) revert DeadlineNotExceeded();\n\n // Update status to REFUNDED.\n // Note: this is a storage write.\n $.status = BridgeStatus.REFUNDED;\n\n // Return the full amount (collateral + protocol fees) to the original sender.\n // The protocol fees are only accumulated when the transaction is claimed, so we don't need to update them here.\n address to = request.originSender();\n address token = request.originToken();\n uint256 amount = request.originAmount() + request.originFeeAmount();\n\n // Emit the event before any external calls.\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n\n // Return the funds to the original sender as last transaction action.\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(to), amount);\n } else {\n IERC20(token).safeTransfer(to, amount);\n }\n }\n\n // ═══════════════════════════════════════ PUBLIC MUTABLE (AGENT FACING) ═══════════════════════════════════════════\n\n /// @inheritdoc IFastBridgeV2\n function relayV2(bytes calldata request, address relayer) public payable {\n // Decode the request and check that it could be relayed.\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n _validateRelayParams(request, transactionId, relayer);\n\n // Mark the bridge request as relayed by saving the relayer and the block details.\n bridgeRelayDetails[transactionId].blockNumber = uint48(block.number);\n bridgeRelayDetails[transactionId].blockTimestamp = uint48(block.timestamp);\n bridgeRelayDetails[transactionId].relayer = relayer;\n\n // Transfer tokens to recipient on destination chain and trigger Zap if requested.\n address to = request.destRecipient();\n address token = request.destToken();\n uint256 amount = request.destAmount();\n uint256 zapNative = request.zapNative();\n\n // Emit the event before any external calls.\n emit BridgeRelayed({\n transactionId: transactionId,\n relayer: relayer,\n to: to,\n originChainId: request.originChainId(),\n originToken: request.originToken(),\n destToken: token,\n originAmount: request.originAmount(),\n destAmount: amount,\n chainGasAmount: zapNative\n });\n\n // All state changes have been done at this point, can proceed to the external calls.\n // This follows the checks-effects-interactions pattern to mitigate potential reentrancy attacks.\n if (token == NATIVE_GAS_TOKEN) {\n // For the native gas token, additional zapNative is not allowed.\n if (zapNative != 0) revert ZapNativeNotSupported();\n // Check that the correct msg.value was sent.\n if (msg.value != amount) revert MsgValueIncorrect();\n // Don't do a native transfer yet: we will handle it alongside the Zap below.\n } else {\n // For ERC20s, we check that the correct msg.value was sent.\n if (msg.value != zapNative) revert MsgValueIncorrect();\n // We need to transfer the tokens from the Relayer to the recipient first before performing an\n // optional post-transfer Zap.\n IERC20(token).safeTransferFrom(msg.sender, to, amount);\n }\n // At this point we have done:\n // - Transferred the requested amount of ERC20 tokens to the recipient.\n // At this point we have confirmed:\n // - For ERC20s: msg.value matches the requested zapNative amount.\n // - For the native gas token: msg.value matches the requested destAmount.\n // Remaining optional things to do:\n // - Forward the full msg.value to the recipient (if non-zero).\n // - Trigger a Zap (if zapData is present).\n bytes calldata zapData = request.zapData();\n if (zapData.length != 0) {\n // Zap Data is present: Zap has been requested by the recipient. Trigger it forwarding the full msg.value.\n _triggerZapWithChecks({recipient: to, token: token, amount: amount, zapData: zapData});\n // Note: if token has a fee on transfers, the recipient will have received less than `amount`.\n // This is a very niche edge case and should be handled by the recipient contract.\n } else if (msg.value != 0) {\n // Zap Data is missing, but msg.value was sent. This could happen in two different cases:\n // - Relay with the native gas token is happening.\n // - Relay with ERC20 is happening, with a `zapNative \u003e 0` request.\n // In both cases, we need to transfer the full msg.value to the recipient.\n Address.sendValue(payable(to), msg.value);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function proveV2(bytes32 transactionId, bytes32 destTxHash, address relayer) public onlyRole(PROVER_ROLE) {\n // Can only prove a REQUESTED transaction.\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n if ($.status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n\n // Update status to RELAYER_PROVED and store the proof details.\n // Note: these are storage writes.\n $.status = BridgeStatus.RELAYER_PROVED;\n $.proofBlockTimestamp = uint56(block.timestamp);\n $.proofRelayer = relayer;\n\n emit BridgeProofProvided(transactionId, relayer, destTxHash);\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes calldata request, address to) public {\n // Decode the request and check that it could be claimed.\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n\n // Aggregate the read operations from the same storage slot.\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n address proofRelayer = $.proofRelayer;\n BridgeStatus status = $.status;\n uint56 proofBlockTimestamp = $.proofBlockTimestamp;\n\n // Can only claim a RELAYER_PROVED transaction after the dispute period.\n if (status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(proofBlockTimestamp) \u003c= DISPUTE_PERIOD) revert DisputePeriodNotPassed();\n if (to == address(0)) {\n // Anyone could claim the funds to the proven relayer on their behalf.\n to = proofRelayer;\n } else if (proofRelayer != msg.sender) {\n // Only the proven relayer could specify an address to claim the funds to.\n revert SenderIncorrect();\n }\n\n // Update status to RELAYER_CLAIMED and transfer the origin collateral to the specified claim address.\n // Note: this is a storage write.\n $.status = BridgeStatus.RELAYER_CLAIMED;\n\n // Accumulate protocol fees if origin fee amount exists.\n address token = request.originToken();\n uint256 amount = request.originAmount();\n uint256 originFeeAmount = request.originFeeAmount();\n if (originFeeAmount \u003e 0) protocolFees[token] += originFeeAmount;\n\n // Emit the event before any external calls.\n emit BridgeDepositClaimed(transactionId, proofRelayer, to, token, amount);\n\n // Complete the relayer claim as the last transaction action.\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(to), amount);\n } else {\n IERC20(token).safeTransfer(to, amount);\n }\n }\n\n // ═══════════════════════════════════════════════ PUBLIC VIEWS ════════════════════════════════════════════════════\n\n /// @inheritdoc IFastBridgeV2\n function bridgeStatuses(bytes32 transactionId) public view returns (BridgeStatus status) {\n return bridgeTxDetails[transactionId].status;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeProofs(bytes32 transactionId) public view returns (uint96 timestamp, address relayer) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n timestamp = $.proofBlockTimestamp;\n relayer = $.proofRelayer;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeRelays(bytes32 transactionId) public view returns (bool) {\n // This transaction has been relayed if the relayer address is recorded.\n return bridgeRelayDetails[transactionId].relayer != address(0);\n }\n\n // ═════════════════════════════════════════════ INTERNAL METHODS ══════════════════════════════════════════════════\n\n /// @notice Takes the bridged asset from the user into FastBridgeV2 custody. The asset will later be\n /// claimed by the relayer who completed the relay on the destination chain, or returned to the user\n /// via the cancel function if no relay is completed.\n function _takeBridgedUserAsset(address token, uint256 amount) internal returns (uint256 amountTaken) {\n if (token == NATIVE_GAS_TOKEN) {\n // For the native gas token, we just need to check that the supplied msg.value is correct.\n // Supplied `msg.value` is already in FastBridgeV2 custody.\n if (amount != msg.value) revert MsgValueIncorrect();\n amountTaken = msg.value;\n } else {\n // For ERC20s, token is explicitly transferred from the user to FastBridgeV2.\n // We don't allow non-zero `msg.value` to avoid extra funds from being stuck in FastBridgeV2.\n if (msg.value != 0) revert MsgValueIncorrect();\n // Throw an explicit error if the provided token address is not a contract.\n if (token.code.length == 0) revert TokenNotContract();\n\n // Use the balance difference as the amount taken in case of fee on transfer tokens.\n amountTaken = IERC20(token).balanceOf(address(this));\n IERC20(token).safeTransferFrom(msg.sender, address(this), amount);\n amountTaken = IERC20(token).balanceOf(address(this)) - amountTaken;\n }\n }\n\n /// @notice Calls the recipient's hook function with the specified zapData and validates\n /// the returned value.\n function _triggerZapWithChecks(address recipient, address token, uint256 amount, bytes calldata zapData) internal {\n // Call the recipient's hook function with the specified zapData, bubbling any revert messages.\n bytes memory returnData = Address.functionCallWithValue({\n target: recipient,\n data: abi.encodeCall(IZapRecipient.zap, (token, amount, zapData)),\n // Note: see `relay()` for reasoning behind passing msg.value.\n value: msg.value\n });\n\n // Explicit revert if no return data at all.\n if (returnData.length == 0) revert RecipientNoReturnValue();\n // Check that exactly a single return value was returned.\n if (returnData.length != 32) revert RecipientIncorrectReturnValue();\n // Return value should be abi-encoded hook function selector.\n if (bytes32(returnData) != bytes32(IZapRecipient.zap.selector)) {\n revert RecipientIncorrectReturnValue();\n }\n }\n\n /// @notice Calculates the time elapsed since a proof was submitted.\n /// @dev The proof.timestamp stores block timestamps as uint56 for gas optimization.\n /// _timeSince(proof) handles timestamp rollover when block.timestamp \u003e type(uint56).max but\n /// proof.timestamp \u003c type(uint56).max via an unchecked statement.\n /// @param proofBlockTimestamp The block timestamp when the proof was submitted.\n /// @return delta The time elapsed since proof submission.\n function _timeSince(uint56 proofBlockTimestamp) internal view returns (uint256 delta) {\n unchecked {\n delta = uint56(block.timestamp) - proofBlockTimestamp;\n }\n }\n\n /// @notice Validates all parameters required for a bridge transaction.\n /// @dev This function's complexity cannot be reduced due to the number of required checks,\n /// so we disable the code-complexity rule.\n // solhint-disable-next-line code-complexity\n function _validateBridgeParams(\n BridgeParams memory params,\n BridgeParamsV2 memory paramsV2,\n int256 exclusivityEndTime\n )\n internal\n view\n {\n // Check V1 (legacy) params.\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.sender == address(0) || params.to == address(0)) revert ZeroAddress();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n\n // Check V2 params.\n if (paramsV2.zapData.length \u003e MAX_ZAP_DATA_LENGTH) revert ZapDataLengthAboveMax();\n if (paramsV2.zapNative != 0 \u0026\u0026 params.destToken == NATIVE_GAS_TOKEN) {\n revert ZapNativeNotSupported();\n }\n\n // exclusivityEndTime must be in range [0 .. params.deadline].\n if (exclusivityEndTime \u003c 0 || exclusivityEndTime \u003e int256(params.deadline)) {\n revert ExclusivityParamsIncorrect();\n }\n }\n\n /// @notice Validates all parameters required for a relay transaction.\n function _validateRelayParams(bytes calldata request, bytes32 transactionId, address relayer) internal view {\n if (relayer == address(0)) revert ZeroAddress();\n // Check that the transaction has not been relayed yet and is for the current chain.\n if (bridgeRelays(transactionId)) revert TransactionRelayed();\n if (request.destChainId() != block.chainid) revert ChainIncorrect();\n // Check that the deadline for relay to happen has not passed yet.\n if (block.timestamp \u003e request.deadline()) revert DeadlineExceeded();\n // Check the exclusivity period, if it was specified and is still ongoing.\n address exclRelayer = request.exclusivityRelayer();\n if (exclRelayer != address(0) \u0026\u0026 exclRelayer != relayer \u0026\u0026 block.timestamp \u003c= request.exclusivityEndTime()) {\n revert ExclusivityPeriodNotPassed();\n }\n }\n}\n","language":"Solidity","languageVersion":"0.8.24","compilerVersion":"0.8.24","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"","srcMapRuntime":"","abiDefinition":[],"userDoc":{"kind":"user","methods":{},"version":1},"developerDoc":{"details":"Provides information about the current execution context, including the sender of the transaction and its data. While these are generally available via msg.sender and msg.data, they should not be accessed in such a direct manner, since when dealing with meta-transactions the account sending and paying for execution may not be the actual sender (as far as an application is concerned). This contract is only required for intermediate, library-like contracts.","kind":"dev","methods":{},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[],\"devdoc\":{\"details\":\"Provides information about the current execution context, including the sender of the transaction and its data. While these are generally available via msg.sender and msg.data, they should not be accessed in such a direct manner, since when dealing with meta-transactions the account sending and paying for execution may not be the actual sender (as far as an application is concerned). This contract is only required for intermediate, library-like contracts.\",\"kind\":\"dev\",\"methods\":{},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeV2.sol\":\"Context\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeV2.sol\":{\"keccak256\":\"0xaab2ee7357681726f0faf799a48ddfbf45fb4da93b69abf61c33dde92b29b74d\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://673391bff9569efc0f9bd99e0e6fece0bc8e8af1f052bb071b407b267a17b3b5\",\"dweb:/ipfs/QmdQQZ6DxpJYhfpinwU5WjLugr2f6qP8h68b5GerhSMQ4j\"]}},\"version\":1}"},"hashes":{}},"solidity/FastBridgeV2.sol:ERC165":{"code":"0x","runtime-code":"0x","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.24 ^0.8.20 ^0.8.4;\n\n// contracts/interfaces/IAdminV2.sol\n\ninterface IAdminV2 {\n event CancelDelayUpdated(uint256 oldCancelDelay, uint256 newCancelDelay);\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n /// @notice Allows the governor to set the cancel delay. The cancel delay is the time period after the transaction\n /// deadline during which a transaction can be permissionlessly cancelled if it hasn't been proven by any Relayer.\n function setCancelDelay(uint256 newCancelDelay) external;\n\n /// @notice Allows the governor to set the protocol fee rate. The protocol fee is taken from the origin\n /// amount and is only applied to completed and claimed transactions.\n /// @dev The protocol fee is abstracted away from the relayers; they always operate using the amounts after fees.\n /// The origin amount they see in the emitted log is what they get credited with.\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n /// @notice Allows the governor to withdraw the accumulated protocol fees from the contract.\n function sweepProtocolFees(address token, address recipient) external;\n}\n\n// contracts/interfaces/IAdminV2Errors.sol\n\ninterface IAdminV2Errors {\n error CancelDelayBelowMin();\n error FeeRateAboveMax();\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IFastBridgeV2Errors.sol\n\ninterface IFastBridgeV2Errors {\n error AmountIncorrect();\n error ChainIncorrect();\n error ExclusivityParamsIncorrect();\n error MsgValueIncorrect();\n error SenderIncorrect();\n error StatusIncorrect();\n error TokenNotContract();\n error ZapDataLengthAboveMax();\n error ZapNativeNotSupported();\n error ZeroAddress();\n\n error RecipientIncorrectReturnValue();\n error RecipientNoReturnValue();\n\n error DeadlineExceeded();\n error DeadlineNotExceeded();\n error DeadlineTooShort();\n error DisputePeriodNotPassed();\n error DisputePeriodPassed();\n error ExclusivityPeriodNotPassed();\n\n error TransactionRelayed();\n}\n\n// contracts/interfaces/IMulticallTarget.sol\n\n/// @notice Interface for a contract that supports multiple calls from the same caller. Inspired by MulticallV3:\n/// https://github.com/mds1/multicall/blob/master/src/Multicall3.sol\ninterface IMulticallTarget {\n struct Result {\n bool success;\n bytes returnData;\n }\n\n /// @notice Executes multiple calls to this contract in a single transaction while preserving msg.sender.\n /// Return data from the calls is discarded.\n /// @dev This method is non-payable, so only calls with msg.value of 0 can be batched.\n /// If ignoreReverts is set to true, reverted calls will be skipped.\n /// Otherwise, the entire batch will revert with the original revert reason.\n /// @param data List of ABI-encoded calldata for the calls to execute\n /// @param ignoreReverts Whether to skip calls that revert\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external;\n\n /// @notice Executes multiple calls to this contract in a single transaction while preserving msg.sender.\n /// Return data from each call is preserved.\n /// @dev This method is non-payable, so only calls with msg.value of 0 can be batched.\n /// If ignoreReverts is set to true, reverted calls will be skipped.\n /// Otherwise, the entire batch will revert with the original revert reason.\n /// @param data List of ABI-encoded calldata for the calls to execute\n /// @param ignoreReverts Whether to skip calls that revert\n /// @return results List of results from the calls, each containing (success, returnData)\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results);\n}\n\n// contracts/interfaces/IZapRecipient.sol\n\n/// @notice Interface for contracts that can perform Zap operations. Such contracts could be used as Recipients\n/// in a FastBridge transaction that includes a Zap operation. The Zap Data should include instructions on how\n/// exactly the Zap operation should be executed, which would typically include the target address and calldata\n/// to use. The exact implementation of the Zap Data encoding is up to the Recipient contract.\ninterface IZapRecipient {\n /// @notice Performs a Zap operation with the given token and amount according to the provided Zap data.\n /// @param token The address of the token being used for the Zap operation.\n /// @param amount The amount of tokens to be used.\n /// @param zapData The encoded data specifying how the Zap operation should be executed.\n /// @return The function selector to indicate successful execution.\n function zap(address token, uint256 amount, bytes memory zapData) external payable returns (bytes4);\n}\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// contracts/interfaces/IFastBridgeV2.sol\n\ninterface IFastBridgeV2 is IFastBridge {\n enum BridgeStatus {\n NULL, // Doesn't exist yet.\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n struct BridgeTxDetails {\n BridgeStatus status;\n uint32 destChainId;\n uint56 proofBlockTimestamp;\n address proofRelayer;\n }\n\n struct BridgeRelay {\n uint48 blockNumber;\n uint48 blockTimestamp;\n address relayer;\n }\n\n /// @notice New params introduced in the FastBridgeV2.\n /// We are passing fields from the older BridgeParams struct outside of this struct for backwards compatibility.\n /// Note: quoteRelayer and quoteExclusivitySeconds are either both zero (indicating no exclusivity)\n /// or both non-zero (indicating exclusivity for the given period).\n /// Note: zapNative \u003e 0 can NOT be used with destToken = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE (native token)\n /// @param quoteRelayer Relayer that provided the quote for the transaction\n /// @param quoteExclusivitySeconds Period of time the quote relayer is guaranteed exclusivity after user's deposit\n /// @param quoteId Unique quote identifier used for tracking the quote\n /// @param zapNative ETH value to send to the recipient (if any)\n /// @param zapData Parameters for the Zap to the destination recipient (if any)\n struct BridgeParamsV2 {\n address quoteRelayer;\n int256 quoteExclusivitySeconds;\n bytes quoteId;\n uint256 zapNative;\n bytes zapData;\n }\n\n /// @notice Updated bridge transaction struct to include parameters introduced in FastBridgeV2.\n /// Note: only `exclusivityRelayer` can fill such a transaction until `exclusivityEndTime`.\n struct BridgeTransactionV2 {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n // Note: sendChainGas flag from V1 is deprecated\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n address exclusivityRelayer;\n uint256 exclusivityEndTime;\n uint256 zapNative; // ETH value to send to the recipient (if any)\n bytes zapData; // data to pass for the Zap action (if any)\n }\n\n event BridgeQuoteDetails(bytes32 indexed transactionId, bytes quoteId);\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability\n /// to provide temporary exclusivity fill rights for the quote relayer.\n /// @param params The parameters required to bridge\n /// @param paramsV2 The parameters for exclusivity fill rights (optional, can be left empty)\n function bridgeV2(BridgeParams memory params, BridgeParamsV2 memory paramsV2) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function relayV2(bytes memory request, address relayer) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param transactionId The transaction id associated with the encoded bridge transaction to prove\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function proveV2(bytes32 transactionId, bytes32 destTxHash, address relayer) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital.\n /// @notice Can only send funds to the relayer address on the proof.\n /// @param request The encoded bridge transaction to claim on origin chain\n function claimV2(bytes memory request) external;\n\n /// @notice Cancels an outstanding bridge transaction in case optimistic bridging failed and returns the full amount\n /// to the original sender.\n /// @param request The encoded bridge transaction to refund\n function cancelV2(bytes memory request) external;\n\n /// @notice Checks if a transaction has been relayed\n /// @param transactionId The ID of the transaction to check\n /// @return True if the transaction has been relayed, false otherwise\n function bridgeRelays(bytes32 transactionId) external view returns (bool);\n\n /// @notice Returns the status of a bridge transaction\n /// @param transactionId The ID of the bridge transaction\n /// @return BridgeStatus Status of the bridge transaction\n function bridgeStatuses(bytes32 transactionId) external view returns (BridgeStatus);\n\n /// @notice Returns the timestamp and relayer of a bridge proof\n /// @param transactionId The ID of the bridge transaction\n /// @return timestamp The timestamp of the bridge proof\n /// @return relayer The relayer address of the bridge proof\n function bridgeProofs(bytes32 transactionId) external view returns (uint96 timestamp, address relayer);\n\n /// @notice Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\n /// @param request The bridge request to decode\n function getBridgeTransactionV2(bytes memory request) external view returns (BridgeTransactionV2 memory);\n}\n\n// contracts/utils/MulticallTarget.sol\n\n// solhint-disable avoid-low-level-calls\n/// @notice Abstract contract template that supports batched calls while preserving msg.sender.\n/// Only calls with msg.value of 0 can be batched.\nabstract contract MulticallTarget is IMulticallTarget {\n error MulticallTarget__UndeterminedRevert();\n\n /// @inheritdoc IMulticallTarget\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external {\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\n if (!success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(result);\n }\n }\n }\n\n /// @inheritdoc IMulticallTarget\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results)\n {\n results = new Result[](data.length);\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (results[i].success, results[i].returnData) = address(this).delegatecall(data[i]);\n if (!results[i].success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(results[i].returnData);\n }\n }\n }\n\n /// @dev Bubbles the revert message from the underlying call.\n /// Note: preserves the same custom error or revert string, if one was used.\n /// Source: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v5.0.2/contracts/utils/Address.sol#L143-L158\n function _bubbleRevert(bytes memory returnData) internal pure {\n // Look for revert reason and bubble it up if present\n if (returnData.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n // solhint-disable-next-line no-inline-assembly\n assembly {\n let returndata_size := mload(returnData)\n revert(add(32, returnData), returndata_size)\n }\n } else {\n revert MulticallTarget__UndeterminedRevert();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// contracts/libs/BridgeTransactionV2.sol\n\n// solhint-disable no-inline-assembly\nlibrary BridgeTransactionV2Lib {\n uint16 internal constant VERSION = 2;\n\n // Offsets of the fields in the packed BridgeTransactionV2 struct\n // uint16 version [000 .. 002)\n // uint32 originChainId [002 .. 006)\n // uint32 destChainId [006 .. 010)\n // address originSender [010 .. 030)\n // address destRecipient [030 .. 050)\n // address originToken [050 .. 070)\n // address destToken [070 .. 090)\n // uint256 originAmount [090 .. 122)\n // uint256 destAmount [122 .. 154)\n // uint256 originFeeAmount [154 .. 186)\n // uint256 deadline [186 .. 218)\n // uint256 nonce [218 .. 250)\n // address exclusivityRelayer [250 .. 270)\n // uint256 exclusivityEndTime [270 .. 302)\n // uint256 zapNative [302 .. 334)\n // bytes zapData [334 .. ***)\n\n // forgefmt: disable-start\n uint256 private constant OFFSET_ORIGIN_CHAIN_ID = 2;\n uint256 private constant OFFSET_DEST_CHAIN_ID = 6;\n uint256 private constant OFFSET_ORIGIN_SENDER = 10;\n uint256 private constant OFFSET_DEST_RECIPIENT = 30;\n uint256 private constant OFFSET_ORIGIN_TOKEN = 50;\n uint256 private constant OFFSET_DEST_TOKEN = 70;\n uint256 private constant OFFSET_ORIGIN_AMOUNT = 90;\n uint256 private constant OFFSET_DEST_AMOUNT = 122;\n uint256 private constant OFFSET_ORIGIN_FEE_AMOUNT = 154;\n uint256 private constant OFFSET_DEADLINE = 186;\n uint256 private constant OFFSET_NONCE = 218;\n uint256 private constant OFFSET_EXCLUSIVITY_RELAYER = 250;\n uint256 private constant OFFSET_EXCLUSIVITY_END_TIME = 270;\n uint256 private constant OFFSET_ZAP_NATIVE = 302;\n uint256 private constant OFFSET_ZAP_DATA = 334;\n // forgefmt: disable-end\n\n error BridgeTransactionV2__InvalidEncodedTx();\n error BridgeTransactionV2__UnsupportedVersion(uint16 version);\n\n /// @notice Validates that the encoded transaction is a tightly packed encoded payload for BridgeTransactionV2.\n /// @dev Checks the minimum length and the version, use this function before decoding any of the fields.\n function validateV2(bytes calldata encodedTx) internal pure {\n // Check the minimum length: must at least include all static fields.\n if (encodedTx.length \u003c OFFSET_ZAP_DATA) revert BridgeTransactionV2__InvalidEncodedTx();\n // Once we validated the length, we can be sure that the version field is present.\n uint16 version_ = version(encodedTx);\n if (version_ != VERSION) revert BridgeTransactionV2__UnsupportedVersion(version_);\n }\n\n /// @notice Encodes the BridgeTransactionV2 struct by tightly packing the fields.\n /// @dev `abi.decode` will not work as a result of the tightly packed fields. Use `decodeV2` to decode instead.\n function encodeV2(IFastBridgeV2.BridgeTransactionV2 memory bridgeTx) internal pure returns (bytes memory) {\n // We split the encoding into two parts to avoid stack-too-deep error\n bytes memory firstPart = abi.encodePacked(\n VERSION,\n bridgeTx.originChainId,\n bridgeTx.destChainId,\n bridgeTx.originSender,\n bridgeTx.destRecipient,\n bridgeTx.originToken,\n bridgeTx.destToken,\n bridgeTx.originAmount\n );\n return abi.encodePacked(\n firstPart,\n bridgeTx.destAmount,\n bridgeTx.originFeeAmount,\n // Note: we skip the deprecated `sendChainGas` flag, which was present in BridgeTransaction V1\n bridgeTx.deadline,\n bridgeTx.nonce,\n // New V2 fields: exclusivity\n bridgeTx.exclusivityRelayer,\n bridgeTx.exclusivityEndTime,\n // New V2 fields: Zap\n bridgeTx.zapNative,\n bridgeTx.zapData\n );\n }\n\n /// @notice Decodes the BridgeTransactionV2 struct from the encoded transaction.\n /// @dev Encoded BridgeTransactionV2 struct must be tightly packed.\n /// Use `validateV2` before decoding to ensure the encoded transaction is valid.\n function decodeV2(bytes calldata encodedTx)\n internal\n pure\n returns (IFastBridgeV2.BridgeTransactionV2 memory bridgeTx)\n {\n bridgeTx.originChainId = originChainId(encodedTx);\n bridgeTx.destChainId = destChainId(encodedTx);\n bridgeTx.originSender = originSender(encodedTx);\n bridgeTx.destRecipient = destRecipient(encodedTx);\n bridgeTx.originToken = originToken(encodedTx);\n bridgeTx.destToken = destToken(encodedTx);\n bridgeTx.originAmount = originAmount(encodedTx);\n bridgeTx.destAmount = destAmount(encodedTx);\n bridgeTx.originFeeAmount = originFeeAmount(encodedTx);\n bridgeTx.deadline = deadline(encodedTx);\n bridgeTx.nonce = nonce(encodedTx);\n bridgeTx.exclusivityRelayer = exclusivityRelayer(encodedTx);\n bridgeTx.exclusivityEndTime = exclusivityEndTime(encodedTx);\n bridgeTx.zapNative = zapNative(encodedTx);\n bridgeTx.zapData = zapData(encodedTx);\n }\n\n /// @notice Extracts the version from the encoded transaction.\n function version(bytes calldata encodedTx) internal pure returns (uint16 version_) {\n // Load 32 bytes from the start and shift it 240 bits to the right to get the highest 16 bits.\n assembly {\n version_ := shr(240, calldataload(encodedTx.offset))\n }\n }\n\n /// @notice Extracts the origin chain ID from the encoded transaction.\n function originChainId(bytes calldata encodedTx) internal pure returns (uint32 originChainId_) {\n // Load 32 bytes from the offset and shift it 224 bits to the right to get the highest 32 bits.\n assembly {\n originChainId_ := shr(224, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_CHAIN_ID)))\n }\n }\n\n /// @notice Extracts the destination chain ID from the encoded transaction.\n function destChainId(bytes calldata encodedTx) internal pure returns (uint32 destChainId_) {\n // Load 32 bytes from the offset and shift it 224 bits to the right to get the highest 32 bits.\n assembly {\n destChainId_ := shr(224, calldataload(add(encodedTx.offset, OFFSET_DEST_CHAIN_ID)))\n }\n }\n\n /// @notice Extracts the origin sender from the encoded transaction.\n function originSender(bytes calldata encodedTx) internal pure returns (address originSender_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n originSender_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_SENDER)))\n }\n }\n\n /// @notice Extracts the destination recipient from the encoded transaction.\n function destRecipient(bytes calldata encodedTx) internal pure returns (address destRecipient_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n destRecipient_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_DEST_RECIPIENT)))\n }\n }\n\n /// @notice Extracts the origin token from the encoded transaction.\n function originToken(bytes calldata encodedTx) internal pure returns (address originToken_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n originToken_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_TOKEN)))\n }\n }\n\n /// @notice Extracts the destination token from the encoded transaction.\n function destToken(bytes calldata encodedTx) internal pure returns (address destToken_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n destToken_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_DEST_TOKEN)))\n }\n }\n\n /// @notice Extracts the origin amount from the encoded transaction.\n function originAmount(bytes calldata encodedTx) internal pure returns (uint256 originAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n originAmount_ := calldataload(add(encodedTx.offset, OFFSET_ORIGIN_AMOUNT))\n }\n }\n\n /// @notice Extracts the destination amount from the encoded transaction.\n function destAmount(bytes calldata encodedTx) internal pure returns (uint256 destAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n destAmount_ := calldataload(add(encodedTx.offset, OFFSET_DEST_AMOUNT))\n }\n }\n\n /// @notice Extracts the origin fee amount from the encoded transaction.\n function originFeeAmount(bytes calldata encodedTx) internal pure returns (uint256 originFeeAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n originFeeAmount_ := calldataload(add(encodedTx.offset, OFFSET_ORIGIN_FEE_AMOUNT))\n }\n }\n\n /// @notice Extracts the deadline from the encoded transaction.\n function deadline(bytes calldata encodedTx) internal pure returns (uint256 deadline_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n deadline_ := calldataload(add(encodedTx.offset, OFFSET_DEADLINE))\n }\n }\n\n /// @notice Extracts the nonce from the encoded transaction.\n function nonce(bytes calldata encodedTx) internal pure returns (uint256 nonce_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n nonce_ := calldataload(add(encodedTx.offset, OFFSET_NONCE))\n }\n }\n\n /// @notice Extracts the exclusivity relayer from the encoded transaction.\n function exclusivityRelayer(bytes calldata encodedTx) internal pure returns (address exclusivityRelayer_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n exclusivityRelayer_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_EXCLUSIVITY_RELAYER)))\n }\n }\n\n /// @notice Extracts the exclusivity end time from the encoded transaction.\n function exclusivityEndTime(bytes calldata encodedTx) internal pure returns (uint256 exclusivityEndTime_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n exclusivityEndTime_ := calldataload(add(encodedTx.offset, OFFSET_EXCLUSIVITY_END_TIME))\n }\n }\n\n /// @notice Extracts the Zap's native value from the encoded transaction.\n function zapNative(bytes calldata encodedTx) internal pure returns (uint256 zapNative_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n zapNative_ := calldataload(add(encodedTx.offset, OFFSET_ZAP_NATIVE))\n }\n }\n\n /// @notice Extracts the Zap's data from the encoded transaction.\n function zapData(bytes calldata encodedTx) internal pure returns (bytes calldata zapData_) {\n zapData_ = encodedTx[OFFSET_ZAP_DATA:];\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/AdminV2.sol\n\n// ════════════════════════════════════════════════ INTERFACES ═════════════════════════════════════════════════════\n\n// ═════════════════════════════════════════════ EXTERNAL IMPORTS ══════════════════════════════════════════════════\n\n/// @title AdminV2\n/// @notice Provides administrative functions and controls for managing the FastBridgeV2 contract,\n/// including access control and configuration settings.\ncontract AdminV2 is AccessControlEnumerable, IAdminV2, IAdminV2Errors {\n using SafeERC20 for IERC20;\n\n /// @notice The address reserved for the native gas token (ETH on Ethereum and most L2s, AVAX on Avalanche, etc.).\n address public constant NATIVE_GAS_TOKEN = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice The role identifier for the Quoter API's off-chain authentication.\n /// @dev Only addresses with this role can post FastBridge quotes to the API.\n bytes32 public constant QUOTER_ROLE = keccak256(\"QUOTER_ROLE\");\n\n /// @notice The role identifier for the Prover's on-chain authentication in FastBridge.\n /// @dev Only addresses with this role can provide proofs that a FastBridge request has been relayed.\n bytes32 public constant PROVER_ROLE = keccak256(\"PROVER_ROLE\");\n\n /// @notice The role identifier for the Guard's on-chain authentication in FastBridge.\n /// @dev Only addresses with this role can dispute submitted relay proofs during the dispute period.\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n\n /// @notice The role identifier for the Canceler's on-chain authentication in FastBridge.\n /// @dev Only addresses with this role can cancel a FastBridge transaction without the cancel delay.\n bytes32 public constant CANCELER_ROLE = keccak256(\"CANCELER_ROLE\");\n\n /// @notice The role identifier for the Governor's on-chain administrative authority.\n /// @dev Only addresses with this role can perform administrative tasks within the contract.\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n /// @notice The denominator for fee rates, representing 100%.\n uint256 public constant FEE_BPS = 1e6;\n /// @notice The maximum protocol fee rate: 1% of the origin amount.\n uint256 public constant FEE_RATE_MAX = 0.01e6;\n\n /// @notice The minimum cancel delay that can be set by the governor.\n uint256 public constant MIN_CANCEL_DELAY = 1 hours;\n /// @notice The default cancel delay set during contract deployment.\n uint256 public constant DEFAULT_CANCEL_DELAY = 1 days;\n\n /// @notice The protocol fee rate taken on the origin amount deposited in the origin chain.\n uint256 public protocolFeeRate;\n\n /// @notice The accumulated protocol fee amounts.\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice The delay period after which a transaction can be permissionlessly cancelled.\n uint256 public cancelDelay;\n\n /// @notice This variable is deprecated and should not be used.\n /// @dev Use ZapNative V2 requests instead.\n uint256 public immutable chainGasAmount = 0;\n\n constructor(address defaultAdmin) {\n _grantRole(DEFAULT_ADMIN_ROLE, defaultAdmin);\n _setCancelDelay(DEFAULT_CANCEL_DELAY);\n }\n\n /// @inheritdoc IAdminV2\n function setCancelDelay(uint256 newCancelDelay) external onlyRole(GOVERNOR_ROLE) {\n _setCancelDelay(newCancelDelay);\n }\n\n /// @inheritdoc IAdminV2\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n if (newFeeRate \u003e FEE_RATE_MAX) revert FeeRateAboveMax();\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n /// @inheritdoc IAdminV2\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n // Early exit if no accumulated fees.\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return;\n // Reset the accumulated fees first.\n protocolFees[token] = 0;\n emit FeesSwept(token, recipient, feeAmount);\n // Sweep the fees as the last transaction action.\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(recipient), feeAmount);\n } else {\n IERC20(token).safeTransfer(recipient, feeAmount);\n }\n }\n\n /// @notice Internal logic to set the cancel delay. Security checks are performed outside of this function.\n /// @dev This function is marked as private to prevent child contracts from calling it directly.\n function _setCancelDelay(uint256 newCancelDelay) private {\n if (newCancelDelay \u003c MIN_CANCEL_DELAY) revert CancelDelayBelowMin();\n uint256 oldCancelDelay = cancelDelay;\n cancelDelay = newCancelDelay;\n emit CancelDelayUpdated(oldCancelDelay, newCancelDelay);\n }\n}\n\n// contracts/FastBridgeV2.sol\n\n// ════════════════════════════════════════════════ INTERFACES ═════════════════════════════════════════════════════\n\n// ═════════════════════════════════════════════ INTERNAL IMPORTS ══════════════════════════════════════════════════\n\n// ═════════════════════════════════════════════ EXTERNAL IMPORTS ══════════════════════════════════════════════════\n\n/// @title FastBridgeV2\n/// @notice Core component of the SynapseRFQ protocol, enabling Relayers (Solvers) to fulfill bridge requests.\n/// Supports ERC20 and native gas tokens, along with the Zap feature for executing actions on the destination chain.\n/// Users interact with the off-chain Quoter API to obtain a current quote for a bridge transaction.\n/// They then submit the bridge request with the quote to this contract, depositing their assets in escrow.\n/// Relayers can fulfill requests by relaying them to the destination chain and must prove fulfillment to claim funds.\n/// Guards monitor proofs and can dispute discrepancies.\n/// Users can reclaim funds by cancelling their requests if it has not been fulfilled within the specified deadline.\ncontract FastBridgeV2 is AdminV2, MulticallTarget, IFastBridgeV2, IFastBridgeV2Errors {\n using BridgeTransactionV2Lib for bytes;\n using SafeERC20 for IERC20;\n\n /// @notice The duration of the dispute period for relayed transactions.\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice The minimum required time between transaction request and deadline.\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n /// @notice The maximum allowed length for zapData.\n uint256 public constant MAX_ZAP_DATA_LENGTH = 2 ** 16 - 1;\n\n /// @notice Maps transaction IDs to bridge details (status, destination chain ID, proof timestamp, and relayer).\n /// Note: this is only stored for transactions having local chain as the origin chain.\n mapping(bytes32 =\u003e BridgeTxDetails) public bridgeTxDetails;\n /// @notice Maps transaction IDs to relay details (block number, block timestamp, and relayer).\n /// Note: this is only stored for transactions having local chain as the destination chain.\n mapping(bytes32 =\u003e BridgeRelay) public bridgeRelayDetails;\n /// @notice Maps sender addresses to their unique bridge nonce.\n mapping(address =\u003e uint256) public senderNonces;\n\n /// @notice This variable is deprecated and should not be used.\n /// @dev Replaced by senderNonces.\n uint256 public immutable nonce = 0;\n /// @notice The block number at which this contract was deployed.\n uint256 public immutable deployBlock;\n\n /// @notice Initializes the FastBridgeV2 contract with the provided default admin,\n /// sets the default cancel delay, and records the deploy block number.\n constructor(address defaultAdmin) AdminV2(defaultAdmin) {\n deployBlock = block.number;\n }\n\n // ══════════════════════════════════════ EXTERNAL MUTABLE (USER FACING) ═══════════════════════════════════════════\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n bridgeV2({\n params: params,\n paramsV2: BridgeParamsV2({\n quoteRelayer: address(0),\n quoteExclusivitySeconds: 0,\n quoteId: bytes(\"\"),\n zapNative: 0,\n zapData: bytes(\"\")\n })\n });\n }\n\n /// Note: this function is deprecated and will be removed in a future version.\n /// @dev Replaced by `cancel`.\n /// @inheritdoc IFastBridge\n function refund(bytes calldata request) external {\n cancelV2(request);\n }\n\n // ══════════════════════════════════════ EXTERNAL MUTABLE (AGENT FACING) ══════════════════════════════════════════\n\n /// @inheritdoc IFastBridge\n function relay(bytes calldata request) external payable {\n // `relay` override will validate the request.\n relayV2({request: request, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes calldata request, bytes32 destTxHash) external {\n request.validateV2();\n proveV2({transactionId: keccak256(request), destTxHash: destTxHash, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridgeV2\n function claimV2(bytes calldata request) external {\n // `claim` override will validate the request.\n claim({request: request, to: address(0)});\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n // Aggregate the read operations from the same storage slot.\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n address disputedRelayer = $.proofRelayer;\n BridgeStatus status = $.status;\n uint56 proofBlockTimestamp = $.proofBlockTimestamp;\n\n // Can only dispute a RELAYER_PROVED transaction within the dispute period.\n if (status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(proofBlockTimestamp) \u003e DISPUTE_PERIOD) {\n revert DisputePeriodPassed();\n }\n\n // Update status to REQUESTED and delete the disputed proof details.\n // Note: these are storage writes.\n $.status = BridgeStatus.REQUESTED;\n $.proofRelayer = address(0);\n $.proofBlockTimestamp = 0;\n\n emit BridgeProofDisputed(transactionId, disputedRelayer);\n }\n\n // ══════════════════════════════════════════════ EXTERNAL VIEWS ═══════════════════════════════════════════════════\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n // The correct relayer can only claim a RELAYER_PROVED transaction after the dispute period.\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n if ($.status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if ($.proofRelayer != relayer) revert SenderIncorrect();\n\n return _timeSince($.proofBlockTimestamp) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n /// @dev This method is added to achieve backwards compatibility with decoding requests into V1 structs:\n /// - `zapNative` is partially reported as a zero/non-zero flag\n /// - `zapData` is ignored\n /// In order to process all kinds of requests use getBridgeTransactionV2 instead.\n function getBridgeTransaction(bytes calldata request) external view returns (BridgeTransaction memory) {\n // Try decoding into V2 struct first. This will revert if V1 struct is passed.\n try this.getBridgeTransactionV2(request) returns (BridgeTransactionV2 memory txV2) {\n // Note: we entirely ignore the zapData field, as it was not present in V1.\n return BridgeTransaction({\n originChainId: txV2.originChainId,\n destChainId: txV2.destChainId,\n originSender: txV2.originSender,\n destRecipient: txV2.destRecipient,\n originToken: txV2.originToken,\n destToken: txV2.destToken,\n originAmount: txV2.originAmount,\n destAmount: txV2.destAmount,\n originFeeAmount: txV2.originFeeAmount,\n sendChainGas: txV2.zapNative != 0,\n deadline: txV2.deadline,\n nonce: txV2.nonce\n });\n } catch {\n // Fallback to V1 struct.\n return abi.decode(request, (BridgeTransaction));\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function getBridgeTransactionV2(bytes calldata request) external pure returns (BridgeTransactionV2 memory) {\n request.validateV2();\n return BridgeTransactionV2Lib.decodeV2(request);\n }\n\n // ═══════════════════════════════════════ PUBLIC MUTABLE (USER FACING) ════════════════════════════════════════════\n\n /// @inheritdoc IFastBridgeV2\n function bridgeV2(BridgeParams memory params, BridgeParamsV2 memory paramsV2) public payable {\n // If relayer exclusivity is not intended for this bridge, set exclusivityEndTime to static zero.\n // Otherwise, set exclusivity to expire at the current block ts offset by quoteExclusivitySeconds.\n int256 exclusivityEndTime = 0;\n if (paramsV2.quoteRelayer != address(0)) {\n exclusivityEndTime = int256(block.timestamp) + paramsV2.quoteExclusivitySeconds;\n }\n _validateBridgeParams(params, paramsV2, exclusivityEndTime);\n\n // Transfer tokens to bridge contract. We use the actual transferred amount in case of transfer fees.\n uint256 originAmount = _takeBridgedUserAsset(params.originToken, params.originAmount);\n\n // Track the amount of origin token owed to protocol.\n uint256 originFeeAmount = 0;\n if (protocolFeeRate \u003e 0) {\n originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n // The Relayer filling this request will be paid the originAmount after fees.\n // Note: the protocol fees will be accumulated only when the Relayer claims the origin collateral.\n originAmount -= originFeeAmount;\n }\n\n // Hash the bridge request and set the initial status to REQUESTED.\n bytes memory request = BridgeTransactionV2Lib.encodeV2(\n BridgeTransactionV2({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n deadline: params.deadline,\n // Increment the sender's nonce on every bridge.\n nonce: senderNonces[params.sender]++,\n exclusivityRelayer: paramsV2.quoteRelayer,\n // We checked exclusivityEndTime to be in range [0 .. params.deadline] above, so can safely cast.\n exclusivityEndTime: uint256(exclusivityEndTime),\n zapNative: paramsV2.zapNative,\n zapData: paramsV2.zapData\n })\n );\n bytes32 transactionId = keccak256(request);\n // Note: the tx status will be updated throughout the tx lifecycle, while destChainId is set once here.\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n bridgeTxDetails[transactionId].destChainId = params.dstChainId;\n\n emit BridgeRequested({\n transactionId: transactionId,\n sender: params.sender,\n request: request,\n destChainId: params.dstChainId,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n sendChainGas: paramsV2.zapNative != 0\n });\n emit BridgeQuoteDetails(transactionId, paramsV2.quoteId);\n }\n\n /// @inheritdoc IFastBridgeV2\n function cancelV2(bytes calldata request) public {\n // Decode the request and check that it could be cancelled.\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n\n // Can only cancel a REQUESTED transaction after its deadline expires.\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n if ($.status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n\n // Permissionless cancel is only allowed after `cancelDelay` on top of the deadline.\n uint256 deadline = request.deadline();\n if (!hasRole(CANCELER_ROLE, msg.sender)) deadline += cancelDelay;\n if (block.timestamp \u003c= deadline) revert DeadlineNotExceeded();\n\n // Update status to REFUNDED.\n // Note: this is a storage write.\n $.status = BridgeStatus.REFUNDED;\n\n // Return the full amount (collateral + protocol fees) to the original sender.\n // The protocol fees are only accumulated when the transaction is claimed, so we don't need to update them here.\n address to = request.originSender();\n address token = request.originToken();\n uint256 amount = request.originAmount() + request.originFeeAmount();\n\n // Emit the event before any external calls.\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n\n // Return the funds to the original sender as last transaction action.\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(to), amount);\n } else {\n IERC20(token).safeTransfer(to, amount);\n }\n }\n\n // ═══════════════════════════════════════ PUBLIC MUTABLE (AGENT FACING) ═══════════════════════════════════════════\n\n /// @inheritdoc IFastBridgeV2\n function relayV2(bytes calldata request, address relayer) public payable {\n // Decode the request and check that it could be relayed.\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n _validateRelayParams(request, transactionId, relayer);\n\n // Mark the bridge request as relayed by saving the relayer and the block details.\n bridgeRelayDetails[transactionId].blockNumber = uint48(block.number);\n bridgeRelayDetails[transactionId].blockTimestamp = uint48(block.timestamp);\n bridgeRelayDetails[transactionId].relayer = relayer;\n\n // Transfer tokens to recipient on destination chain and trigger Zap if requested.\n address to = request.destRecipient();\n address token = request.destToken();\n uint256 amount = request.destAmount();\n uint256 zapNative = request.zapNative();\n\n // Emit the event before any external calls.\n emit BridgeRelayed({\n transactionId: transactionId,\n relayer: relayer,\n to: to,\n originChainId: request.originChainId(),\n originToken: request.originToken(),\n destToken: token,\n originAmount: request.originAmount(),\n destAmount: amount,\n chainGasAmount: zapNative\n });\n\n // All state changes have been done at this point, can proceed to the external calls.\n // This follows the checks-effects-interactions pattern to mitigate potential reentrancy attacks.\n if (token == NATIVE_GAS_TOKEN) {\n // For the native gas token, additional zapNative is not allowed.\n if (zapNative != 0) revert ZapNativeNotSupported();\n // Check that the correct msg.value was sent.\n if (msg.value != amount) revert MsgValueIncorrect();\n // Don't do a native transfer yet: we will handle it alongside the Zap below.\n } else {\n // For ERC20s, we check that the correct msg.value was sent.\n if (msg.value != zapNative) revert MsgValueIncorrect();\n // We need to transfer the tokens from the Relayer to the recipient first before performing an\n // optional post-transfer Zap.\n IERC20(token).safeTransferFrom(msg.sender, to, amount);\n }\n // At this point we have done:\n // - Transferred the requested amount of ERC20 tokens to the recipient.\n // At this point we have confirmed:\n // - For ERC20s: msg.value matches the requested zapNative amount.\n // - For the native gas token: msg.value matches the requested destAmount.\n // Remaining optional things to do:\n // - Forward the full msg.value to the recipient (if non-zero).\n // - Trigger a Zap (if zapData is present).\n bytes calldata zapData = request.zapData();\n if (zapData.length != 0) {\n // Zap Data is present: Zap has been requested by the recipient. Trigger it forwarding the full msg.value.\n _triggerZapWithChecks({recipient: to, token: token, amount: amount, zapData: zapData});\n // Note: if token has a fee on transfers, the recipient will have received less than `amount`.\n // This is a very niche edge case and should be handled by the recipient contract.\n } else if (msg.value != 0) {\n // Zap Data is missing, but msg.value was sent. This could happen in two different cases:\n // - Relay with the native gas token is happening.\n // - Relay with ERC20 is happening, with a `zapNative \u003e 0` request.\n // In both cases, we need to transfer the full msg.value to the recipient.\n Address.sendValue(payable(to), msg.value);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function proveV2(bytes32 transactionId, bytes32 destTxHash, address relayer) public onlyRole(PROVER_ROLE) {\n // Can only prove a REQUESTED transaction.\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n if ($.status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n\n // Update status to RELAYER_PROVED and store the proof details.\n // Note: these are storage writes.\n $.status = BridgeStatus.RELAYER_PROVED;\n $.proofBlockTimestamp = uint56(block.timestamp);\n $.proofRelayer = relayer;\n\n emit BridgeProofProvided(transactionId, relayer, destTxHash);\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes calldata request, address to) public {\n // Decode the request and check that it could be claimed.\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n\n // Aggregate the read operations from the same storage slot.\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n address proofRelayer = $.proofRelayer;\n BridgeStatus status = $.status;\n uint56 proofBlockTimestamp = $.proofBlockTimestamp;\n\n // Can only claim a RELAYER_PROVED transaction after the dispute period.\n if (status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(proofBlockTimestamp) \u003c= DISPUTE_PERIOD) revert DisputePeriodNotPassed();\n if (to == address(0)) {\n // Anyone could claim the funds to the proven relayer on their behalf.\n to = proofRelayer;\n } else if (proofRelayer != msg.sender) {\n // Only the proven relayer could specify an address to claim the funds to.\n revert SenderIncorrect();\n }\n\n // Update status to RELAYER_CLAIMED and transfer the origin collateral to the specified claim address.\n // Note: this is a storage write.\n $.status = BridgeStatus.RELAYER_CLAIMED;\n\n // Accumulate protocol fees if origin fee amount exists.\n address token = request.originToken();\n uint256 amount = request.originAmount();\n uint256 originFeeAmount = request.originFeeAmount();\n if (originFeeAmount \u003e 0) protocolFees[token] += originFeeAmount;\n\n // Emit the event before any external calls.\n emit BridgeDepositClaimed(transactionId, proofRelayer, to, token, amount);\n\n // Complete the relayer claim as the last transaction action.\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(to), amount);\n } else {\n IERC20(token).safeTransfer(to, amount);\n }\n }\n\n // ═══════════════════════════════════════════════ PUBLIC VIEWS ════════════════════════════════════════════════════\n\n /// @inheritdoc IFastBridgeV2\n function bridgeStatuses(bytes32 transactionId) public view returns (BridgeStatus status) {\n return bridgeTxDetails[transactionId].status;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeProofs(bytes32 transactionId) public view returns (uint96 timestamp, address relayer) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n timestamp = $.proofBlockTimestamp;\n relayer = $.proofRelayer;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeRelays(bytes32 transactionId) public view returns (bool) {\n // This transaction has been relayed if the relayer address is recorded.\n return bridgeRelayDetails[transactionId].relayer != address(0);\n }\n\n // ═════════════════════════════════════════════ INTERNAL METHODS ══════════════════════════════════════════════════\n\n /// @notice Takes the bridged asset from the user into FastBridgeV2 custody. The asset will later be\n /// claimed by the relayer who completed the relay on the destination chain, or returned to the user\n /// via the cancel function if no relay is completed.\n function _takeBridgedUserAsset(address token, uint256 amount) internal returns (uint256 amountTaken) {\n if (token == NATIVE_GAS_TOKEN) {\n // For the native gas token, we just need to check that the supplied msg.value is correct.\n // Supplied `msg.value` is already in FastBridgeV2 custody.\n if (amount != msg.value) revert MsgValueIncorrect();\n amountTaken = msg.value;\n } else {\n // For ERC20s, token is explicitly transferred from the user to FastBridgeV2.\n // We don't allow non-zero `msg.value` to avoid extra funds from being stuck in FastBridgeV2.\n if (msg.value != 0) revert MsgValueIncorrect();\n // Throw an explicit error if the provided token address is not a contract.\n if (token.code.length == 0) revert TokenNotContract();\n\n // Use the balance difference as the amount taken in case of fee on transfer tokens.\n amountTaken = IERC20(token).balanceOf(address(this));\n IERC20(token).safeTransferFrom(msg.sender, address(this), amount);\n amountTaken = IERC20(token).balanceOf(address(this)) - amountTaken;\n }\n }\n\n /// @notice Calls the recipient's hook function with the specified zapData and validates\n /// the returned value.\n function _triggerZapWithChecks(address recipient, address token, uint256 amount, bytes calldata zapData) internal {\n // Call the recipient's hook function with the specified zapData, bubbling any revert messages.\n bytes memory returnData = Address.functionCallWithValue({\n target: recipient,\n data: abi.encodeCall(IZapRecipient.zap, (token, amount, zapData)),\n // Note: see `relay()` for reasoning behind passing msg.value.\n value: msg.value\n });\n\n // Explicit revert if no return data at all.\n if (returnData.length == 0) revert RecipientNoReturnValue();\n // Check that exactly a single return value was returned.\n if (returnData.length != 32) revert RecipientIncorrectReturnValue();\n // Return value should be abi-encoded hook function selector.\n if (bytes32(returnData) != bytes32(IZapRecipient.zap.selector)) {\n revert RecipientIncorrectReturnValue();\n }\n }\n\n /// @notice Calculates the time elapsed since a proof was submitted.\n /// @dev The proof.timestamp stores block timestamps as uint56 for gas optimization.\n /// _timeSince(proof) handles timestamp rollover when block.timestamp \u003e type(uint56).max but\n /// proof.timestamp \u003c type(uint56).max via an unchecked statement.\n /// @param proofBlockTimestamp The block timestamp when the proof was submitted.\n /// @return delta The time elapsed since proof submission.\n function _timeSince(uint56 proofBlockTimestamp) internal view returns (uint256 delta) {\n unchecked {\n delta = uint56(block.timestamp) - proofBlockTimestamp;\n }\n }\n\n /// @notice Validates all parameters required for a bridge transaction.\n /// @dev This function's complexity cannot be reduced due to the number of required checks,\n /// so we disable the code-complexity rule.\n // solhint-disable-next-line code-complexity\n function _validateBridgeParams(\n BridgeParams memory params,\n BridgeParamsV2 memory paramsV2,\n int256 exclusivityEndTime\n )\n internal\n view\n {\n // Check V1 (legacy) params.\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.sender == address(0) || params.to == address(0)) revert ZeroAddress();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n\n // Check V2 params.\n if (paramsV2.zapData.length \u003e MAX_ZAP_DATA_LENGTH) revert ZapDataLengthAboveMax();\n if (paramsV2.zapNative != 0 \u0026\u0026 params.destToken == NATIVE_GAS_TOKEN) {\n revert ZapNativeNotSupported();\n }\n\n // exclusivityEndTime must be in range [0 .. params.deadline].\n if (exclusivityEndTime \u003c 0 || exclusivityEndTime \u003e int256(params.deadline)) {\n revert ExclusivityParamsIncorrect();\n }\n }\n\n /// @notice Validates all parameters required for a relay transaction.\n function _validateRelayParams(bytes calldata request, bytes32 transactionId, address relayer) internal view {\n if (relayer == address(0)) revert ZeroAddress();\n // Check that the transaction has not been relayed yet and is for the current chain.\n if (bridgeRelays(transactionId)) revert TransactionRelayed();\n if (request.destChainId() != block.chainid) revert ChainIncorrect();\n // Check that the deadline for relay to happen has not passed yet.\n if (block.timestamp \u003e request.deadline()) revert DeadlineExceeded();\n // Check the exclusivity period, if it was specified and is still ongoing.\n address exclRelayer = request.exclusivityRelayer();\n if (exclRelayer != address(0) \u0026\u0026 exclRelayer != relayer \u0026\u0026 block.timestamp \u003c= request.exclusivityEndTime()) {\n revert ExclusivityPeriodNotPassed();\n }\n }\n}\n","language":"Solidity","languageVersion":"0.8.24","compilerVersion":"0.8.24","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"","srcMapRuntime":"","abiDefinition":[{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"}],"userDoc":{"kind":"user","methods":{},"version":1},"developerDoc":{"details":"Implementation of the {IERC165} interface. Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check for the additional interface id that will be supported. For example: ```solidity function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId); } ```","kind":"dev","methods":{"supportsInterface(bytes4)":{"details":"See {IERC165-supportsInterface}."}},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"bytes4\",\"name\":\"interfaceId\",\"type\":\"bytes4\"}],\"name\":\"supportsInterface\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"}],\"devdoc\":{\"details\":\"Implementation of the {IERC165} interface. Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check for the additional interface id that will be supported. For example: ```solidity function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId); } ```\",\"kind\":\"dev\",\"methods\":{\"supportsInterface(bytes4)\":{\"details\":\"See {IERC165-supportsInterface}.\"}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeV2.sol\":\"ERC165\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeV2.sol\":{\"keccak256\":\"0xaab2ee7357681726f0faf799a48ddfbf45fb4da93b69abf61c33dde92b29b74d\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://673391bff9569efc0f9bd99e0e6fece0bc8e8af1f052bb071b407b267a17b3b5\",\"dweb:/ipfs/QmdQQZ6DxpJYhfpinwU5WjLugr2f6qP8h68b5GerhSMQ4j\"]}},\"version\":1}"},"hashes":{"supportsInterface(bytes4)":"01ffc9a7"}},"solidity/FastBridgeV2.sol:EnumerableSet":{"code":"0x60566037600b82828239805160001a607314602a57634e487b7160e01b600052600060045260246000fd5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600080fdfea2646970667358221220164fbb0c52873ae2972df8055df9a7e90580066b49083b8183327a7192352ac164736f6c63430008180033","runtime-code":"0x73000000000000000000000000000000000000000030146080604052600080fdfea2646970667358221220164fbb0c52873ae2972df8055df9a7e90580066b49083b8183327a7192352ac164736f6c63430008180033","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.24 ^0.8.20 ^0.8.4;\n\n// contracts/interfaces/IAdminV2.sol\n\ninterface IAdminV2 {\n event CancelDelayUpdated(uint256 oldCancelDelay, uint256 newCancelDelay);\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n /// @notice Allows the governor to set the cancel delay. The cancel delay is the time period after the transaction\n /// deadline during which a transaction can be permissionlessly cancelled if it hasn't been proven by any Relayer.\n function setCancelDelay(uint256 newCancelDelay) external;\n\n /// @notice Allows the governor to set the protocol fee rate. The protocol fee is taken from the origin\n /// amount and is only applied to completed and claimed transactions.\n /// @dev The protocol fee is abstracted away from the relayers; they always operate using the amounts after fees.\n /// The origin amount they see in the emitted log is what they get credited with.\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n /// @notice Allows the governor to withdraw the accumulated protocol fees from the contract.\n function sweepProtocolFees(address token, address recipient) external;\n}\n\n// contracts/interfaces/IAdminV2Errors.sol\n\ninterface IAdminV2Errors {\n error CancelDelayBelowMin();\n error FeeRateAboveMax();\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IFastBridgeV2Errors.sol\n\ninterface IFastBridgeV2Errors {\n error AmountIncorrect();\n error ChainIncorrect();\n error ExclusivityParamsIncorrect();\n error MsgValueIncorrect();\n error SenderIncorrect();\n error StatusIncorrect();\n error TokenNotContract();\n error ZapDataLengthAboveMax();\n error ZapNativeNotSupported();\n error ZeroAddress();\n\n error RecipientIncorrectReturnValue();\n error RecipientNoReturnValue();\n\n error DeadlineExceeded();\n error DeadlineNotExceeded();\n error DeadlineTooShort();\n error DisputePeriodNotPassed();\n error DisputePeriodPassed();\n error ExclusivityPeriodNotPassed();\n\n error TransactionRelayed();\n}\n\n// contracts/interfaces/IMulticallTarget.sol\n\n/// @notice Interface for a contract that supports multiple calls from the same caller. Inspired by MulticallV3:\n/// https://github.com/mds1/multicall/blob/master/src/Multicall3.sol\ninterface IMulticallTarget {\n struct Result {\n bool success;\n bytes returnData;\n }\n\n /// @notice Executes multiple calls to this contract in a single transaction while preserving msg.sender.\n /// Return data from the calls is discarded.\n /// @dev This method is non-payable, so only calls with msg.value of 0 can be batched.\n /// If ignoreReverts is set to true, reverted calls will be skipped.\n /// Otherwise, the entire batch will revert with the original revert reason.\n /// @param data List of ABI-encoded calldata for the calls to execute\n /// @param ignoreReverts Whether to skip calls that revert\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external;\n\n /// @notice Executes multiple calls to this contract in a single transaction while preserving msg.sender.\n /// Return data from each call is preserved.\n /// @dev This method is non-payable, so only calls with msg.value of 0 can be batched.\n /// If ignoreReverts is set to true, reverted calls will be skipped.\n /// Otherwise, the entire batch will revert with the original revert reason.\n /// @param data List of ABI-encoded calldata for the calls to execute\n /// @param ignoreReverts Whether to skip calls that revert\n /// @return results List of results from the calls, each containing (success, returnData)\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results);\n}\n\n// contracts/interfaces/IZapRecipient.sol\n\n/// @notice Interface for contracts that can perform Zap operations. Such contracts could be used as Recipients\n/// in a FastBridge transaction that includes a Zap operation. The Zap Data should include instructions on how\n/// exactly the Zap operation should be executed, which would typically include the target address and calldata\n/// to use. The exact implementation of the Zap Data encoding is up to the Recipient contract.\ninterface IZapRecipient {\n /// @notice Performs a Zap operation with the given token and amount according to the provided Zap data.\n /// @param token The address of the token being used for the Zap operation.\n /// @param amount The amount of tokens to be used.\n /// @param zapData The encoded data specifying how the Zap operation should be executed.\n /// @return The function selector to indicate successful execution.\n function zap(address token, uint256 amount, bytes memory zapData) external payable returns (bytes4);\n}\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// contracts/interfaces/IFastBridgeV2.sol\n\ninterface IFastBridgeV2 is IFastBridge {\n enum BridgeStatus {\n NULL, // Doesn't exist yet.\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n struct BridgeTxDetails {\n BridgeStatus status;\n uint32 destChainId;\n uint56 proofBlockTimestamp;\n address proofRelayer;\n }\n\n struct BridgeRelay {\n uint48 blockNumber;\n uint48 blockTimestamp;\n address relayer;\n }\n\n /// @notice New params introduced in the FastBridgeV2.\n /// We are passing fields from the older BridgeParams struct outside of this struct for backwards compatibility.\n /// Note: quoteRelayer and quoteExclusivitySeconds are either both zero (indicating no exclusivity)\n /// or both non-zero (indicating exclusivity for the given period).\n /// Note: zapNative \u003e 0 can NOT be used with destToken = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE (native token)\n /// @param quoteRelayer Relayer that provided the quote for the transaction\n /// @param quoteExclusivitySeconds Period of time the quote relayer is guaranteed exclusivity after user's deposit\n /// @param quoteId Unique quote identifier used for tracking the quote\n /// @param zapNative ETH value to send to the recipient (if any)\n /// @param zapData Parameters for the Zap to the destination recipient (if any)\n struct BridgeParamsV2 {\n address quoteRelayer;\n int256 quoteExclusivitySeconds;\n bytes quoteId;\n uint256 zapNative;\n bytes zapData;\n }\n\n /// @notice Updated bridge transaction struct to include parameters introduced in FastBridgeV2.\n /// Note: only `exclusivityRelayer` can fill such a transaction until `exclusivityEndTime`.\n struct BridgeTransactionV2 {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n // Note: sendChainGas flag from V1 is deprecated\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n address exclusivityRelayer;\n uint256 exclusivityEndTime;\n uint256 zapNative; // ETH value to send to the recipient (if any)\n bytes zapData; // data to pass for the Zap action (if any)\n }\n\n event BridgeQuoteDetails(bytes32 indexed transactionId, bytes quoteId);\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability\n /// to provide temporary exclusivity fill rights for the quote relayer.\n /// @param params The parameters required to bridge\n /// @param paramsV2 The parameters for exclusivity fill rights (optional, can be left empty)\n function bridgeV2(BridgeParams memory params, BridgeParamsV2 memory paramsV2) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function relayV2(bytes memory request, address relayer) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param transactionId The transaction id associated with the encoded bridge transaction to prove\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function proveV2(bytes32 transactionId, bytes32 destTxHash, address relayer) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital.\n /// @notice Can only send funds to the relayer address on the proof.\n /// @param request The encoded bridge transaction to claim on origin chain\n function claimV2(bytes memory request) external;\n\n /// @notice Cancels an outstanding bridge transaction in case optimistic bridging failed and returns the full amount\n /// to the original sender.\n /// @param request The encoded bridge transaction to refund\n function cancelV2(bytes memory request) external;\n\n /// @notice Checks if a transaction has been relayed\n /// @param transactionId The ID of the transaction to check\n /// @return True if the transaction has been relayed, false otherwise\n function bridgeRelays(bytes32 transactionId) external view returns (bool);\n\n /// @notice Returns the status of a bridge transaction\n /// @param transactionId The ID of the bridge transaction\n /// @return BridgeStatus Status of the bridge transaction\n function bridgeStatuses(bytes32 transactionId) external view returns (BridgeStatus);\n\n /// @notice Returns the timestamp and relayer of a bridge proof\n /// @param transactionId The ID of the bridge transaction\n /// @return timestamp The timestamp of the bridge proof\n /// @return relayer The relayer address of the bridge proof\n function bridgeProofs(bytes32 transactionId) external view returns (uint96 timestamp, address relayer);\n\n /// @notice Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\n /// @param request The bridge request to decode\n function getBridgeTransactionV2(bytes memory request) external view returns (BridgeTransactionV2 memory);\n}\n\n// contracts/utils/MulticallTarget.sol\n\n// solhint-disable avoid-low-level-calls\n/// @notice Abstract contract template that supports batched calls while preserving msg.sender.\n/// Only calls with msg.value of 0 can be batched.\nabstract contract MulticallTarget is IMulticallTarget {\n error MulticallTarget__UndeterminedRevert();\n\n /// @inheritdoc IMulticallTarget\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external {\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\n if (!success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(result);\n }\n }\n }\n\n /// @inheritdoc IMulticallTarget\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results)\n {\n results = new Result[](data.length);\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (results[i].success, results[i].returnData) = address(this).delegatecall(data[i]);\n if (!results[i].success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(results[i].returnData);\n }\n }\n }\n\n /// @dev Bubbles the revert message from the underlying call.\n /// Note: preserves the same custom error or revert string, if one was used.\n /// Source: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v5.0.2/contracts/utils/Address.sol#L143-L158\n function _bubbleRevert(bytes memory returnData) internal pure {\n // Look for revert reason and bubble it up if present\n if (returnData.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n // solhint-disable-next-line no-inline-assembly\n assembly {\n let returndata_size := mload(returnData)\n revert(add(32, returnData), returndata_size)\n }\n } else {\n revert MulticallTarget__UndeterminedRevert();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// contracts/libs/BridgeTransactionV2.sol\n\n// solhint-disable no-inline-assembly\nlibrary BridgeTransactionV2Lib {\n uint16 internal constant VERSION = 2;\n\n // Offsets of the fields in the packed BridgeTransactionV2 struct\n // uint16 version [000 .. 002)\n // uint32 originChainId [002 .. 006)\n // uint32 destChainId [006 .. 010)\n // address originSender [010 .. 030)\n // address destRecipient [030 .. 050)\n // address originToken [050 .. 070)\n // address destToken [070 .. 090)\n // uint256 originAmount [090 .. 122)\n // uint256 destAmount [122 .. 154)\n // uint256 originFeeAmount [154 .. 186)\n // uint256 deadline [186 .. 218)\n // uint256 nonce [218 .. 250)\n // address exclusivityRelayer [250 .. 270)\n // uint256 exclusivityEndTime [270 .. 302)\n // uint256 zapNative [302 .. 334)\n // bytes zapData [334 .. ***)\n\n // forgefmt: disable-start\n uint256 private constant OFFSET_ORIGIN_CHAIN_ID = 2;\n uint256 private constant OFFSET_DEST_CHAIN_ID = 6;\n uint256 private constant OFFSET_ORIGIN_SENDER = 10;\n uint256 private constant OFFSET_DEST_RECIPIENT = 30;\n uint256 private constant OFFSET_ORIGIN_TOKEN = 50;\n uint256 private constant OFFSET_DEST_TOKEN = 70;\n uint256 private constant OFFSET_ORIGIN_AMOUNT = 90;\n uint256 private constant OFFSET_DEST_AMOUNT = 122;\n uint256 private constant OFFSET_ORIGIN_FEE_AMOUNT = 154;\n uint256 private constant OFFSET_DEADLINE = 186;\n uint256 private constant OFFSET_NONCE = 218;\n uint256 private constant OFFSET_EXCLUSIVITY_RELAYER = 250;\n uint256 private constant OFFSET_EXCLUSIVITY_END_TIME = 270;\n uint256 private constant OFFSET_ZAP_NATIVE = 302;\n uint256 private constant OFFSET_ZAP_DATA = 334;\n // forgefmt: disable-end\n\n error BridgeTransactionV2__InvalidEncodedTx();\n error BridgeTransactionV2__UnsupportedVersion(uint16 version);\n\n /// @notice Validates that the encoded transaction is a tightly packed encoded payload for BridgeTransactionV2.\n /// @dev Checks the minimum length and the version, use this function before decoding any of the fields.\n function validateV2(bytes calldata encodedTx) internal pure {\n // Check the minimum length: must at least include all static fields.\n if (encodedTx.length \u003c OFFSET_ZAP_DATA) revert BridgeTransactionV2__InvalidEncodedTx();\n // Once we validated the length, we can be sure that the version field is present.\n uint16 version_ = version(encodedTx);\n if (version_ != VERSION) revert BridgeTransactionV2__UnsupportedVersion(version_);\n }\n\n /// @notice Encodes the BridgeTransactionV2 struct by tightly packing the fields.\n /// @dev `abi.decode` will not work as a result of the tightly packed fields. Use `decodeV2` to decode instead.\n function encodeV2(IFastBridgeV2.BridgeTransactionV2 memory bridgeTx) internal pure returns (bytes memory) {\n // We split the encoding into two parts to avoid stack-too-deep error\n bytes memory firstPart = abi.encodePacked(\n VERSION,\n bridgeTx.originChainId,\n bridgeTx.destChainId,\n bridgeTx.originSender,\n bridgeTx.destRecipient,\n bridgeTx.originToken,\n bridgeTx.destToken,\n bridgeTx.originAmount\n );\n return abi.encodePacked(\n firstPart,\n bridgeTx.destAmount,\n bridgeTx.originFeeAmount,\n // Note: we skip the deprecated `sendChainGas` flag, which was present in BridgeTransaction V1\n bridgeTx.deadline,\n bridgeTx.nonce,\n // New V2 fields: exclusivity\n bridgeTx.exclusivityRelayer,\n bridgeTx.exclusivityEndTime,\n // New V2 fields: Zap\n bridgeTx.zapNative,\n bridgeTx.zapData\n );\n }\n\n /// @notice Decodes the BridgeTransactionV2 struct from the encoded transaction.\n /// @dev Encoded BridgeTransactionV2 struct must be tightly packed.\n /// Use `validateV2` before decoding to ensure the encoded transaction is valid.\n function decodeV2(bytes calldata encodedTx)\n internal\n pure\n returns (IFastBridgeV2.BridgeTransactionV2 memory bridgeTx)\n {\n bridgeTx.originChainId = originChainId(encodedTx);\n bridgeTx.destChainId = destChainId(encodedTx);\n bridgeTx.originSender = originSender(encodedTx);\n bridgeTx.destRecipient = destRecipient(encodedTx);\n bridgeTx.originToken = originToken(encodedTx);\n bridgeTx.destToken = destToken(encodedTx);\n bridgeTx.originAmount = originAmount(encodedTx);\n bridgeTx.destAmount = destAmount(encodedTx);\n bridgeTx.originFeeAmount = originFeeAmount(encodedTx);\n bridgeTx.deadline = deadline(encodedTx);\n bridgeTx.nonce = nonce(encodedTx);\n bridgeTx.exclusivityRelayer = exclusivityRelayer(encodedTx);\n bridgeTx.exclusivityEndTime = exclusivityEndTime(encodedTx);\n bridgeTx.zapNative = zapNative(encodedTx);\n bridgeTx.zapData = zapData(encodedTx);\n }\n\n /// @notice Extracts the version from the encoded transaction.\n function version(bytes calldata encodedTx) internal pure returns (uint16 version_) {\n // Load 32 bytes from the start and shift it 240 bits to the right to get the highest 16 bits.\n assembly {\n version_ := shr(240, calldataload(encodedTx.offset))\n }\n }\n\n /// @notice Extracts the origin chain ID from the encoded transaction.\n function originChainId(bytes calldata encodedTx) internal pure returns (uint32 originChainId_) {\n // Load 32 bytes from the offset and shift it 224 bits to the right to get the highest 32 bits.\n assembly {\n originChainId_ := shr(224, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_CHAIN_ID)))\n }\n }\n\n /// @notice Extracts the destination chain ID from the encoded transaction.\n function destChainId(bytes calldata encodedTx) internal pure returns (uint32 destChainId_) {\n // Load 32 bytes from the offset and shift it 224 bits to the right to get the highest 32 bits.\n assembly {\n destChainId_ := shr(224, calldataload(add(encodedTx.offset, OFFSET_DEST_CHAIN_ID)))\n }\n }\n\n /// @notice Extracts the origin sender from the encoded transaction.\n function originSender(bytes calldata encodedTx) internal pure returns (address originSender_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n originSender_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_SENDER)))\n }\n }\n\n /// @notice Extracts the destination recipient from the encoded transaction.\n function destRecipient(bytes calldata encodedTx) internal pure returns (address destRecipient_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n destRecipient_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_DEST_RECIPIENT)))\n }\n }\n\n /// @notice Extracts the origin token from the encoded transaction.\n function originToken(bytes calldata encodedTx) internal pure returns (address originToken_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n originToken_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_TOKEN)))\n }\n }\n\n /// @notice Extracts the destination token from the encoded transaction.\n function destToken(bytes calldata encodedTx) internal pure returns (address destToken_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n destToken_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_DEST_TOKEN)))\n }\n }\n\n /// @notice Extracts the origin amount from the encoded transaction.\n function originAmount(bytes calldata encodedTx) internal pure returns (uint256 originAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n originAmount_ := calldataload(add(encodedTx.offset, OFFSET_ORIGIN_AMOUNT))\n }\n }\n\n /// @notice Extracts the destination amount from the encoded transaction.\n function destAmount(bytes calldata encodedTx) internal pure returns (uint256 destAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n destAmount_ := calldataload(add(encodedTx.offset, OFFSET_DEST_AMOUNT))\n }\n }\n\n /// @notice Extracts the origin fee amount from the encoded transaction.\n function originFeeAmount(bytes calldata encodedTx) internal pure returns (uint256 originFeeAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n originFeeAmount_ := calldataload(add(encodedTx.offset, OFFSET_ORIGIN_FEE_AMOUNT))\n }\n }\n\n /// @notice Extracts the deadline from the encoded transaction.\n function deadline(bytes calldata encodedTx) internal pure returns (uint256 deadline_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n deadline_ := calldataload(add(encodedTx.offset, OFFSET_DEADLINE))\n }\n }\n\n /// @notice Extracts the nonce from the encoded transaction.\n function nonce(bytes calldata encodedTx) internal pure returns (uint256 nonce_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n nonce_ := calldataload(add(encodedTx.offset, OFFSET_NONCE))\n }\n }\n\n /// @notice Extracts the exclusivity relayer from the encoded transaction.\n function exclusivityRelayer(bytes calldata encodedTx) internal pure returns (address exclusivityRelayer_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n exclusivityRelayer_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_EXCLUSIVITY_RELAYER)))\n }\n }\n\n /// @notice Extracts the exclusivity end time from the encoded transaction.\n function exclusivityEndTime(bytes calldata encodedTx) internal pure returns (uint256 exclusivityEndTime_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n exclusivityEndTime_ := calldataload(add(encodedTx.offset, OFFSET_EXCLUSIVITY_END_TIME))\n }\n }\n\n /// @notice Extracts the Zap's native value from the encoded transaction.\n function zapNative(bytes calldata encodedTx) internal pure returns (uint256 zapNative_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n zapNative_ := calldataload(add(encodedTx.offset, OFFSET_ZAP_NATIVE))\n }\n }\n\n /// @notice Extracts the Zap's data from the encoded transaction.\n function zapData(bytes calldata encodedTx) internal pure returns (bytes calldata zapData_) {\n zapData_ = encodedTx[OFFSET_ZAP_DATA:];\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/AdminV2.sol\n\n// ════════════════════════════════════════════════ INTERFACES ═════════════════════════════════════════════════════\n\n// ═════════════════════════════════════════════ EXTERNAL IMPORTS ══════════════════════════════════════════════════\n\n/// @title AdminV2\n/// @notice Provides administrative functions and controls for managing the FastBridgeV2 contract,\n/// including access control and configuration settings.\ncontract AdminV2 is AccessControlEnumerable, IAdminV2, IAdminV2Errors {\n using SafeERC20 for IERC20;\n\n /// @notice The address reserved for the native gas token (ETH on Ethereum and most L2s, AVAX on Avalanche, etc.).\n address public constant NATIVE_GAS_TOKEN = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice The role identifier for the Quoter API's off-chain authentication.\n /// @dev Only addresses with this role can post FastBridge quotes to the API.\n bytes32 public constant QUOTER_ROLE = keccak256(\"QUOTER_ROLE\");\n\n /// @notice The role identifier for the Prover's on-chain authentication in FastBridge.\n /// @dev Only addresses with this role can provide proofs that a FastBridge request has been relayed.\n bytes32 public constant PROVER_ROLE = keccak256(\"PROVER_ROLE\");\n\n /// @notice The role identifier for the Guard's on-chain authentication in FastBridge.\n /// @dev Only addresses with this role can dispute submitted relay proofs during the dispute period.\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n\n /// @notice The role identifier for the Canceler's on-chain authentication in FastBridge.\n /// @dev Only addresses with this role can cancel a FastBridge transaction without the cancel delay.\n bytes32 public constant CANCELER_ROLE = keccak256(\"CANCELER_ROLE\");\n\n /// @notice The role identifier for the Governor's on-chain administrative authority.\n /// @dev Only addresses with this role can perform administrative tasks within the contract.\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n /// @notice The denominator for fee rates, representing 100%.\n uint256 public constant FEE_BPS = 1e6;\n /// @notice The maximum protocol fee rate: 1% of the origin amount.\n uint256 public constant FEE_RATE_MAX = 0.01e6;\n\n /// @notice The minimum cancel delay that can be set by the governor.\n uint256 public constant MIN_CANCEL_DELAY = 1 hours;\n /// @notice The default cancel delay set during contract deployment.\n uint256 public constant DEFAULT_CANCEL_DELAY = 1 days;\n\n /// @notice The protocol fee rate taken on the origin amount deposited in the origin chain.\n uint256 public protocolFeeRate;\n\n /// @notice The accumulated protocol fee amounts.\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice The delay period after which a transaction can be permissionlessly cancelled.\n uint256 public cancelDelay;\n\n /// @notice This variable is deprecated and should not be used.\n /// @dev Use ZapNative V2 requests instead.\n uint256 public immutable chainGasAmount = 0;\n\n constructor(address defaultAdmin) {\n _grantRole(DEFAULT_ADMIN_ROLE, defaultAdmin);\n _setCancelDelay(DEFAULT_CANCEL_DELAY);\n }\n\n /// @inheritdoc IAdminV2\n function setCancelDelay(uint256 newCancelDelay) external onlyRole(GOVERNOR_ROLE) {\n _setCancelDelay(newCancelDelay);\n }\n\n /// @inheritdoc IAdminV2\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n if (newFeeRate \u003e FEE_RATE_MAX) revert FeeRateAboveMax();\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n /// @inheritdoc IAdminV2\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n // Early exit if no accumulated fees.\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return;\n // Reset the accumulated fees first.\n protocolFees[token] = 0;\n emit FeesSwept(token, recipient, feeAmount);\n // Sweep the fees as the last transaction action.\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(recipient), feeAmount);\n } else {\n IERC20(token).safeTransfer(recipient, feeAmount);\n }\n }\n\n /// @notice Internal logic to set the cancel delay. Security checks are performed outside of this function.\n /// @dev This function is marked as private to prevent child contracts from calling it directly.\n function _setCancelDelay(uint256 newCancelDelay) private {\n if (newCancelDelay \u003c MIN_CANCEL_DELAY) revert CancelDelayBelowMin();\n uint256 oldCancelDelay = cancelDelay;\n cancelDelay = newCancelDelay;\n emit CancelDelayUpdated(oldCancelDelay, newCancelDelay);\n }\n}\n\n// contracts/FastBridgeV2.sol\n\n// ════════════════════════════════════════════════ INTERFACES ═════════════════════════════════════════════════════\n\n// ═════════════════════════════════════════════ INTERNAL IMPORTS ══════════════════════════════════════════════════\n\n// ═════════════════════════════════════════════ EXTERNAL IMPORTS ══════════════════════════════════════════════════\n\n/// @title FastBridgeV2\n/// @notice Core component of the SynapseRFQ protocol, enabling Relayers (Solvers) to fulfill bridge requests.\n/// Supports ERC20 and native gas tokens, along with the Zap feature for executing actions on the destination chain.\n/// Users interact with the off-chain Quoter API to obtain a current quote for a bridge transaction.\n/// They then submit the bridge request with the quote to this contract, depositing their assets in escrow.\n/// Relayers can fulfill requests by relaying them to the destination chain and must prove fulfillment to claim funds.\n/// Guards monitor proofs and can dispute discrepancies.\n/// Users can reclaim funds by cancelling their requests if it has not been fulfilled within the specified deadline.\ncontract FastBridgeV2 is AdminV2, MulticallTarget, IFastBridgeV2, IFastBridgeV2Errors {\n using BridgeTransactionV2Lib for bytes;\n using SafeERC20 for IERC20;\n\n /// @notice The duration of the dispute period for relayed transactions.\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice The minimum required time between transaction request and deadline.\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n /// @notice The maximum allowed length for zapData.\n uint256 public constant MAX_ZAP_DATA_LENGTH = 2 ** 16 - 1;\n\n /// @notice Maps transaction IDs to bridge details (status, destination chain ID, proof timestamp, and relayer).\n /// Note: this is only stored for transactions having local chain as the origin chain.\n mapping(bytes32 =\u003e BridgeTxDetails) public bridgeTxDetails;\n /// @notice Maps transaction IDs to relay details (block number, block timestamp, and relayer).\n /// Note: this is only stored for transactions having local chain as the destination chain.\n mapping(bytes32 =\u003e BridgeRelay) public bridgeRelayDetails;\n /// @notice Maps sender addresses to their unique bridge nonce.\n mapping(address =\u003e uint256) public senderNonces;\n\n /// @notice This variable is deprecated and should not be used.\n /// @dev Replaced by senderNonces.\n uint256 public immutable nonce = 0;\n /// @notice The block number at which this contract was deployed.\n uint256 public immutable deployBlock;\n\n /// @notice Initializes the FastBridgeV2 contract with the provided default admin,\n /// sets the default cancel delay, and records the deploy block number.\n constructor(address defaultAdmin) AdminV2(defaultAdmin) {\n deployBlock = block.number;\n }\n\n // ══════════════════════════════════════ EXTERNAL MUTABLE (USER FACING) ═══════════════════════════════════════════\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n bridgeV2({\n params: params,\n paramsV2: BridgeParamsV2({\n quoteRelayer: address(0),\n quoteExclusivitySeconds: 0,\n quoteId: bytes(\"\"),\n zapNative: 0,\n zapData: bytes(\"\")\n })\n });\n }\n\n /// Note: this function is deprecated and will be removed in a future version.\n /// @dev Replaced by `cancel`.\n /// @inheritdoc IFastBridge\n function refund(bytes calldata request) external {\n cancelV2(request);\n }\n\n // ══════════════════════════════════════ EXTERNAL MUTABLE (AGENT FACING) ══════════════════════════════════════════\n\n /// @inheritdoc IFastBridge\n function relay(bytes calldata request) external payable {\n // `relay` override will validate the request.\n relayV2({request: request, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes calldata request, bytes32 destTxHash) external {\n request.validateV2();\n proveV2({transactionId: keccak256(request), destTxHash: destTxHash, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridgeV2\n function claimV2(bytes calldata request) external {\n // `claim` override will validate the request.\n claim({request: request, to: address(0)});\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n // Aggregate the read operations from the same storage slot.\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n address disputedRelayer = $.proofRelayer;\n BridgeStatus status = $.status;\n uint56 proofBlockTimestamp = $.proofBlockTimestamp;\n\n // Can only dispute a RELAYER_PROVED transaction within the dispute period.\n if (status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(proofBlockTimestamp) \u003e DISPUTE_PERIOD) {\n revert DisputePeriodPassed();\n }\n\n // Update status to REQUESTED and delete the disputed proof details.\n // Note: these are storage writes.\n $.status = BridgeStatus.REQUESTED;\n $.proofRelayer = address(0);\n $.proofBlockTimestamp = 0;\n\n emit BridgeProofDisputed(transactionId, disputedRelayer);\n }\n\n // ══════════════════════════════════════════════ EXTERNAL VIEWS ═══════════════════════════════════════════════════\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n // The correct relayer can only claim a RELAYER_PROVED transaction after the dispute period.\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n if ($.status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if ($.proofRelayer != relayer) revert SenderIncorrect();\n\n return _timeSince($.proofBlockTimestamp) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n /// @dev This method is added to achieve backwards compatibility with decoding requests into V1 structs:\n /// - `zapNative` is partially reported as a zero/non-zero flag\n /// - `zapData` is ignored\n /// In order to process all kinds of requests use getBridgeTransactionV2 instead.\n function getBridgeTransaction(bytes calldata request) external view returns (BridgeTransaction memory) {\n // Try decoding into V2 struct first. This will revert if V1 struct is passed.\n try this.getBridgeTransactionV2(request) returns (BridgeTransactionV2 memory txV2) {\n // Note: we entirely ignore the zapData field, as it was not present in V1.\n return BridgeTransaction({\n originChainId: txV2.originChainId,\n destChainId: txV2.destChainId,\n originSender: txV2.originSender,\n destRecipient: txV2.destRecipient,\n originToken: txV2.originToken,\n destToken: txV2.destToken,\n originAmount: txV2.originAmount,\n destAmount: txV2.destAmount,\n originFeeAmount: txV2.originFeeAmount,\n sendChainGas: txV2.zapNative != 0,\n deadline: txV2.deadline,\n nonce: txV2.nonce\n });\n } catch {\n // Fallback to V1 struct.\n return abi.decode(request, (BridgeTransaction));\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function getBridgeTransactionV2(bytes calldata request) external pure returns (BridgeTransactionV2 memory) {\n request.validateV2();\n return BridgeTransactionV2Lib.decodeV2(request);\n }\n\n // ═══════════════════════════════════════ PUBLIC MUTABLE (USER FACING) ════════════════════════════════════════════\n\n /// @inheritdoc IFastBridgeV2\n function bridgeV2(BridgeParams memory params, BridgeParamsV2 memory paramsV2) public payable {\n // If relayer exclusivity is not intended for this bridge, set exclusivityEndTime to static zero.\n // Otherwise, set exclusivity to expire at the current block ts offset by quoteExclusivitySeconds.\n int256 exclusivityEndTime = 0;\n if (paramsV2.quoteRelayer != address(0)) {\n exclusivityEndTime = int256(block.timestamp) + paramsV2.quoteExclusivitySeconds;\n }\n _validateBridgeParams(params, paramsV2, exclusivityEndTime);\n\n // Transfer tokens to bridge contract. We use the actual transferred amount in case of transfer fees.\n uint256 originAmount = _takeBridgedUserAsset(params.originToken, params.originAmount);\n\n // Track the amount of origin token owed to protocol.\n uint256 originFeeAmount = 0;\n if (protocolFeeRate \u003e 0) {\n originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n // The Relayer filling this request will be paid the originAmount after fees.\n // Note: the protocol fees will be accumulated only when the Relayer claims the origin collateral.\n originAmount -= originFeeAmount;\n }\n\n // Hash the bridge request and set the initial status to REQUESTED.\n bytes memory request = BridgeTransactionV2Lib.encodeV2(\n BridgeTransactionV2({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n deadline: params.deadline,\n // Increment the sender's nonce on every bridge.\n nonce: senderNonces[params.sender]++,\n exclusivityRelayer: paramsV2.quoteRelayer,\n // We checked exclusivityEndTime to be in range [0 .. params.deadline] above, so can safely cast.\n exclusivityEndTime: uint256(exclusivityEndTime),\n zapNative: paramsV2.zapNative,\n zapData: paramsV2.zapData\n })\n );\n bytes32 transactionId = keccak256(request);\n // Note: the tx status will be updated throughout the tx lifecycle, while destChainId is set once here.\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n bridgeTxDetails[transactionId].destChainId = params.dstChainId;\n\n emit BridgeRequested({\n transactionId: transactionId,\n sender: params.sender,\n request: request,\n destChainId: params.dstChainId,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n sendChainGas: paramsV2.zapNative != 0\n });\n emit BridgeQuoteDetails(transactionId, paramsV2.quoteId);\n }\n\n /// @inheritdoc IFastBridgeV2\n function cancelV2(bytes calldata request) public {\n // Decode the request and check that it could be cancelled.\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n\n // Can only cancel a REQUESTED transaction after its deadline expires.\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n if ($.status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n\n // Permissionless cancel is only allowed after `cancelDelay` on top of the deadline.\n uint256 deadline = request.deadline();\n if (!hasRole(CANCELER_ROLE, msg.sender)) deadline += cancelDelay;\n if (block.timestamp \u003c= deadline) revert DeadlineNotExceeded();\n\n // Update status to REFUNDED.\n // Note: this is a storage write.\n $.status = BridgeStatus.REFUNDED;\n\n // Return the full amount (collateral + protocol fees) to the original sender.\n // The protocol fees are only accumulated when the transaction is claimed, so we don't need to update them here.\n address to = request.originSender();\n address token = request.originToken();\n uint256 amount = request.originAmount() + request.originFeeAmount();\n\n // Emit the event before any external calls.\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n\n // Return the funds to the original sender as last transaction action.\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(to), amount);\n } else {\n IERC20(token).safeTransfer(to, amount);\n }\n }\n\n // ═══════════════════════════════════════ PUBLIC MUTABLE (AGENT FACING) ═══════════════════════════════════════════\n\n /// @inheritdoc IFastBridgeV2\n function relayV2(bytes calldata request, address relayer) public payable {\n // Decode the request and check that it could be relayed.\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n _validateRelayParams(request, transactionId, relayer);\n\n // Mark the bridge request as relayed by saving the relayer and the block details.\n bridgeRelayDetails[transactionId].blockNumber = uint48(block.number);\n bridgeRelayDetails[transactionId].blockTimestamp = uint48(block.timestamp);\n bridgeRelayDetails[transactionId].relayer = relayer;\n\n // Transfer tokens to recipient on destination chain and trigger Zap if requested.\n address to = request.destRecipient();\n address token = request.destToken();\n uint256 amount = request.destAmount();\n uint256 zapNative = request.zapNative();\n\n // Emit the event before any external calls.\n emit BridgeRelayed({\n transactionId: transactionId,\n relayer: relayer,\n to: to,\n originChainId: request.originChainId(),\n originToken: request.originToken(),\n destToken: token,\n originAmount: request.originAmount(),\n destAmount: amount,\n chainGasAmount: zapNative\n });\n\n // All state changes have been done at this point, can proceed to the external calls.\n // This follows the checks-effects-interactions pattern to mitigate potential reentrancy attacks.\n if (token == NATIVE_GAS_TOKEN) {\n // For the native gas token, additional zapNative is not allowed.\n if (zapNative != 0) revert ZapNativeNotSupported();\n // Check that the correct msg.value was sent.\n if (msg.value != amount) revert MsgValueIncorrect();\n // Don't do a native transfer yet: we will handle it alongside the Zap below.\n } else {\n // For ERC20s, we check that the correct msg.value was sent.\n if (msg.value != zapNative) revert MsgValueIncorrect();\n // We need to transfer the tokens from the Relayer to the recipient first before performing an\n // optional post-transfer Zap.\n IERC20(token).safeTransferFrom(msg.sender, to, amount);\n }\n // At this point we have done:\n // - Transferred the requested amount of ERC20 tokens to the recipient.\n // At this point we have confirmed:\n // - For ERC20s: msg.value matches the requested zapNative amount.\n // - For the native gas token: msg.value matches the requested destAmount.\n // Remaining optional things to do:\n // - Forward the full msg.value to the recipient (if non-zero).\n // - Trigger a Zap (if zapData is present).\n bytes calldata zapData = request.zapData();\n if (zapData.length != 0) {\n // Zap Data is present: Zap has been requested by the recipient. Trigger it forwarding the full msg.value.\n _triggerZapWithChecks({recipient: to, token: token, amount: amount, zapData: zapData});\n // Note: if token has a fee on transfers, the recipient will have received less than `amount`.\n // This is a very niche edge case and should be handled by the recipient contract.\n } else if (msg.value != 0) {\n // Zap Data is missing, but msg.value was sent. This could happen in two different cases:\n // - Relay with the native gas token is happening.\n // - Relay with ERC20 is happening, with a `zapNative \u003e 0` request.\n // In both cases, we need to transfer the full msg.value to the recipient.\n Address.sendValue(payable(to), msg.value);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function proveV2(bytes32 transactionId, bytes32 destTxHash, address relayer) public onlyRole(PROVER_ROLE) {\n // Can only prove a REQUESTED transaction.\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n if ($.status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n\n // Update status to RELAYER_PROVED and store the proof details.\n // Note: these are storage writes.\n $.status = BridgeStatus.RELAYER_PROVED;\n $.proofBlockTimestamp = uint56(block.timestamp);\n $.proofRelayer = relayer;\n\n emit BridgeProofProvided(transactionId, relayer, destTxHash);\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes calldata request, address to) public {\n // Decode the request and check that it could be claimed.\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n\n // Aggregate the read operations from the same storage slot.\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n address proofRelayer = $.proofRelayer;\n BridgeStatus status = $.status;\n uint56 proofBlockTimestamp = $.proofBlockTimestamp;\n\n // Can only claim a RELAYER_PROVED transaction after the dispute period.\n if (status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(proofBlockTimestamp) \u003c= DISPUTE_PERIOD) revert DisputePeriodNotPassed();\n if (to == address(0)) {\n // Anyone could claim the funds to the proven relayer on their behalf.\n to = proofRelayer;\n } else if (proofRelayer != msg.sender) {\n // Only the proven relayer could specify an address to claim the funds to.\n revert SenderIncorrect();\n }\n\n // Update status to RELAYER_CLAIMED and transfer the origin collateral to the specified claim address.\n // Note: this is a storage write.\n $.status = BridgeStatus.RELAYER_CLAIMED;\n\n // Accumulate protocol fees if origin fee amount exists.\n address token = request.originToken();\n uint256 amount = request.originAmount();\n uint256 originFeeAmount = request.originFeeAmount();\n if (originFeeAmount \u003e 0) protocolFees[token] += originFeeAmount;\n\n // Emit the event before any external calls.\n emit BridgeDepositClaimed(transactionId, proofRelayer, to, token, amount);\n\n // Complete the relayer claim as the last transaction action.\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(to), amount);\n } else {\n IERC20(token).safeTransfer(to, amount);\n }\n }\n\n // ═══════════════════════════════════════════════ PUBLIC VIEWS ════════════════════════════════════════════════════\n\n /// @inheritdoc IFastBridgeV2\n function bridgeStatuses(bytes32 transactionId) public view returns (BridgeStatus status) {\n return bridgeTxDetails[transactionId].status;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeProofs(bytes32 transactionId) public view returns (uint96 timestamp, address relayer) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n timestamp = $.proofBlockTimestamp;\n relayer = $.proofRelayer;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeRelays(bytes32 transactionId) public view returns (bool) {\n // This transaction has been relayed if the relayer address is recorded.\n return bridgeRelayDetails[transactionId].relayer != address(0);\n }\n\n // ═════════════════════════════════════════════ INTERNAL METHODS ══════════════════════════════════════════════════\n\n /// @notice Takes the bridged asset from the user into FastBridgeV2 custody. The asset will later be\n /// claimed by the relayer who completed the relay on the destination chain, or returned to the user\n /// via the cancel function if no relay is completed.\n function _takeBridgedUserAsset(address token, uint256 amount) internal returns (uint256 amountTaken) {\n if (token == NATIVE_GAS_TOKEN) {\n // For the native gas token, we just need to check that the supplied msg.value is correct.\n // Supplied `msg.value` is already in FastBridgeV2 custody.\n if (amount != msg.value) revert MsgValueIncorrect();\n amountTaken = msg.value;\n } else {\n // For ERC20s, token is explicitly transferred from the user to FastBridgeV2.\n // We don't allow non-zero `msg.value` to avoid extra funds from being stuck in FastBridgeV2.\n if (msg.value != 0) revert MsgValueIncorrect();\n // Throw an explicit error if the provided token address is not a contract.\n if (token.code.length == 0) revert TokenNotContract();\n\n // Use the balance difference as the amount taken in case of fee on transfer tokens.\n amountTaken = IERC20(token).balanceOf(address(this));\n IERC20(token).safeTransferFrom(msg.sender, address(this), amount);\n amountTaken = IERC20(token).balanceOf(address(this)) - amountTaken;\n }\n }\n\n /// @notice Calls the recipient's hook function with the specified zapData and validates\n /// the returned value.\n function _triggerZapWithChecks(address recipient, address token, uint256 amount, bytes calldata zapData) internal {\n // Call the recipient's hook function with the specified zapData, bubbling any revert messages.\n bytes memory returnData = Address.functionCallWithValue({\n target: recipient,\n data: abi.encodeCall(IZapRecipient.zap, (token, amount, zapData)),\n // Note: see `relay()` for reasoning behind passing msg.value.\n value: msg.value\n });\n\n // Explicit revert if no return data at all.\n if (returnData.length == 0) revert RecipientNoReturnValue();\n // Check that exactly a single return value was returned.\n if (returnData.length != 32) revert RecipientIncorrectReturnValue();\n // Return value should be abi-encoded hook function selector.\n if (bytes32(returnData) != bytes32(IZapRecipient.zap.selector)) {\n revert RecipientIncorrectReturnValue();\n }\n }\n\n /// @notice Calculates the time elapsed since a proof was submitted.\n /// @dev The proof.timestamp stores block timestamps as uint56 for gas optimization.\n /// _timeSince(proof) handles timestamp rollover when block.timestamp \u003e type(uint56).max but\n /// proof.timestamp \u003c type(uint56).max via an unchecked statement.\n /// @param proofBlockTimestamp The block timestamp when the proof was submitted.\n /// @return delta The time elapsed since proof submission.\n function _timeSince(uint56 proofBlockTimestamp) internal view returns (uint256 delta) {\n unchecked {\n delta = uint56(block.timestamp) - proofBlockTimestamp;\n }\n }\n\n /// @notice Validates all parameters required for a bridge transaction.\n /// @dev This function's complexity cannot be reduced due to the number of required checks,\n /// so we disable the code-complexity rule.\n // solhint-disable-next-line code-complexity\n function _validateBridgeParams(\n BridgeParams memory params,\n BridgeParamsV2 memory paramsV2,\n int256 exclusivityEndTime\n )\n internal\n view\n {\n // Check V1 (legacy) params.\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.sender == address(0) || params.to == address(0)) revert ZeroAddress();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n\n // Check V2 params.\n if (paramsV2.zapData.length \u003e MAX_ZAP_DATA_LENGTH) revert ZapDataLengthAboveMax();\n if (paramsV2.zapNative != 0 \u0026\u0026 params.destToken == NATIVE_GAS_TOKEN) {\n revert ZapNativeNotSupported();\n }\n\n // exclusivityEndTime must be in range [0 .. params.deadline].\n if (exclusivityEndTime \u003c 0 || exclusivityEndTime \u003e int256(params.deadline)) {\n revert ExclusivityParamsIncorrect();\n }\n }\n\n /// @notice Validates all parameters required for a relay transaction.\n function _validateRelayParams(bytes calldata request, bytes32 transactionId, address relayer) internal view {\n if (relayer == address(0)) revert ZeroAddress();\n // Check that the transaction has not been relayed yet and is for the current chain.\n if (bridgeRelays(transactionId)) revert TransactionRelayed();\n if (request.destChainId() != block.chainid) revert ChainIncorrect();\n // Check that the deadline for relay to happen has not passed yet.\n if (block.timestamp \u003e request.deadline()) revert DeadlineExceeded();\n // Check the exclusivity period, if it was specified and is still ongoing.\n address exclRelayer = request.exclusivityRelayer();\n if (exclRelayer != address(0) \u0026\u0026 exclRelayer != relayer \u0026\u0026 block.timestamp \u003c= request.exclusivityEndTime()) {\n revert ExclusivityPeriodNotPassed();\n }\n }\n}\n","language":"Solidity","languageVersion":"0.8.24","compilerVersion":"0.8.24","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"28617:11640:0:-:0;;;;;;;;;;;;;;;-1:-1:-1;;;28617:11640:0;;;;;;;;;;;;;;;;;","srcMapRuntime":"28617:11640:0:-:0;;;;;;;;","abiDefinition":[],"userDoc":{"kind":"user","methods":{},"version":1},"developerDoc":{"details":"Library for managing https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive types. Sets have the following properties: - Elements are added, removed, and checked for existence in constant time (O(1)). - Elements are enumerated in O(n). No guarantees are made on the ordering. ```solidity contract Example { // Add the library methods using EnumerableSet for EnumerableSet.AddressSet; // Declare a set state variable EnumerableSet.AddressSet private mySet; } ``` As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`) and `uint256` (`UintSet`) are supported. [WARNING] ==== Trying to delete such a structure from storage will likely result in data corruption, rendering the structure unusable. See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info. In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an array of EnumerableSet. ====","kind":"dev","methods":{},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[],\"devdoc\":{\"details\":\"Library for managing https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive types. Sets have the following properties: - Elements are added, removed, and checked for existence in constant time (O(1)). - Elements are enumerated in O(n). No guarantees are made on the ordering. ```solidity contract Example { // Add the library methods using EnumerableSet for EnumerableSet.AddressSet; // Declare a set state variable EnumerableSet.AddressSet private mySet; } ``` As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`) and `uint256` (`UintSet`) are supported. [WARNING] ==== Trying to delete such a structure from storage will likely result in data corruption, rendering the structure unusable. See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info. In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an array of EnumerableSet. ====\",\"kind\":\"dev\",\"methods\":{},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeV2.sol\":\"EnumerableSet\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeV2.sol\":{\"keccak256\":\"0xaab2ee7357681726f0faf799a48ddfbf45fb4da93b69abf61c33dde92b29b74d\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://673391bff9569efc0f9bd99e0e6fece0bc8e8af1f052bb071b407b267a17b3b5\",\"dweb:/ipfs/QmdQQZ6DxpJYhfpinwU5WjLugr2f6qP8h68b5GerhSMQ4j\"]}},\"version\":1}"},"hashes":{}},"solidity/FastBridgeV2.sol:FastBridgeV2":{"code":"0x60e06040526000608081905260a0523480156200001b57600080fd5b50604051620047ba380380620047ba8339810160408190526200003e9162000215565b806200004c60008262000067565b506200005b62015180620000a4565b50504360c05262000240565b6000806200007684846200010d565b905080156200009b576000848152600160205260409020620000999084620001bb565b505b90505b92915050565b610e10811015620000c857604051630e0ea5c760e01b815260040160405180910390fd5b600480549082905560408051828152602081018490527f909f9078b2f6eac1d10f2aae793656c5a67511eb627ebd1d2cb1eb9c0ab94c95910160405180910390a15050565b6000828152602081815260408083206001600160a01b038516845290915281205460ff16620001b2576000838152602081815260408083206001600160a01b03861684529091529020805460ff19166001179055620001693390565b6001600160a01b0316826001600160a01b0316847f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45060016200009e565b5060006200009e565b60006200009b836001600160a01b0384166000818152600183016020526040812054620001b2575081546001818101845560008481526020808220909301849055845484825282860190935260409020919091556200009e565b6000602082840312156200022857600080fd5b81516001600160a01b03811681146200009b57600080fd5b60805160a05160c05161454a62000270600039600061095e015260006109ff01526000610bcc015261454a6000f3fe60806040526004361061034a5760003560e01c80637ebe815c116101bb578063aa9641ab116100f7578063ca15c87311610095578063dc9a4ef61161006f578063dc9a4ef614610b59578063dcf844a714610b8d578063e00a83e014610bba578063f76d727814610bee57600080fd5b8063ca15c87314610ae5578063ccc5749014610b05578063d547741f14610b3957600080fd5b8063affed0e0116100d1578063affed0e0146109ed578063b13aa2d614610a21578063bf333f2c14610a41578063c79371b114610a5857600080fd5b8063aa9641ab14610980578063ac11fb1a146109a0578063add98c70146109cd57600080fd5b806391ad503911610164578063930ac1801161013e578063930ac18014610920578063a217fddf14610937578063a3ec191a1461094c578063a5bbe22b1461078f57600080fd5b806391ad50391461084057806391d14854146108c6578063922b74871461090a57600080fd5b8063886d36ff11610195578063886d36ff146107ed5780638f0d6f171461080d5780639010d07c1461082057600080fd5b80637ebe815c1461075b578063820688d51461078f5780638379a24f146107a557600080fd5b80633d71e21f1161028a57806358f858801161023357806363787e521161020d57806363787e5214610698578063638a0f091461071257806367e6069314610728578063764430851461074857600080fd5b806358f85880146106355780635aa6ccba1461064b5780635eb7d9461461067857600080fd5b806341fdec801161026457806341fdec80146105ec578063458516941461060c57806354eff0681461061f57600080fd5b80633d71e21f146105995780633f61331d146105ac57806341fcb612146105cc57600080fd5b80630f862f1e116102f7578063295710ff116102d1578063295710ff146104ff5780632f2ff15d1461052c57806336568abe1461054c578063385c1d2f1461056c57600080fd5b80630f862f1e1461046f5780631ea327c5146104af578063248a9ca3146104cf57600080fd5b8063051287bc11610328578063051287bc146103fa57806306f333f2146104375780630f5f6ed71461045957600080fd5b806301ffc9a71461034f57806302d2ff661461038457806303ed0ee5146103c6575b600080fd5b34801561035b57600080fd5b5061036f61036a3660046134f6565b610c0e565b60405190151581526020015b60405180910390f35b34801561039057600080fd5b506103b87febfdca8e46c0b8dacf9989ee613e35727eadd20a1d5e5ad01a53968c7e5fe07a81565b60405190815260200161037b565b3480156103d257600080fd5b506103b87f043c983c49d46f0e102151eaf8085d4a2e6571d5df2d47b013f39bddfd4a639d81565b34801561040657600080fd5b5061042a610415366004613538565b60009081526005602052604090205460ff1690565b60405161037b91906135bb565b34801561044357600080fd5b506104576104523660046135ee565b610c6a565b005b34801561046557600080fd5b506103b861271081565b34801561047b57600080fd5b5061049773eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee81565b6040516001600160a01b03909116815260200161037b565b3480156104bb57600080fd5b506104576104ca366004613538565b610d77565b3480156104db57600080fd5b506103b86104ea366004613538565b60009081526020819052604090206001015490565b34801561050b57600080fd5b506103b861051a366004613627565b60076020526000908152604090205481565b34801561053857600080fd5b50610457610547366004613644565b610dae565b34801561055857600080fd5b50610457610567366004613644565b610dd3565b34801561057857600080fd5b5061058c610587366004613682565b610e1f565b60405161037b9190613758565b6104576105a7366004613837565b610fad565b3480156105b857600080fd5b506104576105c7366004613682565b611237565b3480156105d857600080fd5b506104576105e7366004613837565b6112e1565b3480156105f857600080fd5b50610457610607366004613883565b611553565b61045761061a366004613a66565b611668565b34801561062b57600080fd5b506103b861ffff81565b34801561064157600080fd5b506103b860025481565b34801561065757600080fd5b5061066b610666366004613a83565b6116c5565b60405161037b9190613ac5565b34801561068457600080fd5b50610457610693366004613a83565b611792565b3480156106a457600080fd5b506107026106b3366004613538565b60056020526000908152604090205460ff811690610100810463ffffffff169065010000000000810466ffffffffffffff16906c0100000000000000000000000090046001600160a01b031684565b60405161037b9493929190613be2565b34801561071e57600080fd5b506103b860045481565b34801561073457600080fd5b50610457610743366004613a83565b611798565b610457610756366004613ca1565b61199a565b34801561076757600080fd5b506103b87f9a04aea0a349253cc7277afafdf6ead6729a3972a47ffb40eaef2c93d4e1bfea81565b34801561079b57600080fd5b506103b861070881565b3480156107b157600080fd5b5061036f6107c0366004613538565b6000908152600660205260409020546c0100000000000000000000000090046001600160a01b0316151590565b3480156107f957600080fd5b50610457610808366004613d6f565b611c29565b61045761081b366004613a83565b611c55565b34801561082c57600080fd5b5061049761083b366004613dbb565b611c60565b34801561084c57600080fd5b5061089a61085b366004613538565b60009081526005602052604090205465010000000000810466ffffffffffffff16916c010000000000000000000000009091046001600160a01b031690565b604080516bffffffffffffffffffffffff90931683526001600160a01b0390911660208301520161037b565b3480156108d257600080fd5b5061036f6108e1366004613644565b6000918252602082815260408084206001600160a01b0393909316845291905290205460ff1690565b34801561091657600080fd5b506103b8610e1081565b34801561092c57600080fd5b506103b86201518081565b34801561094357600080fd5b506103b8600081565b34801561095857600080fd5b506103b87f000000000000000000000000000000000000000000000000000000000000000081565b34801561098c57600080fd5b5061036f61099b366004613644565b611c78565b3480156109ac57600080fd5b506109c06109bb366004613a83565b611d4f565b60405161037b9190613ddd565b3480156109d957600080fd5b506104576109e8366004613538565b611f03565b3480156109f957600080fd5b506103b87f000000000000000000000000000000000000000000000000000000000000000081565b348015610a2d57600080fd5b50610457610a3c366004613538565b61204d565b348015610a4d57600080fd5b506103b8620f424081565b348015610a6457600080fd5b50610ab7610a73366004613538565b60066020526000908152604090205465ffffffffffff8082169166010000000000008104909116906c0100000000000000000000000090046001600160a01b031683565b6040805165ffffffffffff94851681529390921660208401526001600160a01b03169082015260600161037b565b348015610af157600080fd5b506103b8610b00366004613538565b6120f9565b348015610b1157600080fd5b506103b87f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f5581565b348015610b4557600080fd5b50610457610b54366004613644565b612110565b348015610b6557600080fd5b506103b87f60044782a422109ac08a415e44260ad5d3bad63d96ebe1fac0363399642ee3f281565b348015610b9957600080fd5b506103b8610ba8366004613627565b60036020526000908152604090205481565b348015610bc657600080fd5b506103b87f000000000000000000000000000000000000000000000000000000000000000081565b348015610bfa57600080fd5b50610457610c09366004613a83565b612135565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f5a05180f000000000000000000000000000000000000000000000000000000001480610c645750610c6482612141565b92915050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f55610c94816121d8565b6001600160a01b03831660009081526003602052604081205490819003610cbb5750505050565b6001600160a01b038481166000818152600360209081526040808320929092558151928352928616928201929092529081018290527f244e51bc38c1452fa8aaf487bcb4bca36c2baa3a5fbdb776b1eabd8dc6d277cd9060600160405180910390a17fffffffffffffffffffffffff11111111111111111111111111111111111111126001600160a01b03851601610d5c57610d5783826121e2565b610d70565b610d706001600160a01b03851684836122b0565b505b505050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f55610da1816121d8565b610daa82612324565b5050565b600082815260208190526040902060010154610dc9816121d8565b610d7083836123a5565b6001600160a01b0381163314610e15576040517f6697b23200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610d7282826123d2565b60608267ffffffffffffffff811115610e3a57610e3a6138b1565b604051908082528060200260200182016040528015610e8057816020015b604080518082019091526000815260606020820152815260200190600190039081610e585790505b50905060005b83811015610fa55730858583818110610ea157610ea1613ec3565b9050602002810190610eb39190613ef2565b604051610ec1929190613f57565b600060405180830381855af49150503d8060008114610efc576040519150601f19603f3d011682016040523d82523d6000602084013e610f01565b606091505b50838381518110610f1457610f14613ec3565b6020026020010151600001848481518110610f3157610f31613ec3565b602002602001015160200182905282151515158152505050818181518110610f5b57610f5b613ec3565b602002602001015160000151158015610f72575082155b15610f9d57610f9d828281518110610f8c57610f8c613ec3565b6020026020010151602001516123ff565b600101610e86565b509392505050565b610fb78383612441565b60008383604051610fc9929190613f57565b60405180910390209050610fdf848483856124c2565b600081815260066020526040902080546001600160a01b0384166c0100000000000000000000000081026bffffffffffffffffffffffff4265ffffffffffff9081166601000000000000027fffffffffffffffffffffffffffffffffffffffff000000000000000000000000909516439190911617939093179290921691909117909155601e850135606090811c91604687013590911c90607a8701359061012e880135908490867ff8ae392d784b1ea5e8881bfa586d81abf07ef4f1e2fc75f7fe51c90f05199a5c60028c013560e01c6040805163ffffffff92909216825260328e0135606090811c60208401526001600160a01b038a1683830152605a8f0135908301526080820188905260a08201879052519081900360c00190a47fffffffffffffffffffffffff11111111111111111111111111111111111111126001600160a01b038416016111a3578015611165576040517f846dedc000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b81341461119e576040517f81de0bf300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6111f1565b8034146111dc576040517f81de0bf300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6111f16001600160a01b038416338685612657565b3660006111fe8a8a612690565b9092509050801561121b5761121686868685856126ac565b61122b565b341561122b5761122b86346121e2565b50505050505050505050565b60005b82811015610d70576000803086868581811061125857611258613ec3565b905060200281019061126a9190613ef2565b604051611278929190613f57565b600060405180830381855af49150503d80600081146112b3576040519150601f19603f3d011682016040523d82523d6000602084013e6112b8565b606091505b5091509150811580156112c9575083155b156112d7576112d7816123ff565b505060010161123a565b6112eb8383612441565b600083836040516112fd929190613f57565b604080519182900390912060008181526005602052919091208054919250906c0100000000000000000000000081046001600160a01b03169060ff81169065010000000000900466ffffffffffffff16600282600481111561136157611361613551565b14611398576040517f4145817200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6107084282900366ffffffffffffff16116113df576040517f1992d0bd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600160a01b0386166113f557829550611437565b6001600160a01b0383163314611437576040517f4af43a9000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b83547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166003178455603288013560601c605a890135609a8a013580156114a6576001600160a01b038316600090815260036020526040812080548392906114a0908490613f96565b90915550505b604080516001600160a01b03858116825260208201859052808c1692908916918b917f582211c35a2139ac3bbaac74663c6a1f56c6cbb658b41fe11fd45a82074ac678910160405180910390a47fffffffffffffffffffffffff11111111111111111111111111111111111111126001600160a01b038416016115325761152d89836121e2565b611546565b6115466001600160a01b0384168a846122b0565b5050505050505050505050565b7f60044782a422109ac08a415e44260ad5d3bad63d96ebe1fac0363399642ee3f261157d816121d8565b60008481526005602052604090206001815460ff1660048111156115a3576115a3613551565b146115da576040517f4145817200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80546001600160a01b0384166c0100000000000000000000000081026bffffffffffffffffffffffff66ffffffffffffff421665010000000000021664ffffffff009093169290921791909117600217825560405185815286907f4ac8af8a2cd87193d64dfc7a3b8d9923b714ec528b18725d080aa1299be0c5e49060200160405180910390a35050505050565b6116c2816040518060a0016040528060006001600160a01b0316815260200160008152602001604051806020016040528060008152508152602001600081526020016040518060200160405280600081525081525061199a565b50565b611777604051806101e00160405280600063ffffffff168152602001600063ffffffff16815260200160006001600160a01b0316815260200160006001600160a01b0316815260200160006001600160a01b0316815260200160006001600160a01b03168152602001600081526020016000815260200160008152602001600081526020016000815260200160006001600160a01b031681526020016000815260200160008152602001606081525090565b6117818383612441565b61178b8383612808565b9392505050565b610daa82825b6117a28282612441565b600082826040516117b4929190613f57565b604080519182900390912060008181526005602052919091209091506001815460ff1660048111156117e8576117e8613551565b1461181f576040517f4145817200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b3360009081527f4527d8b28c468984933d33ae052f26b21c15ca0e7fdec762bba08e540e237001602052604090205460ba8501359060ff1661186b576004546118689082613f96565b90505b8042116118a4576040517fe15ff9ea00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b81547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166004178255600a850135606090811c906032870135901c60006118f3609a890135605a8a0135613f96565b604080516001600160a01b03858116825260208201849052825193945086169289927fb4c55c0c9bc613519b920e88748090150b890a875d307f21bea7d4fb2e8bc958928290030190a37fffffffffffffffffffffffff11111111111111111111111111111111111111126001600160a01b0383160161197c5761197783826121e2565b611990565b6119906001600160a01b03831684836122b0565b5050505050505050565b80516000906001600160a01b0316156119bf5760208201516119bc9042613fa9565b90505b6119ca8383836129aa565b60006119de84606001518560a00151612c2e565b90506000806002541115611a1757620f4240600254836119fe9190613fd1565b611a089190613fe8565b9050611a148183614023565b91505b6000611b20604051806101e001604052804663ffffffff168152602001886000015163ffffffff16815260200188602001516001600160a01b0316815260200188604001516001600160a01b0316815260200188606001516001600160a01b0316815260200188608001516001600160a01b031681526020018581526020018860c0015181526020018481526020018861010001518152602001600760008a602001516001600160a01b03166001600160a01b031681526020019081526020016000206000815480929190611aeb90614036565b90915550815287516001600160a01b031660208201526040810187905260608089015190820152608080890151910152612e41565b805160208083019190912060008181526005835260409081902080548b5163ffffffff8116610100027fffffffffffffffffffffffffffffffffffffffffffffffffffffff000000000090921691909117600117909155928a01516060808c015160808d015160c08e0151928d0151945197985094966001600160a01b039093169587957f120ea0364f36cdac7983bcfdd55270ca09d7f9b314a2ebc425a3b01ab1d6403a95611bdc958b959394938e9290919015159061406e565b60405180910390a3807f3120e2bb59c86aca6890191a589a96af3662838efa374fbdcdf4c95bfe4a6c0e8760400151604051611c1891906140c4565b60405180910390a250505050505050565b611c338383612441565b610d728383604051611c46929190613f57565b60405180910390208233611553565b610daa828233610fad565b600082815260016020526040812061178b9083612f86565b60008281526005602052604081206002815460ff166004811115611c9e57611c9e613551565b14611cd5576040517f4145817200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80546001600160a01b038481166c010000000000000000000000009092041614611d2b576040517f4af43a9000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b546107086501000000000090910466ffffffffffffff908116420316119392505050565b6040805161018081018252600080825260208201819052818301819052606082018190526080820181905260a0820181905260c0820181905260e0820181905261010082018190526101208201819052610140820181905261016082015290517f5aa6ccba0000000000000000000000000000000000000000000000000000000081523090635aa6ccba90611dea9086908690600401614102565b600060405180830381865afa925050508015611e2857506040513d6000823e601f3d908101601f19168201604052611e259190810190614171565b60015b611e3f57611e38828401846142a6565b9050610c64565b604051806101800160405280826000015163ffffffff168152602001826020015163ffffffff16815260200182604001516001600160a01b0316815260200182606001516001600160a01b0316815260200182608001516001600160a01b031681526020018260a001516001600160a01b031681526020018260c0015181526020018260e0015181526020018261010001518152602001826101a0015160001415151581526020018261012001518152602001826101400151815250915050610c64565b7f043c983c49d46f0e102151eaf8085d4a2e6571d5df2d47b013f39bddfd4a639d611f2d816121d8565b600082815260056020526040902080546c0100000000000000000000000081046001600160a01b03169060ff81169065010000000000900466ffffffffffffff166002826004811115611f8257611f82613551565b14611fb9576040517f4145817200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6107084282900366ffffffffffffff161115612001576040517f3e908aac00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b835464ffffffff001660011784556040516001600160a01b0384169087907f0695cf1d39b3055dcd0fe02d8b47eaf0d5a13e1996de925de59d0ef9b7f7fad490600090a3505050505050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f55612077816121d8565b6127108211156120b3576040517f9b569b8100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600280549083905560408051828152602081018590527f14914da2bf76024616fbe1859783fcd4dbddcb179b1f3a854949fbf920dcb957910160405180910390a1505050565b6000818152600160205260408120610c6490612f92565b60008281526020819052604090206001015461212b816121d8565b610d7083836123d2565b610daa828260006112e1565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f7965db0b000000000000000000000000000000000000000000000000000000001480610c6457507f01ffc9a7000000000000000000000000000000000000000000000000000000007fffffffff00000000000000000000000000000000000000000000000000000000831614610c64565b6116c28133612f9c565b80471015612223576040517fcd7860590000000000000000000000000000000000000000000000000000000081523060048201526024015b60405180910390fd5b6000826001600160a01b03168260405160006040518083038185875af1925050503d8060008114612270576040519150601f19603f3d011682016040523d82523d6000602084013e612275565b606091505b5050905080610d72576040517f1425ea4200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040516001600160a01b03838116602483015260448201839052610d7291859182169063a9059cbb906064015b604051602081830303815290604052915060e01b6020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8381831617835250505050613008565b610e10811015612360576040517f0e0ea5c700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600480549082905560408051828152602081018490527f909f9078b2f6eac1d10f2aae793656c5a67511eb627ebd1d2cb1eb9c0ab94c95910160405180910390a15050565b6000806123b28484613084565b9050801561178b576000848152600160205260409020610fa5908461314c565b6000806123df8484613161565b9050801561178b576000848152600160205260409020610fa59084613202565b80511561240f5780518082602001fd5b6040517f5ead5a9d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61014e81101561247d576040517f6ee0e17100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b813560f01c60028114610d72576040517f8bd977e700000000000000000000000000000000000000000000000000000000815261ffff8216600482015260240161221a565b6001600160a01b038116612502576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000828152600660205260409020546c0100000000000000000000000090046001600160a01b031615612561576040517fbef7bb7d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600684013560e01c46146125a1576040517f7029fdf900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60ba8401354211156125df576040517f559895a300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60fa84013560601c80158015906126085750816001600160a01b0316816001600160a01b031614155b8015612619575061010e8501354211155b15612650576040517f14be123200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5050505050565b6040516001600160a01b038481166024830152838116604483015260648201839052610d709186918216906323b872dd906084016122dd565b3660006126a18361014e8187614372565b915091509250929050565b600061272786868686866040516024016126c9949392919061439c565b60408051601f198184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fe85e13dd0000000000000000000000000000000000000000000000000000000017905234613217565b90508051600003612764576040517f1a95ad2600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b805160201461279f576040517ff3725cca00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7fe85e13dd000000000000000000000000000000000000000000000000000000006127c9826143c5565b14612800576040517ff3725cca00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b505050505050565b6128ba604051806101e00160405280600063ffffffff168152602001600063ffffffff16815260200160006001600160a01b0316815260200160006001600160a01b0316815260200160006001600160a01b0316815260200160006001600160a01b03168152602001600081526020016000815260200160008152602001600081526020016000815260200160006001600160a01b031681526020016000815260200160008152602001606081525090565b600283013560e090811c82526006840135811c6020830152600a840135606090811c6040840152601e850135811c818401526032850135811c60808401526046850135811c60a0840152605a85013560c0840152607a85013591830191909152609a84013561010083015260ba84013561012083015260da84013561014083015260fa840135901c61016082015261010e83013561018082015261012e8301356101a082015261296a8383612690565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152505050506101c082015292915050565b46836000015163ffffffff16036129ed576040517f7029fdf900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60a08301511580612a00575060c0830151155b15612a37576040517fe38820c800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60208301516001600160a01b03161580612a5c575060408301516001600160a01b0316155b15612a93576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60608301516001600160a01b03161580612ab8575060808301516001600160a01b0316155b15612aef576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b612afb61070842613f96565b8361010001511015612b39576040517f04b7fcc800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61ffff8260800151511115612b7a576040517f177a70e100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b606082015115801590612bad575060808301516001600160a01b031673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee145b15612be4576040517f846dedc000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000811280612bf7575082610100015181135b15610d72576040517f352807b900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60007fffffffffffffffffffffffff11111111111111111111111111111111111111126001600160a01b03841601612ca057348214612c99576040517f81de0bf300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5034610c64565b3415612cd8576040517f81de0bf300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b826001600160a01b03163b600003612d1c576040517f7f523fe800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201526001600160a01b038416906370a0823190602401602060405180830381865afa158015612d79573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612d9d919061440a565b9050612db46001600160a01b038416333085612657565b6040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015281906001600160a01b038516906370a0823190602401602060405180830381865afa158015612e13573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612e37919061440a565b61178b9190614023565b8051602080830151604080850151606086810151608088015160a089015160c08a015195517e02000000000000000000000000000000000000000000000000000000000000988101989098527fffffffff0000000000000000000000000000000000000000000000000000000060e0998a1b811660228a01529690981b90951660268701527fffffffffffffffffffffffffffffffffffffffff00000000000000000000000092821b8316602a870152811b8216603e86015292831b8116605285015293821b9093166066830152607a820192909252600090609a0160408051601f198184030181529082905260e08501516101008601516101208701516101408801516101608901516101808a01516101a08b01516101c08c0151979950612f6f988a9890602001614423565b604051602081830303815290604052915050919050565b600061178b83836132cd565b6000610c64825490565b6000828152602081815260408083206001600160a01b038516845290915290205460ff16610daa576040517fe2517d3f0000000000000000000000000000000000000000000000000000000081526001600160a01b03821660048201526024810183905260440161221a565b600061301d6001600160a01b038416836132f7565b9050805160001415801561304257508080602001905181019061304091906144ac565b155b15610d72576040517f5274afe70000000000000000000000000000000000000000000000000000000081526001600160a01b038416600482015260240161221a565b6000828152602081815260408083206001600160a01b038516845290915281205460ff16613144576000838152602081815260408083206001600160a01b0386168452909152902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790556130fc3390565b6001600160a01b0316826001600160a01b0316847f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a4506001610c64565b506000610c64565b600061178b836001600160a01b038416613305565b6000828152602081815260408083206001600160a01b038516845290915281205460ff1615613144576000838152602081815260408083206001600160a01b038616808552925280832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016905551339286917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a4506001610c64565b600061178b836001600160a01b03841661334c565b606081471015613255576040517fcd78605900000000000000000000000000000000000000000000000000000000815230600482015260240161221a565b600080856001600160a01b0316848660405161327191906144c9565b60006040518083038185875af1925050503d80600081146132ae576040519150601f19603f3d011682016040523d82523d6000602084013e6132b3565b606091505b50915091506132c386838361343f565b9695505050505050565b60008260000182815481106132e4576132e4613ec3565b9060005260206000200154905092915050565b606061178b83836000613217565b600081815260018301602052604081205461314457508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155610c64565b60008181526001830160205260408120548015613435576000613370600183614023565b855490915060009061338490600190614023565b90508082146133e95760008660000182815481106133a4576133a4613ec3565b90600052602060002001549050808760000184815481106133c7576133c7613ec3565b6000918252602080832090910192909255918252600188019052604090208390555b85548690806133fa576133fa6144e5565b600190038181906000526020600020016000905590558560010160008681526020019081526020016000206000905560019350505050610c64565b6000915050610c64565b6060826134545761344f826134b4565b61178b565b815115801561346b57506001600160a01b0384163b155b156134ad576040517f9996b3150000000000000000000000000000000000000000000000000000000081526001600160a01b038516600482015260240161221a565b508061178b565b8051156134c45780518082602001fd5b6040517f1425ea4200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006020828403121561350857600080fd5b81357fffffffff000000000000000000000000000000000000000000000000000000008116811461178b57600080fd5b60006020828403121561354a57600080fd5b5035919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b600581106135b7577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b9052565b60208101610c648284613580565b6001600160a01b03811681146116c257600080fd5b80356135e9816135c9565b919050565b6000806040838503121561360157600080fd5b823561360c816135c9565b9150602083013561361c816135c9565b809150509250929050565b60006020828403121561363957600080fd5b813561178b816135c9565b6000806040838503121561365757600080fd5b82359150602083013561361c816135c9565b80151581146116c257600080fd5b80356135e981613669565b60008060006040848603121561369757600080fd5b833567ffffffffffffffff808211156136af57600080fd5b818601915086601f8301126136c357600080fd5b8135818111156136d257600080fd5b8760208260051b85010111156136e757600080fd5b602092830195509350508401356136fd81613669565b809150509250925092565b60005b8381101561372357818101518382015260200161370b565b50506000910152565b60008151808452613744816020860160208601613708565b601f01601f19169290920160200192915050565b600060208083018184528085518083526040925060408601915060408160051b87010184880160005b838110156137e0578883037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc001855281518051151584528701518784018790526137cd8785018261372c565b9588019593505090860190600101613781565b509098975050505050505050565b60008083601f84011261380057600080fd5b50813567ffffffffffffffff81111561381857600080fd5b60208301915083602082850101111561383057600080fd5b9250929050565b60008060006040848603121561384c57600080fd5b833567ffffffffffffffff81111561386357600080fd5b61386f868287016137ee565b90945092505060208401356136fd816135c9565b60008060006060848603121561389857600080fd5b833592506020840135915060408401356136fd816135c9565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051610120810167ffffffffffffffff81118282101715613904576139046138b1565b60405290565b60405160a0810167ffffffffffffffff81118282101715613904576139046138b1565b6040516101e0810167ffffffffffffffff81118282101715613904576139046138b1565b604051610180810167ffffffffffffffff81118282101715613904576139046138b1565b604051601f8201601f1916810167ffffffffffffffff8111828210171561399e5761399e6138b1565b604052919050565b63ffffffff811681146116c257600080fd5b80356135e9816139a6565b600061012082840312156139d657600080fd5b6139de6138e0565b90506139e9826139b8565b81526139f7602083016135de565b6020820152613a08604083016135de565b6040820152613a19606083016135de565b6060820152613a2a608083016135de565b608082015260a082013560a082015260c082013560c0820152613a4f60e08301613677565b60e082015261010080830135818301525092915050565b60006101208284031215613a7957600080fd5b61178b83836139c3565b60008060208385031215613a9657600080fd5b823567ffffffffffffffff811115613aad57600080fd5b613ab9858286016137ee565b90969095509350505050565b60208152613adc60208201835163ffffffff169052565b60006020830151613af5604084018263ffffffff169052565b5060408301516001600160a01b03811660608401525060608301516001600160a01b03811660808401525060808301516001600160a01b03811660a08401525060a08301516001600160a01b03811660c08401525060c083015160e08381019190915283015161010080840191909152830151610120808401919091528301516101408084019190915283015161016080840191909152830151610180613ba6818501836001600160a01b03169052565b8401516101a0848101919091528401516101c0808501919091528401516101e0808501529050613bda61020084018261372c565b949350505050565b60808101613bf08287613580565b63ffffffff8516602083015266ffffffffffffff841660408301526001600160a01b038316606083015295945050505050565b600067ffffffffffffffff821115613c3d57613c3d6138b1565b50601f01601f191660200190565b600082601f830112613c5c57600080fd5b8135613c6f613c6a82613c23565b613975565b818152846020838601011115613c8457600080fd5b816020850160208301376000918101602001919091529392505050565b6000806101408385031215613cb557600080fd5b613cbf84846139c3565b915061012083013567ffffffffffffffff80821115613cdd57600080fd5b9084019060a08287031215613cf157600080fd5b613cf961390a565b8235613d04816135c9565b815260208381013590820152604083013582811115613d2257600080fd5b613d2e88828601613c4b565b60408301525060608301356060820152608083013582811115613d5057600080fd5b613d5c88828601613c4b565b6080830152508093505050509250929050565b600080600060408486031215613d8457600080fd5b833567ffffffffffffffff811115613d9b57600080fd5b613da7868287016137ee565b909790965060209590950135949350505050565b60008060408385031215613dce57600080fd5b50508035926020909101359150565b815163ffffffff16815261018081016020830151613e03602084018263ffffffff169052565b506040830151613e1e60408401826001600160a01b03169052565b506060830151613e3960608401826001600160a01b03169052565b506080830151613e5460808401826001600160a01b03169052565b5060a0830151613e6f60a08401826001600160a01b03169052565b5060c083015160c083015260e083015160e083015261010080840151818401525061012080840151613ea48285018215159052565b5050610140838101519083015261016092830151929091019190915290565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112613f2757600080fd5b83018035915067ffffffffffffffff821115613f4257600080fd5b60200191503681900382131561383057600080fd5b8183823760009101908152919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b80820180821115610c6457610c64613f67565b8082018281126000831280158216821582161715613fc957613fc9613f67565b505092915050565b8082028115828204841417610c6457610c64613f67565b60008261401e577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b81810381811115610c6457610c64613f67565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820361406757614067613f67565b5060010190565b60e08152600061408160e083018a61372c565b63ffffffff989098166020830152506001600160a01b039586166040820152939094166060840152608083019190915260a082015290151560c090910152919050565b60208152600061178b602083018461372c565b818352818160208501375060006020828401015260006020601f19601f840116840101905092915050565b602081526000613bda6020830184866140d7565b80516135e9816139a6565b80516135e9816135c9565b600082601f83011261413d57600080fd5b815161414b613c6a82613c23565b81815284602083860101111561416057600080fd5b613bda826020830160208701613708565b60006020828403121561418357600080fd5b815167ffffffffffffffff8082111561419b57600080fd5b908301906101e082860312156141b057600080fd5b6141b861392d565b6141c183614116565b81526141cf60208401614116565b60208201526141e060408401614121565b60408201526141f160608401614121565b606082015261420260808401614121565b608082015261421360a08401614121565b60a082015260c0838101519082015260e0808401519082015261010080840151908201526101208084015190820152610140808401519082015261016061425b818501614121565b9082015261018083810151908201526101a080840151908201526101c0808401518381111561428957600080fd5b6142958882870161412c565b918301919091525095945050505050565b600061018082840312156142b957600080fd5b6142c1613951565b6142ca836139b8565b81526142d8602084016139b8565b60208201526142e9604084016135de565b60408201526142fa606084016135de565b606082015261430b608084016135de565b608082015261431c60a084016135de565b60a082015260c083013560c082015260e083013560e082015261010080840135818301525061012061434f818501613677565b908201526101408381013590820152610160928301359281019290925250919050565b6000808585111561438257600080fd5b8386111561438f57600080fd5b5050820193919092039150565b6001600160a01b03851681528360208201526060604082015260006132c36060830184866140d7565b80516020808301519190811015614404577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8160200360031b1b821691505b50919050565b60006020828403121561441c57600080fd5b5051919050565b60008a51614435818460208f01613708565b80830190508a81528960208201528860408201528760608201527fffffffffffffffffffffffffffffffffffffffff0000000000000000000000008760601b1660808201528560948201528460b482015283516144998160d4840160208801613708565b0160d4019b9a5050505050505050505050565b6000602082840312156144be57600080fd5b815161178b81613669565b600082516144db818460208701613708565b9190910192915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fdfea264697066735822122082edd55575a2d7fd882d29c1a5d3a24f84d274aca2cf25f32089fce5162775cc64736f6c63430008180033","runtime-code":"0x60806040526004361061034a5760003560e01c80637ebe815c116101bb578063aa9641ab116100f7578063ca15c87311610095578063dc9a4ef61161006f578063dc9a4ef614610b59578063dcf844a714610b8d578063e00a83e014610bba578063f76d727814610bee57600080fd5b8063ca15c87314610ae5578063ccc5749014610b05578063d547741f14610b3957600080fd5b8063affed0e0116100d1578063affed0e0146109ed578063b13aa2d614610a21578063bf333f2c14610a41578063c79371b114610a5857600080fd5b8063aa9641ab14610980578063ac11fb1a146109a0578063add98c70146109cd57600080fd5b806391ad503911610164578063930ac1801161013e578063930ac18014610920578063a217fddf14610937578063a3ec191a1461094c578063a5bbe22b1461078f57600080fd5b806391ad50391461084057806391d14854146108c6578063922b74871461090a57600080fd5b8063886d36ff11610195578063886d36ff146107ed5780638f0d6f171461080d5780639010d07c1461082057600080fd5b80637ebe815c1461075b578063820688d51461078f5780638379a24f146107a557600080fd5b80633d71e21f1161028a57806358f858801161023357806363787e521161020d57806363787e5214610698578063638a0f091461071257806367e6069314610728578063764430851461074857600080fd5b806358f85880146106355780635aa6ccba1461064b5780635eb7d9461461067857600080fd5b806341fdec801161026457806341fdec80146105ec578063458516941461060c57806354eff0681461061f57600080fd5b80633d71e21f146105995780633f61331d146105ac57806341fcb612146105cc57600080fd5b80630f862f1e116102f7578063295710ff116102d1578063295710ff146104ff5780632f2ff15d1461052c57806336568abe1461054c578063385c1d2f1461056c57600080fd5b80630f862f1e1461046f5780631ea327c5146104af578063248a9ca3146104cf57600080fd5b8063051287bc11610328578063051287bc146103fa57806306f333f2146104375780630f5f6ed71461045957600080fd5b806301ffc9a71461034f57806302d2ff661461038457806303ed0ee5146103c6575b600080fd5b34801561035b57600080fd5b5061036f61036a3660046134f6565b610c0e565b60405190151581526020015b60405180910390f35b34801561039057600080fd5b506103b87febfdca8e46c0b8dacf9989ee613e35727eadd20a1d5e5ad01a53968c7e5fe07a81565b60405190815260200161037b565b3480156103d257600080fd5b506103b87f043c983c49d46f0e102151eaf8085d4a2e6571d5df2d47b013f39bddfd4a639d81565b34801561040657600080fd5b5061042a610415366004613538565b60009081526005602052604090205460ff1690565b60405161037b91906135bb565b34801561044357600080fd5b506104576104523660046135ee565b610c6a565b005b34801561046557600080fd5b506103b861271081565b34801561047b57600080fd5b5061049773eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee81565b6040516001600160a01b03909116815260200161037b565b3480156104bb57600080fd5b506104576104ca366004613538565b610d77565b3480156104db57600080fd5b506103b86104ea366004613538565b60009081526020819052604090206001015490565b34801561050b57600080fd5b506103b861051a366004613627565b60076020526000908152604090205481565b34801561053857600080fd5b50610457610547366004613644565b610dae565b34801561055857600080fd5b50610457610567366004613644565b610dd3565b34801561057857600080fd5b5061058c610587366004613682565b610e1f565b60405161037b9190613758565b6104576105a7366004613837565b610fad565b3480156105b857600080fd5b506104576105c7366004613682565b611237565b3480156105d857600080fd5b506104576105e7366004613837565b6112e1565b3480156105f857600080fd5b50610457610607366004613883565b611553565b61045761061a366004613a66565b611668565b34801561062b57600080fd5b506103b861ffff81565b34801561064157600080fd5b506103b860025481565b34801561065757600080fd5b5061066b610666366004613a83565b6116c5565b60405161037b9190613ac5565b34801561068457600080fd5b50610457610693366004613a83565b611792565b3480156106a457600080fd5b506107026106b3366004613538565b60056020526000908152604090205460ff811690610100810463ffffffff169065010000000000810466ffffffffffffff16906c0100000000000000000000000090046001600160a01b031684565b60405161037b9493929190613be2565b34801561071e57600080fd5b506103b860045481565b34801561073457600080fd5b50610457610743366004613a83565b611798565b610457610756366004613ca1565b61199a565b34801561076757600080fd5b506103b87f9a04aea0a349253cc7277afafdf6ead6729a3972a47ffb40eaef2c93d4e1bfea81565b34801561079b57600080fd5b506103b861070881565b3480156107b157600080fd5b5061036f6107c0366004613538565b6000908152600660205260409020546c0100000000000000000000000090046001600160a01b0316151590565b3480156107f957600080fd5b50610457610808366004613d6f565b611c29565b61045761081b366004613a83565b611c55565b34801561082c57600080fd5b5061049761083b366004613dbb565b611c60565b34801561084c57600080fd5b5061089a61085b366004613538565b60009081526005602052604090205465010000000000810466ffffffffffffff16916c010000000000000000000000009091046001600160a01b031690565b604080516bffffffffffffffffffffffff90931683526001600160a01b0390911660208301520161037b565b3480156108d257600080fd5b5061036f6108e1366004613644565b6000918252602082815260408084206001600160a01b0393909316845291905290205460ff1690565b34801561091657600080fd5b506103b8610e1081565b34801561092c57600080fd5b506103b86201518081565b34801561094357600080fd5b506103b8600081565b34801561095857600080fd5b506103b87f000000000000000000000000000000000000000000000000000000000000000081565b34801561098c57600080fd5b5061036f61099b366004613644565b611c78565b3480156109ac57600080fd5b506109c06109bb366004613a83565b611d4f565b60405161037b9190613ddd565b3480156109d957600080fd5b506104576109e8366004613538565b611f03565b3480156109f957600080fd5b506103b87f000000000000000000000000000000000000000000000000000000000000000081565b348015610a2d57600080fd5b50610457610a3c366004613538565b61204d565b348015610a4d57600080fd5b506103b8620f424081565b348015610a6457600080fd5b50610ab7610a73366004613538565b60066020526000908152604090205465ffffffffffff8082169166010000000000008104909116906c0100000000000000000000000090046001600160a01b031683565b6040805165ffffffffffff94851681529390921660208401526001600160a01b03169082015260600161037b565b348015610af157600080fd5b506103b8610b00366004613538565b6120f9565b348015610b1157600080fd5b506103b87f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f5581565b348015610b4557600080fd5b50610457610b54366004613644565b612110565b348015610b6557600080fd5b506103b87f60044782a422109ac08a415e44260ad5d3bad63d96ebe1fac0363399642ee3f281565b348015610b9957600080fd5b506103b8610ba8366004613627565b60036020526000908152604090205481565b348015610bc657600080fd5b506103b87f000000000000000000000000000000000000000000000000000000000000000081565b348015610bfa57600080fd5b50610457610c09366004613a83565b612135565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f5a05180f000000000000000000000000000000000000000000000000000000001480610c645750610c6482612141565b92915050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f55610c94816121d8565b6001600160a01b03831660009081526003602052604081205490819003610cbb5750505050565b6001600160a01b038481166000818152600360209081526040808320929092558151928352928616928201929092529081018290527f244e51bc38c1452fa8aaf487bcb4bca36c2baa3a5fbdb776b1eabd8dc6d277cd9060600160405180910390a17fffffffffffffffffffffffff11111111111111111111111111111111111111126001600160a01b03851601610d5c57610d5783826121e2565b610d70565b610d706001600160a01b03851684836122b0565b505b505050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f55610da1816121d8565b610daa82612324565b5050565b600082815260208190526040902060010154610dc9816121d8565b610d7083836123a5565b6001600160a01b0381163314610e15576040517f6697b23200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610d7282826123d2565b60608267ffffffffffffffff811115610e3a57610e3a6138b1565b604051908082528060200260200182016040528015610e8057816020015b604080518082019091526000815260606020820152815260200190600190039081610e585790505b50905060005b83811015610fa55730858583818110610ea157610ea1613ec3565b9050602002810190610eb39190613ef2565b604051610ec1929190613f57565b600060405180830381855af49150503d8060008114610efc576040519150601f19603f3d011682016040523d82523d6000602084013e610f01565b606091505b50838381518110610f1457610f14613ec3565b6020026020010151600001848481518110610f3157610f31613ec3565b602002602001015160200182905282151515158152505050818181518110610f5b57610f5b613ec3565b602002602001015160000151158015610f72575082155b15610f9d57610f9d828281518110610f8c57610f8c613ec3565b6020026020010151602001516123ff565b600101610e86565b509392505050565b610fb78383612441565b60008383604051610fc9929190613f57565b60405180910390209050610fdf848483856124c2565b600081815260066020526040902080546001600160a01b0384166c0100000000000000000000000081026bffffffffffffffffffffffff4265ffffffffffff9081166601000000000000027fffffffffffffffffffffffffffffffffffffffff000000000000000000000000909516439190911617939093179290921691909117909155601e850135606090811c91604687013590911c90607a8701359061012e880135908490867ff8ae392d784b1ea5e8881bfa586d81abf07ef4f1e2fc75f7fe51c90f05199a5c60028c013560e01c6040805163ffffffff92909216825260328e0135606090811c60208401526001600160a01b038a1683830152605a8f0135908301526080820188905260a08201879052519081900360c00190a47fffffffffffffffffffffffff11111111111111111111111111111111111111126001600160a01b038416016111a3578015611165576040517f846dedc000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b81341461119e576040517f81de0bf300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6111f1565b8034146111dc576040517f81de0bf300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6111f16001600160a01b038416338685612657565b3660006111fe8a8a612690565b9092509050801561121b5761121686868685856126ac565b61122b565b341561122b5761122b86346121e2565b50505050505050505050565b60005b82811015610d70576000803086868581811061125857611258613ec3565b905060200281019061126a9190613ef2565b604051611278929190613f57565b600060405180830381855af49150503d80600081146112b3576040519150601f19603f3d011682016040523d82523d6000602084013e6112b8565b606091505b5091509150811580156112c9575083155b156112d7576112d7816123ff565b505060010161123a565b6112eb8383612441565b600083836040516112fd929190613f57565b604080519182900390912060008181526005602052919091208054919250906c0100000000000000000000000081046001600160a01b03169060ff81169065010000000000900466ffffffffffffff16600282600481111561136157611361613551565b14611398576040517f4145817200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6107084282900366ffffffffffffff16116113df576040517f1992d0bd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600160a01b0386166113f557829550611437565b6001600160a01b0383163314611437576040517f4af43a9000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b83547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166003178455603288013560601c605a890135609a8a013580156114a6576001600160a01b038316600090815260036020526040812080548392906114a0908490613f96565b90915550505b604080516001600160a01b03858116825260208201859052808c1692908916918b917f582211c35a2139ac3bbaac74663c6a1f56c6cbb658b41fe11fd45a82074ac678910160405180910390a47fffffffffffffffffffffffff11111111111111111111111111111111111111126001600160a01b038416016115325761152d89836121e2565b611546565b6115466001600160a01b0384168a846122b0565b5050505050505050505050565b7f60044782a422109ac08a415e44260ad5d3bad63d96ebe1fac0363399642ee3f261157d816121d8565b60008481526005602052604090206001815460ff1660048111156115a3576115a3613551565b146115da576040517f4145817200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80546001600160a01b0384166c0100000000000000000000000081026bffffffffffffffffffffffff66ffffffffffffff421665010000000000021664ffffffff009093169290921791909117600217825560405185815286907f4ac8af8a2cd87193d64dfc7a3b8d9923b714ec528b18725d080aa1299be0c5e49060200160405180910390a35050505050565b6116c2816040518060a0016040528060006001600160a01b0316815260200160008152602001604051806020016040528060008152508152602001600081526020016040518060200160405280600081525081525061199a565b50565b611777604051806101e00160405280600063ffffffff168152602001600063ffffffff16815260200160006001600160a01b0316815260200160006001600160a01b0316815260200160006001600160a01b0316815260200160006001600160a01b03168152602001600081526020016000815260200160008152602001600081526020016000815260200160006001600160a01b031681526020016000815260200160008152602001606081525090565b6117818383612441565b61178b8383612808565b9392505050565b610daa82825b6117a28282612441565b600082826040516117b4929190613f57565b604080519182900390912060008181526005602052919091209091506001815460ff1660048111156117e8576117e8613551565b1461181f576040517f4145817200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b3360009081527f4527d8b28c468984933d33ae052f26b21c15ca0e7fdec762bba08e540e237001602052604090205460ba8501359060ff1661186b576004546118689082613f96565b90505b8042116118a4576040517fe15ff9ea00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b81547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166004178255600a850135606090811c906032870135901c60006118f3609a890135605a8a0135613f96565b604080516001600160a01b03858116825260208201849052825193945086169289927fb4c55c0c9bc613519b920e88748090150b890a875d307f21bea7d4fb2e8bc958928290030190a37fffffffffffffffffffffffff11111111111111111111111111111111111111126001600160a01b0383160161197c5761197783826121e2565b611990565b6119906001600160a01b03831684836122b0565b5050505050505050565b80516000906001600160a01b0316156119bf5760208201516119bc9042613fa9565b90505b6119ca8383836129aa565b60006119de84606001518560a00151612c2e565b90506000806002541115611a1757620f4240600254836119fe9190613fd1565b611a089190613fe8565b9050611a148183614023565b91505b6000611b20604051806101e001604052804663ffffffff168152602001886000015163ffffffff16815260200188602001516001600160a01b0316815260200188604001516001600160a01b0316815260200188606001516001600160a01b0316815260200188608001516001600160a01b031681526020018581526020018860c0015181526020018481526020018861010001518152602001600760008a602001516001600160a01b03166001600160a01b031681526020019081526020016000206000815480929190611aeb90614036565b90915550815287516001600160a01b031660208201526040810187905260608089015190820152608080890151910152612e41565b805160208083019190912060008181526005835260409081902080548b5163ffffffff8116610100027fffffffffffffffffffffffffffffffffffffffffffffffffffffff000000000090921691909117600117909155928a01516060808c015160808d015160c08e0151928d0151945197985094966001600160a01b039093169587957f120ea0364f36cdac7983bcfdd55270ca09d7f9b314a2ebc425a3b01ab1d6403a95611bdc958b959394938e9290919015159061406e565b60405180910390a3807f3120e2bb59c86aca6890191a589a96af3662838efa374fbdcdf4c95bfe4a6c0e8760400151604051611c1891906140c4565b60405180910390a250505050505050565b611c338383612441565b610d728383604051611c46929190613f57565b60405180910390208233611553565b610daa828233610fad565b600082815260016020526040812061178b9083612f86565b60008281526005602052604081206002815460ff166004811115611c9e57611c9e613551565b14611cd5576040517f4145817200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80546001600160a01b038481166c010000000000000000000000009092041614611d2b576040517f4af43a9000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b546107086501000000000090910466ffffffffffffff908116420316119392505050565b6040805161018081018252600080825260208201819052818301819052606082018190526080820181905260a0820181905260c0820181905260e0820181905261010082018190526101208201819052610140820181905261016082015290517f5aa6ccba0000000000000000000000000000000000000000000000000000000081523090635aa6ccba90611dea9086908690600401614102565b600060405180830381865afa925050508015611e2857506040513d6000823e601f3d908101601f19168201604052611e259190810190614171565b60015b611e3f57611e38828401846142a6565b9050610c64565b604051806101800160405280826000015163ffffffff168152602001826020015163ffffffff16815260200182604001516001600160a01b0316815260200182606001516001600160a01b0316815260200182608001516001600160a01b031681526020018260a001516001600160a01b031681526020018260c0015181526020018260e0015181526020018261010001518152602001826101a0015160001415151581526020018261012001518152602001826101400151815250915050610c64565b7f043c983c49d46f0e102151eaf8085d4a2e6571d5df2d47b013f39bddfd4a639d611f2d816121d8565b600082815260056020526040902080546c0100000000000000000000000081046001600160a01b03169060ff81169065010000000000900466ffffffffffffff166002826004811115611f8257611f82613551565b14611fb9576040517f4145817200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6107084282900366ffffffffffffff161115612001576040517f3e908aac00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b835464ffffffff001660011784556040516001600160a01b0384169087907f0695cf1d39b3055dcd0fe02d8b47eaf0d5a13e1996de925de59d0ef9b7f7fad490600090a3505050505050565b7f7935bd0ae54bc31f548c14dba4d37c5c64b3f8ca900cb468fb8abd54d5894f55612077816121d8565b6127108211156120b3576040517f9b569b8100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600280549083905560408051828152602081018590527f14914da2bf76024616fbe1859783fcd4dbddcb179b1f3a854949fbf920dcb957910160405180910390a1505050565b6000818152600160205260408120610c6490612f92565b60008281526020819052604090206001015461212b816121d8565b610d7083836123d2565b610daa828260006112e1565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f7965db0b000000000000000000000000000000000000000000000000000000001480610c6457507f01ffc9a7000000000000000000000000000000000000000000000000000000007fffffffff00000000000000000000000000000000000000000000000000000000831614610c64565b6116c28133612f9c565b80471015612223576040517fcd7860590000000000000000000000000000000000000000000000000000000081523060048201526024015b60405180910390fd5b6000826001600160a01b03168260405160006040518083038185875af1925050503d8060008114612270576040519150601f19603f3d011682016040523d82523d6000602084013e612275565b606091505b5050905080610d72576040517f1425ea4200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040516001600160a01b03838116602483015260448201839052610d7291859182169063a9059cbb906064015b604051602081830303815290604052915060e01b6020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8381831617835250505050613008565b610e10811015612360576040517f0e0ea5c700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600480549082905560408051828152602081018490527f909f9078b2f6eac1d10f2aae793656c5a67511eb627ebd1d2cb1eb9c0ab94c95910160405180910390a15050565b6000806123b28484613084565b9050801561178b576000848152600160205260409020610fa5908461314c565b6000806123df8484613161565b9050801561178b576000848152600160205260409020610fa59084613202565b80511561240f5780518082602001fd5b6040517f5ead5a9d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61014e81101561247d576040517f6ee0e17100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b813560f01c60028114610d72576040517f8bd977e700000000000000000000000000000000000000000000000000000000815261ffff8216600482015260240161221a565b6001600160a01b038116612502576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000828152600660205260409020546c0100000000000000000000000090046001600160a01b031615612561576040517fbef7bb7d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600684013560e01c46146125a1576040517f7029fdf900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60ba8401354211156125df576040517f559895a300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60fa84013560601c80158015906126085750816001600160a01b0316816001600160a01b031614155b8015612619575061010e8501354211155b15612650576040517f14be123200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5050505050565b6040516001600160a01b038481166024830152838116604483015260648201839052610d709186918216906323b872dd906084016122dd565b3660006126a18361014e8187614372565b915091509250929050565b600061272786868686866040516024016126c9949392919061439c565b60408051601f198184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fe85e13dd0000000000000000000000000000000000000000000000000000000017905234613217565b90508051600003612764576040517f1a95ad2600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b805160201461279f576040517ff3725cca00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7fe85e13dd000000000000000000000000000000000000000000000000000000006127c9826143c5565b14612800576040517ff3725cca00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b505050505050565b6128ba604051806101e00160405280600063ffffffff168152602001600063ffffffff16815260200160006001600160a01b0316815260200160006001600160a01b0316815260200160006001600160a01b0316815260200160006001600160a01b03168152602001600081526020016000815260200160008152602001600081526020016000815260200160006001600160a01b031681526020016000815260200160008152602001606081525090565b600283013560e090811c82526006840135811c6020830152600a840135606090811c6040840152601e850135811c818401526032850135811c60808401526046850135811c60a0840152605a85013560c0840152607a85013591830191909152609a84013561010083015260ba84013561012083015260da84013561014083015260fa840135901c61016082015261010e83013561018082015261012e8301356101a082015261296a8383612690565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152505050506101c082015292915050565b46836000015163ffffffff16036129ed576040517f7029fdf900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60a08301511580612a00575060c0830151155b15612a37576040517fe38820c800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60208301516001600160a01b03161580612a5c575060408301516001600160a01b0316155b15612a93576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60608301516001600160a01b03161580612ab8575060808301516001600160a01b0316155b15612aef576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b612afb61070842613f96565b8361010001511015612b39576040517f04b7fcc800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61ffff8260800151511115612b7a576040517f177a70e100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b606082015115801590612bad575060808301516001600160a01b031673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee145b15612be4576040517f846dedc000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000811280612bf7575082610100015181135b15610d72576040517f352807b900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60007fffffffffffffffffffffffff11111111111111111111111111111111111111126001600160a01b03841601612ca057348214612c99576040517f81de0bf300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5034610c64565b3415612cd8576040517f81de0bf300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b826001600160a01b03163b600003612d1c576040517f7f523fe800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201526001600160a01b038416906370a0823190602401602060405180830381865afa158015612d79573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612d9d919061440a565b9050612db46001600160a01b038416333085612657565b6040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015281906001600160a01b038516906370a0823190602401602060405180830381865afa158015612e13573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612e37919061440a565b61178b9190614023565b8051602080830151604080850151606086810151608088015160a089015160c08a015195517e02000000000000000000000000000000000000000000000000000000000000988101989098527fffffffff0000000000000000000000000000000000000000000000000000000060e0998a1b811660228a01529690981b90951660268701527fffffffffffffffffffffffffffffffffffffffff00000000000000000000000092821b8316602a870152811b8216603e86015292831b8116605285015293821b9093166066830152607a820192909252600090609a0160408051601f198184030181529082905260e08501516101008601516101208701516101408801516101608901516101808a01516101a08b01516101c08c0151979950612f6f988a9890602001614423565b604051602081830303815290604052915050919050565b600061178b83836132cd565b6000610c64825490565b6000828152602081815260408083206001600160a01b038516845290915290205460ff16610daa576040517fe2517d3f0000000000000000000000000000000000000000000000000000000081526001600160a01b03821660048201526024810183905260440161221a565b600061301d6001600160a01b038416836132f7565b9050805160001415801561304257508080602001905181019061304091906144ac565b155b15610d72576040517f5274afe70000000000000000000000000000000000000000000000000000000081526001600160a01b038416600482015260240161221a565b6000828152602081815260408083206001600160a01b038516845290915281205460ff16613144576000838152602081815260408083206001600160a01b0386168452909152902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790556130fc3390565b6001600160a01b0316826001600160a01b0316847f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a4506001610c64565b506000610c64565b600061178b836001600160a01b038416613305565b6000828152602081815260408083206001600160a01b038516845290915281205460ff1615613144576000838152602081815260408083206001600160a01b038616808552925280832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016905551339286917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a4506001610c64565b600061178b836001600160a01b03841661334c565b606081471015613255576040517fcd78605900000000000000000000000000000000000000000000000000000000815230600482015260240161221a565b600080856001600160a01b0316848660405161327191906144c9565b60006040518083038185875af1925050503d80600081146132ae576040519150601f19603f3d011682016040523d82523d6000602084013e6132b3565b606091505b50915091506132c386838361343f565b9695505050505050565b60008260000182815481106132e4576132e4613ec3565b9060005260206000200154905092915050565b606061178b83836000613217565b600081815260018301602052604081205461314457508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155610c64565b60008181526001830160205260408120548015613435576000613370600183614023565b855490915060009061338490600190614023565b90508082146133e95760008660000182815481106133a4576133a4613ec3565b90600052602060002001549050808760000184815481106133c7576133c7613ec3565b6000918252602080832090910192909255918252600188019052604090208390555b85548690806133fa576133fa6144e5565b600190038181906000526020600020016000905590558560010160008681526020019081526020016000206000905560019350505050610c64565b6000915050610c64565b6060826134545761344f826134b4565b61178b565b815115801561346b57506001600160a01b0384163b155b156134ad576040517f9996b3150000000000000000000000000000000000000000000000000000000081526001600160a01b038516600482015260240161221a565b508061178b565b8051156134c45780518082602001fd5b6040517f1425ea4200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006020828403121561350857600080fd5b81357fffffffff000000000000000000000000000000000000000000000000000000008116811461178b57600080fd5b60006020828403121561354a57600080fd5b5035919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b600581106135b7577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b9052565b60208101610c648284613580565b6001600160a01b03811681146116c257600080fd5b80356135e9816135c9565b919050565b6000806040838503121561360157600080fd5b823561360c816135c9565b9150602083013561361c816135c9565b809150509250929050565b60006020828403121561363957600080fd5b813561178b816135c9565b6000806040838503121561365757600080fd5b82359150602083013561361c816135c9565b80151581146116c257600080fd5b80356135e981613669565b60008060006040848603121561369757600080fd5b833567ffffffffffffffff808211156136af57600080fd5b818601915086601f8301126136c357600080fd5b8135818111156136d257600080fd5b8760208260051b85010111156136e757600080fd5b602092830195509350508401356136fd81613669565b809150509250925092565b60005b8381101561372357818101518382015260200161370b565b50506000910152565b60008151808452613744816020860160208601613708565b601f01601f19169290920160200192915050565b600060208083018184528085518083526040925060408601915060408160051b87010184880160005b838110156137e0578883037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc001855281518051151584528701518784018790526137cd8785018261372c565b9588019593505090860190600101613781565b509098975050505050505050565b60008083601f84011261380057600080fd5b50813567ffffffffffffffff81111561381857600080fd5b60208301915083602082850101111561383057600080fd5b9250929050565b60008060006040848603121561384c57600080fd5b833567ffffffffffffffff81111561386357600080fd5b61386f868287016137ee565b90945092505060208401356136fd816135c9565b60008060006060848603121561389857600080fd5b833592506020840135915060408401356136fd816135c9565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051610120810167ffffffffffffffff81118282101715613904576139046138b1565b60405290565b60405160a0810167ffffffffffffffff81118282101715613904576139046138b1565b6040516101e0810167ffffffffffffffff81118282101715613904576139046138b1565b604051610180810167ffffffffffffffff81118282101715613904576139046138b1565b604051601f8201601f1916810167ffffffffffffffff8111828210171561399e5761399e6138b1565b604052919050565b63ffffffff811681146116c257600080fd5b80356135e9816139a6565b600061012082840312156139d657600080fd5b6139de6138e0565b90506139e9826139b8565b81526139f7602083016135de565b6020820152613a08604083016135de565b6040820152613a19606083016135de565b6060820152613a2a608083016135de565b608082015260a082013560a082015260c082013560c0820152613a4f60e08301613677565b60e082015261010080830135818301525092915050565b60006101208284031215613a7957600080fd5b61178b83836139c3565b60008060208385031215613a9657600080fd5b823567ffffffffffffffff811115613aad57600080fd5b613ab9858286016137ee565b90969095509350505050565b60208152613adc60208201835163ffffffff169052565b60006020830151613af5604084018263ffffffff169052565b5060408301516001600160a01b03811660608401525060608301516001600160a01b03811660808401525060808301516001600160a01b03811660a08401525060a08301516001600160a01b03811660c08401525060c083015160e08381019190915283015161010080840191909152830151610120808401919091528301516101408084019190915283015161016080840191909152830151610180613ba6818501836001600160a01b03169052565b8401516101a0848101919091528401516101c0808501919091528401516101e0808501529050613bda61020084018261372c565b949350505050565b60808101613bf08287613580565b63ffffffff8516602083015266ffffffffffffff841660408301526001600160a01b038316606083015295945050505050565b600067ffffffffffffffff821115613c3d57613c3d6138b1565b50601f01601f191660200190565b600082601f830112613c5c57600080fd5b8135613c6f613c6a82613c23565b613975565b818152846020838601011115613c8457600080fd5b816020850160208301376000918101602001919091529392505050565b6000806101408385031215613cb557600080fd5b613cbf84846139c3565b915061012083013567ffffffffffffffff80821115613cdd57600080fd5b9084019060a08287031215613cf157600080fd5b613cf961390a565b8235613d04816135c9565b815260208381013590820152604083013582811115613d2257600080fd5b613d2e88828601613c4b565b60408301525060608301356060820152608083013582811115613d5057600080fd5b613d5c88828601613c4b565b6080830152508093505050509250929050565b600080600060408486031215613d8457600080fd5b833567ffffffffffffffff811115613d9b57600080fd5b613da7868287016137ee565b909790965060209590950135949350505050565b60008060408385031215613dce57600080fd5b50508035926020909101359150565b815163ffffffff16815261018081016020830151613e03602084018263ffffffff169052565b506040830151613e1e60408401826001600160a01b03169052565b506060830151613e3960608401826001600160a01b03169052565b506080830151613e5460808401826001600160a01b03169052565b5060a0830151613e6f60a08401826001600160a01b03169052565b5060c083015160c083015260e083015160e083015261010080840151818401525061012080840151613ea48285018215159052565b5050610140838101519083015261016092830151929091019190915290565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112613f2757600080fd5b83018035915067ffffffffffffffff821115613f4257600080fd5b60200191503681900382131561383057600080fd5b8183823760009101908152919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b80820180821115610c6457610c64613f67565b8082018281126000831280158216821582161715613fc957613fc9613f67565b505092915050565b8082028115828204841417610c6457610c64613f67565b60008261401e577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b81810381811115610c6457610c64613f67565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820361406757614067613f67565b5060010190565b60e08152600061408160e083018a61372c565b63ffffffff989098166020830152506001600160a01b039586166040820152939094166060840152608083019190915260a082015290151560c090910152919050565b60208152600061178b602083018461372c565b818352818160208501375060006020828401015260006020601f19601f840116840101905092915050565b602081526000613bda6020830184866140d7565b80516135e9816139a6565b80516135e9816135c9565b600082601f83011261413d57600080fd5b815161414b613c6a82613c23565b81815284602083860101111561416057600080fd5b613bda826020830160208701613708565b60006020828403121561418357600080fd5b815167ffffffffffffffff8082111561419b57600080fd5b908301906101e082860312156141b057600080fd5b6141b861392d565b6141c183614116565b81526141cf60208401614116565b60208201526141e060408401614121565b60408201526141f160608401614121565b606082015261420260808401614121565b608082015261421360a08401614121565b60a082015260c0838101519082015260e0808401519082015261010080840151908201526101208084015190820152610140808401519082015261016061425b818501614121565b9082015261018083810151908201526101a080840151908201526101c0808401518381111561428957600080fd5b6142958882870161412c565b918301919091525095945050505050565b600061018082840312156142b957600080fd5b6142c1613951565b6142ca836139b8565b81526142d8602084016139b8565b60208201526142e9604084016135de565b60408201526142fa606084016135de565b606082015261430b608084016135de565b608082015261431c60a084016135de565b60a082015260c083013560c082015260e083013560e082015261010080840135818301525061012061434f818501613677565b908201526101408381013590820152610160928301359281019290925250919050565b6000808585111561438257600080fd5b8386111561438f57600080fd5b5050820193919092039150565b6001600160a01b03851681528360208201526060604082015260006132c36060830184866140d7565b80516020808301519190811015614404577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8160200360031b1b821691505b50919050565b60006020828403121561441c57600080fd5b5051919050565b60008a51614435818460208f01613708565b80830190508a81528960208201528860408201528760608201527fffffffffffffffffffffffffffffffffffffffff0000000000000000000000008760601b1660808201528560948201528460b482015283516144998160d4840160208801613708565b0160d4019b9a5050505050505050505050565b6000602082840312156144be57600080fd5b815161178b81613669565b600082516144db818460208701613708565b9190910192915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fdfea264697066735822122082edd55575a2d7fd882d29c1a5d3a24f84d274aca2cf25f32089fce5162775cc64736f6c63430008180033","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.24 ^0.8.20 ^0.8.4;\n\n// contracts/interfaces/IAdminV2.sol\n\ninterface IAdminV2 {\n event CancelDelayUpdated(uint256 oldCancelDelay, uint256 newCancelDelay);\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n /// @notice Allows the governor to set the cancel delay. The cancel delay is the time period after the transaction\n /// deadline during which a transaction can be permissionlessly cancelled if it hasn't been proven by any Relayer.\n function setCancelDelay(uint256 newCancelDelay) external;\n\n /// @notice Allows the governor to set the protocol fee rate. The protocol fee is taken from the origin\n /// amount and is only applied to completed and claimed transactions.\n /// @dev The protocol fee is abstracted away from the relayers; they always operate using the amounts after fees.\n /// The origin amount they see in the emitted log is what they get credited with.\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n /// @notice Allows the governor to withdraw the accumulated protocol fees from the contract.\n function sweepProtocolFees(address token, address recipient) external;\n}\n\n// contracts/interfaces/IAdminV2Errors.sol\n\ninterface IAdminV2Errors {\n error CancelDelayBelowMin();\n error FeeRateAboveMax();\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IFastBridgeV2Errors.sol\n\ninterface IFastBridgeV2Errors {\n error AmountIncorrect();\n error ChainIncorrect();\n error ExclusivityParamsIncorrect();\n error MsgValueIncorrect();\n error SenderIncorrect();\n error StatusIncorrect();\n error TokenNotContract();\n error ZapDataLengthAboveMax();\n error ZapNativeNotSupported();\n error ZeroAddress();\n\n error RecipientIncorrectReturnValue();\n error RecipientNoReturnValue();\n\n error DeadlineExceeded();\n error DeadlineNotExceeded();\n error DeadlineTooShort();\n error DisputePeriodNotPassed();\n error DisputePeriodPassed();\n error ExclusivityPeriodNotPassed();\n\n error TransactionRelayed();\n}\n\n// contracts/interfaces/IMulticallTarget.sol\n\n/// @notice Interface for a contract that supports multiple calls from the same caller. Inspired by MulticallV3:\n/// https://github.com/mds1/multicall/blob/master/src/Multicall3.sol\ninterface IMulticallTarget {\n struct Result {\n bool success;\n bytes returnData;\n }\n\n /// @notice Executes multiple calls to this contract in a single transaction while preserving msg.sender.\n /// Return data from the calls is discarded.\n /// @dev This method is non-payable, so only calls with msg.value of 0 can be batched.\n /// If ignoreReverts is set to true, reverted calls will be skipped.\n /// Otherwise, the entire batch will revert with the original revert reason.\n /// @param data List of ABI-encoded calldata for the calls to execute\n /// @param ignoreReverts Whether to skip calls that revert\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external;\n\n /// @notice Executes multiple calls to this contract in a single transaction while preserving msg.sender.\n /// Return data from each call is preserved.\n /// @dev This method is non-payable, so only calls with msg.value of 0 can be batched.\n /// If ignoreReverts is set to true, reverted calls will be skipped.\n /// Otherwise, the entire batch will revert with the original revert reason.\n /// @param data List of ABI-encoded calldata for the calls to execute\n /// @param ignoreReverts Whether to skip calls that revert\n /// @return results List of results from the calls, each containing (success, returnData)\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results);\n}\n\n// contracts/interfaces/IZapRecipient.sol\n\n/// @notice Interface for contracts that can perform Zap operations. Such contracts could be used as Recipients\n/// in a FastBridge transaction that includes a Zap operation. The Zap Data should include instructions on how\n/// exactly the Zap operation should be executed, which would typically include the target address and calldata\n/// to use. The exact implementation of the Zap Data encoding is up to the Recipient contract.\ninterface IZapRecipient {\n /// @notice Performs a Zap operation with the given token and amount according to the provided Zap data.\n /// @param token The address of the token being used for the Zap operation.\n /// @param amount The amount of tokens to be used.\n /// @param zapData The encoded data specifying how the Zap operation should be executed.\n /// @return The function selector to indicate successful execution.\n function zap(address token, uint256 amount, bytes memory zapData) external payable returns (bytes4);\n}\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// contracts/interfaces/IFastBridgeV2.sol\n\ninterface IFastBridgeV2 is IFastBridge {\n enum BridgeStatus {\n NULL, // Doesn't exist yet.\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n struct BridgeTxDetails {\n BridgeStatus status;\n uint32 destChainId;\n uint56 proofBlockTimestamp;\n address proofRelayer;\n }\n\n struct BridgeRelay {\n uint48 blockNumber;\n uint48 blockTimestamp;\n address relayer;\n }\n\n /// @notice New params introduced in the FastBridgeV2.\n /// We are passing fields from the older BridgeParams struct outside of this struct for backwards compatibility.\n /// Note: quoteRelayer and quoteExclusivitySeconds are either both zero (indicating no exclusivity)\n /// or both non-zero (indicating exclusivity for the given period).\n /// Note: zapNative \u003e 0 can NOT be used with destToken = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE (native token)\n /// @param quoteRelayer Relayer that provided the quote for the transaction\n /// @param quoteExclusivitySeconds Period of time the quote relayer is guaranteed exclusivity after user's deposit\n /// @param quoteId Unique quote identifier used for tracking the quote\n /// @param zapNative ETH value to send to the recipient (if any)\n /// @param zapData Parameters for the Zap to the destination recipient (if any)\n struct BridgeParamsV2 {\n address quoteRelayer;\n int256 quoteExclusivitySeconds;\n bytes quoteId;\n uint256 zapNative;\n bytes zapData;\n }\n\n /// @notice Updated bridge transaction struct to include parameters introduced in FastBridgeV2.\n /// Note: only `exclusivityRelayer` can fill such a transaction until `exclusivityEndTime`.\n struct BridgeTransactionV2 {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n // Note: sendChainGas flag from V1 is deprecated\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n address exclusivityRelayer;\n uint256 exclusivityEndTime;\n uint256 zapNative; // ETH value to send to the recipient (if any)\n bytes zapData; // data to pass for the Zap action (if any)\n }\n\n event BridgeQuoteDetails(bytes32 indexed transactionId, bytes quoteId);\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability\n /// to provide temporary exclusivity fill rights for the quote relayer.\n /// @param params The parameters required to bridge\n /// @param paramsV2 The parameters for exclusivity fill rights (optional, can be left empty)\n function bridgeV2(BridgeParams memory params, BridgeParamsV2 memory paramsV2) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function relayV2(bytes memory request, address relayer) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param transactionId The transaction id associated with the encoded bridge transaction to prove\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function proveV2(bytes32 transactionId, bytes32 destTxHash, address relayer) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital.\n /// @notice Can only send funds to the relayer address on the proof.\n /// @param request The encoded bridge transaction to claim on origin chain\n function claimV2(bytes memory request) external;\n\n /// @notice Cancels an outstanding bridge transaction in case optimistic bridging failed and returns the full amount\n /// to the original sender.\n /// @param request The encoded bridge transaction to refund\n function cancelV2(bytes memory request) external;\n\n /// @notice Checks if a transaction has been relayed\n /// @param transactionId The ID of the transaction to check\n /// @return True if the transaction has been relayed, false otherwise\n function bridgeRelays(bytes32 transactionId) external view returns (bool);\n\n /// @notice Returns the status of a bridge transaction\n /// @param transactionId The ID of the bridge transaction\n /// @return BridgeStatus Status of the bridge transaction\n function bridgeStatuses(bytes32 transactionId) external view returns (BridgeStatus);\n\n /// @notice Returns the timestamp and relayer of a bridge proof\n /// @param transactionId The ID of the bridge transaction\n /// @return timestamp The timestamp of the bridge proof\n /// @return relayer The relayer address of the bridge proof\n function bridgeProofs(bytes32 transactionId) external view returns (uint96 timestamp, address relayer);\n\n /// @notice Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\n /// @param request The bridge request to decode\n function getBridgeTransactionV2(bytes memory request) external view returns (BridgeTransactionV2 memory);\n}\n\n// contracts/utils/MulticallTarget.sol\n\n// solhint-disable avoid-low-level-calls\n/// @notice Abstract contract template that supports batched calls while preserving msg.sender.\n/// Only calls with msg.value of 0 can be batched.\nabstract contract MulticallTarget is IMulticallTarget {\n error MulticallTarget__UndeterminedRevert();\n\n /// @inheritdoc IMulticallTarget\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external {\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\n if (!success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(result);\n }\n }\n }\n\n /// @inheritdoc IMulticallTarget\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results)\n {\n results = new Result[](data.length);\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (results[i].success, results[i].returnData) = address(this).delegatecall(data[i]);\n if (!results[i].success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(results[i].returnData);\n }\n }\n }\n\n /// @dev Bubbles the revert message from the underlying call.\n /// Note: preserves the same custom error or revert string, if one was used.\n /// Source: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v5.0.2/contracts/utils/Address.sol#L143-L158\n function _bubbleRevert(bytes memory returnData) internal pure {\n // Look for revert reason and bubble it up if present\n if (returnData.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n // solhint-disable-next-line no-inline-assembly\n assembly {\n let returndata_size := mload(returnData)\n revert(add(32, returnData), returndata_size)\n }\n } else {\n revert MulticallTarget__UndeterminedRevert();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// contracts/libs/BridgeTransactionV2.sol\n\n// solhint-disable no-inline-assembly\nlibrary BridgeTransactionV2Lib {\n uint16 internal constant VERSION = 2;\n\n // Offsets of the fields in the packed BridgeTransactionV2 struct\n // uint16 version [000 .. 002)\n // uint32 originChainId [002 .. 006)\n // uint32 destChainId [006 .. 010)\n // address originSender [010 .. 030)\n // address destRecipient [030 .. 050)\n // address originToken [050 .. 070)\n // address destToken [070 .. 090)\n // uint256 originAmount [090 .. 122)\n // uint256 destAmount [122 .. 154)\n // uint256 originFeeAmount [154 .. 186)\n // uint256 deadline [186 .. 218)\n // uint256 nonce [218 .. 250)\n // address exclusivityRelayer [250 .. 270)\n // uint256 exclusivityEndTime [270 .. 302)\n // uint256 zapNative [302 .. 334)\n // bytes zapData [334 .. ***)\n\n // forgefmt: disable-start\n uint256 private constant OFFSET_ORIGIN_CHAIN_ID = 2;\n uint256 private constant OFFSET_DEST_CHAIN_ID = 6;\n uint256 private constant OFFSET_ORIGIN_SENDER = 10;\n uint256 private constant OFFSET_DEST_RECIPIENT = 30;\n uint256 private constant OFFSET_ORIGIN_TOKEN = 50;\n uint256 private constant OFFSET_DEST_TOKEN = 70;\n uint256 private constant OFFSET_ORIGIN_AMOUNT = 90;\n uint256 private constant OFFSET_DEST_AMOUNT = 122;\n uint256 private constant OFFSET_ORIGIN_FEE_AMOUNT = 154;\n uint256 private constant OFFSET_DEADLINE = 186;\n uint256 private constant OFFSET_NONCE = 218;\n uint256 private constant OFFSET_EXCLUSIVITY_RELAYER = 250;\n uint256 private constant OFFSET_EXCLUSIVITY_END_TIME = 270;\n uint256 private constant OFFSET_ZAP_NATIVE = 302;\n uint256 private constant OFFSET_ZAP_DATA = 334;\n // forgefmt: disable-end\n\n error BridgeTransactionV2__InvalidEncodedTx();\n error BridgeTransactionV2__UnsupportedVersion(uint16 version);\n\n /// @notice Validates that the encoded transaction is a tightly packed encoded payload for BridgeTransactionV2.\n /// @dev Checks the minimum length and the version, use this function before decoding any of the fields.\n function validateV2(bytes calldata encodedTx) internal pure {\n // Check the minimum length: must at least include all static fields.\n if (encodedTx.length \u003c OFFSET_ZAP_DATA) revert BridgeTransactionV2__InvalidEncodedTx();\n // Once we validated the length, we can be sure that the version field is present.\n uint16 version_ = version(encodedTx);\n if (version_ != VERSION) revert BridgeTransactionV2__UnsupportedVersion(version_);\n }\n\n /// @notice Encodes the BridgeTransactionV2 struct by tightly packing the fields.\n /// @dev `abi.decode` will not work as a result of the tightly packed fields. Use `decodeV2` to decode instead.\n function encodeV2(IFastBridgeV2.BridgeTransactionV2 memory bridgeTx) internal pure returns (bytes memory) {\n // We split the encoding into two parts to avoid stack-too-deep error\n bytes memory firstPart = abi.encodePacked(\n VERSION,\n bridgeTx.originChainId,\n bridgeTx.destChainId,\n bridgeTx.originSender,\n bridgeTx.destRecipient,\n bridgeTx.originToken,\n bridgeTx.destToken,\n bridgeTx.originAmount\n );\n return abi.encodePacked(\n firstPart,\n bridgeTx.destAmount,\n bridgeTx.originFeeAmount,\n // Note: we skip the deprecated `sendChainGas` flag, which was present in BridgeTransaction V1\n bridgeTx.deadline,\n bridgeTx.nonce,\n // New V2 fields: exclusivity\n bridgeTx.exclusivityRelayer,\n bridgeTx.exclusivityEndTime,\n // New V2 fields: Zap\n bridgeTx.zapNative,\n bridgeTx.zapData\n );\n }\n\n /// @notice Decodes the BridgeTransactionV2 struct from the encoded transaction.\n /// @dev Encoded BridgeTransactionV2 struct must be tightly packed.\n /// Use `validateV2` before decoding to ensure the encoded transaction is valid.\n function decodeV2(bytes calldata encodedTx)\n internal\n pure\n returns (IFastBridgeV2.BridgeTransactionV2 memory bridgeTx)\n {\n bridgeTx.originChainId = originChainId(encodedTx);\n bridgeTx.destChainId = destChainId(encodedTx);\n bridgeTx.originSender = originSender(encodedTx);\n bridgeTx.destRecipient = destRecipient(encodedTx);\n bridgeTx.originToken = originToken(encodedTx);\n bridgeTx.destToken = destToken(encodedTx);\n bridgeTx.originAmount = originAmount(encodedTx);\n bridgeTx.destAmount = destAmount(encodedTx);\n bridgeTx.originFeeAmount = originFeeAmount(encodedTx);\n bridgeTx.deadline = deadline(encodedTx);\n bridgeTx.nonce = nonce(encodedTx);\n bridgeTx.exclusivityRelayer = exclusivityRelayer(encodedTx);\n bridgeTx.exclusivityEndTime = exclusivityEndTime(encodedTx);\n bridgeTx.zapNative = zapNative(encodedTx);\n bridgeTx.zapData = zapData(encodedTx);\n }\n\n /// @notice Extracts the version from the encoded transaction.\n function version(bytes calldata encodedTx) internal pure returns (uint16 version_) {\n // Load 32 bytes from the start and shift it 240 bits to the right to get the highest 16 bits.\n assembly {\n version_ := shr(240, calldataload(encodedTx.offset))\n }\n }\n\n /// @notice Extracts the origin chain ID from the encoded transaction.\n function originChainId(bytes calldata encodedTx) internal pure returns (uint32 originChainId_) {\n // Load 32 bytes from the offset and shift it 224 bits to the right to get the highest 32 bits.\n assembly {\n originChainId_ := shr(224, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_CHAIN_ID)))\n }\n }\n\n /// @notice Extracts the destination chain ID from the encoded transaction.\n function destChainId(bytes calldata encodedTx) internal pure returns (uint32 destChainId_) {\n // Load 32 bytes from the offset and shift it 224 bits to the right to get the highest 32 bits.\n assembly {\n destChainId_ := shr(224, calldataload(add(encodedTx.offset, OFFSET_DEST_CHAIN_ID)))\n }\n }\n\n /// @notice Extracts the origin sender from the encoded transaction.\n function originSender(bytes calldata encodedTx) internal pure returns (address originSender_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n originSender_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_SENDER)))\n }\n }\n\n /// @notice Extracts the destination recipient from the encoded transaction.\n function destRecipient(bytes calldata encodedTx) internal pure returns (address destRecipient_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n destRecipient_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_DEST_RECIPIENT)))\n }\n }\n\n /// @notice Extracts the origin token from the encoded transaction.\n function originToken(bytes calldata encodedTx) internal pure returns (address originToken_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n originToken_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_TOKEN)))\n }\n }\n\n /// @notice Extracts the destination token from the encoded transaction.\n function destToken(bytes calldata encodedTx) internal pure returns (address destToken_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n destToken_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_DEST_TOKEN)))\n }\n }\n\n /// @notice Extracts the origin amount from the encoded transaction.\n function originAmount(bytes calldata encodedTx) internal pure returns (uint256 originAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n originAmount_ := calldataload(add(encodedTx.offset, OFFSET_ORIGIN_AMOUNT))\n }\n }\n\n /// @notice Extracts the destination amount from the encoded transaction.\n function destAmount(bytes calldata encodedTx) internal pure returns (uint256 destAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n destAmount_ := calldataload(add(encodedTx.offset, OFFSET_DEST_AMOUNT))\n }\n }\n\n /// @notice Extracts the origin fee amount from the encoded transaction.\n function originFeeAmount(bytes calldata encodedTx) internal pure returns (uint256 originFeeAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n originFeeAmount_ := calldataload(add(encodedTx.offset, OFFSET_ORIGIN_FEE_AMOUNT))\n }\n }\n\n /// @notice Extracts the deadline from the encoded transaction.\n function deadline(bytes calldata encodedTx) internal pure returns (uint256 deadline_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n deadline_ := calldataload(add(encodedTx.offset, OFFSET_DEADLINE))\n }\n }\n\n /// @notice Extracts the nonce from the encoded transaction.\n function nonce(bytes calldata encodedTx) internal pure returns (uint256 nonce_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n nonce_ := calldataload(add(encodedTx.offset, OFFSET_NONCE))\n }\n }\n\n /// @notice Extracts the exclusivity relayer from the encoded transaction.\n function exclusivityRelayer(bytes calldata encodedTx) internal pure returns (address exclusivityRelayer_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n exclusivityRelayer_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_EXCLUSIVITY_RELAYER)))\n }\n }\n\n /// @notice Extracts the exclusivity end time from the encoded transaction.\n function exclusivityEndTime(bytes calldata encodedTx) internal pure returns (uint256 exclusivityEndTime_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n exclusivityEndTime_ := calldataload(add(encodedTx.offset, OFFSET_EXCLUSIVITY_END_TIME))\n }\n }\n\n /// @notice Extracts the Zap's native value from the encoded transaction.\n function zapNative(bytes calldata encodedTx) internal pure returns (uint256 zapNative_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n zapNative_ := calldataload(add(encodedTx.offset, OFFSET_ZAP_NATIVE))\n }\n }\n\n /// @notice Extracts the Zap's data from the encoded transaction.\n function zapData(bytes calldata encodedTx) internal pure returns (bytes calldata zapData_) {\n zapData_ = encodedTx[OFFSET_ZAP_DATA:];\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/AdminV2.sol\n\n// ════════════════════════════════════════════════ INTERFACES ═════════════════════════════════════════════════════\n\n// ═════════════════════════════════════════════ EXTERNAL IMPORTS ══════════════════════════════════════════════════\n\n/// @title AdminV2\n/// @notice Provides administrative functions and controls for managing the FastBridgeV2 contract,\n/// including access control and configuration settings.\ncontract AdminV2 is AccessControlEnumerable, IAdminV2, IAdminV2Errors {\n using SafeERC20 for IERC20;\n\n /// @notice The address reserved for the native gas token (ETH on Ethereum and most L2s, AVAX on Avalanche, etc.).\n address public constant NATIVE_GAS_TOKEN = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice The role identifier for the Quoter API's off-chain authentication.\n /// @dev Only addresses with this role can post FastBridge quotes to the API.\n bytes32 public constant QUOTER_ROLE = keccak256(\"QUOTER_ROLE\");\n\n /// @notice The role identifier for the Prover's on-chain authentication in FastBridge.\n /// @dev Only addresses with this role can provide proofs that a FastBridge request has been relayed.\n bytes32 public constant PROVER_ROLE = keccak256(\"PROVER_ROLE\");\n\n /// @notice The role identifier for the Guard's on-chain authentication in FastBridge.\n /// @dev Only addresses with this role can dispute submitted relay proofs during the dispute period.\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n\n /// @notice The role identifier for the Canceler's on-chain authentication in FastBridge.\n /// @dev Only addresses with this role can cancel a FastBridge transaction without the cancel delay.\n bytes32 public constant CANCELER_ROLE = keccak256(\"CANCELER_ROLE\");\n\n /// @notice The role identifier for the Governor's on-chain administrative authority.\n /// @dev Only addresses with this role can perform administrative tasks within the contract.\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n /// @notice The denominator for fee rates, representing 100%.\n uint256 public constant FEE_BPS = 1e6;\n /// @notice The maximum protocol fee rate: 1% of the origin amount.\n uint256 public constant FEE_RATE_MAX = 0.01e6;\n\n /// @notice The minimum cancel delay that can be set by the governor.\n uint256 public constant MIN_CANCEL_DELAY = 1 hours;\n /// @notice The default cancel delay set during contract deployment.\n uint256 public constant DEFAULT_CANCEL_DELAY = 1 days;\n\n /// @notice The protocol fee rate taken on the origin amount deposited in the origin chain.\n uint256 public protocolFeeRate;\n\n /// @notice The accumulated protocol fee amounts.\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice The delay period after which a transaction can be permissionlessly cancelled.\n uint256 public cancelDelay;\n\n /// @notice This variable is deprecated and should not be used.\n /// @dev Use ZapNative V2 requests instead.\n uint256 public immutable chainGasAmount = 0;\n\n constructor(address defaultAdmin) {\n _grantRole(DEFAULT_ADMIN_ROLE, defaultAdmin);\n _setCancelDelay(DEFAULT_CANCEL_DELAY);\n }\n\n /// @inheritdoc IAdminV2\n function setCancelDelay(uint256 newCancelDelay) external onlyRole(GOVERNOR_ROLE) {\n _setCancelDelay(newCancelDelay);\n }\n\n /// @inheritdoc IAdminV2\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n if (newFeeRate \u003e FEE_RATE_MAX) revert FeeRateAboveMax();\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n /// @inheritdoc IAdminV2\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n // Early exit if no accumulated fees.\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return;\n // Reset the accumulated fees first.\n protocolFees[token] = 0;\n emit FeesSwept(token, recipient, feeAmount);\n // Sweep the fees as the last transaction action.\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(recipient), feeAmount);\n } else {\n IERC20(token).safeTransfer(recipient, feeAmount);\n }\n }\n\n /// @notice Internal logic to set the cancel delay. Security checks are performed outside of this function.\n /// @dev This function is marked as private to prevent child contracts from calling it directly.\n function _setCancelDelay(uint256 newCancelDelay) private {\n if (newCancelDelay \u003c MIN_CANCEL_DELAY) revert CancelDelayBelowMin();\n uint256 oldCancelDelay = cancelDelay;\n cancelDelay = newCancelDelay;\n emit CancelDelayUpdated(oldCancelDelay, newCancelDelay);\n }\n}\n\n// contracts/FastBridgeV2.sol\n\n// ════════════════════════════════════════════════ INTERFACES ═════════════════════════════════════════════════════\n\n// ═════════════════════════════════════════════ INTERNAL IMPORTS ══════════════════════════════════════════════════\n\n// ═════════════════════════════════════════════ EXTERNAL IMPORTS ══════════════════════════════════════════════════\n\n/// @title FastBridgeV2\n/// @notice Core component of the SynapseRFQ protocol, enabling Relayers (Solvers) to fulfill bridge requests.\n/// Supports ERC20 and native gas tokens, along with the Zap feature for executing actions on the destination chain.\n/// Users interact with the off-chain Quoter API to obtain a current quote for a bridge transaction.\n/// They then submit the bridge request with the quote to this contract, depositing their assets in escrow.\n/// Relayers can fulfill requests by relaying them to the destination chain and must prove fulfillment to claim funds.\n/// Guards monitor proofs and can dispute discrepancies.\n/// Users can reclaim funds by cancelling their requests if it has not been fulfilled within the specified deadline.\ncontract FastBridgeV2 is AdminV2, MulticallTarget, IFastBridgeV2, IFastBridgeV2Errors {\n using BridgeTransactionV2Lib for bytes;\n using SafeERC20 for IERC20;\n\n /// @notice The duration of the dispute period for relayed transactions.\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice The minimum required time between transaction request and deadline.\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n /// @notice The maximum allowed length for zapData.\n uint256 public constant MAX_ZAP_DATA_LENGTH = 2 ** 16 - 1;\n\n /// @notice Maps transaction IDs to bridge details (status, destination chain ID, proof timestamp, and relayer).\n /// Note: this is only stored for transactions having local chain as the origin chain.\n mapping(bytes32 =\u003e BridgeTxDetails) public bridgeTxDetails;\n /// @notice Maps transaction IDs to relay details (block number, block timestamp, and relayer).\n /// Note: this is only stored for transactions having local chain as the destination chain.\n mapping(bytes32 =\u003e BridgeRelay) public bridgeRelayDetails;\n /// @notice Maps sender addresses to their unique bridge nonce.\n mapping(address =\u003e uint256) public senderNonces;\n\n /// @notice This variable is deprecated and should not be used.\n /// @dev Replaced by senderNonces.\n uint256 public immutable nonce = 0;\n /// @notice The block number at which this contract was deployed.\n uint256 public immutable deployBlock;\n\n /// @notice Initializes the FastBridgeV2 contract with the provided default admin,\n /// sets the default cancel delay, and records the deploy block number.\n constructor(address defaultAdmin) AdminV2(defaultAdmin) {\n deployBlock = block.number;\n }\n\n // ══════════════════════════════════════ EXTERNAL MUTABLE (USER FACING) ═══════════════════════════════════════════\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n bridgeV2({\n params: params,\n paramsV2: BridgeParamsV2({\n quoteRelayer: address(0),\n quoteExclusivitySeconds: 0,\n quoteId: bytes(\"\"),\n zapNative: 0,\n zapData: bytes(\"\")\n })\n });\n }\n\n /// Note: this function is deprecated and will be removed in a future version.\n /// @dev Replaced by `cancel`.\n /// @inheritdoc IFastBridge\n function refund(bytes calldata request) external {\n cancelV2(request);\n }\n\n // ══════════════════════════════════════ EXTERNAL MUTABLE (AGENT FACING) ══════════════════════════════════════════\n\n /// @inheritdoc IFastBridge\n function relay(bytes calldata request) external payable {\n // `relay` override will validate the request.\n relayV2({request: request, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes calldata request, bytes32 destTxHash) external {\n request.validateV2();\n proveV2({transactionId: keccak256(request), destTxHash: destTxHash, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridgeV2\n function claimV2(bytes calldata request) external {\n // `claim` override will validate the request.\n claim({request: request, to: address(0)});\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n // Aggregate the read operations from the same storage slot.\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n address disputedRelayer = $.proofRelayer;\n BridgeStatus status = $.status;\n uint56 proofBlockTimestamp = $.proofBlockTimestamp;\n\n // Can only dispute a RELAYER_PROVED transaction within the dispute period.\n if (status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(proofBlockTimestamp) \u003e DISPUTE_PERIOD) {\n revert DisputePeriodPassed();\n }\n\n // Update status to REQUESTED and delete the disputed proof details.\n // Note: these are storage writes.\n $.status = BridgeStatus.REQUESTED;\n $.proofRelayer = address(0);\n $.proofBlockTimestamp = 0;\n\n emit BridgeProofDisputed(transactionId, disputedRelayer);\n }\n\n // ══════════════════════════════════════════════ EXTERNAL VIEWS ═══════════════════════════════════════════════════\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n // The correct relayer can only claim a RELAYER_PROVED transaction after the dispute period.\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n if ($.status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if ($.proofRelayer != relayer) revert SenderIncorrect();\n\n return _timeSince($.proofBlockTimestamp) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n /// @dev This method is added to achieve backwards compatibility with decoding requests into V1 structs:\n /// - `zapNative` is partially reported as a zero/non-zero flag\n /// - `zapData` is ignored\n /// In order to process all kinds of requests use getBridgeTransactionV2 instead.\n function getBridgeTransaction(bytes calldata request) external view returns (BridgeTransaction memory) {\n // Try decoding into V2 struct first. This will revert if V1 struct is passed.\n try this.getBridgeTransactionV2(request) returns (BridgeTransactionV2 memory txV2) {\n // Note: we entirely ignore the zapData field, as it was not present in V1.\n return BridgeTransaction({\n originChainId: txV2.originChainId,\n destChainId: txV2.destChainId,\n originSender: txV2.originSender,\n destRecipient: txV2.destRecipient,\n originToken: txV2.originToken,\n destToken: txV2.destToken,\n originAmount: txV2.originAmount,\n destAmount: txV2.destAmount,\n originFeeAmount: txV2.originFeeAmount,\n sendChainGas: txV2.zapNative != 0,\n deadline: txV2.deadline,\n nonce: txV2.nonce\n });\n } catch {\n // Fallback to V1 struct.\n return abi.decode(request, (BridgeTransaction));\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function getBridgeTransactionV2(bytes calldata request) external pure returns (BridgeTransactionV2 memory) {\n request.validateV2();\n return BridgeTransactionV2Lib.decodeV2(request);\n }\n\n // ═══════════════════════════════════════ PUBLIC MUTABLE (USER FACING) ════════════════════════════════════════════\n\n /// @inheritdoc IFastBridgeV2\n function bridgeV2(BridgeParams memory params, BridgeParamsV2 memory paramsV2) public payable {\n // If relayer exclusivity is not intended for this bridge, set exclusivityEndTime to static zero.\n // Otherwise, set exclusivity to expire at the current block ts offset by quoteExclusivitySeconds.\n int256 exclusivityEndTime = 0;\n if (paramsV2.quoteRelayer != address(0)) {\n exclusivityEndTime = int256(block.timestamp) + paramsV2.quoteExclusivitySeconds;\n }\n _validateBridgeParams(params, paramsV2, exclusivityEndTime);\n\n // Transfer tokens to bridge contract. We use the actual transferred amount in case of transfer fees.\n uint256 originAmount = _takeBridgedUserAsset(params.originToken, params.originAmount);\n\n // Track the amount of origin token owed to protocol.\n uint256 originFeeAmount = 0;\n if (protocolFeeRate \u003e 0) {\n originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n // The Relayer filling this request will be paid the originAmount after fees.\n // Note: the protocol fees will be accumulated only when the Relayer claims the origin collateral.\n originAmount -= originFeeAmount;\n }\n\n // Hash the bridge request and set the initial status to REQUESTED.\n bytes memory request = BridgeTransactionV2Lib.encodeV2(\n BridgeTransactionV2({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n deadline: params.deadline,\n // Increment the sender's nonce on every bridge.\n nonce: senderNonces[params.sender]++,\n exclusivityRelayer: paramsV2.quoteRelayer,\n // We checked exclusivityEndTime to be in range [0 .. params.deadline] above, so can safely cast.\n exclusivityEndTime: uint256(exclusivityEndTime),\n zapNative: paramsV2.zapNative,\n zapData: paramsV2.zapData\n })\n );\n bytes32 transactionId = keccak256(request);\n // Note: the tx status will be updated throughout the tx lifecycle, while destChainId is set once here.\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n bridgeTxDetails[transactionId].destChainId = params.dstChainId;\n\n emit BridgeRequested({\n transactionId: transactionId,\n sender: params.sender,\n request: request,\n destChainId: params.dstChainId,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n sendChainGas: paramsV2.zapNative != 0\n });\n emit BridgeQuoteDetails(transactionId, paramsV2.quoteId);\n }\n\n /// @inheritdoc IFastBridgeV2\n function cancelV2(bytes calldata request) public {\n // Decode the request and check that it could be cancelled.\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n\n // Can only cancel a REQUESTED transaction after its deadline expires.\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n if ($.status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n\n // Permissionless cancel is only allowed after `cancelDelay` on top of the deadline.\n uint256 deadline = request.deadline();\n if (!hasRole(CANCELER_ROLE, msg.sender)) deadline += cancelDelay;\n if (block.timestamp \u003c= deadline) revert DeadlineNotExceeded();\n\n // Update status to REFUNDED.\n // Note: this is a storage write.\n $.status = BridgeStatus.REFUNDED;\n\n // Return the full amount (collateral + protocol fees) to the original sender.\n // The protocol fees are only accumulated when the transaction is claimed, so we don't need to update them here.\n address to = request.originSender();\n address token = request.originToken();\n uint256 amount = request.originAmount() + request.originFeeAmount();\n\n // Emit the event before any external calls.\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n\n // Return the funds to the original sender as last transaction action.\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(to), amount);\n } else {\n IERC20(token).safeTransfer(to, amount);\n }\n }\n\n // ═══════════════════════════════════════ PUBLIC MUTABLE (AGENT FACING) ═══════════════════════════════════════════\n\n /// @inheritdoc IFastBridgeV2\n function relayV2(bytes calldata request, address relayer) public payable {\n // Decode the request and check that it could be relayed.\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n _validateRelayParams(request, transactionId, relayer);\n\n // Mark the bridge request as relayed by saving the relayer and the block details.\n bridgeRelayDetails[transactionId].blockNumber = uint48(block.number);\n bridgeRelayDetails[transactionId].blockTimestamp = uint48(block.timestamp);\n bridgeRelayDetails[transactionId].relayer = relayer;\n\n // Transfer tokens to recipient on destination chain and trigger Zap if requested.\n address to = request.destRecipient();\n address token = request.destToken();\n uint256 amount = request.destAmount();\n uint256 zapNative = request.zapNative();\n\n // Emit the event before any external calls.\n emit BridgeRelayed({\n transactionId: transactionId,\n relayer: relayer,\n to: to,\n originChainId: request.originChainId(),\n originToken: request.originToken(),\n destToken: token,\n originAmount: request.originAmount(),\n destAmount: amount,\n chainGasAmount: zapNative\n });\n\n // All state changes have been done at this point, can proceed to the external calls.\n // This follows the checks-effects-interactions pattern to mitigate potential reentrancy attacks.\n if (token == NATIVE_GAS_TOKEN) {\n // For the native gas token, additional zapNative is not allowed.\n if (zapNative != 0) revert ZapNativeNotSupported();\n // Check that the correct msg.value was sent.\n if (msg.value != amount) revert MsgValueIncorrect();\n // Don't do a native transfer yet: we will handle it alongside the Zap below.\n } else {\n // For ERC20s, we check that the correct msg.value was sent.\n if (msg.value != zapNative) revert MsgValueIncorrect();\n // We need to transfer the tokens from the Relayer to the recipient first before performing an\n // optional post-transfer Zap.\n IERC20(token).safeTransferFrom(msg.sender, to, amount);\n }\n // At this point we have done:\n // - Transferred the requested amount of ERC20 tokens to the recipient.\n // At this point we have confirmed:\n // - For ERC20s: msg.value matches the requested zapNative amount.\n // - For the native gas token: msg.value matches the requested destAmount.\n // Remaining optional things to do:\n // - Forward the full msg.value to the recipient (if non-zero).\n // - Trigger a Zap (if zapData is present).\n bytes calldata zapData = request.zapData();\n if (zapData.length != 0) {\n // Zap Data is present: Zap has been requested by the recipient. Trigger it forwarding the full msg.value.\n _triggerZapWithChecks({recipient: to, token: token, amount: amount, zapData: zapData});\n // Note: if token has a fee on transfers, the recipient will have received less than `amount`.\n // This is a very niche edge case and should be handled by the recipient contract.\n } else if (msg.value != 0) {\n // Zap Data is missing, but msg.value was sent. This could happen in two different cases:\n // - Relay with the native gas token is happening.\n // - Relay with ERC20 is happening, with a `zapNative \u003e 0` request.\n // In both cases, we need to transfer the full msg.value to the recipient.\n Address.sendValue(payable(to), msg.value);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function proveV2(bytes32 transactionId, bytes32 destTxHash, address relayer) public onlyRole(PROVER_ROLE) {\n // Can only prove a REQUESTED transaction.\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n if ($.status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n\n // Update status to RELAYER_PROVED and store the proof details.\n // Note: these are storage writes.\n $.status = BridgeStatus.RELAYER_PROVED;\n $.proofBlockTimestamp = uint56(block.timestamp);\n $.proofRelayer = relayer;\n\n emit BridgeProofProvided(transactionId, relayer, destTxHash);\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes calldata request, address to) public {\n // Decode the request and check that it could be claimed.\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n\n // Aggregate the read operations from the same storage slot.\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n address proofRelayer = $.proofRelayer;\n BridgeStatus status = $.status;\n uint56 proofBlockTimestamp = $.proofBlockTimestamp;\n\n // Can only claim a RELAYER_PROVED transaction after the dispute period.\n if (status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(proofBlockTimestamp) \u003c= DISPUTE_PERIOD) revert DisputePeriodNotPassed();\n if (to == address(0)) {\n // Anyone could claim the funds to the proven relayer on their behalf.\n to = proofRelayer;\n } else if (proofRelayer != msg.sender) {\n // Only the proven relayer could specify an address to claim the funds to.\n revert SenderIncorrect();\n }\n\n // Update status to RELAYER_CLAIMED and transfer the origin collateral to the specified claim address.\n // Note: this is a storage write.\n $.status = BridgeStatus.RELAYER_CLAIMED;\n\n // Accumulate protocol fees if origin fee amount exists.\n address token = request.originToken();\n uint256 amount = request.originAmount();\n uint256 originFeeAmount = request.originFeeAmount();\n if (originFeeAmount \u003e 0) protocolFees[token] += originFeeAmount;\n\n // Emit the event before any external calls.\n emit BridgeDepositClaimed(transactionId, proofRelayer, to, token, amount);\n\n // Complete the relayer claim as the last transaction action.\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(to), amount);\n } else {\n IERC20(token).safeTransfer(to, amount);\n }\n }\n\n // ═══════════════════════════════════════════════ PUBLIC VIEWS ════════════════════════════════════════════════════\n\n /// @inheritdoc IFastBridgeV2\n function bridgeStatuses(bytes32 transactionId) public view returns (BridgeStatus status) {\n return bridgeTxDetails[transactionId].status;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeProofs(bytes32 transactionId) public view returns (uint96 timestamp, address relayer) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n timestamp = $.proofBlockTimestamp;\n relayer = $.proofRelayer;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeRelays(bytes32 transactionId) public view returns (bool) {\n // This transaction has been relayed if the relayer address is recorded.\n return bridgeRelayDetails[transactionId].relayer != address(0);\n }\n\n // ═════════════════════════════════════════════ INTERNAL METHODS ══════════════════════════════════════════════════\n\n /// @notice Takes the bridged asset from the user into FastBridgeV2 custody. The asset will later be\n /// claimed by the relayer who completed the relay on the destination chain, or returned to the user\n /// via the cancel function if no relay is completed.\n function _takeBridgedUserAsset(address token, uint256 amount) internal returns (uint256 amountTaken) {\n if (token == NATIVE_GAS_TOKEN) {\n // For the native gas token, we just need to check that the supplied msg.value is correct.\n // Supplied `msg.value` is already in FastBridgeV2 custody.\n if (amount != msg.value) revert MsgValueIncorrect();\n amountTaken = msg.value;\n } else {\n // For ERC20s, token is explicitly transferred from the user to FastBridgeV2.\n // We don't allow non-zero `msg.value` to avoid extra funds from being stuck in FastBridgeV2.\n if (msg.value != 0) revert MsgValueIncorrect();\n // Throw an explicit error if the provided token address is not a contract.\n if (token.code.length == 0) revert TokenNotContract();\n\n // Use the balance difference as the amount taken in case of fee on transfer tokens.\n amountTaken = IERC20(token).balanceOf(address(this));\n IERC20(token).safeTransferFrom(msg.sender, address(this), amount);\n amountTaken = IERC20(token).balanceOf(address(this)) - amountTaken;\n }\n }\n\n /// @notice Calls the recipient's hook function with the specified zapData and validates\n /// the returned value.\n function _triggerZapWithChecks(address recipient, address token, uint256 amount, bytes calldata zapData) internal {\n // Call the recipient's hook function with the specified zapData, bubbling any revert messages.\n bytes memory returnData = Address.functionCallWithValue({\n target: recipient,\n data: abi.encodeCall(IZapRecipient.zap, (token, amount, zapData)),\n // Note: see `relay()` for reasoning behind passing msg.value.\n value: msg.value\n });\n\n // Explicit revert if no return data at all.\n if (returnData.length == 0) revert RecipientNoReturnValue();\n // Check that exactly a single return value was returned.\n if (returnData.length != 32) revert RecipientIncorrectReturnValue();\n // Return value should be abi-encoded hook function selector.\n if (bytes32(returnData) != bytes32(IZapRecipient.zap.selector)) {\n revert RecipientIncorrectReturnValue();\n }\n }\n\n /// @notice Calculates the time elapsed since a proof was submitted.\n /// @dev The proof.timestamp stores block timestamps as uint56 for gas optimization.\n /// _timeSince(proof) handles timestamp rollover when block.timestamp \u003e type(uint56).max but\n /// proof.timestamp \u003c type(uint56).max via an unchecked statement.\n /// @param proofBlockTimestamp The block timestamp when the proof was submitted.\n /// @return delta The time elapsed since proof submission.\n function _timeSince(uint56 proofBlockTimestamp) internal view returns (uint256 delta) {\n unchecked {\n delta = uint56(block.timestamp) - proofBlockTimestamp;\n }\n }\n\n /// @notice Validates all parameters required for a bridge transaction.\n /// @dev This function's complexity cannot be reduced due to the number of required checks,\n /// so we disable the code-complexity rule.\n // solhint-disable-next-line code-complexity\n function _validateBridgeParams(\n BridgeParams memory params,\n BridgeParamsV2 memory paramsV2,\n int256 exclusivityEndTime\n )\n internal\n view\n {\n // Check V1 (legacy) params.\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.sender == address(0) || params.to == address(0)) revert ZeroAddress();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n\n // Check V2 params.\n if (paramsV2.zapData.length \u003e MAX_ZAP_DATA_LENGTH) revert ZapDataLengthAboveMax();\n if (paramsV2.zapNative != 0 \u0026\u0026 params.destToken == NATIVE_GAS_TOKEN) {\n revert ZapNativeNotSupported();\n }\n\n // exclusivityEndTime must be in range [0 .. params.deadline].\n if (exclusivityEndTime \u003c 0 || exclusivityEndTime \u003e int256(params.deadline)) {\n revert ExclusivityParamsIncorrect();\n }\n }\n\n /// @notice Validates all parameters required for a relay transaction.\n function _validateRelayParams(bytes calldata request, bytes32 transactionId, address relayer) internal view {\n if (relayer == address(0)) revert ZeroAddress();\n // Check that the transaction has not been relayed yet and is for the current chain.\n if (bridgeRelays(transactionId)) revert TransactionRelayed();\n if (request.destChainId() != block.chainid) revert ChainIncorrect();\n // Check that the deadline for relay to happen has not passed yet.\n if (block.timestamp \u003e request.deadline()) revert DeadlineExceeded();\n // Check the exclusivity period, if it was specified and is still ongoing.\n address exclRelayer = request.exclusivityRelayer();\n if (exclRelayer != address(0) \u0026\u0026 exclRelayer != relayer \u0026\u0026 block.timestamp \u003c= request.exclusivityEndTime()) {\n revert ExclusivityPeriodNotPassed();\n }\n }\n}\n","language":"Solidity","languageVersion":"0.8.24","compilerVersion":"0.8.24","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"84624:25992:0:-:0;;;81103:1;81061:43;;;;85955:34;;86271:99;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;86313:12;81155:44;70288:4;86313:12;81155:10;:44::i;:::-;-1:-1:-1;81209:37:0;80564:6;81209:15;:37::i;:::-;-1:-1:-1;;86351:12:0::1;86337:26;::::0;84624:25992;;77010:257;77096:4;;77127:31;77144:4;77150:7;77127:16;:31::i;:::-;77112:46;;77172:7;77168:69;;;77195:18;;;;:12;:18;;;;;:31;;77218:7;77195:22;:31::i;:::-;;77168:69;77253:7;-1:-1:-1;77010:257:0;;;;;:::o;82609:290::-;80431:7;82680:14;:33;82676:67;;;82722:21;;-1:-1:-1;;;82722:21:0;;;;;;;;;;;82676:67;82778:11;;;82799:28;;;;82842:50;;;483:25:1;;;539:2;524:18;;517:34;;;82842:50:0;;456:18:1;82842:50:0;;;;;;;82666:233;82609:290;:::o;74235:316::-;74312:4;71010:12;;;;;;;;;;;-1:-1:-1;;;;;71010:29:0;;;;;;;;;;;;74328:217;;74371:6;:12;;;;;;;;;;;-1:-1:-1;;;;;74371:29:0;;;;;;;;;:36;;-1:-1:-1;;74371:36:0;74403:4;74371:36;;;74453:12;26158:10;;26079:96;74453:12;-1:-1:-1;;;;;74426:40:0;74444:7;-1:-1:-1;;;;;74426:40:0;74438:4;74426:40;;;;;;;;;;-1:-1:-1;74487:4:0;74480:11;;74328:217;-1:-1:-1;74529:5:0;74522:12;;35603:150;35673:4;35696:50;35701:3;-1:-1:-1;;;;;35721:23:0;;29591:4;31647:21;;;:14;;;:21;;;;;;29607:321;;-1:-1:-1;29649:23:0;;;;;;;;:11;:23;;;;;;;;;;;;;29831:18;;29807:21;;;:14;;;:21;;;;;;:42;;;;29863:11;;14:290:1;84:6;137:2;125:9;116:7;112:23;108:32;105:52;;;153:1;150;143:12;105:52;179:16;;-1:-1:-1;;;;;224:31:1;;214:42;;204:70;;270:1;267;260:12;309:248;84624:25992:0;;;;;;;;;;;;;;;;;;;;;;;;","srcMapRuntime":"84624:25992:0:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;75670:212;;;;;;;;;;-1:-1:-1;75670:212:0;;;;;:::i;:::-;;:::i;:::-;;;612:14:1;;605:22;587:41;;575:2;560:18;75670:212:0;;;;;;;;79748:66;;;;;;;;;;;;79788:26;79748:66;;;;;785:25:1;;;773:2;758:18;79748:66:0;639:177:1;79482:60:0;;;;;;;;;;;;79519:23;79482:60;;103949:150;;;;;;;;;;-1:-1:-1;103949:150:0;;;;;:::i;:::-;104017:19;104055:30;;;:15;:30;;;;;:37;;;;103949:150;;;;;;;;:::i;81777:613::-;;;;;;;;;;-1:-1:-1;81777:613:0;;;;;:::i;:::-;;:::i;:::-;;80262:45;;;;;;;;;;;;80301:6;80262:45;;78693:85;;;;;;;;;;;;78736:42;78693:85;;;;;-1:-1:-1;;;;;2885:55:1;;;2867:74;;2855:2;2840:18;78693:85:0;2721:226:1;81288:129:0;;;;;;;;;;-1:-1:-1;81288:129:0;;;;;:::i;:::-;;:::i;71866:120::-;;;;;;;;;;-1:-1:-1;71866:120:0;;;;;:::i;:::-;71931:7;71957:12;;;;;;;;;;:22;;;;71866:120;85794:47;;;;;;;;;;-1:-1:-1;85794:47:0;;;;;:::i;:::-;;;;;;;;;;;;;;72282:136;;;;;;;;;;-1:-1:-1;72282:136:0;;;;;:::i;:::-;;:::i;73384:245::-;;;;;;;;;;-1:-1:-1;73384:245:0;;;;;:::i;:::-;;:::i;47142:875::-;;;;;;;;;;-1:-1:-1;47142:875:0;;;;;:::i;:::-;;:::i;:::-;;;;;;;:::i;97181:3736::-;;;;;;:::i;:::-;;:::i;46381:718::-;;;;;;;;;;-1:-1:-1;46381:718:0;;;;;:::i;:::-;;:::i;101627:1962::-;;;;;;;;;;-1:-1:-1;101627:1962:0;;;;;:::i;:::-;;:::i;100957:632::-;;;;;;;;;;-1:-1:-1;100957:632:0;;;;;:::i;:::-;;:::i;86692:368::-;;;;;;:::i;:::-;;:::i;85131:57::-;;;;;;;;;;;;85177:11;85131:57;;80673:30;;;;;;;;;;;;;;;;91547:201;;;;;;;;;;-1:-1:-1;91547:201:0;;;;;:::i;:::-;;:::i;:::-;;;;;;;:::i;87216:83::-;;;;;;;;;;-1:-1:-1;87216:83:0;;;;;:::i;:::-;;:::i;85403:58::-;;;;;;;;;;-1:-1:-1;85403:58:0;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;85403:58:0;;;;;;;;;;;;;:::i;80912:26::-;;;;;;;;;;;;;;;;95264:1591;;;;;;;;;;-1:-1:-1;95264:1591:0;;;;;:::i;:::-;;:::i;92076:3148::-;;;;;;:::i;:::-;;:::i;78950:62::-;;;;;;;;;;;;78988:24;78950:62;;85012:56;;;;;;;;;;;;85058:10;85012:56;;104432:232;;;;;;;;;;-1:-1:-1;104432:232:0;;;;;:::i;:::-;104498:4;104602:33;;;:18;:33;;;;;:41;;;;-1:-1:-1;;;;;104602:41:0;:55;;;104432:232;87833:204;;;;;;;;;;-1:-1:-1;87833:204:0;;;;;:::i;:::-;;:::i;87619:176::-;;;;;;:::i;:::-;;:::i;76467:142::-;;;;;;;;;;-1:-1:-1;76467:142:0;;;;;:::i;:::-;;:::i;104139:253::-;;;;;;;;;;-1:-1:-1;104139:253:0;;;;;:::i;:::-;104205:16;104278:30;;;:15;:30;;;;;104330:21;;;;;;;104371:14;;;;-1:-1:-1;;;;;104371:14:0;;104139:253;;;;;16312:26:1;16300:39;;;16282:58;;-1:-1:-1;;;;;16376:55:1;;;16371:2;16356:18;;16349:83;16255:18;104139:253:0;16110:328:1;70910:136:0;;;;;;;;;;-1:-1:-1;70910:136:0;;;;;:::i;:::-;70987:4;71010:12;;;;;;;;;;;-1:-1:-1;;;;;71010:29:0;;;;;;;;;;;;;;;70910:136;80388:50;;;;;;;;;;;;80431:7;80388:50;;80517:53;;;;;;;;;;;;80564:6;80517:53;;70243:49;;;;;;;;;;-1:-1:-1;70243:49:0;70288:4;70243:49;;86065:36;;;;;;;;;;;;;;;89577:475;;;;;;;;;;-1:-1:-1;89577:475:0;;;;;:::i;:::-;;:::i;90384:1123::-;;;;;;;;;;-1:-1:-1;90384:1123:0;;;;;:::i;:::-;;:::i;:::-;;;;;;;:::i;88278:945::-;;;;;;;;;;-1:-1:-1;88278:945:0;;;;;:::i;:::-;;:::i;85955:34::-;;;;;;;;;;;;;;;81452:290;;;;;;;;;;-1:-1:-1;81452:290:0;;;;;:::i;:::-;;:::i;80147:37::-;;;;;;;;;;;;80181:3;80147:37;;85663:57;;;;;;;;;;-1:-1:-1;85663:57:0;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;85663:57:0;;;;;;;18029:14:1;18070:15;;;18052:34;;18122:15;;;;18117:2;18102:18;;18095:43;-1:-1:-1;;;;;18174:55:1;18154:18;;;18147:83;18007:2;17992:18;85663:57:0;17821:415:1;76777:131:0;;;;;;;;;;-1:-1:-1;76777:131:0;;;;;:::i;:::-;;:::i;80008:66::-;;;;;;;;;;;;80048:26;80008:66;;72698:138;;;;;;;;;;-1:-1:-1;72698:138:0;;;;;:::i;:::-;;:::i;79217:62::-;;;;;;;;;;;;79255:24;79217:62;;80764:47;;;;;;;;;;-1:-1:-1;80764:47:0;;;;;:::i;:::-;;;;;;;;;;;;;;81061:43;;;;;;;;;;;;;;;88077:163;;;;;;;;;;-1:-1:-1;88077:163:0;;;;;:::i;:::-;;:::i;75670:212::-;75755:4;75778:57;;;75793:42;75778:57;;:97;;;75839:36;75863:11;75839:23;:36::i;:::-;75771:104;75670:212;-1:-1:-1;;75670:212:0:o;81777:613::-;80048:26;70520:16;70531:4;70520:10;:16::i;:::-;-1:-1:-1;;;;;81947:19:0;::::1;81927:17;81947:19:::0;;;:12:::1;:19;::::0;;;;;;81980:14;;;81976:27:::1;;81996:7;81777:613:::0;;;:::o;81976:27::-:1;-1:-1:-1::0;;;;;82057:19:0;;::::1;82079:1;82057:19:::0;;;:12:::1;:19;::::0;;;;;;;:23;;;;82095:38;;18504:34:1;;;18574:15;;;18554:18;;;18547:43;;;;18606:18;;;18599:34;;;82095:38:0::1;::::0;18431:2:1;18416:18;82095:38:0::1;;;;;;;82205:25:::0;-1:-1:-1;;;;;82205:25:0;::::1;::::0;82201:183:::1;;82246:48;82272:9;82284;82246:17;:48::i;:::-;82201:183;;;82325:48;-1:-1:-1::0;;;;;82325:26:0;::::1;82352:9:::0;82363;82325:26:::1;:48::i;:::-;81871:519;70546:1;81777:613:::0;;;:::o;81288:129::-;80048:26;70520:16;70531:4;70520:10;:16::i;:::-;81379:31:::1;81395:14;81379:15;:31::i;:::-;81288:129:::0;;:::o;72282:136::-;71931:7;71957:12;;;;;;;;;;:22;;;70520:16;70531:4;70520:10;:16::i;:::-;72386:25:::1;72397:4;72403:7;72386:10;:25::i;73384:245::-:0;-1:-1:-1;;;;;73477:34:0;;26158:10;73477:34;73473:102;;73534:30;;;;;;;;;;;;;;73473:102;73585:37;73597:4;73603:18;73585:11;:37::i;47142:875::-;47271:23;47333:4;47320:25;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;;;;;;;;;;;;;47320:25:0;;;;;;;;;;;;;;;;47310:35;;47360:9;47355:656;47375:15;;;47355:656;;;47848:4;47867;;47872:1;47867:7;;;;;;;:::i;:::-;;;;;;;;;;;;:::i;:::-;47840:35;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;47795:7;47803:1;47795:10;;;;;;;;:::i;:::-;;;;;;;:18;;47815:7;47823:1;47815:10;;;;;;;;:::i;:::-;;;;;;;:21;;47794:81;;;;;;;;;;;;;47894:7;47902:1;47894:10;;;;;;;;:::i;:::-;;;;;;;:18;;;47893:19;:37;;;;;47917:13;47916:14;47893:37;47889:112;;;47950:36;47964:7;47972:1;47964:10;;;;;;;;:::i;:::-;;;;;;;:21;;;47950:13;:36::i;:::-;47392:3;;47355:656;;;;47142:875;;;;;:::o;97181:3736::-;97330:20;:7;;:18;:20::i;:::-;97360:21;97394:7;;97384:18;;;;;;;:::i;:::-;;;;;;;;97360:42;;97412:53;97433:7;;97442:13;97457:7;97412:20;:53::i;:::-;97567:33;;;;:18;:33;;;;;:68;;-1:-1:-1;;;;;97729:51:0;;;;;;97703:15;97567:68;97645:74;;;;;;;;;97622:12;97567:68;;;;97645:74;;;;;97729:51;;;;;;;;;;;58359:21;58337:44;;58324:58;58320:2;58316:67;;;;59168:17;59146:40;;59133:54;59125:63;;;;59943:18;59921:41;;59908:55;;62311:17;62289:40;;62276:54;;58316:67;;97567:33;98128:368;57115:22;57093:45;;57080:59;57075:3;57071:69;98128:368;;;20009:10:1;19997:23;;;;19979:42;;58765:19:0;58743:42;;58730:56;58726:2;58722:65;;;20113:2:1;20098:18;;20091:43;-1:-1:-1;;;;;20170:15:1;;20150:18;;;20143:43;59555:20:0;59533:43;;59520:57;20202:18:1;;;20195:34;20260:3;20245:19;;20238:35;;;20304:3;20289:19;;20282:35;;;98128:368:0;;;;;19966:3:1;98128:368:0;;;98711:25;-1:-1:-1;;;;;98711:25:0;;;98707:773;;98834:14;;98830:50;;98857:23;;;;;;;;;;;;;;98830:50;98969:6;98956:9;:19;98952:51;;98984:19;;;;;;;;;;;;;;98952:51;98707:773;;;99214:9;99201;:22;99197:54;;99232:19;;;;;;;;;;;;;;99197:54;99415;-1:-1:-1;;;;;99415:30:0;;99446:10;99458:2;99462:6;99415:30;:54::i;:::-;99978:22;;100003:17;:7;;:15;:17::i;:::-;99978:42;;-1:-1:-1;99978:42:0;-1:-1:-1;100034:19:0;;100030:881;;100188:86;100222:2;100233:5;100248:6;100265:7;;100188:21;:86::i;:::-;100030:881;;;100497:9;:14;100493:418;;100859:41;100885:2;100890:9;100859:17;:41::i;:::-;97254:3663;;;;;;;97181:3736;;;:::o;46381:718::-;46476:9;46471:622;46491:15;;;46471:622;;;46911:12;;46956:4;46975;;46980:1;46975:7;;;;;;;:::i;:::-;;;;;;;;;;;;:::i;:::-;46948:35;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;46910:73;;;;47002:7;47001:8;:26;;;;;47014:13;47013:14;47001:26;46997:86;;;47047:21;47061:6;47047:13;:21::i;:::-;-1:-1:-1;;46508:3:0;;46471:622;;101627:1962;101761:20;:7;;:18;:20::i;:::-;101791:21;101825:7;;101815:18;;;;;;;:::i;:::-;;;;;;;;;;;101913:25;101941:30;;;:15;:30;;;;;;102004:14;;101815:18;;-1:-1:-1;101941:30:0;102004:14;;;-1:-1:-1;;;;;102004:14:0;;102050:8;;;;102097:21;;;;;102224:27;102214:6;:37;;;;;;;;:::i;:::-;;102210:67;;102260:17;;;;;;;;;;;;;;102210:67;84911:10;108172:15;108165:45;;;108157:53;;102291:49;102287:86;;102349:24;;;;;;;;;;;;;;102287:86;-1:-1:-1;;;;;102387:16:0;;102383:321;;102507:12;102502:17;;102383:321;;;-1:-1:-1;;;;;102540:26:0;;102556:10;102540:26;102536:168;;102676:17;;;;;;;;;;;;;;102536:168;102867:39;;;;102878:28;102867:39;;;58765:19;58743:42;;58730:56;58726:2;58722:65;59555:20;59533:43;;59520:57;60343:24;60321:47;;60308:61;103143:19;;103139:63;;-1:-1:-1;;;;;103164:19:0;;;;;;:12;:19;;;;;:38;;103187:15;;103164:19;:38;;103187:15;;103164:38;:::i;:::-;;;;-1:-1:-1;;103139:63:0;103271:68;;;-1:-1:-1;;;;;20839:55:1;;;20821:74;;20926:2;20911:18;;20904:34;;;103271:68:0;;;;;;;;103292:13;;103271:68;;20794:18:1;103271:68:0;;;;;;;103424:25;-1:-1:-1;;;;;103424:25:0;;;103420:163;;103465:38;103491:2;103496:6;103465:17;:38::i;:::-;103420:163;;;103534:38;-1:-1:-1;;;;;103534:26:0;;103561:2;103565:6;103534:26;:38::i;:::-;101685:1904;;;;;;;;101627:1962;;;:::o;100957:632::-;79255:24;70520:16;70531:4;70520:10;:16::i;:::-;101124:25:::1;101152:30:::0;;;:15:::1;:30;::::0;;;;101208:22:::1;101196:8:::0;;::::1;;:34;::::0;::::1;;;;;;:::i;:::-;;101192:64;;101239:17;;;;;;;;;;;;;;101192:64;101382:38:::0;;-1:-1:-1;;;;;101487:24:0;::::1;::::0;;::::1;::::0;101430:47:::1;101461:15;101430:47;::::0;::::1;101487:24:::0;;;;;;;;;;;;;101393:27:::1;101487:24:::0;;;101527:55:::1;::::0;785:25:1;;;101547:13:0;;101527:55:::1;::::0;773:2:1;758:18;101527:55:0::1;;;;;;;101063:526;100957:632:::0;;;;:::o;86692:368::-;86763:290;86794:6;86824:218;;;;;;;;86879:1;-1:-1:-1;;;;;86824:218:0;;;;;86924:1;86824:218;;;;86952:9;;;;;;;;;;;;86824:218;;;;86990:1;86824:218;;;;87018:9;;;;;;;;;;;;86824:218;;;86763:8;:290::i;:::-;86692:368;:::o;91547:201::-;91626:26;-1:-1:-1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;91626:26:0;91664:20;:7;;:18;:20::i;:::-;91701:40;91733:7;;91701:31;:40::i;:::-;91694:47;91547:201;-1:-1:-1;;;91547:201:0:o;87216:83::-;87275:17;87284:7;;95264:1591;95391:20;:7;;:18;:20::i;:::-;95421:21;95455:7;;95445:18;;;;;;;:::i;:::-;;;;;;;;;;;95553:25;95581:30;;;:15;:30;;;;;;95445:18;;-1:-1:-1;95637:22:0;95625:8;;;;:34;;;;;;;;:::i;:::-;;95621:64;;95668:17;;;;;;;;;;;;;;95621:64;95864:10;95789:16;71010:29;;;:12;;:29;:12;:29;;;60719:15;60697:38;;60684:52;;71010:29;;95836:64;;95889:11;;95877:23;;;;:::i;:::-;;;95836:64;95933:8;95914:15;:27;95910:61;;95950:21;;;;;;;;;;;;;;95910:61;96062:32;;;;96073:21;96062:32;;;57939:20;57917:43;;57904:57;57900:2;57896:66;;;;58765:19;58743:42;;58730:56;58722:65;;-1:-1:-1;96422:50:0;60343:24;60321:47;;60308:61;59555:20;59533:43;;59520:57;96422:50;:::i;:::-;96541:55;;;-1:-1:-1;;;;;20839:55:1;;;20821:74;;20926:2;20911:18;;20904:34;;;96541:55:0;;20904:34:1;;-1:-1:-1;96541:55:0;;;96563:13;;96541:55;;;;;;;;96690:25;-1:-1:-1;;;;;96690:25:0;;;96686:163;;96731:38;96757:2;96762:6;96731:17;:38::i;:::-;96686:163;;;96800:38;-1:-1:-1;;;;;96800:26:0;;96827:2;96831:6;96800:26;:38::i;:::-;95313:1542;;;;;;95264:1591;;:::o;92076:3148::-;92435:21;;92392:25;;-1:-1:-1;;;;;92435:35:0;;92431:145;;92533:32;;;;92507:58;;92514:15;92507:58;:::i;:::-;92486:79;;92431:145;92585:59;92607:6;92615:8;92625:18;92585:21;:59::i;:::-;92765:20;92788:62;92810:6;:18;;;92830:6;:19;;;92788:21;:62::i;:::-;92765:85;;92923:23;92982:1;92964:15;;:19;92960:356;;;80181:3;93033:15;;93018:12;:30;;;;:::i;:::-;93017:42;;;;:::i;:::-;92999:60;-1:-1:-1;93274:31:0;92999:60;93274:31;;:::i;:::-;;;92960:356;93402:20;93425:1004;93470:949;;;;;;;;93530:13;93470:949;;;;;;93575:6;:17;;;93470:949;;;;;;93624:6;:13;;;-1:-1:-1;;;;;93470:949:0;;;;;93670:6;:9;;;-1:-1:-1;;;;;93470:949:0;;;;;93710:6;:18;;;-1:-1:-1;;;;;93470:949:0;;;;;93757:6;:16;;;-1:-1:-1;;;;;93470:949:0;;;;;93805:12;93470:949;;;;93847:6;:17;;;93470:949;;;;93899:15;93470:949;;;;93942:6;:15;;;93470:949;;;;94047:12;:27;94060:6;:13;;;-1:-1:-1;;;;;94047:27:0;-1:-1:-1;;;;;94047:27:0;;;;;;;;;;;;;:29;;;;;;;;;:::i;:::-;;;;-1:-1:-1;93470:949:0;;94114:21;;-1:-1:-1;;;;;93470:949:0;;;;;;;;;;;;94343:18;;;;93470:949;;;;;94388:16;;;;93470:949;;;93425:31;:1004::i;:::-;94463:18;;;;;;;;;;94439:21;94603:30;;;:15;:30;;;;;;;:62;;94720:17;;94675:62;;;;;;;;;;;;;94643:22;94675:62;;;;94833:13;;;;94947:18;;;;;94990:16;;;;95072:17;;;;95117:18;;;;94753:398;;94463:18;;-1:-1:-1;94463:18:0;;-1:-1:-1;;;;;94753:398:0;;;;94463:18;;94753:398;;;;94463:18;;94720:17;;94947:18;95034:12;;95072:17;;95117:23;;;;94753:398;:::i;:::-;;;;;;;;95185:13;95166:51;95200:8;:16;;;95166:51;;;;;;:::i;:::-;;;;;;;;92169:3055;;;;;92076:3148;;:::o;87833:204::-;87911:20;:7;;:18;:20::i;:::-;87941:89;87975:7;;87965:18;;;;;;;:::i;:::-;;;;;;;;87997:10;88018;87941:7;:89::i;87619:176::-;87740:48;87758:7;;87776:10;87740:7;:48::i;76467:142::-;76548:7;76574:18;;;:12;:18;;;;;:28;;76596:5;76574:21;:28::i;89577:475::-;89658:4;89803:30;;;:15;:30;;;;;89859:27;89847:8;;;;:39;;;;;;;;:::i;:::-;;89843:69;;89895:17;;;;;;;;;;;;;;89843:69;89926:14;;-1:-1:-1;;;;;89926:25:0;;;:14;;;;;:25;89922:55;;89960:17;;;;;;;;;;;;;;89922:55;90006:21;84911:10;90006:21;;;;;;;;108172:15;108165:45;108157:53;89995:50;;;-1:-1:-1;;;89577:475:0:o;90384:1123::-;-1:-1:-1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;90588:36:0;;;;;:4;;:27;;:36;;90616:7;;;;90588:36;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;90588:36:0;;;;;;;;;;;;:::i;:::-;;;90584:917;;91450:40;;;;91461:7;91450:40;:::i;:::-;91443:47;;;;90584:917;90776:597;;;;;;;;90827:4;:18;;;90776:597;;;;;;90876:4;:16;;;90776:597;;;;;;90924:4;:17;;;-1:-1:-1;;;;;90776:597:0;;;;;90974:4;:18;;;-1:-1:-1;;;;;90776:597:0;;;;;91023:4;:16;;;-1:-1:-1;;;;;90776:597:0;;;;;91068:4;:14;;;-1:-1:-1;;;;;90776:597:0;;;;;91114:4;:17;;;90776:597;;;;91161:4;:15;;;90776:597;;;;91211:4;:20;;;90776:597;;;;91263:4;:14;;;91281:1;91263:19;;90776:597;;;;;;91310:4;:13;;;90776:597;;;;91348:4;:10;;;90776:597;;;90769:604;;;;;88278:945;79519:23;70520:16;70531:4;70520:10;:16::i;:::-;88427:25:::1;88455:30:::0;;;:15:::1;:30;::::0;;;;88521:14;;;;::::1;-1:-1:-1::0;;;;;88521:14:0::1;::::0;88567:8:::1;::::0;::::1;::::0;88614:21;;::::1;;;88744:27;88734:6;:37;;;;;;;;:::i;:::-;;88730:67;;88780:17;;;;;;;;;;;;;;88730:67;84911:10;108172:15:::0;108165:45;;;108157:53;;88811:48:::1;88807:107;;;88882:21;;;;;;;;;;;;;;88807:107;89044:33:::0;;89124:25;;89055:22:::1;89124:25:::0;;;89165:51:::1;::::0;-1:-1:-1;;;;;89165:51:0;::::1;::::0;89185:13;;89165:51:::1;::::0;-1:-1:-1;;89165:51:0::1;88348:875;;;;88278:945:::0;;:::o;81452:290::-;80048:26;70520:16;70531:4;70520:10;:16::i;:::-;80301:6:::1;81547:10;:25;81543:55;;;81581:17;;;;;;;;;;;;;;81543:55;81629:15;::::0;;81654:28;;;;81697:38:::1;::::0;;27234:25:1;;;27290:2;27275:18;;27268:34;;;81697:38:0::1;::::0;27207:18:1;81697:38:0::1;;;;;;;81533:209;81452:290:::0;;:::o;76777:131::-;76848:7;76874:18;;;:12;:18;;;;;:27;;:25;:27::i;72698:138::-;71931:7;71957:12;;;;;;;;;;:22;;;70520:16;70531:4;70520:10;:16::i;:::-;72803:26:::1;72815:4;72821:7;72803:11;:26::i;88077:163::-:0;88192:41;88208:7;;88229:1;88192:5;:41::i;70621:202::-;70706:4;70729:47;;;70744:32;70729:47;;:87;;-1:-1:-1;50955:25:0;50940:40;;;;70780:36;50841:146;71255:103;71321:30;71332:4;26158:10;71321;:30::i;20690:331::-;20799:6;20775:21;:30;20771:109;;;20828:41;;;;;20863:4;20828:41;;;2867:74:1;2840:18;;20828:41:0;;;;;;;;20771:109;20891:12;20909:9;-1:-1:-1;;;;;20909:14:0;20931:6;20909:33;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;20890:52;;;20957:7;20952:63;;20987:17;;;;;;;;;;;;;;63738:160;63847:43;;-1:-1:-1;;;;;20839:55:1;;;63847:43:0;;;20821:74:1;20911:18;;;20904:34;;;63820:71:0;;63840:5;;63862:14;;;;;20794:18:1;;63847:43:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;63820:19;:71::i;82609:290::-;80431:7;82680:14;:33;82676:67;;;82722:21;;;;;;;;;;;;;;82676:67;82778:11;;;82799:28;;;;82842:50;;;27234:25:1;;;27290:2;27275:18;;27268:34;;;82842:50:0;;27207:18:1;82842:50:0;;;;;;;82666:233;82609:290;:::o;77010:257::-;77096:4;77112:12;77127:31;77144:4;77150:7;77127:16;:31::i;:::-;77112:46;;77172:7;77168:69;;;77195:18;;;;:12;:18;;;;;:31;;77218:7;77195:22;:31::i;77370:262::-;77457:4;77473:12;77488:32;77506:4;77512:7;77488:17;:32::i;:::-;77473:47;;77534:7;77530:72;;;77557:18;;;;:12;:18;;;;;:34;;77583:7;77557:25;:34::i;48291:556::-;48429:17;;:21;48425:416;;48670:10;48664:17;48726:15;48713:10;48709:2;48705:19;48698:44;48425:416;48793:37;;;;;;;;;;;;;;53427:469;53044:3;53579:34;;53575:86;;;53622:39;;;;;;;;;;;;;;53575:86;56693:30;;56688:3;56684:40;51144:1;53812:19;;53808:81;;53840:49;;;;;27697:6:1;27685:19;;53840:49:0;;;27667:38:1;27640:18;;53840:49:0;27523:188:1;109730:884:0;-1:-1:-1;;;;;109852:21:0;;109848:47;;109882:13;;;;;;;;;;;;;;109848:47;104498:4;104602:33;;;:18;:33;;;;;:41;;;;-1:-1:-1;;;;;104602:41:0;:55;109998:60;;110038:20;;;;;;;;;;;;;;109998:60;57530:20;57508:43;;57495:57;57490:3;57486:67;110097:13;110072:38;110068:67;;110119:16;;;;;;;;;;;;;;110068:67;60719:15;60697:38;;60684:52;110224:15;:36;110220:67;;;110269:18;;;;;;;;;;;;;;110220:67;61498:26;61476:49;;61463:63;61459:2;61455:72;110444:25;;;;;:51;;;110488:7;-1:-1:-1;;;;;110473:22:0;:11;-1:-1:-1;;;;;110473:22:0;;;110444:51;:102;;;;-1:-1:-1;61919:27:0;61897:50;;61884:64;110499:15;:47;;110444:102;110440:168;;;110569:28;;;;;;;;;;;;;;110440:168;109838:776;109730:884;;;;:::o;64137:188::-;64264:53;;-1:-1:-1;;;;;18522:15:1;;;64264:53:0;;;18504:34:1;18574:15;;;18554:18;;;18547:43;18606:18;;;18599:34;;;64237:81:0;;64257:5;;64279:18;;;;;18416::1;;64264:53:0;18241:398:1;62422:146:0;62488:23;;62534:27;:9;53044:3;62534:9;;:27;:::i;:::-;62523:38;;;;62422:146;;;;;:::o;106564:989::-;106792:23;106818:256;106870:9;106934:5;106941:6;106949:7;;106899:59;;;;;;;;;;;:::i;:::-;;;;-1:-1:-1;;106899:59:0;;;;;;;;;;;;;;;;;;;;107054:9;106818:29;:256::i;:::-;106792:282;;107142:10;:17;107163:1;107142:22;107138:59;;107173:24;;;;;;;;;;;;;;107138:59;107277:10;:17;107298:2;107277:23;107273:67;;107309:31;;;;;;;;;;;;;;107273:67;107455:26;107424:19;107432:10;107424:19;:::i;:::-;:58;107420:127;;107505:31;;;;;;;;;;;;;;107420:127;106678:875;106564:989;;;;;:::o;55390:990::-;55481:49;-1:-1:-1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;55481:49:0;57115:22;57093:45;;57080:59;57075:3;57071:69;;;55546:49;;57530:20;57508:43;;57495:57;57486:67;;55605:20;;;:45;57939:20;57917:43;;57904:57;57900:2;57896:66;;;55660:21;;;:47;58359:21;58337:44;;58324:58;58316:67;;55717:22;;;:49;58765:19;58743:42;;58730:56;58722:65;;55776:20;;;:45;59168:17;59146:40;;59133:54;59125:63;;55831:18;;;:41;59555:20;59533:43;;59520:57;55882:21;;;:47;59943:18;59921:41;;59908:55;55939:19;;;:43;;;;60343:24;60321:47;;60308:61;55992:24;;;:53;60719:15;60697:38;;60684:52;56055:17;;;:39;61074:12;61052:35;;61039:49;56104:14;;;:33;61498:26;61476:49;;61463:63;61455:72;;56147:27;;;:59;61919:27;61897:50;;61884:64;56216:27;;;:59;62311:17;62289:40;;62276:54;56285:18;;;:41;56355:18;57093:45;56363:9;56355:7;:18::i;:::-;56336:37;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;56336:16:0;;;:37;:8;55390:990;-1:-1:-1;;55390:990:0:o;108502:1147::-;108756:13;108735:6;:17;;;:34;;;108731:63;;108778:16;;;;;;;;;;;;;;108731:63;108808:19;;;;:24;;:50;;-1:-1:-1;108836:17:0;;;;:22;108808:50;108804:80;;;108867:17;;;;;;;;;;;;;;108804:80;108898:13;;;;-1:-1:-1;;;;;108898:27:0;;;:54;;-1:-1:-1;108929:9:0;;;;-1:-1:-1;;;;;108929:23:0;;108898:54;108894:80;;;108961:13;;;;;;;;;;;;;;108894:80;108988:18;;;;-1:-1:-1;;;;;108988:32:0;;;:66;;-1:-1:-1;109024:16:0;;;;-1:-1:-1;;;;;109024:30:0;;108988:66;108984:92;;;109063:13;;;;;;;;;;;;;;108984:92;109108:37;85058:10;109108:15;:37;:::i;:::-;109090:6;:15;;;:55;109086:86;;;109154:18;;;;;;;;;;;;;;109086:86;85177:11;109215:8;:16;;;:23;:45;109211:81;;;109269:23;;;;;;;;;;;;;;109211:81;109306:18;;;;:23;;;;:63;;-1:-1:-1;109333:16:0;;;;-1:-1:-1;;;;;109333:36:0;78736:42;109333:36;109306:63;109302:124;;;109392:23;;;;;;;;;;;;;;109302:124;109532:1;109511:18;:22;:70;;;;109565:6;:15;;;109537:18;:44;109511:70;109507:136;;;109604:28;;;;;;;;;;;;;;105250:1187;105330:19;105365:25;-1:-1:-1;;;;;105365:25:0;;;105361:1070;;105595:9;105585:6;:19;105581:51;;105613:19;;;;;;;;;;;;;;105581:51;-1:-1:-1;105660:9:0;105361:1070;;;105900:9;:14;105896:46;;105923:19;;;;;;;;;;;;;;105896:46;106048:5;-1:-1:-1;;;;;106048:17:0;;106069:1;106048:22;106044:53;;106079:18;;;;;;;;;;;;;;106044:53;106223:38;;;;;106255:4;106223:38;;;2867:74:1;-1:-1:-1;;;;;106223:23:0;;;;;2840:18:1;;106223:38:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;106209:52;-1:-1:-1;106275:65:0;-1:-1:-1;;;;;106275:30:0;;106306:10;106326:4;106333:6;106275:30;:65::i;:::-;106368:38;;;;;106400:4;106368:38;;;2867:74:1;106409:11:0;;-1:-1:-1;;;;;106368:23:0;;;;;2840:18:1;;106368:38:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;:52;;;;:::i;54104:1038::-;54374:22;;54410:20;;;;;54444:21;;;;;54196:12;54479:22;;;;54515:20;;;;54549:18;;;;54581:21;;;;54323:289;;29378:16:1;54323:289:0;;;29362:102:1;;;;29483:66;29586:3;29582:16;;;29578:25;;29565:11;;;29558:46;29637:16;;;;29633:25;;;29620:11;;;29613:46;29678:66;29778:15;;;29774:24;;29760:12;;;29753:46;29833:15;;29829:24;;29815:12;;;29808:46;29888:15;;;29884:24;;29870:12;;;29863:46;29943:15;;;29939:24;;;29925:12;;;29918:46;29980:12;;;29973:28;;;;54298:22:0;;30017:13:1;;54323:289:0;;;-1:-1:-1;;54323:289:0;;;;;;;;;;54682:19;;;;54715:24;;;;54860:17;;;;54891:14;;;;54961:27;;;;55002;;;;55077:18;;;;55109:16;;;;54323:289;;-1:-1:-1;54629:506:0;;54323:289;;55109:16;54323:289;54629:506;;:::i;:::-;;;;;;;;;;;;;54622:513;;;54104:1038;;;:::o;36861:156::-;36935:7;36985:22;36989:3;37001:5;36985:3;:22::i;36404:115::-;36467:7;36493:19;36501:3;31843:18;;31761:107;71488:197;70987:4;71010:12;;;;;;;;;;;-1:-1:-1;;;;;71010:29:0;;;;;;;;;;;;71571:108;;71621:47;;;;;-1:-1:-1;;;;;20839:55:1;;71621:47:0;;;20821:74:1;20911:18;;;20904:34;;;20794:18;;71621:47:0;20647:297:1;66494:629:0;66913:23;66939:33;-1:-1:-1;;;;;66939:27:0;;66967:4;66939:27;:33::i;:::-;66913:59;;66986:10;:17;67007:1;66986:22;;:57;;;;;67024:10;67013:30;;;;;;;;;;;;:::i;:::-;67012:31;66986:57;66982:135;;;67066:40;;;;;-1:-1:-1;;;;;2885:55:1;;67066:40:0;;;2867:74:1;2840:18;;67066:40:0;2721:226:1;74235:316:0;74312:4;71010:12;;;;;;;;;;;-1:-1:-1;;;;;71010:29:0;;;;;;;;;;;;74328:217;;74371:6;:12;;;;;;;;;;;-1:-1:-1;;;;;74371:29:0;;;;;;;;;:36;;;;74403:4;74371:36;;;74453:12;26158:10;;26079:96;74453:12;-1:-1:-1;;;;;74426:40:0;74444:7;-1:-1:-1;;;;;74426:40:0;74438:4;74426:40;;;;;;;;;;-1:-1:-1;74487:4:0;74480:11;;74328:217;-1:-1:-1;74529:5:0;74522:12;;35603:150;35673:4;35696:50;35701:3;-1:-1:-1;;;;;35721:23:0;;35696:4;:50::i;74786:317::-;74864:4;71010:12;;;;;;;;;;;-1:-1:-1;;;;;71010:29:0;;;;;;;;;;;;74880:217;;;74954:5;74922:12;;;;;;;;;;;-1:-1:-1;;;;;74922:29:0;;;;;;;;;;:37;;;;;;74978:40;26158:10;;74922:12;;74978:40;;74954:5;74978:40;-1:-1:-1;75039:4:0;75032:11;;35921:156;35994:4;36017:53;36025:3;-1:-1:-1;;;;;36045:23:0;;36017:7;:53::i;22339:392::-;22438:12;22490:5;22466:21;:29;22462:108;;;22518:41;;;;;22553:4;22518:41;;;2867:74:1;2840:18;;22518:41:0;2721:226:1;22462:108:0;22580:12;22594:23;22621:6;-1:-1:-1;;;;;22621:11:0;22640:5;22647:4;22621:31;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;22579:73;;;;22669:55;22696:6;22704:7;22713:10;22669:26;:55::i;:::-;22662:62;22339:392;-1:-1:-1;;;;;;22339:392:0:o;32210:118::-;32277:7;32303:3;:11;;32315:5;32303:18;;;;;;;;:::i;:::-;;;;;;;;;32296:25;;32210:118;;;;:::o;21864:151::-;21939:12;21970:38;21992:6;22000:4;22006:1;21970:21;:38::i;29528:406::-;29591:4;31647:21;;;:14;;;:21;;;;;;29607:321;;-1:-1:-1;29649:23:0;;;;;;;;:11;:23;;;;;;;;;;;;;29831:18;;29807:21;;;:14;;;:21;;;;;;:42;;;;29863:11;;30102:1368;30168:4;30297:21;;;:14;;;:21;;;;;;30333:13;;30329:1135;;30700:18;30721:12;30732:1;30721:8;:12;:::i;:::-;30767:18;;30700:33;;-1:-1:-1;30747:17:0;;30767:22;;30788:1;;30767:22;:::i;:::-;30747:42;;30822:9;30808:10;:23;30804:378;;30851:17;30871:3;:11;;30883:9;30871:22;;;;;;;;:::i;:::-;;;;;;;;;30851:42;;31018:9;30992:3;:11;;31004:10;30992:23;;;;;;;;:::i;:::-;;;;;;;;;;;;:35;;;;31131:25;;;:14;;;:25;;;;;:36;;;30804:378;31260:17;;:3;;:17;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;31363:3;:14;;:21;31378:5;31363:21;;;;;;;;;;;31356:28;;;31406:4;31399:11;;;;;;;30329:1135;31448:5;31441:12;;;;;23784:582;23928:12;23957:7;23952:408;;23980:19;23988:10;23980:7;:19::i;:::-;23952:408;;;24204:17;;:22;:49;;;;-1:-1:-1;;;;;;24230:18:0;;;:23;24204:49;24200:119;;;24280:24;;;;;-1:-1:-1;;;;;2885:55:1;;24280:24:0;;;2867:74:1;2840:18;;24280:24:0;2721:226:1;24200:119:0;-1:-1:-1;24339:10:0;24332:17;;24902:516;25033:17;;:21;25029:383;;25261:10;25255:17;25317:15;25304:10;25300:2;25296:19;25289:44;25029:383;25384:17;;;;;;;;;;;;;;14:332:1;72:6;125:2;113:9;104:7;100:23;96:32;93:52;;;141:1;138;131:12;93:52;180:9;167:23;230:66;223:5;219:78;212:5;209:89;199:117;;312:1;309;302:12;821:180;880:6;933:2;921:9;912:7;908:23;904:32;901:52;;;949:1;946;939:12;901:52;-1:-1:-1;972:23:1;;821:180;-1:-1:-1;821:180:1:o;1006:184::-;1058:77;1055:1;1048:88;1155:4;1152:1;1145:15;1179:4;1176:1;1169:15;1195:297;1279:1;1272:5;1269:12;1259:200;;1315:77;1312:1;1305:88;1416:4;1413:1;1406:15;1444:4;1441:1;1434:15;1259:200;1468:18;;1195:297::o;1497:214::-;1646:2;1631:18;;1658:47;1635:9;1687:6;1658:47;:::i;1716:154::-;-1:-1:-1;;;;;1795:5:1;1791:54;1784:5;1781:65;1771:93;;1860:1;1857;1850:12;1875:134;1943:20;;1972:31;1943:20;1972:31;:::i;:::-;1875:134;;;:::o;2014:388::-;2082:6;2090;2143:2;2131:9;2122:7;2118:23;2114:32;2111:52;;;2159:1;2156;2149:12;2111:52;2198:9;2185:23;2217:31;2242:5;2217:31;:::i;:::-;2267:5;-1:-1:-1;2324:2:1;2309:18;;2296:32;2337:33;2296:32;2337:33;:::i;:::-;2389:7;2379:17;;;2014:388;;;;;:::o;3137:247::-;3196:6;3249:2;3237:9;3228:7;3224:23;3220:32;3217:52;;;3265:1;3262;3255:12;3217:52;3304:9;3291:23;3323:31;3348:5;3323:31;:::i;3389:315::-;3457:6;3465;3518:2;3506:9;3497:7;3493:23;3489:32;3486:52;;;3534:1;3531;3524:12;3486:52;3570:9;3557:23;3547:33;;3630:2;3619:9;3615:18;3602:32;3643:31;3668:5;3643:31;:::i;3709:118::-;3795:5;3788:13;3781:21;3774:5;3771:32;3761:60;;3817:1;3814;3807:12;3832:128;3897:20;;3926:28;3897:20;3926:28;:::i;3965:761::-;4068:6;4076;4084;4137:2;4125:9;4116:7;4112:23;4108:32;4105:52;;;4153:1;4150;4143:12;4105:52;4193:9;4180:23;4222:18;4263:2;4255:6;4252:14;4249:34;;;4279:1;4276;4269:12;4249:34;4317:6;4306:9;4302:22;4292:32;;4362:7;4355:4;4351:2;4347:13;4343:27;4333:55;;4384:1;4381;4374:12;4333:55;4424:2;4411:16;4450:2;4442:6;4439:14;4436:34;;;4466:1;4463;4456:12;4436:34;4521:7;4514:4;4504:6;4501:1;4497:14;4493:2;4489:23;4485:34;4482:47;4479:67;;;4542:1;4539;4532:12;4479:67;4573:4;4565:13;;;;-1:-1:-1;4597:6:1;-1:-1:-1;;4638:20:1;;4625:34;4668:28;4625:34;4668:28;:::i;:::-;4715:5;4705:15;;;3965:761;;;;;:::o;4731:250::-;4816:1;4826:113;4840:6;4837:1;4834:13;4826:113;;;4916:11;;;4910:18;4897:11;;;4890:39;4862:2;4855:10;4826:113;;;-1:-1:-1;;4973:1:1;4955:16;;4948:27;4731:250::o;4986:329::-;5027:3;5065:5;5059:12;5092:6;5087:3;5080:19;5108:76;5177:6;5170:4;5165:3;5161:14;5154:4;5147:5;5143:16;5108:76;:::i;:::-;5229:2;5217:15;-1:-1:-1;;5213:88:1;5204:98;;;;5304:4;5200:109;;4986:329;-1:-1:-1;;4986:329:1:o;5320:1097::-;5508:4;5537:2;5577;5566:9;5562:18;5607:2;5596:9;5589:21;5630:6;5665;5659:13;5696:6;5688;5681:22;5722:2;5712:12;;5755:2;5744:9;5740:18;5733:25;;5817:2;5807:6;5804:1;5800:14;5789:9;5785:30;5781:39;5855:2;5847:6;5843:15;5876:1;5886:502;5900:6;5897:1;5894:13;5886:502;;;5965:22;;;5989:66;5961:95;5949:108;;6080:13;;6135:9;;6128:17;6121:25;6106:41;;6186:11;;6180:18;6218:15;;;6211:27;;;6261:47;6292:15;;;6180:18;6261:47;:::i;:::-;6366:12;;;;6251:57;-1:-1:-1;;6331:15:1;;;;5922:1;5915:9;5886:502;;;-1:-1:-1;6405:6:1;;5320:1097;-1:-1:-1;;;;;;;;5320:1097:1:o;6422:347::-;6473:8;6483:6;6537:3;6530:4;6522:6;6518:17;6514:27;6504:55;;6555:1;6552;6545:12;6504:55;-1:-1:-1;6578:20:1;;6621:18;6610:30;;6607:50;;;6653:1;6650;6643:12;6607:50;6690:4;6682:6;6678:17;6666:29;;6742:3;6735:4;6726:6;6718;6714:19;6710:30;6707:39;6704:59;;;6759:1;6756;6749:12;6704:59;6422:347;;;;;:::o;6774:544::-;6853:6;6861;6869;6922:2;6910:9;6901:7;6897:23;6893:32;6890:52;;;6938:1;6935;6928:12;6890:52;6978:9;6965:23;7011:18;7003:6;7000:30;6997:50;;;7043:1;7040;7033:12;6997:50;7082:58;7132:7;7123:6;7112:9;7108:22;7082:58;:::i;:::-;7159:8;;-1:-1:-1;7056:84:1;-1:-1:-1;;7244:2:1;7229:18;;7216:32;7257:31;7216:32;7257:31;:::i;7323:383::-;7400:6;7408;7416;7469:2;7457:9;7448:7;7444:23;7440:32;7437:52;;;7485:1;7482;7475:12;7437:52;7521:9;7508:23;7498:33;;7578:2;7567:9;7563:18;7550:32;7540:42;;7632:2;7621:9;7617:18;7604:32;7645:31;7670:5;7645:31;:::i;7711:184::-;7763:77;7760:1;7753:88;7860:4;7857:1;7850:15;7884:4;7881:1;7874:15;7900:255;7972:2;7966:9;8014:6;8002:19;;8051:18;8036:34;;8072:22;;;8033:62;8030:88;;;8098:18;;:::i;:::-;8134:2;8127:22;7900:255;:::o;8160:253::-;8232:2;8226:9;8274:4;8262:17;;8309:18;8294:34;;8330:22;;;8291:62;8288:88;;;8356:18;;:::i;8418:255::-;8490:2;8484:9;8532:6;8520:19;;8569:18;8554:34;;8590:22;;;8551:62;8548:88;;;8616:18;;:::i;8678:252::-;8750:2;8744:9;8792:3;8780:16;;8826:18;8811:34;;8847:22;;;8808:62;8805:88;;;8873:18;;:::i;8935:334::-;9006:2;9000:9;9062:2;9052:13;;-1:-1:-1;;9048:86:1;9036:99;;9165:18;9150:34;;9186:22;;;9147:62;9144:88;;;9212:18;;:::i;:::-;9248:2;9241:22;8935:334;;-1:-1:-1;8935:334:1:o;9274:121::-;9359:10;9352:5;9348:22;9341:5;9338:33;9328:61;;9385:1;9382;9375:12;9400:132;9467:20;;9496:30;9467:20;9496:30;:::i;9537:806::-;9596:5;9644:6;9632:9;9627:3;9623:19;9619:32;9616:52;;;9664:1;9661;9654:12;9616:52;9686:22;;:::i;:::-;9677:31;;9731:28;9749:9;9731:28;:::i;:::-;9724:5;9717:43;9792:38;9826:2;9815:9;9811:18;9792:38;:::i;:::-;9787:2;9780:5;9776:14;9769:62;9863:38;9897:2;9886:9;9882:18;9863:38;:::i;:::-;9858:2;9851:5;9847:14;9840:62;9934:38;9968:2;9957:9;9953:18;9934:38;:::i;:::-;9929:2;9922:5;9918:14;9911:62;10006:39;10040:3;10029:9;10025:19;10006:39;:::i;:::-;10000:3;9993:5;9989:15;9982:64;10107:3;10096:9;10092:19;10079:33;10073:3;10066:5;10062:15;10055:58;10174:3;10163:9;10159:19;10146:33;10140:3;10133:5;10129:15;10122:58;10213:36;10244:3;10233:9;10229:19;10213:36;:::i;:::-;10207:3;10200:5;10196:15;10189:61;10269:3;10332:2;10321:9;10317:18;10304:32;10299:2;10292:5;10288:14;10281:56;;9537:806;;;;:::o;10348:237::-;10436:6;10489:3;10477:9;10468:7;10464:23;10460:33;10457:53;;;10506:1;10503;10496:12;10457:53;10529:50;10571:7;10560:9;10529:50;:::i;10590:409::-;10660:6;10668;10721:2;10709:9;10700:7;10696:23;10692:32;10689:52;;;10737:1;10734;10727:12;10689:52;10777:9;10764:23;10810:18;10802:6;10799:30;10796:50;;;10842:1;10839;10832:12;10796:50;10881:58;10931:7;10922:6;10911:9;10907:22;10881:58;:::i;:::-;10958:8;;10855:84;;-1:-1:-1;10590:409:1;-1:-1:-1;;;;10590:409:1:o;11103:1865::-;11306:2;11295:9;11288:21;11318:52;11366:2;11355:9;11351:18;11342:6;11336:13;11080:10;11069:22;11057:35;;11004:94;11318:52;11269:4;11417:2;11409:6;11405:15;11399:22;11430:51;11477:2;11466:9;11462:18;11448:12;11080:10;11069:22;11057:35;;11004:94;11430:51;-1:-1:-1;11530:2:1;11518:15;;11512:22;-1:-1:-1;;;;;2655:54:1;;11593:2;11578:18;;2643:67;-1:-1:-1;11646:2:1;11634:15;;11628:22;-1:-1:-1;;;;;2655:54:1;;11709:3;11694:19;;2643:67;-1:-1:-1;11763:3:1;11751:16;;11745:23;-1:-1:-1;;;;;2655:54:1;;11827:3;11812:19;;2643:67;-1:-1:-1;11881:3:1;11869:16;;11863:23;-1:-1:-1;;;;;2655:54:1;;11945:3;11930:19;;2643:67;-1:-1:-1;12005:3:1;11993:16;;11987:23;11981:3;11966:19;;;11959:52;;;;12036:16;;12030:23;12072:3;12091:18;;;12084:30;;;;12139:15;;12133:22;12174:3;12193:18;;;12186:30;;;;12241:15;;12235:22;12276:3;12295:18;;;12288:30;;;;12343:15;;12337:22;12378:3;12397:18;;;12390:30;;;;12457:15;;12451:22;12492:3;12504:54;12539:18;;;12451:22;-1:-1:-1;;;;;2655:54:1;2643:67;;2589:127;12504:54;12584:15;;12578:22;12620:3;12639:19;;;12632:32;;;;12690:16;;12684:23;12727:3;12746:19;;;12739:32;;;;12808:16;;12802:23;12845:6;12867:19;;;12860:32;12802:23;-1:-1:-1;12909:53:1;12957:3;12942:19;;12802:23;12909:53;:::i;:::-;12901:61;11103:1865;-1:-1:-1;;;;11103:1865:1:o;12973:513::-;13202:3;13187:19;;13215:47;13191:9;13244:6;13215:47;:::i;:::-;13310:10;13302:6;13298:23;13293:2;13282:9;13278:18;13271:51;13370:16;13362:6;13358:29;13353:2;13342:9;13338:18;13331:57;-1:-1:-1;;;;;13428:6:1;13424:55;13419:2;13408:9;13404:18;13397:83;12973:513;;;;;;;:::o;13491:245::-;13539:4;13572:18;13564:6;13561:30;13558:56;;;13594:18;;:::i;:::-;-1:-1:-1;13651:2:1;13639:15;-1:-1:-1;;13635:88:1;13725:4;13631:99;;13491:245::o;13741:462::-;13783:5;13836:3;13829:4;13821:6;13817:17;13813:27;13803:55;;13854:1;13851;13844:12;13803:55;13890:6;13877:20;13921:48;13937:31;13965:2;13937:31;:::i;:::-;13921:48;:::i;:::-;13994:2;13985:7;13978:19;14040:3;14033:4;14028:2;14020:6;14016:15;14012:26;14009:35;14006:55;;;14057:1;14054;14047:12;14006:55;14122:2;14115:4;14107:6;14103:17;14096:4;14087:7;14083:18;14070:55;14170:1;14145:16;;;14163:4;14141:27;14134:38;;;;14149:7;13741:462;-1:-1:-1;;;13741:462:1:o;14208:1162::-;14337:6;14345;14398:3;14386:9;14377:7;14373:23;14369:33;14366:53;;;14415:1;14412;14405:12;14366:53;14438:50;14480:7;14469:9;14438:50;:::i;:::-;14428:60;;14539:3;14528:9;14524:19;14511:33;14563:18;14604:2;14596:6;14593:14;14590:34;;;14620:1;14617;14610:12;14590:34;14643:22;;;;14699:4;14681:16;;;14677:27;14674:47;;;14717:1;14714;14707:12;14674:47;14743:22;;:::i;:::-;14802:2;14789:16;14814:33;14839:7;14814:33;:::i;:::-;14856:22;;14931:2;14923:11;;;14910:25;14894:14;;;14887:49;14982:2;14974:11;;14961:25;14998:16;;;14995:36;;;15027:1;15024;15017:12;14995:36;15063:44;15099:7;15088:8;15084:2;15080:17;15063:44;:::i;:::-;15058:2;15051:5;15047:14;15040:68;;15161:2;15157;15153:11;15140:25;15135:2;15128:5;15124:14;15117:49;15212:3;15208:2;15204:12;15191:26;15242:2;15232:8;15229:16;15226:36;;;15258:1;15255;15248:12;15226:36;15295:44;15331:7;15320:8;15316:2;15312:17;15295:44;:::i;:::-;15289:3;15282:5;15278:15;15271:69;;15359:5;15349:15;;;;;14208:1162;;;;;:::o;15375:477::-;15454:6;15462;15470;15523:2;15511:9;15502:7;15498:23;15494:32;15491:52;;;15539:1;15536;15529:12;15491:52;15579:9;15566:23;15612:18;15604:6;15601:30;15598:50;;;15644:1;15641;15634:12;15598:50;15683:58;15733:7;15724:6;15713:9;15709:22;15683:58;:::i;:::-;15760:8;;15657:84;;-1:-1:-1;15842:2:1;15827:18;;;;15814:32;;15375:477;-1:-1:-1;;;;15375:477:1:o;15857:248::-;15925:6;15933;15986:2;15974:9;15965:7;15961:23;15957:32;15954:52;;;16002:1;15999;15992:12;15954:52;-1:-1:-1;;16025:23:1;;;16095:2;16080:18;;;16067:32;;-1:-1:-1;15857:248:1:o;16443:1373::-;16674:13;;11080:10;11069:22;11057:35;;16643:3;16628:19;;16746:4;16738:6;16734:17;16728:24;16761:53;16808:4;16797:9;16793:20;16779:12;11080:10;11069:22;11057:35;;11004:94;16761:53;;16863:4;16855:6;16851:17;16845:24;16878:56;16928:4;16917:9;16913:20;16897:14;-1:-1:-1;;;;;2655:54:1;2643:67;;2589:127;16878:56;;16983:4;16975:6;16971:17;16965:24;16998:56;17048:4;17037:9;17033:20;17017:14;-1:-1:-1;;;;;2655:54:1;2643:67;;2589:127;16998:56;;17103:4;17095:6;17091:17;17085:24;17118:56;17168:4;17157:9;17153:20;17137:14;-1:-1:-1;;;;;2655:54:1;2643:67;;2589:127;17118:56;;17223:4;17215:6;17211:17;17205:24;17238:56;17288:4;17277:9;17273:20;17257:14;-1:-1:-1;;;;;2655:54:1;2643:67;;2589:127;17238:56;;17350:4;17342:6;17338:17;17332:24;17325:4;17314:9;17310:20;17303:54;17413:4;17405:6;17401:17;17395:24;17388:4;17377:9;17373:20;17366:54;17439:6;17499:2;17491:6;17487:15;17481:22;17476:2;17465:9;17461:18;17454:50;;17523:6;17578:2;17570:6;17566:15;17560:22;17591:51;17638:2;17627:9;17623:18;17607:14;421:13;414:21;402:34;;351:91;17591:51;-1:-1:-1;;17661:6:1;17709:15;;;17703:22;17683:18;;;17676:50;17745:6;17793:15;;;17787:22;17767:18;;;;17760:50;;;;16443:1373;:::o;18644:184::-;18696:77;18693:1;18686:88;18793:4;18790:1;18783:15;18817:4;18814:1;18807:15;18833:580;18910:4;18916:6;18976:11;18963:25;19066:66;19055:8;19039:14;19035:29;19031:102;19011:18;19007:127;18997:155;;19148:1;19145;19138:12;18997:155;19175:33;;19227:20;;;-1:-1:-1;19270:18:1;19259:30;;19256:50;;;19302:1;19299;19292:12;19256:50;19335:4;19323:17;;-1:-1:-1;19366:14:1;19362:27;;;19352:38;;19349:58;;;19403:1;19400;19393:12;19418:271;19601:6;19593;19588:3;19575:33;19557:3;19627:16;;19652:13;;;19627:16;19418:271;-1:-1:-1;19418:271:1:o;20328:184::-;20380:77;20377:1;20370:88;20477:4;20474:1;20467:15;20501:4;20498:1;20491:15;20517:125;20582:9;;;20603:10;;;20600:36;;;20616:18;;:::i;20949:216::-;21013:9;;;21041:11;;;20988:3;21071:9;;21099:10;;21095:19;;21124:10;;21116:19;;21092:44;21089:70;;;21139:18;;:::i;:::-;21089:70;;20949:216;;;;:::o;21170:168::-;21243:9;;;21274;;21291:15;;;21285:22;;21271:37;21261:71;;21312:18;;:::i;21343:274::-;21383:1;21409;21399:189;;21444:77;21441:1;21434:88;21545:4;21542:1;21535:15;21573:4;21570:1;21563:15;21399:189;-1:-1:-1;21602:9:1;;21343:274::o;21622:128::-;21689:9;;;21710:11;;;21707:37;;;21724:18;;:::i;21755:195::-;21794:3;21825:66;21818:5;21815:77;21812:103;;21895:18;;:::i;:::-;-1:-1:-1;21942:1:1;21931:13;;21755:195::o;21955:752::-;22262:3;22251:9;22244:22;22225:4;22283:45;22323:3;22312:9;22308:19;22300:6;22283:45;:::i;:::-;22376:10;22364:23;;;;22359:2;22344:18;;22337:51;-1:-1:-1;;;;;;22485:15:1;;;22480:2;22465:18;;22458:43;22537:15;;;;22532:2;22517:18;;22510:43;22584:3;22569:19;;22562:35;;;;22628:3;22613:19;;22606:35;22685:14;;22678:22;22672:3;22657:19;;;22650:51;22275:53;21955:752;-1:-1:-1;21955:752:1:o;22712:217::-;22859:2;22848:9;22841:21;22822:4;22879:44;22919:2;22908:9;22904:18;22896:6;22879:44;:::i;22934:325::-;23022:6;23017:3;23010:19;23074:6;23067:5;23060:4;23055:3;23051:14;23038:43;;23126:1;23119:4;23110:6;23105:3;23101:16;23097:27;23090:38;22992:3;23248:4;-1:-1:-1;;23173:2:1;23165:6;23161:15;23157:88;23152:3;23148:98;23144:109;23137:116;;22934:325;;;;:::o;23264:244::-;23421:2;23410:9;23403:21;23384:4;23441:61;23498:2;23487:9;23483:18;23475:6;23467;23441:61;:::i;23513:136::-;23591:13;;23613:30;23591:13;23613:30;:::i;23654:138::-;23733:13;;23755:31;23733:13;23755:31;:::i;23797:441::-;23850:5;23903:3;23896:4;23888:6;23884:17;23880:27;23870:55;;23921:1;23918;23911:12;23870:55;23950:6;23944:13;23981:48;23997:31;24025:2;23997:31;:::i;23981:48::-;24054:2;24045:7;24038:19;24100:3;24093:4;24088:2;24080:6;24076:15;24072:26;24069:35;24066:55;;;24117:1;24114;24107:12;24066:55;24130:77;24204:2;24197:4;24188:7;24184:18;24177:4;24169:6;24165:17;24130:77;:::i;24243:1672::-;24350:6;24403:2;24391:9;24382:7;24378:23;24374:32;24371:52;;;24419:1;24416;24409:12;24371:52;24452:9;24446:16;24481:18;24522:2;24514:6;24511:14;24508:34;;;24538:1;24535;24528:12;24508:34;24561:22;;;;24617:6;24599:16;;;24595:29;24592:49;;;24637:1;24634;24627:12;24592:49;24663:22;;:::i;:::-;24708:32;24737:2;24708:32;:::i;:::-;24701:5;24694:47;24773:41;24810:2;24806;24802:11;24773:41;:::i;:::-;24768:2;24761:5;24757:14;24750:65;24847:42;24885:2;24881;24877:11;24847:42;:::i;:::-;24842:2;24835:5;24831:14;24824:66;24922:42;24960:2;24956;24952:11;24922:42;:::i;:::-;24917:2;24910:5;24906:14;24899:66;24998:43;25036:3;25032:2;25028:12;24998:43;:::i;:::-;24992:3;24985:5;24981:15;24974:68;25075:43;25113:3;25109:2;25105:12;25075:43;:::i;:::-;25069:3;25058:15;;25051:68;25166:3;25158:12;;;25152:19;25135:15;;;25128:44;25219:3;25211:12;;;25205:19;25188:15;;;25181:44;25244:3;25285:11;;;25279:18;25263:14;;;25256:42;25317:3;25358:11;;;25352:18;25336:14;;;25329:42;25390:3;25431:11;;;25425:18;25409:14;;;25402:42;25463:3;25498:42;25528:11;;;25498:42;:::i;:::-;25482:14;;;25475:66;25560:3;25601:11;;;25595:18;25579:14;;;25572:42;25633:3;25674:11;;;25668:18;25652:14;;;25645:42;25706:3;25740:11;;;25734:18;25764:16;;;25761:36;;;25793:1;25790;25783:12;25761:36;25829:55;25876:7;25865:8;25861:2;25857:17;25829:55;:::i;:::-;25813:14;;;25806:79;;;;-1:-1:-1;25817:5:1;24243:1672;-1:-1:-1;;;;;24243:1672:1:o;25920:1135::-;26012:6;26065:3;26053:9;26044:7;26040:23;26036:33;26033:53;;;26082:1;26079;26072:12;26033:53;26108:22;;:::i;:::-;26153:28;26171:9;26153:28;:::i;:::-;26146:5;26139:43;26214:37;26247:2;26236:9;26232:18;26214:37;:::i;:::-;26209:2;26202:5;26198:14;26191:61;26284:38;26318:2;26307:9;26303:18;26284:38;:::i;:::-;26279:2;26272:5;26268:14;26261:62;26355:38;26389:2;26378:9;26374:18;26355:38;:::i;:::-;26350:2;26343:5;26339:14;26332:62;26427:39;26461:3;26450:9;26446:19;26427:39;:::i;:::-;26421:3;26414:5;26410:15;26403:64;26500:39;26534:3;26523:9;26519:19;26500:39;:::i;:::-;26494:3;26487:5;26483:15;26476:64;26601:3;26590:9;26586:19;26573:33;26567:3;26560:5;26556:15;26549:58;26668:3;26657:9;26653:19;26640:33;26634:3;26627:5;26623:15;26616:58;26693:3;26756:2;26745:9;26741:18;26728:32;26723:2;26716:5;26712:14;26705:56;;26780:3;26815:35;26846:2;26835:9;26831:18;26815:35;:::i;:::-;26799:14;;;26792:59;26870:3;26918:18;;;26905:32;26889:14;;;26882:56;26957:3;27005:18;;;26992:32;26976:14;;;26969:56;;;;-1:-1:-1;26803:5:1;25920:1135;-1:-1:-1;25920:1135:1:o;27716:331::-;27821:9;27832;27874:8;27862:10;27859:24;27856:44;;;27896:1;27893;27886:12;27856:44;27925:6;27915:8;27912:20;27909:40;;;27945:1;27942;27935:12;27909:40;-1:-1:-1;;27971:23:1;;;28016:25;;;;;-1:-1:-1;27716:331:1:o;28052:435::-;-1:-1:-1;;;;;28269:6:1;28265:55;28254:9;28247:74;28357:6;28352:2;28341:9;28337:18;28330:34;28400:2;28395;28384:9;28380:18;28373:30;28228:4;28420:61;28477:2;28466:9;28462:18;28454:6;28446;28420:61;:::i;28492:357::-;28610:12;;28657:4;28646:16;;;28640:23;;28610:12;28675:16;;28672:171;;;28765:66;28755:6;28749:4;28745:17;28742:1;28738:25;28734:98;28727:5;28723:110;28714:119;;28672:171;;28492:357;;;:::o;28854:184::-;28924:6;28977:2;28965:9;28956:7;28952:23;28948:32;28945:52;;;28993:1;28990;28983:12;28945:52;-1:-1:-1;29016:16:1;;28854:184;-1:-1:-1;28854:184:1:o;30041:1059::-;30412:3;30450:6;30444:13;30466:66;30525:6;30520:3;30513:4;30505:6;30501:17;30466:66;:::i;:::-;30563:6;30558:3;30554:16;30541:29;;30593:6;30586:5;30579:21;30634:6;30627:4;30620:5;30616:16;30609:32;30673:6;30668:2;30661:5;30657:14;30650:30;30712:6;30707:2;30700:5;30696:14;30689:30;30773:66;30764:6;30760:2;30756:15;30752:88;30746:3;30739:5;30735:15;30728:113;30874:6;30868:3;30861:5;30857:15;30850:31;30914:6;30908:3;30901:5;30897:15;30890:31;30952:6;30946:13;30968:80;31039:8;31033:3;31026:5;31022:15;31015:4;31007:6;31003:17;30968:80;:::i;:::-;31068:20;31090:3;31064:30;;30041:1059;-1:-1:-1;;;;;;;;;;;30041:1059:1:o;31407:245::-;31474:6;31527:2;31515:9;31506:7;31502:23;31498:32;31495:52;;;31543:1;31540;31533:12;31495:52;31575:9;31569:16;31594:28;31616:5;31594:28;:::i;31657:287::-;31786:3;31824:6;31818:13;31840:66;31899:6;31894:3;31887:4;31879:6;31875:17;31840:66;:::i;:::-;31922:16;;;;;31657:287;-1:-1:-1;;31657:287:1:o;31949:184::-;32001:77;31998:1;31991:88;32098:4;32095:1;32088:15;32122:4;32119:1;32112:15","abiDefinition":[{"inputs":[{"internalType":"address","name":"defaultAdmin","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AccessControlBadConfirmation","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"bytes32","name":"neededRole","type":"bytes32"}],"name":"AccessControlUnauthorizedAccount","type":"error"},{"inputs":[{"internalType":"address","name":"target","type":"address"}],"name":"AddressEmptyCode","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"AddressInsufficientBalance","type":"error"},{"inputs":[],"name":"AmountIncorrect","type":"error"},{"inputs":[],"name":"BridgeTransactionV2__InvalidEncodedTx","type":"error"},{"inputs":[{"internalType":"uint16","name":"version","type":"uint16"}],"name":"BridgeTransactionV2__UnsupportedVersion","type":"error"},{"inputs":[],"name":"CancelDelayBelowMin","type":"error"},{"inputs":[],"name":"ChainIncorrect","type":"error"},{"inputs":[],"name":"DeadlineExceeded","type":"error"},{"inputs":[],"name":"DeadlineNotExceeded","type":"error"},{"inputs":[],"name":"DeadlineTooShort","type":"error"},{"inputs":[],"name":"DisputePeriodNotPassed","type":"error"},{"inputs":[],"name":"DisputePeriodPassed","type":"error"},{"inputs":[],"name":"ExclusivityParamsIncorrect","type":"error"},{"inputs":[],"name":"ExclusivityPeriodNotPassed","type":"error"},{"inputs":[],"name":"FailedInnerCall","type":"error"},{"inputs":[],"name":"FeeRateAboveMax","type":"error"},{"inputs":[],"name":"MsgValueIncorrect","type":"error"},{"inputs":[],"name":"MulticallTarget__UndeterminedRevert","type":"error"},{"inputs":[],"name":"RecipientIncorrectReturnValue","type":"error"},{"inputs":[],"name":"RecipientNoReturnValue","type":"error"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"SafeERC20FailedOperation","type":"error"},{"inputs":[],"name":"SenderIncorrect","type":"error"},{"inputs":[],"name":"StatusIncorrect","type":"error"},{"inputs":[],"name":"TokenNotContract","type":"error"},{"inputs":[],"name":"TransactionRelayed","type":"error"},{"inputs":[],"name":"ZapDataLengthAboveMax","type":"error"},{"inputs":[],"name":"ZapNativeNotSupported","type":"error"},{"inputs":[],"name":"ZeroAddress","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"relayer","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"BridgeDepositClaimed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"BridgeDepositRefunded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"relayer","type":"address"}],"name":"BridgeProofDisputed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"relayer","type":"address"},{"indexed":false,"internalType":"bytes32","name":"transactionHash","type":"bytes32"}],"name":"BridgeProofProvided","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":false,"internalType":"bytes","name":"quoteId","type":"bytes"}],"name":"BridgeQuoteDetails","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"relayer","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint32","name":"originChainId","type":"uint32"},{"indexed":false,"internalType":"address","name":"originToken","type":"address"},{"indexed":false,"internalType":"address","name":"destToken","type":"address"},{"indexed":false,"internalType":"uint256","name":"originAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"destAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"chainGasAmount","type":"uint256"}],"name":"BridgeRelayed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"bytes","name":"request","type":"bytes"},{"indexed":false,"internalType":"uint32","name":"destChainId","type":"uint32"},{"indexed":false,"internalType":"address","name":"originToken","type":"address"},{"indexed":false,"internalType":"address","name":"destToken","type":"address"},{"indexed":false,"internalType":"uint256","name":"originAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"destAmount","type":"uint256"},{"indexed":false,"internalType":"bool","name":"sendChainGas","type":"bool"}],"name":"BridgeRequested","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldCancelDelay","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newCancelDelay","type":"uint256"}],"name":"CancelDelayUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldFeeRate","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newFeeRate","type":"uint256"}],"name":"FeeRateUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"address","name":"recipient","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"FeesSwept","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"previousAdminRole","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"newAdminRole","type":"bytes32"}],"name":"RoleAdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleRevoked","type":"event"},{"inputs":[],"name":"CANCELER_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"DEFAULT_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"DEFAULT_CANCEL_DELAY","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"DISPUTE_PERIOD","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"FEE_BPS","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"FEE_RATE_MAX","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"GOVERNOR_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"GUARD_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_ZAP_DATA_LENGTH","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MIN_CANCEL_DELAY","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MIN_DEADLINE_PERIOD","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"NATIVE_GAS_TOKEN","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"PROVER_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"QUOTER_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"uint32","name":"dstChainId","type":"uint32"},{"internalType":"address","name":"sender","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"address","name":"originToken","type":"address"},{"internalType":"address","name":"destToken","type":"address"},{"internalType":"uint256","name":"originAmount","type":"uint256"},{"internalType":"uint256","name":"destAmount","type":"uint256"},{"internalType":"bool","name":"sendChainGas","type":"bool"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"internalType":"struct IFastBridge.BridgeParams","name":"params","type":"tuple"}],"name":"bridge","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"transactionId","type":"bytes32"}],"name":"bridgeProofs","outputs":[{"internalType":"uint96","name":"timestamp","type":"uint96"},{"internalType":"address","name":"relayer","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"bridgeRelayDetails","outputs":[{"internalType":"uint48","name":"blockNumber","type":"uint48"},{"internalType":"uint48","name":"blockTimestamp","type":"uint48"},{"internalType":"address","name":"relayer","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"transactionId","type":"bytes32"}],"name":"bridgeRelays","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"transactionId","type":"bytes32"}],"name":"bridgeStatuses","outputs":[{"internalType":"enum IFastBridgeV2.BridgeStatus","name":"status","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"bridgeTxDetails","outputs":[{"internalType":"enum IFastBridgeV2.BridgeStatus","name":"status","type":"uint8"},{"internalType":"uint32","name":"destChainId","type":"uint32"},{"internalType":"uint56","name":"proofBlockTimestamp","type":"uint56"},{"internalType":"address","name":"proofRelayer","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"uint32","name":"dstChainId","type":"uint32"},{"internalType":"address","name":"sender","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"address","name":"originToken","type":"address"},{"internalType":"address","name":"destToken","type":"address"},{"internalType":"uint256","name":"originAmount","type":"uint256"},{"internalType":"uint256","name":"destAmount","type":"uint256"},{"internalType":"bool","name":"sendChainGas","type":"bool"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"internalType":"struct IFastBridge.BridgeParams","name":"params","type":"tuple"},{"components":[{"internalType":"address","name":"quoteRelayer","type":"address"},{"internalType":"int256","name":"quoteExclusivitySeconds","type":"int256"},{"internalType":"bytes","name":"quoteId","type":"bytes"},{"internalType":"uint256","name":"zapNative","type":"uint256"},{"internalType":"bytes","name":"zapData","type":"bytes"}],"internalType":"struct IFastBridgeV2.BridgeParamsV2","name":"paramsV2","type":"tuple"}],"name":"bridgeV2","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"internalType":"address","name":"relayer","type":"address"}],"name":"canClaim","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"cancelDelay","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"}],"name":"cancelV2","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"chainGasAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"},{"internalType":"address","name":"to","type":"address"}],"name":"claim","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"}],"name":"claimV2","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"deployBlock","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"transactionId","type":"bytes32"}],"name":"dispute","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"}],"name":"getBridgeTransaction","outputs":[{"components":[{"internalType":"uint32","name":"originChainId","type":"uint32"},{"internalType":"uint32","name":"destChainId","type":"uint32"},{"internalType":"address","name":"originSender","type":"address"},{"internalType":"address","name":"destRecipient","type":"address"},{"internalType":"address","name":"originToken","type":"address"},{"internalType":"address","name":"destToken","type":"address"},{"internalType":"uint256","name":"originAmount","type":"uint256"},{"internalType":"uint256","name":"destAmount","type":"uint256"},{"internalType":"uint256","name":"originFeeAmount","type":"uint256"},{"internalType":"bool","name":"sendChainGas","type":"bool"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint256","name":"nonce","type":"uint256"}],"internalType":"struct IFastBridge.BridgeTransaction","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"}],"name":"getBridgeTransactionV2","outputs":[{"components":[{"internalType":"uint32","name":"originChainId","type":"uint32"},{"internalType":"uint32","name":"destChainId","type":"uint32"},{"internalType":"address","name":"originSender","type":"address"},{"internalType":"address","name":"destRecipient","type":"address"},{"internalType":"address","name":"originToken","type":"address"},{"internalType":"address","name":"destToken","type":"address"},{"internalType":"uint256","name":"originAmount","type":"uint256"},{"internalType":"uint256","name":"destAmount","type":"uint256"},{"internalType":"uint256","name":"originFeeAmount","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"address","name":"exclusivityRelayer","type":"address"},{"internalType":"uint256","name":"exclusivityEndTime","type":"uint256"},{"internalType":"uint256","name":"zapNative","type":"uint256"},{"internalType":"bytes","name":"zapData","type":"bytes"}],"internalType":"struct IFastBridgeV2.BridgeTransactionV2","name":"","type":"tuple"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleAdmin","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"uint256","name":"index","type":"uint256"}],"name":"getRoleMember","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleMemberCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"grantRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"hasRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes[]","name":"data","type":"bytes[]"},{"internalType":"bool","name":"ignoreReverts","type":"bool"}],"name":"multicallNoResults","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes[]","name":"data","type":"bytes[]"},{"internalType":"bool","name":"ignoreReverts","type":"bool"}],"name":"multicallWithResults","outputs":[{"components":[{"internalType":"bool","name":"success","type":"bool"},{"internalType":"bytes","name":"returnData","type":"bytes"}],"internalType":"struct IMulticallTarget.Result[]","name":"results","type":"tuple[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"nonce","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"protocolFeeRate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"protocolFees","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"},{"internalType":"bytes32","name":"destTxHash","type":"bytes32"}],"name":"prove","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"internalType":"bytes32","name":"destTxHash","type":"bytes32"},{"internalType":"address","name":"relayer","type":"address"}],"name":"proveV2","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"}],"name":"refund","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"}],"name":"relay","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"},{"internalType":"address","name":"relayer","type":"address"}],"name":"relayV2","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"callerConfirmation","type":"address"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"revokeRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"senderNonces","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"newCancelDelay","type":"uint256"}],"name":"setCancelDelay","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"newFeeRate","type":"uint256"}],"name":"setProtocolFeeRate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"address","name":"recipient","type":"address"}],"name":"sweepProtocolFees","outputs":[],"stateMutability":"nonpayable","type":"function"}],"userDoc":{"kind":"user","methods":{"CANCELER_ROLE()":{"notice":"The role identifier for the Canceler's on-chain authentication in FastBridge."},"DEFAULT_CANCEL_DELAY()":{"notice":"The default cancel delay set during contract deployment."},"DISPUTE_PERIOD()":{"notice":"The duration of the dispute period for relayed transactions."},"FEE_BPS()":{"notice":"The denominator for fee rates, representing 100%."},"FEE_RATE_MAX()":{"notice":"The maximum protocol fee rate: 1% of the origin amount."},"GOVERNOR_ROLE()":{"notice":"The role identifier for the Governor's on-chain administrative authority."},"GUARD_ROLE()":{"notice":"The role identifier for the Guard's on-chain authentication in FastBridge."},"MAX_ZAP_DATA_LENGTH()":{"notice":"The maximum allowed length for zapData."},"MIN_CANCEL_DELAY()":{"notice":"The minimum cancel delay that can be set by the governor."},"MIN_DEADLINE_PERIOD()":{"notice":"The minimum required time between transaction request and deadline."},"NATIVE_GAS_TOKEN()":{"notice":"The address reserved for the native gas token (ETH on Ethereum and most L2s, AVAX on Avalanche, etc.)."},"PROVER_ROLE()":{"notice":"The role identifier for the Prover's on-chain authentication in FastBridge."},"QUOTER_ROLE()":{"notice":"The role identifier for the Quoter API's off-chain authentication."},"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256))":{"notice":"Initiates bridge on origin chain to be relayed by off-chain relayer"},"bridgeProofs(bytes32)":{"notice":"Returns the timestamp and relayer of a bridge proof"},"bridgeRelayDetails(bytes32)":{"notice":"Maps transaction IDs to relay details (block number, block timestamp, and relayer). Note: this is only stored for transactions having local chain as the destination chain."},"bridgeRelays(bytes32)":{"notice":"Checks if a transaction has been relayed"},"bridgeStatuses(bytes32)":{"notice":"Returns the status of a bridge transaction"},"bridgeTxDetails(bytes32)":{"notice":"Maps transaction IDs to bridge details (status, destination chain ID, proof timestamp, and relayer). Note: this is only stored for transactions having local chain as the origin chain."},"bridgeV2((uint32,address,address,address,address,uint256,uint256,bool,uint256),(address,int256,bytes,uint256,bytes))":{"notice":"Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability to provide temporary exclusivity fill rights for the quote relayer."},"canClaim(bytes32,address)":{"notice":"Checks if the dispute period has passed so bridge deposit can be claimed"},"cancelDelay()":{"notice":"The delay period after which a transaction can be permissionlessly cancelled."},"cancelV2(bytes)":{"notice":"Cancels an outstanding bridge transaction in case optimistic bridging failed and returns the full amount to the original sender."},"chainGasAmount()":{"notice":"This variable is deprecated and should not be used."},"claim(bytes,address)":{"notice":"Completes bridge transaction on origin chain by claiming originally deposited capital"},"claimV2(bytes)":{"notice":"Completes bridge transaction on origin chain by claiming originally deposited capital.Can only send funds to the relayer address on the proof."},"constructor":{"notice":"Initializes the FastBridgeV2 contract with the provided default admin, sets the default cancel delay, and records the deploy block number."},"deployBlock()":{"notice":"The block number at which this contract was deployed."},"dispute(bytes32)":{"notice":"Disputes an outstanding proof in case relayer provided dest chain tx is invalid"},"getBridgeTransaction(bytes)":{"notice":"Decodes bridge request into a bridge transaction"},"getBridgeTransactionV2(bytes)":{"notice":"Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2"},"multicallNoResults(bytes[],bool)":{"notice":"Executes multiple calls to this contract in a single transaction while preserving msg.sender. Return data from the calls is discarded."},"multicallWithResults(bytes[],bool)":{"notice":"Executes multiple calls to this contract in a single transaction while preserving msg.sender. Return data from each call is preserved."},"nonce()":{"notice":"This variable is deprecated and should not be used."},"protocolFeeRate()":{"notice":"The protocol fee rate taken on the origin amount deposited in the origin chain."},"protocolFees(address)":{"notice":"The accumulated protocol fee amounts."},"prove(bytes,bytes32)":{"notice":"Provides proof on origin side that relayer provided funds on destination side of bridge transaction"},"proveV2(bytes32,bytes32,address)":{"notice":"Provides proof on origin side that relayer provided funds on destination side of bridge transaction"},"refund(bytes)":{"notice":"Note: this function is deprecated and will be removed in a future version."},"relay(bytes)":{"notice":"Relays destination side of bridge transaction by off-chain relayer"},"relayV2(bytes,address)":{"notice":"Relays destination side of bridge transaction by off-chain relayer"},"senderNonces(address)":{"notice":"Maps sender addresses to their unique bridge nonce."},"setCancelDelay(uint256)":{"notice":"Allows the governor to set the cancel delay. The cancel delay is the time period after the transaction deadline during which a transaction can be permissionlessly cancelled if it hasn't been proven by any Relayer."},"setProtocolFeeRate(uint256)":{"notice":"Allows the governor to set the protocol fee rate. The protocol fee is taken from the origin amount and is only applied to completed and claimed transactions."},"sweepProtocolFees(address,address)":{"notice":"Allows the governor to withdraw the accumulated protocol fees from the contract."}},"notice":"Core component of the SynapseRFQ protocol, enabling Relayers (Solvers) to fulfill bridge requests. Supports ERC20 and native gas tokens, along with the Zap feature for executing actions on the destination chain. Users interact with the off-chain Quoter API to obtain a current quote for a bridge transaction. They then submit the bridge request with the quote to this contract, depositing their assets in escrow. Relayers can fulfill requests by relaying them to the destination chain and must prove fulfillment to claim funds. Guards monitor proofs and can dispute discrepancies. Users can reclaim funds by cancelling their requests if it has not been fulfilled within the specified deadline.","version":1},"developerDoc":{"errors":{"AccessControlBadConfirmation()":[{"details":"The caller of a function is not the expected one. NOTE: Don't confuse with {AccessControlUnauthorizedAccount}."}],"AccessControlUnauthorizedAccount(address,bytes32)":[{"details":"The `account` is missing a role."}],"AddressEmptyCode(address)":[{"details":"There's no code at `target` (it is not a contract)."}],"AddressInsufficientBalance(address)":[{"details":"The ETH balance of the account is not enough to perform the operation."}],"FailedInnerCall()":[{"details":"A call to an address target failed. The target may have reverted."}],"SafeERC20FailedOperation(address)":[{"details":"An operation with an ERC20 token failed."}]},"events":{"RoleAdminChanged(bytes32,bytes32,bytes32)":{"details":"Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole` `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite {RoleAdminChanged} not being emitted signaling this."},"RoleGranted(bytes32,address,address)":{"details":"Emitted when `account` is granted `role`. `sender` is the account that originated the contract call, an admin role bearer except when using {AccessControl-_setupRole}."},"RoleRevoked(bytes32,address,address)":{"details":"Emitted when `account` is revoked `role`. `sender` is the account that originated the contract call: - if using `revokeRole`, it is the admin role bearer - if using `renounceRole`, it is the role bearer (i.e. `account`)"}},"kind":"dev","methods":{"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256))":{"params":{"params":"The parameters required to bridge"}},"bridgeProofs(bytes32)":{"params":{"transactionId":"The ID of the bridge transaction"},"returns":{"relayer":"The relayer address of the bridge proof","timestamp":"The timestamp of the bridge proof"}},"bridgeRelays(bytes32)":{"params":{"transactionId":"The ID of the transaction to check"},"returns":{"_0":"True if the transaction has been relayed, false otherwise"}},"bridgeStatuses(bytes32)":{"params":{"transactionId":"The ID of the bridge transaction"},"returns":{"status":"BridgeStatus Status of the bridge transaction"}},"bridgeV2((uint32,address,address,address,address,uint256,uint256,bool,uint256),(address,int256,bytes,uint256,bytes))":{"params":{"params":"The parameters required to bridge","paramsV2":"The parameters for exclusivity fill rights (optional, can be left empty)"}},"canClaim(bytes32,address)":{"params":{"relayer":"The address of the relayer attempting to claim","transactionId":"The transaction id associated with the encoded bridge transaction to check"}},"cancelV2(bytes)":{"params":{"request":"The encoded bridge transaction to refund"}},"claim(bytes,address)":{"params":{"request":"The encoded bridge transaction to claim on origin chain","to":"The recipient address of the funds"}},"claimV2(bytes)":{"params":{"request":"The encoded bridge transaction to claim on origin chain"}},"dispute(bytes32)":{"params":{"transactionId":"The transaction id associated with the encoded bridge transaction to dispute"}},"getBridgeTransaction(bytes)":{"details":"This method is added to achieve backwards compatibility with decoding requests into V1 structs: - `zapNative` is partially reported as a zero/non-zero flag - `zapData` is ignored In order to process all kinds of requests use getBridgeTransactionV2 instead.","params":{"request":"The bridge request to decode"}},"getBridgeTransactionV2(bytes)":{"params":{"request":"The bridge request to decode"}},"getRoleAdmin(bytes32)":{"details":"Returns the admin role that controls `role`. See {grantRole} and {revokeRole}. To change a role's admin, use {_setRoleAdmin}."},"getRoleMember(bytes32,uint256)":{"details":"Returns one of the accounts that have `role`. `index` must be a value between 0 and {getRoleMemberCount}, non-inclusive. Role bearers are not sorted in any particular way, and their ordering may change at any point. WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure you perform all queries on the same block. See the following https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post] for more information."},"getRoleMemberCount(bytes32)":{"details":"Returns the number of accounts that have `role`. Can be used together with {getRoleMember} to enumerate all bearers of a role."},"grantRole(bytes32,address)":{"details":"Grants `role` to `account`. If `account` had not been already granted `role`, emits a {RoleGranted} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleGranted} event."},"hasRole(bytes32,address)":{"details":"Returns `true` if `account` has been granted `role`."},"multicallNoResults(bytes[],bool)":{"details":"This method is non-payable, so only calls with msg.value of 0 can be batched. If ignoreReverts is set to true, reverted calls will be skipped. Otherwise, the entire batch will revert with the original revert reason.","params":{"data":"List of ABI-encoded calldata for the calls to execute","ignoreReverts":"Whether to skip calls that revert"}},"multicallWithResults(bytes[],bool)":{"details":"This method is non-payable, so only calls with msg.value of 0 can be batched. If ignoreReverts is set to true, reverted calls will be skipped. Otherwise, the entire batch will revert with the original revert reason.","params":{"data":"List of ABI-encoded calldata for the calls to execute","ignoreReverts":"Whether to skip calls that revert"},"returns":{"results":" List of results from the calls, each containing (success, returnData)"}},"prove(bytes,bytes32)":{"params":{"destTxHash":"The destination tx hash proving bridge transaction was relayed","request":"The encoded bridge transaction to prove on origin chain"}},"proveV2(bytes32,bytes32,address)":{"params":{"destTxHash":"The destination tx hash proving bridge transaction was relayed","relayer":"The address of the relaying entity which should have control of the origin funds when claimed","transactionId":"The transaction id associated with the encoded bridge transaction to prove"}},"refund(bytes)":{"details":"Replaced by `cancel`.","params":{"request":"The encoded bridge transaction to refund"}},"relay(bytes)":{"params":{"request":"The encoded bridge transaction to relay on destination chain"}},"relayV2(bytes,address)":{"params":{"relayer":"The address of the relaying entity which should have control of the origin funds when claimed","request":"The encoded bridge transaction to relay on destination chain"}},"renounceRole(bytes32,address)":{"details":"Revokes `role` from the calling account. Roles are often managed via {grantRole} and {revokeRole}: this function's purpose is to provide a mechanism for accounts to lose their privileges if they are compromised (such as when a trusted device is misplaced). If the calling account had been revoked `role`, emits a {RoleRevoked} event. Requirements: - the caller must be `callerConfirmation`. May emit a {RoleRevoked} event."},"revokeRole(bytes32,address)":{"details":"Revokes `role` from `account`. If `account` had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleRevoked} event."},"setProtocolFeeRate(uint256)":{"details":"The protocol fee is abstracted away from the relayers; they always operate using the amounts after fees. The origin amount they see in the emitted log is what they get credited with."},"supportsInterface(bytes4)":{"details":"See {IERC165-supportsInterface}."}},"stateVariables":{"nonce":{"details":"Replaced by senderNonces."}},"title":"FastBridgeV2","version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"defaultAdmin\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"AccessControlBadConfirmation\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"neededRole\",\"type\":\"bytes32\"}],\"name\":\"AccessControlUnauthorizedAccount\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"}],\"name\":\"AddressEmptyCode\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"AddressInsufficientBalance\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"AmountIncorrect\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"BridgeTransactionV2__InvalidEncodedTx\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint16\",\"name\":\"version\",\"type\":\"uint16\"}],\"name\":\"BridgeTransactionV2__UnsupportedVersion\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"CancelDelayBelowMin\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ChainIncorrect\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DeadlineExceeded\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DeadlineNotExceeded\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DeadlineTooShort\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DisputePeriodNotPassed\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DisputePeriodPassed\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ExclusivityParamsIncorrect\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ExclusivityPeriodNotPassed\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"FailedInnerCall\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"FeeRateAboveMax\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"MsgValueIncorrect\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"MulticallTarget__UndeterminedRevert\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"RecipientIncorrectReturnValue\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"RecipientNoReturnValue\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"}],\"name\":\"SafeERC20FailedOperation\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"SenderIncorrect\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"StatusIncorrect\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"TokenNotContract\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"TransactionRelayed\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ZapDataLengthAboveMax\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ZapNativeNotSupported\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ZeroAddress\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"BridgeDepositClaimed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"BridgeDepositRefunded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"name\":\"BridgeProofDisputed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"transactionHash\",\"type\":\"bytes32\"}],\"name\":\"BridgeProofProvided\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"quoteId\",\"type\":\"bytes\"}],\"name\":\"BridgeQuoteDetails\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"originChainId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"chainGasAmount\",\"type\":\"uint256\"}],\"name\":\"BridgeRelayed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"destChainId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"sendChainGas\",\"type\":\"bool\"}],\"name\":\"BridgeRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"oldCancelDelay\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newCancelDelay\",\"type\":\"uint256\"}],\"name\":\"CancelDelayUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"oldFeeRate\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newFeeRate\",\"type\":\"uint256\"}],\"name\":\"FeeRateUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"FeesSwept\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"previousAdminRole\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"newAdminRole\",\"type\":\"bytes32\"}],\"name\":\"RoleAdminChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleGranted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleRevoked\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"CANCELER_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"DEFAULT_ADMIN_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"DEFAULT_CANCEL_DELAY\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"DISPUTE_PERIOD\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"FEE_BPS\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"FEE_RATE_MAX\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"GOVERNOR_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"GUARD_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"MAX_ZAP_DATA_LENGTH\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"MIN_CANCEL_DELAY\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"MIN_DEADLINE_PERIOD\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"NATIVE_GAS_TOKEN\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"PROVER_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"QUOTER_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"dstChainId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"sendChainGas\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"}],\"internalType\":\"struct IFastBridge.BridgeParams\",\"name\":\"params\",\"type\":\"tuple\"}],\"name\":\"bridge\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"}],\"name\":\"bridgeProofs\",\"outputs\":[{\"internalType\":\"uint96\",\"name\":\"timestamp\",\"type\":\"uint96\"},{\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"bridgeRelayDetails\",\"outputs\":[{\"internalType\":\"uint48\",\"name\":\"blockNumber\",\"type\":\"uint48\"},{\"internalType\":\"uint48\",\"name\":\"blockTimestamp\",\"type\":\"uint48\"},{\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"}],\"name\":\"bridgeRelays\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"}],\"name\":\"bridgeStatuses\",\"outputs\":[{\"internalType\":\"enum IFastBridgeV2.BridgeStatus\",\"name\":\"status\",\"type\":\"uint8\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"bridgeTxDetails\",\"outputs\":[{\"internalType\":\"enum IFastBridgeV2.BridgeStatus\",\"name\":\"status\",\"type\":\"uint8\"},{\"internalType\":\"uint32\",\"name\":\"destChainId\",\"type\":\"uint32\"},{\"internalType\":\"uint56\",\"name\":\"proofBlockTimestamp\",\"type\":\"uint56\"},{\"internalType\":\"address\",\"name\":\"proofRelayer\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"dstChainId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"sendChainGas\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"}],\"internalType\":\"struct IFastBridge.BridgeParams\",\"name\":\"params\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"quoteRelayer\",\"type\":\"address\"},{\"internalType\":\"int256\",\"name\":\"quoteExclusivitySeconds\",\"type\":\"int256\"},{\"internalType\":\"bytes\",\"name\":\"quoteId\",\"type\":\"bytes\"},{\"internalType\":\"uint256\",\"name\":\"zapNative\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"zapData\",\"type\":\"bytes\"}],\"internalType\":\"struct IFastBridgeV2.BridgeParamsV2\",\"name\":\"paramsV2\",\"type\":\"tuple\"}],\"name\":\"bridgeV2\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"name\":\"canClaim\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"cancelDelay\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"cancelV2\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"chainGasAmount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"claim\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"claimV2\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"deployBlock\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"}],\"name\":\"dispute\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"getBridgeTransaction\",\"outputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"originChainId\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"destChainId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"originSender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destRecipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"originFeeAmount\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"sendChainGas\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"}],\"internalType\":\"struct IFastBridge.BridgeTransaction\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"getBridgeTransactionV2\",\"outputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"originChainId\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"destChainId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"originSender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destRecipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"originFeeAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"exclusivityRelayer\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"exclusivityEndTime\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"zapNative\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"zapData\",\"type\":\"bytes\"}],\"internalType\":\"struct IFastBridgeV2.BridgeTransactionV2\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"}],\"name\":\"getRoleAdmin\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"index\",\"type\":\"uint256\"}],\"name\":\"getRoleMember\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"}],\"name\":\"getRoleMemberCount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"grantRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"hasRole\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes[]\",\"name\":\"data\",\"type\":\"bytes[]\"},{\"internalType\":\"bool\",\"name\":\"ignoreReverts\",\"type\":\"bool\"}],\"name\":\"multicallNoResults\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes[]\",\"name\":\"data\",\"type\":\"bytes[]\"},{\"internalType\":\"bool\",\"name\":\"ignoreReverts\",\"type\":\"bool\"}],\"name\":\"multicallWithResults\",\"outputs\":[{\"components\":[{\"internalType\":\"bool\",\"name\":\"success\",\"type\":\"bool\"},{\"internalType\":\"bytes\",\"name\":\"returnData\",\"type\":\"bytes\"}],\"internalType\":\"struct IMulticallTarget.Result[]\",\"name\":\"results\",\"type\":\"tuple[]\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"nonce\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"protocolFeeRate\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"protocolFees\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"},{\"internalType\":\"bytes32\",\"name\":\"destTxHash\",\"type\":\"bytes32\"}],\"name\":\"prove\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"destTxHash\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"name\":\"proveV2\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"refund\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"relay\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"},{\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"name\":\"relayV2\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"callerConfirmation\",\"type\":\"address\"}],\"name\":\"renounceRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"revokeRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"senderNonces\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"newCancelDelay\",\"type\":\"uint256\"}],\"name\":\"setCancelDelay\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"newFeeRate\",\"type\":\"uint256\"}],\"name\":\"setProtocolFeeRate\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes4\",\"name\":\"interfaceId\",\"type\":\"bytes4\"}],\"name\":\"supportsInterface\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"}],\"name\":\"sweepProtocolFees\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"errors\":{\"AccessControlBadConfirmation()\":[{\"details\":\"The caller of a function is not the expected one. NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\"}],\"AccessControlUnauthorizedAccount(address,bytes32)\":[{\"details\":\"The `account` is missing a role.\"}],\"AddressEmptyCode(address)\":[{\"details\":\"There's no code at `target` (it is not a contract).\"}],\"AddressInsufficientBalance(address)\":[{\"details\":\"The ETH balance of the account is not enough to perform the operation.\"}],\"FailedInnerCall()\":[{\"details\":\"A call to an address target failed. The target may have reverted.\"}],\"SafeERC20FailedOperation(address)\":[{\"details\":\"An operation with an ERC20 token failed.\"}]},\"events\":{\"RoleAdminChanged(bytes32,bytes32,bytes32)\":{\"details\":\"Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole` `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite {RoleAdminChanged} not being emitted signaling this.\"},\"RoleGranted(bytes32,address,address)\":{\"details\":\"Emitted when `account` is granted `role`. `sender` is the account that originated the contract call, an admin role bearer except when using {AccessControl-_setupRole}.\"},\"RoleRevoked(bytes32,address,address)\":{\"details\":\"Emitted when `account` is revoked `role`. `sender` is the account that originated the contract call: - if using `revokeRole`, it is the admin role bearer - if using `renounceRole`, it is the role bearer (i.e. `account`)\"}},\"kind\":\"dev\",\"methods\":{\"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256))\":{\"params\":{\"params\":\"The parameters required to bridge\"}},\"bridgeProofs(bytes32)\":{\"params\":{\"transactionId\":\"The ID of the bridge transaction\"},\"returns\":{\"relayer\":\"The relayer address of the bridge proof\",\"timestamp\":\"The timestamp of the bridge proof\"}},\"bridgeRelays(bytes32)\":{\"params\":{\"transactionId\":\"The ID of the transaction to check\"},\"returns\":{\"_0\":\"True if the transaction has been relayed, false otherwise\"}},\"bridgeStatuses(bytes32)\":{\"params\":{\"transactionId\":\"The ID of the bridge transaction\"},\"returns\":{\"status\":\"BridgeStatus Status of the bridge transaction\"}},\"bridgeV2((uint32,address,address,address,address,uint256,uint256,bool,uint256),(address,int256,bytes,uint256,bytes))\":{\"params\":{\"params\":\"The parameters required to bridge\",\"paramsV2\":\"The parameters for exclusivity fill rights (optional, can be left empty)\"}},\"canClaim(bytes32,address)\":{\"params\":{\"relayer\":\"The address of the relayer attempting to claim\",\"transactionId\":\"The transaction id associated with the encoded bridge transaction to check\"}},\"cancelV2(bytes)\":{\"params\":{\"request\":\"The encoded bridge transaction to refund\"}},\"claim(bytes,address)\":{\"params\":{\"request\":\"The encoded bridge transaction to claim on origin chain\",\"to\":\"The recipient address of the funds\"}},\"claimV2(bytes)\":{\"params\":{\"request\":\"The encoded bridge transaction to claim on origin chain\"}},\"dispute(bytes32)\":{\"params\":{\"transactionId\":\"The transaction id associated with the encoded bridge transaction to dispute\"}},\"getBridgeTransaction(bytes)\":{\"details\":\"This method is added to achieve backwards compatibility with decoding requests into V1 structs: - `zapNative` is partially reported as a zero/non-zero flag - `zapData` is ignored In order to process all kinds of requests use getBridgeTransactionV2 instead.\",\"params\":{\"request\":\"The bridge request to decode\"}},\"getBridgeTransactionV2(bytes)\":{\"params\":{\"request\":\"The bridge request to decode\"}},\"getRoleAdmin(bytes32)\":{\"details\":\"Returns the admin role that controls `role`. See {grantRole} and {revokeRole}. To change a role's admin, use {_setRoleAdmin}.\"},\"getRoleMember(bytes32,uint256)\":{\"details\":\"Returns one of the accounts that have `role`. `index` must be a value between 0 and {getRoleMemberCount}, non-inclusive. Role bearers are not sorted in any particular way, and their ordering may change at any point. WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure you perform all queries on the same block. See the following https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post] for more information.\"},\"getRoleMemberCount(bytes32)\":{\"details\":\"Returns the number of accounts that have `role`. Can be used together with {getRoleMember} to enumerate all bearers of a role.\"},\"grantRole(bytes32,address)\":{\"details\":\"Grants `role` to `account`. If `account` had not been already granted `role`, emits a {RoleGranted} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleGranted} event.\"},\"hasRole(bytes32,address)\":{\"details\":\"Returns `true` if `account` has been granted `role`.\"},\"multicallNoResults(bytes[],bool)\":{\"details\":\"This method is non-payable, so only calls with msg.value of 0 can be batched. If ignoreReverts is set to true, reverted calls will be skipped. Otherwise, the entire batch will revert with the original revert reason.\",\"params\":{\"data\":\"List of ABI-encoded calldata for the calls to execute\",\"ignoreReverts\":\"Whether to skip calls that revert\"}},\"multicallWithResults(bytes[],bool)\":{\"details\":\"This method is non-payable, so only calls with msg.value of 0 can be batched. If ignoreReverts is set to true, reverted calls will be skipped. Otherwise, the entire batch will revert with the original revert reason.\",\"params\":{\"data\":\"List of ABI-encoded calldata for the calls to execute\",\"ignoreReverts\":\"Whether to skip calls that revert\"},\"returns\":{\"results\":\" List of results from the calls, each containing (success, returnData)\"}},\"prove(bytes,bytes32)\":{\"params\":{\"destTxHash\":\"The destination tx hash proving bridge transaction was relayed\",\"request\":\"The encoded bridge transaction to prove on origin chain\"}},\"proveV2(bytes32,bytes32,address)\":{\"params\":{\"destTxHash\":\"The destination tx hash proving bridge transaction was relayed\",\"relayer\":\"The address of the relaying entity which should have control of the origin funds when claimed\",\"transactionId\":\"The transaction id associated with the encoded bridge transaction to prove\"}},\"refund(bytes)\":{\"details\":\"Replaced by `cancel`.\",\"params\":{\"request\":\"The encoded bridge transaction to refund\"}},\"relay(bytes)\":{\"params\":{\"request\":\"The encoded bridge transaction to relay on destination chain\"}},\"relayV2(bytes,address)\":{\"params\":{\"relayer\":\"The address of the relaying entity which should have control of the origin funds when claimed\",\"request\":\"The encoded bridge transaction to relay on destination chain\"}},\"renounceRole(bytes32,address)\":{\"details\":\"Revokes `role` from the calling account. Roles are often managed via {grantRole} and {revokeRole}: this function's purpose is to provide a mechanism for accounts to lose their privileges if they are compromised (such as when a trusted device is misplaced). If the calling account had been revoked `role`, emits a {RoleRevoked} event. Requirements: - the caller must be `callerConfirmation`. May emit a {RoleRevoked} event.\"},\"revokeRole(bytes32,address)\":{\"details\":\"Revokes `role` from `account`. If `account` had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleRevoked} event.\"},\"setProtocolFeeRate(uint256)\":{\"details\":\"The protocol fee is abstracted away from the relayers; they always operate using the amounts after fees. The origin amount they see in the emitted log is what they get credited with.\"},\"supportsInterface(bytes4)\":{\"details\":\"See {IERC165-supportsInterface}.\"}},\"stateVariables\":{\"nonce\":{\"details\":\"Replaced by senderNonces.\"}},\"title\":\"FastBridgeV2\",\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"CANCELER_ROLE()\":{\"notice\":\"The role identifier for the Canceler's on-chain authentication in FastBridge.\"},\"DEFAULT_CANCEL_DELAY()\":{\"notice\":\"The default cancel delay set during contract deployment.\"},\"DISPUTE_PERIOD()\":{\"notice\":\"The duration of the dispute period for relayed transactions.\"},\"FEE_BPS()\":{\"notice\":\"The denominator for fee rates, representing 100%.\"},\"FEE_RATE_MAX()\":{\"notice\":\"The maximum protocol fee rate: 1% of the origin amount.\"},\"GOVERNOR_ROLE()\":{\"notice\":\"The role identifier for the Governor's on-chain administrative authority.\"},\"GUARD_ROLE()\":{\"notice\":\"The role identifier for the Guard's on-chain authentication in FastBridge.\"},\"MAX_ZAP_DATA_LENGTH()\":{\"notice\":\"The maximum allowed length for zapData.\"},\"MIN_CANCEL_DELAY()\":{\"notice\":\"The minimum cancel delay that can be set by the governor.\"},\"MIN_DEADLINE_PERIOD()\":{\"notice\":\"The minimum required time between transaction request and deadline.\"},\"NATIVE_GAS_TOKEN()\":{\"notice\":\"The address reserved for the native gas token (ETH on Ethereum and most L2s, AVAX on Avalanche, etc.).\"},\"PROVER_ROLE()\":{\"notice\":\"The role identifier for the Prover's on-chain authentication in FastBridge.\"},\"QUOTER_ROLE()\":{\"notice\":\"The role identifier for the Quoter API's off-chain authentication.\"},\"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256))\":{\"notice\":\"Initiates bridge on origin chain to be relayed by off-chain relayer\"},\"bridgeProofs(bytes32)\":{\"notice\":\"Returns the timestamp and relayer of a bridge proof\"},\"bridgeRelayDetails(bytes32)\":{\"notice\":\"Maps transaction IDs to relay details (block number, block timestamp, and relayer). Note: this is only stored for transactions having local chain as the destination chain.\"},\"bridgeRelays(bytes32)\":{\"notice\":\"Checks if a transaction has been relayed\"},\"bridgeStatuses(bytes32)\":{\"notice\":\"Returns the status of a bridge transaction\"},\"bridgeTxDetails(bytes32)\":{\"notice\":\"Maps transaction IDs to bridge details (status, destination chain ID, proof timestamp, and relayer). Note: this is only stored for transactions having local chain as the origin chain.\"},\"bridgeV2((uint32,address,address,address,address,uint256,uint256,bool,uint256),(address,int256,bytes,uint256,bytes))\":{\"notice\":\"Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability to provide temporary exclusivity fill rights for the quote relayer.\"},\"canClaim(bytes32,address)\":{\"notice\":\"Checks if the dispute period has passed so bridge deposit can be claimed\"},\"cancelDelay()\":{\"notice\":\"The delay period after which a transaction can be permissionlessly cancelled.\"},\"cancelV2(bytes)\":{\"notice\":\"Cancels an outstanding bridge transaction in case optimistic bridging failed and returns the full amount to the original sender.\"},\"chainGasAmount()\":{\"notice\":\"This variable is deprecated and should not be used.\"},\"claim(bytes,address)\":{\"notice\":\"Completes bridge transaction on origin chain by claiming originally deposited capital\"},\"claimV2(bytes)\":{\"notice\":\"Completes bridge transaction on origin chain by claiming originally deposited capital.Can only send funds to the relayer address on the proof.\"},\"constructor\":{\"notice\":\"Initializes the FastBridgeV2 contract with the provided default admin, sets the default cancel delay, and records the deploy block number.\"},\"deployBlock()\":{\"notice\":\"The block number at which this contract was deployed.\"},\"dispute(bytes32)\":{\"notice\":\"Disputes an outstanding proof in case relayer provided dest chain tx is invalid\"},\"getBridgeTransaction(bytes)\":{\"notice\":\"Decodes bridge request into a bridge transaction\"},\"getBridgeTransactionV2(bytes)\":{\"notice\":\"Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\"},\"multicallNoResults(bytes[],bool)\":{\"notice\":\"Executes multiple calls to this contract in a single transaction while preserving msg.sender. Return data from the calls is discarded.\"},\"multicallWithResults(bytes[],bool)\":{\"notice\":\"Executes multiple calls to this contract in a single transaction while preserving msg.sender. Return data from each call is preserved.\"},\"nonce()\":{\"notice\":\"This variable is deprecated and should not be used.\"},\"protocolFeeRate()\":{\"notice\":\"The protocol fee rate taken on the origin amount deposited in the origin chain.\"},\"protocolFees(address)\":{\"notice\":\"The accumulated protocol fee amounts.\"},\"prove(bytes,bytes32)\":{\"notice\":\"Provides proof on origin side that relayer provided funds on destination side of bridge transaction\"},\"proveV2(bytes32,bytes32,address)\":{\"notice\":\"Provides proof on origin side that relayer provided funds on destination side of bridge transaction\"},\"refund(bytes)\":{\"notice\":\"Note: this function is deprecated and will be removed in a future version.\"},\"relay(bytes)\":{\"notice\":\"Relays destination side of bridge transaction by off-chain relayer\"},\"relayV2(bytes,address)\":{\"notice\":\"Relays destination side of bridge transaction by off-chain relayer\"},\"senderNonces(address)\":{\"notice\":\"Maps sender addresses to their unique bridge nonce.\"},\"setCancelDelay(uint256)\":{\"notice\":\"Allows the governor to set the cancel delay. The cancel delay is the time period after the transaction deadline during which a transaction can be permissionlessly cancelled if it hasn't been proven by any Relayer.\"},\"setProtocolFeeRate(uint256)\":{\"notice\":\"Allows the governor to set the protocol fee rate. The protocol fee is taken from the origin amount and is only applied to completed and claimed transactions.\"},\"sweepProtocolFees(address,address)\":{\"notice\":\"Allows the governor to withdraw the accumulated protocol fees from the contract.\"}},\"notice\":\"Core component of the SynapseRFQ protocol, enabling Relayers (Solvers) to fulfill bridge requests. Supports ERC20 and native gas tokens, along with the Zap feature for executing actions on the destination chain. Users interact with the off-chain Quoter API to obtain a current quote for a bridge transaction. They then submit the bridge request with the quote to this contract, depositing their assets in escrow. Relayers can fulfill requests by relaying them to the destination chain and must prove fulfillment to claim funds. Guards monitor proofs and can dispute discrepancies. Users can reclaim funds by cancelling their requests if it has not been fulfilled within the specified deadline.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeV2.sol\":\"FastBridgeV2\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeV2.sol\":{\"keccak256\":\"0xaab2ee7357681726f0faf799a48ddfbf45fb4da93b69abf61c33dde92b29b74d\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://673391bff9569efc0f9bd99e0e6fece0bc8e8af1f052bb071b407b267a17b3b5\",\"dweb:/ipfs/QmdQQZ6DxpJYhfpinwU5WjLugr2f6qP8h68b5GerhSMQ4j\"]}},\"version\":1}"},"hashes":{"CANCELER_ROLE()":"02d2ff66","DEFAULT_ADMIN_ROLE()":"a217fddf","DEFAULT_CANCEL_DELAY()":"930ac180","DISPUTE_PERIOD()":"a5bbe22b","FEE_BPS()":"bf333f2c","FEE_RATE_MAX()":"0f5f6ed7","GOVERNOR_ROLE()":"ccc57490","GUARD_ROLE()":"03ed0ee5","MAX_ZAP_DATA_LENGTH()":"54eff068","MIN_CANCEL_DELAY()":"922b7487","MIN_DEADLINE_PERIOD()":"820688d5","NATIVE_GAS_TOKEN()":"0f862f1e","PROVER_ROLE()":"dc9a4ef6","QUOTER_ROLE()":"7ebe815c","bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256))":"45851694","bridgeProofs(bytes32)":"91ad5039","bridgeRelayDetails(bytes32)":"c79371b1","bridgeRelays(bytes32)":"8379a24f","bridgeStatuses(bytes32)":"051287bc","bridgeTxDetails(bytes32)":"63787e52","bridgeV2((uint32,address,address,address,address,uint256,uint256,bool,uint256),(address,int256,bytes,uint256,bytes))":"76443085","canClaim(bytes32,address)":"aa9641ab","cancelDelay()":"638a0f09","cancelV2(bytes)":"67e60693","chainGasAmount()":"e00a83e0","claim(bytes,address)":"41fcb612","claimV2(bytes)":"f76d7278","deployBlock()":"a3ec191a","dispute(bytes32)":"add98c70","getBridgeTransaction(bytes)":"ac11fb1a","getBridgeTransactionV2(bytes)":"5aa6ccba","getRoleAdmin(bytes32)":"248a9ca3","getRoleMember(bytes32,uint256)":"9010d07c","getRoleMemberCount(bytes32)":"ca15c873","grantRole(bytes32,address)":"2f2ff15d","hasRole(bytes32,address)":"91d14854","multicallNoResults(bytes[],bool)":"3f61331d","multicallWithResults(bytes[],bool)":"385c1d2f","nonce()":"affed0e0","protocolFeeRate()":"58f85880","protocolFees(address)":"dcf844a7","prove(bytes,bytes32)":"886d36ff","proveV2(bytes32,bytes32,address)":"41fdec80","refund(bytes)":"5eb7d946","relay(bytes)":"8f0d6f17","relayV2(bytes,address)":"3d71e21f","renounceRole(bytes32,address)":"36568abe","revokeRole(bytes32,address)":"d547741f","senderNonces(address)":"295710ff","setCancelDelay(uint256)":"1ea327c5","setProtocolFeeRate(uint256)":"b13aa2d6","supportsInterface(bytes4)":"01ffc9a7","sweepProtocolFees(address,address)":"06f333f2"}},"solidity/FastBridgeV2.sol:IAccessControl":{"code":"0x","runtime-code":"0x","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.24 ^0.8.20 ^0.8.4;\n\n// contracts/interfaces/IAdminV2.sol\n\ninterface IAdminV2 {\n event CancelDelayUpdated(uint256 oldCancelDelay, uint256 newCancelDelay);\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n /// @notice Allows the governor to set the cancel delay. The cancel delay is the time period after the transaction\n /// deadline during which a transaction can be permissionlessly cancelled if it hasn't been proven by any Relayer.\n function setCancelDelay(uint256 newCancelDelay) external;\n\n /// @notice Allows the governor to set the protocol fee rate. The protocol fee is taken from the origin\n /// amount and is only applied to completed and claimed transactions.\n /// @dev The protocol fee is abstracted away from the relayers; they always operate using the amounts after fees.\n /// The origin amount they see in the emitted log is what they get credited with.\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n /// @notice Allows the governor to withdraw the accumulated protocol fees from the contract.\n function sweepProtocolFees(address token, address recipient) external;\n}\n\n// contracts/interfaces/IAdminV2Errors.sol\n\ninterface IAdminV2Errors {\n error CancelDelayBelowMin();\n error FeeRateAboveMax();\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IFastBridgeV2Errors.sol\n\ninterface IFastBridgeV2Errors {\n error AmountIncorrect();\n error ChainIncorrect();\n error ExclusivityParamsIncorrect();\n error MsgValueIncorrect();\n error SenderIncorrect();\n error StatusIncorrect();\n error TokenNotContract();\n error ZapDataLengthAboveMax();\n error ZapNativeNotSupported();\n error ZeroAddress();\n\n error RecipientIncorrectReturnValue();\n error RecipientNoReturnValue();\n\n error DeadlineExceeded();\n error DeadlineNotExceeded();\n error DeadlineTooShort();\n error DisputePeriodNotPassed();\n error DisputePeriodPassed();\n error ExclusivityPeriodNotPassed();\n\n error TransactionRelayed();\n}\n\n// contracts/interfaces/IMulticallTarget.sol\n\n/// @notice Interface for a contract that supports multiple calls from the same caller. Inspired by MulticallV3:\n/// https://github.com/mds1/multicall/blob/master/src/Multicall3.sol\ninterface IMulticallTarget {\n struct Result {\n bool success;\n bytes returnData;\n }\n\n /// @notice Executes multiple calls to this contract in a single transaction while preserving msg.sender.\n /// Return data from the calls is discarded.\n /// @dev This method is non-payable, so only calls with msg.value of 0 can be batched.\n /// If ignoreReverts is set to true, reverted calls will be skipped.\n /// Otherwise, the entire batch will revert with the original revert reason.\n /// @param data List of ABI-encoded calldata for the calls to execute\n /// @param ignoreReverts Whether to skip calls that revert\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external;\n\n /// @notice Executes multiple calls to this contract in a single transaction while preserving msg.sender.\n /// Return data from each call is preserved.\n /// @dev This method is non-payable, so only calls with msg.value of 0 can be batched.\n /// If ignoreReverts is set to true, reverted calls will be skipped.\n /// Otherwise, the entire batch will revert with the original revert reason.\n /// @param data List of ABI-encoded calldata for the calls to execute\n /// @param ignoreReverts Whether to skip calls that revert\n /// @return results List of results from the calls, each containing (success, returnData)\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results);\n}\n\n// contracts/interfaces/IZapRecipient.sol\n\n/// @notice Interface for contracts that can perform Zap operations. Such contracts could be used as Recipients\n/// in a FastBridge transaction that includes a Zap operation. The Zap Data should include instructions on how\n/// exactly the Zap operation should be executed, which would typically include the target address and calldata\n/// to use. The exact implementation of the Zap Data encoding is up to the Recipient contract.\ninterface IZapRecipient {\n /// @notice Performs a Zap operation with the given token and amount according to the provided Zap data.\n /// @param token The address of the token being used for the Zap operation.\n /// @param amount The amount of tokens to be used.\n /// @param zapData The encoded data specifying how the Zap operation should be executed.\n /// @return The function selector to indicate successful execution.\n function zap(address token, uint256 amount, bytes memory zapData) external payable returns (bytes4);\n}\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// contracts/interfaces/IFastBridgeV2.sol\n\ninterface IFastBridgeV2 is IFastBridge {\n enum BridgeStatus {\n NULL, // Doesn't exist yet.\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n struct BridgeTxDetails {\n BridgeStatus status;\n uint32 destChainId;\n uint56 proofBlockTimestamp;\n address proofRelayer;\n }\n\n struct BridgeRelay {\n uint48 blockNumber;\n uint48 blockTimestamp;\n address relayer;\n }\n\n /// @notice New params introduced in the FastBridgeV2.\n /// We are passing fields from the older BridgeParams struct outside of this struct for backwards compatibility.\n /// Note: quoteRelayer and quoteExclusivitySeconds are either both zero (indicating no exclusivity)\n /// or both non-zero (indicating exclusivity for the given period).\n /// Note: zapNative \u003e 0 can NOT be used with destToken = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE (native token)\n /// @param quoteRelayer Relayer that provided the quote for the transaction\n /// @param quoteExclusivitySeconds Period of time the quote relayer is guaranteed exclusivity after user's deposit\n /// @param quoteId Unique quote identifier used for tracking the quote\n /// @param zapNative ETH value to send to the recipient (if any)\n /// @param zapData Parameters for the Zap to the destination recipient (if any)\n struct BridgeParamsV2 {\n address quoteRelayer;\n int256 quoteExclusivitySeconds;\n bytes quoteId;\n uint256 zapNative;\n bytes zapData;\n }\n\n /// @notice Updated bridge transaction struct to include parameters introduced in FastBridgeV2.\n /// Note: only `exclusivityRelayer` can fill such a transaction until `exclusivityEndTime`.\n struct BridgeTransactionV2 {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n // Note: sendChainGas flag from V1 is deprecated\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n address exclusivityRelayer;\n uint256 exclusivityEndTime;\n uint256 zapNative; // ETH value to send to the recipient (if any)\n bytes zapData; // data to pass for the Zap action (if any)\n }\n\n event BridgeQuoteDetails(bytes32 indexed transactionId, bytes quoteId);\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability\n /// to provide temporary exclusivity fill rights for the quote relayer.\n /// @param params The parameters required to bridge\n /// @param paramsV2 The parameters for exclusivity fill rights (optional, can be left empty)\n function bridgeV2(BridgeParams memory params, BridgeParamsV2 memory paramsV2) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function relayV2(bytes memory request, address relayer) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param transactionId The transaction id associated with the encoded bridge transaction to prove\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function proveV2(bytes32 transactionId, bytes32 destTxHash, address relayer) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital.\n /// @notice Can only send funds to the relayer address on the proof.\n /// @param request The encoded bridge transaction to claim on origin chain\n function claimV2(bytes memory request) external;\n\n /// @notice Cancels an outstanding bridge transaction in case optimistic bridging failed and returns the full amount\n /// to the original sender.\n /// @param request The encoded bridge transaction to refund\n function cancelV2(bytes memory request) external;\n\n /// @notice Checks if a transaction has been relayed\n /// @param transactionId The ID of the transaction to check\n /// @return True if the transaction has been relayed, false otherwise\n function bridgeRelays(bytes32 transactionId) external view returns (bool);\n\n /// @notice Returns the status of a bridge transaction\n /// @param transactionId The ID of the bridge transaction\n /// @return BridgeStatus Status of the bridge transaction\n function bridgeStatuses(bytes32 transactionId) external view returns (BridgeStatus);\n\n /// @notice Returns the timestamp and relayer of a bridge proof\n /// @param transactionId The ID of the bridge transaction\n /// @return timestamp The timestamp of the bridge proof\n /// @return relayer The relayer address of the bridge proof\n function bridgeProofs(bytes32 transactionId) external view returns (uint96 timestamp, address relayer);\n\n /// @notice Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\n /// @param request The bridge request to decode\n function getBridgeTransactionV2(bytes memory request) external view returns (BridgeTransactionV2 memory);\n}\n\n// contracts/utils/MulticallTarget.sol\n\n// solhint-disable avoid-low-level-calls\n/// @notice Abstract contract template that supports batched calls while preserving msg.sender.\n/// Only calls with msg.value of 0 can be batched.\nabstract contract MulticallTarget is IMulticallTarget {\n error MulticallTarget__UndeterminedRevert();\n\n /// @inheritdoc IMulticallTarget\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external {\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\n if (!success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(result);\n }\n }\n }\n\n /// @inheritdoc IMulticallTarget\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results)\n {\n results = new Result[](data.length);\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (results[i].success, results[i].returnData) = address(this).delegatecall(data[i]);\n if (!results[i].success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(results[i].returnData);\n }\n }\n }\n\n /// @dev Bubbles the revert message from the underlying call.\n /// Note: preserves the same custom error or revert string, if one was used.\n /// Source: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v5.0.2/contracts/utils/Address.sol#L143-L158\n function _bubbleRevert(bytes memory returnData) internal pure {\n // Look for revert reason and bubble it up if present\n if (returnData.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n // solhint-disable-next-line no-inline-assembly\n assembly {\n let returndata_size := mload(returnData)\n revert(add(32, returnData), returndata_size)\n }\n } else {\n revert MulticallTarget__UndeterminedRevert();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// contracts/libs/BridgeTransactionV2.sol\n\n// solhint-disable no-inline-assembly\nlibrary BridgeTransactionV2Lib {\n uint16 internal constant VERSION = 2;\n\n // Offsets of the fields in the packed BridgeTransactionV2 struct\n // uint16 version [000 .. 002)\n // uint32 originChainId [002 .. 006)\n // uint32 destChainId [006 .. 010)\n // address originSender [010 .. 030)\n // address destRecipient [030 .. 050)\n // address originToken [050 .. 070)\n // address destToken [070 .. 090)\n // uint256 originAmount [090 .. 122)\n // uint256 destAmount [122 .. 154)\n // uint256 originFeeAmount [154 .. 186)\n // uint256 deadline [186 .. 218)\n // uint256 nonce [218 .. 250)\n // address exclusivityRelayer [250 .. 270)\n // uint256 exclusivityEndTime [270 .. 302)\n // uint256 zapNative [302 .. 334)\n // bytes zapData [334 .. ***)\n\n // forgefmt: disable-start\n uint256 private constant OFFSET_ORIGIN_CHAIN_ID = 2;\n uint256 private constant OFFSET_DEST_CHAIN_ID = 6;\n uint256 private constant OFFSET_ORIGIN_SENDER = 10;\n uint256 private constant OFFSET_DEST_RECIPIENT = 30;\n uint256 private constant OFFSET_ORIGIN_TOKEN = 50;\n uint256 private constant OFFSET_DEST_TOKEN = 70;\n uint256 private constant OFFSET_ORIGIN_AMOUNT = 90;\n uint256 private constant OFFSET_DEST_AMOUNT = 122;\n uint256 private constant OFFSET_ORIGIN_FEE_AMOUNT = 154;\n uint256 private constant OFFSET_DEADLINE = 186;\n uint256 private constant OFFSET_NONCE = 218;\n uint256 private constant OFFSET_EXCLUSIVITY_RELAYER = 250;\n uint256 private constant OFFSET_EXCLUSIVITY_END_TIME = 270;\n uint256 private constant OFFSET_ZAP_NATIVE = 302;\n uint256 private constant OFFSET_ZAP_DATA = 334;\n // forgefmt: disable-end\n\n error BridgeTransactionV2__InvalidEncodedTx();\n error BridgeTransactionV2__UnsupportedVersion(uint16 version);\n\n /// @notice Validates that the encoded transaction is a tightly packed encoded payload for BridgeTransactionV2.\n /// @dev Checks the minimum length and the version, use this function before decoding any of the fields.\n function validateV2(bytes calldata encodedTx) internal pure {\n // Check the minimum length: must at least include all static fields.\n if (encodedTx.length \u003c OFFSET_ZAP_DATA) revert BridgeTransactionV2__InvalidEncodedTx();\n // Once we validated the length, we can be sure that the version field is present.\n uint16 version_ = version(encodedTx);\n if (version_ != VERSION) revert BridgeTransactionV2__UnsupportedVersion(version_);\n }\n\n /// @notice Encodes the BridgeTransactionV2 struct by tightly packing the fields.\n /// @dev `abi.decode` will not work as a result of the tightly packed fields. Use `decodeV2` to decode instead.\n function encodeV2(IFastBridgeV2.BridgeTransactionV2 memory bridgeTx) internal pure returns (bytes memory) {\n // We split the encoding into two parts to avoid stack-too-deep error\n bytes memory firstPart = abi.encodePacked(\n VERSION,\n bridgeTx.originChainId,\n bridgeTx.destChainId,\n bridgeTx.originSender,\n bridgeTx.destRecipient,\n bridgeTx.originToken,\n bridgeTx.destToken,\n bridgeTx.originAmount\n );\n return abi.encodePacked(\n firstPart,\n bridgeTx.destAmount,\n bridgeTx.originFeeAmount,\n // Note: we skip the deprecated `sendChainGas` flag, which was present in BridgeTransaction V1\n bridgeTx.deadline,\n bridgeTx.nonce,\n // New V2 fields: exclusivity\n bridgeTx.exclusivityRelayer,\n bridgeTx.exclusivityEndTime,\n // New V2 fields: Zap\n bridgeTx.zapNative,\n bridgeTx.zapData\n );\n }\n\n /// @notice Decodes the BridgeTransactionV2 struct from the encoded transaction.\n /// @dev Encoded BridgeTransactionV2 struct must be tightly packed.\n /// Use `validateV2` before decoding to ensure the encoded transaction is valid.\n function decodeV2(bytes calldata encodedTx)\n internal\n pure\n returns (IFastBridgeV2.BridgeTransactionV2 memory bridgeTx)\n {\n bridgeTx.originChainId = originChainId(encodedTx);\n bridgeTx.destChainId = destChainId(encodedTx);\n bridgeTx.originSender = originSender(encodedTx);\n bridgeTx.destRecipient = destRecipient(encodedTx);\n bridgeTx.originToken = originToken(encodedTx);\n bridgeTx.destToken = destToken(encodedTx);\n bridgeTx.originAmount = originAmount(encodedTx);\n bridgeTx.destAmount = destAmount(encodedTx);\n bridgeTx.originFeeAmount = originFeeAmount(encodedTx);\n bridgeTx.deadline = deadline(encodedTx);\n bridgeTx.nonce = nonce(encodedTx);\n bridgeTx.exclusivityRelayer = exclusivityRelayer(encodedTx);\n bridgeTx.exclusivityEndTime = exclusivityEndTime(encodedTx);\n bridgeTx.zapNative = zapNative(encodedTx);\n bridgeTx.zapData = zapData(encodedTx);\n }\n\n /// @notice Extracts the version from the encoded transaction.\n function version(bytes calldata encodedTx) internal pure returns (uint16 version_) {\n // Load 32 bytes from the start and shift it 240 bits to the right to get the highest 16 bits.\n assembly {\n version_ := shr(240, calldataload(encodedTx.offset))\n }\n }\n\n /// @notice Extracts the origin chain ID from the encoded transaction.\n function originChainId(bytes calldata encodedTx) internal pure returns (uint32 originChainId_) {\n // Load 32 bytes from the offset and shift it 224 bits to the right to get the highest 32 bits.\n assembly {\n originChainId_ := shr(224, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_CHAIN_ID)))\n }\n }\n\n /// @notice Extracts the destination chain ID from the encoded transaction.\n function destChainId(bytes calldata encodedTx) internal pure returns (uint32 destChainId_) {\n // Load 32 bytes from the offset and shift it 224 bits to the right to get the highest 32 bits.\n assembly {\n destChainId_ := shr(224, calldataload(add(encodedTx.offset, OFFSET_DEST_CHAIN_ID)))\n }\n }\n\n /// @notice Extracts the origin sender from the encoded transaction.\n function originSender(bytes calldata encodedTx) internal pure returns (address originSender_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n originSender_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_SENDER)))\n }\n }\n\n /// @notice Extracts the destination recipient from the encoded transaction.\n function destRecipient(bytes calldata encodedTx) internal pure returns (address destRecipient_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n destRecipient_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_DEST_RECIPIENT)))\n }\n }\n\n /// @notice Extracts the origin token from the encoded transaction.\n function originToken(bytes calldata encodedTx) internal pure returns (address originToken_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n originToken_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_TOKEN)))\n }\n }\n\n /// @notice Extracts the destination token from the encoded transaction.\n function destToken(bytes calldata encodedTx) internal pure returns (address destToken_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n destToken_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_DEST_TOKEN)))\n }\n }\n\n /// @notice Extracts the origin amount from the encoded transaction.\n function originAmount(bytes calldata encodedTx) internal pure returns (uint256 originAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n originAmount_ := calldataload(add(encodedTx.offset, OFFSET_ORIGIN_AMOUNT))\n }\n }\n\n /// @notice Extracts the destination amount from the encoded transaction.\n function destAmount(bytes calldata encodedTx) internal pure returns (uint256 destAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n destAmount_ := calldataload(add(encodedTx.offset, OFFSET_DEST_AMOUNT))\n }\n }\n\n /// @notice Extracts the origin fee amount from the encoded transaction.\n function originFeeAmount(bytes calldata encodedTx) internal pure returns (uint256 originFeeAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n originFeeAmount_ := calldataload(add(encodedTx.offset, OFFSET_ORIGIN_FEE_AMOUNT))\n }\n }\n\n /// @notice Extracts the deadline from the encoded transaction.\n function deadline(bytes calldata encodedTx) internal pure returns (uint256 deadline_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n deadline_ := calldataload(add(encodedTx.offset, OFFSET_DEADLINE))\n }\n }\n\n /// @notice Extracts the nonce from the encoded transaction.\n function nonce(bytes calldata encodedTx) internal pure returns (uint256 nonce_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n nonce_ := calldataload(add(encodedTx.offset, OFFSET_NONCE))\n }\n }\n\n /// @notice Extracts the exclusivity relayer from the encoded transaction.\n function exclusivityRelayer(bytes calldata encodedTx) internal pure returns (address exclusivityRelayer_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n exclusivityRelayer_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_EXCLUSIVITY_RELAYER)))\n }\n }\n\n /// @notice Extracts the exclusivity end time from the encoded transaction.\n function exclusivityEndTime(bytes calldata encodedTx) internal pure returns (uint256 exclusivityEndTime_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n exclusivityEndTime_ := calldataload(add(encodedTx.offset, OFFSET_EXCLUSIVITY_END_TIME))\n }\n }\n\n /// @notice Extracts the Zap's native value from the encoded transaction.\n function zapNative(bytes calldata encodedTx) internal pure returns (uint256 zapNative_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n zapNative_ := calldataload(add(encodedTx.offset, OFFSET_ZAP_NATIVE))\n }\n }\n\n /// @notice Extracts the Zap's data from the encoded transaction.\n function zapData(bytes calldata encodedTx) internal pure returns (bytes calldata zapData_) {\n zapData_ = encodedTx[OFFSET_ZAP_DATA:];\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/AdminV2.sol\n\n// ════════════════════════════════════════════════ INTERFACES ═════════════════════════════════════════════════════\n\n// ═════════════════════════════════════════════ EXTERNAL IMPORTS ══════════════════════════════════════════════════\n\n/// @title AdminV2\n/// @notice Provides administrative functions and controls for managing the FastBridgeV2 contract,\n/// including access control and configuration settings.\ncontract AdminV2 is AccessControlEnumerable, IAdminV2, IAdminV2Errors {\n using SafeERC20 for IERC20;\n\n /// @notice The address reserved for the native gas token (ETH on Ethereum and most L2s, AVAX on Avalanche, etc.).\n address public constant NATIVE_GAS_TOKEN = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice The role identifier for the Quoter API's off-chain authentication.\n /// @dev Only addresses with this role can post FastBridge quotes to the API.\n bytes32 public constant QUOTER_ROLE = keccak256(\"QUOTER_ROLE\");\n\n /// @notice The role identifier for the Prover's on-chain authentication in FastBridge.\n /// @dev Only addresses with this role can provide proofs that a FastBridge request has been relayed.\n bytes32 public constant PROVER_ROLE = keccak256(\"PROVER_ROLE\");\n\n /// @notice The role identifier for the Guard's on-chain authentication in FastBridge.\n /// @dev Only addresses with this role can dispute submitted relay proofs during the dispute period.\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n\n /// @notice The role identifier for the Canceler's on-chain authentication in FastBridge.\n /// @dev Only addresses with this role can cancel a FastBridge transaction without the cancel delay.\n bytes32 public constant CANCELER_ROLE = keccak256(\"CANCELER_ROLE\");\n\n /// @notice The role identifier for the Governor's on-chain administrative authority.\n /// @dev Only addresses with this role can perform administrative tasks within the contract.\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n /// @notice The denominator for fee rates, representing 100%.\n uint256 public constant FEE_BPS = 1e6;\n /// @notice The maximum protocol fee rate: 1% of the origin amount.\n uint256 public constant FEE_RATE_MAX = 0.01e6;\n\n /// @notice The minimum cancel delay that can be set by the governor.\n uint256 public constant MIN_CANCEL_DELAY = 1 hours;\n /// @notice The default cancel delay set during contract deployment.\n uint256 public constant DEFAULT_CANCEL_DELAY = 1 days;\n\n /// @notice The protocol fee rate taken on the origin amount deposited in the origin chain.\n uint256 public protocolFeeRate;\n\n /// @notice The accumulated protocol fee amounts.\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice The delay period after which a transaction can be permissionlessly cancelled.\n uint256 public cancelDelay;\n\n /// @notice This variable is deprecated and should not be used.\n /// @dev Use ZapNative V2 requests instead.\n uint256 public immutable chainGasAmount = 0;\n\n constructor(address defaultAdmin) {\n _grantRole(DEFAULT_ADMIN_ROLE, defaultAdmin);\n _setCancelDelay(DEFAULT_CANCEL_DELAY);\n }\n\n /// @inheritdoc IAdminV2\n function setCancelDelay(uint256 newCancelDelay) external onlyRole(GOVERNOR_ROLE) {\n _setCancelDelay(newCancelDelay);\n }\n\n /// @inheritdoc IAdminV2\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n if (newFeeRate \u003e FEE_RATE_MAX) revert FeeRateAboveMax();\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n /// @inheritdoc IAdminV2\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n // Early exit if no accumulated fees.\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return;\n // Reset the accumulated fees first.\n protocolFees[token] = 0;\n emit FeesSwept(token, recipient, feeAmount);\n // Sweep the fees as the last transaction action.\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(recipient), feeAmount);\n } else {\n IERC20(token).safeTransfer(recipient, feeAmount);\n }\n }\n\n /// @notice Internal logic to set the cancel delay. Security checks are performed outside of this function.\n /// @dev This function is marked as private to prevent child contracts from calling it directly.\n function _setCancelDelay(uint256 newCancelDelay) private {\n if (newCancelDelay \u003c MIN_CANCEL_DELAY) revert CancelDelayBelowMin();\n uint256 oldCancelDelay = cancelDelay;\n cancelDelay = newCancelDelay;\n emit CancelDelayUpdated(oldCancelDelay, newCancelDelay);\n }\n}\n\n// contracts/FastBridgeV2.sol\n\n// ════════════════════════════════════════════════ INTERFACES ═════════════════════════════════════════════════════\n\n// ═════════════════════════════════════════════ INTERNAL IMPORTS ══════════════════════════════════════════════════\n\n// ═════════════════════════════════════════════ EXTERNAL IMPORTS ══════════════════════════════════════════════════\n\n/// @title FastBridgeV2\n/// @notice Core component of the SynapseRFQ protocol, enabling Relayers (Solvers) to fulfill bridge requests.\n/// Supports ERC20 and native gas tokens, along with the Zap feature for executing actions on the destination chain.\n/// Users interact with the off-chain Quoter API to obtain a current quote for a bridge transaction.\n/// They then submit the bridge request with the quote to this contract, depositing their assets in escrow.\n/// Relayers can fulfill requests by relaying them to the destination chain and must prove fulfillment to claim funds.\n/// Guards monitor proofs and can dispute discrepancies.\n/// Users can reclaim funds by cancelling their requests if it has not been fulfilled within the specified deadline.\ncontract FastBridgeV2 is AdminV2, MulticallTarget, IFastBridgeV2, IFastBridgeV2Errors {\n using BridgeTransactionV2Lib for bytes;\n using SafeERC20 for IERC20;\n\n /// @notice The duration of the dispute period for relayed transactions.\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice The minimum required time between transaction request and deadline.\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n /// @notice The maximum allowed length for zapData.\n uint256 public constant MAX_ZAP_DATA_LENGTH = 2 ** 16 - 1;\n\n /// @notice Maps transaction IDs to bridge details (status, destination chain ID, proof timestamp, and relayer).\n /// Note: this is only stored for transactions having local chain as the origin chain.\n mapping(bytes32 =\u003e BridgeTxDetails) public bridgeTxDetails;\n /// @notice Maps transaction IDs to relay details (block number, block timestamp, and relayer).\n /// Note: this is only stored for transactions having local chain as the destination chain.\n mapping(bytes32 =\u003e BridgeRelay) public bridgeRelayDetails;\n /// @notice Maps sender addresses to their unique bridge nonce.\n mapping(address =\u003e uint256) public senderNonces;\n\n /// @notice This variable is deprecated and should not be used.\n /// @dev Replaced by senderNonces.\n uint256 public immutable nonce = 0;\n /// @notice The block number at which this contract was deployed.\n uint256 public immutable deployBlock;\n\n /// @notice Initializes the FastBridgeV2 contract with the provided default admin,\n /// sets the default cancel delay, and records the deploy block number.\n constructor(address defaultAdmin) AdminV2(defaultAdmin) {\n deployBlock = block.number;\n }\n\n // ══════════════════════════════════════ EXTERNAL MUTABLE (USER FACING) ═══════════════════════════════════════════\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n bridgeV2({\n params: params,\n paramsV2: BridgeParamsV2({\n quoteRelayer: address(0),\n quoteExclusivitySeconds: 0,\n quoteId: bytes(\"\"),\n zapNative: 0,\n zapData: bytes(\"\")\n })\n });\n }\n\n /// Note: this function is deprecated and will be removed in a future version.\n /// @dev Replaced by `cancel`.\n /// @inheritdoc IFastBridge\n function refund(bytes calldata request) external {\n cancelV2(request);\n }\n\n // ══════════════════════════════════════ EXTERNAL MUTABLE (AGENT FACING) ══════════════════════════════════════════\n\n /// @inheritdoc IFastBridge\n function relay(bytes calldata request) external payable {\n // `relay` override will validate the request.\n relayV2({request: request, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes calldata request, bytes32 destTxHash) external {\n request.validateV2();\n proveV2({transactionId: keccak256(request), destTxHash: destTxHash, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridgeV2\n function claimV2(bytes calldata request) external {\n // `claim` override will validate the request.\n claim({request: request, to: address(0)});\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n // Aggregate the read operations from the same storage slot.\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n address disputedRelayer = $.proofRelayer;\n BridgeStatus status = $.status;\n uint56 proofBlockTimestamp = $.proofBlockTimestamp;\n\n // Can only dispute a RELAYER_PROVED transaction within the dispute period.\n if (status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(proofBlockTimestamp) \u003e DISPUTE_PERIOD) {\n revert DisputePeriodPassed();\n }\n\n // Update status to REQUESTED and delete the disputed proof details.\n // Note: these are storage writes.\n $.status = BridgeStatus.REQUESTED;\n $.proofRelayer = address(0);\n $.proofBlockTimestamp = 0;\n\n emit BridgeProofDisputed(transactionId, disputedRelayer);\n }\n\n // ══════════════════════════════════════════════ EXTERNAL VIEWS ═══════════════════════════════════════════════════\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n // The correct relayer can only claim a RELAYER_PROVED transaction after the dispute period.\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n if ($.status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if ($.proofRelayer != relayer) revert SenderIncorrect();\n\n return _timeSince($.proofBlockTimestamp) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n /// @dev This method is added to achieve backwards compatibility with decoding requests into V1 structs:\n /// - `zapNative` is partially reported as a zero/non-zero flag\n /// - `zapData` is ignored\n /// In order to process all kinds of requests use getBridgeTransactionV2 instead.\n function getBridgeTransaction(bytes calldata request) external view returns (BridgeTransaction memory) {\n // Try decoding into V2 struct first. This will revert if V1 struct is passed.\n try this.getBridgeTransactionV2(request) returns (BridgeTransactionV2 memory txV2) {\n // Note: we entirely ignore the zapData field, as it was not present in V1.\n return BridgeTransaction({\n originChainId: txV2.originChainId,\n destChainId: txV2.destChainId,\n originSender: txV2.originSender,\n destRecipient: txV2.destRecipient,\n originToken: txV2.originToken,\n destToken: txV2.destToken,\n originAmount: txV2.originAmount,\n destAmount: txV2.destAmount,\n originFeeAmount: txV2.originFeeAmount,\n sendChainGas: txV2.zapNative != 0,\n deadline: txV2.deadline,\n nonce: txV2.nonce\n });\n } catch {\n // Fallback to V1 struct.\n return abi.decode(request, (BridgeTransaction));\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function getBridgeTransactionV2(bytes calldata request) external pure returns (BridgeTransactionV2 memory) {\n request.validateV2();\n return BridgeTransactionV2Lib.decodeV2(request);\n }\n\n // ═══════════════════════════════════════ PUBLIC MUTABLE (USER FACING) ════════════════════════════════════════════\n\n /// @inheritdoc IFastBridgeV2\n function bridgeV2(BridgeParams memory params, BridgeParamsV2 memory paramsV2) public payable {\n // If relayer exclusivity is not intended for this bridge, set exclusivityEndTime to static zero.\n // Otherwise, set exclusivity to expire at the current block ts offset by quoteExclusivitySeconds.\n int256 exclusivityEndTime = 0;\n if (paramsV2.quoteRelayer != address(0)) {\n exclusivityEndTime = int256(block.timestamp) + paramsV2.quoteExclusivitySeconds;\n }\n _validateBridgeParams(params, paramsV2, exclusivityEndTime);\n\n // Transfer tokens to bridge contract. We use the actual transferred amount in case of transfer fees.\n uint256 originAmount = _takeBridgedUserAsset(params.originToken, params.originAmount);\n\n // Track the amount of origin token owed to protocol.\n uint256 originFeeAmount = 0;\n if (protocolFeeRate \u003e 0) {\n originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n // The Relayer filling this request will be paid the originAmount after fees.\n // Note: the protocol fees will be accumulated only when the Relayer claims the origin collateral.\n originAmount -= originFeeAmount;\n }\n\n // Hash the bridge request and set the initial status to REQUESTED.\n bytes memory request = BridgeTransactionV2Lib.encodeV2(\n BridgeTransactionV2({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n deadline: params.deadline,\n // Increment the sender's nonce on every bridge.\n nonce: senderNonces[params.sender]++,\n exclusivityRelayer: paramsV2.quoteRelayer,\n // We checked exclusivityEndTime to be in range [0 .. params.deadline] above, so can safely cast.\n exclusivityEndTime: uint256(exclusivityEndTime),\n zapNative: paramsV2.zapNative,\n zapData: paramsV2.zapData\n })\n );\n bytes32 transactionId = keccak256(request);\n // Note: the tx status will be updated throughout the tx lifecycle, while destChainId is set once here.\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n bridgeTxDetails[transactionId].destChainId = params.dstChainId;\n\n emit BridgeRequested({\n transactionId: transactionId,\n sender: params.sender,\n request: request,\n destChainId: params.dstChainId,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n sendChainGas: paramsV2.zapNative != 0\n });\n emit BridgeQuoteDetails(transactionId, paramsV2.quoteId);\n }\n\n /// @inheritdoc IFastBridgeV2\n function cancelV2(bytes calldata request) public {\n // Decode the request and check that it could be cancelled.\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n\n // Can only cancel a REQUESTED transaction after its deadline expires.\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n if ($.status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n\n // Permissionless cancel is only allowed after `cancelDelay` on top of the deadline.\n uint256 deadline = request.deadline();\n if (!hasRole(CANCELER_ROLE, msg.sender)) deadline += cancelDelay;\n if (block.timestamp \u003c= deadline) revert DeadlineNotExceeded();\n\n // Update status to REFUNDED.\n // Note: this is a storage write.\n $.status = BridgeStatus.REFUNDED;\n\n // Return the full amount (collateral + protocol fees) to the original sender.\n // The protocol fees are only accumulated when the transaction is claimed, so we don't need to update them here.\n address to = request.originSender();\n address token = request.originToken();\n uint256 amount = request.originAmount() + request.originFeeAmount();\n\n // Emit the event before any external calls.\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n\n // Return the funds to the original sender as last transaction action.\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(to), amount);\n } else {\n IERC20(token).safeTransfer(to, amount);\n }\n }\n\n // ═══════════════════════════════════════ PUBLIC MUTABLE (AGENT FACING) ═══════════════════════════════════════════\n\n /// @inheritdoc IFastBridgeV2\n function relayV2(bytes calldata request, address relayer) public payable {\n // Decode the request and check that it could be relayed.\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n _validateRelayParams(request, transactionId, relayer);\n\n // Mark the bridge request as relayed by saving the relayer and the block details.\n bridgeRelayDetails[transactionId].blockNumber = uint48(block.number);\n bridgeRelayDetails[transactionId].blockTimestamp = uint48(block.timestamp);\n bridgeRelayDetails[transactionId].relayer = relayer;\n\n // Transfer tokens to recipient on destination chain and trigger Zap if requested.\n address to = request.destRecipient();\n address token = request.destToken();\n uint256 amount = request.destAmount();\n uint256 zapNative = request.zapNative();\n\n // Emit the event before any external calls.\n emit BridgeRelayed({\n transactionId: transactionId,\n relayer: relayer,\n to: to,\n originChainId: request.originChainId(),\n originToken: request.originToken(),\n destToken: token,\n originAmount: request.originAmount(),\n destAmount: amount,\n chainGasAmount: zapNative\n });\n\n // All state changes have been done at this point, can proceed to the external calls.\n // This follows the checks-effects-interactions pattern to mitigate potential reentrancy attacks.\n if (token == NATIVE_GAS_TOKEN) {\n // For the native gas token, additional zapNative is not allowed.\n if (zapNative != 0) revert ZapNativeNotSupported();\n // Check that the correct msg.value was sent.\n if (msg.value != amount) revert MsgValueIncorrect();\n // Don't do a native transfer yet: we will handle it alongside the Zap below.\n } else {\n // For ERC20s, we check that the correct msg.value was sent.\n if (msg.value != zapNative) revert MsgValueIncorrect();\n // We need to transfer the tokens from the Relayer to the recipient first before performing an\n // optional post-transfer Zap.\n IERC20(token).safeTransferFrom(msg.sender, to, amount);\n }\n // At this point we have done:\n // - Transferred the requested amount of ERC20 tokens to the recipient.\n // At this point we have confirmed:\n // - For ERC20s: msg.value matches the requested zapNative amount.\n // - For the native gas token: msg.value matches the requested destAmount.\n // Remaining optional things to do:\n // - Forward the full msg.value to the recipient (if non-zero).\n // - Trigger a Zap (if zapData is present).\n bytes calldata zapData = request.zapData();\n if (zapData.length != 0) {\n // Zap Data is present: Zap has been requested by the recipient. Trigger it forwarding the full msg.value.\n _triggerZapWithChecks({recipient: to, token: token, amount: amount, zapData: zapData});\n // Note: if token has a fee on transfers, the recipient will have received less than `amount`.\n // This is a very niche edge case and should be handled by the recipient contract.\n } else if (msg.value != 0) {\n // Zap Data is missing, but msg.value was sent. This could happen in two different cases:\n // - Relay with the native gas token is happening.\n // - Relay with ERC20 is happening, with a `zapNative \u003e 0` request.\n // In both cases, we need to transfer the full msg.value to the recipient.\n Address.sendValue(payable(to), msg.value);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function proveV2(bytes32 transactionId, bytes32 destTxHash, address relayer) public onlyRole(PROVER_ROLE) {\n // Can only prove a REQUESTED transaction.\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n if ($.status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n\n // Update status to RELAYER_PROVED and store the proof details.\n // Note: these are storage writes.\n $.status = BridgeStatus.RELAYER_PROVED;\n $.proofBlockTimestamp = uint56(block.timestamp);\n $.proofRelayer = relayer;\n\n emit BridgeProofProvided(transactionId, relayer, destTxHash);\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes calldata request, address to) public {\n // Decode the request and check that it could be claimed.\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n\n // Aggregate the read operations from the same storage slot.\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n address proofRelayer = $.proofRelayer;\n BridgeStatus status = $.status;\n uint56 proofBlockTimestamp = $.proofBlockTimestamp;\n\n // Can only claim a RELAYER_PROVED transaction after the dispute period.\n if (status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(proofBlockTimestamp) \u003c= DISPUTE_PERIOD) revert DisputePeriodNotPassed();\n if (to == address(0)) {\n // Anyone could claim the funds to the proven relayer on their behalf.\n to = proofRelayer;\n } else if (proofRelayer != msg.sender) {\n // Only the proven relayer could specify an address to claim the funds to.\n revert SenderIncorrect();\n }\n\n // Update status to RELAYER_CLAIMED and transfer the origin collateral to the specified claim address.\n // Note: this is a storage write.\n $.status = BridgeStatus.RELAYER_CLAIMED;\n\n // Accumulate protocol fees if origin fee amount exists.\n address token = request.originToken();\n uint256 amount = request.originAmount();\n uint256 originFeeAmount = request.originFeeAmount();\n if (originFeeAmount \u003e 0) protocolFees[token] += originFeeAmount;\n\n // Emit the event before any external calls.\n emit BridgeDepositClaimed(transactionId, proofRelayer, to, token, amount);\n\n // Complete the relayer claim as the last transaction action.\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(to), amount);\n } else {\n IERC20(token).safeTransfer(to, amount);\n }\n }\n\n // ═══════════════════════════════════════════════ PUBLIC VIEWS ════════════════════════════════════════════════════\n\n /// @inheritdoc IFastBridgeV2\n function bridgeStatuses(bytes32 transactionId) public view returns (BridgeStatus status) {\n return bridgeTxDetails[transactionId].status;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeProofs(bytes32 transactionId) public view returns (uint96 timestamp, address relayer) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n timestamp = $.proofBlockTimestamp;\n relayer = $.proofRelayer;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeRelays(bytes32 transactionId) public view returns (bool) {\n // This transaction has been relayed if the relayer address is recorded.\n return bridgeRelayDetails[transactionId].relayer != address(0);\n }\n\n // ═════════════════════════════════════════════ INTERNAL METHODS ══════════════════════════════════════════════════\n\n /// @notice Takes the bridged asset from the user into FastBridgeV2 custody. The asset will later be\n /// claimed by the relayer who completed the relay on the destination chain, or returned to the user\n /// via the cancel function if no relay is completed.\n function _takeBridgedUserAsset(address token, uint256 amount) internal returns (uint256 amountTaken) {\n if (token == NATIVE_GAS_TOKEN) {\n // For the native gas token, we just need to check that the supplied msg.value is correct.\n // Supplied `msg.value` is already in FastBridgeV2 custody.\n if (amount != msg.value) revert MsgValueIncorrect();\n amountTaken = msg.value;\n } else {\n // For ERC20s, token is explicitly transferred from the user to FastBridgeV2.\n // We don't allow non-zero `msg.value` to avoid extra funds from being stuck in FastBridgeV2.\n if (msg.value != 0) revert MsgValueIncorrect();\n // Throw an explicit error if the provided token address is not a contract.\n if (token.code.length == 0) revert TokenNotContract();\n\n // Use the balance difference as the amount taken in case of fee on transfer tokens.\n amountTaken = IERC20(token).balanceOf(address(this));\n IERC20(token).safeTransferFrom(msg.sender, address(this), amount);\n amountTaken = IERC20(token).balanceOf(address(this)) - amountTaken;\n }\n }\n\n /// @notice Calls the recipient's hook function with the specified zapData and validates\n /// the returned value.\n function _triggerZapWithChecks(address recipient, address token, uint256 amount, bytes calldata zapData) internal {\n // Call the recipient's hook function with the specified zapData, bubbling any revert messages.\n bytes memory returnData = Address.functionCallWithValue({\n target: recipient,\n data: abi.encodeCall(IZapRecipient.zap, (token, amount, zapData)),\n // Note: see `relay()` for reasoning behind passing msg.value.\n value: msg.value\n });\n\n // Explicit revert if no return data at all.\n if (returnData.length == 0) revert RecipientNoReturnValue();\n // Check that exactly a single return value was returned.\n if (returnData.length != 32) revert RecipientIncorrectReturnValue();\n // Return value should be abi-encoded hook function selector.\n if (bytes32(returnData) != bytes32(IZapRecipient.zap.selector)) {\n revert RecipientIncorrectReturnValue();\n }\n }\n\n /// @notice Calculates the time elapsed since a proof was submitted.\n /// @dev The proof.timestamp stores block timestamps as uint56 for gas optimization.\n /// _timeSince(proof) handles timestamp rollover when block.timestamp \u003e type(uint56).max but\n /// proof.timestamp \u003c type(uint56).max via an unchecked statement.\n /// @param proofBlockTimestamp The block timestamp when the proof was submitted.\n /// @return delta The time elapsed since proof submission.\n function _timeSince(uint56 proofBlockTimestamp) internal view returns (uint256 delta) {\n unchecked {\n delta = uint56(block.timestamp) - proofBlockTimestamp;\n }\n }\n\n /// @notice Validates all parameters required for a bridge transaction.\n /// @dev This function's complexity cannot be reduced due to the number of required checks,\n /// so we disable the code-complexity rule.\n // solhint-disable-next-line code-complexity\n function _validateBridgeParams(\n BridgeParams memory params,\n BridgeParamsV2 memory paramsV2,\n int256 exclusivityEndTime\n )\n internal\n view\n {\n // Check V1 (legacy) params.\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.sender == address(0) || params.to == address(0)) revert ZeroAddress();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n\n // Check V2 params.\n if (paramsV2.zapData.length \u003e MAX_ZAP_DATA_LENGTH) revert ZapDataLengthAboveMax();\n if (paramsV2.zapNative != 0 \u0026\u0026 params.destToken == NATIVE_GAS_TOKEN) {\n revert ZapNativeNotSupported();\n }\n\n // exclusivityEndTime must be in range [0 .. params.deadline].\n if (exclusivityEndTime \u003c 0 || exclusivityEndTime \u003e int256(params.deadline)) {\n revert ExclusivityParamsIncorrect();\n }\n }\n\n /// @notice Validates all parameters required for a relay transaction.\n function _validateRelayParams(bytes calldata request, bytes32 transactionId, address relayer) internal view {\n if (relayer == address(0)) revert ZeroAddress();\n // Check that the transaction has not been relayed yet and is for the current chain.\n if (bridgeRelays(transactionId)) revert TransactionRelayed();\n if (request.destChainId() != block.chainid) revert ChainIncorrect();\n // Check that the deadline for relay to happen has not passed yet.\n if (block.timestamp \u003e request.deadline()) revert DeadlineExceeded();\n // Check the exclusivity period, if it was specified and is still ongoing.\n address exclRelayer = request.exclusivityRelayer();\n if (exclRelayer != address(0) \u0026\u0026 exclRelayer != relayer \u0026\u0026 block.timestamp \u003c= request.exclusivityEndTime()) {\n revert ExclusivityPeriodNotPassed();\n }\n }\n}\n","language":"Solidity","languageVersion":"0.8.24","compilerVersion":"0.8.24","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"","srcMapRuntime":"","abiDefinition":[{"inputs":[],"name":"AccessControlBadConfirmation","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"bytes32","name":"neededRole","type":"bytes32"}],"name":"AccessControlUnauthorizedAccount","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"previousAdminRole","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"newAdminRole","type":"bytes32"}],"name":"RoleAdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleRevoked","type":"event"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleAdmin","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"grantRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"hasRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"callerConfirmation","type":"address"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"revokeRole","outputs":[],"stateMutability":"nonpayable","type":"function"}],"userDoc":{"kind":"user","methods":{},"version":1},"developerDoc":{"details":"External interface of AccessControl declared to support ERC165 detection.","errors":{"AccessControlBadConfirmation()":[{"details":"The caller of a function is not the expected one. NOTE: Don't confuse with {AccessControlUnauthorizedAccount}."}],"AccessControlUnauthorizedAccount(address,bytes32)":[{"details":"The `account` is missing a role."}]},"events":{"RoleAdminChanged(bytes32,bytes32,bytes32)":{"details":"Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole` `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite {RoleAdminChanged} not being emitted signaling this."},"RoleGranted(bytes32,address,address)":{"details":"Emitted when `account` is granted `role`. `sender` is the account that originated the contract call, an admin role bearer except when using {AccessControl-_setupRole}."},"RoleRevoked(bytes32,address,address)":{"details":"Emitted when `account` is revoked `role`. `sender` is the account that originated the contract call: - if using `revokeRole`, it is the admin role bearer - if using `renounceRole`, it is the role bearer (i.e. `account`)"}},"kind":"dev","methods":{"getRoleAdmin(bytes32)":{"details":"Returns the admin role that controls `role`. See {grantRole} and {revokeRole}. To change a role's admin, use {AccessControl-_setRoleAdmin}."},"grantRole(bytes32,address)":{"details":"Grants `role` to `account`. If `account` had not been already granted `role`, emits a {RoleGranted} event. Requirements: - the caller must have ``role``'s admin role."},"hasRole(bytes32,address)":{"details":"Returns `true` if `account` has been granted `role`."},"renounceRole(bytes32,address)":{"details":"Revokes `role` from the calling account. Roles are often managed via {grantRole} and {revokeRole}: this function's purpose is to provide a mechanism for accounts to lose their privileges if they are compromised (such as when a trusted device is misplaced). If the calling account had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must be `callerConfirmation`."},"revokeRole(bytes32,address)":{"details":"Revokes `role` from `account`. If `account` had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must have ``role``'s admin role."}},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[],\"name\":\"AccessControlBadConfirmation\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"neededRole\",\"type\":\"bytes32\"}],\"name\":\"AccessControlUnauthorizedAccount\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"previousAdminRole\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"newAdminRole\",\"type\":\"bytes32\"}],\"name\":\"RoleAdminChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleGranted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleRevoked\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"}],\"name\":\"getRoleAdmin\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"grantRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"hasRole\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"callerConfirmation\",\"type\":\"address\"}],\"name\":\"renounceRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"revokeRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"details\":\"External interface of AccessControl declared to support ERC165 detection.\",\"errors\":{\"AccessControlBadConfirmation()\":[{\"details\":\"The caller of a function is not the expected one. NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\"}],\"AccessControlUnauthorizedAccount(address,bytes32)\":[{\"details\":\"The `account` is missing a role.\"}]},\"events\":{\"RoleAdminChanged(bytes32,bytes32,bytes32)\":{\"details\":\"Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole` `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite {RoleAdminChanged} not being emitted signaling this.\"},\"RoleGranted(bytes32,address,address)\":{\"details\":\"Emitted when `account` is granted `role`. `sender` is the account that originated the contract call, an admin role bearer except when using {AccessControl-_setupRole}.\"},\"RoleRevoked(bytes32,address,address)\":{\"details\":\"Emitted when `account` is revoked `role`. `sender` is the account that originated the contract call: - if using `revokeRole`, it is the admin role bearer - if using `renounceRole`, it is the role bearer (i.e. `account`)\"}},\"kind\":\"dev\",\"methods\":{\"getRoleAdmin(bytes32)\":{\"details\":\"Returns the admin role that controls `role`. See {grantRole} and {revokeRole}. To change a role's admin, use {AccessControl-_setRoleAdmin}.\"},\"grantRole(bytes32,address)\":{\"details\":\"Grants `role` to `account`. If `account` had not been already granted `role`, emits a {RoleGranted} event. Requirements: - the caller must have ``role``'s admin role.\"},\"hasRole(bytes32,address)\":{\"details\":\"Returns `true` if `account` has been granted `role`.\"},\"renounceRole(bytes32,address)\":{\"details\":\"Revokes `role` from the calling account. Roles are often managed via {grantRole} and {revokeRole}: this function's purpose is to provide a mechanism for accounts to lose their privileges if they are compromised (such as when a trusted device is misplaced). If the calling account had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must be `callerConfirmation`.\"},\"revokeRole(bytes32,address)\":{\"details\":\"Revokes `role` from `account`. If `account` had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must have ``role``'s admin role.\"}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeV2.sol\":\"IAccessControl\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeV2.sol\":{\"keccak256\":\"0xaab2ee7357681726f0faf799a48ddfbf45fb4da93b69abf61c33dde92b29b74d\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://673391bff9569efc0f9bd99e0e6fece0bc8e8af1f052bb071b407b267a17b3b5\",\"dweb:/ipfs/QmdQQZ6DxpJYhfpinwU5WjLugr2f6qP8h68b5GerhSMQ4j\"]}},\"version\":1}"},"hashes":{"getRoleAdmin(bytes32)":"248a9ca3","grantRole(bytes32,address)":"2f2ff15d","hasRole(bytes32,address)":"91d14854","renounceRole(bytes32,address)":"36568abe","revokeRole(bytes32,address)":"d547741f"}},"solidity/FastBridgeV2.sol:IAccessControlEnumerable":{"code":"0x","runtime-code":"0x","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.24 ^0.8.20 ^0.8.4;\n\n// contracts/interfaces/IAdminV2.sol\n\ninterface IAdminV2 {\n event CancelDelayUpdated(uint256 oldCancelDelay, uint256 newCancelDelay);\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n /// @notice Allows the governor to set the cancel delay. The cancel delay is the time period after the transaction\n /// deadline during which a transaction can be permissionlessly cancelled if it hasn't been proven by any Relayer.\n function setCancelDelay(uint256 newCancelDelay) external;\n\n /// @notice Allows the governor to set the protocol fee rate. The protocol fee is taken from the origin\n /// amount and is only applied to completed and claimed transactions.\n /// @dev The protocol fee is abstracted away from the relayers; they always operate using the amounts after fees.\n /// The origin amount they see in the emitted log is what they get credited with.\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n /// @notice Allows the governor to withdraw the accumulated protocol fees from the contract.\n function sweepProtocolFees(address token, address recipient) external;\n}\n\n// contracts/interfaces/IAdminV2Errors.sol\n\ninterface IAdminV2Errors {\n error CancelDelayBelowMin();\n error FeeRateAboveMax();\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IFastBridgeV2Errors.sol\n\ninterface IFastBridgeV2Errors {\n error AmountIncorrect();\n error ChainIncorrect();\n error ExclusivityParamsIncorrect();\n error MsgValueIncorrect();\n error SenderIncorrect();\n error StatusIncorrect();\n error TokenNotContract();\n error ZapDataLengthAboveMax();\n error ZapNativeNotSupported();\n error ZeroAddress();\n\n error RecipientIncorrectReturnValue();\n error RecipientNoReturnValue();\n\n error DeadlineExceeded();\n error DeadlineNotExceeded();\n error DeadlineTooShort();\n error DisputePeriodNotPassed();\n error DisputePeriodPassed();\n error ExclusivityPeriodNotPassed();\n\n error TransactionRelayed();\n}\n\n// contracts/interfaces/IMulticallTarget.sol\n\n/// @notice Interface for a contract that supports multiple calls from the same caller. Inspired by MulticallV3:\n/// https://github.com/mds1/multicall/blob/master/src/Multicall3.sol\ninterface IMulticallTarget {\n struct Result {\n bool success;\n bytes returnData;\n }\n\n /// @notice Executes multiple calls to this contract in a single transaction while preserving msg.sender.\n /// Return data from the calls is discarded.\n /// @dev This method is non-payable, so only calls with msg.value of 0 can be batched.\n /// If ignoreReverts is set to true, reverted calls will be skipped.\n /// Otherwise, the entire batch will revert with the original revert reason.\n /// @param data List of ABI-encoded calldata for the calls to execute\n /// @param ignoreReverts Whether to skip calls that revert\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external;\n\n /// @notice Executes multiple calls to this contract in a single transaction while preserving msg.sender.\n /// Return data from each call is preserved.\n /// @dev This method is non-payable, so only calls with msg.value of 0 can be batched.\n /// If ignoreReverts is set to true, reverted calls will be skipped.\n /// Otherwise, the entire batch will revert with the original revert reason.\n /// @param data List of ABI-encoded calldata for the calls to execute\n /// @param ignoreReverts Whether to skip calls that revert\n /// @return results List of results from the calls, each containing (success, returnData)\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results);\n}\n\n// contracts/interfaces/IZapRecipient.sol\n\n/// @notice Interface for contracts that can perform Zap operations. Such contracts could be used as Recipients\n/// in a FastBridge transaction that includes a Zap operation. The Zap Data should include instructions on how\n/// exactly the Zap operation should be executed, which would typically include the target address and calldata\n/// to use. The exact implementation of the Zap Data encoding is up to the Recipient contract.\ninterface IZapRecipient {\n /// @notice Performs a Zap operation with the given token and amount according to the provided Zap data.\n /// @param token The address of the token being used for the Zap operation.\n /// @param amount The amount of tokens to be used.\n /// @param zapData The encoded data specifying how the Zap operation should be executed.\n /// @return The function selector to indicate successful execution.\n function zap(address token, uint256 amount, bytes memory zapData) external payable returns (bytes4);\n}\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// contracts/interfaces/IFastBridgeV2.sol\n\ninterface IFastBridgeV2 is IFastBridge {\n enum BridgeStatus {\n NULL, // Doesn't exist yet.\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n struct BridgeTxDetails {\n BridgeStatus status;\n uint32 destChainId;\n uint56 proofBlockTimestamp;\n address proofRelayer;\n }\n\n struct BridgeRelay {\n uint48 blockNumber;\n uint48 blockTimestamp;\n address relayer;\n }\n\n /// @notice New params introduced in the FastBridgeV2.\n /// We are passing fields from the older BridgeParams struct outside of this struct for backwards compatibility.\n /// Note: quoteRelayer and quoteExclusivitySeconds are either both zero (indicating no exclusivity)\n /// or both non-zero (indicating exclusivity for the given period).\n /// Note: zapNative \u003e 0 can NOT be used with destToken = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE (native token)\n /// @param quoteRelayer Relayer that provided the quote for the transaction\n /// @param quoteExclusivitySeconds Period of time the quote relayer is guaranteed exclusivity after user's deposit\n /// @param quoteId Unique quote identifier used for tracking the quote\n /// @param zapNative ETH value to send to the recipient (if any)\n /// @param zapData Parameters for the Zap to the destination recipient (if any)\n struct BridgeParamsV2 {\n address quoteRelayer;\n int256 quoteExclusivitySeconds;\n bytes quoteId;\n uint256 zapNative;\n bytes zapData;\n }\n\n /// @notice Updated bridge transaction struct to include parameters introduced in FastBridgeV2.\n /// Note: only `exclusivityRelayer` can fill such a transaction until `exclusivityEndTime`.\n struct BridgeTransactionV2 {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n // Note: sendChainGas flag from V1 is deprecated\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n address exclusivityRelayer;\n uint256 exclusivityEndTime;\n uint256 zapNative; // ETH value to send to the recipient (if any)\n bytes zapData; // data to pass for the Zap action (if any)\n }\n\n event BridgeQuoteDetails(bytes32 indexed transactionId, bytes quoteId);\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability\n /// to provide temporary exclusivity fill rights for the quote relayer.\n /// @param params The parameters required to bridge\n /// @param paramsV2 The parameters for exclusivity fill rights (optional, can be left empty)\n function bridgeV2(BridgeParams memory params, BridgeParamsV2 memory paramsV2) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function relayV2(bytes memory request, address relayer) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param transactionId The transaction id associated with the encoded bridge transaction to prove\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function proveV2(bytes32 transactionId, bytes32 destTxHash, address relayer) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital.\n /// @notice Can only send funds to the relayer address on the proof.\n /// @param request The encoded bridge transaction to claim on origin chain\n function claimV2(bytes memory request) external;\n\n /// @notice Cancels an outstanding bridge transaction in case optimistic bridging failed and returns the full amount\n /// to the original sender.\n /// @param request The encoded bridge transaction to refund\n function cancelV2(bytes memory request) external;\n\n /// @notice Checks if a transaction has been relayed\n /// @param transactionId The ID of the transaction to check\n /// @return True if the transaction has been relayed, false otherwise\n function bridgeRelays(bytes32 transactionId) external view returns (bool);\n\n /// @notice Returns the status of a bridge transaction\n /// @param transactionId The ID of the bridge transaction\n /// @return BridgeStatus Status of the bridge transaction\n function bridgeStatuses(bytes32 transactionId) external view returns (BridgeStatus);\n\n /// @notice Returns the timestamp and relayer of a bridge proof\n /// @param transactionId The ID of the bridge transaction\n /// @return timestamp The timestamp of the bridge proof\n /// @return relayer The relayer address of the bridge proof\n function bridgeProofs(bytes32 transactionId) external view returns (uint96 timestamp, address relayer);\n\n /// @notice Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\n /// @param request The bridge request to decode\n function getBridgeTransactionV2(bytes memory request) external view returns (BridgeTransactionV2 memory);\n}\n\n// contracts/utils/MulticallTarget.sol\n\n// solhint-disable avoid-low-level-calls\n/// @notice Abstract contract template that supports batched calls while preserving msg.sender.\n/// Only calls with msg.value of 0 can be batched.\nabstract contract MulticallTarget is IMulticallTarget {\n error MulticallTarget__UndeterminedRevert();\n\n /// @inheritdoc IMulticallTarget\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external {\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\n if (!success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(result);\n }\n }\n }\n\n /// @inheritdoc IMulticallTarget\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results)\n {\n results = new Result[](data.length);\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (results[i].success, results[i].returnData) = address(this).delegatecall(data[i]);\n if (!results[i].success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(results[i].returnData);\n }\n }\n }\n\n /// @dev Bubbles the revert message from the underlying call.\n /// Note: preserves the same custom error or revert string, if one was used.\n /// Source: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v5.0.2/contracts/utils/Address.sol#L143-L158\n function _bubbleRevert(bytes memory returnData) internal pure {\n // Look for revert reason and bubble it up if present\n if (returnData.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n // solhint-disable-next-line no-inline-assembly\n assembly {\n let returndata_size := mload(returnData)\n revert(add(32, returnData), returndata_size)\n }\n } else {\n revert MulticallTarget__UndeterminedRevert();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// contracts/libs/BridgeTransactionV2.sol\n\n// solhint-disable no-inline-assembly\nlibrary BridgeTransactionV2Lib {\n uint16 internal constant VERSION = 2;\n\n // Offsets of the fields in the packed BridgeTransactionV2 struct\n // uint16 version [000 .. 002)\n // uint32 originChainId [002 .. 006)\n // uint32 destChainId [006 .. 010)\n // address originSender [010 .. 030)\n // address destRecipient [030 .. 050)\n // address originToken [050 .. 070)\n // address destToken [070 .. 090)\n // uint256 originAmount [090 .. 122)\n // uint256 destAmount [122 .. 154)\n // uint256 originFeeAmount [154 .. 186)\n // uint256 deadline [186 .. 218)\n // uint256 nonce [218 .. 250)\n // address exclusivityRelayer [250 .. 270)\n // uint256 exclusivityEndTime [270 .. 302)\n // uint256 zapNative [302 .. 334)\n // bytes zapData [334 .. ***)\n\n // forgefmt: disable-start\n uint256 private constant OFFSET_ORIGIN_CHAIN_ID = 2;\n uint256 private constant OFFSET_DEST_CHAIN_ID = 6;\n uint256 private constant OFFSET_ORIGIN_SENDER = 10;\n uint256 private constant OFFSET_DEST_RECIPIENT = 30;\n uint256 private constant OFFSET_ORIGIN_TOKEN = 50;\n uint256 private constant OFFSET_DEST_TOKEN = 70;\n uint256 private constant OFFSET_ORIGIN_AMOUNT = 90;\n uint256 private constant OFFSET_DEST_AMOUNT = 122;\n uint256 private constant OFFSET_ORIGIN_FEE_AMOUNT = 154;\n uint256 private constant OFFSET_DEADLINE = 186;\n uint256 private constant OFFSET_NONCE = 218;\n uint256 private constant OFFSET_EXCLUSIVITY_RELAYER = 250;\n uint256 private constant OFFSET_EXCLUSIVITY_END_TIME = 270;\n uint256 private constant OFFSET_ZAP_NATIVE = 302;\n uint256 private constant OFFSET_ZAP_DATA = 334;\n // forgefmt: disable-end\n\n error BridgeTransactionV2__InvalidEncodedTx();\n error BridgeTransactionV2__UnsupportedVersion(uint16 version);\n\n /// @notice Validates that the encoded transaction is a tightly packed encoded payload for BridgeTransactionV2.\n /// @dev Checks the minimum length and the version, use this function before decoding any of the fields.\n function validateV2(bytes calldata encodedTx) internal pure {\n // Check the minimum length: must at least include all static fields.\n if (encodedTx.length \u003c OFFSET_ZAP_DATA) revert BridgeTransactionV2__InvalidEncodedTx();\n // Once we validated the length, we can be sure that the version field is present.\n uint16 version_ = version(encodedTx);\n if (version_ != VERSION) revert BridgeTransactionV2__UnsupportedVersion(version_);\n }\n\n /// @notice Encodes the BridgeTransactionV2 struct by tightly packing the fields.\n /// @dev `abi.decode` will not work as a result of the tightly packed fields. Use `decodeV2` to decode instead.\n function encodeV2(IFastBridgeV2.BridgeTransactionV2 memory bridgeTx) internal pure returns (bytes memory) {\n // We split the encoding into two parts to avoid stack-too-deep error\n bytes memory firstPart = abi.encodePacked(\n VERSION,\n bridgeTx.originChainId,\n bridgeTx.destChainId,\n bridgeTx.originSender,\n bridgeTx.destRecipient,\n bridgeTx.originToken,\n bridgeTx.destToken,\n bridgeTx.originAmount\n );\n return abi.encodePacked(\n firstPart,\n bridgeTx.destAmount,\n bridgeTx.originFeeAmount,\n // Note: we skip the deprecated `sendChainGas` flag, which was present in BridgeTransaction V1\n bridgeTx.deadline,\n bridgeTx.nonce,\n // New V2 fields: exclusivity\n bridgeTx.exclusivityRelayer,\n bridgeTx.exclusivityEndTime,\n // New V2 fields: Zap\n bridgeTx.zapNative,\n bridgeTx.zapData\n );\n }\n\n /// @notice Decodes the BridgeTransactionV2 struct from the encoded transaction.\n /// @dev Encoded BridgeTransactionV2 struct must be tightly packed.\n /// Use `validateV2` before decoding to ensure the encoded transaction is valid.\n function decodeV2(bytes calldata encodedTx)\n internal\n pure\n returns (IFastBridgeV2.BridgeTransactionV2 memory bridgeTx)\n {\n bridgeTx.originChainId = originChainId(encodedTx);\n bridgeTx.destChainId = destChainId(encodedTx);\n bridgeTx.originSender = originSender(encodedTx);\n bridgeTx.destRecipient = destRecipient(encodedTx);\n bridgeTx.originToken = originToken(encodedTx);\n bridgeTx.destToken = destToken(encodedTx);\n bridgeTx.originAmount = originAmount(encodedTx);\n bridgeTx.destAmount = destAmount(encodedTx);\n bridgeTx.originFeeAmount = originFeeAmount(encodedTx);\n bridgeTx.deadline = deadline(encodedTx);\n bridgeTx.nonce = nonce(encodedTx);\n bridgeTx.exclusivityRelayer = exclusivityRelayer(encodedTx);\n bridgeTx.exclusivityEndTime = exclusivityEndTime(encodedTx);\n bridgeTx.zapNative = zapNative(encodedTx);\n bridgeTx.zapData = zapData(encodedTx);\n }\n\n /// @notice Extracts the version from the encoded transaction.\n function version(bytes calldata encodedTx) internal pure returns (uint16 version_) {\n // Load 32 bytes from the start and shift it 240 bits to the right to get the highest 16 bits.\n assembly {\n version_ := shr(240, calldataload(encodedTx.offset))\n }\n }\n\n /// @notice Extracts the origin chain ID from the encoded transaction.\n function originChainId(bytes calldata encodedTx) internal pure returns (uint32 originChainId_) {\n // Load 32 bytes from the offset and shift it 224 bits to the right to get the highest 32 bits.\n assembly {\n originChainId_ := shr(224, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_CHAIN_ID)))\n }\n }\n\n /// @notice Extracts the destination chain ID from the encoded transaction.\n function destChainId(bytes calldata encodedTx) internal pure returns (uint32 destChainId_) {\n // Load 32 bytes from the offset and shift it 224 bits to the right to get the highest 32 bits.\n assembly {\n destChainId_ := shr(224, calldataload(add(encodedTx.offset, OFFSET_DEST_CHAIN_ID)))\n }\n }\n\n /// @notice Extracts the origin sender from the encoded transaction.\n function originSender(bytes calldata encodedTx) internal pure returns (address originSender_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n originSender_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_SENDER)))\n }\n }\n\n /// @notice Extracts the destination recipient from the encoded transaction.\n function destRecipient(bytes calldata encodedTx) internal pure returns (address destRecipient_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n destRecipient_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_DEST_RECIPIENT)))\n }\n }\n\n /// @notice Extracts the origin token from the encoded transaction.\n function originToken(bytes calldata encodedTx) internal pure returns (address originToken_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n originToken_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_TOKEN)))\n }\n }\n\n /// @notice Extracts the destination token from the encoded transaction.\n function destToken(bytes calldata encodedTx) internal pure returns (address destToken_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n destToken_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_DEST_TOKEN)))\n }\n }\n\n /// @notice Extracts the origin amount from the encoded transaction.\n function originAmount(bytes calldata encodedTx) internal pure returns (uint256 originAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n originAmount_ := calldataload(add(encodedTx.offset, OFFSET_ORIGIN_AMOUNT))\n }\n }\n\n /// @notice Extracts the destination amount from the encoded transaction.\n function destAmount(bytes calldata encodedTx) internal pure returns (uint256 destAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n destAmount_ := calldataload(add(encodedTx.offset, OFFSET_DEST_AMOUNT))\n }\n }\n\n /// @notice Extracts the origin fee amount from the encoded transaction.\n function originFeeAmount(bytes calldata encodedTx) internal pure returns (uint256 originFeeAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n originFeeAmount_ := calldataload(add(encodedTx.offset, OFFSET_ORIGIN_FEE_AMOUNT))\n }\n }\n\n /// @notice Extracts the deadline from the encoded transaction.\n function deadline(bytes calldata encodedTx) internal pure returns (uint256 deadline_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n deadline_ := calldataload(add(encodedTx.offset, OFFSET_DEADLINE))\n }\n }\n\n /// @notice Extracts the nonce from the encoded transaction.\n function nonce(bytes calldata encodedTx) internal pure returns (uint256 nonce_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n nonce_ := calldataload(add(encodedTx.offset, OFFSET_NONCE))\n }\n }\n\n /// @notice Extracts the exclusivity relayer from the encoded transaction.\n function exclusivityRelayer(bytes calldata encodedTx) internal pure returns (address exclusivityRelayer_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n exclusivityRelayer_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_EXCLUSIVITY_RELAYER)))\n }\n }\n\n /// @notice Extracts the exclusivity end time from the encoded transaction.\n function exclusivityEndTime(bytes calldata encodedTx) internal pure returns (uint256 exclusivityEndTime_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n exclusivityEndTime_ := calldataload(add(encodedTx.offset, OFFSET_EXCLUSIVITY_END_TIME))\n }\n }\n\n /// @notice Extracts the Zap's native value from the encoded transaction.\n function zapNative(bytes calldata encodedTx) internal pure returns (uint256 zapNative_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n zapNative_ := calldataload(add(encodedTx.offset, OFFSET_ZAP_NATIVE))\n }\n }\n\n /// @notice Extracts the Zap's data from the encoded transaction.\n function zapData(bytes calldata encodedTx) internal pure returns (bytes calldata zapData_) {\n zapData_ = encodedTx[OFFSET_ZAP_DATA:];\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/AdminV2.sol\n\n// ════════════════════════════════════════════════ INTERFACES ═════════════════════════════════════════════════════\n\n// ═════════════════════════════════════════════ EXTERNAL IMPORTS ══════════════════════════════════════════════════\n\n/// @title AdminV2\n/// @notice Provides administrative functions and controls for managing the FastBridgeV2 contract,\n/// including access control and configuration settings.\ncontract AdminV2 is AccessControlEnumerable, IAdminV2, IAdminV2Errors {\n using SafeERC20 for IERC20;\n\n /// @notice The address reserved for the native gas token (ETH on Ethereum and most L2s, AVAX on Avalanche, etc.).\n address public constant NATIVE_GAS_TOKEN = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice The role identifier for the Quoter API's off-chain authentication.\n /// @dev Only addresses with this role can post FastBridge quotes to the API.\n bytes32 public constant QUOTER_ROLE = keccak256(\"QUOTER_ROLE\");\n\n /// @notice The role identifier for the Prover's on-chain authentication in FastBridge.\n /// @dev Only addresses with this role can provide proofs that a FastBridge request has been relayed.\n bytes32 public constant PROVER_ROLE = keccak256(\"PROVER_ROLE\");\n\n /// @notice The role identifier for the Guard's on-chain authentication in FastBridge.\n /// @dev Only addresses with this role can dispute submitted relay proofs during the dispute period.\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n\n /// @notice The role identifier for the Canceler's on-chain authentication in FastBridge.\n /// @dev Only addresses with this role can cancel a FastBridge transaction without the cancel delay.\n bytes32 public constant CANCELER_ROLE = keccak256(\"CANCELER_ROLE\");\n\n /// @notice The role identifier for the Governor's on-chain administrative authority.\n /// @dev Only addresses with this role can perform administrative tasks within the contract.\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n /// @notice The denominator for fee rates, representing 100%.\n uint256 public constant FEE_BPS = 1e6;\n /// @notice The maximum protocol fee rate: 1% of the origin amount.\n uint256 public constant FEE_RATE_MAX = 0.01e6;\n\n /// @notice The minimum cancel delay that can be set by the governor.\n uint256 public constant MIN_CANCEL_DELAY = 1 hours;\n /// @notice The default cancel delay set during contract deployment.\n uint256 public constant DEFAULT_CANCEL_DELAY = 1 days;\n\n /// @notice The protocol fee rate taken on the origin amount deposited in the origin chain.\n uint256 public protocolFeeRate;\n\n /// @notice The accumulated protocol fee amounts.\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice The delay period after which a transaction can be permissionlessly cancelled.\n uint256 public cancelDelay;\n\n /// @notice This variable is deprecated and should not be used.\n /// @dev Use ZapNative V2 requests instead.\n uint256 public immutable chainGasAmount = 0;\n\n constructor(address defaultAdmin) {\n _grantRole(DEFAULT_ADMIN_ROLE, defaultAdmin);\n _setCancelDelay(DEFAULT_CANCEL_DELAY);\n }\n\n /// @inheritdoc IAdminV2\n function setCancelDelay(uint256 newCancelDelay) external onlyRole(GOVERNOR_ROLE) {\n _setCancelDelay(newCancelDelay);\n }\n\n /// @inheritdoc IAdminV2\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n if (newFeeRate \u003e FEE_RATE_MAX) revert FeeRateAboveMax();\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n /// @inheritdoc IAdminV2\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n // Early exit if no accumulated fees.\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return;\n // Reset the accumulated fees first.\n protocolFees[token] = 0;\n emit FeesSwept(token, recipient, feeAmount);\n // Sweep the fees as the last transaction action.\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(recipient), feeAmount);\n } else {\n IERC20(token).safeTransfer(recipient, feeAmount);\n }\n }\n\n /// @notice Internal logic to set the cancel delay. Security checks are performed outside of this function.\n /// @dev This function is marked as private to prevent child contracts from calling it directly.\n function _setCancelDelay(uint256 newCancelDelay) private {\n if (newCancelDelay \u003c MIN_CANCEL_DELAY) revert CancelDelayBelowMin();\n uint256 oldCancelDelay = cancelDelay;\n cancelDelay = newCancelDelay;\n emit CancelDelayUpdated(oldCancelDelay, newCancelDelay);\n }\n}\n\n// contracts/FastBridgeV2.sol\n\n// ════════════════════════════════════════════════ INTERFACES ═════════════════════════════════════════════════════\n\n// ═════════════════════════════════════════════ INTERNAL IMPORTS ══════════════════════════════════════════════════\n\n// ═════════════════════════════════════════════ EXTERNAL IMPORTS ══════════════════════════════════════════════════\n\n/// @title FastBridgeV2\n/// @notice Core component of the SynapseRFQ protocol, enabling Relayers (Solvers) to fulfill bridge requests.\n/// Supports ERC20 and native gas tokens, along with the Zap feature for executing actions on the destination chain.\n/// Users interact with the off-chain Quoter API to obtain a current quote for a bridge transaction.\n/// They then submit the bridge request with the quote to this contract, depositing their assets in escrow.\n/// Relayers can fulfill requests by relaying them to the destination chain and must prove fulfillment to claim funds.\n/// Guards monitor proofs and can dispute discrepancies.\n/// Users can reclaim funds by cancelling their requests if it has not been fulfilled within the specified deadline.\ncontract FastBridgeV2 is AdminV2, MulticallTarget, IFastBridgeV2, IFastBridgeV2Errors {\n using BridgeTransactionV2Lib for bytes;\n using SafeERC20 for IERC20;\n\n /// @notice The duration of the dispute period for relayed transactions.\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice The minimum required time between transaction request and deadline.\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n /// @notice The maximum allowed length for zapData.\n uint256 public constant MAX_ZAP_DATA_LENGTH = 2 ** 16 - 1;\n\n /// @notice Maps transaction IDs to bridge details (status, destination chain ID, proof timestamp, and relayer).\n /// Note: this is only stored for transactions having local chain as the origin chain.\n mapping(bytes32 =\u003e BridgeTxDetails) public bridgeTxDetails;\n /// @notice Maps transaction IDs to relay details (block number, block timestamp, and relayer).\n /// Note: this is only stored for transactions having local chain as the destination chain.\n mapping(bytes32 =\u003e BridgeRelay) public bridgeRelayDetails;\n /// @notice Maps sender addresses to their unique bridge nonce.\n mapping(address =\u003e uint256) public senderNonces;\n\n /// @notice This variable is deprecated and should not be used.\n /// @dev Replaced by senderNonces.\n uint256 public immutable nonce = 0;\n /// @notice The block number at which this contract was deployed.\n uint256 public immutable deployBlock;\n\n /// @notice Initializes the FastBridgeV2 contract with the provided default admin,\n /// sets the default cancel delay, and records the deploy block number.\n constructor(address defaultAdmin) AdminV2(defaultAdmin) {\n deployBlock = block.number;\n }\n\n // ══════════════════════════════════════ EXTERNAL MUTABLE (USER FACING) ═══════════════════════════════════════════\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n bridgeV2({\n params: params,\n paramsV2: BridgeParamsV2({\n quoteRelayer: address(0),\n quoteExclusivitySeconds: 0,\n quoteId: bytes(\"\"),\n zapNative: 0,\n zapData: bytes(\"\")\n })\n });\n }\n\n /// Note: this function is deprecated and will be removed in a future version.\n /// @dev Replaced by `cancel`.\n /// @inheritdoc IFastBridge\n function refund(bytes calldata request) external {\n cancelV2(request);\n }\n\n // ══════════════════════════════════════ EXTERNAL MUTABLE (AGENT FACING) ══════════════════════════════════════════\n\n /// @inheritdoc IFastBridge\n function relay(bytes calldata request) external payable {\n // `relay` override will validate the request.\n relayV2({request: request, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes calldata request, bytes32 destTxHash) external {\n request.validateV2();\n proveV2({transactionId: keccak256(request), destTxHash: destTxHash, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridgeV2\n function claimV2(bytes calldata request) external {\n // `claim` override will validate the request.\n claim({request: request, to: address(0)});\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n // Aggregate the read operations from the same storage slot.\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n address disputedRelayer = $.proofRelayer;\n BridgeStatus status = $.status;\n uint56 proofBlockTimestamp = $.proofBlockTimestamp;\n\n // Can only dispute a RELAYER_PROVED transaction within the dispute period.\n if (status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(proofBlockTimestamp) \u003e DISPUTE_PERIOD) {\n revert DisputePeriodPassed();\n }\n\n // Update status to REQUESTED and delete the disputed proof details.\n // Note: these are storage writes.\n $.status = BridgeStatus.REQUESTED;\n $.proofRelayer = address(0);\n $.proofBlockTimestamp = 0;\n\n emit BridgeProofDisputed(transactionId, disputedRelayer);\n }\n\n // ══════════════════════════════════════════════ EXTERNAL VIEWS ═══════════════════════════════════════════════════\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n // The correct relayer can only claim a RELAYER_PROVED transaction after the dispute period.\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n if ($.status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if ($.proofRelayer != relayer) revert SenderIncorrect();\n\n return _timeSince($.proofBlockTimestamp) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n /// @dev This method is added to achieve backwards compatibility with decoding requests into V1 structs:\n /// - `zapNative` is partially reported as a zero/non-zero flag\n /// - `zapData` is ignored\n /// In order to process all kinds of requests use getBridgeTransactionV2 instead.\n function getBridgeTransaction(bytes calldata request) external view returns (BridgeTransaction memory) {\n // Try decoding into V2 struct first. This will revert if V1 struct is passed.\n try this.getBridgeTransactionV2(request) returns (BridgeTransactionV2 memory txV2) {\n // Note: we entirely ignore the zapData field, as it was not present in V1.\n return BridgeTransaction({\n originChainId: txV2.originChainId,\n destChainId: txV2.destChainId,\n originSender: txV2.originSender,\n destRecipient: txV2.destRecipient,\n originToken: txV2.originToken,\n destToken: txV2.destToken,\n originAmount: txV2.originAmount,\n destAmount: txV2.destAmount,\n originFeeAmount: txV2.originFeeAmount,\n sendChainGas: txV2.zapNative != 0,\n deadline: txV2.deadline,\n nonce: txV2.nonce\n });\n } catch {\n // Fallback to V1 struct.\n return abi.decode(request, (BridgeTransaction));\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function getBridgeTransactionV2(bytes calldata request) external pure returns (BridgeTransactionV2 memory) {\n request.validateV2();\n return BridgeTransactionV2Lib.decodeV2(request);\n }\n\n // ═══════════════════════════════════════ PUBLIC MUTABLE (USER FACING) ════════════════════════════════════════════\n\n /// @inheritdoc IFastBridgeV2\n function bridgeV2(BridgeParams memory params, BridgeParamsV2 memory paramsV2) public payable {\n // If relayer exclusivity is not intended for this bridge, set exclusivityEndTime to static zero.\n // Otherwise, set exclusivity to expire at the current block ts offset by quoteExclusivitySeconds.\n int256 exclusivityEndTime = 0;\n if (paramsV2.quoteRelayer != address(0)) {\n exclusivityEndTime = int256(block.timestamp) + paramsV2.quoteExclusivitySeconds;\n }\n _validateBridgeParams(params, paramsV2, exclusivityEndTime);\n\n // Transfer tokens to bridge contract. We use the actual transferred amount in case of transfer fees.\n uint256 originAmount = _takeBridgedUserAsset(params.originToken, params.originAmount);\n\n // Track the amount of origin token owed to protocol.\n uint256 originFeeAmount = 0;\n if (protocolFeeRate \u003e 0) {\n originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n // The Relayer filling this request will be paid the originAmount after fees.\n // Note: the protocol fees will be accumulated only when the Relayer claims the origin collateral.\n originAmount -= originFeeAmount;\n }\n\n // Hash the bridge request and set the initial status to REQUESTED.\n bytes memory request = BridgeTransactionV2Lib.encodeV2(\n BridgeTransactionV2({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n deadline: params.deadline,\n // Increment the sender's nonce on every bridge.\n nonce: senderNonces[params.sender]++,\n exclusivityRelayer: paramsV2.quoteRelayer,\n // We checked exclusivityEndTime to be in range [0 .. params.deadline] above, so can safely cast.\n exclusivityEndTime: uint256(exclusivityEndTime),\n zapNative: paramsV2.zapNative,\n zapData: paramsV2.zapData\n })\n );\n bytes32 transactionId = keccak256(request);\n // Note: the tx status will be updated throughout the tx lifecycle, while destChainId is set once here.\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n bridgeTxDetails[transactionId].destChainId = params.dstChainId;\n\n emit BridgeRequested({\n transactionId: transactionId,\n sender: params.sender,\n request: request,\n destChainId: params.dstChainId,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n sendChainGas: paramsV2.zapNative != 0\n });\n emit BridgeQuoteDetails(transactionId, paramsV2.quoteId);\n }\n\n /// @inheritdoc IFastBridgeV2\n function cancelV2(bytes calldata request) public {\n // Decode the request and check that it could be cancelled.\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n\n // Can only cancel a REQUESTED transaction after its deadline expires.\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n if ($.status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n\n // Permissionless cancel is only allowed after `cancelDelay` on top of the deadline.\n uint256 deadline = request.deadline();\n if (!hasRole(CANCELER_ROLE, msg.sender)) deadline += cancelDelay;\n if (block.timestamp \u003c= deadline) revert DeadlineNotExceeded();\n\n // Update status to REFUNDED.\n // Note: this is a storage write.\n $.status = BridgeStatus.REFUNDED;\n\n // Return the full amount (collateral + protocol fees) to the original sender.\n // The protocol fees are only accumulated when the transaction is claimed, so we don't need to update them here.\n address to = request.originSender();\n address token = request.originToken();\n uint256 amount = request.originAmount() + request.originFeeAmount();\n\n // Emit the event before any external calls.\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n\n // Return the funds to the original sender as last transaction action.\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(to), amount);\n } else {\n IERC20(token).safeTransfer(to, amount);\n }\n }\n\n // ═══════════════════════════════════════ PUBLIC MUTABLE (AGENT FACING) ═══════════════════════════════════════════\n\n /// @inheritdoc IFastBridgeV2\n function relayV2(bytes calldata request, address relayer) public payable {\n // Decode the request and check that it could be relayed.\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n _validateRelayParams(request, transactionId, relayer);\n\n // Mark the bridge request as relayed by saving the relayer and the block details.\n bridgeRelayDetails[transactionId].blockNumber = uint48(block.number);\n bridgeRelayDetails[transactionId].blockTimestamp = uint48(block.timestamp);\n bridgeRelayDetails[transactionId].relayer = relayer;\n\n // Transfer tokens to recipient on destination chain and trigger Zap if requested.\n address to = request.destRecipient();\n address token = request.destToken();\n uint256 amount = request.destAmount();\n uint256 zapNative = request.zapNative();\n\n // Emit the event before any external calls.\n emit BridgeRelayed({\n transactionId: transactionId,\n relayer: relayer,\n to: to,\n originChainId: request.originChainId(),\n originToken: request.originToken(),\n destToken: token,\n originAmount: request.originAmount(),\n destAmount: amount,\n chainGasAmount: zapNative\n });\n\n // All state changes have been done at this point, can proceed to the external calls.\n // This follows the checks-effects-interactions pattern to mitigate potential reentrancy attacks.\n if (token == NATIVE_GAS_TOKEN) {\n // For the native gas token, additional zapNative is not allowed.\n if (zapNative != 0) revert ZapNativeNotSupported();\n // Check that the correct msg.value was sent.\n if (msg.value != amount) revert MsgValueIncorrect();\n // Don't do a native transfer yet: we will handle it alongside the Zap below.\n } else {\n // For ERC20s, we check that the correct msg.value was sent.\n if (msg.value != zapNative) revert MsgValueIncorrect();\n // We need to transfer the tokens from the Relayer to the recipient first before performing an\n // optional post-transfer Zap.\n IERC20(token).safeTransferFrom(msg.sender, to, amount);\n }\n // At this point we have done:\n // - Transferred the requested amount of ERC20 tokens to the recipient.\n // At this point we have confirmed:\n // - For ERC20s: msg.value matches the requested zapNative amount.\n // - For the native gas token: msg.value matches the requested destAmount.\n // Remaining optional things to do:\n // - Forward the full msg.value to the recipient (if non-zero).\n // - Trigger a Zap (if zapData is present).\n bytes calldata zapData = request.zapData();\n if (zapData.length != 0) {\n // Zap Data is present: Zap has been requested by the recipient. Trigger it forwarding the full msg.value.\n _triggerZapWithChecks({recipient: to, token: token, amount: amount, zapData: zapData});\n // Note: if token has a fee on transfers, the recipient will have received less than `amount`.\n // This is a very niche edge case and should be handled by the recipient contract.\n } else if (msg.value != 0) {\n // Zap Data is missing, but msg.value was sent. This could happen in two different cases:\n // - Relay with the native gas token is happening.\n // - Relay with ERC20 is happening, with a `zapNative \u003e 0` request.\n // In both cases, we need to transfer the full msg.value to the recipient.\n Address.sendValue(payable(to), msg.value);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function proveV2(bytes32 transactionId, bytes32 destTxHash, address relayer) public onlyRole(PROVER_ROLE) {\n // Can only prove a REQUESTED transaction.\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n if ($.status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n\n // Update status to RELAYER_PROVED and store the proof details.\n // Note: these are storage writes.\n $.status = BridgeStatus.RELAYER_PROVED;\n $.proofBlockTimestamp = uint56(block.timestamp);\n $.proofRelayer = relayer;\n\n emit BridgeProofProvided(transactionId, relayer, destTxHash);\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes calldata request, address to) public {\n // Decode the request and check that it could be claimed.\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n\n // Aggregate the read operations from the same storage slot.\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n address proofRelayer = $.proofRelayer;\n BridgeStatus status = $.status;\n uint56 proofBlockTimestamp = $.proofBlockTimestamp;\n\n // Can only claim a RELAYER_PROVED transaction after the dispute period.\n if (status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(proofBlockTimestamp) \u003c= DISPUTE_PERIOD) revert DisputePeriodNotPassed();\n if (to == address(0)) {\n // Anyone could claim the funds to the proven relayer on their behalf.\n to = proofRelayer;\n } else if (proofRelayer != msg.sender) {\n // Only the proven relayer could specify an address to claim the funds to.\n revert SenderIncorrect();\n }\n\n // Update status to RELAYER_CLAIMED and transfer the origin collateral to the specified claim address.\n // Note: this is a storage write.\n $.status = BridgeStatus.RELAYER_CLAIMED;\n\n // Accumulate protocol fees if origin fee amount exists.\n address token = request.originToken();\n uint256 amount = request.originAmount();\n uint256 originFeeAmount = request.originFeeAmount();\n if (originFeeAmount \u003e 0) protocolFees[token] += originFeeAmount;\n\n // Emit the event before any external calls.\n emit BridgeDepositClaimed(transactionId, proofRelayer, to, token, amount);\n\n // Complete the relayer claim as the last transaction action.\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(to), amount);\n } else {\n IERC20(token).safeTransfer(to, amount);\n }\n }\n\n // ═══════════════════════════════════════════════ PUBLIC VIEWS ════════════════════════════════════════════════════\n\n /// @inheritdoc IFastBridgeV2\n function bridgeStatuses(bytes32 transactionId) public view returns (BridgeStatus status) {\n return bridgeTxDetails[transactionId].status;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeProofs(bytes32 transactionId) public view returns (uint96 timestamp, address relayer) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n timestamp = $.proofBlockTimestamp;\n relayer = $.proofRelayer;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeRelays(bytes32 transactionId) public view returns (bool) {\n // This transaction has been relayed if the relayer address is recorded.\n return bridgeRelayDetails[transactionId].relayer != address(0);\n }\n\n // ═════════════════════════════════════════════ INTERNAL METHODS ══════════════════════════════════════════════════\n\n /// @notice Takes the bridged asset from the user into FastBridgeV2 custody. The asset will later be\n /// claimed by the relayer who completed the relay on the destination chain, or returned to the user\n /// via the cancel function if no relay is completed.\n function _takeBridgedUserAsset(address token, uint256 amount) internal returns (uint256 amountTaken) {\n if (token == NATIVE_GAS_TOKEN) {\n // For the native gas token, we just need to check that the supplied msg.value is correct.\n // Supplied `msg.value` is already in FastBridgeV2 custody.\n if (amount != msg.value) revert MsgValueIncorrect();\n amountTaken = msg.value;\n } else {\n // For ERC20s, token is explicitly transferred from the user to FastBridgeV2.\n // We don't allow non-zero `msg.value` to avoid extra funds from being stuck in FastBridgeV2.\n if (msg.value != 0) revert MsgValueIncorrect();\n // Throw an explicit error if the provided token address is not a contract.\n if (token.code.length == 0) revert TokenNotContract();\n\n // Use the balance difference as the amount taken in case of fee on transfer tokens.\n amountTaken = IERC20(token).balanceOf(address(this));\n IERC20(token).safeTransferFrom(msg.sender, address(this), amount);\n amountTaken = IERC20(token).balanceOf(address(this)) - amountTaken;\n }\n }\n\n /// @notice Calls the recipient's hook function with the specified zapData and validates\n /// the returned value.\n function _triggerZapWithChecks(address recipient, address token, uint256 amount, bytes calldata zapData) internal {\n // Call the recipient's hook function with the specified zapData, bubbling any revert messages.\n bytes memory returnData = Address.functionCallWithValue({\n target: recipient,\n data: abi.encodeCall(IZapRecipient.zap, (token, amount, zapData)),\n // Note: see `relay()` for reasoning behind passing msg.value.\n value: msg.value\n });\n\n // Explicit revert if no return data at all.\n if (returnData.length == 0) revert RecipientNoReturnValue();\n // Check that exactly a single return value was returned.\n if (returnData.length != 32) revert RecipientIncorrectReturnValue();\n // Return value should be abi-encoded hook function selector.\n if (bytes32(returnData) != bytes32(IZapRecipient.zap.selector)) {\n revert RecipientIncorrectReturnValue();\n }\n }\n\n /// @notice Calculates the time elapsed since a proof was submitted.\n /// @dev The proof.timestamp stores block timestamps as uint56 for gas optimization.\n /// _timeSince(proof) handles timestamp rollover when block.timestamp \u003e type(uint56).max but\n /// proof.timestamp \u003c type(uint56).max via an unchecked statement.\n /// @param proofBlockTimestamp The block timestamp when the proof was submitted.\n /// @return delta The time elapsed since proof submission.\n function _timeSince(uint56 proofBlockTimestamp) internal view returns (uint256 delta) {\n unchecked {\n delta = uint56(block.timestamp) - proofBlockTimestamp;\n }\n }\n\n /// @notice Validates all parameters required for a bridge transaction.\n /// @dev This function's complexity cannot be reduced due to the number of required checks,\n /// so we disable the code-complexity rule.\n // solhint-disable-next-line code-complexity\n function _validateBridgeParams(\n BridgeParams memory params,\n BridgeParamsV2 memory paramsV2,\n int256 exclusivityEndTime\n )\n internal\n view\n {\n // Check V1 (legacy) params.\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.sender == address(0) || params.to == address(0)) revert ZeroAddress();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n\n // Check V2 params.\n if (paramsV2.zapData.length \u003e MAX_ZAP_DATA_LENGTH) revert ZapDataLengthAboveMax();\n if (paramsV2.zapNative != 0 \u0026\u0026 params.destToken == NATIVE_GAS_TOKEN) {\n revert ZapNativeNotSupported();\n }\n\n // exclusivityEndTime must be in range [0 .. params.deadline].\n if (exclusivityEndTime \u003c 0 || exclusivityEndTime \u003e int256(params.deadline)) {\n revert ExclusivityParamsIncorrect();\n }\n }\n\n /// @notice Validates all parameters required for a relay transaction.\n function _validateRelayParams(bytes calldata request, bytes32 transactionId, address relayer) internal view {\n if (relayer == address(0)) revert ZeroAddress();\n // Check that the transaction has not been relayed yet and is for the current chain.\n if (bridgeRelays(transactionId)) revert TransactionRelayed();\n if (request.destChainId() != block.chainid) revert ChainIncorrect();\n // Check that the deadline for relay to happen has not passed yet.\n if (block.timestamp \u003e request.deadline()) revert DeadlineExceeded();\n // Check the exclusivity period, if it was specified and is still ongoing.\n address exclRelayer = request.exclusivityRelayer();\n if (exclRelayer != address(0) \u0026\u0026 exclRelayer != relayer \u0026\u0026 block.timestamp \u003c= request.exclusivityEndTime()) {\n revert ExclusivityPeriodNotPassed();\n }\n }\n}\n","language":"Solidity","languageVersion":"0.8.24","compilerVersion":"0.8.24","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"","srcMapRuntime":"","abiDefinition":[{"inputs":[],"name":"AccessControlBadConfirmation","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"bytes32","name":"neededRole","type":"bytes32"}],"name":"AccessControlUnauthorizedAccount","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"previousAdminRole","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"newAdminRole","type":"bytes32"}],"name":"RoleAdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleRevoked","type":"event"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleAdmin","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"uint256","name":"index","type":"uint256"}],"name":"getRoleMember","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleMemberCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"grantRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"hasRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"callerConfirmation","type":"address"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"revokeRole","outputs":[],"stateMutability":"nonpayable","type":"function"}],"userDoc":{"kind":"user","methods":{},"version":1},"developerDoc":{"details":"External interface of AccessControlEnumerable declared to support ERC165 detection.","errors":{"AccessControlBadConfirmation()":[{"details":"The caller of a function is not the expected one. NOTE: Don't confuse with {AccessControlUnauthorizedAccount}."}],"AccessControlUnauthorizedAccount(address,bytes32)":[{"details":"The `account` is missing a role."}]},"events":{"RoleAdminChanged(bytes32,bytes32,bytes32)":{"details":"Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole` `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite {RoleAdminChanged} not being emitted signaling this."},"RoleGranted(bytes32,address,address)":{"details":"Emitted when `account` is granted `role`. `sender` is the account that originated the contract call, an admin role bearer except when using {AccessControl-_setupRole}."},"RoleRevoked(bytes32,address,address)":{"details":"Emitted when `account` is revoked `role`. `sender` is the account that originated the contract call: - if using `revokeRole`, it is the admin role bearer - if using `renounceRole`, it is the role bearer (i.e. `account`)"}},"kind":"dev","methods":{"getRoleAdmin(bytes32)":{"details":"Returns the admin role that controls `role`. See {grantRole} and {revokeRole}. To change a role's admin, use {AccessControl-_setRoleAdmin}."},"getRoleMember(bytes32,uint256)":{"details":"Returns one of the accounts that have `role`. `index` must be a value between 0 and {getRoleMemberCount}, non-inclusive. Role bearers are not sorted in any particular way, and their ordering may change at any point. WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure you perform all queries on the same block. See the following https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post] for more information."},"getRoleMemberCount(bytes32)":{"details":"Returns the number of accounts that have `role`. Can be used together with {getRoleMember} to enumerate all bearers of a role."},"grantRole(bytes32,address)":{"details":"Grants `role` to `account`. If `account` had not been already granted `role`, emits a {RoleGranted} event. Requirements: - the caller must have ``role``'s admin role."},"hasRole(bytes32,address)":{"details":"Returns `true` if `account` has been granted `role`."},"renounceRole(bytes32,address)":{"details":"Revokes `role` from the calling account. Roles are often managed via {grantRole} and {revokeRole}: this function's purpose is to provide a mechanism for accounts to lose their privileges if they are compromised (such as when a trusted device is misplaced). If the calling account had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must be `callerConfirmation`."},"revokeRole(bytes32,address)":{"details":"Revokes `role` from `account`. If `account` had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must have ``role``'s admin role."}},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[],\"name\":\"AccessControlBadConfirmation\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"neededRole\",\"type\":\"bytes32\"}],\"name\":\"AccessControlUnauthorizedAccount\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"previousAdminRole\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"newAdminRole\",\"type\":\"bytes32\"}],\"name\":\"RoleAdminChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleGranted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleRevoked\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"}],\"name\":\"getRoleAdmin\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"index\",\"type\":\"uint256\"}],\"name\":\"getRoleMember\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"}],\"name\":\"getRoleMemberCount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"grantRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"hasRole\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"callerConfirmation\",\"type\":\"address\"}],\"name\":\"renounceRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"revokeRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"details\":\"External interface of AccessControlEnumerable declared to support ERC165 detection.\",\"errors\":{\"AccessControlBadConfirmation()\":[{\"details\":\"The caller of a function is not the expected one. NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\"}],\"AccessControlUnauthorizedAccount(address,bytes32)\":[{\"details\":\"The `account` is missing a role.\"}]},\"events\":{\"RoleAdminChanged(bytes32,bytes32,bytes32)\":{\"details\":\"Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole` `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite {RoleAdminChanged} not being emitted signaling this.\"},\"RoleGranted(bytes32,address,address)\":{\"details\":\"Emitted when `account` is granted `role`. `sender` is the account that originated the contract call, an admin role bearer except when using {AccessControl-_setupRole}.\"},\"RoleRevoked(bytes32,address,address)\":{\"details\":\"Emitted when `account` is revoked `role`. `sender` is the account that originated the contract call: - if using `revokeRole`, it is the admin role bearer - if using `renounceRole`, it is the role bearer (i.e. `account`)\"}},\"kind\":\"dev\",\"methods\":{\"getRoleAdmin(bytes32)\":{\"details\":\"Returns the admin role that controls `role`. See {grantRole} and {revokeRole}. To change a role's admin, use {AccessControl-_setRoleAdmin}.\"},\"getRoleMember(bytes32,uint256)\":{\"details\":\"Returns one of the accounts that have `role`. `index` must be a value between 0 and {getRoleMemberCount}, non-inclusive. Role bearers are not sorted in any particular way, and their ordering may change at any point. WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure you perform all queries on the same block. See the following https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post] for more information.\"},\"getRoleMemberCount(bytes32)\":{\"details\":\"Returns the number of accounts that have `role`. Can be used together with {getRoleMember} to enumerate all bearers of a role.\"},\"grantRole(bytes32,address)\":{\"details\":\"Grants `role` to `account`. If `account` had not been already granted `role`, emits a {RoleGranted} event. Requirements: - the caller must have ``role``'s admin role.\"},\"hasRole(bytes32,address)\":{\"details\":\"Returns `true` if `account` has been granted `role`.\"},\"renounceRole(bytes32,address)\":{\"details\":\"Revokes `role` from the calling account. Roles are often managed via {grantRole} and {revokeRole}: this function's purpose is to provide a mechanism for accounts to lose their privileges if they are compromised (such as when a trusted device is misplaced). If the calling account had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must be `callerConfirmation`.\"},\"revokeRole(bytes32,address)\":{\"details\":\"Revokes `role` from `account`. If `account` had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must have ``role``'s admin role.\"}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeV2.sol\":\"IAccessControlEnumerable\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeV2.sol\":{\"keccak256\":\"0xaab2ee7357681726f0faf799a48ddfbf45fb4da93b69abf61c33dde92b29b74d\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://673391bff9569efc0f9bd99e0e6fece0bc8e8af1f052bb071b407b267a17b3b5\",\"dweb:/ipfs/QmdQQZ6DxpJYhfpinwU5WjLugr2f6qP8h68b5GerhSMQ4j\"]}},\"version\":1}"},"hashes":{"getRoleAdmin(bytes32)":"248a9ca3","getRoleMember(bytes32,uint256)":"9010d07c","getRoleMemberCount(bytes32)":"ca15c873","grantRole(bytes32,address)":"2f2ff15d","hasRole(bytes32,address)":"91d14854","renounceRole(bytes32,address)":"36568abe","revokeRole(bytes32,address)":"d547741f"}},"solidity/FastBridgeV2.sol:IAdminV2":{"code":"0x","runtime-code":"0x","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.24 ^0.8.20 ^0.8.4;\n\n// contracts/interfaces/IAdminV2.sol\n\ninterface IAdminV2 {\n event CancelDelayUpdated(uint256 oldCancelDelay, uint256 newCancelDelay);\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n /// @notice Allows the governor to set the cancel delay. The cancel delay is the time period after the transaction\n /// deadline during which a transaction can be permissionlessly cancelled if it hasn't been proven by any Relayer.\n function setCancelDelay(uint256 newCancelDelay) external;\n\n /// @notice Allows the governor to set the protocol fee rate. The protocol fee is taken from the origin\n /// amount and is only applied to completed and claimed transactions.\n /// @dev The protocol fee is abstracted away from the relayers; they always operate using the amounts after fees.\n /// The origin amount they see in the emitted log is what they get credited with.\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n /// @notice Allows the governor to withdraw the accumulated protocol fees from the contract.\n function sweepProtocolFees(address token, address recipient) external;\n}\n\n// contracts/interfaces/IAdminV2Errors.sol\n\ninterface IAdminV2Errors {\n error CancelDelayBelowMin();\n error FeeRateAboveMax();\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IFastBridgeV2Errors.sol\n\ninterface IFastBridgeV2Errors {\n error AmountIncorrect();\n error ChainIncorrect();\n error ExclusivityParamsIncorrect();\n error MsgValueIncorrect();\n error SenderIncorrect();\n error StatusIncorrect();\n error TokenNotContract();\n error ZapDataLengthAboveMax();\n error ZapNativeNotSupported();\n error ZeroAddress();\n\n error RecipientIncorrectReturnValue();\n error RecipientNoReturnValue();\n\n error DeadlineExceeded();\n error DeadlineNotExceeded();\n error DeadlineTooShort();\n error DisputePeriodNotPassed();\n error DisputePeriodPassed();\n error ExclusivityPeriodNotPassed();\n\n error TransactionRelayed();\n}\n\n// contracts/interfaces/IMulticallTarget.sol\n\n/// @notice Interface for a contract that supports multiple calls from the same caller. Inspired by MulticallV3:\n/// https://github.com/mds1/multicall/blob/master/src/Multicall3.sol\ninterface IMulticallTarget {\n struct Result {\n bool success;\n bytes returnData;\n }\n\n /// @notice Executes multiple calls to this contract in a single transaction while preserving msg.sender.\n /// Return data from the calls is discarded.\n /// @dev This method is non-payable, so only calls with msg.value of 0 can be batched.\n /// If ignoreReverts is set to true, reverted calls will be skipped.\n /// Otherwise, the entire batch will revert with the original revert reason.\n /// @param data List of ABI-encoded calldata for the calls to execute\n /// @param ignoreReverts Whether to skip calls that revert\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external;\n\n /// @notice Executes multiple calls to this contract in a single transaction while preserving msg.sender.\n /// Return data from each call is preserved.\n /// @dev This method is non-payable, so only calls with msg.value of 0 can be batched.\n /// If ignoreReverts is set to true, reverted calls will be skipped.\n /// Otherwise, the entire batch will revert with the original revert reason.\n /// @param data List of ABI-encoded calldata for the calls to execute\n /// @param ignoreReverts Whether to skip calls that revert\n /// @return results List of results from the calls, each containing (success, returnData)\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results);\n}\n\n// contracts/interfaces/IZapRecipient.sol\n\n/// @notice Interface for contracts that can perform Zap operations. Such contracts could be used as Recipients\n/// in a FastBridge transaction that includes a Zap operation. The Zap Data should include instructions on how\n/// exactly the Zap operation should be executed, which would typically include the target address and calldata\n/// to use. The exact implementation of the Zap Data encoding is up to the Recipient contract.\ninterface IZapRecipient {\n /// @notice Performs a Zap operation with the given token and amount according to the provided Zap data.\n /// @param token The address of the token being used for the Zap operation.\n /// @param amount The amount of tokens to be used.\n /// @param zapData The encoded data specifying how the Zap operation should be executed.\n /// @return The function selector to indicate successful execution.\n function zap(address token, uint256 amount, bytes memory zapData) external payable returns (bytes4);\n}\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// contracts/interfaces/IFastBridgeV2.sol\n\ninterface IFastBridgeV2 is IFastBridge {\n enum BridgeStatus {\n NULL, // Doesn't exist yet.\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n struct BridgeTxDetails {\n BridgeStatus status;\n uint32 destChainId;\n uint56 proofBlockTimestamp;\n address proofRelayer;\n }\n\n struct BridgeRelay {\n uint48 blockNumber;\n uint48 blockTimestamp;\n address relayer;\n }\n\n /// @notice New params introduced in the FastBridgeV2.\n /// We are passing fields from the older BridgeParams struct outside of this struct for backwards compatibility.\n /// Note: quoteRelayer and quoteExclusivitySeconds are either both zero (indicating no exclusivity)\n /// or both non-zero (indicating exclusivity for the given period).\n /// Note: zapNative \u003e 0 can NOT be used with destToken = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE (native token)\n /// @param quoteRelayer Relayer that provided the quote for the transaction\n /// @param quoteExclusivitySeconds Period of time the quote relayer is guaranteed exclusivity after user's deposit\n /// @param quoteId Unique quote identifier used for tracking the quote\n /// @param zapNative ETH value to send to the recipient (if any)\n /// @param zapData Parameters for the Zap to the destination recipient (if any)\n struct BridgeParamsV2 {\n address quoteRelayer;\n int256 quoteExclusivitySeconds;\n bytes quoteId;\n uint256 zapNative;\n bytes zapData;\n }\n\n /// @notice Updated bridge transaction struct to include parameters introduced in FastBridgeV2.\n /// Note: only `exclusivityRelayer` can fill such a transaction until `exclusivityEndTime`.\n struct BridgeTransactionV2 {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n // Note: sendChainGas flag from V1 is deprecated\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n address exclusivityRelayer;\n uint256 exclusivityEndTime;\n uint256 zapNative; // ETH value to send to the recipient (if any)\n bytes zapData; // data to pass for the Zap action (if any)\n }\n\n event BridgeQuoteDetails(bytes32 indexed transactionId, bytes quoteId);\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability\n /// to provide temporary exclusivity fill rights for the quote relayer.\n /// @param params The parameters required to bridge\n /// @param paramsV2 The parameters for exclusivity fill rights (optional, can be left empty)\n function bridgeV2(BridgeParams memory params, BridgeParamsV2 memory paramsV2) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function relayV2(bytes memory request, address relayer) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param transactionId The transaction id associated with the encoded bridge transaction to prove\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function proveV2(bytes32 transactionId, bytes32 destTxHash, address relayer) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital.\n /// @notice Can only send funds to the relayer address on the proof.\n /// @param request The encoded bridge transaction to claim on origin chain\n function claimV2(bytes memory request) external;\n\n /// @notice Cancels an outstanding bridge transaction in case optimistic bridging failed and returns the full amount\n /// to the original sender.\n /// @param request The encoded bridge transaction to refund\n function cancelV2(bytes memory request) external;\n\n /// @notice Checks if a transaction has been relayed\n /// @param transactionId The ID of the transaction to check\n /// @return True if the transaction has been relayed, false otherwise\n function bridgeRelays(bytes32 transactionId) external view returns (bool);\n\n /// @notice Returns the status of a bridge transaction\n /// @param transactionId The ID of the bridge transaction\n /// @return BridgeStatus Status of the bridge transaction\n function bridgeStatuses(bytes32 transactionId) external view returns (BridgeStatus);\n\n /// @notice Returns the timestamp and relayer of a bridge proof\n /// @param transactionId The ID of the bridge transaction\n /// @return timestamp The timestamp of the bridge proof\n /// @return relayer The relayer address of the bridge proof\n function bridgeProofs(bytes32 transactionId) external view returns (uint96 timestamp, address relayer);\n\n /// @notice Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\n /// @param request The bridge request to decode\n function getBridgeTransactionV2(bytes memory request) external view returns (BridgeTransactionV2 memory);\n}\n\n// contracts/utils/MulticallTarget.sol\n\n// solhint-disable avoid-low-level-calls\n/// @notice Abstract contract template that supports batched calls while preserving msg.sender.\n/// Only calls with msg.value of 0 can be batched.\nabstract contract MulticallTarget is IMulticallTarget {\n error MulticallTarget__UndeterminedRevert();\n\n /// @inheritdoc IMulticallTarget\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external {\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\n if (!success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(result);\n }\n }\n }\n\n /// @inheritdoc IMulticallTarget\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results)\n {\n results = new Result[](data.length);\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (results[i].success, results[i].returnData) = address(this).delegatecall(data[i]);\n if (!results[i].success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(results[i].returnData);\n }\n }\n }\n\n /// @dev Bubbles the revert message from the underlying call.\n /// Note: preserves the same custom error or revert string, if one was used.\n /// Source: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v5.0.2/contracts/utils/Address.sol#L143-L158\n function _bubbleRevert(bytes memory returnData) internal pure {\n // Look for revert reason and bubble it up if present\n if (returnData.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n // solhint-disable-next-line no-inline-assembly\n assembly {\n let returndata_size := mload(returnData)\n revert(add(32, returnData), returndata_size)\n }\n } else {\n revert MulticallTarget__UndeterminedRevert();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// contracts/libs/BridgeTransactionV2.sol\n\n// solhint-disable no-inline-assembly\nlibrary BridgeTransactionV2Lib {\n uint16 internal constant VERSION = 2;\n\n // Offsets of the fields in the packed BridgeTransactionV2 struct\n // uint16 version [000 .. 002)\n // uint32 originChainId [002 .. 006)\n // uint32 destChainId [006 .. 010)\n // address originSender [010 .. 030)\n // address destRecipient [030 .. 050)\n // address originToken [050 .. 070)\n // address destToken [070 .. 090)\n // uint256 originAmount [090 .. 122)\n // uint256 destAmount [122 .. 154)\n // uint256 originFeeAmount [154 .. 186)\n // uint256 deadline [186 .. 218)\n // uint256 nonce [218 .. 250)\n // address exclusivityRelayer [250 .. 270)\n // uint256 exclusivityEndTime [270 .. 302)\n // uint256 zapNative [302 .. 334)\n // bytes zapData [334 .. ***)\n\n // forgefmt: disable-start\n uint256 private constant OFFSET_ORIGIN_CHAIN_ID = 2;\n uint256 private constant OFFSET_DEST_CHAIN_ID = 6;\n uint256 private constant OFFSET_ORIGIN_SENDER = 10;\n uint256 private constant OFFSET_DEST_RECIPIENT = 30;\n uint256 private constant OFFSET_ORIGIN_TOKEN = 50;\n uint256 private constant OFFSET_DEST_TOKEN = 70;\n uint256 private constant OFFSET_ORIGIN_AMOUNT = 90;\n uint256 private constant OFFSET_DEST_AMOUNT = 122;\n uint256 private constant OFFSET_ORIGIN_FEE_AMOUNT = 154;\n uint256 private constant OFFSET_DEADLINE = 186;\n uint256 private constant OFFSET_NONCE = 218;\n uint256 private constant OFFSET_EXCLUSIVITY_RELAYER = 250;\n uint256 private constant OFFSET_EXCLUSIVITY_END_TIME = 270;\n uint256 private constant OFFSET_ZAP_NATIVE = 302;\n uint256 private constant OFFSET_ZAP_DATA = 334;\n // forgefmt: disable-end\n\n error BridgeTransactionV2__InvalidEncodedTx();\n error BridgeTransactionV2__UnsupportedVersion(uint16 version);\n\n /// @notice Validates that the encoded transaction is a tightly packed encoded payload for BridgeTransactionV2.\n /// @dev Checks the minimum length and the version, use this function before decoding any of the fields.\n function validateV2(bytes calldata encodedTx) internal pure {\n // Check the minimum length: must at least include all static fields.\n if (encodedTx.length \u003c OFFSET_ZAP_DATA) revert BridgeTransactionV2__InvalidEncodedTx();\n // Once we validated the length, we can be sure that the version field is present.\n uint16 version_ = version(encodedTx);\n if (version_ != VERSION) revert BridgeTransactionV2__UnsupportedVersion(version_);\n }\n\n /// @notice Encodes the BridgeTransactionV2 struct by tightly packing the fields.\n /// @dev `abi.decode` will not work as a result of the tightly packed fields. Use `decodeV2` to decode instead.\n function encodeV2(IFastBridgeV2.BridgeTransactionV2 memory bridgeTx) internal pure returns (bytes memory) {\n // We split the encoding into two parts to avoid stack-too-deep error\n bytes memory firstPart = abi.encodePacked(\n VERSION,\n bridgeTx.originChainId,\n bridgeTx.destChainId,\n bridgeTx.originSender,\n bridgeTx.destRecipient,\n bridgeTx.originToken,\n bridgeTx.destToken,\n bridgeTx.originAmount\n );\n return abi.encodePacked(\n firstPart,\n bridgeTx.destAmount,\n bridgeTx.originFeeAmount,\n // Note: we skip the deprecated `sendChainGas` flag, which was present in BridgeTransaction V1\n bridgeTx.deadline,\n bridgeTx.nonce,\n // New V2 fields: exclusivity\n bridgeTx.exclusivityRelayer,\n bridgeTx.exclusivityEndTime,\n // New V2 fields: Zap\n bridgeTx.zapNative,\n bridgeTx.zapData\n );\n }\n\n /// @notice Decodes the BridgeTransactionV2 struct from the encoded transaction.\n /// @dev Encoded BridgeTransactionV2 struct must be tightly packed.\n /// Use `validateV2` before decoding to ensure the encoded transaction is valid.\n function decodeV2(bytes calldata encodedTx)\n internal\n pure\n returns (IFastBridgeV2.BridgeTransactionV2 memory bridgeTx)\n {\n bridgeTx.originChainId = originChainId(encodedTx);\n bridgeTx.destChainId = destChainId(encodedTx);\n bridgeTx.originSender = originSender(encodedTx);\n bridgeTx.destRecipient = destRecipient(encodedTx);\n bridgeTx.originToken = originToken(encodedTx);\n bridgeTx.destToken = destToken(encodedTx);\n bridgeTx.originAmount = originAmount(encodedTx);\n bridgeTx.destAmount = destAmount(encodedTx);\n bridgeTx.originFeeAmount = originFeeAmount(encodedTx);\n bridgeTx.deadline = deadline(encodedTx);\n bridgeTx.nonce = nonce(encodedTx);\n bridgeTx.exclusivityRelayer = exclusivityRelayer(encodedTx);\n bridgeTx.exclusivityEndTime = exclusivityEndTime(encodedTx);\n bridgeTx.zapNative = zapNative(encodedTx);\n bridgeTx.zapData = zapData(encodedTx);\n }\n\n /// @notice Extracts the version from the encoded transaction.\n function version(bytes calldata encodedTx) internal pure returns (uint16 version_) {\n // Load 32 bytes from the start and shift it 240 bits to the right to get the highest 16 bits.\n assembly {\n version_ := shr(240, calldataload(encodedTx.offset))\n }\n }\n\n /// @notice Extracts the origin chain ID from the encoded transaction.\n function originChainId(bytes calldata encodedTx) internal pure returns (uint32 originChainId_) {\n // Load 32 bytes from the offset and shift it 224 bits to the right to get the highest 32 bits.\n assembly {\n originChainId_ := shr(224, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_CHAIN_ID)))\n }\n }\n\n /// @notice Extracts the destination chain ID from the encoded transaction.\n function destChainId(bytes calldata encodedTx) internal pure returns (uint32 destChainId_) {\n // Load 32 bytes from the offset and shift it 224 bits to the right to get the highest 32 bits.\n assembly {\n destChainId_ := shr(224, calldataload(add(encodedTx.offset, OFFSET_DEST_CHAIN_ID)))\n }\n }\n\n /// @notice Extracts the origin sender from the encoded transaction.\n function originSender(bytes calldata encodedTx) internal pure returns (address originSender_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n originSender_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_SENDER)))\n }\n }\n\n /// @notice Extracts the destination recipient from the encoded transaction.\n function destRecipient(bytes calldata encodedTx) internal pure returns (address destRecipient_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n destRecipient_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_DEST_RECIPIENT)))\n }\n }\n\n /// @notice Extracts the origin token from the encoded transaction.\n function originToken(bytes calldata encodedTx) internal pure returns (address originToken_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n originToken_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_TOKEN)))\n }\n }\n\n /// @notice Extracts the destination token from the encoded transaction.\n function destToken(bytes calldata encodedTx) internal pure returns (address destToken_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n destToken_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_DEST_TOKEN)))\n }\n }\n\n /// @notice Extracts the origin amount from the encoded transaction.\n function originAmount(bytes calldata encodedTx) internal pure returns (uint256 originAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n originAmount_ := calldataload(add(encodedTx.offset, OFFSET_ORIGIN_AMOUNT))\n }\n }\n\n /// @notice Extracts the destination amount from the encoded transaction.\n function destAmount(bytes calldata encodedTx) internal pure returns (uint256 destAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n destAmount_ := calldataload(add(encodedTx.offset, OFFSET_DEST_AMOUNT))\n }\n }\n\n /// @notice Extracts the origin fee amount from the encoded transaction.\n function originFeeAmount(bytes calldata encodedTx) internal pure returns (uint256 originFeeAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n originFeeAmount_ := calldataload(add(encodedTx.offset, OFFSET_ORIGIN_FEE_AMOUNT))\n }\n }\n\n /// @notice Extracts the deadline from the encoded transaction.\n function deadline(bytes calldata encodedTx) internal pure returns (uint256 deadline_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n deadline_ := calldataload(add(encodedTx.offset, OFFSET_DEADLINE))\n }\n }\n\n /// @notice Extracts the nonce from the encoded transaction.\n function nonce(bytes calldata encodedTx) internal pure returns (uint256 nonce_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n nonce_ := calldataload(add(encodedTx.offset, OFFSET_NONCE))\n }\n }\n\n /// @notice Extracts the exclusivity relayer from the encoded transaction.\n function exclusivityRelayer(bytes calldata encodedTx) internal pure returns (address exclusivityRelayer_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n exclusivityRelayer_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_EXCLUSIVITY_RELAYER)))\n }\n }\n\n /// @notice Extracts the exclusivity end time from the encoded transaction.\n function exclusivityEndTime(bytes calldata encodedTx) internal pure returns (uint256 exclusivityEndTime_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n exclusivityEndTime_ := calldataload(add(encodedTx.offset, OFFSET_EXCLUSIVITY_END_TIME))\n }\n }\n\n /// @notice Extracts the Zap's native value from the encoded transaction.\n function zapNative(bytes calldata encodedTx) internal pure returns (uint256 zapNative_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n zapNative_ := calldataload(add(encodedTx.offset, OFFSET_ZAP_NATIVE))\n }\n }\n\n /// @notice Extracts the Zap's data from the encoded transaction.\n function zapData(bytes calldata encodedTx) internal pure returns (bytes calldata zapData_) {\n zapData_ = encodedTx[OFFSET_ZAP_DATA:];\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/AdminV2.sol\n\n// ════════════════════════════════════════════════ INTERFACES ═════════════════════════════════════════════════════\n\n// ═════════════════════════════════════════════ EXTERNAL IMPORTS ══════════════════════════════════════════════════\n\n/// @title AdminV2\n/// @notice Provides administrative functions and controls for managing the FastBridgeV2 contract,\n/// including access control and configuration settings.\ncontract AdminV2 is AccessControlEnumerable, IAdminV2, IAdminV2Errors {\n using SafeERC20 for IERC20;\n\n /// @notice The address reserved for the native gas token (ETH on Ethereum and most L2s, AVAX on Avalanche, etc.).\n address public constant NATIVE_GAS_TOKEN = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice The role identifier for the Quoter API's off-chain authentication.\n /// @dev Only addresses with this role can post FastBridge quotes to the API.\n bytes32 public constant QUOTER_ROLE = keccak256(\"QUOTER_ROLE\");\n\n /// @notice The role identifier for the Prover's on-chain authentication in FastBridge.\n /// @dev Only addresses with this role can provide proofs that a FastBridge request has been relayed.\n bytes32 public constant PROVER_ROLE = keccak256(\"PROVER_ROLE\");\n\n /// @notice The role identifier for the Guard's on-chain authentication in FastBridge.\n /// @dev Only addresses with this role can dispute submitted relay proofs during the dispute period.\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n\n /// @notice The role identifier for the Canceler's on-chain authentication in FastBridge.\n /// @dev Only addresses with this role can cancel a FastBridge transaction without the cancel delay.\n bytes32 public constant CANCELER_ROLE = keccak256(\"CANCELER_ROLE\");\n\n /// @notice The role identifier for the Governor's on-chain administrative authority.\n /// @dev Only addresses with this role can perform administrative tasks within the contract.\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n /// @notice The denominator for fee rates, representing 100%.\n uint256 public constant FEE_BPS = 1e6;\n /// @notice The maximum protocol fee rate: 1% of the origin amount.\n uint256 public constant FEE_RATE_MAX = 0.01e6;\n\n /// @notice The minimum cancel delay that can be set by the governor.\n uint256 public constant MIN_CANCEL_DELAY = 1 hours;\n /// @notice The default cancel delay set during contract deployment.\n uint256 public constant DEFAULT_CANCEL_DELAY = 1 days;\n\n /// @notice The protocol fee rate taken on the origin amount deposited in the origin chain.\n uint256 public protocolFeeRate;\n\n /// @notice The accumulated protocol fee amounts.\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice The delay period after which a transaction can be permissionlessly cancelled.\n uint256 public cancelDelay;\n\n /// @notice This variable is deprecated and should not be used.\n /// @dev Use ZapNative V2 requests instead.\n uint256 public immutable chainGasAmount = 0;\n\n constructor(address defaultAdmin) {\n _grantRole(DEFAULT_ADMIN_ROLE, defaultAdmin);\n _setCancelDelay(DEFAULT_CANCEL_DELAY);\n }\n\n /// @inheritdoc IAdminV2\n function setCancelDelay(uint256 newCancelDelay) external onlyRole(GOVERNOR_ROLE) {\n _setCancelDelay(newCancelDelay);\n }\n\n /// @inheritdoc IAdminV2\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n if (newFeeRate \u003e FEE_RATE_MAX) revert FeeRateAboveMax();\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n /// @inheritdoc IAdminV2\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n // Early exit if no accumulated fees.\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return;\n // Reset the accumulated fees first.\n protocolFees[token] = 0;\n emit FeesSwept(token, recipient, feeAmount);\n // Sweep the fees as the last transaction action.\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(recipient), feeAmount);\n } else {\n IERC20(token).safeTransfer(recipient, feeAmount);\n }\n }\n\n /// @notice Internal logic to set the cancel delay. Security checks are performed outside of this function.\n /// @dev This function is marked as private to prevent child contracts from calling it directly.\n function _setCancelDelay(uint256 newCancelDelay) private {\n if (newCancelDelay \u003c MIN_CANCEL_DELAY) revert CancelDelayBelowMin();\n uint256 oldCancelDelay = cancelDelay;\n cancelDelay = newCancelDelay;\n emit CancelDelayUpdated(oldCancelDelay, newCancelDelay);\n }\n}\n\n// contracts/FastBridgeV2.sol\n\n// ════════════════════════════════════════════════ INTERFACES ═════════════════════════════════════════════════════\n\n// ═════════════════════════════════════════════ INTERNAL IMPORTS ══════════════════════════════════════════════════\n\n// ═════════════════════════════════════════════ EXTERNAL IMPORTS ══════════════════════════════════════════════════\n\n/// @title FastBridgeV2\n/// @notice Core component of the SynapseRFQ protocol, enabling Relayers (Solvers) to fulfill bridge requests.\n/// Supports ERC20 and native gas tokens, along with the Zap feature for executing actions on the destination chain.\n/// Users interact with the off-chain Quoter API to obtain a current quote for a bridge transaction.\n/// They then submit the bridge request with the quote to this contract, depositing their assets in escrow.\n/// Relayers can fulfill requests by relaying them to the destination chain and must prove fulfillment to claim funds.\n/// Guards monitor proofs and can dispute discrepancies.\n/// Users can reclaim funds by cancelling their requests if it has not been fulfilled within the specified deadline.\ncontract FastBridgeV2 is AdminV2, MulticallTarget, IFastBridgeV2, IFastBridgeV2Errors {\n using BridgeTransactionV2Lib for bytes;\n using SafeERC20 for IERC20;\n\n /// @notice The duration of the dispute period for relayed transactions.\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice The minimum required time between transaction request and deadline.\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n /// @notice The maximum allowed length for zapData.\n uint256 public constant MAX_ZAP_DATA_LENGTH = 2 ** 16 - 1;\n\n /// @notice Maps transaction IDs to bridge details (status, destination chain ID, proof timestamp, and relayer).\n /// Note: this is only stored for transactions having local chain as the origin chain.\n mapping(bytes32 =\u003e BridgeTxDetails) public bridgeTxDetails;\n /// @notice Maps transaction IDs to relay details (block number, block timestamp, and relayer).\n /// Note: this is only stored for transactions having local chain as the destination chain.\n mapping(bytes32 =\u003e BridgeRelay) public bridgeRelayDetails;\n /// @notice Maps sender addresses to their unique bridge nonce.\n mapping(address =\u003e uint256) public senderNonces;\n\n /// @notice This variable is deprecated and should not be used.\n /// @dev Replaced by senderNonces.\n uint256 public immutable nonce = 0;\n /// @notice The block number at which this contract was deployed.\n uint256 public immutable deployBlock;\n\n /// @notice Initializes the FastBridgeV2 contract with the provided default admin,\n /// sets the default cancel delay, and records the deploy block number.\n constructor(address defaultAdmin) AdminV2(defaultAdmin) {\n deployBlock = block.number;\n }\n\n // ══════════════════════════════════════ EXTERNAL MUTABLE (USER FACING) ═══════════════════════════════════════════\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n bridgeV2({\n params: params,\n paramsV2: BridgeParamsV2({\n quoteRelayer: address(0),\n quoteExclusivitySeconds: 0,\n quoteId: bytes(\"\"),\n zapNative: 0,\n zapData: bytes(\"\")\n })\n });\n }\n\n /// Note: this function is deprecated and will be removed in a future version.\n /// @dev Replaced by `cancel`.\n /// @inheritdoc IFastBridge\n function refund(bytes calldata request) external {\n cancelV2(request);\n }\n\n // ══════════════════════════════════════ EXTERNAL MUTABLE (AGENT FACING) ══════════════════════════════════════════\n\n /// @inheritdoc IFastBridge\n function relay(bytes calldata request) external payable {\n // `relay` override will validate the request.\n relayV2({request: request, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes calldata request, bytes32 destTxHash) external {\n request.validateV2();\n proveV2({transactionId: keccak256(request), destTxHash: destTxHash, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridgeV2\n function claimV2(bytes calldata request) external {\n // `claim` override will validate the request.\n claim({request: request, to: address(0)});\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n // Aggregate the read operations from the same storage slot.\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n address disputedRelayer = $.proofRelayer;\n BridgeStatus status = $.status;\n uint56 proofBlockTimestamp = $.proofBlockTimestamp;\n\n // Can only dispute a RELAYER_PROVED transaction within the dispute period.\n if (status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(proofBlockTimestamp) \u003e DISPUTE_PERIOD) {\n revert DisputePeriodPassed();\n }\n\n // Update status to REQUESTED and delete the disputed proof details.\n // Note: these are storage writes.\n $.status = BridgeStatus.REQUESTED;\n $.proofRelayer = address(0);\n $.proofBlockTimestamp = 0;\n\n emit BridgeProofDisputed(transactionId, disputedRelayer);\n }\n\n // ══════════════════════════════════════════════ EXTERNAL VIEWS ═══════════════════════════════════════════════════\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n // The correct relayer can only claim a RELAYER_PROVED transaction after the dispute period.\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n if ($.status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if ($.proofRelayer != relayer) revert SenderIncorrect();\n\n return _timeSince($.proofBlockTimestamp) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n /// @dev This method is added to achieve backwards compatibility with decoding requests into V1 structs:\n /// - `zapNative` is partially reported as a zero/non-zero flag\n /// - `zapData` is ignored\n /// In order to process all kinds of requests use getBridgeTransactionV2 instead.\n function getBridgeTransaction(bytes calldata request) external view returns (BridgeTransaction memory) {\n // Try decoding into V2 struct first. This will revert if V1 struct is passed.\n try this.getBridgeTransactionV2(request) returns (BridgeTransactionV2 memory txV2) {\n // Note: we entirely ignore the zapData field, as it was not present in V1.\n return BridgeTransaction({\n originChainId: txV2.originChainId,\n destChainId: txV2.destChainId,\n originSender: txV2.originSender,\n destRecipient: txV2.destRecipient,\n originToken: txV2.originToken,\n destToken: txV2.destToken,\n originAmount: txV2.originAmount,\n destAmount: txV2.destAmount,\n originFeeAmount: txV2.originFeeAmount,\n sendChainGas: txV2.zapNative != 0,\n deadline: txV2.deadline,\n nonce: txV2.nonce\n });\n } catch {\n // Fallback to V1 struct.\n return abi.decode(request, (BridgeTransaction));\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function getBridgeTransactionV2(bytes calldata request) external pure returns (BridgeTransactionV2 memory) {\n request.validateV2();\n return BridgeTransactionV2Lib.decodeV2(request);\n }\n\n // ═══════════════════════════════════════ PUBLIC MUTABLE (USER FACING) ════════════════════════════════════════════\n\n /// @inheritdoc IFastBridgeV2\n function bridgeV2(BridgeParams memory params, BridgeParamsV2 memory paramsV2) public payable {\n // If relayer exclusivity is not intended for this bridge, set exclusivityEndTime to static zero.\n // Otherwise, set exclusivity to expire at the current block ts offset by quoteExclusivitySeconds.\n int256 exclusivityEndTime = 0;\n if (paramsV2.quoteRelayer != address(0)) {\n exclusivityEndTime = int256(block.timestamp) + paramsV2.quoteExclusivitySeconds;\n }\n _validateBridgeParams(params, paramsV2, exclusivityEndTime);\n\n // Transfer tokens to bridge contract. We use the actual transferred amount in case of transfer fees.\n uint256 originAmount = _takeBridgedUserAsset(params.originToken, params.originAmount);\n\n // Track the amount of origin token owed to protocol.\n uint256 originFeeAmount = 0;\n if (protocolFeeRate \u003e 0) {\n originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n // The Relayer filling this request will be paid the originAmount after fees.\n // Note: the protocol fees will be accumulated only when the Relayer claims the origin collateral.\n originAmount -= originFeeAmount;\n }\n\n // Hash the bridge request and set the initial status to REQUESTED.\n bytes memory request = BridgeTransactionV2Lib.encodeV2(\n BridgeTransactionV2({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n deadline: params.deadline,\n // Increment the sender's nonce on every bridge.\n nonce: senderNonces[params.sender]++,\n exclusivityRelayer: paramsV2.quoteRelayer,\n // We checked exclusivityEndTime to be in range [0 .. params.deadline] above, so can safely cast.\n exclusivityEndTime: uint256(exclusivityEndTime),\n zapNative: paramsV2.zapNative,\n zapData: paramsV2.zapData\n })\n );\n bytes32 transactionId = keccak256(request);\n // Note: the tx status will be updated throughout the tx lifecycle, while destChainId is set once here.\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n bridgeTxDetails[transactionId].destChainId = params.dstChainId;\n\n emit BridgeRequested({\n transactionId: transactionId,\n sender: params.sender,\n request: request,\n destChainId: params.dstChainId,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n sendChainGas: paramsV2.zapNative != 0\n });\n emit BridgeQuoteDetails(transactionId, paramsV2.quoteId);\n }\n\n /// @inheritdoc IFastBridgeV2\n function cancelV2(bytes calldata request) public {\n // Decode the request and check that it could be cancelled.\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n\n // Can only cancel a REQUESTED transaction after its deadline expires.\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n if ($.status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n\n // Permissionless cancel is only allowed after `cancelDelay` on top of the deadline.\n uint256 deadline = request.deadline();\n if (!hasRole(CANCELER_ROLE, msg.sender)) deadline += cancelDelay;\n if (block.timestamp \u003c= deadline) revert DeadlineNotExceeded();\n\n // Update status to REFUNDED.\n // Note: this is a storage write.\n $.status = BridgeStatus.REFUNDED;\n\n // Return the full amount (collateral + protocol fees) to the original sender.\n // The protocol fees are only accumulated when the transaction is claimed, so we don't need to update them here.\n address to = request.originSender();\n address token = request.originToken();\n uint256 amount = request.originAmount() + request.originFeeAmount();\n\n // Emit the event before any external calls.\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n\n // Return the funds to the original sender as last transaction action.\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(to), amount);\n } else {\n IERC20(token).safeTransfer(to, amount);\n }\n }\n\n // ═══════════════════════════════════════ PUBLIC MUTABLE (AGENT FACING) ═══════════════════════════════════════════\n\n /// @inheritdoc IFastBridgeV2\n function relayV2(bytes calldata request, address relayer) public payable {\n // Decode the request and check that it could be relayed.\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n _validateRelayParams(request, transactionId, relayer);\n\n // Mark the bridge request as relayed by saving the relayer and the block details.\n bridgeRelayDetails[transactionId].blockNumber = uint48(block.number);\n bridgeRelayDetails[transactionId].blockTimestamp = uint48(block.timestamp);\n bridgeRelayDetails[transactionId].relayer = relayer;\n\n // Transfer tokens to recipient on destination chain and trigger Zap if requested.\n address to = request.destRecipient();\n address token = request.destToken();\n uint256 amount = request.destAmount();\n uint256 zapNative = request.zapNative();\n\n // Emit the event before any external calls.\n emit BridgeRelayed({\n transactionId: transactionId,\n relayer: relayer,\n to: to,\n originChainId: request.originChainId(),\n originToken: request.originToken(),\n destToken: token,\n originAmount: request.originAmount(),\n destAmount: amount,\n chainGasAmount: zapNative\n });\n\n // All state changes have been done at this point, can proceed to the external calls.\n // This follows the checks-effects-interactions pattern to mitigate potential reentrancy attacks.\n if (token == NATIVE_GAS_TOKEN) {\n // For the native gas token, additional zapNative is not allowed.\n if (zapNative != 0) revert ZapNativeNotSupported();\n // Check that the correct msg.value was sent.\n if (msg.value != amount) revert MsgValueIncorrect();\n // Don't do a native transfer yet: we will handle it alongside the Zap below.\n } else {\n // For ERC20s, we check that the correct msg.value was sent.\n if (msg.value != zapNative) revert MsgValueIncorrect();\n // We need to transfer the tokens from the Relayer to the recipient first before performing an\n // optional post-transfer Zap.\n IERC20(token).safeTransferFrom(msg.sender, to, amount);\n }\n // At this point we have done:\n // - Transferred the requested amount of ERC20 tokens to the recipient.\n // At this point we have confirmed:\n // - For ERC20s: msg.value matches the requested zapNative amount.\n // - For the native gas token: msg.value matches the requested destAmount.\n // Remaining optional things to do:\n // - Forward the full msg.value to the recipient (if non-zero).\n // - Trigger a Zap (if zapData is present).\n bytes calldata zapData = request.zapData();\n if (zapData.length != 0) {\n // Zap Data is present: Zap has been requested by the recipient. Trigger it forwarding the full msg.value.\n _triggerZapWithChecks({recipient: to, token: token, amount: amount, zapData: zapData});\n // Note: if token has a fee on transfers, the recipient will have received less than `amount`.\n // This is a very niche edge case and should be handled by the recipient contract.\n } else if (msg.value != 0) {\n // Zap Data is missing, but msg.value was sent. This could happen in two different cases:\n // - Relay with the native gas token is happening.\n // - Relay with ERC20 is happening, with a `zapNative \u003e 0` request.\n // In both cases, we need to transfer the full msg.value to the recipient.\n Address.sendValue(payable(to), msg.value);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function proveV2(bytes32 transactionId, bytes32 destTxHash, address relayer) public onlyRole(PROVER_ROLE) {\n // Can only prove a REQUESTED transaction.\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n if ($.status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n\n // Update status to RELAYER_PROVED and store the proof details.\n // Note: these are storage writes.\n $.status = BridgeStatus.RELAYER_PROVED;\n $.proofBlockTimestamp = uint56(block.timestamp);\n $.proofRelayer = relayer;\n\n emit BridgeProofProvided(transactionId, relayer, destTxHash);\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes calldata request, address to) public {\n // Decode the request and check that it could be claimed.\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n\n // Aggregate the read operations from the same storage slot.\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n address proofRelayer = $.proofRelayer;\n BridgeStatus status = $.status;\n uint56 proofBlockTimestamp = $.proofBlockTimestamp;\n\n // Can only claim a RELAYER_PROVED transaction after the dispute period.\n if (status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(proofBlockTimestamp) \u003c= DISPUTE_PERIOD) revert DisputePeriodNotPassed();\n if (to == address(0)) {\n // Anyone could claim the funds to the proven relayer on their behalf.\n to = proofRelayer;\n } else if (proofRelayer != msg.sender) {\n // Only the proven relayer could specify an address to claim the funds to.\n revert SenderIncorrect();\n }\n\n // Update status to RELAYER_CLAIMED and transfer the origin collateral to the specified claim address.\n // Note: this is a storage write.\n $.status = BridgeStatus.RELAYER_CLAIMED;\n\n // Accumulate protocol fees if origin fee amount exists.\n address token = request.originToken();\n uint256 amount = request.originAmount();\n uint256 originFeeAmount = request.originFeeAmount();\n if (originFeeAmount \u003e 0) protocolFees[token] += originFeeAmount;\n\n // Emit the event before any external calls.\n emit BridgeDepositClaimed(transactionId, proofRelayer, to, token, amount);\n\n // Complete the relayer claim as the last transaction action.\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(to), amount);\n } else {\n IERC20(token).safeTransfer(to, amount);\n }\n }\n\n // ═══════════════════════════════════════════════ PUBLIC VIEWS ════════════════════════════════════════════════════\n\n /// @inheritdoc IFastBridgeV2\n function bridgeStatuses(bytes32 transactionId) public view returns (BridgeStatus status) {\n return bridgeTxDetails[transactionId].status;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeProofs(bytes32 transactionId) public view returns (uint96 timestamp, address relayer) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n timestamp = $.proofBlockTimestamp;\n relayer = $.proofRelayer;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeRelays(bytes32 transactionId) public view returns (bool) {\n // This transaction has been relayed if the relayer address is recorded.\n return bridgeRelayDetails[transactionId].relayer != address(0);\n }\n\n // ═════════════════════════════════════════════ INTERNAL METHODS ══════════════════════════════════════════════════\n\n /// @notice Takes the bridged asset from the user into FastBridgeV2 custody. The asset will later be\n /// claimed by the relayer who completed the relay on the destination chain, or returned to the user\n /// via the cancel function if no relay is completed.\n function _takeBridgedUserAsset(address token, uint256 amount) internal returns (uint256 amountTaken) {\n if (token == NATIVE_GAS_TOKEN) {\n // For the native gas token, we just need to check that the supplied msg.value is correct.\n // Supplied `msg.value` is already in FastBridgeV2 custody.\n if (amount != msg.value) revert MsgValueIncorrect();\n amountTaken = msg.value;\n } else {\n // For ERC20s, token is explicitly transferred from the user to FastBridgeV2.\n // We don't allow non-zero `msg.value` to avoid extra funds from being stuck in FastBridgeV2.\n if (msg.value != 0) revert MsgValueIncorrect();\n // Throw an explicit error if the provided token address is not a contract.\n if (token.code.length == 0) revert TokenNotContract();\n\n // Use the balance difference as the amount taken in case of fee on transfer tokens.\n amountTaken = IERC20(token).balanceOf(address(this));\n IERC20(token).safeTransferFrom(msg.sender, address(this), amount);\n amountTaken = IERC20(token).balanceOf(address(this)) - amountTaken;\n }\n }\n\n /// @notice Calls the recipient's hook function with the specified zapData and validates\n /// the returned value.\n function _triggerZapWithChecks(address recipient, address token, uint256 amount, bytes calldata zapData) internal {\n // Call the recipient's hook function with the specified zapData, bubbling any revert messages.\n bytes memory returnData = Address.functionCallWithValue({\n target: recipient,\n data: abi.encodeCall(IZapRecipient.zap, (token, amount, zapData)),\n // Note: see `relay()` for reasoning behind passing msg.value.\n value: msg.value\n });\n\n // Explicit revert if no return data at all.\n if (returnData.length == 0) revert RecipientNoReturnValue();\n // Check that exactly a single return value was returned.\n if (returnData.length != 32) revert RecipientIncorrectReturnValue();\n // Return value should be abi-encoded hook function selector.\n if (bytes32(returnData) != bytes32(IZapRecipient.zap.selector)) {\n revert RecipientIncorrectReturnValue();\n }\n }\n\n /// @notice Calculates the time elapsed since a proof was submitted.\n /// @dev The proof.timestamp stores block timestamps as uint56 for gas optimization.\n /// _timeSince(proof) handles timestamp rollover when block.timestamp \u003e type(uint56).max but\n /// proof.timestamp \u003c type(uint56).max via an unchecked statement.\n /// @param proofBlockTimestamp The block timestamp when the proof was submitted.\n /// @return delta The time elapsed since proof submission.\n function _timeSince(uint56 proofBlockTimestamp) internal view returns (uint256 delta) {\n unchecked {\n delta = uint56(block.timestamp) - proofBlockTimestamp;\n }\n }\n\n /// @notice Validates all parameters required for a bridge transaction.\n /// @dev This function's complexity cannot be reduced due to the number of required checks,\n /// so we disable the code-complexity rule.\n // solhint-disable-next-line code-complexity\n function _validateBridgeParams(\n BridgeParams memory params,\n BridgeParamsV2 memory paramsV2,\n int256 exclusivityEndTime\n )\n internal\n view\n {\n // Check V1 (legacy) params.\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.sender == address(0) || params.to == address(0)) revert ZeroAddress();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n\n // Check V2 params.\n if (paramsV2.zapData.length \u003e MAX_ZAP_DATA_LENGTH) revert ZapDataLengthAboveMax();\n if (paramsV2.zapNative != 0 \u0026\u0026 params.destToken == NATIVE_GAS_TOKEN) {\n revert ZapNativeNotSupported();\n }\n\n // exclusivityEndTime must be in range [0 .. params.deadline].\n if (exclusivityEndTime \u003c 0 || exclusivityEndTime \u003e int256(params.deadline)) {\n revert ExclusivityParamsIncorrect();\n }\n }\n\n /// @notice Validates all parameters required for a relay transaction.\n function _validateRelayParams(bytes calldata request, bytes32 transactionId, address relayer) internal view {\n if (relayer == address(0)) revert ZeroAddress();\n // Check that the transaction has not been relayed yet and is for the current chain.\n if (bridgeRelays(transactionId)) revert TransactionRelayed();\n if (request.destChainId() != block.chainid) revert ChainIncorrect();\n // Check that the deadline for relay to happen has not passed yet.\n if (block.timestamp \u003e request.deadline()) revert DeadlineExceeded();\n // Check the exclusivity period, if it was specified and is still ongoing.\n address exclRelayer = request.exclusivityRelayer();\n if (exclRelayer != address(0) \u0026\u0026 exclRelayer != relayer \u0026\u0026 block.timestamp \u003c= request.exclusivityEndTime()) {\n revert ExclusivityPeriodNotPassed();\n }\n }\n}\n","language":"Solidity","languageVersion":"0.8.24","compilerVersion":"0.8.24","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"","srcMapRuntime":"","abiDefinition":[{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldCancelDelay","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newCancelDelay","type":"uint256"}],"name":"CancelDelayUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldFeeRate","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newFeeRate","type":"uint256"}],"name":"FeeRateUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"address","name":"recipient","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"FeesSwept","type":"event"},{"inputs":[{"internalType":"uint256","name":"newCancelDelay","type":"uint256"}],"name":"setCancelDelay","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"newFeeRate","type":"uint256"}],"name":"setProtocolFeeRate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"address","name":"recipient","type":"address"}],"name":"sweepProtocolFees","outputs":[],"stateMutability":"nonpayable","type":"function"}],"userDoc":{"kind":"user","methods":{"setCancelDelay(uint256)":{"notice":"Allows the governor to set the cancel delay. The cancel delay is the time period after the transaction deadline during which a transaction can be permissionlessly cancelled if it hasn't been proven by any Relayer."},"setProtocolFeeRate(uint256)":{"notice":"Allows the governor to set the protocol fee rate. The protocol fee is taken from the origin amount and is only applied to completed and claimed transactions."},"sweepProtocolFees(address,address)":{"notice":"Allows the governor to withdraw the accumulated protocol fees from the contract."}},"version":1},"developerDoc":{"kind":"dev","methods":{"setProtocolFeeRate(uint256)":{"details":"The protocol fee is abstracted away from the relayers; they always operate using the amounts after fees. The origin amount they see in the emitted log is what they get credited with."}},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"oldCancelDelay\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newCancelDelay\",\"type\":\"uint256\"}],\"name\":\"CancelDelayUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"oldFeeRate\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newFeeRate\",\"type\":\"uint256\"}],\"name\":\"FeeRateUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"FeesSwept\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"newCancelDelay\",\"type\":\"uint256\"}],\"name\":\"setCancelDelay\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"newFeeRate\",\"type\":\"uint256\"}],\"name\":\"setProtocolFeeRate\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"}],\"name\":\"sweepProtocolFees\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{\"setProtocolFeeRate(uint256)\":{\"details\":\"The protocol fee is abstracted away from the relayers; they always operate using the amounts after fees. The origin amount they see in the emitted log is what they get credited with.\"}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"setCancelDelay(uint256)\":{\"notice\":\"Allows the governor to set the cancel delay. The cancel delay is the time period after the transaction deadline during which a transaction can be permissionlessly cancelled if it hasn't been proven by any Relayer.\"},\"setProtocolFeeRate(uint256)\":{\"notice\":\"Allows the governor to set the protocol fee rate. The protocol fee is taken from the origin amount and is only applied to completed and claimed transactions.\"},\"sweepProtocolFees(address,address)\":{\"notice\":\"Allows the governor to withdraw the accumulated protocol fees from the contract.\"}},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeV2.sol\":\"IAdminV2\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeV2.sol\":{\"keccak256\":\"0xaab2ee7357681726f0faf799a48ddfbf45fb4da93b69abf61c33dde92b29b74d\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://673391bff9569efc0f9bd99e0e6fece0bc8e8af1f052bb071b407b267a17b3b5\",\"dweb:/ipfs/QmdQQZ6DxpJYhfpinwU5WjLugr2f6qP8h68b5GerhSMQ4j\"]}},\"version\":1}"},"hashes":{"setCancelDelay(uint256)":"1ea327c5","setProtocolFeeRate(uint256)":"b13aa2d6","sweepProtocolFees(address,address)":"06f333f2"}},"solidity/FastBridgeV2.sol:IAdminV2Errors":{"code":"0x","runtime-code":"0x","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.24 ^0.8.20 ^0.8.4;\n\n// contracts/interfaces/IAdminV2.sol\n\ninterface IAdminV2 {\n event CancelDelayUpdated(uint256 oldCancelDelay, uint256 newCancelDelay);\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n /// @notice Allows the governor to set the cancel delay. The cancel delay is the time period after the transaction\n /// deadline during which a transaction can be permissionlessly cancelled if it hasn't been proven by any Relayer.\n function setCancelDelay(uint256 newCancelDelay) external;\n\n /// @notice Allows the governor to set the protocol fee rate. The protocol fee is taken from the origin\n /// amount and is only applied to completed and claimed transactions.\n /// @dev The protocol fee is abstracted away from the relayers; they always operate using the amounts after fees.\n /// The origin amount they see in the emitted log is what they get credited with.\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n /// @notice Allows the governor to withdraw the accumulated protocol fees from the contract.\n function sweepProtocolFees(address token, address recipient) external;\n}\n\n// contracts/interfaces/IAdminV2Errors.sol\n\ninterface IAdminV2Errors {\n error CancelDelayBelowMin();\n error FeeRateAboveMax();\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IFastBridgeV2Errors.sol\n\ninterface IFastBridgeV2Errors {\n error AmountIncorrect();\n error ChainIncorrect();\n error ExclusivityParamsIncorrect();\n error MsgValueIncorrect();\n error SenderIncorrect();\n error StatusIncorrect();\n error TokenNotContract();\n error ZapDataLengthAboveMax();\n error ZapNativeNotSupported();\n error ZeroAddress();\n\n error RecipientIncorrectReturnValue();\n error RecipientNoReturnValue();\n\n error DeadlineExceeded();\n error DeadlineNotExceeded();\n error DeadlineTooShort();\n error DisputePeriodNotPassed();\n error DisputePeriodPassed();\n error ExclusivityPeriodNotPassed();\n\n error TransactionRelayed();\n}\n\n// contracts/interfaces/IMulticallTarget.sol\n\n/// @notice Interface for a contract that supports multiple calls from the same caller. Inspired by MulticallV3:\n/// https://github.com/mds1/multicall/blob/master/src/Multicall3.sol\ninterface IMulticallTarget {\n struct Result {\n bool success;\n bytes returnData;\n }\n\n /// @notice Executes multiple calls to this contract in a single transaction while preserving msg.sender.\n /// Return data from the calls is discarded.\n /// @dev This method is non-payable, so only calls with msg.value of 0 can be batched.\n /// If ignoreReverts is set to true, reverted calls will be skipped.\n /// Otherwise, the entire batch will revert with the original revert reason.\n /// @param data List of ABI-encoded calldata for the calls to execute\n /// @param ignoreReverts Whether to skip calls that revert\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external;\n\n /// @notice Executes multiple calls to this contract in a single transaction while preserving msg.sender.\n /// Return data from each call is preserved.\n /// @dev This method is non-payable, so only calls with msg.value of 0 can be batched.\n /// If ignoreReverts is set to true, reverted calls will be skipped.\n /// Otherwise, the entire batch will revert with the original revert reason.\n /// @param data List of ABI-encoded calldata for the calls to execute\n /// @param ignoreReverts Whether to skip calls that revert\n /// @return results List of results from the calls, each containing (success, returnData)\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results);\n}\n\n// contracts/interfaces/IZapRecipient.sol\n\n/// @notice Interface for contracts that can perform Zap operations. Such contracts could be used as Recipients\n/// in a FastBridge transaction that includes a Zap operation. The Zap Data should include instructions on how\n/// exactly the Zap operation should be executed, which would typically include the target address and calldata\n/// to use. The exact implementation of the Zap Data encoding is up to the Recipient contract.\ninterface IZapRecipient {\n /// @notice Performs a Zap operation with the given token and amount according to the provided Zap data.\n /// @param token The address of the token being used for the Zap operation.\n /// @param amount The amount of tokens to be used.\n /// @param zapData The encoded data specifying how the Zap operation should be executed.\n /// @return The function selector to indicate successful execution.\n function zap(address token, uint256 amount, bytes memory zapData) external payable returns (bytes4);\n}\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// contracts/interfaces/IFastBridgeV2.sol\n\ninterface IFastBridgeV2 is IFastBridge {\n enum BridgeStatus {\n NULL, // Doesn't exist yet.\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n struct BridgeTxDetails {\n BridgeStatus status;\n uint32 destChainId;\n uint56 proofBlockTimestamp;\n address proofRelayer;\n }\n\n struct BridgeRelay {\n uint48 blockNumber;\n uint48 blockTimestamp;\n address relayer;\n }\n\n /// @notice New params introduced in the FastBridgeV2.\n /// We are passing fields from the older BridgeParams struct outside of this struct for backwards compatibility.\n /// Note: quoteRelayer and quoteExclusivitySeconds are either both zero (indicating no exclusivity)\n /// or both non-zero (indicating exclusivity for the given period).\n /// Note: zapNative \u003e 0 can NOT be used with destToken = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE (native token)\n /// @param quoteRelayer Relayer that provided the quote for the transaction\n /// @param quoteExclusivitySeconds Period of time the quote relayer is guaranteed exclusivity after user's deposit\n /// @param quoteId Unique quote identifier used for tracking the quote\n /// @param zapNative ETH value to send to the recipient (if any)\n /// @param zapData Parameters for the Zap to the destination recipient (if any)\n struct BridgeParamsV2 {\n address quoteRelayer;\n int256 quoteExclusivitySeconds;\n bytes quoteId;\n uint256 zapNative;\n bytes zapData;\n }\n\n /// @notice Updated bridge transaction struct to include parameters introduced in FastBridgeV2.\n /// Note: only `exclusivityRelayer` can fill such a transaction until `exclusivityEndTime`.\n struct BridgeTransactionV2 {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n // Note: sendChainGas flag from V1 is deprecated\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n address exclusivityRelayer;\n uint256 exclusivityEndTime;\n uint256 zapNative; // ETH value to send to the recipient (if any)\n bytes zapData; // data to pass for the Zap action (if any)\n }\n\n event BridgeQuoteDetails(bytes32 indexed transactionId, bytes quoteId);\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability\n /// to provide temporary exclusivity fill rights for the quote relayer.\n /// @param params The parameters required to bridge\n /// @param paramsV2 The parameters for exclusivity fill rights (optional, can be left empty)\n function bridgeV2(BridgeParams memory params, BridgeParamsV2 memory paramsV2) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function relayV2(bytes memory request, address relayer) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param transactionId The transaction id associated with the encoded bridge transaction to prove\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function proveV2(bytes32 transactionId, bytes32 destTxHash, address relayer) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital.\n /// @notice Can only send funds to the relayer address on the proof.\n /// @param request The encoded bridge transaction to claim on origin chain\n function claimV2(bytes memory request) external;\n\n /// @notice Cancels an outstanding bridge transaction in case optimistic bridging failed and returns the full amount\n /// to the original sender.\n /// @param request The encoded bridge transaction to refund\n function cancelV2(bytes memory request) external;\n\n /// @notice Checks if a transaction has been relayed\n /// @param transactionId The ID of the transaction to check\n /// @return True if the transaction has been relayed, false otherwise\n function bridgeRelays(bytes32 transactionId) external view returns (bool);\n\n /// @notice Returns the status of a bridge transaction\n /// @param transactionId The ID of the bridge transaction\n /// @return BridgeStatus Status of the bridge transaction\n function bridgeStatuses(bytes32 transactionId) external view returns (BridgeStatus);\n\n /// @notice Returns the timestamp and relayer of a bridge proof\n /// @param transactionId The ID of the bridge transaction\n /// @return timestamp The timestamp of the bridge proof\n /// @return relayer The relayer address of the bridge proof\n function bridgeProofs(bytes32 transactionId) external view returns (uint96 timestamp, address relayer);\n\n /// @notice Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\n /// @param request The bridge request to decode\n function getBridgeTransactionV2(bytes memory request) external view returns (BridgeTransactionV2 memory);\n}\n\n// contracts/utils/MulticallTarget.sol\n\n// solhint-disable avoid-low-level-calls\n/// @notice Abstract contract template that supports batched calls while preserving msg.sender.\n/// Only calls with msg.value of 0 can be batched.\nabstract contract MulticallTarget is IMulticallTarget {\n error MulticallTarget__UndeterminedRevert();\n\n /// @inheritdoc IMulticallTarget\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external {\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\n if (!success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(result);\n }\n }\n }\n\n /// @inheritdoc IMulticallTarget\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results)\n {\n results = new Result[](data.length);\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (results[i].success, results[i].returnData) = address(this).delegatecall(data[i]);\n if (!results[i].success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(results[i].returnData);\n }\n }\n }\n\n /// @dev Bubbles the revert message from the underlying call.\n /// Note: preserves the same custom error or revert string, if one was used.\n /// Source: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v5.0.2/contracts/utils/Address.sol#L143-L158\n function _bubbleRevert(bytes memory returnData) internal pure {\n // Look for revert reason and bubble it up if present\n if (returnData.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n // solhint-disable-next-line no-inline-assembly\n assembly {\n let returndata_size := mload(returnData)\n revert(add(32, returnData), returndata_size)\n }\n } else {\n revert MulticallTarget__UndeterminedRevert();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// contracts/libs/BridgeTransactionV2.sol\n\n// solhint-disable no-inline-assembly\nlibrary BridgeTransactionV2Lib {\n uint16 internal constant VERSION = 2;\n\n // Offsets of the fields in the packed BridgeTransactionV2 struct\n // uint16 version [000 .. 002)\n // uint32 originChainId [002 .. 006)\n // uint32 destChainId [006 .. 010)\n // address originSender [010 .. 030)\n // address destRecipient [030 .. 050)\n // address originToken [050 .. 070)\n // address destToken [070 .. 090)\n // uint256 originAmount [090 .. 122)\n // uint256 destAmount [122 .. 154)\n // uint256 originFeeAmount [154 .. 186)\n // uint256 deadline [186 .. 218)\n // uint256 nonce [218 .. 250)\n // address exclusivityRelayer [250 .. 270)\n // uint256 exclusivityEndTime [270 .. 302)\n // uint256 zapNative [302 .. 334)\n // bytes zapData [334 .. ***)\n\n // forgefmt: disable-start\n uint256 private constant OFFSET_ORIGIN_CHAIN_ID = 2;\n uint256 private constant OFFSET_DEST_CHAIN_ID = 6;\n uint256 private constant OFFSET_ORIGIN_SENDER = 10;\n uint256 private constant OFFSET_DEST_RECIPIENT = 30;\n uint256 private constant OFFSET_ORIGIN_TOKEN = 50;\n uint256 private constant OFFSET_DEST_TOKEN = 70;\n uint256 private constant OFFSET_ORIGIN_AMOUNT = 90;\n uint256 private constant OFFSET_DEST_AMOUNT = 122;\n uint256 private constant OFFSET_ORIGIN_FEE_AMOUNT = 154;\n uint256 private constant OFFSET_DEADLINE = 186;\n uint256 private constant OFFSET_NONCE = 218;\n uint256 private constant OFFSET_EXCLUSIVITY_RELAYER = 250;\n uint256 private constant OFFSET_EXCLUSIVITY_END_TIME = 270;\n uint256 private constant OFFSET_ZAP_NATIVE = 302;\n uint256 private constant OFFSET_ZAP_DATA = 334;\n // forgefmt: disable-end\n\n error BridgeTransactionV2__InvalidEncodedTx();\n error BridgeTransactionV2__UnsupportedVersion(uint16 version);\n\n /// @notice Validates that the encoded transaction is a tightly packed encoded payload for BridgeTransactionV2.\n /// @dev Checks the minimum length and the version, use this function before decoding any of the fields.\n function validateV2(bytes calldata encodedTx) internal pure {\n // Check the minimum length: must at least include all static fields.\n if (encodedTx.length \u003c OFFSET_ZAP_DATA) revert BridgeTransactionV2__InvalidEncodedTx();\n // Once we validated the length, we can be sure that the version field is present.\n uint16 version_ = version(encodedTx);\n if (version_ != VERSION) revert BridgeTransactionV2__UnsupportedVersion(version_);\n }\n\n /// @notice Encodes the BridgeTransactionV2 struct by tightly packing the fields.\n /// @dev `abi.decode` will not work as a result of the tightly packed fields. Use `decodeV2` to decode instead.\n function encodeV2(IFastBridgeV2.BridgeTransactionV2 memory bridgeTx) internal pure returns (bytes memory) {\n // We split the encoding into two parts to avoid stack-too-deep error\n bytes memory firstPart = abi.encodePacked(\n VERSION,\n bridgeTx.originChainId,\n bridgeTx.destChainId,\n bridgeTx.originSender,\n bridgeTx.destRecipient,\n bridgeTx.originToken,\n bridgeTx.destToken,\n bridgeTx.originAmount\n );\n return abi.encodePacked(\n firstPart,\n bridgeTx.destAmount,\n bridgeTx.originFeeAmount,\n // Note: we skip the deprecated `sendChainGas` flag, which was present in BridgeTransaction V1\n bridgeTx.deadline,\n bridgeTx.nonce,\n // New V2 fields: exclusivity\n bridgeTx.exclusivityRelayer,\n bridgeTx.exclusivityEndTime,\n // New V2 fields: Zap\n bridgeTx.zapNative,\n bridgeTx.zapData\n );\n }\n\n /// @notice Decodes the BridgeTransactionV2 struct from the encoded transaction.\n /// @dev Encoded BridgeTransactionV2 struct must be tightly packed.\n /// Use `validateV2` before decoding to ensure the encoded transaction is valid.\n function decodeV2(bytes calldata encodedTx)\n internal\n pure\n returns (IFastBridgeV2.BridgeTransactionV2 memory bridgeTx)\n {\n bridgeTx.originChainId = originChainId(encodedTx);\n bridgeTx.destChainId = destChainId(encodedTx);\n bridgeTx.originSender = originSender(encodedTx);\n bridgeTx.destRecipient = destRecipient(encodedTx);\n bridgeTx.originToken = originToken(encodedTx);\n bridgeTx.destToken = destToken(encodedTx);\n bridgeTx.originAmount = originAmount(encodedTx);\n bridgeTx.destAmount = destAmount(encodedTx);\n bridgeTx.originFeeAmount = originFeeAmount(encodedTx);\n bridgeTx.deadline = deadline(encodedTx);\n bridgeTx.nonce = nonce(encodedTx);\n bridgeTx.exclusivityRelayer = exclusivityRelayer(encodedTx);\n bridgeTx.exclusivityEndTime = exclusivityEndTime(encodedTx);\n bridgeTx.zapNative = zapNative(encodedTx);\n bridgeTx.zapData = zapData(encodedTx);\n }\n\n /// @notice Extracts the version from the encoded transaction.\n function version(bytes calldata encodedTx) internal pure returns (uint16 version_) {\n // Load 32 bytes from the start and shift it 240 bits to the right to get the highest 16 bits.\n assembly {\n version_ := shr(240, calldataload(encodedTx.offset))\n }\n }\n\n /// @notice Extracts the origin chain ID from the encoded transaction.\n function originChainId(bytes calldata encodedTx) internal pure returns (uint32 originChainId_) {\n // Load 32 bytes from the offset and shift it 224 bits to the right to get the highest 32 bits.\n assembly {\n originChainId_ := shr(224, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_CHAIN_ID)))\n }\n }\n\n /// @notice Extracts the destination chain ID from the encoded transaction.\n function destChainId(bytes calldata encodedTx) internal pure returns (uint32 destChainId_) {\n // Load 32 bytes from the offset and shift it 224 bits to the right to get the highest 32 bits.\n assembly {\n destChainId_ := shr(224, calldataload(add(encodedTx.offset, OFFSET_DEST_CHAIN_ID)))\n }\n }\n\n /// @notice Extracts the origin sender from the encoded transaction.\n function originSender(bytes calldata encodedTx) internal pure returns (address originSender_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n originSender_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_SENDER)))\n }\n }\n\n /// @notice Extracts the destination recipient from the encoded transaction.\n function destRecipient(bytes calldata encodedTx) internal pure returns (address destRecipient_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n destRecipient_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_DEST_RECIPIENT)))\n }\n }\n\n /// @notice Extracts the origin token from the encoded transaction.\n function originToken(bytes calldata encodedTx) internal pure returns (address originToken_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n originToken_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_TOKEN)))\n }\n }\n\n /// @notice Extracts the destination token from the encoded transaction.\n function destToken(bytes calldata encodedTx) internal pure returns (address destToken_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n destToken_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_DEST_TOKEN)))\n }\n }\n\n /// @notice Extracts the origin amount from the encoded transaction.\n function originAmount(bytes calldata encodedTx) internal pure returns (uint256 originAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n originAmount_ := calldataload(add(encodedTx.offset, OFFSET_ORIGIN_AMOUNT))\n }\n }\n\n /// @notice Extracts the destination amount from the encoded transaction.\n function destAmount(bytes calldata encodedTx) internal pure returns (uint256 destAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n destAmount_ := calldataload(add(encodedTx.offset, OFFSET_DEST_AMOUNT))\n }\n }\n\n /// @notice Extracts the origin fee amount from the encoded transaction.\n function originFeeAmount(bytes calldata encodedTx) internal pure returns (uint256 originFeeAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n originFeeAmount_ := calldataload(add(encodedTx.offset, OFFSET_ORIGIN_FEE_AMOUNT))\n }\n }\n\n /// @notice Extracts the deadline from the encoded transaction.\n function deadline(bytes calldata encodedTx) internal pure returns (uint256 deadline_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n deadline_ := calldataload(add(encodedTx.offset, OFFSET_DEADLINE))\n }\n }\n\n /// @notice Extracts the nonce from the encoded transaction.\n function nonce(bytes calldata encodedTx) internal pure returns (uint256 nonce_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n nonce_ := calldataload(add(encodedTx.offset, OFFSET_NONCE))\n }\n }\n\n /// @notice Extracts the exclusivity relayer from the encoded transaction.\n function exclusivityRelayer(bytes calldata encodedTx) internal pure returns (address exclusivityRelayer_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n exclusivityRelayer_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_EXCLUSIVITY_RELAYER)))\n }\n }\n\n /// @notice Extracts the exclusivity end time from the encoded transaction.\n function exclusivityEndTime(bytes calldata encodedTx) internal pure returns (uint256 exclusivityEndTime_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n exclusivityEndTime_ := calldataload(add(encodedTx.offset, OFFSET_EXCLUSIVITY_END_TIME))\n }\n }\n\n /// @notice Extracts the Zap's native value from the encoded transaction.\n function zapNative(bytes calldata encodedTx) internal pure returns (uint256 zapNative_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n zapNative_ := calldataload(add(encodedTx.offset, OFFSET_ZAP_NATIVE))\n }\n }\n\n /// @notice Extracts the Zap's data from the encoded transaction.\n function zapData(bytes calldata encodedTx) internal pure returns (bytes calldata zapData_) {\n zapData_ = encodedTx[OFFSET_ZAP_DATA:];\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/AdminV2.sol\n\n// ════════════════════════════════════════════════ INTERFACES ═════════════════════════════════════════════════════\n\n// ═════════════════════════════════════════════ EXTERNAL IMPORTS ══════════════════════════════════════════════════\n\n/// @title AdminV2\n/// @notice Provides administrative functions and controls for managing the FastBridgeV2 contract,\n/// including access control and configuration settings.\ncontract AdminV2 is AccessControlEnumerable, IAdminV2, IAdminV2Errors {\n using SafeERC20 for IERC20;\n\n /// @notice The address reserved for the native gas token (ETH on Ethereum and most L2s, AVAX on Avalanche, etc.).\n address public constant NATIVE_GAS_TOKEN = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice The role identifier for the Quoter API's off-chain authentication.\n /// @dev Only addresses with this role can post FastBridge quotes to the API.\n bytes32 public constant QUOTER_ROLE = keccak256(\"QUOTER_ROLE\");\n\n /// @notice The role identifier for the Prover's on-chain authentication in FastBridge.\n /// @dev Only addresses with this role can provide proofs that a FastBridge request has been relayed.\n bytes32 public constant PROVER_ROLE = keccak256(\"PROVER_ROLE\");\n\n /// @notice The role identifier for the Guard's on-chain authentication in FastBridge.\n /// @dev Only addresses with this role can dispute submitted relay proofs during the dispute period.\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n\n /// @notice The role identifier for the Canceler's on-chain authentication in FastBridge.\n /// @dev Only addresses with this role can cancel a FastBridge transaction without the cancel delay.\n bytes32 public constant CANCELER_ROLE = keccak256(\"CANCELER_ROLE\");\n\n /// @notice The role identifier for the Governor's on-chain administrative authority.\n /// @dev Only addresses with this role can perform administrative tasks within the contract.\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n /// @notice The denominator for fee rates, representing 100%.\n uint256 public constant FEE_BPS = 1e6;\n /// @notice The maximum protocol fee rate: 1% of the origin amount.\n uint256 public constant FEE_RATE_MAX = 0.01e6;\n\n /// @notice The minimum cancel delay that can be set by the governor.\n uint256 public constant MIN_CANCEL_DELAY = 1 hours;\n /// @notice The default cancel delay set during contract deployment.\n uint256 public constant DEFAULT_CANCEL_DELAY = 1 days;\n\n /// @notice The protocol fee rate taken on the origin amount deposited in the origin chain.\n uint256 public protocolFeeRate;\n\n /// @notice The accumulated protocol fee amounts.\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice The delay period after which a transaction can be permissionlessly cancelled.\n uint256 public cancelDelay;\n\n /// @notice This variable is deprecated and should not be used.\n /// @dev Use ZapNative V2 requests instead.\n uint256 public immutable chainGasAmount = 0;\n\n constructor(address defaultAdmin) {\n _grantRole(DEFAULT_ADMIN_ROLE, defaultAdmin);\n _setCancelDelay(DEFAULT_CANCEL_DELAY);\n }\n\n /// @inheritdoc IAdminV2\n function setCancelDelay(uint256 newCancelDelay) external onlyRole(GOVERNOR_ROLE) {\n _setCancelDelay(newCancelDelay);\n }\n\n /// @inheritdoc IAdminV2\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n if (newFeeRate \u003e FEE_RATE_MAX) revert FeeRateAboveMax();\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n /// @inheritdoc IAdminV2\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n // Early exit if no accumulated fees.\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return;\n // Reset the accumulated fees first.\n protocolFees[token] = 0;\n emit FeesSwept(token, recipient, feeAmount);\n // Sweep the fees as the last transaction action.\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(recipient), feeAmount);\n } else {\n IERC20(token).safeTransfer(recipient, feeAmount);\n }\n }\n\n /// @notice Internal logic to set the cancel delay. Security checks are performed outside of this function.\n /// @dev This function is marked as private to prevent child contracts from calling it directly.\n function _setCancelDelay(uint256 newCancelDelay) private {\n if (newCancelDelay \u003c MIN_CANCEL_DELAY) revert CancelDelayBelowMin();\n uint256 oldCancelDelay = cancelDelay;\n cancelDelay = newCancelDelay;\n emit CancelDelayUpdated(oldCancelDelay, newCancelDelay);\n }\n}\n\n// contracts/FastBridgeV2.sol\n\n// ════════════════════════════════════════════════ INTERFACES ═════════════════════════════════════════════════════\n\n// ═════════════════════════════════════════════ INTERNAL IMPORTS ══════════════════════════════════════════════════\n\n// ═════════════════════════════════════════════ EXTERNAL IMPORTS ══════════════════════════════════════════════════\n\n/// @title FastBridgeV2\n/// @notice Core component of the SynapseRFQ protocol, enabling Relayers (Solvers) to fulfill bridge requests.\n/// Supports ERC20 and native gas tokens, along with the Zap feature for executing actions on the destination chain.\n/// Users interact with the off-chain Quoter API to obtain a current quote for a bridge transaction.\n/// They then submit the bridge request with the quote to this contract, depositing their assets in escrow.\n/// Relayers can fulfill requests by relaying them to the destination chain and must prove fulfillment to claim funds.\n/// Guards monitor proofs and can dispute discrepancies.\n/// Users can reclaim funds by cancelling their requests if it has not been fulfilled within the specified deadline.\ncontract FastBridgeV2 is AdminV2, MulticallTarget, IFastBridgeV2, IFastBridgeV2Errors {\n using BridgeTransactionV2Lib for bytes;\n using SafeERC20 for IERC20;\n\n /// @notice The duration of the dispute period for relayed transactions.\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice The minimum required time between transaction request and deadline.\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n /// @notice The maximum allowed length for zapData.\n uint256 public constant MAX_ZAP_DATA_LENGTH = 2 ** 16 - 1;\n\n /// @notice Maps transaction IDs to bridge details (status, destination chain ID, proof timestamp, and relayer).\n /// Note: this is only stored for transactions having local chain as the origin chain.\n mapping(bytes32 =\u003e BridgeTxDetails) public bridgeTxDetails;\n /// @notice Maps transaction IDs to relay details (block number, block timestamp, and relayer).\n /// Note: this is only stored for transactions having local chain as the destination chain.\n mapping(bytes32 =\u003e BridgeRelay) public bridgeRelayDetails;\n /// @notice Maps sender addresses to their unique bridge nonce.\n mapping(address =\u003e uint256) public senderNonces;\n\n /// @notice This variable is deprecated and should not be used.\n /// @dev Replaced by senderNonces.\n uint256 public immutable nonce = 0;\n /// @notice The block number at which this contract was deployed.\n uint256 public immutable deployBlock;\n\n /// @notice Initializes the FastBridgeV2 contract with the provided default admin,\n /// sets the default cancel delay, and records the deploy block number.\n constructor(address defaultAdmin) AdminV2(defaultAdmin) {\n deployBlock = block.number;\n }\n\n // ══════════════════════════════════════ EXTERNAL MUTABLE (USER FACING) ═══════════════════════════════════════════\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n bridgeV2({\n params: params,\n paramsV2: BridgeParamsV2({\n quoteRelayer: address(0),\n quoteExclusivitySeconds: 0,\n quoteId: bytes(\"\"),\n zapNative: 0,\n zapData: bytes(\"\")\n })\n });\n }\n\n /// Note: this function is deprecated and will be removed in a future version.\n /// @dev Replaced by `cancel`.\n /// @inheritdoc IFastBridge\n function refund(bytes calldata request) external {\n cancelV2(request);\n }\n\n // ══════════════════════════════════════ EXTERNAL MUTABLE (AGENT FACING) ══════════════════════════════════════════\n\n /// @inheritdoc IFastBridge\n function relay(bytes calldata request) external payable {\n // `relay` override will validate the request.\n relayV2({request: request, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes calldata request, bytes32 destTxHash) external {\n request.validateV2();\n proveV2({transactionId: keccak256(request), destTxHash: destTxHash, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridgeV2\n function claimV2(bytes calldata request) external {\n // `claim` override will validate the request.\n claim({request: request, to: address(0)});\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n // Aggregate the read operations from the same storage slot.\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n address disputedRelayer = $.proofRelayer;\n BridgeStatus status = $.status;\n uint56 proofBlockTimestamp = $.proofBlockTimestamp;\n\n // Can only dispute a RELAYER_PROVED transaction within the dispute period.\n if (status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(proofBlockTimestamp) \u003e DISPUTE_PERIOD) {\n revert DisputePeriodPassed();\n }\n\n // Update status to REQUESTED and delete the disputed proof details.\n // Note: these are storage writes.\n $.status = BridgeStatus.REQUESTED;\n $.proofRelayer = address(0);\n $.proofBlockTimestamp = 0;\n\n emit BridgeProofDisputed(transactionId, disputedRelayer);\n }\n\n // ══════════════════════════════════════════════ EXTERNAL VIEWS ═══════════════════════════════════════════════════\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n // The correct relayer can only claim a RELAYER_PROVED transaction after the dispute period.\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n if ($.status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if ($.proofRelayer != relayer) revert SenderIncorrect();\n\n return _timeSince($.proofBlockTimestamp) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n /// @dev This method is added to achieve backwards compatibility with decoding requests into V1 structs:\n /// - `zapNative` is partially reported as a zero/non-zero flag\n /// - `zapData` is ignored\n /// In order to process all kinds of requests use getBridgeTransactionV2 instead.\n function getBridgeTransaction(bytes calldata request) external view returns (BridgeTransaction memory) {\n // Try decoding into V2 struct first. This will revert if V1 struct is passed.\n try this.getBridgeTransactionV2(request) returns (BridgeTransactionV2 memory txV2) {\n // Note: we entirely ignore the zapData field, as it was not present in V1.\n return BridgeTransaction({\n originChainId: txV2.originChainId,\n destChainId: txV2.destChainId,\n originSender: txV2.originSender,\n destRecipient: txV2.destRecipient,\n originToken: txV2.originToken,\n destToken: txV2.destToken,\n originAmount: txV2.originAmount,\n destAmount: txV2.destAmount,\n originFeeAmount: txV2.originFeeAmount,\n sendChainGas: txV2.zapNative != 0,\n deadline: txV2.deadline,\n nonce: txV2.nonce\n });\n } catch {\n // Fallback to V1 struct.\n return abi.decode(request, (BridgeTransaction));\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function getBridgeTransactionV2(bytes calldata request) external pure returns (BridgeTransactionV2 memory) {\n request.validateV2();\n return BridgeTransactionV2Lib.decodeV2(request);\n }\n\n // ═══════════════════════════════════════ PUBLIC MUTABLE (USER FACING) ════════════════════════════════════════════\n\n /// @inheritdoc IFastBridgeV2\n function bridgeV2(BridgeParams memory params, BridgeParamsV2 memory paramsV2) public payable {\n // If relayer exclusivity is not intended for this bridge, set exclusivityEndTime to static zero.\n // Otherwise, set exclusivity to expire at the current block ts offset by quoteExclusivitySeconds.\n int256 exclusivityEndTime = 0;\n if (paramsV2.quoteRelayer != address(0)) {\n exclusivityEndTime = int256(block.timestamp) + paramsV2.quoteExclusivitySeconds;\n }\n _validateBridgeParams(params, paramsV2, exclusivityEndTime);\n\n // Transfer tokens to bridge contract. We use the actual transferred amount in case of transfer fees.\n uint256 originAmount = _takeBridgedUserAsset(params.originToken, params.originAmount);\n\n // Track the amount of origin token owed to protocol.\n uint256 originFeeAmount = 0;\n if (protocolFeeRate \u003e 0) {\n originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n // The Relayer filling this request will be paid the originAmount after fees.\n // Note: the protocol fees will be accumulated only when the Relayer claims the origin collateral.\n originAmount -= originFeeAmount;\n }\n\n // Hash the bridge request and set the initial status to REQUESTED.\n bytes memory request = BridgeTransactionV2Lib.encodeV2(\n BridgeTransactionV2({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n deadline: params.deadline,\n // Increment the sender's nonce on every bridge.\n nonce: senderNonces[params.sender]++,\n exclusivityRelayer: paramsV2.quoteRelayer,\n // We checked exclusivityEndTime to be in range [0 .. params.deadline] above, so can safely cast.\n exclusivityEndTime: uint256(exclusivityEndTime),\n zapNative: paramsV2.zapNative,\n zapData: paramsV2.zapData\n })\n );\n bytes32 transactionId = keccak256(request);\n // Note: the tx status will be updated throughout the tx lifecycle, while destChainId is set once here.\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n bridgeTxDetails[transactionId].destChainId = params.dstChainId;\n\n emit BridgeRequested({\n transactionId: transactionId,\n sender: params.sender,\n request: request,\n destChainId: params.dstChainId,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n sendChainGas: paramsV2.zapNative != 0\n });\n emit BridgeQuoteDetails(transactionId, paramsV2.quoteId);\n }\n\n /// @inheritdoc IFastBridgeV2\n function cancelV2(bytes calldata request) public {\n // Decode the request and check that it could be cancelled.\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n\n // Can only cancel a REQUESTED transaction after its deadline expires.\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n if ($.status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n\n // Permissionless cancel is only allowed after `cancelDelay` on top of the deadline.\n uint256 deadline = request.deadline();\n if (!hasRole(CANCELER_ROLE, msg.sender)) deadline += cancelDelay;\n if (block.timestamp \u003c= deadline) revert DeadlineNotExceeded();\n\n // Update status to REFUNDED.\n // Note: this is a storage write.\n $.status = BridgeStatus.REFUNDED;\n\n // Return the full amount (collateral + protocol fees) to the original sender.\n // The protocol fees are only accumulated when the transaction is claimed, so we don't need to update them here.\n address to = request.originSender();\n address token = request.originToken();\n uint256 amount = request.originAmount() + request.originFeeAmount();\n\n // Emit the event before any external calls.\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n\n // Return the funds to the original sender as last transaction action.\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(to), amount);\n } else {\n IERC20(token).safeTransfer(to, amount);\n }\n }\n\n // ═══════════════════════════════════════ PUBLIC MUTABLE (AGENT FACING) ═══════════════════════════════════════════\n\n /// @inheritdoc IFastBridgeV2\n function relayV2(bytes calldata request, address relayer) public payable {\n // Decode the request and check that it could be relayed.\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n _validateRelayParams(request, transactionId, relayer);\n\n // Mark the bridge request as relayed by saving the relayer and the block details.\n bridgeRelayDetails[transactionId].blockNumber = uint48(block.number);\n bridgeRelayDetails[transactionId].blockTimestamp = uint48(block.timestamp);\n bridgeRelayDetails[transactionId].relayer = relayer;\n\n // Transfer tokens to recipient on destination chain and trigger Zap if requested.\n address to = request.destRecipient();\n address token = request.destToken();\n uint256 amount = request.destAmount();\n uint256 zapNative = request.zapNative();\n\n // Emit the event before any external calls.\n emit BridgeRelayed({\n transactionId: transactionId,\n relayer: relayer,\n to: to,\n originChainId: request.originChainId(),\n originToken: request.originToken(),\n destToken: token,\n originAmount: request.originAmount(),\n destAmount: amount,\n chainGasAmount: zapNative\n });\n\n // All state changes have been done at this point, can proceed to the external calls.\n // This follows the checks-effects-interactions pattern to mitigate potential reentrancy attacks.\n if (token == NATIVE_GAS_TOKEN) {\n // For the native gas token, additional zapNative is not allowed.\n if (zapNative != 0) revert ZapNativeNotSupported();\n // Check that the correct msg.value was sent.\n if (msg.value != amount) revert MsgValueIncorrect();\n // Don't do a native transfer yet: we will handle it alongside the Zap below.\n } else {\n // For ERC20s, we check that the correct msg.value was sent.\n if (msg.value != zapNative) revert MsgValueIncorrect();\n // We need to transfer the tokens from the Relayer to the recipient first before performing an\n // optional post-transfer Zap.\n IERC20(token).safeTransferFrom(msg.sender, to, amount);\n }\n // At this point we have done:\n // - Transferred the requested amount of ERC20 tokens to the recipient.\n // At this point we have confirmed:\n // - For ERC20s: msg.value matches the requested zapNative amount.\n // - For the native gas token: msg.value matches the requested destAmount.\n // Remaining optional things to do:\n // - Forward the full msg.value to the recipient (if non-zero).\n // - Trigger a Zap (if zapData is present).\n bytes calldata zapData = request.zapData();\n if (zapData.length != 0) {\n // Zap Data is present: Zap has been requested by the recipient. Trigger it forwarding the full msg.value.\n _triggerZapWithChecks({recipient: to, token: token, amount: amount, zapData: zapData});\n // Note: if token has a fee on transfers, the recipient will have received less than `amount`.\n // This is a very niche edge case and should be handled by the recipient contract.\n } else if (msg.value != 0) {\n // Zap Data is missing, but msg.value was sent. This could happen in two different cases:\n // - Relay with the native gas token is happening.\n // - Relay with ERC20 is happening, with a `zapNative \u003e 0` request.\n // In both cases, we need to transfer the full msg.value to the recipient.\n Address.sendValue(payable(to), msg.value);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function proveV2(bytes32 transactionId, bytes32 destTxHash, address relayer) public onlyRole(PROVER_ROLE) {\n // Can only prove a REQUESTED transaction.\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n if ($.status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n\n // Update status to RELAYER_PROVED and store the proof details.\n // Note: these are storage writes.\n $.status = BridgeStatus.RELAYER_PROVED;\n $.proofBlockTimestamp = uint56(block.timestamp);\n $.proofRelayer = relayer;\n\n emit BridgeProofProvided(transactionId, relayer, destTxHash);\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes calldata request, address to) public {\n // Decode the request and check that it could be claimed.\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n\n // Aggregate the read operations from the same storage slot.\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n address proofRelayer = $.proofRelayer;\n BridgeStatus status = $.status;\n uint56 proofBlockTimestamp = $.proofBlockTimestamp;\n\n // Can only claim a RELAYER_PROVED transaction after the dispute period.\n if (status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(proofBlockTimestamp) \u003c= DISPUTE_PERIOD) revert DisputePeriodNotPassed();\n if (to == address(0)) {\n // Anyone could claim the funds to the proven relayer on their behalf.\n to = proofRelayer;\n } else if (proofRelayer != msg.sender) {\n // Only the proven relayer could specify an address to claim the funds to.\n revert SenderIncorrect();\n }\n\n // Update status to RELAYER_CLAIMED and transfer the origin collateral to the specified claim address.\n // Note: this is a storage write.\n $.status = BridgeStatus.RELAYER_CLAIMED;\n\n // Accumulate protocol fees if origin fee amount exists.\n address token = request.originToken();\n uint256 amount = request.originAmount();\n uint256 originFeeAmount = request.originFeeAmount();\n if (originFeeAmount \u003e 0) protocolFees[token] += originFeeAmount;\n\n // Emit the event before any external calls.\n emit BridgeDepositClaimed(transactionId, proofRelayer, to, token, amount);\n\n // Complete the relayer claim as the last transaction action.\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(to), amount);\n } else {\n IERC20(token).safeTransfer(to, amount);\n }\n }\n\n // ═══════════════════════════════════════════════ PUBLIC VIEWS ════════════════════════════════════════════════════\n\n /// @inheritdoc IFastBridgeV2\n function bridgeStatuses(bytes32 transactionId) public view returns (BridgeStatus status) {\n return bridgeTxDetails[transactionId].status;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeProofs(bytes32 transactionId) public view returns (uint96 timestamp, address relayer) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n timestamp = $.proofBlockTimestamp;\n relayer = $.proofRelayer;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeRelays(bytes32 transactionId) public view returns (bool) {\n // This transaction has been relayed if the relayer address is recorded.\n return bridgeRelayDetails[transactionId].relayer != address(0);\n }\n\n // ═════════════════════════════════════════════ INTERNAL METHODS ══════════════════════════════════════════════════\n\n /// @notice Takes the bridged asset from the user into FastBridgeV2 custody. The asset will later be\n /// claimed by the relayer who completed the relay on the destination chain, or returned to the user\n /// via the cancel function if no relay is completed.\n function _takeBridgedUserAsset(address token, uint256 amount) internal returns (uint256 amountTaken) {\n if (token == NATIVE_GAS_TOKEN) {\n // For the native gas token, we just need to check that the supplied msg.value is correct.\n // Supplied `msg.value` is already in FastBridgeV2 custody.\n if (amount != msg.value) revert MsgValueIncorrect();\n amountTaken = msg.value;\n } else {\n // For ERC20s, token is explicitly transferred from the user to FastBridgeV2.\n // We don't allow non-zero `msg.value` to avoid extra funds from being stuck in FastBridgeV2.\n if (msg.value != 0) revert MsgValueIncorrect();\n // Throw an explicit error if the provided token address is not a contract.\n if (token.code.length == 0) revert TokenNotContract();\n\n // Use the balance difference as the amount taken in case of fee on transfer tokens.\n amountTaken = IERC20(token).balanceOf(address(this));\n IERC20(token).safeTransferFrom(msg.sender, address(this), amount);\n amountTaken = IERC20(token).balanceOf(address(this)) - amountTaken;\n }\n }\n\n /// @notice Calls the recipient's hook function with the specified zapData and validates\n /// the returned value.\n function _triggerZapWithChecks(address recipient, address token, uint256 amount, bytes calldata zapData) internal {\n // Call the recipient's hook function with the specified zapData, bubbling any revert messages.\n bytes memory returnData = Address.functionCallWithValue({\n target: recipient,\n data: abi.encodeCall(IZapRecipient.zap, (token, amount, zapData)),\n // Note: see `relay()` for reasoning behind passing msg.value.\n value: msg.value\n });\n\n // Explicit revert if no return data at all.\n if (returnData.length == 0) revert RecipientNoReturnValue();\n // Check that exactly a single return value was returned.\n if (returnData.length != 32) revert RecipientIncorrectReturnValue();\n // Return value should be abi-encoded hook function selector.\n if (bytes32(returnData) != bytes32(IZapRecipient.zap.selector)) {\n revert RecipientIncorrectReturnValue();\n }\n }\n\n /// @notice Calculates the time elapsed since a proof was submitted.\n /// @dev The proof.timestamp stores block timestamps as uint56 for gas optimization.\n /// _timeSince(proof) handles timestamp rollover when block.timestamp \u003e type(uint56).max but\n /// proof.timestamp \u003c type(uint56).max via an unchecked statement.\n /// @param proofBlockTimestamp The block timestamp when the proof was submitted.\n /// @return delta The time elapsed since proof submission.\n function _timeSince(uint56 proofBlockTimestamp) internal view returns (uint256 delta) {\n unchecked {\n delta = uint56(block.timestamp) - proofBlockTimestamp;\n }\n }\n\n /// @notice Validates all parameters required for a bridge transaction.\n /// @dev This function's complexity cannot be reduced due to the number of required checks,\n /// so we disable the code-complexity rule.\n // solhint-disable-next-line code-complexity\n function _validateBridgeParams(\n BridgeParams memory params,\n BridgeParamsV2 memory paramsV2,\n int256 exclusivityEndTime\n )\n internal\n view\n {\n // Check V1 (legacy) params.\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.sender == address(0) || params.to == address(0)) revert ZeroAddress();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n\n // Check V2 params.\n if (paramsV2.zapData.length \u003e MAX_ZAP_DATA_LENGTH) revert ZapDataLengthAboveMax();\n if (paramsV2.zapNative != 0 \u0026\u0026 params.destToken == NATIVE_GAS_TOKEN) {\n revert ZapNativeNotSupported();\n }\n\n // exclusivityEndTime must be in range [0 .. params.deadline].\n if (exclusivityEndTime \u003c 0 || exclusivityEndTime \u003e int256(params.deadline)) {\n revert ExclusivityParamsIncorrect();\n }\n }\n\n /// @notice Validates all parameters required for a relay transaction.\n function _validateRelayParams(bytes calldata request, bytes32 transactionId, address relayer) internal view {\n if (relayer == address(0)) revert ZeroAddress();\n // Check that the transaction has not been relayed yet and is for the current chain.\n if (bridgeRelays(transactionId)) revert TransactionRelayed();\n if (request.destChainId() != block.chainid) revert ChainIncorrect();\n // Check that the deadline for relay to happen has not passed yet.\n if (block.timestamp \u003e request.deadline()) revert DeadlineExceeded();\n // Check the exclusivity period, if it was specified and is still ongoing.\n address exclRelayer = request.exclusivityRelayer();\n if (exclRelayer != address(0) \u0026\u0026 exclRelayer != relayer \u0026\u0026 block.timestamp \u003c= request.exclusivityEndTime()) {\n revert ExclusivityPeriodNotPassed();\n }\n }\n}\n","language":"Solidity","languageVersion":"0.8.24","compilerVersion":"0.8.24","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"","srcMapRuntime":"","abiDefinition":[{"inputs":[],"name":"CancelDelayBelowMin","type":"error"},{"inputs":[],"name":"FeeRateAboveMax","type":"error"}],"userDoc":{"kind":"user","methods":{},"version":1},"developerDoc":{"kind":"dev","methods":{},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[],\"name\":\"CancelDelayBelowMin\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"FeeRateAboveMax\",\"type\":\"error\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeV2.sol\":\"IAdminV2Errors\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeV2.sol\":{\"keccak256\":\"0xaab2ee7357681726f0faf799a48ddfbf45fb4da93b69abf61c33dde92b29b74d\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://673391bff9569efc0f9bd99e0e6fece0bc8e8af1f052bb071b407b267a17b3b5\",\"dweb:/ipfs/QmdQQZ6DxpJYhfpinwU5WjLugr2f6qP8h68b5GerhSMQ4j\"]}},\"version\":1}"},"hashes":{}},"solidity/FastBridgeV2.sol:IERC165":{"code":"0x","runtime-code":"0x","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.24 ^0.8.20 ^0.8.4;\n\n// contracts/interfaces/IAdminV2.sol\n\ninterface IAdminV2 {\n event CancelDelayUpdated(uint256 oldCancelDelay, uint256 newCancelDelay);\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n /// @notice Allows the governor to set the cancel delay. The cancel delay is the time period after the transaction\n /// deadline during which a transaction can be permissionlessly cancelled if it hasn't been proven by any Relayer.\n function setCancelDelay(uint256 newCancelDelay) external;\n\n /// @notice Allows the governor to set the protocol fee rate. The protocol fee is taken from the origin\n /// amount and is only applied to completed and claimed transactions.\n /// @dev The protocol fee is abstracted away from the relayers; they always operate using the amounts after fees.\n /// The origin amount they see in the emitted log is what they get credited with.\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n /// @notice Allows the governor to withdraw the accumulated protocol fees from the contract.\n function sweepProtocolFees(address token, address recipient) external;\n}\n\n// contracts/interfaces/IAdminV2Errors.sol\n\ninterface IAdminV2Errors {\n error CancelDelayBelowMin();\n error FeeRateAboveMax();\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IFastBridgeV2Errors.sol\n\ninterface IFastBridgeV2Errors {\n error AmountIncorrect();\n error ChainIncorrect();\n error ExclusivityParamsIncorrect();\n error MsgValueIncorrect();\n error SenderIncorrect();\n error StatusIncorrect();\n error TokenNotContract();\n error ZapDataLengthAboveMax();\n error ZapNativeNotSupported();\n error ZeroAddress();\n\n error RecipientIncorrectReturnValue();\n error RecipientNoReturnValue();\n\n error DeadlineExceeded();\n error DeadlineNotExceeded();\n error DeadlineTooShort();\n error DisputePeriodNotPassed();\n error DisputePeriodPassed();\n error ExclusivityPeriodNotPassed();\n\n error TransactionRelayed();\n}\n\n// contracts/interfaces/IMulticallTarget.sol\n\n/// @notice Interface for a contract that supports multiple calls from the same caller. Inspired by MulticallV3:\n/// https://github.com/mds1/multicall/blob/master/src/Multicall3.sol\ninterface IMulticallTarget {\n struct Result {\n bool success;\n bytes returnData;\n }\n\n /// @notice Executes multiple calls to this contract in a single transaction while preserving msg.sender.\n /// Return data from the calls is discarded.\n /// @dev This method is non-payable, so only calls with msg.value of 0 can be batched.\n /// If ignoreReverts is set to true, reverted calls will be skipped.\n /// Otherwise, the entire batch will revert with the original revert reason.\n /// @param data List of ABI-encoded calldata for the calls to execute\n /// @param ignoreReverts Whether to skip calls that revert\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external;\n\n /// @notice Executes multiple calls to this contract in a single transaction while preserving msg.sender.\n /// Return data from each call is preserved.\n /// @dev This method is non-payable, so only calls with msg.value of 0 can be batched.\n /// If ignoreReverts is set to true, reverted calls will be skipped.\n /// Otherwise, the entire batch will revert with the original revert reason.\n /// @param data List of ABI-encoded calldata for the calls to execute\n /// @param ignoreReverts Whether to skip calls that revert\n /// @return results List of results from the calls, each containing (success, returnData)\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results);\n}\n\n// contracts/interfaces/IZapRecipient.sol\n\n/// @notice Interface for contracts that can perform Zap operations. Such contracts could be used as Recipients\n/// in a FastBridge transaction that includes a Zap operation. The Zap Data should include instructions on how\n/// exactly the Zap operation should be executed, which would typically include the target address and calldata\n/// to use. The exact implementation of the Zap Data encoding is up to the Recipient contract.\ninterface IZapRecipient {\n /// @notice Performs a Zap operation with the given token and amount according to the provided Zap data.\n /// @param token The address of the token being used for the Zap operation.\n /// @param amount The amount of tokens to be used.\n /// @param zapData The encoded data specifying how the Zap operation should be executed.\n /// @return The function selector to indicate successful execution.\n function zap(address token, uint256 amount, bytes memory zapData) external payable returns (bytes4);\n}\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// contracts/interfaces/IFastBridgeV2.sol\n\ninterface IFastBridgeV2 is IFastBridge {\n enum BridgeStatus {\n NULL, // Doesn't exist yet.\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n struct BridgeTxDetails {\n BridgeStatus status;\n uint32 destChainId;\n uint56 proofBlockTimestamp;\n address proofRelayer;\n }\n\n struct BridgeRelay {\n uint48 blockNumber;\n uint48 blockTimestamp;\n address relayer;\n }\n\n /// @notice New params introduced in the FastBridgeV2.\n /// We are passing fields from the older BridgeParams struct outside of this struct for backwards compatibility.\n /// Note: quoteRelayer and quoteExclusivitySeconds are either both zero (indicating no exclusivity)\n /// or both non-zero (indicating exclusivity for the given period).\n /// Note: zapNative \u003e 0 can NOT be used with destToken = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE (native token)\n /// @param quoteRelayer Relayer that provided the quote for the transaction\n /// @param quoteExclusivitySeconds Period of time the quote relayer is guaranteed exclusivity after user's deposit\n /// @param quoteId Unique quote identifier used for tracking the quote\n /// @param zapNative ETH value to send to the recipient (if any)\n /// @param zapData Parameters for the Zap to the destination recipient (if any)\n struct BridgeParamsV2 {\n address quoteRelayer;\n int256 quoteExclusivitySeconds;\n bytes quoteId;\n uint256 zapNative;\n bytes zapData;\n }\n\n /// @notice Updated bridge transaction struct to include parameters introduced in FastBridgeV2.\n /// Note: only `exclusivityRelayer` can fill such a transaction until `exclusivityEndTime`.\n struct BridgeTransactionV2 {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n // Note: sendChainGas flag from V1 is deprecated\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n address exclusivityRelayer;\n uint256 exclusivityEndTime;\n uint256 zapNative; // ETH value to send to the recipient (if any)\n bytes zapData; // data to pass for the Zap action (if any)\n }\n\n event BridgeQuoteDetails(bytes32 indexed transactionId, bytes quoteId);\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability\n /// to provide temporary exclusivity fill rights for the quote relayer.\n /// @param params The parameters required to bridge\n /// @param paramsV2 The parameters for exclusivity fill rights (optional, can be left empty)\n function bridgeV2(BridgeParams memory params, BridgeParamsV2 memory paramsV2) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function relayV2(bytes memory request, address relayer) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param transactionId The transaction id associated with the encoded bridge transaction to prove\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function proveV2(bytes32 transactionId, bytes32 destTxHash, address relayer) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital.\n /// @notice Can only send funds to the relayer address on the proof.\n /// @param request The encoded bridge transaction to claim on origin chain\n function claimV2(bytes memory request) external;\n\n /// @notice Cancels an outstanding bridge transaction in case optimistic bridging failed and returns the full amount\n /// to the original sender.\n /// @param request The encoded bridge transaction to refund\n function cancelV2(bytes memory request) external;\n\n /// @notice Checks if a transaction has been relayed\n /// @param transactionId The ID of the transaction to check\n /// @return True if the transaction has been relayed, false otherwise\n function bridgeRelays(bytes32 transactionId) external view returns (bool);\n\n /// @notice Returns the status of a bridge transaction\n /// @param transactionId The ID of the bridge transaction\n /// @return BridgeStatus Status of the bridge transaction\n function bridgeStatuses(bytes32 transactionId) external view returns (BridgeStatus);\n\n /// @notice Returns the timestamp and relayer of a bridge proof\n /// @param transactionId The ID of the bridge transaction\n /// @return timestamp The timestamp of the bridge proof\n /// @return relayer The relayer address of the bridge proof\n function bridgeProofs(bytes32 transactionId) external view returns (uint96 timestamp, address relayer);\n\n /// @notice Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\n /// @param request The bridge request to decode\n function getBridgeTransactionV2(bytes memory request) external view returns (BridgeTransactionV2 memory);\n}\n\n// contracts/utils/MulticallTarget.sol\n\n// solhint-disable avoid-low-level-calls\n/// @notice Abstract contract template that supports batched calls while preserving msg.sender.\n/// Only calls with msg.value of 0 can be batched.\nabstract contract MulticallTarget is IMulticallTarget {\n error MulticallTarget__UndeterminedRevert();\n\n /// @inheritdoc IMulticallTarget\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external {\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\n if (!success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(result);\n }\n }\n }\n\n /// @inheritdoc IMulticallTarget\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results)\n {\n results = new Result[](data.length);\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (results[i].success, results[i].returnData) = address(this).delegatecall(data[i]);\n if (!results[i].success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(results[i].returnData);\n }\n }\n }\n\n /// @dev Bubbles the revert message from the underlying call.\n /// Note: preserves the same custom error or revert string, if one was used.\n /// Source: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v5.0.2/contracts/utils/Address.sol#L143-L158\n function _bubbleRevert(bytes memory returnData) internal pure {\n // Look for revert reason and bubble it up if present\n if (returnData.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n // solhint-disable-next-line no-inline-assembly\n assembly {\n let returndata_size := mload(returnData)\n revert(add(32, returnData), returndata_size)\n }\n } else {\n revert MulticallTarget__UndeterminedRevert();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// contracts/libs/BridgeTransactionV2.sol\n\n// solhint-disable no-inline-assembly\nlibrary BridgeTransactionV2Lib {\n uint16 internal constant VERSION = 2;\n\n // Offsets of the fields in the packed BridgeTransactionV2 struct\n // uint16 version [000 .. 002)\n // uint32 originChainId [002 .. 006)\n // uint32 destChainId [006 .. 010)\n // address originSender [010 .. 030)\n // address destRecipient [030 .. 050)\n // address originToken [050 .. 070)\n // address destToken [070 .. 090)\n // uint256 originAmount [090 .. 122)\n // uint256 destAmount [122 .. 154)\n // uint256 originFeeAmount [154 .. 186)\n // uint256 deadline [186 .. 218)\n // uint256 nonce [218 .. 250)\n // address exclusivityRelayer [250 .. 270)\n // uint256 exclusivityEndTime [270 .. 302)\n // uint256 zapNative [302 .. 334)\n // bytes zapData [334 .. ***)\n\n // forgefmt: disable-start\n uint256 private constant OFFSET_ORIGIN_CHAIN_ID = 2;\n uint256 private constant OFFSET_DEST_CHAIN_ID = 6;\n uint256 private constant OFFSET_ORIGIN_SENDER = 10;\n uint256 private constant OFFSET_DEST_RECIPIENT = 30;\n uint256 private constant OFFSET_ORIGIN_TOKEN = 50;\n uint256 private constant OFFSET_DEST_TOKEN = 70;\n uint256 private constant OFFSET_ORIGIN_AMOUNT = 90;\n uint256 private constant OFFSET_DEST_AMOUNT = 122;\n uint256 private constant OFFSET_ORIGIN_FEE_AMOUNT = 154;\n uint256 private constant OFFSET_DEADLINE = 186;\n uint256 private constant OFFSET_NONCE = 218;\n uint256 private constant OFFSET_EXCLUSIVITY_RELAYER = 250;\n uint256 private constant OFFSET_EXCLUSIVITY_END_TIME = 270;\n uint256 private constant OFFSET_ZAP_NATIVE = 302;\n uint256 private constant OFFSET_ZAP_DATA = 334;\n // forgefmt: disable-end\n\n error BridgeTransactionV2__InvalidEncodedTx();\n error BridgeTransactionV2__UnsupportedVersion(uint16 version);\n\n /// @notice Validates that the encoded transaction is a tightly packed encoded payload for BridgeTransactionV2.\n /// @dev Checks the minimum length and the version, use this function before decoding any of the fields.\n function validateV2(bytes calldata encodedTx) internal pure {\n // Check the minimum length: must at least include all static fields.\n if (encodedTx.length \u003c OFFSET_ZAP_DATA) revert BridgeTransactionV2__InvalidEncodedTx();\n // Once we validated the length, we can be sure that the version field is present.\n uint16 version_ = version(encodedTx);\n if (version_ != VERSION) revert BridgeTransactionV2__UnsupportedVersion(version_);\n }\n\n /// @notice Encodes the BridgeTransactionV2 struct by tightly packing the fields.\n /// @dev `abi.decode` will not work as a result of the tightly packed fields. Use `decodeV2` to decode instead.\n function encodeV2(IFastBridgeV2.BridgeTransactionV2 memory bridgeTx) internal pure returns (bytes memory) {\n // We split the encoding into two parts to avoid stack-too-deep error\n bytes memory firstPart = abi.encodePacked(\n VERSION,\n bridgeTx.originChainId,\n bridgeTx.destChainId,\n bridgeTx.originSender,\n bridgeTx.destRecipient,\n bridgeTx.originToken,\n bridgeTx.destToken,\n bridgeTx.originAmount\n );\n return abi.encodePacked(\n firstPart,\n bridgeTx.destAmount,\n bridgeTx.originFeeAmount,\n // Note: we skip the deprecated `sendChainGas` flag, which was present in BridgeTransaction V1\n bridgeTx.deadline,\n bridgeTx.nonce,\n // New V2 fields: exclusivity\n bridgeTx.exclusivityRelayer,\n bridgeTx.exclusivityEndTime,\n // New V2 fields: Zap\n bridgeTx.zapNative,\n bridgeTx.zapData\n );\n }\n\n /// @notice Decodes the BridgeTransactionV2 struct from the encoded transaction.\n /// @dev Encoded BridgeTransactionV2 struct must be tightly packed.\n /// Use `validateV2` before decoding to ensure the encoded transaction is valid.\n function decodeV2(bytes calldata encodedTx)\n internal\n pure\n returns (IFastBridgeV2.BridgeTransactionV2 memory bridgeTx)\n {\n bridgeTx.originChainId = originChainId(encodedTx);\n bridgeTx.destChainId = destChainId(encodedTx);\n bridgeTx.originSender = originSender(encodedTx);\n bridgeTx.destRecipient = destRecipient(encodedTx);\n bridgeTx.originToken = originToken(encodedTx);\n bridgeTx.destToken = destToken(encodedTx);\n bridgeTx.originAmount = originAmount(encodedTx);\n bridgeTx.destAmount = destAmount(encodedTx);\n bridgeTx.originFeeAmount = originFeeAmount(encodedTx);\n bridgeTx.deadline = deadline(encodedTx);\n bridgeTx.nonce = nonce(encodedTx);\n bridgeTx.exclusivityRelayer = exclusivityRelayer(encodedTx);\n bridgeTx.exclusivityEndTime = exclusivityEndTime(encodedTx);\n bridgeTx.zapNative = zapNative(encodedTx);\n bridgeTx.zapData = zapData(encodedTx);\n }\n\n /// @notice Extracts the version from the encoded transaction.\n function version(bytes calldata encodedTx) internal pure returns (uint16 version_) {\n // Load 32 bytes from the start and shift it 240 bits to the right to get the highest 16 bits.\n assembly {\n version_ := shr(240, calldataload(encodedTx.offset))\n }\n }\n\n /// @notice Extracts the origin chain ID from the encoded transaction.\n function originChainId(bytes calldata encodedTx) internal pure returns (uint32 originChainId_) {\n // Load 32 bytes from the offset and shift it 224 bits to the right to get the highest 32 bits.\n assembly {\n originChainId_ := shr(224, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_CHAIN_ID)))\n }\n }\n\n /// @notice Extracts the destination chain ID from the encoded transaction.\n function destChainId(bytes calldata encodedTx) internal pure returns (uint32 destChainId_) {\n // Load 32 bytes from the offset and shift it 224 bits to the right to get the highest 32 bits.\n assembly {\n destChainId_ := shr(224, calldataload(add(encodedTx.offset, OFFSET_DEST_CHAIN_ID)))\n }\n }\n\n /// @notice Extracts the origin sender from the encoded transaction.\n function originSender(bytes calldata encodedTx) internal pure returns (address originSender_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n originSender_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_SENDER)))\n }\n }\n\n /// @notice Extracts the destination recipient from the encoded transaction.\n function destRecipient(bytes calldata encodedTx) internal pure returns (address destRecipient_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n destRecipient_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_DEST_RECIPIENT)))\n }\n }\n\n /// @notice Extracts the origin token from the encoded transaction.\n function originToken(bytes calldata encodedTx) internal pure returns (address originToken_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n originToken_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_TOKEN)))\n }\n }\n\n /// @notice Extracts the destination token from the encoded transaction.\n function destToken(bytes calldata encodedTx) internal pure returns (address destToken_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n destToken_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_DEST_TOKEN)))\n }\n }\n\n /// @notice Extracts the origin amount from the encoded transaction.\n function originAmount(bytes calldata encodedTx) internal pure returns (uint256 originAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n originAmount_ := calldataload(add(encodedTx.offset, OFFSET_ORIGIN_AMOUNT))\n }\n }\n\n /// @notice Extracts the destination amount from the encoded transaction.\n function destAmount(bytes calldata encodedTx) internal pure returns (uint256 destAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n destAmount_ := calldataload(add(encodedTx.offset, OFFSET_DEST_AMOUNT))\n }\n }\n\n /// @notice Extracts the origin fee amount from the encoded transaction.\n function originFeeAmount(bytes calldata encodedTx) internal pure returns (uint256 originFeeAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n originFeeAmount_ := calldataload(add(encodedTx.offset, OFFSET_ORIGIN_FEE_AMOUNT))\n }\n }\n\n /// @notice Extracts the deadline from the encoded transaction.\n function deadline(bytes calldata encodedTx) internal pure returns (uint256 deadline_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n deadline_ := calldataload(add(encodedTx.offset, OFFSET_DEADLINE))\n }\n }\n\n /// @notice Extracts the nonce from the encoded transaction.\n function nonce(bytes calldata encodedTx) internal pure returns (uint256 nonce_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n nonce_ := calldataload(add(encodedTx.offset, OFFSET_NONCE))\n }\n }\n\n /// @notice Extracts the exclusivity relayer from the encoded transaction.\n function exclusivityRelayer(bytes calldata encodedTx) internal pure returns (address exclusivityRelayer_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n exclusivityRelayer_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_EXCLUSIVITY_RELAYER)))\n }\n }\n\n /// @notice Extracts the exclusivity end time from the encoded transaction.\n function exclusivityEndTime(bytes calldata encodedTx) internal pure returns (uint256 exclusivityEndTime_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n exclusivityEndTime_ := calldataload(add(encodedTx.offset, OFFSET_EXCLUSIVITY_END_TIME))\n }\n }\n\n /// @notice Extracts the Zap's native value from the encoded transaction.\n function zapNative(bytes calldata encodedTx) internal pure returns (uint256 zapNative_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n zapNative_ := calldataload(add(encodedTx.offset, OFFSET_ZAP_NATIVE))\n }\n }\n\n /// @notice Extracts the Zap's data from the encoded transaction.\n function zapData(bytes calldata encodedTx) internal pure returns (bytes calldata zapData_) {\n zapData_ = encodedTx[OFFSET_ZAP_DATA:];\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/AdminV2.sol\n\n// ════════════════════════════════════════════════ INTERFACES ═════════════════════════════════════════════════════\n\n// ═════════════════════════════════════════════ EXTERNAL IMPORTS ══════════════════════════════════════════════════\n\n/// @title AdminV2\n/// @notice Provides administrative functions and controls for managing the FastBridgeV2 contract,\n/// including access control and configuration settings.\ncontract AdminV2 is AccessControlEnumerable, IAdminV2, IAdminV2Errors {\n using SafeERC20 for IERC20;\n\n /// @notice The address reserved for the native gas token (ETH on Ethereum and most L2s, AVAX on Avalanche, etc.).\n address public constant NATIVE_GAS_TOKEN = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice The role identifier for the Quoter API's off-chain authentication.\n /// @dev Only addresses with this role can post FastBridge quotes to the API.\n bytes32 public constant QUOTER_ROLE = keccak256(\"QUOTER_ROLE\");\n\n /// @notice The role identifier for the Prover's on-chain authentication in FastBridge.\n /// @dev Only addresses with this role can provide proofs that a FastBridge request has been relayed.\n bytes32 public constant PROVER_ROLE = keccak256(\"PROVER_ROLE\");\n\n /// @notice The role identifier for the Guard's on-chain authentication in FastBridge.\n /// @dev Only addresses with this role can dispute submitted relay proofs during the dispute period.\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n\n /// @notice The role identifier for the Canceler's on-chain authentication in FastBridge.\n /// @dev Only addresses with this role can cancel a FastBridge transaction without the cancel delay.\n bytes32 public constant CANCELER_ROLE = keccak256(\"CANCELER_ROLE\");\n\n /// @notice The role identifier for the Governor's on-chain administrative authority.\n /// @dev Only addresses with this role can perform administrative tasks within the contract.\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n /// @notice The denominator for fee rates, representing 100%.\n uint256 public constant FEE_BPS = 1e6;\n /// @notice The maximum protocol fee rate: 1% of the origin amount.\n uint256 public constant FEE_RATE_MAX = 0.01e6;\n\n /// @notice The minimum cancel delay that can be set by the governor.\n uint256 public constant MIN_CANCEL_DELAY = 1 hours;\n /// @notice The default cancel delay set during contract deployment.\n uint256 public constant DEFAULT_CANCEL_DELAY = 1 days;\n\n /// @notice The protocol fee rate taken on the origin amount deposited in the origin chain.\n uint256 public protocolFeeRate;\n\n /// @notice The accumulated protocol fee amounts.\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice The delay period after which a transaction can be permissionlessly cancelled.\n uint256 public cancelDelay;\n\n /// @notice This variable is deprecated and should not be used.\n /// @dev Use ZapNative V2 requests instead.\n uint256 public immutable chainGasAmount = 0;\n\n constructor(address defaultAdmin) {\n _grantRole(DEFAULT_ADMIN_ROLE, defaultAdmin);\n _setCancelDelay(DEFAULT_CANCEL_DELAY);\n }\n\n /// @inheritdoc IAdminV2\n function setCancelDelay(uint256 newCancelDelay) external onlyRole(GOVERNOR_ROLE) {\n _setCancelDelay(newCancelDelay);\n }\n\n /// @inheritdoc IAdminV2\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n if (newFeeRate \u003e FEE_RATE_MAX) revert FeeRateAboveMax();\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n /// @inheritdoc IAdminV2\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n // Early exit if no accumulated fees.\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return;\n // Reset the accumulated fees first.\n protocolFees[token] = 0;\n emit FeesSwept(token, recipient, feeAmount);\n // Sweep the fees as the last transaction action.\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(recipient), feeAmount);\n } else {\n IERC20(token).safeTransfer(recipient, feeAmount);\n }\n }\n\n /// @notice Internal logic to set the cancel delay. Security checks are performed outside of this function.\n /// @dev This function is marked as private to prevent child contracts from calling it directly.\n function _setCancelDelay(uint256 newCancelDelay) private {\n if (newCancelDelay \u003c MIN_CANCEL_DELAY) revert CancelDelayBelowMin();\n uint256 oldCancelDelay = cancelDelay;\n cancelDelay = newCancelDelay;\n emit CancelDelayUpdated(oldCancelDelay, newCancelDelay);\n }\n}\n\n// contracts/FastBridgeV2.sol\n\n// ════════════════════════════════════════════════ INTERFACES ═════════════════════════════════════════════════════\n\n// ═════════════════════════════════════════════ INTERNAL IMPORTS ══════════════════════════════════════════════════\n\n// ═════════════════════════════════════════════ EXTERNAL IMPORTS ══════════════════════════════════════════════════\n\n/// @title FastBridgeV2\n/// @notice Core component of the SynapseRFQ protocol, enabling Relayers (Solvers) to fulfill bridge requests.\n/// Supports ERC20 and native gas tokens, along with the Zap feature for executing actions on the destination chain.\n/// Users interact with the off-chain Quoter API to obtain a current quote for a bridge transaction.\n/// They then submit the bridge request with the quote to this contract, depositing their assets in escrow.\n/// Relayers can fulfill requests by relaying them to the destination chain and must prove fulfillment to claim funds.\n/// Guards monitor proofs and can dispute discrepancies.\n/// Users can reclaim funds by cancelling their requests if it has not been fulfilled within the specified deadline.\ncontract FastBridgeV2 is AdminV2, MulticallTarget, IFastBridgeV2, IFastBridgeV2Errors {\n using BridgeTransactionV2Lib for bytes;\n using SafeERC20 for IERC20;\n\n /// @notice The duration of the dispute period for relayed transactions.\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice The minimum required time between transaction request and deadline.\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n /// @notice The maximum allowed length for zapData.\n uint256 public constant MAX_ZAP_DATA_LENGTH = 2 ** 16 - 1;\n\n /// @notice Maps transaction IDs to bridge details (status, destination chain ID, proof timestamp, and relayer).\n /// Note: this is only stored for transactions having local chain as the origin chain.\n mapping(bytes32 =\u003e BridgeTxDetails) public bridgeTxDetails;\n /// @notice Maps transaction IDs to relay details (block number, block timestamp, and relayer).\n /// Note: this is only stored for transactions having local chain as the destination chain.\n mapping(bytes32 =\u003e BridgeRelay) public bridgeRelayDetails;\n /// @notice Maps sender addresses to their unique bridge nonce.\n mapping(address =\u003e uint256) public senderNonces;\n\n /// @notice This variable is deprecated and should not be used.\n /// @dev Replaced by senderNonces.\n uint256 public immutable nonce = 0;\n /// @notice The block number at which this contract was deployed.\n uint256 public immutable deployBlock;\n\n /// @notice Initializes the FastBridgeV2 contract with the provided default admin,\n /// sets the default cancel delay, and records the deploy block number.\n constructor(address defaultAdmin) AdminV2(defaultAdmin) {\n deployBlock = block.number;\n }\n\n // ══════════════════════════════════════ EXTERNAL MUTABLE (USER FACING) ═══════════════════════════════════════════\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n bridgeV2({\n params: params,\n paramsV2: BridgeParamsV2({\n quoteRelayer: address(0),\n quoteExclusivitySeconds: 0,\n quoteId: bytes(\"\"),\n zapNative: 0,\n zapData: bytes(\"\")\n })\n });\n }\n\n /// Note: this function is deprecated and will be removed in a future version.\n /// @dev Replaced by `cancel`.\n /// @inheritdoc IFastBridge\n function refund(bytes calldata request) external {\n cancelV2(request);\n }\n\n // ══════════════════════════════════════ EXTERNAL MUTABLE (AGENT FACING) ══════════════════════════════════════════\n\n /// @inheritdoc IFastBridge\n function relay(bytes calldata request) external payable {\n // `relay` override will validate the request.\n relayV2({request: request, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes calldata request, bytes32 destTxHash) external {\n request.validateV2();\n proveV2({transactionId: keccak256(request), destTxHash: destTxHash, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridgeV2\n function claimV2(bytes calldata request) external {\n // `claim` override will validate the request.\n claim({request: request, to: address(0)});\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n // Aggregate the read operations from the same storage slot.\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n address disputedRelayer = $.proofRelayer;\n BridgeStatus status = $.status;\n uint56 proofBlockTimestamp = $.proofBlockTimestamp;\n\n // Can only dispute a RELAYER_PROVED transaction within the dispute period.\n if (status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(proofBlockTimestamp) \u003e DISPUTE_PERIOD) {\n revert DisputePeriodPassed();\n }\n\n // Update status to REQUESTED and delete the disputed proof details.\n // Note: these are storage writes.\n $.status = BridgeStatus.REQUESTED;\n $.proofRelayer = address(0);\n $.proofBlockTimestamp = 0;\n\n emit BridgeProofDisputed(transactionId, disputedRelayer);\n }\n\n // ══════════════════════════════════════════════ EXTERNAL VIEWS ═══════════════════════════════════════════════════\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n // The correct relayer can only claim a RELAYER_PROVED transaction after the dispute period.\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n if ($.status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if ($.proofRelayer != relayer) revert SenderIncorrect();\n\n return _timeSince($.proofBlockTimestamp) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n /// @dev This method is added to achieve backwards compatibility with decoding requests into V1 structs:\n /// - `zapNative` is partially reported as a zero/non-zero flag\n /// - `zapData` is ignored\n /// In order to process all kinds of requests use getBridgeTransactionV2 instead.\n function getBridgeTransaction(bytes calldata request) external view returns (BridgeTransaction memory) {\n // Try decoding into V2 struct first. This will revert if V1 struct is passed.\n try this.getBridgeTransactionV2(request) returns (BridgeTransactionV2 memory txV2) {\n // Note: we entirely ignore the zapData field, as it was not present in V1.\n return BridgeTransaction({\n originChainId: txV2.originChainId,\n destChainId: txV2.destChainId,\n originSender: txV2.originSender,\n destRecipient: txV2.destRecipient,\n originToken: txV2.originToken,\n destToken: txV2.destToken,\n originAmount: txV2.originAmount,\n destAmount: txV2.destAmount,\n originFeeAmount: txV2.originFeeAmount,\n sendChainGas: txV2.zapNative != 0,\n deadline: txV2.deadline,\n nonce: txV2.nonce\n });\n } catch {\n // Fallback to V1 struct.\n return abi.decode(request, (BridgeTransaction));\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function getBridgeTransactionV2(bytes calldata request) external pure returns (BridgeTransactionV2 memory) {\n request.validateV2();\n return BridgeTransactionV2Lib.decodeV2(request);\n }\n\n // ═══════════════════════════════════════ PUBLIC MUTABLE (USER FACING) ════════════════════════════════════════════\n\n /// @inheritdoc IFastBridgeV2\n function bridgeV2(BridgeParams memory params, BridgeParamsV2 memory paramsV2) public payable {\n // If relayer exclusivity is not intended for this bridge, set exclusivityEndTime to static zero.\n // Otherwise, set exclusivity to expire at the current block ts offset by quoteExclusivitySeconds.\n int256 exclusivityEndTime = 0;\n if (paramsV2.quoteRelayer != address(0)) {\n exclusivityEndTime = int256(block.timestamp) + paramsV2.quoteExclusivitySeconds;\n }\n _validateBridgeParams(params, paramsV2, exclusivityEndTime);\n\n // Transfer tokens to bridge contract. We use the actual transferred amount in case of transfer fees.\n uint256 originAmount = _takeBridgedUserAsset(params.originToken, params.originAmount);\n\n // Track the amount of origin token owed to protocol.\n uint256 originFeeAmount = 0;\n if (protocolFeeRate \u003e 0) {\n originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n // The Relayer filling this request will be paid the originAmount after fees.\n // Note: the protocol fees will be accumulated only when the Relayer claims the origin collateral.\n originAmount -= originFeeAmount;\n }\n\n // Hash the bridge request and set the initial status to REQUESTED.\n bytes memory request = BridgeTransactionV2Lib.encodeV2(\n BridgeTransactionV2({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n deadline: params.deadline,\n // Increment the sender's nonce on every bridge.\n nonce: senderNonces[params.sender]++,\n exclusivityRelayer: paramsV2.quoteRelayer,\n // We checked exclusivityEndTime to be in range [0 .. params.deadline] above, so can safely cast.\n exclusivityEndTime: uint256(exclusivityEndTime),\n zapNative: paramsV2.zapNative,\n zapData: paramsV2.zapData\n })\n );\n bytes32 transactionId = keccak256(request);\n // Note: the tx status will be updated throughout the tx lifecycle, while destChainId is set once here.\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n bridgeTxDetails[transactionId].destChainId = params.dstChainId;\n\n emit BridgeRequested({\n transactionId: transactionId,\n sender: params.sender,\n request: request,\n destChainId: params.dstChainId,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n sendChainGas: paramsV2.zapNative != 0\n });\n emit BridgeQuoteDetails(transactionId, paramsV2.quoteId);\n }\n\n /// @inheritdoc IFastBridgeV2\n function cancelV2(bytes calldata request) public {\n // Decode the request and check that it could be cancelled.\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n\n // Can only cancel a REQUESTED transaction after its deadline expires.\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n if ($.status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n\n // Permissionless cancel is only allowed after `cancelDelay` on top of the deadline.\n uint256 deadline = request.deadline();\n if (!hasRole(CANCELER_ROLE, msg.sender)) deadline += cancelDelay;\n if (block.timestamp \u003c= deadline) revert DeadlineNotExceeded();\n\n // Update status to REFUNDED.\n // Note: this is a storage write.\n $.status = BridgeStatus.REFUNDED;\n\n // Return the full amount (collateral + protocol fees) to the original sender.\n // The protocol fees are only accumulated when the transaction is claimed, so we don't need to update them here.\n address to = request.originSender();\n address token = request.originToken();\n uint256 amount = request.originAmount() + request.originFeeAmount();\n\n // Emit the event before any external calls.\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n\n // Return the funds to the original sender as last transaction action.\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(to), amount);\n } else {\n IERC20(token).safeTransfer(to, amount);\n }\n }\n\n // ═══════════════════════════════════════ PUBLIC MUTABLE (AGENT FACING) ═══════════════════════════════════════════\n\n /// @inheritdoc IFastBridgeV2\n function relayV2(bytes calldata request, address relayer) public payable {\n // Decode the request and check that it could be relayed.\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n _validateRelayParams(request, transactionId, relayer);\n\n // Mark the bridge request as relayed by saving the relayer and the block details.\n bridgeRelayDetails[transactionId].blockNumber = uint48(block.number);\n bridgeRelayDetails[transactionId].blockTimestamp = uint48(block.timestamp);\n bridgeRelayDetails[transactionId].relayer = relayer;\n\n // Transfer tokens to recipient on destination chain and trigger Zap if requested.\n address to = request.destRecipient();\n address token = request.destToken();\n uint256 amount = request.destAmount();\n uint256 zapNative = request.zapNative();\n\n // Emit the event before any external calls.\n emit BridgeRelayed({\n transactionId: transactionId,\n relayer: relayer,\n to: to,\n originChainId: request.originChainId(),\n originToken: request.originToken(),\n destToken: token,\n originAmount: request.originAmount(),\n destAmount: amount,\n chainGasAmount: zapNative\n });\n\n // All state changes have been done at this point, can proceed to the external calls.\n // This follows the checks-effects-interactions pattern to mitigate potential reentrancy attacks.\n if (token == NATIVE_GAS_TOKEN) {\n // For the native gas token, additional zapNative is not allowed.\n if (zapNative != 0) revert ZapNativeNotSupported();\n // Check that the correct msg.value was sent.\n if (msg.value != amount) revert MsgValueIncorrect();\n // Don't do a native transfer yet: we will handle it alongside the Zap below.\n } else {\n // For ERC20s, we check that the correct msg.value was sent.\n if (msg.value != zapNative) revert MsgValueIncorrect();\n // We need to transfer the tokens from the Relayer to the recipient first before performing an\n // optional post-transfer Zap.\n IERC20(token).safeTransferFrom(msg.sender, to, amount);\n }\n // At this point we have done:\n // - Transferred the requested amount of ERC20 tokens to the recipient.\n // At this point we have confirmed:\n // - For ERC20s: msg.value matches the requested zapNative amount.\n // - For the native gas token: msg.value matches the requested destAmount.\n // Remaining optional things to do:\n // - Forward the full msg.value to the recipient (if non-zero).\n // - Trigger a Zap (if zapData is present).\n bytes calldata zapData = request.zapData();\n if (zapData.length != 0) {\n // Zap Data is present: Zap has been requested by the recipient. Trigger it forwarding the full msg.value.\n _triggerZapWithChecks({recipient: to, token: token, amount: amount, zapData: zapData});\n // Note: if token has a fee on transfers, the recipient will have received less than `amount`.\n // This is a very niche edge case and should be handled by the recipient contract.\n } else if (msg.value != 0) {\n // Zap Data is missing, but msg.value was sent. This could happen in two different cases:\n // - Relay with the native gas token is happening.\n // - Relay with ERC20 is happening, with a `zapNative \u003e 0` request.\n // In both cases, we need to transfer the full msg.value to the recipient.\n Address.sendValue(payable(to), msg.value);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function proveV2(bytes32 transactionId, bytes32 destTxHash, address relayer) public onlyRole(PROVER_ROLE) {\n // Can only prove a REQUESTED transaction.\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n if ($.status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n\n // Update status to RELAYER_PROVED and store the proof details.\n // Note: these are storage writes.\n $.status = BridgeStatus.RELAYER_PROVED;\n $.proofBlockTimestamp = uint56(block.timestamp);\n $.proofRelayer = relayer;\n\n emit BridgeProofProvided(transactionId, relayer, destTxHash);\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes calldata request, address to) public {\n // Decode the request and check that it could be claimed.\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n\n // Aggregate the read operations from the same storage slot.\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n address proofRelayer = $.proofRelayer;\n BridgeStatus status = $.status;\n uint56 proofBlockTimestamp = $.proofBlockTimestamp;\n\n // Can only claim a RELAYER_PROVED transaction after the dispute period.\n if (status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(proofBlockTimestamp) \u003c= DISPUTE_PERIOD) revert DisputePeriodNotPassed();\n if (to == address(0)) {\n // Anyone could claim the funds to the proven relayer on their behalf.\n to = proofRelayer;\n } else if (proofRelayer != msg.sender) {\n // Only the proven relayer could specify an address to claim the funds to.\n revert SenderIncorrect();\n }\n\n // Update status to RELAYER_CLAIMED and transfer the origin collateral to the specified claim address.\n // Note: this is a storage write.\n $.status = BridgeStatus.RELAYER_CLAIMED;\n\n // Accumulate protocol fees if origin fee amount exists.\n address token = request.originToken();\n uint256 amount = request.originAmount();\n uint256 originFeeAmount = request.originFeeAmount();\n if (originFeeAmount \u003e 0) protocolFees[token] += originFeeAmount;\n\n // Emit the event before any external calls.\n emit BridgeDepositClaimed(transactionId, proofRelayer, to, token, amount);\n\n // Complete the relayer claim as the last transaction action.\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(to), amount);\n } else {\n IERC20(token).safeTransfer(to, amount);\n }\n }\n\n // ═══════════════════════════════════════════════ PUBLIC VIEWS ════════════════════════════════════════════════════\n\n /// @inheritdoc IFastBridgeV2\n function bridgeStatuses(bytes32 transactionId) public view returns (BridgeStatus status) {\n return bridgeTxDetails[transactionId].status;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeProofs(bytes32 transactionId) public view returns (uint96 timestamp, address relayer) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n timestamp = $.proofBlockTimestamp;\n relayer = $.proofRelayer;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeRelays(bytes32 transactionId) public view returns (bool) {\n // This transaction has been relayed if the relayer address is recorded.\n return bridgeRelayDetails[transactionId].relayer != address(0);\n }\n\n // ═════════════════════════════════════════════ INTERNAL METHODS ══════════════════════════════════════════════════\n\n /// @notice Takes the bridged asset from the user into FastBridgeV2 custody. The asset will later be\n /// claimed by the relayer who completed the relay on the destination chain, or returned to the user\n /// via the cancel function if no relay is completed.\n function _takeBridgedUserAsset(address token, uint256 amount) internal returns (uint256 amountTaken) {\n if (token == NATIVE_GAS_TOKEN) {\n // For the native gas token, we just need to check that the supplied msg.value is correct.\n // Supplied `msg.value` is already in FastBridgeV2 custody.\n if (amount != msg.value) revert MsgValueIncorrect();\n amountTaken = msg.value;\n } else {\n // For ERC20s, token is explicitly transferred from the user to FastBridgeV2.\n // We don't allow non-zero `msg.value` to avoid extra funds from being stuck in FastBridgeV2.\n if (msg.value != 0) revert MsgValueIncorrect();\n // Throw an explicit error if the provided token address is not a contract.\n if (token.code.length == 0) revert TokenNotContract();\n\n // Use the balance difference as the amount taken in case of fee on transfer tokens.\n amountTaken = IERC20(token).balanceOf(address(this));\n IERC20(token).safeTransferFrom(msg.sender, address(this), amount);\n amountTaken = IERC20(token).balanceOf(address(this)) - amountTaken;\n }\n }\n\n /// @notice Calls the recipient's hook function with the specified zapData and validates\n /// the returned value.\n function _triggerZapWithChecks(address recipient, address token, uint256 amount, bytes calldata zapData) internal {\n // Call the recipient's hook function with the specified zapData, bubbling any revert messages.\n bytes memory returnData = Address.functionCallWithValue({\n target: recipient,\n data: abi.encodeCall(IZapRecipient.zap, (token, amount, zapData)),\n // Note: see `relay()` for reasoning behind passing msg.value.\n value: msg.value\n });\n\n // Explicit revert if no return data at all.\n if (returnData.length == 0) revert RecipientNoReturnValue();\n // Check that exactly a single return value was returned.\n if (returnData.length != 32) revert RecipientIncorrectReturnValue();\n // Return value should be abi-encoded hook function selector.\n if (bytes32(returnData) != bytes32(IZapRecipient.zap.selector)) {\n revert RecipientIncorrectReturnValue();\n }\n }\n\n /// @notice Calculates the time elapsed since a proof was submitted.\n /// @dev The proof.timestamp stores block timestamps as uint56 for gas optimization.\n /// _timeSince(proof) handles timestamp rollover when block.timestamp \u003e type(uint56).max but\n /// proof.timestamp \u003c type(uint56).max via an unchecked statement.\n /// @param proofBlockTimestamp The block timestamp when the proof was submitted.\n /// @return delta The time elapsed since proof submission.\n function _timeSince(uint56 proofBlockTimestamp) internal view returns (uint256 delta) {\n unchecked {\n delta = uint56(block.timestamp) - proofBlockTimestamp;\n }\n }\n\n /// @notice Validates all parameters required for a bridge transaction.\n /// @dev This function's complexity cannot be reduced due to the number of required checks,\n /// so we disable the code-complexity rule.\n // solhint-disable-next-line code-complexity\n function _validateBridgeParams(\n BridgeParams memory params,\n BridgeParamsV2 memory paramsV2,\n int256 exclusivityEndTime\n )\n internal\n view\n {\n // Check V1 (legacy) params.\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.sender == address(0) || params.to == address(0)) revert ZeroAddress();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n\n // Check V2 params.\n if (paramsV2.zapData.length \u003e MAX_ZAP_DATA_LENGTH) revert ZapDataLengthAboveMax();\n if (paramsV2.zapNative != 0 \u0026\u0026 params.destToken == NATIVE_GAS_TOKEN) {\n revert ZapNativeNotSupported();\n }\n\n // exclusivityEndTime must be in range [0 .. params.deadline].\n if (exclusivityEndTime \u003c 0 || exclusivityEndTime \u003e int256(params.deadline)) {\n revert ExclusivityParamsIncorrect();\n }\n }\n\n /// @notice Validates all parameters required for a relay transaction.\n function _validateRelayParams(bytes calldata request, bytes32 transactionId, address relayer) internal view {\n if (relayer == address(0)) revert ZeroAddress();\n // Check that the transaction has not been relayed yet and is for the current chain.\n if (bridgeRelays(transactionId)) revert TransactionRelayed();\n if (request.destChainId() != block.chainid) revert ChainIncorrect();\n // Check that the deadline for relay to happen has not passed yet.\n if (block.timestamp \u003e request.deadline()) revert DeadlineExceeded();\n // Check the exclusivity period, if it was specified and is still ongoing.\n address exclRelayer = request.exclusivityRelayer();\n if (exclRelayer != address(0) \u0026\u0026 exclRelayer != relayer \u0026\u0026 block.timestamp \u003c= request.exclusivityEndTime()) {\n revert ExclusivityPeriodNotPassed();\n }\n }\n}\n","language":"Solidity","languageVersion":"0.8.24","compilerVersion":"0.8.24","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"","srcMapRuntime":"","abiDefinition":[{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"}],"userDoc":{"kind":"user","methods":{},"version":1},"developerDoc":{"details":"Interface of the ERC165 standard, as defined in the https://eips.ethereum.org/EIPS/eip-165[EIP]. Implementers can declare support of contract interfaces, which can then be queried by others ({ERC165Checker}). For an implementation, see {ERC165}.","kind":"dev","methods":{"supportsInterface(bytes4)":{"details":"Returns true if this contract implements the interface defined by `interfaceId`. See the corresponding https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section] to learn more about how these ids are created. This function call must use less than 30 000 gas."}},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"bytes4\",\"name\":\"interfaceId\",\"type\":\"bytes4\"}],\"name\":\"supportsInterface\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"}],\"devdoc\":{\"details\":\"Interface of the ERC165 standard, as defined in the https://eips.ethereum.org/EIPS/eip-165[EIP]. Implementers can declare support of contract interfaces, which can then be queried by others ({ERC165Checker}). For an implementation, see {ERC165}.\",\"kind\":\"dev\",\"methods\":{\"supportsInterface(bytes4)\":{\"details\":\"Returns true if this contract implements the interface defined by `interfaceId`. See the corresponding https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section] to learn more about how these ids are created. This function call must use less than 30 000 gas.\"}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeV2.sol\":\"IERC165\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeV2.sol\":{\"keccak256\":\"0xaab2ee7357681726f0faf799a48ddfbf45fb4da93b69abf61c33dde92b29b74d\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://673391bff9569efc0f9bd99e0e6fece0bc8e8af1f052bb071b407b267a17b3b5\",\"dweb:/ipfs/QmdQQZ6DxpJYhfpinwU5WjLugr2f6qP8h68b5GerhSMQ4j\"]}},\"version\":1}"},"hashes":{"supportsInterface(bytes4)":"01ffc9a7"}},"solidity/FastBridgeV2.sol:IERC20":{"code":"0x","runtime-code":"0x","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.24 ^0.8.20 ^0.8.4;\n\n// contracts/interfaces/IAdminV2.sol\n\ninterface IAdminV2 {\n event CancelDelayUpdated(uint256 oldCancelDelay, uint256 newCancelDelay);\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n /// @notice Allows the governor to set the cancel delay. The cancel delay is the time period after the transaction\n /// deadline during which a transaction can be permissionlessly cancelled if it hasn't been proven by any Relayer.\n function setCancelDelay(uint256 newCancelDelay) external;\n\n /// @notice Allows the governor to set the protocol fee rate. The protocol fee is taken from the origin\n /// amount and is only applied to completed and claimed transactions.\n /// @dev The protocol fee is abstracted away from the relayers; they always operate using the amounts after fees.\n /// The origin amount they see in the emitted log is what they get credited with.\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n /// @notice Allows the governor to withdraw the accumulated protocol fees from the contract.\n function sweepProtocolFees(address token, address recipient) external;\n}\n\n// contracts/interfaces/IAdminV2Errors.sol\n\ninterface IAdminV2Errors {\n error CancelDelayBelowMin();\n error FeeRateAboveMax();\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IFastBridgeV2Errors.sol\n\ninterface IFastBridgeV2Errors {\n error AmountIncorrect();\n error ChainIncorrect();\n error ExclusivityParamsIncorrect();\n error MsgValueIncorrect();\n error SenderIncorrect();\n error StatusIncorrect();\n error TokenNotContract();\n error ZapDataLengthAboveMax();\n error ZapNativeNotSupported();\n error ZeroAddress();\n\n error RecipientIncorrectReturnValue();\n error RecipientNoReturnValue();\n\n error DeadlineExceeded();\n error DeadlineNotExceeded();\n error DeadlineTooShort();\n error DisputePeriodNotPassed();\n error DisputePeriodPassed();\n error ExclusivityPeriodNotPassed();\n\n error TransactionRelayed();\n}\n\n// contracts/interfaces/IMulticallTarget.sol\n\n/// @notice Interface for a contract that supports multiple calls from the same caller. Inspired by MulticallV3:\n/// https://github.com/mds1/multicall/blob/master/src/Multicall3.sol\ninterface IMulticallTarget {\n struct Result {\n bool success;\n bytes returnData;\n }\n\n /// @notice Executes multiple calls to this contract in a single transaction while preserving msg.sender.\n /// Return data from the calls is discarded.\n /// @dev This method is non-payable, so only calls with msg.value of 0 can be batched.\n /// If ignoreReverts is set to true, reverted calls will be skipped.\n /// Otherwise, the entire batch will revert with the original revert reason.\n /// @param data List of ABI-encoded calldata for the calls to execute\n /// @param ignoreReverts Whether to skip calls that revert\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external;\n\n /// @notice Executes multiple calls to this contract in a single transaction while preserving msg.sender.\n /// Return data from each call is preserved.\n /// @dev This method is non-payable, so only calls with msg.value of 0 can be batched.\n /// If ignoreReverts is set to true, reverted calls will be skipped.\n /// Otherwise, the entire batch will revert with the original revert reason.\n /// @param data List of ABI-encoded calldata for the calls to execute\n /// @param ignoreReverts Whether to skip calls that revert\n /// @return results List of results from the calls, each containing (success, returnData)\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results);\n}\n\n// contracts/interfaces/IZapRecipient.sol\n\n/// @notice Interface for contracts that can perform Zap operations. Such contracts could be used as Recipients\n/// in a FastBridge transaction that includes a Zap operation. The Zap Data should include instructions on how\n/// exactly the Zap operation should be executed, which would typically include the target address and calldata\n/// to use. The exact implementation of the Zap Data encoding is up to the Recipient contract.\ninterface IZapRecipient {\n /// @notice Performs a Zap operation with the given token and amount according to the provided Zap data.\n /// @param token The address of the token being used for the Zap operation.\n /// @param amount The amount of tokens to be used.\n /// @param zapData The encoded data specifying how the Zap operation should be executed.\n /// @return The function selector to indicate successful execution.\n function zap(address token, uint256 amount, bytes memory zapData) external payable returns (bytes4);\n}\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// contracts/interfaces/IFastBridgeV2.sol\n\ninterface IFastBridgeV2 is IFastBridge {\n enum BridgeStatus {\n NULL, // Doesn't exist yet.\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n struct BridgeTxDetails {\n BridgeStatus status;\n uint32 destChainId;\n uint56 proofBlockTimestamp;\n address proofRelayer;\n }\n\n struct BridgeRelay {\n uint48 blockNumber;\n uint48 blockTimestamp;\n address relayer;\n }\n\n /// @notice New params introduced in the FastBridgeV2.\n /// We are passing fields from the older BridgeParams struct outside of this struct for backwards compatibility.\n /// Note: quoteRelayer and quoteExclusivitySeconds are either both zero (indicating no exclusivity)\n /// or both non-zero (indicating exclusivity for the given period).\n /// Note: zapNative \u003e 0 can NOT be used with destToken = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE (native token)\n /// @param quoteRelayer Relayer that provided the quote for the transaction\n /// @param quoteExclusivitySeconds Period of time the quote relayer is guaranteed exclusivity after user's deposit\n /// @param quoteId Unique quote identifier used for tracking the quote\n /// @param zapNative ETH value to send to the recipient (if any)\n /// @param zapData Parameters for the Zap to the destination recipient (if any)\n struct BridgeParamsV2 {\n address quoteRelayer;\n int256 quoteExclusivitySeconds;\n bytes quoteId;\n uint256 zapNative;\n bytes zapData;\n }\n\n /// @notice Updated bridge transaction struct to include parameters introduced in FastBridgeV2.\n /// Note: only `exclusivityRelayer` can fill such a transaction until `exclusivityEndTime`.\n struct BridgeTransactionV2 {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n // Note: sendChainGas flag from V1 is deprecated\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n address exclusivityRelayer;\n uint256 exclusivityEndTime;\n uint256 zapNative; // ETH value to send to the recipient (if any)\n bytes zapData; // data to pass for the Zap action (if any)\n }\n\n event BridgeQuoteDetails(bytes32 indexed transactionId, bytes quoteId);\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability\n /// to provide temporary exclusivity fill rights for the quote relayer.\n /// @param params The parameters required to bridge\n /// @param paramsV2 The parameters for exclusivity fill rights (optional, can be left empty)\n function bridgeV2(BridgeParams memory params, BridgeParamsV2 memory paramsV2) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function relayV2(bytes memory request, address relayer) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param transactionId The transaction id associated with the encoded bridge transaction to prove\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function proveV2(bytes32 transactionId, bytes32 destTxHash, address relayer) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital.\n /// @notice Can only send funds to the relayer address on the proof.\n /// @param request The encoded bridge transaction to claim on origin chain\n function claimV2(bytes memory request) external;\n\n /// @notice Cancels an outstanding bridge transaction in case optimistic bridging failed and returns the full amount\n /// to the original sender.\n /// @param request The encoded bridge transaction to refund\n function cancelV2(bytes memory request) external;\n\n /// @notice Checks if a transaction has been relayed\n /// @param transactionId The ID of the transaction to check\n /// @return True if the transaction has been relayed, false otherwise\n function bridgeRelays(bytes32 transactionId) external view returns (bool);\n\n /// @notice Returns the status of a bridge transaction\n /// @param transactionId The ID of the bridge transaction\n /// @return BridgeStatus Status of the bridge transaction\n function bridgeStatuses(bytes32 transactionId) external view returns (BridgeStatus);\n\n /// @notice Returns the timestamp and relayer of a bridge proof\n /// @param transactionId The ID of the bridge transaction\n /// @return timestamp The timestamp of the bridge proof\n /// @return relayer The relayer address of the bridge proof\n function bridgeProofs(bytes32 transactionId) external view returns (uint96 timestamp, address relayer);\n\n /// @notice Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\n /// @param request The bridge request to decode\n function getBridgeTransactionV2(bytes memory request) external view returns (BridgeTransactionV2 memory);\n}\n\n// contracts/utils/MulticallTarget.sol\n\n// solhint-disable avoid-low-level-calls\n/// @notice Abstract contract template that supports batched calls while preserving msg.sender.\n/// Only calls with msg.value of 0 can be batched.\nabstract contract MulticallTarget is IMulticallTarget {\n error MulticallTarget__UndeterminedRevert();\n\n /// @inheritdoc IMulticallTarget\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external {\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\n if (!success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(result);\n }\n }\n }\n\n /// @inheritdoc IMulticallTarget\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results)\n {\n results = new Result[](data.length);\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (results[i].success, results[i].returnData) = address(this).delegatecall(data[i]);\n if (!results[i].success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(results[i].returnData);\n }\n }\n }\n\n /// @dev Bubbles the revert message from the underlying call.\n /// Note: preserves the same custom error or revert string, if one was used.\n /// Source: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v5.0.2/contracts/utils/Address.sol#L143-L158\n function _bubbleRevert(bytes memory returnData) internal pure {\n // Look for revert reason and bubble it up if present\n if (returnData.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n // solhint-disable-next-line no-inline-assembly\n assembly {\n let returndata_size := mload(returnData)\n revert(add(32, returnData), returndata_size)\n }\n } else {\n revert MulticallTarget__UndeterminedRevert();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// contracts/libs/BridgeTransactionV2.sol\n\n// solhint-disable no-inline-assembly\nlibrary BridgeTransactionV2Lib {\n uint16 internal constant VERSION = 2;\n\n // Offsets of the fields in the packed BridgeTransactionV2 struct\n // uint16 version [000 .. 002)\n // uint32 originChainId [002 .. 006)\n // uint32 destChainId [006 .. 010)\n // address originSender [010 .. 030)\n // address destRecipient [030 .. 050)\n // address originToken [050 .. 070)\n // address destToken [070 .. 090)\n // uint256 originAmount [090 .. 122)\n // uint256 destAmount [122 .. 154)\n // uint256 originFeeAmount [154 .. 186)\n // uint256 deadline [186 .. 218)\n // uint256 nonce [218 .. 250)\n // address exclusivityRelayer [250 .. 270)\n // uint256 exclusivityEndTime [270 .. 302)\n // uint256 zapNative [302 .. 334)\n // bytes zapData [334 .. ***)\n\n // forgefmt: disable-start\n uint256 private constant OFFSET_ORIGIN_CHAIN_ID = 2;\n uint256 private constant OFFSET_DEST_CHAIN_ID = 6;\n uint256 private constant OFFSET_ORIGIN_SENDER = 10;\n uint256 private constant OFFSET_DEST_RECIPIENT = 30;\n uint256 private constant OFFSET_ORIGIN_TOKEN = 50;\n uint256 private constant OFFSET_DEST_TOKEN = 70;\n uint256 private constant OFFSET_ORIGIN_AMOUNT = 90;\n uint256 private constant OFFSET_DEST_AMOUNT = 122;\n uint256 private constant OFFSET_ORIGIN_FEE_AMOUNT = 154;\n uint256 private constant OFFSET_DEADLINE = 186;\n uint256 private constant OFFSET_NONCE = 218;\n uint256 private constant OFFSET_EXCLUSIVITY_RELAYER = 250;\n uint256 private constant OFFSET_EXCLUSIVITY_END_TIME = 270;\n uint256 private constant OFFSET_ZAP_NATIVE = 302;\n uint256 private constant OFFSET_ZAP_DATA = 334;\n // forgefmt: disable-end\n\n error BridgeTransactionV2__InvalidEncodedTx();\n error BridgeTransactionV2__UnsupportedVersion(uint16 version);\n\n /// @notice Validates that the encoded transaction is a tightly packed encoded payload for BridgeTransactionV2.\n /// @dev Checks the minimum length and the version, use this function before decoding any of the fields.\n function validateV2(bytes calldata encodedTx) internal pure {\n // Check the minimum length: must at least include all static fields.\n if (encodedTx.length \u003c OFFSET_ZAP_DATA) revert BridgeTransactionV2__InvalidEncodedTx();\n // Once we validated the length, we can be sure that the version field is present.\n uint16 version_ = version(encodedTx);\n if (version_ != VERSION) revert BridgeTransactionV2__UnsupportedVersion(version_);\n }\n\n /// @notice Encodes the BridgeTransactionV2 struct by tightly packing the fields.\n /// @dev `abi.decode` will not work as a result of the tightly packed fields. Use `decodeV2` to decode instead.\n function encodeV2(IFastBridgeV2.BridgeTransactionV2 memory bridgeTx) internal pure returns (bytes memory) {\n // We split the encoding into two parts to avoid stack-too-deep error\n bytes memory firstPart = abi.encodePacked(\n VERSION,\n bridgeTx.originChainId,\n bridgeTx.destChainId,\n bridgeTx.originSender,\n bridgeTx.destRecipient,\n bridgeTx.originToken,\n bridgeTx.destToken,\n bridgeTx.originAmount\n );\n return abi.encodePacked(\n firstPart,\n bridgeTx.destAmount,\n bridgeTx.originFeeAmount,\n // Note: we skip the deprecated `sendChainGas` flag, which was present in BridgeTransaction V1\n bridgeTx.deadline,\n bridgeTx.nonce,\n // New V2 fields: exclusivity\n bridgeTx.exclusivityRelayer,\n bridgeTx.exclusivityEndTime,\n // New V2 fields: Zap\n bridgeTx.zapNative,\n bridgeTx.zapData\n );\n }\n\n /// @notice Decodes the BridgeTransactionV2 struct from the encoded transaction.\n /// @dev Encoded BridgeTransactionV2 struct must be tightly packed.\n /// Use `validateV2` before decoding to ensure the encoded transaction is valid.\n function decodeV2(bytes calldata encodedTx)\n internal\n pure\n returns (IFastBridgeV2.BridgeTransactionV2 memory bridgeTx)\n {\n bridgeTx.originChainId = originChainId(encodedTx);\n bridgeTx.destChainId = destChainId(encodedTx);\n bridgeTx.originSender = originSender(encodedTx);\n bridgeTx.destRecipient = destRecipient(encodedTx);\n bridgeTx.originToken = originToken(encodedTx);\n bridgeTx.destToken = destToken(encodedTx);\n bridgeTx.originAmount = originAmount(encodedTx);\n bridgeTx.destAmount = destAmount(encodedTx);\n bridgeTx.originFeeAmount = originFeeAmount(encodedTx);\n bridgeTx.deadline = deadline(encodedTx);\n bridgeTx.nonce = nonce(encodedTx);\n bridgeTx.exclusivityRelayer = exclusivityRelayer(encodedTx);\n bridgeTx.exclusivityEndTime = exclusivityEndTime(encodedTx);\n bridgeTx.zapNative = zapNative(encodedTx);\n bridgeTx.zapData = zapData(encodedTx);\n }\n\n /// @notice Extracts the version from the encoded transaction.\n function version(bytes calldata encodedTx) internal pure returns (uint16 version_) {\n // Load 32 bytes from the start and shift it 240 bits to the right to get the highest 16 bits.\n assembly {\n version_ := shr(240, calldataload(encodedTx.offset))\n }\n }\n\n /// @notice Extracts the origin chain ID from the encoded transaction.\n function originChainId(bytes calldata encodedTx) internal pure returns (uint32 originChainId_) {\n // Load 32 bytes from the offset and shift it 224 bits to the right to get the highest 32 bits.\n assembly {\n originChainId_ := shr(224, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_CHAIN_ID)))\n }\n }\n\n /// @notice Extracts the destination chain ID from the encoded transaction.\n function destChainId(bytes calldata encodedTx) internal pure returns (uint32 destChainId_) {\n // Load 32 bytes from the offset and shift it 224 bits to the right to get the highest 32 bits.\n assembly {\n destChainId_ := shr(224, calldataload(add(encodedTx.offset, OFFSET_DEST_CHAIN_ID)))\n }\n }\n\n /// @notice Extracts the origin sender from the encoded transaction.\n function originSender(bytes calldata encodedTx) internal pure returns (address originSender_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n originSender_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_SENDER)))\n }\n }\n\n /// @notice Extracts the destination recipient from the encoded transaction.\n function destRecipient(bytes calldata encodedTx) internal pure returns (address destRecipient_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n destRecipient_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_DEST_RECIPIENT)))\n }\n }\n\n /// @notice Extracts the origin token from the encoded transaction.\n function originToken(bytes calldata encodedTx) internal pure returns (address originToken_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n originToken_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_TOKEN)))\n }\n }\n\n /// @notice Extracts the destination token from the encoded transaction.\n function destToken(bytes calldata encodedTx) internal pure returns (address destToken_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n destToken_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_DEST_TOKEN)))\n }\n }\n\n /// @notice Extracts the origin amount from the encoded transaction.\n function originAmount(bytes calldata encodedTx) internal pure returns (uint256 originAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n originAmount_ := calldataload(add(encodedTx.offset, OFFSET_ORIGIN_AMOUNT))\n }\n }\n\n /// @notice Extracts the destination amount from the encoded transaction.\n function destAmount(bytes calldata encodedTx) internal pure returns (uint256 destAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n destAmount_ := calldataload(add(encodedTx.offset, OFFSET_DEST_AMOUNT))\n }\n }\n\n /// @notice Extracts the origin fee amount from the encoded transaction.\n function originFeeAmount(bytes calldata encodedTx) internal pure returns (uint256 originFeeAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n originFeeAmount_ := calldataload(add(encodedTx.offset, OFFSET_ORIGIN_FEE_AMOUNT))\n }\n }\n\n /// @notice Extracts the deadline from the encoded transaction.\n function deadline(bytes calldata encodedTx) internal pure returns (uint256 deadline_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n deadline_ := calldataload(add(encodedTx.offset, OFFSET_DEADLINE))\n }\n }\n\n /// @notice Extracts the nonce from the encoded transaction.\n function nonce(bytes calldata encodedTx) internal pure returns (uint256 nonce_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n nonce_ := calldataload(add(encodedTx.offset, OFFSET_NONCE))\n }\n }\n\n /// @notice Extracts the exclusivity relayer from the encoded transaction.\n function exclusivityRelayer(bytes calldata encodedTx) internal pure returns (address exclusivityRelayer_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n exclusivityRelayer_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_EXCLUSIVITY_RELAYER)))\n }\n }\n\n /// @notice Extracts the exclusivity end time from the encoded transaction.\n function exclusivityEndTime(bytes calldata encodedTx) internal pure returns (uint256 exclusivityEndTime_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n exclusivityEndTime_ := calldataload(add(encodedTx.offset, OFFSET_EXCLUSIVITY_END_TIME))\n }\n }\n\n /// @notice Extracts the Zap's native value from the encoded transaction.\n function zapNative(bytes calldata encodedTx) internal pure returns (uint256 zapNative_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n zapNative_ := calldataload(add(encodedTx.offset, OFFSET_ZAP_NATIVE))\n }\n }\n\n /// @notice Extracts the Zap's data from the encoded transaction.\n function zapData(bytes calldata encodedTx) internal pure returns (bytes calldata zapData_) {\n zapData_ = encodedTx[OFFSET_ZAP_DATA:];\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/AdminV2.sol\n\n// ════════════════════════════════════════════════ INTERFACES ═════════════════════════════════════════════════════\n\n// ═════════════════════════════════════════════ EXTERNAL IMPORTS ══════════════════════════════════════════════════\n\n/// @title AdminV2\n/// @notice Provides administrative functions and controls for managing the FastBridgeV2 contract,\n/// including access control and configuration settings.\ncontract AdminV2 is AccessControlEnumerable, IAdminV2, IAdminV2Errors {\n using SafeERC20 for IERC20;\n\n /// @notice The address reserved for the native gas token (ETH on Ethereum and most L2s, AVAX on Avalanche, etc.).\n address public constant NATIVE_GAS_TOKEN = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice The role identifier for the Quoter API's off-chain authentication.\n /// @dev Only addresses with this role can post FastBridge quotes to the API.\n bytes32 public constant QUOTER_ROLE = keccak256(\"QUOTER_ROLE\");\n\n /// @notice The role identifier for the Prover's on-chain authentication in FastBridge.\n /// @dev Only addresses with this role can provide proofs that a FastBridge request has been relayed.\n bytes32 public constant PROVER_ROLE = keccak256(\"PROVER_ROLE\");\n\n /// @notice The role identifier for the Guard's on-chain authentication in FastBridge.\n /// @dev Only addresses with this role can dispute submitted relay proofs during the dispute period.\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n\n /// @notice The role identifier for the Canceler's on-chain authentication in FastBridge.\n /// @dev Only addresses with this role can cancel a FastBridge transaction without the cancel delay.\n bytes32 public constant CANCELER_ROLE = keccak256(\"CANCELER_ROLE\");\n\n /// @notice The role identifier for the Governor's on-chain administrative authority.\n /// @dev Only addresses with this role can perform administrative tasks within the contract.\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n /// @notice The denominator for fee rates, representing 100%.\n uint256 public constant FEE_BPS = 1e6;\n /// @notice The maximum protocol fee rate: 1% of the origin amount.\n uint256 public constant FEE_RATE_MAX = 0.01e6;\n\n /// @notice The minimum cancel delay that can be set by the governor.\n uint256 public constant MIN_CANCEL_DELAY = 1 hours;\n /// @notice The default cancel delay set during contract deployment.\n uint256 public constant DEFAULT_CANCEL_DELAY = 1 days;\n\n /// @notice The protocol fee rate taken on the origin amount deposited in the origin chain.\n uint256 public protocolFeeRate;\n\n /// @notice The accumulated protocol fee amounts.\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice The delay period after which a transaction can be permissionlessly cancelled.\n uint256 public cancelDelay;\n\n /// @notice This variable is deprecated and should not be used.\n /// @dev Use ZapNative V2 requests instead.\n uint256 public immutable chainGasAmount = 0;\n\n constructor(address defaultAdmin) {\n _grantRole(DEFAULT_ADMIN_ROLE, defaultAdmin);\n _setCancelDelay(DEFAULT_CANCEL_DELAY);\n }\n\n /// @inheritdoc IAdminV2\n function setCancelDelay(uint256 newCancelDelay) external onlyRole(GOVERNOR_ROLE) {\n _setCancelDelay(newCancelDelay);\n }\n\n /// @inheritdoc IAdminV2\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n if (newFeeRate \u003e FEE_RATE_MAX) revert FeeRateAboveMax();\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n /// @inheritdoc IAdminV2\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n // Early exit if no accumulated fees.\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return;\n // Reset the accumulated fees first.\n protocolFees[token] = 0;\n emit FeesSwept(token, recipient, feeAmount);\n // Sweep the fees as the last transaction action.\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(recipient), feeAmount);\n } else {\n IERC20(token).safeTransfer(recipient, feeAmount);\n }\n }\n\n /// @notice Internal logic to set the cancel delay. Security checks are performed outside of this function.\n /// @dev This function is marked as private to prevent child contracts from calling it directly.\n function _setCancelDelay(uint256 newCancelDelay) private {\n if (newCancelDelay \u003c MIN_CANCEL_DELAY) revert CancelDelayBelowMin();\n uint256 oldCancelDelay = cancelDelay;\n cancelDelay = newCancelDelay;\n emit CancelDelayUpdated(oldCancelDelay, newCancelDelay);\n }\n}\n\n// contracts/FastBridgeV2.sol\n\n// ════════════════════════════════════════════════ INTERFACES ═════════════════════════════════════════════════════\n\n// ═════════════════════════════════════════════ INTERNAL IMPORTS ══════════════════════════════════════════════════\n\n// ═════════════════════════════════════════════ EXTERNAL IMPORTS ══════════════════════════════════════════════════\n\n/// @title FastBridgeV2\n/// @notice Core component of the SynapseRFQ protocol, enabling Relayers (Solvers) to fulfill bridge requests.\n/// Supports ERC20 and native gas tokens, along with the Zap feature for executing actions on the destination chain.\n/// Users interact with the off-chain Quoter API to obtain a current quote for a bridge transaction.\n/// They then submit the bridge request with the quote to this contract, depositing their assets in escrow.\n/// Relayers can fulfill requests by relaying them to the destination chain and must prove fulfillment to claim funds.\n/// Guards monitor proofs and can dispute discrepancies.\n/// Users can reclaim funds by cancelling their requests if it has not been fulfilled within the specified deadline.\ncontract FastBridgeV2 is AdminV2, MulticallTarget, IFastBridgeV2, IFastBridgeV2Errors {\n using BridgeTransactionV2Lib for bytes;\n using SafeERC20 for IERC20;\n\n /// @notice The duration of the dispute period for relayed transactions.\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice The minimum required time between transaction request and deadline.\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n /// @notice The maximum allowed length for zapData.\n uint256 public constant MAX_ZAP_DATA_LENGTH = 2 ** 16 - 1;\n\n /// @notice Maps transaction IDs to bridge details (status, destination chain ID, proof timestamp, and relayer).\n /// Note: this is only stored for transactions having local chain as the origin chain.\n mapping(bytes32 =\u003e BridgeTxDetails) public bridgeTxDetails;\n /// @notice Maps transaction IDs to relay details (block number, block timestamp, and relayer).\n /// Note: this is only stored for transactions having local chain as the destination chain.\n mapping(bytes32 =\u003e BridgeRelay) public bridgeRelayDetails;\n /// @notice Maps sender addresses to their unique bridge nonce.\n mapping(address =\u003e uint256) public senderNonces;\n\n /// @notice This variable is deprecated and should not be used.\n /// @dev Replaced by senderNonces.\n uint256 public immutable nonce = 0;\n /// @notice The block number at which this contract was deployed.\n uint256 public immutable deployBlock;\n\n /// @notice Initializes the FastBridgeV2 contract with the provided default admin,\n /// sets the default cancel delay, and records the deploy block number.\n constructor(address defaultAdmin) AdminV2(defaultAdmin) {\n deployBlock = block.number;\n }\n\n // ══════════════════════════════════════ EXTERNAL MUTABLE (USER FACING) ═══════════════════════════════════════════\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n bridgeV2({\n params: params,\n paramsV2: BridgeParamsV2({\n quoteRelayer: address(0),\n quoteExclusivitySeconds: 0,\n quoteId: bytes(\"\"),\n zapNative: 0,\n zapData: bytes(\"\")\n })\n });\n }\n\n /// Note: this function is deprecated and will be removed in a future version.\n /// @dev Replaced by `cancel`.\n /// @inheritdoc IFastBridge\n function refund(bytes calldata request) external {\n cancelV2(request);\n }\n\n // ══════════════════════════════════════ EXTERNAL MUTABLE (AGENT FACING) ══════════════════════════════════════════\n\n /// @inheritdoc IFastBridge\n function relay(bytes calldata request) external payable {\n // `relay` override will validate the request.\n relayV2({request: request, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes calldata request, bytes32 destTxHash) external {\n request.validateV2();\n proveV2({transactionId: keccak256(request), destTxHash: destTxHash, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridgeV2\n function claimV2(bytes calldata request) external {\n // `claim` override will validate the request.\n claim({request: request, to: address(0)});\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n // Aggregate the read operations from the same storage slot.\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n address disputedRelayer = $.proofRelayer;\n BridgeStatus status = $.status;\n uint56 proofBlockTimestamp = $.proofBlockTimestamp;\n\n // Can only dispute a RELAYER_PROVED transaction within the dispute period.\n if (status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(proofBlockTimestamp) \u003e DISPUTE_PERIOD) {\n revert DisputePeriodPassed();\n }\n\n // Update status to REQUESTED and delete the disputed proof details.\n // Note: these are storage writes.\n $.status = BridgeStatus.REQUESTED;\n $.proofRelayer = address(0);\n $.proofBlockTimestamp = 0;\n\n emit BridgeProofDisputed(transactionId, disputedRelayer);\n }\n\n // ══════════════════════════════════════════════ EXTERNAL VIEWS ═══════════════════════════════════════════════════\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n // The correct relayer can only claim a RELAYER_PROVED transaction after the dispute period.\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n if ($.status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if ($.proofRelayer != relayer) revert SenderIncorrect();\n\n return _timeSince($.proofBlockTimestamp) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n /// @dev This method is added to achieve backwards compatibility with decoding requests into V1 structs:\n /// - `zapNative` is partially reported as a zero/non-zero flag\n /// - `zapData` is ignored\n /// In order to process all kinds of requests use getBridgeTransactionV2 instead.\n function getBridgeTransaction(bytes calldata request) external view returns (BridgeTransaction memory) {\n // Try decoding into V2 struct first. This will revert if V1 struct is passed.\n try this.getBridgeTransactionV2(request) returns (BridgeTransactionV2 memory txV2) {\n // Note: we entirely ignore the zapData field, as it was not present in V1.\n return BridgeTransaction({\n originChainId: txV2.originChainId,\n destChainId: txV2.destChainId,\n originSender: txV2.originSender,\n destRecipient: txV2.destRecipient,\n originToken: txV2.originToken,\n destToken: txV2.destToken,\n originAmount: txV2.originAmount,\n destAmount: txV2.destAmount,\n originFeeAmount: txV2.originFeeAmount,\n sendChainGas: txV2.zapNative != 0,\n deadline: txV2.deadline,\n nonce: txV2.nonce\n });\n } catch {\n // Fallback to V1 struct.\n return abi.decode(request, (BridgeTransaction));\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function getBridgeTransactionV2(bytes calldata request) external pure returns (BridgeTransactionV2 memory) {\n request.validateV2();\n return BridgeTransactionV2Lib.decodeV2(request);\n }\n\n // ═══════════════════════════════════════ PUBLIC MUTABLE (USER FACING) ════════════════════════════════════════════\n\n /// @inheritdoc IFastBridgeV2\n function bridgeV2(BridgeParams memory params, BridgeParamsV2 memory paramsV2) public payable {\n // If relayer exclusivity is not intended for this bridge, set exclusivityEndTime to static zero.\n // Otherwise, set exclusivity to expire at the current block ts offset by quoteExclusivitySeconds.\n int256 exclusivityEndTime = 0;\n if (paramsV2.quoteRelayer != address(0)) {\n exclusivityEndTime = int256(block.timestamp) + paramsV2.quoteExclusivitySeconds;\n }\n _validateBridgeParams(params, paramsV2, exclusivityEndTime);\n\n // Transfer tokens to bridge contract. We use the actual transferred amount in case of transfer fees.\n uint256 originAmount = _takeBridgedUserAsset(params.originToken, params.originAmount);\n\n // Track the amount of origin token owed to protocol.\n uint256 originFeeAmount = 0;\n if (protocolFeeRate \u003e 0) {\n originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n // The Relayer filling this request will be paid the originAmount after fees.\n // Note: the protocol fees will be accumulated only when the Relayer claims the origin collateral.\n originAmount -= originFeeAmount;\n }\n\n // Hash the bridge request and set the initial status to REQUESTED.\n bytes memory request = BridgeTransactionV2Lib.encodeV2(\n BridgeTransactionV2({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n deadline: params.deadline,\n // Increment the sender's nonce on every bridge.\n nonce: senderNonces[params.sender]++,\n exclusivityRelayer: paramsV2.quoteRelayer,\n // We checked exclusivityEndTime to be in range [0 .. params.deadline] above, so can safely cast.\n exclusivityEndTime: uint256(exclusivityEndTime),\n zapNative: paramsV2.zapNative,\n zapData: paramsV2.zapData\n })\n );\n bytes32 transactionId = keccak256(request);\n // Note: the tx status will be updated throughout the tx lifecycle, while destChainId is set once here.\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n bridgeTxDetails[transactionId].destChainId = params.dstChainId;\n\n emit BridgeRequested({\n transactionId: transactionId,\n sender: params.sender,\n request: request,\n destChainId: params.dstChainId,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n sendChainGas: paramsV2.zapNative != 0\n });\n emit BridgeQuoteDetails(transactionId, paramsV2.quoteId);\n }\n\n /// @inheritdoc IFastBridgeV2\n function cancelV2(bytes calldata request) public {\n // Decode the request and check that it could be cancelled.\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n\n // Can only cancel a REQUESTED transaction after its deadline expires.\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n if ($.status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n\n // Permissionless cancel is only allowed after `cancelDelay` on top of the deadline.\n uint256 deadline = request.deadline();\n if (!hasRole(CANCELER_ROLE, msg.sender)) deadline += cancelDelay;\n if (block.timestamp \u003c= deadline) revert DeadlineNotExceeded();\n\n // Update status to REFUNDED.\n // Note: this is a storage write.\n $.status = BridgeStatus.REFUNDED;\n\n // Return the full amount (collateral + protocol fees) to the original sender.\n // The protocol fees are only accumulated when the transaction is claimed, so we don't need to update them here.\n address to = request.originSender();\n address token = request.originToken();\n uint256 amount = request.originAmount() + request.originFeeAmount();\n\n // Emit the event before any external calls.\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n\n // Return the funds to the original sender as last transaction action.\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(to), amount);\n } else {\n IERC20(token).safeTransfer(to, amount);\n }\n }\n\n // ═══════════════════════════════════════ PUBLIC MUTABLE (AGENT FACING) ═══════════════════════════════════════════\n\n /// @inheritdoc IFastBridgeV2\n function relayV2(bytes calldata request, address relayer) public payable {\n // Decode the request and check that it could be relayed.\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n _validateRelayParams(request, transactionId, relayer);\n\n // Mark the bridge request as relayed by saving the relayer and the block details.\n bridgeRelayDetails[transactionId].blockNumber = uint48(block.number);\n bridgeRelayDetails[transactionId].blockTimestamp = uint48(block.timestamp);\n bridgeRelayDetails[transactionId].relayer = relayer;\n\n // Transfer tokens to recipient on destination chain and trigger Zap if requested.\n address to = request.destRecipient();\n address token = request.destToken();\n uint256 amount = request.destAmount();\n uint256 zapNative = request.zapNative();\n\n // Emit the event before any external calls.\n emit BridgeRelayed({\n transactionId: transactionId,\n relayer: relayer,\n to: to,\n originChainId: request.originChainId(),\n originToken: request.originToken(),\n destToken: token,\n originAmount: request.originAmount(),\n destAmount: amount,\n chainGasAmount: zapNative\n });\n\n // All state changes have been done at this point, can proceed to the external calls.\n // This follows the checks-effects-interactions pattern to mitigate potential reentrancy attacks.\n if (token == NATIVE_GAS_TOKEN) {\n // For the native gas token, additional zapNative is not allowed.\n if (zapNative != 0) revert ZapNativeNotSupported();\n // Check that the correct msg.value was sent.\n if (msg.value != amount) revert MsgValueIncorrect();\n // Don't do a native transfer yet: we will handle it alongside the Zap below.\n } else {\n // For ERC20s, we check that the correct msg.value was sent.\n if (msg.value != zapNative) revert MsgValueIncorrect();\n // We need to transfer the tokens from the Relayer to the recipient first before performing an\n // optional post-transfer Zap.\n IERC20(token).safeTransferFrom(msg.sender, to, amount);\n }\n // At this point we have done:\n // - Transferred the requested amount of ERC20 tokens to the recipient.\n // At this point we have confirmed:\n // - For ERC20s: msg.value matches the requested zapNative amount.\n // - For the native gas token: msg.value matches the requested destAmount.\n // Remaining optional things to do:\n // - Forward the full msg.value to the recipient (if non-zero).\n // - Trigger a Zap (if zapData is present).\n bytes calldata zapData = request.zapData();\n if (zapData.length != 0) {\n // Zap Data is present: Zap has been requested by the recipient. Trigger it forwarding the full msg.value.\n _triggerZapWithChecks({recipient: to, token: token, amount: amount, zapData: zapData});\n // Note: if token has a fee on transfers, the recipient will have received less than `amount`.\n // This is a very niche edge case and should be handled by the recipient contract.\n } else if (msg.value != 0) {\n // Zap Data is missing, but msg.value was sent. This could happen in two different cases:\n // - Relay with the native gas token is happening.\n // - Relay with ERC20 is happening, with a `zapNative \u003e 0` request.\n // In both cases, we need to transfer the full msg.value to the recipient.\n Address.sendValue(payable(to), msg.value);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function proveV2(bytes32 transactionId, bytes32 destTxHash, address relayer) public onlyRole(PROVER_ROLE) {\n // Can only prove a REQUESTED transaction.\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n if ($.status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n\n // Update status to RELAYER_PROVED and store the proof details.\n // Note: these are storage writes.\n $.status = BridgeStatus.RELAYER_PROVED;\n $.proofBlockTimestamp = uint56(block.timestamp);\n $.proofRelayer = relayer;\n\n emit BridgeProofProvided(transactionId, relayer, destTxHash);\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes calldata request, address to) public {\n // Decode the request and check that it could be claimed.\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n\n // Aggregate the read operations from the same storage slot.\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n address proofRelayer = $.proofRelayer;\n BridgeStatus status = $.status;\n uint56 proofBlockTimestamp = $.proofBlockTimestamp;\n\n // Can only claim a RELAYER_PROVED transaction after the dispute period.\n if (status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(proofBlockTimestamp) \u003c= DISPUTE_PERIOD) revert DisputePeriodNotPassed();\n if (to == address(0)) {\n // Anyone could claim the funds to the proven relayer on their behalf.\n to = proofRelayer;\n } else if (proofRelayer != msg.sender) {\n // Only the proven relayer could specify an address to claim the funds to.\n revert SenderIncorrect();\n }\n\n // Update status to RELAYER_CLAIMED and transfer the origin collateral to the specified claim address.\n // Note: this is a storage write.\n $.status = BridgeStatus.RELAYER_CLAIMED;\n\n // Accumulate protocol fees if origin fee amount exists.\n address token = request.originToken();\n uint256 amount = request.originAmount();\n uint256 originFeeAmount = request.originFeeAmount();\n if (originFeeAmount \u003e 0) protocolFees[token] += originFeeAmount;\n\n // Emit the event before any external calls.\n emit BridgeDepositClaimed(transactionId, proofRelayer, to, token, amount);\n\n // Complete the relayer claim as the last transaction action.\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(to), amount);\n } else {\n IERC20(token).safeTransfer(to, amount);\n }\n }\n\n // ═══════════════════════════════════════════════ PUBLIC VIEWS ════════════════════════════════════════════════════\n\n /// @inheritdoc IFastBridgeV2\n function bridgeStatuses(bytes32 transactionId) public view returns (BridgeStatus status) {\n return bridgeTxDetails[transactionId].status;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeProofs(bytes32 transactionId) public view returns (uint96 timestamp, address relayer) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n timestamp = $.proofBlockTimestamp;\n relayer = $.proofRelayer;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeRelays(bytes32 transactionId) public view returns (bool) {\n // This transaction has been relayed if the relayer address is recorded.\n return bridgeRelayDetails[transactionId].relayer != address(0);\n }\n\n // ═════════════════════════════════════════════ INTERNAL METHODS ══════════════════════════════════════════════════\n\n /// @notice Takes the bridged asset from the user into FastBridgeV2 custody. The asset will later be\n /// claimed by the relayer who completed the relay on the destination chain, or returned to the user\n /// via the cancel function if no relay is completed.\n function _takeBridgedUserAsset(address token, uint256 amount) internal returns (uint256 amountTaken) {\n if (token == NATIVE_GAS_TOKEN) {\n // For the native gas token, we just need to check that the supplied msg.value is correct.\n // Supplied `msg.value` is already in FastBridgeV2 custody.\n if (amount != msg.value) revert MsgValueIncorrect();\n amountTaken = msg.value;\n } else {\n // For ERC20s, token is explicitly transferred from the user to FastBridgeV2.\n // We don't allow non-zero `msg.value` to avoid extra funds from being stuck in FastBridgeV2.\n if (msg.value != 0) revert MsgValueIncorrect();\n // Throw an explicit error if the provided token address is not a contract.\n if (token.code.length == 0) revert TokenNotContract();\n\n // Use the balance difference as the amount taken in case of fee on transfer tokens.\n amountTaken = IERC20(token).balanceOf(address(this));\n IERC20(token).safeTransferFrom(msg.sender, address(this), amount);\n amountTaken = IERC20(token).balanceOf(address(this)) - amountTaken;\n }\n }\n\n /// @notice Calls the recipient's hook function with the specified zapData and validates\n /// the returned value.\n function _triggerZapWithChecks(address recipient, address token, uint256 amount, bytes calldata zapData) internal {\n // Call the recipient's hook function with the specified zapData, bubbling any revert messages.\n bytes memory returnData = Address.functionCallWithValue({\n target: recipient,\n data: abi.encodeCall(IZapRecipient.zap, (token, amount, zapData)),\n // Note: see `relay()` for reasoning behind passing msg.value.\n value: msg.value\n });\n\n // Explicit revert if no return data at all.\n if (returnData.length == 0) revert RecipientNoReturnValue();\n // Check that exactly a single return value was returned.\n if (returnData.length != 32) revert RecipientIncorrectReturnValue();\n // Return value should be abi-encoded hook function selector.\n if (bytes32(returnData) != bytes32(IZapRecipient.zap.selector)) {\n revert RecipientIncorrectReturnValue();\n }\n }\n\n /// @notice Calculates the time elapsed since a proof was submitted.\n /// @dev The proof.timestamp stores block timestamps as uint56 for gas optimization.\n /// _timeSince(proof) handles timestamp rollover when block.timestamp \u003e type(uint56).max but\n /// proof.timestamp \u003c type(uint56).max via an unchecked statement.\n /// @param proofBlockTimestamp The block timestamp when the proof was submitted.\n /// @return delta The time elapsed since proof submission.\n function _timeSince(uint56 proofBlockTimestamp) internal view returns (uint256 delta) {\n unchecked {\n delta = uint56(block.timestamp) - proofBlockTimestamp;\n }\n }\n\n /// @notice Validates all parameters required for a bridge transaction.\n /// @dev This function's complexity cannot be reduced due to the number of required checks,\n /// so we disable the code-complexity rule.\n // solhint-disable-next-line code-complexity\n function _validateBridgeParams(\n BridgeParams memory params,\n BridgeParamsV2 memory paramsV2,\n int256 exclusivityEndTime\n )\n internal\n view\n {\n // Check V1 (legacy) params.\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.sender == address(0) || params.to == address(0)) revert ZeroAddress();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n\n // Check V2 params.\n if (paramsV2.zapData.length \u003e MAX_ZAP_DATA_LENGTH) revert ZapDataLengthAboveMax();\n if (paramsV2.zapNative != 0 \u0026\u0026 params.destToken == NATIVE_GAS_TOKEN) {\n revert ZapNativeNotSupported();\n }\n\n // exclusivityEndTime must be in range [0 .. params.deadline].\n if (exclusivityEndTime \u003c 0 || exclusivityEndTime \u003e int256(params.deadline)) {\n revert ExclusivityParamsIncorrect();\n }\n }\n\n /// @notice Validates all parameters required for a relay transaction.\n function _validateRelayParams(bytes calldata request, bytes32 transactionId, address relayer) internal view {\n if (relayer == address(0)) revert ZeroAddress();\n // Check that the transaction has not been relayed yet and is for the current chain.\n if (bridgeRelays(transactionId)) revert TransactionRelayed();\n if (request.destChainId() != block.chainid) revert ChainIncorrect();\n // Check that the deadline for relay to happen has not passed yet.\n if (block.timestamp \u003e request.deadline()) revert DeadlineExceeded();\n // Check the exclusivity period, if it was specified and is still ongoing.\n address exclRelayer = request.exclusivityRelayer();\n if (exclRelayer != address(0) \u0026\u0026 exclRelayer != relayer \u0026\u0026 block.timestamp \u003c= request.exclusivityEndTime()) {\n revert ExclusivityPeriodNotPassed();\n }\n }\n}\n","language":"Solidity","languageVersion":"0.8.24","compilerVersion":"0.8.24","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"","srcMapRuntime":"","abiDefinition":[{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Transfer","type":"event"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"}],"userDoc":{"kind":"user","methods":{},"version":1},"developerDoc":{"details":"Interface of the ERC20 standard as defined in the EIP.","events":{"Approval(address,address,uint256)":{"details":"Emitted when the allowance of a `spender` for an `owner` is set by a call to {approve}. `value` is the new allowance."},"Transfer(address,address,uint256)":{"details":"Emitted when `value` tokens are moved from one account (`from`) to another (`to`). Note that `value` may be zero."}},"kind":"dev","methods":{"allowance(address,address)":{"details":"Returns the remaining number of tokens that `spender` will be allowed to spend on behalf of `owner` through {transferFrom}. This is zero by default. This value changes when {approve} or {transferFrom} are called."},"approve(address,uint256)":{"details":"Sets a `value` amount of tokens as the allowance of `spender` over the caller's tokens. Returns a boolean value indicating whether the operation succeeded. IMPORTANT: Beware that changing an allowance with this method brings the risk that someone may use both the old and the new allowance by unfortunate transaction ordering. One possible solution to mitigate this race condition is to first reduce the spender's allowance to 0 and set the desired value afterwards: https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 Emits an {Approval} event."},"balanceOf(address)":{"details":"Returns the value of tokens owned by `account`."},"totalSupply()":{"details":"Returns the value of tokens in existence."},"transfer(address,uint256)":{"details":"Moves a `value` amount of tokens from the caller's account to `to`. Returns a boolean value indicating whether the operation succeeded. Emits a {Transfer} event."},"transferFrom(address,address,uint256)":{"details":"Moves a `value` amount of tokens from `from` to `to` using the allowance mechanism. `value` is then deducted from the caller's allowance. Returns a boolean value indicating whether the operation succeeded. Emits a {Transfer} event."}},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"Approval\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"Transfer\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"}],\"name\":\"allowance\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"approve\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"balanceOf\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"totalSupply\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"transfer\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"transferFrom\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"details\":\"Interface of the ERC20 standard as defined in the EIP.\",\"events\":{\"Approval(address,address,uint256)\":{\"details\":\"Emitted when the allowance of a `spender` for an `owner` is set by a call to {approve}. `value` is the new allowance.\"},\"Transfer(address,address,uint256)\":{\"details\":\"Emitted when `value` tokens are moved from one account (`from`) to another (`to`). Note that `value` may be zero.\"}},\"kind\":\"dev\",\"methods\":{\"allowance(address,address)\":{\"details\":\"Returns the remaining number of tokens that `spender` will be allowed to spend on behalf of `owner` through {transferFrom}. This is zero by default. This value changes when {approve} or {transferFrom} are called.\"},\"approve(address,uint256)\":{\"details\":\"Sets a `value` amount of tokens as the allowance of `spender` over the caller's tokens. Returns a boolean value indicating whether the operation succeeded. IMPORTANT: Beware that changing an allowance with this method brings the risk that someone may use both the old and the new allowance by unfortunate transaction ordering. One possible solution to mitigate this race condition is to first reduce the spender's allowance to 0 and set the desired value afterwards: https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 Emits an {Approval} event.\"},\"balanceOf(address)\":{\"details\":\"Returns the value of tokens owned by `account`.\"},\"totalSupply()\":{\"details\":\"Returns the value of tokens in existence.\"},\"transfer(address,uint256)\":{\"details\":\"Moves a `value` amount of tokens from the caller's account to `to`. Returns a boolean value indicating whether the operation succeeded. Emits a {Transfer} event.\"},\"transferFrom(address,address,uint256)\":{\"details\":\"Moves a `value` amount of tokens from `from` to `to` using the allowance mechanism. `value` is then deducted from the caller's allowance. Returns a boolean value indicating whether the operation succeeded. Emits a {Transfer} event.\"}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeV2.sol\":\"IERC20\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeV2.sol\":{\"keccak256\":\"0xaab2ee7357681726f0faf799a48ddfbf45fb4da93b69abf61c33dde92b29b74d\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://673391bff9569efc0f9bd99e0e6fece0bc8e8af1f052bb071b407b267a17b3b5\",\"dweb:/ipfs/QmdQQZ6DxpJYhfpinwU5WjLugr2f6qP8h68b5GerhSMQ4j\"]}},\"version\":1}"},"hashes":{"allowance(address,address)":"dd62ed3e","approve(address,uint256)":"095ea7b3","balanceOf(address)":"70a08231","totalSupply()":"18160ddd","transfer(address,uint256)":"a9059cbb","transferFrom(address,address,uint256)":"23b872dd"}},"solidity/FastBridgeV2.sol:IERC20Permit":{"code":"0x","runtime-code":"0x","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.24 ^0.8.20 ^0.8.4;\n\n// contracts/interfaces/IAdminV2.sol\n\ninterface IAdminV2 {\n event CancelDelayUpdated(uint256 oldCancelDelay, uint256 newCancelDelay);\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n /// @notice Allows the governor to set the cancel delay. The cancel delay is the time period after the transaction\n /// deadline during which a transaction can be permissionlessly cancelled if it hasn't been proven by any Relayer.\n function setCancelDelay(uint256 newCancelDelay) external;\n\n /// @notice Allows the governor to set the protocol fee rate. The protocol fee is taken from the origin\n /// amount and is only applied to completed and claimed transactions.\n /// @dev The protocol fee is abstracted away from the relayers; they always operate using the amounts after fees.\n /// The origin amount they see in the emitted log is what they get credited with.\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n /// @notice Allows the governor to withdraw the accumulated protocol fees from the contract.\n function sweepProtocolFees(address token, address recipient) external;\n}\n\n// contracts/interfaces/IAdminV2Errors.sol\n\ninterface IAdminV2Errors {\n error CancelDelayBelowMin();\n error FeeRateAboveMax();\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IFastBridgeV2Errors.sol\n\ninterface IFastBridgeV2Errors {\n error AmountIncorrect();\n error ChainIncorrect();\n error ExclusivityParamsIncorrect();\n error MsgValueIncorrect();\n error SenderIncorrect();\n error StatusIncorrect();\n error TokenNotContract();\n error ZapDataLengthAboveMax();\n error ZapNativeNotSupported();\n error ZeroAddress();\n\n error RecipientIncorrectReturnValue();\n error RecipientNoReturnValue();\n\n error DeadlineExceeded();\n error DeadlineNotExceeded();\n error DeadlineTooShort();\n error DisputePeriodNotPassed();\n error DisputePeriodPassed();\n error ExclusivityPeriodNotPassed();\n\n error TransactionRelayed();\n}\n\n// contracts/interfaces/IMulticallTarget.sol\n\n/// @notice Interface for a contract that supports multiple calls from the same caller. Inspired by MulticallV3:\n/// https://github.com/mds1/multicall/blob/master/src/Multicall3.sol\ninterface IMulticallTarget {\n struct Result {\n bool success;\n bytes returnData;\n }\n\n /// @notice Executes multiple calls to this contract in a single transaction while preserving msg.sender.\n /// Return data from the calls is discarded.\n /// @dev This method is non-payable, so only calls with msg.value of 0 can be batched.\n /// If ignoreReverts is set to true, reverted calls will be skipped.\n /// Otherwise, the entire batch will revert with the original revert reason.\n /// @param data List of ABI-encoded calldata for the calls to execute\n /// @param ignoreReverts Whether to skip calls that revert\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external;\n\n /// @notice Executes multiple calls to this contract in a single transaction while preserving msg.sender.\n /// Return data from each call is preserved.\n /// @dev This method is non-payable, so only calls with msg.value of 0 can be batched.\n /// If ignoreReverts is set to true, reverted calls will be skipped.\n /// Otherwise, the entire batch will revert with the original revert reason.\n /// @param data List of ABI-encoded calldata for the calls to execute\n /// @param ignoreReverts Whether to skip calls that revert\n /// @return results List of results from the calls, each containing (success, returnData)\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results);\n}\n\n// contracts/interfaces/IZapRecipient.sol\n\n/// @notice Interface for contracts that can perform Zap operations. Such contracts could be used as Recipients\n/// in a FastBridge transaction that includes a Zap operation. The Zap Data should include instructions on how\n/// exactly the Zap operation should be executed, which would typically include the target address and calldata\n/// to use. The exact implementation of the Zap Data encoding is up to the Recipient contract.\ninterface IZapRecipient {\n /// @notice Performs a Zap operation with the given token and amount according to the provided Zap data.\n /// @param token The address of the token being used for the Zap operation.\n /// @param amount The amount of tokens to be used.\n /// @param zapData The encoded data specifying how the Zap operation should be executed.\n /// @return The function selector to indicate successful execution.\n function zap(address token, uint256 amount, bytes memory zapData) external payable returns (bytes4);\n}\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// contracts/interfaces/IFastBridgeV2.sol\n\ninterface IFastBridgeV2 is IFastBridge {\n enum BridgeStatus {\n NULL, // Doesn't exist yet.\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n struct BridgeTxDetails {\n BridgeStatus status;\n uint32 destChainId;\n uint56 proofBlockTimestamp;\n address proofRelayer;\n }\n\n struct BridgeRelay {\n uint48 blockNumber;\n uint48 blockTimestamp;\n address relayer;\n }\n\n /// @notice New params introduced in the FastBridgeV2.\n /// We are passing fields from the older BridgeParams struct outside of this struct for backwards compatibility.\n /// Note: quoteRelayer and quoteExclusivitySeconds are either both zero (indicating no exclusivity)\n /// or both non-zero (indicating exclusivity for the given period).\n /// Note: zapNative \u003e 0 can NOT be used with destToken = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE (native token)\n /// @param quoteRelayer Relayer that provided the quote for the transaction\n /// @param quoteExclusivitySeconds Period of time the quote relayer is guaranteed exclusivity after user's deposit\n /// @param quoteId Unique quote identifier used for tracking the quote\n /// @param zapNative ETH value to send to the recipient (if any)\n /// @param zapData Parameters for the Zap to the destination recipient (if any)\n struct BridgeParamsV2 {\n address quoteRelayer;\n int256 quoteExclusivitySeconds;\n bytes quoteId;\n uint256 zapNative;\n bytes zapData;\n }\n\n /// @notice Updated bridge transaction struct to include parameters introduced in FastBridgeV2.\n /// Note: only `exclusivityRelayer` can fill such a transaction until `exclusivityEndTime`.\n struct BridgeTransactionV2 {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n // Note: sendChainGas flag from V1 is deprecated\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n address exclusivityRelayer;\n uint256 exclusivityEndTime;\n uint256 zapNative; // ETH value to send to the recipient (if any)\n bytes zapData; // data to pass for the Zap action (if any)\n }\n\n event BridgeQuoteDetails(bytes32 indexed transactionId, bytes quoteId);\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability\n /// to provide temporary exclusivity fill rights for the quote relayer.\n /// @param params The parameters required to bridge\n /// @param paramsV2 The parameters for exclusivity fill rights (optional, can be left empty)\n function bridgeV2(BridgeParams memory params, BridgeParamsV2 memory paramsV2) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function relayV2(bytes memory request, address relayer) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param transactionId The transaction id associated with the encoded bridge transaction to prove\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function proveV2(bytes32 transactionId, bytes32 destTxHash, address relayer) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital.\n /// @notice Can only send funds to the relayer address on the proof.\n /// @param request The encoded bridge transaction to claim on origin chain\n function claimV2(bytes memory request) external;\n\n /// @notice Cancels an outstanding bridge transaction in case optimistic bridging failed and returns the full amount\n /// to the original sender.\n /// @param request The encoded bridge transaction to refund\n function cancelV2(bytes memory request) external;\n\n /// @notice Checks if a transaction has been relayed\n /// @param transactionId The ID of the transaction to check\n /// @return True if the transaction has been relayed, false otherwise\n function bridgeRelays(bytes32 transactionId) external view returns (bool);\n\n /// @notice Returns the status of a bridge transaction\n /// @param transactionId The ID of the bridge transaction\n /// @return BridgeStatus Status of the bridge transaction\n function bridgeStatuses(bytes32 transactionId) external view returns (BridgeStatus);\n\n /// @notice Returns the timestamp and relayer of a bridge proof\n /// @param transactionId The ID of the bridge transaction\n /// @return timestamp The timestamp of the bridge proof\n /// @return relayer The relayer address of the bridge proof\n function bridgeProofs(bytes32 transactionId) external view returns (uint96 timestamp, address relayer);\n\n /// @notice Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\n /// @param request The bridge request to decode\n function getBridgeTransactionV2(bytes memory request) external view returns (BridgeTransactionV2 memory);\n}\n\n// contracts/utils/MulticallTarget.sol\n\n// solhint-disable avoid-low-level-calls\n/// @notice Abstract contract template that supports batched calls while preserving msg.sender.\n/// Only calls with msg.value of 0 can be batched.\nabstract contract MulticallTarget is IMulticallTarget {\n error MulticallTarget__UndeterminedRevert();\n\n /// @inheritdoc IMulticallTarget\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external {\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\n if (!success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(result);\n }\n }\n }\n\n /// @inheritdoc IMulticallTarget\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results)\n {\n results = new Result[](data.length);\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (results[i].success, results[i].returnData) = address(this).delegatecall(data[i]);\n if (!results[i].success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(results[i].returnData);\n }\n }\n }\n\n /// @dev Bubbles the revert message from the underlying call.\n /// Note: preserves the same custom error or revert string, if one was used.\n /// Source: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v5.0.2/contracts/utils/Address.sol#L143-L158\n function _bubbleRevert(bytes memory returnData) internal pure {\n // Look for revert reason and bubble it up if present\n if (returnData.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n // solhint-disable-next-line no-inline-assembly\n assembly {\n let returndata_size := mload(returnData)\n revert(add(32, returnData), returndata_size)\n }\n } else {\n revert MulticallTarget__UndeterminedRevert();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// contracts/libs/BridgeTransactionV2.sol\n\n// solhint-disable no-inline-assembly\nlibrary BridgeTransactionV2Lib {\n uint16 internal constant VERSION = 2;\n\n // Offsets of the fields in the packed BridgeTransactionV2 struct\n // uint16 version [000 .. 002)\n // uint32 originChainId [002 .. 006)\n // uint32 destChainId [006 .. 010)\n // address originSender [010 .. 030)\n // address destRecipient [030 .. 050)\n // address originToken [050 .. 070)\n // address destToken [070 .. 090)\n // uint256 originAmount [090 .. 122)\n // uint256 destAmount [122 .. 154)\n // uint256 originFeeAmount [154 .. 186)\n // uint256 deadline [186 .. 218)\n // uint256 nonce [218 .. 250)\n // address exclusivityRelayer [250 .. 270)\n // uint256 exclusivityEndTime [270 .. 302)\n // uint256 zapNative [302 .. 334)\n // bytes zapData [334 .. ***)\n\n // forgefmt: disable-start\n uint256 private constant OFFSET_ORIGIN_CHAIN_ID = 2;\n uint256 private constant OFFSET_DEST_CHAIN_ID = 6;\n uint256 private constant OFFSET_ORIGIN_SENDER = 10;\n uint256 private constant OFFSET_DEST_RECIPIENT = 30;\n uint256 private constant OFFSET_ORIGIN_TOKEN = 50;\n uint256 private constant OFFSET_DEST_TOKEN = 70;\n uint256 private constant OFFSET_ORIGIN_AMOUNT = 90;\n uint256 private constant OFFSET_DEST_AMOUNT = 122;\n uint256 private constant OFFSET_ORIGIN_FEE_AMOUNT = 154;\n uint256 private constant OFFSET_DEADLINE = 186;\n uint256 private constant OFFSET_NONCE = 218;\n uint256 private constant OFFSET_EXCLUSIVITY_RELAYER = 250;\n uint256 private constant OFFSET_EXCLUSIVITY_END_TIME = 270;\n uint256 private constant OFFSET_ZAP_NATIVE = 302;\n uint256 private constant OFFSET_ZAP_DATA = 334;\n // forgefmt: disable-end\n\n error BridgeTransactionV2__InvalidEncodedTx();\n error BridgeTransactionV2__UnsupportedVersion(uint16 version);\n\n /// @notice Validates that the encoded transaction is a tightly packed encoded payload for BridgeTransactionV2.\n /// @dev Checks the minimum length and the version, use this function before decoding any of the fields.\n function validateV2(bytes calldata encodedTx) internal pure {\n // Check the minimum length: must at least include all static fields.\n if (encodedTx.length \u003c OFFSET_ZAP_DATA) revert BridgeTransactionV2__InvalidEncodedTx();\n // Once we validated the length, we can be sure that the version field is present.\n uint16 version_ = version(encodedTx);\n if (version_ != VERSION) revert BridgeTransactionV2__UnsupportedVersion(version_);\n }\n\n /// @notice Encodes the BridgeTransactionV2 struct by tightly packing the fields.\n /// @dev `abi.decode` will not work as a result of the tightly packed fields. Use `decodeV2` to decode instead.\n function encodeV2(IFastBridgeV2.BridgeTransactionV2 memory bridgeTx) internal pure returns (bytes memory) {\n // We split the encoding into two parts to avoid stack-too-deep error\n bytes memory firstPart = abi.encodePacked(\n VERSION,\n bridgeTx.originChainId,\n bridgeTx.destChainId,\n bridgeTx.originSender,\n bridgeTx.destRecipient,\n bridgeTx.originToken,\n bridgeTx.destToken,\n bridgeTx.originAmount\n );\n return abi.encodePacked(\n firstPart,\n bridgeTx.destAmount,\n bridgeTx.originFeeAmount,\n // Note: we skip the deprecated `sendChainGas` flag, which was present in BridgeTransaction V1\n bridgeTx.deadline,\n bridgeTx.nonce,\n // New V2 fields: exclusivity\n bridgeTx.exclusivityRelayer,\n bridgeTx.exclusivityEndTime,\n // New V2 fields: Zap\n bridgeTx.zapNative,\n bridgeTx.zapData\n );\n }\n\n /// @notice Decodes the BridgeTransactionV2 struct from the encoded transaction.\n /// @dev Encoded BridgeTransactionV2 struct must be tightly packed.\n /// Use `validateV2` before decoding to ensure the encoded transaction is valid.\n function decodeV2(bytes calldata encodedTx)\n internal\n pure\n returns (IFastBridgeV2.BridgeTransactionV2 memory bridgeTx)\n {\n bridgeTx.originChainId = originChainId(encodedTx);\n bridgeTx.destChainId = destChainId(encodedTx);\n bridgeTx.originSender = originSender(encodedTx);\n bridgeTx.destRecipient = destRecipient(encodedTx);\n bridgeTx.originToken = originToken(encodedTx);\n bridgeTx.destToken = destToken(encodedTx);\n bridgeTx.originAmount = originAmount(encodedTx);\n bridgeTx.destAmount = destAmount(encodedTx);\n bridgeTx.originFeeAmount = originFeeAmount(encodedTx);\n bridgeTx.deadline = deadline(encodedTx);\n bridgeTx.nonce = nonce(encodedTx);\n bridgeTx.exclusivityRelayer = exclusivityRelayer(encodedTx);\n bridgeTx.exclusivityEndTime = exclusivityEndTime(encodedTx);\n bridgeTx.zapNative = zapNative(encodedTx);\n bridgeTx.zapData = zapData(encodedTx);\n }\n\n /// @notice Extracts the version from the encoded transaction.\n function version(bytes calldata encodedTx) internal pure returns (uint16 version_) {\n // Load 32 bytes from the start and shift it 240 bits to the right to get the highest 16 bits.\n assembly {\n version_ := shr(240, calldataload(encodedTx.offset))\n }\n }\n\n /// @notice Extracts the origin chain ID from the encoded transaction.\n function originChainId(bytes calldata encodedTx) internal pure returns (uint32 originChainId_) {\n // Load 32 bytes from the offset and shift it 224 bits to the right to get the highest 32 bits.\n assembly {\n originChainId_ := shr(224, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_CHAIN_ID)))\n }\n }\n\n /// @notice Extracts the destination chain ID from the encoded transaction.\n function destChainId(bytes calldata encodedTx) internal pure returns (uint32 destChainId_) {\n // Load 32 bytes from the offset and shift it 224 bits to the right to get the highest 32 bits.\n assembly {\n destChainId_ := shr(224, calldataload(add(encodedTx.offset, OFFSET_DEST_CHAIN_ID)))\n }\n }\n\n /// @notice Extracts the origin sender from the encoded transaction.\n function originSender(bytes calldata encodedTx) internal pure returns (address originSender_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n originSender_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_SENDER)))\n }\n }\n\n /// @notice Extracts the destination recipient from the encoded transaction.\n function destRecipient(bytes calldata encodedTx) internal pure returns (address destRecipient_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n destRecipient_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_DEST_RECIPIENT)))\n }\n }\n\n /// @notice Extracts the origin token from the encoded transaction.\n function originToken(bytes calldata encodedTx) internal pure returns (address originToken_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n originToken_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_TOKEN)))\n }\n }\n\n /// @notice Extracts the destination token from the encoded transaction.\n function destToken(bytes calldata encodedTx) internal pure returns (address destToken_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n destToken_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_DEST_TOKEN)))\n }\n }\n\n /// @notice Extracts the origin amount from the encoded transaction.\n function originAmount(bytes calldata encodedTx) internal pure returns (uint256 originAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n originAmount_ := calldataload(add(encodedTx.offset, OFFSET_ORIGIN_AMOUNT))\n }\n }\n\n /// @notice Extracts the destination amount from the encoded transaction.\n function destAmount(bytes calldata encodedTx) internal pure returns (uint256 destAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n destAmount_ := calldataload(add(encodedTx.offset, OFFSET_DEST_AMOUNT))\n }\n }\n\n /// @notice Extracts the origin fee amount from the encoded transaction.\n function originFeeAmount(bytes calldata encodedTx) internal pure returns (uint256 originFeeAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n originFeeAmount_ := calldataload(add(encodedTx.offset, OFFSET_ORIGIN_FEE_AMOUNT))\n }\n }\n\n /// @notice Extracts the deadline from the encoded transaction.\n function deadline(bytes calldata encodedTx) internal pure returns (uint256 deadline_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n deadline_ := calldataload(add(encodedTx.offset, OFFSET_DEADLINE))\n }\n }\n\n /// @notice Extracts the nonce from the encoded transaction.\n function nonce(bytes calldata encodedTx) internal pure returns (uint256 nonce_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n nonce_ := calldataload(add(encodedTx.offset, OFFSET_NONCE))\n }\n }\n\n /// @notice Extracts the exclusivity relayer from the encoded transaction.\n function exclusivityRelayer(bytes calldata encodedTx) internal pure returns (address exclusivityRelayer_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n exclusivityRelayer_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_EXCLUSIVITY_RELAYER)))\n }\n }\n\n /// @notice Extracts the exclusivity end time from the encoded transaction.\n function exclusivityEndTime(bytes calldata encodedTx) internal pure returns (uint256 exclusivityEndTime_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n exclusivityEndTime_ := calldataload(add(encodedTx.offset, OFFSET_EXCLUSIVITY_END_TIME))\n }\n }\n\n /// @notice Extracts the Zap's native value from the encoded transaction.\n function zapNative(bytes calldata encodedTx) internal pure returns (uint256 zapNative_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n zapNative_ := calldataload(add(encodedTx.offset, OFFSET_ZAP_NATIVE))\n }\n }\n\n /// @notice Extracts the Zap's data from the encoded transaction.\n function zapData(bytes calldata encodedTx) internal pure returns (bytes calldata zapData_) {\n zapData_ = encodedTx[OFFSET_ZAP_DATA:];\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/AdminV2.sol\n\n// ════════════════════════════════════════════════ INTERFACES ═════════════════════════════════════════════════════\n\n// ═════════════════════════════════════════════ EXTERNAL IMPORTS ══════════════════════════════════════════════════\n\n/// @title AdminV2\n/// @notice Provides administrative functions and controls for managing the FastBridgeV2 contract,\n/// including access control and configuration settings.\ncontract AdminV2 is AccessControlEnumerable, IAdminV2, IAdminV2Errors {\n using SafeERC20 for IERC20;\n\n /// @notice The address reserved for the native gas token (ETH on Ethereum and most L2s, AVAX on Avalanche, etc.).\n address public constant NATIVE_GAS_TOKEN = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice The role identifier for the Quoter API's off-chain authentication.\n /// @dev Only addresses with this role can post FastBridge quotes to the API.\n bytes32 public constant QUOTER_ROLE = keccak256(\"QUOTER_ROLE\");\n\n /// @notice The role identifier for the Prover's on-chain authentication in FastBridge.\n /// @dev Only addresses with this role can provide proofs that a FastBridge request has been relayed.\n bytes32 public constant PROVER_ROLE = keccak256(\"PROVER_ROLE\");\n\n /// @notice The role identifier for the Guard's on-chain authentication in FastBridge.\n /// @dev Only addresses with this role can dispute submitted relay proofs during the dispute period.\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n\n /// @notice The role identifier for the Canceler's on-chain authentication in FastBridge.\n /// @dev Only addresses with this role can cancel a FastBridge transaction without the cancel delay.\n bytes32 public constant CANCELER_ROLE = keccak256(\"CANCELER_ROLE\");\n\n /// @notice The role identifier for the Governor's on-chain administrative authority.\n /// @dev Only addresses with this role can perform administrative tasks within the contract.\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n /// @notice The denominator for fee rates, representing 100%.\n uint256 public constant FEE_BPS = 1e6;\n /// @notice The maximum protocol fee rate: 1% of the origin amount.\n uint256 public constant FEE_RATE_MAX = 0.01e6;\n\n /// @notice The minimum cancel delay that can be set by the governor.\n uint256 public constant MIN_CANCEL_DELAY = 1 hours;\n /// @notice The default cancel delay set during contract deployment.\n uint256 public constant DEFAULT_CANCEL_DELAY = 1 days;\n\n /// @notice The protocol fee rate taken on the origin amount deposited in the origin chain.\n uint256 public protocolFeeRate;\n\n /// @notice The accumulated protocol fee amounts.\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice The delay period after which a transaction can be permissionlessly cancelled.\n uint256 public cancelDelay;\n\n /// @notice This variable is deprecated and should not be used.\n /// @dev Use ZapNative V2 requests instead.\n uint256 public immutable chainGasAmount = 0;\n\n constructor(address defaultAdmin) {\n _grantRole(DEFAULT_ADMIN_ROLE, defaultAdmin);\n _setCancelDelay(DEFAULT_CANCEL_DELAY);\n }\n\n /// @inheritdoc IAdminV2\n function setCancelDelay(uint256 newCancelDelay) external onlyRole(GOVERNOR_ROLE) {\n _setCancelDelay(newCancelDelay);\n }\n\n /// @inheritdoc IAdminV2\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n if (newFeeRate \u003e FEE_RATE_MAX) revert FeeRateAboveMax();\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n /// @inheritdoc IAdminV2\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n // Early exit if no accumulated fees.\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return;\n // Reset the accumulated fees first.\n protocolFees[token] = 0;\n emit FeesSwept(token, recipient, feeAmount);\n // Sweep the fees as the last transaction action.\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(recipient), feeAmount);\n } else {\n IERC20(token).safeTransfer(recipient, feeAmount);\n }\n }\n\n /// @notice Internal logic to set the cancel delay. Security checks are performed outside of this function.\n /// @dev This function is marked as private to prevent child contracts from calling it directly.\n function _setCancelDelay(uint256 newCancelDelay) private {\n if (newCancelDelay \u003c MIN_CANCEL_DELAY) revert CancelDelayBelowMin();\n uint256 oldCancelDelay = cancelDelay;\n cancelDelay = newCancelDelay;\n emit CancelDelayUpdated(oldCancelDelay, newCancelDelay);\n }\n}\n\n// contracts/FastBridgeV2.sol\n\n// ════════════════════════════════════════════════ INTERFACES ═════════════════════════════════════════════════════\n\n// ═════════════════════════════════════════════ INTERNAL IMPORTS ══════════════════════════════════════════════════\n\n// ═════════════════════════════════════════════ EXTERNAL IMPORTS ══════════════════════════════════════════════════\n\n/// @title FastBridgeV2\n/// @notice Core component of the SynapseRFQ protocol, enabling Relayers (Solvers) to fulfill bridge requests.\n/// Supports ERC20 and native gas tokens, along with the Zap feature for executing actions on the destination chain.\n/// Users interact with the off-chain Quoter API to obtain a current quote for a bridge transaction.\n/// They then submit the bridge request with the quote to this contract, depositing their assets in escrow.\n/// Relayers can fulfill requests by relaying them to the destination chain and must prove fulfillment to claim funds.\n/// Guards monitor proofs and can dispute discrepancies.\n/// Users can reclaim funds by cancelling their requests if it has not been fulfilled within the specified deadline.\ncontract FastBridgeV2 is AdminV2, MulticallTarget, IFastBridgeV2, IFastBridgeV2Errors {\n using BridgeTransactionV2Lib for bytes;\n using SafeERC20 for IERC20;\n\n /// @notice The duration of the dispute period for relayed transactions.\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice The minimum required time between transaction request and deadline.\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n /// @notice The maximum allowed length for zapData.\n uint256 public constant MAX_ZAP_DATA_LENGTH = 2 ** 16 - 1;\n\n /// @notice Maps transaction IDs to bridge details (status, destination chain ID, proof timestamp, and relayer).\n /// Note: this is only stored for transactions having local chain as the origin chain.\n mapping(bytes32 =\u003e BridgeTxDetails) public bridgeTxDetails;\n /// @notice Maps transaction IDs to relay details (block number, block timestamp, and relayer).\n /// Note: this is only stored for transactions having local chain as the destination chain.\n mapping(bytes32 =\u003e BridgeRelay) public bridgeRelayDetails;\n /// @notice Maps sender addresses to their unique bridge nonce.\n mapping(address =\u003e uint256) public senderNonces;\n\n /// @notice This variable is deprecated and should not be used.\n /// @dev Replaced by senderNonces.\n uint256 public immutable nonce = 0;\n /// @notice The block number at which this contract was deployed.\n uint256 public immutable deployBlock;\n\n /// @notice Initializes the FastBridgeV2 contract with the provided default admin,\n /// sets the default cancel delay, and records the deploy block number.\n constructor(address defaultAdmin) AdminV2(defaultAdmin) {\n deployBlock = block.number;\n }\n\n // ══════════════════════════════════════ EXTERNAL MUTABLE (USER FACING) ═══════════════════════════════════════════\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n bridgeV2({\n params: params,\n paramsV2: BridgeParamsV2({\n quoteRelayer: address(0),\n quoteExclusivitySeconds: 0,\n quoteId: bytes(\"\"),\n zapNative: 0,\n zapData: bytes(\"\")\n })\n });\n }\n\n /// Note: this function is deprecated and will be removed in a future version.\n /// @dev Replaced by `cancel`.\n /// @inheritdoc IFastBridge\n function refund(bytes calldata request) external {\n cancelV2(request);\n }\n\n // ══════════════════════════════════════ EXTERNAL MUTABLE (AGENT FACING) ══════════════════════════════════════════\n\n /// @inheritdoc IFastBridge\n function relay(bytes calldata request) external payable {\n // `relay` override will validate the request.\n relayV2({request: request, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes calldata request, bytes32 destTxHash) external {\n request.validateV2();\n proveV2({transactionId: keccak256(request), destTxHash: destTxHash, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridgeV2\n function claimV2(bytes calldata request) external {\n // `claim` override will validate the request.\n claim({request: request, to: address(0)});\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n // Aggregate the read operations from the same storage slot.\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n address disputedRelayer = $.proofRelayer;\n BridgeStatus status = $.status;\n uint56 proofBlockTimestamp = $.proofBlockTimestamp;\n\n // Can only dispute a RELAYER_PROVED transaction within the dispute period.\n if (status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(proofBlockTimestamp) \u003e DISPUTE_PERIOD) {\n revert DisputePeriodPassed();\n }\n\n // Update status to REQUESTED and delete the disputed proof details.\n // Note: these are storage writes.\n $.status = BridgeStatus.REQUESTED;\n $.proofRelayer = address(0);\n $.proofBlockTimestamp = 0;\n\n emit BridgeProofDisputed(transactionId, disputedRelayer);\n }\n\n // ══════════════════════════════════════════════ EXTERNAL VIEWS ═══════════════════════════════════════════════════\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n // The correct relayer can only claim a RELAYER_PROVED transaction after the dispute period.\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n if ($.status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if ($.proofRelayer != relayer) revert SenderIncorrect();\n\n return _timeSince($.proofBlockTimestamp) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n /// @dev This method is added to achieve backwards compatibility with decoding requests into V1 structs:\n /// - `zapNative` is partially reported as a zero/non-zero flag\n /// - `zapData` is ignored\n /// In order to process all kinds of requests use getBridgeTransactionV2 instead.\n function getBridgeTransaction(bytes calldata request) external view returns (BridgeTransaction memory) {\n // Try decoding into V2 struct first. This will revert if V1 struct is passed.\n try this.getBridgeTransactionV2(request) returns (BridgeTransactionV2 memory txV2) {\n // Note: we entirely ignore the zapData field, as it was not present in V1.\n return BridgeTransaction({\n originChainId: txV2.originChainId,\n destChainId: txV2.destChainId,\n originSender: txV2.originSender,\n destRecipient: txV2.destRecipient,\n originToken: txV2.originToken,\n destToken: txV2.destToken,\n originAmount: txV2.originAmount,\n destAmount: txV2.destAmount,\n originFeeAmount: txV2.originFeeAmount,\n sendChainGas: txV2.zapNative != 0,\n deadline: txV2.deadline,\n nonce: txV2.nonce\n });\n } catch {\n // Fallback to V1 struct.\n return abi.decode(request, (BridgeTransaction));\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function getBridgeTransactionV2(bytes calldata request) external pure returns (BridgeTransactionV2 memory) {\n request.validateV2();\n return BridgeTransactionV2Lib.decodeV2(request);\n }\n\n // ═══════════════════════════════════════ PUBLIC MUTABLE (USER FACING) ════════════════════════════════════════════\n\n /// @inheritdoc IFastBridgeV2\n function bridgeV2(BridgeParams memory params, BridgeParamsV2 memory paramsV2) public payable {\n // If relayer exclusivity is not intended for this bridge, set exclusivityEndTime to static zero.\n // Otherwise, set exclusivity to expire at the current block ts offset by quoteExclusivitySeconds.\n int256 exclusivityEndTime = 0;\n if (paramsV2.quoteRelayer != address(0)) {\n exclusivityEndTime = int256(block.timestamp) + paramsV2.quoteExclusivitySeconds;\n }\n _validateBridgeParams(params, paramsV2, exclusivityEndTime);\n\n // Transfer tokens to bridge contract. We use the actual transferred amount in case of transfer fees.\n uint256 originAmount = _takeBridgedUserAsset(params.originToken, params.originAmount);\n\n // Track the amount of origin token owed to protocol.\n uint256 originFeeAmount = 0;\n if (protocolFeeRate \u003e 0) {\n originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n // The Relayer filling this request will be paid the originAmount after fees.\n // Note: the protocol fees will be accumulated only when the Relayer claims the origin collateral.\n originAmount -= originFeeAmount;\n }\n\n // Hash the bridge request and set the initial status to REQUESTED.\n bytes memory request = BridgeTransactionV2Lib.encodeV2(\n BridgeTransactionV2({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n deadline: params.deadline,\n // Increment the sender's nonce on every bridge.\n nonce: senderNonces[params.sender]++,\n exclusivityRelayer: paramsV2.quoteRelayer,\n // We checked exclusivityEndTime to be in range [0 .. params.deadline] above, so can safely cast.\n exclusivityEndTime: uint256(exclusivityEndTime),\n zapNative: paramsV2.zapNative,\n zapData: paramsV2.zapData\n })\n );\n bytes32 transactionId = keccak256(request);\n // Note: the tx status will be updated throughout the tx lifecycle, while destChainId is set once here.\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n bridgeTxDetails[transactionId].destChainId = params.dstChainId;\n\n emit BridgeRequested({\n transactionId: transactionId,\n sender: params.sender,\n request: request,\n destChainId: params.dstChainId,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n sendChainGas: paramsV2.zapNative != 0\n });\n emit BridgeQuoteDetails(transactionId, paramsV2.quoteId);\n }\n\n /// @inheritdoc IFastBridgeV2\n function cancelV2(bytes calldata request) public {\n // Decode the request and check that it could be cancelled.\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n\n // Can only cancel a REQUESTED transaction after its deadline expires.\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n if ($.status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n\n // Permissionless cancel is only allowed after `cancelDelay` on top of the deadline.\n uint256 deadline = request.deadline();\n if (!hasRole(CANCELER_ROLE, msg.sender)) deadline += cancelDelay;\n if (block.timestamp \u003c= deadline) revert DeadlineNotExceeded();\n\n // Update status to REFUNDED.\n // Note: this is a storage write.\n $.status = BridgeStatus.REFUNDED;\n\n // Return the full amount (collateral + protocol fees) to the original sender.\n // The protocol fees are only accumulated when the transaction is claimed, so we don't need to update them here.\n address to = request.originSender();\n address token = request.originToken();\n uint256 amount = request.originAmount() + request.originFeeAmount();\n\n // Emit the event before any external calls.\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n\n // Return the funds to the original sender as last transaction action.\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(to), amount);\n } else {\n IERC20(token).safeTransfer(to, amount);\n }\n }\n\n // ═══════════════════════════════════════ PUBLIC MUTABLE (AGENT FACING) ═══════════════════════════════════════════\n\n /// @inheritdoc IFastBridgeV2\n function relayV2(bytes calldata request, address relayer) public payable {\n // Decode the request and check that it could be relayed.\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n _validateRelayParams(request, transactionId, relayer);\n\n // Mark the bridge request as relayed by saving the relayer and the block details.\n bridgeRelayDetails[transactionId].blockNumber = uint48(block.number);\n bridgeRelayDetails[transactionId].blockTimestamp = uint48(block.timestamp);\n bridgeRelayDetails[transactionId].relayer = relayer;\n\n // Transfer tokens to recipient on destination chain and trigger Zap if requested.\n address to = request.destRecipient();\n address token = request.destToken();\n uint256 amount = request.destAmount();\n uint256 zapNative = request.zapNative();\n\n // Emit the event before any external calls.\n emit BridgeRelayed({\n transactionId: transactionId,\n relayer: relayer,\n to: to,\n originChainId: request.originChainId(),\n originToken: request.originToken(),\n destToken: token,\n originAmount: request.originAmount(),\n destAmount: amount,\n chainGasAmount: zapNative\n });\n\n // All state changes have been done at this point, can proceed to the external calls.\n // This follows the checks-effects-interactions pattern to mitigate potential reentrancy attacks.\n if (token == NATIVE_GAS_TOKEN) {\n // For the native gas token, additional zapNative is not allowed.\n if (zapNative != 0) revert ZapNativeNotSupported();\n // Check that the correct msg.value was sent.\n if (msg.value != amount) revert MsgValueIncorrect();\n // Don't do a native transfer yet: we will handle it alongside the Zap below.\n } else {\n // For ERC20s, we check that the correct msg.value was sent.\n if (msg.value != zapNative) revert MsgValueIncorrect();\n // We need to transfer the tokens from the Relayer to the recipient first before performing an\n // optional post-transfer Zap.\n IERC20(token).safeTransferFrom(msg.sender, to, amount);\n }\n // At this point we have done:\n // - Transferred the requested amount of ERC20 tokens to the recipient.\n // At this point we have confirmed:\n // - For ERC20s: msg.value matches the requested zapNative amount.\n // - For the native gas token: msg.value matches the requested destAmount.\n // Remaining optional things to do:\n // - Forward the full msg.value to the recipient (if non-zero).\n // - Trigger a Zap (if zapData is present).\n bytes calldata zapData = request.zapData();\n if (zapData.length != 0) {\n // Zap Data is present: Zap has been requested by the recipient. Trigger it forwarding the full msg.value.\n _triggerZapWithChecks({recipient: to, token: token, amount: amount, zapData: zapData});\n // Note: if token has a fee on transfers, the recipient will have received less than `amount`.\n // This is a very niche edge case and should be handled by the recipient contract.\n } else if (msg.value != 0) {\n // Zap Data is missing, but msg.value was sent. This could happen in two different cases:\n // - Relay with the native gas token is happening.\n // - Relay with ERC20 is happening, with a `zapNative \u003e 0` request.\n // In both cases, we need to transfer the full msg.value to the recipient.\n Address.sendValue(payable(to), msg.value);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function proveV2(bytes32 transactionId, bytes32 destTxHash, address relayer) public onlyRole(PROVER_ROLE) {\n // Can only prove a REQUESTED transaction.\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n if ($.status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n\n // Update status to RELAYER_PROVED and store the proof details.\n // Note: these are storage writes.\n $.status = BridgeStatus.RELAYER_PROVED;\n $.proofBlockTimestamp = uint56(block.timestamp);\n $.proofRelayer = relayer;\n\n emit BridgeProofProvided(transactionId, relayer, destTxHash);\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes calldata request, address to) public {\n // Decode the request and check that it could be claimed.\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n\n // Aggregate the read operations from the same storage slot.\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n address proofRelayer = $.proofRelayer;\n BridgeStatus status = $.status;\n uint56 proofBlockTimestamp = $.proofBlockTimestamp;\n\n // Can only claim a RELAYER_PROVED transaction after the dispute period.\n if (status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(proofBlockTimestamp) \u003c= DISPUTE_PERIOD) revert DisputePeriodNotPassed();\n if (to == address(0)) {\n // Anyone could claim the funds to the proven relayer on their behalf.\n to = proofRelayer;\n } else if (proofRelayer != msg.sender) {\n // Only the proven relayer could specify an address to claim the funds to.\n revert SenderIncorrect();\n }\n\n // Update status to RELAYER_CLAIMED and transfer the origin collateral to the specified claim address.\n // Note: this is a storage write.\n $.status = BridgeStatus.RELAYER_CLAIMED;\n\n // Accumulate protocol fees if origin fee amount exists.\n address token = request.originToken();\n uint256 amount = request.originAmount();\n uint256 originFeeAmount = request.originFeeAmount();\n if (originFeeAmount \u003e 0) protocolFees[token] += originFeeAmount;\n\n // Emit the event before any external calls.\n emit BridgeDepositClaimed(transactionId, proofRelayer, to, token, amount);\n\n // Complete the relayer claim as the last transaction action.\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(to), amount);\n } else {\n IERC20(token).safeTransfer(to, amount);\n }\n }\n\n // ═══════════════════════════════════════════════ PUBLIC VIEWS ════════════════════════════════════════════════════\n\n /// @inheritdoc IFastBridgeV2\n function bridgeStatuses(bytes32 transactionId) public view returns (BridgeStatus status) {\n return bridgeTxDetails[transactionId].status;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeProofs(bytes32 transactionId) public view returns (uint96 timestamp, address relayer) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n timestamp = $.proofBlockTimestamp;\n relayer = $.proofRelayer;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeRelays(bytes32 transactionId) public view returns (bool) {\n // This transaction has been relayed if the relayer address is recorded.\n return bridgeRelayDetails[transactionId].relayer != address(0);\n }\n\n // ═════════════════════════════════════════════ INTERNAL METHODS ══════════════════════════════════════════════════\n\n /// @notice Takes the bridged asset from the user into FastBridgeV2 custody. The asset will later be\n /// claimed by the relayer who completed the relay on the destination chain, or returned to the user\n /// via the cancel function if no relay is completed.\n function _takeBridgedUserAsset(address token, uint256 amount) internal returns (uint256 amountTaken) {\n if (token == NATIVE_GAS_TOKEN) {\n // For the native gas token, we just need to check that the supplied msg.value is correct.\n // Supplied `msg.value` is already in FastBridgeV2 custody.\n if (amount != msg.value) revert MsgValueIncorrect();\n amountTaken = msg.value;\n } else {\n // For ERC20s, token is explicitly transferred from the user to FastBridgeV2.\n // We don't allow non-zero `msg.value` to avoid extra funds from being stuck in FastBridgeV2.\n if (msg.value != 0) revert MsgValueIncorrect();\n // Throw an explicit error if the provided token address is not a contract.\n if (token.code.length == 0) revert TokenNotContract();\n\n // Use the balance difference as the amount taken in case of fee on transfer tokens.\n amountTaken = IERC20(token).balanceOf(address(this));\n IERC20(token).safeTransferFrom(msg.sender, address(this), amount);\n amountTaken = IERC20(token).balanceOf(address(this)) - amountTaken;\n }\n }\n\n /// @notice Calls the recipient's hook function with the specified zapData and validates\n /// the returned value.\n function _triggerZapWithChecks(address recipient, address token, uint256 amount, bytes calldata zapData) internal {\n // Call the recipient's hook function with the specified zapData, bubbling any revert messages.\n bytes memory returnData = Address.functionCallWithValue({\n target: recipient,\n data: abi.encodeCall(IZapRecipient.zap, (token, amount, zapData)),\n // Note: see `relay()` for reasoning behind passing msg.value.\n value: msg.value\n });\n\n // Explicit revert if no return data at all.\n if (returnData.length == 0) revert RecipientNoReturnValue();\n // Check that exactly a single return value was returned.\n if (returnData.length != 32) revert RecipientIncorrectReturnValue();\n // Return value should be abi-encoded hook function selector.\n if (bytes32(returnData) != bytes32(IZapRecipient.zap.selector)) {\n revert RecipientIncorrectReturnValue();\n }\n }\n\n /// @notice Calculates the time elapsed since a proof was submitted.\n /// @dev The proof.timestamp stores block timestamps as uint56 for gas optimization.\n /// _timeSince(proof) handles timestamp rollover when block.timestamp \u003e type(uint56).max but\n /// proof.timestamp \u003c type(uint56).max via an unchecked statement.\n /// @param proofBlockTimestamp The block timestamp when the proof was submitted.\n /// @return delta The time elapsed since proof submission.\n function _timeSince(uint56 proofBlockTimestamp) internal view returns (uint256 delta) {\n unchecked {\n delta = uint56(block.timestamp) - proofBlockTimestamp;\n }\n }\n\n /// @notice Validates all parameters required for a bridge transaction.\n /// @dev This function's complexity cannot be reduced due to the number of required checks,\n /// so we disable the code-complexity rule.\n // solhint-disable-next-line code-complexity\n function _validateBridgeParams(\n BridgeParams memory params,\n BridgeParamsV2 memory paramsV2,\n int256 exclusivityEndTime\n )\n internal\n view\n {\n // Check V1 (legacy) params.\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.sender == address(0) || params.to == address(0)) revert ZeroAddress();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n\n // Check V2 params.\n if (paramsV2.zapData.length \u003e MAX_ZAP_DATA_LENGTH) revert ZapDataLengthAboveMax();\n if (paramsV2.zapNative != 0 \u0026\u0026 params.destToken == NATIVE_GAS_TOKEN) {\n revert ZapNativeNotSupported();\n }\n\n // exclusivityEndTime must be in range [0 .. params.deadline].\n if (exclusivityEndTime \u003c 0 || exclusivityEndTime \u003e int256(params.deadline)) {\n revert ExclusivityParamsIncorrect();\n }\n }\n\n /// @notice Validates all parameters required for a relay transaction.\n function _validateRelayParams(bytes calldata request, bytes32 transactionId, address relayer) internal view {\n if (relayer == address(0)) revert ZeroAddress();\n // Check that the transaction has not been relayed yet and is for the current chain.\n if (bridgeRelays(transactionId)) revert TransactionRelayed();\n if (request.destChainId() != block.chainid) revert ChainIncorrect();\n // Check that the deadline for relay to happen has not passed yet.\n if (block.timestamp \u003e request.deadline()) revert DeadlineExceeded();\n // Check the exclusivity period, if it was specified and is still ongoing.\n address exclRelayer = request.exclusivityRelayer();\n if (exclRelayer != address(0) \u0026\u0026 exclRelayer != relayer \u0026\u0026 block.timestamp \u003c= request.exclusivityEndTime()) {\n revert ExclusivityPeriodNotPassed();\n }\n }\n}\n","language":"Solidity","languageVersion":"0.8.24","compilerVersion":"0.8.24","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"","srcMapRuntime":"","abiDefinition":[{"inputs":[],"name":"DOMAIN_SEPARATOR","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"nonces","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"permit","outputs":[],"stateMutability":"nonpayable","type":"function"}],"userDoc":{"kind":"user","methods":{},"version":1},"developerDoc":{"details":"Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in https://eips.ethereum.org/EIPS/eip-2612[EIP-2612]. Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't need to send a transaction, and thus is not required to hold Ether at all. ==== Security Considerations There are two important considerations concerning the use of `permit`. The first is that a valid permit signature expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be considered as an intention to spend the allowance in any specific way. The second is that because permits have built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be generally recommended is: ```solidity function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public { try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {} doThing(..., value); } function doThing(..., uint256 value) public { token.safeTransferFrom(msg.sender, address(this), value); ... } ``` Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also {SafeERC20-safeTransferFrom}). Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so contracts should have entry points that don't rely on permit.","kind":"dev","methods":{"DOMAIN_SEPARATOR()":{"details":"Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}."},"nonces(address)":{"details":"Returns the current nonce for `owner`. This value must be included whenever a signature is generated for {permit}. Every successful call to {permit} increases ``owner``'s nonce by one. This prevents a signature from being used multiple times."},"permit(address,address,uint256,uint256,uint8,bytes32,bytes32)":{"details":"Sets `value` as the allowance of `spender` over ``owner``'s tokens, given ``owner``'s signed approval. IMPORTANT: The same issues {IERC20-approve} has related to transaction ordering also apply here. Emits an {Approval} event. Requirements: - `spender` cannot be the zero address. - `deadline` must be a timestamp in the future. - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner` over the EIP712-formatted function arguments. - the signature must use ``owner``'s current nonce (see {nonces}). For more information on the signature format, see the https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP section]. CAUTION: See Security Considerations above."}},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[],\"name\":\"DOMAIN_SEPARATOR\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"}],\"name\":\"nonces\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"},{\"internalType\":\"uint8\",\"name\":\"v\",\"type\":\"uint8\"},{\"internalType\":\"bytes32\",\"name\":\"r\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"s\",\"type\":\"bytes32\"}],\"name\":\"permit\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"details\":\"Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in https://eips.ethereum.org/EIPS/eip-2612[EIP-2612]. Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't need to send a transaction, and thus is not required to hold Ether at all. ==== Security Considerations There are two important considerations concerning the use of `permit`. The first is that a valid permit signature expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be considered as an intention to spend the allowance in any specific way. The second is that because permits have built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be generally recommended is: ```solidity function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public { try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {} doThing(..., value); } function doThing(..., uint256 value) public { token.safeTransferFrom(msg.sender, address(this), value); ... } ``` Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also {SafeERC20-safeTransferFrom}). Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so contracts should have entry points that don't rely on permit.\",\"kind\":\"dev\",\"methods\":{\"DOMAIN_SEPARATOR()\":{\"details\":\"Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\"},\"nonces(address)\":{\"details\":\"Returns the current nonce for `owner`. This value must be included whenever a signature is generated for {permit}. Every successful call to {permit} increases ``owner``'s nonce by one. This prevents a signature from being used multiple times.\"},\"permit(address,address,uint256,uint256,uint8,bytes32,bytes32)\":{\"details\":\"Sets `value` as the allowance of `spender` over ``owner``'s tokens, given ``owner``'s signed approval. IMPORTANT: The same issues {IERC20-approve} has related to transaction ordering also apply here. Emits an {Approval} event. Requirements: - `spender` cannot be the zero address. - `deadline` must be a timestamp in the future. - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner` over the EIP712-formatted function arguments. - the signature must use ``owner``'s current nonce (see {nonces}). For more information on the signature format, see the https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP section]. CAUTION: See Security Considerations above.\"}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeV2.sol\":\"IERC20Permit\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeV2.sol\":{\"keccak256\":\"0xaab2ee7357681726f0faf799a48ddfbf45fb4da93b69abf61c33dde92b29b74d\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://673391bff9569efc0f9bd99e0e6fece0bc8e8af1f052bb071b407b267a17b3b5\",\"dweb:/ipfs/QmdQQZ6DxpJYhfpinwU5WjLugr2f6qP8h68b5GerhSMQ4j\"]}},\"version\":1}"},"hashes":{"DOMAIN_SEPARATOR()":"3644e515","nonces(address)":"7ecebe00","permit(address,address,uint256,uint256,uint8,bytes32,bytes32)":"d505accf"}},"solidity/FastBridgeV2.sol:IFastBridge":{"code":"0x","runtime-code":"0x","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.24 ^0.8.20 ^0.8.4;\n\n// contracts/interfaces/IAdminV2.sol\n\ninterface IAdminV2 {\n event CancelDelayUpdated(uint256 oldCancelDelay, uint256 newCancelDelay);\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n /// @notice Allows the governor to set the cancel delay. The cancel delay is the time period after the transaction\n /// deadline during which a transaction can be permissionlessly cancelled if it hasn't been proven by any Relayer.\n function setCancelDelay(uint256 newCancelDelay) external;\n\n /// @notice Allows the governor to set the protocol fee rate. The protocol fee is taken from the origin\n /// amount and is only applied to completed and claimed transactions.\n /// @dev The protocol fee is abstracted away from the relayers; they always operate using the amounts after fees.\n /// The origin amount they see in the emitted log is what they get credited with.\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n /// @notice Allows the governor to withdraw the accumulated protocol fees from the contract.\n function sweepProtocolFees(address token, address recipient) external;\n}\n\n// contracts/interfaces/IAdminV2Errors.sol\n\ninterface IAdminV2Errors {\n error CancelDelayBelowMin();\n error FeeRateAboveMax();\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IFastBridgeV2Errors.sol\n\ninterface IFastBridgeV2Errors {\n error AmountIncorrect();\n error ChainIncorrect();\n error ExclusivityParamsIncorrect();\n error MsgValueIncorrect();\n error SenderIncorrect();\n error StatusIncorrect();\n error TokenNotContract();\n error ZapDataLengthAboveMax();\n error ZapNativeNotSupported();\n error ZeroAddress();\n\n error RecipientIncorrectReturnValue();\n error RecipientNoReturnValue();\n\n error DeadlineExceeded();\n error DeadlineNotExceeded();\n error DeadlineTooShort();\n error DisputePeriodNotPassed();\n error DisputePeriodPassed();\n error ExclusivityPeriodNotPassed();\n\n error TransactionRelayed();\n}\n\n// contracts/interfaces/IMulticallTarget.sol\n\n/// @notice Interface for a contract that supports multiple calls from the same caller. Inspired by MulticallV3:\n/// https://github.com/mds1/multicall/blob/master/src/Multicall3.sol\ninterface IMulticallTarget {\n struct Result {\n bool success;\n bytes returnData;\n }\n\n /// @notice Executes multiple calls to this contract in a single transaction while preserving msg.sender.\n /// Return data from the calls is discarded.\n /// @dev This method is non-payable, so only calls with msg.value of 0 can be batched.\n /// If ignoreReverts is set to true, reverted calls will be skipped.\n /// Otherwise, the entire batch will revert with the original revert reason.\n /// @param data List of ABI-encoded calldata for the calls to execute\n /// @param ignoreReverts Whether to skip calls that revert\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external;\n\n /// @notice Executes multiple calls to this contract in a single transaction while preserving msg.sender.\n /// Return data from each call is preserved.\n /// @dev This method is non-payable, so only calls with msg.value of 0 can be batched.\n /// If ignoreReverts is set to true, reverted calls will be skipped.\n /// Otherwise, the entire batch will revert with the original revert reason.\n /// @param data List of ABI-encoded calldata for the calls to execute\n /// @param ignoreReverts Whether to skip calls that revert\n /// @return results List of results from the calls, each containing (success, returnData)\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results);\n}\n\n// contracts/interfaces/IZapRecipient.sol\n\n/// @notice Interface for contracts that can perform Zap operations. Such contracts could be used as Recipients\n/// in a FastBridge transaction that includes a Zap operation. The Zap Data should include instructions on how\n/// exactly the Zap operation should be executed, which would typically include the target address and calldata\n/// to use. The exact implementation of the Zap Data encoding is up to the Recipient contract.\ninterface IZapRecipient {\n /// @notice Performs a Zap operation with the given token and amount according to the provided Zap data.\n /// @param token The address of the token being used for the Zap operation.\n /// @param amount The amount of tokens to be used.\n /// @param zapData The encoded data specifying how the Zap operation should be executed.\n /// @return The function selector to indicate successful execution.\n function zap(address token, uint256 amount, bytes memory zapData) external payable returns (bytes4);\n}\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// contracts/interfaces/IFastBridgeV2.sol\n\ninterface IFastBridgeV2 is IFastBridge {\n enum BridgeStatus {\n NULL, // Doesn't exist yet.\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n struct BridgeTxDetails {\n BridgeStatus status;\n uint32 destChainId;\n uint56 proofBlockTimestamp;\n address proofRelayer;\n }\n\n struct BridgeRelay {\n uint48 blockNumber;\n uint48 blockTimestamp;\n address relayer;\n }\n\n /// @notice New params introduced in the FastBridgeV2.\n /// We are passing fields from the older BridgeParams struct outside of this struct for backwards compatibility.\n /// Note: quoteRelayer and quoteExclusivitySeconds are either both zero (indicating no exclusivity)\n /// or both non-zero (indicating exclusivity for the given period).\n /// Note: zapNative \u003e 0 can NOT be used with destToken = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE (native token)\n /// @param quoteRelayer Relayer that provided the quote for the transaction\n /// @param quoteExclusivitySeconds Period of time the quote relayer is guaranteed exclusivity after user's deposit\n /// @param quoteId Unique quote identifier used for tracking the quote\n /// @param zapNative ETH value to send to the recipient (if any)\n /// @param zapData Parameters for the Zap to the destination recipient (if any)\n struct BridgeParamsV2 {\n address quoteRelayer;\n int256 quoteExclusivitySeconds;\n bytes quoteId;\n uint256 zapNative;\n bytes zapData;\n }\n\n /// @notice Updated bridge transaction struct to include parameters introduced in FastBridgeV2.\n /// Note: only `exclusivityRelayer` can fill such a transaction until `exclusivityEndTime`.\n struct BridgeTransactionV2 {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n // Note: sendChainGas flag from V1 is deprecated\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n address exclusivityRelayer;\n uint256 exclusivityEndTime;\n uint256 zapNative; // ETH value to send to the recipient (if any)\n bytes zapData; // data to pass for the Zap action (if any)\n }\n\n event BridgeQuoteDetails(bytes32 indexed transactionId, bytes quoteId);\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability\n /// to provide temporary exclusivity fill rights for the quote relayer.\n /// @param params The parameters required to bridge\n /// @param paramsV2 The parameters for exclusivity fill rights (optional, can be left empty)\n function bridgeV2(BridgeParams memory params, BridgeParamsV2 memory paramsV2) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function relayV2(bytes memory request, address relayer) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param transactionId The transaction id associated with the encoded bridge transaction to prove\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function proveV2(bytes32 transactionId, bytes32 destTxHash, address relayer) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital.\n /// @notice Can only send funds to the relayer address on the proof.\n /// @param request The encoded bridge transaction to claim on origin chain\n function claimV2(bytes memory request) external;\n\n /// @notice Cancels an outstanding bridge transaction in case optimistic bridging failed and returns the full amount\n /// to the original sender.\n /// @param request The encoded bridge transaction to refund\n function cancelV2(bytes memory request) external;\n\n /// @notice Checks if a transaction has been relayed\n /// @param transactionId The ID of the transaction to check\n /// @return True if the transaction has been relayed, false otherwise\n function bridgeRelays(bytes32 transactionId) external view returns (bool);\n\n /// @notice Returns the status of a bridge transaction\n /// @param transactionId The ID of the bridge transaction\n /// @return BridgeStatus Status of the bridge transaction\n function bridgeStatuses(bytes32 transactionId) external view returns (BridgeStatus);\n\n /// @notice Returns the timestamp and relayer of a bridge proof\n /// @param transactionId The ID of the bridge transaction\n /// @return timestamp The timestamp of the bridge proof\n /// @return relayer The relayer address of the bridge proof\n function bridgeProofs(bytes32 transactionId) external view returns (uint96 timestamp, address relayer);\n\n /// @notice Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\n /// @param request The bridge request to decode\n function getBridgeTransactionV2(bytes memory request) external view returns (BridgeTransactionV2 memory);\n}\n\n// contracts/utils/MulticallTarget.sol\n\n// solhint-disable avoid-low-level-calls\n/// @notice Abstract contract template that supports batched calls while preserving msg.sender.\n/// Only calls with msg.value of 0 can be batched.\nabstract contract MulticallTarget is IMulticallTarget {\n error MulticallTarget__UndeterminedRevert();\n\n /// @inheritdoc IMulticallTarget\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external {\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\n if (!success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(result);\n }\n }\n }\n\n /// @inheritdoc IMulticallTarget\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results)\n {\n results = new Result[](data.length);\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (results[i].success, results[i].returnData) = address(this).delegatecall(data[i]);\n if (!results[i].success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(results[i].returnData);\n }\n }\n }\n\n /// @dev Bubbles the revert message from the underlying call.\n /// Note: preserves the same custom error or revert string, if one was used.\n /// Source: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v5.0.2/contracts/utils/Address.sol#L143-L158\n function _bubbleRevert(bytes memory returnData) internal pure {\n // Look for revert reason and bubble it up if present\n if (returnData.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n // solhint-disable-next-line no-inline-assembly\n assembly {\n let returndata_size := mload(returnData)\n revert(add(32, returnData), returndata_size)\n }\n } else {\n revert MulticallTarget__UndeterminedRevert();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// contracts/libs/BridgeTransactionV2.sol\n\n// solhint-disable no-inline-assembly\nlibrary BridgeTransactionV2Lib {\n uint16 internal constant VERSION = 2;\n\n // Offsets of the fields in the packed BridgeTransactionV2 struct\n // uint16 version [000 .. 002)\n // uint32 originChainId [002 .. 006)\n // uint32 destChainId [006 .. 010)\n // address originSender [010 .. 030)\n // address destRecipient [030 .. 050)\n // address originToken [050 .. 070)\n // address destToken [070 .. 090)\n // uint256 originAmount [090 .. 122)\n // uint256 destAmount [122 .. 154)\n // uint256 originFeeAmount [154 .. 186)\n // uint256 deadline [186 .. 218)\n // uint256 nonce [218 .. 250)\n // address exclusivityRelayer [250 .. 270)\n // uint256 exclusivityEndTime [270 .. 302)\n // uint256 zapNative [302 .. 334)\n // bytes zapData [334 .. ***)\n\n // forgefmt: disable-start\n uint256 private constant OFFSET_ORIGIN_CHAIN_ID = 2;\n uint256 private constant OFFSET_DEST_CHAIN_ID = 6;\n uint256 private constant OFFSET_ORIGIN_SENDER = 10;\n uint256 private constant OFFSET_DEST_RECIPIENT = 30;\n uint256 private constant OFFSET_ORIGIN_TOKEN = 50;\n uint256 private constant OFFSET_DEST_TOKEN = 70;\n uint256 private constant OFFSET_ORIGIN_AMOUNT = 90;\n uint256 private constant OFFSET_DEST_AMOUNT = 122;\n uint256 private constant OFFSET_ORIGIN_FEE_AMOUNT = 154;\n uint256 private constant OFFSET_DEADLINE = 186;\n uint256 private constant OFFSET_NONCE = 218;\n uint256 private constant OFFSET_EXCLUSIVITY_RELAYER = 250;\n uint256 private constant OFFSET_EXCLUSIVITY_END_TIME = 270;\n uint256 private constant OFFSET_ZAP_NATIVE = 302;\n uint256 private constant OFFSET_ZAP_DATA = 334;\n // forgefmt: disable-end\n\n error BridgeTransactionV2__InvalidEncodedTx();\n error BridgeTransactionV2__UnsupportedVersion(uint16 version);\n\n /// @notice Validates that the encoded transaction is a tightly packed encoded payload for BridgeTransactionV2.\n /// @dev Checks the minimum length and the version, use this function before decoding any of the fields.\n function validateV2(bytes calldata encodedTx) internal pure {\n // Check the minimum length: must at least include all static fields.\n if (encodedTx.length \u003c OFFSET_ZAP_DATA) revert BridgeTransactionV2__InvalidEncodedTx();\n // Once we validated the length, we can be sure that the version field is present.\n uint16 version_ = version(encodedTx);\n if (version_ != VERSION) revert BridgeTransactionV2__UnsupportedVersion(version_);\n }\n\n /// @notice Encodes the BridgeTransactionV2 struct by tightly packing the fields.\n /// @dev `abi.decode` will not work as a result of the tightly packed fields. Use `decodeV2` to decode instead.\n function encodeV2(IFastBridgeV2.BridgeTransactionV2 memory bridgeTx) internal pure returns (bytes memory) {\n // We split the encoding into two parts to avoid stack-too-deep error\n bytes memory firstPart = abi.encodePacked(\n VERSION,\n bridgeTx.originChainId,\n bridgeTx.destChainId,\n bridgeTx.originSender,\n bridgeTx.destRecipient,\n bridgeTx.originToken,\n bridgeTx.destToken,\n bridgeTx.originAmount\n );\n return abi.encodePacked(\n firstPart,\n bridgeTx.destAmount,\n bridgeTx.originFeeAmount,\n // Note: we skip the deprecated `sendChainGas` flag, which was present in BridgeTransaction V1\n bridgeTx.deadline,\n bridgeTx.nonce,\n // New V2 fields: exclusivity\n bridgeTx.exclusivityRelayer,\n bridgeTx.exclusivityEndTime,\n // New V2 fields: Zap\n bridgeTx.zapNative,\n bridgeTx.zapData\n );\n }\n\n /// @notice Decodes the BridgeTransactionV2 struct from the encoded transaction.\n /// @dev Encoded BridgeTransactionV2 struct must be tightly packed.\n /// Use `validateV2` before decoding to ensure the encoded transaction is valid.\n function decodeV2(bytes calldata encodedTx)\n internal\n pure\n returns (IFastBridgeV2.BridgeTransactionV2 memory bridgeTx)\n {\n bridgeTx.originChainId = originChainId(encodedTx);\n bridgeTx.destChainId = destChainId(encodedTx);\n bridgeTx.originSender = originSender(encodedTx);\n bridgeTx.destRecipient = destRecipient(encodedTx);\n bridgeTx.originToken = originToken(encodedTx);\n bridgeTx.destToken = destToken(encodedTx);\n bridgeTx.originAmount = originAmount(encodedTx);\n bridgeTx.destAmount = destAmount(encodedTx);\n bridgeTx.originFeeAmount = originFeeAmount(encodedTx);\n bridgeTx.deadline = deadline(encodedTx);\n bridgeTx.nonce = nonce(encodedTx);\n bridgeTx.exclusivityRelayer = exclusivityRelayer(encodedTx);\n bridgeTx.exclusivityEndTime = exclusivityEndTime(encodedTx);\n bridgeTx.zapNative = zapNative(encodedTx);\n bridgeTx.zapData = zapData(encodedTx);\n }\n\n /// @notice Extracts the version from the encoded transaction.\n function version(bytes calldata encodedTx) internal pure returns (uint16 version_) {\n // Load 32 bytes from the start and shift it 240 bits to the right to get the highest 16 bits.\n assembly {\n version_ := shr(240, calldataload(encodedTx.offset))\n }\n }\n\n /// @notice Extracts the origin chain ID from the encoded transaction.\n function originChainId(bytes calldata encodedTx) internal pure returns (uint32 originChainId_) {\n // Load 32 bytes from the offset and shift it 224 bits to the right to get the highest 32 bits.\n assembly {\n originChainId_ := shr(224, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_CHAIN_ID)))\n }\n }\n\n /// @notice Extracts the destination chain ID from the encoded transaction.\n function destChainId(bytes calldata encodedTx) internal pure returns (uint32 destChainId_) {\n // Load 32 bytes from the offset and shift it 224 bits to the right to get the highest 32 bits.\n assembly {\n destChainId_ := shr(224, calldataload(add(encodedTx.offset, OFFSET_DEST_CHAIN_ID)))\n }\n }\n\n /// @notice Extracts the origin sender from the encoded transaction.\n function originSender(bytes calldata encodedTx) internal pure returns (address originSender_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n originSender_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_SENDER)))\n }\n }\n\n /// @notice Extracts the destination recipient from the encoded transaction.\n function destRecipient(bytes calldata encodedTx) internal pure returns (address destRecipient_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n destRecipient_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_DEST_RECIPIENT)))\n }\n }\n\n /// @notice Extracts the origin token from the encoded transaction.\n function originToken(bytes calldata encodedTx) internal pure returns (address originToken_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n originToken_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_TOKEN)))\n }\n }\n\n /// @notice Extracts the destination token from the encoded transaction.\n function destToken(bytes calldata encodedTx) internal pure returns (address destToken_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n destToken_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_DEST_TOKEN)))\n }\n }\n\n /// @notice Extracts the origin amount from the encoded transaction.\n function originAmount(bytes calldata encodedTx) internal pure returns (uint256 originAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n originAmount_ := calldataload(add(encodedTx.offset, OFFSET_ORIGIN_AMOUNT))\n }\n }\n\n /// @notice Extracts the destination amount from the encoded transaction.\n function destAmount(bytes calldata encodedTx) internal pure returns (uint256 destAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n destAmount_ := calldataload(add(encodedTx.offset, OFFSET_DEST_AMOUNT))\n }\n }\n\n /// @notice Extracts the origin fee amount from the encoded transaction.\n function originFeeAmount(bytes calldata encodedTx) internal pure returns (uint256 originFeeAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n originFeeAmount_ := calldataload(add(encodedTx.offset, OFFSET_ORIGIN_FEE_AMOUNT))\n }\n }\n\n /// @notice Extracts the deadline from the encoded transaction.\n function deadline(bytes calldata encodedTx) internal pure returns (uint256 deadline_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n deadline_ := calldataload(add(encodedTx.offset, OFFSET_DEADLINE))\n }\n }\n\n /// @notice Extracts the nonce from the encoded transaction.\n function nonce(bytes calldata encodedTx) internal pure returns (uint256 nonce_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n nonce_ := calldataload(add(encodedTx.offset, OFFSET_NONCE))\n }\n }\n\n /// @notice Extracts the exclusivity relayer from the encoded transaction.\n function exclusivityRelayer(bytes calldata encodedTx) internal pure returns (address exclusivityRelayer_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n exclusivityRelayer_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_EXCLUSIVITY_RELAYER)))\n }\n }\n\n /// @notice Extracts the exclusivity end time from the encoded transaction.\n function exclusivityEndTime(bytes calldata encodedTx) internal pure returns (uint256 exclusivityEndTime_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n exclusivityEndTime_ := calldataload(add(encodedTx.offset, OFFSET_EXCLUSIVITY_END_TIME))\n }\n }\n\n /// @notice Extracts the Zap's native value from the encoded transaction.\n function zapNative(bytes calldata encodedTx) internal pure returns (uint256 zapNative_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n zapNative_ := calldataload(add(encodedTx.offset, OFFSET_ZAP_NATIVE))\n }\n }\n\n /// @notice Extracts the Zap's data from the encoded transaction.\n function zapData(bytes calldata encodedTx) internal pure returns (bytes calldata zapData_) {\n zapData_ = encodedTx[OFFSET_ZAP_DATA:];\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/AdminV2.sol\n\n// ════════════════════════════════════════════════ INTERFACES ═════════════════════════════════════════════════════\n\n// ═════════════════════════════════════════════ EXTERNAL IMPORTS ══════════════════════════════════════════════════\n\n/// @title AdminV2\n/// @notice Provides administrative functions and controls for managing the FastBridgeV2 contract,\n/// including access control and configuration settings.\ncontract AdminV2 is AccessControlEnumerable, IAdminV2, IAdminV2Errors {\n using SafeERC20 for IERC20;\n\n /// @notice The address reserved for the native gas token (ETH on Ethereum and most L2s, AVAX on Avalanche, etc.).\n address public constant NATIVE_GAS_TOKEN = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice The role identifier for the Quoter API's off-chain authentication.\n /// @dev Only addresses with this role can post FastBridge quotes to the API.\n bytes32 public constant QUOTER_ROLE = keccak256(\"QUOTER_ROLE\");\n\n /// @notice The role identifier for the Prover's on-chain authentication in FastBridge.\n /// @dev Only addresses with this role can provide proofs that a FastBridge request has been relayed.\n bytes32 public constant PROVER_ROLE = keccak256(\"PROVER_ROLE\");\n\n /// @notice The role identifier for the Guard's on-chain authentication in FastBridge.\n /// @dev Only addresses with this role can dispute submitted relay proofs during the dispute period.\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n\n /// @notice The role identifier for the Canceler's on-chain authentication in FastBridge.\n /// @dev Only addresses with this role can cancel a FastBridge transaction without the cancel delay.\n bytes32 public constant CANCELER_ROLE = keccak256(\"CANCELER_ROLE\");\n\n /// @notice The role identifier for the Governor's on-chain administrative authority.\n /// @dev Only addresses with this role can perform administrative tasks within the contract.\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n /// @notice The denominator for fee rates, representing 100%.\n uint256 public constant FEE_BPS = 1e6;\n /// @notice The maximum protocol fee rate: 1% of the origin amount.\n uint256 public constant FEE_RATE_MAX = 0.01e6;\n\n /// @notice The minimum cancel delay that can be set by the governor.\n uint256 public constant MIN_CANCEL_DELAY = 1 hours;\n /// @notice The default cancel delay set during contract deployment.\n uint256 public constant DEFAULT_CANCEL_DELAY = 1 days;\n\n /// @notice The protocol fee rate taken on the origin amount deposited in the origin chain.\n uint256 public protocolFeeRate;\n\n /// @notice The accumulated protocol fee amounts.\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice The delay period after which a transaction can be permissionlessly cancelled.\n uint256 public cancelDelay;\n\n /// @notice This variable is deprecated and should not be used.\n /// @dev Use ZapNative V2 requests instead.\n uint256 public immutable chainGasAmount = 0;\n\n constructor(address defaultAdmin) {\n _grantRole(DEFAULT_ADMIN_ROLE, defaultAdmin);\n _setCancelDelay(DEFAULT_CANCEL_DELAY);\n }\n\n /// @inheritdoc IAdminV2\n function setCancelDelay(uint256 newCancelDelay) external onlyRole(GOVERNOR_ROLE) {\n _setCancelDelay(newCancelDelay);\n }\n\n /// @inheritdoc IAdminV2\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n if (newFeeRate \u003e FEE_RATE_MAX) revert FeeRateAboveMax();\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n /// @inheritdoc IAdminV2\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n // Early exit if no accumulated fees.\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return;\n // Reset the accumulated fees first.\n protocolFees[token] = 0;\n emit FeesSwept(token, recipient, feeAmount);\n // Sweep the fees as the last transaction action.\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(recipient), feeAmount);\n } else {\n IERC20(token).safeTransfer(recipient, feeAmount);\n }\n }\n\n /// @notice Internal logic to set the cancel delay. Security checks are performed outside of this function.\n /// @dev This function is marked as private to prevent child contracts from calling it directly.\n function _setCancelDelay(uint256 newCancelDelay) private {\n if (newCancelDelay \u003c MIN_CANCEL_DELAY) revert CancelDelayBelowMin();\n uint256 oldCancelDelay = cancelDelay;\n cancelDelay = newCancelDelay;\n emit CancelDelayUpdated(oldCancelDelay, newCancelDelay);\n }\n}\n\n// contracts/FastBridgeV2.sol\n\n// ════════════════════════════════════════════════ INTERFACES ═════════════════════════════════════════════════════\n\n// ═════════════════════════════════════════════ INTERNAL IMPORTS ══════════════════════════════════════════════════\n\n// ═════════════════════════════════════════════ EXTERNAL IMPORTS ══════════════════════════════════════════════════\n\n/// @title FastBridgeV2\n/// @notice Core component of the SynapseRFQ protocol, enabling Relayers (Solvers) to fulfill bridge requests.\n/// Supports ERC20 and native gas tokens, along with the Zap feature for executing actions on the destination chain.\n/// Users interact with the off-chain Quoter API to obtain a current quote for a bridge transaction.\n/// They then submit the bridge request with the quote to this contract, depositing their assets in escrow.\n/// Relayers can fulfill requests by relaying them to the destination chain and must prove fulfillment to claim funds.\n/// Guards monitor proofs and can dispute discrepancies.\n/// Users can reclaim funds by cancelling their requests if it has not been fulfilled within the specified deadline.\ncontract FastBridgeV2 is AdminV2, MulticallTarget, IFastBridgeV2, IFastBridgeV2Errors {\n using BridgeTransactionV2Lib for bytes;\n using SafeERC20 for IERC20;\n\n /// @notice The duration of the dispute period for relayed transactions.\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice The minimum required time between transaction request and deadline.\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n /// @notice The maximum allowed length for zapData.\n uint256 public constant MAX_ZAP_DATA_LENGTH = 2 ** 16 - 1;\n\n /// @notice Maps transaction IDs to bridge details (status, destination chain ID, proof timestamp, and relayer).\n /// Note: this is only stored for transactions having local chain as the origin chain.\n mapping(bytes32 =\u003e BridgeTxDetails) public bridgeTxDetails;\n /// @notice Maps transaction IDs to relay details (block number, block timestamp, and relayer).\n /// Note: this is only stored for transactions having local chain as the destination chain.\n mapping(bytes32 =\u003e BridgeRelay) public bridgeRelayDetails;\n /// @notice Maps sender addresses to their unique bridge nonce.\n mapping(address =\u003e uint256) public senderNonces;\n\n /// @notice This variable is deprecated and should not be used.\n /// @dev Replaced by senderNonces.\n uint256 public immutable nonce = 0;\n /// @notice The block number at which this contract was deployed.\n uint256 public immutable deployBlock;\n\n /// @notice Initializes the FastBridgeV2 contract with the provided default admin,\n /// sets the default cancel delay, and records the deploy block number.\n constructor(address defaultAdmin) AdminV2(defaultAdmin) {\n deployBlock = block.number;\n }\n\n // ══════════════════════════════════════ EXTERNAL MUTABLE (USER FACING) ═══════════════════════════════════════════\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n bridgeV2({\n params: params,\n paramsV2: BridgeParamsV2({\n quoteRelayer: address(0),\n quoteExclusivitySeconds: 0,\n quoteId: bytes(\"\"),\n zapNative: 0,\n zapData: bytes(\"\")\n })\n });\n }\n\n /// Note: this function is deprecated and will be removed in a future version.\n /// @dev Replaced by `cancel`.\n /// @inheritdoc IFastBridge\n function refund(bytes calldata request) external {\n cancelV2(request);\n }\n\n // ══════════════════════════════════════ EXTERNAL MUTABLE (AGENT FACING) ══════════════════════════════════════════\n\n /// @inheritdoc IFastBridge\n function relay(bytes calldata request) external payable {\n // `relay` override will validate the request.\n relayV2({request: request, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes calldata request, bytes32 destTxHash) external {\n request.validateV2();\n proveV2({transactionId: keccak256(request), destTxHash: destTxHash, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridgeV2\n function claimV2(bytes calldata request) external {\n // `claim` override will validate the request.\n claim({request: request, to: address(0)});\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n // Aggregate the read operations from the same storage slot.\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n address disputedRelayer = $.proofRelayer;\n BridgeStatus status = $.status;\n uint56 proofBlockTimestamp = $.proofBlockTimestamp;\n\n // Can only dispute a RELAYER_PROVED transaction within the dispute period.\n if (status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(proofBlockTimestamp) \u003e DISPUTE_PERIOD) {\n revert DisputePeriodPassed();\n }\n\n // Update status to REQUESTED and delete the disputed proof details.\n // Note: these are storage writes.\n $.status = BridgeStatus.REQUESTED;\n $.proofRelayer = address(0);\n $.proofBlockTimestamp = 0;\n\n emit BridgeProofDisputed(transactionId, disputedRelayer);\n }\n\n // ══════════════════════════════════════════════ EXTERNAL VIEWS ═══════════════════════════════════════════════════\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n // The correct relayer can only claim a RELAYER_PROVED transaction after the dispute period.\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n if ($.status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if ($.proofRelayer != relayer) revert SenderIncorrect();\n\n return _timeSince($.proofBlockTimestamp) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n /// @dev This method is added to achieve backwards compatibility with decoding requests into V1 structs:\n /// - `zapNative` is partially reported as a zero/non-zero flag\n /// - `zapData` is ignored\n /// In order to process all kinds of requests use getBridgeTransactionV2 instead.\n function getBridgeTransaction(bytes calldata request) external view returns (BridgeTransaction memory) {\n // Try decoding into V2 struct first. This will revert if V1 struct is passed.\n try this.getBridgeTransactionV2(request) returns (BridgeTransactionV2 memory txV2) {\n // Note: we entirely ignore the zapData field, as it was not present in V1.\n return BridgeTransaction({\n originChainId: txV2.originChainId,\n destChainId: txV2.destChainId,\n originSender: txV2.originSender,\n destRecipient: txV2.destRecipient,\n originToken: txV2.originToken,\n destToken: txV2.destToken,\n originAmount: txV2.originAmount,\n destAmount: txV2.destAmount,\n originFeeAmount: txV2.originFeeAmount,\n sendChainGas: txV2.zapNative != 0,\n deadline: txV2.deadline,\n nonce: txV2.nonce\n });\n } catch {\n // Fallback to V1 struct.\n return abi.decode(request, (BridgeTransaction));\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function getBridgeTransactionV2(bytes calldata request) external pure returns (BridgeTransactionV2 memory) {\n request.validateV2();\n return BridgeTransactionV2Lib.decodeV2(request);\n }\n\n // ═══════════════════════════════════════ PUBLIC MUTABLE (USER FACING) ════════════════════════════════════════════\n\n /// @inheritdoc IFastBridgeV2\n function bridgeV2(BridgeParams memory params, BridgeParamsV2 memory paramsV2) public payable {\n // If relayer exclusivity is not intended for this bridge, set exclusivityEndTime to static zero.\n // Otherwise, set exclusivity to expire at the current block ts offset by quoteExclusivitySeconds.\n int256 exclusivityEndTime = 0;\n if (paramsV2.quoteRelayer != address(0)) {\n exclusivityEndTime = int256(block.timestamp) + paramsV2.quoteExclusivitySeconds;\n }\n _validateBridgeParams(params, paramsV2, exclusivityEndTime);\n\n // Transfer tokens to bridge contract. We use the actual transferred amount in case of transfer fees.\n uint256 originAmount = _takeBridgedUserAsset(params.originToken, params.originAmount);\n\n // Track the amount of origin token owed to protocol.\n uint256 originFeeAmount = 0;\n if (protocolFeeRate \u003e 0) {\n originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n // The Relayer filling this request will be paid the originAmount after fees.\n // Note: the protocol fees will be accumulated only when the Relayer claims the origin collateral.\n originAmount -= originFeeAmount;\n }\n\n // Hash the bridge request and set the initial status to REQUESTED.\n bytes memory request = BridgeTransactionV2Lib.encodeV2(\n BridgeTransactionV2({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n deadline: params.deadline,\n // Increment the sender's nonce on every bridge.\n nonce: senderNonces[params.sender]++,\n exclusivityRelayer: paramsV2.quoteRelayer,\n // We checked exclusivityEndTime to be in range [0 .. params.deadline] above, so can safely cast.\n exclusivityEndTime: uint256(exclusivityEndTime),\n zapNative: paramsV2.zapNative,\n zapData: paramsV2.zapData\n })\n );\n bytes32 transactionId = keccak256(request);\n // Note: the tx status will be updated throughout the tx lifecycle, while destChainId is set once here.\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n bridgeTxDetails[transactionId].destChainId = params.dstChainId;\n\n emit BridgeRequested({\n transactionId: transactionId,\n sender: params.sender,\n request: request,\n destChainId: params.dstChainId,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n sendChainGas: paramsV2.zapNative != 0\n });\n emit BridgeQuoteDetails(transactionId, paramsV2.quoteId);\n }\n\n /// @inheritdoc IFastBridgeV2\n function cancelV2(bytes calldata request) public {\n // Decode the request and check that it could be cancelled.\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n\n // Can only cancel a REQUESTED transaction after its deadline expires.\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n if ($.status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n\n // Permissionless cancel is only allowed after `cancelDelay` on top of the deadline.\n uint256 deadline = request.deadline();\n if (!hasRole(CANCELER_ROLE, msg.sender)) deadline += cancelDelay;\n if (block.timestamp \u003c= deadline) revert DeadlineNotExceeded();\n\n // Update status to REFUNDED.\n // Note: this is a storage write.\n $.status = BridgeStatus.REFUNDED;\n\n // Return the full amount (collateral + protocol fees) to the original sender.\n // The protocol fees are only accumulated when the transaction is claimed, so we don't need to update them here.\n address to = request.originSender();\n address token = request.originToken();\n uint256 amount = request.originAmount() + request.originFeeAmount();\n\n // Emit the event before any external calls.\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n\n // Return the funds to the original sender as last transaction action.\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(to), amount);\n } else {\n IERC20(token).safeTransfer(to, amount);\n }\n }\n\n // ═══════════════════════════════════════ PUBLIC MUTABLE (AGENT FACING) ═══════════════════════════════════════════\n\n /// @inheritdoc IFastBridgeV2\n function relayV2(bytes calldata request, address relayer) public payable {\n // Decode the request and check that it could be relayed.\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n _validateRelayParams(request, transactionId, relayer);\n\n // Mark the bridge request as relayed by saving the relayer and the block details.\n bridgeRelayDetails[transactionId].blockNumber = uint48(block.number);\n bridgeRelayDetails[transactionId].blockTimestamp = uint48(block.timestamp);\n bridgeRelayDetails[transactionId].relayer = relayer;\n\n // Transfer tokens to recipient on destination chain and trigger Zap if requested.\n address to = request.destRecipient();\n address token = request.destToken();\n uint256 amount = request.destAmount();\n uint256 zapNative = request.zapNative();\n\n // Emit the event before any external calls.\n emit BridgeRelayed({\n transactionId: transactionId,\n relayer: relayer,\n to: to,\n originChainId: request.originChainId(),\n originToken: request.originToken(),\n destToken: token,\n originAmount: request.originAmount(),\n destAmount: amount,\n chainGasAmount: zapNative\n });\n\n // All state changes have been done at this point, can proceed to the external calls.\n // This follows the checks-effects-interactions pattern to mitigate potential reentrancy attacks.\n if (token == NATIVE_GAS_TOKEN) {\n // For the native gas token, additional zapNative is not allowed.\n if (zapNative != 0) revert ZapNativeNotSupported();\n // Check that the correct msg.value was sent.\n if (msg.value != amount) revert MsgValueIncorrect();\n // Don't do a native transfer yet: we will handle it alongside the Zap below.\n } else {\n // For ERC20s, we check that the correct msg.value was sent.\n if (msg.value != zapNative) revert MsgValueIncorrect();\n // We need to transfer the tokens from the Relayer to the recipient first before performing an\n // optional post-transfer Zap.\n IERC20(token).safeTransferFrom(msg.sender, to, amount);\n }\n // At this point we have done:\n // - Transferred the requested amount of ERC20 tokens to the recipient.\n // At this point we have confirmed:\n // - For ERC20s: msg.value matches the requested zapNative amount.\n // - For the native gas token: msg.value matches the requested destAmount.\n // Remaining optional things to do:\n // - Forward the full msg.value to the recipient (if non-zero).\n // - Trigger a Zap (if zapData is present).\n bytes calldata zapData = request.zapData();\n if (zapData.length != 0) {\n // Zap Data is present: Zap has been requested by the recipient. Trigger it forwarding the full msg.value.\n _triggerZapWithChecks({recipient: to, token: token, amount: amount, zapData: zapData});\n // Note: if token has a fee on transfers, the recipient will have received less than `amount`.\n // This is a very niche edge case and should be handled by the recipient contract.\n } else if (msg.value != 0) {\n // Zap Data is missing, but msg.value was sent. This could happen in two different cases:\n // - Relay with the native gas token is happening.\n // - Relay with ERC20 is happening, with a `zapNative \u003e 0` request.\n // In both cases, we need to transfer the full msg.value to the recipient.\n Address.sendValue(payable(to), msg.value);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function proveV2(bytes32 transactionId, bytes32 destTxHash, address relayer) public onlyRole(PROVER_ROLE) {\n // Can only prove a REQUESTED transaction.\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n if ($.status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n\n // Update status to RELAYER_PROVED and store the proof details.\n // Note: these are storage writes.\n $.status = BridgeStatus.RELAYER_PROVED;\n $.proofBlockTimestamp = uint56(block.timestamp);\n $.proofRelayer = relayer;\n\n emit BridgeProofProvided(transactionId, relayer, destTxHash);\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes calldata request, address to) public {\n // Decode the request and check that it could be claimed.\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n\n // Aggregate the read operations from the same storage slot.\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n address proofRelayer = $.proofRelayer;\n BridgeStatus status = $.status;\n uint56 proofBlockTimestamp = $.proofBlockTimestamp;\n\n // Can only claim a RELAYER_PROVED transaction after the dispute period.\n if (status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(proofBlockTimestamp) \u003c= DISPUTE_PERIOD) revert DisputePeriodNotPassed();\n if (to == address(0)) {\n // Anyone could claim the funds to the proven relayer on their behalf.\n to = proofRelayer;\n } else if (proofRelayer != msg.sender) {\n // Only the proven relayer could specify an address to claim the funds to.\n revert SenderIncorrect();\n }\n\n // Update status to RELAYER_CLAIMED and transfer the origin collateral to the specified claim address.\n // Note: this is a storage write.\n $.status = BridgeStatus.RELAYER_CLAIMED;\n\n // Accumulate protocol fees if origin fee amount exists.\n address token = request.originToken();\n uint256 amount = request.originAmount();\n uint256 originFeeAmount = request.originFeeAmount();\n if (originFeeAmount \u003e 0) protocolFees[token] += originFeeAmount;\n\n // Emit the event before any external calls.\n emit BridgeDepositClaimed(transactionId, proofRelayer, to, token, amount);\n\n // Complete the relayer claim as the last transaction action.\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(to), amount);\n } else {\n IERC20(token).safeTransfer(to, amount);\n }\n }\n\n // ═══════════════════════════════════════════════ PUBLIC VIEWS ════════════════════════════════════════════════════\n\n /// @inheritdoc IFastBridgeV2\n function bridgeStatuses(bytes32 transactionId) public view returns (BridgeStatus status) {\n return bridgeTxDetails[transactionId].status;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeProofs(bytes32 transactionId) public view returns (uint96 timestamp, address relayer) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n timestamp = $.proofBlockTimestamp;\n relayer = $.proofRelayer;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeRelays(bytes32 transactionId) public view returns (bool) {\n // This transaction has been relayed if the relayer address is recorded.\n return bridgeRelayDetails[transactionId].relayer != address(0);\n }\n\n // ═════════════════════════════════════════════ INTERNAL METHODS ══════════════════════════════════════════════════\n\n /// @notice Takes the bridged asset from the user into FastBridgeV2 custody. The asset will later be\n /// claimed by the relayer who completed the relay on the destination chain, or returned to the user\n /// via the cancel function if no relay is completed.\n function _takeBridgedUserAsset(address token, uint256 amount) internal returns (uint256 amountTaken) {\n if (token == NATIVE_GAS_TOKEN) {\n // For the native gas token, we just need to check that the supplied msg.value is correct.\n // Supplied `msg.value` is already in FastBridgeV2 custody.\n if (amount != msg.value) revert MsgValueIncorrect();\n amountTaken = msg.value;\n } else {\n // For ERC20s, token is explicitly transferred from the user to FastBridgeV2.\n // We don't allow non-zero `msg.value` to avoid extra funds from being stuck in FastBridgeV2.\n if (msg.value != 0) revert MsgValueIncorrect();\n // Throw an explicit error if the provided token address is not a contract.\n if (token.code.length == 0) revert TokenNotContract();\n\n // Use the balance difference as the amount taken in case of fee on transfer tokens.\n amountTaken = IERC20(token).balanceOf(address(this));\n IERC20(token).safeTransferFrom(msg.sender, address(this), amount);\n amountTaken = IERC20(token).balanceOf(address(this)) - amountTaken;\n }\n }\n\n /// @notice Calls the recipient's hook function with the specified zapData and validates\n /// the returned value.\n function _triggerZapWithChecks(address recipient, address token, uint256 amount, bytes calldata zapData) internal {\n // Call the recipient's hook function with the specified zapData, bubbling any revert messages.\n bytes memory returnData = Address.functionCallWithValue({\n target: recipient,\n data: abi.encodeCall(IZapRecipient.zap, (token, amount, zapData)),\n // Note: see `relay()` for reasoning behind passing msg.value.\n value: msg.value\n });\n\n // Explicit revert if no return data at all.\n if (returnData.length == 0) revert RecipientNoReturnValue();\n // Check that exactly a single return value was returned.\n if (returnData.length != 32) revert RecipientIncorrectReturnValue();\n // Return value should be abi-encoded hook function selector.\n if (bytes32(returnData) != bytes32(IZapRecipient.zap.selector)) {\n revert RecipientIncorrectReturnValue();\n }\n }\n\n /// @notice Calculates the time elapsed since a proof was submitted.\n /// @dev The proof.timestamp stores block timestamps as uint56 for gas optimization.\n /// _timeSince(proof) handles timestamp rollover when block.timestamp \u003e type(uint56).max but\n /// proof.timestamp \u003c type(uint56).max via an unchecked statement.\n /// @param proofBlockTimestamp The block timestamp when the proof was submitted.\n /// @return delta The time elapsed since proof submission.\n function _timeSince(uint56 proofBlockTimestamp) internal view returns (uint256 delta) {\n unchecked {\n delta = uint56(block.timestamp) - proofBlockTimestamp;\n }\n }\n\n /// @notice Validates all parameters required for a bridge transaction.\n /// @dev This function's complexity cannot be reduced due to the number of required checks,\n /// so we disable the code-complexity rule.\n // solhint-disable-next-line code-complexity\n function _validateBridgeParams(\n BridgeParams memory params,\n BridgeParamsV2 memory paramsV2,\n int256 exclusivityEndTime\n )\n internal\n view\n {\n // Check V1 (legacy) params.\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.sender == address(0) || params.to == address(0)) revert ZeroAddress();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n\n // Check V2 params.\n if (paramsV2.zapData.length \u003e MAX_ZAP_DATA_LENGTH) revert ZapDataLengthAboveMax();\n if (paramsV2.zapNative != 0 \u0026\u0026 params.destToken == NATIVE_GAS_TOKEN) {\n revert ZapNativeNotSupported();\n }\n\n // exclusivityEndTime must be in range [0 .. params.deadline].\n if (exclusivityEndTime \u003c 0 || exclusivityEndTime \u003e int256(params.deadline)) {\n revert ExclusivityParamsIncorrect();\n }\n }\n\n /// @notice Validates all parameters required for a relay transaction.\n function _validateRelayParams(bytes calldata request, bytes32 transactionId, address relayer) internal view {\n if (relayer == address(0)) revert ZeroAddress();\n // Check that the transaction has not been relayed yet and is for the current chain.\n if (bridgeRelays(transactionId)) revert TransactionRelayed();\n if (request.destChainId() != block.chainid) revert ChainIncorrect();\n // Check that the deadline for relay to happen has not passed yet.\n if (block.timestamp \u003e request.deadline()) revert DeadlineExceeded();\n // Check the exclusivity period, if it was specified and is still ongoing.\n address exclRelayer = request.exclusivityRelayer();\n if (exclRelayer != address(0) \u0026\u0026 exclRelayer != relayer \u0026\u0026 block.timestamp \u003c= request.exclusivityEndTime()) {\n revert ExclusivityPeriodNotPassed();\n }\n }\n}\n","language":"Solidity","languageVersion":"0.8.24","compilerVersion":"0.8.24","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"","srcMapRuntime":"","abiDefinition":[{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"relayer","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"BridgeDepositClaimed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"BridgeDepositRefunded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"relayer","type":"address"}],"name":"BridgeProofDisputed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"relayer","type":"address"},{"indexed":false,"internalType":"bytes32","name":"transactionHash","type":"bytes32"}],"name":"BridgeProofProvided","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"relayer","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint32","name":"originChainId","type":"uint32"},{"indexed":false,"internalType":"address","name":"originToken","type":"address"},{"indexed":false,"internalType":"address","name":"destToken","type":"address"},{"indexed":false,"internalType":"uint256","name":"originAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"destAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"chainGasAmount","type":"uint256"}],"name":"BridgeRelayed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"bytes","name":"request","type":"bytes"},{"indexed":false,"internalType":"uint32","name":"destChainId","type":"uint32"},{"indexed":false,"internalType":"address","name":"originToken","type":"address"},{"indexed":false,"internalType":"address","name":"destToken","type":"address"},{"indexed":false,"internalType":"uint256","name":"originAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"destAmount","type":"uint256"},{"indexed":false,"internalType":"bool","name":"sendChainGas","type":"bool"}],"name":"BridgeRequested","type":"event"},{"inputs":[{"components":[{"internalType":"uint32","name":"dstChainId","type":"uint32"},{"internalType":"address","name":"sender","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"address","name":"originToken","type":"address"},{"internalType":"address","name":"destToken","type":"address"},{"internalType":"uint256","name":"originAmount","type":"uint256"},{"internalType":"uint256","name":"destAmount","type":"uint256"},{"internalType":"bool","name":"sendChainGas","type":"bool"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"internalType":"struct IFastBridge.BridgeParams","name":"params","type":"tuple"}],"name":"bridge","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"internalType":"address","name":"relayer","type":"address"}],"name":"canClaim","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"},{"internalType":"address","name":"to","type":"address"}],"name":"claim","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"transactionId","type":"bytes32"}],"name":"dispute","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"}],"name":"getBridgeTransaction","outputs":[{"components":[{"internalType":"uint32","name":"originChainId","type":"uint32"},{"internalType":"uint32","name":"destChainId","type":"uint32"},{"internalType":"address","name":"originSender","type":"address"},{"internalType":"address","name":"destRecipient","type":"address"},{"internalType":"address","name":"originToken","type":"address"},{"internalType":"address","name":"destToken","type":"address"},{"internalType":"uint256","name":"originAmount","type":"uint256"},{"internalType":"uint256","name":"destAmount","type":"uint256"},{"internalType":"uint256","name":"originFeeAmount","type":"uint256"},{"internalType":"bool","name":"sendChainGas","type":"bool"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint256","name":"nonce","type":"uint256"}],"internalType":"struct IFastBridge.BridgeTransaction","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"},{"internalType":"bytes32","name":"destTxHash","type":"bytes32"}],"name":"prove","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"}],"name":"refund","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"}],"name":"relay","outputs":[],"stateMutability":"payable","type":"function"}],"userDoc":{"kind":"user","methods":{"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256))":{"notice":"Initiates bridge on origin chain to be relayed by off-chain relayer"},"canClaim(bytes32,address)":{"notice":"Checks if the dispute period has passed so bridge deposit can be claimed"},"claim(bytes,address)":{"notice":"Completes bridge transaction on origin chain by claiming originally deposited capital"},"dispute(bytes32)":{"notice":"Disputes an outstanding proof in case relayer provided dest chain tx is invalid"},"getBridgeTransaction(bytes)":{"notice":"Decodes bridge request into a bridge transaction"},"prove(bytes,bytes32)":{"notice":"Provides proof on origin side that relayer provided funds on destination side of bridge transaction"},"refund(bytes)":{"notice":"Refunds an outstanding bridge transaction in case optimistic bridging failed"},"relay(bytes)":{"notice":"Relays destination side of bridge transaction by off-chain relayer"}},"version":1},"developerDoc":{"kind":"dev","methods":{"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256))":{"params":{"params":"The parameters required to bridge"}},"canClaim(bytes32,address)":{"params":{"relayer":"The address of the relayer attempting to claim","transactionId":"The transaction id associated with the encoded bridge transaction to check"}},"claim(bytes,address)":{"params":{"request":"The encoded bridge transaction to claim on origin chain","to":"The recipient address of the funds"}},"dispute(bytes32)":{"params":{"transactionId":"The transaction id associated with the encoded bridge transaction to dispute"}},"getBridgeTransaction(bytes)":{"params":{"request":"The bridge request to decode"}},"prove(bytes,bytes32)":{"params":{"destTxHash":"The destination tx hash proving bridge transaction was relayed","request":"The encoded bridge transaction to prove on origin chain"}},"refund(bytes)":{"params":{"request":"The encoded bridge transaction to refund"}},"relay(bytes)":{"params":{"request":"The encoded bridge transaction to relay on destination chain"}}},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"BridgeDepositClaimed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"BridgeDepositRefunded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"name\":\"BridgeProofDisputed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"transactionHash\",\"type\":\"bytes32\"}],\"name\":\"BridgeProofProvided\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"originChainId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"chainGasAmount\",\"type\":\"uint256\"}],\"name\":\"BridgeRelayed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"destChainId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"sendChainGas\",\"type\":\"bool\"}],\"name\":\"BridgeRequested\",\"type\":\"event\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"dstChainId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"sendChainGas\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"}],\"internalType\":\"struct IFastBridge.BridgeParams\",\"name\":\"params\",\"type\":\"tuple\"}],\"name\":\"bridge\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"name\":\"canClaim\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"claim\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"}],\"name\":\"dispute\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"getBridgeTransaction\",\"outputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"originChainId\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"destChainId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"originSender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destRecipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"originFeeAmount\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"sendChainGas\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"}],\"internalType\":\"struct IFastBridge.BridgeTransaction\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"},{\"internalType\":\"bytes32\",\"name\":\"destTxHash\",\"type\":\"bytes32\"}],\"name\":\"prove\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"refund\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"relay\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{\"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256))\":{\"params\":{\"params\":\"The parameters required to bridge\"}},\"canClaim(bytes32,address)\":{\"params\":{\"relayer\":\"The address of the relayer attempting to claim\",\"transactionId\":\"The transaction id associated with the encoded bridge transaction to check\"}},\"claim(bytes,address)\":{\"params\":{\"request\":\"The encoded bridge transaction to claim on origin chain\",\"to\":\"The recipient address of the funds\"}},\"dispute(bytes32)\":{\"params\":{\"transactionId\":\"The transaction id associated with the encoded bridge transaction to dispute\"}},\"getBridgeTransaction(bytes)\":{\"params\":{\"request\":\"The bridge request to decode\"}},\"prove(bytes,bytes32)\":{\"params\":{\"destTxHash\":\"The destination tx hash proving bridge transaction was relayed\",\"request\":\"The encoded bridge transaction to prove on origin chain\"}},\"refund(bytes)\":{\"params\":{\"request\":\"The encoded bridge transaction to refund\"}},\"relay(bytes)\":{\"params\":{\"request\":\"The encoded bridge transaction to relay on destination chain\"}}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256))\":{\"notice\":\"Initiates bridge on origin chain to be relayed by off-chain relayer\"},\"canClaim(bytes32,address)\":{\"notice\":\"Checks if the dispute period has passed so bridge deposit can be claimed\"},\"claim(bytes,address)\":{\"notice\":\"Completes bridge transaction on origin chain by claiming originally deposited capital\"},\"dispute(bytes32)\":{\"notice\":\"Disputes an outstanding proof in case relayer provided dest chain tx is invalid\"},\"getBridgeTransaction(bytes)\":{\"notice\":\"Decodes bridge request into a bridge transaction\"},\"prove(bytes,bytes32)\":{\"notice\":\"Provides proof on origin side that relayer provided funds on destination side of bridge transaction\"},\"refund(bytes)\":{\"notice\":\"Refunds an outstanding bridge transaction in case optimistic bridging failed\"},\"relay(bytes)\":{\"notice\":\"Relays destination side of bridge transaction by off-chain relayer\"}},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeV2.sol\":\"IFastBridge\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeV2.sol\":{\"keccak256\":\"0xaab2ee7357681726f0faf799a48ddfbf45fb4da93b69abf61c33dde92b29b74d\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://673391bff9569efc0f9bd99e0e6fece0bc8e8af1f052bb071b407b267a17b3b5\",\"dweb:/ipfs/QmdQQZ6DxpJYhfpinwU5WjLugr2f6qP8h68b5GerhSMQ4j\"]}},\"version\":1}"},"hashes":{"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256))":"45851694","canClaim(bytes32,address)":"aa9641ab","claim(bytes,address)":"41fcb612","dispute(bytes32)":"add98c70","getBridgeTransaction(bytes)":"ac11fb1a","prove(bytes,bytes32)":"886d36ff","refund(bytes)":"5eb7d946","relay(bytes)":"8f0d6f17"}},"solidity/FastBridgeV2.sol:IFastBridgeV2":{"code":"0x","runtime-code":"0x","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.24 ^0.8.20 ^0.8.4;\n\n// contracts/interfaces/IAdminV2.sol\n\ninterface IAdminV2 {\n event CancelDelayUpdated(uint256 oldCancelDelay, uint256 newCancelDelay);\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n /// @notice Allows the governor to set the cancel delay. The cancel delay is the time period after the transaction\n /// deadline during which a transaction can be permissionlessly cancelled if it hasn't been proven by any Relayer.\n function setCancelDelay(uint256 newCancelDelay) external;\n\n /// @notice Allows the governor to set the protocol fee rate. The protocol fee is taken from the origin\n /// amount and is only applied to completed and claimed transactions.\n /// @dev The protocol fee is abstracted away from the relayers; they always operate using the amounts after fees.\n /// The origin amount they see in the emitted log is what they get credited with.\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n /// @notice Allows the governor to withdraw the accumulated protocol fees from the contract.\n function sweepProtocolFees(address token, address recipient) external;\n}\n\n// contracts/interfaces/IAdminV2Errors.sol\n\ninterface IAdminV2Errors {\n error CancelDelayBelowMin();\n error FeeRateAboveMax();\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IFastBridgeV2Errors.sol\n\ninterface IFastBridgeV2Errors {\n error AmountIncorrect();\n error ChainIncorrect();\n error ExclusivityParamsIncorrect();\n error MsgValueIncorrect();\n error SenderIncorrect();\n error StatusIncorrect();\n error TokenNotContract();\n error ZapDataLengthAboveMax();\n error ZapNativeNotSupported();\n error ZeroAddress();\n\n error RecipientIncorrectReturnValue();\n error RecipientNoReturnValue();\n\n error DeadlineExceeded();\n error DeadlineNotExceeded();\n error DeadlineTooShort();\n error DisputePeriodNotPassed();\n error DisputePeriodPassed();\n error ExclusivityPeriodNotPassed();\n\n error TransactionRelayed();\n}\n\n// contracts/interfaces/IMulticallTarget.sol\n\n/// @notice Interface for a contract that supports multiple calls from the same caller. Inspired by MulticallV3:\n/// https://github.com/mds1/multicall/blob/master/src/Multicall3.sol\ninterface IMulticallTarget {\n struct Result {\n bool success;\n bytes returnData;\n }\n\n /// @notice Executes multiple calls to this contract in a single transaction while preserving msg.sender.\n /// Return data from the calls is discarded.\n /// @dev This method is non-payable, so only calls with msg.value of 0 can be batched.\n /// If ignoreReverts is set to true, reverted calls will be skipped.\n /// Otherwise, the entire batch will revert with the original revert reason.\n /// @param data List of ABI-encoded calldata for the calls to execute\n /// @param ignoreReverts Whether to skip calls that revert\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external;\n\n /// @notice Executes multiple calls to this contract in a single transaction while preserving msg.sender.\n /// Return data from each call is preserved.\n /// @dev This method is non-payable, so only calls with msg.value of 0 can be batched.\n /// If ignoreReverts is set to true, reverted calls will be skipped.\n /// Otherwise, the entire batch will revert with the original revert reason.\n /// @param data List of ABI-encoded calldata for the calls to execute\n /// @param ignoreReverts Whether to skip calls that revert\n /// @return results List of results from the calls, each containing (success, returnData)\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results);\n}\n\n// contracts/interfaces/IZapRecipient.sol\n\n/// @notice Interface for contracts that can perform Zap operations. Such contracts could be used as Recipients\n/// in a FastBridge transaction that includes a Zap operation. The Zap Data should include instructions on how\n/// exactly the Zap operation should be executed, which would typically include the target address and calldata\n/// to use. The exact implementation of the Zap Data encoding is up to the Recipient contract.\ninterface IZapRecipient {\n /// @notice Performs a Zap operation with the given token and amount according to the provided Zap data.\n /// @param token The address of the token being used for the Zap operation.\n /// @param amount The amount of tokens to be used.\n /// @param zapData The encoded data specifying how the Zap operation should be executed.\n /// @return The function selector to indicate successful execution.\n function zap(address token, uint256 amount, bytes memory zapData) external payable returns (bytes4);\n}\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// contracts/interfaces/IFastBridgeV2.sol\n\ninterface IFastBridgeV2 is IFastBridge {\n enum BridgeStatus {\n NULL, // Doesn't exist yet.\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n struct BridgeTxDetails {\n BridgeStatus status;\n uint32 destChainId;\n uint56 proofBlockTimestamp;\n address proofRelayer;\n }\n\n struct BridgeRelay {\n uint48 blockNumber;\n uint48 blockTimestamp;\n address relayer;\n }\n\n /// @notice New params introduced in the FastBridgeV2.\n /// We are passing fields from the older BridgeParams struct outside of this struct for backwards compatibility.\n /// Note: quoteRelayer and quoteExclusivitySeconds are either both zero (indicating no exclusivity)\n /// or both non-zero (indicating exclusivity for the given period).\n /// Note: zapNative \u003e 0 can NOT be used with destToken = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE (native token)\n /// @param quoteRelayer Relayer that provided the quote for the transaction\n /// @param quoteExclusivitySeconds Period of time the quote relayer is guaranteed exclusivity after user's deposit\n /// @param quoteId Unique quote identifier used for tracking the quote\n /// @param zapNative ETH value to send to the recipient (if any)\n /// @param zapData Parameters for the Zap to the destination recipient (if any)\n struct BridgeParamsV2 {\n address quoteRelayer;\n int256 quoteExclusivitySeconds;\n bytes quoteId;\n uint256 zapNative;\n bytes zapData;\n }\n\n /// @notice Updated bridge transaction struct to include parameters introduced in FastBridgeV2.\n /// Note: only `exclusivityRelayer` can fill such a transaction until `exclusivityEndTime`.\n struct BridgeTransactionV2 {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n // Note: sendChainGas flag from V1 is deprecated\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n address exclusivityRelayer;\n uint256 exclusivityEndTime;\n uint256 zapNative; // ETH value to send to the recipient (if any)\n bytes zapData; // data to pass for the Zap action (if any)\n }\n\n event BridgeQuoteDetails(bytes32 indexed transactionId, bytes quoteId);\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability\n /// to provide temporary exclusivity fill rights for the quote relayer.\n /// @param params The parameters required to bridge\n /// @param paramsV2 The parameters for exclusivity fill rights (optional, can be left empty)\n function bridgeV2(BridgeParams memory params, BridgeParamsV2 memory paramsV2) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function relayV2(bytes memory request, address relayer) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param transactionId The transaction id associated with the encoded bridge transaction to prove\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function proveV2(bytes32 transactionId, bytes32 destTxHash, address relayer) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital.\n /// @notice Can only send funds to the relayer address on the proof.\n /// @param request The encoded bridge transaction to claim on origin chain\n function claimV2(bytes memory request) external;\n\n /// @notice Cancels an outstanding bridge transaction in case optimistic bridging failed and returns the full amount\n /// to the original sender.\n /// @param request The encoded bridge transaction to refund\n function cancelV2(bytes memory request) external;\n\n /// @notice Checks if a transaction has been relayed\n /// @param transactionId The ID of the transaction to check\n /// @return True if the transaction has been relayed, false otherwise\n function bridgeRelays(bytes32 transactionId) external view returns (bool);\n\n /// @notice Returns the status of a bridge transaction\n /// @param transactionId The ID of the bridge transaction\n /// @return BridgeStatus Status of the bridge transaction\n function bridgeStatuses(bytes32 transactionId) external view returns (BridgeStatus);\n\n /// @notice Returns the timestamp and relayer of a bridge proof\n /// @param transactionId The ID of the bridge transaction\n /// @return timestamp The timestamp of the bridge proof\n /// @return relayer The relayer address of the bridge proof\n function bridgeProofs(bytes32 transactionId) external view returns (uint96 timestamp, address relayer);\n\n /// @notice Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\n /// @param request The bridge request to decode\n function getBridgeTransactionV2(bytes memory request) external view returns (BridgeTransactionV2 memory);\n}\n\n// contracts/utils/MulticallTarget.sol\n\n// solhint-disable avoid-low-level-calls\n/// @notice Abstract contract template that supports batched calls while preserving msg.sender.\n/// Only calls with msg.value of 0 can be batched.\nabstract contract MulticallTarget is IMulticallTarget {\n error MulticallTarget__UndeterminedRevert();\n\n /// @inheritdoc IMulticallTarget\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external {\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\n if (!success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(result);\n }\n }\n }\n\n /// @inheritdoc IMulticallTarget\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results)\n {\n results = new Result[](data.length);\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (results[i].success, results[i].returnData) = address(this).delegatecall(data[i]);\n if (!results[i].success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(results[i].returnData);\n }\n }\n }\n\n /// @dev Bubbles the revert message from the underlying call.\n /// Note: preserves the same custom error or revert string, if one was used.\n /// Source: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v5.0.2/contracts/utils/Address.sol#L143-L158\n function _bubbleRevert(bytes memory returnData) internal pure {\n // Look for revert reason and bubble it up if present\n if (returnData.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n // solhint-disable-next-line no-inline-assembly\n assembly {\n let returndata_size := mload(returnData)\n revert(add(32, returnData), returndata_size)\n }\n } else {\n revert MulticallTarget__UndeterminedRevert();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// contracts/libs/BridgeTransactionV2.sol\n\n// solhint-disable no-inline-assembly\nlibrary BridgeTransactionV2Lib {\n uint16 internal constant VERSION = 2;\n\n // Offsets of the fields in the packed BridgeTransactionV2 struct\n // uint16 version [000 .. 002)\n // uint32 originChainId [002 .. 006)\n // uint32 destChainId [006 .. 010)\n // address originSender [010 .. 030)\n // address destRecipient [030 .. 050)\n // address originToken [050 .. 070)\n // address destToken [070 .. 090)\n // uint256 originAmount [090 .. 122)\n // uint256 destAmount [122 .. 154)\n // uint256 originFeeAmount [154 .. 186)\n // uint256 deadline [186 .. 218)\n // uint256 nonce [218 .. 250)\n // address exclusivityRelayer [250 .. 270)\n // uint256 exclusivityEndTime [270 .. 302)\n // uint256 zapNative [302 .. 334)\n // bytes zapData [334 .. ***)\n\n // forgefmt: disable-start\n uint256 private constant OFFSET_ORIGIN_CHAIN_ID = 2;\n uint256 private constant OFFSET_DEST_CHAIN_ID = 6;\n uint256 private constant OFFSET_ORIGIN_SENDER = 10;\n uint256 private constant OFFSET_DEST_RECIPIENT = 30;\n uint256 private constant OFFSET_ORIGIN_TOKEN = 50;\n uint256 private constant OFFSET_DEST_TOKEN = 70;\n uint256 private constant OFFSET_ORIGIN_AMOUNT = 90;\n uint256 private constant OFFSET_DEST_AMOUNT = 122;\n uint256 private constant OFFSET_ORIGIN_FEE_AMOUNT = 154;\n uint256 private constant OFFSET_DEADLINE = 186;\n uint256 private constant OFFSET_NONCE = 218;\n uint256 private constant OFFSET_EXCLUSIVITY_RELAYER = 250;\n uint256 private constant OFFSET_EXCLUSIVITY_END_TIME = 270;\n uint256 private constant OFFSET_ZAP_NATIVE = 302;\n uint256 private constant OFFSET_ZAP_DATA = 334;\n // forgefmt: disable-end\n\n error BridgeTransactionV2__InvalidEncodedTx();\n error BridgeTransactionV2__UnsupportedVersion(uint16 version);\n\n /// @notice Validates that the encoded transaction is a tightly packed encoded payload for BridgeTransactionV2.\n /// @dev Checks the minimum length and the version, use this function before decoding any of the fields.\n function validateV2(bytes calldata encodedTx) internal pure {\n // Check the minimum length: must at least include all static fields.\n if (encodedTx.length \u003c OFFSET_ZAP_DATA) revert BridgeTransactionV2__InvalidEncodedTx();\n // Once we validated the length, we can be sure that the version field is present.\n uint16 version_ = version(encodedTx);\n if (version_ != VERSION) revert BridgeTransactionV2__UnsupportedVersion(version_);\n }\n\n /// @notice Encodes the BridgeTransactionV2 struct by tightly packing the fields.\n /// @dev `abi.decode` will not work as a result of the tightly packed fields. Use `decodeV2` to decode instead.\n function encodeV2(IFastBridgeV2.BridgeTransactionV2 memory bridgeTx) internal pure returns (bytes memory) {\n // We split the encoding into two parts to avoid stack-too-deep error\n bytes memory firstPart = abi.encodePacked(\n VERSION,\n bridgeTx.originChainId,\n bridgeTx.destChainId,\n bridgeTx.originSender,\n bridgeTx.destRecipient,\n bridgeTx.originToken,\n bridgeTx.destToken,\n bridgeTx.originAmount\n );\n return abi.encodePacked(\n firstPart,\n bridgeTx.destAmount,\n bridgeTx.originFeeAmount,\n // Note: we skip the deprecated `sendChainGas` flag, which was present in BridgeTransaction V1\n bridgeTx.deadline,\n bridgeTx.nonce,\n // New V2 fields: exclusivity\n bridgeTx.exclusivityRelayer,\n bridgeTx.exclusivityEndTime,\n // New V2 fields: Zap\n bridgeTx.zapNative,\n bridgeTx.zapData\n );\n }\n\n /// @notice Decodes the BridgeTransactionV2 struct from the encoded transaction.\n /// @dev Encoded BridgeTransactionV2 struct must be tightly packed.\n /// Use `validateV2` before decoding to ensure the encoded transaction is valid.\n function decodeV2(bytes calldata encodedTx)\n internal\n pure\n returns (IFastBridgeV2.BridgeTransactionV2 memory bridgeTx)\n {\n bridgeTx.originChainId = originChainId(encodedTx);\n bridgeTx.destChainId = destChainId(encodedTx);\n bridgeTx.originSender = originSender(encodedTx);\n bridgeTx.destRecipient = destRecipient(encodedTx);\n bridgeTx.originToken = originToken(encodedTx);\n bridgeTx.destToken = destToken(encodedTx);\n bridgeTx.originAmount = originAmount(encodedTx);\n bridgeTx.destAmount = destAmount(encodedTx);\n bridgeTx.originFeeAmount = originFeeAmount(encodedTx);\n bridgeTx.deadline = deadline(encodedTx);\n bridgeTx.nonce = nonce(encodedTx);\n bridgeTx.exclusivityRelayer = exclusivityRelayer(encodedTx);\n bridgeTx.exclusivityEndTime = exclusivityEndTime(encodedTx);\n bridgeTx.zapNative = zapNative(encodedTx);\n bridgeTx.zapData = zapData(encodedTx);\n }\n\n /// @notice Extracts the version from the encoded transaction.\n function version(bytes calldata encodedTx) internal pure returns (uint16 version_) {\n // Load 32 bytes from the start and shift it 240 bits to the right to get the highest 16 bits.\n assembly {\n version_ := shr(240, calldataload(encodedTx.offset))\n }\n }\n\n /// @notice Extracts the origin chain ID from the encoded transaction.\n function originChainId(bytes calldata encodedTx) internal pure returns (uint32 originChainId_) {\n // Load 32 bytes from the offset and shift it 224 bits to the right to get the highest 32 bits.\n assembly {\n originChainId_ := shr(224, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_CHAIN_ID)))\n }\n }\n\n /// @notice Extracts the destination chain ID from the encoded transaction.\n function destChainId(bytes calldata encodedTx) internal pure returns (uint32 destChainId_) {\n // Load 32 bytes from the offset and shift it 224 bits to the right to get the highest 32 bits.\n assembly {\n destChainId_ := shr(224, calldataload(add(encodedTx.offset, OFFSET_DEST_CHAIN_ID)))\n }\n }\n\n /// @notice Extracts the origin sender from the encoded transaction.\n function originSender(bytes calldata encodedTx) internal pure returns (address originSender_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n originSender_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_SENDER)))\n }\n }\n\n /// @notice Extracts the destination recipient from the encoded transaction.\n function destRecipient(bytes calldata encodedTx) internal pure returns (address destRecipient_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n destRecipient_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_DEST_RECIPIENT)))\n }\n }\n\n /// @notice Extracts the origin token from the encoded transaction.\n function originToken(bytes calldata encodedTx) internal pure returns (address originToken_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n originToken_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_TOKEN)))\n }\n }\n\n /// @notice Extracts the destination token from the encoded transaction.\n function destToken(bytes calldata encodedTx) internal pure returns (address destToken_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n destToken_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_DEST_TOKEN)))\n }\n }\n\n /// @notice Extracts the origin amount from the encoded transaction.\n function originAmount(bytes calldata encodedTx) internal pure returns (uint256 originAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n originAmount_ := calldataload(add(encodedTx.offset, OFFSET_ORIGIN_AMOUNT))\n }\n }\n\n /// @notice Extracts the destination amount from the encoded transaction.\n function destAmount(bytes calldata encodedTx) internal pure returns (uint256 destAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n destAmount_ := calldataload(add(encodedTx.offset, OFFSET_DEST_AMOUNT))\n }\n }\n\n /// @notice Extracts the origin fee amount from the encoded transaction.\n function originFeeAmount(bytes calldata encodedTx) internal pure returns (uint256 originFeeAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n originFeeAmount_ := calldataload(add(encodedTx.offset, OFFSET_ORIGIN_FEE_AMOUNT))\n }\n }\n\n /// @notice Extracts the deadline from the encoded transaction.\n function deadline(bytes calldata encodedTx) internal pure returns (uint256 deadline_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n deadline_ := calldataload(add(encodedTx.offset, OFFSET_DEADLINE))\n }\n }\n\n /// @notice Extracts the nonce from the encoded transaction.\n function nonce(bytes calldata encodedTx) internal pure returns (uint256 nonce_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n nonce_ := calldataload(add(encodedTx.offset, OFFSET_NONCE))\n }\n }\n\n /// @notice Extracts the exclusivity relayer from the encoded transaction.\n function exclusivityRelayer(bytes calldata encodedTx) internal pure returns (address exclusivityRelayer_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n exclusivityRelayer_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_EXCLUSIVITY_RELAYER)))\n }\n }\n\n /// @notice Extracts the exclusivity end time from the encoded transaction.\n function exclusivityEndTime(bytes calldata encodedTx) internal pure returns (uint256 exclusivityEndTime_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n exclusivityEndTime_ := calldataload(add(encodedTx.offset, OFFSET_EXCLUSIVITY_END_TIME))\n }\n }\n\n /// @notice Extracts the Zap's native value from the encoded transaction.\n function zapNative(bytes calldata encodedTx) internal pure returns (uint256 zapNative_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n zapNative_ := calldataload(add(encodedTx.offset, OFFSET_ZAP_NATIVE))\n }\n }\n\n /// @notice Extracts the Zap's data from the encoded transaction.\n function zapData(bytes calldata encodedTx) internal pure returns (bytes calldata zapData_) {\n zapData_ = encodedTx[OFFSET_ZAP_DATA:];\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/AdminV2.sol\n\n// ════════════════════════════════════════════════ INTERFACES ═════════════════════════════════════════════════════\n\n// ═════════════════════════════════════════════ EXTERNAL IMPORTS ══════════════════════════════════════════════════\n\n/// @title AdminV2\n/// @notice Provides administrative functions and controls for managing the FastBridgeV2 contract,\n/// including access control and configuration settings.\ncontract AdminV2 is AccessControlEnumerable, IAdminV2, IAdminV2Errors {\n using SafeERC20 for IERC20;\n\n /// @notice The address reserved for the native gas token (ETH on Ethereum and most L2s, AVAX on Avalanche, etc.).\n address public constant NATIVE_GAS_TOKEN = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice The role identifier for the Quoter API's off-chain authentication.\n /// @dev Only addresses with this role can post FastBridge quotes to the API.\n bytes32 public constant QUOTER_ROLE = keccak256(\"QUOTER_ROLE\");\n\n /// @notice The role identifier for the Prover's on-chain authentication in FastBridge.\n /// @dev Only addresses with this role can provide proofs that a FastBridge request has been relayed.\n bytes32 public constant PROVER_ROLE = keccak256(\"PROVER_ROLE\");\n\n /// @notice The role identifier for the Guard's on-chain authentication in FastBridge.\n /// @dev Only addresses with this role can dispute submitted relay proofs during the dispute period.\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n\n /// @notice The role identifier for the Canceler's on-chain authentication in FastBridge.\n /// @dev Only addresses with this role can cancel a FastBridge transaction without the cancel delay.\n bytes32 public constant CANCELER_ROLE = keccak256(\"CANCELER_ROLE\");\n\n /// @notice The role identifier for the Governor's on-chain administrative authority.\n /// @dev Only addresses with this role can perform administrative tasks within the contract.\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n /// @notice The denominator for fee rates, representing 100%.\n uint256 public constant FEE_BPS = 1e6;\n /// @notice The maximum protocol fee rate: 1% of the origin amount.\n uint256 public constant FEE_RATE_MAX = 0.01e6;\n\n /// @notice The minimum cancel delay that can be set by the governor.\n uint256 public constant MIN_CANCEL_DELAY = 1 hours;\n /// @notice The default cancel delay set during contract deployment.\n uint256 public constant DEFAULT_CANCEL_DELAY = 1 days;\n\n /// @notice The protocol fee rate taken on the origin amount deposited in the origin chain.\n uint256 public protocolFeeRate;\n\n /// @notice The accumulated protocol fee amounts.\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice The delay period after which a transaction can be permissionlessly cancelled.\n uint256 public cancelDelay;\n\n /// @notice This variable is deprecated and should not be used.\n /// @dev Use ZapNative V2 requests instead.\n uint256 public immutable chainGasAmount = 0;\n\n constructor(address defaultAdmin) {\n _grantRole(DEFAULT_ADMIN_ROLE, defaultAdmin);\n _setCancelDelay(DEFAULT_CANCEL_DELAY);\n }\n\n /// @inheritdoc IAdminV2\n function setCancelDelay(uint256 newCancelDelay) external onlyRole(GOVERNOR_ROLE) {\n _setCancelDelay(newCancelDelay);\n }\n\n /// @inheritdoc IAdminV2\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n if (newFeeRate \u003e FEE_RATE_MAX) revert FeeRateAboveMax();\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n /// @inheritdoc IAdminV2\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n // Early exit if no accumulated fees.\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return;\n // Reset the accumulated fees first.\n protocolFees[token] = 0;\n emit FeesSwept(token, recipient, feeAmount);\n // Sweep the fees as the last transaction action.\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(recipient), feeAmount);\n } else {\n IERC20(token).safeTransfer(recipient, feeAmount);\n }\n }\n\n /// @notice Internal logic to set the cancel delay. Security checks are performed outside of this function.\n /// @dev This function is marked as private to prevent child contracts from calling it directly.\n function _setCancelDelay(uint256 newCancelDelay) private {\n if (newCancelDelay \u003c MIN_CANCEL_DELAY) revert CancelDelayBelowMin();\n uint256 oldCancelDelay = cancelDelay;\n cancelDelay = newCancelDelay;\n emit CancelDelayUpdated(oldCancelDelay, newCancelDelay);\n }\n}\n\n// contracts/FastBridgeV2.sol\n\n// ════════════════════════════════════════════════ INTERFACES ═════════════════════════════════════════════════════\n\n// ═════════════════════════════════════════════ INTERNAL IMPORTS ══════════════════════════════════════════════════\n\n// ═════════════════════════════════════════════ EXTERNAL IMPORTS ══════════════════════════════════════════════════\n\n/// @title FastBridgeV2\n/// @notice Core component of the SynapseRFQ protocol, enabling Relayers (Solvers) to fulfill bridge requests.\n/// Supports ERC20 and native gas tokens, along with the Zap feature for executing actions on the destination chain.\n/// Users interact with the off-chain Quoter API to obtain a current quote for a bridge transaction.\n/// They then submit the bridge request with the quote to this contract, depositing their assets in escrow.\n/// Relayers can fulfill requests by relaying them to the destination chain and must prove fulfillment to claim funds.\n/// Guards monitor proofs and can dispute discrepancies.\n/// Users can reclaim funds by cancelling their requests if it has not been fulfilled within the specified deadline.\ncontract FastBridgeV2 is AdminV2, MulticallTarget, IFastBridgeV2, IFastBridgeV2Errors {\n using BridgeTransactionV2Lib for bytes;\n using SafeERC20 for IERC20;\n\n /// @notice The duration of the dispute period for relayed transactions.\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice The minimum required time between transaction request and deadline.\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n /// @notice The maximum allowed length for zapData.\n uint256 public constant MAX_ZAP_DATA_LENGTH = 2 ** 16 - 1;\n\n /// @notice Maps transaction IDs to bridge details (status, destination chain ID, proof timestamp, and relayer).\n /// Note: this is only stored for transactions having local chain as the origin chain.\n mapping(bytes32 =\u003e BridgeTxDetails) public bridgeTxDetails;\n /// @notice Maps transaction IDs to relay details (block number, block timestamp, and relayer).\n /// Note: this is only stored for transactions having local chain as the destination chain.\n mapping(bytes32 =\u003e BridgeRelay) public bridgeRelayDetails;\n /// @notice Maps sender addresses to their unique bridge nonce.\n mapping(address =\u003e uint256) public senderNonces;\n\n /// @notice This variable is deprecated and should not be used.\n /// @dev Replaced by senderNonces.\n uint256 public immutable nonce = 0;\n /// @notice The block number at which this contract was deployed.\n uint256 public immutable deployBlock;\n\n /// @notice Initializes the FastBridgeV2 contract with the provided default admin,\n /// sets the default cancel delay, and records the deploy block number.\n constructor(address defaultAdmin) AdminV2(defaultAdmin) {\n deployBlock = block.number;\n }\n\n // ══════════════════════════════════════ EXTERNAL MUTABLE (USER FACING) ═══════════════════════════════════════════\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n bridgeV2({\n params: params,\n paramsV2: BridgeParamsV2({\n quoteRelayer: address(0),\n quoteExclusivitySeconds: 0,\n quoteId: bytes(\"\"),\n zapNative: 0,\n zapData: bytes(\"\")\n })\n });\n }\n\n /// Note: this function is deprecated and will be removed in a future version.\n /// @dev Replaced by `cancel`.\n /// @inheritdoc IFastBridge\n function refund(bytes calldata request) external {\n cancelV2(request);\n }\n\n // ══════════════════════════════════════ EXTERNAL MUTABLE (AGENT FACING) ══════════════════════════════════════════\n\n /// @inheritdoc IFastBridge\n function relay(bytes calldata request) external payable {\n // `relay` override will validate the request.\n relayV2({request: request, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes calldata request, bytes32 destTxHash) external {\n request.validateV2();\n proveV2({transactionId: keccak256(request), destTxHash: destTxHash, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridgeV2\n function claimV2(bytes calldata request) external {\n // `claim` override will validate the request.\n claim({request: request, to: address(0)});\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n // Aggregate the read operations from the same storage slot.\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n address disputedRelayer = $.proofRelayer;\n BridgeStatus status = $.status;\n uint56 proofBlockTimestamp = $.proofBlockTimestamp;\n\n // Can only dispute a RELAYER_PROVED transaction within the dispute period.\n if (status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(proofBlockTimestamp) \u003e DISPUTE_PERIOD) {\n revert DisputePeriodPassed();\n }\n\n // Update status to REQUESTED and delete the disputed proof details.\n // Note: these are storage writes.\n $.status = BridgeStatus.REQUESTED;\n $.proofRelayer = address(0);\n $.proofBlockTimestamp = 0;\n\n emit BridgeProofDisputed(transactionId, disputedRelayer);\n }\n\n // ══════════════════════════════════════════════ EXTERNAL VIEWS ═══════════════════════════════════════════════════\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n // The correct relayer can only claim a RELAYER_PROVED transaction after the dispute period.\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n if ($.status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if ($.proofRelayer != relayer) revert SenderIncorrect();\n\n return _timeSince($.proofBlockTimestamp) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n /// @dev This method is added to achieve backwards compatibility with decoding requests into V1 structs:\n /// - `zapNative` is partially reported as a zero/non-zero flag\n /// - `zapData` is ignored\n /// In order to process all kinds of requests use getBridgeTransactionV2 instead.\n function getBridgeTransaction(bytes calldata request) external view returns (BridgeTransaction memory) {\n // Try decoding into V2 struct first. This will revert if V1 struct is passed.\n try this.getBridgeTransactionV2(request) returns (BridgeTransactionV2 memory txV2) {\n // Note: we entirely ignore the zapData field, as it was not present in V1.\n return BridgeTransaction({\n originChainId: txV2.originChainId,\n destChainId: txV2.destChainId,\n originSender: txV2.originSender,\n destRecipient: txV2.destRecipient,\n originToken: txV2.originToken,\n destToken: txV2.destToken,\n originAmount: txV2.originAmount,\n destAmount: txV2.destAmount,\n originFeeAmount: txV2.originFeeAmount,\n sendChainGas: txV2.zapNative != 0,\n deadline: txV2.deadline,\n nonce: txV2.nonce\n });\n } catch {\n // Fallback to V1 struct.\n return abi.decode(request, (BridgeTransaction));\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function getBridgeTransactionV2(bytes calldata request) external pure returns (BridgeTransactionV2 memory) {\n request.validateV2();\n return BridgeTransactionV2Lib.decodeV2(request);\n }\n\n // ═══════════════════════════════════════ PUBLIC MUTABLE (USER FACING) ════════════════════════════════════════════\n\n /// @inheritdoc IFastBridgeV2\n function bridgeV2(BridgeParams memory params, BridgeParamsV2 memory paramsV2) public payable {\n // If relayer exclusivity is not intended for this bridge, set exclusivityEndTime to static zero.\n // Otherwise, set exclusivity to expire at the current block ts offset by quoteExclusivitySeconds.\n int256 exclusivityEndTime = 0;\n if (paramsV2.quoteRelayer != address(0)) {\n exclusivityEndTime = int256(block.timestamp) + paramsV2.quoteExclusivitySeconds;\n }\n _validateBridgeParams(params, paramsV2, exclusivityEndTime);\n\n // Transfer tokens to bridge contract. We use the actual transferred amount in case of transfer fees.\n uint256 originAmount = _takeBridgedUserAsset(params.originToken, params.originAmount);\n\n // Track the amount of origin token owed to protocol.\n uint256 originFeeAmount = 0;\n if (protocolFeeRate \u003e 0) {\n originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n // The Relayer filling this request will be paid the originAmount after fees.\n // Note: the protocol fees will be accumulated only when the Relayer claims the origin collateral.\n originAmount -= originFeeAmount;\n }\n\n // Hash the bridge request and set the initial status to REQUESTED.\n bytes memory request = BridgeTransactionV2Lib.encodeV2(\n BridgeTransactionV2({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n deadline: params.deadline,\n // Increment the sender's nonce on every bridge.\n nonce: senderNonces[params.sender]++,\n exclusivityRelayer: paramsV2.quoteRelayer,\n // We checked exclusivityEndTime to be in range [0 .. params.deadline] above, so can safely cast.\n exclusivityEndTime: uint256(exclusivityEndTime),\n zapNative: paramsV2.zapNative,\n zapData: paramsV2.zapData\n })\n );\n bytes32 transactionId = keccak256(request);\n // Note: the tx status will be updated throughout the tx lifecycle, while destChainId is set once here.\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n bridgeTxDetails[transactionId].destChainId = params.dstChainId;\n\n emit BridgeRequested({\n transactionId: transactionId,\n sender: params.sender,\n request: request,\n destChainId: params.dstChainId,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n sendChainGas: paramsV2.zapNative != 0\n });\n emit BridgeQuoteDetails(transactionId, paramsV2.quoteId);\n }\n\n /// @inheritdoc IFastBridgeV2\n function cancelV2(bytes calldata request) public {\n // Decode the request and check that it could be cancelled.\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n\n // Can only cancel a REQUESTED transaction after its deadline expires.\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n if ($.status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n\n // Permissionless cancel is only allowed after `cancelDelay` on top of the deadline.\n uint256 deadline = request.deadline();\n if (!hasRole(CANCELER_ROLE, msg.sender)) deadline += cancelDelay;\n if (block.timestamp \u003c= deadline) revert DeadlineNotExceeded();\n\n // Update status to REFUNDED.\n // Note: this is a storage write.\n $.status = BridgeStatus.REFUNDED;\n\n // Return the full amount (collateral + protocol fees) to the original sender.\n // The protocol fees are only accumulated when the transaction is claimed, so we don't need to update them here.\n address to = request.originSender();\n address token = request.originToken();\n uint256 amount = request.originAmount() + request.originFeeAmount();\n\n // Emit the event before any external calls.\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n\n // Return the funds to the original sender as last transaction action.\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(to), amount);\n } else {\n IERC20(token).safeTransfer(to, amount);\n }\n }\n\n // ═══════════════════════════════════════ PUBLIC MUTABLE (AGENT FACING) ═══════════════════════════════════════════\n\n /// @inheritdoc IFastBridgeV2\n function relayV2(bytes calldata request, address relayer) public payable {\n // Decode the request and check that it could be relayed.\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n _validateRelayParams(request, transactionId, relayer);\n\n // Mark the bridge request as relayed by saving the relayer and the block details.\n bridgeRelayDetails[transactionId].blockNumber = uint48(block.number);\n bridgeRelayDetails[transactionId].blockTimestamp = uint48(block.timestamp);\n bridgeRelayDetails[transactionId].relayer = relayer;\n\n // Transfer tokens to recipient on destination chain and trigger Zap if requested.\n address to = request.destRecipient();\n address token = request.destToken();\n uint256 amount = request.destAmount();\n uint256 zapNative = request.zapNative();\n\n // Emit the event before any external calls.\n emit BridgeRelayed({\n transactionId: transactionId,\n relayer: relayer,\n to: to,\n originChainId: request.originChainId(),\n originToken: request.originToken(),\n destToken: token,\n originAmount: request.originAmount(),\n destAmount: amount,\n chainGasAmount: zapNative\n });\n\n // All state changes have been done at this point, can proceed to the external calls.\n // This follows the checks-effects-interactions pattern to mitigate potential reentrancy attacks.\n if (token == NATIVE_GAS_TOKEN) {\n // For the native gas token, additional zapNative is not allowed.\n if (zapNative != 0) revert ZapNativeNotSupported();\n // Check that the correct msg.value was sent.\n if (msg.value != amount) revert MsgValueIncorrect();\n // Don't do a native transfer yet: we will handle it alongside the Zap below.\n } else {\n // For ERC20s, we check that the correct msg.value was sent.\n if (msg.value != zapNative) revert MsgValueIncorrect();\n // We need to transfer the tokens from the Relayer to the recipient first before performing an\n // optional post-transfer Zap.\n IERC20(token).safeTransferFrom(msg.sender, to, amount);\n }\n // At this point we have done:\n // - Transferred the requested amount of ERC20 tokens to the recipient.\n // At this point we have confirmed:\n // - For ERC20s: msg.value matches the requested zapNative amount.\n // - For the native gas token: msg.value matches the requested destAmount.\n // Remaining optional things to do:\n // - Forward the full msg.value to the recipient (if non-zero).\n // - Trigger a Zap (if zapData is present).\n bytes calldata zapData = request.zapData();\n if (zapData.length != 0) {\n // Zap Data is present: Zap has been requested by the recipient. Trigger it forwarding the full msg.value.\n _triggerZapWithChecks({recipient: to, token: token, amount: amount, zapData: zapData});\n // Note: if token has a fee on transfers, the recipient will have received less than `amount`.\n // This is a very niche edge case and should be handled by the recipient contract.\n } else if (msg.value != 0) {\n // Zap Data is missing, but msg.value was sent. This could happen in two different cases:\n // - Relay with the native gas token is happening.\n // - Relay with ERC20 is happening, with a `zapNative \u003e 0` request.\n // In both cases, we need to transfer the full msg.value to the recipient.\n Address.sendValue(payable(to), msg.value);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function proveV2(bytes32 transactionId, bytes32 destTxHash, address relayer) public onlyRole(PROVER_ROLE) {\n // Can only prove a REQUESTED transaction.\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n if ($.status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n\n // Update status to RELAYER_PROVED and store the proof details.\n // Note: these are storage writes.\n $.status = BridgeStatus.RELAYER_PROVED;\n $.proofBlockTimestamp = uint56(block.timestamp);\n $.proofRelayer = relayer;\n\n emit BridgeProofProvided(transactionId, relayer, destTxHash);\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes calldata request, address to) public {\n // Decode the request and check that it could be claimed.\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n\n // Aggregate the read operations from the same storage slot.\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n address proofRelayer = $.proofRelayer;\n BridgeStatus status = $.status;\n uint56 proofBlockTimestamp = $.proofBlockTimestamp;\n\n // Can only claim a RELAYER_PROVED transaction after the dispute period.\n if (status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(proofBlockTimestamp) \u003c= DISPUTE_PERIOD) revert DisputePeriodNotPassed();\n if (to == address(0)) {\n // Anyone could claim the funds to the proven relayer on their behalf.\n to = proofRelayer;\n } else if (proofRelayer != msg.sender) {\n // Only the proven relayer could specify an address to claim the funds to.\n revert SenderIncorrect();\n }\n\n // Update status to RELAYER_CLAIMED and transfer the origin collateral to the specified claim address.\n // Note: this is a storage write.\n $.status = BridgeStatus.RELAYER_CLAIMED;\n\n // Accumulate protocol fees if origin fee amount exists.\n address token = request.originToken();\n uint256 amount = request.originAmount();\n uint256 originFeeAmount = request.originFeeAmount();\n if (originFeeAmount \u003e 0) protocolFees[token] += originFeeAmount;\n\n // Emit the event before any external calls.\n emit BridgeDepositClaimed(transactionId, proofRelayer, to, token, amount);\n\n // Complete the relayer claim as the last transaction action.\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(to), amount);\n } else {\n IERC20(token).safeTransfer(to, amount);\n }\n }\n\n // ═══════════════════════════════════════════════ PUBLIC VIEWS ════════════════════════════════════════════════════\n\n /// @inheritdoc IFastBridgeV2\n function bridgeStatuses(bytes32 transactionId) public view returns (BridgeStatus status) {\n return bridgeTxDetails[transactionId].status;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeProofs(bytes32 transactionId) public view returns (uint96 timestamp, address relayer) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n timestamp = $.proofBlockTimestamp;\n relayer = $.proofRelayer;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeRelays(bytes32 transactionId) public view returns (bool) {\n // This transaction has been relayed if the relayer address is recorded.\n return bridgeRelayDetails[transactionId].relayer != address(0);\n }\n\n // ═════════════════════════════════════════════ INTERNAL METHODS ══════════════════════════════════════════════════\n\n /// @notice Takes the bridged asset from the user into FastBridgeV2 custody. The asset will later be\n /// claimed by the relayer who completed the relay on the destination chain, or returned to the user\n /// via the cancel function if no relay is completed.\n function _takeBridgedUserAsset(address token, uint256 amount) internal returns (uint256 amountTaken) {\n if (token == NATIVE_GAS_TOKEN) {\n // For the native gas token, we just need to check that the supplied msg.value is correct.\n // Supplied `msg.value` is already in FastBridgeV2 custody.\n if (amount != msg.value) revert MsgValueIncorrect();\n amountTaken = msg.value;\n } else {\n // For ERC20s, token is explicitly transferred from the user to FastBridgeV2.\n // We don't allow non-zero `msg.value` to avoid extra funds from being stuck in FastBridgeV2.\n if (msg.value != 0) revert MsgValueIncorrect();\n // Throw an explicit error if the provided token address is not a contract.\n if (token.code.length == 0) revert TokenNotContract();\n\n // Use the balance difference as the amount taken in case of fee on transfer tokens.\n amountTaken = IERC20(token).balanceOf(address(this));\n IERC20(token).safeTransferFrom(msg.sender, address(this), amount);\n amountTaken = IERC20(token).balanceOf(address(this)) - amountTaken;\n }\n }\n\n /// @notice Calls the recipient's hook function with the specified zapData and validates\n /// the returned value.\n function _triggerZapWithChecks(address recipient, address token, uint256 amount, bytes calldata zapData) internal {\n // Call the recipient's hook function with the specified zapData, bubbling any revert messages.\n bytes memory returnData = Address.functionCallWithValue({\n target: recipient,\n data: abi.encodeCall(IZapRecipient.zap, (token, amount, zapData)),\n // Note: see `relay()` for reasoning behind passing msg.value.\n value: msg.value\n });\n\n // Explicit revert if no return data at all.\n if (returnData.length == 0) revert RecipientNoReturnValue();\n // Check that exactly a single return value was returned.\n if (returnData.length != 32) revert RecipientIncorrectReturnValue();\n // Return value should be abi-encoded hook function selector.\n if (bytes32(returnData) != bytes32(IZapRecipient.zap.selector)) {\n revert RecipientIncorrectReturnValue();\n }\n }\n\n /// @notice Calculates the time elapsed since a proof was submitted.\n /// @dev The proof.timestamp stores block timestamps as uint56 for gas optimization.\n /// _timeSince(proof) handles timestamp rollover when block.timestamp \u003e type(uint56).max but\n /// proof.timestamp \u003c type(uint56).max via an unchecked statement.\n /// @param proofBlockTimestamp The block timestamp when the proof was submitted.\n /// @return delta The time elapsed since proof submission.\n function _timeSince(uint56 proofBlockTimestamp) internal view returns (uint256 delta) {\n unchecked {\n delta = uint56(block.timestamp) - proofBlockTimestamp;\n }\n }\n\n /// @notice Validates all parameters required for a bridge transaction.\n /// @dev This function's complexity cannot be reduced due to the number of required checks,\n /// so we disable the code-complexity rule.\n // solhint-disable-next-line code-complexity\n function _validateBridgeParams(\n BridgeParams memory params,\n BridgeParamsV2 memory paramsV2,\n int256 exclusivityEndTime\n )\n internal\n view\n {\n // Check V1 (legacy) params.\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.sender == address(0) || params.to == address(0)) revert ZeroAddress();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n\n // Check V2 params.\n if (paramsV2.zapData.length \u003e MAX_ZAP_DATA_LENGTH) revert ZapDataLengthAboveMax();\n if (paramsV2.zapNative != 0 \u0026\u0026 params.destToken == NATIVE_GAS_TOKEN) {\n revert ZapNativeNotSupported();\n }\n\n // exclusivityEndTime must be in range [0 .. params.deadline].\n if (exclusivityEndTime \u003c 0 || exclusivityEndTime \u003e int256(params.deadline)) {\n revert ExclusivityParamsIncorrect();\n }\n }\n\n /// @notice Validates all parameters required for a relay transaction.\n function _validateRelayParams(bytes calldata request, bytes32 transactionId, address relayer) internal view {\n if (relayer == address(0)) revert ZeroAddress();\n // Check that the transaction has not been relayed yet and is for the current chain.\n if (bridgeRelays(transactionId)) revert TransactionRelayed();\n if (request.destChainId() != block.chainid) revert ChainIncorrect();\n // Check that the deadline for relay to happen has not passed yet.\n if (block.timestamp \u003e request.deadline()) revert DeadlineExceeded();\n // Check the exclusivity period, if it was specified and is still ongoing.\n address exclRelayer = request.exclusivityRelayer();\n if (exclRelayer != address(0) \u0026\u0026 exclRelayer != relayer \u0026\u0026 block.timestamp \u003c= request.exclusivityEndTime()) {\n revert ExclusivityPeriodNotPassed();\n }\n }\n}\n","language":"Solidity","languageVersion":"0.8.24","compilerVersion":"0.8.24","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"","srcMapRuntime":"","abiDefinition":[{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"relayer","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"BridgeDepositClaimed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"BridgeDepositRefunded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"relayer","type":"address"}],"name":"BridgeProofDisputed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"relayer","type":"address"},{"indexed":false,"internalType":"bytes32","name":"transactionHash","type":"bytes32"}],"name":"BridgeProofProvided","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":false,"internalType":"bytes","name":"quoteId","type":"bytes"}],"name":"BridgeQuoteDetails","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"relayer","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint32","name":"originChainId","type":"uint32"},{"indexed":false,"internalType":"address","name":"originToken","type":"address"},{"indexed":false,"internalType":"address","name":"destToken","type":"address"},{"indexed":false,"internalType":"uint256","name":"originAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"destAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"chainGasAmount","type":"uint256"}],"name":"BridgeRelayed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"bytes","name":"request","type":"bytes"},{"indexed":false,"internalType":"uint32","name":"destChainId","type":"uint32"},{"indexed":false,"internalType":"address","name":"originToken","type":"address"},{"indexed":false,"internalType":"address","name":"destToken","type":"address"},{"indexed":false,"internalType":"uint256","name":"originAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"destAmount","type":"uint256"},{"indexed":false,"internalType":"bool","name":"sendChainGas","type":"bool"}],"name":"BridgeRequested","type":"event"},{"inputs":[{"components":[{"internalType":"uint32","name":"dstChainId","type":"uint32"},{"internalType":"address","name":"sender","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"address","name":"originToken","type":"address"},{"internalType":"address","name":"destToken","type":"address"},{"internalType":"uint256","name":"originAmount","type":"uint256"},{"internalType":"uint256","name":"destAmount","type":"uint256"},{"internalType":"bool","name":"sendChainGas","type":"bool"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"internalType":"struct IFastBridge.BridgeParams","name":"params","type":"tuple"}],"name":"bridge","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"transactionId","type":"bytes32"}],"name":"bridgeProofs","outputs":[{"internalType":"uint96","name":"timestamp","type":"uint96"},{"internalType":"address","name":"relayer","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"transactionId","type":"bytes32"}],"name":"bridgeRelays","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"transactionId","type":"bytes32"}],"name":"bridgeStatuses","outputs":[{"internalType":"enum IFastBridgeV2.BridgeStatus","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"uint32","name":"dstChainId","type":"uint32"},{"internalType":"address","name":"sender","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"address","name":"originToken","type":"address"},{"internalType":"address","name":"destToken","type":"address"},{"internalType":"uint256","name":"originAmount","type":"uint256"},{"internalType":"uint256","name":"destAmount","type":"uint256"},{"internalType":"bool","name":"sendChainGas","type":"bool"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"internalType":"struct IFastBridge.BridgeParams","name":"params","type":"tuple"},{"components":[{"internalType":"address","name":"quoteRelayer","type":"address"},{"internalType":"int256","name":"quoteExclusivitySeconds","type":"int256"},{"internalType":"bytes","name":"quoteId","type":"bytes"},{"internalType":"uint256","name":"zapNative","type":"uint256"},{"internalType":"bytes","name":"zapData","type":"bytes"}],"internalType":"struct IFastBridgeV2.BridgeParamsV2","name":"paramsV2","type":"tuple"}],"name":"bridgeV2","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"internalType":"address","name":"relayer","type":"address"}],"name":"canClaim","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"}],"name":"cancelV2","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"},{"internalType":"address","name":"to","type":"address"}],"name":"claim","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"}],"name":"claimV2","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"transactionId","type":"bytes32"}],"name":"dispute","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"}],"name":"getBridgeTransaction","outputs":[{"components":[{"internalType":"uint32","name":"originChainId","type":"uint32"},{"internalType":"uint32","name":"destChainId","type":"uint32"},{"internalType":"address","name":"originSender","type":"address"},{"internalType":"address","name":"destRecipient","type":"address"},{"internalType":"address","name":"originToken","type":"address"},{"internalType":"address","name":"destToken","type":"address"},{"internalType":"uint256","name":"originAmount","type":"uint256"},{"internalType":"uint256","name":"destAmount","type":"uint256"},{"internalType":"uint256","name":"originFeeAmount","type":"uint256"},{"internalType":"bool","name":"sendChainGas","type":"bool"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint256","name":"nonce","type":"uint256"}],"internalType":"struct IFastBridge.BridgeTransaction","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"}],"name":"getBridgeTransactionV2","outputs":[{"components":[{"internalType":"uint32","name":"originChainId","type":"uint32"},{"internalType":"uint32","name":"destChainId","type":"uint32"},{"internalType":"address","name":"originSender","type":"address"},{"internalType":"address","name":"destRecipient","type":"address"},{"internalType":"address","name":"originToken","type":"address"},{"internalType":"address","name":"destToken","type":"address"},{"internalType":"uint256","name":"originAmount","type":"uint256"},{"internalType":"uint256","name":"destAmount","type":"uint256"},{"internalType":"uint256","name":"originFeeAmount","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"address","name":"exclusivityRelayer","type":"address"},{"internalType":"uint256","name":"exclusivityEndTime","type":"uint256"},{"internalType":"uint256","name":"zapNative","type":"uint256"},{"internalType":"bytes","name":"zapData","type":"bytes"}],"internalType":"struct IFastBridgeV2.BridgeTransactionV2","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"},{"internalType":"bytes32","name":"destTxHash","type":"bytes32"}],"name":"prove","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"internalType":"bytes32","name":"destTxHash","type":"bytes32"},{"internalType":"address","name":"relayer","type":"address"}],"name":"proveV2","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"}],"name":"refund","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"}],"name":"relay","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"},{"internalType":"address","name":"relayer","type":"address"}],"name":"relayV2","outputs":[],"stateMutability":"payable","type":"function"}],"userDoc":{"kind":"user","methods":{"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256))":{"notice":"Initiates bridge on origin chain to be relayed by off-chain relayer"},"bridgeProofs(bytes32)":{"notice":"Returns the timestamp and relayer of a bridge proof"},"bridgeRelays(bytes32)":{"notice":"Checks if a transaction has been relayed"},"bridgeStatuses(bytes32)":{"notice":"Returns the status of a bridge transaction"},"bridgeV2((uint32,address,address,address,address,uint256,uint256,bool,uint256),(address,int256,bytes,uint256,bytes))":{"notice":"Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability to provide temporary exclusivity fill rights for the quote relayer."},"canClaim(bytes32,address)":{"notice":"Checks if the dispute period has passed so bridge deposit can be claimed"},"cancelV2(bytes)":{"notice":"Cancels an outstanding bridge transaction in case optimistic bridging failed and returns the full amount to the original sender."},"claim(bytes,address)":{"notice":"Completes bridge transaction on origin chain by claiming originally deposited capital"},"claimV2(bytes)":{"notice":"Completes bridge transaction on origin chain by claiming originally deposited capital.Can only send funds to the relayer address on the proof."},"dispute(bytes32)":{"notice":"Disputes an outstanding proof in case relayer provided dest chain tx is invalid"},"getBridgeTransaction(bytes)":{"notice":"Decodes bridge request into a bridge transaction"},"getBridgeTransactionV2(bytes)":{"notice":"Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2"},"prove(bytes,bytes32)":{"notice":"Provides proof on origin side that relayer provided funds on destination side of bridge transaction"},"proveV2(bytes32,bytes32,address)":{"notice":"Provides proof on origin side that relayer provided funds on destination side of bridge transaction"},"refund(bytes)":{"notice":"Refunds an outstanding bridge transaction in case optimistic bridging failed"},"relay(bytes)":{"notice":"Relays destination side of bridge transaction by off-chain relayer"},"relayV2(bytes,address)":{"notice":"Relays destination side of bridge transaction by off-chain relayer"}},"version":1},"developerDoc":{"kind":"dev","methods":{"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256))":{"params":{"params":"The parameters required to bridge"}},"bridgeProofs(bytes32)":{"params":{"transactionId":"The ID of the bridge transaction"},"returns":{"relayer":"The relayer address of the bridge proof","timestamp":"The timestamp of the bridge proof"}},"bridgeRelays(bytes32)":{"params":{"transactionId":"The ID of the transaction to check"},"returns":{"_0":"True if the transaction has been relayed, false otherwise"}},"bridgeStatuses(bytes32)":{"params":{"transactionId":"The ID of the bridge transaction"},"returns":{"_0":"BridgeStatus Status of the bridge transaction"}},"bridgeV2((uint32,address,address,address,address,uint256,uint256,bool,uint256),(address,int256,bytes,uint256,bytes))":{"params":{"params":"The parameters required to bridge","paramsV2":"The parameters for exclusivity fill rights (optional, can be left empty)"}},"canClaim(bytes32,address)":{"params":{"relayer":"The address of the relayer attempting to claim","transactionId":"The transaction id associated with the encoded bridge transaction to check"}},"cancelV2(bytes)":{"params":{"request":"The encoded bridge transaction to refund"}},"claim(bytes,address)":{"params":{"request":"The encoded bridge transaction to claim on origin chain","to":"The recipient address of the funds"}},"claimV2(bytes)":{"params":{"request":"The encoded bridge transaction to claim on origin chain"}},"dispute(bytes32)":{"params":{"transactionId":"The transaction id associated with the encoded bridge transaction to dispute"}},"getBridgeTransaction(bytes)":{"params":{"request":"The bridge request to decode"}},"getBridgeTransactionV2(bytes)":{"params":{"request":"The bridge request to decode"}},"prove(bytes,bytes32)":{"params":{"destTxHash":"The destination tx hash proving bridge transaction was relayed","request":"The encoded bridge transaction to prove on origin chain"}},"proveV2(bytes32,bytes32,address)":{"params":{"destTxHash":"The destination tx hash proving bridge transaction was relayed","relayer":"The address of the relaying entity which should have control of the origin funds when claimed","transactionId":"The transaction id associated with the encoded bridge transaction to prove"}},"refund(bytes)":{"params":{"request":"The encoded bridge transaction to refund"}},"relay(bytes)":{"params":{"request":"The encoded bridge transaction to relay on destination chain"}},"relayV2(bytes,address)":{"params":{"relayer":"The address of the relaying entity which should have control of the origin funds when claimed","request":"The encoded bridge transaction to relay on destination chain"}}},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"BridgeDepositClaimed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"BridgeDepositRefunded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"name\":\"BridgeProofDisputed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"transactionHash\",\"type\":\"bytes32\"}],\"name\":\"BridgeProofProvided\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"quoteId\",\"type\":\"bytes\"}],\"name\":\"BridgeQuoteDetails\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"originChainId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"chainGasAmount\",\"type\":\"uint256\"}],\"name\":\"BridgeRelayed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"destChainId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"sendChainGas\",\"type\":\"bool\"}],\"name\":\"BridgeRequested\",\"type\":\"event\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"dstChainId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"sendChainGas\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"}],\"internalType\":\"struct IFastBridge.BridgeParams\",\"name\":\"params\",\"type\":\"tuple\"}],\"name\":\"bridge\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"}],\"name\":\"bridgeProofs\",\"outputs\":[{\"internalType\":\"uint96\",\"name\":\"timestamp\",\"type\":\"uint96\"},{\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"}],\"name\":\"bridgeRelays\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"}],\"name\":\"bridgeStatuses\",\"outputs\":[{\"internalType\":\"enum IFastBridgeV2.BridgeStatus\",\"name\":\"\",\"type\":\"uint8\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"dstChainId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"sendChainGas\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"}],\"internalType\":\"struct IFastBridge.BridgeParams\",\"name\":\"params\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"quoteRelayer\",\"type\":\"address\"},{\"internalType\":\"int256\",\"name\":\"quoteExclusivitySeconds\",\"type\":\"int256\"},{\"internalType\":\"bytes\",\"name\":\"quoteId\",\"type\":\"bytes\"},{\"internalType\":\"uint256\",\"name\":\"zapNative\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"zapData\",\"type\":\"bytes\"}],\"internalType\":\"struct IFastBridgeV2.BridgeParamsV2\",\"name\":\"paramsV2\",\"type\":\"tuple\"}],\"name\":\"bridgeV2\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"name\":\"canClaim\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"cancelV2\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"claim\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"claimV2\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"}],\"name\":\"dispute\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"getBridgeTransaction\",\"outputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"originChainId\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"destChainId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"originSender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destRecipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"originFeeAmount\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"sendChainGas\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"}],\"internalType\":\"struct IFastBridge.BridgeTransaction\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"getBridgeTransactionV2\",\"outputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"originChainId\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"destChainId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"originSender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destRecipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"originFeeAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"exclusivityRelayer\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"exclusivityEndTime\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"zapNative\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"zapData\",\"type\":\"bytes\"}],\"internalType\":\"struct IFastBridgeV2.BridgeTransactionV2\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"},{\"internalType\":\"bytes32\",\"name\":\"destTxHash\",\"type\":\"bytes32\"}],\"name\":\"prove\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"destTxHash\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"name\":\"proveV2\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"refund\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"relay\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"},{\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"name\":\"relayV2\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{\"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256))\":{\"params\":{\"params\":\"The parameters required to bridge\"}},\"bridgeProofs(bytes32)\":{\"params\":{\"transactionId\":\"The ID of the bridge transaction\"},\"returns\":{\"relayer\":\"The relayer address of the bridge proof\",\"timestamp\":\"The timestamp of the bridge proof\"}},\"bridgeRelays(bytes32)\":{\"params\":{\"transactionId\":\"The ID of the transaction to check\"},\"returns\":{\"_0\":\"True if the transaction has been relayed, false otherwise\"}},\"bridgeStatuses(bytes32)\":{\"params\":{\"transactionId\":\"The ID of the bridge transaction\"},\"returns\":{\"_0\":\"BridgeStatus Status of the bridge transaction\"}},\"bridgeV2((uint32,address,address,address,address,uint256,uint256,bool,uint256),(address,int256,bytes,uint256,bytes))\":{\"params\":{\"params\":\"The parameters required to bridge\",\"paramsV2\":\"The parameters for exclusivity fill rights (optional, can be left empty)\"}},\"canClaim(bytes32,address)\":{\"params\":{\"relayer\":\"The address of the relayer attempting to claim\",\"transactionId\":\"The transaction id associated with the encoded bridge transaction to check\"}},\"cancelV2(bytes)\":{\"params\":{\"request\":\"The encoded bridge transaction to refund\"}},\"claim(bytes,address)\":{\"params\":{\"request\":\"The encoded bridge transaction to claim on origin chain\",\"to\":\"The recipient address of the funds\"}},\"claimV2(bytes)\":{\"params\":{\"request\":\"The encoded bridge transaction to claim on origin chain\"}},\"dispute(bytes32)\":{\"params\":{\"transactionId\":\"The transaction id associated with the encoded bridge transaction to dispute\"}},\"getBridgeTransaction(bytes)\":{\"params\":{\"request\":\"The bridge request to decode\"}},\"getBridgeTransactionV2(bytes)\":{\"params\":{\"request\":\"The bridge request to decode\"}},\"prove(bytes,bytes32)\":{\"params\":{\"destTxHash\":\"The destination tx hash proving bridge transaction was relayed\",\"request\":\"The encoded bridge transaction to prove on origin chain\"}},\"proveV2(bytes32,bytes32,address)\":{\"params\":{\"destTxHash\":\"The destination tx hash proving bridge transaction was relayed\",\"relayer\":\"The address of the relaying entity which should have control of the origin funds when claimed\",\"transactionId\":\"The transaction id associated with the encoded bridge transaction to prove\"}},\"refund(bytes)\":{\"params\":{\"request\":\"The encoded bridge transaction to refund\"}},\"relay(bytes)\":{\"params\":{\"request\":\"The encoded bridge transaction to relay on destination chain\"}},\"relayV2(bytes,address)\":{\"params\":{\"relayer\":\"The address of the relaying entity which should have control of the origin funds when claimed\",\"request\":\"The encoded bridge transaction to relay on destination chain\"}}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256))\":{\"notice\":\"Initiates bridge on origin chain to be relayed by off-chain relayer\"},\"bridgeProofs(bytes32)\":{\"notice\":\"Returns the timestamp and relayer of a bridge proof\"},\"bridgeRelays(bytes32)\":{\"notice\":\"Checks if a transaction has been relayed\"},\"bridgeStatuses(bytes32)\":{\"notice\":\"Returns the status of a bridge transaction\"},\"bridgeV2((uint32,address,address,address,address,uint256,uint256,bool,uint256),(address,int256,bytes,uint256,bytes))\":{\"notice\":\"Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability to provide temporary exclusivity fill rights for the quote relayer.\"},\"canClaim(bytes32,address)\":{\"notice\":\"Checks if the dispute period has passed so bridge deposit can be claimed\"},\"cancelV2(bytes)\":{\"notice\":\"Cancels an outstanding bridge transaction in case optimistic bridging failed and returns the full amount to the original sender.\"},\"claim(bytes,address)\":{\"notice\":\"Completes bridge transaction on origin chain by claiming originally deposited capital\"},\"claimV2(bytes)\":{\"notice\":\"Completes bridge transaction on origin chain by claiming originally deposited capital.Can only send funds to the relayer address on the proof.\"},\"dispute(bytes32)\":{\"notice\":\"Disputes an outstanding proof in case relayer provided dest chain tx is invalid\"},\"getBridgeTransaction(bytes)\":{\"notice\":\"Decodes bridge request into a bridge transaction\"},\"getBridgeTransactionV2(bytes)\":{\"notice\":\"Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\"},\"prove(bytes,bytes32)\":{\"notice\":\"Provides proof on origin side that relayer provided funds on destination side of bridge transaction\"},\"proveV2(bytes32,bytes32,address)\":{\"notice\":\"Provides proof on origin side that relayer provided funds on destination side of bridge transaction\"},\"refund(bytes)\":{\"notice\":\"Refunds an outstanding bridge transaction in case optimistic bridging failed\"},\"relay(bytes)\":{\"notice\":\"Relays destination side of bridge transaction by off-chain relayer\"},\"relayV2(bytes,address)\":{\"notice\":\"Relays destination side of bridge transaction by off-chain relayer\"}},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeV2.sol\":\"IFastBridgeV2\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeV2.sol\":{\"keccak256\":\"0xaab2ee7357681726f0faf799a48ddfbf45fb4da93b69abf61c33dde92b29b74d\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://673391bff9569efc0f9bd99e0e6fece0bc8e8af1f052bb071b407b267a17b3b5\",\"dweb:/ipfs/QmdQQZ6DxpJYhfpinwU5WjLugr2f6qP8h68b5GerhSMQ4j\"]}},\"version\":1}"},"hashes":{"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256))":"45851694","bridgeProofs(bytes32)":"91ad5039","bridgeRelays(bytes32)":"8379a24f","bridgeStatuses(bytes32)":"051287bc","bridgeV2((uint32,address,address,address,address,uint256,uint256,bool,uint256),(address,int256,bytes,uint256,bytes))":"76443085","canClaim(bytes32,address)":"aa9641ab","cancelV2(bytes)":"67e60693","claim(bytes,address)":"41fcb612","claimV2(bytes)":"f76d7278","dispute(bytes32)":"add98c70","getBridgeTransaction(bytes)":"ac11fb1a","getBridgeTransactionV2(bytes)":"5aa6ccba","prove(bytes,bytes32)":"886d36ff","proveV2(bytes32,bytes32,address)":"41fdec80","refund(bytes)":"5eb7d946","relay(bytes)":"8f0d6f17","relayV2(bytes,address)":"3d71e21f"}},"solidity/FastBridgeV2.sol:IFastBridgeV2Errors":{"code":"0x","runtime-code":"0x","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.24 ^0.8.20 ^0.8.4;\n\n// contracts/interfaces/IAdminV2.sol\n\ninterface IAdminV2 {\n event CancelDelayUpdated(uint256 oldCancelDelay, uint256 newCancelDelay);\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n /// @notice Allows the governor to set the cancel delay. The cancel delay is the time period after the transaction\n /// deadline during which a transaction can be permissionlessly cancelled if it hasn't been proven by any Relayer.\n function setCancelDelay(uint256 newCancelDelay) external;\n\n /// @notice Allows the governor to set the protocol fee rate. The protocol fee is taken from the origin\n /// amount and is only applied to completed and claimed transactions.\n /// @dev The protocol fee is abstracted away from the relayers; they always operate using the amounts after fees.\n /// The origin amount they see in the emitted log is what they get credited with.\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n /// @notice Allows the governor to withdraw the accumulated protocol fees from the contract.\n function sweepProtocolFees(address token, address recipient) external;\n}\n\n// contracts/interfaces/IAdminV2Errors.sol\n\ninterface IAdminV2Errors {\n error CancelDelayBelowMin();\n error FeeRateAboveMax();\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IFastBridgeV2Errors.sol\n\ninterface IFastBridgeV2Errors {\n error AmountIncorrect();\n error ChainIncorrect();\n error ExclusivityParamsIncorrect();\n error MsgValueIncorrect();\n error SenderIncorrect();\n error StatusIncorrect();\n error TokenNotContract();\n error ZapDataLengthAboveMax();\n error ZapNativeNotSupported();\n error ZeroAddress();\n\n error RecipientIncorrectReturnValue();\n error RecipientNoReturnValue();\n\n error DeadlineExceeded();\n error DeadlineNotExceeded();\n error DeadlineTooShort();\n error DisputePeriodNotPassed();\n error DisputePeriodPassed();\n error ExclusivityPeriodNotPassed();\n\n error TransactionRelayed();\n}\n\n// contracts/interfaces/IMulticallTarget.sol\n\n/// @notice Interface for a contract that supports multiple calls from the same caller. Inspired by MulticallV3:\n/// https://github.com/mds1/multicall/blob/master/src/Multicall3.sol\ninterface IMulticallTarget {\n struct Result {\n bool success;\n bytes returnData;\n }\n\n /// @notice Executes multiple calls to this contract in a single transaction while preserving msg.sender.\n /// Return data from the calls is discarded.\n /// @dev This method is non-payable, so only calls with msg.value of 0 can be batched.\n /// If ignoreReverts is set to true, reverted calls will be skipped.\n /// Otherwise, the entire batch will revert with the original revert reason.\n /// @param data List of ABI-encoded calldata for the calls to execute\n /// @param ignoreReverts Whether to skip calls that revert\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external;\n\n /// @notice Executes multiple calls to this contract in a single transaction while preserving msg.sender.\n /// Return data from each call is preserved.\n /// @dev This method is non-payable, so only calls with msg.value of 0 can be batched.\n /// If ignoreReverts is set to true, reverted calls will be skipped.\n /// Otherwise, the entire batch will revert with the original revert reason.\n /// @param data List of ABI-encoded calldata for the calls to execute\n /// @param ignoreReverts Whether to skip calls that revert\n /// @return results List of results from the calls, each containing (success, returnData)\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results);\n}\n\n// contracts/interfaces/IZapRecipient.sol\n\n/// @notice Interface for contracts that can perform Zap operations. Such contracts could be used as Recipients\n/// in a FastBridge transaction that includes a Zap operation. The Zap Data should include instructions on how\n/// exactly the Zap operation should be executed, which would typically include the target address and calldata\n/// to use. The exact implementation of the Zap Data encoding is up to the Recipient contract.\ninterface IZapRecipient {\n /// @notice Performs a Zap operation with the given token and amount according to the provided Zap data.\n /// @param token The address of the token being used for the Zap operation.\n /// @param amount The amount of tokens to be used.\n /// @param zapData The encoded data specifying how the Zap operation should be executed.\n /// @return The function selector to indicate successful execution.\n function zap(address token, uint256 amount, bytes memory zapData) external payable returns (bytes4);\n}\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// contracts/interfaces/IFastBridgeV2.sol\n\ninterface IFastBridgeV2 is IFastBridge {\n enum BridgeStatus {\n NULL, // Doesn't exist yet.\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n struct BridgeTxDetails {\n BridgeStatus status;\n uint32 destChainId;\n uint56 proofBlockTimestamp;\n address proofRelayer;\n }\n\n struct BridgeRelay {\n uint48 blockNumber;\n uint48 blockTimestamp;\n address relayer;\n }\n\n /// @notice New params introduced in the FastBridgeV2.\n /// We are passing fields from the older BridgeParams struct outside of this struct for backwards compatibility.\n /// Note: quoteRelayer and quoteExclusivitySeconds are either both zero (indicating no exclusivity)\n /// or both non-zero (indicating exclusivity for the given period).\n /// Note: zapNative \u003e 0 can NOT be used with destToken = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE (native token)\n /// @param quoteRelayer Relayer that provided the quote for the transaction\n /// @param quoteExclusivitySeconds Period of time the quote relayer is guaranteed exclusivity after user's deposit\n /// @param quoteId Unique quote identifier used for tracking the quote\n /// @param zapNative ETH value to send to the recipient (if any)\n /// @param zapData Parameters for the Zap to the destination recipient (if any)\n struct BridgeParamsV2 {\n address quoteRelayer;\n int256 quoteExclusivitySeconds;\n bytes quoteId;\n uint256 zapNative;\n bytes zapData;\n }\n\n /// @notice Updated bridge transaction struct to include parameters introduced in FastBridgeV2.\n /// Note: only `exclusivityRelayer` can fill such a transaction until `exclusivityEndTime`.\n struct BridgeTransactionV2 {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n // Note: sendChainGas flag from V1 is deprecated\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n address exclusivityRelayer;\n uint256 exclusivityEndTime;\n uint256 zapNative; // ETH value to send to the recipient (if any)\n bytes zapData; // data to pass for the Zap action (if any)\n }\n\n event BridgeQuoteDetails(bytes32 indexed transactionId, bytes quoteId);\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability\n /// to provide temporary exclusivity fill rights for the quote relayer.\n /// @param params The parameters required to bridge\n /// @param paramsV2 The parameters for exclusivity fill rights (optional, can be left empty)\n function bridgeV2(BridgeParams memory params, BridgeParamsV2 memory paramsV2) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function relayV2(bytes memory request, address relayer) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param transactionId The transaction id associated with the encoded bridge transaction to prove\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function proveV2(bytes32 transactionId, bytes32 destTxHash, address relayer) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital.\n /// @notice Can only send funds to the relayer address on the proof.\n /// @param request The encoded bridge transaction to claim on origin chain\n function claimV2(bytes memory request) external;\n\n /// @notice Cancels an outstanding bridge transaction in case optimistic bridging failed and returns the full amount\n /// to the original sender.\n /// @param request The encoded bridge transaction to refund\n function cancelV2(bytes memory request) external;\n\n /// @notice Checks if a transaction has been relayed\n /// @param transactionId The ID of the transaction to check\n /// @return True if the transaction has been relayed, false otherwise\n function bridgeRelays(bytes32 transactionId) external view returns (bool);\n\n /// @notice Returns the status of a bridge transaction\n /// @param transactionId The ID of the bridge transaction\n /// @return BridgeStatus Status of the bridge transaction\n function bridgeStatuses(bytes32 transactionId) external view returns (BridgeStatus);\n\n /// @notice Returns the timestamp and relayer of a bridge proof\n /// @param transactionId The ID of the bridge transaction\n /// @return timestamp The timestamp of the bridge proof\n /// @return relayer The relayer address of the bridge proof\n function bridgeProofs(bytes32 transactionId) external view returns (uint96 timestamp, address relayer);\n\n /// @notice Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\n /// @param request The bridge request to decode\n function getBridgeTransactionV2(bytes memory request) external view returns (BridgeTransactionV2 memory);\n}\n\n// contracts/utils/MulticallTarget.sol\n\n// solhint-disable avoid-low-level-calls\n/// @notice Abstract contract template that supports batched calls while preserving msg.sender.\n/// Only calls with msg.value of 0 can be batched.\nabstract contract MulticallTarget is IMulticallTarget {\n error MulticallTarget__UndeterminedRevert();\n\n /// @inheritdoc IMulticallTarget\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external {\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\n if (!success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(result);\n }\n }\n }\n\n /// @inheritdoc IMulticallTarget\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results)\n {\n results = new Result[](data.length);\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (results[i].success, results[i].returnData) = address(this).delegatecall(data[i]);\n if (!results[i].success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(results[i].returnData);\n }\n }\n }\n\n /// @dev Bubbles the revert message from the underlying call.\n /// Note: preserves the same custom error or revert string, if one was used.\n /// Source: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v5.0.2/contracts/utils/Address.sol#L143-L158\n function _bubbleRevert(bytes memory returnData) internal pure {\n // Look for revert reason and bubble it up if present\n if (returnData.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n // solhint-disable-next-line no-inline-assembly\n assembly {\n let returndata_size := mload(returnData)\n revert(add(32, returnData), returndata_size)\n }\n } else {\n revert MulticallTarget__UndeterminedRevert();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// contracts/libs/BridgeTransactionV2.sol\n\n// solhint-disable no-inline-assembly\nlibrary BridgeTransactionV2Lib {\n uint16 internal constant VERSION = 2;\n\n // Offsets of the fields in the packed BridgeTransactionV2 struct\n // uint16 version [000 .. 002)\n // uint32 originChainId [002 .. 006)\n // uint32 destChainId [006 .. 010)\n // address originSender [010 .. 030)\n // address destRecipient [030 .. 050)\n // address originToken [050 .. 070)\n // address destToken [070 .. 090)\n // uint256 originAmount [090 .. 122)\n // uint256 destAmount [122 .. 154)\n // uint256 originFeeAmount [154 .. 186)\n // uint256 deadline [186 .. 218)\n // uint256 nonce [218 .. 250)\n // address exclusivityRelayer [250 .. 270)\n // uint256 exclusivityEndTime [270 .. 302)\n // uint256 zapNative [302 .. 334)\n // bytes zapData [334 .. ***)\n\n // forgefmt: disable-start\n uint256 private constant OFFSET_ORIGIN_CHAIN_ID = 2;\n uint256 private constant OFFSET_DEST_CHAIN_ID = 6;\n uint256 private constant OFFSET_ORIGIN_SENDER = 10;\n uint256 private constant OFFSET_DEST_RECIPIENT = 30;\n uint256 private constant OFFSET_ORIGIN_TOKEN = 50;\n uint256 private constant OFFSET_DEST_TOKEN = 70;\n uint256 private constant OFFSET_ORIGIN_AMOUNT = 90;\n uint256 private constant OFFSET_DEST_AMOUNT = 122;\n uint256 private constant OFFSET_ORIGIN_FEE_AMOUNT = 154;\n uint256 private constant OFFSET_DEADLINE = 186;\n uint256 private constant OFFSET_NONCE = 218;\n uint256 private constant OFFSET_EXCLUSIVITY_RELAYER = 250;\n uint256 private constant OFFSET_EXCLUSIVITY_END_TIME = 270;\n uint256 private constant OFFSET_ZAP_NATIVE = 302;\n uint256 private constant OFFSET_ZAP_DATA = 334;\n // forgefmt: disable-end\n\n error BridgeTransactionV2__InvalidEncodedTx();\n error BridgeTransactionV2__UnsupportedVersion(uint16 version);\n\n /// @notice Validates that the encoded transaction is a tightly packed encoded payload for BridgeTransactionV2.\n /// @dev Checks the minimum length and the version, use this function before decoding any of the fields.\n function validateV2(bytes calldata encodedTx) internal pure {\n // Check the minimum length: must at least include all static fields.\n if (encodedTx.length \u003c OFFSET_ZAP_DATA) revert BridgeTransactionV2__InvalidEncodedTx();\n // Once we validated the length, we can be sure that the version field is present.\n uint16 version_ = version(encodedTx);\n if (version_ != VERSION) revert BridgeTransactionV2__UnsupportedVersion(version_);\n }\n\n /// @notice Encodes the BridgeTransactionV2 struct by tightly packing the fields.\n /// @dev `abi.decode` will not work as a result of the tightly packed fields. Use `decodeV2` to decode instead.\n function encodeV2(IFastBridgeV2.BridgeTransactionV2 memory bridgeTx) internal pure returns (bytes memory) {\n // We split the encoding into two parts to avoid stack-too-deep error\n bytes memory firstPart = abi.encodePacked(\n VERSION,\n bridgeTx.originChainId,\n bridgeTx.destChainId,\n bridgeTx.originSender,\n bridgeTx.destRecipient,\n bridgeTx.originToken,\n bridgeTx.destToken,\n bridgeTx.originAmount\n );\n return abi.encodePacked(\n firstPart,\n bridgeTx.destAmount,\n bridgeTx.originFeeAmount,\n // Note: we skip the deprecated `sendChainGas` flag, which was present in BridgeTransaction V1\n bridgeTx.deadline,\n bridgeTx.nonce,\n // New V2 fields: exclusivity\n bridgeTx.exclusivityRelayer,\n bridgeTx.exclusivityEndTime,\n // New V2 fields: Zap\n bridgeTx.zapNative,\n bridgeTx.zapData\n );\n }\n\n /// @notice Decodes the BridgeTransactionV2 struct from the encoded transaction.\n /// @dev Encoded BridgeTransactionV2 struct must be tightly packed.\n /// Use `validateV2` before decoding to ensure the encoded transaction is valid.\n function decodeV2(bytes calldata encodedTx)\n internal\n pure\n returns (IFastBridgeV2.BridgeTransactionV2 memory bridgeTx)\n {\n bridgeTx.originChainId = originChainId(encodedTx);\n bridgeTx.destChainId = destChainId(encodedTx);\n bridgeTx.originSender = originSender(encodedTx);\n bridgeTx.destRecipient = destRecipient(encodedTx);\n bridgeTx.originToken = originToken(encodedTx);\n bridgeTx.destToken = destToken(encodedTx);\n bridgeTx.originAmount = originAmount(encodedTx);\n bridgeTx.destAmount = destAmount(encodedTx);\n bridgeTx.originFeeAmount = originFeeAmount(encodedTx);\n bridgeTx.deadline = deadline(encodedTx);\n bridgeTx.nonce = nonce(encodedTx);\n bridgeTx.exclusivityRelayer = exclusivityRelayer(encodedTx);\n bridgeTx.exclusivityEndTime = exclusivityEndTime(encodedTx);\n bridgeTx.zapNative = zapNative(encodedTx);\n bridgeTx.zapData = zapData(encodedTx);\n }\n\n /// @notice Extracts the version from the encoded transaction.\n function version(bytes calldata encodedTx) internal pure returns (uint16 version_) {\n // Load 32 bytes from the start and shift it 240 bits to the right to get the highest 16 bits.\n assembly {\n version_ := shr(240, calldataload(encodedTx.offset))\n }\n }\n\n /// @notice Extracts the origin chain ID from the encoded transaction.\n function originChainId(bytes calldata encodedTx) internal pure returns (uint32 originChainId_) {\n // Load 32 bytes from the offset and shift it 224 bits to the right to get the highest 32 bits.\n assembly {\n originChainId_ := shr(224, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_CHAIN_ID)))\n }\n }\n\n /// @notice Extracts the destination chain ID from the encoded transaction.\n function destChainId(bytes calldata encodedTx) internal pure returns (uint32 destChainId_) {\n // Load 32 bytes from the offset and shift it 224 bits to the right to get the highest 32 bits.\n assembly {\n destChainId_ := shr(224, calldataload(add(encodedTx.offset, OFFSET_DEST_CHAIN_ID)))\n }\n }\n\n /// @notice Extracts the origin sender from the encoded transaction.\n function originSender(bytes calldata encodedTx) internal pure returns (address originSender_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n originSender_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_SENDER)))\n }\n }\n\n /// @notice Extracts the destination recipient from the encoded transaction.\n function destRecipient(bytes calldata encodedTx) internal pure returns (address destRecipient_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n destRecipient_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_DEST_RECIPIENT)))\n }\n }\n\n /// @notice Extracts the origin token from the encoded transaction.\n function originToken(bytes calldata encodedTx) internal pure returns (address originToken_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n originToken_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_TOKEN)))\n }\n }\n\n /// @notice Extracts the destination token from the encoded transaction.\n function destToken(bytes calldata encodedTx) internal pure returns (address destToken_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n destToken_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_DEST_TOKEN)))\n }\n }\n\n /// @notice Extracts the origin amount from the encoded transaction.\n function originAmount(bytes calldata encodedTx) internal pure returns (uint256 originAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n originAmount_ := calldataload(add(encodedTx.offset, OFFSET_ORIGIN_AMOUNT))\n }\n }\n\n /// @notice Extracts the destination amount from the encoded transaction.\n function destAmount(bytes calldata encodedTx) internal pure returns (uint256 destAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n destAmount_ := calldataload(add(encodedTx.offset, OFFSET_DEST_AMOUNT))\n }\n }\n\n /// @notice Extracts the origin fee amount from the encoded transaction.\n function originFeeAmount(bytes calldata encodedTx) internal pure returns (uint256 originFeeAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n originFeeAmount_ := calldataload(add(encodedTx.offset, OFFSET_ORIGIN_FEE_AMOUNT))\n }\n }\n\n /// @notice Extracts the deadline from the encoded transaction.\n function deadline(bytes calldata encodedTx) internal pure returns (uint256 deadline_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n deadline_ := calldataload(add(encodedTx.offset, OFFSET_DEADLINE))\n }\n }\n\n /// @notice Extracts the nonce from the encoded transaction.\n function nonce(bytes calldata encodedTx) internal pure returns (uint256 nonce_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n nonce_ := calldataload(add(encodedTx.offset, OFFSET_NONCE))\n }\n }\n\n /// @notice Extracts the exclusivity relayer from the encoded transaction.\n function exclusivityRelayer(bytes calldata encodedTx) internal pure returns (address exclusivityRelayer_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n exclusivityRelayer_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_EXCLUSIVITY_RELAYER)))\n }\n }\n\n /// @notice Extracts the exclusivity end time from the encoded transaction.\n function exclusivityEndTime(bytes calldata encodedTx) internal pure returns (uint256 exclusivityEndTime_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n exclusivityEndTime_ := calldataload(add(encodedTx.offset, OFFSET_EXCLUSIVITY_END_TIME))\n }\n }\n\n /// @notice Extracts the Zap's native value from the encoded transaction.\n function zapNative(bytes calldata encodedTx) internal pure returns (uint256 zapNative_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n zapNative_ := calldataload(add(encodedTx.offset, OFFSET_ZAP_NATIVE))\n }\n }\n\n /// @notice Extracts the Zap's data from the encoded transaction.\n function zapData(bytes calldata encodedTx) internal pure returns (bytes calldata zapData_) {\n zapData_ = encodedTx[OFFSET_ZAP_DATA:];\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/AdminV2.sol\n\n// ════════════════════════════════════════════════ INTERFACES ═════════════════════════════════════════════════════\n\n// ═════════════════════════════════════════════ EXTERNAL IMPORTS ══════════════════════════════════════════════════\n\n/// @title AdminV2\n/// @notice Provides administrative functions and controls for managing the FastBridgeV2 contract,\n/// including access control and configuration settings.\ncontract AdminV2 is AccessControlEnumerable, IAdminV2, IAdminV2Errors {\n using SafeERC20 for IERC20;\n\n /// @notice The address reserved for the native gas token (ETH on Ethereum and most L2s, AVAX on Avalanche, etc.).\n address public constant NATIVE_GAS_TOKEN = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice The role identifier for the Quoter API's off-chain authentication.\n /// @dev Only addresses with this role can post FastBridge quotes to the API.\n bytes32 public constant QUOTER_ROLE = keccak256(\"QUOTER_ROLE\");\n\n /// @notice The role identifier for the Prover's on-chain authentication in FastBridge.\n /// @dev Only addresses with this role can provide proofs that a FastBridge request has been relayed.\n bytes32 public constant PROVER_ROLE = keccak256(\"PROVER_ROLE\");\n\n /// @notice The role identifier for the Guard's on-chain authentication in FastBridge.\n /// @dev Only addresses with this role can dispute submitted relay proofs during the dispute period.\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n\n /// @notice The role identifier for the Canceler's on-chain authentication in FastBridge.\n /// @dev Only addresses with this role can cancel a FastBridge transaction without the cancel delay.\n bytes32 public constant CANCELER_ROLE = keccak256(\"CANCELER_ROLE\");\n\n /// @notice The role identifier for the Governor's on-chain administrative authority.\n /// @dev Only addresses with this role can perform administrative tasks within the contract.\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n /// @notice The denominator for fee rates, representing 100%.\n uint256 public constant FEE_BPS = 1e6;\n /// @notice The maximum protocol fee rate: 1% of the origin amount.\n uint256 public constant FEE_RATE_MAX = 0.01e6;\n\n /// @notice The minimum cancel delay that can be set by the governor.\n uint256 public constant MIN_CANCEL_DELAY = 1 hours;\n /// @notice The default cancel delay set during contract deployment.\n uint256 public constant DEFAULT_CANCEL_DELAY = 1 days;\n\n /// @notice The protocol fee rate taken on the origin amount deposited in the origin chain.\n uint256 public protocolFeeRate;\n\n /// @notice The accumulated protocol fee amounts.\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice The delay period after which a transaction can be permissionlessly cancelled.\n uint256 public cancelDelay;\n\n /// @notice This variable is deprecated and should not be used.\n /// @dev Use ZapNative V2 requests instead.\n uint256 public immutable chainGasAmount = 0;\n\n constructor(address defaultAdmin) {\n _grantRole(DEFAULT_ADMIN_ROLE, defaultAdmin);\n _setCancelDelay(DEFAULT_CANCEL_DELAY);\n }\n\n /// @inheritdoc IAdminV2\n function setCancelDelay(uint256 newCancelDelay) external onlyRole(GOVERNOR_ROLE) {\n _setCancelDelay(newCancelDelay);\n }\n\n /// @inheritdoc IAdminV2\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n if (newFeeRate \u003e FEE_RATE_MAX) revert FeeRateAboveMax();\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n /// @inheritdoc IAdminV2\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n // Early exit if no accumulated fees.\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return;\n // Reset the accumulated fees first.\n protocolFees[token] = 0;\n emit FeesSwept(token, recipient, feeAmount);\n // Sweep the fees as the last transaction action.\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(recipient), feeAmount);\n } else {\n IERC20(token).safeTransfer(recipient, feeAmount);\n }\n }\n\n /// @notice Internal logic to set the cancel delay. Security checks are performed outside of this function.\n /// @dev This function is marked as private to prevent child contracts from calling it directly.\n function _setCancelDelay(uint256 newCancelDelay) private {\n if (newCancelDelay \u003c MIN_CANCEL_DELAY) revert CancelDelayBelowMin();\n uint256 oldCancelDelay = cancelDelay;\n cancelDelay = newCancelDelay;\n emit CancelDelayUpdated(oldCancelDelay, newCancelDelay);\n }\n}\n\n// contracts/FastBridgeV2.sol\n\n// ════════════════════════════════════════════════ INTERFACES ═════════════════════════════════════════════════════\n\n// ═════════════════════════════════════════════ INTERNAL IMPORTS ══════════════════════════════════════════════════\n\n// ═════════════════════════════════════════════ EXTERNAL IMPORTS ══════════════════════════════════════════════════\n\n/// @title FastBridgeV2\n/// @notice Core component of the SynapseRFQ protocol, enabling Relayers (Solvers) to fulfill bridge requests.\n/// Supports ERC20 and native gas tokens, along with the Zap feature for executing actions on the destination chain.\n/// Users interact with the off-chain Quoter API to obtain a current quote for a bridge transaction.\n/// They then submit the bridge request with the quote to this contract, depositing their assets in escrow.\n/// Relayers can fulfill requests by relaying them to the destination chain and must prove fulfillment to claim funds.\n/// Guards monitor proofs and can dispute discrepancies.\n/// Users can reclaim funds by cancelling their requests if it has not been fulfilled within the specified deadline.\ncontract FastBridgeV2 is AdminV2, MulticallTarget, IFastBridgeV2, IFastBridgeV2Errors {\n using BridgeTransactionV2Lib for bytes;\n using SafeERC20 for IERC20;\n\n /// @notice The duration of the dispute period for relayed transactions.\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice The minimum required time between transaction request and deadline.\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n /// @notice The maximum allowed length for zapData.\n uint256 public constant MAX_ZAP_DATA_LENGTH = 2 ** 16 - 1;\n\n /// @notice Maps transaction IDs to bridge details (status, destination chain ID, proof timestamp, and relayer).\n /// Note: this is only stored for transactions having local chain as the origin chain.\n mapping(bytes32 =\u003e BridgeTxDetails) public bridgeTxDetails;\n /// @notice Maps transaction IDs to relay details (block number, block timestamp, and relayer).\n /// Note: this is only stored for transactions having local chain as the destination chain.\n mapping(bytes32 =\u003e BridgeRelay) public bridgeRelayDetails;\n /// @notice Maps sender addresses to their unique bridge nonce.\n mapping(address =\u003e uint256) public senderNonces;\n\n /// @notice This variable is deprecated and should not be used.\n /// @dev Replaced by senderNonces.\n uint256 public immutable nonce = 0;\n /// @notice The block number at which this contract was deployed.\n uint256 public immutable deployBlock;\n\n /// @notice Initializes the FastBridgeV2 contract with the provided default admin,\n /// sets the default cancel delay, and records the deploy block number.\n constructor(address defaultAdmin) AdminV2(defaultAdmin) {\n deployBlock = block.number;\n }\n\n // ══════════════════════════════════════ EXTERNAL MUTABLE (USER FACING) ═══════════════════════════════════════════\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n bridgeV2({\n params: params,\n paramsV2: BridgeParamsV2({\n quoteRelayer: address(0),\n quoteExclusivitySeconds: 0,\n quoteId: bytes(\"\"),\n zapNative: 0,\n zapData: bytes(\"\")\n })\n });\n }\n\n /// Note: this function is deprecated and will be removed in a future version.\n /// @dev Replaced by `cancel`.\n /// @inheritdoc IFastBridge\n function refund(bytes calldata request) external {\n cancelV2(request);\n }\n\n // ══════════════════════════════════════ EXTERNAL MUTABLE (AGENT FACING) ══════════════════════════════════════════\n\n /// @inheritdoc IFastBridge\n function relay(bytes calldata request) external payable {\n // `relay` override will validate the request.\n relayV2({request: request, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes calldata request, bytes32 destTxHash) external {\n request.validateV2();\n proveV2({transactionId: keccak256(request), destTxHash: destTxHash, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridgeV2\n function claimV2(bytes calldata request) external {\n // `claim` override will validate the request.\n claim({request: request, to: address(0)});\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n // Aggregate the read operations from the same storage slot.\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n address disputedRelayer = $.proofRelayer;\n BridgeStatus status = $.status;\n uint56 proofBlockTimestamp = $.proofBlockTimestamp;\n\n // Can only dispute a RELAYER_PROVED transaction within the dispute period.\n if (status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(proofBlockTimestamp) \u003e DISPUTE_PERIOD) {\n revert DisputePeriodPassed();\n }\n\n // Update status to REQUESTED and delete the disputed proof details.\n // Note: these are storage writes.\n $.status = BridgeStatus.REQUESTED;\n $.proofRelayer = address(0);\n $.proofBlockTimestamp = 0;\n\n emit BridgeProofDisputed(transactionId, disputedRelayer);\n }\n\n // ══════════════════════════════════════════════ EXTERNAL VIEWS ═══════════════════════════════════════════════════\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n // The correct relayer can only claim a RELAYER_PROVED transaction after the dispute period.\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n if ($.status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if ($.proofRelayer != relayer) revert SenderIncorrect();\n\n return _timeSince($.proofBlockTimestamp) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n /// @dev This method is added to achieve backwards compatibility with decoding requests into V1 structs:\n /// - `zapNative` is partially reported as a zero/non-zero flag\n /// - `zapData` is ignored\n /// In order to process all kinds of requests use getBridgeTransactionV2 instead.\n function getBridgeTransaction(bytes calldata request) external view returns (BridgeTransaction memory) {\n // Try decoding into V2 struct first. This will revert if V1 struct is passed.\n try this.getBridgeTransactionV2(request) returns (BridgeTransactionV2 memory txV2) {\n // Note: we entirely ignore the zapData field, as it was not present in V1.\n return BridgeTransaction({\n originChainId: txV2.originChainId,\n destChainId: txV2.destChainId,\n originSender: txV2.originSender,\n destRecipient: txV2.destRecipient,\n originToken: txV2.originToken,\n destToken: txV2.destToken,\n originAmount: txV2.originAmount,\n destAmount: txV2.destAmount,\n originFeeAmount: txV2.originFeeAmount,\n sendChainGas: txV2.zapNative != 0,\n deadline: txV2.deadline,\n nonce: txV2.nonce\n });\n } catch {\n // Fallback to V1 struct.\n return abi.decode(request, (BridgeTransaction));\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function getBridgeTransactionV2(bytes calldata request) external pure returns (BridgeTransactionV2 memory) {\n request.validateV2();\n return BridgeTransactionV2Lib.decodeV2(request);\n }\n\n // ═══════════════════════════════════════ PUBLIC MUTABLE (USER FACING) ════════════════════════════════════════════\n\n /// @inheritdoc IFastBridgeV2\n function bridgeV2(BridgeParams memory params, BridgeParamsV2 memory paramsV2) public payable {\n // If relayer exclusivity is not intended for this bridge, set exclusivityEndTime to static zero.\n // Otherwise, set exclusivity to expire at the current block ts offset by quoteExclusivitySeconds.\n int256 exclusivityEndTime = 0;\n if (paramsV2.quoteRelayer != address(0)) {\n exclusivityEndTime = int256(block.timestamp) + paramsV2.quoteExclusivitySeconds;\n }\n _validateBridgeParams(params, paramsV2, exclusivityEndTime);\n\n // Transfer tokens to bridge contract. We use the actual transferred amount in case of transfer fees.\n uint256 originAmount = _takeBridgedUserAsset(params.originToken, params.originAmount);\n\n // Track the amount of origin token owed to protocol.\n uint256 originFeeAmount = 0;\n if (protocolFeeRate \u003e 0) {\n originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n // The Relayer filling this request will be paid the originAmount after fees.\n // Note: the protocol fees will be accumulated only when the Relayer claims the origin collateral.\n originAmount -= originFeeAmount;\n }\n\n // Hash the bridge request and set the initial status to REQUESTED.\n bytes memory request = BridgeTransactionV2Lib.encodeV2(\n BridgeTransactionV2({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n deadline: params.deadline,\n // Increment the sender's nonce on every bridge.\n nonce: senderNonces[params.sender]++,\n exclusivityRelayer: paramsV2.quoteRelayer,\n // We checked exclusivityEndTime to be in range [0 .. params.deadline] above, so can safely cast.\n exclusivityEndTime: uint256(exclusivityEndTime),\n zapNative: paramsV2.zapNative,\n zapData: paramsV2.zapData\n })\n );\n bytes32 transactionId = keccak256(request);\n // Note: the tx status will be updated throughout the tx lifecycle, while destChainId is set once here.\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n bridgeTxDetails[transactionId].destChainId = params.dstChainId;\n\n emit BridgeRequested({\n transactionId: transactionId,\n sender: params.sender,\n request: request,\n destChainId: params.dstChainId,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n sendChainGas: paramsV2.zapNative != 0\n });\n emit BridgeQuoteDetails(transactionId, paramsV2.quoteId);\n }\n\n /// @inheritdoc IFastBridgeV2\n function cancelV2(bytes calldata request) public {\n // Decode the request and check that it could be cancelled.\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n\n // Can only cancel a REQUESTED transaction after its deadline expires.\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n if ($.status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n\n // Permissionless cancel is only allowed after `cancelDelay` on top of the deadline.\n uint256 deadline = request.deadline();\n if (!hasRole(CANCELER_ROLE, msg.sender)) deadline += cancelDelay;\n if (block.timestamp \u003c= deadline) revert DeadlineNotExceeded();\n\n // Update status to REFUNDED.\n // Note: this is a storage write.\n $.status = BridgeStatus.REFUNDED;\n\n // Return the full amount (collateral + protocol fees) to the original sender.\n // The protocol fees are only accumulated when the transaction is claimed, so we don't need to update them here.\n address to = request.originSender();\n address token = request.originToken();\n uint256 amount = request.originAmount() + request.originFeeAmount();\n\n // Emit the event before any external calls.\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n\n // Return the funds to the original sender as last transaction action.\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(to), amount);\n } else {\n IERC20(token).safeTransfer(to, amount);\n }\n }\n\n // ═══════════════════════════════════════ PUBLIC MUTABLE (AGENT FACING) ═══════════════════════════════════════════\n\n /// @inheritdoc IFastBridgeV2\n function relayV2(bytes calldata request, address relayer) public payable {\n // Decode the request and check that it could be relayed.\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n _validateRelayParams(request, transactionId, relayer);\n\n // Mark the bridge request as relayed by saving the relayer and the block details.\n bridgeRelayDetails[transactionId].blockNumber = uint48(block.number);\n bridgeRelayDetails[transactionId].blockTimestamp = uint48(block.timestamp);\n bridgeRelayDetails[transactionId].relayer = relayer;\n\n // Transfer tokens to recipient on destination chain and trigger Zap if requested.\n address to = request.destRecipient();\n address token = request.destToken();\n uint256 amount = request.destAmount();\n uint256 zapNative = request.zapNative();\n\n // Emit the event before any external calls.\n emit BridgeRelayed({\n transactionId: transactionId,\n relayer: relayer,\n to: to,\n originChainId: request.originChainId(),\n originToken: request.originToken(),\n destToken: token,\n originAmount: request.originAmount(),\n destAmount: amount,\n chainGasAmount: zapNative\n });\n\n // All state changes have been done at this point, can proceed to the external calls.\n // This follows the checks-effects-interactions pattern to mitigate potential reentrancy attacks.\n if (token == NATIVE_GAS_TOKEN) {\n // For the native gas token, additional zapNative is not allowed.\n if (zapNative != 0) revert ZapNativeNotSupported();\n // Check that the correct msg.value was sent.\n if (msg.value != amount) revert MsgValueIncorrect();\n // Don't do a native transfer yet: we will handle it alongside the Zap below.\n } else {\n // For ERC20s, we check that the correct msg.value was sent.\n if (msg.value != zapNative) revert MsgValueIncorrect();\n // We need to transfer the tokens from the Relayer to the recipient first before performing an\n // optional post-transfer Zap.\n IERC20(token).safeTransferFrom(msg.sender, to, amount);\n }\n // At this point we have done:\n // - Transferred the requested amount of ERC20 tokens to the recipient.\n // At this point we have confirmed:\n // - For ERC20s: msg.value matches the requested zapNative amount.\n // - For the native gas token: msg.value matches the requested destAmount.\n // Remaining optional things to do:\n // - Forward the full msg.value to the recipient (if non-zero).\n // - Trigger a Zap (if zapData is present).\n bytes calldata zapData = request.zapData();\n if (zapData.length != 0) {\n // Zap Data is present: Zap has been requested by the recipient. Trigger it forwarding the full msg.value.\n _triggerZapWithChecks({recipient: to, token: token, amount: amount, zapData: zapData});\n // Note: if token has a fee on transfers, the recipient will have received less than `amount`.\n // This is a very niche edge case and should be handled by the recipient contract.\n } else if (msg.value != 0) {\n // Zap Data is missing, but msg.value was sent. This could happen in two different cases:\n // - Relay with the native gas token is happening.\n // - Relay with ERC20 is happening, with a `zapNative \u003e 0` request.\n // In both cases, we need to transfer the full msg.value to the recipient.\n Address.sendValue(payable(to), msg.value);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function proveV2(bytes32 transactionId, bytes32 destTxHash, address relayer) public onlyRole(PROVER_ROLE) {\n // Can only prove a REQUESTED transaction.\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n if ($.status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n\n // Update status to RELAYER_PROVED and store the proof details.\n // Note: these are storage writes.\n $.status = BridgeStatus.RELAYER_PROVED;\n $.proofBlockTimestamp = uint56(block.timestamp);\n $.proofRelayer = relayer;\n\n emit BridgeProofProvided(transactionId, relayer, destTxHash);\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes calldata request, address to) public {\n // Decode the request and check that it could be claimed.\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n\n // Aggregate the read operations from the same storage slot.\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n address proofRelayer = $.proofRelayer;\n BridgeStatus status = $.status;\n uint56 proofBlockTimestamp = $.proofBlockTimestamp;\n\n // Can only claim a RELAYER_PROVED transaction after the dispute period.\n if (status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(proofBlockTimestamp) \u003c= DISPUTE_PERIOD) revert DisputePeriodNotPassed();\n if (to == address(0)) {\n // Anyone could claim the funds to the proven relayer on their behalf.\n to = proofRelayer;\n } else if (proofRelayer != msg.sender) {\n // Only the proven relayer could specify an address to claim the funds to.\n revert SenderIncorrect();\n }\n\n // Update status to RELAYER_CLAIMED and transfer the origin collateral to the specified claim address.\n // Note: this is a storage write.\n $.status = BridgeStatus.RELAYER_CLAIMED;\n\n // Accumulate protocol fees if origin fee amount exists.\n address token = request.originToken();\n uint256 amount = request.originAmount();\n uint256 originFeeAmount = request.originFeeAmount();\n if (originFeeAmount \u003e 0) protocolFees[token] += originFeeAmount;\n\n // Emit the event before any external calls.\n emit BridgeDepositClaimed(transactionId, proofRelayer, to, token, amount);\n\n // Complete the relayer claim as the last transaction action.\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(to), amount);\n } else {\n IERC20(token).safeTransfer(to, amount);\n }\n }\n\n // ═══════════════════════════════════════════════ PUBLIC VIEWS ════════════════════════════════════════════════════\n\n /// @inheritdoc IFastBridgeV2\n function bridgeStatuses(bytes32 transactionId) public view returns (BridgeStatus status) {\n return bridgeTxDetails[transactionId].status;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeProofs(bytes32 transactionId) public view returns (uint96 timestamp, address relayer) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n timestamp = $.proofBlockTimestamp;\n relayer = $.proofRelayer;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeRelays(bytes32 transactionId) public view returns (bool) {\n // This transaction has been relayed if the relayer address is recorded.\n return bridgeRelayDetails[transactionId].relayer != address(0);\n }\n\n // ═════════════════════════════════════════════ INTERNAL METHODS ══════════════════════════════════════════════════\n\n /// @notice Takes the bridged asset from the user into FastBridgeV2 custody. The asset will later be\n /// claimed by the relayer who completed the relay on the destination chain, or returned to the user\n /// via the cancel function if no relay is completed.\n function _takeBridgedUserAsset(address token, uint256 amount) internal returns (uint256 amountTaken) {\n if (token == NATIVE_GAS_TOKEN) {\n // For the native gas token, we just need to check that the supplied msg.value is correct.\n // Supplied `msg.value` is already in FastBridgeV2 custody.\n if (amount != msg.value) revert MsgValueIncorrect();\n amountTaken = msg.value;\n } else {\n // For ERC20s, token is explicitly transferred from the user to FastBridgeV2.\n // We don't allow non-zero `msg.value` to avoid extra funds from being stuck in FastBridgeV2.\n if (msg.value != 0) revert MsgValueIncorrect();\n // Throw an explicit error if the provided token address is not a contract.\n if (token.code.length == 0) revert TokenNotContract();\n\n // Use the balance difference as the amount taken in case of fee on transfer tokens.\n amountTaken = IERC20(token).balanceOf(address(this));\n IERC20(token).safeTransferFrom(msg.sender, address(this), amount);\n amountTaken = IERC20(token).balanceOf(address(this)) - amountTaken;\n }\n }\n\n /// @notice Calls the recipient's hook function with the specified zapData and validates\n /// the returned value.\n function _triggerZapWithChecks(address recipient, address token, uint256 amount, bytes calldata zapData) internal {\n // Call the recipient's hook function with the specified zapData, bubbling any revert messages.\n bytes memory returnData = Address.functionCallWithValue({\n target: recipient,\n data: abi.encodeCall(IZapRecipient.zap, (token, amount, zapData)),\n // Note: see `relay()` for reasoning behind passing msg.value.\n value: msg.value\n });\n\n // Explicit revert if no return data at all.\n if (returnData.length == 0) revert RecipientNoReturnValue();\n // Check that exactly a single return value was returned.\n if (returnData.length != 32) revert RecipientIncorrectReturnValue();\n // Return value should be abi-encoded hook function selector.\n if (bytes32(returnData) != bytes32(IZapRecipient.zap.selector)) {\n revert RecipientIncorrectReturnValue();\n }\n }\n\n /// @notice Calculates the time elapsed since a proof was submitted.\n /// @dev The proof.timestamp stores block timestamps as uint56 for gas optimization.\n /// _timeSince(proof) handles timestamp rollover when block.timestamp \u003e type(uint56).max but\n /// proof.timestamp \u003c type(uint56).max via an unchecked statement.\n /// @param proofBlockTimestamp The block timestamp when the proof was submitted.\n /// @return delta The time elapsed since proof submission.\n function _timeSince(uint56 proofBlockTimestamp) internal view returns (uint256 delta) {\n unchecked {\n delta = uint56(block.timestamp) - proofBlockTimestamp;\n }\n }\n\n /// @notice Validates all parameters required for a bridge transaction.\n /// @dev This function's complexity cannot be reduced due to the number of required checks,\n /// so we disable the code-complexity rule.\n // solhint-disable-next-line code-complexity\n function _validateBridgeParams(\n BridgeParams memory params,\n BridgeParamsV2 memory paramsV2,\n int256 exclusivityEndTime\n )\n internal\n view\n {\n // Check V1 (legacy) params.\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.sender == address(0) || params.to == address(0)) revert ZeroAddress();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n\n // Check V2 params.\n if (paramsV2.zapData.length \u003e MAX_ZAP_DATA_LENGTH) revert ZapDataLengthAboveMax();\n if (paramsV2.zapNative != 0 \u0026\u0026 params.destToken == NATIVE_GAS_TOKEN) {\n revert ZapNativeNotSupported();\n }\n\n // exclusivityEndTime must be in range [0 .. params.deadline].\n if (exclusivityEndTime \u003c 0 || exclusivityEndTime \u003e int256(params.deadline)) {\n revert ExclusivityParamsIncorrect();\n }\n }\n\n /// @notice Validates all parameters required for a relay transaction.\n function _validateRelayParams(bytes calldata request, bytes32 transactionId, address relayer) internal view {\n if (relayer == address(0)) revert ZeroAddress();\n // Check that the transaction has not been relayed yet and is for the current chain.\n if (bridgeRelays(transactionId)) revert TransactionRelayed();\n if (request.destChainId() != block.chainid) revert ChainIncorrect();\n // Check that the deadline for relay to happen has not passed yet.\n if (block.timestamp \u003e request.deadline()) revert DeadlineExceeded();\n // Check the exclusivity period, if it was specified and is still ongoing.\n address exclRelayer = request.exclusivityRelayer();\n if (exclRelayer != address(0) \u0026\u0026 exclRelayer != relayer \u0026\u0026 block.timestamp \u003c= request.exclusivityEndTime()) {\n revert ExclusivityPeriodNotPassed();\n }\n }\n}\n","language":"Solidity","languageVersion":"0.8.24","compilerVersion":"0.8.24","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"","srcMapRuntime":"","abiDefinition":[{"inputs":[],"name":"AmountIncorrect","type":"error"},{"inputs":[],"name":"ChainIncorrect","type":"error"},{"inputs":[],"name":"DeadlineExceeded","type":"error"},{"inputs":[],"name":"DeadlineNotExceeded","type":"error"},{"inputs":[],"name":"DeadlineTooShort","type":"error"},{"inputs":[],"name":"DisputePeriodNotPassed","type":"error"},{"inputs":[],"name":"DisputePeriodPassed","type":"error"},{"inputs":[],"name":"ExclusivityParamsIncorrect","type":"error"},{"inputs":[],"name":"ExclusivityPeriodNotPassed","type":"error"},{"inputs":[],"name":"MsgValueIncorrect","type":"error"},{"inputs":[],"name":"RecipientIncorrectReturnValue","type":"error"},{"inputs":[],"name":"RecipientNoReturnValue","type":"error"},{"inputs":[],"name":"SenderIncorrect","type":"error"},{"inputs":[],"name":"StatusIncorrect","type":"error"},{"inputs":[],"name":"TokenNotContract","type":"error"},{"inputs":[],"name":"TransactionRelayed","type":"error"},{"inputs":[],"name":"ZapDataLengthAboveMax","type":"error"},{"inputs":[],"name":"ZapNativeNotSupported","type":"error"},{"inputs":[],"name":"ZeroAddress","type":"error"}],"userDoc":{"kind":"user","methods":{},"version":1},"developerDoc":{"kind":"dev","methods":{},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[],\"name\":\"AmountIncorrect\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ChainIncorrect\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DeadlineExceeded\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DeadlineNotExceeded\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DeadlineTooShort\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DisputePeriodNotPassed\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DisputePeriodPassed\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ExclusivityParamsIncorrect\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ExclusivityPeriodNotPassed\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"MsgValueIncorrect\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"RecipientIncorrectReturnValue\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"RecipientNoReturnValue\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"SenderIncorrect\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"StatusIncorrect\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"TokenNotContract\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"TransactionRelayed\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ZapDataLengthAboveMax\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ZapNativeNotSupported\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ZeroAddress\",\"type\":\"error\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeV2.sol\":\"IFastBridgeV2Errors\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeV2.sol\":{\"keccak256\":\"0xaab2ee7357681726f0faf799a48ddfbf45fb4da93b69abf61c33dde92b29b74d\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://673391bff9569efc0f9bd99e0e6fece0bc8e8af1f052bb071b407b267a17b3b5\",\"dweb:/ipfs/QmdQQZ6DxpJYhfpinwU5WjLugr2f6qP8h68b5GerhSMQ4j\"]}},\"version\":1}"},"hashes":{}},"solidity/FastBridgeV2.sol:IMulticallTarget":{"code":"0x","runtime-code":"0x","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.24 ^0.8.20 ^0.8.4;\n\n// contracts/interfaces/IAdminV2.sol\n\ninterface IAdminV2 {\n event CancelDelayUpdated(uint256 oldCancelDelay, uint256 newCancelDelay);\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n /// @notice Allows the governor to set the cancel delay. The cancel delay is the time period after the transaction\n /// deadline during which a transaction can be permissionlessly cancelled if it hasn't been proven by any Relayer.\n function setCancelDelay(uint256 newCancelDelay) external;\n\n /// @notice Allows the governor to set the protocol fee rate. The protocol fee is taken from the origin\n /// amount and is only applied to completed and claimed transactions.\n /// @dev The protocol fee is abstracted away from the relayers; they always operate using the amounts after fees.\n /// The origin amount they see in the emitted log is what they get credited with.\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n /// @notice Allows the governor to withdraw the accumulated protocol fees from the contract.\n function sweepProtocolFees(address token, address recipient) external;\n}\n\n// contracts/interfaces/IAdminV2Errors.sol\n\ninterface IAdminV2Errors {\n error CancelDelayBelowMin();\n error FeeRateAboveMax();\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IFastBridgeV2Errors.sol\n\ninterface IFastBridgeV2Errors {\n error AmountIncorrect();\n error ChainIncorrect();\n error ExclusivityParamsIncorrect();\n error MsgValueIncorrect();\n error SenderIncorrect();\n error StatusIncorrect();\n error TokenNotContract();\n error ZapDataLengthAboveMax();\n error ZapNativeNotSupported();\n error ZeroAddress();\n\n error RecipientIncorrectReturnValue();\n error RecipientNoReturnValue();\n\n error DeadlineExceeded();\n error DeadlineNotExceeded();\n error DeadlineTooShort();\n error DisputePeriodNotPassed();\n error DisputePeriodPassed();\n error ExclusivityPeriodNotPassed();\n\n error TransactionRelayed();\n}\n\n// contracts/interfaces/IMulticallTarget.sol\n\n/// @notice Interface for a contract that supports multiple calls from the same caller. Inspired by MulticallV3:\n/// https://github.com/mds1/multicall/blob/master/src/Multicall3.sol\ninterface IMulticallTarget {\n struct Result {\n bool success;\n bytes returnData;\n }\n\n /// @notice Executes multiple calls to this contract in a single transaction while preserving msg.sender.\n /// Return data from the calls is discarded.\n /// @dev This method is non-payable, so only calls with msg.value of 0 can be batched.\n /// If ignoreReverts is set to true, reverted calls will be skipped.\n /// Otherwise, the entire batch will revert with the original revert reason.\n /// @param data List of ABI-encoded calldata for the calls to execute\n /// @param ignoreReverts Whether to skip calls that revert\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external;\n\n /// @notice Executes multiple calls to this contract in a single transaction while preserving msg.sender.\n /// Return data from each call is preserved.\n /// @dev This method is non-payable, so only calls with msg.value of 0 can be batched.\n /// If ignoreReverts is set to true, reverted calls will be skipped.\n /// Otherwise, the entire batch will revert with the original revert reason.\n /// @param data List of ABI-encoded calldata for the calls to execute\n /// @param ignoreReverts Whether to skip calls that revert\n /// @return results List of results from the calls, each containing (success, returnData)\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results);\n}\n\n// contracts/interfaces/IZapRecipient.sol\n\n/// @notice Interface for contracts that can perform Zap operations. Such contracts could be used as Recipients\n/// in a FastBridge transaction that includes a Zap operation. The Zap Data should include instructions on how\n/// exactly the Zap operation should be executed, which would typically include the target address and calldata\n/// to use. The exact implementation of the Zap Data encoding is up to the Recipient contract.\ninterface IZapRecipient {\n /// @notice Performs a Zap operation with the given token and amount according to the provided Zap data.\n /// @param token The address of the token being used for the Zap operation.\n /// @param amount The amount of tokens to be used.\n /// @param zapData The encoded data specifying how the Zap operation should be executed.\n /// @return The function selector to indicate successful execution.\n function zap(address token, uint256 amount, bytes memory zapData) external payable returns (bytes4);\n}\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// contracts/interfaces/IFastBridgeV2.sol\n\ninterface IFastBridgeV2 is IFastBridge {\n enum BridgeStatus {\n NULL, // Doesn't exist yet.\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n struct BridgeTxDetails {\n BridgeStatus status;\n uint32 destChainId;\n uint56 proofBlockTimestamp;\n address proofRelayer;\n }\n\n struct BridgeRelay {\n uint48 blockNumber;\n uint48 blockTimestamp;\n address relayer;\n }\n\n /// @notice New params introduced in the FastBridgeV2.\n /// We are passing fields from the older BridgeParams struct outside of this struct for backwards compatibility.\n /// Note: quoteRelayer and quoteExclusivitySeconds are either both zero (indicating no exclusivity)\n /// or both non-zero (indicating exclusivity for the given period).\n /// Note: zapNative \u003e 0 can NOT be used with destToken = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE (native token)\n /// @param quoteRelayer Relayer that provided the quote for the transaction\n /// @param quoteExclusivitySeconds Period of time the quote relayer is guaranteed exclusivity after user's deposit\n /// @param quoteId Unique quote identifier used for tracking the quote\n /// @param zapNative ETH value to send to the recipient (if any)\n /// @param zapData Parameters for the Zap to the destination recipient (if any)\n struct BridgeParamsV2 {\n address quoteRelayer;\n int256 quoteExclusivitySeconds;\n bytes quoteId;\n uint256 zapNative;\n bytes zapData;\n }\n\n /// @notice Updated bridge transaction struct to include parameters introduced in FastBridgeV2.\n /// Note: only `exclusivityRelayer` can fill such a transaction until `exclusivityEndTime`.\n struct BridgeTransactionV2 {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n // Note: sendChainGas flag from V1 is deprecated\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n address exclusivityRelayer;\n uint256 exclusivityEndTime;\n uint256 zapNative; // ETH value to send to the recipient (if any)\n bytes zapData; // data to pass for the Zap action (if any)\n }\n\n event BridgeQuoteDetails(bytes32 indexed transactionId, bytes quoteId);\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability\n /// to provide temporary exclusivity fill rights for the quote relayer.\n /// @param params The parameters required to bridge\n /// @param paramsV2 The parameters for exclusivity fill rights (optional, can be left empty)\n function bridgeV2(BridgeParams memory params, BridgeParamsV2 memory paramsV2) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function relayV2(bytes memory request, address relayer) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param transactionId The transaction id associated with the encoded bridge transaction to prove\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function proveV2(bytes32 transactionId, bytes32 destTxHash, address relayer) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital.\n /// @notice Can only send funds to the relayer address on the proof.\n /// @param request The encoded bridge transaction to claim on origin chain\n function claimV2(bytes memory request) external;\n\n /// @notice Cancels an outstanding bridge transaction in case optimistic bridging failed and returns the full amount\n /// to the original sender.\n /// @param request The encoded bridge transaction to refund\n function cancelV2(bytes memory request) external;\n\n /// @notice Checks if a transaction has been relayed\n /// @param transactionId The ID of the transaction to check\n /// @return True if the transaction has been relayed, false otherwise\n function bridgeRelays(bytes32 transactionId) external view returns (bool);\n\n /// @notice Returns the status of a bridge transaction\n /// @param transactionId The ID of the bridge transaction\n /// @return BridgeStatus Status of the bridge transaction\n function bridgeStatuses(bytes32 transactionId) external view returns (BridgeStatus);\n\n /// @notice Returns the timestamp and relayer of a bridge proof\n /// @param transactionId The ID of the bridge transaction\n /// @return timestamp The timestamp of the bridge proof\n /// @return relayer The relayer address of the bridge proof\n function bridgeProofs(bytes32 transactionId) external view returns (uint96 timestamp, address relayer);\n\n /// @notice Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\n /// @param request The bridge request to decode\n function getBridgeTransactionV2(bytes memory request) external view returns (BridgeTransactionV2 memory);\n}\n\n// contracts/utils/MulticallTarget.sol\n\n// solhint-disable avoid-low-level-calls\n/// @notice Abstract contract template that supports batched calls while preserving msg.sender.\n/// Only calls with msg.value of 0 can be batched.\nabstract contract MulticallTarget is IMulticallTarget {\n error MulticallTarget__UndeterminedRevert();\n\n /// @inheritdoc IMulticallTarget\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external {\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\n if (!success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(result);\n }\n }\n }\n\n /// @inheritdoc IMulticallTarget\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results)\n {\n results = new Result[](data.length);\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (results[i].success, results[i].returnData) = address(this).delegatecall(data[i]);\n if (!results[i].success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(results[i].returnData);\n }\n }\n }\n\n /// @dev Bubbles the revert message from the underlying call.\n /// Note: preserves the same custom error or revert string, if one was used.\n /// Source: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v5.0.2/contracts/utils/Address.sol#L143-L158\n function _bubbleRevert(bytes memory returnData) internal pure {\n // Look for revert reason and bubble it up if present\n if (returnData.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n // solhint-disable-next-line no-inline-assembly\n assembly {\n let returndata_size := mload(returnData)\n revert(add(32, returnData), returndata_size)\n }\n } else {\n revert MulticallTarget__UndeterminedRevert();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// contracts/libs/BridgeTransactionV2.sol\n\n// solhint-disable no-inline-assembly\nlibrary BridgeTransactionV2Lib {\n uint16 internal constant VERSION = 2;\n\n // Offsets of the fields in the packed BridgeTransactionV2 struct\n // uint16 version [000 .. 002)\n // uint32 originChainId [002 .. 006)\n // uint32 destChainId [006 .. 010)\n // address originSender [010 .. 030)\n // address destRecipient [030 .. 050)\n // address originToken [050 .. 070)\n // address destToken [070 .. 090)\n // uint256 originAmount [090 .. 122)\n // uint256 destAmount [122 .. 154)\n // uint256 originFeeAmount [154 .. 186)\n // uint256 deadline [186 .. 218)\n // uint256 nonce [218 .. 250)\n // address exclusivityRelayer [250 .. 270)\n // uint256 exclusivityEndTime [270 .. 302)\n // uint256 zapNative [302 .. 334)\n // bytes zapData [334 .. ***)\n\n // forgefmt: disable-start\n uint256 private constant OFFSET_ORIGIN_CHAIN_ID = 2;\n uint256 private constant OFFSET_DEST_CHAIN_ID = 6;\n uint256 private constant OFFSET_ORIGIN_SENDER = 10;\n uint256 private constant OFFSET_DEST_RECIPIENT = 30;\n uint256 private constant OFFSET_ORIGIN_TOKEN = 50;\n uint256 private constant OFFSET_DEST_TOKEN = 70;\n uint256 private constant OFFSET_ORIGIN_AMOUNT = 90;\n uint256 private constant OFFSET_DEST_AMOUNT = 122;\n uint256 private constant OFFSET_ORIGIN_FEE_AMOUNT = 154;\n uint256 private constant OFFSET_DEADLINE = 186;\n uint256 private constant OFFSET_NONCE = 218;\n uint256 private constant OFFSET_EXCLUSIVITY_RELAYER = 250;\n uint256 private constant OFFSET_EXCLUSIVITY_END_TIME = 270;\n uint256 private constant OFFSET_ZAP_NATIVE = 302;\n uint256 private constant OFFSET_ZAP_DATA = 334;\n // forgefmt: disable-end\n\n error BridgeTransactionV2__InvalidEncodedTx();\n error BridgeTransactionV2__UnsupportedVersion(uint16 version);\n\n /// @notice Validates that the encoded transaction is a tightly packed encoded payload for BridgeTransactionV2.\n /// @dev Checks the minimum length and the version, use this function before decoding any of the fields.\n function validateV2(bytes calldata encodedTx) internal pure {\n // Check the minimum length: must at least include all static fields.\n if (encodedTx.length \u003c OFFSET_ZAP_DATA) revert BridgeTransactionV2__InvalidEncodedTx();\n // Once we validated the length, we can be sure that the version field is present.\n uint16 version_ = version(encodedTx);\n if (version_ != VERSION) revert BridgeTransactionV2__UnsupportedVersion(version_);\n }\n\n /// @notice Encodes the BridgeTransactionV2 struct by tightly packing the fields.\n /// @dev `abi.decode` will not work as a result of the tightly packed fields. Use `decodeV2` to decode instead.\n function encodeV2(IFastBridgeV2.BridgeTransactionV2 memory bridgeTx) internal pure returns (bytes memory) {\n // We split the encoding into two parts to avoid stack-too-deep error\n bytes memory firstPart = abi.encodePacked(\n VERSION,\n bridgeTx.originChainId,\n bridgeTx.destChainId,\n bridgeTx.originSender,\n bridgeTx.destRecipient,\n bridgeTx.originToken,\n bridgeTx.destToken,\n bridgeTx.originAmount\n );\n return abi.encodePacked(\n firstPart,\n bridgeTx.destAmount,\n bridgeTx.originFeeAmount,\n // Note: we skip the deprecated `sendChainGas` flag, which was present in BridgeTransaction V1\n bridgeTx.deadline,\n bridgeTx.nonce,\n // New V2 fields: exclusivity\n bridgeTx.exclusivityRelayer,\n bridgeTx.exclusivityEndTime,\n // New V2 fields: Zap\n bridgeTx.zapNative,\n bridgeTx.zapData\n );\n }\n\n /// @notice Decodes the BridgeTransactionV2 struct from the encoded transaction.\n /// @dev Encoded BridgeTransactionV2 struct must be tightly packed.\n /// Use `validateV2` before decoding to ensure the encoded transaction is valid.\n function decodeV2(bytes calldata encodedTx)\n internal\n pure\n returns (IFastBridgeV2.BridgeTransactionV2 memory bridgeTx)\n {\n bridgeTx.originChainId = originChainId(encodedTx);\n bridgeTx.destChainId = destChainId(encodedTx);\n bridgeTx.originSender = originSender(encodedTx);\n bridgeTx.destRecipient = destRecipient(encodedTx);\n bridgeTx.originToken = originToken(encodedTx);\n bridgeTx.destToken = destToken(encodedTx);\n bridgeTx.originAmount = originAmount(encodedTx);\n bridgeTx.destAmount = destAmount(encodedTx);\n bridgeTx.originFeeAmount = originFeeAmount(encodedTx);\n bridgeTx.deadline = deadline(encodedTx);\n bridgeTx.nonce = nonce(encodedTx);\n bridgeTx.exclusivityRelayer = exclusivityRelayer(encodedTx);\n bridgeTx.exclusivityEndTime = exclusivityEndTime(encodedTx);\n bridgeTx.zapNative = zapNative(encodedTx);\n bridgeTx.zapData = zapData(encodedTx);\n }\n\n /// @notice Extracts the version from the encoded transaction.\n function version(bytes calldata encodedTx) internal pure returns (uint16 version_) {\n // Load 32 bytes from the start and shift it 240 bits to the right to get the highest 16 bits.\n assembly {\n version_ := shr(240, calldataload(encodedTx.offset))\n }\n }\n\n /// @notice Extracts the origin chain ID from the encoded transaction.\n function originChainId(bytes calldata encodedTx) internal pure returns (uint32 originChainId_) {\n // Load 32 bytes from the offset and shift it 224 bits to the right to get the highest 32 bits.\n assembly {\n originChainId_ := shr(224, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_CHAIN_ID)))\n }\n }\n\n /// @notice Extracts the destination chain ID from the encoded transaction.\n function destChainId(bytes calldata encodedTx) internal pure returns (uint32 destChainId_) {\n // Load 32 bytes from the offset and shift it 224 bits to the right to get the highest 32 bits.\n assembly {\n destChainId_ := shr(224, calldataload(add(encodedTx.offset, OFFSET_DEST_CHAIN_ID)))\n }\n }\n\n /// @notice Extracts the origin sender from the encoded transaction.\n function originSender(bytes calldata encodedTx) internal pure returns (address originSender_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n originSender_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_SENDER)))\n }\n }\n\n /// @notice Extracts the destination recipient from the encoded transaction.\n function destRecipient(bytes calldata encodedTx) internal pure returns (address destRecipient_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n destRecipient_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_DEST_RECIPIENT)))\n }\n }\n\n /// @notice Extracts the origin token from the encoded transaction.\n function originToken(bytes calldata encodedTx) internal pure returns (address originToken_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n originToken_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_TOKEN)))\n }\n }\n\n /// @notice Extracts the destination token from the encoded transaction.\n function destToken(bytes calldata encodedTx) internal pure returns (address destToken_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n destToken_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_DEST_TOKEN)))\n }\n }\n\n /// @notice Extracts the origin amount from the encoded transaction.\n function originAmount(bytes calldata encodedTx) internal pure returns (uint256 originAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n originAmount_ := calldataload(add(encodedTx.offset, OFFSET_ORIGIN_AMOUNT))\n }\n }\n\n /// @notice Extracts the destination amount from the encoded transaction.\n function destAmount(bytes calldata encodedTx) internal pure returns (uint256 destAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n destAmount_ := calldataload(add(encodedTx.offset, OFFSET_DEST_AMOUNT))\n }\n }\n\n /// @notice Extracts the origin fee amount from the encoded transaction.\n function originFeeAmount(bytes calldata encodedTx) internal pure returns (uint256 originFeeAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n originFeeAmount_ := calldataload(add(encodedTx.offset, OFFSET_ORIGIN_FEE_AMOUNT))\n }\n }\n\n /// @notice Extracts the deadline from the encoded transaction.\n function deadline(bytes calldata encodedTx) internal pure returns (uint256 deadline_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n deadline_ := calldataload(add(encodedTx.offset, OFFSET_DEADLINE))\n }\n }\n\n /// @notice Extracts the nonce from the encoded transaction.\n function nonce(bytes calldata encodedTx) internal pure returns (uint256 nonce_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n nonce_ := calldataload(add(encodedTx.offset, OFFSET_NONCE))\n }\n }\n\n /// @notice Extracts the exclusivity relayer from the encoded transaction.\n function exclusivityRelayer(bytes calldata encodedTx) internal pure returns (address exclusivityRelayer_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n exclusivityRelayer_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_EXCLUSIVITY_RELAYER)))\n }\n }\n\n /// @notice Extracts the exclusivity end time from the encoded transaction.\n function exclusivityEndTime(bytes calldata encodedTx) internal pure returns (uint256 exclusivityEndTime_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n exclusivityEndTime_ := calldataload(add(encodedTx.offset, OFFSET_EXCLUSIVITY_END_TIME))\n }\n }\n\n /// @notice Extracts the Zap's native value from the encoded transaction.\n function zapNative(bytes calldata encodedTx) internal pure returns (uint256 zapNative_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n zapNative_ := calldataload(add(encodedTx.offset, OFFSET_ZAP_NATIVE))\n }\n }\n\n /// @notice Extracts the Zap's data from the encoded transaction.\n function zapData(bytes calldata encodedTx) internal pure returns (bytes calldata zapData_) {\n zapData_ = encodedTx[OFFSET_ZAP_DATA:];\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/AdminV2.sol\n\n// ════════════════════════════════════════════════ INTERFACES ═════════════════════════════════════════════════════\n\n// ═════════════════════════════════════════════ EXTERNAL IMPORTS ══════════════════════════════════════════════════\n\n/// @title AdminV2\n/// @notice Provides administrative functions and controls for managing the FastBridgeV2 contract,\n/// including access control and configuration settings.\ncontract AdminV2 is AccessControlEnumerable, IAdminV2, IAdminV2Errors {\n using SafeERC20 for IERC20;\n\n /// @notice The address reserved for the native gas token (ETH on Ethereum and most L2s, AVAX on Avalanche, etc.).\n address public constant NATIVE_GAS_TOKEN = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice The role identifier for the Quoter API's off-chain authentication.\n /// @dev Only addresses with this role can post FastBridge quotes to the API.\n bytes32 public constant QUOTER_ROLE = keccak256(\"QUOTER_ROLE\");\n\n /// @notice The role identifier for the Prover's on-chain authentication in FastBridge.\n /// @dev Only addresses with this role can provide proofs that a FastBridge request has been relayed.\n bytes32 public constant PROVER_ROLE = keccak256(\"PROVER_ROLE\");\n\n /// @notice The role identifier for the Guard's on-chain authentication in FastBridge.\n /// @dev Only addresses with this role can dispute submitted relay proofs during the dispute period.\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n\n /// @notice The role identifier for the Canceler's on-chain authentication in FastBridge.\n /// @dev Only addresses with this role can cancel a FastBridge transaction without the cancel delay.\n bytes32 public constant CANCELER_ROLE = keccak256(\"CANCELER_ROLE\");\n\n /// @notice The role identifier for the Governor's on-chain administrative authority.\n /// @dev Only addresses with this role can perform administrative tasks within the contract.\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n /// @notice The denominator for fee rates, representing 100%.\n uint256 public constant FEE_BPS = 1e6;\n /// @notice The maximum protocol fee rate: 1% of the origin amount.\n uint256 public constant FEE_RATE_MAX = 0.01e6;\n\n /// @notice The minimum cancel delay that can be set by the governor.\n uint256 public constant MIN_CANCEL_DELAY = 1 hours;\n /// @notice The default cancel delay set during contract deployment.\n uint256 public constant DEFAULT_CANCEL_DELAY = 1 days;\n\n /// @notice The protocol fee rate taken on the origin amount deposited in the origin chain.\n uint256 public protocolFeeRate;\n\n /// @notice The accumulated protocol fee amounts.\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice The delay period after which a transaction can be permissionlessly cancelled.\n uint256 public cancelDelay;\n\n /// @notice This variable is deprecated and should not be used.\n /// @dev Use ZapNative V2 requests instead.\n uint256 public immutable chainGasAmount = 0;\n\n constructor(address defaultAdmin) {\n _grantRole(DEFAULT_ADMIN_ROLE, defaultAdmin);\n _setCancelDelay(DEFAULT_CANCEL_DELAY);\n }\n\n /// @inheritdoc IAdminV2\n function setCancelDelay(uint256 newCancelDelay) external onlyRole(GOVERNOR_ROLE) {\n _setCancelDelay(newCancelDelay);\n }\n\n /// @inheritdoc IAdminV2\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n if (newFeeRate \u003e FEE_RATE_MAX) revert FeeRateAboveMax();\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n /// @inheritdoc IAdminV2\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n // Early exit if no accumulated fees.\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return;\n // Reset the accumulated fees first.\n protocolFees[token] = 0;\n emit FeesSwept(token, recipient, feeAmount);\n // Sweep the fees as the last transaction action.\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(recipient), feeAmount);\n } else {\n IERC20(token).safeTransfer(recipient, feeAmount);\n }\n }\n\n /// @notice Internal logic to set the cancel delay. Security checks are performed outside of this function.\n /// @dev This function is marked as private to prevent child contracts from calling it directly.\n function _setCancelDelay(uint256 newCancelDelay) private {\n if (newCancelDelay \u003c MIN_CANCEL_DELAY) revert CancelDelayBelowMin();\n uint256 oldCancelDelay = cancelDelay;\n cancelDelay = newCancelDelay;\n emit CancelDelayUpdated(oldCancelDelay, newCancelDelay);\n }\n}\n\n// contracts/FastBridgeV2.sol\n\n// ════════════════════════════════════════════════ INTERFACES ═════════════════════════════════════════════════════\n\n// ═════════════════════════════════════════════ INTERNAL IMPORTS ══════════════════════════════════════════════════\n\n// ═════════════════════════════════════════════ EXTERNAL IMPORTS ══════════════════════════════════════════════════\n\n/// @title FastBridgeV2\n/// @notice Core component of the SynapseRFQ protocol, enabling Relayers (Solvers) to fulfill bridge requests.\n/// Supports ERC20 and native gas tokens, along with the Zap feature for executing actions on the destination chain.\n/// Users interact with the off-chain Quoter API to obtain a current quote for a bridge transaction.\n/// They then submit the bridge request with the quote to this contract, depositing their assets in escrow.\n/// Relayers can fulfill requests by relaying them to the destination chain and must prove fulfillment to claim funds.\n/// Guards monitor proofs and can dispute discrepancies.\n/// Users can reclaim funds by cancelling their requests if it has not been fulfilled within the specified deadline.\ncontract FastBridgeV2 is AdminV2, MulticallTarget, IFastBridgeV2, IFastBridgeV2Errors {\n using BridgeTransactionV2Lib for bytes;\n using SafeERC20 for IERC20;\n\n /// @notice The duration of the dispute period for relayed transactions.\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice The minimum required time between transaction request and deadline.\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n /// @notice The maximum allowed length for zapData.\n uint256 public constant MAX_ZAP_DATA_LENGTH = 2 ** 16 - 1;\n\n /// @notice Maps transaction IDs to bridge details (status, destination chain ID, proof timestamp, and relayer).\n /// Note: this is only stored for transactions having local chain as the origin chain.\n mapping(bytes32 =\u003e BridgeTxDetails) public bridgeTxDetails;\n /// @notice Maps transaction IDs to relay details (block number, block timestamp, and relayer).\n /// Note: this is only stored for transactions having local chain as the destination chain.\n mapping(bytes32 =\u003e BridgeRelay) public bridgeRelayDetails;\n /// @notice Maps sender addresses to their unique bridge nonce.\n mapping(address =\u003e uint256) public senderNonces;\n\n /// @notice This variable is deprecated and should not be used.\n /// @dev Replaced by senderNonces.\n uint256 public immutable nonce = 0;\n /// @notice The block number at which this contract was deployed.\n uint256 public immutable deployBlock;\n\n /// @notice Initializes the FastBridgeV2 contract with the provided default admin,\n /// sets the default cancel delay, and records the deploy block number.\n constructor(address defaultAdmin) AdminV2(defaultAdmin) {\n deployBlock = block.number;\n }\n\n // ══════════════════════════════════════ EXTERNAL MUTABLE (USER FACING) ═══════════════════════════════════════════\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n bridgeV2({\n params: params,\n paramsV2: BridgeParamsV2({\n quoteRelayer: address(0),\n quoteExclusivitySeconds: 0,\n quoteId: bytes(\"\"),\n zapNative: 0,\n zapData: bytes(\"\")\n })\n });\n }\n\n /// Note: this function is deprecated and will be removed in a future version.\n /// @dev Replaced by `cancel`.\n /// @inheritdoc IFastBridge\n function refund(bytes calldata request) external {\n cancelV2(request);\n }\n\n // ══════════════════════════════════════ EXTERNAL MUTABLE (AGENT FACING) ══════════════════════════════════════════\n\n /// @inheritdoc IFastBridge\n function relay(bytes calldata request) external payable {\n // `relay` override will validate the request.\n relayV2({request: request, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes calldata request, bytes32 destTxHash) external {\n request.validateV2();\n proveV2({transactionId: keccak256(request), destTxHash: destTxHash, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridgeV2\n function claimV2(bytes calldata request) external {\n // `claim` override will validate the request.\n claim({request: request, to: address(0)});\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n // Aggregate the read operations from the same storage slot.\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n address disputedRelayer = $.proofRelayer;\n BridgeStatus status = $.status;\n uint56 proofBlockTimestamp = $.proofBlockTimestamp;\n\n // Can only dispute a RELAYER_PROVED transaction within the dispute period.\n if (status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(proofBlockTimestamp) \u003e DISPUTE_PERIOD) {\n revert DisputePeriodPassed();\n }\n\n // Update status to REQUESTED and delete the disputed proof details.\n // Note: these are storage writes.\n $.status = BridgeStatus.REQUESTED;\n $.proofRelayer = address(0);\n $.proofBlockTimestamp = 0;\n\n emit BridgeProofDisputed(transactionId, disputedRelayer);\n }\n\n // ══════════════════════════════════════════════ EXTERNAL VIEWS ═══════════════════════════════════════════════════\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n // The correct relayer can only claim a RELAYER_PROVED transaction after the dispute period.\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n if ($.status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if ($.proofRelayer != relayer) revert SenderIncorrect();\n\n return _timeSince($.proofBlockTimestamp) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n /// @dev This method is added to achieve backwards compatibility with decoding requests into V1 structs:\n /// - `zapNative` is partially reported as a zero/non-zero flag\n /// - `zapData` is ignored\n /// In order to process all kinds of requests use getBridgeTransactionV2 instead.\n function getBridgeTransaction(bytes calldata request) external view returns (BridgeTransaction memory) {\n // Try decoding into V2 struct first. This will revert if V1 struct is passed.\n try this.getBridgeTransactionV2(request) returns (BridgeTransactionV2 memory txV2) {\n // Note: we entirely ignore the zapData field, as it was not present in V1.\n return BridgeTransaction({\n originChainId: txV2.originChainId,\n destChainId: txV2.destChainId,\n originSender: txV2.originSender,\n destRecipient: txV2.destRecipient,\n originToken: txV2.originToken,\n destToken: txV2.destToken,\n originAmount: txV2.originAmount,\n destAmount: txV2.destAmount,\n originFeeAmount: txV2.originFeeAmount,\n sendChainGas: txV2.zapNative != 0,\n deadline: txV2.deadline,\n nonce: txV2.nonce\n });\n } catch {\n // Fallback to V1 struct.\n return abi.decode(request, (BridgeTransaction));\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function getBridgeTransactionV2(bytes calldata request) external pure returns (BridgeTransactionV2 memory) {\n request.validateV2();\n return BridgeTransactionV2Lib.decodeV2(request);\n }\n\n // ═══════════════════════════════════════ PUBLIC MUTABLE (USER FACING) ════════════════════════════════════════════\n\n /// @inheritdoc IFastBridgeV2\n function bridgeV2(BridgeParams memory params, BridgeParamsV2 memory paramsV2) public payable {\n // If relayer exclusivity is not intended for this bridge, set exclusivityEndTime to static zero.\n // Otherwise, set exclusivity to expire at the current block ts offset by quoteExclusivitySeconds.\n int256 exclusivityEndTime = 0;\n if (paramsV2.quoteRelayer != address(0)) {\n exclusivityEndTime = int256(block.timestamp) + paramsV2.quoteExclusivitySeconds;\n }\n _validateBridgeParams(params, paramsV2, exclusivityEndTime);\n\n // Transfer tokens to bridge contract. We use the actual transferred amount in case of transfer fees.\n uint256 originAmount = _takeBridgedUserAsset(params.originToken, params.originAmount);\n\n // Track the amount of origin token owed to protocol.\n uint256 originFeeAmount = 0;\n if (protocolFeeRate \u003e 0) {\n originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n // The Relayer filling this request will be paid the originAmount after fees.\n // Note: the protocol fees will be accumulated only when the Relayer claims the origin collateral.\n originAmount -= originFeeAmount;\n }\n\n // Hash the bridge request and set the initial status to REQUESTED.\n bytes memory request = BridgeTransactionV2Lib.encodeV2(\n BridgeTransactionV2({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n deadline: params.deadline,\n // Increment the sender's nonce on every bridge.\n nonce: senderNonces[params.sender]++,\n exclusivityRelayer: paramsV2.quoteRelayer,\n // We checked exclusivityEndTime to be in range [0 .. params.deadline] above, so can safely cast.\n exclusivityEndTime: uint256(exclusivityEndTime),\n zapNative: paramsV2.zapNative,\n zapData: paramsV2.zapData\n })\n );\n bytes32 transactionId = keccak256(request);\n // Note: the tx status will be updated throughout the tx lifecycle, while destChainId is set once here.\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n bridgeTxDetails[transactionId].destChainId = params.dstChainId;\n\n emit BridgeRequested({\n transactionId: transactionId,\n sender: params.sender,\n request: request,\n destChainId: params.dstChainId,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n sendChainGas: paramsV2.zapNative != 0\n });\n emit BridgeQuoteDetails(transactionId, paramsV2.quoteId);\n }\n\n /// @inheritdoc IFastBridgeV2\n function cancelV2(bytes calldata request) public {\n // Decode the request and check that it could be cancelled.\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n\n // Can only cancel a REQUESTED transaction after its deadline expires.\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n if ($.status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n\n // Permissionless cancel is only allowed after `cancelDelay` on top of the deadline.\n uint256 deadline = request.deadline();\n if (!hasRole(CANCELER_ROLE, msg.sender)) deadline += cancelDelay;\n if (block.timestamp \u003c= deadline) revert DeadlineNotExceeded();\n\n // Update status to REFUNDED.\n // Note: this is a storage write.\n $.status = BridgeStatus.REFUNDED;\n\n // Return the full amount (collateral + protocol fees) to the original sender.\n // The protocol fees are only accumulated when the transaction is claimed, so we don't need to update them here.\n address to = request.originSender();\n address token = request.originToken();\n uint256 amount = request.originAmount() + request.originFeeAmount();\n\n // Emit the event before any external calls.\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n\n // Return the funds to the original sender as last transaction action.\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(to), amount);\n } else {\n IERC20(token).safeTransfer(to, amount);\n }\n }\n\n // ═══════════════════════════════════════ PUBLIC MUTABLE (AGENT FACING) ═══════════════════════════════════════════\n\n /// @inheritdoc IFastBridgeV2\n function relayV2(bytes calldata request, address relayer) public payable {\n // Decode the request and check that it could be relayed.\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n _validateRelayParams(request, transactionId, relayer);\n\n // Mark the bridge request as relayed by saving the relayer and the block details.\n bridgeRelayDetails[transactionId].blockNumber = uint48(block.number);\n bridgeRelayDetails[transactionId].blockTimestamp = uint48(block.timestamp);\n bridgeRelayDetails[transactionId].relayer = relayer;\n\n // Transfer tokens to recipient on destination chain and trigger Zap if requested.\n address to = request.destRecipient();\n address token = request.destToken();\n uint256 amount = request.destAmount();\n uint256 zapNative = request.zapNative();\n\n // Emit the event before any external calls.\n emit BridgeRelayed({\n transactionId: transactionId,\n relayer: relayer,\n to: to,\n originChainId: request.originChainId(),\n originToken: request.originToken(),\n destToken: token,\n originAmount: request.originAmount(),\n destAmount: amount,\n chainGasAmount: zapNative\n });\n\n // All state changes have been done at this point, can proceed to the external calls.\n // This follows the checks-effects-interactions pattern to mitigate potential reentrancy attacks.\n if (token == NATIVE_GAS_TOKEN) {\n // For the native gas token, additional zapNative is not allowed.\n if (zapNative != 0) revert ZapNativeNotSupported();\n // Check that the correct msg.value was sent.\n if (msg.value != amount) revert MsgValueIncorrect();\n // Don't do a native transfer yet: we will handle it alongside the Zap below.\n } else {\n // For ERC20s, we check that the correct msg.value was sent.\n if (msg.value != zapNative) revert MsgValueIncorrect();\n // We need to transfer the tokens from the Relayer to the recipient first before performing an\n // optional post-transfer Zap.\n IERC20(token).safeTransferFrom(msg.sender, to, amount);\n }\n // At this point we have done:\n // - Transferred the requested amount of ERC20 tokens to the recipient.\n // At this point we have confirmed:\n // - For ERC20s: msg.value matches the requested zapNative amount.\n // - For the native gas token: msg.value matches the requested destAmount.\n // Remaining optional things to do:\n // - Forward the full msg.value to the recipient (if non-zero).\n // - Trigger a Zap (if zapData is present).\n bytes calldata zapData = request.zapData();\n if (zapData.length != 0) {\n // Zap Data is present: Zap has been requested by the recipient. Trigger it forwarding the full msg.value.\n _triggerZapWithChecks({recipient: to, token: token, amount: amount, zapData: zapData});\n // Note: if token has a fee on transfers, the recipient will have received less than `amount`.\n // This is a very niche edge case and should be handled by the recipient contract.\n } else if (msg.value != 0) {\n // Zap Data is missing, but msg.value was sent. This could happen in two different cases:\n // - Relay with the native gas token is happening.\n // - Relay with ERC20 is happening, with a `zapNative \u003e 0` request.\n // In both cases, we need to transfer the full msg.value to the recipient.\n Address.sendValue(payable(to), msg.value);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function proveV2(bytes32 transactionId, bytes32 destTxHash, address relayer) public onlyRole(PROVER_ROLE) {\n // Can only prove a REQUESTED transaction.\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n if ($.status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n\n // Update status to RELAYER_PROVED and store the proof details.\n // Note: these are storage writes.\n $.status = BridgeStatus.RELAYER_PROVED;\n $.proofBlockTimestamp = uint56(block.timestamp);\n $.proofRelayer = relayer;\n\n emit BridgeProofProvided(transactionId, relayer, destTxHash);\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes calldata request, address to) public {\n // Decode the request and check that it could be claimed.\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n\n // Aggregate the read operations from the same storage slot.\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n address proofRelayer = $.proofRelayer;\n BridgeStatus status = $.status;\n uint56 proofBlockTimestamp = $.proofBlockTimestamp;\n\n // Can only claim a RELAYER_PROVED transaction after the dispute period.\n if (status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(proofBlockTimestamp) \u003c= DISPUTE_PERIOD) revert DisputePeriodNotPassed();\n if (to == address(0)) {\n // Anyone could claim the funds to the proven relayer on their behalf.\n to = proofRelayer;\n } else if (proofRelayer != msg.sender) {\n // Only the proven relayer could specify an address to claim the funds to.\n revert SenderIncorrect();\n }\n\n // Update status to RELAYER_CLAIMED and transfer the origin collateral to the specified claim address.\n // Note: this is a storage write.\n $.status = BridgeStatus.RELAYER_CLAIMED;\n\n // Accumulate protocol fees if origin fee amount exists.\n address token = request.originToken();\n uint256 amount = request.originAmount();\n uint256 originFeeAmount = request.originFeeAmount();\n if (originFeeAmount \u003e 0) protocolFees[token] += originFeeAmount;\n\n // Emit the event before any external calls.\n emit BridgeDepositClaimed(transactionId, proofRelayer, to, token, amount);\n\n // Complete the relayer claim as the last transaction action.\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(to), amount);\n } else {\n IERC20(token).safeTransfer(to, amount);\n }\n }\n\n // ═══════════════════════════════════════════════ PUBLIC VIEWS ════════════════════════════════════════════════════\n\n /// @inheritdoc IFastBridgeV2\n function bridgeStatuses(bytes32 transactionId) public view returns (BridgeStatus status) {\n return bridgeTxDetails[transactionId].status;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeProofs(bytes32 transactionId) public view returns (uint96 timestamp, address relayer) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n timestamp = $.proofBlockTimestamp;\n relayer = $.proofRelayer;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeRelays(bytes32 transactionId) public view returns (bool) {\n // This transaction has been relayed if the relayer address is recorded.\n return bridgeRelayDetails[transactionId].relayer != address(0);\n }\n\n // ═════════════════════════════════════════════ INTERNAL METHODS ══════════════════════════════════════════════════\n\n /// @notice Takes the bridged asset from the user into FastBridgeV2 custody. The asset will later be\n /// claimed by the relayer who completed the relay on the destination chain, or returned to the user\n /// via the cancel function if no relay is completed.\n function _takeBridgedUserAsset(address token, uint256 amount) internal returns (uint256 amountTaken) {\n if (token == NATIVE_GAS_TOKEN) {\n // For the native gas token, we just need to check that the supplied msg.value is correct.\n // Supplied `msg.value` is already in FastBridgeV2 custody.\n if (amount != msg.value) revert MsgValueIncorrect();\n amountTaken = msg.value;\n } else {\n // For ERC20s, token is explicitly transferred from the user to FastBridgeV2.\n // We don't allow non-zero `msg.value` to avoid extra funds from being stuck in FastBridgeV2.\n if (msg.value != 0) revert MsgValueIncorrect();\n // Throw an explicit error if the provided token address is not a contract.\n if (token.code.length == 0) revert TokenNotContract();\n\n // Use the balance difference as the amount taken in case of fee on transfer tokens.\n amountTaken = IERC20(token).balanceOf(address(this));\n IERC20(token).safeTransferFrom(msg.sender, address(this), amount);\n amountTaken = IERC20(token).balanceOf(address(this)) - amountTaken;\n }\n }\n\n /// @notice Calls the recipient's hook function with the specified zapData and validates\n /// the returned value.\n function _triggerZapWithChecks(address recipient, address token, uint256 amount, bytes calldata zapData) internal {\n // Call the recipient's hook function with the specified zapData, bubbling any revert messages.\n bytes memory returnData = Address.functionCallWithValue({\n target: recipient,\n data: abi.encodeCall(IZapRecipient.zap, (token, amount, zapData)),\n // Note: see `relay()` for reasoning behind passing msg.value.\n value: msg.value\n });\n\n // Explicit revert if no return data at all.\n if (returnData.length == 0) revert RecipientNoReturnValue();\n // Check that exactly a single return value was returned.\n if (returnData.length != 32) revert RecipientIncorrectReturnValue();\n // Return value should be abi-encoded hook function selector.\n if (bytes32(returnData) != bytes32(IZapRecipient.zap.selector)) {\n revert RecipientIncorrectReturnValue();\n }\n }\n\n /// @notice Calculates the time elapsed since a proof was submitted.\n /// @dev The proof.timestamp stores block timestamps as uint56 for gas optimization.\n /// _timeSince(proof) handles timestamp rollover when block.timestamp \u003e type(uint56).max but\n /// proof.timestamp \u003c type(uint56).max via an unchecked statement.\n /// @param proofBlockTimestamp The block timestamp when the proof was submitted.\n /// @return delta The time elapsed since proof submission.\n function _timeSince(uint56 proofBlockTimestamp) internal view returns (uint256 delta) {\n unchecked {\n delta = uint56(block.timestamp) - proofBlockTimestamp;\n }\n }\n\n /// @notice Validates all parameters required for a bridge transaction.\n /// @dev This function's complexity cannot be reduced due to the number of required checks,\n /// so we disable the code-complexity rule.\n // solhint-disable-next-line code-complexity\n function _validateBridgeParams(\n BridgeParams memory params,\n BridgeParamsV2 memory paramsV2,\n int256 exclusivityEndTime\n )\n internal\n view\n {\n // Check V1 (legacy) params.\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.sender == address(0) || params.to == address(0)) revert ZeroAddress();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n\n // Check V2 params.\n if (paramsV2.zapData.length \u003e MAX_ZAP_DATA_LENGTH) revert ZapDataLengthAboveMax();\n if (paramsV2.zapNative != 0 \u0026\u0026 params.destToken == NATIVE_GAS_TOKEN) {\n revert ZapNativeNotSupported();\n }\n\n // exclusivityEndTime must be in range [0 .. params.deadline].\n if (exclusivityEndTime \u003c 0 || exclusivityEndTime \u003e int256(params.deadline)) {\n revert ExclusivityParamsIncorrect();\n }\n }\n\n /// @notice Validates all parameters required for a relay transaction.\n function _validateRelayParams(bytes calldata request, bytes32 transactionId, address relayer) internal view {\n if (relayer == address(0)) revert ZeroAddress();\n // Check that the transaction has not been relayed yet and is for the current chain.\n if (bridgeRelays(transactionId)) revert TransactionRelayed();\n if (request.destChainId() != block.chainid) revert ChainIncorrect();\n // Check that the deadline for relay to happen has not passed yet.\n if (block.timestamp \u003e request.deadline()) revert DeadlineExceeded();\n // Check the exclusivity period, if it was specified and is still ongoing.\n address exclRelayer = request.exclusivityRelayer();\n if (exclRelayer != address(0) \u0026\u0026 exclRelayer != relayer \u0026\u0026 block.timestamp \u003c= request.exclusivityEndTime()) {\n revert ExclusivityPeriodNotPassed();\n }\n }\n}\n","language":"Solidity","languageVersion":"0.8.24","compilerVersion":"0.8.24","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"","srcMapRuntime":"","abiDefinition":[{"inputs":[{"internalType":"bytes[]","name":"data","type":"bytes[]"},{"internalType":"bool","name":"ignoreReverts","type":"bool"}],"name":"multicallNoResults","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes[]","name":"data","type":"bytes[]"},{"internalType":"bool","name":"ignoreReverts","type":"bool"}],"name":"multicallWithResults","outputs":[{"components":[{"internalType":"bool","name":"success","type":"bool"},{"internalType":"bytes","name":"returnData","type":"bytes"}],"internalType":"struct IMulticallTarget.Result[]","name":"results","type":"tuple[]"}],"stateMutability":"nonpayable","type":"function"}],"userDoc":{"kind":"user","methods":{"multicallNoResults(bytes[],bool)":{"notice":"Executes multiple calls to this contract in a single transaction while preserving msg.sender. Return data from the calls is discarded."},"multicallWithResults(bytes[],bool)":{"notice":"Executes multiple calls to this contract in a single transaction while preserving msg.sender. Return data from each call is preserved."}},"notice":"Interface for a contract that supports multiple calls from the same caller. Inspired by MulticallV3: https://github.com/mds1/multicall/blob/master/src/Multicall3.sol","version":1},"developerDoc":{"kind":"dev","methods":{"multicallNoResults(bytes[],bool)":{"details":"This method is non-payable, so only calls with msg.value of 0 can be batched. If ignoreReverts is set to true, reverted calls will be skipped. Otherwise, the entire batch will revert with the original revert reason.","params":{"data":"List of ABI-encoded calldata for the calls to execute","ignoreReverts":"Whether to skip calls that revert"}},"multicallWithResults(bytes[],bool)":{"details":"This method is non-payable, so only calls with msg.value of 0 can be batched. If ignoreReverts is set to true, reverted calls will be skipped. Otherwise, the entire batch will revert with the original revert reason.","params":{"data":"List of ABI-encoded calldata for the calls to execute","ignoreReverts":"Whether to skip calls that revert"},"returns":{"results":" List of results from the calls, each containing (success, returnData)"}}},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"bytes[]\",\"name\":\"data\",\"type\":\"bytes[]\"},{\"internalType\":\"bool\",\"name\":\"ignoreReverts\",\"type\":\"bool\"}],\"name\":\"multicallNoResults\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes[]\",\"name\":\"data\",\"type\":\"bytes[]\"},{\"internalType\":\"bool\",\"name\":\"ignoreReverts\",\"type\":\"bool\"}],\"name\":\"multicallWithResults\",\"outputs\":[{\"components\":[{\"internalType\":\"bool\",\"name\":\"success\",\"type\":\"bool\"},{\"internalType\":\"bytes\",\"name\":\"returnData\",\"type\":\"bytes\"}],\"internalType\":\"struct IMulticallTarget.Result[]\",\"name\":\"results\",\"type\":\"tuple[]\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{\"multicallNoResults(bytes[],bool)\":{\"details\":\"This method is non-payable, so only calls with msg.value of 0 can be batched. If ignoreReverts is set to true, reverted calls will be skipped. Otherwise, the entire batch will revert with the original revert reason.\",\"params\":{\"data\":\"List of ABI-encoded calldata for the calls to execute\",\"ignoreReverts\":\"Whether to skip calls that revert\"}},\"multicallWithResults(bytes[],bool)\":{\"details\":\"This method is non-payable, so only calls with msg.value of 0 can be batched. If ignoreReverts is set to true, reverted calls will be skipped. Otherwise, the entire batch will revert with the original revert reason.\",\"params\":{\"data\":\"List of ABI-encoded calldata for the calls to execute\",\"ignoreReverts\":\"Whether to skip calls that revert\"},\"returns\":{\"results\":\" List of results from the calls, each containing (success, returnData)\"}}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"multicallNoResults(bytes[],bool)\":{\"notice\":\"Executes multiple calls to this contract in a single transaction while preserving msg.sender. Return data from the calls is discarded.\"},\"multicallWithResults(bytes[],bool)\":{\"notice\":\"Executes multiple calls to this contract in a single transaction while preserving msg.sender. Return data from each call is preserved.\"}},\"notice\":\"Interface for a contract that supports multiple calls from the same caller. Inspired by MulticallV3: https://github.com/mds1/multicall/blob/master/src/Multicall3.sol\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeV2.sol\":\"IMulticallTarget\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeV2.sol\":{\"keccak256\":\"0xaab2ee7357681726f0faf799a48ddfbf45fb4da93b69abf61c33dde92b29b74d\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://673391bff9569efc0f9bd99e0e6fece0bc8e8af1f052bb071b407b267a17b3b5\",\"dweb:/ipfs/QmdQQZ6DxpJYhfpinwU5WjLugr2f6qP8h68b5GerhSMQ4j\"]}},\"version\":1}"},"hashes":{"multicallNoResults(bytes[],bool)":"3f61331d","multicallWithResults(bytes[],bool)":"385c1d2f"}},"solidity/FastBridgeV2.sol:IZapRecipient":{"code":"0x","runtime-code":"0x","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.24 ^0.8.20 ^0.8.4;\n\n// contracts/interfaces/IAdminV2.sol\n\ninterface IAdminV2 {\n event CancelDelayUpdated(uint256 oldCancelDelay, uint256 newCancelDelay);\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n /// @notice Allows the governor to set the cancel delay. The cancel delay is the time period after the transaction\n /// deadline during which a transaction can be permissionlessly cancelled if it hasn't been proven by any Relayer.\n function setCancelDelay(uint256 newCancelDelay) external;\n\n /// @notice Allows the governor to set the protocol fee rate. The protocol fee is taken from the origin\n /// amount and is only applied to completed and claimed transactions.\n /// @dev The protocol fee is abstracted away from the relayers; they always operate using the amounts after fees.\n /// The origin amount they see in the emitted log is what they get credited with.\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n /// @notice Allows the governor to withdraw the accumulated protocol fees from the contract.\n function sweepProtocolFees(address token, address recipient) external;\n}\n\n// contracts/interfaces/IAdminV2Errors.sol\n\ninterface IAdminV2Errors {\n error CancelDelayBelowMin();\n error FeeRateAboveMax();\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IFastBridgeV2Errors.sol\n\ninterface IFastBridgeV2Errors {\n error AmountIncorrect();\n error ChainIncorrect();\n error ExclusivityParamsIncorrect();\n error MsgValueIncorrect();\n error SenderIncorrect();\n error StatusIncorrect();\n error TokenNotContract();\n error ZapDataLengthAboveMax();\n error ZapNativeNotSupported();\n error ZeroAddress();\n\n error RecipientIncorrectReturnValue();\n error RecipientNoReturnValue();\n\n error DeadlineExceeded();\n error DeadlineNotExceeded();\n error DeadlineTooShort();\n error DisputePeriodNotPassed();\n error DisputePeriodPassed();\n error ExclusivityPeriodNotPassed();\n\n error TransactionRelayed();\n}\n\n// contracts/interfaces/IMulticallTarget.sol\n\n/// @notice Interface for a contract that supports multiple calls from the same caller. Inspired by MulticallV3:\n/// https://github.com/mds1/multicall/blob/master/src/Multicall3.sol\ninterface IMulticallTarget {\n struct Result {\n bool success;\n bytes returnData;\n }\n\n /// @notice Executes multiple calls to this contract in a single transaction while preserving msg.sender.\n /// Return data from the calls is discarded.\n /// @dev This method is non-payable, so only calls with msg.value of 0 can be batched.\n /// If ignoreReverts is set to true, reverted calls will be skipped.\n /// Otherwise, the entire batch will revert with the original revert reason.\n /// @param data List of ABI-encoded calldata for the calls to execute\n /// @param ignoreReverts Whether to skip calls that revert\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external;\n\n /// @notice Executes multiple calls to this contract in a single transaction while preserving msg.sender.\n /// Return data from each call is preserved.\n /// @dev This method is non-payable, so only calls with msg.value of 0 can be batched.\n /// If ignoreReverts is set to true, reverted calls will be skipped.\n /// Otherwise, the entire batch will revert with the original revert reason.\n /// @param data List of ABI-encoded calldata for the calls to execute\n /// @param ignoreReverts Whether to skip calls that revert\n /// @return results List of results from the calls, each containing (success, returnData)\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results);\n}\n\n// contracts/interfaces/IZapRecipient.sol\n\n/// @notice Interface for contracts that can perform Zap operations. Such contracts could be used as Recipients\n/// in a FastBridge transaction that includes a Zap operation. The Zap Data should include instructions on how\n/// exactly the Zap operation should be executed, which would typically include the target address and calldata\n/// to use. The exact implementation of the Zap Data encoding is up to the Recipient contract.\ninterface IZapRecipient {\n /// @notice Performs a Zap operation with the given token and amount according to the provided Zap data.\n /// @param token The address of the token being used for the Zap operation.\n /// @param amount The amount of tokens to be used.\n /// @param zapData The encoded data specifying how the Zap operation should be executed.\n /// @return The function selector to indicate successful execution.\n function zap(address token, uint256 amount, bytes memory zapData) external payable returns (bytes4);\n}\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// contracts/interfaces/IFastBridgeV2.sol\n\ninterface IFastBridgeV2 is IFastBridge {\n enum BridgeStatus {\n NULL, // Doesn't exist yet.\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n struct BridgeTxDetails {\n BridgeStatus status;\n uint32 destChainId;\n uint56 proofBlockTimestamp;\n address proofRelayer;\n }\n\n struct BridgeRelay {\n uint48 blockNumber;\n uint48 blockTimestamp;\n address relayer;\n }\n\n /// @notice New params introduced in the FastBridgeV2.\n /// We are passing fields from the older BridgeParams struct outside of this struct for backwards compatibility.\n /// Note: quoteRelayer and quoteExclusivitySeconds are either both zero (indicating no exclusivity)\n /// or both non-zero (indicating exclusivity for the given period).\n /// Note: zapNative \u003e 0 can NOT be used with destToken = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE (native token)\n /// @param quoteRelayer Relayer that provided the quote for the transaction\n /// @param quoteExclusivitySeconds Period of time the quote relayer is guaranteed exclusivity after user's deposit\n /// @param quoteId Unique quote identifier used for tracking the quote\n /// @param zapNative ETH value to send to the recipient (if any)\n /// @param zapData Parameters for the Zap to the destination recipient (if any)\n struct BridgeParamsV2 {\n address quoteRelayer;\n int256 quoteExclusivitySeconds;\n bytes quoteId;\n uint256 zapNative;\n bytes zapData;\n }\n\n /// @notice Updated bridge transaction struct to include parameters introduced in FastBridgeV2.\n /// Note: only `exclusivityRelayer` can fill such a transaction until `exclusivityEndTime`.\n struct BridgeTransactionV2 {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n // Note: sendChainGas flag from V1 is deprecated\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n address exclusivityRelayer;\n uint256 exclusivityEndTime;\n uint256 zapNative; // ETH value to send to the recipient (if any)\n bytes zapData; // data to pass for the Zap action (if any)\n }\n\n event BridgeQuoteDetails(bytes32 indexed transactionId, bytes quoteId);\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability\n /// to provide temporary exclusivity fill rights for the quote relayer.\n /// @param params The parameters required to bridge\n /// @param paramsV2 The parameters for exclusivity fill rights (optional, can be left empty)\n function bridgeV2(BridgeParams memory params, BridgeParamsV2 memory paramsV2) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function relayV2(bytes memory request, address relayer) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param transactionId The transaction id associated with the encoded bridge transaction to prove\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function proveV2(bytes32 transactionId, bytes32 destTxHash, address relayer) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital.\n /// @notice Can only send funds to the relayer address on the proof.\n /// @param request The encoded bridge transaction to claim on origin chain\n function claimV2(bytes memory request) external;\n\n /// @notice Cancels an outstanding bridge transaction in case optimistic bridging failed and returns the full amount\n /// to the original sender.\n /// @param request The encoded bridge transaction to refund\n function cancelV2(bytes memory request) external;\n\n /// @notice Checks if a transaction has been relayed\n /// @param transactionId The ID of the transaction to check\n /// @return True if the transaction has been relayed, false otherwise\n function bridgeRelays(bytes32 transactionId) external view returns (bool);\n\n /// @notice Returns the status of a bridge transaction\n /// @param transactionId The ID of the bridge transaction\n /// @return BridgeStatus Status of the bridge transaction\n function bridgeStatuses(bytes32 transactionId) external view returns (BridgeStatus);\n\n /// @notice Returns the timestamp and relayer of a bridge proof\n /// @param transactionId The ID of the bridge transaction\n /// @return timestamp The timestamp of the bridge proof\n /// @return relayer The relayer address of the bridge proof\n function bridgeProofs(bytes32 transactionId) external view returns (uint96 timestamp, address relayer);\n\n /// @notice Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\n /// @param request The bridge request to decode\n function getBridgeTransactionV2(bytes memory request) external view returns (BridgeTransactionV2 memory);\n}\n\n// contracts/utils/MulticallTarget.sol\n\n// solhint-disable avoid-low-level-calls\n/// @notice Abstract contract template that supports batched calls while preserving msg.sender.\n/// Only calls with msg.value of 0 can be batched.\nabstract contract MulticallTarget is IMulticallTarget {\n error MulticallTarget__UndeterminedRevert();\n\n /// @inheritdoc IMulticallTarget\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external {\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\n if (!success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(result);\n }\n }\n }\n\n /// @inheritdoc IMulticallTarget\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results)\n {\n results = new Result[](data.length);\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (results[i].success, results[i].returnData) = address(this).delegatecall(data[i]);\n if (!results[i].success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(results[i].returnData);\n }\n }\n }\n\n /// @dev Bubbles the revert message from the underlying call.\n /// Note: preserves the same custom error or revert string, if one was used.\n /// Source: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v5.0.2/contracts/utils/Address.sol#L143-L158\n function _bubbleRevert(bytes memory returnData) internal pure {\n // Look for revert reason and bubble it up if present\n if (returnData.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n // solhint-disable-next-line no-inline-assembly\n assembly {\n let returndata_size := mload(returnData)\n revert(add(32, returnData), returndata_size)\n }\n } else {\n revert MulticallTarget__UndeterminedRevert();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// contracts/libs/BridgeTransactionV2.sol\n\n// solhint-disable no-inline-assembly\nlibrary BridgeTransactionV2Lib {\n uint16 internal constant VERSION = 2;\n\n // Offsets of the fields in the packed BridgeTransactionV2 struct\n // uint16 version [000 .. 002)\n // uint32 originChainId [002 .. 006)\n // uint32 destChainId [006 .. 010)\n // address originSender [010 .. 030)\n // address destRecipient [030 .. 050)\n // address originToken [050 .. 070)\n // address destToken [070 .. 090)\n // uint256 originAmount [090 .. 122)\n // uint256 destAmount [122 .. 154)\n // uint256 originFeeAmount [154 .. 186)\n // uint256 deadline [186 .. 218)\n // uint256 nonce [218 .. 250)\n // address exclusivityRelayer [250 .. 270)\n // uint256 exclusivityEndTime [270 .. 302)\n // uint256 zapNative [302 .. 334)\n // bytes zapData [334 .. ***)\n\n // forgefmt: disable-start\n uint256 private constant OFFSET_ORIGIN_CHAIN_ID = 2;\n uint256 private constant OFFSET_DEST_CHAIN_ID = 6;\n uint256 private constant OFFSET_ORIGIN_SENDER = 10;\n uint256 private constant OFFSET_DEST_RECIPIENT = 30;\n uint256 private constant OFFSET_ORIGIN_TOKEN = 50;\n uint256 private constant OFFSET_DEST_TOKEN = 70;\n uint256 private constant OFFSET_ORIGIN_AMOUNT = 90;\n uint256 private constant OFFSET_DEST_AMOUNT = 122;\n uint256 private constant OFFSET_ORIGIN_FEE_AMOUNT = 154;\n uint256 private constant OFFSET_DEADLINE = 186;\n uint256 private constant OFFSET_NONCE = 218;\n uint256 private constant OFFSET_EXCLUSIVITY_RELAYER = 250;\n uint256 private constant OFFSET_EXCLUSIVITY_END_TIME = 270;\n uint256 private constant OFFSET_ZAP_NATIVE = 302;\n uint256 private constant OFFSET_ZAP_DATA = 334;\n // forgefmt: disable-end\n\n error BridgeTransactionV2__InvalidEncodedTx();\n error BridgeTransactionV2__UnsupportedVersion(uint16 version);\n\n /// @notice Validates that the encoded transaction is a tightly packed encoded payload for BridgeTransactionV2.\n /// @dev Checks the minimum length and the version, use this function before decoding any of the fields.\n function validateV2(bytes calldata encodedTx) internal pure {\n // Check the minimum length: must at least include all static fields.\n if (encodedTx.length \u003c OFFSET_ZAP_DATA) revert BridgeTransactionV2__InvalidEncodedTx();\n // Once we validated the length, we can be sure that the version field is present.\n uint16 version_ = version(encodedTx);\n if (version_ != VERSION) revert BridgeTransactionV2__UnsupportedVersion(version_);\n }\n\n /// @notice Encodes the BridgeTransactionV2 struct by tightly packing the fields.\n /// @dev `abi.decode` will not work as a result of the tightly packed fields. Use `decodeV2` to decode instead.\n function encodeV2(IFastBridgeV2.BridgeTransactionV2 memory bridgeTx) internal pure returns (bytes memory) {\n // We split the encoding into two parts to avoid stack-too-deep error\n bytes memory firstPart = abi.encodePacked(\n VERSION,\n bridgeTx.originChainId,\n bridgeTx.destChainId,\n bridgeTx.originSender,\n bridgeTx.destRecipient,\n bridgeTx.originToken,\n bridgeTx.destToken,\n bridgeTx.originAmount\n );\n return abi.encodePacked(\n firstPart,\n bridgeTx.destAmount,\n bridgeTx.originFeeAmount,\n // Note: we skip the deprecated `sendChainGas` flag, which was present in BridgeTransaction V1\n bridgeTx.deadline,\n bridgeTx.nonce,\n // New V2 fields: exclusivity\n bridgeTx.exclusivityRelayer,\n bridgeTx.exclusivityEndTime,\n // New V2 fields: Zap\n bridgeTx.zapNative,\n bridgeTx.zapData\n );\n }\n\n /// @notice Decodes the BridgeTransactionV2 struct from the encoded transaction.\n /// @dev Encoded BridgeTransactionV2 struct must be tightly packed.\n /// Use `validateV2` before decoding to ensure the encoded transaction is valid.\n function decodeV2(bytes calldata encodedTx)\n internal\n pure\n returns (IFastBridgeV2.BridgeTransactionV2 memory bridgeTx)\n {\n bridgeTx.originChainId = originChainId(encodedTx);\n bridgeTx.destChainId = destChainId(encodedTx);\n bridgeTx.originSender = originSender(encodedTx);\n bridgeTx.destRecipient = destRecipient(encodedTx);\n bridgeTx.originToken = originToken(encodedTx);\n bridgeTx.destToken = destToken(encodedTx);\n bridgeTx.originAmount = originAmount(encodedTx);\n bridgeTx.destAmount = destAmount(encodedTx);\n bridgeTx.originFeeAmount = originFeeAmount(encodedTx);\n bridgeTx.deadline = deadline(encodedTx);\n bridgeTx.nonce = nonce(encodedTx);\n bridgeTx.exclusivityRelayer = exclusivityRelayer(encodedTx);\n bridgeTx.exclusivityEndTime = exclusivityEndTime(encodedTx);\n bridgeTx.zapNative = zapNative(encodedTx);\n bridgeTx.zapData = zapData(encodedTx);\n }\n\n /// @notice Extracts the version from the encoded transaction.\n function version(bytes calldata encodedTx) internal pure returns (uint16 version_) {\n // Load 32 bytes from the start and shift it 240 bits to the right to get the highest 16 bits.\n assembly {\n version_ := shr(240, calldataload(encodedTx.offset))\n }\n }\n\n /// @notice Extracts the origin chain ID from the encoded transaction.\n function originChainId(bytes calldata encodedTx) internal pure returns (uint32 originChainId_) {\n // Load 32 bytes from the offset and shift it 224 bits to the right to get the highest 32 bits.\n assembly {\n originChainId_ := shr(224, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_CHAIN_ID)))\n }\n }\n\n /// @notice Extracts the destination chain ID from the encoded transaction.\n function destChainId(bytes calldata encodedTx) internal pure returns (uint32 destChainId_) {\n // Load 32 bytes from the offset and shift it 224 bits to the right to get the highest 32 bits.\n assembly {\n destChainId_ := shr(224, calldataload(add(encodedTx.offset, OFFSET_DEST_CHAIN_ID)))\n }\n }\n\n /// @notice Extracts the origin sender from the encoded transaction.\n function originSender(bytes calldata encodedTx) internal pure returns (address originSender_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n originSender_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_SENDER)))\n }\n }\n\n /// @notice Extracts the destination recipient from the encoded transaction.\n function destRecipient(bytes calldata encodedTx) internal pure returns (address destRecipient_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n destRecipient_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_DEST_RECIPIENT)))\n }\n }\n\n /// @notice Extracts the origin token from the encoded transaction.\n function originToken(bytes calldata encodedTx) internal pure returns (address originToken_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n originToken_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_TOKEN)))\n }\n }\n\n /// @notice Extracts the destination token from the encoded transaction.\n function destToken(bytes calldata encodedTx) internal pure returns (address destToken_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n destToken_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_DEST_TOKEN)))\n }\n }\n\n /// @notice Extracts the origin amount from the encoded transaction.\n function originAmount(bytes calldata encodedTx) internal pure returns (uint256 originAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n originAmount_ := calldataload(add(encodedTx.offset, OFFSET_ORIGIN_AMOUNT))\n }\n }\n\n /// @notice Extracts the destination amount from the encoded transaction.\n function destAmount(bytes calldata encodedTx) internal pure returns (uint256 destAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n destAmount_ := calldataload(add(encodedTx.offset, OFFSET_DEST_AMOUNT))\n }\n }\n\n /// @notice Extracts the origin fee amount from the encoded transaction.\n function originFeeAmount(bytes calldata encodedTx) internal pure returns (uint256 originFeeAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n originFeeAmount_ := calldataload(add(encodedTx.offset, OFFSET_ORIGIN_FEE_AMOUNT))\n }\n }\n\n /// @notice Extracts the deadline from the encoded transaction.\n function deadline(bytes calldata encodedTx) internal pure returns (uint256 deadline_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n deadline_ := calldataload(add(encodedTx.offset, OFFSET_DEADLINE))\n }\n }\n\n /// @notice Extracts the nonce from the encoded transaction.\n function nonce(bytes calldata encodedTx) internal pure returns (uint256 nonce_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n nonce_ := calldataload(add(encodedTx.offset, OFFSET_NONCE))\n }\n }\n\n /// @notice Extracts the exclusivity relayer from the encoded transaction.\n function exclusivityRelayer(bytes calldata encodedTx) internal pure returns (address exclusivityRelayer_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n exclusivityRelayer_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_EXCLUSIVITY_RELAYER)))\n }\n }\n\n /// @notice Extracts the exclusivity end time from the encoded transaction.\n function exclusivityEndTime(bytes calldata encodedTx) internal pure returns (uint256 exclusivityEndTime_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n exclusivityEndTime_ := calldataload(add(encodedTx.offset, OFFSET_EXCLUSIVITY_END_TIME))\n }\n }\n\n /// @notice Extracts the Zap's native value from the encoded transaction.\n function zapNative(bytes calldata encodedTx) internal pure returns (uint256 zapNative_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n zapNative_ := calldataload(add(encodedTx.offset, OFFSET_ZAP_NATIVE))\n }\n }\n\n /// @notice Extracts the Zap's data from the encoded transaction.\n function zapData(bytes calldata encodedTx) internal pure returns (bytes calldata zapData_) {\n zapData_ = encodedTx[OFFSET_ZAP_DATA:];\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/AdminV2.sol\n\n// ════════════════════════════════════════════════ INTERFACES ═════════════════════════════════════════════════════\n\n// ═════════════════════════════════════════════ EXTERNAL IMPORTS ══════════════════════════════════════════════════\n\n/// @title AdminV2\n/// @notice Provides administrative functions and controls for managing the FastBridgeV2 contract,\n/// including access control and configuration settings.\ncontract AdminV2 is AccessControlEnumerable, IAdminV2, IAdminV2Errors {\n using SafeERC20 for IERC20;\n\n /// @notice The address reserved for the native gas token (ETH on Ethereum and most L2s, AVAX on Avalanche, etc.).\n address public constant NATIVE_GAS_TOKEN = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice The role identifier for the Quoter API's off-chain authentication.\n /// @dev Only addresses with this role can post FastBridge quotes to the API.\n bytes32 public constant QUOTER_ROLE = keccak256(\"QUOTER_ROLE\");\n\n /// @notice The role identifier for the Prover's on-chain authentication in FastBridge.\n /// @dev Only addresses with this role can provide proofs that a FastBridge request has been relayed.\n bytes32 public constant PROVER_ROLE = keccak256(\"PROVER_ROLE\");\n\n /// @notice The role identifier for the Guard's on-chain authentication in FastBridge.\n /// @dev Only addresses with this role can dispute submitted relay proofs during the dispute period.\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n\n /// @notice The role identifier for the Canceler's on-chain authentication in FastBridge.\n /// @dev Only addresses with this role can cancel a FastBridge transaction without the cancel delay.\n bytes32 public constant CANCELER_ROLE = keccak256(\"CANCELER_ROLE\");\n\n /// @notice The role identifier for the Governor's on-chain administrative authority.\n /// @dev Only addresses with this role can perform administrative tasks within the contract.\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n /// @notice The denominator for fee rates, representing 100%.\n uint256 public constant FEE_BPS = 1e6;\n /// @notice The maximum protocol fee rate: 1% of the origin amount.\n uint256 public constant FEE_RATE_MAX = 0.01e6;\n\n /// @notice The minimum cancel delay that can be set by the governor.\n uint256 public constant MIN_CANCEL_DELAY = 1 hours;\n /// @notice The default cancel delay set during contract deployment.\n uint256 public constant DEFAULT_CANCEL_DELAY = 1 days;\n\n /// @notice The protocol fee rate taken on the origin amount deposited in the origin chain.\n uint256 public protocolFeeRate;\n\n /// @notice The accumulated protocol fee amounts.\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice The delay period after which a transaction can be permissionlessly cancelled.\n uint256 public cancelDelay;\n\n /// @notice This variable is deprecated and should not be used.\n /// @dev Use ZapNative V2 requests instead.\n uint256 public immutable chainGasAmount = 0;\n\n constructor(address defaultAdmin) {\n _grantRole(DEFAULT_ADMIN_ROLE, defaultAdmin);\n _setCancelDelay(DEFAULT_CANCEL_DELAY);\n }\n\n /// @inheritdoc IAdminV2\n function setCancelDelay(uint256 newCancelDelay) external onlyRole(GOVERNOR_ROLE) {\n _setCancelDelay(newCancelDelay);\n }\n\n /// @inheritdoc IAdminV2\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n if (newFeeRate \u003e FEE_RATE_MAX) revert FeeRateAboveMax();\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n /// @inheritdoc IAdminV2\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n // Early exit if no accumulated fees.\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return;\n // Reset the accumulated fees first.\n protocolFees[token] = 0;\n emit FeesSwept(token, recipient, feeAmount);\n // Sweep the fees as the last transaction action.\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(recipient), feeAmount);\n } else {\n IERC20(token).safeTransfer(recipient, feeAmount);\n }\n }\n\n /// @notice Internal logic to set the cancel delay. Security checks are performed outside of this function.\n /// @dev This function is marked as private to prevent child contracts from calling it directly.\n function _setCancelDelay(uint256 newCancelDelay) private {\n if (newCancelDelay \u003c MIN_CANCEL_DELAY) revert CancelDelayBelowMin();\n uint256 oldCancelDelay = cancelDelay;\n cancelDelay = newCancelDelay;\n emit CancelDelayUpdated(oldCancelDelay, newCancelDelay);\n }\n}\n\n// contracts/FastBridgeV2.sol\n\n// ════════════════════════════════════════════════ INTERFACES ═════════════════════════════════════════════════════\n\n// ═════════════════════════════════════════════ INTERNAL IMPORTS ══════════════════════════════════════════════════\n\n// ═════════════════════════════════════════════ EXTERNAL IMPORTS ══════════════════════════════════════════════════\n\n/// @title FastBridgeV2\n/// @notice Core component of the SynapseRFQ protocol, enabling Relayers (Solvers) to fulfill bridge requests.\n/// Supports ERC20 and native gas tokens, along with the Zap feature for executing actions on the destination chain.\n/// Users interact with the off-chain Quoter API to obtain a current quote for a bridge transaction.\n/// They then submit the bridge request with the quote to this contract, depositing their assets in escrow.\n/// Relayers can fulfill requests by relaying them to the destination chain and must prove fulfillment to claim funds.\n/// Guards monitor proofs and can dispute discrepancies.\n/// Users can reclaim funds by cancelling their requests if it has not been fulfilled within the specified deadline.\ncontract FastBridgeV2 is AdminV2, MulticallTarget, IFastBridgeV2, IFastBridgeV2Errors {\n using BridgeTransactionV2Lib for bytes;\n using SafeERC20 for IERC20;\n\n /// @notice The duration of the dispute period for relayed transactions.\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice The minimum required time between transaction request and deadline.\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n /// @notice The maximum allowed length for zapData.\n uint256 public constant MAX_ZAP_DATA_LENGTH = 2 ** 16 - 1;\n\n /// @notice Maps transaction IDs to bridge details (status, destination chain ID, proof timestamp, and relayer).\n /// Note: this is only stored for transactions having local chain as the origin chain.\n mapping(bytes32 =\u003e BridgeTxDetails) public bridgeTxDetails;\n /// @notice Maps transaction IDs to relay details (block number, block timestamp, and relayer).\n /// Note: this is only stored for transactions having local chain as the destination chain.\n mapping(bytes32 =\u003e BridgeRelay) public bridgeRelayDetails;\n /// @notice Maps sender addresses to their unique bridge nonce.\n mapping(address =\u003e uint256) public senderNonces;\n\n /// @notice This variable is deprecated and should not be used.\n /// @dev Replaced by senderNonces.\n uint256 public immutable nonce = 0;\n /// @notice The block number at which this contract was deployed.\n uint256 public immutable deployBlock;\n\n /// @notice Initializes the FastBridgeV2 contract with the provided default admin,\n /// sets the default cancel delay, and records the deploy block number.\n constructor(address defaultAdmin) AdminV2(defaultAdmin) {\n deployBlock = block.number;\n }\n\n // ══════════════════════════════════════ EXTERNAL MUTABLE (USER FACING) ═══════════════════════════════════════════\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n bridgeV2({\n params: params,\n paramsV2: BridgeParamsV2({\n quoteRelayer: address(0),\n quoteExclusivitySeconds: 0,\n quoteId: bytes(\"\"),\n zapNative: 0,\n zapData: bytes(\"\")\n })\n });\n }\n\n /// Note: this function is deprecated and will be removed in a future version.\n /// @dev Replaced by `cancel`.\n /// @inheritdoc IFastBridge\n function refund(bytes calldata request) external {\n cancelV2(request);\n }\n\n // ══════════════════════════════════════ EXTERNAL MUTABLE (AGENT FACING) ══════════════════════════════════════════\n\n /// @inheritdoc IFastBridge\n function relay(bytes calldata request) external payable {\n // `relay` override will validate the request.\n relayV2({request: request, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes calldata request, bytes32 destTxHash) external {\n request.validateV2();\n proveV2({transactionId: keccak256(request), destTxHash: destTxHash, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridgeV2\n function claimV2(bytes calldata request) external {\n // `claim` override will validate the request.\n claim({request: request, to: address(0)});\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n // Aggregate the read operations from the same storage slot.\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n address disputedRelayer = $.proofRelayer;\n BridgeStatus status = $.status;\n uint56 proofBlockTimestamp = $.proofBlockTimestamp;\n\n // Can only dispute a RELAYER_PROVED transaction within the dispute period.\n if (status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(proofBlockTimestamp) \u003e DISPUTE_PERIOD) {\n revert DisputePeriodPassed();\n }\n\n // Update status to REQUESTED and delete the disputed proof details.\n // Note: these are storage writes.\n $.status = BridgeStatus.REQUESTED;\n $.proofRelayer = address(0);\n $.proofBlockTimestamp = 0;\n\n emit BridgeProofDisputed(transactionId, disputedRelayer);\n }\n\n // ══════════════════════════════════════════════ EXTERNAL VIEWS ═══════════════════════════════════════════════════\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n // The correct relayer can only claim a RELAYER_PROVED transaction after the dispute period.\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n if ($.status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if ($.proofRelayer != relayer) revert SenderIncorrect();\n\n return _timeSince($.proofBlockTimestamp) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n /// @dev This method is added to achieve backwards compatibility with decoding requests into V1 structs:\n /// - `zapNative` is partially reported as a zero/non-zero flag\n /// - `zapData` is ignored\n /// In order to process all kinds of requests use getBridgeTransactionV2 instead.\n function getBridgeTransaction(bytes calldata request) external view returns (BridgeTransaction memory) {\n // Try decoding into V2 struct first. This will revert if V1 struct is passed.\n try this.getBridgeTransactionV2(request) returns (BridgeTransactionV2 memory txV2) {\n // Note: we entirely ignore the zapData field, as it was not present in V1.\n return BridgeTransaction({\n originChainId: txV2.originChainId,\n destChainId: txV2.destChainId,\n originSender: txV2.originSender,\n destRecipient: txV2.destRecipient,\n originToken: txV2.originToken,\n destToken: txV2.destToken,\n originAmount: txV2.originAmount,\n destAmount: txV2.destAmount,\n originFeeAmount: txV2.originFeeAmount,\n sendChainGas: txV2.zapNative != 0,\n deadline: txV2.deadline,\n nonce: txV2.nonce\n });\n } catch {\n // Fallback to V1 struct.\n return abi.decode(request, (BridgeTransaction));\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function getBridgeTransactionV2(bytes calldata request) external pure returns (BridgeTransactionV2 memory) {\n request.validateV2();\n return BridgeTransactionV2Lib.decodeV2(request);\n }\n\n // ═══════════════════════════════════════ PUBLIC MUTABLE (USER FACING) ════════════════════════════════════════════\n\n /// @inheritdoc IFastBridgeV2\n function bridgeV2(BridgeParams memory params, BridgeParamsV2 memory paramsV2) public payable {\n // If relayer exclusivity is not intended for this bridge, set exclusivityEndTime to static zero.\n // Otherwise, set exclusivity to expire at the current block ts offset by quoteExclusivitySeconds.\n int256 exclusivityEndTime = 0;\n if (paramsV2.quoteRelayer != address(0)) {\n exclusivityEndTime = int256(block.timestamp) + paramsV2.quoteExclusivitySeconds;\n }\n _validateBridgeParams(params, paramsV2, exclusivityEndTime);\n\n // Transfer tokens to bridge contract. We use the actual transferred amount in case of transfer fees.\n uint256 originAmount = _takeBridgedUserAsset(params.originToken, params.originAmount);\n\n // Track the amount of origin token owed to protocol.\n uint256 originFeeAmount = 0;\n if (protocolFeeRate \u003e 0) {\n originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n // The Relayer filling this request will be paid the originAmount after fees.\n // Note: the protocol fees will be accumulated only when the Relayer claims the origin collateral.\n originAmount -= originFeeAmount;\n }\n\n // Hash the bridge request and set the initial status to REQUESTED.\n bytes memory request = BridgeTransactionV2Lib.encodeV2(\n BridgeTransactionV2({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n deadline: params.deadline,\n // Increment the sender's nonce on every bridge.\n nonce: senderNonces[params.sender]++,\n exclusivityRelayer: paramsV2.quoteRelayer,\n // We checked exclusivityEndTime to be in range [0 .. params.deadline] above, so can safely cast.\n exclusivityEndTime: uint256(exclusivityEndTime),\n zapNative: paramsV2.zapNative,\n zapData: paramsV2.zapData\n })\n );\n bytes32 transactionId = keccak256(request);\n // Note: the tx status will be updated throughout the tx lifecycle, while destChainId is set once here.\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n bridgeTxDetails[transactionId].destChainId = params.dstChainId;\n\n emit BridgeRequested({\n transactionId: transactionId,\n sender: params.sender,\n request: request,\n destChainId: params.dstChainId,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n sendChainGas: paramsV2.zapNative != 0\n });\n emit BridgeQuoteDetails(transactionId, paramsV2.quoteId);\n }\n\n /// @inheritdoc IFastBridgeV2\n function cancelV2(bytes calldata request) public {\n // Decode the request and check that it could be cancelled.\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n\n // Can only cancel a REQUESTED transaction after its deadline expires.\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n if ($.status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n\n // Permissionless cancel is only allowed after `cancelDelay` on top of the deadline.\n uint256 deadline = request.deadline();\n if (!hasRole(CANCELER_ROLE, msg.sender)) deadline += cancelDelay;\n if (block.timestamp \u003c= deadline) revert DeadlineNotExceeded();\n\n // Update status to REFUNDED.\n // Note: this is a storage write.\n $.status = BridgeStatus.REFUNDED;\n\n // Return the full amount (collateral + protocol fees) to the original sender.\n // The protocol fees are only accumulated when the transaction is claimed, so we don't need to update them here.\n address to = request.originSender();\n address token = request.originToken();\n uint256 amount = request.originAmount() + request.originFeeAmount();\n\n // Emit the event before any external calls.\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n\n // Return the funds to the original sender as last transaction action.\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(to), amount);\n } else {\n IERC20(token).safeTransfer(to, amount);\n }\n }\n\n // ═══════════════════════════════════════ PUBLIC MUTABLE (AGENT FACING) ═══════════════════════════════════════════\n\n /// @inheritdoc IFastBridgeV2\n function relayV2(bytes calldata request, address relayer) public payable {\n // Decode the request and check that it could be relayed.\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n _validateRelayParams(request, transactionId, relayer);\n\n // Mark the bridge request as relayed by saving the relayer and the block details.\n bridgeRelayDetails[transactionId].blockNumber = uint48(block.number);\n bridgeRelayDetails[transactionId].blockTimestamp = uint48(block.timestamp);\n bridgeRelayDetails[transactionId].relayer = relayer;\n\n // Transfer tokens to recipient on destination chain and trigger Zap if requested.\n address to = request.destRecipient();\n address token = request.destToken();\n uint256 amount = request.destAmount();\n uint256 zapNative = request.zapNative();\n\n // Emit the event before any external calls.\n emit BridgeRelayed({\n transactionId: transactionId,\n relayer: relayer,\n to: to,\n originChainId: request.originChainId(),\n originToken: request.originToken(),\n destToken: token,\n originAmount: request.originAmount(),\n destAmount: amount,\n chainGasAmount: zapNative\n });\n\n // All state changes have been done at this point, can proceed to the external calls.\n // This follows the checks-effects-interactions pattern to mitigate potential reentrancy attacks.\n if (token == NATIVE_GAS_TOKEN) {\n // For the native gas token, additional zapNative is not allowed.\n if (zapNative != 0) revert ZapNativeNotSupported();\n // Check that the correct msg.value was sent.\n if (msg.value != amount) revert MsgValueIncorrect();\n // Don't do a native transfer yet: we will handle it alongside the Zap below.\n } else {\n // For ERC20s, we check that the correct msg.value was sent.\n if (msg.value != zapNative) revert MsgValueIncorrect();\n // We need to transfer the tokens from the Relayer to the recipient first before performing an\n // optional post-transfer Zap.\n IERC20(token).safeTransferFrom(msg.sender, to, amount);\n }\n // At this point we have done:\n // - Transferred the requested amount of ERC20 tokens to the recipient.\n // At this point we have confirmed:\n // - For ERC20s: msg.value matches the requested zapNative amount.\n // - For the native gas token: msg.value matches the requested destAmount.\n // Remaining optional things to do:\n // - Forward the full msg.value to the recipient (if non-zero).\n // - Trigger a Zap (if zapData is present).\n bytes calldata zapData = request.zapData();\n if (zapData.length != 0) {\n // Zap Data is present: Zap has been requested by the recipient. Trigger it forwarding the full msg.value.\n _triggerZapWithChecks({recipient: to, token: token, amount: amount, zapData: zapData});\n // Note: if token has a fee on transfers, the recipient will have received less than `amount`.\n // This is a very niche edge case and should be handled by the recipient contract.\n } else if (msg.value != 0) {\n // Zap Data is missing, but msg.value was sent. This could happen in two different cases:\n // - Relay with the native gas token is happening.\n // - Relay with ERC20 is happening, with a `zapNative \u003e 0` request.\n // In both cases, we need to transfer the full msg.value to the recipient.\n Address.sendValue(payable(to), msg.value);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function proveV2(bytes32 transactionId, bytes32 destTxHash, address relayer) public onlyRole(PROVER_ROLE) {\n // Can only prove a REQUESTED transaction.\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n if ($.status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n\n // Update status to RELAYER_PROVED and store the proof details.\n // Note: these are storage writes.\n $.status = BridgeStatus.RELAYER_PROVED;\n $.proofBlockTimestamp = uint56(block.timestamp);\n $.proofRelayer = relayer;\n\n emit BridgeProofProvided(transactionId, relayer, destTxHash);\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes calldata request, address to) public {\n // Decode the request and check that it could be claimed.\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n\n // Aggregate the read operations from the same storage slot.\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n address proofRelayer = $.proofRelayer;\n BridgeStatus status = $.status;\n uint56 proofBlockTimestamp = $.proofBlockTimestamp;\n\n // Can only claim a RELAYER_PROVED transaction after the dispute period.\n if (status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(proofBlockTimestamp) \u003c= DISPUTE_PERIOD) revert DisputePeriodNotPassed();\n if (to == address(0)) {\n // Anyone could claim the funds to the proven relayer on their behalf.\n to = proofRelayer;\n } else if (proofRelayer != msg.sender) {\n // Only the proven relayer could specify an address to claim the funds to.\n revert SenderIncorrect();\n }\n\n // Update status to RELAYER_CLAIMED and transfer the origin collateral to the specified claim address.\n // Note: this is a storage write.\n $.status = BridgeStatus.RELAYER_CLAIMED;\n\n // Accumulate protocol fees if origin fee amount exists.\n address token = request.originToken();\n uint256 amount = request.originAmount();\n uint256 originFeeAmount = request.originFeeAmount();\n if (originFeeAmount \u003e 0) protocolFees[token] += originFeeAmount;\n\n // Emit the event before any external calls.\n emit BridgeDepositClaimed(transactionId, proofRelayer, to, token, amount);\n\n // Complete the relayer claim as the last transaction action.\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(to), amount);\n } else {\n IERC20(token).safeTransfer(to, amount);\n }\n }\n\n // ═══════════════════════════════════════════════ PUBLIC VIEWS ════════════════════════════════════════════════════\n\n /// @inheritdoc IFastBridgeV2\n function bridgeStatuses(bytes32 transactionId) public view returns (BridgeStatus status) {\n return bridgeTxDetails[transactionId].status;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeProofs(bytes32 transactionId) public view returns (uint96 timestamp, address relayer) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n timestamp = $.proofBlockTimestamp;\n relayer = $.proofRelayer;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeRelays(bytes32 transactionId) public view returns (bool) {\n // This transaction has been relayed if the relayer address is recorded.\n return bridgeRelayDetails[transactionId].relayer != address(0);\n }\n\n // ═════════════════════════════════════════════ INTERNAL METHODS ══════════════════════════════════════════════════\n\n /// @notice Takes the bridged asset from the user into FastBridgeV2 custody. The asset will later be\n /// claimed by the relayer who completed the relay on the destination chain, or returned to the user\n /// via the cancel function if no relay is completed.\n function _takeBridgedUserAsset(address token, uint256 amount) internal returns (uint256 amountTaken) {\n if (token == NATIVE_GAS_TOKEN) {\n // For the native gas token, we just need to check that the supplied msg.value is correct.\n // Supplied `msg.value` is already in FastBridgeV2 custody.\n if (amount != msg.value) revert MsgValueIncorrect();\n amountTaken = msg.value;\n } else {\n // For ERC20s, token is explicitly transferred from the user to FastBridgeV2.\n // We don't allow non-zero `msg.value` to avoid extra funds from being stuck in FastBridgeV2.\n if (msg.value != 0) revert MsgValueIncorrect();\n // Throw an explicit error if the provided token address is not a contract.\n if (token.code.length == 0) revert TokenNotContract();\n\n // Use the balance difference as the amount taken in case of fee on transfer tokens.\n amountTaken = IERC20(token).balanceOf(address(this));\n IERC20(token).safeTransferFrom(msg.sender, address(this), amount);\n amountTaken = IERC20(token).balanceOf(address(this)) - amountTaken;\n }\n }\n\n /// @notice Calls the recipient's hook function with the specified zapData and validates\n /// the returned value.\n function _triggerZapWithChecks(address recipient, address token, uint256 amount, bytes calldata zapData) internal {\n // Call the recipient's hook function with the specified zapData, bubbling any revert messages.\n bytes memory returnData = Address.functionCallWithValue({\n target: recipient,\n data: abi.encodeCall(IZapRecipient.zap, (token, amount, zapData)),\n // Note: see `relay()` for reasoning behind passing msg.value.\n value: msg.value\n });\n\n // Explicit revert if no return data at all.\n if (returnData.length == 0) revert RecipientNoReturnValue();\n // Check that exactly a single return value was returned.\n if (returnData.length != 32) revert RecipientIncorrectReturnValue();\n // Return value should be abi-encoded hook function selector.\n if (bytes32(returnData) != bytes32(IZapRecipient.zap.selector)) {\n revert RecipientIncorrectReturnValue();\n }\n }\n\n /// @notice Calculates the time elapsed since a proof was submitted.\n /// @dev The proof.timestamp stores block timestamps as uint56 for gas optimization.\n /// _timeSince(proof) handles timestamp rollover when block.timestamp \u003e type(uint56).max but\n /// proof.timestamp \u003c type(uint56).max via an unchecked statement.\n /// @param proofBlockTimestamp The block timestamp when the proof was submitted.\n /// @return delta The time elapsed since proof submission.\n function _timeSince(uint56 proofBlockTimestamp) internal view returns (uint256 delta) {\n unchecked {\n delta = uint56(block.timestamp) - proofBlockTimestamp;\n }\n }\n\n /// @notice Validates all parameters required for a bridge transaction.\n /// @dev This function's complexity cannot be reduced due to the number of required checks,\n /// so we disable the code-complexity rule.\n // solhint-disable-next-line code-complexity\n function _validateBridgeParams(\n BridgeParams memory params,\n BridgeParamsV2 memory paramsV2,\n int256 exclusivityEndTime\n )\n internal\n view\n {\n // Check V1 (legacy) params.\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.sender == address(0) || params.to == address(0)) revert ZeroAddress();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n\n // Check V2 params.\n if (paramsV2.zapData.length \u003e MAX_ZAP_DATA_LENGTH) revert ZapDataLengthAboveMax();\n if (paramsV2.zapNative != 0 \u0026\u0026 params.destToken == NATIVE_GAS_TOKEN) {\n revert ZapNativeNotSupported();\n }\n\n // exclusivityEndTime must be in range [0 .. params.deadline].\n if (exclusivityEndTime \u003c 0 || exclusivityEndTime \u003e int256(params.deadline)) {\n revert ExclusivityParamsIncorrect();\n }\n }\n\n /// @notice Validates all parameters required for a relay transaction.\n function _validateRelayParams(bytes calldata request, bytes32 transactionId, address relayer) internal view {\n if (relayer == address(0)) revert ZeroAddress();\n // Check that the transaction has not been relayed yet and is for the current chain.\n if (bridgeRelays(transactionId)) revert TransactionRelayed();\n if (request.destChainId() != block.chainid) revert ChainIncorrect();\n // Check that the deadline for relay to happen has not passed yet.\n if (block.timestamp \u003e request.deadline()) revert DeadlineExceeded();\n // Check the exclusivity period, if it was specified and is still ongoing.\n address exclRelayer = request.exclusivityRelayer();\n if (exclRelayer != address(0) \u0026\u0026 exclRelayer != relayer \u0026\u0026 block.timestamp \u003c= request.exclusivityEndTime()) {\n revert ExclusivityPeriodNotPassed();\n }\n }\n}\n","language":"Solidity","languageVersion":"0.8.24","compilerVersion":"0.8.24","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"","srcMapRuntime":"","abiDefinition":[{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"bytes","name":"zapData","type":"bytes"}],"name":"zap","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"payable","type":"function"}],"userDoc":{"kind":"user","methods":{"zap(address,uint256,bytes)":{"notice":"Performs a Zap operation with the given token and amount according to the provided Zap data."}},"notice":"Interface for contracts that can perform Zap operations. Such contracts could be used as Recipients in a FastBridge transaction that includes a Zap operation. The Zap Data should include instructions on how exactly the Zap operation should be executed, which would typically include the target address and calldata to use. The exact implementation of the Zap Data encoding is up to the Recipient contract.","version":1},"developerDoc":{"kind":"dev","methods":{"zap(address,uint256,bytes)":{"params":{"amount":"The amount of tokens to be used.","token":"The address of the token being used for the Zap operation.","zapData":"The encoded data specifying how the Zap operation should be executed."},"returns":{"_0":"The function selector to indicate successful execution."}}},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"zapData\",\"type\":\"bytes\"}],\"name\":\"zap\",\"outputs\":[{\"internalType\":\"bytes4\",\"name\":\"\",\"type\":\"bytes4\"}],\"stateMutability\":\"payable\",\"type\":\"function\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{\"zap(address,uint256,bytes)\":{\"params\":{\"amount\":\"The amount of tokens to be used.\",\"token\":\"The address of the token being used for the Zap operation.\",\"zapData\":\"The encoded data specifying how the Zap operation should be executed.\"},\"returns\":{\"_0\":\"The function selector to indicate successful execution.\"}}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"zap(address,uint256,bytes)\":{\"notice\":\"Performs a Zap operation with the given token and amount according to the provided Zap data.\"}},\"notice\":\"Interface for contracts that can perform Zap operations. Such contracts could be used as Recipients in a FastBridge transaction that includes a Zap operation. The Zap Data should include instructions on how exactly the Zap operation should be executed, which would typically include the target address and calldata to use. The exact implementation of the Zap Data encoding is up to the Recipient contract.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeV2.sol\":\"IZapRecipient\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeV2.sol\":{\"keccak256\":\"0xaab2ee7357681726f0faf799a48ddfbf45fb4da93b69abf61c33dde92b29b74d\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://673391bff9569efc0f9bd99e0e6fece0bc8e8af1f052bb071b407b267a17b3b5\",\"dweb:/ipfs/QmdQQZ6DxpJYhfpinwU5WjLugr2f6qP8h68b5GerhSMQ4j\"]}},\"version\":1}"},"hashes":{"zap(address,uint256,bytes)":"e85e13dd"}},"solidity/FastBridgeV2.sol:MulticallTarget":{"code":"0x","runtime-code":"0x","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.24 ^0.8.20 ^0.8.4;\n\n// contracts/interfaces/IAdminV2.sol\n\ninterface IAdminV2 {\n event CancelDelayUpdated(uint256 oldCancelDelay, uint256 newCancelDelay);\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n /// @notice Allows the governor to set the cancel delay. The cancel delay is the time period after the transaction\n /// deadline during which a transaction can be permissionlessly cancelled if it hasn't been proven by any Relayer.\n function setCancelDelay(uint256 newCancelDelay) external;\n\n /// @notice Allows the governor to set the protocol fee rate. The protocol fee is taken from the origin\n /// amount and is only applied to completed and claimed transactions.\n /// @dev The protocol fee is abstracted away from the relayers; they always operate using the amounts after fees.\n /// The origin amount they see in the emitted log is what they get credited with.\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n /// @notice Allows the governor to withdraw the accumulated protocol fees from the contract.\n function sweepProtocolFees(address token, address recipient) external;\n}\n\n// contracts/interfaces/IAdminV2Errors.sol\n\ninterface IAdminV2Errors {\n error CancelDelayBelowMin();\n error FeeRateAboveMax();\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IFastBridgeV2Errors.sol\n\ninterface IFastBridgeV2Errors {\n error AmountIncorrect();\n error ChainIncorrect();\n error ExclusivityParamsIncorrect();\n error MsgValueIncorrect();\n error SenderIncorrect();\n error StatusIncorrect();\n error TokenNotContract();\n error ZapDataLengthAboveMax();\n error ZapNativeNotSupported();\n error ZeroAddress();\n\n error RecipientIncorrectReturnValue();\n error RecipientNoReturnValue();\n\n error DeadlineExceeded();\n error DeadlineNotExceeded();\n error DeadlineTooShort();\n error DisputePeriodNotPassed();\n error DisputePeriodPassed();\n error ExclusivityPeriodNotPassed();\n\n error TransactionRelayed();\n}\n\n// contracts/interfaces/IMulticallTarget.sol\n\n/// @notice Interface for a contract that supports multiple calls from the same caller. Inspired by MulticallV3:\n/// https://github.com/mds1/multicall/blob/master/src/Multicall3.sol\ninterface IMulticallTarget {\n struct Result {\n bool success;\n bytes returnData;\n }\n\n /// @notice Executes multiple calls to this contract in a single transaction while preserving msg.sender.\n /// Return data from the calls is discarded.\n /// @dev This method is non-payable, so only calls with msg.value of 0 can be batched.\n /// If ignoreReverts is set to true, reverted calls will be skipped.\n /// Otherwise, the entire batch will revert with the original revert reason.\n /// @param data List of ABI-encoded calldata for the calls to execute\n /// @param ignoreReverts Whether to skip calls that revert\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external;\n\n /// @notice Executes multiple calls to this contract in a single transaction while preserving msg.sender.\n /// Return data from each call is preserved.\n /// @dev This method is non-payable, so only calls with msg.value of 0 can be batched.\n /// If ignoreReverts is set to true, reverted calls will be skipped.\n /// Otherwise, the entire batch will revert with the original revert reason.\n /// @param data List of ABI-encoded calldata for the calls to execute\n /// @param ignoreReverts Whether to skip calls that revert\n /// @return results List of results from the calls, each containing (success, returnData)\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results);\n}\n\n// contracts/interfaces/IZapRecipient.sol\n\n/// @notice Interface for contracts that can perform Zap operations. Such contracts could be used as Recipients\n/// in a FastBridge transaction that includes a Zap operation. The Zap Data should include instructions on how\n/// exactly the Zap operation should be executed, which would typically include the target address and calldata\n/// to use. The exact implementation of the Zap Data encoding is up to the Recipient contract.\ninterface IZapRecipient {\n /// @notice Performs a Zap operation with the given token and amount according to the provided Zap data.\n /// @param token The address of the token being used for the Zap operation.\n /// @param amount The amount of tokens to be used.\n /// @param zapData The encoded data specifying how the Zap operation should be executed.\n /// @return The function selector to indicate successful execution.\n function zap(address token, uint256 amount, bytes memory zapData) external payable returns (bytes4);\n}\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// contracts/interfaces/IFastBridgeV2.sol\n\ninterface IFastBridgeV2 is IFastBridge {\n enum BridgeStatus {\n NULL, // Doesn't exist yet.\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n struct BridgeTxDetails {\n BridgeStatus status;\n uint32 destChainId;\n uint56 proofBlockTimestamp;\n address proofRelayer;\n }\n\n struct BridgeRelay {\n uint48 blockNumber;\n uint48 blockTimestamp;\n address relayer;\n }\n\n /// @notice New params introduced in the FastBridgeV2.\n /// We are passing fields from the older BridgeParams struct outside of this struct for backwards compatibility.\n /// Note: quoteRelayer and quoteExclusivitySeconds are either both zero (indicating no exclusivity)\n /// or both non-zero (indicating exclusivity for the given period).\n /// Note: zapNative \u003e 0 can NOT be used with destToken = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE (native token)\n /// @param quoteRelayer Relayer that provided the quote for the transaction\n /// @param quoteExclusivitySeconds Period of time the quote relayer is guaranteed exclusivity after user's deposit\n /// @param quoteId Unique quote identifier used for tracking the quote\n /// @param zapNative ETH value to send to the recipient (if any)\n /// @param zapData Parameters for the Zap to the destination recipient (if any)\n struct BridgeParamsV2 {\n address quoteRelayer;\n int256 quoteExclusivitySeconds;\n bytes quoteId;\n uint256 zapNative;\n bytes zapData;\n }\n\n /// @notice Updated bridge transaction struct to include parameters introduced in FastBridgeV2.\n /// Note: only `exclusivityRelayer` can fill such a transaction until `exclusivityEndTime`.\n struct BridgeTransactionV2 {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n // Note: sendChainGas flag from V1 is deprecated\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n address exclusivityRelayer;\n uint256 exclusivityEndTime;\n uint256 zapNative; // ETH value to send to the recipient (if any)\n bytes zapData; // data to pass for the Zap action (if any)\n }\n\n event BridgeQuoteDetails(bytes32 indexed transactionId, bytes quoteId);\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability\n /// to provide temporary exclusivity fill rights for the quote relayer.\n /// @param params The parameters required to bridge\n /// @param paramsV2 The parameters for exclusivity fill rights (optional, can be left empty)\n function bridgeV2(BridgeParams memory params, BridgeParamsV2 memory paramsV2) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function relayV2(bytes memory request, address relayer) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param transactionId The transaction id associated with the encoded bridge transaction to prove\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function proveV2(bytes32 transactionId, bytes32 destTxHash, address relayer) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital.\n /// @notice Can only send funds to the relayer address on the proof.\n /// @param request The encoded bridge transaction to claim on origin chain\n function claimV2(bytes memory request) external;\n\n /// @notice Cancels an outstanding bridge transaction in case optimistic bridging failed and returns the full amount\n /// to the original sender.\n /// @param request The encoded bridge transaction to refund\n function cancelV2(bytes memory request) external;\n\n /// @notice Checks if a transaction has been relayed\n /// @param transactionId The ID of the transaction to check\n /// @return True if the transaction has been relayed, false otherwise\n function bridgeRelays(bytes32 transactionId) external view returns (bool);\n\n /// @notice Returns the status of a bridge transaction\n /// @param transactionId The ID of the bridge transaction\n /// @return BridgeStatus Status of the bridge transaction\n function bridgeStatuses(bytes32 transactionId) external view returns (BridgeStatus);\n\n /// @notice Returns the timestamp and relayer of a bridge proof\n /// @param transactionId The ID of the bridge transaction\n /// @return timestamp The timestamp of the bridge proof\n /// @return relayer The relayer address of the bridge proof\n function bridgeProofs(bytes32 transactionId) external view returns (uint96 timestamp, address relayer);\n\n /// @notice Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\n /// @param request The bridge request to decode\n function getBridgeTransactionV2(bytes memory request) external view returns (BridgeTransactionV2 memory);\n}\n\n// contracts/utils/MulticallTarget.sol\n\n// solhint-disable avoid-low-level-calls\n/// @notice Abstract contract template that supports batched calls while preserving msg.sender.\n/// Only calls with msg.value of 0 can be batched.\nabstract contract MulticallTarget is IMulticallTarget {\n error MulticallTarget__UndeterminedRevert();\n\n /// @inheritdoc IMulticallTarget\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external {\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\n if (!success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(result);\n }\n }\n }\n\n /// @inheritdoc IMulticallTarget\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results)\n {\n results = new Result[](data.length);\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (results[i].success, results[i].returnData) = address(this).delegatecall(data[i]);\n if (!results[i].success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(results[i].returnData);\n }\n }\n }\n\n /// @dev Bubbles the revert message from the underlying call.\n /// Note: preserves the same custom error or revert string, if one was used.\n /// Source: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v5.0.2/contracts/utils/Address.sol#L143-L158\n function _bubbleRevert(bytes memory returnData) internal pure {\n // Look for revert reason and bubble it up if present\n if (returnData.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n // solhint-disable-next-line no-inline-assembly\n assembly {\n let returndata_size := mload(returnData)\n revert(add(32, returnData), returndata_size)\n }\n } else {\n revert MulticallTarget__UndeterminedRevert();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// contracts/libs/BridgeTransactionV2.sol\n\n// solhint-disable no-inline-assembly\nlibrary BridgeTransactionV2Lib {\n uint16 internal constant VERSION = 2;\n\n // Offsets of the fields in the packed BridgeTransactionV2 struct\n // uint16 version [000 .. 002)\n // uint32 originChainId [002 .. 006)\n // uint32 destChainId [006 .. 010)\n // address originSender [010 .. 030)\n // address destRecipient [030 .. 050)\n // address originToken [050 .. 070)\n // address destToken [070 .. 090)\n // uint256 originAmount [090 .. 122)\n // uint256 destAmount [122 .. 154)\n // uint256 originFeeAmount [154 .. 186)\n // uint256 deadline [186 .. 218)\n // uint256 nonce [218 .. 250)\n // address exclusivityRelayer [250 .. 270)\n // uint256 exclusivityEndTime [270 .. 302)\n // uint256 zapNative [302 .. 334)\n // bytes zapData [334 .. ***)\n\n // forgefmt: disable-start\n uint256 private constant OFFSET_ORIGIN_CHAIN_ID = 2;\n uint256 private constant OFFSET_DEST_CHAIN_ID = 6;\n uint256 private constant OFFSET_ORIGIN_SENDER = 10;\n uint256 private constant OFFSET_DEST_RECIPIENT = 30;\n uint256 private constant OFFSET_ORIGIN_TOKEN = 50;\n uint256 private constant OFFSET_DEST_TOKEN = 70;\n uint256 private constant OFFSET_ORIGIN_AMOUNT = 90;\n uint256 private constant OFFSET_DEST_AMOUNT = 122;\n uint256 private constant OFFSET_ORIGIN_FEE_AMOUNT = 154;\n uint256 private constant OFFSET_DEADLINE = 186;\n uint256 private constant OFFSET_NONCE = 218;\n uint256 private constant OFFSET_EXCLUSIVITY_RELAYER = 250;\n uint256 private constant OFFSET_EXCLUSIVITY_END_TIME = 270;\n uint256 private constant OFFSET_ZAP_NATIVE = 302;\n uint256 private constant OFFSET_ZAP_DATA = 334;\n // forgefmt: disable-end\n\n error BridgeTransactionV2__InvalidEncodedTx();\n error BridgeTransactionV2__UnsupportedVersion(uint16 version);\n\n /// @notice Validates that the encoded transaction is a tightly packed encoded payload for BridgeTransactionV2.\n /// @dev Checks the minimum length and the version, use this function before decoding any of the fields.\n function validateV2(bytes calldata encodedTx) internal pure {\n // Check the minimum length: must at least include all static fields.\n if (encodedTx.length \u003c OFFSET_ZAP_DATA) revert BridgeTransactionV2__InvalidEncodedTx();\n // Once we validated the length, we can be sure that the version field is present.\n uint16 version_ = version(encodedTx);\n if (version_ != VERSION) revert BridgeTransactionV2__UnsupportedVersion(version_);\n }\n\n /// @notice Encodes the BridgeTransactionV2 struct by tightly packing the fields.\n /// @dev `abi.decode` will not work as a result of the tightly packed fields. Use `decodeV2` to decode instead.\n function encodeV2(IFastBridgeV2.BridgeTransactionV2 memory bridgeTx) internal pure returns (bytes memory) {\n // We split the encoding into two parts to avoid stack-too-deep error\n bytes memory firstPart = abi.encodePacked(\n VERSION,\n bridgeTx.originChainId,\n bridgeTx.destChainId,\n bridgeTx.originSender,\n bridgeTx.destRecipient,\n bridgeTx.originToken,\n bridgeTx.destToken,\n bridgeTx.originAmount\n );\n return abi.encodePacked(\n firstPart,\n bridgeTx.destAmount,\n bridgeTx.originFeeAmount,\n // Note: we skip the deprecated `sendChainGas` flag, which was present in BridgeTransaction V1\n bridgeTx.deadline,\n bridgeTx.nonce,\n // New V2 fields: exclusivity\n bridgeTx.exclusivityRelayer,\n bridgeTx.exclusivityEndTime,\n // New V2 fields: Zap\n bridgeTx.zapNative,\n bridgeTx.zapData\n );\n }\n\n /// @notice Decodes the BridgeTransactionV2 struct from the encoded transaction.\n /// @dev Encoded BridgeTransactionV2 struct must be tightly packed.\n /// Use `validateV2` before decoding to ensure the encoded transaction is valid.\n function decodeV2(bytes calldata encodedTx)\n internal\n pure\n returns (IFastBridgeV2.BridgeTransactionV2 memory bridgeTx)\n {\n bridgeTx.originChainId = originChainId(encodedTx);\n bridgeTx.destChainId = destChainId(encodedTx);\n bridgeTx.originSender = originSender(encodedTx);\n bridgeTx.destRecipient = destRecipient(encodedTx);\n bridgeTx.originToken = originToken(encodedTx);\n bridgeTx.destToken = destToken(encodedTx);\n bridgeTx.originAmount = originAmount(encodedTx);\n bridgeTx.destAmount = destAmount(encodedTx);\n bridgeTx.originFeeAmount = originFeeAmount(encodedTx);\n bridgeTx.deadline = deadline(encodedTx);\n bridgeTx.nonce = nonce(encodedTx);\n bridgeTx.exclusivityRelayer = exclusivityRelayer(encodedTx);\n bridgeTx.exclusivityEndTime = exclusivityEndTime(encodedTx);\n bridgeTx.zapNative = zapNative(encodedTx);\n bridgeTx.zapData = zapData(encodedTx);\n }\n\n /// @notice Extracts the version from the encoded transaction.\n function version(bytes calldata encodedTx) internal pure returns (uint16 version_) {\n // Load 32 bytes from the start and shift it 240 bits to the right to get the highest 16 bits.\n assembly {\n version_ := shr(240, calldataload(encodedTx.offset))\n }\n }\n\n /// @notice Extracts the origin chain ID from the encoded transaction.\n function originChainId(bytes calldata encodedTx) internal pure returns (uint32 originChainId_) {\n // Load 32 bytes from the offset and shift it 224 bits to the right to get the highest 32 bits.\n assembly {\n originChainId_ := shr(224, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_CHAIN_ID)))\n }\n }\n\n /// @notice Extracts the destination chain ID from the encoded transaction.\n function destChainId(bytes calldata encodedTx) internal pure returns (uint32 destChainId_) {\n // Load 32 bytes from the offset and shift it 224 bits to the right to get the highest 32 bits.\n assembly {\n destChainId_ := shr(224, calldataload(add(encodedTx.offset, OFFSET_DEST_CHAIN_ID)))\n }\n }\n\n /// @notice Extracts the origin sender from the encoded transaction.\n function originSender(bytes calldata encodedTx) internal pure returns (address originSender_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n originSender_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_SENDER)))\n }\n }\n\n /// @notice Extracts the destination recipient from the encoded transaction.\n function destRecipient(bytes calldata encodedTx) internal pure returns (address destRecipient_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n destRecipient_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_DEST_RECIPIENT)))\n }\n }\n\n /// @notice Extracts the origin token from the encoded transaction.\n function originToken(bytes calldata encodedTx) internal pure returns (address originToken_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n originToken_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_TOKEN)))\n }\n }\n\n /// @notice Extracts the destination token from the encoded transaction.\n function destToken(bytes calldata encodedTx) internal pure returns (address destToken_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n destToken_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_DEST_TOKEN)))\n }\n }\n\n /// @notice Extracts the origin amount from the encoded transaction.\n function originAmount(bytes calldata encodedTx) internal pure returns (uint256 originAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n originAmount_ := calldataload(add(encodedTx.offset, OFFSET_ORIGIN_AMOUNT))\n }\n }\n\n /// @notice Extracts the destination amount from the encoded transaction.\n function destAmount(bytes calldata encodedTx) internal pure returns (uint256 destAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n destAmount_ := calldataload(add(encodedTx.offset, OFFSET_DEST_AMOUNT))\n }\n }\n\n /// @notice Extracts the origin fee amount from the encoded transaction.\n function originFeeAmount(bytes calldata encodedTx) internal pure returns (uint256 originFeeAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n originFeeAmount_ := calldataload(add(encodedTx.offset, OFFSET_ORIGIN_FEE_AMOUNT))\n }\n }\n\n /// @notice Extracts the deadline from the encoded transaction.\n function deadline(bytes calldata encodedTx) internal pure returns (uint256 deadline_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n deadline_ := calldataload(add(encodedTx.offset, OFFSET_DEADLINE))\n }\n }\n\n /// @notice Extracts the nonce from the encoded transaction.\n function nonce(bytes calldata encodedTx) internal pure returns (uint256 nonce_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n nonce_ := calldataload(add(encodedTx.offset, OFFSET_NONCE))\n }\n }\n\n /// @notice Extracts the exclusivity relayer from the encoded transaction.\n function exclusivityRelayer(bytes calldata encodedTx) internal pure returns (address exclusivityRelayer_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n exclusivityRelayer_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_EXCLUSIVITY_RELAYER)))\n }\n }\n\n /// @notice Extracts the exclusivity end time from the encoded transaction.\n function exclusivityEndTime(bytes calldata encodedTx) internal pure returns (uint256 exclusivityEndTime_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n exclusivityEndTime_ := calldataload(add(encodedTx.offset, OFFSET_EXCLUSIVITY_END_TIME))\n }\n }\n\n /// @notice Extracts the Zap's native value from the encoded transaction.\n function zapNative(bytes calldata encodedTx) internal pure returns (uint256 zapNative_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n zapNative_ := calldataload(add(encodedTx.offset, OFFSET_ZAP_NATIVE))\n }\n }\n\n /// @notice Extracts the Zap's data from the encoded transaction.\n function zapData(bytes calldata encodedTx) internal pure returns (bytes calldata zapData_) {\n zapData_ = encodedTx[OFFSET_ZAP_DATA:];\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/AdminV2.sol\n\n// ════════════════════════════════════════════════ INTERFACES ═════════════════════════════════════════════════════\n\n// ═════════════════════════════════════════════ EXTERNAL IMPORTS ══════════════════════════════════════════════════\n\n/// @title AdminV2\n/// @notice Provides administrative functions and controls for managing the FastBridgeV2 contract,\n/// including access control and configuration settings.\ncontract AdminV2 is AccessControlEnumerable, IAdminV2, IAdminV2Errors {\n using SafeERC20 for IERC20;\n\n /// @notice The address reserved for the native gas token (ETH on Ethereum and most L2s, AVAX on Avalanche, etc.).\n address public constant NATIVE_GAS_TOKEN = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice The role identifier for the Quoter API's off-chain authentication.\n /// @dev Only addresses with this role can post FastBridge quotes to the API.\n bytes32 public constant QUOTER_ROLE = keccak256(\"QUOTER_ROLE\");\n\n /// @notice The role identifier for the Prover's on-chain authentication in FastBridge.\n /// @dev Only addresses with this role can provide proofs that a FastBridge request has been relayed.\n bytes32 public constant PROVER_ROLE = keccak256(\"PROVER_ROLE\");\n\n /// @notice The role identifier for the Guard's on-chain authentication in FastBridge.\n /// @dev Only addresses with this role can dispute submitted relay proofs during the dispute period.\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n\n /// @notice The role identifier for the Canceler's on-chain authentication in FastBridge.\n /// @dev Only addresses with this role can cancel a FastBridge transaction without the cancel delay.\n bytes32 public constant CANCELER_ROLE = keccak256(\"CANCELER_ROLE\");\n\n /// @notice The role identifier for the Governor's on-chain administrative authority.\n /// @dev Only addresses with this role can perform administrative tasks within the contract.\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n /// @notice The denominator for fee rates, representing 100%.\n uint256 public constant FEE_BPS = 1e6;\n /// @notice The maximum protocol fee rate: 1% of the origin amount.\n uint256 public constant FEE_RATE_MAX = 0.01e6;\n\n /// @notice The minimum cancel delay that can be set by the governor.\n uint256 public constant MIN_CANCEL_DELAY = 1 hours;\n /// @notice The default cancel delay set during contract deployment.\n uint256 public constant DEFAULT_CANCEL_DELAY = 1 days;\n\n /// @notice The protocol fee rate taken on the origin amount deposited in the origin chain.\n uint256 public protocolFeeRate;\n\n /// @notice The accumulated protocol fee amounts.\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice The delay period after which a transaction can be permissionlessly cancelled.\n uint256 public cancelDelay;\n\n /// @notice This variable is deprecated and should not be used.\n /// @dev Use ZapNative V2 requests instead.\n uint256 public immutable chainGasAmount = 0;\n\n constructor(address defaultAdmin) {\n _grantRole(DEFAULT_ADMIN_ROLE, defaultAdmin);\n _setCancelDelay(DEFAULT_CANCEL_DELAY);\n }\n\n /// @inheritdoc IAdminV2\n function setCancelDelay(uint256 newCancelDelay) external onlyRole(GOVERNOR_ROLE) {\n _setCancelDelay(newCancelDelay);\n }\n\n /// @inheritdoc IAdminV2\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n if (newFeeRate \u003e FEE_RATE_MAX) revert FeeRateAboveMax();\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n /// @inheritdoc IAdminV2\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n // Early exit if no accumulated fees.\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return;\n // Reset the accumulated fees first.\n protocolFees[token] = 0;\n emit FeesSwept(token, recipient, feeAmount);\n // Sweep the fees as the last transaction action.\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(recipient), feeAmount);\n } else {\n IERC20(token).safeTransfer(recipient, feeAmount);\n }\n }\n\n /// @notice Internal logic to set the cancel delay. Security checks are performed outside of this function.\n /// @dev This function is marked as private to prevent child contracts from calling it directly.\n function _setCancelDelay(uint256 newCancelDelay) private {\n if (newCancelDelay \u003c MIN_CANCEL_DELAY) revert CancelDelayBelowMin();\n uint256 oldCancelDelay = cancelDelay;\n cancelDelay = newCancelDelay;\n emit CancelDelayUpdated(oldCancelDelay, newCancelDelay);\n }\n}\n\n// contracts/FastBridgeV2.sol\n\n// ════════════════════════════════════════════════ INTERFACES ═════════════════════════════════════════════════════\n\n// ═════════════════════════════════════════════ INTERNAL IMPORTS ══════════════════════════════════════════════════\n\n// ═════════════════════════════════════════════ EXTERNAL IMPORTS ══════════════════════════════════════════════════\n\n/// @title FastBridgeV2\n/// @notice Core component of the SynapseRFQ protocol, enabling Relayers (Solvers) to fulfill bridge requests.\n/// Supports ERC20 and native gas tokens, along with the Zap feature for executing actions on the destination chain.\n/// Users interact with the off-chain Quoter API to obtain a current quote for a bridge transaction.\n/// They then submit the bridge request with the quote to this contract, depositing their assets in escrow.\n/// Relayers can fulfill requests by relaying them to the destination chain and must prove fulfillment to claim funds.\n/// Guards monitor proofs and can dispute discrepancies.\n/// Users can reclaim funds by cancelling their requests if it has not been fulfilled within the specified deadline.\ncontract FastBridgeV2 is AdminV2, MulticallTarget, IFastBridgeV2, IFastBridgeV2Errors {\n using BridgeTransactionV2Lib for bytes;\n using SafeERC20 for IERC20;\n\n /// @notice The duration of the dispute period for relayed transactions.\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice The minimum required time between transaction request and deadline.\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n /// @notice The maximum allowed length for zapData.\n uint256 public constant MAX_ZAP_DATA_LENGTH = 2 ** 16 - 1;\n\n /// @notice Maps transaction IDs to bridge details (status, destination chain ID, proof timestamp, and relayer).\n /// Note: this is only stored for transactions having local chain as the origin chain.\n mapping(bytes32 =\u003e BridgeTxDetails) public bridgeTxDetails;\n /// @notice Maps transaction IDs to relay details (block number, block timestamp, and relayer).\n /// Note: this is only stored for transactions having local chain as the destination chain.\n mapping(bytes32 =\u003e BridgeRelay) public bridgeRelayDetails;\n /// @notice Maps sender addresses to their unique bridge nonce.\n mapping(address =\u003e uint256) public senderNonces;\n\n /// @notice This variable is deprecated and should not be used.\n /// @dev Replaced by senderNonces.\n uint256 public immutable nonce = 0;\n /// @notice The block number at which this contract was deployed.\n uint256 public immutable deployBlock;\n\n /// @notice Initializes the FastBridgeV2 contract with the provided default admin,\n /// sets the default cancel delay, and records the deploy block number.\n constructor(address defaultAdmin) AdminV2(defaultAdmin) {\n deployBlock = block.number;\n }\n\n // ══════════════════════════════════════ EXTERNAL MUTABLE (USER FACING) ═══════════════════════════════════════════\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n bridgeV2({\n params: params,\n paramsV2: BridgeParamsV2({\n quoteRelayer: address(0),\n quoteExclusivitySeconds: 0,\n quoteId: bytes(\"\"),\n zapNative: 0,\n zapData: bytes(\"\")\n })\n });\n }\n\n /// Note: this function is deprecated and will be removed in a future version.\n /// @dev Replaced by `cancel`.\n /// @inheritdoc IFastBridge\n function refund(bytes calldata request) external {\n cancelV2(request);\n }\n\n // ══════════════════════════════════════ EXTERNAL MUTABLE (AGENT FACING) ══════════════════════════════════════════\n\n /// @inheritdoc IFastBridge\n function relay(bytes calldata request) external payable {\n // `relay` override will validate the request.\n relayV2({request: request, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes calldata request, bytes32 destTxHash) external {\n request.validateV2();\n proveV2({transactionId: keccak256(request), destTxHash: destTxHash, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridgeV2\n function claimV2(bytes calldata request) external {\n // `claim` override will validate the request.\n claim({request: request, to: address(0)});\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n // Aggregate the read operations from the same storage slot.\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n address disputedRelayer = $.proofRelayer;\n BridgeStatus status = $.status;\n uint56 proofBlockTimestamp = $.proofBlockTimestamp;\n\n // Can only dispute a RELAYER_PROVED transaction within the dispute period.\n if (status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(proofBlockTimestamp) \u003e DISPUTE_PERIOD) {\n revert DisputePeriodPassed();\n }\n\n // Update status to REQUESTED and delete the disputed proof details.\n // Note: these are storage writes.\n $.status = BridgeStatus.REQUESTED;\n $.proofRelayer = address(0);\n $.proofBlockTimestamp = 0;\n\n emit BridgeProofDisputed(transactionId, disputedRelayer);\n }\n\n // ══════════════════════════════════════════════ EXTERNAL VIEWS ═══════════════════════════════════════════════════\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n // The correct relayer can only claim a RELAYER_PROVED transaction after the dispute period.\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n if ($.status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if ($.proofRelayer != relayer) revert SenderIncorrect();\n\n return _timeSince($.proofBlockTimestamp) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n /// @dev This method is added to achieve backwards compatibility with decoding requests into V1 structs:\n /// - `zapNative` is partially reported as a zero/non-zero flag\n /// - `zapData` is ignored\n /// In order to process all kinds of requests use getBridgeTransactionV2 instead.\n function getBridgeTransaction(bytes calldata request) external view returns (BridgeTransaction memory) {\n // Try decoding into V2 struct first. This will revert if V1 struct is passed.\n try this.getBridgeTransactionV2(request) returns (BridgeTransactionV2 memory txV2) {\n // Note: we entirely ignore the zapData field, as it was not present in V1.\n return BridgeTransaction({\n originChainId: txV2.originChainId,\n destChainId: txV2.destChainId,\n originSender: txV2.originSender,\n destRecipient: txV2.destRecipient,\n originToken: txV2.originToken,\n destToken: txV2.destToken,\n originAmount: txV2.originAmount,\n destAmount: txV2.destAmount,\n originFeeAmount: txV2.originFeeAmount,\n sendChainGas: txV2.zapNative != 0,\n deadline: txV2.deadline,\n nonce: txV2.nonce\n });\n } catch {\n // Fallback to V1 struct.\n return abi.decode(request, (BridgeTransaction));\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function getBridgeTransactionV2(bytes calldata request) external pure returns (BridgeTransactionV2 memory) {\n request.validateV2();\n return BridgeTransactionV2Lib.decodeV2(request);\n }\n\n // ═══════════════════════════════════════ PUBLIC MUTABLE (USER FACING) ════════════════════════════════════════════\n\n /// @inheritdoc IFastBridgeV2\n function bridgeV2(BridgeParams memory params, BridgeParamsV2 memory paramsV2) public payable {\n // If relayer exclusivity is not intended for this bridge, set exclusivityEndTime to static zero.\n // Otherwise, set exclusivity to expire at the current block ts offset by quoteExclusivitySeconds.\n int256 exclusivityEndTime = 0;\n if (paramsV2.quoteRelayer != address(0)) {\n exclusivityEndTime = int256(block.timestamp) + paramsV2.quoteExclusivitySeconds;\n }\n _validateBridgeParams(params, paramsV2, exclusivityEndTime);\n\n // Transfer tokens to bridge contract. We use the actual transferred amount in case of transfer fees.\n uint256 originAmount = _takeBridgedUserAsset(params.originToken, params.originAmount);\n\n // Track the amount of origin token owed to protocol.\n uint256 originFeeAmount = 0;\n if (protocolFeeRate \u003e 0) {\n originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n // The Relayer filling this request will be paid the originAmount after fees.\n // Note: the protocol fees will be accumulated only when the Relayer claims the origin collateral.\n originAmount -= originFeeAmount;\n }\n\n // Hash the bridge request and set the initial status to REQUESTED.\n bytes memory request = BridgeTransactionV2Lib.encodeV2(\n BridgeTransactionV2({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n deadline: params.deadline,\n // Increment the sender's nonce on every bridge.\n nonce: senderNonces[params.sender]++,\n exclusivityRelayer: paramsV2.quoteRelayer,\n // We checked exclusivityEndTime to be in range [0 .. params.deadline] above, so can safely cast.\n exclusivityEndTime: uint256(exclusivityEndTime),\n zapNative: paramsV2.zapNative,\n zapData: paramsV2.zapData\n })\n );\n bytes32 transactionId = keccak256(request);\n // Note: the tx status will be updated throughout the tx lifecycle, while destChainId is set once here.\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n bridgeTxDetails[transactionId].destChainId = params.dstChainId;\n\n emit BridgeRequested({\n transactionId: transactionId,\n sender: params.sender,\n request: request,\n destChainId: params.dstChainId,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n sendChainGas: paramsV2.zapNative != 0\n });\n emit BridgeQuoteDetails(transactionId, paramsV2.quoteId);\n }\n\n /// @inheritdoc IFastBridgeV2\n function cancelV2(bytes calldata request) public {\n // Decode the request and check that it could be cancelled.\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n\n // Can only cancel a REQUESTED transaction after its deadline expires.\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n if ($.status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n\n // Permissionless cancel is only allowed after `cancelDelay` on top of the deadline.\n uint256 deadline = request.deadline();\n if (!hasRole(CANCELER_ROLE, msg.sender)) deadline += cancelDelay;\n if (block.timestamp \u003c= deadline) revert DeadlineNotExceeded();\n\n // Update status to REFUNDED.\n // Note: this is a storage write.\n $.status = BridgeStatus.REFUNDED;\n\n // Return the full amount (collateral + protocol fees) to the original sender.\n // The protocol fees are only accumulated when the transaction is claimed, so we don't need to update them here.\n address to = request.originSender();\n address token = request.originToken();\n uint256 amount = request.originAmount() + request.originFeeAmount();\n\n // Emit the event before any external calls.\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n\n // Return the funds to the original sender as last transaction action.\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(to), amount);\n } else {\n IERC20(token).safeTransfer(to, amount);\n }\n }\n\n // ═══════════════════════════════════════ PUBLIC MUTABLE (AGENT FACING) ═══════════════════════════════════════════\n\n /// @inheritdoc IFastBridgeV2\n function relayV2(bytes calldata request, address relayer) public payable {\n // Decode the request and check that it could be relayed.\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n _validateRelayParams(request, transactionId, relayer);\n\n // Mark the bridge request as relayed by saving the relayer and the block details.\n bridgeRelayDetails[transactionId].blockNumber = uint48(block.number);\n bridgeRelayDetails[transactionId].blockTimestamp = uint48(block.timestamp);\n bridgeRelayDetails[transactionId].relayer = relayer;\n\n // Transfer tokens to recipient on destination chain and trigger Zap if requested.\n address to = request.destRecipient();\n address token = request.destToken();\n uint256 amount = request.destAmount();\n uint256 zapNative = request.zapNative();\n\n // Emit the event before any external calls.\n emit BridgeRelayed({\n transactionId: transactionId,\n relayer: relayer,\n to: to,\n originChainId: request.originChainId(),\n originToken: request.originToken(),\n destToken: token,\n originAmount: request.originAmount(),\n destAmount: amount,\n chainGasAmount: zapNative\n });\n\n // All state changes have been done at this point, can proceed to the external calls.\n // This follows the checks-effects-interactions pattern to mitigate potential reentrancy attacks.\n if (token == NATIVE_GAS_TOKEN) {\n // For the native gas token, additional zapNative is not allowed.\n if (zapNative != 0) revert ZapNativeNotSupported();\n // Check that the correct msg.value was sent.\n if (msg.value != amount) revert MsgValueIncorrect();\n // Don't do a native transfer yet: we will handle it alongside the Zap below.\n } else {\n // For ERC20s, we check that the correct msg.value was sent.\n if (msg.value != zapNative) revert MsgValueIncorrect();\n // We need to transfer the tokens from the Relayer to the recipient first before performing an\n // optional post-transfer Zap.\n IERC20(token).safeTransferFrom(msg.sender, to, amount);\n }\n // At this point we have done:\n // - Transferred the requested amount of ERC20 tokens to the recipient.\n // At this point we have confirmed:\n // - For ERC20s: msg.value matches the requested zapNative amount.\n // - For the native gas token: msg.value matches the requested destAmount.\n // Remaining optional things to do:\n // - Forward the full msg.value to the recipient (if non-zero).\n // - Trigger a Zap (if zapData is present).\n bytes calldata zapData = request.zapData();\n if (zapData.length != 0) {\n // Zap Data is present: Zap has been requested by the recipient. Trigger it forwarding the full msg.value.\n _triggerZapWithChecks({recipient: to, token: token, amount: amount, zapData: zapData});\n // Note: if token has a fee on transfers, the recipient will have received less than `amount`.\n // This is a very niche edge case and should be handled by the recipient contract.\n } else if (msg.value != 0) {\n // Zap Data is missing, but msg.value was sent. This could happen in two different cases:\n // - Relay with the native gas token is happening.\n // - Relay with ERC20 is happening, with a `zapNative \u003e 0` request.\n // In both cases, we need to transfer the full msg.value to the recipient.\n Address.sendValue(payable(to), msg.value);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function proveV2(bytes32 transactionId, bytes32 destTxHash, address relayer) public onlyRole(PROVER_ROLE) {\n // Can only prove a REQUESTED transaction.\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n if ($.status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n\n // Update status to RELAYER_PROVED and store the proof details.\n // Note: these are storage writes.\n $.status = BridgeStatus.RELAYER_PROVED;\n $.proofBlockTimestamp = uint56(block.timestamp);\n $.proofRelayer = relayer;\n\n emit BridgeProofProvided(transactionId, relayer, destTxHash);\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes calldata request, address to) public {\n // Decode the request and check that it could be claimed.\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n\n // Aggregate the read operations from the same storage slot.\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n address proofRelayer = $.proofRelayer;\n BridgeStatus status = $.status;\n uint56 proofBlockTimestamp = $.proofBlockTimestamp;\n\n // Can only claim a RELAYER_PROVED transaction after the dispute period.\n if (status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(proofBlockTimestamp) \u003c= DISPUTE_PERIOD) revert DisputePeriodNotPassed();\n if (to == address(0)) {\n // Anyone could claim the funds to the proven relayer on their behalf.\n to = proofRelayer;\n } else if (proofRelayer != msg.sender) {\n // Only the proven relayer could specify an address to claim the funds to.\n revert SenderIncorrect();\n }\n\n // Update status to RELAYER_CLAIMED and transfer the origin collateral to the specified claim address.\n // Note: this is a storage write.\n $.status = BridgeStatus.RELAYER_CLAIMED;\n\n // Accumulate protocol fees if origin fee amount exists.\n address token = request.originToken();\n uint256 amount = request.originAmount();\n uint256 originFeeAmount = request.originFeeAmount();\n if (originFeeAmount \u003e 0) protocolFees[token] += originFeeAmount;\n\n // Emit the event before any external calls.\n emit BridgeDepositClaimed(transactionId, proofRelayer, to, token, amount);\n\n // Complete the relayer claim as the last transaction action.\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(to), amount);\n } else {\n IERC20(token).safeTransfer(to, amount);\n }\n }\n\n // ═══════════════════════════════════════════════ PUBLIC VIEWS ════════════════════════════════════════════════════\n\n /// @inheritdoc IFastBridgeV2\n function bridgeStatuses(bytes32 transactionId) public view returns (BridgeStatus status) {\n return bridgeTxDetails[transactionId].status;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeProofs(bytes32 transactionId) public view returns (uint96 timestamp, address relayer) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n timestamp = $.proofBlockTimestamp;\n relayer = $.proofRelayer;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeRelays(bytes32 transactionId) public view returns (bool) {\n // This transaction has been relayed if the relayer address is recorded.\n return bridgeRelayDetails[transactionId].relayer != address(0);\n }\n\n // ═════════════════════════════════════════════ INTERNAL METHODS ══════════════════════════════════════════════════\n\n /// @notice Takes the bridged asset from the user into FastBridgeV2 custody. The asset will later be\n /// claimed by the relayer who completed the relay on the destination chain, or returned to the user\n /// via the cancel function if no relay is completed.\n function _takeBridgedUserAsset(address token, uint256 amount) internal returns (uint256 amountTaken) {\n if (token == NATIVE_GAS_TOKEN) {\n // For the native gas token, we just need to check that the supplied msg.value is correct.\n // Supplied `msg.value` is already in FastBridgeV2 custody.\n if (amount != msg.value) revert MsgValueIncorrect();\n amountTaken = msg.value;\n } else {\n // For ERC20s, token is explicitly transferred from the user to FastBridgeV2.\n // We don't allow non-zero `msg.value` to avoid extra funds from being stuck in FastBridgeV2.\n if (msg.value != 0) revert MsgValueIncorrect();\n // Throw an explicit error if the provided token address is not a contract.\n if (token.code.length == 0) revert TokenNotContract();\n\n // Use the balance difference as the amount taken in case of fee on transfer tokens.\n amountTaken = IERC20(token).balanceOf(address(this));\n IERC20(token).safeTransferFrom(msg.sender, address(this), amount);\n amountTaken = IERC20(token).balanceOf(address(this)) - amountTaken;\n }\n }\n\n /// @notice Calls the recipient's hook function with the specified zapData and validates\n /// the returned value.\n function _triggerZapWithChecks(address recipient, address token, uint256 amount, bytes calldata zapData) internal {\n // Call the recipient's hook function with the specified zapData, bubbling any revert messages.\n bytes memory returnData = Address.functionCallWithValue({\n target: recipient,\n data: abi.encodeCall(IZapRecipient.zap, (token, amount, zapData)),\n // Note: see `relay()` for reasoning behind passing msg.value.\n value: msg.value\n });\n\n // Explicit revert if no return data at all.\n if (returnData.length == 0) revert RecipientNoReturnValue();\n // Check that exactly a single return value was returned.\n if (returnData.length != 32) revert RecipientIncorrectReturnValue();\n // Return value should be abi-encoded hook function selector.\n if (bytes32(returnData) != bytes32(IZapRecipient.zap.selector)) {\n revert RecipientIncorrectReturnValue();\n }\n }\n\n /// @notice Calculates the time elapsed since a proof was submitted.\n /// @dev The proof.timestamp stores block timestamps as uint56 for gas optimization.\n /// _timeSince(proof) handles timestamp rollover when block.timestamp \u003e type(uint56).max but\n /// proof.timestamp \u003c type(uint56).max via an unchecked statement.\n /// @param proofBlockTimestamp The block timestamp when the proof was submitted.\n /// @return delta The time elapsed since proof submission.\n function _timeSince(uint56 proofBlockTimestamp) internal view returns (uint256 delta) {\n unchecked {\n delta = uint56(block.timestamp) - proofBlockTimestamp;\n }\n }\n\n /// @notice Validates all parameters required for a bridge transaction.\n /// @dev This function's complexity cannot be reduced due to the number of required checks,\n /// so we disable the code-complexity rule.\n // solhint-disable-next-line code-complexity\n function _validateBridgeParams(\n BridgeParams memory params,\n BridgeParamsV2 memory paramsV2,\n int256 exclusivityEndTime\n )\n internal\n view\n {\n // Check V1 (legacy) params.\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.sender == address(0) || params.to == address(0)) revert ZeroAddress();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n\n // Check V2 params.\n if (paramsV2.zapData.length \u003e MAX_ZAP_DATA_LENGTH) revert ZapDataLengthAboveMax();\n if (paramsV2.zapNative != 0 \u0026\u0026 params.destToken == NATIVE_GAS_TOKEN) {\n revert ZapNativeNotSupported();\n }\n\n // exclusivityEndTime must be in range [0 .. params.deadline].\n if (exclusivityEndTime \u003c 0 || exclusivityEndTime \u003e int256(params.deadline)) {\n revert ExclusivityParamsIncorrect();\n }\n }\n\n /// @notice Validates all parameters required for a relay transaction.\n function _validateRelayParams(bytes calldata request, bytes32 transactionId, address relayer) internal view {\n if (relayer == address(0)) revert ZeroAddress();\n // Check that the transaction has not been relayed yet and is for the current chain.\n if (bridgeRelays(transactionId)) revert TransactionRelayed();\n if (request.destChainId() != block.chainid) revert ChainIncorrect();\n // Check that the deadline for relay to happen has not passed yet.\n if (block.timestamp \u003e request.deadline()) revert DeadlineExceeded();\n // Check the exclusivity period, if it was specified and is still ongoing.\n address exclRelayer = request.exclusivityRelayer();\n if (exclRelayer != address(0) \u0026\u0026 exclRelayer != relayer \u0026\u0026 block.timestamp \u003c= request.exclusivityEndTime()) {\n revert ExclusivityPeriodNotPassed();\n }\n }\n}\n","language":"Solidity","languageVersion":"0.8.24","compilerVersion":"0.8.24","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"","srcMapRuntime":"","abiDefinition":[{"inputs":[],"name":"MulticallTarget__UndeterminedRevert","type":"error"},{"inputs":[{"internalType":"bytes[]","name":"data","type":"bytes[]"},{"internalType":"bool","name":"ignoreReverts","type":"bool"}],"name":"multicallNoResults","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes[]","name":"data","type":"bytes[]"},{"internalType":"bool","name":"ignoreReverts","type":"bool"}],"name":"multicallWithResults","outputs":[{"components":[{"internalType":"bool","name":"success","type":"bool"},{"internalType":"bytes","name":"returnData","type":"bytes"}],"internalType":"struct IMulticallTarget.Result[]","name":"results","type":"tuple[]"}],"stateMutability":"nonpayable","type":"function"}],"userDoc":{"kind":"user","methods":{"multicallNoResults(bytes[],bool)":{"notice":"Executes multiple calls to this contract in a single transaction while preserving msg.sender. Return data from the calls is discarded."},"multicallWithResults(bytes[],bool)":{"notice":"Executes multiple calls to this contract in a single transaction while preserving msg.sender. Return data from each call is preserved."}},"notice":"Abstract contract template that supports batched calls while preserving msg.sender. Only calls with msg.value of 0 can be batched.","version":1},"developerDoc":{"kind":"dev","methods":{"multicallNoResults(bytes[],bool)":{"details":"This method is non-payable, so only calls with msg.value of 0 can be batched. If ignoreReverts is set to true, reverted calls will be skipped. Otherwise, the entire batch will revert with the original revert reason.","params":{"data":"List of ABI-encoded calldata for the calls to execute","ignoreReverts":"Whether to skip calls that revert"}},"multicallWithResults(bytes[],bool)":{"details":"This method is non-payable, so only calls with msg.value of 0 can be batched. If ignoreReverts is set to true, reverted calls will be skipped. Otherwise, the entire batch will revert with the original revert reason.","params":{"data":"List of ABI-encoded calldata for the calls to execute","ignoreReverts":"Whether to skip calls that revert"},"returns":{"results":" List of results from the calls, each containing (success, returnData)"}}},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[],\"name\":\"MulticallTarget__UndeterminedRevert\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"bytes[]\",\"name\":\"data\",\"type\":\"bytes[]\"},{\"internalType\":\"bool\",\"name\":\"ignoreReverts\",\"type\":\"bool\"}],\"name\":\"multicallNoResults\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes[]\",\"name\":\"data\",\"type\":\"bytes[]\"},{\"internalType\":\"bool\",\"name\":\"ignoreReverts\",\"type\":\"bool\"}],\"name\":\"multicallWithResults\",\"outputs\":[{\"components\":[{\"internalType\":\"bool\",\"name\":\"success\",\"type\":\"bool\"},{\"internalType\":\"bytes\",\"name\":\"returnData\",\"type\":\"bytes\"}],\"internalType\":\"struct IMulticallTarget.Result[]\",\"name\":\"results\",\"type\":\"tuple[]\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{\"multicallNoResults(bytes[],bool)\":{\"details\":\"This method is non-payable, so only calls with msg.value of 0 can be batched. If ignoreReverts is set to true, reverted calls will be skipped. Otherwise, the entire batch will revert with the original revert reason.\",\"params\":{\"data\":\"List of ABI-encoded calldata for the calls to execute\",\"ignoreReverts\":\"Whether to skip calls that revert\"}},\"multicallWithResults(bytes[],bool)\":{\"details\":\"This method is non-payable, so only calls with msg.value of 0 can be batched. If ignoreReverts is set to true, reverted calls will be skipped. Otherwise, the entire batch will revert with the original revert reason.\",\"params\":{\"data\":\"List of ABI-encoded calldata for the calls to execute\",\"ignoreReverts\":\"Whether to skip calls that revert\"},\"returns\":{\"results\":\" List of results from the calls, each containing (success, returnData)\"}}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"multicallNoResults(bytes[],bool)\":{\"notice\":\"Executes multiple calls to this contract in a single transaction while preserving msg.sender. Return data from the calls is discarded.\"},\"multicallWithResults(bytes[],bool)\":{\"notice\":\"Executes multiple calls to this contract in a single transaction while preserving msg.sender. Return data from each call is preserved.\"}},\"notice\":\"Abstract contract template that supports batched calls while preserving msg.sender. Only calls with msg.value of 0 can be batched.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeV2.sol\":\"MulticallTarget\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeV2.sol\":{\"keccak256\":\"0xaab2ee7357681726f0faf799a48ddfbf45fb4da93b69abf61c33dde92b29b74d\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://673391bff9569efc0f9bd99e0e6fece0bc8e8af1f052bb071b407b267a17b3b5\",\"dweb:/ipfs/QmdQQZ6DxpJYhfpinwU5WjLugr2f6qP8h68b5GerhSMQ4j\"]}},\"version\":1}"},"hashes":{"multicallNoResults(bytes[],bool)":"3f61331d","multicallWithResults(bytes[],bool)":"385c1d2f"}},"solidity/FastBridgeV2.sol:SafeERC20":{"code":"0x60566037600b82828239805160001a607314602a57634e487b7160e01b600052600060045260246000fd5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600080fdfea2646970667358221220efeebe297f7317982e4aa5525f5b73e1604baf8d70a09b9809f700b1855f985d64736f6c63430008180033","runtime-code":"0x73000000000000000000000000000000000000000030146080604052600080fdfea2646970667358221220efeebe297f7317982e4aa5525f5b73e1604baf8d70a09b9809f700b1855f985d64736f6c63430008180033","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.24 ^0.8.20 ^0.8.4;\n\n// contracts/interfaces/IAdminV2.sol\n\ninterface IAdminV2 {\n event CancelDelayUpdated(uint256 oldCancelDelay, uint256 newCancelDelay);\n event FeeRateUpdated(uint256 oldFeeRate, uint256 newFeeRate);\n event FeesSwept(address token, address recipient, uint256 amount);\n\n /// @notice Allows the governor to set the cancel delay. The cancel delay is the time period after the transaction\n /// deadline during which a transaction can be permissionlessly cancelled if it hasn't been proven by any Relayer.\n function setCancelDelay(uint256 newCancelDelay) external;\n\n /// @notice Allows the governor to set the protocol fee rate. The protocol fee is taken from the origin\n /// amount and is only applied to completed and claimed transactions.\n /// @dev The protocol fee is abstracted away from the relayers; they always operate using the amounts after fees.\n /// The origin amount they see in the emitted log is what they get credited with.\n function setProtocolFeeRate(uint256 newFeeRate) external;\n\n /// @notice Allows the governor to withdraw the accumulated protocol fees from the contract.\n function sweepProtocolFees(address token, address recipient) external;\n}\n\n// contracts/interfaces/IAdminV2Errors.sol\n\ninterface IAdminV2Errors {\n error CancelDelayBelowMin();\n error FeeRateAboveMax();\n}\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IFastBridgeV2Errors.sol\n\ninterface IFastBridgeV2Errors {\n error AmountIncorrect();\n error ChainIncorrect();\n error ExclusivityParamsIncorrect();\n error MsgValueIncorrect();\n error SenderIncorrect();\n error StatusIncorrect();\n error TokenNotContract();\n error ZapDataLengthAboveMax();\n error ZapNativeNotSupported();\n error ZeroAddress();\n\n error RecipientIncorrectReturnValue();\n error RecipientNoReturnValue();\n\n error DeadlineExceeded();\n error DeadlineNotExceeded();\n error DeadlineTooShort();\n error DisputePeriodNotPassed();\n error DisputePeriodPassed();\n error ExclusivityPeriodNotPassed();\n\n error TransactionRelayed();\n}\n\n// contracts/interfaces/IMulticallTarget.sol\n\n/// @notice Interface for a contract that supports multiple calls from the same caller. Inspired by MulticallV3:\n/// https://github.com/mds1/multicall/blob/master/src/Multicall3.sol\ninterface IMulticallTarget {\n struct Result {\n bool success;\n bytes returnData;\n }\n\n /// @notice Executes multiple calls to this contract in a single transaction while preserving msg.sender.\n /// Return data from the calls is discarded.\n /// @dev This method is non-payable, so only calls with msg.value of 0 can be batched.\n /// If ignoreReverts is set to true, reverted calls will be skipped.\n /// Otherwise, the entire batch will revert with the original revert reason.\n /// @param data List of ABI-encoded calldata for the calls to execute\n /// @param ignoreReverts Whether to skip calls that revert\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external;\n\n /// @notice Executes multiple calls to this contract in a single transaction while preserving msg.sender.\n /// Return data from each call is preserved.\n /// @dev This method is non-payable, so only calls with msg.value of 0 can be batched.\n /// If ignoreReverts is set to true, reverted calls will be skipped.\n /// Otherwise, the entire batch will revert with the original revert reason.\n /// @param data List of ABI-encoded calldata for the calls to execute\n /// @param ignoreReverts Whether to skip calls that revert\n /// @return results List of results from the calls, each containing (success, returnData)\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results);\n}\n\n// contracts/interfaces/IZapRecipient.sol\n\n/// @notice Interface for contracts that can perform Zap operations. Such contracts could be used as Recipients\n/// in a FastBridge transaction that includes a Zap operation. The Zap Data should include instructions on how\n/// exactly the Zap operation should be executed, which would typically include the target address and calldata\n/// to use. The exact implementation of the Zap Data encoding is up to the Recipient contract.\ninterface IZapRecipient {\n /// @notice Performs a Zap operation with the given token and amount according to the provided Zap data.\n /// @param token The address of the token being used for the Zap operation.\n /// @param amount The amount of tokens to be used.\n /// @param zapData The encoded data specifying how the Zap operation should be executed.\n /// @return The function selector to indicate successful execution.\n function zap(address token, uint256 amount, bytes memory zapData) external payable returns (bytes4);\n}\n\n// node_modules/@openzeppelin/contracts/access/IAccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n\n// node_modules/@openzeppelin/contracts/utils/Address.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error AddressInsufficientBalance(address account);\n\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedInnerCall();\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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance \u003c amount) {\n revert AddressInsufficientBalance(address(this));\n }\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n if (!success) {\n revert FailedInnerCall();\n }\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 or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {FailedInnerCall} error.\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 function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\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 function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance \u003c value) {\n revert AddressInsufficientBalance(address(this));\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\n * unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 \u0026\u0026 target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {FailedInnerCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert FailedInnerCall();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/Context.sol\n\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\n// node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)\n// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```solidity\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n *\n * [WARNING]\n * ====\n * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure\n * unusable.\n * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.\n *\n * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an\n * array of EnumerableSet.\n * ====\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n // Position is the index of the value in the `values` array plus 1.\n // Position 0 is used to mean a value is not in the set.\n mapping(bytes32 value =\u003e uint256) _positions;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._positions[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We cache the value's position to prevent multiple reads from the same storage slot\n uint256 position = set._positions[value];\n\n if (position != 0) {\n // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as 'swap and pop').\n // This modifies the order of the array, as noted in {at}.\n\n uint256 valueIndex = position - 1;\n uint256 lastIndex = set._values.length - 1;\n\n if (valueIndex != lastIndex) {\n bytes32 lastValue = set._values[lastIndex];\n\n // Move the lastValue to the index where the value to delete is\n set._values[valueIndex] = lastValue;\n // Update the tracked position of the lastValue (that was just moved)\n set._positions[lastValue] = position;\n }\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the tracked position for the deleted slot\n delete set._positions[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._positions[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n return set._values[index];\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function _values(Set storage set) private view returns (bytes32[] memory) {\n return set._values;\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n bytes32[] memory store = _values(set._inner);\n bytes32[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(AddressSet storage set) internal view returns (address[] memory) {\n bytes32[] memory store = _values(set._inner);\n address[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n\n /**\n * @dev Return the entire set in an array\n *\n * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n */\n function values(UintSet storage set) internal view returns (uint256[] memory) {\n bytes32[] memory store = _values(set._inner);\n uint256[] memory result;\n\n /// @solidity memory-safe-assembly\n assembly {\n result := store\n }\n\n return result;\n }\n}\n\n// contracts/interfaces/IFastBridgeV2.sol\n\ninterface IFastBridgeV2 is IFastBridge {\n enum BridgeStatus {\n NULL, // Doesn't exist yet.\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n struct BridgeTxDetails {\n BridgeStatus status;\n uint32 destChainId;\n uint56 proofBlockTimestamp;\n address proofRelayer;\n }\n\n struct BridgeRelay {\n uint48 blockNumber;\n uint48 blockTimestamp;\n address relayer;\n }\n\n /// @notice New params introduced in the FastBridgeV2.\n /// We are passing fields from the older BridgeParams struct outside of this struct for backwards compatibility.\n /// Note: quoteRelayer and quoteExclusivitySeconds are either both zero (indicating no exclusivity)\n /// or both non-zero (indicating exclusivity for the given period).\n /// Note: zapNative \u003e 0 can NOT be used with destToken = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE (native token)\n /// @param quoteRelayer Relayer that provided the quote for the transaction\n /// @param quoteExclusivitySeconds Period of time the quote relayer is guaranteed exclusivity after user's deposit\n /// @param quoteId Unique quote identifier used for tracking the quote\n /// @param zapNative ETH value to send to the recipient (if any)\n /// @param zapData Parameters for the Zap to the destination recipient (if any)\n struct BridgeParamsV2 {\n address quoteRelayer;\n int256 quoteExclusivitySeconds;\n bytes quoteId;\n uint256 zapNative;\n bytes zapData;\n }\n\n /// @notice Updated bridge transaction struct to include parameters introduced in FastBridgeV2.\n /// Note: only `exclusivityRelayer` can fill such a transaction until `exclusivityEndTime`.\n struct BridgeTransactionV2 {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n // Note: sendChainGas flag from V1 is deprecated\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n address exclusivityRelayer;\n uint256 exclusivityEndTime;\n uint256 zapNative; // ETH value to send to the recipient (if any)\n bytes zapData; // data to pass for the Zap action (if any)\n }\n\n event BridgeQuoteDetails(bytes32 indexed transactionId, bytes quoteId);\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability\n /// to provide temporary exclusivity fill rights for the quote relayer.\n /// @param params The parameters required to bridge\n /// @param paramsV2 The parameters for exclusivity fill rights (optional, can be left empty)\n function bridgeV2(BridgeParams memory params, BridgeParamsV2 memory paramsV2) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function relayV2(bytes memory request, address relayer) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param transactionId The transaction id associated with the encoded bridge transaction to prove\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function proveV2(bytes32 transactionId, bytes32 destTxHash, address relayer) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital.\n /// @notice Can only send funds to the relayer address on the proof.\n /// @param request The encoded bridge transaction to claim on origin chain\n function claimV2(bytes memory request) external;\n\n /// @notice Cancels an outstanding bridge transaction in case optimistic bridging failed and returns the full amount\n /// to the original sender.\n /// @param request The encoded bridge transaction to refund\n function cancelV2(bytes memory request) external;\n\n /// @notice Checks if a transaction has been relayed\n /// @param transactionId The ID of the transaction to check\n /// @return True if the transaction has been relayed, false otherwise\n function bridgeRelays(bytes32 transactionId) external view returns (bool);\n\n /// @notice Returns the status of a bridge transaction\n /// @param transactionId The ID of the bridge transaction\n /// @return BridgeStatus Status of the bridge transaction\n function bridgeStatuses(bytes32 transactionId) external view returns (BridgeStatus);\n\n /// @notice Returns the timestamp and relayer of a bridge proof\n /// @param transactionId The ID of the bridge transaction\n /// @return timestamp The timestamp of the bridge proof\n /// @return relayer The relayer address of the bridge proof\n function bridgeProofs(bytes32 transactionId) external view returns (uint96 timestamp, address relayer);\n\n /// @notice Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\n /// @param request The bridge request to decode\n function getBridgeTransactionV2(bytes memory request) external view returns (BridgeTransactionV2 memory);\n}\n\n// contracts/utils/MulticallTarget.sol\n\n// solhint-disable avoid-low-level-calls\n/// @notice Abstract contract template that supports batched calls while preserving msg.sender.\n/// Only calls with msg.value of 0 can be batched.\nabstract contract MulticallTarget is IMulticallTarget {\n error MulticallTarget__UndeterminedRevert();\n\n /// @inheritdoc IMulticallTarget\n function multicallNoResults(bytes[] calldata data, bool ignoreReverts) external {\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (bool success, bytes memory result) = address(this).delegatecall(data[i]);\n if (!success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(result);\n }\n }\n }\n\n /// @inheritdoc IMulticallTarget\n function multicallWithResults(\n bytes[] calldata data,\n bool ignoreReverts\n )\n external\n returns (Result[] memory results)\n {\n results = new Result[](data.length);\n for (uint256 i = 0; i \u003c data.length; ++i) {\n // We perform a delegate call to ourself to preserve the msg.sender. This is identical to `msg.sender`\n // calling the functions directly one by one, therefore doesn't add any security risks.\n // Note: msg.value is also preserved when doing a delegate call, but this function is not payable,\n // so it's always 0 and not a security risk.\n (results[i].success, results[i].returnData) = address(this).delegatecall(data[i]);\n if (!results[i].success \u0026\u0026 !ignoreReverts) {\n _bubbleRevert(results[i].returnData);\n }\n }\n }\n\n /// @dev Bubbles the revert message from the underlying call.\n /// Note: preserves the same custom error or revert string, if one was used.\n /// Source: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v5.0.2/contracts/utils/Address.sol#L143-L158\n function _bubbleRevert(bytes memory returnData) internal pure {\n // Look for revert reason and bubble it up if present\n if (returnData.length \u003e 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n // solhint-disable-next-line no-inline-assembly\n assembly {\n let returndata_size := mload(returnData)\n revert(add(32, returnData), returndata_size)\n }\n } else {\n revert MulticallTarget__UndeterminedRevert();\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol)\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n\n// node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n\n// contracts/libs/BridgeTransactionV2.sol\n\n// solhint-disable no-inline-assembly\nlibrary BridgeTransactionV2Lib {\n uint16 internal constant VERSION = 2;\n\n // Offsets of the fields in the packed BridgeTransactionV2 struct\n // uint16 version [000 .. 002)\n // uint32 originChainId [002 .. 006)\n // uint32 destChainId [006 .. 010)\n // address originSender [010 .. 030)\n // address destRecipient [030 .. 050)\n // address originToken [050 .. 070)\n // address destToken [070 .. 090)\n // uint256 originAmount [090 .. 122)\n // uint256 destAmount [122 .. 154)\n // uint256 originFeeAmount [154 .. 186)\n // uint256 deadline [186 .. 218)\n // uint256 nonce [218 .. 250)\n // address exclusivityRelayer [250 .. 270)\n // uint256 exclusivityEndTime [270 .. 302)\n // uint256 zapNative [302 .. 334)\n // bytes zapData [334 .. ***)\n\n // forgefmt: disable-start\n uint256 private constant OFFSET_ORIGIN_CHAIN_ID = 2;\n uint256 private constant OFFSET_DEST_CHAIN_ID = 6;\n uint256 private constant OFFSET_ORIGIN_SENDER = 10;\n uint256 private constant OFFSET_DEST_RECIPIENT = 30;\n uint256 private constant OFFSET_ORIGIN_TOKEN = 50;\n uint256 private constant OFFSET_DEST_TOKEN = 70;\n uint256 private constant OFFSET_ORIGIN_AMOUNT = 90;\n uint256 private constant OFFSET_DEST_AMOUNT = 122;\n uint256 private constant OFFSET_ORIGIN_FEE_AMOUNT = 154;\n uint256 private constant OFFSET_DEADLINE = 186;\n uint256 private constant OFFSET_NONCE = 218;\n uint256 private constant OFFSET_EXCLUSIVITY_RELAYER = 250;\n uint256 private constant OFFSET_EXCLUSIVITY_END_TIME = 270;\n uint256 private constant OFFSET_ZAP_NATIVE = 302;\n uint256 private constant OFFSET_ZAP_DATA = 334;\n // forgefmt: disable-end\n\n error BridgeTransactionV2__InvalidEncodedTx();\n error BridgeTransactionV2__UnsupportedVersion(uint16 version);\n\n /// @notice Validates that the encoded transaction is a tightly packed encoded payload for BridgeTransactionV2.\n /// @dev Checks the minimum length and the version, use this function before decoding any of the fields.\n function validateV2(bytes calldata encodedTx) internal pure {\n // Check the minimum length: must at least include all static fields.\n if (encodedTx.length \u003c OFFSET_ZAP_DATA) revert BridgeTransactionV2__InvalidEncodedTx();\n // Once we validated the length, we can be sure that the version field is present.\n uint16 version_ = version(encodedTx);\n if (version_ != VERSION) revert BridgeTransactionV2__UnsupportedVersion(version_);\n }\n\n /// @notice Encodes the BridgeTransactionV2 struct by tightly packing the fields.\n /// @dev `abi.decode` will not work as a result of the tightly packed fields. Use `decodeV2` to decode instead.\n function encodeV2(IFastBridgeV2.BridgeTransactionV2 memory bridgeTx) internal pure returns (bytes memory) {\n // We split the encoding into two parts to avoid stack-too-deep error\n bytes memory firstPart = abi.encodePacked(\n VERSION,\n bridgeTx.originChainId,\n bridgeTx.destChainId,\n bridgeTx.originSender,\n bridgeTx.destRecipient,\n bridgeTx.originToken,\n bridgeTx.destToken,\n bridgeTx.originAmount\n );\n return abi.encodePacked(\n firstPart,\n bridgeTx.destAmount,\n bridgeTx.originFeeAmount,\n // Note: we skip the deprecated `sendChainGas` flag, which was present in BridgeTransaction V1\n bridgeTx.deadline,\n bridgeTx.nonce,\n // New V2 fields: exclusivity\n bridgeTx.exclusivityRelayer,\n bridgeTx.exclusivityEndTime,\n // New V2 fields: Zap\n bridgeTx.zapNative,\n bridgeTx.zapData\n );\n }\n\n /// @notice Decodes the BridgeTransactionV2 struct from the encoded transaction.\n /// @dev Encoded BridgeTransactionV2 struct must be tightly packed.\n /// Use `validateV2` before decoding to ensure the encoded transaction is valid.\n function decodeV2(bytes calldata encodedTx)\n internal\n pure\n returns (IFastBridgeV2.BridgeTransactionV2 memory bridgeTx)\n {\n bridgeTx.originChainId = originChainId(encodedTx);\n bridgeTx.destChainId = destChainId(encodedTx);\n bridgeTx.originSender = originSender(encodedTx);\n bridgeTx.destRecipient = destRecipient(encodedTx);\n bridgeTx.originToken = originToken(encodedTx);\n bridgeTx.destToken = destToken(encodedTx);\n bridgeTx.originAmount = originAmount(encodedTx);\n bridgeTx.destAmount = destAmount(encodedTx);\n bridgeTx.originFeeAmount = originFeeAmount(encodedTx);\n bridgeTx.deadline = deadline(encodedTx);\n bridgeTx.nonce = nonce(encodedTx);\n bridgeTx.exclusivityRelayer = exclusivityRelayer(encodedTx);\n bridgeTx.exclusivityEndTime = exclusivityEndTime(encodedTx);\n bridgeTx.zapNative = zapNative(encodedTx);\n bridgeTx.zapData = zapData(encodedTx);\n }\n\n /// @notice Extracts the version from the encoded transaction.\n function version(bytes calldata encodedTx) internal pure returns (uint16 version_) {\n // Load 32 bytes from the start and shift it 240 bits to the right to get the highest 16 bits.\n assembly {\n version_ := shr(240, calldataload(encodedTx.offset))\n }\n }\n\n /// @notice Extracts the origin chain ID from the encoded transaction.\n function originChainId(bytes calldata encodedTx) internal pure returns (uint32 originChainId_) {\n // Load 32 bytes from the offset and shift it 224 bits to the right to get the highest 32 bits.\n assembly {\n originChainId_ := shr(224, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_CHAIN_ID)))\n }\n }\n\n /// @notice Extracts the destination chain ID from the encoded transaction.\n function destChainId(bytes calldata encodedTx) internal pure returns (uint32 destChainId_) {\n // Load 32 bytes from the offset and shift it 224 bits to the right to get the highest 32 bits.\n assembly {\n destChainId_ := shr(224, calldataload(add(encodedTx.offset, OFFSET_DEST_CHAIN_ID)))\n }\n }\n\n /// @notice Extracts the origin sender from the encoded transaction.\n function originSender(bytes calldata encodedTx) internal pure returns (address originSender_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n originSender_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_SENDER)))\n }\n }\n\n /// @notice Extracts the destination recipient from the encoded transaction.\n function destRecipient(bytes calldata encodedTx) internal pure returns (address destRecipient_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n destRecipient_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_DEST_RECIPIENT)))\n }\n }\n\n /// @notice Extracts the origin token from the encoded transaction.\n function originToken(bytes calldata encodedTx) internal pure returns (address originToken_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n originToken_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_TOKEN)))\n }\n }\n\n /// @notice Extracts the destination token from the encoded transaction.\n function destToken(bytes calldata encodedTx) internal pure returns (address destToken_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n destToken_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_DEST_TOKEN)))\n }\n }\n\n /// @notice Extracts the origin amount from the encoded transaction.\n function originAmount(bytes calldata encodedTx) internal pure returns (uint256 originAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n originAmount_ := calldataload(add(encodedTx.offset, OFFSET_ORIGIN_AMOUNT))\n }\n }\n\n /// @notice Extracts the destination amount from the encoded transaction.\n function destAmount(bytes calldata encodedTx) internal pure returns (uint256 destAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n destAmount_ := calldataload(add(encodedTx.offset, OFFSET_DEST_AMOUNT))\n }\n }\n\n /// @notice Extracts the origin fee amount from the encoded transaction.\n function originFeeAmount(bytes calldata encodedTx) internal pure returns (uint256 originFeeAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n originFeeAmount_ := calldataload(add(encodedTx.offset, OFFSET_ORIGIN_FEE_AMOUNT))\n }\n }\n\n /// @notice Extracts the deadline from the encoded transaction.\n function deadline(bytes calldata encodedTx) internal pure returns (uint256 deadline_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n deadline_ := calldataload(add(encodedTx.offset, OFFSET_DEADLINE))\n }\n }\n\n /// @notice Extracts the nonce from the encoded transaction.\n function nonce(bytes calldata encodedTx) internal pure returns (uint256 nonce_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n nonce_ := calldataload(add(encodedTx.offset, OFFSET_NONCE))\n }\n }\n\n /// @notice Extracts the exclusivity relayer from the encoded transaction.\n function exclusivityRelayer(bytes calldata encodedTx) internal pure returns (address exclusivityRelayer_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n exclusivityRelayer_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_EXCLUSIVITY_RELAYER)))\n }\n }\n\n /// @notice Extracts the exclusivity end time from the encoded transaction.\n function exclusivityEndTime(bytes calldata encodedTx) internal pure returns (uint256 exclusivityEndTime_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n exclusivityEndTime_ := calldataload(add(encodedTx.offset, OFFSET_EXCLUSIVITY_END_TIME))\n }\n }\n\n /// @notice Extracts the Zap's native value from the encoded transaction.\n function zapNative(bytes calldata encodedTx) internal pure returns (uint256 zapNative_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n zapNative_ := calldataload(add(encodedTx.offset, OFFSET_ZAP_NATIVE))\n }\n }\n\n /// @notice Extracts the Zap's data from the encoded transaction.\n function zapData(bytes calldata encodedTx) internal pure returns (bytes calldata zapData_) {\n zapData_ = encodedTx[OFFSET_ZAP_DATA:];\n }\n}\n\n// node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using Address for address;\n\n /**\n * @dev An operation with an ERC20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance \u003c requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n // the target address contains contract code and also asserts for success in the low-level call.\n\n bytes memory returndata = address(token).functionCall(data);\n if (returndata.length != 0 \u0026\u0026 !abi.decode(returndata, (bool))) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n // and not revert is the subcall reverts.\n\n (bool success, bytes memory returndata) = address(token).call(data);\n return success \u0026\u0026 (returndata.length == 0 || abi.decode(returndata, (bool))) \u0026\u0026 address(token).code.length \u003e 0;\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/AccessControl.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account =\u003e bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role =\u003e RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n\n// node_modules/@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol\n\n// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol)\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n using EnumerableSet for EnumerableSet.AddressSet;\n\n mapping(bytes32 role =\u003e EnumerableSet.AddressSet) private _roleMembers;\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns one of the accounts that have `role`. `index` must be a\n * value between 0 and {getRoleMemberCount}, non-inclusive.\n *\n * Role bearers are not sorted in any particular way, and their ordering may\n * change at any point.\n *\n * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n * you perform all queries on the same block. See the following\n * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n * for more information.\n */\n function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {\n return _roleMembers[role].at(index);\n }\n\n /**\n * @dev Returns the number of accounts that have `role`. Can be used\n * together with {getRoleMember} to enumerate all bearers of a role.\n */\n function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {\n return _roleMembers[role].length();\n }\n\n /**\n * @dev Overload {AccessControl-_grantRole} to track enumerable memberships\n */\n function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool granted = super._grantRole(role, account);\n if (granted) {\n _roleMembers[role].add(account);\n }\n return granted;\n }\n\n /**\n * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships\n */\n function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {\n bool revoked = super._revokeRole(role, account);\n if (revoked) {\n _roleMembers[role].remove(account);\n }\n return revoked;\n }\n}\n\n// contracts/AdminV2.sol\n\n// ════════════════════════════════════════════════ INTERFACES ═════════════════════════════════════════════════════\n\n// ═════════════════════════════════════════════ EXTERNAL IMPORTS ══════════════════════════════════════════════════\n\n/// @title AdminV2\n/// @notice Provides administrative functions and controls for managing the FastBridgeV2 contract,\n/// including access control and configuration settings.\ncontract AdminV2 is AccessControlEnumerable, IAdminV2, IAdminV2Errors {\n using SafeERC20 for IERC20;\n\n /// @notice The address reserved for the native gas token (ETH on Ethereum and most L2s, AVAX on Avalanche, etc.).\n address public constant NATIVE_GAS_TOKEN = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;\n\n /// @notice The role identifier for the Quoter API's off-chain authentication.\n /// @dev Only addresses with this role can post FastBridge quotes to the API.\n bytes32 public constant QUOTER_ROLE = keccak256(\"QUOTER_ROLE\");\n\n /// @notice The role identifier for the Prover's on-chain authentication in FastBridge.\n /// @dev Only addresses with this role can provide proofs that a FastBridge request has been relayed.\n bytes32 public constant PROVER_ROLE = keccak256(\"PROVER_ROLE\");\n\n /// @notice The role identifier for the Guard's on-chain authentication in FastBridge.\n /// @dev Only addresses with this role can dispute submitted relay proofs during the dispute period.\n bytes32 public constant GUARD_ROLE = keccak256(\"GUARD_ROLE\");\n\n /// @notice The role identifier for the Canceler's on-chain authentication in FastBridge.\n /// @dev Only addresses with this role can cancel a FastBridge transaction without the cancel delay.\n bytes32 public constant CANCELER_ROLE = keccak256(\"CANCELER_ROLE\");\n\n /// @notice The role identifier for the Governor's on-chain administrative authority.\n /// @dev Only addresses with this role can perform administrative tasks within the contract.\n bytes32 public constant GOVERNOR_ROLE = keccak256(\"GOVERNOR_ROLE\");\n\n /// @notice The denominator for fee rates, representing 100%.\n uint256 public constant FEE_BPS = 1e6;\n /// @notice The maximum protocol fee rate: 1% of the origin amount.\n uint256 public constant FEE_RATE_MAX = 0.01e6;\n\n /// @notice The minimum cancel delay that can be set by the governor.\n uint256 public constant MIN_CANCEL_DELAY = 1 hours;\n /// @notice The default cancel delay set during contract deployment.\n uint256 public constant DEFAULT_CANCEL_DELAY = 1 days;\n\n /// @notice The protocol fee rate taken on the origin amount deposited in the origin chain.\n uint256 public protocolFeeRate;\n\n /// @notice The accumulated protocol fee amounts.\n mapping(address =\u003e uint256) public protocolFees;\n\n /// @notice The delay period after which a transaction can be permissionlessly cancelled.\n uint256 public cancelDelay;\n\n /// @notice This variable is deprecated and should not be used.\n /// @dev Use ZapNative V2 requests instead.\n uint256 public immutable chainGasAmount = 0;\n\n constructor(address defaultAdmin) {\n _grantRole(DEFAULT_ADMIN_ROLE, defaultAdmin);\n _setCancelDelay(DEFAULT_CANCEL_DELAY);\n }\n\n /// @inheritdoc IAdminV2\n function setCancelDelay(uint256 newCancelDelay) external onlyRole(GOVERNOR_ROLE) {\n _setCancelDelay(newCancelDelay);\n }\n\n /// @inheritdoc IAdminV2\n function setProtocolFeeRate(uint256 newFeeRate) external onlyRole(GOVERNOR_ROLE) {\n if (newFeeRate \u003e FEE_RATE_MAX) revert FeeRateAboveMax();\n uint256 oldFeeRate = protocolFeeRate;\n protocolFeeRate = newFeeRate;\n emit FeeRateUpdated(oldFeeRate, newFeeRate);\n }\n\n /// @inheritdoc IAdminV2\n function sweepProtocolFees(address token, address recipient) external onlyRole(GOVERNOR_ROLE) {\n // Early exit if no accumulated fees.\n uint256 feeAmount = protocolFees[token];\n if (feeAmount == 0) return;\n // Reset the accumulated fees first.\n protocolFees[token] = 0;\n emit FeesSwept(token, recipient, feeAmount);\n // Sweep the fees as the last transaction action.\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(recipient), feeAmount);\n } else {\n IERC20(token).safeTransfer(recipient, feeAmount);\n }\n }\n\n /// @notice Internal logic to set the cancel delay. Security checks are performed outside of this function.\n /// @dev This function is marked as private to prevent child contracts from calling it directly.\n function _setCancelDelay(uint256 newCancelDelay) private {\n if (newCancelDelay \u003c MIN_CANCEL_DELAY) revert CancelDelayBelowMin();\n uint256 oldCancelDelay = cancelDelay;\n cancelDelay = newCancelDelay;\n emit CancelDelayUpdated(oldCancelDelay, newCancelDelay);\n }\n}\n\n// contracts/FastBridgeV2.sol\n\n// ════════════════════════════════════════════════ INTERFACES ═════════════════════════════════════════════════════\n\n// ═════════════════════════════════════════════ INTERNAL IMPORTS ══════════════════════════════════════════════════\n\n// ═════════════════════════════════════════════ EXTERNAL IMPORTS ══════════════════════════════════════════════════\n\n/// @title FastBridgeV2\n/// @notice Core component of the SynapseRFQ protocol, enabling Relayers (Solvers) to fulfill bridge requests.\n/// Supports ERC20 and native gas tokens, along with the Zap feature for executing actions on the destination chain.\n/// Users interact with the off-chain Quoter API to obtain a current quote for a bridge transaction.\n/// They then submit the bridge request with the quote to this contract, depositing their assets in escrow.\n/// Relayers can fulfill requests by relaying them to the destination chain and must prove fulfillment to claim funds.\n/// Guards monitor proofs and can dispute discrepancies.\n/// Users can reclaim funds by cancelling their requests if it has not been fulfilled within the specified deadline.\ncontract FastBridgeV2 is AdminV2, MulticallTarget, IFastBridgeV2, IFastBridgeV2Errors {\n using BridgeTransactionV2Lib for bytes;\n using SafeERC20 for IERC20;\n\n /// @notice The duration of the dispute period for relayed transactions.\n uint256 public constant DISPUTE_PERIOD = 30 minutes;\n\n /// @notice The minimum required time between transaction request and deadline.\n uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;\n\n /// @notice The maximum allowed length for zapData.\n uint256 public constant MAX_ZAP_DATA_LENGTH = 2 ** 16 - 1;\n\n /// @notice Maps transaction IDs to bridge details (status, destination chain ID, proof timestamp, and relayer).\n /// Note: this is only stored for transactions having local chain as the origin chain.\n mapping(bytes32 =\u003e BridgeTxDetails) public bridgeTxDetails;\n /// @notice Maps transaction IDs to relay details (block number, block timestamp, and relayer).\n /// Note: this is only stored for transactions having local chain as the destination chain.\n mapping(bytes32 =\u003e BridgeRelay) public bridgeRelayDetails;\n /// @notice Maps sender addresses to their unique bridge nonce.\n mapping(address =\u003e uint256) public senderNonces;\n\n /// @notice This variable is deprecated and should not be used.\n /// @dev Replaced by senderNonces.\n uint256 public immutable nonce = 0;\n /// @notice The block number at which this contract was deployed.\n uint256 public immutable deployBlock;\n\n /// @notice Initializes the FastBridgeV2 contract with the provided default admin,\n /// sets the default cancel delay, and records the deploy block number.\n constructor(address defaultAdmin) AdminV2(defaultAdmin) {\n deployBlock = block.number;\n }\n\n // ══════════════════════════════════════ EXTERNAL MUTABLE (USER FACING) ═══════════════════════════════════════════\n\n /// @inheritdoc IFastBridge\n function bridge(BridgeParams memory params) external payable {\n bridgeV2({\n params: params,\n paramsV2: BridgeParamsV2({\n quoteRelayer: address(0),\n quoteExclusivitySeconds: 0,\n quoteId: bytes(\"\"),\n zapNative: 0,\n zapData: bytes(\"\")\n })\n });\n }\n\n /// Note: this function is deprecated and will be removed in a future version.\n /// @dev Replaced by `cancel`.\n /// @inheritdoc IFastBridge\n function refund(bytes calldata request) external {\n cancelV2(request);\n }\n\n // ══════════════════════════════════════ EXTERNAL MUTABLE (AGENT FACING) ══════════════════════════════════════════\n\n /// @inheritdoc IFastBridge\n function relay(bytes calldata request) external payable {\n // `relay` override will validate the request.\n relayV2({request: request, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridge\n function prove(bytes calldata request, bytes32 destTxHash) external {\n request.validateV2();\n proveV2({transactionId: keccak256(request), destTxHash: destTxHash, relayer: msg.sender});\n }\n\n /// @inheritdoc IFastBridgeV2\n function claimV2(bytes calldata request) external {\n // `claim` override will validate the request.\n claim({request: request, to: address(0)});\n }\n\n /// @inheritdoc IFastBridge\n function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {\n // Aggregate the read operations from the same storage slot.\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n address disputedRelayer = $.proofRelayer;\n BridgeStatus status = $.status;\n uint56 proofBlockTimestamp = $.proofBlockTimestamp;\n\n // Can only dispute a RELAYER_PROVED transaction within the dispute period.\n if (status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(proofBlockTimestamp) \u003e DISPUTE_PERIOD) {\n revert DisputePeriodPassed();\n }\n\n // Update status to REQUESTED and delete the disputed proof details.\n // Note: these are storage writes.\n $.status = BridgeStatus.REQUESTED;\n $.proofRelayer = address(0);\n $.proofBlockTimestamp = 0;\n\n emit BridgeProofDisputed(transactionId, disputedRelayer);\n }\n\n // ══════════════════════════════════════════════ EXTERNAL VIEWS ═══════════════════════════════════════════════════\n\n /// @inheritdoc IFastBridge\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {\n // The correct relayer can only claim a RELAYER_PROVED transaction after the dispute period.\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n if ($.status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if ($.proofRelayer != relayer) revert SenderIncorrect();\n\n return _timeSince($.proofBlockTimestamp) \u003e DISPUTE_PERIOD;\n }\n\n /// @inheritdoc IFastBridge\n /// @dev This method is added to achieve backwards compatibility with decoding requests into V1 structs:\n /// - `zapNative` is partially reported as a zero/non-zero flag\n /// - `zapData` is ignored\n /// In order to process all kinds of requests use getBridgeTransactionV2 instead.\n function getBridgeTransaction(bytes calldata request) external view returns (BridgeTransaction memory) {\n // Try decoding into V2 struct first. This will revert if V1 struct is passed.\n try this.getBridgeTransactionV2(request) returns (BridgeTransactionV2 memory txV2) {\n // Note: we entirely ignore the zapData field, as it was not present in V1.\n return BridgeTransaction({\n originChainId: txV2.originChainId,\n destChainId: txV2.destChainId,\n originSender: txV2.originSender,\n destRecipient: txV2.destRecipient,\n originToken: txV2.originToken,\n destToken: txV2.destToken,\n originAmount: txV2.originAmount,\n destAmount: txV2.destAmount,\n originFeeAmount: txV2.originFeeAmount,\n sendChainGas: txV2.zapNative != 0,\n deadline: txV2.deadline,\n nonce: txV2.nonce\n });\n } catch {\n // Fallback to V1 struct.\n return abi.decode(request, (BridgeTransaction));\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function getBridgeTransactionV2(bytes calldata request) external pure returns (BridgeTransactionV2 memory) {\n request.validateV2();\n return BridgeTransactionV2Lib.decodeV2(request);\n }\n\n // ═══════════════════════════════════════ PUBLIC MUTABLE (USER FACING) ════════════════════════════════════════════\n\n /// @inheritdoc IFastBridgeV2\n function bridgeV2(BridgeParams memory params, BridgeParamsV2 memory paramsV2) public payable {\n // If relayer exclusivity is not intended for this bridge, set exclusivityEndTime to static zero.\n // Otherwise, set exclusivity to expire at the current block ts offset by quoteExclusivitySeconds.\n int256 exclusivityEndTime = 0;\n if (paramsV2.quoteRelayer != address(0)) {\n exclusivityEndTime = int256(block.timestamp) + paramsV2.quoteExclusivitySeconds;\n }\n _validateBridgeParams(params, paramsV2, exclusivityEndTime);\n\n // Transfer tokens to bridge contract. We use the actual transferred amount in case of transfer fees.\n uint256 originAmount = _takeBridgedUserAsset(params.originToken, params.originAmount);\n\n // Track the amount of origin token owed to protocol.\n uint256 originFeeAmount = 0;\n if (protocolFeeRate \u003e 0) {\n originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;\n // The Relayer filling this request will be paid the originAmount after fees.\n // Note: the protocol fees will be accumulated only when the Relayer claims the origin collateral.\n originAmount -= originFeeAmount;\n }\n\n // Hash the bridge request and set the initial status to REQUESTED.\n bytes memory request = BridgeTransactionV2Lib.encodeV2(\n BridgeTransactionV2({\n originChainId: uint32(block.chainid),\n destChainId: params.dstChainId,\n originSender: params.sender,\n destRecipient: params.to,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n originFeeAmount: originFeeAmount,\n deadline: params.deadline,\n // Increment the sender's nonce on every bridge.\n nonce: senderNonces[params.sender]++,\n exclusivityRelayer: paramsV2.quoteRelayer,\n // We checked exclusivityEndTime to be in range [0 .. params.deadline] above, so can safely cast.\n exclusivityEndTime: uint256(exclusivityEndTime),\n zapNative: paramsV2.zapNative,\n zapData: paramsV2.zapData\n })\n );\n bytes32 transactionId = keccak256(request);\n // Note: the tx status will be updated throughout the tx lifecycle, while destChainId is set once here.\n bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;\n bridgeTxDetails[transactionId].destChainId = params.dstChainId;\n\n emit BridgeRequested({\n transactionId: transactionId,\n sender: params.sender,\n request: request,\n destChainId: params.dstChainId,\n originToken: params.originToken,\n destToken: params.destToken,\n originAmount: originAmount,\n destAmount: params.destAmount,\n sendChainGas: paramsV2.zapNative != 0\n });\n emit BridgeQuoteDetails(transactionId, paramsV2.quoteId);\n }\n\n /// @inheritdoc IFastBridgeV2\n function cancelV2(bytes calldata request) public {\n // Decode the request and check that it could be cancelled.\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n\n // Can only cancel a REQUESTED transaction after its deadline expires.\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n if ($.status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n\n // Permissionless cancel is only allowed after `cancelDelay` on top of the deadline.\n uint256 deadline = request.deadline();\n if (!hasRole(CANCELER_ROLE, msg.sender)) deadline += cancelDelay;\n if (block.timestamp \u003c= deadline) revert DeadlineNotExceeded();\n\n // Update status to REFUNDED.\n // Note: this is a storage write.\n $.status = BridgeStatus.REFUNDED;\n\n // Return the full amount (collateral + protocol fees) to the original sender.\n // The protocol fees are only accumulated when the transaction is claimed, so we don't need to update them here.\n address to = request.originSender();\n address token = request.originToken();\n uint256 amount = request.originAmount() + request.originFeeAmount();\n\n // Emit the event before any external calls.\n emit BridgeDepositRefunded(transactionId, to, token, amount);\n\n // Return the funds to the original sender as last transaction action.\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(to), amount);\n } else {\n IERC20(token).safeTransfer(to, amount);\n }\n }\n\n // ═══════════════════════════════════════ PUBLIC MUTABLE (AGENT FACING) ═══════════════════════════════════════════\n\n /// @inheritdoc IFastBridgeV2\n function relayV2(bytes calldata request, address relayer) public payable {\n // Decode the request and check that it could be relayed.\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n _validateRelayParams(request, transactionId, relayer);\n\n // Mark the bridge request as relayed by saving the relayer and the block details.\n bridgeRelayDetails[transactionId].blockNumber = uint48(block.number);\n bridgeRelayDetails[transactionId].blockTimestamp = uint48(block.timestamp);\n bridgeRelayDetails[transactionId].relayer = relayer;\n\n // Transfer tokens to recipient on destination chain and trigger Zap if requested.\n address to = request.destRecipient();\n address token = request.destToken();\n uint256 amount = request.destAmount();\n uint256 zapNative = request.zapNative();\n\n // Emit the event before any external calls.\n emit BridgeRelayed({\n transactionId: transactionId,\n relayer: relayer,\n to: to,\n originChainId: request.originChainId(),\n originToken: request.originToken(),\n destToken: token,\n originAmount: request.originAmount(),\n destAmount: amount,\n chainGasAmount: zapNative\n });\n\n // All state changes have been done at this point, can proceed to the external calls.\n // This follows the checks-effects-interactions pattern to mitigate potential reentrancy attacks.\n if (token == NATIVE_GAS_TOKEN) {\n // For the native gas token, additional zapNative is not allowed.\n if (zapNative != 0) revert ZapNativeNotSupported();\n // Check that the correct msg.value was sent.\n if (msg.value != amount) revert MsgValueIncorrect();\n // Don't do a native transfer yet: we will handle it alongside the Zap below.\n } else {\n // For ERC20s, we check that the correct msg.value was sent.\n if (msg.value != zapNative) revert MsgValueIncorrect();\n // We need to transfer the tokens from the Relayer to the recipient first before performing an\n // optional post-transfer Zap.\n IERC20(token).safeTransferFrom(msg.sender, to, amount);\n }\n // At this point we have done:\n // - Transferred the requested amount of ERC20 tokens to the recipient.\n // At this point we have confirmed:\n // - For ERC20s: msg.value matches the requested zapNative amount.\n // - For the native gas token: msg.value matches the requested destAmount.\n // Remaining optional things to do:\n // - Forward the full msg.value to the recipient (if non-zero).\n // - Trigger a Zap (if zapData is present).\n bytes calldata zapData = request.zapData();\n if (zapData.length != 0) {\n // Zap Data is present: Zap has been requested by the recipient. Trigger it forwarding the full msg.value.\n _triggerZapWithChecks({recipient: to, token: token, amount: amount, zapData: zapData});\n // Note: if token has a fee on transfers, the recipient will have received less than `amount`.\n // This is a very niche edge case and should be handled by the recipient contract.\n } else if (msg.value != 0) {\n // Zap Data is missing, but msg.value was sent. This could happen in two different cases:\n // - Relay with the native gas token is happening.\n // - Relay with ERC20 is happening, with a `zapNative \u003e 0` request.\n // In both cases, we need to transfer the full msg.value to the recipient.\n Address.sendValue(payable(to), msg.value);\n }\n }\n\n /// @inheritdoc IFastBridgeV2\n function proveV2(bytes32 transactionId, bytes32 destTxHash, address relayer) public onlyRole(PROVER_ROLE) {\n // Can only prove a REQUESTED transaction.\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n if ($.status != BridgeStatus.REQUESTED) revert StatusIncorrect();\n\n // Update status to RELAYER_PROVED and store the proof details.\n // Note: these are storage writes.\n $.status = BridgeStatus.RELAYER_PROVED;\n $.proofBlockTimestamp = uint56(block.timestamp);\n $.proofRelayer = relayer;\n\n emit BridgeProofProvided(transactionId, relayer, destTxHash);\n }\n\n /// @inheritdoc IFastBridge\n function claim(bytes calldata request, address to) public {\n // Decode the request and check that it could be claimed.\n request.validateV2();\n bytes32 transactionId = keccak256(request);\n\n // Aggregate the read operations from the same storage slot.\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n address proofRelayer = $.proofRelayer;\n BridgeStatus status = $.status;\n uint56 proofBlockTimestamp = $.proofBlockTimestamp;\n\n // Can only claim a RELAYER_PROVED transaction after the dispute period.\n if (status != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();\n if (_timeSince(proofBlockTimestamp) \u003c= DISPUTE_PERIOD) revert DisputePeriodNotPassed();\n if (to == address(0)) {\n // Anyone could claim the funds to the proven relayer on their behalf.\n to = proofRelayer;\n } else if (proofRelayer != msg.sender) {\n // Only the proven relayer could specify an address to claim the funds to.\n revert SenderIncorrect();\n }\n\n // Update status to RELAYER_CLAIMED and transfer the origin collateral to the specified claim address.\n // Note: this is a storage write.\n $.status = BridgeStatus.RELAYER_CLAIMED;\n\n // Accumulate protocol fees if origin fee amount exists.\n address token = request.originToken();\n uint256 amount = request.originAmount();\n uint256 originFeeAmount = request.originFeeAmount();\n if (originFeeAmount \u003e 0) protocolFees[token] += originFeeAmount;\n\n // Emit the event before any external calls.\n emit BridgeDepositClaimed(transactionId, proofRelayer, to, token, amount);\n\n // Complete the relayer claim as the last transaction action.\n if (token == NATIVE_GAS_TOKEN) {\n Address.sendValue(payable(to), amount);\n } else {\n IERC20(token).safeTransfer(to, amount);\n }\n }\n\n // ═══════════════════════════════════════════════ PUBLIC VIEWS ════════════════════════════════════════════════════\n\n /// @inheritdoc IFastBridgeV2\n function bridgeStatuses(bytes32 transactionId) public view returns (BridgeStatus status) {\n return bridgeTxDetails[transactionId].status;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeProofs(bytes32 transactionId) public view returns (uint96 timestamp, address relayer) {\n BridgeTxDetails storage $ = bridgeTxDetails[transactionId];\n timestamp = $.proofBlockTimestamp;\n relayer = $.proofRelayer;\n }\n\n /// @inheritdoc IFastBridgeV2\n function bridgeRelays(bytes32 transactionId) public view returns (bool) {\n // This transaction has been relayed if the relayer address is recorded.\n return bridgeRelayDetails[transactionId].relayer != address(0);\n }\n\n // ═════════════════════════════════════════════ INTERNAL METHODS ══════════════════════════════════════════════════\n\n /// @notice Takes the bridged asset from the user into FastBridgeV2 custody. The asset will later be\n /// claimed by the relayer who completed the relay on the destination chain, or returned to the user\n /// via the cancel function if no relay is completed.\n function _takeBridgedUserAsset(address token, uint256 amount) internal returns (uint256 amountTaken) {\n if (token == NATIVE_GAS_TOKEN) {\n // For the native gas token, we just need to check that the supplied msg.value is correct.\n // Supplied `msg.value` is already in FastBridgeV2 custody.\n if (amount != msg.value) revert MsgValueIncorrect();\n amountTaken = msg.value;\n } else {\n // For ERC20s, token is explicitly transferred from the user to FastBridgeV2.\n // We don't allow non-zero `msg.value` to avoid extra funds from being stuck in FastBridgeV2.\n if (msg.value != 0) revert MsgValueIncorrect();\n // Throw an explicit error if the provided token address is not a contract.\n if (token.code.length == 0) revert TokenNotContract();\n\n // Use the balance difference as the amount taken in case of fee on transfer tokens.\n amountTaken = IERC20(token).balanceOf(address(this));\n IERC20(token).safeTransferFrom(msg.sender, address(this), amount);\n amountTaken = IERC20(token).balanceOf(address(this)) - amountTaken;\n }\n }\n\n /// @notice Calls the recipient's hook function with the specified zapData and validates\n /// the returned value.\n function _triggerZapWithChecks(address recipient, address token, uint256 amount, bytes calldata zapData) internal {\n // Call the recipient's hook function with the specified zapData, bubbling any revert messages.\n bytes memory returnData = Address.functionCallWithValue({\n target: recipient,\n data: abi.encodeCall(IZapRecipient.zap, (token, amount, zapData)),\n // Note: see `relay()` for reasoning behind passing msg.value.\n value: msg.value\n });\n\n // Explicit revert if no return data at all.\n if (returnData.length == 0) revert RecipientNoReturnValue();\n // Check that exactly a single return value was returned.\n if (returnData.length != 32) revert RecipientIncorrectReturnValue();\n // Return value should be abi-encoded hook function selector.\n if (bytes32(returnData) != bytes32(IZapRecipient.zap.selector)) {\n revert RecipientIncorrectReturnValue();\n }\n }\n\n /// @notice Calculates the time elapsed since a proof was submitted.\n /// @dev The proof.timestamp stores block timestamps as uint56 for gas optimization.\n /// _timeSince(proof) handles timestamp rollover when block.timestamp \u003e type(uint56).max but\n /// proof.timestamp \u003c type(uint56).max via an unchecked statement.\n /// @param proofBlockTimestamp The block timestamp when the proof was submitted.\n /// @return delta The time elapsed since proof submission.\n function _timeSince(uint56 proofBlockTimestamp) internal view returns (uint256 delta) {\n unchecked {\n delta = uint56(block.timestamp) - proofBlockTimestamp;\n }\n }\n\n /// @notice Validates all parameters required for a bridge transaction.\n /// @dev This function's complexity cannot be reduced due to the number of required checks,\n /// so we disable the code-complexity rule.\n // solhint-disable-next-line code-complexity\n function _validateBridgeParams(\n BridgeParams memory params,\n BridgeParamsV2 memory paramsV2,\n int256 exclusivityEndTime\n )\n internal\n view\n {\n // Check V1 (legacy) params.\n if (params.dstChainId == block.chainid) revert ChainIncorrect();\n if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();\n if (params.sender == address(0) || params.to == address(0)) revert ZeroAddress();\n if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();\n if (params.deadline \u003c block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();\n\n // Check V2 params.\n if (paramsV2.zapData.length \u003e MAX_ZAP_DATA_LENGTH) revert ZapDataLengthAboveMax();\n if (paramsV2.zapNative != 0 \u0026\u0026 params.destToken == NATIVE_GAS_TOKEN) {\n revert ZapNativeNotSupported();\n }\n\n // exclusivityEndTime must be in range [0 .. params.deadline].\n if (exclusivityEndTime \u003c 0 || exclusivityEndTime \u003e int256(params.deadline)) {\n revert ExclusivityParamsIncorrect();\n }\n }\n\n /// @notice Validates all parameters required for a relay transaction.\n function _validateRelayParams(bytes calldata request, bytes32 transactionId, address relayer) internal view {\n if (relayer == address(0)) revert ZeroAddress();\n // Check that the transaction has not been relayed yet and is for the current chain.\n if (bridgeRelays(transactionId)) revert TransactionRelayed();\n if (request.destChainId() != block.chainid) revert ChainIncorrect();\n // Check that the deadline for relay to happen has not passed yet.\n if (block.timestamp \u003e request.deadline()) revert DeadlineExceeded();\n // Check the exclusivity period, if it was specified and is still ongoing.\n address exclRelayer = request.exclusivityRelayer();\n if (exclRelayer != address(0) \u0026\u0026 exclRelayer != relayer \u0026\u0026 block.timestamp \u003c= request.exclusivityEndTime()) {\n revert ExclusivityPeriodNotPassed();\n }\n }\n}\n","language":"Solidity","languageVersion":"0.8.24","compilerVersion":"0.8.24","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"63186:5018:0:-:0;;;;;;;;;;;;;;;-1:-1:-1;;;63186:5018:0;;;;;;;;;;;;;;;;;","srcMapRuntime":"63186:5018:0:-:0;;;;;;;;","abiDefinition":[{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"currentAllowance","type":"uint256"},{"internalType":"uint256","name":"requestedDecrease","type":"uint256"}],"name":"SafeERC20FailedDecreaseAllowance","type":"error"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"SafeERC20FailedOperation","type":"error"}],"userDoc":{"kind":"user","methods":{},"version":1},"developerDoc":{"details":"Wrappers around ERC20 operations that throw on failure (when the token contract returns false). Tokens that return no value (and instead revert or throw on failure) are also supported, non-reverting calls are assumed to be successful. To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract, which allows you to call the safe operations as `token.safeTransfer(...)`, etc.","errors":{"SafeERC20FailedDecreaseAllowance(address,uint256,uint256)":[{"details":"Indicates a failed `decreaseAllowance` request."}],"SafeERC20FailedOperation(address)":[{"details":"An operation with an ERC20 token failed."}]},"kind":"dev","methods":{},"title":"SafeERC20","version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"currentAllowance\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"requestedDecrease\",\"type\":\"uint256\"}],\"name\":\"SafeERC20FailedDecreaseAllowance\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"}],\"name\":\"SafeERC20FailedOperation\",\"type\":\"error\"}],\"devdoc\":{\"details\":\"Wrappers around ERC20 operations that throw on failure (when the token contract returns false). Tokens that return no value (and instead revert or throw on failure) are also supported, non-reverting calls are assumed to be successful. To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract, which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\",\"errors\":{\"SafeERC20FailedDecreaseAllowance(address,uint256,uint256)\":[{\"details\":\"Indicates a failed `decreaseAllowance` request.\"}],\"SafeERC20FailedOperation(address)\":[{\"details\":\"An operation with an ERC20 token failed.\"}]},\"kind\":\"dev\",\"methods\":{},\"title\":\"SafeERC20\",\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/FastBridgeV2.sol\":\"SafeERC20\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/FastBridgeV2.sol\":{\"keccak256\":\"0xaab2ee7357681726f0faf799a48ddfbf45fb4da93b69abf61c33dde92b29b74d\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://673391bff9569efc0f9bd99e0e6fece0bc8e8af1f052bb071b407b267a17b3b5\",\"dweb:/ipfs/QmdQQZ6DxpJYhfpinwU5WjLugr2f6qP8h68b5GerhSMQ4j\"]}},\"version\":1}"},"hashes":{}}} \ No newline at end of file diff --git a/services/rfq/e2e/rfq_test.go b/services/rfq/e2e/rfq_test.go index 975b75a959..3de433d45f 100644 --- a/services/rfq/e2e/rfq_test.go +++ b/services/rfq/e2e/rfq_test.go @@ -478,7 +478,7 @@ func (i *IntegrationSuite) TestZap() { ZapData: []byte("Hello, world!"), ZapNative: big.NewInt(1_337_420), } - tx, err = originFastBridge.Bridge0(auth.TransactOpts, params, paramsV2) + tx, err = originFastBridge.BridgeV2(auth.TransactOpts, params, paramsV2) i.NoError(err) i.originBackend.WaitForConfirmation(i.GetTestContext(), tx) @@ -589,7 +589,7 @@ func (i *IntegrationSuite) TestDispute() { // call prove() from the relayer wallet before relay actually occurred on dest relayerAuth := i.originBackend.GetTxContext(i.GetTestContext(), i.relayerWallet.AddressPtr()) fakeHash := common.HexToHash("0xdeadbeef") - tx, err = originFastBridge.Prove(relayerAuth.TransactOpts, txID, fakeHash, relayerAuth.From) + tx, err = originFastBridge.ProveV2(relayerAuth.TransactOpts, txID, fakeHash, relayerAuth.From) i.NoError(err) i.originBackend.WaitForConfirmation(i.GetTestContext(), tx) diff --git a/services/rfq/relayer/chain/chain.go b/services/rfq/relayer/chain/chain.go index 07ffd4896b..7fed1ff887 100644 --- a/services/rfq/relayer/chain/chain.go +++ b/services/rfq/relayer/chain/chain.go @@ -89,7 +89,7 @@ func (c Chain) SubmitRelay(ctx context.Context, request reldb.QuoteRequest) (uin nonce, err := c.SubmitTransaction(ctx, func(transactor *bind.TransactOpts) (tx *types.Transaction, err error) { transactor.Value = core.CopyBigInt(gasAmount) - tx, err = c.Bridge.Relay0(transactor, request.RawRequest, c.submitter.Address()) + tx, err = c.Bridge.RelayV2(transactor, request.RawRequest, c.submitter.Address()) if err != nil { return nil, fmt.Errorf("could not relay: %w", err) } diff --git a/services/rfq/relayer/service/handlers.go b/services/rfq/relayer/service/handlers.go index 02563655b9..5856861976 100644 --- a/services/rfq/relayer/service/handlers.go +++ b/services/rfq/relayer/service/handlers.go @@ -472,7 +472,7 @@ func (q *QuoteRequestHandler) handleRelayCompleted(ctx context.Context, span tra // relay has been finalized, it's time to go back to the origin chain and try to prove _, err = q.Origin.SubmitTransaction(ctx, func(transactor *bind.TransactOpts) (tx *types.Transaction, err error) { - tx, err = q.Origin.Bridge.Prove0(transactor, request.RawRequest, request.DestTxHash) + tx, err = q.Origin.Bridge.Prove(transactor, request.RawRequest, request.DestTxHash) if err != nil { return nil, fmt.Errorf("could not relay: %w", err) } From 21323698f8566517861fce082f94fe25e16675c7 Mon Sep 17 00:00:00 2001 From: Daniel Wasserman Date: Tue, 26 Nov 2024 12:30:12 -0500 Subject: [PATCH 54/85] [goreleaser] From 57efbd00dd6a84490ebc919feb1f478d14650c0a Mon Sep 17 00:00:00 2001 From: dwasse Date: Tue, 26 Nov 2024 13:50:47 -0600 Subject: [PATCH 55/85] feat(rfq-guard): v2 guard logic [SLT-387] (#3324) * Feat: add FastBridgeAddress to pending proven model * Feat: add v2 address to config * Feat: add fastBridgeHandlers and v1/v2 specific guard logic * Feat: different listener logic on v1/v2 * WIP: add RelayerAddressV1 to relayer config * WIP: addr v1 is ptr * Feat: remove fastBridgeHandler * Fix: TestDispute * Cleanup: func sig * Cleanup: lint * Fix: e2e test * proposed mods for feat/guard-v2 [SLT-422] (#3364) * relabeling & using v2 events/parsing for both versions * lint * typo * addtl nil check on deref * prove multicalled relays [SLT-422] * runChainListener tweak. Parse proof relabel * removing fastbridgev1 BridgeRequested & refs * test probe - revert guard listener label * restore legacy listener "guard" label. Establish "guardV2" for new version * poke to rerun w/o explorer check * removing dev comments * [goreleaser] * Feat: add fastbridgev2 and fastbridge for integration tests * WIP: add separate dispute tests * Fix: e2e --------- Co-authored-by: parodime --- services/rfq/e2e/rfq_test.go | 107 +++++++++- services/rfq/e2e/setup_test.go | 95 +++++++-- services/rfq/guard/guardconfig/config.go | 35 ++- services/rfq/guard/guarddb/base/model.go | 32 +-- services/rfq/guard/guarddb/db.go | 17 +- services/rfq/guard/service/guard.go | 201 ++++++++++++++---- services/rfq/guard/service/handlers.go | 166 +++++++++++---- services/rfq/relayer/relconfig/config.go | 4 +- services/rfq/testutil/contracttype.go | 7 +- .../rfq/testutil/contracttypeimpl_string.go | 19 +- services/rfq/testutil/deployers.go | 24 ++- services/rfq/testutil/typecast.go | 12 +- 12 files changed, 575 insertions(+), 144 deletions(-) diff --git a/services/rfq/e2e/rfq_test.go b/services/rfq/e2e/rfq_test.go index 3de433d45f..5674ba18f5 100644 --- a/services/rfq/e2e/rfq_test.go +++ b/services/rfq/e2e/rfq_test.go @@ -165,7 +165,7 @@ func (i *IntegrationSuite) TestUSDCtoUSDC() { }) // now we can send the money - _, originFastBridge := i.manager.GetFastBridge(i.GetTestContext(), i.originBackend) + _, originFastBridge := i.manager.GetFastBridgeV2(i.GetTestContext(), i.originBackend) auth := i.originBackend.GetTxContext(i.GetTestContext(), i.userWallet.AddressPtr()) tx, err = originFastBridge.Bridge(auth.TransactOpts, fastbridgev2.IFastBridgeBridgeParams{ DstChainId: uint32(i.destBackend.GetChainID()), @@ -318,7 +318,7 @@ func (i *IntegrationSuite) TestETHtoETH() { }) // now we can send the money - _, originFastBridge := i.manager.GetFastBridge(i.GetTestContext(), i.originBackend) + _, originFastBridge := i.manager.GetFastBridgeV2(i.GetTestContext(), i.originBackend) auth := i.originBackend.GetTxContext(i.GetTestContext(), i.userWallet.AddressPtr()) auth.TransactOpts.Value = realWantAmount // we want 499 ETH for 500 requested within a day @@ -458,7 +458,7 @@ func (i *IntegrationSuite) TestZap() { }) // now we can send the money - _, originFastBridge := i.manager.GetFastBridge(i.GetTestContext(), i.originBackend) + _, originFastBridge := i.manager.GetFastBridgeV2(i.GetTestContext(), i.originBackend) _, destRecipient := i.manager.GetRecipientMock(i.GetTestContext(), i.destBackend) auth := i.originBackend.GetTxContext(i.GetTestContext(), i.userWallet.AddressPtr()) params := fastbridgev2.IFastBridgeBridgeParams{ @@ -511,7 +511,7 @@ func (i *IntegrationSuite) TestZap() { }) } -func (i *IntegrationSuite) TestDispute() { +func (i *IntegrationSuite) TestDisputeV1() { // start the guard go func() { _ = i.guard.Start(i.GetTestContext()) @@ -551,6 +551,103 @@ func (i *IntegrationSuite) TestDispute() { _, originFastBridge := i.manager.GetFastBridge(i.GetTestContext(), i.originBackend) auth := i.originBackend.GetTxContext(i.GetTestContext(), i.userWallet.AddressPtr()) // we want 499 usdc for 500 requested within a day + tx, err = originFastBridge.Bridge(auth.TransactOpts, fastbridge.IFastBridgeBridgeParams{ + DstChainId: uint32(i.destBackend.GetChainID()), + Sender: i.userWallet.Address(), + To: i.userWallet.Address(), + OriginToken: originUSDC.Address(), + SendChainGas: true, + DestToken: destUSDC.Address(), + OriginAmount: realRFQAmount, + DestAmount: new(big.Int).Sub(realRFQAmount, big.NewInt(10_000_000)), + Deadline: new(big.Int).SetInt64(time.Now().Add(time.Hour * 24).Unix()), + }) + i.NoError(err) + i.originBackend.WaitForConfirmation(i.GetTestContext(), tx) + + // fetch the txid and raw request + var txID [32]byte + var rawRequest []byte + parser, err := fastbridge.NewParser(originFastBridge.Address()) + i.NoError(err) + i.Eventually(func() bool { + receipt, err := i.originBackend.TransactionReceipt(i.GetTestContext(), tx.Hash()) + i.NoError(err) + for _, log := range receipt.Logs { + _, parsedEvent, ok := parser.ParseEvent(*log) + if !ok { + continue + } + event, ok := parsedEvent.(*fastbridge.FastBridgeBridgeRequested) + if ok { + txID = event.TransactionId + rawRequest = event.Request + return true + } + } + return false + }) + + // call prove() from the relayer wallet before relay actually occurred on dest + relayerAuth := i.originBackend.GetTxContext(i.GetTestContext(), i.relayerWallet.AddressPtr()) + fakeHash := common.HexToHash("0xdeadbeef") + tx, err = originFastBridge.Prove(relayerAuth.TransactOpts, rawRequest, fakeHash) + i.NoError(err) + i.originBackend.WaitForConfirmation(i.GetTestContext(), tx) + + // verify that the guard calls Dispute() + i.Eventually(func() bool { + results, err := i.guardStore.GetPendingProvensByStatus(i.GetTestContext(), guarddb.Disputed) + i.NoError(err) + if len(results) != 1 { + return false + } + result, err := i.guardStore.GetPendingProvenByID(i.GetTestContext(), txID) + i.NoError(err) + return result.TxHash == fakeHash && result.Status == guarddb.Disputed && result.TransactionID == txID + }) +} + +func (i *IntegrationSuite) TestDisputeV2() { + // start the guard + go func() { + _ = i.guard.Start(i.GetTestContext()) + }() + + // load token contracts + const startAmount = 1000 + const rfqAmount = 900 + opts := i.destBackend.GetTxContext(i.GetTestContext(), nil) + destUSDC, destUSDCHandle := i.cctpDeployManager.GetMockMintBurnTokenType(i.GetTestContext(), i.destBackend) + realStartAmount, err := testutil.AdjustAmount(i.GetTestContext(), big.NewInt(startAmount), destUSDC.ContractHandle()) + i.NoError(err) + realRFQAmount, err := testutil.AdjustAmount(i.GetTestContext(), big.NewInt(rfqAmount), destUSDC.ContractHandle()) + i.NoError(err) + + // add initial usdc to relayer on destination + tx, err := destUSDCHandle.MintPublic(opts.TransactOpts, i.relayerWallet.Address(), realStartAmount) + i.Nil(err) + i.destBackend.WaitForConfirmation(i.GetTestContext(), tx) + i.Approve(i.destBackend, destUSDC, i.relayerWallet) + + // add initial USDC to relayer on origin + optsOrigin := i.originBackend.GetTxContext(i.GetTestContext(), nil) + originUSDC, originUSDCHandle := i.cctpDeployManager.GetMockMintBurnTokenType(i.GetTestContext(), i.originBackend) + tx, err = originUSDCHandle.MintPublic(optsOrigin.TransactOpts, i.relayerWallet.Address(), realStartAmount) + i.Nil(err) + i.originBackend.WaitForConfirmation(i.GetTestContext(), tx) + i.Approve(i.originBackend, originUSDC, i.relayerWallet) + + // add initial USDC to user on origin + tx, err = originUSDCHandle.MintPublic(optsOrigin.TransactOpts, i.userWallet.Address(), realRFQAmount) + i.Nil(err) + i.originBackend.WaitForConfirmation(i.GetTestContext(), tx) + i.Approve(i.originBackend, originUSDC, i.userWallet) + + // now we can send the money + _, originFastBridge := i.manager.GetFastBridgeV2(i.GetTestContext(), i.originBackend) + auth := i.originBackend.GetTxContext(i.GetTestContext(), i.userWallet.AddressPtr()) + // we want 499 usdc for 500 requested within a day tx, err = originFastBridge.Bridge(auth.TransactOpts, fastbridgev2.IFastBridgeBridgeParams{ DstChainId: uint32(i.destBackend.GetChainID()), Sender: i.userWallet.Address(), @@ -670,7 +767,7 @@ func (i *IntegrationSuite) TestConcurrentBridges() { return false }) - _, originFastBridge := i.manager.GetFastBridge(i.GetTestContext(), i.originBackend) + _, originFastBridge := i.manager.GetFastBridgeV2(i.GetTestContext(), i.originBackend) auth := i.originBackend.GetTxContext(i.GetTestContext(), i.userWallet.AddressPtr()) parser, err := fastbridge.NewParser(originFastBridge.Address()) i.NoError(err) diff --git a/services/rfq/e2e/setup_test.go b/services/rfq/e2e/setup_test.go index fe18c9a543..892617465b 100644 --- a/services/rfq/e2e/setup_test.go +++ b/services/rfq/e2e/setup_test.go @@ -63,6 +63,10 @@ func (i *IntegrationSuite) setupQuoterAPI() { originBackendChainID: i.manager.Get(i.GetTestContext(), i.originBackend, testutil.FastBridgeType).Address().String(), destBackendChainID: i.manager.Get(i.GetTestContext(), i.destBackend, testutil.FastBridgeType).Address().String(), }, + FastBridgeContractsV2: map[uint32]string{ + originBackendChainID: i.manager.Get(i.GetTestContext(), i.originBackend, testutil.FastBridgeV2Type).Address().String(), + destBackendChainID: i.manager.Get(i.GetTestContext(), i.destBackend, testutil.FastBridgeV2Type).Address().String(), + }, Port: strconv.Itoa(apiPort), } api, err := rest.NewAPI(i.GetTestContext(), apiCfg, i.metrics, i.omniClient, apiStore) @@ -147,7 +151,7 @@ func (i *IntegrationSuite) setupBE(backend backends.SimulatedTestBackend) { // but this way we can do something while we're waiting for the other backend to startup. // no need to wait for these to deploy since they can happen in background as soon as the backend is up. predeployTokens := []contracts.ContractType{testutil.DAIType, testutil.USDTType, testutil.WETH9Type} - predeploys := append(predeployTokens, testutil.FastBridgeType) + predeploys := append(predeployTokens, testutil.FastBridgeV2Type) slices.Reverse(predeploys) // return fast bridge first ethAmount := *new(big.Int).Mul(big.NewInt(params.Ether), big.NewInt(10)) @@ -267,15 +271,41 @@ func (i *IntegrationSuite) Approve(backend backends.SimulatedTestBackend, token erc20, err := ierc20.NewIERC20(token.Address(), backend) i.Require().NoError(err, "Failed to get erc20") - _, fastBridge := i.manager.GetFastBridge(i.GetTestContext(), backend) - allowance, err := erc20.Allowance(&bind.CallOpts{Context: i.GetTestContext()}, user.Address(), fastBridge.Address()) + + // approve fastbridgev1 + _, fastBridgeV1 := i.manager.GetFastBridge(i.GetTestContext(), backend) + allowance, err := erc20.Allowance(&bind.CallOpts{Context: i.GetTestContext()}, user.Address(), fastBridgeV1.Address()) + i.Require().NoError(err, "Failed to get allowance") + + if allowance.Cmp(big.NewInt(0)) == 0 { + err = retry.WithBackoff(i.GetTestContext(), func(ctx context.Context) error { + txOpts := backend.GetTxContext(ctx, user.AddressPtr()) + tx, err := erc20.Approve(txOpts.TransactOpts, fastBridgeV1.Address(), core.CopyBigInt(abi.MaxUint256)) + if err != nil { + return fmt.Errorf("failed to approve: %w", err) + } + backend.WaitForConfirmation(ctx, tx) + return nil + }) + i.Require().NoError(err, "Failed to approve") + } + + // approve fastbridgev2 + _, fastBridgeV2 := i.manager.GetFastBridgeV2(i.GetTestContext(), backend) + allowance, err = erc20.Allowance(&bind.CallOpts{Context: i.GetTestContext()}, user.Address(), fastBridgeV2.Address()) i.Require().NoError(err, "Failed to get allowance") if allowance.Cmp(big.NewInt(0)) == 0 { - txOpts := backend.GetTxContext(i.GetTestContext(), user.AddressPtr()) - tx, err := erc20.Approve(txOpts.TransactOpts, fastBridge.Address(), core.CopyBigInt(abi.MaxUint256)) + err = retry.WithBackoff(i.GetTestContext(), func(ctx context.Context) error { + txOpts := backend.GetTxContext(ctx, user.AddressPtr()) + tx, err := erc20.Approve(txOpts.TransactOpts, fastBridgeV2.Address(), core.CopyBigInt(abi.MaxUint256)) + if err != nil { + return fmt.Errorf("failed to approve: %w", err) + } + backend.WaitForConfirmation(ctx, tx) + return nil + }) i.Require().NoError(err, "Failed to approve") - backend.WaitForConfirmation(i.GetTestContext(), tx) } } @@ -286,11 +316,14 @@ func (i *IntegrationSuite) getRelayerConfig() relconfig.Config { dsn := filet.TmpDir(i.T(), "") cctpContractOrigin, _ := i.cctpDeployManager.GetSynapseCCTP(i.GetTestContext(), i.originBackend) cctpContractDest, _ := i.cctpDeployManager.GetSynapseCCTP(i.GetTestContext(), i.destBackend) + rfqAddressV1Origin := i.manager.Get(i.GetTestContext(), i.originBackend, testutil.FastBridgeType).Address().String() + rfqAddressV1Dest := i.manager.Get(i.GetTestContext(), i.destBackend, testutil.FastBridgeType).Address().String() return relconfig.Config{ // generated ex-post facto Chains: map[int]relconfig.ChainConfig{ originBackendChainID: { - RFQAddress: i.manager.Get(i.GetTestContext(), i.originBackend, testutil.FastBridgeType).Address().String(), + RFQAddress: i.manager.Get(i.GetTestContext(), i.originBackend, testutil.FastBridgeV2Type).Address().String(), + RFQAddressV1: &rfqAddressV1Origin, RebalanceConfigs: relconfig.RebalanceConfigs{ Synapse: &relconfig.SynapseCCTPRebalanceConfig{ SynapseCCTPAddress: cctpContractOrigin.Address().Hex(), @@ -307,7 +340,8 @@ func (i *IntegrationSuite) getRelayerConfig() relconfig.Config { NativeToken: "ETH", }, destBackendChainID: { - RFQAddress: i.manager.Get(i.GetTestContext(), i.destBackend, testutil.FastBridgeType).Address().String(), + RFQAddress: i.manager.Get(i.GetTestContext(), i.destBackend, testutil.FastBridgeV2Type).Address().String(), + RFQAddressV1: &rfqAddressV1Dest, RebalanceConfigs: relconfig.RebalanceConfigs{ Synapse: &relconfig.SynapseCCTPRebalanceConfig{ SynapseCCTPAddress: cctpContractDest.Address().Hex(), @@ -362,26 +396,38 @@ func (i *IntegrationSuite) setupRelayer() { defer wg.Done() err := retry.WithBackoff(i.GetTestContext(), func(ctx context.Context) error { - metadata, rfqContract := i.manager.GetFastBridge(i.GetTestContext(), backend) + metadataV1, rfqContractV1 := i.manager.GetFastBridge(i.GetTestContext(), backend) + txContextV1 := backend.GetTxContext(i.GetTestContext(), metadataV1.OwnerPtr()) - txContext := backend.GetTxContext(i.GetTestContext(), metadata.OwnerPtr()) - proverRole, err := rfqContract.PROVERROLE(&bind.CallOpts{Context: i.GetTestContext()}) + relayerRole, err := rfqContractV1.RELAYERROLE(&bind.CallOpts{Context: i.GetTestContext()}) + proverRole, err := rfqContractV1.RELAYERROLE(&bind.CallOpts{Context: i.GetTestContext()}) if err != nil { return fmt.Errorf("could not get prover role: %w", err) } + tx, err := rfqContractV1.GrantRole(txContextV1.TransactOpts, relayerRole, i.relayerWallet.Address()) + if err != nil { + return fmt.Errorf("could not grant relayer role: %w", err) + } + backend.WaitForConfirmation(i.GetTestContext(), tx) + + metadataV2, rfqContractV2 := i.manager.GetFastBridgeV2(i.GetTestContext(), backend) + txContextV2 := backend.GetTxContext(i.GetTestContext(), metadataV2.OwnerPtr()) - tx, err := rfqContract.GrantRole(txContext.TransactOpts, proverRole, i.relayerWallet.Address()) + proverRole, err = rfqContractV2.PROVERROLE(&bind.CallOpts{Context: i.GetTestContext()}) + if err != nil { + return fmt.Errorf("could not get prover role: %w", err) + } + tx, err = rfqContractV2.GrantRole(txContextV2.TransactOpts, proverRole, i.relayerWallet.Address()) if err != nil { return fmt.Errorf("could not grant prover role: %w", err) } backend.WaitForConfirmation(i.GetTestContext(), tx) - quoterRole, err := rfqContract.QUOTERROLE(&bind.CallOpts{Context: i.GetTestContext()}) + quoterRole, err := rfqContractV2.QUOTERROLE(&bind.CallOpts{Context: i.GetTestContext()}) if err != nil { return fmt.Errorf("could not get quoter role: %w", err) } - - tx, err = rfqContract.GrantRole(txContext.TransactOpts, quoterRole, i.relayerWallet.Address()) + tx, err = rfqContractV2.GrantRole(txContextV2.TransactOpts, quoterRole, i.relayerWallet.Address()) if err != nil { return fmt.Errorf("could not grant quoter role: %w", err) } @@ -488,13 +534,24 @@ func (i *IntegrationSuite) setupGuard() { go func(backend backends.SimulatedTestBackend) { defer wg.Done() - metadata, rfqContract := i.manager.GetFastBridge(i.GetTestContext(), backend) + metadataV1, rfqContractV1 := i.manager.GetFastBridge(i.GetTestContext(), backend) + + txContext := backend.GetTxContext(i.GetTestContext(), metadataV1.OwnerPtr()) + guardRole, err := rfqContractV1.GUARDROLE(&bind.CallOpts{Context: i.GetTestContext()}) + i.NoError(err) + + tx, err := rfqContractV1.GrantRole(txContext.TransactOpts, guardRole, i.guardWallet.Address()) + i.NoError(err) + + backend.WaitForConfirmation(i.GetTestContext(), tx) + + metadataV2, rfqContractV2 := i.manager.GetFastBridgeV2(i.GetTestContext(), backend) - txContext := backend.GetTxContext(i.GetTestContext(), metadata.OwnerPtr()) - guardRole, err := rfqContract.GUARDROLE(&bind.CallOpts{Context: i.GetTestContext()}) + txContext = backend.GetTxContext(i.GetTestContext(), metadataV2.OwnerPtr()) + guardRole, err = rfqContractV2.GUARDROLE(&bind.CallOpts{Context: i.GetTestContext()}) i.NoError(err) - tx, err := rfqContract.GrantRole(txContext.TransactOpts, guardRole, i.guardWallet.Address()) + tx, err = rfqContractV2.GrantRole(txContext.TransactOpts, guardRole, i.guardWallet.Address()) i.NoError(err) backend.WaitForConfirmation(i.GetTestContext(), tx) diff --git a/services/rfq/guard/guardconfig/config.go b/services/rfq/guard/guardconfig/config.go index f43557d35a..0e49c47d06 100644 --- a/services/rfq/guard/guardconfig/config.go +++ b/services/rfq/guard/guardconfig/config.go @@ -34,7 +34,9 @@ type Config struct { // ChainConfig represents the configuration for a chain. type ChainConfig struct { - // Bridge is the rfq bridge contract address. + // RFQAddressV1 is the legacy V1 rfq bridge contract address. OPTIONAL. Only populate if also guarding a deprecated V1 contract. + RFQAddressV1 *string `yaml:"rfq_address_v1"` + // RFQAddress is the current/latest rfq bridge contract address. REQUIRED. RFQAddress string `yaml:"rfq_address"` // Confirmations is the number of required confirmations. Confirmations uint64 `yaml:"confirmations"` @@ -66,12 +68,19 @@ func LoadConfig(path string) (config Config, err error) { // Validate validates the config. func (c Config) Validate() (err error) { for chainID := range c.Chains { - addr, err := c.GetRFQAddress(chainID) + addrV1, err := c.GetRFQAddressV1(chainID) if err != nil { - return fmt.Errorf("could not get rfq address: %w", err) + return fmt.Errorf("could not get v1 rfq address: %w", err) } - if !common.IsHexAddress(addr) { - return fmt.Errorf("invalid rfq address: %s", addr) + if addrV1 != nil && !common.IsHexAddress(*addrV1) { + return fmt.Errorf("invalid rfq v1 address: %s", *addrV1) + } + addrV2, err := c.GetRFQAddressV2(chainID) + if err != nil { + return fmt.Errorf("could not get v2 rfq address: %w", err) + } + if !common.IsHexAddress(addrV2) { + return fmt.Errorf("invalid rfq v2 address: %s", addrV2) } } @@ -83,11 +92,20 @@ func (c Config) GetChains() map[int]ChainConfig { return c.Chains } -// GetRFQAddress returns the RFQ address for the given chain. -func (c Config) GetRFQAddress(chainID int) (string, error) { +// GetRFQAddressV1 returns the RFQ address for the given chain. +func (c Config) GetRFQAddressV1(chainID int) (*string, error) { + chainCfg, ok := c.Chains[chainID] + if !ok { + return nil, fmt.Errorf("v1 chain config not found for chain %d", chainID) + } + return chainCfg.RFQAddressV1, nil +} + +// GetRFQAddressV2 returns the RFQ address for the given chain. +func (c Config) GetRFQAddressV2(chainID int) (string, error) { chainCfg, ok := c.Chains[chainID] if !ok { - return "", fmt.Errorf("chain config not found for chain %d", chainID) + return "", fmt.Errorf("v2 chain config not found for chain %d", chainID) } return chainCfg.RFQAddress, nil } @@ -115,6 +133,7 @@ func NewGuardConfigFromRelayer(relayerCfg relconfig.Config) Config { } for chainID, chainCfg := range relayerCfg.GetChains() { cfg.Chains[chainID] = ChainConfig{ + RFQAddressV1: chainCfg.RFQAddressV1, RFQAddress: chainCfg.RFQAddress, Confirmations: chainCfg.FinalityConfirmations, } diff --git a/services/rfq/guard/guarddb/base/model.go b/services/rfq/guard/guarddb/base/model.go index bf2e08d42b..30999462a3 100644 --- a/services/rfq/guard/guarddb/base/model.go +++ b/services/rfq/guard/guarddb/base/model.go @@ -9,7 +9,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" "github.com/synapsecns/sanguine/core/dbcommon" - "github.com/synapsecns/sanguine/services/rfq/contracts/fastbridge" + "github.com/synapsecns/sanguine/services/rfq/contracts/fastbridgev2" "github.com/synapsecns/sanguine/services/rfq/guard/guarddb" ) @@ -36,6 +36,8 @@ type PendingProvenModel struct { Origin uint32 // RelayerAddress is the address of the relayer that called prove() RelayerAddress string + // FastBridgeAddress is the address of the fast bridge contract + FastBridgeAddress string // TransactionID is the transaction id of the event TransactionID string `gorm:"column:transaction_id;primaryKey"` // TxHash is the hash of the relay transaction on destination @@ -49,12 +51,13 @@ type PendingProvenModel struct { // FromPendingProven converts a quote request to an object that can be stored in the db. func FromPendingProven(proven guarddb.PendingProven) PendingProvenModel { return PendingProvenModel{ - Origin: proven.Origin, - RelayerAddress: proven.RelayerAddress.Hex(), - TransactionID: hexutil.Encode(proven.TransactionID[:]), - TxHash: proven.TxHash.Hex(), - Status: proven.Status, - BlockNumber: proven.BlockNumber, + Origin: proven.Origin, + RelayerAddress: proven.RelayerAddress.Hex(), + FastBridgeAddress: proven.FastBridgeAddress.Hex(), + TransactionID: hexutil.Encode(proven.TransactionID[:]), + TxHash: proven.TxHash.Hex(), + Status: proven.Status, + BlockNumber: proven.BlockNumber, } } @@ -71,12 +74,13 @@ func (p PendingProvenModel) ToPendingProven() (*guarddb.PendingProven, error) { } return &guarddb.PendingProven{ - Origin: p.Origin, - RelayerAddress: common.HexToAddress(p.RelayerAddress), - TransactionID: transactionID, - TxHash: common.HexToHash(p.TxHash), - Status: p.Status, - BlockNumber: p.BlockNumber, + Origin: p.Origin, + RelayerAddress: common.HexToAddress(p.RelayerAddress), + FastBridgeAddress: common.HexToAddress(p.FastBridgeAddress), + TransactionID: transactionID, + TxHash: common.HexToHash(p.TxHash), + Status: p.Status, + BlockNumber: p.BlockNumber, }, nil } @@ -164,7 +168,7 @@ func (b BridgeRequestModel) ToBridgeRequest() (*guarddb.BridgeRequest, error) { return &guarddb.BridgeRequest{ TransactionID: transactionID, RawRequest: req, - Transaction: fastbridge.IFastBridgeBridgeTransaction{ + Transaction: fastbridgev2.IFastBridgeBridgeTransaction{ OriginChainId: b.OriginChainID, DestChainId: b.DestChainID, OriginSender: common.HexToAddress(b.OriginSender), diff --git a/services/rfq/guard/guarddb/db.go b/services/rfq/guard/guarddb/db.go index d177cc7e7a..9e62fbf380 100644 --- a/services/rfq/guard/guarddb/db.go +++ b/services/rfq/guard/guarddb/db.go @@ -7,7 +7,7 @@ import ( "fmt" "github.com/synapsecns/sanguine/ethergo/listener/db" - "github.com/synapsecns/sanguine/services/rfq/contracts/fastbridge" + "github.com/synapsecns/sanguine/services/rfq/contracts/fastbridgev2" "github.com/ethereum/go-ethereum/common" "github.com/synapsecns/sanguine/core/dbcommon" @@ -53,18 +53,19 @@ type Service interface { // BridgeRequest is the bridge request object. type BridgeRequest struct { TransactionID [32]byte - Transaction fastbridge.IFastBridgeBridgeTransaction + Transaction fastbridgev2.IFastBridgeBridgeTransaction RawRequest []byte } // PendingProven is the pending proven object. type PendingProven struct { - Origin uint32 - RelayerAddress common.Address - TransactionID [32]byte - TxHash common.Hash - Status PendingProvenStatus - BlockNumber uint64 + Origin uint32 + RelayerAddress common.Address + FastBridgeAddress common.Address + TransactionID [32]byte + TxHash common.Hash + Status PendingProvenStatus + BlockNumber uint64 } // PendingProvenStatus is the status of a quote request in the db. diff --git a/services/rfq/guard/service/guard.go b/services/rfq/guard/service/guard.go index e341abd3dc..4fd56c311b 100644 --- a/services/rfq/guard/service/guard.go +++ b/services/rfq/guard/service/guard.go @@ -17,6 +17,7 @@ import ( "github.com/synapsecns/sanguine/ethergo/submitter" omniClient "github.com/synapsecns/sanguine/services/omnirpc/client" "github.com/synapsecns/sanguine/services/rfq/contracts/fastbridge" + "github.com/synapsecns/sanguine/services/rfq/contracts/fastbridgev2" "github.com/synapsecns/sanguine/services/rfq/guard/guardconfig" "github.com/synapsecns/sanguine/services/rfq/guard/guarddb" "github.com/synapsecns/sanguine/services/rfq/guard/guarddb/connect" @@ -29,14 +30,16 @@ var logger = log.Logger("guard") // Guard monitors calls to prove() and verifies them. type Guard struct { - cfg guardconfig.Config - metrics metrics.Handler - db guarddb.Service - client omniClient.RPCClient - chainListeners map[int]listener.ContractListener - contracts map[int]*fastbridge.FastBridgeRef - txSubmitter submitter.TransactionSubmitter - otelRecorder iOtelRecorder + cfg guardconfig.Config + metrics metrics.Handler + db guarddb.Service + client omniClient.RPCClient + contractsV1 map[int]*fastbridge.FastBridgeRef + contractsV2 map[int]*fastbridgev2.FastBridgeV2Ref + listenersV1 map[int]listener.ContractListener + listenersV2 map[int]listener.ContractListener + txSubmitter submitter.TransactionSubmitter + otelRecorder iOtelRecorder } // NewGuard creates a new Guard. @@ -44,7 +47,6 @@ type Guard struct { //nolint:cyclop func NewGuard(ctx context.Context, metricHandler metrics.Handler, cfg guardconfig.Config, txSubmitter submitter.TransactionSubmitter) (*Guard, error) { omniClient := omniClient.NewOmnirpcClient(cfg.OmniRPCURL, metricHandler, omniClient.WithCaptureReqRes()) - chainListeners := make(map[int]listener.ContractListener) dbType, err := dbcommon.DBTypeFromString(cfg.Database.Type) if err != nil { @@ -55,10 +57,41 @@ func NewGuard(ctx context.Context, metricHandler metrics.Handler, cfg guardconfi return nil, fmt.Errorf("could not make db: %w", err) } + contractsV1 := make(map[int]*fastbridge.FastBridgeRef) + contractsV2 := make(map[int]*fastbridgev2.FastBridgeV2Ref) + listenersV1 := make(map[int]listener.ContractListener) + listenersV2 := make(map[int]listener.ContractListener) + // setup chain listeners - contracts := make(map[int]*fastbridge.FastBridgeRef) for chainID := range cfg.GetChains() { - rfqAddr, err := cfg.GetRFQAddress(chainID) + // setup v1 + rfqAddrV1, err := cfg.GetRFQAddressV1(chainID) + if err != nil { + return nil, fmt.Errorf("could not get rfq address: %w", err) + } + if rfqAddrV1 != nil { + chainClient, err := omniClient.GetChainClient(ctx, chainID) + if err != nil { + return nil, fmt.Errorf("could not get chain client: %w", err) + } + contract, err := fastbridge.NewFastBridgeRef(common.HexToAddress(*rfqAddrV1), chainClient) + if err != nil { + return nil, fmt.Errorf("could not create fast bridge contract: %w", err) + } + startBlock, err := contract.DeployBlock(&bind.CallOpts{Context: ctx}) + if err != nil { + return nil, fmt.Errorf("could not get deploy block: %w", err) + } + chainListener, err := listener.NewChainListener(chainClient, store, common.HexToAddress(*rfqAddrV1), uint64(startBlock.Int64()), metricHandler, listener.WithName("guard")) + if err != nil { + return nil, fmt.Errorf("could not get chain listener: %w", err) + } + listenersV1[chainID] = chainListener + contractsV1[chainID] = contract + } + + // setup v2 + rfqAddrV2, err := cfg.GetRFQAddressV2(chainID) if err != nil { return nil, fmt.Errorf("could not get rfq address: %w", err) } @@ -66,8 +99,7 @@ func NewGuard(ctx context.Context, metricHandler metrics.Handler, cfg guardconfi if err != nil { return nil, fmt.Errorf("could not get chain client: %w", err) } - - contract, err := fastbridge.NewFastBridgeRef(common.HexToAddress(rfqAddr), chainClient) + contract, err := fastbridgev2.NewFastBridgeV2Ref(common.HexToAddress(rfqAddrV2), chainClient) if err != nil { return nil, fmt.Errorf("could not create fast bridge contract: %w", err) } @@ -75,17 +107,12 @@ func NewGuard(ctx context.Context, metricHandler metrics.Handler, cfg guardconfi if err != nil { return nil, fmt.Errorf("could not get deploy block: %w", err) } - chainListener, err := listener.NewChainListener(chainClient, store, common.HexToAddress(rfqAddr), uint64(startBlock.Int64()), metricHandler, listener.WithName("guard")) + chainListener, err := listener.NewChainListener(chainClient, store, common.HexToAddress(rfqAddrV2), uint64(startBlock.Int64()), metricHandler, listener.WithName("guardV2")) if err != nil { return nil, fmt.Errorf("could not get chain listener: %w", err) } - chainListeners[chainID] = chainListener - - // setup FastBridge contract on this chain - contracts[chainID], err = fastbridge.NewFastBridgeRef(common.HexToAddress(rfqAddr), chainClient) - if err != nil { - return nil, fmt.Errorf("could not create bridge contract: %w", err) - } + listenersV2[chainID] = chainListener + contractsV2[chainID] = contract } // build submitter from config if one is not supplied @@ -103,14 +130,16 @@ func NewGuard(ctx context.Context, metricHandler metrics.Handler, cfg guardconfi } return &Guard{ - cfg: cfg, - metrics: metricHandler, - db: store, - client: omniClient, - chainListeners: chainListeners, - contracts: contracts, - txSubmitter: txSubmitter, - otelRecorder: otelRecorder, + cfg: cfg, + metrics: metricHandler, + db: store, + client: omniClient, + contractsV1: contractsV1, + contractsV2: contractsV2, + listenersV1: listenersV1, + listenersV2: listenersV2, + txSubmitter: txSubmitter, + otelRecorder: otelRecorder, }, nil } @@ -173,10 +202,26 @@ func (g *Guard) startChainIndexers(ctx context.Context) (err error) { for chainID := range g.cfg.GetChains() { //nolint: copyloopvar chainID := chainID // capture loop variable + + // only run v1 if it is set + v1Addr, err := g.cfg.GetRFQAddressV1(chainID) + if err != nil { + return fmt.Errorf("could not get rfq address v1: %w", err) + } + if v1Addr != nil { + group.Go(func() error { + err := g.runChainIndexerV1(ctx, chainID, g.listenersV1[chainID]) + if err != nil { + return fmt.Errorf("could not runChainIndexer chain indexer for chain %d [v1]: %w", chainID, err) + } + return nil + }) + } + group.Go(func() error { - err := g.runChainIndexer(ctx, chainID) + err := g.runChainIndexerV2(ctx, chainID, g.listenersV2[chainID]) if err != nil { - return fmt.Errorf("could not runChainIndexer chain indexer for chain %d: %w", chainID, err) + return fmt.Errorf("could not runChainIndexer chain indexer for chain %d [v2]: %w", chainID, err) } return nil }) @@ -191,9 +236,7 @@ func (g *Guard) startChainIndexers(ctx context.Context) (err error) { } //nolint:cyclop -func (g Guard) runChainIndexer(ctx context.Context, chainID int) (err error) { - chainListener := g.chainListeners[chainID] - +func (g Guard) runChainIndexerV1(ctx context.Context, chainID int, chainListener listener.ContractListener) (err error) { parser, err := fastbridge.NewParser(chainListener.Address()) if err != nil { return fmt.Errorf("could not parse: %w", err) @@ -223,16 +266,94 @@ func (g Guard) runChainIndexer(ctx context.Context, chainID int) (err error) { switch event := parsedEvent.(type) { case *fastbridge.FastBridgeBridgeRequested: - err = g.handleBridgeRequestedLog(ctx, event, chainID) + v2Event := &fastbridgev2.FastBridgeV2BridgeRequested{ + TransactionId: event.TransactionId, + Sender: event.Sender, + Request: event.Request, + DestChainId: event.DestChainId, + OriginToken: event.OriginToken, + DestToken: event.DestToken, + OriginAmount: event.OriginAmount, + DestAmount: event.DestAmount, + SendChainGas: event.SendChainGas, + Raw: event.Raw, + } + err = g.handleBridgeRequestedLog(ctx, v2Event, chainID) if err != nil { return fmt.Errorf("could not handle request: %w", err) } case *fastbridge.FastBridgeBridgeProofProvided: - err = g.handleProofProvidedLog(ctx, event, chainID) + v2Event := &fastbridgev2.FastBridgeV2BridgeProofProvided{ + TransactionId: event.TransactionId, + Relayer: event.Relayer, + TransactionHash: event.TransactionHash, + Raw: event.Raw, + } + err = g.handleProofProvidedLog(ctx, v2Event, chainID) if err != nil { return fmt.Errorf("could not handle request: %w", err) } case *fastbridge.FastBridgeBridgeProofDisputed: + eventV2 := &fastbridgev2.FastBridgeV2BridgeProofDisputed{ + TransactionId: event.TransactionId, + Relayer: event.Relayer, + Raw: event.Raw, + } + err = g.handleProofDisputedLog(ctx, eventV2) + if err != nil { + return fmt.Errorf("could not handle request: %w", err) + } + } + + return nil + }) + if err != nil { + return fmt.Errorf("listener failed: %w", err) + } + return nil +} + +//nolint:cyclop +func (g Guard) runChainIndexerV2(ctx context.Context, chainID int, chainListener listener.ContractListener) (err error) { + parser, err := fastbridgev2.NewParser(chainListener.Address()) + if err != nil { + return fmt.Errorf("could not parse: %w", err) + } + + err = chainListener.Listen(ctx, func(parentCtx context.Context, log types.Log) (err error) { + et, parsedEvent, ok := parser.ParseEvent(log) + // handle unknown event + if !ok { + if len(log.Topics) != 0 { + logger.Warnf("unknown event %s", log.Topics[0]) + } + return nil + } + + ctx, span := g.metrics.Tracer().Start(parentCtx, fmt.Sprintf("handleLog-%s", et), trace.WithAttributes( + attribute.String(metrics.TxHash, log.TxHash.String()), + attribute.Int(metrics.Origin, chainID), + attribute.String(metrics.Contract, log.Address.String()), + attribute.String("block_hash", log.BlockHash.String()), + attribute.Int64("block_number", int64(log.BlockNumber)), + )) + + defer func() { + metrics.EndSpanWithErr(span, err) + }() + + switch event := parsedEvent.(type) { + case *fastbridgev2.FastBridgeV2BridgeRequested: + err = g.handleBridgeRequestedLog(ctx, event, chainID) + if err != nil { + return fmt.Errorf("could not handle request: %w", err) + } + case *fastbridgev2.FastBridgeV2BridgeProofProvided: + err = g.handleProofProvidedLog(ctx, event, chainID) + if err != nil { + return fmt.Errorf("could not handle request: %w", err) + } + case *fastbridgev2.FastBridgeV2BridgeProofDisputed: err = g.handleProofDisputedLog(ctx, event) if err != nil { return fmt.Errorf("could not handle request: %w", err) @@ -262,3 +383,11 @@ func (g *Guard) processDB(ctx context.Context) (err error) { return nil } + +func (g *Guard) isV2Address(chainID int, addr common.Address) bool { + rfqAddr, err := g.cfg.GetRFQAddressV2(chainID) + if err != nil { + return false + } + return addr == common.HexToAddress(rfqAddr) +} diff --git a/services/rfq/guard/service/handlers.go b/services/rfq/guard/service/handlers.go index c8fdb627c3..35102cad9c 100644 --- a/services/rfq/guard/service/handlers.go +++ b/services/rfq/guard/service/handlers.go @@ -14,7 +14,7 @@ import ( "github.com/ethereum/go-ethereum/core/types" "github.com/synapsecns/sanguine/core/metrics" "github.com/synapsecns/sanguine/core/retry" - "github.com/synapsecns/sanguine/services/rfq/contracts/fastbridge" + "github.com/synapsecns/sanguine/services/rfq/contracts/fastbridgev2" "github.com/synapsecns/sanguine/services/rfq/guard/guarddb" "go.opentelemetry.io/otel/attribute" "go.opentelemetry.io/otel/trace" @@ -22,7 +22,7 @@ import ( var maxRPCRetryTime = 15 * time.Second -func (g *Guard) handleBridgeRequestedLog(parentCtx context.Context, req *fastbridge.FastBridgeBridgeRequested, chainID int) (err error) { +func (g *Guard) handleBridgeRequestedLog(parentCtx context.Context, req *fastbridgev2.FastBridgeV2BridgeRequested, chainID int) (err error) { ctx, span := g.metrics.Tracer().Start(parentCtx, "handleBridgeRequestedLog-guard", trace.WithAttributes( attribute.Int(metrics.Origin, chainID), attribute.String("transaction_id", hexutil.Encode(req.TransactionId[:])), @@ -36,14 +36,14 @@ func (g *Guard) handleBridgeRequestedLog(parentCtx context.Context, req *fastbri return fmt.Errorf("could not get correct omnirpc client: %w", err) } - fastBridge, err := fastbridge.NewFastBridgeRef(req.Raw.Address, originClient) + fastBridgev2, err := fastbridgev2.NewFastBridgeV2Ref(req.Raw.Address, originClient) if err != nil { return fmt.Errorf("could not get correct fast bridge: %w", err) } - var bridgeTx fastbridge.IFastBridgeBridgeTransaction + var bridgeTx fastbridgev2.IFastBridgeBridgeTransaction call := func(ctx context.Context) error { - bridgeTx, err = fastBridge.GetBridgeTransaction(&bind.CallOpts{Context: ctx}, req.Request) + bridgeTx, err = fastBridgev2.GetBridgeTransaction(&bind.CallOpts{Context: ctx}, req.Request) if err != nil { return fmt.Errorf("could not get bridge transaction: %w", err) } @@ -66,7 +66,8 @@ func (g *Guard) handleBridgeRequestedLog(parentCtx context.Context, req *fastbri return nil } -func (g *Guard) handleProofProvidedLog(parentCtx context.Context, event *fastbridge.FastBridgeBridgeProofProvided, chainID int) (err error) { +//nolint:gosec +func (g *Guard) handleProofProvidedLog(parentCtx context.Context, event *fastbridgev2.FastBridgeV2BridgeProofProvided, chainID int) (err error) { ctx, span := g.metrics.Tracer().Start(parentCtx, "handleProofProvidedLog-guard", trace.WithAttributes( attribute.Int(metrics.Origin, chainID), attribute.String("transaction_id", hexutil.Encode(event.TransactionId[:])), @@ -77,12 +78,13 @@ func (g *Guard) handleProofProvidedLog(parentCtx context.Context, event *fastbri }() proven := guarddb.PendingProven{ - Origin: uint32(chainID), - RelayerAddress: event.Relayer, - TransactionID: event.TransactionId, - TxHash: event.TransactionHash, - Status: guarddb.ProveCalled, - BlockNumber: event.Raw.BlockNumber, + Origin: uint32(chainID), + RelayerAddress: event.Relayer, + FastBridgeAddress: event.Raw.Address, + TransactionID: event.TransactionId, + TxHash: event.TransactionHash, + Status: guarddb.ProveCalled, + BlockNumber: event.Raw.BlockNumber, } err = g.db.StorePendingProven(ctx, proven) if err != nil { @@ -92,7 +94,7 @@ func (g *Guard) handleProofProvidedLog(parentCtx context.Context, event *fastbri return nil } -func (g *Guard) handleProofDisputedLog(parentCtx context.Context, event *fastbridge.FastBridgeBridgeProofDisputed) (err error) { +func (g *Guard) handleProofDisputedLog(parentCtx context.Context, event *fastbridgev2.FastBridgeV2BridgeProofDisputed) (err error) { ctx, span := g.metrics.Tracer().Start(parentCtx, "handleProofDisputedLog-guard", trace.WithAttributes( attribute.String("transaction_id", hexutil.Encode(event.TransactionId[:])), )) @@ -147,18 +149,11 @@ func (g *Guard) handleProveCalled(parentCtx context.Context, proven *guarddb.Pen } } else { // trigger dispute - contract, ok := g.contracts[int(bridgeRequest.Transaction.OriginChainId)] - if !ok { - return fmt.Errorf("could not get contract for chain: %d", bridgeRequest.Transaction.OriginChainId) + if g.isV2Address(int(bridgeRequest.Transaction.OriginChainId), proven.FastBridgeAddress) { + err = g.disputeV2(ctx, proven, bridgeRequest) + } else { + err = g.disputeV1(ctx, proven, bridgeRequest) } - _, err = g.txSubmitter.SubmitTransaction(ctx, big.NewInt(int64(bridgeRequest.Transaction.OriginChainId)), func(transactor *bind.TransactOpts) (tx *types.Transaction, err error) { - tx, err = contract.Dispute(transactor, proven.TransactionID) - if err != nil { - return nil, fmt.Errorf("could not dispute: %w", err) - } - - return tx, nil - }) if err != nil { return fmt.Errorf("could not dispute: %w", err) } @@ -173,9 +168,48 @@ func (g *Guard) handleProveCalled(parentCtx context.Context, proven *guarddb.Pen return nil } +func (g *Guard) disputeV1(ctx context.Context, proven *guarddb.PendingProven, bridgeRequest *guarddb.BridgeRequest) error { + contract, ok := g.contractsV1[int(bridgeRequest.Transaction.OriginChainId)] + if !ok { + return errors.New("could not get contract") + } + _, err := g.txSubmitter.SubmitTransaction(ctx, big.NewInt(int64(bridgeRequest.Transaction.OriginChainId)), func(transactor *bind.TransactOpts) (tx *types.Transaction, err error) { + tx, err = contract.Dispute(transactor, proven.TransactionID) + if err != nil { + return nil, fmt.Errorf("could not dispute: %w", err) + } + + return tx, nil + }) + if err != nil { + return fmt.Errorf("could not dispute: %w", err) + } + + return nil +} + +func (g *Guard) disputeV2(ctx context.Context, proven *guarddb.PendingProven, bridgeRequest *guarddb.BridgeRequest) error { + contract, ok := g.contractsV2[int(bridgeRequest.Transaction.OriginChainId)] + if !ok { + return errors.New("could not get contract") + } + _, err := g.txSubmitter.SubmitTransaction(ctx, big.NewInt(int64(bridgeRequest.Transaction.OriginChainId)), func(transactor *bind.TransactOpts) (tx *types.Transaction, err error) { + tx, err = contract.Dispute(transactor, proven.TransactionID) + if err != nil { + return nil, fmt.Errorf("could not dispute: %w", err) + } + + return tx, nil + }) + if err != nil { + return fmt.Errorf("could not dispute: %w", err) + } + + return nil +} + //nolint:cyclop func (g *Guard) isProveValid(ctx context.Context, proven *guarddb.PendingProven, bridgeRequest *guarddb.BridgeRequest) (bool, error) { - span := trace.SpanFromContext(ctx) // get the receipt for this tx on dest chain chainClient, err := g.client.GetChainClient(ctx, int(bridgeRequest.Transaction.DestChainId)) @@ -190,11 +224,39 @@ func (g *Guard) isProveValid(ctx context.Context, proven *guarddb.PendingProven, if err != nil { return false, fmt.Errorf("could not get receipt: %w", err) } - rfqAddr, err := g.cfg.GetRFQAddress(int(bridgeRequest.Transaction.DestChainId)) + + var rfqContractAddr string + + if g.isV2Address(int(bridgeRequest.Transaction.OriginChainId), proven.FastBridgeAddress) { + rfqContractAddr, err = g.cfg.GetRFQAddressV2(int(bridgeRequest.Transaction.DestChainId)) + if err != nil { + return false, fmt.Errorf("could not get rfq address v2: %w", err) + } + } else { + v1addr, err := g.cfg.GetRFQAddressV1(int(bridgeRequest.Transaction.DestChainId)) + if err != nil { + return false, fmt.Errorf("could not get rfq address v1: %w", err) + } + if v1addr == nil { + return false, fmt.Errorf("rfq address v1 is nil") + } + rfqContractAddr = *v1addr + } + + var valid bool + valid, err = g.parseProvenTransaction(ctx, proven, bridgeRequest, receipt, rfqContractAddr) + if err != nil { - return false, fmt.Errorf("could not get rfq address: %w", err) + return false, fmt.Errorf("could not parse proven transaction for validity: %w", err) } - parser, err := fastbridge.NewParser(common.HexToAddress(rfqAddr)) + + return valid, nil +} + +func (g *Guard) parseProvenTransaction(ctx context.Context, proven *guarddb.PendingProven, bridgeRequest *guarddb.BridgeRequest, receipt *types.Receipt, rfqContractAddr string) (bool, error) { + span := trace.SpanFromContext(ctx) + + parser, err := fastbridgev2.NewParser(common.HexToAddress(rfqContractAddr)) if err != nil { return false, fmt.Errorf("could not get parser: %w", err) } @@ -205,12 +267,12 @@ func (g *Guard) isProveValid(ctx context.Context, proven *guarddb.PendingProven, continue } - if log.Address != common.HexToAddress(rfqAddr) { - span.AddEvent(fmt.Sprintf("log address %s does not match rfq address %s", log.Address.Hex(), rfqAddr)) + if log.Address != common.HexToAddress(rfqContractAddr) { + span.AddEvent(fmt.Sprintf("log address %s does not match rfq address %s", log.Address.Hex(), rfqContractAddr)) continue } - event, ok := parsedEvent.(*fastbridge.FastBridgeBridgeRelayed) + event, ok := parsedEvent.(*fastbridgev2.FastBridgeV2BridgeRelayed) if !ok { span.AddEvent("event is not a BridgeRelayed event") continue @@ -221,33 +283,57 @@ func (g *Guard) isProveValid(ctx context.Context, proven *guarddb.PendingProven, continue } - return relayMatchesBridgeRequest(event, bridgeRequest), nil + details := relayDetails{ + TransactionID: event.TransactionId, + OriginAmount: event.OriginAmount, + DestAmount: event.DestAmount, + OriginChainID: event.OriginChainId, + To: event.To, + OriginToken: event.OriginToken, + DestToken: event.DestToken, + } + + // if we find a relay that matches the bridge, then we can return true. otherwise continue looking through any remaining logs. + if relayMatchesBridgeRequest(details, bridgeRequest) { + return true, nil + } } + // if we have reached this point, then every log has been examined & none found suitable to validate the proof return false, nil } -func relayMatchesBridgeRequest(event *fastbridge.FastBridgeBridgeRelayed, bridgeRequest *guarddb.BridgeRequest) bool { +type relayDetails struct { + TransactionID [32]byte + OriginAmount *big.Int + DestAmount *big.Int + OriginChainID uint32 + To common.Address + OriginToken common.Address + DestToken common.Address +} + +func relayMatchesBridgeRequest(details relayDetails, bridgeRequest *guarddb.BridgeRequest) bool { // TODO: is this exhaustive? - if event.TransactionId != bridgeRequest.TransactionID { + if details.TransactionID != bridgeRequest.TransactionID { return false } - if event.OriginAmount.Cmp(bridgeRequest.Transaction.OriginAmount) != 0 { + if details.OriginAmount.Cmp(bridgeRequest.Transaction.OriginAmount) != 0 { return false } - if event.DestAmount.Cmp(bridgeRequest.Transaction.DestAmount) != 0 { + if details.DestAmount.Cmp(bridgeRequest.Transaction.DestAmount) != 0 { return false } - if event.OriginChainId != bridgeRequest.Transaction.OriginChainId { + if details.OriginChainID != bridgeRequest.Transaction.OriginChainId { return false } - if event.To != bridgeRequest.Transaction.DestRecipient { + if details.To != bridgeRequest.Transaction.DestRecipient { return false } - if event.OriginToken != bridgeRequest.Transaction.OriginToken { + if details.OriginToken != bridgeRequest.Transaction.OriginToken { return false } - if event.DestToken != bridgeRequest.Transaction.DestToken { + if details.DestToken != bridgeRequest.Transaction.DestToken { return false } return true diff --git a/services/rfq/relayer/relconfig/config.go b/services/rfq/relayer/relconfig/config.go index 5804c3da5d..fb5e484363 100644 --- a/services/rfq/relayer/relconfig/config.go +++ b/services/rfq/relayer/relconfig/config.go @@ -73,8 +73,10 @@ type Config struct { // ChainConfig represents the configuration for a chain. type ChainConfig struct { - // Bridge is the rfq bridge contract address. + // RFQAddress is the rfq bridge contract address (v2). RFQAddress string `yaml:"rfq_address"` + // RFQAddressV1 is the rfq bridge contract address (v1, optional). + RFQAddressV1 *string `yaml:"rfq_address_v1"` // Confirmations is the number of required confirmations. Confirmations uint64 `yaml:"confirmations"` // FinalityConfirmations is the number of required confirmations before proving. diff --git a/services/rfq/testutil/contracttype.go b/services/rfq/testutil/contracttype.go index dd163fb789..c3e6d5f5da 100644 --- a/services/rfq/testutil/contracttype.go +++ b/services/rfq/testutil/contracttype.go @@ -5,6 +5,7 @@ import ( "github.com/synapsecns/sanguine/ethergo/backends/base" "github.com/synapsecns/sanguine/ethergo/contracts" "github.com/synapsecns/sanguine/services/rfq/contracts/fastbridge" + "github.com/synapsecns/sanguine/services/rfq/contracts/fastbridgev2" "github.com/synapsecns/sanguine/services/rfq/contracts/testcontracts/dai" "github.com/synapsecns/sanguine/services/rfq/contracts/testcontracts/fastbridgemockv2" "github.com/synapsecns/sanguine/services/rfq/contracts/testcontracts/mockerc20" @@ -50,7 +51,9 @@ type contractTypeImpl int const ( // FastBridgeType is the type of the fast bridge contract. - FastBridgeType contractTypeImpl = iota + 1 // FastBridge + FastBridgeType contractTypeImpl = iota + 1 // FastBridgeV1 + // FastBridgeV2Type is the type of the fast bridge contract. + FastBridgeV2Type // FastBridgeV2 // MockERC20Type is a mock erc20 contract. MockERC20Type // MockERC20 // FastBridgeMockType is a mock contract for testing fast bridge interactions. @@ -94,6 +97,8 @@ func (c contractTypeImpl) ContractInfo() *compiler.Contract { switch c { case FastBridgeType: return fastbridge.Contracts["solidity/FastBridge.sol:FastBridge"] + case FastBridgeV2Type: + return fastbridgev2.Contracts["solidity/FastBridgeV2.sol:FastBridgeV2"] case MockERC20Type: return mockerc20.Contracts["solidity/MockERC20.sol:MockERC20"] case FastBridgeMockType: diff --git a/services/rfq/testutil/contracttypeimpl_string.go b/services/rfq/testutil/contracttypeimpl_string.go index ea177a0db3..a693f563d9 100644 --- a/services/rfq/testutil/contracttypeimpl_string.go +++ b/services/rfq/testutil/contracttypeimpl_string.go @@ -9,18 +9,19 @@ func _() { // Re-run the stringer command to generate them again. var x [1]struct{} _ = x[FastBridgeType-1] - _ = x[MockERC20Type-2] - _ = x[FastBridgeMockType-3] - _ = x[RecipientMockType-4] - _ = x[WETH9Type-5] - _ = x[USDTType-6] - _ = x[USDCType-7] - _ = x[DAIType-8] + _ = x[FastBridgeV2Type-2] + _ = x[MockERC20Type-3] + _ = x[FastBridgeMockType-4] + _ = x[RecipientMockType-5] + _ = x[WETH9Type-6] + _ = x[USDTType-7] + _ = x[USDCType-8] + _ = x[DAIType-9] } -const _contractTypeImpl_name = "FastBridgeMockERC20FastBridgeMockRecipientMockWETH9USDTUSDCDAI" +const _contractTypeImpl_name = "FastBridgeV1FastBridgeV2MockERC20FastBridgeMockRecipientMockWETH9USDTUSDCDAI" -var _contractTypeImpl_index = [...]uint8{0, 10, 19, 33, 46, 51, 55, 59, 62} +var _contractTypeImpl_index = [...]uint8{0, 12, 24, 33, 47, 60, 65, 69, 73, 76} func (i contractTypeImpl) String() string { i -= 1 diff --git a/services/rfq/testutil/deployers.go b/services/rfq/testutil/deployers.go index bdeb0917bb..854f341889 100644 --- a/services/rfq/testutil/deployers.go +++ b/services/rfq/testutil/deployers.go @@ -14,6 +14,7 @@ import ( "github.com/synapsecns/sanguine/ethergo/contracts" "github.com/synapsecns/sanguine/ethergo/deployer" "github.com/synapsecns/sanguine/ethergo/manager" + "github.com/synapsecns/sanguine/services/rfq/contracts/fastbridge" "github.com/synapsecns/sanguine/services/rfq/contracts/fastbridgev2" "github.com/synapsecns/sanguine/services/rfq/contracts/testcontracts/fastbridgemockv2" "github.com/synapsecns/sanguine/services/rfq/contracts/testcontracts/recipientmock" @@ -28,7 +29,7 @@ type DeployManager struct { func NewDeployManager(t *testing.T) *DeployManager { t.Helper() - parentManager := manager.NewDeployerManager(t, NewFastBridgeDeployer, NewMockERC20Deployer, NewMockFastBridgeDeployer, NewRecipientMockDeployer, NewWETH9Deployer, NewUSDTDeployer, NewUSDCDeployer, NewDAIDeployer) + parentManager := manager.NewDeployerManager(t, NewFastBridgeDeployer, NewFastBridgeV2Deployer, NewMockERC20Deployer, NewMockFastBridgeDeployer, NewRecipientMockDeployer, NewWETH9Deployer, NewUSDTDeployer, NewUSDCDeployer, NewDAIDeployer) return &DeployManager{parentManager} } @@ -113,6 +114,27 @@ func NewFastBridgeDeployer(registry deployer.GetOnlyContractRegistry, backend ba // Deploy deploys the fast bridge contract. func (f FastBridgeDeployer) Deploy(ctx context.Context) (contracts.DeployedContract, error) { + return f.DeploySimpleContract(ctx, func(transactOps *bind.TransactOpts, backend bind.ContractBackend) (common.Address, *types.Transaction, interface{}, error) { + return fastbridge.DeployFastBridge(transactOps, backend, transactOps.From) + }, func(address common.Address, backend bind.ContractBackend) (interface{}, error) { + return fastbridge.NewFastBridgeRef(address, backend) + }) +} + +// FastBridgeV2Deployer deplyos a fast bridge contract for testing. +type FastBridgeV2Deployer struct { + *deployer.BaseDeployer +} + +// NewFastBridgeV2Deployer deploys a fast bridge contract. +func NewFastBridgeV2Deployer(registry deployer.GetOnlyContractRegistry, backend backends.SimulatedTestBackend) deployer.ContractDeployer { + return FastBridgeV2Deployer{ + deployer.NewSimpleDeployer(registry, backend, FastBridgeV2Type), + } +} + +// Deploy deploys the fast bridge contract. +func (f FastBridgeV2Deployer) Deploy(ctx context.Context) (contracts.DeployedContract, error) { return f.DeploySimpleContract(ctx, func(transactOps *bind.TransactOpts, backend bind.ContractBackend) (common.Address, *types.Transaction, interface{}, error) { return fastbridgev2.DeployFastBridgeV2(transactOps, backend, transactOps.From) }, func(address common.Address, backend bind.ContractBackend) (interface{}, error) { diff --git a/services/rfq/testutil/typecast.go b/services/rfq/testutil/typecast.go index 1c4b14269f..541655dbe8 100644 --- a/services/rfq/testutil/typecast.go +++ b/services/rfq/testutil/typecast.go @@ -6,6 +6,7 @@ import ( "github.com/synapsecns/sanguine/ethergo/backends" "github.com/synapsecns/sanguine/ethergo/contracts" "github.com/synapsecns/sanguine/ethergo/manager" + "github.com/synapsecns/sanguine/services/rfq/contracts/fastbridge" "github.com/synapsecns/sanguine/services/rfq/contracts/fastbridgev2" "github.com/synapsecns/sanguine/services/rfq/contracts/testcontracts/dai" "github.com/synapsecns/sanguine/services/rfq/contracts/testcontracts/fastbridgemockv2" @@ -17,10 +18,17 @@ import ( ) // GetFastBridge gets the pre-created fast bridge contract. -func (d *DeployManager) GetFastBridge(ctx context.Context, backend backends.SimulatedTestBackend) (contract contracts.DeployedContract, handle *fastbridgev2.FastBridgeV2Ref) { +func (d *DeployManager) GetFastBridge(ctx context.Context, backend backends.SimulatedTestBackend) (contract contracts.DeployedContract, handle *fastbridge.FastBridgeRef) { d.T().Helper() - return manager.GetContract[*fastbridgev2.FastBridgeV2Ref](ctx, d.T(), d, backend, FastBridgeType) + return manager.GetContract[*fastbridge.FastBridgeRef](ctx, d.T(), d, backend, FastBridgeType) +} + +// GetFastBridgeV2 gets the pre-created fast bridge v2 contract. +func (d *DeployManager) GetFastBridgeV2(ctx context.Context, backend backends.SimulatedTestBackend) (contract contracts.DeployedContract, handle *fastbridgev2.FastBridgeV2Ref) { + d.T().Helper() + + return manager.GetContract[*fastbridgev2.FastBridgeV2Ref](ctx, d.T(), d, backend, FastBridgeV2Type) } // GetMockERC20 gets a mock erc20 deployed on a chain. From fab0b9e511de12998e47b45c483ba4765f9b05ac Mon Sep 17 00:00:00 2001 From: Daniel Wasserman Date: Wed, 4 Dec 2024 12:12:16 -0600 Subject: [PATCH 56/85] [goreleaser] From c1f57ef36a425cccc60efdb9d928f55625bf0a4a Mon Sep 17 00:00:00 2001 From: dwasse Date: Fri, 6 Dec 2024 14:59:50 -0600 Subject: [PATCH 57/85] feat(rfq-relayer): fee pricer considers v2 CallValue and CallParams [SLT-320] (#3299) * WIP: incorporate call params into fee * WIP: decompose getFee() * Feat: account for CallValue in getDestinationFee() * Fix: build * Feat: test call value and call param calculation in fee pricer * Feat: add context on request body in rpc fwd errs * Fix: zap estimate gas * Cleanup: move gas estimate into own func * Fix: quoter tests * Cleanup: lint * Cleanup: lint * Fix: tests * Cleanup: decompose func * Cleanup: lint * Fix: tests * Cleanup: lint * Feat: always use quote fee multiplier * WIP: abi encode pack relay() * Feat: pass full RawRequest for gas estimation * Cleanup: lint * Fix: pricer tests * Feat: ignore static l2 fee when incorporating call params * Fix: tests * Clarifying comment * Feat: add extra check for call param len * Attempt to fix flake * Cleanup: lint * Fix: build * feat(rfq-relayer): apply zap fee to dest amount for active quotes [SLT-465] (#3395) * Feat: set zap params in supply to fee pricer * Feat: adjust dest amount by fee for active quote * Feat: add TestGenerateActiveRFQ * Feat: add nonzero case * Cleanup: lint * fix(rfq-relayer): gas estimation for zaps (#3413) * WIP: use QuoteData instead of QuoteRequest * WIP: impl conversion * Feat: use QuoteRequest instead of QuoteData for encoding * WIP: another encoding impl * WIP: add bridgetransactionv2 * WIP: regenerate with running test * Working zap e2e * Cleanup: encoding * Cleanup: move to new encoding file * ABIgen from harness instead of lib * Cleanup: lint * Fix: CI build * Fix: deploy harness * Fix: rfq test * Feat: use gofakeit to mock * Cleanup: test structure * Replace: EncodeQuoteRequest -> EncodeBridgeTx * Feat: add Decode func and add to parity test * Fix: eth address mocks * Cleanup: lint * Cleanup: lint --------- Co-authored-by: parodime --- ethergo/backends/anvil/anvil.go | 13 +- packages/contracts-rfq/package.json | 2 +- services/omnirpc/proxy/forward.go | 7 +- services/rfq/api/model/request.go | 3 +- .../bridgetransactionv2.abigen.go | 4004 +++++++++++++++++ .../bridgetransactionv2.contractinfo.json | 1 + .../bridgetransactionv2.metadata.go | 25 + .../contracts/bridgetransactionv2/generate.go | 4 + .../contracts/bridgetransactionv2/helper.go | 35 + services/rfq/e2e/rfq_test.go | 110 + services/rfq/relayer/chain/encoding.go | 113 + services/rfq/relayer/pricer/fee_pricer.go | 191 +- .../rfq/relayer/pricer/fee_pricer_test.go | 82 +- services/rfq/relayer/pricer/suite_test.go | 2 + services/rfq/relayer/quoter/export_test.go | 4 + services/rfq/relayer/quoter/quoter.go | 76 +- services/rfq/relayer/quoter/quoter_test.go | 91 +- services/rfq/relayer/quoter/suite_test.go | 2 +- services/rfq/relayer/service/relayer.go | 2 +- services/rfq/testutil/contracttype.go | 5 + .../rfq/testutil/contracttypeimpl_string.go | 13 +- services/rfq/testutil/deployers.go | 25 +- services/rfq/testutil/typecast.go | 9 +- 23 files changed, 4747 insertions(+), 72 deletions(-) create mode 100644 services/rfq/contracts/bridgetransactionv2/bridgetransactionv2.abigen.go create mode 100644 services/rfq/contracts/bridgetransactionv2/bridgetransactionv2.contractinfo.json create mode 100644 services/rfq/contracts/bridgetransactionv2/bridgetransactionv2.metadata.go create mode 100644 services/rfq/contracts/bridgetransactionv2/generate.go create mode 100644 services/rfq/contracts/bridgetransactionv2/helper.go create mode 100644 services/rfq/relayer/chain/encoding.go diff --git a/ethergo/backends/anvil/anvil.go b/ethergo/backends/anvil/anvil.go index 6bc14c3e3d..5006beb150 100644 --- a/ethergo/backends/anvil/anvil.go +++ b/ethergo/backends/anvil/anvil.go @@ -30,6 +30,7 @@ import ( "github.com/synapsecns/sanguine/core/dockerutil" "github.com/synapsecns/sanguine/core/mapmutex" "github.com/synapsecns/sanguine/core/processlog" + "github.com/synapsecns/sanguine/core/retry" "github.com/synapsecns/sanguine/ethergo/backends" "github.com/synapsecns/sanguine/ethergo/backends/base" "github.com/synapsecns/sanguine/ethergo/chain" @@ -386,9 +387,15 @@ func (f *Backend) GetTxContext(ctx context.Context, address *common.Address) (re var acct *keystore.Key // TODO handle storing accounts to conform to get tx context if address != nil { - acct = f.GetAccount(*address) - if acct == nil { - f.T().Errorf("could not get account %s", address.String()) + err := retry.WithBackoff(ctx, func(_ context.Context) error { + acct = f.GetAccount(*address) + if acct == nil { + return fmt.Errorf("could not get account %s", address.String()) + } + return nil + }, retry.WithMaxTotalTime(10*time.Second)) + if err != nil { + f.T().Errorf("could not get account %s: %v", address.String(), err) return res } } else { diff --git a/packages/contracts-rfq/package.json b/packages/contracts-rfq/package.json index 98cc2d4c08..b92cc0e2d9 100644 --- a/packages/contracts-rfq/package.json +++ b/packages/contracts-rfq/package.json @@ -26,7 +26,7 @@ "lint": "forge fmt && npm run solhint", "lint:check": "forge fmt --check && npm run solhint:check", "ci:lint": "npm run lint:check", - "build:go": "./flatten.sh contracts/*.sol test/*.sol test/mocks/*.sol", + "build:go": "./flatten.sh contracts/*.sol test/*.sol test/mocks/*.sol test/harnesses/*.sol", "solhint": "solhint '{contracts,script,test}/**/*.sol' --fix --noPrompt --max-warnings 3", "solhint:check": "solhint '{contracts,script,test}/**/*.sol' --max-warnings 3" } diff --git a/services/omnirpc/proxy/forward.go b/services/omnirpc/proxy/forward.go index ffdf2d37dc..a5ba63cb6a 100644 --- a/services/omnirpc/proxy/forward.go +++ b/services/omnirpc/proxy/forward.go @@ -5,6 +5,9 @@ import ( "context" "crypto/sha256" "fmt" + goHTTP "net/http" + "strings" + "github.com/ImVexed/fasturl" "github.com/goccy/go-json" "github.com/jftuga/ellipsis" @@ -14,8 +17,6 @@ import ( "go.opentelemetry.io/otel/attribute" "go.opentelemetry.io/otel/trace" "golang.org/x/exp/slices" - goHTTP "net/http" - "strings" ) type rawResponse struct { @@ -56,7 +57,7 @@ func (f *Forwarder) newRawResponse(ctx context.Context, body []byte, url string) standardizedResponse, err = standardizeResponse(ctx, &f.rpcRequest[0], rpcMessage) if err != nil { - return nil, fmt.Errorf("could not standardize response: %w", err) + return nil, fmt.Errorf("could not standardize response from body %s: %w", ellipsis.Shorten(string(body), 200), err) } } diff --git a/services/rfq/api/model/request.go b/services/rfq/api/model/request.go index bbc5c1aa88..4ed1305c7c 100644 --- a/services/rfq/api/model/request.go +++ b/services/rfq/api/model/request.go @@ -55,11 +55,12 @@ type QuoteData struct { DestChainID int `json:"dest_chain_id"` OriginTokenAddr string `json:"origin_token_addr"` DestTokenAddr string `json:"dest_token_addr"` - OriginAmount string `json:"origin_amount"` ExpirationWindow int64 `json:"expiration_window"` ZapData string `json:"zap_data"` ZapNative string `json:"zap_native"` OriginAmountExact string `json:"origin_amount_exact"` + OriginSender string `json:"origin_sender"` + DestRecipient string `json:"dest_recipient"` DestAmount *string `json:"dest_amount"` RelayerAddress *string `json:"relayer_address"` QuoteID *string `json:"quote_id"` diff --git a/services/rfq/contracts/bridgetransactionv2/bridgetransactionv2.abigen.go b/services/rfq/contracts/bridgetransactionv2/bridgetransactionv2.abigen.go new file mode 100644 index 0000000000..6e8d5c3897 --- /dev/null +++ b/services/rfq/contracts/bridgetransactionv2/bridgetransactionv2.abigen.go @@ -0,0 +1,4004 @@ +// Code generated - DO NOT EDIT. +// This file is a generated binding and any manual changes will be lost. + +package bridgetransactionv2 + +import ( + "errors" + "math/big" + "strings" + + ethereum "github.com/ethereum/go-ethereum" + "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/event" +) + +// Reference imports to suppress errors if they are not otherwise used. +var ( + _ = errors.New + _ = big.NewInt + _ = strings.NewReader + _ = ethereum.NotFound + _ = bind.Bind + _ = common.Big1 + _ = types.BloomLookup + _ = event.NewSubscription + _ = abi.ConvertType +) + +// IFastBridgeBridgeParams is an auto generated low-level Go binding around an user-defined struct. +type IFastBridgeBridgeParams struct { + DstChainId uint32 + Sender common.Address + To common.Address + OriginToken common.Address + DestToken common.Address + OriginAmount *big.Int + DestAmount *big.Int + SendChainGas bool + Deadline *big.Int +} + +// IFastBridgeBridgeTransaction is an auto generated low-level Go binding around an user-defined struct. +type IFastBridgeBridgeTransaction struct { + OriginChainId uint32 + DestChainId uint32 + OriginSender common.Address + DestRecipient common.Address + OriginToken common.Address + DestToken common.Address + OriginAmount *big.Int + DestAmount *big.Int + OriginFeeAmount *big.Int + SendChainGas bool + Deadline *big.Int + Nonce *big.Int +} + +// IFastBridgeV2BridgeParamsV2 is an auto generated low-level Go binding around an user-defined struct. +type IFastBridgeV2BridgeParamsV2 struct { + QuoteRelayer common.Address + QuoteExclusivitySeconds *big.Int + QuoteId []byte + ZapNative *big.Int + ZapData []byte +} + +// IFastBridgeV2BridgeTransactionV2 is an auto generated low-level Go binding around an user-defined struct. +type IFastBridgeV2BridgeTransactionV2 struct { + OriginChainId uint32 + DestChainId uint32 + OriginSender common.Address + DestRecipient common.Address + OriginToken common.Address + DestToken common.Address + OriginAmount *big.Int + DestAmount *big.Int + OriginFeeAmount *big.Int + Deadline *big.Int + Nonce *big.Int + ExclusivityRelayer common.Address + ExclusivityEndTime *big.Int + ZapNative *big.Int + ZapData []byte +} + +// BridgeTransactionV2HarnessMetaData contains all meta data concerning the BridgeTransactionV2Harness contract. +var BridgeTransactionV2HarnessMetaData = &bind.MetaData{ + ABI: "[{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"encodedTx\",\"type\":\"bytes\"}],\"name\":\"deadline\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"encodedTx\",\"type\":\"bytes\"}],\"name\":\"decodeV2\",\"outputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"originChainId\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"destChainId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"originSender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destRecipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"originFeeAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"exclusivityRelayer\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"exclusivityEndTime\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"zapNative\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"zapData\",\"type\":\"bytes\"}],\"internalType\":\"structIFastBridgeV2.BridgeTransactionV2\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"encodedTx\",\"type\":\"bytes\"}],\"name\":\"destAmount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"encodedTx\",\"type\":\"bytes\"}],\"name\":\"destChainId\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"encodedTx\",\"type\":\"bytes\"}],\"name\":\"destRecipient\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"encodedTx\",\"type\":\"bytes\"}],\"name\":\"destToken\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"originChainId\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"destChainId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"originSender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destRecipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"originFeeAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"exclusivityRelayer\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"exclusivityEndTime\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"zapNative\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"zapData\",\"type\":\"bytes\"}],\"internalType\":\"structIFastBridgeV2.BridgeTransactionV2\",\"name\":\"bridgeTx\",\"type\":\"tuple\"}],\"name\":\"encodeV2\",\"outputs\":[{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"encodedTx\",\"type\":\"bytes\"}],\"name\":\"exclusivityEndTime\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"encodedTx\",\"type\":\"bytes\"}],\"name\":\"exclusivityRelayer\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"encodedTx\",\"type\":\"bytes\"}],\"name\":\"nonce\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"encodedTx\",\"type\":\"bytes\"}],\"name\":\"originAmount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"encodedTx\",\"type\":\"bytes\"}],\"name\":\"originChainId\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"encodedTx\",\"type\":\"bytes\"}],\"name\":\"originFeeAmount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"encodedTx\",\"type\":\"bytes\"}],\"name\":\"originSender\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"encodedTx\",\"type\":\"bytes\"}],\"name\":\"originToken\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"encodedTx\",\"type\":\"bytes\"}],\"name\":\"version\",\"outputs\":[{\"internalType\":\"uint16\",\"name\":\"\",\"type\":\"uint16\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"encodedTx\",\"type\":\"bytes\"}],\"name\":\"zapData\",\"outputs\":[{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"encodedTx\",\"type\":\"bytes\"}],\"name\":\"zapNative\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"pure\",\"type\":\"function\"}]", + Sigs: map[string]string{ + "e79f1782": "deadline(bytes)", + "24657024": "decodeV2(bytes)", + "12d0c512": "destAmount(bytes)", + "5c3fa4c0": "destChainId(bytes)", + "9c538802": "destRecipient(bytes)", + "37518e50": "destToken(bytes)", + "faef535a": "encodeV2((uint32,uint32,address,address,address,address,uint256,uint256,uint256,uint256,uint256,address,uint256,uint256,bytes))", + "6907efd7": "exclusivityEndTime(bytes)", + "dcafa970": "exclusivityRelayer(bytes)", + "4e765004": "nonce(bytes)", + "7241b9cb": "originAmount(bytes)", + "93bb0d80": "originChainId(bytes)", + "e938730e": "originFeeAmount(bytes)", + "9bdb46fe": "originSender(bytes)", + "93832899": "originToken(bytes)", + "7d67c5a7": "version(bytes)", + "0af3f403": "zapData(bytes)", + "230602c1": "zapNative(bytes)", + }, + Bin: "0x608060405234801561001057600080fd5b50610e65806100206000396000f3fe608060405234801561001057600080fd5b50600436106101365760003560e01c80637d67c5a7116100b25780639c53880211610081578063e79f178211610066578063e79f1782146102d7578063e938730e146102ea578063faef535a146102fd57600080fd5b80639c538802146102b1578063dcafa970146102c457600080fd5b80637d67c5a714610252578063938328991461027857806393bb0d801461028b5780639bdb46fe1461029e57600080fd5b806337518e50116101095780635c3fa4c0116100ee5780635c3fa4c0146102045780636907efd71461022c5780637241b9cb1461023f57600080fd5b806337518e50146101b95780634e765004146101f157600080fd5b80630af3f4031461013b57806312d0c51214610165578063230602c1146101865780632465702414610199575b600080fd5b61014e610149366004610868565b61031d565b60405161015c9291906108da565b60405180910390f35b610178610173366004610868565b610335565b60405190815260200161015c565b610178610194366004610868565b610344565b6101ac6101a7366004610868565b610351565b60405161015c9190610995565b6101cc6101c7366004610868565b61044e565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200161015c565b6101786101ff366004610868565b61045d565b610217610212366004610868565b610469565b60405163ffffffff909116815260200161015c565b61017861023a366004610868565b610478565b61017861024d366004610868565b610485565b610265610260366004610868565b610491565b60405161ffff909116815260200161015c565b6101cc610286366004610868565b61049d565b610217610299366004610868565b6104ac565b6101cc6102ac366004610868565b6104bb565b6101cc6102bf366004610868565b6104ca565b6101cc6102d2366004610868565b6104d9565b6101786102e5366004610868565b6104e8565b6101786102f8366004610868565b6104f4565b61031061030b366004610c34565b610500565b60405161015c9190610d69565b36600061032a8484610511565b915091509250929050565b6000607a8301355b9392505050565b600061012e83013561033d565b610444604051806101e00160405280600063ffffffff168152602001600063ffffffff168152602001600073ffffffffffffffffffffffffffffffffffffffff168152602001600073ffffffffffffffffffffffffffffffffffffffff168152602001600073ffffffffffffffffffffffffffffffffffffffff168152602001600073ffffffffffffffffffffffffffffffffffffffff1681526020016000815260200160008152602001600081526020016000815260200160008152602001600073ffffffffffffffffffffffffffffffffffffffff1681526020016000815260200160008152602001606081525090565b61033d8383610522565b6000604683013560601c61033d565b600060da83013561033d565b6000600683013560e01c61033d565b600061010e83013561033d565b6000605a83013561033d565b6000823560f01c61033d565b6000603283013560601c61033d565b6000600283013560e01c61033d565b6000600a83013560601c61033d565b6000601e83013560601c61033d565b600060fa83013560601c61033d565b600060ba83013561033d565b6000609a83013561033d565b606061050b82610705565b92915050565b36600061032a8361014e8187610d7c565b610615604051806101e00160405280600063ffffffff168152602001600063ffffffff168152602001600073ffffffffffffffffffffffffffffffffffffffff168152602001600073ffffffffffffffffffffffffffffffffffffffff168152602001600073ffffffffffffffffffffffffffffffffffffffff168152602001600073ffffffffffffffffffffffffffffffffffffffff1681526020016000815260200160008152602001600081526020016000815260200160008152602001600073ffffffffffffffffffffffffffffffffffffffff1681526020016000815260200160008152602001606081525090565b600283013560e090811c82526006840135811c6020830152600a840135606090811c6040840152601e850135811c818401526032850135811c60808401526046850135811c60a0840152605a85013560c0840152607a85013591830191909152609a84013561010083015260ba84013561012083015260da84013561014083015260fa840135901c61016082015261010e83013561018082015261012e8301356101a08201526106c58383610511565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152505050506101c082015292915050565b8051602080830151604080850151606086810151608088015160a089015160c08a015195517e02000000000000000000000000000000000000000000000000000000000000988101989098527fffffffff0000000000000000000000000000000000000000000000000000000060e0998a1b811660228a01529690981b90951660268701527fffffffffffffffffffffffffffffffffffffffff00000000000000000000000092821b8316602a870152811b8216603e86015292831b8116605285015293821b9093166066830152607a820192909252600090609a01604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529082905260e08501516101008601516101208701516101408801516101608901516101808a01516101a08b01516101c08c0151979950610851988a9890602001610da6565b604051602081830303815290604052915050919050565b6000806020838503121561087b57600080fd5b823567ffffffffffffffff8082111561089357600080fd5b818501915085601f8301126108a757600080fd5b8135818111156108b657600080fd5b8660208285010111156108c857600080fd5b60209290920196919550909350505050565b60208152816020820152818360408301376000818301604090810191909152601f9092017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0160101919050565b60005b8381101561094257818101518382015260200161092a565b50506000910152565b60008151808452610963816020860160208601610927565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b602081526109ac60208201835163ffffffff169052565b600060208301516109c5604084018263ffffffff169052565b50604083015173ffffffffffffffffffffffffffffffffffffffff8116606084015250606083015173ffffffffffffffffffffffffffffffffffffffff8116608084015250608083015173ffffffffffffffffffffffffffffffffffffffff811660a08401525060a083015173ffffffffffffffffffffffffffffffffffffffff811660c08401525060c083015160e08381019190915283015161010080840191909152830151610120808401919091528301516101408084019190915283015161016080840191909152830151610180610ab78185018373ffffffffffffffffffffffffffffffffffffffff169052565b8401516101a0848101919091528401516101c0808501919091528401516101e0808501529050610aeb61020084018261094b565b949350505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6040516101e0810167ffffffffffffffff81118282101715610b4657610b46610af3565b60405290565b803563ffffffff81168114610b6057600080fd5b919050565b803573ffffffffffffffffffffffffffffffffffffffff81168114610b6057600080fd5b600082601f830112610b9a57600080fd5b813567ffffffffffffffff80821115610bb557610bb5610af3565b604051601f83017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f01168101908282118183101715610bfb57610bfb610af3565b81604052838152866020858801011115610c1457600080fd5b836020870160208301376000602085830101528094505050505092915050565b600060208284031215610c4657600080fd5b813567ffffffffffffffff80821115610c5e57600080fd5b908301906101e08286031215610c7357600080fd5b610c7b610b22565b610c8483610b4c565b8152610c9260208401610b4c565b6020820152610ca360408401610b65565b6040820152610cb460608401610b65565b6060820152610cc560808401610b65565b6080820152610cd660a08401610b65565b60a082015260c0838101359082015260e08084013590820152610100808401359082015261012080840135908201526101408084013590820152610160610d1e818501610b65565b9082015261018083810135908201526101a080840135908201526101c08084013583811115610d4c57600080fd5b610d5888828701610b89565b918301919091525095945050505050565b60208152600061033d602083018461094b565b60008085851115610d8c57600080fd5b83861115610d9957600080fd5b5050820193919092039150565b60008a51610db8818460208f01610927565b80830190508a81528960208201528860408201528760608201527fffffffffffffffffffffffffffffffffffffffff0000000000000000000000008760601b1660808201528560948201528460b48201528351610e1c8160d4840160208801610927565b0160d4019b9a505050505050505050505056fea2646970667358221220ec634eada85ddd9f3a51bdae8c8de0703366a52e644989f6d717509c24795d6864736f6c63430008180033", +} + +// BridgeTransactionV2HarnessABI is the input ABI used to generate the binding from. +// Deprecated: Use BridgeTransactionV2HarnessMetaData.ABI instead. +var BridgeTransactionV2HarnessABI = BridgeTransactionV2HarnessMetaData.ABI + +// Deprecated: Use BridgeTransactionV2HarnessMetaData.Sigs instead. +// BridgeTransactionV2HarnessFuncSigs maps the 4-byte function signature to its string representation. +var BridgeTransactionV2HarnessFuncSigs = BridgeTransactionV2HarnessMetaData.Sigs + +// BridgeTransactionV2HarnessBin is the compiled bytecode used for deploying new contracts. +// Deprecated: Use BridgeTransactionV2HarnessMetaData.Bin instead. +var BridgeTransactionV2HarnessBin = BridgeTransactionV2HarnessMetaData.Bin + +// DeployBridgeTransactionV2Harness deploys a new Ethereum contract, binding an instance of BridgeTransactionV2Harness to it. +func DeployBridgeTransactionV2Harness(auth *bind.TransactOpts, backend bind.ContractBackend) (common.Address, *types.Transaction, *BridgeTransactionV2Harness, error) { + parsed, err := BridgeTransactionV2HarnessMetaData.GetAbi() + if err != nil { + return common.Address{}, nil, nil, err + } + if parsed == nil { + return common.Address{}, nil, nil, errors.New("GetABI returned nil") + } + + address, tx, contract, err := bind.DeployContract(auth, *parsed, common.FromHex(BridgeTransactionV2HarnessBin), backend) + if err != nil { + return common.Address{}, nil, nil, err + } + return address, tx, &BridgeTransactionV2Harness{BridgeTransactionV2HarnessCaller: BridgeTransactionV2HarnessCaller{contract: contract}, BridgeTransactionV2HarnessTransactor: BridgeTransactionV2HarnessTransactor{contract: contract}, BridgeTransactionV2HarnessFilterer: BridgeTransactionV2HarnessFilterer{contract: contract}}, nil +} + +// BridgeTransactionV2Harness is an auto generated Go binding around an Ethereum contract. +type BridgeTransactionV2Harness struct { + BridgeTransactionV2HarnessCaller // Read-only binding to the contract + BridgeTransactionV2HarnessTransactor // Write-only binding to the contract + BridgeTransactionV2HarnessFilterer // Log filterer for contract events +} + +// BridgeTransactionV2HarnessCaller is an auto generated read-only Go binding around an Ethereum contract. +type BridgeTransactionV2HarnessCaller struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// BridgeTransactionV2HarnessTransactor is an auto generated write-only Go binding around an Ethereum contract. +type BridgeTransactionV2HarnessTransactor struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// BridgeTransactionV2HarnessFilterer is an auto generated log filtering Go binding around an Ethereum contract events. +type BridgeTransactionV2HarnessFilterer struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// BridgeTransactionV2HarnessSession is an auto generated Go binding around an Ethereum contract, +// with pre-set call and transact options. +type BridgeTransactionV2HarnessSession struct { + Contract *BridgeTransactionV2Harness // Generic contract binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// BridgeTransactionV2HarnessCallerSession is an auto generated read-only Go binding around an Ethereum contract, +// with pre-set call options. +type BridgeTransactionV2HarnessCallerSession struct { + Contract *BridgeTransactionV2HarnessCaller // Generic contract caller binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session +} + +// BridgeTransactionV2HarnessTransactorSession is an auto generated write-only Go binding around an Ethereum contract, +// with pre-set transact options. +type BridgeTransactionV2HarnessTransactorSession struct { + Contract *BridgeTransactionV2HarnessTransactor // Generic contract transactor binding to set the session for + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// BridgeTransactionV2HarnessRaw is an auto generated low-level Go binding around an Ethereum contract. +type BridgeTransactionV2HarnessRaw struct { + Contract *BridgeTransactionV2Harness // Generic contract binding to access the raw methods on +} + +// BridgeTransactionV2HarnessCallerRaw is an auto generated low-level read-only Go binding around an Ethereum contract. +type BridgeTransactionV2HarnessCallerRaw struct { + Contract *BridgeTransactionV2HarnessCaller // Generic read-only contract binding to access the raw methods on +} + +// BridgeTransactionV2HarnessTransactorRaw is an auto generated low-level write-only Go binding around an Ethereum contract. +type BridgeTransactionV2HarnessTransactorRaw struct { + Contract *BridgeTransactionV2HarnessTransactor // Generic write-only contract binding to access the raw methods on +} + +// NewBridgeTransactionV2Harness creates a new instance of BridgeTransactionV2Harness, bound to a specific deployed contract. +func NewBridgeTransactionV2Harness(address common.Address, backend bind.ContractBackend) (*BridgeTransactionV2Harness, error) { + contract, err := bindBridgeTransactionV2Harness(address, backend, backend, backend) + if err != nil { + return nil, err + } + return &BridgeTransactionV2Harness{BridgeTransactionV2HarnessCaller: BridgeTransactionV2HarnessCaller{contract: contract}, BridgeTransactionV2HarnessTransactor: BridgeTransactionV2HarnessTransactor{contract: contract}, BridgeTransactionV2HarnessFilterer: BridgeTransactionV2HarnessFilterer{contract: contract}}, nil +} + +// NewBridgeTransactionV2HarnessCaller creates a new read-only instance of BridgeTransactionV2Harness, bound to a specific deployed contract. +func NewBridgeTransactionV2HarnessCaller(address common.Address, caller bind.ContractCaller) (*BridgeTransactionV2HarnessCaller, error) { + contract, err := bindBridgeTransactionV2Harness(address, caller, nil, nil) + if err != nil { + return nil, err + } + return &BridgeTransactionV2HarnessCaller{contract: contract}, nil +} + +// NewBridgeTransactionV2HarnessTransactor creates a new write-only instance of BridgeTransactionV2Harness, bound to a specific deployed contract. +func NewBridgeTransactionV2HarnessTransactor(address common.Address, transactor bind.ContractTransactor) (*BridgeTransactionV2HarnessTransactor, error) { + contract, err := bindBridgeTransactionV2Harness(address, nil, transactor, nil) + if err != nil { + return nil, err + } + return &BridgeTransactionV2HarnessTransactor{contract: contract}, nil +} + +// NewBridgeTransactionV2HarnessFilterer creates a new log filterer instance of BridgeTransactionV2Harness, bound to a specific deployed contract. +func NewBridgeTransactionV2HarnessFilterer(address common.Address, filterer bind.ContractFilterer) (*BridgeTransactionV2HarnessFilterer, error) { + contract, err := bindBridgeTransactionV2Harness(address, nil, nil, filterer) + if err != nil { + return nil, err + } + return &BridgeTransactionV2HarnessFilterer{contract: contract}, nil +} + +// bindBridgeTransactionV2Harness binds a generic wrapper to an already deployed contract. +func bindBridgeTransactionV2Harness(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) { + parsed, err := BridgeTransactionV2HarnessMetaData.GetAbi() + if err != nil { + return nil, err + } + return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil +} + +// Call invokes the (constant) contract method with params as input values and +// sets the output to result. The result type might be a single field for simple +// returns, a slice of interfaces for anonymous returns and a struct for named +// returns. +func (_BridgeTransactionV2Harness *BridgeTransactionV2HarnessRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _BridgeTransactionV2Harness.Contract.BridgeTransactionV2HarnessCaller.contract.Call(opts, result, method, params...) +} + +// Transfer initiates a plain transaction to move funds to the contract, calling +// its default method if one is available. +func (_BridgeTransactionV2Harness *BridgeTransactionV2HarnessRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _BridgeTransactionV2Harness.Contract.BridgeTransactionV2HarnessTransactor.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_BridgeTransactionV2Harness *BridgeTransactionV2HarnessRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _BridgeTransactionV2Harness.Contract.BridgeTransactionV2HarnessTransactor.contract.Transact(opts, method, params...) +} + +// Call invokes the (constant) contract method with params as input values and +// sets the output to result. The result type might be a single field for simple +// returns, a slice of interfaces for anonymous returns and a struct for named +// returns. +func (_BridgeTransactionV2Harness *BridgeTransactionV2HarnessCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _BridgeTransactionV2Harness.Contract.contract.Call(opts, result, method, params...) +} + +// Transfer initiates a plain transaction to move funds to the contract, calling +// its default method if one is available. +func (_BridgeTransactionV2Harness *BridgeTransactionV2HarnessTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _BridgeTransactionV2Harness.Contract.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_BridgeTransactionV2Harness *BridgeTransactionV2HarnessTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _BridgeTransactionV2Harness.Contract.contract.Transact(opts, method, params...) +} + +// Deadline is a free data retrieval call binding the contract method 0xe79f1782. +// +// Solidity: function deadline(bytes encodedTx) pure returns(uint256) +func (_BridgeTransactionV2Harness *BridgeTransactionV2HarnessCaller) Deadline(opts *bind.CallOpts, encodedTx []byte) (*big.Int, error) { + var out []interface{} + err := _BridgeTransactionV2Harness.contract.Call(opts, &out, "deadline", encodedTx) + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// Deadline is a free data retrieval call binding the contract method 0xe79f1782. +// +// Solidity: function deadline(bytes encodedTx) pure returns(uint256) +func (_BridgeTransactionV2Harness *BridgeTransactionV2HarnessSession) Deadline(encodedTx []byte) (*big.Int, error) { + return _BridgeTransactionV2Harness.Contract.Deadline(&_BridgeTransactionV2Harness.CallOpts, encodedTx) +} + +// Deadline is a free data retrieval call binding the contract method 0xe79f1782. +// +// Solidity: function deadline(bytes encodedTx) pure returns(uint256) +func (_BridgeTransactionV2Harness *BridgeTransactionV2HarnessCallerSession) Deadline(encodedTx []byte) (*big.Int, error) { + return _BridgeTransactionV2Harness.Contract.Deadline(&_BridgeTransactionV2Harness.CallOpts, encodedTx) +} + +// DecodeV2 is a free data retrieval call binding the contract method 0x24657024. +// +// Solidity: function decodeV2(bytes encodedTx) pure returns((uint32,uint32,address,address,address,address,uint256,uint256,uint256,uint256,uint256,address,uint256,uint256,bytes)) +func (_BridgeTransactionV2Harness *BridgeTransactionV2HarnessCaller) DecodeV2(opts *bind.CallOpts, encodedTx []byte) (IFastBridgeV2BridgeTransactionV2, error) { + var out []interface{} + err := _BridgeTransactionV2Harness.contract.Call(opts, &out, "decodeV2", encodedTx) + + if err != nil { + return *new(IFastBridgeV2BridgeTransactionV2), err + } + + out0 := *abi.ConvertType(out[0], new(IFastBridgeV2BridgeTransactionV2)).(*IFastBridgeV2BridgeTransactionV2) + + return out0, err + +} + +// DecodeV2 is a free data retrieval call binding the contract method 0x24657024. +// +// Solidity: function decodeV2(bytes encodedTx) pure returns((uint32,uint32,address,address,address,address,uint256,uint256,uint256,uint256,uint256,address,uint256,uint256,bytes)) +func (_BridgeTransactionV2Harness *BridgeTransactionV2HarnessSession) DecodeV2(encodedTx []byte) (IFastBridgeV2BridgeTransactionV2, error) { + return _BridgeTransactionV2Harness.Contract.DecodeV2(&_BridgeTransactionV2Harness.CallOpts, encodedTx) +} + +// DecodeV2 is a free data retrieval call binding the contract method 0x24657024. +// +// Solidity: function decodeV2(bytes encodedTx) pure returns((uint32,uint32,address,address,address,address,uint256,uint256,uint256,uint256,uint256,address,uint256,uint256,bytes)) +func (_BridgeTransactionV2Harness *BridgeTransactionV2HarnessCallerSession) DecodeV2(encodedTx []byte) (IFastBridgeV2BridgeTransactionV2, error) { + return _BridgeTransactionV2Harness.Contract.DecodeV2(&_BridgeTransactionV2Harness.CallOpts, encodedTx) +} + +// DestAmount is a free data retrieval call binding the contract method 0x12d0c512. +// +// Solidity: function destAmount(bytes encodedTx) pure returns(uint256) +func (_BridgeTransactionV2Harness *BridgeTransactionV2HarnessCaller) DestAmount(opts *bind.CallOpts, encodedTx []byte) (*big.Int, error) { + var out []interface{} + err := _BridgeTransactionV2Harness.contract.Call(opts, &out, "destAmount", encodedTx) + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// DestAmount is a free data retrieval call binding the contract method 0x12d0c512. +// +// Solidity: function destAmount(bytes encodedTx) pure returns(uint256) +func (_BridgeTransactionV2Harness *BridgeTransactionV2HarnessSession) DestAmount(encodedTx []byte) (*big.Int, error) { + return _BridgeTransactionV2Harness.Contract.DestAmount(&_BridgeTransactionV2Harness.CallOpts, encodedTx) +} + +// DestAmount is a free data retrieval call binding the contract method 0x12d0c512. +// +// Solidity: function destAmount(bytes encodedTx) pure returns(uint256) +func (_BridgeTransactionV2Harness *BridgeTransactionV2HarnessCallerSession) DestAmount(encodedTx []byte) (*big.Int, error) { + return _BridgeTransactionV2Harness.Contract.DestAmount(&_BridgeTransactionV2Harness.CallOpts, encodedTx) +} + +// DestChainId is a free data retrieval call binding the contract method 0x5c3fa4c0. +// +// Solidity: function destChainId(bytes encodedTx) pure returns(uint32) +func (_BridgeTransactionV2Harness *BridgeTransactionV2HarnessCaller) DestChainId(opts *bind.CallOpts, encodedTx []byte) (uint32, error) { + var out []interface{} + err := _BridgeTransactionV2Harness.contract.Call(opts, &out, "destChainId", encodedTx) + + if err != nil { + return *new(uint32), err + } + + out0 := *abi.ConvertType(out[0], new(uint32)).(*uint32) + + return out0, err + +} + +// DestChainId is a free data retrieval call binding the contract method 0x5c3fa4c0. +// +// Solidity: function destChainId(bytes encodedTx) pure returns(uint32) +func (_BridgeTransactionV2Harness *BridgeTransactionV2HarnessSession) DestChainId(encodedTx []byte) (uint32, error) { + return _BridgeTransactionV2Harness.Contract.DestChainId(&_BridgeTransactionV2Harness.CallOpts, encodedTx) +} + +// DestChainId is a free data retrieval call binding the contract method 0x5c3fa4c0. +// +// Solidity: function destChainId(bytes encodedTx) pure returns(uint32) +func (_BridgeTransactionV2Harness *BridgeTransactionV2HarnessCallerSession) DestChainId(encodedTx []byte) (uint32, error) { + return _BridgeTransactionV2Harness.Contract.DestChainId(&_BridgeTransactionV2Harness.CallOpts, encodedTx) +} + +// DestRecipient is a free data retrieval call binding the contract method 0x9c538802. +// +// Solidity: function destRecipient(bytes encodedTx) pure returns(address) +func (_BridgeTransactionV2Harness *BridgeTransactionV2HarnessCaller) DestRecipient(opts *bind.CallOpts, encodedTx []byte) (common.Address, error) { + var out []interface{} + err := _BridgeTransactionV2Harness.contract.Call(opts, &out, "destRecipient", encodedTx) + + if err != nil { + return *new(common.Address), err + } + + out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) + + return out0, err + +} + +// DestRecipient is a free data retrieval call binding the contract method 0x9c538802. +// +// Solidity: function destRecipient(bytes encodedTx) pure returns(address) +func (_BridgeTransactionV2Harness *BridgeTransactionV2HarnessSession) DestRecipient(encodedTx []byte) (common.Address, error) { + return _BridgeTransactionV2Harness.Contract.DestRecipient(&_BridgeTransactionV2Harness.CallOpts, encodedTx) +} + +// DestRecipient is a free data retrieval call binding the contract method 0x9c538802. +// +// Solidity: function destRecipient(bytes encodedTx) pure returns(address) +func (_BridgeTransactionV2Harness *BridgeTransactionV2HarnessCallerSession) DestRecipient(encodedTx []byte) (common.Address, error) { + return _BridgeTransactionV2Harness.Contract.DestRecipient(&_BridgeTransactionV2Harness.CallOpts, encodedTx) +} + +// DestToken is a free data retrieval call binding the contract method 0x37518e50. +// +// Solidity: function destToken(bytes encodedTx) pure returns(address) +func (_BridgeTransactionV2Harness *BridgeTransactionV2HarnessCaller) DestToken(opts *bind.CallOpts, encodedTx []byte) (common.Address, error) { + var out []interface{} + err := _BridgeTransactionV2Harness.contract.Call(opts, &out, "destToken", encodedTx) + + if err != nil { + return *new(common.Address), err + } + + out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) + + return out0, err + +} + +// DestToken is a free data retrieval call binding the contract method 0x37518e50. +// +// Solidity: function destToken(bytes encodedTx) pure returns(address) +func (_BridgeTransactionV2Harness *BridgeTransactionV2HarnessSession) DestToken(encodedTx []byte) (common.Address, error) { + return _BridgeTransactionV2Harness.Contract.DestToken(&_BridgeTransactionV2Harness.CallOpts, encodedTx) +} + +// DestToken is a free data retrieval call binding the contract method 0x37518e50. +// +// Solidity: function destToken(bytes encodedTx) pure returns(address) +func (_BridgeTransactionV2Harness *BridgeTransactionV2HarnessCallerSession) DestToken(encodedTx []byte) (common.Address, error) { + return _BridgeTransactionV2Harness.Contract.DestToken(&_BridgeTransactionV2Harness.CallOpts, encodedTx) +} + +// EncodeV2 is a free data retrieval call binding the contract method 0xfaef535a. +// +// Solidity: function encodeV2((uint32,uint32,address,address,address,address,uint256,uint256,uint256,uint256,uint256,address,uint256,uint256,bytes) bridgeTx) pure returns(bytes) +func (_BridgeTransactionV2Harness *BridgeTransactionV2HarnessCaller) EncodeV2(opts *bind.CallOpts, bridgeTx IFastBridgeV2BridgeTransactionV2) ([]byte, error) { + var out []interface{} + err := _BridgeTransactionV2Harness.contract.Call(opts, &out, "encodeV2", bridgeTx) + + if err != nil { + return *new([]byte), err + } + + out0 := *abi.ConvertType(out[0], new([]byte)).(*[]byte) + + return out0, err + +} + +// EncodeV2 is a free data retrieval call binding the contract method 0xfaef535a. +// +// Solidity: function encodeV2((uint32,uint32,address,address,address,address,uint256,uint256,uint256,uint256,uint256,address,uint256,uint256,bytes) bridgeTx) pure returns(bytes) +func (_BridgeTransactionV2Harness *BridgeTransactionV2HarnessSession) EncodeV2(bridgeTx IFastBridgeV2BridgeTransactionV2) ([]byte, error) { + return _BridgeTransactionV2Harness.Contract.EncodeV2(&_BridgeTransactionV2Harness.CallOpts, bridgeTx) +} + +// EncodeV2 is a free data retrieval call binding the contract method 0xfaef535a. +// +// Solidity: function encodeV2((uint32,uint32,address,address,address,address,uint256,uint256,uint256,uint256,uint256,address,uint256,uint256,bytes) bridgeTx) pure returns(bytes) +func (_BridgeTransactionV2Harness *BridgeTransactionV2HarnessCallerSession) EncodeV2(bridgeTx IFastBridgeV2BridgeTransactionV2) ([]byte, error) { + return _BridgeTransactionV2Harness.Contract.EncodeV2(&_BridgeTransactionV2Harness.CallOpts, bridgeTx) +} + +// ExclusivityEndTime is a free data retrieval call binding the contract method 0x6907efd7. +// +// Solidity: function exclusivityEndTime(bytes encodedTx) pure returns(uint256) +func (_BridgeTransactionV2Harness *BridgeTransactionV2HarnessCaller) ExclusivityEndTime(opts *bind.CallOpts, encodedTx []byte) (*big.Int, error) { + var out []interface{} + err := _BridgeTransactionV2Harness.contract.Call(opts, &out, "exclusivityEndTime", encodedTx) + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// ExclusivityEndTime is a free data retrieval call binding the contract method 0x6907efd7. +// +// Solidity: function exclusivityEndTime(bytes encodedTx) pure returns(uint256) +func (_BridgeTransactionV2Harness *BridgeTransactionV2HarnessSession) ExclusivityEndTime(encodedTx []byte) (*big.Int, error) { + return _BridgeTransactionV2Harness.Contract.ExclusivityEndTime(&_BridgeTransactionV2Harness.CallOpts, encodedTx) +} + +// ExclusivityEndTime is a free data retrieval call binding the contract method 0x6907efd7. +// +// Solidity: function exclusivityEndTime(bytes encodedTx) pure returns(uint256) +func (_BridgeTransactionV2Harness *BridgeTransactionV2HarnessCallerSession) ExclusivityEndTime(encodedTx []byte) (*big.Int, error) { + return _BridgeTransactionV2Harness.Contract.ExclusivityEndTime(&_BridgeTransactionV2Harness.CallOpts, encodedTx) +} + +// ExclusivityRelayer is a free data retrieval call binding the contract method 0xdcafa970. +// +// Solidity: function exclusivityRelayer(bytes encodedTx) pure returns(address) +func (_BridgeTransactionV2Harness *BridgeTransactionV2HarnessCaller) ExclusivityRelayer(opts *bind.CallOpts, encodedTx []byte) (common.Address, error) { + var out []interface{} + err := _BridgeTransactionV2Harness.contract.Call(opts, &out, "exclusivityRelayer", encodedTx) + + if err != nil { + return *new(common.Address), err + } + + out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) + + return out0, err + +} + +// ExclusivityRelayer is a free data retrieval call binding the contract method 0xdcafa970. +// +// Solidity: function exclusivityRelayer(bytes encodedTx) pure returns(address) +func (_BridgeTransactionV2Harness *BridgeTransactionV2HarnessSession) ExclusivityRelayer(encodedTx []byte) (common.Address, error) { + return _BridgeTransactionV2Harness.Contract.ExclusivityRelayer(&_BridgeTransactionV2Harness.CallOpts, encodedTx) +} + +// ExclusivityRelayer is a free data retrieval call binding the contract method 0xdcafa970. +// +// Solidity: function exclusivityRelayer(bytes encodedTx) pure returns(address) +func (_BridgeTransactionV2Harness *BridgeTransactionV2HarnessCallerSession) ExclusivityRelayer(encodedTx []byte) (common.Address, error) { + return _BridgeTransactionV2Harness.Contract.ExclusivityRelayer(&_BridgeTransactionV2Harness.CallOpts, encodedTx) +} + +// Nonce is a free data retrieval call binding the contract method 0x4e765004. +// +// Solidity: function nonce(bytes encodedTx) pure returns(uint256) +func (_BridgeTransactionV2Harness *BridgeTransactionV2HarnessCaller) Nonce(opts *bind.CallOpts, encodedTx []byte) (*big.Int, error) { + var out []interface{} + err := _BridgeTransactionV2Harness.contract.Call(opts, &out, "nonce", encodedTx) + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// Nonce is a free data retrieval call binding the contract method 0x4e765004. +// +// Solidity: function nonce(bytes encodedTx) pure returns(uint256) +func (_BridgeTransactionV2Harness *BridgeTransactionV2HarnessSession) Nonce(encodedTx []byte) (*big.Int, error) { + return _BridgeTransactionV2Harness.Contract.Nonce(&_BridgeTransactionV2Harness.CallOpts, encodedTx) +} + +// Nonce is a free data retrieval call binding the contract method 0x4e765004. +// +// Solidity: function nonce(bytes encodedTx) pure returns(uint256) +func (_BridgeTransactionV2Harness *BridgeTransactionV2HarnessCallerSession) Nonce(encodedTx []byte) (*big.Int, error) { + return _BridgeTransactionV2Harness.Contract.Nonce(&_BridgeTransactionV2Harness.CallOpts, encodedTx) +} + +// OriginAmount is a free data retrieval call binding the contract method 0x7241b9cb. +// +// Solidity: function originAmount(bytes encodedTx) pure returns(uint256) +func (_BridgeTransactionV2Harness *BridgeTransactionV2HarnessCaller) OriginAmount(opts *bind.CallOpts, encodedTx []byte) (*big.Int, error) { + var out []interface{} + err := _BridgeTransactionV2Harness.contract.Call(opts, &out, "originAmount", encodedTx) + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// OriginAmount is a free data retrieval call binding the contract method 0x7241b9cb. +// +// Solidity: function originAmount(bytes encodedTx) pure returns(uint256) +func (_BridgeTransactionV2Harness *BridgeTransactionV2HarnessSession) OriginAmount(encodedTx []byte) (*big.Int, error) { + return _BridgeTransactionV2Harness.Contract.OriginAmount(&_BridgeTransactionV2Harness.CallOpts, encodedTx) +} + +// OriginAmount is a free data retrieval call binding the contract method 0x7241b9cb. +// +// Solidity: function originAmount(bytes encodedTx) pure returns(uint256) +func (_BridgeTransactionV2Harness *BridgeTransactionV2HarnessCallerSession) OriginAmount(encodedTx []byte) (*big.Int, error) { + return _BridgeTransactionV2Harness.Contract.OriginAmount(&_BridgeTransactionV2Harness.CallOpts, encodedTx) +} + +// OriginChainId is a free data retrieval call binding the contract method 0x93bb0d80. +// +// Solidity: function originChainId(bytes encodedTx) pure returns(uint32) +func (_BridgeTransactionV2Harness *BridgeTransactionV2HarnessCaller) OriginChainId(opts *bind.CallOpts, encodedTx []byte) (uint32, error) { + var out []interface{} + err := _BridgeTransactionV2Harness.contract.Call(opts, &out, "originChainId", encodedTx) + + if err != nil { + return *new(uint32), err + } + + out0 := *abi.ConvertType(out[0], new(uint32)).(*uint32) + + return out0, err + +} + +// OriginChainId is a free data retrieval call binding the contract method 0x93bb0d80. +// +// Solidity: function originChainId(bytes encodedTx) pure returns(uint32) +func (_BridgeTransactionV2Harness *BridgeTransactionV2HarnessSession) OriginChainId(encodedTx []byte) (uint32, error) { + return _BridgeTransactionV2Harness.Contract.OriginChainId(&_BridgeTransactionV2Harness.CallOpts, encodedTx) +} + +// OriginChainId is a free data retrieval call binding the contract method 0x93bb0d80. +// +// Solidity: function originChainId(bytes encodedTx) pure returns(uint32) +func (_BridgeTransactionV2Harness *BridgeTransactionV2HarnessCallerSession) OriginChainId(encodedTx []byte) (uint32, error) { + return _BridgeTransactionV2Harness.Contract.OriginChainId(&_BridgeTransactionV2Harness.CallOpts, encodedTx) +} + +// OriginFeeAmount is a free data retrieval call binding the contract method 0xe938730e. +// +// Solidity: function originFeeAmount(bytes encodedTx) pure returns(uint256) +func (_BridgeTransactionV2Harness *BridgeTransactionV2HarnessCaller) OriginFeeAmount(opts *bind.CallOpts, encodedTx []byte) (*big.Int, error) { + var out []interface{} + err := _BridgeTransactionV2Harness.contract.Call(opts, &out, "originFeeAmount", encodedTx) + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// OriginFeeAmount is a free data retrieval call binding the contract method 0xe938730e. +// +// Solidity: function originFeeAmount(bytes encodedTx) pure returns(uint256) +func (_BridgeTransactionV2Harness *BridgeTransactionV2HarnessSession) OriginFeeAmount(encodedTx []byte) (*big.Int, error) { + return _BridgeTransactionV2Harness.Contract.OriginFeeAmount(&_BridgeTransactionV2Harness.CallOpts, encodedTx) +} + +// OriginFeeAmount is a free data retrieval call binding the contract method 0xe938730e. +// +// Solidity: function originFeeAmount(bytes encodedTx) pure returns(uint256) +func (_BridgeTransactionV2Harness *BridgeTransactionV2HarnessCallerSession) OriginFeeAmount(encodedTx []byte) (*big.Int, error) { + return _BridgeTransactionV2Harness.Contract.OriginFeeAmount(&_BridgeTransactionV2Harness.CallOpts, encodedTx) +} + +// OriginSender is a free data retrieval call binding the contract method 0x9bdb46fe. +// +// Solidity: function originSender(bytes encodedTx) pure returns(address) +func (_BridgeTransactionV2Harness *BridgeTransactionV2HarnessCaller) OriginSender(opts *bind.CallOpts, encodedTx []byte) (common.Address, error) { + var out []interface{} + err := _BridgeTransactionV2Harness.contract.Call(opts, &out, "originSender", encodedTx) + + if err != nil { + return *new(common.Address), err + } + + out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) + + return out0, err + +} + +// OriginSender is a free data retrieval call binding the contract method 0x9bdb46fe. +// +// Solidity: function originSender(bytes encodedTx) pure returns(address) +func (_BridgeTransactionV2Harness *BridgeTransactionV2HarnessSession) OriginSender(encodedTx []byte) (common.Address, error) { + return _BridgeTransactionV2Harness.Contract.OriginSender(&_BridgeTransactionV2Harness.CallOpts, encodedTx) +} + +// OriginSender is a free data retrieval call binding the contract method 0x9bdb46fe. +// +// Solidity: function originSender(bytes encodedTx) pure returns(address) +func (_BridgeTransactionV2Harness *BridgeTransactionV2HarnessCallerSession) OriginSender(encodedTx []byte) (common.Address, error) { + return _BridgeTransactionV2Harness.Contract.OriginSender(&_BridgeTransactionV2Harness.CallOpts, encodedTx) +} + +// OriginToken is a free data retrieval call binding the contract method 0x93832899. +// +// Solidity: function originToken(bytes encodedTx) pure returns(address) +func (_BridgeTransactionV2Harness *BridgeTransactionV2HarnessCaller) OriginToken(opts *bind.CallOpts, encodedTx []byte) (common.Address, error) { + var out []interface{} + err := _BridgeTransactionV2Harness.contract.Call(opts, &out, "originToken", encodedTx) + + if err != nil { + return *new(common.Address), err + } + + out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) + + return out0, err + +} + +// OriginToken is a free data retrieval call binding the contract method 0x93832899. +// +// Solidity: function originToken(bytes encodedTx) pure returns(address) +func (_BridgeTransactionV2Harness *BridgeTransactionV2HarnessSession) OriginToken(encodedTx []byte) (common.Address, error) { + return _BridgeTransactionV2Harness.Contract.OriginToken(&_BridgeTransactionV2Harness.CallOpts, encodedTx) +} + +// OriginToken is a free data retrieval call binding the contract method 0x93832899. +// +// Solidity: function originToken(bytes encodedTx) pure returns(address) +func (_BridgeTransactionV2Harness *BridgeTransactionV2HarnessCallerSession) OriginToken(encodedTx []byte) (common.Address, error) { + return _BridgeTransactionV2Harness.Contract.OriginToken(&_BridgeTransactionV2Harness.CallOpts, encodedTx) +} + +// Version is a free data retrieval call binding the contract method 0x7d67c5a7. +// +// Solidity: function version(bytes encodedTx) pure returns(uint16) +func (_BridgeTransactionV2Harness *BridgeTransactionV2HarnessCaller) Version(opts *bind.CallOpts, encodedTx []byte) (uint16, error) { + var out []interface{} + err := _BridgeTransactionV2Harness.contract.Call(opts, &out, "version", encodedTx) + + if err != nil { + return *new(uint16), err + } + + out0 := *abi.ConvertType(out[0], new(uint16)).(*uint16) + + return out0, err + +} + +// Version is a free data retrieval call binding the contract method 0x7d67c5a7. +// +// Solidity: function version(bytes encodedTx) pure returns(uint16) +func (_BridgeTransactionV2Harness *BridgeTransactionV2HarnessSession) Version(encodedTx []byte) (uint16, error) { + return _BridgeTransactionV2Harness.Contract.Version(&_BridgeTransactionV2Harness.CallOpts, encodedTx) +} + +// Version is a free data retrieval call binding the contract method 0x7d67c5a7. +// +// Solidity: function version(bytes encodedTx) pure returns(uint16) +func (_BridgeTransactionV2Harness *BridgeTransactionV2HarnessCallerSession) Version(encodedTx []byte) (uint16, error) { + return _BridgeTransactionV2Harness.Contract.Version(&_BridgeTransactionV2Harness.CallOpts, encodedTx) +} + +// ZapData is a free data retrieval call binding the contract method 0x0af3f403. +// +// Solidity: function zapData(bytes encodedTx) pure returns(bytes) +func (_BridgeTransactionV2Harness *BridgeTransactionV2HarnessCaller) ZapData(opts *bind.CallOpts, encodedTx []byte) ([]byte, error) { + var out []interface{} + err := _BridgeTransactionV2Harness.contract.Call(opts, &out, "zapData", encodedTx) + + if err != nil { + return *new([]byte), err + } + + out0 := *abi.ConvertType(out[0], new([]byte)).(*[]byte) + + return out0, err + +} + +// ZapData is a free data retrieval call binding the contract method 0x0af3f403. +// +// Solidity: function zapData(bytes encodedTx) pure returns(bytes) +func (_BridgeTransactionV2Harness *BridgeTransactionV2HarnessSession) ZapData(encodedTx []byte) ([]byte, error) { + return _BridgeTransactionV2Harness.Contract.ZapData(&_BridgeTransactionV2Harness.CallOpts, encodedTx) +} + +// ZapData is a free data retrieval call binding the contract method 0x0af3f403. +// +// Solidity: function zapData(bytes encodedTx) pure returns(bytes) +func (_BridgeTransactionV2Harness *BridgeTransactionV2HarnessCallerSession) ZapData(encodedTx []byte) ([]byte, error) { + return _BridgeTransactionV2Harness.Contract.ZapData(&_BridgeTransactionV2Harness.CallOpts, encodedTx) +} + +// ZapNative is a free data retrieval call binding the contract method 0x230602c1. +// +// Solidity: function zapNative(bytes encodedTx) pure returns(uint256) +func (_BridgeTransactionV2Harness *BridgeTransactionV2HarnessCaller) ZapNative(opts *bind.CallOpts, encodedTx []byte) (*big.Int, error) { + var out []interface{} + err := _BridgeTransactionV2Harness.contract.Call(opts, &out, "zapNative", encodedTx) + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// ZapNative is a free data retrieval call binding the contract method 0x230602c1. +// +// Solidity: function zapNative(bytes encodedTx) pure returns(uint256) +func (_BridgeTransactionV2Harness *BridgeTransactionV2HarnessSession) ZapNative(encodedTx []byte) (*big.Int, error) { + return _BridgeTransactionV2Harness.Contract.ZapNative(&_BridgeTransactionV2Harness.CallOpts, encodedTx) +} + +// ZapNative is a free data retrieval call binding the contract method 0x230602c1. +// +// Solidity: function zapNative(bytes encodedTx) pure returns(uint256) +func (_BridgeTransactionV2Harness *BridgeTransactionV2HarnessCallerSession) ZapNative(encodedTx []byte) (*big.Int, error) { + return _BridgeTransactionV2Harness.Contract.ZapNative(&_BridgeTransactionV2Harness.CallOpts, encodedTx) +} + +// BridgeTransactionV2LibMetaData contains all meta data concerning the BridgeTransactionV2Lib contract. +var BridgeTransactionV2LibMetaData = &bind.MetaData{ + ABI: "[{\"inputs\":[],\"name\":\"BridgeTransactionV2__InvalidEncodedTx\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint16\",\"name\":\"version\",\"type\":\"uint16\"}],\"name\":\"BridgeTransactionV2__UnsupportedVersion\",\"type\":\"error\"}]", + Bin: "0x60566037600b82828239805160001a607314602a57634e487b7160e01b600052600060045260246000fd5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600080fdfea2646970667358221220da262e011b1740fc866d94ce46470fa9e1d5daf267ae4e8119df1dcd7edab25964736f6c63430008180033", +} + +// BridgeTransactionV2LibABI is the input ABI used to generate the binding from. +// Deprecated: Use BridgeTransactionV2LibMetaData.ABI instead. +var BridgeTransactionV2LibABI = BridgeTransactionV2LibMetaData.ABI + +// BridgeTransactionV2LibBin is the compiled bytecode used for deploying new contracts. +// Deprecated: Use BridgeTransactionV2LibMetaData.Bin instead. +var BridgeTransactionV2LibBin = BridgeTransactionV2LibMetaData.Bin + +// DeployBridgeTransactionV2Lib deploys a new Ethereum contract, binding an instance of BridgeTransactionV2Lib to it. +func DeployBridgeTransactionV2Lib(auth *bind.TransactOpts, backend bind.ContractBackend) (common.Address, *types.Transaction, *BridgeTransactionV2Lib, error) { + parsed, err := BridgeTransactionV2LibMetaData.GetAbi() + if err != nil { + return common.Address{}, nil, nil, err + } + if parsed == nil { + return common.Address{}, nil, nil, errors.New("GetABI returned nil") + } + + address, tx, contract, err := bind.DeployContract(auth, *parsed, common.FromHex(BridgeTransactionV2LibBin), backend) + if err != nil { + return common.Address{}, nil, nil, err + } + return address, tx, &BridgeTransactionV2Lib{BridgeTransactionV2LibCaller: BridgeTransactionV2LibCaller{contract: contract}, BridgeTransactionV2LibTransactor: BridgeTransactionV2LibTransactor{contract: contract}, BridgeTransactionV2LibFilterer: BridgeTransactionV2LibFilterer{contract: contract}}, nil +} + +// BridgeTransactionV2Lib is an auto generated Go binding around an Ethereum contract. +type BridgeTransactionV2Lib struct { + BridgeTransactionV2LibCaller // Read-only binding to the contract + BridgeTransactionV2LibTransactor // Write-only binding to the contract + BridgeTransactionV2LibFilterer // Log filterer for contract events +} + +// BridgeTransactionV2LibCaller is an auto generated read-only Go binding around an Ethereum contract. +type BridgeTransactionV2LibCaller struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// BridgeTransactionV2LibTransactor is an auto generated write-only Go binding around an Ethereum contract. +type BridgeTransactionV2LibTransactor struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// BridgeTransactionV2LibFilterer is an auto generated log filtering Go binding around an Ethereum contract events. +type BridgeTransactionV2LibFilterer struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// BridgeTransactionV2LibSession is an auto generated Go binding around an Ethereum contract, +// with pre-set call and transact options. +type BridgeTransactionV2LibSession struct { + Contract *BridgeTransactionV2Lib // Generic contract binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// BridgeTransactionV2LibCallerSession is an auto generated read-only Go binding around an Ethereum contract, +// with pre-set call options. +type BridgeTransactionV2LibCallerSession struct { + Contract *BridgeTransactionV2LibCaller // Generic contract caller binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session +} + +// BridgeTransactionV2LibTransactorSession is an auto generated write-only Go binding around an Ethereum contract, +// with pre-set transact options. +type BridgeTransactionV2LibTransactorSession struct { + Contract *BridgeTransactionV2LibTransactor // Generic contract transactor binding to set the session for + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// BridgeTransactionV2LibRaw is an auto generated low-level Go binding around an Ethereum contract. +type BridgeTransactionV2LibRaw struct { + Contract *BridgeTransactionV2Lib // Generic contract binding to access the raw methods on +} + +// BridgeTransactionV2LibCallerRaw is an auto generated low-level read-only Go binding around an Ethereum contract. +type BridgeTransactionV2LibCallerRaw struct { + Contract *BridgeTransactionV2LibCaller // Generic read-only contract binding to access the raw methods on +} + +// BridgeTransactionV2LibTransactorRaw is an auto generated low-level write-only Go binding around an Ethereum contract. +type BridgeTransactionV2LibTransactorRaw struct { + Contract *BridgeTransactionV2LibTransactor // Generic write-only contract binding to access the raw methods on +} + +// NewBridgeTransactionV2Lib creates a new instance of BridgeTransactionV2Lib, bound to a specific deployed contract. +func NewBridgeTransactionV2Lib(address common.Address, backend bind.ContractBackend) (*BridgeTransactionV2Lib, error) { + contract, err := bindBridgeTransactionV2Lib(address, backend, backend, backend) + if err != nil { + return nil, err + } + return &BridgeTransactionV2Lib{BridgeTransactionV2LibCaller: BridgeTransactionV2LibCaller{contract: contract}, BridgeTransactionV2LibTransactor: BridgeTransactionV2LibTransactor{contract: contract}, BridgeTransactionV2LibFilterer: BridgeTransactionV2LibFilterer{contract: contract}}, nil +} + +// NewBridgeTransactionV2LibCaller creates a new read-only instance of BridgeTransactionV2Lib, bound to a specific deployed contract. +func NewBridgeTransactionV2LibCaller(address common.Address, caller bind.ContractCaller) (*BridgeTransactionV2LibCaller, error) { + contract, err := bindBridgeTransactionV2Lib(address, caller, nil, nil) + if err != nil { + return nil, err + } + return &BridgeTransactionV2LibCaller{contract: contract}, nil +} + +// NewBridgeTransactionV2LibTransactor creates a new write-only instance of BridgeTransactionV2Lib, bound to a specific deployed contract. +func NewBridgeTransactionV2LibTransactor(address common.Address, transactor bind.ContractTransactor) (*BridgeTransactionV2LibTransactor, error) { + contract, err := bindBridgeTransactionV2Lib(address, nil, transactor, nil) + if err != nil { + return nil, err + } + return &BridgeTransactionV2LibTransactor{contract: contract}, nil +} + +// NewBridgeTransactionV2LibFilterer creates a new log filterer instance of BridgeTransactionV2Lib, bound to a specific deployed contract. +func NewBridgeTransactionV2LibFilterer(address common.Address, filterer bind.ContractFilterer) (*BridgeTransactionV2LibFilterer, error) { + contract, err := bindBridgeTransactionV2Lib(address, nil, nil, filterer) + if err != nil { + return nil, err + } + return &BridgeTransactionV2LibFilterer{contract: contract}, nil +} + +// bindBridgeTransactionV2Lib binds a generic wrapper to an already deployed contract. +func bindBridgeTransactionV2Lib(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) { + parsed, err := BridgeTransactionV2LibMetaData.GetAbi() + if err != nil { + return nil, err + } + return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil +} + +// Call invokes the (constant) contract method with params as input values and +// sets the output to result. The result type might be a single field for simple +// returns, a slice of interfaces for anonymous returns and a struct for named +// returns. +func (_BridgeTransactionV2Lib *BridgeTransactionV2LibRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _BridgeTransactionV2Lib.Contract.BridgeTransactionV2LibCaller.contract.Call(opts, result, method, params...) +} + +// Transfer initiates a plain transaction to move funds to the contract, calling +// its default method if one is available. +func (_BridgeTransactionV2Lib *BridgeTransactionV2LibRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _BridgeTransactionV2Lib.Contract.BridgeTransactionV2LibTransactor.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_BridgeTransactionV2Lib *BridgeTransactionV2LibRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _BridgeTransactionV2Lib.Contract.BridgeTransactionV2LibTransactor.contract.Transact(opts, method, params...) +} + +// Call invokes the (constant) contract method with params as input values and +// sets the output to result. The result type might be a single field for simple +// returns, a slice of interfaces for anonymous returns and a struct for named +// returns. +func (_BridgeTransactionV2Lib *BridgeTransactionV2LibCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _BridgeTransactionV2Lib.Contract.contract.Call(opts, result, method, params...) +} + +// Transfer initiates a plain transaction to move funds to the contract, calling +// its default method if one is available. +func (_BridgeTransactionV2Lib *BridgeTransactionV2LibTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _BridgeTransactionV2Lib.Contract.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_BridgeTransactionV2Lib *BridgeTransactionV2LibTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _BridgeTransactionV2Lib.Contract.contract.Transact(opts, method, params...) +} + +// IFastBridgeMetaData contains all meta data concerning the IFastBridge contract. +var IFastBridgeMetaData = &bind.MetaData{ + ABI: "[{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"BridgeDepositClaimed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"BridgeDepositRefunded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"name\":\"BridgeProofDisputed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"transactionHash\",\"type\":\"bytes32\"}],\"name\":\"BridgeProofProvided\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"originChainId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"chainGasAmount\",\"type\":\"uint256\"}],\"name\":\"BridgeRelayed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"destChainId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"sendChainGas\",\"type\":\"bool\"}],\"name\":\"BridgeRequested\",\"type\":\"event\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"dstChainId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"sendChainGas\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"}],\"internalType\":\"structIFastBridge.BridgeParams\",\"name\":\"params\",\"type\":\"tuple\"}],\"name\":\"bridge\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"name\":\"canClaim\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"claim\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"}],\"name\":\"dispute\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"getBridgeTransaction\",\"outputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"originChainId\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"destChainId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"originSender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destRecipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"originFeeAmount\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"sendChainGas\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"}],\"internalType\":\"structIFastBridge.BridgeTransaction\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"},{\"internalType\":\"bytes32\",\"name\":\"destTxHash\",\"type\":\"bytes32\"}],\"name\":\"prove\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"refund\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"relay\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"}]", + Sigs: map[string]string{ + "45851694": "bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256))", + "aa9641ab": "canClaim(bytes32,address)", + "41fcb612": "claim(bytes,address)", + "add98c70": "dispute(bytes32)", + "ac11fb1a": "getBridgeTransaction(bytes)", + "886d36ff": "prove(bytes,bytes32)", + "5eb7d946": "refund(bytes)", + "8f0d6f17": "relay(bytes)", + }, +} + +// IFastBridgeABI is the input ABI used to generate the binding from. +// Deprecated: Use IFastBridgeMetaData.ABI instead. +var IFastBridgeABI = IFastBridgeMetaData.ABI + +// Deprecated: Use IFastBridgeMetaData.Sigs instead. +// IFastBridgeFuncSigs maps the 4-byte function signature to its string representation. +var IFastBridgeFuncSigs = IFastBridgeMetaData.Sigs + +// IFastBridge is an auto generated Go binding around an Ethereum contract. +type IFastBridge struct { + IFastBridgeCaller // Read-only binding to the contract + IFastBridgeTransactor // Write-only binding to the contract + IFastBridgeFilterer // Log filterer for contract events +} + +// IFastBridgeCaller is an auto generated read-only Go binding around an Ethereum contract. +type IFastBridgeCaller struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// IFastBridgeTransactor is an auto generated write-only Go binding around an Ethereum contract. +type IFastBridgeTransactor struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// IFastBridgeFilterer is an auto generated log filtering Go binding around an Ethereum contract events. +type IFastBridgeFilterer struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// IFastBridgeSession is an auto generated Go binding around an Ethereum contract, +// with pre-set call and transact options. +type IFastBridgeSession struct { + Contract *IFastBridge // Generic contract binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// IFastBridgeCallerSession is an auto generated read-only Go binding around an Ethereum contract, +// with pre-set call options. +type IFastBridgeCallerSession struct { + Contract *IFastBridgeCaller // Generic contract caller binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session +} + +// IFastBridgeTransactorSession is an auto generated write-only Go binding around an Ethereum contract, +// with pre-set transact options. +type IFastBridgeTransactorSession struct { + Contract *IFastBridgeTransactor // Generic contract transactor binding to set the session for + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// IFastBridgeRaw is an auto generated low-level Go binding around an Ethereum contract. +type IFastBridgeRaw struct { + Contract *IFastBridge // Generic contract binding to access the raw methods on +} + +// IFastBridgeCallerRaw is an auto generated low-level read-only Go binding around an Ethereum contract. +type IFastBridgeCallerRaw struct { + Contract *IFastBridgeCaller // Generic read-only contract binding to access the raw methods on +} + +// IFastBridgeTransactorRaw is an auto generated low-level write-only Go binding around an Ethereum contract. +type IFastBridgeTransactorRaw struct { + Contract *IFastBridgeTransactor // Generic write-only contract binding to access the raw methods on +} + +// NewIFastBridge creates a new instance of IFastBridge, bound to a specific deployed contract. +func NewIFastBridge(address common.Address, backend bind.ContractBackend) (*IFastBridge, error) { + contract, err := bindIFastBridge(address, backend, backend, backend) + if err != nil { + return nil, err + } + return &IFastBridge{IFastBridgeCaller: IFastBridgeCaller{contract: contract}, IFastBridgeTransactor: IFastBridgeTransactor{contract: contract}, IFastBridgeFilterer: IFastBridgeFilterer{contract: contract}}, nil +} + +// NewIFastBridgeCaller creates a new read-only instance of IFastBridge, bound to a specific deployed contract. +func NewIFastBridgeCaller(address common.Address, caller bind.ContractCaller) (*IFastBridgeCaller, error) { + contract, err := bindIFastBridge(address, caller, nil, nil) + if err != nil { + return nil, err + } + return &IFastBridgeCaller{contract: contract}, nil +} + +// NewIFastBridgeTransactor creates a new write-only instance of IFastBridge, bound to a specific deployed contract. +func NewIFastBridgeTransactor(address common.Address, transactor bind.ContractTransactor) (*IFastBridgeTransactor, error) { + contract, err := bindIFastBridge(address, nil, transactor, nil) + if err != nil { + return nil, err + } + return &IFastBridgeTransactor{contract: contract}, nil +} + +// NewIFastBridgeFilterer creates a new log filterer instance of IFastBridge, bound to a specific deployed contract. +func NewIFastBridgeFilterer(address common.Address, filterer bind.ContractFilterer) (*IFastBridgeFilterer, error) { + contract, err := bindIFastBridge(address, nil, nil, filterer) + if err != nil { + return nil, err + } + return &IFastBridgeFilterer{contract: contract}, nil +} + +// bindIFastBridge binds a generic wrapper to an already deployed contract. +func bindIFastBridge(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) { + parsed, err := IFastBridgeMetaData.GetAbi() + if err != nil { + return nil, err + } + return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil +} + +// Call invokes the (constant) contract method with params as input values and +// sets the output to result. The result type might be a single field for simple +// returns, a slice of interfaces for anonymous returns and a struct for named +// returns. +func (_IFastBridge *IFastBridgeRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _IFastBridge.Contract.IFastBridgeCaller.contract.Call(opts, result, method, params...) +} + +// Transfer initiates a plain transaction to move funds to the contract, calling +// its default method if one is available. +func (_IFastBridge *IFastBridgeRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _IFastBridge.Contract.IFastBridgeTransactor.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_IFastBridge *IFastBridgeRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _IFastBridge.Contract.IFastBridgeTransactor.contract.Transact(opts, method, params...) +} + +// Call invokes the (constant) contract method with params as input values and +// sets the output to result. The result type might be a single field for simple +// returns, a slice of interfaces for anonymous returns and a struct for named +// returns. +func (_IFastBridge *IFastBridgeCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _IFastBridge.Contract.contract.Call(opts, result, method, params...) +} + +// Transfer initiates a plain transaction to move funds to the contract, calling +// its default method if one is available. +func (_IFastBridge *IFastBridgeTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _IFastBridge.Contract.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_IFastBridge *IFastBridgeTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _IFastBridge.Contract.contract.Transact(opts, method, params...) +} + +// CanClaim is a free data retrieval call binding the contract method 0xaa9641ab. +// +// Solidity: function canClaim(bytes32 transactionId, address relayer) view returns(bool) +func (_IFastBridge *IFastBridgeCaller) CanClaim(opts *bind.CallOpts, transactionId [32]byte, relayer common.Address) (bool, error) { + var out []interface{} + err := _IFastBridge.contract.Call(opts, &out, "canClaim", transactionId, relayer) + + if err != nil { + return *new(bool), err + } + + out0 := *abi.ConvertType(out[0], new(bool)).(*bool) + + return out0, err + +} + +// CanClaim is a free data retrieval call binding the contract method 0xaa9641ab. +// +// Solidity: function canClaim(bytes32 transactionId, address relayer) view returns(bool) +func (_IFastBridge *IFastBridgeSession) CanClaim(transactionId [32]byte, relayer common.Address) (bool, error) { + return _IFastBridge.Contract.CanClaim(&_IFastBridge.CallOpts, transactionId, relayer) +} + +// CanClaim is a free data retrieval call binding the contract method 0xaa9641ab. +// +// Solidity: function canClaim(bytes32 transactionId, address relayer) view returns(bool) +func (_IFastBridge *IFastBridgeCallerSession) CanClaim(transactionId [32]byte, relayer common.Address) (bool, error) { + return _IFastBridge.Contract.CanClaim(&_IFastBridge.CallOpts, transactionId, relayer) +} + +// GetBridgeTransaction is a free data retrieval call binding the contract method 0xac11fb1a. +// +// Solidity: function getBridgeTransaction(bytes request) view returns((uint32,uint32,address,address,address,address,uint256,uint256,uint256,bool,uint256,uint256)) +func (_IFastBridge *IFastBridgeCaller) GetBridgeTransaction(opts *bind.CallOpts, request []byte) (IFastBridgeBridgeTransaction, error) { + var out []interface{} + err := _IFastBridge.contract.Call(opts, &out, "getBridgeTransaction", request) + + if err != nil { + return *new(IFastBridgeBridgeTransaction), err + } + + out0 := *abi.ConvertType(out[0], new(IFastBridgeBridgeTransaction)).(*IFastBridgeBridgeTransaction) + + return out0, err + +} + +// GetBridgeTransaction is a free data retrieval call binding the contract method 0xac11fb1a. +// +// Solidity: function getBridgeTransaction(bytes request) view returns((uint32,uint32,address,address,address,address,uint256,uint256,uint256,bool,uint256,uint256)) +func (_IFastBridge *IFastBridgeSession) GetBridgeTransaction(request []byte) (IFastBridgeBridgeTransaction, error) { + return _IFastBridge.Contract.GetBridgeTransaction(&_IFastBridge.CallOpts, request) +} + +// GetBridgeTransaction is a free data retrieval call binding the contract method 0xac11fb1a. +// +// Solidity: function getBridgeTransaction(bytes request) view returns((uint32,uint32,address,address,address,address,uint256,uint256,uint256,bool,uint256,uint256)) +func (_IFastBridge *IFastBridgeCallerSession) GetBridgeTransaction(request []byte) (IFastBridgeBridgeTransaction, error) { + return _IFastBridge.Contract.GetBridgeTransaction(&_IFastBridge.CallOpts, request) +} + +// Bridge is a paid mutator transaction binding the contract method 0x45851694. +// +// Solidity: function bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256) params) payable returns() +func (_IFastBridge *IFastBridgeTransactor) Bridge(opts *bind.TransactOpts, params IFastBridgeBridgeParams) (*types.Transaction, error) { + return _IFastBridge.contract.Transact(opts, "bridge", params) +} + +// Bridge is a paid mutator transaction binding the contract method 0x45851694. +// +// Solidity: function bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256) params) payable returns() +func (_IFastBridge *IFastBridgeSession) Bridge(params IFastBridgeBridgeParams) (*types.Transaction, error) { + return _IFastBridge.Contract.Bridge(&_IFastBridge.TransactOpts, params) +} + +// Bridge is a paid mutator transaction binding the contract method 0x45851694. +// +// Solidity: function bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256) params) payable returns() +func (_IFastBridge *IFastBridgeTransactorSession) Bridge(params IFastBridgeBridgeParams) (*types.Transaction, error) { + return _IFastBridge.Contract.Bridge(&_IFastBridge.TransactOpts, params) +} + +// Claim is a paid mutator transaction binding the contract method 0x41fcb612. +// +// Solidity: function claim(bytes request, address to) returns() +func (_IFastBridge *IFastBridgeTransactor) Claim(opts *bind.TransactOpts, request []byte, to common.Address) (*types.Transaction, error) { + return _IFastBridge.contract.Transact(opts, "claim", request, to) +} + +// Claim is a paid mutator transaction binding the contract method 0x41fcb612. +// +// Solidity: function claim(bytes request, address to) returns() +func (_IFastBridge *IFastBridgeSession) Claim(request []byte, to common.Address) (*types.Transaction, error) { + return _IFastBridge.Contract.Claim(&_IFastBridge.TransactOpts, request, to) +} + +// Claim is a paid mutator transaction binding the contract method 0x41fcb612. +// +// Solidity: function claim(bytes request, address to) returns() +func (_IFastBridge *IFastBridgeTransactorSession) Claim(request []byte, to common.Address) (*types.Transaction, error) { + return _IFastBridge.Contract.Claim(&_IFastBridge.TransactOpts, request, to) +} + +// Dispute is a paid mutator transaction binding the contract method 0xadd98c70. +// +// Solidity: function dispute(bytes32 transactionId) returns() +func (_IFastBridge *IFastBridgeTransactor) Dispute(opts *bind.TransactOpts, transactionId [32]byte) (*types.Transaction, error) { + return _IFastBridge.contract.Transact(opts, "dispute", transactionId) +} + +// Dispute is a paid mutator transaction binding the contract method 0xadd98c70. +// +// Solidity: function dispute(bytes32 transactionId) returns() +func (_IFastBridge *IFastBridgeSession) Dispute(transactionId [32]byte) (*types.Transaction, error) { + return _IFastBridge.Contract.Dispute(&_IFastBridge.TransactOpts, transactionId) +} + +// Dispute is a paid mutator transaction binding the contract method 0xadd98c70. +// +// Solidity: function dispute(bytes32 transactionId) returns() +func (_IFastBridge *IFastBridgeTransactorSession) Dispute(transactionId [32]byte) (*types.Transaction, error) { + return _IFastBridge.Contract.Dispute(&_IFastBridge.TransactOpts, transactionId) +} + +// Prove is a paid mutator transaction binding the contract method 0x886d36ff. +// +// Solidity: function prove(bytes request, bytes32 destTxHash) returns() +func (_IFastBridge *IFastBridgeTransactor) Prove(opts *bind.TransactOpts, request []byte, destTxHash [32]byte) (*types.Transaction, error) { + return _IFastBridge.contract.Transact(opts, "prove", request, destTxHash) +} + +// Prove is a paid mutator transaction binding the contract method 0x886d36ff. +// +// Solidity: function prove(bytes request, bytes32 destTxHash) returns() +func (_IFastBridge *IFastBridgeSession) Prove(request []byte, destTxHash [32]byte) (*types.Transaction, error) { + return _IFastBridge.Contract.Prove(&_IFastBridge.TransactOpts, request, destTxHash) +} + +// Prove is a paid mutator transaction binding the contract method 0x886d36ff. +// +// Solidity: function prove(bytes request, bytes32 destTxHash) returns() +func (_IFastBridge *IFastBridgeTransactorSession) Prove(request []byte, destTxHash [32]byte) (*types.Transaction, error) { + return _IFastBridge.Contract.Prove(&_IFastBridge.TransactOpts, request, destTxHash) +} + +// Refund is a paid mutator transaction binding the contract method 0x5eb7d946. +// +// Solidity: function refund(bytes request) returns() +func (_IFastBridge *IFastBridgeTransactor) Refund(opts *bind.TransactOpts, request []byte) (*types.Transaction, error) { + return _IFastBridge.contract.Transact(opts, "refund", request) +} + +// Refund is a paid mutator transaction binding the contract method 0x5eb7d946. +// +// Solidity: function refund(bytes request) returns() +func (_IFastBridge *IFastBridgeSession) Refund(request []byte) (*types.Transaction, error) { + return _IFastBridge.Contract.Refund(&_IFastBridge.TransactOpts, request) +} + +// Refund is a paid mutator transaction binding the contract method 0x5eb7d946. +// +// Solidity: function refund(bytes request) returns() +func (_IFastBridge *IFastBridgeTransactorSession) Refund(request []byte) (*types.Transaction, error) { + return _IFastBridge.Contract.Refund(&_IFastBridge.TransactOpts, request) +} + +// Relay is a paid mutator transaction binding the contract method 0x8f0d6f17. +// +// Solidity: function relay(bytes request) payable returns() +func (_IFastBridge *IFastBridgeTransactor) Relay(opts *bind.TransactOpts, request []byte) (*types.Transaction, error) { + return _IFastBridge.contract.Transact(opts, "relay", request) +} + +// Relay is a paid mutator transaction binding the contract method 0x8f0d6f17. +// +// Solidity: function relay(bytes request) payable returns() +func (_IFastBridge *IFastBridgeSession) Relay(request []byte) (*types.Transaction, error) { + return _IFastBridge.Contract.Relay(&_IFastBridge.TransactOpts, request) +} + +// Relay is a paid mutator transaction binding the contract method 0x8f0d6f17. +// +// Solidity: function relay(bytes request) payable returns() +func (_IFastBridge *IFastBridgeTransactorSession) Relay(request []byte) (*types.Transaction, error) { + return _IFastBridge.Contract.Relay(&_IFastBridge.TransactOpts, request) +} + +// IFastBridgeBridgeDepositClaimedIterator is returned from FilterBridgeDepositClaimed and is used to iterate over the raw logs and unpacked data for BridgeDepositClaimed events raised by the IFastBridge contract. +type IFastBridgeBridgeDepositClaimedIterator struct { + Event *IFastBridgeBridgeDepositClaimed // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *IFastBridgeBridgeDepositClaimedIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(IFastBridgeBridgeDepositClaimed) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(IFastBridgeBridgeDepositClaimed) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *IFastBridgeBridgeDepositClaimedIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *IFastBridgeBridgeDepositClaimedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// IFastBridgeBridgeDepositClaimed represents a BridgeDepositClaimed event raised by the IFastBridge contract. +type IFastBridgeBridgeDepositClaimed struct { + TransactionId [32]byte + Relayer common.Address + To common.Address + Token common.Address + Amount *big.Int + Raw types.Log // Blockchain specific contextual infos +} + +// FilterBridgeDepositClaimed is a free log retrieval operation binding the contract event 0x582211c35a2139ac3bbaac74663c6a1f56c6cbb658b41fe11fd45a82074ac678. +// +// Solidity: event BridgeDepositClaimed(bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount) +func (_IFastBridge *IFastBridgeFilterer) FilterBridgeDepositClaimed(opts *bind.FilterOpts, transactionId [][32]byte, relayer []common.Address, to []common.Address) (*IFastBridgeBridgeDepositClaimedIterator, error) { + + var transactionIdRule []interface{} + for _, transactionIdItem := range transactionId { + transactionIdRule = append(transactionIdRule, transactionIdItem) + } + var relayerRule []interface{} + for _, relayerItem := range relayer { + relayerRule = append(relayerRule, relayerItem) + } + var toRule []interface{} + for _, toItem := range to { + toRule = append(toRule, toItem) + } + + logs, sub, err := _IFastBridge.contract.FilterLogs(opts, "BridgeDepositClaimed", transactionIdRule, relayerRule, toRule) + if err != nil { + return nil, err + } + return &IFastBridgeBridgeDepositClaimedIterator{contract: _IFastBridge.contract, event: "BridgeDepositClaimed", logs: logs, sub: sub}, nil +} + +// WatchBridgeDepositClaimed is a free log subscription operation binding the contract event 0x582211c35a2139ac3bbaac74663c6a1f56c6cbb658b41fe11fd45a82074ac678. +// +// Solidity: event BridgeDepositClaimed(bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount) +func (_IFastBridge *IFastBridgeFilterer) WatchBridgeDepositClaimed(opts *bind.WatchOpts, sink chan<- *IFastBridgeBridgeDepositClaimed, transactionId [][32]byte, relayer []common.Address, to []common.Address) (event.Subscription, error) { + + var transactionIdRule []interface{} + for _, transactionIdItem := range transactionId { + transactionIdRule = append(transactionIdRule, transactionIdItem) + } + var relayerRule []interface{} + for _, relayerItem := range relayer { + relayerRule = append(relayerRule, relayerItem) + } + var toRule []interface{} + for _, toItem := range to { + toRule = append(toRule, toItem) + } + + logs, sub, err := _IFastBridge.contract.WatchLogs(opts, "BridgeDepositClaimed", transactionIdRule, relayerRule, toRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(IFastBridgeBridgeDepositClaimed) + if err := _IFastBridge.contract.UnpackLog(event, "BridgeDepositClaimed", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseBridgeDepositClaimed is a log parse operation binding the contract event 0x582211c35a2139ac3bbaac74663c6a1f56c6cbb658b41fe11fd45a82074ac678. +// +// Solidity: event BridgeDepositClaimed(bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount) +func (_IFastBridge *IFastBridgeFilterer) ParseBridgeDepositClaimed(log types.Log) (*IFastBridgeBridgeDepositClaimed, error) { + event := new(IFastBridgeBridgeDepositClaimed) + if err := _IFastBridge.contract.UnpackLog(event, "BridgeDepositClaimed", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// IFastBridgeBridgeDepositRefundedIterator is returned from FilterBridgeDepositRefunded and is used to iterate over the raw logs and unpacked data for BridgeDepositRefunded events raised by the IFastBridge contract. +type IFastBridgeBridgeDepositRefundedIterator struct { + Event *IFastBridgeBridgeDepositRefunded // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *IFastBridgeBridgeDepositRefundedIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(IFastBridgeBridgeDepositRefunded) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(IFastBridgeBridgeDepositRefunded) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *IFastBridgeBridgeDepositRefundedIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *IFastBridgeBridgeDepositRefundedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// IFastBridgeBridgeDepositRefunded represents a BridgeDepositRefunded event raised by the IFastBridge contract. +type IFastBridgeBridgeDepositRefunded struct { + TransactionId [32]byte + To common.Address + Token common.Address + Amount *big.Int + Raw types.Log // Blockchain specific contextual infos +} + +// FilterBridgeDepositRefunded is a free log retrieval operation binding the contract event 0xb4c55c0c9bc613519b920e88748090150b890a875d307f21bea7d4fb2e8bc958. +// +// Solidity: event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount) +func (_IFastBridge *IFastBridgeFilterer) FilterBridgeDepositRefunded(opts *bind.FilterOpts, transactionId [][32]byte, to []common.Address) (*IFastBridgeBridgeDepositRefundedIterator, error) { + + var transactionIdRule []interface{} + for _, transactionIdItem := range transactionId { + transactionIdRule = append(transactionIdRule, transactionIdItem) + } + var toRule []interface{} + for _, toItem := range to { + toRule = append(toRule, toItem) + } + + logs, sub, err := _IFastBridge.contract.FilterLogs(opts, "BridgeDepositRefunded", transactionIdRule, toRule) + if err != nil { + return nil, err + } + return &IFastBridgeBridgeDepositRefundedIterator{contract: _IFastBridge.contract, event: "BridgeDepositRefunded", logs: logs, sub: sub}, nil +} + +// WatchBridgeDepositRefunded is a free log subscription operation binding the contract event 0xb4c55c0c9bc613519b920e88748090150b890a875d307f21bea7d4fb2e8bc958. +// +// Solidity: event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount) +func (_IFastBridge *IFastBridgeFilterer) WatchBridgeDepositRefunded(opts *bind.WatchOpts, sink chan<- *IFastBridgeBridgeDepositRefunded, transactionId [][32]byte, to []common.Address) (event.Subscription, error) { + + var transactionIdRule []interface{} + for _, transactionIdItem := range transactionId { + transactionIdRule = append(transactionIdRule, transactionIdItem) + } + var toRule []interface{} + for _, toItem := range to { + toRule = append(toRule, toItem) + } + + logs, sub, err := _IFastBridge.contract.WatchLogs(opts, "BridgeDepositRefunded", transactionIdRule, toRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(IFastBridgeBridgeDepositRefunded) + if err := _IFastBridge.contract.UnpackLog(event, "BridgeDepositRefunded", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseBridgeDepositRefunded is a log parse operation binding the contract event 0xb4c55c0c9bc613519b920e88748090150b890a875d307f21bea7d4fb2e8bc958. +// +// Solidity: event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount) +func (_IFastBridge *IFastBridgeFilterer) ParseBridgeDepositRefunded(log types.Log) (*IFastBridgeBridgeDepositRefunded, error) { + event := new(IFastBridgeBridgeDepositRefunded) + if err := _IFastBridge.contract.UnpackLog(event, "BridgeDepositRefunded", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// IFastBridgeBridgeProofDisputedIterator is returned from FilterBridgeProofDisputed and is used to iterate over the raw logs and unpacked data for BridgeProofDisputed events raised by the IFastBridge contract. +type IFastBridgeBridgeProofDisputedIterator struct { + Event *IFastBridgeBridgeProofDisputed // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *IFastBridgeBridgeProofDisputedIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(IFastBridgeBridgeProofDisputed) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(IFastBridgeBridgeProofDisputed) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *IFastBridgeBridgeProofDisputedIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *IFastBridgeBridgeProofDisputedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// IFastBridgeBridgeProofDisputed represents a BridgeProofDisputed event raised by the IFastBridge contract. +type IFastBridgeBridgeProofDisputed struct { + TransactionId [32]byte + Relayer common.Address + Raw types.Log // Blockchain specific contextual infos +} + +// FilterBridgeProofDisputed is a free log retrieval operation binding the contract event 0x0695cf1d39b3055dcd0fe02d8b47eaf0d5a13e1996de925de59d0ef9b7f7fad4. +// +// Solidity: event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer) +func (_IFastBridge *IFastBridgeFilterer) FilterBridgeProofDisputed(opts *bind.FilterOpts, transactionId [][32]byte, relayer []common.Address) (*IFastBridgeBridgeProofDisputedIterator, error) { + + var transactionIdRule []interface{} + for _, transactionIdItem := range transactionId { + transactionIdRule = append(transactionIdRule, transactionIdItem) + } + var relayerRule []interface{} + for _, relayerItem := range relayer { + relayerRule = append(relayerRule, relayerItem) + } + + logs, sub, err := _IFastBridge.contract.FilterLogs(opts, "BridgeProofDisputed", transactionIdRule, relayerRule) + if err != nil { + return nil, err + } + return &IFastBridgeBridgeProofDisputedIterator{contract: _IFastBridge.contract, event: "BridgeProofDisputed", logs: logs, sub: sub}, nil +} + +// WatchBridgeProofDisputed is a free log subscription operation binding the contract event 0x0695cf1d39b3055dcd0fe02d8b47eaf0d5a13e1996de925de59d0ef9b7f7fad4. +// +// Solidity: event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer) +func (_IFastBridge *IFastBridgeFilterer) WatchBridgeProofDisputed(opts *bind.WatchOpts, sink chan<- *IFastBridgeBridgeProofDisputed, transactionId [][32]byte, relayer []common.Address) (event.Subscription, error) { + + var transactionIdRule []interface{} + for _, transactionIdItem := range transactionId { + transactionIdRule = append(transactionIdRule, transactionIdItem) + } + var relayerRule []interface{} + for _, relayerItem := range relayer { + relayerRule = append(relayerRule, relayerItem) + } + + logs, sub, err := _IFastBridge.contract.WatchLogs(opts, "BridgeProofDisputed", transactionIdRule, relayerRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(IFastBridgeBridgeProofDisputed) + if err := _IFastBridge.contract.UnpackLog(event, "BridgeProofDisputed", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseBridgeProofDisputed is a log parse operation binding the contract event 0x0695cf1d39b3055dcd0fe02d8b47eaf0d5a13e1996de925de59d0ef9b7f7fad4. +// +// Solidity: event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer) +func (_IFastBridge *IFastBridgeFilterer) ParseBridgeProofDisputed(log types.Log) (*IFastBridgeBridgeProofDisputed, error) { + event := new(IFastBridgeBridgeProofDisputed) + if err := _IFastBridge.contract.UnpackLog(event, "BridgeProofDisputed", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// IFastBridgeBridgeProofProvidedIterator is returned from FilterBridgeProofProvided and is used to iterate over the raw logs and unpacked data for BridgeProofProvided events raised by the IFastBridge contract. +type IFastBridgeBridgeProofProvidedIterator struct { + Event *IFastBridgeBridgeProofProvided // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *IFastBridgeBridgeProofProvidedIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(IFastBridgeBridgeProofProvided) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(IFastBridgeBridgeProofProvided) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *IFastBridgeBridgeProofProvidedIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *IFastBridgeBridgeProofProvidedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// IFastBridgeBridgeProofProvided represents a BridgeProofProvided event raised by the IFastBridge contract. +type IFastBridgeBridgeProofProvided struct { + TransactionId [32]byte + Relayer common.Address + TransactionHash [32]byte + Raw types.Log // Blockchain specific contextual infos +} + +// FilterBridgeProofProvided is a free log retrieval operation binding the contract event 0x4ac8af8a2cd87193d64dfc7a3b8d9923b714ec528b18725d080aa1299be0c5e4. +// +// Solidity: event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash) +func (_IFastBridge *IFastBridgeFilterer) FilterBridgeProofProvided(opts *bind.FilterOpts, transactionId [][32]byte, relayer []common.Address) (*IFastBridgeBridgeProofProvidedIterator, error) { + + var transactionIdRule []interface{} + for _, transactionIdItem := range transactionId { + transactionIdRule = append(transactionIdRule, transactionIdItem) + } + var relayerRule []interface{} + for _, relayerItem := range relayer { + relayerRule = append(relayerRule, relayerItem) + } + + logs, sub, err := _IFastBridge.contract.FilterLogs(opts, "BridgeProofProvided", transactionIdRule, relayerRule) + if err != nil { + return nil, err + } + return &IFastBridgeBridgeProofProvidedIterator{contract: _IFastBridge.contract, event: "BridgeProofProvided", logs: logs, sub: sub}, nil +} + +// WatchBridgeProofProvided is a free log subscription operation binding the contract event 0x4ac8af8a2cd87193d64dfc7a3b8d9923b714ec528b18725d080aa1299be0c5e4. +// +// Solidity: event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash) +func (_IFastBridge *IFastBridgeFilterer) WatchBridgeProofProvided(opts *bind.WatchOpts, sink chan<- *IFastBridgeBridgeProofProvided, transactionId [][32]byte, relayer []common.Address) (event.Subscription, error) { + + var transactionIdRule []interface{} + for _, transactionIdItem := range transactionId { + transactionIdRule = append(transactionIdRule, transactionIdItem) + } + var relayerRule []interface{} + for _, relayerItem := range relayer { + relayerRule = append(relayerRule, relayerItem) + } + + logs, sub, err := _IFastBridge.contract.WatchLogs(opts, "BridgeProofProvided", transactionIdRule, relayerRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(IFastBridgeBridgeProofProvided) + if err := _IFastBridge.contract.UnpackLog(event, "BridgeProofProvided", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseBridgeProofProvided is a log parse operation binding the contract event 0x4ac8af8a2cd87193d64dfc7a3b8d9923b714ec528b18725d080aa1299be0c5e4. +// +// Solidity: event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash) +func (_IFastBridge *IFastBridgeFilterer) ParseBridgeProofProvided(log types.Log) (*IFastBridgeBridgeProofProvided, error) { + event := new(IFastBridgeBridgeProofProvided) + if err := _IFastBridge.contract.UnpackLog(event, "BridgeProofProvided", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// IFastBridgeBridgeRelayedIterator is returned from FilterBridgeRelayed and is used to iterate over the raw logs and unpacked data for BridgeRelayed events raised by the IFastBridge contract. +type IFastBridgeBridgeRelayedIterator struct { + Event *IFastBridgeBridgeRelayed // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *IFastBridgeBridgeRelayedIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(IFastBridgeBridgeRelayed) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(IFastBridgeBridgeRelayed) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *IFastBridgeBridgeRelayedIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *IFastBridgeBridgeRelayedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// IFastBridgeBridgeRelayed represents a BridgeRelayed event raised by the IFastBridge contract. +type IFastBridgeBridgeRelayed struct { + TransactionId [32]byte + Relayer common.Address + To common.Address + OriginChainId uint32 + OriginToken common.Address + DestToken common.Address + OriginAmount *big.Int + DestAmount *big.Int + ChainGasAmount *big.Int + Raw types.Log // Blockchain specific contextual infos +} + +// FilterBridgeRelayed is a free log retrieval operation binding the contract event 0xf8ae392d784b1ea5e8881bfa586d81abf07ef4f1e2fc75f7fe51c90f05199a5c. +// +// Solidity: event BridgeRelayed(bytes32 indexed transactionId, address indexed relayer, address indexed to, uint32 originChainId, address originToken, address destToken, uint256 originAmount, uint256 destAmount, uint256 chainGasAmount) +func (_IFastBridge *IFastBridgeFilterer) FilterBridgeRelayed(opts *bind.FilterOpts, transactionId [][32]byte, relayer []common.Address, to []common.Address) (*IFastBridgeBridgeRelayedIterator, error) { + + var transactionIdRule []interface{} + for _, transactionIdItem := range transactionId { + transactionIdRule = append(transactionIdRule, transactionIdItem) + } + var relayerRule []interface{} + for _, relayerItem := range relayer { + relayerRule = append(relayerRule, relayerItem) + } + var toRule []interface{} + for _, toItem := range to { + toRule = append(toRule, toItem) + } + + logs, sub, err := _IFastBridge.contract.FilterLogs(opts, "BridgeRelayed", transactionIdRule, relayerRule, toRule) + if err != nil { + return nil, err + } + return &IFastBridgeBridgeRelayedIterator{contract: _IFastBridge.contract, event: "BridgeRelayed", logs: logs, sub: sub}, nil +} + +// WatchBridgeRelayed is a free log subscription operation binding the contract event 0xf8ae392d784b1ea5e8881bfa586d81abf07ef4f1e2fc75f7fe51c90f05199a5c. +// +// Solidity: event BridgeRelayed(bytes32 indexed transactionId, address indexed relayer, address indexed to, uint32 originChainId, address originToken, address destToken, uint256 originAmount, uint256 destAmount, uint256 chainGasAmount) +func (_IFastBridge *IFastBridgeFilterer) WatchBridgeRelayed(opts *bind.WatchOpts, sink chan<- *IFastBridgeBridgeRelayed, transactionId [][32]byte, relayer []common.Address, to []common.Address) (event.Subscription, error) { + + var transactionIdRule []interface{} + for _, transactionIdItem := range transactionId { + transactionIdRule = append(transactionIdRule, transactionIdItem) + } + var relayerRule []interface{} + for _, relayerItem := range relayer { + relayerRule = append(relayerRule, relayerItem) + } + var toRule []interface{} + for _, toItem := range to { + toRule = append(toRule, toItem) + } + + logs, sub, err := _IFastBridge.contract.WatchLogs(opts, "BridgeRelayed", transactionIdRule, relayerRule, toRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(IFastBridgeBridgeRelayed) + if err := _IFastBridge.contract.UnpackLog(event, "BridgeRelayed", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseBridgeRelayed is a log parse operation binding the contract event 0xf8ae392d784b1ea5e8881bfa586d81abf07ef4f1e2fc75f7fe51c90f05199a5c. +// +// Solidity: event BridgeRelayed(bytes32 indexed transactionId, address indexed relayer, address indexed to, uint32 originChainId, address originToken, address destToken, uint256 originAmount, uint256 destAmount, uint256 chainGasAmount) +func (_IFastBridge *IFastBridgeFilterer) ParseBridgeRelayed(log types.Log) (*IFastBridgeBridgeRelayed, error) { + event := new(IFastBridgeBridgeRelayed) + if err := _IFastBridge.contract.UnpackLog(event, "BridgeRelayed", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// IFastBridgeBridgeRequestedIterator is returned from FilterBridgeRequested and is used to iterate over the raw logs and unpacked data for BridgeRequested events raised by the IFastBridge contract. +type IFastBridgeBridgeRequestedIterator struct { + Event *IFastBridgeBridgeRequested // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *IFastBridgeBridgeRequestedIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(IFastBridgeBridgeRequested) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(IFastBridgeBridgeRequested) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *IFastBridgeBridgeRequestedIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *IFastBridgeBridgeRequestedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// IFastBridgeBridgeRequested represents a BridgeRequested event raised by the IFastBridge contract. +type IFastBridgeBridgeRequested struct { + TransactionId [32]byte + Sender common.Address + Request []byte + DestChainId uint32 + OriginToken common.Address + DestToken common.Address + OriginAmount *big.Int + DestAmount *big.Int + SendChainGas bool + Raw types.Log // Blockchain specific contextual infos +} + +// FilterBridgeRequested is a free log retrieval operation binding the contract event 0x120ea0364f36cdac7983bcfdd55270ca09d7f9b314a2ebc425a3b01ab1d6403a. +// +// Solidity: event BridgeRequested(bytes32 indexed transactionId, address indexed sender, bytes request, uint32 destChainId, address originToken, address destToken, uint256 originAmount, uint256 destAmount, bool sendChainGas) +func (_IFastBridge *IFastBridgeFilterer) FilterBridgeRequested(opts *bind.FilterOpts, transactionId [][32]byte, sender []common.Address) (*IFastBridgeBridgeRequestedIterator, error) { + + var transactionIdRule []interface{} + for _, transactionIdItem := range transactionId { + transactionIdRule = append(transactionIdRule, transactionIdItem) + } + var senderRule []interface{} + for _, senderItem := range sender { + senderRule = append(senderRule, senderItem) + } + + logs, sub, err := _IFastBridge.contract.FilterLogs(opts, "BridgeRequested", transactionIdRule, senderRule) + if err != nil { + return nil, err + } + return &IFastBridgeBridgeRequestedIterator{contract: _IFastBridge.contract, event: "BridgeRequested", logs: logs, sub: sub}, nil +} + +// WatchBridgeRequested is a free log subscription operation binding the contract event 0x120ea0364f36cdac7983bcfdd55270ca09d7f9b314a2ebc425a3b01ab1d6403a. +// +// Solidity: event BridgeRequested(bytes32 indexed transactionId, address indexed sender, bytes request, uint32 destChainId, address originToken, address destToken, uint256 originAmount, uint256 destAmount, bool sendChainGas) +func (_IFastBridge *IFastBridgeFilterer) WatchBridgeRequested(opts *bind.WatchOpts, sink chan<- *IFastBridgeBridgeRequested, transactionId [][32]byte, sender []common.Address) (event.Subscription, error) { + + var transactionIdRule []interface{} + for _, transactionIdItem := range transactionId { + transactionIdRule = append(transactionIdRule, transactionIdItem) + } + var senderRule []interface{} + for _, senderItem := range sender { + senderRule = append(senderRule, senderItem) + } + + logs, sub, err := _IFastBridge.contract.WatchLogs(opts, "BridgeRequested", transactionIdRule, senderRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(IFastBridgeBridgeRequested) + if err := _IFastBridge.contract.UnpackLog(event, "BridgeRequested", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseBridgeRequested is a log parse operation binding the contract event 0x120ea0364f36cdac7983bcfdd55270ca09d7f9b314a2ebc425a3b01ab1d6403a. +// +// Solidity: event BridgeRequested(bytes32 indexed transactionId, address indexed sender, bytes request, uint32 destChainId, address originToken, address destToken, uint256 originAmount, uint256 destAmount, bool sendChainGas) +func (_IFastBridge *IFastBridgeFilterer) ParseBridgeRequested(log types.Log) (*IFastBridgeBridgeRequested, error) { + event := new(IFastBridgeBridgeRequested) + if err := _IFastBridge.contract.UnpackLog(event, "BridgeRequested", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// IFastBridgeV2MetaData contains all meta data concerning the IFastBridgeV2 contract. +var IFastBridgeV2MetaData = &bind.MetaData{ + ABI: "[{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"BridgeDepositClaimed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"BridgeDepositRefunded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"name\":\"BridgeProofDisputed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"transactionHash\",\"type\":\"bytes32\"}],\"name\":\"BridgeProofProvided\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"quoteId\",\"type\":\"bytes\"}],\"name\":\"BridgeQuoteDetails\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"originChainId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"chainGasAmount\",\"type\":\"uint256\"}],\"name\":\"BridgeRelayed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"destChainId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"sendChainGas\",\"type\":\"bool\"}],\"name\":\"BridgeRequested\",\"type\":\"event\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"dstChainId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"sendChainGas\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"}],\"internalType\":\"structIFastBridge.BridgeParams\",\"name\":\"params\",\"type\":\"tuple\"}],\"name\":\"bridge\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"dstChainId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"sendChainGas\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"}],\"internalType\":\"structIFastBridge.BridgeParams\",\"name\":\"params\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"quoteRelayer\",\"type\":\"address\"},{\"internalType\":\"int256\",\"name\":\"quoteExclusivitySeconds\",\"type\":\"int256\"},{\"internalType\":\"bytes\",\"name\":\"quoteId\",\"type\":\"bytes\"},{\"internalType\":\"uint256\",\"name\":\"zapNative\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"zapData\",\"type\":\"bytes\"}],\"internalType\":\"structIFastBridgeV2.BridgeParamsV2\",\"name\":\"paramsV2\",\"type\":\"tuple\"}],\"name\":\"bridge\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"}],\"name\":\"bridgeProofs\",\"outputs\":[{\"internalType\":\"uint96\",\"name\":\"timestamp\",\"type\":\"uint96\"},{\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"}],\"name\":\"bridgeRelays\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"}],\"name\":\"bridgeStatuses\",\"outputs\":[{\"internalType\":\"enumIFastBridgeV2.BridgeStatus\",\"name\":\"\",\"type\":\"uint8\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"name\":\"canClaim\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"claim\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"claim\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"}],\"name\":\"dispute\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"getBridgeTransaction\",\"outputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"originChainId\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"destChainId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"originSender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destRecipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"originFeeAmount\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"sendChainGas\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"}],\"internalType\":\"structIFastBridge.BridgeTransaction\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"getBridgeTransactionV2\",\"outputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"originChainId\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"destChainId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"originSender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destRecipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"originFeeAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"exclusivityRelayer\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"exclusivityEndTime\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"zapNative\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"zapData\",\"type\":\"bytes\"}],\"internalType\":\"structIFastBridgeV2.BridgeTransactionV2\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"destTxHash\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"name\":\"prove\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"},{\"internalType\":\"bytes32\",\"name\":\"destTxHash\",\"type\":\"bytes32\"}],\"name\":\"prove\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"refund\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"relay\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"},{\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"name\":\"relay\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"}]", + Sigs: map[string]string{ + "45851694": "bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256))", + "bfc7c607": "bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256),(address,int256,bytes,uint256,bytes))", + "91ad5039": "bridgeProofs(bytes32)", + "8379a24f": "bridgeRelays(bytes32)", + "051287bc": "bridgeStatuses(bytes32)", + "aa9641ab": "canClaim(bytes32,address)", + "c63ff8dd": "claim(bytes)", + "41fcb612": "claim(bytes,address)", + "add98c70": "dispute(bytes32)", + "ac11fb1a": "getBridgeTransaction(bytes)", + "5aa6ccba": "getBridgeTransactionV2(bytes)", + "886d36ff": "prove(bytes,bytes32)", + "18e4357d": "prove(bytes32,bytes32,address)", + "5eb7d946": "refund(bytes)", + "8f0d6f17": "relay(bytes)", + "9c9545f0": "relay(bytes,address)", + }, +} + +// IFastBridgeV2ABI is the input ABI used to generate the binding from. +// Deprecated: Use IFastBridgeV2MetaData.ABI instead. +var IFastBridgeV2ABI = IFastBridgeV2MetaData.ABI + +// Deprecated: Use IFastBridgeV2MetaData.Sigs instead. +// IFastBridgeV2FuncSigs maps the 4-byte function signature to its string representation. +var IFastBridgeV2FuncSigs = IFastBridgeV2MetaData.Sigs + +// IFastBridgeV2 is an auto generated Go binding around an Ethereum contract. +type IFastBridgeV2 struct { + IFastBridgeV2Caller // Read-only binding to the contract + IFastBridgeV2Transactor // Write-only binding to the contract + IFastBridgeV2Filterer // Log filterer for contract events +} + +// IFastBridgeV2Caller is an auto generated read-only Go binding around an Ethereum contract. +type IFastBridgeV2Caller struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// IFastBridgeV2Transactor is an auto generated write-only Go binding around an Ethereum contract. +type IFastBridgeV2Transactor struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// IFastBridgeV2Filterer is an auto generated log filtering Go binding around an Ethereum contract events. +type IFastBridgeV2Filterer struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// IFastBridgeV2Session is an auto generated Go binding around an Ethereum contract, +// with pre-set call and transact options. +type IFastBridgeV2Session struct { + Contract *IFastBridgeV2 // Generic contract binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// IFastBridgeV2CallerSession is an auto generated read-only Go binding around an Ethereum contract, +// with pre-set call options. +type IFastBridgeV2CallerSession struct { + Contract *IFastBridgeV2Caller // Generic contract caller binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session +} + +// IFastBridgeV2TransactorSession is an auto generated write-only Go binding around an Ethereum contract, +// with pre-set transact options. +type IFastBridgeV2TransactorSession struct { + Contract *IFastBridgeV2Transactor // Generic contract transactor binding to set the session for + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// IFastBridgeV2Raw is an auto generated low-level Go binding around an Ethereum contract. +type IFastBridgeV2Raw struct { + Contract *IFastBridgeV2 // Generic contract binding to access the raw methods on +} + +// IFastBridgeV2CallerRaw is an auto generated low-level read-only Go binding around an Ethereum contract. +type IFastBridgeV2CallerRaw struct { + Contract *IFastBridgeV2Caller // Generic read-only contract binding to access the raw methods on +} + +// IFastBridgeV2TransactorRaw is an auto generated low-level write-only Go binding around an Ethereum contract. +type IFastBridgeV2TransactorRaw struct { + Contract *IFastBridgeV2Transactor // Generic write-only contract binding to access the raw methods on +} + +// NewIFastBridgeV2 creates a new instance of IFastBridgeV2, bound to a specific deployed contract. +func NewIFastBridgeV2(address common.Address, backend bind.ContractBackend) (*IFastBridgeV2, error) { + contract, err := bindIFastBridgeV2(address, backend, backend, backend) + if err != nil { + return nil, err + } + return &IFastBridgeV2{IFastBridgeV2Caller: IFastBridgeV2Caller{contract: contract}, IFastBridgeV2Transactor: IFastBridgeV2Transactor{contract: contract}, IFastBridgeV2Filterer: IFastBridgeV2Filterer{contract: contract}}, nil +} + +// NewIFastBridgeV2Caller creates a new read-only instance of IFastBridgeV2, bound to a specific deployed contract. +func NewIFastBridgeV2Caller(address common.Address, caller bind.ContractCaller) (*IFastBridgeV2Caller, error) { + contract, err := bindIFastBridgeV2(address, caller, nil, nil) + if err != nil { + return nil, err + } + return &IFastBridgeV2Caller{contract: contract}, nil +} + +// NewIFastBridgeV2Transactor creates a new write-only instance of IFastBridgeV2, bound to a specific deployed contract. +func NewIFastBridgeV2Transactor(address common.Address, transactor bind.ContractTransactor) (*IFastBridgeV2Transactor, error) { + contract, err := bindIFastBridgeV2(address, nil, transactor, nil) + if err != nil { + return nil, err + } + return &IFastBridgeV2Transactor{contract: contract}, nil +} + +// NewIFastBridgeV2Filterer creates a new log filterer instance of IFastBridgeV2, bound to a specific deployed contract. +func NewIFastBridgeV2Filterer(address common.Address, filterer bind.ContractFilterer) (*IFastBridgeV2Filterer, error) { + contract, err := bindIFastBridgeV2(address, nil, nil, filterer) + if err != nil { + return nil, err + } + return &IFastBridgeV2Filterer{contract: contract}, nil +} + +// bindIFastBridgeV2 binds a generic wrapper to an already deployed contract. +func bindIFastBridgeV2(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) { + parsed, err := IFastBridgeV2MetaData.GetAbi() + if err != nil { + return nil, err + } + return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil +} + +// Call invokes the (constant) contract method with params as input values and +// sets the output to result. The result type might be a single field for simple +// returns, a slice of interfaces for anonymous returns and a struct for named +// returns. +func (_IFastBridgeV2 *IFastBridgeV2Raw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _IFastBridgeV2.Contract.IFastBridgeV2Caller.contract.Call(opts, result, method, params...) +} + +// Transfer initiates a plain transaction to move funds to the contract, calling +// its default method if one is available. +func (_IFastBridgeV2 *IFastBridgeV2Raw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _IFastBridgeV2.Contract.IFastBridgeV2Transactor.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_IFastBridgeV2 *IFastBridgeV2Raw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _IFastBridgeV2.Contract.IFastBridgeV2Transactor.contract.Transact(opts, method, params...) +} + +// Call invokes the (constant) contract method with params as input values and +// sets the output to result. The result type might be a single field for simple +// returns, a slice of interfaces for anonymous returns and a struct for named +// returns. +func (_IFastBridgeV2 *IFastBridgeV2CallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _IFastBridgeV2.Contract.contract.Call(opts, result, method, params...) +} + +// Transfer initiates a plain transaction to move funds to the contract, calling +// its default method if one is available. +func (_IFastBridgeV2 *IFastBridgeV2TransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _IFastBridgeV2.Contract.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_IFastBridgeV2 *IFastBridgeV2TransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _IFastBridgeV2.Contract.contract.Transact(opts, method, params...) +} + +// BridgeProofs is a free data retrieval call binding the contract method 0x91ad5039. +// +// Solidity: function bridgeProofs(bytes32 transactionId) view returns(uint96 timestamp, address relayer) +func (_IFastBridgeV2 *IFastBridgeV2Caller) BridgeProofs(opts *bind.CallOpts, transactionId [32]byte) (struct { + Timestamp *big.Int + Relayer common.Address +}, error) { + var out []interface{} + err := _IFastBridgeV2.contract.Call(opts, &out, "bridgeProofs", transactionId) + + outstruct := new(struct { + Timestamp *big.Int + Relayer common.Address + }) + if err != nil { + return *outstruct, err + } + + outstruct.Timestamp = *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + outstruct.Relayer = *abi.ConvertType(out[1], new(common.Address)).(*common.Address) + + return *outstruct, err + +} + +// BridgeProofs is a free data retrieval call binding the contract method 0x91ad5039. +// +// Solidity: function bridgeProofs(bytes32 transactionId) view returns(uint96 timestamp, address relayer) +func (_IFastBridgeV2 *IFastBridgeV2Session) BridgeProofs(transactionId [32]byte) (struct { + Timestamp *big.Int + Relayer common.Address +}, error) { + return _IFastBridgeV2.Contract.BridgeProofs(&_IFastBridgeV2.CallOpts, transactionId) +} + +// BridgeProofs is a free data retrieval call binding the contract method 0x91ad5039. +// +// Solidity: function bridgeProofs(bytes32 transactionId) view returns(uint96 timestamp, address relayer) +func (_IFastBridgeV2 *IFastBridgeV2CallerSession) BridgeProofs(transactionId [32]byte) (struct { + Timestamp *big.Int + Relayer common.Address +}, error) { + return _IFastBridgeV2.Contract.BridgeProofs(&_IFastBridgeV2.CallOpts, transactionId) +} + +// BridgeRelays is a free data retrieval call binding the contract method 0x8379a24f. +// +// Solidity: function bridgeRelays(bytes32 transactionId) view returns(bool) +func (_IFastBridgeV2 *IFastBridgeV2Caller) BridgeRelays(opts *bind.CallOpts, transactionId [32]byte) (bool, error) { + var out []interface{} + err := _IFastBridgeV2.contract.Call(opts, &out, "bridgeRelays", transactionId) + + if err != nil { + return *new(bool), err + } + + out0 := *abi.ConvertType(out[0], new(bool)).(*bool) + + return out0, err + +} + +// BridgeRelays is a free data retrieval call binding the contract method 0x8379a24f. +// +// Solidity: function bridgeRelays(bytes32 transactionId) view returns(bool) +func (_IFastBridgeV2 *IFastBridgeV2Session) BridgeRelays(transactionId [32]byte) (bool, error) { + return _IFastBridgeV2.Contract.BridgeRelays(&_IFastBridgeV2.CallOpts, transactionId) +} + +// BridgeRelays is a free data retrieval call binding the contract method 0x8379a24f. +// +// Solidity: function bridgeRelays(bytes32 transactionId) view returns(bool) +func (_IFastBridgeV2 *IFastBridgeV2CallerSession) BridgeRelays(transactionId [32]byte) (bool, error) { + return _IFastBridgeV2.Contract.BridgeRelays(&_IFastBridgeV2.CallOpts, transactionId) +} + +// BridgeStatuses is a free data retrieval call binding the contract method 0x051287bc. +// +// Solidity: function bridgeStatuses(bytes32 transactionId) view returns(uint8) +func (_IFastBridgeV2 *IFastBridgeV2Caller) BridgeStatuses(opts *bind.CallOpts, transactionId [32]byte) (uint8, error) { + var out []interface{} + err := _IFastBridgeV2.contract.Call(opts, &out, "bridgeStatuses", transactionId) + + if err != nil { + return *new(uint8), err + } + + out0 := *abi.ConvertType(out[0], new(uint8)).(*uint8) + + return out0, err + +} + +// BridgeStatuses is a free data retrieval call binding the contract method 0x051287bc. +// +// Solidity: function bridgeStatuses(bytes32 transactionId) view returns(uint8) +func (_IFastBridgeV2 *IFastBridgeV2Session) BridgeStatuses(transactionId [32]byte) (uint8, error) { + return _IFastBridgeV2.Contract.BridgeStatuses(&_IFastBridgeV2.CallOpts, transactionId) +} + +// BridgeStatuses is a free data retrieval call binding the contract method 0x051287bc. +// +// Solidity: function bridgeStatuses(bytes32 transactionId) view returns(uint8) +func (_IFastBridgeV2 *IFastBridgeV2CallerSession) BridgeStatuses(transactionId [32]byte) (uint8, error) { + return _IFastBridgeV2.Contract.BridgeStatuses(&_IFastBridgeV2.CallOpts, transactionId) +} + +// CanClaim is a free data retrieval call binding the contract method 0xaa9641ab. +// +// Solidity: function canClaim(bytes32 transactionId, address relayer) view returns(bool) +func (_IFastBridgeV2 *IFastBridgeV2Caller) CanClaim(opts *bind.CallOpts, transactionId [32]byte, relayer common.Address) (bool, error) { + var out []interface{} + err := _IFastBridgeV2.contract.Call(opts, &out, "canClaim", transactionId, relayer) + + if err != nil { + return *new(bool), err + } + + out0 := *abi.ConvertType(out[0], new(bool)).(*bool) + + return out0, err + +} + +// CanClaim is a free data retrieval call binding the contract method 0xaa9641ab. +// +// Solidity: function canClaim(bytes32 transactionId, address relayer) view returns(bool) +func (_IFastBridgeV2 *IFastBridgeV2Session) CanClaim(transactionId [32]byte, relayer common.Address) (bool, error) { + return _IFastBridgeV2.Contract.CanClaim(&_IFastBridgeV2.CallOpts, transactionId, relayer) +} + +// CanClaim is a free data retrieval call binding the contract method 0xaa9641ab. +// +// Solidity: function canClaim(bytes32 transactionId, address relayer) view returns(bool) +func (_IFastBridgeV2 *IFastBridgeV2CallerSession) CanClaim(transactionId [32]byte, relayer common.Address) (bool, error) { + return _IFastBridgeV2.Contract.CanClaim(&_IFastBridgeV2.CallOpts, transactionId, relayer) +} + +// GetBridgeTransaction is a free data retrieval call binding the contract method 0xac11fb1a. +// +// Solidity: function getBridgeTransaction(bytes request) view returns((uint32,uint32,address,address,address,address,uint256,uint256,uint256,bool,uint256,uint256)) +func (_IFastBridgeV2 *IFastBridgeV2Caller) GetBridgeTransaction(opts *bind.CallOpts, request []byte) (IFastBridgeBridgeTransaction, error) { + var out []interface{} + err := _IFastBridgeV2.contract.Call(opts, &out, "getBridgeTransaction", request) + + if err != nil { + return *new(IFastBridgeBridgeTransaction), err + } + + out0 := *abi.ConvertType(out[0], new(IFastBridgeBridgeTransaction)).(*IFastBridgeBridgeTransaction) + + return out0, err + +} + +// GetBridgeTransaction is a free data retrieval call binding the contract method 0xac11fb1a. +// +// Solidity: function getBridgeTransaction(bytes request) view returns((uint32,uint32,address,address,address,address,uint256,uint256,uint256,bool,uint256,uint256)) +func (_IFastBridgeV2 *IFastBridgeV2Session) GetBridgeTransaction(request []byte) (IFastBridgeBridgeTransaction, error) { + return _IFastBridgeV2.Contract.GetBridgeTransaction(&_IFastBridgeV2.CallOpts, request) +} + +// GetBridgeTransaction is a free data retrieval call binding the contract method 0xac11fb1a. +// +// Solidity: function getBridgeTransaction(bytes request) view returns((uint32,uint32,address,address,address,address,uint256,uint256,uint256,bool,uint256,uint256)) +func (_IFastBridgeV2 *IFastBridgeV2CallerSession) GetBridgeTransaction(request []byte) (IFastBridgeBridgeTransaction, error) { + return _IFastBridgeV2.Contract.GetBridgeTransaction(&_IFastBridgeV2.CallOpts, request) +} + +// GetBridgeTransactionV2 is a free data retrieval call binding the contract method 0x5aa6ccba. +// +// Solidity: function getBridgeTransactionV2(bytes request) view returns((uint32,uint32,address,address,address,address,uint256,uint256,uint256,uint256,uint256,address,uint256,uint256,bytes)) +func (_IFastBridgeV2 *IFastBridgeV2Caller) GetBridgeTransactionV2(opts *bind.CallOpts, request []byte) (IFastBridgeV2BridgeTransactionV2, error) { + var out []interface{} + err := _IFastBridgeV2.contract.Call(opts, &out, "getBridgeTransactionV2", request) + + if err != nil { + return *new(IFastBridgeV2BridgeTransactionV2), err + } + + out0 := *abi.ConvertType(out[0], new(IFastBridgeV2BridgeTransactionV2)).(*IFastBridgeV2BridgeTransactionV2) + + return out0, err + +} + +// GetBridgeTransactionV2 is a free data retrieval call binding the contract method 0x5aa6ccba. +// +// Solidity: function getBridgeTransactionV2(bytes request) view returns((uint32,uint32,address,address,address,address,uint256,uint256,uint256,uint256,uint256,address,uint256,uint256,bytes)) +func (_IFastBridgeV2 *IFastBridgeV2Session) GetBridgeTransactionV2(request []byte) (IFastBridgeV2BridgeTransactionV2, error) { + return _IFastBridgeV2.Contract.GetBridgeTransactionV2(&_IFastBridgeV2.CallOpts, request) +} + +// GetBridgeTransactionV2 is a free data retrieval call binding the contract method 0x5aa6ccba. +// +// Solidity: function getBridgeTransactionV2(bytes request) view returns((uint32,uint32,address,address,address,address,uint256,uint256,uint256,uint256,uint256,address,uint256,uint256,bytes)) +func (_IFastBridgeV2 *IFastBridgeV2CallerSession) GetBridgeTransactionV2(request []byte) (IFastBridgeV2BridgeTransactionV2, error) { + return _IFastBridgeV2.Contract.GetBridgeTransactionV2(&_IFastBridgeV2.CallOpts, request) +} + +// Bridge is a paid mutator transaction binding the contract method 0x45851694. +// +// Solidity: function bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256) params) payable returns() +func (_IFastBridgeV2 *IFastBridgeV2Transactor) Bridge(opts *bind.TransactOpts, params IFastBridgeBridgeParams) (*types.Transaction, error) { + return _IFastBridgeV2.contract.Transact(opts, "bridge", params) +} + +// Bridge is a paid mutator transaction binding the contract method 0x45851694. +// +// Solidity: function bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256) params) payable returns() +func (_IFastBridgeV2 *IFastBridgeV2Session) Bridge(params IFastBridgeBridgeParams) (*types.Transaction, error) { + return _IFastBridgeV2.Contract.Bridge(&_IFastBridgeV2.TransactOpts, params) +} + +// Bridge is a paid mutator transaction binding the contract method 0x45851694. +// +// Solidity: function bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256) params) payable returns() +func (_IFastBridgeV2 *IFastBridgeV2TransactorSession) Bridge(params IFastBridgeBridgeParams) (*types.Transaction, error) { + return _IFastBridgeV2.Contract.Bridge(&_IFastBridgeV2.TransactOpts, params) +} + +// Bridge0 is a paid mutator transaction binding the contract method 0xbfc7c607. +// +// Solidity: function bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256) params, (address,int256,bytes,uint256,bytes) paramsV2) payable returns() +func (_IFastBridgeV2 *IFastBridgeV2Transactor) Bridge0(opts *bind.TransactOpts, params IFastBridgeBridgeParams, paramsV2 IFastBridgeV2BridgeParamsV2) (*types.Transaction, error) { + return _IFastBridgeV2.contract.Transact(opts, "bridge0", params, paramsV2) +} + +// Bridge0 is a paid mutator transaction binding the contract method 0xbfc7c607. +// +// Solidity: function bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256) params, (address,int256,bytes,uint256,bytes) paramsV2) payable returns() +func (_IFastBridgeV2 *IFastBridgeV2Session) Bridge0(params IFastBridgeBridgeParams, paramsV2 IFastBridgeV2BridgeParamsV2) (*types.Transaction, error) { + return _IFastBridgeV2.Contract.Bridge0(&_IFastBridgeV2.TransactOpts, params, paramsV2) +} + +// Bridge0 is a paid mutator transaction binding the contract method 0xbfc7c607. +// +// Solidity: function bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256) params, (address,int256,bytes,uint256,bytes) paramsV2) payable returns() +func (_IFastBridgeV2 *IFastBridgeV2TransactorSession) Bridge0(params IFastBridgeBridgeParams, paramsV2 IFastBridgeV2BridgeParamsV2) (*types.Transaction, error) { + return _IFastBridgeV2.Contract.Bridge0(&_IFastBridgeV2.TransactOpts, params, paramsV2) +} + +// Claim is a paid mutator transaction binding the contract method 0x41fcb612. +// +// Solidity: function claim(bytes request, address to) returns() +func (_IFastBridgeV2 *IFastBridgeV2Transactor) Claim(opts *bind.TransactOpts, request []byte, to common.Address) (*types.Transaction, error) { + return _IFastBridgeV2.contract.Transact(opts, "claim", request, to) +} + +// Claim is a paid mutator transaction binding the contract method 0x41fcb612. +// +// Solidity: function claim(bytes request, address to) returns() +func (_IFastBridgeV2 *IFastBridgeV2Session) Claim(request []byte, to common.Address) (*types.Transaction, error) { + return _IFastBridgeV2.Contract.Claim(&_IFastBridgeV2.TransactOpts, request, to) +} + +// Claim is a paid mutator transaction binding the contract method 0x41fcb612. +// +// Solidity: function claim(bytes request, address to) returns() +func (_IFastBridgeV2 *IFastBridgeV2TransactorSession) Claim(request []byte, to common.Address) (*types.Transaction, error) { + return _IFastBridgeV2.Contract.Claim(&_IFastBridgeV2.TransactOpts, request, to) +} + +// Claim0 is a paid mutator transaction binding the contract method 0xc63ff8dd. +// +// Solidity: function claim(bytes request) returns() +func (_IFastBridgeV2 *IFastBridgeV2Transactor) Claim0(opts *bind.TransactOpts, request []byte) (*types.Transaction, error) { + return _IFastBridgeV2.contract.Transact(opts, "claim0", request) +} + +// Claim0 is a paid mutator transaction binding the contract method 0xc63ff8dd. +// +// Solidity: function claim(bytes request) returns() +func (_IFastBridgeV2 *IFastBridgeV2Session) Claim0(request []byte) (*types.Transaction, error) { + return _IFastBridgeV2.Contract.Claim0(&_IFastBridgeV2.TransactOpts, request) +} + +// Claim0 is a paid mutator transaction binding the contract method 0xc63ff8dd. +// +// Solidity: function claim(bytes request) returns() +func (_IFastBridgeV2 *IFastBridgeV2TransactorSession) Claim0(request []byte) (*types.Transaction, error) { + return _IFastBridgeV2.Contract.Claim0(&_IFastBridgeV2.TransactOpts, request) +} + +// Dispute is a paid mutator transaction binding the contract method 0xadd98c70. +// +// Solidity: function dispute(bytes32 transactionId) returns() +func (_IFastBridgeV2 *IFastBridgeV2Transactor) Dispute(opts *bind.TransactOpts, transactionId [32]byte) (*types.Transaction, error) { + return _IFastBridgeV2.contract.Transact(opts, "dispute", transactionId) +} + +// Dispute is a paid mutator transaction binding the contract method 0xadd98c70. +// +// Solidity: function dispute(bytes32 transactionId) returns() +func (_IFastBridgeV2 *IFastBridgeV2Session) Dispute(transactionId [32]byte) (*types.Transaction, error) { + return _IFastBridgeV2.Contract.Dispute(&_IFastBridgeV2.TransactOpts, transactionId) +} + +// Dispute is a paid mutator transaction binding the contract method 0xadd98c70. +// +// Solidity: function dispute(bytes32 transactionId) returns() +func (_IFastBridgeV2 *IFastBridgeV2TransactorSession) Dispute(transactionId [32]byte) (*types.Transaction, error) { + return _IFastBridgeV2.Contract.Dispute(&_IFastBridgeV2.TransactOpts, transactionId) +} + +// Prove is a paid mutator transaction binding the contract method 0x18e4357d. +// +// Solidity: function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) returns() +func (_IFastBridgeV2 *IFastBridgeV2Transactor) Prove(opts *bind.TransactOpts, transactionId [32]byte, destTxHash [32]byte, relayer common.Address) (*types.Transaction, error) { + return _IFastBridgeV2.contract.Transact(opts, "prove", transactionId, destTxHash, relayer) +} + +// Prove is a paid mutator transaction binding the contract method 0x18e4357d. +// +// Solidity: function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) returns() +func (_IFastBridgeV2 *IFastBridgeV2Session) Prove(transactionId [32]byte, destTxHash [32]byte, relayer common.Address) (*types.Transaction, error) { + return _IFastBridgeV2.Contract.Prove(&_IFastBridgeV2.TransactOpts, transactionId, destTxHash, relayer) +} + +// Prove is a paid mutator transaction binding the contract method 0x18e4357d. +// +// Solidity: function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) returns() +func (_IFastBridgeV2 *IFastBridgeV2TransactorSession) Prove(transactionId [32]byte, destTxHash [32]byte, relayer common.Address) (*types.Transaction, error) { + return _IFastBridgeV2.Contract.Prove(&_IFastBridgeV2.TransactOpts, transactionId, destTxHash, relayer) +} + +// Prove0 is a paid mutator transaction binding the contract method 0x886d36ff. +// +// Solidity: function prove(bytes request, bytes32 destTxHash) returns() +func (_IFastBridgeV2 *IFastBridgeV2Transactor) Prove0(opts *bind.TransactOpts, request []byte, destTxHash [32]byte) (*types.Transaction, error) { + return _IFastBridgeV2.contract.Transact(opts, "prove0", request, destTxHash) +} + +// Prove0 is a paid mutator transaction binding the contract method 0x886d36ff. +// +// Solidity: function prove(bytes request, bytes32 destTxHash) returns() +func (_IFastBridgeV2 *IFastBridgeV2Session) Prove0(request []byte, destTxHash [32]byte) (*types.Transaction, error) { + return _IFastBridgeV2.Contract.Prove0(&_IFastBridgeV2.TransactOpts, request, destTxHash) +} + +// Prove0 is a paid mutator transaction binding the contract method 0x886d36ff. +// +// Solidity: function prove(bytes request, bytes32 destTxHash) returns() +func (_IFastBridgeV2 *IFastBridgeV2TransactorSession) Prove0(request []byte, destTxHash [32]byte) (*types.Transaction, error) { + return _IFastBridgeV2.Contract.Prove0(&_IFastBridgeV2.TransactOpts, request, destTxHash) +} + +// Refund is a paid mutator transaction binding the contract method 0x5eb7d946. +// +// Solidity: function refund(bytes request) returns() +func (_IFastBridgeV2 *IFastBridgeV2Transactor) Refund(opts *bind.TransactOpts, request []byte) (*types.Transaction, error) { + return _IFastBridgeV2.contract.Transact(opts, "refund", request) +} + +// Refund is a paid mutator transaction binding the contract method 0x5eb7d946. +// +// Solidity: function refund(bytes request) returns() +func (_IFastBridgeV2 *IFastBridgeV2Session) Refund(request []byte) (*types.Transaction, error) { + return _IFastBridgeV2.Contract.Refund(&_IFastBridgeV2.TransactOpts, request) +} + +// Refund is a paid mutator transaction binding the contract method 0x5eb7d946. +// +// Solidity: function refund(bytes request) returns() +func (_IFastBridgeV2 *IFastBridgeV2TransactorSession) Refund(request []byte) (*types.Transaction, error) { + return _IFastBridgeV2.Contract.Refund(&_IFastBridgeV2.TransactOpts, request) +} + +// Relay is a paid mutator transaction binding the contract method 0x8f0d6f17. +// +// Solidity: function relay(bytes request) payable returns() +func (_IFastBridgeV2 *IFastBridgeV2Transactor) Relay(opts *bind.TransactOpts, request []byte) (*types.Transaction, error) { + return _IFastBridgeV2.contract.Transact(opts, "relay", request) +} + +// Relay is a paid mutator transaction binding the contract method 0x8f0d6f17. +// +// Solidity: function relay(bytes request) payable returns() +func (_IFastBridgeV2 *IFastBridgeV2Session) Relay(request []byte) (*types.Transaction, error) { + return _IFastBridgeV2.Contract.Relay(&_IFastBridgeV2.TransactOpts, request) +} + +// Relay is a paid mutator transaction binding the contract method 0x8f0d6f17. +// +// Solidity: function relay(bytes request) payable returns() +func (_IFastBridgeV2 *IFastBridgeV2TransactorSession) Relay(request []byte) (*types.Transaction, error) { + return _IFastBridgeV2.Contract.Relay(&_IFastBridgeV2.TransactOpts, request) +} + +// Relay0 is a paid mutator transaction binding the contract method 0x9c9545f0. +// +// Solidity: function relay(bytes request, address relayer) payable returns() +func (_IFastBridgeV2 *IFastBridgeV2Transactor) Relay0(opts *bind.TransactOpts, request []byte, relayer common.Address) (*types.Transaction, error) { + return _IFastBridgeV2.contract.Transact(opts, "relay0", request, relayer) +} + +// Relay0 is a paid mutator transaction binding the contract method 0x9c9545f0. +// +// Solidity: function relay(bytes request, address relayer) payable returns() +func (_IFastBridgeV2 *IFastBridgeV2Session) Relay0(request []byte, relayer common.Address) (*types.Transaction, error) { + return _IFastBridgeV2.Contract.Relay0(&_IFastBridgeV2.TransactOpts, request, relayer) +} + +// Relay0 is a paid mutator transaction binding the contract method 0x9c9545f0. +// +// Solidity: function relay(bytes request, address relayer) payable returns() +func (_IFastBridgeV2 *IFastBridgeV2TransactorSession) Relay0(request []byte, relayer common.Address) (*types.Transaction, error) { + return _IFastBridgeV2.Contract.Relay0(&_IFastBridgeV2.TransactOpts, request, relayer) +} + +// IFastBridgeV2BridgeDepositClaimedIterator is returned from FilterBridgeDepositClaimed and is used to iterate over the raw logs and unpacked data for BridgeDepositClaimed events raised by the IFastBridgeV2 contract. +type IFastBridgeV2BridgeDepositClaimedIterator struct { + Event *IFastBridgeV2BridgeDepositClaimed // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *IFastBridgeV2BridgeDepositClaimedIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(IFastBridgeV2BridgeDepositClaimed) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(IFastBridgeV2BridgeDepositClaimed) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *IFastBridgeV2BridgeDepositClaimedIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *IFastBridgeV2BridgeDepositClaimedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// IFastBridgeV2BridgeDepositClaimed represents a BridgeDepositClaimed event raised by the IFastBridgeV2 contract. +type IFastBridgeV2BridgeDepositClaimed struct { + TransactionId [32]byte + Relayer common.Address + To common.Address + Token common.Address + Amount *big.Int + Raw types.Log // Blockchain specific contextual infos +} + +// FilterBridgeDepositClaimed is a free log retrieval operation binding the contract event 0x582211c35a2139ac3bbaac74663c6a1f56c6cbb658b41fe11fd45a82074ac678. +// +// Solidity: event BridgeDepositClaimed(bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount) +func (_IFastBridgeV2 *IFastBridgeV2Filterer) FilterBridgeDepositClaimed(opts *bind.FilterOpts, transactionId [][32]byte, relayer []common.Address, to []common.Address) (*IFastBridgeV2BridgeDepositClaimedIterator, error) { + + var transactionIdRule []interface{} + for _, transactionIdItem := range transactionId { + transactionIdRule = append(transactionIdRule, transactionIdItem) + } + var relayerRule []interface{} + for _, relayerItem := range relayer { + relayerRule = append(relayerRule, relayerItem) + } + var toRule []interface{} + for _, toItem := range to { + toRule = append(toRule, toItem) + } + + logs, sub, err := _IFastBridgeV2.contract.FilterLogs(opts, "BridgeDepositClaimed", transactionIdRule, relayerRule, toRule) + if err != nil { + return nil, err + } + return &IFastBridgeV2BridgeDepositClaimedIterator{contract: _IFastBridgeV2.contract, event: "BridgeDepositClaimed", logs: logs, sub: sub}, nil +} + +// WatchBridgeDepositClaimed is a free log subscription operation binding the contract event 0x582211c35a2139ac3bbaac74663c6a1f56c6cbb658b41fe11fd45a82074ac678. +// +// Solidity: event BridgeDepositClaimed(bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount) +func (_IFastBridgeV2 *IFastBridgeV2Filterer) WatchBridgeDepositClaimed(opts *bind.WatchOpts, sink chan<- *IFastBridgeV2BridgeDepositClaimed, transactionId [][32]byte, relayer []common.Address, to []common.Address) (event.Subscription, error) { + + var transactionIdRule []interface{} + for _, transactionIdItem := range transactionId { + transactionIdRule = append(transactionIdRule, transactionIdItem) + } + var relayerRule []interface{} + for _, relayerItem := range relayer { + relayerRule = append(relayerRule, relayerItem) + } + var toRule []interface{} + for _, toItem := range to { + toRule = append(toRule, toItem) + } + + logs, sub, err := _IFastBridgeV2.contract.WatchLogs(opts, "BridgeDepositClaimed", transactionIdRule, relayerRule, toRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(IFastBridgeV2BridgeDepositClaimed) + if err := _IFastBridgeV2.contract.UnpackLog(event, "BridgeDepositClaimed", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseBridgeDepositClaimed is a log parse operation binding the contract event 0x582211c35a2139ac3bbaac74663c6a1f56c6cbb658b41fe11fd45a82074ac678. +// +// Solidity: event BridgeDepositClaimed(bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount) +func (_IFastBridgeV2 *IFastBridgeV2Filterer) ParseBridgeDepositClaimed(log types.Log) (*IFastBridgeV2BridgeDepositClaimed, error) { + event := new(IFastBridgeV2BridgeDepositClaimed) + if err := _IFastBridgeV2.contract.UnpackLog(event, "BridgeDepositClaimed", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// IFastBridgeV2BridgeDepositRefundedIterator is returned from FilterBridgeDepositRefunded and is used to iterate over the raw logs and unpacked data for BridgeDepositRefunded events raised by the IFastBridgeV2 contract. +type IFastBridgeV2BridgeDepositRefundedIterator struct { + Event *IFastBridgeV2BridgeDepositRefunded // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *IFastBridgeV2BridgeDepositRefundedIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(IFastBridgeV2BridgeDepositRefunded) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(IFastBridgeV2BridgeDepositRefunded) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *IFastBridgeV2BridgeDepositRefundedIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *IFastBridgeV2BridgeDepositRefundedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// IFastBridgeV2BridgeDepositRefunded represents a BridgeDepositRefunded event raised by the IFastBridgeV2 contract. +type IFastBridgeV2BridgeDepositRefunded struct { + TransactionId [32]byte + To common.Address + Token common.Address + Amount *big.Int + Raw types.Log // Blockchain specific contextual infos +} + +// FilterBridgeDepositRefunded is a free log retrieval operation binding the contract event 0xb4c55c0c9bc613519b920e88748090150b890a875d307f21bea7d4fb2e8bc958. +// +// Solidity: event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount) +func (_IFastBridgeV2 *IFastBridgeV2Filterer) FilterBridgeDepositRefunded(opts *bind.FilterOpts, transactionId [][32]byte, to []common.Address) (*IFastBridgeV2BridgeDepositRefundedIterator, error) { + + var transactionIdRule []interface{} + for _, transactionIdItem := range transactionId { + transactionIdRule = append(transactionIdRule, transactionIdItem) + } + var toRule []interface{} + for _, toItem := range to { + toRule = append(toRule, toItem) + } + + logs, sub, err := _IFastBridgeV2.contract.FilterLogs(opts, "BridgeDepositRefunded", transactionIdRule, toRule) + if err != nil { + return nil, err + } + return &IFastBridgeV2BridgeDepositRefundedIterator{contract: _IFastBridgeV2.contract, event: "BridgeDepositRefunded", logs: logs, sub: sub}, nil +} + +// WatchBridgeDepositRefunded is a free log subscription operation binding the contract event 0xb4c55c0c9bc613519b920e88748090150b890a875d307f21bea7d4fb2e8bc958. +// +// Solidity: event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount) +func (_IFastBridgeV2 *IFastBridgeV2Filterer) WatchBridgeDepositRefunded(opts *bind.WatchOpts, sink chan<- *IFastBridgeV2BridgeDepositRefunded, transactionId [][32]byte, to []common.Address) (event.Subscription, error) { + + var transactionIdRule []interface{} + for _, transactionIdItem := range transactionId { + transactionIdRule = append(transactionIdRule, transactionIdItem) + } + var toRule []interface{} + for _, toItem := range to { + toRule = append(toRule, toItem) + } + + logs, sub, err := _IFastBridgeV2.contract.WatchLogs(opts, "BridgeDepositRefunded", transactionIdRule, toRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(IFastBridgeV2BridgeDepositRefunded) + if err := _IFastBridgeV2.contract.UnpackLog(event, "BridgeDepositRefunded", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseBridgeDepositRefunded is a log parse operation binding the contract event 0xb4c55c0c9bc613519b920e88748090150b890a875d307f21bea7d4fb2e8bc958. +// +// Solidity: event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount) +func (_IFastBridgeV2 *IFastBridgeV2Filterer) ParseBridgeDepositRefunded(log types.Log) (*IFastBridgeV2BridgeDepositRefunded, error) { + event := new(IFastBridgeV2BridgeDepositRefunded) + if err := _IFastBridgeV2.contract.UnpackLog(event, "BridgeDepositRefunded", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// IFastBridgeV2BridgeProofDisputedIterator is returned from FilterBridgeProofDisputed and is used to iterate over the raw logs and unpacked data for BridgeProofDisputed events raised by the IFastBridgeV2 contract. +type IFastBridgeV2BridgeProofDisputedIterator struct { + Event *IFastBridgeV2BridgeProofDisputed // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *IFastBridgeV2BridgeProofDisputedIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(IFastBridgeV2BridgeProofDisputed) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(IFastBridgeV2BridgeProofDisputed) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *IFastBridgeV2BridgeProofDisputedIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *IFastBridgeV2BridgeProofDisputedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// IFastBridgeV2BridgeProofDisputed represents a BridgeProofDisputed event raised by the IFastBridgeV2 contract. +type IFastBridgeV2BridgeProofDisputed struct { + TransactionId [32]byte + Relayer common.Address + Raw types.Log // Blockchain specific contextual infos +} + +// FilterBridgeProofDisputed is a free log retrieval operation binding the contract event 0x0695cf1d39b3055dcd0fe02d8b47eaf0d5a13e1996de925de59d0ef9b7f7fad4. +// +// Solidity: event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer) +func (_IFastBridgeV2 *IFastBridgeV2Filterer) FilterBridgeProofDisputed(opts *bind.FilterOpts, transactionId [][32]byte, relayer []common.Address) (*IFastBridgeV2BridgeProofDisputedIterator, error) { + + var transactionIdRule []interface{} + for _, transactionIdItem := range transactionId { + transactionIdRule = append(transactionIdRule, transactionIdItem) + } + var relayerRule []interface{} + for _, relayerItem := range relayer { + relayerRule = append(relayerRule, relayerItem) + } + + logs, sub, err := _IFastBridgeV2.contract.FilterLogs(opts, "BridgeProofDisputed", transactionIdRule, relayerRule) + if err != nil { + return nil, err + } + return &IFastBridgeV2BridgeProofDisputedIterator{contract: _IFastBridgeV2.contract, event: "BridgeProofDisputed", logs: logs, sub: sub}, nil +} + +// WatchBridgeProofDisputed is a free log subscription operation binding the contract event 0x0695cf1d39b3055dcd0fe02d8b47eaf0d5a13e1996de925de59d0ef9b7f7fad4. +// +// Solidity: event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer) +func (_IFastBridgeV2 *IFastBridgeV2Filterer) WatchBridgeProofDisputed(opts *bind.WatchOpts, sink chan<- *IFastBridgeV2BridgeProofDisputed, transactionId [][32]byte, relayer []common.Address) (event.Subscription, error) { + + var transactionIdRule []interface{} + for _, transactionIdItem := range transactionId { + transactionIdRule = append(transactionIdRule, transactionIdItem) + } + var relayerRule []interface{} + for _, relayerItem := range relayer { + relayerRule = append(relayerRule, relayerItem) + } + + logs, sub, err := _IFastBridgeV2.contract.WatchLogs(opts, "BridgeProofDisputed", transactionIdRule, relayerRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(IFastBridgeV2BridgeProofDisputed) + if err := _IFastBridgeV2.contract.UnpackLog(event, "BridgeProofDisputed", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseBridgeProofDisputed is a log parse operation binding the contract event 0x0695cf1d39b3055dcd0fe02d8b47eaf0d5a13e1996de925de59d0ef9b7f7fad4. +// +// Solidity: event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer) +func (_IFastBridgeV2 *IFastBridgeV2Filterer) ParseBridgeProofDisputed(log types.Log) (*IFastBridgeV2BridgeProofDisputed, error) { + event := new(IFastBridgeV2BridgeProofDisputed) + if err := _IFastBridgeV2.contract.UnpackLog(event, "BridgeProofDisputed", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// IFastBridgeV2BridgeProofProvidedIterator is returned from FilterBridgeProofProvided and is used to iterate over the raw logs and unpacked data for BridgeProofProvided events raised by the IFastBridgeV2 contract. +type IFastBridgeV2BridgeProofProvidedIterator struct { + Event *IFastBridgeV2BridgeProofProvided // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *IFastBridgeV2BridgeProofProvidedIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(IFastBridgeV2BridgeProofProvided) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(IFastBridgeV2BridgeProofProvided) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *IFastBridgeV2BridgeProofProvidedIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *IFastBridgeV2BridgeProofProvidedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// IFastBridgeV2BridgeProofProvided represents a BridgeProofProvided event raised by the IFastBridgeV2 contract. +type IFastBridgeV2BridgeProofProvided struct { + TransactionId [32]byte + Relayer common.Address + TransactionHash [32]byte + Raw types.Log // Blockchain specific contextual infos +} + +// FilterBridgeProofProvided is a free log retrieval operation binding the contract event 0x4ac8af8a2cd87193d64dfc7a3b8d9923b714ec528b18725d080aa1299be0c5e4. +// +// Solidity: event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash) +func (_IFastBridgeV2 *IFastBridgeV2Filterer) FilterBridgeProofProvided(opts *bind.FilterOpts, transactionId [][32]byte, relayer []common.Address) (*IFastBridgeV2BridgeProofProvidedIterator, error) { + + var transactionIdRule []interface{} + for _, transactionIdItem := range transactionId { + transactionIdRule = append(transactionIdRule, transactionIdItem) + } + var relayerRule []interface{} + for _, relayerItem := range relayer { + relayerRule = append(relayerRule, relayerItem) + } + + logs, sub, err := _IFastBridgeV2.contract.FilterLogs(opts, "BridgeProofProvided", transactionIdRule, relayerRule) + if err != nil { + return nil, err + } + return &IFastBridgeV2BridgeProofProvidedIterator{contract: _IFastBridgeV2.contract, event: "BridgeProofProvided", logs: logs, sub: sub}, nil +} + +// WatchBridgeProofProvided is a free log subscription operation binding the contract event 0x4ac8af8a2cd87193d64dfc7a3b8d9923b714ec528b18725d080aa1299be0c5e4. +// +// Solidity: event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash) +func (_IFastBridgeV2 *IFastBridgeV2Filterer) WatchBridgeProofProvided(opts *bind.WatchOpts, sink chan<- *IFastBridgeV2BridgeProofProvided, transactionId [][32]byte, relayer []common.Address) (event.Subscription, error) { + + var transactionIdRule []interface{} + for _, transactionIdItem := range transactionId { + transactionIdRule = append(transactionIdRule, transactionIdItem) + } + var relayerRule []interface{} + for _, relayerItem := range relayer { + relayerRule = append(relayerRule, relayerItem) + } + + logs, sub, err := _IFastBridgeV2.contract.WatchLogs(opts, "BridgeProofProvided", transactionIdRule, relayerRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(IFastBridgeV2BridgeProofProvided) + if err := _IFastBridgeV2.contract.UnpackLog(event, "BridgeProofProvided", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseBridgeProofProvided is a log parse operation binding the contract event 0x4ac8af8a2cd87193d64dfc7a3b8d9923b714ec528b18725d080aa1299be0c5e4. +// +// Solidity: event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash) +func (_IFastBridgeV2 *IFastBridgeV2Filterer) ParseBridgeProofProvided(log types.Log) (*IFastBridgeV2BridgeProofProvided, error) { + event := new(IFastBridgeV2BridgeProofProvided) + if err := _IFastBridgeV2.contract.UnpackLog(event, "BridgeProofProvided", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// IFastBridgeV2BridgeQuoteDetailsIterator is returned from FilterBridgeQuoteDetails and is used to iterate over the raw logs and unpacked data for BridgeQuoteDetails events raised by the IFastBridgeV2 contract. +type IFastBridgeV2BridgeQuoteDetailsIterator struct { + Event *IFastBridgeV2BridgeQuoteDetails // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *IFastBridgeV2BridgeQuoteDetailsIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(IFastBridgeV2BridgeQuoteDetails) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(IFastBridgeV2BridgeQuoteDetails) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *IFastBridgeV2BridgeQuoteDetailsIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *IFastBridgeV2BridgeQuoteDetailsIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// IFastBridgeV2BridgeQuoteDetails represents a BridgeQuoteDetails event raised by the IFastBridgeV2 contract. +type IFastBridgeV2BridgeQuoteDetails struct { + TransactionId [32]byte + QuoteId []byte + Raw types.Log // Blockchain specific contextual infos +} + +// FilterBridgeQuoteDetails is a free log retrieval operation binding the contract event 0x3120e2bb59c86aca6890191a589a96af3662838efa374fbdcdf4c95bfe4a6c0e. +// +// Solidity: event BridgeQuoteDetails(bytes32 indexed transactionId, bytes quoteId) +func (_IFastBridgeV2 *IFastBridgeV2Filterer) FilterBridgeQuoteDetails(opts *bind.FilterOpts, transactionId [][32]byte) (*IFastBridgeV2BridgeQuoteDetailsIterator, error) { + + var transactionIdRule []interface{} + for _, transactionIdItem := range transactionId { + transactionIdRule = append(transactionIdRule, transactionIdItem) + } + + logs, sub, err := _IFastBridgeV2.contract.FilterLogs(opts, "BridgeQuoteDetails", transactionIdRule) + if err != nil { + return nil, err + } + return &IFastBridgeV2BridgeQuoteDetailsIterator{contract: _IFastBridgeV2.contract, event: "BridgeQuoteDetails", logs: logs, sub: sub}, nil +} + +// WatchBridgeQuoteDetails is a free log subscription operation binding the contract event 0x3120e2bb59c86aca6890191a589a96af3662838efa374fbdcdf4c95bfe4a6c0e. +// +// Solidity: event BridgeQuoteDetails(bytes32 indexed transactionId, bytes quoteId) +func (_IFastBridgeV2 *IFastBridgeV2Filterer) WatchBridgeQuoteDetails(opts *bind.WatchOpts, sink chan<- *IFastBridgeV2BridgeQuoteDetails, transactionId [][32]byte) (event.Subscription, error) { + + var transactionIdRule []interface{} + for _, transactionIdItem := range transactionId { + transactionIdRule = append(transactionIdRule, transactionIdItem) + } + + logs, sub, err := _IFastBridgeV2.contract.WatchLogs(opts, "BridgeQuoteDetails", transactionIdRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(IFastBridgeV2BridgeQuoteDetails) + if err := _IFastBridgeV2.contract.UnpackLog(event, "BridgeQuoteDetails", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseBridgeQuoteDetails is a log parse operation binding the contract event 0x3120e2bb59c86aca6890191a589a96af3662838efa374fbdcdf4c95bfe4a6c0e. +// +// Solidity: event BridgeQuoteDetails(bytes32 indexed transactionId, bytes quoteId) +func (_IFastBridgeV2 *IFastBridgeV2Filterer) ParseBridgeQuoteDetails(log types.Log) (*IFastBridgeV2BridgeQuoteDetails, error) { + event := new(IFastBridgeV2BridgeQuoteDetails) + if err := _IFastBridgeV2.contract.UnpackLog(event, "BridgeQuoteDetails", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// IFastBridgeV2BridgeRelayedIterator is returned from FilterBridgeRelayed and is used to iterate over the raw logs and unpacked data for BridgeRelayed events raised by the IFastBridgeV2 contract. +type IFastBridgeV2BridgeRelayedIterator struct { + Event *IFastBridgeV2BridgeRelayed // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *IFastBridgeV2BridgeRelayedIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(IFastBridgeV2BridgeRelayed) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(IFastBridgeV2BridgeRelayed) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *IFastBridgeV2BridgeRelayedIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *IFastBridgeV2BridgeRelayedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// IFastBridgeV2BridgeRelayed represents a BridgeRelayed event raised by the IFastBridgeV2 contract. +type IFastBridgeV2BridgeRelayed struct { + TransactionId [32]byte + Relayer common.Address + To common.Address + OriginChainId uint32 + OriginToken common.Address + DestToken common.Address + OriginAmount *big.Int + DestAmount *big.Int + ChainGasAmount *big.Int + Raw types.Log // Blockchain specific contextual infos +} + +// FilterBridgeRelayed is a free log retrieval operation binding the contract event 0xf8ae392d784b1ea5e8881bfa586d81abf07ef4f1e2fc75f7fe51c90f05199a5c. +// +// Solidity: event BridgeRelayed(bytes32 indexed transactionId, address indexed relayer, address indexed to, uint32 originChainId, address originToken, address destToken, uint256 originAmount, uint256 destAmount, uint256 chainGasAmount) +func (_IFastBridgeV2 *IFastBridgeV2Filterer) FilterBridgeRelayed(opts *bind.FilterOpts, transactionId [][32]byte, relayer []common.Address, to []common.Address) (*IFastBridgeV2BridgeRelayedIterator, error) { + + var transactionIdRule []interface{} + for _, transactionIdItem := range transactionId { + transactionIdRule = append(transactionIdRule, transactionIdItem) + } + var relayerRule []interface{} + for _, relayerItem := range relayer { + relayerRule = append(relayerRule, relayerItem) + } + var toRule []interface{} + for _, toItem := range to { + toRule = append(toRule, toItem) + } + + logs, sub, err := _IFastBridgeV2.contract.FilterLogs(opts, "BridgeRelayed", transactionIdRule, relayerRule, toRule) + if err != nil { + return nil, err + } + return &IFastBridgeV2BridgeRelayedIterator{contract: _IFastBridgeV2.contract, event: "BridgeRelayed", logs: logs, sub: sub}, nil +} + +// WatchBridgeRelayed is a free log subscription operation binding the contract event 0xf8ae392d784b1ea5e8881bfa586d81abf07ef4f1e2fc75f7fe51c90f05199a5c. +// +// Solidity: event BridgeRelayed(bytes32 indexed transactionId, address indexed relayer, address indexed to, uint32 originChainId, address originToken, address destToken, uint256 originAmount, uint256 destAmount, uint256 chainGasAmount) +func (_IFastBridgeV2 *IFastBridgeV2Filterer) WatchBridgeRelayed(opts *bind.WatchOpts, sink chan<- *IFastBridgeV2BridgeRelayed, transactionId [][32]byte, relayer []common.Address, to []common.Address) (event.Subscription, error) { + + var transactionIdRule []interface{} + for _, transactionIdItem := range transactionId { + transactionIdRule = append(transactionIdRule, transactionIdItem) + } + var relayerRule []interface{} + for _, relayerItem := range relayer { + relayerRule = append(relayerRule, relayerItem) + } + var toRule []interface{} + for _, toItem := range to { + toRule = append(toRule, toItem) + } + + logs, sub, err := _IFastBridgeV2.contract.WatchLogs(opts, "BridgeRelayed", transactionIdRule, relayerRule, toRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(IFastBridgeV2BridgeRelayed) + if err := _IFastBridgeV2.contract.UnpackLog(event, "BridgeRelayed", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseBridgeRelayed is a log parse operation binding the contract event 0xf8ae392d784b1ea5e8881bfa586d81abf07ef4f1e2fc75f7fe51c90f05199a5c. +// +// Solidity: event BridgeRelayed(bytes32 indexed transactionId, address indexed relayer, address indexed to, uint32 originChainId, address originToken, address destToken, uint256 originAmount, uint256 destAmount, uint256 chainGasAmount) +func (_IFastBridgeV2 *IFastBridgeV2Filterer) ParseBridgeRelayed(log types.Log) (*IFastBridgeV2BridgeRelayed, error) { + event := new(IFastBridgeV2BridgeRelayed) + if err := _IFastBridgeV2.contract.UnpackLog(event, "BridgeRelayed", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// IFastBridgeV2BridgeRequestedIterator is returned from FilterBridgeRequested and is used to iterate over the raw logs and unpacked data for BridgeRequested events raised by the IFastBridgeV2 contract. +type IFastBridgeV2BridgeRequestedIterator struct { + Event *IFastBridgeV2BridgeRequested // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *IFastBridgeV2BridgeRequestedIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(IFastBridgeV2BridgeRequested) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(IFastBridgeV2BridgeRequested) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *IFastBridgeV2BridgeRequestedIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *IFastBridgeV2BridgeRequestedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// IFastBridgeV2BridgeRequested represents a BridgeRequested event raised by the IFastBridgeV2 contract. +type IFastBridgeV2BridgeRequested struct { + TransactionId [32]byte + Sender common.Address + Request []byte + DestChainId uint32 + OriginToken common.Address + DestToken common.Address + OriginAmount *big.Int + DestAmount *big.Int + SendChainGas bool + Raw types.Log // Blockchain specific contextual infos +} + +// FilterBridgeRequested is a free log retrieval operation binding the contract event 0x120ea0364f36cdac7983bcfdd55270ca09d7f9b314a2ebc425a3b01ab1d6403a. +// +// Solidity: event BridgeRequested(bytes32 indexed transactionId, address indexed sender, bytes request, uint32 destChainId, address originToken, address destToken, uint256 originAmount, uint256 destAmount, bool sendChainGas) +func (_IFastBridgeV2 *IFastBridgeV2Filterer) FilterBridgeRequested(opts *bind.FilterOpts, transactionId [][32]byte, sender []common.Address) (*IFastBridgeV2BridgeRequestedIterator, error) { + + var transactionIdRule []interface{} + for _, transactionIdItem := range transactionId { + transactionIdRule = append(transactionIdRule, transactionIdItem) + } + var senderRule []interface{} + for _, senderItem := range sender { + senderRule = append(senderRule, senderItem) + } + + logs, sub, err := _IFastBridgeV2.contract.FilterLogs(opts, "BridgeRequested", transactionIdRule, senderRule) + if err != nil { + return nil, err + } + return &IFastBridgeV2BridgeRequestedIterator{contract: _IFastBridgeV2.contract, event: "BridgeRequested", logs: logs, sub: sub}, nil +} + +// WatchBridgeRequested is a free log subscription operation binding the contract event 0x120ea0364f36cdac7983bcfdd55270ca09d7f9b314a2ebc425a3b01ab1d6403a. +// +// Solidity: event BridgeRequested(bytes32 indexed transactionId, address indexed sender, bytes request, uint32 destChainId, address originToken, address destToken, uint256 originAmount, uint256 destAmount, bool sendChainGas) +func (_IFastBridgeV2 *IFastBridgeV2Filterer) WatchBridgeRequested(opts *bind.WatchOpts, sink chan<- *IFastBridgeV2BridgeRequested, transactionId [][32]byte, sender []common.Address) (event.Subscription, error) { + + var transactionIdRule []interface{} + for _, transactionIdItem := range transactionId { + transactionIdRule = append(transactionIdRule, transactionIdItem) + } + var senderRule []interface{} + for _, senderItem := range sender { + senderRule = append(senderRule, senderItem) + } + + logs, sub, err := _IFastBridgeV2.contract.WatchLogs(opts, "BridgeRequested", transactionIdRule, senderRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(IFastBridgeV2BridgeRequested) + if err := _IFastBridgeV2.contract.UnpackLog(event, "BridgeRequested", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseBridgeRequested is a log parse operation binding the contract event 0x120ea0364f36cdac7983bcfdd55270ca09d7f9b314a2ebc425a3b01ab1d6403a. +// +// Solidity: event BridgeRequested(bytes32 indexed transactionId, address indexed sender, bytes request, uint32 destChainId, address originToken, address destToken, uint256 originAmount, uint256 destAmount, bool sendChainGas) +func (_IFastBridgeV2 *IFastBridgeV2Filterer) ParseBridgeRequested(log types.Log) (*IFastBridgeV2BridgeRequested, error) { + event := new(IFastBridgeV2BridgeRequested) + if err := _IFastBridgeV2.contract.UnpackLog(event, "BridgeRequested", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} diff --git a/services/rfq/contracts/bridgetransactionv2/bridgetransactionv2.contractinfo.json b/services/rfq/contracts/bridgetransactionv2/bridgetransactionv2.contractinfo.json new file mode 100644 index 0000000000..90094d2f4d --- /dev/null +++ b/services/rfq/contracts/bridgetransactionv2/bridgetransactionv2.contractinfo.json @@ -0,0 +1 @@ +{"solidity/BridgeTransactionV2Harness.sol:BridgeTransactionV2Harness":{"code":"0x608060405234801561001057600080fd5b50610e65806100206000396000f3fe608060405234801561001057600080fd5b50600436106101365760003560e01c80637d67c5a7116100b25780639c53880211610081578063e79f178211610066578063e79f1782146102d7578063e938730e146102ea578063faef535a146102fd57600080fd5b80639c538802146102b1578063dcafa970146102c457600080fd5b80637d67c5a714610252578063938328991461027857806393bb0d801461028b5780639bdb46fe1461029e57600080fd5b806337518e50116101095780635c3fa4c0116100ee5780635c3fa4c0146102045780636907efd71461022c5780637241b9cb1461023f57600080fd5b806337518e50146101b95780634e765004146101f157600080fd5b80630af3f4031461013b57806312d0c51214610165578063230602c1146101865780632465702414610199575b600080fd5b61014e610149366004610868565b61031d565b60405161015c9291906108da565b60405180910390f35b610178610173366004610868565b610335565b60405190815260200161015c565b610178610194366004610868565b610344565b6101ac6101a7366004610868565b610351565b60405161015c9190610995565b6101cc6101c7366004610868565b61044e565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200161015c565b6101786101ff366004610868565b61045d565b610217610212366004610868565b610469565b60405163ffffffff909116815260200161015c565b61017861023a366004610868565b610478565b61017861024d366004610868565b610485565b610265610260366004610868565b610491565b60405161ffff909116815260200161015c565b6101cc610286366004610868565b61049d565b610217610299366004610868565b6104ac565b6101cc6102ac366004610868565b6104bb565b6101cc6102bf366004610868565b6104ca565b6101cc6102d2366004610868565b6104d9565b6101786102e5366004610868565b6104e8565b6101786102f8366004610868565b6104f4565b61031061030b366004610c34565b610500565b60405161015c9190610d69565b36600061032a8484610511565b915091509250929050565b6000607a8301355b9392505050565b600061012e83013561033d565b610444604051806101e00160405280600063ffffffff168152602001600063ffffffff168152602001600073ffffffffffffffffffffffffffffffffffffffff168152602001600073ffffffffffffffffffffffffffffffffffffffff168152602001600073ffffffffffffffffffffffffffffffffffffffff168152602001600073ffffffffffffffffffffffffffffffffffffffff1681526020016000815260200160008152602001600081526020016000815260200160008152602001600073ffffffffffffffffffffffffffffffffffffffff1681526020016000815260200160008152602001606081525090565b61033d8383610522565b6000604683013560601c61033d565b600060da83013561033d565b6000600683013560e01c61033d565b600061010e83013561033d565b6000605a83013561033d565b6000823560f01c61033d565b6000603283013560601c61033d565b6000600283013560e01c61033d565b6000600a83013560601c61033d565b6000601e83013560601c61033d565b600060fa83013560601c61033d565b600060ba83013561033d565b6000609a83013561033d565b606061050b82610705565b92915050565b36600061032a8361014e8187610d7c565b610615604051806101e00160405280600063ffffffff168152602001600063ffffffff168152602001600073ffffffffffffffffffffffffffffffffffffffff168152602001600073ffffffffffffffffffffffffffffffffffffffff168152602001600073ffffffffffffffffffffffffffffffffffffffff168152602001600073ffffffffffffffffffffffffffffffffffffffff1681526020016000815260200160008152602001600081526020016000815260200160008152602001600073ffffffffffffffffffffffffffffffffffffffff1681526020016000815260200160008152602001606081525090565b600283013560e090811c82526006840135811c6020830152600a840135606090811c6040840152601e850135811c818401526032850135811c60808401526046850135811c60a0840152605a85013560c0840152607a85013591830191909152609a84013561010083015260ba84013561012083015260da84013561014083015260fa840135901c61016082015261010e83013561018082015261012e8301356101a08201526106c58383610511565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152505050506101c082015292915050565b8051602080830151604080850151606086810151608088015160a089015160c08a015195517e02000000000000000000000000000000000000000000000000000000000000988101989098527fffffffff0000000000000000000000000000000000000000000000000000000060e0998a1b811660228a01529690981b90951660268701527fffffffffffffffffffffffffffffffffffffffff00000000000000000000000092821b8316602a870152811b8216603e86015292831b8116605285015293821b9093166066830152607a820192909252600090609a01604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529082905260e08501516101008601516101208701516101408801516101608901516101808a01516101a08b01516101c08c0151979950610851988a9890602001610da6565b604051602081830303815290604052915050919050565b6000806020838503121561087b57600080fd5b823567ffffffffffffffff8082111561089357600080fd5b818501915085601f8301126108a757600080fd5b8135818111156108b657600080fd5b8660208285010111156108c857600080fd5b60209290920196919550909350505050565b60208152816020820152818360408301376000818301604090810191909152601f9092017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0160101919050565b60005b8381101561094257818101518382015260200161092a565b50506000910152565b60008151808452610963816020860160208601610927565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b602081526109ac60208201835163ffffffff169052565b600060208301516109c5604084018263ffffffff169052565b50604083015173ffffffffffffffffffffffffffffffffffffffff8116606084015250606083015173ffffffffffffffffffffffffffffffffffffffff8116608084015250608083015173ffffffffffffffffffffffffffffffffffffffff811660a08401525060a083015173ffffffffffffffffffffffffffffffffffffffff811660c08401525060c083015160e08381019190915283015161010080840191909152830151610120808401919091528301516101408084019190915283015161016080840191909152830151610180610ab78185018373ffffffffffffffffffffffffffffffffffffffff169052565b8401516101a0848101919091528401516101c0808501919091528401516101e0808501529050610aeb61020084018261094b565b949350505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6040516101e0810167ffffffffffffffff81118282101715610b4657610b46610af3565b60405290565b803563ffffffff81168114610b6057600080fd5b919050565b803573ffffffffffffffffffffffffffffffffffffffff81168114610b6057600080fd5b600082601f830112610b9a57600080fd5b813567ffffffffffffffff80821115610bb557610bb5610af3565b604051601f83017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f01168101908282118183101715610bfb57610bfb610af3565b81604052838152866020858801011115610c1457600080fd5b836020870160208301376000602085830101528094505050505092915050565b600060208284031215610c4657600080fd5b813567ffffffffffffffff80821115610c5e57600080fd5b908301906101e08286031215610c7357600080fd5b610c7b610b22565b610c8483610b4c565b8152610c9260208401610b4c565b6020820152610ca360408401610b65565b6040820152610cb460608401610b65565b6060820152610cc560808401610b65565b6080820152610cd660a08401610b65565b60a082015260c0838101359082015260e08084013590820152610100808401359082015261012080840135908201526101408084013590820152610160610d1e818501610b65565b9082015261018083810135908201526101a080840135908201526101c08084013583811115610d4c57600080fd5b610d5888828701610b89565b918301919091525095945050505050565b60208152600061033d602083018461094b565b60008085851115610d8c57600080fd5b83861115610d9957600080fd5b5050820193919092039150565b60008a51610db8818460208f01610927565b80830190508a81528960208201528860408201528760608201527fffffffffffffffffffffffffffffffffffffffff0000000000000000000000008760601b1660808201528560948201528460b48201528351610e1c8160d4840160208801610927565b0160d4019b9a505050505050505050505056fea2646970667358221220ec634eada85ddd9f3a51bdae8c8de0703366a52e644989f6d717509c24795d6864736f6c63430008180033","runtime-code":"0x608060405234801561001057600080fd5b50600436106101365760003560e01c80637d67c5a7116100b25780639c53880211610081578063e79f178211610066578063e79f1782146102d7578063e938730e146102ea578063faef535a146102fd57600080fd5b80639c538802146102b1578063dcafa970146102c457600080fd5b80637d67c5a714610252578063938328991461027857806393bb0d801461028b5780639bdb46fe1461029e57600080fd5b806337518e50116101095780635c3fa4c0116100ee5780635c3fa4c0146102045780636907efd71461022c5780637241b9cb1461023f57600080fd5b806337518e50146101b95780634e765004146101f157600080fd5b80630af3f4031461013b57806312d0c51214610165578063230602c1146101865780632465702414610199575b600080fd5b61014e610149366004610868565b61031d565b60405161015c9291906108da565b60405180910390f35b610178610173366004610868565b610335565b60405190815260200161015c565b610178610194366004610868565b610344565b6101ac6101a7366004610868565b610351565b60405161015c9190610995565b6101cc6101c7366004610868565b61044e565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200161015c565b6101786101ff366004610868565b61045d565b610217610212366004610868565b610469565b60405163ffffffff909116815260200161015c565b61017861023a366004610868565b610478565b61017861024d366004610868565b610485565b610265610260366004610868565b610491565b60405161ffff909116815260200161015c565b6101cc610286366004610868565b61049d565b610217610299366004610868565b6104ac565b6101cc6102ac366004610868565b6104bb565b6101cc6102bf366004610868565b6104ca565b6101cc6102d2366004610868565b6104d9565b6101786102e5366004610868565b6104e8565b6101786102f8366004610868565b6104f4565b61031061030b366004610c34565b610500565b60405161015c9190610d69565b36600061032a8484610511565b915091509250929050565b6000607a8301355b9392505050565b600061012e83013561033d565b610444604051806101e00160405280600063ffffffff168152602001600063ffffffff168152602001600073ffffffffffffffffffffffffffffffffffffffff168152602001600073ffffffffffffffffffffffffffffffffffffffff168152602001600073ffffffffffffffffffffffffffffffffffffffff168152602001600073ffffffffffffffffffffffffffffffffffffffff1681526020016000815260200160008152602001600081526020016000815260200160008152602001600073ffffffffffffffffffffffffffffffffffffffff1681526020016000815260200160008152602001606081525090565b61033d8383610522565b6000604683013560601c61033d565b600060da83013561033d565b6000600683013560e01c61033d565b600061010e83013561033d565b6000605a83013561033d565b6000823560f01c61033d565b6000603283013560601c61033d565b6000600283013560e01c61033d565b6000600a83013560601c61033d565b6000601e83013560601c61033d565b600060fa83013560601c61033d565b600060ba83013561033d565b6000609a83013561033d565b606061050b82610705565b92915050565b36600061032a8361014e8187610d7c565b610615604051806101e00160405280600063ffffffff168152602001600063ffffffff168152602001600073ffffffffffffffffffffffffffffffffffffffff168152602001600073ffffffffffffffffffffffffffffffffffffffff168152602001600073ffffffffffffffffffffffffffffffffffffffff168152602001600073ffffffffffffffffffffffffffffffffffffffff1681526020016000815260200160008152602001600081526020016000815260200160008152602001600073ffffffffffffffffffffffffffffffffffffffff1681526020016000815260200160008152602001606081525090565b600283013560e090811c82526006840135811c6020830152600a840135606090811c6040840152601e850135811c818401526032850135811c60808401526046850135811c60a0840152605a85013560c0840152607a85013591830191909152609a84013561010083015260ba84013561012083015260da84013561014083015260fa840135901c61016082015261010e83013561018082015261012e8301356101a08201526106c58383610511565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152505050506101c082015292915050565b8051602080830151604080850151606086810151608088015160a089015160c08a015195517e02000000000000000000000000000000000000000000000000000000000000988101989098527fffffffff0000000000000000000000000000000000000000000000000000000060e0998a1b811660228a01529690981b90951660268701527fffffffffffffffffffffffffffffffffffffffff00000000000000000000000092821b8316602a870152811b8216603e86015292831b8116605285015293821b9093166066830152607a820192909252600090609a01604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529082905260e08501516101008601516101208701516101408801516101608901516101808a01516101a08b01516101c08c0151979950610851988a9890602001610da6565b604051602081830303815290604052915050919050565b6000806020838503121561087b57600080fd5b823567ffffffffffffffff8082111561089357600080fd5b818501915085601f8301126108a757600080fd5b8135818111156108b657600080fd5b8660208285010111156108c857600080fd5b60209290920196919550909350505050565b60208152816020820152818360408301376000818301604090810191909152601f9092017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0160101919050565b60005b8381101561094257818101518382015260200161092a565b50506000910152565b60008151808452610963816020860160208601610927565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b602081526109ac60208201835163ffffffff169052565b600060208301516109c5604084018263ffffffff169052565b50604083015173ffffffffffffffffffffffffffffffffffffffff8116606084015250606083015173ffffffffffffffffffffffffffffffffffffffff8116608084015250608083015173ffffffffffffffffffffffffffffffffffffffff811660a08401525060a083015173ffffffffffffffffffffffffffffffffffffffff811660c08401525060c083015160e08381019190915283015161010080840191909152830151610120808401919091528301516101408084019190915283015161016080840191909152830151610180610ab78185018373ffffffffffffffffffffffffffffffffffffffff169052565b8401516101a0848101919091528401516101c0808501919091528401516101e0808501529050610aeb61020084018261094b565b949350505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6040516101e0810167ffffffffffffffff81118282101715610b4657610b46610af3565b60405290565b803563ffffffff81168114610b6057600080fd5b919050565b803573ffffffffffffffffffffffffffffffffffffffff81168114610b6057600080fd5b600082601f830112610b9a57600080fd5b813567ffffffffffffffff80821115610bb557610bb5610af3565b604051601f83017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f01168101908282118183101715610bfb57610bfb610af3565b81604052838152866020858801011115610c1457600080fd5b836020870160208301376000602085830101528094505050505092915050565b600060208284031215610c4657600080fd5b813567ffffffffffffffff80821115610c5e57600080fd5b908301906101e08286031215610c7357600080fd5b610c7b610b22565b610c8483610b4c565b8152610c9260208401610b4c565b6020820152610ca360408401610b65565b6040820152610cb460608401610b65565b6060820152610cc560808401610b65565b6080820152610cd660a08401610b65565b60a082015260c0838101359082015260e08084013590820152610100808401359082015261012080840135908201526101408084013590820152610160610d1e818501610b65565b9082015261018083810135908201526101a080840135908201526101c08084013583811115610d4c57600080fd5b610d5888828701610b89565b918301919091525095945050505050565b60208152600061033d602083018461094b565b60008085851115610d8c57600080fd5b83861115610d9957600080fd5b5050820193919092039150565b60008a51610db8818460208f01610927565b80830190508a81528960208201528860408201528760608201527fffffffffffffffffffffffffffffffffffffffff0000000000000000000000008760601b1660808201528560948201528460b48201528351610e1c8160d4840160208801610927565b0160d4019b9a505050505050505050505056fea2646970667358221220ec634eada85ddd9f3a51bdae8c8de0703366a52e644989f6d717509c24795d6864736f6c63430008180033","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.24 ^0.8.4;\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IFastBridgeV2.sol\n\ninterface IFastBridgeV2 is IFastBridge {\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n struct BridgeTxDetails {\n BridgeStatus status;\n uint32 destChainId;\n uint56 proofBlockTimestamp;\n address proofRelayer;\n }\n\n struct BridgeRelay {\n uint48 blockNumber;\n uint48 blockTimestamp;\n address relayer;\n }\n\n /// @notice New params introduced in the FastBridgeV2.\n /// We are passing fields from the older BridgeParams struct outside of this struct\n /// for backwards compatibility.\n /// Note: quoteRelayer and quoteExclusivitySeconds are either both zero (indicating no exclusivity)\n /// or both non-zero (indicating exclusivity for the given period).\n /// Note: zapNative \u003e 0 can NOT be used with destToken = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE (native token)\n /// @param quoteRelayer Relayer that provided the quote for the transaction\n /// @param quoteExclusivitySeconds Period of time the quote relayer is guaranteed exclusivity after user's deposit\n /// @param quoteId Unique quote identifier used for tracking the quote\n /// @param zapNative ETH value to send to the recipient (if any)\n /// @param zapData Parameters for the Zap to the destination recipient (if any)\n struct BridgeParamsV2 {\n address quoteRelayer;\n int256 quoteExclusivitySeconds;\n bytes quoteId;\n uint256 zapNative;\n bytes zapData;\n }\n\n /// @notice Updated bridge transaction struct to include parameters introduced in FastBridgeV2.\n /// Note: only `exclusivityRelayer` can fill such a transaction until `exclusivityEndTime`.\n struct BridgeTransactionV2 {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n // Note: sendChainGas flag from V1 is deprecated\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n address exclusivityRelayer;\n uint256 exclusivityEndTime;\n uint256 zapNative; // ETH value to send to the recipient (if any)\n bytes zapData; // data to pass for the Zap action (if any)\n }\n\n event BridgeQuoteDetails(bytes32 indexed transactionId, bytes quoteId);\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability\n /// to provide temporary exclusivity fill rights for the quote relayer.\n /// @param params The parameters required to bridge\n /// @param paramsV2 The parameters for exclusivity fill rights (optional, can be left empty)\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function relay(bytes memory request, address relayer) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param transactionId The transaction id associated with the encoded bridge transaction to prove\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital.\n /// @notice Can only send funds to the relayer address on the proof.\n /// @param request The encoded bridge transaction to claim on origin chain\n function claim(bytes memory request) external;\n /// @notice Checks if a transaction has been relayed\n /// @param transactionId The ID of the transaction to check\n /// @return True if the transaction has been relayed, false otherwise\n function bridgeRelays(bytes32 transactionId) external view returns (bool);\n\n /// @notice Returns the status of a bridge transaction\n /// @param transactionId The ID of the bridge transaction\n /// @return BridgeStatus Status of the bridge transaction\n function bridgeStatuses(bytes32 transactionId) external view returns (BridgeStatus);\n\n /// @notice Returns the timestamp and relayer of a bridge proof\n /// @param transactionId The ID of the bridge transaction\n /// @return timestamp The timestamp of the bridge proof\n /// @return relayer The relayer address of the bridge proof\n function bridgeProofs(bytes32 transactionId) external view returns (uint96 timestamp, address relayer);\n\n /// @notice Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\n /// @param request The bridge request to decode\n function getBridgeTransactionV2(bytes memory request) external view returns (BridgeTransactionV2 memory);\n}\n\n// contracts/libs/BridgeTransactionV2.sol\n\n// solhint-disable no-inline-assembly\nlibrary BridgeTransactionV2Lib {\n uint16 internal constant VERSION = 2;\n\n // Offsets of the fields in the packed BridgeTransactionV2 struct\n // uint16 version [000 .. 002)\n // uint32 originChainId [002 .. 006)\n // uint32 destChainId [006 .. 010)\n // address originSender [010 .. 030)\n // address destRecipient [030 .. 050)\n // address originToken [050 .. 070)\n // address destToken [070 .. 090)\n // uint256 originAmount [090 .. 122)\n // uint256 destAmount [122 .. 154)\n // uint256 originFeeAmount [154 .. 186)\n // uint256 deadline [186 .. 218)\n // uint256 nonce [218 .. 250)\n // address exclusivityRelayer [250 .. 270)\n // uint256 exclusivityEndTime [270 .. 302)\n // uint256 zapNative [302 .. 334)\n // bytes zapData [334 .. ***)\n\n // forgefmt: disable-start\n uint256 private constant OFFSET_ORIGIN_CHAIN_ID = 2;\n uint256 private constant OFFSET_DEST_CHAIN_ID = 6;\n uint256 private constant OFFSET_ORIGIN_SENDER = 10;\n uint256 private constant OFFSET_DEST_RECIPIENT = 30;\n uint256 private constant OFFSET_ORIGIN_TOKEN = 50;\n uint256 private constant OFFSET_DEST_TOKEN = 70;\n uint256 private constant OFFSET_ORIGIN_AMOUNT = 90;\n uint256 private constant OFFSET_DEST_AMOUNT = 122;\n uint256 private constant OFFSET_ORIGIN_FEE_AMOUNT = 154;\n uint256 private constant OFFSET_DEADLINE = 186;\n uint256 private constant OFFSET_NONCE = 218;\n uint256 private constant OFFSET_EXCLUSIVITY_RELAYER = 250;\n uint256 private constant OFFSET_EXCLUSIVITY_END_TIME = 270;\n uint256 private constant OFFSET_ZAP_NATIVE = 302;\n uint256 private constant OFFSET_ZAP_DATA = 334;\n // forgefmt: disable-end\n\n error BridgeTransactionV2__InvalidEncodedTx();\n error BridgeTransactionV2__UnsupportedVersion(uint16 version);\n\n /// @notice Validates the encoded transaction to be a tightly packed encoded payload for BridgeTransactionV2.\n /// @dev Checks the minimum length and the version, use this function before decoding any of the fields.\n function validateV2(bytes calldata encodedTx) internal pure {\n // Check the minimum length: must at least include all static fields.\n if (encodedTx.length \u003c OFFSET_ZAP_DATA) revert BridgeTransactionV2__InvalidEncodedTx();\n // Once we validated the length, we can be sure that the version field is present.\n uint16 version_ = version(encodedTx);\n if (version_ != VERSION) revert BridgeTransactionV2__UnsupportedVersion(version_);\n }\n\n /// @notice Encodes the BridgeTransactionV2 struct by tightly packing the fields.\n /// @dev `abi.decode` will not work as a result of the tightly packed fields. Use `decodeV2` to decode instead.\n function encodeV2(IFastBridgeV2.BridgeTransactionV2 memory bridgeTx) internal pure returns (bytes memory) {\n // We split the encoding into two parts to avoid stack-too-deep error\n bytes memory firstPart = abi.encodePacked(\n VERSION,\n bridgeTx.originChainId,\n bridgeTx.destChainId,\n bridgeTx.originSender,\n bridgeTx.destRecipient,\n bridgeTx.originToken,\n bridgeTx.destToken,\n bridgeTx.originAmount\n );\n return abi.encodePacked(\n firstPart,\n bridgeTx.destAmount,\n bridgeTx.originFeeAmount,\n // Note: we skip the deprecated `sendChainGas` flag, which was present in BridgeTransaction V1\n bridgeTx.deadline,\n bridgeTx.nonce,\n // New V2 fields: exclusivity\n bridgeTx.exclusivityRelayer,\n bridgeTx.exclusivityEndTime,\n // New V2 fields: Zap\n bridgeTx.zapNative,\n bridgeTx.zapData\n );\n }\n\n /// @notice Decodes the BridgeTransactionV2 struct from the encoded transaction.\n /// @dev Encoded BridgeTransactionV2 struct must be tightly packed.\n /// Use `validateV2` before decoding to ensure the encoded transaction is valid.\n function decodeV2(bytes calldata encodedTx)\n internal\n pure\n returns (IFastBridgeV2.BridgeTransactionV2 memory bridgeTx)\n {\n bridgeTx.originChainId = originChainId(encodedTx);\n bridgeTx.destChainId = destChainId(encodedTx);\n bridgeTx.originSender = originSender(encodedTx);\n bridgeTx.destRecipient = destRecipient(encodedTx);\n bridgeTx.originToken = originToken(encodedTx);\n bridgeTx.destToken = destToken(encodedTx);\n bridgeTx.originAmount = originAmount(encodedTx);\n bridgeTx.destAmount = destAmount(encodedTx);\n bridgeTx.originFeeAmount = originFeeAmount(encodedTx);\n bridgeTx.deadline = deadline(encodedTx);\n bridgeTx.nonce = nonce(encodedTx);\n bridgeTx.exclusivityRelayer = exclusivityRelayer(encodedTx);\n bridgeTx.exclusivityEndTime = exclusivityEndTime(encodedTx);\n bridgeTx.zapNative = zapNative(encodedTx);\n bridgeTx.zapData = zapData(encodedTx);\n }\n\n /// @notice Extracts the version from the encoded transaction.\n function version(bytes calldata encodedTx) internal pure returns (uint16 version_) {\n // Load 32 bytes from the start and shift it 240 bits to the right to get the highest 16 bits.\n assembly {\n version_ := shr(240, calldataload(encodedTx.offset))\n }\n }\n\n /// @notice Extracts the origin chain ID from the encoded transaction.\n function originChainId(bytes calldata encodedTx) internal pure returns (uint32 originChainId_) {\n // Load 32 bytes from the offset and shift it 224 bits to the right to get the highest 32 bits.\n assembly {\n originChainId_ := shr(224, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_CHAIN_ID)))\n }\n }\n\n /// @notice Extracts the destination chain ID from the encoded transaction.\n function destChainId(bytes calldata encodedTx) internal pure returns (uint32 destChainId_) {\n // Load 32 bytes from the offset and shift it 224 bits to the right to get the highest 32 bits.\n assembly {\n destChainId_ := shr(224, calldataload(add(encodedTx.offset, OFFSET_DEST_CHAIN_ID)))\n }\n }\n\n /// @notice Extracts the origin sender from the encoded transaction.\n function originSender(bytes calldata encodedTx) internal pure returns (address originSender_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n originSender_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_SENDER)))\n }\n }\n\n /// @notice Extracts the destination recipient from the encoded transaction.\n function destRecipient(bytes calldata encodedTx) internal pure returns (address destRecipient_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n destRecipient_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_DEST_RECIPIENT)))\n }\n }\n\n /// @notice Extracts the origin token from the encoded transaction.\n function originToken(bytes calldata encodedTx) internal pure returns (address originToken_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n originToken_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_TOKEN)))\n }\n }\n\n /// @notice Extracts the destination token from the encoded transaction.\n function destToken(bytes calldata encodedTx) internal pure returns (address destToken_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n destToken_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_DEST_TOKEN)))\n }\n }\n\n /// @notice Extracts the origin amount from the encoded transaction.\n function originAmount(bytes calldata encodedTx) internal pure returns (uint256 originAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n originAmount_ := calldataload(add(encodedTx.offset, OFFSET_ORIGIN_AMOUNT))\n }\n }\n\n /// @notice Extracts the destination amount from the encoded transaction.\n function destAmount(bytes calldata encodedTx) internal pure returns (uint256 destAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n destAmount_ := calldataload(add(encodedTx.offset, OFFSET_DEST_AMOUNT))\n }\n }\n\n /// @notice Extracts the origin fee amount from the encoded transaction.\n function originFeeAmount(bytes calldata encodedTx) internal pure returns (uint256 originFeeAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n originFeeAmount_ := calldataload(add(encodedTx.offset, OFFSET_ORIGIN_FEE_AMOUNT))\n }\n }\n\n /// @notice Extracts the deadline from the encoded transaction.\n function deadline(bytes calldata encodedTx) internal pure returns (uint256 deadline_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n deadline_ := calldataload(add(encodedTx.offset, OFFSET_DEADLINE))\n }\n }\n\n /// @notice Extracts the nonce from the encoded transaction.\n function nonce(bytes calldata encodedTx) internal pure returns (uint256 nonce_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n nonce_ := calldataload(add(encodedTx.offset, OFFSET_NONCE))\n }\n }\n\n /// @notice Extracts the exclusivity relayer from the encoded transaction.\n function exclusivityRelayer(bytes calldata encodedTx) internal pure returns (address exclusivityRelayer_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n exclusivityRelayer_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_EXCLUSIVITY_RELAYER)))\n }\n }\n\n /// @notice Extracts the exclusivity end time from the encoded transaction.\n function exclusivityEndTime(bytes calldata encodedTx) internal pure returns (uint256 exclusivityEndTime_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n exclusivityEndTime_ := calldataload(add(encodedTx.offset, OFFSET_EXCLUSIVITY_END_TIME))\n }\n }\n\n /// @notice Extracts the Zap's native value from the encoded transaction.\n function zapNative(bytes calldata encodedTx) internal pure returns (uint256 zapNative_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n zapNative_ := calldataload(add(encodedTx.offset, OFFSET_ZAP_NATIVE))\n }\n }\n\n /// @notice Extracts the Zap's data from the encoded transaction.\n function zapData(bytes calldata encodedTx) internal pure returns (bytes calldata zapData_) {\n zapData_ = encodedTx[OFFSET_ZAP_DATA:];\n }\n}\n\n// test/harnesses/BridgeTransactionV2Harness.sol\n\ncontract BridgeTransactionV2Harness {\n function encodeV2(IFastBridgeV2.BridgeTransactionV2 memory bridgeTx) public pure returns (bytes memory) {\n return BridgeTransactionV2Lib.encodeV2(bridgeTx);\n }\n\n function decodeV2(bytes calldata encodedTx) public pure returns (IFastBridgeV2.BridgeTransactionV2 memory) {\n return BridgeTransactionV2Lib.decodeV2(encodedTx);\n }\n\n function version(bytes calldata encodedTx) public pure returns (uint16) {\n return BridgeTransactionV2Lib.version(encodedTx);\n }\n\n function originChainId(bytes calldata encodedTx) public pure returns (uint32) {\n return BridgeTransactionV2Lib.originChainId(encodedTx);\n }\n\n function destChainId(bytes calldata encodedTx) public pure returns (uint32) {\n return BridgeTransactionV2Lib.destChainId(encodedTx);\n }\n\n function originSender(bytes calldata encodedTx) public pure returns (address) {\n return BridgeTransactionV2Lib.originSender(encodedTx);\n }\n\n function destRecipient(bytes calldata encodedTx) public pure returns (address) {\n return BridgeTransactionV2Lib.destRecipient(encodedTx);\n }\n\n function originToken(bytes calldata encodedTx) public pure returns (address) {\n return BridgeTransactionV2Lib.originToken(encodedTx);\n }\n\n function destToken(bytes calldata encodedTx) public pure returns (address) {\n return BridgeTransactionV2Lib.destToken(encodedTx);\n }\n\n function originAmount(bytes calldata encodedTx) public pure returns (uint256) {\n return BridgeTransactionV2Lib.originAmount(encodedTx);\n }\n\n function destAmount(bytes calldata encodedTx) public pure returns (uint256) {\n return BridgeTransactionV2Lib.destAmount(encodedTx);\n }\n\n function originFeeAmount(bytes calldata encodedTx) public pure returns (uint256) {\n return BridgeTransactionV2Lib.originFeeAmount(encodedTx);\n }\n\n function zapNative(bytes calldata encodedTx) public pure returns (uint256) {\n return BridgeTransactionV2Lib.zapNative(encodedTx);\n }\n\n function deadline(bytes calldata encodedTx) public pure returns (uint256) {\n return BridgeTransactionV2Lib.deadline(encodedTx);\n }\n\n function nonce(bytes calldata encodedTx) public pure returns (uint256) {\n return BridgeTransactionV2Lib.nonce(encodedTx);\n }\n\n function exclusivityRelayer(bytes calldata encodedTx) public pure returns (address) {\n return BridgeTransactionV2Lib.exclusivityRelayer(encodedTx);\n }\n\n function exclusivityEndTime(bytes calldata encodedTx) public pure returns (uint256) {\n return BridgeTransactionV2Lib.exclusivityEndTime(encodedTx);\n }\n\n function zapData(bytes calldata encodedTx) public pure returns (bytes calldata) {\n return BridgeTransactionV2Lib.zapData(encodedTx);\n }\n}\n","language":"Solidity","languageVersion":"0.8.24","compilerVersion":"0.8.24","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"21499:2832:0:-:0;;;;;;;;;;;;;;;;;;;","srcMapRuntime":"21499:2832:0:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;24184:145;;;;;;:::i;:::-;;:::i;:::-;;;;;;;;:::i;:::-;;;;;;;;23108:144;;;;;;:::i;:::-;;:::i;:::-;;;1208:25:1;;;1196:2;1181:18;23108:144:0;1062:177:1;23418:142:0;;;;;;:::i;:::-;;:::i;21716:173::-;;;;;;:::i;:::-;;:::i;:::-;;;;;;;:::i;22806:142::-;;;;;;:::i;:::-;;:::i;:::-;;;4108:42:1;4096:55;;;4078:74;;4066:2;4051:18;22806:142:0;3932:226:1;23712:134:0;;;;;;:::i;:::-;;:::i;22193:145::-;;;;;;:::i;:::-;;:::i;:::-;;;4337:10:1;4325:23;;;4307:42;;4295:2;4280:18;22193:145:0;4163:192:1;24018:160:0;;;;;;:::i;:::-;;:::i;22954:148::-;;;;;;:::i;:::-;;:::i;21895:137::-;;;;;;:::i;:::-;;:::i;:::-;;;4534:6:1;4522:19;;;4504:38;;4492:2;4477:18;21895:137:0;4360:188:1;22654:146:0;;;;;;:::i;:::-;;:::i;22038:149::-;;;;;;:::i;:::-;;:::i;22344:148::-;;;;;;:::i;:::-;;:::i;22498:150::-;;;;;;:::i;:::-;;:::i;23852:160::-;;;;;;:::i;:::-;;:::i;23566:140::-;;;;;;:::i;:::-;;:::i;23258:154::-;;;;;;:::i;:::-;;:::i;21541:169::-;;;;;;:::i;:::-;;:::i;:::-;;;;;;;:::i;24184:145::-;24248:14;;24281:41;24312:9;;24281:30;:41::i;:::-;24274:48;;;;24184:145;;;;;:::o;23108:144::-;23175:7;18820:18;18798:41;;18785:55;23201:44;23194:51;23108:144;-1:-1:-1;;;23108:144:0:o;23418:142::-;23484:7;21188:17;21166:40;;21153:54;23510:43;20925:298;21716:173;21781:40;-1:-1:-1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;21781:40:0;21840:42;21872:9;;21840:31;:42::i;22806:142::-;22872:7;18045:17;18023:40;;18010:54;18006:2;18002:63;22898:43;17763:318;23712:134;23774:7;19951:12;19929:35;;19916:49;23800:39;19700:281;22193:145;22261:6;16407:20;16385:43;;16372:57;16367:3;16363:67;22286:45;16119:327;24018:160;24093:7;20796:27;20774:50;;20761:64;24119:52;20506:335;22954:148;23023:7;18432:20;18410:43;;18397:57;23049:46;18160:310;21895:137;21959:6;15570:30;;15565:3;15561:40;21984:41;15330:287;22654:146;22722:7;17642:19;17620:42;;17607:56;17603:2;17599:65;22748:45;17354:326;22038:149;22108:6;15992:22;15970:45;;15957:59;15952:3;15948:69;22133:47;15698:335;22344:148;22413:7;16816:20;16794:43;;16781:57;16777:2;16773:66;22439:46;16525:330;22498:150;22568:7;17236:21;17214:44;;17201:58;17197:2;17193:67;22594:47;16942:334;23852:160;23927:7;20375:26;20353:49;;20340:63;20336:2;20332:72;23953:52;20066:354;23566:140;23631:7;19596:15;19574:38;;19561:52;23657:42;19336:293;23258:154;23330:7;19220:24;19198:47;;19185:61;23356:49;18939:323;21541:169;21631:12;21662:41;21694:8;21662:31;:41::i;:::-;21655:48;21541:169;-1:-1:-1;;21541:169:0:o;21299:146::-;21365:23;;21411:27;:9;11923:3;21411:9;;:27;:::i;14267:990::-;14358:49;-1:-1:-1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;14358:49:0;15992:22;15970:45;;15957:59;15952:3;15948:69;;;14423:49;;16407:20;16385:43;;16372:57;16363:67;;14482:20;;;:45;16816:20;16794:43;;16781:57;16777:2;16773:66;;;14537:21;;;:47;17236:21;17214:44;;17201:58;17193:67;;14594:22;;;:49;17642:19;17620:42;;17607:56;17599:65;;14653:20;;;:45;18045:17;18023:40;;18010:54;18002:63;;14708:18;;;:41;18432:20;18410:43;;18397:57;14759:21;;;:47;18820:18;18798:41;;18785:55;14816:19;;;:43;;;;19220:24;19198:47;;19185:61;14869:24;;;:53;19596:15;19574:38;;19561:52;14932:17;;;:39;19951:12;19929:35;;19916:49;14981:14;;;:33;20375:26;20353:49;;20340:63;20332:72;;15024:27;;;:59;20796:27;20774:50;;20761:64;15093:27;;;:59;21188:17;21166:40;;21153:54;15162:18;;;:41;15232:18;15970:45;15240:9;15232:7;:18::i;:::-;15213:37;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;15213:16:0;;;:37;:8;14267:990;-1:-1:-1;;14267:990:0:o;12981:1038::-;13251:22;;13287:20;;;;;13321:21;;;;;13073:12;13356:22;;;;13392:20;;;;13426:18;;;;13458:21;;;;13200:289;;8676:16:1;13200:289:0;;;8660:102:1;;;;8781:66;8884:3;8880:16;;;8876:25;;8863:11;;;8856:46;8935:16;;;;8931:25;;;8918:11;;;8911:46;8976:66;9076:15;;;9072:24;;9058:12;;;9051:46;9131:15;;9127:24;;9113:12;;;9106:46;9186:15;;;9182:24;;9168:12;;;9161:46;9241:15;;;9237:24;;;9223:12;;;9216:46;9278:12;;;9271:28;;;;13175:22:0;;9315:13:1;;13200:289:0;;;;;;;;;;;;;;13559:19;;;;13592:24;;;;13737:17;;;;13768:14;;;;13838:27;;;;13879;;;;13954:18;;;;13986:16;;;;13200:289;;-1:-1:-1;13506:506:0;;13200:289;;13986:16;13200:289;13506:506;;:::i;:::-;;;;;;;;;;;;;13499:513;;;12981:1038;;;:::o;14:591:1:-;84:6;92;145:2;133:9;124:7;120:23;116:32;113:52;;;161:1;158;151:12;113:52;201:9;188:23;230:18;271:2;263:6;260:14;257:34;;;287:1;284;277:12;257:34;325:6;314:9;310:22;300:32;;370:7;363:4;359:2;355:13;351:27;341:55;;392:1;389;382:12;341:55;432:2;419:16;458:2;450:6;447:14;444:34;;;474:1;471;464:12;444:34;519:7;514:2;505:6;501:2;497:15;493:24;490:37;487:57;;;540:1;537;530:12;487:57;571:2;563:11;;;;;593:6;;-1:-1:-1;14:591:1;;-1:-1:-1;;;;14:591:1:o;610:447::-;767:2;756:9;749:21;806:6;801:2;790:9;786:18;779:34;863:6;855;850:2;839:9;835:18;822:48;919:1;890:22;;;914:2;886:31;;;879:42;;;;973:2;961:15;;;978:66;957:88;942:104;938:113;;610:447;-1:-1:-1;610:447:1:o;1475:250::-;1560:1;1570:113;1584:6;1581:1;1578:13;1570:113;;;1660:11;;;1654:18;1641:11;;;1634:39;1606:2;1599:10;1570:113;;;-1:-1:-1;;1717:1:1;1699:16;;1692:27;1475:250::o;1730:329::-;1771:3;1809:5;1803:12;1836:6;1831:3;1824:19;1852:76;1921:6;1914:4;1909:3;1905:14;1898:4;1891:5;1887:16;1852:76;:::i;:::-;1973:2;1961:15;1978:66;1957:88;1948:98;;;;2048:4;1944:109;;1730:329;-1:-1:-1;;1730:329:1:o;2064:1863::-;2265:2;2254:9;2247:21;2277:52;2325:2;2314:9;2310:18;2301:6;2295:13;1320:10;1309:22;1297:35;;1244:94;2277:52;2228:4;2376:2;2368:6;2364:15;2358:22;2389:51;2436:2;2425:9;2421:18;2407:12;1320:10;1309:22;1297:35;;1244:94;2389:51;-1:-1:-1;2489:2:1;2477:15;;2471:22;1420:42;1409:54;;2552:2;2537:18;;1397:67;-1:-1:-1;2605:2:1;2593:15;;2587:22;1420:42;1409:54;;2668:3;2653:19;;1397:67;-1:-1:-1;2722:3:1;2710:16;;2704:23;1420:42;1409:54;;2786:3;2771:19;;1397:67;-1:-1:-1;2840:3:1;2828:16;;2822:23;1420:42;1409:54;;2904:3;2889:19;;1397:67;-1:-1:-1;2964:3:1;2952:16;;2946:23;2940:3;2925:19;;;2918:52;;;;2995:16;;2989:23;3031:3;3050:18;;;3043:30;;;;3098:15;;3092:22;3133:3;3152:18;;;3145:30;;;;3200:15;;3194:22;3235:3;3254:18;;;3247:30;;;;3302:15;;3296:22;3337:3;3356:18;;;3349:30;;;;3416:15;;3410:22;3451:3;3463:54;3498:18;;;3410:22;1420:42;1409:54;1397:67;;1343:127;3463:54;3543:15;;3537:22;3579:3;3598:19;;;3591:32;;;;3649:16;;3643:23;3686:3;3705:19;;;3698:32;;;;3767:16;;3761:23;3804:6;3826:19;;;3819:32;3761:23;-1:-1:-1;3868:53:1;3916:3;3901:19;;3761:23;3868:53;:::i;:::-;3860:61;2064:1863;-1:-1:-1;;;;2064:1863:1:o;4553:184::-;4605:77;4602:1;4595:88;4702:4;4699:1;4692:15;4726:4;4723:1;4716:15;4742:250;4809:2;4803:9;4851:6;4839:19;;4888:18;4873:34;;4909:22;;;4870:62;4867:88;;;4935:18;;:::i;:::-;4971:2;4964:22;4742:250;:::o;4997:163::-;5064:20;;5124:10;5113:22;;5103:33;;5093:61;;5150:1;5147;5140:12;5093:61;4997:163;;;:::o;5165:196::-;5233:20;;5293:42;5282:54;;5272:65;;5262:93;;5351:1;5348;5341:12;5366:777;5408:5;5461:3;5454:4;5446:6;5442:17;5438:27;5428:55;;5479:1;5476;5469:12;5428:55;5515:6;5502:20;5541:18;5578:2;5574;5571:10;5568:36;;;5584:18;;:::i;:::-;5718:2;5712:9;5780:4;5772:13;;5623:66;5768:22;;;5792:2;5764:31;5760:40;5748:53;;;5816:18;;;5836:22;;;5813:46;5810:72;;;5862:18;;:::i;:::-;5902:10;5898:2;5891:22;5937:2;5929:6;5922:18;5983:3;5976:4;5971:2;5963:6;5959:15;5955:26;5952:35;5949:55;;;6000:1;5997;5990:12;5949:55;6064:2;6057:4;6049:6;6045:17;6038:4;6030:6;6026:17;6013:54;6111:1;6104:4;6099:2;6091:6;6087:15;6083:26;6076:37;6131:6;6122:15;;;;;;5366:777;;;;:::o;6148:1630::-;6243:6;6296:2;6284:9;6275:7;6271:23;6267:32;6264:52;;;6312:1;6309;6302:12;6264:52;6352:9;6339:23;6381:18;6422:2;6414:6;6411:14;6408:34;;;6438:1;6435;6428:12;6408:34;6461:22;;;;6517:6;6499:16;;;6495:29;6492:49;;;6537:1;6534;6527:12;6492:49;6563:17;;:::i;:::-;6603:21;6621:2;6603:21;:::i;:::-;6596:5;6589:36;6657:30;6683:2;6679;6675:11;6657:30;:::i;:::-;6652:2;6645:5;6641:14;6634:54;6720:31;6747:2;6743;6739:11;6720:31;:::i;:::-;6715:2;6708:5;6704:14;6697:55;6784:31;6811:2;6807;6803:11;6784:31;:::i;:::-;6779:2;6772:5;6768:14;6761:55;6849:32;6876:3;6872:2;6868:12;6849:32;:::i;:::-;6843:3;6836:5;6832:15;6825:57;6915:32;6942:3;6938:2;6934:12;6915:32;:::i;:::-;6909:3;6898:15;;6891:57;7002:3;6994:12;;;6981:26;6964:15;;;6957:51;7062:3;7054:12;;;7041:26;7024:15;;;7017:51;7087:3;7135:11;;;7122:25;7106:14;;;7099:49;7167:3;7215:11;;;7202:25;7186:14;;;7179:49;7247:3;7295:11;;;7282:25;7266:14;;;7259:49;7327:3;7362:31;7381:11;;;7362:31;:::i;:::-;7346:14;;;7339:55;7413:3;7461:11;;;7448:25;7432:14;;;7425:49;7493:3;7541:11;;;7528:25;7512:14;;;7505:49;7573:3;7614:11;;;7601:25;7638:16;;;7635:36;;;7667:1;7664;7657:12;7635:36;7703:44;7739:7;7728:8;7724:2;7720:17;7703:44;:::i;:::-;7687:14;;;7680:68;;;;-1:-1:-1;7691:5:1;6148:1630;-1:-1:-1;;;;;6148:1630:1:o;7783:217::-;7930:2;7919:9;7912:21;7893:4;7950:44;7990:2;7979:9;7975:18;7967:6;7950:44;:::i;8005:331::-;8110:9;8121;8163:8;8151:10;8148:24;8145:44;;;8185:1;8182;8175:12;8145:44;8214:6;8204:8;8201:20;8198:40;;;8234:1;8231;8224:12;8198:40;-1:-1:-1;;8260:23:1;;;8305:25;;;;;-1:-1:-1;8005:331:1:o;9339:1059::-;9710:3;9748:6;9742:13;9764:66;9823:6;9818:3;9811:4;9803:6;9799:17;9764:66;:::i;:::-;9861:6;9856:3;9852:16;9839:29;;9891:6;9884:5;9877:21;9932:6;9925:4;9918:5;9914:16;9907:32;9971:6;9966:2;9959:5;9955:14;9948:30;10010:6;10005:2;9998:5;9994:14;9987:30;10071:66;10062:6;10058:2;10054:15;10050:88;10044:3;10037:5;10033:15;10026:113;10172:6;10166:3;10159:5;10155:15;10148:31;10212:6;10206:3;10199:5;10195:15;10188:31;10250:6;10244:13;10266:80;10337:8;10331:3;10324:5;10320:15;10313:4;10305:6;10301:17;10266:80;:::i;:::-;10366:20;10388:3;10362:30;;9339:1059;-1:-1:-1;;;;;;;;;;;9339:1059:1:o","abiDefinition":[{"inputs":[{"internalType":"bytes","name":"encodedTx","type":"bytes"}],"name":"deadline","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"bytes","name":"encodedTx","type":"bytes"}],"name":"decodeV2","outputs":[{"components":[{"internalType":"uint32","name":"originChainId","type":"uint32"},{"internalType":"uint32","name":"destChainId","type":"uint32"},{"internalType":"address","name":"originSender","type":"address"},{"internalType":"address","name":"destRecipient","type":"address"},{"internalType":"address","name":"originToken","type":"address"},{"internalType":"address","name":"destToken","type":"address"},{"internalType":"uint256","name":"originAmount","type":"uint256"},{"internalType":"uint256","name":"destAmount","type":"uint256"},{"internalType":"uint256","name":"originFeeAmount","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"address","name":"exclusivityRelayer","type":"address"},{"internalType":"uint256","name":"exclusivityEndTime","type":"uint256"},{"internalType":"uint256","name":"zapNative","type":"uint256"},{"internalType":"bytes","name":"zapData","type":"bytes"}],"internalType":"struct IFastBridgeV2.BridgeTransactionV2","name":"","type":"tuple"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"bytes","name":"encodedTx","type":"bytes"}],"name":"destAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"bytes","name":"encodedTx","type":"bytes"}],"name":"destChainId","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"bytes","name":"encodedTx","type":"bytes"}],"name":"destRecipient","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"bytes","name":"encodedTx","type":"bytes"}],"name":"destToken","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"pure","type":"function"},{"inputs":[{"components":[{"internalType":"uint32","name":"originChainId","type":"uint32"},{"internalType":"uint32","name":"destChainId","type":"uint32"},{"internalType":"address","name":"originSender","type":"address"},{"internalType":"address","name":"destRecipient","type":"address"},{"internalType":"address","name":"originToken","type":"address"},{"internalType":"address","name":"destToken","type":"address"},{"internalType":"uint256","name":"originAmount","type":"uint256"},{"internalType":"uint256","name":"destAmount","type":"uint256"},{"internalType":"uint256","name":"originFeeAmount","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"address","name":"exclusivityRelayer","type":"address"},{"internalType":"uint256","name":"exclusivityEndTime","type":"uint256"},{"internalType":"uint256","name":"zapNative","type":"uint256"},{"internalType":"bytes","name":"zapData","type":"bytes"}],"internalType":"struct IFastBridgeV2.BridgeTransactionV2","name":"bridgeTx","type":"tuple"}],"name":"encodeV2","outputs":[{"internalType":"bytes","name":"","type":"bytes"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"bytes","name":"encodedTx","type":"bytes"}],"name":"exclusivityEndTime","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"bytes","name":"encodedTx","type":"bytes"}],"name":"exclusivityRelayer","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"bytes","name":"encodedTx","type":"bytes"}],"name":"nonce","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"bytes","name":"encodedTx","type":"bytes"}],"name":"originAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"bytes","name":"encodedTx","type":"bytes"}],"name":"originChainId","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"bytes","name":"encodedTx","type":"bytes"}],"name":"originFeeAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"bytes","name":"encodedTx","type":"bytes"}],"name":"originSender","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"bytes","name":"encodedTx","type":"bytes"}],"name":"originToken","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"bytes","name":"encodedTx","type":"bytes"}],"name":"version","outputs":[{"internalType":"uint16","name":"","type":"uint16"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"bytes","name":"encodedTx","type":"bytes"}],"name":"zapData","outputs":[{"internalType":"bytes","name":"","type":"bytes"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"bytes","name":"encodedTx","type":"bytes"}],"name":"zapNative","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"}],"userDoc":{"kind":"user","methods":{},"version":1},"developerDoc":{"kind":"dev","methods":{},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"encodedTx\",\"type\":\"bytes\"}],\"name\":\"deadline\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"encodedTx\",\"type\":\"bytes\"}],\"name\":\"decodeV2\",\"outputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"originChainId\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"destChainId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"originSender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destRecipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"originFeeAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"exclusivityRelayer\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"exclusivityEndTime\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"zapNative\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"zapData\",\"type\":\"bytes\"}],\"internalType\":\"struct IFastBridgeV2.BridgeTransactionV2\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"encodedTx\",\"type\":\"bytes\"}],\"name\":\"destAmount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"encodedTx\",\"type\":\"bytes\"}],\"name\":\"destChainId\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"encodedTx\",\"type\":\"bytes\"}],\"name\":\"destRecipient\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"encodedTx\",\"type\":\"bytes\"}],\"name\":\"destToken\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"originChainId\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"destChainId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"originSender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destRecipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"originFeeAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"exclusivityRelayer\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"exclusivityEndTime\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"zapNative\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"zapData\",\"type\":\"bytes\"}],\"internalType\":\"struct IFastBridgeV2.BridgeTransactionV2\",\"name\":\"bridgeTx\",\"type\":\"tuple\"}],\"name\":\"encodeV2\",\"outputs\":[{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"encodedTx\",\"type\":\"bytes\"}],\"name\":\"exclusivityEndTime\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"encodedTx\",\"type\":\"bytes\"}],\"name\":\"exclusivityRelayer\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"encodedTx\",\"type\":\"bytes\"}],\"name\":\"nonce\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"encodedTx\",\"type\":\"bytes\"}],\"name\":\"originAmount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"encodedTx\",\"type\":\"bytes\"}],\"name\":\"originChainId\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"encodedTx\",\"type\":\"bytes\"}],\"name\":\"originFeeAmount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"encodedTx\",\"type\":\"bytes\"}],\"name\":\"originSender\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"encodedTx\",\"type\":\"bytes\"}],\"name\":\"originToken\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"encodedTx\",\"type\":\"bytes\"}],\"name\":\"version\",\"outputs\":[{\"internalType\":\"uint16\",\"name\":\"\",\"type\":\"uint16\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"encodedTx\",\"type\":\"bytes\"}],\"name\":\"zapData\",\"outputs\":[{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"encodedTx\",\"type\":\"bytes\"}],\"name\":\"zapNative\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"pure\",\"type\":\"function\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/BridgeTransactionV2Harness.sol\":\"BridgeTransactionV2Harness\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/BridgeTransactionV2Harness.sol\":{\"keccak256\":\"0x163fc97efd1365765820c3f01e2d17aa275f32bfbdcd651602808861111a7c00\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://3fbd6475c98b3c1c7e4492e7a59c79a87cc991b403cefd1ac3a980afe441419e\",\"dweb:/ipfs/QmTCQazGcsUMZXtHLFXHwg3Nmc3xFxxFWZ4KY6qXTWpmPx\"]}},\"version\":1}"},"hashes":{"deadline(bytes)":"e79f1782","decodeV2(bytes)":"24657024","destAmount(bytes)":"12d0c512","destChainId(bytes)":"5c3fa4c0","destRecipient(bytes)":"9c538802","destToken(bytes)":"37518e50","encodeV2((uint32,uint32,address,address,address,address,uint256,uint256,uint256,uint256,uint256,address,uint256,uint256,bytes))":"faef535a","exclusivityEndTime(bytes)":"6907efd7","exclusivityRelayer(bytes)":"dcafa970","nonce(bytes)":"4e765004","originAmount(bytes)":"7241b9cb","originChainId(bytes)":"93bb0d80","originFeeAmount(bytes)":"e938730e","originSender(bytes)":"9bdb46fe","originToken(bytes)":"93832899","version(bytes)":"7d67c5a7","zapData(bytes)":"0af3f403","zapNative(bytes)":"230602c1"}},"solidity/BridgeTransactionV2Harness.sol:BridgeTransactionV2Lib":{"code":"0x60566037600b82828239805160001a607314602a57634e487b7160e01b600052600060045260246000fd5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600080fdfea2646970667358221220da262e011b1740fc866d94ce46470fa9e1d5daf267ae4e8119df1dcd7edab25964736f6c63430008180033","runtime-code":"0x73000000000000000000000000000000000000000030146080604052600080fdfea2646970667358221220da262e011b1740fc866d94ce46470fa9e1d5daf267ae4e8119df1dcd7edab25964736f6c63430008180033","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.24 ^0.8.4;\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IFastBridgeV2.sol\n\ninterface IFastBridgeV2 is IFastBridge {\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n struct BridgeTxDetails {\n BridgeStatus status;\n uint32 destChainId;\n uint56 proofBlockTimestamp;\n address proofRelayer;\n }\n\n struct BridgeRelay {\n uint48 blockNumber;\n uint48 blockTimestamp;\n address relayer;\n }\n\n /// @notice New params introduced in the FastBridgeV2.\n /// We are passing fields from the older BridgeParams struct outside of this struct\n /// for backwards compatibility.\n /// Note: quoteRelayer and quoteExclusivitySeconds are either both zero (indicating no exclusivity)\n /// or both non-zero (indicating exclusivity for the given period).\n /// Note: zapNative \u003e 0 can NOT be used with destToken = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE (native token)\n /// @param quoteRelayer Relayer that provided the quote for the transaction\n /// @param quoteExclusivitySeconds Period of time the quote relayer is guaranteed exclusivity after user's deposit\n /// @param quoteId Unique quote identifier used for tracking the quote\n /// @param zapNative ETH value to send to the recipient (if any)\n /// @param zapData Parameters for the Zap to the destination recipient (if any)\n struct BridgeParamsV2 {\n address quoteRelayer;\n int256 quoteExclusivitySeconds;\n bytes quoteId;\n uint256 zapNative;\n bytes zapData;\n }\n\n /// @notice Updated bridge transaction struct to include parameters introduced in FastBridgeV2.\n /// Note: only `exclusivityRelayer` can fill such a transaction until `exclusivityEndTime`.\n struct BridgeTransactionV2 {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n // Note: sendChainGas flag from V1 is deprecated\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n address exclusivityRelayer;\n uint256 exclusivityEndTime;\n uint256 zapNative; // ETH value to send to the recipient (if any)\n bytes zapData; // data to pass for the Zap action (if any)\n }\n\n event BridgeQuoteDetails(bytes32 indexed transactionId, bytes quoteId);\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability\n /// to provide temporary exclusivity fill rights for the quote relayer.\n /// @param params The parameters required to bridge\n /// @param paramsV2 The parameters for exclusivity fill rights (optional, can be left empty)\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function relay(bytes memory request, address relayer) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param transactionId The transaction id associated with the encoded bridge transaction to prove\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital.\n /// @notice Can only send funds to the relayer address on the proof.\n /// @param request The encoded bridge transaction to claim on origin chain\n function claim(bytes memory request) external;\n /// @notice Checks if a transaction has been relayed\n /// @param transactionId The ID of the transaction to check\n /// @return True if the transaction has been relayed, false otherwise\n function bridgeRelays(bytes32 transactionId) external view returns (bool);\n\n /// @notice Returns the status of a bridge transaction\n /// @param transactionId The ID of the bridge transaction\n /// @return BridgeStatus Status of the bridge transaction\n function bridgeStatuses(bytes32 transactionId) external view returns (BridgeStatus);\n\n /// @notice Returns the timestamp and relayer of a bridge proof\n /// @param transactionId The ID of the bridge transaction\n /// @return timestamp The timestamp of the bridge proof\n /// @return relayer The relayer address of the bridge proof\n function bridgeProofs(bytes32 transactionId) external view returns (uint96 timestamp, address relayer);\n\n /// @notice Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\n /// @param request The bridge request to decode\n function getBridgeTransactionV2(bytes memory request) external view returns (BridgeTransactionV2 memory);\n}\n\n// contracts/libs/BridgeTransactionV2.sol\n\n// solhint-disable no-inline-assembly\nlibrary BridgeTransactionV2Lib {\n uint16 internal constant VERSION = 2;\n\n // Offsets of the fields in the packed BridgeTransactionV2 struct\n // uint16 version [000 .. 002)\n // uint32 originChainId [002 .. 006)\n // uint32 destChainId [006 .. 010)\n // address originSender [010 .. 030)\n // address destRecipient [030 .. 050)\n // address originToken [050 .. 070)\n // address destToken [070 .. 090)\n // uint256 originAmount [090 .. 122)\n // uint256 destAmount [122 .. 154)\n // uint256 originFeeAmount [154 .. 186)\n // uint256 deadline [186 .. 218)\n // uint256 nonce [218 .. 250)\n // address exclusivityRelayer [250 .. 270)\n // uint256 exclusivityEndTime [270 .. 302)\n // uint256 zapNative [302 .. 334)\n // bytes zapData [334 .. ***)\n\n // forgefmt: disable-start\n uint256 private constant OFFSET_ORIGIN_CHAIN_ID = 2;\n uint256 private constant OFFSET_DEST_CHAIN_ID = 6;\n uint256 private constant OFFSET_ORIGIN_SENDER = 10;\n uint256 private constant OFFSET_DEST_RECIPIENT = 30;\n uint256 private constant OFFSET_ORIGIN_TOKEN = 50;\n uint256 private constant OFFSET_DEST_TOKEN = 70;\n uint256 private constant OFFSET_ORIGIN_AMOUNT = 90;\n uint256 private constant OFFSET_DEST_AMOUNT = 122;\n uint256 private constant OFFSET_ORIGIN_FEE_AMOUNT = 154;\n uint256 private constant OFFSET_DEADLINE = 186;\n uint256 private constant OFFSET_NONCE = 218;\n uint256 private constant OFFSET_EXCLUSIVITY_RELAYER = 250;\n uint256 private constant OFFSET_EXCLUSIVITY_END_TIME = 270;\n uint256 private constant OFFSET_ZAP_NATIVE = 302;\n uint256 private constant OFFSET_ZAP_DATA = 334;\n // forgefmt: disable-end\n\n error BridgeTransactionV2__InvalidEncodedTx();\n error BridgeTransactionV2__UnsupportedVersion(uint16 version);\n\n /// @notice Validates the encoded transaction to be a tightly packed encoded payload for BridgeTransactionV2.\n /// @dev Checks the minimum length and the version, use this function before decoding any of the fields.\n function validateV2(bytes calldata encodedTx) internal pure {\n // Check the minimum length: must at least include all static fields.\n if (encodedTx.length \u003c OFFSET_ZAP_DATA) revert BridgeTransactionV2__InvalidEncodedTx();\n // Once we validated the length, we can be sure that the version field is present.\n uint16 version_ = version(encodedTx);\n if (version_ != VERSION) revert BridgeTransactionV2__UnsupportedVersion(version_);\n }\n\n /// @notice Encodes the BridgeTransactionV2 struct by tightly packing the fields.\n /// @dev `abi.decode` will not work as a result of the tightly packed fields. Use `decodeV2` to decode instead.\n function encodeV2(IFastBridgeV2.BridgeTransactionV2 memory bridgeTx) internal pure returns (bytes memory) {\n // We split the encoding into two parts to avoid stack-too-deep error\n bytes memory firstPart = abi.encodePacked(\n VERSION,\n bridgeTx.originChainId,\n bridgeTx.destChainId,\n bridgeTx.originSender,\n bridgeTx.destRecipient,\n bridgeTx.originToken,\n bridgeTx.destToken,\n bridgeTx.originAmount\n );\n return abi.encodePacked(\n firstPart,\n bridgeTx.destAmount,\n bridgeTx.originFeeAmount,\n // Note: we skip the deprecated `sendChainGas` flag, which was present in BridgeTransaction V1\n bridgeTx.deadline,\n bridgeTx.nonce,\n // New V2 fields: exclusivity\n bridgeTx.exclusivityRelayer,\n bridgeTx.exclusivityEndTime,\n // New V2 fields: Zap\n bridgeTx.zapNative,\n bridgeTx.zapData\n );\n }\n\n /// @notice Decodes the BridgeTransactionV2 struct from the encoded transaction.\n /// @dev Encoded BridgeTransactionV2 struct must be tightly packed.\n /// Use `validateV2` before decoding to ensure the encoded transaction is valid.\n function decodeV2(bytes calldata encodedTx)\n internal\n pure\n returns (IFastBridgeV2.BridgeTransactionV2 memory bridgeTx)\n {\n bridgeTx.originChainId = originChainId(encodedTx);\n bridgeTx.destChainId = destChainId(encodedTx);\n bridgeTx.originSender = originSender(encodedTx);\n bridgeTx.destRecipient = destRecipient(encodedTx);\n bridgeTx.originToken = originToken(encodedTx);\n bridgeTx.destToken = destToken(encodedTx);\n bridgeTx.originAmount = originAmount(encodedTx);\n bridgeTx.destAmount = destAmount(encodedTx);\n bridgeTx.originFeeAmount = originFeeAmount(encodedTx);\n bridgeTx.deadline = deadline(encodedTx);\n bridgeTx.nonce = nonce(encodedTx);\n bridgeTx.exclusivityRelayer = exclusivityRelayer(encodedTx);\n bridgeTx.exclusivityEndTime = exclusivityEndTime(encodedTx);\n bridgeTx.zapNative = zapNative(encodedTx);\n bridgeTx.zapData = zapData(encodedTx);\n }\n\n /// @notice Extracts the version from the encoded transaction.\n function version(bytes calldata encodedTx) internal pure returns (uint16 version_) {\n // Load 32 bytes from the start and shift it 240 bits to the right to get the highest 16 bits.\n assembly {\n version_ := shr(240, calldataload(encodedTx.offset))\n }\n }\n\n /// @notice Extracts the origin chain ID from the encoded transaction.\n function originChainId(bytes calldata encodedTx) internal pure returns (uint32 originChainId_) {\n // Load 32 bytes from the offset and shift it 224 bits to the right to get the highest 32 bits.\n assembly {\n originChainId_ := shr(224, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_CHAIN_ID)))\n }\n }\n\n /// @notice Extracts the destination chain ID from the encoded transaction.\n function destChainId(bytes calldata encodedTx) internal pure returns (uint32 destChainId_) {\n // Load 32 bytes from the offset and shift it 224 bits to the right to get the highest 32 bits.\n assembly {\n destChainId_ := shr(224, calldataload(add(encodedTx.offset, OFFSET_DEST_CHAIN_ID)))\n }\n }\n\n /// @notice Extracts the origin sender from the encoded transaction.\n function originSender(bytes calldata encodedTx) internal pure returns (address originSender_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n originSender_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_SENDER)))\n }\n }\n\n /// @notice Extracts the destination recipient from the encoded transaction.\n function destRecipient(bytes calldata encodedTx) internal pure returns (address destRecipient_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n destRecipient_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_DEST_RECIPIENT)))\n }\n }\n\n /// @notice Extracts the origin token from the encoded transaction.\n function originToken(bytes calldata encodedTx) internal pure returns (address originToken_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n originToken_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_TOKEN)))\n }\n }\n\n /// @notice Extracts the destination token from the encoded transaction.\n function destToken(bytes calldata encodedTx) internal pure returns (address destToken_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n destToken_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_DEST_TOKEN)))\n }\n }\n\n /// @notice Extracts the origin amount from the encoded transaction.\n function originAmount(bytes calldata encodedTx) internal pure returns (uint256 originAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n originAmount_ := calldataload(add(encodedTx.offset, OFFSET_ORIGIN_AMOUNT))\n }\n }\n\n /// @notice Extracts the destination amount from the encoded transaction.\n function destAmount(bytes calldata encodedTx) internal pure returns (uint256 destAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n destAmount_ := calldataload(add(encodedTx.offset, OFFSET_DEST_AMOUNT))\n }\n }\n\n /// @notice Extracts the origin fee amount from the encoded transaction.\n function originFeeAmount(bytes calldata encodedTx) internal pure returns (uint256 originFeeAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n originFeeAmount_ := calldataload(add(encodedTx.offset, OFFSET_ORIGIN_FEE_AMOUNT))\n }\n }\n\n /// @notice Extracts the deadline from the encoded transaction.\n function deadline(bytes calldata encodedTx) internal pure returns (uint256 deadline_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n deadline_ := calldataload(add(encodedTx.offset, OFFSET_DEADLINE))\n }\n }\n\n /// @notice Extracts the nonce from the encoded transaction.\n function nonce(bytes calldata encodedTx) internal pure returns (uint256 nonce_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n nonce_ := calldataload(add(encodedTx.offset, OFFSET_NONCE))\n }\n }\n\n /// @notice Extracts the exclusivity relayer from the encoded transaction.\n function exclusivityRelayer(bytes calldata encodedTx) internal pure returns (address exclusivityRelayer_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n exclusivityRelayer_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_EXCLUSIVITY_RELAYER)))\n }\n }\n\n /// @notice Extracts the exclusivity end time from the encoded transaction.\n function exclusivityEndTime(bytes calldata encodedTx) internal pure returns (uint256 exclusivityEndTime_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n exclusivityEndTime_ := calldataload(add(encodedTx.offset, OFFSET_EXCLUSIVITY_END_TIME))\n }\n }\n\n /// @notice Extracts the Zap's native value from the encoded transaction.\n function zapNative(bytes calldata encodedTx) internal pure returns (uint256 zapNative_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n zapNative_ := calldataload(add(encodedTx.offset, OFFSET_ZAP_NATIVE))\n }\n }\n\n /// @notice Extracts the Zap's data from the encoded transaction.\n function zapData(bytes calldata encodedTx) internal pure returns (bytes calldata zapData_) {\n zapData_ = encodedTx[OFFSET_ZAP_DATA:];\n }\n}\n\n// test/harnesses/BridgeTransactionV2Harness.sol\n\ncontract BridgeTransactionV2Harness {\n function encodeV2(IFastBridgeV2.BridgeTransactionV2 memory bridgeTx) public pure returns (bytes memory) {\n return BridgeTransactionV2Lib.encodeV2(bridgeTx);\n }\n\n function decodeV2(bytes calldata encodedTx) public pure returns (IFastBridgeV2.BridgeTransactionV2 memory) {\n return BridgeTransactionV2Lib.decodeV2(encodedTx);\n }\n\n function version(bytes calldata encodedTx) public pure returns (uint16) {\n return BridgeTransactionV2Lib.version(encodedTx);\n }\n\n function originChainId(bytes calldata encodedTx) public pure returns (uint32) {\n return BridgeTransactionV2Lib.originChainId(encodedTx);\n }\n\n function destChainId(bytes calldata encodedTx) public pure returns (uint32) {\n return BridgeTransactionV2Lib.destChainId(encodedTx);\n }\n\n function originSender(bytes calldata encodedTx) public pure returns (address) {\n return BridgeTransactionV2Lib.originSender(encodedTx);\n }\n\n function destRecipient(bytes calldata encodedTx) public pure returns (address) {\n return BridgeTransactionV2Lib.destRecipient(encodedTx);\n }\n\n function originToken(bytes calldata encodedTx) public pure returns (address) {\n return BridgeTransactionV2Lib.originToken(encodedTx);\n }\n\n function destToken(bytes calldata encodedTx) public pure returns (address) {\n return BridgeTransactionV2Lib.destToken(encodedTx);\n }\n\n function originAmount(bytes calldata encodedTx) public pure returns (uint256) {\n return BridgeTransactionV2Lib.originAmount(encodedTx);\n }\n\n function destAmount(bytes calldata encodedTx) public pure returns (uint256) {\n return BridgeTransactionV2Lib.destAmount(encodedTx);\n }\n\n function originFeeAmount(bytes calldata encodedTx) public pure returns (uint256) {\n return BridgeTransactionV2Lib.originFeeAmount(encodedTx);\n }\n\n function zapNative(bytes calldata encodedTx) public pure returns (uint256) {\n return BridgeTransactionV2Lib.zapNative(encodedTx);\n }\n\n function deadline(bytes calldata encodedTx) public pure returns (uint256) {\n return BridgeTransactionV2Lib.deadline(encodedTx);\n }\n\n function nonce(bytes calldata encodedTx) public pure returns (uint256) {\n return BridgeTransactionV2Lib.nonce(encodedTx);\n }\n\n function exclusivityRelayer(bytes calldata encodedTx) public pure returns (address) {\n return BridgeTransactionV2Lib.exclusivityRelayer(encodedTx);\n }\n\n function exclusivityEndTime(bytes calldata encodedTx) public pure returns (uint256) {\n return BridgeTransactionV2Lib.exclusivityEndTime(encodedTx);\n }\n\n function zapData(bytes calldata encodedTx) public pure returns (bytes calldata) {\n return BridgeTransactionV2Lib.zapData(encodedTx);\n }\n}\n","language":"Solidity","languageVersion":"0.8.24","compilerVersion":"0.8.24","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"9951:11496:0:-:0;;;;;;;;;;;;;;;-1:-1:-1;;;9951:11496:0;;;;;;;;;;;;;;;;;","srcMapRuntime":"9951:11496:0:-:0;;;;;;;;","abiDefinition":[{"inputs":[],"name":"BridgeTransactionV2__InvalidEncodedTx","type":"error"},{"inputs":[{"internalType":"uint16","name":"version","type":"uint16"}],"name":"BridgeTransactionV2__UnsupportedVersion","type":"error"}],"userDoc":{"kind":"user","methods":{},"version":1},"developerDoc":{"kind":"dev","methods":{},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[],\"name\":\"BridgeTransactionV2__InvalidEncodedTx\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint16\",\"name\":\"version\",\"type\":\"uint16\"}],\"name\":\"BridgeTransactionV2__UnsupportedVersion\",\"type\":\"error\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/BridgeTransactionV2Harness.sol\":\"BridgeTransactionV2Lib\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/BridgeTransactionV2Harness.sol\":{\"keccak256\":\"0x163fc97efd1365765820c3f01e2d17aa275f32bfbdcd651602808861111a7c00\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://3fbd6475c98b3c1c7e4492e7a59c79a87cc991b403cefd1ac3a980afe441419e\",\"dweb:/ipfs/QmTCQazGcsUMZXtHLFXHwg3Nmc3xFxxFWZ4KY6qXTWpmPx\"]}},\"version\":1}"},"hashes":{}},"solidity/BridgeTransactionV2Harness.sol:IFastBridge":{"code":"0x","runtime-code":"0x","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.24 ^0.8.4;\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IFastBridgeV2.sol\n\ninterface IFastBridgeV2 is IFastBridge {\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n struct BridgeTxDetails {\n BridgeStatus status;\n uint32 destChainId;\n uint56 proofBlockTimestamp;\n address proofRelayer;\n }\n\n struct BridgeRelay {\n uint48 blockNumber;\n uint48 blockTimestamp;\n address relayer;\n }\n\n /// @notice New params introduced in the FastBridgeV2.\n /// We are passing fields from the older BridgeParams struct outside of this struct\n /// for backwards compatibility.\n /// Note: quoteRelayer and quoteExclusivitySeconds are either both zero (indicating no exclusivity)\n /// or both non-zero (indicating exclusivity for the given period).\n /// Note: zapNative \u003e 0 can NOT be used with destToken = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE (native token)\n /// @param quoteRelayer Relayer that provided the quote for the transaction\n /// @param quoteExclusivitySeconds Period of time the quote relayer is guaranteed exclusivity after user's deposit\n /// @param quoteId Unique quote identifier used for tracking the quote\n /// @param zapNative ETH value to send to the recipient (if any)\n /// @param zapData Parameters for the Zap to the destination recipient (if any)\n struct BridgeParamsV2 {\n address quoteRelayer;\n int256 quoteExclusivitySeconds;\n bytes quoteId;\n uint256 zapNative;\n bytes zapData;\n }\n\n /// @notice Updated bridge transaction struct to include parameters introduced in FastBridgeV2.\n /// Note: only `exclusivityRelayer` can fill such a transaction until `exclusivityEndTime`.\n struct BridgeTransactionV2 {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n // Note: sendChainGas flag from V1 is deprecated\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n address exclusivityRelayer;\n uint256 exclusivityEndTime;\n uint256 zapNative; // ETH value to send to the recipient (if any)\n bytes zapData; // data to pass for the Zap action (if any)\n }\n\n event BridgeQuoteDetails(bytes32 indexed transactionId, bytes quoteId);\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability\n /// to provide temporary exclusivity fill rights for the quote relayer.\n /// @param params The parameters required to bridge\n /// @param paramsV2 The parameters for exclusivity fill rights (optional, can be left empty)\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function relay(bytes memory request, address relayer) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param transactionId The transaction id associated with the encoded bridge transaction to prove\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital.\n /// @notice Can only send funds to the relayer address on the proof.\n /// @param request The encoded bridge transaction to claim on origin chain\n function claim(bytes memory request) external;\n /// @notice Checks if a transaction has been relayed\n /// @param transactionId The ID of the transaction to check\n /// @return True if the transaction has been relayed, false otherwise\n function bridgeRelays(bytes32 transactionId) external view returns (bool);\n\n /// @notice Returns the status of a bridge transaction\n /// @param transactionId The ID of the bridge transaction\n /// @return BridgeStatus Status of the bridge transaction\n function bridgeStatuses(bytes32 transactionId) external view returns (BridgeStatus);\n\n /// @notice Returns the timestamp and relayer of a bridge proof\n /// @param transactionId The ID of the bridge transaction\n /// @return timestamp The timestamp of the bridge proof\n /// @return relayer The relayer address of the bridge proof\n function bridgeProofs(bytes32 transactionId) external view returns (uint96 timestamp, address relayer);\n\n /// @notice Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\n /// @param request The bridge request to decode\n function getBridgeTransactionV2(bytes memory request) external view returns (BridgeTransactionV2 memory);\n}\n\n// contracts/libs/BridgeTransactionV2.sol\n\n// solhint-disable no-inline-assembly\nlibrary BridgeTransactionV2Lib {\n uint16 internal constant VERSION = 2;\n\n // Offsets of the fields in the packed BridgeTransactionV2 struct\n // uint16 version [000 .. 002)\n // uint32 originChainId [002 .. 006)\n // uint32 destChainId [006 .. 010)\n // address originSender [010 .. 030)\n // address destRecipient [030 .. 050)\n // address originToken [050 .. 070)\n // address destToken [070 .. 090)\n // uint256 originAmount [090 .. 122)\n // uint256 destAmount [122 .. 154)\n // uint256 originFeeAmount [154 .. 186)\n // uint256 deadline [186 .. 218)\n // uint256 nonce [218 .. 250)\n // address exclusivityRelayer [250 .. 270)\n // uint256 exclusivityEndTime [270 .. 302)\n // uint256 zapNative [302 .. 334)\n // bytes zapData [334 .. ***)\n\n // forgefmt: disable-start\n uint256 private constant OFFSET_ORIGIN_CHAIN_ID = 2;\n uint256 private constant OFFSET_DEST_CHAIN_ID = 6;\n uint256 private constant OFFSET_ORIGIN_SENDER = 10;\n uint256 private constant OFFSET_DEST_RECIPIENT = 30;\n uint256 private constant OFFSET_ORIGIN_TOKEN = 50;\n uint256 private constant OFFSET_DEST_TOKEN = 70;\n uint256 private constant OFFSET_ORIGIN_AMOUNT = 90;\n uint256 private constant OFFSET_DEST_AMOUNT = 122;\n uint256 private constant OFFSET_ORIGIN_FEE_AMOUNT = 154;\n uint256 private constant OFFSET_DEADLINE = 186;\n uint256 private constant OFFSET_NONCE = 218;\n uint256 private constant OFFSET_EXCLUSIVITY_RELAYER = 250;\n uint256 private constant OFFSET_EXCLUSIVITY_END_TIME = 270;\n uint256 private constant OFFSET_ZAP_NATIVE = 302;\n uint256 private constant OFFSET_ZAP_DATA = 334;\n // forgefmt: disable-end\n\n error BridgeTransactionV2__InvalidEncodedTx();\n error BridgeTransactionV2__UnsupportedVersion(uint16 version);\n\n /// @notice Validates the encoded transaction to be a tightly packed encoded payload for BridgeTransactionV2.\n /// @dev Checks the minimum length and the version, use this function before decoding any of the fields.\n function validateV2(bytes calldata encodedTx) internal pure {\n // Check the minimum length: must at least include all static fields.\n if (encodedTx.length \u003c OFFSET_ZAP_DATA) revert BridgeTransactionV2__InvalidEncodedTx();\n // Once we validated the length, we can be sure that the version field is present.\n uint16 version_ = version(encodedTx);\n if (version_ != VERSION) revert BridgeTransactionV2__UnsupportedVersion(version_);\n }\n\n /// @notice Encodes the BridgeTransactionV2 struct by tightly packing the fields.\n /// @dev `abi.decode` will not work as a result of the tightly packed fields. Use `decodeV2` to decode instead.\n function encodeV2(IFastBridgeV2.BridgeTransactionV2 memory bridgeTx) internal pure returns (bytes memory) {\n // We split the encoding into two parts to avoid stack-too-deep error\n bytes memory firstPart = abi.encodePacked(\n VERSION,\n bridgeTx.originChainId,\n bridgeTx.destChainId,\n bridgeTx.originSender,\n bridgeTx.destRecipient,\n bridgeTx.originToken,\n bridgeTx.destToken,\n bridgeTx.originAmount\n );\n return abi.encodePacked(\n firstPart,\n bridgeTx.destAmount,\n bridgeTx.originFeeAmount,\n // Note: we skip the deprecated `sendChainGas` flag, which was present in BridgeTransaction V1\n bridgeTx.deadline,\n bridgeTx.nonce,\n // New V2 fields: exclusivity\n bridgeTx.exclusivityRelayer,\n bridgeTx.exclusivityEndTime,\n // New V2 fields: Zap\n bridgeTx.zapNative,\n bridgeTx.zapData\n );\n }\n\n /// @notice Decodes the BridgeTransactionV2 struct from the encoded transaction.\n /// @dev Encoded BridgeTransactionV2 struct must be tightly packed.\n /// Use `validateV2` before decoding to ensure the encoded transaction is valid.\n function decodeV2(bytes calldata encodedTx)\n internal\n pure\n returns (IFastBridgeV2.BridgeTransactionV2 memory bridgeTx)\n {\n bridgeTx.originChainId = originChainId(encodedTx);\n bridgeTx.destChainId = destChainId(encodedTx);\n bridgeTx.originSender = originSender(encodedTx);\n bridgeTx.destRecipient = destRecipient(encodedTx);\n bridgeTx.originToken = originToken(encodedTx);\n bridgeTx.destToken = destToken(encodedTx);\n bridgeTx.originAmount = originAmount(encodedTx);\n bridgeTx.destAmount = destAmount(encodedTx);\n bridgeTx.originFeeAmount = originFeeAmount(encodedTx);\n bridgeTx.deadline = deadline(encodedTx);\n bridgeTx.nonce = nonce(encodedTx);\n bridgeTx.exclusivityRelayer = exclusivityRelayer(encodedTx);\n bridgeTx.exclusivityEndTime = exclusivityEndTime(encodedTx);\n bridgeTx.zapNative = zapNative(encodedTx);\n bridgeTx.zapData = zapData(encodedTx);\n }\n\n /// @notice Extracts the version from the encoded transaction.\n function version(bytes calldata encodedTx) internal pure returns (uint16 version_) {\n // Load 32 bytes from the start and shift it 240 bits to the right to get the highest 16 bits.\n assembly {\n version_ := shr(240, calldataload(encodedTx.offset))\n }\n }\n\n /// @notice Extracts the origin chain ID from the encoded transaction.\n function originChainId(bytes calldata encodedTx) internal pure returns (uint32 originChainId_) {\n // Load 32 bytes from the offset and shift it 224 bits to the right to get the highest 32 bits.\n assembly {\n originChainId_ := shr(224, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_CHAIN_ID)))\n }\n }\n\n /// @notice Extracts the destination chain ID from the encoded transaction.\n function destChainId(bytes calldata encodedTx) internal pure returns (uint32 destChainId_) {\n // Load 32 bytes from the offset and shift it 224 bits to the right to get the highest 32 bits.\n assembly {\n destChainId_ := shr(224, calldataload(add(encodedTx.offset, OFFSET_DEST_CHAIN_ID)))\n }\n }\n\n /// @notice Extracts the origin sender from the encoded transaction.\n function originSender(bytes calldata encodedTx) internal pure returns (address originSender_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n originSender_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_SENDER)))\n }\n }\n\n /// @notice Extracts the destination recipient from the encoded transaction.\n function destRecipient(bytes calldata encodedTx) internal pure returns (address destRecipient_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n destRecipient_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_DEST_RECIPIENT)))\n }\n }\n\n /// @notice Extracts the origin token from the encoded transaction.\n function originToken(bytes calldata encodedTx) internal pure returns (address originToken_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n originToken_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_TOKEN)))\n }\n }\n\n /// @notice Extracts the destination token from the encoded transaction.\n function destToken(bytes calldata encodedTx) internal pure returns (address destToken_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n destToken_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_DEST_TOKEN)))\n }\n }\n\n /// @notice Extracts the origin amount from the encoded transaction.\n function originAmount(bytes calldata encodedTx) internal pure returns (uint256 originAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n originAmount_ := calldataload(add(encodedTx.offset, OFFSET_ORIGIN_AMOUNT))\n }\n }\n\n /// @notice Extracts the destination amount from the encoded transaction.\n function destAmount(bytes calldata encodedTx) internal pure returns (uint256 destAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n destAmount_ := calldataload(add(encodedTx.offset, OFFSET_DEST_AMOUNT))\n }\n }\n\n /// @notice Extracts the origin fee amount from the encoded transaction.\n function originFeeAmount(bytes calldata encodedTx) internal pure returns (uint256 originFeeAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n originFeeAmount_ := calldataload(add(encodedTx.offset, OFFSET_ORIGIN_FEE_AMOUNT))\n }\n }\n\n /// @notice Extracts the deadline from the encoded transaction.\n function deadline(bytes calldata encodedTx) internal pure returns (uint256 deadline_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n deadline_ := calldataload(add(encodedTx.offset, OFFSET_DEADLINE))\n }\n }\n\n /// @notice Extracts the nonce from the encoded transaction.\n function nonce(bytes calldata encodedTx) internal pure returns (uint256 nonce_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n nonce_ := calldataload(add(encodedTx.offset, OFFSET_NONCE))\n }\n }\n\n /// @notice Extracts the exclusivity relayer from the encoded transaction.\n function exclusivityRelayer(bytes calldata encodedTx) internal pure returns (address exclusivityRelayer_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n exclusivityRelayer_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_EXCLUSIVITY_RELAYER)))\n }\n }\n\n /// @notice Extracts the exclusivity end time from the encoded transaction.\n function exclusivityEndTime(bytes calldata encodedTx) internal pure returns (uint256 exclusivityEndTime_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n exclusivityEndTime_ := calldataload(add(encodedTx.offset, OFFSET_EXCLUSIVITY_END_TIME))\n }\n }\n\n /// @notice Extracts the Zap's native value from the encoded transaction.\n function zapNative(bytes calldata encodedTx) internal pure returns (uint256 zapNative_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n zapNative_ := calldataload(add(encodedTx.offset, OFFSET_ZAP_NATIVE))\n }\n }\n\n /// @notice Extracts the Zap's data from the encoded transaction.\n function zapData(bytes calldata encodedTx) internal pure returns (bytes calldata zapData_) {\n zapData_ = encodedTx[OFFSET_ZAP_DATA:];\n }\n}\n\n// test/harnesses/BridgeTransactionV2Harness.sol\n\ncontract BridgeTransactionV2Harness {\n function encodeV2(IFastBridgeV2.BridgeTransactionV2 memory bridgeTx) public pure returns (bytes memory) {\n return BridgeTransactionV2Lib.encodeV2(bridgeTx);\n }\n\n function decodeV2(bytes calldata encodedTx) public pure returns (IFastBridgeV2.BridgeTransactionV2 memory) {\n return BridgeTransactionV2Lib.decodeV2(encodedTx);\n }\n\n function version(bytes calldata encodedTx) public pure returns (uint16) {\n return BridgeTransactionV2Lib.version(encodedTx);\n }\n\n function originChainId(bytes calldata encodedTx) public pure returns (uint32) {\n return BridgeTransactionV2Lib.originChainId(encodedTx);\n }\n\n function destChainId(bytes calldata encodedTx) public pure returns (uint32) {\n return BridgeTransactionV2Lib.destChainId(encodedTx);\n }\n\n function originSender(bytes calldata encodedTx) public pure returns (address) {\n return BridgeTransactionV2Lib.originSender(encodedTx);\n }\n\n function destRecipient(bytes calldata encodedTx) public pure returns (address) {\n return BridgeTransactionV2Lib.destRecipient(encodedTx);\n }\n\n function originToken(bytes calldata encodedTx) public pure returns (address) {\n return BridgeTransactionV2Lib.originToken(encodedTx);\n }\n\n function destToken(bytes calldata encodedTx) public pure returns (address) {\n return BridgeTransactionV2Lib.destToken(encodedTx);\n }\n\n function originAmount(bytes calldata encodedTx) public pure returns (uint256) {\n return BridgeTransactionV2Lib.originAmount(encodedTx);\n }\n\n function destAmount(bytes calldata encodedTx) public pure returns (uint256) {\n return BridgeTransactionV2Lib.destAmount(encodedTx);\n }\n\n function originFeeAmount(bytes calldata encodedTx) public pure returns (uint256) {\n return BridgeTransactionV2Lib.originFeeAmount(encodedTx);\n }\n\n function zapNative(bytes calldata encodedTx) public pure returns (uint256) {\n return BridgeTransactionV2Lib.zapNative(encodedTx);\n }\n\n function deadline(bytes calldata encodedTx) public pure returns (uint256) {\n return BridgeTransactionV2Lib.deadline(encodedTx);\n }\n\n function nonce(bytes calldata encodedTx) public pure returns (uint256) {\n return BridgeTransactionV2Lib.nonce(encodedTx);\n }\n\n function exclusivityRelayer(bytes calldata encodedTx) public pure returns (address) {\n return BridgeTransactionV2Lib.exclusivityRelayer(encodedTx);\n }\n\n function exclusivityEndTime(bytes calldata encodedTx) public pure returns (uint256) {\n return BridgeTransactionV2Lib.exclusivityEndTime(encodedTx);\n }\n\n function zapData(bytes calldata encodedTx) public pure returns (bytes calldata) {\n return BridgeTransactionV2Lib.zapData(encodedTx);\n }\n}\n","language":"Solidity","languageVersion":"0.8.24","compilerVersion":"0.8.24","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"","srcMapRuntime":"","abiDefinition":[{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"relayer","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"BridgeDepositClaimed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"BridgeDepositRefunded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"relayer","type":"address"}],"name":"BridgeProofDisputed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"relayer","type":"address"},{"indexed":false,"internalType":"bytes32","name":"transactionHash","type":"bytes32"}],"name":"BridgeProofProvided","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"relayer","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint32","name":"originChainId","type":"uint32"},{"indexed":false,"internalType":"address","name":"originToken","type":"address"},{"indexed":false,"internalType":"address","name":"destToken","type":"address"},{"indexed":false,"internalType":"uint256","name":"originAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"destAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"chainGasAmount","type":"uint256"}],"name":"BridgeRelayed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"bytes","name":"request","type":"bytes"},{"indexed":false,"internalType":"uint32","name":"destChainId","type":"uint32"},{"indexed":false,"internalType":"address","name":"originToken","type":"address"},{"indexed":false,"internalType":"address","name":"destToken","type":"address"},{"indexed":false,"internalType":"uint256","name":"originAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"destAmount","type":"uint256"},{"indexed":false,"internalType":"bool","name":"sendChainGas","type":"bool"}],"name":"BridgeRequested","type":"event"},{"inputs":[{"components":[{"internalType":"uint32","name":"dstChainId","type":"uint32"},{"internalType":"address","name":"sender","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"address","name":"originToken","type":"address"},{"internalType":"address","name":"destToken","type":"address"},{"internalType":"uint256","name":"originAmount","type":"uint256"},{"internalType":"uint256","name":"destAmount","type":"uint256"},{"internalType":"bool","name":"sendChainGas","type":"bool"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"internalType":"struct IFastBridge.BridgeParams","name":"params","type":"tuple"}],"name":"bridge","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"internalType":"address","name":"relayer","type":"address"}],"name":"canClaim","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"},{"internalType":"address","name":"to","type":"address"}],"name":"claim","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"transactionId","type":"bytes32"}],"name":"dispute","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"}],"name":"getBridgeTransaction","outputs":[{"components":[{"internalType":"uint32","name":"originChainId","type":"uint32"},{"internalType":"uint32","name":"destChainId","type":"uint32"},{"internalType":"address","name":"originSender","type":"address"},{"internalType":"address","name":"destRecipient","type":"address"},{"internalType":"address","name":"originToken","type":"address"},{"internalType":"address","name":"destToken","type":"address"},{"internalType":"uint256","name":"originAmount","type":"uint256"},{"internalType":"uint256","name":"destAmount","type":"uint256"},{"internalType":"uint256","name":"originFeeAmount","type":"uint256"},{"internalType":"bool","name":"sendChainGas","type":"bool"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint256","name":"nonce","type":"uint256"}],"internalType":"struct IFastBridge.BridgeTransaction","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"},{"internalType":"bytes32","name":"destTxHash","type":"bytes32"}],"name":"prove","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"}],"name":"refund","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"}],"name":"relay","outputs":[],"stateMutability":"payable","type":"function"}],"userDoc":{"kind":"user","methods":{"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256))":{"notice":"Initiates bridge on origin chain to be relayed by off-chain relayer"},"canClaim(bytes32,address)":{"notice":"Checks if the dispute period has passed so bridge deposit can be claimed"},"claim(bytes,address)":{"notice":"Completes bridge transaction on origin chain by claiming originally deposited capital"},"dispute(bytes32)":{"notice":"Disputes an outstanding proof in case relayer provided dest chain tx is invalid"},"getBridgeTransaction(bytes)":{"notice":"Decodes bridge request into a bridge transaction"},"prove(bytes,bytes32)":{"notice":"Provides proof on origin side that relayer provided funds on destination side of bridge transaction"},"refund(bytes)":{"notice":"Refunds an outstanding bridge transaction in case optimistic bridging failed"},"relay(bytes)":{"notice":"Relays destination side of bridge transaction by off-chain relayer"}},"version":1},"developerDoc":{"kind":"dev","methods":{"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256))":{"params":{"params":"The parameters required to bridge"}},"canClaim(bytes32,address)":{"params":{"relayer":"The address of the relayer attempting to claim","transactionId":"The transaction id associated with the encoded bridge transaction to check"}},"claim(bytes,address)":{"params":{"request":"The encoded bridge transaction to claim on origin chain","to":"The recipient address of the funds"}},"dispute(bytes32)":{"params":{"transactionId":"The transaction id associated with the encoded bridge transaction to dispute"}},"getBridgeTransaction(bytes)":{"params":{"request":"The bridge request to decode"}},"prove(bytes,bytes32)":{"params":{"destTxHash":"The destination tx hash proving bridge transaction was relayed","request":"The encoded bridge transaction to prove on origin chain"}},"refund(bytes)":{"params":{"request":"The encoded bridge transaction to refund"}},"relay(bytes)":{"params":{"request":"The encoded bridge transaction to relay on destination chain"}}},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"BridgeDepositClaimed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"BridgeDepositRefunded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"name\":\"BridgeProofDisputed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"transactionHash\",\"type\":\"bytes32\"}],\"name\":\"BridgeProofProvided\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"originChainId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"chainGasAmount\",\"type\":\"uint256\"}],\"name\":\"BridgeRelayed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"destChainId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"sendChainGas\",\"type\":\"bool\"}],\"name\":\"BridgeRequested\",\"type\":\"event\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"dstChainId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"sendChainGas\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"}],\"internalType\":\"struct IFastBridge.BridgeParams\",\"name\":\"params\",\"type\":\"tuple\"}],\"name\":\"bridge\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"name\":\"canClaim\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"claim\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"}],\"name\":\"dispute\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"getBridgeTransaction\",\"outputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"originChainId\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"destChainId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"originSender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destRecipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"originFeeAmount\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"sendChainGas\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"}],\"internalType\":\"struct IFastBridge.BridgeTransaction\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"},{\"internalType\":\"bytes32\",\"name\":\"destTxHash\",\"type\":\"bytes32\"}],\"name\":\"prove\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"refund\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"relay\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{\"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256))\":{\"params\":{\"params\":\"The parameters required to bridge\"}},\"canClaim(bytes32,address)\":{\"params\":{\"relayer\":\"The address of the relayer attempting to claim\",\"transactionId\":\"The transaction id associated with the encoded bridge transaction to check\"}},\"claim(bytes,address)\":{\"params\":{\"request\":\"The encoded bridge transaction to claim on origin chain\",\"to\":\"The recipient address of the funds\"}},\"dispute(bytes32)\":{\"params\":{\"transactionId\":\"The transaction id associated with the encoded bridge transaction to dispute\"}},\"getBridgeTransaction(bytes)\":{\"params\":{\"request\":\"The bridge request to decode\"}},\"prove(bytes,bytes32)\":{\"params\":{\"destTxHash\":\"The destination tx hash proving bridge transaction was relayed\",\"request\":\"The encoded bridge transaction to prove on origin chain\"}},\"refund(bytes)\":{\"params\":{\"request\":\"The encoded bridge transaction to refund\"}},\"relay(bytes)\":{\"params\":{\"request\":\"The encoded bridge transaction to relay on destination chain\"}}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256))\":{\"notice\":\"Initiates bridge on origin chain to be relayed by off-chain relayer\"},\"canClaim(bytes32,address)\":{\"notice\":\"Checks if the dispute period has passed so bridge deposit can be claimed\"},\"claim(bytes,address)\":{\"notice\":\"Completes bridge transaction on origin chain by claiming originally deposited capital\"},\"dispute(bytes32)\":{\"notice\":\"Disputes an outstanding proof in case relayer provided dest chain tx is invalid\"},\"getBridgeTransaction(bytes)\":{\"notice\":\"Decodes bridge request into a bridge transaction\"},\"prove(bytes,bytes32)\":{\"notice\":\"Provides proof on origin side that relayer provided funds on destination side of bridge transaction\"},\"refund(bytes)\":{\"notice\":\"Refunds an outstanding bridge transaction in case optimistic bridging failed\"},\"relay(bytes)\":{\"notice\":\"Relays destination side of bridge transaction by off-chain relayer\"}},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/BridgeTransactionV2Harness.sol\":\"IFastBridge\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/BridgeTransactionV2Harness.sol\":{\"keccak256\":\"0x163fc97efd1365765820c3f01e2d17aa275f32bfbdcd651602808861111a7c00\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://3fbd6475c98b3c1c7e4492e7a59c79a87cc991b403cefd1ac3a980afe441419e\",\"dweb:/ipfs/QmTCQazGcsUMZXtHLFXHwg3Nmc3xFxxFWZ4KY6qXTWpmPx\"]}},\"version\":1}"},"hashes":{"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256))":"45851694","canClaim(bytes32,address)":"aa9641ab","claim(bytes,address)":"41fcb612","dispute(bytes32)":"add98c70","getBridgeTransaction(bytes)":"ac11fb1a","prove(bytes,bytes32)":"886d36ff","refund(bytes)":"5eb7d946","relay(bytes)":"8f0d6f17"}},"solidity/BridgeTransactionV2Harness.sol:IFastBridgeV2":{"code":"0x","runtime-code":"0x","info":{"source":"// SPDX-License-Identifier: MIT\npragma solidity =0.8.24 ^0.8.4;\n\n// contracts/interfaces/IFastBridge.sol\n\ninterface IFastBridge {\n struct BridgeTransaction {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n bool sendChainGas;\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n }\n\n struct BridgeProof {\n uint96 timestamp;\n address relayer;\n }\n\n // ============ Events ============\n\n event BridgeRequested(\n bytes32 indexed transactionId,\n address indexed sender,\n bytes request,\n uint32 destChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n bool sendChainGas\n );\n event BridgeRelayed(\n bytes32 indexed transactionId,\n address indexed relayer,\n address indexed to,\n uint32 originChainId,\n address originToken,\n address destToken,\n uint256 originAmount,\n uint256 destAmount,\n uint256 chainGasAmount\n );\n event BridgeProofProvided(bytes32 indexed transactionId, address indexed relayer, bytes32 transactionHash);\n event BridgeProofDisputed(bytes32 indexed transactionId, address indexed relayer);\n event BridgeDepositClaimed(\n bytes32 indexed transactionId, address indexed relayer, address indexed to, address token, uint256 amount\n );\n event BridgeDepositRefunded(bytes32 indexed transactionId, address indexed to, address token, uint256 amount);\n\n // ============ Methods ============\n\n struct BridgeParams {\n uint32 dstChainId;\n address sender;\n address to;\n address originToken;\n address destToken;\n uint256 originAmount; // should include protocol fee (if any)\n uint256 destAmount; // should include relayer fee\n bool sendChainGas;\n uint256 deadline;\n }\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer\n /// @param params The parameters required to bridge\n function bridge(BridgeParams memory params) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n function relay(bytes memory request) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param request The encoded bridge transaction to prove on origin chain\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n function prove(bytes memory request, bytes32 destTxHash) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital\n /// @param request The encoded bridge transaction to claim on origin chain\n /// @param to The recipient address of the funds\n function claim(bytes memory request, address to) external;\n\n /// @notice Disputes an outstanding proof in case relayer provided dest chain tx is invalid\n /// @param transactionId The transaction id associated with the encoded bridge transaction to dispute\n function dispute(bytes32 transactionId) external;\n\n /// @notice Refunds an outstanding bridge transaction in case optimistic bridging failed\n /// @param request The encoded bridge transaction to refund\n function refund(bytes memory request) external;\n\n // ============ Views ============\n\n /// @notice Decodes bridge request into a bridge transaction\n /// @param request The bridge request to decode\n function getBridgeTransaction(bytes memory request) external view returns (BridgeTransaction memory);\n\n /// @notice Checks if the dispute period has passed so bridge deposit can be claimed\n /// @param transactionId The transaction id associated with the encoded bridge transaction to check\n /// @param relayer The address of the relayer attempting to claim\n function canClaim(bytes32 transactionId, address relayer) external view returns (bool);\n}\n\n// contracts/interfaces/IFastBridgeV2.sol\n\ninterface IFastBridgeV2 is IFastBridge {\n enum BridgeStatus {\n NULL, // doesn't exist yet\n REQUESTED,\n RELAYER_PROVED,\n RELAYER_CLAIMED,\n REFUNDED\n }\n\n struct BridgeTxDetails {\n BridgeStatus status;\n uint32 destChainId;\n uint56 proofBlockTimestamp;\n address proofRelayer;\n }\n\n struct BridgeRelay {\n uint48 blockNumber;\n uint48 blockTimestamp;\n address relayer;\n }\n\n /// @notice New params introduced in the FastBridgeV2.\n /// We are passing fields from the older BridgeParams struct outside of this struct\n /// for backwards compatibility.\n /// Note: quoteRelayer and quoteExclusivitySeconds are either both zero (indicating no exclusivity)\n /// or both non-zero (indicating exclusivity for the given period).\n /// Note: zapNative \u003e 0 can NOT be used with destToken = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE (native token)\n /// @param quoteRelayer Relayer that provided the quote for the transaction\n /// @param quoteExclusivitySeconds Period of time the quote relayer is guaranteed exclusivity after user's deposit\n /// @param quoteId Unique quote identifier used for tracking the quote\n /// @param zapNative ETH value to send to the recipient (if any)\n /// @param zapData Parameters for the Zap to the destination recipient (if any)\n struct BridgeParamsV2 {\n address quoteRelayer;\n int256 quoteExclusivitySeconds;\n bytes quoteId;\n uint256 zapNative;\n bytes zapData;\n }\n\n /// @notice Updated bridge transaction struct to include parameters introduced in FastBridgeV2.\n /// Note: only `exclusivityRelayer` can fill such a transaction until `exclusivityEndTime`.\n struct BridgeTransactionV2 {\n uint32 originChainId;\n uint32 destChainId;\n address originSender; // user (origin)\n address destRecipient; // user (dest)\n address originToken;\n address destToken;\n uint256 originAmount; // amount in on origin bridge less originFeeAmount\n uint256 destAmount;\n uint256 originFeeAmount;\n // Note: sendChainGas flag from V1 is deprecated\n uint256 deadline; // user specified deadline for destination relay\n uint256 nonce;\n address exclusivityRelayer;\n uint256 exclusivityEndTime;\n uint256 zapNative; // ETH value to send to the recipient (if any)\n bytes zapData; // data to pass for the Zap action (if any)\n }\n\n event BridgeQuoteDetails(bytes32 indexed transactionId, bytes quoteId);\n\n /// @notice Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability\n /// to provide temporary exclusivity fill rights for the quote relayer.\n /// @param params The parameters required to bridge\n /// @param paramsV2 The parameters for exclusivity fill rights (optional, can be left empty)\n function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) external payable;\n\n /// @notice Relays destination side of bridge transaction by off-chain relayer\n /// @param request The encoded bridge transaction to relay on destination chain\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function relay(bytes memory request, address relayer) external payable;\n\n /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction\n /// @param transactionId The transaction id associated with the encoded bridge transaction to prove\n /// @param destTxHash The destination tx hash proving bridge transaction was relayed\n /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed\n function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) external;\n\n /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital.\n /// @notice Can only send funds to the relayer address on the proof.\n /// @param request The encoded bridge transaction to claim on origin chain\n function claim(bytes memory request) external;\n /// @notice Checks if a transaction has been relayed\n /// @param transactionId The ID of the transaction to check\n /// @return True if the transaction has been relayed, false otherwise\n function bridgeRelays(bytes32 transactionId) external view returns (bool);\n\n /// @notice Returns the status of a bridge transaction\n /// @param transactionId The ID of the bridge transaction\n /// @return BridgeStatus Status of the bridge transaction\n function bridgeStatuses(bytes32 transactionId) external view returns (BridgeStatus);\n\n /// @notice Returns the timestamp and relayer of a bridge proof\n /// @param transactionId The ID of the bridge transaction\n /// @return timestamp The timestamp of the bridge proof\n /// @return relayer The relayer address of the bridge proof\n function bridgeProofs(bytes32 transactionId) external view returns (uint96 timestamp, address relayer);\n\n /// @notice Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\n /// @param request The bridge request to decode\n function getBridgeTransactionV2(bytes memory request) external view returns (BridgeTransactionV2 memory);\n}\n\n// contracts/libs/BridgeTransactionV2.sol\n\n// solhint-disable no-inline-assembly\nlibrary BridgeTransactionV2Lib {\n uint16 internal constant VERSION = 2;\n\n // Offsets of the fields in the packed BridgeTransactionV2 struct\n // uint16 version [000 .. 002)\n // uint32 originChainId [002 .. 006)\n // uint32 destChainId [006 .. 010)\n // address originSender [010 .. 030)\n // address destRecipient [030 .. 050)\n // address originToken [050 .. 070)\n // address destToken [070 .. 090)\n // uint256 originAmount [090 .. 122)\n // uint256 destAmount [122 .. 154)\n // uint256 originFeeAmount [154 .. 186)\n // uint256 deadline [186 .. 218)\n // uint256 nonce [218 .. 250)\n // address exclusivityRelayer [250 .. 270)\n // uint256 exclusivityEndTime [270 .. 302)\n // uint256 zapNative [302 .. 334)\n // bytes zapData [334 .. ***)\n\n // forgefmt: disable-start\n uint256 private constant OFFSET_ORIGIN_CHAIN_ID = 2;\n uint256 private constant OFFSET_DEST_CHAIN_ID = 6;\n uint256 private constant OFFSET_ORIGIN_SENDER = 10;\n uint256 private constant OFFSET_DEST_RECIPIENT = 30;\n uint256 private constant OFFSET_ORIGIN_TOKEN = 50;\n uint256 private constant OFFSET_DEST_TOKEN = 70;\n uint256 private constant OFFSET_ORIGIN_AMOUNT = 90;\n uint256 private constant OFFSET_DEST_AMOUNT = 122;\n uint256 private constant OFFSET_ORIGIN_FEE_AMOUNT = 154;\n uint256 private constant OFFSET_DEADLINE = 186;\n uint256 private constant OFFSET_NONCE = 218;\n uint256 private constant OFFSET_EXCLUSIVITY_RELAYER = 250;\n uint256 private constant OFFSET_EXCLUSIVITY_END_TIME = 270;\n uint256 private constant OFFSET_ZAP_NATIVE = 302;\n uint256 private constant OFFSET_ZAP_DATA = 334;\n // forgefmt: disable-end\n\n error BridgeTransactionV2__InvalidEncodedTx();\n error BridgeTransactionV2__UnsupportedVersion(uint16 version);\n\n /// @notice Validates the encoded transaction to be a tightly packed encoded payload for BridgeTransactionV2.\n /// @dev Checks the minimum length and the version, use this function before decoding any of the fields.\n function validateV2(bytes calldata encodedTx) internal pure {\n // Check the minimum length: must at least include all static fields.\n if (encodedTx.length \u003c OFFSET_ZAP_DATA) revert BridgeTransactionV2__InvalidEncodedTx();\n // Once we validated the length, we can be sure that the version field is present.\n uint16 version_ = version(encodedTx);\n if (version_ != VERSION) revert BridgeTransactionV2__UnsupportedVersion(version_);\n }\n\n /// @notice Encodes the BridgeTransactionV2 struct by tightly packing the fields.\n /// @dev `abi.decode` will not work as a result of the tightly packed fields. Use `decodeV2` to decode instead.\n function encodeV2(IFastBridgeV2.BridgeTransactionV2 memory bridgeTx) internal pure returns (bytes memory) {\n // We split the encoding into two parts to avoid stack-too-deep error\n bytes memory firstPart = abi.encodePacked(\n VERSION,\n bridgeTx.originChainId,\n bridgeTx.destChainId,\n bridgeTx.originSender,\n bridgeTx.destRecipient,\n bridgeTx.originToken,\n bridgeTx.destToken,\n bridgeTx.originAmount\n );\n return abi.encodePacked(\n firstPart,\n bridgeTx.destAmount,\n bridgeTx.originFeeAmount,\n // Note: we skip the deprecated `sendChainGas` flag, which was present in BridgeTransaction V1\n bridgeTx.deadline,\n bridgeTx.nonce,\n // New V2 fields: exclusivity\n bridgeTx.exclusivityRelayer,\n bridgeTx.exclusivityEndTime,\n // New V2 fields: Zap\n bridgeTx.zapNative,\n bridgeTx.zapData\n );\n }\n\n /// @notice Decodes the BridgeTransactionV2 struct from the encoded transaction.\n /// @dev Encoded BridgeTransactionV2 struct must be tightly packed.\n /// Use `validateV2` before decoding to ensure the encoded transaction is valid.\n function decodeV2(bytes calldata encodedTx)\n internal\n pure\n returns (IFastBridgeV2.BridgeTransactionV2 memory bridgeTx)\n {\n bridgeTx.originChainId = originChainId(encodedTx);\n bridgeTx.destChainId = destChainId(encodedTx);\n bridgeTx.originSender = originSender(encodedTx);\n bridgeTx.destRecipient = destRecipient(encodedTx);\n bridgeTx.originToken = originToken(encodedTx);\n bridgeTx.destToken = destToken(encodedTx);\n bridgeTx.originAmount = originAmount(encodedTx);\n bridgeTx.destAmount = destAmount(encodedTx);\n bridgeTx.originFeeAmount = originFeeAmount(encodedTx);\n bridgeTx.deadline = deadline(encodedTx);\n bridgeTx.nonce = nonce(encodedTx);\n bridgeTx.exclusivityRelayer = exclusivityRelayer(encodedTx);\n bridgeTx.exclusivityEndTime = exclusivityEndTime(encodedTx);\n bridgeTx.zapNative = zapNative(encodedTx);\n bridgeTx.zapData = zapData(encodedTx);\n }\n\n /// @notice Extracts the version from the encoded transaction.\n function version(bytes calldata encodedTx) internal pure returns (uint16 version_) {\n // Load 32 bytes from the start and shift it 240 bits to the right to get the highest 16 bits.\n assembly {\n version_ := shr(240, calldataload(encodedTx.offset))\n }\n }\n\n /// @notice Extracts the origin chain ID from the encoded transaction.\n function originChainId(bytes calldata encodedTx) internal pure returns (uint32 originChainId_) {\n // Load 32 bytes from the offset and shift it 224 bits to the right to get the highest 32 bits.\n assembly {\n originChainId_ := shr(224, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_CHAIN_ID)))\n }\n }\n\n /// @notice Extracts the destination chain ID from the encoded transaction.\n function destChainId(bytes calldata encodedTx) internal pure returns (uint32 destChainId_) {\n // Load 32 bytes from the offset and shift it 224 bits to the right to get the highest 32 bits.\n assembly {\n destChainId_ := shr(224, calldataload(add(encodedTx.offset, OFFSET_DEST_CHAIN_ID)))\n }\n }\n\n /// @notice Extracts the origin sender from the encoded transaction.\n function originSender(bytes calldata encodedTx) internal pure returns (address originSender_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n originSender_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_SENDER)))\n }\n }\n\n /// @notice Extracts the destination recipient from the encoded transaction.\n function destRecipient(bytes calldata encodedTx) internal pure returns (address destRecipient_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n destRecipient_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_DEST_RECIPIENT)))\n }\n }\n\n /// @notice Extracts the origin token from the encoded transaction.\n function originToken(bytes calldata encodedTx) internal pure returns (address originToken_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n originToken_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_ORIGIN_TOKEN)))\n }\n }\n\n /// @notice Extracts the destination token from the encoded transaction.\n function destToken(bytes calldata encodedTx) internal pure returns (address destToken_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n destToken_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_DEST_TOKEN)))\n }\n }\n\n /// @notice Extracts the origin amount from the encoded transaction.\n function originAmount(bytes calldata encodedTx) internal pure returns (uint256 originAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n originAmount_ := calldataload(add(encodedTx.offset, OFFSET_ORIGIN_AMOUNT))\n }\n }\n\n /// @notice Extracts the destination amount from the encoded transaction.\n function destAmount(bytes calldata encodedTx) internal pure returns (uint256 destAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n destAmount_ := calldataload(add(encodedTx.offset, OFFSET_DEST_AMOUNT))\n }\n }\n\n /// @notice Extracts the origin fee amount from the encoded transaction.\n function originFeeAmount(bytes calldata encodedTx) internal pure returns (uint256 originFeeAmount_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n originFeeAmount_ := calldataload(add(encodedTx.offset, OFFSET_ORIGIN_FEE_AMOUNT))\n }\n }\n\n /// @notice Extracts the deadline from the encoded transaction.\n function deadline(bytes calldata encodedTx) internal pure returns (uint256 deadline_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n deadline_ := calldataload(add(encodedTx.offset, OFFSET_DEADLINE))\n }\n }\n\n /// @notice Extracts the nonce from the encoded transaction.\n function nonce(bytes calldata encodedTx) internal pure returns (uint256 nonce_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n nonce_ := calldataload(add(encodedTx.offset, OFFSET_NONCE))\n }\n }\n\n /// @notice Extracts the exclusivity relayer from the encoded transaction.\n function exclusivityRelayer(bytes calldata encodedTx) internal pure returns (address exclusivityRelayer_) {\n // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.\n assembly {\n exclusivityRelayer_ := shr(96, calldataload(add(encodedTx.offset, OFFSET_EXCLUSIVITY_RELAYER)))\n }\n }\n\n /// @notice Extracts the exclusivity end time from the encoded transaction.\n function exclusivityEndTime(bytes calldata encodedTx) internal pure returns (uint256 exclusivityEndTime_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n exclusivityEndTime_ := calldataload(add(encodedTx.offset, OFFSET_EXCLUSIVITY_END_TIME))\n }\n }\n\n /// @notice Extracts the Zap's native value from the encoded transaction.\n function zapNative(bytes calldata encodedTx) internal pure returns (uint256 zapNative_) {\n // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits.\n assembly {\n zapNative_ := calldataload(add(encodedTx.offset, OFFSET_ZAP_NATIVE))\n }\n }\n\n /// @notice Extracts the Zap's data from the encoded transaction.\n function zapData(bytes calldata encodedTx) internal pure returns (bytes calldata zapData_) {\n zapData_ = encodedTx[OFFSET_ZAP_DATA:];\n }\n}\n\n// test/harnesses/BridgeTransactionV2Harness.sol\n\ncontract BridgeTransactionV2Harness {\n function encodeV2(IFastBridgeV2.BridgeTransactionV2 memory bridgeTx) public pure returns (bytes memory) {\n return BridgeTransactionV2Lib.encodeV2(bridgeTx);\n }\n\n function decodeV2(bytes calldata encodedTx) public pure returns (IFastBridgeV2.BridgeTransactionV2 memory) {\n return BridgeTransactionV2Lib.decodeV2(encodedTx);\n }\n\n function version(bytes calldata encodedTx) public pure returns (uint16) {\n return BridgeTransactionV2Lib.version(encodedTx);\n }\n\n function originChainId(bytes calldata encodedTx) public pure returns (uint32) {\n return BridgeTransactionV2Lib.originChainId(encodedTx);\n }\n\n function destChainId(bytes calldata encodedTx) public pure returns (uint32) {\n return BridgeTransactionV2Lib.destChainId(encodedTx);\n }\n\n function originSender(bytes calldata encodedTx) public pure returns (address) {\n return BridgeTransactionV2Lib.originSender(encodedTx);\n }\n\n function destRecipient(bytes calldata encodedTx) public pure returns (address) {\n return BridgeTransactionV2Lib.destRecipient(encodedTx);\n }\n\n function originToken(bytes calldata encodedTx) public pure returns (address) {\n return BridgeTransactionV2Lib.originToken(encodedTx);\n }\n\n function destToken(bytes calldata encodedTx) public pure returns (address) {\n return BridgeTransactionV2Lib.destToken(encodedTx);\n }\n\n function originAmount(bytes calldata encodedTx) public pure returns (uint256) {\n return BridgeTransactionV2Lib.originAmount(encodedTx);\n }\n\n function destAmount(bytes calldata encodedTx) public pure returns (uint256) {\n return BridgeTransactionV2Lib.destAmount(encodedTx);\n }\n\n function originFeeAmount(bytes calldata encodedTx) public pure returns (uint256) {\n return BridgeTransactionV2Lib.originFeeAmount(encodedTx);\n }\n\n function zapNative(bytes calldata encodedTx) public pure returns (uint256) {\n return BridgeTransactionV2Lib.zapNative(encodedTx);\n }\n\n function deadline(bytes calldata encodedTx) public pure returns (uint256) {\n return BridgeTransactionV2Lib.deadline(encodedTx);\n }\n\n function nonce(bytes calldata encodedTx) public pure returns (uint256) {\n return BridgeTransactionV2Lib.nonce(encodedTx);\n }\n\n function exclusivityRelayer(bytes calldata encodedTx) public pure returns (address) {\n return BridgeTransactionV2Lib.exclusivityRelayer(encodedTx);\n }\n\n function exclusivityEndTime(bytes calldata encodedTx) public pure returns (uint256) {\n return BridgeTransactionV2Lib.exclusivityEndTime(encodedTx);\n }\n\n function zapData(bytes calldata encodedTx) public pure returns (bytes calldata) {\n return BridgeTransactionV2Lib.zapData(encodedTx);\n }\n}\n","language":"Solidity","languageVersion":"0.8.24","compilerVersion":"0.8.24","compilerOptions":"--combined-json bin,bin-runtime,srcmap,srcmap-runtime,abi,userdoc,devdoc,metadata,hashes --optimize --optimize-runs 10000 --allow-paths ., ./, ../ --evm-version=istanbul","srcMap":"","srcMapRuntime":"","abiDefinition":[{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"relayer","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"BridgeDepositClaimed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"BridgeDepositRefunded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"relayer","type":"address"}],"name":"BridgeProofDisputed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"relayer","type":"address"},{"indexed":false,"internalType":"bytes32","name":"transactionHash","type":"bytes32"}],"name":"BridgeProofProvided","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":false,"internalType":"bytes","name":"quoteId","type":"bytes"}],"name":"BridgeQuoteDetails","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"relayer","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint32","name":"originChainId","type":"uint32"},{"indexed":false,"internalType":"address","name":"originToken","type":"address"},{"indexed":false,"internalType":"address","name":"destToken","type":"address"},{"indexed":false,"internalType":"uint256","name":"originAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"destAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"chainGasAmount","type":"uint256"}],"name":"BridgeRelayed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"bytes","name":"request","type":"bytes"},{"indexed":false,"internalType":"uint32","name":"destChainId","type":"uint32"},{"indexed":false,"internalType":"address","name":"originToken","type":"address"},{"indexed":false,"internalType":"address","name":"destToken","type":"address"},{"indexed":false,"internalType":"uint256","name":"originAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"destAmount","type":"uint256"},{"indexed":false,"internalType":"bool","name":"sendChainGas","type":"bool"}],"name":"BridgeRequested","type":"event"},{"inputs":[{"components":[{"internalType":"uint32","name":"dstChainId","type":"uint32"},{"internalType":"address","name":"sender","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"address","name":"originToken","type":"address"},{"internalType":"address","name":"destToken","type":"address"},{"internalType":"uint256","name":"originAmount","type":"uint256"},{"internalType":"uint256","name":"destAmount","type":"uint256"},{"internalType":"bool","name":"sendChainGas","type":"bool"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"internalType":"struct IFastBridge.BridgeParams","name":"params","type":"tuple"}],"name":"bridge","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"uint32","name":"dstChainId","type":"uint32"},{"internalType":"address","name":"sender","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"address","name":"originToken","type":"address"},{"internalType":"address","name":"destToken","type":"address"},{"internalType":"uint256","name":"originAmount","type":"uint256"},{"internalType":"uint256","name":"destAmount","type":"uint256"},{"internalType":"bool","name":"sendChainGas","type":"bool"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"internalType":"struct IFastBridge.BridgeParams","name":"params","type":"tuple"},{"components":[{"internalType":"address","name":"quoteRelayer","type":"address"},{"internalType":"int256","name":"quoteExclusivitySeconds","type":"int256"},{"internalType":"bytes","name":"quoteId","type":"bytes"},{"internalType":"uint256","name":"zapNative","type":"uint256"},{"internalType":"bytes","name":"zapData","type":"bytes"}],"internalType":"struct IFastBridgeV2.BridgeParamsV2","name":"paramsV2","type":"tuple"}],"name":"bridge","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"transactionId","type":"bytes32"}],"name":"bridgeProofs","outputs":[{"internalType":"uint96","name":"timestamp","type":"uint96"},{"internalType":"address","name":"relayer","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"transactionId","type":"bytes32"}],"name":"bridgeRelays","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"transactionId","type":"bytes32"}],"name":"bridgeStatuses","outputs":[{"internalType":"enum IFastBridgeV2.BridgeStatus","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"internalType":"address","name":"relayer","type":"address"}],"name":"canClaim","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"},{"internalType":"address","name":"to","type":"address"}],"name":"claim","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"}],"name":"claim","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"transactionId","type":"bytes32"}],"name":"dispute","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"}],"name":"getBridgeTransaction","outputs":[{"components":[{"internalType":"uint32","name":"originChainId","type":"uint32"},{"internalType":"uint32","name":"destChainId","type":"uint32"},{"internalType":"address","name":"originSender","type":"address"},{"internalType":"address","name":"destRecipient","type":"address"},{"internalType":"address","name":"originToken","type":"address"},{"internalType":"address","name":"destToken","type":"address"},{"internalType":"uint256","name":"originAmount","type":"uint256"},{"internalType":"uint256","name":"destAmount","type":"uint256"},{"internalType":"uint256","name":"originFeeAmount","type":"uint256"},{"internalType":"bool","name":"sendChainGas","type":"bool"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint256","name":"nonce","type":"uint256"}],"internalType":"struct IFastBridge.BridgeTransaction","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"}],"name":"getBridgeTransactionV2","outputs":[{"components":[{"internalType":"uint32","name":"originChainId","type":"uint32"},{"internalType":"uint32","name":"destChainId","type":"uint32"},{"internalType":"address","name":"originSender","type":"address"},{"internalType":"address","name":"destRecipient","type":"address"},{"internalType":"address","name":"originToken","type":"address"},{"internalType":"address","name":"destToken","type":"address"},{"internalType":"uint256","name":"originAmount","type":"uint256"},{"internalType":"uint256","name":"destAmount","type":"uint256"},{"internalType":"uint256","name":"originFeeAmount","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"address","name":"exclusivityRelayer","type":"address"},{"internalType":"uint256","name":"exclusivityEndTime","type":"uint256"},{"internalType":"uint256","name":"zapNative","type":"uint256"},{"internalType":"bytes","name":"zapData","type":"bytes"}],"internalType":"struct IFastBridgeV2.BridgeTransactionV2","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"internalType":"bytes32","name":"destTxHash","type":"bytes32"},{"internalType":"address","name":"relayer","type":"address"}],"name":"prove","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"},{"internalType":"bytes32","name":"destTxHash","type":"bytes32"}],"name":"prove","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"}],"name":"refund","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"}],"name":"relay","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes","name":"request","type":"bytes"},{"internalType":"address","name":"relayer","type":"address"}],"name":"relay","outputs":[],"stateMutability":"payable","type":"function"}],"userDoc":{"kind":"user","methods":{"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256))":{"notice":"Initiates bridge on origin chain to be relayed by off-chain relayer"},"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256),(address,int256,bytes,uint256,bytes))":{"notice":"Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability to provide temporary exclusivity fill rights for the quote relayer."},"bridgeProofs(bytes32)":{"notice":"Returns the timestamp and relayer of a bridge proof"},"bridgeRelays(bytes32)":{"notice":"Checks if a transaction has been relayed"},"bridgeStatuses(bytes32)":{"notice":"Returns the status of a bridge transaction"},"canClaim(bytes32,address)":{"notice":"Checks if the dispute period has passed so bridge deposit can be claimed"},"claim(bytes)":{"notice":"Completes bridge transaction on origin chain by claiming originally deposited capital.Can only send funds to the relayer address on the proof."},"claim(bytes,address)":{"notice":"Completes bridge transaction on origin chain by claiming originally deposited capital"},"dispute(bytes32)":{"notice":"Disputes an outstanding proof in case relayer provided dest chain tx is invalid"},"getBridgeTransaction(bytes)":{"notice":"Decodes bridge request into a bridge transaction"},"getBridgeTransactionV2(bytes)":{"notice":"Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2"},"prove(bytes,bytes32)":{"notice":"Provides proof on origin side that relayer provided funds on destination side of bridge transaction"},"prove(bytes32,bytes32,address)":{"notice":"Provides proof on origin side that relayer provided funds on destination side of bridge transaction"},"refund(bytes)":{"notice":"Refunds an outstanding bridge transaction in case optimistic bridging failed"},"relay(bytes)":{"notice":"Relays destination side of bridge transaction by off-chain relayer"},"relay(bytes,address)":{"notice":"Relays destination side of bridge transaction by off-chain relayer"}},"version":1},"developerDoc":{"kind":"dev","methods":{"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256))":{"params":{"params":"The parameters required to bridge"}},"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256),(address,int256,bytes,uint256,bytes))":{"params":{"params":"The parameters required to bridge","paramsV2":"The parameters for exclusivity fill rights (optional, can be left empty)"}},"bridgeProofs(bytes32)":{"params":{"transactionId":"The ID of the bridge transaction"},"returns":{"relayer":"The relayer address of the bridge proof","timestamp":"The timestamp of the bridge proof"}},"bridgeRelays(bytes32)":{"params":{"transactionId":"The ID of the transaction to check"},"returns":{"_0":"True if the transaction has been relayed, false otherwise"}},"bridgeStatuses(bytes32)":{"params":{"transactionId":"The ID of the bridge transaction"},"returns":{"_0":"BridgeStatus Status of the bridge transaction"}},"canClaim(bytes32,address)":{"params":{"relayer":"The address of the relayer attempting to claim","transactionId":"The transaction id associated with the encoded bridge transaction to check"}},"claim(bytes)":{"params":{"request":"The encoded bridge transaction to claim on origin chain"}},"claim(bytes,address)":{"params":{"request":"The encoded bridge transaction to claim on origin chain","to":"The recipient address of the funds"}},"dispute(bytes32)":{"params":{"transactionId":"The transaction id associated with the encoded bridge transaction to dispute"}},"getBridgeTransaction(bytes)":{"params":{"request":"The bridge request to decode"}},"getBridgeTransactionV2(bytes)":{"params":{"request":"The bridge request to decode"}},"prove(bytes,bytes32)":{"params":{"destTxHash":"The destination tx hash proving bridge transaction was relayed","request":"The encoded bridge transaction to prove on origin chain"}},"prove(bytes32,bytes32,address)":{"params":{"destTxHash":"The destination tx hash proving bridge transaction was relayed","relayer":"The address of the relaying entity which should have control of the origin funds when claimed","transactionId":"The transaction id associated with the encoded bridge transaction to prove"}},"refund(bytes)":{"params":{"request":"The encoded bridge transaction to refund"}},"relay(bytes)":{"params":{"request":"The encoded bridge transaction to relay on destination chain"}},"relay(bytes,address)":{"params":{"relayer":"The address of the relaying entity which should have control of the origin funds when claimed","request":"The encoded bridge transaction to relay on destination chain"}}},"version":1},"metadata":"{\"compiler\":{\"version\":\"0.8.24+commit.e11b9ed9\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"BridgeDepositClaimed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"BridgeDepositRefunded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"name\":\"BridgeProofDisputed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"transactionHash\",\"type\":\"bytes32\"}],\"name\":\"BridgeProofProvided\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"quoteId\",\"type\":\"bytes\"}],\"name\":\"BridgeQuoteDetails\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"originChainId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"chainGasAmount\",\"type\":\"uint256\"}],\"name\":\"BridgeRelayed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"destChainId\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"sendChainGas\",\"type\":\"bool\"}],\"name\":\"BridgeRequested\",\"type\":\"event\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"dstChainId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"sendChainGas\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"}],\"internalType\":\"struct IFastBridge.BridgeParams\",\"name\":\"params\",\"type\":\"tuple\"}],\"name\":\"bridge\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"dstChainId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"sendChainGas\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"}],\"internalType\":\"struct IFastBridge.BridgeParams\",\"name\":\"params\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"quoteRelayer\",\"type\":\"address\"},{\"internalType\":\"int256\",\"name\":\"quoteExclusivitySeconds\",\"type\":\"int256\"},{\"internalType\":\"bytes\",\"name\":\"quoteId\",\"type\":\"bytes\"},{\"internalType\":\"uint256\",\"name\":\"zapNative\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"zapData\",\"type\":\"bytes\"}],\"internalType\":\"struct IFastBridgeV2.BridgeParamsV2\",\"name\":\"paramsV2\",\"type\":\"tuple\"}],\"name\":\"bridge\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"}],\"name\":\"bridgeProofs\",\"outputs\":[{\"internalType\":\"uint96\",\"name\":\"timestamp\",\"type\":\"uint96\"},{\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"}],\"name\":\"bridgeRelays\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"}],\"name\":\"bridgeStatuses\",\"outputs\":[{\"internalType\":\"enum IFastBridgeV2.BridgeStatus\",\"name\":\"\",\"type\":\"uint8\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"name\":\"canClaim\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"claim\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"claim\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"}],\"name\":\"dispute\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"getBridgeTransaction\",\"outputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"originChainId\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"destChainId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"originSender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destRecipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"originFeeAmount\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"sendChainGas\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"}],\"internalType\":\"struct IFastBridge.BridgeTransaction\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"getBridgeTransactionV2\",\"outputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"originChainId\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"destChainId\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"originSender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destRecipient\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"originToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"originAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"originFeeAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"exclusivityRelayer\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"exclusivityEndTime\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"zapNative\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"zapData\",\"type\":\"bytes\"}],\"internalType\":\"struct IFastBridgeV2.BridgeTransactionV2\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"transactionId\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"destTxHash\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"name\":\"prove\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"},{\"internalType\":\"bytes32\",\"name\":\"destTxHash\",\"type\":\"bytes32\"}],\"name\":\"prove\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"refund\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"}],\"name\":\"relay\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"request\",\"type\":\"bytes\"},{\"internalType\":\"address\",\"name\":\"relayer\",\"type\":\"address\"}],\"name\":\"relay\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{\"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256))\":{\"params\":{\"params\":\"The parameters required to bridge\"}},\"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256),(address,int256,bytes,uint256,bytes))\":{\"params\":{\"params\":\"The parameters required to bridge\",\"paramsV2\":\"The parameters for exclusivity fill rights (optional, can be left empty)\"}},\"bridgeProofs(bytes32)\":{\"params\":{\"transactionId\":\"The ID of the bridge transaction\"},\"returns\":{\"relayer\":\"The relayer address of the bridge proof\",\"timestamp\":\"The timestamp of the bridge proof\"}},\"bridgeRelays(bytes32)\":{\"params\":{\"transactionId\":\"The ID of the transaction to check\"},\"returns\":{\"_0\":\"True if the transaction has been relayed, false otherwise\"}},\"bridgeStatuses(bytes32)\":{\"params\":{\"transactionId\":\"The ID of the bridge transaction\"},\"returns\":{\"_0\":\"BridgeStatus Status of the bridge transaction\"}},\"canClaim(bytes32,address)\":{\"params\":{\"relayer\":\"The address of the relayer attempting to claim\",\"transactionId\":\"The transaction id associated with the encoded bridge transaction to check\"}},\"claim(bytes)\":{\"params\":{\"request\":\"The encoded bridge transaction to claim on origin chain\"}},\"claim(bytes,address)\":{\"params\":{\"request\":\"The encoded bridge transaction to claim on origin chain\",\"to\":\"The recipient address of the funds\"}},\"dispute(bytes32)\":{\"params\":{\"transactionId\":\"The transaction id associated with the encoded bridge transaction to dispute\"}},\"getBridgeTransaction(bytes)\":{\"params\":{\"request\":\"The bridge request to decode\"}},\"getBridgeTransactionV2(bytes)\":{\"params\":{\"request\":\"The bridge request to decode\"}},\"prove(bytes,bytes32)\":{\"params\":{\"destTxHash\":\"The destination tx hash proving bridge transaction was relayed\",\"request\":\"The encoded bridge transaction to prove on origin chain\"}},\"prove(bytes32,bytes32,address)\":{\"params\":{\"destTxHash\":\"The destination tx hash proving bridge transaction was relayed\",\"relayer\":\"The address of the relaying entity which should have control of the origin funds when claimed\",\"transactionId\":\"The transaction id associated with the encoded bridge transaction to prove\"}},\"refund(bytes)\":{\"params\":{\"request\":\"The encoded bridge transaction to refund\"}},\"relay(bytes)\":{\"params\":{\"request\":\"The encoded bridge transaction to relay on destination chain\"}},\"relay(bytes,address)\":{\"params\":{\"relayer\":\"The address of the relaying entity which should have control of the origin funds when claimed\",\"request\":\"The encoded bridge transaction to relay on destination chain\"}}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256))\":{\"notice\":\"Initiates bridge on origin chain to be relayed by off-chain relayer\"},\"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256),(address,int256,bytes,uint256,bytes))\":{\"notice\":\"Initiates bridge on origin chain to be relayed by off-chain relayer, with the ability to provide temporary exclusivity fill rights for the quote relayer.\"},\"bridgeProofs(bytes32)\":{\"notice\":\"Returns the timestamp and relayer of a bridge proof\"},\"bridgeRelays(bytes32)\":{\"notice\":\"Checks if a transaction has been relayed\"},\"bridgeStatuses(bytes32)\":{\"notice\":\"Returns the status of a bridge transaction\"},\"canClaim(bytes32,address)\":{\"notice\":\"Checks if the dispute period has passed so bridge deposit can be claimed\"},\"claim(bytes)\":{\"notice\":\"Completes bridge transaction on origin chain by claiming originally deposited capital.Can only send funds to the relayer address on the proof.\"},\"claim(bytes,address)\":{\"notice\":\"Completes bridge transaction on origin chain by claiming originally deposited capital\"},\"dispute(bytes32)\":{\"notice\":\"Disputes an outstanding proof in case relayer provided dest chain tx is invalid\"},\"getBridgeTransaction(bytes)\":{\"notice\":\"Decodes bridge request into a bridge transaction\"},\"getBridgeTransactionV2(bytes)\":{\"notice\":\"Decodes bridge request into a bridge transaction V2 struct used by FastBridgeV2\"},\"prove(bytes,bytes32)\":{\"notice\":\"Provides proof on origin side that relayer provided funds on destination side of bridge transaction\"},\"prove(bytes32,bytes32,address)\":{\"notice\":\"Provides proof on origin side that relayer provided funds on destination side of bridge transaction\"},\"refund(bytes)\":{\"notice\":\"Refunds an outstanding bridge transaction in case optimistic bridging failed\"},\"relay(bytes)\":{\"notice\":\"Relays destination side of bridge transaction by off-chain relayer\"},\"relay(bytes,address)\":{\"notice\":\"Relays destination side of bridge transaction by off-chain relayer\"}},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solidity/BridgeTransactionV2Harness.sol\":\"IFastBridgeV2\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"solidity/BridgeTransactionV2Harness.sol\":{\"keccak256\":\"0x163fc97efd1365765820c3f01e2d17aa275f32bfbdcd651602808861111a7c00\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://3fbd6475c98b3c1c7e4492e7a59c79a87cc991b403cefd1ac3a980afe441419e\",\"dweb:/ipfs/QmTCQazGcsUMZXtHLFXHwg3Nmc3xFxxFWZ4KY6qXTWpmPx\"]}},\"version\":1}"},"hashes":{"bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256))":"45851694","bridge((uint32,address,address,address,address,uint256,uint256,bool,uint256),(address,int256,bytes,uint256,bytes))":"bfc7c607","bridgeProofs(bytes32)":"91ad5039","bridgeRelays(bytes32)":"8379a24f","bridgeStatuses(bytes32)":"051287bc","canClaim(bytes32,address)":"aa9641ab","claim(bytes)":"c63ff8dd","claim(bytes,address)":"41fcb612","dispute(bytes32)":"add98c70","getBridgeTransaction(bytes)":"ac11fb1a","getBridgeTransactionV2(bytes)":"5aa6ccba","prove(bytes,bytes32)":"886d36ff","prove(bytes32,bytes32,address)":"18e4357d","refund(bytes)":"5eb7d946","relay(bytes)":"8f0d6f17","relay(bytes,address)":"9c9545f0"}}} \ No newline at end of file diff --git a/services/rfq/contracts/bridgetransactionv2/bridgetransactionv2.metadata.go b/services/rfq/contracts/bridgetransactionv2/bridgetransactionv2.metadata.go new file mode 100644 index 0000000000..0b641d6130 --- /dev/null +++ b/services/rfq/contracts/bridgetransactionv2/bridgetransactionv2.metadata.go @@ -0,0 +1,25 @@ +// Code generated by synapse abigen DO NOT EDIT. +package bridgetransactionv2 + +import ( + _ "embed" + "encoding/json" + "github.com/ethereum/go-ethereum/common/compiler" +) + +// rawContracts are the json we use to derive the processed contracts +// +//go:embed bridgetransactionv2.contractinfo.json +var rawContracts []byte + +// Contracts are unmarshalled on start +var Contracts map[string]*compiler.Contract + +func init() { + // load contract metadata + var err error + err = json.Unmarshal(rawContracts, &Contracts) + if err != nil { + panic(err) + } +} diff --git a/services/rfq/contracts/bridgetransactionv2/generate.go b/services/rfq/contracts/bridgetransactionv2/generate.go new file mode 100644 index 0000000000..55207bf7af --- /dev/null +++ b/services/rfq/contracts/bridgetransactionv2/generate.go @@ -0,0 +1,4 @@ +// Package bridgetransactionv2 is the bridge transaction contract. +package bridgetransactionv2 + +//go:generate go run github.com/synapsecns/sanguine/tools/abigen generate --sol ../../../../packages/contracts-rfq/flattened/BridgeTransactionV2Harness.sol --pkg bridgetransactionv2 --sol-version 0.8.24 --filename bridgetransactionv2 --evm-version istanbul diff --git a/services/rfq/contracts/bridgetransactionv2/helper.go b/services/rfq/contracts/bridgetransactionv2/helper.go new file mode 100644 index 0000000000..c755de75fa --- /dev/null +++ b/services/rfq/contracts/bridgetransactionv2/helper.go @@ -0,0 +1,35 @@ +package bridgetransactionv2 + +import ( + "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/vm" +) + +// BridgeTransactionV2Ref is a bound fast bridge contract that returns the address of the contract. +// +//nolint:golint +type BridgeTransactionV2Ref struct { + *BridgeTransactionV2Harness + address common.Address +} + +// Address gets the ocntract address. +func (f *BridgeTransactionV2Ref) Address() common.Address { + return f.address +} + +// NewBridgeTransactionV2Ref creates a new fast bridge mock contract with a ref. +func NewBridgeTransactionV2Ref(address common.Address, backend bind.ContractBackend) (*BridgeTransactionV2Ref, error) { + bridgetransactionv2, err := NewBridgeTransactionV2Harness(address, backend) + if err != nil { + return nil, err + } + + return &BridgeTransactionV2Ref{ + BridgeTransactionV2Harness: bridgetransactionv2, + address: address, + }, nil +} + +var _ vm.ContractRef = &BridgeTransactionV2Ref{} diff --git a/services/rfq/e2e/rfq_test.go b/services/rfq/e2e/rfq_test.go index 5674ba18f5..693e35ad06 100644 --- a/services/rfq/e2e/rfq_test.go +++ b/services/rfq/e2e/rfq_test.go @@ -21,15 +21,19 @@ import ( cctpTest "github.com/synapsecns/sanguine/services/cctp-relayer/testutil" omnirpcClient "github.com/synapsecns/sanguine/services/omnirpc/client" "github.com/synapsecns/sanguine/services/rfq/api/client" + "github.com/synapsecns/sanguine/services/rfq/contracts/bridgetransactionv2" "github.com/synapsecns/sanguine/services/rfq/contracts/fastbridge" "github.com/synapsecns/sanguine/services/rfq/contracts/fastbridgev2" "github.com/synapsecns/sanguine/services/rfq/guard/guarddb" guardService "github.com/synapsecns/sanguine/services/rfq/guard/service" + "github.com/synapsecns/sanguine/services/rfq/relayer/chain" "github.com/synapsecns/sanguine/services/rfq/relayer/reldb" "github.com/synapsecns/sanguine/services/rfq/relayer/service" "github.com/synapsecns/sanguine/services/rfq/testutil" "github.com/synapsecns/sanguine/services/rfq/util" "golang.org/x/sync/errgroup" + + "github.com/brianvoe/gofakeit/v6" ) type IntegrationSuite struct { @@ -403,6 +407,8 @@ func (i *IntegrationSuite) TestZap() { _ = i.guard.Start(i.GetTestContext()) }() + fmt.Printf("omnirpc url: %s\n", i.destBackend.RPCAddress()) + // load token contracts const startAmount = 1000 const rfqAmount = 900 @@ -868,3 +874,107 @@ func (i *IntegrationSuite) TestConcurrentBridges() { return true }) } + +//nolint:gosec +func (i *IntegrationSuite) TestEncodeBridgeTransactionParity() { + _, handle := i.manager.GetBridgeTransactionV2(i.GetTestContext(), i.originBackend) + + mockAddress := func() common.Address { + // Generate 20 random bytes for the address + b := make([]byte, 20) + for i := range b { + b[i] = byte(gofakeit.Number(0, 255)) + } + return common.BytesToAddress(b) + } + + // Generate random values that will be used for both transactions + originChainId := uint32(gofakeit.Number(1, 1000000)) + destChainId := uint32(gofakeit.Number(1, 1000000)) + originSender := mockAddress() + destRecipient := mockAddress() + originToken := mockAddress() + destToken := mockAddress() + originAmount := new(big.Int).SetUint64(gofakeit.Uint64()) + destAmount := new(big.Int).SetUint64(gofakeit.Uint64()) + originFeeAmount := new(big.Int).SetUint64(gofakeit.Uint64()) + deadline := new(big.Int).SetUint64(gofakeit.Uint64()) + nonce := new(big.Int).SetUint64(gofakeit.Uint64()) + exclusivityRelayer := mockAddress() + exclusivityEndTime := new(big.Int).SetUint64(gofakeit.Uint64()) + zapNative := new(big.Int).SetUint64(gofakeit.Uint64()) + + // Random size and values for zapData + zapDataSize := gofakeit.Number(0, 1000) + zapData := make([]byte, zapDataSize) + for i := range zapDataSize { + zapData[i] = gofakeit.Uint8() + } + + // Create first transaction + bridgeTx := bridgetransactionv2.IFastBridgeV2BridgeTransactionV2{ + OriginChainId: originChainId, + DestChainId: destChainId, + OriginSender: originSender, + DestRecipient: destRecipient, + OriginToken: originToken, + DestToken: destToken, + OriginAmount: originAmount, + DestAmount: destAmount, + OriginFeeAmount: originFeeAmount, + Deadline: deadline, + Nonce: nonce, + ExclusivityRelayer: exclusivityRelayer, + ExclusivityEndTime: exclusivityEndTime, + ZapNative: zapNative, + ZapData: zapData, + } + + // Create second transaction with same values + tx := fastbridgev2.IFastBridgeV2BridgeTransactionV2{ + OriginChainId: originChainId, + DestChainId: destChainId, + OriginSender: originSender, + DestRecipient: destRecipient, + OriginToken: originToken, + DestToken: destToken, + OriginAmount: originAmount, + DestAmount: destAmount, + OriginFeeAmount: originFeeAmount, + Deadline: deadline, + Nonce: nonce, + ExclusivityRelayer: exclusivityRelayer, + ExclusivityEndTime: exclusivityEndTime, + ZapNative: zapNative, + ZapData: zapData, + } + + expectedEncoded, err := handle.EncodeV2(&bind.CallOpts{Context: i.GetTestContext()}, bridgeTx) + i.NoError(err) + + encoded, err := chain.EncodeBridgeTx(tx) + i.NoError(err) + + i.Equal(expectedEncoded, encoded) + + // Test decoding + decodedTx, err := chain.DecodeBridgeTx(encoded) + i.NoError(err) + + // Verify all fields match the original transaction + i.Equal(tx.OriginChainId, decodedTx.OriginChainId) + i.Equal(tx.DestChainId, decodedTx.DestChainId) + i.Equal(tx.OriginSender, decodedTx.OriginSender) + i.Equal(tx.DestRecipient, decodedTx.DestRecipient) + i.Equal(tx.OriginToken, decodedTx.OriginToken) + i.Equal(tx.DestToken, decodedTx.DestToken) + i.Equal(tx.OriginAmount.String(), decodedTx.OriginAmount.String()) + i.Equal(tx.DestAmount.String(), decodedTx.DestAmount.String()) + i.Equal(tx.OriginFeeAmount.String(), decodedTx.OriginFeeAmount.String()) + i.Equal(tx.Deadline.String(), decodedTx.Deadline.String()) + i.Equal(tx.Nonce.String(), decodedTx.Nonce.String()) + i.Equal(tx.ExclusivityRelayer, decodedTx.ExclusivityRelayer) + i.Equal(tx.ExclusivityEndTime.String(), decodedTx.ExclusivityEndTime.String()) + i.Equal(tx.ZapNative.String(), decodedTx.ZapNative.String()) + i.Equal(tx.ZapData, decodedTx.ZapData) +} diff --git a/services/rfq/relayer/chain/encoding.go b/services/rfq/relayer/chain/encoding.go new file mode 100644 index 0000000000..b931343f53 --- /dev/null +++ b/services/rfq/relayer/chain/encoding.go @@ -0,0 +1,113 @@ +package chain + +import ( + "encoding/binary" + "fmt" + "math/big" + + "github.com/ethereum/go-ethereum/common" + "github.com/synapsecns/sanguine/services/rfq/contracts/fastbridgev2" +) + +const ( + // Field sizes in bytes. + sizeVersion = 2 + sizeChainID = 4 + sizeAddress = 20 + sizeUint256 = 32 + + // Field offsets in bytes. + offsetVersion = 0 + offsetOriginChainID = offsetVersion + sizeVersion + offsetDestChainID = offsetOriginChainID + sizeChainID + offsetOriginSender = offsetDestChainID + sizeChainID + offsetDestRecipient = offsetOriginSender + sizeAddress + offsetOriginToken = offsetDestRecipient + sizeAddress + offsetDestToken = offsetOriginToken + sizeAddress + offsetOriginAmount = offsetDestToken + sizeAddress + offsetDestAmount = offsetOriginAmount + sizeUint256 + offsetOriginFeeAmount = offsetDestAmount + sizeUint256 + offsetDeadline = offsetOriginFeeAmount + sizeUint256 + offsetNonce = offsetDeadline + sizeUint256 + offsetExclusivityRelayer = offsetNonce + sizeUint256 + offsetExclusivityEndTime = offsetExclusivityRelayer + sizeAddress + offsetZapNative = offsetExclusivityEndTime + sizeUint256 + offsetZapData = offsetZapNative + sizeUint256 +) + +// Helper function to properly encode uint256. +func padUint256(b *big.Int) []byte { + // Convert big.Int to bytes + bytes := b.Bytes() + // Create 32-byte array (initialized to zeros) + result := make([]byte, 32) + // Copy bytes to right side of array (left-pad with zeros) + copy(result[32-len(bytes):], bytes) + return result +} + +// EncodeBridgeTx encodes a bridge transaction into a byte array. +func EncodeBridgeTx(tx fastbridgev2.IFastBridgeV2BridgeTransactionV2) ([]byte, error) { + // Initialize with total size including ZapData + result := make([]byte, offsetZapData+len(tx.ZapData)) + + // Version + result[offsetVersion] = 0 + result[offsetVersion+1] = 2 + + // Chain IDs + binary.BigEndian.PutUint32(result[offsetOriginChainID:offsetOriginChainID+sizeChainID], tx.OriginChainId) + binary.BigEndian.PutUint32(result[offsetDestChainID:offsetDestChainID+sizeChainID], tx.DestChainId) + + // Addresses + copy(result[offsetOriginSender:offsetOriginSender+sizeAddress], tx.OriginSender.Bytes()) + copy(result[offsetDestRecipient:offsetDestRecipient+sizeAddress], tx.DestRecipient.Bytes()) + copy(result[offsetOriginToken:offsetOriginToken+sizeAddress], tx.OriginToken.Bytes()) + copy(result[offsetDestToken:offsetDestToken+sizeAddress], tx.DestToken.Bytes()) + + // uint256 values + copy(result[offsetOriginAmount:offsetOriginAmount+sizeUint256], padUint256(tx.OriginAmount)) + copy(result[offsetDestAmount:offsetDestAmount+sizeUint256], padUint256(tx.DestAmount)) + copy(result[offsetOriginFeeAmount:offsetOriginFeeAmount+sizeUint256], padUint256(tx.OriginFeeAmount)) + copy(result[offsetDeadline:offsetDeadline+sizeUint256], padUint256(tx.Deadline)) + copy(result[offsetNonce:offsetNonce+sizeUint256], padUint256(tx.Nonce)) + + // Exclusivity address + copy(result[offsetExclusivityRelayer:offsetExclusivityRelayer+sizeAddress], tx.ExclusivityRelayer.Bytes()) + + // More uint256 values + copy(result[offsetExclusivityEndTime:offsetExclusivityEndTime+sizeUint256], padUint256(tx.ExclusivityEndTime)) + copy(result[offsetZapNative:offsetZapNative+sizeUint256], padUint256(tx.ZapNative)) + + // Replace append with copy for ZapData + copy(result[offsetZapData:], tx.ZapData) + + return result, nil +} + +// DecodeBridgeTx decodes a byte array into a bridge transaction. +func DecodeBridgeTx(data []byte) (fastbridgev2.IFastBridgeV2BridgeTransactionV2, error) { + if len(data) < offsetZapData { + return fastbridgev2.IFastBridgeV2BridgeTransactionV2{}, fmt.Errorf("data too short: got %d bytes, need at least %d", len(data), offsetZapData) + } + + tx := fastbridgev2.IFastBridgeV2BridgeTransactionV2{ + OriginChainId: binary.BigEndian.Uint32(data[offsetOriginChainID:offsetDestChainID]), + DestChainId: binary.BigEndian.Uint32(data[offsetDestChainID:offsetOriginSender]), + OriginSender: common.BytesToAddress(data[offsetOriginSender:offsetDestRecipient]), + DestRecipient: common.BytesToAddress(data[offsetDestRecipient:offsetOriginToken]), + OriginToken: common.BytesToAddress(data[offsetOriginToken:offsetDestToken]), + DestToken: common.BytesToAddress(data[offsetDestToken:offsetOriginAmount]), + OriginAmount: new(big.Int).SetBytes(data[offsetOriginAmount:offsetDestAmount]), + DestAmount: new(big.Int).SetBytes(data[offsetDestAmount:offsetOriginFeeAmount]), + OriginFeeAmount: new(big.Int).SetBytes(data[offsetOriginFeeAmount:offsetDeadline]), + Deadline: new(big.Int).SetBytes(data[offsetDeadline:offsetNonce]), + Nonce: new(big.Int).SetBytes(data[offsetNonce:offsetExclusivityRelayer]), + ExclusivityRelayer: common.BytesToAddress(data[offsetExclusivityRelayer:offsetExclusivityEndTime]), + ExclusivityEndTime: new(big.Int).SetBytes(data[offsetExclusivityEndTime:offsetZapNative]), + ZapNative: new(big.Int).SetBytes(data[offsetZapNative:offsetZapData]), + ZapData: data[offsetZapData:], + } + + return tx, nil +} diff --git a/services/rfq/relayer/pricer/fee_pricer.go b/services/rfq/relayer/pricer/fee_pricer.go index 7468c7631c..625ba240a2 100644 --- a/services/rfq/relayer/pricer/fee_pricer.go +++ b/services/rfq/relayer/pricer/fee_pricer.go @@ -5,12 +5,19 @@ import ( "context" "fmt" "math/big" + "strings" "time" + "github.com/ethereum/go-ethereum" + "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/ethereum/go-ethereum/common" "github.com/jellydator/ttlcache/v3" "github.com/synapsecns/sanguine/core/metrics" "github.com/synapsecns/sanguine/ethergo/submitter" + "github.com/synapsecns/sanguine/services/rfq/contracts/fastbridgev2" + "github.com/synapsecns/sanguine/services/rfq/relayer/chain" "github.com/synapsecns/sanguine/services/rfq/relayer/relconfig" + "github.com/synapsecns/sanguine/services/rfq/relayer/reldb" "go.opentelemetry.io/otel/attribute" "go.opentelemetry.io/otel/trace" ) @@ -22,9 +29,9 @@ type FeePricer interface { // GetOriginFee returns the total fee for a given chainID and gas limit, denominated in a given token. GetOriginFee(ctx context.Context, origin, destination uint32, denomToken string, isQuote bool) (*big.Int, error) // GetDestinationFee returns the total fee for a given chainID and gas limit, denominated in a given token. - GetDestinationFee(ctx context.Context, origin, destination uint32, denomToken string, isQuote bool) (*big.Int, error) + GetDestinationFee(ctx context.Context, origin, destination uint32, denomToken string, isQuote bool, quoteRequest *reldb.QuoteRequest) (*big.Int, error) // GetTotalFee returns the total fee for a given origin and destination chainID, denominated in a given token. - GetTotalFee(ctx context.Context, origin, destination uint32, denomToken string, isQuote bool) (*big.Int, error) + GetTotalFee(ctx context.Context, origin, destination uint32, denomToken string, isQuote bool, quoteRequest *reldb.QuoteRequest) (*big.Int, error) // GetGasPrice returns the gas price for a given chainID in native units. GetGasPrice(ctx context.Context, chainID uint32) (*big.Int, error) // GetTokenPrice returns the price of a token in USD. @@ -44,10 +51,12 @@ type feePricer struct { handler metrics.Handler // priceFetcher is used to fetch prices from coingecko. priceFetcher CoingeckoPriceFetcher + // relayerAddress is the address of the relayer. + relayerAddress common.Address } // NewFeePricer creates a new fee pricer. -func NewFeePricer(config relconfig.Config, clientFetcher submitter.ClientFetcher, priceFetcher CoingeckoPriceFetcher, handler metrics.Handler) FeePricer { +func NewFeePricer(config relconfig.Config, clientFetcher submitter.ClientFetcher, priceFetcher CoingeckoPriceFetcher, handler metrics.Handler, relayerAddress common.Address) FeePricer { gasPriceCache := ttlcache.New[uint32, *big.Int]( ttlcache.WithTTL[uint32, *big.Int](time.Second*time.Duration(config.GetFeePricer().GasPriceCacheTTLSeconds)), ttlcache.WithDisableTouchOnHit[uint32, *big.Int](), @@ -63,6 +72,7 @@ func NewFeePricer(config relconfig.Config, clientFetcher submitter.ClientFetcher clientFetcher: clientFetcher, handler: handler, priceFetcher: priceFetcher, + relayerAddress: relayerAddress, } } @@ -116,7 +126,8 @@ func (f *feePricer) GetOriginFee(parentCtx context.Context, origin, destination return fee, nil } -func (f *feePricer) GetDestinationFee(parentCtx context.Context, _, destination uint32, denomToken string, isQuote bool) (*big.Int, error) { +//nolint:gosec +func (f *feePricer) GetDestinationFee(parentCtx context.Context, _, destination uint32, denomToken string, isQuote bool, quoteRequest *reldb.QuoteRequest) (*big.Int, error) { var err error ctx, span := f.handler.Tracer().Start(parentCtx, "getDestinationFee", trace.WithAttributes( attribute.Int(metrics.Destination, int(destination)), @@ -127,14 +138,28 @@ func (f *feePricer) GetDestinationFee(parentCtx context.Context, _, destination metrics.EndSpanWithErr(span, err) }() - // Calculate the destination fee - gasEstimate, err := f.config.GetDestGasEstimate(int(destination)) - if err != nil { - return nil, fmt.Errorf("could not get dest gas estimate: %w", err) + fee := big.NewInt(0) + + // Calculate the static L2 fee if it won't be incorporated by directly estimating the relay() call + // in addZapFees(). + if quoteRequest == nil || quoteRequest.Transaction.ZapNative == nil || quoteRequest.Transaction.ZapData == nil { + gasEstimate, err := f.config.GetDestGasEstimate(int(destination)) + if err != nil { + return nil, fmt.Errorf("could not get dest gas estimate: %w", err) + } + fee, err = f.getFee(ctx, destination, destination, gasEstimate, denomToken, isQuote) + if err != nil { + return nil, err + } } - fee, err := f.getFee(ctx, destination, destination, gasEstimate, denomToken, isQuote) - if err != nil { - return nil, err + span.SetAttributes(attribute.String("raw_fee", fee.String())) + + // If specified, calculate and add the call fee, as well as the call value which will be paid by the relayer + if quoteRequest != nil { + fee, err = f.addZapFees(ctx, destination, denomToken, quoteRequest, fee) + if err != nil { + return nil, err + } } // If specified, calculate and add the L1 fee @@ -147,11 +172,97 @@ func (f *feePricer) GetDestinationFee(parentCtx context.Context, _, destination fee = new(big.Int).Add(fee, l1Fee) span.SetAttributes(attribute.String("l1_fee", l1Fee.String())) } + span.SetAttributes(attribute.String("destination_fee", fee.String())) return fee, nil } -func (f *feePricer) GetTotalFee(parentCtx context.Context, origin, destination uint32, denomToken string, isQuote bool) (_ *big.Int, err error) { +// addZapFees incorporates the cost of the call and the call value into the fee. +// Note that to be conservative, we always use the QuoteFixedFeeMultiplier over the RelayFixedFeeMultiplier. +// +//nolint:gosec +func (f *feePricer) addZapFees(ctx context.Context, destination uint32, denomToken string, quoteRequest *reldb.QuoteRequest, fee *big.Int) (*big.Int, error) { + span := trace.SpanFromContext(ctx) + + if quoteRequest.Transaction.ZapData != nil { + gasEstimate, err := f.getZapGasEstimate(ctx, destination, quoteRequest) + if err != nil { + return nil, err + } + callFee, err := f.getFee(ctx, destination, destination, int(gasEstimate), denomToken, true) + if err != nil { + return nil, err + } + fee = new(big.Int).Add(fee, callFee) + span.SetAttributes(attribute.String("call_fee", callFee.String())) + } + + if quoteRequest.Transaction.ZapNative != nil && quoteRequest.Transaction.ZapNative.Sign() > 0 { + callValueFloat := new(big.Float).SetInt(quoteRequest.Transaction.ZapNative) + valueDenom, err := f.getDenomFee(ctx, destination, destination, denomToken, callValueFloat) + if err != nil { + return nil, err + } + valueScaled, err := f.getFeeWithMultiplier(ctx, destination, true, valueDenom) + if err != nil { + return nil, err + } + fee = new(big.Int).Add(fee, valueScaled) + span.SetAttributes(attribute.String("value_scaled", valueScaled.String())) + } + + return fee, nil +} + +// cache so that we don't have to parse the ABI every time. +var fastBridgeV2ABI *abi.ABI + +const methodName = "relay0" + +func (f *feePricer) getZapGasEstimate(ctx context.Context, destination uint32, quoteRequest *reldb.QuoteRequest) (gasEstimate uint64, err error) { + client, err := f.clientFetcher.GetClient(ctx, big.NewInt(int64(destination))) + if err != nil { + return 0, fmt.Errorf("could not get client: %w", err) + } + + if fastBridgeV2ABI == nil { + parsedABI, err := abi.JSON(strings.NewReader(fastbridgev2.IFastBridgeV2MetaData.ABI)) + if err != nil { + return 0, fmt.Errorf("could not parse ABI: %w", err) + } + fastBridgeV2ABI = &parsedABI + } + + rawRequest, err := chain.EncodeBridgeTx(quoteRequest.Transaction) + if err != nil { + return 0, fmt.Errorf("could not encode quote data: %w", err) + } + + encodedData, err := fastBridgeV2ABI.Pack(methodName, rawRequest, f.relayerAddress) + if err != nil { + return 0, fmt.Errorf("could not encode function call: %w", err) + } + + rfqAddr, err := f.config.GetRFQAddress(int(destination)) + if err != nil { + return 0, fmt.Errorf("could not get RFQ address: %w", err) + } + + callMsg := ethereum.CallMsg{ + From: f.relayerAddress, + To: &rfqAddr, + Value: quoteRequest.Transaction.ZapNative, + Data: encodedData, + } + gasEstimate, err = client.EstimateGas(ctx, callMsg) + if err != nil { + return 0, fmt.Errorf("could not estimate gas: %w", err) + } + + return gasEstimate, nil +} + +func (f *feePricer) GetTotalFee(parentCtx context.Context, origin, destination uint32, denomToken string, isQuote bool, quoteRequest *reldb.QuoteRequest) (_ *big.Int, err error) { ctx, span := f.handler.Tracer().Start(parentCtx, "getTotalFee", trace.WithAttributes( attribute.Int(metrics.Origin, int(origin)), attribute.Int(metrics.Destination, int(destination)), @@ -170,7 +281,7 @@ func (f *feePricer) GetTotalFee(parentCtx context.Context, origin, destination u )) return nil, err } - destFee, err := f.GetDestinationFee(ctx, origin, destination, denomToken, isQuote) + destFee, err := f.GetDestinationFee(ctx, origin, destination, denomToken, isQuote, quoteRequest) if err != nil { span.AddEvent("could not get destination fee", trace.WithAttributes( attribute.String("error", err.Error()), @@ -202,6 +313,30 @@ func (f *feePricer) getFee(parentCtx context.Context, gasChain, denomChain uint3 if err != nil { return nil, err } + feeWei := new(big.Float).Mul(new(big.Float).SetInt(gasPrice), new(big.Float).SetFloat64(float64(gasEstimate))) + + feeDenom, err := f.getDenomFee(ctx, gasChain, denomChain, denomToken, feeWei) + if err != nil { + return nil, err + } + + feeScaled, err := f.getFeeWithMultiplier(ctx, gasChain, isQuote, feeDenom) + if err != nil { + return nil, err + } + + span.SetAttributes( + attribute.String("gas_price", gasPrice.String()), + attribute.String("fee_wei", feeWei.String()), + attribute.String("fee_denom", feeDenom.String()), + attribute.String("fee_scaled", feeScaled.String()), + ) + return feeScaled, nil +} + +func (f *feePricer) getDenomFee(ctx context.Context, gasChain, denomChain uint32, denomToken string, feeWei *big.Float) (*big.Float, error) { + span := trace.SpanFromContext(ctx) + nativeToken, err := f.config.GetNativeToken(int(gasChain)) if err != nil { return nil, err @@ -222,7 +357,6 @@ func (f *feePricer) getFee(parentCtx context.Context, gasChain, denomChain uint3 // Compute the fee. var feeDenom *big.Float - feeWei := new(big.Float).Mul(new(big.Float).SetInt(gasPrice), new(big.Float).SetFloat64(float64(gasEstimate))) if denomToken == nativeToken { // Denomination token is native token, so no need for unit conversion. feeDenom = feeWei @@ -239,6 +373,17 @@ func (f *feePricer) getFee(parentCtx context.Context, gasChain, denomChain uint3 attribute.String("fee_usdc", feeUSDC.String()), ) } + span.SetAttributes( + attribute.Float64("native_token_price", nativeTokenPrice), + attribute.Float64("denom_token_price", denomTokenPrice), + attribute.Int("denom_token_decimals", int(denomTokenDecimals)), + ) + + return feeDenom, nil +} + +func (f *feePricer) getFeeWithMultiplier(ctx context.Context, gasChain uint32, isQuote bool, feeDenom *big.Float) (feeScaled *big.Int, err error) { + span := trace.SpanFromContext(ctx) var multiplier float64 if isQuote { @@ -252,22 +397,16 @@ func (f *feePricer) getFee(parentCtx context.Context, gasChain, denomChain uint3 return nil, fmt.Errorf("could not get relay fixed fee multiplier: %w", err) } } + span.SetAttributes( + attribute.Float64("multiplier", multiplier), + ) // Apply the fixed fee multiplier. // Note that this step rounds towards zero- we may need to apply rounding here if // we want to be conservative and lean towards overestimating fees. - feeUSDCDecimalsScaled, _ := new(big.Float).Mul(feeDenom, new(big.Float).SetFloat64(multiplier)).Int(nil) - span.SetAttributes( - attribute.String("gas_price", gasPrice.String()), - attribute.Float64("native_token_price", nativeTokenPrice), - attribute.Float64("denom_token_price", denomTokenPrice), - attribute.Float64("multplier", multiplier), - attribute.Int("denom_token_decimals", int(denomTokenDecimals)), - attribute.String("fee_wei", feeWei.String()), - attribute.String("fee_denom", feeDenom.String()), - attribute.String("fee_usdc_decimals_scaled", feeUSDCDecimalsScaled.String()), - ) - return feeUSDCDecimalsScaled, nil + feeScaled, _ = new(big.Float).Mul(feeDenom, new(big.Float).SetFloat64(multiplier)).Int(nil) + + return feeScaled, nil } // getGasPrice returns the gas price for a given chainID in native units. diff --git a/services/rfq/relayer/pricer/fee_pricer_test.go b/services/rfq/relayer/pricer/fee_pricer_test.go index 6b6174c7c3..25cf9e4d8b 100644 --- a/services/rfq/relayer/pricer/fee_pricer_test.go +++ b/services/rfq/relayer/pricer/fee_pricer_test.go @@ -4,17 +4,21 @@ import ( "fmt" "math/big" + "github.com/ethereum/go-ethereum/common" "github.com/stretchr/testify/mock" "github.com/synapsecns/sanguine/core/metrics" "github.com/synapsecns/sanguine/core/testsuite" clientMocks "github.com/synapsecns/sanguine/ethergo/client/mocks" fetcherMocks "github.com/synapsecns/sanguine/ethergo/submitter/mocks" + "github.com/synapsecns/sanguine/services/rfq/contracts/fastbridgev2" "github.com/synapsecns/sanguine/services/rfq/relayer/pricer" priceMocks "github.com/synapsecns/sanguine/services/rfq/relayer/pricer/mocks" "github.com/synapsecns/sanguine/services/rfq/relayer/relconfig" + "github.com/synapsecns/sanguine/services/rfq/relayer/reldb" ) var defaultPrices = map[string]float64{"ETH": 2000., "USDC": 1., "MATIC": 0.5} +var relayerAddress = common.HexToAddress("0x1234567890123456789012345678901234567890") func getPriceFetcher(prices map[string]float64) *priceMocks.CoingeckoPriceFetcher { priceFetcher := new(priceMocks.CoingeckoPriceFetcher) @@ -38,7 +42,7 @@ func (s *PricerSuite) TestGetOriginFee() { client.On(testsuite.GetFunctionName(client.SuggestGasPrice), mock.Anything).Once().Return(currentHeader, nil) clientFetcher.On(testsuite.GetFunctionName(clientFetcher.GetClient), mock.Anything, mock.Anything).Twice().Return(client, nil) priceFetcher := getPriceFetcher(nil) - feePricer := pricer.NewFeePricer(s.config, clientFetcher, priceFetcher, metrics.NewNullHandler()) + feePricer := pricer.NewFeePricer(s.config, clientFetcher, priceFetcher, metrics.NewNullHandler(), relayerAddress) go func() { feePricer.Start(s.GetTestContext()) }() // Calculate the origin fee. @@ -82,7 +86,7 @@ func (s *PricerSuite) TestGetOriginFeeWithOverrides() { client.On(testsuite.GetFunctionName(client.SuggestGasPrice), mock.Anything).Return(currentHeader, nil) clientFetcher.On(testsuite.GetFunctionName(clientFetcher.GetClient), mock.Anything, mock.Anything).Return(client, nil) priceFetcher := getPriceFetcher(map[string]float64{"ETH": 1000}) - feePricer := pricer.NewFeePricer(s.config, clientFetcher, priceFetcher, metrics.NewNullHandler()) + feePricer := pricer.NewFeePricer(s.config, clientFetcher, priceFetcher, metrics.NewNullHandler(), relayerAddress) go func() { feePricer.Start(s.GetTestContext()) }() // Calculate the origin fee. @@ -123,11 +127,11 @@ func (s *PricerSuite) TestGetDestinationFee() { client.On(testsuite.GetFunctionName(client.SuggestGasPrice), mock.Anything).Once().Return(currentHeader, nil) clientFetcher.On(testsuite.GetFunctionName(clientFetcher.GetClient), mock.Anything, mock.Anything).Twice().Return(client, nil) priceFetcher := getPriceFetcher(nil) - feePricer := pricer.NewFeePricer(s.config, clientFetcher, priceFetcher, metrics.NewNullHandler()) + feePricer := pricer.NewFeePricer(s.config, clientFetcher, priceFetcher, metrics.NewNullHandler(), relayerAddress) go func() { feePricer.Start(s.GetTestContext()) }() // Calculate the destination fee. - fee, err := feePricer.GetDestinationFee(s.GetTestContext(), s.origin, s.destination, "USDC", true) + fee, err := feePricer.GetDestinationFee(s.GetTestContext(), s.origin, s.destination, "USDC", true, nil) s.NoError(err) /* @@ -146,7 +150,7 @@ func (s *PricerSuite) TestGetDestinationFee() { // Ensure that the fee has been cached. client.On(testsuite.GetFunctionName(client.SuggestGasPrice), mock.Anything).Once().Return(nil, fmt.Errorf("could not fetch header")) - fee, err = feePricer.GetDestinationFee(s.GetTestContext(), s.origin, s.destination, "USDC", true) + fee, err = feePricer.GetDestinationFee(s.GetTestContext(), s.origin, s.destination, "USDC", true, nil) s.NoError(err) s.Equal(expectedFee, fee) } @@ -167,11 +171,11 @@ func (s *PricerSuite) TestGetDestinationFeeWithOverrides() { client.On(testsuite.GetFunctionName(client.SuggestGasPrice), mock.Anything).Return(currentHeader, nil) clientFetcher.On(testsuite.GetFunctionName(clientFetcher.GetClient), mock.Anything, mock.Anything).Return(client, nil) priceFetcher := getPriceFetcher(nil) - feePricer := pricer.NewFeePricer(s.config, clientFetcher, priceFetcher, metrics.NewNullHandler()) + feePricer := pricer.NewFeePricer(s.config, clientFetcher, priceFetcher, metrics.NewNullHandler(), relayerAddress) go func() { feePricer.Start(s.GetTestContext()) }() // Calculate the destination fee. - fee, err := feePricer.GetDestinationFee(s.GetTestContext(), s.origin, s.destination, "USDC", true) + fee, err := feePricer.GetDestinationFee(s.GetTestContext(), s.origin, s.destination, "USDC", true, nil) s.NoError(err) /* @@ -195,7 +199,7 @@ func (s *PricerSuite) TestGetDestinationFeeWithOverrides() { // Ensure that the fee has been cached. client.On(testsuite.GetFunctionName(client.SuggestGasPrice), mock.Anything).Once().Return(nil, fmt.Errorf("could not fetch header")) - fee, err = feePricer.GetDestinationFee(s.GetTestContext(), s.origin, s.destination, "USDC", true) + fee, err = feePricer.GetDestinationFee(s.GetTestContext(), s.origin, s.destination, "USDC", true, nil) s.NoError(err) s.Equal(expectedFee, fee) } @@ -207,21 +211,55 @@ func (s *PricerSuite) TestGetTotalFee() { clientDestination := new(clientMocks.EVM) headerOrigin := big.NewInt(100_000_000_000) // 100 gwei headerDestination := big.NewInt(500_000_000_000) // 500 gwei - clientOrigin.On(testsuite.GetFunctionName(clientOrigin.SuggestGasPrice), mock.Anything).Once().Return(headerOrigin, nil) - clientDestination.On(testsuite.GetFunctionName(clientDestination.SuggestGasPrice), mock.Anything).Once().Return(headerDestination, nil) - clientFetcher.On(testsuite.GetFunctionName(clientFetcher.GetClient), mock.Anything, big.NewInt(int64(s.origin))).Once().Return(clientOrigin, nil) - clientFetcher.On(testsuite.GetFunctionName(clientFetcher.GetClient), mock.Anything, big.NewInt(int64(s.destination))).Once().Return(clientDestination, nil) + clientOrigin.On(testsuite.GetFunctionName(clientOrigin.SuggestGasPrice), mock.Anything).Return(headerOrigin, nil) + clientDestination.On(testsuite.GetFunctionName(clientDestination.SuggestGasPrice), mock.Anything).Return(headerDestination, nil) + clientFetcher.On(testsuite.GetFunctionName(clientFetcher.GetClient), mock.Anything, big.NewInt(int64(s.origin))).Return(clientOrigin, nil) + clientFetcher.On(testsuite.GetFunctionName(clientFetcher.GetClient), mock.Anything, big.NewInt(int64(s.destination))).Return(clientDestination, nil) priceFetcher := getPriceFetcher(nil) - feePricer := pricer.NewFeePricer(s.config, clientFetcher, priceFetcher, metrics.NewNullHandler()) + feePricer := pricer.NewFeePricer(s.config, clientFetcher, priceFetcher, metrics.NewNullHandler(), relayerAddress) go func() { feePricer.Start(s.GetTestContext()) }() // Calculate the total fee. - fee, err := feePricer.GetTotalFee(s.GetTestContext(), s.origin, s.destination, "USDC", true) + fee, err := feePricer.GetTotalFee(s.GetTestContext(), s.origin, s.destination, "USDC", true, nil) s.NoError(err) // The expected fee should be the sum of the Origin and Destination fees, i.e. 100_250_000. expectedFee := big.NewInt(100_250_000) // 100.25 usd s.Equal(expectedFee, fee) + + // Calculate the total fee with v2 call value. + quoteRequest := &reldb.QuoteRequest{ + RawRequest: []byte{}, + Transaction: fastbridgev2.IFastBridgeV2BridgeTransactionV2{ + ZapNative: big.NewInt(1 * 1e18), + }, + } + fee, err = feePricer.GetTotalFee(s.GetTestContext(), s.origin, s.destination, "USDC", true, quoteRequest) + s.NoError(err) + + // The expected fee should be the sum of the Origin and Destination fees, i.e. 100_750_000, + // plus the call value of 1 MATIC * 0.5 USD. + expectedFee = big.NewInt(100_750_000) // 100.75 usd + s.Equal(expectedFee, fee) + + // Calculate the total fee with v2 call value and call params. + quoteRequest = &reldb.QuoteRequest{ + RawRequest: []byte{}, + Transaction: fastbridgev2.IFastBridgeV2BridgeTransactionV2{ + ZapNative: big.NewInt(1 * 1e18), + ZapData: []byte{1}, + DestAmount: big.NewInt(1 * 1e18), + }, + } + clientDestination.On(testsuite.GetFunctionName(clientDestination.EstimateGas), mock.Anything, mock.Anything).Once().Return(uint64(1_000_000), nil) + fee, err = feePricer.GetTotalFee(s.GetTestContext(), s.origin, s.destination, "USDC", true, quoteRequest) + s.NoError(err) + + // The expected fee should be the sum of the Origin and Destination fees + // plus the call value of 1 MATIC * 0.5 USD. + // Note that the static L2 fee is covered by the Zap fees. + expectedFee = big.NewInt(100_750_000) // 100.75 usd + s.Equal(expectedFee, fee) } func (s *PricerSuite) TestGetGasPrice() { @@ -234,7 +272,7 @@ func (s *PricerSuite) TestGetGasPrice() { // Override the gas price cache TTL to 1 second. s.config.FeePricer.GasPriceCacheTTLSeconds = 1 priceFetcher := getPriceFetcher(nil) - feePricer := pricer.NewFeePricer(s.config, clientFetcher, priceFetcher, metrics.NewNullHandler()) + feePricer := pricer.NewFeePricer(s.config, clientFetcher, priceFetcher, metrics.NewNullHandler(), relayerAddress) go func() { feePricer.Start(s.GetTestContext()) }() // Fetch the mocked gas price. @@ -276,11 +314,11 @@ func (s *PricerSuite) TestGetTotalFeeWithMultiplier() { clientFetcher.On(testsuite.GetFunctionName(clientFetcher.GetClient), mock.Anything, big.NewInt(int64(s.origin))).Once().Return(clientOrigin, nil) clientFetcher.On(testsuite.GetFunctionName(clientFetcher.GetClient), mock.Anything, big.NewInt(int64(s.destination))).Once().Return(clientDestination, nil) priceFetcher := getPriceFetcher(nil) - feePricer := pricer.NewFeePricer(s.config, clientFetcher, priceFetcher, metrics.NewNullHandler()) + feePricer := pricer.NewFeePricer(s.config, clientFetcher, priceFetcher, metrics.NewNullHandler(), relayerAddress) go func() { feePricer.Start(s.GetTestContext()) }() // Calculate the total fee [quote]. - fee, err := feePricer.GetTotalFee(s.GetTestContext(), s.origin, s.destination, "USDC", true) + fee, err := feePricer.GetTotalFee(s.GetTestContext(), s.origin, s.destination, "USDC", true, nil) s.NoError(err) // The expected fee should be the sum of the Origin and Destination fees, i.e. 200_500_000. @@ -288,7 +326,7 @@ func (s *PricerSuite) TestGetTotalFeeWithMultiplier() { s.Equal(expectedFee, fee) // Calculate the total fee [relay]. - fee, err = feePricer.GetTotalFee(s.GetTestContext(), s.origin, s.destination, "USDC", false) + fee, err = feePricer.GetTotalFee(s.GetTestContext(), s.origin, s.destination, "USDC", false, nil) s.NoError(err) // The expected fee should be the sum of the Origin and Destination fees, i.e. 401_000_000. @@ -303,11 +341,11 @@ func (s *PricerSuite) TestGetTotalFeeWithMultiplier() { clientDestination.On(testsuite.GetFunctionName(clientDestination.SuggestGasPrice), mock.Anything).Once().Return(headerDestination, nil) clientFetcher.On(testsuite.GetFunctionName(clientFetcher.GetClient), mock.Anything, big.NewInt(int64(s.origin))).Once().Return(clientOrigin, nil) clientFetcher.On(testsuite.GetFunctionName(clientFetcher.GetClient), mock.Anything, big.NewInt(int64(s.destination))).Once().Return(clientDestination, nil) - feePricer = pricer.NewFeePricer(s.config, clientFetcher, priceFetcher, metrics.NewNullHandler()) + feePricer = pricer.NewFeePricer(s.config, clientFetcher, priceFetcher, metrics.NewNullHandler(), relayerAddress) go func() { feePricer.Start(s.GetTestContext()) }() // Calculate the total fee. - fee, err = feePricer.GetTotalFee(s.GetTestContext(), s.origin, s.destination, "USDC", true) + fee, err = feePricer.GetTotalFee(s.GetTestContext(), s.origin, s.destination, "USDC", true, nil) s.NoError(err) // The expected fee should be the sum of the Origin and Destination fees, i.e. 100_250_000. @@ -322,11 +360,11 @@ func (s *PricerSuite) TestGetTotalFeeWithMultiplier() { clientDestination.On(testsuite.GetFunctionName(clientDestination.SuggestGasPrice), mock.Anything).Once().Return(headerDestination, nil) clientFetcher.On(testsuite.GetFunctionName(clientFetcher.GetClient), mock.Anything, big.NewInt(int64(s.origin))).Once().Return(clientOrigin, nil) clientFetcher.On(testsuite.GetFunctionName(clientFetcher.GetClient), mock.Anything, big.NewInt(int64(s.destination))).Once().Return(clientDestination, nil) - feePricer = pricer.NewFeePricer(s.config, clientFetcher, priceFetcher, metrics.NewNullHandler()) + feePricer = pricer.NewFeePricer(s.config, clientFetcher, priceFetcher, metrics.NewNullHandler(), relayerAddress) go func() { feePricer.Start(s.GetTestContext()) }() // Calculate the total fee. - fee, err = feePricer.GetTotalFee(s.GetTestContext(), s.origin, s.destination, "USDC", true) + fee, err = feePricer.GetTotalFee(s.GetTestContext(), s.origin, s.destination, "USDC", true, nil) s.NoError(err) // The expected fee should be the sum of the Origin and Destination fees, i.e. 100_250_000. diff --git a/services/rfq/relayer/pricer/suite_test.go b/services/rfq/relayer/pricer/suite_test.go index 35640388de..9c834647ab 100644 --- a/services/rfq/relayer/pricer/suite_test.go +++ b/services/rfq/relayer/pricer/suite_test.go @@ -42,6 +42,7 @@ func (c *PricerSuite) SetupTest() { }, Chains: map[int]relconfig.ChainConfig{ int(c.origin): { + RFQAddress: "0x0000000000000000000000000000000000000000", Tokens: map[string]relconfig.TokenConfig{ "USDC": { Address: "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48", @@ -57,6 +58,7 @@ func (c *PricerSuite) SetupTest() { NativeToken: "ETH", }, int(c.destination): { + RFQAddress: "0x0000000000000000000000000000000000000000", Tokens: map[string]relconfig.TokenConfig{ "USDC": { Address: "0x0b2c639c533813f4aa9d7837caf62653d097ff85", diff --git a/services/rfq/relayer/quoter/export_test.go b/services/rfq/relayer/quoter/export_test.go index 9f12c9477d..8111df11b8 100644 --- a/services/rfq/relayer/quoter/export_test.go +++ b/services/rfq/relayer/quoter/export_test.go @@ -22,6 +22,10 @@ func (m *Manager) GetDestAmount(ctx context.Context, quoteAmount *big.Int, token return m.getDestAmount(ctx, quoteAmount, tokenName, input) } +func (m *Manager) GenerateActiveRFQ(ctx context.Context, msg *model.ActiveRFQMessage) (resp *model.ActiveRFQMessage, err error) { + return m.generateActiveRFQ(ctx, msg) +} + func (m *Manager) SetConfig(cfg relconfig.Config) { m.config = cfg } diff --git a/services/rfq/relayer/quoter/quoter.go b/services/rfq/relayer/quoter/quoter.go index f0520618a1..c552aad541 100644 --- a/services/rfq/relayer/quoter/quoter.go +++ b/services/rfq/relayer/quoter/quoter.go @@ -21,6 +21,7 @@ import ( "github.com/ipfs/go-log" "github.com/synapsecns/sanguine/core/metrics" + "github.com/synapsecns/sanguine/services/rfq/contracts/fastbridgev2" "github.com/synapsecns/sanguine/services/rfq/relayer/pricer" "github.com/synapsecns/sanguine/services/rfq/relayer/relconfig" "github.com/synapsecns/sanguine/services/rfq/relayer/reldb" @@ -233,7 +234,7 @@ func (m *Manager) IsProfitable(parentCtx context.Context, quote reldb.QuoteReque if err != nil { return false, fmt.Errorf("error getting dest token ID: %w", err) } - fee, err := m.feePricer.GetTotalFee(ctx, quote.Transaction.OriginChainId, quote.Transaction.DestChainId, destTokenID, false) + fee, err := m.feePricer.GetTotalFee(ctx, quote.Transaction.OriginChainId, quote.Transaction.DestChainId, destTokenID, false, "e) if err != nil { return false, fmt.Errorf("error getting total fee: %w", err) } @@ -337,7 +338,7 @@ func (m *Manager) SubscribeActiveRFQ(ctx context.Context) (err error) { // getActiveRFQ handles an active RFQ message. // -//nolint:nilnil +//nolint:nilnil,cyclop func (m *Manager) generateActiveRFQ(ctx context.Context, msg *model.ActiveRFQMessage) (resp *model.ActiveRFQMessage, err error) { ctx, span := m.metricsHandler.Tracer().Start(ctx, "generateActiveRFQ", trace.WithAttributes( attribute.String("op", msg.Op), @@ -364,6 +365,7 @@ func (m *Manager) generateActiveRFQ(ctx context.Context, msg *model.ActiveRFQMes } span.SetAttributes(attribute.String("request_id", rfqRequest.RequestID)) + // TODO: incorporate the user call data into the quote request and set the Transaction here originAmountExact, ok := new(big.Int).SetString(rfqRequest.Data.OriginAmountExact, 10) if !ok { return nil, fmt.Errorf("invalid rfq request deposit amount: %s", rfqRequest.Data.OriginAmountExact) @@ -378,11 +380,33 @@ func (m *Manager) generateActiveRFQ(ctx context.Context, msg *model.ActiveRFQMes DestBalance: inv[rfqRequest.Data.DestChainID][common.HexToAddress(rfqRequest.Data.DestTokenAddr)], OriginAmountExact: originAmountExact, } + if rfqRequest.Data.ZapNative != "" || rfqRequest.Data.ZapData != "" { + quoteRequest, err := quoteDataToQuoteRequestV2(&rfqRequest.Data) + if err != nil { + return nil, fmt.Errorf("error converting quote data to quote request: %w", err) + } + quoteInput.QuoteRequest = quoteRequest + } rawQuote, err := m.generateQuote(ctx, quoteInput) if err != nil { return nil, fmt.Errorf("error generating quote: %w", err) } + + // adjust dest amount by fixed fee + destAmountBigInt, ok := new(big.Int).SetString(rawQuote.DestAmount, 10) + if !ok { + return nil, fmt.Errorf("invalid dest amount: %s", rawQuote.DestAmount) + } + fixedFeeBigInt, ok := new(big.Int).SetString(rawQuote.FixedFee, 10) + if !ok { + return nil, fmt.Errorf("invalid fixed fee: %s", rawQuote.FixedFee) + } + destAmountAdj := new(big.Int).Sub(destAmountBigInt, fixedFeeBigInt) + if destAmountAdj.Sign() < 0 { + destAmountAdj = big.NewInt(0) + } + rawQuote.DestAmount = destAmountAdj.String() span.SetAttributes(attribute.String("dest_amount", rawQuote.DestAmount)) rfqResp := model.WsRFQResponse{ @@ -403,6 +427,50 @@ func (m *Manager) generateActiveRFQ(ctx context.Context, msg *model.ActiveRFQMes return resp, nil } +//nolint:gosec +func quoteDataToQuoteRequestV2(quoteData *model.QuoteData) (*reldb.QuoteRequest, error) { + if quoteData == nil { + return nil, errors.New("quote data is nil") + } + + originAmount, ok := new(big.Int).SetString(quoteData.OriginAmountExact, 10) + if !ok { + return nil, errors.New("invalid origin amount") + } + destAmount := originAmount // assume dest amount same as origin amount for estimation purposes + originFeeAmount := big.NewInt(0) + nonce := big.NewInt(0) + exclusivityEndTime := big.NewInt(0) + zapNative, ok := new(big.Int).SetString(quoteData.ZapNative, 10) + if !ok { + return nil, errors.New("invalid zap native") + } + deadline := new(big.Int).Sub(new(big.Int).Exp(big.NewInt(2), big.NewInt(256), nil), big.NewInt(1)) + exclusivityRelayer := common.HexToAddress("") + + quoteRequest := &reldb.QuoteRequest{ + Transaction: fastbridgev2.IFastBridgeV2BridgeTransactionV2{ + OriginChainId: uint32(quoteData.OriginChainID), + DestChainId: uint32(quoteData.DestChainID), + OriginSender: common.HexToAddress(quoteData.OriginSender), + DestRecipient: common.HexToAddress(quoteData.DestRecipient), + OriginToken: common.HexToAddress(quoteData.OriginTokenAddr), + DestToken: common.HexToAddress(quoteData.DestTokenAddr), + OriginAmount: originAmount, + DestAmount: destAmount, + OriginFeeAmount: originFeeAmount, + Deadline: deadline, + Nonce: nonce, + ExclusivityRelayer: exclusivityRelayer, + ExclusivityEndTime: exclusivityEndTime, + ZapNative: zapNative, + ZapData: []byte(quoteData.ZapData), + }, + } + + return quoteRequest, nil +} + // GetPrice gets the price of a token. func (m *Manager) GetPrice(parentCtx context.Context, tokenName string) (_ float64, err error) { ctx, span := m.metricsHandler.Tracer().Start(parentCtx, "GetPrice") @@ -585,8 +653,10 @@ type QuoteInput struct { DestBalance *big.Int OriginAmountExact *big.Int DestRFQAddr string + QuoteRequest *reldb.QuoteRequest } +//nolint:gosec func (m *Manager) generateQuote(ctx context.Context, input QuoteInput) (quote *model.PutRelayerQuoteRequest, err error) { // Calculate the quote amount for this route originAmount, err := m.getOriginAmount(ctx, input) @@ -604,7 +674,7 @@ func (m *Manager) generateQuote(ctx context.Context, input QuoteInput) (quote *m logger.Error("Error getting dest token ID", "error", err) return nil, fmt.Errorf("error getting dest token ID: %w", err) } - fee, err := m.feePricer.GetTotalFee(ctx, uint32(input.OriginChainID), uint32(input.DestChainID), destToken, true) + fee, err := m.feePricer.GetTotalFee(ctx, uint32(input.OriginChainID), uint32(input.DestChainID), destToken, true, input.QuoteRequest) if err != nil { logger.Error("Error getting total fee", "error", err) return nil, fmt.Errorf("error getting total fee: %w", err) diff --git a/services/rfq/relayer/quoter/quoter_test.go b/services/rfq/relayer/quoter/quoter_test.go index 7f30fabb65..c4826448eb 100644 --- a/services/rfq/relayer/quoter/quoter_test.go +++ b/services/rfq/relayer/quoter/quoter_test.go @@ -1,6 +1,7 @@ package quoter_test import ( + "encoding/json" "fmt" "math/big" @@ -8,8 +9,10 @@ import ( "github.com/stretchr/testify/mock" "github.com/synapsecns/sanguine/core/metrics" "github.com/synapsecns/sanguine/core/testsuite" + clientMocks "github.com/synapsecns/sanguine/ethergo/client/mocks" fetcherMocks "github.com/synapsecns/sanguine/ethergo/submitter/mocks" "github.com/synapsecns/sanguine/services/rfq/api/model" + "github.com/synapsecns/sanguine/services/rfq/api/rest" "github.com/synapsecns/sanguine/services/rfq/contracts/fastbridgev2" inventoryMocks "github.com/synapsecns/sanguine/services/rfq/relayer/inventory/mocks" "github.com/synapsecns/sanguine/services/rfq/relayer/pricer" @@ -444,6 +447,92 @@ func (s *QuoterSuite) TestGetOriginAmountActiveQuotes() { s.Equal(expectedAmount, quoteAmount) } +func (s *QuoterSuite) TestGenerateActiveRFQ() { + origin := int(s.origin) + dest := int(s.destination) + originAddr := common.HexToAddress("0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48") + destAddr := common.HexToAddress("0x0b2c639c533813f4aa9d7837caf62653d097ff85") + balance := big.NewInt(1_000_000_000_000) + balances := map[int]map[common.Address]*big.Int{ + origin: { + originAddr: balance, + }, + dest: { + destAddr: balance, + }, + } + + currentHeader := big.NewInt(100_000_000_000) // 100 gwei + clientFetcher := new(fetcherMocks.ClientFetcher) + clientMock := new(clientMocks.EVM) + clientMock.On(testsuite.GetFunctionName(clientMock.SuggestGasPrice), mock.Anything).Return(currentHeader, nil) + clientFetcher.On(testsuite.GetFunctionName(clientMock.EstimateGas), mock.Anything, mock.Anything).Return(100_000, nil) + clientFetcher.On(testsuite.GetFunctionName(clientFetcher.GetClient), mock.Anything, mock.Anything).Return(clientMock, nil) + priceFetcher := new(priceMocks.CoingeckoPriceFetcher) + priceFetcher.On(testsuite.GetFunctionName(priceFetcher.GetPrice), mock.Anything, mock.Anything).Return(0., fmt.Errorf("not using mocked price")) + feePricer := pricer.NewFeePricer(s.config, clientFetcher, priceFetcher, metrics.NewNullHandler(), common.HexToAddress("0x123")) + inventoryManager := new(inventoryMocks.Manager) + inventoryManager.On(testsuite.GetFunctionName(inventoryManager.HasSufficientGas), mock.Anything, mock.Anything, mock.Anything).Return(true, nil) + inventoryManager.On(testsuite.GetFunctionName(inventoryManager.GetCommittableBalances), mock.Anything, mock.Anything, mock.Anything).Return(balances, nil) + mgr, err := quoter.NewQuoterManager(s.config, metrics.NewNullHandler(), inventoryManager, nil, feePricer, nil) + s.NoError(err) + + var ok bool + s.manager, ok = mgr.(*quoter.Manager) + s.True(ok) + + req := model.PutRFQRequest{ + UserAddress: "0x123", + IntegratorID: "123", + QuoteTypes: []string{"active"}, + Data: model.QuoteData{ + OriginChainID: origin, + DestChainID: dest, + OriginAmountExact: "100000", + OriginTokenAddr: originAddr.String(), + DestTokenAddr: destAddr.String(), + }, + } + reqBytes, err := json.Marshal(req) + s.NoError(err) + msg := model.ActiveRFQMessage{ + Op: rest.RequestQuoteOp, + Content: json.RawMessage(reqBytes), + } + + respMsg, err := s.manager.GenerateActiveRFQ(s.GetTestContext(), &msg) + s.NoError(err) + var resp model.WsRFQResponse + err = json.Unmarshal(respMsg.Content, &resp) + s.NoError(err) + s.Equal("0", resp.DestAmount) + + req = model.PutRFQRequest{ + UserAddress: "0x123", + IntegratorID: "123", + QuoteTypes: []string{"active"}, + Data: model.QuoteData{ + OriginChainID: origin, + DestChainID: dest, + OriginAmountExact: "500000000000", + OriginTokenAddr: originAddr.String(), + DestTokenAddr: destAddr.String(), + }, + } + reqBytes, err = json.Marshal(req) + s.NoError(err) + msg = model.ActiveRFQMessage{ + Op: rest.RequestQuoteOp, + Content: json.RawMessage(reqBytes), + } + + respMsg, err = s.manager.GenerateActiveRFQ(s.GetTestContext(), &msg) + s.NoError(err) + err = json.Unmarshal(respMsg.Content, &resp) + s.NoError(err) + s.Equal("499899950000", resp.DestAmount) +} + func (s *QuoterSuite) TestGetOriginAmount() { origin := int(s.origin) dest := int(s.destination) @@ -573,7 +662,7 @@ func (s *QuoterSuite) setGasSufficiency(sufficient bool) { clientFetcher := new(fetcherMocks.ClientFetcher) priceFetcher := new(priceMocks.CoingeckoPriceFetcher) priceFetcher.On(testsuite.GetFunctionName(priceFetcher.GetPrice), mock.Anything, mock.Anything).Return(0., fmt.Errorf("not using mocked price")) - feePricer := pricer.NewFeePricer(s.config, clientFetcher, priceFetcher, metrics.NewNullHandler()) + feePricer := pricer.NewFeePricer(s.config, clientFetcher, priceFetcher, metrics.NewNullHandler(), common.HexToAddress("0x123")) inventoryManager := new(inventoryMocks.Manager) inventoryManager.On(testsuite.GetFunctionName(inventoryManager.HasSufficientGas), mock.Anything, mock.Anything, mock.Anything).Return(sufficient, nil) mgr, err := quoter.NewQuoterManager(s.config, metrics.NewNullHandler(), inventoryManager, nil, feePricer, nil) diff --git a/services/rfq/relayer/quoter/suite_test.go b/services/rfq/relayer/quoter/suite_test.go index b9f3371a83..81f14ea420 100644 --- a/services/rfq/relayer/quoter/suite_test.go +++ b/services/rfq/relayer/quoter/suite_test.go @@ -115,7 +115,7 @@ func (s *QuoterSuite) SetupTest() { client.On(testsuite.GetFunctionName(client.SuggestGasPrice), mock.Anything).Return(gasPrice, nil) clientFetcher.On(testsuite.GetFunctionName(clientFetcher.GetClient), mock.Anything, mock.Anything).Twice().Return(client, nil) priceFetcher.On(testsuite.GetFunctionName(priceFetcher.GetPrice), mock.Anything, mock.Anything).Return(0., fmt.Errorf("not using mocked price")) - feePricer := pricer.NewFeePricer(s.config, clientFetcher, priceFetcher, metrics.NewNullHandler()) + feePricer := pricer.NewFeePricer(s.config, clientFetcher, priceFetcher, metrics.NewNullHandler(), common.HexToAddress("0x123")) go func() { feePricer.Start(s.GetTestContext()) }() inventoryManager := new(inventoryMocks.Manager) diff --git a/services/rfq/relayer/service/relayer.go b/services/rfq/relayer/service/relayer.go index bda410b6aa..3d4334e57d 100644 --- a/services/rfq/relayer/service/relayer.go +++ b/services/rfq/relayer/service/relayer.go @@ -128,7 +128,7 @@ func NewRelayer(ctx context.Context, metricHandler metrics.Handler, cfg relconfi } priceFetcher := pricer.NewCoingeckoPriceFetcher(cfg.GetHTTPTimeout()) - fp := pricer.NewFeePricer(cfg, omniClient, priceFetcher, metricHandler) + fp := pricer.NewFeePricer(cfg, omniClient, priceFetcher, metricHandler, sg.Address()) apiClient, err := rfqAPIClient.NewAuthenticatedClient(metricHandler, cfg.GetRFQAPIURL(), sg) if err != nil { diff --git a/services/rfq/testutil/contracttype.go b/services/rfq/testutil/contracttype.go index c3e6d5f5da..3dc397c45d 100644 --- a/services/rfq/testutil/contracttype.go +++ b/services/rfq/testutil/contracttype.go @@ -4,6 +4,7 @@ import ( "github.com/ethereum/go-ethereum/common/compiler" "github.com/synapsecns/sanguine/ethergo/backends/base" "github.com/synapsecns/sanguine/ethergo/contracts" + "github.com/synapsecns/sanguine/services/rfq/contracts/bridgetransactionv2" "github.com/synapsecns/sanguine/services/rfq/contracts/fastbridge" "github.com/synapsecns/sanguine/services/rfq/contracts/fastbridgev2" "github.com/synapsecns/sanguine/services/rfq/contracts/testcontracts/dai" @@ -61,6 +62,8 @@ const ( FastBridgeMockType // FastBridgeMock // RecipientMockType is a mock contract for testing fast bridge interactions. RecipientMockType // RecipientMock + // BridgeTransactionV2Type is a bridge transaction contract for testing fast bridge interactions. + BridgeTransactionV2Type // BridgeTransactionV2 // WETH9Type is the weth 9 contract. WETH9Type // WETH9 // USDTType is the tether type. @@ -105,6 +108,8 @@ func (c contractTypeImpl) ContractInfo() *compiler.Contract { return fastbridgemockv2.Contracts["solidity/FastBridgeMock.sol:FastBridgeMock"] case RecipientMockType: return recipientmock.Contracts["solidity/RecipientMock.sol:RecipientMock"] + case BridgeTransactionV2Type: + return bridgetransactionv2.Contracts["solidity/BridgeTransactionV2Harness.sol:BridgeTransactionV2Harness"] case WETH9Type: return weth9.Contracts["/solidity/WETH9.sol:WETH9"] case USDTType: diff --git a/services/rfq/testutil/contracttypeimpl_string.go b/services/rfq/testutil/contracttypeimpl_string.go index a693f563d9..6f461d5b45 100644 --- a/services/rfq/testutil/contracttypeimpl_string.go +++ b/services/rfq/testutil/contracttypeimpl_string.go @@ -9,20 +9,19 @@ func _() { // Re-run the stringer command to generate them again. var x [1]struct{} _ = x[FastBridgeType-1] - _ = x[FastBridgeV2Type-2] - _ = x[MockERC20Type-3] - _ = x[FastBridgeMockType-4] - _ = x[RecipientMockType-5] + _ = x[MockERC20Type-2] + _ = x[FastBridgeMockType-3] + _ = x[RecipientMockType-4] + _ = x[BridgeTransactionV2Type-5] _ = x[WETH9Type-6] _ = x[USDTType-7] _ = x[USDCType-8] _ = x[DAIType-9] } -const _contractTypeImpl_name = "FastBridgeV1FastBridgeV2MockERC20FastBridgeMockRecipientMockWETH9USDTUSDCDAI" - -var _contractTypeImpl_index = [...]uint8{0, 12, 24, 33, 47, 60, 65, 69, 73, 76} +const _contractTypeImpl_name = "FastBridgeMockERC20FastBridgeMockRecipientMockBridgeTransactionV2WETH9USDTUSDCDAI" +var _contractTypeImpl_index = [...]uint8{0, 10, 19, 33, 46, 65, 70, 74, 78, 81} func (i contractTypeImpl) String() string { i -= 1 if i < 0 || i >= contractTypeImpl(len(_contractTypeImpl_index)-1) { diff --git a/services/rfq/testutil/deployers.go b/services/rfq/testutil/deployers.go index 854f341889..9f0041f422 100644 --- a/services/rfq/testutil/deployers.go +++ b/services/rfq/testutil/deployers.go @@ -14,7 +14,7 @@ import ( "github.com/synapsecns/sanguine/ethergo/contracts" "github.com/synapsecns/sanguine/ethergo/deployer" "github.com/synapsecns/sanguine/ethergo/manager" - "github.com/synapsecns/sanguine/services/rfq/contracts/fastbridge" + "github.com/synapsecns/sanguine/services/rfq/contracts/bridgetransactionv2" "github.com/synapsecns/sanguine/services/rfq/contracts/fastbridgev2" "github.com/synapsecns/sanguine/services/rfq/contracts/testcontracts/fastbridgemockv2" "github.com/synapsecns/sanguine/services/rfq/contracts/testcontracts/recipientmock" @@ -29,7 +29,7 @@ type DeployManager struct { func NewDeployManager(t *testing.T) *DeployManager { t.Helper() - parentManager := manager.NewDeployerManager(t, NewFastBridgeDeployer, NewFastBridgeV2Deployer, NewMockERC20Deployer, NewMockFastBridgeDeployer, NewRecipientMockDeployer, NewWETH9Deployer, NewUSDTDeployer, NewUSDCDeployer, NewDAIDeployer) + parentManager := manager.NewDeployerManager(t, NewFastBridgeDeployer, NewMockERC20Deployer, NewMockFastBridgeDeployer, NewRecipientMockDeployer, NewBridgeTransactionV2Deployer, NewWETH9Deployer, NewUSDTDeployer, NewUSDCDeployer, NewDAIDeployer) return &DeployManager{parentManager} } @@ -183,3 +183,24 @@ func (m RecipientMockDeployer) Deploy(ctx context.Context) (contracts.DeployedCo return recipientmock.NewRecipientMockRef(address, backend) }) } + +// BridgeTransactionV2Deployer deploys a bridge transaction contract for testing. +type BridgeTransactionV2Deployer struct { + *deployer.BaseDeployer +} + +// NewBridgeTransactionV2Deployer deploys a mock recipient contract. +func NewBridgeTransactionV2Deployer(registry deployer.GetOnlyContractRegistry, backend backends.SimulatedTestBackend) deployer.ContractDeployer { + return BridgeTransactionV2Deployer{ + deployer.NewSimpleDeployer(registry, backend, BridgeTransactionV2Type), + } +} + +// Deploy deploys the bridge transaction contract. +func (m BridgeTransactionV2Deployer) Deploy(ctx context.Context) (contracts.DeployedContract, error) { + return m.DeploySimpleContract(ctx, func(transactOps *bind.TransactOpts, backend bind.ContractBackend) (common.Address, *types.Transaction, interface{}, error) { + return bridgetransactionv2.DeployBridgeTransactionV2Harness(transactOps, backend) + }, func(address common.Address, backend bind.ContractBackend) (interface{}, error) { + return bridgetransactionv2.NewBridgeTransactionV2Ref(address, backend) + }) +} diff --git a/services/rfq/testutil/typecast.go b/services/rfq/testutil/typecast.go index 541655dbe8..a185ba6756 100644 --- a/services/rfq/testutil/typecast.go +++ b/services/rfq/testutil/typecast.go @@ -6,7 +6,7 @@ import ( "github.com/synapsecns/sanguine/ethergo/backends" "github.com/synapsecns/sanguine/ethergo/contracts" "github.com/synapsecns/sanguine/ethergo/manager" - "github.com/synapsecns/sanguine/services/rfq/contracts/fastbridge" + "github.com/synapsecns/sanguine/services/rfq/contracts/bridgetransactionv2" "github.com/synapsecns/sanguine/services/rfq/contracts/fastbridgev2" "github.com/synapsecns/sanguine/services/rfq/contracts/testcontracts/dai" "github.com/synapsecns/sanguine/services/rfq/contracts/testcontracts/fastbridgemockv2" @@ -52,6 +52,13 @@ func (d *DeployManager) GetRecipientMock(ctx context.Context, backend backends.S return manager.GetContract[*recipientmock.RecipientMockRef](ctx, d.T(), d, backend, RecipientMockType) } +// GetBridgeTransactionV2 gets the bridge transaction v2. +func (d *DeployManager) GetBridgeTransactionV2(ctx context.Context, backend backends.SimulatedTestBackend) (contract contracts.DeployedContract, handle *bridgetransactionv2.BridgeTransactionV2Ref) { + d.T().Helper() + + return manager.GetContract[*bridgetransactionv2.BridgeTransactionV2Ref](ctx, d.T(), d, backend, BridgeTransactionV2Type) +} + // GetWETH9 gets the weth9 contract. func (d *DeployManager) GetWETH9(ctx context.Context, backend backends.SimulatedTestBackend) (contract contracts.DeployedContract, handle *weth9.Weth9Ref) { d.T().Helper() From e2dfc5a15ec244e7a9f3eaae0040ecd282754c03 Mon Sep 17 00:00:00 2001 From: parodime Date: Fri, 6 Dec 2024 16:01:11 -0500 Subject: [PATCH 58/85] [goreleaser] From 731a83c57636081e6ec4c18effa9061fe3fe1778 Mon Sep 17 00:00:00 2001 From: parodime Date: Sat, 7 Dec 2024 05:32:21 -0500 Subject: [PATCH 59/85] pr 3299 comments. modify Zap checks --- services/rfq/relayer/pricer/fee_pricer.go | 6 +++--- services/rfq/relayer/quoter/quoter.go | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/services/rfq/relayer/pricer/fee_pricer.go b/services/rfq/relayer/pricer/fee_pricer.go index 625ba240a2..20df34be12 100644 --- a/services/rfq/relayer/pricer/fee_pricer.go +++ b/services/rfq/relayer/pricer/fee_pricer.go @@ -142,7 +142,7 @@ func (f *feePricer) GetDestinationFee(parentCtx context.Context, _, destination // Calculate the static L2 fee if it won't be incorporated by directly estimating the relay() call // in addZapFees(). - if quoteRequest == nil || quoteRequest.Transaction.ZapNative == nil || quoteRequest.Transaction.ZapData == nil { + if len(quoteRequest.Transaction.ZapData) == 0 { gasEstimate, err := f.config.GetDestGasEstimate(int(destination)) if err != nil { return nil, fmt.Errorf("could not get dest gas estimate: %w", err) @@ -184,7 +184,7 @@ func (f *feePricer) GetDestinationFee(parentCtx context.Context, _, destination func (f *feePricer) addZapFees(ctx context.Context, destination uint32, denomToken string, quoteRequest *reldb.QuoteRequest, fee *big.Int) (*big.Int, error) { span := trace.SpanFromContext(ctx) - if quoteRequest.Transaction.ZapData != nil { + if len(quoteRequest.Transaction.ZapData) == 0 { gasEstimate, err := f.getZapGasEstimate(ctx, destination, quoteRequest) if err != nil { return nil, err @@ -217,7 +217,7 @@ func (f *feePricer) addZapFees(ctx context.Context, destination uint32, denomTok // cache so that we don't have to parse the ABI every time. var fastBridgeV2ABI *abi.ABI -const methodName = "relay0" +const methodName = "relayV2" func (f *feePricer) getZapGasEstimate(ctx context.Context, destination uint32, quoteRequest *reldb.QuoteRequest) (gasEstimate uint64, err error) { client, err := f.clientFetcher.GetClient(ctx, big.NewInt(int64(destination))) diff --git a/services/rfq/relayer/quoter/quoter.go b/services/rfq/relayer/quoter/quoter.go index c552aad541..a5c1d25c14 100644 --- a/services/rfq/relayer/quoter/quoter.go +++ b/services/rfq/relayer/quoter/quoter.go @@ -380,7 +380,7 @@ func (m *Manager) generateActiveRFQ(ctx context.Context, msg *model.ActiveRFQMes DestBalance: inv[rfqRequest.Data.DestChainID][common.HexToAddress(rfqRequest.Data.DestTokenAddr)], OriginAmountExact: originAmountExact, } - if rfqRequest.Data.ZapNative != "" || rfqRequest.Data.ZapData != "" { + if (rfqRequest.Data.ZapNative != "0" && rfqRequest.Data.ZapNative != "") || rfqRequest.Data.ZapData != "" { quoteRequest, err := quoteDataToQuoteRequestV2(&rfqRequest.Data) if err != nil { return nil, fmt.Errorf("error converting quote data to quote request: %w", err) From a7bb3a3b8eaf3f46feb17d8b6661c6df08a1c850 Mon Sep 17 00:00:00 2001 From: parodime Date: Sat, 7 Dec 2024 05:32:40 -0500 Subject: [PATCH 60/85] [goreleaser] From ac79f4d7dd16f5e0a1443072f9537913a00a2c8a Mon Sep 17 00:00:00 2001 From: parodime Date: Mon, 9 Dec 2024 10:30:04 -0500 Subject: [PATCH 61/85] [goreleaser] From 6dac46b57f05e1f6f6c96b39b8861597db051f54 Mon Sep 17 00:00:00 2001 From: parodime Date: Mon, 9 Dec 2024 13:41:07 -0500 Subject: [PATCH 62/85] zap data nil check & test fixes --- services/rfq/relayer/pricer/fee_pricer.go | 6 +++--- .../rfq/relayer/pricer/fee_pricer_test.go | 21 +++++++++++++++---- 2 files changed, 20 insertions(+), 7 deletions(-) diff --git a/services/rfq/relayer/pricer/fee_pricer.go b/services/rfq/relayer/pricer/fee_pricer.go index 20df34be12..d604300433 100644 --- a/services/rfq/relayer/pricer/fee_pricer.go +++ b/services/rfq/relayer/pricer/fee_pricer.go @@ -142,7 +142,7 @@ func (f *feePricer) GetDestinationFee(parentCtx context.Context, _, destination // Calculate the static L2 fee if it won't be incorporated by directly estimating the relay() call // in addZapFees(). - if len(quoteRequest.Transaction.ZapData) == 0 { + if quoteRequest == nil || len(quoteRequest.Transaction.ZapData) == 0 { gasEstimate, err := f.config.GetDestGasEstimate(int(destination)) if err != nil { return nil, fmt.Errorf("could not get dest gas estimate: %w", err) @@ -184,7 +184,7 @@ func (f *feePricer) GetDestinationFee(parentCtx context.Context, _, destination func (f *feePricer) addZapFees(ctx context.Context, destination uint32, denomToken string, quoteRequest *reldb.QuoteRequest, fee *big.Int) (*big.Int, error) { span := trace.SpanFromContext(ctx) - if len(quoteRequest.Transaction.ZapData) == 0 { + if quoteRequest != nil && len(quoteRequest.Transaction.ZapData) != 0 { gasEstimate, err := f.getZapGasEstimate(ctx, destination, quoteRequest) if err != nil { return nil, err @@ -197,7 +197,7 @@ func (f *feePricer) addZapFees(ctx context.Context, destination uint32, denomTok span.SetAttributes(attribute.String("call_fee", callFee.String())) } - if quoteRequest.Transaction.ZapNative != nil && quoteRequest.Transaction.ZapNative.Sign() > 0 { + if quoteRequest != nil && quoteRequest.Transaction.ZapNative != nil && quoteRequest.Transaction.ZapNative.Cmp(big.NewInt(0)) > 0 && quoteRequest.Transaction.ZapNative.Sign() > 0 { callValueFloat := new(big.Float).SetInt(quoteRequest.Transaction.ZapNative) valueDenom, err := f.getDenomFee(ctx, destination, destination, denomToken, callValueFloat) if err != nil { diff --git a/services/rfq/relayer/pricer/fee_pricer_test.go b/services/rfq/relayer/pricer/fee_pricer_test.go index 25cf9e4d8b..c3fc089ea3 100644 --- a/services/rfq/relayer/pricer/fee_pricer_test.go +++ b/services/rfq/relayer/pricer/fee_pricer_test.go @@ -231,7 +231,15 @@ func (s *PricerSuite) TestGetTotalFee() { quoteRequest := &reldb.QuoteRequest{ RawRequest: []byte{}, Transaction: fastbridgev2.IFastBridgeV2BridgeTransactionV2{ - ZapNative: big.NewInt(1 * 1e18), + ZapNative: big.NewInt(1 * 1e18), + OriginSender: common.HexToAddress("0xAA000000000000000000000000000000000000001"), + DestRecipient: common.HexToAddress("0xAA00000000000000000000000000000000000001"), + OriginAmount: big.NewInt(1 * 1e18), + DestAmount: big.NewInt(1 * 1e18), + OriginFeeAmount: big.NewInt(1 * 1e15), + Deadline: big.NewInt(1733769166), + Nonce: big.NewInt(123456), + ExclusivityEndTime: big.NewInt(0), }, } fee, err = feePricer.GetTotalFee(s.GetTestContext(), s.origin, s.destination, "USDC", true, quoteRequest) @@ -246,9 +254,14 @@ func (s *PricerSuite) TestGetTotalFee() { quoteRequest = &reldb.QuoteRequest{ RawRequest: []byte{}, Transaction: fastbridgev2.IFastBridgeV2BridgeTransactionV2{ - ZapNative: big.NewInt(1 * 1e18), - ZapData: []byte{1}, - DestAmount: big.NewInt(1 * 1e18), + ZapNative: big.NewInt(1 * 1e18), + ZapData: []byte{1}, + OriginAmount: big.NewInt(1 * 1e18), + DestAmount: big.NewInt(1 * 1e18), + OriginFeeAmount: big.NewInt(1 * 1e15), + Deadline: big.NewInt(1733769166), + Nonce: big.NewInt(123456), + ExclusivityEndTime: big.NewInt(0), }, } clientDestination.On(testsuite.GetFunctionName(clientDestination.EstimateGas), mock.Anything, mock.Anything).Once().Return(uint64(1_000_000), nil) From 9ff5bf3a0008e6a6fcc893f9dbbab1da85a71e95 Mon Sep 17 00:00:00 2001 From: parodime Date: Mon, 9 Dec 2024 13:42:08 -0500 Subject: [PATCH 63/85] [goreleaser] From 231bbea1042df30d9eabbe25b3e83f3e0919297e Mon Sep 17 00:00:00 2001 From: parodime Date: Thu, 12 Dec 2024 09:33:02 -0500 Subject: [PATCH 64/85] [goreleaser] add debugging --- services/rfq/relayer/pricer/fee_pricer.go | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/services/rfq/relayer/pricer/fee_pricer.go b/services/rfq/relayer/pricer/fee_pricer.go index d604300433..db02d80744 100644 --- a/services/rfq/relayer/pricer/fee_pricer.go +++ b/services/rfq/relayer/pricer/fee_pricer.go @@ -220,6 +220,8 @@ var fastBridgeV2ABI *abi.ABI const methodName = "relayV2" func (f *feePricer) getZapGasEstimate(ctx context.Context, destination uint32, quoteRequest *reldb.QuoteRequest) (gasEstimate uint64, err error) { + span := trace.SpanFromContext(ctx) + client, err := f.clientFetcher.GetClient(ctx, big.NewInt(int64(destination))) if err != nil { return 0, fmt.Errorf("could not get client: %w", err) @@ -254,6 +256,14 @@ func (f *feePricer) getZapGasEstimate(ctx context.Context, destination uint32, q Value: quoteRequest.Transaction.ZapNative, Data: encodedData, } + + span.SetAttributes( + attribute.String("callMsg.From", callMsg.From.Hex()), + attribute.String("callMsg.To", callMsg.To.Hex()), + attribute.String("callMsg.Value", callMsg.Value.String()), + attribute.String("callMsg.Data", string(callMsg.Data)), + ) + gasEstimate, err = client.EstimateGas(ctx, callMsg) if err != nil { return 0, fmt.Errorf("could not estimate gas: %w", err) From 1a12f35cdec709bd2b472c1809792bc0f7b8aec4 Mon Sep 17 00:00:00 2001 From: parodime Date: Thu, 12 Dec 2024 09:55:46 -0500 Subject: [PATCH 65/85] [goreleaser] span switch --- services/rfq/relayer/pricer/fee_pricer.go | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/services/rfq/relayer/pricer/fee_pricer.go b/services/rfq/relayer/pricer/fee_pricer.go index db02d80744..c3f8e70290 100644 --- a/services/rfq/relayer/pricer/fee_pricer.go +++ b/services/rfq/relayer/pricer/fee_pricer.go @@ -220,8 +220,6 @@ var fastBridgeV2ABI *abi.ABI const methodName = "relayV2" func (f *feePricer) getZapGasEstimate(ctx context.Context, destination uint32, quoteRequest *reldb.QuoteRequest) (gasEstimate uint64, err error) { - span := trace.SpanFromContext(ctx) - client, err := f.clientFetcher.GetClient(ctx, big.NewInt(int64(destination))) if err != nil { return 0, fmt.Errorf("could not get client: %w", err) @@ -257,12 +255,15 @@ func (f *feePricer) getZapGasEstimate(ctx context.Context, destination uint32, q Data: encodedData, } - span.SetAttributes( + ctx, span := f.handler.Tracer().Start(ctx, "getZapGasEstimate", trace.WithAttributes( attribute.String("callMsg.From", callMsg.From.Hex()), attribute.String("callMsg.To", callMsg.To.Hex()), attribute.String("callMsg.Value", callMsg.Value.String()), attribute.String("callMsg.Data", string(callMsg.Data)), - ) + )) + defer func() { + metrics.EndSpanWithErr(span, err) + }() gasEstimate, err = client.EstimateGas(ctx, callMsg) if err != nil { From bf8b443ba9094ffce4cad82c8609c565122f66d0 Mon Sep 17 00:00:00 2001 From: parodime Date: Thu, 12 Dec 2024 10:04:32 -0500 Subject: [PATCH 66/85] [goreleaser] switch to console prints --- services/rfq/relayer/pricer/fee_pricer.go | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/services/rfq/relayer/pricer/fee_pricer.go b/services/rfq/relayer/pricer/fee_pricer.go index c3f8e70290..4b7967ed04 100644 --- a/services/rfq/relayer/pricer/fee_pricer.go +++ b/services/rfq/relayer/pricer/fee_pricer.go @@ -220,6 +220,8 @@ var fastBridgeV2ABI *abi.ABI const methodName = "relayV2" func (f *feePricer) getZapGasEstimate(ctx context.Context, destination uint32, quoteRequest *reldb.QuoteRequest) (gasEstimate uint64, err error) { + fmt.Println("Starting getZapGasEstimate with destination:", destination, "and quoteRequest:", quoteRequest) + client, err := f.clientFetcher.GetClient(ctx, big.NewInt(int64(destination))) if err != nil { return 0, fmt.Errorf("could not get client: %w", err) @@ -255,15 +257,8 @@ func (f *feePricer) getZapGasEstimate(ctx context.Context, destination uint32, q Data: encodedData, } - ctx, span := f.handler.Tracer().Start(ctx, "getZapGasEstimate", trace.WithAttributes( - attribute.String("callMsg.From", callMsg.From.Hex()), - attribute.String("callMsg.To", callMsg.To.Hex()), - attribute.String("callMsg.Value", callMsg.Value.String()), - attribute.String("callMsg.Data", string(callMsg.Data)), - )) - defer func() { - metrics.EndSpanWithErr(span, err) - }() + fmt.Printf("Starting getZapGasEstimate with callMsg.From: %s, callMsg.To: %s, callMsg.Value: %s, callMsg.Data: %s\n", + callMsg.From.Hex(), callMsg.To.Hex(), callMsg.Value.String(), string(callMsg.Data)) gasEstimate, err = client.EstimateGas(ctx, callMsg) if err != nil { From f1135047c6a2b8780cb36c3342e74982114a7b95 Mon Sep 17 00:00:00 2001 From: parodime Date: Thu, 12 Dec 2024 10:14:52 -0500 Subject: [PATCH 67/85] [goreleaser] more debugggggg --- services/rfq/relayer/pricer/fee_pricer.go | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/services/rfq/relayer/pricer/fee_pricer.go b/services/rfq/relayer/pricer/fee_pricer.go index 4b7967ed04..e682e506de 100644 --- a/services/rfq/relayer/pricer/fee_pricer.go +++ b/services/rfq/relayer/pricer/fee_pricer.go @@ -11,6 +11,7 @@ import ( "github.com/ethereum/go-ethereum" "github.com/ethereum/go-ethereum/accounts/abi" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/hexutil" "github.com/jellydator/ttlcache/v3" "github.com/synapsecns/sanguine/core/metrics" "github.com/synapsecns/sanguine/ethergo/submitter" @@ -257,8 +258,11 @@ func (f *feePricer) getZapGasEstimate(ctx context.Context, destination uint32, q Data: encodedData, } - fmt.Printf("Starting getZapGasEstimate with callMsg.From: %s, callMsg.To: %s, callMsg.Value: %s, callMsg.Data: %s\n", - callMsg.From.Hex(), callMsg.To.Hex(), callMsg.Value.String(), string(callMsg.Data)) + fmt.Printf("\nStarting getZapGasEstimate with callMsg.From: %s, callMsg.To: %s, callMsg.Value: %s, callMsg.Data: %x\n", + callMsg.From.Hex(), callMsg.To.Hex(), callMsg.Value.String(), callMsg.Data) + + fmt.Printf("\nStarting getZapGasEstimate with callMsg.From: %s, callMsg.To: %s, callMsg.Value: %s, callMsg.Data: %s\n", + callMsg.From.Hex(), callMsg.To.Hex(), callMsg.Value.String(), hexutil.Encode(callMsg.Data)) gasEstimate, err = client.EstimateGas(ctx, callMsg) if err != nil { From bff23486ef2b8bb4039b7b0484bb2ccb3382035a Mon Sep 17 00:00:00 2001 From: parodime Date: Thu, 12 Dec 2024 10:36:35 -0500 Subject: [PATCH 68/85] [goreleaser] debug --- services/rfq/relayer/quoter/quoter.go | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/services/rfq/relayer/quoter/quoter.go b/services/rfq/relayer/quoter/quoter.go index a5c1d25c14..513a58ceed 100644 --- a/services/rfq/relayer/quoter/quoter.go +++ b/services/rfq/relayer/quoter/quoter.go @@ -340,6 +340,10 @@ func (m *Manager) SubscribeActiveRFQ(ctx context.Context) (err error) { // //nolint:nilnil,cyclop func (m *Manager) generateActiveRFQ(ctx context.Context, msg *model.ActiveRFQMessage) (resp *model.ActiveRFQMessage, err error) { + + //tmpdebug + fmt.Printf("\nActiveRFQMessage RawMessage: %s\n", string(msg.Content)) + ctx, span := m.metricsHandler.Tracer().Start(ctx, "generateActiveRFQ", trace.WithAttributes( attribute.String("op", msg.Op), attribute.String("content", string(msg.Content)), @@ -365,6 +369,8 @@ func (m *Manager) generateActiveRFQ(ctx context.Context, msg *model.ActiveRFQMes } span.SetAttributes(attribute.String("request_id", rfqRequest.RequestID)) + fmt.Printf("RFQ Request Data: %+v\n", rfqRequest.Data) + // TODO: incorporate the user call data into the quote request and set the Transaction here originAmountExact, ok := new(big.Int).SetString(rfqRequest.Data.OriginAmountExact, 10) if !ok { From 442be53fe7320579309b2afa247887de264b10d0 Mon Sep 17 00:00:00 2001 From: Daniel Wasserman Date: Thu, 12 Dec 2024 09:58:23 -0600 Subject: [PATCH 69/85] quote data logging --- services/rfq/api/model/request.go | 6 +++++- services/rfq/api/rest/rfq.go | 2 ++ services/rfq/api/rest/ws.go | 4 ++++ services/rfq/relayer/quoter/quoter.go | 1 + 4 files changed, 12 insertions(+), 1 deletion(-) diff --git a/services/rfq/api/model/request.go b/services/rfq/api/model/request.go index 4ed1305c7c..06e2edb234 100644 --- a/services/rfq/api/model/request.go +++ b/services/rfq/api/model/request.go @@ -1,6 +1,9 @@ package model -import "time" +import ( + "fmt" + "time" +) // PutRelayerQuoteRequest contains the schema for a PUT /quote request. type PutRelayerQuoteRequest struct { @@ -82,6 +85,7 @@ type SubscribeActiveRFQRequest struct { // NewWsRFQRequest creates a new WsRFQRequest. func NewWsRFQRequest(data QuoteData, requestID string) *WsRFQRequest { + fmt.Printf("NewWsRFQRequest with data: %+v\n", data) return &WsRFQRequest{ RequestID: requestID, Data: data, diff --git a/services/rfq/api/rest/rfq.go b/services/rfq/api/rest/rfq.go index 213adcc714..dbd404c283 100644 --- a/services/rfq/api/rest/rfq.go +++ b/services/rfq/api/rest/rfq.go @@ -20,6 +20,7 @@ import ( const collectionTimeout = 1 * time.Minute func (r *QuoterAPIServer) handleActiveRFQ(ctx context.Context, request *model.PutRFQRequest, requestID string) (quote *model.QuoteData) { + fmt.Printf("handleActiveRFQ with request data: %+v\n", request.Data) ctx, span := r.handler.Tracer().Start(ctx, "handleActiveRFQ", trace.WithAttributes( attribute.String("user_address", request.UserAddress), attribute.String("request_id", requestID), @@ -30,6 +31,7 @@ func (r *QuoterAPIServer) handleActiveRFQ(ctx context.Context, request *model.Pu // publish the quote request to all connected clients relayerReq := model.NewWsRFQRequest(request.Data, requestID) + fmt.Printf("parsed websocket request: %+v\n", relayerReq.Data) r.wsClients.Range(func(relayerAddr string, client WsClient) bool { sendCtx, sendSpan := r.handler.Tracer().Start(ctx, "sendQuoteRequest", trace.WithAttributes( attribute.String("relayer_address", relayerAddr), diff --git a/services/rfq/api/rest/ws.go b/services/rfq/api/rest/ws.go index 445ed47876..23b0a062eb 100644 --- a/services/rfq/api/rest/ws.go +++ b/services/rfq/api/rest/ws.go @@ -48,6 +48,7 @@ func newWsClient(relayerAddr string, conn *websocket.Conn, pubsub PubSubManager, } func (c *wsClient) SendQuoteRequest(ctx context.Context, quoteRequest *model.WsRFQRequest) error { + fmt.Printf("wsClient.SendQuoteRequest with data: %+v\n", quoteRequest.Data) select { case c.requestChan <- quoteRequest: // successfully sent, register a response channel @@ -172,6 +173,7 @@ func (c *wsClient) processWs(ctx context.Context, messageChan chan []byte) (err } func (c *wsClient) sendRelayerRequest(ctx context.Context, req *model.WsRFQRequest) (err error) { + fmt.Printf("sendRelayerRequest with data: %+v\n", req.Data) _, span := c.handler.Tracer().Start(ctx, "sendRelayerRequest", trace.WithAttributes( attribute.String("relayer_address", c.relayerAddr), attribute.String("request_id", req.RequestID), @@ -184,10 +186,12 @@ func (c *wsClient) sendRelayerRequest(ctx context.Context, req *model.WsRFQReque if err != nil { return fmt.Errorf("error marshaling quote request: %w", err) } + fmt.Printf("rawData: %+v\n", string(rawData)) msg := model.ActiveRFQMessage{ Op: RequestQuoteOp, Content: json.RawMessage(rawData), } + fmt.Printf("writing raw msg: %+v\n", msg) err = c.conn.WriteJSON(msg) if err != nil { return fmt.Errorf("error sending quote request: %w", err) diff --git a/services/rfq/relayer/quoter/quoter.go b/services/rfq/relayer/quoter/quoter.go index 513a58ceed..2d9a53f455 100644 --- a/services/rfq/relayer/quoter/quoter.go +++ b/services/rfq/relayer/quoter/quoter.go @@ -327,6 +327,7 @@ func (m *Manager) SubscribeActiveRFQ(ctx context.Context) (err error) { if msg == nil { continue } + fmt.Printf("parsed msg from respChan: %+v\n", msg.Content) resp, err := m.generateActiveRFQ(ctx, msg) if err != nil { return fmt.Errorf("error generating active RFQ message: %w", err) From 96055a76d81000aec22662a6dc80809241f922f1 Mon Sep 17 00:00:00 2001 From: Daniel Wasserman Date: Thu, 12 Dec 2024 09:58:24 -0600 Subject: [PATCH 70/85] [goreleaser] From b7c4f2048aae44f6171dbf1370225325cccf2722 Mon Sep 17 00:00:00 2001 From: parodime Date: Thu, 12 Dec 2024 11:12:58 -0500 Subject: [PATCH 71/85] [goreleaser] more debug --- services/rfq/relayer/pricer/fee_pricer.go | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/services/rfq/relayer/pricer/fee_pricer.go b/services/rfq/relayer/pricer/fee_pricer.go index e682e506de..3dfcb9a205 100644 --- a/services/rfq/relayer/pricer/fee_pricer.go +++ b/services/rfq/relayer/pricer/fee_pricer.go @@ -236,7 +236,14 @@ func (f *feePricer) getZapGasEstimate(ctx context.Context, destination uint32, q fastBridgeV2ABI = &parsedABI } + //tmpdebug + fmt.Printf("\nquoteRequest.Transaction: %+v\n", quoteRequest.Transaction) + rawRequest, err := chain.EncodeBridgeTx(quoteRequest.Transaction) + + //tmpdebug + fmt.Printf("\nrawRequest: %+v\n", rawRequest) + if err != nil { return 0, fmt.Errorf("could not encode quote data: %w", err) } From ba5afb9b980c8079f5f33cef55b1553424745eab Mon Sep 17 00:00:00 2001 From: Daniel Wasserman Date: Thu, 12 Dec 2024 10:56:46 -0600 Subject: [PATCH 72/85] Fix: use hexutil.Decode() for str -> byte --- services/rfq/relayer/quoter/quoter.go | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/services/rfq/relayer/quoter/quoter.go b/services/rfq/relayer/quoter/quoter.go index 2d9a53f455..7ae2e1e4f2 100644 --- a/services/rfq/relayer/quoter/quoter.go +++ b/services/rfq/relayer/quoter/quoter.go @@ -455,6 +455,11 @@ func quoteDataToQuoteRequestV2(quoteData *model.QuoteData) (*reldb.QuoteRequest, deadline := new(big.Int).Sub(new(big.Int).Exp(big.NewInt(2), big.NewInt(256), nil), big.NewInt(1)) exclusivityRelayer := common.HexToAddress("") + zapData, err := hexutil.Decode(quoteData.ZapData) + if err != nil { + return nil, fmt.Errorf("error decoding zap data: %w", err) + } + quoteRequest := &reldb.QuoteRequest{ Transaction: fastbridgev2.IFastBridgeV2BridgeTransactionV2{ OriginChainId: uint32(quoteData.OriginChainID), @@ -471,7 +476,7 @@ func quoteDataToQuoteRequestV2(quoteData *model.QuoteData) (*reldb.QuoteRequest, ExclusivityRelayer: exclusivityRelayer, ExclusivityEndTime: exclusivityEndTime, ZapNative: zapNative, - ZapData: []byte(quoteData.ZapData), + ZapData: zapData, }, } From 3ba6ddadb8ee9bf38b172877e5127288f068beed Mon Sep 17 00:00:00 2001 From: Daniel Wasserman Date: Thu, 12 Dec 2024 10:56:47 -0600 Subject: [PATCH 73/85] [goreleaser] From e160c450be443b650848a40a748b82261acd894b Mon Sep 17 00:00:00 2001 From: Daniel Wasserman Date: Thu, 12 Dec 2024 12:06:38 -0600 Subject: [PATCH 74/85] More logs --- services/rfq/api/client/client.go | 2 ++ services/rfq/api/rest/rfq.go | 13 +++++++++++++ services/rfq/relayer/quoter/quoter.go | 6 +++--- 3 files changed, 18 insertions(+), 3 deletions(-) diff --git a/services/rfq/api/client/client.go b/services/rfq/api/client/client.go index 1bcba494b5..c688d37be4 100644 --- a/services/rfq/api/client/client.go +++ b/services/rfq/api/client/client.go @@ -275,6 +275,7 @@ func (c *clientImpl) processWebsocket(ctx context.Context, conn *websocket.Conn, case <-ctx.Done(): return nil case msg, ok := <-reqChan: + fmt.Printf("recved message from reqChan: %+v\n", msg) if !ok { return fmt.Errorf("error reading from reqChan: %w", ctx.Err()) } @@ -283,6 +284,7 @@ func (c *clientImpl) processWebsocket(ctx context.Context, conn *websocket.Conn, return fmt.Errorf("error sending message to websocket: %w", err) } case msg, ok := <-readChan: + fmt.Printf("recved message from readChan: %+v\n", msg) if !ok { return nil } diff --git a/services/rfq/api/rest/rfq.go b/services/rfq/api/rest/rfq.go index dbd404c283..eef0a71522 100644 --- a/services/rfq/api/rest/rfq.go +++ b/services/rfq/api/rest/rfq.go @@ -33,6 +33,7 @@ func (r *QuoterAPIServer) handleActiveRFQ(ctx context.Context, request *model.Pu relayerReq := model.NewWsRFQRequest(request.Data, requestID) fmt.Printf("parsed websocket request: %+v\n", relayerReq.Data) r.wsClients.Range(func(relayerAddr string, client WsClient) bool { + fmt.Printf("sending quote request to client with address %v: %v\n", relayerAddr, client) sendCtx, sendSpan := r.handler.Tracer().Start(ctx, "sendQuoteRequest", trace.WithAttributes( attribute.String("relayer_address", relayerAddr), attribute.String("request_id", requestID), @@ -40,8 +41,10 @@ func (r *QuoterAPIServer) handleActiveRFQ(ctx context.Context, request *model.Pu defer metrics.EndSpan(sendSpan) subscribed := r.pubSubManager.IsSubscribed(relayerAddr, request.Data.OriginChainID, request.Data.DestChainID) + fmt.Printf("relayer %v subscribed: %v\n", relayerAddr, subscribed) span.SetAttributes(attribute.Bool("subscribed", subscribed)) if subscribed { + fmt.Printf("sending request to relayer %v: %+v\n", relayerAddr, relayerReq) err := client.SendQuoteRequest(sendCtx, relayerReq) if err != nil { logger.Errorf("Error sending quote request to %s: %v", relayerAddr, err) @@ -57,10 +60,12 @@ func (r *QuoterAPIServer) handleActiveRFQ(ctx context.Context, request *model.Pu // collect the responses and determine the best quote responses := r.collectRelayerResponses(ctx, request, requestID) for r, resp := range responses { + fmt.Printf("considering response: %+v\n", resp) relayerAddr := r quote = getBestQuote(quote, getRelayerQuoteData(request, resp)) quote.RelayerAddress = &relayerAddr } + fmt.Printf("best quote: %+v\n", quote) err = r.recordActiveQuote(ctx, quote, requestID) if err != nil { logger.Errorf("Error recording active quote: %v", err) @@ -70,6 +75,7 @@ func (r *QuoterAPIServer) handleActiveRFQ(ctx context.Context, request *model.Pu } func (r *QuoterAPIServer) collectRelayerResponses(ctx context.Context, request *model.PutRFQRequest, requestID string) (responses map[string]*model.WsRFQResponse) { + fmt.Printf("collectRelayerResponses with request data: %+v\n", request.Data) ctx, span := r.handler.Tracer().Start(ctx, "collectRelayerResponses", trace.WithAttributes( attribute.String("user_address", request.UserAddress), attribute.String("request_id", requestID), @@ -87,6 +93,7 @@ func (r *QuoterAPIServer) collectRelayerResponses(ctx context.Context, request * respMux := sync.Mutex{} responses = map[string]*model.WsRFQResponse{} r.wsClients.Range(func(relayerAddr string, client WsClient) bool { + fmt.Printf("processing ws client with addr: %v: client: %v\n", relayerAddr, client) wg.Add(1) go func(client WsClient) { var respStatus db.ActiveQuoteResponseStatus @@ -102,6 +109,7 @@ func (r *QuoterAPIServer) collectRelayerResponses(ctx context.Context, request * defer wg.Done() resp, err := client.ReceiveQuoteResponse(collectionCtx, requestID) + fmt.Printf("recved quote resp: %+v\n", resp) if err != nil { logger.Errorf("Error receiving quote response: %v", err) return @@ -121,6 +129,7 @@ func (r *QuoterAPIServer) collectRelayerResponses(ctx context.Context, request * } // record the response + fmt.Printf("recording resp: %+v\n", resp) err = r.db.InsertActiveQuoteResponse(collectionCtx, resp, relayerAddr, respStatus) if err != nil { logger.Errorf("Error inserting active quote response: %v", err) @@ -132,6 +141,7 @@ func (r *QuoterAPIServer) collectRelayerResponses(ctx context.Context, request * // wait for all responses to be received, or expiration select { case <-expireCtx.Done(): + fmt.Println("request expired") // request expired before all responses were received case <-func() chan struct{} { ch := make(chan struct{}) @@ -144,6 +154,9 @@ func (r *QuoterAPIServer) collectRelayerResponses(ctx context.Context, request * // all responses received } + fmt.Printf("responses received: %+v\n", responses) + fmt.Printf("num responses: %v\n", len(responses)) + return responses } diff --git a/services/rfq/relayer/quoter/quoter.go b/services/rfq/relayer/quoter/quoter.go index 7ae2e1e4f2..ee923a7c8c 100644 --- a/services/rfq/relayer/quoter/quoter.go +++ b/services/rfq/relayer/quoter/quoter.go @@ -297,9 +297,6 @@ func (m *Manager) SubmitAllQuotes(ctx context.Context) (err error) { // This function is blocking and will run until the context is canceled. func (m *Manager) SubscribeActiveRFQ(ctx context.Context) (err error) { ctx, span := m.metricsHandler.Tracer().Start(ctx, "SubscribeActiveRFQ") - defer func() { - metrics.EndSpanWithErr(span, err) - }() chainIDs := []int{} for chainID := range m.config.Chains { @@ -313,9 +310,12 @@ func (m *Manager) SubscribeActiveRFQ(ctx context.Context) (err error) { reqChan := make(chan *model.ActiveRFQMessage) respChan, err := m.rfqClient.SubscribeActiveQuotes(ctx, &req, reqChan) if err != nil { + metrics.EndSpanWithErr(span, err) return fmt.Errorf("error subscribing to active quotes: %w", err) } span.AddEvent("subscribed to active quotes") + metrics.EndSpan(span) + for { select { case <-ctx.Done(): From ac4c1a0dddc73403029867a9fdc4fe04292efd5a Mon Sep 17 00:00:00 2001 From: Daniel Wasserman Date: Thu, 12 Dec 2024 12:06:39 -0600 Subject: [PATCH 75/85] [goreleaser] From d80847ed395be28eb9f063c869bfcebcec85b538 Mon Sep 17 00:00:00 2001 From: Daniel Wasserman Date: Thu, 12 Dec 2024 12:40:23 -0600 Subject: [PATCH 76/85] Try panic on ws cancel --- services/rfq/api/client/client.go | 11 ++++++++--- services/rfq/api/rest/rfq.go | 15 ++++++++------- services/rfq/api/rest/ws.go | 3 +++ services/rfq/relayer/quoter/quoter.go | 3 +++ 4 files changed, 22 insertions(+), 10 deletions(-) diff --git a/services/rfq/api/client/client.go b/services/rfq/api/client/client.go index c688d37be4..9346491ba6 100644 --- a/services/rfq/api/client/client.go +++ b/services/rfq/api/client/client.go @@ -273,9 +273,11 @@ func (c *clientImpl) processWebsocket(ctx context.Context, conn *websocket.Conn, for { select { case <-ctx.Done(): - return nil + fmt.Printf("[%v] WEBSOCKET CANCELED: %v\n", time.Now(), ctx.Err()) + panic("stopping") + // return nil case msg, ok := <-reqChan: - fmt.Printf("recved message from reqChan: %+v\n", msg) + fmt.Printf("[%v] recved message from reqChan: %+v\n", time.Now(), msg) if !ok { return fmt.Errorf("error reading from reqChan: %w", ctx.Err()) } @@ -284,7 +286,7 @@ func (c *clientImpl) processWebsocket(ctx context.Context, conn *websocket.Conn, return fmt.Errorf("error sending message to websocket: %w", err) } case msg, ok := <-readChan: - fmt.Printf("recved message from readChan: %+v\n", msg) + fmt.Printf("[%v] recved message from readChan: %+v\n", time.Now(), msg) if !ok { return nil } @@ -308,6 +310,7 @@ func (c *clientImpl) sendPings(ctx context.Context, reqChan chan *model.ActiveRF } reqChan <- &pingMsg case <-ctx.Done(): + fmt.Printf("[%v] STOPPING PINGS: %v\n", time.Now(), ctx.Err()) return } } @@ -322,6 +325,7 @@ func (c *clientImpl) listenWsMessages(ctx context.Context, conn *websocket.Conn, } return } + fmt.Printf("[%v] recved message from websocket: %+v\n", time.Now(), message) select { case readChan <- message: case <-ctx.Done(): @@ -331,6 +335,7 @@ func (c *clientImpl) listenWsMessages(ctx context.Context, conn *websocket.Conn, } func (c *clientImpl) handleWsMessage(ctx context.Context, msg []byte, respChan chan *model.ActiveRFQMessage) (err error) { + fmt.Printf("[%v] handling message: %+v\n", time.Now(), msg) var rfqMsg model.ActiveRFQMessage err = json.Unmarshal(msg, &rfqMsg) if err != nil { diff --git a/services/rfq/api/rest/rfq.go b/services/rfq/api/rest/rfq.go index eef0a71522..a457e1bf86 100644 --- a/services/rfq/api/rest/rfq.go +++ b/services/rfq/api/rest/rfq.go @@ -75,7 +75,7 @@ func (r *QuoterAPIServer) handleActiveRFQ(ctx context.Context, request *model.Pu } func (r *QuoterAPIServer) collectRelayerResponses(ctx context.Context, request *model.PutRFQRequest, requestID string) (responses map[string]*model.WsRFQResponse) { - fmt.Printf("collectRelayerResponses with request data: %+v\n", request.Data) + fmt.Printf("[%v] collectRelayerResponses with requestid %v, data: %+v\n", time.Now(), requestID, request.Data) ctx, span := r.handler.Tracer().Start(ctx, "collectRelayerResponses", trace.WithAttributes( attribute.String("user_address", request.UserAddress), attribute.String("request_id", requestID), @@ -93,7 +93,7 @@ func (r *QuoterAPIServer) collectRelayerResponses(ctx context.Context, request * respMux := sync.Mutex{} responses = map[string]*model.WsRFQResponse{} r.wsClients.Range(func(relayerAddr string, client WsClient) bool { - fmt.Printf("processing ws client with addr: %v: client: %v\n", relayerAddr, client) + fmt.Printf("[%v] processing ws client with addr: %v: client: %v\n", time.Now(), relayerAddr, client) wg.Add(1) go func(client WsClient) { var respStatus db.ActiveQuoteResponseStatus @@ -109,7 +109,7 @@ func (r *QuoterAPIServer) collectRelayerResponses(ctx context.Context, request * defer wg.Done() resp, err := client.ReceiveQuoteResponse(collectionCtx, requestID) - fmt.Printf("recved quote resp: %+v\n", resp) + fmt.Printf("[%v] recved quote resp: %+v\n", time.Now(), resp) if err != nil { logger.Errorf("Error receiving quote response: %v", err) return @@ -129,7 +129,7 @@ func (r *QuoterAPIServer) collectRelayerResponses(ctx context.Context, request * } // record the response - fmt.Printf("recording resp: %+v\n", resp) + fmt.Printf("[%v] recording resp: %+v\n", time.Now(), resp) err = r.db.InsertActiveQuoteResponse(collectionCtx, resp, relayerAddr, respStatus) if err != nil { logger.Errorf("Error inserting active quote response: %v", err) @@ -141,7 +141,7 @@ func (r *QuoterAPIServer) collectRelayerResponses(ctx context.Context, request * // wait for all responses to be received, or expiration select { case <-expireCtx.Done(): - fmt.Println("request expired") + fmt.Printf("[%v] request expired\n", time.Now()) // request expired before all responses were received case <-func() chan struct{} { ch := make(chan struct{}) @@ -152,10 +152,11 @@ func (r *QuoterAPIServer) collectRelayerResponses(ctx context.Context, request * return ch }(): // all responses received + fmt.Printf("[%v] all responses received\n", time.Now()) } - fmt.Printf("responses received: %+v\n", responses) - fmt.Printf("num responses: %v\n", len(responses)) + fmt.Printf("[%v] responses received: %+v\n", time.Now(), responses) + fmt.Printf("[%v] num responses: %v\n", time.Now(), len(responses)) return responses } diff --git a/services/rfq/api/rest/ws.go b/services/rfq/api/rest/ws.go index 23b0a062eb..a32a934afb 100644 --- a/services/rfq/api/rest/ws.go +++ b/services/rfq/api/rest/ws.go @@ -223,10 +223,12 @@ func (c *wsClient) handleRelayerMessage(ctx context.Context, msg []byte) (err er case PingOp: c.lastPing = time.Now() resp := c.handlePing(ctx) + fmt.Printf("[%v] writing pong resp: %+v\n", time.Now(), resp) err = c.conn.WriteJSON(resp) if err != nil { return fmt.Errorf("error sending ping response: %w", err) } + fmt.Printf("[%v] wrote pong resp: %+v\n", time.Now(), resp) case SubscribeOp: resp := c.handleSubscribe(ctx, rfqMsg.Content) err = c.conn.WriteJSON(resp) @@ -253,6 +255,7 @@ func (c *wsClient) handleRelayerMessage(ctx context.Context, msg []byte) (err er } func (c *wsClient) handlePing(ctx context.Context) (resp model.ActiveRFQMessage) { + fmt.Printf("[%v] handlePing", time.Now()) _, span := c.handler.Tracer().Start(ctx, "handlePing", trace.WithAttributes( attribute.String("relayer_address", c.relayerAddr), )) diff --git a/services/rfq/relayer/quoter/quoter.go b/services/rfq/relayer/quoter/quoter.go index ee923a7c8c..d9da7683ab 100644 --- a/services/rfq/relayer/quoter/quoter.go +++ b/services/rfq/relayer/quoter/quoter.go @@ -11,6 +11,7 @@ import ( "strings" "sync" "sync/atomic" + "time" "github.com/synapsecns/sanguine/contrib/screener-api/client" @@ -332,6 +333,7 @@ func (m *Manager) SubscribeActiveRFQ(ctx context.Context) (err error) { if err != nil { return fmt.Errorf("error generating active RFQ message: %w", err) } + fmt.Printf("[%v] generated active RFQ message: %+v\n", time.Now(), resp) reqChan <- resp } } @@ -430,6 +432,7 @@ func (m *Manager) generateActiveRFQ(ctx context.Context, msg *model.ActiveRFQMes Content: respBytes, } span.AddEvent("generated response") + fmt.Printf("[%v] generated response: %+v\n", time.Now(), resp) return resp, nil } From 62e17def0da72d96d9b4e77f7347e0b2d4760784 Mon Sep 17 00:00:00 2001 From: Daniel Wasserman Date: Thu, 12 Dec 2024 12:40:25 -0600 Subject: [PATCH 77/85] [goreleaser] From 15858f7c4851537524643ac86fe5f290bfe9781d Mon Sep 17 00:00:00 2001 From: Daniel Wasserman Date: Thu, 12 Dec 2024 15:20:32 -0600 Subject: [PATCH 78/85] Add chan buffers, panics --- services/rfq/api/client/client.go | 13 +++++++++---- services/rfq/api/rest/ws.go | 8 +++++--- services/rfq/relayer/quoter/quoter.go | 6 ++++-- 3 files changed, 18 insertions(+), 9 deletions(-) diff --git a/services/rfq/api/client/client.go b/services/rfq/api/client/client.go index 9346491ba6..6fd8f17cf6 100644 --- a/services/rfq/api/client/client.go +++ b/services/rfq/api/client/client.go @@ -29,7 +29,10 @@ import ( var logger = log.Logger("rfq-client") -const pingPeriod = 20 * time.Second +const ( + pingPeriod = 20 * time.Second + chanBuffer = 1000 +) // AuthenticatedClient is an interface for the RFQ API. // It provides methods for creating, retrieving and updating quotes. @@ -208,7 +211,7 @@ func (c *clientImpl) SubscribeActiveQuotes(ctx context.Context, req *model.Subsc return nil, fmt.Errorf("subscription failed") } - respChan = make(chan *model.ActiveRFQMessage) + respChan = make(chan *model.ActiveRFQMessage, chanBuffer) go func() { wsErr := c.processWebsocket(ctx, conn, reqChan, respChan) if wsErr != nil { @@ -264,9 +267,10 @@ func (c *clientImpl) processWebsocket(ctx context.Context, conn *websocket.Conn, if err != nil { logger.Warnf("error closing websocket connection: %v", err) } + panic("processWebsocket exited") }() - readChan := make(chan []byte) + readChan := make(chan []byte, chanBuffer) go c.listenWsMessages(ctx, conn, readChan) go c.sendPings(ctx, reqChan) @@ -323,7 +327,8 @@ func (c *clientImpl) listenWsMessages(ctx context.Context, conn *websocket.Conn, if websocket.IsUnexpectedCloseError(err, websocket.CloseGoingAway, websocket.CloseAbnormalClosure) { logger.Warnf("websocket connection closed unexpectedly: %v", err) } - return + panic("stopping due to failed ws read") + // return } fmt.Printf("[%v] recved message from websocket: %+v\n", time.Now(), message) select { diff --git a/services/rfq/api/rest/ws.go b/services/rfq/api/rest/ws.go index a32a934afb..272e4b61bd 100644 --- a/services/rfq/api/rest/ws.go +++ b/services/rfq/api/rest/ws.go @@ -34,13 +34,15 @@ type wsClient struct { lastPing time.Time } +const chanBuffer = 1000 + func newWsClient(relayerAddr string, conn *websocket.Conn, pubsub PubSubManager, handler metrics.Handler) *wsClient { return &wsClient{ handler: handler, relayerAddr: relayerAddr, conn: conn, pubsub: pubsub, - requestChan: make(chan *model.WsRFQRequest), + requestChan: make(chan *model.WsRFQRequest, chanBuffer), responseChans: xsync.NewMapOf[chan *model.WsRFQResponse](), doneChan: make(chan struct{}), pingTicker: time.NewTicker(pingPeriod), @@ -52,7 +54,7 @@ func (c *wsClient) SendQuoteRequest(ctx context.Context, quoteRequest *model.WsR select { case c.requestChan <- quoteRequest: // successfully sent, register a response channel - c.responseChans.Store(quoteRequest.RequestID, make(chan *model.WsRFQResponse)) + c.responseChans.Store(quoteRequest.RequestID, make(chan *model.WsRFQResponse, chanBuffer)) case <-c.doneChan: return fmt.Errorf("websocket client is closed") case <-ctx.Done(): @@ -100,7 +102,7 @@ const ( // Run runs the WebSocket client. func (c *wsClient) Run(ctx context.Context) (err error) { - messageChan := make(chan []byte) + messageChan := make(chan []byte, chanBuffer) g, gctx := errgroup.WithContext(ctx) g.Go(func() error { diff --git a/services/rfq/relayer/quoter/quoter.go b/services/rfq/relayer/quoter/quoter.go index d9da7683ab..46641cf9aa 100644 --- a/services/rfq/relayer/quoter/quoter.go +++ b/services/rfq/relayer/quoter/quoter.go @@ -294,6 +294,8 @@ func (m *Manager) SubmitAllQuotes(ctx context.Context) (err error) { return m.prepareAndSubmitQuotes(ctx, inv) } +const chanBuffer = 1000 + // SubscribeActiveRFQ subscribes to the RFQ websocket API. // This function is blocking and will run until the context is canceled. func (m *Manager) SubscribeActiveRFQ(ctx context.Context) (err error) { @@ -308,7 +310,7 @@ func (m *Manager) SubscribeActiveRFQ(ctx context.Context) (err error) { } span.SetAttributes(attribute.IntSlice("chain_ids", chainIDs)) - reqChan := make(chan *model.ActiveRFQMessage) + reqChan := make(chan *model.ActiveRFQMessage, chanBuffer) respChan, err := m.rfqClient.SubscribeActiveQuotes(ctx, &req, reqChan) if err != nil { metrics.EndSpanWithErr(span, err) @@ -320,7 +322,7 @@ func (m *Manager) SubscribeActiveRFQ(ctx context.Context) (err error) { for { select { case <-ctx.Done(): - return nil + return ctx.Err() case msg, ok := <-respChan: if !ok { return errors.New("ws channel closed") From cd6015fd8b1877b719ff3b4f030a6ebb2bf73c45 Mon Sep 17 00:00:00 2001 From: Daniel Wasserman Date: Thu, 12 Dec 2024 15:20:33 -0600 Subject: [PATCH 79/85] [goreleaser] From a90924edaa280bfb1d0ac8c6d5c904aea1056172 Mon Sep 17 00:00:00 2001 From: Daniel Wasserman Date: Thu, 12 Dec 2024 16:24:41 -0600 Subject: [PATCH 80/85] Cleanup: remove logs --- services/rfq/api/client/client.go | 12 ++---------- services/rfq/api/model/request.go | 2 -- services/rfq/api/rest/rfq.go | 20 ++------------------ services/rfq/api/rest/ws.go | 7 ------- services/rfq/relayer/pricer/fee_pricer.go | 16 ---------------- services/rfq/relayer/quoter/quoter.go | 10 ---------- 6 files changed, 4 insertions(+), 63 deletions(-) diff --git a/services/rfq/api/client/client.go b/services/rfq/api/client/client.go index 6fd8f17cf6..c65d36c312 100644 --- a/services/rfq/api/client/client.go +++ b/services/rfq/api/client/client.go @@ -277,11 +277,8 @@ func (c *clientImpl) processWebsocket(ctx context.Context, conn *websocket.Conn, for { select { case <-ctx.Done(): - fmt.Printf("[%v] WEBSOCKET CANCELED: %v\n", time.Now(), ctx.Err()) - panic("stopping") - // return nil + return ctx.Err() case msg, ok := <-reqChan: - fmt.Printf("[%v] recved message from reqChan: %+v\n", time.Now(), msg) if !ok { return fmt.Errorf("error reading from reqChan: %w", ctx.Err()) } @@ -290,7 +287,6 @@ func (c *clientImpl) processWebsocket(ctx context.Context, conn *websocket.Conn, return fmt.Errorf("error sending message to websocket: %w", err) } case msg, ok := <-readChan: - fmt.Printf("[%v] recved message from readChan: %+v\n", time.Now(), msg) if !ok { return nil } @@ -314,7 +310,6 @@ func (c *clientImpl) sendPings(ctx context.Context, reqChan chan *model.ActiveRF } reqChan <- &pingMsg case <-ctx.Done(): - fmt.Printf("[%v] STOPPING PINGS: %v\n", time.Now(), ctx.Err()) return } } @@ -327,10 +322,8 @@ func (c *clientImpl) listenWsMessages(ctx context.Context, conn *websocket.Conn, if websocket.IsUnexpectedCloseError(err, websocket.CloseGoingAway, websocket.CloseAbnormalClosure) { logger.Warnf("websocket connection closed unexpectedly: %v", err) } - panic("stopping due to failed ws read") - // return + return } - fmt.Printf("[%v] recved message from websocket: %+v\n", time.Now(), message) select { case readChan <- message: case <-ctx.Done(): @@ -340,7 +333,6 @@ func (c *clientImpl) listenWsMessages(ctx context.Context, conn *websocket.Conn, } func (c *clientImpl) handleWsMessage(ctx context.Context, msg []byte, respChan chan *model.ActiveRFQMessage) (err error) { - fmt.Printf("[%v] handling message: %+v\n", time.Now(), msg) var rfqMsg model.ActiveRFQMessage err = json.Unmarshal(msg, &rfqMsg) if err != nil { diff --git a/services/rfq/api/model/request.go b/services/rfq/api/model/request.go index 06e2edb234..3e588981b9 100644 --- a/services/rfq/api/model/request.go +++ b/services/rfq/api/model/request.go @@ -1,7 +1,6 @@ package model import ( - "fmt" "time" ) @@ -85,7 +84,6 @@ type SubscribeActiveRFQRequest struct { // NewWsRFQRequest creates a new WsRFQRequest. func NewWsRFQRequest(data QuoteData, requestID string) *WsRFQRequest { - fmt.Printf("NewWsRFQRequest with data: %+v\n", data) return &WsRFQRequest{ RequestID: requestID, Data: data, diff --git a/services/rfq/api/rest/rfq.go b/services/rfq/api/rest/rfq.go index a457e1bf86..ac8e5c6da2 100644 --- a/services/rfq/api/rest/rfq.go +++ b/services/rfq/api/rest/rfq.go @@ -20,7 +20,6 @@ import ( const collectionTimeout = 1 * time.Minute func (r *QuoterAPIServer) handleActiveRFQ(ctx context.Context, request *model.PutRFQRequest, requestID string) (quote *model.QuoteData) { - fmt.Printf("handleActiveRFQ with request data: %+v\n", request.Data) ctx, span := r.handler.Tracer().Start(ctx, "handleActiveRFQ", trace.WithAttributes( attribute.String("user_address", request.UserAddress), attribute.String("request_id", requestID), @@ -31,9 +30,7 @@ func (r *QuoterAPIServer) handleActiveRFQ(ctx context.Context, request *model.Pu // publish the quote request to all connected clients relayerReq := model.NewWsRFQRequest(request.Data, requestID) - fmt.Printf("parsed websocket request: %+v\n", relayerReq.Data) r.wsClients.Range(func(relayerAddr string, client WsClient) bool { - fmt.Printf("sending quote request to client with address %v: %v\n", relayerAddr, client) sendCtx, sendSpan := r.handler.Tracer().Start(ctx, "sendQuoteRequest", trace.WithAttributes( attribute.String("relayer_address", relayerAddr), attribute.String("request_id", requestID), @@ -41,10 +38,8 @@ func (r *QuoterAPIServer) handleActiveRFQ(ctx context.Context, request *model.Pu defer metrics.EndSpan(sendSpan) subscribed := r.pubSubManager.IsSubscribed(relayerAddr, request.Data.OriginChainID, request.Data.DestChainID) - fmt.Printf("relayer %v subscribed: %v\n", relayerAddr, subscribed) span.SetAttributes(attribute.Bool("subscribed", subscribed)) if subscribed { - fmt.Printf("sending request to relayer %v: %+v\n", relayerAddr, relayerReq) err := client.SendQuoteRequest(sendCtx, relayerReq) if err != nil { logger.Errorf("Error sending quote request to %s: %v", relayerAddr, err) @@ -60,12 +55,10 @@ func (r *QuoterAPIServer) handleActiveRFQ(ctx context.Context, request *model.Pu // collect the responses and determine the best quote responses := r.collectRelayerResponses(ctx, request, requestID) for r, resp := range responses { - fmt.Printf("considering response: %+v\n", resp) relayerAddr := r quote = getBestQuote(quote, getRelayerQuoteData(request, resp)) quote.RelayerAddress = &relayerAddr } - fmt.Printf("best quote: %+v\n", quote) err = r.recordActiveQuote(ctx, quote, requestID) if err != nil { logger.Errorf("Error recording active quote: %v", err) @@ -75,7 +68,6 @@ func (r *QuoterAPIServer) handleActiveRFQ(ctx context.Context, request *model.Pu } func (r *QuoterAPIServer) collectRelayerResponses(ctx context.Context, request *model.PutRFQRequest, requestID string) (responses map[string]*model.WsRFQResponse) { - fmt.Printf("[%v] collectRelayerResponses with requestid %v, data: %+v\n", time.Now(), requestID, request.Data) ctx, span := r.handler.Tracer().Start(ctx, "collectRelayerResponses", trace.WithAttributes( attribute.String("user_address", request.UserAddress), attribute.String("request_id", requestID), @@ -93,7 +85,6 @@ func (r *QuoterAPIServer) collectRelayerResponses(ctx context.Context, request * respMux := sync.Mutex{} responses = map[string]*model.WsRFQResponse{} r.wsClients.Range(func(relayerAddr string, client WsClient) bool { - fmt.Printf("[%v] processing ws client with addr: %v: client: %v\n", time.Now(), relayerAddr, client) wg.Add(1) go func(client WsClient) { var respStatus db.ActiveQuoteResponseStatus @@ -109,7 +100,6 @@ func (r *QuoterAPIServer) collectRelayerResponses(ctx context.Context, request * defer wg.Done() resp, err := client.ReceiveQuoteResponse(collectionCtx, requestID) - fmt.Printf("[%v] recved quote resp: %+v\n", time.Now(), resp) if err != nil { logger.Errorf("Error receiving quote response: %v", err) return @@ -129,7 +119,6 @@ func (r *QuoterAPIServer) collectRelayerResponses(ctx context.Context, request * } // record the response - fmt.Printf("[%v] recording resp: %+v\n", time.Now(), resp) err = r.db.InsertActiveQuoteResponse(collectionCtx, resp, relayerAddr, respStatus) if err != nil { logger.Errorf("Error inserting active quote response: %v", err) @@ -141,8 +130,7 @@ func (r *QuoterAPIServer) collectRelayerResponses(ctx context.Context, request * // wait for all responses to be received, or expiration select { case <-expireCtx.Done(): - fmt.Printf("[%v] request expired\n", time.Now()) - // request expired before all responses were received + span.AddEvent("request expired") case <-func() chan struct{} { ch := make(chan struct{}) go func() { @@ -151,13 +139,9 @@ func (r *QuoterAPIServer) collectRelayerResponses(ctx context.Context, request * }() return ch }(): - // all responses received - fmt.Printf("[%v] all responses received\n", time.Now()) + span.AddEvent("all responses received") } - fmt.Printf("[%v] responses received: %+v\n", time.Now(), responses) - fmt.Printf("[%v] num responses: %v\n", time.Now(), len(responses)) - return responses } diff --git a/services/rfq/api/rest/ws.go b/services/rfq/api/rest/ws.go index 272e4b61bd..ecb80cf532 100644 --- a/services/rfq/api/rest/ws.go +++ b/services/rfq/api/rest/ws.go @@ -50,7 +50,6 @@ func newWsClient(relayerAddr string, conn *websocket.Conn, pubsub PubSubManager, } func (c *wsClient) SendQuoteRequest(ctx context.Context, quoteRequest *model.WsRFQRequest) error { - fmt.Printf("wsClient.SendQuoteRequest with data: %+v\n", quoteRequest.Data) select { case c.requestChan <- quoteRequest: // successfully sent, register a response channel @@ -175,7 +174,6 @@ func (c *wsClient) processWs(ctx context.Context, messageChan chan []byte) (err } func (c *wsClient) sendRelayerRequest(ctx context.Context, req *model.WsRFQRequest) (err error) { - fmt.Printf("sendRelayerRequest with data: %+v\n", req.Data) _, span := c.handler.Tracer().Start(ctx, "sendRelayerRequest", trace.WithAttributes( attribute.String("relayer_address", c.relayerAddr), attribute.String("request_id", req.RequestID), @@ -188,12 +186,10 @@ func (c *wsClient) sendRelayerRequest(ctx context.Context, req *model.WsRFQReque if err != nil { return fmt.Errorf("error marshaling quote request: %w", err) } - fmt.Printf("rawData: %+v\n", string(rawData)) msg := model.ActiveRFQMessage{ Op: RequestQuoteOp, Content: json.RawMessage(rawData), } - fmt.Printf("writing raw msg: %+v\n", msg) err = c.conn.WriteJSON(msg) if err != nil { return fmt.Errorf("error sending quote request: %w", err) @@ -225,12 +221,10 @@ func (c *wsClient) handleRelayerMessage(ctx context.Context, msg []byte) (err er case PingOp: c.lastPing = time.Now() resp := c.handlePing(ctx) - fmt.Printf("[%v] writing pong resp: %+v\n", time.Now(), resp) err = c.conn.WriteJSON(resp) if err != nil { return fmt.Errorf("error sending ping response: %w", err) } - fmt.Printf("[%v] wrote pong resp: %+v\n", time.Now(), resp) case SubscribeOp: resp := c.handleSubscribe(ctx, rfqMsg.Content) err = c.conn.WriteJSON(resp) @@ -257,7 +251,6 @@ func (c *wsClient) handleRelayerMessage(ctx context.Context, msg []byte) (err er } func (c *wsClient) handlePing(ctx context.Context) (resp model.ActiveRFQMessage) { - fmt.Printf("[%v] handlePing", time.Now()) _, span := c.handler.Tracer().Start(ctx, "handlePing", trace.WithAttributes( attribute.String("relayer_address", c.relayerAddr), )) diff --git a/services/rfq/relayer/pricer/fee_pricer.go b/services/rfq/relayer/pricer/fee_pricer.go index 3dfcb9a205..3c11d8a8cb 100644 --- a/services/rfq/relayer/pricer/fee_pricer.go +++ b/services/rfq/relayer/pricer/fee_pricer.go @@ -11,7 +11,6 @@ import ( "github.com/ethereum/go-ethereum" "github.com/ethereum/go-ethereum/accounts/abi" "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/common/hexutil" "github.com/jellydator/ttlcache/v3" "github.com/synapsecns/sanguine/core/metrics" "github.com/synapsecns/sanguine/ethergo/submitter" @@ -221,8 +220,6 @@ var fastBridgeV2ABI *abi.ABI const methodName = "relayV2" func (f *feePricer) getZapGasEstimate(ctx context.Context, destination uint32, quoteRequest *reldb.QuoteRequest) (gasEstimate uint64, err error) { - fmt.Println("Starting getZapGasEstimate with destination:", destination, "and quoteRequest:", quoteRequest) - client, err := f.clientFetcher.GetClient(ctx, big.NewInt(int64(destination))) if err != nil { return 0, fmt.Errorf("could not get client: %w", err) @@ -236,14 +233,7 @@ func (f *feePricer) getZapGasEstimate(ctx context.Context, destination uint32, q fastBridgeV2ABI = &parsedABI } - //tmpdebug - fmt.Printf("\nquoteRequest.Transaction: %+v\n", quoteRequest.Transaction) - rawRequest, err := chain.EncodeBridgeTx(quoteRequest.Transaction) - - //tmpdebug - fmt.Printf("\nrawRequest: %+v\n", rawRequest) - if err != nil { return 0, fmt.Errorf("could not encode quote data: %w", err) } @@ -265,12 +255,6 @@ func (f *feePricer) getZapGasEstimate(ctx context.Context, destination uint32, q Data: encodedData, } - fmt.Printf("\nStarting getZapGasEstimate with callMsg.From: %s, callMsg.To: %s, callMsg.Value: %s, callMsg.Data: %x\n", - callMsg.From.Hex(), callMsg.To.Hex(), callMsg.Value.String(), callMsg.Data) - - fmt.Printf("\nStarting getZapGasEstimate with callMsg.From: %s, callMsg.To: %s, callMsg.Value: %s, callMsg.Data: %s\n", - callMsg.From.Hex(), callMsg.To.Hex(), callMsg.Value.String(), hexutil.Encode(callMsg.Data)) - gasEstimate, err = client.EstimateGas(ctx, callMsg) if err != nil { return 0, fmt.Errorf("could not estimate gas: %w", err) diff --git a/services/rfq/relayer/quoter/quoter.go b/services/rfq/relayer/quoter/quoter.go index 46641cf9aa..b8ce97da86 100644 --- a/services/rfq/relayer/quoter/quoter.go +++ b/services/rfq/relayer/quoter/quoter.go @@ -11,7 +11,6 @@ import ( "strings" "sync" "sync/atomic" - "time" "github.com/synapsecns/sanguine/contrib/screener-api/client" @@ -330,12 +329,10 @@ func (m *Manager) SubscribeActiveRFQ(ctx context.Context) (err error) { if msg == nil { continue } - fmt.Printf("parsed msg from respChan: %+v\n", msg.Content) resp, err := m.generateActiveRFQ(ctx, msg) if err != nil { return fmt.Errorf("error generating active RFQ message: %w", err) } - fmt.Printf("[%v] generated active RFQ message: %+v\n", time.Now(), resp) reqChan <- resp } } @@ -345,10 +342,6 @@ func (m *Manager) SubscribeActiveRFQ(ctx context.Context) (err error) { // //nolint:nilnil,cyclop func (m *Manager) generateActiveRFQ(ctx context.Context, msg *model.ActiveRFQMessage) (resp *model.ActiveRFQMessage, err error) { - - //tmpdebug - fmt.Printf("\nActiveRFQMessage RawMessage: %s\n", string(msg.Content)) - ctx, span := m.metricsHandler.Tracer().Start(ctx, "generateActiveRFQ", trace.WithAttributes( attribute.String("op", msg.Op), attribute.String("content", string(msg.Content)), @@ -374,8 +367,6 @@ func (m *Manager) generateActiveRFQ(ctx context.Context, msg *model.ActiveRFQMes } span.SetAttributes(attribute.String("request_id", rfqRequest.RequestID)) - fmt.Printf("RFQ Request Data: %+v\n", rfqRequest.Data) - // TODO: incorporate the user call data into the quote request and set the Transaction here originAmountExact, ok := new(big.Int).SetString(rfqRequest.Data.OriginAmountExact, 10) if !ok { @@ -434,7 +425,6 @@ func (m *Manager) generateActiveRFQ(ctx context.Context, msg *model.ActiveRFQMes Content: respBytes, } span.AddEvent("generated response") - fmt.Printf("[%v] generated response: %+v\n", time.Now(), resp) return resp, nil } From 67f7e144431c0acadae6c2a6facace1ce6c2d61d Mon Sep 17 00:00:00 2001 From: ChiTimesChi <88190723+ChiTimesChi@users.noreply.github.com> Date: Wed, 18 Dec 2024 15:01:04 +0000 Subject: [PATCH 81/85] fix: correct Tx.Value for `EstimateGas` --- services/rfq/relayer/pricer/fee_pricer.go | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/services/rfq/relayer/pricer/fee_pricer.go b/services/rfq/relayer/pricer/fee_pricer.go index 3c11d8a8cb..71c49540d9 100644 --- a/services/rfq/relayer/pricer/fee_pricer.go +++ b/services/rfq/relayer/pricer/fee_pricer.go @@ -18,6 +18,7 @@ import ( "github.com/synapsecns/sanguine/services/rfq/relayer/chain" "github.com/synapsecns/sanguine/services/rfq/relayer/relconfig" "github.com/synapsecns/sanguine/services/rfq/relayer/reldb" + "github.com/synapsecns/sanguine/services/rfq/util" "go.opentelemetry.io/otel/attribute" "go.opentelemetry.io/otel/trace" ) @@ -249,10 +250,15 @@ func (f *feePricer) getZapGasEstimate(ctx context.Context, destination uint32, q } callMsg := ethereum.CallMsg{ - From: f.relayerAddress, - To: &rfqAddr, - Value: quoteRequest.Transaction.ZapNative, - Data: encodedData, + From: f.relayerAddress, + To: &rfqAddr, + Data: encodedData, + } + // Tx.value needs to match `DestAmount` for native gas token, or `ZapNative` for ERC20s. + if util.IsGasToken(quoteRequest.Transaction.DestToken) { + callMsg.Value = quoteRequest.Transaction.DestAmount + } else { + callMsg.Value = quoteRequest.Transaction.ZapNative } gasEstimate, err = client.EstimateGas(ctx, callMsg) From 19b24c6da00c2c61057c5e4ff70f49270eb3bcda Mon Sep 17 00:00:00 2001 From: ChiTimesChi <88190723+ChiTimesChi@users.noreply.github.com> Date: Wed, 18 Dec 2024 15:03:40 +0000 Subject: [PATCH 82/85] [goreleaser] From 551083bca9b9c3b0231a898c119b8bd9c9fd23f7 Mon Sep 17 00:00:00 2001 From: Daniel Wasserman Date: Mon, 23 Dec 2024 11:47:08 -0500 Subject: [PATCH 83/85] Fix: integration tests --- .../rfq/testutil/contracttypeimpl_string.go | 22 ++++++++++--------- services/rfq/testutil/deployers.go | 3 ++- services/rfq/testutil/typecast.go | 1 + 3 files changed, 15 insertions(+), 11 deletions(-) diff --git a/services/rfq/testutil/contracttypeimpl_string.go b/services/rfq/testutil/contracttypeimpl_string.go index 6f461d5b45..9968574bf0 100644 --- a/services/rfq/testutil/contracttypeimpl_string.go +++ b/services/rfq/testutil/contracttypeimpl_string.go @@ -9,19 +9,21 @@ func _() { // Re-run the stringer command to generate them again. var x [1]struct{} _ = x[FastBridgeType-1] - _ = x[MockERC20Type-2] - _ = x[FastBridgeMockType-3] - _ = x[RecipientMockType-4] - _ = x[BridgeTransactionV2Type-5] - _ = x[WETH9Type-6] - _ = x[USDTType-7] - _ = x[USDCType-8] - _ = x[DAIType-9] + _ = x[FastBridgeV2Type-2] + _ = x[MockERC20Type-3] + _ = x[FastBridgeMockType-4] + _ = x[RecipientMockType-5] + _ = x[BridgeTransactionV2Type-6] + _ = x[WETH9Type-7] + _ = x[USDTType-8] + _ = x[USDCType-9] + _ = x[DAIType-10] } -const _contractTypeImpl_name = "FastBridgeMockERC20FastBridgeMockRecipientMockBridgeTransactionV2WETH9USDTUSDCDAI" +const _contractTypeImpl_name = "FastBridgeV1FastBridgeV2MockERC20FastBridgeMockRecipientMockBridgeTransactionV2WETH9USDTUSDCDAI" + +var _contractTypeImpl_index = [...]uint8{0, 12, 24, 33, 47, 60, 79, 84, 88, 92, 95} -var _contractTypeImpl_index = [...]uint8{0, 10, 19, 33, 46, 65, 70, 74, 78, 81} func (i contractTypeImpl) String() string { i -= 1 if i < 0 || i >= contractTypeImpl(len(_contractTypeImpl_index)-1) { diff --git a/services/rfq/testutil/deployers.go b/services/rfq/testutil/deployers.go index 9f0041f422..7120f65c60 100644 --- a/services/rfq/testutil/deployers.go +++ b/services/rfq/testutil/deployers.go @@ -15,6 +15,7 @@ import ( "github.com/synapsecns/sanguine/ethergo/deployer" "github.com/synapsecns/sanguine/ethergo/manager" "github.com/synapsecns/sanguine/services/rfq/contracts/bridgetransactionv2" + "github.com/synapsecns/sanguine/services/rfq/contracts/fastbridge" "github.com/synapsecns/sanguine/services/rfq/contracts/fastbridgev2" "github.com/synapsecns/sanguine/services/rfq/contracts/testcontracts/fastbridgemockv2" "github.com/synapsecns/sanguine/services/rfq/contracts/testcontracts/recipientmock" @@ -29,7 +30,7 @@ type DeployManager struct { func NewDeployManager(t *testing.T) *DeployManager { t.Helper() - parentManager := manager.NewDeployerManager(t, NewFastBridgeDeployer, NewMockERC20Deployer, NewMockFastBridgeDeployer, NewRecipientMockDeployer, NewBridgeTransactionV2Deployer, NewWETH9Deployer, NewUSDTDeployer, NewUSDCDeployer, NewDAIDeployer) + parentManager := manager.NewDeployerManager(t, NewFastBridgeDeployer, NewFastBridgeV2Deployer, NewMockERC20Deployer, NewMockFastBridgeDeployer, NewRecipientMockDeployer, NewBridgeTransactionV2Deployer, NewWETH9Deployer, NewUSDTDeployer, NewUSDCDeployer, NewDAIDeployer) return &DeployManager{parentManager} } diff --git a/services/rfq/testutil/typecast.go b/services/rfq/testutil/typecast.go index a185ba6756..96fe659bdd 100644 --- a/services/rfq/testutil/typecast.go +++ b/services/rfq/testutil/typecast.go @@ -7,6 +7,7 @@ import ( "github.com/synapsecns/sanguine/ethergo/contracts" "github.com/synapsecns/sanguine/ethergo/manager" "github.com/synapsecns/sanguine/services/rfq/contracts/bridgetransactionv2" + "github.com/synapsecns/sanguine/services/rfq/contracts/fastbridge" "github.com/synapsecns/sanguine/services/rfq/contracts/fastbridgev2" "github.com/synapsecns/sanguine/services/rfq/contracts/testcontracts/dai" "github.com/synapsecns/sanguine/services/rfq/contracts/testcontracts/fastbridgemockv2" From 0aaf37e3ab906968f7549e8312f9f8d20e010e65 Mon Sep 17 00:00:00 2001 From: Daniel Wasserman Date: Mon, 30 Dec 2024 10:32:15 -0600 Subject: [PATCH 84/85] Cleanup: lint --- services/rfq/contracts/fastbridgev2/parser.go | 2 +- services/rfq/e2e/rfq_test.go | 12 ++++++------ services/rfq/e2e/setup_test.go | 11 +++++------ services/rfq/guard/service/guard.go | 10 ++++++---- services/rfq/relayer/quoter/quoter.go | 3 ++- 5 files changed, 20 insertions(+), 18 deletions(-) diff --git a/services/rfq/contracts/fastbridgev2/parser.go b/services/rfq/contracts/fastbridgev2/parser.go index c6e5fd429d..5fe9d66570 100644 --- a/services/rfq/contracts/fastbridgev2/parser.go +++ b/services/rfq/contracts/fastbridgev2/parser.go @@ -48,7 +48,7 @@ func NewParser(fastBridgeAddress common.Address) (Parser, error) { func (p parserImpl) ParseEvent(log ethTypes.Log) (_ EventType, event interface{}, ok bool) { // return an unknown event to avoid cases where user failed to check the event type // make it high enough to make it obvious (we start iotas at +1, see uber style guide for details) - noOpEvent := EventType(len(topicMap()) + 2) + noOpEvent := EventType(len(topicMap()) + 2) //nolint:gosec // Acceptable conversion if len(log.Topics) == 0 { return noOpEvent, nil, false diff --git a/services/rfq/e2e/rfq_test.go b/services/rfq/e2e/rfq_test.go index 693e35ad06..821320d48b 100644 --- a/services/rfq/e2e/rfq_test.go +++ b/services/rfq/e2e/rfq_test.go @@ -172,7 +172,7 @@ func (i *IntegrationSuite) TestUSDCtoUSDC() { _, originFastBridge := i.manager.GetFastBridgeV2(i.GetTestContext(), i.originBackend) auth := i.originBackend.GetTxContext(i.GetTestContext(), i.userWallet.AddressPtr()) tx, err = originFastBridge.Bridge(auth.TransactOpts, fastbridgev2.IFastBridgeBridgeParams{ - DstChainId: uint32(i.destBackend.GetChainID()), + DstChainId: uint32(i.destBackend.GetChainID()), //nolint:gosec // Acceptable conversion Sender: i.userWallet.Address(), To: i.userWallet.Address(), OriginToken: originUSDC.Address(), @@ -327,7 +327,7 @@ func (i *IntegrationSuite) TestETHtoETH() { auth.TransactOpts.Value = realWantAmount // we want 499 ETH for 500 requested within a day tx, err := originFastBridge.Bridge(auth.TransactOpts, fastbridgev2.IFastBridgeBridgeParams{ - DstChainId: uint32(i.destBackend.GetChainID()), + DstChainId: uint32(i.destBackend.GetChainID()), //nolint:gosec // Acceptable conversion Sender: i.userWallet.Address(), To: i.userWallet.Address(), OriginToken: util.EthAddress, @@ -468,7 +468,7 @@ func (i *IntegrationSuite) TestZap() { _, destRecipient := i.manager.GetRecipientMock(i.GetTestContext(), i.destBackend) auth := i.originBackend.GetTxContext(i.GetTestContext(), i.userWallet.AddressPtr()) params := fastbridgev2.IFastBridgeBridgeParams{ - DstChainId: uint32(i.destBackend.GetChainID()), + DstChainId: uint32(i.destBackend.GetChainID()), //nolint:gosec // Acceptable conversion Sender: i.userWallet.Address(), To: destRecipient.Address(), OriginToken: originUSDC.Address(), @@ -558,7 +558,7 @@ func (i *IntegrationSuite) TestDisputeV1() { auth := i.originBackend.GetTxContext(i.GetTestContext(), i.userWallet.AddressPtr()) // we want 499 usdc for 500 requested within a day tx, err = originFastBridge.Bridge(auth.TransactOpts, fastbridge.IFastBridgeBridgeParams{ - DstChainId: uint32(i.destBackend.GetChainID()), + DstChainId: uint32(i.destBackend.GetChainID()), //nolint:gosec // Acceptable conversion Sender: i.userWallet.Address(), To: i.userWallet.Address(), OriginToken: originUSDC.Address(), @@ -655,7 +655,7 @@ func (i *IntegrationSuite) TestDisputeV2() { auth := i.originBackend.GetTxContext(i.GetTestContext(), i.userWallet.AddressPtr()) // we want 499 usdc for 500 requested within a day tx, err = originFastBridge.Bridge(auth.TransactOpts, fastbridgev2.IFastBridgeBridgeParams{ - DstChainId: uint32(i.destBackend.GetChainID()), + DstChainId: uint32(i.destBackend.GetChainID()), //nolint:gosec // Acceptable conversion Sender: i.userWallet.Address(), To: i.userWallet.Address(), OriginToken: originUSDC.Address(), @@ -785,7 +785,7 @@ func (i *IntegrationSuite) TestConcurrentBridges() { auth.TransactOpts.Nonce = nonce defer txMux.Unlock() tx, err = originFastBridge.Bridge(auth.TransactOpts, fastbridgev2.IFastBridgeBridgeParams{ - DstChainId: uint32(i.destBackend.GetChainID()), + DstChainId: uint32(i.destBackend.GetChainID()), //nolint:gosec // Acceptable conversion Sender: i.userWallet.Address(), To: i.userWallet.Address(), OriginToken: originUSDC.Address(), diff --git a/services/rfq/e2e/setup_test.go b/services/rfq/e2e/setup_test.go index 892617465b..658671bb17 100644 --- a/services/rfq/e2e/setup_test.go +++ b/services/rfq/e2e/setup_test.go @@ -269,7 +269,7 @@ func (i *IntegrationSuite) Approve(backend backends.SimulatedTestBackend, token err := i.waitForContractDeployment(i.GetTestContext(), backend, token.Address()) i.Require().NoError(err, "Failed to wait for contract deployment") - erc20, err := ierc20.NewIERC20(token.Address(), backend) + erc20, err := ierc20.NewIerc20Ref(common.HexToAddress(token.Address().String()), backend) i.Require().NoError(err, "Failed to get erc20") // approve fastbridgev1 @@ -400,9 +400,12 @@ func (i *IntegrationSuite) setupRelayer() { txContextV1 := backend.GetTxContext(i.GetTestContext(), metadataV1.OwnerPtr()) relayerRole, err := rfqContractV1.RELAYERROLE(&bind.CallOpts{Context: i.GetTestContext()}) + if err != nil { + return fmt.Errorf("failed to get relayer role: %w", err) + } proverRole, err := rfqContractV1.RELAYERROLE(&bind.CallOpts{Context: i.GetTestContext()}) if err != nil { - return fmt.Errorf("could not get prover role: %w", err) + return fmt.Errorf("failed to get relayer role: %w", err) } tx, err := rfqContractV1.GrantRole(txContextV1.TransactOpts, relayerRole, i.relayerWallet.Address()) if err != nil { @@ -413,10 +416,6 @@ func (i *IntegrationSuite) setupRelayer() { metadataV2, rfqContractV2 := i.manager.GetFastBridgeV2(i.GetTestContext(), backend) txContextV2 := backend.GetTxContext(i.GetTestContext(), metadataV2.OwnerPtr()) - proverRole, err = rfqContractV2.PROVERROLE(&bind.CallOpts{Context: i.GetTestContext()}) - if err != nil { - return fmt.Errorf("could not get prover role: %w", err) - } tx, err = rfqContractV2.GrantRole(txContextV2.TransactOpts, proverRole, i.relayerWallet.Address()) if err != nil { return fmt.Errorf("could not grant prover role: %w", err) diff --git a/services/rfq/guard/service/guard.go b/services/rfq/guard/service/guard.go index 4fd56c311b..6da309fcd5 100644 --- a/services/rfq/guard/service/guard.go +++ b/services/rfq/guard/service/guard.go @@ -82,7 +82,8 @@ func NewGuard(ctx context.Context, metricHandler metrics.Handler, cfg guardconfi if err != nil { return nil, fmt.Errorf("could not get deploy block: %w", err) } - chainListener, err := listener.NewChainListener(chainClient, store, common.HexToAddress(*rfqAddrV1), uint64(startBlock.Int64()), metricHandler, listener.WithName("guard")) + chainListener, err := listener.NewChainListener(chainClient, store, common.HexToAddress(*rfqAddrV1), uint64(startBlock.Int64()), //nolint:gosec // Acceptable conversion + metricHandler, listener.WithName("guard")) if err != nil { return nil, fmt.Errorf("could not get chain listener: %w", err) } @@ -107,7 +108,8 @@ func NewGuard(ctx context.Context, metricHandler metrics.Handler, cfg guardconfi if err != nil { return nil, fmt.Errorf("could not get deploy block: %w", err) } - chainListener, err := listener.NewChainListener(chainClient, store, common.HexToAddress(rfqAddrV2), uint64(startBlock.Int64()), metricHandler, listener.WithName("guardV2")) + chainListener, err := listener.NewChainListener(chainClient, store, common.HexToAddress(rfqAddrV2), uint64(startBlock.Int64()), //nolint:gosec // Acceptable conversion + metricHandler, listener.WithName("guardV2")) if err != nil { return nil, fmt.Errorf("could not get chain listener: %w", err) } @@ -257,7 +259,7 @@ func (g Guard) runChainIndexerV1(ctx context.Context, chainID int, chainListener attribute.Int(metrics.Origin, chainID), attribute.String(metrics.Contract, log.Address.String()), attribute.String("block_hash", log.BlockHash.String()), - attribute.Int64("block_number", int64(log.BlockNumber)), + attribute.Int64("block_number", int64(log.BlockNumber)), //nolint:gosec // Acceptable conversion )) defer func() { @@ -335,7 +337,7 @@ func (g Guard) runChainIndexerV2(ctx context.Context, chainID int, chainListener attribute.Int(metrics.Origin, chainID), attribute.String(metrics.Contract, log.Address.String()), attribute.String("block_hash", log.BlockHash.String()), - attribute.Int64("block_number", int64(log.BlockNumber)), + attribute.Int64("block_number", int64(log.BlockNumber)), //nolint:gosec // Acceptable conversion )) defer func() { diff --git a/services/rfq/relayer/quoter/quoter.go b/services/rfq/relayer/quoter/quoter.go index b72bf36d11..f7b03211c9 100644 --- a/services/rfq/relayer/quoter/quoter.go +++ b/services/rfq/relayer/quoter/quoter.go @@ -286,6 +286,7 @@ func (m *Manager) getAmountWithOffset(ctx context.Context, chainID uint32, token func (m *Manager) SubmitAllQuotes(ctx context.Context) (err error) { ctx, span := m.metricsHandler.Tracer().Start(ctx, "SubmitAllQuotes") defer func() { + span.SetAttributes(attribute.Bool("relay_paused", m.relayPaused.Load())) metrics.EndSpanWithErr(span, err) }() @@ -325,7 +326,7 @@ func (m *Manager) SubscribeActiveRFQ(ctx context.Context) (err error) { for { select { case <-ctx.Done(): - return ctx.Err() + return fmt.Errorf("context error: %w", ctx.Err()) case msg, ok := <-respChan: if !ok { return errors.New("ws channel closed") From 15c2598d45f0db7014c5b8310574a6d122ccf3da Mon Sep 17 00:00:00 2001 From: Daniel Wasserman Date: Thu, 2 Jan 2025 10:47:37 -0600 Subject: [PATCH 85/85] Cleanup: lint --- services/rfq/relayer/pricer/fee_pricer.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/rfq/relayer/pricer/fee_pricer.go b/services/rfq/relayer/pricer/fee_pricer.go index 71c49540d9..b259497b01 100644 --- a/services/rfq/relayer/pricer/fee_pricer.go +++ b/services/rfq/relayer/pricer/fee_pricer.go @@ -181,7 +181,7 @@ func (f *feePricer) GetDestinationFee(parentCtx context.Context, _, destination // addZapFees incorporates the cost of the call and the call value into the fee. // Note that to be conservative, we always use the QuoteFixedFeeMultiplier over the RelayFixedFeeMultiplier. // -//nolint:gosec +//nolint:cyclop,gosec func (f *feePricer) addZapFees(ctx context.Context, destination uint32, denomToken string, quoteRequest *reldb.QuoteRequest, fee *big.Int) (*big.Int, error) { span := trace.SpanFromContext(ctx)